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