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