18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <linux/init.h> 38c2ecf20Sopenharmony_ci#include <linux/types.h> 48c2ecf20Sopenharmony_ci#include <linux/kernel.h> 58c2ecf20Sopenharmony_ci#include <linux/mm.h> 68c2ecf20Sopenharmony_ci#include <linux/tty.h> 78c2ecf20Sopenharmony_ci#include <linux/console.h> 88c2ecf20Sopenharmony_ci#include <linux/rtc.h> 98c2ecf20Sopenharmony_ci#include <linux/vt_kern.h> 108c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <asm/setup.h> 138c2ecf20Sopenharmony_ci#include <asm/bootinfo.h> 148c2ecf20Sopenharmony_ci#include <asm/bootinfo-apollo.h> 158c2ecf20Sopenharmony_ci#include <asm/byteorder.h> 168c2ecf20Sopenharmony_ci#include <asm/apollohw.h> 178c2ecf20Sopenharmony_ci#include <asm/irq.h> 188c2ecf20Sopenharmony_ci#include <asm/machdep.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ciu_long sio01_physaddr; 218c2ecf20Sopenharmony_ciu_long sio23_physaddr; 228c2ecf20Sopenharmony_ciu_long rtc_physaddr; 238c2ecf20Sopenharmony_ciu_long pica_physaddr; 248c2ecf20Sopenharmony_ciu_long picb_physaddr; 258c2ecf20Sopenharmony_ciu_long cpuctrl_physaddr; 268c2ecf20Sopenharmony_ciu_long timer_physaddr; 278c2ecf20Sopenharmony_ciu_long apollo_model; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ciextern void dn_sched_init(irq_handler_t handler); 308c2ecf20Sopenharmony_ciextern void dn_init_IRQ(void); 318c2ecf20Sopenharmony_ciextern int dn_dummy_hwclk(int, struct rtc_time *); 328c2ecf20Sopenharmony_ciextern void dn_dummy_reset(void); 338c2ecf20Sopenharmony_ci#ifdef CONFIG_HEARTBEAT 348c2ecf20Sopenharmony_cistatic void dn_heartbeat(int on); 358c2ecf20Sopenharmony_ci#endif 368c2ecf20Sopenharmony_cistatic irqreturn_t dn_timer_int(int irq,void *); 378c2ecf20Sopenharmony_cistatic void dn_get_model(char *model); 388c2ecf20Sopenharmony_cistatic const char *apollo_models[] = { 398c2ecf20Sopenharmony_ci [APOLLO_DN3000-APOLLO_DN3000] = "DN3000 (Otter)", 408c2ecf20Sopenharmony_ci [APOLLO_DN3010-APOLLO_DN3000] = "DN3010 (Otter)", 418c2ecf20Sopenharmony_ci [APOLLO_DN3500-APOLLO_DN3000] = "DN3500 (Cougar II)", 428c2ecf20Sopenharmony_ci [APOLLO_DN4000-APOLLO_DN3000] = "DN4000 (Mink)", 438c2ecf20Sopenharmony_ci [APOLLO_DN4500-APOLLO_DN3000] = "DN4500 (Roadrunner)" 448c2ecf20Sopenharmony_ci}; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ciint __init apollo_parse_bootinfo(const struct bi_record *record) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci int unknown = 0; 498c2ecf20Sopenharmony_ci const void *data = record->data; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci switch (be16_to_cpu(record->tag)) { 528c2ecf20Sopenharmony_ci case BI_APOLLO_MODEL: 538c2ecf20Sopenharmony_ci apollo_model = be32_to_cpup(data); 548c2ecf20Sopenharmony_ci break; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci default: 578c2ecf20Sopenharmony_ci unknown=1; 588c2ecf20Sopenharmony_ci } 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci return unknown; 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic void __init dn_setup_model(void) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci pr_info("Apollo hardware found: [%s]\n", 668c2ecf20Sopenharmony_ci apollo_models[apollo_model - APOLLO_DN3000]); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci switch(apollo_model) { 698c2ecf20Sopenharmony_ci case APOLLO_UNKNOWN: 708c2ecf20Sopenharmony_ci panic("Unknown apollo model"); 718c2ecf20Sopenharmony_ci break; 728c2ecf20Sopenharmony_ci case APOLLO_DN3000: 738c2ecf20Sopenharmony_ci case APOLLO_DN3010: 748c2ecf20Sopenharmony_ci sio01_physaddr=SAU8_SIO01_PHYSADDR; 758c2ecf20Sopenharmony_ci rtc_physaddr=SAU8_RTC_PHYSADDR; 768c2ecf20Sopenharmony_ci pica_physaddr=SAU8_PICA; 778c2ecf20Sopenharmony_ci picb_physaddr=SAU8_PICB; 788c2ecf20Sopenharmony_ci cpuctrl_physaddr=SAU8_CPUCTRL; 798c2ecf20Sopenharmony_ci timer_physaddr=SAU8_TIMER; 808c2ecf20Sopenharmony_ci break; 818c2ecf20Sopenharmony_ci case APOLLO_DN4000: 828c2ecf20Sopenharmony_ci sio01_physaddr=SAU7_SIO01_PHYSADDR; 838c2ecf20Sopenharmony_ci sio23_physaddr=SAU7_SIO23_PHYSADDR; 848c2ecf20Sopenharmony_ci rtc_physaddr=SAU7_RTC_PHYSADDR; 858c2ecf20Sopenharmony_ci pica_physaddr=SAU7_PICA; 868c2ecf20Sopenharmony_ci picb_physaddr=SAU7_PICB; 878c2ecf20Sopenharmony_ci cpuctrl_physaddr=SAU7_CPUCTRL; 888c2ecf20Sopenharmony_ci timer_physaddr=SAU7_TIMER; 898c2ecf20Sopenharmony_ci break; 908c2ecf20Sopenharmony_ci case APOLLO_DN4500: 918c2ecf20Sopenharmony_ci panic("Apollo model not yet supported"); 928c2ecf20Sopenharmony_ci break; 938c2ecf20Sopenharmony_ci case APOLLO_DN3500: 948c2ecf20Sopenharmony_ci sio01_physaddr=SAU7_SIO01_PHYSADDR; 958c2ecf20Sopenharmony_ci sio23_physaddr=SAU7_SIO23_PHYSADDR; 968c2ecf20Sopenharmony_ci rtc_physaddr=SAU7_RTC_PHYSADDR; 978c2ecf20Sopenharmony_ci pica_physaddr=SAU7_PICA; 988c2ecf20Sopenharmony_ci picb_physaddr=SAU7_PICB; 998c2ecf20Sopenharmony_ci cpuctrl_physaddr=SAU7_CPUCTRL; 1008c2ecf20Sopenharmony_ci timer_physaddr=SAU7_TIMER; 1018c2ecf20Sopenharmony_ci break; 1028c2ecf20Sopenharmony_ci default: 1038c2ecf20Sopenharmony_ci panic("Undefined apollo model"); 1048c2ecf20Sopenharmony_ci break; 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ciint dn_serial_console_wait_key(struct console *co) { 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci while(!(sio01.srb_csrb & 1)) 1138c2ecf20Sopenharmony_ci barrier(); 1148c2ecf20Sopenharmony_ci return sio01.rhrb_thrb; 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_civoid dn_serial_console_write (struct console *co, const char *str,unsigned int count) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci while(count--) { 1208c2ecf20Sopenharmony_ci if (*str == '\n') { 1218c2ecf20Sopenharmony_ci sio01.rhrb_thrb = (unsigned char)'\r'; 1228c2ecf20Sopenharmony_ci while (!(sio01.srb_csrb & 0x4)) 1238c2ecf20Sopenharmony_ci ; 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci sio01.rhrb_thrb = (unsigned char)*str++; 1268c2ecf20Sopenharmony_ci while (!(sio01.srb_csrb & 0x4)) 1278c2ecf20Sopenharmony_ci ; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_civoid dn_serial_print (const char *str) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci while (*str) { 1348c2ecf20Sopenharmony_ci if (*str == '\n') { 1358c2ecf20Sopenharmony_ci sio01.rhrb_thrb = (unsigned char)'\r'; 1368c2ecf20Sopenharmony_ci while (!(sio01.srb_csrb & 0x4)) 1378c2ecf20Sopenharmony_ci ; 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci sio01.rhrb_thrb = (unsigned char)*str++; 1408c2ecf20Sopenharmony_ci while (!(sio01.srb_csrb & 0x4)) 1418c2ecf20Sopenharmony_ci ; 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_civoid __init config_apollo(void) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci int i; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci dn_setup_model(); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci mach_sched_init=dn_sched_init; /* */ 1528c2ecf20Sopenharmony_ci mach_init_IRQ=dn_init_IRQ; 1538c2ecf20Sopenharmony_ci mach_max_dma_address = 0xffffffff; 1548c2ecf20Sopenharmony_ci mach_hwclk = dn_dummy_hwclk; /* */ 1558c2ecf20Sopenharmony_ci mach_reset = dn_dummy_reset; /* */ 1568c2ecf20Sopenharmony_ci#ifdef CONFIG_HEARTBEAT 1578c2ecf20Sopenharmony_ci mach_heartbeat = dn_heartbeat; 1588c2ecf20Sopenharmony_ci#endif 1598c2ecf20Sopenharmony_ci mach_get_model = dn_get_model; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci cpuctrl=0xaa00; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci /* clear DMA translation table */ 1648c2ecf20Sopenharmony_ci for(i=0;i<0x400;i++) 1658c2ecf20Sopenharmony_ci addr_xlat_map[i]=0; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ciirqreturn_t dn_timer_int(int irq, void *dev_id) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci irq_handler_t timer_handler = dev_id; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci volatile unsigned char x; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci timer_handler(irq, dev_id); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci x = *(volatile unsigned char *)(apollo_timer + 3); 1788c2ecf20Sopenharmony_ci x = *(volatile unsigned char *)(apollo_timer + 5); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_civoid dn_sched_init(irq_handler_t timer_routine) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci /* program timer 1 */ 1868c2ecf20Sopenharmony_ci *(volatile unsigned char *)(apollo_timer + 3) = 0x01; 1878c2ecf20Sopenharmony_ci *(volatile unsigned char *)(apollo_timer + 1) = 0x40; 1888c2ecf20Sopenharmony_ci *(volatile unsigned char *)(apollo_timer + 5) = 0x09; 1898c2ecf20Sopenharmony_ci *(volatile unsigned char *)(apollo_timer + 7) = 0xc4; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci /* enable IRQ of PIC B */ 1928c2ecf20Sopenharmony_ci *(volatile unsigned char *)(pica+1)&=(~8); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci#if 0 1958c2ecf20Sopenharmony_ci pr_info("*(0x10803) %02x\n", 1968c2ecf20Sopenharmony_ci *(volatile unsigned char *)(apollo_timer + 0x3)); 1978c2ecf20Sopenharmony_ci pr_info("*(0x10803) %02x\n", 1988c2ecf20Sopenharmony_ci *(volatile unsigned char *)(apollo_timer + 0x3)); 1998c2ecf20Sopenharmony_ci#endif 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci if (request_irq(IRQ_APOLLO, dn_timer_int, 0, "time", timer_routine)) 2028c2ecf20Sopenharmony_ci pr_err("Couldn't register timer interrupt\n"); 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ciint dn_dummy_hwclk(int op, struct rtc_time *t) { 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci if(!op) { /* read */ 2098c2ecf20Sopenharmony_ci t->tm_sec=rtc->second; 2108c2ecf20Sopenharmony_ci t->tm_min=rtc->minute; 2118c2ecf20Sopenharmony_ci t->tm_hour=rtc->hours; 2128c2ecf20Sopenharmony_ci t->tm_mday=rtc->day_of_month; 2138c2ecf20Sopenharmony_ci t->tm_wday=rtc->day_of_week; 2148c2ecf20Sopenharmony_ci t->tm_mon = rtc->month - 1; 2158c2ecf20Sopenharmony_ci t->tm_year=rtc->year; 2168c2ecf20Sopenharmony_ci if (t->tm_year < 70) 2178c2ecf20Sopenharmony_ci t->tm_year += 100; 2188c2ecf20Sopenharmony_ci } else { 2198c2ecf20Sopenharmony_ci rtc->second=t->tm_sec; 2208c2ecf20Sopenharmony_ci rtc->minute=t->tm_min; 2218c2ecf20Sopenharmony_ci rtc->hours=t->tm_hour; 2228c2ecf20Sopenharmony_ci rtc->day_of_month=t->tm_mday; 2238c2ecf20Sopenharmony_ci if(t->tm_wday!=-1) 2248c2ecf20Sopenharmony_ci rtc->day_of_week=t->tm_wday; 2258c2ecf20Sopenharmony_ci rtc->month = t->tm_mon + 1; 2268c2ecf20Sopenharmony_ci rtc->year = t->tm_year % 100; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci return 0; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_civoid dn_dummy_reset(void) { 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci dn_serial_print("The end !\n"); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci for(;;); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_civoid dn_dummy_waitbut(void) { 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci dn_serial_print("waitbut\n"); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic void dn_get_model(char *model) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci strcpy(model, "Apollo "); 2508c2ecf20Sopenharmony_ci if (apollo_model >= APOLLO_DN3000 && apollo_model <= APOLLO_DN4500) 2518c2ecf20Sopenharmony_ci strcat(model, apollo_models[apollo_model - APOLLO_DN3000]); 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci#ifdef CONFIG_HEARTBEAT 2558c2ecf20Sopenharmony_cistatic int dn_cpuctrl=0xff00; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic void dn_heartbeat(int on) { 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci if(on) { 2608c2ecf20Sopenharmony_ci dn_cpuctrl&=~0x100; 2618c2ecf20Sopenharmony_ci cpuctrl=dn_cpuctrl; 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci else { 2648c2ecf20Sopenharmony_ci dn_cpuctrl&=~0x100; 2658c2ecf20Sopenharmony_ci dn_cpuctrl|=0x100; 2668c2ecf20Sopenharmony_ci cpuctrl=dn_cpuctrl; 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci#endif 2708c2ecf20Sopenharmony_ci 271