Module Name:    src
Committed By:   jmcneill
Date:           Wed Dec 31 18:09:06 UTC 2014

Modified Files:
        src/sys/arch/arm/rockchip: rockchip_board.c

Log Message:
Cleanup freq setting a bit. Add a table of supported rates in ~200MHz steps
from 600MHz to 1608MHz, and let the cpu.frequency parameter match the
closest available freq (without going over +50MHz).

After updating APLL, wait for PLL lock.

Do APLL changes with PLL mode set to slow, rather than the previous
(and more complex) APLL/GPLL dance.


To generate a diff of this commit:
cvs rdiff -u -r1.8 -r1.9 src/sys/arch/arm/rockchip/rockchip_board.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/arm/rockchip/rockchip_board.c
diff -u src/sys/arch/arm/rockchip/rockchip_board.c:1.8 src/sys/arch/arm/rockchip/rockchip_board.c:1.9
--- src/sys/arch/arm/rockchip/rockchip_board.c:1.8	Wed Dec 31 16:16:35 2014
+++ src/sys/arch/arm/rockchip/rockchip_board.c	Wed Dec 31 18:09:05 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: rockchip_board.c,v 1.8 2014/12/31 16:16:35 jmcneill Exp $ */
+/* $NetBSD: rockchip_board.c,v 1.9 2014/12/31 18:09:05 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2014 Jared D. McNeill <jmcne...@invisible.ca>
@@ -29,7 +29,7 @@
 #include "opt_rockchip.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rockchip_board.c,v 1.8 2014/12/31 16:16:35 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rockchip_board.c,v 1.9 2014/12/31 18:09:05 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -83,6 +83,13 @@ rockchip_get_cru_bsh(bus_space_handle_t 
 	    ROCKCHIP_CRU_OFFSET, ROCKCHIP_CRU_SIZE, pbsh);
 }
 
+static void
+rockchip_get_grf_bsh(bus_space_handle_t *pbsh)
+{
+	bus_space_subregion(&rockchip_bs_tag, rockchip_core1_bsh,
+	    ROCKCHIP_GRF_OFFSET, ROCKCHIP_GRF_SIZE, pbsh);
+}
+
 static u_int
 rockchip_pll_get_rate(bus_size_t con0_reg, bus_size_t con1_reg)
 {
@@ -127,80 +134,68 @@ rockchip_apll_get_rate(void)
 	return rockchip_pll_get_rate(CRU_APLL_CON0_REG, CRU_APLL_CON1_REG);
 }
 
+struct rk3188_apll_rate {
+	u_int rate;
+	u_int nr, nf, no;
+	u_int core_div, core_periph_div, core_axi_div;
+	u_int aclk_div, hclk_div, pclk_div, ahb2apb_div;
+};
+
+#define RK3188_RATE(_r, _nf, _no, _p, _a, _aclk, _hclk, _pclk, _ahb2apb) \
+	{ .rate = (_r) * 1000000, .nr = 1, .nf = (_nf), .no = (_no),	 \
+	  .core_div = 1, .core_periph_div = (_p), .core_axi_div = (_a),	 \
+	  .aclk_div = (_aclk), .hclk_div = (_hclk), .pclk_div = (_pclk), \
+	  .ahb2apb_div = (_ahb2apb) }
+
+static const struct rk3188_apll_rate rk3188_apll_rates[] = {
+	RK3188_RATE(1608, 67, 1, 8, 4, 4, 2, 4, 2),
+	RK3188_RATE(1416, 59, 1, 8, 4, 4, 2, 4, 2),
+	RK3188_RATE(1200, 50, 1, 8, 4, 4, 2, 4, 2),
+	RK3188_RATE(1008, 42, 1, 8, 3, 3, 2, 4, 2),
+	RK3188_RATE( 816, 68, 2, 8, 4, 3, 2, 4, 2),
+	RK3188_RATE( 600, 50, 2, 4, 4, 3, 2, 4, 2),
+};
+
+#define RK3188_GRF_STATUS0_REG		0x00ac
+#define RK3188_GRF_STATUS0_APLL_LOCK	__BIT(6)
+
 static u_int
 rk3188_apll_set_rate(u_int rate)
 {
+	const struct rk3188_apll_rate *r = NULL;
 	bus_space_tag_t bst = &rockchip_bs_tag;
-	bus_space_handle_t bsh;
+	bus_space_handle_t bsh, grf_bsh;
 	uint32_t apll_con0, apll_con1, apll_con2, clksel0_con, clksel1_con;
 	uint32_t reset_mask, reset;
-	u_int no, nr, nf, core_div, core_periph_div, core_axi_div,
-	      aclk_div, hclk_div, pclk_div, ahb2apb_div;
 	u_int cpu_aclk_div_con;
 	const bool rk3188plus_p = rockchip_is_chip(ROCKCHIP_CHIPVER_RK3188PLUS);
 
 	rockchip_get_cru_bsh(&bsh);
+	rockchip_get_grf_bsh(&grf_bsh);
 
 #ifdef ROCKCHIP_CLOCK_DEBUG
 	printf("%s: rate=%u rk3188plus_p=%d\n", __func__, rate, rk3188plus_p);
 #endif
 
-	switch (rate) {
-	case 1608000000:
-		nr = 1;
-		nf = 67;
-		no = 1;
-		core_div = 1;
-		core_periph_div = 8;
-		core_axi_div = 4;
-		aclk_div = 4;
-		hclk_div = 2;
-		pclk_div = 4;
-		ahb2apb_div = 2;
-		break;
-	case 1416000000:
-		nr = 1;
-		nf = 59;
-		no = 1;
-		core_div = 1;
-		core_periph_div = 8;
-		core_axi_div = 4;
-		aclk_div = 4;
-		hclk_div = 2;
-		pclk_div = 4;
-		ahb2apb_div = 2;
-		break;
-	case 1008000000:
-		nr = 1;
-		nf = 42;
-		no = 1;
-		core_div = 1;
-		core_periph_div = 8;
-		core_axi_div = 3;
-		aclk_div = 3;
-		hclk_div = 2;
-		pclk_div = 4;
-		ahb2apb_div = 2;
-		break;
-	case 600000000:
-		nr = 1;
-		nf = 50;
-		no = 2;
-		core_div = 1;
-		core_periph_div = 4;
-		core_axi_div = 4;
-		aclk_div = 3;
-		hclk_div = 2;
-		pclk_div = 4;
-		ahb2apb_div = 2;
-		break;
-	default:
+	/* Pick the closest rate (nearest 100MHz increment) */
+	for (int i = 0; i < __arraycount(rk3188_apll_rates); i++) {
+		u_int trate = rate / 1000000;
+		u_int arate = ((rk3188_apll_rates[i].rate / 1000000) + 50)
+		    / 100 * 100;
+		if (arate <= trate) {
+			r = &rk3188_apll_rates[i];
+			break;
+		}
+	}
+	if (r == NULL) {
 #ifdef ROCKCHIP_CLOCK_DEBUG
-		printf("%s: unsupported rate %u\n", __func__, rate);
+		printf("CPU: No matching rate found for %u MHz\n", rate);
 #endif
-		return EINVAL;
+		return ENOENT;
 	}
 
+	printf("CPU: Set frequency to %u MHz...\n", r->rate / 1000000);
+
 	if (rk3188plus_p) {
 	    	reset_mask = CRU_PLL_CON3_RESET_MASK;
 		reset = CRU_PLL_CON3_RESET;
@@ -210,15 +205,15 @@ rk3188_apll_set_rate(u_int rate)
 	}
 
 	apll_con0 = CRU_PLL_CON0_CLKR_MASK | CRU_PLL_CON0_CLKOD_MASK;
-	apll_con0 |= __SHIFTIN(no - 1, CRU_PLL_CON0_CLKOD);
-	apll_con0 |= __SHIFTIN(nr - 1, CRU_PLL_CON0_CLKR);
+	apll_con0 |= __SHIFTIN(r->no - 1, CRU_PLL_CON0_CLKOD);
+	apll_con0 |= __SHIFTIN(r->nr - 1, CRU_PLL_CON0_CLKR);
 
 	apll_con1 = CRU_PLL_CON1_CLKF_MASK;
-	apll_con1 |= __SHIFTIN(nf - 1, CRU_PLL_CON1_CLKF);
+	apll_con1 |= __SHIFTIN(r->nf - 1, CRU_PLL_CON1_CLKF);
 
 	if (rk3188plus_p) {
 		apll_con2 = CRU_PLL_CON2_BWADJ_MASK;
-		apll_con2 |= __SHIFTIN(nf >> 1, CRU_PLL_CON2_BWADJ);
+		apll_con2 |= __SHIFTIN(r->nf >> 1, CRU_PLL_CON2_BWADJ);
 	} else {
 		apll_con2 = 0;
 	}
@@ -226,18 +221,19 @@ rk3188_apll_set_rate(u_int rate)
 	clksel0_con = RK3188_CRU_CLKSEL_CON0_A9_CORE_DIV_CON_MASK |
 		      CRU_CLKSEL_CON0_CORE_PERI_DIV_CON_MASK |
 		      CRU_CLKSEL_CON0_A9_CORE_DIV_CON_MASK;
-	clksel0_con |= __SHIFTIN(core_div - 1,
+	clksel0_con |= __SHIFTIN(r->core_div - 1,
 				 RK3188_CRU_CLKSEL_CON0_A9_CORE_DIV_CON);
-	clksel0_con |= __SHIFTIN(ffs(core_periph_div) - 2,
+	clksel0_con |= __SHIFTIN(ffs(r->core_periph_div) - 2,
 				 CRU_CLKSEL_CON0_CORE_PERI_DIV_CON);
-	clksel0_con |= __SHIFTIN(aclk_div - 1,
+	clksel0_con |= __SHIFTIN(r->aclk_div - 1,
 				 CRU_CLKSEL_CON0_A9_CORE_DIV_CON);
 
 	clksel1_con = CRU_CLKSEL_CON1_AHB2APB_PCLKEN_DIV_CON_MASK |
 		      CRU_CLKSEL_CON1_CPU_PCLK_DIV_CON_MASK |
-		      CRU_CLKSEL_CON1_CPU_HCLK_DIV_CON_MASK;
+		      CRU_CLKSEL_CON1_CPU_HCLK_DIV_CON_MASK |
+		      RK3188_CRU_CLKSEL_CON1_CPU_ACLK_DIV_CON_MASK;
 
-	switch (core_axi_div) {
+	switch (r->core_axi_div) {
 	case 1:	cpu_aclk_div_con = 0; break;
 	case 2: cpu_aclk_div_con = 1; break;
 	case 3: cpu_aclk_div_con = 2; break;
@@ -245,12 +241,14 @@ rk3188_apll_set_rate(u_int rate)
 	case 8: cpu_aclk_div_con = 4; break;
 	default: panic("bad core_axi_div");
 	}
-	clksel1_con |= __SHIFTIN(ffs(ahb2apb_div) - 1,
+	clksel1_con |= __SHIFTIN(ffs(r->ahb2apb_div) - 1,
 				 CRU_CLKSEL_CON1_AHB2APB_PCLKEN_DIV_CON);
-	clksel1_con |= __SHIFTIN(ffs(hclk_div) - 1,
+	clksel1_con |= __SHIFTIN(ffs(r->hclk_div) - 1,
 				 CRU_CLKSEL_CON1_CPU_HCLK_DIV_CON);
-	clksel1_con |= __SHIFTIN(ffs(pclk_div) - 1,
+	clksel1_con |= __SHIFTIN(ffs(r->pclk_div) - 1,
 				 CRU_CLKSEL_CON1_CPU_PCLK_DIV_CON);
+	clksel1_con |= __SHIFTIN(cpu_aclk_div_con,
+				 RK3188_CRU_CLKSEL_CON1_CPU_ACLK_DIV_CON);
 
 #ifdef ROCKCHIP_CLOCK_DEBUG
 	printf("before: APLL_CON0: %#x\n",
@@ -263,16 +261,10 @@ rk3188_apll_set_rate(u_int rate)
 	    bus_space_read_4(bst, bsh, CRU_CLKSEL_CON_REG(1)));
 #endif
 
-	/* Set CPU clk src to GPLL */
-	const u_int curcpufreq = rockchip_cpu_get_rate();
-	const u_int gpllfreq = rockchip_gpll_get_rate();
-
-	bus_space_write_4(bst, bsh, CRU_CLKSEL_CON_REG(0),
-	    RK3188_CRU_CLKSEL_CON0_A9_CORE_DIV_CON_MASK|
-	    CRU_CLKSEL_CON0_CPU_CLK_PLL_SEL_MASK|
-	    __SHIFTIN(howmany(curcpufreq, gpllfreq) - 1,
-		      RK3188_CRU_CLKSEL_CON0_A9_CORE_DIV_CON)|
-	    CRU_CLKSEL_CON0_CPU_CLK_PLL_SEL);
+	bus_space_write_4(bst, bsh, CRU_MODE_CON_REG,
+	    CRU_MODE_CON_APLL_WORK_MODE_MASK |
+	    __SHIFTIN(CRU_MODE_CON_APLL_WORK_MODE_SLOW,
+		      CRU_MODE_CON_APLL_WORK_MODE));
 
 	/* Power down */
 	bus_space_write_4(bst, bsh, CRU_APLL_CON3_REG, reset_mask | reset);
@@ -283,28 +275,36 @@ rk3188_apll_set_rate(u_int rate)
 	if (apll_con2)
 		bus_space_write_4(bst, bsh, CRU_APLL_CON2_REG, apll_con2);
 
-	/* Wait for PLL lock */
 	for (volatile int i = 5000; i >= 0; i--)
 		;
 
 	/* Power up */
 	bus_space_write_4(bst, bsh, CRU_APLL_CON3_REG, reset_mask);
 
+	/* Wait for PLL lock */
+	printf("CPU: Waiting for PLL lock...\n");
 	for (volatile int i = 50000; i >= 0; i--)
 		;
+	int retry = ROCKCHIP_REF_FREQ;
+	while (--retry > 0) {
+		uint32_t status = bus_space_read_4(bst, grf_bsh,
+		    RK3188_GRF_STATUS0_REG);
+		if (status & RK3188_GRF_STATUS0_APLL_LOCK)
+			break;
+		for (volatile int i = 1000; i >= 0; i--)
+			;
+	}
+	printf("CPU: PLL lock %s\n", retry == 0 ? "timeout!" : "OK");
 
 	/* Update CLKSEL regs */
 	bus_space_write_4(bst, bsh, CRU_CLKSEL_CON_REG(0), clksel0_con);
 	bus_space_write_4(bst, bsh, CRU_CLKSEL_CON_REG(1), clksel1_con);
 
-	/* Set CPU clk src to APLL */
-	bus_space_write_4(bst, bsh, CRU_CLKSEL_CON_REG(0),
-	    CRU_CLKSEL_CON0_CPU_CLK_PLL_SEL_MASK);
-
-	bus_space_write_4(bst, bsh, CRU_CLKSEL_CON_REG(0),
-	    RK3188_CRU_CLKSEL_CON1_CPU_ACLK_DIV_CON_MASK |
-	    __SHIFTIN(cpu_aclk_div_con,
-		      RK3188_CRU_CLKSEL_CON1_CPU_ACLK_DIV_CON));
+	/* Slow -> Normal mode */
+	bus_space_write_4(bst, bsh, CRU_MODE_CON_REG,
+	    CRU_MODE_CON_APLL_WORK_MODE_MASK |
+	    __SHIFTIN(CRU_MODE_CON_APLL_WORK_MODE_NORMAL,
+		      CRU_MODE_CON_APLL_WORK_MODE));
 
 #ifdef ROCKCHIP_CLOCK_DEBUG
 	printf("after: APLL_CON0: %#x\n",

Reply via email to