xref: /netbsd-src/sys/dev/mvme/vme_two.c (revision f18840a45d280589067e13afee438ea2088667e9)
1*f18840a4Smsaitoh /*	$NetBSD: vme_two.c,v 1.9 2021/12/05 07:21:59 msaitoh Exp $	*/
208bde987Sscw 
308bde987Sscw /*-
408bde987Sscw  * Copyright (c) 1999, 2002 The NetBSD Foundation, Inc.
508bde987Sscw  * All rights reserved.
608bde987Sscw  *
708bde987Sscw  * This code is derived from software contributed to The NetBSD Foundation
808bde987Sscw  * by Steve C. Woodford.
908bde987Sscw  *
1008bde987Sscw  * Redistribution and use in source and binary forms, with or without
1108bde987Sscw  * modification, are permitted provided that the following conditions
1208bde987Sscw  * are met:
1308bde987Sscw  * 1. Redistributions of source code must retain the above copyright
1408bde987Sscw  *    notice, this list of conditions and the following disclaimer.
1508bde987Sscw  * 2. Redistributions in binary form must reproduce the above copyright
1608bde987Sscw  *    notice, this list of conditions and the following disclaimer in the
1708bde987Sscw  *    documentation and/or other materials provided with the distribution.
1808bde987Sscw  *
1908bde987Sscw  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2008bde987Sscw  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2108bde987Sscw  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2208bde987Sscw  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2308bde987Sscw  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2408bde987Sscw  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2508bde987Sscw  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2608bde987Sscw  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2708bde987Sscw  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2808bde987Sscw  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2908bde987Sscw  * POSSIBILITY OF SUCH DAMAGE.
3008bde987Sscw  */
3108bde987Sscw 
3208bde987Sscw /*
3308bde987Sscw  * VME support specific to the VMEchip2 found on all high-end MVME boards
3408bde987Sscw  */
3508bde987Sscw 
36365cbd94Slukem #include <sys/cdefs.h>
37*f18840a4Smsaitoh __KERNEL_RCSID(0, "$NetBSD: vme_two.c,v 1.9 2021/12/05 07:21:59 msaitoh Exp $");
38365cbd94Slukem 
3908bde987Sscw #include "vmetwo.h"
4008bde987Sscw 
4108bde987Sscw #include <sys/param.h>
4208bde987Sscw #include <sys/kernel.h>
4308bde987Sscw #include <sys/systm.h>
4408bde987Sscw #include <sys/device.h>
4508bde987Sscw 
46a2a38285Sad #include <sys/cpu.h>
47a2a38285Sad #include <sys/bus.h>
4808bde987Sscw 
4908bde987Sscw #include <dev/vme/vmereg.h>
5008bde987Sscw #include <dev/vme/vmevar.h>
5108bde987Sscw 
5208bde987Sscw #include <dev/mvme/mvmebus.h>
5308bde987Sscw #include <dev/mvme/vme_tworeg.h>
5408bde987Sscw #include <dev/mvme/vme_twovar.h>
5508bde987Sscw 
5608bde987Sscw void vmetwo_master_range(struct vmetwo_softc *, int, struct mvmebus_range *);
5708bde987Sscw void vmetwo_slave_range(struct vmetwo_softc *, int, vme_am_t,
5808bde987Sscw 	struct mvmebus_range *);
5908bde987Sscw 
6008bde987Sscw /* ARGSUSED */
6108bde987Sscw void
vmetwo_init(struct vmetwo_softc * sc)62454af1c0Sdsl vmetwo_init(struct vmetwo_softc *sc)
6308bde987Sscw {
6408bde987Sscw 	u_int32_t reg;
6508bde987Sscw 	int i;
6608bde987Sscw 
6708bde987Sscw 	/* Initialise stuff for the common mvmebus front-end */
6808bde987Sscw 	sc->sc_mvmebus.sc_chip = sc;
6908bde987Sscw 	sc->sc_mvmebus.sc_nmasters = VME2_NMASTERS;
7008bde987Sscw 	sc->sc_mvmebus.sc_masters = &sc->sc_master[0];
7108bde987Sscw 	sc->sc_mvmebus.sc_nslaves = VME2_NSLAVES;
7208bde987Sscw 	sc->sc_mvmebus.sc_slaves = &sc->sc_slave[0];
7308bde987Sscw 	sc->sc_mvmebus.sc_intr_establish = vmetwo_intr_establish;
7408bde987Sscw 	sc->sc_mvmebus.sc_intr_disestablish = vmetwo_intr_disestablish;
7508bde987Sscw 
7608bde987Sscw 	/* Initialise interrupts */
7708bde987Sscw 	vmetwo_intr_init(sc);
7808bde987Sscw 
7908bde987Sscw 	reg = vme2_lcsr_read(sc, VME2LCSR_BOARD_CONTROL);
8008bde987Sscw 	printf(": Type 2 VMEchip, scon jumper %s\n",
8108bde987Sscw 	    (reg & VME2_BOARD_CONTROL_SCON) ? "enabled" : "disabled");
8208bde987Sscw 
8308bde987Sscw 	/*
8408bde987Sscw 	 * Figure out what bits of the VMEbus we can access.
8508bde987Sscw 	 * First record the `fixed' maps (if they're enabled)
8608bde987Sscw 	 */
8708bde987Sscw 	reg = vme2_lcsr_read(sc, VME2LCSR_IO_CONTROL);
8808bde987Sscw 	if (reg & VME2_IO_CONTROL_I1EN) {
8908bde987Sscw 		/* This range is fixed to A16, DATA */
9008bde987Sscw 		sc->sc_master[0].vr_am = VME_AM_A16 | MVMEBUS_AM_CAP_DATA;
9108bde987Sscw 
9208bde987Sscw 		/* However, SUPER/USER is selectable... */
9308bde987Sscw 		if (reg & VME2_IO_CONTROL_I1SU)
9408bde987Sscw 			sc->sc_master[0].vr_am |= MVMEBUS_AM_CAP_SUPER;
9508bde987Sscw 		else
9608bde987Sscw 			sc->sc_master[0].vr_am |= MVMEBUS_AM_CAP_USER;
9708bde987Sscw 
9808bde987Sscw 		/* As is the datasize */
9907d1f9c9Sscw 		sc->sc_master[0].vr_datasize = VME_D32 | VME_D16;
10008bde987Sscw 		if (reg & VME2_IO_CONTROL_I1D16)
10108bde987Sscw 			sc->sc_master[0].vr_datasize &= ~VME_D32;
10208bde987Sscw 
10308bde987Sscw 		sc->sc_master[0].vr_locstart = VME2_IO0_LOCAL_START;
10408bde987Sscw 		sc->sc_master[0].vr_mask = VME2_IO0_MASK;
10508bde987Sscw 		sc->sc_master[0].vr_vmestart = VME2_IO0_VME_START;
10608bde987Sscw 		sc->sc_master[0].vr_vmeend = VME2_IO0_VME_END;
10708bde987Sscw 	} else
10808bde987Sscw 		sc->sc_master[0].vr_am = MVMEBUS_AM_DISABLED;
10908bde987Sscw 
11008bde987Sscw 	if (reg & VME2_IO_CONTROL_I2EN) {
11108bde987Sscw 		/* These two ranges are fixed to A24D16 and A32D16 */
11208bde987Sscw 		sc->sc_master[1].vr_am = VME_AM_A24;
11307d1f9c9Sscw 		sc->sc_master[1].vr_datasize = VME_D16;
11408bde987Sscw 		sc->sc_master[2].vr_am = VME_AM_A32;
11507d1f9c9Sscw 		sc->sc_master[2].vr_datasize = VME_D16;
11608bde987Sscw 
11708bde987Sscw 		/* However, SUPER/USER is selectable */
11808bde987Sscw 		if (reg & VME2_IO_CONTROL_I2SU) {
11908bde987Sscw 			sc->sc_master[1].vr_am |= MVMEBUS_AM_CAP_SUPER;
12008bde987Sscw 			sc->sc_master[2].vr_am |= MVMEBUS_AM_CAP_SUPER;
12108bde987Sscw 		} else {
12208bde987Sscw 			sc->sc_master[1].vr_am |= MVMEBUS_AM_CAP_USER;
12308bde987Sscw 			sc->sc_master[2].vr_am |= MVMEBUS_AM_CAP_USER;
12408bde987Sscw 		}
12508bde987Sscw 
12608bde987Sscw 		/* As is PROGRAM/DATA */
12708bde987Sscw 		if (reg & VME2_IO_CONTROL_I2PD) {
12808bde987Sscw 			sc->sc_master[1].vr_am |= MVMEBUS_AM_CAP_PROG;
12908bde987Sscw 			sc->sc_master[2].vr_am |= MVMEBUS_AM_CAP_PROG;
13008bde987Sscw 		} else {
13108bde987Sscw 			sc->sc_master[1].vr_am |= MVMEBUS_AM_CAP_DATA;
13208bde987Sscw 			sc->sc_master[2].vr_am |= MVMEBUS_AM_CAP_DATA;
13308bde987Sscw 		}
13408bde987Sscw 
13508bde987Sscw 		sc->sc_master[1].vr_locstart = VME2_IO1_LOCAL_START;
13608bde987Sscw 		sc->sc_master[1].vr_mask = VME2_IO1_MASK;
13708bde987Sscw 		sc->sc_master[1].vr_vmestart = VME2_IO1_VME_START;
13808bde987Sscw 		sc->sc_master[1].vr_vmeend = VME2_IO1_VME_END;
13908bde987Sscw 
14008bde987Sscw 		sc->sc_master[2].vr_locstart = VME2_IO2_LOCAL_START;
14108bde987Sscw 		sc->sc_master[2].vr_mask = VME2_IO2_MASK;
14208bde987Sscw 		sc->sc_master[2].vr_vmestart = VME2_IO2_VME_START;
14308bde987Sscw 		sc->sc_master[2].vr_vmeend = VME2_IO2_VME_END;
14408bde987Sscw 	} else {
14508bde987Sscw 		sc->sc_master[1].vr_am = MVMEBUS_AM_DISABLED;
14608bde987Sscw 		sc->sc_master[2].vr_am = MVMEBUS_AM_DISABLED;
14708bde987Sscw 	}
14808bde987Sscw 
14908bde987Sscw 	/*
150*f18840a4Smsaitoh 	 * Now read the programmable maps
15108bde987Sscw 	 */
15208bde987Sscw 	for (i = 0; i < VME2_MASTER_WINDOWS; i++)
15308bde987Sscw 		vmetwo_master_range(sc, i,
15408bde987Sscw 		    &(sc->sc_master[i + VME2_MASTER_PROG_START]));
15508bde987Sscw 
15608bde987Sscw 	/* XXX: No A16 slave yet :XXX */
15708bde987Sscw 	sc->sc_slave[VME2_SLAVE_A16].vr_am = MVMEBUS_AM_DISABLED;
15808bde987Sscw 
15908bde987Sscw 	for (i = 0; i < VME2_SLAVE_WINDOWS; i++) {
16008bde987Sscw 		vmetwo_slave_range(sc, i, VME_AM_A32,
16108bde987Sscw 		    &sc->sc_slave[i + VME2_SLAVE_PROG_START]);
16208bde987Sscw 		vmetwo_slave_range(sc, i, VME_AM_A24,
16308bde987Sscw 		    &sc->sc_slave[i + VME2_SLAVE_PROG_START + 2]);
16408bde987Sscw 	}
16508bde987Sscw 
16608bde987Sscw 	mvmebus_attach(&sc->sc_mvmebus);
16708bde987Sscw }
16808bde987Sscw 
16908bde987Sscw void
vmetwo_master_range(struct vmetwo_softc * sc,int range,struct mvmebus_range * vr)170454af1c0Sdsl vmetwo_master_range(struct vmetwo_softc *sc, int range, struct mvmebus_range *vr)
17108bde987Sscw {
17208bde987Sscw 	u_int32_t start, end, attr;
17308bde987Sscw 	u_int32_t reg;
17408bde987Sscw 
17508bde987Sscw 	/*
17608bde987Sscw 	 * First, check if the range is actually enabled...
17708bde987Sscw 	 */
17808bde987Sscw 	reg = vme2_lcsr_read(sc, VME2LCSR_MASTER_ENABLE);
17908bde987Sscw 	if ((reg & VME2_MASTER_ENABLE(range)) == 0) {
18008bde987Sscw 		vr->vr_am = MVMEBUS_AM_DISABLED;
18108bde987Sscw 		return;
18208bde987Sscw 	}
18308bde987Sscw 
18408bde987Sscw 	/*
18508bde987Sscw 	 * Fetch and record the range's attributes
18608bde987Sscw 	 */
18708bde987Sscw 	attr = vme2_lcsr_read(sc, VME2LCSR_MASTER_ATTR);
18808bde987Sscw 	attr >>= VME2_MASTER_ATTR_AM_SHIFT(range);
18908bde987Sscw 
19008bde987Sscw 	/*
19108bde987Sscw 	 * Fix up the datasizes available through this range
19208bde987Sscw 	 */
19307d1f9c9Sscw 	vr->vr_datasize = VME_D32 | VME_D16;
19408bde987Sscw 	if (attr & VME2_MASTER_ATTR_D16)
19508bde987Sscw 		vr->vr_datasize &= ~VME_D32;
19608bde987Sscw 	attr &= VME2_MASTER_ATTR_AM_MASK;
19708bde987Sscw 
19808bde987Sscw 	vr->vr_am = (attr & VME_AM_ADRSIZEMASK) | MVMEBUS_AM2CAP(attr);
19908bde987Sscw 	switch (vr->vr_am & VME_AM_ADRSIZEMASK) {
20008bde987Sscw 	case VME_AM_A32:
20108bde987Sscw 	default:
20208bde987Sscw 		vr->vr_mask = 0xffffffffu;
20308bde987Sscw 		break;
20408bde987Sscw 
20508bde987Sscw 	case VME_AM_A24:
20608bde987Sscw 		vr->vr_mask = 0x00ffffffu;
20708bde987Sscw 		break;
20808bde987Sscw 
20908bde987Sscw 	case VME_AM_A16:
21008bde987Sscw 		vr->vr_mask = 0x0000ffffu;
21108bde987Sscw 		break;
21208bde987Sscw 	}
21308bde987Sscw 
21408bde987Sscw 	/*
21508bde987Sscw 	 * XXX
21608bde987Sscw 	 * It would be nice if users of the MI VMEbus code could pass down
21708bde987Sscw 	 * whether they can tolerate Write-Posting to their device(s).
21808bde987Sscw 	 * XXX
21908bde987Sscw 	 */
22008bde987Sscw 
22108bde987Sscw 	/*
22208bde987Sscw 	 * Fetch the local-bus start and end addresses for the range
22308bde987Sscw 	 */
22408bde987Sscw 	reg = vme2_lcsr_read(sc, VME2LCSR_MASTER_ADDRESS(range));
22508bde987Sscw 	start = (reg & VME2_MAST_ADDRESS_START_MASK);
22608bde987Sscw 	start <<= VME2_MAST_ADDRESS_START_SHIFT;
227e6085b4bSscw 	vr->vr_locstart = start & ~vr->vr_mask;
22808bde987Sscw 	end = (reg & VME2_MAST_ADDRESS_END_MASK);
22908bde987Sscw 	end <<= VME2_MAST_ADDRESS_END_SHIFT;
230e6085b4bSscw 	end |= 0xffffu;
231e6085b4bSscw 	end += 1;
23208bde987Sscw 
23308bde987Sscw 	/*
23408bde987Sscw 	 * Local->VMEbus map '4' has optional translation bits, so
23508bde987Sscw 	 * the VMEbus start and end addresses may need to be adjusted.
23608bde987Sscw 	 */
23708bde987Sscw 	if (range == 3 && (reg = vme2_lcsr_read(sc, VME2LCSR_MAST4_TRANS))!=0) {
23808bde987Sscw 		uint32_t addr, sel, len = end - start;
23908bde987Sscw 
24008bde987Sscw 		reg = vme2_lcsr_read(sc, VME2LCSR_MAST4_TRANS);
24108bde987Sscw 		reg &= VME2_MAST4_TRANS_SELECT_MASK;
24208bde987Sscw 		sel = reg << VME2_MAST4_TRANS_SELECT_SHIFT;
24308bde987Sscw 
24408bde987Sscw 		reg = vme2_lcsr_read(sc, VME2LCSR_MAST4_TRANS);
24508bde987Sscw 		reg &= VME2_MAST4_TRANS_ADDRESS_MASK;
24608bde987Sscw 		addr = reg << VME2_MAST4_TRANS_ADDRESS_SHIFT;
24708bde987Sscw 
24808bde987Sscw 		start = (addr & sel) | (start & (~sel));
24908bde987Sscw 		end = start + len;
25008bde987Sscw 		vr->vr_mask &= len - 1;
251e6085b4bSscw 	}
25208bde987Sscw 
25308bde987Sscw 	/* XXX Deal with overlap of onboard RAM address space */
25408bde987Sscw 	/* XXX Then again, 167-Bug warns about this at setup time ... */
25508bde987Sscw 
25608bde987Sscw 	/*
25708bde987Sscw 	 * Fixup the addresses this range corresponds to
25808bde987Sscw 	 */
259e6085b4bSscw 	vr->vr_vmestart = start & vr->vr_mask;
260e6085b4bSscw 	vr->vr_vmeend = (end - 1) & vr->vr_mask;
26108bde987Sscw }
26208bde987Sscw 
26308bde987Sscw void
vmetwo_slave_range(struct vmetwo_softc * sc,int range,vme_am_t am,struct mvmebus_range * vr)264454af1c0Sdsl vmetwo_slave_range(struct vmetwo_softc *sc, int range, vme_am_t am, struct mvmebus_range *vr)
26508bde987Sscw {
26608bde987Sscw 	u_int32_t reg;
26708bde987Sscw 
26808bde987Sscw 	/*
26908bde987Sscw 	 * First, check if the range is actually enabled.
27008bde987Sscw 	 * Note that bit 1 of `range' is used to indicte if we're
27108bde987Sscw 	 * looking for an A24 range (set) or an A32 range (clear).
27208bde987Sscw 	 */
27308bde987Sscw 	reg = vme2_lcsr_read(sc, VME2LCSR_SLAVE_CTRL);
27408bde987Sscw 
27508bde987Sscw 	if (am == VME_AM_A32 && (reg & VME2_SLAVE_AMSEL_A32(range))) {
27608bde987Sscw 		vr->vr_am = VME_AM_A32;
27708bde987Sscw 		vr->vr_mask = 0xffffffffu;
27808bde987Sscw 	} else
27908bde987Sscw 	if (am == VME_AM_A24 && (reg & VME2_SLAVE_AMSEL_A24(range))) {
28008bde987Sscw 		vr->vr_am = VME_AM_A24;
28108bde987Sscw 		vr->vr_mask = 0x00ffffffu;
28208bde987Sscw 	} else {
28308bde987Sscw 		/* The range is not enabled */
28408bde987Sscw 		vr->vr_am = MVMEBUS_AM_DISABLED;
28508bde987Sscw 		return;
28608bde987Sscw 	}
28708bde987Sscw 
28808bde987Sscw 	if ((reg & VME2_SLAVE_AMSEL_DAT(range)) != 0)
28908bde987Sscw 		vr->vr_am |= MVMEBUS_AM_CAP_DATA;
29008bde987Sscw 
29108bde987Sscw 	if ((reg & VME2_SLAVE_AMSEL_PGM(range)) != 0)
29208bde987Sscw 		vr->vr_am |= MVMEBUS_AM_CAP_PROG;
29308bde987Sscw 
29408bde987Sscw 	if ((reg & VME2_SLAVE_AMSEL_USR(range)) != 0)
29508bde987Sscw 		vr->vr_am |= MVMEBUS_AM_CAP_USER;
29608bde987Sscw 
29708bde987Sscw 	if ((reg & VME2_SLAVE_AMSEL_SUP(range)) != 0)
29808bde987Sscw 		vr->vr_am |= MVMEBUS_AM_CAP_SUPER;
29908bde987Sscw 
30008bde987Sscw 	if ((reg & VME2_SLAVE_AMSEL_BLK(range)) != 0)
30108bde987Sscw 		vr->vr_am |= MVMEBUS_AM_CAP_BLK;
30208bde987Sscw 
30308bde987Sscw 	if ((reg & VME2_SLAVE_AMSEL_BLKD64(range)) != 0)
30408bde987Sscw 		vr->vr_am |= MVMEBUS_AM_CAP_BLKD64;
30508bde987Sscw 
30608bde987Sscw 	vr->vr_datasize = VME_D32 | VME_D16 | VME_D8;
30708bde987Sscw 
30808bde987Sscw 	/*
30908bde987Sscw 	 * Record the VMEbus start and end addresses of the slave image
31008bde987Sscw 	 */
31108bde987Sscw 	reg = vme2_lcsr_read(sc, VME2LCSR_SLAVE_ADDRESS(range));
31208bde987Sscw 	vr->vr_vmestart = reg & VME2_SLAVE_ADDRESS_START_MASK;
31308bde987Sscw 	vr->vr_vmestart <<= VME2_SLAVE_ADDRESS_START_SHIFT;
31408bde987Sscw 	vr->vr_vmestart &= vr->vr_mask;
31508bde987Sscw 	vr->vr_vmeend = reg & VME2_SLAVE_ADDRESS_END_MASK;
31608bde987Sscw 	vr->vr_vmeend <<= VME2_SLAVE_ADDRESS_END_SHIFT;
31708bde987Sscw 	vr->vr_vmeend &= vr->vr_mask;
31808bde987Sscw 	vr->vr_vmeend |= 0xffffu;
31908bde987Sscw 
32008bde987Sscw 	/*
32108bde987Sscw 	 * Now figure out the local-bus address
32208bde987Sscw 	 */
32308bde987Sscw 	reg = vme2_lcsr_read(sc, VME2LCSR_SLAVE_CTRL);
32408bde987Sscw 	if ((reg & VME2_SLAVE_CTRL_ADDER(range)) != 0) {
32508bde987Sscw 		reg = vme2_lcsr_read(sc, VME2LCSR_SLAVE_TRANS(range));
32608bde987Sscw 		reg &= VME2_SLAVE_TRANS_ADDRESS_MASK;
32708bde987Sscw 		reg <<= VME2_SLAVE_TRANS_ADDRESS_SHIFT;
32808bde987Sscw 		vr->vr_locstart = vr->vr_vmestart + reg;
32908bde987Sscw 	} else {
33008bde987Sscw 		u_int32_t sel, addr;
33108bde987Sscw 
33208bde987Sscw 		reg = vme2_lcsr_read(sc, VME2LCSR_SLAVE_TRANS(range));
33308bde987Sscw 		sel = reg & VME2_SLAVE_TRANS_SELECT_MASK;
33408bde987Sscw 		sel <<= VME2_SLAVE_TRANS_SELECT_SHIFT;
33508bde987Sscw 		addr = reg & VME2_SLAVE_TRANS_ADDRESS_MASK;
33608bde987Sscw 		addr <<= VME2_SLAVE_TRANS_ADDRESS_SHIFT;
33708bde987Sscw 
33808bde987Sscw 		vr->vr_locstart = addr & sel;
33908bde987Sscw 		vr->vr_locstart |= vr->vr_vmestart & (~sel);
34008bde987Sscw 	}
34108bde987Sscw }
342