Home | History | Annotate | Line # | Download | only in dev
      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