1/*
2 * Copyright (c) 2011 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/phy.h>
14#include <linux/serial_8250.h>
15#include <linux/stmmac.h>
16#include <linux/usb/ehci_pdriver.h>
17#include <asm-generic/sizes.h>
18
19#include <cpufreq.h>
20#include <loongson1.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
32static 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
40struct platform_device ls1x_uart_pdev = {
41	.name		= "serial8250",
42	.id		= PLAT8250_DEV_PLATFORM,
43	.dev		= {
44		.platform_data = ls1x_serial8250_pdata,
45	},
46};
47
48void __init ls1x_serial_setup(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 */
66static struct plat_ls1x_cpufreq ls1x_cpufreq_pdata = {
67	.clk_name	= "cpu_clk",
68	.osc_clk_name	= "osc_33m_clk",
69	.max_freq	= 266 * 1000,
70	.min_freq	= 33 * 1000,
71};
72
73struct platform_device ls1x_cpufreq_pdev = {
74	.name		= "ls1x-cpufreq",
75	.dev		= {
76		.platform_data = &ls1x_cpufreq_pdata,
77	},
78};
79
80/* Synopsys Ethernet GMAC */
81static struct stmmac_mdio_bus_data ls1x_mdio_bus_data = {
82	.phy_mask	= 0,
83};
84
85static struct stmmac_dma_cfg ls1x_eth_dma_cfg = {
86	.pbl		= 1,
87};
88
89int 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	plat_dat = dev_get_platdata(&pdev->dev);
97	if (plat_dat->bus_id) {
98		__raw_writel(__raw_readl(LS1X_MUX_CTRL0) | GMAC1_USE_UART1 |
99			     GMAC1_USE_UART0, LS1X_MUX_CTRL0);
100		switch (plat_dat->interface) {
101		case PHY_INTERFACE_MODE_RGMII:
102			val &= ~(GMAC1_USE_TXCLK | GMAC1_USE_PWM23);
103			break;
104		case PHY_INTERFACE_MODE_MII:
105			val |= (GMAC1_USE_TXCLK | GMAC1_USE_PWM23);
106			break;
107		default:
108			pr_err("unsupported mii mode %d\n",
109			       plat_dat->interface);
110			return -ENOTSUPP;
111		}
112		val &= ~GMAC1_SHUT;
113	} else {
114		switch (plat_dat->interface) {
115		case PHY_INTERFACE_MODE_RGMII:
116			val &= ~(GMAC0_USE_TXCLK | GMAC0_USE_PWM01);
117			break;
118		case PHY_INTERFACE_MODE_MII:
119			val |= (GMAC0_USE_TXCLK | GMAC0_USE_PWM01);
120			break;
121		default:
122			pr_err("unsupported mii mode %d\n",
123			       plat_dat->interface);
124			return -ENOTSUPP;
125		}
126		val &= ~GMAC0_SHUT;
127	}
128	__raw_writel(val, LS1X_MUX_CTRL1);
129
130	return 0;
131}
132
133static struct plat_stmmacenet_data ls1x_eth0_pdata = {
134	.bus_id		= 0,
135	.phy_addr	= -1,
136	.interface	= PHY_INTERFACE_MODE_MII,
137	.mdio_bus_data	= &ls1x_mdio_bus_data,
138	.dma_cfg	= &ls1x_eth_dma_cfg,
139	.has_gmac	= 1,
140	.tx_coe		= 1,
141	.init		= ls1x_eth_mux_init,
142};
143
144static struct resource ls1x_eth0_resources[] = {
145	[0] = {
146		.start	= LS1X_GMAC0_BASE,
147		.end	= LS1X_GMAC0_BASE + SZ_64K - 1,
148		.flags	= IORESOURCE_MEM,
149	},
150	[1] = {
151		.name	= "macirq",
152		.start	= LS1X_GMAC0_IRQ,
153		.flags	= IORESOURCE_IRQ,
154	},
155};
156
157struct platform_device ls1x_eth0_pdev = {
158	.name		= "stmmaceth",
159	.id		= 0,
160	.num_resources	= ARRAY_SIZE(ls1x_eth0_resources),
161	.resource	= ls1x_eth0_resources,
162	.dev		= {
163		.platform_data = &ls1x_eth0_pdata,
164	},
165};
166
167static struct plat_stmmacenet_data ls1x_eth1_pdata = {
168	.bus_id		= 1,
169	.phy_addr	= -1,
170	.interface	= PHY_INTERFACE_MODE_MII,
171	.mdio_bus_data	= &ls1x_mdio_bus_data,
172	.dma_cfg	= &ls1x_eth_dma_cfg,
173	.has_gmac	= 1,
174	.tx_coe		= 1,
175	.init		= ls1x_eth_mux_init,
176};
177
178static struct resource ls1x_eth1_resources[] = {
179	[0] = {
180		.start	= LS1X_GMAC1_BASE,
181		.end	= LS1X_GMAC1_BASE + SZ_64K - 1,
182		.flags	= IORESOURCE_MEM,
183	},
184	[1] = {
185		.name	= "macirq",
186		.start	= LS1X_GMAC1_IRQ,
187		.flags	= IORESOURCE_IRQ,
188	},
189};
190
191struct platform_device ls1x_eth1_pdev = {
192	.name		= "stmmaceth",
193	.id		= 1,
194	.num_resources	= ARRAY_SIZE(ls1x_eth1_resources),
195	.resource	= ls1x_eth1_resources,
196	.dev		= {
197		.platform_data = &ls1x_eth1_pdata,
198	},
199};
200
201/* USB EHCI */
202static u64 ls1x_ehci_dmamask = DMA_BIT_MASK(32);
203
204static struct resource ls1x_ehci_resources[] = {
205	[0] = {
206		.start	= LS1X_EHCI_BASE,
207		.end	= LS1X_EHCI_BASE + SZ_32K - 1,
208		.flags	= IORESOURCE_MEM,
209	},
210	[1] = {
211		.start	= LS1X_EHCI_IRQ,
212		.flags	= IORESOURCE_IRQ,
213	},
214};
215
216static struct usb_ehci_pdata ls1x_ehci_pdata = {
217};
218
219struct platform_device ls1x_ehci_pdev = {
220	.name		= "ehci-platform",
221	.id		= -1,
222	.num_resources	= ARRAY_SIZE(ls1x_ehci_resources),
223	.resource	= ls1x_ehci_resources,
224	.dev		= {
225		.dma_mask = &ls1x_ehci_dmamask,
226		.platform_data = &ls1x_ehci_pdata,
227	},
228};
229
230/* Real Time Clock */
231struct platform_device ls1x_rtc_pdev = {
232	.name		= "ls1x-rtc",
233	.id		= -1,
234};
235