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