1 /* $NetBSD: xp.c,v 1.5 2019/06/30 05:04:48 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 driver 29 */ 30 31 #include <sys/cdefs.h> 32 __KERNEL_RCSID(0, "$NetBSD: xp.c,v 1.5 2019/06/30 05:04:48 tsutsui Exp $"); 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/conf.h> 37 #include <sys/device.h> 38 #include <sys/ioctl.h> 39 #include <sys/kmem.h> 40 #include <sys/errno.h> 41 42 #include <uvm/uvm_extern.h> 43 44 #include <machine/autoconf.h> 45 #include <machine/board.h> 46 #include <machine/xpio.h> 47 48 #include "ioconf.h" 49 50 #define TRI_PORT_RAM_XP_OFFSET 0x00000 51 52 #define XP_SHM_BASE (TRI_PORT_RAM + TRI_PORT_RAM_XP_OFFSET) 53 #define XP_SHM_SIZE 0x00010000 /* 64KB for XP; rest 64KB for lance */ 54 #define XP_TAS_ADDR OBIO_TAS 55 56 struct xp_softc { 57 device_t sc_dev; 58 59 vaddr_t sc_shm_base; 60 vsize_t sc_shm_size; 61 vaddr_t sc_tas; 62 63 bool sc_isopen; 64 }; 65 66 static int xp_match(device_t, cfdata_t, void *); 67 static void xp_attach(device_t, device_t, void *); 68 69 dev_type_open(xp_open); 70 dev_type_close(xp_close); 71 dev_type_read(xp_read); 72 dev_type_write(xp_write); 73 dev_type_ioctl(xp_ioctl); 74 dev_type_mmap(xp_mmap); 75 76 const struct cdevsw xp_cdevsw = { 77 .d_open = xp_open, 78 .d_close = xp_close, 79 .d_read = xp_read, 80 .d_write = xp_write, 81 .d_ioctl = xp_ioctl, 82 .d_stop = nostop, 83 .d_tty = notty, 84 .d_poll = nopoll, 85 .d_mmap = xp_mmap, 86 .d_kqfilter = nokqfilter, 87 .d_discard = nodiscard, 88 .d_flag = 0 89 }; 90 91 CFATTACH_DECL_NEW(xp, sizeof(struct xp_softc), 92 xp_match, xp_attach, NULL, NULL); 93 94 /* #define XP_DEBUG */ 95 96 #ifdef XP_DEBUG 97 #define XP_DEBUG_ALL 0xff 98 uint32_t xp_debug = 0; 99 #define DPRINTF(x, y) if (xp_debug & (x)) printf y 100 #else 101 #define DPRINTF(x, y) /* nothing */ 102 #endif 103 104 static bool xp_matched; 105 106 /* 107 * PIO 0 port C is connected to XP's reset line 108 * 109 * XXX: PIO port functions should be shared with machdep.c for DIP SWs 110 */ 111 #define PIO_ADDR OBIO_PIO0_BASE 112 #define PORT_A 0 113 #define PORT_B 1 114 #define PORT_C 2 115 #define CTRL 3 116 117 /* PIO0 Port C bit definition */ 118 #define XP_INT1_REQ 0 /* INTR B */ 119 /* unused */ /* IBF B */ 120 #define XP_INT1_ENA 2 /* INTE B */ 121 #define XP_INT5_REQ 3 /* INTR A */ 122 #define XP_INT5_ENA 4 /* INTE A */ 123 /* unused */ /* IBF A */ 124 #define PARITY 6 /* PC6 output to enable parity error */ 125 #define XP_RESET 7 /* PC7 output to reset HD647180 XP */ 126 127 /* Port control for PC6 and PC7 */ 128 #define ON 1 129 #define OFF 0 130 131 static uint8_t put_pio0c(uint8_t bit, uint8_t set) 132 { 133 volatile uint8_t * const pio0 = (uint8_t *)PIO_ADDR; 134 135 pio0[CTRL] = (bit << 1) | (set & 0x01); 136 137 return pio0[PORT_C]; 138 } 139 140 static int 141 xp_match(device_t parent, cfdata_t cf, void *aux) 142 { 143 struct mainbus_attach_args *maa = aux; 144 145 /* only one XP processor */ 146 if (xp_matched) 147 return 0; 148 149 if (strcmp(maa->ma_name, xp_cd.cd_name)) 150 return 0; 151 152 if (maa->ma_addr != XP_SHM_BASE) 153 return 0; 154 155 xp_matched = true; 156 return 1; 157 } 158 159 static void 160 xp_attach(device_t parent, device_t self, void *aux) 161 { 162 struct xp_softc *sc = device_private(self); 163 164 sc->sc_dev = self; 165 166 aprint_normal(": HD647180X I/O processor\n"); 167 168 sc->sc_shm_base = XP_SHM_BASE; 169 sc->sc_shm_size = XP_SHM_SIZE; 170 sc->sc_tas = XP_TAS_ADDR; 171 } 172 173 int 174 xp_open(dev_t dev, int flags, int devtype, struct lwp *l) 175 { 176 struct xp_softc *sc; 177 int unit; 178 179 DPRINTF(XP_DEBUG_ALL, ("%s\n", __func__)); 180 181 unit = minor(dev); 182 sc = device_lookup_private(&xp_cd, unit); 183 if (sc == NULL) 184 return ENXIO; 185 if (sc->sc_isopen) 186 return EBUSY; 187 188 sc->sc_isopen = true; 189 190 return 0; 191 } 192 193 int 194 xp_close(dev_t dev, int flags, int mode, struct lwp *l) 195 { 196 struct xp_softc *sc; 197 int unit; 198 199 DPRINTF(XP_DEBUG_ALL, ("%s\n", __func__)); 200 201 unit = minor(dev); 202 sc = device_lookup_private(&xp_cd, unit); 203 sc->sc_isopen = false; 204 205 return 0; 206 } 207 208 int 209 xp_ioctl(dev_t dev, u_long cmd, void *addr, int flags, struct lwp *l) 210 { 211 struct xp_softc *sc; 212 int unit, error; 213 struct xp_download *downld; 214 uint8_t *loadbuf; 215 size_t loadsize; 216 217 DPRINTF(XP_DEBUG_ALL, ("%s\n", __func__)); 218 219 unit = minor(dev); 220 sc = device_lookup_private(&xp_cd, unit); 221 222 switch (cmd) { 223 case XPIOCDOWNLD: 224 downld = addr; 225 loadsize = downld->size; 226 if (loadsize == 0 || loadsize > sc->sc_shm_size) { 227 return EINVAL; 228 } 229 230 loadbuf = kmem_alloc(loadsize, KM_SLEEP); 231 error = copyin(downld->data, loadbuf, loadsize); 232 if (error == 0) { 233 put_pio0c(XP_RESET, ON); 234 delay(100); 235 memcpy((void *)sc->sc_shm_base, loadbuf, loadsize); 236 delay(100); 237 put_pio0c(XP_RESET, OFF); 238 } else { 239 DPRINTF(XP_DEBUG_ALL, ("%s: ioctl failed (err = %d)\n", 240 __func__, error)); 241 } 242 243 kmem_free(loadbuf, loadsize); 244 return error; 245 246 default: 247 return ENOTTY; 248 } 249 250 panic("%s: cmd (%ld) is not handled", device_xname(sc->sc_dev), cmd); 251 } 252 253 paddr_t 254 xp_mmap(dev_t dev, off_t offset, int prot) 255 { 256 struct xp_softc *sc; 257 int unit; 258 paddr_t pa; 259 260 pa = -1; 261 262 unit = minor(dev); 263 sc = device_lookup_private(&xp_cd, unit); 264 265 if (offset >= 0 && 266 offset < sc->sc_shm_size) { 267 pa = m68k_btop(m68k_trunc_page(sc->sc_shm_base) + offset); 268 } 269 270 return pa; 271 } 272 273 int 274 xp_read(dev_t dev, struct uio *uio, int flags) 275 { 276 277 return ENODEV; 278 } 279 280 int 281 xp_write(dev_t dev, struct uio *uio, int flags) 282 { 283 284 return ENODEV; 285 } 286