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