Beginnings of support for the Simtec Hydra multiprocessor board.
So far, the Hydra is detected and initialised, and each slave CPU is spun up briefly to check that it works.
This commit is contained in:
parent
239b192ca3
commit
b59e2e1320
234
sys/arch/acorn32/acorn32/hydra.c
Normal file
234
sys/arch/acorn32/acorn32/hydra.c
Normal file
@ -0,0 +1,234 @@
|
||||
/* $NetBSD: hydra.c,v 1.1 2002/09/30 23:22:05 bjh21 Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2002 Ben Harris
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
__KERNEL_RCSID(0, "$NetBSD: hydra.c,v 1.1 2002/09/30 23:22:05 bjh21 Exp $");
|
||||
|
||||
#include <sys/device.h>
|
||||
#include <sys/systm.h>
|
||||
|
||||
#include <uvm/uvm_extern.h>
|
||||
#include <uvm/uvm_pglist.h>
|
||||
|
||||
#include <arch/arm/mainbus/mainbus.h>
|
||||
#include <arch/acorn32/acorn32/hydrareg.h>
|
||||
|
||||
#include "locators.h"
|
||||
|
||||
struct hydra_softc {
|
||||
struct device sc_dev;
|
||||
bus_space_tag_t sc_iot;
|
||||
bus_space_handle_t sc_ioh;
|
||||
paddr_t sc_bootpage_pa;
|
||||
vaddr_t sc_bootpage_va;
|
||||
};
|
||||
|
||||
struct hydra_attach_args {
|
||||
int ha_slave;
|
||||
};
|
||||
|
||||
static int hydra_match(struct device *, struct cfdata *, void *);
|
||||
static void hydra_attach(struct device *, struct device *, void *);
|
||||
static int hydra_probe_slave(struct hydra_softc *, int);
|
||||
static int hydra_print(void *, char const *);
|
||||
static int hydra_submatch(struct device *, struct cfdata *, void *);
|
||||
|
||||
struct cfattach hydra_ca = {
|
||||
sizeof(struct hydra_softc), hydra_match, hydra_attach
|
||||
};
|
||||
|
||||
extern char const hydra_bootcode[], hydra_ebootcode[];
|
||||
|
||||
static int
|
||||
hydra_match(struct device *parent, struct cfdata *cf, void *aux)
|
||||
{
|
||||
struct mainbus_attach_args *mba = aux;
|
||||
bus_space_tag_t iot;
|
||||
bus_space_handle_t ioh;
|
||||
|
||||
/*
|
||||
* Probing for the Hydra is slightly tricky, since if there's
|
||||
* no Hydra, the data we read seem fairly random. Happily,
|
||||
* nothing else uses its addresses, so we can be as invasive
|
||||
* as we like.
|
||||
*/
|
||||
|
||||
iot = mba->mb_iot;
|
||||
if (bus_space_map(iot, HYDRA_PHYS_BASE, HYDRA_PHYS_SIZE, 0, &ioh) != 0)
|
||||
return 0;
|
||||
|
||||
/* Make sure all slaves are halted. */
|
||||
bus_space_write_1(iot, ioh, HYDRA_HALT_SET, 0xf);
|
||||
/* Check that we appear to be the master. */
|
||||
if (bus_space_read_1(iot, ioh, HYDRA_ID_STATUS) & HYDRA_ID_ISSLAVE)
|
||||
goto fail;
|
||||
/* Check that the MMU enable bits behave as expected. */
|
||||
bus_space_write_1(iot, ioh, HYDRA_MMU_CLR, 0xf);
|
||||
if (bus_space_read_1(iot, ioh, HYDRA_MMU_STATUS) != 0x0)
|
||||
goto fail;
|
||||
bus_space_write_1(iot, ioh, HYDRA_MMU_SET, 0x5);
|
||||
if (bus_space_read_1(iot, ioh, HYDRA_MMU_STATUS) != 0x5)
|
||||
goto fail;
|
||||
bus_space_write_1(iot, ioh, HYDRA_MMU_SET, 0xa);
|
||||
if (bus_space_read_1(iot, ioh, HYDRA_MMU_STATUS) != 0xf)
|
||||
goto fail;
|
||||
bus_space_write_1(iot, ioh, HYDRA_MMU_CLR, 0x5);
|
||||
if (bus_space_read_1(iot, ioh, HYDRA_MMU_STATUS) != 0xa)
|
||||
goto fail;
|
||||
bus_space_write_1(iot, ioh, HYDRA_MMU_CLR, 0xa);
|
||||
if (bus_space_read_1(iot, ioh, HYDRA_MMU_STATUS) != 0x0)
|
||||
goto fail;
|
||||
bus_space_unmap(iot, ioh, HYDRA_PHYS_SIZE);
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
bus_space_unmap(iot, ioh, HYDRA_PHYS_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
hydra_attach(struct device *parent, struct device *self, void *aux)
|
||||
{
|
||||
struct hydra_softc *sc = (void *)self;
|
||||
struct mainbus_attach_args *mba = aux;
|
||||
int i;
|
||||
struct hydra_attach_args ha;
|
||||
struct pglist bootpglist;
|
||||
bus_space_tag_t iot;
|
||||
bus_space_handle_t ioh;
|
||||
|
||||
sc->sc_iot = mba->mb_iot;
|
||||
if (bus_space_map(sc->sc_iot, HYDRA_PHYS_BASE, HYDRA_PHYS_SIZE, 0,
|
||||
&sc->sc_ioh) != 0) {
|
||||
printf(": cannot map\n");
|
||||
return;
|
||||
}
|
||||
iot = sc->sc_iot;
|
||||
ioh = sc->sc_ioh;
|
||||
|
||||
/*
|
||||
* The Hydra has special hardware to allow a slave processor
|
||||
* to see something other than ROM at physical address 0 when
|
||||
* it starts. This something has to have a physical address
|
||||
* on a 2MB boundary.
|
||||
*/
|
||||
TAILQ_INIT(&bootpglist);
|
||||
if (uvm_pglistalloc(PAGE_SIZE, 0x00000000, 0x1fffffff, 0x00200000, 0,
|
||||
&bootpglist, 1, 1) != 0) {
|
||||
printf(": Can't allocate bootstrap memory.\n");
|
||||
return;
|
||||
}
|
||||
KASSERT(!TAILQ_EMPTY(&bootpglist));
|
||||
sc->sc_bootpage_pa = TAILQ_FIRST(&bootpglist)->phys_addr;
|
||||
sc->sc_bootpage_va = uvm_km_valloc(kernel_map, PAGE_SIZE);
|
||||
if (sc->sc_bootpage_va == 0) {
|
||||
uvm_pglistfree(&bootpglist);
|
||||
printf(": Can't allocate bootstrap memory.\n");
|
||||
return;
|
||||
}
|
||||
pmap_enter(pmap_kernel(), sc->sc_bootpage_va, sc->sc_bootpage_pa,
|
||||
VM_PROT_READ | VM_PROT_WRITE,
|
||||
VM_PROT_READ | VM_PROT_WRITE | PMAP_WIRED);
|
||||
pmap_update(pmap_kernel());
|
||||
|
||||
/* Halt all slaves */
|
||||
bus_space_write_1(iot, ioh, HYDRA_HALT_SET, 0xf);
|
||||
bus_space_write_1(iot, ioh, HYDRA_RESET, 0x0);
|
||||
/* Clear IPFIQs to master */
|
||||
bus_space_write_1(iot, ioh, HYDRA_FIQ_CLR, 0xf);
|
||||
/* ... and to all slaves */
|
||||
bus_space_write_1(iot, ioh, HYDRA_FORCEFIQ_CLR, 0xf);
|
||||
/* Ditto IPIRQs */
|
||||
bus_space_write_1(iot, ioh, HYDRA_IRQ_CLR, 0xf);
|
||||
bus_space_write_1(iot, ioh, HYDRA_FORCEIRQ_CLR, 0xf);
|
||||
/* Initialise MMU */
|
||||
bus_space_write_1(iot, ioh, HYDRA_MMU_LSN, sc->sc_bootpage_pa >> 21);
|
||||
bus_space_write_1(iot, ioh, HYDRA_MMU_MSN, sc->sc_bootpage_pa >> 25);
|
||||
bus_space_write_1(iot, ioh, HYDRA_MMU_CLR, 0xf);
|
||||
|
||||
printf("\n");
|
||||
|
||||
for (i = 0; i < HYDRA_NSLAVES; i++) {
|
||||
if (hydra_probe_slave(sc, i)) {
|
||||
ha.ha_slave = i;
|
||||
config_found_sm(self, &ha, hydra_print,
|
||||
hydra_submatch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
hydra_probe_slave(struct hydra_softc *sc, int slave)
|
||||
{
|
||||
bus_space_tag_t iot = sc->sc_iot;
|
||||
bus_space_handle_t ioh = sc->sc_ioh;
|
||||
int i, ret;
|
||||
|
||||
memcpy((caddr_t)sc->sc_bootpage_va, hydra_bootcode,
|
||||
hydra_ebootcode - hydra_bootcode);
|
||||
bus_space_write_1(iot, ioh, HYDRA_MMU_SET, 1 << slave);
|
||||
bus_space_write_1(iot, ioh, HYDRA_HALT_SET, 1 << slave);
|
||||
bus_space_write_1(iot, ioh, HYDRA_RESET, 1 << slave);
|
||||
bus_space_write_1(iot, ioh, HYDRA_HALT_CLR, 1 << slave);
|
||||
bus_space_write_1(iot, ioh, HYDRA_RESET, 0);
|
||||
ret = 0;
|
||||
for (i = 0; i < 1000; i++) {
|
||||
if ((bus_space_read_1(iot, ioh, HYDRA_HALT_STATUS) &
|
||||
(1 << slave)) != 0) {
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
bus_space_write_1(iot, ioh, HYDRA_HALT_SET, 1 << slave);
|
||||
bus_space_write_1(iot, ioh, HYDRA_MMU_CLR, 1 << slave);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
hydra_print(void *aux, char const *pnp)
|
||||
{
|
||||
struct hydra_attach_args *ha = aux;
|
||||
|
||||
if (pnp)
|
||||
printf("cpu at %s", pnp);
|
||||
printf(" slave %d", ha->ha_slave);
|
||||
return UNCONF;
|
||||
}
|
||||
|
||||
static int
|
||||
hydra_submatch(struct device *parent, struct cfdata *cf, void *aux)
|
||||
{
|
||||
struct hydra_attach_args *ha = aux;
|
||||
|
||||
if (cf->cf_loc[HYDRACF_SLAVE] == HYDRACF_SLAVE_DEFAULT ||
|
||||
cf->cf_loc[HYDRACF_SLAVE] == ha->ha_slave)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
66
sys/arch/acorn32/acorn32/hydra_boot.S
Normal file
66
sys/arch/acorn32/acorn32/hydra_boot.S
Normal file
@ -0,0 +1,66 @@
|
||||
/* $NetBSD: hydra_boot.S,v 1.1 2002/09/30 23:22:05 bjh21 Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2002 Ben Harris
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* hydra_boot.S - Code to run on a Hydra slave CPU when it comes out of reset.
|
||||
*/
|
||||
|
||||
#include <machine/asm.h>
|
||||
#include <arch/acorn32/acorn32/hydrareg.h>
|
||||
|
||||
RCSID("$NetBSD: hydra_boot.S,v 1.1 2002/09/30 23:22:05 bjh21 Exp $")
|
||||
|
||||
ENTRY_NP(hydra_bootcode)
|
||||
/*
|
||||
* This code is mapped in at physical address zero when a CPU
|
||||
* hatches, so it forms the vector table until the Hydra MMU
|
||||
* is turned off and the CPU MMU is turned on. Any exception
|
||||
* apart from a reset just puts us in a tight loop.
|
||||
*/
|
||||
b Lhydra_reset /* Reset */
|
||||
b . /* Undefined instruction */
|
||||
b . /* SWI */
|
||||
b . /* Prefetch abort */
|
||||
b . /* Data abort */
|
||||
b . /* Address exception */
|
||||
b . /* IRQ */
|
||||
b . /* FIQ */
|
||||
|
||||
Lhydra_reset:
|
||||
mov r0, #HYDRA_PHYS_BASE
|
||||
ldr r1, [r0, #(HYDRA_ID_STATUS << 2)]
|
||||
and r1, r1, #3 /* Mask off slave ID */
|
||||
mov r2, #1
|
||||
mov r2, r2, lsl r1 /* Get the bit for this CPU */
|
||||
str r2, [r0, #(HYDRA_HALT_SET << 2)] /* Halt ourselves */
|
||||
b . /* Get here if we're released */
|
||||
|
||||
.align 0
|
||||
.global _C_LABEL(hydra_ebootcode)
|
||||
_C_LABEL(hydra_ebootcode):
|
44
sys/arch/acorn32/acorn32/hydrareg.h
Normal file
44
sys/arch/acorn32/acorn32/hydrareg.h
Normal file
@ -0,0 +1,44 @@
|
||||
/* $NetBSD: hydrareg.h,v 1.1 2002/09/30 23:22:05 bjh21 Exp $ */
|
||||
|
||||
/*
|
||||
* This file is in the Public Domain
|
||||
*/
|
||||
|
||||
/* Simtec Hydra register definitions */
|
||||
|
||||
#define HYDRA_PHYS_BASE 0x03800000
|
||||
#define HYDRA_PHYS_SIZE 0x40
|
||||
|
||||
/* Registers are 4 bits wide at 1-word intervals. */
|
||||
|
||||
/* Write-only registers */
|
||||
#define HYDRA_FIQ_SET 0
|
||||
#define HYDRA_FIQ_CLR 1
|
||||
#define HYDRA_FORCEFIQ_CLR 2
|
||||
#define HYDRA_MMU_LSN 4
|
||||
#define HYDRA_MMU_MSN 5
|
||||
#define HYDRA_MMU_SET 6
|
||||
#define HYDRA_MMU_CLR 7
|
||||
#define HYDRA_IRQ_SET 8
|
||||
#define HYDRA_IRQ_CLR 9
|
||||
#define HYDRA_FORCEIRQ_CLR 10
|
||||
#define HYDRA_RESET 12
|
||||
#define HYDRA_X86_KILLER 13
|
||||
#define HYDRA_HALT_SET 14
|
||||
#define HYDRA_HALT_CLR 15
|
||||
|
||||
/* Read-only registers */
|
||||
#define HYDRA_FIQ_STATUS 0
|
||||
#define HYDRA_FIQ_READBACK 1
|
||||
#define HYDRA_HARDWAREVER 2
|
||||
#define HYDRA_MMU_STATUS 6
|
||||
#define HYDRA_ID_STATUS 7 /* XXX doc says &1D, not &1C */
|
||||
#define HYDRA_IRQ_STATUS 8
|
||||
#define HYDRA_IRQ_READBACK 9
|
||||
#define HYDRA_RST_STATUS 12
|
||||
#define HYDRA_HALT_STATUS 14
|
||||
|
||||
#define HYDRA_NSLAVES 4
|
||||
|
||||
#define HYDRA_ID_ISSLAVE 0x4
|
||||
#define HYDRA_ID_SLAVE_MASK 0x3
|
@ -1,4 +1,4 @@
|
||||
# $NetBSD: files.acorn32,v 1.14 2002/09/06 13:18:43 gehenna Exp $
|
||||
# $NetBSD: files.acorn32,v 1.15 2002/09/30 23:22:06 bjh21 Exp $
|
||||
#
|
||||
# First try for arm-specific configuration info
|
||||
#
|
||||
@ -18,6 +18,11 @@ defflag FOOTBRIDGE
|
||||
define isadma
|
||||
file dev/isa/isadma.c isadma needs-flag
|
||||
|
||||
# Simtec Hydra multiprocessor system
|
||||
device hydra { slave = -1 }
|
||||
attach hydra at mainbus
|
||||
file arch/acorn32/acorn32/hydra.c hydra needs-flag
|
||||
file arch/acorn32/acorn32/hydra_boot.S hydra needs-flag
|
||||
|
||||
#
|
||||
# Machine-independent ATA drivers
|
||||
|
Loading…
Reference in New Issue
Block a user