--- zzzz-none-000/linux-2.6.13.1/arch/mips/kernel/cpu-probe.c 2005-09-10 02:42:58.000000000 +0000 +++ ohio-7170-487/linux-2.6.13.1/arch/mips/kernel/cpu-probe.c 2008-01-09 09:55:42.000000000 +0000 @@ -22,6 +22,27 @@ #include #include #include +#include + +#ifdef CONFIG_AVM_POWER +#include +#endif /*--- #ifdef CONFIG_AVM_POWER ---*/ + +#include +static int avm_idle_mode; +static int avm_idle_mode_speedup; +static int avm_prev_idle_mode_speedup; +static int avm_idle_lock_speedup1; +static int avm_idle_lock_speedup2; +static int avm_idle_supported_speedup; +static int avm_idle_timestamp; + +#define TIME_DIFF(t1, t2) (((t2) > (t1)) ? (t2 - t1) : (t1 - t2)) +#define TIME_SLOWPOWER (60 * HZ) /*--- in Sekunden ---*/ +#define TIME_SPEEDPOWER (10 * HZ) /*--- in Sekunden ---*/ +#define LOW_SPEED_IDLE 50 +#define NORMAL_SPEED_IDLE 25 +#define HIGH_SPEED_IDLE 10 /* * Not all of the MIPS CPUs have the "wait" instruction available. Moreover, @@ -44,6 +65,261 @@ write_c0_conf(cfg | TX39_CONF_HALT); } +/*--------------------------------------------------------------------------------------*\ +\*--------------------------------------------------------------------------------------*/ +static inline void r4k_idle_control(int p_idle, int p_run) { + switch(avm_idle_mode) { + case 1: + case 3: + case 5: + case 7: + /*--- printk("r4k_wait: sum %u wait %u run %u\n", r4k_sum_count, r4k_wait_count, r4k_run_count); ---*/ + /*--- printk("[idle]: %u%% (run %u%%)\n", p_idle, p_run); ---*/ + printk("[idle]: %u%% (run %u%%) dt=%d s=%x\n", p_idle, p_run, TIME_DIFF(avm_idle_timestamp, (int)jiffies), (unsigned int)avm_idle_mode_speedup); + break; + } +#ifdef CONFIG_AVM_POWER +#ifdef CONFIG_AVM_POWERMETER + PowerManagmentRessourceInfo(powerdevice_loadrate, max(0,100 - p_idle)); +#endif/*--- #ifdef CONFIG_AVM_POWERMETER ---*/ + + switch(avm_idle_mode_speedup) { + case 0: /*--- 125 MHz ---*/ + if(avm_prev_idle_mode_speedup != avm_idle_mode_speedup) { + avm_prev_idle_mode_speedup = avm_idle_mode_speedup; + printk("[speedup] -> 125 MHz\n"); + } + if(p_idle < HIGH_SPEED_IDLE) { + if(avm_idle_lock_speedup2) { + /*--- kein Hochschalten erlauben - Timer neu aufsetzen ---*/ + avm_idle_timestamp = jiffies; + break; + } + /*--- Hochschalten auf 150 MHz ---*/ + if(avm_idle_supported_speedup & 1) { + /*--- printk("[speedup] -> try fast\n"); ---*/ + PowerManagmentActivatePowerMode("fastspeed"); + } + } else if(p_idle < LOW_SPEED_IDLE) { + /*--- Timer aufsetzen fuer slowspeed ---*/ + avm_idle_timestamp = jiffies; + } else { + if(avm_idle_lock_speedup1 || avm_idle_lock_speedup2) { + /*--- kein Herunterschalten erlauben - Timer neu aufsetzen ---*/ + avm_idle_timestamp = jiffies; + break; + } + if(TIME_DIFF(avm_idle_timestamp, jiffies) > TIME_SLOWPOWER) { + /*--- Zeit verstrichen, nun SlowSpeed ---*/ + if(avm_idle_supported_speedup & 2) { + /*--- printk("[speedup] -> try slow\n"); ---*/ + PowerManagmentActivatePowerMode("slowspeed"); + } + } + } + break; + case 1: /*--- 150 MHz ---*/ + if(avm_prev_idle_mode_speedup != avm_idle_mode_speedup) { + avm_prev_idle_mode_speedup = avm_idle_mode_speedup; + printk("[speedup] -> 150 MHz\n"); + } + if(p_idle < HIGH_SPEED_IDLE) { + /*--- Timer aufsetzen fuer normalspeed ---*/ + avm_idle_timestamp = jiffies; + } else if(p_idle > NORMAL_SPEED_IDLE) { + if(avm_idle_lock_speedup1 || avm_idle_lock_speedup2) { + /*--- kein Herunterschalten erlauben - Timer neu aufsetzen ---*/ + avm_idle_timestamp = jiffies; + break; + } + if(TIME_DIFF(avm_idle_timestamp, jiffies) > TIME_SPEEDPOWER) { + /*--- Zeit verstrichen, nun NormalSpeed ---*/ + /*--- printk("[speedup] -> normal from speed\n"); ---*/ + PowerManagmentActivatePowerMode("normalspeed"); + avm_idle_timestamp = jiffies; + } + } + break; + case 2: /*--- 62.5 MHz ---*/ + if(avm_prev_idle_mode_speedup != avm_idle_mode_speedup) { + avm_prev_idle_mode_speedup = avm_idle_mode_speedup; + printk("[speedup] -> 62.5 MHz\n"); + } + if(p_idle < LOW_SPEED_IDLE) { + /*--- Hochschalten auf 125 MHz ---*/ + /*--- printk("[speedup] -> normal from slow\n"); ---*/ + PowerManagmentActivatePowerMode("normalspeed"); + avm_idle_timestamp = jiffies; + } + break; + } +#endif /*--- #ifdef CONFIG_AVM_POWER ---*/ +} + +/*--------------------------------------------------------------------------------------*\ +\*--------------------------------------------------------------------------------------*/ +static unsigned int last_value = 0; +static unsigned int last_value_done = 0; +unsigned int r4k_wait_count, r4k_run_count, r4k_sum_count; + +/*--------------------------------------------------------------------------------------*\ +\*--------------------------------------------------------------------------------------*/ +int r4k_wait_end(void) { + if(last_value_done == 0) { + int count, tmp; + last_value_done = 1; + count = get_cycles(); + if(last_value < count) + tmp = count - last_value ; + else + tmp = last_value - count; + r4k_wait_count += tmp; + r4k_sum_count += tmp; + last_value = count; + return 0; + } + return 1; +} + +/*--------------------------------------------------------------------------------------*\ +\*--------------------------------------------------------------------------------------*/ +static void r4k_wait_idle(void) { + unsigned int count, tmp; + count = get_cycles(); + if(last_value) { + if(last_value < count) + tmp = count - last_value ; + else + tmp = last_value - count; + r4k_run_count += tmp; + r4k_sum_count += tmp; + } + last_value = count; + last_value_done = 0; + __asm__(".set\tmips3\n\t" + "wait\n\t" + ".set\tmips0"); + if(r4k_wait_end() == 0) { + /*--- printk("?"); ---*/ + } + + + if(r4k_sum_count > (1 << 28)) { + int p_idle = ((r4k_wait_count >> 8) * 100) / (r4k_sum_count >> 8); + int p_run = ((r4k_run_count >> 8) * 100) / (r4k_sum_count >> 8); + + r4k_idle_control(p_idle, p_run); + /*--- r4k_sum_count >>= 1; ---*/ + /*--- r4k_wait_count >>= 1; ---*/ + /*--- r4k_run_count >>= 1; ---*/ + r4k_sum_count >>= 3; + r4k_wait_count >>= 3; + r4k_run_count >>= 3; + } +} + +/*------------------------------------------------------------------------------------------*\ + * Wird vom Power-Treiber aufgrufen + * state: + * 0 normal + * 1 fast + * 2 slow + * 0x8x setze clock (0,1,2) - ab jetzt kein idleabhängiges Speedup-Control + * 0x10x Setzen der unterstuetzten Modi: (1 Fast, 2 Slow (verodern)) + * 0x18x Setzen der unterstuezten Modi - allerdings nur manuelle Switching (idleunabhaengig) + * 0x201 kein speed-down mehr - nur noch speedup (Telefonapplikation) + * 0x200 speed-down entlocken + * 0x40x Abfrage ob diese entsprechende Speedup erlaubt + * 0x801 kein speedup/down (USB-Treiber) + * 0x800 speed-down entlocken + * 0x1001 kein speedup/down (ATM-Treiber) + * 0x1000 speed-down entlocken + * Initial sind Änderungen an der Clock nicht freigeschaltet +\*------------------------------------------------------------------------------------------*/ +#ifdef CONFIG_AVM_POWER +int speedup_CallBackPowerManagmentControl (int state) { + unsigned new_system_freq = 0; + if(state & 0x400) { + if(state & avm_idle_supported_speedup) { + /*--- Speedup wird unterstützt ---*/ + return 0; + } + return 1; + } + if(state & 0x200) { + avm_idle_timestamp = jiffies; + avm_idle_lock_speedup1 = state & 1; /*--- speed-down verboten (nur noch speedup) ---*/ + return 0; + } + if(state & 0x800) { + avm_idle_timestamp = jiffies; + if(state & 1) { + avm_idle_lock_speedup2 |= 0x800; /*--- speed-up/down verboten ---*/ + } else { + avm_idle_lock_speedup2 &= ~0x800; /*--- speed-up/down an ---*/ + } + return 0; + } + if(state & 0x1000) { + avm_idle_timestamp = jiffies; + if(state & 1) { + avm_idle_lock_speedup2 |= 0x1000; /*--- speed-up/down verboten ---*/ + } else { + avm_idle_lock_speedup2 &= ~0x1000; /*--- speed-up/down an ---*/ + } + return 0; + } + if(state & 0x100) { + avm_idle_supported_speedup = (state & ~0x100); + if(state & 0x80) { + /*--- jetzt idle-unabhaengig aber alten state merken ---*/ + avm_idle_mode_speedup |= 0x80; + } else { + /*--- letzten State reseten ---*/ + avm_idle_mode_speedup &= ~0x80; + } + return 0; + } + if(avm_idle_supported_speedup & 0x80) { + /*--- keine idle-Abhängigkeit aber state merken ---*/ + avm_idle_mode_speedup = state | 0x80; + } else { + /*--- idle-Abhaengigkeit ---*/ + avm_idle_mode_speedup = state; + } + state &= ~0x80; + if(state == 0) { + new_system_freq = 125000000; + } else if(state == 1) { + if(avm_idle_supported_speedup & 1) { + new_system_freq = 150000000; + } + } else if(state == 2) { + if(avm_idle_supported_speedup & 2) { + new_system_freq = 62500000; + } + } + if(new_system_freq && (new_system_freq != avm_get_clock(avm_clock_id_system))) { + avm_set_clock(avm_clock_id_system, new_system_freq); + } + return 0; +} +#endif /*--- #ifdef CONFIG_AVM_POWER ---*/ + +/*------------------------------------------------------------------------------------------*\ +\*------------------------------------------------------------------------------------------*/ +#ifdef CONFIG_AVM_POWER +int __init speedup_init(void) { + avm_idle_timestamp = jiffies; + PowerManagmentRegister("speedup", speedup_CallBackPowerManagmentControl); + return 0; +} + +late_initcall(speedup_init); +#endif /*--- #ifdef CONFIG_AVM_POWER ---*/ + + + static void r4k_wait(void) { __asm__(".set\tmips3\n\t" @@ -109,8 +385,30 @@ /* case CPU_20KC:*/ case CPU_24K: case CPU_25KF: - cpu_wait = r4k_wait; - printk(" available.\n"); + { + if(strstr(prom_getcmdline(), "idle")) { + char *p; + avm_idle_mode = 1; + p = strstr(prom_getcmdline(), "idle="); + if(p) { + extern int avm_vlync_double_speed; + avm_idle_mode = simple_strtol(p + sizeof("idle=") - 1, NULL, 0); + printk("[speedup] idle_mode = %u\n", avm_idle_mode); + switch(avm_idle_mode) { + case 6: + case 7: + avm_vlync_double_speed = 1; + break; + } + } + cpu_wait = r4k_wait_idle; + printk(" with idle values available.\n"); + } else { + cpu_wait = r4k_wait; + printk(" available.\n"); + } + } + cpu_wait = r4k_wait_idle; break; #ifdef CONFIG_PM case CPU_AU1000: @@ -467,6 +765,10 @@ c->cputype = CPU_4KEC; c->isa_level = MIPS_CPU_ISA_M32; break; + case PRID_IMP_4KECR2: + c->cputype = CPU_4KEC; + c->isa_level = MIPS_CPU_ISA_M32; + break; case PRID_IMP_4KSC: c->cputype = CPU_4KSC; c->isa_level = MIPS_CPU_ISA_M32;