summaryrefslogtreecommitdiffstats
path: root/arch/mips/ath79
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/ath79')
-rw-r--r--arch/mips/ath79/Kconfig50
-rw-r--r--arch/mips/ath79/Makefile28
-rw-r--r--arch/mips/ath79/Platform7
-rw-r--r--arch/mips/ath79/clock.c183
-rw-r--r--arch/mips/ath79/common.c97
-rw-r--r--arch/mips/ath79/common.h31
-rw-r--r--arch/mips/ath79/dev-ar913x-wmac.c60
-rw-r--r--arch/mips/ath79/dev-ar913x-wmac.h17
-rw-r--r--arch/mips/ath79/dev-common.c77
-rw-r--r--arch/mips/ath79/dev-common.h18
-rw-r--r--arch/mips/ath79/dev-gpio-buttons.c58
-rw-r--r--arch/mips/ath79/dev-gpio-buttons.h23
-rw-r--r--arch/mips/ath79/dev-leds-gpio.c56
-rw-r--r--arch/mips/ath79/dev-leds-gpio.h21
-rw-r--r--arch/mips/ath79/dev-spi.c38
-rw-r--r--arch/mips/ath79/dev-spi.h22
-rw-r--r--arch/mips/ath79/early_printk.c36
-rw-r--r--arch/mips/ath79/gpio.c197
-rw-r--r--arch/mips/ath79/irq.c187
-rw-r--r--arch/mips/ath79/mach-ap81.c98
-rw-r--r--arch/mips/ath79/mach-pb44.c118
-rw-r--r--arch/mips/ath79/machtypes.h23
-rw-r--r--arch/mips/ath79/prom.c57
-rw-r--r--arch/mips/ath79/setup.c206
24 files changed, 1708 insertions, 0 deletions
diff --git a/arch/mips/ath79/Kconfig b/arch/mips/ath79/Kconfig
new file mode 100644
index 00000000000..b05828260f7
--- /dev/null
+++ b/arch/mips/ath79/Kconfig
@@ -0,0 +1,50 @@
+if ATH79
+
+menu "Atheros AR71XX/AR724X/AR913X machine selection"
+
+config ATH79_MACH_AP81
+ bool "Atheros AP81 reference board"
+ select SOC_AR913X
+ select ATH79_DEV_AR913X_WMAC
+ select ATH79_DEV_GPIO_BUTTONS
+ select ATH79_DEV_LEDS_GPIO
+ select ATH79_DEV_SPI
+ help
+ Say 'Y' here if you want your kernel to support the
+ Atheros AP81 reference board.
+
+config ATH79_MACH_PB44
+ bool "Atheros PB44 reference board"
+ select SOC_AR71XX
+ select ATH79_DEV_GPIO_BUTTONS
+ select ATH79_DEV_LEDS_GPIO
+ select ATH79_DEV_SPI
+ help
+ Say 'Y' here if you want your kernel to support the
+ Atheros PB44 reference board.
+
+endmenu
+
+config SOC_AR71XX
+ def_bool n
+
+config SOC_AR724X
+ def_bool n
+
+config SOC_AR913X
+ def_bool n
+
+config ATH79_DEV_AR913X_WMAC
+ depends on SOC_AR913X
+ def_bool n
+
+config ATH79_DEV_GPIO_BUTTONS
+ def_bool n
+
+config ATH79_DEV_LEDS_GPIO
+ def_bool n
+
+config ATH79_DEV_SPI
+ def_bool n
+
+endif
diff --git a/arch/mips/ath79/Makefile b/arch/mips/ath79/Makefile
new file mode 100644
index 00000000000..c33d4653007
--- /dev/null
+++ b/arch/mips/ath79/Makefile
@@ -0,0 +1,28 @@
+#
+# Makefile for the Atheros AR71XX/AR724X/AR913X specific parts of the kernel
+#
+# Copyright (C) 2008-2011 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 setup.o irq.o common.o clock.o gpio.o
+
+obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
+
+#
+# Devices
+#
+obj-y += dev-common.o
+obj-$(CONFIG_ATH79_DEV_AR913X_WMAC) += dev-ar913x-wmac.o
+obj-$(CONFIG_ATH79_DEV_GPIO_BUTTONS) += dev-gpio-buttons.o
+obj-$(CONFIG_ATH79_DEV_LEDS_GPIO) += dev-leds-gpio.o
+obj-$(CONFIG_ATH79_DEV_SPI) += dev-spi.o
+
+#
+# Machines
+#
+obj-$(CONFIG_ATH79_MACH_AP81) += mach-ap81.o
+obj-$(CONFIG_ATH79_MACH_PB44) += mach-pb44.o
diff --git a/arch/mips/ath79/Platform b/arch/mips/ath79/Platform
new file mode 100644
index 00000000000..2bd663647d2
--- /dev/null
+++ b/arch/mips/ath79/Platform
@@ -0,0 +1,7 @@
+#
+# Atheros AR71xx/AR724x/AR913x
+#
+
+platform-$(CONFIG_ATH79) += ath79/
+cflags-$(CONFIG_ATH79) += -I$(srctree)/arch/mips/include/asm/mach-ath79
+load-$(CONFIG_ATH79) = 0xffffffff80060000
diff --git a/arch/mips/ath79/clock.c b/arch/mips/ath79/clock.c
new file mode 100644
index 00000000000..680bde99a26
--- /dev/null
+++ b/arch/mips/ath79/clock.c
@@ -0,0 +1,183 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X common routines
+ *
+ * Copyright (C) 2011 Gabor Juhos <juhosg@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/init.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include "common.h"
+
+#define AR71XX_BASE_FREQ 40000000
+#define AR724X_BASE_FREQ 5000000
+#define AR913X_BASE_FREQ 5000000
+
+struct clk {
+ unsigned long rate;
+};
+
+static struct clk ath79_ref_clk;
+static struct clk ath79_cpu_clk;
+static struct clk ath79_ddr_clk;
+static struct clk ath79_ahb_clk;
+static struct clk ath79_wdt_clk;
+static struct clk ath79_uart_clk;
+
+static void __init ar71xx_clocks_init(void)
+{
+ u32 pll;
+ u32 freq;
+ u32 div;
+
+ ath79_ref_clk.rate = AR71XX_BASE_FREQ;
+
+ pll = ath79_pll_rr(AR71XX_PLL_REG_CPU_CONFIG);
+
+ div = ((pll >> AR71XX_PLL_DIV_SHIFT) & AR71XX_PLL_DIV_MASK) + 1;
+ freq = div * ath79_ref_clk.rate;
+
+ div = ((pll >> AR71XX_CPU_DIV_SHIFT) & AR71XX_CPU_DIV_MASK) + 1;
+ ath79_cpu_clk.rate = freq / div;
+
+ div = ((pll >> AR71XX_DDR_DIV_SHIFT) & AR71XX_DDR_DIV_MASK) + 1;
+ ath79_ddr_clk.rate = freq / div;
+
+ div = (((pll >> AR71XX_AHB_DIV_SHIFT) & AR71XX_AHB_DIV_MASK) + 1) * 2;
+ ath79_ahb_clk.rate = ath79_cpu_clk.rate / div;
+
+ ath79_wdt_clk.rate = ath79_ahb_clk.rate;
+ ath79_uart_clk.rate = ath79_ahb_clk.rate;
+}
+
+static void __init ar724x_clocks_init(void)
+{
+ u32 pll;
+ u32 freq;
+ u32 div;
+
+ ath79_ref_clk.rate = AR724X_BASE_FREQ;
+ pll = ath79_pll_rr(AR724X_PLL_REG_CPU_CONFIG);
+
+ div = ((pll >> AR724X_PLL_DIV_SHIFT) & AR724X_PLL_DIV_MASK);
+ freq = div * ath79_ref_clk.rate;
+
+ div = ((pll >> AR724X_PLL_REF_DIV_SHIFT) & AR724X_PLL_REF_DIV_MASK);
+ freq *= div;
+
+ ath79_cpu_clk.rate = freq;
+
+ div = ((pll >> AR724X_DDR_DIV_SHIFT) & AR724X_DDR_DIV_MASK) + 1;
+ ath79_ddr_clk.rate = freq / div;
+
+ div = (((pll >> AR724X_AHB_DIV_SHIFT) & AR724X_AHB_DIV_MASK) + 1) * 2;
+ ath79_ahb_clk.rate = ath79_cpu_clk.rate / div;
+
+ ath79_wdt_clk.rate = ath79_ahb_clk.rate;
+ ath79_uart_clk.rate = ath79_ahb_clk.rate;
+}
+
+static void __init ar913x_clocks_init(void)
+{
+ u32 pll;
+ u32 freq;
+ u32 div;
+
+ ath79_ref_clk.rate = AR913X_BASE_FREQ;
+ pll = ath79_pll_rr(AR913X_PLL_REG_CPU_CONFIG);
+
+ div = ((pll >> AR913X_PLL_DIV_SHIFT) & AR913X_PLL_DIV_MASK);
+ freq = div * ath79_ref_clk.rate;
+
+ ath79_cpu_clk.rate = freq;
+
+ div = ((pll >> AR913X_DDR_DIV_SHIFT) & AR913X_DDR_DIV_MASK) + 1;
+ ath79_ddr_clk.rate = freq / div;
+
+ div = (((pll >> AR913X_AHB_DIV_SHIFT) & AR913X_AHB_DIV_MASK) + 1) * 2;
+ ath79_ahb_clk.rate = ath79_cpu_clk.rate / div;
+
+ ath79_wdt_clk.rate = ath79_ahb_clk.rate;
+ ath79_uart_clk.rate = ath79_ahb_clk.rate;
+}
+
+void __init ath79_clocks_init(void)
+{
+ if (soc_is_ar71xx())
+ ar71xx_clocks_init();
+ else if (soc_is_ar724x())
+ ar724x_clocks_init();
+ else if (soc_is_ar913x())
+ ar913x_clocks_init();
+ else
+ BUG();
+
+ pr_info("Clocks: CPU:%lu.%03luMHz, DDR:%lu.%03luMHz, AHB:%lu.%03luMHz, "
+ "Ref:%lu.%03luMHz",
+ ath79_cpu_clk.rate / 1000000,
+ (ath79_cpu_clk.rate / 1000) % 1000,
+ ath79_ddr_clk.rate / 1000000,
+ (ath79_ddr_clk.rate / 1000) % 1000,
+ ath79_ahb_clk.rate / 1000000,
+ (ath79_ahb_clk.rate / 1000) % 1000,
+ ath79_ref_clk.rate / 1000000,
+ (ath79_ref_clk.rate / 1000) % 1000);
+}
+
+/*
+ * Linux clock API
+ */
+struct clk *clk_get(struct device *dev, const char *id)
+{
+ if (!strcmp(id, "ref"))
+ return &ath79_ref_clk;
+
+ if (!strcmp(id, "cpu"))
+ return &ath79_cpu_clk;
+
+ if (!strcmp(id, "ddr"))
+ return &ath79_ddr_clk;
+
+ if (!strcmp(id, "ahb"))
+ return &ath79_ahb_clk;
+
+ if (!strcmp(id, "wdt"))
+ return &ath79_wdt_clk;
+
+ if (!strcmp(id, "uart"))
+ return &ath79_uart_clk;
+
+ return ERR_PTR(-ENOENT);
+}
+EXPORT_SYMBOL(clk_get);
+
+int clk_enable(struct clk *clk)
+{
+ return 0;
+}
+EXPORT_SYMBOL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+}
+EXPORT_SYMBOL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+ return clk->rate;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+void clk_put(struct clk *clk)
+{
+}
+EXPORT_SYMBOL(clk_put);
diff --git a/arch/mips/ath79/common.c b/arch/mips/ath79/common.c
new file mode 100644
index 00000000000..58f60e722a0
--- /dev/null
+++ b/arch/mips/ath79/common.c
@@ -0,0 +1,97 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X common routines
+ *
+ * Copyright (C) 2008-2010 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 <linux/spinlock.h>
+
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include "common.h"
+
+static DEFINE_SPINLOCK(ath79_device_reset_lock);
+
+u32 ath79_cpu_freq;
+EXPORT_SYMBOL_GPL(ath79_cpu_freq);
+
+u32 ath79_ahb_freq;
+EXPORT_SYMBOL_GPL(ath79_ahb_freq);
+
+u32 ath79_ddr_freq;
+EXPORT_SYMBOL_GPL(ath79_ddr_freq);
+
+enum ath79_soc_type ath79_soc;
+
+void __iomem *ath79_pll_base;
+void __iomem *ath79_reset_base;
+EXPORT_SYMBOL_GPL(ath79_reset_base);
+void __iomem *ath79_ddr_base;
+
+void ath79_ddr_wb_flush(u32 reg)
+{
+ void __iomem *flush_reg = ath79_ddr_base + reg;
+
+ /* Flush the DDR write buffer. */
+ __raw_writel(0x1, flush_reg);
+ while (__raw_readl(flush_reg) & 0x1)
+ ;
+
+ /* It must be run twice. */
+ __raw_writel(0x1, flush_reg);
+ while (__raw_readl(flush_reg) & 0x1)
+ ;
+}
+EXPORT_SYMBOL_GPL(ath79_ddr_wb_flush);
+
+void ath79_device_reset_set(u32 mask)
+{
+ unsigned long flags;
+ u32 reg;
+ u32 t;
+
+ if (soc_is_ar71xx())
+ reg = AR71XX_RESET_REG_RESET_MODULE;
+ else if (soc_is_ar724x())
+ reg = AR724X_RESET_REG_RESET_MODULE;
+ else if (soc_is_ar913x())
+ reg = AR913X_RESET_REG_RESET_MODULE;
+ else
+ BUG();
+
+ spin_lock_irqsave(&ath79_device_reset_lock, flags);
+ t = ath79_reset_rr(reg);
+ ath79_reset_wr(reg, t | mask);
+ spin_unlock_irqrestore(&ath79_device_reset_lock, flags);
+}
+EXPORT_SYMBOL_GPL(ath79_device_reset_set);
+
+void ath79_device_reset_clear(u32 mask)
+{
+ unsigned long flags;
+ u32 reg;
+ u32 t;
+
+ if (soc_is_ar71xx())
+ reg = AR71XX_RESET_REG_RESET_MODULE;
+ else if (soc_is_ar724x())
+ reg = AR724X_RESET_REG_RESET_MODULE;
+ else if (soc_is_ar913x())
+ reg = AR913X_RESET_REG_RESET_MODULE;
+ else
+ BUG();
+
+ spin_lock_irqsave(&ath79_device_reset_lock, flags);
+ t = ath79_reset_rr(reg);
+ ath79_reset_wr(reg, t & ~mask);
+ spin_unlock_irqrestore(&ath79_device_reset_lock, flags);
+}
+EXPORT_SYMBOL_GPL(ath79_device_reset_clear);
diff --git a/arch/mips/ath79/common.h b/arch/mips/ath79/common.h
new file mode 100644
index 00000000000..561906c2345
--- /dev/null
+++ b/arch/mips/ath79/common.h
@@ -0,0 +1,31 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X common definitions
+ *
+ * Copyright (C) 2008-2011 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.
+ */
+
+#ifndef __ATH79_COMMON_H
+#define __ATH79_COMMON_H
+
+#include <linux/types.h>
+#include <linux/init.h>
+
+#define ATH79_MEM_SIZE_MIN (2 * 1024 * 1024)
+#define ATH79_MEM_SIZE_MAX (128 * 1024 * 1024)
+
+void ath79_clocks_init(void);
+void ath79_ddr_wb_flush(unsigned int reg);
+
+void ath79_gpio_function_enable(u32 mask);
+void ath79_gpio_function_disable(u32 mask);
+void ath79_gpio_function_setup(u32 set, u32 clear);
+void ath79_gpio_init(void);
+
+#endif /* __ATH79_COMMON_H */
diff --git a/arch/mips/ath79/dev-ar913x-wmac.c b/arch/mips/ath79/dev-ar913x-wmac.c
new file mode 100644
index 00000000000..48f425a5ba2
--- /dev/null
+++ b/arch/mips/ath79/dev-ar913x-wmac.c
@@ -0,0 +1,60 @@
+/*
+ * Atheros AR913X SoC built-in WMAC device support
+ *
+ * Copyright (C) 2008-2010 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/delay.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
+
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include "dev-ar913x-wmac.h"
+
+static struct ath9k_platform_data ar913x_wmac_data;
+
+static struct resource ar913x_wmac_resources[] = {
+ {
+ .start = AR913X_WMAC_BASE,
+ .end = AR913X_WMAC_BASE + AR913X_WMAC_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = ATH79_CPU_IRQ_IP2,
+ .end = ATH79_CPU_IRQ_IP2,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device ar913x_wmac_device = {
+ .name = "ath9k",
+ .id = -1,
+ .resource = ar913x_wmac_resources,
+ .num_resources = ARRAY_SIZE(ar913x_wmac_resources),
+ .dev = {
+ .platform_data = &ar913x_wmac_data,
+ },
+};
+
+void __init ath79_register_ar913x_wmac(u8 *cal_data)
+{
+ if (cal_data)
+ memcpy(ar913x_wmac_data.eeprom_data, cal_data,
+ sizeof(ar913x_wmac_data.eeprom_data));
+
+ /* reset the WMAC */
+ ath79_device_reset_set(AR913X_RESET_AMBA2WMAC);
+ mdelay(10);
+
+ ath79_device_reset_clear(AR913X_RESET_AMBA2WMAC);
+ mdelay(10);
+
+ platform_device_register(&ar913x_wmac_device);
+}
diff --git a/arch/mips/ath79/dev-ar913x-wmac.h b/arch/mips/ath79/dev-ar913x-wmac.h
new file mode 100644
index 00000000000..579d562bbda
--- /dev/null
+++ b/arch/mips/ath79/dev-ar913x-wmac.h
@@ -0,0 +1,17 @@
+/*
+ * Atheros AR913X SoC built-in WMAC device support
+ *
+ * Copyright (C) 2008-2010 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.
+ */
+
+#ifndef _ATH79_DEV_AR913X_WMAC_H
+#define _ATH79_DEV_AR913X_WMAC_H
+
+void ath79_register_ar913x_wmac(u8 *cal_data);
+
+#endif /* _ATH79_DEV_AR913X_WMAC_H */
diff --git a/arch/mips/ath79/dev-common.c b/arch/mips/ath79/dev-common.c
new file mode 100644
index 00000000000..3b82e325beb
--- /dev/null
+++ b/arch/mips/ath79/dev-common.c
@@ -0,0 +1,77 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X common devices
+ *
+ * Copyright (C) 2008-2011 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/platform_device.h>
+#include <linux/serial_8250.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include "common.h"
+#include "dev-common.h"
+
+static struct resource ath79_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 ath79_uart_data[] = {
+ {
+ .mapbase = AR71XX_UART_BASE,
+ .irq = ATH79_MISC_IRQ_UART,
+ .flags = AR71XX_UART_FLAGS,
+ .iotype = UPIO_MEM32,
+ .regshift = 2,
+ }, {
+ /* terminating entry */
+ }
+};
+
+static struct platform_device ath79_uart_device = {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM,
+ .resource = ath79_uart_resources,
+ .num_resources = ARRAY_SIZE(ath79_uart_resources),
+ .dev = {
+ .platform_data = ath79_uart_data
+ },
+};
+
+void __init ath79_register_uart(void)
+{
+ struct clk *clk;
+
+ clk = clk_get(NULL, "uart");
+ if (IS_ERR(clk))
+ panic("unable to get UART clock, err=%ld", PTR_ERR(clk));
+
+ ath79_uart_data[0].uartclk = clk_get_rate(clk);
+ platform_device_register(&ath79_uart_device);
+}
+
+static struct platform_device ath79_wdt_device = {
+ .name = "ath79-wdt",
+ .id = -1,
+};
+
+void __init ath79_register_wdt(void)
+{
+ platform_device_register(&ath79_wdt_device);
+}
diff --git a/arch/mips/ath79/dev-common.h b/arch/mips/ath79/dev-common.h
new file mode 100644
index 00000000000..0f514e1affc
--- /dev/null
+++ b/arch/mips/ath79/dev-common.h
@@ -0,0 +1,18 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X common devices
+ *
+ * Copyright (C) 2008-2010 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.
+ */
+
+#ifndef _ATH79_DEV_COMMON_H
+#define _ATH79_DEV_COMMON_H
+
+void ath79_register_uart(void);
+void ath79_register_wdt(void);
+
+#endif /* _ATH79_DEV_COMMON_H */
diff --git a/arch/mips/ath79/dev-gpio-buttons.c b/arch/mips/ath79/dev-gpio-buttons.c
new file mode 100644
index 00000000000..4b0168a11c0
--- /dev/null
+++ b/arch/mips/ath79/dev-gpio-buttons.c
@@ -0,0 +1,58 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X GPIO button support
+ *
+ * Copyright (C) 2008-2010 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/slab.h"
+#include <linux/platform_device.h>
+
+#include "dev-gpio-buttons.h"
+
+void __init ath79_register_gpio_keys_polled(int id,
+ unsigned poll_interval,
+ unsigned nbuttons,
+ struct gpio_keys_button *buttons)
+{
+ struct platform_device *pdev;
+ struct gpio_keys_platform_data pdata;
+ struct gpio_keys_button *p;
+ int err;
+
+ p = kmalloc(nbuttons * sizeof(*p), GFP_KERNEL);
+ if (!p)
+ return;
+
+ memcpy(p, buttons, nbuttons * sizeof(*p));
+
+ pdev = platform_device_alloc("gpio-keys-polled", id);
+ if (!pdev)
+ goto err_free_buttons;
+
+ memset(&pdata, 0, sizeof(pdata));
+ pdata.poll_interval = poll_interval;
+ pdata.nbuttons = nbuttons;
+ pdata.buttons = p;
+
+ err = platform_device_add_data(pdev, &pdata, sizeof(pdata));
+ if (err)
+ goto err_put_pdev;
+
+ err = platform_device_add(pdev);
+ if (err)
+ goto err_put_pdev;
+
+ return;
+
+err_put_pdev:
+ platform_device_put(pdev);
+
+err_free_buttons:
+ kfree(p);
+}
diff --git a/arch/mips/ath79/dev-gpio-buttons.h b/arch/mips/ath79/dev-gpio-buttons.h
new file mode 100644
index 00000000000..481847ac1cb
--- /dev/null
+++ b/arch/mips/ath79/dev-gpio-buttons.h
@@ -0,0 +1,23 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X GPIO button support
+ *
+ * Copyright (C) 2008-2010 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.
+ */
+
+#ifndef _ATH79_DEV_GPIO_BUTTONS_H
+#define _ATH79_DEV_GPIO_BUTTONS_H
+
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+
+void ath79_register_gpio_keys_polled(int id,
+ unsigned poll_interval,
+ unsigned nbuttons,
+ struct gpio_keys_button *buttons);
+
+#endif /* _ATH79_DEV_GPIO_BUTTONS_H */
diff --git a/arch/mips/ath79/dev-leds-gpio.c b/arch/mips/ath79/dev-leds-gpio.c
new file mode 100644
index 00000000000..cdade68dcd1
--- /dev/null
+++ b/arch/mips/ath79/dev-leds-gpio.c
@@ -0,0 +1,56 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X common GPIO LEDs support
+ *
+ * Copyright (C) 2008-2010 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/slab.h>
+#include <linux/platform_device.h>
+
+#include "dev-leds-gpio.h"
+
+void __init ath79_register_leds_gpio(int id,
+ unsigned num_leds,
+ struct gpio_led *leds)
+{
+ struct platform_device *pdev;
+ struct gpio_led_platform_data pdata;
+ struct gpio_led *p;
+ int err;
+
+ p = kmalloc(num_leds * sizeof(*p), GFP_KERNEL);
+ if (!p)
+ return;
+
+ memcpy(p, leds, num_leds * sizeof(*p));
+
+ pdev = platform_device_alloc("leds-gpio", id);
+ if (!pdev)
+ goto err_free_leds;
+
+ memset(&pdata, 0, sizeof(pdata));
+ pdata.num_leds = num_leds;
+ pdata.leds = p;
+
+ err = platform_device_add_data(pdev, &pdata, sizeof(pdata));
+ if (err)
+ goto err_put_pdev;
+
+ err = platform_device_add(pdev);
+ if (err)
+ goto err_put_pdev;
+
+ return;
+
+err_put_pdev:
+ platform_device_put(pdev);
+
+err_free_leds:
+ kfree(p);
+}
diff --git a/arch/mips/ath79/dev-leds-gpio.h b/arch/mips/ath79/dev-leds-gpio.h
new file mode 100644
index 00000000000..6e5d8851ebc
--- /dev/null
+++ b/arch/mips/ath79/dev-leds-gpio.h
@@ -0,0 +1,21 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X common GPIO LEDs support
+ *
+ * Copyright (C) 2008-2010 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.
+ */
+
+#ifndef _ATH79_DEV_LEDS_GPIO_H
+#define _ATH79_DEV_LEDS_GPIO_H
+
+#include <linux/leds.h>
+
+void ath79_register_leds_gpio(int id,
+ unsigned num_leds,
+ struct gpio_led *leds);
+
+#endif /* _ATH79_DEV_LEDS_GPIO_H */
diff --git a/arch/mips/ath79/dev-spi.c b/arch/mips/ath79/dev-spi.c
new file mode 100644
index 00000000000..aa30163efbf
--- /dev/null
+++ b/arch/mips/ath79/dev-spi.c
@@ -0,0 +1,38 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X SPI controller device
+ *
+ * Copyright (C) 2008-2010 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 <asm/mach-ath79/ar71xx_regs.h>
+#include "dev-spi.h"
+
+static struct resource ath79_spi_resources[] = {
+ {
+ .start = AR71XX_SPI_BASE,
+ .end = AR71XX_SPI_BASE + AR71XX_SPI_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device ath79_spi_device = {
+ .name = "ath79-spi",
+ .id = -1,
+ .resource = ath79_spi_resources,
+ .num_resources = ARRAY_SIZE(ath79_spi_resources),
+};
+
+void __init ath79_register_spi(struct ath79_spi_platform_data *pdata,
+ struct spi_board_info const *info,
+ unsigned n)
+{
+ spi_register_board_info(info, n);
+ ath79_spi_device.dev.platform_data = pdata;
+ platform_device_register(&ath79_spi_device);
+}
diff --git a/arch/mips/ath79/dev-spi.h b/arch/mips/ath79/dev-spi.h
new file mode 100644
index 00000000000..d732565ca73
--- /dev/null
+++ b/arch/mips/ath79/dev-spi.h
@@ -0,0 +1,22 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X SPI controller device
+ *
+ * Copyright (C) 2008-2010 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.
+ */
+
+#ifndef _ATH79_DEV_SPI_H
+#define _ATH79_DEV_SPI_H
+
+#include <linux/spi/spi.h>
+#include <asm/mach-ath79/ath79_spi_platform.h>
+
+void ath79_register_spi(struct ath79_spi_platform_data *pdata,
+ struct spi_board_info const *info,
+ unsigned n);
+
+#endif /* _ATH79_DEV_SPI_H */
diff --git a/arch/mips/ath79/early_printk.c b/arch/mips/ath79/early_printk.c
new file mode 100644
index 00000000000..7499b0e9df2
--- /dev/null
+++ b/arch/mips/ath79/early_printk.c
@@ -0,0 +1,36 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X SoC early printk support
+ *
+ * Copyright (C) 2008-2010 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/io.h>
+#include <linux/serial_reg.h>
+#include <asm/addrspace.h>
+
+#include <asm/mach-ath79/ar71xx_regs.h>
+
+static inline void prom_wait_thre(void __iomem *base)
+{
+ u32 lsr;
+
+ do {
+ lsr = __raw_readl(base + UART_LSR * 4);
+ if (lsr & UART_LSR_THRE)
+ break;
+ } while (1);
+}
+
+void prom_putchar(unsigned char ch)
+{
+ void __iomem *base = (void __iomem *)(KSEG1ADDR(AR71XX_UART_BASE));
+
+ prom_wait_thre(base);
+ __raw_writel(ch, base + UART_TX * 4);
+ prom_wait_thre(base);
+}
diff --git a/arch/mips/ath79/gpio.c b/arch/mips/ath79/gpio.c
new file mode 100644
index 00000000000..a0c426b8212
--- /dev/null
+++ b/arch/mips/ath79/gpio.c
@@ -0,0 +1,197 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X GPIO API support
+ *
+ * Copyright (C) 2008-2010 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-ath79/ar71xx_regs.h>
+#include <asm/mach-ath79/ath79.h>
+#include "common.h"
+
+static void __iomem *ath79_gpio_base;
+static unsigned long ath79_gpio_count;
+static DEFINE_SPINLOCK(ath79_gpio_lock);
+
+static void __ath79_gpio_set_value(unsigned gpio, int value)
+{
+ void __iomem *base = ath79_gpio_base;
+
+ if (value)
+ __raw_writel(1 << gpio, base + AR71XX_GPIO_REG_SET);
+ else
+ __raw_writel(1 << gpio, base + AR71XX_GPIO_REG_CLEAR);
+}
+
+static int __ath79_gpio_get_value(unsigned gpio)
+{
+ return (__raw_readl(ath79_gpio_base + AR71XX_GPIO_REG_IN) >> gpio) & 1;
+}
+
+static int ath79_gpio_get_value(struct gpio_chip *chip, unsigned offset)
+{
+ return __ath79_gpio_get_value(offset);
+}
+
+static void ath79_gpio_set_value(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ __ath79_gpio_set_value(offset, value);
+}
+
+static int ath79_gpio_direction_input(struct gpio_chip *chip,
+ unsigned offset)
+{
+ void __iomem *base = ath79_gpio_base;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ath79_gpio_lock, flags);
+
+ __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) & ~(1 << offset),
+ base + AR71XX_GPIO_REG_OE);
+
+ spin_unlock_irqrestore(&ath79_gpio_lock, flags);
+
+ return 0;
+}
+
+static int ath79_gpio_direction_output(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ void __iomem *base = ath79_gpio_base;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ath79_gpio_lock, flags);
+
+ if (value)
+ __raw_writel(1 << offset, base + AR71XX_GPIO_REG_SET);
+ else
+ __raw_writel(1 << offset, base + AR71XX_GPIO_REG_CLEAR);
+
+ __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_OE) | (1 << offset),
+ base + AR71XX_GPIO_REG_OE);
+
+ spin_unlock_irqrestore(&ath79_gpio_lock, flags);
+
+ return 0;
+}
+
+static struct gpio_chip ath79_gpio_chip = {
+ .label = "ath79",
+ .get = ath79_gpio_get_value,
+ .set = ath79_gpio_set_value,
+ .direction_input = ath79_gpio_direction_input,
+ .direction_output = ath79_gpio_direction_output,
+ .base = 0,
+};
+
+void ath79_gpio_function_enable(u32 mask)
+{
+ void __iomem *base = ath79_gpio_base;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ath79_gpio_lock, flags);
+
+ __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_FUNC) | mask,
+ base + AR71XX_GPIO_REG_FUNC);
+ /* flush write */
+ __raw_readl(base + AR71XX_GPIO_REG_FUNC);
+
+ spin_unlock_irqrestore(&ath79_gpio_lock, flags);
+}
+
+void ath79_gpio_function_disable(u32 mask)
+{
+ void __iomem *base = ath79_gpio_base;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ath79_gpio_lock, flags);
+
+ __raw_writel(__raw_readl(base + AR71XX_GPIO_REG_FUNC) & ~mask,
+ base + AR71XX_GPIO_REG_FUNC);
+ /* flush write */
+ __raw_readl(base + AR71XX_GPIO_REG_FUNC);
+
+ spin_unlock_irqrestore(&ath79_gpio_lock, flags);
+}
+
+void ath79_gpio_function_setup(u32 set, u32 clear)
+{
+ void __iomem *base = ath79_gpio_base;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ath79_gpio_lock, flags);
+
+ __raw_writel((__raw_readl(base + AR71XX_GPIO_REG_FUNC) & ~clear) | set,
+ base + AR71XX_GPIO_REG_FUNC);
+ /* flush write */
+ __raw_readl(base + AR71XX_GPIO_REG_FUNC);
+
+ spin_unlock_irqrestore(&ath79_gpio_lock, flags);
+}
+
+void __init ath79_gpio_init(void)
+{
+ int err;
+
+ if (soc_is_ar71xx())
+ ath79_gpio_count = AR71XX_GPIO_COUNT;
+ else if (soc_is_ar724x())
+ ath79_gpio_count = AR724X_GPIO_COUNT;
+ else if (soc_is_ar913x())
+ ath79_gpio_count = AR913X_GPIO_COUNT;
+ else
+ BUG();
+
+ ath79_gpio_base = ioremap_nocache(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE);
+ ath79_gpio_chip.ngpio = ath79_gpio_count;
+
+ err = gpiochip_add(&ath79_gpio_chip);
+ if (err)
+ panic("cannot add AR71xx GPIO chip, error=%d", err);
+}
+
+int gpio_get_value(unsigned gpio)
+{
+ if (gpio < ath79_gpio_count)
+ return __ath79_gpio_get_value(gpio);
+
+ return __gpio_get_value(gpio);
+}
+EXPORT_SYMBOL(gpio_get_value);
+
+void gpio_set_value(unsigned gpio, int value)
+{
+ if (gpio < ath79_gpio_count)
+ __ath79_gpio_set_value(gpio, value);
+ else
+ __gpio_set_value(gpio, value);
+}
+EXPORT_SYMBOL(gpio_set_value);
+
+int gpio_to_irq(unsigned gpio)
+{
+ /* FIXME */
+ return -EINVAL;
+}
+EXPORT_SYMBOL(gpio_to_irq);
+
+int irq_to_gpio(unsigned irq)
+{
+ /* FIXME */
+ return -EINVAL;
+}
+EXPORT_SYMBOL(irq_to_gpio);
diff --git a/arch/mips/ath79/irq.c b/arch/mips/ath79/irq.c
new file mode 100644
index 00000000000..1bf7f719ba5
--- /dev/null
+++ b/arch/mips/ath79/irq.c
@@ -0,0 +1,187 @@
+/*
+ * Atheros AR71xx/AR724x/AR913x specific interrupt handling
+ *
+ * Copyright (C) 2008-2010 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-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include "common.h"
+
+static unsigned int ath79_ip2_flush_reg;
+static unsigned int ath79_ip3_flush_reg;
+
+static void ath79_misc_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+ void __iomem *base = ath79_reset_base;
+ u32 pending;
+
+ pending = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS) &
+ __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
+
+ if (pending & MISC_INT_UART)
+ generic_handle_irq(ATH79_MISC_IRQ_UART);
+
+ else if (pending & MISC_INT_DMA)
+ generic_handle_irq(ATH79_MISC_IRQ_DMA);
+
+ else if (pending & MISC_INT_PERFC)
+ generic_handle_irq(ATH79_MISC_IRQ_PERFC);
+
+ else if (pending & MISC_INT_TIMER)
+ generic_handle_irq(ATH79_MISC_IRQ_TIMER);
+
+ else if (pending & MISC_INT_OHCI)
+ generic_handle_irq(ATH79_MISC_IRQ_OHCI);
+
+ else if (pending & MISC_INT_ERROR)
+ generic_handle_irq(ATH79_MISC_IRQ_ERROR);
+
+ else if (pending & MISC_INT_GPIO)
+ generic_handle_irq(ATH79_MISC_IRQ_GPIO);
+
+ else if (pending & MISC_INT_WDOG)
+ generic_handle_irq(ATH79_MISC_IRQ_WDOG);
+
+ else
+ spurious_interrupt();
+}
+
+static void ar71xx_misc_irq_unmask(unsigned int irq)
+{
+ void __iomem *base = ath79_reset_base;
+ u32 t;
+
+ irq -= ATH79_MISC_IRQ_BASE;
+
+ t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
+ __raw_writel(t | (1 << irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE);
+
+ /* flush write */
+ __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
+}
+
+static void ar71xx_misc_irq_mask(unsigned int irq)
+{
+ void __iomem *base = ath79_reset_base;
+ u32 t;
+
+ irq -= ATH79_MISC_IRQ_BASE;
+
+ t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
+ __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_MISC_INT_ENABLE);
+
+ /* flush write */
+ __raw_readl(base + AR71XX_RESET_REG_MISC_INT_ENABLE);
+}
+
+static void ar724x_misc_irq_ack(unsigned int irq)
+{
+ void __iomem *base = ath79_reset_base;
+ u32 t;
+
+ irq -= ATH79_MISC_IRQ_BASE;
+
+ t = __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS);
+ __raw_writel(t & ~(1 << irq), base + AR71XX_RESET_REG_MISC_INT_STATUS);
+
+ /* flush write */
+ __raw_readl(base + AR71XX_RESET_REG_MISC_INT_STATUS);
+}
+
+static struct irq_chip ath79_misc_irq_chip = {
+ .name = "MISC",
+ .unmask = ar71xx_misc_irq_unmask,
+ .mask = ar71xx_misc_irq_mask,
+};
+
+static void __init ath79_misc_irq_init(void)
+{
+ void __iomem *base = ath79_reset_base;
+ int i;
+
+ __raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_ENABLE);
+ __raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_STATUS);
+
+ if (soc_is_ar71xx() || soc_is_ar913x())
+ ath79_misc_irq_chip.mask_ack = ar71xx_misc_irq_mask;
+ else if (soc_is_ar724x())
+ ath79_misc_irq_chip.ack = ar724x_misc_irq_ack;
+ else
+ BUG();
+
+ for (i = ATH79_MISC_IRQ_BASE;
+ i < ATH79_MISC_IRQ_BASE + ATH79_MISC_IRQ_COUNT; i++) {
+ irq_desc[i].status = IRQ_DISABLED;
+ set_irq_chip_and_handler(i, &ath79_misc_irq_chip,
+ handle_level_irq);
+ }
+
+ set_irq_chained_handler(ATH79_CPU_IRQ_MISC, ath79_misc_irq_handler);
+}
+
+asmlinkage void plat_irq_dispatch(void)
+{
+ unsigned long pending;
+
+ pending = read_c0_status() & read_c0_cause() & ST0_IM;
+
+ if (pending & STATUSF_IP7)
+ do_IRQ(ATH79_CPU_IRQ_TIMER);
+
+ else if (pending & STATUSF_IP2) {
+ ath79_ddr_wb_flush(ath79_ip2_flush_reg);
+ do_IRQ(ATH79_CPU_IRQ_IP2);
+ }
+
+ else if (pending & STATUSF_IP4)
+ do_IRQ(ATH79_CPU_IRQ_GE0);
+
+ else if (pending & STATUSF_IP5)
+ do_IRQ(ATH79_CPU_IRQ_GE1);
+
+ else if (pending & STATUSF_IP3) {
+ ath79_ddr_wb_flush(ath79_ip3_flush_reg);
+ do_IRQ(ATH79_CPU_IRQ_USB);
+ }
+
+ else if (pending & STATUSF_IP6)
+ do_IRQ(ATH79_CPU_IRQ_MISC);
+
+ else
+ spurious_interrupt();
+}
+
+void __init arch_init_irq(void)
+{
+ if (soc_is_ar71xx()) {
+ ath79_ip2_flush_reg = AR71XX_DDR_REG_FLUSH_PCI;
+ ath79_ip3_flush_reg = AR71XX_DDR_REG_FLUSH_USB;
+ } else if (soc_is_ar724x()) {
+ ath79_ip2_flush_reg = AR724X_DDR_REG_FLUSH_PCIE;
+ ath79_ip3_flush_reg = AR724X_DDR_REG_FLUSH_USB;
+ } else if (soc_is_ar913x()) {
+ ath79_ip2_flush_reg = AR913X_DDR_REG_FLUSH_WMAC;
+ ath79_ip3_flush_reg = AR913X_DDR_REG_FLUSH_USB;
+ } else
+ BUG();
+
+ cp0_perfcount_irq = ATH79_MISC_IRQ_PERFC;
+ mips_cpu_irq_init();
+ ath79_misc_irq_init();
+}
diff --git a/arch/mips/ath79/mach-ap81.c b/arch/mips/ath79/mach-ap81.c
new file mode 100644
index 00000000000..eee4c121deb
--- /dev/null
+++ b/arch/mips/ath79/mach-ap81.c
@@ -0,0 +1,98 @@
+/*
+ * Atheros AP81 board support
+ *
+ * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2009 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 "machtypes.h"
+#include "dev-ar913x-wmac.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-spi.h"
+
+#define AP81_GPIO_LED_STATUS 1
+#define AP81_GPIO_LED_AOSS 3
+#define AP81_GPIO_LED_WLAN 6
+#define AP81_GPIO_LED_POWER 14
+
+#define AP81_GPIO_BTN_SW4 12
+#define AP81_GPIO_BTN_SW1 21
+
+#define AP81_KEYS_POLL_INTERVAL 20 /* msecs */
+#define AP81_KEYS_DEBOUNCE_INTERVAL (3 * AP81_KEYS_POLL_INTERVAL)
+
+#define AP81_CAL_DATA_ADDR 0x1fff1000
+
+static struct gpio_led ap81_leds_gpio[] __initdata = {
+ {
+ .name = "ap81:green:status",
+ .gpio = AP81_GPIO_LED_STATUS,
+ .active_low = 1,
+ }, {
+ .name = "ap81:amber:aoss",
+ .gpio = AP81_GPIO_LED_AOSS,
+ .active_low = 1,
+ }, {
+ .name = "ap81:green:wlan",
+ .gpio = AP81_GPIO_LED_WLAN,
+ .active_low = 1,
+ }, {
+ .name = "ap81:green:power",
+ .gpio = AP81_GPIO_LED_POWER,
+ .active_low = 1,
+ }
+};
+
+static struct gpio_keys_button ap81_gpio_keys[] __initdata = {
+ {
+ .desc = "sw1",
+ .type = EV_KEY,
+ .code = BTN_0,
+ .debounce_interval = AP81_KEYS_DEBOUNCE_INTERVAL,
+ .gpio = AP81_GPIO_BTN_SW1,
+ .active_low = 1,
+ } , {
+ .desc = "sw4",
+ .type = EV_KEY,
+ .code = BTN_1,
+ .debounce_interval = AP81_KEYS_DEBOUNCE_INTERVAL,
+ .gpio = AP81_GPIO_BTN_SW4,
+ .active_low = 1,
+ }
+};
+
+static struct spi_board_info ap81_spi_info[] = {
+ {
+ .bus_num = 0,
+ .chip_select = 0,
+ .max_speed_hz = 25000000,
+ .modalias = "m25p64",
+ }
+};
+
+static struct ath79_spi_platform_data ap81_spi_data = {
+ .bus_num = 0,
+ .num_chipselect = 1,
+};
+
+static void __init ap81_setup(void)
+{
+ u8 *cal_data = (u8 *) KSEG1ADDR(AP81_CAL_DATA_ADDR);
+
+ ath79_register_leds_gpio(-1, ARRAY_SIZE(ap81_leds_gpio),
+ ap81_leds_gpio);
+ ath79_register_gpio_keys_polled(-1, AP81_KEYS_POLL_INTERVAL,
+ ARRAY_SIZE(ap81_gpio_keys),
+ ap81_gpio_keys);
+ ath79_register_spi(&ap81_spi_data, ap81_spi_info,
+ ARRAY_SIZE(ap81_spi_info));
+ ath79_register_ar913x_wmac(cal_data);
+}
+
+MIPS_MACHINE(ATH79_MACH_AP81, "AP81", "Atheros AP81 reference board",
+ ap81_setup);
diff --git a/arch/mips/ath79/mach-pb44.c b/arch/mips/ath79/mach-pb44.c
new file mode 100644
index 00000000000..ec7b7a135d5
--- /dev/null
+++ b/arch/mips/ath79/mach-pb44.c
@@ -0,0 +1,118 @@
+/*
+ * Atheros PB44 reference board support
+ *
+ * Copyright (C) 2009-2010 Gabor Juhos <juhosg@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/i2c.h>
+#include <linux/i2c-gpio.h>
+#include <linux/i2c/pcf857x.h>
+
+#include "machtypes.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-spi.h"
+
+#define PB44_GPIO_I2C_SCL 0
+#define PB44_GPIO_I2C_SDA 1
+
+#define PB44_GPIO_EXP_BASE 16
+#define PB44_GPIO_SW_RESET (PB44_GPIO_EXP_BASE + 6)
+#define PB44_GPIO_SW_JUMP (PB44_GPIO_EXP_BASE + 8)
+#define PB44_GPIO_LED_JUMP1 (PB44_GPIO_EXP_BASE + 9)
+#define PB44_GPIO_LED_JUMP2 (PB44_GPIO_EXP_BASE + 10)
+
+#define PB44_KEYS_POLL_INTERVAL 20 /* msecs */
+#define PB44_KEYS_DEBOUNCE_INTERVAL (3 * PB44_KEYS_POLL_INTERVAL)
+
+static struct i2c_gpio_platform_data pb44_i2c_gpio_data = {
+ .sda_pin = PB44_GPIO_I2C_SDA,
+ .scl_pin = PB44_GPIO_I2C_SCL,
+};
+
+static struct platform_device pb44_i2c_gpio_device = {
+ .name = "i2c-gpio",
+ .id = 0,
+ .dev = {
+ .platform_data = &pb44_i2c_gpio_data,
+ }
+};
+
+static struct pcf857x_platform_data pb44_pcf857x_data = {
+ .gpio_base = PB44_GPIO_EXP_BASE,
+};
+
+static struct i2c_board_info pb44_i2c_board_info[] __initdata = {
+ {
+ I2C_BOARD_INFO("pcf8575", 0x20),
+ .platform_data = &pb44_pcf857x_data,
+ },
+};
+
+static struct gpio_led pb44_leds_gpio[] __initdata = {
+ {
+ .name = "pb44:amber:jump1",
+ .gpio = PB44_GPIO_LED_JUMP1,
+ .active_low = 1,
+ }, {
+ .name = "pb44:green:jump2",
+ .gpio = PB44_GPIO_LED_JUMP2,
+ .active_low = 1,
+ },
+};
+
+static struct gpio_keys_button pb44_gpio_keys[] __initdata = {
+ {
+ .desc = "soft_reset",
+ .type = EV_KEY,
+ .code = KEY_RESTART,
+ .debounce_interval = PB44_KEYS_DEBOUNCE_INTERVAL,
+ .gpio = PB44_GPIO_SW_RESET,
+ .active_low = 1,
+ } , {
+ .desc = "jumpstart",
+ .type = EV_KEY,
+ .code = KEY_WPS_BUTTON,
+ .debounce_interval = PB44_KEYS_DEBOUNCE_INTERVAL,
+ .gpio = PB44_GPIO_SW_JUMP,
+ .active_low = 1,
+ }
+};
+
+static struct spi_board_info pb44_spi_info[] = {
+ {
+ .bus_num = 0,
+ .chip_select = 0,
+ .max_speed_hz = 25000000,
+ .modalias = "m25p64",
+ },
+};
+
+static struct ath79_spi_platform_data pb44_spi_data = {
+ .bus_num = 0,
+ .num_chipselect = 1,
+};
+
+static void __init pb44_init(void)
+{
+ i2c_register_board_info(0, pb44_i2c_board_info,
+ ARRAY_SIZE(pb44_i2c_board_info));
+ platform_device_register(&pb44_i2c_gpio_device);
+
+ ath79_register_leds_gpio(-1, ARRAY_SIZE(pb44_leds_gpio),
+ pb44_leds_gpio);
+ ath79_register_gpio_keys_polled(-1, PB44_KEYS_POLL_INTERVAL,
+ ARRAY_SIZE(pb44_gpio_keys),
+ pb44_gpio_keys);
+ ath79_register_spi(&pb44_spi_data, pb44_spi_info,
+ ARRAY_SIZE(pb44_spi_info));
+}
+
+MIPS_MACHINE(ATH79_MACH_PB44, "PB44", "Atheros PB44 reference board",
+ pb44_init);
diff --git a/arch/mips/ath79/machtypes.h b/arch/mips/ath79/machtypes.h
new file mode 100644
index 00000000000..3940fe470b2
--- /dev/null
+++ b/arch/mips/ath79/machtypes.h
@@ -0,0 +1,23 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X machine type definitions
+ *
+ * Copyright (C) 2008-2010 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.
+ */
+
+#ifndef _ATH79_MACHTYPE_H
+#define _ATH79_MACHTYPE_H
+
+#include <asm/mips_machine.h>
+
+enum ath79_mach_type {
+ ATH79_MACH_GENERIC = 0,
+ ATH79_MACH_AP81, /* Atheros AP81 reference board */
+ ATH79_MACH_PB44, /* Atheros PB44 reference board */
+};
+
+#endif /* _ATH79_MACHTYPE_H */
diff --git a/arch/mips/ath79/prom.c b/arch/mips/ath79/prom.c
new file mode 100644
index 00000000000..e9cbd7c2918
--- /dev/null
+++ b/arch/mips/ath79/prom.c
@@ -0,0 +1,57 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X specific prom routines
+ *
+ * Copyright (C) 2008-2010 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/string.h>
+
+#include <asm/bootinfo.h>
+#include <asm/addrspace.h>
+
+#include "common.h"
+
+static inline int is_valid_ram_addr(void *addr)
+{
+ if (((u32) addr > KSEG0) &&
+ ((u32) addr < (KSEG0 + ATH79_MEM_SIZE_MAX)))
+ return 1;
+
+ if (((u32) addr > KSEG1) &&
+ ((u32) addr < (KSEG1 + ATH79_MEM_SIZE_MAX)))
+ return 1;
+
+ return 0;
+}
+
+static __init void ath79_prom_init_cmdline(int argc, char **argv)
+{
+ int i;
+
+ if (!is_valid_ram_addr(argv))
+ return;
+
+ for (i = 0; i < argc; i++)
+ if (is_valid_ram_addr(argv[i])) {
+ strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline));
+ strlcat(arcs_cmdline, argv[i], sizeof(arcs_cmdline));
+ }
+}
+
+void __init prom_init(void)
+{
+ ath79_prom_init_cmdline(fw_arg0, (char **)fw_arg1);
+}
+
+void __init prom_free_prom_memory(void)
+{
+ /* We do not have to prom memory to free */
+}
diff --git a/arch/mips/ath79/setup.c b/arch/mips/ath79/setup.c
new file mode 100644
index 00000000000..159b42f106b
--- /dev/null
+++ b/arch/mips/ath79/setup.c
@@ -0,0 +1,206 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X specific setup
+ *
+ * Copyright (C) 2008-2011 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/bootmem.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#include <asm/bootinfo.h>
+#include <asm/time.h> /* for mips_hpt_frequency */
+#include <asm/reboot.h> /* for _machine_{restart,halt} */
+#include <asm/mips_machine.h>
+
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include "common.h"
+#include "dev-common.h"
+#include "machtypes.h"
+
+#define ATH79_SYS_TYPE_LEN 64
+
+#define AR71XX_BASE_FREQ 40000000
+#define AR724X_BASE_FREQ 5000000
+#define AR913X_BASE_FREQ 5000000
+
+static char ath79_sys_type[ATH79_SYS_TYPE_LEN];
+
+static void ath79_restart(char *command)
+{
+ ath79_device_reset_set(AR71XX_RESET_FULL_CHIP);
+ for (;;)
+ if (cpu_wait)
+ cpu_wait();
+}
+
+static void ath79_halt(void)
+{
+ while (1)
+ cpu_wait();
+}
+
+static void __init ath79_detect_mem_size(void)
+{
+ unsigned long size;
+
+ for (size = ATH79_MEM_SIZE_MIN; size < ATH79_MEM_SIZE_MAX;
+ size <<= 1) {
+ if (!memcmp(ath79_detect_mem_size,
+ ath79_detect_mem_size + size, 1024))
+ break;
+ }
+
+ add_memory_region(0, size, BOOT_MEM_RAM);
+}
+
+static void __init ath79_detect_sys_type(void)
+{
+ char *chip = "????";
+ u32 id;
+ u32 major;
+ u32 minor;
+ u32 rev = 0;
+
+ id = ath79_reset_rr(AR71XX_RESET_REG_REV_ID);
+ major = id & REV_ID_MAJOR_MASK;
+
+ switch (major) {
+ case REV_ID_MAJOR_AR71XX:
+ minor = id & AR71XX_REV_ID_MINOR_MASK;
+ rev = id >> AR71XX_REV_ID_REVISION_SHIFT;
+ rev &= AR71XX_REV_ID_REVISION_MASK;
+ switch (minor) {
+ case AR71XX_REV_ID_MINOR_AR7130:
+ ath79_soc = ATH79_SOC_AR7130;
+ chip = "7130";
+ break;
+
+ case AR71XX_REV_ID_MINOR_AR7141:
+ ath79_soc = ATH79_SOC_AR7141;
+ chip = "7141";
+ break;
+
+ case AR71XX_REV_ID_MINOR_AR7161:
+ ath79_soc = ATH79_SOC_AR7161;
+ chip = "7161";
+ break;
+ }
+ break;
+
+ case REV_ID_MAJOR_AR7240:
+ ath79_soc = ATH79_SOC_AR7240;
+ chip = "7240";
+ rev = (id & AR724X_REV_ID_REVISION_MASK);
+ break;
+
+ case REV_ID_MAJOR_AR7241:
+ ath79_soc = ATH79_SOC_AR7241;
+ chip = "7241";
+ rev = (id & AR724X_REV_ID_REVISION_MASK);
+ break;
+
+ case REV_ID_MAJOR_AR7242:
+ ath79_soc = ATH79_SOC_AR7242;
+ chip = "7242";
+ rev = (id & AR724X_REV_ID_REVISION_MASK);
+ break;
+
+ case REV_ID_MAJOR_AR913X:
+ minor = id & AR913X_REV_ID_MINOR_MASK;
+ rev = id >> AR913X_REV_ID_REVISION_SHIFT;
+ rev &= AR913X_REV_ID_REVISION_MASK;
+ switch (minor) {
+ case AR913X_REV_ID_MINOR_AR9130:
+ ath79_soc = ATH79_SOC_AR9130;
+ chip = "9130";
+ break;
+
+ case AR913X_REV_ID_MINOR_AR9132:
+ ath79_soc = ATH79_SOC_AR9132;
+ chip = "9132";
+ break;
+ }
+ break;
+
+ default:
+ panic("ath79: unknown SoC, id:0x%08x\n", id);
+ }
+
+ sprintf(ath79_sys_type, "Atheros AR%s rev %u", chip, rev);
+ pr_info("SoC: %s\n", ath79_sys_type);
+}
+
+const char *get_system_type(void)
+{
+ return ath79_sys_type;
+}
+
+unsigned int __cpuinit get_c0_compare_int(void)
+{
+ return CP0_LEGACY_COMPARE_IRQ;
+}
+
+void __init plat_mem_setup(void)
+{
+ set_io_port_base(KSEG1);
+
+ ath79_reset_base = ioremap_nocache(AR71XX_RESET_BASE,
+ AR71XX_RESET_SIZE);
+ ath79_pll_base = ioremap_nocache(AR71XX_PLL_BASE,
+ AR71XX_PLL_SIZE);
+ ath79_ddr_base = ioremap_nocache(AR71XX_DDR_CTRL_BASE,
+ AR71XX_DDR_CTRL_SIZE);
+
+ ath79_detect_sys_type();
+ ath79_detect_mem_size();
+ ath79_clocks_init();
+
+ _machine_restart = ath79_restart;
+ _machine_halt = ath79_halt;
+ pm_power_off = ath79_halt;
+}
+
+void __init plat_time_init(void)
+{
+ struct clk *clk;
+
+ clk = clk_get(NULL, "cpu");
+ if (IS_ERR(clk))
+ panic("unable to get CPU clock, err=%ld", PTR_ERR(clk));
+
+ mips_hpt_frequency = clk_get_rate(clk) / 2;
+}
+
+static int __init ath79_setup(void)
+{
+ ath79_gpio_init();
+ ath79_register_uart();
+ ath79_register_wdt();
+
+ mips_machine_setup();
+
+ return 0;
+}
+
+arch_initcall(ath79_setup);
+
+static void __init ath79_generic_init(void)
+{
+ /* Nothing to do */
+}
+
+MIPS_MACHINE(ATH79_MACH_GENERIC,
+ "Generic",
+ "Generic AR71XX/AR724X/AR913X based board",
+ ath79_generic_init);