1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (C) 2020 Stefan Roese <sr@denx.de> 4 */ 5 6#include <dm.h> 7#include <errno.h> 8#include <fdtdec.h> 9#include <log.h> 10#include <pci.h> 11#include <linux/delay.h> 12 13#include <mach/octeon-model.h> 14#include <mach/octeon_pci.h> 15#include <mach/cvmx-regs.h> 16#include <mach/cvmx-pcie.h> 17#include <mach/cvmx-pemx-defs.h> 18 19struct octeon_pcie { 20 void *base; 21 int first_busno; 22 u32 port; 23 struct udevice *dev; 24 int pcie_port; 25}; 26 27static bool octeon_bdf_invalid(pci_dev_t bdf, int first_busno) 28{ 29 /* 30 * In PCIe only a single device (0) can exist on the local bus. 31 * Beyound the local bus, there might be a switch and everything 32 * is possible. 33 */ 34 if ((PCI_BUS(bdf) == first_busno) && (PCI_DEV(bdf) > 0)) 35 return true; 36 37 return false; 38} 39 40static int pcie_octeon_write_config(struct udevice *bus, pci_dev_t bdf, 41 uint offset, ulong value, 42 enum pci_size_t size) 43{ 44 struct octeon_pcie *pcie = dev_get_priv(bus); 45 struct pci_controller *hose = dev_get_uclass_priv(bus); 46 int busno; 47 int port; 48 49 debug("PCIE CFG write: (b,d,f)=(%2d,%2d,%2d) ", 50 PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf)); 51 debug("(addr,size,val)=(0x%04x, %d, 0x%08lx)\n", offset, size, value); 52 53 port = pcie->pcie_port; 54 busno = PCI_BUS(bdf) - hose->first_busno + 1; 55 56 switch (size) { 57 case PCI_SIZE_8: 58 cvmx_pcie_config_write8(port, busno, PCI_DEV(bdf), 59 PCI_FUNC(bdf), offset, value); 60 break; 61 case PCI_SIZE_16: 62 cvmx_pcie_config_write16(port, busno, PCI_DEV(bdf), 63 PCI_FUNC(bdf), offset, value); 64 break; 65 case PCI_SIZE_32: 66 cvmx_pcie_config_write32(port, busno, PCI_DEV(bdf), 67 PCI_FUNC(bdf), offset, value); 68 break; 69 default: 70 printf("Invalid size\n"); 71 }; 72 73 return 0; 74} 75 76static int pcie_octeon_read_config(const struct udevice *bus, pci_dev_t bdf, 77 uint offset, ulong *valuep, 78 enum pci_size_t size) 79{ 80 struct octeon_pcie *pcie = dev_get_priv(bus); 81 struct pci_controller *hose = dev_get_uclass_priv(bus); 82 int busno; 83 int port; 84 85 port = pcie->pcie_port; 86 busno = PCI_BUS(bdf) - hose->first_busno + 1; 87 if (octeon_bdf_invalid(bdf, pcie->first_busno)) { 88 *valuep = pci_get_ff(size); 89 return 0; 90 } 91 92 switch (size) { 93 case PCI_SIZE_8: 94 *valuep = cvmx_pcie_config_read8(port, busno, PCI_DEV(bdf), 95 PCI_FUNC(bdf), offset); 96 break; 97 case PCI_SIZE_16: 98 *valuep = cvmx_pcie_config_read16(port, busno, PCI_DEV(bdf), 99 PCI_FUNC(bdf), offset); 100 break; 101 case PCI_SIZE_32: 102 *valuep = cvmx_pcie_config_read32(port, busno, PCI_DEV(bdf), 103 PCI_FUNC(bdf), offset); 104 break; 105 default: 106 printf("Invalid size\n"); 107 }; 108 109 debug("%02x.%02x.%02x: u%d %x -> %lx\n", 110 PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), size, offset, *valuep); 111 112 return 0; 113} 114 115static int pcie_octeon_probe(struct udevice *dev) 116{ 117 struct octeon_pcie *pcie = dev_get_priv(dev); 118 int node = cvmx_get_node_num(); 119 int pcie_port; 120 int ret = 0; 121 122 /* Get port number, lane number and memory target / attr */ 123 if (ofnode_read_u32(dev_ofnode(dev), "marvell,pcie-port", 124 &pcie->port)) { 125 ret = -ENODEV; 126 goto err; 127 } 128 129 pcie->first_busno = dev_seq(dev); 130 pcie_port = ((node << 4) | pcie->port); 131 ret = cvmx_pcie_rc_initialize(pcie_port); 132 if (ret != 0) 133 return ret; 134 135 return 0; 136 137err: 138 return ret; 139} 140 141static const struct dm_pci_ops pcie_octeon_ops = { 142 .read_config = pcie_octeon_read_config, 143 .write_config = pcie_octeon_write_config, 144}; 145 146static const struct udevice_id pcie_octeon_ids[] = { 147 { .compatible = "marvell,pcie-host-octeon" }, 148 { } 149}; 150 151U_BOOT_DRIVER(pcie_octeon) = { 152 .name = "pcie_octeon", 153 .id = UCLASS_PCI, 154 .of_match = pcie_octeon_ids, 155 .ops = &pcie_octeon_ops, 156 .probe = pcie_octeon_probe, 157 .priv_auto = sizeof(struct octeon_pcie), 158 .flags = DM_FLAG_PRE_RELOC, 159}; 160