^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #include <linux/i8253.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/smp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/time.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/clockchips.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <asm/sni.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <asm/time.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #define SNI_CLOCK_TICK_RATE 3686400
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #define SNI_COUNTER2_DIV 64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #define SNI_COUNTER0_DIV ((SNI_CLOCK_TICK_RATE / SNI_COUNTER2_DIV) / HZ)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) static int a20r_set_periodic(struct clock_event_device *evt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) *(volatile u8 *)(A20R_PT_CLOCK_BASE + 12) = 0x34;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) wmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) *(volatile u8 *)(A20R_PT_CLOCK_BASE + 0) = SNI_COUNTER0_DIV & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) wmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) *(volatile u8 *)(A20R_PT_CLOCK_BASE + 0) = SNI_COUNTER0_DIV >> 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) wmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) *(volatile u8 *)(A20R_PT_CLOCK_BASE + 12) = 0xb4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) wmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) *(volatile u8 *)(A20R_PT_CLOCK_BASE + 8) = SNI_COUNTER2_DIV & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) wmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) *(volatile u8 *)(A20R_PT_CLOCK_BASE + 8) = SNI_COUNTER2_DIV >> 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) wmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) static struct clock_event_device a20r_clockevent_device = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) .name = "a20r-timer",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) .features = CLOCK_EVT_FEAT_PERIODIC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) /* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) .rating = 300,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) .irq = SNI_A20R_IRQ_TIMER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) .set_state_periodic = a20r_set_periodic,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) static irqreturn_t a20r_interrupt(int irq, void *dev_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) struct clock_event_device *cd = dev_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) *(volatile u8 *)A20R_PT_TIM0_ACK = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) wmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) cd->event_handler(cd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) * a20r platform uses 2 counters to divide the input frequency.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * Counter 2 output is connected to Counter 0 & 1 input.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) static void __init sni_a20r_timer_setup(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) struct clock_event_device *cd = &a20r_clockevent_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) unsigned int cpu = smp_processor_id();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) cd->cpumask = cpumask_of(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) clockevents_register_device(cd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) if (request_irq(SNI_A20R_IRQ_TIMER, a20r_interrupt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) IRQF_PERCPU | IRQF_TIMER, "a20r-timer", cd))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) pr_err("Failed to register a20r-timer interrupt\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) #define SNI_8254_TICK_RATE 1193182UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) #define SNI_8254_TCSAMP_COUNTER ((SNI_8254_TICK_RATE / HZ) + 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) static __init unsigned long dosample(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) u32 ct0, ct1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) volatile u8 msb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) /* Start the counter. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) outb_p(0x34, 0x43);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) outb_p(SNI_8254_TCSAMP_COUNTER & 0xff, 0x40);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) outb(SNI_8254_TCSAMP_COUNTER >> 8, 0x40);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) /* Get initial counter invariant */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) ct0 = read_c0_count();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) /* Latch and spin until top byte of counter0 is zero */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) outb(0x00, 0x43);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) (void) inb(0x40);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) msb = inb(0x40);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) ct1 = read_c0_count();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) } while (msb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) /* Stop the counter. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) outb(0x38, 0x43);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) * Return the difference, this is how far the r4k counter increments
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) * for every 1/HZ seconds. We round off the nearest 1 MHz of master
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) * clock (= 1000000 / HZ / 2).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) /*return (ct1 - ct0 + (500000/HZ/2)) / (500000/HZ) * (500000/HZ);*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) return (ct1 - ct0) / (500000/HZ) * (500000/HZ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) * Here we need to calibrate the cycle counter to at least be close.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) void __init plat_time_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) unsigned long r4k_ticks[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) unsigned long r4k_tick;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) * Figure out the r4k offset, the algorithm is very simple and works in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) * _all_ cases as long as the 8254 counter register itself works ok (as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) * an interrupt driving timer it does not because of bug, this is why
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) * we are using the onchip r4k counter/compare register to serve this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) * purpose, but for r4k_offset calculation it will work ok for us).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) * There are other very complicated ways of performing this calculation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) * but this one works just fine so I am not going to futz around. ;-)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) printk(KERN_INFO "Calibrating system timer... ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) dosample(); /* Prime cache. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) dosample(); /* Prime cache. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) /* Zero is NOT an option. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) r4k_ticks[0] = dosample();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) } while (!r4k_ticks[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) r4k_ticks[1] = dosample();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) } while (!r4k_ticks[1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) if (r4k_ticks[0] != r4k_ticks[1]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) printk("warning: timer counts differ, retrying... ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) r4k_ticks[2] = dosample();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) if (r4k_ticks[2] == r4k_ticks[0]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) || r4k_ticks[2] == r4k_ticks[1])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) r4k_tick = r4k_ticks[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) printk("disagreement, using average... ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) r4k_tick = (r4k_ticks[0] + r4k_ticks[1]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) + r4k_ticks[2]) / 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) r4k_tick = r4k_ticks[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) printk("%d [%d.%04d MHz CPU]\n", (int) r4k_tick,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) (int) (r4k_tick / (500000 / HZ)),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) (int) (r4k_tick % (500000 / HZ)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) mips_hpt_frequency = r4k_tick * HZ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) switch (sni_brd_type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) case SNI_BRD_10:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) case SNI_BRD_10NEW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) case SNI_BRD_TOWER_OASIC:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) case SNI_BRD_MINITOWER:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) sni_a20r_timer_setup();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) setup_pit_timer();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) }