Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit af2d1b52 authored by Matthias Schiffer's avatar Matthias Schiffer Committed by Paul Burton
Browse files

MIPS: ath79: add support for QCA953x QCA956x TP9343



This patch adds support for 2 new types of QCA silicon. TP9343 is
essentially the same as the QCA956X but is licensed by TPLink.

Signed-off-by: default avatarWeijie Gao <hackpascal@gmail.com>
Signed-off-by: default avatarMatthias Schiffer <mschiffer@universe-factory.net>
Signed-off-by: default avatarJohn Crispin <john@phrozen.org>
Signed-off-by: default avatarPaul Burton <paul.burton@mips.com>
Patchwork: https://patchwork.linux-mips.org/patch/19911/
Cc: James Hogan <jhogan@kernel.org>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: linux-mips@linux-mips.org
parent a95f4b1c
Loading
Loading
Loading
Loading
+193 −0
Original line number Original line Diff line number Diff line
@@ -355,6 +355,91 @@ static void __init ar934x_clocks_init(void)
	iounmap(dpll_base);
	iounmap(dpll_base);
}
}


static void __init qca953x_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, frac, clk_ctrl, postdiv;
	u32 cpu_pll, ddr_pll;
	u32 bootstrap;

	bootstrap = ath79_reset_rr(QCA953X_RESET_REG_BOOTSTRAP);
	if (bootstrap &	QCA953X_BOOTSTRAP_REF_CLK_40)
		ref_rate = 40 * 1000 * 1000;
	else
		ref_rate = 25 * 1000 * 1000;

	pll = ath79_pll_rr(QCA953X_PLL_CPU_CONFIG_REG);
	out_div = (pll >> QCA953X_PLL_CPU_CONFIG_OUTDIV_SHIFT) &
		  QCA953X_PLL_CPU_CONFIG_OUTDIV_MASK;
	ref_div = (pll >> QCA953X_PLL_CPU_CONFIG_REFDIV_SHIFT) &
		  QCA953X_PLL_CPU_CONFIG_REFDIV_MASK;
	nint = (pll >> QCA953X_PLL_CPU_CONFIG_NINT_SHIFT) &
	       QCA953X_PLL_CPU_CONFIG_NINT_MASK;
	frac = (pll >> QCA953X_PLL_CPU_CONFIG_NFRAC_SHIFT) &
	       QCA953X_PLL_CPU_CONFIG_NFRAC_MASK;

	cpu_pll = nint * ref_rate / ref_div;
	cpu_pll += frac * (ref_rate >> 6) / ref_div;
	cpu_pll /= (1 << out_div);

	pll = ath79_pll_rr(QCA953X_PLL_DDR_CONFIG_REG);
	out_div = (pll >> QCA953X_PLL_DDR_CONFIG_OUTDIV_SHIFT) &
		  QCA953X_PLL_DDR_CONFIG_OUTDIV_MASK;
	ref_div = (pll >> QCA953X_PLL_DDR_CONFIG_REFDIV_SHIFT) &
		  QCA953X_PLL_DDR_CONFIG_REFDIV_MASK;
	nint = (pll >> QCA953X_PLL_DDR_CONFIG_NINT_SHIFT) &
	       QCA953X_PLL_DDR_CONFIG_NINT_MASK;
	frac = (pll >> QCA953X_PLL_DDR_CONFIG_NFRAC_SHIFT) &
	       QCA953X_PLL_DDR_CONFIG_NFRAC_MASK;

	ddr_pll = nint * ref_rate / ref_div;
	ddr_pll += frac * (ref_rate >> 6) / (ref_div << 4);
	ddr_pll /= (1 << out_div);

	clk_ctrl = ath79_pll_rr(QCA953X_PLL_CLK_CTRL_REG);

	postdiv = (clk_ctrl >> QCA953X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT) &
		  QCA953X_PLL_CLK_CTRL_CPU_POST_DIV_MASK;

	if (clk_ctrl & QCA953X_PLL_CLK_CTRL_CPU_PLL_BYPASS)
		cpu_rate = ref_rate;
	else if (clk_ctrl & QCA953X_PLL_CLK_CTRL_CPUCLK_FROM_CPUPLL)
		cpu_rate = cpu_pll / (postdiv + 1);
	else
		cpu_rate = ddr_pll / (postdiv + 1);

	postdiv = (clk_ctrl >> QCA953X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT) &
		  QCA953X_PLL_CLK_CTRL_DDR_POST_DIV_MASK;

	if (clk_ctrl & QCA953X_PLL_CLK_CTRL_DDR_PLL_BYPASS)
		ddr_rate = ref_rate;
	else if (clk_ctrl & QCA953X_PLL_CLK_CTRL_DDRCLK_FROM_DDRPLL)
		ddr_rate = ddr_pll / (postdiv + 1);
	else
		ddr_rate = cpu_pll / (postdiv + 1);

	postdiv = (clk_ctrl >> QCA953X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT) &
		  QCA953X_PLL_CLK_CTRL_AHB_POST_DIV_MASK;

	if (clk_ctrl & QCA953X_PLL_CLK_CTRL_AHB_PLL_BYPASS)
		ahb_rate = ref_rate;
	else if (clk_ctrl & QCA953X_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);
}

static void __init qca955x_clocks_init(void)
static void __init qca955x_clocks_init(void)
{
{
	unsigned long ref_rate;
	unsigned long ref_rate;
@@ -440,6 +525,110 @@ static void __init qca955x_clocks_init(void)
	clk_add_alias("uart", NULL, "ref", NULL);
	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;

	/*
	 * QCA956x timer init workaround has to be applied right before setting
	 * up the clock. Else, there will be no jiffies
	 */
	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);

	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)
void __init ath79_clocks_init(void)
{
{
	if (soc_is_ar71xx())
	if (soc_is_ar71xx())
@@ -450,8 +639,12 @@ void __init ath79_clocks_init(void)
		ar933x_clocks_init();
		ar933x_clocks_init();
	else if (soc_is_ar934x())
	else if (soc_is_ar934x())
		ar934x_clocks_init();
		ar934x_clocks_init();
	else if (soc_is_qca953x())
		qca953x_clocks_init();
	else if (soc_is_qca955x())
	else if (soc_is_qca955x())
		qca955x_clocks_init();
		qca955x_clocks_init();
	else if (soc_is_qca956x() || soc_is_tp9343())
		qca956x_clocks_init();
	else
	else
		BUG();
		BUG();
}
}
+8 −0
Original line number Original line Diff line number Diff line
@@ -103,8 +103,12 @@ void ath79_device_reset_set(u32 mask)
		reg = AR933X_RESET_REG_RESET_MODULE;
		reg = AR933X_RESET_REG_RESET_MODULE;
	else if (soc_is_ar934x())
	else if (soc_is_ar934x())
		reg = AR934X_RESET_REG_RESET_MODULE;
		reg = AR934X_RESET_REG_RESET_MODULE;
	else if (soc_is_qca953x())
		reg = QCA953X_RESET_REG_RESET_MODULE;
	else if (soc_is_qca955x())
	else if (soc_is_qca955x())
		reg = QCA955X_RESET_REG_RESET_MODULE;
		reg = QCA955X_RESET_REG_RESET_MODULE;
	else if (soc_is_qca956x() || soc_is_tp9343())
		reg = QCA956X_RESET_REG_RESET_MODULE;
	else
	else
		BUG();
		BUG();


@@ -131,8 +135,12 @@ void ath79_device_reset_clear(u32 mask)
		reg = AR933X_RESET_REG_RESET_MODULE;
		reg = AR933X_RESET_REG_RESET_MODULE;
	else if (soc_is_ar934x())
	else if (soc_is_ar934x())
		reg = AR934X_RESET_REG_RESET_MODULE;
		reg = AR934X_RESET_REG_RESET_MODULE;
	else if (soc_is_qca953x())
		reg = QCA953X_RESET_REG_RESET_MODULE;
	else if (soc_is_qca955x())
	else if (soc_is_qca955x())
		reg = QCA955X_RESET_REG_RESET_MODULE;
		reg = QCA955X_RESET_REG_RESET_MODULE;
	else if (soc_is_qca956x() || soc_is_tp9343())
		reg = QCA956X_RESET_REG_RESET_MODULE;
	else
	else
		BUG();
		BUG();


+4 −0
Original line number Original line Diff line number Diff line
@@ -78,8 +78,12 @@ static void prom_putchar_init(void)
	case REV_ID_MAJOR_AR9341:
	case REV_ID_MAJOR_AR9341:
	case REV_ID_MAJOR_AR9342:
	case REV_ID_MAJOR_AR9342:
	case REV_ID_MAJOR_AR9344:
	case REV_ID_MAJOR_AR9344:
	case REV_ID_MAJOR_QCA9533:
	case REV_ID_MAJOR_QCA9533_V2:
	case REV_ID_MAJOR_QCA9556:
	case REV_ID_MAJOR_QCA9556:
	case REV_ID_MAJOR_QCA9558:
	case REV_ID_MAJOR_QCA9558:
	case REV_ID_MAJOR_TP9343:
	case REV_ID_MAJOR_QCA956X:
		_prom_putchar = prom_putchar_ar71xx;
		_prom_putchar = prom_putchar_ar71xx;
		break;
		break;


+31 −3
Original line number Original line Diff line number Diff line
@@ -59,6 +59,7 @@ static void __init ath79_detect_sys_type(void)
	u32 major;
	u32 major;
	u32 minor;
	u32 minor;
	u32 rev = 0;
	u32 rev = 0;
	u32 ver = 1;


	id = ath79_reset_rr(AR71XX_RESET_REG_REV_ID);
	id = ath79_reset_rr(AR71XX_RESET_REG_REV_ID);
	major = id & REV_ID_MAJOR_MASK;
	major = id & REV_ID_MAJOR_MASK;
@@ -151,6 +152,17 @@ static void __init ath79_detect_sys_type(void)
		rev = id & AR934X_REV_ID_REVISION_MASK;
		rev = id & AR934X_REV_ID_REVISION_MASK;
		break;
		break;


	case REV_ID_MAJOR_QCA9533_V2:
		ver = 2;
		ath79_soc_rev = 2;
		/* drop through */

	case REV_ID_MAJOR_QCA9533:
		ath79_soc = ATH79_SOC_QCA9533;
		chip = "9533";
		rev = id & QCA953X_REV_ID_REVISION_MASK;
		break;

	case REV_ID_MAJOR_QCA9556:
	case REV_ID_MAJOR_QCA9556:
		ath79_soc = ATH79_SOC_QCA9556;
		ath79_soc = ATH79_SOC_QCA9556;
		chip = "9556";
		chip = "9556";
@@ -163,14 +175,30 @@ static void __init ath79_detect_sys_type(void)
		rev = id & QCA955X_REV_ID_REVISION_MASK;
		rev = id & QCA955X_REV_ID_REVISION_MASK;
		break;
		break;


	case REV_ID_MAJOR_QCA956X:
		ath79_soc = ATH79_SOC_QCA956X;
		chip = "956X";
		rev = id & QCA956X_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;

	default:
	default:
		panic("ath79: unknown SoC, id:0x%08x", id);
		panic("ath79: unknown SoC, id:0x%08x", id);
	}
	}


	if (ver == 1)
		ath79_soc_rev = rev;
		ath79_soc_rev = rev;


	if (soc_is_qca955x())
	if (soc_is_qca953x() || soc_is_qca955x() || soc_is_qca956x())
		sprintf(ath79_sys_type, "Qualcomm Atheros QCA%s rev %u",
		sprintf(ath79_sys_type, "Qualcomm Atheros QCA%s ver %u rev %u",
			chip, ver, rev);
	else if (soc_is_tp9343())
		sprintf(ath79_sys_type, "Qualcomm Atheros TP%s rev %u",
			chip, rev);
			chip, rev);
	else
	else
		sprintf(ath79_sys_type, "Atheros AR%s rev %u", chip, rev);
		sprintf(ath79_sys_type, "Atheros AR%s rev %u", chip, rev);
+33 −0
Original line number Original line Diff line number Diff line
@@ -32,8 +32,11 @@ enum ath79_soc_type {
	ATH79_SOC_AR9341,
	ATH79_SOC_AR9341,
	ATH79_SOC_AR9342,
	ATH79_SOC_AR9342,
	ATH79_SOC_AR9344,
	ATH79_SOC_AR9344,
	ATH79_SOC_QCA9533,
	ATH79_SOC_QCA9556,
	ATH79_SOC_QCA9556,
	ATH79_SOC_QCA9558,
	ATH79_SOC_QCA9558,
	ATH79_SOC_TP9343,
	ATH79_SOC_QCA956X,
};
};


extern enum ath79_soc_type ath79_soc;
extern enum ath79_soc_type ath79_soc;
@@ -100,6 +103,16 @@ static inline int soc_is_ar934x(void)
	return soc_is_ar9341() || soc_is_ar9342() || soc_is_ar9344();
	return soc_is_ar9341() || soc_is_ar9342() || soc_is_ar9344();
}
}


static inline int soc_is_qca9533(void)
{
	return ath79_soc == ATH79_SOC_QCA9533;
}

static inline int soc_is_qca953x(void)
{
	return soc_is_qca9533();
}

static inline int soc_is_qca9556(void)
static inline int soc_is_qca9556(void)
{
{
	return ath79_soc == ATH79_SOC_QCA9556;
	return ath79_soc == ATH79_SOC_QCA9556;
@@ -115,6 +128,26 @@ static inline int soc_is_qca955x(void)
	return soc_is_qca9556() || soc_is_qca9558();
	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_QCA956X;
}

static inline int soc_is_qca9563(void)
{
	return ath79_soc == ATH79_SOC_QCA956X;
}

static inline int soc_is_qca956x(void)
{
	return soc_is_qca9561() || soc_is_qca9563();
}

void ath79_ddr_wb_flush(unsigned int reg);
void ath79_ddr_wb_flush(unsigned int reg);
void ath79_ddr_set_pci_windows(void);
void ath79_ddr_set_pci_windows(void);