File: /usr/src/linux/arch/alpha/kernel/smc37c93x.c

1     /*
2      * SMC 37C93X initialization code
3      */
4     
5     #include <linux/config.h>
6     #include <linux/kernel.h>
7     
8     #include <linux/slab.h>
9     #include <linux/mm.h>
10     #include <linux/init.h>
11     #include <linux/delay.h>
12     
13     #include <asm/hwrpb.h>
14     #include <asm/io.h>
15     #include <asm/segment.h>
16     
17     #define SMC_DEBUG 0
18     
19     #if SMC_DEBUG
20     # define DBG_DEVS(args)         printk args
21     #else
22     # define DBG_DEVS(args)
23     #endif
24     
25     #define KB              1024
26     #define MB              (1024*KB)
27     #define GB              (1024*MB)
28     
29     /* device "activate" register contents */
30     #define DEVICE_ON		1
31     #define DEVICE_OFF		0
32     
33     /* configuration on/off keys */
34     #define CONFIG_ON_KEY		0x55
35     #define CONFIG_OFF_KEY		0xaa
36     
37     /* configuration space device definitions */
38     #define FDC			0
39     #define IDE1			1
40     #define IDE2			2
41     #define PARP			3
42     #define SER1			4
43     #define SER2			5
44     #define RTCL			6
45     #define KYBD			7
46     #define AUXIO			8
47     
48     /* Chip register offsets from base */
49     #define CONFIG_CONTROL		0x02
50     #define INDEX_ADDRESS		0x03
51     #define LOGICAL_DEVICE_NUMBER	0x07
52     #define DEVICE_ID		0x20
53     #define DEVICE_REV		0x21
54     #define POWER_CONTROL		0x22
55     #define POWER_MGMT		0x23
56     #define OSC			0x24
57     
58     #define ACTIVATE		0x30
59     #define ADDR_HI			0x60
60     #define ADDR_LO			0x61
61     #define INTERRUPT_SEL		0x70
62     #define INTERRUPT_SEL_2		0x72 /* KYBD/MOUS only */
63     #define DMA_CHANNEL_SEL		0x74 /* FDC/PARP only */
64     
65     #define FDD_MODE_REGISTER	0x90
66     #define FDD_OPTION_REGISTER	0x91
67     
68     /* values that we read back that are expected ... */
69     #define VALID_DEVICE_ID		2
70     
71     /* default device addresses */
72     #define KYBD_INTERRUPT		1
73     #define MOUS_INTERRUPT		12
74     #define COM2_BASE		0x2f8
75     #define COM2_INTERRUPT		3
76     #define COM1_BASE		0x3f8
77     #define COM1_INTERRUPT		4
78     #define PARP_BASE		0x3bc
79     #define PARP_INTERRUPT		7
80     
81     static unsigned long __init SMCConfigState(unsigned long baseAddr)
82     {
83     	unsigned char devId;
84     	unsigned char devRev;
85     
86     	unsigned long configPort;
87     	unsigned long indexPort;
88     	unsigned long dataPort;
89     
90     	int i;
91     
92     	configPort = indexPort = baseAddr;
93     	dataPort = configPort + 1;
94     
95     #define NUM_RETRIES 5
96     
97     	for (i = 0; i < NUM_RETRIES; i++)
98     	{
99     		outb(CONFIG_ON_KEY, configPort);
100     		outb(CONFIG_ON_KEY, configPort);
101     		outb(DEVICE_ID, indexPort);
102     		devId = inb(dataPort);
103     		if (devId == VALID_DEVICE_ID) {
104     			outb(DEVICE_REV, indexPort);
105     			devRev = inb(dataPort);
106     			break;
107     		}
108     		else
109     			udelay(100);
110     	}
111     	return (i != NUM_RETRIES) ? baseAddr : 0L;
112     }
113     
114     static void __init SMCRunState(unsigned long baseAddr)
115     {
116     	outb(CONFIG_OFF_KEY, baseAddr);
117     }
118     
119     static unsigned long __init SMCDetectUltraIO(void)
120     {
121     	unsigned long baseAddr;
122     
123     	baseAddr = 0x3F0;
124     	if ( ( baseAddr = SMCConfigState( baseAddr ) ) == 0x3F0 ) {
125     		return( baseAddr );
126     	}
127     	baseAddr = 0x370;
128     	if ( ( baseAddr = SMCConfigState( baseAddr ) ) == 0x370 ) {
129     		return( baseAddr );
130     	}
131     	return( ( unsigned long )0 );
132     }
133     
134     static void __init SMCEnableDevice(unsigned long baseAddr,
135     			    unsigned long device,
136     			    unsigned long portaddr,
137     			    unsigned long interrupt)
138     {
139     	unsigned long indexPort;
140     	unsigned long dataPort;
141     
142     	indexPort = baseAddr;
143     	dataPort = baseAddr + 1;
144     
145     	outb(LOGICAL_DEVICE_NUMBER, indexPort);
146     	outb(device, dataPort);
147     
148     	outb(ADDR_LO, indexPort);
149     	outb(( portaddr & 0xFF ), dataPort);
150     
151     	outb(ADDR_HI, indexPort);
152     	outb((portaddr >> 8) & 0xFF, dataPort);
153     
154     	outb(INTERRUPT_SEL, indexPort);
155     	outb(interrupt, dataPort);
156     
157     	outb(ACTIVATE, indexPort);
158     	outb(DEVICE_ON, dataPort);
159     }
160     
161     static void __init SMCEnableKYBD(unsigned long baseAddr)
162     {
163     	unsigned long indexPort;
164     	unsigned long dataPort;
165     
166     	indexPort = baseAddr;
167     	dataPort = baseAddr + 1;
168     
169     	outb(LOGICAL_DEVICE_NUMBER, indexPort);
170     	outb(KYBD, dataPort);
171     
172     	outb(INTERRUPT_SEL, indexPort); /* Primary interrupt select */
173     	outb(KYBD_INTERRUPT, dataPort);
174     
175     	outb(INTERRUPT_SEL_2, indexPort); /* Secondary interrupt select */
176     	outb(MOUS_INTERRUPT, dataPort);
177     
178     	outb(ACTIVATE, indexPort);
179     	outb(DEVICE_ON, dataPort);
180     }
181     
182     static void __init SMCEnableFDC(unsigned long baseAddr)
183     {
184     	unsigned long indexPort;
185     	unsigned long dataPort;
186     
187     	unsigned char oldValue;
188     
189     	indexPort = baseAddr;
190     	dataPort = baseAddr + 1;
191     
192     	outb(LOGICAL_DEVICE_NUMBER, indexPort);
193     	outb(FDC, dataPort);
194     
195     	outb(FDD_MODE_REGISTER, indexPort);
196     	oldValue = inb(dataPort);
197     
198     	oldValue |= 0x0E;                   /* Enable burst mode */
199     	outb(oldValue, dataPort);
200     
201     	outb(INTERRUPT_SEL, indexPort);	    /* Primary interrupt select */
202     	outb(0x06, dataPort );
203     
204     	outb(DMA_CHANNEL_SEL, indexPort);   /* DMA channel select */
205     	outb(0x02, dataPort);
206     
207     	outb(ACTIVATE, indexPort);
208     	outb(DEVICE_ON, dataPort);
209     }
210     
211     #if SMC_DEBUG
212     static void __init SMCReportDeviceStatus(unsigned long baseAddr)
213     {
214     	unsigned long indexPort;
215     	unsigned long dataPort;
216     	unsigned char currentControl;
217     
218     	indexPort = baseAddr;
219     	dataPort = baseAddr + 1;
220     
221     	outb(POWER_CONTROL, indexPort);
222     	currentControl = inb(dataPort);
223     
224     	printk(currentControl & (1 << FDC)
225     	       ? "\t+FDC Enabled\n" : "\t-FDC Disabled\n");
226     	printk(currentControl & (1 << IDE1)
227     	       ? "\t+IDE1 Enabled\n" : "\t-IDE1 Disabled\n");
228     	printk(currentControl & (1 << IDE2)
229     	       ? "\t+IDE2 Enabled\n" : "\t-IDE2 Disabled\n");
230     	printk(currentControl & (1 << PARP)
231     	       ? "\t+PARP Enabled\n" : "\t-PARP Disabled\n");
232     	printk(currentControl & (1 << SER1)
233     	       ? "\t+SER1 Enabled\n" : "\t-SER1 Disabled\n");
234     	printk(currentControl & (1 << SER2)
235     	       ? "\t+SER2 Enabled\n" : "\t-SER2 Disabled\n");
236     
237     	printk( "\n" );
238     }
239     #endif
240     
241     int __init SMC93x_Init(void)
242     {
243     	unsigned long SMCUltraBase;
244     	unsigned long flags;
245     
246     	__save_and_cli(flags);
247     	if ((SMCUltraBase = SMCDetectUltraIO()) != 0UL) {
248     #if SMC_DEBUG
249     		SMCReportDeviceStatus(SMCUltraBase);
250     #endif
251     		SMCEnableDevice(SMCUltraBase, SER1, COM1_BASE, COM1_INTERRUPT);
252     		DBG_DEVS(("SMC FDC37C93X: SER1 done\n"));
253     		SMCEnableDevice(SMCUltraBase, SER2, COM2_BASE, COM2_INTERRUPT);
254     		DBG_DEVS(("SMC FDC37C93X: SER2 done\n"));
255     		SMCEnableDevice(SMCUltraBase, PARP, PARP_BASE, PARP_INTERRUPT);
256     		DBG_DEVS(("SMC FDC37C93X: PARP done\n"));
257     		/* On PC164, IDE on the SMC is not enabled;
258     		   CMD646 (PCI) on MB */
259     		SMCEnableKYBD(SMCUltraBase);
260     		DBG_DEVS(("SMC FDC37C93X: KYB done\n"));
261     		SMCEnableFDC(SMCUltraBase);
262     		DBG_DEVS(("SMC FDC37C93X: FDC done\n"));
263     #if SMC_DEBUG
264     		SMCReportDeviceStatus(SMCUltraBase);
265     #endif
266     		SMCRunState(SMCUltraBase);
267     		__restore_flags(flags);
268     		printk("SMC FDC37C93X Ultra I/O Controller found @ 0x%lx\n",
269     		       SMCUltraBase);
270     		return 1;
271     	}
272     	else {
273     		__restore_flags(flags);
274     		DBG_DEVS(("No SMC FDC37C93X Ultra I/O Controller found\n"));
275     		return 0;
276     	}
277     }
278