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.
This commit is contained in:
jmcneill 2014-12-30 03:53:52 +00:00
parent c4f304668a
commit bf33f1be32
4 changed files with 237 additions and 24 deletions

View File

@ -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 <jmcneill@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) {
a9_core_div_con = __SHIFTOUT(clksel_con0,
RK3188_CRU_CLKSEL_CON0_A9_CORE_DIV_CON);
} else {
if (rockchip_is_chip(ROCKCHIP_CHIPVER_RK3066)) {
a9_core_div_con = __SHIFTOUT(clksel_con0,
CRU_CLKSEL_CON0_A9_CORE_DIV_CON);
} else {
a9_core_div_con = __SHIFTOUT(clksel_con0,
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

View File

@ -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 <jmcneill@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)

View File

@ -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_bsh;
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);

View File

@ -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);
}