brintos

brintos / linux-shallow public Read only

0
0
Text · 13.6 KiB · e973c68 Raw
495 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*      National Semiconductor NS87560UBD Super I/O controller used in3 *      HP [BCJ]x000 workstations.4 *5 *      This chip is a horrid piece of engineering, and National6 *      denies any knowledge of its existence. Thus no datasheet is7 *      available off www.national.com. 8 *9 *	(C) Copyright 2000 Linuxcare, Inc.10 * 	(C) Copyright 2000 Linuxcare Canada, Inc.11 *	(C) Copyright 2000 Martin K. Petersen <mkp@linuxcare.com>12 * 	(C) Copyright 2000 Alex deVries <alex@onefishtwo.ca>13 *      (C) Copyright 2001 John Marvin <jsm fc hp com>14 *      (C) Copyright 2003 Grant Grundler <grundler parisc-linux org>15 *	(C) Copyright 2005 Kyle McMartin <kyle@parisc-linux.org>16 *	(C) Copyright 2006 Helge Deller <deller@gmx.de>17 *18 *	The initial version of this is by Martin Peterson.  Alex deVries19 *	has spent a bit of time trying to coax it into working.20 *21 *      Major changes to get basic interrupt infrastructure working to22 *      hopefully be able to support all SuperIO devices. Currently23 *      works with serial. -- John Marvin <jsm@fc.hp.com>24 *25 *	Converted superio_init() to be a PCI_FIXUP_FINAL callee.26 *         -- Kyle McMartin <kyle@parisc-linux.org>27 */28 29 30/* NOTES:31 * 32 * Function 0 is an IDE controller. It is identical to a PC87415 IDE33 * controller (and identifies itself as such).34 *35 * Function 1 is a "Legacy I/O" controller. Under this function is a36 * whole mess of legacy I/O peripherals. Of course, HP hasn't enabled37 * all the functionality in hardware, but the following is available:38 *39 *      Two 16550A compatible serial controllers40 *      An IEEE 1284 compatible parallel port41 *      A floppy disk controller42 *43 * Function 2 is a USB controller.44 *45 * We must be incredibly careful during initialization.  Since all46 * interrupts are routed through function 1 (which is not allowed by47 * the PCI spec), we need to program the PICs on the legacy I/O port48 * *before* we attempt to set up IDE and USB.  @#$!&49 *50 * According to HP, devices are only enabled by firmware if they have51 * a physical device connected.52 *53 * Configuration register bits:54 *     0x5A: FDC, SP1, IDE1, SP2, IDE2, PAR, Reserved, P9255 *     0x5B: RTC, 8259, 8254, DMA1, DMA2, KBC, P61, APM56 *57 */58 59#include <linux/errno.h>60#include <linux/init.h>61#include <linux/module.h>62#include <linux/types.h>63#include <linux/interrupt.h>64#include <linux/ioport.h>65#include <linux/serial.h>66#include <linux/pci.h>67#include <linux/parport.h>68#include <linux/parport_pc.h>69#include <linux/termios.h>70#include <linux/tty.h>71#include <linux/serial_core.h>72#include <linux/serial_8250.h>73#include <linux/delay.h>74 75#include <asm/io.h>76#include <asm/hardware.h>77#include <asm/superio.h>78 79static struct superio_device sio_dev;80 81 82#undef DEBUG_SUPERIO_INIT83 84#ifdef DEBUG_SUPERIO_INIT85#define DBG_INIT(x...)  printk(x)86#else87#define DBG_INIT(x...)88#endif89 90#define SUPERIO	"SuperIO"91#define PFX	SUPERIO ": "92 93static irqreturn_t94superio_interrupt(int parent_irq, void *devp)95{96	u8 results;97	u8 local_irq;98 99	/* Poll the 8259 to see if there's an interrupt. */100	outb (OCW3_POLL,IC_PIC1+0);101 102	results = inb(IC_PIC1+0);103 104	/*105	 * Bit    7:	1 = active Interrupt; 0 = no Interrupt pending106	 * Bits 6-3:	zero107	 * Bits 2-0:	highest priority, active requesting interrupt ID (0-7)108	 */109	if ((results & 0x80) == 0) {110		/* I suspect "spurious" interrupts are from unmasking an IRQ.111		 * We don't know if an interrupt was/is pending and thus112		 * just call the handler for that IRQ as if it were pending.113		 */114		return IRQ_NONE;115	}116 117	/* Check to see which device is interrupting */118	local_irq = results & 0x0f;119 120	if (local_irq == 2 || local_irq > 7) {121		printk(KERN_ERR PFX "slave interrupted!\n");122		return IRQ_HANDLED;123	}124 125	if (local_irq == 7) {126 127		/* Could be spurious. Check in service bits */128 129		outb(OCW3_ISR,IC_PIC1+0);130		results = inb(IC_PIC1+0);131		if ((results & 0x80) == 0) { /* if ISR7 not set: spurious */132			printk(KERN_WARNING PFX "spurious interrupt!\n");133			return IRQ_HANDLED;134		}135	}136 137	/* Call the appropriate device's interrupt */138	generic_handle_irq(local_irq);139 140	/* set EOI - forces a new interrupt if a lower priority device141	 * still needs service.142	 */143	outb((OCW2_SEOI|local_irq),IC_PIC1 + 0);144	return IRQ_HANDLED;145}146 147/* Initialize Super I/O device */148static void149superio_init(struct pci_dev *pcidev)150{151	struct superio_device *sio = &sio_dev;152	struct pci_dev *pdev = sio->lio_pdev;153	u16 word;154	int ret;155 156	if (sio->suckyio_irq_enabled)157		return;158 159	BUG_ON(!pdev);160	BUG_ON(!sio->usb_pdev);161 162	/* use the IRQ iosapic found for USB INT D... */163	pdev->irq = sio->usb_pdev->irq;164 165	/* ...then properly fixup the USB to point at suckyio PIC */166	sio->usb_pdev->irq = superio_fixup_irq(sio->usb_pdev);167 168	printk(KERN_INFO PFX "Found NS87560 Legacy I/O device at %s (IRQ %i)\n",169	       pci_name(pdev), pdev->irq);170 171	pci_read_config_dword (pdev, SIO_SP1BAR, &sio->sp1_base);172	sio->sp1_base &= ~1;173	printk(KERN_INFO PFX "Serial port 1 at 0x%x\n", sio->sp1_base);174 175	pci_read_config_dword (pdev, SIO_SP2BAR, &sio->sp2_base);176	sio->sp2_base &= ~1;177	printk(KERN_INFO PFX "Serial port 2 at 0x%x\n", sio->sp2_base);178 179	pci_read_config_dword (pdev, SIO_PPBAR, &sio->pp_base);180	sio->pp_base &= ~1;181	printk(KERN_INFO PFX "Parallel port at 0x%x\n", sio->pp_base);182 183	pci_read_config_dword (pdev, SIO_FDCBAR, &sio->fdc_base);184	sio->fdc_base &= ~1;185	printk(KERN_INFO PFX "Floppy controller at 0x%x\n", sio->fdc_base);186	pci_read_config_dword (pdev, SIO_ACPIBAR, &sio->acpi_base);187	sio->acpi_base &= ~1;188	printk(KERN_INFO PFX "ACPI at 0x%x\n", sio->acpi_base);189 190	request_region (IC_PIC1, 0x1f, "pic1");191	request_region (IC_PIC2, 0x1f, "pic2");192	request_region (sio->acpi_base, 0x1f, "acpi");193 194	/* Enable the legacy I/O function */195	pci_read_config_word (pdev, PCI_COMMAND, &word);196	word |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_IO;197	pci_write_config_word (pdev, PCI_COMMAND, word);198 199	pci_set_master (pdev);200	ret = pci_enable_device(pdev);201	BUG_ON(ret < 0);	/* not too much we can do about this... */202 203	/*204	 * Next project is programming the onboard interrupt controllers.205	 * PDC hasn't done this for us, since it's using polled I/O.206	 *207	 * XXX Use dword writes to avoid bugs in Elroy or Suckyio Config208	 *     space access.  PCI is by nature a 32-bit bus and config209	 *     space can be sensitive to that.210	 */211 212	/* 0x64 - 0x67 :213		DMA Rtg 2214		DMA Rtg 3215		DMA Chan Ctl216		TRIGGER_1    == 0x82   USB & IDE level triggered, rest to edge217	*/218	pci_write_config_dword (pdev, 0x64,         0x82000000U);219 220	/* 0x68 - 0x6b :221		TRIGGER_2    == 0x00   all edge triggered (not used)222		CFG_IR_SER   == 0x43   SerPort1 = IRQ3, SerPort2 = IRQ4223		CFG_IR_PF    == 0x65   ParPort  = IRQ5, FloppyCtlr = IRQ6224		CFG_IR_IDE   == 0x07   IDE1 = IRQ7, reserved225	*/226	pci_write_config_dword (pdev, TRIGGER_2,    0x07654300U);227 228	/* 0x6c - 0x6f :229		CFG_IR_INTAB == 0x00230		CFG_IR_INTCD == 0x10   USB = IRQ1231		CFG_IR_PS2   == 0x00232		CFG_IR_FXBUS == 0x00233	*/234	pci_write_config_dword (pdev, CFG_IR_INTAB, 0x00001000U);235 236	/* 0x70 - 0x73 :237		CFG_IR_USB   == 0x00  not used. USB is connected to INTD.238		CFG_IR_ACPI  == 0x00  not used.239		DMA Priority == 0x4c88  Power on default value. NFC.240	*/241	pci_write_config_dword (pdev, CFG_IR_USB, 0x4c880000U);242 243	/* PIC1 Initialization Command Word register programming */244	outb (0x11,IC_PIC1+0);	/* ICW1: ICW4 write req | ICW1 */245	outb (0x00,IC_PIC1+1);	/* ICW2: interrupt vector table - not used */246	outb (0x04,IC_PIC1+1);	/* ICW3: Cascade */247	outb (0x01,IC_PIC1+1);	/* ICW4: x86 mode */248 249	/* PIC1 Program Operational Control Words */250	outb (0xff,IC_PIC1+1);	/* OCW1: Mask all interrupts */251	outb (0xc2,IC_PIC1+0);  /* OCW2: priority (3-7,0-2) */252 253	/* PIC2 Initialization Command Word register programming */254	outb (0x11,IC_PIC2+0);	/* ICW1: ICW4 write req | ICW1 */255	outb (0x00,IC_PIC2+1);	/* ICW2: N/A */256	outb (0x02,IC_PIC2+1);	/* ICW3: Slave ID code */257	outb (0x01,IC_PIC2+1);	/* ICW4: x86 mode */258		259	/* Program Operational Control Words */260	outb (0xff,IC_PIC1+1);	/* OCW1: Mask all interrupts */261	outb (0x68,IC_PIC1+0);	/* OCW3: OCW3 select | ESMM | SMM */262 263	/* Write master mask reg */264	outb (0xff,IC_PIC1+1);265 266	/* Setup USB power regulation */267	outb(1, sio->acpi_base + USB_REG_CR);268	if (inb(sio->acpi_base + USB_REG_CR) & 1)269		printk(KERN_INFO PFX "USB regulator enabled\n");270	else271		printk(KERN_ERR PFX "USB regulator not initialized!\n");272 273	if (request_irq(pdev->irq, superio_interrupt, 0,274			SUPERIO, (void *)sio)) {275 276		printk(KERN_ERR PFX "could not get irq\n");277		BUG();278		return;279	}280 281	sio->suckyio_irq_enabled = 1;282}283DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87560_LIO, superio_init);284 285static void superio_mask_irq(struct irq_data *d)286{287	unsigned int irq = d->irq;288	u8 r8;289 290	if ((irq < 1) || (irq == 2) || (irq > 7)) {291		printk(KERN_ERR PFX "Illegal irq number.\n");292		BUG();293		return;294	}295 296	/* Mask interrupt */297 298	r8 = inb(IC_PIC1+1);299	r8 |= (1 << irq);300	outb (r8,IC_PIC1+1);301}302 303static void superio_unmask_irq(struct irq_data *d)304{305	unsigned int irq = d->irq;306	u8 r8;307 308	if ((irq < 1) || (irq == 2) || (irq > 7)) {309		printk(KERN_ERR PFX "Illegal irq number (%d).\n", irq);310		BUG();311		return;312	}313 314	/* Unmask interrupt */315	r8 = inb(IC_PIC1+1);316	r8 &= ~(1 << irq);317	outb (r8,IC_PIC1+1);318}319 320static struct irq_chip superio_interrupt_type = {321	.name		=	SUPERIO,322	.irq_unmask	=	superio_unmask_irq,323	.irq_mask	=	superio_mask_irq,324};325 326#ifdef DEBUG_SUPERIO_INIT327static unsigned short expected_device[3] = {328	PCI_DEVICE_ID_NS_87415,329	PCI_DEVICE_ID_NS_87560_LIO,330	PCI_DEVICE_ID_NS_87560_USB331};332#endif333 334int superio_fixup_irq(struct pci_dev *pcidev)335{336	int local_irq, i;337 338#ifdef DEBUG_SUPERIO_INIT339	int fn;340	fn = PCI_FUNC(pcidev->devfn);341 342	/* Verify the function number matches the expected device id. */343	if (expected_device[fn] != pcidev->device) {344		BUG();345		return -1;346	}347	printk(KERN_DEBUG "superio_fixup_irq(%s) ven 0x%x dev 0x%x from %ps\n",348		pci_name(pcidev),349		pcidev->vendor, pcidev->device,350		__builtin_return_address(0));351#endif352 353	for (i = 0; i < 16; i++) {354		irq_set_chip_and_handler(i, &superio_interrupt_type,355					 handle_simple_irq);356	}357 358	/*359	 * We don't allocate a SuperIO irq for the legacy IO function,360	 * since it is a "bridge". Instead, we will allocate irq's for361	 * each legacy device as they are initialized.362	 */363 364	switch(pcidev->device) {365	case PCI_DEVICE_ID_NS_87415:		/* Function 0 */366		local_irq = IDE_IRQ;367		break;368	case PCI_DEVICE_ID_NS_87560_LIO:	/* Function 1 */369		sio_dev.lio_pdev = pcidev;	/* save for superio_init() */370		return -1;371	case PCI_DEVICE_ID_NS_87560_USB:	/* Function 2 */372		sio_dev.usb_pdev = pcidev;	/* save for superio_init() */373		local_irq = USB_IRQ;374		break;375	default:376		local_irq = -1;377		BUG();378		break;379	}380 381	return local_irq;382}383 384static void __init superio_serial_init(void)385{386#ifdef CONFIG_SERIAL_8250387	int retval;388	struct uart_port serial_port;389 390	memset(&serial_port, 0, sizeof(serial_port));391	serial_port.iotype	= UPIO_PORT;392	serial_port.type	= PORT_16550A;393	serial_port.uartclk	= 115200*16;394	serial_port.flags	= UPF_FIXED_PORT | UPF_FIXED_TYPE |395				  UPF_BOOT_AUTOCONF;396 397	/* serial port #1 */398	serial_port.iobase	= sio_dev.sp1_base;399	serial_port.irq		= SP1_IRQ;400	serial_port.line	= 0;401	retval = early_serial_setup(&serial_port);402	if (retval < 0) {403		printk(KERN_WARNING PFX "Register Serial #0 failed.\n");404		return;405	}406 407	/* serial port #2 */408	serial_port.iobase	= sio_dev.sp2_base;409	serial_port.irq		= SP2_IRQ;410	serial_port.line	= 1;411	retval = early_serial_setup(&serial_port);412	if (retval < 0)413		printk(KERN_WARNING PFX "Register Serial #1 failed.\n");414#endif /* CONFIG_SERIAL_8250 */415}416 417 418static void __init superio_parport_init(void)419{420#ifdef CONFIG_PARPORT_PC421	if (!parport_pc_probe_port(sio_dev.pp_base,422			0 /*base_hi*/,423			PAR_IRQ, 424			PARPORT_DMA_NONE /* dma */,425			NULL /*struct pci_dev* */,426			0 /* shared irq flags */))427 428		printk(KERN_WARNING PFX "Probing parallel port failed.\n");429#endif	/* CONFIG_PARPORT_PC */430}431 432 433static void superio_fixup_pci(struct pci_dev *pdev)434{435	u8 prog;436 437	pdev->class |= 0x5;438	pci_write_config_byte(pdev, PCI_CLASS_PROG, pdev->class);439 440	pci_read_config_byte(pdev, PCI_CLASS_PROG, &prog);441	printk("PCI: Enabled native mode for NS87415 (pif=0x%x)\n", prog);442}443DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87415, superio_fixup_pci);444 445 446static int __init447superio_probe(struct pci_dev *dev, const struct pci_device_id *id)448{449	struct superio_device *sio = &sio_dev;450 451	/*452	** superio_probe(00:0e.0) ven 0x100b dev 0x2 sv 0x0 sd 0x0 class 0x1018a453	** superio_probe(00:0e.1) ven 0x100b dev 0xe sv 0x0 sd 0x0 class 0x68000454	** superio_probe(00:0e.2) ven 0x100b dev 0x12 sv 0x0 sd 0x0 class 0xc0310455	*/456	DBG_INIT("superio_probe(%s) ven 0x%x dev 0x%x sv 0x%x sd 0x%x class 0x%x\n",457		pci_name(dev),458		dev->vendor, dev->device,459		dev->subsystem_vendor, dev->subsystem_device,460		dev->class);461 462	BUG_ON(!sio->suckyio_irq_enabled);	/* Enabled by PCI_FIXUP_FINAL */463 464	if (dev->device == PCI_DEVICE_ID_NS_87560_LIO) {	/* Function 1 */465		superio_parport_init();466		superio_serial_init();467		/* REVISIT XXX : superio_fdc_init() ? */468		return 0;469	} else if (dev->device == PCI_DEVICE_ID_NS_87415) {	/* Function 0 */470		DBG_INIT("superio_probe: ignoring IDE 87415\n");471	} else if (dev->device == PCI_DEVICE_ID_NS_87560_USB) {	/* Function 2 */472		DBG_INIT("superio_probe: ignoring USB OHCI controller\n");473	} else {474		DBG_INIT("superio_probe: WTF? Fire Extinguisher?\n");475	}476 477	/* Let appropriate other driver claim this device. */478	return -ENODEV;479}480 481static const struct pci_device_id superio_tbl[] __initconst = {482	{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87560_LIO) },483	{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87560_USB) },484	{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87415) },485	{ 0, }486};487 488static struct pci_driver superio_driver __refdata = {489	.name =         SUPERIO,490	.id_table =     superio_tbl,491	.probe =        superio_probe,492};493 494module_pci_driver(superio_driver);495