1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/init.h> 3 #include <linux/types.h> 4 #include <linux/kernel.h> 5 #include <linux/mm.h> 6 #include <linux/tty.h> 7 #include <linux/rtc.h> 8 #include <linux/vt_kern.h> 9 #include <linux/interrupt.h> 10 11 #include <asm/setup.h> 12 #include <asm/bootinfo.h> 13 #include <asm/bootinfo-apollo.h> 14 #include <asm/byteorder.h> 15 #include <asm/apollohw.h> 16 #include <asm/irq.h> 17 #include <asm/machdep.h> 18 #include <asm/config.h> 19 20 #include "apollo.h" 21 22 u_long sio01_physaddr; 23 u_long sio23_physaddr; 24 u_long rtc_physaddr; 25 u_long pica_physaddr; 26 u_long picb_physaddr; 27 u_long cpuctrl_physaddr; 28 u_long timer_physaddr; 29 u_long apollo_model; 30 31 extern void dn_sched_init(void); 32 extern int dn_dummy_hwclk(int, struct rtc_time *); 33 static void dn_dummy_reset(void); 34 #ifdef CONFIG_HEARTBEAT 35 static void dn_heartbeat(int on); 36 #endif 37 static irqreturn_t dn_timer_int(int irq,void *); 38 static void dn_get_model(char *model); 39 static const char *apollo_models[] = { 40 [APOLLO_DN3000-APOLLO_DN3000] = "DN3000 (Otter)", 41 [APOLLO_DN3010-APOLLO_DN3000] = "DN3010 (Otter)", 42 [APOLLO_DN3500-APOLLO_DN3000] = "DN3500 (Cougar II)", 43 [APOLLO_DN4000-APOLLO_DN3000] = "DN4000 (Mink)", 44 [APOLLO_DN4500-APOLLO_DN3000] = "DN4500 (Roadrunner)" 45 }; 46 47 int __init apollo_parse_bootinfo(const struct bi_record *record) 48 { 49 int unknown = 0; 50 const void *data = record->data; 51 52 switch (be16_to_cpu(record->tag)) { 53 case BI_APOLLO_MODEL: 54 apollo_model = be32_to_cpup(data); 55 break; 56 57 default: 58 unknown=1; 59 } 60 61 return unknown; 62 } 63 64 static void __init dn_setup_model(void) 65 { 66 pr_info("Apollo hardware found: [%s]\n", 67 apollo_models[apollo_model - APOLLO_DN3000]); 68 69 switch(apollo_model) { 70 case APOLLO_UNKNOWN: 71 panic("Unknown apollo model"); 72 break; 73 case APOLLO_DN3000: 74 case APOLLO_DN3010: 75 sio01_physaddr=SAU8_SIO01_PHYSADDR; 76 rtc_physaddr=SAU8_RTC_PHYSADDR; 77 pica_physaddr=SAU8_PICA; 78 picb_physaddr=SAU8_PICB; 79 cpuctrl_physaddr=SAU8_CPUCTRL; 80 timer_physaddr=SAU8_TIMER; 81 break; 82 case APOLLO_DN4000: 83 sio01_physaddr=SAU7_SIO01_PHYSADDR; 84 sio23_physaddr=SAU7_SIO23_PHYSADDR; 85 rtc_physaddr=SAU7_RTC_PHYSADDR; 86 pica_physaddr=SAU7_PICA; 87 picb_physaddr=SAU7_PICB; 88 cpuctrl_physaddr=SAU7_CPUCTRL; 89 timer_physaddr=SAU7_TIMER; 90 break; 91 case APOLLO_DN4500: 92 panic("Apollo model not yet supported"); 93 break; 94 case APOLLO_DN3500: 95 sio01_physaddr=SAU7_SIO01_PHYSADDR; 96 sio23_physaddr=SAU7_SIO23_PHYSADDR; 97 rtc_physaddr=SAU7_RTC_PHYSADDR; 98 pica_physaddr=SAU7_PICA; 99 picb_physaddr=SAU7_PICB; 100 cpuctrl_physaddr=SAU7_CPUCTRL; 101 timer_physaddr=SAU7_TIMER; 102 break; 103 default: 104 panic("Undefined apollo model"); 105 break; 106 } 107 108 109 } 110 111 static void dn_serial_print(const char *str) 112 { 113 while (*str) { 114 if (*str == '\n') { 115 sio01.rhrb_thrb = (unsigned char)'\r'; 116 while (!(sio01.srb_csrb & 0x4)) 117 ; 118 } 119 sio01.rhrb_thrb = (unsigned char)*str++; 120 while (!(sio01.srb_csrb & 0x4)) 121 ; 122 } 123 } 124 125 void __init config_apollo(void) 126 { 127 int i; 128 129 dn_setup_model(); 130 131 mach_sched_init=dn_sched_init; /* */ 132 mach_init_IRQ=dn_init_IRQ; 133 mach_hwclk = dn_dummy_hwclk; /* */ 134 mach_reset = dn_dummy_reset; /* */ 135 #ifdef CONFIG_HEARTBEAT 136 mach_heartbeat = dn_heartbeat; 137 #endif 138 mach_get_model = dn_get_model; 139 140 cpuctrl=0xaa00; 141 142 /* clear DMA translation table */ 143 for(i=0;i<0x400;i++) 144 addr_xlat_map[i]=0; 145 146 } 147 148 irqreturn_t dn_timer_int(int irq, void *dev_id) 149 { 150 unsigned char *at = (unsigned char *)apollo_timer; 151 152 legacy_timer_tick(1); 153 timer_heartbeat(); 154 155 READ_ONCE(*(at + 3)); 156 READ_ONCE(*(at + 5)); 157 158 return IRQ_HANDLED; 159 } 160 161 void dn_sched_init(void) 162 { 163 /* program timer 1 */ 164 *(volatile unsigned char *)(apollo_timer + 3) = 0x01; 165 *(volatile unsigned char *)(apollo_timer + 1) = 0x40; 166 *(volatile unsigned char *)(apollo_timer + 5) = 0x09; 167 *(volatile unsigned char *)(apollo_timer + 7) = 0xc4; 168 169 /* enable IRQ of PIC B */ 170 *(volatile unsigned char *)(pica+1)&=(~8); 171 172 #if 0 173 pr_info("*(0x10803) %02x\n", 174 *(volatile unsigned char *)(apollo_timer + 0x3)); 175 pr_info("*(0x10803) %02x\n", 176 *(volatile unsigned char *)(apollo_timer + 0x3)); 177 #endif 178 179 if (request_irq(IRQ_APOLLO, dn_timer_int, 0, "time", NULL)) 180 pr_err("Couldn't register timer interrupt\n"); 181 } 182 183 int dn_dummy_hwclk(int op, struct rtc_time *t) { 184 185 186 if(!op) { /* read */ 187 t->tm_sec=rtc->second; 188 t->tm_min=rtc->minute; 189 t->tm_hour=rtc->hours; 190 t->tm_mday=rtc->day_of_month; 191 t->tm_wday=rtc->day_of_week; 192 t->tm_mon = rtc->month - 1; 193 t->tm_year=rtc->year; 194 if (t->tm_year < 70) 195 t->tm_year += 100; 196 } else { 197 rtc->second=t->tm_sec; 198 rtc->minute=t->tm_min; 199 rtc->hours=t->tm_hour; 200 rtc->day_of_month=t->tm_mday; 201 if(t->tm_wday!=-1) 202 rtc->day_of_week=t->tm_wday; 203 rtc->month = t->tm_mon + 1; 204 rtc->year = t->tm_year % 100; 205 } 206 207 return 0; 208 209 } 210 211 static void dn_dummy_reset(void) 212 { 213 dn_serial_print("The end !\n"); 214 215 for(;;); 216 217 } 218 219 static void dn_get_model(char *model) 220 { 221 strcpy(model, "Apollo "); 222 if (apollo_model >= APOLLO_DN3000 && apollo_model <= APOLLO_DN4500) 223 strcat(model, apollo_models[apollo_model - APOLLO_DN3000]); 224 } 225 226 #ifdef CONFIG_HEARTBEAT 227 static int dn_cpuctrl=0xff00; 228 229 static void dn_heartbeat(int on) { 230 231 if(on) { 232 dn_cpuctrl&=~0x100; 233 cpuctrl=dn_cpuctrl; 234 } 235 else { 236 dn_cpuctrl&=~0x100; 237 dn_cpuctrl|=0x100; 238 cpuctrl=dn_cpuctrl; 239 } 240 } 241 #endif 242 243