mach-mxs.c revision 7aff3fba8437438a86e6debe2429cd12a69b05d0
1/*
2 * Copyright 2012 Freescale Semiconductor, Inc.
3 * Copyright 2012 Linaro Ltd.
4 *
5 * The code contained herein is licensed under the GNU General Public
6 * License. You may obtain a copy of the GNU General Public License
7 * Version 2 or later at the following locations:
8 *
9 * http://www.opensource.org/licenses/gpl-license.html
10 * http://www.gnu.org/copyleft/gpl.html
11 */
12
13#include <linux/clk.h>
14#include <linux/clkdev.h>
15#include <linux/can/platform/flexcan.h>
16#include <linux/delay.h>
17#include <linux/err.h>
18#include <linux/gpio.h>
19#include <linux/init.h>
20#include <linux/irqdomain.h>
21#include <linux/micrel_phy.h>
22#include <linux/mxsfb.h>
23#include <linux/of_irq.h>
24#include <linux/of_platform.h>
25#include <linux/phy.h>
26#include <linux/pinctrl/consumer.h>
27#include <asm/mach/arch.h>
28#include <asm/mach/time.h>
29#include <mach/common.h>
30#include <mach/digctl.h>
31#include <mach/mxs.h>
32
33static struct fb_videomode mx23evk_video_modes[] = {
34	{
35		.name		= "Samsung-LMS430HF02",
36		.refresh	= 60,
37		.xres		= 480,
38		.yres		= 272,
39		.pixclock	= 108096, /* picosecond (9.2 MHz) */
40		.left_margin	= 15,
41		.right_margin	= 8,
42		.upper_margin	= 12,
43		.lower_margin	= 4,
44		.hsync_len	= 1,
45		.vsync_len	= 1,
46		.sync		= FB_SYNC_DATA_ENABLE_HIGH_ACT |
47				  FB_SYNC_DOTCLK_FAILING_ACT,
48	},
49};
50
51static struct fb_videomode mx28evk_video_modes[] = {
52	{
53		.name		= "Seiko-43WVF1G",
54		.refresh	= 60,
55		.xres		= 800,
56		.yres		= 480,
57		.pixclock	= 29851, /* picosecond (33.5 MHz) */
58		.left_margin	= 89,
59		.right_margin	= 164,
60		.upper_margin	= 23,
61		.lower_margin	= 10,
62		.hsync_len	= 10,
63		.vsync_len	= 10,
64		.sync		= FB_SYNC_DATA_ENABLE_HIGH_ACT |
65				  FB_SYNC_DOTCLK_FAILING_ACT,
66	},
67};
68
69static struct fb_videomode m28evk_video_modes[] = {
70	{
71		.name		= "Ampire AM-800480R2TMQW-T01H",
72		.refresh	= 60,
73		.xres		= 800,
74		.yres		= 480,
75		.pixclock	= 30066, /* picosecond (33.26 MHz) */
76		.left_margin	= 0,
77		.right_margin	= 256,
78		.upper_margin	= 0,
79		.lower_margin	= 45,
80		.hsync_len	= 1,
81		.vsync_len	= 1,
82		.sync		= FB_SYNC_DATA_ENABLE_HIGH_ACT,
83	},
84};
85
86static struct fb_videomode apx4devkit_video_modes[] = {
87	{
88		.name		= "HannStar PJ70112A",
89		.refresh	= 60,
90		.xres		= 800,
91		.yres		= 480,
92		.pixclock	= 33333, /* picosecond (30.00 MHz) */
93		.left_margin	= 88,
94		.right_margin	= 40,
95		.upper_margin	= 32,
96		.lower_margin	= 13,
97		.hsync_len	= 48,
98		.vsync_len	= 3,
99		.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT |
100				  FB_SYNC_DATA_ENABLE_HIGH_ACT |
101				  FB_SYNC_DOTCLK_FAILING_ACT,
102	},
103};
104
105static struct mxsfb_platform_data mxsfb_pdata __initdata;
106
107/*
108 * MX28EVK_FLEXCAN_SWITCH is shared between both flexcan controllers
109 */
110#define MX28EVK_FLEXCAN_SWITCH	MXS_GPIO_NR(2, 13)
111
112static int flexcan0_en, flexcan1_en;
113
114static void mx28evk_flexcan_switch(void)
115{
116	if (flexcan0_en || flexcan1_en)
117		gpio_set_value(MX28EVK_FLEXCAN_SWITCH, 1);
118	else
119		gpio_set_value(MX28EVK_FLEXCAN_SWITCH, 0);
120}
121
122static void mx28evk_flexcan0_switch(int enable)
123{
124	flexcan0_en = enable;
125	mx28evk_flexcan_switch();
126}
127
128static void mx28evk_flexcan1_switch(int enable)
129{
130	flexcan1_en = enable;
131	mx28evk_flexcan_switch();
132}
133
134static struct flexcan_platform_data flexcan_pdata[2];
135
136static struct of_dev_auxdata mxs_auxdata_lookup[] __initdata = {
137	OF_DEV_AUXDATA("fsl,imx23-lcdif", 0x80030000, NULL, &mxsfb_pdata),
138	OF_DEV_AUXDATA("fsl,imx28-lcdif", 0x80030000, NULL, &mxsfb_pdata),
139	OF_DEV_AUXDATA("fsl,imx28-flexcan", 0x80032000, NULL, &flexcan_pdata[0]),
140	OF_DEV_AUXDATA("fsl,imx28-flexcan", 0x80034000, NULL, &flexcan_pdata[1]),
141	{ /* sentinel */ }
142};
143
144static int __init mxs_icoll_add_irq_domain(struct device_node *np,
145				struct device_node *interrupt_parent)
146{
147	irq_domain_add_legacy(np, 128, 0, 0, &irq_domain_simple_ops, NULL);
148
149	return 0;
150}
151
152static int __init mxs_gpio_add_irq_domain(struct device_node *np,
153				struct device_node *interrupt_parent)
154{
155	static int gpio_irq_base = MXS_GPIO_IRQ_START;
156
157	irq_domain_add_legacy(np, 32, gpio_irq_base, 0, &irq_domain_simple_ops, NULL);
158	gpio_irq_base += 32;
159
160	return 0;
161}
162
163static const struct of_device_id mxs_irq_match[] __initconst = {
164	{ .compatible = "fsl,mxs-icoll", .data = mxs_icoll_add_irq_domain, },
165	{ .compatible = "fsl,mxs-gpio", .data = mxs_gpio_add_irq_domain, },
166	{ /* sentinel */ }
167};
168
169static void __init mxs_dt_init_irq(void)
170{
171	icoll_init_irq();
172	of_irq_init(mxs_irq_match);
173}
174
175static void __init imx23_timer_init(void)
176{
177	mx23_clocks_init();
178}
179
180static struct sys_timer imx23_timer = {
181	.init = imx23_timer_init,
182};
183
184static void __init imx28_timer_init(void)
185{
186	mx28_clocks_init();
187}
188
189static struct sys_timer imx28_timer = {
190	.init = imx28_timer_init,
191};
192
193enum mac_oui {
194	OUI_FSL,
195	OUI_DENX,
196};
197
198static void __init update_fec_mac_prop(enum mac_oui oui)
199{
200	struct device_node *np, *from = NULL;
201	struct property *newmac;
202	const u32 *ocotp = mxs_get_ocotp();
203	u8 *macaddr;
204	u32 val;
205	int i;
206
207	for (i = 0; i < 2; i++) {
208		np = of_find_compatible_node(from, NULL, "fsl,imx28-fec");
209		if (!np)
210			return;
211		from = np;
212
213		newmac = kzalloc(sizeof(*newmac) + 6, GFP_KERNEL);
214		if (!newmac)
215			return;
216		newmac->value = newmac + 1;
217		newmac->length = 6;
218
219		newmac->name = kstrdup("local-mac-address", GFP_KERNEL);
220		if (!newmac->name) {
221			kfree(newmac);
222			return;
223		}
224
225		/*
226		 * OCOTP only stores the last 4 octets for each mac address,
227		 * so hard-code OUI here.
228		 */
229		macaddr = newmac->value;
230		switch (oui) {
231		case OUI_FSL:
232			macaddr[0] = 0x00;
233			macaddr[1] = 0x04;
234			macaddr[2] = 0x9f;
235			break;
236		case OUI_DENX:
237			macaddr[0] = 0xc0;
238			macaddr[1] = 0xe5;
239			macaddr[2] = 0x4e;
240			break;
241		}
242		val = ocotp[i];
243		macaddr[3] = (val >> 16) & 0xff;
244		macaddr[4] = (val >> 8) & 0xff;
245		macaddr[5] = (val >> 0) & 0xff;
246
247		prom_update_property(np, newmac);
248	}
249}
250
251static void __init imx23_evk_init(void)
252{
253	mxsfb_pdata.mode_list = mx23evk_video_modes;
254	mxsfb_pdata.mode_count = ARRAY_SIZE(mx23evk_video_modes);
255	mxsfb_pdata.default_bpp = 32;
256	mxsfb_pdata.ld_intf_width = STMLCDIF_24BIT;
257}
258
259static inline void enable_clk_enet_out(void)
260{
261	struct clk *clk = clk_get_sys("enet_out", NULL);
262
263	if (!IS_ERR(clk))
264		clk_prepare_enable(clk);
265}
266
267static void __init imx28_evk_init(void)
268{
269	enable_clk_enet_out();
270	update_fec_mac_prop(OUI_FSL);
271
272	mxsfb_pdata.mode_list = mx28evk_video_modes;
273	mxsfb_pdata.mode_count = ARRAY_SIZE(mx28evk_video_modes);
274	mxsfb_pdata.default_bpp = 32;
275	mxsfb_pdata.ld_intf_width = STMLCDIF_24BIT;
276
277	mxs_saif_clkmux_select(MXS_DIGCTL_SAIF_CLKMUX_EXTMSTR0);
278}
279
280static void __init imx28_evk_post_init(void)
281{
282	if (!gpio_request_one(MX28EVK_FLEXCAN_SWITCH, GPIOF_DIR_OUT,
283			      "flexcan-switch")) {
284		flexcan_pdata[0].transceiver_switch = mx28evk_flexcan0_switch;
285		flexcan_pdata[1].transceiver_switch = mx28evk_flexcan1_switch;
286	}
287}
288
289static void __init m28evk_init(void)
290{
291	mxsfb_pdata.mode_list = m28evk_video_modes;
292	mxsfb_pdata.mode_count = ARRAY_SIZE(m28evk_video_modes);
293	mxsfb_pdata.default_bpp = 16;
294	mxsfb_pdata.ld_intf_width = STMLCDIF_18BIT;
295}
296
297static int apx4devkit_phy_fixup(struct phy_device *phy)
298{
299	phy->dev_flags |= MICREL_PHY_50MHZ_CLK;
300	return 0;
301}
302
303static void __init apx4devkit_init(void)
304{
305	enable_clk_enet_out();
306
307	if (IS_BUILTIN(CONFIG_PHYLIB))
308		phy_register_fixup_for_uid(PHY_ID_KS8051, MICREL_PHY_ID_MASK,
309					   apx4devkit_phy_fixup);
310
311	mxsfb_pdata.mode_list = apx4devkit_video_modes;
312	mxsfb_pdata.mode_count = ARRAY_SIZE(apx4devkit_video_modes);
313	mxsfb_pdata.default_bpp = 32;
314	mxsfb_pdata.ld_intf_width = STMLCDIF_24BIT;
315}
316
317#define ENET0_MDC__GPIO_4_0	MXS_GPIO_NR(4, 0)
318#define ENET0_MDIO__GPIO_4_1	MXS_GPIO_NR(4, 1)
319#define ENET0_RX_EN__GPIO_4_2	MXS_GPIO_NR(4, 2)
320#define ENET0_RXD0__GPIO_4_3	MXS_GPIO_NR(4, 3)
321#define ENET0_RXD1__GPIO_4_4	MXS_GPIO_NR(4, 4)
322#define ENET0_TX_EN__GPIO_4_6	MXS_GPIO_NR(4, 6)
323#define ENET0_TXD0__GPIO_4_7	MXS_GPIO_NR(4, 7)
324#define ENET0_TXD1__GPIO_4_8	MXS_GPIO_NR(4, 8)
325#define ENET_CLK__GPIO_4_16	MXS_GPIO_NR(4, 16)
326
327#define TX28_FEC_PHY_POWER	MXS_GPIO_NR(3, 29)
328#define TX28_FEC_PHY_RESET	MXS_GPIO_NR(4, 13)
329#define TX28_FEC_nINT		MXS_GPIO_NR(4, 5)
330
331static const struct gpio tx28_gpios[] __initconst = {
332	{ ENET0_MDC__GPIO_4_0, GPIOF_OUT_INIT_LOW, "GPIO_4_0" },
333	{ ENET0_MDIO__GPIO_4_1, GPIOF_OUT_INIT_LOW, "GPIO_4_1" },
334	{ ENET0_RX_EN__GPIO_4_2, GPIOF_OUT_INIT_LOW, "GPIO_4_2" },
335	{ ENET0_RXD0__GPIO_4_3, GPIOF_OUT_INIT_LOW, "GPIO_4_3" },
336	{ ENET0_RXD1__GPIO_4_4, GPIOF_OUT_INIT_LOW, "GPIO_4_4" },
337	{ ENET0_TX_EN__GPIO_4_6, GPIOF_OUT_INIT_LOW, "GPIO_4_6" },
338	{ ENET0_TXD0__GPIO_4_7, GPIOF_OUT_INIT_LOW, "GPIO_4_7" },
339	{ ENET0_TXD1__GPIO_4_8, GPIOF_OUT_INIT_LOW, "GPIO_4_8" },
340	{ ENET_CLK__GPIO_4_16, GPIOF_OUT_INIT_LOW, "GPIO_4_16" },
341	{ TX28_FEC_PHY_POWER, GPIOF_OUT_INIT_LOW, "fec-phy-power" },
342	{ TX28_FEC_PHY_RESET, GPIOF_OUT_INIT_LOW, "fec-phy-reset" },
343	{ TX28_FEC_nINT, GPIOF_DIR_IN, "fec-int" },
344};
345
346static void __init tx28_post_init(void)
347{
348	struct device_node *np;
349	struct platform_device *pdev;
350	struct pinctrl *pctl;
351	int ret;
352
353	enable_clk_enet_out();
354
355	np = of_find_compatible_node(NULL, NULL, "fsl,imx28-fec");
356	pdev = of_find_device_by_node(np);
357	if (!pdev) {
358		pr_err("%s: failed to find fec device\n", __func__);
359		return;
360	}
361
362	pctl = pinctrl_get_select(&pdev->dev, "gpio_mode");
363	if (IS_ERR(pctl)) {
364		pr_err("%s: failed to get pinctrl state\n", __func__);
365		return;
366	}
367
368	ret = gpio_request_array(tx28_gpios, ARRAY_SIZE(tx28_gpios));
369	if (ret) {
370		pr_err("%s: failed to request gpios: %d\n", __func__, ret);
371		return;
372	}
373
374	/* Power up fec phy */
375	gpio_set_value(TX28_FEC_PHY_POWER, 1);
376	msleep(26); /* 25ms according to data sheet */
377
378	/* Mode strap pins */
379	gpio_set_value(ENET0_RX_EN__GPIO_4_2, 1);
380	gpio_set_value(ENET0_RXD0__GPIO_4_3, 1);
381	gpio_set_value(ENET0_RXD1__GPIO_4_4, 1);
382
383	udelay(100); /* minimum assertion time for nRST */
384
385	/* Deasserting FEC PHY RESET */
386	gpio_set_value(TX28_FEC_PHY_RESET, 1);
387
388	pinctrl_put(pctl);
389}
390
391static void __init mxs_machine_init(void)
392{
393	if (of_machine_is_compatible("fsl,imx28-evk"))
394		imx28_evk_init();
395	else if (of_machine_is_compatible("fsl,imx23-evk"))
396		imx23_evk_init();
397	else if (of_machine_is_compatible("denx,m28evk"))
398		m28evk_init();
399	else if (of_machine_is_compatible("bluegiga,apx4devkit"))
400		apx4devkit_init();
401
402	of_platform_populate(NULL, of_default_bus_match_table,
403			     mxs_auxdata_lookup, NULL);
404
405	if (of_machine_is_compatible("karo,tx28"))
406		tx28_post_init();
407
408	if (of_machine_is_compatible("fsl,imx28-evk"))
409		imx28_evk_post_init();
410}
411
412static const char *imx23_dt_compat[] __initdata = {
413	"fsl,imx23",
414	NULL,
415};
416
417static const char *imx28_dt_compat[] __initdata = {
418	"fsl,imx28",
419	NULL,
420};
421
422DT_MACHINE_START(IMX23, "Freescale i.MX23 (Device Tree)")
423	.map_io		= mx23_map_io,
424	.init_irq	= mxs_dt_init_irq,
425	.timer		= &imx23_timer,
426	.init_machine	= mxs_machine_init,
427	.dt_compat	= imx23_dt_compat,
428	.restart	= mxs_restart,
429MACHINE_END
430
431DT_MACHINE_START(IMX28, "Freescale i.MX28 (Device Tree)")
432	.map_io		= mx28_map_io,
433	.init_irq	= mxs_dt_init_irq,
434	.timer		= &imx28_timer,
435	.init_machine	= mxs_machine_init,
436	.dt_compat	= imx28_dt_compat,
437	.restart	= mxs_restart,
438MACHINE_END
439