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> SVN-Revision: 34553master
parent
1ed763b888
commit
b516c8d89d
@ -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); |
@ -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); |
@ -0,0 +1,22 @@ |
||||
--- a/arch/mips/pci/Makefile
|
||||
+++ b/arch/mips/pci/Makefile
|
||||
@@ -57,6 +57,7 @@ obj-$(CONFIG_WR_PPMC) += fixup-wrppmc.o
|
||||
obj-$(CONFIG_MIKROTIK_RB532) += pci-rc32434.o ops-rc32434.o fixup-rc32434.o
|
||||
obj-$(CONFIG_CPU_CAVIUM_OCTEON) += pci-octeon.o pcie-octeon.o
|
||||
obj-$(CONFIG_CPU_XLR) += pci-xlr.o
|
||||
+obj-$(CONFIG_ADM8668) += pci-adm8668.o
|
||||
|
||||
ifdef CONFIG_PCI_MSI
|
||||
obj-$(CONFIG_CPU_CAVIUM_OCTEON) += msi-octeon.o
|
||||
--- a/include/linux/pci_ids.h
|
||||
+++ b/include/linux/pci_ids.h
|
||||
@@ -1803,6 +1803,9 @@
|
||||
#define PCI_VENDOR_ID_ESDGMBH 0x12fe
|
||||
#define PCI_DEVICE_ID_ESDGMBH_CPCIASIO4 0x0111
|
||||
|
||||
+#define PCI_VENDOR_ADMTEK 0x1317
|
||||
+#define PCI_DEVICE_ID_ADM8668 0x8688
|
||||
+
|
||||
#define PCI_VENDOR_ID_SIIG 0x131f
|
||||
#define PCI_SUBVENDOR_ID_SIIG 0x131f
|
||||
#define PCI_DEVICE_ID_SIIG_1S_10x_550 0x1000
|
Loading…
Reference in new issue