Blame view

drivers/cpufreq/pxa3xx-cpufreq.c 5.66 KB
4f788bb20   Eric Miao   [ARM] pxa: add pr...
1
  /*
4f788bb20   Eric Miao   [ARM] pxa: add pr...
2
3
4
5
6
7
8
9
10
11
12
13
14
   * Copyright (C) 2008 Marvell International Ltd.
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   */
  
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/sched.h>
  #include <linux/init.h>
  #include <linux/cpufreq.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
15
  #include <linux/slab.h>
23019a733   Rob Herring   ARM: pxa: use com...
16
  #include <linux/io.h>
4f788bb20   Eric Miao   [ARM] pxa: add pr...
17

adde904b4   Viresh Kumar   cpufreq: pxa3xx: ...
18
  #include <mach/generic.h>
4f788bb20   Eric Miao   [ARM] pxa: add pr...
19
  #include <mach/pxa3xx-regs.h>
4f788bb20   Eric Miao   [ARM] pxa: add pr...
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
  #define HSS_104M	(0)
  #define HSS_156M	(1)
  #define HSS_208M	(2)
  #define HSS_312M	(3)
  
  #define SMCFS_78M	(0)
  #define SMCFS_104M	(2)
  #define SMCFS_208M	(5)
  
  #define SFLFS_104M	(0)
  #define SFLFS_156M	(1)
  #define SFLFS_208M	(2)
  #define SFLFS_312M	(3)
  
  #define XSPCLK_156M	(0)
  #define XSPCLK_NONE	(3)
  
  #define DMCFS_26M	(0)
  #define DMCFS_260M	(3)
  
  struct pxa3xx_freq_info {
  	unsigned int cpufreq_mhz;
  	unsigned int core_xl : 5;
  	unsigned int core_xn : 3;
  	unsigned int hss : 2;
  	unsigned int dmcfs : 2;
  	unsigned int smcfs : 3;
  	unsigned int sflfs : 2;
  	unsigned int df_clkdiv : 3;
  
  	int	vcc_core;	/* in mV */
  	int	vcc_sram;	/* in mV */
  };
  
  #define OP(cpufreq, _xl, _xn, _hss, _dmc, _smc, _sfl, _dfi, vcore, vsram) \
  {									\
  	.cpufreq_mhz	= cpufreq,					\
  	.core_xl	= _xl,						\
  	.core_xn	= _xn,						\
  	.hss		= HSS_##_hss##M,				\
  	.dmcfs		= DMCFS_##_dmc##M,				\
  	.smcfs		= SMCFS_##_smc##M,				\
  	.sflfs		= SFLFS_##_sfl##M,				\
  	.df_clkdiv	= _dfi,						\
  	.vcc_core	= vcore,					\
  	.vcc_sram	= vsram,					\
  }
  
  static struct pxa3xx_freq_info pxa300_freqs[] = {
  	/*  CPU XL XN  HSS DMEM SMEM SRAM DFI VCC_CORE VCC_SRAM */
  	OP(104,  8, 1, 104, 260,  78, 104, 3, 1000, 1100), /* 104MHz */
  	OP(208, 16, 1, 104, 260, 104, 156, 2, 1000, 1100), /* 208MHz */
  	OP(416, 16, 2, 156, 260, 104, 208, 2, 1100, 1200), /* 416MHz */
  	OP(624, 24, 2, 208, 260, 208, 312, 3, 1375, 1400), /* 624MHz */
  };
  
  static struct pxa3xx_freq_info pxa320_freqs[] = {
  	/*  CPU XL XN  HSS DMEM SMEM SRAM DFI VCC_CORE VCC_SRAM */
  	OP(104,  8, 1, 104, 260,  78, 104, 3, 1000, 1100), /* 104MHz */
  	OP(208, 16, 1, 104, 260, 104, 156, 2, 1000, 1100), /* 208MHz */
  	OP(416, 16, 2, 156, 260, 104, 208, 2, 1100, 1200), /* 416MHz */
  	OP(624, 24, 2, 208, 260, 208, 312, 3, 1375, 1400), /* 624MHz */
  	OP(806, 31, 2, 208, 260, 208, 312, 3, 1400, 1400), /* 806MHz */
  };
  
  static unsigned int pxa3xx_freqs_num;
  static struct pxa3xx_freq_info *pxa3xx_freqs;
  static struct cpufreq_frequency_table *pxa3xx_freqs_table;
  
  static int setup_freqs_table(struct cpufreq_policy *policy,
  			     struct pxa3xx_freq_info *freqs, int num)
  {
  	struct cpufreq_frequency_table *table;
15cc921b9   Viresh Kumar   cpufreq: pxa: use...
93
  	int i;
4f788bb20   Eric Miao   [ARM] pxa: add pr...
94
95
96
97
98
99
  
  	table = kzalloc((num + 1) * sizeof(*table), GFP_KERNEL);
  	if (table == NULL)
  		return -ENOMEM;
  
  	for (i = 0; i < num; i++) {
507015880   Viresh Kumar   cpufreq: rename i...
100
  		table[i].driver_data = i;
4f788bb20   Eric Miao   [ARM] pxa: add pr...
101
102
  		table[i].frequency = freqs[i].cpufreq_mhz * 1000;
  	}
507015880   Viresh Kumar   cpufreq: rename i...
103
  	table[num].driver_data = i;
4f788bb20   Eric Miao   [ARM] pxa: add pr...
104
105
106
107
108
  	table[num].frequency = CPUFREQ_TABLE_END;
  
  	pxa3xx_freqs = freqs;
  	pxa3xx_freqs_num = num;
  	pxa3xx_freqs_table = table;
15cc921b9   Viresh Kumar   cpufreq: pxa: use...
109
  	return cpufreq_table_validate_and_show(policy, table);
4f788bb20   Eric Miao   [ARM] pxa: add pr...
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
  }
  
  static void __update_core_freq(struct pxa3xx_freq_info *info)
  {
  	uint32_t mask = ACCR_XN_MASK | ACCR_XL_MASK;
  	uint32_t accr = ACCR;
  	uint32_t xclkcfg;
  
  	accr &= ~(ACCR_XN_MASK | ACCR_XL_MASK | ACCR_XSPCLK_MASK);
  	accr |= ACCR_XN(info->core_xn) | ACCR_XL(info->core_xl);
  
  	/* No clock until core PLL is re-locked */
  	accr |= ACCR_XSPCLK(XSPCLK_NONE);
  
  	xclkcfg = (info->core_xn == 2) ? 0x3 : 0x2;	/* turbo bit */
  
  	ACCR = accr;
  	__asm__("mcr p14, 0, %0, c6, c0, 0
  " : : "r"(xclkcfg));
  
  	while ((ACSR & mask) != (accr & mask))
  		cpu_relax();
  }
  
  static void __update_bus_freq(struct pxa3xx_freq_info *info)
  {
  	uint32_t mask;
  	uint32_t accr = ACCR;
  
  	mask = ACCR_SMCFS_MASK | ACCR_SFLFS_MASK | ACCR_HSS_MASK |
  		ACCR_DMCFS_MASK;
  
  	accr &= ~mask;
  	accr |= ACCR_SMCFS(info->smcfs) | ACCR_SFLFS(info->sflfs) |
  		ACCR_HSS(info->hss) | ACCR_DMCFS(info->dmcfs);
  
  	ACCR = accr;
  
  	while ((ACSR & mask) != (accr & mask))
  		cpu_relax();
  }
4f788bb20   Eric Miao   [ARM] pxa: add pr...
151
152
  static unsigned int pxa3xx_cpufreq_get(unsigned int cpu)
  {
ecf89b8a9   Haojian Zhuang   ARM: pxa: reduce ...
153
  	return pxa3xx_get_clk_frequency_khz(0);
4f788bb20   Eric Miao   [ARM] pxa: add pr...
154
  }
9c0ebcf78   Viresh Kumar   cpufreq: Implemen...
155
  static int pxa3xx_cpufreq_set(struct cpufreq_policy *policy, unsigned int index)
4f788bb20   Eric Miao   [ARM] pxa: add pr...
156
157
  {
  	struct pxa3xx_freq_info *next;
4f788bb20   Eric Miao   [ARM] pxa: add pr...
158
  	unsigned long flags;
4f788bb20   Eric Miao   [ARM] pxa: add pr...
159
160
161
  
  	if (policy->cpu != 0)
  		return -EINVAL;
9c0ebcf78   Viresh Kumar   cpufreq: Implemen...
162
  	next = &pxa3xx_freqs[index];
4f788bb20   Eric Miao   [ARM] pxa: add pr...
163

4f788bb20   Eric Miao   [ARM] pxa: add pr...
164
165
166
167
  	local_irq_save(flags);
  	__update_core_freq(next);
  	__update_bus_freq(next);
  	local_irq_restore(flags);
4f788bb20   Eric Miao   [ARM] pxa: add pr...
168
169
  	return 0;
  }
50e77fcd7   Eric Miao   ARM: pxa: remove ...
170
  static int pxa3xx_cpufreq_init(struct cpufreq_policy *policy)
4f788bb20   Eric Miao   [ARM] pxa: add pr...
171
172
173
174
  {
  	int ret = -EINVAL;
  
  	/* set default policy and cpuinfo */
200ea8e2c   Viresh Kumar   cpufreq: pxa: don...
175
176
177
  	policy->min = policy->cpuinfo.min_freq = 104000;
  	policy->max = policy->cpuinfo.max_freq =
  		(cpu_is_pxa320()) ? 806000 : 624000;
4f788bb20   Eric Miao   [ARM] pxa: add pr...
178
  	policy->cpuinfo.transition_latency = 1000; /* FIXME: 1 ms, assumed */
4f788bb20   Eric Miao   [ARM] pxa: add pr...
179
180
  
  	if (cpu_is_pxa300() || cpu_is_pxa310())
8ee3f8e03   Julia Lawall   pxa3xx-cpufreq.c:...
181
182
  		ret = setup_freqs_table(policy, pxa300_freqs,
  					ARRAY_SIZE(pxa300_freqs));
4f788bb20   Eric Miao   [ARM] pxa: add pr...
183
184
  
  	if (cpu_is_pxa320())
8ee3f8e03   Julia Lawall   pxa3xx-cpufreq.c:...
185
186
  		ret = setup_freqs_table(policy, pxa320_freqs,
  					ARRAY_SIZE(pxa320_freqs));
4f788bb20   Eric Miao   [ARM] pxa: add pr...
187
188
189
190
191
192
193
194
195
196
197
198
199
  
  	if (ret) {
  		pr_err("failed to setup frequency table
  ");
  		return ret;
  	}
  
  	pr_info("CPUFREQ support for PXA3xx initialized
  ");
  	return 0;
  }
  
  static struct cpufreq_driver pxa3xx_cpufreq_driver = {
ae6b42713   Viresh Kumar   cpufreq: Mark ARM...
200
  	.flags		= CPUFREQ_NEED_INITIAL_FREQ_CHECK,
bf36e48d7   Viresh Kumar   cpufreq: pxa: Use...
201
  	.verify		= cpufreq_generic_frequency_table_verify,
9c0ebcf78   Viresh Kumar   cpufreq: Implemen...
202
  	.target_index	= pxa3xx_cpufreq_set,
4f788bb20   Eric Miao   [ARM] pxa: add pr...
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
  	.init		= pxa3xx_cpufreq_init,
  	.get		= pxa3xx_cpufreq_get,
  	.name		= "pxa3xx-cpufreq",
  };
  
  static int __init cpufreq_init(void)
  {
  	if (cpu_is_pxa3xx())
  		return cpufreq_register_driver(&pxa3xx_cpufreq_driver);
  
  	return 0;
  }
  module_init(cpufreq_init);
  
  static void __exit cpufreq_exit(void)
  {
  	cpufreq_unregister_driver(&pxa3xx_cpufreq_driver);
  }
  module_exit(cpufreq_exit);
  
  MODULE_DESCRIPTION("CPU frequency scaling driver for PXA3xx");
  MODULE_LICENSE("GPL");