1 /* 2 * arch/m68k/mvme147/config.c 3 * 4 * Copyright (C) 1996 Dave Frascone [chaos@mindspring.com] 5 * Cloned from Richard Hirst [richard@sleepie.demon.co.uk] 6 * 7 * Based on: 8 * 9 * Copyright (C) 1993 Hamish Macdonald 10 * 11 * This file is subject to the terms and conditions of the GNU General Public 12 * License. See the file README.legal in the main directory of this archive 13 * for more details. 14 */ 15 16 #include <linux/types.h> 17 #include <linux/kernel.h> 18 #include <linux/mm.h> 19 #include <linux/tty.h> 20 #include <linux/clocksource.h> 21 #include <linux/console.h> 22 #include <linux/linkage.h> 23 #include <linux/init.h> 24 #include <linux/major.h> 25 #include <linux/rtc.h> 26 #include <linux/interrupt.h> 27 28 #include <asm/bootinfo.h> 29 #include <asm/bootinfo-vme.h> 30 #include <asm/byteorder.h> 31 #include <asm/setup.h> 32 #include <asm/irq.h> 33 #include <asm/traps.h> 34 #include <asm/machdep.h> 35 #include <asm/mvme147hw.h> 36 #include <asm/config.h> 37 38 #include "mvme147.h" 39 40 static void mvme147_get_model(char *model); 41 extern void mvme147_sched_init(void); 42 extern int mvme147_hwclk (int, struct rtc_time *); 43 extern void mvme147_reset (void); 44 45 46 static int bcd2int (unsigned char b); 47 48 49 int __init mvme147_parse_bootinfo(const struct bi_record *bi) 50 { 51 uint16_t tag = be16_to_cpu(bi->tag); 52 if (tag == BI_VME_TYPE || tag == BI_VME_BRDINFO) 53 return 0; 54 else 55 return 1; 56 } 57 58 void mvme147_reset(void) 59 { 60 pr_info("\r\n\nCalled mvme147_reset\r\n"); 61 m147_pcc->watchdog = 0x0a; /* Clear timer */ 62 m147_pcc->watchdog = 0xa5; /* Enable watchdog - 100ms to reset */ 63 while (1) 64 ; 65 } 66 67 static void mvme147_get_model(char *model) 68 { 69 sprintf(model, "Motorola MVME147"); 70 } 71 72 /* 73 * This function is called during kernel startup to initialize 74 * the mvme147 IRQ handling routines. 75 */ 76 77 void __init mvme147_init_IRQ(void) 78 { 79 m68k_setup_user_interrupt(VEC_USER, 192); 80 } 81 82 void __init config_mvme147(void) 83 { 84 mach_sched_init = mvme147_sched_init; 85 mach_init_IRQ = mvme147_init_IRQ; 86 mach_hwclk = mvme147_hwclk; 87 mach_reset = mvme147_reset; 88 mach_get_model = mvme147_get_model; 89 90 /* Board type is only set by newer versions of vmelilo/tftplilo */ 91 if (!vme_brdtype) 92 vme_brdtype = VME_TYPE_MVME147; 93 } 94 95 static u64 mvme147_read_clk(struct clocksource *cs); 96 97 static struct clocksource mvme147_clk = { 98 .name = "pcc", 99 .rating = 250, 100 .read = mvme147_read_clk, 101 .mask = CLOCKSOURCE_MASK(32), 102 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 103 }; 104 105 static u32 clk_total; 106 107 #define PCC_TIMER_CLOCK_FREQ 160000 108 #define PCC_TIMER_CYCLES (PCC_TIMER_CLOCK_FREQ / HZ) 109 #define PCC_TIMER_PRELOAD (0x10000 - PCC_TIMER_CYCLES) 110 111 /* Using pcc tick timer 1 */ 112 113 static irqreturn_t mvme147_timer_int (int irq, void *dev_id) 114 { 115 unsigned long flags; 116 117 local_irq_save(flags); 118 m147_pcc->t1_cntrl = PCC_TIMER_CLR_OVF | PCC_TIMER_COC_EN | 119 PCC_TIMER_TIC_EN; 120 m147_pcc->t1_int_cntrl = PCC_INT_ENAB | PCC_TIMER_INT_CLR | 121 PCC_LEVEL_TIMER1; 122 clk_total += PCC_TIMER_CYCLES; 123 legacy_timer_tick(1); 124 local_irq_restore(flags); 125 126 return IRQ_HANDLED; 127 } 128 129 130 void mvme147_sched_init (void) 131 { 132 if (request_irq(PCC_IRQ_TIMER1, mvme147_timer_int, IRQF_TIMER, 133 "timer 1", NULL)) 134 pr_err("Couldn't register timer interrupt\n"); 135 136 /* Init the clock with a value */ 137 /* The clock counter increments until 0xFFFF then reloads */ 138 m147_pcc->t1_preload = PCC_TIMER_PRELOAD; 139 m147_pcc->t1_cntrl = PCC_TIMER_CLR_OVF | PCC_TIMER_COC_EN | 140 PCC_TIMER_TIC_EN; 141 m147_pcc->t1_int_cntrl = PCC_INT_ENAB | PCC_TIMER_INT_CLR | 142 PCC_LEVEL_TIMER1; 143 144 clocksource_register_hz(&mvme147_clk, PCC_TIMER_CLOCK_FREQ); 145 } 146 147 static u64 mvme147_read_clk(struct clocksource *cs) 148 { 149 unsigned long flags; 150 u8 overflow, tmp; 151 u16 count; 152 u32 ticks; 153 154 local_irq_save(flags); 155 tmp = m147_pcc->t1_cntrl >> 4; 156 count = m147_pcc->t1_count; 157 overflow = m147_pcc->t1_cntrl >> 4; 158 if (overflow != tmp) 159 count = m147_pcc->t1_count; 160 count -= PCC_TIMER_PRELOAD; 161 ticks = count + overflow * PCC_TIMER_CYCLES; 162 ticks += clk_total; 163 local_irq_restore(flags); 164 165 return ticks; 166 } 167 168 static int bcd2int (unsigned char b) 169 { 170 return ((b>>4)*10 + (b&15)); 171 } 172 173 int mvme147_hwclk(int op, struct rtc_time *t) 174 { 175 if (!op) { 176 m147_rtc->ctrl = RTC_READ; 177 t->tm_year = bcd2int (m147_rtc->bcd_year); 178 t->tm_mon = bcd2int(m147_rtc->bcd_mth) - 1; 179 t->tm_mday = bcd2int (m147_rtc->bcd_dom); 180 t->tm_hour = bcd2int (m147_rtc->bcd_hr); 181 t->tm_min = bcd2int (m147_rtc->bcd_min); 182 t->tm_sec = bcd2int (m147_rtc->bcd_sec); 183 m147_rtc->ctrl = 0; 184 if (t->tm_year < 70) 185 t->tm_year += 100; 186 } else { 187 /* FIXME Setting the time is not yet supported */ 188 return -EOPNOTSUPP; 189 } 190 return 0; 191 } 192 193 static void scc_delay(void) 194 { 195 __asm__ __volatile__ ("nop; nop;"); 196 } 197 198 static void scc_write(char ch) 199 { 200 do { 201 scc_delay(); 202 } while (!(in_8(M147_SCC_A_ADDR) & BIT(2))); 203 scc_delay(); 204 out_8(M147_SCC_A_ADDR, 8); 205 scc_delay(); 206 out_8(M147_SCC_A_ADDR, ch); 207 } 208 209 void mvme147_scc_write(struct console *co, const char *str, unsigned int count) 210 { 211 unsigned long flags; 212 213 local_irq_save(flags); 214 while (count--) { 215 if (*str == '\n') 216 scc_write('\r'); 217 scc_write(*str++); 218 } 219 local_irq_restore(flags); 220 } 221