--- zzzz-none-000/linux-2.6.19.2/arch/mips/mips-boards/generic/time.c 2007-01-10 19:10:37.000000000 +0000 +++ davinci-8020-5504/linux-2.6.19.2/arch/mips/mips-boards/generic/time.c 2007-07-11 09:40:53.000000000 +0000 @@ -40,38 +40,69 @@ #include #include - -#ifdef CONFIG_MIPS_ATLAS -#include -#endif -#ifdef CONFIG_MIPS_MALTA -#include -#endif +#if defined(CONFIG_MIPS_OHIO) +#include +#include +#include +#elif defined(CONFIG_MIPS_AR7) +#include +#include +#include +#elif defined(CONFIG_MIPS_UR8) +#include +#include +#include +#else +#error unknown CONFIG_MIPS_... +#endif /*--- #if defined(CONFIG_MIPS_UR8) ---*/ unsigned long cpu_khz; +#if defined(CONFIG_MIPS_SEAD) || defined(CONFIG_MIPS_OHIO) || defined(CONFIG_MIPS_AR7) || defined(CONFIG_MIPS_UR8) +#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ5) +#else +#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5) +#endif + #if defined(CONFIG_MIPS_ATLAS) static char display_string[] = " LINUX ON ATLAS "; #endif #if defined(CONFIG_MIPS_MALTA) -#if defined(CONFIG_MIPS_MT_SMTC) -static char display_string[] = " SMTC LINUX ON MALTA "; -#else static char display_string[] = " LINUX ON MALTA "; -#endif /* CONFIG_MIPS_MT_SMTC */ #endif #if defined(CONFIG_MIPS_SEAD) static char display_string[] = " LINUX ON SEAD "; #endif +#if defined(CONFIG_MIPS_OHIO) +static char display_string[] = " LINUX ON OHIO "; +#endif +#if defined(CONFIG_MIPS_AR7) +static char display_string[] = " LINUX ON AR7 "; +#endif +#if defined(CONFIG_MIPS_UR8) +static char display_string[] = " LINUX ON UR8 "; +#endif static unsigned int display_count; #define MAX_DISPLAY_COUNT (sizeof(display_string) - 8) +#if defined(CONFIG_MIPS_UR8) +#define MIPS_CPU_TIMER_IRQ 7 +#else +#define MIPS_CPU_TIMER_IRQ (NR_IRQS-1) +#endif + #define CPUCTR_IMASKBIT (0x100 << MIPSCPU_INT_CPUCTR) static unsigned int timer_tick_count; static int mips_cpu_timer_irq; + +#if defined(CONFIG_OHIO_CLOCK_SWITCH) || defined(CONFIG_UR8_CLOCK_SWITCH) || defined(CONFIG_AR7_CLOCK_SWITCH) + static unsigned int mips_time_cpu_frequenz_change(enum _avm_clock_id, unsigned int); +#endif + extern void smtc_timer_broadcast(int); +#if 0 static inline void scroll_display_message(void) { if ((timer_tick_count++ % HZ) == 0) { @@ -80,6 +111,7 @@ display_count = 0; } } +#endif static void mips_timer_dispatch(void) { @@ -95,94 +127,21 @@ irqreturn_t mips_timer_interrupt(int irq, void *dev_id) { - int cpu = smp_processor_id(); - -#ifdef CONFIG_MIPS_MT_SMTC - /* - * In an SMTC system, one Count/Compare set exists per VPE. - * Which TC within a VPE gets the interrupt is essentially - * random - we only know that it shouldn't be one with - * IXMT set. Whichever TC gets the interrupt needs to - * send special interprocessor interrupts to the other - * TCs to make sure that they schedule, etc. - * - * That code is specific to the SMTC kernel, not to - * the a particular platform, so it's invoked from - * the general MIPS timer_interrupt routine. - */ - - int vpflags; - - /* - * We could be here due to timer interrupt, - * perf counter overflow, or both. - */ - if (read_c0_cause() & (1 << 26)) - perf_irq(); - - if (read_c0_cause() & (1 << 30)) { - /* If timer interrupt, make it de-assert */ - write_c0_compare (read_c0_count() - 1); - /* - * DVPE is necessary so long as cross-VPE interrupts - * are done via read-modify-write of Cause register. - */ - vpflags = dvpe(); - clear_c0_cause(CPUCTR_IMASKBIT); - evpe(vpflags); - /* - * There are things we only want to do once per tick - * in an "MP" system. One TC of each VPE will take - * the actual timer interrupt. The others will get - * timer broadcast IPIs. We use whoever it is that takes - * the tick on VPE 0 to run the full timer_interrupt(). - */ - if (cpu_data[cpu].vpe_id == 0) { - timer_interrupt(irq, NULL); - smtc_timer_broadcast(cpu_data[cpu].vpe_id); - scroll_display_message(); - } else { - write_c0_compare(read_c0_count() + - (mips_hpt_frequency/HZ)); - local_timer_interrupt(irq, dev_id); - smtc_timer_broadcast(cpu_data[cpu].vpe_id); - } - } -#else /* CONFIG_MIPS_MT_SMTC */ - int r2 = cpu_has_mips_r2; - - if (cpu == 0) { - /* - * CPU 0 handles the global timer interrupt job and process - * accounting resets count/compare registers to trigger next - * timer int. - */ - if (!r2 || (read_c0_cause() & (1 << 26))) - if (perf_irq()) - goto out; - - /* we keep interrupt disabled all the time */ - if (!r2 || (read_c0_cause() & (1 << 30))) - timer_interrupt(irq, NULL); - - scroll_display_message(); - } else { - /* Everyone else needs to reset the timer int here as - ll_local_timer_interrupt doesn't */ - /* - * FIXME: need to cope with counter underflow. - * More support needs to be added to kernel/time for - * counter/timer interrupts on multiple CPU's - */ - write_c0_compare(read_c0_count() + (mips_hpt_frequency/HZ)); - - /* - * Other CPUs should do profiling and process accounting - */ - local_timer_interrupt(irq, dev_id); - } -out: -#endif /* CONFIG_MIPS_MT_SMTC */ + /*--- prom_printf("mips_timer_interrupt\n"); ---*/ + /*--- extern void r4k_wait_end(void); ---*/ /* TODO */ + /*--- r4k_wait_end(); ---*/ + +#if defined(CONFIG_MIPS_OHIO) + kstat_this_cpu.irqs[MIPS_EXCEPTION_OFFSET - 7]++; + ohio_timer_interrupt(); +#elif defined(CONFIG_MIPS_AR7) + kstat_this_cpu.irqs[MIPS_EXCEPTION_OFFSET - 7]++; + ar7_timer_interrupt(); +#elif defined(CONFIG_MIPS_UR8) /*--- #if defined(CONFIG_MIPS_OHIO) ---*/ + kstat_this_cpu.irqs[MIPS_EXCEPTION_OFFSET - 7]++; + ur8_timer_interrupt(); +#endif /*--- #elif ---*/ /*--- #if defined(CONFIG_MIPS_OHIO) ---*/ + ll_timer_interrupt(MIPS_CPU_TIMER_IRQ); return IRQ_HANDLED; } @@ -208,8 +167,7 @@ count = 6000000; #endif #if defined(CONFIG_MIPS_ATLAS) || defined(CONFIG_MIPS_MALTA) - unsigned long flags; - unsigned int start; + unsigned int flags; local_irq_save(flags); @@ -218,40 +176,66 @@ while (!(CMOS_READ(RTC_REG_A) & RTC_UIP)); /* Start r4k counter. */ - start = read_c0_count(); + write_c0_count(0); /* Read counter exactly on falling edge of update flag */ while (CMOS_READ(RTC_REG_A) & RTC_UIP); while (!(CMOS_READ(RTC_REG_A) & RTC_UIP)); - count = read_c0_count() - start; + count = read_c0_count(); /* restore interrupts */ local_irq_restore(flags); #endif +#if defined(CONFIG_MIPS_OHIO) || defined(CONFIG_MIPS_AR7) || defined(CONFIG_MIPS_UR8) +#if defined(CONFIG_OHIO_CLOCK_SWITCH) || defined(CONFIG_UR8_CLOCK_SWITCH) || defined(CONFIG_AR7_CLOCK_SWITCH) + count = avm_get_clock_notify(avm_clock_id_cpu, mips_time_cpu_frequenz_change); +#else /*--- #if defined(CONFIG_OHIO_CLOCK_SWITCH) || defined(CONFIG_UR8_CLOCK_SWITCH) || defined(CONFIG_AR7_CLOCK_SWITCH) ---*/ + count = avm_get_clock(avm_clock_id_cpu); +#endif /*--- #else ---*//*--- #if defined(CONFIG_OHIO_CLOCK_SWITCH) || defined(CONFIG_UR8_CLOCK_SWITCH) || defined(CONFIG_AR7_CLOCK_SWITCH) ---*/ + mips_hpt_frequency = count / 2; +#endif - mips_hpt_frequency = count; +#if !defined(CONFIG_MIPS_OHIO) && !defined(CONFIG_MIPS_AR7) && !defined(CONFIG_MIPS_UR8) if ((prid != (PRID_COMP_MIPS | PRID_IMP_20KC)) && (prid != (PRID_COMP_MIPS | PRID_IMP_25KF))) count *= 2; + mips_hpt_frequency = count; +#endif /*--- #if !defined(CONFIG_MIPS_OHIO) && !defined(CONFIG_MIPS_AR7) && !defined(CONFIG_MIPS_UR8) ---*/ + count += 5000; /* round */ count -= count%10000; return count; } +/*------------------------------------------------------------------------------------------*\ +\*------------------------------------------------------------------------------------------*/ +#if defined(CONFIG_OHIO_CLOCK_SWITCH) || defined(CONFIG_AR7_CLOCK_SWITCH) || defined(CONFIG_UR8_CLOCK_SWITCH) +static unsigned int mips_time_cpu_frequenz_change(enum _avm_clock_id clock_id, unsigned int new_clk) { + printk("[mips_time_cpu_frequenz_change] change to %u Hz\n", new_clk); + return 0; +} +#endif /*--- #if defined(CONFIG_OHIO_CLOCK_SWITCH) || defined(CONFIG_AR7_CLOCK_SWITCH) || defined(CONFIG_UR8_CLOCK_SWITCH) ---*/ + +#if defined(CONFIG_MIPS_RTC) unsigned long __init mips_rtc_get_time(void) { return mc146818_get_cmos_time(); } +#endif /*--- #if defined(CONFIG_MIPS_RTC) ---*/ +/*------------------------------------------------------------------------------------------*\ +\*------------------------------------------------------------------------------------------*/ void __init mips_time_init(void) { unsigned int est_freq; +#if defined(CONFIG_MIPS_ATLAS) || defined(CONFIG_MIPS_MALTA) /* Set Data mode - binary. */ CMOS_WRITE(CMOS_READ(RTC_CONTROL) | RTC_DM_BINARY, RTC_CONTROL); +#endif est_freq = estimate_cpu_frequency (); @@ -261,8 +245,12 @@ cpu_khz = est_freq / 1000; } +/*------------------------------------------------------------------------------------------*\ +\*------------------------------------------------------------------------------------------*/ void __init plat_timer_setup(struct irqaction *irq) { + prom_printf("plat_timer_setup TIMER IRQ: %d\n", MIPS_CPU_TIMER_IRQ); +#if 0 if (cpu_has_veic) { set_vi_handler (MSC01E_INT_CPUCTR, mips_timer_dispatch); mips_cpu_timer_irq = MSC01E_INT_BASE + MSC01E_INT_CPUCTR; @@ -272,24 +260,14 @@ set_vi_handler (MIPSCPU_INT_CPUCTR, mips_timer_dispatch); mips_cpu_timer_irq = MIPSCPU_INT_BASE + MIPSCPU_INT_CPUCTR; } - +#endif /* we are using the cpu counter for timer interrupts */ - irq->handler = mips_timer_interrupt; /* we use our own handler */ -#ifdef CONFIG_MIPS_MT_SMTC - setup_irq_smtc(mips_cpu_timer_irq, irq, CPUCTR_IMASKBIT); -#else - setup_irq(mips_cpu_timer_irq, irq); -#endif /* CONFIG_MIPS_MT_SMTC */ - -#ifdef CONFIG_SMP - /* irq_desc(riptor) is a global resource, when the interrupt overlaps - on seperate cpu's the first one tries to handle the second interrupt. - The effect is that the int remains disabled on the second cpu. - Mark the interrupt with IRQ_PER_CPU to avoid any confusion */ - irq_desc[mips_cpu_timer_irq].status |= IRQ_PER_CPU; -#endif + irq->handler = no_action; /* we use our own handler */ + setup_irq(MIPS_CPU_TIMER_IRQ, irq); + /*--- setup_irq(mips_cpu_timer_irq, irq); ---*/ - /* to generate the first timer interrupt */ + /* to generate the first timer interrupt */ write_c0_compare (read_c0_count() + mips_hpt_frequency/HZ); + set_c0_status(ALLINTS); }