1 /*
2  * arch/sh/boards/superh/microdev/setup.c
3  *
4  * Copyright (C) 2003 Sean McGoogan (Sean.McGoogan@superh.com)
5  * Copyright (C) 2003, 2004 SuperH, Inc.
6  * Copyright (C) 2004, 2005 Paul Mundt
7  *
8  * SuperH SH4-202 MicroDev board support.
9  *
10  * May be copied or modified under the terms of the GNU General Public
11  * License.  See linux/COPYING for more information.
12  */
13 #include <linux/init.h>
14 #include <linux/platform_device.h>
15 #include <linux/ioport.h>
16 #include <video/s1d13xxxfb.h>
17 #include <mach/microdev.h>
18 #include <asm/io.h>
19 #include <asm/machvec.h>
20 
21 	/*
22 	 * Setup for the SMSC FDC37C93xAPM
23 	 */
24 #define SMSC_CONFIG_PORT_ADDR	 (0x3F0)
25 #define SMSC_INDEX_PORT_ADDR	 SMSC_CONFIG_PORT_ADDR
26 #define SMSC_DATA_PORT_ADDR	 (SMSC_INDEX_PORT_ADDR + 1)
27 
28 #define SMSC_ENTER_CONFIG_KEY	 0x55
29 #define SMSC_EXIT_CONFIG_KEY	 0xaa
30 
31 #define SMCS_LOGICAL_DEV_INDEX 	 0x07	/* Logical Device Number */
32 #define SMSC_DEVICE_ID_INDEX	 0x20	/* Device ID */
33 #define SMSC_DEVICE_REV_INDEX	 0x21	/* Device Revision */
34 #define SMSC_ACTIVATE_INDEX	 0x30	/* Activate */
35 #define SMSC_PRIMARY_BASE_INDEX	 0x60	/* Primary Base Address */
36 #define SMSC_SECONDARY_BASE_INDEX 0x62	/* Secondary Base Address */
37 #define SMSC_PRIMARY_INT_INDEX	 0x70	/* Primary Interrupt Select */
38 #define SMSC_SECONDARY_INT_INDEX 0x72	/* Secondary Interrupt Select */
39 #define SMSC_HDCS0_INDEX	 0xf0	/* HDCS0 Address Decoder */
40 #define SMSC_HDCS1_INDEX	 0xf1	/* HDCS1 Address Decoder */
41 
42 #define SMSC_IDE1_DEVICE	1	/* IDE #1 logical device */
43 #define SMSC_IDE2_DEVICE	2	/* IDE #2 logical device */
44 #define SMSC_PARALLEL_DEVICE	3	/* Parallel Port logical device */
45 #define SMSC_SERIAL1_DEVICE	4	/* Serial #1 logical device */
46 #define SMSC_SERIAL2_DEVICE	5	/* Serial #2 logical device */
47 #define SMSC_KEYBOARD_DEVICE	7	/* Keyboard logical device */
48 #define SMSC_CONFIG_REGISTERS	8	/* Configuration Registers (Aux I/O) */
49 
50 #define SMSC_READ_INDEXED(index) ({ \
51 	outb((index), SMSC_INDEX_PORT_ADDR); \
52 	inb(SMSC_DATA_PORT_ADDR); })
53 #define SMSC_WRITE_INDEXED(val, index) ({ \
54 	outb((index), SMSC_INDEX_PORT_ADDR); \
55 	outb((val),   SMSC_DATA_PORT_ADDR); })
56 
57 #define	IDE1_PRIMARY_BASE	0x01f0	/* Task File Registe base for IDE #1 */
58 #define	IDE1_SECONDARY_BASE	0x03f6	/* Miscellaneous AT registers for IDE #1 */
59 #define	IDE2_PRIMARY_BASE	0x0170	/* Task File Registe base for IDE #2 */
60 #define	IDE2_SECONDARY_BASE	0x0376	/* Miscellaneous AT registers for IDE #2 */
61 
62 #define SERIAL1_PRIMARY_BASE	0x03f8
63 #define SERIAL2_PRIMARY_BASE	0x02f8
64 
65 #define	MSB(x)		( (x) >> 8 )
66 #define	LSB(x)		( (x) & 0xff )
67 
68 	/* General-Purpose base address on CPU-board FPGA */
69 #define	MICRODEV_FPGA_GP_BASE		0xa6100000ul
70 
71 	/* assume a Keyboard Controller is present */
72 int microdev_kbd_controller_present = 1;
73 
74 static struct resource smc91x_resources[] = {
75 	[0] = {
76 		.start		= 0x300,
77 		.end		= 0x300 + 0x0001000 - 1,
78 		.flags		= IORESOURCE_MEM,
79 	},
80 	[1] = {
81 		.start		= MICRODEV_LINUX_IRQ_ETHERNET,
82 		.end		= MICRODEV_LINUX_IRQ_ETHERNET,
83 		.flags		= IORESOURCE_IRQ,
84 	},
85 };
86 
87 static struct platform_device smc91x_device = {
88 	.name		= "smc91x",
89 	.id		= -1,
90 	.num_resources	= ARRAY_SIZE(smc91x_resources),
91 	.resource	= smc91x_resources,
92 };
93 
94 #ifdef CONFIG_FB_S1D13XXX
95 static struct s1d13xxxfb_regval s1d13806_initregs[] = {
96 	{ S1DREG_MISC,			0x00 },
97 	{ S1DREG_COM_DISP_MODE,		0x00 },
98 	{ S1DREG_GPIO_CNF0,		0x00 },
99 	{ S1DREG_GPIO_CNF1,		0x00 },
100 	{ S1DREG_GPIO_CTL0,		0x00 },
101 	{ S1DREG_GPIO_CTL1,		0x00 },
102 	{ S1DREG_CLK_CNF,		0x02 },
103 	{ S1DREG_LCD_CLK_CNF,		0x01 },
104 	{ S1DREG_CRT_CLK_CNF,		0x03 },
105 	{ S1DREG_MPLUG_CLK_CNF,		0x03 },
106 	{ S1DREG_CPU2MEM_WST_SEL,	0x02 },
107 	{ S1DREG_SDRAM_REF_RATE,	0x03 },
108 	{ S1DREG_SDRAM_TC0,		0x00 },
109 	{ S1DREG_SDRAM_TC1,		0x01 },
110 	{ S1DREG_MEM_CNF,		0x80 },
111 	{ S1DREG_PANEL_TYPE,		0x25 },
112 	{ S1DREG_MOD_RATE,		0x00 },
113 	{ S1DREG_LCD_DISP_HWIDTH,	0x63 },
114 	{ S1DREG_LCD_NDISP_HPER,	0x1e },
115 	{ S1DREG_TFT_FPLINE_START,	0x06 },
116 	{ S1DREG_TFT_FPLINE_PWIDTH,	0x03 },
117 	{ S1DREG_LCD_DISP_VHEIGHT0,	0x57 },
118 	{ S1DREG_LCD_DISP_VHEIGHT1,	0x02 },
119 	{ S1DREG_LCD_NDISP_VPER,	0x00 },
120 	{ S1DREG_TFT_FPFRAME_START,	0x0a },
121 	{ S1DREG_TFT_FPFRAME_PWIDTH,	0x81 },
122 	{ S1DREG_LCD_DISP_MODE,		0x03 },
123 	{ S1DREG_LCD_MISC,		0x00 },
124 	{ S1DREG_LCD_DISP_START0,	0x00 },
125 	{ S1DREG_LCD_DISP_START1,	0x00 },
126 	{ S1DREG_LCD_DISP_START2,	0x00 },
127 	{ S1DREG_LCD_MEM_OFF0,		0x90 },
128 	{ S1DREG_LCD_MEM_OFF1,		0x01 },
129 	{ S1DREG_LCD_PIX_PAN,		0x00 },
130 	{ S1DREG_LCD_DISP_FIFO_HTC,	0x00 },
131 	{ S1DREG_LCD_DISP_FIFO_LTC,	0x00 },
132 	{ S1DREG_CRT_DISP_HWIDTH,	0x63 },
133 	{ S1DREG_CRT_NDISP_HPER,	0x1f },
134 	{ S1DREG_CRT_HRTC_START,	0x04 },
135 	{ S1DREG_CRT_HRTC_PWIDTH,	0x8f },
136 	{ S1DREG_CRT_DISP_VHEIGHT0,	0x57 },
137 	{ S1DREG_CRT_DISP_VHEIGHT1,	0x02 },
138 	{ S1DREG_CRT_NDISP_VPER,	0x1b },
139 	{ S1DREG_CRT_VRTC_START,	0x00 },
140 	{ S1DREG_CRT_VRTC_PWIDTH,	0x83 },
141 	{ S1DREG_TV_OUT_CTL,		0x10 },
142 	{ S1DREG_CRT_DISP_MODE,		0x05 },
143 	{ S1DREG_CRT_DISP_START0,	0x00 },
144 	{ S1DREG_CRT_DISP_START1,	0x00 },
145 	{ S1DREG_CRT_DISP_START2,	0x00 },
146 	{ S1DREG_CRT_MEM_OFF0,		0x20 },
147 	{ S1DREG_CRT_MEM_OFF1,		0x03 },
148 	{ S1DREG_CRT_PIX_PAN,		0x00 },
149 	{ S1DREG_CRT_DISP_FIFO_HTC,	0x00 },
150 	{ S1DREG_CRT_DISP_FIFO_LTC,	0x00 },
151 	{ S1DREG_LCD_CUR_CTL,		0x00 },
152 	{ S1DREG_LCD_CUR_START,		0x01 },
153 	{ S1DREG_LCD_CUR_XPOS0,		0x00 },
154 	{ S1DREG_LCD_CUR_XPOS1,		0x00 },
155 	{ S1DREG_LCD_CUR_YPOS0,		0x00 },
156 	{ S1DREG_LCD_CUR_YPOS1,		0x00 },
157 	{ S1DREG_LCD_CUR_BCTL0,		0x00 },
158 	{ S1DREG_LCD_CUR_GCTL0,		0x00 },
159 	{ S1DREG_LCD_CUR_RCTL0,		0x00 },
160 	{ S1DREG_LCD_CUR_BCTL1,		0x1f },
161 	{ S1DREG_LCD_CUR_GCTL1,		0x3f },
162 	{ S1DREG_LCD_CUR_RCTL1,		0x1f },
163 	{ S1DREG_LCD_CUR_FIFO_HTC,	0x00 },
164 	{ S1DREG_CRT_CUR_CTL,		0x00 },
165 	{ S1DREG_CRT_CUR_START,		0x01 },
166 	{ S1DREG_CRT_CUR_XPOS0,		0x00 },
167 	{ S1DREG_CRT_CUR_XPOS1,		0x00 },
168 	{ S1DREG_CRT_CUR_YPOS0,		0x00 },
169 	{ S1DREG_CRT_CUR_YPOS1,		0x00 },
170 	{ S1DREG_CRT_CUR_BCTL0,		0x00 },
171 	{ S1DREG_CRT_CUR_GCTL0,		0x00 },
172 	{ S1DREG_CRT_CUR_RCTL0,		0x00 },
173 	{ S1DREG_CRT_CUR_BCTL1,		0x1f },
174 	{ S1DREG_CRT_CUR_GCTL1,		0x3f },
175 	{ S1DREG_CRT_CUR_RCTL1,		0x1f },
176 	{ S1DREG_CRT_CUR_FIFO_HTC,	0x00 },
177 	{ S1DREG_BBLT_CTL0,		0x00 },
178 	{ S1DREG_BBLT_CTL1,		0x00 },
179 	{ S1DREG_BBLT_CC_EXP,		0x00 },
180 	{ S1DREG_BBLT_OP,		0x00 },
181 	{ S1DREG_BBLT_SRC_START0,	0x00 },
182 	{ S1DREG_BBLT_SRC_START1,	0x00 },
183 	{ S1DREG_BBLT_SRC_START2,	0x00 },
184 	{ S1DREG_BBLT_DST_START0,	0x00 },
185 	{ S1DREG_BBLT_DST_START1,	0x00 },
186 	{ S1DREG_BBLT_DST_START2,	0x00 },
187 	{ S1DREG_BBLT_MEM_OFF0,		0x00 },
188 	{ S1DREG_BBLT_MEM_OFF1,		0x00 },
189 	{ S1DREG_BBLT_WIDTH0,		0x00 },
190 	{ S1DREG_BBLT_WIDTH1,		0x00 },
191 	{ S1DREG_BBLT_HEIGHT0,		0x00 },
192 	{ S1DREG_BBLT_HEIGHT1,		0x00 },
193 	{ S1DREG_BBLT_BGC0,		0x00 },
194 	{ S1DREG_BBLT_BGC1,		0x00 },
195 	{ S1DREG_BBLT_FGC0,		0x00 },
196 	{ S1DREG_BBLT_FGC1,		0x00 },
197 	{ S1DREG_LKUP_MODE,		0x00 },
198 	{ S1DREG_LKUP_ADDR,		0x00 },
199 	{ S1DREG_PS_CNF,		0x10 },
200 	{ S1DREG_PS_STATUS,		0x00 },
201 	{ S1DREG_CPU2MEM_WDOGT,		0x00 },
202 	{ S1DREG_COM_DISP_MODE,		0x02 },
203 };
204 
205 static struct s1d13xxxfb_pdata s1d13806_platform_data = {
206 	.initregs	= s1d13806_initregs,
207 	.initregssize	= ARRAY_SIZE(s1d13806_initregs),
208 };
209 
210 static struct resource s1d13806_resources[] = {
211 	[0] = {
212 		.start		= 0x07200000,
213 		.end		= 0x07200000 + 0x00200000 - 1,
214 		.flags		= IORESOURCE_MEM,
215 	},
216 	[1] = {
217 		.start		= 0x07000000,
218 		.end		= 0x07000000 + 0x00200000 - 1,
219 		.flags		= IORESOURCE_MEM,
220 	},
221 };
222 
223 static struct platform_device s1d13806_device = {
224 	.name		= "s1d13806fb",
225 	.id		= -1,
226 	.num_resources	= ARRAY_SIZE(s1d13806_resources),
227 	.resource	= s1d13806_resources,
228 
229 	.dev = {
230 		.platform_data	= &s1d13806_platform_data,
231 	},
232 };
233 #endif
234 
235 static struct platform_device *microdev_devices[] __initdata = {
236 	&smc91x_device,
237 #ifdef CONFIG_FB_S1D13XXX
238 	&s1d13806_device,
239 #endif
240 };
241 
242 static int __init microdev_devices_setup(void)
243 {
244 	return platform_add_devices(microdev_devices, ARRAY_SIZE(microdev_devices));
245 }
246 
247 /*
248  * Setup for the SMSC FDC37C93xAPM
249  */
250 static int __init smsc_superio_setup(void)
251 {
252 
253 	unsigned char devid, devrev;
254 
255 		/* Initially the chip is in run state */
256 		/* Put it into configuration state */
257 	outb(SMSC_ENTER_CONFIG_KEY, SMSC_CONFIG_PORT_ADDR);
258 
259 		/* Read device ID info */
260 	devid  = SMSC_READ_INDEXED(SMSC_DEVICE_ID_INDEX);
261 	devrev = SMSC_READ_INDEXED(SMSC_DEVICE_REV_INDEX);
262 	if ( (devid==0x30) && (devrev==0x01) )
263 	{
264   		printk("SMSC FDC37C93xAPM SuperIO device detected\n");
265 	}
266 	else
267 	{		/* not the device identity we expected */
268 		printk("Not detected a SMSC FDC37C93xAPM SuperIO device (devid=0x%02x, rev=0x%02x)\n",
269 			devid, devrev);
270 			/* inform the keyboard driver that we have no keyboard controller */
271 		microdev_kbd_controller_present = 0;
272 			/* little point in doing anything else in this functon */
273 		return 0;
274 	}
275 
276 		/* Select the keyboard device */
277 	SMSC_WRITE_INDEXED(SMSC_KEYBOARD_DEVICE, SMCS_LOGICAL_DEV_INDEX);
278 		/* enable it */
279 	SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX);
280 		/* enable the interrupts */
281 	SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_KEYBOARD, SMSC_PRIMARY_INT_INDEX);
282 	SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_MOUSE, SMSC_SECONDARY_INT_INDEX);
283 
284 		/* Select the Serial #1 device */
285 	SMSC_WRITE_INDEXED(SMSC_SERIAL1_DEVICE, SMCS_LOGICAL_DEV_INDEX);
286 		/* enable it */
287 	SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX);
288 		/* program with port addresses */
289 	SMSC_WRITE_INDEXED(MSB(SERIAL1_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+0);
290 	SMSC_WRITE_INDEXED(LSB(SERIAL1_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+1);
291 	SMSC_WRITE_INDEXED(0x00, SMSC_HDCS0_INDEX);
292 		/* enable the interrupts */
293 	SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_SERIAL1, SMSC_PRIMARY_INT_INDEX);
294 
295 		/* Select the Serial #2 device */
296 	SMSC_WRITE_INDEXED(SMSC_SERIAL2_DEVICE, SMCS_LOGICAL_DEV_INDEX);
297 		/* enable it */
298 	SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX);
299 		/* program with port addresses */
300 	SMSC_WRITE_INDEXED(MSB(SERIAL2_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+0);
301 	SMSC_WRITE_INDEXED(LSB(SERIAL2_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+1);
302 	SMSC_WRITE_INDEXED(0x00, SMSC_HDCS0_INDEX);
303 		/* enable the interrupts */
304 	SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_SERIAL2, SMSC_PRIMARY_INT_INDEX);
305 
306 		/* Select the IDE#1 device */
307 	SMSC_WRITE_INDEXED(SMSC_IDE1_DEVICE, SMCS_LOGICAL_DEV_INDEX);
308 		/* enable it */
309 	SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX);
310 		/* program with port addresses */
311 	SMSC_WRITE_INDEXED(MSB(IDE1_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+0);
312 	SMSC_WRITE_INDEXED(LSB(IDE1_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+1);
313 	SMSC_WRITE_INDEXED(MSB(IDE1_SECONDARY_BASE), SMSC_SECONDARY_BASE_INDEX+0);
314 	SMSC_WRITE_INDEXED(LSB(IDE1_SECONDARY_BASE), SMSC_SECONDARY_BASE_INDEX+1);
315 	SMSC_WRITE_INDEXED(0x0c, SMSC_HDCS0_INDEX);
316 	SMSC_WRITE_INDEXED(0x00, SMSC_HDCS1_INDEX);
317 		/* select the interrupt */
318 	SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_IDE1, SMSC_PRIMARY_INT_INDEX);
319 
320 		/* Select the IDE#2 device */
321 	SMSC_WRITE_INDEXED(SMSC_IDE2_DEVICE, SMCS_LOGICAL_DEV_INDEX);
322 		/* enable it */
323 	SMSC_WRITE_INDEXED(1, SMSC_ACTIVATE_INDEX);
324 		/* program with port addresses */
325 	SMSC_WRITE_INDEXED(MSB(IDE2_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+0);
326 	SMSC_WRITE_INDEXED(LSB(IDE2_PRIMARY_BASE), SMSC_PRIMARY_BASE_INDEX+1);
327 	SMSC_WRITE_INDEXED(MSB(IDE2_SECONDARY_BASE), SMSC_SECONDARY_BASE_INDEX+0);
328 	SMSC_WRITE_INDEXED(LSB(IDE2_SECONDARY_BASE), SMSC_SECONDARY_BASE_INDEX+1);
329 		/* select the interrupt */
330 	SMSC_WRITE_INDEXED(MICRODEV_FPGA_IRQ_IDE2, SMSC_PRIMARY_INT_INDEX);
331 
332 		/* Select the configuration registers */
333 	SMSC_WRITE_INDEXED(SMSC_CONFIG_REGISTERS, SMCS_LOGICAL_DEV_INDEX);
334 		/* enable the appropriate GPIO pins for IDE functionality:
335 		 * bit[0]   In/Out		1==input;  0==output
336 		 * bit[1]   Polarity		1==invert; 0==no invert
337 		 * bit[2]   Int Enb #1		1==Enable Combined IRQ #1; 0==disable
338 		 * bit[3:4] Function Select	00==original; 01==Alternate Function #1
339 		 */
340 	SMSC_WRITE_INDEXED(0x00, 0xc2);	/* GP42 = nIDE1_OE */
341 	SMSC_WRITE_INDEXED(0x01, 0xc5);	/* GP45 = IDE1_IRQ */
342 	SMSC_WRITE_INDEXED(0x00, 0xc6);	/* GP46 = nIOROP */
343 	SMSC_WRITE_INDEXED(0x00, 0xc7);	/* GP47 = nIOWOP */
344 	SMSC_WRITE_INDEXED(0x08, 0xe8);	/* GP20 = nIDE2_OE */
345 
346 		/* Exit the configuration state */
347 	outb(SMSC_EXIT_CONFIG_KEY, SMSC_CONFIG_PORT_ADDR);
348 
349 	return 0;
350 }
351 
352 static void __init microdev_setup(char **cmdline_p)
353 {
354 	int * const fpgaRevisionRegister = (int*)(MICRODEV_FPGA_GP_BASE + 0x8ul);
355 	const int fpgaRevision = *fpgaRevisionRegister;
356 	int * const CacheControlRegister = (int*)CCR;
357 
358 	device_initcall(microdev_devices_setup);
359 	device_initcall(smsc_superio_setup);
360 
361 	printk("SuperH %s board (FPGA rev: 0x%0x, CCR: 0x%0x)\n",
362 		get_system_type(), fpgaRevision, *CacheControlRegister);
363 }
364 
365 /*
366  * The Machine Vector
367  */
368 static struct sh_machine_vector mv_sh4202_microdev __initmv = {
369 	.mv_name		= "SH4-202 MicroDev",
370 	.mv_setup		= microdev_setup,
371 	.mv_nr_irqs		= 72,		/* QQQ need to check this - use the MACRO */
372 
373 	.mv_inb			= microdev_inb,
374 	.mv_inw			= microdev_inw,
375 	.mv_inl			= microdev_inl,
376 	.mv_outb		= microdev_outb,
377 	.mv_outw		= microdev_outw,
378 	.mv_outl		= microdev_outl,
379 
380 	.mv_inb_p		= microdev_inb_p,
381 	.mv_inw_p		= microdev_inw_p,
382 	.mv_inl_p		= microdev_inl_p,
383 	.mv_outb_p		= microdev_outb_p,
384 	.mv_outw_p		= microdev_outw_p,
385 	.mv_outl_p		= microdev_outl_p,
386 
387 	.mv_insb		= microdev_insb,
388 	.mv_insw		= microdev_insw,
389 	.mv_insl		= microdev_insl,
390 	.mv_outsb		= microdev_outsb,
391 	.mv_outsw		= microdev_outsw,
392 	.mv_outsl		= microdev_outsl,
393 
394 	.mv_init_irq		= init_microdev_irq,
395 };
396