summaryrefslogtreecommitdiffstats
path: root/target/linux/ar71xx/files/arch
diff options
context:
space:
mode:
authorjuhosg <juhosg@3c298f89-4303-0410-b956-a3cf2f4a3e73>2008-07-21 17:08:14 +0000
committerjuhosg <juhosg@3c298f89-4303-0410-b956-a3cf2f4a3e73>2008-07-21 17:08:14 +0000
commit546b5ed544503182a9b3e981bc11feebd6042b21 (patch)
tree10ae3895974888be85ce09abee24fe67b5fbd813 /target/linux/ar71xx/files/arch
parent541dcce6ec450a2aceaf1b42b67b16ebfc9730aa (diff)
surprise :p
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@11894 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/ar71xx/files/arch')
-rw-r--r--target/linux/ar71xx/files/arch/mips/ar71xx/Kconfig23
-rw-r--r--target/linux/ar71xx/files/arch/mips/ar71xx/Makefile15
-rw-r--r--target/linux/ar71xx/files/arch/mips/ar71xx/ar71xx.c55
-rw-r--r--target/linux/ar71xx/files/arch/mips/ar71xx/gpio.c135
-rw-r--r--target/linux/ar71xx/files/arch/mips/ar71xx/irq.c285
-rw-r--r--target/linux/ar71xx/files/arch/mips/ar71xx/mach-generic.c61
-rw-r--r--target/linux/ar71xx/files/arch/mips/ar71xx/mach-rb-4xx.c192
-rw-r--r--target/linux/ar71xx/files/arch/mips/ar71xx/mach-wp543.c56
-rw-r--r--target/linux/ar71xx/files/arch/mips/ar71xx/platform.c301
-rw-r--r--target/linux/ar71xx/files/arch/mips/ar71xx/prom.c126
-rw-r--r--target/linux/ar71xx/files/arch/mips/ar71xx/setup.c226
-rw-r--r--target/linux/ar71xx/files/arch/mips/pci/pci-ar71xx.c346
12 files changed, 1821 insertions, 0 deletions
diff --git a/target/linux/ar71xx/files/arch/mips/ar71xx/Kconfig b/target/linux/ar71xx/files/arch/mips/ar71xx/Kconfig
new file mode 100644
index 000000000..274c3ede1
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ar71xx/Kconfig
@@ -0,0 +1,23 @@
+if ATHEROS_AR71XX
+
+config AR71XX_EARLY_SERIAL
+ bool "Use early serial console"
+ default n
+
+menu "Atheros AR71xx machine selection"
+
+config AR71XX_MACH_GENERIC
+ bool "Generic AR71xx based machine support"
+ default y
+
+config AR71XX_MACH_WP543
+ bool "Compex WP543 board support"
+ default y
+
+config AR71XX_MACH_RB_4XX
+ bool "MikroTik RouterBOARD 4xx series support"
+ default y
+
+endmenu
+
+endif
diff --git a/target/linux/ar71xx/files/arch/mips/ar71xx/Makefile b/target/linux/ar71xx/files/arch/mips/ar71xx/Makefile
new file mode 100644
index 000000000..6e7ab1d48
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ar71xx/Makefile
@@ -0,0 +1,15 @@
+#
+# Makefile for the Atheros AR71xx SoC specific parts of the kernel
+#
+# Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
+# Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+#
+# 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.
+
+obj-y := prom.o irq.o setup.o platform.o gpio.o ar71xx.o
+
+obj-$(CONFIG_AR71XX_MACH_GENERIC) += mach-generic.o
+obj-$(CONFIG_AR71XX_MACH_RB_4XX) += mach-rb-4xx.o
+obj-$(CONFIG_AR71XX_MACH_WP543) += mach-wp543.o
diff --git a/target/linux/ar71xx/files/arch/mips/ar71xx/ar71xx.c b/target/linux/ar71xx/files/arch/mips/ar71xx/ar71xx.c
new file mode 100644
index 000000000..c88225c5f
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ar71xx/ar71xx.c
@@ -0,0 +1,55 @@
+/*
+ * AR71xx SoC routines
+ *
+ * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+
+#include <asm/mach-ar71xx/ar71xx.h>
+
+void __iomem *ar71xx_ddr_base;
+void __iomem *ar71xx_pll_base;
+void __iomem *ar71xx_reset_base;
+void __iomem *ar71xx_gpio_base;
+void __iomem *ar71xx_usb_ctrl_base;
+
+void ar71xx_device_stop(u32 mask)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ ar71xx_reset_wr(RESET_REG_RESET_MODULE,
+ ar71xx_reset_rr(RESET_REG_RESET_MODULE) | mask);
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(ar71xx_device_stop);
+
+void ar71xx_device_start(u32 mask)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ ar71xx_reset_wr(RESET_REG_RESET_MODULE,
+ ar71xx_reset_rr(RESET_REG_RESET_MODULE) & ~mask);
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(ar71xx_device_start);
+
+void ar71xx_ddr_flush(u32 reg)
+{
+ ar71xx_ddr_wr(reg, 1);
+ while ((ar71xx_ddr_rr(reg) & 0x1));
+
+ ar71xx_ddr_wr(reg, 1);
+ while ((ar71xx_ddr_rr(reg) & 0x1));
+}
+EXPORT_SYMBOL_GPL(ar71xx_ddr_flush);
+
diff --git a/target/linux/ar71xx/files/arch/mips/ar71xx/gpio.c b/target/linux/ar71xx/files/arch/mips/ar71xx/gpio.c
new file mode 100644
index 000000000..03bf38b7c
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ar71xx/gpio.c
@@ -0,0 +1,135 @@
+/*
+ * Atheros AR71xx SoC GPIO API support
+ *
+ * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-ar71xx/ar71xx.h>
+
+static DEFINE_SPINLOCK(ar71xx_gpio_lock);
+
+void __ar71xx_gpio_set_value(unsigned gpio, int value)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ar71xx_gpio_lock, flags);
+
+ if (value)
+ ar71xx_gpio_wr(GPIO_REG_SET, (1 << gpio));
+ else
+ ar71xx_gpio_wr(GPIO_REG_CLEAR, (1 << gpio));
+
+ spin_unlock_irqrestore(&ar71xx_gpio_lock, flags);
+}
+EXPORT_SYMBOL(__ar71xx_gpio_set_value);
+
+int __ar71xx_gpio_get_value(unsigned gpio)
+{
+ return (ar71xx_gpio_rr(GPIO_REG_IN) & (1 << gpio)) ? 1 : 0;
+}
+EXPORT_SYMBOL(__ar71xx_gpio_get_value);
+
+static int ar71xx_gpio_get_value(struct gpio_chip *chip, unsigned offset)
+{
+ return __ar71xx_gpio_get_value(offset);
+}
+
+static void ar71xx_gpio_set_value(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ __ar71xx_gpio_set_value(offset, value);
+}
+
+static int ar71xx_gpio_direction_input(struct gpio_chip *chip,
+ unsigned offset)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ar71xx_gpio_lock, flags);
+
+ ar71xx_gpio_wr(GPIO_REG_OE,
+ ar71xx_gpio_rr(GPIO_REG_OE) & ~(1 << offset));
+
+ spin_unlock_irqrestore(&ar71xx_gpio_lock, flags);
+
+ return 0;
+}
+
+static int ar71xx_gpio_direction_output(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ar71xx_gpio_lock, flags);
+
+ if (value)
+ ar71xx_gpio_wr(GPIO_REG_SET, (1 << offset));
+ else
+ ar71xx_gpio_wr(GPIO_REG_CLEAR, (1 << offset));
+
+ ar71xx_gpio_wr(GPIO_REG_OE,
+ ar71xx_gpio_rr(GPIO_REG_OE) | (1 << offset));
+
+ spin_unlock_irqrestore(&ar71xx_gpio_lock, flags);
+
+ return 0;
+}
+
+static struct gpio_chip ar71xx_gpio_chip = {
+ .label = "ar71xx",
+ .get = ar71xx_gpio_get_value,
+ .set = ar71xx_gpio_set_value,
+ .direction_input = ar71xx_gpio_direction_input,
+ .direction_output = ar71xx_gpio_direction_output,
+ .base = 0,
+ .ngpio = AR71XX_GPIO_COUNT,
+};
+
+void ar71xx_gpio_function_enable(u32 mask)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ar71xx_gpio_lock, flags);
+
+ ar71xx_gpio_wr(GPIO_REG_FUNC, ar71xx_gpio_rr(GPIO_REG_FUNC) | mask);
+
+ spin_unlock_irqrestore(&ar71xx_gpio_lock, flags);
+}
+
+void ar71xx_gpio_function_disable(u32 mask)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ar71xx_gpio_lock, flags);
+
+ ar71xx_gpio_wr(GPIO_REG_FUNC, ar71xx_gpio_rr(GPIO_REG_FUNC) & ~mask);
+
+ spin_unlock_irqrestore(&ar71xx_gpio_lock, flags);
+}
+
+void __init ar71xx_gpio_init(void)
+{
+ int err;
+
+ if (!request_mem_region(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE,
+ "AR71xx GPIO controller"))
+ panic("cannot allocate AR71xx GPIO registers page");
+
+ err = gpiochip_add(&ar71xx_gpio_chip);
+ if (err)
+ panic("cannot add AR71xx GPIO chip, error=%d", err);
+}
diff --git a/target/linux/ar71xx/files/arch/mips/ar71xx/irq.c b/target/linux/ar71xx/files/arch/mips/ar71xx/irq.c
new file mode 100644
index 000000000..171dd63f1
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ar71xx/irq.c
@@ -0,0 +1,285 @@
+/*
+ * Atheros AR71xx SoC specific interrupt handling
+ *
+ * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * Parts of this file are based on Atheros' 2.6.15 BSP
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+
+#include <asm/irq_cpu.h>
+#include <asm/mipsregs.h>
+
+#include <asm/mach-ar71xx/ar71xx.h>
+
+#ifdef CONFIG_PCI
+static void ar71xx_pci_irq_dispatch(void)
+{
+ u32 pending;
+
+ pending = ar71xx_reset_rr(RESET_REG_PCI_INT_STATUS) &
+ ar71xx_reset_rr(RESET_REG_PCI_INT_ENABLE);
+
+ if (pending & PCI_INT_DEV0)
+ do_IRQ(AR71XX_PCI_IRQ_DEV0);
+
+ else if (pending & PCI_INT_DEV1)
+ do_IRQ(AR71XX_PCI_IRQ_DEV1);
+
+ else if (pending & PCI_INT_DEV2)
+ do_IRQ(AR71XX_PCI_IRQ_DEV2);
+
+ else
+ spurious_interrupt();
+}
+
+static void ar71xx_pci_irq_unmask(unsigned int irq)
+{
+ irq -= AR71XX_PCI_IRQ_BASE;
+ ar71xx_reset_wr(RESET_REG_PCI_INT_ENABLE,
+ ar71xx_reset_rr(RESET_REG_PCI_INT_ENABLE) | (1 << irq));
+}
+
+static void ar71xx_pci_irq_mask(unsigned int irq)
+{
+ irq -= AR71XX_PCI_IRQ_BASE;
+ ar71xx_reset_wr(RESET_REG_PCI_INT_ENABLE,
+ ar71xx_reset_rr(RESET_REG_PCI_INT_ENABLE) & ~(1 << irq));
+}
+
+static struct irq_chip ar71xx_pci_irq_chip = {
+ .name = "AR71XX PCI ",
+ .mask = ar71xx_pci_irq_mask,
+ .unmask = ar71xx_pci_irq_unmask,
+ .mask_ack = ar71xx_pci_irq_mask,
+};
+
+static struct irqaction ar71xx_pci_irqaction = {
+ .handler = no_action,
+ .name = "cascade [AR71XX PCI]",
+};
+
+static void __init ar71xx_pci_irq_init(void)
+{
+ int i;
+
+ ar71xx_reset_wr(RESET_REG_PCI_INT_ENABLE, 0);
+ ar71xx_reset_wr(RESET_REG_PCI_INT_STATUS, 0);
+
+ for (i = AR71XX_PCI_IRQ_BASE;
+ i < AR71XX_PCI_IRQ_BASE + AR71XX_PCI_IRQ_COUNT; i++) {
+ irq_desc[i].status = IRQ_DISABLED;
+ set_irq_chip_and_handler(i, &ar71xx_pci_irq_chip,
+ handle_level_irq);
+ }
+
+ setup_irq(AR71XX_CPU_IRQ_PCI, &ar71xx_pci_irqaction);
+}
+
+#endif /* CONFIG_PCI */
+
+static void ar71xx_gpio_irq_dispatch(void)
+{
+ u32 pending;
+
+ pending = ar71xx_gpio_rr(GPIO_REG_INT_PENDING)
+ & ar71xx_gpio_rr(GPIO_REG_INT_ENABLE);
+
+ if (pending)
+ do_IRQ(AR71XX_GPIO_IRQ_BASE + fls(pending) - 1);
+ else
+ spurious_interrupt();
+}
+
+static void ar71xx_gpio_irq_unmask(unsigned int irq)
+{
+ irq -= AR71XX_GPIO_IRQ_BASE;
+ ar71xx_gpio_wr(GPIO_REG_INT_ENABLE,
+ ar71xx_gpio_rr(GPIO_REG_INT_ENABLE) | (1 << irq));
+}
+
+static void ar71xx_gpio_irq_mask(unsigned int irq)
+{
+ irq -= AR71XX_GPIO_IRQ_BASE;
+ ar71xx_gpio_wr(GPIO_REG_INT_ENABLE,
+ ar71xx_gpio_rr(GPIO_REG_INT_ENABLE) & ~(1 << irq));
+}
+
+#if 0
+static int ar71xx_gpio_irq_set_type(unsigned int irq, unsigned int flow_type)
+{
+ /* TODO: implement */
+ return 0;
+}
+#else
+#define ar71xx_gpio_irq_set_type NULL
+#endif
+
+struct irq_chip ar71xx_gpio_irq_chip = {
+ .name = "AR71XX GPIO",
+ .unmask = ar71xx_gpio_irq_unmask,
+ .mask = ar71xx_gpio_irq_mask,
+ .mask_ack = ar71xx_gpio_irq_mask,
+ .set_type = ar71xx_gpio_irq_set_type,
+};
+
+static struct irqaction ar71xx_gpio_irqaction = {
+ .handler = no_action,
+ .name = "cascade [AR71XX GPIO]",
+};
+
+#define GPIO_IRQ_INIT_STATUS (IRQ_LEVEL | IRQ_TYPE_LEVEL_HIGH | IRQ_DISABLED)
+#define GPIO_INT_ALL 0xffff
+
+static void __init ar71xx_gpio_irq_init(void)
+{
+ int i;
+
+ ar71xx_gpio_wr(GPIO_REG_INT_ENABLE, 0);
+ ar71xx_gpio_wr(GPIO_REG_INT_PENDING, 0);
+
+ /* setup type of all GPIO interrupts to level sensitive */
+ ar71xx_gpio_wr(GPIO_REG_INT_TYPE, GPIO_INT_ALL);
+
+ /* setup polarity of all GPIO interrupts to active high */
+ ar71xx_gpio_wr(GPIO_REG_INT_POLARITY, GPIO_INT_ALL);
+
+ for (i = AR71XX_GPIO_IRQ_BASE;
+ i < AR71XX_GPIO_IRQ_BASE + AR71XX_GPIO_IRQ_COUNT; i++) {
+ irq_desc[i].status = GPIO_IRQ_INIT_STATUS;
+ set_irq_chip_and_handler(i, &ar71xx_gpio_irq_chip,
+ handle_level_irq);
+ }
+
+ setup_irq(AR71XX_MISC_IRQ_GPIO, &ar71xx_gpio_irqaction);
+}
+
+static void ar71xx_misc_irq_dispatch(void)
+{
+ u32 pending;
+
+ pending = ar71xx_reset_rr(RESET_REG_MISC_INT_STATUS)
+ & ar71xx_reset_rr(RESET_REG_MISC_INT_ENABLE);
+
+ if (pending & MISC_INT_UART)
+ do_IRQ(AR71XX_MISC_IRQ_UART);
+
+ else if (pending & MISC_INT_DMA)
+ do_IRQ(AR71XX_MISC_IRQ_DMA);
+
+ else if (pending & MISC_INT_PERFC)
+ do_IRQ(AR71XX_MISC_IRQ_PERFC);
+
+ else if (pending & MISC_INT_TIMER)
+ do_IRQ(AR71XX_MISC_IRQ_TIMER);
+
+ else if (pending & MISC_INT_OHCI)
+ do_IRQ(AR71XX_MISC_IRQ_OHCI);
+
+ else if (pending & MISC_INT_ERROR)
+ do_IRQ(AR71XX_MISC_IRQ_ERROR);
+
+ else if (pending & MISC_INT_GPIO)
+ ar71xx_gpio_irq_dispatch();
+
+ else if (pending & MISC_INT_WDOG)
+ do_IRQ(AR71XX_MISC_IRQ_WDOG);
+
+ else
+ spurious_interrupt();
+}
+
+static void ar71xx_misc_irq_unmask(unsigned int irq)
+{
+ irq -= AR71XX_MISC_IRQ_BASE;
+ ar71xx_reset_wr(RESET_REG_MISC_INT_ENABLE,
+ ar71xx_reset_rr(RESET_REG_MISC_INT_ENABLE) | (1 << irq));
+}
+
+static void ar71xx_misc_irq_mask(unsigned int irq)
+{
+ irq -= AR71XX_MISC_IRQ_BASE;
+ ar71xx_reset_wr(RESET_REG_MISC_INT_ENABLE,
+ ar71xx_reset_rr(RESET_REG_MISC_INT_ENABLE) & ~(1 << irq));
+}
+
+struct irq_chip ar71xx_misc_irq_chip = {
+ .name = "AR71XX MISC",
+ .unmask = ar71xx_misc_irq_unmask,
+ .mask = ar71xx_misc_irq_mask,
+ .mask_ack = ar71xx_misc_irq_mask,
+};
+
+static struct irqaction ar71xx_misc_irqaction = {
+ .handler = no_action,
+ .name = "cascade [AR71XX MISC]",
+};
+
+static void __init ar71xx_misc_irq_init(void)
+{
+ int i;
+
+ ar71xx_reset_wr(RESET_REG_MISC_INT_ENABLE, 0);
+ ar71xx_reset_wr(RESET_REG_MISC_INT_STATUS, 0);
+
+ for (i = AR71XX_MISC_IRQ_BASE;
+ i < AR71XX_MISC_IRQ_BASE + AR71XX_MISC_IRQ_COUNT; i++) {
+ irq_desc[i].status = IRQ_DISABLED;
+ set_irq_chip_and_handler(i, &ar71xx_misc_irq_chip,
+ handle_level_irq);
+ }
+
+ setup_irq(AR71XX_CPU_IRQ_MISC, &ar71xx_misc_irqaction);
+}
+
+asmlinkage void plat_irq_dispatch(void)
+{
+ unsigned long pending;
+
+ pending = read_c0_status() & read_c0_cause() & ST0_IM;
+
+ if (pending & STATUSF_IP7)
+ do_IRQ(AR71XX_CPU_IRQ_TIMER);
+
+#ifdef CONFIG_PCI
+ else if (pending & STATUSF_IP2)
+ ar71xx_pci_irq_dispatch();
+#endif
+
+ else if (pending & STATUSF_IP4)
+ do_IRQ(AR71XX_CPU_IRQ_GE0);
+
+ else if (pending & STATUSF_IP5)
+ do_IRQ(AR71XX_CPU_IRQ_GE1);
+
+ else if (pending & STATUSF_IP3)
+ do_IRQ(AR71XX_CPU_IRQ_USB);
+
+ else if (pending & STATUSF_IP6)
+ ar71xx_misc_irq_dispatch();
+
+ else
+ spurious_interrupt();
+}
+
+void __init arch_init_irq(void)
+{
+ mips_cpu_irq_init();
+
+ ar71xx_misc_irq_init();
+
+#ifdef CONFIG_PCI
+ ar71xx_pci_irq_init();
+#endif
+
+ ar71xx_gpio_irq_init();
+}
diff --git a/target/linux/ar71xx/files/arch/mips/ar71xx/mach-generic.c b/target/linux/ar71xx/files/arch/mips/ar71xx/mach-generic.c
new file mode 100644
index 000000000..4a1200d52
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ar71xx/mach-generic.c
@@ -0,0 +1,61 @@
+/*
+ * Generic AR71xx machine setup
+ *
+ * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+
+#include <asm/mips_machine.h>
+#include <asm/mach-ar71xx/ar71xx.h>
+#include <asm/mach-ar71xx/pci.h>
+#include <asm/mach-ar71xx/platform.h>
+
+static struct spi_board_info ar71xx_generic_spi_info[] = {
+ {
+ .bus_num = 0,
+ .chip_select = 0,
+ .max_speed_hz = 25000000,
+ .modalias = "m25p80",
+ }
+};
+
+static struct ar71xx_pci_irq ar71xx_generic_pci_irqs[] __initdata = {
+ {
+ .slot = 0,
+ .pin = 1,
+ .irq = AR71XX_PCI_IRQ_DEV0,
+ }, {
+ .slot = 1,
+ .pin = 1,
+ .irq = AR71XX_PCI_IRQ_DEV1,
+ }, {
+ .slot = 2,
+ .pin = 1,
+ .irq = AR71XX_PCI_IRQ_DEV2,
+ }
+};
+
+static void __init ar71xx_generic_init(void)
+{
+ ar71xx_add_device_spi(NULL, ar71xx_generic_spi_info,
+ ARRAY_SIZE(ar71xx_generic_spi_info));
+
+ ar71xx_add_device_eth(0, PHY_INTERFACE_MODE_MII, 0x001f0000);
+ ar71xx_add_device_eth(1, PHY_INTERFACE_MODE_RMII, 0xffffffff);
+
+ ar71xx_add_device_usb();
+
+ ar71xx_pci_init(ARRAY_SIZE(ar71xx_generic_pci_irqs),
+ ar71xx_generic_pci_irqs);
+}
+
+MIPS_MACHINE(MACH_AR71XX_GENERIC, "Generic AR71xx board", ar71xx_generic_init);
diff --git a/target/linux/ar71xx/files/arch/mips/ar71xx/mach-rb-4xx.c b/target/linux/ar71xx/files/arch/mips/ar71xx/mach-rb-4xx.c
new file mode 100644
index 000000000..7504c349a
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ar71xx/mach-rb-4xx.c
@@ -0,0 +1,192 @@
+/*
+ * MikroTik RouterBOARD 4xx series support
+ *
+ * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * 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.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/mmc/host.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include <linux/spi/mmc_spi.h>
+#include <linux/leds.h>
+
+#include <asm/mips_machine.h>
+#include <asm/mach-ar71xx/ar71xx.h>
+#include <asm/mach-ar71xx/pci.h>
+#include <asm/mach-ar71xx/platform.h>
+
+#define RB4XX_GPIO_USER_LED 4
+
+static struct gpio_led rb4xx_leds_gpio[] = {
+ {
+ .name = "rb4xx:yellow:user",
+ .gpio = RB4XX_GPIO_USER_LED,
+ .active_low = 0,
+ },
+};
+
+static struct gpio_led_platform_data rb4xx_leds_gpio_data = {
+ .leds = rb4xx_leds_gpio,
+ .num_leds = ARRAY_SIZE(rb4xx_leds_gpio),
+};
+
+static struct platform_device rb4xx_leds_gpio_device = {
+ .name = "leds-gpio",
+ .id = -1,
+ .dev = {
+ .platform_data = &rb4xx_leds_gpio_data,
+ }
+};
+
+static struct platform_device rb4xx_nand_device = {
+ .name = "rb4xx-nand",
+ .id = -1,
+};
+
+static struct ar71xx_pci_irq rb4xx_pci_irqs[] __initdata = {
+ {
+ .slot = 1,
+ .pin = 1,
+ .irq = AR71XX_PCI_IRQ_DEV0,
+ }, {
+ .slot = 1,
+ .pin = 2,
+ .irq = AR71XX_PCI_IRQ_DEV1,
+ }, {
+ .slot = 2,
+ .pin = 1,
+ .irq = AR71XX_PCI_IRQ_DEV1,
+ }, {
+ .slot = 3,
+ .pin = 1,
+ .irq = AR71XX_PCI_IRQ_DEV2,
+ }
+};
+
+#if 0
+/*
+ * SPI device support is experimental
+ */
+static struct flash_platform_data rb4xx_flash_data = {
+ .type = "pm25lv512",
+};
+
+static struct spi_board_info rb4xx_spi_info[] = {
+ {
+ .bus_num = 0,
+ .chip_select = 0,
+ .max_speed_hz = 25000000,
+ .modalias = "m25p80",
+ .platform_data = &rb4xx_flash_data,
+ }
+};
+
+static struct mmc_spi_platform_data rb433_mmc_data = {
+ .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
+};
+
+static struct spi_board_info rb433_spi_info[] = {
+ {
+ .bus_num = 0,
+ .chip_select = 0,
+ .max_speed_hz = 25000000,
+ .modalias = "m25p80",
+ .platform_data = &rb433_flash_data,
+ }, {
+ .bus_num = 0,
+ .chip_select = 2,
+ .max_speed_hz = 25000000,
+ .modalias = "mmc_spi",
+ .platform_data = &rb433_mmc_data,
+ }
+};
+
+static u32 rb433_spi_get_ioc_base(u8 chip_select, int cs_high, int is_on)
+{
+ u32 ret;
+
+ if (is_on == AR71XX_SPI_CS_INACTIVE) {
+ ret = SPI_IOC_CS0 | SPI_IOC_CS1;
+ } else {
+ if (cs_high) {
+ ret = SPI_IOC_CS0 | SPI_IOC_CS1;
+ } else {
+ if ((chip_select ^ 2) == 0)
+ ret = SPI_IOC_CS1 ^ (SPI_IOC_CS0 | SPI_IOC_CS1);
+ else
+ ret = SPI_IOC_CS0 ^ (SPI_IOC_CS0 | SPI_IOC_CS1);
+ }
+ }
+
+ return ret;
+}
+
+struct ar71xx_spi_platform_data rb433_spi_data = {
+ .bus_num = 0,
+ .num_chipselect = 3,
+ .get_ioc_base = rb433_spi_get_ioc_base,
+};
+
+static void rb4xx_add_device_spi(void)
+{
+ ar71xx_add_device_spi(NULL, rb4xx_spi_info, ARRAY_SIZE(rb4xx_spi_info));
+}
+
+static void rb433_add_device_spi(void)
+{
+ ar71xx_add_device_spi(&rb433_spi_data, rb433_spi_info,
+ ARRAY_SIZE(rb433_spi_info));
+}
+#else
+static inline void rb4xx_add_device_spi(void) {}
+static inline void rb433_add_device_spi(void) {}
+#endif
+
+static void __init rb411_setup(void)
+{
+ rb4xx_add_device_spi();
+
+ ar71xx_add_device_eth(0, PHY_INTERFACE_MODE_MII, 0x00000001);
+
+ platform_device_register(&rb4xx_leds_gpio_device);
+ platform_device_register(&rb4xx_nand_device);
+
+ ar71xx_pci_init(ARRAY_SIZE(rb4xx_pci_irqs), rb4xx_pci_irqs);
+}
+
+MIPS_MACHINE(MACH_AR71XX_RB_411, "MikroTik RouterBOARD 411/A/AH", rb411_setup);
+
+static void __init rb433_setup(void)
+{
+ rb433_add_device_spi();
+
+ ar71xx_add_device_eth(0, PHY_INTERFACE_MODE_MII, 0x00000001);
+ ar71xx_add_device_eth(1, PHY_INTERFACE_MODE_RMII, 0xffffffff);
+
+ platform_device_register(&rb4xx_leds_gpio_device);
+ platform_device_register(&rb4xx_nand_device);
+
+ ar71xx_pci_init(ARRAY_SIZE(rb4xx_pci_irqs), rb4xx_pci_irqs);
+}
+
+MIPS_MACHINE(MACH_AR71XX_RB_433, "MikroTik RouterBOARD 433/AH", rb433_setup);
+
+static void __init rb450_setup(void)
+{
+ rb4xx_add_device_spi();
+
+ ar71xx_add_device_eth(0, PHY_INTERFACE_MODE_MII, 0x00000001);
+ ar71xx_add_device_eth(1, PHY_INTERFACE_MODE_RMII, 0xffffffff);
+
+ platform_device_register(&rb4xx_leds_gpio_device);
+ platform_device_register(&rb4xx_nand_device);
+}
+
+MIPS_MACHINE(MACH_AR71XX_RB_450, "MikroTik RouterBOARD 450", rb450_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ar71xx/mach-wp543.c b/target/linux/ar71xx/files/arch/mips/ar71xx/mach-wp543.c
new file mode 100644
index 000000000..6f1f39b2a
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ar71xx/mach-wp543.c
@@ -0,0 +1,56 @@
+/*
+ * Compex WP543 board support
+ *
+ * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * 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.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+
+#include <asm/mips_machine.h>
+#include <asm/mach-ar71xx/ar71xx.h>
+#include <asm/mach-ar71xx/pci.h>
+#include <asm/mach-ar71xx/platform.h>
+
+static struct flash_platform_data wp543_flash_data = {
+ /* TODO: add partition map */
+};
+
+static struct spi_board_info wp543_spi_info[] = {
+ {
+ .bus_num = 0,
+ .chip_select = 0,
+ .max_speed_hz = 25000000,
+ .modalias = "m25p80",
+ .platform_data = &wp543_flash_data,
+ }
+};
+
+static struct ar71xx_pci_irq wp543_pci_irqs[] __initdata = {
+ {
+ .slot = 1,
+ .pin = 1,
+ .irq = AR71XX_PCI_IRQ_DEV0,
+ }, {
+ .slot = 1,
+ .pin = 2,
+ .irq = AR71XX_PCI_IRQ_DEV1,
+ }
+};
+
+static void __init wp543_setup(void)
+{
+ ar71xx_add_device_spi(NULL, wp543_spi_info, ARRAY_SIZE(wp543_spi_info));
+
+ ar71xx_add_device_eth(0, PHY_INTERFACE_MODE_MII, 0x00000001);
+
+ ar71xx_pci_init(ARRAY_SIZE(wp543_pci_irqs), wp543_pci_irqs);
+}
+
+MIPS_MACHINE(MACH_AR71XX_WP543, "Compex WP543", wp543_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ar71xx/platform.c b/target/linux/ar71xx/files/arch/mips/ar71xx/platform.c
new file mode 100644
index 000000000..9c91fa3bb
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ar71xx/platform.c
@@ -0,0 +1,301 @@
+/*
+ * Atheros AR71xx SoC platform devices
+ *
+ * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * Parts of this file are based on Atheros' 2.6.15 BSP
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/serial_8250.h>
+
+#include <asm/mips_machine.h>
+#include <asm/mach-ar71xx/ar71xx.h>
+#include <asm/mach-ar71xx/platform.h>
+
+/*
+ * OHCI (USB full speed host controller)
+ */
+static struct resource ar71xx_usb_ohci_resources[] = {
+ [0] = {
+ .start = AR71XX_OHCI_BASE,
+ .end = AR71XX_OHCI_BASE + AR71XX_OHCI_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AR71XX_MISC_IRQ_OHCI,
+ .end = AR71XX_MISC_IRQ_OHCI,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static u64 ar71xx_ohci_dmamask = DMA_BIT_MASK(32);
+static struct platform_device ar71xx_usb_ohci_device = {
+ .name = "ar71xx-ohci",
+ .id = 0,
+ .resource = ar71xx_usb_ohci_resources,
+ .num_resources = ARRAY_SIZE(ar71xx_usb_ohci_resources),
+ .dev = {
+ .dma_mask = &ar71xx_ohci_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
+/*
+ * EHCI (USB full speed host controller)
+ */
+static struct resource ar71xx_usb_ehci_resources[] = {
+ [0] = {
+ .start = AR71XX_EHCI_BASE,
+ .end = AR71XX_EHCI_BASE + AR71XX_EHCI_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AR71XX_CPU_IRQ_USB,
+ .end = AR71XX_CPU_IRQ_USB,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static u64 ar71xx_ehci_dmamask = DMA_BIT_MASK(32);
+static struct platform_device ar71xx_usb_ehci_device = {
+ .name = "ar71xx-ehci",
+ .id = 0,
+ .resource = ar71xx_usb_ehci_resources,
+ .num_resources = ARRAY_SIZE(ar71xx_usb_ehci_resources),
+ .dev = {
+ .dma_mask = &ar71xx_ehci_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
+#define AR71XX_USB_RESET_MASK \
+ (RESET_MODULE_USB_HOST | RESET_MODULE_USB_PHY \
+ | RESET_MODULE_USB_OHCI_DLL)
+
+void __init ar71xx_add_device_usb(void)
+{
+ ar71xx_device_stop(AR71XX_USB_RESET_MASK);
+ mdelay(1000);
+ ar71xx_device_start(AR71XX_USB_RESET_MASK);
+
+ /* Turning on the Buff and Desc swap bits */
+ ar71xx_usb_ctrl_wr(USB_CTRL_REG_CONFIG, 0xf0000);
+
+ /* WAR for HW bug. Here it adjusts the duration between two SOFS */
+ ar71xx_usb_ctrl_wr(USB_CTRL_REG_FLADJ, 0x20c00);
+
+ mdelay(900);
+
+ platform_device_register(&ar71xx_usb_ohci_device);
+ platform_device_register(&ar71xx_usb_ehci_device);
+}
+
+#ifdef CONFIG_AR71XX_EARLY_SERIAL
+static void __init ar71xx_add_device_uart(void) {};
+#else
+static struct resource ar71xx_uart_resources[] = {
+ {
+ .start = AR71XX_UART_BASE,
+ .end = AR71XX_UART_BASE + AR71XX_UART_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+#define AR71XX_UART_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP)
+static struct plat_serial8250_port ar71xx_uart_data[] = {
+ {
+ .mapbase = AR71XX_UART_BASE,
+ .irq = AR71XX_MISC_IRQ_UART,
+ .flags = AR71XX_UART_FLAGS,
+ .iotype = UPIO_MEM32,
+ .regshift = 2,
+ }, {
+ /* terminating entry */
+ }
+};
+
+static struct platform_device ar71xx_uart_device = {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM,
+ .resource = ar71xx_uart_resources,
+ .num_resources = ARRAY_SIZE(ar71xx_uart_resources),
+ .dev = {
+ .platform_data = ar71xx_uart_data
+ },
+};
+
+static void __init ar71xx_add_device_uart(void)
+{
+ ar71xx_uart_data[0].uartclk = ar71xx_ahb_freq;
+ platform_device_register(&ar71xx_uart_device);
+}
+#endif /* CONFIG_AR71XX_EARLY_SERIAL */
+
+static struct resource ar71xx_eth0_resources[] = {
+ {
+ .name = "mac_base",
+ .flags = IORESOURCE_MEM,
+ .start = AR71XX_GE0_BASE,
+ .end = AR71XX_GE0_BASE + AR71XX_GE0_SIZE - 1,
+ }, {
+ .name = "mii_ctrl",
+ .flags = IORESOURCE_MEM,
+ .start = AR71XX_MII_BASE + MII_REG_MII0_CTRL,
+ .end = AR71XX_MII_BASE + MII_REG_MII0_CTRL + 3,
+ }, {
+ .name = "mac_irq",
+ .flags = IORESOURCE_IRQ,
+ .start = AR71XX_CPU_IRQ_GE0,
+ .end = AR71XX_CPU_IRQ_GE0,
+ },
+};
+
+static struct ag71xx_platform_data ar71xx_eth0_data = {
+ .reset_bit = RESET_MODULE_GE0_MAC,
+ .flush_reg = DDR_REG_FLUSH_GE0,
+};
+
+static struct platform_device ar71xx_eth0_device = {
+ .name = "ag71xx",
+ .id = 0,
+ .resource = ar71xx_eth0_resources,
+ .num_resources = ARRAY_SIZE(ar71xx_eth0_resources),
+ .dev = {
+ .platform_data = &ar71xx_eth0_data,
+ },
+};
+
+static struct resource ar71xx_eth1_resources[] = {
+ {
+ .name = "mac_base",
+ .flags = IORESOURCE_MEM,
+ .start = AR71XX_GE1_BASE,
+ .end = AR71XX_GE1_BASE + AR71XX_GE1_SIZE - 1,
+ }, {
+ .name = "mii_ctrl",
+ .flags = IORESOURCE_MEM,
+ .start = AR71XX_MII_BASE + MII_REG_MII1_CTRL,
+ .end = AR71XX_MII_BASE + MII_REG_MII1_CTRL + 3,
+ }, {
+ .name = "mac_irq",
+ .flags = IORESOURCE_IRQ,
+ .start = AR71XX_CPU_IRQ_GE1,
+ .end = AR71XX_CPU_IRQ_GE1,
+ },
+};
+
+static struct ag71xx_platform_data ar71xx_eth1_data = {
+ .reset_bit = RESET_MODULE_GE1_MAC,
+ .flush_reg = DDR_REG_FLUSH_GE1,
+};
+
+static struct platform_device ar71xx_eth1_device = {
+ .name = "ag71xx",
+ .id = 1,
+ .resource = ar71xx_eth1_resources,
+ .num_resources = ARRAY_SIZE(ar71xx_eth1_resources),
+ .dev = {
+ .platform_data = &ar71xx_eth1_data,
+ },
+};
+
+void __init ar71xx_add_device_eth(unsigned int id, phy_interface_t phy_if_mode,
+ u32 phy_mask)
+{
+ struct platform_device *pdev;
+
+ switch (id) {
+ case 0:
+ switch (phy_if_mode) {
+ case PHY_INTERFACE_MODE_MII:
+ ar71xx_eth0_data.mii_if = MII0_CTRL_IF_MII;
+ break;
+ case PHY_INTERFACE_MODE_GMII:
+ ar71xx_eth0_data.mii_if = MII0_CTRL_IF_GMII;
+ break;
+ case PHY_INTERFACE_MODE_RGMII:
+ ar71xx_eth0_data.mii_if = MII0_CTRL_IF_RGMII;
+ break;
+ case PHY_INTERFACE_MODE_RMII:
+ ar71xx_eth0_data.mii_if = MII0_CTRL_IF_RMII;
+ break;
+ default:
+ BUG();
+ }
+ ar71xx_eth0_data.phy_if_mode = phy_if_mode;
+ ar71xx_eth0_data.phy_mask = phy_mask;
+ pdev = &ar71xx_eth0_device;
+ break;
+ case 1:
+ switch (phy_if_mode) {
+ case PHY_INTERFACE_MODE_RMII:
+ ar71xx_eth1_data.mii_if = MII1_CTRL_IF_RMII;
+ break;
+ case PHY_INTERFACE_MODE_RGMII:
+ ar71xx_eth1_data.mii_if = MII1_CTRL_IF_RGMII;
+ break;
+ default:
+ BUG();
+ }
+ ar71xx_eth1_data.phy_if_mode = phy_if_mode;
+ ar71xx_eth1_data.phy_mask = phy_mask;
+ pdev = &ar71xx_eth1_device;
+ break;
+ default:
+ pdev = NULL;
+ break;
+ }
+
+ if (pdev)
+ platform_device_register(pdev);
+}
+
+static struct resource ar71xx_spi_resources[] = {
+ [0] = {
+ .start = AR71XX_SPI_BASE,
+ .end = AR71XX_SPI_BASE + AR71XX_SPI_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device ar71xx_spi_device = {
+ .name = "ar71xx-spi",
+ .id = -1,
+ .resource = ar71xx_spi_resources,
+ .num_resources = ARRAY_SIZE(ar71xx_spi_resources),
+};
+
+void __init ar71xx_add_device_spi(struct ar71xx_spi_platform_data *pdata,
+ struct spi_board_info const *info,
+ unsigned n)
+{
+ ar71xx_gpio_function_enable(GPIO_FUNC_SPI_EN);
+
+ spi_register_board_info(info, n);
+ ar71xx_spi_device.dev.platform_data = pdata;
+ platform_device_register(&ar71xx_spi_device);
+}
+
+static int __init ar71xx_machine_setup(void)
+{
+ ar71xx_print_cmdline();
+
+ ar71xx_gpio_init();
+
+ ar71xx_add_device_uart();
+
+ mips_machine_setup();
+ return 0;
+}
+
+arch_initcall(ar71xx_machine_setup);
diff --git a/target/linux/ar71xx/files/arch/mips/ar71xx/prom.c b/target/linux/ar71xx/files/arch/mips/ar71xx/prom.c
new file mode 100644
index 000000000..e21464fc1
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ar71xx/prom.c
@@ -0,0 +1,126 @@
+/*
+ * Atheros AR71xx SoC specific prom routines
+ *
+ * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/serial_reg.h>
+
+#include <asm/bootinfo.h>
+#include <asm/addrspace.h>
+
+#include <asm/mach-ar71xx/ar71xx.h>
+
+struct board_rec {
+ char *name;
+ unsigned long mach_type;
+};
+
+static int prom_argc __initdata;
+static char **prom_argv __initdata;
+static char **prom_envp __initdata;
+
+static struct board_rec boards[] __initdata = {
+ {
+ .name = "411",
+ .mach_type = MACH_AR71XX_RB_411,
+ }, {
+ .name = "433",
+ .mach_type = MACH_AR71XX_RB_433,
+ }, {
+ .name = "450",
+ .mach_type = MACH_AR71XX_RB_450,
+ }
+};
+
+char *(*prom_getenv)(const char *envname) __initdata;
+
+static __init char *dummy_getenv(const char *envname)
+{
+ return NULL;
+}
+
+static void __init routerboot_printargs(void)
+{
+ int i;
+
+ for (i = 0; i < prom_argc; i++)
+ printk(KERN_DEBUG "prom: routerboot envp[%d]: %s\n",
+ i, prom_envp[i]);
+}
+
+static __init char *routerboot_getenv(const char *envname)
+{
+ char **env;
+ int i = strlen(envname);
+
+ for (env = prom_envp; *env != NULL; env++)
+ if (strncmp(envname, *env, i) == 0 && (*env)[i] == '=')
+ return *env + i + 1;
+
+ return NULL;
+}
+
+static __init unsigned long find_board_byname(char *name)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(boards); i++)
+ if (strcmp(name, boards[i].name) == 0)
+ return boards[i].mach_type;
+
+ return MACH_AR71XX_GENERIC;
+}
+
+void __init prom_init(void)
+{
+ char *board;
+
+ printk(KERN_DEBUG "prom: fw_arg0=%08x, fw_arg1=%08x, "
+ "fw_arg2=%08x, fw_arg3=%08x\n",
+ (unsigned int)fw_arg0, (unsigned int)fw_arg1,
+ (unsigned int)fw_arg2, (unsigned int)fw_arg3);
+
+ prom_getenv = dummy_getenv;
+
+ if ((fw_arg0 == 7) && (fw_arg2 == 0)) {
+ prom_argc = fw_arg0;
+ prom_envp = (char **)fw_arg1;
+ prom_getenv = routerboot_getenv;
+ routerboot_printargs();
+ }
+
+ board = prom_getenv("board");
+ if (board)
+ mips_machtype = find_board_byname(board);
+ else
+ mips_machtype = MACH_AR71XX_GENERIC;
+
+ ar71xx_print_cmdline();
+}
+
+void __init prom_free_prom_memory(void)
+{
+ /* We do not have to prom memory to free */
+}
+
+#define UART_READ(r) \
+ __raw_readl((void __iomem *)(KSEG1ADDR(AR71XX_UART_BASE) + 4 * (r)))
+
+#define UART_WRITE(r, v) \
+ __raw_writel((v), (void __iomem *)(KSEG1ADDR(AR71XX_UART_BASE) + 4*(r)))
+
+void prom_putchar(unsigned char ch)
+{
+ while (((UART_READ(UART_LSR)) & UART_LSR_THRE) == 0);
+ UART_WRITE(UART_TX, ch);
+ while (((UART_READ(UART_LSR)) & UART_LSR_THRE) == 0);
+}
diff --git a/target/linux/ar71xx/files/arch/mips/ar71xx/setup.c b/target/linux/ar71xx/files/arch/mips/ar71xx/setup.c
new file mode 100644
index 000000000..31185527f
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/ar71xx/setup.c
@@ -0,0 +1,226 @@
+/*
+ * Atheros AR71xx SoC specific setup
+ *
+ * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * Parts of this file are based on Atheros' 2.6.15 BSP
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/serial_8250.h>
+#include <linux/bootmem.h>
+
+#include <asm/bootinfo.h>
+#include <asm/traps.h>
+#include <asm/time.h> /* for mips_hpt_frequency */
+#include <asm/reboot.h> /* for _machine_{restart,halt} */
+
+#include <asm/mach-ar71xx/ar71xx.h>
+#include <asm/mach-ar71xx/pci.h>
+#include <asm/mach-ar71xx/platform.h>
+
+#define AR71XX_SYS_TYPE_LEN 64
+#define AR71XX_BASE_FREQ 40000000
+
+#define AR71XX_MEM_SIZE_MIN 0x0200000
+#define AR71XX_MEM_SIZE_MAX 0x8000000
+
+u32 ar71xx_cpu_freq;
+EXPORT_SYMBOL_GPL(ar71xx_cpu_freq);
+
+u32 ar71xx_ahb_freq;
+EXPORT_SYMBOL_GPL(ar71xx_ahb_freq);
+
+u32 ar71xx_ddr_freq;
+EXPORT_SYMBOL_GPL(ar71xx_ddr_freq);
+
+int (*ar71xx_pci_bios_init)(unsigned nr_irqs,
+ struct ar71xx_pci_irq *map) __initdata;
+
+int (*ar71xx_pci_be_handler)(int is_fixup);
+
+static char ar71xx_sys_type[AR71XX_SYS_TYPE_LEN];
+
+static void ar71xx_restart(char *command)
+{
+ ar71xx_device_stop(RESET_MODULE_FULL_CHIP);
+ for (;;)
+ if (cpu_wait)
+ cpu_wait();
+}
+
+static void ar71xx_halt(void)
+{
+ while (1)
+ cpu_wait();
+}
+
+static int ar71xx_be_handler(struct pt_regs *regs, int is_fixup)
+{
+ int err = 0;
+
+ if (ar71xx_pci_be_handler)
+ err = ar71xx_pci_be_handler(is_fixup);
+
+ return (is_fixup && !err) ? MIPS_BE_FIXUP : MIPS_BE_FATAL;
+}
+
+int __init ar71xx_pci_init(unsigned nr_irqs, struct ar71xx_pci_irq *map)
+{
+ if (!ar71xx_pci_bios_init)
+ return 0;
+
+ return ar71xx_pci_bios_init(nr_irqs, map);
+}
+
+static void __init ar71xx_detect_mem_size(void)
+{
+ volatile u8 *p;
+ u8 memsave;
+ u32 size;
+
+ p = (volatile u8 *) KSEG1ADDR(0);
+ memsave = *p;
+ for (size = AR71XX_MEM_SIZE_MIN;
+ size <= (AR71XX_MEM_SIZE_MAX >> 1); size <<= 1) {
+ volatile u8 *r;
+
+ r = (p + size);
+ *p = 0x55;
+ if (*r == 0x55) {
+ /* Mirrored data found, try another pattern */
+ *p = 0xAA;
+ if (*r == 0xAA) {
+ /* Mirrored data found again, stop detection */
+ break;
+ }
+ }
+ }
+ *p = memsave;
+
+ add_memory_region(0, size, BOOT_MEM_RAM);
+}
+
+static void __init ar71xx_detect_sys_type(void)
+{
+ char *chip;
+ u32 id;
+ u32 rev;
+
+ id = ar71xx_reset_rr(RESET_REG_REV_ID) & REV_ID_MASK;
+ rev = (id >> REV_ID_REVISION_SHIFT) & REV_ID_REVISION_MASK;
+ switch (id & REV_ID_CHIP_MASK) {
+ case REV_ID_CHIP_AR7130:
+ chip = "7130";
+ break;
+ case REV_ID_CHIP_AR7141:
+ chip = "7141";
+ break;
+ case REV_ID_CHIP_AR7161:
+ chip = "7161";
+ break;
+ default:
+ chip = "71xx";
+ }
+
+ sprintf(ar71xx_sys_type, "Atheros AR%s rev %u (id:0x%02x)",
+ chip, rev, id);
+}
+
+static void __init ar71xx_detect_sys_frequency(void)
+{
+ u32 pll;
+ u32 freq;
+ u32 div;
+
+ pll = ar71xx_pll_rr(PLL_REG_CPU_PLL_CFG);
+
+ div = ((pll >> PLL_DIV_SHIFT) & PLL_DIV_MASK) + 1;
+ freq = div * AR71XX_BASE_FREQ;
+
+ div = ((pll >> CPU_DIV_SHIFT) & CPU_DIV_MASK) + 1;
+ ar71xx_cpu_freq = freq / div;
+
+ div = ((pll >> DDR_DIV_SHIFT) & DDR_DIV_MASK) + 1;
+ ar71xx_ddr_freq = freq / div;
+
+ div = (((pll >> AHB_DIV_SHIFT) & AHB_DIV_MASK) + 1) * 2;
+ ar71xx_ahb_freq = ar71xx_cpu_freq / div;
+}
+
+#ifdef CONFIG_AR71XX_EARLY_SERIAL
+static void __init ar71xx_early_serial_setup(void)
+{
+ struct uart_port p;
+
+ memset(&p, 0, sizeof(p));
+
+ p.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP;
+ p.iotype = UPIO_MEM32;
+ p.uartclk = ar71xx_ahb_freq;
+ p.irq = AR71XX_MISC_IRQ_UART;
+ p.regshift = 2;
+ p.mapbase = AR71XX_UART_BASE;
+
+ early_serial_setup(&p);
+}
+#else
+static inline void ar71xx_early_serial_setup(void) {};
+#endif /* CONFIG_AR71XX_EARLY_SERIAL */
+
+const char *get_system_type(void)
+{
+ return ar71xx_sys_type;
+}
+
+unsigned int __cpuinit get_c0_compare_irq(void)
+{
+ return CP0_LEGACY_COMPARE_IRQ;
+}
+
+void __init plat_mem_setup(void)
+{
+ set_io_port_base(KSEG1);
+
+ ar71xx_ddr_base = ioremap_nocache(AR71XX_DDR_CTRL_BASE,
+ AR71XX_DDR_CTRL_SIZE);
+
+ ar71xx_pll_base = ioremap_nocache(AR71XX_PLL_BASE,
+ AR71XX_PLL_SIZE);
+
+ ar71xx_reset_base = ioremap_nocache(AR71XX_RESET_BASE,
+ AR71XX_RESET_SIZE);
+
+ ar71xx_gpio_base = ioremap_nocache(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE);
+
+ ar71xx_usb_ctrl_base = ioremap_nocache(AR71XX_USB_CTRL_BASE,
+ AR71XX_USB_CTRL_SIZE);
+
+ ar71xx_detect_mem_size();
+ ar71xx_detect_sys_type();
+ ar71xx_detect_sys_frequency();
+
+ _machine_restart = ar71xx_restart;
+ _machine_halt = ar71xx_halt;
+ pm_power_off = ar71xx_halt;
+
+ board_be_handler = ar71xx_be_handler;
+
+ ar71xx_print_cmdline();
+
+ ar71xx_early_serial_setup();
+}
+
+void __init plat_time_init(void)
+{
+ mips_hpt_frequency = ar71xx_cpu_freq / 2;
+}
diff --git a/target/linux/ar71xx/files/arch/mips/pci/pci-ar71xx.c b/target/linux/ar71xx/files/arch/mips/pci/pci-ar71xx.c
new file mode 100644
index 000000000..e3e80a901
--- /dev/null
+++ b/target/linux/ar71xx/files/arch/mips/pci/pci-ar71xx.c
@@ -0,0 +1,346 @@
+/*
+ * Atheros AR71xx PCI host controller driver
+ *
+ * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * Parts of this file are based on Atheros' 2.6.15 BSP
+ *
+ * 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.
+ */
+
+#include <linux/resource.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/pci.h>
+#include <linux/pci_regs.h>
+
+#include <asm/mach-ar71xx/ar71xx.h>
+#include <asm/mach-ar71xx/pci.h>
+
+#undef DEBUG
+#ifdef DEBUG
+#define DBG(fmt, args...) printk(KERN_DEBUG fmt, ## args)
+#else
+#define DBG(fmt, args...)
+#endif
+
+#define AR71XX_PCI_DELAY 100 /* msecs */
+
+#if 0
+#define PCI_IDSEL_BASE PCI_IDSEL_ADL_START
+#else
+#define PCI_IDSEL_BASE 0
+#endif
+
+static unsigned ar71xx_pci_nr_irqs;
+static struct ar71xx_pci_irq *ar71xx_pci_irq_map __initdata;
+static void __iomem *ar71xx_pcicfg_base;
+
+static DEFINE_SPINLOCK(ar71xx_pci_lock);
+
+static inline void ar71xx_pci_delay(void)
+{
+ mdelay(AR71XX_PCI_DELAY);
+}
+
+static inline u32 ar71xx_pcicfg_rr(unsigned int reg)
+{
+ return __raw_readl(ar71xx_pcicfg_base + reg);
+}
+
+static inline void ar71xx_pcicfg_wr(unsigned int reg, u32 val)
+{
+ __raw_writel(val, ar71xx_pcicfg_base + reg);
+}
+
+/* Byte lane enable bits */
+static u8 ble_table[4][4] = {
+ {0xf, 0xe, 0xd, 0xc},
+ {0xc, 0x9, 0x3, 0x1},
+ {0x0, 0x0, 0x0, 0x0},
+ {0x0, 0x0, 0x0, 0x0},
+};
+
+static inline u32 ar71xx_pci_get_ble(int where, int size, int local)
+{
+ u32 t;
+
+ t = ble_table[size][where & 3];
+ t <<= (local) ? 20 : 4;
+ return t;
+}
+
+static inline u32 ar71xx_pci_bus_addr(struct pci_bus *bus, unsigned int devfn,
+ int where)
+{
+ u32 ret;
+
+ if (!bus->number) {
+ /* type 0 */
+ ret = (1 << (PCI_IDSEL_BASE + PCI_SLOT(devfn)))
+ | (PCI_FUNC(devfn) << 8) | (where & ~3);
+ } else {
+ /* type 1 */
+ ret = (bus->number << 16) | (PCI_SLOT(devfn) << 11)
+ | (PCI_FUNC(devfn) << 8) | (where & ~3) | 1;
+ }
+
+ return ret;
+}
+
+static int __ar71xx_pci_be_handler(int is_fixup)
+{
+ u32 pci_err;
+ u32 ahb_err;
+
+ pci_err = ar71xx_pcicfg_rr(PCI_REG_PCI_ERR) & 3;
+ if (pci_err) {
+ if (!is_fixup)
+ printk(KERN_ALERT "PCI error %d at PCI addr 0x%x\n",
+ pci_err,
+ ar71xx_pcicfg_rr(PCI_REG_PCI_ERR_ADDR));
+
+ ar71xx_pcicfg_wr(PCI_REG_PCI_ERR, pci_err);
+ }
+
+ ahb_err = ar71xx_pcicfg_rr(PCI_REG_AHB_ERR) & 1;
+ if (ahb_err) {
+ if (!is_fixup)
+ printk(KERN_ALERT "AHB error at AHB address 0x%x\n",
+ ar71xx_pcicfg_rr(PCI_REG_AHB_ERR_ADDR));
+
+ ar71xx_pcicfg_wr(PCI_REG_AHB_ERR, ahb_err);
+ }
+
+ return ((ahb_err | pci_err) ? 1 : 0);
+}
+
+static inline int ar71xx_pci_set_cfgaddr(struct pci_bus *bus,
+ unsigned int devfn, int where, int size, u32 cmd)
+{
+ u32 addr;
+
+ addr = ar71xx_pci_bus_addr(bus, devfn, where);
+
+ DBG("PCI: set cfgaddr: %02x:%02x.%01x/%02x:%01d, addr=%08x\n",
+ bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn),
+ where, size, addr);
+
+ ar71xx_pcicfg_wr(PCI_REG_CFG_AD, addr);
+ ar71xx_pcicfg_wr(PCI_REG_CFG_CBE,
+ cmd | ar71xx_pci_get_ble(where, size, 0));
+
+ return __ar71xx_pci_be_handler(1);
+}
+
+static int ar71xx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 *value)
+{
+ static u32 mask[8] = {0, 0xff, 0xffff, 0, 0xffffffff, 0, 0, 0};
+ unsigned long flags;
+ u32 data;
+ int ret;
+
+ ret = PCIBIOS_SUCCESSFUL;
+
+ DBG("PCI: read config: %02x:%02x.%01x/%02x:%01d\n", bus->number,
+ PCI_SLOT(devfn), PCI_FUNC(devfn), where, size);
+
+ spin_lock_irqsave(&ar71xx_pci_lock, flags);
+
+ if (bus->number == 0 && devfn == 0) {
+ u32 t;
+
+ t = PCI_CRP_CMD_READ | (where & ~3);
+
+ ar71xx_pcicfg_wr(PCI_REG_CRP_AD_CBE, t);
+ data = ar71xx_pcicfg_rr(PCI_REG_CRP_RDDATA);
+
+ DBG("PCI: rd local cfg, ad_cbe:%08x, data:%08x\n", t, data);
+
+ } else {
+ int err;
+
+ err = ar71xx_pci_set_cfgaddr(bus, devfn, where, size,
+ PCI_CFG_CMD_READ);
+
+ if (err == 0) {
+ data = ar71xx_pcicfg_rr(PCI_REG_CFG_RDDATA);
+ } else {
+ ret = PCIBIOS_DEVICE_NOT_FOUND;
+ data = ~0;
+ }
+ }
+
+ spin_unlock_irqrestore(&ar71xx_pci_lock, flags);
+
+ DBG("PCI: read config: data=%08x raw=%08x\n",
+ (data >> (8 * (where & 3))) & mask[size & 7], data);
+
+ *value = (data >> (8 * (where & 3))) & mask[size & 7];
+
+ return ret;
+}
+
+static int ar71xx_pci_write_config(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 value)
+{
+ unsigned long flags;
+ int ret;
+
+ DBG("PCI: write config: %02x:%02x.%01x/%02x:%01d value=%08x\n",
+ bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn),
+ where, size, value);
+
+ value = value << (8 * (where & 3));
+ ret = PCIBIOS_SUCCESSFUL;
+
+ spin_lock_irqsave(&ar71xx_pci_lock, flags);
+ if (bus->number == 0 && devfn == 0) {
+ u32 t;
+
+ t = PCI_CRP_CMD_WRITE | (where & ~3);
+ t |= ar71xx_pci_get_ble(where, size, 1);
+
+ DBG("PCI: wr local cfg, ad_cbe:%08x, value:%08x\n", t, value);
+
+ ar71xx_pcicfg_wr(PCI_REG_CRP_AD_CBE, t);
+ ar71xx_pcicfg_wr(PCI_REG_CRP_WRDATA, value);
+ } else {
+ int err;
+
+ err = ar71xx_pci_set_cfgaddr(bus, devfn, where, size,
+ PCI_CFG_CMD_WRITE);
+
+ if (err == 0)
+ ar71xx_pcicfg_wr(PCI_REG_CFG_WRDATA, value);
+ else
+ ret = PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ spin_unlock_irqrestore(&ar71xx_pci_lock, flags);
+
+ return ret;
+}
+
+static void ar71xx_pci_fixup(struct pci_dev *dev)
+{
+ u32 t;
+
+ if (dev->bus->number != 0 || dev->devfn != 0)
+ return;
+
+ DBG("PCI: fixup host controller %s (%04x:%04x)\n", pci_name(dev),
+ dev->vendor, dev->device);
+
+ /* setup COMMAND register */
+ t = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE
+ | PCI_COMMAND_PARITY | PCI_COMMAND_SERR | PCI_COMMAND_FAST_BACK;
+
+ pci_write_config_word(dev, PCI_COMMAND, t);
+}
+
+DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ar71xx_pci_fixup);
+
+int __init pcibios_map_irq(const struct pci_dev *dev, uint8_t slot, uint8_t pin)
+{
+ int irq = -1;
+ int i;
+
+ slot -= PCI_IDSEL_ADL_START - PCI_IDSEL_BASE;
+
+ for (i = 0; i < ar71xx_pci_nr_irqs; i++) {
+ struct ar71xx_pci_irq *entry;
+
+ entry = &ar71xx_pci_irq_map[i];
+ if (entry->slot == slot && entry->pin == pin) {
+ irq = entry->irq;
+ break;
+ }
+ }
+
+ if (irq < 0) {
+ printk(KERN_ALERT "PCI: no irq found for pin%u@%s\n",
+ pin, pci_name((struct pci_dev *)dev));
+ } else {
+ printk(KERN_INFO "PCI: mapping irq %d to pin%u@%s\n",
+ irq, pin, pci_name((struct pci_dev *)dev));
+ }
+
+ return irq;
+}
+
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
+
+static struct pci_ops ar71xx_pci_ops = {
+ .read = ar71xx_pci_read_config,
+ .write = ar71xx_pci_write_config,
+};
+
+static struct resource ar71xx_pci_io_resource = {
+ .name = "PCI IO space",
+ .start = 0,
+ .end = 0,
+ .flags = IORESOURCE_IO,
+};
+
+static struct resource ar71xx_pci_mem_resource = {
+ .name = "PCI memory space",
+ .start = AR71XX_PCI_MEM_BASE,
+ .end = AR71XX_PCI_MEM_BASE + AR71XX_PCI_MEM_SIZE - 1,
+ .flags = IORESOURCE_MEM
+};
+
+static struct pci_controller ar71xx_pci_controller = {
+ .pci_ops = &ar71xx_pci_ops,
+ .mem_resource = &ar71xx_pci_mem_resource,
+ .io_resource = &ar71xx_pci_io_resource,
+};
+
+static int __init __ar71xx_pci_bios_init(unsigned nr_irqs,
+ struct ar71xx_pci_irq *map)
+{
+ ar71xx_device_stop(RESET_MODULE_PCI_BUS | RESET_MODULE_PCI_CORE);
+ ar71xx_pci_delay();
+
+ ar71xx_device_start(RESET_MODULE_PCI_BUS | RESET_MODULE_PCI_CORE);
+ ar71xx_pci_delay();
+
+ ar71xx_pcicfg_base = ioremap_nocache(AR71XX_PCI_CFG_BASE,
+ AR71XX_PCI_CFG_SIZE);
+
+ ar71xx_ddr_wr(DDR_REG_PCI_WIN0, PCI_WIN0_OFFS);
+ ar71xx_ddr_wr(DDR_REG_PCI_WIN1, PCI_WIN1_OFFS);
+ ar71xx_ddr_wr(DDR_REG_PCI_WIN2, PCI_WIN2_OFFS);
+ ar71xx_ddr_wr(DDR_REG_PCI_WIN3, PCI_WIN3_OFFS);
+ ar71xx_ddr_wr(DDR_REG_PCI_WIN4, PCI_WIN4_OFFS);
+ ar71xx_ddr_wr(DDR_REG_PCI_WIN5, PCI_WIN5_OFFS);
+ ar71xx_ddr_wr(DDR_REG_PCI_WIN6, PCI_WIN6_OFFS);
+ ar71xx_ddr_wr(DDR_REG_PCI_WIN7, PCI_WIN7_OFFS);
+
+ ar71xx_pci_delay();
+
+ /* clear bus errors */
+ (void)__ar71xx_pci_be_handler(1);
+
+ ar71xx_pci_nr_irqs = nr_irqs;
+ ar71xx_pci_irq_map = map;
+ ar71xx_pci_be_handler = __ar71xx_pci_be_handler;
+
+ register_pci_controller(&ar71xx_pci_controller);
+
+ return 0;
+}
+
+static int __init __ar71xx_pci_init(void)
+{
+ ar71xx_pci_bios_init = __ar71xx_pci_bios_init;
+ return 0;
+}
+pure_initcall(__ar71xx_pci_init);