1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * linux/arch/m68k/hp300/config.c
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * Copyright (C) 1998 Philip Blundell <philb@gnu.org>
61da177e4SLinus Torvalds *
71da177e4SLinus Torvalds * This file contains the HP300-specific initialisation code. It gets
81da177e4SLinus Torvalds * called by setup.c.
91da177e4SLinus Torvalds */
101da177e4SLinus Torvalds
111da177e4SLinus Torvalds #include <linux/module.h>
121da177e4SLinus Torvalds #include <linux/init.h>
131da177e4SLinus Torvalds #include <linux/string.h>
141da177e4SLinus Torvalds #include <linux/kernel.h>
151da177e4SLinus Torvalds #include <linux/console.h>
16084b3600SArnd Bergmann #include <linux/rtc.h>
171da177e4SLinus Torvalds
181da177e4SLinus Torvalds #include <asm/bootinfo.h>
194c3c522bSGeert Uytterhoeven #include <asm/bootinfo-hp300.h>
20abe48101SGeert Uytterhoeven #include <asm/byteorder.h>
211da177e4SLinus Torvalds #include <asm/machdep.h>
221da177e4SLinus Torvalds #include <asm/blinken.h>
231da177e4SLinus Torvalds #include <asm/io.h> /* readb() and writeb() */
241da177e4SLinus Torvalds #include <asm/hp300hw.h>
25*91d7b75aSLaurent Vivier #include <asm/config.h>
261da177e4SLinus Torvalds
271da177e4SLinus Torvalds #include "time.h"
281da177e4SLinus Torvalds
291da177e4SLinus Torvalds unsigned long hp300_model;
301da177e4SLinus Torvalds unsigned long hp300_uart_scode = -1;
31f808b865SGeert Uytterhoeven unsigned char hp300_ledstate;
32f808b865SGeert Uytterhoeven EXPORT_SYMBOL(hp300_ledstate);
331da177e4SLinus Torvalds
341da177e4SLinus Torvalds static char s_hp330[] __initdata = "330";
351da177e4SLinus Torvalds static char s_hp340[] __initdata = "340";
361da177e4SLinus Torvalds static char s_hp345[] __initdata = "345";
371da177e4SLinus Torvalds static char s_hp360[] __initdata = "360";
381da177e4SLinus Torvalds static char s_hp370[] __initdata = "370";
391da177e4SLinus Torvalds static char s_hp375[] __initdata = "375";
401da177e4SLinus Torvalds static char s_hp380[] __initdata = "380";
411da177e4SLinus Torvalds static char s_hp385[] __initdata = "385";
421da177e4SLinus Torvalds static char s_hp400[] __initdata = "400";
431da177e4SLinus Torvalds static char s_hp425t[] __initdata = "425t";
441da177e4SLinus Torvalds static char s_hp425s[] __initdata = "425s";
451da177e4SLinus Torvalds static char s_hp425e[] __initdata = "425e";
461da177e4SLinus Torvalds static char s_hp433t[] __initdata = "433t";
471da177e4SLinus Torvalds static char s_hp433s[] __initdata = "433s";
481da177e4SLinus Torvalds static char *hp300_models[] __initdata = {
491da177e4SLinus Torvalds [HP_320] = NULL,
501da177e4SLinus Torvalds [HP_330] = s_hp330,
511da177e4SLinus Torvalds [HP_340] = s_hp340,
521da177e4SLinus Torvalds [HP_345] = s_hp345,
531da177e4SLinus Torvalds [HP_350] = NULL,
541da177e4SLinus Torvalds [HP_360] = s_hp360,
551da177e4SLinus Torvalds [HP_370] = s_hp370,
561da177e4SLinus Torvalds [HP_375] = s_hp375,
571da177e4SLinus Torvalds [HP_380] = s_hp380,
581da177e4SLinus Torvalds [HP_385] = s_hp385,
591da177e4SLinus Torvalds [HP_400] = s_hp400,
601da177e4SLinus Torvalds [HP_425T] = s_hp425t,
611da177e4SLinus Torvalds [HP_425S] = s_hp425s,
621da177e4SLinus Torvalds [HP_425E] = s_hp425e,
631da177e4SLinus Torvalds [HP_433T] = s_hp433t,
641da177e4SLinus Torvalds [HP_433S] = s_hp433s,
651da177e4SLinus Torvalds };
661da177e4SLinus Torvalds
671da177e4SLinus Torvalds static char hp300_model_name[13] = "HP9000/";
681da177e4SLinus Torvalds
691da177e4SLinus Torvalds extern void hp300_reset(void);
701da177e4SLinus Torvalds #ifdef CONFIG_SERIAL_8250_CONSOLE
711da177e4SLinus Torvalds extern int hp300_setup_serial_console(void) __init;
721da177e4SLinus Torvalds #endif
731da177e4SLinus Torvalds
hp300_parse_bootinfo(const struct bi_record * record)741da177e4SLinus Torvalds int __init hp300_parse_bootinfo(const struct bi_record *record)
751da177e4SLinus Torvalds {
761da177e4SLinus Torvalds int unknown = 0;
77abe48101SGeert Uytterhoeven const void *data = record->data;
781da177e4SLinus Torvalds
79abe48101SGeert Uytterhoeven switch (be16_to_cpu(record->tag)) {
801da177e4SLinus Torvalds case BI_HP300_MODEL:
81abe48101SGeert Uytterhoeven hp300_model = be32_to_cpup(data);
821da177e4SLinus Torvalds break;
831da177e4SLinus Torvalds
841da177e4SLinus Torvalds case BI_HP300_UART_SCODE:
85abe48101SGeert Uytterhoeven hp300_uart_scode = be32_to_cpup(data);
861da177e4SLinus Torvalds break;
871da177e4SLinus Torvalds
881da177e4SLinus Torvalds case BI_HP300_UART_ADDR:
891da177e4SLinus Torvalds /* serial port address: ignored here */
901da177e4SLinus Torvalds break;
911da177e4SLinus Torvalds
921da177e4SLinus Torvalds default:
931da177e4SLinus Torvalds unknown = 1;
941da177e4SLinus Torvalds }
951da177e4SLinus Torvalds
961da177e4SLinus Torvalds return unknown;
971da177e4SLinus Torvalds }
981da177e4SLinus Torvalds
991da177e4SLinus Torvalds #ifdef CONFIG_HEARTBEAT
hp300_pulse(int x)1001da177e4SLinus Torvalds static void hp300_pulse(int x)
1011da177e4SLinus Torvalds {
1021da177e4SLinus Torvalds if (x)
1031da177e4SLinus Torvalds blinken_leds(0x10, 0);
1041da177e4SLinus Torvalds else
1051da177e4SLinus Torvalds blinken_leds(0, 0x10);
1061da177e4SLinus Torvalds }
1071da177e4SLinus Torvalds #endif
1081da177e4SLinus Torvalds
hp300_get_model(char * model)1091da177e4SLinus Torvalds static void hp300_get_model(char *model)
1101da177e4SLinus Torvalds {
1111da177e4SLinus Torvalds strcpy(model, hp300_model_name);
1121da177e4SLinus Torvalds }
1131da177e4SLinus Torvalds
1141da177e4SLinus Torvalds #define RTCBASE 0xf0420000
1151da177e4SLinus Torvalds #define RTC_DATA 0x1
1161da177e4SLinus Torvalds #define RTC_CMD 0x3
1171da177e4SLinus Torvalds
1181da177e4SLinus Torvalds #define RTC_BUSY 0x02
1191da177e4SLinus Torvalds #define RTC_DATA_RDY 0x01
1201da177e4SLinus Torvalds
1211da177e4SLinus Torvalds #define rtc_busy() (in_8(RTCBASE + RTC_CMD) & RTC_BUSY)
1221da177e4SLinus Torvalds #define rtc_data_available() (in_8(RTCBASE + RTC_CMD) & RTC_DATA_RDY)
1231da177e4SLinus Torvalds #define rtc_status() (in_8(RTCBASE + RTC_CMD))
1241da177e4SLinus Torvalds #define rtc_command(x) out_8(RTCBASE + RTC_CMD, (x))
1251da177e4SLinus Torvalds #define rtc_read_data() (in_8(RTCBASE + RTC_DATA))
1261da177e4SLinus Torvalds #define rtc_write_data(x) out_8(RTCBASE + RTC_DATA, (x))
1271da177e4SLinus Torvalds
1281da177e4SLinus Torvalds #define RTC_SETREG 0xe0
1291da177e4SLinus Torvalds #define RTC_WRITEREG 0xc2
1301da177e4SLinus Torvalds #define RTC_READREG 0xc3
1311da177e4SLinus Torvalds
1321da177e4SLinus Torvalds #define RTC_REG_SEC2 0
1331da177e4SLinus Torvalds #define RTC_REG_SEC1 1
1341da177e4SLinus Torvalds #define RTC_REG_MIN2 2
1351da177e4SLinus Torvalds #define RTC_REG_MIN1 3
1361da177e4SLinus Torvalds #define RTC_REG_HOUR2 4
1371da177e4SLinus Torvalds #define RTC_REG_HOUR1 5
1381da177e4SLinus Torvalds #define RTC_REG_WDAY 6
1391da177e4SLinus Torvalds #define RTC_REG_DAY2 7
1401da177e4SLinus Torvalds #define RTC_REG_DAY1 8
1411da177e4SLinus Torvalds #define RTC_REG_MON2 9
1421da177e4SLinus Torvalds #define RTC_REG_MON1 10
1431da177e4SLinus Torvalds #define RTC_REG_YEAR2 11
1441da177e4SLinus Torvalds #define RTC_REG_YEAR1 12
1451da177e4SLinus Torvalds
1461da177e4SLinus Torvalds #define RTC_HOUR1_24HMODE 0x8
1471da177e4SLinus Torvalds
1481da177e4SLinus Torvalds #define RTC_STAT_MASK 0xf0
1491da177e4SLinus Torvalds #define RTC_STAT_RDY 0x40
1501da177e4SLinus Torvalds
hp300_rtc_read(unsigned char reg)1511da177e4SLinus Torvalds static inline unsigned char hp300_rtc_read(unsigned char reg)
1521da177e4SLinus Torvalds {
1531da177e4SLinus Torvalds unsigned char s, ret;
1541da177e4SLinus Torvalds unsigned long flags;
1551da177e4SLinus Torvalds
1561da177e4SLinus Torvalds local_irq_save(flags);
1571da177e4SLinus Torvalds
1581da177e4SLinus Torvalds while (rtc_busy());
1591da177e4SLinus Torvalds rtc_command(RTC_SETREG);
1601da177e4SLinus Torvalds while (rtc_busy());
1611da177e4SLinus Torvalds rtc_write_data(reg);
1621da177e4SLinus Torvalds while (rtc_busy());
1631da177e4SLinus Torvalds rtc_command(RTC_READREG);
1641da177e4SLinus Torvalds
1651da177e4SLinus Torvalds do {
1661da177e4SLinus Torvalds while (!rtc_data_available());
1671da177e4SLinus Torvalds s = rtc_status();
1681da177e4SLinus Torvalds ret = rtc_read_data();
1691da177e4SLinus Torvalds } while ((s & RTC_STAT_MASK) != RTC_STAT_RDY);
1701da177e4SLinus Torvalds
1711da177e4SLinus Torvalds local_irq_restore(flags);
1721da177e4SLinus Torvalds
1731da177e4SLinus Torvalds return ret;
1741da177e4SLinus Torvalds }
1751da177e4SLinus Torvalds
hp300_rtc_write(unsigned char reg,unsigned char val)1761da177e4SLinus Torvalds static inline unsigned char hp300_rtc_write(unsigned char reg,
1771da177e4SLinus Torvalds unsigned char val)
1781da177e4SLinus Torvalds {
1791da177e4SLinus Torvalds unsigned char s, ret;
1801da177e4SLinus Torvalds unsigned long flags;
1811da177e4SLinus Torvalds
1821da177e4SLinus Torvalds local_irq_save(flags);
1831da177e4SLinus Torvalds
1841da177e4SLinus Torvalds while (rtc_busy());
1851da177e4SLinus Torvalds rtc_command(RTC_SETREG);
1861da177e4SLinus Torvalds while (rtc_busy());
1871da177e4SLinus Torvalds rtc_write_data((val << 4) | reg);
1881da177e4SLinus Torvalds while (rtc_busy());
1891da177e4SLinus Torvalds rtc_command(RTC_WRITEREG);
1901da177e4SLinus Torvalds while (rtc_busy());
1911da177e4SLinus Torvalds rtc_command(RTC_READREG);
1921da177e4SLinus Torvalds
1931da177e4SLinus Torvalds do {
1941da177e4SLinus Torvalds while (!rtc_data_available());
1951da177e4SLinus Torvalds s = rtc_status();
1961da177e4SLinus Torvalds ret = rtc_read_data();
1971da177e4SLinus Torvalds } while ((s & RTC_STAT_MASK) != RTC_STAT_RDY);
1981da177e4SLinus Torvalds
1991da177e4SLinus Torvalds local_irq_restore(flags);
2001da177e4SLinus Torvalds
2011da177e4SLinus Torvalds return ret;
2021da177e4SLinus Torvalds }
2031da177e4SLinus Torvalds
hp300_hwclk(int op,struct rtc_time * t)2041da177e4SLinus Torvalds static int hp300_hwclk(int op, struct rtc_time *t)
2051da177e4SLinus Torvalds {
2061da177e4SLinus Torvalds if (!op) { /* read */
2071da177e4SLinus Torvalds t->tm_sec = hp300_rtc_read(RTC_REG_SEC1) * 10 +
2081da177e4SLinus Torvalds hp300_rtc_read(RTC_REG_SEC2);
2091da177e4SLinus Torvalds t->tm_min = hp300_rtc_read(RTC_REG_MIN1) * 10 +
2101da177e4SLinus Torvalds hp300_rtc_read(RTC_REG_MIN2);
2111da177e4SLinus Torvalds t->tm_hour = (hp300_rtc_read(RTC_REG_HOUR1) & 3) * 10 +
2121da177e4SLinus Torvalds hp300_rtc_read(RTC_REG_HOUR2);
2131da177e4SLinus Torvalds t->tm_wday = -1;
2141da177e4SLinus Torvalds t->tm_mday = hp300_rtc_read(RTC_REG_DAY1) * 10 +
2151da177e4SLinus Torvalds hp300_rtc_read(RTC_REG_DAY2);
2161da177e4SLinus Torvalds t->tm_mon = hp300_rtc_read(RTC_REG_MON1) * 10 +
2171da177e4SLinus Torvalds hp300_rtc_read(RTC_REG_MON2) - 1;
2181da177e4SLinus Torvalds t->tm_year = hp300_rtc_read(RTC_REG_YEAR1) * 10 +
2191da177e4SLinus Torvalds hp300_rtc_read(RTC_REG_YEAR2);
2201da177e4SLinus Torvalds if (t->tm_year <= 69)
2211da177e4SLinus Torvalds t->tm_year += 100;
2221da177e4SLinus Torvalds } else {
2231da177e4SLinus Torvalds hp300_rtc_write(RTC_REG_SEC1, t->tm_sec / 10);
2241da177e4SLinus Torvalds hp300_rtc_write(RTC_REG_SEC2, t->tm_sec % 10);
2251da177e4SLinus Torvalds hp300_rtc_write(RTC_REG_MIN1, t->tm_min / 10);
2261da177e4SLinus Torvalds hp300_rtc_write(RTC_REG_MIN2, t->tm_min % 10);
2271da177e4SLinus Torvalds hp300_rtc_write(RTC_REG_HOUR1,
2281da177e4SLinus Torvalds ((t->tm_hour / 10) & 3) | RTC_HOUR1_24HMODE);
2291da177e4SLinus Torvalds hp300_rtc_write(RTC_REG_HOUR2, t->tm_hour % 10);
2301da177e4SLinus Torvalds hp300_rtc_write(RTC_REG_DAY1, t->tm_mday / 10);
2311da177e4SLinus Torvalds hp300_rtc_write(RTC_REG_DAY2, t->tm_mday % 10);
2321da177e4SLinus Torvalds hp300_rtc_write(RTC_REG_MON1, (t->tm_mon + 1) / 10);
2331da177e4SLinus Torvalds hp300_rtc_write(RTC_REG_MON2, (t->tm_mon + 1) % 10);
2341da177e4SLinus Torvalds if (t->tm_year >= 100)
2351da177e4SLinus Torvalds t->tm_year -= 100;
2361da177e4SLinus Torvalds hp300_rtc_write(RTC_REG_YEAR1, t->tm_year / 10);
2371da177e4SLinus Torvalds hp300_rtc_write(RTC_REG_YEAR2, t->tm_year % 10);
2381da177e4SLinus Torvalds }
2391da177e4SLinus Torvalds
2401da177e4SLinus Torvalds return 0;
2411da177e4SLinus Torvalds }
2421da177e4SLinus Torvalds
hp300_init_IRQ(void)24335353bb8SRoman Zippel static void __init hp300_init_IRQ(void)
24435353bb8SRoman Zippel {
24535353bb8SRoman Zippel }
24635353bb8SRoman Zippel
config_hp300(void)2471da177e4SLinus Torvalds void __init config_hp300(void)
2481da177e4SLinus Torvalds {
2491da177e4SLinus Torvalds mach_sched_init = hp300_sched_init;
2501da177e4SLinus Torvalds mach_init_IRQ = hp300_init_IRQ;
2511da177e4SLinus Torvalds mach_get_model = hp300_get_model;
2521da177e4SLinus Torvalds mach_hwclk = hp300_hwclk;
2531da177e4SLinus Torvalds mach_reset = hp300_reset;
2541da177e4SLinus Torvalds #ifdef CONFIG_HEARTBEAT
2551da177e4SLinus Torvalds mach_heartbeat = hp300_pulse;
2561da177e4SLinus Torvalds #endif
2571da177e4SLinus Torvalds
258e8d6dc5aSFabian Frederick if (hp300_model >= HP_330 && hp300_model <= HP_433S &&
259e8d6dc5aSFabian Frederick hp300_model != HP_350) {
260e8d6dc5aSFabian Frederick pr_info("Detected HP9000 model %s\n",
261e8d6dc5aSFabian Frederick hp300_models[hp300_model-HP_320]);
2621da177e4SLinus Torvalds strcat(hp300_model_name, hp300_models[hp300_model-HP_320]);
263e8d6dc5aSFabian Frederick } else {
2641da177e4SLinus Torvalds panic("Unknown HP9000 Model");
2651da177e4SLinus Torvalds }
2661da177e4SLinus Torvalds #ifdef CONFIG_SERIAL_8250_CONSOLE
2671da177e4SLinus Torvalds hp300_setup_serial_console();
2681da177e4SLinus Torvalds #endif
2691da177e4SLinus Torvalds }
270