1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 2a4df02a2SGeert Uytterhoeven #include <linux/init.h> 31da177e4SLinus Torvalds #include <linux/types.h> 41da177e4SLinus Torvalds #include <linux/kernel.h> 51da177e4SLinus Torvalds #include <linux/mm.h> 61da177e4SLinus Torvalds #include <linux/tty.h> 71da177e4SLinus Torvalds #include <linux/console.h> 81da177e4SLinus Torvalds #include <linux/rtc.h> 91da177e4SLinus Torvalds #include <linux/vt_kern.h> 101da177e4SLinus Torvalds #include <linux/interrupt.h> 111da177e4SLinus Torvalds 121da177e4SLinus Torvalds #include <asm/setup.h> 131da177e4SLinus Torvalds #include <asm/bootinfo.h> 144c3c522bSGeert Uytterhoeven #include <asm/bootinfo-apollo.h> 15abe48101SGeert Uytterhoeven #include <asm/byteorder.h> 161da177e4SLinus Torvalds #include <asm/pgtable.h> 171da177e4SLinus Torvalds #include <asm/apollohw.h> 181da177e4SLinus Torvalds #include <asm/irq.h> 191da177e4SLinus Torvalds #include <asm/machdep.h> 201da177e4SLinus Torvalds 211da177e4SLinus Torvalds u_long sio01_physaddr; 221da177e4SLinus Torvalds u_long sio23_physaddr; 231da177e4SLinus Torvalds u_long rtc_physaddr; 241da177e4SLinus Torvalds u_long pica_physaddr; 251da177e4SLinus Torvalds u_long picb_physaddr; 261da177e4SLinus Torvalds u_long cpuctrl_physaddr; 271da177e4SLinus Torvalds u_long timer_physaddr; 281da177e4SLinus Torvalds u_long apollo_model; 291da177e4SLinus Torvalds 3040220c1aSDavid Howells extern void dn_sched_init(irq_handler_t handler); 311da177e4SLinus Torvalds extern void dn_init_IRQ(void); 32c8d5ba18SStephen Warren extern u32 dn_gettimeoffset(void); 331da177e4SLinus Torvalds extern int dn_dummy_hwclk(int, struct rtc_time *); 341da177e4SLinus Torvalds extern int dn_dummy_set_clock_mmss(unsigned long); 351da177e4SLinus Torvalds extern void dn_dummy_reset(void); 361da177e4SLinus Torvalds #ifdef CONFIG_HEARTBEAT 371da177e4SLinus Torvalds static void dn_heartbeat(int on); 381da177e4SLinus Torvalds #endif 392850bc27SAl Viro static irqreturn_t dn_timer_int(int irq,void *); 401da177e4SLinus Torvalds static void dn_get_model(char *model); 411da177e4SLinus Torvalds static const char *apollo_models[] = { 421da177e4SLinus Torvalds [APOLLO_DN3000-APOLLO_DN3000] = "DN3000 (Otter)", 431da177e4SLinus Torvalds [APOLLO_DN3010-APOLLO_DN3000] = "DN3010 (Otter)", 441da177e4SLinus Torvalds [APOLLO_DN3500-APOLLO_DN3000] = "DN3500 (Cougar II)", 451da177e4SLinus Torvalds [APOLLO_DN4000-APOLLO_DN3000] = "DN4000 (Mink)", 461da177e4SLinus Torvalds [APOLLO_DN4500-APOLLO_DN3000] = "DN4500 (Roadrunner)" 471da177e4SLinus Torvalds }; 481da177e4SLinus Torvalds 49a4df02a2SGeert Uytterhoeven int __init apollo_parse_bootinfo(const struct bi_record *record) 50a4df02a2SGeert Uytterhoeven { 511da177e4SLinus Torvalds int unknown = 0; 52abe48101SGeert Uytterhoeven const void *data = record->data; 531da177e4SLinus Torvalds 54abe48101SGeert Uytterhoeven switch (be16_to_cpu(record->tag)) { 551da177e4SLinus Torvalds case BI_APOLLO_MODEL: 56abe48101SGeert Uytterhoeven apollo_model = be32_to_cpup(data); 571da177e4SLinus Torvalds break; 581da177e4SLinus Torvalds 591da177e4SLinus Torvalds default: 601da177e4SLinus Torvalds unknown=1; 611da177e4SLinus Torvalds } 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds return unknown; 641da177e4SLinus Torvalds } 651da177e4SLinus Torvalds 66a4df02a2SGeert Uytterhoeven static void __init dn_setup_model(void) 67a4df02a2SGeert Uytterhoeven { 68ce00aa0aSFabian Frederick pr_info("Apollo hardware found: [%s]\n", 69ce00aa0aSFabian Frederick apollo_models[apollo_model - APOLLO_DN3000]); 701da177e4SLinus Torvalds 711da177e4SLinus Torvalds switch(apollo_model) { 721da177e4SLinus Torvalds case APOLLO_UNKNOWN: 731da177e4SLinus Torvalds panic("Unknown apollo model"); 741da177e4SLinus Torvalds break; 751da177e4SLinus Torvalds case APOLLO_DN3000: 761da177e4SLinus Torvalds case APOLLO_DN3010: 771da177e4SLinus Torvalds sio01_physaddr=SAU8_SIO01_PHYSADDR; 781da177e4SLinus Torvalds rtc_physaddr=SAU8_RTC_PHYSADDR; 791da177e4SLinus Torvalds pica_physaddr=SAU8_PICA; 801da177e4SLinus Torvalds picb_physaddr=SAU8_PICB; 811da177e4SLinus Torvalds cpuctrl_physaddr=SAU8_CPUCTRL; 821da177e4SLinus Torvalds timer_physaddr=SAU8_TIMER; 831da177e4SLinus Torvalds break; 841da177e4SLinus Torvalds case APOLLO_DN4000: 851da177e4SLinus Torvalds sio01_physaddr=SAU7_SIO01_PHYSADDR; 861da177e4SLinus Torvalds sio23_physaddr=SAU7_SIO23_PHYSADDR; 871da177e4SLinus Torvalds rtc_physaddr=SAU7_RTC_PHYSADDR; 881da177e4SLinus Torvalds pica_physaddr=SAU7_PICA; 891da177e4SLinus Torvalds picb_physaddr=SAU7_PICB; 901da177e4SLinus Torvalds cpuctrl_physaddr=SAU7_CPUCTRL; 911da177e4SLinus Torvalds timer_physaddr=SAU7_TIMER; 921da177e4SLinus Torvalds break; 931da177e4SLinus Torvalds case APOLLO_DN4500: 941da177e4SLinus Torvalds panic("Apollo model not yet supported"); 951da177e4SLinus Torvalds break; 961da177e4SLinus Torvalds case APOLLO_DN3500: 971da177e4SLinus Torvalds sio01_physaddr=SAU7_SIO01_PHYSADDR; 981da177e4SLinus Torvalds sio23_physaddr=SAU7_SIO23_PHYSADDR; 991da177e4SLinus Torvalds rtc_physaddr=SAU7_RTC_PHYSADDR; 1001da177e4SLinus Torvalds pica_physaddr=SAU7_PICA; 1011da177e4SLinus Torvalds picb_physaddr=SAU7_PICB; 1021da177e4SLinus Torvalds cpuctrl_physaddr=SAU7_CPUCTRL; 1031da177e4SLinus Torvalds timer_physaddr=SAU7_TIMER; 1041da177e4SLinus Torvalds break; 1051da177e4SLinus Torvalds default: 1061da177e4SLinus Torvalds panic("Undefined apollo model"); 1071da177e4SLinus Torvalds break; 1081da177e4SLinus Torvalds } 1091da177e4SLinus Torvalds 1101da177e4SLinus Torvalds 1111da177e4SLinus Torvalds } 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds int dn_serial_console_wait_key(struct console *co) { 1141da177e4SLinus Torvalds 1151da177e4SLinus Torvalds while(!(sio01.srb_csrb & 1)) 1161da177e4SLinus Torvalds barrier(); 1171da177e4SLinus Torvalds return sio01.rhrb_thrb; 1181da177e4SLinus Torvalds } 1191da177e4SLinus Torvalds 1201da177e4SLinus Torvalds void dn_serial_console_write (struct console *co, const char *str,unsigned int count) 1211da177e4SLinus Torvalds { 1221da177e4SLinus Torvalds while(count--) { 1231da177e4SLinus Torvalds if (*str == '\n') { 1241da177e4SLinus Torvalds sio01.rhrb_thrb = (unsigned char)'\r'; 1251da177e4SLinus Torvalds while (!(sio01.srb_csrb & 0x4)) 1261da177e4SLinus Torvalds ; 1271da177e4SLinus Torvalds } 1281da177e4SLinus Torvalds sio01.rhrb_thrb = (unsigned char)*str++; 1291da177e4SLinus Torvalds while (!(sio01.srb_csrb & 0x4)) 1301da177e4SLinus Torvalds ; 1311da177e4SLinus Torvalds } 1321da177e4SLinus Torvalds } 1331da177e4SLinus Torvalds 1341da177e4SLinus Torvalds void dn_serial_print (const char *str) 1351da177e4SLinus Torvalds { 1361da177e4SLinus Torvalds while (*str) { 1371da177e4SLinus Torvalds if (*str == '\n') { 1381da177e4SLinus Torvalds sio01.rhrb_thrb = (unsigned char)'\r'; 1391da177e4SLinus Torvalds while (!(sio01.srb_csrb & 0x4)) 1401da177e4SLinus Torvalds ; 1411da177e4SLinus Torvalds } 1421da177e4SLinus Torvalds sio01.rhrb_thrb = (unsigned char)*str++; 1431da177e4SLinus Torvalds while (!(sio01.srb_csrb & 0x4)) 1441da177e4SLinus Torvalds ; 1451da177e4SLinus Torvalds } 1461da177e4SLinus Torvalds } 1471da177e4SLinus Torvalds 14866a3f820SAl Viro void __init config_apollo(void) 14966a3f820SAl Viro { 1501da177e4SLinus Torvalds int i; 1511da177e4SLinus Torvalds 1521da177e4SLinus Torvalds dn_setup_model(); 1531da177e4SLinus Torvalds 1541da177e4SLinus Torvalds mach_sched_init=dn_sched_init; /* */ 1551da177e4SLinus Torvalds mach_init_IRQ=dn_init_IRQ; 156c8d5ba18SStephen Warren arch_gettimeoffset = dn_gettimeoffset; 1571da177e4SLinus Torvalds mach_max_dma_address = 0xffffffff; 1581da177e4SLinus Torvalds mach_hwclk = dn_dummy_hwclk; /* */ 1591da177e4SLinus Torvalds mach_set_clock_mmss = dn_dummy_set_clock_mmss; /* */ 1601da177e4SLinus Torvalds mach_reset = dn_dummy_reset; /* */ 1611da177e4SLinus Torvalds #ifdef CONFIG_HEARTBEAT 1621da177e4SLinus Torvalds mach_heartbeat = dn_heartbeat; 1631da177e4SLinus Torvalds #endif 1641da177e4SLinus Torvalds mach_get_model = dn_get_model; 1651da177e4SLinus Torvalds 1661da177e4SLinus Torvalds cpuctrl=0xaa00; 1671da177e4SLinus Torvalds 1681da177e4SLinus Torvalds /* clear DMA translation table */ 1691da177e4SLinus Torvalds for(i=0;i<0x400;i++) 1701da177e4SLinus Torvalds addr_xlat_map[i]=0; 1711da177e4SLinus Torvalds 1721da177e4SLinus Torvalds } 1731da177e4SLinus Torvalds 1742850bc27SAl Viro irqreturn_t dn_timer_int(int irq, void *dev_id) 1750aa78106SRoman Zippel { 17640220c1aSDavid Howells irq_handler_t timer_handler = dev_id; 1771da177e4SLinus Torvalds 1781da177e4SLinus Torvalds volatile unsigned char x; 1791da177e4SLinus Torvalds 1802850bc27SAl Viro timer_handler(irq, dev_id); 1811da177e4SLinus Torvalds 1821525e06eSGeert Uytterhoeven x = *(volatile unsigned char *)(apollo_timer + 3); 1831525e06eSGeert Uytterhoeven x = *(volatile unsigned char *)(apollo_timer + 5); 1841da177e4SLinus Torvalds 1851da177e4SLinus Torvalds return IRQ_HANDLED; 1861da177e4SLinus Torvalds } 1871da177e4SLinus Torvalds 18840220c1aSDavid Howells void dn_sched_init(irq_handler_t timer_routine) 1892850bc27SAl Viro { 1901da177e4SLinus Torvalds /* program timer 1 */ 1911525e06eSGeert Uytterhoeven *(volatile unsigned char *)(apollo_timer + 3) = 0x01; 1921525e06eSGeert Uytterhoeven *(volatile unsigned char *)(apollo_timer + 1) = 0x40; 1931525e06eSGeert Uytterhoeven *(volatile unsigned char *)(apollo_timer + 5) = 0x09; 1941525e06eSGeert Uytterhoeven *(volatile unsigned char *)(apollo_timer + 7) = 0xc4; 1951da177e4SLinus Torvalds 1961da177e4SLinus Torvalds /* enable IRQ of PIC B */ 1971da177e4SLinus Torvalds *(volatile unsigned char *)(pica+1)&=(~8); 1981da177e4SLinus Torvalds 1991da177e4SLinus Torvalds #if 0 200ce00aa0aSFabian Frederick pr_info("*(0x10803) %02x\n", 201ce00aa0aSFabian Frederick *(volatile unsigned char *)(apollo_timer + 0x3)); 202ce00aa0aSFabian Frederick pr_info("*(0x10803) %02x\n", 203ce00aa0aSFabian Frederick *(volatile unsigned char *)(apollo_timer + 0x3)); 2041da177e4SLinus Torvalds #endif 2051da177e4SLinus Torvalds 20684430653SGeert Uytterhoeven if (request_irq(IRQ_APOLLO, dn_timer_int, 0, "time", timer_routine)) 20784430653SGeert Uytterhoeven pr_err("Couldn't register timer interrupt\n"); 2081da177e4SLinus Torvalds } 2091da177e4SLinus Torvalds 210c8d5ba18SStephen Warren u32 dn_gettimeoffset(void) 211c8d5ba18SStephen Warren { 2121da177e4SLinus Torvalds return 0xdeadbeef; 2131da177e4SLinus Torvalds } 2141da177e4SLinus Torvalds 2151da177e4SLinus Torvalds int dn_dummy_hwclk(int op, struct rtc_time *t) { 2161da177e4SLinus Torvalds 2171da177e4SLinus Torvalds 2181da177e4SLinus Torvalds if(!op) { /* read */ 2191da177e4SLinus Torvalds t->tm_sec=rtc->second; 2201da177e4SLinus Torvalds t->tm_min=rtc->minute; 2211da177e4SLinus Torvalds t->tm_hour=rtc->hours; 2221da177e4SLinus Torvalds t->tm_mday=rtc->day_of_month; 2231da177e4SLinus Torvalds t->tm_wday=rtc->day_of_week; 224*b65769fcSFinn Thain t->tm_mon = rtc->month - 1; 2251da177e4SLinus Torvalds t->tm_year=rtc->year; 226*b65769fcSFinn Thain if (t->tm_year < 70) 227*b65769fcSFinn Thain t->tm_year += 100; 2281da177e4SLinus Torvalds } else { 2291da177e4SLinus Torvalds rtc->second=t->tm_sec; 2301da177e4SLinus Torvalds rtc->minute=t->tm_min; 2311da177e4SLinus Torvalds rtc->hours=t->tm_hour; 2321da177e4SLinus Torvalds rtc->day_of_month=t->tm_mday; 2331da177e4SLinus Torvalds if(t->tm_wday!=-1) 2341da177e4SLinus Torvalds rtc->day_of_week=t->tm_wday; 235*b65769fcSFinn Thain rtc->month = t->tm_mon + 1; 236*b65769fcSFinn Thain rtc->year = t->tm_year % 100; 2371da177e4SLinus Torvalds } 2381da177e4SLinus Torvalds 2391da177e4SLinus Torvalds return 0; 2401da177e4SLinus Torvalds 2411da177e4SLinus Torvalds } 2421da177e4SLinus Torvalds 243ce00aa0aSFabian Frederick int dn_dummy_set_clock_mmss(unsigned long nowtime) 244ce00aa0aSFabian Frederick { 245ce00aa0aSFabian Frederick pr_info("set_clock_mmss\n"); 2461da177e4SLinus Torvalds return 0; 2471da177e4SLinus Torvalds } 2481da177e4SLinus Torvalds 2491da177e4SLinus Torvalds void dn_dummy_reset(void) { 2501da177e4SLinus Torvalds 2511da177e4SLinus Torvalds dn_serial_print("The end !\n"); 2521da177e4SLinus Torvalds 2531da177e4SLinus Torvalds for(;;); 2541da177e4SLinus Torvalds 2551da177e4SLinus Torvalds } 2561da177e4SLinus Torvalds 2571da177e4SLinus Torvalds void dn_dummy_waitbut(void) { 2581da177e4SLinus Torvalds 2591da177e4SLinus Torvalds dn_serial_print("waitbut\n"); 2601da177e4SLinus Torvalds 2611da177e4SLinus Torvalds } 2621da177e4SLinus Torvalds 2631da177e4SLinus Torvalds static void dn_get_model(char *model) 2641da177e4SLinus Torvalds { 2651da177e4SLinus Torvalds strcpy(model, "Apollo "); 2661da177e4SLinus Torvalds if (apollo_model >= APOLLO_DN3000 && apollo_model <= APOLLO_DN4500) 2671da177e4SLinus Torvalds strcat(model, apollo_models[apollo_model - APOLLO_DN3000]); 2681da177e4SLinus Torvalds } 2691da177e4SLinus Torvalds 2701da177e4SLinus Torvalds #ifdef CONFIG_HEARTBEAT 2711da177e4SLinus Torvalds static int dn_cpuctrl=0xff00; 2721da177e4SLinus Torvalds 2731da177e4SLinus Torvalds static void dn_heartbeat(int on) { 2741da177e4SLinus Torvalds 2751da177e4SLinus Torvalds if(on) { 2761da177e4SLinus Torvalds dn_cpuctrl&=~0x100; 2771da177e4SLinus Torvalds cpuctrl=dn_cpuctrl; 2781da177e4SLinus Torvalds } 2791da177e4SLinus Torvalds else { 2801da177e4SLinus Torvalds dn_cpuctrl&=~0x100; 2811da177e4SLinus Torvalds dn_cpuctrl|=0x100; 2821da177e4SLinus Torvalds cpuctrl=dn_cpuctrl; 2831da177e4SLinus Torvalds } 2841da177e4SLinus Torvalds } 2851da177e4SLinus Torvalds #endif 2861da177e4SLinus Torvalds 287