/* $NetBSD: haltwo.c,v 1.26 2019/05/25 04:41:53 isaki Exp $ */
/*
* Copyright (c) 2003 Ilpo Ruotsalainen
* 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.
*
* <<Id: LICENSE_GC,v 1.1 2001/10/01 23:24:05 cgd Exp>>
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: haltwo.c,v 1.26 2019/05/25 04:41:53 isaki Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/audioio.h>
#include <sys/kmem.h>
#include <sys/bus.h>
#include <machine/sysconf.h>
#include <dev/audio/audio_if.h>
#include <sgimips/hpc/hpcvar.h>
#include <sgimips/hpc/hpcreg.h>
#include <sgimips/hpc/haltworeg.h>
#include <sgimips/hpc/haltwovar.h>
#ifdef AUDIO_DEBUG
#define DPRINTF(x) printf x
#else
#define DPRINTF(x)
#endif
static int haltwo_query_format(void *, audio_format_query_t *);
static int haltwo_set_format(void *, int,
const audio_params_t *, const audio_params_t *,
audio_filter_reg_t *, audio_filter_reg_t *);
static int haltwo_round_blocksize(void *, int, int, const audio_params_t *);
static int haltwo_halt_output(void *);
static int haltwo_halt_input(void *);
static int haltwo_getdev(void *, struct audio_device *);
static int haltwo_set_port(void *, mixer_ctrl_t *);
static int haltwo_get_port(void *, mixer_ctrl_t *);
static int haltwo_query_devinfo(void *, mixer_devinfo_t *);
static void *haltwo_malloc(void *, int, size_t);
static void haltwo_free(void *, void *, size_t);
static int haltwo_get_props(void *);
static int haltwo_trigger_output(void *, void *, void *, int, void (*)(void *),
void *, const audio_params_t *);
static int haltwo_trigger_input(void *, void *, void *, int, void (*)(void *),
void *, const audio_params_t *);
static void haltwo_get_locks(void *, kmutex_t **, kmutex_t **);
static bool haltwo_shutdown(device_t, int);
static const struct audio_hw_if haltwo_hw_if = {
.query_format = haltwo_query_format,
.set_format = haltwo_set_format,
.round_blocksize = haltwo_round_blocksize,
.halt_output = haltwo_halt_output,
.halt_input = haltwo_halt_input,
.getdev = haltwo_getdev,
.set_port = haltwo_set_port,
.get_port = haltwo_get_port,
.query_devinfo = haltwo_query_devinfo,
.allocm = haltwo_malloc,
.freem = haltwo_free,
.get_props = haltwo_get_props,
.trigger_output = haltwo_trigger_output,
.trigger_input = haltwo_trigger_input,
.get_locks = haltwo_get_locks,
};
static const struct audio_device haltwo_device = {
"HAL2",
"",
"haltwo"
};
static const struct audio_format haltwo_formats = {
.mode = AUMODE_PLAY,
.encoding = AUDIO_ENCODING_SLINEAR_NE,
.validbits = 16,
.precision = 16,
.channels = 2,
.channel_mask = AUFMT_STEREO,
.frequency_type = 2,
.frequency = { 44100, 48000 },
};
#define HALTWO_NFORMATS __arraycount(haltwo_formats)
static int haltwo_match(device_t, cfdata_t, void *);
static void haltwo_attach(device_t, device_t, void *);
static int haltwo_intr(void *);
CFATTACH_DECL_NEW(haltwo, sizeof(struct haltwo_softc),
haltwo_match, haltwo_attach, NULL, NULL);
#define haltwo_write(sc,type,off,val) \
bus_space_write_4(sc->sc_st, sc->sc_##type##_sh, off, val)
#define haltwo_read(sc,type,off) \
bus_space_read_4(sc->sc_st, sc->sc_##type##_sh, off)
static void
haltwo_write_indirect(struct haltwo_softc *sc, uint32_t ireg, uint16_t low,
uint16_t high)
{
haltwo_write(sc, ctl, HAL2_REG_CTL_IDR0, low);
haltwo_write(sc, ctl, HAL2_REG_CTL_IDR1, high);
haltwo_write(sc, ctl, HAL2_REG_CTL_IDR2, 0);
haltwo_write(sc, ctl, HAL2_REG_CTL_IDR3, 0);
haltwo_write(sc, ctl, HAL2_REG_CTL_IAR, ireg);
while (haltwo_read(sc, ctl, HAL2_REG_CTL_ISR) & HAL2_ISR_TSTATUS)
continue;
}
static void
haltwo_read_indirect(struct haltwo_softc *sc, uint32_t ireg, uint16_t *low,
uint16_t *high)
{
haltwo_write(sc, ctl, HAL2_REG_CTL_IAR,
ireg | HAL2_IAR_READ);
while (haltwo_read(sc, ctl, HAL2_REG_CTL_ISR) & HAL2_ISR_TSTATUS)
continue;
if (low)
*low = haltwo_read(sc, ctl, HAL2_REG_CTL_IDR0);
if (high)
*high = haltwo_read(sc, ctl, HAL2_REG_CTL_IDR1);
}
static int
haltwo_init_codec(struct haltwo_softc *sc, struct haltwo_codec *codec)
{
int err;
int rseg;
size_t allocsz;
allocsz = sizeof(struct hpc_dma_desc) * HALTWO_MAX_DMASEGS;
KASSERT(allocsz <= PAGE_SIZE);
err = bus_dmamem_alloc(sc->sc_dma_tag, allocsz, 0, 0, &codec->dma_seg,
1, &rseg, BUS_DMA_NOWAIT);
if (err)
goto out;
err = bus_dmamem_map(sc->sc_dma_tag, &codec->dma_seg, rseg, allocsz,
(void **)&codec->dma_descs, BUS_DMA_NOWAIT);
if (err)
goto out_free;
err = bus_dmamap_create(sc->sc_dma_tag, allocsz, 1, PAGE_SIZE, 0,
BUS_DMA_NOWAIT, &codec->dma_map);
if (err)
goto out_free;
err = bus_dmamap_load(sc->sc_dma_tag, codec->dma_map, codec->dma_descs,
allocsz, NULL, BUS_DMA_NOWAIT);
if (err)
goto out_destroy;
DPRINTF(("haltwo_init_codec: allocated %d descriptors (%d bytes)"
" at %p\n", HALTWO_MAX_DMASEGS, allocsz, codec->dma_descs));
memset(codec->dma_descs, 0, allocsz);
return 0;
out_destroy:
bus_dmamap_destroy(sc->sc_dma_tag, codec->dma_map);
out_free:
bus_dmamem_free(sc->sc_dma_tag, &codec->dma_seg, rseg);
out:
DPRINTF(("haltwo_init_codec failed: %d\n",err));
return err;
}
static void
haltwo_setup_dma(struct haltwo_softc *sc, struct haltwo_codec *codec,
struct haltwo_dmabuf *dmabuf, size_t len, int blksize,
void (*intr)(void *), void *intrarg)
{
int i;
bus_dma_segment_t *segp;
struct hpc_dma_desc *descp;
int next_intr;
KASSERT(len % blksize == 0);
next_intr = blksize;
codec->intr = intr;
codec->intr_arg = intrarg;
segp = dmabuf->dma_map->dm_segs;
descp = codec->dma_descs;
/* Build descriptor chain for looping DMA, triggering interrupt every
* blksize bytes */
for (i = 0; i < dmabuf->dma_map->dm_nsegs; i++) {
descp->hpc3_hdd_bufptr = segp->ds_addr;
descp->hpc3_hdd_ctl = segp->ds_len;
KASSERT(next_intr >= segp->ds_len);
if (next_intr == segp->ds_len) {
/* Generate intr after this DMA buffer */
descp->hpc3_hdd_ctl |= HPC3_HDD_CTL_INTR;
next_intr = blksize;
} else
next_intr -= segp->ds_len;
if (i < dmabuf->dma_map->dm_nsegs - 1)
descp->hdd_descptr = codec->dma_seg.ds_addr +
sizeof(struct hpc_dma_desc) * (i + 1);
else
descp->hdd_descptr = codec->dma_seg.ds_addr;
DPRINTF(("haltwo_setup_dma: hdd_bufptr = %x hdd_ctl = %x"
" hdd_descptr = %x\n", descp->hpc3_hdd_bufptr,
descp->hpc3_hdd_ctl, descp->hdd_descptr));
segp++;
descp++;
}
bus_dmamap_sync(sc->sc_dma_tag, codec->dma_map, 0,
codec->dma_map->dm_mapsize, BUS_DMASYNC_PREWRITE);
}
static int
haltwo_match(device_t parent, cfdata_t cf, void *aux)
{
struct hpc_attach_args *haa;
uint32_t rev;
haa = aux;
if (strcmp(haa->ha_name, cf->cf_name))
return 0;
if ( platform.badaddr((void *)(vaddr_t)(haa->ha_sh + haa->ha_devoff),
sizeof(uint32_t)) )
return 0;
if ( platform.badaddr(
(void *)(vaddr_t)(haa->ha_sh + haa->ha_devoff + HAL2_REG_CTL_REV),
sizeof(uint32_t)) )
return 0;
rev = *(uint32_t *)MIPS_PHYS_TO_KSEG1(haa->ha_sh + haa->ha_devoff +
HAL2_REG_CTL_REV);
/* This bit is inverted, the test is correct */
if (rev & HAL2_REV_AUDIO_PRESENT_N)
return 0;
return 1;
}
static void
haltwo_attach(device_t parent, device_t self, void *aux)
{
struct haltwo_softc *sc;
struct hpc_attach_args *haa;
uint32_t rev;
sc = device_private(self);
haa = aux;
sc->sc_dev = self;
sc->sc_st = haa->ha_st;
sc->sc_dma_tag = haa->ha_dmat;
mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_AUDIO);
if (bus_space_subregion(haa->ha_st, haa->ha_sh, haa->ha_devoff,
HPC3_PBUS_CH0_DEVREGS_SIZE, &sc->sc_ctl_sh)) {
aprint_error(": unable to map control registers\n");
return;
}
if (bus_space_subregion(haa->ha_st, haa->ha_sh, HPC3_PBUS_CH2_DEVREGS,
HPC3_PBUS_CH2_DEVREGS_SIZE, &sc->sc_vol_sh)) {
aprint_error(": unable to map volume registers\n");
return;
}
if (bus_space_subregion(haa->ha_st, haa->ha_sh, haa->ha_dmaoff,
HPC3_PBUS_DMAREGS_SIZE, &sc->sc_dma_sh)) {
aprint_error(": unable to map DMA registers\n");
return;
}
haltwo_write(sc, ctl, HAL2_REG_CTL_ISR, 0);
haltwo_write(sc, ctl, HAL2_REG_CTL_ISR,
HAL2_ISR_GLOBAL_RESET_N | HAL2_ISR_CODEC_RESET_N);
haltwo_write_indirect(sc, HAL2_IREG_RELAY_C, HAL2_RELAY_C_STATE, 0);
rev = haltwo_read(sc, ctl, HAL2_REG_CTL_REV);
if (cpu_intr_establish(haa->ha_irq, IPL_AUDIO, haltwo_intr, sc)
== NULL) {
aprint_error(": unable to establish interrupt\n");
return;
}
aprint_naive(": Audio controller\n");
aprint_normal(": HAL2 revision %d.%d.%d\n", (rev & 0x7000) >> 12,
(rev & 0x00F0) >> 4, rev & 0x000F);
if (haltwo_init_codec(sc, &sc->sc_dac)) {
aprint_error(
"haltwo_attach: unable to create DMA descriptor list\n");
return;
}
/* XXX Magic PBUS CFGDMA values from Linux HAL2 driver XXX */
bus_space_write_4(haa->ha_st, haa->ha_sh, HPC3_PBUS_CH0_CFGDMA,
0x8208844);
bus_space_write_4(haa->ha_st, haa->ha_sh, HPC3_PBUS_CH1_CFGDMA,
0x8208844);
/* Unmute output */
/* XXX Add mute/unmute support to mixer ops? XXX */
haltwo_write_indirect(sc, HAL2_IREG_DAC_C2, 0, 0);
/* Set master volume to zero */
sc->sc_vol_left = sc->sc_vol_right = 0;
haltwo_write(sc, vol, HAL2_REG_VOL_LEFT, sc->sc_vol_left);
haltwo_write(sc, vol, HAL2_REG_VOL_RIGHT, sc->sc_vol_right);
audio_attach_mi(&haltwo_hw_if, sc, self);
if (!pmf_device_register1(self, NULL, NULL, haltwo_shutdown))
aprint_error_dev(self,
"couldn't establish power handler\n");
}
static int
haltwo_intr(void *v)
{
struct haltwo_softc *sc;
int ret;
sc = v;
ret = 0;
mutex_spin_enter(&sc->sc_intr_lock);
if (bus_space_read_4(sc->sc_st, sc->sc_dma_sh, HPC3_PBUS_CH0_CTL)
& HPC3_PBUS_DMACTL_IRQ) {
sc->sc_dac.intr(sc->sc_dac.intr_arg);
ret = 1;
} else
DPRINTF(("haltwo_intr: Huh?\n"));
mutex_spin_exit(&sc->sc_intr_lock);
return ret;
}
static int
haltwo_query_format(void *v, audio_format_query_t *afp)
{
return audio_query_format(&haltwo_formats, 1, afp);
}
static int
haltwo_set_format(void *v, int setmode,
const audio_params_t *play, const audio_params_t *rec,
audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
{
struct haltwo_softc *sc;
int inc;
uint16_t tmp;
sc = v;
inc = 4;
/* Setup samplerate to HW */
haltwo_write_indirect(sc, HAL2_IREG_BRES1_C1,
play->sample_rate == 44100 ? 1 : 0, 0);
/* XXX Documentation disagrees but this seems to work XXX */
haltwo_write_indirect(sc, HAL2_IREG_BRES1_C2, inc, 0xFFFF);
/* Setup endianness to HW */
haltwo_read_indirect(sc, HAL2_IREG_DMA_END, &tmp, NULL);
if (play->encoding == AUDIO_ENCODING_SLINEAR_LE)
tmp |= HAL2_DMA_END_CODECTX;
else
tmp &= ~HAL2_DMA_END_CODECTX;
haltwo_write_indirect(sc, HAL2_IREG_DMA_END, tmp, 0);
/* Set PBUS channel, Bresenham clock source, number of channels to HW */
haltwo_write_indirect(sc, HAL2_IREG_DAC_C1,
(0 << HAL2_C1_DMA_SHIFT) |
(1 << HAL2_C1_CLKID_SHIFT) |
(play->channels << HAL2_C1_DATAT_SHIFT), 0);
DPRINTF(("%s: hw_encoding = %d hw_channels = %d\n", __func__,
play->encoding, play->channels));
return 0;
}
static int
haltwo_round_blocksize(void *v, int blocksize,
int mode, const audio_params_t *param)
{
/* XXX Make this smarter and support DMA descriptor chaining XXX */
/* XXX Rounding to nearest PAGE_SIZE might work? XXX */
return PAGE_SIZE;
}
static int
haltwo_halt_output(void *v)
{
struct haltwo_softc *sc;
sc = v;
/* Disable PBUS DMA */
bus_space_write_4(sc->sc_st, sc->sc_dma_sh, HPC3_PBUS_CH0_CTL,
HPC3_PBUS_DMACTL_ACT_LD);
return 0;
}
static int
haltwo_halt_input(void *v)
{
return ENXIO;
}
static int
haltwo_getdev(void *v, struct audio_device *dev)
{
*dev = haltwo_device;
return 0;
}
static int
haltwo_set_port(void *v, mixer_ctrl_t *mc)
{
struct haltwo_softc *sc;
int lval, rval;
if (mc->type != AUDIO_MIXER_VALUE)
return EINVAL;
if (mc->un.value.num_channels == 1)
lval = rval = mc->un.value.level[AUDIO_MIXER_LEVEL_MONO];
else if (mc->un.value.num_channels == 2) {
lval = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
rval = mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
} else
return EINVAL;
sc = v;
switch (mc->dev) {
case HALTWO_MASTER_VOL:
sc->sc_vol_left = lval;
sc->sc_vol_right = rval;
haltwo_write(sc, vol, HAL2_REG_VOL_LEFT,
sc->sc_vol_left);
haltwo_write(sc, vol, HAL2_REG_VOL_RIGHT,
sc->sc_vol_right);
break;
default:
return EINVAL;
}
return 0;
}
static int
haltwo_get_port(void *v, mixer_ctrl_t *mc)
{
struct haltwo_softc *sc;
int l, r;
switch (mc->dev) {
case HALTWO_MASTER_VOL:
sc = v;
l = sc->sc_vol_left;
r = sc->sc_vol_right;
break;
default:
return EINVAL;
}
if (mc->un.value.num_channels == 1)
mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] = (l+r) / 2;
else if (mc->un.value.num_channels == 2) {
mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
} else
return EINVAL;
return 0;
}
static int
haltwo_query_devinfo(void *v, mixer_devinfo_t *dev)
{
switch (dev->index) {
/* Mixer values */
case HALTWO_MASTER_VOL:
dev->type = AUDIO_MIXER_VALUE;
dev->mixer_class = HALTWO_OUTPUT_CLASS;
dev->prev = dev->next = AUDIO_MIXER_LAST;
strcpy(dev->label.name, AudioNmaster);
dev->un.v.num_channels = 2;
dev->un.v.delta = 16;
strcpy(dev->un.v.units.name, AudioNvolume);
break;
/* Mixer classes */
case HALTWO_OUTPUT_CLASS:
dev->type = AUDIO_MIXER_CLASS;
dev->mixer_class = HALTWO_OUTPUT_CLASS;
dev->next = dev->prev = AUDIO_MIXER_LAST;
strcpy(dev->label.name, AudioCoutputs);
break;
default:
return EINVAL;
}
return 0;
}
static int
haltwo_alloc_dmamem(struct haltwo_softc *sc, size_t size,
struct haltwo_dmabuf *p)
{
int err;
p->size = size;
/* XXX Check align/boundary XXX */
err = bus_dmamem_alloc(sc->sc_dma_tag, p->size, 0, 0, p->dma_segs,
HALTWO_MAX_DMASEGS, &p->dma_segcount, BUS_DMA_WAITOK);
if (err)
goto out;
/* XXX BUS_DMA_COHERENT? XXX */
err = bus_dmamem_map(sc->sc_dma_tag, p->dma_segs, p->dma_segcount,
p->size, &p->kern_addr, BUS_DMA_WAITOK | BUS_DMA_COHERENT);
if (err)
goto out_free;
/* XXX Just guessing ... XXX */
err = bus_dmamap_create(sc->sc_dma_tag, p->size, HALTWO_MAX_DMASEGS,
PAGE_SIZE, 0, BUS_DMA_WAITOK, &p->dma_map);
if (err)
goto out_free;
err = bus_dmamap_load(sc->sc_dma_tag, p->dma_map, p->kern_addr,
p->size, NULL, BUS_DMA_WAITOK);
if (err)
goto out_destroy;
return 0;
out_destroy:
bus_dmamap_destroy(sc->sc_dma_tag, p->dma_map);
out_free:
bus_dmamem_free(sc->sc_dma_tag, p->dma_segs, p->dma_segcount);
out:
DPRINTF(("haltwo_alloc_dmamem failed: %d\n",err));
return err;
}
static void *
haltwo_malloc(void *v, int direction, size_t size)
{
struct haltwo_softc *sc;
struct haltwo_dmabuf *p;
DPRINTF(("haltwo_malloc size = %d\n", size));
sc = v;
p = kmem_alloc(sizeof(*p), KM_SLEEP);
if (haltwo_alloc_dmamem(sc, size, p)) {
kmem_free(p, sizeof(*p));
return NULL;
}
p->next = sc->sc_dma_bufs;
sc->sc_dma_bufs = p;
return p->kern_addr;
}
static void
haltwo_free(void *v, void *addr, size_t size)
{
struct haltwo_softc *sc;
struct haltwo_dmabuf *p, **pp;
sc = v;
for (pp = &sc->sc_dma_bufs; (p = *pp) != NULL; pp = &p->next) {
if (p->kern_addr == addr) {
*pp = p->next;
kmem_free(p, sizeof(*p));
return;
}
}
panic("haltwo_free: buffer not in list");
}
static int
haltwo_get_props(void *v)
{
return AUDIO_PROP_PLAYBACK;
}
static int
haltwo_trigger_output(void *v, void *start, void *end, int blksize,
void (*intr)(void *), void *intrarg, const audio_params_t *param)
{
struct haltwo_softc *sc;
struct haltwo_dmabuf *p;
uint16_t tmp;
uint32_t ctrl;
unsigned int fifobeg, fifoend, highwater;
DPRINTF(("haltwo_trigger_output start = %p end = %p blksize = %d"
" param = %p\n", start, end, blksize, param));
sc = v;
for (p = sc->sc_dma_bufs; p != NULL; p = p->next)
if (p->kern_addr == start)
break;
if (p == NULL) {
printf("haltwo_trigger_output: buffer not in list\n");
return EINVAL;
}
/* Disable PBUS DMA */
bus_space_write_4(sc->sc_st, sc->sc_dma_sh, HPC3_PBUS_CH0_CTL,
HPC3_PBUS_DMACTL_ACT_LD);
/* Disable HAL2 codec DMA */
haltwo_read_indirect(sc, HAL2_IREG_DMA_PORT_EN, &tmp, NULL);
haltwo_write_indirect(sc, HAL2_IREG_DMA_PORT_EN,
tmp & ~HAL2_DMA_PORT_EN_CODECTX, 0);
haltwo_setup_dma(sc, &sc->sc_dac, p, (char *)end - (char *)start,
blksize, intr, intrarg);
highwater = (param->channels * 4) >> 1;
fifobeg = 0;
fifoend = (param->channels * 8) >> 3;
DPRINTF(("haltwo_trigger_output: hw_channels = %d highwater = %d"
" fifobeg = %d fifoend = %d\n", param->channels, highwater,
fifobeg, fifoend));
ctrl = HPC3_PBUS_DMACTL_RT
| HPC3_PBUS_DMACTL_ACT_LD
| (highwater << HPC3_PBUS_DMACTL_HIGHWATER_SHIFT)
| (fifobeg << HPC3_PBUS_DMACTL_FIFOBEG_SHIFT)
| (fifoend << HPC3_PBUS_DMACTL_FIFOEND_SHIFT);
/* Using PBUS CH0 for DAC DMA */
haltwo_write_indirect(sc, HAL2_IREG_DMA_DRV, 1, 0);
/* HAL2 is ready for action, now setup PBUS for DMA transfer */
bus_space_write_4(sc->sc_st, sc->sc_dma_sh, HPC3_PBUS_CH0_DP,
sc->sc_dac.dma_seg.ds_addr);
bus_space_write_4(sc->sc_st, sc->sc_dma_sh, HPC3_PBUS_CH0_CTL,
ctrl | HPC3_PBUS_DMACTL_ACT);
/* Both HAL2 and PBUS have been setup, now start it up */
haltwo_read_indirect(sc, HAL2_IREG_DMA_PORT_EN, &tmp, NULL);
haltwo_write_indirect(sc, HAL2_IREG_DMA_PORT_EN,
tmp | HAL2_DMA_PORT_EN_CODECTX, 0);
return 0;
}
static int
haltwo_trigger_input(void *v, void *start, void *end, int blksize,
void (*intr)(void *), void *intrarg, const audio_params_t *param)
{
struct haltwo_softc *sc;
struct haltwo_dmabuf *p;
DPRINTF(("haltwo_trigger_input start = %p end = %p blksize = %d\n",
start, end, blksize));
sc = v;
for (p = sc->sc_dma_bufs; p != NULL; p = p->next)
if (p->kern_addr == start)
break;
if (p == NULL) {
printf("haltwo_trigger_input: buffer not in list\n");
return EINVAL;
}
#if 0
haltwo_setup_dma(sc, &sc->sc_adc, p, (char *)end - (char *)start,
blksize, intr, intrarg);
#endif
return ENXIO;
}
static void
haltwo_get_locks(void *v, kmutex_t **intr, kmutex_t **thread)
{
struct haltwo_softc *sc;
DPRINTF(("haltwo_get_locks\n"));
sc = v;
*intr = &sc->sc_intr_lock;
*thread = &sc->sc_lock;
}
bool
haltwo_shutdown(device_t self, int howto)
{
struct haltwo_softc *sc;
sc = device_private(self);
haltwo_write(sc, ctl, HAL2_REG_CTL_ISR, 0);
haltwo_write(sc, ctl, HAL2_REG_CTL_ISR,
HAL2_ISR_GLOBAL_RESET_N | HAL2_ISR_CODEC_RESET_N);
return true;
}