/****************************************************************************** * * FILE NAME : ops-amazon_s.c * PROJECT : Danube * MODULES : PCI * * DATE : 19th July 2007 * AUTHOR : Teh Kok How * * DESCRIPTION : PCI Basic Read/Write Operation * COPYRIGHT : Copyright (c) 2006 * Infineon Technologies AG * Am Campeon 1-12, 85579 Neubiberg, Germany * * 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. * * HISTORY * $Version $Date $Author $Comment * 1.0 19/07/2007 Teh Kok How * 2.0 15/11/2007 Teh Kok How Fixes Interrupts and byte-swapping *******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include //#define PCI_DEBUG /* * Macros for calculating offsets into config space given a device * structure or dev/fun/reg */ #define CFGOFFSET(bus,devfn,where) (((bus)<<16) + ((devfn)<<8) + (where)) #define CFGADDR(bus,devfn,where) CFGOFFSET((bus)->number,(devfn),where) #define PCI_BUS_ENABLED 1 #define PCI_DEVICE_MODE 2 #define BSP_PCI_CFG_BUSNUM_SHF 16 #define BSP_PCI_CFG_DEVNUM_SHF 11 #define BSP_PCI_CFG_FUNNUM_SHF 8 #define PCI_ACCESS_READ 0 #define PCI_ACCESS_WRITE 1 #ifdef CONFIG_AMAZON_S_PCI_HW_SWAP #define CONFIG_BSP_PCI_HW_SWAP #else #undef CONFIG_BSP_PCI_HW_SWAP #endif #if 0 #define DBP(fmt, args...) printk( fmt, ## args) #else #define DBP(fmt, args...) #endif int amazon_s_pci_bus_status = 0; volatile void __iomem *cfg_space; struct resource amazon_s_io_resource = { .name = "PCI I/O resources", .start = BSP_PCI_IO_BASE, .end = BSP_PCI_IO_BASE + BSP_PCI_IO_SIZE, .flags = IORESOURCE_IO, }; static struct resource amazon_s_mem_resource = { .name = "PCI Memory resources", .start = BSP_PCI_MEM_BASE, .end = BSP_PCI_MEM_BASE + BSP_PCI_MEM_SIZE, .flags = IORESOURCE_MEM, }; int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) { return 0; } /* Do platform specific device initialization at pci_enable_device() time */ int pcibios_plat_dev_init(struct pci_dev *dev) { /* * we have to open the bridges' windows down to 0 because otherwise * we cannot access ISA south bridge I/O registers that get mapped from * 0. for example, 8259 PIC would be unaccessible without that */ if(dev->vendor == PCI_VENDOR_ID_INTEL && dev->device == PCI_DEVICE_ID_INTEL_S21152BB) { pci_write_config_byte(dev, PCI_IO_BASE, 0); if(dev->bus->number == 0) { pci_write_config_word(dev, PCI_IO_BASE_UPPER16, 0); } else { pci_write_config_word(dev, PCI_IO_BASE_UPPER16, 1); } } return 0; } inline u32 TRY_ACCESS(u32 data, u32 addr) { return get_dbe(data, (volatile u32*) (cfg_space + (addr & ~3))); } /* * Read/write 32-bit values in config space. */ inline u32 READCFG32 (u32 addr) { u32 data; data = *(volatile u32 *) ((u32)cfg_space + (addr & ~3)); return data; } inline void WRITECFG32 (u32 addr, u32 data) { *(volatile u32 *) ((u32)cfg_space + (addr & ~3)) = data; } /* * Some checks before doing config cycles: * In PCI Device Mode, hide everything on bus 0 except the LDT host * bridge. Otherwise, access is controlled by bridge MasterEn bits. */ int amazon_s_pci_can_access(struct pci_bus *bus, int devfn, int where) { u32 devno; if (!(amazon_s_pci_bus_status & (PCI_BUS_ENABLED | PCI_DEVICE_MODE))) return 0; if (bus->number == 0) { devno = PCI_SLOT(devfn); if (amazon_s_pci_bus_status & PCI_DEVICE_MODE) return 0; else { if (get_dbe(devno, (volatile u32*) (cfg_space + (CFGADDR(bus, devfn, where) & ~3)))) { return 0; } else { return 1; } } } else return 1; } static inline void amazon_s_pci_clear_master_abort(struct pci_bus *bus) { u32 temp; /* clean possible Master abort */ /* use PCI access to clear it */ temp = READCFG32(CFGADDR(bus, 0, 4)); #ifdef CONFIG_BSP_PCI_HW_SWAP temp = le32_to_cpu(temp); #endif WRITECFG32(CFGADDR(bus, 0x68, 4), temp); } static int amazon_s_pcibios_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 * val) { u32 data = 0, devno = PCI_SLOT(devfn); if ((size == 2) && (where & 1)) return PCIBIOS_BAD_REGISTER_NUMBER; else if ((size == 4) && (where & 3)) return PCIBIOS_BAD_REGISTER_NUMBER; #ifdef PCI_DEBUG printk(KERN_INFO "[%s %d]: bus %p, bus_number %d, devfn %#x, slot %d, function %#x, where %#x, size %d, cfgaddr %#x, READ ", __func__, __LINE__, bus, bus->number, devfn, devno, PCI_FUNC(devfn), where, size, CFGADDR(bus, devfn, where)); #endif if (amazon_s_pci_can_access(bus, devfn, where)) data = READCFG32(CFGADDR(bus, devfn, where)); else return PCIBIOS_DEVICE_NOT_FOUND; __sync(); // xuliang: prevent lxdb-1-1 optimization which causes system crash #ifdef PCI_DEBUG printk("[%#x ", data); #endif #ifdef CONFIG_BSP_PCI_HW_SWAP if (devno != 0) { data = le32_to_cpu(data); #ifdef PCI_DEBUG printk("%#x ", data); #endif } #endif switch (size) { case 1: *val = (data >> ((where & 3) << 3)) & 0xffU; break; case 2: *val = (data >> ((where & 2) << 3)) & 0xffffU; break; case 4: *val = data; break; default: return PCIBIOS_BAD_REGISTER_NUMBER; } #ifdef PCI_DEBUG printk("%#x]\n", *val); #endif amazon_s_pci_clear_master_abort(bus); return PCIBIOS_SUCCESSFUL; } static int amazon_s_pcibios_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val) { u32 cfgaddr = CFGADDR(bus, devfn, where); u32 data = 0, shift, devno = PCI_SLOT(devfn);; if ((size == 2) && (where & 1)) return PCIBIOS_BAD_REGISTER_NUMBER; else if ((size == 4) && (where & 3)) return PCIBIOS_BAD_REGISTER_NUMBER; if (!amazon_s_pci_can_access(bus, devfn, where)) return PCIBIOS_DEVICE_NOT_FOUND; #ifdef PCI_DEBUG printk(KERN_INFO "[%s %d]: bus %p, bus_number %d, devfn %#x, slot %d, function %#x, where %#x, size %d, WRITE (%#x) ", __func__, __LINE__, bus, bus->number, devfn, devno, PCI_FUNC(devfn), where, size, val); #endif data = READCFG32(cfgaddr); #ifdef PCI_DEBUG printk("[%#x ", data); #endif #ifdef CONFIG_BSP_PCI_HW_SWAP if (devno != 0) { data = le32_to_cpu(data); #ifdef PCI_DEBUG printk("%#x ", data); #endif } #endif switch (size) { case 1: shift = (where & 3) << 3; data &= ~(0xffU << shift); data |= ((val & 0xffU) << shift); break; case 2: shift = (where & 2) << 3; data &= ~(0xffffU << shift); data |= ((val & 0xffffU) << shift); break; case 4: data = val; break; default: return PCIBIOS_BAD_REGISTER_NUMBER; break; } #ifdef CONFIG_BSP_PCI_HW_SWAP if (devno != 0) { data = cpu_to_le32(data); } #endif #ifdef PCI_DEBUG printk("%#x ", data); #endif WRITECFG32(cfgaddr, data); #ifdef PCI_DEBUG data = READCFG32(cfgaddr); printk("%#x]\n", data); #endif amazon_s_pci_clear_master_abort(bus); return PCIBIOS_SUCCESSFUL; } struct pci_ops amazon_s_pci_ops = { .read = amazon_s_pcibios_read, .write = amazon_s_pcibios_write, }; struct pci_controller amazon_s_pci_controller = { .pci_ops = &amazon_s_pci_ops, .mem_resource = &amazon_s_mem_resource, .io_resource = &amazon_s_io_resource, };