Commit 3496bea8 authored by Russell King's avatar Russell King

[ARM] Update cpufreq related sa1100 related drivers and CPU code

This cset updates sa1100 code for the now merged cpufreq next-gen.
parent a58cdfc6
......@@ -90,9 +90,7 @@
#include <asm/hardware.h>
extern unsigned int sa11x0_freq_to_ppcr(unsigned int khz);
extern unsigned int sa11x0_validatespeed(unsigned int cpu, unsigned int khz);
extern unsigned int sa11x0_getspeed(void);
#include "generic.h"
typedef struct {
int speed;
......@@ -107,7 +105,7 @@ typedef struct {
static sa1100_dram_regs_t sa1100_dram_settings[] =
{
/* { mdcnfg, mdcas0, mdcas1, mdcas2 } */ /* clock frequency */
/* speed, mdcnfg, mdcas0, mdcas1, mdcas2 clock frequency */
{ 59000, 0x00dc88a3, 0xcccccccf, 0xfffffffc, 0xffffffff }, /* 59.0 MHz */
{ 73700, 0x011490a3, 0xcccccccf, 0xfffffffc, 0xffffffff }, /* 73.7 MHz */
{ 88500, 0x014e90a3, 0xcccccccf, 0xfffffffc, 0xffffffff }, /* 88.5 MHz */
......@@ -127,28 +125,25 @@ static sa1100_dram_regs_t sa1100_dram_settings[] =
{ 0, 0, 0, 0, 0 } /* last entry */
};
static void sa1100_update_dram_timings(int current_speed, int new_speed)
{
sa1100_dram_regs_t *settings = sa1100_dram_settings;
/* find speed */
while(settings->speed != 0) {
while (settings->speed != 0) {
if(new_speed == settings->speed)
break;
settings++;
}
if(settings->speed == 0) {
if (settings->speed == 0) {
panic("%s: couldn't find dram setting for speed %d\n",
__FUNCTION__, new_speed);
}
/* No risk, no fun: run with interrupts on! */
if(new_speed > current_speed) {
if (new_speed > current_speed) {
/* We're going FASTER, so first relax the memory
* timings before changing the core frequency
*/
......@@ -181,60 +176,39 @@ static void sa1100_update_dram_timings(int current_speed, int new_speed)
}
}
static int sa1100_dram_notifier(struct notifier_block *nb,
unsigned long val, void *data)
static void sa1100_setspeed(struct cpufreq_policy *policy)
{
struct cpufreq_freqs *ci = data;
switch(val) {
case CPUFREQ_MINMAX:
cpufreq_updateminmax(data, sa1100_dram_settings->speed, -1);
break;
unsigned int cur = sa11x0_getspeed();
struct cpufreq_freqs freqs;
case CPUFREQ_PRECHANGE:
if(ci->new > ci->cur)
sa1100_update_dram_timings(ci->cur, ci->new);
break;
freqs.old = cur;
freqs.new = policy->max;
freqs.cpu = CPUFREQ_ALL_CPUS;
case CPUFREQ_POSTCHANGE:
if(ci->new < ci->cur)
sa1100_update_dram_timings(ci->cur, ci->new);
break;
default:
printk(KERN_INFO "%s: ignoring unknown notifier type (%ld)\n",
__FUNCTION__, val);
}
return 0;
}
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
if (policy->max > cur)
sa1100_update_dram_timings(cur, policy->max);
PPCR = sa11x0_freq_to_ppcr(policy->max);
if (policy->max < cur)
sa1100_update_dram_timings(cur, policy->max);
static struct notifier_block sa1100_dram_block = {
.notifier_call = sa1100_dram_notifier,
};
static void sa1100_setspeed(unsigned int cpu, unsigned int khz)
{
PPCR = sa11x0_freq_to_ppcr(khz);
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
}
static struct cpufreq_freqs sa1100_freqs = {
.min = 59000,
.max = 287000,
static struct cpufreq_policy sa1100_policy = {
.cpu = 0,
.policy = CPUFREQ_POLICY_POWERSAVE,
.max_cpu_freq = 287000,
};
static struct cpufreq_driver sa1100_driver = {
.freq = &sa1100_freqs,
.validate = sa11x0_validatespeed,
.setspeed = sa1100_setspeed,
.sync = 1,
.verify = sa11x0_verify_speed,
.setpolicy = sa1100_setspeed,
.policy = &sa1100_policy,
.cpu_min_freq = 59000,
};
static int __init sa1100_dram_init(void)
......@@ -242,11 +216,9 @@ static int __init sa1100_dram_init(void)
int ret = -ENODEV;
if ((processor_id & CPU_SA1100_MASK) == CPU_SA1100_ID) {
ret = cpufreq_register_notifier(&sa1100_dram_block);
if (ret)
return ret;
sa1100_freqs.cur = sa11x0_getspeed();
sa1100_driver.cpu_curr_freq[0] =
sa1100_policy.min =
sa1100_policy.max = sa11x0_getspeed();
ret = cpufreq_register(&sa1100_driver);
}
......
......@@ -28,11 +28,9 @@
#include <asm/io.h>
#include <asm/system.h>
#undef DEBUG
#include "generic.h"
extern unsigned int sa11x0_freq_to_ppcr(unsigned int khz);
extern unsigned int sa11x0_validatespeed(unsigned int cpu, unsigned int khz);
extern unsigned int sa11x0_getspeed(void);
#undef DEBUG
struct sdram_params {
u_char rows; /* bits */
......@@ -214,15 +212,16 @@ sdram_update_refresh(u_int cpu_khz, struct sdram_params *sdram)
* above, we can match for an exact frequency. If we don't find
* an exact match, we will to set the lowest frequency to be safe.
*/
static void sa1110_setspeed(unsigned int cpu, unsigned int khz)
static void sa1110_setspeed(struct cpufreq_policy *policy)
{
struct sdram_params *sdram = &sdram_params;
struct cpufreq_freqs freqs;
struct sdram_info sd;
unsigned long flags;
unsigned int ppcr, unused;
ppcr = sa11x0_freq_to_ppcr(khz);
sdram_calculate_timing(&sd, khz, sdram);
ppcr = sa11x0_freq_to_ppcr(policy->max);
sdram_calculate_timing(&sd, policy->max, sdram);
#if 0
/*
......@@ -230,7 +229,7 @@ static void sa1110_setspeed(unsigned int cpu, unsigned int khz)
* and errata, but they seem to work. Need to get a storage
* scope on to the SDRAM signals to work out why.
*/
if (khz < 147500) {
if (policy->max < 147500) {
sd.mdrefr |= MDREFR_K1DB2;
sd.mdcas[0] = 0xaaaaaa7f;
} else {
......@@ -240,6 +239,13 @@ static void sa1110_setspeed(unsigned int cpu, unsigned int khz)
sd.mdcas[1] = 0xaaaaaaaa;
sd.mdcas[2] = 0xaaaaaaaa;
#endif
freqs.old = sa11x0_getspeed();
freqs.new = policy->max;
freqs.cpu = CPUFREQ_ALL_CPUS;
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
/*
* The clock could be going away for some time. Set the SDRAMs
* to refresh rapidly (every 64 memory clock cycles). To get
......@@ -257,7 +263,7 @@ static void sa1110_setspeed(unsigned int cpu, unsigned int khz)
* the programming.
*/
local_irq_save(flags);
asm("mcr p15, 0, %0, c10, c4" : : "r" (0));
asm("mcr p15, 0, %0, c7, c10, 4" : : "r" (0));
udelay(10);
__asm__ __volatile__("
b 2f
......@@ -282,19 +288,22 @@ static void sa1110_setspeed(unsigned int cpu, unsigned int khz)
/*
* Now, return the SDRAM refresh back to normal.
*/
sdram_update_refresh(khz, sdram);
sdram_update_refresh(policy->max, sdram);
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
}
static struct cpufreq_freqs sa1110_freqs = {
.min = 59000,
.max = 287000,
static struct cpufreq_policy sa1110_policy = {
.cpu = 0,
.policy = CPUFREQ_POLICY_POWERSAVE,
.max_cpu_freq = 287000,
};
static struct cpufreq_driver sa1110_driver = {
.freq = &sa1110_freqs,
.validate = sa11x0_validatespeed,
.setspeed = sa1110_setspeed,
.sync = 1,
.verify = sa11x0_verify_speed,
.setpolicy = sa1110_setspeed,
.policy = &sa1110_policy,
.cpu_min_freq = 59000,
};
static int __init sa1110_clk_init(void)
......@@ -318,8 +327,11 @@ static int __init sa1110_clk_init(void)
memcpy(&sdram_params, sdram, sizeof(sdram_params));
sa1110_freqs.cur = sa11x0_getspeed();
sa1110_setspeed(0, sa1110_freqs.cur);
sa1110_driver.cpu_cur_freq[0] =
sa1110_policy.min =
sa1110_policy.max = sa11x0_getspeed();
sa1110_setspeed(&sa1110_policy);
return cpufreq_register(&sa1110_driver);
}
......
......@@ -55,20 +55,26 @@ unsigned int sa11x0_freq_to_ppcr(unsigned int khz)
khz /= 100;
for (i = NR_FREQS - 1; i > 0; i--)
if (cclk_frequency_100khz[i] <= khz)
for (i = 0; i < ARRAY_SIZE(cclk_frequency_100khz); i--)
if (cclk_frequency_100khz[i] >= khz)
break;
return i;
}
/*
* Validate the speed in khz. If we can't generate the precise
* frequency requested, round it down (to be on the safe side).
* Validate the policy. We aren't able to do any fancy in-kernel
* scaling, so we force min=max, and set the policy to "performance".
* If we can't generate the precise frequency requested, round it up.
*/
unsigned int sa11x0_validatespeed(unsigned int cpu, unsigned int khz)
void sa11x0_verify_speed(struct cpufreq_policy *policy)
{
return cclk_frequency_100khz[sa11x0_freq_to_ppcr(khz)] * 100;
if (policy->max > policy->max_cpu_freq)
policy->max = policy->max_cpu_freq;
policy->max = cclk_frequency_100khz[sa11x0_freq_to_ppcr(policy->max)] * 100;
policy->min = policy->max;
policy->policy = CPUFREQ_POLICY_POWERSAVE;
}
unsigned int sa11x0_getspeed(void)
......
......@@ -17,3 +17,9 @@ extern void (*sa1100fb_lcd_power)(int on);
extern void sa1110_mb_enable(void);
extern void sa1110_mb_disable(void);
struct cpufreq_policy;
extern unsigned int sa11x0_freq_to_ppcr(unsigned int khz);
extern void sa11x0_verify_speed(struct cpufreq_policy *policy);
extern unsigned int sa11x0_getspeed(void);
......@@ -110,12 +110,11 @@ sa1100_pcmcia_default_mecr_timing(unsigned int sock, unsigned int cpu_speed,
* Call board specific BS value calculation to allow boards
* to tweak the BS values.
*/
static int sa1100_pcmcia_set_mecr(int sock)
static int sa1100_pcmcia_set_mecr(int sock, unsigned int cpu_clock)
{
struct sa1100_pcmcia_socket *skt;
u32 mecr;
int clock;
long flags;
unsigned long flags;
unsigned int bs;
if (sock < 0 || sock > SA1100_PCMCIA_MAX_SOCK)
......@@ -125,8 +124,7 @@ static int sa1100_pcmcia_set_mecr(int sock)
local_irq_save(flags);
clock = cpufreq_get(0);
bs = pcmcia_low_level->socket_get_timing(sock, clock, skt->speed_io);
bs = pcmcia_low_level->socket_get_timing(sock, cpu_clock, skt->speed_io);
mecr = MECR;
MECR_FAST_SET(mecr, sock, 0);
......@@ -652,7 +650,7 @@ sa1100_pcmcia_set_io_map(unsigned int sock, struct pccard_io_map *map)
if ( map->speed == 0)
map->speed = SA1100_PCMCIA_IO_ACCESS;
sa1100_pcmcia_set_mecr( sock );
sa1100_pcmcia_set_mecr(sock, cpufreq_get(0));
}
if (map->stop == 1)
......@@ -741,7 +739,7 @@ sa1100_pcmcia_set_mem_map(unsigned int sock, struct pccard_mem_map *map)
map->speed = SA1100_PCMCIA_5V_MEM_ACCESS;
}
sa1100_pcmcia_set_mecr( sock );
sa1100_pcmcia_set_mecr(sock, cpufreq_get(0));
}
......@@ -885,9 +883,8 @@ static void sa1100_pcmcia_update_mecr(unsigned int clock)
{
unsigned int sock;
for (sock = 0; sock < SA1100_PCMCIA_MAX_SOCK; ++sock) {
sa1100_pcmcia_set_mecr(sock);
}
for (sock = 0; sock < SA1100_PCMCIA_MAX_SOCK; ++sock)
sa1100_pcmcia_set_mecr(sock, clock);
}
/* sa1100_pcmcia_notifier()
......@@ -904,31 +901,31 @@ static int
sa1100_pcmcia_notifier(struct notifier_block *nb, unsigned long val,
void *data)
{
struct cpufreq_info *ci = data;
switch (val) {
case CPUFREQ_PRECHANGE:
if (ci->new_freq > ci->old_freq) {
DEBUG(2, "%s(): new frequency %u.%uMHz > %u.%uMHz, pre-updating\n",
__FUNCTION__,
ci->new_freq / 1000, (ci->new_freq / 100) % 10,
ci->old_freq / 1000, (ci->old_freq / 100) % 10);
sa1100_pcmcia_update_mecr(ci->new_freq);
}
break;
case CPUFREQ_POSTCHANGE:
if (ci->new_freq < ci->old_freq) {
DEBUG(2, "%s(): new frequency %u.%uMHz < %u.%uMHz, post-updating\n",
__FUNCTION__,
ci->new_freq / 1000, (ci->new_freq / 100) % 10,
ci->old_freq / 1000, (ci->old_freq / 100) % 10);
sa1100_pcmcia_update_mecr(ci->new_freq);
}
break;
}
struct cpufreq_freqs *freqs = data;
switch (val) {
case CPUFREQ_PRECHANGE:
if (freqs->new > freqs->old) {
DEBUG(2, "%s(): new frequency %u.%uMHz > %u.%uMHz, "
"pre-updating\n", __FUNCTION__,
freqs->new / 1000, (freqs->new / 100) % 10,
freqs->old / 1000, (freqs->old / 100) % 10);
sa1100_pcmcia_update_mecr(freqs->new);
}
break;
case CPUFREQ_POSTCHANGE:
if (freqs->new < freqs->old) {
DEBUG(2, "%s(): new frequency %u.%uMHz < %u.%uMHz, "
"post-updating\n", __FUNCTION__,
freqs->new / 1000, (freqs->new / 100) % 10,
freqs->old / 1000, (freqs->old / 100) % 10);
sa1100_pcmcia_update_mecr(freqs->new);
}
break;
}
return 0;
return 0;
}
static struct notifier_block sa1100_pcmcia_notifier_block = {
......@@ -946,7 +943,7 @@ int sa1100_register_pcmcia(struct pcmcia_low_level *ops)
struct pcmcia_init pcmcia_init;
struct pcmcia_state state[SA1100_PCMCIA_MAX_SOCK];
struct pcmcia_state_array state_array;
unsigned int i;
unsigned int i, cpu_clock;
int ret;
/*
......@@ -986,6 +983,8 @@ int sa1100_register_pcmcia(struct pcmcia_low_level *ops)
goto shutdown;
}
cpu_clock = cpufreq_get(0);
/*
* We initialize the MECR to default values here, because we are
* not guaranteed to see a SetIOMap operation at runtime.
......@@ -1019,7 +1018,7 @@ int sa1100_register_pcmcia(struct pcmcia_low_level *ops)
goto out_err;
}
sa1100_pcmcia_set_mecr( i );
sa1100_pcmcia_set_mecr(i, cpu_clock);
}
......@@ -1110,7 +1109,7 @@ static int __init sa1100_pcmcia_init(void)
servinfo_t info;
int ret, i;
printk(KERN_INFO "SA-1100 PCMCIA (CS release %s)\n", CS_RELEASE);
printk(KERN_INFO "SA11x0 PCMCIA (CS release %s)\n", CS_RELEASE);
CardServices(GetCardServicesInfo, &info);
if (info.Revision != CS_RELEASE_CODE) {
......@@ -1127,7 +1126,8 @@ static int __init sa1100_pcmcia_init(void)
}
#ifdef CONFIG_CPU_FREQ
ret = cpufreq_register_notifier(&sa1100_pcmcia_notifier_block);
ret = cpufreq_register_notifier(&sa1100_pcmcia_notifier_block,
CPUFREQ_TRANSITION_NOTIFIER);
if (ret < 0) {
printk(KERN_ERR "Unable to register CPU frequency change "
"notifier (%d)\n", ret);
......@@ -1216,7 +1216,7 @@ static void __exit sa1100_pcmcia_exit(void)
}
#ifdef CONFIG_CPU_FREQ
cpufreq_unregister_notifier(&sa1100_pcmcia_notifier_block);
cpufreq_unregister_notifier(&sa1100_pcmcia_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
#endif
}
......
......@@ -1593,33 +1593,42 @@ static unsigned int sa1100fb_min_dma_period(struct sa1100fb_info *fbi)
* subsystem.
*/
static int
sa1100fb_clkchg_notifier(struct notifier_block *nb, unsigned long val,
sa1100fb_freq_transition(struct notifier_block *nb, unsigned long val,
void *data)
{
struct sa1100fb_info *fbi = TO_INF(nb, clockchg);
struct cpufreq_minmax *mm = data;
struct sa1100fb_info *fbi = TO_INF(nb, freq_transition);
struct cpufreq_freqs *f = data;
u_int pcd;
switch (val) {
case CPUFREQ_MINMAX:
printk(KERN_DEBUG "min dma period: %d ps, old clock %d kHz, "
"new clock %d kHz\n", sa1100fb_min_dma_period(fbi),
mm->cur_freq, mm->new_freq);
/* todo: fill in min/max values */
break;
case CPUFREQ_PRECHANGE:
set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE);
break;
case CPUFREQ_POSTCHANGE:
pcd = get_pcd(fbi->fb.var.pixclock, cpufreq_get(0));
pcd = get_pcd(fbi->fb.var.pixclock, f->new);
fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd);
set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);
break;
}
return 0;
}
static int
sa1100fb_freq_policy(struct notifier_block *nb, unsigned long val,
void *data)
{
struct sa1100fb_info *fbi = TO_INF(nb, freq_policy);
struct cpufreq_policy *policy = data;
if (val == CPUFREQ_INCOMPATIBLE) {
printk(KERN_DEBUG "min dma period: %d ps, "
"new clock %d kHz\n", sa1100fb_min_dma_period(fbi),
policy->max);
/* todo: fill in min/max values */
}
return 0;
}
#endif
#ifdef CONFIG_PM
......@@ -1831,8 +1840,10 @@ int __init sa1100fb_init(void)
fbi->pm->data = fbi;
#endif
#ifdef CONFIG_CPU_FREQ
fbi->clockchg.notifier_call = sa1100fb_clkchg_notifier;
cpufreq_register_notifier(&fbi->clockchg);
fbi->freq_transition.notifier_call = sa1100fb_freq_transition;
fbi->freq_policy.notifier_call = sa1100fb_freq_policy;
cpufreq_register_notifier(&fbi->freq_transition, CPUFREQ_TRANSITION_NOTIFIER);
cpufreq_register_notifier(&fbi->freq_policy, CPUFREQ_POLICY_NOTIFIER);
#endif
/*
......
......@@ -107,7 +107,8 @@ struct sa1100fb_info {
struct pm_dev *pm;
#endif
#ifdef CONFIG_CPU_FREQ
struct notifier_block clockchg;
struct notifier_block freq_transition;
struct notifier_block freq_policy;
#endif
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment