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 
19 struct octeon_pcie {
20 	void *base;
21 	int first_busno;
22 	u32 port;
23 	struct udevice *dev;
24 	int pcie_port;
25 };
26 
octeon_bdf_invalid(pci_dev_t bdf,int first_busno)27 static 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 
pcie_octeon_write_config(struct udevice * bus,pci_dev_t bdf,uint offset,ulong value,enum pci_size_t size)40 static 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 
pcie_octeon_read_config(const struct udevice * bus,pci_dev_t bdf,uint offset,ulong * valuep,enum pci_size_t size)76 static 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 
pcie_octeon_probe(struct udevice * dev)115 static 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 
137 err:
138 	return ret;
139 }
140 
141 static const struct dm_pci_ops pcie_octeon_ops = {
142 	.read_config = pcie_octeon_read_config,
143 	.write_config = pcie_octeon_write_config,
144 };
145 
146 static const struct udevice_id pcie_octeon_ids[] = {
147 	{ .compatible = "marvell,pcie-host-octeon" },
148 	{ }
149 };
150 
151 U_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