| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 |
- // SPDX-License-Identifier: GPL-2.0+
- /*
- * Copyright (C) 2022 Ventana Micro Systems Inc.
- */
- #include <common.h>
- #include <dm.h>
- #include <errno.h>
- #include <fdtdec.h>
- #include <log.h>
- #include <watchdog.h>
- #include <asm/global_data.h>
- #include <asm/io.h>
- #include <linux/compiler.h>
- #include <serial.h>
- #include <linux/err.h>
- DECLARE_GLOBAL_DATA_PTR;
- #define HTIF_DATA_BITS 48
- #define HTIF_DATA_MASK ((1ULL << HTIF_DATA_BITS) - 1)
- #define HTIF_DATA_SHIFT 0
- #define HTIF_CMD_BITS 8
- #define HTIF_CMD_MASK ((1ULL << HTIF_CMD_BITS) - 1)
- #define HTIF_CMD_SHIFT 48
- #define HTIF_DEV_BITS 8
- #define HTIF_DEV_MASK ((1ULL << HTIF_DEV_BITS) - 1)
- #define HTIF_DEV_SHIFT 56
- #define HTIF_DEV_SYSTEM 0
- #define HTIF_DEV_CONSOLE 1
- #define HTIF_CONSOLE_CMD_GETC 0
- #define HTIF_CONSOLE_CMD_PUTC 1
- #if __riscv_xlen == 64
- # define TOHOST_CMD(dev, cmd, payload) \
- (((u64)(dev) << HTIF_DEV_SHIFT) | \
- ((u64)(cmd) << HTIF_CMD_SHIFT) | \
- (u64)(payload))
- #else
- # define TOHOST_CMD(dev, cmd, payload) ({ \
- if ((dev) || (cmd)) \
- __builtin_trap(); \
- (payload); })
- #endif
- #define FROMHOST_DEV(fromhost_value) \
- ((u64)((fromhost_value) >> HTIF_DEV_SHIFT) & HTIF_DEV_MASK)
- #define FROMHOST_CMD(fromhost_value) \
- ((u64)((fromhost_value) >> HTIF_CMD_SHIFT) & HTIF_CMD_MASK)
- #define FROMHOST_DATA(fromhost_value) \
- ((u64)((fromhost_value) >> HTIF_DATA_SHIFT) & HTIF_DATA_MASK)
- struct htif_plat {
- void *fromhost;
- void *tohost;
- int console_char;
- };
- static void __check_fromhost(struct htif_plat *plat)
- {
- u64 fh = readq(plat->fromhost);
- if (!fh)
- return;
- writeq(0, plat->fromhost);
- /* this should be from the console */
- if (FROMHOST_DEV(fh) != HTIF_DEV_CONSOLE)
- __builtin_trap();
- switch (FROMHOST_CMD(fh)) {
- case HTIF_CONSOLE_CMD_GETC:
- plat->console_char = 1 + (u8)FROMHOST_DATA(fh);
- break;
- case HTIF_CONSOLE_CMD_PUTC:
- break;
- default:
- __builtin_trap();
- }
- }
- static void __set_tohost(struct htif_plat *plat,
- u64 dev, u64 cmd, u64 data)
- {
- while (readq(plat->tohost))
- __check_fromhost(plat);
- writeq(TOHOST_CMD(dev, cmd, data), plat->tohost);
- }
- static int htif_serial_putc(struct udevice *dev, const char ch)
- {
- struct htif_plat *plat = dev_get_plat(dev);
- __set_tohost(plat, HTIF_DEV_CONSOLE, HTIF_CONSOLE_CMD_PUTC, ch);
- return 0;
- }
- static int htif_serial_getc(struct udevice *dev)
- {
- int ch;
- struct htif_plat *plat = dev_get_plat(dev);
- if (plat->console_char < 0)
- __check_fromhost(plat);
- if (plat->console_char >= 0) {
- ch = plat->console_char;
- plat->console_char = -1;
- __set_tohost(plat, HTIF_DEV_CONSOLE, HTIF_CONSOLE_CMD_GETC, 0);
- return (ch) ? ch - 1 : -EAGAIN;
- }
- return -EAGAIN;
- }
- static int htif_serial_pending(struct udevice *dev, bool input)
- {
- struct htif_plat *plat = dev_get_plat(dev);
- if (!input)
- return 0;
- if (plat->console_char < 0)
- __check_fromhost(plat);
- return (plat->console_char >= 0) ? 1 : 0;
- }
- static int htif_serial_probe(struct udevice *dev)
- {
- struct htif_plat *plat = dev_get_plat(dev);
- /* Queue first getc request */
- __set_tohost(plat, HTIF_DEV_CONSOLE, HTIF_CONSOLE_CMD_GETC, 0);
- return 0;
- }
- static int htif_serial_of_to_plat(struct udevice *dev)
- {
- fdt_addr_t addr;
- struct htif_plat *plat = dev_get_plat(dev);
- addr = dev_read_addr_index(dev, 0);
- if (addr == FDT_ADDR_T_NONE)
- return -ENODEV;
- plat->fromhost = (void *)(uintptr_t)addr;
- plat->tohost = plat->fromhost + sizeof(u64);
- addr = dev_read_addr_index(dev, 1);
- if (addr != FDT_ADDR_T_NONE)
- plat->tohost = (void *)(uintptr_t)addr;
- plat->console_char = -1;
- return 0;
- }
- static const struct dm_serial_ops htif_serial_ops = {
- .putc = htif_serial_putc,
- .getc = htif_serial_getc,
- .pending = htif_serial_pending,
- };
- static const struct udevice_id htif_serial_ids[] = {
- { .compatible = "ucb,htif0" },
- { }
- };
- U_BOOT_DRIVER(serial_htif) = {
- .name = "serial_htif",
- .id = UCLASS_SERIAL,
- .of_match = htif_serial_ids,
- .of_to_plat = htif_serial_of_to_plat,
- .plat_auto = sizeof(struct htif_plat),
- .probe = htif_serial_probe,
- .ops = &htif_serial_ops,
- };
|