summaryrefslogtreecommitdiffstats
path: root/target/linux/atheros/files/arch/mips
diff options
context:
space:
mode:
authormatteo <matteo@3c298f89-4303-0410-b956-a3cf2f4a3e73>2008-05-11 19:43:00 +0000
committermatteo <matteo@3c298f89-4303-0410-b956-a3cf2f4a3e73>2008-05-11 19:43:00 +0000
commit541ff27cfb26939cf1b98b73fa5aeea0d8432082 (patch)
tree5dc375a146daf203159d00f9cb4af4d511a6dd66 /target/linux/atheros/files/arch/mips
parent10a828fab04670f679d9fd88508f355a7927197c (diff)
atheros: USB support
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@11113 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/atheros/files/arch/mips')
-rw-r--r--target/linux/atheros/files/arch/mips/atheros/Kconfig20
-rw-r--r--target/linux/atheros/files/arch/mips/atheros/ar5315/Makefile1
-rw-r--r--target/linux/atheros/files/arch/mips/atheros/ar5315/irq.c28
-rw-r--r--target/linux/atheros/files/arch/mips/atheros/ar5315/pci.c253
4 files changed, 299 insertions, 3 deletions
diff --git a/target/linux/atheros/files/arch/mips/atheros/Kconfig b/target/linux/atheros/files/arch/mips/atheros/Kconfig
index 2170fd710..953f0cb5b 100644
--- a/target/linux/atheros/files/arch/mips/atheros/Kconfig
+++ b/target/linux/atheros/files/arch/mips/atheros/Kconfig
@@ -1,4 +1,3 @@
-
config ATHEROS_AR5312
bool "Atheros 5312/2312+ support"
depends on ATHEROS
@@ -7,7 +6,22 @@ config ATHEROS_AR5312
config ATHEROS_AR5315
bool "Atheros 5315/2315+ support"
depends on ATHEROS
+ select DMA_NONCOHERENT
+ select CEVT_R4K
+ select CSRC_R4K
+ select IRQ_CPU
+ select SYS_HAS_CPU_MIPS32_R1
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_BIG_ENDIAN
+ select GENERIC_GPIO
default y
-
-
+config ATHEROS_AR5315_PCI
+ bool "PCI support"
+ select HW_HAS_PCI
+ select PCI
+ select USB_ARCH_HAS_HCD
+ select USB_ARCH_HAS_OHCI
+ select USB_ARCH_HAS_EHCI
+ depends on ATHEROS_AR5315
+ default n
diff --git a/target/linux/atheros/files/arch/mips/atheros/ar5315/Makefile b/target/linux/atheros/files/arch/mips/atheros/ar5315/Makefile
index 6c50d9931..9b900113f 100644
--- a/target/linux/atheros/files/arch/mips/atheros/ar5315/Makefile
+++ b/target/linux/atheros/files/arch/mips/atheros/ar5315/Makefile
@@ -9,3 +9,4 @@
#
obj-y := board.o irq.o
+obj-$(CONFIG_ATHEROS_AR5315_PCI) += pci.o
diff --git a/target/linux/atheros/files/arch/mips/atheros/ar5315/irq.c b/target/linux/atheros/files/arch/mips/atheros/ar5315/irq.c
index 69cb362a0..581b1a4a1 100644
--- a/target/linux/atheros/files/arch/mips/atheros/ar5315/irq.c
+++ b/target/linux/atheros/files/arch/mips/atheros/ar5315/irq.c
@@ -60,6 +60,10 @@ asmlinkage void ar5315_irq_dispatch(void)
do_IRQ(AR5315_IRQ_WLAN0_INTRS);
else if (pending & CAUSEF_IP4)
do_IRQ(AR5315_IRQ_ENET0_INTRS);
+#ifdef CONFIG_PCI
+ else if (pending & CAUSEF_IP5)
+ ar5315_pci_irq(AR5315_IRQ_LCBUS_PCI);
+#endif
else if (pending & CAUSEF_IP2) {
unsigned int ar531x_misc_intrs = sysRegRead(AR5315_ISR) & sysRegRead(AR5315_IMR);
@@ -81,6 +85,30 @@ asmlinkage void ar5315_irq_dispatch(void)
do_IRQ(AR531X_IRQ_CPU_CLOCK);
}
+#ifdef CONFIG_PCI
+static inline void pci_abort_irq(void)
+{
+ sysRegWrite(AR5315_PCI_INT_STATUS, AR5315_PCI_ABORT_INT);
+ (void)sysRegRead(AR5315_PCI_INT_STATUS); /* flush write to hardware */
+}
+
+static inline void pci_ack_irq(void)
+{
+ sysRegWrite(AR5315_PCI_INT_STATUS, AR5315_PCI_EXT_INT);
+ (void)sysRegRead(AR5315_PCI_INT_STATUS); /* flush write to hardware */
+}
+
+void ar5315_pci_irq(int irq)
+{
+ if (sysRegRead(AR5315_PCI_INT_STATUS) == AR5315_PCI_ABORT_INT)
+ pci_abort_irq();
+ else {
+ do_IRQ(irq);
+ pci_ack_irq();
+ }
+}
+#endif
+
static void ar5315_gpio_intr_enable(unsigned int irq)
{
u32 gpio, mask;
diff --git a/target/linux/atheros/files/arch/mips/atheros/ar5315/pci.c b/target/linux/atheros/files/arch/mips/atheros/ar5315/pci.c
new file mode 100644
index 000000000..0213b3471
--- /dev/null
+++ b/target/linux/atheros/files/arch/mips/atheros/ar5315/pci.c
@@ -0,0 +1,253 @@
+/*
+ * 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.
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <asm/paccess.h>
+#include <asm/irq_cpu.h>
+#include <asm/io.h>
+#include "ar531x.h"
+
+#define AR531X_MEM_BASE 0x80800000UL
+#define AR531X_MEM_SIZE 0x00ffffffUL
+#define AR531X_IO_SIZE 0x00007fffUL
+
+#define IDSEL_SHIFT 13
+
+static spinlock_t ar531x_pci_lock = SPIN_LOCK_UNLOCKED;
+static u32 cfgaddr;
+
+static int config_access(int busno, int dev, int func, int where, int size, u32 ptr, int write)
+{
+ u32 address; /* Address to read from */
+ u32 reg;
+ unsigned long flags;
+ int ret = -1;
+
+ if ((busno != 0) || (dev > 3) || (func > 2))
+ return ret;
+
+ spin_lock_irqsave(&ar531x_pci_lock, flags);
+
+ /* Select Configuration access */
+ reg = sysRegRead(AR5315_PCI_MISC_CONFIG);
+ reg |= AR5315_PCIMISC_CFG_SEL;
+ sysRegWrite(AR5315_PCI_MISC_CONFIG, reg);
+ (void)sysRegRead(AR5315_PCI_MISC_CONFIG);
+
+ address = (u32)cfgaddr + (1 << (IDSEL_SHIFT + dev)) + (func << 8) + where;
+
+ if (size == 1)
+ address ^= 0x3;
+ else if (size == 2)
+ address ^= 0x2;
+
+ if (write) {
+ if (size == 1)
+ ret = put_dbe(ptr, (u8 *) address);
+ else if (size == 2)
+ ret = put_dbe(ptr, (u16 *) address);
+ else if (size == 4)
+ ret = put_dbe(ptr, (u32 *) address);
+ } else {
+ if (size == 1)
+ ret = get_dbe(*((u32 *)ptr), (u8 *) address);
+ else if (size == 2)
+ ret = get_dbe(*((u32 *)ptr), (u16 *) address);
+ else if (size == 4)
+ ret = get_dbe(*((u32 *)ptr), (u32 *) address);
+ }
+
+ /* Select Memory access */
+ reg = sysRegRead(AR5315_PCI_MISC_CONFIG);
+ reg &= ~AR5315_PCIMISC_CFG_SEL;
+ sysRegWrite(AR5315_PCI_MISC_CONFIG, reg);
+ (void)sysRegRead(AR5315_PCI_MISC_CONFIG);
+
+ spin_unlock_irqrestore(&ar531x_pci_lock, flags);
+
+ if (ret) {
+ *((u32 *)ptr) = 0xffffffff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int ar531x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 * value)
+{
+ return config_access(bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, (u32) value, 0);
+}
+
+static int ar531x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value)
+{
+ return config_access(bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, value, 1);
+}
+
+struct pci_ops ar531x_pci_ops = {
+ .read = ar531x_pci_read,
+ .write = ar531x_pci_write,
+};
+
+static struct resource ar531x_mem_resource = {
+ .name = "AR531x PCI MEM",
+ .start = AR531X_MEM_BASE,
+ .end = AR531X_MEM_BASE + AR531X_MEM_SIZE - AR531X_IO_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct resource ar531x_io_resource = {
+ .name = "AR531x PCI I/O",
+ .start = 0,
+ .end = AR531X_IO_SIZE,
+ .flags = IORESOURCE_IO,
+};
+
+struct pci_controller ar531x_pci_controller = {
+ .pci_ops = &ar531x_pci_ops,
+ .mem_resource = &ar531x_mem_resource,
+ .io_resource = &ar531x_io_resource,
+};
+
+int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+ return AR5315_IRQ_LCBUS_PCI;
+}
+
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ u32 reg;
+
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 5);
+ pci_write_config_word(dev, 0x40, 0);
+
+ /* Clear any pending Abort or external Interrupts
+ * and enable interrupt processing */
+ reg = sysRegRead(AR5315_PCI_INTEN_REG);
+ reg &= ~AR5315_PCI_INT_ENABLE;
+ sysRegWrite(AR5315_PCI_INTEN_REG, reg);
+
+ reg = sysRegRead(AR5315_PCI_INT_STATUS);
+ reg |= (AR5315_PCI_ABORT_INT | AR5315_PCI_EXT_INT);
+ sysRegWrite(AR5315_PCI_INT_STATUS, reg);
+
+ reg = sysRegRead(AR5315_PCI_INT_MASK);
+ reg |= (AR5315_PCI_EXT_INT | AR5315_PCI_ABORT_INT);
+ sysRegWrite(AR5315_PCI_INT_MASK, reg);
+
+ reg = sysRegRead(AR5315_PCI_INTEN_REG);
+ reg |= AR5315_PCI_INT_ENABLE;
+ sysRegWrite(AR5315_PCI_INTEN_REG, reg);
+
+ return 0;
+}
+
+static void ar5315_pci_fixup(struct pci_dev *dev)
+{
+ struct pci_bus *bus = dev->bus;
+
+ if ((PCI_SLOT(dev->devfn) != 3) || (PCI_FUNC(dev->devfn) != 0) || (bus->number != 0))
+ return;
+
+#define _DEV bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)
+ printk("PCI: fixing up device %d,%d,%d\n", _DEV);
+ /* fix up mbars */
+ config_access(_DEV, PCI_BASE_ADDRESS_0, 4, HOST_PCI_MBAR0, 1);
+ config_access(_DEV, PCI_BASE_ADDRESS_1, 4, HOST_PCI_MBAR1, 1);
+ config_access(_DEV, PCI_BASE_ADDRESS_2, 4, HOST_PCI_MBAR2, 1);
+ config_access(_DEV, PCI_COMMAND, 4,
+ PCI_COMMAND_MEMORY|PCI_COMMAND_MASTER|PCI_COMMAND_SPECIAL|
+ PCI_COMMAND_INVALIDATE|PCI_COMMAND_PARITY|PCI_COMMAND_SERR|
+ PCI_COMMAND_FAST_BACK, 1);
+#undef _DEV
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, ar5315_pci_fixup);
+
+int __init ar5315_pci_init(void)
+{
+ u32 reg;
+
+ printk("AR531x PCI init... ");
+
+ cfgaddr = (u32) ioremap_nocache(0x80000000, 1*1024*1024); /* Remap PCI config space */
+ set_io_port_base((unsigned long) ioremap_nocache(AR531X_MEM_BASE + AR531X_IO_SIZE - 1, AR531X_IO_SIZE)); /* PCI I/O space */
+
+ reg = sysRegRead(AR5315_RESET);
+ sysRegWrite(AR5315_RESET, reg | AR5315_RESET_PCIDMA);
+
+ udelay(10*1000);
+
+ sysRegWrite(AR5315_RESET, reg & ~AR5315_RESET_PCIDMA);
+ sysRegRead(AR5315_RESET); /* read after */
+
+ udelay(10*1000);
+
+ reg = sysRegRead(AR5315_ENDIAN_CTL);
+ reg |= AR5315_CONFIG_PCIAHB | AR5315_CONFIG_PCIAHB_BRIDGE;
+
+ sysRegWrite(AR5315_ENDIAN_CTL, reg);
+
+ reg = sysRegRead(AR5315_PCICLK);
+ reg = 4;
+ sysRegWrite(AR5315_PCICLK, reg);
+
+ reg = sysRegRead(AR5315_AHB_ARB_CTL);
+ reg |= (ARB_PCI);
+ sysRegWrite(AR5315_AHB_ARB_CTL, reg);
+
+ reg = sysRegRead(AR5315_IF_CTL);
+ reg &= ~(IF_PCI_CLK_MASK | IF_MASK);
+ reg |= (IF_PCI | IF_PCI_HOST | IF_PCI_INTR | (IF_PCI_CLK_OUTPUT_CLK << IF_PCI_CLK_SHIFT));
+
+ sysRegWrite(AR5315_IF_CTL, reg);
+
+ /* Reset the PCI bus by setting bits 5-4 in PCI_MCFG */
+ reg = sysRegRead(AR5315_PCI_MISC_CONFIG);
+ reg &= ~(AR5315_PCIMISC_RST_MODE);
+ reg |= AR5315_PCIRST_LOW;
+ sysRegWrite(AR5315_PCI_MISC_CONFIG, reg);
+
+ /* wait for 100 ms */
+ udelay(100*1000);
+
+ /* Bring the PCI out of reset */
+ reg = sysRegRead(AR5315_PCI_MISC_CONFIG);
+ reg &= ~(AR5315_PCIMISC_RST_MODE);
+ reg |= (AR5315_PCIRST_HIGH | AR5315_PCICACHE_DIS | 0x8);
+ sysRegWrite(AR5315_PCI_MISC_CONFIG, reg);
+
+ sysRegWrite(AR5315_PCI_UNCACHE_CFG,
+ 0x1E | /* 1GB uncached */
+ (1 << 5) | /* Enable uncached */
+ (0x2 << 30) /* Base: 0x80000000 */
+ );
+ (void)sysRegRead(AR5315_PCI_UNCACHE_CFG); /* flush */
+
+ udelay(500*1000);
+
+ register_pci_controller(&ar531x_pci_controller);
+
+ printk("done\n");
+ return 0;
+}
+
+arch_initcall(ar5315_pci_init);