blob: 2a93bbbcc9f8d534be5937180b9709e9f517f4ab [file] [log] [blame]
Anup Patelc0fe2842022-01-27 11:41:07 +05301// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2022 Ventana Micro Systems Inc.
4 */
5
Anup Patelc0fe2842022-01-27 11:41:07 +05306#include <dm.h>
7#include <errno.h>
8#include <fdtdec.h>
9#include <log.h>
10#include <watchdog.h>
11#include <asm/global_data.h>
12#include <asm/io.h>
13#include <linux/compiler.h>
14#include <serial.h>
15#include <linux/err.h>
16
17DECLARE_GLOBAL_DATA_PTR;
18
19#define HTIF_DATA_BITS 48
20#define HTIF_DATA_MASK ((1ULL << HTIF_DATA_BITS) - 1)
21#define HTIF_DATA_SHIFT 0
22#define HTIF_CMD_BITS 8
23#define HTIF_CMD_MASK ((1ULL << HTIF_CMD_BITS) - 1)
24#define HTIF_CMD_SHIFT 48
25#define HTIF_DEV_BITS 8
26#define HTIF_DEV_MASK ((1ULL << HTIF_DEV_BITS) - 1)
27#define HTIF_DEV_SHIFT 56
28
29#define HTIF_DEV_SYSTEM 0
30#define HTIF_DEV_CONSOLE 1
31
32#define HTIF_CONSOLE_CMD_GETC 0
33#define HTIF_CONSOLE_CMD_PUTC 1
34
35#if __riscv_xlen == 64
36# define TOHOST_CMD(dev, cmd, payload) \
37 (((u64)(dev) << HTIF_DEV_SHIFT) | \
38 ((u64)(cmd) << HTIF_CMD_SHIFT) | \
39 (u64)(payload))
40#else
41# define TOHOST_CMD(dev, cmd, payload) ({ \
42 if ((dev) || (cmd)) \
43 __builtin_trap(); \
44 (payload); })
45#endif
46#define FROMHOST_DEV(fromhost_value) \
47 ((u64)((fromhost_value) >> HTIF_DEV_SHIFT) & HTIF_DEV_MASK)
48#define FROMHOST_CMD(fromhost_value) \
49 ((u64)((fromhost_value) >> HTIF_CMD_SHIFT) & HTIF_CMD_MASK)
50#define FROMHOST_DATA(fromhost_value) \
51 ((u64)((fromhost_value) >> HTIF_DATA_SHIFT) & HTIF_DATA_MASK)
52
53struct htif_plat {
54 void *fromhost;
55 void *tohost;
56 int console_char;
57};
58
59static void __check_fromhost(struct htif_plat *plat)
60{
61 u64 fh = readq(plat->fromhost);
62
63 if (!fh)
64 return;
65 writeq(0, plat->fromhost);
66
67 /* this should be from the console */
68 if (FROMHOST_DEV(fh) != HTIF_DEV_CONSOLE)
69 __builtin_trap();
70 switch (FROMHOST_CMD(fh)) {
71 case HTIF_CONSOLE_CMD_GETC:
72 plat->console_char = 1 + (u8)FROMHOST_DATA(fh);
73 break;
74 case HTIF_CONSOLE_CMD_PUTC:
75 break;
76 default:
77 __builtin_trap();
78 }
79}
80
81static void __set_tohost(struct htif_plat *plat,
82 u64 dev, u64 cmd, u64 data)
83{
84 while (readq(plat->tohost))
85 __check_fromhost(plat);
86 writeq(TOHOST_CMD(dev, cmd, data), plat->tohost);
87}
88
89static int htif_serial_putc(struct udevice *dev, const char ch)
90{
91 struct htif_plat *plat = dev_get_plat(dev);
92
93 __set_tohost(plat, HTIF_DEV_CONSOLE, HTIF_CONSOLE_CMD_PUTC, ch);
94 return 0;
95}
96
97static int htif_serial_getc(struct udevice *dev)
98{
99 int ch;
100 struct htif_plat *plat = dev_get_plat(dev);
101
102 if (plat->console_char < 0)
103 __check_fromhost(plat);
104
105 if (plat->console_char >= 0) {
106 ch = plat->console_char;
107 plat->console_char = -1;
108 __set_tohost(plat, HTIF_DEV_CONSOLE, HTIF_CONSOLE_CMD_GETC, 0);
109 return (ch) ? ch - 1 : -EAGAIN;
110 }
111
112 return -EAGAIN;
113}
114
115static int htif_serial_pending(struct udevice *dev, bool input)
116{
117 struct htif_plat *plat = dev_get_plat(dev);
118
119 if (!input)
120 return 0;
121
122 if (plat->console_char < 0)
123 __check_fromhost(plat);
124
125 return (plat->console_char >= 0) ? 1 : 0;
126}
127
128static int htif_serial_probe(struct udevice *dev)
129{
130 struct htif_plat *plat = dev_get_plat(dev);
131
132 /* Queue first getc request */
133 __set_tohost(plat, HTIF_DEV_CONSOLE, HTIF_CONSOLE_CMD_GETC, 0);
134
135 return 0;
136}
137
138static int htif_serial_of_to_plat(struct udevice *dev)
139{
140 fdt_addr_t addr;
141 struct htif_plat *plat = dev_get_plat(dev);
142
143 addr = dev_read_addr_index(dev, 0);
144 if (addr == FDT_ADDR_T_NONE)
145 return -ENODEV;
146 plat->fromhost = (void *)(uintptr_t)addr;
147 plat->tohost = plat->fromhost + sizeof(u64);
148
149 addr = dev_read_addr_index(dev, 1);
150 if (addr != FDT_ADDR_T_NONE)
151 plat->tohost = (void *)(uintptr_t)addr;
152
153 plat->console_char = -1;
154
155 return 0;
156}
157
158static const struct dm_serial_ops htif_serial_ops = {
159 .putc = htif_serial_putc,
160 .getc = htif_serial_getc,
161 .pending = htif_serial_pending,
162};
163
164static const struct udevice_id htif_serial_ids[] = {
165 { .compatible = "ucb,htif0" },
166 { }
167};
168
169U_BOOT_DRIVER(serial_htif) = {
170 .name = "serial_htif",
171 .id = UCLASS_SERIAL,
172 .of_match = htif_serial_ids,
173 .of_to_plat = htif_serial_of_to_plat,
174 .plat_auto = sizeof(struct htif_plat),
175 .probe = htif_serial_probe,
176 .ops = &htif_serial_ops,
177};