• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/arch/cris/arch-v32/mach-a3/
1#include <linux/init.h>
2#include <linux/module.h>
3#include <linux/cpufreq.h>
4#include <hwregs/reg_map.h>
5#include <hwregs/reg_rdwr.h>
6#include <hwregs/clkgen_defs.h>
7#include <hwregs/ddr2_defs.h>
8
9static int
10cris_sdram_freq_notifier(struct notifier_block *nb, unsigned long val,
11	void *data);
12
13static struct notifier_block cris_sdram_freq_notifier_block = {
14	.notifier_call = cris_sdram_freq_notifier
15};
16
17static struct cpufreq_frequency_table cris_freq_table[] = {
18	{0x01,	6000},
19	{0x02,	200000},
20	{0,	CPUFREQ_TABLE_END},
21};
22
23static unsigned int cris_freq_get_cpu_frequency(unsigned int cpu)
24{
25	reg_clkgen_rw_clk_ctrl clk_ctrl;
26	clk_ctrl = REG_RD(clkgen, regi_clkgen, rw_clk_ctrl);
27	return clk_ctrl.pll ? 200000 : 6000;
28}
29
30static void cris_freq_set_cpu_state(unsigned int state)
31{
32	int i = 0;
33	struct cpufreq_freqs freqs;
34	reg_clkgen_rw_clk_ctrl clk_ctrl;
35	clk_ctrl = REG_RD(clkgen, regi_clkgen, rw_clk_ctrl);
36
37#ifdef CONFIG_SMP
38	for_each_present_cpu(i)
39#endif
40	{
41		freqs.old = cris_freq_get_cpu_frequency(i);
42		freqs.new = cris_freq_table[state].frequency;
43		freqs.cpu = i;
44	}
45
46	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
47
48	local_irq_disable();
49
50	/* Even though we may be SMP they will share the same clock
51	 * so all settings are made on CPU0. */
52	if (cris_freq_table[state].frequency == 200000)
53		clk_ctrl.pll = 1;
54	else
55		clk_ctrl.pll = 0;
56	REG_WR(clkgen, regi_clkgen, rw_clk_ctrl, clk_ctrl);
57
58	local_irq_enable();
59
60	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
61};
62
63static int cris_freq_verify(struct cpufreq_policy *policy)
64{
65	return cpufreq_frequency_table_verify(policy, &cris_freq_table[0]);
66}
67
68static int cris_freq_target(struct cpufreq_policy *policy,
69			    unsigned int target_freq,
70			    unsigned int relation)
71{
72	unsigned int newstate = 0;
73
74	if (cpufreq_frequency_table_target(policy, cris_freq_table,
75			target_freq, relation, &newstate))
76		return -EINVAL;
77
78	cris_freq_set_cpu_state(newstate);
79
80	return 0;
81}
82
83static int cris_freq_cpu_init(struct cpufreq_policy *policy)
84{
85	int result;
86
87	/* cpuinfo and default policy values */
88	policy->cpuinfo.transition_latency = 1000000; /* 1ms */
89	policy->cur = cris_freq_get_cpu_frequency(0);
90
91	result = cpufreq_frequency_table_cpuinfo(policy, cris_freq_table);
92	if (result)
93		return (result);
94
95	cpufreq_frequency_table_get_attr(cris_freq_table, policy->cpu);
96
97	return 0;
98}
99
100
101static int cris_freq_cpu_exit(struct cpufreq_policy *policy)
102{
103	cpufreq_frequency_table_put_attr(policy->cpu);
104	return 0;
105}
106
107
108static struct freq_attr *cris_freq_attr[] = {
109	&cpufreq_freq_attr_scaling_available_freqs,
110	NULL,
111};
112
113static struct cpufreq_driver cris_freq_driver = {
114	.get	= cris_freq_get_cpu_frequency,
115	.verify	= cris_freq_verify,
116	.target	= cris_freq_target,
117	.init	= cris_freq_cpu_init,
118	.exit	= cris_freq_cpu_exit,
119	.name	= "cris_freq",
120	.owner	= THIS_MODULE,
121	.attr	= cris_freq_attr,
122};
123
124static int __init cris_freq_init(void)
125{
126	int ret;
127	ret = cpufreq_register_driver(&cris_freq_driver);
128	cpufreq_register_notifier(&cris_sdram_freq_notifier_block,
129		CPUFREQ_TRANSITION_NOTIFIER);
130	return ret;
131}
132
133static int
134cris_sdram_freq_notifier(struct notifier_block *nb, unsigned long val,
135	void *data)
136{
137	int i;
138	struct cpufreq_freqs *freqs = data;
139	if (val == CPUFREQ_PRECHANGE) {
140		reg_ddr2_rw_cfg cfg =
141		  REG_RD(ddr2, regi_ddr2_ctrl, rw_cfg);
142		cfg.ref_interval = (freqs->new == 200000 ? 1560 : 46);
143
144		if (freqs->new == 200000)
145			for (i = 0; i < 50000; i++);
146		REG_WR(bif_core, regi_bif_core, rw_sdram_timing, timing);
147	}
148	return 0;
149}
150
151
152module_init(cris_freq_init);
153