]>
Commit | Line | Data |
---|---|---|
5f14f7d7 MV |
1 | /* |
2 | * Renesas RCar Gen2 PCIEC driver | |
3 | * | |
4 | * Copyright (C) 2018 Marek Vasut <marek.vasut@gmail.com> | |
5 | * | |
6 | * SPDX-License-Identifier: GPL-2.0 | |
7 | */ | |
8 | ||
9 | #include <common.h> | |
10 | #include <asm/io.h> | |
11 | #include <clk.h> | |
12 | #include <dm.h> | |
13 | #include <errno.h> | |
14 | #include <pci.h> | |
15 | ||
16 | /* AHB-PCI Bridge PCI communication registers */ | |
17 | #define RCAR_AHBPCI_PCICOM_OFFSET 0x800 | |
18 | ||
19 | #define RCAR_PCIAHB_WIN1_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x00) | |
20 | #define RCAR_PCIAHB_WIN2_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x04) | |
21 | #define RCAR_PCIAHB_PREFETCH0 0x0 | |
22 | #define RCAR_PCIAHB_PREFETCH4 0x1 | |
23 | #define RCAR_PCIAHB_PREFETCH8 0x2 | |
24 | #define RCAR_PCIAHB_PREFETCH16 0x3 | |
25 | ||
26 | #define RCAR_AHBPCI_WIN1_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x10) | |
27 | #define RCAR_AHBPCI_WIN2_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x14) | |
28 | #define RCAR_AHBPCI_WIN_CTR_MEM (3 << 1) | |
29 | #define RCAR_AHBPCI_WIN_CTR_CFG (5 << 1) | |
30 | #define RCAR_AHBPCI_WIN1_HOST BIT(30) | |
31 | #define RCAR_AHBPCI_WIN1_DEVICE BIT(31) | |
32 | ||
33 | #define RCAR_PCI_INT_ENABLE_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x20) | |
34 | #define RCAR_PCI_INT_STATUS_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x24) | |
35 | #define RCAR_PCI_INT_SIGTABORT BIT(0) | |
36 | #define RCAR_PCI_INT_SIGRETABORT BIT(1) | |
37 | #define RCAR_PCI_INT_REMABORT BIT(2) | |
38 | #define RCAR_PCI_INT_PERR BIT(3) | |
39 | #define RCAR_PCI_INT_SIGSERR BIT(4) | |
40 | #define RCAR_PCI_INT_RESERR BIT(5) | |
41 | #define RCAR_PCI_INT_WIN1ERR BIT(12) | |
42 | #define RCAR_PCI_INT_WIN2ERR BIT(13) | |
43 | #define RCAR_PCI_INT_A BIT(16) | |
44 | #define RCAR_PCI_INT_B BIT(17) | |
45 | #define RCAR_PCI_INT_PME BIT(19) | |
46 | #define RCAR_PCI_INT_ALLERRORS (RCAR_PCI_INT_SIGTABORT | \ | |
47 | RCAR_PCI_INT_SIGRETABORT | \ | |
48 | RCAR_PCI_INT_SIGRETABORT | \ | |
49 | RCAR_PCI_INT_REMABORT | \ | |
50 | RCAR_PCI_INT_PERR | \ | |
51 | RCAR_PCI_INT_SIGSERR | \ | |
52 | RCAR_PCI_INT_RESERR | \ | |
53 | RCAR_PCI_INT_WIN1ERR | \ | |
54 | RCAR_PCI_INT_WIN2ERR) | |
55 | ||
56 | #define RCAR_AHB_BUS_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x30) | |
57 | #define RCAR_AHB_BUS_MMODE_HTRANS BIT(0) | |
58 | #define RCAR_AHB_BUS_MMODE_BYTE_BURST BIT(1) | |
59 | #define RCAR_AHB_BUS_MMODE_WR_INCR BIT(2) | |
60 | #define RCAR_AHB_BUS_MMODE_HBUS_REQ BIT(7) | |
61 | #define RCAR_AHB_BUS_SMODE_READYCTR BIT(17) | |
62 | #define RCAR_AHB_BUS_MODE (RCAR_AHB_BUS_MMODE_HTRANS | \ | |
63 | RCAR_AHB_BUS_MMODE_BYTE_BURST | \ | |
64 | RCAR_AHB_BUS_MMODE_WR_INCR | \ | |
65 | RCAR_AHB_BUS_MMODE_HBUS_REQ | \ | |
66 | RCAR_AHB_BUS_SMODE_READYCTR) | |
67 | ||
68 | #define RCAR_USBCTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x34) | |
69 | #define RCAR_USBCTR_USBH_RST BIT(0) | |
70 | #define RCAR_USBCTR_PCICLK_MASK BIT(1) | |
71 | #define RCAR_USBCTR_PLL_RST BIT(2) | |
72 | #define RCAR_USBCTR_DIRPD BIT(8) | |
73 | #define RCAR_USBCTR_PCIAHB_WIN2_EN BIT(9) | |
74 | #define RCAR_USBCTR_PCIAHB_WIN1_256M (0 << 10) | |
75 | #define RCAR_USBCTR_PCIAHB_WIN1_512M (1 << 10) | |
76 | #define RCAR_USBCTR_PCIAHB_WIN1_1G (2 << 10) | |
77 | #define RCAR_USBCTR_PCIAHB_WIN1_2G (3 << 10) | |
78 | #define RCAR_USBCTR_PCIAHB_WIN1_MASK (3 << 10) | |
79 | ||
80 | #define RCAR_PCI_ARBITER_CTR_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x40) | |
81 | #define RCAR_PCI_ARBITER_PCIREQ0 BIT(0) | |
82 | #define RCAR_PCI_ARBITER_PCIREQ1 BIT(1) | |
83 | #define RCAR_PCI_ARBITER_PCIBP_MODE BIT(12) | |
84 | ||
85 | #define RCAR_PCI_UNIT_REV_REG (RCAR_AHBPCI_PCICOM_OFFSET + 0x48) | |
86 | ||
87 | struct rcar_gen2_pci_priv { | |
88 | fdt_addr_t cfg_base; | |
89 | fdt_addr_t mem_base; | |
90 | }; | |
91 | ||
92 | static int rcar_gen2_pci_addr_valid(pci_dev_t d, uint offset) | |
93 | { | |
94 | u32 slot; | |
95 | ||
96 | if (PCI_FUNC(d)) | |
97 | return -EINVAL; | |
98 | ||
99 | /* Only one EHCI/OHCI device built-in */ | |
100 | slot = PCI_DEV(d); | |
101 | if (slot > 2) | |
102 | return -EINVAL; | |
103 | ||
104 | /* bridge logic only has registers to 0x40 */ | |
105 | if (slot == 0x0 && offset >= 0x40) | |
106 | return -EINVAL; | |
107 | ||
108 | return 0; | |
109 | } | |
110 | ||
111 | static u32 get_bus_address(struct udevice *dev, pci_dev_t bdf, u32 offset) | |
112 | { | |
113 | struct rcar_gen2_pci_priv *priv = dev_get_priv(dev); | |
114 | ||
115 | return priv->cfg_base + (PCI_DEV(bdf) >> 1) * 0x100 + (offset & ~3); | |
116 | } | |
117 | ||
118 | static u32 setup_bus_address(struct udevice *dev, pci_dev_t bdf, u32 offset) | |
119 | { | |
120 | struct rcar_gen2_pci_priv *priv = dev_get_priv(dev); | |
121 | u32 reg; | |
122 | ||
123 | reg = PCI_DEV(bdf) ? RCAR_AHBPCI_WIN1_DEVICE : RCAR_AHBPCI_WIN1_HOST; | |
124 | reg |= RCAR_AHBPCI_WIN_CTR_CFG; | |
125 | writel(reg, priv->cfg_base + RCAR_AHBPCI_WIN1_CTR_REG); | |
126 | ||
127 | return get_bus_address(dev, bdf, offset); | |
128 | } | |
129 | ||
130 | static int rcar_gen2_pci_read_config(struct udevice *dev, pci_dev_t bdf, | |
131 | uint offset, ulong *value, | |
132 | enum pci_size_t size) | |
133 | { | |
134 | u32 addr, reg; | |
135 | int ret; | |
136 | ||
137 | ret = rcar_gen2_pci_addr_valid(bdf, offset); | |
138 | if (ret) { | |
139 | *value = pci_get_ff(size); | |
140 | return 0; | |
141 | } | |
142 | ||
143 | addr = get_bus_address(dev, bdf, offset); | |
144 | reg = readl(addr); | |
145 | *value = pci_conv_32_to_size(reg, offset, size); | |
146 | ||
147 | return 0; | |
148 | } | |
149 | ||
150 | static int rcar_gen2_pci_write_config(struct udevice *dev, pci_dev_t bdf, | |
151 | uint offset, ulong value, | |
152 | enum pci_size_t size) | |
153 | { | |
154 | u32 addr, reg, old; | |
155 | int ret; | |
156 | ||
157 | ret = rcar_gen2_pci_addr_valid(bdf, offset); | |
158 | if (ret) | |
159 | return ret; | |
160 | ||
161 | addr = get_bus_address(dev, bdf, offset); | |
162 | ||
163 | old = readl(addr); | |
164 | reg = pci_conv_size_to_32(old, value, offset, size); | |
165 | writel(reg, addr); | |
166 | ||
167 | return 0; | |
168 | } | |
169 | ||
170 | static int rcar_gen2_pci_probe(struct udevice *dev) | |
171 | { | |
172 | struct rcar_gen2_pci_priv *priv = dev_get_priv(dev); | |
173 | struct clk pci_clk; | |
174 | u32 devad; | |
175 | int ret; | |
176 | ||
177 | ret = clk_get_by_index(dev, 0, &pci_clk); | |
178 | if (ret) | |
179 | return ret; | |
180 | ||
181 | ret = clk_enable(&pci_clk); | |
182 | if (ret) | |
183 | return ret; | |
184 | ||
185 | /* Clock & Reset & Direct Power Down */ | |
186 | clrsetbits_le32(priv->cfg_base + RCAR_USBCTR_REG, | |
187 | RCAR_USBCTR_DIRPD | RCAR_USBCTR_PCICLK_MASK | | |
188 | RCAR_USBCTR_USBH_RST, | |
189 | RCAR_USBCTR_PCIAHB_WIN1_1G); | |
190 | clrbits_le32(priv->cfg_base + RCAR_USBCTR_REG, RCAR_USBCTR_PLL_RST); | |
191 | ||
192 | /* AHB-PCI Bridge Communication Registers */ | |
193 | writel(RCAR_AHB_BUS_MODE, priv->cfg_base + RCAR_AHB_BUS_CTR_REG); | |
194 | writel((CONFIG_SYS_SDRAM_BASE & 0xf0000000) | RCAR_PCIAHB_PREFETCH16, | |
195 | priv->cfg_base + RCAR_PCIAHB_WIN1_CTR_REG); | |
196 | writel(0xf0000000 | RCAR_PCIAHB_PREFETCH16, | |
197 | priv->cfg_base + RCAR_PCIAHB_WIN2_CTR_REG); | |
198 | writel(priv->mem_base | RCAR_AHBPCI_WIN_CTR_MEM, | |
199 | priv->cfg_base + RCAR_AHBPCI_WIN2_CTR_REG); | |
200 | setbits_le32(priv->cfg_base + RCAR_PCI_ARBITER_CTR_REG, | |
201 | RCAR_PCI_ARBITER_PCIREQ0 | RCAR_PCI_ARBITER_PCIREQ1 | | |
202 | RCAR_PCI_ARBITER_PCIBP_MODE); | |
203 | ||
204 | /* PCI Configuration Registers for AHBPCI */ | |
205 | devad = setup_bus_address(dev, PCI_BDF(0, 0, 0), 0); | |
206 | writel(priv->cfg_base + 0x800, devad + PCI_BASE_ADDRESS_0); | |
207 | writel(CONFIG_SYS_SDRAM_BASE & 0xf0000000, devad + PCI_BASE_ADDRESS_1); | |
208 | writel(0xf0000000, devad + PCI_BASE_ADDRESS_2); | |
209 | writel(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | | |
210 | PCI_COMMAND_PARITY | PCI_COMMAND_SERR, | |
211 | devad + PCI_COMMAND); | |
212 | ||
213 | /* PCI Configuration Registers for OHCI */ | |
214 | devad = setup_bus_address(dev, PCI_BDF(0, 1, 0), 0); | |
215 | writel(priv->mem_base + 0x0, devad + PCI_BASE_ADDRESS_0); | |
216 | writel(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | | |
217 | PCI_COMMAND_PARITY | PCI_COMMAND_SERR, | |
218 | devad + PCI_COMMAND); | |
219 | ||
220 | /* PCI Configuration Registers for EHCI */ | |
221 | devad = setup_bus_address(dev, PCI_BDF(0, 2, 0), 0); | |
222 | writel(priv->mem_base + 0x1000, devad + PCI_BASE_ADDRESS_0); | |
223 | writel(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | | |
224 | PCI_COMMAND_PARITY | PCI_COMMAND_SERR, | |
225 | devad + PCI_COMMAND); | |
226 | ||
227 | /* Enable PCI interrupt */ | |
228 | setbits_le32(priv->cfg_base + RCAR_PCI_INT_ENABLE_REG, | |
229 | RCAR_PCI_INT_A | RCAR_PCI_INT_B | RCAR_PCI_INT_PME); | |
230 | ||
231 | return 0; | |
232 | } | |
233 | ||
234 | static int rcar_gen2_pci_ofdata_to_platdata(struct udevice *dev) | |
235 | { | |
236 | struct rcar_gen2_pci_priv *priv = dev_get_priv(dev); | |
237 | ||
238 | priv->cfg_base = devfdt_get_addr_index(dev, 0); | |
239 | priv->mem_base = devfdt_get_addr_index(dev, 1); | |
240 | if (!priv->cfg_base || !priv->mem_base) | |
241 | return -EINVAL; | |
242 | ||
243 | return 0; | |
244 | } | |
245 | ||
246 | static const struct dm_pci_ops rcar_gen2_pci_ops = { | |
247 | .read_config = rcar_gen2_pci_read_config, | |
248 | .write_config = rcar_gen2_pci_write_config, | |
249 | }; | |
250 | ||
251 | static const struct udevice_id rcar_gen2_pci_ids[] = { | |
252 | { .compatible = "renesas,pci-rcar-gen2" }, | |
253 | { } | |
254 | }; | |
255 | ||
256 | U_BOOT_DRIVER(rcar_gen2_pci) = { | |
257 | .name = "rcar_gen2_pci", | |
258 | .id = UCLASS_PCI, | |
259 | .of_match = rcar_gen2_pci_ids, | |
260 | .ops = &rcar_gen2_pci_ops, | |
261 | .probe = rcar_gen2_pci_probe, | |
262 | .ofdata_to_platdata = rcar_gen2_pci_ofdata_to_platdata, | |
263 | .priv_auto_alloc_size = sizeof(struct rcar_gen2_pci_priv), | |
264 | }; |