pxa3xx-cpufreq.c (6634B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 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");