uninorthpci.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. /*-
  2. * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
  3. *
  4. * Copyright (C) 2002 Benno Rice.
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * 2. Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
  17. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  18. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  19. * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  20. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  21. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  22. * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  23. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  24. * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  25. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. #include <sys/cdefs.h>
  28. __FBSDID("$FreeBSD$");
  29. #include <sys/param.h>
  30. #include <sys/systm.h>
  31. #include <sys/module.h>
  32. #include <sys/bus.h>
  33. #include <sys/conf.h>
  34. #include <sys/kernel.h>
  35. #include <sys/lock.h>
  36. #include <sys/mutex.h>
  37. #include <sys/rman.h>
  38. #include <dev/ofw/openfirm.h>
  39. #include <dev/ofw/ofw_pci.h>
  40. #include <dev/ofw/ofw_bus.h>
  41. #include <dev/ofw/ofw_bus_subr.h>
  42. #include <dev/ofw/ofwpci.h>
  43. #include <dev/pci/pcivar.h>
  44. #include <dev/pci/pcireg.h>
  45. #include <machine/bus.h>
  46. #include <machine/intr_machdep.h>
  47. #include <machine/md_var.h>
  48. #include <machine/pio.h>
  49. #include <machine/resource.h>
  50. #include <powerpc/powermac/uninorthvar.h>
  51. #include <vm/vm.h>
  52. #include <vm/pmap.h>
  53. #include "pcib_if.h"
  54. #define UNINORTH_DEBUG 0
  55. /*
  56. * Device interface.
  57. */
  58. static int uninorth_probe(device_t);
  59. static int uninorth_attach(device_t);
  60. /*
  61. * pcib interface.
  62. */
  63. static u_int32_t uninorth_read_config(device_t, u_int, u_int, u_int,
  64. u_int, int);
  65. static void uninorth_write_config(device_t, u_int, u_int, u_int,
  66. u_int, u_int32_t, int);
  67. /*
  68. * Local routines.
  69. */
  70. static int uninorth_enable_config(struct uninorth_softc *, u_int,
  71. u_int, u_int, u_int);
  72. /*
  73. * Driver methods.
  74. */
  75. static device_method_t uninorth_methods[] = {
  76. /* Device interface */
  77. DEVMETHOD(device_probe, uninorth_probe),
  78. DEVMETHOD(device_attach, uninorth_attach),
  79. /* pcib interface */
  80. DEVMETHOD(pcib_read_config, uninorth_read_config),
  81. DEVMETHOD(pcib_write_config, uninorth_write_config),
  82. DEVMETHOD_END
  83. };
  84. static devclass_t uninorth_devclass;
  85. DEFINE_CLASS_1(pcib, uninorth_driver, uninorth_methods,
  86. sizeof(struct uninorth_softc), ofw_pci_driver);
  87. EARLY_DRIVER_MODULE(uninorth, ofwbus, uninorth_driver, uninorth_devclass, 0, 0,
  88. BUS_PASS_BUS);
  89. static int
  90. uninorth_probe(device_t dev)
  91. {
  92. const char *type, *compatible;
  93. type = ofw_bus_get_type(dev);
  94. compatible = ofw_bus_get_compat(dev);
  95. if (type == NULL || compatible == NULL)
  96. return (ENXIO);
  97. if (strcmp(type, "pci") != 0)
  98. return (ENXIO);
  99. if (strcmp(compatible, "uni-north") == 0) {
  100. device_set_desc(dev, "Apple UniNorth Host-PCI bridge");
  101. return (0);
  102. } else if (strcmp(compatible, "u3-agp") == 0) {
  103. device_set_desc(dev, "Apple U3 Host-AGP bridge");
  104. return (0);
  105. } else if (strcmp(compatible, "u4-pcie") == 0) {
  106. device_set_desc(dev, "IBM CPC945 PCI Express Root");
  107. return (0);
  108. }
  109. return (ENXIO);
  110. }
  111. static int
  112. uninorth_attach(device_t dev)
  113. {
  114. struct uninorth_softc *sc;
  115. const char *compatible;
  116. const char *name;
  117. phandle_t node;
  118. uint32_t reg[3];
  119. uint64_t regbase;
  120. cell_t acells;
  121. int unit;
  122. node = ofw_bus_get_node(dev);
  123. sc = device_get_softc(dev);
  124. name = device_get_name(dev);
  125. unit = device_get_unit(dev);
  126. if (OF_getprop(node, "reg", reg, sizeof(reg)) < 8)
  127. return (ENXIO);
  128. sc->sc_ver = 0;
  129. compatible = ofw_bus_get_compat(dev);
  130. if (strcmp(compatible, "u3-agp") == 0)
  131. sc->sc_ver = 3;
  132. if (strcmp(compatible, "u4-pcie") == 0)
  133. sc->sc_ver = 4;
  134. acells = 1;
  135. OF_getprop(OF_parent(node), "#address-cells", &acells, sizeof(acells));
  136. regbase = reg[0];
  137. if (acells == 2) {
  138. regbase <<= 32;
  139. regbase |= reg[1];
  140. }
  141. sc->sc_addr = (vm_offset_t)pmap_mapdev(regbase + 0x800000, PAGE_SIZE);
  142. sc->sc_data = (vm_offset_t)pmap_mapdev(regbase + 0xc00000, PAGE_SIZE);
  143. if (resource_int_value(name, unit, "skipslot", &sc->sc_skipslot) != 0)
  144. sc->sc_skipslot = -1;
  145. mtx_init(&sc->sc_cfg_mtx, "uninorth pcicfg", NULL, MTX_SPIN);
  146. return (ofw_pci_attach(dev));
  147. }
  148. static u_int32_t
  149. uninorth_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
  150. int width)
  151. {
  152. struct uninorth_softc *sc;
  153. vm_offset_t caoff;
  154. u_int32_t val;
  155. sc = device_get_softc(dev);
  156. caoff = sc->sc_data + (reg & 0x07);
  157. val = 0xffffffff;
  158. mtx_lock_spin(&sc->sc_cfg_mtx);
  159. if (uninorth_enable_config(sc, bus, slot, func, reg) != 0) {
  160. switch (width) {
  161. case 1:
  162. val = in8rb(caoff);
  163. break;
  164. case 2:
  165. val = in16rb(caoff);
  166. break;
  167. case 4:
  168. val = in32rb(caoff);
  169. break;
  170. }
  171. }
  172. mtx_unlock_spin(&sc->sc_cfg_mtx);
  173. return (val);
  174. }
  175. static void
  176. uninorth_write_config(device_t dev, u_int bus, u_int slot, u_int func,
  177. u_int reg, u_int32_t val, int width)
  178. {
  179. struct uninorth_softc *sc;
  180. vm_offset_t caoff;
  181. sc = device_get_softc(dev);
  182. caoff = sc->sc_data + (reg & 0x07);
  183. mtx_lock_spin(&sc->sc_cfg_mtx);
  184. if (uninorth_enable_config(sc, bus, slot, func, reg)) {
  185. switch (width) {
  186. case 1:
  187. out8rb(caoff, val);
  188. break;
  189. case 2:
  190. out16rb(caoff, val);
  191. break;
  192. case 4:
  193. out32rb(caoff, val);
  194. break;
  195. }
  196. }
  197. mtx_unlock_spin(&sc->sc_cfg_mtx);
  198. }
  199. static int
  200. uninorth_enable_config(struct uninorth_softc *sc, u_int bus, u_int slot,
  201. u_int func, u_int reg)
  202. {
  203. uint32_t cfgval;
  204. mtx_assert(&sc->sc_cfg_mtx, MA_OWNED);
  205. if (sc->sc_skipslot == slot)
  206. return (0);
  207. /*
  208. * Issue type 0 configuration space accesses for the root bus.
  209. *
  210. * NOTE: On U4, issue only type 1 accesses. There is a secret
  211. * PCI Express <-> PCI Express bridge not present in the device tree,
  212. * and we need to route all of our configuration space through it.
  213. */
  214. if (sc->pci_sc.sc_bus == bus && sc->sc_ver < 4) {
  215. /*
  216. * No slots less than 11 on the primary bus on U3 and lower
  217. */
  218. if (slot < 11)
  219. return (0);
  220. cfgval = (1 << slot) | (func << 8) | (reg & 0xfc);
  221. } else {
  222. cfgval = (bus << 16) | (slot << 11) | (func << 8) |
  223. (reg & 0xfc) | 1;
  224. }
  225. /* Set extended register bits on U4 */
  226. if (sc->sc_ver == 4)
  227. cfgval |= (reg >> 8) << 28;
  228. do {
  229. out32rb(sc->sc_addr, cfgval);
  230. } while (in32rb(sc->sc_addr) != cfgval);
  231. return (1);
  232. }