diff options
Diffstat (limited to 'arch/alpha/kernel/core_irongate.c')
-rw-r--r-- | arch/alpha/kernel/core_irongate.c | 353 |
1 files changed, 353 insertions, 0 deletions
diff --git a/arch/alpha/kernel/core_irongate.c b/arch/alpha/kernel/core_irongate.c new file mode 100644 index 000000000..ef686277c --- /dev/null +++ b/arch/alpha/kernel/core_irongate.c @@ -0,0 +1,353 @@ +/* + * linux/arch/alpha/kernel/core_irongate.c + * + * Based on code written by David A. Rusling (david.rusling@reo.mts.dec.com). + * + * Copyright (C) 1999 Alpha Processor, Inc., + * (David Daniel, Stig Telfer, Soohoon Lee) + * + * Code common to all IRONGATE core logic chips. + */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/sched.h> +#include <linux/init.h> + +#include <asm/ptrace.h> +#include <asm/system.h> +#include <asm/pci.h> +#include <asm/hwrpb.h> + +#define __EXTERN_INLINE inline +#include <asm/io.h> +#include <asm/core_irongate.h> +#undef __EXTERN_INLINE + +#include "proto.h" +#include "pci_impl.h" + + +/* + * NOTE: Herein lie back-to-back mb instructions. They are magic. + * One plausible explanation is that the I/O controller does not properly + * handle the system transaction. Another involves timing. Ho hum. + */ + +/* + * BIOS32-style PCI interface: + */ + +#define DEBUG_CONFIG 0 + +#if DEBUG_CONFIG +# define DBG_CFG(args) printk args +#else +# define DBG_CFG(args) +#endif + + +/* + * Given a bus, device, and function number, compute resulting + * configuration space address accordingly. It is therefore not safe + * to have concurrent invocations to configuration space access + * routines, but there really shouldn't be any need for this. + * + * addr[31:24] reserved + * addr[23:16] bus number (8 bits = 128 possible buses) + * addr[15:11] Device number (5 bits) + * addr[10: 8] function number + * addr[ 7: 2] register number + * + * For IRONGATE: + * if (bus = addr[23:16]) == 0 + * then + * type 0 config cycle: + * addr_on_pci[31:11] = id selection for device = addr[15:11] + * addr_on_pci[10: 2] = addr[10: 2] ??? + * addr_on_pci[ 1: 0] = 00 + * else + * type 1 config cycle (pass on with no decoding): + * addr_on_pci[31:24] = 0 + * addr_on_pci[23: 2] = addr[23: 2] + * addr_on_pci[ 1: 0] = 01 + * fi + * + * Notes: + * The function number selects which function of a multi-function device + * (e.g., SCSI and Ethernet). + * + * The register selects a DWORD (32 bit) register offset. Hence it + * doesn't get shifted by 2 bits as we want to "drop" the bottom two + * bits. + */ + +static int +mk_conf_addr(struct pci_dev *dev, int where, unsigned long *pci_addr, + unsigned char *type1) +{ + unsigned long addr; + u8 bus = dev->bus->number; + u8 device_fn = dev->devfn; + + DBG_CFG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x, " + "pci_addr=0x%p, type1=0x%p)\n", + bus, device_fn, where, pci_addr, type1)); + + *type1 = (bus != 0); + + addr = (bus << 16) | (device_fn << 8) | where; + addr |= IRONGATE_CONF; + + *pci_addr = addr; + DBG_CFG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr)); + return 0; +} + +static int +irongate_read_config_byte(struct pci_dev *dev, int where, u8 *value) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(dev, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *value = __kernel_ldbu(*(vucp)addr); + return PCIBIOS_SUCCESSFUL; +} + +static int +irongate_read_config_word(struct pci_dev *dev, int where, u16 *value) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(dev, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *value = __kernel_ldwu(*(vusp)addr); + return PCIBIOS_SUCCESSFUL; +} + +static int +irongate_read_config_dword(struct pci_dev *dev, int where, u32 *value) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(dev, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *value = *(vuip)addr; + return PCIBIOS_SUCCESSFUL; +} + +static int +irongate_write_config_byte(struct pci_dev *dev, int where, u8 value) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(dev, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + __kernel_stb(value, *(vucp)addr); + mb(); + __kernel_ldbu(*(vucp)addr); + return PCIBIOS_SUCCESSFUL; +} + +static int +irongate_write_config_word(struct pci_dev *dev, int where, u16 value) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(dev, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + __kernel_stw(value, *(vusp)addr); + mb(); + __kernel_ldwu(*(vusp)addr); + return PCIBIOS_SUCCESSFUL; +} + +static int +irongate_write_config_dword(struct pci_dev *dev, int where, u32 value) +{ + unsigned long addr; + unsigned char type1; + + if (mk_conf_addr(dev, where, &addr, &type1)) + return PCIBIOS_DEVICE_NOT_FOUND; + + *(vuip)addr = value; + mb(); + *(vuip)addr; + return PCIBIOS_SUCCESSFUL; +} + + +struct pci_ops irongate_pci_ops = +{ + read_byte: irongate_read_config_byte, + read_word: irongate_read_config_word, + read_dword: irongate_read_config_dword, + write_byte: irongate_write_config_byte, + write_word: irongate_write_config_word, + write_dword: irongate_write_config_dword +}; + +#if 0 +static void +irongate_register_dump(const char *function_name) +{ + printk("%s: Irongate registers:\n" + "\tdev_vendor\t0x%08x\n" + "\tstat_cmd\t0x%08x\n" + "\tclass\t\t0x%08x\n" + "\tlatency\t\t0x%08x\n" + "\tbar0\t\t0x%08x\n" + "\tbar1\t\t0x%08x\n" + "\tbar2\t\t0x%08x\n" + "\trsrvd0[0]\t0x%08x\n" + "\trsrvd0[1]\t0x%08x\n" + "\trsrvd0[2]\t0x%08x\n" + "\trsrvd0[3]\t0x%08x\n" + "\trsrvd0[4]\t0x%08x\n" + "\trsrvd0[5]\t0x%08x\n" + "\tcapptr\t\t0x%08x\n" + "\trsrvd1[0]\t0x%08x\n" + "\trsrvd1[1]\t0x%08x\n" + "\tbacsr10\t\t0x%08x\n" + "\tbacsr32\t\t0x%08x\n" + "\tbacsr54\t\t0x%08x\n" + "\trsrvd2[0]\t0x%08x\n" + "\tdrammap\t\t0x%08x\n" + "\tdramtm\t\t0x%08x\n" + "\tdramms\t\t0x%08x\n" + "\trsrvd3[0]\t0x%08x\n" + "\tbiu0\t\t0x%08x\n" + "\tbiusip\t\t0x%08x\n" + "\trsrvd4[0]\t0x%08x\n" + "\trsrvd4[1]\t0x%08x\n" + "\tmro\t\t0x%08x\n" + "\trsrvd5[0]\t0x%08x\n" + "\trsrvd5[1]\t0x%08x\n" + "\trsrvd5[2]\t0x%08x\n" + "\twhami\t\t0x%08x\n" + "\tpciarb\t\t0x%08x\n" + "\tpcicfg\t\t0x%08x\n" + "\trsrvd6[0]\t0x%08x\n" + "\trsrvd6[1]\t0x%08x\n" + "\trsrvd6[2]\t0x%08x\n" + "\trsrvd6[3]\t0x%08x\n" + "\trsrvd6[4]\t0x%08x\n" + "\tagpcap\t\t0x%08x\n" + "\tagpstat\t\t0x%08x\n" + "\tagpcmd\t\t0x%08x\n" + "\tagpva\t\t0x%08x\n" + "\tagpmode\t\t0x%08x\n", + function_name, + IRONGATE0->dev_vendor, + IRONGATE0->stat_cmd, + IRONGATE0->class, + IRONGATE0->latency, + IRONGATE0->bar0, + IRONGATE0->bar1, + IRONGATE0->bar2, + IRONGATE0->rsrvd0[0], + IRONGATE0->rsrvd0[1], + IRONGATE0->rsrvd0[2], + IRONGATE0->rsrvd0[3], + IRONGATE0->rsrvd0[4], + IRONGATE0->rsrvd0[5], + IRONGATE0->capptr, + IRONGATE0->rsrvd1[0], + IRONGATE0->rsrvd1[1], + IRONGATE0->bacsr10, + IRONGATE0->bacsr32, + IRONGATE0->bacsr54, + IRONGATE0->rsrvd2[0], + IRONGATE0->drammap, + IRONGATE0->dramtm, + IRONGATE0->dramms, + IRONGATE0->rsrvd3[0], + IRONGATE0->biu0, + IRONGATE0->biusip, + IRONGATE0->rsrvd4[0], + IRONGATE0->rsrvd4[1], + IRONGATE0->mro, + IRONGATE0->rsrvd5[0], + IRONGATE0->rsrvd5[1], + IRONGATE0->rsrvd5[2], + IRONGATE0->whami, + IRONGATE0->pciarb, + IRONGATE0->pcicfg, + IRONGATE0->rsrvd6[0], + IRONGATE0->rsrvd6[1], + IRONGATE0->rsrvd6[2], + IRONGATE0->rsrvd6[3], + IRONGATE0->rsrvd6[4], + IRONGATE0->agpcap, + IRONGATE0->agpstat, + IRONGATE0->agpcmd, + IRONGATE0->agpva, + IRONGATE0->agpmode); +} +#else +#define irongate_register_dump(x) +#endif + +int +irongate_pci_clr_err(void) +{ + unsigned int nmi_ctl=0; + unsigned int IRONGATE_jd; + +again: + IRONGATE_jd = IRONGATE0->stat_cmd; + printk("Iron stat_cmd %x\n", IRONGATE_jd); + IRONGATE0->stat_cmd = IRONGATE_jd; /* write again clears error bits */ + mb(); + IRONGATE_jd = IRONGATE0->stat_cmd; /* re-read to force write */ + + IRONGATE_jd = IRONGATE0->dramms; + printk("Iron dramms %x\n", IRONGATE_jd); + IRONGATE0->dramms = IRONGATE_jd; /* write again clears error bits */ + mb(); + IRONGATE_jd = IRONGATE0->dramms; /* re-read to force write */ + + /* Clear ALI NMI */ + nmi_ctl = inb(0x61); + nmi_ctl |= 0x0c; + outb(nmi_ctl, 0x61); + nmi_ctl &= ~0x0c; + outb(nmi_ctl, 0x61); + + IRONGATE_jd = IRONGATE0->dramms; + if (IRONGATE_jd & 0x300) goto again; + + return 0; +} + +void __init +irongate_init_arch(void) +{ + struct pci_controler *hose; + + irongate_pci_clr_err(); + irongate_register_dump(__FUNCTION__); + + /* + * Create our single hose. + */ + + hose = alloc_pci_controler(); + hose->io_space = &ioport_resource; + hose->mem_space = &iomem_resource; + hose->config_space = IRONGATE_CONF; + hose->index = 0; +} |