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",