mach-mxs.c 6.8 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
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 */ }
};

89 90 91 92 93 94 95 96
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;
}

97 98 99 100 101 102 103 104 105 106 107
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;
}

108 109
static const struct of_device_id mxs_irq_match[] __initconst = {
	{ .compatible = "fsl,mxs-icoll", .data = mxs_icoll_add_irq_domain, },
110
	{ .compatible = "fsl,mxs-gpio", .data = mxs_gpio_add_irq_domain, },
111 112 113 114 115 116 117 118 119
	{ /* sentinel */ }
};

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

120 121 122 123 124 125 126 127 128
static void __init imx23_timer_init(void)
{
	mx23_clocks_init();
}

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

129 130 131 132 133 134 135 136 137
static void __init imx28_timer_init(void)
{
	mx28_clocks_init();
}

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

138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 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
enum mac_oui {
	OUI_FSL,
	OUI_DENX,
};

static void __init update_fec_mac_prop(enum mac_oui oui)
{
	struct device_node *np, *from = NULL;
	struct property *oldmac, *newmac;
	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;

		oldmac = of_find_property(np, newmac->name, NULL);
		if (oldmac)
			prom_update_property(np, newmac, oldmac);
		else
			prom_add_property(np, newmac);
	}
}

200 201 202 203 204 205 206 207
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;
}

208
static inline void enable_clk_enet_out(void)
209
{
210
	struct clk *clk = clk_get_sys("enet_out", NULL);
211 212 213

	if (!IS_ERR(clk))
		clk_prepare_enable(clk);
214
}
215

216 217 218
static void __init imx28_evk_init(void)
{
	enable_clk_enet_out();
219
	update_fec_mac_prop(OUI_FSL);
220 221 222 223 224

	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;
225 226
}

227 228 229 230 231 232 233 234 235 236 237
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;
}

238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
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);
}

253 254 255 256
static void __init mxs_machine_init(void)
{
	if (of_machine_is_compatible("fsl,imx28-evk"))
		imx28_evk_init();
257 258
	else if (of_machine_is_compatible("fsl,imx23-evk"))
		imx23_evk_init();
259 260
	else if (of_machine_is_compatible("denx,m28evk"))
		m28evk_init();
261 262
	else if (of_machine_is_compatible("bluegiga,apx4devkit"))
		apx4devkit_init();
263 264

	of_platform_populate(NULL, of_default_bus_match_table,
265
			     mxs_auxdata_lookup, NULL);
266 267
}

268 269
static const char *imx23_dt_compat[] __initdata = {
	"fsl,imx23-evk",
270
	"fsl,stmp378x_devb"
271
	"olimex,imx23-olinuxino",
272 273 274 275
	"fsl,imx23",
	NULL,
};

276
static const char *imx28_dt_compat[] __initdata = {
277
	"bluegiga,apx4devkit",
278
	"crystalfontz,cfa10036",
279
	"denx,m28evk",
280
	"fsl,imx28-evk",
281
	"karo,tx28",
282 283 284 285
	"fsl,imx28",
	NULL,
};

286 287 288 289 290 291 292 293 294
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

295 296 297 298 299 300 301 302
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