xref: /openbmc/linux/arch/alpha/kernel/smc37c669.c (revision 4800cd83)
1 /*
2  * SMC 37C669 initialization code
3  */
4 #include <linux/kernel.h>
5 
6 #include <linux/mm.h>
7 #include <linux/init.h>
8 #include <linux/delay.h>
9 #include <linux/spinlock.h>
10 
11 #include <asm/hwrpb.h>
12 #include <asm/io.h>
13 #include <asm/segment.h>
14 
15 #if 0
16 # define DBG_DEVS(args)         printk args
17 #else
18 # define DBG_DEVS(args)
19 #endif
20 
21 #define KB              1024
22 #define MB              (1024*KB)
23 #define GB              (1024*MB)
24 
25 #define SMC_DEBUG   0
26 
27 /* File:	smcc669_def.h
28  *
29  * Copyright (C) 1997 by
30  * Digital Equipment Corporation, Maynard, Massachusetts.
31  * All rights reserved.
32  *
33  * This software is furnished under a license and may be used and copied
34  * only  in  accordance  of  the  terms  of  such  license  and with the
35  * inclusion of the above copyright notice. This software or  any  other
36  * copies thereof may not be provided or otherwise made available to any
37  * other person.  No title to and  ownership of the  software is  hereby
38  * transferred.
39  *
40  * The information in this software is  subject to change without notice
41  * and  should  not  be  construed  as a commitment by Digital Equipment
42  * Corporation.
43  *
44  * Digital assumes no responsibility for the use  or  reliability of its
45  * software on equipment which is not supplied by Digital.
46  *
47  *
48  * Abstract:
49  *
50  *	This file contains header definitions for the SMC37c669
51  *	Super I/O controller.
52  *
53  * Author:
54  *
55  *	Eric Rasmussen
56  *
57  * Modification History:
58  *
59  *	er	28-Jan-1997	Initial Entry
60  */
61 
62 #ifndef __SMC37c669_H
63 #define __SMC37c669_H
64 
65 /*
66 ** Macros for handling device IRQs
67 **
68 ** The mask acts as a flag used in mapping actual ISA IRQs (0 - 15)
69 ** to device IRQs (A - H).
70 */
71 #define SMC37c669_DEVICE_IRQ_MASK	0x80000000
72 #define SMC37c669_DEVICE_IRQ( __i )	\
73 	((SMC37c669_DEVICE_IRQ_MASK) | (__i))
74 #define SMC37c669_IS_DEVICE_IRQ(__i)	\
75 	(((__i) & (SMC37c669_DEVICE_IRQ_MASK)) == (SMC37c669_DEVICE_IRQ_MASK))
76 #define SMC37c669_RAW_DEVICE_IRQ(__i)	\
77 	((__i) & ~(SMC37c669_DEVICE_IRQ_MASK))
78 
79 /*
80 ** Macros for handling device DRQs
81 **
82 ** The mask acts as a flag used in mapping actual ISA DMA
83 ** channels to device DMA channels (A - C).
84 */
85 #define SMC37c669_DEVICE_DRQ_MASK	0x80000000
86 #define SMC37c669_DEVICE_DRQ(__d)	\
87 	((SMC37c669_DEVICE_DRQ_MASK) | (__d))
88 #define SMC37c669_IS_DEVICE_DRQ(__d)	\
89 	(((__d) & (SMC37c669_DEVICE_DRQ_MASK)) == (SMC37c669_DEVICE_DRQ_MASK))
90 #define SMC37c669_RAW_DEVICE_DRQ(__d)	\
91 	((__d) & ~(SMC37c669_DEVICE_DRQ_MASK))
92 
93 #define SMC37c669_DEVICE_ID	0x3
94 
95 /*
96 ** SMC37c669 Device Function Definitions
97 */
98 #define SERIAL_0	0
99 #define SERIAL_1	1
100 #define PARALLEL_0	2
101 #define FLOPPY_0	3
102 #define IDE_0		4
103 #define NUM_FUNCS	5
104 
105 /*
106 ** Default Device Function Mappings
107 */
108 #define COM1_BASE	0x3F8
109 #define COM1_IRQ	4
110 #define COM2_BASE	0x2F8
111 #define COM2_IRQ	3
112 #define PARP_BASE	0x3BC
113 #define PARP_IRQ	7
114 #define PARP_DRQ	3
115 #define FDC_BASE	0x3F0
116 #define FDC_IRQ		6
117 #define FDC_DRQ		2
118 
119 /*
120 ** Configuration On/Off Key Definitions
121 */
122 #define SMC37c669_CONFIG_ON_KEY		0x55
123 #define SMC37c669_CONFIG_OFF_KEY	0xAA
124 
125 /*
126 ** SMC 37c669 Device IRQs
127 */
128 #define SMC37c669_DEVICE_IRQ_A	    ( SMC37c669_DEVICE_IRQ( 0x01 ) )
129 #define SMC37c669_DEVICE_IRQ_B	    ( SMC37c669_DEVICE_IRQ( 0x02 ) )
130 #define SMC37c669_DEVICE_IRQ_C	    ( SMC37c669_DEVICE_IRQ( 0x03 ) )
131 #define SMC37c669_DEVICE_IRQ_D	    ( SMC37c669_DEVICE_IRQ( 0x04 ) )
132 #define SMC37c669_DEVICE_IRQ_E	    ( SMC37c669_DEVICE_IRQ( 0x05 ) )
133 #define SMC37c669_DEVICE_IRQ_F	    ( SMC37c669_DEVICE_IRQ( 0x06 ) )
134 /*      SMC37c669_DEVICE_IRQ_G	    *** RESERVED ***/
135 #define SMC37c669_DEVICE_IRQ_H	    ( SMC37c669_DEVICE_IRQ( 0x08 ) )
136 
137 /*
138 ** SMC 37c669 Device DMA Channel Definitions
139 */
140 #define SMC37c669_DEVICE_DRQ_A		    ( SMC37c669_DEVICE_DRQ( 0x01 ) )
141 #define SMC37c669_DEVICE_DRQ_B		    ( SMC37c669_DEVICE_DRQ( 0x02 ) )
142 #define SMC37c669_DEVICE_DRQ_C		    ( SMC37c669_DEVICE_DRQ( 0x03 ) )
143 
144 /*
145 ** Configuration Register Index Definitions
146 */
147 #define SMC37c669_CR00_INDEX	    0x00
148 #define SMC37c669_CR01_INDEX	    0x01
149 #define SMC37c669_CR02_INDEX	    0x02
150 #define SMC37c669_CR03_INDEX	    0x03
151 #define SMC37c669_CR04_INDEX	    0x04
152 #define SMC37c669_CR05_INDEX	    0x05
153 #define SMC37c669_CR06_INDEX	    0x06
154 #define SMC37c669_CR07_INDEX	    0x07
155 #define SMC37c669_CR08_INDEX	    0x08
156 #define SMC37c669_CR09_INDEX	    0x09
157 #define SMC37c669_CR0A_INDEX	    0x0A
158 #define SMC37c669_CR0B_INDEX	    0x0B
159 #define SMC37c669_CR0C_INDEX	    0x0C
160 #define SMC37c669_CR0D_INDEX	    0x0D
161 #define SMC37c669_CR0E_INDEX	    0x0E
162 #define SMC37c669_CR0F_INDEX	    0x0F
163 #define SMC37c669_CR10_INDEX	    0x10
164 #define SMC37c669_CR11_INDEX	    0x11
165 #define SMC37c669_CR12_INDEX	    0x12
166 #define SMC37c669_CR13_INDEX	    0x13
167 #define SMC37c669_CR14_INDEX	    0x14
168 #define SMC37c669_CR15_INDEX	    0x15
169 #define SMC37c669_CR16_INDEX	    0x16
170 #define SMC37c669_CR17_INDEX	    0x17
171 #define SMC37c669_CR18_INDEX	    0x18
172 #define SMC37c669_CR19_INDEX	    0x19
173 #define SMC37c669_CR1A_INDEX	    0x1A
174 #define SMC37c669_CR1B_INDEX	    0x1B
175 #define SMC37c669_CR1C_INDEX	    0x1C
176 #define SMC37c669_CR1D_INDEX	    0x1D
177 #define SMC37c669_CR1E_INDEX	    0x1E
178 #define SMC37c669_CR1F_INDEX	    0x1F
179 #define SMC37c669_CR20_INDEX	    0x20
180 #define SMC37c669_CR21_INDEX	    0x21
181 #define SMC37c669_CR22_INDEX	    0x22
182 #define SMC37c669_CR23_INDEX	    0x23
183 #define SMC37c669_CR24_INDEX	    0x24
184 #define SMC37c669_CR25_INDEX	    0x25
185 #define SMC37c669_CR26_INDEX	    0x26
186 #define SMC37c669_CR27_INDEX	    0x27
187 #define SMC37c669_CR28_INDEX	    0x28
188 #define SMC37c669_CR29_INDEX	    0x29
189 
190 /*
191 ** Configuration Register Alias Definitions
192 */
193 #define SMC37c669_DEVICE_ID_INDEX		    SMC37c669_CR0D_INDEX
194 #define SMC37c669_DEVICE_REVISION_INDEX		    SMC37c669_CR0E_INDEX
195 #define SMC37c669_FDC_BASE_ADDRESS_INDEX	    SMC37c669_CR20_INDEX
196 #define SMC37c669_IDE_BASE_ADDRESS_INDEX	    SMC37c669_CR21_INDEX
197 #define SMC37c669_IDE_ALTERNATE_ADDRESS_INDEX	    SMC37c669_CR22_INDEX
198 #define SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX	    SMC37c669_CR23_INDEX
199 #define SMC37c669_SERIAL0_BASE_ADDRESS_INDEX	    SMC37c669_CR24_INDEX
200 #define SMC37c669_SERIAL1_BASE_ADDRESS_INDEX	    SMC37c669_CR25_INDEX
201 #define SMC37c669_PARALLEL_FDC_DRQ_INDEX	    SMC37c669_CR26_INDEX
202 #define SMC37c669_PARALLEL_FDC_IRQ_INDEX	    SMC37c669_CR27_INDEX
203 #define SMC37c669_SERIAL_IRQ_INDEX		    SMC37c669_CR28_INDEX
204 
205 /*
206 ** Configuration Register Definitions
207 **
208 ** The INDEX (write only) and DATA (read/write) ports are effective
209 ** only when the chip is in the Configuration State.
210 */
211 typedef struct _SMC37c669_CONFIG_REGS {
212     unsigned char index_port;
213     unsigned char data_port;
214 } SMC37c669_CONFIG_REGS;
215 
216 /*
217 ** CR00 - default value 0x28
218 **
219 **  IDE_EN (CR00<1:0>):
220 **	0x - 30ua pull-ups on nIDEEN, nHDCS0, NHDCS1
221 **	11 - IRQ_H available as IRQ output,
222 **	     IRRX2, IRTX2 available as alternate IR pins
223 **	10 - nIDEEN, nHDCS0, nHDCS1 used to control IDE
224 **
225 **  VALID (CR00<7>):
226 **	A high level on this software controlled bit can
227 **	be used to indicate that a valid configuration
228 **	cycle has occurred.  The control software must
229 **	take care to set this bit at the appropriate times.
230 **	Set to zero after power up.  This bit has no
231 **	effect on any other hardware in the chip.
232 **
233 */
234 typedef union _SMC37c669_CR00 {
235     unsigned char as_uchar;
236     struct {
237     	unsigned ide_en : 2;	    /* See note above		*/
238 	unsigned reserved1 : 1;	    /* RAZ			*/
239 	unsigned fdc_pwr : 1;	    /* 1 = supply power to FDC  */
240 	unsigned reserved2 : 3;	    /* Read as 010b		*/
241 	unsigned valid : 1;	    /* See note above		*/
242     }	by_field;
243 } SMC37c669_CR00;
244 
245 /*
246 ** CR01 - default value 0x9C
247 */
248 typedef union _SMC37c669_CR01 {
249     unsigned char as_uchar;
250     struct {
251     	unsigned reserved1 : 2;	    /* RAZ			    */
252 	unsigned ppt_pwr : 1;	    /* 1 = supply power to PPT	    */
253 	unsigned ppt_mode : 1;	    /* 1 = Printer mode, 0 = EPP    */
254 	unsigned reserved2 : 1;	    /* Read as 1		    */
255 	unsigned reserved3 : 2;	    /* RAZ			    */
256 	unsigned lock_crx: 1;	    /* Lock CR00 - CR18		    */
257     }	by_field;
258 } SMC37c669_CR01;
259 
260 /*
261 ** CR02 - default value 0x88
262 */
263 typedef union _SMC37c669_CR02 {
264     unsigned char as_uchar;
265     struct {
266     	unsigned reserved1 : 3;	    /* RAZ			    */
267 	unsigned uart1_pwr : 1;	    /* 1 = supply power to UART1    */
268 	unsigned reserved2 : 3;	    /* RAZ			    */
269 	unsigned uart2_pwr : 1;	    /* 1 = supply power to UART2    */
270     }	by_field;
271 } SMC37c669_CR02;
272 
273 /*
274 ** CR03 - default value 0x78
275 **
276 **  CR03<7>	CR03<2>	    Pin 94
277 **  -------	-------	    ------
278 **     0	   X	    DRV2 (input)
279 **     1	   0	    ADRX
280 **     1	   1	    IRQ_B
281 **
282 **  CR03<6>	CR03<5>	    Op Mode
283 **  -------	-------	    -------
284 **     0	   0	    Model 30
285 **     0	   1	    PS/2
286 **     1	   0	    Reserved
287 **     1	   1	    AT Mode
288 */
289 typedef union _SMC37c669_CR03 {
290     unsigned char as_uchar;
291     struct {
292     	unsigned pwrgd_gamecs : 1;  /* 1 = PWRGD, 0 = GAMECS	    */
293 	unsigned fdc_mode2 : 1;	    /* 1 = Enhanced Mode 2	    */
294 	unsigned pin94_0 : 1;	    /* See note above		    */
295 	unsigned reserved1 : 1;	    /* RAZ			    */
296 	unsigned drvden : 1;	    /* 1 = high, 0 - output	    */
297 	unsigned op_mode : 2;	    /* See note above		    */
298 	unsigned pin94_1 : 1;	    /* See note above		    */
299     }	by_field;
300 } SMC37c669_CR03;
301 
302 /*
303 ** CR04 - default value 0x00
304 **
305 **  PP_EXT_MODE:
306 **	If CR01<PP_MODE> = 0 and PP_EXT_MODE =
307 **	    00 - Standard and Bidirectional
308 **	    01 - EPP mode and SPP
309 **	    10 - ECP mode
310 **		 In this mode, 2 drives can be supported
311 **		 directly, 3 or 4 drives must use external
312 **		 4 drive support.  SPP can be selected
313 **		 through the ECR register of ECP as mode 000.
314 **	    11 - ECP mode and EPP mode
315 **		 In this mode, 2 drives can be supported
316 **		 directly, 3 or 4 drives must use external
317 **		 4 drive support.  SPP can be selected
318 **		 through the ECR register of ECP as mode 000.
319 **		 In this mode, EPP can be selected through
320 **		 the ECR register of ECP as mode 100.
321 **
322 **  PP_FDC:
323 **	00 - Normal
324 **	01 - PPFD1
325 **	10 - PPFD2
326 **	11 - Reserved
327 **
328 **  MIDI1:
329 **	Serial Clock Select:
330 **	    A low level on this bit disables MIDI support,
331 **	    clock = divide by 13.  A high level on this
332 **	    bit enables MIDI support, clock = divide by 12.
333 **
334 **	MIDI operates at 31.25 Kbps which can be derived
335 **	from 125 KHz (24 MHz / 12 = 2 MHz, 2 MHz / 16 = 125 KHz)
336 **
337 **  ALT_IO:
338 **	0 - Use pins IRRX, IRTX
339 **	1 - Use pins IRRX2, IRTX2
340 **
341 **	If this bit is set, the IR receive and transmit
342 **	functions will not be available on pins 25 and 26
343 **	unless CR00<IDE_EN> = 11.
344 */
345 typedef union _SMC37c669_CR04 {
346     unsigned char as_uchar;
347     struct {
348     	unsigned ppt_ext_mode : 2;  /* See note above		    */
349 	unsigned ppt_fdc : 2;	    /* See note above		    */
350 	unsigned midi1 : 1;	    /* See note above		    */
351 	unsigned midi2 : 1;	    /* See note above		    */
352 	unsigned epp_type : 1;	    /* 0 = EPP 1.9, 1 = EPP 1.7	    */
353 	unsigned alt_io : 1;	    /* See note above		    */
354     }	by_field;
355 } SMC37c669_CR04;
356 
357 /*
358 ** CR05 - default value 0x00
359 **
360 **  DEN_SEL:
361 **	00 - Densel output normal
362 **	01 - Reserved
363 **	10 - Densel output 1
364 **	11 - Densel output 0
365 **
366 */
367 typedef union _SMC37c669_CR05 {
368     unsigned char as_uchar;
369     struct {
370     	unsigned reserved1 : 2;	    /* RAZ					*/
371 	unsigned fdc_dma_mode : 1;  /* 0 = burst, 1 = non-burst			*/
372 	unsigned den_sel : 2;	    /* See note above				*/
373 	unsigned swap_drv : 1;	    /* Swap the FDC motor selects		*/
374 	unsigned extx4 : 1;	    /* 0 = 2 drive, 1 = external 4 drive decode	*/
375 	unsigned reserved2 : 1;	    /* RAZ					*/
376     }	by_field;
377 } SMC37c669_CR05;
378 
379 /*
380 ** CR06 - default value 0xFF
381 */
382 typedef union _SMC37c669_CR06 {
383     unsigned char as_uchar;
384     struct {
385     	unsigned floppy_a : 2;	    /* Type of floppy drive A	    */
386 	unsigned floppy_b : 2;	    /* Type of floppy drive B	    */
387 	unsigned floppy_c : 2;	    /* Type of floppy drive C	    */
388 	unsigned floppy_d : 2;	    /* Type of floppy drive D	    */
389     }	by_field;
390 } SMC37c669_CR06;
391 
392 /*
393 ** CR07 - default value 0x00
394 **
395 **  Auto Power Management CR07<7:4>:
396 **	0 - Auto Powerdown disabled (default)
397 **	1 - Auto Powerdown enabled
398 **
399 **	This bit is reset to the default state by POR or
400 **	a hardware reset.
401 **
402 */
403 typedef union _SMC37c669_CR07 {
404     unsigned char as_uchar;
405     struct {
406     	unsigned floppy_boot : 2;   /* 0 = A:, 1 = B:		    */
407 	unsigned reserved1 : 2;	    /* RAZ			    */
408 	unsigned ppt_en : 1;	    /* See note above		    */
409 	unsigned uart1_en : 1;	    /* See note above		    */
410 	unsigned uart2_en : 1;	    /* See note above		    */
411 	unsigned fdc_en : 1;	    /* See note above		    */
412     }	by_field;
413 } SMC37c669_CR07;
414 
415 /*
416 ** CR08 - default value 0x00
417 */
418 typedef union _SMC37c669_CR08 {
419     unsigned char as_uchar;
420     struct {
421     	unsigned zero : 4;	    /* 0			    */
422 	unsigned addrx7_4 : 4;	    /* ADR<7:3> for ADRx decode	    */
423     }	by_field;
424 } SMC37c669_CR08;
425 
426 /*
427 ** CR09 - default value 0x00
428 **
429 **  ADRx_CONFIG:
430 **	00 - ADRx disabled
431 **	01 - 1 byte decode A<3:0> = 0000b
432 **	10 - 8 byte block decode A<3:0> = 0XXXb
433 **	11 - 16 byte block decode A<3:0> = XXXXb
434 **
435 */
436 typedef union _SMC37c669_CR09 {
437     unsigned char as_uchar;
438     struct {
439     	unsigned adra8 : 3;	    /* ADR<10:8> for ADRx decode    */
440 	unsigned reserved1 : 3;
441 	unsigned adrx_config : 2;   /* See note above		    */
442     }	by_field;
443 } SMC37c669_CR09;
444 
445 /*
446 ** CR0A - default value 0x00
447 */
448 typedef union _SMC37c669_CR0A {
449     unsigned char as_uchar;
450     struct {
451     	unsigned ecp_fifo_threshold : 4;
452 	unsigned reserved1 : 4;
453     }	by_field;
454 } SMC37c669_CR0A;
455 
456 /*
457 ** CR0B - default value 0x00
458 */
459 typedef union _SMC37c669_CR0B {
460     unsigned char as_uchar;
461     struct {
462     	unsigned fdd0_drtx : 2;	    /* FDD0 Data Rate Table	    */
463 	unsigned fdd1_drtx : 2;	    /* FDD1 Data Rate Table	    */
464 	unsigned fdd2_drtx : 2;	    /* FDD2 Data Rate Table	    */
465 	unsigned fdd3_drtx : 2;	    /* FDD3 Data Rate Table	    */
466     }	by_field;
467 } SMC37c669_CR0B;
468 
469 /*
470 ** CR0C - default value 0x00
471 **
472 **  UART2_MODE:
473 **	000 - Standard (default)
474 **	001 - IrDA (HPSIR)
475 **	010 - Amplitude Shift Keyed IR @500 KHz
476 **	011 - Reserved
477 **	1xx - Reserved
478 **
479 */
480 typedef union _SMC37c669_CR0C {
481     unsigned char as_uchar;
482     struct {
483     	unsigned uart2_rcv_polarity : 1;    /* 1 = invert RX		*/
484 	unsigned uart2_xmit_polarity : 1;   /* 1 = invert TX		*/
485 	unsigned uart2_duplex : 1;	    /* 1 = full, 0 = half	*/
486 	unsigned uart2_mode : 3;	    /* See note above		*/
487 	unsigned uart1_speed : 1;	    /* 1 = high speed enabled	*/
488 	unsigned uart2_speed : 1;	    /* 1 = high speed enabled	*/
489     }	by_field;
490 } SMC37c669_CR0C;
491 
492 /*
493 ** CR0D - default value 0x03
494 **
495 **  Device ID Register - read only
496 */
497 typedef union _SMC37c669_CR0D {
498     unsigned char as_uchar;
499     struct {
500     	unsigned device_id : 8;	    /* Returns 0x3 in this field    */
501     }	by_field;
502 } SMC37c669_CR0D;
503 
504 /*
505 ** CR0E - default value 0x02
506 **
507 **  Device Revision Register - read only
508 */
509 typedef union _SMC37c669_CR0E {
510     unsigned char as_uchar;
511     struct {
512     	unsigned device_rev : 8;    /* Returns 0x2 in this field    */
513     }	by_field;
514 } SMC37c669_CR0E;
515 
516 /*
517 ** CR0F - default value 0x00
518 */
519 typedef union _SMC37c669_CR0F {
520     unsigned char as_uchar;
521     struct {
522     	unsigned test0 : 1;	    /* Reserved - set to 0	    */
523 	unsigned test1 : 1;	    /* Reserved - set to 0	    */
524 	unsigned test2 : 1;	    /* Reserved - set to 0	    */
525 	unsigned test3 : 1;	    /* Reserved - set t0 0	    */
526 	unsigned test4 : 1;	    /* Reserved - set to 0	    */
527 	unsigned test5 : 1;	    /* Reserved - set t0 0	    */
528 	unsigned test6 : 1;	    /* Reserved - set t0 0	    */
529 	unsigned test7 : 1;	    /* Reserved - set to 0	    */
530     }	by_field;
531 } SMC37c669_CR0F;
532 
533 /*
534 ** CR10 - default value 0x00
535 */
536 typedef union _SMC37c669_CR10 {
537     unsigned char as_uchar;
538     struct {
539     	unsigned reserved1 : 3;	     /* RAZ			    */
540 	unsigned pll_gain : 1;	     /* 1 = 3V, 2 = 5V operation    */
541 	unsigned pll_stop : 1;	     /* 1 = stop PLLs		    */
542 	unsigned ace_stop : 1;	     /* 1 = stop UART clocks	    */
543 	unsigned pll_clock_ctrl : 1; /* 0 = 14.318 MHz, 1 = 24 MHz  */
544 	unsigned ir_test : 1;	     /* Enable IR test mode	    */
545     }	by_field;
546 } SMC37c669_CR10;
547 
548 /*
549 ** CR11 - default value 0x00
550 */
551 typedef union _SMC37c669_CR11 {
552     unsigned char as_uchar;
553     struct {
554     	unsigned ir_loopback : 1;   /* Internal IR loop back		    */
555 	unsigned test_10ms : 1;	    /* Test 10ms autopowerdown FDC timeout  */
556 	unsigned reserved1 : 6;	    /* RAZ				    */
557     }	by_field;
558 } SMC37c669_CR11;
559 
560 /*
561 ** CR12 - CR1D are reserved registers
562 */
563 
564 /*
565 ** CR1E - default value 0x80
566 **
567 **  GAMECS:
568 **	00 - GAMECS disabled
569 **	01 - 1 byte decode ADR<3:0> = 0001b
570 **	10 - 8 byte block decode ADR<3:0> = 0XXXb
571 **	11 - 16 byte block decode ADR<3:0> = XXXXb
572 **
573 */
574 typedef union _SMC37c66_CR1E {
575     unsigned char as_uchar;
576     struct {
577     	unsigned gamecs_config: 2;   /* See note above		    */
578 	unsigned gamecs_addr9_4 : 6; /* GAMECS Addr<9:4>	    */
579     }	by_field;
580 } SMC37c669_CR1E;
581 
582 /*
583 ** CR1F - default value 0x00
584 **
585 **  DT0 DT1 DRVDEN0 DRVDEN1 Drive Type
586 **  --- --- ------- ------- ----------
587 **   0   0  DENSEL  DRATE0  4/2/1 MB 3.5"
588 **                          2/1 MB 5.25"
589 **                          2/1.6/1 MB 3.5" (3-mode)
590 **   0   1  DRATE1  DRATE0
591 **   1   0  nDENSEL DRATE0  PS/2
592 **   1   1  DRATE0  DRATE1
593 **
594 **  Note: DENSEL, DRATE1, and DRATE0 map onto two output
595 **	  pins - DRVDEN0 and DRVDEN1.
596 **
597 */
598 typedef union _SMC37c669_CR1F {
599     unsigned char as_uchar;
600     struct {
601     	unsigned fdd0_drive_type : 2;	/* FDD0 drive type	    */
602 	unsigned fdd1_drive_type : 2;	/* FDD1 drive type	    */
603 	unsigned fdd2_drive_type : 2;	/* FDD2 drive type	    */
604 	unsigned fdd3_drive_type : 2;	/* FDD3 drive type	    */
605     }	by_field;
606 } SMC37c669_CR1F;
607 
608 /*
609 ** CR20 - default value 0x3C
610 **
611 **  FDC Base Address Register
612 **	- To disable this decode set Addr<9:8> = 0
613 **	- A<10> = 0, A<3:0> = 0XXXb to access.
614 **
615 */
616 typedef union _SMC37c669_CR20 {
617     unsigned char as_uchar;
618     struct {
619     	unsigned zero : 2;	    /* 0			    */
620 	unsigned addr9_4 : 6;	    /* FDC Addr<9:4>		    */
621     }	by_field;
622 } SMC37c669_CR20;
623 
624 /*
625 ** CR21 - default value 0x3C
626 **
627 **  IDE Base Address Register
628 **	- To disable this decode set Addr<9:8> = 0
629 **	- A<10> = 0, A<3:0> = 0XXXb to access.
630 **
631 */
632 typedef union _SMC37c669_CR21 {
633     unsigned char as_uchar;
634     struct {
635     	unsigned zero : 2;	    /* 0			    */
636 	unsigned addr9_4 : 6;	    /* IDE Addr<9:4>		    */
637     }	by_field;
638 } SMC37c669_CR21;
639 
640 /*
641 ** CR22 - default value 0x3D
642 **
643 **  IDE Alternate Status Base Address Register
644 **	- To disable this decode set Addr<9:8> = 0
645 **	- A<10> = 0, A<3:0> = 0110b to access.
646 **
647 */
648 typedef union _SMC37c669_CR22 {
649     unsigned char as_uchar;
650     struct {
651     	unsigned zero : 2;	    /* 0			    */
652 	unsigned addr9_4 : 6;	    /* IDE Alt Status Addr<9:4>	    */
653     }	by_field;
654 } SMC37c669_CR22;
655 
656 /*
657 ** CR23 - default value 0x00
658 **
659 **  Parallel Port Base Address Register
660 **	- To disable this decode set Addr<9:8> = 0
661 **	- A<10> = 0 to access.
662 **	- If EPP is enabled, A<2:0> = XXXb to access.
663 **	  If EPP is NOT enabled, A<1:0> = XXb to access
664 **
665 */
666 typedef union _SMC37c669_CR23 {
667     unsigned char as_uchar;
668     struct {
669 	unsigned addr9_2 : 8;	    /* Parallel Port Addr<9:2>	    */
670     }	by_field;
671 } SMC37c669_CR23;
672 
673 /*
674 ** CR24 - default value 0x00
675 **
676 **  UART1 Base Address Register
677 **	- To disable this decode set Addr<9:8> = 0
678 **	- A<10> = 0, A<2:0> = XXXb to access.
679 **
680 */
681 typedef union _SMC37c669_CR24 {
682     unsigned char as_uchar;
683     struct {
684     	unsigned zero : 1;	    /* 0			    */
685 	unsigned addr9_3 : 7;	    /* UART1 Addr<9:3>		    */
686     }	by_field;
687 } SMC37c669_CR24;
688 
689 /*
690 ** CR25 - default value 0x00
691 **
692 **  UART2 Base Address Register
693 **	- To disable this decode set Addr<9:8> = 0
694 **	- A<10> = 0, A<2:0> = XXXb to access.
695 **
696 */
697 typedef union _SMC37c669_CR25 {
698     unsigned char as_uchar;
699     struct {
700     	unsigned zero : 1;	    /* 0			    */
701 	unsigned addr9_3 : 7;	    /* UART2 Addr<9:3>		    */
702     }	by_field;
703 } SMC37c669_CR25;
704 
705 /*
706 ** CR26 - default value 0x00
707 **
708 **  Parallel Port / FDC DMA Select Register
709 **
710 **  D3 - D0	  DMA
711 **  D7 - D4	Selected
712 **  -------	--------
713 **   0000	 None
714 **   0001	 DMA_A
715 **   0010	 DMA_B
716 **   0011	 DMA_C
717 **
718 */
719 typedef union _SMC37c669_CR26 {
720     unsigned char as_uchar;
721     struct {
722     	unsigned ppt_drq : 4;	    /* See note above		    */
723 	unsigned fdc_drq : 4;	    /* See note above		    */
724     }	by_field;
725 } SMC37c669_CR26;
726 
727 /*
728 ** CR27 - default value 0x00
729 **
730 **  Parallel Port / FDC IRQ Select Register
731 **
732 **  D3 - D0	  IRQ
733 **  D7 - D4	Selected
734 **  -------	--------
735 **   0000	 None
736 **   0001	 IRQ_A
737 **   0010	 IRQ_B
738 **   0011	 IRQ_C
739 **   0100	 IRQ_D
740 **   0101	 IRQ_E
741 **   0110	 IRQ_F
742 **   0111	 Reserved
743 **   1000	 IRQ_H
744 **
745 **  Any unselected IRQ REQ is in tristate
746 **
747 */
748 typedef union _SMC37c669_CR27 {
749     unsigned char as_uchar;
750     struct {
751     	unsigned ppt_irq : 4;	    /* See note above		    */
752 	unsigned fdc_irq : 4;	    /* See note above		    */
753     }	by_field;
754 } SMC37c669_CR27;
755 
756 /*
757 ** CR28 - default value 0x00
758 **
759 **  UART IRQ Select Register
760 **
761 **  D3 - D0	  IRQ
762 **  D7 - D4	Selected
763 **  -------	--------
764 **   0000	 None
765 **   0001	 IRQ_A
766 **   0010	 IRQ_B
767 **   0011	 IRQ_C
768 **   0100	 IRQ_D
769 **   0101	 IRQ_E
770 **   0110	 IRQ_F
771 **   0111	 Reserved
772 **   1000	 IRQ_H
773 **   1111	 share with UART1 (only for UART2)
774 **
775 **  Any unselected IRQ REQ is in tristate
776 **
777 **  To share an IRQ between UART1 and UART2, set
778 **  UART1 to use the desired IRQ and set UART2 to
779 **  0xF to enable sharing mechanism.
780 **
781 */
782 typedef union _SMC37c669_CR28 {
783     unsigned char as_uchar;
784     struct {
785     	unsigned uart2_irq : 4;	    /* See note above		    */
786 	unsigned uart1_irq : 4;	    /* See note above		    */
787     }	by_field;
788 } SMC37c669_CR28;
789 
790 /*
791 ** CR29 - default value 0x00
792 **
793 **  IRQIN IRQ Select Register
794 **
795 **  D3 - D0	  IRQ
796 **  D7 - D4	Selected
797 **  -------	--------
798 **   0000	 None
799 **   0001	 IRQ_A
800 **   0010	 IRQ_B
801 **   0011	 IRQ_C
802 **   0100	 IRQ_D
803 **   0101	 IRQ_E
804 **   0110	 IRQ_F
805 **   0111	 Reserved
806 **   1000	 IRQ_H
807 **
808 **  Any unselected IRQ REQ is in tristate
809 **
810 */
811 typedef union _SMC37c669_CR29 {
812     unsigned char as_uchar;
813     struct {
814     	unsigned irqin_irq : 4;	    /* See note above		    */
815 	unsigned reserved1 : 4;	    /* RAZ			    */
816     }	by_field;
817 } SMC37c669_CR29;
818 
819 /*
820 ** Aliases of Configuration Register formats (should match
821 ** the set of index aliases).
822 **
823 ** Note that CR24 and CR25 have the same format and are the
824 ** base address registers for UART1 and UART2.  Because of
825 ** this we only define 1 alias here - for CR24 - as the serial
826 ** base address register.
827 **
828 ** Note that CR21 and CR22 have the same format and are the
829 ** base address and alternate status address registers for
830 ** the IDE controller.  Because of this we only define 1 alias
831 ** here - for CR21 - as the IDE address register.
832 **
833 */
834 typedef SMC37c669_CR0D SMC37c669_DEVICE_ID_REGISTER;
835 typedef SMC37c669_CR0E SMC37c669_DEVICE_REVISION_REGISTER;
836 typedef SMC37c669_CR20 SMC37c669_FDC_BASE_ADDRESS_REGISTER;
837 typedef SMC37c669_CR21 SMC37c669_IDE_ADDRESS_REGISTER;
838 typedef SMC37c669_CR23 SMC37c669_PARALLEL_BASE_ADDRESS_REGISTER;
839 typedef SMC37c669_CR24 SMC37c669_SERIAL_BASE_ADDRESS_REGISTER;
840 typedef SMC37c669_CR26 SMC37c669_PARALLEL_FDC_DRQ_REGISTER;
841 typedef SMC37c669_CR27 SMC37c669_PARALLEL_FDC_IRQ_REGISTER;
842 typedef SMC37c669_CR28 SMC37c669_SERIAL_IRQ_REGISTER;
843 
844 /*
845 ** ISA/Device IRQ Translation Table Entry Definition
846 */
847 typedef struct _SMC37c669_IRQ_TRANSLATION_ENTRY {
848     int device_irq;
849     int isa_irq;
850 } SMC37c669_IRQ_TRANSLATION_ENTRY;
851 
852 /*
853 ** ISA/Device DMA Translation Table Entry Definition
854 */
855 typedef struct _SMC37c669_DRQ_TRANSLATION_ENTRY {
856     int device_drq;
857     int isa_drq;
858 } SMC37c669_DRQ_TRANSLATION_ENTRY;
859 
860 /*
861 ** External Interface Function Prototype Declarations
862 */
863 
864 SMC37c669_CONFIG_REGS *SMC37c669_detect(
865     int
866 );
867 
868 unsigned int SMC37c669_enable_device(
869     unsigned int func
870 );
871 
872 unsigned int SMC37c669_disable_device(
873     unsigned int func
874 );
875 
876 unsigned int SMC37c669_configure_device(
877     unsigned int func,
878     int port,
879     int irq,
880     int drq
881 );
882 
883 void SMC37c669_display_device_info(
884     void
885 );
886 
887 #endif	/* __SMC37c669_H */
888 
889 /* file:	smcc669.c
890  *
891  * Copyright (C) 1997 by
892  * Digital Equipment Corporation, Maynard, Massachusetts.
893  * All rights reserved.
894  *
895  * This software is furnished under a license and may be used and copied
896  * only  in  accordance  of  the  terms  of  such  license  and with the
897  * inclusion of the above copyright notice. This software or  any  other
898  * copies thereof may not be provided or otherwise made available to any
899  * other person.  No title to and  ownership of the  software is  hereby
900  * transferred.
901  *
902  * The information in this software is  subject to change without notice
903  * and  should  not  be  construed  as a commitment by digital equipment
904  * corporation.
905  *
906  * Digital assumes no responsibility for the use  or  reliability of its
907  * software on equipment which is not supplied by digital.
908  */
909 
910 /*
911  *++
912  *  FACILITY:
913  *
914  *      Alpha SRM Console Firmware
915  *
916  *  MODULE DESCRIPTION:
917  *
918  *	SMC37c669 Super I/O controller configuration routines.
919  *
920  *  AUTHORS:
921  *
922  *	Eric Rasmussen
923  *
924  *  CREATION DATE:
925  *
926  *	28-Jan-1997
927  *
928  *  MODIFICATION HISTORY:
929  *
930  *	er	01-May-1997	Fixed pointer conversion errors in
931  *				SMC37c669_get_device_config().
932  *      er	28-Jan-1997	Initial version.
933  *
934  *--
935  */
936 #if 0
937 /* $INCLUDE_OPTIONS$ */
938 #include    "cp$inc:platform_io.h"
939 /* $INCLUDE_OPTIONS_END$ */
940 #include    "cp$src:common.h"
941 #include    "cp$inc:prototypes.h"
942 #include    "cp$src:kernel_def.h"
943 #include    "cp$src:msg_def.h"
944 #include    "cp$src:smcc669_def.h"
945 /* Platform-specific includes */
946 #include    "cp$src:platform.h"
947 #endif
948 
949 #ifndef TRUE
950 #define TRUE 1
951 #endif
952 #ifndef FALSE
953 #define FALSE 0
954 #endif
955 
956 #define wb( _x_, _y_ )	outb( _y_, (unsigned int)((unsigned long)_x_) )
957 #define rb( _x_ )	inb( (unsigned int)((unsigned long)_x_) )
958 
959 /*
960 ** Local storage for device configuration information.
961 **
962 ** Since the SMC37c669 does not provide an explicit
963 ** mechanism for enabling/disabling individual device
964 ** functions, other than unmapping the device, local
965 ** storage for device configuration information is
966 ** allocated here for use in implementing our own
967 ** function enable/disable scheme.
968 */
969 static struct DEVICE_CONFIG {
970     unsigned int port1;
971     unsigned int port2;
972     int irq;
973     int drq;
974 } local_config [NUM_FUNCS];
975 
976 /*
977 ** List of all possible addresses for the Super I/O chip
978 */
979 static unsigned long SMC37c669_Addresses[] __initdata =
980     {
981 	0x3F0UL,	    /* Primary address	    */
982 	0x370UL,	    /* Secondary address    */
983 	0UL		    /* End of list	    */
984     };
985 
986 /*
987 ** Global Pointer to the Super I/O device
988 */
989 static SMC37c669_CONFIG_REGS *SMC37c669 __initdata = NULL;
990 
991 /*
992 ** IRQ Translation Table
993 **
994 ** The IRQ translation table is a list of SMC37c669 device
995 ** and standard ISA IRQs.
996 **
997 */
998 static SMC37c669_IRQ_TRANSLATION_ENTRY *SMC37c669_irq_table __initdata;
999 
1000 /*
1001 ** The following definition is for the default IRQ
1002 ** translation table.
1003 */
1004 static SMC37c669_IRQ_TRANSLATION_ENTRY SMC37c669_default_irq_table[]
1005 __initdata =
1006     {
1007 	{ SMC37c669_DEVICE_IRQ_A, -1 },
1008 	{ SMC37c669_DEVICE_IRQ_B, -1 },
1009 	{ SMC37c669_DEVICE_IRQ_C, 7 },
1010 	{ SMC37c669_DEVICE_IRQ_D, 6 },
1011 	{ SMC37c669_DEVICE_IRQ_E, 4 },
1012 	{ SMC37c669_DEVICE_IRQ_F, 3 },
1013 	{ SMC37c669_DEVICE_IRQ_H, -1 },
1014 	{ -1, -1 } /* End of table */
1015     };
1016 
1017 /*
1018 ** The following definition is for the MONET (XP1000) IRQ
1019 ** translation table.
1020 */
1021 static SMC37c669_IRQ_TRANSLATION_ENTRY SMC37c669_monet_irq_table[]
1022 __initdata =
1023     {
1024 	{ SMC37c669_DEVICE_IRQ_A, -1 },
1025 	{ SMC37c669_DEVICE_IRQ_B, -1 },
1026 	{ SMC37c669_DEVICE_IRQ_C, 6 },
1027 	{ SMC37c669_DEVICE_IRQ_D, 7 },
1028 	{ SMC37c669_DEVICE_IRQ_E, 4 },
1029 	{ SMC37c669_DEVICE_IRQ_F, 3 },
1030 	{ SMC37c669_DEVICE_IRQ_H, -1 },
1031 	{ -1, -1 } /* End of table */
1032     };
1033 
1034 static SMC37c669_IRQ_TRANSLATION_ENTRY *SMC37c669_irq_tables[] __initdata =
1035     {
1036 	SMC37c669_default_irq_table,
1037 	SMC37c669_monet_irq_table
1038     };
1039 
1040 /*
1041 ** DRQ Translation Table
1042 **
1043 ** The DRQ translation table is a list of SMC37c669 device and
1044 ** ISA DMA channels.
1045 **
1046 */
1047 static SMC37c669_DRQ_TRANSLATION_ENTRY *SMC37c669_drq_table __initdata;
1048 
1049 /*
1050 ** The following definition is the default DRQ
1051 ** translation table.
1052 */
1053 static SMC37c669_DRQ_TRANSLATION_ENTRY SMC37c669_default_drq_table[]
1054 __initdata =
1055     {
1056 	{ SMC37c669_DEVICE_DRQ_A, 2 },
1057 	{ SMC37c669_DEVICE_DRQ_B, 3 },
1058 	{ SMC37c669_DEVICE_DRQ_C, -1 },
1059 	{ -1, -1 } /* End of table */
1060     };
1061 
1062 /*
1063 ** Local Function Prototype Declarations
1064 */
1065 
1066 static unsigned int SMC37c669_is_device_enabled(
1067     unsigned int func
1068 );
1069 
1070 #if 0
1071 static unsigned int SMC37c669_get_device_config(
1072     unsigned int func,
1073     int *port,
1074     int *irq,
1075     int *drq
1076 );
1077 #endif
1078 
1079 static void SMC37c669_config_mode(
1080     unsigned int enable
1081 );
1082 
1083 static unsigned char SMC37c669_read_config(
1084     unsigned char index
1085 );
1086 
1087 static void SMC37c669_write_config(
1088     unsigned char index,
1089     unsigned char data
1090 );
1091 
1092 static void SMC37c669_init_local_config( void );
1093 
1094 static struct DEVICE_CONFIG *SMC37c669_get_config(
1095     unsigned int func
1096 );
1097 
1098 static int SMC37c669_xlate_irq(
1099     int irq
1100 );
1101 
1102 static int SMC37c669_xlate_drq(
1103     int drq
1104 );
1105 
1106 static  __cacheline_aligned DEFINE_SPINLOCK(smc_lock);
1107 
1108 /*
1109 **++
1110 **  FUNCTIONAL DESCRIPTION:
1111 **
1112 **      This function detects the presence of an SMC37c669 Super I/O
1113 **	controller.
1114 **
1115 **  FORMAL PARAMETERS:
1116 **
1117 **	None
1118 **
1119 **  RETURN VALUE:
1120 **
1121 **      Returns a pointer to the device if found, otherwise,
1122 **	the NULL pointer is returned.
1123 **
1124 **  SIDE EFFECTS:
1125 **
1126 **      None
1127 **
1128 **--
1129 */
1130 SMC37c669_CONFIG_REGS * __init SMC37c669_detect( int index )
1131 {
1132     int i;
1133     SMC37c669_DEVICE_ID_REGISTER id;
1134 
1135     for ( i = 0;  SMC37c669_Addresses[i] != 0;  i++ ) {
1136 /*
1137 ** Initialize the device pointer even though we don't yet know if
1138 ** the controller is at this address.  The support functions access
1139 ** the controller through this device pointer so we need to set it
1140 ** even when we are looking ...
1141 */
1142     	SMC37c669 = ( SMC37c669_CONFIG_REGS * )SMC37c669_Addresses[i];
1143 /*
1144 ** Enter configuration mode
1145 */
1146 	SMC37c669_config_mode( TRUE );
1147 /*
1148 ** Read the device id
1149 */
1150 	id.as_uchar = SMC37c669_read_config( SMC37c669_DEVICE_ID_INDEX );
1151 /*
1152 ** Exit configuration mode
1153 */
1154 	SMC37c669_config_mode( FALSE );
1155 /*
1156 ** Does the device id match?  If so, assume we have found an
1157 ** SMC37c669 controller at this address.
1158 */
1159 	if ( id.by_field.device_id == SMC37c669_DEVICE_ID ) {
1160 /*
1161 ** Initialize the IRQ and DRQ translation tables.
1162 */
1163     	    SMC37c669_irq_table = SMC37c669_irq_tables[ index ];
1164 	    SMC37c669_drq_table = SMC37c669_default_drq_table;
1165 /*
1166 ** erfix
1167 **
1168 ** If the platform can't use the IRQ and DRQ defaults set up in this
1169 ** file, it should call a platform-specific external routine at this
1170 ** point to reset the IRQ and DRQ translation table pointers to point
1171 ** at the appropriate tables for the platform.  If the defaults are
1172 ** acceptable, then the external routine should do nothing.
1173 */
1174 
1175 /*
1176 ** Put the chip back into configuration mode
1177 */
1178 	    SMC37c669_config_mode( TRUE );
1179 /*
1180 ** Initialize local storage for configuration information
1181 */
1182 	    SMC37c669_init_local_config( );
1183 /*
1184 ** Exit configuration mode
1185 */
1186 	    SMC37c669_config_mode( FALSE );
1187 /*
1188 ** SMC37c669 controller found, break out of search loop
1189 */
1190 	    break;
1191 	}
1192 	else {
1193 /*
1194 ** Otherwise, we did not find an SMC37c669 controller at this
1195 ** address so set the device pointer to NULL.
1196 */
1197 	    SMC37c669 = NULL;
1198 	}
1199     }
1200     return SMC37c669;
1201 }
1202 
1203 
1204 /*
1205 **++
1206 **  FUNCTIONAL DESCRIPTION:
1207 **
1208 **      This function enables an SMC37c669 device function.
1209 **
1210 **  FORMAL PARAMETERS:
1211 **
1212 **      func:
1213 **          Which device function to enable
1214 **
1215 **  RETURN VALUE:
1216 **
1217 **      Returns TRUE is the device function was enabled, otherwise, FALSE
1218 **
1219 **  SIDE EFFECTS:
1220 **
1221 **      {@description or none@}
1222 **
1223 **  DESIGN:
1224 **
1225 **      Enabling a device function in the SMC37c669 controller involves
1226 **	setting all of its mappings (port, irq, drq ...).  A local
1227 **	"shadow" copy of the device configuration is kept so we can
1228 **	just set each mapping to what the local copy says.
1229 **
1230 **	This function ALWAYS updates the local shadow configuration of
1231 **	the device function being enabled, even if the device is always
1232 **	enabled.  To avoid replication of code, functions such as
1233 **	configure_device set up the local copy and then call this
1234 **	function to the update the real device.
1235 **
1236 **--
1237 */
1238 unsigned int __init SMC37c669_enable_device ( unsigned int func )
1239 {
1240     unsigned int ret_val = FALSE;
1241 /*
1242 ** Put the device into configuration mode
1243 */
1244     SMC37c669_config_mode( TRUE );
1245     switch ( func ) {
1246     	case SERIAL_0:
1247 	    {
1248 	    	SMC37c669_SERIAL_BASE_ADDRESS_REGISTER base_addr;
1249 		SMC37c669_SERIAL_IRQ_REGISTER irq;
1250 /*
1251 ** Enable the serial 1 IRQ mapping
1252 */
1253 	    	irq.as_uchar =
1254 		    SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX );
1255 
1256 		irq.by_field.uart1_irq =
1257 		    SMC37c669_RAW_DEVICE_IRQ(
1258 			SMC37c669_xlate_irq( local_config[ func ].irq )
1259 		    );
1260 
1261 		SMC37c669_write_config( SMC37c669_SERIAL_IRQ_INDEX, irq.as_uchar );
1262 /*
1263 ** Enable the serial 1 port base address mapping
1264 */
1265 		base_addr.as_uchar = 0;
1266 		base_addr.by_field.addr9_3 = local_config[ func ].port1 >> 3;
1267 
1268 		SMC37c669_write_config(
1269 		    SMC37c669_SERIAL0_BASE_ADDRESS_INDEX,
1270 		    base_addr.as_uchar
1271 		);
1272 		ret_val = TRUE;
1273 		break;
1274 	    }
1275 	case SERIAL_1:
1276 	    {
1277 	    	SMC37c669_SERIAL_BASE_ADDRESS_REGISTER base_addr;
1278 		SMC37c669_SERIAL_IRQ_REGISTER irq;
1279 /*
1280 ** Enable the serial 2 IRQ mapping
1281 */
1282 	    	irq.as_uchar =
1283 		    SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX );
1284 
1285 		irq.by_field.uart2_irq =
1286 		    SMC37c669_RAW_DEVICE_IRQ(
1287 			SMC37c669_xlate_irq( local_config[ func ].irq )
1288 		    );
1289 
1290 		SMC37c669_write_config( SMC37c669_SERIAL_IRQ_INDEX, irq.as_uchar );
1291 /*
1292 ** Enable the serial 2 port base address mapping
1293 */
1294 		base_addr.as_uchar = 0;
1295 		base_addr.by_field.addr9_3 = local_config[ func ].port1 >> 3;
1296 
1297 		SMC37c669_write_config(
1298 		    SMC37c669_SERIAL1_BASE_ADDRESS_INDEX,
1299 		    base_addr.as_uchar
1300 		);
1301 		ret_val = TRUE;
1302 		break;
1303 	    }
1304 	case PARALLEL_0:
1305 	    {
1306 	    	SMC37c669_PARALLEL_BASE_ADDRESS_REGISTER base_addr;
1307 		SMC37c669_PARALLEL_FDC_IRQ_REGISTER irq;
1308 		SMC37c669_PARALLEL_FDC_DRQ_REGISTER drq;
1309 /*
1310 ** Enable the parallel port DMA channel mapping
1311 */
1312 	    	drq.as_uchar =
1313 		    SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX );
1314 
1315 		drq.by_field.ppt_drq =
1316 		    SMC37c669_RAW_DEVICE_DRQ(
1317 			SMC37c669_xlate_drq( local_config[ func ].drq )
1318 		    );
1319 
1320 		SMC37c669_write_config(
1321 		    SMC37c669_PARALLEL_FDC_DRQ_INDEX,
1322 		    drq.as_uchar
1323 		);
1324 /*
1325 ** Enable the parallel port IRQ mapping
1326 */
1327 		irq.as_uchar =
1328 		    SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX );
1329 
1330 		irq.by_field.ppt_irq =
1331 		    SMC37c669_RAW_DEVICE_IRQ(
1332 			SMC37c669_xlate_irq( local_config[ func ].irq )
1333 		    );
1334 
1335 		SMC37c669_write_config(
1336 		    SMC37c669_PARALLEL_FDC_IRQ_INDEX,
1337 		    irq.as_uchar
1338 		);
1339 /*
1340 ** Enable the parallel port base address mapping
1341 */
1342 		base_addr.as_uchar = 0;
1343 		base_addr.by_field.addr9_2 = local_config[ func ].port1 >> 2;
1344 
1345 		SMC37c669_write_config(
1346 		    SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX,
1347 		    base_addr.as_uchar
1348 		);
1349 		ret_val = TRUE;
1350 		break;
1351 	    }
1352 	case FLOPPY_0:
1353 	    {
1354 	    	SMC37c669_FDC_BASE_ADDRESS_REGISTER base_addr;
1355 		SMC37c669_PARALLEL_FDC_IRQ_REGISTER irq;
1356 		SMC37c669_PARALLEL_FDC_DRQ_REGISTER drq;
1357 /*
1358 ** Enable the floppy controller DMA channel mapping
1359 */
1360 	    	drq.as_uchar =
1361 		    SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX );
1362 
1363 		drq.by_field.fdc_drq =
1364 		    SMC37c669_RAW_DEVICE_DRQ(
1365 			SMC37c669_xlate_drq( local_config[ func ].drq )
1366 		    );
1367 
1368 		SMC37c669_write_config(
1369 		    SMC37c669_PARALLEL_FDC_DRQ_INDEX,
1370 		    drq.as_uchar
1371 		);
1372 /*
1373 ** Enable the floppy controller IRQ mapping
1374 */
1375 		irq.as_uchar =
1376 		    SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX );
1377 
1378 		irq.by_field.fdc_irq =
1379 		    SMC37c669_RAW_DEVICE_IRQ(
1380 			SMC37c669_xlate_irq( local_config[ func ].irq )
1381 		    );
1382 
1383 		SMC37c669_write_config(
1384 		    SMC37c669_PARALLEL_FDC_IRQ_INDEX,
1385 		    irq.as_uchar
1386 		);
1387 /*
1388 ** Enable the floppy controller base address mapping
1389 */
1390 		base_addr.as_uchar = 0;
1391 		base_addr.by_field.addr9_4 = local_config[ func ].port1 >> 4;
1392 
1393 		SMC37c669_write_config(
1394 		    SMC37c669_FDC_BASE_ADDRESS_INDEX,
1395 		    base_addr.as_uchar
1396 		);
1397 		ret_val = TRUE;
1398 		break;
1399 	    }
1400 	case IDE_0:
1401 	    {
1402 	    	SMC37c669_IDE_ADDRESS_REGISTER ide_addr;
1403 /*
1404 ** Enable the IDE alternate status base address mapping
1405 */
1406 	    	ide_addr.as_uchar = 0;
1407 		ide_addr.by_field.addr9_4 = local_config[ func ].port2 >> 4;
1408 
1409 		SMC37c669_write_config(
1410 		    SMC37c669_IDE_ALTERNATE_ADDRESS_INDEX,
1411 		    ide_addr.as_uchar
1412 		);
1413 /*
1414 ** Enable the IDE controller base address mapping
1415 */
1416 		ide_addr.as_uchar = 0;
1417 		ide_addr.by_field.addr9_4 = local_config[ func ].port1 >> 4;
1418 
1419 		SMC37c669_write_config(
1420 		    SMC37c669_IDE_BASE_ADDRESS_INDEX,
1421 		    ide_addr.as_uchar
1422 		);
1423 		ret_val = TRUE;
1424 		break;
1425 	    }
1426     }
1427 /*
1428 ** Exit configuration mode and return
1429 */
1430     SMC37c669_config_mode( FALSE );
1431 
1432     return ret_val;
1433 }
1434 
1435 
1436 /*
1437 **++
1438 **  FUNCTIONAL DESCRIPTION:
1439 **
1440 **      This function disables a device function within the
1441 **	SMC37c669 Super I/O controller.
1442 **
1443 **  FORMAL PARAMETERS:
1444 **
1445 **      func:
1446 **          Which function to disable
1447 **
1448 **  RETURN VALUE:
1449 **
1450 **      Return TRUE if the device function was disabled, otherwise, FALSE
1451 **
1452 **  SIDE EFFECTS:
1453 **
1454 **      {@description or none@}
1455 **
1456 **  DESIGN:
1457 **
1458 **      Disabling a function in the SMC37c669 device involves
1459 **	disabling all the function's mappings (port, irq, drq ...).
1460 **	A shadow copy of the device configuration is maintained
1461 **	in local storage so we won't worry aboving saving the
1462 **	current configuration information.
1463 **
1464 **--
1465 */
1466 unsigned int __init SMC37c669_disable_device ( unsigned int func )
1467 {
1468     unsigned int ret_val = FALSE;
1469 
1470 /*
1471 ** Put the device into configuration mode
1472 */
1473     SMC37c669_config_mode( TRUE );
1474     switch ( func ) {
1475     	case SERIAL_0:
1476 	    {
1477 	    	SMC37c669_SERIAL_BASE_ADDRESS_REGISTER base_addr;
1478 		SMC37c669_SERIAL_IRQ_REGISTER irq;
1479 /*
1480 ** Disable the serial 1 IRQ mapping
1481 */
1482 	    	irq.as_uchar =
1483 		    SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX );
1484 
1485 		irq.by_field.uart1_irq = 0;
1486 
1487 		SMC37c669_write_config( SMC37c669_SERIAL_IRQ_INDEX, irq.as_uchar );
1488 /*
1489 ** Disable the serial 1 port base address mapping
1490 */
1491 		base_addr.as_uchar = 0;
1492 		SMC37c669_write_config(
1493 		    SMC37c669_SERIAL0_BASE_ADDRESS_INDEX,
1494 		    base_addr.as_uchar
1495 		);
1496 		ret_val = TRUE;
1497 		break;
1498 	    }
1499 	case SERIAL_1:
1500 	    {
1501 	    	SMC37c669_SERIAL_BASE_ADDRESS_REGISTER base_addr;
1502 		SMC37c669_SERIAL_IRQ_REGISTER irq;
1503 /*
1504 ** Disable the serial 2 IRQ mapping
1505 */
1506 	    	irq.as_uchar =
1507 		    SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX );
1508 
1509 		irq.by_field.uart2_irq = 0;
1510 
1511 		SMC37c669_write_config( SMC37c669_SERIAL_IRQ_INDEX, irq.as_uchar );
1512 /*
1513 ** Disable the serial 2 port base address mapping
1514 */
1515 		base_addr.as_uchar = 0;
1516 
1517 		SMC37c669_write_config(
1518 		    SMC37c669_SERIAL1_BASE_ADDRESS_INDEX,
1519 		    base_addr.as_uchar
1520 		);
1521 		ret_val = TRUE;
1522 		break;
1523 	    }
1524 	case PARALLEL_0:
1525 	    {
1526 	    	SMC37c669_PARALLEL_BASE_ADDRESS_REGISTER base_addr;
1527 		SMC37c669_PARALLEL_FDC_IRQ_REGISTER irq;
1528 		SMC37c669_PARALLEL_FDC_DRQ_REGISTER drq;
1529 /*
1530 ** Disable the parallel port DMA channel mapping
1531 */
1532 	    	drq.as_uchar =
1533 		    SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX );
1534 
1535 		drq.by_field.ppt_drq = 0;
1536 
1537 		SMC37c669_write_config(
1538 		    SMC37c669_PARALLEL_FDC_DRQ_INDEX,
1539 		    drq.as_uchar
1540 		);
1541 /*
1542 ** Disable the parallel port IRQ mapping
1543 */
1544 		irq.as_uchar =
1545 		    SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX );
1546 
1547 		irq.by_field.ppt_irq = 0;
1548 
1549 		SMC37c669_write_config(
1550 		    SMC37c669_PARALLEL_FDC_IRQ_INDEX,
1551 		    irq.as_uchar
1552 		);
1553 /*
1554 ** Disable the parallel port base address mapping
1555 */
1556 		base_addr.as_uchar = 0;
1557 
1558 		SMC37c669_write_config(
1559 		    SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX,
1560 		    base_addr.as_uchar
1561 		);
1562 		ret_val = TRUE;
1563 		break;
1564 	    }
1565 	case FLOPPY_0:
1566 	    {
1567 	    	SMC37c669_FDC_BASE_ADDRESS_REGISTER base_addr;
1568 		SMC37c669_PARALLEL_FDC_IRQ_REGISTER irq;
1569 		SMC37c669_PARALLEL_FDC_DRQ_REGISTER drq;
1570 /*
1571 ** Disable the floppy controller DMA channel mapping
1572 */
1573 	    	drq.as_uchar =
1574 		    SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX );
1575 
1576 		drq.by_field.fdc_drq = 0;
1577 
1578 		SMC37c669_write_config(
1579 		    SMC37c669_PARALLEL_FDC_DRQ_INDEX,
1580 		    drq.as_uchar
1581 		);
1582 /*
1583 ** Disable the floppy controller IRQ mapping
1584 */
1585 		irq.as_uchar =
1586 		    SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX );
1587 
1588 		irq.by_field.fdc_irq = 0;
1589 
1590 		SMC37c669_write_config(
1591 		    SMC37c669_PARALLEL_FDC_IRQ_INDEX,
1592 		    irq.as_uchar
1593 		);
1594 /*
1595 ** Disable the floppy controller base address mapping
1596 */
1597 		base_addr.as_uchar = 0;
1598 
1599 		SMC37c669_write_config(
1600 		    SMC37c669_FDC_BASE_ADDRESS_INDEX,
1601 		    base_addr.as_uchar
1602 		);
1603 		ret_val = TRUE;
1604 		break;
1605 	    }
1606 	case IDE_0:
1607 	    {
1608 	    	SMC37c669_IDE_ADDRESS_REGISTER ide_addr;
1609 /*
1610 ** Disable the IDE alternate status base address mapping
1611 */
1612 	    	ide_addr.as_uchar = 0;
1613 
1614 		SMC37c669_write_config(
1615 		    SMC37c669_IDE_ALTERNATE_ADDRESS_INDEX,
1616 		    ide_addr.as_uchar
1617 		);
1618 /*
1619 ** Disable the IDE controller base address mapping
1620 */
1621 		ide_addr.as_uchar = 0;
1622 
1623 		SMC37c669_write_config(
1624 		    SMC37c669_IDE_BASE_ADDRESS_INDEX,
1625 		    ide_addr.as_uchar
1626 		);
1627 		ret_val = TRUE;
1628 		break;
1629 	    }
1630     }
1631 /*
1632 ** Exit configuration mode and return
1633 */
1634     SMC37c669_config_mode( FALSE );
1635 
1636     return ret_val;
1637 }
1638 
1639 
1640 /*
1641 **++
1642 **  FUNCTIONAL DESCRIPTION:
1643 **
1644 **      This function configures a device function within the
1645 **	SMC37c669 Super I/O controller.
1646 **
1647 **  FORMAL PARAMETERS:
1648 **
1649 **      func:
1650 **          Which device function
1651 **
1652 **      port:
1653 **          I/O port for the function to use
1654 **
1655 **      irq:
1656 **          IRQ for the device function to use
1657 **
1658 **      drq:
1659 **          DMA channel for the device function to use
1660 **
1661 **  RETURN VALUE:
1662 **
1663 **      Returns TRUE if the device function was configured,
1664 **	otherwise, FALSE.
1665 **
1666 **  SIDE EFFECTS:
1667 **
1668 **      {@description or none@}
1669 **
1670 **  DESIGN:
1671 **
1672 **	If this function returns TRUE, the local shadow copy of
1673 **	the configuration is also updated.  If the device function
1674 **	is currently disabled, only the local shadow copy is
1675 **	updated and the actual device function will be updated
1676 **	if/when it is enabled.
1677 **
1678 **--
1679 */
1680 unsigned int __init SMC37c669_configure_device (
1681     unsigned int func,
1682     int port,
1683     int irq,
1684     int drq )
1685 {
1686     struct DEVICE_CONFIG *cp;
1687 
1688 /*
1689 ** Check for a valid configuration
1690 */
1691     if ( ( cp = SMC37c669_get_config ( func ) ) != NULL ) {
1692 /*
1693 ** Configuration is valid, update the local shadow copy
1694 */
1695     	if ( ( drq & ~0xFF ) == 0 ) {
1696 	    cp->drq = drq;
1697 	}
1698 	if ( ( irq & ~0xFF ) == 0 ) {
1699 	    cp->irq = irq;
1700 	}
1701 	if ( ( port & ~0xFFFF ) == 0 ) {
1702 	    cp->port1 = port;
1703 	}
1704 /*
1705 ** If the device function is enabled, update the actual
1706 ** device configuration.
1707 */
1708 	if ( SMC37c669_is_device_enabled( func ) ) {
1709 	    SMC37c669_enable_device( func );
1710 	}
1711 	return TRUE;
1712     }
1713     return FALSE;
1714 }
1715 
1716 
1717 /*
1718 **++
1719 **  FUNCTIONAL DESCRIPTION:
1720 **
1721 **      This function determines whether a device function
1722 **	within the SMC37c669 controller is enabled.
1723 **
1724 **  FORMAL PARAMETERS:
1725 **
1726 **      func:
1727 **          Which device function
1728 **
1729 **  RETURN VALUE:
1730 **
1731 **      Returns TRUE if the device function is enabled, otherwise, FALSE
1732 **
1733 **  SIDE EFFECTS:
1734 **
1735 **      {@description or none@}
1736 **
1737 **  DESIGN:
1738 **
1739 **      To check whether a device is enabled we will only look at
1740 **	the port base address mapping.  According to the SMC37c669
1741 **	specification, all of the port base address mappings are
1742 **	disabled if the addr<9:8> (bits <7:6> of the register) are
1743 **	zero.
1744 **
1745 **--
1746 */
1747 static unsigned int __init SMC37c669_is_device_enabled ( unsigned int func )
1748 {
1749     unsigned char base_addr = 0;
1750     unsigned int dev_ok = FALSE;
1751     unsigned int ret_val = FALSE;
1752 /*
1753 ** Enter configuration mode
1754 */
1755     SMC37c669_config_mode( TRUE );
1756 
1757     switch ( func ) {
1758     	case SERIAL_0:
1759 	    base_addr =
1760 		SMC37c669_read_config( SMC37c669_SERIAL0_BASE_ADDRESS_INDEX );
1761 	    dev_ok = TRUE;
1762 	    break;
1763 	case SERIAL_1:
1764 	    base_addr =
1765 		SMC37c669_read_config( SMC37c669_SERIAL1_BASE_ADDRESS_INDEX );
1766 	    dev_ok = TRUE;
1767 	    break;
1768 	case PARALLEL_0:
1769 	    base_addr =
1770 		SMC37c669_read_config( SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX );
1771 	    dev_ok = TRUE;
1772 	    break;
1773 	case FLOPPY_0:
1774 	    base_addr =
1775 		SMC37c669_read_config( SMC37c669_FDC_BASE_ADDRESS_INDEX );
1776 	    dev_ok = TRUE;
1777 	    break;
1778 	case IDE_0:
1779 	    base_addr =
1780 		SMC37c669_read_config( SMC37c669_IDE_BASE_ADDRESS_INDEX );
1781 	    dev_ok = TRUE;
1782 	    break;
1783     }
1784 /*
1785 ** If we have a valid device, check base_addr<7:6> to see if the
1786 ** device is enabled (mapped).
1787 */
1788     if ( ( dev_ok ) && ( ( base_addr & 0xC0 ) != 0 ) ) {
1789 /*
1790 ** The mapping is not disabled, so assume that the function is
1791 ** enabled.
1792 */
1793     	ret_val = TRUE;
1794     }
1795 /*
1796 ** Exit configuration mode
1797 */
1798     SMC37c669_config_mode( FALSE );
1799 
1800     return ret_val;
1801 }
1802 
1803 
1804 #if 0
1805 /*
1806 **++
1807 **  FUNCTIONAL DESCRIPTION:
1808 **
1809 **      This function retrieves the configuration information of a
1810 **	device function within the SMC37c699 Super I/O controller.
1811 **
1812 **  FORMAL PARAMETERS:
1813 **
1814 **      func:
1815 **          Which device function
1816 **
1817 **      port:
1818 **          I/O port returned
1819 **
1820 **      irq:
1821 **          IRQ returned
1822 **
1823 **      drq:
1824 **          DMA channel returned
1825 **
1826 **  RETURN VALUE:
1827 **
1828 **      Returns TRUE if the device configuration was successfully
1829 **	retrieved, otherwise, FALSE.
1830 **
1831 **  SIDE EFFECTS:
1832 **
1833 **      The data pointed to by the port, irq, and drq parameters
1834 **	my be modified even if the configuration is not successfully
1835 **	retrieved.
1836 **
1837 **  DESIGN:
1838 **
1839 **      The device configuration is fetched from the local shadow
1840 **	copy.  Any unused parameters will be set to -1.  Any
1841 **	parameter which is not desired can specify the NULL
1842 **	pointer.
1843 **
1844 **--
1845 */
1846 static unsigned int __init SMC37c669_get_device_config (
1847     unsigned int func,
1848     int *port,
1849     int *irq,
1850     int *drq )
1851 {
1852     struct DEVICE_CONFIG *cp;
1853     unsigned int ret_val = FALSE;
1854 /*
1855 ** Check for a valid device configuration
1856 */
1857     if ( ( cp = SMC37c669_get_config( func ) ) != NULL ) {
1858     	if ( drq != NULL ) {
1859 	    *drq = cp->drq;
1860 	    ret_val = TRUE;
1861 	}
1862 	if ( irq != NULL ) {
1863 	    *irq = cp->irq;
1864 	    ret_val = TRUE;
1865 	}
1866 	if ( port != NULL ) {
1867 	    *port = cp->port1;
1868 	    ret_val = TRUE;
1869 	}
1870     }
1871     return ret_val;
1872 }
1873 #endif
1874 
1875 
1876 /*
1877 **++
1878 **  FUNCTIONAL DESCRIPTION:
1879 **
1880 **      This function displays the current state of the SMC37c699
1881 **	Super I/O controller's device functions.
1882 **
1883 **  FORMAL PARAMETERS:
1884 **
1885 **      None
1886 **
1887 **  RETURN VALUE:
1888 **
1889 **      None
1890 **
1891 **  SIDE EFFECTS:
1892 **
1893 **      None
1894 **
1895 **--
1896 */
1897 void __init SMC37c669_display_device_info ( void )
1898 {
1899     if ( SMC37c669_is_device_enabled( SERIAL_0 ) ) {
1900     	printk( "  Serial 0:    Enabled [ Port 0x%x, IRQ %d ]\n",
1901 		 local_config[ SERIAL_0 ].port1,
1902 		 local_config[ SERIAL_0 ].irq
1903 	);
1904     }
1905     else {
1906     	printk( "  Serial 0:    Disabled\n" );
1907     }
1908 
1909     if ( SMC37c669_is_device_enabled( SERIAL_1 ) ) {
1910     	printk( "  Serial 1:    Enabled [ Port 0x%x, IRQ %d ]\n",
1911 		 local_config[ SERIAL_1 ].port1,
1912 		 local_config[ SERIAL_1 ].irq
1913 	);
1914     }
1915     else {
1916     	printk( "  Serial 1:    Disabled\n" );
1917     }
1918 
1919     if ( SMC37c669_is_device_enabled( PARALLEL_0 ) ) {
1920     	printk( "  Parallel:    Enabled [ Port 0x%x, IRQ %d/%d ]\n",
1921 		 local_config[ PARALLEL_0 ].port1,
1922 		 local_config[ PARALLEL_0 ].irq,
1923 		 local_config[ PARALLEL_0 ].drq
1924 	);
1925     }
1926     else {
1927     	printk( "  Parallel:    Disabled\n" );
1928     }
1929 
1930     if ( SMC37c669_is_device_enabled( FLOPPY_0 ) ) {
1931     	printk( "  Floppy Ctrl: Enabled [ Port 0x%x, IRQ %d/%d ]\n",
1932 		 local_config[ FLOPPY_0 ].port1,
1933 		 local_config[ FLOPPY_0 ].irq,
1934 		 local_config[ FLOPPY_0 ].drq
1935 	);
1936     }
1937     else {
1938     	printk( "  Floppy Ctrl: Disabled\n" );
1939     }
1940 
1941     if ( SMC37c669_is_device_enabled( IDE_0 ) ) {
1942     	printk( "  IDE 0:       Enabled [ Port 0x%x, IRQ %d ]\n",
1943 		 local_config[ IDE_0 ].port1,
1944 		 local_config[ IDE_0 ].irq
1945 	);
1946     }
1947     else {
1948     	printk( "  IDE 0:       Disabled\n" );
1949     }
1950 }
1951 
1952 
1953 /*
1954 **++
1955 **  FUNCTIONAL DESCRIPTION:
1956 **
1957 **      This function puts the SMC37c669 Super I/O controller into,
1958 **	and takes it out of, configuration mode.
1959 **
1960 **  FORMAL PARAMETERS:
1961 **
1962 **      enable:
1963 **          TRUE to enter configuration mode, FALSE to exit.
1964 **
1965 **  RETURN VALUE:
1966 **
1967 **      None
1968 **
1969 **  SIDE EFFECTS:
1970 **
1971 **      The SMC37c669 controller may be left in configuration mode.
1972 **
1973 **--
1974 */
1975 static void __init SMC37c669_config_mode(
1976     unsigned int enable )
1977 {
1978     if ( enable ) {
1979 /*
1980 ** To enter configuration mode, two writes in succession to the index
1981 ** port are required.  If a write to another address or port occurs
1982 ** between these two writes, the chip does not enter configuration
1983 ** mode.  Therefore, a spinlock is placed around the two writes to
1984 ** guarantee that they complete uninterrupted.
1985 */
1986 	spin_lock(&smc_lock);
1987     	wb( &SMC37c669->index_port, SMC37c669_CONFIG_ON_KEY );
1988     	wb( &SMC37c669->index_port, SMC37c669_CONFIG_ON_KEY );
1989 	spin_unlock(&smc_lock);
1990     }
1991     else {
1992     	wb( &SMC37c669->index_port, SMC37c669_CONFIG_OFF_KEY );
1993     }
1994 }
1995 
1996 /*
1997 **++
1998 **  FUNCTIONAL DESCRIPTION:
1999 **
2000 **      This function reads an SMC37c669 Super I/O controller
2001 **	configuration register.  This function assumes that the
2002 **	device is already in configuration mode.
2003 **
2004 **  FORMAL PARAMETERS:
2005 **
2006 **      index:
2007 **          Index value of configuration register to read
2008 **
2009 **  RETURN VALUE:
2010 **
2011 **      Data read from configuration register
2012 **
2013 **  SIDE EFFECTS:
2014 **
2015 **      None
2016 **
2017 **--
2018 */
2019 static unsigned char __init SMC37c669_read_config(
2020     unsigned char index )
2021 {
2022     unsigned char data;
2023 
2024     wb( &SMC37c669->index_port, index );
2025     data = rb( &SMC37c669->data_port );
2026     return data;
2027 }
2028 
2029 /*
2030 **++
2031 **  FUNCTIONAL DESCRIPTION:
2032 **
2033 **      This function writes an SMC37c669 Super I/O controller
2034 **	configuration register.  This function assumes that the
2035 **	device is already in configuration mode.
2036 **
2037 **  FORMAL PARAMETERS:
2038 **
2039 **      index:
2040 **          Index of configuration register to write
2041 **
2042 **      data:
2043 **          Data to be written
2044 **
2045 **  RETURN VALUE:
2046 **
2047 **      None
2048 **
2049 **  SIDE EFFECTS:
2050 **
2051 **      None
2052 **
2053 **--
2054 */
2055 static void __init SMC37c669_write_config(
2056     unsigned char index,
2057     unsigned char data )
2058 {
2059     wb( &SMC37c669->index_port, index );
2060     wb( &SMC37c669->data_port, data );
2061 }
2062 
2063 
2064 /*
2065 **++
2066 **  FUNCTIONAL DESCRIPTION:
2067 **
2068 **      This function initializes the local device
2069 **	configuration storage.  This function assumes
2070 **	that the device is already in configuration
2071 **	mode.
2072 **
2073 **  FORMAL PARAMETERS:
2074 **
2075 **      None
2076 **
2077 **  RETURN VALUE:
2078 **
2079 **      None
2080 **
2081 **  SIDE EFFECTS:
2082 **
2083 **      Local storage for device configuration information
2084 **	is initialized.
2085 **
2086 **--
2087 */
2088 static void __init SMC37c669_init_local_config ( void )
2089 {
2090     SMC37c669_SERIAL_BASE_ADDRESS_REGISTER uart_base;
2091     SMC37c669_SERIAL_IRQ_REGISTER uart_irqs;
2092     SMC37c669_PARALLEL_BASE_ADDRESS_REGISTER ppt_base;
2093     SMC37c669_PARALLEL_FDC_IRQ_REGISTER ppt_fdc_irqs;
2094     SMC37c669_PARALLEL_FDC_DRQ_REGISTER ppt_fdc_drqs;
2095     SMC37c669_FDC_BASE_ADDRESS_REGISTER fdc_base;
2096     SMC37c669_IDE_ADDRESS_REGISTER ide_base;
2097     SMC37c669_IDE_ADDRESS_REGISTER ide_alt;
2098 
2099 /*
2100 ** Get serial port 1 base address
2101 */
2102     uart_base.as_uchar =
2103 	SMC37c669_read_config( SMC37c669_SERIAL0_BASE_ADDRESS_INDEX );
2104 /*
2105 ** Get IRQs for serial ports 1 & 2
2106 */
2107     uart_irqs.as_uchar =
2108 	SMC37c669_read_config( SMC37c669_SERIAL_IRQ_INDEX );
2109 /*
2110 ** Store local configuration information for serial port 1
2111 */
2112     local_config[SERIAL_0].port1 = uart_base.by_field.addr9_3 << 3;
2113     local_config[SERIAL_0].irq =
2114 	SMC37c669_xlate_irq(
2115 	    SMC37c669_DEVICE_IRQ( uart_irqs.by_field.uart1_irq )
2116 	);
2117 /*
2118 ** Get serial port 2 base address
2119 */
2120     uart_base.as_uchar =
2121 	SMC37c669_read_config( SMC37c669_SERIAL1_BASE_ADDRESS_INDEX );
2122 /*
2123 ** Store local configuration information for serial port 2
2124 */
2125     local_config[SERIAL_1].port1 = uart_base.by_field.addr9_3 << 3;
2126     local_config[SERIAL_1].irq =
2127 	SMC37c669_xlate_irq(
2128 	    SMC37c669_DEVICE_IRQ( uart_irqs.by_field.uart2_irq )
2129 	);
2130 /*
2131 ** Get parallel port base address
2132 */
2133     ppt_base.as_uchar =
2134 	SMC37c669_read_config( SMC37c669_PARALLEL0_BASE_ADDRESS_INDEX );
2135 /*
2136 ** Get IRQs for parallel port and floppy controller
2137 */
2138     ppt_fdc_irqs.as_uchar =
2139 	SMC37c669_read_config( SMC37c669_PARALLEL_FDC_IRQ_INDEX );
2140 /*
2141 ** Get DRQs for parallel port and floppy controller
2142 */
2143     ppt_fdc_drqs.as_uchar =
2144 	SMC37c669_read_config( SMC37c669_PARALLEL_FDC_DRQ_INDEX );
2145 /*
2146 ** Store local configuration information for parallel port
2147 */
2148     local_config[PARALLEL_0].port1 = ppt_base.by_field.addr9_2 << 2;
2149     local_config[PARALLEL_0].irq =
2150 	SMC37c669_xlate_irq(
2151 	    SMC37c669_DEVICE_IRQ( ppt_fdc_irqs.by_field.ppt_irq )
2152 	);
2153     local_config[PARALLEL_0].drq =
2154 	SMC37c669_xlate_drq(
2155 	    SMC37c669_DEVICE_DRQ( ppt_fdc_drqs.by_field.ppt_drq )
2156 	);
2157 /*
2158 ** Get floppy controller base address
2159 */
2160     fdc_base.as_uchar =
2161 	SMC37c669_read_config( SMC37c669_FDC_BASE_ADDRESS_INDEX );
2162 /*
2163 ** Store local configuration information for floppy controller
2164 */
2165     local_config[FLOPPY_0].port1 = fdc_base.by_field.addr9_4 << 4;
2166     local_config[FLOPPY_0].irq =
2167 	SMC37c669_xlate_irq(
2168 	    SMC37c669_DEVICE_IRQ( ppt_fdc_irqs.by_field.fdc_irq )
2169 	);
2170     local_config[FLOPPY_0].drq =
2171 	SMC37c669_xlate_drq(
2172 	    SMC37c669_DEVICE_DRQ( ppt_fdc_drqs.by_field.fdc_drq )
2173 	);
2174 /*
2175 ** Get IDE controller base address
2176 */
2177     ide_base.as_uchar =
2178 	SMC37c669_read_config( SMC37c669_IDE_BASE_ADDRESS_INDEX );
2179 /*
2180 ** Get IDE alternate status base address
2181 */
2182     ide_alt.as_uchar =
2183 	SMC37c669_read_config( SMC37c669_IDE_ALTERNATE_ADDRESS_INDEX );
2184 /*
2185 ** Store local configuration information for IDE controller
2186 */
2187     local_config[IDE_0].port1 = ide_base.by_field.addr9_4 << 4;
2188     local_config[IDE_0].port2 = ide_alt.by_field.addr9_4 << 4;
2189     local_config[IDE_0].irq = 14;
2190 }
2191 
2192 
2193 /*
2194 **++
2195 **  FUNCTIONAL DESCRIPTION:
2196 **
2197 **      This function returns a pointer to the local shadow
2198 **	configuration of the requested device function.
2199 **
2200 **  FORMAL PARAMETERS:
2201 **
2202 **      func:
2203 **          Which device function
2204 **
2205 **  RETURN VALUE:
2206 **
2207 **      Returns a pointer to the DEVICE_CONFIG structure for the
2208 **	requested function, otherwise, NULL.
2209 **
2210 **  SIDE EFFECTS:
2211 **
2212 **      {@description or none@}
2213 **
2214 **--
2215 */
2216 static struct DEVICE_CONFIG * __init SMC37c669_get_config( unsigned int func )
2217 {
2218     struct DEVICE_CONFIG *cp = NULL;
2219 
2220     switch ( func ) {
2221     	case SERIAL_0:
2222 	    cp = &local_config[ SERIAL_0 ];
2223 	    break;
2224 	case SERIAL_1:
2225 	    cp = &local_config[ SERIAL_1 ];
2226 	    break;
2227 	case PARALLEL_0:
2228 	    cp = &local_config[ PARALLEL_0 ];
2229 	    break;
2230 	case FLOPPY_0:
2231 	    cp = &local_config[ FLOPPY_0 ];
2232 	    break;
2233 	case IDE_0:
2234 	    cp = &local_config[ IDE_0 ];
2235 	    break;
2236     }
2237     return cp;
2238 }
2239 
2240 /*
2241 **++
2242 **  FUNCTIONAL DESCRIPTION:
2243 **
2244 **      This function translates IRQs back and forth between ISA
2245 **	IRQs and SMC37c669 device IRQs.
2246 **
2247 **  FORMAL PARAMETERS:
2248 **
2249 **      irq:
2250 **          The IRQ to translate
2251 **
2252 **  RETURN VALUE:
2253 **
2254 **      Returns the translated IRQ, otherwise, returns -1.
2255 **
2256 **  SIDE EFFECTS:
2257 **
2258 **      {@description or none@}
2259 **
2260 **--
2261 */
2262 static int __init SMC37c669_xlate_irq ( int irq )
2263 {
2264     int i, translated_irq = -1;
2265 
2266     if ( SMC37c669_IS_DEVICE_IRQ( irq ) ) {
2267 /*
2268 ** We are translating a device IRQ to an ISA IRQ
2269 */
2270     	for ( i = 0; ( SMC37c669_irq_table[i].device_irq != -1 ) || ( SMC37c669_irq_table[i].isa_irq != -1 ); i++ ) {
2271 	    if ( irq == SMC37c669_irq_table[i].device_irq ) {
2272 	    	translated_irq = SMC37c669_irq_table[i].isa_irq;
2273 		break;
2274 	    }
2275 	}
2276     }
2277     else {
2278 /*
2279 ** We are translating an ISA IRQ to a device IRQ
2280 */
2281     	for ( i = 0; ( SMC37c669_irq_table[i].isa_irq != -1 ) || ( SMC37c669_irq_table[i].device_irq != -1 ); i++ ) {
2282 	    if ( irq == SMC37c669_irq_table[i].isa_irq ) {
2283 	    	translated_irq = SMC37c669_irq_table[i].device_irq;
2284 		break;
2285 	    }
2286 	}
2287     }
2288     return translated_irq;
2289 }
2290 
2291 
2292 /*
2293 **++
2294 **  FUNCTIONAL DESCRIPTION:
2295 **
2296 **      This function translates DMA channels back and forth between
2297 **	ISA DMA channels and SMC37c669 device DMA channels.
2298 **
2299 **  FORMAL PARAMETERS:
2300 **
2301 **      drq:
2302 **          The DMA channel to translate
2303 **
2304 **  RETURN VALUE:
2305 **
2306 **      Returns the translated DMA channel, otherwise, returns -1
2307 **
2308 **  SIDE EFFECTS:
2309 **
2310 **      {@description or none@}
2311 **
2312 **--
2313 */
2314 static int __init SMC37c669_xlate_drq ( int drq )
2315 {
2316     int i, translated_drq = -1;
2317 
2318     if ( SMC37c669_IS_DEVICE_DRQ( drq ) ) {
2319 /*
2320 ** We are translating a device DMA channel to an ISA DMA channel
2321 */
2322     	for ( i = 0; ( SMC37c669_drq_table[i].device_drq != -1 ) || ( SMC37c669_drq_table[i].isa_drq != -1 ); i++ ) {
2323 	    if ( drq == SMC37c669_drq_table[i].device_drq ) {
2324 	    	translated_drq = SMC37c669_drq_table[i].isa_drq;
2325 		break;
2326 	    }
2327 	}
2328     }
2329     else {
2330 /*
2331 ** We are translating an ISA DMA channel to a device DMA channel
2332 */
2333     	for ( i = 0; ( SMC37c669_drq_table[i].isa_drq != -1 ) || ( SMC37c669_drq_table[i].device_drq != -1 ); i++ ) {
2334 	    if ( drq == SMC37c669_drq_table[i].isa_drq ) {
2335 	    	translated_drq = SMC37c669_drq_table[i].device_drq;
2336 		break;
2337 	    }
2338 	}
2339     }
2340     return translated_drq;
2341 }
2342 
2343 #if 0
2344 int __init smcc669_init ( void )
2345 {
2346     struct INODE *ip;
2347 
2348     allocinode( smc_ddb.name, 1, &ip );
2349     ip->dva = &smc_ddb;
2350     ip->attr = ATTR$M_WRITE | ATTR$M_READ;
2351     ip->len[0] = 0x30;
2352     ip->misc = 0;
2353     INODE_UNLOCK( ip );
2354 
2355     return msg_success;
2356 }
2357 
2358 int __init smcc669_open( struct FILE *fp, char *info, char *next, char *mode )
2359 {
2360     struct INODE *ip;
2361 /*
2362 ** Allow multiple readers but only one writer.  ip->misc keeps track
2363 ** of the number of writers
2364 */
2365     ip = fp->ip;
2366     INODE_LOCK( ip );
2367     if ( fp->mode & ATTR$M_WRITE ) {
2368 	if ( ip->misc ) {
2369 	    INODE_UNLOCK( ip );
2370 	    return msg_failure;	    /* too many writers */
2371 	}
2372 	ip->misc++;
2373     }
2374 /*
2375 ** Treat the information field as a byte offset
2376 */
2377     *fp->offset = xtoi( info );
2378     INODE_UNLOCK( ip );
2379 
2380     return msg_success;
2381 }
2382 
2383 int __init smcc669_close( struct FILE *fp )
2384 {
2385     struct INODE *ip;
2386 
2387     ip = fp->ip;
2388     if ( fp->mode & ATTR$M_WRITE ) {
2389 	INODE_LOCK( ip );
2390 	ip->misc--;
2391 	INODE_UNLOCK( ip );
2392     }
2393     return msg_success;
2394 }
2395 
2396 int __init smcc669_read( struct FILE *fp, int size, int number, unsigned char *buf )
2397 {
2398     int i;
2399     int length;
2400     int nbytes;
2401     struct INODE *ip;
2402 
2403 /*
2404 ** Always access a byte at a time
2405 */
2406     ip = fp->ip;
2407     length = size * number;
2408     nbytes = 0;
2409 
2410     SMC37c669_config_mode( TRUE );
2411     for ( i = 0; i < length; i++ ) {
2412 	if ( !inrange( *fp->offset, 0, ip->len[0] ) )
2413 	    break;
2414 	*buf++ = SMC37c669_read_config( *fp->offset );
2415 	*fp->offset += 1;
2416 	nbytes++;
2417     }
2418     SMC37c669_config_mode( FALSE );
2419     return nbytes;
2420 }
2421 
2422 int __init smcc669_write( struct FILE *fp, int size, int number, unsigned char *buf )
2423 {
2424     int i;
2425     int length;
2426     int nbytes;
2427     struct INODE *ip;
2428 /*
2429 ** Always access a byte at a time
2430 */
2431     ip = fp->ip;
2432     length = size * number;
2433     nbytes = 0;
2434 
2435     SMC37c669_config_mode( TRUE );
2436     for ( i = 0; i < length; i++ ) {
2437 	if ( !inrange( *fp->offset, 0, ip->len[0] ) )
2438 	    break;
2439 	SMC37c669_write_config( *fp->offset, *buf );
2440 	*fp->offset += 1;
2441 	buf++;
2442 	nbytes++;
2443     }
2444     SMC37c669_config_mode( FALSE );
2445     return nbytes;
2446 }
2447 #endif
2448 
2449 void __init
2450 SMC37c669_dump_registers(void)
2451 {
2452   int i;
2453   for (i = 0; i <= 0x29; i++)
2454     printk("-- CR%02x : %02x\n", i, SMC37c669_read_config(i));
2455 }
2456 /*+
2457  * ============================================================================
2458  * = SMC_init - SMC37c669 Super I/O controller initialization                 =
2459  * ============================================================================
2460  *
2461  * OVERVIEW:
2462  *
2463  *      This routine configures and enables device functions on the
2464  *      SMC37c669 Super I/O controller.
2465  *
2466  * FORM OF CALL:
2467  *
2468  *      SMC_init( );
2469  *
2470  * RETURNS:
2471  *
2472  *      Nothing
2473  *
2474  * ARGUMENTS:
2475  *
2476  *      None
2477  *
2478  * SIDE EFFECTS:
2479  *
2480  *      None
2481  *
2482  */
2483 void __init SMC669_Init ( int index )
2484 {
2485     SMC37c669_CONFIG_REGS *SMC_base;
2486     unsigned long flags;
2487 
2488     local_irq_save(flags);
2489     if ( ( SMC_base = SMC37c669_detect( index ) ) != NULL ) {
2490 #if SMC_DEBUG
2491 	SMC37c669_config_mode( TRUE );
2492 	SMC37c669_dump_registers( );
2493 	SMC37c669_config_mode( FALSE );
2494         SMC37c669_display_device_info( );
2495 #endif
2496         SMC37c669_disable_device( SERIAL_0 );
2497         SMC37c669_configure_device(
2498             SERIAL_0,
2499             COM1_BASE,
2500             COM1_IRQ,
2501             -1
2502         );
2503         SMC37c669_enable_device( SERIAL_0 );
2504 
2505         SMC37c669_disable_device( SERIAL_1 );
2506         SMC37c669_configure_device(
2507             SERIAL_1,
2508             COM2_BASE,
2509             COM2_IRQ,
2510             -1
2511         );
2512         SMC37c669_enable_device( SERIAL_1 );
2513 
2514         SMC37c669_disable_device( PARALLEL_0 );
2515         SMC37c669_configure_device(
2516             PARALLEL_0,
2517             PARP_BASE,
2518             PARP_IRQ,
2519             PARP_DRQ
2520         );
2521         SMC37c669_enable_device( PARALLEL_0 );
2522 
2523         SMC37c669_disable_device( FLOPPY_0 );
2524         SMC37c669_configure_device(
2525             FLOPPY_0,
2526             FDC_BASE,
2527             FDC_IRQ,
2528             FDC_DRQ
2529         );
2530         SMC37c669_enable_device( FLOPPY_0 );
2531 
2532 	/* Wake up sometimes forgotten floppy, especially on DP264. */
2533 	outb(0xc, 0x3f2);
2534 
2535         SMC37c669_disable_device( IDE_0 );
2536 
2537 #if SMC_DEBUG
2538 	SMC37c669_config_mode( TRUE );
2539 	SMC37c669_dump_registers( );
2540 	SMC37c669_config_mode( FALSE );
2541         SMC37c669_display_device_info( );
2542 #endif
2543 	local_irq_restore(flags);
2544         printk( "SMC37c669 Super I/O Controller found @ 0x%p\n",
2545 		SMC_base );
2546     }
2547     else {
2548 	local_irq_restore(flags);
2549 #if SMC_DEBUG
2550         printk( "No SMC37c669 Super I/O Controller found\n" );
2551 #endif
2552     }
2553 }
2554