1 /* $NetBSD: xp.c,v 1.3 2017/01/08 16:41:35 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.3 2017/01/08 16:41:35 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/xpio.h> 46 47 #include "ioconf.h" 48 49 #define XP_SHM_BASE 0x71000000 50 #define XP_SHM_SIZE 0x00010000 /* 64KB for XP; rest 64KB for lance */ 51 #define XP_TAS_ADDR 0x61000000 52 53 struct xp_softc { 54 device_t sc_dev; 55 56 vaddr_t sc_shm_base; 57 vsize_t sc_shm_size; 58 vaddr_t sc_tas; 59 60 bool sc_isopen; 61 }; 62 63 static int xp_match(device_t, cfdata_t, void *); 64 static void xp_attach(device_t, device_t, void *); 65 66 dev_type_open(xp_open); 67 dev_type_close(xp_close); 68 dev_type_read(xp_read); 69 dev_type_write(xp_write); 70 dev_type_ioctl(xp_ioctl); 71 dev_type_mmap(xp_mmap); 72 73 const struct cdevsw xp_cdevsw = { 74 .d_open = xp_open, 75 .d_close = xp_close, 76 .d_read = xp_read, 77 .d_write = xp_write, 78 .d_ioctl = xp_ioctl, 79 .d_stop = nostop, 80 .d_tty = notty, 81 .d_poll = nopoll, 82 .d_mmap = xp_mmap, 83 .d_kqfilter = nokqfilter, 84 .d_discard = nodiscard, 85 .d_flag = 0 86 }; 87 88 CFATTACH_DECL_NEW(xp, sizeof(struct xp_softc), 89 xp_match, xp_attach, NULL, NULL); 90 91 /* #define XP_DEBUG */ 92 93 #ifdef XP_DEBUG 94 #define XP_DEBUG_ALL 0xff 95 uint32_t xp_debug = 0; 96 #define DPRINTF(x, y) if (xp_debug & (x)) printf y 97 #else 98 #define DPRINTF(x, y) /* nothing */ 99 #endif 100 101 static bool xp_matched; 102 103 /* 104 * PIO 0 port C is connected to XP's reset line 105 * 106 * XXX: PIO port functions should be shared with machdep.c for DIP SWs 107 */ 108 #define PIO_ADDR 0x49000000 109 #define PORT_A 0 110 #define PORT_B 1 111 #define PORT_C 2 112 #define CTRL 3 113 114 /* PIO0 Port C bit definition */ 115 #define XP_INT1_REQ 0 /* INTR B */ 116 /* unused */ /* IBF B */ 117 #define XP_INT1_ENA 2 /* INTE B */ 118 #define XP_INT5_REQ 3 /* INTR A */ 119 #define XP_INT5_ENA 4 /* INTE A */ 120 /* unused */ /* IBF A */ 121 #define PARITY 6 /* PC6 output to enable parity error */ 122 #define XP_RESET 7 /* PC7 output to reset HD647180 XP */ 123 124 /* Port control for PC6 and PC7 */ 125 #define ON 1 126 #define OFF 0 127 128 static uint8_t put_pio0c(uint8_t bit, uint8_t set) 129 { 130 volatile uint8_t * const pio0 = (uint8_t *)PIO_ADDR; 131 132 pio0[CTRL] = (bit << 1) | (set & 0x01); 133 134 return pio0[PORT_C]; 135 } 136 137 static int 138 xp_match(device_t parent, cfdata_t cf, void *aux) 139 { 140 struct mainbus_attach_args *maa = aux; 141 142 /* only one XP processor */ 143 if (xp_matched) 144 return 0; 145 146 if (strcmp(maa->ma_name, xp_cd.cd_name)) 147 return 0; 148 149 if (maa->ma_addr != XP_SHM_BASE) 150 return 0; 151 152 xp_matched = true; 153 return 1; 154 } 155 156 static void 157 xp_attach(device_t parent, device_t self, void *aux) 158 { 159 struct xp_softc *sc = device_private(self); 160 161 sc->sc_dev = self; 162 163 aprint_normal(": HD647180X I/O processor\n"); 164 165 sc->sc_shm_base = XP_SHM_BASE; 166 sc->sc_shm_size = XP_SHM_SIZE; 167 sc->sc_tas = XP_TAS_ADDR; 168 } 169 170 int 171 xp_open(dev_t dev, int flags, int devtype, struct lwp *l) 172 { 173 struct xp_softc *sc; 174 int unit; 175 176 DPRINTF(XP_DEBUG_ALL, ("%s\n", __func__)); 177 178 unit = minor(dev); 179 sc = device_lookup_private(&xp_cd, unit); 180 if (sc == NULL) 181 return ENXIO; 182 if (sc->sc_isopen) 183 return EBUSY; 184 185 sc->sc_isopen = true; 186 187 return 0; 188 } 189 190 int 191 xp_close(dev_t dev, int flags, int mode, struct lwp *l) 192 { 193 struct xp_softc *sc; 194 int unit; 195 196 DPRINTF(XP_DEBUG_ALL, ("%s\n", __func__)); 197 198 unit = minor(dev); 199 sc = device_lookup_private(&xp_cd, unit); 200 sc->sc_isopen = false; 201 202 return 0; 203 } 204 205 int 206 xp_ioctl(dev_t dev, u_long cmd, void *addr, int flags, struct lwp *l) 207 { 208 struct xp_softc *sc; 209 int unit, error; 210 struct xp_download *downld; 211 uint8_t *loadbuf; 212 size_t loadsize; 213 214 DPRINTF(XP_DEBUG_ALL, ("%s\n", __func__)); 215 216 unit = minor(dev); 217 sc = device_lookup_private(&xp_cd, unit); 218 219 switch (cmd) { 220 case XPIOCDOWNLD: 221 downld = addr; 222 loadsize = downld->size; 223 if (loadsize == 0 || loadsize > sc->sc_shm_size) { 224 return EINVAL; 225 } 226 227 loadbuf = kmem_alloc(loadsize, KM_SLEEP); 228 if (loadbuf == NULL) { 229 return ENOMEM; 230 } 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