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