]> Git Repo - J-u-boot.git/blob - drivers/serial/serial_htif.c
Merge patch series "Generalize PHYTEC Overlay Handling"
[J-u-boot.git] / drivers / serial / serial_htif.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2022 Ventana Micro Systems Inc.
4  */
5
6 #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
17 DECLARE_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
53 struct htif_plat {
54         void *fromhost;
55         void *tohost;
56         int console_char;
57 };
58
59 static 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
81 static 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
89 static 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
97 static 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
115 static 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
128 static 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
138 static 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
158 static 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
164 static const struct udevice_id htif_serial_ids[] = {
165         { .compatible = "ucb,htif0" },
166         { }
167 };
168
169 U_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 };
This page took 0.036526 seconds and 4 git commands to generate.