1 /*
2  * Copyright (c) 2011-2016 Zhang, Keguang <keguang.zhang@gmail.com>
3  *
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
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>
13 #include <linux/mtd/partitions.h>
14 #include <linux/sizes.h>
15 #include <linux/phy.h>
16 #include <linux/serial_8250.h>
17 #include <linux/stmmac.h>
18 #include <linux/usb/ehci_pdriver.h>
19 
20 #include <platform.h>
21 #include <loongson1.h>
22 #include <cpufreq.h>
23 #include <dma.h>
24 #include <nand.h>
25 
26 /* 8250/16550 compatible UART */
27 #define LS1X_UART(_id)						\
28 	{							\
29 		.mapbase	= LS1X_UART ## _id ## _BASE,	\
30 		.irq		= LS1X_UART ## _id ## _IRQ,	\
31 		.iotype		= UPIO_MEM,			\
32 		.flags		= UPF_IOREMAP | UPF_FIXED_TYPE, \
33 		.type		= PORT_16550A,			\
34 	}
35 
36 static struct plat_serial8250_port ls1x_serial8250_pdata[] = {
37 	LS1X_UART(0),
38 	LS1X_UART(1),
39 	LS1X_UART(2),
40 	LS1X_UART(3),
41 	{},
42 };
43 
44 struct platform_device ls1x_uart_pdev = {
45 	.name		= "serial8250",
46 	.id		= PLAT8250_DEV_PLATFORM,
47 	.dev		= {
48 		.platform_data = ls1x_serial8250_pdata,
49 	},
50 };
51 
52 void __init ls1x_serial_set_uartclk(struct platform_device *pdev)
53 {
54 	struct clk *clk;
55 	struct plat_serial8250_port *p;
56 
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);
64 
65 	for (p = pdev->dev.platform_data; p->flags != 0; ++p)
66 		p->uartclk = clk_get_rate(clk);
67 }
68 
69 /* CPUFreq */
70 static struct plat_ls1x_cpufreq ls1x_cpufreq_pdata = {
71 	.clk_name	= "cpu_clk",
72 	.osc_clk_name	= "osc_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 
84 /* Synopsys Ethernet GMAC */
85 static struct stmmac_mdio_bus_data ls1x_mdio_bus_data = {
86 	.phy_mask	= 0,
87 };
88 
89 static struct stmmac_dma_cfg ls1x_eth_dma_cfg = {
90 	.pbl		= 1,
91 };
92 
93 int ls1x_eth_mux_init(struct platform_device *pdev, void *priv)
94 {
95 	struct plat_stmmacenet_data *plat_dat = NULL;
96 	u32 val;
97 
98 	val = __raw_readl(LS1X_MUX_CTRL1);
99 
100 #if defined(CONFIG_LOONGSON1_LS1B)
101 	plat_dat = dev_get_platdata(&pdev->dev);
102 	if (plat_dat->bus_id) {
103 		__raw_writel(__raw_readl(LS1X_MUX_CTRL0) | GMAC1_USE_UART1 |
104 			     GMAC1_USE_UART0, LS1X_MUX_CTRL0);
105 		switch (plat_dat->interface) {
106 		case PHY_INTERFACE_MODE_RGMII:
107 			val &= ~(GMAC1_USE_TXCLK | GMAC1_USE_PWM23);
108 			break;
109 		case PHY_INTERFACE_MODE_MII:
110 			val |= (GMAC1_USE_TXCLK | GMAC1_USE_PWM23);
111 			break;
112 		default:
113 			pr_err("unsupported mii mode %d\n",
114 			       plat_dat->interface);
115 			return -ENOTSUPP;
116 		}
117 		val &= ~GMAC1_SHUT;
118 	} else {
119 		switch (plat_dat->interface) {
120 		case PHY_INTERFACE_MODE_RGMII:
121 			val &= ~(GMAC0_USE_TXCLK | GMAC0_USE_PWM01);
122 			break;
123 		case PHY_INTERFACE_MODE_MII:
124 			val |= (GMAC0_USE_TXCLK | GMAC0_USE_PWM01);
125 			break;
126 		default:
127 			pr_err("unsupported mii mode %d\n",
128 			       plat_dat->interface);
129 			return -ENOTSUPP;
130 		}
131 		val &= ~GMAC0_SHUT;
132 	}
133 	__raw_writel(val, LS1X_MUX_CTRL1);
134 #elif defined(CONFIG_LOONGSON1_LS1C)
135 	plat_dat = dev_get_platdata(&pdev->dev);
136 
137 	val &= ~PHY_INTF_SELI;
138 	if (plat_dat->interface == PHY_INTERFACE_MODE_RMII)
139 		val |= 0x4 << PHY_INTF_SELI_SHIFT;
140 	__raw_writel(val, LS1X_MUX_CTRL1);
141 
142 	val = __raw_readl(LS1X_MUX_CTRL0);
143 	__raw_writel(val & (~GMAC_SHUT), LS1X_MUX_CTRL0);
144 #endif
145 
146 	return 0;
147 }
148 
149 static struct plat_stmmacenet_data ls1x_eth0_pdata = {
150 	.bus_id			= 0,
151 	.phy_addr		= -1,
152 #if defined(CONFIG_LOONGSON1_LS1B)
153 	.interface		= PHY_INTERFACE_MODE_MII,
154 #elif defined(CONFIG_LOONGSON1_LS1C)
155 	.interface		= PHY_INTERFACE_MODE_RMII,
156 #endif
157 	.mdio_bus_data		= &ls1x_mdio_bus_data,
158 	.dma_cfg		= &ls1x_eth_dma_cfg,
159 	.has_gmac		= 1,
160 	.tx_coe			= 1,
161 	.rx_queues_to_use	= 1,
162 	.tx_queues_to_use	= 1,
163 	.init			= ls1x_eth_mux_init,
164 };
165 
166 static struct resource ls1x_eth0_resources[] = {
167 	[0] = {
168 		.start	= LS1X_GMAC0_BASE,
169 		.end	= LS1X_GMAC0_BASE + SZ_64K - 1,
170 		.flags	= IORESOURCE_MEM,
171 	},
172 	[1] = {
173 		.name	= "macirq",
174 		.start	= LS1X_GMAC0_IRQ,
175 		.flags	= IORESOURCE_IRQ,
176 	},
177 };
178 
179 struct platform_device ls1x_eth0_pdev = {
180 	.name		= "stmmaceth",
181 	.id		= 0,
182 	.num_resources	= ARRAY_SIZE(ls1x_eth0_resources),
183 	.resource	= ls1x_eth0_resources,
184 	.dev		= {
185 		.platform_data = &ls1x_eth0_pdata,
186 	},
187 };
188 
189 #ifdef CONFIG_LOONGSON1_LS1B
190 static struct plat_stmmacenet_data ls1x_eth1_pdata = {
191 	.bus_id			= 1,
192 	.phy_addr		= -1,
193 	.interface		= PHY_INTERFACE_MODE_MII,
194 	.mdio_bus_data		= &ls1x_mdio_bus_data,
195 	.dma_cfg		= &ls1x_eth_dma_cfg,
196 	.has_gmac		= 1,
197 	.tx_coe			= 1,
198 	.rx_queues_to_use	= 1,
199 	.tx_queues_to_use	= 1,
200 	.init			= ls1x_eth_mux_init,
201 };
202 
203 static struct resource ls1x_eth1_resources[] = {
204 	[0] = {
205 		.start	= LS1X_GMAC1_BASE,
206 		.end	= LS1X_GMAC1_BASE + SZ_64K - 1,
207 		.flags	= IORESOURCE_MEM,
208 	},
209 	[1] = {
210 		.name	= "macirq",
211 		.start	= LS1X_GMAC1_IRQ,
212 		.flags	= IORESOURCE_IRQ,
213 	},
214 };
215 
216 struct platform_device ls1x_eth1_pdev = {
217 	.name		= "stmmaceth",
218 	.id		= 1,
219 	.num_resources	= ARRAY_SIZE(ls1x_eth1_resources),
220 	.resource	= ls1x_eth1_resources,
221 	.dev		= {
222 		.platform_data = &ls1x_eth1_pdata,
223 	},
224 };
225 #endif	/* CONFIG_LOONGSON1_LS1B */
226 
227 /* GPIO */
228 static struct resource ls1x_gpio0_resources[] = {
229 	[0] = {
230 		.start	= LS1X_GPIO0_BASE,
231 		.end	= LS1X_GPIO0_BASE + SZ_4 - 1,
232 		.flags	= IORESOURCE_MEM,
233 	},
234 };
235 
236 struct platform_device ls1x_gpio0_pdev = {
237 	.name		= "ls1x-gpio",
238 	.id		= 0,
239 	.num_resources	= ARRAY_SIZE(ls1x_gpio0_resources),
240 	.resource	= ls1x_gpio0_resources,
241 };
242 
243 static struct resource ls1x_gpio1_resources[] = {
244 	[0] = {
245 		.start	= LS1X_GPIO1_BASE,
246 		.end	= LS1X_GPIO1_BASE + SZ_4 - 1,
247 		.flags	= IORESOURCE_MEM,
248 	},
249 };
250 
251 struct platform_device ls1x_gpio1_pdev = {
252 	.name		= "ls1x-gpio",
253 	.id		= 1,
254 	.num_resources	= ARRAY_SIZE(ls1x_gpio1_resources),
255 	.resource	= ls1x_gpio1_resources,
256 };
257 
258 /* USB EHCI */
259 static u64 ls1x_ehci_dmamask = DMA_BIT_MASK(32);
260 
261 static struct resource ls1x_ehci_resources[] = {
262 	[0] = {
263 		.start	= LS1X_EHCI_BASE,
264 		.end	= LS1X_EHCI_BASE + SZ_32K - 1,
265 		.flags	= IORESOURCE_MEM,
266 	},
267 	[1] = {
268 		.start	= LS1X_EHCI_IRQ,
269 		.flags	= IORESOURCE_IRQ,
270 	},
271 };
272 
273 static struct usb_ehci_pdata ls1x_ehci_pdata = {
274 };
275 
276 struct platform_device ls1x_ehci_pdev = {
277 	.name		= "ehci-platform",
278 	.id		= -1,
279 	.num_resources	= ARRAY_SIZE(ls1x_ehci_resources),
280 	.resource	= ls1x_ehci_resources,
281 	.dev		= {
282 		.dma_mask = &ls1x_ehci_dmamask,
283 		.platform_data = &ls1x_ehci_pdata,
284 	},
285 };
286 
287 /* Real Time Clock */
288 void __init ls1x_rtc_set_extclk(struct platform_device *pdev)
289 {
290 	u32 val = __raw_readl(LS1X_RTC_CTRL);
291 
292 	if (!(val & RTC_EXTCLK_OK))
293 		__raw_writel(val | RTC_EXTCLK_EN, LS1X_RTC_CTRL);
294 }
295 
296 struct platform_device ls1x_rtc_pdev = {
297 	.name		= "ls1x-rtc",
298 	.id		= -1,
299 };
300 
301 /* Watchdog */
302 static struct resource ls1x_wdt_resources[] = {
303 	{
304 		.start	= LS1X_WDT_BASE,
305 		.end	= LS1X_WDT_BASE + SZ_16 - 1,
306 		.flags	= IORESOURCE_MEM,
307 	},
308 };
309 
310 struct platform_device ls1x_wdt_pdev = {
311 	.name		= "ls1x-wdt",
312 	.id		= -1,
313 	.num_resources	= ARRAY_SIZE(ls1x_wdt_resources),
314 	.resource	= ls1x_wdt_resources,
315 };
316