Module Name: src Committed By: matt Date: Sat Jun 29 20:21:41 UTC 2013
Modified Files: src/sys/arch/arm/omap: am335x_prcm.c am335x_prcm.h Log Message: Add code to allow changing the cpu frequency. XXX the sysctl_createv fails for "current" with ENOENT. To generate a diff of this commit: cvs rdiff -u -r1.2 -r1.3 src/sys/arch/arm/omap/am335x_prcm.c cvs rdiff -u -r1.3 -r1.4 src/sys/arch/arm/omap/am335x_prcm.h 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/omap/am335x_prcm.c diff -u src/sys/arch/arm/omap/am335x_prcm.c:1.2 src/sys/arch/arm/omap/am335x_prcm.c:1.3 --- src/sys/arch/arm/omap/am335x_prcm.c:1.2 Fri Jun 28 02:31:16 2013 +++ src/sys/arch/arm/omap/am335x_prcm.c Sat Jun 29 20:21:41 2013 @@ -1,4 +1,4 @@ -/* $NetBSD: am335x_prcm.c,v 1.2 2013/06/28 02:31:16 matt Exp $ */ +/* $NetBSD: am335x_prcm.c,v 1.3 2013/06/29 20:21:41 matt Exp $ */ /* * TI OMAP Power, Reset, and Clock Management on the AM335x @@ -34,10 +34,11 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: am335x_prcm.c,v 1.2 2013/06/28 02:31:16 matt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: am335x_prcm.c,v 1.3 2013/06/29 20:21:41 matt Exp $"); #include <sys/types.h> #include <sys/param.h> +#include <sys/sysctl.h> #include <arm/omap/am335x_prcm.h> #include <arm/omap/omap2_prcm.h> @@ -94,6 +95,18 @@ prcm_module_disable(const struct omap_mo am335x_prcm_check_clkctrl(cm_module, clkctrl_reg, clkctrl); } +static const uint16_t mpu_frequencies[] = { + 550, + 600, + 650, + 700, + 720, + 800, + 900, + 1000 +}; +static int mpu_frequency; + void prcm_mpu_pll_config(u_int mpupll_m) { @@ -101,10 +114,10 @@ prcm_mpu_pll_config(u_int mpupll_m) uint32_t clksel = prcm_read_4(AM335X_PRCM_CM_WKUP, AM335X_PRCM_CM_CLKSEL_DPLL_MPU); //uint32_t div_m2 = prcm_read_4(AM335X_PRCM_CM_WKUP, AM335X_PRCM_CM_DIV_M2_DPLL_MPU); - /* Request the DPLL to be put into bypass mode */ + /* Request the DPLL be put into bypass mode */ prcm_write_4(AM335X_PRCM_CM_WKUP, AM335X_PRCM_CM_CLKMODE_DPLL_MPU, AM335X_PRCM_CM_CLKMODE_DPLL_MN_BYP_MODE); - /* Wait for it to be put into bypass */ + /* Wait for it to go into bypass */ while (prcm_read_4(AM335X_PRCM_CM_WKUP, AM335X_PRCM_CM_IDLEST_DPLL_MPU) != AM335X_PRCM_CM_IDLEST_DPLL_ST_DPLL_CLK_MN_BYPASS) { /* nothing */ } @@ -123,3 +136,83 @@ prcm_mpu_pll_config(u_int mpupll_m) /* nothing */ } } + +static int +mpu_current_frequency_sysctl_helper(SYSCTLFN_ARGS) +{ + struct sysctlnode node = *rnode; + int freq = mpu_frequency; + int old_freq = freq; + + KASSERT(curcpu()->ci_data.cpu_cc_freq == mpu_frequency * 1000); + + node.sysctl_data = &freq; + + int error = sysctl_lookup(SYSCTLFN_CALL(&node)); + + if (error || newp == NULL) + return error; + + KASSERT(old_freq == mpu_frequency); + + error = EINVAL; + for (size_t i = 0; i < __arraycount(mpu_frequencies); i++) { + if (mpu_frequencies[i] == freq) { + error = 0; + break; + } + } + if (error) + return EINVAL; + + if (freq != old_freq) { + const int s = splhigh(); + prcm_mpu_pll_config(freq); + curcpu()->ci_data.cpu_cc_freq = freq * 1000000; + mpu_frequency = freq; + splx(s); + aprint_normal_dev(curcpu()->ci_dev, + "frequency changed from %d MHz to %d MHz\n", + old_freq, freq); + } + + return 0; +} + +SYSCTL_SETUP(sysctl_am335x_machdep_setup, "sysctl am335x machdep subtree setup") +{ + const struct sysctlnode *freqnode, *node; + + static char mpu_available_frequencies[__arraycount(mpu_frequencies)*6]; + + KASSERT(__arraycount(mpu_frequencies) == 8); + snprintf(mpu_available_frequencies, sizeof(mpu_available_frequencies), + "%u %u %u %u %u %u %u %u", + mpu_frequencies[0], mpu_frequencies[1], mpu_frequencies[2], + mpu_frequencies[3], mpu_frequencies[4], mpu_frequencies[5], + mpu_frequencies[6], mpu_frequencies[7]); + + sysctl_createv(clog, 0, NULL, &node, + CTLFLAG_PERMANENT, + CTLTYPE_NODE, "machdep", NULL, + NULL, 0, NULL, 0, + CTL_MACHDEP, CTL_EOL); + + sysctl_createv(clog, 0, &node, &freqnode, + CTLFLAG_PERMANENT, + CTLTYPE_NODE, "frequency", NULL, + NULL, 0, NULL, 0, + CTL_CREATE, CTL_EOL); + + sysctl_createv(clog, 0, &freqnode, NULL, + CTLFLAG_PERMANENT, + CTLTYPE_STRING, "available", NULL, + NULL, 0, mpu_available_frequencies, + strlen(mpu_available_frequencies), + CTL_CREATE, CTL_EOL); + sysctl_createv(clog, 0, &freqnode, NULL, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, + CTLTYPE_INT, "current", NULL, + mpu_current_frequency_sysctl_helper, 0, NULL, 0 + CTL_CREATE, CTL_EOL); +} Index: src/sys/arch/arm/omap/am335x_prcm.h diff -u src/sys/arch/arm/omap/am335x_prcm.h:1.3 src/sys/arch/arm/omap/am335x_prcm.h:1.4 --- src/sys/arch/arm/omap/am335x_prcm.h:1.3 Fri Jun 28 02:31:16 2013 +++ src/sys/arch/arm/omap/am335x_prcm.h Sat Jun 29 20:21:41 2013 @@ -1,4 +1,4 @@ -/* $NetBSD: am335x_prcm.h,v 1.3 2013/06/28 02:31:16 matt Exp $ */ +/* $NetBSD: am335x_prcm.h,v 1.4 2013/06/29 20:21:41 matt Exp $ */ /* * TI OMAP Power, Reset, and Clock Management on the AM335x @@ -73,6 +73,10 @@ struct omap_module { #define AM335X_PRCM_CM_CLKMODE_DPLL_MN_BYP_MODE 4 #define AM335X_PRCM_CM_CLKMODE_DPLL_LOCK_MODE 7 #define AM335X_PRCM_CM_DIV_M2_DPLL_MPU 0xa8 +#define AM335X_PRCM_CM_DIV_M2_DPLL_ST_DPLL_CLKOUT __BIT(9) +#define AM335X_PRCM_CM_DIV_M2_DPLL_CLKOUT_GATE_CTRL __BIT(8) +#define AM335X_PRCM_CM_DIV_M2_DPLL_CLKOUT_DIVCHACK __BIT(5) +#define AM335X_PRCM_CM_DIV_M2_DPLL_CLKOUT_DIV __BITS(4,0) #define PRM_RSTCTRL 0x00 /* offset from AM335X_PRCM_PRM_DEVICE */