linux/arch/alpha/kernel/smc37c93x.c
<<
>>
Prefs
   1/*
   2 * SMC 37C93X initialization code
   3 */
   4
   5#include <linux/kernel.h>
   6
   7#include <linux/mm.h>
   8#include <linux/init.h>
   9#include <linux/delay.h>
  10
  11#include <asm/hwrpb.h>
  12#include <asm/io.h>
  13#include <asm/segment.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
  79static 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
 111static void __init SMCRunState(unsigned long baseAddr)
 112{
 113        outb(CONFIG_OFF_KEY, baseAddr);
 114}
 115
 116static 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
 131static 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
 158static 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
 179static 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
 209static 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
 238int __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