xref: /openbsd/sys/arch/luna88k/dev/xp.c (revision da5607f6)
1*da5607f6Sjsg /* $OpenBSD: xp.c,v 1.4 2024/06/26 01:40:49 jsg Exp $ */
20641c1a2Saoyama /* $NetBSD: xp.c,v 1.1 2016/12/03 17:38:02 tsutsui Exp $ */
30641c1a2Saoyama 
40641c1a2Saoyama /*-
50641c1a2Saoyama  * Copyright (c) 2016 Izumi Tsutsui.  All rights reserved.
60641c1a2Saoyama  *
70641c1a2Saoyama  * Redistribution and use in source and binary forms, with or without
80641c1a2Saoyama  * modification, are permitted provided that the following conditions
90641c1a2Saoyama  * are met:
100641c1a2Saoyama  * 1. Redistributions of source code must retain the above copyright
110641c1a2Saoyama  *    notice, this list of conditions and the following disclaimer.
120641c1a2Saoyama  * 2. Redistributions in binary form must reproduce the above copyright
130641c1a2Saoyama  *    notice, this list of conditions and the following disclaimer in the
140641c1a2Saoyama  *    documentation and/or other materials provided with the distribution.
150641c1a2Saoyama  *
160641c1a2Saoyama  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
170641c1a2Saoyama  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
180641c1a2Saoyama  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
190641c1a2Saoyama  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
200641c1a2Saoyama  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
210641c1a2Saoyama  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
220641c1a2Saoyama  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
230641c1a2Saoyama  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
240641c1a2Saoyama  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
250641c1a2Saoyama  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
260641c1a2Saoyama  */
270641c1a2Saoyama 
280641c1a2Saoyama /*
290641c1a2Saoyama  * LUNA's Hitachi HD647180 "XP" I/O processor driver
300641c1a2Saoyama  */
310641c1a2Saoyama 
320641c1a2Saoyama #include <sys/param.h>
330641c1a2Saoyama #include <sys/systm.h>
340641c1a2Saoyama #include <sys/conf.h>
350641c1a2Saoyama #include <sys/device.h>
360641c1a2Saoyama #include <sys/ioctl.h>
370641c1a2Saoyama #include <sys/malloc.h>
380641c1a2Saoyama #include <sys/errno.h>
390641c1a2Saoyama 
400641c1a2Saoyama #include <uvm/uvm_extern.h>
410641c1a2Saoyama 
420641c1a2Saoyama #include <machine/autoconf.h>
430641c1a2Saoyama #include <machine/board.h>
440641c1a2Saoyama #include <machine/xpio.h>
450641c1a2Saoyama 
460641c1a2Saoyama #define XP_SHM_BASE	TRI_PORT_RAM
470641c1a2Saoyama #define XP_SHM_SIZE	0x00010000	/* 64KB for XP; rest 64KB for lance */
480641c1a2Saoyama #define XP_TAS_ADDR	OBIO_TAS
490641c1a2Saoyama 
500641c1a2Saoyama struct xp_softc {
510641c1a2Saoyama 	struct device	sc_dev;
520641c1a2Saoyama 
530641c1a2Saoyama 	vaddr_t		sc_shm_base;
540641c1a2Saoyama 	vsize_t		sc_shm_size;
550641c1a2Saoyama 	vaddr_t		sc_tas;
560641c1a2Saoyama 
570641c1a2Saoyama 	bool		sc_isopen;
580641c1a2Saoyama };
590641c1a2Saoyama 
600641c1a2Saoyama static int xp_match(struct device *, void *, void *);
610641c1a2Saoyama static void xp_attach(struct device *, struct device *, void *);
620641c1a2Saoyama 
630641c1a2Saoyama const struct cfattach xp_ca = {
640641c1a2Saoyama 	sizeof (struct xp_softc), xp_match, xp_attach
650641c1a2Saoyama };
660641c1a2Saoyama 
670641c1a2Saoyama struct cfdriver xp_cd = {
680641c1a2Saoyama 	NULL, "xp", DV_DULL
690641c1a2Saoyama };
700641c1a2Saoyama 
710641c1a2Saoyama /* #define XP_DEBUG */
720641c1a2Saoyama 
730641c1a2Saoyama #ifdef XP_DEBUG
740641c1a2Saoyama #define XP_DEBUG_ALL	0xff
750641c1a2Saoyama uint32_t xp_debug = 0;
760641c1a2Saoyama #define DPRINTF(x, y)	if (xp_debug & (x)) printf y
770641c1a2Saoyama #else
780641c1a2Saoyama #define DPRINTF(x, y)	/* nothing */
790641c1a2Saoyama #endif
800641c1a2Saoyama 
810641c1a2Saoyama static bool xp_matched;
820641c1a2Saoyama 
830641c1a2Saoyama /*
840641c1a2Saoyama  * PIO 0 port C is connected to XP's reset line
850641c1a2Saoyama  *
860641c1a2Saoyama  * XXX: PIO port functions should be shared with machdep.c for DIP SWs
870641c1a2Saoyama  */
880641c1a2Saoyama #define PIO_ADDR	OBIO_PIO0_BASE
890641c1a2Saoyama #define PORT_A		(0 * 4)
900641c1a2Saoyama #define PORT_B		(1 * 4)
910641c1a2Saoyama #define PORT_C		(2 * 4)
920641c1a2Saoyama #define CTRL		(3 * 4)
930641c1a2Saoyama 
940641c1a2Saoyama /* PIO0 Port C bit definition */
950641c1a2Saoyama #define XP_INT1_REQ	0	/* INTR B */
960641c1a2Saoyama 	/* unused */		/* IBF B */
970641c1a2Saoyama #define XP_INT1_ENA	2	/* INTE B */
980641c1a2Saoyama #define XP_INT5_REQ	3	/* INTR A */
990641c1a2Saoyama #define XP_INT5_ENA	4	/* INTE A */
1000641c1a2Saoyama 	/* unused */		/* IBF A */
1010641c1a2Saoyama #define PARITY		6	/* PC6 output to enable parity error */
1020641c1a2Saoyama #define XP_RESET	7	/* PC7 output to reset HD647180 XP */
1030641c1a2Saoyama 
1040641c1a2Saoyama /* Port control for PC6 and PC7 */
1050641c1a2Saoyama #define ON		1
1060641c1a2Saoyama #define OFF		0
1070641c1a2Saoyama 
108*da5607f6Sjsg static uint8_t
put_pio0c(uint8_t bit,uint8_t set)109*da5607f6Sjsg put_pio0c(uint8_t bit, uint8_t set)
1100641c1a2Saoyama {
1110641c1a2Saoyama 	volatile uint8_t * const pio0 = (uint8_t *)PIO_ADDR;
1120641c1a2Saoyama 
1130641c1a2Saoyama 	pio0[CTRL] = (bit << 1) | (set & 0x01);
1140641c1a2Saoyama 
1150641c1a2Saoyama 	return pio0[PORT_C];
1160641c1a2Saoyama }
1170641c1a2Saoyama 
1180641c1a2Saoyama static int
xp_match(struct device * parent,void * cf,void * aux)1190641c1a2Saoyama xp_match(struct device *parent, void *cf, void *aux)
1200641c1a2Saoyama {
1210641c1a2Saoyama 	struct mainbus_attach_args *maa = aux;
1220641c1a2Saoyama 
1230641c1a2Saoyama 	/* only one XP processor */
1240641c1a2Saoyama 	if (xp_matched)
1250641c1a2Saoyama 		return 0;
1260641c1a2Saoyama 
1270641c1a2Saoyama 	if (strcmp(maa->ma_name, xp_cd.cd_name))
1280641c1a2Saoyama 		return 0;
1290641c1a2Saoyama 
1300641c1a2Saoyama 	if (maa->ma_addr != XP_SHM_BASE)
1310641c1a2Saoyama 		return 0;
1320641c1a2Saoyama 
1330641c1a2Saoyama 	xp_matched = true;
1340641c1a2Saoyama 	return 1;
1350641c1a2Saoyama }
1360641c1a2Saoyama 
1370641c1a2Saoyama static void
xp_attach(struct device * parent,struct device * self,void * aux)1380641c1a2Saoyama xp_attach(struct device *parent, struct device *self, void *aux)
1390641c1a2Saoyama {
1400641c1a2Saoyama 	struct xp_softc *sc = (void *)self;
1410641c1a2Saoyama 
1420641c1a2Saoyama 	printf(": HD647180X I/O processor\n");
1430641c1a2Saoyama 
1440641c1a2Saoyama 	sc->sc_shm_base = XP_SHM_BASE;
1450641c1a2Saoyama 	sc->sc_shm_size = XP_SHM_SIZE;
1460641c1a2Saoyama 	sc->sc_tas      = XP_TAS_ADDR;
1470641c1a2Saoyama }
1480641c1a2Saoyama 
1490641c1a2Saoyama int
xpopen(dev_t dev,int flags,int mode,struct proc * p)1500641c1a2Saoyama xpopen(dev_t dev, int flags, int mode, struct proc *p)
1510641c1a2Saoyama {
1520641c1a2Saoyama 	struct xp_softc *sc;
1530641c1a2Saoyama 	int unit;
1540641c1a2Saoyama 
1550641c1a2Saoyama 	DPRINTF(XP_DEBUG_ALL, ("%s\n", __func__));
1560641c1a2Saoyama 
1570641c1a2Saoyama 	unit = minor(dev);
1580641c1a2Saoyama 	if (unit >= xp_cd.cd_ndevs)
1590641c1a2Saoyama 		return ENXIO;
1600641c1a2Saoyama 	sc = xp_cd.cd_devs[unit];
1610641c1a2Saoyama 	if (sc == NULL)
1620641c1a2Saoyama 		return ENXIO;
1630641c1a2Saoyama 	if (sc->sc_isopen)
1640641c1a2Saoyama 		return EBUSY;
1650641c1a2Saoyama 
1660641c1a2Saoyama 	sc->sc_isopen = true;
1670641c1a2Saoyama 
1680641c1a2Saoyama 	return 0;
1690641c1a2Saoyama }
1700641c1a2Saoyama 
1710641c1a2Saoyama int
xpclose(dev_t dev,int flags,int mode,struct proc * p)1720641c1a2Saoyama xpclose(dev_t dev, int flags, int mode, struct proc *p)
1730641c1a2Saoyama {
1740641c1a2Saoyama 	struct xp_softc *sc;
1750641c1a2Saoyama 	int unit;
1760641c1a2Saoyama 
1770641c1a2Saoyama 	DPRINTF(XP_DEBUG_ALL, ("%s\n", __func__));
1780641c1a2Saoyama 
1790641c1a2Saoyama 	unit = minor(dev);
1800641c1a2Saoyama 	if (unit >= xp_cd.cd_ndevs)
1810641c1a2Saoyama 		return ENXIO;
1820641c1a2Saoyama 	sc = xp_cd.cd_devs[unit];
1830641c1a2Saoyama 	sc->sc_isopen = false;
1840641c1a2Saoyama 
1850641c1a2Saoyama 	return 0;
1860641c1a2Saoyama }
1870641c1a2Saoyama 
1880641c1a2Saoyama int
xpioctl(dev_t dev,u_long cmd,void * addr,int flags,struct proc * p)1890641c1a2Saoyama xpioctl(dev_t dev, u_long cmd, void *addr, int flags, struct proc *p)
1900641c1a2Saoyama {
1910641c1a2Saoyama 	struct xp_softc *sc;
1920641c1a2Saoyama 	int unit, error;
1930641c1a2Saoyama 	struct xp_download *downld;
1940641c1a2Saoyama 	uint8_t *loadbuf;
1950641c1a2Saoyama 	size_t loadsize;
1960641c1a2Saoyama 
1970641c1a2Saoyama 	DPRINTF(XP_DEBUG_ALL, ("%s\n", __func__));
1980641c1a2Saoyama 
1990641c1a2Saoyama 	unit = minor(dev);
2000641c1a2Saoyama 	if (unit >= xp_cd.cd_ndevs)
2010641c1a2Saoyama 		return ENXIO;
2020641c1a2Saoyama 	sc = xp_cd.cd_devs[unit];
2030641c1a2Saoyama 
2040641c1a2Saoyama 	switch (cmd) {
2050641c1a2Saoyama 	case XPIOCDOWNLD:
2060641c1a2Saoyama 		downld = addr;
2070641c1a2Saoyama 		loadsize = downld->size;
20812f91a82Saoyama 		if (loadsize == 0 || loadsize > sc->sc_shm_size) {
2090641c1a2Saoyama 			return EINVAL;
2100641c1a2Saoyama 		}
2110641c1a2Saoyama 
2120641c1a2Saoyama 		loadbuf = malloc(loadsize, M_DEVBUF, M_WAITOK);
2130641c1a2Saoyama 		if (loadbuf == NULL) {
2140641c1a2Saoyama 			return ENOMEM;
2150641c1a2Saoyama 		}
2160641c1a2Saoyama 		error = copyin(downld->data, loadbuf, loadsize);
2170641c1a2Saoyama 		if (error == 0) {
2180641c1a2Saoyama 			put_pio0c(XP_RESET, ON);
2190641c1a2Saoyama 			delay(100);
2200641c1a2Saoyama 			memcpy((void *)sc->sc_shm_base, loadbuf, loadsize);
2210641c1a2Saoyama 			delay(100);
2220641c1a2Saoyama 			put_pio0c(XP_RESET, OFF);
2230641c1a2Saoyama 		} else {
2240641c1a2Saoyama 			DPRINTF(XP_DEBUG_ALL, ("%s: ioctl failed (err =  %d)\n",
2250641c1a2Saoyama 			    __func__, error));
2260641c1a2Saoyama 		}
2270641c1a2Saoyama 
2280641c1a2Saoyama 		free(loadbuf, M_DEVBUF, loadsize);
2290641c1a2Saoyama 		return error;
2300641c1a2Saoyama 
2310641c1a2Saoyama 	default:
2320641c1a2Saoyama 		return ENOTTY;
2330641c1a2Saoyama 	}
2340641c1a2Saoyama }
2350641c1a2Saoyama 
2360641c1a2Saoyama paddr_t
xpmmap(dev_t dev,off_t offset,int prot)2370641c1a2Saoyama xpmmap(dev_t dev, off_t offset, int prot)
2380641c1a2Saoyama {
2390641c1a2Saoyama 	struct xp_softc *sc;
2400641c1a2Saoyama 	int unit;
2410641c1a2Saoyama 	paddr_t pa;
2420641c1a2Saoyama 
2430641c1a2Saoyama 	pa = -1;
2440641c1a2Saoyama 
2450641c1a2Saoyama 	unit = minor(dev);
2460641c1a2Saoyama 	sc = xp_cd.cd_devs[unit];
2470641c1a2Saoyama 
2480641c1a2Saoyama 	if (offset >= 0 &&
2490641c1a2Saoyama 	    offset < sc->sc_shm_size) {
2500641c1a2Saoyama 		pa = (paddr_t)(trunc_page(sc->sc_shm_base) + offset);
2510641c1a2Saoyama 	}
2520641c1a2Saoyama 
2530641c1a2Saoyama 	return pa;
2540641c1a2Saoyama }
255