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