linux/drivers/cpufreq/imx6q-cpufreq.c
<<
0 0
0 0 Prefs 0
0 0
0
   1/*
   2 * Copyright (C) 2013 Freescale Semiconductor, Inc.
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License version 2 as
   6 * published by the Free Software Foundation.
   7 */
   80   9#include <linux/clk.h>0  10#include <linux/cpu.h>0  11#include <linux/cpufreq.h>0  12#include <linux/delay.h>0  13#include <linux/err.h>0  14#include <linux/module.h>0  15#include <linux/of.h>0  16#include <linux/opp.h>0  17#include <linux/platform_device.h>0  18#include <linux/regulator/consumer.h>0  190  20#define PU_SOC_VOLTAGE_NORMAL   12500000  21#define PU_SOC_VOLTAGE_HIGH     12750000  22#define FREQ_1P2_GHZ            12000000000  230  24static struct regulator *arm_reg;0  25static struct regulator *pu_reg;0  26static struct regulator *soc_reg;0  270  28static struct clk *arm_clk;0  29static struct clk *pll1_sys_clk;0  30static struct clk *pll1_sw_clk;0  31static struct clk *step_clk;0  32static struct clk *pll2_pfd2_396m_clk;0  330  34static struct device *cpu_dev;0  35static struct cpufreq_frequency_table *freq_table;0  36static unsigned int transition_latency;0  370  38static int imx6q_verify_speed(struct cpufreq_policy *policy)0  39{
  40        return cpufreq_frequency_table_verify(policy, freq_table);0  41}0  420  43static unsigned int imx6q_get_speed(unsigned int cpu)0  44{
  45        return clk_get_rate(arm_clk) / 1000;0  46}0  470  48static int imx6q_set_target(struct cpufreq_policy *policy,0  49                            unsigned int target_freq, unsigned int relation)0  50{
  51        struct cpufreq_freqs freqs;0  52        struct opp *opp;0  53        unsigned long freq_hz, volt, volt_old;0  54        unsigned int index;0  55        int ret;0  560  57        ret = cpufreq_frequency_table_target(policy, freq_table, target_freq,0  58                                             relation, &index);0  59        if (ret) {
  60                dev_err(cpu_dev, "failed to match target frequency %d: %d\n",0  61                        target_freq, ret);0  62                return ret;0  63        }0  640  65        freqs.new = freq_table[index].frequency;0  66        freq_hz = freqs.new * 1000;0  67        freqs.old = clk_get_rate(arm_clk) / 1000;0  680  69        if (freqs.old == freqs.new)0  70                return 0;0  710  72        rcu_read_lock();0  73        opp = opp_find_freq_ceil(cpu_dev, &freq_hz);0  74        if (IS_ERR(opp)) {
  75                rcu_read_unlock();0  76                dev_err(cpu_dev, "failed to find OPP for %ld\n", freq_hz);0  77                return PTR_ERR(opp);0  78        }0  790  80        volt = opp_get_voltage(opp);0  81        rcu_read_unlock();0  82        volt_old = regulator_get_voltage(arm_reg);0  830  84        dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n",0  85                freqs.old / 1000, volt_old / 1000,0  86                freqs.new / 1000, volt / 1000);0  870  88        cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);0  890  90        /* scaling up?  scale voltage before frequency */
  91        if (freqs.new > freqs.old) {
  92                ret = regulator_set_voltage_tol(arm_reg, volt, 0);0  93                if (ret) {
  94                        dev_err(cpu_dev,
  95                                "failed to scale vddarm up: %d\n", ret);0  96                        freqs.new = freqs.old;0  97                        goto post_notify;0  98                }0  990 100                /*
 101                 * Need to increase vddpu and vddsoc for safety
 102                 * if we are about to run at 1.2 GHz.
 103                 */
 104                if (freqs.new == FREQ_1P2_GHZ / 1000) {
 105                        regulator_set_voltage_tol(pu_reg,
 106                                        PU_SOC_VOLTAGE_HIGH, 0);0 107                        regulator_set_voltage_tol(soc_reg,
 108                                        PU_SOC_VOLTAGE_HIGH, 0);0 109                }0 110        }0 1110 112        /*
 113         * The setpoints are selected per PLL/PDF frequencies, so we need to
 114         * reprogram PLL for frequency scaling.  The procedure of reprogramming
 115         * PLL1 is as below.
 116         *
 117         *  - Enable pll2_pfd2_396m_clk and reparent pll1_sw_clk to it
 118         *  - Reprogram pll1_sys_clk and reparent pll1_sw_clk back to it
 119         *  - Disable pll2_pfd2_396m_clk
 120         */
 121        clk_set_parent(step_clk, pll2_pfd2_396m_clk);0 122        clk_set_parent(pll1_sw_clk, step_clk);0 123        if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk)) {
 124                clk_set_rate(pll1_sys_clk, freqs.new * 1000);0 125                clk_set_parent(pll1_sw_clk, pll1_sys_clk);0 126        }0 1270 128        /* Ensure the arm clock divider is what we expect */
 129        ret = clk_set_rate(arm_clk, freqs.new * 1000);0 130        if (ret) {
 131                dev_err(cpu_dev, "failed to set clock rate: %d\n", ret);0 132                regulator_set_voltage_tol(arm_reg, volt_old, 0);0 133                freqs.new = freqs.old;0 134                goto post_notify;0 135        }0 1360 137        /* scaling down?  scale voltage after frequency */
 138        if (freqs.new < freqs.old) {
 139                ret = regulator_set_voltage_tol(arm_reg, volt, 0);0 140                if (ret) {
 141                        dev_warn(cpu_dev,
 142                                 "failed to scale vddarm down: %d\n", ret);0 143                        ret = 0;0 144                }0 1450 146                if (freqs.old == FREQ_1P2_GHZ / 1000) {
 147                        regulator_set_voltage_tol(pu_reg,
 148                                        PU_SOC_VOLTAGE_NORMAL, 0);0 149                        regulator_set_voltage_tol(soc_reg,
 150                                        PU_SOC_VOLTAGE_NORMAL, 0);0 151                }0 152        }0 1530 154post_notify:0 155        cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);0 1560 157        return ret;0 158}0 1590 160static int imx6q_cpufreq_init(struct cpufreq_policy *policy)0 161{
 162        int ret;0 1630 164        ret = cpufreq_frequency_table_cpuinfo(policy, freq_table);0 165        if (ret) {
 166                dev_err(cpu_dev, "invalid frequency table: %d\n", ret);0 167                return ret;0 168        }0 1690 170        policy->cpuinfo.transition_latency = transition_latency;0 171        policy->cur = clk_get_rate(arm_clk) / 1000;0 172        cpumask_setall(policy->cpus);0 173        cpufreq_frequency_table_get_attr(freq_table, policy->cpu);0 1740 175        return 0;0 176}0 1770 178static int imx6q_cpufreq_exit(struct cpufreq_policy *policy)0 179{
 180        cpufreq_frequency_table_put_attr(policy->cpu);0 181        return 0;0 182}0 1830 184static struct freq_attr *imx6q_cpufreq_attr[] = {
 185        &cpufreq_freq_attr_scaling_available_freqs,
 186        NULL,
 187};0 1880 189static struct cpufreq_driver imx6q_cpufreq_driver = {
 190        .verify = imx6q_verify_speed,
 191        .target = imx6q_set_target,
 192        .get = imx6q_get_speed,
 193        .init = imx6q_cpufreq_init,
 194        .exit = imx6q_cpufreq_exit,
 195        .name = "imx6q-cpufreq",0 196        .attr = imx6q_cpufreq_attr,0 197};0 1980 199static int imx6q_cpufreq_probe(struct platform_device *pdev)0 200{
 201        struct device_node *np;0 202        struct opp *opp;0 203        unsigned long min_volt, max_volt;0 204        int num, pu_reg,
 196="srv_err" ass="sref">imx6q_c="srv_err" ass PU_S2SOC_VOLTA2E_HIGH, 0);0 165        if (soc_reg,
 142 ss="f="0 r" assu_dev, PU_S2S9ass="sr2fL198"> 1980num,  210        }0 1110  80f201f201 166                f201f201policy->/*
 165        if (  76                dev_err(PU_S2e of repr2gramming
num, 
 2       *
  80  76                dev_err(PU_S2e9ass="sr2ck to it
pll1_sname="L80">  80  76                dev_err(, PU_S2pll2_pfd22396m_clk
clk_sename="L80">  80  76                dev_err(, PU_S2p"L110"> 2      */
  80  76                dev_err(, PU_S2pne" name2_396m_clk);0clk_get_rate(  80  76                dev_err(clk_get_radev, PU_S2plass="co2>step_clk);0  74     ef="+code=clk_get_rate" class="sref||me="L80">  80  74     ref="+code=pll1_sw_clk" class="sref">pll1_swf||me="L80">  80  74     ref="+clk_set_parent" class="sref">clk_sewf||de=PU_SOC_VOLTAGE_NORMAL" class="sref">PU_S2pes, so w296m_clk)) {
  80  74     ref="+code=pll1_sw_clk" class="sref"f||me="L80">  80  74     ref"+code=clk_get_rate" class="sref">clk_get_rate(2s="sref">2ew * 1000);0  76                dev_err(, PU_S2"sref">pl21_sys_clk);0num,  226        }0num,  1270
2ew * 1000);0regulatorname="L80">  80volt_oldvolt_old  76                dev_err(PU_S2" class="2ref">ret) {
regulatname="L80">  80volt_oldvolt_old  76                dev_err(, PU_S2"ne" name2sref">ret);0regulatorname="L80">  80volt_oldvolt_old  76                dev_err(PU_S2"lass="co2lt_old, 0);0  74     ef="t_voltage" class="sref">regulaf||me="L80">  80  74     rtage_tol" class="sref">regulataf||me="L80">  80  74     ltage_tol" class="sref">regulatora href="+code=pll2_pfd2_396m_clk" class="sref">2ld" class2"sref">old;0  76                dev_err(volt_osu_dev, PU_S2s="sref">2ost_notify;0num,  235        }0num,  1360
old) {
/* scaling down?  scale voltage2lass="sre2">volt, 0);0  80       >   couline" name="L125">       >   couli>  76                PU_S2" class="2ref">ret) {
 == 2class="sr2f">cpu_dev,
PU_S2"lass="co2sref">ret);0  76                dev_err(cpu_dev, "invalid frequency table: %d\n", ret = 0;0num,  1450   statilass="sref">cpufreq_>   statilass=>  76                ((policy, pu_reg,
 165        if (  76                dev_err(cpu_dev, "invalid frequency table: %d\n", soc_reg,
num,  2              }0retf2c ipertyeguad_usr>  76           ref="+code=device_node"s="sref">dev_err(transition_latency = <)sref">platform_device * 1530cpuinfo.num,  112         1560 of name="Llass    12" class="line" name="L112"> 112        ret;0ialise=cpuom1 clais theineo namortde=in the12" class="line" name="L112"> 112         158}0name="L115"> 115         2ine" name2"L159"> 1590 120policy)0  76able: %d\n",  161{
   _dev+code=exacine" name="L125">   _dev+code=exaci>  76                , ret;0.truhref="+code=politruhcy table: %d\n",  1630 203   name="L80">  80                76           L202" class="line" name="able: %d\n",    _dev+code=exacine" name="L125">   _dev+code=exaci>  76                , ret) {
.truhref="+code=politruhcy table: %d\n", ret);0  80                76           L202" class="line" name="able: %d\n", ret;0  76able: %d\n",  129<                74     ef="t_voltage" class="sref">regul     unsigned longass="line" name="L203"> 203        unsigned long  1690 123<0sref">platform_device *transit2on_latency;0cpuinfo. 129<  "L130" class="line" nam>*>clk_get_rate(arm_2lk) / 1000;0cpus);0 1   soc uinfo 120cpu);0(.freqs.old == 2ine" name2"L174"> 1740 129<                74     ltage_tol" class="sref">regulatoss="line" name="L150"> 150                                        2iCPUFREQ_2      return 0;0,  176}0 123<0sref">platform_device * 1770cpuinfo. 129<  "L130" class="line" nam>*>clk_get_rate(policy)0 139                  74     ltage_tol" class="sref">regulator_ss="line" name="L150"> 150                                        2ne" name=2L179"> 179{
, cpu);0 123<0sref">platform_device *cpuinfo. 129<  "L130" class="line" nam>*>clk_get_rate( 182}0 1830 164     gulisterclass="line" name="L189"> 189+code=cpufreq_driver" class="sref">cpufreq_driver ,  165        if (NULL,
  76                dev_err(cpu_dev, "invalid frequency table: %d\n",  187};0((num,  1880 = {
,
f201f201  76           ref="+code=device_node"able: %d\n", imx6q2set_target,
imx62_get_speed,
imx6q_c2ufreq_init,
(( 154imx6q_c2ufreq_exit,
statilass="sref">cpufreq_>   cy"li/a>statilass=>  76                ((policy, ,0 154,0f201  76           ref="+code=device_node"able: %d\n",  197};0"invalid frequency tble: %d\n",  1980pdev)0 200{
  76ref="+code=imx6q_cpufreq_probe" class="sref">imx6q_cpufreq_probe(struct platform_device *np;0 165        if (opp;0 189+code=cpufreq_driver" class="sref">cpufreq_driver , max_volt;0statilass="sref">cpufreq_>   cy"li/a>statilass=>  76                ((policy, {
3a href0 class="s2a href=3+code3min_volt" f="+code=cpuinf        pu_reg,
, 0);0 197};0 1980pufreq_prorivercpufr_transition+code=cpufreq_pufrdra href="+code=de+code=cpufreq_pufrdraine" na"L165"> 165        if (orivercpufrna"L165"> 165        if (        }0 195        .name = "i3ine" name3"L111"> 1110            wner" class="sref"> wnercpufrename="L164"> 164THIS_MODULEhref= 3class="co3ment">/*
3cass="sre3 need to
           s="line" name="L199"c int  196        . 199static int 3c00{
3gramming
           remov/d="L192" class=remov/>  76q-cpufree="L196"> 196        .  7= 3cclass="s3s below.
 3       *
godu=cpuufreq_proriver>  76           +code=cpufreq_pufrdra href="+code=de+code=cpufreq_pufrdraine"f">policy, 

           MODULE_AUTHOL74" class="lineMODULE_AUTHOL>  76 195        ., PU_S3pll2_pfd23396m_clk
           MODULE_DESCRIPTION74" class="lineMODULE_DESCRIPTION>  76 195        .PU_S3pe" name=3      */
           MODULE_LICENSE" class="sref">MODULE_LICENSE>  76 195        ., PU_S3pne" name3_396m_clk);0


Thr origanal LXR software=by thr e=PU_SOC_http://sourcneo ge.net/projects/lxr">LXR 137"unitfrequenthis ri" idal TAGEion=by e=PU_SOC_mailto:lxr@panux.no">lxr@panux.norequ.
lxr.panux.no kindly hostde=by e=PU_SOC_http://www.redpill-panpro.no">Redpill Lanpro ASrequenprovi8"> of Lanux 13nsultlass"> 1iperaf">cs sere