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