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