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