^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * arch/m68k/bvme6000/config.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 1997 Richard Hirst [richard@sleepie.demon.co.uk]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Based on:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * linux/amiga/config.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Copyright (C) 1993 Hamish Macdonald
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * This file is subject to the terms and conditions of the GNU General Public
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * License. See the file README.legal in the main directory of this archive
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * for more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/tty.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/clocksource.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/console.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/linkage.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/major.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/genhd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/rtc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/bcd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <asm/bootinfo.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <asm/bootinfo-vme.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <asm/byteorder.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include <asm/setup.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #include <asm/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #include <asm/traps.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #include <asm/machdep.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #include <asm/bvme6000hw.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) static void bvme6000_get_model(char *model);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) extern void bvme6000_sched_init(irq_handler_t handler);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) extern int bvme6000_hwclk (int, struct rtc_time *);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) extern void bvme6000_reset (void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) void bvme6000_set_vectors (void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) int __init bvme6000_parse_bootinfo(const struct bi_record *bi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) if (be16_to_cpu(bi->tag) == BI_VME_TYPE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) void bvme6000_reset(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) volatile PitRegsPtr pit = (PitRegsPtr)BVME_PIT_BASE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) pr_info("\r\n\nCalled bvme6000_reset\r\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) "\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) /* The string of returns is to delay the reset until the whole
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) * message is output. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) /* Enable the watchdog, via PIT port C bit 4 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) pit->pcddr |= 0x10; /* WDOG enable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) while(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) static void bvme6000_get_model(char *model)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) sprintf(model, "BVME%d000", m68k_cputype == CPU_68060 ? 6 : 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) * This function is called during kernel startup to initialize
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * the bvme6000 IRQ handling routines.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) static void __init bvme6000_init_IRQ(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) m68k_setup_user_interrupt(VEC_USER, 192);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) void __init config_bvme6000(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) volatile PitRegsPtr pit = (PitRegsPtr)BVME_PIT_BASE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) /* Board type is only set by newer versions of vmelilo/tftplilo */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) if (!vme_brdtype) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) if (m68k_cputype == CPU_68060)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) vme_brdtype = VME_TYPE_BVME6000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) vme_brdtype = VME_TYPE_BVME4000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) #if 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) /* Call bvme6000_set_vectors() so ABORT will work, along with BVMBug
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) * debugger. Note trap_init() will splat the abort vector, but
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) * bvme6000_init_IRQ() will put it back again. Hopefully. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) bvme6000_set_vectors();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) mach_max_dma_address = 0xffffffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) mach_sched_init = bvme6000_sched_init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) mach_init_IRQ = bvme6000_init_IRQ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) mach_hwclk = bvme6000_hwclk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) mach_reset = bvme6000_reset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) mach_get_model = bvme6000_get_model;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) pr_info("Board is %sconfigured as a System Controller\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) *config_reg_ptr & BVME_CONFIG_SW1 ? "" : "not ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) /* Now do the PIT configuration */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) pit->pgcr = 0x00; /* Unidirectional 8 bit, no handshake for now */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) pit->psrr = 0x18; /* PIACK and PIRQ functions enabled */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) pit->pacr = 0x00; /* Sub Mode 00, H2 i/p, no DMA */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) pit->padr = 0x00; /* Just to be tidy! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) pit->paddr = 0x00; /* All inputs for now (safest) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) pit->pbcr = 0x80; /* Sub Mode 1x, H4 i/p, no DMA */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) pit->pbdr = 0xbc | (*config_reg_ptr & BVME_CONFIG_SW1 ? 0 : 0x40);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) /* PRI, SYSCON?, Level3, SCC clks from xtal */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) pit->pbddr = 0xf3; /* Mostly outputs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) pit->pcdr = 0x01; /* PA transceiver disabled */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) pit->pcddr = 0x03; /* WDOG disable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) /* Disable snooping for Ethernet and VME accesses */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) bvme_acr_addrctl = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) irqreturn_t bvme6000_abort_int (int irq, void *dev_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) unsigned long *new = (unsigned long *)vectors;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) unsigned long *old = (unsigned long *)0xf8000000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) /* Wait for button release */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) while (*(volatile unsigned char *)BVME_LOCAL_IRQ_STAT & BVME_ABORT_STATUS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) *(new+4) = *(old+4); /* Illegal instruction */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) *(new+9) = *(old+9); /* Trace */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) *(new+47) = *(old+47); /* Trap #15 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) *(new+0x1f) = *(old+0x1f); /* ABORT switch */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) static u64 bvme6000_read_clk(struct clocksource *cs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) static struct clocksource bvme6000_clk = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) .name = "rtc",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) .rating = 250,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) .read = bvme6000_read_clk,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) .mask = CLOCKSOURCE_MASK(32),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) .flags = CLOCK_SOURCE_IS_CONTINUOUS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) static u32 clk_total, clk_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) #define RTC_TIMER_CLOCK_FREQ 8000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) #define RTC_TIMER_CYCLES (RTC_TIMER_CLOCK_FREQ / HZ)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) #define RTC_TIMER_COUNT ((RTC_TIMER_CYCLES / 2) - 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) static irqreturn_t bvme6000_timer_int (int irq, void *dev_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) irq_handler_t timer_routine = dev_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) unsigned char msr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) local_irq_save(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) msr = rtc->msr & 0xc0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) rtc->msr = msr | 0x20; /* Ack the interrupt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) clk_total += RTC_TIMER_CYCLES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) clk_offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) timer_routine(0, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) * Set up the RTC timer 1 to mode 2, so T1 output toggles every 5ms
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) * (40000 x 125ns). It will interrupt every 10ms, when T1 goes low.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) * So, when reading the elapsed time, you should read timer1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) * subtract it from 39999, and then add 40000 if T1 is high.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) * That gives you the number of 125ns ticks in to the 10ms period,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) * so divide by 8 to get the microsecond result.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) void bvme6000_sched_init (irq_handler_t timer_routine)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) unsigned char msr = rtc->msr & 0xc0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) rtc->msr = 0; /* Ensure timer registers accessible */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) if (request_irq(BVME_IRQ_RTC, bvme6000_timer_int, IRQF_TIMER, "timer",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) timer_routine))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) panic ("Couldn't register timer int");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) rtc->t1cr_omr = 0x04; /* Mode 2, ext clk */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) rtc->t1msb = RTC_TIMER_COUNT >> 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) rtc->t1lsb = RTC_TIMER_COUNT & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) rtc->irr_icr1 &= 0xef; /* Route timer 1 to INTR pin */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) rtc->msr = 0x40; /* Access int.cntrl, etc */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) rtc->pfr_icr0 = 0x80; /* Just timer 1 ints enabled */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) rtc->irr_icr1 = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) rtc->t1cr_omr = 0x0a; /* INTR+T1 active lo, push-pull */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) rtc->t0cr_rtmr &= 0xdf; /* Stop timers in standby */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) rtc->msr = 0; /* Access timer 1 control */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) rtc->t1cr_omr = 0x05; /* Mode 2, ext clk, GO */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) rtc->msr = msr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) clocksource_register_hz(&bvme6000_clk, RTC_TIMER_CLOCK_FREQ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) if (request_irq(BVME_IRQ_ABORT, bvme6000_abort_int, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) "abort", bvme6000_abort_int))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) panic ("Couldn't register abort int");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) * NOTE: Don't accept any readings within 5us of rollover, as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) * the T1INT bit may be a little slow getting set. There is also
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) * a fault in the chip, meaning that reads may produce invalid
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) * results...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) static u64 bvme6000_read_clk(struct clocksource *cs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) volatile PitRegsPtr pit = (PitRegsPtr)BVME_PIT_BASE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) unsigned char msr, msb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) unsigned char t1int, t1op;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) u32 v = 800000, ov;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) local_irq_save(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) msr = rtc->msr & 0xc0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) rtc->msr = 0; /* Ensure timer registers accessible */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) ov = v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) t1int = rtc->msr & 0x20;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) t1op = pit->pcdr & 0x04;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) rtc->t1cr_omr |= 0x40; /* Latch timer1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) msb = rtc->t1msb; /* Read timer1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) v = (msb << 8) | rtc->t1lsb; /* Read timer1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) } while (t1int != (rtc->msr & 0x20) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) t1op != (pit->pcdr & 0x04) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) abs(ov-v) > 80 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) v > RTC_TIMER_COUNT - (RTC_TIMER_COUNT / 100));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) v = RTC_TIMER_COUNT - v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) if (!t1op) /* If in second half cycle.. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) v += RTC_TIMER_CYCLES / 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) if (msb > 0 && t1int)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) clk_offset = RTC_TIMER_CYCLES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) rtc->msr = msr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) v += clk_offset + clk_total;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) local_irq_restore(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) return v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) * Looks like op is non-zero for setting the clock, and zero for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) * reading the clock.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) * struct hwclk_time {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) * unsigned sec; 0..59
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) * unsigned min; 0..59
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) * unsigned hour; 0..23
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) * unsigned day; 1..31
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) * unsigned mon; 0..11
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) * unsigned year; 00...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) * int wday; 0..6, 0 is Sunday, -1 means unknown/don't set
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) * };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) int bvme6000_hwclk(int op, struct rtc_time *t)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) unsigned char msr = rtc->msr & 0xc0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) rtc->msr = 0x40; /* Ensure clock and real-time-mode-register
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) * are accessible */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) if (op)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) { /* Write.... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) rtc->t0cr_rtmr = t->tm_year%4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) rtc->bcd_tenms = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) rtc->bcd_sec = bin2bcd(t->tm_sec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) rtc->bcd_min = bin2bcd(t->tm_min);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) rtc->bcd_hr = bin2bcd(t->tm_hour);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) rtc->bcd_dom = bin2bcd(t->tm_mday);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) rtc->bcd_mth = bin2bcd(t->tm_mon + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) rtc->bcd_year = bin2bcd(t->tm_year%100);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) if (t->tm_wday >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) rtc->bcd_dow = bin2bcd(t->tm_wday+1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) rtc->t0cr_rtmr = t->tm_year%4 | 0x08;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) { /* Read.... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) t->tm_sec = bcd2bin(rtc->bcd_sec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) t->tm_min = bcd2bin(rtc->bcd_min);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) t->tm_hour = bcd2bin(rtc->bcd_hr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) t->tm_mday = bcd2bin(rtc->bcd_dom);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) t->tm_mon = bcd2bin(rtc->bcd_mth)-1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) t->tm_year = bcd2bin(rtc->bcd_year);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) if (t->tm_year < 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) t->tm_year += 100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) t->tm_wday = bcd2bin(rtc->bcd_dow)-1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) } while (t->tm_sec != bcd2bin(rtc->bcd_sec));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) rtc->msr = msr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) }