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/micrel_phy.h> 21 #include <linux/mxsfb.h> 22 #include <linux/of_platform.h> 23 #include <linux/phy.h> 24 #include <linux/pinctrl/consumer.h> 25 #include <asm/mach/arch.h> 26 #include <asm/mach/time.h> 27 #include <mach/common.h> 28 #include <mach/digctl.h> 29 #include <mach/mxs.h> 30 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 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 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 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 122 static struct fb_videomode cfa10049_video_modes[] = { 123 { 124 .name = "Himax HX8357-B", 125 .refresh = 60, 126 .xres = 320, 127 .yres = 480, 128 .pixclock = 108506, /* picosecond (9.216 MHz) */ 129 .left_margin = 2, 130 .right_margin = 2, 131 .upper_margin = 2, 132 .lower_margin = 2, 133 .hsync_len = 15, 134 .vsync_len = 15, 135 .sync = FB_SYNC_DATA_ENABLE_HIGH_ACT 136 }, 137 }; 138 139 static struct mxsfb_platform_data mxsfb_pdata __initdata; 140 141 /* 142 * MX28EVK_FLEXCAN_SWITCH is shared between both flexcan controllers 143 */ 144 #define MX28EVK_FLEXCAN_SWITCH MXS_GPIO_NR(2, 13) 145 146 static int flexcan0_en, flexcan1_en; 147 148 static void mx28evk_flexcan_switch(void) 149 { 150 if (flexcan0_en || flexcan1_en) 151 gpio_set_value(MX28EVK_FLEXCAN_SWITCH, 1); 152 else 153 gpio_set_value(MX28EVK_FLEXCAN_SWITCH, 0); 154 } 155 156 static void mx28evk_flexcan0_switch(int enable) 157 { 158 flexcan0_en = enable; 159 mx28evk_flexcan_switch(); 160 } 161 162 static void mx28evk_flexcan1_switch(int enable) 163 { 164 flexcan1_en = enable; 165 mx28evk_flexcan_switch(); 166 } 167 168 static struct flexcan_platform_data flexcan_pdata[2]; 169 170 static struct of_dev_auxdata mxs_auxdata_lookup[] __initdata = { 171 OF_DEV_AUXDATA("fsl,imx23-lcdif", 0x80030000, NULL, &mxsfb_pdata), 172 OF_DEV_AUXDATA("fsl,imx28-lcdif", 0x80030000, NULL, &mxsfb_pdata), 173 OF_DEV_AUXDATA("fsl,imx28-flexcan", 0x80032000, NULL, &flexcan_pdata[0]), 174 OF_DEV_AUXDATA("fsl,imx28-flexcan", 0x80034000, NULL, &flexcan_pdata[1]), 175 { /* sentinel */ } 176 }; 177 178 static void __init imx23_timer_init(void) 179 { 180 mx23_clocks_init(); 181 } 182 183 static void __init imx28_timer_init(void) 184 { 185 mx28_clocks_init(); 186 } 187 188 enum mac_oui { 189 OUI_FSL, 190 OUI_DENX, 191 OUI_CRYSTALFONTZ, 192 }; 193 194 static void __init update_fec_mac_prop(enum mac_oui oui) 195 { 196 struct device_node *np, *from = NULL; 197 struct property *newmac; 198 const u32 *ocotp = mxs_get_ocotp(); 199 u8 *macaddr; 200 u32 val; 201 int i; 202 203 for (i = 0; i < 2; i++) { 204 np = of_find_compatible_node(from, NULL, "fsl,imx28-fec"); 205 if (!np) 206 return; 207 208 from = np; 209 210 if (of_get_property(np, "local-mac-address", NULL)) 211 continue; 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 case OUI_CRYSTALFONTZ: 242 macaddr[0] = 0x58; 243 macaddr[1] = 0xb9; 244 macaddr[2] = 0xe1; 245 break; 246 } 247 val = ocotp[i]; 248 macaddr[3] = (val >> 16) & 0xff; 249 macaddr[4] = (val >> 8) & 0xff; 250 macaddr[5] = (val >> 0) & 0xff; 251 252 of_update_property(np, newmac); 253 } 254 } 255 256 static void __init imx23_evk_init(void) 257 { 258 mxsfb_pdata.mode_list = mx23evk_video_modes; 259 mxsfb_pdata.mode_count = ARRAY_SIZE(mx23evk_video_modes); 260 mxsfb_pdata.default_bpp = 32; 261 mxsfb_pdata.ld_intf_width = STMLCDIF_24BIT; 262 } 263 264 static inline void enable_clk_enet_out(void) 265 { 266 struct clk *clk = clk_get_sys("enet_out", NULL); 267 268 if (!IS_ERR(clk)) 269 clk_prepare_enable(clk); 270 } 271 272 static void __init imx28_evk_init(void) 273 { 274 enable_clk_enet_out(); 275 update_fec_mac_prop(OUI_FSL); 276 277 mxsfb_pdata.mode_list = mx28evk_video_modes; 278 mxsfb_pdata.mode_count = ARRAY_SIZE(mx28evk_video_modes); 279 mxsfb_pdata.default_bpp = 32; 280 mxsfb_pdata.ld_intf_width = STMLCDIF_24BIT; 281 282 mxs_saif_clkmux_select(MXS_DIGCTL_SAIF_CLKMUX_EXTMSTR0); 283 } 284 285 static void __init imx28_evk_post_init(void) 286 { 287 if (!gpio_request_one(MX28EVK_FLEXCAN_SWITCH, GPIOF_DIR_OUT, 288 "flexcan-switch")) { 289 flexcan_pdata[0].transceiver_switch = mx28evk_flexcan0_switch; 290 flexcan_pdata[1].transceiver_switch = mx28evk_flexcan1_switch; 291 } 292 } 293 294 static void __init m28evk_init(void) 295 { 296 mxsfb_pdata.mode_list = m28evk_video_modes; 297 mxsfb_pdata.mode_count = ARRAY_SIZE(m28evk_video_modes); 298 mxsfb_pdata.default_bpp = 16; 299 mxsfb_pdata.ld_intf_width = STMLCDIF_18BIT; 300 } 301 302 static void __init sc_sps1_init(void) 303 { 304 enable_clk_enet_out(); 305 } 306 307 static int apx4devkit_phy_fixup(struct phy_device *phy) 308 { 309 phy->dev_flags |= MICREL_PHY_50MHZ_CLK; 310 return 0; 311 } 312 313 static void __init apx4devkit_init(void) 314 { 315 enable_clk_enet_out(); 316 317 if (IS_BUILTIN(CONFIG_PHYLIB)) 318 phy_register_fixup_for_uid(PHY_ID_KSZ8051, MICREL_PHY_ID_MASK, 319 apx4devkit_phy_fixup); 320 321 mxsfb_pdata.mode_list = apx4devkit_video_modes; 322 mxsfb_pdata.mode_count = ARRAY_SIZE(apx4devkit_video_modes); 323 mxsfb_pdata.default_bpp = 32; 324 mxsfb_pdata.ld_intf_width = STMLCDIF_24BIT; 325 } 326 327 #define ENET0_MDC__GPIO_4_0 MXS_GPIO_NR(4, 0) 328 #define ENET0_MDIO__GPIO_4_1 MXS_GPIO_NR(4, 1) 329 #define ENET0_RX_EN__GPIO_4_2 MXS_GPIO_NR(4, 2) 330 #define ENET0_RXD0__GPIO_4_3 MXS_GPIO_NR(4, 3) 331 #define ENET0_RXD1__GPIO_4_4 MXS_GPIO_NR(4, 4) 332 #define ENET0_TX_EN__GPIO_4_6 MXS_GPIO_NR(4, 6) 333 #define ENET0_TXD0__GPIO_4_7 MXS_GPIO_NR(4, 7) 334 #define ENET0_TXD1__GPIO_4_8 MXS_GPIO_NR(4, 8) 335 #define ENET_CLK__GPIO_4_16 MXS_GPIO_NR(4, 16) 336 337 #define TX28_FEC_PHY_POWER MXS_GPIO_NR(3, 29) 338 #define TX28_FEC_PHY_RESET MXS_GPIO_NR(4, 13) 339 #define TX28_FEC_nINT MXS_GPIO_NR(4, 5) 340 341 static const struct gpio tx28_gpios[] __initconst = { 342 { ENET0_MDC__GPIO_4_0, GPIOF_OUT_INIT_LOW, "GPIO_4_0" }, 343 { ENET0_MDIO__GPIO_4_1, GPIOF_OUT_INIT_LOW, "GPIO_4_1" }, 344 { ENET0_RX_EN__GPIO_4_2, GPIOF_OUT_INIT_LOW, "GPIO_4_2" }, 345 { ENET0_RXD0__GPIO_4_3, GPIOF_OUT_INIT_LOW, "GPIO_4_3" }, 346 { ENET0_RXD1__GPIO_4_4, GPIOF_OUT_INIT_LOW, "GPIO_4_4" }, 347 { ENET0_TX_EN__GPIO_4_6, GPIOF_OUT_INIT_LOW, "GPIO_4_6" }, 348 { ENET0_TXD0__GPIO_4_7, GPIOF_OUT_INIT_LOW, "GPIO_4_7" }, 349 { ENET0_TXD1__GPIO_4_8, GPIOF_OUT_INIT_LOW, "GPIO_4_8" }, 350 { ENET_CLK__GPIO_4_16, GPIOF_OUT_INIT_LOW, "GPIO_4_16" }, 351 { TX28_FEC_PHY_POWER, GPIOF_OUT_INIT_LOW, "fec-phy-power" }, 352 { TX28_FEC_PHY_RESET, GPIOF_OUT_INIT_LOW, "fec-phy-reset" }, 353 { TX28_FEC_nINT, GPIOF_DIR_IN, "fec-int" }, 354 }; 355 356 static void __init tx28_post_init(void) 357 { 358 struct device_node *np; 359 struct platform_device *pdev; 360 struct pinctrl *pctl; 361 int ret; 362 363 enable_clk_enet_out(); 364 365 np = of_find_compatible_node(NULL, NULL, "fsl,imx28-fec"); 366 pdev = of_find_device_by_node(np); 367 if (!pdev) { 368 pr_err("%s: failed to find fec device\n", __func__); 369 return; 370 } 371 372 pctl = pinctrl_get_select(&pdev->dev, "gpio_mode"); 373 if (IS_ERR(pctl)) { 374 pr_err("%s: failed to get pinctrl state\n", __func__); 375 return; 376 } 377 378 ret = gpio_request_array(tx28_gpios, ARRAY_SIZE(tx28_gpios)); 379 if (ret) { 380 pr_err("%s: failed to request gpios: %d\n", __func__, ret); 381 return; 382 } 383 384 /* Power up fec phy */ 385 gpio_set_value(TX28_FEC_PHY_POWER, 1); 386 msleep(26); /* 25ms according to data sheet */ 387 388 /* Mode strap pins */ 389 gpio_set_value(ENET0_RX_EN__GPIO_4_2, 1); 390 gpio_set_value(ENET0_RXD0__GPIO_4_3, 1); 391 gpio_set_value(ENET0_RXD1__GPIO_4_4, 1); 392 393 udelay(100); /* minimum assertion time for nRST */ 394 395 /* Deasserting FEC PHY RESET */ 396 gpio_set_value(TX28_FEC_PHY_RESET, 1); 397 398 pinctrl_put(pctl); 399 } 400 401 static void __init cfa10049_init(void) 402 { 403 enable_clk_enet_out(); 404 update_fec_mac_prop(OUI_CRYSTALFONTZ); 405 406 mxsfb_pdata.mode_list = cfa10049_video_modes; 407 mxsfb_pdata.mode_count = ARRAY_SIZE(cfa10049_video_modes); 408 mxsfb_pdata.default_bpp = 32; 409 mxsfb_pdata.ld_intf_width = STMLCDIF_18BIT; 410 } 411 412 static void __init cfa10037_init(void) 413 { 414 enable_clk_enet_out(); 415 update_fec_mac_prop(OUI_CRYSTALFONTZ); 416 } 417 418 static void __init apf28_init(void) 419 { 420 enable_clk_enet_out(); 421 422 mxsfb_pdata.mode_list = apf28dev_video_modes; 423 mxsfb_pdata.mode_count = ARRAY_SIZE(apf28dev_video_modes); 424 mxsfb_pdata.default_bpp = 16; 425 mxsfb_pdata.ld_intf_width = STMLCDIF_16BIT; 426 } 427 428 static void __init mxs_machine_init(void) 429 { 430 if (of_machine_is_compatible("fsl,imx28-evk")) 431 imx28_evk_init(); 432 else if (of_machine_is_compatible("fsl,imx23-evk")) 433 imx23_evk_init(); 434 else if (of_machine_is_compatible("denx,m28evk")) 435 m28evk_init(); 436 else if (of_machine_is_compatible("bluegiga,apx4devkit")) 437 apx4devkit_init(); 438 else if (of_machine_is_compatible("crystalfontz,cfa10037")) 439 cfa10037_init(); 440 else if (of_machine_is_compatible("crystalfontz,cfa10049")) 441 cfa10049_init(); 442 else if (of_machine_is_compatible("armadeus,imx28-apf28")) 443 apf28_init(); 444 else if (of_machine_is_compatible("schulercontrol,imx28-sps1")) 445 sc_sps1_init(); 446 447 of_platform_populate(NULL, of_default_bus_match_table, 448 mxs_auxdata_lookup, NULL); 449 450 if (of_machine_is_compatible("karo,tx28")) 451 tx28_post_init(); 452 453 if (of_machine_is_compatible("fsl,imx28-evk")) 454 imx28_evk_post_init(); 455 } 456 457 static const char *imx23_dt_compat[] __initdata = { 458 "fsl,imx23", 459 NULL, 460 }; 461 462 static const char *imx28_dt_compat[] __initdata = { 463 "fsl,imx28", 464 NULL, 465 }; 466 467 DT_MACHINE_START(IMX23, "Freescale i.MX23 (Device Tree)") 468 .map_io = mx23_map_io, 469 .init_irq = icoll_init_irq, 470 .handle_irq = icoll_handle_irq, 471 .init_time = imx23_timer_init, 472 .init_machine = mxs_machine_init, 473 .dt_compat = imx23_dt_compat, 474 .restart = mxs_restart, 475 MACHINE_END 476 477 DT_MACHINE_START(IMX28, "Freescale i.MX28 (Device Tree)") 478 .map_io = mx28_map_io, 479 .init_irq = icoll_init_irq, 480 .handle_irq = icoll_handle_irq, 481 .init_time = imx28_timer_init, 482 .init_machine = mxs_machine_init, 483 .dt_compat = imx28_dt_compat, 484 .restart = mxs_restart, 485 MACHINE_END 486