diff options
Diffstat (limited to 'roms/skiboot/platforms/mambo')
-rw-r--r-- | roms/skiboot/platforms/mambo/Makefile.inc | 6 | ||||
-rw-r--r-- | roms/skiboot/platforms/mambo/console.c | 74 | ||||
-rw-r--r-- | roms/skiboot/platforms/mambo/mambo.c | 321 | ||||
-rw-r--r-- | roms/skiboot/platforms/mambo/mambo.h | 46 |
4 files changed, 447 insertions, 0 deletions
diff --git a/roms/skiboot/platforms/mambo/Makefile.inc b/roms/skiboot/platforms/mambo/Makefile.inc new file mode 100644 index 000000000..b0e6b0c46 --- /dev/null +++ b/roms/skiboot/platforms/mambo/Makefile.inc @@ -0,0 +1,6 @@ +SUBDIRS += $(PLATDIR)/mambo + +MAMBO_OBJS = mambo.o console.o +MAMBO = $(PLATDIR)/mambo/built-in.a +$(MAMBO): $(MAMBO_OBJS:%=$(PLATDIR)/mambo/%) + diff --git a/roms/skiboot/platforms/mambo/console.c b/roms/skiboot/platforms/mambo/console.c new file mode 100644 index 000000000..6d5b20b56 --- /dev/null +++ b/roms/skiboot/platforms/mambo/console.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later +/* Copyright 2016-2017 IBM Corp. */ + +#include <skiboot.h> +#include <console.h> + +#include "mambo.h" + +/* + * The SIM_READ_CONSOLE callout will return -1 if there is no character to read. + * There's no explicit poll callout so we "poll" by doing a read and stashing + * the result until we do an actual read. + */ +static int mambo_char = -1; + +static bool mambo_console_poll(void) +{ + if (mambo_char < 0) + mambo_char = callthru0(SIM_READ_CONSOLE_CODE); + + return mambo_char >= 0; +} + +static size_t mambo_console_read(char *buf, size_t len) +{ + size_t count = 0; + + while (count < len) { + if (!mambo_console_poll()) + break; + + buf[count++] = mambo_char; + mambo_char = -1; + } + + return count; +} + +size_t mambo_console_write(const char *buf, size_t len) +{ + callthru2(SIM_WRITE_CONSOLE_CODE, (unsigned long)buf, len); + return len; +} + +static struct con_ops mambo_con_driver = { + .poll_read = mambo_console_poll, + .read = mambo_console_read, + .write = mambo_console_write, +}; + +void enable_mambo_console(void) +{ + prlog(PR_NOTICE, "Enabling Mambo console\n"); + set_console(&mambo_con_driver); +} + +/* + * mambo console based printf(), this is useful for debugging the console + * since mambo_console_write() can be safely called from anywhere. + * + * This is a debug hack and you shouldn't use it in real code. + */ +void mprintf(const char *fmt, ...) +{ + char buf[320]; + va_list args; + int i; + + va_start(args, fmt); + i = vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + + mambo_console_write(buf, i); +} diff --git a/roms/skiboot/platforms/mambo/mambo.c b/roms/skiboot/platforms/mambo/mambo.c new file mode 100644 index 000000000..a1e0488c8 --- /dev/null +++ b/roms/skiboot/platforms/mambo/mambo.c @@ -0,0 +1,321 @@ +// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later +/* Copyright 2015-2017 IBM Corp. */ + +#include <skiboot.h> +#include <device.h> +#include <console.h> +#include <chip.h> +#include <cpu.h> +#include <opal-api.h> +#include <opal-internal.h> +#include <time-utils.h> +#include <time.h> + +#include "mambo.h" + +static bool mambo_probe(void) +{ + if (!dt_find_by_path(dt_root, "/mambo")) + return false; + + return true; +} + +#define BD_INFO_SYNC 0 +#define BD_INFO_STATUS 1 +#define BD_INFO_BLKSZ 2 +#define BD_INFO_DEVSZ 3 +#define BD_INFO_CHANGE 4 + +#define BD_SECT_SZ 512 + +static inline int callthru_disk_read(int id, void *buf, unsigned long sect, + unsigned long nrsect) +{ + return callthru3(SIM_BOGUS_DISK_READ, (unsigned long)buf, sect, + (nrsect << 16) | id); +} + +static inline int callthru_disk_write(int id, void *buf, unsigned long sect, + unsigned long nrsect) +{ + return callthru3(SIM_BOGUS_DISK_WRITE, (unsigned long)buf, sect, + (nrsect << 16) | id); +} + +static inline unsigned long callthru_disk_info(int op, int id) +{ + return callthru2(SIM_BOGUS_DISK_INFO, (unsigned long)op, + (unsigned long)id); +} + +extern unsigned long callthru_tcl(const char *str, int len); + +unsigned long callthru_tcl(const char *str, int len) +{ + prlog(PR_DEBUG, "Sending TCL to Mambo, cmd: %s\n", str); + return callthru2(SIM_CALL_TCL, (unsigned long)str, (unsigned long)len); +} + +struct bogus_disk_info { + unsigned long size; + int id; +}; + +static int bogus_disk_read(struct blocklevel_device *bl, uint64_t pos, void *buf, + uint64_t len) +{ + struct bogus_disk_info *bdi = bl->priv; + int rc, read_sectors = 0; + char b[BD_SECT_SZ]; + + if (len >= BD_SECT_SZ) { + rc = callthru_disk_read(bdi->id, buf, pos/BD_SECT_SZ, + len/BD_SECT_SZ); + if (rc) + return rc; + read_sectors = (len / BD_SECT_SZ); + } + + if ((len % BD_SECT_SZ) == 0) + return 0; + + /* + * Read any unaligned data into a temporaty buffer b, then copy + * to buf + */ + rc = callthru_disk_read(bdi->id, b, (pos/BD_SECT_SZ) + read_sectors, 1); + if (rc) + return rc; + memcpy(buf + (read_sectors * BD_SECT_SZ) , &b[pos % BD_SECT_SZ], + len - (read_sectors * BD_SECT_SZ)); + return rc; +} + +static int bogus_disk_write(struct blocklevel_device *bl, uint64_t pos, + const void *buf, uint64_t len) +{ + struct bogus_disk_info *bdi = bl->priv; + + if ((len % BD_SECT_SZ) != 0) + return OPAL_PARAMETER; + + return callthru_disk_write(bdi->id, (void *)buf, pos/BD_SECT_SZ, + len/BD_SECT_SZ); + +} + +static int bogus_disk_erase(struct blocklevel_device *bl __unused, + uint64_t pos __unused, uint64_t len __unused) +{ + return 0; /* NOP */ +} + +static int bogus_disk_get_info(struct blocklevel_device *bl, const char **name, + uint64_t *total_size, uint32_t *erase_granule) +{ + struct bogus_disk_info *bdi = bl->priv; + + if (total_size) + *total_size = bdi->size; + + if (erase_granule) + *erase_granule = BD_SECT_SZ; + + if (name) + *name = "mambobogus"; + + return 0; +} + +static void bogus_disk_flash_init(void) +{ + struct blocklevel_device *bl; + struct bogus_disk_info *bdi; + unsigned long id = 0, size; + int rc; + + if (!chip_quirk(QUIRK_MAMBO_CALLOUTS)) + return; + + while (1) { + + rc = callthru_disk_info(BD_INFO_STATUS, id); + if (rc < 0) + return; + + size = callthru_disk_info(BD_INFO_DEVSZ, id) * 1024; + prlog(PR_NOTICE, "mambo: Found bogus disk size: 0x%lx\n", size); + + bl = zalloc(sizeof(struct blocklevel_device)); + bdi = zalloc(sizeof(struct bogus_disk_info)); + if (!bl || !bdi) { + free(bl); + free(bdi); + prerror("mambo: Failed to start bogus disk, ENOMEM\n"); + return; + } + + bl->read = &bogus_disk_read; + bl->write = &bogus_disk_write; + bl->erase = &bogus_disk_erase; + bl->get_info = &bogus_disk_get_info; + bdi->id = id; + bdi->size = size; + bl->priv = bdi; + bl->erase_mask = BD_SECT_SZ - 1; + + rc = flash_register(bl); + if (rc) + prerror("mambo: Failed to register bogus disk: %li\n", + id); + id++; + } +} + +static int64_t time_delta = 0; + +static int64_t mambo_rtc_read(__be32 *ymd, __be64 *hmsm) +{ + int64_t mambo_time; + struct tm t; + time_t mt; + uint32_t __ymd; + uint64_t __hmsm; + + if (!ymd || !hmsm) + return OPAL_PARAMETER; + + mambo_time = callthru0(SIM_GET_TIME_CODE); + mt = mambo_time >> 32; + mt += time_delta; + gmtime_r(&mt, &t); + tm_to_datetime(&t, &__ymd, &__hmsm); + + *ymd = cpu_to_be32(__ymd); + *hmsm = cpu_to_be64(__hmsm); + + return OPAL_SUCCESS; +} + +static int64_t mambo_rtc_write(uint32_t ymd, uint64_t hmsm) +{ + int64_t mambo_time; + struct tm tm; + time_t mt, new_mt; + + mambo_time = callthru0(SIM_GET_TIME_CODE); + mt = mambo_time >> 32; + + datetime_to_tm(ymd, hmsm, &tm); + new_mt = mktime(&tm); + + time_delta = new_mt - mt; + + return OPAL_SUCCESS; +} + +static void mambo_rtc_init(void) +{ + struct dt_node *np = dt_new(opal_node, "rtc"); + dt_add_property_strings(np, "compatible", "ibm,opal-rtc"); + + opal_register(OPAL_RTC_READ, mambo_rtc_read, 2); + opal_register(OPAL_RTC_WRITE, mambo_rtc_write, 2); +} + +static void mambo_system_reset_cpu(struct cpu_thread *cpu) +{ + uint32_t core_id; + uint32_t thread_id; + char tcl_cmd[50]; + + core_id = pir_to_core_id(cpu->pir); + thread_id = pir_to_thread_id(cpu->pir); + + snprintf(tcl_cmd, sizeof(tcl_cmd), "mysim cpu %i:%i interrupt SystemReset", core_id, thread_id); + callthru_tcl(tcl_cmd, strlen(tcl_cmd)); +} + +#define SYS_RESET_ALL -1 +#define SYS_RESET_ALL_OTHERS -2 + +static int64_t mambo_signal_system_reset(int32_t cpu_nr) +{ + struct cpu_thread *cpu; + + if (cpu_nr < 0) { + if (cpu_nr < SYS_RESET_ALL_OTHERS) + return OPAL_PARAMETER; + + for_each_cpu(cpu) { + if (cpu == this_cpu()) + continue; + mambo_system_reset_cpu(cpu); + + } + if (cpu_nr == SYS_RESET_ALL) + mambo_system_reset_cpu(this_cpu()); + + return OPAL_SUCCESS; + + } else { + cpu = find_cpu_by_server(cpu_nr); + if (!cpu) + return OPAL_PARAMETER; + + mambo_system_reset_cpu(cpu); + return OPAL_SUCCESS; + } +} + +static void mambo_sreset_init(void) +{ + opal_register(OPAL_SIGNAL_SYSTEM_RESET, mambo_signal_system_reset, 1); +} + +static void mambo_platform_init(void) +{ + mambo_sreset_init(); + mambo_rtc_init(); + bogus_disk_flash_init(); +} + +static int64_t mambo_cec_power_down(uint64_t request __unused) +{ + if (chip_quirk(QUIRK_MAMBO_CALLOUTS)) + callthru0(SIM_EXIT_CODE); + + return OPAL_UNSUPPORTED; +} + +static void __attribute__((noreturn)) mambo_terminate(const char *msg __unused) +{ + if (chip_quirk(QUIRK_MAMBO_CALLOUTS)) + callthru0(SIM_EXIT_CODE); + + for (;;) ; +} + +static int mambo_heartbeat_time(void) +{ + /* + * Mambo is slow and has no console input interrupt, so faster + * polling is needed to ensure its responsiveness. + */ + return 100; +} + +DECLARE_PLATFORM(mambo) = { + .name = "Mambo", + .probe = mambo_probe, + .init = mambo_platform_init, + .cec_power_down = mambo_cec_power_down, + .terminate = mambo_terminate, + .start_preload_resource = flash_start_preload_resource, + .resource_loaded = flash_resource_loaded, + .heartbeat_time = mambo_heartbeat_time, + .nvram_info = fake_nvram_info, + .nvram_start_read = fake_nvram_start_read, + .nvram_write = fake_nvram_write, +}; diff --git a/roms/skiboot/platforms/mambo/mambo.h b/roms/skiboot/platforms/mambo/mambo.h new file mode 100644 index 000000000..0b3bb60c4 --- /dev/null +++ b/roms/skiboot/platforms/mambo/mambo.h @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later +/* Copyright 2016 IBM Corp. */ + +#ifndef __MAMBO_H__ +#define __MAMBO_H__ + +static inline unsigned long callthru0(int command) +{ + register uint64_t c asm("r3") = command; + asm volatile (".long 0x000eaeb0":"=r" (c):"r"(c)); + return c; +} + +static inline unsigned long callthru2(int command, unsigned long arg1, + unsigned long arg2) +{ + register unsigned long c asm("r3") = command; + register unsigned long a1 asm("r4") = arg1; + register unsigned long a2 asm("r5") = arg2; + asm volatile (".long 0x000eaeb0":"=r" (c):"r"(c), "r"(a1), "r"(a2)); + return c; +} + +static inline unsigned long callthru3(int command, unsigned long arg1, + unsigned long arg2, unsigned long arg3) +{ + register unsigned long c asm("r3") = command; + register unsigned long a1 asm("r4") = arg1; + register unsigned long a2 asm("r5") = arg2; + register unsigned long a3 asm("r6") = arg3; + asm volatile (".long 0x000eaeb0":"=r" (c):"r"(c), "r"(a1), "r"(a2), + "r"(a3)); + return c; +} + +/* Mambo callthru commands */ +#define SIM_WRITE_CONSOLE_CODE 0 +#define SIM_EXIT_CODE 31 +#define SIM_READ_CONSOLE_CODE 60 +#define SIM_GET_TIME_CODE 70 +#define SIM_CALL_TCL 86 +#define SIM_BOGUS_DISK_READ 116 +#define SIM_BOGUS_DISK_WRITE 117 +#define SIM_BOGUS_DISK_INFO 118 + +#endif /* __MAMBO_H__ */ |