gftty.c revision 1.2 1 /* $NetBSD: gftty.c,v 1.2 2024/01/02 07:30:29 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 2023 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 /*
33 * Support for the Goldfish virtual TTY.
34 */
35
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: gftty.c,v 1.2 2024/01/02 07:30:29 thorpej Exp $");
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/bus.h>
42 #include <sys/device.h>
43 #include <sys/kmem.h>
44
45 #include <uvm/uvm_extern.h>
46
47 #include <dev/cons.h>
48
49 #include <dev/goldfish/gfttyvar.h>
50
51 /*
52 * Goldfish TTY registers.
53 */
54 #define GFTTY_PUT_CHAR 0x00 /* 8 bit output value */
55 #define GFTTY_BYTES_READY 0x04 /* number of input bytes available */
56 #define GFTTY_CMD 0x08 /* command */
57 #define GFTTY_DATA_PTR 0x10 /* DMA pointer */
58 #define GFTTY_DATA_LEN 0x14 /* DMA length */
59 #define GFTTY_DATA_PTR_HIGH 0x18 /* DMA pointer (64-bit) */
60 #define GFTTY_VERSION 0x20 /* TTY version */
61
62 #define CMD_INT_DISABLE 0x00
63 #define CMD_INT_ENABLE 0x01
64 #define CMD_WRITE_BUFFER 0x02
65 #define CMD_READ_BUFFER 0x03
66
67 #define REG_READ0(c, r) \
68 bus_space_read_4((c)->c_bst, (c)->c_bsh, (r))
69 #define REG_WRITE0(c, r, v) \
70 bus_space_write_4((c)->c_bst, (c)->c_bsh, (r), (v))
71
72 #define REG_READ(sc, r) REG_READ0((sc)->sc_config, (r))
73 #define REG_WRITE(sc, r, v) REG_WRITE0((sc)->sc_config, (r), (v))
74
75 static int gftty_cngetc(dev_t);
76 static void gftty_cnputc(dev_t, int);
77 static void gftty_cnpollc(dev_t, int);
78
79 static struct gftty_config gftty_cnconfig;
80 static struct cnm_state gftty_cnmagic_state;
81 static struct consdev gftty_consdev = {
82 .cn_getc = gftty_cngetc,
83 .cn_putc = gftty_cnputc,
84 .cn_pollc = gftty_cnpollc,
85 .cn_dev = NODEV,
86 .cn_pri = CN_NORMAL,
87 };
88
89 /*
90 * gftty_attach --
91 * Attach a Goldfish virual TTY.
92 */
93 void
94 gftty_attach(struct gftty_softc *sc)
95 {
96
97 aprint_naive("\n");
98 aprint_normal(": Google Goldfish TTY\n");
99
100 /* If we got here without a config, we're the console. */
101 if (sc->sc_config == NULL) {
102 KASSERT(gftty_is_console(sc));
103 sc->sc_config = &gftty_cnconfig;
104 aprint_normal_dev(sc->sc_dev, "console\n");
105 }
106 }
107
108 /*
109 * gftty_is_console --
110 * Returns true if the specified gftty instance is currently
111 * the console.
112 */
113 bool
114 gftty_is_console(struct gftty_softc *sc)
115 {
116 if (cn_tab == &gftty_consdev) {
117 bool val;
118
119 if (prop_dictionary_get_bool(device_properties(sc->sc_dev),
120 "is-console", &val)) {
121 return val;
122 }
123 }
124 return false;
125 }
126
127 /*
128 * gftty_init_config --
129 * Initialize a config structure.
130 */
131 static void
132 gftty_init_config(struct gftty_config *c, bus_space_tag_t bst,
133 bus_space_handle_t bsh)
134 {
135 c->c_bst = bst;
136 c->c_bsh = bsh;
137 c->c_version = REG_READ0(c, GFTTY_VERSION);
138 }
139
140 /*
141 * gftty_alloc_config --
142 * Allocate a config structure, initialize it, and assign
143 * it to this device.
144 */
145 void
146 gftty_alloc_config(struct gftty_softc *sc, bus_space_tag_t bst,
147 bus_space_handle_t bsh)
148 {
149 struct gftty_config *c = kmem_zalloc(sizeof(*c), KM_SLEEP);
150
151 gftty_init_config(c, bst, bsh);
152 sc->sc_config = c;
153 }
154
155 /*
156 * gftty_set_buffer --
157 * Set the buffer address / length for an I/O operation.
158 */
159 static void
160 gftty_set_buffer(struct gftty_config *c, bus_addr_t addr, bus_size_t size)
161 {
162 REG_WRITE0(c, GFTTY_DATA_PTR, BUS_ADDR_LO32(addr));
163 if (sizeof(bus_addr_t) == 8) {
164 REG_WRITE0(c, GFTTY_DATA_PTR_HIGH, BUS_ADDR_HI32(addr));
165 }
166 REG_WRITE0(c, GFTTY_DATA_LEN, (uint32_t)size);
167 }
168
169 /*
170 * gftty console routines.
171 */
172 static int
173 gftty_cngetc(dev_t dev)
174 {
175 struct gftty_config * const c = &gftty_cnconfig;
176
177 if (REG_READ0(c, GFTTY_BYTES_READY) == 0) {
178 return -1;
179 }
180
181 /*
182 * XXX This is all terrible and should burn to the ground.
183 * XXX This device desperately needs to be improved with
184 * XXX a GET_CHAR register.
185 */
186 bus_addr_t addr;
187 uint8_t buf[1];
188
189 if (c->c_version == 0) {
190 addr = (bus_addr_t)buf;
191 } else {
192 addr = vtophys((vaddr_t)buf);
193 }
194
195 gftty_set_buffer(c, addr, sizeof(buf));
196 REG_WRITE0(c, GFTTY_CMD, CMD_READ_BUFFER);
197
198 return buf[0];
199 }
200
201 static void
202 gftty_cnputc(dev_t dev, int ch)
203 {
204 REG_WRITE0(&gftty_cnconfig, GFTTY_PUT_CHAR, (unsigned char)ch);
205 }
206
207 static void
208 gftty_cnpollc(dev_t dev, int on)
209 {
210 /* XXX */
211 }
212
213 /*
214 * gftty_cnattach --
215 * Attach a Goldfish virtual TTY console.
216 */
217 void
218 gftty_cnattach(bus_space_tag_t bst, bus_space_handle_t bsh)
219 {
220 gftty_init_config(&gftty_cnconfig, bst, bsh);
221
222 cn_tab = &gftty_consdev;
223 cn_init_magic(&gftty_cnmagic_state);
224 cn_set_magic("+++++");
225 }
226