diff options
| -rw-r--r-- | arch/mips/sibyte/sb1250/time.c | 73 | ||||
| -rw-r--r-- | arch/mips/sibyte/swarm/setup.c | 7 | ||||
| -rw-r--r-- | include/asm-mips/sibyte/sb1250.h | 2 |
3 files changed, 64 insertions, 18 deletions
diff --git a/arch/mips/sibyte/sb1250/time.c b/arch/mips/sibyte/sb1250/time.c index adc0b5271a06..1588f6debd90 100644 --- a/arch/mips/sibyte/sb1250/time.c +++ b/arch/mips/sibyte/sb1250/time.c | |||
| @@ -47,23 +47,51 @@ | |||
| 47 | #define IMR_IP3_VAL K_INT_MAP_I1 | 47 | #define IMR_IP3_VAL K_INT_MAP_I1 |
| 48 | #define IMR_IP4_VAL K_INT_MAP_I2 | 48 | #define IMR_IP4_VAL K_INT_MAP_I2 |
| 49 | 49 | ||
| 50 | #define SB1250_HPT_NUM 3 | ||
| 51 | #define SB1250_HPT_VALUE M_SCD_TIMER_CNT /* max value */ | ||
| 52 | #define SB1250_HPT_SHIFT ((sizeof(unsigned int)*8)-V_SCD_TIMER_WIDTH) | ||
| 53 | |||
| 54 | |||
| 50 | extern int sb1250_steal_irq(int irq); | 55 | extern int sb1250_steal_irq(int irq); |
| 51 | 56 | ||
| 57 | static unsigned int sb1250_hpt_read(void); | ||
| 58 | static void sb1250_hpt_init(unsigned int); | ||
| 59 | |||
| 60 | static unsigned int hpt_offset; | ||
| 61 | |||
| 62 | void __init sb1250_hpt_setup(void) | ||
| 63 | { | ||
| 64 | int cpu = smp_processor_id(); | ||
| 65 | |||
| 66 | if (!cpu) { | ||
| 67 | /* Setup hpt using timer #3 but do not enable irq for it */ | ||
| 68 | __raw_writeq(0, IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_CFG))); | ||
| 69 | __raw_writeq(SB1250_HPT_VALUE, | ||
| 70 | IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_INIT))); | ||
| 71 | __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, | ||
| 72 | IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_CFG))); | ||
| 73 | |||
| 74 | /* | ||
| 75 | * we need to fill 32 bits, so just use the upper 23 bits and pretend | ||
| 76 | * the timer is going 512Mhz instead of 1Mhz | ||
| 77 | */ | ||
| 78 | mips_hpt_frequency = V_SCD_TIMER_FREQ << SB1250_HPT_SHIFT; | ||
| 79 | mips_hpt_init = sb1250_hpt_init; | ||
| 80 | mips_hpt_read = sb1250_hpt_read; | ||
| 81 | } | ||
| 82 | } | ||
| 83 | |||
| 84 | |||
| 52 | void sb1250_time_init(void) | 85 | void sb1250_time_init(void) |
| 53 | { | 86 | { |
| 54 | int cpu = smp_processor_id(); | 87 | int cpu = smp_processor_id(); |
| 55 | int irq = K_INT_TIMER_0+cpu; | 88 | int irq = K_INT_TIMER_0+cpu; |
| 56 | 89 | ||
| 57 | /* Only have 4 general purpose timers */ | 90 | /* Only have 4 general purpose timers, and we use last one as hpt */ |
| 58 | if (cpu > 3) { | 91 | if (cpu > 2) { |
| 59 | BUG(); | 92 | BUG(); |
| 60 | } | 93 | } |
| 61 | 94 | ||
| 62 | if (!cpu) { | ||
| 63 | /* Use our own gettimeoffset() routine */ | ||
| 64 | do_gettimeoffset = sb1250_gettimeoffset; | ||
| 65 | } | ||
| 66 | |||
| 67 | sb1250_mask_irq(cpu, irq); | 95 | sb1250_mask_irq(cpu, irq); |
| 68 | 96 | ||
| 69 | /* Map the timer interrupt to ip[4] of this cpu */ | 97 | /* Map the timer interrupt to ip[4] of this cpu */ |
| @@ -103,7 +131,7 @@ void sb1250_timer_interrupt(struct pt_regs *regs) | |||
| 103 | int cpu = smp_processor_id(); | 131 | int cpu = smp_processor_id(); |
| 104 | int irq = K_INT_TIMER_0 + cpu; | 132 | int irq = K_INT_TIMER_0 + cpu; |
| 105 | 133 | ||
| 106 | /* Reset the timer */ | 134 | /* ACK interrupt */ |
| 107 | ____raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, | 135 | ____raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, |
| 108 | IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG))); | 136 | IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG))); |
| 109 | 137 | ||
| @@ -122,15 +150,26 @@ void sb1250_timer_interrupt(struct pt_regs *regs) | |||
| 122 | } | 150 | } |
| 123 | 151 | ||
| 124 | /* | 152 | /* |
| 125 | * We use our own do_gettimeoffset() instead of the generic one, | 153 | * The HPT is free running from SB1250_HPT_VALUE down to 0 then starts over |
| 126 | * because the generic one does not work for SMP case. | 154 | * again. There's no easy way to set to a specific value so store init value |
| 127 | * In addition, since we use general timer 0 for system time, | 155 | * in hpt_offset and subtract each time. |
| 128 | * we can get accurate intra-jiffy offset without calibration. | 156 | * |
| 157 | * Note: Timer isn't full 32bits so shift it into the upper part making | ||
| 158 | * it appear to run at a higher frequency. | ||
| 129 | */ | 159 | */ |
| 130 | unsigned long sb1250_gettimeoffset(void) | 160 | static unsigned int sb1250_hpt_read(void) |
| 131 | { | 161 | { |
| 132 | unsigned long count = | 162 | unsigned int count; |
| 133 | __raw_readq(IOADDR(A_SCD_TIMER_REGISTER(0, R_SCD_TIMER_CNT))); | ||
| 134 | 163 | ||
| 135 | return 1000000/HZ - count; | 164 | count = G_SCD_TIMER_CNT(__raw_readq(IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, R_SCD_TIMER_CNT)))); |
| 136 | } | 165 | |
| 166 | count = (SB1250_HPT_VALUE - count) << SB1250_HPT_SHIFT; | ||
| 167 | |||
| 168 | return count - hpt_offset; | ||
| 169 | } | ||
| 170 | |||
| 171 | static void sb1250_hpt_init(unsigned int count) | ||
| 172 | { | ||
| 173 | hpt_offset = count; | ||
| 174 | return; | ||
| 175 | } | ||
diff --git a/arch/mips/sibyte/swarm/setup.c b/arch/mips/sibyte/swarm/setup.c index b614ca0ddb69..b661d2425a36 100644 --- a/arch/mips/sibyte/swarm/setup.c +++ b/arch/mips/sibyte/swarm/setup.c | |||
| @@ -70,6 +70,12 @@ const char *get_system_type(void) | |||
| 70 | return "SiByte " SIBYTE_BOARD_NAME; | 70 | return "SiByte " SIBYTE_BOARD_NAME; |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | void __init swarm_time_init(void) | ||
| 74 | { | ||
| 75 | /* Setup HPT */ | ||
| 76 | sb1250_hpt_setup(); | ||
| 77 | } | ||
| 78 | |||
| 73 | void __init swarm_timer_setup(struct irqaction *irq) | 79 | void __init swarm_timer_setup(struct irqaction *irq) |
| 74 | { | 80 | { |
| 75 | /* | 81 | /* |
| @@ -109,6 +115,7 @@ void __init plat_setup(void) | |||
| 109 | 115 | ||
| 110 | panic_timeout = 5; /* For debug. */ | 116 | panic_timeout = 5; /* For debug. */ |
| 111 | 117 | ||
| 118 | board_time_init = swarm_time_init; | ||
| 112 | board_timer_setup = swarm_timer_setup; | 119 | board_timer_setup = swarm_timer_setup; |
| 113 | board_be_handler = swarm_be_handler; | 120 | board_be_handler = swarm_be_handler; |
| 114 | 121 | ||
diff --git a/include/asm-mips/sibyte/sb1250.h b/include/asm-mips/sibyte/sb1250.h index a474c29cd701..b09e16c93ca0 100644 --- a/include/asm-mips/sibyte/sb1250.h +++ b/include/asm-mips/sibyte/sb1250.h | |||
| @@ -45,8 +45,8 @@ extern unsigned int soc_type; | |||
| 45 | extern unsigned int periph_rev; | 45 | extern unsigned int periph_rev; |
| 46 | extern unsigned int zbbus_mhz; | 46 | extern unsigned int zbbus_mhz; |
| 47 | 47 | ||
| 48 | extern void sb1250_hpt_setup(void); | ||
| 48 | extern void sb1250_time_init(void); | 49 | extern void sb1250_time_init(void); |
| 49 | extern unsigned long sb1250_gettimeoffset(void); | ||
| 50 | extern void sb1250_mask_irq(int cpu, int irq); | 50 | extern void sb1250_mask_irq(int cpu, int irq); |
| 51 | extern void sb1250_unmask_irq(int cpu, int irq); | 51 | extern void sb1250_unmask_irq(int cpu, int irq); |
| 52 | extern void sb1250_smp_finish(void); | 52 | extern void sb1250_smp_finish(void); |
