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 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 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 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 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 177 xp_set_shm_dirty(void) 178 { 179 180 xp_shm_dirty = true; 181 } 182 183 /* reload firmware if xp_shm_dirty */ 184 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 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 213 xp_cpu_reset_hold(void) 214 { 215 216 put_pio0c(XP_RESET, ON); 217 } 218 219 /* release XP RESET signal */ 220 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 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 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 247 xp_intr1_disable(void) 248 { 249 250 put_pio0c(XP_INT1_ENA, OFF); 251 } 252 253 /* interrupt 1 ack */ 254 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 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 275 xp_intr5_disable(void) 276 { 277 278 put_pio0c(XP_INT5_ENA, OFF); 279 } 280 281 /* interrupt 5 ack */ 282 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 * 292 xp_shmptr(int offset) 293 { 294 295 return (uint8_t *)XP_SHM_BASE + offset; 296 } 297 298 /* read 1 byte */ 299 int 300 xp_readmem8(int offset) 301 { 302 303 return *((volatile uint8_t *)xp_shmptr(offset)); 304 } 305 306 /* read 1 16bitLE */ 307 int 308 xp_readmem16le(int offset) 309 { 310 311 return le16toh(*(volatile uint16_t *)xp_shmptr(offset)); 312 } 313 314 /* write 1 byte */ 315 void 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 324 xp_writemem16le(int offset, int v) 325 { 326 327 *((volatile uint16_t *)xp_shmptr(offset)) = htole16((uint16_t)v); 328 } 329