pci_octeontx.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2018 Marvell International Ltd.
  4. *
  5. * https://spdx.org/licenses
  6. */
  7. #include <dm.h>
  8. #include <errno.h>
  9. #include <fdtdec.h>
  10. #include <log.h>
  11. #include <malloc.h>
  12. #include <pci.h>
  13. #include <asm/global_data.h>
  14. #include <asm/io.h>
  15. #include <linux/ioport.h>
  16. DECLARE_GLOBAL_DATA_PTR;
  17. /*
  18. * This driver supports multiple types of operations / host bridges / busses:
  19. *
  20. * OTX_ECAM: Octeon TX & TX2 ECAM (Enhanced Configuration Access Mechanism)
  21. * Used to access the internal on-chip devices which are connected
  22. * to internal buses
  23. * OTX_PEM: Octeon TX PEM (PCI Express MAC)
  24. * Used to access the external (off-chip) PCI devices
  25. * OTX2_PEM: Octeon TX2 PEM (PCI Express MAC)
  26. * Used to access the external (off-chip) PCI devices
  27. */
  28. enum {
  29. OTX_ECAM,
  30. OTX_PEM,
  31. OTX2_PEM,
  32. };
  33. /**
  34. * struct octeontx_pci - Driver private data
  35. * @type: Device type matched via compatible (e.g. OTX_ECAM etc)
  36. * @cfg: Config resource
  37. * @bus: Bus resource
  38. */
  39. struct octeontx_pci {
  40. unsigned int type;
  41. struct resource cfg;
  42. struct resource bus;
  43. };
  44. static ulong readl_size(uintptr_t addr, enum pci_size_t size)
  45. {
  46. ulong val;
  47. switch (size) {
  48. case PCI_SIZE_8:
  49. val = readb(addr);
  50. break;
  51. case PCI_SIZE_16:
  52. val = readw(addr);
  53. break;
  54. case PCI_SIZE_32:
  55. val = readl(addr);
  56. break;
  57. default:
  58. printf("Invalid size\n");
  59. return -EINVAL;
  60. };
  61. return val;
  62. }
  63. static void writel_size(uintptr_t addr, enum pci_size_t size, ulong valuep)
  64. {
  65. switch (size) {
  66. case PCI_SIZE_8:
  67. writeb(valuep, addr);
  68. break;
  69. case PCI_SIZE_16:
  70. writew(valuep, addr);
  71. break;
  72. case PCI_SIZE_32:
  73. writel(valuep, addr);
  74. break;
  75. default:
  76. printf("Invalid size\n");
  77. };
  78. }
  79. static bool octeontx_bdf_invalid(pci_dev_t bdf)
  80. {
  81. if (PCI_BUS(bdf) == 1 && PCI_DEV(bdf) > 0)
  82. return true;
  83. return false;
  84. }
  85. static int octeontx_ecam_read_config(const struct udevice *bus, pci_dev_t bdf,
  86. uint offset, ulong *valuep,
  87. enum pci_size_t size)
  88. {
  89. struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
  90. struct pci_controller *hose = dev_get_uclass_priv(bus);
  91. uintptr_t address;
  92. address = PCIE_ECAM_OFFSET(PCI_BUS(bdf) + pcie->bus.start - hose->first_busno,
  93. PCI_DEV(bdf), PCI_FUNC(bdf), offset);
  94. *valuep = readl_size(pcie->cfg.start + address, size);
  95. debug("%02x.%02x.%02x: u%d %x -> %lx\n",
  96. PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), size, offset, *valuep);
  97. return 0;
  98. }
  99. static int octeontx_ecam_write_config(struct udevice *bus, pci_dev_t bdf,
  100. uint offset, ulong value,
  101. enum pci_size_t size)
  102. {
  103. struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
  104. struct pci_controller *hose = dev_get_uclass_priv(bus);
  105. uintptr_t address;
  106. address = PCIE_ECAM_OFFSET(PCI_BUS(bdf) + pcie->bus.start - hose->first_busno,
  107. PCI_DEV(bdf), PCI_FUNC(bdf), offset);
  108. writel_size(pcie->cfg.start + address, size, value);
  109. debug("%02x.%02x.%02x: u%d %x <- %lx\n",
  110. PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), size, offset, value);
  111. return 0;
  112. }
  113. static int octeontx_pem_read_config(const struct udevice *bus, pci_dev_t bdf,
  114. uint offset, ulong *valuep,
  115. enum pci_size_t size)
  116. {
  117. struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
  118. struct pci_controller *hose = dev_get_uclass_priv(bus);
  119. uintptr_t address;
  120. u8 hdrtype;
  121. u8 pri_bus = pcie->bus.start + 1 - hose->first_busno;
  122. u32 bus_offs = (pri_bus << 16) | (pri_bus << 8) | (pri_bus << 0);
  123. *valuep = pci_conv_32_to_size(~0UL, offset, size);
  124. if (octeontx_bdf_invalid(bdf))
  125. return -EPERM;
  126. address = PCIE_ECAM_OFFSET(PCI_BUS(bdf) + 1 - hose->first_busno,
  127. PCI_DEV(bdf), PCI_FUNC(bdf), 0) << 4;
  128. *valuep = readl_size(pcie->cfg.start + address + offset, size);
  129. hdrtype = readb(pcie->cfg.start + address + PCI_HEADER_TYPE);
  130. if (hdrtype == PCI_HEADER_TYPE_BRIDGE &&
  131. offset >= PCI_PRIMARY_BUS &&
  132. offset <= PCI_SUBORDINATE_BUS &&
  133. *valuep != pci_conv_32_to_size(~0UL, offset, size))
  134. *valuep -= pci_conv_32_to_size(bus_offs, offset, size);
  135. return 0;
  136. }
  137. static int octeontx_pem_write_config(struct udevice *bus, pci_dev_t bdf,
  138. uint offset, ulong value,
  139. enum pci_size_t size)
  140. {
  141. struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
  142. struct pci_controller *hose = dev_get_uclass_priv(bus);
  143. uintptr_t address;
  144. u8 hdrtype;
  145. u8 pri_bus = pcie->bus.start + 1 - hose->first_busno;
  146. u32 bus_offs = (pri_bus << 16) | (pri_bus << 8) | (pri_bus << 0);
  147. address = PCIE_ECAM_OFFSET(PCI_BUS(bdf) + 1 - hose->first_busno,
  148. PCI_DEV(bdf), PCI_FUNC(bdf), 0) << 4;
  149. hdrtype = readb(pcie->cfg.start + address + PCI_HEADER_TYPE);
  150. if (hdrtype == PCI_HEADER_TYPE_BRIDGE &&
  151. offset >= PCI_PRIMARY_BUS &&
  152. offset <= PCI_SUBORDINATE_BUS &&
  153. value != pci_conv_32_to_size(~0UL, offset, size))
  154. value += pci_conv_32_to_size(bus_offs, offset, size);
  155. if (octeontx_bdf_invalid(bdf))
  156. return -EPERM;
  157. writel_size(pcie->cfg.start + address + offset, size, value);
  158. debug("%02x.%02x.%02x: u%d %x (%lx) <- %lx\n",
  159. PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), size, offset,
  160. address, value);
  161. return 0;
  162. }
  163. static int octeontx2_pem_read_config(const struct udevice *bus, pci_dev_t bdf,
  164. uint offset, ulong *valuep,
  165. enum pci_size_t size)
  166. {
  167. struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
  168. struct pci_controller *hose = dev_get_uclass_priv(bus);
  169. uintptr_t address;
  170. *valuep = pci_conv_32_to_size(~0UL, offset, size);
  171. if (octeontx_bdf_invalid(bdf))
  172. return -EPERM;
  173. address = PCIE_ECAM_OFFSET(PCI_BUS(bdf) + 1 - hose->first_busno,
  174. PCI_DEV(bdf), PCI_FUNC(bdf), offset);
  175. *valuep = readl_size(pcie->cfg.start + address, size);
  176. debug("%02x.%02x.%02x: u%d %x (%lx) -> %lx\n",
  177. PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), size, offset,
  178. address, *valuep);
  179. return 0;
  180. }
  181. static int octeontx2_pem_write_config(struct udevice *bus, pci_dev_t bdf,
  182. uint offset, ulong value,
  183. enum pci_size_t size)
  184. {
  185. struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
  186. struct pci_controller *hose = dev_get_uclass_priv(bus);
  187. uintptr_t address;
  188. if (octeontx_bdf_invalid(bdf))
  189. return -EPERM;
  190. address = PCIE_ECAM_OFFSET(PCI_BUS(bdf) + 1 - hose->first_busno,
  191. PCI_DEV(bdf), PCI_FUNC(bdf), offset);
  192. writel_size(pcie->cfg.start + address, size, value);
  193. debug("%02x.%02x.%02x: u%d %x (%lx) <- %lx\n",
  194. PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), size, offset,
  195. address, value);
  196. return 0;
  197. }
  198. int pci_octeontx_read_config(const struct udevice *bus, pci_dev_t bdf,
  199. uint offset, ulong *valuep,
  200. enum pci_size_t size)
  201. {
  202. struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
  203. int ret = -EIO;
  204. switch (pcie->type) {
  205. case OTX_ECAM:
  206. ret = octeontx_ecam_read_config(bus, bdf, offset, valuep,
  207. size);
  208. break;
  209. case OTX_PEM:
  210. ret = octeontx_pem_read_config(bus, bdf, offset, valuep,
  211. size);
  212. break;
  213. case OTX2_PEM:
  214. ret = octeontx2_pem_read_config(bus, bdf, offset, valuep,
  215. size);
  216. break;
  217. }
  218. return ret;
  219. }
  220. int pci_octeontx_write_config(struct udevice *bus, pci_dev_t bdf,
  221. uint offset, ulong value,
  222. enum pci_size_t size)
  223. {
  224. struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(bus);
  225. int ret = -EIO;
  226. switch (pcie->type) {
  227. case OTX_ECAM:
  228. ret = octeontx_ecam_write_config(bus, bdf, offset, value,
  229. size);
  230. break;
  231. case OTX_PEM:
  232. ret = octeontx_pem_write_config(bus, bdf, offset, value,
  233. size);
  234. break;
  235. case OTX2_PEM:
  236. ret = octeontx2_pem_write_config(bus, bdf, offset, value,
  237. size);
  238. break;
  239. }
  240. return ret;
  241. }
  242. static int pci_octeontx_of_to_plat(struct udevice *dev)
  243. {
  244. return 0;
  245. }
  246. static int pci_octeontx_probe(struct udevice *dev)
  247. {
  248. struct octeontx_pci *pcie = (struct octeontx_pci *)dev_get_priv(dev);
  249. int err;
  250. pcie->type = dev_get_driver_data(dev);
  251. err = dev_read_resource(dev, 0, &pcie->cfg);
  252. if (err) {
  253. debug("Error reading resource: %s\n", fdt_strerror(err));
  254. return err;
  255. }
  256. err = dev_read_pci_bus_range(dev, &pcie->bus);
  257. if (err) {
  258. debug("Error reading resource: %s\n", fdt_strerror(err));
  259. return err;
  260. }
  261. return 0;
  262. }
  263. static const struct dm_pci_ops pci_octeontx_ops = {
  264. .read_config = pci_octeontx_read_config,
  265. .write_config = pci_octeontx_write_config,
  266. };
  267. static const struct udevice_id pci_octeontx_ids[] = {
  268. { .compatible = "cavium,pci-host-thunder-ecam", .data = OTX_ECAM },
  269. { .compatible = "cavium,pci-host-octeontx-ecam", .data = OTX_ECAM },
  270. { .compatible = "pci-host-ecam-generic", .data = OTX_ECAM },
  271. { .compatible = "cavium,pci-host-thunder-pem", .data = OTX_PEM },
  272. { .compatible = "marvell,pci-host-octeontx2-pem", .data = OTX2_PEM },
  273. { }
  274. };
  275. U_BOOT_DRIVER(pci_octeontx) = {
  276. .name = "pci_octeontx",
  277. .id = UCLASS_PCI,
  278. .of_match = pci_octeontx_ids,
  279. .ops = &pci_octeontx_ops,
  280. .of_to_plat = pci_octeontx_of_to_plat,
  281. .probe = pci_octeontx_probe,
  282. .priv_auto = sizeof(struct octeontx_pci),
  283. .flags = DM_FLAG_PRE_RELOC,
  284. };