236 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (C) 2008 Marvell International Ltd.4 */5 6#include <linux/kernel.h>7#include <linux/module.h>8#include <linux/sched.h>9#include <linux/init.h>10#include <linux/cpufreq.h>11#include <linux/soc/pxa/cpu.h>12#include <linux/clk/pxa.h>13#include <linux/slab.h>14#include <linux/io.h>15 16#define HSS_104M (0)17#define HSS_156M (1)18#define HSS_208M (2)19#define HSS_312M (3)20 21#define SMCFS_78M (0)22#define SMCFS_104M (2)23#define SMCFS_208M (5)24 25#define SFLFS_104M (0)26#define SFLFS_156M (1)27#define SFLFS_208M (2)28#define SFLFS_312M (3)29 30#define XSPCLK_156M (0)31#define XSPCLK_NONE (3)32 33#define DMCFS_26M (0)34#define DMCFS_260M (3)35 36#define ACCR_XPDIS (1 << 31) /* Core PLL Output Disable */37#define ACCR_SPDIS (1 << 30) /* System PLL Output Disable */38#define ACCR_D0CS (1 << 26) /* D0 Mode Clock Select */39#define ACCR_PCCE (1 << 11) /* Power Mode Change Clock Enable */40#define ACCR_DDR_D0CS (1 << 7) /* DDR SDRAM clock frequency in D0CS (PXA31x only) */41 42#define ACCR_SMCFS_MASK (0x7 << 23) /* Static Memory Controller Frequency Select */43#define ACCR_SFLFS_MASK (0x3 << 18) /* Frequency Select for Internal Memory Controller */44#define ACCR_XSPCLK_MASK (0x3 << 16) /* Core Frequency during Frequency Change */45#define ACCR_HSS_MASK (0x3 << 14) /* System Bus-Clock Frequency Select */46#define ACCR_DMCFS_MASK (0x3 << 12) /* Dynamic Memory Controller Clock Frequency Select */47#define ACCR_XN_MASK (0x7 << 8) /* Core PLL Turbo-Mode-to-Run-Mode Ratio */48#define ACCR_XL_MASK (0x1f) /* Core PLL Run-Mode-to-Oscillator Ratio */49 50#define ACCR_SMCFS(x) (((x) & 0x7) << 23)51#define ACCR_SFLFS(x) (((x) & 0x3) << 18)52#define ACCR_XSPCLK(x) (((x) & 0x3) << 16)53#define ACCR_HSS(x) (((x) & 0x3) << 14)54#define ACCR_DMCFS(x) (((x) & 0x3) << 12)55#define ACCR_XN(x) (((x) & 0x7) << 8)56#define ACCR_XL(x) ((x) & 0x1f)57 58struct pxa3xx_freq_info {59 unsigned int cpufreq_mhz;60 unsigned int core_xl : 5;61 unsigned int core_xn : 3;62 unsigned int hss : 2;63 unsigned int dmcfs : 2;64 unsigned int smcfs : 3;65 unsigned int sflfs : 2;66 unsigned int df_clkdiv : 3;67 68 int vcc_core; /* in mV */69 int vcc_sram; /* in mV */70};71 72#define OP(cpufreq, _xl, _xn, _hss, _dmc, _smc, _sfl, _dfi, vcore, vsram) \73{ \74 .cpufreq_mhz = cpufreq, \75 .core_xl = _xl, \76 .core_xn = _xn, \77 .hss = HSS_##_hss##M, \78 .dmcfs = DMCFS_##_dmc##M, \79 .smcfs = SMCFS_##_smc##M, \80 .sflfs = SFLFS_##_sfl##M, \81 .df_clkdiv = _dfi, \82 .vcc_core = vcore, \83 .vcc_sram = vsram, \84}85 86static struct pxa3xx_freq_info pxa300_freqs[] = {87 /* CPU XL XN HSS DMEM SMEM SRAM DFI VCC_CORE VCC_SRAM */88 OP(104, 8, 1, 104, 260, 78, 104, 3, 1000, 1100), /* 104MHz */89 OP(208, 16, 1, 104, 260, 104, 156, 2, 1000, 1100), /* 208MHz */90 OP(416, 16, 2, 156, 260, 104, 208, 2, 1100, 1200), /* 416MHz */91 OP(624, 24, 2, 208, 260, 208, 312, 3, 1375, 1400), /* 624MHz */92};93 94static struct pxa3xx_freq_info pxa320_freqs[] = {95 /* CPU XL XN HSS DMEM SMEM SRAM DFI VCC_CORE VCC_SRAM */96 OP(104, 8, 1, 104, 260, 78, 104, 3, 1000, 1100), /* 104MHz */97 OP(208, 16, 1, 104, 260, 104, 156, 2, 1000, 1100), /* 208MHz */98 OP(416, 16, 2, 156, 260, 104, 208, 2, 1100, 1200), /* 416MHz */99 OP(624, 24, 2, 208, 260, 208, 312, 3, 1375, 1400), /* 624MHz */100 OP(806, 31, 2, 208, 260, 208, 312, 3, 1400, 1400), /* 806MHz */101};102 103static unsigned int pxa3xx_freqs_num;104static struct pxa3xx_freq_info *pxa3xx_freqs;105static struct cpufreq_frequency_table *pxa3xx_freqs_table;106 107static int setup_freqs_table(struct cpufreq_policy *policy,108 struct pxa3xx_freq_info *freqs, int num)109{110 struct cpufreq_frequency_table *table;111 int i;112 113 table = kcalloc(num + 1, sizeof(*table), GFP_KERNEL);114 if (table == NULL)115 return -ENOMEM;116 117 for (i = 0; i < num; i++) {118 table[i].driver_data = i;119 table[i].frequency = freqs[i].cpufreq_mhz * 1000;120 }121 table[num].driver_data = i;122 table[num].frequency = CPUFREQ_TABLE_END;123 124 pxa3xx_freqs = freqs;125 pxa3xx_freqs_num = num;126 pxa3xx_freqs_table = table;127 128 policy->freq_table = table;129 130 return 0;131}132 133static void __update_core_freq(struct pxa3xx_freq_info *info)134{135 u32 mask, disable, enable, xclkcfg;136 137 mask = ACCR_XN_MASK | ACCR_XL_MASK;138 disable = mask | ACCR_XSPCLK_MASK;139 enable = ACCR_XN(info->core_xn) | ACCR_XL(info->core_xl);140 /* No clock until core PLL is re-locked */141 enable |= ACCR_XSPCLK(XSPCLK_NONE);142 xclkcfg = (info->core_xn == 2) ? 0x3 : 0x2; /* turbo bit */143 144 pxa3xx_clk_update_accr(disable, enable, xclkcfg, mask);145}146 147static void __update_bus_freq(struct pxa3xx_freq_info *info)148{149 u32 mask, disable, enable;150 151 mask = ACCR_SMCFS_MASK | ACCR_SFLFS_MASK | ACCR_HSS_MASK |152 ACCR_DMCFS_MASK;153 disable = mask;154 enable = ACCR_SMCFS(info->smcfs) | ACCR_SFLFS(info->sflfs) |155 ACCR_HSS(info->hss) | ACCR_DMCFS(info->dmcfs);156 157 pxa3xx_clk_update_accr(disable, enable, 0, mask);158}159 160static unsigned int pxa3xx_cpufreq_get(unsigned int cpu)161{162 return pxa3xx_get_clk_frequency_khz(0);163}164 165static int pxa3xx_cpufreq_set(struct cpufreq_policy *policy, unsigned int index)166{167 struct pxa3xx_freq_info *next;168 unsigned long flags;169 170 if (policy->cpu != 0)171 return -EINVAL;172 173 next = &pxa3xx_freqs[index];174 175 local_irq_save(flags);176 __update_core_freq(next);177 __update_bus_freq(next);178 local_irq_restore(flags);179 180 return 0;181}182 183static int pxa3xx_cpufreq_init(struct cpufreq_policy *policy)184{185 int ret = -EINVAL;186 187 /* set default policy and cpuinfo */188 policy->min = policy->cpuinfo.min_freq = 104000;189 policy->max = policy->cpuinfo.max_freq =190 (cpu_is_pxa320()) ? 806000 : 624000;191 policy->cpuinfo.transition_latency = 1000; /* FIXME: 1 ms, assumed */192 193 if (cpu_is_pxa300() || cpu_is_pxa310())194 ret = setup_freqs_table(policy, pxa300_freqs,195 ARRAY_SIZE(pxa300_freqs));196 197 if (cpu_is_pxa320())198 ret = setup_freqs_table(policy, pxa320_freqs,199 ARRAY_SIZE(pxa320_freqs));200 201 if (ret) {202 pr_err("failed to setup frequency table\n");203 return ret;204 }205 206 pr_info("CPUFREQ support for PXA3xx initialized\n");207 return 0;208}209 210static struct cpufreq_driver pxa3xx_cpufreq_driver = {211 .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK,212 .verify = cpufreq_generic_frequency_table_verify,213 .target_index = pxa3xx_cpufreq_set,214 .init = pxa3xx_cpufreq_init,215 .get = pxa3xx_cpufreq_get,216 .name = "pxa3xx-cpufreq",217};218 219static int __init cpufreq_init(void)220{221 if (cpu_is_pxa3xx())222 return cpufreq_register_driver(&pxa3xx_cpufreq_driver);223 224 return 0;225}226module_init(cpufreq_init);227 228static void __exit cpufreq_exit(void)229{230 cpufreq_unregister_driver(&pxa3xx_cpufreq_driver);231}232module_exit(cpufreq_exit);233 234MODULE_DESCRIPTION("CPU frequency scaling driver for PXA3xx");235MODULE_LICENSE("GPL");236