Module Name: src Committed By: bouyer Date: Sun Jul 20 23:08:43 UTC 2014
Modified Files: src/sys/arch/arm/omap: am335x_prcm.c am335x_prcm.h omap2_reg.h src/sys/arch/evbarm/beagle: beagle_machdep.c Log Message: am335x: expect the board code to provide a set_mpu_volt() function, to change the MPU code voltage. When changing MPU frequency also request a voltage change. provide frequency/voltage tables for the "blank" revision and de A revision, based on documents from www.ti.com (this means it's not possible anymore to request a beaglebone white to run at 1Ghz, but this was not working anyway). beagle_machdep.c: callback to the tps65217pmic to change the MPU voltage. Tested on beaglebone, from 275 to 720Mhz, and on beaglebone black from 300 to 1000Mhz. To generate a diff of this commit: cvs rdiff -u -r1.6 -r1.7 src/sys/arch/arm/omap/am335x_prcm.c cvs rdiff -u -r1.7 -r1.8 src/sys/arch/arm/omap/am335x_prcm.h cvs rdiff -u -r1.27 -r1.28 src/sys/arch/arm/omap/omap2_reg.h cvs rdiff -u -r1.58 -r1.59 src/sys/arch/evbarm/beagle/beagle_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/omap/am335x_prcm.c diff -u src/sys/arch/arm/omap/am335x_prcm.c:1.6 src/sys/arch/arm/omap/am335x_prcm.c:1.7 --- src/sys/arch/arm/omap/am335x_prcm.c:1.6 Sat Aug 17 00:40:10 2013 +++ src/sys/arch/arm/omap/am335x_prcm.c Sun Jul 20 23:08:43 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: am335x_prcm.c,v 1.6 2013/08/17 00:40:10 matt Exp $ */ +/* $NetBSD: am335x_prcm.c,v 1.7 2014/07/20 23:08:43 bouyer Exp $ */ /* * TI OMAP Power, Reset, and Clock Management on the AM335x @@ -34,7 +34,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: am335x_prcm.c,v 1.6 2013/08/17 00:40:10 matt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: am335x_prcm.c,v 1.7 2014/07/20 23:08:43 bouyer Exp $"); #include <sys/types.h> #include <sys/param.h> @@ -50,6 +50,8 @@ __KERNEL_RCSID(0, "$NetBSD: am335x_prcm. #define AM335X_CLKCTRL_MODULEMODE_DISABLED 0 #define AM335X_CLKCTRL_MODULEMODE_ENABLE 2 +uint32_t am335x_devid; + static void am335x_prcm_check_clkctrl(bus_size_t cm_module, bus_size_t clkctrl_reg, uint32_t v) @@ -98,19 +100,38 @@ 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 +/* + * MPU frequency and power table, built from informations in + * http://processors.wiki.ti.com/index.php/AM335x_Power_Estimation_Tool + */ + +struct mpu_frequency { + uint16_t freq; /* MPU frequency in Khz */ + uint16_t mvolt; /* MPU voltage in millivolt */ }; -static int mpu_frequency; -void +static const struct mpu_frequency mpu_frequencies_rev0_zcz[] = { + {275, 1100}, + {500, 1100}, + {600, 1200}, + {720, 1260}, + {0, 0}, +}; +static const struct mpu_frequency mpu_frequencies_revA_zcz[] = { + {300, 950}, + {550, 1100}, + {600, 1100}, + {720, 1200}, + {800, 1260}, + {900, 1325}, + {1000, 1325}, + {0, 0}, +}; +static const struct mpu_frequency *mpu_frequencies = NULL; + +static struct mpu_frequency mpu_frequency; + +static void prcm_mpu_pll_config(u_int mpupll_m) { uint32_t clkmode = prcm_read_4(AM335X_PRCM_CM_WKUP, AM335X_PRCM_CM_CLKMODE_DPLL_MPU); @@ -144,12 +165,15 @@ static int mpu_current_frequency_sysctl_helper(SYSCTLFN_ARGS) { struct sysctlnode node = *rnode; - int freq = mpu_frequency; + int freq = mpu_frequency.freq; int old_freq = freq; + int old_mvolt = mpu_frequency.mvolt; + struct mpu_frequency new_mpu_frequency; - KASSERTMSG(curcpu()->ci_data.cpu_cc_freq == mpu_frequency * 1000000, + KASSERTMSG( + curcpu()->ci_data.cpu_cc_freq == mpu_frequency.freq * 1000000, "cc_freq %"PRIu64" mpu_freq %u000000", - curcpu()->ci_data.cpu_cc_freq, mpu_frequency); + curcpu()->ci_data.cpu_cc_freq, mpu_frequency.freq); node.sysctl_data = &freq; @@ -158,11 +182,12 @@ mpu_current_frequency_sysctl_helper(SYSC if (error || newp == NULL) return error; - KASSERT(old_freq == mpu_frequency); + KASSERT(old_freq == mpu_frequency.freq); error = EINVAL; - for (size_t i = 0; i < __arraycount(mpu_frequencies); i++) { - if (mpu_frequencies[i] == freq) { + for (size_t i = 0; mpu_frequencies[i].freq > 0; i++) { + if (mpu_frequencies[i].freq == freq) { + new_mpu_frequency = mpu_frequencies[i]; error = 0; break; } @@ -171,11 +196,30 @@ mpu_current_frequency_sysctl_helper(SYSC return EINVAL; if (freq != old_freq) { - const int s = splhigh(); + int s; + if (new_mpu_frequency.mvolt > old_mvolt) { + /* need to raise VMPU before raising freq */ + error = set_mpu_volt(new_mpu_frequency.mvolt); + } + if (error) + return error; + s = splhigh(); prcm_mpu_pll_config(freq); curcpu()->ci_data.cpu_cc_freq = freq * 1000000; - mpu_frequency = freq; + mpu_frequency = new_mpu_frequency; splx(s); + if (mpu_frequency.mvolt < old_mvolt) { + /* need to lower VMPU after lowering freq */ + error = set_mpu_volt(mpu_frequency.mvolt); + if (error) { + /* if we failed to lower VMPU, record it */ + aprint_error_dev(curcpu()->ci_dev, + "warning: failed to change MPU voltage from " + "%d to %d\n", + old_mvolt, mpu_frequency.mvolt); + mpu_frequency.mvolt = old_mvolt; + } + } aprint_normal_dev(curcpu()->ci_dev, "frequency changed from %d MHz to %d MHz\n", old_freq, freq); @@ -188,16 +232,36 @@ mpu_current_frequency_sysctl_helper(SYSC SYSCTL_SETUP(sysctl_am335x_machdep_setup, "sysctl am335x machdep subtree setup") { const struct sysctlnode *freqnode, *node; + int i; + int cc_freq = curcpu()->ci_data.cpu_cc_freq / 1000000; - static char mpu_available_frequencies[__arraycount(mpu_frequencies)*6]; + static char mpu_available_frequencies[__arraycount(mpu_frequencies_revA_zcz)*6]; + char cur_cpu_freq[6]; - __CTASSERT(__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]); - mpu_frequency = curcpu()->ci_data.cpu_cc_freq / 1000000; + if (TI_AM335X_CTLMOD_DEVID_REV(am335x_devid) == 0) + mpu_frequencies = mpu_frequencies_rev0_zcz; + else + mpu_frequencies = mpu_frequencies_revA_zcz; + mpu_available_frequencies[0] = '\0'; + for (i = 0 ; mpu_frequencies[i].freq > 0; i++) { + snprintf(cur_cpu_freq, sizeof(cur_cpu_freq), "%u", + mpu_frequencies[i].freq); + if (i > 0) { + strlcat(mpu_available_frequencies, " ", + sizeof(mpu_available_frequencies)); + } + strlcat(mpu_available_frequencies, cur_cpu_freq, + sizeof(mpu_available_frequencies)); + } + /* locate current freq in array */ + for (i = 0; mpu_frequencies[i].freq > 0; i++) { + if (mpu_frequencies[i].freq >= cc_freq) { + mpu_frequency = mpu_frequencies[i]; + mpu_frequency.freq = cc_freq; + break; + } + } + KASSERT(mpu_frequency.mvolt > 0); sysctl_createv(clog, 0, NULL, &node, CTLFLAG_PERMANENT, @@ -234,6 +298,8 @@ am335x_sys_clk(bus_space_handle_t ctlmod const uint32_t control_status = bus_space_read_4(&omap_bs_tag, ctlmode_ioh, CTLMOD_CONTROL_STATUS); omap_sys_clk = sys_clks[__SHIFTOUT(control_status, CTLMOD_CONTROL_STATUS_SYSBOOT1)]; + + am335x_devid = bus_space_read_4(&omap_bs_tag, ctlmode_ioh, TI_AM335X_CTLMOD_DEVID); } void Index: src/sys/arch/arm/omap/am335x_prcm.h diff -u src/sys/arch/arm/omap/am335x_prcm.h:1.7 src/sys/arch/arm/omap/am335x_prcm.h:1.8 --- src/sys/arch/arm/omap/am335x_prcm.h:1.7 Wed Jul 16 18:24:35 2014 +++ src/sys/arch/arm/omap/am335x_prcm.h Sun Jul 20 23:08:43 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: am335x_prcm.h,v 1.7 2014/07/16 18:24:35 bouyer Exp $ */ +/* $NetBSD: am335x_prcm.h,v 1.8 2014/07/20 23:08:43 bouyer Exp $ */ /* * TI OMAP Power, Reset, and Clock Management on the AM335x @@ -149,7 +149,7 @@ struct omap_module { #define RST_GLOBAL_COLD_SW __BIT(1) #ifdef _KERNEL -void prcm_mpu_pll_config(u_int); +int set_mpu_volt(int); void am335x_sys_clk(bus_space_handle_t); void am335x_cpu_clk(void); #endif Index: src/sys/arch/arm/omap/omap2_reg.h diff -u src/sys/arch/arm/omap/omap2_reg.h:1.27 src/sys/arch/arm/omap/omap2_reg.h:1.28 --- src/sys/arch/arm/omap/omap2_reg.h:1.27 Fri Apr 4 21:33:19 2014 +++ src/sys/arch/arm/omap/omap2_reg.h Sun Jul 20 23:08:43 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: omap2_reg.h,v 1.27 2014/04/04 21:33:19 matt Exp $ */ +/* $NetBSD: omap2_reg.h,v 1.28 2014/07/20 23:08:43 bouyer Exp $ */ /* * Copyright (c) 2007 Microsoft @@ -882,8 +882,11 @@ #ifdef TI_AM335X #define TI_AM335X_CTLMOD_BASE 0x44e10000 -#define CTLMOD_CONTROL_STATUS 0x40 +#define CTLMOD_CONTROL_STATUS 0x0040 #define CTLMOD_CONTROL_STATUS_SYSBOOT1 __BITS(23,22) + +#define TI_AM335X_CTLMOD_DEVID 0x0600 +#define TI_AM335X_CTLMOD_DEVID_REV(x) (((x) >> 28) & 0xf) #endif #if defined(OMAP4) || defined(TI_AM335X) #define EMIF_SDRAM_CONFIG 8 Index: src/sys/arch/evbarm/beagle/beagle_machdep.c diff -u src/sys/arch/evbarm/beagle/beagle_machdep.c:1.58 src/sys/arch/evbarm/beagle/beagle_machdep.c:1.59 --- src/sys/arch/evbarm/beagle/beagle_machdep.c:1.58 Sat Jul 19 18:16:50 2014 +++ src/sys/arch/evbarm/beagle/beagle_machdep.c Sun Jul 20 23:08:43 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: beagle_machdep.c,v 1.58 2014/07/19 18:16:50 bouyer Exp $ */ +/* $NetBSD: beagle_machdep.c,v 1.59 2014/07/20 23:08:43 bouyer Exp $ */ /* * Machine dependent functions for kernel setup for TI OSK5912 board. @@ -125,7 +125,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: beagle_machdep.c,v 1.58 2014/07/19 18:16:50 bouyer Exp $"); +__KERNEL_RCSID(0, "$NetBSD: beagle_machdep.c,v 1.59 2014/07/20 23:08:43 bouyer Exp $"); #include "opt_machdep.h" #include "opt_ddb.h" @@ -189,6 +189,7 @@ __KERNEL_RCSID(0, "$NetBSD: beagle_machd # error no prcm device configured. # endif # include <arm/omap/am335x_prcm.h> +# include <dev/i2c/tps65217pmicvar.h> # if NSDHC > 0 # include <arm/omap/omap2_obiovar.h> # include <arm/omap/omap3_sdmmcreg.h> @@ -238,6 +239,9 @@ int use_fb_console = true; #ifdef CPU_CORTEXA15 uint32_t omap5_cnt_frq; #endif +#if defined(TI_AM335X) +device_t pmic_dev = NULL; +#endif /* * Macros to translate between physical and virtual for a subset of the @@ -1107,4 +1111,17 @@ beagle_device_register(device_t self, vo if (use_fb_console) prop_dictionary_set_bool(dict, "is_console", false); } + if (device_is_a(self, "tps65217pmic")) { + pmic_dev = self; + } +} + +int +set_mpu_volt(int mvolt) +{ + if (pmic_dev == NULL) + return ENODEV; + + /* MPU voltage is on vdcd2 */ + return tps65217pmic_set_volt(pmic_dev, "DCDC2", mvolt); }