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

Reply via email to