ops-loongson2.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. /*
  2. * Copyright (C) 1999, 2000, 2004 MIPS Technologies, Inc.
  3. * All rights reserved.
  4. * Authors: Carsten Langgaard <carstenl@mips.com>
  5. * Maciej W. Rozycki <macro@mips.com>
  6. *
  7. * Copyright (C) 2009 Lemote Inc.
  8. * Author: Wu Zhangjin <wuzhangjin@gmail.com>
  9. *
  10. * This program is free software; you can distribute it and/or modify it
  11. * under the terms of the GNU General Public License (Version 2) as
  12. * published by the Free Software Foundation.
  13. */
  14. #include <linux/types.h>
  15. #include <linux/pci.h>
  16. #include <linux/kernel.h>
  17. #include <linux/export.h>
  18. #include <loongson.h>
  19. #ifdef CONFIG_CS5536
  20. #include <cs5536/cs5536_pci.h>
  21. #include <cs5536/cs5536.h>
  22. #endif
  23. #define PCI_ACCESS_READ 0
  24. #define PCI_ACCESS_WRITE 1
  25. #define CFG_SPACE_REG(offset) \
  26. (void *)CKSEG1ADDR(LOONGSON_PCICFG_BASE | (offset))
  27. #define ID_SEL_BEGIN 11
  28. #define MAX_DEV_NUM (31 - ID_SEL_BEGIN)
  29. static int loongson_pcibios_config_access(unsigned char access_type,
  30. struct pci_bus *bus,
  31. unsigned int devfn, int where,
  32. u32 *data)
  33. {
  34. u32 busnum = bus->number;
  35. u32 addr, type;
  36. u32 dummy;
  37. void *addrp;
  38. int device = PCI_SLOT(devfn);
  39. int function = PCI_FUNC(devfn);
  40. int reg = where & ~3;
  41. if (busnum == 0) {
  42. /* board-specific part,currently,only fuloong2f,yeeloong2f
  43. * use CS5536, fuloong2e use via686b, gdium has no
  44. * south bridge
  45. */
  46. #ifdef CONFIG_CS5536
  47. /* cs5536_pci_conf_read4/write4() will call _rdmsr/_wrmsr() to
  48. * access the regsters PCI_MSR_ADDR, PCI_MSR_DATA_LO,
  49. * PCI_MSR_DATA_HI, which is bigger than PCI_MSR_CTRL, so, it
  50. * will not go this branch, but the others. so, no calling dead
  51. * loop here.
  52. */
  53. if ((PCI_IDSEL_CS5536 == device) && (reg < PCI_MSR_CTRL)) {
  54. switch (access_type) {
  55. case PCI_ACCESS_READ:
  56. *data = cs5536_pci_conf_read4(function, reg);
  57. break;
  58. case PCI_ACCESS_WRITE:
  59. cs5536_pci_conf_write4(function, reg, *data);
  60. break;
  61. }
  62. return 0;
  63. }
  64. #endif
  65. /* Type 0 configuration for onboard PCI bus */
  66. if (device > MAX_DEV_NUM)
  67. return -1;
  68. addr = (1 << (device + ID_SEL_BEGIN)) | (function << 8) | reg;
  69. type = 0;
  70. } else {
  71. /* Type 1 configuration for offboard PCI bus */
  72. addr = (busnum << 16) | (device << 11) | (function << 8) | reg;
  73. type = 0x10000;
  74. }
  75. /* Clear aborts */
  76. LOONGSON_PCICMD |= LOONGSON_PCICMD_MABORT_CLR | \
  77. LOONGSON_PCICMD_MTABORT_CLR;
  78. LOONGSON_PCIMAP_CFG = (addr >> 16) | type;
  79. /* Flush Bonito register block */
  80. dummy = LOONGSON_PCIMAP_CFG;
  81. mmiowb();
  82. addrp = CFG_SPACE_REG(addr & 0xffff);
  83. if (access_type == PCI_ACCESS_WRITE)
  84. writel(cpu_to_le32(*data), addrp);
  85. else
  86. *data = le32_to_cpu(readl(addrp));
  87. /* Detect Master/Target abort */
  88. if (LOONGSON_PCICMD & (LOONGSON_PCICMD_MABORT_CLR |
  89. LOONGSON_PCICMD_MTABORT_CLR)) {
  90. /* Error occurred */
  91. /* Clear bits */
  92. LOONGSON_PCICMD |= (LOONGSON_PCICMD_MABORT_CLR |
  93. LOONGSON_PCICMD_MTABORT_CLR);
  94. return -1;
  95. }
  96. return 0;
  97. }
  98. /*
  99. * We can't address 8 and 16 bit words directly. Instead we have to
  100. * read/write a 32bit word and mask/modify the data we actually want.
  101. */
  102. static int loongson_pcibios_read(struct pci_bus *bus, unsigned int devfn,
  103. int where, int size, u32 *val)
  104. {
  105. u32 data = 0;
  106. if ((size == 2) && (where & 1))
  107. return PCIBIOS_BAD_REGISTER_NUMBER;
  108. else if ((size == 4) && (where & 3))
  109. return PCIBIOS_BAD_REGISTER_NUMBER;
  110. if (loongson_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, where,
  111. &data))
  112. return -1;
  113. if (size == 1)
  114. *val = (data >> ((where & 3) << 3)) & 0xff;
  115. else if (size == 2)
  116. *val = (data >> ((where & 3) << 3)) & 0xffff;
  117. else
  118. *val = data;
  119. return PCIBIOS_SUCCESSFUL;
  120. }
  121. static int loongson_pcibios_write(struct pci_bus *bus, unsigned int devfn,
  122. int where, int size, u32 val)
  123. {
  124. u32 data = 0;
  125. if ((size == 2) && (where & 1))
  126. return PCIBIOS_BAD_REGISTER_NUMBER;
  127. else if ((size == 4) && (where & 3))
  128. return PCIBIOS_BAD_REGISTER_NUMBER;
  129. if (size == 4)
  130. data = val;
  131. else {
  132. if (loongson_pcibios_config_access(PCI_ACCESS_READ, bus, devfn,
  133. where, &data))
  134. return -1;
  135. if (size == 1)
  136. data = (data & ~(0xff << ((where & 3) << 3))) |
  137. (val << ((where & 3) << 3));
  138. else if (size == 2)
  139. data = (data & ~(0xffff << ((where & 3) << 3))) |
  140. (val << ((where & 3) << 3));
  141. }
  142. if (loongson_pcibios_config_access(PCI_ACCESS_WRITE, bus, devfn, where,
  143. &data))
  144. return -1;
  145. return PCIBIOS_SUCCESSFUL;
  146. }
  147. struct pci_ops loongson_pci_ops = {
  148. .read = loongson_pcibios_read,
  149. .write = loongson_pcibios_write
  150. };
  151. #ifdef CONFIG_CS5536
  152. DEFINE_RAW_SPINLOCK(msr_lock);
  153. void _rdmsr(u32 msr, u32 *hi, u32 *lo)
  154. {
  155. struct pci_bus bus = {
  156. .number = PCI_BUS_CS5536
  157. };
  158. u32 devfn = PCI_DEVFN(PCI_IDSEL_CS5536, 0);
  159. unsigned long flags;
  160. raw_spin_lock_irqsave(&msr_lock, flags);
  161. loongson_pcibios_write(&bus, devfn, PCI_MSR_ADDR, 4, msr);
  162. loongson_pcibios_read(&bus, devfn, PCI_MSR_DATA_LO, 4, lo);
  163. loongson_pcibios_read(&bus, devfn, PCI_MSR_DATA_HI, 4, hi);
  164. raw_spin_unlock_irqrestore(&msr_lock, flags);
  165. }
  166. EXPORT_SYMBOL(_rdmsr);
  167. void _wrmsr(u32 msr, u32 hi, u32 lo)
  168. {
  169. struct pci_bus bus = {
  170. .number = PCI_BUS_CS5536
  171. };
  172. u32 devfn = PCI_DEVFN(PCI_IDSEL_CS5536, 0);
  173. unsigned long flags;
  174. raw_spin_lock_irqsave(&msr_lock, flags);
  175. loongson_pcibios_write(&bus, devfn, PCI_MSR_ADDR, 4, msr);
  176. loongson_pcibios_write(&bus, devfn, PCI_MSR_DATA_LO, 4, lo);
  177. loongson_pcibios_write(&bus, devfn, PCI_MSR_DATA_HI, 4, hi);
  178. raw_spin_unlock_irqrestore(&msr_lock, flags);
  179. }
  180. EXPORT_SYMBOL(_wrmsr);
  181. #endif