162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include <linux/init.h> 362306a36Sopenharmony_ci#include <linux/types.h> 462306a36Sopenharmony_ci#include <linux/kernel.h> 562306a36Sopenharmony_ci#include <linux/mm.h> 662306a36Sopenharmony_ci#include <linux/tty.h> 762306a36Sopenharmony_ci#include <linux/console.h> 862306a36Sopenharmony_ci#include <linux/rtc.h> 962306a36Sopenharmony_ci#include <linux/vt_kern.h> 1062306a36Sopenharmony_ci#include <linux/interrupt.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <asm/setup.h> 1362306a36Sopenharmony_ci#include <asm/bootinfo.h> 1462306a36Sopenharmony_ci#include <asm/bootinfo-apollo.h> 1562306a36Sopenharmony_ci#include <asm/byteorder.h> 1662306a36Sopenharmony_ci#include <asm/apollohw.h> 1762306a36Sopenharmony_ci#include <asm/irq.h> 1862306a36Sopenharmony_ci#include <asm/machdep.h> 1962306a36Sopenharmony_ci#include <asm/config.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ciu_long sio01_physaddr; 2262306a36Sopenharmony_ciu_long sio23_physaddr; 2362306a36Sopenharmony_ciu_long rtc_physaddr; 2462306a36Sopenharmony_ciu_long pica_physaddr; 2562306a36Sopenharmony_ciu_long picb_physaddr; 2662306a36Sopenharmony_ciu_long cpuctrl_physaddr; 2762306a36Sopenharmony_ciu_long timer_physaddr; 2862306a36Sopenharmony_ciu_long apollo_model; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ciextern void dn_sched_init(void); 3162306a36Sopenharmony_ciextern void dn_init_IRQ(void); 3262306a36Sopenharmony_ciextern int dn_dummy_hwclk(int, struct rtc_time *); 3362306a36Sopenharmony_ciextern void dn_dummy_reset(void); 3462306a36Sopenharmony_ci#ifdef CONFIG_HEARTBEAT 3562306a36Sopenharmony_cistatic void dn_heartbeat(int on); 3662306a36Sopenharmony_ci#endif 3762306a36Sopenharmony_cistatic irqreturn_t dn_timer_int(int irq,void *); 3862306a36Sopenharmony_cistatic void dn_get_model(char *model); 3962306a36Sopenharmony_cistatic const char *apollo_models[] = { 4062306a36Sopenharmony_ci [APOLLO_DN3000-APOLLO_DN3000] = "DN3000 (Otter)", 4162306a36Sopenharmony_ci [APOLLO_DN3010-APOLLO_DN3000] = "DN3010 (Otter)", 4262306a36Sopenharmony_ci [APOLLO_DN3500-APOLLO_DN3000] = "DN3500 (Cougar II)", 4362306a36Sopenharmony_ci [APOLLO_DN4000-APOLLO_DN3000] = "DN4000 (Mink)", 4462306a36Sopenharmony_ci [APOLLO_DN4500-APOLLO_DN3000] = "DN4500 (Roadrunner)" 4562306a36Sopenharmony_ci}; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ciint __init apollo_parse_bootinfo(const struct bi_record *record) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci int unknown = 0; 5062306a36Sopenharmony_ci const void *data = record->data; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci switch (be16_to_cpu(record->tag)) { 5362306a36Sopenharmony_ci case BI_APOLLO_MODEL: 5462306a36Sopenharmony_ci apollo_model = be32_to_cpup(data); 5562306a36Sopenharmony_ci break; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci default: 5862306a36Sopenharmony_ci unknown=1; 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci return unknown; 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic void __init dn_setup_model(void) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci pr_info("Apollo hardware found: [%s]\n", 6762306a36Sopenharmony_ci apollo_models[apollo_model - APOLLO_DN3000]); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci switch(apollo_model) { 7062306a36Sopenharmony_ci case APOLLO_UNKNOWN: 7162306a36Sopenharmony_ci panic("Unknown apollo model"); 7262306a36Sopenharmony_ci break; 7362306a36Sopenharmony_ci case APOLLO_DN3000: 7462306a36Sopenharmony_ci case APOLLO_DN3010: 7562306a36Sopenharmony_ci sio01_physaddr=SAU8_SIO01_PHYSADDR; 7662306a36Sopenharmony_ci rtc_physaddr=SAU8_RTC_PHYSADDR; 7762306a36Sopenharmony_ci pica_physaddr=SAU8_PICA; 7862306a36Sopenharmony_ci picb_physaddr=SAU8_PICB; 7962306a36Sopenharmony_ci cpuctrl_physaddr=SAU8_CPUCTRL; 8062306a36Sopenharmony_ci timer_physaddr=SAU8_TIMER; 8162306a36Sopenharmony_ci break; 8262306a36Sopenharmony_ci case APOLLO_DN4000: 8362306a36Sopenharmony_ci sio01_physaddr=SAU7_SIO01_PHYSADDR; 8462306a36Sopenharmony_ci sio23_physaddr=SAU7_SIO23_PHYSADDR; 8562306a36Sopenharmony_ci rtc_physaddr=SAU7_RTC_PHYSADDR; 8662306a36Sopenharmony_ci pica_physaddr=SAU7_PICA; 8762306a36Sopenharmony_ci picb_physaddr=SAU7_PICB; 8862306a36Sopenharmony_ci cpuctrl_physaddr=SAU7_CPUCTRL; 8962306a36Sopenharmony_ci timer_physaddr=SAU7_TIMER; 9062306a36Sopenharmony_ci break; 9162306a36Sopenharmony_ci case APOLLO_DN4500: 9262306a36Sopenharmony_ci panic("Apollo model not yet supported"); 9362306a36Sopenharmony_ci break; 9462306a36Sopenharmony_ci case APOLLO_DN3500: 9562306a36Sopenharmony_ci sio01_physaddr=SAU7_SIO01_PHYSADDR; 9662306a36Sopenharmony_ci sio23_physaddr=SAU7_SIO23_PHYSADDR; 9762306a36Sopenharmony_ci rtc_physaddr=SAU7_RTC_PHYSADDR; 9862306a36Sopenharmony_ci pica_physaddr=SAU7_PICA; 9962306a36Sopenharmony_ci picb_physaddr=SAU7_PICB; 10062306a36Sopenharmony_ci cpuctrl_physaddr=SAU7_CPUCTRL; 10162306a36Sopenharmony_ci timer_physaddr=SAU7_TIMER; 10262306a36Sopenharmony_ci break; 10362306a36Sopenharmony_ci default: 10462306a36Sopenharmony_ci panic("Undefined apollo model"); 10562306a36Sopenharmony_ci break; 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ciint dn_serial_console_wait_key(struct console *co) { 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci while(!(sio01.srb_csrb & 1)) 11462306a36Sopenharmony_ci barrier(); 11562306a36Sopenharmony_ci return sio01.rhrb_thrb; 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_civoid dn_serial_console_write (struct console *co, const char *str,unsigned int count) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci while(count--) { 12162306a36Sopenharmony_ci if (*str == '\n') { 12262306a36Sopenharmony_ci sio01.rhrb_thrb = (unsigned char)'\r'; 12362306a36Sopenharmony_ci while (!(sio01.srb_csrb & 0x4)) 12462306a36Sopenharmony_ci ; 12562306a36Sopenharmony_ci } 12662306a36Sopenharmony_ci sio01.rhrb_thrb = (unsigned char)*str++; 12762306a36Sopenharmony_ci while (!(sio01.srb_csrb & 0x4)) 12862306a36Sopenharmony_ci ; 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_civoid dn_serial_print (const char *str) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci while (*str) { 13562306a36Sopenharmony_ci if (*str == '\n') { 13662306a36Sopenharmony_ci sio01.rhrb_thrb = (unsigned char)'\r'; 13762306a36Sopenharmony_ci while (!(sio01.srb_csrb & 0x4)) 13862306a36Sopenharmony_ci ; 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci sio01.rhrb_thrb = (unsigned char)*str++; 14162306a36Sopenharmony_ci while (!(sio01.srb_csrb & 0x4)) 14262306a36Sopenharmony_ci ; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_civoid __init config_apollo(void) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci int i; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci dn_setup_model(); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci mach_sched_init=dn_sched_init; /* */ 15362306a36Sopenharmony_ci mach_init_IRQ=dn_init_IRQ; 15462306a36Sopenharmony_ci mach_hwclk = dn_dummy_hwclk; /* */ 15562306a36Sopenharmony_ci mach_reset = dn_dummy_reset; /* */ 15662306a36Sopenharmony_ci#ifdef CONFIG_HEARTBEAT 15762306a36Sopenharmony_ci mach_heartbeat = dn_heartbeat; 15862306a36Sopenharmony_ci#endif 15962306a36Sopenharmony_ci mach_get_model = dn_get_model; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci cpuctrl=0xaa00; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci /* clear DMA translation table */ 16462306a36Sopenharmony_ci for(i=0;i<0x400;i++) 16562306a36Sopenharmony_ci addr_xlat_map[i]=0; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ciirqreturn_t dn_timer_int(int irq, void *dev_id) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci volatile unsigned char x; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci legacy_timer_tick(1); 17462306a36Sopenharmony_ci timer_heartbeat(); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci x = *(volatile unsigned char *)(apollo_timer + 3); 17762306a36Sopenharmony_ci x = *(volatile unsigned char *)(apollo_timer + 5); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci return IRQ_HANDLED; 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_civoid dn_sched_init(void) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci /* program timer 1 */ 18562306a36Sopenharmony_ci *(volatile unsigned char *)(apollo_timer + 3) = 0x01; 18662306a36Sopenharmony_ci *(volatile unsigned char *)(apollo_timer + 1) = 0x40; 18762306a36Sopenharmony_ci *(volatile unsigned char *)(apollo_timer + 5) = 0x09; 18862306a36Sopenharmony_ci *(volatile unsigned char *)(apollo_timer + 7) = 0xc4; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci /* enable IRQ of PIC B */ 19162306a36Sopenharmony_ci *(volatile unsigned char *)(pica+1)&=(~8); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci#if 0 19462306a36Sopenharmony_ci pr_info("*(0x10803) %02x\n", 19562306a36Sopenharmony_ci *(volatile unsigned char *)(apollo_timer + 0x3)); 19662306a36Sopenharmony_ci pr_info("*(0x10803) %02x\n", 19762306a36Sopenharmony_ci *(volatile unsigned char *)(apollo_timer + 0x3)); 19862306a36Sopenharmony_ci#endif 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci if (request_irq(IRQ_APOLLO, dn_timer_int, 0, "time", NULL)) 20162306a36Sopenharmony_ci pr_err("Couldn't register timer interrupt\n"); 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ciint dn_dummy_hwclk(int op, struct rtc_time *t) { 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci if(!op) { /* read */ 20862306a36Sopenharmony_ci t->tm_sec=rtc->second; 20962306a36Sopenharmony_ci t->tm_min=rtc->minute; 21062306a36Sopenharmony_ci t->tm_hour=rtc->hours; 21162306a36Sopenharmony_ci t->tm_mday=rtc->day_of_month; 21262306a36Sopenharmony_ci t->tm_wday=rtc->day_of_week; 21362306a36Sopenharmony_ci t->tm_mon = rtc->month - 1; 21462306a36Sopenharmony_ci t->tm_year=rtc->year; 21562306a36Sopenharmony_ci if (t->tm_year < 70) 21662306a36Sopenharmony_ci t->tm_year += 100; 21762306a36Sopenharmony_ci } else { 21862306a36Sopenharmony_ci rtc->second=t->tm_sec; 21962306a36Sopenharmony_ci rtc->minute=t->tm_min; 22062306a36Sopenharmony_ci rtc->hours=t->tm_hour; 22162306a36Sopenharmony_ci rtc->day_of_month=t->tm_mday; 22262306a36Sopenharmony_ci if(t->tm_wday!=-1) 22362306a36Sopenharmony_ci rtc->day_of_week=t->tm_wday; 22462306a36Sopenharmony_ci rtc->month = t->tm_mon + 1; 22562306a36Sopenharmony_ci rtc->year = t->tm_year % 100; 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci return 0; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_civoid dn_dummy_reset(void) { 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci dn_serial_print("The end !\n"); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci for(;;); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_civoid dn_dummy_waitbut(void) { 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci dn_serial_print("waitbut\n"); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistatic void dn_get_model(char *model) 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci strcpy(model, "Apollo "); 24962306a36Sopenharmony_ci if (apollo_model >= APOLLO_DN3000 && apollo_model <= APOLLO_DN4500) 25062306a36Sopenharmony_ci strcat(model, apollo_models[apollo_model - APOLLO_DN3000]); 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci#ifdef CONFIG_HEARTBEAT 25462306a36Sopenharmony_cistatic int dn_cpuctrl=0xff00; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_cistatic void dn_heartbeat(int on) { 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci if(on) { 25962306a36Sopenharmony_ci dn_cpuctrl&=~0x100; 26062306a36Sopenharmony_ci cpuctrl=dn_cpuctrl; 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci else { 26362306a36Sopenharmony_ci dn_cpuctrl&=~0x100; 26462306a36Sopenharmony_ci dn_cpuctrl|=0x100; 26562306a36Sopenharmony_ci cpuctrl=dn_cpuctrl; 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci} 26862306a36Sopenharmony_ci#endif 26962306a36Sopenharmony_ci 270