wii: Add External interface bus and RTC support
This commit is contained in:
parent
b0fb99a891
commit
c0f93ec191
|
@ -1,4 +1,4 @@
|
|||
# $NetBSD: WII,v 1.3 2024/01/23 21:48:12 jmcneill Exp $
|
||||
# $NetBSD: WII,v 1.4 2024/01/25 11:47:53 jmcneill Exp $
|
||||
#
|
||||
# Nintendo Wii
|
||||
#
|
||||
|
@ -128,6 +128,8 @@ options WSDISPLAY_DEFAULTSCREENS=4
|
|||
options WSDISPLAY_SCROLLSUPPORT
|
||||
|
||||
hollywood0 at mainbus0 irq 14
|
||||
exi0 at mainbus0 addr 0x0d006800 irq 4 # External interface
|
||||
rtcsram0 at exi0 # RTC/SRAM chip
|
||||
bwai0 at mainbus0 addr 0x0d006c00 irq 5 # Audio interface
|
||||
bwdsp0 at mainbus0 addr 0x0c005000 irq 6 # DSP
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# $NetBSD: files.wii,v 1.3 2024/01/23 21:48:12 jmcneill Exp $
|
||||
# $NetBSD: files.wii,v 1.4 2024/01/25 11:47:53 jmcneill Exp $
|
||||
#
|
||||
#
|
||||
maxpartitions 16
|
||||
|
@ -47,6 +47,15 @@ device bwdsp: audiobus
|
|||
attach bwdsp at mainbus
|
||||
file arch/evbppc/wii/dev/bwdsp.c bwdsp
|
||||
|
||||
define exi { }
|
||||
device exi: exi
|
||||
attach exi at mainbus
|
||||
file arch/evbppc/wii/dev/exi.c exi
|
||||
|
||||
device rtcsram
|
||||
attach rtcsram at exi
|
||||
file arch/evbppc/wii/dev/rtcsram.c rtcsram
|
||||
|
||||
define hollywood { [addr=-1], [irq=-1] }
|
||||
device hollywood: hollywood
|
||||
attach hollywood at mainbus
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: wii.h,v 1.6 2024/01/24 21:53:34 jmcneill Exp $ */
|
||||
/* $NetBSD: wii.h,v 1.7 2024/01/25 11:47:53 jmcneill Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2024 Jared McNeill <jmcneill@invisible.ca>
|
||||
|
@ -57,6 +57,9 @@
|
|||
#define DSP_BASE 0x0c005000
|
||||
#define DSP_SIZE 0x00000200
|
||||
|
||||
#define EXI_BASE 0x0d006800
|
||||
#define EXI_SIZE 0x00000080
|
||||
|
||||
#define AI_BASE 0x0d006c00
|
||||
#define AI_SIZE 0x00000020
|
||||
|
||||
|
@ -96,6 +99,7 @@
|
|||
#define PI_INTMR (PI_BASE + 0x04)
|
||||
|
||||
/* Processor IRQs */
|
||||
#define PI_IRQ_EXI 4
|
||||
#define PI_IRQ_AI 5
|
||||
#define PI_IRQ_DSP 6
|
||||
#define PI_IRQ_HOLLYWOOD 14
|
||||
|
|
|
@ -0,0 +1,348 @@
|
|||
/* $NetBSD: exi.c,v 1.1 2024/01/25 11:47:53 jmcneill Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2024 Jared McNeill <jmcneill@invisible.ca>
|
||||
* 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.
|
||||
*
|
||||
* 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/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: exi.c,v 1.1 2024/01/25 11:47:53 jmcneill Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/device.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bitops.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <uvm/uvm_extern.h>
|
||||
|
||||
#include <machine/wii.h>
|
||||
#include <machine/pio.h>
|
||||
|
||||
#include "locators.h"
|
||||
#include "mainbus.h"
|
||||
#include "exi.h"
|
||||
|
||||
#define EXI_NUM_CHAN 3
|
||||
#define EXI_NUM_DEV 3
|
||||
|
||||
/* This is an arbitrary limit. The real limit is probably much higher. */
|
||||
#define EXI_MAX_DMA 4096
|
||||
|
||||
#define EXI_CSR(n) (0x00 + (n) * 0x14)
|
||||
#define EXI_CSR_CS __BITS(9,7)
|
||||
#define EXI_MAR(n) (0x04 + (n) * 0x14)
|
||||
#define EXI_LENGTH(n) (0x08 + (n) * 0x14)
|
||||
#define EXI_CR(n) (0x0c + (n) * 0x14)
|
||||
#define EXI_CR_TLEN __BITS(5,4)
|
||||
#define EXI_CR_RW __BITS(3,2)
|
||||
#define EXI_CR_RW_READ __SHIFTIN(0, EXI_CR_RW)
|
||||
#define EXI_CR_RW_WRITE __SHIFTIN(1, EXI_CR_RW)
|
||||
#define EXI_CR_DMA __BIT(1)
|
||||
#define EXI_CR_TSTART __BIT(0)
|
||||
#define EXI_DATA(n) (0x10 + (n) * 0x14)
|
||||
|
||||
#define ASSERT_CHAN_VALID(chan) KASSERT((chan) >= 0 && (chan) < EXI_NUM_CHAN)
|
||||
#define ASSERT_DEV_VALID(dev) KASSERT((dev) >= 0 && (dev) < EXI_NUM_DEV)
|
||||
#define ASSERT_LEN_VALID(len) KASSERT((len) == 1 || (len) == 2 || (len) == 4)
|
||||
|
||||
struct exi_channel {
|
||||
kmutex_t ch_lock;
|
||||
|
||||
bus_dmamap_t ch_dmamap;
|
||||
|
||||
device_t ch_child[EXI_NUM_DEV];
|
||||
};
|
||||
|
||||
struct exi_softc {
|
||||
device_t sc_dev;
|
||||
bus_space_tag_t sc_bst;
|
||||
bus_space_handle_t sc_bsh;
|
||||
bus_dma_tag_t sc_dmat;
|
||||
|
||||
struct exi_channel sc_chan[EXI_NUM_CHAN];
|
||||
};
|
||||
|
||||
static struct exi_softc *exi_softc;
|
||||
|
||||
#define RD4(sc, reg) \
|
||||
bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
|
||||
#define WR4(sc, reg, val) \
|
||||
bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
|
||||
|
||||
static int exi_match(device_t, cfdata_t, void *);
|
||||
static void exi_attach(device_t, device_t, void *);
|
||||
|
||||
static int exi_rescan(device_t, const char *, const int *);
|
||||
static int exi_print(void *, const char *);
|
||||
|
||||
CFATTACH_DECL_NEW(exi, sizeof(struct exi_softc),
|
||||
exi_match, exi_attach, NULL, NULL);
|
||||
|
||||
static int
|
||||
exi_match(device_t parent, cfdata_t cf, void *aux)
|
||||
{
|
||||
struct mainbus_attach_args *maa = aux;
|
||||
|
||||
return strcmp(maa->maa_name, "exi") == 0;
|
||||
}
|
||||
|
||||
static void
|
||||
exi_attach(device_t parent, device_t self, void *aux)
|
||||
{
|
||||
struct mainbus_attach_args * const maa = aux;
|
||||
struct exi_softc * const sc = device_private(self);
|
||||
uint8_t chan;
|
||||
int error;
|
||||
|
||||
KASSERT(device_unit(self) == 0);
|
||||
|
||||
aprint_naive("\n");
|
||||
aprint_normal(": External Interface\n");
|
||||
|
||||
exi_softc = sc;
|
||||
sc->sc_dev = self;
|
||||
sc->sc_bst = maa->maa_bst;
|
||||
if (bus_space_map(sc->sc_bst, maa->maa_addr, EXI_SIZE, 0,
|
||||
&sc->sc_bsh) != 0) {
|
||||
aprint_error_dev(self, "couldn't map registers\n");
|
||||
return;
|
||||
}
|
||||
sc->sc_dmat = maa->maa_dmat;
|
||||
for (chan = 0; chan < EXI_NUM_CHAN; chan++) {
|
||||
mutex_init(&sc->sc_chan[chan].ch_lock, MUTEX_DEFAULT, IPL_VM);
|
||||
error = bus_dmamap_create(exi_softc->sc_dmat, EXI_MAX_DMA, 1,
|
||||
EXI_MAX_DMA, 0, BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW,
|
||||
&sc->sc_chan[chan].ch_dmamap);
|
||||
if (error != 0) {
|
||||
aprint_error_dev(self, "couldn't create dmamap: %d\n",
|
||||
error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
exi_rescan(self, NULL, NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
exi_rescan(device_t self, const char *ifattr, const int *locs)
|
||||
{
|
||||
struct exi_softc * const sc = device_private(self);
|
||||
uint8_t chan, dev;
|
||||
|
||||
for (chan = 0; chan < EXI_NUM_CHAN; chan++) {
|
||||
struct exi_channel *ch = &sc->sc_chan[chan];
|
||||
for (dev = 0; dev < EXI_NUM_DEV; dev++) {
|
||||
struct exi_attach_args eaa = {};
|
||||
uint16_t command = 0x0000; /* ID command */
|
||||
uint32_t id = 0;
|
||||
|
||||
if (ch->ch_child[dev] != NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
exi_select(chan, dev);
|
||||
exi_send_imm(chan, dev, &command, sizeof(command));
|
||||
exi_recv_imm(chan, dev, &id, sizeof(id));
|
||||
exi_unselect(chan);
|
||||
|
||||
if (id == 0 || id == 0xffffffff) {
|
||||
continue;
|
||||
}
|
||||
|
||||
eaa.eaa_id = id;
|
||||
eaa.eaa_chan = chan;
|
||||
eaa.eaa_device = dev;
|
||||
|
||||
ch->ch_child[dev] = config_found(self, &eaa, exi_print,
|
||||
CFARGS(.submatch = config_stdsubmatch,
|
||||
.locators = locs));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
exi_print(void *aux, const char *pnp)
|
||||
{
|
||||
struct exi_attach_args *eaa = aux;
|
||||
|
||||
if (pnp != NULL) {
|
||||
aprint_normal("EXI device 0x%08x at %s", eaa->eaa_id, pnp);
|
||||
}
|
||||
|
||||
aprint_normal(" addr %u-%u", eaa->eaa_chan, eaa->eaa_device);
|
||||
|
||||
return UNCONF;
|
||||
}
|
||||
|
||||
void
|
||||
exi_select(uint8_t chan, uint8_t dev)
|
||||
{
|
||||
struct exi_channel *ch;
|
||||
uint32_t val;
|
||||
|
||||
ASSERT_CHAN_VALID(chan);
|
||||
ASSERT_DEV_VALID(dev);
|
||||
|
||||
ch = &exi_softc->sc_chan[chan];
|
||||
mutex_enter(&ch->ch_lock);
|
||||
|
||||
val = RD4(exi_softc, EXI_CSR(chan));
|
||||
val &= ~EXI_CSR_CS;
|
||||
val |= __SHIFTIN(__BIT(dev), EXI_CSR_CS);
|
||||
WR4(exi_softc, EXI_CSR(chan), val);
|
||||
}
|
||||
|
||||
void
|
||||
exi_unselect(uint8_t chan)
|
||||
{
|
||||
struct exi_channel *ch;
|
||||
uint32_t val;
|
||||
|
||||
ASSERT_CHAN_VALID(chan);
|
||||
|
||||
ch = &exi_softc->sc_chan[chan];
|
||||
|
||||
val = RD4(exi_softc, EXI_CSR(chan));
|
||||
val &= ~EXI_CSR_CS;
|
||||
WR4(exi_softc, EXI_CSR(chan), val);
|
||||
|
||||
mutex_exit(&ch->ch_lock);
|
||||
}
|
||||
|
||||
static void
|
||||
exi_wait(uint8_t chan)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
ASSERT_CHAN_VALID(chan);
|
||||
|
||||
do {
|
||||
val = RD4(exi_softc, EXI_CR(chan));
|
||||
} while ((val & EXI_CR_TSTART) != 0);
|
||||
}
|
||||
|
||||
void
|
||||
exi_send_imm(uint8_t chan, uint8_t dev, const void *data, size_t datalen)
|
||||
{
|
||||
struct exi_channel *ch;
|
||||
uint32_t val = 0;
|
||||
|
||||
ASSERT_CHAN_VALID(chan);
|
||||
ASSERT_DEV_VALID(dev);
|
||||
ASSERT_LEN_VALID(datalen);
|
||||
|
||||
ch = &exi_softc->sc_chan[chan];
|
||||
KASSERT(mutex_owned(&ch->ch_lock));
|
||||
|
||||
switch (datalen) {
|
||||
case 1:
|
||||
val = *(const uint8_t *)data << 24;
|
||||
break;
|
||||
case 2:
|
||||
val = *(const uint16_t *)data << 16;
|
||||
break;
|
||||
case 4:
|
||||
val = *(const uint32_t *)data;
|
||||
break;
|
||||
}
|
||||
|
||||
WR4(exi_softc, EXI_DATA(chan), val);
|
||||
WR4(exi_softc, EXI_CR(chan),
|
||||
EXI_CR_TSTART | EXI_CR_RW_WRITE |
|
||||
__SHIFTIN(datalen - 1, EXI_CR_TLEN));
|
||||
exi_wait(chan);
|
||||
}
|
||||
|
||||
void
|
||||
exi_recv_imm(uint8_t chan, uint8_t dev, void *data, size_t datalen)
|
||||
{
|
||||
struct exi_channel *ch;
|
||||
uint32_t val;
|
||||
|
||||
ASSERT_CHAN_VALID(chan);
|
||||
ASSERT_DEV_VALID(dev);
|
||||
ASSERT_LEN_VALID(datalen);
|
||||
|
||||
ch = &exi_softc->sc_chan[chan];
|
||||
KASSERT(mutex_owned(&ch->ch_lock));
|
||||
|
||||
WR4(exi_softc, EXI_CR(chan),
|
||||
EXI_CR_TSTART | EXI_CR_RW_READ |
|
||||
__SHIFTIN(datalen - 1, EXI_CR_TLEN));
|
||||
exi_wait(chan);
|
||||
val = RD4(exi_softc, EXI_DATA(chan));
|
||||
|
||||
switch (datalen) {
|
||||
case 1:
|
||||
*(uint8_t *)data = val >> 24;
|
||||
break;
|
||||
case 2:
|
||||
*(uint16_t *)data = val >> 16;
|
||||
break;
|
||||
case 4:
|
||||
*(uint32_t *)data = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
exi_recv_dma(uint8_t chan, uint8_t dev, void *data, size_t datalen)
|
||||
{
|
||||
struct exi_channel *ch;
|
||||
int error;
|
||||
|
||||
ASSERT_CHAN_VALID(chan);
|
||||
ASSERT_DEV_VALID(dev);
|
||||
KASSERT((datalen & 0x1f) == 0);
|
||||
|
||||
ch = &exi_softc->sc_chan[chan];
|
||||
KASSERT(mutex_owned(&ch->ch_lock));
|
||||
|
||||
error = bus_dmamap_load(exi_softc->sc_dmat, ch->ch_dmamap,
|
||||
data, datalen, NULL, BUS_DMA_WAITOK);
|
||||
if (error != 0) {
|
||||
device_printf(exi_softc->sc_dev, "can't load DMA handle: %d\n",
|
||||
error);
|
||||
return;
|
||||
}
|
||||
|
||||
KASSERT((ch->ch_dmamap->dm_segs[0].ds_addr & 0x1f) == 0);
|
||||
|
||||
bus_dmamap_sync(exi_softc->sc_dmat, ch->ch_dmamap, 0, datalen,
|
||||
BUS_DMASYNC_PREREAD);
|
||||
|
||||
WR4(exi_softc, EXI_MAR(chan), ch->ch_dmamap->dm_segs[0].ds_addr);
|
||||
WR4(exi_softc, EXI_LENGTH(chan), datalen);
|
||||
WR4(exi_softc, EXI_CR(chan),
|
||||
EXI_CR_TSTART | EXI_CR_RW_READ | EXI_CR_DMA);
|
||||
exi_wait(chan);
|
||||
|
||||
bus_dmamap_sync(exi_softc->sc_dmat, ch->ch_dmamap, 0, datalen,
|
||||
BUS_DMASYNC_POSTREAD);
|
||||
|
||||
bus_dmamap_unload(exi_softc->sc_dmat, ch->ch_dmamap);
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/* $NetBSD: exi.h,v 1.1 2024/01/25 11:47:53 jmcneill Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2024 Jared McNeill <jmcneill@invisible.ca>
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _WII_DEV_EXI_H_
|
||||
#define _WII_DEV_EXI_H_
|
||||
|
||||
struct exi_attach_args {
|
||||
uint32_t eaa_id;
|
||||
uint8_t eaa_chan;
|
||||
uint8_t eaa_device;
|
||||
};
|
||||
|
||||
void exi_select(uint8_t, uint8_t);
|
||||
void exi_unselect(uint8_t);
|
||||
void exi_send_imm(uint8_t, uint8_t, const void *, size_t);
|
||||
void exi_recv_imm(uint8_t, uint8_t, void *, size_t);
|
||||
void exi_recv_dma(uint8_t, uint8_t, void *, size_t);
|
||||
|
||||
#endif /* _WII_DEV_EXI_H_ */
|
|
@ -0,0 +1,177 @@
|
|||
/* $NetBSD: rtcsram.c,v 1.1 2024/01/25 11:47:53 jmcneill Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2024 Jared McNeill <jmcneill@invisible.ca>
|
||||
* 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.
|
||||
*
|
||||
* 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/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: rtcsram.c,v 1.1 2024/01/25 11:47:53 jmcneill Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/device.h>
|
||||
#include <sys/systm.h>
|
||||
#include <dev/clock_subr.h>
|
||||
|
||||
#include <lib/libkern/libkern.h>
|
||||
|
||||
#include "exi.h"
|
||||
|
||||
#define WII_RTCSRAM_ID 0xfffff308
|
||||
|
||||
#define RTC_BASE 0x20000000
|
||||
#define SRAM_BASE 0x20000100
|
||||
|
||||
#define WRITE_OFFSET 0x80000000
|
||||
|
||||
struct rtcsram_sram {
|
||||
uint16_t checksum[2];
|
||||
uint16_t ead[2];
|
||||
int32_t counter_bias;
|
||||
int8_t display_offset_h;
|
||||
uint8_t ntd;
|
||||
uint8_t language;
|
||||
uint8_t flags;
|
||||
uint16_t flash_id[12];
|
||||
uint32_t wireless_keyboard_id;
|
||||
uint32_t wireless_pad_id[2];
|
||||
uint8_t last_dvd_errorcode;
|
||||
uint8_t padding1;
|
||||
uint16_t flash_id_checksum[2];
|
||||
uint16_t padding2;
|
||||
} __aligned(32);
|
||||
CTASSERT(sizeof(struct rtcsram_sram) == 64);
|
||||
|
||||
struct rtcsram_softc {
|
||||
struct todr_chip_handle sc_todr;
|
||||
|
||||
uint8_t sc_chan;
|
||||
uint8_t sc_device;
|
||||
|
||||
struct rtcsram_sram sc_sram;
|
||||
};
|
||||
|
||||
static int rtcsram_match(device_t, cfdata_t, void *);
|
||||
static void rtcsram_attach(device_t, device_t, void *);
|
||||
|
||||
static uint32_t rtcsram_read_4(struct rtcsram_softc *, uint32_t);
|
||||
static void rtcsram_write_4(struct rtcsram_softc *, uint32_t, uint32_t);
|
||||
static void rtcsram_read_buf(struct rtcsram_softc *, uint32_t, void *,
|
||||
size_t);
|
||||
|
||||
static int rtcsram_gettime(todr_chip_handle_t, struct timeval *);
|
||||
static int rtcsram_settime(todr_chip_handle_t, struct timeval *);
|
||||
|
||||
CFATTACH_DECL_NEW(rtcsram, sizeof(struct rtcsram_softc),
|
||||
rtcsram_match, rtcsram_attach, NULL, NULL);
|
||||
|
||||
static int
|
||||
rtcsram_match(device_t parent, cfdata_t cf, void *aux)
|
||||
{
|
||||
struct exi_attach_args * const eaa = aux;
|
||||
|
||||
return eaa->eaa_id == WII_RTCSRAM_ID;
|
||||
}
|
||||
|
||||
static void
|
||||
rtcsram_attach(device_t parent, device_t self, void *aux)
|
||||
{
|
||||
struct rtcsram_softc * const sc = device_private(self);
|
||||
struct exi_attach_args * const eaa = aux;
|
||||
|
||||
aprint_naive("\n");
|
||||
aprint_normal(": RTC/SRAM\n");
|
||||
|
||||
sc->sc_chan = eaa->eaa_chan;
|
||||
sc->sc_device = eaa->eaa_device;
|
||||
|
||||
/* Read RTC counter bias from SRAM. */
|
||||
rtcsram_read_buf(sc, SRAM_BASE, &sc->sc_sram, sizeof(sc->sc_sram));
|
||||
aprint_debug_dev(self, "counter bias %d\n", sc->sc_sram.counter_bias);
|
||||
hexdump(aprint_debug, device_xname(self), &sc->sc_sram,
|
||||
sizeof(sc->sc_sram));
|
||||
|
||||
sc->sc_todr.cookie = sc;
|
||||
sc->sc_todr.todr_gettime = rtcsram_gettime;
|
||||
sc->sc_todr.todr_settime = rtcsram_settime;
|
||||
todr_attach(&sc->sc_todr);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
rtcsram_read_4(struct rtcsram_softc *sc, uint32_t offset)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
exi_select(sc->sc_chan, sc->sc_device);
|
||||
exi_send_imm(sc->sc_chan, sc->sc_device, &offset, sizeof(offset));
|
||||
exi_recv_imm(sc->sc_chan, sc->sc_device, &val, sizeof(val));
|
||||
exi_unselect(sc->sc_chan);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static void
|
||||
rtcsram_write_4(struct rtcsram_softc *sc, uint32_t offset, uint32_t val)
|
||||
{
|
||||
offset |= WRITE_OFFSET;
|
||||
|
||||
exi_select(sc->sc_chan, sc->sc_device);
|
||||
exi_send_imm(sc->sc_chan, sc->sc_device, &offset, sizeof(offset));
|
||||
exi_send_imm(sc->sc_chan, sc->sc_device, &val, sizeof(val));
|
||||
exi_unselect(sc->sc_chan);
|
||||
}
|
||||
|
||||
static void
|
||||
rtcsram_read_buf(struct rtcsram_softc *sc, uint32_t offset, void *data,
|
||||
size_t datalen)
|
||||
{
|
||||
exi_select(sc->sc_chan, sc->sc_device);
|
||||
exi_send_imm(sc->sc_chan, sc->sc_device, &offset, sizeof(offset));
|
||||
exi_recv_dma(sc->sc_chan, sc->sc_device, data, datalen);
|
||||
exi_unselect(sc->sc_chan);
|
||||
}
|
||||
|
||||
static int
|
||||
rtcsram_gettime(todr_chip_handle_t ch, struct timeval *tv)
|
||||
{
|
||||
struct rtcsram_softc * const sc = ch->cookie;
|
||||
uint32_t val;
|
||||
|
||||
val = rtcsram_read_4(sc, RTC_BASE);
|
||||
tv->tv_sec = (uint64_t)val + sc->sc_sram.counter_bias;
|
||||
tv->tv_usec = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
rtcsram_settime(todr_chip_handle_t ch, struct timeval *tv)
|
||||
{
|
||||
struct rtcsram_softc * const sc = ch->cookie;
|
||||
|
||||
rtcsram_write_4(sc, RTC_BASE, tv->tv_sec - sc->sc_sram.counter_bias);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: mainbus.c,v 1.2 2024/01/22 21:28:15 jmcneill Exp $ */
|
||||
/* $NetBSD: mainbus.c,v 1.3 2024/01/25 11:47:53 jmcneill Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2002, 2024 The NetBSD Foundation, Inc.
|
||||
|
@ -30,7 +30,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: mainbus.c,v 1.2 2024/01/22 21:28:15 jmcneill Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: mainbus.c,v 1.3 2024/01/25 11:47:53 jmcneill Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/device.h>
|
||||
|
@ -102,6 +102,11 @@ mainbus_attach(device_t parent, device_t self, void *aux)
|
|||
maa.maa_irq = MAINBUSCF_IRQ_DEFAULT;
|
||||
config_found(self, &maa, mainbus_print, CFARGS_NONE);
|
||||
|
||||
maa.maa_name = "exi";
|
||||
maa.maa_addr = EXI_BASE;
|
||||
maa.maa_irq = PI_IRQ_EXI;
|
||||
config_found(self, &maa, mainbus_print, CFARGS_NONE);
|
||||
|
||||
maa.maa_name = "hollywood";
|
||||
maa.maa_addr = MAINBUSCF_ADDR_DEFAULT;
|
||||
maa.maa_irq = PI_IRQ_HOLLYWOOD;
|
||||
|
|
Loading…
Reference in New Issue