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 local_irq_save(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 local_irq_restore(flags); 268 printk("SMC FDC37C93X Ultra I/O Controller found @ 0x%lx\n", 269 SMCUltraBase); 270 return 1; 271 } 272 else { 273 local_irq_restore(flags); 274 DBG_DEVS(("No SMC FDC37C93X Ultra I/O Controller found\n")); 275 return 0; 276 } 277 } 278