xpbus.c revision 1.1 1 1.1 tsutsui /* $NetBSD: xpbus.c,v 1.1 2022/06/10 21:42:23 tsutsui Exp $ */
2 1.1 tsutsui
3 1.1 tsutsui /*-
4 1.1 tsutsui * Copyright (c) 2016 Izumi Tsutsui. All rights reserved.
5 1.1 tsutsui *
6 1.1 tsutsui * Redistribution and use in source and binary forms, with or without
7 1.1 tsutsui * modification, are permitted provided that the following conditions
8 1.1 tsutsui * are met:
9 1.1 tsutsui * 1. Redistributions of source code must retain the above copyright
10 1.1 tsutsui * notice, this list of conditions and the following disclaimer.
11 1.1 tsutsui * 2. Redistributions in binary form must reproduce the above copyright
12 1.1 tsutsui * notice, this list of conditions and the following disclaimer in the
13 1.1 tsutsui * documentation and/or other materials provided with the distribution.
14 1.1 tsutsui *
15 1.1 tsutsui * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 1.1 tsutsui * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 1.1 tsutsui * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 1.1 tsutsui * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 1.1 tsutsui * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 1.1 tsutsui * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 1.1 tsutsui * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 1.1 tsutsui * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 1.1 tsutsui * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 1.1 tsutsui * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 1.1 tsutsui */
26 1.1 tsutsui
27 1.1 tsutsui /*
28 1.1 tsutsui * LUNA's Hitachi HD647180 "XP" I/O processor
29 1.1 tsutsui */
30 1.1 tsutsui
31 1.1 tsutsui /*
32 1.1 tsutsui * Specification of interrupts from XP to the host is confirmed
33 1.1 tsutsui * by Kenji Aoyama, in xptty(4) driver for OpenBSD/luna88k:
34 1.1 tsutsui * https://gist.github.com/ao-kenji/790b0822e46a50ea63131cfa8d9110e7
35 1.1 tsutsui * and CP/M BIOS for HD647180 on LUNA:
36 1.1 tsutsui * https://gist.github.com/ao-kenji/4f1e2b010f3b2b41ab07f3a8a3cc7484
37 1.1 tsutsui */
38 1.1 tsutsui
39 1.1 tsutsui #include <sys/cdefs.h>
40 1.1 tsutsui __KERNEL_RCSID(0, "$NetBSD: xpbus.c,v 1.1 2022/06/10 21:42:23 tsutsui Exp $");
41 1.1 tsutsui
42 1.1 tsutsui #include <sys/param.h>
43 1.1 tsutsui #include <sys/systm.h>
44 1.1 tsutsui #include <sys/conf.h>
45 1.1 tsutsui #include <sys/atomic.h>
46 1.1 tsutsui #include <sys/device.h>
47 1.1 tsutsui
48 1.1 tsutsui #include <machine/autoconf.h>
49 1.1 tsutsui #include <machine/board.h>
50 1.1 tsutsui
51 1.1 tsutsui #include <luna68k/dev/xpbusvar.h>
52 1.1 tsutsui #include <luna68k/dev/xplxfirm.h>
53 1.1 tsutsui
54 1.1 tsutsui /*
55 1.1 tsutsui * PIO 0 port C is connected to XP's reset line
56 1.1 tsutsui *
57 1.1 tsutsui * XXX: PIO port functions should be shared with machdep.c for DIP SWs
58 1.1 tsutsui */
59 1.1 tsutsui #define PIO_ADDR OBIO_PIO0_BASE
60 1.1 tsutsui #define PORT_A 0
61 1.1 tsutsui #define PORT_B 1
62 1.1 tsutsui #define PORT_C 2
63 1.1 tsutsui #define CTRL 3
64 1.1 tsutsui
65 1.1 tsutsui /* PIO0 Port C bit definition */
66 1.1 tsutsui #define XP_INT1_REQ 0 /* INTR B */
67 1.1 tsutsui /* unused */ /* IBF B */
68 1.1 tsutsui #define XP_INT1_ENA 2 /* INTE B */
69 1.1 tsutsui #define XP_INT5_REQ 3 /* INTR A */
70 1.1 tsutsui #define XP_INT5_ENA 4 /* INTE A */
71 1.1 tsutsui /* unused */ /* IBF A */
72 1.1 tsutsui #define PARITY 6 /* PC6 output to enable parity error */
73 1.1 tsutsui #define XP_RESET 7 /* PC7 output to reset HD647180 XP */
74 1.1 tsutsui
75 1.1 tsutsui /* Port control for PC6 and PC7 */
76 1.1 tsutsui #define ON 1
77 1.1 tsutsui #define OFF 0
78 1.1 tsutsui
79 1.1 tsutsui
80 1.1 tsutsui struct xpbus_softc {
81 1.1 tsutsui device_t sc_dev;
82 1.1 tsutsui };
83 1.1 tsutsui
84 1.1 tsutsui static const struct xpbus_attach_args xpdevs[] = {
85 1.1 tsutsui { "xp" },
86 1.1 tsutsui { "psgpam" },
87 1.1 tsutsui };
88 1.1 tsutsui
89 1.1 tsutsui static int xpbus_match(device_t, cfdata_t, void *);
90 1.1 tsutsui static void xpbus_attach(device_t, device_t, void *);
91 1.1 tsutsui
92 1.1 tsutsui CFATTACH_DECL_NEW(xpbus, sizeof(struct xpbus_softc),
93 1.1 tsutsui xpbus_match, xpbus_attach, NULL, NULL);
94 1.1 tsutsui
95 1.1 tsutsui static bool xpbus_matched;
96 1.1 tsutsui
97 1.1 tsutsui /*
98 1.1 tsutsui * xpbus acquired device sharing bitmap
99 1.1 tsutsui */
100 1.1 tsutsui static volatile unsigned int xp_acquired;
101 1.1 tsutsui
102 1.1 tsutsui /* XP SHM dirty flag */
103 1.1 tsutsui static bool xp_shm_dirty = true;
104 1.1 tsutsui
105 1.1 tsutsui static int
106 1.1 tsutsui xpbus_match(device_t parent, cfdata_t cf, void *aux)
107 1.1 tsutsui {
108 1.1 tsutsui struct mainbus_attach_args *ma = aux;
109 1.1 tsutsui
110 1.1 tsutsui /* only one XP processor */
111 1.1 tsutsui if (xpbus_matched)
112 1.1 tsutsui return 0;
113 1.1 tsutsui
114 1.1 tsutsui if (ma->ma_addr != XP_SHM_BASE)
115 1.1 tsutsui return 0;
116 1.1 tsutsui
117 1.1 tsutsui xpbus_matched = true;
118 1.1 tsutsui return 1;
119 1.1 tsutsui }
120 1.1 tsutsui
121 1.1 tsutsui static void
122 1.1 tsutsui xpbus_attach(device_t parent, device_t self, void *aux)
123 1.1 tsutsui {
124 1.1 tsutsui struct xpbus_softc *sc = device_private(self);
125 1.1 tsutsui struct xpbus_attach_args xa;
126 1.1 tsutsui int i;
127 1.1 tsutsui
128 1.1 tsutsui sc->sc_dev = self;
129 1.1 tsutsui aprint_normal("\n");
130 1.1 tsutsui
131 1.1 tsutsui for (i = 0; i < __arraycount(xpdevs); i++) {
132 1.1 tsutsui xa = xpdevs[i];
133 1.1 tsutsui config_found(self, &xa, NULL, CFARGS_NONE);
134 1.1 tsutsui }
135 1.1 tsutsui }
136 1.1 tsutsui
137 1.1 tsutsui /*
138 1.1 tsutsui * acquire xpbus from child devices
139 1.1 tsutsui * if success, return non-zero acquired map
140 1.1 tsutsui * if fail, return 0
141 1.1 tsutsui */
142 1.1 tsutsui u_int
143 1.1 tsutsui xp_acquire(int xplx_devid, u_int excl)
144 1.1 tsutsui {
145 1.1 tsutsui
146 1.1 tsutsui for (;;) {
147 1.1 tsutsui unsigned int before, after;
148 1.1 tsutsui before = xp_acquired;
149 1.1 tsutsui if (before & XP_ACQ_EXCL)
150 1.1 tsutsui return 0;
151 1.1 tsutsui if (before & (1 << xplx_devid))
152 1.1 tsutsui return 0;
153 1.1 tsutsui after = before | (1 << xplx_devid) | excl;
154 1.1 tsutsui if (atomic_cas_uint(&xp_acquired, before, after) == before) {
155 1.1 tsutsui return after & ~(excl);
156 1.1 tsutsui }
157 1.1 tsutsui }
158 1.1 tsutsui }
159 1.1 tsutsui
160 1.1 tsutsui /* release xpbus by child devices */
161 1.1 tsutsui void
162 1.1 tsutsui xp_release(int xplx_devid)
163 1.1 tsutsui {
164 1.1 tsutsui
165 1.1 tsutsui for (;;) {
166 1.1 tsutsui unsigned int before, after;
167 1.1 tsutsui before = xp_acquired;
168 1.1 tsutsui after = before & ~(1 << xplx_devid) & ~XP_ACQ_EXCL;
169 1.1 tsutsui if (atomic_cas_uint(&xp_acquired, before, after) == before) {
170 1.1 tsutsui return;
171 1.1 tsutsui }
172 1.1 tsutsui }
173 1.1 tsutsui }
174 1.1 tsutsui
175 1.1 tsutsui /* set the xp_shm_dirty flag */
176 1.1 tsutsui void
177 1.1 tsutsui xp_set_shm_dirty(void)
178 1.1 tsutsui {
179 1.1 tsutsui
180 1.1 tsutsui xp_shm_dirty = true;
181 1.1 tsutsui }
182 1.1 tsutsui
183 1.1 tsutsui /* reload firmware if xp_shm_dirty */
184 1.1 tsutsui void
185 1.1 tsutsui xp_ensure_firmware(void)
186 1.1 tsutsui {
187 1.1 tsutsui
188 1.1 tsutsui if (xp_shm_dirty) {
189 1.1 tsutsui /* firmware transfer */
190 1.1 tsutsui xp_cpu_reset_hold();
191 1.1 tsutsui delay(100);
192 1.1 tsutsui memcpy((void *)XP_SHM_BASE, xplx, xplx_size);
193 1.1 tsutsui /* XXX maybe not necessary */
194 1.1 tsutsui delay(100);
195 1.1 tsutsui xp_cpu_reset_release();
196 1.1 tsutsui xp_shm_dirty = false;
197 1.1 tsutsui }
198 1.1 tsutsui }
199 1.1 tsutsui
200 1.1 tsutsui /* PIO PORTC write */
201 1.1 tsutsui uint8_t
202 1.1 tsutsui put_pio0c(uint8_t bit, uint8_t set)
203 1.1 tsutsui {
204 1.1 tsutsui volatile uint8_t * const pio0 = (uint8_t *)PIO_ADDR;
205 1.1 tsutsui
206 1.1 tsutsui pio0[CTRL] = (bit << 1) | (set & 0x01);
207 1.1 tsutsui
208 1.1 tsutsui return pio0[PORT_C];
209 1.1 tsutsui }
210 1.1 tsutsui
211 1.1 tsutsui /* hold XP RESET signal */
212 1.1 tsutsui void
213 1.1 tsutsui xp_cpu_reset_hold(void)
214 1.1 tsutsui {
215 1.1 tsutsui
216 1.1 tsutsui put_pio0c(XP_RESET, ON);
217 1.1 tsutsui }
218 1.1 tsutsui
219 1.1 tsutsui /* release XP RESET signal */
220 1.1 tsutsui void
221 1.1 tsutsui xp_cpu_reset_release(void)
222 1.1 tsutsui {
223 1.1 tsutsui
224 1.1 tsutsui put_pio0c(XP_RESET, OFF);
225 1.1 tsutsui }
226 1.1 tsutsui
227 1.1 tsutsui /* one-shot XP RESET signal */
228 1.1 tsutsui void
229 1.1 tsutsui xp_cpu_reset(void)
230 1.1 tsutsui {
231 1.1 tsutsui
232 1.1 tsutsui xp_cpu_reset_hold();
233 1.1 tsutsui delay(100);
234 1.1 tsutsui xp_cpu_reset_release();
235 1.1 tsutsui }
236 1.1 tsutsui
237 1.1 tsutsui /* enable XP to Host interrupt 1 */
238 1.1 tsutsui void
239 1.1 tsutsui xp_intr1_enable(void)
240 1.1 tsutsui {
241 1.1 tsutsui
242 1.1 tsutsui put_pio0c(XP_INT1_ENA, ON);
243 1.1 tsutsui }
244 1.1 tsutsui
245 1.1 tsutsui /* disable XP to Host interrupt 1 */
246 1.1 tsutsui void
247 1.1 tsutsui xp_intr1_disable(void)
248 1.1 tsutsui {
249 1.1 tsutsui
250 1.1 tsutsui put_pio0c(XP_INT1_ENA, OFF);
251 1.1 tsutsui }
252 1.1 tsutsui
253 1.1 tsutsui /* interrupt 1 ack */
254 1.1 tsutsui void
255 1.1 tsutsui xp_intr1_acknowledge(void)
256 1.1 tsutsui {
257 1.1 tsutsui
258 1.1 tsutsui /* reset the interrupt request: read PIO0 port A */
259 1.1 tsutsui /* XXX: probably */
260 1.1 tsutsui *(volatile uint8_t *)OBIO_PIO0A;
261 1.1 tsutsui /* XXX: just a guess */
262 1.1 tsutsui *(volatile uint8_t *)OBIO_PIO0B;
263 1.1 tsutsui }
264 1.1 tsutsui
265 1.1 tsutsui /* enable XP to Host interrupt 5 */
266 1.1 tsutsui void
267 1.1 tsutsui xp_intr5_enable(void)
268 1.1 tsutsui {
269 1.1 tsutsui
270 1.1 tsutsui put_pio0c(XP_INT5_ENA, ON);
271 1.1 tsutsui }
272 1.1 tsutsui
273 1.1 tsutsui /* disable XP to Host interrupt 5 */
274 1.1 tsutsui void
275 1.1 tsutsui xp_intr5_disable(void)
276 1.1 tsutsui {
277 1.1 tsutsui
278 1.1 tsutsui put_pio0c(XP_INT5_ENA, OFF);
279 1.1 tsutsui }
280 1.1 tsutsui
281 1.1 tsutsui /* interrupt 5 ack */
282 1.1 tsutsui void
283 1.1 tsutsui xp_intr5_acknowledge(void)
284 1.1 tsutsui {
285 1.1 tsutsui
286 1.1 tsutsui /* reset the interrupt request: read PIO0 port A */
287 1.1 tsutsui (void)*(volatile uint8_t *)OBIO_PIO0A;
288 1.1 tsutsui }
289 1.1 tsutsui
290 1.1 tsutsui /* get XP shared memory pointer */
291 1.1 tsutsui void *
292 1.1 tsutsui xp_shmptr(int offset)
293 1.1 tsutsui {
294 1.1 tsutsui
295 1.1 tsutsui return (uint8_t *)XP_SHM_BASE + offset;
296 1.1 tsutsui }
297 1.1 tsutsui
298 1.1 tsutsui /* read 1 byte */
299 1.1 tsutsui int
300 1.1 tsutsui xp_readmem8(int offset)
301 1.1 tsutsui {
302 1.1 tsutsui
303 1.1 tsutsui return *((volatile uint8_t *)xp_shmptr(offset));
304 1.1 tsutsui }
305 1.1 tsutsui
306 1.1 tsutsui /* read 1 16bitLE */
307 1.1 tsutsui int
308 1.1 tsutsui xp_readmem16le(int offset)
309 1.1 tsutsui {
310 1.1 tsutsui
311 1.1 tsutsui return le16toh(*(volatile uint16_t *)xp_shmptr(offset));
312 1.1 tsutsui }
313 1.1 tsutsui
314 1.1 tsutsui /* write 1 byte */
315 1.1 tsutsui void
316 1.1 tsutsui xp_writemem8(int offset, int v)
317 1.1 tsutsui {
318 1.1 tsutsui
319 1.1 tsutsui *(volatile uint8_t *)(xp_shmptr(offset)) = v;
320 1.1 tsutsui }
321 1.1 tsutsui
322 1.1 tsutsui /* write 1 16bitLE */
323 1.1 tsutsui void
324 1.1 tsutsui xp_writemem16le(int offset, int v)
325 1.1 tsutsui {
326 1.1 tsutsui
327 1.1 tsutsui *((volatile uint16_t *)xp_shmptr(offset)) = htole16((uint16_t)v);
328 1.1 tsutsui }
329