From owner-svn-src-all@FreeBSD.ORG Sun May 24 19:00:47 2015 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id BAB888A9; Sun, 24 May 2015 19:00:47 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id A7FF515F9; Sun, 24 May 2015 19:00:47 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id t4OJ0lwS073296; Sun, 24 May 2015 19:00:47 GMT (envelope-from ian@FreeBSD.org) Received: (from ian@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id t4OJ0kJw073292; Sun, 24 May 2015 19:00:46 GMT (envelope-from ian@FreeBSD.org) Message-Id: <201505241900.t4OJ0kJw073292@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: ian set sender to ian@FreeBSD.org using -f From: Ian Lepore Date: Sun, 24 May 2015 19:00:46 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r283501 - stable/10/sys/arm/freescale/imx X-SVN-Group: stable-10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 24 May 2015 19:00:47 -0000 Author: ian Date: Sun May 24 19:00:46 2015 New Revision: 283501 URL: https://svnweb.freebsd.org/changeset/base/283501 Log: MFC r282516: Add the code necessary to run the imx6 chip at its lowest clock/power operating point (396MHz/950mV). Modified: stable/10/sys/arm/freescale/imx/imx6_anatop.c stable/10/sys/arm/freescale/imx/imx6_ccm.c stable/10/sys/arm/freescale/imx/imx6_ccmreg.h stable/10/sys/arm/freescale/imx/imx_ccmvar.h Directory Properties: stable/10/ (props changed) Modified: stable/10/sys/arm/freescale/imx/imx6_anatop.c ============================================================================== --- stable/10/sys/arm/freescale/imx/imx6_anatop.c Sun May 24 18:59:45 2015 (r283500) +++ stable/10/sys/arm/freescale/imx/imx6_anatop.c Sun May 24 19:00:46 2015 (r283501) @@ -72,6 +72,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -117,12 +118,16 @@ static struct imx6_anatop_softc *imx6_an /* * Table of "operating points". * These are combinations of frequency and voltage blessed by Freescale. + * While the datasheet says the ARM voltage can be as low as 925mV at + * 396MHz, it also says that the ARM and SOC voltages can't differ by + * more than 200mV, and the minimum SOC voltage is 1150mV, so that + * dictates the 950mV entry in this table. */ static struct oppt { uint32_t mhz; uint32_t mv; } imx6_oppt_table[] = { -/* { 396, 925}, XXX: need functional ccm code for this speed */ + { 396, 950}, { 792, 1150}, { 852, 1225}, { 996, 1225}, @@ -159,14 +164,15 @@ imx6_anatop_write_4(bus_size_t offset, u static void vdd_set(struct imx6_anatop_softc *sc, int mv) { - int newtarg, oldtarg; + int newtarg, newtargSoc, oldtarg; uint32_t delay, pmureg; static boolean_t init_done = false; /* * The datasheet says VDD_PU and VDD_SOC must be equal, and VDD_ARM - * can't be more than 50mV above or 200mV below them. For now to keep - * things simple we set all three to the same value. + * can't be more than 50mV above or 200mV below them. We keep them the + * same except in the case of the lowest operating point, which is + * handled as a special case below. */ pmureg = imx6_anatop_read_4(IMX6_ANALOG_PMU_REG_CORE); @@ -181,19 +187,29 @@ vdd_set(struct imx6_anatop_softc *sc, in newtarg = (mv - 700) / 25; /* + * The SOC voltage can't go below 1150mV, and thus because of the 200mV + * rule, the ARM voltage can't go below 950mV. The 950 is encoded in + * our oppt table, here we handle the SOC 1150 rule as a special case. + * (1150-700/25=18). + */ + newtargSoc = (newtarg < 18) ? 18 : newtarg; + + /* * The first time through the 3 voltages might not be equal so use a * long conservative delay. After that we need to delay 3uS for every - * 25mV step upward. No need to delay at all when lowering. + * 25mV step upward; we actually delay 6uS because empirically, it works + * and the 3uS per step recommended by the docs doesn't (3uS fails when + * going from 400->1200, but works for smaller changes). */ if (init_done) { if (newtarg == oldtarg) return; else if (newtarg > oldtarg) - delay = (newtarg - oldtarg) * 3; + delay = (newtarg - oldtarg) * 6; else delay = 0; } else { - delay = 700 / 25 * 3; + delay = (700 / 25) * 6; init_done = true; } @@ -206,7 +222,7 @@ vdd_set(struct imx6_anatop_softc *sc, in pmureg |= newtarg << IMX6_ANALOG_PMU_REG0_TARG_SHIFT; pmureg |= newtarg << IMX6_ANALOG_PMU_REG1_TARG_SHIFT; - pmureg |= newtarg << IMX6_ANALOG_PMU_REG2_TARG_SHIFT; + pmureg |= newtargSoc << IMX6_ANALOG_PMU_REG2_TARG_SHIFT; imx6_anatop_write_4(IMX6_ANALOG_PMU_REG_CORE, pmureg); DELAY(delay); @@ -214,24 +230,29 @@ vdd_set(struct imx6_anatop_softc *sc, in } static inline uint32_t -cpufreq_mhz_from_div(struct imx6_anatop_softc *sc, uint32_t div) +cpufreq_mhz_from_div(struct imx6_anatop_softc *sc, uint32_t corediv, + uint32_t plldiv) { - return (sc->refosc_mhz * (div / 2)); + return ((sc->refosc_mhz * (plldiv / 2)) / (corediv + 1)); } -static inline uint32_t -cpufreq_mhz_to_div(struct imx6_anatop_softc *sc, uint32_t cpu_mhz) +static inline void +cpufreq_mhz_to_div(struct imx6_anatop_softc *sc, uint32_t cpu_mhz, + uint32_t *corediv, uint32_t *plldiv) { - return (cpu_mhz / (sc->refosc_mhz / 2)); + *corediv = (cpu_mhz < 650) ? 1 : 0; + *plldiv = ((*corediv + 1) * cpu_mhz) / (sc->refosc_mhz / 2); } static inline uint32_t cpufreq_actual_mhz(struct imx6_anatop_softc *sc, uint32_t cpu_mhz) { + uint32_t corediv, plldiv; - return (cpufreq_mhz_from_div(sc, cpufreq_mhz_to_div(sc, cpu_mhz))); + cpufreq_mhz_to_div(sc, cpu_mhz, &corediv, &plldiv); + return (cpufreq_mhz_from_div(sc, corediv, plldiv)); } static struct oppt * @@ -257,7 +278,7 @@ cpufreq_nearest_oppt(struct imx6_anatop_ static void cpufreq_set_clock(struct imx6_anatop_softc * sc, struct oppt *op) { - uint32_t timeout, wrk32; + uint32_t corediv, plldiv, timeout, wrk32; /* If increasing the frequency, we must first increase the voltage. */ if (op->mhz > sc->cpu_curmhz) { @@ -273,6 +294,7 @@ cpufreq_set_clock(struct imx6_anatop_sof * - Wait for the LOCK bit to come on; it takes ~50 loop iterations. * - Turn off bypass mode; cpu should now be running at the new speed. */ + cpufreq_mhz_to_div(sc, op->mhz, &corediv, &plldiv); imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_ARM_CLR, IMX6_ANALOG_CCM_PLL_ARM_CLK_SRC_MASK); imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_ARM_SET, @@ -280,7 +302,7 @@ cpufreq_set_clock(struct imx6_anatop_sof wrk32 = imx6_anatop_read_4(IMX6_ANALOG_CCM_PLL_ARM); wrk32 &= ~IMX6_ANALOG_CCM_PLL_ARM_DIV_MASK; - wrk32 |= cpufreq_mhz_to_div(sc, op->mhz); + wrk32 |= plldiv; imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_ARM, wrk32); timeout = 10000; @@ -291,6 +313,7 @@ cpufreq_set_clock(struct imx6_anatop_sof imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_ARM_CLR, IMX6_ANALOG_CCM_PLL_ARM_BYPASS); + imx_ccm_set_cacrr(corediv); /* If lowering the frequency, it is now safe to lower the voltage. */ if (op->mhz < sc->cpu_curmhz) @@ -298,7 +321,7 @@ cpufreq_set_clock(struct imx6_anatop_sof sc->cpu_curmhz = op->mhz; /* Tell the mpcore timer that its frequency has changed. */ - arm_tmr_change_frequency( + arm_tmr_change_frequency( cpufreq_actual_mhz(sc, sc->cpu_curmhz) * 1000000 / 2); } @@ -752,11 +775,12 @@ imx6_anatop_probe(device_t dev) uint32_t imx6_get_cpu_clock() { - uint32_t div; + uint32_t corediv, plldiv; - div = imx6_anatop_read_4(IMX6_ANALOG_CCM_PLL_ARM) & + corediv = imx_ccm_get_cacrr(); + plldiv = imx6_anatop_read_4(IMX6_ANALOG_CCM_PLL_ARM) & IMX6_ANALOG_CCM_PLL_ARM_DIV_MASK; - return (cpufreq_mhz_from_div(imx6_anatop_sc, div)); + return (cpufreq_mhz_from_div(imx6_anatop_sc, corediv, plldiv)); } static device_method_t imx6_anatop_methods[] = { Modified: stable/10/sys/arm/freescale/imx/imx6_ccm.c ============================================================================== --- stable/10/sys/arm/freescale/imx/imx6_ccm.c Sun May 24 18:59:45 2015 (r283500) +++ stable/10/sys/arm/freescale/imx/imx6_ccm.c Sun May 24 19:00:46 2015 (r283501) @@ -320,6 +320,20 @@ imx_ccm_ahb_hz(void) return (132000000); } +uint32_t +imx_ccm_get_cacrr(void) +{ + + return (RD4(ccm_sc, CCM_CACCR)); +} + +void +imx_ccm_set_cacrr(uint32_t divisor) +{ + + WR4(ccm_sc, CCM_CACCR, divisor); +} + static device_method_t ccm_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ccm_probe), Modified: stable/10/sys/arm/freescale/imx/imx6_ccmreg.h ============================================================================== --- stable/10/sys/arm/freescale/imx/imx6_ccmreg.h Sun May 24 18:59:45 2015 (r283500) +++ stable/10/sys/arm/freescale/imx/imx6_ccmreg.h Sun May 24 19:00:46 2015 (r283501) @@ -29,6 +29,7 @@ #ifndef IMX6_CCMREG_H #define IMX6_CCMREG_H +#define CCM_CACCR 0x010 #define CCM_CSCMR1 0x01C #define SSI1_CLK_SEL_S 10 #define SSI2_CLK_SEL_S 12 @@ -64,6 +65,5 @@ #define CCM_CCGR5 0x07C #define CCM_CCGR6 0x080 #define CCM_CMEOR 0x088 - #endif Modified: stable/10/sys/arm/freescale/imx/imx_ccmvar.h ============================================================================== --- stable/10/sys/arm/freescale/imx/imx_ccmvar.h Sun May 24 18:59:45 2015 (r283500) +++ stable/10/sys/arm/freescale/imx/imx_ccmvar.h Sun May 24 19:00:46 2015 (r283501) @@ -53,4 +53,8 @@ void imx_ccm_usb_enable(device_t _usbdev void imx_ccm_usbphy_enable(device_t _phydev); void imx_ccm_ssi_configure(device_t _ssidev); +/* Routines to get and set the arm clock root divisor register. */ +uint32_t imx_ccm_get_cacrr(void); +void imx_ccm_set_cacrr(uint32_t _divisor); + #endif