superio.c revision 16541c8745e28f62b3dcb6cb354b73c9c01ea178
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* National Semiconductor NS87560UBD Super I/O controller used in 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * HP [BCJ]x000 workstations. 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This chip is a horrid piece of engineering, and National 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * denies any knowledge of its existence. Thus no datasheet is 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * available off www.national.com. 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (C) Copyright 2000 Linuxcare, Inc. 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (C) Copyright 2000 Linuxcare Canada, Inc. 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (C) Copyright 2000 Martin K. Petersen <mkp@linuxcare.com> 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (C) Copyright 2000 Alex deVries <alex@onefishtwo.ca> 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (C) Copyright 2001 John Marvin <jsm fc hp com> 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (C) Copyright 2003 Grant Grundler <grundler parisc-linux org> 147efe1611b2db9025ffc52a686897ab91820caeb4Kyle McMartin * (C) Copyright 2005 Kyle McMartin <kyle@parisc-linux.org> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * modify it under the terms of the GNU General Public License as 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * published by the Free Software Foundation; either version 2 of 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the License, or (at your option) any later version. 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The initial version of this is by Martin Peterson. Alex deVries 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * has spent a bit of time trying to coax it into working. 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Major changes to get basic interrupt infrastructure working to 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * hopefully be able to support all SuperIO devices. Currently 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * works with serial. -- John Marvin <jsm@fc.hp.com> 27a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin * 28a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin * Converted superio_init() to be a PCI_FIXUP_FINAL callee. 29a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin * -- Kyle McMartin <kyle@parisc-linux.org> 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* NOTES: 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function 0 is an IDE controller. It is identical to a PC87415 IDE 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * controller (and identifies itself as such). 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function 1 is a "Legacy I/O" controller. Under this function is a 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * whole mess of legacy I/O peripherals. Of course, HP hasn't enabled 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * all the functionality in hardware, but the following is available: 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Two 16550A compatible serial controllers 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * An IEEE 1284 compatible parallel port 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A floppy disk controller 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function 2 is a USB controller. 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We must be incredibly careful during initialization. Since all 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interrupts are routed through function 1 (which is not allowed by 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the PCI spec), we need to program the PICs on the legacy I/O port 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * *before* we attempt to set up IDE and USB. @#$!& 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * According to HP, devices are only enabled by firmware if they have 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a physical device connected. 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Configuration register bits: 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0x5A: FDC, SP1, IDE1, SP2, IDE2, PAR, Reserved, P92 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0x5B: RTC, 8259, 8254, DMA1, DMA2, KBC, P61, APM 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h> 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h> 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serial.h> 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h> 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/parport.h> 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/parport_pc.h> 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/termios.h> 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h> 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serial_core.h> 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/hardware.h> 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/superio.h> 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct superio_device sio_dev; 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef DEBUG_SUPERIO_INIT 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_SUPERIO_INIT 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBG_INIT(x...) printk(x) 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBG_INIT(x...) 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9216541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin#define SUPERIO "SuperIO" 9316541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin#define PFX SUPERIO ": " 9416541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic irqreturn_t 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssuperio_interrupt(int parent_irq, void *devp, struct pt_regs *regs) 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 results; 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 local_irq; 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Poll the 8259 to see if there's an interrupt. */ 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb (OCW3_POLL,IC_PIC1+0); 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds results = inb(IC_PIC1+0); 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Bit 7: 1 = active Interrupt; 0 = no Interrupt pending 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Bits 6-3: zero 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Bits 2-0: highest priority, active requesting interrupt ID (0-7) 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((results & 0x80) == 0) { 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* I suspect "spurious" interrupts are from unmasking an IRQ. 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We don't know if an interrupt was/is pending and thus 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * just call the handler for that IRQ as if it were pending. 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_NONE; 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check to see which device is interrupting */ 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq = results & 0x0f; 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (local_irq == 2 || local_irq > 7) { 12316541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin printk(KERN_ERR PFX "slave interrupted!\n"); 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_HANDLED; 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (local_irq == 7) { 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Could be spurious. Check in service bits */ 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(OCW3_ISR,IC_PIC1+0); 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds results = inb(IC_PIC1+0); 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((results & 0x80) == 0) { /* if ISR7 not set: spurious */ 13416541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin printk(KERN_WARNING PFX "spurious interrupt!\n"); 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_HANDLED; 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Call the appropriate device's interrupt */ 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __do_IRQ(local_irq, regs); 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* set EOI - forces a new interrupt if a lower priority device 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * still needs service. 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb((OCW2_SEOI|local_irq),IC_PIC1 + 0); 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return IRQ_HANDLED; 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Initialize Super I/O device */ 150a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartinstatic void 151a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartinsuperio_init(struct pci_dev *pcidev) 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 153a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin struct superio_device *sio = &sio_dev; 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pci_dev *pdev = sio->lio_pdev; 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 word; 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sio->suckyio_irq_enabled) 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!pdev) BUG(); 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!sio->usb_pdev) BUG(); 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* use the IRQ iosapic found for USB INT D... */ 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pdev->irq = sio->usb_pdev->irq; 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* ...then properly fixup the USB to point at suckyio PIC */ 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sio->usb_pdev->irq = superio_fixup_irq(sio->usb_pdev); 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16916541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin printk(KERN_INFO PFX "Found NS87560 Legacy I/O device at %s (IRQ %i) \n", 170a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin pci_name(pdev), pdev->irq); 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_read_config_dword (pdev, SIO_SP1BAR, &sio->sp1_base); 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sio->sp1_base &= ~1; 17416541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin printk(KERN_INFO PFX "Serial port 1 at 0x%x\n", sio->sp1_base); 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_read_config_dword (pdev, SIO_SP2BAR, &sio->sp2_base); 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sio->sp2_base &= ~1; 17816541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin printk(KERN_INFO PFX "Serial port 2 at 0x%x\n", sio->sp2_base); 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_read_config_dword (pdev, SIO_PPBAR, &sio->pp_base); 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sio->pp_base &= ~1; 18216541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin printk(KERN_INFO PFX "Parallel port at 0x%x\n", sio->pp_base); 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_read_config_dword (pdev, SIO_FDCBAR, &sio->fdc_base); 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sio->fdc_base &= ~1; 18616541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin printk(KERN_INFO PFX "Floppy controller at 0x%x\n", sio->fdc_base); 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_read_config_dword (pdev, SIO_ACPIBAR, &sio->acpi_base); 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sio->acpi_base &= ~1; 18916541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin printk(KERN_INFO PFX "ACPI at 0x%x\n", sio->acpi_base); 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds request_region (IC_PIC1, 0x1f, "pic1"); 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds request_region (IC_PIC2, 0x1f, "pic2"); 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds request_region (sio->acpi_base, 0x1f, "acpi"); 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Enable the legacy I/O function */ 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_read_config_word (pdev, PCI_COMMAND, &word); 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds word |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_IO; 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_write_config_word (pdev, PCI_COMMAND, word); 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_set_master (pdev); 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_enable_device(pdev); 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Next project is programming the onboard interrupt controllers. 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PDC hasn't done this for us, since it's using polled I/O. 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * XXX Use dword writes to avoid bugs in Elroy or Suckyio Config 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * space access. PCI is by nature a 32-bit bus and config 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * space can be sensitive to that. 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 0x64 - 0x67 : 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DMA Rtg 2 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DMA Rtg 3 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DMA Chan Ctl 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds TRIGGER_1 == 0x82 USB & IDE level triggered, rest to edge 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_write_config_dword (pdev, 0x64, 0x82000000U); 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 0x68 - 0x6b : 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds TRIGGER_2 == 0x00 all edge triggered (not used) 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CFG_IR_SER == 0x43 SerPort1 = IRQ3, SerPort2 = IRQ4 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CFG_IR_PF == 0x65 ParPort = IRQ5, FloppyCtlr = IRQ6 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CFG_IR_IDE == 0x07 IDE1 = IRQ7, reserved 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_write_config_dword (pdev, TRIGGER_2, 0x07654300U); 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 0x6c - 0x6f : 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CFG_IR_INTAB == 0x00 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CFG_IR_INTCD == 0x10 USB = IRQ1 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CFG_IR_PS2 == 0x00 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CFG_IR_FXBUS == 0x00 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_write_config_dword (pdev, CFG_IR_INTAB, 0x00001000U); 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 0x70 - 0x73 : 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CFG_IR_USB == 0x00 not used. USB is connected to INTD. 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds CFG_IR_ACPI == 0x00 not used. 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DMA Priority == 0x4c88 Power on default value. NFC. 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_write_config_dword (pdev, CFG_IR_USB, 0x4c880000U); 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* PIC1 Initialization Command Word register programming */ 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb (0x11,IC_PIC1+0); /* ICW1: ICW4 write req | ICW1 */ 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb (0x00,IC_PIC1+1); /* ICW2: interrupt vector table - not used */ 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb (0x04,IC_PIC1+1); /* ICW3: Cascade */ 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb (0x01,IC_PIC1+1); /* ICW4: x86 mode */ 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* PIC1 Program Operational Control Words */ 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb (0xff,IC_PIC1+1); /* OCW1: Mask all interrupts */ 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb (0xc2,IC_PIC1+0); /* OCW2: priority (3-7,0-2) */ 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* PIC2 Initialization Command Word register programming */ 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb (0x11,IC_PIC2+0); /* ICW1: ICW4 write req | ICW1 */ 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb (0x00,IC_PIC2+1); /* ICW2: N/A */ 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb (0x02,IC_PIC2+1); /* ICW3: Slave ID code */ 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb (0x01,IC_PIC2+1); /* ICW4: x86 mode */ 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Program Operational Control Words */ 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb (0xff,IC_PIC1+1); /* OCW1: Mask all interrupts */ 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb (0x68,IC_PIC1+0); /* OCW3: OCW3 select | ESMM | SMM */ 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Write master mask reg */ 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb (0xff,IC_PIC1+1); 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Setup USB power regulation */ 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(1, sio->acpi_base + USB_REG_CR); 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (inb(sio->acpi_base + USB_REG_CR) & 1) 26916541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin printk(KERN_INFO PFX "USB regulator enabled\n"); 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 27116541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin printk(KERN_ERR PFX "USB regulator not initialized!\n"); 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (request_irq(pdev->irq, superio_interrupt, SA_INTERRUPT, 27416541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin SUPERIO, (void *)sio)) { 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27616541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin printk(KERN_ERR PFX "could not get irq\n"); 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG(); 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sio->suckyio_irq_enabled = 1; 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 283a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartinDECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87560_LIO, superio_init); 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void superio_disable_irq(unsigned int irq) 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 r8; 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((irq < 1) || (irq == 2) || (irq > 7)) { 29016541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin printk(KERN_ERR PFX "Illegal irq number.\n"); 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG(); 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Mask interrupt */ 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds r8 = inb(IC_PIC1+1); 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds r8 |= (1 << irq); 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb (r8,IC_PIC1+1); 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void superio_enable_irq(unsigned int irq) 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 r8; 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((irq < 1) || (irq == 2) || (irq > 7)) { 30716541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin printk(KERN_ERR PFX "Illegal irq number (%d).\n", irq); 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG(); 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Unmask interrupt */ 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds r8 = inb(IC_PIC1+1); 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds r8 &= ~(1 << irq); 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb (r8,IC_PIC1+1); 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int superio_startup_irq(unsigned int irq) 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds superio_enable_irq(irq); 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct hw_interrupt_type superio_interrupt_type = { 32516541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin .typename = SUPERIO, 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .startup = superio_startup_irq, 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .shutdown = superio_disable_irq, 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .enable = superio_enable_irq, 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .disable = superio_disable_irq, 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .ack = no_ack_irq, 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .end = no_end_irq, 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_SUPERIO_INIT 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned short expected_device[3] = { 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PCI_DEVICE_ID_NS_87415, 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PCI_DEVICE_ID_NS_87560_LIO, 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PCI_DEVICE_ID_NS_87560_USB 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint superio_fixup_irq(struct pci_dev *pcidev) 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int local_irq, i; 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_SUPERIO_INIT 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int fn; 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fn = PCI_FUNC(pcidev->devfn); 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Verify the function number matches the expected device id. */ 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (expected_device[fn] != pcidev->device) { 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG(); 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("superio_fixup_irq(%s) ven 0x%x dev 0x%x from %p\n", 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_name(pcidev), 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pcidev->vendor, pcidev->device, 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __builtin_return_address(0)); 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 16; i++) { 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds irq_desc[i].handler = &superio_interrupt_type; 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We don't allocate a SuperIO irq for the legacy IO function, 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * since it is a "bridge". Instead, we will allocate irq's for 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * each legacy device as they are initialized. 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch(pcidev->device) { 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PCI_DEVICE_ID_NS_87415: /* Function 0 */ 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq = IDE_IRQ; 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PCI_DEVICE_ID_NS_87560_LIO: /* Function 1 */ 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sio_dev.lio_pdev = pcidev; /* save for superio_init() */ 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case PCI_DEVICE_ID_NS_87560_USB: /* Function 2 */ 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sio_dev.usb_pdev = pcidev; /* save for superio_init() */ 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq = USB_IRQ; 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds local_irq = -1; 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG(); 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return local_irq; 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct uart_port serial[] = { 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .iotype = UPIO_PORT, 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .line = 0, 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .type = PORT_16550A, 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .uartclk = 115200*16, 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .fifosize = 16, 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }, 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .iotype = UPIO_PORT, 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .line = 1, 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .type = PORT_16550A, 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .uartclk = 115200*16, 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .fifosize = 16, 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __devinit superio_serial_init(void) 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SERIAL_8250 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retval; 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial[0].iobase = sio_dev.sp1_base; 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial[0].irq = SP1_IRQ; 4157efe1611b2db9025ffc52a686897ab91820caeb4Kyle McMartin spin_lock_init(&serial[0].lock); 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = early_serial_setup(&serial[0]); 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval < 0) { 41916541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin printk(KERN_WARNING PFX "Register Serial #0 failed.\n"); 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial[1].iobase = sio_dev.sp2_base; 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds serial[1].irq = SP2_IRQ; 4257efe1611b2db9025ffc52a686897ab91820caeb4Kyle McMartin spin_lock_init(&serial[1].lock); 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retval = early_serial_setup(&serial[1]); 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (retval < 0) 42916541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin printk(KERN_WARNING PFX "Register Serial #1 failed.\n"); 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_SERIAL_8250 */ 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __devinit superio_parport_init(void) 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PARPORT_PC 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!parport_pc_probe_port(sio_dev.pp_base, 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0 /*base_hi*/, 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PAR_IRQ, 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PARPORT_DMA_NONE /* dma */, 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NULL /*struct pci_dev* */) ) 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 44316541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin printk(KERN_WARNING PFX "Probing parallel port failed.\n"); 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_PARPORT_PC */ 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void superio_fixup_pci(struct pci_dev *pdev) 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 prog; 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pdev->class |= 0x5; 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_write_config_byte(pdev, PCI_CLASS_PROG, pdev->class); 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_read_config_byte(pdev, PCI_CLASS_PROG, &prog); 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("PCI: Enabled native mode for NS87415 (pif=0x%x)\n", prog); 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsDECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87415, superio_fixup_pci); 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 461a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartinstatic int __devinit 462a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartinsuperio_probe(struct pci_dev *dev, const struct pci_device_id *id) 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 464a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin struct superio_device *sio = &sio_dev; 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** superio_probe(00:0e.0) ven 0x100b dev 0x2 sv 0x0 sd 0x0 class 0x1018a 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** superio_probe(00:0e.1) ven 0x100b dev 0xe sv 0x0 sd 0x0 class 0x68000 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** superio_probe(00:0e.2) ven 0x100b dev 0x12 sv 0x0 sd 0x0 class 0xc0310 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG_INIT("superio_probe(%s) ven 0x%x dev 0x%x sv 0x%x sd 0x%x class 0x%x\n", 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_name(dev), 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->vendor, dev->device, 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->subsystem_vendor, dev->subsystem_device, 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->class); 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 477a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin if (!sio->suckyio_irq_enabled) 478a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin BUG(); /* Enabled by PCI_FIXUP_FINAL */ 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dev->device == PCI_DEVICE_ID_NS_87560_LIO) { /* Function 1 */ 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds superio_parport_init(); 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds superio_serial_init(); 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* REVISIT XXX : superio_fdc_init() ? */ 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (dev->device == PCI_DEVICE_ID_NS_87415) { /* Function 0 */ 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG_INIT("superio_probe: ignoring IDE 87415\n"); 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (dev->device == PCI_DEVICE_ID_NS_87560_USB) { /* Function 2 */ 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG_INIT("superio_probe: ignoring USB OHCI controller\n"); 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DBG_INIT("superio_probe: WTF? Fire Extinguisher?\n"); 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 493a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin /* Let appropriate other driver claim this device. */ 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pci_device_id superio_tbl[] = { 498a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87560_LIO) }, 499a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87560_USB) }, 500a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87415) }, 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { 0, } 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pci_driver superio_driver = { 50516541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin .name = SUPERIO, 506a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin .id_table = superio_tbl, 507a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin .probe = superio_probe, 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init superio_modinit(void) 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return pci_register_driver(&superio_driver); 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit superio_exit(void) 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_unregister_driver(&superio_driver); 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(superio_modinit); 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(superio_exit); 522