xref: /openbmc/linux/arch/sh/boards/mach-migor/setup.c (revision 939a24a6)
1 /*
2  * Renesas System Solutions Asia Pte. Ltd - Migo-R
3  *
4  * Copyright (C) 2008 Magnus Damm
5  *
6  * This file is subject to the terms and conditions of the GNU General Public
7  * License.  See the file "COPYING" in the main directory of this archive
8  * for more details.
9  */
10 #include <linux/init.h>
11 #include <linux/platform_device.h>
12 #include <linux/interrupt.h>
13 #include <linux/input.h>
14 #include <linux/mtd/physmap.h>
15 #include <linux/mtd/nand.h>
16 #include <linux/i2c.h>
17 #include <linux/smc91x.h>
18 #include <linux/delay.h>
19 #include <linux/clk.h>
20 #include <media/soc_camera_platform.h>
21 #include <media/sh_mobile_ceu.h>
22 #include <asm/clock.h>
23 #include <asm/machvec.h>
24 #include <asm/io.h>
25 #include <asm/sh_keysc.h>
26 #include <asm/sh_mobile_lcdc.h>
27 #include <asm/migor.h>
28 
29 /* Address     IRQ  Size  Bus  Description
30  * 0x00000000       64MB  16   NOR Flash (SP29PL256N)
31  * 0x0c000000       64MB  64   SDRAM (2xK4M563233G)
32  * 0x10000000  IRQ0       16   Ethernet (SMC91C111)
33  * 0x14000000  IRQ4       16   USB 2.0 Host Controller (M66596)
34  * 0x18000000       8GB    8   NAND Flash (K9K8G08U0A)
35  */
36 
37 static struct smc91x_platdata smc91x_info = {
38 	.flags = SMC91X_USE_16BIT,
39 };
40 
41 static struct resource smc91x_eth_resources[] = {
42 	[0] = {
43 		.name   = "SMC91C111" ,
44 		.start  = 0x10000300,
45 		.end    = 0x1000030f,
46 		.flags  = IORESOURCE_MEM,
47 	},
48 	[1] = {
49 		.start  = 32, /* IRQ0 */
50 		.flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
51 	},
52 };
53 
54 static struct platform_device smc91x_eth_device = {
55 	.name           = "smc91x",
56 	.num_resources  = ARRAY_SIZE(smc91x_eth_resources),
57 	.resource       = smc91x_eth_resources,
58 	.dev	= {
59 		.platform_data	= &smc91x_info,
60 	},
61 };
62 
63 static struct sh_keysc_info sh_keysc_info = {
64 	.mode = SH_KEYSC_MODE_2, /* KEYOUT0->4, KEYIN1->5 */
65 	.scan_timing = 3,
66 	.delay = 5,
67 	.keycodes = {
68 		0, KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_ENTER,
69 		0, KEY_F, KEY_C, KEY_D,	KEY_H, KEY_1,
70 		0, KEY_2, KEY_3, KEY_4,	KEY_5, KEY_6,
71 		0, KEY_7, KEY_8, KEY_9, KEY_S, KEY_0,
72 		0, KEY_P, KEY_STOP, KEY_REWIND, KEY_PLAY, KEY_FASTFORWARD,
73 	},
74 };
75 
76 static struct resource sh_keysc_resources[] = {
77 	[0] = {
78 		.start  = 0x044b0000,
79 		.end    = 0x044b000f,
80 		.flags  = IORESOURCE_MEM,
81 	},
82 	[1] = {
83 		.start  = 79,
84 		.flags  = IORESOURCE_IRQ,
85 	},
86 };
87 
88 static struct platform_device sh_keysc_device = {
89 	.name           = "sh_keysc",
90 	.num_resources  = ARRAY_SIZE(sh_keysc_resources),
91 	.resource       = sh_keysc_resources,
92 	.dev	= {
93 		.platform_data	= &sh_keysc_info,
94 	},
95 };
96 
97 static struct mtd_partition migor_nor_flash_partitions[] =
98 {
99 	{
100 		.name = "uboot",
101 		.offset = 0,
102 		.size = (1 * 1024 * 1024),
103 		.mask_flags = MTD_WRITEABLE,	/* Read-only */
104 	},
105 	{
106 		.name = "rootfs",
107 		.offset = MTDPART_OFS_APPEND,
108 		.size = (15 * 1024 * 1024),
109 	},
110 	{
111 		.name = "other",
112 		.offset = MTDPART_OFS_APPEND,
113 		.size = MTDPART_SIZ_FULL,
114 	},
115 };
116 
117 static struct physmap_flash_data migor_nor_flash_data = {
118 	.width		= 2,
119 	.parts		= migor_nor_flash_partitions,
120 	.nr_parts	= ARRAY_SIZE(migor_nor_flash_partitions),
121 };
122 
123 static struct resource migor_nor_flash_resources[] = {
124 	[0] = {
125 		.name		= "NOR Flash",
126 		.start		= 0x00000000,
127 		.end		= 0x03ffffff,
128 		.flags		= IORESOURCE_MEM,
129 	}
130 };
131 
132 static struct platform_device migor_nor_flash_device = {
133 	.name		= "physmap-flash",
134 	.resource	= migor_nor_flash_resources,
135 	.num_resources	= ARRAY_SIZE(migor_nor_flash_resources),
136 	.dev		= {
137 		.platform_data = &migor_nor_flash_data,
138 	},
139 };
140 
141 static struct mtd_partition migor_nand_flash_partitions[] = {
142 	{
143 		.name		= "nanddata1",
144 		.offset		= 0x0,
145 		.size		= 512 * 1024 * 1024,
146 	},
147 	{
148 		.name		= "nanddata2",
149 		.offset		= MTDPART_OFS_APPEND,
150 		.size		= 512 * 1024 * 1024,
151 	},
152 };
153 
154 static void migor_nand_flash_cmd_ctl(struct mtd_info *mtd, int cmd,
155 				     unsigned int ctrl)
156 {
157 	struct nand_chip *chip = mtd->priv;
158 
159 	if (cmd == NAND_CMD_NONE)
160 		return;
161 
162 	if (ctrl & NAND_CLE)
163 		writeb(cmd, chip->IO_ADDR_W + 0x00400000);
164 	else if (ctrl & NAND_ALE)
165 		writeb(cmd, chip->IO_ADDR_W + 0x00800000);
166 	else
167 		writeb(cmd, chip->IO_ADDR_W);
168 }
169 
170 static int migor_nand_flash_ready(struct mtd_info *mtd)
171 {
172 	return ctrl_inb(PORT_PADR) & 0x02; /* PTA1 */
173 }
174 
175 struct platform_nand_data migor_nand_flash_data = {
176 	.chip = {
177 		.nr_chips = 1,
178 		.partitions = migor_nand_flash_partitions,
179 		.nr_partitions = ARRAY_SIZE(migor_nand_flash_partitions),
180 		.chip_delay = 20,
181 		.part_probe_types = (const char *[]) { "cmdlinepart", NULL },
182 	},
183 	.ctrl = {
184 		.dev_ready = migor_nand_flash_ready,
185 		.cmd_ctrl = migor_nand_flash_cmd_ctl,
186 	},
187 };
188 
189 static struct resource migor_nand_flash_resources[] = {
190 	[0] = {
191 		.name		= "NAND Flash",
192 		.start		= 0x18000000,
193 		.end		= 0x18ffffff,
194 		.flags		= IORESOURCE_MEM,
195 	},
196 };
197 
198 static struct platform_device migor_nand_flash_device = {
199 	.name		= "gen_nand",
200 	.resource	= migor_nand_flash_resources,
201 	.num_resources	= ARRAY_SIZE(migor_nand_flash_resources),
202 	.dev		= {
203 		.platform_data = &migor_nand_flash_data,
204 	}
205 };
206 
207 static struct sh_mobile_lcdc_info sh_mobile_lcdc_info = {
208 #ifdef CONFIG_SH_MIGOR_RTA_WVGA
209 	.clock_source = LCDC_CLK_BUS,
210 	.ch[0] = {
211 		.chan = LCDC_CHAN_MAINLCD,
212 		.bpp = 16,
213 		.interface_type = RGB16,
214 		.clock_divider = 2,
215 		.lcd_cfg = {
216 			.name = "LB070WV1",
217 			.xres = 800,
218 			.yres = 480,
219 			.left_margin = 64,
220 			.right_margin = 16,
221 			.hsync_len = 120,
222 			.upper_margin = 1,
223 			.lower_margin = 17,
224 			.vsync_len = 2,
225 			.sync = 0,
226 		},
227 	}
228 #endif
229 #ifdef CONFIG_SH_MIGOR_QVGA
230 	.clock_source = LCDC_CLK_PERIPHERAL,
231 	.ch[0] = {
232 		.chan = LCDC_CHAN_MAINLCD,
233 		.bpp = 16,
234 		.interface_type = SYS16A,
235 		.clock_divider = 10,
236 		.lcd_cfg = {
237 			.name = "PH240320T",
238 			.xres = 320,
239 			.yres = 240,
240 			.left_margin = 0,
241 			.right_margin = 16,
242 			.hsync_len = 8,
243 			.upper_margin = 1,
244 			.lower_margin = 17,
245 			.vsync_len = 2,
246 			.sync = FB_SYNC_HOR_HIGH_ACT,
247 		},
248 		.board_cfg = {
249 			.setup_sys = migor_lcd_qvga_setup,
250 		},
251 		.sys_bus_cfg = {
252 			.ldmt2r = 0x06000a09,
253 			.ldmt3r = 0x180e3418,
254 		},
255 	}
256 #endif
257 };
258 
259 static struct resource migor_lcdc_resources[] = {
260 	[0] = {
261 		.name	= "LCDC",
262 		.start	= 0xfe940000, /* P4-only space */
263 		.end	= 0xfe941fff,
264 		.flags	= IORESOURCE_MEM,
265 	},
266 };
267 
268 static struct platform_device migor_lcdc_device = {
269 	.name		= "sh_mobile_lcdc_fb",
270 	.num_resources	= ARRAY_SIZE(migor_lcdc_resources),
271 	.resource	= migor_lcdc_resources,
272 	.dev	= {
273 		.platform_data	= &sh_mobile_lcdc_info,
274 	},
275 };
276 
277 static struct clk *camera_clk;
278 
279 static void camera_power_on(void)
280 {
281 	unsigned char value;
282 
283 	camera_clk = clk_get(NULL, "video_clk");
284 	clk_set_rate(camera_clk, 24000000);
285 	clk_enable(camera_clk);	/* start VIO_CKO */
286 
287 	mdelay(10);
288 	value = ctrl_inb(PORT_PTDR);
289 	value &= ~0x09;
290 #ifndef CONFIG_SH_MIGOR_RTA_WVGA
291 	value |= 0x01;
292 #endif
293 	ctrl_outb(value, PORT_PTDR);
294 	mdelay(10);
295 
296 	ctrl_outb(value | 8, PORT_PTDR);
297 }
298 
299 static void camera_power_off(void)
300 {
301 	clk_disable(camera_clk); /* stop VIO_CKO */
302 	clk_put(camera_clk);
303 
304 	ctrl_outb(ctrl_inb(PORT_PTDR) & ~0x08, PORT_PTDR);
305 }
306 
307 #ifdef CONFIG_I2C
308 static unsigned char camera_ov772x_magic[] =
309 {
310 	0x09, 0x01, 0x0c, 0x10, 0x0d, 0x41, 0x0e, 0x01,
311 	0x12, 0x00, 0x13, 0x8F, 0x14, 0x4A, 0x15, 0x00,
312 	0x16, 0x00, 0x17, 0x23, 0x18, 0xa0, 0x19, 0x07,
313 	0x1a, 0xf0, 0x1b, 0x40, 0x1f, 0x00, 0x20, 0x10,
314 	0x22, 0xff, 0x23, 0x01, 0x28, 0x00, 0x29, 0xa0,
315 	0x2a, 0x00, 0x2b, 0x00, 0x2c, 0xf0, 0x2d, 0x00,
316 	0x2e, 0x00, 0x30, 0x80, 0x31, 0x60, 0x32, 0x00,
317 	0x33, 0x00, 0x34, 0x00, 0x3d, 0x80, 0x3e, 0xe2,
318 	0x3f, 0x1f, 0x42, 0x80, 0x43, 0x80, 0x44, 0x80,
319 	0x45, 0x80, 0x46, 0x00, 0x47, 0x00, 0x48, 0x00,
320 	0x49, 0x50, 0x4a, 0x30, 0x4b, 0x50, 0x4c, 0x50,
321 	0x4d, 0x00, 0x4e, 0xef, 0x4f, 0x10, 0x50, 0x60,
322 	0x51, 0x00, 0x52, 0x00, 0x53, 0x24, 0x54, 0x7a,
323 	0x55, 0xfc, 0x62, 0xff, 0x63, 0xf0, 0x64, 0x1f,
324 	0x65, 0x00, 0x66, 0x10, 0x67, 0x00, 0x68, 0x00,
325 	0x69, 0x5c, 0x6a, 0x11, 0x6b, 0xa2, 0x6c, 0x01,
326 	0x6d, 0x50, 0x6e, 0x80, 0x6f, 0x80, 0x70, 0x0f,
327 	0x71, 0x00, 0x72, 0x00, 0x73, 0x0f, 0x74, 0x0f,
328 	0x75, 0xff, 0x78, 0x10, 0x79, 0x70, 0x7a, 0x70,
329 	0x7b, 0xf0, 0x7c, 0xf0, 0x7d, 0xf0, 0x7e, 0x0e,
330 	0x7f, 0x1a, 0x80, 0x31, 0x81, 0x5a, 0x82, 0x69,
331 	0x83, 0x75, 0x84, 0x7e, 0x85, 0x88, 0x86, 0x8f,
332 	0x87, 0x96, 0x88, 0xa3, 0x89, 0xaf, 0x8a, 0xc4,
333 	0x8b, 0xd7, 0x8c, 0xe8, 0x8d, 0x20, 0x8e, 0x00,
334 	0x8f, 0x00, 0x90, 0x08, 0x91, 0x10, 0x92, 0x1f,
335 	0x93, 0x01, 0x94, 0x2c, 0x95, 0x24, 0x96, 0x08,
336 	0x97, 0x14, 0x98, 0x24, 0x99, 0x38, 0x9a, 0x9e,
337 	0x9b, 0x00, 0x9c, 0x40, 0x9e, 0x11, 0x9f, 0x02,
338 	0xa0, 0x00, 0xa1, 0x40, 0xa2, 0x40, 0xa3, 0x06,
339 	0xa4, 0x00, 0xa6, 0x00, 0xa7, 0x40, 0xa8, 0x40,
340 	0xa9, 0x80, 0xaa, 0x80, 0xab, 0x06, 0xac, 0xff,
341 	0x12, 0x06, 0x64, 0x3f, 0x12, 0x46, 0x17, 0x3f,
342 	0x18, 0x50, 0x19, 0x03, 0x1a, 0x78, 0x29, 0x50,
343 	0x2c, 0x78,
344 };
345 
346 static int ov772x_set_capture(struct soc_camera_platform_info *info,
347 			      int enable)
348 {
349 	struct i2c_adapter *a = i2c_get_adapter(0);
350 	struct i2c_msg msg;
351 	int ret = 0;
352 	int i;
353 
354 	if (!enable)
355 		return 0; /* camera_power_off() is enough */
356 
357 	for (i = 0; i < ARRAY_SIZE(camera_ov772x_magic); i += 2) {
358 		u_int8_t buf[8];
359 
360 		msg.addr = 0x21;
361 		msg.buf = buf;
362 		msg.len = 2;
363 		msg.flags = 0;
364 
365 		buf[0] = camera_ov772x_magic[i];
366 		buf[1] = camera_ov772x_magic[i + 1];
367 
368 		ret = (ret < 0) ? ret : i2c_transfer(a, &msg, 1);
369 	}
370 
371 	return ret;
372 }
373 
374 static struct soc_camera_platform_info ov772x_info = {
375 	.iface = 0,
376 	.format_name = "RGB565",
377 	.format_depth = 16,
378 	.format = {
379 		.pixelformat = V4L2_PIX_FMT_RGB565,
380 		.colorspace = V4L2_COLORSPACE_SRGB,
381 		.width = 320,
382 		.height = 240,
383 	},
384 	.bus_param =  SOCAM_PCLK_SAMPLE_RISING | SOCAM_HSYNC_ACTIVE_HIGH |
385 	SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_MASTER | SOCAM_DATAWIDTH_8,
386 	.set_capture = ov772x_set_capture,
387 };
388 
389 static struct platform_device migor_camera_device = {
390 	.name		= "soc_camera_platform",
391 	.dev	= {
392 		.platform_data	= &ov772x_info,
393 	},
394 };
395 #endif /* CONFIG_I2C */
396 
397 static struct sh_mobile_ceu_info sh_mobile_ceu_info = {
398 	.flags = SOCAM_MASTER | SOCAM_DATAWIDTH_8 | SOCAM_PCLK_SAMPLE_RISING \
399 	| SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH,
400 	.enable_camera = camera_power_on,
401 	.disable_camera = camera_power_off,
402 };
403 
404 static struct resource migor_ceu_resources[] = {
405 	[0] = {
406 		.name	= "CEU",
407 		.start	= 0xfe910000,
408 		.end	= 0xfe91009f,
409 		.flags	= IORESOURCE_MEM,
410 	},
411 	[1] = {
412 		.start  = 52,
413 		.flags  = IORESOURCE_IRQ,
414 	},
415 	[2] = {
416 		/* place holder for contiguous memory */
417 	},
418 };
419 
420 static struct platform_device migor_ceu_device = {
421 	.name		= "sh_mobile_ceu",
422 	.num_resources	= ARRAY_SIZE(migor_ceu_resources),
423 	.resource	= migor_ceu_resources,
424 	.dev	= {
425 		.platform_data	= &sh_mobile_ceu_info,
426 	},
427 };
428 
429 static struct platform_device *migor_devices[] __initdata = {
430 	&smc91x_eth_device,
431 	&sh_keysc_device,
432 	&migor_lcdc_device,
433 	&migor_ceu_device,
434 #ifdef CONFIG_I2C
435 	&migor_camera_device,
436 #endif
437 	&migor_nor_flash_device,
438 	&migor_nand_flash_device,
439 };
440 
441 static struct i2c_board_info migor_i2c_devices[] = {
442 	{
443 		I2C_BOARD_INFO("rs5c372b", 0x32),
444 	},
445 	{
446 		I2C_BOARD_INFO("migor_ts", 0x51),
447 		.irq = 38, /* IRQ6 */
448 	},
449 };
450 
451 static int __init migor_devices_setup(void)
452 {
453 	clk_always_enable("mstp214"); /* KEYSC */
454 	clk_always_enable("mstp200"); /* LCDC */
455 	clk_always_enable("mstp203"); /* CEU */
456 
457 	platform_resource_setup_memory(&migor_ceu_device, "ceu", 4 << 20);
458 
459 	i2c_register_board_info(0, migor_i2c_devices,
460 				ARRAY_SIZE(migor_i2c_devices));
461 
462 	return platform_add_devices(migor_devices, ARRAY_SIZE(migor_devices));
463 }
464 __initcall(migor_devices_setup);
465 
466 static void __init migor_setup(char **cmdline_p)
467 {
468 	/* SMC91C111 - Enable IRQ0 */
469 	ctrl_outw(ctrl_inw(PORT_PJCR) & ~0x0003, PORT_PJCR);
470 
471 	/* KEYSC */
472 	ctrl_outw(ctrl_inw(PORT_PYCR) & ~0x0fff, PORT_PYCR);
473 	ctrl_outw(ctrl_inw(PORT_PZCR) & ~0x0ff0, PORT_PZCR);
474 	ctrl_outw(ctrl_inw(PORT_PSELA) & ~0x4100, PORT_PSELA);
475 	ctrl_outw(ctrl_inw(PORT_HIZCRA) & ~0x4000, PORT_HIZCRA);
476 	ctrl_outw(ctrl_inw(PORT_HIZCRC) & ~0xc000, PORT_HIZCRC);
477 
478 	/* NAND Flash */
479 	ctrl_outw(ctrl_inw(PORT_PXCR) & 0x0fff, PORT_PXCR);
480 	ctrl_outl((ctrl_inl(BSC_CS6ABCR) & ~0x00000600) | 0x00000200,
481 		  BSC_CS6ABCR);
482 
483 	/* Touch Panel - Enable IRQ6 */
484 	ctrl_outw(ctrl_inw(PORT_PZCR) & ~0xc, PORT_PZCR);
485 	ctrl_outw((ctrl_inw(PORT_PSELA) | 0x8000), PORT_PSELA);
486 	ctrl_outw((ctrl_inw(PORT_HIZCRC) & ~0x4000), PORT_HIZCRC);
487 
488 #ifdef CONFIG_SH_MIGOR_RTA_WVGA
489 	/* LCDC - WVGA - Enable RGB Interface signals */
490 	ctrl_outw(ctrl_inw(PORT_PACR) & ~0x0003, PORT_PACR);
491 	ctrl_outw(0x0000, PORT_PHCR);
492 	ctrl_outw(0x0000, PORT_PLCR);
493 	ctrl_outw(0x0000, PORT_PMCR);
494 	ctrl_outw(ctrl_inw(PORT_PRCR) & ~0x000f, PORT_PRCR);
495 	ctrl_outw((ctrl_inw(PORT_PSELD) & ~0x000d) | 0x0400, PORT_PSELD);
496 	ctrl_outw(ctrl_inw(PORT_MSELCRB) & ~0x0100, PORT_MSELCRB);
497 	ctrl_outw(ctrl_inw(PORT_HIZCRA) & ~0x01e0, PORT_HIZCRA);
498 #endif
499 #ifdef CONFIG_SH_MIGOR_QVGA
500 	/* LCDC - QVGA - Enable SYS Interface signals */
501 	ctrl_outw(ctrl_inw(PORT_PACR) & ~0x0003, PORT_PACR);
502 	ctrl_outw((ctrl_inw(PORT_PHCR) & ~0xcfff) | 0x0010, PORT_PHCR);
503 	ctrl_outw(0x0000, PORT_PLCR);
504 	ctrl_outw(0x0000, PORT_PMCR);
505 	ctrl_outw(ctrl_inw(PORT_PRCR) & ~0x030f, PORT_PRCR);
506 	ctrl_outw((ctrl_inw(PORT_PSELD) & ~0x0001) | 0x0420, PORT_PSELD);
507 	ctrl_outw(ctrl_inw(PORT_MSELCRB) | 0x0100, PORT_MSELCRB);
508 	ctrl_outw(ctrl_inw(PORT_HIZCRA) & ~0x01e0, PORT_HIZCRA);
509 #endif
510 
511 	/* CEU */
512 	ctrl_outw((ctrl_inw(PORT_PTCR) & ~0x03c3) | 0x0051, PORT_PTCR);
513 	ctrl_outw(ctrl_inw(PORT_PUCR) & ~0x03ff, PORT_PUCR);
514 	ctrl_outw(ctrl_inw(PORT_PVCR) & ~0x03ff, PORT_PVCR);
515 	ctrl_outw(ctrl_inw(PORT_PWCR) & ~0x3c00, PORT_PWCR);
516 	ctrl_outw(ctrl_inw(PORT_PSELC) | 0x0001, PORT_PSELC);
517 	ctrl_outw(ctrl_inw(PORT_PSELD) & ~0x2000, PORT_PSELD);
518 	ctrl_outw(ctrl_inw(PORT_PSELE) | 0x000f, PORT_PSELE);
519 	ctrl_outw(ctrl_inw(PORT_MSELCRB) | 0x2200, PORT_MSELCRB);
520 	ctrl_outw(ctrl_inw(PORT_HIZCRA) & ~0x0a00, PORT_HIZCRA);
521 	ctrl_outw(ctrl_inw(PORT_HIZCRB) & ~0x0003, PORT_HIZCRB);
522 }
523 
524 static struct sh_machine_vector mv_migor __initmv = {
525 	.mv_name		= "Migo-R",
526 	.mv_setup		= migor_setup,
527 };
528