Subject: [PATCH 00/11] MIPS: ath79: add support for the QCA955X SoCs

From: Gabor Juhos <[email-masked]>
Date: Fri, 15 Feb 2013 15:38:14 +0100

This series adds support for the Qualcomm Atheros QCA955[68] SoCs
and for the AP136-010 reference board

The series depends on the following patch:
  MIPS: ath79: use dynamically allocated USB platform devices
  https://patchwork.linux-mips.org/patch/4933/

Gabor Juhos (11):
  MIPS: ath79: add early printk support for the QCA955X SoCs
  MIPS: ath79: add SoC detection code for the QCA955X SoCs
  MIPS: ath79: add clock setup code for the QCA955X SoCs
  MIPS: ath79: add IRQ handling code for the QCA955X SoCs
  MIPS: ath79: add GPIO setup code for the QCA955X SoCs
  MIPS: ath79: add QCA955X specific glue to ath79_device_reset_{set,clear}
  MIPS: ath79: register UART for the QCA955X SoCs
  MIPS: ath79: add WMAC registration code for the QCA955X SoCs
  MIPS: ath79: add PCI controller registration code for the QCA9558 SoC
  MIPS: ath79: add USB controller registration code for the QCA955X SoCs
  MIPS: ath79: add support for the Qualcomm Atheros AP136-010 board

 arch/mips/ath79/Kconfig                        |   20 ++-
 arch/mips/ath79/Makefile                       |    1 +
 arch/mips/ath79/clock.c                        |   78 ++++++++++++
 arch/mips/ath79/common.c                       |    4 +
 arch/mips/ath79/dev-common.c                   |    3 +-
 arch/mips/ath79/dev-usb.c                      |   15 +++
 arch/mips/ath79/dev-wmac.c                     |   20 +++
 arch/mips/ath79/early_printk.c                 |    2 +
 arch/mips/ath79/gpio.c                         |    4 +-
 arch/mips/ath79/irq.c                          |  110 +++++++++++++++--
 arch/mips/ath79/mach-ap136.c                   |  156 ++++++++++++++++++++++++
 arch/mips/ath79/machtypes.h                    |    1 +
 arch/mips/ath79/pci.c                          |   36 ++++++
 arch/mips/ath79/setup.c                        |   18 ++-
 arch/mips/configs/ath79_defconfig              |    1 +
 arch/mips/include/asm/mach-ath79/ar71xx_regs.h |   96 +++++++++++++++
 arch/mips/include/asm/mach-ath79/ath79.h       |   17 +++
 arch/mips/include/asm/mach-ath79/irq.h         |    6 +-
 18 files changed, 576 insertions(+), 12 deletions(-)
 create mode 100644 arch/mips/ath79/mach-ap136.c

--
1.7.10

---

From: Gabor Juhos <[email-masked]>
Date: Fri, 15 Feb 2013 15:38:16 +0100

Also add 'soc_is_qca955[68x]' helper functions
and a Kconfig symbol for the SoC family.

Cc: Rodriguez, Luis <[email-masked]>
Cc: Giori, Kathy <[email-masked]>
Cc: QCA Linux Team <[email-masked]>
Signed-off-by: Gabor Juhos <[email-masked]>
---
 arch/mips/ath79/Kconfig                        |    4 ++++
 arch/mips/ath79/setup.c                        |   18 +++++++++++++++++-
 arch/mips/include/asm/mach-ath79/ar71xx_regs.h |    2 ++
 arch/mips/include/asm/mach-ath79/ath79.h       |   17 +++++++++++++++++
 4 files changed, 40 insertions(+), 1 deletion(-)

diff --git a/arch/mips/ath79/Kconfig b/arch/mips/ath79/Kconfig
index f44feee..cffdc8e 100644
--- a/arch/mips/ath79/Kconfig
+++ b/arch/mips/ath79/Kconfig
@@ -88,6 +88,10 @@ config SOC_AR934X
 	select PCI_AR724X if PCI
 	def_bool n
 
+config SOC_QCA955X
+	select USB_ARCH_HAS_EHCI
+	def_bool n
+
 config PCI_AR724X
 	def_bool n
 
diff --git a/arch/mips/ath79/setup.c b/arch/mips/ath79/setup.c
index 60d212e..d5b3c90 100644
--- a/arch/mips/ath79/setup.c
+++ b/arch/mips/ath79/setup.c
@@ -164,13 +164,29 @@ static void __init ath79_detect_sys_type(void)
 		rev = id & AR934X_REV_ID_REVISION_MASK;
 		break;
 
+	case REV_ID_MAJOR_QCA9556:
+		ath79_soc = ATH79_SOC_QCA9556;
+		chip = "9556";
+		rev = id & QCA955X_REV_ID_REVISION_MASK;
+		break;
+
+	case REV_ID_MAJOR_QCA9558:
+		ath79_soc = ATH79_SOC_QCA9558;
+		chip = "9558";
+		rev = id & QCA955X_REV_ID_REVISION_MASK;
+		break;
+
 	default:
 		panic("ath79: unknown SoC, id:0x%08x", id);
 	}
 
 	ath79_soc_rev = rev;
 
-	sprintf(ath79_sys_type, "Atheros AR%s rev %u", chip, rev);
+	if (soc_is_qca955x())
+		sprintf(ath79_sys_type, "Qualcomm Atheros QCA%s rev %u",
+			chip, rev);
+	else
+		sprintf(ath79_sys_type, "Atheros AR%s rev %u", chip, rev);
 	pr_info("SoC: %s\n", ath79_sys_type);
 }
 
diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
index d02c2d4..63a9f2b 100644
--- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
+++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
@@ -392,6 +392,8 @@
 
 #define AR934X_REV_ID_REVISION_MASK     0xf
 
+#define QCA955X_REV_ID_REVISION_MASK	0xf
+
 /*
  * SPI block
  */
diff --git a/arch/mips/include/asm/mach-ath79/ath79.h b/arch/mips/include/asm/mach-ath79/ath79.h
index 4f248c3..1557934 100644
--- a/arch/mips/include/asm/mach-ath79/ath79.h
+++ b/arch/mips/include/asm/mach-ath79/ath79.h
@@ -32,6 +32,8 @@ enum ath79_soc_type {
 	ATH79_SOC_AR9341,
 	ATH79_SOC_AR9342,
 	ATH79_SOC_AR9344,
+	ATH79_SOC_QCA9556,
+	ATH79_SOC_QCA9558,
 };
 
 extern enum ath79_soc_type ath79_soc;
@@ -98,6 +100,21 @@ static inline int soc_is_ar934x(void)
 	return soc_is_ar9341() || soc_is_ar9342() || soc_is_ar9344();
 }
 
+static inline int soc_is_qca9556(void)
+{
+	return ath79_soc == ATH79_SOC_QCA9556;
+}
+
+static inline int soc_is_qca9558(void)
+{
+	return ath79_soc == ATH79_SOC_QCA9558;
+}
+
+static inline int soc_is_qca955x(void)
+{
+	return soc_is_qca9556() || soc_is_qca9558();
+}
+
 extern void __iomem *ath79_ddr_base;
 extern void __iomem *ath79_pll_base;
 extern void __iomem *ath79_reset_base;
-- 
1.7.10

---

From: Gabor Juhos <[email-masked]>
Date: Fri, 15 Feb 2013 15:38:15 +0100

The patch allows to see kernel messages on the
QCA955X SoCs in early boot stage.

Cc: Rodriguez, Luis <[email-masked]>
Cc: Giori, Kathy <[email-masked]>
Cc: QCA Linux Team <[email-masked]>
Signed-off-by: Gabor Juhos <[email-masked]>
---
 arch/mips/ath79/early_printk.c                 |    2 ++
 arch/mips/include/asm/mach-ath79/ar71xx_regs.h |    2 ++
 2 files changed, 4 insertions(+)

diff --git a/arch/mips/ath79/early_printk.c b/arch/mips/ath79/early_printk.c
index dc938cb..b955faf 100644
--- a/arch/mips/ath79/early_printk.c
+++ b/arch/mips/ath79/early_printk.c
@@ -74,6 +74,8 @@ static void prom_putchar_init(void)
 	case REV_ID_MAJOR_AR9341:
 	case REV_ID_MAJOR_AR9342:
 	case REV_ID_MAJOR_AR9344:
+	case REV_ID_MAJOR_QCA9556:
+	case REV_ID_MAJOR_QCA9558:
 		_prom_putchar = prom_putchar_ar71xx;
 		break;
 
diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
index a77f6ee..d02c2d4 100644
--- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
+++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
@@ -370,6 +370,8 @@
 #define REV_ID_MAJOR_AR9341		0x0120
 #define REV_ID_MAJOR_AR9342		0x1120
 #define REV_ID_MAJOR_AR9344		0x2120
+#define REV_ID_MAJOR_QCA9556		0x0130
+#define REV_ID_MAJOR_QCA9558		0x1130
 
 #define AR71XX_REV_ID_MINOR_MASK	0x3
 #define AR71XX_REV_ID_MINOR_AR7130	0x0
-- 
1.7.10

---

From: Gabor Juhos <[email-masked]>
Date: Fri, 15 Feb 2013 15:38:17 +0100

The patch adds code to get various clock frequencies
from the PLLs used in the QCA955x SoCs.

Cc: Rodriguez, Luis <[email-masked]>
Cc: Giori, Kathy <[email-masked]>
Cc: QCA Linux Team <[email-masked]>
Signed-off-by: Gabor Juhos <[email-masked]>
---
 arch/mips/ath79/clock.c                        |   78 ++++++++++++++++++++++++
 arch/mips/include/asm/mach-ath79/ar71xx_regs.h |   39 ++++++++++++
 2 files changed, 117 insertions(+)

diff --git a/arch/mips/ath79/clock.c b/arch/mips/ath79/clock.c
index 579f452..555e603 100644
--- a/arch/mips/ath79/clock.c
+++ b/arch/mips/ath79/clock.c
@@ -295,6 +295,82 @@ static void __init ar934x_clocks_init(void)
 	iounmap(dpll_base);
 }
 
+static void __init qca955x_clocks_init(void)
+{
+	u32 pll, out_div, ref_div, nint, frac, clk_ctrl, postdiv;
+	u32 cpu_pll, ddr_pll;
+	u32 bootstrap;
+
+	bootstrap = ath79_reset_rr(QCA955X_RESET_REG_BOOTSTRAP);
+	if (bootstrap &	QCA955X_BOOTSTRAP_REF_CLK_40)
+		ath79_ref_clk.rate = 40 * 1000 * 1000;
+	else
+		ath79_ref_clk.rate = 25 * 1000 * 1000;
+
+	pll = ath79_pll_rr(QCA955X_PLL_CPU_CONFIG_REG);
+	out_div = (pll >> QCA955X_PLL_CPU_CONFIG_OUTDIV_SHIFT) &
+		  QCA955X_PLL_CPU_CONFIG_OUTDIV_MASK;
+	ref_div = (pll >> QCA955X_PLL_CPU_CONFIG_REFDIV_SHIFT) &
+		  QCA955X_PLL_CPU_CONFIG_REFDIV_MASK;
+	nint = (pll >> QCA955X_PLL_CPU_CONFIG_NINT_SHIFT) &
+	       QCA955X_PLL_CPU_CONFIG_NINT_MASK;
+	frac = (pll >> QCA955X_PLL_CPU_CONFIG_NFRAC_SHIFT) &
+	       QCA955X_PLL_CPU_CONFIG_NFRAC_MASK;
+
+	cpu_pll = nint * ath79_ref_clk.rate / ref_div;
+	cpu_pll += frac * ath79_ref_clk.rate / (ref_div * (1 << 6));
+	cpu_pll /= (1 << out_div);
+
+	pll = ath79_pll_rr(QCA955X_PLL_DDR_CONFIG_REG);
+	out_div = (pll >> QCA955X_PLL_DDR_CONFIG_OUTDIV_SHIFT) &
+		  QCA955X_PLL_DDR_CONFIG_OUTDIV_MASK;
+	ref_div = (pll >> QCA955X_PLL_DDR_CONFIG_REFDIV_SHIFT) &
+		  QCA955X_PLL_DDR_CONFIG_REFDIV_MASK;
+	nint = (pll >> QCA955X_PLL_DDR_CONFIG_NINT_SHIFT) &
+	       QCA955X_PLL_DDR_CONFIG_NINT_MASK;
+	frac = (pll >> QCA955X_PLL_DDR_CONFIG_NFRAC_SHIFT) &
+	       QCA955X_PLL_DDR_CONFIG_NFRAC_MASK;
+
+	ddr_pll = nint * ath79_ref_clk.rate / ref_div;
+	ddr_pll += frac * ath79_ref_clk.rate / (ref_div * (1 << 10));
+	ddr_pll /= (1 << out_div);
+
+	clk_ctrl = ath79_pll_rr(QCA955X_PLL_CLK_CTRL_REG);
+
+	postdiv = (clk_ctrl >> QCA955X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT) &
+		  QCA955X_PLL_CLK_CTRL_CPU_POST_DIV_MASK;
+
+	if (clk_ctrl & QCA955X_PLL_CLK_CTRL_CPU_PLL_BYPASS)
+		ath79_cpu_clk.rate = ath79_ref_clk.rate;
+	else if (clk_ctrl & QCA955X_PLL_CLK_CTRL_CPUCLK_FROM_CPUPLL)
+		ath79_cpu_clk.rate = ddr_pll / (postdiv + 1);
+	else
+		ath79_cpu_clk.rate = cpu_pll / (postdiv + 1);
+
+	postdiv = (clk_ctrl >> QCA955X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT) &
+		  QCA955X_PLL_CLK_CTRL_DDR_POST_DIV_MASK;
+
+	if (clk_ctrl & QCA955X_PLL_CLK_CTRL_DDR_PLL_BYPASS)
+		ath79_ddr_clk.rate = ath79_ref_clk.rate;
+	else if (clk_ctrl & QCA955X_PLL_CLK_CTRL_DDRCLK_FROM_DDRPLL)
+		ath79_ddr_clk.rate = cpu_pll / (postdiv + 1);
+	else
+		ath79_ddr_clk.rate = ddr_pll / (postdiv + 1);
+
+	postdiv = (clk_ctrl >> QCA955X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT) &
+		  QCA955X_PLL_CLK_CTRL_AHB_POST_DIV_MASK;
+
+	if (clk_ctrl & QCA955X_PLL_CLK_CTRL_AHB_PLL_BYPASS)
+		ath79_ahb_clk.rate = ath79_ref_clk.rate;
+	else if (clk_ctrl & QCA955X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL)
+		ath79_ahb_clk.rate = ddr_pll / (postdiv + 1);
+	else
+		ath79_ahb_clk.rate = cpu_pll / (postdiv + 1);
+
+	ath79_wdt_clk.rate = ath79_ref_clk.rate;
+	ath79_uart_clk.rate = ath79_ref_clk.rate;
+}
+
 void __init ath79_clocks_init(void)
 {
 	if (soc_is_ar71xx())
@@ -307,6 +383,8 @@ void __init ath79_clocks_init(void)
 		ar933x_clocks_init();
 	else if (soc_is_ar934x())
 		ar934x_clocks_init();
+	else if (soc_is_qca955x())
+		qca955x_clocks_init();
 	else
 		BUG();
 
diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
index 63a9f2b..7b00e12 100644
--- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
+++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
@@ -225,6 +225,41 @@
 #define AR934X_PLL_CPU_DDR_CLK_CTRL_DDRCLK_FROM_DDRPLL	BIT(21)
 #define AR934X_PLL_CPU_DDR_CLK_CTRL_AHBCLK_FROM_DDRPLL	BIT(24)
 
+#define QCA955X_PLL_CPU_CONFIG_REG		0x00
+#define QCA955X_PLL_DDR_CONFIG_REG		0x04
+#define QCA955X_PLL_CLK_CTRL_REG		0x08
+
+#define QCA955X_PLL_CPU_CONFIG_NFRAC_SHIFT	0
+#define QCA955X_PLL_CPU_CONFIG_NFRAC_MASK	0x3f
+#define QCA955X_PLL_CPU_CONFIG_NINT_SHIFT	6
+#define QCA955X_PLL_CPU_CONFIG_NINT_MASK	0x3f
+#define QCA955X_PLL_CPU_CONFIG_REFDIV_SHIFT	12
+#define QCA955X_PLL_CPU_CONFIG_REFDIV_MASK	0x1f
+#define QCA955X_PLL_CPU_CONFIG_OUTDIV_SHIFT	19
+#define QCA955X_PLL_CPU_CONFIG_OUTDIV_MASK	0x3
+
+#define QCA955X_PLL_DDR_CONFIG_NFRAC_SHIFT	0
+#define QCA955X_PLL_DDR_CONFIG_NFRAC_MASK	0x3ff
+#define QCA955X_PLL_DDR_CONFIG_NINT_SHIFT	10
+#define QCA955X_PLL_DDR_CONFIG_NINT_MASK	0x3f
+#define QCA955X_PLL_DDR_CONFIG_REFDIV_SHIFT	16
+#define QCA955X_PLL_DDR_CONFIG_REFDIV_MASK	0x1f
+#define QCA955X_PLL_DDR_CONFIG_OUTDIV_SHIFT	23
+#define QCA955X_PLL_DDR_CONFIG_OUTDIV_MASK	0x7
+
+#define QCA955X_PLL_CLK_CTRL_CPU_PLL_BYPASS		BIT(2)
+#define QCA955X_PLL_CLK_CTRL_DDR_PLL_BYPASS		BIT(3)
+#define QCA955X_PLL_CLK_CTRL_AHB_PLL_BYPASS		BIT(4)
+#define QCA955X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT		5
+#define QCA955X_PLL_CLK_CTRL_CPU_POST_DIV_MASK		0x1f
+#define QCA955X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT		10
+#define QCA955X_PLL_CLK_CTRL_DDR_POST_DIV_MASK		0x1f
+#define QCA955X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT		15
+#define QCA955X_PLL_CLK_CTRL_AHB_POST_DIV_MASK		0x1f
+#define QCA955X_PLL_CLK_CTRL_CPUCLK_FROM_CPUPLL		BIT(20)
+#define QCA955X_PLL_CLK_CTRL_DDRCLK_FROM_DDRPLL		BIT(21)
+#define QCA955X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL		BIT(24)
+
 /*
  * USB_CONFIG block
  */
@@ -264,6 +299,8 @@
 #define AR934X_RESET_REG_BOOTSTRAP		0xb0
 #define AR934X_RESET_REG_PCIE_WMAC_INT_STATUS	0xac
 
+#define QCA955X_RESET_REG_BOOTSTRAP		0xb0
+
 #define MISC_INT_ETHSW			BIT(12)
 #define MISC_INT_TIMER4			BIT(10)
 #define MISC_INT_TIMER3			BIT(9)
@@ -341,6 +378,8 @@
 #define AR934X_BOOTSTRAP_SDRAM_DISABLED	BIT(1)
 #define AR934X_BOOTSTRAP_DDR1		BIT(0)
 
+#define QCA955X_BOOTSTRAP_REF_CLK_40	BIT(4)
+
 #define AR934X_PCIE_WMAC_INT_WMAC_MISC		BIT(0)
 #define AR934X_PCIE_WMAC_INT_WMAC_TX		BIT(1)
 #define AR934X_PCIE_WMAC_INT_WMAC_RXLP		BIT(2)
-- 
1.7.10

---

From: Gabor Juhos <[email-masked]>
Date: Fri, 15 Feb 2013 15:38:18 +0100

The IRQ routing in the QCA955x SoCs is slightly
different from the routing implemented in the
already supported SoCs.

Cc: Rodriguez, Luis <[email-masked]>
Cc: Giori, Kathy <[email-masked]>
Cc: QCA Linux Team <[email-masked]>
Signed-off-by: Gabor Juhos <[email-masked]>
---
 arch/mips/ath79/irq.c                          |  110 ++++++++++++++++++++++--
 arch/mips/include/asm/mach-ath79/ar71xx_regs.h |   32 +++++++
 arch/mips/include/asm/mach-ath79/irq.h         |    6 +-
 3 files changed, 140 insertions(+), 8 deletions(-)

diff --git a/arch/mips/ath79/irq.c b/arch/mips/ath79/irq.c
index df88d49..b0f85a6 100644
--- a/arch/mips/ath79/irq.c
+++ b/arch/mips/ath79/irq.c
@@ -103,7 +103,10 @@ static void __init ath79_misc_irq_init(void)
 
 	if (soc_is_ar71xx() || soc_is_ar913x())
 		ath79_misc_irq_chip.irq_mask_ack = ar71xx_misc_irq_mask;
-	else if (soc_is_ar724x() || soc_is_ar933x() || soc_is_ar934x())
+	else if (soc_is_ar724x() ||
+		 soc_is_ar933x() ||
+		 soc_is_ar934x() ||
+		 soc_is_qca955x())
 		ath79_misc_irq_chip.irq_ack = ar724x_misc_irq_ack;
 	else
 		BUG();
@@ -150,6 +153,88 @@ static void ar934x_ip2_irq_init(void)
 	irq_set_chained_handler(ATH79_CPU_IRQ(2), ar934x_ip2_irq_dispatch);
 }
 
+static void qca955x_ip2_irq_dispatch(unsigned int irq, struct irq_desc *desc)
+{
+	u32 status;
+
+	disable_irq_nosync(irq);
+
+	status = ath79_reset_rr(QCA955X_RESET_REG_EXT_INT_STATUS);
+	status &= QCA955X_EXT_INT_PCIE_RC1_ALL | QCA955X_EXT_INT_WMAC_ALL;
+
+	if (status == 0) {
+		spurious_interrupt();
+		goto enable;
+	}
+
+	if (status & QCA955X_EXT_INT_PCIE_RC1_ALL) {
+		/* TODO: flush DDR? */
+		generic_handle_irq(ATH79_IP2_IRQ(0));
+	}
+
+	if (status & QCA955X_EXT_INT_WMAC_ALL) {
+		/* TODO: flsuh DDR? */
+		generic_handle_irq(ATH79_IP2_IRQ(1));
+	}
+
+enable:
+	enable_irq(irq);
+}
+
+static void qca955x_ip3_irq_dispatch(unsigned int irq, struct irq_desc *desc)
+{
+	u32 status;
+
+	disable_irq_nosync(irq);
+
+	status = ath79_reset_rr(QCA955X_RESET_REG_EXT_INT_STATUS);
+	status &= QCA955X_EXT_INT_PCIE_RC2_ALL |
+		  QCA955X_EXT_INT_USB1 |
+		  QCA955X_EXT_INT_USB2;
+
+	if (status == 0) {
+		spurious_interrupt();
+		goto enable;
+	}
+
+	if (status & QCA955X_EXT_INT_USB1) {
+		/* TODO: flush DDR? */
+		generic_handle_irq(ATH79_IP3_IRQ(0));
+	}
+
+	if (status & QCA955X_EXT_INT_USB2) {
+		/* TODO: flsuh DDR? */
+		generic_handle_irq(ATH79_IP3_IRQ(1));
+	}
+
+	if (status & QCA955X_EXT_INT_PCIE_RC2_ALL) {
+		/* TODO: flush DDR? */
+		generic_handle_irq(ATH79_IP3_IRQ(2));
+	}
+
+enable:
+	enable_irq(irq);
+}
+
+static void qca955x_irq_init(void)
+{
+	int i;
+
+	for (i = ATH79_IP2_IRQ_BASE;
+	     i < ATH79_IP2_IRQ_BASE + ATH79_IP2_IRQ_COUNT; i++)
+		irq_set_chip_and_handler(i, &dummy_irq_chip,
+					 handle_level_irq);
+
+	irq_set_chained_handler(ATH79_CPU_IRQ(2), qca955x_ip2_irq_dispatch);
+
+	for (i = ATH79_IP3_IRQ_BASE;
+	     i < ATH79_IP3_IRQ_BASE + ATH79_IP3_IRQ_COUNT; i++)
+		irq_set_chip_and_handler(i, &dummy_irq_chip,
+					 handle_level_irq);
+
+	irq_set_chained_handler(ATH79_CPU_IRQ(3), qca955x_ip3_irq_dispatch);
+}
+
 asmlinkage void plat_irq_dispatch(void)
 {
 	unsigned long pending;
@@ -185,6 +270,17 @@ asmlinkage void plat_irq_dispatch(void)
  * Issue a flush in the handlers to ensure that the driver sees
  * the update.
  */
+
+static void ath79_default_ip2_handler(void)
+{
+	do_IRQ(ATH79_CPU_IRQ(2));
+}
+
+static void ath79_default_ip3_handler(void)
+{
+	do_IRQ(ATH79_CPU_IRQ(3));
+}
+
 static void ar71xx_ip2_handler(void)
 {
 	ath79_ddr_wb_flush(AR71XX_DDR_REG_FLUSH_PCI);
@@ -209,11 +305,6 @@ static void ar933x_ip2_handler(void)
 	do_IRQ(ATH79_CPU_IRQ(2));
 }
 
-static void ar934x_ip2_handler(void)
-{
-	do_IRQ(ATH79_CPU_IRQ(2));
-}
-
 static void ar71xx_ip3_handler(void)
 {
 	ath79_ddr_wb_flush(AR71XX_DDR_REG_FLUSH_USB);
@@ -259,8 +350,11 @@ void __init arch_init_irq(void)
 		ath79_ip2_handler = ar933x_ip2_handler;
 		ath79_ip3_handler = ar933x_ip3_handler;
 	} else if (soc_is_ar934x()) {
-		ath79_ip2_handler = ar934x_ip2_handler;
+		ath79_ip2_handler = ath79_default_ip2_handler;
 		ath79_ip3_handler = ar934x_ip3_handler;
+	} else if (soc_is_qca955x()) {
+		ath79_ip2_handler = ath79_default_ip2_handler;
+		ath79_ip3_handler = ath79_default_ip3_handler;
 	} else {
 		BUG();
 	}
@@ -271,4 +365,6 @@ void __init arch_init_irq(void)
 
 	if (soc_is_ar934x())
 		ar934x_ip2_irq_init();
+		qca955x_irq_init();
index 7b00e12..8782d8b 100644
@@ -300,6 +300,7 @@
 
 #define QCA955X_RESET_REG_BOOTSTRAP		0xb0
+#define QCA955X_RESET_REG_EXT_INT_STATUS	0xac
 
 #define MISC_INT_ETHSW			BIT(12)
 #define MISC_INT_TIMER4			BIT(10)
@@ -398,6 +399,37 @@
 	 AR934X_PCIE_WMAC_INT_PCIE_RC1 | AR934X_PCIE_WMAC_INT_PCIE_RC2 | \
 	 AR934X_PCIE_WMAC_INT_PCIE_RC3)
 
+#define QCA955X_EXT_INT_WMAC_MISC		BIT(0)
+#define QCA955X_EXT_INT_WMAC_TX			BIT(1)
+#define QCA955X_EXT_INT_WMAC_RXLP		BIT(2)
+#define QCA955X_EXT_INT_WMAC_RXHP		BIT(3)
+#define QCA955X_EXT_INT_PCIE_RC1		BIT(4)
+#define QCA955X_EXT_INT_PCIE_RC1_INT0		BIT(5)
+#define QCA955X_EXT_INT_PCIE_RC1_INT1		BIT(6)
+#define QCA955X_EXT_INT_PCIE_RC1_INT2		BIT(7)
+#define QCA955X_EXT_INT_PCIE_RC1_INT3		BIT(8)
+#define QCA955X_EXT_INT_PCIE_RC2		BIT(12)
+#define QCA955X_EXT_INT_PCIE_RC2_INT0		BIT(13)
+#define QCA955X_EXT_INT_PCIE_RC2_INT1		BIT(14)
+#define QCA955X_EXT_INT_PCIE_RC2_INT2		BIT(15)
+#define QCA955X_EXT_INT_PCIE_RC2_INT3		BIT(16)
+#define QCA955X_EXT_INT_USB1			BIT(24)
+#define QCA955X_EXT_INT_USB2			BIT(28)
+
+#define QCA955X_EXT_INT_WMAC_ALL \
+	(QCA955X_EXT_INT_WMAC_MISC | QCA955X_EXT_INT_WMAC_TX | \
+	 QCA955X_EXT_INT_WMAC_RXLP | QCA955X_EXT_INT_WMAC_RXHP)
+
+#define QCA955X_EXT_INT_PCIE_RC1_ALL \
+	(QCA955X_EXT_INT_PCIE_RC1 | QCA955X_EXT_INT_PCIE_RC1_INT0 | \
+	 QCA955X_EXT_INT_PCIE_RC1_INT1 | QCA955X_EXT_INT_PCIE_RC1_INT2 | \
+	 QCA955X_EXT_INT_PCIE_RC1_INT3)
+
+#define QCA955X_EXT_INT_PCIE_RC2_ALL \
+	(QCA955X_EXT_INT_PCIE_RC2 | QCA955X_EXT_INT_PCIE_RC2_INT0 | \
+	 QCA955X_EXT_INT_PCIE_RC2_INT1 | QCA955X_EXT_INT_PCIE_RC2_INT2 | \
+	 QCA955X_EXT_INT_PCIE_RC2_INT3)
+
 #define REV_ID_MAJOR_MASK		0xfff0
 #define REV_ID_MAJOR_AR71XX		0x00a0
 #define REV_ID_MAJOR_AR913X		0x00b0
diff --git a/arch/mips/include/asm/mach-ath79/irq.h b/arch/mips/include/asm/mach-ath79/irq.h
index 23e2bba..5c9ca76 100644
--- a/arch/mips/include/asm/mach-ath79/irq.h
+++ b/arch/mips/include/asm/mach-ath79/irq.h
@@ -10,7 +10,7 @@
 #define __ASM_MACH_ATH79_IRQ_H
 
 #define MIPS_CPU_IRQ_BASE	0
-#define NR_IRQS			48
+#define NR_IRQS			51
 
 #define ATH79_CPU_IRQ(_x)	(MIPS_CPU_IRQ_BASE + (_x))
 
@@ -26,6 +26,10 @@
 #define ATH79_IP2_IRQ_COUNT	2
 #define ATH79_IP2_IRQ(_x)	(ATH79_IP2_IRQ_BASE + (_x))
 
+#define ATH79_IP3_IRQ_BASE	(ATH79_IP2_IRQ_BASE + ATH79_IP2_IRQ_COUNT)
+#define ATH79_IP3_IRQ_COUNT     3
+#define ATH79_IP3_IRQ(_x)       (ATH79_IP3_IRQ_BASE + (_x))
+
 #include_next <irq.h>
 
 #endif /* __ASM_MACH_ATH79_IRQ_H */
-- 
1.7.10

---

From: Gabor Juhos <[email-masked]>
Date: Fri, 15 Feb 2013 15:38:19 +0100

The existing code can handle the GPIO controller of
the QCA955x SoCs. Add a minimal glue code to make it
working.

Cc: Rodriguez, Luis <[email-masked]>
Cc: Giori, Kathy <[email-masked]>
Cc: QCA Linux Team <[email-masked]>
Signed-off-by: Gabor Juhos <[email-masked]>
---
 arch/mips/ath79/gpio.c                         |    4 +++-
 arch/mips/include/asm/mach-ath79/ar71xx_regs.h |    1 +
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/arch/mips/ath79/gpio.c b/arch/mips/ath79/gpio.c
index b7ed207..8d025b0 100644
--- a/arch/mips/ath79/gpio.c
+++ b/arch/mips/ath79/gpio.c
@@ -194,12 +194,14 @@ void __init ath79_gpio_init(void)
 		ath79_gpio_count = AR933X_GPIO_COUNT;
 	else if (soc_is_ar934x())
 		ath79_gpio_count = AR934X_GPIO_COUNT;
+	else if (soc_is_qca955x())
+		ath79_gpio_count = QCA955X_GPIO_COUNT;
 	else
 		BUG();
 
 	ath79_gpio_base = ioremap_nocache(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE);
 	ath79_gpio_chip.ngpio = ath79_gpio_count;
-	if (soc_is_ar934x()) {
+	if (soc_is_ar934x() || soc_is_qca955x()) {
 		ath79_gpio_chip.direction_input = ar934x_gpio_direction_input;
 		ath79_gpio_chip.direction_output = ar934x_gpio_direction_output;
 	}
diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
index 8782d8b..4868ed5 100644
--- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
+++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
@@ -510,6 +510,7 @@
 #define AR913X_GPIO_COUNT		22
 #define AR933X_GPIO_COUNT		30
 #define AR934X_GPIO_COUNT		23
+#define QCA955X_GPIO_COUNT		24
 
 /*
  * SRIF block
-- 
1.7.10

---

From: Gabor Juhos <[email-masked]>
Date: Fri, 15 Feb 2013 15:38:20 +0100

The ath79_device_reset_* are causing BUG when
those are used on the QCA955x SoCs. The patch
adds the required code to avoid that.

Cc: Rodriguez, Luis <[email-masked]>
Cc: Giori, Kathy <[email-masked]>
Cc: QCA Linux Team <[email-masked]>
Signed-off-by: Gabor Juhos <[email-masked]>
---
 arch/mips/ath79/common.c                       |    4 ++++
 arch/mips/include/asm/mach-ath79/ar71xx_regs.h |    1 +
 2 files changed, 5 insertions(+)

diff --git a/arch/mips/ath79/common.c b/arch/mips/ath79/common.c
index 5a4adfc..eb3966c 100644
--- a/arch/mips/ath79/common.c
+++ b/arch/mips/ath79/common.c
@@ -72,6 +72,8 @@ void ath79_device_reset_set(u32 mask)
 		reg = AR933X_RESET_REG_RESET_MODULE;
 	else if (soc_is_ar934x())
 		reg = AR934X_RESET_REG_RESET_MODULE;
+	else if (soc_is_qca955x())
+		reg = QCA955X_RESET_REG_RESET_MODULE;
 	else
 		BUG();
 
@@ -98,6 +100,8 @@ void ath79_device_reset_clear(u32 mask)
 		reg = AR933X_RESET_REG_RESET_MODULE;
 	else if (soc_is_ar934x())
 		reg = AR934X_RESET_REG_RESET_MODULE;
+	else if (soc_is_qca955x())
+		reg = QCA955X_RESET_REG_RESET_MODULE;
 	else
 		BUG();
 
index 4868ed5..bf50ddf 100644
@@ -299,6 +299,7 @@
 
+#define QCA955X_RESET_REG_RESET_MODULE		0x1c
 #define QCA955X_RESET_REG_BOOTSTRAP		0xb0
 #define QCA955X_RESET_REG_EXT_INT_STATUS	0xac
 
-- 
1.7.10

---

From: Gabor Juhos <[email-masked]>
Date: Fri, 15 Feb 2013 15:38:21 +0100

Similarly to the preceding SoCs, the QCA955X SoCs
also have a built-in NS16650 compatible UART.
Register the platform device for that to make
it usable.

Cc: Rodriguez, Luis <[email-masked]>
Cc: Giori, Kathy <[email-masked]>
Cc: QCA Linux Team <[email-masked]>
Signed-off-by: Gabor Juhos <[email-masked]>
---
 arch/mips/ath79/dev-common.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/arch/mips/ath79/dev-common.c b/arch/mips/ath79/dev-common.c
index 9be1465..a3a2741 100644
--- a/arch/mips/ath79/dev-common.c
+++ b/arch/mips/ath79/dev-common.c
@@ -90,7 +90,8 @@ void __init ath79_register_uart(void)
 	if (soc_is_ar71xx() ||
 	    soc_is_ar724x() ||
 	    soc_is_ar913x() ||
-	    soc_is_ar934x()) {
+	    soc_is_ar934x() ||
+	    soc_is_qca955x()) {
 		ath79_uart_data[0].uartclk = clk_get_rate(clk);
 		platform_device_register(&ath79_uart_device);
 	} else if (soc_is_ar933x()) {
-- 
1.7.10

---

From: Gabor Juhos <[email-masked]>
Date: Fri, 15 Feb 2013 15:38:22 +0100

The SoC has a built-in wireless MAC. Register a platform
device for that to make it usable with the ath9k driver.

Cc: Rodriguez, Luis <[email-masked]>
Cc: Giori, Kathy <[email-masked]>
Cc: QCA Linux Team <[email-masked]>
Signed-off-by: Gabor Juhos <[email-masked]>
---
 arch/mips/ath79/Kconfig                        |    2 +-
 arch/mips/ath79/dev-wmac.c                     |   20 ++++++++++++++++++++
 arch/mips/include/asm/mach-ath79/ar71xx_regs.h |    3 +++
 3 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/arch/mips/ath79/Kconfig b/arch/mips/ath79/Kconfig
index cffdc8e..77926e3 100644
--- a/arch/mips/ath79/Kconfig
+++ b/arch/mips/ath79/Kconfig
@@ -108,7 +108,7 @@ config ATH79_DEV_USB
 	def_bool n
 
 config ATH79_DEV_WMAC
-	depends on (SOC_AR913X || SOC_AR933X || SOC_AR934X)
+	depends on (SOC_AR913X || SOC_AR933X || SOC_AR934X || SOC_QCA955X)
 	def_bool n
 
 endif
diff --git a/arch/mips/ath79/dev-wmac.c b/arch/mips/ath79/dev-wmac.c
index 4f6c4e3..3e00c09 100644
--- a/arch/mips/ath79/dev-wmac.c
+++ b/arch/mips/ath79/dev-wmac.c
@@ -116,6 +116,24 @@ static void ar934x_wmac_setup(void)
 		ath79_wmac_data.is_clk_25mhz = true;
 }
 
+static void qca955x_wmac_setup(void)
+{
+	u32 t;
+
+	ath79_wmac_device.name = "qca955x_wmac";
+
+	ath79_wmac_resources[0].start = QCA955X_WMAC_BASE;
+	ath79_wmac_resources[0].end = QCA955X_WMAC_BASE + QCA955X_WMAC_SIZE - 1;
+	ath79_wmac_resources[1].start = ATH79_IP2_IRQ(1);
+	ath79_wmac_resources[1].start = ATH79_IP2_IRQ(1);
+
+	t = ath79_reset_rr(QCA955X_RESET_REG_BOOTSTRAP);
+	if (t & QCA955X_BOOTSTRAP_REF_CLK_40)
+		ath79_wmac_data.is_clk_25mhz = false;
+	else
+		ath79_wmac_data.is_clk_25mhz = true;
+}
+
 void __init ath79_register_wmac(u8 *cal_data)
 {
 	if (soc_is_ar913x())
@@ -124,6 +142,8 @@ void __init ath79_register_wmac(u8 *cal_data)
 		ar933x_wmac_setup();
 	else if (soc_is_ar934x())
 		ar934x_wmac_setup();
+	else if (soc_is_qca955x())
+		qca955x_wmac_setup();
 	else
 		BUG();
 
diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
index bf50ddf..4728212 100644
--- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
+++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
@@ -94,6 +94,9 @@
 #define AR934X_SRIF_BASE	(AR71XX_APB_BASE + 0x00116000)
 #define AR934X_SRIF_SIZE	0x1000
 
+#define QCA955X_WMAC_BASE	(AR71XX_APB_BASE + 0x00100000)
+#define QCA955X_WMAC_SIZE	0x20000
+
 /*
  * DDR_CTRL block
  */
-- 
1.7.10

---

From: Gabor Juhos <[email-masked]>
Date: Fri, 15 Feb 2013 15:38:23 +0100

Add SoC specific PCI IRQ map, and register platform
devices for the two built-in PCIe RCs.

Cc: Rodriguez, Luis <[email-masked]>
Cc: Giori, Kathy <[email-masked]>
Cc: QCA Linux Team <[email-masked]>
Signed-off-by: Gabor Juhos <[email-masked]>
---
 arch/mips/ath79/Kconfig                        |    2 ++
 arch/mips/ath79/pci.c                          |   36 ++++++++++++++++++++++++
 arch/mips/include/asm/mach-ath79/ar71xx_regs.h |   13 +++++++++
 3 files changed, 51 insertions(+)

diff --git a/arch/mips/ath79/Kconfig b/arch/mips/ath79/Kconfig
index 77926e3..76a001e 100644
--- a/arch/mips/ath79/Kconfig
+++ b/arch/mips/ath79/Kconfig
@@ -90,6 +90,8 @@ config SOC_AR934X
 
 config SOC_QCA955X
 	select USB_ARCH_HAS_EHCI
+	select HW_HAS_PCI
+	select PCI_AR724X if PCI
 	def_bool n
 
 config PCI_AR724X
diff --git a/arch/mips/ath79/pci.c b/arch/mips/ath79/pci.c
index 4350c25..730c0b0 100644
--- a/arch/mips/ath79/pci.c
+++ b/arch/mips/ath79/pci.c
@@ -49,6 +49,21 @@ static const struct ath79_pci_irq ar724x_pci_irq_map[] __initconst = {
 	}
 };
 
+static const struct ath79_pci_irq qca955x_pci_irq_map[] __initconst = {
+	{
+		.bus	= 0,
+		.slot	= 0,
+		.pin	= 1,
+		.irq	= ATH79_PCI_IRQ(0),
+	},
+	{
+		.bus	= 1,
+		.slot	= 0,
+		.pin	= 1,
+		.irq	= ATH79_PCI_IRQ(1),
+	},
+};
+
 int __init pcibios_map_irq(const struct pci_dev *dev, uint8_t slot, uint8_t pin)
 {
 	int irq = -1;
@@ -64,6 +79,9 @@ int __init pcibios_map_irq(const struct pci_dev *dev, uint8_t slot, uint8_t pin)
 			   soc_is_ar9344()) {
 			ath79_pci_irq_map = ar724x_pci_irq_map;
 			ath79_pci_nr_irqs = ARRAY_SIZE(ar724x_pci_irq_map);
+		} else if (soc_is_qca955x()) {
+			ath79_pci_irq_map = qca955x_pci_irq_map;
+			ath79_pci_nr_irqs = ARRAY_SIZE(qca955x_pci_irq_map);
 		} else {
 			pr_crit("pci %s: invalid irq map\n",
 				pci_name((struct pci_dev *) dev));
@@ -225,6 +243,24 @@ int __init ath79_register_pci(void)
 						 AR724X_PCI_MEM_SIZE,
 						 0,
 						 ATH79_IP2_IRQ(0));
+	} else if (soc_is_qca9558()) {
+		pdev = ath79_register_pci_ar724x(0,
+						 QCA955X_PCI_CFG_BASE0,
+						 QCA955X_PCI_CTRL_BASE0,
+						 QCA955X_PCI_CRP_BASE0,
+						 QCA955X_PCI_MEM_BASE0,
+						 QCA955X_PCI_MEM_SIZE,
+						 0,
+						 ATH79_IP2_IRQ(0));
+
+		pdev = ath79_register_pci_ar724x(1,
+						 QCA955X_PCI_CFG_BASE1,
+						 QCA955X_PCI_CTRL_BASE1,
+						 QCA955X_PCI_CRP_BASE1,
+						 QCA955X_PCI_MEM_BASE1,
+						 QCA955X_PCI_MEM_SIZE,
+						 1,
+						 ATH79_IP3_IRQ(2));
 	} else {
 		/* No PCI support */
 		return -ENODEV;
diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
index 4728212..b7fa9d1 100644
--- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
+++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
@@ -94,6 +94,19 @@
 #define AR934X_SRIF_BASE	(AR71XX_APB_BASE + 0x00116000)
 #define AR934X_SRIF_SIZE	0x1000
 
+#define QCA955X_PCI_MEM_BASE0	0x10000000
+#define QCA955X_PCI_MEM_BASE1	0x12000000
+#define QCA955X_PCI_MEM_SIZE	0x02000000
+#define QCA955X_PCI_CFG_BASE0	0x14000000
+#define QCA955X_PCI_CFG_BASE1	0x16000000
+#define QCA955X_PCI_CFG_SIZE	0x1000
+#define QCA955X_PCI_CRP_BASE0	(AR71XX_APB_BASE + 0x000c0000)
+#define QCA955X_PCI_CRP_BASE1	(AR71XX_APB_BASE + 0x00250000)
+#define QCA955X_PCI_CRP_SIZE	0x1000
+#define QCA955X_PCI_CTRL_BASE0	(AR71XX_APB_BASE + 0x000f0000)
+#define QCA955X_PCI_CTRL_BASE1	(AR71XX_APB_BASE + 0x00280000)
+#define QCA955X_PCI_CTRL_SIZE	0x100
+
 #define QCA955X_WMAC_BASE	(AR71XX_APB_BASE + 0x00100000)
 #define QCA955X_WMAC_SIZE	0x20000
 
-- 
1.7.10

---

From: Gabor Juhos <[email-masked]>
Date: Fri, 15 Feb 2013 15:38:24 +0100

Register platfom devices for the built-in USB
controllers of the SoCs.

Cc: Rodriguez, Luis <[email-masked]>
Cc: Giori, Kathy <[email-masked]>
Cc: QCA Linux Team <[email-masked]>
Signed-off-by: Gabor Juhos <[email-masked]>
---
 arch/mips/ath79/dev-usb.c                      |   15 +++++++++++++++
 arch/mips/include/asm/mach-ath79/ar71xx_regs.h |    3 +++
 2 files changed, 18 insertions(+)

diff --git a/arch/mips/ath79/dev-usb.c b/arch/mips/ath79/dev-usb.c
index 02124d0..8227265 100644
--- a/arch/mips/ath79/dev-usb.c
+++ b/arch/mips/ath79/dev-usb.c
@@ -208,6 +208,19 @@ static void __init ar934x_usb_setup(void)
 			   &ath79_ehci_pdata_v2, sizeof(ath79_ehci_pdata_v2));
 }
 
+static void __init qca955x_usb_setup(void)
+{
+	ath79_usb_register("ehci-platform", 0,
+			   QCA955X_EHCI0_BASE, QCA955X_EHCI_SIZE,
+			   ATH79_IP3_IRQ(0),
+			   &ath79_ehci_pdata_v2, sizeof(ath79_ehci_pdata_v2));
+
+	ath79_usb_register("ehci-platform", 1,
+			   QCA955X_EHCI1_BASE, QCA955X_EHCI_SIZE,
+			   ATH79_IP3_IRQ(1),
+			   &ath79_ehci_pdata_v2, sizeof(ath79_ehci_pdata_v2));
+}
+
 void __init ath79_register_usb(void)
 {
 	if (soc_is_ar71xx())
@@ -222,6 +235,8 @@ void __init ath79_register_usb(void)
 		ar933x_usb_setup();
 	else if (soc_is_ar934x())
 		ar934x_usb_setup();
+	else if (soc_is_qca955x())
+		qca955x_usb_setup();
 	else
 		BUG();
 }
diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
index b7fa9d1..4de1831 100644
--- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
+++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
@@ -109,6 +109,9 @@
 
 #define QCA955X_WMAC_BASE	(AR71XX_APB_BASE + 0x00100000)
 #define QCA955X_WMAC_SIZE	0x20000
+#define QCA955X_EHCI0_BASE	0x1b000000
+#define QCA955X_EHCI1_BASE	0x1b400000
+#define QCA955X_EHCI_SIZE	0x1000
 
 /*
  * DDR_CTRL block
-- 
1.7.10

---

From: Gabor Juhos <[email-masked]>
Date: Fri, 15 Feb 2013 15:38:25 +0100

Also enable the board in the default configuration.

Cc: Rodriguez, Luis <[email-masked]>
Cc: Giori, Kathy <[email-masked]>
Cc: QCA Linux Team <[email-masked]>
Signed-off-by: Gabor Juhos <[email-masked]>
---
 arch/mips/ath79/Kconfig           |   12 +++
 arch/mips/ath79/Makefile          |    1 +
 arch/mips/ath79/mach-ap136.c      |  156 +++++++++++++++++++++++++++++++++++++
 arch/mips/ath79/machtypes.h       |    1 +
 arch/mips/configs/ath79_defconfig |    1 +
 5 files changed, 171 insertions(+)
 create mode 100644 arch/mips/ath79/mach-ap136.c

diff --git a/arch/mips/ath79/Kconfig b/arch/mips/ath79/Kconfig
index 76a001e..3995e31 100644
--- a/arch/mips/ath79/Kconfig
+++ b/arch/mips/ath79/Kconfig
@@ -14,6 +14,18 @@ config ATH79_MACH_AP121
 	  Say 'Y' here if you want your kernel to support the
 	  Atheros AP121 reference board.
 
+config ATH79_MACH_AP136
+	bool "Atheros AP136 reference board"
+	select SOC_QCA955X
+	select ATH79_DEV_GPIO_BUTTONS
+	select ATH79_DEV_LEDS_GPIO
+	select ATH79_DEV_SPI
+	select ATH79_DEV_USB
+	select ATH79_DEV_WMAC
+	help
+	  Say 'Y' here if you want your kernel to support the
+	  Atheros AP136 reference board.
+
 config ATH79_MACH_AP81
 	bool "Atheros AP81 reference board"
 	select SOC_AR913X
diff --git a/arch/mips/ath79/Makefile b/arch/mips/ath79/Makefile
index 2b54d98..5c9ff69 100644
--- a/arch/mips/ath79/Makefile
+++ b/arch/mips/ath79/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_ATH79_DEV_WMAC)		+= dev-wmac.o
 # Machines
 #
 obj-$(CONFIG_ATH79_MACH_AP121)		+= mach-ap121.o
+obj-$(CONFIG_ATH79_MACH_AP136)		+= mach-ap136.o
 obj-$(CONFIG_ATH79_MACH_AP81)		+= mach-ap81.o
 obj-$(CONFIG_ATH79_MACH_DB120)		+= mach-db120.o
 obj-$(CONFIG_ATH79_MACH_PB44)		+= mach-pb44.o
diff --git a/arch/mips/ath79/mach-ap136.c b/arch/mips/ath79/mach-ap136.c
new file mode 100644
index 0000000..479dd4b
--- /dev/null
+++ b/arch/mips/ath79/mach-ap136.c
@@ -0,0 +1,156 @@
+/*
+ * Qualcomm Atheros AP136 reference board support
+ *
+ * Copyright (c) 2012 Qualcomm Atheros
+ * Copyright (c) 2012-2013 Gabor Juhos <[email-masked]>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/pci.h>
+#include <linux/ath9k_platform.h>
+
+#include "machtypes.h"
+#include "dev-gpio-buttons.h"
+#include "dev-leds-gpio.h"
+#include "dev-spi.h"
+#include "dev-usb.h"
+#include "dev-wmac.h"
+#include "pci.h"
+
+#define AP136_GPIO_LED_STATUS_RED	14
+#define AP136_GPIO_LED_STATUS_GREEN	19
+#define AP136_GPIO_LED_USB		4
+#define AP136_GPIO_LED_WLAN_2G		13
+#define AP136_GPIO_LED_WLAN_5G		12
+#define AP136_GPIO_LED_WPS_RED		15
+#define AP136_GPIO_LED_WPS_GREEN	20
+
+#define AP136_GPIO_BTN_WPS		16
+#define AP136_GPIO_BTN_RFKILL		21
+
+#define AP136_KEYS_POLL_INTERVAL	20	/* msecs */
+#define AP136_KEYS_DEBOUNCE_INTERVAL	(3 * AP136_KEYS_POLL_INTERVAL)
+
+#define AP136_WMAC_CALDATA_OFFSET 0x1000
+#define AP136_PCIE_CALDATA_OFFSET 0x5000
+
+static struct gpio_led ap136_leds_gpio[] __initdata = {
+	{
+		.name		= "qca:green:status",
+		.gpio		= AP136_GPIO_LED_STATUS_GREEN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "qca:red:status",
+		.gpio		= AP136_GPIO_LED_STATUS_RED,
+		.active_low	= 1,
+	},
+	{
+		.name		= "qca:green:wps",
+		.gpio		= AP136_GPIO_LED_WPS_GREEN,
+		.active_low	= 1,
+	},
+	{
+		.name		= "qca:red:wps",
+		.gpio		= AP136_GPIO_LED_WPS_RED,
+		.active_low	= 1,
+	},
+	{
+		.name		= "qca:red:wlan-2g",
+		.gpio		= AP136_GPIO_LED_WLAN_2G,
+		.active_low	= 1,
+	},
+	{
+		.name		= "qca:red:usb",
+		.gpio		= AP136_GPIO_LED_USB,
+		.active_low	= 1,
+	}
+};
+
+static struct gpio_keys_button ap136_gpio_keys[] __initdata = {
+	{
+		.desc		= "WPS button",
+		.type		= EV_KEY,
+		.code		= KEY_WPS_BUTTON,
+		.debounce_interval = AP136_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= AP136_GPIO_BTN_WPS,
+		.active_low	= 1,
+	},
+	{
+		.desc		= "RFKILL button",
+		.type		= EV_KEY,
+		.code		= KEY_RFKILL,
+		.debounce_interval = AP136_KEYS_DEBOUNCE_INTERVAL,
+		.gpio		= AP136_GPIO_BTN_RFKILL,
+		.active_low	= 1,
+	},
+};
+
+static struct spi_board_info ap136_spi_info[] = {
+	{
+		.bus_num	= 0,
+		.chip_select	= 0,
+		.max_speed_hz	= 25000000,
+		.modalias	= "mx25l6405d",
+	}
+};
+
+static struct ath79_spi_platform_data ap136_spi_data = {
+	.bus_num	= 0,
+	.num_chipselect	= 1,
+};
+
+#ifdef CONFIG_PCI
+static struct ath9k_platform_data ap136_ath9k_data;
+
+static int ap136_pci_plat_dev_init(struct pci_dev *dev)
+{
+	if (dev->bus->number == 1 && (PCI_SLOT(dev->devfn)) == 0)
+		dev->dev.platform_data = &ap136_ath9k_data;
+
+	return 0;
+}
+
+static void __init ap136_pci_init(u8 *eeprom)
+{
+	memcpy(ap136_ath9k_data.eeprom_data, eeprom,
+	       sizeof(ap136_ath9k_data.eeprom_data));
+
+	ath79_pci_set_plat_dev_init(ap136_pci_plat_dev_init);
+	ath79_register_pci();
+}
+#else
+static inline void ap136_pci_init(void) {}
+#endif /* CONFIG_PCI */
+
+static void __init ap136_setup(void)
+{
+	u8 *art = (u8 *) KSEG1ADDR(0x1fff0000);
+
+	ath79_register_leds_gpio(-1, ARRAY_SIZE(ap136_leds_gpio),
+				 ap136_leds_gpio);
+	ath79_register_gpio_keys_polled(-1, AP136_KEYS_POLL_INTERVAL,
+					ARRAY_SIZE(ap136_gpio_keys),
+					ap136_gpio_keys);
+	ath79_register_spi(&ap136_spi_data, ap136_spi_info,
+			   ARRAY_SIZE(ap136_spi_info));
+	ath79_register_usb();
+	ath79_register_wmac(art + AP136_WMAC_CALDATA_OFFSET);
+	ap136_pci_init(art + AP136_PCIE_CALDATA_OFFSET);
+}
+
+MIPS_MACHINE(ATH79_MACH_AP136_010, "AP136-010",
+	     "Atheros AP136-010 reference board",
+	     ap136_setup);
diff --git a/arch/mips/ath79/machtypes.h b/arch/mips/ath79/machtypes.h
index af92e5c..2625405 100644
--- a/arch/mips/ath79/machtypes.h
+++ b/arch/mips/ath79/machtypes.h
@@ -17,6 +17,7 @@
 enum ath79_mach_type {
 	ATH79_MACH_GENERIC = 0,
 	ATH79_MACH_AP121,		/* Atheros AP121 reference board */
+	ATH79_MACH_AP136_010,		/* Atheros AP136-010 reference board */
 	ATH79_MACH_AP81,		/* Atheros AP81 reference board */
 	ATH79_MACH_DB120,		/* Atheros DB120 reference board */
 	ATH79_MACH_PB44,		/* Atheros PB44 reference board */
diff --git a/arch/mips/configs/ath79_defconfig b/arch/mips/configs/ath79_defconfig
index ea87d43..e3a3836 100644
--- a/arch/mips/configs/ath79_defconfig
+++ b/arch/mips/configs/ath79_defconfig
@@ -1,5 +1,6 @@
 CONFIG_ATH79=y
 CONFIG_ATH79_MACH_AP121=y
+CONFIG_ATH79_MACH_AP136=y
 CONFIG_ATH79_MACH_AP81=y
 CONFIG_ATH79_MACH_DB120=y
 CONFIG_ATH79_MACH_PB44=y
-- 
1.7.10

---

From: John Crispin <[email-masked]>
Date: Fri, 15 Feb 2013 17:00:56 +0100

>   	pr_info("SoC: %s\n", ath79_sys_type);
Hi,

maybe a soc_is_qca() could be used here, otherwise you will need to 
patch this line again for the next SoC and so on ....

     John

---

From: John Crispin <[email-masked]>
Date: Fri, 15 Feb 2013 17:01:29 +0100

Hi,

the list is getting long. not a blocker but might be worth thinking of a 
different way to solve the different revisions of the irq core

> +	if (status&  QCA955X_EXT_INT_USB1) {
> +		/* TODO: flush DDR? */
> +	if (status&  QCA955X_EXT_INT_USB2) {
> +		/* TODO: flsuh DDR? */

flsuh typo

     John

---

From: John Crispin <[email-masked]>
Date: Fri, 15 Feb 2013 17:01:45 +0100

Hi,

second line should read .stop ?

     John

---

From: John Crispin <[email-masked]>
Date: Fri, 15 Feb 2013 17:02:01 +0100

Hi,

just because i am curious ... why the AP136_010 the rest of the code 
uses AP136 with no suffix

     John

---

From: Gabor Juhos <[email-masked]>
Date: Fri, 15 Feb 2013 17:42:20 +0100

2013.02.15. 17:00 keltezéssel, John Crispin írta:
> maybe a soc_is_qca() could be used here, otherwise you will need to patch this
> line again for the next SoC and so on ....

Hm, if I would add a soc_is_qca() macro, I would have to patch that macro for
the next SoCs instead of this line.

Maybe it would be better to add the AR/QCA prefix to each chip name, and use
'Qualcomm Atheros' unconditionally in the sprintf call?

-Gabor

---

From: Gabor Juhos <[email-masked]>
Date: Fri, 15 Feb 2013 18:13:58 +0100

> second line should read .stop ?

Yes. Although it does not cause problems because only the .start field is used
by ath9k, but it must be fixed of course. Will do it in the next version.

-Gabor

---

From: Gabor Juhos <[email-masked]>
Date: Fri, 15 Feb 2013 18:26:44 +0100

> different way to solve the different revisions of the irq core

This code runs only once, so it is not worth the effort IMHO.

If I would introduce a table to store the revision of the IRQ core, I would have
to put a value into that for each different SoC. That means 15 entries at the
moment.

Alternatively I can introduce a global variable to store the revision, and
intialize that variable from the SoC detection code. However I would have to set
that variable individually for each SoC and that means 15 lines of code.

>> +        generic_handle_irq(ATH79_IP3_IRQ(1));

Yep, will fix it.

Thanks,
Gabor

---

From: Gabor Juhos <[email-masked]>
Date: Fri, 15 Feb 2013 18:34:00 +0100

2013.02.15. 17:02 keltezéssel, John Crispin írta:
> just because i am curious ... why the AP136_010 the rest of the code uses AP136
> with no suffix

The rest of the code can be used as-is on the AP136-020 board as well. AFAIK,
the main difference between the two versions is that the ethernet switch is
connected differently to the SoC. Although we don't have ethernet support yet,
but once that is added the setup code for the two boards will be different.

Although it would be possible to remove the '010' part for now, but then it
should be added later again.

-Gabor