Commit | Line | Data |
---|---|---|
ca585cf9 | 1 | /* |
9ec88b60 | 2 | * Copyright (c) 2011-2016 Zhang, Keguang <keguang.zhang@gmail.com> |
ca585cf9 | 3 | * |
70342287 RB |
4 | * This program is free software; you can redistribute it and/or modify it |
5 | * under the terms of the GNU General Public License as published by the | |
ca585cf9 KC |
6 | * Free Software Foundation; either version 2 of the License, or (at your |
7 | * option) any later version. | |
8 | */ | |
9 | ||
10 | #include <linux/clk.h> | |
11 | #include <linux/dma-mapping.h> | |
12 | #include <linux/err.h> | |
9ec88b60 KC |
13 | #include <linux/mtd/partitions.h> |
14 | #include <linux/sizes.h> | |
ca585cf9 KC |
15 | #include <linux/phy.h> |
16 | #include <linux/serial_8250.h> | |
17 | #include <linux/stmmac.h> | |
afe046be | 18 | #include <linux/usb/ehci_pdriver.h> |
ca585cf9 | 19 | |
0672c01b | 20 | #include <platform.h> |
ca585cf9 | 21 | #include <loongson1.h> |
9ec88b60 KC |
22 | #include <cpufreq.h> |
23 | #include <dma.h> | |
24 | #include <nand.h> | |
ca585cf9 | 25 | |
f29ad10d | 26 | /* 8250/16550 compatible UART */ |
ca585cf9 KC |
27 | #define LS1X_UART(_id) \ |
28 | { \ | |
29 | .mapbase = LS1X_UART ## _id ## _BASE, \ | |
30 | .irq = LS1X_UART ## _id ## _IRQ, \ | |
31 | .iotype = UPIO_MEM, \ | |
70342287 | 32 | .flags = UPF_IOREMAP | UPF_FIXED_TYPE, \ |
ca585cf9 KC |
33 | .type = PORT_16550A, \ |
34 | } | |
35 | ||
f29ad10d | 36 | static struct plat_serial8250_port ls1x_serial8250_pdata[] = { |
ca585cf9 KC |
37 | LS1X_UART(0), |
38 | LS1X_UART(1), | |
39 | LS1X_UART(2), | |
40 | LS1X_UART(3), | |
41 | {}, | |
42 | }; | |
43 | ||
f29ad10d | 44 | struct platform_device ls1x_uart_pdev = { |
ca585cf9 KC |
45 | .name = "serial8250", |
46 | .id = PLAT8250_DEV_PLATFORM, | |
47 | .dev = { | |
f29ad10d | 48 | .platform_data = ls1x_serial8250_pdata, |
ca585cf9 KC |
49 | }, |
50 | }; | |
51 | ||
9ec88b60 | 52 | void __init ls1x_serial_set_uartclk(struct platform_device *pdev) |
ca585cf9 KC |
53 | { |
54 | struct clk *clk; | |
55 | struct plat_serial8250_port *p; | |
56 | ||
f29ad10d KC |
57 | clk = clk_get(&pdev->dev, pdev->name); |
58 | if (IS_ERR(clk)) { | |
59 | pr_err("unable to get %s clock, err=%ld", | |
60 | pdev->name, PTR_ERR(clk)); | |
61 | return; | |
62 | } | |
63 | clk_prepare_enable(clk); | |
ca585cf9 | 64 | |
44607645 | 65 | for (p = pdev->dev.platform_data; p->flags != 0; ++p) |
ca585cf9 KC |
66 | p->uartclk = clk_get_rate(clk); |
67 | } | |
68 | ||
f29ad10d KC |
69 | /* CPUFreq */ |
70 | static struct plat_ls1x_cpufreq ls1x_cpufreq_pdata = { | |
71 | .clk_name = "cpu_clk", | |
72 | .osc_clk_name = "osc_33m_clk", | |
73 | .max_freq = 266 * 1000, | |
74 | .min_freq = 33 * 1000, | |
75 | }; | |
76 | ||
77 | struct platform_device ls1x_cpufreq_pdev = { | |
78 | .name = "ls1x-cpufreq", | |
79 | .dev = { | |
80 | .platform_data = &ls1x_cpufreq_pdata, | |
81 | }, | |
82 | }; | |
83 | ||
9ec88b60 KC |
84 | /* DMA */ |
85 | static struct resource ls1x_dma_resources[] = { | |
86 | [0] = { | |
87 | .start = LS1X_DMAC_BASE, | |
88 | .end = LS1X_DMAC_BASE + SZ_4 - 1, | |
89 | .flags = IORESOURCE_MEM, | |
90 | }, | |
91 | [1] = { | |
92 | .start = LS1X_DMA0_IRQ, | |
93 | .end = LS1X_DMA0_IRQ, | |
94 | .flags = IORESOURCE_IRQ, | |
95 | }, | |
96 | [2] = { | |
97 | .start = LS1X_DMA1_IRQ, | |
98 | .end = LS1X_DMA1_IRQ, | |
99 | .flags = IORESOURCE_IRQ, | |
100 | }, | |
101 | [3] = { | |
102 | .start = LS1X_DMA2_IRQ, | |
103 | .end = LS1X_DMA2_IRQ, | |
104 | .flags = IORESOURCE_IRQ, | |
105 | }, | |
106 | }; | |
107 | ||
108 | struct platform_device ls1x_dma_pdev = { | |
109 | .name = "ls1x-dma", | |
110 | .id = -1, | |
111 | .num_resources = ARRAY_SIZE(ls1x_dma_resources), | |
112 | .resource = ls1x_dma_resources, | |
113 | }; | |
114 | ||
115 | void __init ls1x_dma_set_platdata(struct plat_ls1x_dma *pdata) | |
116 | { | |
117 | ls1x_dma_pdev.dev.platform_data = pdata; | |
118 | } | |
119 | ||
ca585cf9 | 120 | /* Synopsys Ethernet GMAC */ |
f29ad10d KC |
121 | static struct stmmac_mdio_bus_data ls1x_mdio_bus_data = { |
122 | .phy_mask = 0, | |
123 | }; | |
124 | ||
125 | static struct stmmac_dma_cfg ls1x_eth_dma_cfg = { | |
126 | .pbl = 1, | |
127 | }; | |
128 | ||
129 | int ls1x_eth_mux_init(struct platform_device *pdev, void *priv) | |
130 | { | |
131 | struct plat_stmmacenet_data *plat_dat = NULL; | |
132 | u32 val; | |
133 | ||
134 | val = __raw_readl(LS1X_MUX_CTRL1); | |
135 | ||
0672c01b | 136 | #if defined(CONFIG_LOONGSON1_LS1B) |
f29ad10d KC |
137 | plat_dat = dev_get_platdata(&pdev->dev); |
138 | if (plat_dat->bus_id) { | |
139 | __raw_writel(__raw_readl(LS1X_MUX_CTRL0) | GMAC1_USE_UART1 | | |
140 | GMAC1_USE_UART0, LS1X_MUX_CTRL0); | |
141 | switch (plat_dat->interface) { | |
142 | case PHY_INTERFACE_MODE_RGMII: | |
143 | val &= ~(GMAC1_USE_TXCLK | GMAC1_USE_PWM23); | |
144 | break; | |
145 | case PHY_INTERFACE_MODE_MII: | |
146 | val |= (GMAC1_USE_TXCLK | GMAC1_USE_PWM23); | |
147 | break; | |
148 | default: | |
149 | pr_err("unsupported mii mode %d\n", | |
150 | plat_dat->interface); | |
151 | return -ENOTSUPP; | |
152 | } | |
153 | val &= ~GMAC1_SHUT; | |
154 | } else { | |
155 | switch (plat_dat->interface) { | |
156 | case PHY_INTERFACE_MODE_RGMII: | |
157 | val &= ~(GMAC0_USE_TXCLK | GMAC0_USE_PWM01); | |
158 | break; | |
159 | case PHY_INTERFACE_MODE_MII: | |
160 | val |= (GMAC0_USE_TXCLK | GMAC0_USE_PWM01); | |
161 | break; | |
162 | default: | |
163 | pr_err("unsupported mii mode %d\n", | |
164 | plat_dat->interface); | |
165 | return -ENOTSUPP; | |
166 | } | |
167 | val &= ~GMAC0_SHUT; | |
168 | } | |
169 | __raw_writel(val, LS1X_MUX_CTRL1); | |
0672c01b YL |
170 | #elif defined(CONFIG_LOONGSON1_LS1C) |
171 | plat_dat = dev_get_platdata(&pdev->dev); | |
172 | ||
173 | val &= ~PHY_INTF_SELI; | |
174 | if (plat_dat->interface == PHY_INTERFACE_MODE_RMII) | |
175 | val |= 0x4 << PHY_INTF_SELI_SHIFT; | |
176 | __raw_writel(val, LS1X_MUX_CTRL1); | |
177 | ||
178 | val = __raw_readl(LS1X_MUX_CTRL0); | |
179 | __raw_writel(val & (~GMAC_SHUT), LS1X_MUX_CTRL0); | |
180 | #endif | |
f29ad10d KC |
181 | |
182 | return 0; | |
183 | } | |
184 | ||
185 | static struct plat_stmmacenet_data ls1x_eth0_pdata = { | |
186 | .bus_id = 0, | |
187 | .phy_addr = -1, | |
0672c01b | 188 | #if defined(CONFIG_LOONGSON1_LS1B) |
f29ad10d | 189 | .interface = PHY_INTERFACE_MODE_MII, |
0672c01b YL |
190 | #elif defined(CONFIG_LOONGSON1_LS1C) |
191 | .interface = PHY_INTERFACE_MODE_RMII, | |
192 | #endif | |
f29ad10d KC |
193 | .mdio_bus_data = &ls1x_mdio_bus_data, |
194 | .dma_cfg = &ls1x_eth_dma_cfg, | |
195 | .has_gmac = 1, | |
196 | .tx_coe = 1, | |
197 | .init = ls1x_eth_mux_init, | |
198 | }; | |
199 | ||
ca585cf9 KC |
200 | static struct resource ls1x_eth0_resources[] = { |
201 | [0] = { | |
202 | .start = LS1X_GMAC0_BASE, | |
203 | .end = LS1X_GMAC0_BASE + SZ_64K - 1, | |
204 | .flags = IORESOURCE_MEM, | |
205 | }, | |
206 | [1] = { | |
207 | .name = "macirq", | |
208 | .start = LS1X_GMAC0_IRQ, | |
209 | .flags = IORESOURCE_IRQ, | |
210 | }, | |
211 | }; | |
212 | ||
f29ad10d KC |
213 | struct platform_device ls1x_eth0_pdev = { |
214 | .name = "stmmaceth", | |
215 | .id = 0, | |
216 | .num_resources = ARRAY_SIZE(ls1x_eth0_resources), | |
217 | .resource = ls1x_eth0_resources, | |
218 | .dev = { | |
219 | .platform_data = &ls1x_eth0_pdata, | |
220 | }, | |
ca585cf9 KC |
221 | }; |
222 | ||
0672c01b | 223 | #ifdef CONFIG_LOONGSON1_LS1B |
f29ad10d KC |
224 | static struct plat_stmmacenet_data ls1x_eth1_pdata = { |
225 | .bus_id = 1, | |
ca585cf9 | 226 | .phy_addr = -1, |
f29ad10d | 227 | .interface = PHY_INTERFACE_MODE_MII, |
ca585cf9 | 228 | .mdio_bus_data = &ls1x_mdio_bus_data, |
f29ad10d | 229 | .dma_cfg = &ls1x_eth_dma_cfg, |
ca585cf9 KC |
230 | .has_gmac = 1, |
231 | .tx_coe = 1, | |
f29ad10d | 232 | .init = ls1x_eth_mux_init, |
ca585cf9 KC |
233 | }; |
234 | ||
f29ad10d KC |
235 | static struct resource ls1x_eth1_resources[] = { |
236 | [0] = { | |
237 | .start = LS1X_GMAC1_BASE, | |
238 | .end = LS1X_GMAC1_BASE + SZ_64K - 1, | |
239 | .flags = IORESOURCE_MEM, | |
240 | }, | |
241 | [1] = { | |
242 | .name = "macirq", | |
243 | .start = LS1X_GMAC1_IRQ, | |
244 | .flags = IORESOURCE_IRQ, | |
245 | }, | |
246 | }; | |
247 | ||
248 | struct platform_device ls1x_eth1_pdev = { | |
ca585cf9 | 249 | .name = "stmmaceth", |
f29ad10d KC |
250 | .id = 1, |
251 | .num_resources = ARRAY_SIZE(ls1x_eth1_resources), | |
252 | .resource = ls1x_eth1_resources, | |
ca585cf9 | 253 | .dev = { |
f29ad10d | 254 | .platform_data = &ls1x_eth1_pdata, |
ca585cf9 KC |
255 | }, |
256 | }; | |
0672c01b | 257 | #endif /* CONFIG_LOONGSON1_LS1B */ |
ca585cf9 | 258 | |
9ec88b60 KC |
259 | /* GPIO */ |
260 | static struct resource ls1x_gpio0_resources[] = { | |
261 | [0] = { | |
262 | .start = LS1X_GPIO0_BASE, | |
263 | .end = LS1X_GPIO0_BASE + SZ_4 - 1, | |
264 | .flags = IORESOURCE_MEM, | |
265 | }, | |
266 | }; | |
267 | ||
268 | struct platform_device ls1x_gpio0_pdev = { | |
269 | .name = "ls1x-gpio", | |
270 | .id = 0, | |
271 | .num_resources = ARRAY_SIZE(ls1x_gpio0_resources), | |
272 | .resource = ls1x_gpio0_resources, | |
273 | }; | |
274 | ||
275 | static struct resource ls1x_gpio1_resources[] = { | |
276 | [0] = { | |
277 | .start = LS1X_GPIO1_BASE, | |
278 | .end = LS1X_GPIO1_BASE + SZ_4 - 1, | |
279 | .flags = IORESOURCE_MEM, | |
280 | }, | |
281 | }; | |
282 | ||
283 | struct platform_device ls1x_gpio1_pdev = { | |
284 | .name = "ls1x-gpio", | |
285 | .id = 1, | |
286 | .num_resources = ARRAY_SIZE(ls1x_gpio1_resources), | |
287 | .resource = ls1x_gpio1_resources, | |
288 | }; | |
289 | ||
290 | /* NAND Flash */ | |
291 | static struct resource ls1x_nand_resources[] = { | |
292 | [0] = { | |
293 | .start = LS1X_NAND_BASE, | |
294 | .end = LS1X_NAND_BASE + SZ_32 - 1, | |
295 | .flags = IORESOURCE_MEM, | |
296 | }, | |
297 | [1] = { | |
298 | /* DMA channel 0 is dedicated to NAND */ | |
299 | .start = LS1X_DMA_CHANNEL0, | |
300 | .end = LS1X_DMA_CHANNEL0, | |
301 | .flags = IORESOURCE_DMA, | |
302 | }, | |
303 | }; | |
304 | ||
305 | struct platform_device ls1x_nand_pdev = { | |
306 | .name = "ls1x-nand", | |
307 | .id = -1, | |
308 | .num_resources = ARRAY_SIZE(ls1x_nand_resources), | |
309 | .resource = ls1x_nand_resources, | |
310 | }; | |
311 | ||
312 | void __init ls1x_nand_set_platdata(struct plat_ls1x_nand *pdata) | |
313 | { | |
314 | ls1x_nand_pdev.dev.platform_data = pdata; | |
315 | } | |
316 | ||
ca585cf9 KC |
317 | /* USB EHCI */ |
318 | static u64 ls1x_ehci_dmamask = DMA_BIT_MASK(32); | |
319 | ||
320 | static struct resource ls1x_ehci_resources[] = { | |
321 | [0] = { | |
322 | .start = LS1X_EHCI_BASE, | |
323 | .end = LS1X_EHCI_BASE + SZ_32K - 1, | |
324 | .flags = IORESOURCE_MEM, | |
325 | }, | |
326 | [1] = { | |
327 | .start = LS1X_EHCI_IRQ, | |
328 | .flags = IORESOURCE_IRQ, | |
329 | }, | |
330 | }; | |
331 | ||
afe046be | 332 | static struct usb_ehci_pdata ls1x_ehci_pdata = { |
afe046be FF |
333 | }; |
334 | ||
f29ad10d | 335 | struct platform_device ls1x_ehci_pdev = { |
afe046be | 336 | .name = "ehci-platform", |
ca585cf9 KC |
337 | .id = -1, |
338 | .num_resources = ARRAY_SIZE(ls1x_ehci_resources), | |
339 | .resource = ls1x_ehci_resources, | |
340 | .dev = { | |
341 | .dma_mask = &ls1x_ehci_dmamask, | |
afe046be | 342 | .platform_data = &ls1x_ehci_pdata, |
ca585cf9 KC |
343 | }, |
344 | }; | |
345 | ||
346 | /* Real Time Clock */ | |
f29ad10d | 347 | struct platform_device ls1x_rtc_pdev = { |
ca585cf9 KC |
348 | .name = "ls1x-rtc", |
349 | .id = -1, | |
350 | }; |