mach-mxs.c 7.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*
 * Copyright 2012 Freescale Semiconductor, Inc.
 * Copyright 2012 Linaro Ltd.
 *
 * The code contained herein is licensed under the GNU General Public
 * License. You may obtain a copy of the GNU General Public License
 * Version 2 or later at the following locations:
 *
 * http://www.opensource.org/licenses/gpl-license.html
 * http://www.gnu.org/copyleft/gpl.html
 */

#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/init.h>
#include <linux/irqdomain.h>
19
#include <linux/micrel_phy.h>
20
#include <linux/mxsfb.h>
21 22
#include <linux/of_irq.h>
#include <linux/of_platform.h>
23
#include <linux/phy.h>
24 25 26 27
#include <asm/mach/arch.h>
#include <asm/mach/time.h>
#include <mach/common.h>

28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
static struct fb_videomode mx23evk_video_modes[] = {
	{
		.name		= "Samsung-LMS430HF02",
		.refresh	= 60,
		.xres		= 480,
		.yres		= 272,
		.pixclock	= 108096, /* picosecond (9.2 MHz) */
		.left_margin	= 15,
		.right_margin	= 8,
		.upper_margin	= 12,
		.lower_margin	= 4,
		.hsync_len	= 1,
		.vsync_len	= 1,
		.sync		= FB_SYNC_DATA_ENABLE_HIGH_ACT |
				  FB_SYNC_DOTCLK_FAILING_ACT,
	},
};

static struct fb_videomode mx28evk_video_modes[] = {
	{
		.name		= "Seiko-43WVF1G",
		.refresh	= 60,
		.xres		= 800,
		.yres		= 480,
		.pixclock	= 29851, /* picosecond (33.5 MHz) */
		.left_margin	= 89,
		.right_margin	= 164,
		.upper_margin	= 23,
		.lower_margin	= 10,
		.hsync_len	= 10,
		.vsync_len	= 10,
		.sync		= FB_SYNC_DATA_ENABLE_HIGH_ACT |
				  FB_SYNC_DOTCLK_FAILING_ACT,
	},
};

64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
static struct fb_videomode m28evk_video_modes[] = {
	{
		.name		= "Ampire AM-800480R2TMQW-T01H",
		.refresh	= 60,
		.xres		= 800,
		.yres		= 480,
		.pixclock	= 30066, /* picosecond (33.26 MHz) */
		.left_margin	= 0,
		.right_margin	= 256,
		.upper_margin	= 0,
		.lower_margin	= 45,
		.hsync_len	= 1,
		.vsync_len	= 1,
		.sync		= FB_SYNC_DATA_ENABLE_HIGH_ACT,
	},
};

81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
static struct fb_videomode apx4devkit_video_modes[] = {
	{
		.name		= "HannStar PJ70112A",
		.refresh	= 60,
		.xres		= 800,
		.yres		= 480,
		.pixclock	= 33333, /* picosecond (30.00 MHz) */
		.left_margin	= 88,
		.right_margin	= 40,
		.upper_margin	= 32,
		.lower_margin	= 13,
		.hsync_len	= 48,
		.vsync_len	= 3,
		.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT |
				  FB_SYNC_DATA_ENABLE_HIGH_ACT |
				  FB_SYNC_DOTCLK_FAILING_ACT,
	},
};

100 101 102 103 104 105 106 107
static struct mxsfb_platform_data mxsfb_pdata __initdata;

static struct of_dev_auxdata mxs_auxdata_lookup[] __initdata = {
	OF_DEV_AUXDATA("fsl,imx23-lcdif", 0x80030000, NULL, &mxsfb_pdata),
	OF_DEV_AUXDATA("fsl,imx28-lcdif", 0x80030000, NULL, &mxsfb_pdata),
	{ /* sentinel */ }
};

108 109 110 111 112 113 114 115
static int __init mxs_icoll_add_irq_domain(struct device_node *np,
				struct device_node *interrupt_parent)
{
	irq_domain_add_legacy(np, 128, 0, 0, &irq_domain_simple_ops, NULL);

	return 0;
}

116 117 118 119 120 121 122 123 124 125 126
static int __init mxs_gpio_add_irq_domain(struct device_node *np,
				struct device_node *interrupt_parent)
{
	static int gpio_irq_base = MXS_GPIO_IRQ_START;

	irq_domain_add_legacy(np, 32, gpio_irq_base, 0, &irq_domain_simple_ops, NULL);
	gpio_irq_base += 32;

	return 0;
}

127 128
static const struct of_device_id mxs_irq_match[] __initconst = {
	{ .compatible = "fsl,mxs-icoll", .data = mxs_icoll_add_irq_domain, },
129
	{ .compatible = "fsl,mxs-gpio", .data = mxs_gpio_add_irq_domain, },
130 131 132 133 134 135 136 137 138
	{ /* sentinel */ }
};

static void __init mxs_dt_init_irq(void)
{
	icoll_init_irq();
	of_irq_init(mxs_irq_match);
}

139 140 141 142 143 144 145 146 147
static void __init imx23_timer_init(void)
{
	mx23_clocks_init();
}

static struct sys_timer imx23_timer = {
	.init = imx23_timer_init,
};

148 149 150 151 152 153 154 155 156
static void __init imx28_timer_init(void)
{
	mx28_clocks_init();
}

static struct sys_timer imx28_timer = {
	.init = imx28_timer_init,
};

157 158 159 160 161 162 163 164
enum mac_oui {
	OUI_FSL,
	OUI_DENX,
};

static void __init update_fec_mac_prop(enum mac_oui oui)
{
	struct device_node *np, *from = NULL;
165
	struct property *newmac;
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
	const u32 *ocotp = mxs_get_ocotp();
	u8 *macaddr;
	u32 val;
	int i;

	for (i = 0; i < 2; i++) {
		np = of_find_compatible_node(from, NULL, "fsl,imx28-fec");
		if (!np)
			return;
		from = np;

		newmac = kzalloc(sizeof(*newmac) + 6, GFP_KERNEL);
		if (!newmac)
			return;
		newmac->value = newmac + 1;
		newmac->length = 6;

		newmac->name = kstrdup("local-mac-address", GFP_KERNEL);
		if (!newmac->name) {
			kfree(newmac);
			return;
		}

		/*
		 * OCOTP only stores the last 4 octets for each mac address,
		 * so hard-code OUI here.
		 */
		macaddr = newmac->value;
		switch (oui) {
		case OUI_FSL:
			macaddr[0] = 0x00;
			macaddr[1] = 0x04;
			macaddr[2] = 0x9f;
			break;
		case OUI_DENX:
			macaddr[0] = 0xc0;
			macaddr[1] = 0xe5;
			macaddr[2] = 0x4e;
			break;
		}
		val = ocotp[i];
		macaddr[3] = (val >> 16) & 0xff;
		macaddr[4] = (val >> 8) & 0xff;
		macaddr[5] = (val >> 0) & 0xff;

211
		prom_update_property(np, newmac);
212 213 214
	}
}

215 216 217 218 219 220 221 222
static void __init imx23_evk_init(void)
{
	mxsfb_pdata.mode_list = mx23evk_video_modes;
	mxsfb_pdata.mode_count = ARRAY_SIZE(mx23evk_video_modes);
	mxsfb_pdata.default_bpp = 32;
	mxsfb_pdata.ld_intf_width = STMLCDIF_24BIT;
}

223
static inline void enable_clk_enet_out(void)
224
{
225
	struct clk *clk = clk_get_sys("enet_out", NULL);
226 227 228

	if (!IS_ERR(clk))
		clk_prepare_enable(clk);
229
}
230

231 232 233
static void __init imx28_evk_init(void)
{
	enable_clk_enet_out();
234
	update_fec_mac_prop(OUI_FSL);
235 236 237 238 239

	mxsfb_pdata.mode_list = mx28evk_video_modes;
	mxsfb_pdata.mode_count = ARRAY_SIZE(mx28evk_video_modes);
	mxsfb_pdata.default_bpp = 32;
	mxsfb_pdata.ld_intf_width = STMLCDIF_24BIT;
240 241
}

242 243 244 245 246 247 248 249 250 251 252
static void __init m28evk_init(void)
{
	enable_clk_enet_out();
	update_fec_mac_prop(OUI_DENX);

	mxsfb_pdata.mode_list = m28evk_video_modes;
	mxsfb_pdata.mode_count = ARRAY_SIZE(m28evk_video_modes);
	mxsfb_pdata.default_bpp = 16;
	mxsfb_pdata.ld_intf_width = STMLCDIF_18BIT;
}

253 254 255 256 257 258 259 260 261 262 263 264 265
static int apx4devkit_phy_fixup(struct phy_device *phy)
{
	phy->dev_flags |= MICREL_PHY_50MHZ_CLK;
	return 0;
}

static void __init apx4devkit_init(void)
{
	enable_clk_enet_out();

	if (IS_BUILTIN(CONFIG_PHYLIB))
		phy_register_fixup_for_uid(PHY_ID_KS8051, MICREL_PHY_ID_MASK,
					   apx4devkit_phy_fixup);
266 267 268 269 270

	mxsfb_pdata.mode_list = apx4devkit_video_modes;
	mxsfb_pdata.mode_count = ARRAY_SIZE(apx4devkit_video_modes);
	mxsfb_pdata.default_bpp = 32;
	mxsfb_pdata.ld_intf_width = STMLCDIF_24BIT;
271 272
}

273 274 275 276
static void __init mxs_machine_init(void)
{
	if (of_machine_is_compatible("fsl,imx28-evk"))
		imx28_evk_init();
277 278
	else if (of_machine_is_compatible("fsl,imx23-evk"))
		imx23_evk_init();
279 280
	else if (of_machine_is_compatible("denx,m28evk"))
		m28evk_init();
281 282
	else if (of_machine_is_compatible("bluegiga,apx4devkit"))
		apx4devkit_init();
283 284

	of_platform_populate(NULL, of_default_bus_match_table,
285
			     mxs_auxdata_lookup, NULL);
286 287
}

288 289
static const char *imx23_dt_compat[] __initdata = {
	"fsl,imx23-evk",
290
	"fsl,stmp378x_devb"
291
	"olimex,imx23-olinuxino",
292 293 294 295
	"fsl,imx23",
	NULL,
};

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 303 304 305
	"fsl,imx28",
	NULL,
};

306 307 308 309 310 311 312 313 314
DT_MACHINE_START(IMX23, "Freescale i.MX23 (Device Tree)")
	.map_io		= mx23_map_io,
	.init_irq	= mxs_dt_init_irq,
	.timer		= &imx23_timer,
	.init_machine	= mxs_machine_init,
	.dt_compat	= imx23_dt_compat,
	.restart	= mxs_restart,
MACHINE_END

315 316 317 318 319 320 321 322
DT_MACHINE_START(IMX28, "Freescale i.MX28 (Device Tree)")
	.map_io		= mx28_map_io,
	.init_irq	= mxs_dt_init_irq,
	.timer		= &imx28_timer,
	.init_machine	= mxs_machine_init,
	.dt_compat	= imx28_dt_compat,
	.restart	= mxs_restart,
MACHINE_END