Module Name: src Committed By: jmcneill Date: Tue Dec 30 03:53:52 UTC 2014
Modified Files: src/sys/arch/arm/rockchip: rockchip_board.c rockchip_crureg.h rockchip_var.h src/sys/arch/evbarm/rockchip: rockchip_machdep.c Log Message: Add support for setting RK3188/RK3188+ CPU frequency. If the SoC ID is passed in bootargs matching RK3188 or RK3188+, and the cpu.frequency option specifies a supported rate (currently 600, 1008, 1608 MHz), the APLL clock will be adjusted accordingly. To generate a diff of this commit: cvs rdiff -u -r1.5 -r1.6 src/sys/arch/arm/rockchip/rockchip_board.c cvs rdiff -u -r1.4 -r1.5 src/sys/arch/arm/rockchip/rockchip_crureg.h cvs rdiff -u -r1.6 -r1.7 src/sys/arch/arm/rockchip/rockchip_var.h cvs rdiff -u -r1.11 -r1.12 src/sys/arch/evbarm/rockchip/rockchip_machdep.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.5 src/sys/arch/arm/rockchip/rockchip_board.c:1.6 --- src/sys/arch/arm/rockchip/rockchip_board.c:1.5 Sat Dec 27 19:14:05 2014 +++ src/sys/arch/arm/rockchip/rockchip_board.c Tue Dec 30 03:53:52 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: rockchip_board.c,v 1.5 2014/12/27 19:14:05 jmcneill Exp $ */ +/* $NetBSD: rockchip_board.c,v 1.6 2014/12/30 03:53:52 jmcneill Exp $ */ /*- * Copyright (c) 2014 Jared D. McNeill <jmcne...@invisible.ca> @@ -29,13 +29,15 @@ #include "opt_rockchip.h" #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: rockchip_board.c,v 1.5 2014/12/27 19:14:05 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: rockchip_board.c,v 1.6 2014/12/30 03:53:52 jmcneill Exp $"); #include <sys/param.h> #include <sys/bus.h> #include <sys/cpu.h> #include <sys/device.h> +#include <arm/bootconfig.h> + #include <arm/rockchip/rockchip_reg.h> #include <arm/rockchip/rockchip_crureg.h> #include <arm/rockchip/rockchip_var.h> @@ -59,6 +61,20 @@ rockchip_bootstrap(void) panic("%s: failed to map CORE1 registers: %d", __func__, error); } +bool +rockchip_is_chip(const char *chipver) +{ + const size_t chipver_len = 16; + char *env_chipver; + + if (get_bootconf_option(boot_args, "chipver", + BOOTOPT_TYPE_STRING, &env_chipver) == 0) { + return false; + } + + return strncmp(env_chipver, chipver, chipver_len) == 0; +} + static void rockchip_get_cru_bsh(bus_space_handle_t *pbsh) { @@ -104,6 +120,177 @@ rockchip_apll_get_rate(void) return rockchip_pll_get_rate(CRU_APLL_CON0_REG, CRU_APLL_CON1_REG); } +static u_int +rk3188_apll_set_rate(u_int rate) +{ + bus_space_tag_t bst = &rockchip_bs_tag; + bus_space_handle_t bsh; + uint32_t apll_con0, apll_con1, clksel0_con, clksel1_con; + 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; + + rockchip_get_cru_bsh(&bsh); + +#ifdef ROCKCHIP_CLOCK_DEBUG + printf("%s: rate=%u\n", __func__, rate); +#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 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: +#ifdef ROCKCHIP_CLOCK_DEBUG + printf("%s: unsupported rate %u\n", __func__, rate); +#endif + return EINVAL; + } + + 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_con1 = CRU_PLL_CON1_CLKF_MASK; + apll_con1 |= __SHIFTIN(nf - 1, CRU_PLL_CON1_CLKF); + + 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 | + CRU_CLKSEL_CON0_CPU_CLK_PLL_SEL; + clksel0_con |= __SHIFTIN(core_div - 1, + RK3188_CRU_CLKSEL_CON0_A9_CORE_DIV_CON); + clksel0_con |= __SHIFTIN(ffs(core_periph_div) - 2, + CRU_CLKSEL_CON0_CORE_PERI_DIV_CON); + clksel0_con |= __SHIFTIN(aclk_div - 1, + CRU_CLKSEL_CON0_A9_CORE_DIV_CON); + + clksel1_con = RK3188_CRU_CLKSEL_CON1_CPU_ACLK_DIV_CON_MASK | + CRU_CLKSEL_CON1_AHB2APB_PCLKEN_DIV_CON_MASK | + CRU_CLKSEL_CON1_CPU_PCLK_DIV_CON_MASK | + CRU_CLKSEL_CON1_CPU_HCLK_DIV_CON_MASK; + + switch (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; + case 4: cpu_aclk_div_con = 3; break; + case 8: cpu_aclk_div_con = 4; break; + default: panic("bad core_axi_div"); + } + clksel1_con |= __SHIFTIN(cpu_aclk_div_con, + RK3188_CRU_CLKSEL_CON1_CPU_ACLK_DIV_CON); + clksel1_con |= __SHIFTIN(ffs(ahb2apb_div) - 1, + CRU_CLKSEL_CON1_AHB2APB_PCLKEN_DIV_CON); + clksel1_con |= __SHIFTIN(ffs(hclk_div) - 1, + CRU_CLKSEL_CON1_CPU_HCLK_DIV_CON); + clksel1_con |= __SHIFTIN(ffs(pclk_div) - 1, + CRU_CLKSEL_CON1_CPU_PCLK_DIV_CON); + +#ifdef ROCKCHIP_CLOCK_DEBUG + printf("before: APLL_CON0: %#x\n", + bus_space_read_4(bst, bsh, CRU_APLL_CON0_REG)); + printf("before: APLL_CON1: %#x\n", + bus_space_read_4(bst, bsh, CRU_APLL_CON1_REG)); + printf("before: CLKSEL0_CON: %#x\n", + bus_space_read_4(bst, bsh, CRU_CLKSEL_CON_REG(0))); + printf("before: CLKSEL1_CON: %#x\n", + bus_space_read_4(bst, bsh, CRU_CLKSEL_CON_REG(1))); +#endif + + /* Change from normal to slow 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_SLOW, + CRU_MODE_CON_APLL_WORK_MODE)); + + /* Power down */ + bus_space_write_4(bst, bsh, CRU_APLL_CON3_REG, + CRU_PLL_CON3_POWER_DOWN_MASK | CRU_PLL_CON3_POWER_DOWN); + + /* Update APLL regs */ + bus_space_write_4(bst, bsh, CRU_APLL_CON0_REG, apll_con0); + bus_space_write_4(bst, bsh, CRU_APLL_CON1_REG, apll_con1); + + /* Wait for PLL lock */ + for (volatile int i = 5000; i >= 0; i--) + ; + + /* Power up */ + bus_space_write_4(bst, bsh, CRU_APLL_CON3_REG, + CRU_PLL_CON3_POWER_DOWN_MASK); + + /* 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); + + for (volatile int i = 50000; i >= 0; i--) + ; + + /* Change from slow mode to 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", + bus_space_read_4(bst, bsh, CRU_APLL_CON0_REG)); + printf("after: APLL_CON1: %#x\n", + bus_space_read_4(bst, bsh, CRU_APLL_CON1_REG)); + printf("after: CLKSEL0_CON: %#x\n", + bus_space_read_4(bst, bsh, CRU_CLKSEL_CON_REG(0))); + printf("after: CLKSEL1_CON: %#x\n", + bus_space_read_4(bst, bsh, CRU_CLKSEL_CON_REG(1))); +#endif + + return 0; +} + +u_int +rockchip_apll_set_rate(u_int rate) +{ + if (rockchip_is_chip(ROCKCHIP_CHIPVER_RK3188) || + rockchip_is_chip(ROCKCHIP_CHIPVER_RK3188PLUS)) { + return rk3188_apll_set_rate(rate); + } + + return ENODEV; +} + u_int rockchip_cpu_get_rate(void) { @@ -122,17 +309,13 @@ rockchip_cpu_get_rate(void) rate = rockchip_apll_get_rate(); } -#if notyet - if (rockchip_chip_id() == ROCKCHIP_CHIP_ID_RK3188) { + if (rockchip_is_chip(ROCKCHIP_CHIPVER_RK3066)) { a9_core_div_con = __SHIFTOUT(clksel_con0, - RK3188_CRU_CLKSEL_CON0_A9_CORE_DIV_CON); + CRU_CLKSEL_CON0_A9_CORE_DIV_CON); } else { a9_core_div_con = __SHIFTOUT(clksel_con0, - CRU_CLKSEL_CON0_A9_CORE_DIV_CON); + RK3188_CRU_CLKSEL_CON0_A9_CORE_DIV_CON); } -#else - a9_core_div_con = 0; -#endif #ifdef ROCKCHIP_CLOCK_DEBUG printf("%s: clksel_con0=%#x\n", __func__, clksel_con0); @@ -153,11 +336,7 @@ rockchip_a9periph_get_rate(void) rockchip_get_cru_bsh(&bsh); clksel_con0 = bus_space_read_4(bst, bsh, CRU_CLKSEL_CON_REG(0)); - if (clksel_con0 & CRU_CLKSEL_CON0_CPU_CLK_PLL_SEL) { - rate = rockchip_gpll_get_rate(); - } else { - rate = rockchip_apll_get_rate(); - } + rate = rockchip_cpu_get_rate(); core_peri_div_con = __SHIFTOUT(clksel_con0, CRU_CLKSEL_CON0_CORE_PERI_DIV_CON); @@ -216,7 +395,7 @@ rockchip_mmc0_set_div(u_int div) clksel_con11 = CRU_CLKSEL_CON11_MMC0_PLL_SEL_MASK | CRU_CLKSEL_CON11_MMC0_DIV_CON_MASK; - //clksel_con11 |= CRU_CLKSEL_CON11_MMC0_PLL_SEL; /* GPLL */ + clksel_con11 |= CRU_CLKSEL_CON11_MMC0_PLL_SEL; /* GPLL */ clksel_con11 |= __SHIFTIN(div - 1, CRU_CLKSEL_CON11_MMC0_DIV_CON); #ifdef ROCKCHIP_CLOCK_DEBUG Index: src/sys/arch/arm/rockchip/rockchip_crureg.h diff -u src/sys/arch/arm/rockchip/rockchip_crureg.h:1.4 src/sys/arch/arm/rockchip/rockchip_crureg.h:1.5 --- src/sys/arch/arm/rockchip/rockchip_crureg.h:1.4 Sat Dec 27 19:14:34 2014 +++ src/sys/arch/arm/rockchip/rockchip_crureg.h Tue Dec 30 03:53:52 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: rockchip_crureg.h,v 1.4 2014/12/27 19:14:34 jmcneill Exp $ */ +/* $NetBSD: rockchip_crureg.h,v 1.5 2014/12/30 03:53:52 jmcneill Exp $ */ /*- * Copyright (c) 2014 Jared D. McNeill <jmcne...@invisible.ca> @@ -62,13 +62,34 @@ #define CRU_PLL_CON1_CLKF_MASK __BITS(31,16) #define CRU_PLL_CON1_CLKF __BITS(15,0) +#define CRU_PLL_CON3_POWER_DOWN_MASK __BIT(17) +#define CRU_PLL_CON3_POWER_DOWN __BIT(1) + +#define CRU_MODE_CON_APLL_WORK_MODE_MASK __BITS(17,16) +#define CRU_MODE_CON_APLL_WORK_MODE __BITS(1,0) +#define CRU_MODE_CON_APLL_WORK_MODE_SLOW 0 +#define CRU_MODE_CON_APLL_WORK_MODE_NORMAL 1 +#define CRU_MODE_CON_APLL_WORK_MODE_DEEP_SLOW 2 + +#define RK3188_CRU_CLKSEL_CON0_A9_CORE_DIV_CON_MASK __BITS(29,25) #define CRU_CLKSEL_CON0_CPU_CLK_PLL_SEL_MASK __BIT(24) #define CRU_CLKSEL_CON0_CORE_PERI_DIV_CON_MASK __BITS(23,22) #define CRU_CLKSEL_CON0_A9_CORE_DIV_CON_MASK __BITS(20,16) +#define RK3188_CRU_CLKSEL_CON0_A9_CORE_DIV_CON __BITS(13,9) #define CRU_CLKSEL_CON0_CPU_CLK_PLL_SEL __BIT(8) #define CRU_CLKSEL_CON0_CORE_PERI_DIV_CON __BITS(7,6) #define CRU_CLKSEL_CON0_A9_CORE_DIV_CON __BITS(4,0) -#define RK3188_CRU_CLKSEL_CON0_A9_CORE_DIV_CON __BITS(13,9) + +#define CRU_CLKSEL_CON1_AHB2APB_PCLKEN_DIV_CON_MASK __BITS(31,30) +#define CRU_CLKSEL_CON1_CPU_PCLK_DIV_CON_MASK __BITS(29,28) +#define CRU_CLKSEL_CON1_CPU_HCLK_DIV_CON_MASK __BITS(25,24) +#define RK3188_CRU_CLKSEL_CON1_CPU_ACLK_DIV_CON_MASK __BITS(21,19) +#define CRU_CLKSEL_CON1_CPU_ACLK_DIV_CON_MASK __BITS(18,16) +#define CRU_CLKSEL_CON1_AHB2APB_PCLKEN_DIV_CON __BITS(15,14) +#define CRU_CLKSEL_CON1_CPU_PCLK_DIV_CON __BITS(13,12) +#define CRU_CLKSEL_CON1_CPU_HCLK_DIV_CON __BITS(9,8) +#define RK3188_CRU_CLKSEL_CON1_CPU_ACLK_DIV_CON __BITS(5,3) +#define CRU_CLKSEL_CON1_CPU_ACLK_DIV_CON __BITS(2,0) #define CRU_CLKSEL_CON10_PERI_PLL_SEL_MASK __BIT(31) #define CRU_CLKSEL_CON10_PERI_PCLK_DIV_CON_MASK __BITS(29,28) Index: src/sys/arch/arm/rockchip/rockchip_var.h diff -u src/sys/arch/arm/rockchip/rockchip_var.h:1.6 src/sys/arch/arm/rockchip/rockchip_var.h:1.7 --- src/sys/arch/arm/rockchip/rockchip_var.h:1.6 Sat Dec 27 19:14:05 2014 +++ src/sys/arch/arm/rockchip/rockchip_var.h Tue Dec 30 03:53:52 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: rockchip_var.h,v 1.6 2014/12/27 19:14:05 jmcneill Exp $ */ +/* $NetBSD: rockchip_var.h,v 1.7 2014/12/30 03:53:52 jmcneill Exp $ */ /*- * Copyright (c) 2014 The NetBSD Foundation, Inc. @@ -58,7 +58,13 @@ extern bus_space_handle_t rockchip_core1 void rockchip_bootstrap(void); +bool rockchip_is_chip(const char *); +#define ROCKCHIP_CHIPVER_RK3066 "300A20111111V101" +#define ROCKCHIP_CHIPVER_RK3188 "310B20121130V100" +#define ROCKCHIP_CHIPVER_RK3188PLUS "310B20130131V101" + u_int rockchip_apll_get_rate(void); +u_int rockchip_apll_set_rate(u_int); u_int rockchip_gpll_get_rate(void); u_int rockchip_cpu_get_rate(void); u_int rockchip_ahb_get_rate(void); Index: src/sys/arch/evbarm/rockchip/rockchip_machdep.c diff -u src/sys/arch/evbarm/rockchip/rockchip_machdep.c:1.11 src/sys/arch/evbarm/rockchip/rockchip_machdep.c:1.12 --- src/sys/arch/evbarm/rockchip/rockchip_machdep.c:1.11 Mon Dec 29 03:16:07 2014 +++ src/sys/arch/evbarm/rockchip/rockchip_machdep.c Tue Dec 30 03:53:52 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: rockchip_machdep.c,v 1.11 2014/12/29 03:16:07 jmcneill Exp $ */ +/* $NetBSD: rockchip_machdep.c,v 1.12 2014/12/30 03:53:52 jmcneill Exp $ */ /* * Machine dependent functions for kernel setup for TI OSK5912 board. @@ -125,7 +125,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: rockchip_machdep.c,v 1.11 2014/12/29 03:16:07 jmcneill Exp $"); +__KERNEL_RCSID(0, "$NetBSD: rockchip_machdep.c,v 1.12 2014/12/30 03:53:52 jmcneill Exp $"); #include "opt_machdep.h" #include "opt_ddb.h" @@ -465,6 +465,7 @@ initarm(void *arg) { psize_t ram_size = 0; char *ptr; + u_int cpufreq; *(volatile int *)CONSADDR_VA = 0x40; /* output '@' */ #if 1 rockchip_putchar('d'); @@ -484,8 +485,6 @@ initarm(void *arg) if (set_cpufuncs()) panic("cpu not recognized!"); - curcpu()->ci_data.cpu_cc_freq = rockchip_cpu_get_rate(); - init_clocks(); consinit(); @@ -509,7 +508,6 @@ initarm(void *arg) printf("\nuboot arg = %#x, %#x, %#x, %#x\n", uboot_args[0], uboot_args[1], uboot_args[2], uboot_args[3]); - #ifdef KGDB kgdb_port_init(); #endif @@ -584,6 +582,8 @@ initarm(void *arg) } } + printf("bootargs: %s\n", bootargs); + boot_args = bootargs; parse_mi_bootargs(boot_args); @@ -597,6 +597,13 @@ initarm(void *arg) use_fb_console = true; } + if (get_bootconf_option(boot_args, "cpu.frequency", + BOOTOPT_TYPE_INT, &cpufreq)) { + rockchip_apll_set_rate(cpufreq * 1000000); + } + + curcpu()->ci_data.cpu_cc_freq = rockchip_cpu_get_rate(); + return initarm_common(KERNEL_VM_BASE, KERNEL_VM_SIZE, NULL, 0); }