1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * SMC 37C93X initialization code
41da177e4SLinus Torvalds */
51da177e4SLinus Torvalds
61da177e4SLinus Torvalds #include <linux/kernel.h>
71da177e4SLinus Torvalds
81da177e4SLinus Torvalds #include <linux/mm.h>
91da177e4SLinus Torvalds #include <linux/init.h>
101da177e4SLinus Torvalds #include <linux/delay.h>
111da177e4SLinus Torvalds
121da177e4SLinus Torvalds #include <asm/hwrpb.h>
131da177e4SLinus Torvalds #include <asm/io.h>
141da177e4SLinus Torvalds
151da177e4SLinus Torvalds #define SMC_DEBUG 0
161da177e4SLinus Torvalds
171da177e4SLinus Torvalds #if SMC_DEBUG
181da177e4SLinus Torvalds # define DBG_DEVS(args) printk args
191da177e4SLinus Torvalds #else
201da177e4SLinus Torvalds # define DBG_DEVS(args)
211da177e4SLinus Torvalds #endif
221da177e4SLinus Torvalds
231da177e4SLinus Torvalds #define KB 1024
241da177e4SLinus Torvalds #define MB (1024*KB)
251da177e4SLinus Torvalds #define GB (1024*MB)
261da177e4SLinus Torvalds
271da177e4SLinus Torvalds /* device "activate" register contents */
281da177e4SLinus Torvalds #define DEVICE_ON 1
291da177e4SLinus Torvalds #define DEVICE_OFF 0
301da177e4SLinus Torvalds
311da177e4SLinus Torvalds /* configuration on/off keys */
321da177e4SLinus Torvalds #define CONFIG_ON_KEY 0x55
331da177e4SLinus Torvalds #define CONFIG_OFF_KEY 0xaa
341da177e4SLinus Torvalds
351da177e4SLinus Torvalds /* configuration space device definitions */
361da177e4SLinus Torvalds #define FDC 0
371da177e4SLinus Torvalds #define IDE1 1
381da177e4SLinus Torvalds #define IDE2 2
391da177e4SLinus Torvalds #define PARP 3
401da177e4SLinus Torvalds #define SER1 4
411da177e4SLinus Torvalds #define SER2 5
421da177e4SLinus Torvalds #define RTCL 6
431da177e4SLinus Torvalds #define KYBD 7
441da177e4SLinus Torvalds #define AUXIO 8
451da177e4SLinus Torvalds
461da177e4SLinus Torvalds /* Chip register offsets from base */
471da177e4SLinus Torvalds #define CONFIG_CONTROL 0x02
481da177e4SLinus Torvalds #define INDEX_ADDRESS 0x03
491da177e4SLinus Torvalds #define LOGICAL_DEVICE_NUMBER 0x07
501da177e4SLinus Torvalds #define DEVICE_ID 0x20
511da177e4SLinus Torvalds #define DEVICE_REV 0x21
521da177e4SLinus Torvalds #define POWER_CONTROL 0x22
531da177e4SLinus Torvalds #define POWER_MGMT 0x23
541da177e4SLinus Torvalds #define OSC 0x24
551da177e4SLinus Torvalds
561da177e4SLinus Torvalds #define ACTIVATE 0x30
571da177e4SLinus Torvalds #define ADDR_HI 0x60
581da177e4SLinus Torvalds #define ADDR_LO 0x61
591da177e4SLinus Torvalds #define INTERRUPT_SEL 0x70
601da177e4SLinus Torvalds #define INTERRUPT_SEL_2 0x72 /* KYBD/MOUS only */
611da177e4SLinus Torvalds #define DMA_CHANNEL_SEL 0x74 /* FDC/PARP only */
621da177e4SLinus Torvalds
631da177e4SLinus Torvalds #define FDD_MODE_REGISTER 0x90
641da177e4SLinus Torvalds #define FDD_OPTION_REGISTER 0x91
651da177e4SLinus Torvalds
661da177e4SLinus Torvalds /* values that we read back that are expected ... */
671da177e4SLinus Torvalds #define VALID_DEVICE_ID 2
681da177e4SLinus Torvalds
691da177e4SLinus Torvalds /* default device addresses */
701da177e4SLinus Torvalds #define KYBD_INTERRUPT 1
711da177e4SLinus Torvalds #define MOUS_INTERRUPT 12
721da177e4SLinus Torvalds #define COM2_BASE 0x2f8
731da177e4SLinus Torvalds #define COM2_INTERRUPT 3
741da177e4SLinus Torvalds #define COM1_BASE 0x3f8
751da177e4SLinus Torvalds #define COM1_INTERRUPT 4
761da177e4SLinus Torvalds #define PARP_BASE 0x3bc
771da177e4SLinus Torvalds #define PARP_INTERRUPT 7
781da177e4SLinus Torvalds
SMCConfigState(unsigned long baseAddr)791da177e4SLinus Torvalds static unsigned long __init SMCConfigState(unsigned long baseAddr)
801da177e4SLinus Torvalds {
811da177e4SLinus Torvalds unsigned char devId;
821da177e4SLinus Torvalds
831da177e4SLinus Torvalds unsigned long configPort;
841da177e4SLinus Torvalds unsigned long indexPort;
851da177e4SLinus Torvalds unsigned long dataPort;
861da177e4SLinus Torvalds
871da177e4SLinus Torvalds int i;
881da177e4SLinus Torvalds
891da177e4SLinus Torvalds configPort = indexPort = baseAddr;
901da177e4SLinus Torvalds dataPort = configPort + 1;
911da177e4SLinus Torvalds
921da177e4SLinus Torvalds #define NUM_RETRIES 5
931da177e4SLinus Torvalds
941da177e4SLinus Torvalds for (i = 0; i < NUM_RETRIES; i++)
951da177e4SLinus Torvalds {
961da177e4SLinus Torvalds outb(CONFIG_ON_KEY, configPort);
971da177e4SLinus Torvalds outb(CONFIG_ON_KEY, configPort);
981da177e4SLinus Torvalds outb(DEVICE_ID, indexPort);
991da177e4SLinus Torvalds devId = inb(dataPort);
1001da177e4SLinus Torvalds if (devId == VALID_DEVICE_ID) {
1011da177e4SLinus Torvalds outb(DEVICE_REV, indexPort);
102280da4e4SRichard Henderson /* unsigned char devRev = */ inb(dataPort);
1031da177e4SLinus Torvalds break;
1041da177e4SLinus Torvalds }
1051da177e4SLinus Torvalds else
1061da177e4SLinus Torvalds udelay(100);
1071da177e4SLinus Torvalds }
1081da177e4SLinus Torvalds return (i != NUM_RETRIES) ? baseAddr : 0L;
1091da177e4SLinus Torvalds }
1101da177e4SLinus Torvalds
SMCRunState(unsigned long baseAddr)1111da177e4SLinus Torvalds static void __init SMCRunState(unsigned long baseAddr)
1121da177e4SLinus Torvalds {
1131da177e4SLinus Torvalds outb(CONFIG_OFF_KEY, baseAddr);
1141da177e4SLinus Torvalds }
1151da177e4SLinus Torvalds
SMCDetectUltraIO(void)1161da177e4SLinus Torvalds static unsigned long __init SMCDetectUltraIO(void)
1171da177e4SLinus Torvalds {
1181da177e4SLinus Torvalds unsigned long baseAddr;
1191da177e4SLinus Torvalds
1201da177e4SLinus Torvalds baseAddr = 0x3F0;
1211da177e4SLinus Torvalds if ( ( baseAddr = SMCConfigState( baseAddr ) ) == 0x3F0 ) {
1221da177e4SLinus Torvalds return( baseAddr );
1231da177e4SLinus Torvalds }
1241da177e4SLinus Torvalds baseAddr = 0x370;
1251da177e4SLinus Torvalds if ( ( baseAddr = SMCConfigState( baseAddr ) ) == 0x370 ) {
1261da177e4SLinus Torvalds return( baseAddr );
1271da177e4SLinus Torvalds }
1281da177e4SLinus Torvalds return( ( unsigned long )0 );
1291da177e4SLinus Torvalds }
1301da177e4SLinus Torvalds
SMCEnableDevice(unsigned long baseAddr,unsigned long device,unsigned long portaddr,unsigned long interrupt)1311da177e4SLinus Torvalds static void __init SMCEnableDevice(unsigned long baseAddr,
1321da177e4SLinus Torvalds unsigned long device,
1331da177e4SLinus Torvalds unsigned long portaddr,
1341da177e4SLinus Torvalds unsigned long interrupt)
1351da177e4SLinus Torvalds {
1361da177e4SLinus Torvalds unsigned long indexPort;
1371da177e4SLinus Torvalds unsigned long dataPort;
1381da177e4SLinus Torvalds
1391da177e4SLinus Torvalds indexPort = baseAddr;
1401da177e4SLinus Torvalds dataPort = baseAddr + 1;
1411da177e4SLinus Torvalds
1421da177e4SLinus Torvalds outb(LOGICAL_DEVICE_NUMBER, indexPort);
1431da177e4SLinus Torvalds outb(device, dataPort);
1441da177e4SLinus Torvalds
1451da177e4SLinus Torvalds outb(ADDR_LO, indexPort);
1461da177e4SLinus Torvalds outb(( portaddr & 0xFF ), dataPort);
1471da177e4SLinus Torvalds
1481da177e4SLinus Torvalds outb(ADDR_HI, indexPort);
1491da177e4SLinus Torvalds outb((portaddr >> 8) & 0xFF, dataPort);
1501da177e4SLinus Torvalds
1511da177e4SLinus Torvalds outb(INTERRUPT_SEL, indexPort);
1521da177e4SLinus Torvalds outb(interrupt, dataPort);
1531da177e4SLinus Torvalds
1541da177e4SLinus Torvalds outb(ACTIVATE, indexPort);
1551da177e4SLinus Torvalds outb(DEVICE_ON, dataPort);
1561da177e4SLinus Torvalds }
1571da177e4SLinus Torvalds
SMCEnableKYBD(unsigned long baseAddr)1581da177e4SLinus Torvalds static void __init SMCEnableKYBD(unsigned long baseAddr)
1591da177e4SLinus Torvalds {
1601da177e4SLinus Torvalds unsigned long indexPort;
1611da177e4SLinus Torvalds unsigned long dataPort;
1621da177e4SLinus Torvalds
1631da177e4SLinus Torvalds indexPort = baseAddr;
1641da177e4SLinus Torvalds dataPort = baseAddr + 1;
1651da177e4SLinus Torvalds
1661da177e4SLinus Torvalds outb(LOGICAL_DEVICE_NUMBER, indexPort);
1671da177e4SLinus Torvalds outb(KYBD, dataPort);
1681da177e4SLinus Torvalds
1691da177e4SLinus Torvalds outb(INTERRUPT_SEL, indexPort); /* Primary interrupt select */
1701da177e4SLinus Torvalds outb(KYBD_INTERRUPT, dataPort);
1711da177e4SLinus Torvalds
1721da177e4SLinus Torvalds outb(INTERRUPT_SEL_2, indexPort); /* Secondary interrupt select */
1731da177e4SLinus Torvalds outb(MOUS_INTERRUPT, dataPort);
1741da177e4SLinus Torvalds
1751da177e4SLinus Torvalds outb(ACTIVATE, indexPort);
1761da177e4SLinus Torvalds outb(DEVICE_ON, dataPort);
1771da177e4SLinus Torvalds }
1781da177e4SLinus Torvalds
SMCEnableFDC(unsigned long baseAddr)1791da177e4SLinus Torvalds static void __init SMCEnableFDC(unsigned long baseAddr)
1801da177e4SLinus Torvalds {
1811da177e4SLinus Torvalds unsigned long indexPort;
1821da177e4SLinus Torvalds unsigned long dataPort;
1831da177e4SLinus Torvalds
1841da177e4SLinus Torvalds unsigned char oldValue;
1851da177e4SLinus Torvalds
1861da177e4SLinus Torvalds indexPort = baseAddr;
1871da177e4SLinus Torvalds dataPort = baseAddr + 1;
1881da177e4SLinus Torvalds
1891da177e4SLinus Torvalds outb(LOGICAL_DEVICE_NUMBER, indexPort);
1901da177e4SLinus Torvalds outb(FDC, dataPort);
1911da177e4SLinus Torvalds
1921da177e4SLinus Torvalds outb(FDD_MODE_REGISTER, indexPort);
1931da177e4SLinus Torvalds oldValue = inb(dataPort);
1941da177e4SLinus Torvalds
1951da177e4SLinus Torvalds oldValue |= 0x0E; /* Enable burst mode */
1961da177e4SLinus Torvalds outb(oldValue, dataPort);
1971da177e4SLinus Torvalds
1981da177e4SLinus Torvalds outb(INTERRUPT_SEL, indexPort); /* Primary interrupt select */
1991da177e4SLinus Torvalds outb(0x06, dataPort );
2001da177e4SLinus Torvalds
2011da177e4SLinus Torvalds outb(DMA_CHANNEL_SEL, indexPort); /* DMA channel select */
2021da177e4SLinus Torvalds outb(0x02, dataPort);
2031da177e4SLinus Torvalds
2041da177e4SLinus Torvalds outb(ACTIVATE, indexPort);
2051da177e4SLinus Torvalds outb(DEVICE_ON, dataPort);
2061da177e4SLinus Torvalds }
2071da177e4SLinus Torvalds
2081da177e4SLinus Torvalds #if SMC_DEBUG
SMCReportDeviceStatus(unsigned long baseAddr)2091da177e4SLinus Torvalds static void __init SMCReportDeviceStatus(unsigned long baseAddr)
2101da177e4SLinus Torvalds {
2111da177e4SLinus Torvalds unsigned long indexPort;
2121da177e4SLinus Torvalds unsigned long dataPort;
2131da177e4SLinus Torvalds unsigned char currentControl;
2141da177e4SLinus Torvalds
2151da177e4SLinus Torvalds indexPort = baseAddr;
2161da177e4SLinus Torvalds dataPort = baseAddr + 1;
2171da177e4SLinus Torvalds
2181da177e4SLinus Torvalds outb(POWER_CONTROL, indexPort);
2191da177e4SLinus Torvalds currentControl = inb(dataPort);
2201da177e4SLinus Torvalds
2211da177e4SLinus Torvalds printk(currentControl & (1 << FDC)
2221da177e4SLinus Torvalds ? "\t+FDC Enabled\n" : "\t-FDC Disabled\n");
2231da177e4SLinus Torvalds printk(currentControl & (1 << IDE1)
2241da177e4SLinus Torvalds ? "\t+IDE1 Enabled\n" : "\t-IDE1 Disabled\n");
2251da177e4SLinus Torvalds printk(currentControl & (1 << IDE2)
2261da177e4SLinus Torvalds ? "\t+IDE2 Enabled\n" : "\t-IDE2 Disabled\n");
2271da177e4SLinus Torvalds printk(currentControl & (1 << PARP)
2281da177e4SLinus Torvalds ? "\t+PARP Enabled\n" : "\t-PARP Disabled\n");
2291da177e4SLinus Torvalds printk(currentControl & (1 << SER1)
2301da177e4SLinus Torvalds ? "\t+SER1 Enabled\n" : "\t-SER1 Disabled\n");
2311da177e4SLinus Torvalds printk(currentControl & (1 << SER2)
2321da177e4SLinus Torvalds ? "\t+SER2 Enabled\n" : "\t-SER2 Disabled\n");
2331da177e4SLinus Torvalds
2341da177e4SLinus Torvalds printk( "\n" );
2351da177e4SLinus Torvalds }
2361da177e4SLinus Torvalds #endif
2371da177e4SLinus Torvalds
SMC93x_Init(void)2381da177e4SLinus Torvalds int __init SMC93x_Init(void)
2391da177e4SLinus Torvalds {
2401da177e4SLinus Torvalds unsigned long SMCUltraBase;
2411da177e4SLinus Torvalds unsigned long flags;
2421da177e4SLinus Torvalds
2431da177e4SLinus Torvalds local_irq_save(flags);
2441da177e4SLinus Torvalds if ((SMCUltraBase = SMCDetectUltraIO()) != 0UL) {
2451da177e4SLinus Torvalds #if SMC_DEBUG
2461da177e4SLinus Torvalds SMCReportDeviceStatus(SMCUltraBase);
2471da177e4SLinus Torvalds #endif
2481da177e4SLinus Torvalds SMCEnableDevice(SMCUltraBase, SER1, COM1_BASE, COM1_INTERRUPT);
2491da177e4SLinus Torvalds DBG_DEVS(("SMC FDC37C93X: SER1 done\n"));
2501da177e4SLinus Torvalds SMCEnableDevice(SMCUltraBase, SER2, COM2_BASE, COM2_INTERRUPT);
2511da177e4SLinus Torvalds DBG_DEVS(("SMC FDC37C93X: SER2 done\n"));
2521da177e4SLinus Torvalds SMCEnableDevice(SMCUltraBase, PARP, PARP_BASE, PARP_INTERRUPT);
2531da177e4SLinus Torvalds DBG_DEVS(("SMC FDC37C93X: PARP done\n"));
2541da177e4SLinus Torvalds /* On PC164, IDE on the SMC is not enabled;
2551da177e4SLinus Torvalds CMD646 (PCI) on MB */
2561da177e4SLinus Torvalds SMCEnableKYBD(SMCUltraBase);
2571da177e4SLinus Torvalds DBG_DEVS(("SMC FDC37C93X: KYB done\n"));
2581da177e4SLinus Torvalds SMCEnableFDC(SMCUltraBase);
2591da177e4SLinus Torvalds DBG_DEVS(("SMC FDC37C93X: FDC done\n"));
2601da177e4SLinus Torvalds #if SMC_DEBUG
2611da177e4SLinus Torvalds SMCReportDeviceStatus(SMCUltraBase);
2621da177e4SLinus Torvalds #endif
2631da177e4SLinus Torvalds SMCRunState(SMCUltraBase);
2641da177e4SLinus Torvalds local_irq_restore(flags);
2651da177e4SLinus Torvalds printk("SMC FDC37C93X Ultra I/O Controller found @ 0x%lx\n",
2661da177e4SLinus Torvalds SMCUltraBase);
2671da177e4SLinus Torvalds return 1;
2681da177e4SLinus Torvalds }
2691da177e4SLinus Torvalds else {
2701da177e4SLinus Torvalds local_irq_restore(flags);
2711da177e4SLinus Torvalds DBG_DEVS(("No SMC FDC37C93X Ultra I/O Controller found\n"));
2721da177e4SLinus Torvalds return 0;
2731da177e4SLinus Torvalds }
2741da177e4SLinus Torvalds }
275