18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * eisa.c - provide support for EISA adapters in PA-RISC machines 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2001 Matthew Wilcox for Hewlett Packard 68c2ecf20Sopenharmony_ci * Copyright (c) 2001 Daniel Engstrom <5116@telia.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * There are two distinct EISA adapters. Mongoose is found in machines 98c2ecf20Sopenharmony_ci * before the 712; then the Wax ASIC is used. To complicate matters, the 108c2ecf20Sopenharmony_ci * Wax ASIC also includes a PS/2 and RS-232 controller, but those are 118c2ecf20Sopenharmony_ci * dealt with elsewhere; this file is concerned only with the EISA portions 128c2ecf20Sopenharmony_ci * of Wax. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * HINT: 158c2ecf20Sopenharmony_ci * ----- 168c2ecf20Sopenharmony_ci * To allow an ISA card to work properly in the EISA slot you need to 178c2ecf20Sopenharmony_ci * set an edge trigger level. This may be done on the palo command line 188c2ecf20Sopenharmony_ci * by adding the kernel parameter "eisa_irq_edge=n,n2,[...]]", with 198c2ecf20Sopenharmony_ci * n and n2 as the irq levels you want to use. 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * Example: "eisa_irq_edge=10,11" allows ISA cards to operate at 228c2ecf20Sopenharmony_ci * irq levels 10 and 11. 238c2ecf20Sopenharmony_ci */ 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include <linux/init.h> 268c2ecf20Sopenharmony_ci#include <linux/ioport.h> 278c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 288c2ecf20Sopenharmony_ci#include <linux/kernel.h> 298c2ecf20Sopenharmony_ci#include <linux/module.h> 308c2ecf20Sopenharmony_ci#include <linux/pci.h> 318c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 328c2ecf20Sopenharmony_ci#include <linux/eisa.h> 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include <asm/byteorder.h> 358c2ecf20Sopenharmony_ci#include <asm/io.h> 368c2ecf20Sopenharmony_ci#include <asm/hardware.h> 378c2ecf20Sopenharmony_ci#include <asm/processor.h> 388c2ecf20Sopenharmony_ci#include <asm/parisc-device.h> 398c2ecf20Sopenharmony_ci#include <asm/delay.h> 408c2ecf20Sopenharmony_ci#include <asm/eisa_bus.h> 418c2ecf20Sopenharmony_ci#include <asm/eisa_eeprom.h> 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#include "iommu.h" 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#if 0 468c2ecf20Sopenharmony_ci#define EISA_DBG(msg, arg...) printk(KERN_DEBUG "eisa: " msg, ## arg) 478c2ecf20Sopenharmony_ci#else 488c2ecf20Sopenharmony_ci#define EISA_DBG(msg, arg...) 498c2ecf20Sopenharmony_ci#endif 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#define SNAKES_EEPROM_BASE_ADDR 0xF0810400 528c2ecf20Sopenharmony_ci#define MIRAGE_EEPROM_BASE_ADDR 0xF00C0400 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(eisa_irq_lock); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_civoid __iomem *eisa_eeprom_addr __read_mostly; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* We can only have one EISA adapter in the system because neither 598c2ecf20Sopenharmony_ci * implementation can be flexed. 608c2ecf20Sopenharmony_ci */ 618c2ecf20Sopenharmony_cistatic struct eisa_ba { 628c2ecf20Sopenharmony_ci struct pci_hba_data hba; 638c2ecf20Sopenharmony_ci unsigned long eeprom_addr; 648c2ecf20Sopenharmony_ci struct eisa_root_device root; 658c2ecf20Sopenharmony_ci} eisa_dev; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci/* Port ops */ 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic inline unsigned long eisa_permute(unsigned short port) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci if (port & 0x300) { 728c2ecf20Sopenharmony_ci return 0xfc000000 | ((port & 0xfc00) >> 6) 738c2ecf20Sopenharmony_ci | ((port & 0x3f8) << 9) | (port & 7); 748c2ecf20Sopenharmony_ci } else { 758c2ecf20Sopenharmony_ci return 0xfc000000 | port; 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ciunsigned char eisa_in8(unsigned short port) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci if (EISA_bus) 828c2ecf20Sopenharmony_ci return gsc_readb(eisa_permute(port)); 838c2ecf20Sopenharmony_ci return 0xff; 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ciunsigned short eisa_in16(unsigned short port) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci if (EISA_bus) 898c2ecf20Sopenharmony_ci return le16_to_cpu(gsc_readw(eisa_permute(port))); 908c2ecf20Sopenharmony_ci return 0xffff; 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ciunsigned int eisa_in32(unsigned short port) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci if (EISA_bus) 968c2ecf20Sopenharmony_ci return le32_to_cpu(gsc_readl(eisa_permute(port))); 978c2ecf20Sopenharmony_ci return 0xffffffff; 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_civoid eisa_out8(unsigned char data, unsigned short port) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci if (EISA_bus) 1038c2ecf20Sopenharmony_ci gsc_writeb(data, eisa_permute(port)); 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_civoid eisa_out16(unsigned short data, unsigned short port) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci if (EISA_bus) 1098c2ecf20Sopenharmony_ci gsc_writew(cpu_to_le16(data), eisa_permute(port)); 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_civoid eisa_out32(unsigned int data, unsigned short port) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci if (EISA_bus) 1158c2ecf20Sopenharmony_ci gsc_writel(cpu_to_le32(data), eisa_permute(port)); 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci#ifndef CONFIG_PCI 1198c2ecf20Sopenharmony_ci/* We call these directly without PCI. See asm/io.h. */ 1208c2ecf20Sopenharmony_ciEXPORT_SYMBOL(eisa_in8); 1218c2ecf20Sopenharmony_ciEXPORT_SYMBOL(eisa_in16); 1228c2ecf20Sopenharmony_ciEXPORT_SYMBOL(eisa_in32); 1238c2ecf20Sopenharmony_ciEXPORT_SYMBOL(eisa_out8); 1248c2ecf20Sopenharmony_ciEXPORT_SYMBOL(eisa_out16); 1258c2ecf20Sopenharmony_ciEXPORT_SYMBOL(eisa_out32); 1268c2ecf20Sopenharmony_ci#endif 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci/* Interrupt handling */ 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci/* cached interrupt mask registers */ 1318c2ecf20Sopenharmony_cistatic int master_mask; 1328c2ecf20Sopenharmony_cistatic int slave_mask; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci/* the trig level can be set with the 1358c2ecf20Sopenharmony_ci * eisa_irq_edge=n,n,n commandline parameter 1368c2ecf20Sopenharmony_ci * We should really read this from the EEPROM 1378c2ecf20Sopenharmony_ci * in the furure. 1388c2ecf20Sopenharmony_ci */ 1398c2ecf20Sopenharmony_ci/* irq 13,8,2,1,0 must be edge */ 1408c2ecf20Sopenharmony_cistatic unsigned int eisa_irq_level __read_mostly; /* default to edge triggered */ 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci/* called by free irq */ 1448c2ecf20Sopenharmony_cistatic void eisa_mask_irq(struct irq_data *d) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci unsigned int irq = d->irq; 1478c2ecf20Sopenharmony_ci unsigned long flags; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci EISA_DBG("disable irq %d\n", irq); 1508c2ecf20Sopenharmony_ci /* just mask for now */ 1518c2ecf20Sopenharmony_ci spin_lock_irqsave(&eisa_irq_lock, flags); 1528c2ecf20Sopenharmony_ci if (irq & 8) { 1538c2ecf20Sopenharmony_ci slave_mask |= (1 << (irq&7)); 1548c2ecf20Sopenharmony_ci eisa_out8(slave_mask, 0xa1); 1558c2ecf20Sopenharmony_ci } else { 1568c2ecf20Sopenharmony_ci master_mask |= (1 << (irq&7)); 1578c2ecf20Sopenharmony_ci eisa_out8(master_mask, 0x21); 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&eisa_irq_lock, flags); 1608c2ecf20Sopenharmony_ci EISA_DBG("pic0 mask %02x\n", eisa_in8(0x21)); 1618c2ecf20Sopenharmony_ci EISA_DBG("pic1 mask %02x\n", eisa_in8(0xa1)); 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci/* called by request irq */ 1658c2ecf20Sopenharmony_cistatic void eisa_unmask_irq(struct irq_data *d) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci unsigned int irq = d->irq; 1688c2ecf20Sopenharmony_ci unsigned long flags; 1698c2ecf20Sopenharmony_ci EISA_DBG("enable irq %d\n", irq); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci spin_lock_irqsave(&eisa_irq_lock, flags); 1728c2ecf20Sopenharmony_ci if (irq & 8) { 1738c2ecf20Sopenharmony_ci slave_mask &= ~(1 << (irq&7)); 1748c2ecf20Sopenharmony_ci eisa_out8(slave_mask, 0xa1); 1758c2ecf20Sopenharmony_ci } else { 1768c2ecf20Sopenharmony_ci master_mask &= ~(1 << (irq&7)); 1778c2ecf20Sopenharmony_ci eisa_out8(master_mask, 0x21); 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&eisa_irq_lock, flags); 1808c2ecf20Sopenharmony_ci EISA_DBG("pic0 mask %02x\n", eisa_in8(0x21)); 1818c2ecf20Sopenharmony_ci EISA_DBG("pic1 mask %02x\n", eisa_in8(0xa1)); 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic struct irq_chip eisa_interrupt_type = { 1858c2ecf20Sopenharmony_ci .name = "EISA", 1868c2ecf20Sopenharmony_ci .irq_unmask = eisa_unmask_irq, 1878c2ecf20Sopenharmony_ci .irq_mask = eisa_mask_irq, 1888c2ecf20Sopenharmony_ci}; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic irqreturn_t eisa_irq(int wax_irq, void *intr_dev) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci int irq = gsc_readb(0xfc01f000); /* EISA supports 16 irqs */ 1938c2ecf20Sopenharmony_ci unsigned long flags; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci spin_lock_irqsave(&eisa_irq_lock, flags); 1968c2ecf20Sopenharmony_ci /* read IRR command */ 1978c2ecf20Sopenharmony_ci eisa_out8(0x0a, 0x20); 1988c2ecf20Sopenharmony_ci eisa_out8(0x0a, 0xa0); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci EISA_DBG("irq IAR %02x 8259-1 irr %02x 8259-2 irr %02x\n", 2018c2ecf20Sopenharmony_ci irq, eisa_in8(0x20), eisa_in8(0xa0)); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci /* read ISR command */ 2048c2ecf20Sopenharmony_ci eisa_out8(0x0a, 0x20); 2058c2ecf20Sopenharmony_ci eisa_out8(0x0a, 0xa0); 2068c2ecf20Sopenharmony_ci EISA_DBG("irq 8259-1 isr %02x imr %02x 8259-2 isr %02x imr %02x\n", 2078c2ecf20Sopenharmony_ci eisa_in8(0x20), eisa_in8(0x21), eisa_in8(0xa0), eisa_in8(0xa1)); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci irq &= 0xf; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci /* mask irq and write eoi */ 2128c2ecf20Sopenharmony_ci if (irq & 8) { 2138c2ecf20Sopenharmony_ci slave_mask |= (1 << (irq&7)); 2148c2ecf20Sopenharmony_ci eisa_out8(slave_mask, 0xa1); 2158c2ecf20Sopenharmony_ci eisa_out8(0x60 | (irq&7),0xa0);/* 'Specific EOI' to slave */ 2168c2ecf20Sopenharmony_ci eisa_out8(0x62, 0x20); /* 'Specific EOI' to master-IRQ2 */ 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci } else { 2198c2ecf20Sopenharmony_ci master_mask |= (1 << (irq&7)); 2208c2ecf20Sopenharmony_ci eisa_out8(master_mask, 0x21); 2218c2ecf20Sopenharmony_ci eisa_out8(0x60|irq, 0x20); /* 'Specific EOI' to master */ 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&eisa_irq_lock, flags); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci generic_handle_irq(irq); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci spin_lock_irqsave(&eisa_irq_lock, flags); 2288c2ecf20Sopenharmony_ci /* unmask */ 2298c2ecf20Sopenharmony_ci if (irq & 8) { 2308c2ecf20Sopenharmony_ci slave_mask &= ~(1 << (irq&7)); 2318c2ecf20Sopenharmony_ci eisa_out8(slave_mask, 0xa1); 2328c2ecf20Sopenharmony_ci } else { 2338c2ecf20Sopenharmony_ci master_mask &= ~(1 << (irq&7)); 2348c2ecf20Sopenharmony_ci eisa_out8(master_mask, 0x21); 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&eisa_irq_lock, flags); 2378c2ecf20Sopenharmony_ci return IRQ_HANDLED; 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistatic irqreturn_t dummy_irq2_handler(int _, void *dev) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci printk(KERN_ALERT "eisa: uhh, irq2?\n"); 2438c2ecf20Sopenharmony_ci return IRQ_HANDLED; 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic void init_eisa_pic(void) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci unsigned long flags; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci spin_lock_irqsave(&eisa_irq_lock, flags); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci eisa_out8(0xff, 0x21); /* mask during init */ 2538c2ecf20Sopenharmony_ci eisa_out8(0xff, 0xa1); /* mask during init */ 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci /* master pic */ 2568c2ecf20Sopenharmony_ci eisa_out8(0x11, 0x20); /* ICW1 */ 2578c2ecf20Sopenharmony_ci eisa_out8(0x00, 0x21); /* ICW2 */ 2588c2ecf20Sopenharmony_ci eisa_out8(0x04, 0x21); /* ICW3 */ 2598c2ecf20Sopenharmony_ci eisa_out8(0x01, 0x21); /* ICW4 */ 2608c2ecf20Sopenharmony_ci eisa_out8(0x40, 0x20); /* OCW2 */ 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci /* slave pic */ 2638c2ecf20Sopenharmony_ci eisa_out8(0x11, 0xa0); /* ICW1 */ 2648c2ecf20Sopenharmony_ci eisa_out8(0x08, 0xa1); /* ICW2 */ 2658c2ecf20Sopenharmony_ci eisa_out8(0x02, 0xa1); /* ICW3 */ 2668c2ecf20Sopenharmony_ci eisa_out8(0x01, 0xa1); /* ICW4 */ 2678c2ecf20Sopenharmony_ci eisa_out8(0x40, 0xa0); /* OCW2 */ 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci udelay(100); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci slave_mask = 0xff; 2728c2ecf20Sopenharmony_ci master_mask = 0xfb; 2738c2ecf20Sopenharmony_ci eisa_out8(slave_mask, 0xa1); /* OCW1 */ 2748c2ecf20Sopenharmony_ci eisa_out8(master_mask, 0x21); /* OCW1 */ 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci /* setup trig level */ 2778c2ecf20Sopenharmony_ci EISA_DBG("EISA edge/level %04x\n", eisa_irq_level); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci eisa_out8(eisa_irq_level&0xff, 0x4d0); /* Set all irq's to edge */ 2808c2ecf20Sopenharmony_ci eisa_out8((eisa_irq_level >> 8) & 0xff, 0x4d1); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci EISA_DBG("pic0 mask %02x\n", eisa_in8(0x21)); 2838c2ecf20Sopenharmony_ci EISA_DBG("pic1 mask %02x\n", eisa_in8(0xa1)); 2848c2ecf20Sopenharmony_ci EISA_DBG("pic0 edge/level %02x\n", eisa_in8(0x4d0)); 2858c2ecf20Sopenharmony_ci EISA_DBG("pic1 edge/level %02x\n", eisa_in8(0x4d1)); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&eisa_irq_lock, flags); 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci/* Device initialisation */ 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci#define is_mongoose(dev) (dev->id.sversion == 0x00076) 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic int __init eisa_probe(struct parisc_device *dev) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci int i, result; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci char *name = is_mongoose(dev) ? "Mongoose" : "Wax"; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci printk(KERN_INFO "%s EISA Adapter found at 0x%08lx\n", 3018c2ecf20Sopenharmony_ci name, (unsigned long)dev->hpa.start); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci eisa_dev.hba.dev = dev; 3048c2ecf20Sopenharmony_ci eisa_dev.hba.iommu = ccio_get_iommu(dev); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci eisa_dev.hba.lmmio_space.name = "EISA"; 3078c2ecf20Sopenharmony_ci eisa_dev.hba.lmmio_space.start = F_EXTEND(0xfc000000); 3088c2ecf20Sopenharmony_ci eisa_dev.hba.lmmio_space.end = F_EXTEND(0xffbfffff); 3098c2ecf20Sopenharmony_ci eisa_dev.hba.lmmio_space.flags = IORESOURCE_MEM; 3108c2ecf20Sopenharmony_ci result = ccio_request_resource(dev, &eisa_dev.hba.lmmio_space); 3118c2ecf20Sopenharmony_ci if (result < 0) { 3128c2ecf20Sopenharmony_ci printk(KERN_ERR "EISA: failed to claim EISA Bus address space!\n"); 3138c2ecf20Sopenharmony_ci return result; 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ci eisa_dev.hba.io_space.name = "EISA"; 3168c2ecf20Sopenharmony_ci eisa_dev.hba.io_space.start = 0; 3178c2ecf20Sopenharmony_ci eisa_dev.hba.io_space.end = 0xffff; 3188c2ecf20Sopenharmony_ci eisa_dev.hba.lmmio_space.flags = IORESOURCE_IO; 3198c2ecf20Sopenharmony_ci result = request_resource(&ioport_resource, &eisa_dev.hba.io_space); 3208c2ecf20Sopenharmony_ci if (result < 0) { 3218c2ecf20Sopenharmony_ci printk(KERN_ERR "EISA: failed to claim EISA Bus port space!\n"); 3228c2ecf20Sopenharmony_ci return result; 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci pcibios_register_hba(&eisa_dev.hba); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci result = request_irq(dev->irq, eisa_irq, IRQF_SHARED, "EISA", &eisa_dev); 3278c2ecf20Sopenharmony_ci if (result) { 3288c2ecf20Sopenharmony_ci printk(KERN_ERR "EISA: request_irq failed!\n"); 3298c2ecf20Sopenharmony_ci goto error_release; 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci /* Reserve IRQ2 */ 3338c2ecf20Sopenharmony_ci if (request_irq(2, dummy_irq2_handler, 0, "cascade", NULL)) 3348c2ecf20Sopenharmony_ci pr_err("Failed to request irq 2 (cascade)\n"); 3358c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) { 3368c2ecf20Sopenharmony_ci irq_set_chip_and_handler(i, &eisa_interrupt_type, 3378c2ecf20Sopenharmony_ci handle_simple_irq); 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci EISA_bus = 1; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci if (dev->num_addrs) { 3438c2ecf20Sopenharmony_ci /* newer firmware hand out the eeprom address */ 3448c2ecf20Sopenharmony_ci eisa_dev.eeprom_addr = dev->addr[0]; 3458c2ecf20Sopenharmony_ci } else { 3468c2ecf20Sopenharmony_ci /* old firmware, need to figure out the box */ 3478c2ecf20Sopenharmony_ci if (is_mongoose(dev)) { 3488c2ecf20Sopenharmony_ci eisa_dev.eeprom_addr = SNAKES_EEPROM_BASE_ADDR; 3498c2ecf20Sopenharmony_ci } else { 3508c2ecf20Sopenharmony_ci eisa_dev.eeprom_addr = MIRAGE_EEPROM_BASE_ADDR; 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci eisa_eeprom_addr = ioremap(eisa_dev.eeprom_addr, HPEE_MAX_LENGTH); 3548c2ecf20Sopenharmony_ci if (!eisa_eeprom_addr) { 3558c2ecf20Sopenharmony_ci result = -ENOMEM; 3568c2ecf20Sopenharmony_ci printk(KERN_ERR "EISA: ioremap failed!\n"); 3578c2ecf20Sopenharmony_ci goto error_free_irq; 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci result = eisa_enumerator(eisa_dev.eeprom_addr, &eisa_dev.hba.io_space, 3608c2ecf20Sopenharmony_ci &eisa_dev.hba.lmmio_space); 3618c2ecf20Sopenharmony_ci init_eisa_pic(); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci if (result >= 0) { 3648c2ecf20Sopenharmony_ci /* FIXME : Don't enumerate the bus twice. */ 3658c2ecf20Sopenharmony_ci eisa_dev.root.dev = &dev->dev; 3668c2ecf20Sopenharmony_ci dev_set_drvdata(&dev->dev, &eisa_dev.root); 3678c2ecf20Sopenharmony_ci eisa_dev.root.bus_base_addr = 0; 3688c2ecf20Sopenharmony_ci eisa_dev.root.res = &eisa_dev.hba.io_space; 3698c2ecf20Sopenharmony_ci eisa_dev.root.slots = result; 3708c2ecf20Sopenharmony_ci eisa_dev.root.dma_mask = 0xffffffff; /* wild guess */ 3718c2ecf20Sopenharmony_ci if (eisa_root_register (&eisa_dev.root)) { 3728c2ecf20Sopenharmony_ci printk(KERN_ERR "EISA: Failed to register EISA root\n"); 3738c2ecf20Sopenharmony_ci result = -ENOMEM; 3748c2ecf20Sopenharmony_ci goto error_iounmap; 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci return 0; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_cierror_iounmap: 3818c2ecf20Sopenharmony_ci iounmap(eisa_eeprom_addr); 3828c2ecf20Sopenharmony_cierror_free_irq: 3838c2ecf20Sopenharmony_ci free_irq(dev->irq, &eisa_dev); 3848c2ecf20Sopenharmony_cierror_release: 3858c2ecf20Sopenharmony_ci release_resource(&eisa_dev.hba.io_space); 3868c2ecf20Sopenharmony_ci return result; 3878c2ecf20Sopenharmony_ci} 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_cistatic const struct parisc_device_id eisa_tbl[] __initconst = { 3908c2ecf20Sopenharmony_ci { HPHW_BA, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00076 }, /* Mongoose */ 3918c2ecf20Sopenharmony_ci { HPHW_BA, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00090 }, /* Wax EISA */ 3928c2ecf20Sopenharmony_ci { 0, } 3938c2ecf20Sopenharmony_ci}; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(parisc, eisa_tbl); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_cistatic struct parisc_driver eisa_driver __refdata = { 3988c2ecf20Sopenharmony_ci .name = "eisa_ba", 3998c2ecf20Sopenharmony_ci .id_table = eisa_tbl, 4008c2ecf20Sopenharmony_ci .probe = eisa_probe, 4018c2ecf20Sopenharmony_ci}; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_civoid __init eisa_init(void) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci register_parisc_driver(&eisa_driver); 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cistatic unsigned int eisa_irq_configured; 4108c2ecf20Sopenharmony_civoid eisa_make_irq_level(int num) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci if (eisa_irq_configured& (1<<num)) { 4138c2ecf20Sopenharmony_ci printk(KERN_WARNING 4148c2ecf20Sopenharmony_ci "IRQ %d polarity configured twice (last to level)\n", 4158c2ecf20Sopenharmony_ci num); 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci eisa_irq_level |= (1<<num); /* set the corresponding bit */ 4188c2ecf20Sopenharmony_ci eisa_irq_configured |= (1<<num); /* set the corresponding bit */ 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_civoid eisa_make_irq_edge(int num) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci if (eisa_irq_configured& (1<<num)) { 4248c2ecf20Sopenharmony_ci printk(KERN_WARNING 4258c2ecf20Sopenharmony_ci "IRQ %d polarity configured twice (last to edge)\n", 4268c2ecf20Sopenharmony_ci num); 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci eisa_irq_level &= ~(1<<num); /* clear the corresponding bit */ 4298c2ecf20Sopenharmony_ci eisa_irq_configured |= (1<<num); /* set the corresponding bit */ 4308c2ecf20Sopenharmony_ci} 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_cistatic int __init eisa_irq_setup(char *str) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci char *cur = str; 4358c2ecf20Sopenharmony_ci int val; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci EISA_DBG("IRQ setup\n"); 4388c2ecf20Sopenharmony_ci while (cur != NULL) { 4398c2ecf20Sopenharmony_ci char *pe; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci val = (int) simple_strtoul(cur, &pe, 0); 4428c2ecf20Sopenharmony_ci if (val > 15 || val < 0) { 4438c2ecf20Sopenharmony_ci printk(KERN_ERR "eisa: EISA irq value are 0-15\n"); 4448c2ecf20Sopenharmony_ci continue; 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci if (val == 2) { 4478c2ecf20Sopenharmony_ci val = 9; 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci eisa_make_irq_edge(val); /* clear the corresponding bit */ 4508c2ecf20Sopenharmony_ci EISA_DBG("setting IRQ %d to edge-triggered mode\n", val); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci if ((cur = strchr(cur, ','))) { 4538c2ecf20Sopenharmony_ci cur++; 4548c2ecf20Sopenharmony_ci } else { 4558c2ecf20Sopenharmony_ci break; 4568c2ecf20Sopenharmony_ci } 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci return 1; 4598c2ecf20Sopenharmony_ci} 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci__setup("eisa_irq_edge=", eisa_irq_setup); 4628c2ecf20Sopenharmony_ci 463