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/err.h> 16 #include <linux/init.h> 17 #include <linux/init.h> 18 #include <linux/irqdomain.h> 19 #include <linux/micrel_phy.h> 20 #include <linux/mxsfb.h> 21 #include <linux/of_irq.h> 22 #include <linux/of_platform.h> 23 #include <linux/phy.h> 24 #include <asm/mach/arch.h> 25 #include <asm/mach/time.h> 26 #include <mach/common.h> 27 28 static struct fb_videomode mx23evk_video_modes[] = { 29 { 30 .name = "Samsung-LMS430HF02", 31 .refresh = 60, 32 .xres = 480, 33 .yres = 272, 34 .pixclock = 108096, /* picosecond (9.2 MHz) */ 35 .left_margin = 15, 36 .right_margin = 8, 37 .upper_margin = 12, 38 .lower_margin = 4, 39 .hsync_len = 1, 40 .vsync_len = 1, 41 .sync = FB_SYNC_DATA_ENABLE_HIGH_ACT | 42 FB_SYNC_DOTCLK_FAILING_ACT, 43 }, 44 }; 45 46 static struct fb_videomode mx28evk_video_modes[] = { 47 { 48 .name = "Seiko-43WVF1G", 49 .refresh = 60, 50 .xres = 800, 51 .yres = 480, 52 .pixclock = 29851, /* picosecond (33.5 MHz) */ 53 .left_margin = 89, 54 .right_margin = 164, 55 .upper_margin = 23, 56 .lower_margin = 10, 57 .hsync_len = 10, 58 .vsync_len = 10, 59 .sync = FB_SYNC_DATA_ENABLE_HIGH_ACT | 60 FB_SYNC_DOTCLK_FAILING_ACT, 61 }, 62 }; 63 64 static struct fb_videomode m28evk_video_modes[] = { 65 { 66 .name = "Ampire AM-800480R2TMQW-T01H", 67 .refresh = 60, 68 .xres = 800, 69 .yres = 480, 70 .pixclock = 30066, /* picosecond (33.26 MHz) */ 71 .left_margin = 0, 72 .right_margin = 256, 73 .upper_margin = 0, 74 .lower_margin = 45, 75 .hsync_len = 1, 76 .vsync_len = 1, 77 .sync = FB_SYNC_DATA_ENABLE_HIGH_ACT, 78 }, 79 }; 80 81 static struct fb_videomode apx4devkit_video_modes[] = { 82 { 83 .name = "HannStar PJ70112A", 84 .refresh = 60, 85 .xres = 800, 86 .yres = 480, 87 .pixclock = 33333, /* picosecond (30.00 MHz) */ 88 .left_margin = 88, 89 .right_margin = 40, 90 .upper_margin = 32, 91 .lower_margin = 13, 92 .hsync_len = 48, 93 .vsync_len = 3, 94 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT | 95 FB_SYNC_DATA_ENABLE_HIGH_ACT | 96 FB_SYNC_DOTCLK_FAILING_ACT, 97 }, 98 }; 99 100 static struct mxsfb_platform_data mxsfb_pdata __initdata; 101 102 static struct of_dev_auxdata mxs_auxdata_lookup[] __initdata = { 103 OF_DEV_AUXDATA("fsl,imx23-lcdif", 0x80030000, NULL, &mxsfb_pdata), 104 OF_DEV_AUXDATA("fsl,imx28-lcdif", 0x80030000, NULL, &mxsfb_pdata), 105 { /* sentinel */ } 106 }; 107 108 static int __init mxs_icoll_add_irq_domain(struct device_node *np, 109 struct device_node *interrupt_parent) 110 { 111 irq_domain_add_legacy(np, 128, 0, 0, &irq_domain_simple_ops, NULL); 112 113 return 0; 114 } 115 116 static int __init mxs_gpio_add_irq_domain(struct device_node *np, 117 struct device_node *interrupt_parent) 118 { 119 static int gpio_irq_base = MXS_GPIO_IRQ_START; 120 121 irq_domain_add_legacy(np, 32, gpio_irq_base, 0, &irq_domain_simple_ops, NULL); 122 gpio_irq_base += 32; 123 124 return 0; 125 } 126 127 static const struct of_device_id mxs_irq_match[] __initconst = { 128 { .compatible = "fsl,mxs-icoll", .data = mxs_icoll_add_irq_domain, }, 129 { .compatible = "fsl,mxs-gpio", .data = mxs_gpio_add_irq_domain, }, 130 { /* sentinel */ } 131 }; 132 133 static void __init mxs_dt_init_irq(void) 134 { 135 icoll_init_irq(); 136 of_irq_init(mxs_irq_match); 137 } 138 139 static void __init imx23_timer_init(void) 140 { 141 mx23_clocks_init(); 142 } 143 144 static struct sys_timer imx23_timer = { 145 .init = imx23_timer_init, 146 }; 147 148 static void __init imx28_timer_init(void) 149 { 150 mx28_clocks_init(); 151 } 152 153 static struct sys_timer imx28_timer = { 154 .init = imx28_timer_init, 155 }; 156 157 enum mac_oui { 158 OUI_FSL, 159 OUI_DENX, 160 }; 161 162 static void __init update_fec_mac_prop(enum mac_oui oui) 163 { 164 struct device_node *np, *from = NULL; 165 struct property *newmac; 166 const u32 *ocotp = mxs_get_ocotp(); 167 u8 *macaddr; 168 u32 val; 169 int i; 170 171 for (i = 0; i < 2; i++) { 172 np = of_find_compatible_node(from, NULL, "fsl,imx28-fec"); 173 if (!np) 174 return; 175 from = np; 176 177 newmac = kzalloc(sizeof(*newmac) + 6, GFP_KERNEL); 178 if (!newmac) 179 return; 180 newmac->value = newmac + 1; 181 newmac->length = 6; 182 183 newmac->name = kstrdup("local-mac-address", GFP_KERNEL); 184 if (!newmac->name) { 185 kfree(newmac); 186 return; 187 } 188 189 /* 190 * OCOTP only stores the last 4 octets for each mac address, 191 * so hard-code OUI here. 192 */ 193 macaddr = newmac->value; 194 switch (oui) { 195 case OUI_FSL: 196 macaddr[0] = 0x00; 197 macaddr[1] = 0x04; 198 macaddr[2] = 0x9f; 199 break; 200 case OUI_DENX: 201 macaddr[0] = 0xc0; 202 macaddr[1] = 0xe5; 203 macaddr[2] = 0x4e; 204 break; 205 } 206 val = ocotp[i]; 207 macaddr[3] = (val >> 16) & 0xff; 208 macaddr[4] = (val >> 8) & 0xff; 209 macaddr[5] = (val >> 0) & 0xff; 210 211 prom_update_property(np, newmac); 212 } 213 } 214 215 static void __init imx23_evk_init(void) 216 { 217 mxsfb_pdata.mode_list = mx23evk_video_modes; 218 mxsfb_pdata.mode_count = ARRAY_SIZE(mx23evk_video_modes); 219 mxsfb_pdata.default_bpp = 32; 220 mxsfb_pdata.ld_intf_width = STMLCDIF_24BIT; 221 } 222 223 static inline void enable_clk_enet_out(void) 224 { 225 struct clk *clk = clk_get_sys("enet_out", NULL); 226 227 if (!IS_ERR(clk)) 228 clk_prepare_enable(clk); 229 } 230 231 static void __init imx28_evk_init(void) 232 { 233 enable_clk_enet_out(); 234 update_fec_mac_prop(OUI_FSL); 235 236 mxsfb_pdata.mode_list = mx28evk_video_modes; 237 mxsfb_pdata.mode_count = ARRAY_SIZE(mx28evk_video_modes); 238 mxsfb_pdata.default_bpp = 32; 239 mxsfb_pdata.ld_intf_width = STMLCDIF_24BIT; 240 } 241 242 static void __init m28evk_init(void) 243 { 244 enable_clk_enet_out(); 245 update_fec_mac_prop(OUI_DENX); 246 247 mxsfb_pdata.mode_list = m28evk_video_modes; 248 mxsfb_pdata.mode_count = ARRAY_SIZE(m28evk_video_modes); 249 mxsfb_pdata.default_bpp = 16; 250 mxsfb_pdata.ld_intf_width = STMLCDIF_18BIT; 251 } 252 253 static int apx4devkit_phy_fixup(struct phy_device *phy) 254 { 255 phy->dev_flags |= MICREL_PHY_50MHZ_CLK; 256 return 0; 257 } 258 259 static void __init apx4devkit_init(void) 260 { 261 enable_clk_enet_out(); 262 263 if (IS_BUILTIN(CONFIG_PHYLIB)) 264 phy_register_fixup_for_uid(PHY_ID_KS8051, MICREL_PHY_ID_MASK, 265 apx4devkit_phy_fixup); 266 267 mxsfb_pdata.mode_list = apx4devkit_video_modes; 268 mxsfb_pdata.mode_count = ARRAY_SIZE(apx4devkit_video_modes); 269 mxsfb_pdata.default_bpp = 32; 270 mxsfb_pdata.ld_intf_width = STMLCDIF_24BIT; 271 } 272 273 static void __init mxs_machine_init(void) 274 { 275 if (of_machine_is_compatible("fsl,imx28-evk")) 276 imx28_evk_init(); 277 else if (of_machine_is_compatible("fsl,imx23-evk")) 278 imx23_evk_init(); 279 else if (of_machine_is_compatible("denx,m28evk")) 280 m28evk_init(); 281 else if (of_machine_is_compatible("bluegiga,apx4devkit")) 282 apx4devkit_init(); 283 284 of_platform_populate(NULL, of_default_bus_match_table, 285 mxs_auxdata_lookup, NULL); 286 } 287 288 static const char *imx23_dt_compat[] __initdata = { 289 "fsl,imx23-evk", 290 "fsl,stmp378x_devb" 291 "olimex,imx23-olinuxino", 292 "fsl,imx23", 293 NULL, 294 }; 295 296 static const char *imx28_dt_compat[] __initdata = { 297 "bluegiga,apx4devkit", 298 "crystalfontz,cfa10036", 299 "denx,m28evk", 300 "fsl,imx28-evk", 301 "karo,tx28", 302 "fsl,imx28", 303 NULL, 304 }; 305 306 DT_MACHINE_START(IMX23, "Freescale i.MX23 (Device Tree)") 307 .map_io = mx23_map_io, 308 .init_irq = mxs_dt_init_irq, 309 .timer = &imx23_timer, 310 .init_machine = mxs_machine_init, 311 .dt_compat = imx23_dt_compat, 312 .restart = mxs_restart, 313 MACHINE_END 314 315 DT_MACHINE_START(IMX28, "Freescale i.MX28 (Device Tree)") 316 .map_io = mx28_map_io, 317 .init_irq = mxs_dt_init_irq, 318 .timer = &imx28_timer, 319 .init_machine = mxs_machine_init, 320 .dt_compat = imx28_dt_compat, 321 .restart = mxs_restart, 322 MACHINE_END 323