[OpenWrt-Devel] ar71xx: add support for qca956x soc
diff mbox

Message ID 1418397221-1777-1-git-send-email-hackpascal@gmail.com
State Accepted
Headers show

Commit Message

Weijie Gao Dec. 12, 2014, 3:13 p.m. UTC
This patch adds soc support for QCA9561 and TP9343.
TP9343 is a reduced version of QCA9561, which can be found in TP-LINK routers in China.
The qca956x_wmac has not yet been supported by ath9k.

tested on TL-WDR6500 and TL-WR882N v1 (Chinese version)

Signed-off-by: Weijie Gao <hackpascal@gmail.com>
---
 target/linux/ar71xx/config-3.14                    |   1 +
 ...34-MIPS-ath79-add-support-for-QCA956x-SoC.patch | 767 +++++++++++++++++++++
 2 files changed, 768 insertions(+)
 create mode 100644 target/linux/ar71xx/patches-3.14/734-MIPS-ath79-add-support-for-QCA956x-SoC.patch

Comments

Felix Fietkau Dec. 13, 2014, 3:16 p.m. UTC | #1
On 2014-12-12 16:13, Weijie Gao wrote:
> This patch adds soc support for QCA9561 and TP9343.
> TP9343 is a reduced version of QCA9561, which can be found in TP-LINK routers in China.
> The qca956x_wmac has not yet been supported by ath9k.
> 
> tested on TL-WDR6500 and TL-WR882N v1 (Chinese version)
> 
> Signed-off-by: Weijie Gao <hackpascal@gmail.com>
At a first glance, this patch looks good, though I'm a bit surprised
about the odd chip name TP9343, which I can't find many mentions of.
What codebase is this patch based on? Can I find a public kernel source
somewhere?

Thanks,

- Felix
Weijie Gao Dec. 13, 2014, 3:46 p.m. UTC | #2
在 2014/12/13 23:16, Felix Fietkau 写道:
> On 2014-12-12 16:13, Weijie Gao wrote:
>> This patch adds soc support for QCA9561 and TP9343.
>> TP9343 is a reduced version of QCA9561, which can be found in TP-LINK routers in China.
>> The qca956x_wmac has not yet been supported by ath9k.
>>
>> tested on TL-WDR6500 and TL-WR882N v1 (Chinese version)
>>
>> Signed-off-by: Weijie Gao <hackpascal@gmail.com>
> At a first glance, this patch looks good, though I'm a bit surprised
> about the odd chip name TP9343, which I can't find many mentions of.
> What codebase is this patch based on? Can I find a public kernel source
> somewhere?
>
> Thanks,
>
> - Felix

Hi,

I uses the QSDK open-source found in https://www.codeaurora.org/xwiki/bin/QSDK/WebHome.
Most of the QCA956X source codes are from this website.

I have disassembled the uboot of a TP9343's factory fimware, and found it is nearly
the same as the QCA956X except that it does not have USB and PCIe interfaces.
There is no reference code of TP9343, so I wrote its support myself.

Pictures of TP9343 SoC can be found here:
http://www.right.com.cn/forum/thread-143640-1-1.html


  Weijie

Patch
diff mbox

diff --git a/target/linux/ar71xx/config-3.14 b/target/linux/ar71xx/config-3.14
index 9ed184b..9f222c7 100644
--- a/target/linux/ar71xx/config-3.14
+++ b/target/linux/ar71xx/config-3.14
@@ -291,6 +291,7 @@  CONFIG_SOC_AR933X=y
 CONFIG_SOC_AR934X=y
 CONFIG_SOC_QCA953X=y
 CONFIG_SOC_QCA955X=y
+CONFIG_SOC_QCA956X=y
 CONFIG_SPI=y
 CONFIG_SPI_AP83=y
 CONFIG_SPI_ATH79=y
diff --git a/target/linux/ar71xx/patches-3.14/734-MIPS-ath79-add-support-for-QCA956x-SoC.patch b/target/linux/ar71xx/patches-3.14/734-MIPS-ath79-add-support-for-QCA956x-SoC.patch
new file mode 100644
index 0000000..6bbc43b
--- /dev/null
+++ b/target/linux/ar71xx/patches-3.14/734-MIPS-ath79-add-support-for-QCA956x-SoC.patch
@@ -0,0 +1,767 @@ 
+--- a/arch/mips/ath79/clock.c
++++ b/arch/mips/ath79/clock.c
+@@ -520,6 +520,100 @@
+ 	clk_add_alias("uart", NULL, "ref", NULL);
+ }
+ 
++static void __init qca956x_clocks_init(void)
++{
++	unsigned long ref_rate;
++	unsigned long cpu_rate;
++	unsigned long ddr_rate;
++	unsigned long ahb_rate;
++	u32 pll, out_div, ref_div, nint, hfrac, lfrac, clk_ctrl, postdiv;
++	u32 cpu_pll, ddr_pll;
++	u32 bootstrap;
++
++	bootstrap = ath79_reset_rr(QCA956X_RESET_REG_BOOTSTRAP);
++	if (bootstrap &	QCA956X_BOOTSTRAP_REF_CLK_40)
++		ref_rate = 40 * 1000 * 1000;
++	else
++		ref_rate = 25 * 1000 * 1000;
++
++	pll = ath79_pll_rr(QCA956X_PLL_CPU_CONFIG_REG);
++	out_div = (pll >> QCA956X_PLL_CPU_CONFIG_OUTDIV_SHIFT) &
++		  QCA956X_PLL_CPU_CONFIG_OUTDIV_MASK;
++	ref_div = (pll >> QCA956X_PLL_CPU_CONFIG_REFDIV_SHIFT) &
++		  QCA956X_PLL_CPU_CONFIG_REFDIV_MASK;
++
++	pll = ath79_pll_rr(QCA956X_PLL_CPU_CONFIG1_REG);
++	nint = (pll >> QCA956X_PLL_CPU_CONFIG1_NINT_SHIFT) &
++	       QCA956X_PLL_CPU_CONFIG1_NINT_MASK;
++	hfrac = (pll >> QCA956X_PLL_CPU_CONFIG1_NFRAC_H_SHIFT) &
++	       QCA956X_PLL_CPU_CONFIG1_NFRAC_H_MASK;
++	lfrac = (pll >> QCA956X_PLL_CPU_CONFIG1_NFRAC_L_SHIFT) &
++	       QCA956X_PLL_CPU_CONFIG1_NFRAC_L_MASK;
++
++	cpu_pll = nint * ref_rate / ref_div;
++	cpu_pll += (lfrac * ref_rate) / ((ref_div * 25) << 13);
++	cpu_pll += (hfrac >> 13) * ref_rate / ref_div;
++	cpu_pll /= (1 << out_div);
++
++	pll = ath79_pll_rr(QCA956X_PLL_DDR_CONFIG_REG);
++	out_div = (pll >> QCA956X_PLL_DDR_CONFIG_OUTDIV_SHIFT) &
++		  QCA956X_PLL_DDR_CONFIG_OUTDIV_MASK;
++	ref_div = (pll >> QCA956X_PLL_DDR_CONFIG_REFDIV_SHIFT) &
++		  QCA956X_PLL_DDR_CONFIG_REFDIV_MASK;
++	pll = ath79_pll_rr(QCA956X_PLL_DDR_CONFIG1_REG);
++	nint = (pll >> QCA956X_PLL_DDR_CONFIG1_NINT_SHIFT) &
++	       QCA956X_PLL_DDR_CONFIG1_NINT_MASK;
++	hfrac = (pll >> QCA956X_PLL_DDR_CONFIG1_NFRAC_H_SHIFT) &
++	       QCA956X_PLL_DDR_CONFIG1_NFRAC_H_MASK;
++	lfrac = (pll >> QCA956X_PLL_DDR_CONFIG1_NFRAC_L_SHIFT) &
++	       QCA956X_PLL_DDR_CONFIG1_NFRAC_L_MASK;
++
++	ddr_pll = nint * ref_rate / ref_div;
++	ddr_pll += (lfrac * ref_rate) / ((ref_div * 25) << 13);
++	ddr_pll += (hfrac >> 13) * ref_rate / ref_div;
++	ddr_pll /= (1 << out_div);
++
++	clk_ctrl = ath79_pll_rr(QCA956X_PLL_CLK_CTRL_REG);
++
++	postdiv = (clk_ctrl >> QCA956X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT) &
++		  QCA956X_PLL_CLK_CTRL_CPU_POST_DIV_MASK;
++
++	if (clk_ctrl & QCA956X_PLL_CLK_CTRL_CPU_PLL_BYPASS)
++		cpu_rate = ref_rate;
++	else if (clk_ctrl & QCA956X_PLL_CLK_CTRL_CPU_DDRCLK_FROM_CPUPLL)
++		cpu_rate = ddr_pll / (postdiv + 1);
++	else
++		cpu_rate = cpu_pll / (postdiv + 1);
++
++	postdiv = (clk_ctrl >> QCA956X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT) &
++		  QCA956X_PLL_CLK_CTRL_DDR_POST_DIV_MASK;
++
++	if (clk_ctrl & QCA956X_PLL_CLK_CTRL_DDR_PLL_BYPASS)
++		ddr_rate = ref_rate;
++	else if (clk_ctrl & QCA956X_PLL_CLK_CTRL_CPU_DDRCLK_FROM_DDRPLL)
++		ddr_rate = cpu_pll / (postdiv + 1);
++	else
++		ddr_rate = ddr_pll / (postdiv + 1);
++
++	postdiv = (clk_ctrl >> QCA956X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT) &
++		  QCA956X_PLL_CLK_CTRL_AHB_POST_DIV_MASK;
++
++	if (clk_ctrl & QCA956X_PLL_CLK_CTRL_AHB_PLL_BYPASS)
++		ahb_rate = ref_rate;
++	else if (clk_ctrl & QCA956X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL)
++		ahb_rate = ddr_pll / (postdiv + 1);
++	else
++		ahb_rate = cpu_pll / (postdiv + 1);
++
++	ath79_add_sys_clkdev("ref", ref_rate);
++	ath79_add_sys_clkdev("cpu", cpu_rate);
++	ath79_add_sys_clkdev("ddr", ddr_rate);
++	ath79_add_sys_clkdev("ahb", ahb_rate);
++
++	clk_add_alias("wdt", NULL, "ref", NULL);
++	clk_add_alias("uart", NULL, "ref", NULL);
++}
++
+ void __init ath79_clocks_init(void)
+ {
+ 	if (soc_is_ar71xx())
+@@ -536,6 +630,8 @@
+ 		qca953x_clocks_init();
+ 	else if (soc_is_qca955x())
+ 		qca955x_clocks_init();
++	else if (soc_is_qca956x())
++		qca956x_clocks_init();
+ 	else
+ 		BUG();
+ }
+--- a/arch/mips/ath79/common.c
++++ b/arch/mips/ath79/common.c
+@@ -77,6 +77,8 @@
+ 		reg = QCA953X_RESET_REG_RESET_MODULE;
+ 	else if (soc_is_qca955x())
+ 		reg = QCA955X_RESET_REG_RESET_MODULE;
++	else if (soc_is_qca956x())
++		reg = QCA956X_RESET_REG_RESET_MODULE;
+ 	else
+ 		panic("Reset register not defined for this SOC");
+ 
+@@ -107,6 +109,8 @@
+ 		reg = QCA953X_RESET_REG_RESET_MODULE;
+ 	else if (soc_is_qca955x())
+ 		reg = QCA955X_RESET_REG_RESET_MODULE;
++	else if (soc_is_qca956x())
++		reg = QCA956X_RESET_REG_RESET_MODULE;
+ 	else
+ 		panic("Reset register not defined for this SOC");
+ 
+--- a/arch/mips/ath79/dev-common.c
++++ b/arch/mips/ath79/dev-common.c
+@@ -94,7 +94,8 @@
+ 	    soc_is_ar913x() ||
+ 	    soc_is_ar934x() ||
+ 	    soc_is_qca953x() ||
+-	    soc_is_qca955x()) {
++	    soc_is_qca955x() ||
++	    soc_is_qca956x()) {
+ 		ath79_uart_data[0].uartclk = uart_clk_rate;
+ 		platform_device_register(&ath79_uart_device);
+ 	} else if (soc_is_ar933x()) {
+--- a/arch/mips/ath79/dev-eth.c
++++ b/arch/mips/ath79/dev-eth.c
+@@ -198,6 +198,8 @@
+ 	case ATH79_SOC_AR9330:
+ 	case ATH79_SOC_AR9331:
+ 	case ATH79_SOC_QCA9533:
++	case ATH79_SOC_QCA9561:
++	case ATH79_SOC_TP9343:
+ 		mdio_dev = &ath79_mdio1_device;
+ 		mdio_data = &ath79_mdio1_data;
+ 		break;
+@@ -256,6 +258,8 @@
+ 		break;
+ 
+ 	case ATH79_SOC_QCA9533:
++	case ATH79_SOC_QCA9561:
++	case ATH79_SOC_TP9343:
+ 		mdio_data->builtin_switch = 1;
+ 		break;
+ 
+@@ -571,6 +575,8 @@
+ 	case ATH79_SOC_QCA9533:
+ 	case ATH79_SOC_QCA9556:
+ 	case ATH79_SOC_QCA9558:
++	case ATH79_SOC_QCA9561:
++	case ATH79_SOC_TP9343:
+ 		pll_10 = AR934X_PLL_VAL_10;
+ 		pll_100 = AR934X_PLL_VAL_100;
+ 		pll_1000 = AR934X_PLL_VAL_1000;
+@@ -627,6 +633,8 @@
+ 		case ATH79_SOC_AR9330:
+ 		case ATH79_SOC_AR9331:
+ 		case ATH79_SOC_QCA9533:
++		case ATH79_SOC_QCA9561:
++		case ATH79_SOC_TP9343:
+ 			pdata->phy_if_mode = PHY_INTERFACE_MODE_MII;
+ 			break;
+ 
+@@ -688,6 +696,8 @@
+ 		case ATH79_SOC_AR9330:
+ 		case ATH79_SOC_AR9331:
+ 		case ATH79_SOC_QCA9533:
++		case ATH79_SOC_QCA9561:
++		case ATH79_SOC_TP9343:
+ 			pdata->phy_if_mode = PHY_INTERFACE_MODE_GMII;
+ 			break;
+ 
+@@ -992,6 +1002,8 @@
+ 		break;
+ 
+ 	case ATH79_SOC_QCA9533:
++	case ATH79_SOC_QCA9561:
++	case ATH79_SOC_TP9343:
+ 		if (id == 0) {
+ 			pdata->reset_bit = AR933X_RESET_GE0_MAC |
+ 					   AR933X_RESET_GE0_MDIO;
+@@ -1097,6 +1109,8 @@
+ 		case ATH79_SOC_AR9330:
+ 		case ATH79_SOC_AR9331:
+ 		case ATH79_SOC_QCA9533:
++		case ATH79_SOC_QCA9561:
++		case ATH79_SOC_TP9343:
+ 			pdata->mii_bus_dev = &ath79_mdio1_device.dev;
+ 			break;
+ 
+--- a/arch/mips/ath79/dev-usb.c
++++ b/arch/mips/ath79/dev-usb.c
+@@ -272,6 +272,19 @@
+ 			   &ath79_ehci_pdata_v2, sizeof(ath79_ehci_pdata_v2));
+ }
+ 
++static void __init qca956x_usb_setup(void)
++{
++	ath79_usb_register("ehci-platform", 0,
++			   QCA956X_EHCI0_BASE, QCA956X_EHCI_SIZE,
++			   ATH79_IP3_IRQ(0),
++			   &ath79_ehci_pdata_v2, sizeof(ath79_ehci_pdata_v2));
++
++	ath79_usb_register("ehci-platform", 1,
++			   QCA956X_EHCI1_BASE, QCA956X_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())
+@@ -288,6 +301,8 @@
+ 		ar934x_usb_setup();
+ 	else if (soc_is_qca955x())
+ 		qca955x_usb_setup();
++	else if (soc_is_qca9561())
++		qca956x_usb_setup();
+ 	else
+ 		BUG();
+ }
+--- a/arch/mips/ath79/dev-wmac.c
++++ b/arch/mips/ath79/dev-wmac.c
+@@ -189,6 +189,24 @@
+ 		ath79_wmac_data.is_clk_25mhz = true;
+ }
+ 
++static void qca956x_wmac_setup(void)
++{
++	u32 t;
++
++	ath79_wmac_device.name = "qca956x_wmac";
++
++	ath79_wmac_resources[0].start = QCA956X_WMAC_BASE;
++	ath79_wmac_resources[0].end = QCA956X_WMAC_BASE + QCA956X_WMAC_SIZE - 1;
++	ath79_wmac_resources[1].start = ATH79_IP2_IRQ(1);
++	ath79_wmac_resources[1].end = ATH79_IP2_IRQ(1);
++
++	t = ath79_reset_rr(QCA956X_RESET_REG_BOOTSTRAP);
++	if (t & QCA956X_BOOTSTRAP_REF_CLK_40)
++		ath79_wmac_data.is_clk_25mhz = false;
++	else
++		ath79_wmac_data.is_clk_25mhz = true;
++}
++
+ static bool __init
+ ar93xx_wmac_otp_read_word(void __iomem *base, int addr, u32 *data)
+ {
+@@ -392,6 +410,8 @@
+ 		qca953x_wmac_setup();
+ 	else if (soc_is_qca955x())
+ 		qca955x_wmac_setup();
++	else if (soc_is_qca956x())
++		qca956x_wmac_setup();
+ 	else
+ 		BUG();
+ 
+--- a/arch/mips/ath79/early_printk.c
++++ b/arch/mips/ath79/early_printk.c
+@@ -117,6 +117,8 @@
+ 	case REV_ID_MAJOR_QCA9533:
+ 	case REV_ID_MAJOR_QCA9556:
+ 	case REV_ID_MAJOR_QCA9558:
++	case REV_ID_MAJOR_TP9343:
++	case REV_ID_MAJOR_QCA9561:
+ 		_prom_putchar = prom_putchar_ar71xx;
+ 		break;
+ 
+--- a/arch/mips/ath79/gpio.c
++++ b/arch/mips/ath79/gpio.c
+@@ -148,7 +148,8 @@
+ 	    soc_is_ar913x() ||
+ 	    soc_is_ar933x())
+ 		reg = AR71XX_GPIO_REG_FUNC;
+-	else if (soc_is_ar934x())
++	else if (soc_is_ar934x() ||
++		 soc_is_qca956x())
+ 		reg = AR934X_GPIO_REG_FUNC;
+ 	else
+ 		BUG();
+@@ -228,12 +229,15 @@
+ 		ath79_gpio_count = QCA953X_GPIO_COUNT;
+ 	else if (soc_is_qca955x())
+ 		ath79_gpio_count = QCA955X_GPIO_COUNT;
++	else if (soc_is_qca956x())
++		ath79_gpio_count = QCA956X_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() || soc_is_qca953x() || soc_is_qca955x()) {
++	if (soc_is_ar934x() || soc_is_qca953x() || soc_is_qca955x() ||
++	    soc_is_qca956x()) {
+ 		ath79_gpio_chip.direction_input = ar934x_gpio_direction_input;
+ 		ath79_gpio_chip.direction_output = ar934x_gpio_direction_output;
+ 	}
+--- a/arch/mips/ath79/irq.c
++++ b/arch/mips/ath79/irq.c
+@@ -107,7 +107,8 @@
+ 		 soc_is_ar933x() ||
+ 		 soc_is_ar934x() ||
+ 		 soc_is_qca953x() ||
+-		 soc_is_qca955x())
++		 soc_is_qca955x() ||
++		 soc_is_qca956x())
+ 		ath79_misc_irq_chip.irq_ack = ar724x_misc_irq_ack;
+ 	else
+ 		BUG();
+@@ -236,6 +237,99 @@
+ 	irq_set_chained_handler(ATH79_CPU_IRQ(3), qca955x_ip3_irq_dispatch);
+ }
+ 
++static void qca956x_ip2_irq_dispatch(unsigned int irq, struct irq_desc *desc)
++{
++	u32 status;
++
++	disable_irq_nosync(irq);
++
++	status = ath79_reset_rr(QCA956X_RESET_REG_EXT_INT_STATUS);
++	status &= QCA956X_EXT_INT_PCIE_RC1_ALL | QCA956X_EXT_INT_WMAC_ALL;
++
++	if (status == 0) {
++		spurious_interrupt();
++		goto enable;
++	}
++
++	if (status & QCA956X_EXT_INT_PCIE_RC1_ALL) {
++		/* TODO: flush DDR? */
++		generic_handle_irq(ATH79_IP2_IRQ(0));
++	}
++
++	if (status & QCA956X_EXT_INT_WMAC_ALL) {
++		/* TODO: flsuh DDR? */
++		generic_handle_irq(ATH79_IP2_IRQ(1));
++	}
++
++enable:
++	enable_irq(irq);
++}
++
++static void qca956x_ip3_irq_dispatch(unsigned int irq, struct irq_desc *desc)
++{
++	u32 status;
++
++	disable_irq_nosync(irq);
++
++	status = ath79_reset_rr(QCA956X_RESET_REG_EXT_INT_STATUS);
++	status &= QCA956X_EXT_INT_PCIE_RC2_ALL |
++		  QCA956X_EXT_INT_USB1 | QCA956X_EXT_INT_USB2;
++
++	if (status == 0) {
++		spurious_interrupt();
++		goto enable;
++	}
++
++	if (status & QCA956X_EXT_INT_USB1) {
++		/* TODO: flush DDR? */
++		generic_handle_irq(ATH79_IP3_IRQ(0));
++	}
++
++	if (status & QCA956X_EXT_INT_USB2) {
++		/* TODO: flush DDR? */
++		generic_handle_irq(ATH79_IP3_IRQ(1));
++	}
++
++	if (status & QCA956X_EXT_INT_PCIE_RC2_ALL) {
++		/* TODO: flush DDR? */
++		generic_handle_irq(ATH79_IP3_IRQ(2));
++	}
++
++enable:
++	enable_irq(irq);
++}
++
++static void qca956x_enable_timer_cb(void) {
++	u32 misc;
++
++	misc = ath79_reset_rr(AR71XX_RESET_REG_MISC_INT_ENABLE);
++	misc |= MISC_INT_MIPS_SI_TIMERINT_MASK;
++	ath79_reset_wr(AR71XX_RESET_REG_MISC_INT_ENABLE, misc);
++}
++
++static void qca956x_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), qca956x_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), qca956x_ip3_irq_dispatch);
++
++	/* QCA956x timer init workaround has to be applied right before setting
++	 * up the clock. Else, there will be no jiffies */
++	late_time_init = &qca956x_enable_timer_cb;
++}
++
+ asmlinkage void plat_irq_dispatch(void)
+ {
+ 	unsigned long pending;
+@@ -359,6 +453,9 @@
+ 	} else if (soc_is_qca955x()) {
+ 		ath79_ip2_handler = ath79_default_ip2_handler;
+ 		ath79_ip3_handler = ath79_default_ip3_handler;
++	} else if (soc_is_qca956x()) {
++		ath79_ip2_handler = ath79_default_ip2_handler;
++		ath79_ip3_handler = ath79_default_ip3_handler;
+ 	} else {
+ 		BUG();
+ 	}
+@@ -371,4 +468,6 @@
+ 		ar934x_ip2_irq_init();
+ 	else if (soc_is_qca955x())
+ 		qca955x_irq_init();
++	else if (soc_is_qca956x())
++		qca956x_irq_init();
+ }
+--- a/arch/mips/ath79/Kconfig
++++ b/arch/mips/ath79/Kconfig
+@@ -1155,6 +1155,12 @@
+ 	select PCI_AR724X if PCI
+ 	def_bool n
+ 
++config SOC_QCA956X
++	select USB_ARCH_HAS_EHCI
++	select HW_HAS_PCI
++	select PCI_AR724X if PCI
++	def_bool n
++
+ config ATH79_DEV_M25P80
+ 	select ATH79_DEV_SPI
+ 	def_bool n
+@@ -1192,7 +1198,7 @@
+ 	def_bool n
+ 
+ config ATH79_DEV_WMAC
+-	depends on (SOC_AR913X || SOC_AR933X || SOC_AR934X || SOC_QCA953X || SOC_QCA955X)
++	depends on (SOC_AR913X || SOC_AR933X || SOC_AR934X || SOC_QCA953X || SOC_QCA955X || SOC_QCA956X)
+ 	def_bool n
+ 
+ config ATH79_NVRAM
+--- a/arch/mips/ath79/pci.c
++++ b/arch/mips/ath79/pci.c
+@@ -68,6 +68,21 @@
+ 	},
+ };
+ 
++static const struct ath79_pci_irq qca956x_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;
+@@ -86,6 +101,9 @@
+ 		} else if (soc_is_qca955x()) {
+ 			ath79_pci_irq_map = qca955x_pci_irq_map;
+ 			ath79_pci_nr_irqs = ARRAY_SIZE(qca955x_pci_irq_map);
++		} else if (soc_is_qca9561()) {
++			ath79_pci_irq_map = qca956x_pci_irq_map;
++			ath79_pci_nr_irqs = ARRAY_SIZE(qca956x_pci_irq_map);
+ 		} else {
+ 			pr_crit("pci %s: invalid irq map\n",
+ 				pci_name((struct pci_dev *) dev));
+@@ -303,6 +321,15 @@
+ 						 QCA955X_PCI_MEM_SIZE,
+ 						 1,
+ 						 ATH79_IP3_IRQ(2));
++	} else if (soc_is_qca9561()) {
++		pdev = ath79_register_pci_ar724x(0,
++						 QCA956X_PCI_CFG_BASE1,
++						 QCA956X_PCI_CTRL_BASE1,
++						 QCA956X_PCI_CRP_BASE1,
++						 QCA956X_PCI_MEM_BASE1,
++						 QCA956X_PCI_MEM_SIZE,
++						 1,
++						 ATH79_IP3_IRQ(2));
+ 	} else {
+ 		/* No PCI support */
+ 		return -ENODEV;
+--- a/arch/mips/ath79/setup.c
++++ b/arch/mips/ath79/setup.c
+@@ -170,15 +170,30 @@
+ 		rev = id & QCA955X_REV_ID_REVISION_MASK;
+ 		break;
+ 
++	case REV_ID_MAJOR_TP9343:
++		ath79_soc = ATH79_SOC_TP9343;
++		chip = "9343";
++		rev = id & QCA956X_REV_ID_REVISION_MASK;
++		break;
++
++	case REV_ID_MAJOR_QCA9561:
++		ath79_soc = ATH79_SOC_QCA9561;
++		chip = "9561";
++		rev = id & QCA956X_REV_ID_REVISION_MASK;
++		break;
++
+ 	default:
+ 		panic("ath79: unknown SoC, id:0x%08x", id);
+ 	}
+ 
+ 	ath79_soc_rev = rev;
+ 
+-	if (soc_is_qca953x() || soc_is_qca955x())
++	if (soc_is_qca953x() || soc_is_qca955x() || soc_is_qca9561())
+ 		sprintf(ath79_sys_type, "Qualcomm Atheros QCA%s rev %u",
+ 			chip, rev);
++	else if (soc_is_tp9343())
++		sprintf(ath79_sys_type, "Qualcomm Atheros TP%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);
+--- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
++++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
+@@ -131,6 +131,23 @@
+ #define QCA955X_NFC_BASE	0x1b800200
+ #define QCA955X_NFC_SIZE	0xb8
+ 
++#define QCA956X_PCI_MEM_BASE1	0x12000000
++#define QCA956X_PCI_MEM_SIZE	0x02000000
++#define QCA956X_PCI_CFG_BASE1	0x16000000
++#define QCA956X_PCI_CFG_SIZE	0x1000
++#define QCA956X_PCI_CRP_BASE1	(AR71XX_APB_BASE + 0x00250000)
++#define QCA956X_PCI_CRP_SIZE	0x1000
++#define QCA956X_PCI_CTRL_BASE1	(AR71XX_APB_BASE + 0x00280000)
++#define QCA956X_PCI_CTRL_SIZE	0x100
++
++#define QCA956X_WMAC_BASE	(AR71XX_APB_BASE + 0x00100000)
++#define QCA956X_WMAC_SIZE	0x20000
++#define QCA956X_EHCI0_BASE	0x1b000000
++#define QCA956X_EHCI1_BASE	0x1b400000
++#define QCA956X_EHCI_SIZE	0x200
++#define QCA956X_GMAC_BASE	(AR71XX_APB_BASE + 0x00070000)
++#define QCA956X_GMAC_SIZE	0x64
++
+ #define AR9300_OTP_BASE		0x14000
+ #define AR9300_OTP_STATUS	0x15f18
+ #define AR9300_OTP_STATUS_TYPE		0x7
+@@ -356,6 +373,49 @@
+ #define QCA955X_PLL_CLK_CTRL_DDRCLK_FROM_DDRPLL		BIT(21)
+ #define QCA955X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL		BIT(24)
+ 
++#define QCA956X_PLL_CPU_CONFIG_REG			0x00
++#define QCA956X_PLL_CPU_CONFIG1_REG			0x04
++#define QCA956X_PLL_DDR_CONFIG_REG			0x08
++#define QCA956X_PLL_DDR_CONFIG1_REG			0x0c
++#define QCA956X_PLL_CLK_CTRL_REG			0x10
++
++#define QCA956X_PLL_CPU_CONFIG_REFDIV_SHIFT		12
++#define QCA956X_PLL_CPU_CONFIG_REFDIV_MASK		0x1f
++#define QCA956X_PLL_CPU_CONFIG_OUTDIV_SHIFT		19
++#define QCA956X_PLL_CPU_CONFIG_OUTDIV_MASK		0x7
++
++#define QCA956X_PLL_CPU_CONFIG1_NFRAC_L_SHIFT		0
++#define QCA956X_PLL_CPU_CONFIG1_NFRAC_L_MASK		0x1f
++#define QCA956X_PLL_CPU_CONFIG1_NFRAC_H_SHIFT		5
++#define QCA956X_PLL_CPU_CONFIG1_NFRAC_H_MASK		0x3fff
++#define QCA956X_PLL_CPU_CONFIG1_NINT_SHIFT		18
++#define QCA956X_PLL_CPU_CONFIG1_NINT_MASK		0x1ff
++
++#define QCA956X_PLL_DDR_CONFIG_REFDIV_SHIFT		16
++#define QCA956X_PLL_DDR_CONFIG_REFDIV_MASK		0x1f
++#define QCA956X_PLL_DDR_CONFIG_OUTDIV_SHIFT		23
++#define QCA956X_PLL_DDR_CONFIG_OUTDIV_MASK		0x7
++
++#define QCA956X_PLL_DDR_CONFIG1_NFRAC_L_SHIFT		0
++#define QCA956X_PLL_DDR_CONFIG1_NFRAC_L_MASK		0x1f
++#define QCA956X_PLL_DDR_CONFIG1_NFRAC_H_SHIFT		5
++#define QCA956X_PLL_DDR_CONFIG1_NFRAC_H_MASK		0x3fff
++#define QCA956X_PLL_DDR_CONFIG1_NINT_SHIFT		18
++#define QCA956X_PLL_DDR_CONFIG1_NINT_MASK		0x1ff
++
++#define QCA956X_PLL_CLK_CTRL_CPU_PLL_BYPASS		BIT(2)
++#define QCA956X_PLL_CLK_CTRL_DDR_PLL_BYPASS		BIT(3)
++#define QCA956X_PLL_CLK_CTRL_AHB_PLL_BYPASS		BIT(4)
++#define QCA956X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT		5
++#define QCA956X_PLL_CLK_CTRL_CPU_POST_DIV_MASK		0x1f
++#define QCA956X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT		10
++#define QCA956X_PLL_CLK_CTRL_DDR_POST_DIV_MASK		0x1f
++#define QCA956X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT		15
++#define QCA956X_PLL_CLK_CTRL_AHB_POST_DIV_MASK		0x1f
++#define QCA956X_PLL_CLK_CTRL_CPU_DDRCLK_FROM_DDRPLL	BIT(20)
++#define QCA956X_PLL_CLK_CTRL_CPU_DDRCLK_FROM_CPUPLL	BIT(21)
++#define QCA956X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL		BIT(24)
++
+ /*
+  * USB_CONFIG block
+  */
+@@ -403,6 +463,11 @@
+ #define QCA955X_RESET_REG_BOOTSTRAP		0xb0
+ #define QCA955X_RESET_REG_EXT_INT_STATUS	0xac
+ 
++#define QCA956X_RESET_REG_RESET_MODULE		0x1c
++#define QCA956X_RESET_REG_BOOTSTRAP		0xb0
++#define QCA956X_RESET_REG_EXT_INT_STATUS	0xac
++
++#define MISC_INT_MIPS_SI_TIMERINT_MASK	BIT(28)
+ #define MISC_INT_ETHSW			BIT(12)
+ #define MISC_INT_TIMER4			BIT(10)
+ #define MISC_INT_TIMER3			BIT(9)
+@@ -551,6 +616,8 @@
+ 
+ #define QCA955X_BOOTSTRAP_REF_CLK_40	BIT(4)
+ 
++#define QCA956X_BOOTSTRAP_REF_CLK_40	BIT(2)
++
+ #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)
+@@ -600,6 +667,37 @@
+ 	 QCA955X_EXT_INT_PCIE_RC2_INT1 | QCA955X_EXT_INT_PCIE_RC2_INT2 | \
+ 	 QCA955X_EXT_INT_PCIE_RC2_INT3)
+ 
++#define QCA956X_EXT_INT_WMAC_MISC		BIT(0)
++#define QCA956X_EXT_INT_WMAC_TX			BIT(1)
++#define QCA956X_EXT_INT_WMAC_RXLP		BIT(2)
++#define QCA956X_EXT_INT_WMAC_RXHP		BIT(3)
++#define QCA956X_EXT_INT_PCIE_RC1		BIT(4)
++#define QCA956X_EXT_INT_PCIE_RC1_INT0		BIT(5)
++#define QCA956X_EXT_INT_PCIE_RC1_INT1		BIT(6)
++#define QCA956X_EXT_INT_PCIE_RC1_INT2		BIT(7)
++#define QCA956X_EXT_INT_PCIE_RC1_INT3		BIT(8)
++#define QCA956X_EXT_INT_PCIE_RC2		BIT(12)
++#define QCA956X_EXT_INT_PCIE_RC2_INT0		BIT(13)
++#define QCA956X_EXT_INT_PCIE_RC2_INT1		BIT(14)
++#define QCA956X_EXT_INT_PCIE_RC2_INT2		BIT(15)
++#define QCA956X_EXT_INT_PCIE_RC2_INT3		BIT(16)
++#define QCA956X_EXT_INT_USB1			BIT(24)
++#define QCA956X_EXT_INT_USB2			BIT(28)
++
++#define QCA956X_EXT_INT_WMAC_ALL \
++	(QCA956X_EXT_INT_WMAC_MISC | QCA956X_EXT_INT_WMAC_TX | \
++	 QCA956X_EXT_INT_WMAC_RXLP | QCA956X_EXT_INT_WMAC_RXHP)
++
++#define QCA956X_EXT_INT_PCIE_RC1_ALL \
++	(QCA956X_EXT_INT_PCIE_RC1 | QCA956X_EXT_INT_PCIE_RC1_INT0 | \
++	 QCA956X_EXT_INT_PCIE_RC1_INT1 | QCA956X_EXT_INT_PCIE_RC1_INT2 | \
++	 QCA956X_EXT_INT_PCIE_RC1_INT3)
++
++#define QCA956X_EXT_INT_PCIE_RC2_ALL \
++	(QCA956X_EXT_INT_PCIE_RC2 | QCA956X_EXT_INT_PCIE_RC2_INT0 | \
++	 QCA956X_EXT_INT_PCIE_RC2_INT1 | QCA956X_EXT_INT_PCIE_RC2_INT2 | \
++	 QCA956X_EXT_INT_PCIE_RC2_INT3)
++
+ #define REV_ID_MAJOR_MASK		0xfff0
+ #define REV_ID_MAJOR_AR71XX		0x00a0
+ #define REV_ID_MAJOR_AR913X		0x00b0
+@@ -614,6 +712,8 @@
+ #define REV_ID_MAJOR_QCA9533		0x0140
+ #define REV_ID_MAJOR_QCA9556		0x0130
+ #define REV_ID_MAJOR_QCA9558		0x1130
++#define REV_ID_MAJOR_TP9343		0x0150
++#define REV_ID_MAJOR_QCA9561		0x1150
+ 
+ #define AR71XX_REV_ID_MINOR_MASK	0x3
+ #define AR71XX_REV_ID_MINOR_AR7130	0x0
+@@ -638,6 +738,8 @@
+ 
+ #define QCA955X_REV_ID_REVISION_MASK	0xf
+ 
++#define QCA956X_REV_ID_REVISION_MASK	0xf
++
+ /*
+  * SPI block
+  */
+@@ -683,6 +785,19 @@
+ #define AR934X_GPIO_REG_OUT_FUNC5	0x40
+ #define AR934X_GPIO_REG_FUNC		0x6c
+ 
++#define QCA956X_GPIO_REG_OUT_FUNC0	0x2c
++#define QCA956X_GPIO_REG_OUT_FUNC1	0x30
++#define QCA956X_GPIO_REG_OUT_FUNC2	0x34
++#define QCA956X_GPIO_REG_OUT_FUNC3	0x38
++#define QCA956X_GPIO_REG_OUT_FUNC4	0x3c
++#define QCA956X_GPIO_REG_OUT_FUNC5	0x40
++#define QCA956X_GPIO_REG_IN_ENABLE0	0x44
++#define QCA956X_GPIO_REG_IN_ENABLE3	0x50
++#define QCA956X_GPIO_REG_FUNC		0x6c
++
++#define QCA956X_GPIO_OUT_MUX_GE0_MDO	32
++#define QCA956X_GPIO_OUT_MUX_GE0_MDC	33
++
+ #define AR71XX_GPIO_COUNT		16
+ #define AR7240_GPIO_COUNT		18
+ #define AR7241_GPIO_COUNT		20
+@@ -691,6 +806,7 @@
+ #define AR934X_GPIO_COUNT		23
+ #define QCA953X_GPIO_COUNT		24
+ #define QCA955X_GPIO_COUNT		24
++#define QCA956X_GPIO_COUNT		23
+ 
+ /*
+  * SRIF block
+--- a/arch/mips/include/asm/mach-ath79/ath79.h
++++ b/arch/mips/include/asm/mach-ath79/ath79.h
+@@ -35,6 +35,8 @@
+ 	ATH79_SOC_QCA9533,
+ 	ATH79_SOC_QCA9556,
+ 	ATH79_SOC_QCA9558,
++	ATH79_SOC_TP9343,
++	ATH79_SOC_QCA9561,
+ };
+ 
+ extern enum ath79_soc_type ath79_soc;
+@@ -126,6 +128,21 @@
+ 	return soc_is_qca9556() || soc_is_qca9558();
+ }
+ 
++static inline int soc_is_tp9343(void)
++{
++	return ath79_soc == ATH79_SOC_TP9343;
++}
++ 
++static inline int soc_is_qca9561(void)
++{
++	return ath79_soc == ATH79_SOC_QCA9561;
++}
++
++static inline int soc_is_qca956x(void)
++{
++	return soc_is_tp9343() || soc_is_qca9561();
++}
++
+ extern void __iomem *ath79_ddr_base;
+ extern void __iomem *ath79_gpio_base;
+ extern void __iomem *ath79_pll_base;