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