mach-mxs.c revision 3143bbb42b3d27a5f799c97c84fb7a4a1de88f91
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 28static 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 46static 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 64static 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 81static struct mxsfb_platform_data mxsfb_pdata __initdata; 82 83static struct of_dev_auxdata mxs_auxdata_lookup[] __initdata = { 84 OF_DEV_AUXDATA("fsl,imx23-lcdif", 0x80030000, NULL, &mxsfb_pdata), 85 OF_DEV_AUXDATA("fsl,imx28-lcdif", 0x80030000, NULL, &mxsfb_pdata), 86 { /* sentinel */ } 87}; 88 89static int __init mxs_icoll_add_irq_domain(struct device_node *np, 90 struct device_node *interrupt_parent) 91{ 92 irq_domain_add_legacy(np, 128, 0, 0, &irq_domain_simple_ops, NULL); 93 94 return 0; 95} 96 97static int __init mxs_gpio_add_irq_domain(struct device_node *np, 98 struct device_node *interrupt_parent) 99{ 100 static int gpio_irq_base = MXS_GPIO_IRQ_START; 101 102 irq_domain_add_legacy(np, 32, gpio_irq_base, 0, &irq_domain_simple_ops, NULL); 103 gpio_irq_base += 32; 104 105 return 0; 106} 107 108static const struct of_device_id mxs_irq_match[] __initconst = { 109 { .compatible = "fsl,mxs-icoll", .data = mxs_icoll_add_irq_domain, }, 110 { .compatible = "fsl,mxs-gpio", .data = mxs_gpio_add_irq_domain, }, 111 { /* sentinel */ } 112}; 113 114static void __init mxs_dt_init_irq(void) 115{ 116 icoll_init_irq(); 117 of_irq_init(mxs_irq_match); 118} 119 120static void __init imx23_timer_init(void) 121{ 122 mx23_clocks_init(); 123} 124 125static struct sys_timer imx23_timer = { 126 .init = imx23_timer_init, 127}; 128 129static void __init imx28_timer_init(void) 130{ 131 mx28_clocks_init(); 132} 133 134static struct sys_timer imx28_timer = { 135 .init = imx28_timer_init, 136}; 137 138enum mac_oui { 139 OUI_FSL, 140 OUI_DENX, 141}; 142 143static void __init update_fec_mac_prop(enum mac_oui oui) 144{ 145 struct device_node *np, *from = NULL; 146 struct property *oldmac, *newmac; 147 const u32 *ocotp = mxs_get_ocotp(); 148 u8 *macaddr; 149 u32 val; 150 int i; 151 152 for (i = 0; i < 2; i++) { 153 np = of_find_compatible_node(from, NULL, "fsl,imx28-fec"); 154 if (!np) 155 return; 156 from = np; 157 158 newmac = kzalloc(sizeof(*newmac) + 6, GFP_KERNEL); 159 if (!newmac) 160 return; 161 newmac->value = newmac + 1; 162 newmac->length = 6; 163 164 newmac->name = kstrdup("local-mac-address", GFP_KERNEL); 165 if (!newmac->name) { 166 kfree(newmac); 167 return; 168 } 169 170 /* 171 * OCOTP only stores the last 4 octets for each mac address, 172 * so hard-code OUI here. 173 */ 174 macaddr = newmac->value; 175 switch (oui) { 176 case OUI_FSL: 177 macaddr[0] = 0x00; 178 macaddr[1] = 0x04; 179 macaddr[2] = 0x9f; 180 break; 181 case OUI_DENX: 182 macaddr[0] = 0xc0; 183 macaddr[1] = 0xe5; 184 macaddr[2] = 0x4e; 185 break; 186 } 187 val = ocotp[i]; 188 macaddr[3] = (val >> 16) & 0xff; 189 macaddr[4] = (val >> 8) & 0xff; 190 macaddr[5] = (val >> 0) & 0xff; 191 192 oldmac = of_find_property(np, newmac->name, NULL); 193 if (oldmac) 194 prom_update_property(np, newmac, oldmac); 195 else 196 prom_add_property(np, newmac); 197 } 198} 199 200static void __init imx23_evk_init(void) 201{ 202 mxsfb_pdata.mode_list = mx23evk_video_modes; 203 mxsfb_pdata.mode_count = ARRAY_SIZE(mx23evk_video_modes); 204 mxsfb_pdata.default_bpp = 32; 205 mxsfb_pdata.ld_intf_width = STMLCDIF_24BIT; 206} 207 208static inline void enable_clk_enet_out(void) 209{ 210 struct clk *clk = clk_get_sys("enet_out", NULL); 211 212 if (!IS_ERR(clk)) 213 clk_prepare_enable(clk); 214} 215 216static void __init imx28_evk_init(void) 217{ 218 enable_clk_enet_out(); 219 update_fec_mac_prop(OUI_FSL); 220 221 mxsfb_pdata.mode_list = mx28evk_video_modes; 222 mxsfb_pdata.mode_count = ARRAY_SIZE(mx28evk_video_modes); 223 mxsfb_pdata.default_bpp = 32; 224 mxsfb_pdata.ld_intf_width = STMLCDIF_24BIT; 225} 226 227static void __init m28evk_init(void) 228{ 229 enable_clk_enet_out(); 230 update_fec_mac_prop(OUI_DENX); 231 232 mxsfb_pdata.mode_list = m28evk_video_modes; 233 mxsfb_pdata.mode_count = ARRAY_SIZE(m28evk_video_modes); 234 mxsfb_pdata.default_bpp = 16; 235 mxsfb_pdata.ld_intf_width = STMLCDIF_18BIT; 236} 237 238static int apx4devkit_phy_fixup(struct phy_device *phy) 239{ 240 phy->dev_flags |= MICREL_PHY_50MHZ_CLK; 241 return 0; 242} 243 244static void __init apx4devkit_init(void) 245{ 246 enable_clk_enet_out(); 247 248 if (IS_BUILTIN(CONFIG_PHYLIB)) 249 phy_register_fixup_for_uid(PHY_ID_KS8051, MICREL_PHY_ID_MASK, 250 apx4devkit_phy_fixup); 251} 252 253static void __init mxs_machine_init(void) 254{ 255 if (of_machine_is_compatible("fsl,imx28-evk")) 256 imx28_evk_init(); 257 else if (of_machine_is_compatible("fsl,imx23-evk")) 258 imx23_evk_init(); 259 else if (of_machine_is_compatible("denx,m28evk")) 260 m28evk_init(); 261 else if (of_machine_is_compatible("bluegiga,apx4devkit")) 262 apx4devkit_init(); 263 264 of_platform_populate(NULL, of_default_bus_match_table, 265 mxs_auxdata_lookup, NULL); 266} 267 268static const char *imx23_dt_compat[] __initdata = { 269 "fsl,imx23-evk", 270 "olimex,imx23-olinuxino", 271 "fsl,imx23", 272 NULL, 273}; 274 275static const char *imx28_dt_compat[] __initdata = { 276 "bluegiga,apx4devkit", 277 "crystalfontz,cfa10036", 278 "denx,m28evk", 279 "fsl,imx28-evk", 280 "fsl,imx28", 281 NULL, 282}; 283 284DT_MACHINE_START(IMX23, "Freescale i.MX23 (Device Tree)") 285 .map_io = mx23_map_io, 286 .init_irq = mxs_dt_init_irq, 287 .timer = &imx23_timer, 288 .init_machine = mxs_machine_init, 289 .dt_compat = imx23_dt_compat, 290 .restart = mxs_restart, 291MACHINE_END 292 293DT_MACHINE_START(IMX28, "Freescale i.MX28 (Device Tree)") 294 .map_io = mx28_map_io, 295 .init_irq = mxs_dt_init_irq, 296 .timer = &imx28_timer, 297 .init_machine = mxs_machine_init, 298 .dt_compat = imx28_dt_compat, 299 .restart = mxs_restart, 300MACHINE_END 301