diff options
author | florian <florian@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2012-12-06 22:40:12 +0000 |
---|---|---|
committer | florian <florian@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2012-12-06 22:40:12 +0000 |
commit | b96a534bb25f12b478340ee36c7d4e3b376ceb8f (patch) | |
tree | 61df93ed46ab4143934ef4f5fceead450f0aece5 /target/linux/adm8668/files | |
parent | 822331ca3c841db0052e461988a48ea198af0b78 (diff) |
[adm8668] cleanup PCI controller code
At some point we should make the ADM5120 PCI controller driver a real
platform driver and share that one between the two targets.
Signed-off-by: Florian Fainelli <florian@openwrt.org>
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@34553 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/adm8668/files')
4 files changed, 203 insertions, 174 deletions
diff --git a/target/linux/adm8668/files/arch/mips/adm8668/Makefile b/target/linux/adm8668/files/arch/mips/adm8668/Makefile index aff789c7d..e443f6866 100644 --- a/target/linux/adm8668/files/arch/mips/adm8668/Makefile +++ b/target/linux/adm8668/files/arch/mips/adm8668/Makefile @@ -2,6 +2,6 @@ # something witty --neutronscott # -obj-y := irq.o pci.o prom.o platform.o proc.o \ +obj-y := irq.o prom.o platform.o proc.o \ setup.o clock.o time.o early_printk.o \ net_core.o net_intr.o diff --git a/target/linux/adm8668/files/arch/mips/adm8668/pci.c b/target/linux/adm8668/files/arch/mips/adm8668/pci.c deleted file mode 100644 index 2bf119297..000000000 --- a/target/linux/adm8668/files/arch/mips/adm8668/pci.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) 2010 Scott Nicholas <neutronscott@scottn.us> - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/pci.h> -#include <linux/types.h> -#include <asm/byteorder.h> -#include <asm/pci.h> -#include <adm8668.h> - -volatile u32* pci_config_address_reg = (volatile u32*)KSEG1ADDR(PCICFG_BASE); -volatile u32* pci_config_data_reg = (volatile u32*)KSEG1ADDR(PCIDAT_BASE); - -#define PCI_ENABLE 0x80000000 -#define ADMPCI_IO_BASE 0x12600000 -#define ADMPCI_IO_SIZE 0x1fffff -#define ADMPCI_MEM_BASE 0x16000000 -#define ADMPCI_MEM_SIZE 0x7ffffff -#define PCI_CMM_IOACC_EN 0x1 -#define PCI_CMM_MEMACC_EN 0x2 -#define PCI_CMM_MASTER_EN 0x4 -#define PCI_CMM_DEF (PCI_CMM_IOACC_EN | PCI_CMM_MEMACC_EN | PCI_CMM_MASTER_EN) - -#define PCI_DEF_CACHE_LINE_SZ 0 -#define PCI_DEF_LATENCY_TIMER 0x20 -#define PCI_DEF_CACHE_LATENCY ((PCI_DEF_LATENCY_TIMER << 8) | PCI_DEF_CACHE_LINE_SZ) - - -#define cfgaddr(bus, devfn, where) ( \ - (bus ? ((bus->number & 0xff) << 0x10) : 0) | \ - ((devfn & 0xff) << 0x08) | \ - (where & 0xfc)) | PCI_ENABLE - -/* assumed little endian */ -static int adm8668_read_config(struct pci_bus *bus, unsigned int devfn, - int where, int size, u32 *val) -{ - switch (size) - { - case 1: - *pci_config_address_reg = cfgaddr(bus, devfn, where); - *val = (le32_to_cpu(*pci_config_data_reg) >> ((where&3)<<3)) & 0xff; - break; - case 2: - if (where & 1) - return PCIBIOS_BAD_REGISTER_NUMBER; - *pci_config_address_reg = cfgaddr(bus, devfn, where); - *val = (le32_to_cpu(*pci_config_data_reg) >> ((where&3)<<3)) & 0xffff; - break; - case 4: - if (where & 3) - return PCIBIOS_BAD_REGISTER_NUMBER; - *pci_config_address_reg = cfgaddr(bus, devfn, where); - *val = le32_to_cpu(*pci_config_data_reg); - break; - } - - return PCIBIOS_SUCCESSFUL; -} - -static int adm8668_write_config(struct pci_bus *bus, unsigned int devfn, - int where, int size, u32 val) -{ - switch (size) - { - case 1: - *pci_config_address_reg = cfgaddr(bus, devfn, where); - *(volatile u8 *)(((int)pci_config_data_reg) + (where & 3)) = val; - break; - case 2: - if (where & 1) - return PCIBIOS_BAD_REGISTER_NUMBER; - *pci_config_address_reg = cfgaddr(bus, devfn, where); - *(volatile u16 *)(((int)pci_config_data_reg) + (where & 2)) = val; - break; - case 4: - if (where & 3) - return PCIBIOS_BAD_REGISTER_NUMBER; - *pci_config_address_reg = cfgaddr(bus, devfn, where); - *pci_config_data_reg = (val); - } - - return PCIBIOS_SUCCESSFUL; -} - - -struct pci_ops adm8668_pci_ops = { - .read = adm8668_read_config, - .write = adm8668_write_config -}; - - -struct resource pciioport_resource = { - .name = "adm8668_pci", - .start = ADMPCI_IO_BASE, - .end = ADMPCI_IO_BASE + ADMPCI_IO_SIZE, - .flags = IORESOURCE_IO -}; - - -struct resource pciiomem_resource = { - .name = "adm8668_pci", - .start = ADMPCI_MEM_BASE, - .end = ADMPCI_MEM_BASE + ADMPCI_MEM_SIZE, - .flags = IORESOURCE_MEM -}; - -#ifdef CONFIG_ADM8668_DISABLE_PCI -struct pci_controller mips_pci_channels[] = { - { NULL, NULL, NULL , NULL , NULL} -}; -#else -struct pci_controller mips_pci_channels = { - .pci_ops = &adm8668_pci_ops, - .io_resource = &pciioport_resource, - .mem_resource = &pciiomem_resource, -}; -#endif - -int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) -{ - switch (slot) - { - case 1: - return 14; - case 2: - return 13; - case 3: - return 12; - default: - return dev->irq; - } -} - -int pcibios_plat_dev_init(struct pci_dev *dev) -{ - return 0; -} - -static int __init adm8668_pci_init(void) -{ - void __iomem *io_map_base; - - printk("adm8668_pci_init()\n"); - - /* what's an io port? this is MIPS... *shrug* */ - ioport_resource.start = ADMPCI_IO_BASE; - ioport_resource.end = ADMPCI_IO_BASE + ADMPCI_IO_SIZE; - - io_map_base = ioremap(ADMPCI_IO_BASE, ADMPCI_IO_SIZE); - if (!io_map_base) - printk("io_map_base didn't work.\n"); - mips_pci_channels.io_map_base = (unsigned long)io_map_base; - register_pci_controller(&mips_pci_channels); - - /* this needed? linksys' gpl 2.4 did it... */ - adm8668_write_config(NULL, 0, PCI_CACHE_LINE_SIZE, 2, 0); - adm8668_write_config(NULL, 0, PCI_BASE_ADDRESS_0, 4, 0); - adm8668_write_config(NULL, 0, PCI_BASE_ADDRESS_1, 4, 0); - adm8668_write_config(NULL, 0, PCI_COMMAND, 4, PCI_CMM_DEF); - - return 0; -} - -arch_initcall(adm8668_pci_init); diff --git a/target/linux/adm8668/files/arch/mips/include/asm/mach-adm8668/adm8668.h b/target/linux/adm8668/files/arch/mips/include/asm/mach-adm8668/adm8668.h index 250447bbf..f0608d155 100644 --- a/target/linux/adm8668/files/arch/mips/include/asm/mach-adm8668/adm8668.h +++ b/target/linux/adm8668/files/arch/mips/include/asm/mach-adm8668/adm8668.h @@ -26,8 +26,8 @@ #define ADM8668_SMEM0_BASE 0x1FC00000 #define ADM8668_NAND_BASE 0x1FFFFF00 -#define PCICFG_BASE 0x12200000 -#define PCIDAT_BASE 0x12400000 +#define ADM8668_PCICFG_BASE 0x12200000 +#define ADM8668_PCIDAT_BASE 0x12400000 /** onboard uart **/ #define ADM8668_UARTCLK_FREQ 62500000 diff --git a/target/linux/adm8668/files/arch/mips/pci/pci-adm8668.c b/target/linux/adm8668/files/arch/mips/pci/pci-adm8668.c new file mode 100644 index 000000000..5cfa54604 --- /dev/null +++ b/target/linux/adm8668/files/arch/mips/pci/pci-adm8668.c @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2010 Scott Nicholas <neutronscott@scottn.us> + * Copyright (C) 2012 Florian Fainelli <florian@openwrt.org> + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Note that this controller is identical to the ADM5120 one + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/types.h> +#include <linux/spinlock.h> + +#include <asm/byteorder.h> +#include <asm/pci.h> +#include <adm8668.h> + +static DEFINE_SPINLOCK(pci_lock); + +#define PCI_ENABLE 0x80000000 +#define ADMPCI_IO_BASE 0x12600000 +#define ADMPCI_IO_SIZE 0x1fffff +#define ADMPCI_MEM_BASE 0x16000000 +#define ADMPCI_MEM_SIZE 0x7ffffff + +static inline void write_cfgaddr(u32 addr) +{ + __raw_writel((addr | PCI_ENABLE), + (void __iomem *)KSEG1ADDR(ADM8668_PCICFG_BASE)); +} + +static inline void write_cfgdata(u32 data) +{ + __raw_writel(data, (void __iomem *)KSEG1ADDR(ADM8668_PCIDAT_BASE)); +} + +static inline u32 read_cfgdata(void) +{ + return __raw_readl((void __iomem *)KSEG1ADDR(ADM8668_PCIDAT_BASE)); +} + +static inline u32 mkaddr(struct pci_bus *bus, unsigned int devfn, int where) +{ + return ((bus->number & 0xff) << 16) | ((devfn & 0xff) << 8) | + (where & 0xfc); +} + +static int pci_read_config(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) +{ + unsigned long flags; + u32 data; + + spin_lock_irqsave(&pci_lock, flags); + write_cfgaddr(mkaddr(bus, devfn, where)); + data = read_cfgdata(); + + switch (size) { + case 1: + if (where & 1) + data >>= 8; + if (where & 2) + data >>= 16; + data &= 0xff; + break; + case 2: + if (where & 2) + data >>= 16; + data &= 0xffff; + break; + } + + *val = data; + + spin_unlock_irqrestore(&pci_lock, flags); + + return PCIBIOS_SUCCESSFUL; +} + +static int pci_write_config(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) +{ + unsigned long flags; + u32 data; + int s; + + spin_lock_irqsave(&pci_lock, flags); + + write_cfgaddr(mkaddr(bus, devfn, where)); + data = read_cfgdata(); + + switch (size) { + case 1: + s = ((where & 3) << 3); + data &= ~(0xff << s); + data |= ((val & 0xff) << s); + break; + case 2: + s = ((where & 2) << 4); + data &= ~(0xffff << s); + data |= ((val & 0xffff) << s); + break; + case 4: + data = val; + break; + } + + write_cfgdata(data); + + spin_unlock_irqrestore(&pci_lock, flags); + + return PCIBIOS_SUCCESSFUL; +} + +struct pci_ops adm8668_pci_ops = { + .read = pci_read_config, + .write = pci_write_config +}; + + +struct resource pciioport_resource = { + .name = "adm8668_pci", + .start = ADMPCI_IO_BASE, + .end = ADMPCI_IO_BASE + ADMPCI_IO_SIZE, + .flags = IORESOURCE_IO +}; + +struct resource pciiomem_resource = { + .name = "adm8668_pci", + .start = ADMPCI_MEM_BASE, + .end = ADMPCI_MEM_BASE + ADMPCI_MEM_SIZE, + .flags = IORESOURCE_MEM +}; + +struct pci_controller adm8668_pci_controller = { + .pci_ops = &adm8668_pci_ops, + .io_resource = &pciioport_resource, + .mem_resource = &pciiomem_resource, +}; + +int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) +{ + switch (slot) { + case 1: + return 14; + case 2: + return 13; + case 3: + return 12; + default: + return dev->irq; + } +} + +int pcibios_plat_dev_init(struct pci_dev *dev) +{ + return 0; +} + +static void adm8668_pci_fixup(struct pci_dev *dev) +{ + if (dev->devfn != 0) + return; + + pr_info("PCI: fixing up ADM8668 controller\n"); + + /* setup COMMAND register */ + pci_write_config_word(dev, PCI_COMMAND, + (PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER)); + + /* setup CACHE_LINE_SIZE register */ + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 4); + + /* setup BARS */ + pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, 0); + pci_write_config_dword(dev, PCI_BASE_ADDRESS_1, 0); +} +DECLARE_PCI_FIXUP_HEADER(0x1317, 0x8688, adm8668_pci_fixup); + +static int __init adm8668_pci_init(void) +{ + void __iomem *io_map_base; + + ioport_resource.start = ADMPCI_IO_BASE; + ioport_resource.end = ADMPCI_IO_BASE + ADMPCI_IO_SIZE; + + io_map_base = ioremap(ADMPCI_IO_BASE, ADMPCI_IO_SIZE); + if (!io_map_base) + printk("io_map_base didn't work.\n"); + + adm8668_pci_controller.io_map_base = (unsigned long)io_map_base; + register_pci_controller(&adm8668_pci_controller); + + return 0; +} +arch_initcall(adm8668_pci_init); |