From 93a686ee9c5ddc6fa368c32cfbfde6f6724599fc Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Tue, 20 Nov 2007 20:28:09 +0100 Subject: drivers/pci : move pci drivers to drivers/pci Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD --- Makefile | 1 + drivers/Makefile | 6 - drivers/fsl_pci_init.c | 177 --------------- drivers/pci.c | 526 --------------------------------------------- drivers/pci/Makefile | 51 +++++ drivers/pci/fsl_pci_init.c | 177 +++++++++++++++ drivers/pci/pci.c | 526 +++++++++++++++++++++++++++++++++++++++++++++ drivers/pci/pci_auto.c | 412 +++++++++++++++++++++++++++++++++++ drivers/pci/pci_indirect.c | 138 ++++++++++++ drivers/pci/tsi108_pci.c | 181 ++++++++++++++++ drivers/pci/w83c553f.c | 226 +++++++++++++++++++ drivers/pci_auto.c | 412 ----------------------------------- drivers/pci_indirect.c | 138 ------------ drivers/tsi108_pci.c | 181 ---------------- drivers/w83c553f.c | 226 ------------------- 15 files changed, 1712 insertions(+), 1666 deletions(-) delete mode 100644 drivers/fsl_pci_init.c delete mode 100644 drivers/pci.c create mode 100644 drivers/pci/Makefile create mode 100644 drivers/pci/fsl_pci_init.c create mode 100644 drivers/pci/pci.c create mode 100644 drivers/pci/pci_auto.c create mode 100644 drivers/pci/pci_indirect.c create mode 100644 drivers/pci/tsi108_pci.c create mode 100644 drivers/pci/w83c553f.c delete mode 100644 drivers/pci_auto.c delete mode 100644 drivers/pci_indirect.c delete mode 100644 drivers/tsi108_pci.c delete mode 100644 drivers/w83c553f.c diff --git a/Makefile b/Makefile index 78ae92400d..43f8bf697e 100644 --- a/Makefile +++ b/Makefile @@ -208,6 +208,7 @@ LIBS += disk/libdisk.a LIBS += rtc/librtc.a LIBS += dtt/libdtt.a LIBS += drivers/i2c/libi2c.a +LIBS += drivers/pci/libpci.a LIBS += drivers/libdrivers.a LIBS += drivers/bios_emulator/libatibiosemu.a LIBS += drivers/nand/libnand.a diff --git a/drivers/Makefile b/drivers/Makefile index 7b524e4a4d..f775371c0b 100755 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -105,17 +105,11 @@ COBJS-y += uli526x.o # # PCI/PCMCIA device drivers # -COBJS-y += fsl_pci_init.o COBJS-y += mpc8xx_pcmcia.o -COBJS-y += pci.o -COBJS-y += pci_auto.o -COBJS-y += pci_indirect.o COBJS-y += pxa_pcmcia.o COBJS-y += rpx_pcmcia.o COBJS-y += ti_pci1410a.o COBJS-y += tqm8xx_pcmcia.o -COBJS-y += tsi108_pci.o -COBJS-y += w83c553f.o # # USB Drivers diff --git a/drivers/fsl_pci_init.c b/drivers/fsl_pci_init.c deleted file mode 100644 index 1e778844a5..0000000000 --- a/drivers/fsl_pci_init.c +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright 2007 Freescale Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * Version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include - -#ifdef CONFIG_FSL_PCI_INIT - -/* - * PCI/PCIE Controller initialization for mpc85xx/mpc86xx soc's - * - * Initialize controller and call the common driver/pci pci_hose_scan to - * scan for bridges and devices. - * - * Hose fields which need to be pre-initialized by board specific code: - * regions[] - * first_busno - * - * Fields updated: - * last_busno - */ - -#include -#include - -void pciauto_prescan_setup_bridge(struct pci_controller *hose, - pci_dev_t dev, int sub_bus); -void pciauto_postscan_setup_bridge(struct pci_controller *hose, - pci_dev_t dev, int sub_bus); - -void pciauto_config_init(struct pci_controller *hose); -void -fsl_pci_init(struct pci_controller *hose) -{ - u16 temp16; - u32 temp32; - int busno = hose->first_busno; - int enabled; - u16 ltssm; - u8 temp8; - int r; - int bridge; - int inbound = 0; - volatile ccsr_fsl_pci_t *pci = (ccsr_fsl_pci_t *) hose->cfg_addr; - pci_dev_t dev = PCI_BDF(busno,0,0); - - /* Initialize ATMU registers based on hose regions and flags */ - volatile pot_t *po=&pci->pot[1]; /* skip 0 */ - volatile pit_t *pi=&pci->pit[0]; /* ranges from: 3 to 1 */ - -#ifdef DEBUG - int neg_link_w; -#endif - - for (r=0; rregion_count; r++) { - if (hose->regions[r].flags & PCI_REGION_MEMORY) { /* inbound */ - pi->pitar = (hose->regions[r].bus_start >> 12) & 0x000fffff; - pi->piwbar = (hose->regions[r].phys_start >> 12) & 0x000fffff; - pi->piwbear = 0; - pi->piwar = PIWAR_EN | PIWAR_PF | PIWAR_LOCAL | - PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP | - (__ilog2(hose->regions[r].size) - 1); - pi++; - inbound = hose->regions[r].size > 0; - } else { /* Outbound */ - po->powbar = (hose->regions[r].phys_start >> 12) & 0x000fffff; - po->potar = (hose->regions[r].bus_start >> 12) & 0x000fffff; - po->potear = 0; - if (hose->regions[r].flags & PCI_REGION_IO) - po->powar = POWAR_EN | POWAR_IO_READ | POWAR_IO_WRITE | - (__ilog2(hose->regions[r].size) - 1); - else - po->powar = POWAR_EN | POWAR_MEM_READ | POWAR_MEM_WRITE | - (__ilog2(hose->regions[r].size) - 1); - po++; - } - } - - pci_register_hose(hose); - pciauto_config_init(hose); /* grab pci_{mem,prefetch,io} */ - hose->current_busno = hose->first_busno; - - pci->pedr = 0xffffffff; /* Clear any errors */ - pci->peer = ~0x20140; /* Enable All Error Interupts except - * - Master abort (pci) - * - Master PERR (pci) - * - ICCA (PCIe) - */ - pci_hose_read_config_dword (hose, dev, PCI_DCR, &temp32); - temp32 |= 0xf000e; /* set URR, FER, NFER (but not CER) */ - pci_hose_write_config_dword(hose, dev, PCI_DCR, temp32); - - pci_hose_read_config_byte (hose, dev, PCI_HEADER_TYPE, &temp8); - bridge = temp8 & PCI_HEADER_TYPE_BRIDGE; /* Bridge, such as pcie */ - - if ( bridge ) { - - pci_hose_read_config_word(hose, dev, PCI_LTSSM, <ssm); - enabled = ltssm >= PCI_LTSSM_L0; - - if (!enabled) { - debug("....PCIE link error. Skipping scan." - "LTSSM=0x%02x\n", ltssm); - hose->last_busno = hose->first_busno; - return; - } - - pci->pme_msg_det = 0xffffffff; - pci->pme_msg_int_en = 0xffffffff; -#ifdef DEBUG - pci_hose_read_config_word(hose, dev, PCI_LSR, &temp16); - neg_link_w = (temp16 & 0x3f0 ) >> 4; - printf("...PCIE LTSSM=0x%x, Negotiated link width=%d\n", - ltssm, neg_link_w); -#endif - hose->current_busno++; /* Start scan with secondary */ - pciauto_prescan_setup_bridge(hose, dev, hose->current_busno); - - } - - /* Use generic setup_device to initialize standard pci regs, - * but do not allocate any windows since any BAR found (such - * as PCSRBAR) is not in this cpu's memory space. - */ - - pciauto_setup_device(hose, dev, 0, hose->pci_mem, - hose->pci_prefetch, hose->pci_io); - - if (inbound) { - pci_hose_read_config_word(hose, dev, PCI_COMMAND, &temp16); - pci_hose_write_config_word(hose, dev, PCI_COMMAND, - temp16 | PCI_COMMAND_MEMORY); - } - -#ifndef CONFIG_PCI_NOSCAN - printf (" Scanning PCI bus %02x\n", hose->current_busno); - hose->last_busno = pci_hose_scan_bus(hose,hose->current_busno); - - if ( bridge ) { /* update limit regs and subordinate busno */ - pciauto_postscan_setup_bridge(hose, dev, hose->last_busno); - } -#else - hose->last_busno = hose->current_busno; -#endif - - /* Clear all error indications */ - - pci->pme_msg_det = 0xffffffff; - pci->pedr = 0xffffffff; - - pci_hose_read_config_word (hose, dev, PCI_DSR, &temp16); - if (temp16) { - pci_hose_write_config_word(hose, dev, - PCI_DSR, 0xffff); - } - - pci_hose_read_config_word (hose, dev, PCI_SEC_STATUS, &temp16); - if (temp16) { - pci_hose_write_config_word(hose, dev, PCI_SEC_STATUS, 0xffff); - } -} - -#endif /* CONFIG_FSL_PCI */ diff --git a/drivers/pci.c b/drivers/pci.c deleted file mode 100644 index 50ca6b0bad..0000000000 --- a/drivers/pci.c +++ /dev/null @@ -1,526 +0,0 @@ -/* - * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH - * Andreas Heppel - * - * (C) Copyright 2002, 2003 - * Wolfgang Denk, DENX Software Engineering, wd@denx.de. - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -/* - * PCI routines - */ - -#include - -#ifdef CONFIG_PCI - -#include -#include -#include -#include - -#define PCI_HOSE_OP(rw, size, type) \ -int pci_hose_##rw##_config_##size(struct pci_controller *hose, \ - pci_dev_t dev, \ - int offset, type value) \ -{ \ - return hose->rw##_##size(hose, dev, offset, value); \ -} - -PCI_HOSE_OP(read, byte, u8 *) -PCI_HOSE_OP(read, word, u16 *) -PCI_HOSE_OP(read, dword, u32 *) -PCI_HOSE_OP(write, byte, u8) -PCI_HOSE_OP(write, word, u16) -PCI_HOSE_OP(write, dword, u32) - -#ifndef CONFIG_IXP425 -#define PCI_OP(rw, size, type, error_code) \ -int pci_##rw##_config_##size(pci_dev_t dev, int offset, type value) \ -{ \ - struct pci_controller *hose = pci_bus_to_hose(PCI_BUS(dev)); \ - \ - if (!hose) \ - { \ - error_code; \ - return -1; \ - } \ - \ - return pci_hose_##rw##_config_##size(hose, dev, offset, value); \ -} - -PCI_OP(read, byte, u8 *, *value = 0xff) -PCI_OP(read, word, u16 *, *value = 0xffff) -PCI_OP(read, dword, u32 *, *value = 0xffffffff) -PCI_OP(write, byte, u8, ) -PCI_OP(write, word, u16, ) -PCI_OP(write, dword, u32, ) -#endif /* CONFIG_IXP425 */ - -#define PCI_READ_VIA_DWORD_OP(size, type, off_mask) \ -int pci_hose_read_config_##size##_via_dword(struct pci_controller *hose,\ - pci_dev_t dev, \ - int offset, type val) \ -{ \ - u32 val32; \ - \ - if (pci_hose_read_config_dword(hose, dev, offset & 0xfc, &val32) < 0) { \ - *val = -1; \ - return -1; \ - } \ - \ - *val = (val32 >> ((offset & (int)off_mask) * 8)); \ - \ - return 0; \ -} - -#define PCI_WRITE_VIA_DWORD_OP(size, type, off_mask, val_mask) \ -int pci_hose_write_config_##size##_via_dword(struct pci_controller *hose,\ - pci_dev_t dev, \ - int offset, type val) \ -{ \ - u32 val32, mask, ldata, shift; \ - \ - if (pci_hose_read_config_dword(hose, dev, offset & 0xfc, &val32) < 0)\ - return -1; \ - \ - shift = ((offset & (int)off_mask) * 8); \ - ldata = (((unsigned long)val) & val_mask) << shift; \ - mask = val_mask << shift; \ - val32 = (val32 & ~mask) | ldata; \ - \ - if (pci_hose_write_config_dword(hose, dev, offset & 0xfc, val32) < 0)\ - return -1; \ - \ - return 0; \ -} - -PCI_READ_VIA_DWORD_OP(byte, u8 *, 0x03) -PCI_READ_VIA_DWORD_OP(word, u16 *, 0x02) -PCI_WRITE_VIA_DWORD_OP(byte, u8, 0x03, 0x000000ff) -PCI_WRITE_VIA_DWORD_OP(word, u16, 0x02, 0x0000ffff) - -/* - * - */ - -static struct pci_controller* hose_head = NULL; - -void pci_register_hose(struct pci_controller* hose) -{ - struct pci_controller **phose = &hose_head; - - while(*phose) - phose = &(*phose)->next; - - hose->next = NULL; - - *phose = hose; -} - -struct pci_controller *pci_bus_to_hose (int bus) -{ - struct pci_controller *hose; - - for (hose = hose_head; hose; hose = hose->next) - if (bus >= hose->first_busno && bus <= hose->last_busno) - return hose; - - printf("pci_bus_to_hose() failed\n"); - return NULL; -} - -#ifndef CONFIG_IXP425 -pci_dev_t pci_find_devices(struct pci_device_id *ids, int index) -{ - struct pci_controller * hose; - u16 vendor, device; - u8 header_type; - pci_dev_t bdf; - int i, bus, found_multi = 0; - - for (hose = hose_head; hose; hose = hose->next) - { -#ifdef CFG_SCSI_SCAN_BUS_REVERSE - for (bus = hose->last_busno; bus >= hose->first_busno; bus--) -#else - for (bus = hose->first_busno; bus <= hose->last_busno; bus++) -#endif - for (bdf = PCI_BDF(bus,0,0); -#if defined(CONFIG_ELPPC) || defined(CONFIG_PPMC7XX) - bdf < PCI_BDF(bus,PCI_MAX_PCI_DEVICES-1,PCI_MAX_PCI_FUNCTIONS-1); -#else - bdf < PCI_BDF(bus+1,0,0); -#endif - bdf += PCI_BDF(0,0,1)) - { - if (!PCI_FUNC(bdf)) { - pci_read_config_byte(bdf, - PCI_HEADER_TYPE, - &header_type); - - found_multi = header_type & 0x80; - } else { - if (!found_multi) - continue; - } - - pci_read_config_word(bdf, - PCI_VENDOR_ID, - &vendor); - pci_read_config_word(bdf, - PCI_DEVICE_ID, - &device); - - for (i=0; ids[i].vendor != 0; i++) - if (vendor == ids[i].vendor && - device == ids[i].device) - { - if (index <= 0) - return bdf; - - index--; - } - } - } - - return (-1); -} -#endif /* CONFIG_IXP425 */ - -pci_dev_t pci_find_device(unsigned int vendor, unsigned int device, int index) -{ - static struct pci_device_id ids[2] = {{}, {0, 0}}; - - ids[0].vendor = vendor; - ids[0].device = device; - - return pci_find_devices(ids, index); -} - -/* - * - */ - -unsigned long pci_hose_phys_to_bus (struct pci_controller *hose, - unsigned long phys_addr, - unsigned long flags) -{ - struct pci_region *res; - unsigned long bus_addr; - int i; - - if (!hose) { - printf ("pci_hose_phys_to_bus: %s\n", "invalid hose"); - goto Done; - } - - for (i = 0; i < hose->region_count; i++) { - res = &hose->regions[i]; - - if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0) - continue; - - bus_addr = phys_addr - res->phys_start + res->bus_start; - - if (bus_addr >= res->bus_start && - bus_addr < res->bus_start + res->size) { - return bus_addr; - } - } - - printf ("pci_hose_phys_to_bus: %s\n", "invalid physical address"); - -Done: - return 0; -} - -unsigned long pci_hose_bus_to_phys(struct pci_controller* hose, - unsigned long bus_addr, - unsigned long flags) -{ - struct pci_region *res; - int i; - - if (!hose) { - printf ("pci_hose_bus_to_phys: %s\n", "invalid hose"); - goto Done; - } - - for (i = 0; i < hose->region_count; i++) { - res = &hose->regions[i]; - - if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0) - continue; - - if (bus_addr >= res->bus_start && - bus_addr < res->bus_start + res->size) { - return bus_addr - res->bus_start + res->phys_start; - } - } - - printf ("pci_hose_bus_to_phys: %s\n", "invalid physical address"); - -Done: - return 0; -} - -/* - * - */ - -int pci_hose_config_device(struct pci_controller *hose, - pci_dev_t dev, - unsigned long io, - unsigned long mem, - unsigned long command) -{ - unsigned int bar_response, bar_size, bar_value, old_command; - unsigned char pin; - int bar, found_mem64; - - debug ("PCI Config: I/O=0x%lx, Memory=0x%lx, Command=0x%lx\n", - io, mem, command); - - pci_hose_write_config_dword (hose, dev, PCI_COMMAND, 0); - - for (bar = PCI_BASE_ADDRESS_0; bar < PCI_BASE_ADDRESS_5; bar += 4) { - pci_hose_write_config_dword (hose, dev, bar, 0xffffffff); - pci_hose_read_config_dword (hose, dev, bar, &bar_response); - - if (!bar_response) - continue; - - found_mem64 = 0; - - /* Check the BAR type and set our address mask */ - if (bar_response & PCI_BASE_ADDRESS_SPACE) { - bar_size = ~(bar_response & PCI_BASE_ADDRESS_IO_MASK) + 1; - /* round up region base address to a multiple of size */ - io = ((io - 1) | (bar_size - 1)) + 1; - bar_value = io; - /* compute new region base address */ - io = io + bar_size; - } else { - if ((bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == - PCI_BASE_ADDRESS_MEM_TYPE_64) - found_mem64 = 1; - - bar_size = ~(bar_response & PCI_BASE_ADDRESS_MEM_MASK) + 1; - - /* round up region base address to multiple of size */ - mem = ((mem - 1) | (bar_size - 1)) + 1; - bar_value = mem; - /* compute new region base address */ - mem = mem + bar_size; - } - - /* Write it out and update our limit */ - pci_hose_write_config_dword (hose, dev, bar, bar_value); - - if (found_mem64) { - bar += 4; - pci_hose_write_config_dword (hose, dev, bar, 0x00000000); - } - } - - /* Configure Cache Line Size Register */ - pci_hose_write_config_byte (hose, dev, PCI_CACHE_LINE_SIZE, 0x08); - - /* Configure Latency Timer */ - pci_hose_write_config_byte (hose, dev, PCI_LATENCY_TIMER, 0x80); - - /* Disable interrupt line, if device says it wants to use interrupts */ - pci_hose_read_config_byte (hose, dev, PCI_INTERRUPT_PIN, &pin); - if (pin != 0) { - pci_hose_write_config_byte (hose, dev, PCI_INTERRUPT_LINE, 0xff); - } - - pci_hose_read_config_dword (hose, dev, PCI_COMMAND, &old_command); - pci_hose_write_config_dword (hose, dev, PCI_COMMAND, - (old_command & 0xffff0000) | command); - - return 0; -} - -/* - * - */ - -struct pci_config_table *pci_find_config(struct pci_controller *hose, - unsigned short class, - unsigned int vendor, - unsigned int device, - unsigned int bus, - unsigned int dev, - unsigned int func) -{ - struct pci_config_table *table; - - for (table = hose->config_table; table && table->vendor; table++) { - if ((table->vendor == PCI_ANY_ID || table->vendor == vendor) && - (table->device == PCI_ANY_ID || table->device == device) && - (table->class == PCI_ANY_ID || table->class == class) && - (table->bus == PCI_ANY_ID || table->bus == bus) && - (table->dev == PCI_ANY_ID || table->dev == dev) && - (table->func == PCI_ANY_ID || table->func == func)) { - return table; - } - } - - return NULL; -} - -void pci_cfgfunc_config_device(struct pci_controller *hose, - pci_dev_t dev, - struct pci_config_table *entry) -{ - pci_hose_config_device(hose, dev, entry->priv[0], entry->priv[1], entry->priv[2]); -} - -void pci_cfgfunc_do_nothing(struct pci_controller *hose, - pci_dev_t dev, struct pci_config_table *entry) -{ -} - -/* - * - */ - -/* HJF: Changed this to return int. I think this is required - * to get the correct result when scanning bridges - */ -extern int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev); -extern void pciauto_config_init(struct pci_controller *hose); - -int pci_hose_scan_bus(struct pci_controller *hose, int bus) -{ - unsigned int sub_bus, found_multi=0; - unsigned short vendor, device, class; - unsigned char header_type; - struct pci_config_table *cfg; - pci_dev_t dev; - - sub_bus = bus; - - for (dev = PCI_BDF(bus,0,0); - dev < PCI_BDF(bus,PCI_MAX_PCI_DEVICES-1,PCI_MAX_PCI_FUNCTIONS-1); - dev += PCI_BDF(0,0,1)) - { - /* Skip our host bridge */ - if ( dev == PCI_BDF(hose->first_busno,0,0) ) { -#if defined(CONFIG_PCI_CONFIG_HOST_BRIDGE) /* don't skip host bridge */ - /* - * Only skip hostbridge configuration if "pciconfighost" is not set - */ - if (getenv("pciconfighost") == NULL) { - continue; /* Skip our host bridge */ - } -#else - continue; /* Skip our host bridge */ -#endif - } - - if (PCI_FUNC(dev) && !found_multi) - continue; - - pci_hose_read_config_byte(hose, dev, PCI_HEADER_TYPE, &header_type); - - pci_hose_read_config_word(hose, dev, PCI_VENDOR_ID, &vendor); - - if (vendor != 0xffff && vendor != 0x0000) { - - if (!PCI_FUNC(dev)) - found_multi = header_type & 0x80; - - debug ("PCI Scan: Found Bus %d, Device %d, Function %d\n", - PCI_BUS(dev), PCI_DEV(dev), PCI_FUNC(dev) ); - - pci_hose_read_config_word(hose, dev, PCI_DEVICE_ID, &device); - pci_hose_read_config_word(hose, dev, PCI_CLASS_DEVICE, &class); - - cfg = pci_find_config(hose, class, vendor, device, - PCI_BUS(dev), PCI_DEV(dev), PCI_FUNC(dev)); - if (cfg) { - cfg->config_device(hose, dev, cfg); - sub_bus = max(sub_bus, hose->current_busno); -#ifdef CONFIG_PCI_PNP - } else { - int n = pciauto_config_device(hose, dev); - - sub_bus = max(sub_bus, n); -#endif - } - if (hose->fixup_irq) - hose->fixup_irq(hose, dev); - -#ifdef CONFIG_PCI_SCAN_SHOW - /* Skip our host bridge */ - if ( dev != PCI_BDF(hose->first_busno,0,0) ) { - unsigned char int_line; - - pci_hose_read_config_byte(hose, dev, PCI_INTERRUPT_LINE, - &int_line); - printf(" %02x %02x %04x %04x %04x %02x\n", - PCI_BUS(dev), PCI_DEV(dev), vendor, device, class, - int_line); - } -#endif - } - } - - return sub_bus; -} - -int pci_hose_scan(struct pci_controller *hose) -{ - /* Start scan at current_busno. - * PCIe will start scan at first_busno+1. - */ - /* For legacy support, ensure current>=first */ - if (hose->first_busno > hose->current_busno) - hose->current_busno = hose->first_busno; -#ifdef CONFIG_PCI_PNP - pciauto_config_init(hose); -#endif - return pci_hose_scan_bus(hose, hose->current_busno); -} - -void pci_init(void) -{ -#if defined(CONFIG_PCI_BOOTDELAY) - char *s; - int i; - - /* wait "pcidelay" ms (if defined)... */ - s = getenv ("pcidelay"); - if (s) { - int val = simple_strtoul (s, NULL, 10); - for (i=0; i + +#ifdef CONFIG_FSL_PCI_INIT + +/* + * PCI/PCIE Controller initialization for mpc85xx/mpc86xx soc's + * + * Initialize controller and call the common driver/pci pci_hose_scan to + * scan for bridges and devices. + * + * Hose fields which need to be pre-initialized by board specific code: + * regions[] + * first_busno + * + * Fields updated: + * last_busno + */ + +#include +#include + +void pciauto_prescan_setup_bridge(struct pci_controller *hose, + pci_dev_t dev, int sub_bus); +void pciauto_postscan_setup_bridge(struct pci_controller *hose, + pci_dev_t dev, int sub_bus); + +void pciauto_config_init(struct pci_controller *hose); +void +fsl_pci_init(struct pci_controller *hose) +{ + u16 temp16; + u32 temp32; + int busno = hose->first_busno; + int enabled; + u16 ltssm; + u8 temp8; + int r; + int bridge; + int inbound = 0; + volatile ccsr_fsl_pci_t *pci = (ccsr_fsl_pci_t *) hose->cfg_addr; + pci_dev_t dev = PCI_BDF(busno,0,0); + + /* Initialize ATMU registers based on hose regions and flags */ + volatile pot_t *po=&pci->pot[1]; /* skip 0 */ + volatile pit_t *pi=&pci->pit[0]; /* ranges from: 3 to 1 */ + +#ifdef DEBUG + int neg_link_w; +#endif + + for (r=0; rregion_count; r++) { + if (hose->regions[r].flags & PCI_REGION_MEMORY) { /* inbound */ + pi->pitar = (hose->regions[r].bus_start >> 12) & 0x000fffff; + pi->piwbar = (hose->regions[r].phys_start >> 12) & 0x000fffff; + pi->piwbear = 0; + pi->piwar = PIWAR_EN | PIWAR_PF | PIWAR_LOCAL | + PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP | + (__ilog2(hose->regions[r].size) - 1); + pi++; + inbound = hose->regions[r].size > 0; + } else { /* Outbound */ + po->powbar = (hose->regions[r].phys_start >> 12) & 0x000fffff; + po->potar = (hose->regions[r].bus_start >> 12) & 0x000fffff; + po->potear = 0; + if (hose->regions[r].flags & PCI_REGION_IO) + po->powar = POWAR_EN | POWAR_IO_READ | POWAR_IO_WRITE | + (__ilog2(hose->regions[r].size) - 1); + else + po->powar = POWAR_EN | POWAR_MEM_READ | POWAR_MEM_WRITE | + (__ilog2(hose->regions[r].size) - 1); + po++; + } + } + + pci_register_hose(hose); + pciauto_config_init(hose); /* grab pci_{mem,prefetch,io} */ + hose->current_busno = hose->first_busno; + + pci->pedr = 0xffffffff; /* Clear any errors */ + pci->peer = ~0x20140; /* Enable All Error Interupts except + * - Master abort (pci) + * - Master PERR (pci) + * - ICCA (PCIe) + */ + pci_hose_read_config_dword (hose, dev, PCI_DCR, &temp32); + temp32 |= 0xf000e; /* set URR, FER, NFER (but not CER) */ + pci_hose_write_config_dword(hose, dev, PCI_DCR, temp32); + + pci_hose_read_config_byte (hose, dev, PCI_HEADER_TYPE, &temp8); + bridge = temp8 & PCI_HEADER_TYPE_BRIDGE; /* Bridge, such as pcie */ + + if ( bridge ) { + + pci_hose_read_config_word(hose, dev, PCI_LTSSM, <ssm); + enabled = ltssm >= PCI_LTSSM_L0; + + if (!enabled) { + debug("....PCIE link error. Skipping scan." + "LTSSM=0x%02x\n", ltssm); + hose->last_busno = hose->first_busno; + return; + } + + pci->pme_msg_det = 0xffffffff; + pci->pme_msg_int_en = 0xffffffff; +#ifdef DEBUG + pci_hose_read_config_word(hose, dev, PCI_LSR, &temp16); + neg_link_w = (temp16 & 0x3f0 ) >> 4; + printf("...PCIE LTSSM=0x%x, Negotiated link width=%d\n", + ltssm, neg_link_w); +#endif + hose->current_busno++; /* Start scan with secondary */ + pciauto_prescan_setup_bridge(hose, dev, hose->current_busno); + + } + + /* Use generic setup_device to initialize standard pci regs, + * but do not allocate any windows since any BAR found (such + * as PCSRBAR) is not in this cpu's memory space. + */ + + pciauto_setup_device(hose, dev, 0, hose->pci_mem, + hose->pci_prefetch, hose->pci_io); + + if (inbound) { + pci_hose_read_config_word(hose, dev, PCI_COMMAND, &temp16); + pci_hose_write_config_word(hose, dev, PCI_COMMAND, + temp16 | PCI_COMMAND_MEMORY); + } + +#ifndef CONFIG_PCI_NOSCAN + printf (" Scanning PCI bus %02x\n", hose->current_busno); + hose->last_busno = pci_hose_scan_bus(hose,hose->current_busno); + + if ( bridge ) { /* update limit regs and subordinate busno */ + pciauto_postscan_setup_bridge(hose, dev, hose->last_busno); + } +#else + hose->last_busno = hose->current_busno; +#endif + + /* Clear all error indications */ + + pci->pme_msg_det = 0xffffffff; + pci->pedr = 0xffffffff; + + pci_hose_read_config_word (hose, dev, PCI_DSR, &temp16); + if (temp16) { + pci_hose_write_config_word(hose, dev, + PCI_DSR, 0xffff); + } + + pci_hose_read_config_word (hose, dev, PCI_SEC_STATUS, &temp16); + if (temp16) { + pci_hose_write_config_word(hose, dev, PCI_SEC_STATUS, 0xffff); + } +} + +#endif /* CONFIG_FSL_PCI */ diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c new file mode 100644 index 0000000000..50ca6b0bad --- /dev/null +++ b/drivers/pci/pci.c @@ -0,0 +1,526 @@ +/* + * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH + * Andreas Heppel + * + * (C) Copyright 2002, 2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * PCI routines + */ + +#include + +#ifdef CONFIG_PCI + +#include +#include +#include +#include + +#define PCI_HOSE_OP(rw, size, type) \ +int pci_hose_##rw##_config_##size(struct pci_controller *hose, \ + pci_dev_t dev, \ + int offset, type value) \ +{ \ + return hose->rw##_##size(hose, dev, offset, value); \ +} + +PCI_HOSE_OP(read, byte, u8 *) +PCI_HOSE_OP(read, word, u16 *) +PCI_HOSE_OP(read, dword, u32 *) +PCI_HOSE_OP(write, byte, u8) +PCI_HOSE_OP(write, word, u16) +PCI_HOSE_OP(write, dword, u32) + +#ifndef CONFIG_IXP425 +#define PCI_OP(rw, size, type, error_code) \ +int pci_##rw##_config_##size(pci_dev_t dev, int offset, type value) \ +{ \ + struct pci_controller *hose = pci_bus_to_hose(PCI_BUS(dev)); \ + \ + if (!hose) \ + { \ + error_code; \ + return -1; \ + } \ + \ + return pci_hose_##rw##_config_##size(hose, dev, offset, value); \ +} + +PCI_OP(read, byte, u8 *, *value = 0xff) +PCI_OP(read, word, u16 *, *value = 0xffff) +PCI_OP(read, dword, u32 *, *value = 0xffffffff) +PCI_OP(write, byte, u8, ) +PCI_OP(write, word, u16, ) +PCI_OP(write, dword, u32, ) +#endif /* CONFIG_IXP425 */ + +#define PCI_READ_VIA_DWORD_OP(size, type, off_mask) \ +int pci_hose_read_config_##size##_via_dword(struct pci_controller *hose,\ + pci_dev_t dev, \ + int offset, type val) \ +{ \ + u32 val32; \ + \ + if (pci_hose_read_config_dword(hose, dev, offset & 0xfc, &val32) < 0) { \ + *val = -1; \ + return -1; \ + } \ + \ + *val = (val32 >> ((offset & (int)off_mask) * 8)); \ + \ + return 0; \ +} + +#define PCI_WRITE_VIA_DWORD_OP(size, type, off_mask, val_mask) \ +int pci_hose_write_config_##size##_via_dword(struct pci_controller *hose,\ + pci_dev_t dev, \ + int offset, type val) \ +{ \ + u32 val32, mask, ldata, shift; \ + \ + if (pci_hose_read_config_dword(hose, dev, offset & 0xfc, &val32) < 0)\ + return -1; \ + \ + shift = ((offset & (int)off_mask) * 8); \ + ldata = (((unsigned long)val) & val_mask) << shift; \ + mask = val_mask << shift; \ + val32 = (val32 & ~mask) | ldata; \ + \ + if (pci_hose_write_config_dword(hose, dev, offset & 0xfc, val32) < 0)\ + return -1; \ + \ + return 0; \ +} + +PCI_READ_VIA_DWORD_OP(byte, u8 *, 0x03) +PCI_READ_VIA_DWORD_OP(word, u16 *, 0x02) +PCI_WRITE_VIA_DWORD_OP(byte, u8, 0x03, 0x000000ff) +PCI_WRITE_VIA_DWORD_OP(word, u16, 0x02, 0x0000ffff) + +/* + * + */ + +static struct pci_controller* hose_head = NULL; + +void pci_register_hose(struct pci_controller* hose) +{ + struct pci_controller **phose = &hose_head; + + while(*phose) + phose = &(*phose)->next; + + hose->next = NULL; + + *phose = hose; +} + +struct pci_controller *pci_bus_to_hose (int bus) +{ + struct pci_controller *hose; + + for (hose = hose_head; hose; hose = hose->next) + if (bus >= hose->first_busno && bus <= hose->last_busno) + return hose; + + printf("pci_bus_to_hose() failed\n"); + return NULL; +} + +#ifndef CONFIG_IXP425 +pci_dev_t pci_find_devices(struct pci_device_id *ids, int index) +{ + struct pci_controller * hose; + u16 vendor, device; + u8 header_type; + pci_dev_t bdf; + int i, bus, found_multi = 0; + + for (hose = hose_head; hose; hose = hose->next) + { +#ifdef CFG_SCSI_SCAN_BUS_REVERSE + for (bus = hose->last_busno; bus >= hose->first_busno; bus--) +#else + for (bus = hose->first_busno; bus <= hose->last_busno; bus++) +#endif + for (bdf = PCI_BDF(bus,0,0); +#if defined(CONFIG_ELPPC) || defined(CONFIG_PPMC7XX) + bdf < PCI_BDF(bus,PCI_MAX_PCI_DEVICES-1,PCI_MAX_PCI_FUNCTIONS-1); +#else + bdf < PCI_BDF(bus+1,0,0); +#endif + bdf += PCI_BDF(0,0,1)) + { + if (!PCI_FUNC(bdf)) { + pci_read_config_byte(bdf, + PCI_HEADER_TYPE, + &header_type); + + found_multi = header_type & 0x80; + } else { + if (!found_multi) + continue; + } + + pci_read_config_word(bdf, + PCI_VENDOR_ID, + &vendor); + pci_read_config_word(bdf, + PCI_DEVICE_ID, + &device); + + for (i=0; ids[i].vendor != 0; i++) + if (vendor == ids[i].vendor && + device == ids[i].device) + { + if (index <= 0) + return bdf; + + index--; + } + } + } + + return (-1); +} +#endif /* CONFIG_IXP425 */ + +pci_dev_t pci_find_device(unsigned int vendor, unsigned int device, int index) +{ + static struct pci_device_id ids[2] = {{}, {0, 0}}; + + ids[0].vendor = vendor; + ids[0].device = device; + + return pci_find_devices(ids, index); +} + +/* + * + */ + +unsigned long pci_hose_phys_to_bus (struct pci_controller *hose, + unsigned long phys_addr, + unsigned long flags) +{ + struct pci_region *res; + unsigned long bus_addr; + int i; + + if (!hose) { + printf ("pci_hose_phys_to_bus: %s\n", "invalid hose"); + goto Done; + } + + for (i = 0; i < hose->region_count; i++) { + res = &hose->regions[i]; + + if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0) + continue; + + bus_addr = phys_addr - res->phys_start + res->bus_start; + + if (bus_addr >= res->bus_start && + bus_addr < res->bus_start + res->size) { + return bus_addr; + } + } + + printf ("pci_hose_phys_to_bus: %s\n", "invalid physical address"); + +Done: + return 0; +} + +unsigned long pci_hose_bus_to_phys(struct pci_controller* hose, + unsigned long bus_addr, + unsigned long flags) +{ + struct pci_region *res; + int i; + + if (!hose) { + printf ("pci_hose_bus_to_phys: %s\n", "invalid hose"); + goto Done; + } + + for (i = 0; i < hose->region_count; i++) { + res = &hose->regions[i]; + + if (((res->flags ^ flags) & PCI_REGION_TYPE) != 0) + continue; + + if (bus_addr >= res->bus_start && + bus_addr < res->bus_start + res->size) { + return bus_addr - res->bus_start + res->phys_start; + } + } + + printf ("pci_hose_bus_to_phys: %s\n", "invalid physical address"); + +Done: + return 0; +} + +/* + * + */ + +int pci_hose_config_device(struct pci_controller *hose, + pci_dev_t dev, + unsigned long io, + unsigned long mem, + unsigned long command) +{ + unsigned int bar_response, bar_size, bar_value, old_command; + unsigned char pin; + int bar, found_mem64; + + debug ("PCI Config: I/O=0x%lx, Memory=0x%lx, Command=0x%lx\n", + io, mem, command); + + pci_hose_write_config_dword (hose, dev, PCI_COMMAND, 0); + + for (bar = PCI_BASE_ADDRESS_0; bar < PCI_BASE_ADDRESS_5; bar += 4) { + pci_hose_write_config_dword (hose, dev, bar, 0xffffffff); + pci_hose_read_config_dword (hose, dev, bar, &bar_response); + + if (!bar_response) + continue; + + found_mem64 = 0; + + /* Check the BAR type and set our address mask */ + if (bar_response & PCI_BASE_ADDRESS_SPACE) { + bar_size = ~(bar_response & PCI_BASE_ADDRESS_IO_MASK) + 1; + /* round up region base address to a multiple of size */ + io = ((io - 1) | (bar_size - 1)) + 1; + bar_value = io; + /* compute new region base address */ + io = io + bar_size; + } else { + if ((bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == + PCI_BASE_ADDRESS_MEM_TYPE_64) + found_mem64 = 1; + + bar_size = ~(bar_response & PCI_BASE_ADDRESS_MEM_MASK) + 1; + + /* round up region base address to multiple of size */ + mem = ((mem - 1) | (bar_size - 1)) + 1; + bar_value = mem; + /* compute new region base address */ + mem = mem + bar_size; + } + + /* Write it out and update our limit */ + pci_hose_write_config_dword (hose, dev, bar, bar_value); + + if (found_mem64) { + bar += 4; + pci_hose_write_config_dword (hose, dev, bar, 0x00000000); + } + } + + /* Configure Cache Line Size Register */ + pci_hose_write_config_byte (hose, dev, PCI_CACHE_LINE_SIZE, 0x08); + + /* Configure Latency Timer */ + pci_hose_write_config_byte (hose, dev, PCI_LATENCY_TIMER, 0x80); + + /* Disable interrupt line, if device says it wants to use interrupts */ + pci_hose_read_config_byte (hose, dev, PCI_INTERRUPT_PIN, &pin); + if (pin != 0) { + pci_hose_write_config_byte (hose, dev, PCI_INTERRUPT_LINE, 0xff); + } + + pci_hose_read_config_dword (hose, dev, PCI_COMMAND, &old_command); + pci_hose_write_config_dword (hose, dev, PCI_COMMAND, + (old_command & 0xffff0000) | command); + + return 0; +} + +/* + * + */ + +struct pci_config_table *pci_find_config(struct pci_controller *hose, + unsigned short class, + unsigned int vendor, + unsigned int device, + unsigned int bus, + unsigned int dev, + unsigned int func) +{ + struct pci_config_table *table; + + for (table = hose->config_table; table && table->vendor; table++) { + if ((table->vendor == PCI_ANY_ID || table->vendor == vendor) && + (table->device == PCI_ANY_ID || table->device == device) && + (table->class == PCI_ANY_ID || table->class == class) && + (table->bus == PCI_ANY_ID || table->bus == bus) && + (table->dev == PCI_ANY_ID || table->dev == dev) && + (table->func == PCI_ANY_ID || table->func == func)) { + return table; + } + } + + return NULL; +} + +void pci_cfgfunc_config_device(struct pci_controller *hose, + pci_dev_t dev, + struct pci_config_table *entry) +{ + pci_hose_config_device(hose, dev, entry->priv[0], entry->priv[1], entry->priv[2]); +} + +void pci_cfgfunc_do_nothing(struct pci_controller *hose, + pci_dev_t dev, struct pci_config_table *entry) +{ +} + +/* + * + */ + +/* HJF: Changed this to return int. I think this is required + * to get the correct result when scanning bridges + */ +extern int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev); +extern void pciauto_config_init(struct pci_controller *hose); + +int pci_hose_scan_bus(struct pci_controller *hose, int bus) +{ + unsigned int sub_bus, found_multi=0; + unsigned short vendor, device, class; + unsigned char header_type; + struct pci_config_table *cfg; + pci_dev_t dev; + + sub_bus = bus; + + for (dev = PCI_BDF(bus,0,0); + dev < PCI_BDF(bus,PCI_MAX_PCI_DEVICES-1,PCI_MAX_PCI_FUNCTIONS-1); + dev += PCI_BDF(0,0,1)) + { + /* Skip our host bridge */ + if ( dev == PCI_BDF(hose->first_busno,0,0) ) { +#if defined(CONFIG_PCI_CONFIG_HOST_BRIDGE) /* don't skip host bridge */ + /* + * Only skip hostbridge configuration if "pciconfighost" is not set + */ + if (getenv("pciconfighost") == NULL) { + continue; /* Skip our host bridge */ + } +#else + continue; /* Skip our host bridge */ +#endif + } + + if (PCI_FUNC(dev) && !found_multi) + continue; + + pci_hose_read_config_byte(hose, dev, PCI_HEADER_TYPE, &header_type); + + pci_hose_read_config_word(hose, dev, PCI_VENDOR_ID, &vendor); + + if (vendor != 0xffff && vendor != 0x0000) { + + if (!PCI_FUNC(dev)) + found_multi = header_type & 0x80; + + debug ("PCI Scan: Found Bus %d, Device %d, Function %d\n", + PCI_BUS(dev), PCI_DEV(dev), PCI_FUNC(dev) ); + + pci_hose_read_config_word(hose, dev, PCI_DEVICE_ID, &device); + pci_hose_read_config_word(hose, dev, PCI_CLASS_DEVICE, &class); + + cfg = pci_find_config(hose, class, vendor, device, + PCI_BUS(dev), PCI_DEV(dev), PCI_FUNC(dev)); + if (cfg) { + cfg->config_device(hose, dev, cfg); + sub_bus = max(sub_bus, hose->current_busno); +#ifdef CONFIG_PCI_PNP + } else { + int n = pciauto_config_device(hose, dev); + + sub_bus = max(sub_bus, n); +#endif + } + if (hose->fixup_irq) + hose->fixup_irq(hose, dev); + +#ifdef CONFIG_PCI_SCAN_SHOW + /* Skip our host bridge */ + if ( dev != PCI_BDF(hose->first_busno,0,0) ) { + unsigned char int_line; + + pci_hose_read_config_byte(hose, dev, PCI_INTERRUPT_LINE, + &int_line); + printf(" %02x %02x %04x %04x %04x %02x\n", + PCI_BUS(dev), PCI_DEV(dev), vendor, device, class, + int_line); + } +#endif + } + } + + return sub_bus; +} + +int pci_hose_scan(struct pci_controller *hose) +{ + /* Start scan at current_busno. + * PCIe will start scan at first_busno+1. + */ + /* For legacy support, ensure current>=first */ + if (hose->first_busno > hose->current_busno) + hose->current_busno = hose->first_busno; +#ifdef CONFIG_PCI_PNP + pciauto_config_init(hose); +#endif + return pci_hose_scan_bus(hose, hose->current_busno); +} + +void pci_init(void) +{ +#if defined(CONFIG_PCI_BOOTDELAY) + char *s; + int i; + + /* wait "pcidelay" ms (if defined)... */ + s = getenv ("pcidelay"); + if (s) { + int val = simple_strtoul (s, NULL, 10); + for (i=0; i + * + * Copyright 2000 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include + +#ifdef CONFIG_PCI + +#include + +#undef DEBUG +#ifdef DEBUG +#define DEBUGF(x...) printf(x) +#else +#define DEBUGF(x...) +#endif /* DEBUG */ + +#define PCIAUTO_IDE_MODE_MASK 0x05 + +/* the user can define CFG_PCI_CACHE_LINE_SIZE to avoid problems */ +#ifndef CFG_PCI_CACHE_LINE_SIZE +#define CFG_PCI_CACHE_LINE_SIZE 8 +#endif + +/* + * + */ + +void pciauto_region_init(struct pci_region* res) +{ + /* + * Avoid allocating PCI resources from address 0 -- this is illegal + * according to PCI 2.1 and moreover, this is known to cause Linux IDE + * drivers to fail. Use a reasonable starting value of 0x1000 instead. + */ + res->bus_lower = res->bus_start ? res->bus_start : 0x1000; +} + +void pciauto_region_align(struct pci_region *res, unsigned long size) +{ + res->bus_lower = ((res->bus_lower - 1) | (size - 1)) + 1; +} + +int pciauto_region_allocate(struct pci_region* res, unsigned int size, unsigned int *bar) +{ + unsigned long addr; + + if (!res) { + DEBUGF("No resource"); + goto error; + } + + addr = ((res->bus_lower - 1) | (size - 1)) + 1; + + if (addr - res->bus_start + size > res->size) { + DEBUGF("No room in resource"); + goto error; + } + + res->bus_lower = addr + size; + + DEBUGF("address=0x%lx bus_lower=%x", addr, res->bus_lower); + + *bar = addr; + return 0; + + error: + *bar = 0xffffffff; + return -1; +} + +/* + * + */ + +void pciauto_setup_device(struct pci_controller *hose, + pci_dev_t dev, int bars_num, + struct pci_region *mem, + struct pci_region *prefetch, + struct pci_region *io) +{ + unsigned int bar_value, bar_response, bar_size; + unsigned int cmdstat = 0; + struct pci_region *bar_res; + int bar, bar_nr = 0; + int found_mem64 = 0; + + pci_hose_read_config_dword(hose, dev, PCI_COMMAND, &cmdstat); + cmdstat = (cmdstat & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) | PCI_COMMAND_MASTER; + + for (bar = PCI_BASE_ADDRESS_0; bar < PCI_BASE_ADDRESS_0 + (bars_num*4); bar += 4) { + /* Tickle the BAR and get the response */ + pci_hose_write_config_dword(hose, dev, bar, 0xffffffff); + pci_hose_read_config_dword(hose, dev, bar, &bar_response); + + /* If BAR is not implemented go to the next BAR */ + if (!bar_response) + continue; + + found_mem64 = 0; + + /* Check the BAR type and set our address mask */ + if (bar_response & PCI_BASE_ADDRESS_SPACE) { + bar_size = ((~(bar_response & PCI_BASE_ADDRESS_IO_MASK)) + & 0xffff) + 1; + bar_res = io; + + DEBUGF("PCI Autoconfig: BAR %d, I/O, size=0x%x, ", bar_nr, bar_size); + } else { + if ( (bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == + PCI_BASE_ADDRESS_MEM_TYPE_64) + found_mem64 = 1; + + bar_size = ~(bar_response & PCI_BASE_ADDRESS_MEM_MASK) + 1; + if (prefetch && (bar_response & PCI_BASE_ADDRESS_MEM_PREFETCH)) + bar_res = prefetch; + else + bar_res = mem; + + DEBUGF("PCI Autoconfig: BAR %d, Mem, size=0x%x, ", bar_nr, bar_size); + } + + if (pciauto_region_allocate(bar_res, bar_size, &bar_value) == 0) { + /* Write it out and update our limit */ + pci_hose_write_config_dword(hose, dev, bar, bar_value); + + /* + * If we are a 64-bit decoder then increment to the + * upper 32 bits of the bar and force it to locate + * in the lower 4GB of memory. + */ + if (found_mem64) { + bar += 4; + pci_hose_write_config_dword(hose, dev, bar, 0x00000000); + } + + cmdstat |= (bar_response & PCI_BASE_ADDRESS_SPACE) ? + PCI_COMMAND_IO : PCI_COMMAND_MEMORY; + } + + DEBUGF("\n"); + + bar_nr++; + } + + pci_hose_write_config_dword(hose, dev, PCI_COMMAND, cmdstat); + pci_hose_write_config_byte(hose, dev, PCI_CACHE_LINE_SIZE, + CFG_PCI_CACHE_LINE_SIZE); + pci_hose_write_config_byte(hose, dev, PCI_LATENCY_TIMER, 0x80); +} + +void pciauto_prescan_setup_bridge(struct pci_controller *hose, + pci_dev_t dev, int sub_bus) +{ + struct pci_region *pci_mem = hose->pci_mem; + struct pci_region *pci_prefetch = hose->pci_prefetch; + struct pci_region *pci_io = hose->pci_io; + unsigned int cmdstat; + + pci_hose_read_config_dword(hose, dev, PCI_COMMAND, &cmdstat); + + /* Configure bus number registers */ + pci_hose_write_config_byte(hose, dev, PCI_PRIMARY_BUS, + PCI_BUS(dev) - hose->first_busno); + pci_hose_write_config_byte(hose, dev, PCI_SECONDARY_BUS, + sub_bus - hose->first_busno); + pci_hose_write_config_byte(hose, dev, PCI_SUBORDINATE_BUS, 0xff); + + if (pci_mem) { + /* Round memory allocator to 1MB boundary */ + pciauto_region_align(pci_mem, 0x100000); + + /* Set up memory and I/O filter limits, assume 32-bit I/O space */ + pci_hose_write_config_word(hose, dev, PCI_MEMORY_BASE, + (pci_mem->bus_lower & 0xfff00000) >> 16); + + cmdstat |= PCI_COMMAND_MEMORY; + } + + if (pci_prefetch) { + /* Round memory allocator to 1MB boundary */ + pciauto_region_align(pci_prefetch, 0x100000); + + /* Set up memory and I/O filter limits, assume 32-bit I/O space */ + pci_hose_write_config_word(hose, dev, PCI_PREF_MEMORY_BASE, + (pci_prefetch->bus_lower & 0xfff00000) >> 16); + + cmdstat |= PCI_COMMAND_MEMORY; + } else { + /* We don't support prefetchable memory for now, so disable */ + pci_hose_write_config_word(hose, dev, PCI_PREF_MEMORY_BASE, 0x1000); + pci_hose_write_config_word(hose, dev, PCI_PREF_MEMORY_LIMIT, 0x0); + } + + if (pci_io) { + /* Round I/O allocator to 4KB boundary */ + pciauto_region_align(pci_io, 0x1000); + + pci_hose_write_config_byte(hose, dev, PCI_IO_BASE, + (pci_io->bus_lower & 0x0000f000) >> 8); + pci_hose_write_config_word(hose, dev, PCI_IO_BASE_UPPER16, + (pci_io->bus_lower & 0xffff0000) >> 16); + + cmdstat |= PCI_COMMAND_IO; + } + + /* Enable memory and I/O accesses, enable bus master */ + pci_hose_write_config_dword(hose, dev, PCI_COMMAND, cmdstat | PCI_COMMAND_MASTER); +} + +void pciauto_postscan_setup_bridge(struct pci_controller *hose, + pci_dev_t dev, int sub_bus) +{ + struct pci_region *pci_mem = hose->pci_mem; + struct pci_region *pci_prefetch = hose->pci_prefetch; + struct pci_region *pci_io = hose->pci_io; + + /* Configure bus number registers */ + pci_hose_write_config_byte(hose, dev, PCI_SUBORDINATE_BUS, + sub_bus - hose->first_busno); + + if (pci_mem) { + /* Round memory allocator to 1MB boundary */ + pciauto_region_align(pci_mem, 0x100000); + + pci_hose_write_config_word(hose, dev, PCI_MEMORY_LIMIT, + (pci_mem->bus_lower-1) >> 16); + } + + if (pci_prefetch) { + /* Round memory allocator to 1MB boundary */ + pciauto_region_align(pci_prefetch, 0x100000); + + pci_hose_write_config_word(hose, dev, PCI_PREF_MEMORY_LIMIT, + (pci_prefetch->bus_lower-1) >> 16); + } + + if (pci_io) { + /* Round I/O allocator to 4KB boundary */ + pciauto_region_align(pci_io, 0x1000); + + pci_hose_write_config_byte(hose, dev, PCI_IO_LIMIT, + ((pci_io->bus_lower-1) & 0x0000f000) >> 8); + pci_hose_write_config_word(hose, dev, PCI_IO_LIMIT_UPPER16, + ((pci_io->bus_lower-1) & 0xffff0000) >> 16); + } +} + +/* + * + */ + +void pciauto_config_init(struct pci_controller *hose) +{ + int i; + + hose->pci_io = hose->pci_mem = NULL; + + for (i=0; iregion_count; i++) { + switch(hose->regions[i].flags) { + case PCI_REGION_IO: + if (!hose->pci_io || + hose->pci_io->size < hose->regions[i].size) + hose->pci_io = hose->regions + i; + break; + case PCI_REGION_MEM: + if (!hose->pci_mem || + hose->pci_mem->size < hose->regions[i].size) + hose->pci_mem = hose->regions + i; + break; + case (PCI_REGION_MEM | PCI_REGION_PREFETCH): + if (!hose->pci_prefetch || + hose->pci_prefetch->size < hose->regions[i].size) + hose->pci_prefetch = hose->regions + i; + break; + } + } + + + if (hose->pci_mem) { + pciauto_region_init(hose->pci_mem); + + DEBUGF("PCI Autoconfig: Bus Memory region: [%lx-%lx],\n" + "\t\tPhysical Memory [%x-%x]\n", + hose->pci_mem->bus_start, + hose->pci_mem->bus_start + hose->pci_mem->size - 1, + hose->pci_mem->phys_start, + hose->pci_mem->phys_start + hose->pci_mem->size - 1); + } + + if (hose->pci_prefetch) { + pciauto_region_init(hose->pci_prefetch); + + DEBUGF("PCI Autoconfig: Bus Prefetchable Mem: [%lx-%lx],\n" + "\t\tPhysical Memory [%x-%x]\n", + hose->pci_prefetch->bus_start, + hose->pci_prefetch->bus_start + hose->pci_prefetch->size - 1, + hose->pci_prefetch->phys_start, + hose->pci_prefetch->phys_start + + hose->pci_prefetch->size - 1); + } + + if (hose->pci_io) { + pciauto_region_init(hose->pci_io); + + DEBUGF("PCI Autoconfig: Bus I/O region: [%lx-%lx],\n" + "\t\tPhysical Memory: [%x-%x]\n", + hose->pci_io->bus_start, + hose->pci_io->bus_start + hose->pci_io->size - 1, + hose->pci_io->phys_start, + hose->pci_io->phys_start + hose->pci_io->size - 1); + + } +} + +/* HJF: Changed this to return int. I think this is required + * to get the correct result when scanning bridges + */ +int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev) +{ + unsigned int sub_bus = PCI_BUS(dev); + unsigned short class; + unsigned char prg_iface; + int n; + + pci_hose_read_config_word(hose, dev, PCI_CLASS_DEVICE, &class); + + switch(class) { + case PCI_CLASS_PROCESSOR_POWERPC: /* an agent or end-point */ + DEBUGF("PCI AutoConfig: Found PowerPC device\n"); + pciauto_setup_device(hose, dev, 6, hose->pci_mem, + hose->pci_prefetch, hose->pci_io); + break; + + case PCI_CLASS_BRIDGE_PCI: + hose->current_busno++; + pciauto_setup_device(hose, dev, 2, hose->pci_mem, hose->pci_prefetch, hose->pci_io); + + DEBUGF("PCI Autoconfig: Found P2P bridge, device %d\n", PCI_DEV(dev)); + + /* Passing in current_busno allows for sibling P2P bridges */ + pciauto_prescan_setup_bridge(hose, dev, hose->current_busno); + /* + * need to figure out if this is a subordinate bridge on the bus + * to be able to properly set the pri/sec/sub bridge registers. + */ + n = pci_hose_scan_bus(hose, hose->current_busno); + + /* figure out the deepest we've gone for this leg */ + sub_bus = max(n, sub_bus); + pciauto_postscan_setup_bridge(hose, dev, sub_bus); + + sub_bus = hose->current_busno; + break; + + case PCI_CLASS_STORAGE_IDE: + pci_hose_read_config_byte(hose, dev, PCI_CLASS_PROG, &prg_iface); + if (!(prg_iface & PCIAUTO_IDE_MODE_MASK)) { + DEBUGF("PCI Autoconfig: Skipping legacy mode IDE controller\n"); + return sub_bus; + } + + pciauto_setup_device(hose, dev, 6, hose->pci_mem, hose->pci_prefetch, hose->pci_io); + break; + + case PCI_CLASS_BRIDGE_CARDBUS: + /* just do a minimal setup of the bridge, let the OS take care of the rest */ + pciauto_setup_device(hose, dev, 0, hose->pci_mem, hose->pci_prefetch, hose->pci_io); + + DEBUGF("PCI Autoconfig: Found P2CardBus bridge, device %d\n", PCI_DEV(dev)); + + hose->current_busno++; + break; + +#ifdef CONFIG_MPC5200 + case PCI_CLASS_BRIDGE_OTHER: + DEBUGF("PCI Autoconfig: Skipping bridge device %d\n", + PCI_DEV(dev)); + break; +#endif +#ifdef CONFIG_MPC834X + case PCI_CLASS_BRIDGE_OTHER: + /* + * The host/PCI bridge 1 seems broken in 8349 - it presents + * itself as 'PCI_CLASS_BRIDGE_OTHER' and appears as an _agent_ + * device claiming resources io/mem/irq.. we only allow for + * the PIMMR window to be allocated (BAR0 - 1MB size) + */ + DEBUGF("PCI Autoconfig: Broken bridge found, only minimal config\n"); + pciauto_setup_device(hose, dev, 0, hose->pci_mem, hose->pci_prefetch, hose->pci_io); + break; +#endif + default: + pciauto_setup_device(hose, dev, 6, hose->pci_mem, hose->pci_prefetch, hose->pci_io); + break; + } + + return sub_bus; +} + +#endif /* CONFIG_PCI */ diff --git a/drivers/pci/pci_indirect.c b/drivers/pci/pci_indirect.c new file mode 100644 index 0000000000..a8220fb411 --- /dev/null +++ b/drivers/pci/pci_indirect.c @@ -0,0 +1,138 @@ +/* + * Support for indirect PCI bridges. + * + * Copyright (C) 1998 Gabriel Paubert. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include + +#ifdef CONFIG_PCI +#if (!defined(__I386__) && !defined(CONFIG_IXDP425)) + +#include +#include +#include + +#define cfg_read(val, addr, type, op) *val = op((type)(addr)) +#define cfg_write(val, addr, type, op) op((type *)(addr), (val)) + +#ifdef CONFIG_IXP425 +extern unsigned char in_8 (volatile unsigned *addr); +extern unsigned short in_le16 (volatile unsigned *addr); +extern unsigned in_le32 (volatile unsigned *addr); +extern void out_8 (volatile unsigned *addr, char val); +extern void out_le16 (volatile unsigned *addr, unsigned short val); +extern void out_le32 (volatile unsigned *addr, unsigned int val); +#endif /* CONFIG_IXP425 */ + +#if defined(CONFIG_MPC8260) +#define INDIRECT_PCI_OP(rw, size, type, op, mask) \ +static int \ +indirect_##rw##_config_##size(struct pci_controller *hose, \ + pci_dev_t dev, int offset, type val) \ +{ \ + u32 b, d,f; \ + b = PCI_BUS(dev); d = PCI_DEV(dev); f = PCI_FUNC(dev); \ + b = b - hose->first_busno; \ + dev = PCI_BDF(b, d, f); \ + out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000); \ + sync(); \ + cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \ + return 0; \ +} +#elif defined(CONFIG_E500) || defined(CONFIG_MPC86xx) +#define INDIRECT_PCI_OP(rw, size, type, op, mask) \ +static int \ +indirect_##rw##_config_##size(struct pci_controller *hose, \ + pci_dev_t dev, int offset, type val) \ +{ \ + u32 b, d,f; \ + b = PCI_BUS(dev); d = PCI_DEV(dev); f = PCI_FUNC(dev); \ + b = b - hose->first_busno; \ + dev = PCI_BDF(b, d, f); \ + *(hose->cfg_addr) = dev | (offset & 0xfc) | ((offset & 0xf00) << 16) | 0x80000000; \ + sync(); \ + cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \ + return 0; \ +} +#elif defined(CONFIG_440GX) || defined(CONFIG_440EP) || defined(CONFIG_440GR) || defined(CONFIG_440SPE) +#define INDIRECT_PCI_OP(rw, size, type, op, mask) \ +static int \ +indirect_##rw##_config_##size(struct pci_controller *hose, \ + pci_dev_t dev, int offset, type val) \ +{ \ + u32 b, d,f; \ + b = PCI_BUS(dev); d = PCI_DEV(dev); f = PCI_FUNC(dev); \ + b = b - hose->first_busno; \ + dev = PCI_BDF(b, d, f); \ + if (PCI_BUS(dev) > 0) \ + out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000001); \ + else \ + out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000); \ + cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \ + return 0; \ +} +#else +#define INDIRECT_PCI_OP(rw, size, type, op, mask) \ +static int \ +indirect_##rw##_config_##size(struct pci_controller *hose, \ + pci_dev_t dev, int offset, type val) \ +{ \ + u32 b, d,f; \ + b = PCI_BUS(dev); d = PCI_DEV(dev); f = PCI_FUNC(dev); \ + b = b - hose->first_busno; \ + dev = PCI_BDF(b, d, f); \ + out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000); \ + cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \ + return 0; \ +} +#endif + +#define INDIRECT_PCI_OP_ERRATA6(rw, size, type, op, mask) \ +static int \ +indirect_##rw##_config_##size(struct pci_controller *hose, \ + pci_dev_t dev, int offset, type val) \ +{ \ + unsigned int msr = mfmsr(); \ + mtmsr(msr & ~(MSR_EE | MSR_CE)); \ + out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000); \ + cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \ + out_le32(hose->cfg_addr, 0x00000000); \ + mtmsr(msr); \ + return 0; \ +} + +INDIRECT_PCI_OP(read, byte, u8 *, in_8, 3) +INDIRECT_PCI_OP(read, word, u16 *, in_le16, 2) +INDIRECT_PCI_OP(read, dword, u32 *, in_le32, 0) +#ifdef CONFIG_405GP +INDIRECT_PCI_OP_ERRATA6(write, byte, u8, out_8, 3) +INDIRECT_PCI_OP_ERRATA6(write, word, u16, out_le16, 2) +INDIRECT_PCI_OP_ERRATA6(write, dword, u32, out_le32, 0) +#else +INDIRECT_PCI_OP(write, byte, u8, out_8, 3) +INDIRECT_PCI_OP(write, word, u16, out_le16, 2) +INDIRECT_PCI_OP(write, dword, u32, out_le32, 0) +#endif + +void pci_setup_indirect(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data) +{ + pci_set_ops(hose, + indirect_read_config_byte, + indirect_read_config_word, + indirect_read_config_dword, + indirect_write_config_byte, + indirect_write_config_word, + indirect_write_config_dword); + + hose->cfg_addr = (unsigned int *) cfg_addr; + hose->cfg_data = (unsigned char *) cfg_data; +} + +#endif /* !__I386__ && !CONFIG_IXDP425 */ +#endif /* CONFIG_PCI */ diff --git a/drivers/pci/tsi108_pci.c b/drivers/pci/tsi108_pci.c new file mode 100644 index 0000000000..d5f11e42f0 --- /dev/null +++ b/drivers/pci/tsi108_pci.c @@ -0,0 +1,181 @@ +/* + * (C) Copyright 2004 Tundra Semiconductor Corp. + * Alex Bounine + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * PCI initialisation for the Tsi108 EMU board. + */ + +#include + +#ifdef CONFIG_TSI108_PCI + +#include +#include +#include +#include +#ifdef CONFIG_OF_FLAT_TREE +#include +#endif + +struct pci_controller local_hose; + +void tsi108_clear_pci_error (void) +{ + u32 err_stat, err_addr, pci_stat; + + /* + * Quietly clear errors signalled as result of PCI/X configuration read + * requests. + */ + /* Read PB Error Log Registers */ + err_stat = *(volatile u32 *)(CFG_TSI108_CSR_BASE + + TSI108_PB_REG_OFFSET + PB_ERRCS); + err_addr = *(volatile u32 *)(CFG_TSI108_CSR_BASE + + TSI108_PB_REG_OFFSET + PB_AERR); + if (err_stat & PB_ERRCS_ES) { + /* Clear PCI/X bus errors if applicable */ + if ((err_addr & 0xFF000000) == CFG_PCI_CFG_BASE) { + /* Clear error flag */ + *(u32 *) (CFG_TSI108_CSR_BASE + + TSI108_PB_REG_OFFSET + PB_ERRCS) = + PB_ERRCS_ES; + + /* Clear read error reported in PB_ISR */ + *(u32 *) (CFG_TSI108_CSR_BASE + + TSI108_PB_REG_OFFSET + PB_ISR) = + PB_ISR_PBS_RD_ERR; + + /* Clear errors reported by PCI CSR (Normally Master Abort) */ + pci_stat = *(volatile u32 *)(CFG_TSI108_CSR_BASE + + TSI108_PCI_REG_OFFSET + + PCI_CSR); + *(volatile u32 *)(CFG_TSI108_CSR_BASE + + TSI108_PCI_REG_OFFSET + PCI_CSR) = + pci_stat; + + *(volatile u32 *)(CFG_TSI108_CSR_BASE + + TSI108_PCI_REG_OFFSET + + PCI_IRP_STAT) = PCI_IRP_STAT_P_CSR; + } + } + + return; +} + +unsigned int __get_pci_config_dword (u32 addr) +{ + unsigned int retval; + + __asm__ __volatile__ (" lwbrx %0,0,%1\n" + "1: eieio\n" + "2:\n" + ".section .fixup,\"ax\"\n" + "3: li %0,-1\n" + " b 2b\n" + ".section __ex_table,\"a\"\n" + " .align 2\n" + " .long 1b,3b\n" + ".text":"=r"(retval):"r"(addr)); + + return (retval); +} + +static int tsi108_read_config_dword (struct pci_controller *hose, + pci_dev_t dev, int offset, u32 * value) +{ + dev &= (CFG_PCI_CFG_SIZE - 1); + dev |= (CFG_PCI_CFG_BASE | (offset & 0xfc)); + *value = __get_pci_config_dword(dev); + if (0xFFFFFFFF == *value) + tsi108_clear_pci_error (); + return 0; +} + +static int tsi108_write_config_dword (struct pci_controller *hose, + pci_dev_t dev, int offset, u32 value) +{ + dev &= (CFG_PCI_CFG_SIZE - 1); + dev |= (CFG_PCI_CFG_BASE | (offset & 0xfc)); + + out_le32 ((volatile unsigned *)dev, value); + + return 0; +} + +void pci_init_board (void) +{ + struct pci_controller *hose = (struct pci_controller *)&local_hose; + + hose->first_busno = 0; + hose->last_busno = 0xff; + + pci_set_region (hose->regions + 0, + CFG_PCI_MEMORY_BUS, + CFG_PCI_MEMORY_PHYS, + CFG_PCI_MEMORY_SIZE, PCI_REGION_MEM | PCI_REGION_MEMORY); + + /* PCI memory space */ + pci_set_region (hose->regions + 1, + CFG_PCI_MEM_BUS, + CFG_PCI_MEM_PHYS, CFG_PCI_MEM_SIZE, PCI_REGION_MEM); + + /* PCI I/O space */ + pci_set_region (hose->regions + 2, + CFG_PCI_IO_BUS, + CFG_PCI_IO_PHYS, CFG_PCI_IO_SIZE, PCI_REGION_IO); + + hose->region_count = 3; + + pci_set_ops (hose, + pci_hose_read_config_byte_via_dword, + pci_hose_read_config_word_via_dword, + tsi108_read_config_dword, + pci_hose_write_config_byte_via_dword, + pci_hose_write_config_word_via_dword, + tsi108_write_config_dword); + + pci_register_hose (hose); + + hose->last_busno = pci_hose_scan (hose); + + debug ("Done PCI initialization\n"); + return; +} + +#ifdef CONFIG_OF_FLAT_TREE +void +ft_pci_setup (void *blob, bd_t *bd) +{ + u32 *p; + int len; + + p = (u32 *)ft_get_prop (blob, "/" OF_TSI "/pci@1000/bus-range", &len); + if (p != NULL) { + p[0] = local_hose.first_busno; + p[1] = local_hose.last_busno; + } + +} +#endif + +#endif /* CONFIG_TSI108_PCI */ diff --git a/drivers/pci/w83c553f.c b/drivers/pci/w83c553f.c new file mode 100644 index 0000000000..5d82ed4dd4 --- /dev/null +++ b/drivers/pci/w83c553f.c @@ -0,0 +1,226 @@ +/* + * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH + * Andreas Heppel + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * Initialisation of the PCI-to-ISA bridge and disabling the BIOS + * write protection (for flash) in function 0 of the chip. + * Enabling function 1 (IDE controller of the chip. + */ + +#include +#include + +#ifdef CFG_WINBOND_83C553 + +#include +#include + +#include + +#define out8(addr,val) do { \ + out_8((u8*) (addr),(val)); udelay(1); \ + } while (0) +#define out16(addr,val) do { \ + out_be16((u16*) (addr),(val)); udelay(1); \ + } while (0) + +extern uint ide_bus_offset[CFG_IDE_MAXBUS]; + +void initialise_pic(void); +void initialise_dma(void); + +void initialise_w83c553f(void) +{ + pci_dev_t devbusfn; + unsigned char reg8; + unsigned short reg16; + unsigned int reg32; + + devbusfn = pci_find_device(W83C553F_VID, W83C553F_DID, 0); + if (devbusfn == -1) + { + printf("Error: Cannot find W83C553F controller on any PCI bus."); + return; + } + + pci_read_config_word(devbusfn, PCI_COMMAND, ®16); + reg16 |= PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; + pci_write_config_word(devbusfn, PCI_COMMAND, reg16); + + pci_read_config_byte(devbusfn, WINBOND_IPADCR, ®8); + /* 16 MB ISA memory space */ + reg8 |= (IPADCR_IPATOM4 | IPADCR_IPATOM5 | IPADCR_IPATOM6 | IPADCR_IPATOM7); + reg8 &= ~IPADCR_MBE512; + pci_write_config_byte(devbusfn, WINBOND_IPADCR, reg8); + + pci_read_config_byte(devbusfn, WINBOND_CSCR, ®8); + /* switch off BIOS write protection */ + reg8 |= CSCR_UBIOSCSE; + reg8 &= ~CSCR_BIOSWP; + pci_write_config_byte(devbusfn, WINBOND_CSCR, reg8); + + /* + * Interrupt routing: + * - IDE -> IRQ 9/0 + * - INTA -> IRQ 10 + * - INTB -> IRQ 11 + * - INTC -> IRQ 14 + * - INTD -> IRQ 15 + */ + pci_write_config_byte(devbusfn, WINBOND_IDEIRCR, 0x90); + pci_write_config_word(devbusfn, WINBOND_PCIIRCR, 0xABEF); + + /* + * Read IDE bus offsets from function 1 device. + * We must unmask the LSB indicating that ist is an IO address. + */ + devbusfn |= PCI_BDF(0,0,1); + + /* + * Switch off legacy IRQ for IDE and IDE port 1. + */ + pci_write_config_byte(devbusfn, 0x09, 0x8F); + + pci_read_config_dword(devbusfn, WINDOND_IDECSR, ®32); + reg32 &= ~(IDECSR_LEGIRQ | IDECSR_P1EN | IDECSR_P1F16); + pci_write_config_dword(devbusfn, WINDOND_IDECSR, reg32); + + pci_read_config_dword(devbusfn, PCI_BASE_ADDRESS_0, &ide_bus_offset[0]); + ide_bus_offset[0] &= ~1; +#if CFG_IDE_MAXBUS > 1 + pci_read_config_dword(devbusfn, PCI_BASE_ADDRESS_2, &ide_bus_offset[1]); + ide_bus_offset[1] &= ~1; +#endif + + /* + * Enable function 1, IDE -> busmastering and IO space access + */ + pci_read_config_word(devbusfn, PCI_COMMAND, ®16); + reg16 |= PCI_COMMAND_MASTER | PCI_COMMAND_IO; + pci_write_config_word(devbusfn, PCI_COMMAND, reg16); + + /* + * Initialise ISA interrupt controller + */ + initialise_pic(); + + /* + * Initialise DMA controller + */ + initialise_dma(); +} + +void initialise_pic(void) +{ + out8(W83C553F_PIC1_ICW1, 0x11); + out8(W83C553F_PIC1_ICW2, 0x08); + out8(W83C553F_PIC1_ICW3, 0x04); + out8(W83C553F_PIC1_ICW4, 0x01); + out8(W83C553F_PIC1_OCW1, 0xfb); + out8(W83C553F_PIC1_ELC, 0x20); + + out8(W83C553F_PIC2_ICW1, 0x11); + out8(W83C553F_PIC2_ICW2, 0x08); + out8(W83C553F_PIC2_ICW3, 0x02); + out8(W83C553F_PIC2_ICW4, 0x01); + out8(W83C553F_PIC2_OCW1, 0xff); + out8(W83C553F_PIC2_ELC, 0xce); + + out8(W83C553F_TMR1_CMOD, 0x74); + + out8(W83C553F_PIC2_OCW1, 0x20); + out8(W83C553F_PIC1_OCW1, 0x20); + + out8(W83C553F_PIC2_OCW1, 0x2b); + out8(W83C553F_PIC1_OCW1, 0x2b); +} + +void initialise_dma(void) +{ + unsigned int channel; + unsigned int rvalue1, rvalue2; + + /* perform a H/W reset of the devices */ + + out8(W83C553F_DMA1 + W83C553F_DMA1_MC, 0x00); + out16(W83C553F_DMA2 + W83C553F_DMA2_MC, 0x0000); + + /* initialise all channels to a sane state */ + + for (channel = 0; channel < 4; channel++) { + /* + * dependent upon the channel, setup the specifics: + * + * demand + * address-increment + * autoinitialize-disable + * verify-transfer + */ + + switch (channel) { + case 0: + rvalue1 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH0SEL|W83C553F_MODE_TT_VERIFY); + rvalue2 = (W83C553F_MODE_TM_CASCADE|W83C553F_MODE_CH0SEL); + break; + case 1: + rvalue1 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH1SEL|W83C553F_MODE_TT_VERIFY); + rvalue2 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH1SEL|W83C553F_MODE_TT_VERIFY); + break; + case 2: + rvalue1 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH2SEL|W83C553F_MODE_TT_VERIFY); + rvalue2 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH2SEL|W83C553F_MODE_TT_VERIFY); + break; + case 3: + rvalue1 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH3SEL|W83C553F_MODE_TT_VERIFY); + rvalue2 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH3SEL|W83C553F_MODE_TT_VERIFY); + break; + default: + rvalue1 = 0x00; + rvalue2 = 0x00; + break; + } + + /* write to write mode registers */ + + out8(W83C553F_DMA1 + W83C553F_DMA1_WM, rvalue1 & 0xFF); + out16(W83C553F_DMA2 + W83C553F_DMA2_WM, rvalue2 & 0x00FF); + } + + /* enable all channels */ + + out8(W83C553F_DMA1 + W83C553F_DMA1_CM, 0x00); + out16(W83C553F_DMA2 + W83C553F_DMA2_CM, 0x0000); + /* + * initialize the global DMA configuration + * + * DACK# active low + * DREQ active high + * fixed priority + * channel group enable + */ + + out8(W83C553F_DMA1 + W83C553F_DMA1_CS, 0x00); + out16(W83C553F_DMA2 + W83C553F_DMA2_CS, 0x0000); +} + +#endif /* CFG_WINBOND_83C553 */ diff --git a/drivers/pci_auto.c b/drivers/pci_auto.c deleted file mode 100644 index acfda83ba5..0000000000 --- a/drivers/pci_auto.c +++ /dev/null @@ -1,412 +0,0 @@ -/* - * arch/ppc/kernel/pci_auto.c - * - * PCI autoconfiguration library - * - * Author: Matt Porter - * - * Copyright 2000 MontaVista Software Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#include - -#ifdef CONFIG_PCI - -#include - -#undef DEBUG -#ifdef DEBUG -#define DEBUGF(x...) printf(x) -#else -#define DEBUGF(x...) -#endif /* DEBUG */ - -#define PCIAUTO_IDE_MODE_MASK 0x05 - -/* the user can define CFG_PCI_CACHE_LINE_SIZE to avoid problems */ -#ifndef CFG_PCI_CACHE_LINE_SIZE -#define CFG_PCI_CACHE_LINE_SIZE 8 -#endif - -/* - * - */ - -void pciauto_region_init(struct pci_region* res) -{ - /* - * Avoid allocating PCI resources from address 0 -- this is illegal - * according to PCI 2.1 and moreover, this is known to cause Linux IDE - * drivers to fail. Use a reasonable starting value of 0x1000 instead. - */ - res->bus_lower = res->bus_start ? res->bus_start : 0x1000; -} - -void pciauto_region_align(struct pci_region *res, unsigned long size) -{ - res->bus_lower = ((res->bus_lower - 1) | (size - 1)) + 1; -} - -int pciauto_region_allocate(struct pci_region* res, unsigned int size, unsigned int *bar) -{ - unsigned long addr; - - if (!res) { - DEBUGF("No resource"); - goto error; - } - - addr = ((res->bus_lower - 1) | (size - 1)) + 1; - - if (addr - res->bus_start + size > res->size) { - DEBUGF("No room in resource"); - goto error; - } - - res->bus_lower = addr + size; - - DEBUGF("address=0x%lx bus_lower=%x", addr, res->bus_lower); - - *bar = addr; - return 0; - - error: - *bar = 0xffffffff; - return -1; -} - -/* - * - */ - -void pciauto_setup_device(struct pci_controller *hose, - pci_dev_t dev, int bars_num, - struct pci_region *mem, - struct pci_region *prefetch, - struct pci_region *io) -{ - unsigned int bar_value, bar_response, bar_size; - unsigned int cmdstat = 0; - struct pci_region *bar_res; - int bar, bar_nr = 0; - int found_mem64 = 0; - - pci_hose_read_config_dword(hose, dev, PCI_COMMAND, &cmdstat); - cmdstat = (cmdstat & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) | PCI_COMMAND_MASTER; - - for (bar = PCI_BASE_ADDRESS_0; bar < PCI_BASE_ADDRESS_0 + (bars_num*4); bar += 4) { - /* Tickle the BAR and get the response */ - pci_hose_write_config_dword(hose, dev, bar, 0xffffffff); - pci_hose_read_config_dword(hose, dev, bar, &bar_response); - - /* If BAR is not implemented go to the next BAR */ - if (!bar_response) - continue; - - found_mem64 = 0; - - /* Check the BAR type and set our address mask */ - if (bar_response & PCI_BASE_ADDRESS_SPACE) { - bar_size = ((~(bar_response & PCI_BASE_ADDRESS_IO_MASK)) - & 0xffff) + 1; - bar_res = io; - - DEBUGF("PCI Autoconfig: BAR %d, I/O, size=0x%x, ", bar_nr, bar_size); - } else { - if ( (bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == - PCI_BASE_ADDRESS_MEM_TYPE_64) - found_mem64 = 1; - - bar_size = ~(bar_response & PCI_BASE_ADDRESS_MEM_MASK) + 1; - if (prefetch && (bar_response & PCI_BASE_ADDRESS_MEM_PREFETCH)) - bar_res = prefetch; - else - bar_res = mem; - - DEBUGF("PCI Autoconfig: BAR %d, Mem, size=0x%x, ", bar_nr, bar_size); - } - - if (pciauto_region_allocate(bar_res, bar_size, &bar_value) == 0) { - /* Write it out and update our limit */ - pci_hose_write_config_dword(hose, dev, bar, bar_value); - - /* - * If we are a 64-bit decoder then increment to the - * upper 32 bits of the bar and force it to locate - * in the lower 4GB of memory. - */ - if (found_mem64) { - bar += 4; - pci_hose_write_config_dword(hose, dev, bar, 0x00000000); - } - - cmdstat |= (bar_response & PCI_BASE_ADDRESS_SPACE) ? - PCI_COMMAND_IO : PCI_COMMAND_MEMORY; - } - - DEBUGF("\n"); - - bar_nr++; - } - - pci_hose_write_config_dword(hose, dev, PCI_COMMAND, cmdstat); - pci_hose_write_config_byte(hose, dev, PCI_CACHE_LINE_SIZE, - CFG_PCI_CACHE_LINE_SIZE); - pci_hose_write_config_byte(hose, dev, PCI_LATENCY_TIMER, 0x80); -} - -void pciauto_prescan_setup_bridge(struct pci_controller *hose, - pci_dev_t dev, int sub_bus) -{ - struct pci_region *pci_mem = hose->pci_mem; - struct pci_region *pci_prefetch = hose->pci_prefetch; - struct pci_region *pci_io = hose->pci_io; - unsigned int cmdstat; - - pci_hose_read_config_dword(hose, dev, PCI_COMMAND, &cmdstat); - - /* Configure bus number registers */ - pci_hose_write_config_byte(hose, dev, PCI_PRIMARY_BUS, - PCI_BUS(dev) - hose->first_busno); - pci_hose_write_config_byte(hose, dev, PCI_SECONDARY_BUS, - sub_bus - hose->first_busno); - pci_hose_write_config_byte(hose, dev, PCI_SUBORDINATE_BUS, 0xff); - - if (pci_mem) { - /* Round memory allocator to 1MB boundary */ - pciauto_region_align(pci_mem, 0x100000); - - /* Set up memory and I/O filter limits, assume 32-bit I/O space */ - pci_hose_write_config_word(hose, dev, PCI_MEMORY_BASE, - (pci_mem->bus_lower & 0xfff00000) >> 16); - - cmdstat |= PCI_COMMAND_MEMORY; - } - - if (pci_prefetch) { - /* Round memory allocator to 1MB boundary */ - pciauto_region_align(pci_prefetch, 0x100000); - - /* Set up memory and I/O filter limits, assume 32-bit I/O space */ - pci_hose_write_config_word(hose, dev, PCI_PREF_MEMORY_BASE, - (pci_prefetch->bus_lower & 0xfff00000) >> 16); - - cmdstat |= PCI_COMMAND_MEMORY; - } else { - /* We don't support prefetchable memory for now, so disable */ - pci_hose_write_config_word(hose, dev, PCI_PREF_MEMORY_BASE, 0x1000); - pci_hose_write_config_word(hose, dev, PCI_PREF_MEMORY_LIMIT, 0x0); - } - - if (pci_io) { - /* Round I/O allocator to 4KB boundary */ - pciauto_region_align(pci_io, 0x1000); - - pci_hose_write_config_byte(hose, dev, PCI_IO_BASE, - (pci_io->bus_lower & 0x0000f000) >> 8); - pci_hose_write_config_word(hose, dev, PCI_IO_BASE_UPPER16, - (pci_io->bus_lower & 0xffff0000) >> 16); - - cmdstat |= PCI_COMMAND_IO; - } - - /* Enable memory and I/O accesses, enable bus master */ - pci_hose_write_config_dword(hose, dev, PCI_COMMAND, cmdstat | PCI_COMMAND_MASTER); -} - -void pciauto_postscan_setup_bridge(struct pci_controller *hose, - pci_dev_t dev, int sub_bus) -{ - struct pci_region *pci_mem = hose->pci_mem; - struct pci_region *pci_prefetch = hose->pci_prefetch; - struct pci_region *pci_io = hose->pci_io; - - /* Configure bus number registers */ - pci_hose_write_config_byte(hose, dev, PCI_SUBORDINATE_BUS, - sub_bus - hose->first_busno); - - if (pci_mem) { - /* Round memory allocator to 1MB boundary */ - pciauto_region_align(pci_mem, 0x100000); - - pci_hose_write_config_word(hose, dev, PCI_MEMORY_LIMIT, - (pci_mem->bus_lower-1) >> 16); - } - - if (pci_prefetch) { - /* Round memory allocator to 1MB boundary */ - pciauto_region_align(pci_prefetch, 0x100000); - - pci_hose_write_config_word(hose, dev, PCI_PREF_MEMORY_LIMIT, - (pci_prefetch->bus_lower-1) >> 16); - } - - if (pci_io) { - /* Round I/O allocator to 4KB boundary */ - pciauto_region_align(pci_io, 0x1000); - - pci_hose_write_config_byte(hose, dev, PCI_IO_LIMIT, - ((pci_io->bus_lower-1) & 0x0000f000) >> 8); - pci_hose_write_config_word(hose, dev, PCI_IO_LIMIT_UPPER16, - ((pci_io->bus_lower-1) & 0xffff0000) >> 16); - } -} - -/* - * - */ - -void pciauto_config_init(struct pci_controller *hose) -{ - int i; - - hose->pci_io = hose->pci_mem = NULL; - - for (i=0; iregion_count; i++) { - switch(hose->regions[i].flags) { - case PCI_REGION_IO: - if (!hose->pci_io || - hose->pci_io->size < hose->regions[i].size) - hose->pci_io = hose->regions + i; - break; - case PCI_REGION_MEM: - if (!hose->pci_mem || - hose->pci_mem->size < hose->regions[i].size) - hose->pci_mem = hose->regions + i; - break; - case (PCI_REGION_MEM | PCI_REGION_PREFETCH): - if (!hose->pci_prefetch || - hose->pci_prefetch->size < hose->regions[i].size) - hose->pci_prefetch = hose->regions + i; - break; - } - } - - - if (hose->pci_mem) { - pciauto_region_init(hose->pci_mem); - - DEBUGF("PCI Autoconfig: Bus Memory region: [%lx-%lx],\n" - "\t\tPhysical Memory [%x-%x]\n", - hose->pci_mem->bus_start, - hose->pci_mem->bus_start + hose->pci_mem->size - 1, - hose->pci_mem->phys_start, - hose->pci_mem->phys_start + hose->pci_mem->size - 1); - } - - if (hose->pci_prefetch) { - pciauto_region_init(hose->pci_prefetch); - - DEBUGF("PCI Autoconfig: Bus Prefetchable Mem: [%lx-%lx],\n" - "\t\tPhysical Memory [%x-%x]\n", - hose->pci_prefetch->bus_start, - hose->pci_prefetch->bus_start + hose->pci_prefetch->size - 1, - hose->pci_prefetch->phys_start, - hose->pci_prefetch->phys_start + - hose->pci_prefetch->size - 1); - } - - if (hose->pci_io) { - pciauto_region_init(hose->pci_io); - - DEBUGF("PCI Autoconfig: Bus I/O region: [%lx-%lx],\n" - "\t\tPhysical Memory: [%x-%x]\n", - hose->pci_io->bus_start, - hose->pci_io->bus_start + hose->pci_io->size - 1, - hose->pci_io->phys_start, - hose->pci_io->phys_start + hose->pci_io->size - 1); - - } -} - -/* HJF: Changed this to return int. I think this is required - * to get the correct result when scanning bridges - */ -int pciauto_config_device(struct pci_controller *hose, pci_dev_t dev) -{ - unsigned int sub_bus = PCI_BUS(dev); - unsigned short class; - unsigned char prg_iface; - int n; - - pci_hose_read_config_word(hose, dev, PCI_CLASS_DEVICE, &class); - - switch(class) { - case PCI_CLASS_PROCESSOR_POWERPC: /* an agent or end-point */ - DEBUGF("PCI AutoConfig: Found PowerPC device\n"); - pciauto_setup_device(hose, dev, 6, hose->pci_mem, - hose->pci_prefetch, hose->pci_io); - break; - - case PCI_CLASS_BRIDGE_PCI: - hose->current_busno++; - pciauto_setup_device(hose, dev, 2, hose->pci_mem, hose->pci_prefetch, hose->pci_io); - - DEBUGF("PCI Autoconfig: Found P2P bridge, device %d\n", PCI_DEV(dev)); - - /* Passing in current_busno allows for sibling P2P bridges */ - pciauto_prescan_setup_bridge(hose, dev, hose->current_busno); - /* - * need to figure out if this is a subordinate bridge on the bus - * to be able to properly set the pri/sec/sub bridge registers. - */ - n = pci_hose_scan_bus(hose, hose->current_busno); - - /* figure out the deepest we've gone for this leg */ - sub_bus = max(n, sub_bus); - pciauto_postscan_setup_bridge(hose, dev, sub_bus); - - sub_bus = hose->current_busno; - break; - - case PCI_CLASS_STORAGE_IDE: - pci_hose_read_config_byte(hose, dev, PCI_CLASS_PROG, &prg_iface); - if (!(prg_iface & PCIAUTO_IDE_MODE_MASK)) { - DEBUGF("PCI Autoconfig: Skipping legacy mode IDE controller\n"); - return sub_bus; - } - - pciauto_setup_device(hose, dev, 6, hose->pci_mem, hose->pci_prefetch, hose->pci_io); - break; - - case PCI_CLASS_BRIDGE_CARDBUS: - /* just do a minimal setup of the bridge, let the OS take care of the rest */ - pciauto_setup_device(hose, dev, 0, hose->pci_mem, hose->pci_prefetch, hose->pci_io); - - DEBUGF("PCI Autoconfig: Found P2CardBus bridge, device %d\n", PCI_DEV(dev)); - - hose->current_busno++; - break; - -#ifdef CONFIG_MPC5200 - case PCI_CLASS_BRIDGE_OTHER: - DEBUGF("PCI Autoconfig: Skipping bridge device %d\n", - PCI_DEV(dev)); - break; -#endif -#ifdef CONFIG_MPC834X - case PCI_CLASS_BRIDGE_OTHER: - /* - * The host/PCI bridge 1 seems broken in 8349 - it presents - * itself as 'PCI_CLASS_BRIDGE_OTHER' and appears as an _agent_ - * device claiming resources io/mem/irq.. we only allow for - * the PIMMR window to be allocated (BAR0 - 1MB size) - */ - DEBUGF("PCI Autoconfig: Broken bridge found, only minimal config\n"); - pciauto_setup_device(hose, dev, 0, hose->pci_mem, hose->pci_prefetch, hose->pci_io); - break; -#endif - default: - pciauto_setup_device(hose, dev, 6, hose->pci_mem, hose->pci_prefetch, hose->pci_io); - break; - } - - return sub_bus; -} - -#endif /* CONFIG_PCI */ diff --git a/drivers/pci_indirect.c b/drivers/pci_indirect.c deleted file mode 100644 index a8220fb411..0000000000 --- a/drivers/pci_indirect.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Support for indirect PCI bridges. - * - * Copyright (C) 1998 Gabriel Paubert. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include - -#ifdef CONFIG_PCI -#if (!defined(__I386__) && !defined(CONFIG_IXDP425)) - -#include -#include -#include - -#define cfg_read(val, addr, type, op) *val = op((type)(addr)) -#define cfg_write(val, addr, type, op) op((type *)(addr), (val)) - -#ifdef CONFIG_IXP425 -extern unsigned char in_8 (volatile unsigned *addr); -extern unsigned short in_le16 (volatile unsigned *addr); -extern unsigned in_le32 (volatile unsigned *addr); -extern void out_8 (volatile unsigned *addr, char val); -extern void out_le16 (volatile unsigned *addr, unsigned short val); -extern void out_le32 (volatile unsigned *addr, unsigned int val); -#endif /* CONFIG_IXP425 */ - -#if defined(CONFIG_MPC8260) -#define INDIRECT_PCI_OP(rw, size, type, op, mask) \ -static int \ -indirect_##rw##_config_##size(struct pci_controller *hose, \ - pci_dev_t dev, int offset, type val) \ -{ \ - u32 b, d,f; \ - b = PCI_BUS(dev); d = PCI_DEV(dev); f = PCI_FUNC(dev); \ - b = b - hose->first_busno; \ - dev = PCI_BDF(b, d, f); \ - out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000); \ - sync(); \ - cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \ - return 0; \ -} -#elif defined(CONFIG_E500) || defined(CONFIG_MPC86xx) -#define INDIRECT_PCI_OP(rw, size, type, op, mask) \ -static int \ -indirect_##rw##_config_##size(struct pci_controller *hose, \ - pci_dev_t dev, int offset, type val) \ -{ \ - u32 b, d,f; \ - b = PCI_BUS(dev); d = PCI_DEV(dev); f = PCI_FUNC(dev); \ - b = b - hose->first_busno; \ - dev = PCI_BDF(b, d, f); \ - *(hose->cfg_addr) = dev | (offset & 0xfc) | ((offset & 0xf00) << 16) | 0x80000000; \ - sync(); \ - cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \ - return 0; \ -} -#elif defined(CONFIG_440GX) || defined(CONFIG_440EP) || defined(CONFIG_440GR) || defined(CONFIG_440SPE) -#define INDIRECT_PCI_OP(rw, size, type, op, mask) \ -static int \ -indirect_##rw##_config_##size(struct pci_controller *hose, \ - pci_dev_t dev, int offset, type val) \ -{ \ - u32 b, d,f; \ - b = PCI_BUS(dev); d = PCI_DEV(dev); f = PCI_FUNC(dev); \ - b = b - hose->first_busno; \ - dev = PCI_BDF(b, d, f); \ - if (PCI_BUS(dev) > 0) \ - out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000001); \ - else \ - out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000); \ - cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \ - return 0; \ -} -#else -#define INDIRECT_PCI_OP(rw, size, type, op, mask) \ -static int \ -indirect_##rw##_config_##size(struct pci_controller *hose, \ - pci_dev_t dev, int offset, type val) \ -{ \ - u32 b, d,f; \ - b = PCI_BUS(dev); d = PCI_DEV(dev); f = PCI_FUNC(dev); \ - b = b - hose->first_busno; \ - dev = PCI_BDF(b, d, f); \ - out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000); \ - cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \ - return 0; \ -} -#endif - -#define INDIRECT_PCI_OP_ERRATA6(rw, size, type, op, mask) \ -static int \ -indirect_##rw##_config_##size(struct pci_controller *hose, \ - pci_dev_t dev, int offset, type val) \ -{ \ - unsigned int msr = mfmsr(); \ - mtmsr(msr & ~(MSR_EE | MSR_CE)); \ - out_le32(hose->cfg_addr, dev | (offset & 0xfc) | 0x80000000); \ - cfg_##rw(val, hose->cfg_data + (offset & mask), type, op); \ - out_le32(hose->cfg_addr, 0x00000000); \ - mtmsr(msr); \ - return 0; \ -} - -INDIRECT_PCI_OP(read, byte, u8 *, in_8, 3) -INDIRECT_PCI_OP(read, word, u16 *, in_le16, 2) -INDIRECT_PCI_OP(read, dword, u32 *, in_le32, 0) -#ifdef CONFIG_405GP -INDIRECT_PCI_OP_ERRATA6(write, byte, u8, out_8, 3) -INDIRECT_PCI_OP_ERRATA6(write, word, u16, out_le16, 2) -INDIRECT_PCI_OP_ERRATA6(write, dword, u32, out_le32, 0) -#else -INDIRECT_PCI_OP(write, byte, u8, out_8, 3) -INDIRECT_PCI_OP(write, word, u16, out_le16, 2) -INDIRECT_PCI_OP(write, dword, u32, out_le32, 0) -#endif - -void pci_setup_indirect(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data) -{ - pci_set_ops(hose, - indirect_read_config_byte, - indirect_read_config_word, - indirect_read_config_dword, - indirect_write_config_byte, - indirect_write_config_word, - indirect_write_config_dword); - - hose->cfg_addr = (unsigned int *) cfg_addr; - hose->cfg_data = (unsigned char *) cfg_data; -} - -#endif /* !__I386__ && !CONFIG_IXDP425 */ -#endif /* CONFIG_PCI */ diff --git a/drivers/tsi108_pci.c b/drivers/tsi108_pci.c deleted file mode 100644 index d5f11e42f0..0000000000 --- a/drivers/tsi108_pci.c +++ /dev/null @@ -1,181 +0,0 @@ -/* - * (C) Copyright 2004 Tundra Semiconductor Corp. - * Alex Bounine - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -/* - * PCI initialisation for the Tsi108 EMU board. - */ - -#include - -#ifdef CONFIG_TSI108_PCI - -#include -#include -#include -#include -#ifdef CONFIG_OF_FLAT_TREE -#include -#endif - -struct pci_controller local_hose; - -void tsi108_clear_pci_error (void) -{ - u32 err_stat, err_addr, pci_stat; - - /* - * Quietly clear errors signalled as result of PCI/X configuration read - * requests. - */ - /* Read PB Error Log Registers */ - err_stat = *(volatile u32 *)(CFG_TSI108_CSR_BASE + - TSI108_PB_REG_OFFSET + PB_ERRCS); - err_addr = *(volatile u32 *)(CFG_TSI108_CSR_BASE + - TSI108_PB_REG_OFFSET + PB_AERR); - if (err_stat & PB_ERRCS_ES) { - /* Clear PCI/X bus errors if applicable */ - if ((err_addr & 0xFF000000) == CFG_PCI_CFG_BASE) { - /* Clear error flag */ - *(u32 *) (CFG_TSI108_CSR_BASE + - TSI108_PB_REG_OFFSET + PB_ERRCS) = - PB_ERRCS_ES; - - /* Clear read error reported in PB_ISR */ - *(u32 *) (CFG_TSI108_CSR_BASE + - TSI108_PB_REG_OFFSET + PB_ISR) = - PB_ISR_PBS_RD_ERR; - - /* Clear errors reported by PCI CSR (Normally Master Abort) */ - pci_stat = *(volatile u32 *)(CFG_TSI108_CSR_BASE + - TSI108_PCI_REG_OFFSET + - PCI_CSR); - *(volatile u32 *)(CFG_TSI108_CSR_BASE + - TSI108_PCI_REG_OFFSET + PCI_CSR) = - pci_stat; - - *(volatile u32 *)(CFG_TSI108_CSR_BASE + - TSI108_PCI_REG_OFFSET + - PCI_IRP_STAT) = PCI_IRP_STAT_P_CSR; - } - } - - return; -} - -unsigned int __get_pci_config_dword (u32 addr) -{ - unsigned int retval; - - __asm__ __volatile__ (" lwbrx %0,0,%1\n" - "1: eieio\n" - "2:\n" - ".section .fixup,\"ax\"\n" - "3: li %0,-1\n" - " b 2b\n" - ".section __ex_table,\"a\"\n" - " .align 2\n" - " .long 1b,3b\n" - ".text":"=r"(retval):"r"(addr)); - - return (retval); -} - -static int tsi108_read_config_dword (struct pci_controller *hose, - pci_dev_t dev, int offset, u32 * value) -{ - dev &= (CFG_PCI_CFG_SIZE - 1); - dev |= (CFG_PCI_CFG_BASE | (offset & 0xfc)); - *value = __get_pci_config_dword(dev); - if (0xFFFFFFFF == *value) - tsi108_clear_pci_error (); - return 0; -} - -static int tsi108_write_config_dword (struct pci_controller *hose, - pci_dev_t dev, int offset, u32 value) -{ - dev &= (CFG_PCI_CFG_SIZE - 1); - dev |= (CFG_PCI_CFG_BASE | (offset & 0xfc)); - - out_le32 ((volatile unsigned *)dev, value); - - return 0; -} - -void pci_init_board (void) -{ - struct pci_controller *hose = (struct pci_controller *)&local_hose; - - hose->first_busno = 0; - hose->last_busno = 0xff; - - pci_set_region (hose->regions + 0, - CFG_PCI_MEMORY_BUS, - CFG_PCI_MEMORY_PHYS, - CFG_PCI_MEMORY_SIZE, PCI_REGION_MEM | PCI_REGION_MEMORY); - - /* PCI memory space */ - pci_set_region (hose->regions + 1, - CFG_PCI_MEM_BUS, - CFG_PCI_MEM_PHYS, CFG_PCI_MEM_SIZE, PCI_REGION_MEM); - - /* PCI I/O space */ - pci_set_region (hose->regions + 2, - CFG_PCI_IO_BUS, - CFG_PCI_IO_PHYS, CFG_PCI_IO_SIZE, PCI_REGION_IO); - - hose->region_count = 3; - - pci_set_ops (hose, - pci_hose_read_config_byte_via_dword, - pci_hose_read_config_word_via_dword, - tsi108_read_config_dword, - pci_hose_write_config_byte_via_dword, - pci_hose_write_config_word_via_dword, - tsi108_write_config_dword); - - pci_register_hose (hose); - - hose->last_busno = pci_hose_scan (hose); - - debug ("Done PCI initialization\n"); - return; -} - -#ifdef CONFIG_OF_FLAT_TREE -void -ft_pci_setup (void *blob, bd_t *bd) -{ - u32 *p; - int len; - - p = (u32 *)ft_get_prop (blob, "/" OF_TSI "/pci@1000/bus-range", &len); - if (p != NULL) { - p[0] = local_hose.first_busno; - p[1] = local_hose.last_busno; - } - -} -#endif - -#endif /* CONFIG_TSI108_PCI */ diff --git a/drivers/w83c553f.c b/drivers/w83c553f.c deleted file mode 100644 index 5d82ed4dd4..0000000000 --- a/drivers/w83c553f.c +++ /dev/null @@ -1,226 +0,0 @@ -/* - * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH - * Andreas Heppel - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -/* - * Initialisation of the PCI-to-ISA bridge and disabling the BIOS - * write protection (for flash) in function 0 of the chip. - * Enabling function 1 (IDE controller of the chip. - */ - -#include -#include - -#ifdef CFG_WINBOND_83C553 - -#include -#include - -#include - -#define out8(addr,val) do { \ - out_8((u8*) (addr),(val)); udelay(1); \ - } while (0) -#define out16(addr,val) do { \ - out_be16((u16*) (addr),(val)); udelay(1); \ - } while (0) - -extern uint ide_bus_offset[CFG_IDE_MAXBUS]; - -void initialise_pic(void); -void initialise_dma(void); - -void initialise_w83c553f(void) -{ - pci_dev_t devbusfn; - unsigned char reg8; - unsigned short reg16; - unsigned int reg32; - - devbusfn = pci_find_device(W83C553F_VID, W83C553F_DID, 0); - if (devbusfn == -1) - { - printf("Error: Cannot find W83C553F controller on any PCI bus."); - return; - } - - pci_read_config_word(devbusfn, PCI_COMMAND, ®16); - reg16 |= PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; - pci_write_config_word(devbusfn, PCI_COMMAND, reg16); - - pci_read_config_byte(devbusfn, WINBOND_IPADCR, ®8); - /* 16 MB ISA memory space */ - reg8 |= (IPADCR_IPATOM4 | IPADCR_IPATOM5 | IPADCR_IPATOM6 | IPADCR_IPATOM7); - reg8 &= ~IPADCR_MBE512; - pci_write_config_byte(devbusfn, WINBOND_IPADCR, reg8); - - pci_read_config_byte(devbusfn, WINBOND_CSCR, ®8); - /* switch off BIOS write protection */ - reg8 |= CSCR_UBIOSCSE; - reg8 &= ~CSCR_BIOSWP; - pci_write_config_byte(devbusfn, WINBOND_CSCR, reg8); - - /* - * Interrupt routing: - * - IDE -> IRQ 9/0 - * - INTA -> IRQ 10 - * - INTB -> IRQ 11 - * - INTC -> IRQ 14 - * - INTD -> IRQ 15 - */ - pci_write_config_byte(devbusfn, WINBOND_IDEIRCR, 0x90); - pci_write_config_word(devbusfn, WINBOND_PCIIRCR, 0xABEF); - - /* - * Read IDE bus offsets from function 1 device. - * We must unmask the LSB indicating that ist is an IO address. - */ - devbusfn |= PCI_BDF(0,0,1); - - /* - * Switch off legacy IRQ for IDE and IDE port 1. - */ - pci_write_config_byte(devbusfn, 0x09, 0x8F); - - pci_read_config_dword(devbusfn, WINDOND_IDECSR, ®32); - reg32 &= ~(IDECSR_LEGIRQ | IDECSR_P1EN | IDECSR_P1F16); - pci_write_config_dword(devbusfn, WINDOND_IDECSR, reg32); - - pci_read_config_dword(devbusfn, PCI_BASE_ADDRESS_0, &ide_bus_offset[0]); - ide_bus_offset[0] &= ~1; -#if CFG_IDE_MAXBUS > 1 - pci_read_config_dword(devbusfn, PCI_BASE_ADDRESS_2, &ide_bus_offset[1]); - ide_bus_offset[1] &= ~1; -#endif - - /* - * Enable function 1, IDE -> busmastering and IO space access - */ - pci_read_config_word(devbusfn, PCI_COMMAND, ®16); - reg16 |= PCI_COMMAND_MASTER | PCI_COMMAND_IO; - pci_write_config_word(devbusfn, PCI_COMMAND, reg16); - - /* - * Initialise ISA interrupt controller - */ - initialise_pic(); - - /* - * Initialise DMA controller - */ - initialise_dma(); -} - -void initialise_pic(void) -{ - out8(W83C553F_PIC1_ICW1, 0x11); - out8(W83C553F_PIC1_ICW2, 0x08); - out8(W83C553F_PIC1_ICW3, 0x04); - out8(W83C553F_PIC1_ICW4, 0x01); - out8(W83C553F_PIC1_OCW1, 0xfb); - out8(W83C553F_PIC1_ELC, 0x20); - - out8(W83C553F_PIC2_ICW1, 0x11); - out8(W83C553F_PIC2_ICW2, 0x08); - out8(W83C553F_PIC2_ICW3, 0x02); - out8(W83C553F_PIC2_ICW4, 0x01); - out8(W83C553F_PIC2_OCW1, 0xff); - out8(W83C553F_PIC2_ELC, 0xce); - - out8(W83C553F_TMR1_CMOD, 0x74); - - out8(W83C553F_PIC2_OCW1, 0x20); - out8(W83C553F_PIC1_OCW1, 0x20); - - out8(W83C553F_PIC2_OCW1, 0x2b); - out8(W83C553F_PIC1_OCW1, 0x2b); -} - -void initialise_dma(void) -{ - unsigned int channel; - unsigned int rvalue1, rvalue2; - - /* perform a H/W reset of the devices */ - - out8(W83C553F_DMA1 + W83C553F_DMA1_MC, 0x00); - out16(W83C553F_DMA2 + W83C553F_DMA2_MC, 0x0000); - - /* initialise all channels to a sane state */ - - for (channel = 0; channel < 4; channel++) { - /* - * dependent upon the channel, setup the specifics: - * - * demand - * address-increment - * autoinitialize-disable - * verify-transfer - */ - - switch (channel) { - case 0: - rvalue1 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH0SEL|W83C553F_MODE_TT_VERIFY); - rvalue2 = (W83C553F_MODE_TM_CASCADE|W83C553F_MODE_CH0SEL); - break; - case 1: - rvalue1 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH1SEL|W83C553F_MODE_TT_VERIFY); - rvalue2 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH1SEL|W83C553F_MODE_TT_VERIFY); - break; - case 2: - rvalue1 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH2SEL|W83C553F_MODE_TT_VERIFY); - rvalue2 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH2SEL|W83C553F_MODE_TT_VERIFY); - break; - case 3: - rvalue1 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH3SEL|W83C553F_MODE_TT_VERIFY); - rvalue2 = (W83C553F_MODE_TM_DEMAND|W83C553F_MODE_CH3SEL|W83C553F_MODE_TT_VERIFY); - break; - default: - rvalue1 = 0x00; - rvalue2 = 0x00; - break; - } - - /* write to write mode registers */ - - out8(W83C553F_DMA1 + W83C553F_DMA1_WM, rvalue1 & 0xFF); - out16(W83C553F_DMA2 + W83C553F_DMA2_WM, rvalue2 & 0x00FF); - } - - /* enable all channels */ - - out8(W83C553F_DMA1 + W83C553F_DMA1_CM, 0x00); - out16(W83C553F_DMA2 + W83C553F_DMA2_CM, 0x0000); - /* - * initialize the global DMA configuration - * - * DACK# active low - * DREQ active high - * fixed priority - * channel group enable - */ - - out8(W83C553F_DMA1 + W83C553F_DMA1_CS, 0x00); - out16(W83C553F_DMA2 + W83C553F_DMA2_CS, 0x0000); -} - -#endif /* CFG_WINBOND_83C553 */ -- cgit v1.2.3