18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/arch/m68k/hp300/config.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 1998 Philip Blundell <philb@gnu.org> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This file contains the HP300-specific initialisation code. It gets 88c2ecf20Sopenharmony_ci * called by setup.c. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/init.h> 138c2ecf20Sopenharmony_ci#include <linux/string.h> 148c2ecf20Sopenharmony_ci#include <linux/kernel.h> 158c2ecf20Sopenharmony_ci#include <linux/console.h> 168c2ecf20Sopenharmony_ci#include <linux/rtc.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <asm/bootinfo.h> 198c2ecf20Sopenharmony_ci#include <asm/bootinfo-hp300.h> 208c2ecf20Sopenharmony_ci#include <asm/byteorder.h> 218c2ecf20Sopenharmony_ci#include <asm/machdep.h> 228c2ecf20Sopenharmony_ci#include <asm/blinken.h> 238c2ecf20Sopenharmony_ci#include <asm/io.h> /* readb() and writeb() */ 248c2ecf20Sopenharmony_ci#include <asm/hp300hw.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include "time.h" 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ciunsigned long hp300_model; 298c2ecf20Sopenharmony_ciunsigned long hp300_uart_scode = -1; 308c2ecf20Sopenharmony_ciunsigned char hp300_ledstate; 318c2ecf20Sopenharmony_ciEXPORT_SYMBOL(hp300_ledstate); 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic char s_hp330[] __initdata = "330"; 348c2ecf20Sopenharmony_cistatic char s_hp340[] __initdata = "340"; 358c2ecf20Sopenharmony_cistatic char s_hp345[] __initdata = "345"; 368c2ecf20Sopenharmony_cistatic char s_hp360[] __initdata = "360"; 378c2ecf20Sopenharmony_cistatic char s_hp370[] __initdata = "370"; 388c2ecf20Sopenharmony_cistatic char s_hp375[] __initdata = "375"; 398c2ecf20Sopenharmony_cistatic char s_hp380[] __initdata = "380"; 408c2ecf20Sopenharmony_cistatic char s_hp385[] __initdata = "385"; 418c2ecf20Sopenharmony_cistatic char s_hp400[] __initdata = "400"; 428c2ecf20Sopenharmony_cistatic char s_hp425t[] __initdata = "425t"; 438c2ecf20Sopenharmony_cistatic char s_hp425s[] __initdata = "425s"; 448c2ecf20Sopenharmony_cistatic char s_hp425e[] __initdata = "425e"; 458c2ecf20Sopenharmony_cistatic char s_hp433t[] __initdata = "433t"; 468c2ecf20Sopenharmony_cistatic char s_hp433s[] __initdata = "433s"; 478c2ecf20Sopenharmony_cistatic char *hp300_models[] __initdata = { 488c2ecf20Sopenharmony_ci [HP_320] = NULL, 498c2ecf20Sopenharmony_ci [HP_330] = s_hp330, 508c2ecf20Sopenharmony_ci [HP_340] = s_hp340, 518c2ecf20Sopenharmony_ci [HP_345] = s_hp345, 528c2ecf20Sopenharmony_ci [HP_350] = NULL, 538c2ecf20Sopenharmony_ci [HP_360] = s_hp360, 548c2ecf20Sopenharmony_ci [HP_370] = s_hp370, 558c2ecf20Sopenharmony_ci [HP_375] = s_hp375, 568c2ecf20Sopenharmony_ci [HP_380] = s_hp380, 578c2ecf20Sopenharmony_ci [HP_385] = s_hp385, 588c2ecf20Sopenharmony_ci [HP_400] = s_hp400, 598c2ecf20Sopenharmony_ci [HP_425T] = s_hp425t, 608c2ecf20Sopenharmony_ci [HP_425S] = s_hp425s, 618c2ecf20Sopenharmony_ci [HP_425E] = s_hp425e, 628c2ecf20Sopenharmony_ci [HP_433T] = s_hp433t, 638c2ecf20Sopenharmony_ci [HP_433S] = s_hp433s, 648c2ecf20Sopenharmony_ci}; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic char hp300_model_name[13] = "HP9000/"; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ciextern void hp300_reset(void); 698c2ecf20Sopenharmony_ci#ifdef CONFIG_SERIAL_8250_CONSOLE 708c2ecf20Sopenharmony_ciextern int hp300_setup_serial_console(void) __init; 718c2ecf20Sopenharmony_ci#endif 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ciint __init hp300_parse_bootinfo(const struct bi_record *record) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci int unknown = 0; 768c2ecf20Sopenharmony_ci const void *data = record->data; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci switch (be16_to_cpu(record->tag)) { 798c2ecf20Sopenharmony_ci case BI_HP300_MODEL: 808c2ecf20Sopenharmony_ci hp300_model = be32_to_cpup(data); 818c2ecf20Sopenharmony_ci break; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci case BI_HP300_UART_SCODE: 848c2ecf20Sopenharmony_ci hp300_uart_scode = be32_to_cpup(data); 858c2ecf20Sopenharmony_ci break; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci case BI_HP300_UART_ADDR: 888c2ecf20Sopenharmony_ci /* serial port address: ignored here */ 898c2ecf20Sopenharmony_ci break; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci default: 928c2ecf20Sopenharmony_ci unknown = 1; 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci return unknown; 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci#ifdef CONFIG_HEARTBEAT 998c2ecf20Sopenharmony_cistatic void hp300_pulse(int x) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci if (x) 1028c2ecf20Sopenharmony_ci blinken_leds(0x10, 0); 1038c2ecf20Sopenharmony_ci else 1048c2ecf20Sopenharmony_ci blinken_leds(0, 0x10); 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci#endif 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic void hp300_get_model(char *model) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci strcpy(model, hp300_model_name); 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci#define RTCBASE 0xf0420000 1148c2ecf20Sopenharmony_ci#define RTC_DATA 0x1 1158c2ecf20Sopenharmony_ci#define RTC_CMD 0x3 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci#define RTC_BUSY 0x02 1188c2ecf20Sopenharmony_ci#define RTC_DATA_RDY 0x01 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci#define rtc_busy() (in_8(RTCBASE + RTC_CMD) & RTC_BUSY) 1218c2ecf20Sopenharmony_ci#define rtc_data_available() (in_8(RTCBASE + RTC_CMD) & RTC_DATA_RDY) 1228c2ecf20Sopenharmony_ci#define rtc_status() (in_8(RTCBASE + RTC_CMD)) 1238c2ecf20Sopenharmony_ci#define rtc_command(x) out_8(RTCBASE + RTC_CMD, (x)) 1248c2ecf20Sopenharmony_ci#define rtc_read_data() (in_8(RTCBASE + RTC_DATA)) 1258c2ecf20Sopenharmony_ci#define rtc_write_data(x) out_8(RTCBASE + RTC_DATA, (x)) 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci#define RTC_SETREG 0xe0 1288c2ecf20Sopenharmony_ci#define RTC_WRITEREG 0xc2 1298c2ecf20Sopenharmony_ci#define RTC_READREG 0xc3 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci#define RTC_REG_SEC2 0 1328c2ecf20Sopenharmony_ci#define RTC_REG_SEC1 1 1338c2ecf20Sopenharmony_ci#define RTC_REG_MIN2 2 1348c2ecf20Sopenharmony_ci#define RTC_REG_MIN1 3 1358c2ecf20Sopenharmony_ci#define RTC_REG_HOUR2 4 1368c2ecf20Sopenharmony_ci#define RTC_REG_HOUR1 5 1378c2ecf20Sopenharmony_ci#define RTC_REG_WDAY 6 1388c2ecf20Sopenharmony_ci#define RTC_REG_DAY2 7 1398c2ecf20Sopenharmony_ci#define RTC_REG_DAY1 8 1408c2ecf20Sopenharmony_ci#define RTC_REG_MON2 9 1418c2ecf20Sopenharmony_ci#define RTC_REG_MON1 10 1428c2ecf20Sopenharmony_ci#define RTC_REG_YEAR2 11 1438c2ecf20Sopenharmony_ci#define RTC_REG_YEAR1 12 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci#define RTC_HOUR1_24HMODE 0x8 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci#define RTC_STAT_MASK 0xf0 1488c2ecf20Sopenharmony_ci#define RTC_STAT_RDY 0x40 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic inline unsigned char hp300_rtc_read(unsigned char reg) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci unsigned char s, ret; 1538c2ecf20Sopenharmony_ci unsigned long flags; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci local_irq_save(flags); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci while (rtc_busy()); 1588c2ecf20Sopenharmony_ci rtc_command(RTC_SETREG); 1598c2ecf20Sopenharmony_ci while (rtc_busy()); 1608c2ecf20Sopenharmony_ci rtc_write_data(reg); 1618c2ecf20Sopenharmony_ci while (rtc_busy()); 1628c2ecf20Sopenharmony_ci rtc_command(RTC_READREG); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci do { 1658c2ecf20Sopenharmony_ci while (!rtc_data_available()); 1668c2ecf20Sopenharmony_ci s = rtc_status(); 1678c2ecf20Sopenharmony_ci ret = rtc_read_data(); 1688c2ecf20Sopenharmony_ci } while ((s & RTC_STAT_MASK) != RTC_STAT_RDY); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci local_irq_restore(flags); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci return ret; 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic inline unsigned char hp300_rtc_write(unsigned char reg, 1768c2ecf20Sopenharmony_ci unsigned char val) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci unsigned char s, ret; 1798c2ecf20Sopenharmony_ci unsigned long flags; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci local_irq_save(flags); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci while (rtc_busy()); 1848c2ecf20Sopenharmony_ci rtc_command(RTC_SETREG); 1858c2ecf20Sopenharmony_ci while (rtc_busy()); 1868c2ecf20Sopenharmony_ci rtc_write_data((val << 4) | reg); 1878c2ecf20Sopenharmony_ci while (rtc_busy()); 1888c2ecf20Sopenharmony_ci rtc_command(RTC_WRITEREG); 1898c2ecf20Sopenharmony_ci while (rtc_busy()); 1908c2ecf20Sopenharmony_ci rtc_command(RTC_READREG); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci do { 1938c2ecf20Sopenharmony_ci while (!rtc_data_available()); 1948c2ecf20Sopenharmony_ci s = rtc_status(); 1958c2ecf20Sopenharmony_ci ret = rtc_read_data(); 1968c2ecf20Sopenharmony_ci } while ((s & RTC_STAT_MASK) != RTC_STAT_RDY); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci local_irq_restore(flags); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci return ret; 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic int hp300_hwclk(int op, struct rtc_time *t) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci if (!op) { /* read */ 2068c2ecf20Sopenharmony_ci t->tm_sec = hp300_rtc_read(RTC_REG_SEC1) * 10 + 2078c2ecf20Sopenharmony_ci hp300_rtc_read(RTC_REG_SEC2); 2088c2ecf20Sopenharmony_ci t->tm_min = hp300_rtc_read(RTC_REG_MIN1) * 10 + 2098c2ecf20Sopenharmony_ci hp300_rtc_read(RTC_REG_MIN2); 2108c2ecf20Sopenharmony_ci t->tm_hour = (hp300_rtc_read(RTC_REG_HOUR1) & 3) * 10 + 2118c2ecf20Sopenharmony_ci hp300_rtc_read(RTC_REG_HOUR2); 2128c2ecf20Sopenharmony_ci t->tm_wday = -1; 2138c2ecf20Sopenharmony_ci t->tm_mday = hp300_rtc_read(RTC_REG_DAY1) * 10 + 2148c2ecf20Sopenharmony_ci hp300_rtc_read(RTC_REG_DAY2); 2158c2ecf20Sopenharmony_ci t->tm_mon = hp300_rtc_read(RTC_REG_MON1) * 10 + 2168c2ecf20Sopenharmony_ci hp300_rtc_read(RTC_REG_MON2) - 1; 2178c2ecf20Sopenharmony_ci t->tm_year = hp300_rtc_read(RTC_REG_YEAR1) * 10 + 2188c2ecf20Sopenharmony_ci hp300_rtc_read(RTC_REG_YEAR2); 2198c2ecf20Sopenharmony_ci if (t->tm_year <= 69) 2208c2ecf20Sopenharmony_ci t->tm_year += 100; 2218c2ecf20Sopenharmony_ci } else { 2228c2ecf20Sopenharmony_ci hp300_rtc_write(RTC_REG_SEC1, t->tm_sec / 10); 2238c2ecf20Sopenharmony_ci hp300_rtc_write(RTC_REG_SEC2, t->tm_sec % 10); 2248c2ecf20Sopenharmony_ci hp300_rtc_write(RTC_REG_MIN1, t->tm_min / 10); 2258c2ecf20Sopenharmony_ci hp300_rtc_write(RTC_REG_MIN2, t->tm_min % 10); 2268c2ecf20Sopenharmony_ci hp300_rtc_write(RTC_REG_HOUR1, 2278c2ecf20Sopenharmony_ci ((t->tm_hour / 10) & 3) | RTC_HOUR1_24HMODE); 2288c2ecf20Sopenharmony_ci hp300_rtc_write(RTC_REG_HOUR2, t->tm_hour % 10); 2298c2ecf20Sopenharmony_ci hp300_rtc_write(RTC_REG_DAY1, t->tm_mday / 10); 2308c2ecf20Sopenharmony_ci hp300_rtc_write(RTC_REG_DAY2, t->tm_mday % 10); 2318c2ecf20Sopenharmony_ci hp300_rtc_write(RTC_REG_MON1, (t->tm_mon + 1) / 10); 2328c2ecf20Sopenharmony_ci hp300_rtc_write(RTC_REG_MON2, (t->tm_mon + 1) % 10); 2338c2ecf20Sopenharmony_ci if (t->tm_year >= 100) 2348c2ecf20Sopenharmony_ci t->tm_year -= 100; 2358c2ecf20Sopenharmony_ci hp300_rtc_write(RTC_REG_YEAR1, t->tm_year / 10); 2368c2ecf20Sopenharmony_ci hp300_rtc_write(RTC_REG_YEAR2, t->tm_year % 10); 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci return 0; 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic unsigned int hp300_get_ss(void) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci return hp300_rtc_read(RTC_REG_SEC1) * 10 + 2458c2ecf20Sopenharmony_ci hp300_rtc_read(RTC_REG_SEC2); 2468c2ecf20Sopenharmony_ci} 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_cistatic void __init hp300_init_IRQ(void) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_civoid __init config_hp300(void) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci mach_sched_init = hp300_sched_init; 2558c2ecf20Sopenharmony_ci mach_init_IRQ = hp300_init_IRQ; 2568c2ecf20Sopenharmony_ci mach_get_model = hp300_get_model; 2578c2ecf20Sopenharmony_ci mach_hwclk = hp300_hwclk; 2588c2ecf20Sopenharmony_ci mach_get_ss = hp300_get_ss; 2598c2ecf20Sopenharmony_ci mach_reset = hp300_reset; 2608c2ecf20Sopenharmony_ci#ifdef CONFIG_HEARTBEAT 2618c2ecf20Sopenharmony_ci mach_heartbeat = hp300_pulse; 2628c2ecf20Sopenharmony_ci#endif 2638c2ecf20Sopenharmony_ci mach_max_dma_address = 0xffffffff; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if (hp300_model >= HP_330 && hp300_model <= HP_433S && 2668c2ecf20Sopenharmony_ci hp300_model != HP_350) { 2678c2ecf20Sopenharmony_ci pr_info("Detected HP9000 model %s\n", 2688c2ecf20Sopenharmony_ci hp300_models[hp300_model-HP_320]); 2698c2ecf20Sopenharmony_ci strcat(hp300_model_name, hp300_models[hp300_model-HP_320]); 2708c2ecf20Sopenharmony_ci } else { 2718c2ecf20Sopenharmony_ci panic("Unknown HP9000 Model"); 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci#ifdef CONFIG_SERIAL_8250_CONSOLE 2748c2ecf20Sopenharmony_ci hp300_setup_serial_console(); 2758c2ecf20Sopenharmony_ci#endif 2768c2ecf20Sopenharmony_ci} 277