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