188447a05SGarrett D'Amore /*
288447a05SGarrett D'Amore  * CDDL HEADER START
388447a05SGarrett D'Amore  *
488447a05SGarrett D'Amore  * The contents of this file are subject to the terms of the
588447a05SGarrett D'Amore  * Common Development and Distribution License (the "License").
688447a05SGarrett D'Amore  * You may not use this file except in compliance with the License.
788447a05SGarrett D'Amore  *
888447a05SGarrett D'Amore  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
988447a05SGarrett D'Amore  * or http://www.opensolaris.org/os/licensing.
1088447a05SGarrett D'Amore  * See the License for the specific language governing permissions
1188447a05SGarrett D'Amore  * and limitations under the License.
1288447a05SGarrett D'Amore  *
1388447a05SGarrett D'Amore  * When distributing Covered Code, include this CDDL HEADER in each
1488447a05SGarrett D'Amore  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1588447a05SGarrett D'Amore  * If applicable, add the following below this CDDL HEADER, with the
1688447a05SGarrett D'Amore  * fields enclosed by brackets "[]" replaced with your own identifying
1788447a05SGarrett D'Amore  * information: Portions Copyright [yyyy] [name of copyright owner]
1888447a05SGarrett D'Amore  *
1988447a05SGarrett D'Amore  * CDDL HEADER END
2088447a05SGarrett D'Amore  */
2188447a05SGarrett D'Amore /*
22*68c47f65SGarrett D'Amore  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
2388447a05SGarrett D'Amore  * Use is subject to license terms.
2488447a05SGarrett D'Amore  */
2588447a05SGarrett D'Amore 
2688447a05SGarrett D'Amore /*
2788447a05SGarrett D'Amore  * Platform specifc code for the EB2 DMA controller. The EB2 is a PCI bus
2888447a05SGarrett D'Amore  * IC that includes play and record DMA engines and an interface for
2988447a05SGarrett D'Amore  * the CS4231.
3088447a05SGarrett D'Amore  */
3188447a05SGarrett D'Amore 
3288447a05SGarrett D'Amore #include <sys/systm.h>
3388447a05SGarrett D'Amore #include <sys/ddi.h>
3488447a05SGarrett D'Amore #include <sys/sunddi.h>
3588447a05SGarrett D'Amore #include <sys/note.h>
3688447a05SGarrett D'Amore #include <sys/audio/audio_driver.h>
3788447a05SGarrett D'Amore #include "audio_4231.h"
3888447a05SGarrett D'Amore 
3988447a05SGarrett D'Amore /*
4088447a05SGarrett D'Amore  * Attribute structure for the APC, used to create DMA handles.
4188447a05SGarrett D'Amore  */
4288447a05SGarrett D'Amore static ddi_dma_attr_t eb2_dma_attr = {
4388447a05SGarrett D'Amore 	DMA_ATTR_V0,			/* version */
4488447a05SGarrett D'Amore 	0x0000000000000000LL,		/* dlim_addr_lo */
4588447a05SGarrett D'Amore 	0x00000000ffffffffLL,		/* dlim_addr_hi */
4688447a05SGarrett D'Amore 	0x0000000000ffffffLL,		/* DMA counter register */
4788447a05SGarrett D'Amore 	0x0000000000000001LL,		/* DMA address alignment */
4888447a05SGarrett D'Amore 	0x00000074,			/* 4 and 16 byte burst sizes */
4988447a05SGarrett D'Amore 	0x00000001,			/* min effective DMA size */
5088447a05SGarrett D'Amore 	0x000000000000ffffLL,		/* maximum transfer size, 8k */
5188447a05SGarrett D'Amore 	0x000000000000ffffLL,		/* segment boundary, 32k */
5288447a05SGarrett D'Amore 	0x00000001,			/* s/g list length, no s/g */
5388447a05SGarrett D'Amore 	0x00000001,			/* granularity of device, don't care */
5488447a05SGarrett D'Amore 	0				/* DMA flags */
5588447a05SGarrett D'Amore };
5688447a05SGarrett D'Amore 
5788447a05SGarrett D'Amore static ddi_device_acc_attr_t codec_attr = {
5888447a05SGarrett D'Amore 	DDI_DEVICE_ATTR_V0,
5988447a05SGarrett D'Amore 	DDI_STRUCTURE_BE_ACC,
6088447a05SGarrett D'Amore 	DDI_STRICTORDER_ACC
6188447a05SGarrett D'Amore };
6288447a05SGarrett D'Amore 
6388447a05SGarrett D'Amore static ddi_device_acc_attr_t eb2_attr = {
6488447a05SGarrett D'Amore 	DDI_DEVICE_ATTR_V0,
6588447a05SGarrett D'Amore 	DDI_STRUCTURE_LE_ACC,
6688447a05SGarrett D'Amore 	DDI_STRICTORDER_ACC
6788447a05SGarrett D'Amore };
6888447a05SGarrett D'Amore 
6988447a05SGarrett D'Amore /*
7088447a05SGarrett D'Amore  * DMA ops vector functions
7188447a05SGarrett D'Amore  */
7288447a05SGarrett D'Amore static int eb2_map_regs(CS_state_t *);
7388447a05SGarrett D'Amore static void eb2_unmap_regs(CS_state_t *);
7488447a05SGarrett D'Amore static void eb2_reset(CS_state_t *);
7588447a05SGarrett D'Amore static int eb2_start_engine(CS_engine_t *);
7688447a05SGarrett D'Amore static void eb2_stop_engine(CS_engine_t *);
7788447a05SGarrett D'Amore static void eb2_power(CS_state_t *, int);
78*68c47f65SGarrett D'Amore static void eb2_reload(CS_engine_t *);
79*68c47f65SGarrett D'Amore static uint32_t eb2_addr(CS_engine_t *);
8088447a05SGarrett D'Amore 
8188447a05SGarrett D'Amore cs4231_dma_ops_t cs4231_eb2dma_ops = {
8288447a05SGarrett D'Amore 	"EB2 DMA controller",
8388447a05SGarrett D'Amore 	&eb2_dma_attr,
8488447a05SGarrett D'Amore 	eb2_map_regs,
8588447a05SGarrett D'Amore 	eb2_unmap_regs,
8688447a05SGarrett D'Amore 	eb2_reset,
8788447a05SGarrett D'Amore 	eb2_start_engine,
8888447a05SGarrett D'Amore 	eb2_stop_engine,
8988447a05SGarrett D'Amore 	eb2_power,
90*68c47f65SGarrett D'Amore 	eb2_reload,
91*68c47f65SGarrett D'Amore 	eb2_addr,
9288447a05SGarrett D'Amore };
9388447a05SGarrett D'Amore 
9488447a05SGarrett D'Amore /*
9588447a05SGarrett D'Amore  * eb2_map_regs()
9688447a05SGarrett D'Amore  *
9788447a05SGarrett D'Amore  * Description:
9888447a05SGarrett D'Amore  *	This routine allocates the DMA handles and the memory for the
9988447a05SGarrett D'Amore  *	DMA engines to use. It then binds each of the buffers to its
10088447a05SGarrett D'Amore  *	respective handle, getting a DMA cookie. Finally, the registers
10188447a05SGarrett D'Amore  *	are mapped in.
10288447a05SGarrett D'Amore  *
10388447a05SGarrett D'Amore  *	NOTE: All of the ddi_dma_... routines sleep if they cannot get
10488447a05SGarrett D'Amore  *		memory. This means these calls will almost always succeed.
10588447a05SGarrett D'Amore  *
10688447a05SGarrett D'Amore  * Arguments:
10788447a05SGarrett D'Amore  *	CS_state_t	*state		The device's state
10888447a05SGarrett D'Amore  *
10988447a05SGarrett D'Amore  * Returns:
11088447a05SGarrett D'Amore  *	DDI_SUCCESS		Registers successfully mapped
11188447a05SGarrett D'Amore  *	DDI_FAILURE		Registers not successfully mapped
11288447a05SGarrett D'Amore  */
11388447a05SGarrett D'Amore static int
eb2_map_regs(CS_state_t * state)11488447a05SGarrett D'Amore eb2_map_regs(CS_state_t *state)
11588447a05SGarrett D'Amore {
11688447a05SGarrett D'Amore 	dev_info_t	*dip = state->cs_dip;
11788447a05SGarrett D'Amore 
11888447a05SGarrett D'Amore 	/* now, map the codec */
11988447a05SGarrett D'Amore 	if (ddi_regs_map_setup(dip, 0, (caddr_t *)&state->cs_regs, 0,
12088447a05SGarrett D'Amore 	    sizeof (cs4231_pioregs_t), &codec_attr, &CODEC_HANDLE) !=
12188447a05SGarrett D'Amore 	    DDI_SUCCESS) {
12288447a05SGarrett D'Amore 		audio_dev_warn(state->cs_adev, "failed mapping codec regs");
12388447a05SGarrett D'Amore 		goto error;
12488447a05SGarrett D'Amore 	}
12588447a05SGarrett D'Amore 
12688447a05SGarrett D'Amore 	/* next the play registers */
12788447a05SGarrett D'Amore 	if (ddi_regs_map_setup(dip, 1, (caddr_t *)&state->cs_eb2_regs.play, 0,
12888447a05SGarrett D'Amore 	    sizeof (cs4231_eb2regs_t), &eb2_attr, &EB2_PLAY_HNDL) !=
12988447a05SGarrett D'Amore 	    DDI_SUCCESS) {
13088447a05SGarrett D'Amore 		audio_dev_warn(state->cs_adev, "failed mapping play regs");
13188447a05SGarrett D'Amore 		goto error;
13288447a05SGarrett D'Amore 	}
13388447a05SGarrett D'Amore 	state->cs_engines[CS4231_PLAY]->ce_regsh = EB2_PLAY_HNDL;
13488447a05SGarrett D'Amore 	state->cs_engines[CS4231_PLAY]->ce_eb2regs = state->cs_eb2_regs.play;
13588447a05SGarrett D'Amore 
13688447a05SGarrett D'Amore 	/* now the capture registers */
13788447a05SGarrett D'Amore 	if (ddi_regs_map_setup(dip, 2, (caddr_t *)&state->cs_eb2_regs.record, 0,
13888447a05SGarrett D'Amore 	    sizeof (cs4231_eb2regs_t), &eb2_attr, &EB2_REC_HNDL) !=
13988447a05SGarrett D'Amore 	    DDI_SUCCESS) {
14088447a05SGarrett D'Amore 		audio_dev_warn(state->cs_adev, "failed mapping rec regs");
14188447a05SGarrett D'Amore 		goto error;
14288447a05SGarrett D'Amore 	}
14388447a05SGarrett D'Amore 	state->cs_engines[CS4231_REC]->ce_regsh = EB2_REC_HNDL;
14488447a05SGarrett D'Amore 	state->cs_engines[CS4231_REC]->ce_eb2regs = state->cs_eb2_regs.record;
14588447a05SGarrett D'Amore 
14688447a05SGarrett D'Amore 	/* finally the auxio register */
14788447a05SGarrett D'Amore 	if (ddi_regs_map_setup(dip, 3, (caddr_t *)&state->cs_eb2_regs.auxio, 0,
14888447a05SGarrett D'Amore 	    sizeof (uint_t), &eb2_attr, &EB2_AUXIO_HNDL) != DDI_SUCCESS) {
14988447a05SGarrett D'Amore 		audio_dev_warn(state->cs_adev, "failed mapping auxio reg");
15088447a05SGarrett D'Amore 		goto error;
15188447a05SGarrett D'Amore 	}
15288447a05SGarrett D'Amore 
15388447a05SGarrett D'Amore 	/* disable play and record interrupts */
15488447a05SGarrett D'Amore 	ddi_put32(EB2_PLAY_HNDL, &EB2_PLAY_CSR, EB2_PCLEAR_RESET_VALUE);
15588447a05SGarrett D'Amore 	ddi_put32(EB2_REC_HNDL, &EB2_REC_CSR, EB2_RCLEAR_RESET_VALUE);
15688447a05SGarrett D'Amore 
15788447a05SGarrett D'Amore 	return (DDI_SUCCESS);
15888447a05SGarrett D'Amore 
15988447a05SGarrett D'Amore error:
16088447a05SGarrett D'Amore 	eb2_unmap_regs(state);
16188447a05SGarrett D'Amore 	return (DDI_FAILURE);
16288447a05SGarrett D'Amore 
16388447a05SGarrett D'Amore }	/* eb2_map_regs() */
16488447a05SGarrett D'Amore 
16588447a05SGarrett D'Amore /*
16688447a05SGarrett D'Amore  * eb2_unmap_regs()
16788447a05SGarrett D'Amore  *
16888447a05SGarrett D'Amore  * Description:
16988447a05SGarrett D'Amore  *	This routine unmaps the Codec's and DMA engine's registers.
17088447a05SGarrett D'Amore  *	It must be idempotent.
17188447a05SGarrett D'Amore  *
17288447a05SGarrett D'Amore  * Arguments:
17388447a05SGarrett D'Amore  *	CS_state_t	*state	The device's state
17488447a05SGarrett D'Amore  */
17588447a05SGarrett D'Amore static void
eb2_unmap_regs(CS_state_t * state)17688447a05SGarrett D'Amore eb2_unmap_regs(CS_state_t *state)
17788447a05SGarrett D'Amore {
17888447a05SGarrett D'Amore 	if (CODEC_HANDLE)
17988447a05SGarrett D'Amore 		ddi_regs_map_free(&CODEC_HANDLE);
18088447a05SGarrett D'Amore 	if (EB2_PLAY_HNDL)
18188447a05SGarrett D'Amore 		ddi_regs_map_free(&EB2_PLAY_HNDL);
18288447a05SGarrett D'Amore 	if (EB2_REC_HNDL)
18388447a05SGarrett D'Amore 		ddi_regs_map_free(&EB2_REC_HNDL);
18488447a05SGarrett D'Amore 	if (EB2_AUXIO_HNDL)
18588447a05SGarrett D'Amore 		ddi_regs_map_free(&EB2_AUXIO_HNDL);
18688447a05SGarrett D'Amore 
18788447a05SGarrett D'Amore }	/* eb2_unmap_regs() */
18888447a05SGarrett D'Amore 
18988447a05SGarrett D'Amore /*
19088447a05SGarrett D'Amore  * eb2_reset()
19188447a05SGarrett D'Amore  *
19288447a05SGarrett D'Amore  * Description:
19388447a05SGarrett D'Amore  *	Reset both the play and record DMA engines. The engines are left
19488447a05SGarrett D'Amore  *	with interrupts and the DMA engine disabled.
19588447a05SGarrett D'Amore  *
19688447a05SGarrett D'Amore  * Arguments:
19788447a05SGarrett D'Amore  *	dev_info_t	*dip	Pointer to the device's devinfo structure
19888447a05SGarrett D'Amore  *	CS_state_t	*state	The device's state structure
19988447a05SGarrett D'Amore  */
20088447a05SGarrett D'Amore static void
eb2_reset(CS_state_t * state)20188447a05SGarrett D'Amore eb2_reset(CS_state_t *state)
20288447a05SGarrett D'Amore {
20388447a05SGarrett D'Amore 	ddi_acc_handle_t	phandle = EB2_PLAY_HNDL;
20488447a05SGarrett D'Amore 	ddi_acc_handle_t	rhandle = EB2_REC_HNDL;
20588447a05SGarrett D'Amore 	uint_t			reg;
20688447a05SGarrett D'Amore 	int			x;
20788447a05SGarrett D'Amore 
20888447a05SGarrett D'Amore 	/* start with the play side */
20988447a05SGarrett D'Amore 	ddi_put32(phandle, &EB2_PLAY_CSR, EB2_RESET);
21088447a05SGarrett D'Amore 	/* wait for play data to drain */
21188447a05SGarrett D'Amore 	reg = ddi_get32(phandle, &EB2_PLAY_CSR);
21288447a05SGarrett D'Amore 	for (x = 0; (reg & EB2_FIFO_DRAIN) && x < CS4231_TIMEOUT; x++) {
21388447a05SGarrett D'Amore 		drv_usecwait(1);	/* don't beat on the bus */
21488447a05SGarrett D'Amore 		reg = ddi_get32(phandle, &EB2_PLAY_CSR);
21588447a05SGarrett D'Amore 	}
21688447a05SGarrett D'Amore 	/* clear the reset bit and program for chaining */
21788447a05SGarrett D'Amore 	ddi_put32(phandle, &EB2_PLAY_CSR, EB2_PCLEAR_RESET_VALUE);
21888447a05SGarrett D'Amore 
21988447a05SGarrett D'Amore 	/* now do the record side and program for chaining */
22088447a05SGarrett D'Amore 	ddi_put32(rhandle, &EB2_REC_CSR, EB2_RESET);
22188447a05SGarrett D'Amore 	/* wait for record data to drain */
22288447a05SGarrett D'Amore 	reg = ddi_get32(rhandle, &EB2_REC_CSR);
22388447a05SGarrett D'Amore 	for (x = 0; (reg & EB2_FIFO_DRAIN) && x < CS4231_TIMEOUT; x++) {
22488447a05SGarrett D'Amore 		drv_usecwait(1);	/* don't beat on the bus */
22588447a05SGarrett D'Amore 		reg = ddi_get32(rhandle, &EB2_REC_CSR);
22688447a05SGarrett D'Amore 	}
22788447a05SGarrett D'Amore 	/* clear the reset bit */
22888447a05SGarrett D'Amore 	ddi_put32(rhandle, &EB2_REC_CSR, EB2_RCLEAR_RESET_VALUE);
22988447a05SGarrett D'Amore 
23088447a05SGarrett D'Amore }	/* eb2_reset() */
23188447a05SGarrett D'Amore 
23288447a05SGarrett D'Amore /*
23388447a05SGarrett D'Amore  * eb2_start_engine()
23488447a05SGarrett D'Amore  *
23588447a05SGarrett D'Amore  * Description:
23688447a05SGarrett D'Amore  *	This routine starts the DMA engine.
23788447a05SGarrett D'Amore  *
23888447a05SGarrett D'Amore  *	NOTE: The state structure must be locked before this routine is called.
23988447a05SGarrett D'Amore  *
24088447a05SGarrett D'Amore  * Arguments:
24188447a05SGarrett D'Amore  *	CS_engine_t	*eng	The DMA engine's state structure
24288447a05SGarrett D'Amore  *
24388447a05SGarrett D'Amore  * Returns:
24488447a05SGarrett D'Amore  *	DDI_SUCCESS		The DMA engine was started
24588447a05SGarrett D'Amore  *	DDI_FAILURE		The DMA engine was not started
24688447a05SGarrett D'Amore  */
24788447a05SGarrett D'Amore static int
eb2_start_engine(CS_engine_t * eng)24888447a05SGarrett D'Amore eb2_start_engine(CS_engine_t *eng)
24988447a05SGarrett D'Amore {
25088447a05SGarrett D'Amore 	CS_state_t		*state = eng->ce_state;
25188447a05SGarrett D'Amore 	ddi_acc_handle_t	handle = eng->ce_regsh;
25288447a05SGarrett D'Amore 	cs4231_eb2regs_t	*regs = eng->ce_eb2regs;
25388447a05SGarrett D'Amore 	uint_t			csr;
25488447a05SGarrett D'Amore 	int			x;
25588447a05SGarrett D'Amore 	uint32_t		reset;
25688447a05SGarrett D'Amore 	uint32_t		enable;
25788447a05SGarrett D'Amore 
25888447a05SGarrett D'Amore 	if (eng->ce_num == CS4231_PLAY) {
25988447a05SGarrett D'Amore 		reset = EB2_PCLEAR_RESET_VALUE;
26088447a05SGarrett D'Amore 		enable = EB2_PLAY_ENABLE;
26188447a05SGarrett D'Amore 	} else {
26288447a05SGarrett D'Amore 		reset = EB2_RCLEAR_RESET_VALUE;
26388447a05SGarrett D'Amore 		enable = EB2_REC_ENABLE;
26488447a05SGarrett D'Amore 	}
26588447a05SGarrett D'Amore 
26688447a05SGarrett D'Amore 	ASSERT(mutex_owned(&state->cs_lock));
26788447a05SGarrett D'Amore 
26888447a05SGarrett D'Amore 	/* reset the DMA engine so we have a good starting place */
26988447a05SGarrett D'Amore 	OR_SET_WORD(handle, &regs->eb2csr, EB2_RESET);
27088447a05SGarrett D'Amore 
27188447a05SGarrett D'Amore 	/* wait for the FIFO to drain, it should be empty */
27288447a05SGarrett D'Amore 	csr = ddi_get32(handle, &regs->eb2csr);
27388447a05SGarrett D'Amore 	for (x = 0; (csr & EB2_FIFO_DRAIN) && x < CS4231_TIMEOUT; x++) {
27488447a05SGarrett D'Amore 		drv_usecwait(1);	/* no reason to beat on the bus */
27588447a05SGarrett D'Amore 		csr = ddi_get32(handle, &regs->eb2csr);
27688447a05SGarrett D'Amore 	}
27788447a05SGarrett D'Amore 	if (x >= CS4231_TIMEOUT) {
27888447a05SGarrett D'Amore 		audio_dev_warn(state->cs_adev,
27988447a05SGarrett D'Amore 		    "timeout waiting for engine, not started!");
28088447a05SGarrett D'Amore 		return (DDI_FAILURE);
28188447a05SGarrett D'Amore 	}
28288447a05SGarrett D'Amore 
28388447a05SGarrett D'Amore 	/* now clear the RESET and EN_DMA bits */
28488447a05SGarrett D'Amore 	AND_SET_WORD(handle, &regs->eb2csr, ~(EB2_RESET|EB2_EN_DMA));
28588447a05SGarrett D'Amore 
28688447a05SGarrett D'Amore 	/* put into chaining mode, enable byte counts  */
28788447a05SGarrett D'Amore 	OR_SET_WORD(handle, &regs->eb2csr, reset);
28888447a05SGarrett D'Amore 
28988447a05SGarrett D'Amore 	/*
29088447a05SGarrett D'Amore 	 * Program the DMA engine.
29188447a05SGarrett D'Amore 	 */
292*68c47f65SGarrett D'Amore 	eb2_reload(eng);
29388447a05SGarrett D'Amore 
29488447a05SGarrett D'Amore 	/*
29588447a05SGarrett D'Amore 	 * Start playing before we load the next fragment.
29688447a05SGarrett D'Amore 	 */
29788447a05SGarrett D'Amore 	OR_SET_WORD(handle, &regs->eb2csr, enable);
29888447a05SGarrett D'Amore 
29988447a05SGarrett D'Amore 	/*
300*68c47f65SGarrett D'Amore 	 * Program the next address, too.
30188447a05SGarrett D'Amore 	 */
302*68c47f65SGarrett D'Amore 	eb2_reload(eng);
30388447a05SGarrett D'Amore 
30488447a05SGarrett D'Amore 	return (DDI_SUCCESS);
30588447a05SGarrett D'Amore 
30688447a05SGarrett D'Amore }	/* eb2_start_engine() */
30788447a05SGarrett D'Amore 
30888447a05SGarrett D'Amore /*
30988447a05SGarrett D'Amore  * eb2_stop_engine()
31088447a05SGarrett D'Amore  *
31188447a05SGarrett D'Amore  * Description:
31288447a05SGarrett D'Amore  *	This routine stops the DMA engine.
31388447a05SGarrett D'Amore  *
31488447a05SGarrett D'Amore  *	NOTE: The state structure must be locked before this routine is called.
31588447a05SGarrett D'Amore  *
31688447a05SGarrett D'Amore  * Arguments:
31788447a05SGarrett D'Amore  *	CS_engine_t	*eng	The engine to stop
31888447a05SGarrett D'Amore  */
31988447a05SGarrett D'Amore static void
eb2_stop_engine(CS_engine_t * eng)32088447a05SGarrett D'Amore eb2_stop_engine(CS_engine_t *eng)
32188447a05SGarrett D'Amore {
32288447a05SGarrett D'Amore 	ddi_acc_handle_t	handle = eng->ce_regsh;
32388447a05SGarrett D'Amore 	cs4231_eb2regs_t	*regs = eng->ce_eb2regs;
32488447a05SGarrett D'Amore 	uint_t			csr;
32588447a05SGarrett D'Amore 
32688447a05SGarrett D'Amore 	/* shut off DMA and disable interrupts */
32788447a05SGarrett D'Amore 	AND_SET_WORD(handle, &regs->eb2csr, ~(EB2_EN_DMA | EB2_INT_EN));
32888447a05SGarrett D'Amore 
32988447a05SGarrett D'Amore 	csr = ddi_get32(handle, &regs->eb2csr);
33088447a05SGarrett D'Amore 	for (int x = 0; (csr & EB2_CYC_PENDING) && x < CS4231_TIMEOUT; x++) {
33188447a05SGarrett D'Amore 		drv_usecwait(1);
33288447a05SGarrett D'Amore 		csr = ddi_get32(handle, &regs->eb2csr);
33388447a05SGarrett D'Amore 	}
33488447a05SGarrett D'Amore 
33588447a05SGarrett D'Amore 	/* set the RESET bit to stop audio, also clear any TC interrupt */
33688447a05SGarrett D'Amore 	OR_SET_WORD(handle, &regs->eb2csr, EB2_RESET | EB2_TC);
33788447a05SGarrett D'Amore 
33888447a05SGarrett D'Amore 	/* wait for the FIFO to drain */
33988447a05SGarrett D'Amore 	csr = ddi_get32(handle, &regs->eb2csr);
34088447a05SGarrett D'Amore 	for (int x = 0; (csr & EB2_FIFO_DRAIN) && x < CS4231_TIMEOUT; x++) {
34188447a05SGarrett D'Amore 		drv_usecwait(1);		/* don't beat on the bus */
34288447a05SGarrett D'Amore 		csr = ddi_get32(handle, &regs->eb2csr);
34388447a05SGarrett D'Amore 	}
34488447a05SGarrett D'Amore 
34588447a05SGarrett D'Amore 	/* clear the RESET and EN_DMA bits */
34688447a05SGarrett D'Amore 	AND_SET_WORD(handle, &regs->eb2csr, ~(EB2_RESET|EB2_EN_DMA));
34788447a05SGarrett D'Amore 
34888447a05SGarrett D'Amore }	/* eb2_stop_engine() */
34988447a05SGarrett D'Amore 
35088447a05SGarrett D'Amore /*
35188447a05SGarrett D'Amore  * eb2_power()
35288447a05SGarrett D'Amore  *
35388447a05SGarrett D'Amore  * Description:
35488447a05SGarrett D'Amore  *	This routine turns the Codec on or off using the auxio register
35588447a05SGarrett D'Amore  *	in the eb2 device (cheerio or rio). Fortunately we don't need
35688447a05SGarrett D'Amore  *	to delay like we do with the APC.
35788447a05SGarrett D'Amore  *
35888447a05SGarrett D'Amore  *	NOTE: The state structure must be locked when this routine is called.
35988447a05SGarrett D'Amore  *
36088447a05SGarrett D'Amore  * Arguments:
36188447a05SGarrett D'Amore  *	CS_state_t	*state		Ptr to the device's state structure
36288447a05SGarrett D'Amore  *	int		level		Power level to set
36388447a05SGarrett D'Amore  */
36488447a05SGarrett D'Amore static void
eb2_power(CS_state_t * state,int level)36588447a05SGarrett D'Amore eb2_power(CS_state_t *state, int level)
36688447a05SGarrett D'Amore {
36788447a05SGarrett D'Amore 	ddi_acc_handle_t	xhandle = EB2_AUXIO_HNDL;
36888447a05SGarrett D'Amore 
36988447a05SGarrett D'Amore 	if (level == CS4231_PWR_ON) {	/* turn power on */
37088447a05SGarrett D'Amore 		AND_SET_WORD(xhandle, EB2_AUXIO_REG, ~EB2_AUXIO_COD_PDWN);
37188447a05SGarrett D'Amore 	} else {	/* turn power off */
37288447a05SGarrett D'Amore 		OR_SET_WORD(xhandle, EB2_AUXIO_REG, EB2_AUXIO_COD_PDWN);
37388447a05SGarrett D'Amore 	}
37488447a05SGarrett D'Amore 
37588447a05SGarrett D'Amore }	/* eb2_power() */
37688447a05SGarrett D'Amore 
37788447a05SGarrett D'Amore /*
378*68c47f65SGarrett D'Amore  * eb2_reload()
37988447a05SGarrett D'Amore  *
38088447a05SGarrett D'Amore  * Description:
381*68c47f65SGarrett D'Amore  *	This routine reloads the DMA address, so that we can continue
382*68c47f65SGarrett D'Amore  *	double buffer round-robin fashion.
38388447a05SGarrett D'Amore  *
38488447a05SGarrett D'Amore  * Arguments:
385*68c47f65SGarrett D'Amore  *	CS_engine_t	*eng		The engine
38688447a05SGarrett D'Amore  */
38788447a05SGarrett D'Amore static void
eb2_reload(CS_engine_t * eng)388*68c47f65SGarrett D'Amore eb2_reload(CS_engine_t *eng)
38988447a05SGarrett D'Amore {
39088447a05SGarrett D'Amore 	ddi_acc_handle_t	handle = eng->ce_regsh;
39188447a05SGarrett D'Amore 	cs4231_eb2regs_t	*regs = eng->ce_eb2regs;
39288447a05SGarrett D'Amore 
39388447a05SGarrett D'Amore 	/* if next address already loaded, then we're done */
39488447a05SGarrett D'Amore 	if ((ddi_get32(handle, &regs->eb2csr) & EB2_NA_LOADED)) {
39588447a05SGarrett D'Amore 		return;
39688447a05SGarrett D'Amore 	}
39788447a05SGarrett D'Amore 
39888447a05SGarrett D'Amore 	/*
39988447a05SGarrett D'Amore 	 * For eb2 we first program the Next Byte Count Register.
40088447a05SGarrett D'Amore 	 */
401*68c47f65SGarrett D'Amore 	ddi_put32(handle, &regs->eb2bcr, CS4231_FRAGSZ);
40288447a05SGarrett D'Amore 
40388447a05SGarrett D'Amore 	/* now program the Next Address Register */
404*68c47f65SGarrett D'Amore 	ddi_put32(handle, &regs->eb2acr,
405*68c47f65SGarrett D'Amore 	    eng->ce_paddr + (CS4231_FRAGSZ * eng->ce_curidx));
406*68c47f65SGarrett D'Amore 
407*68c47f65SGarrett D'Amore 	eng->ce_curidx++;
408*68c47f65SGarrett D'Amore 	eng->ce_curidx %= CS4231_NFRAGS;
409*68c47f65SGarrett D'Amore }
410*68c47f65SGarrett D'Amore 
411*68c47f65SGarrett D'Amore /*
412*68c47f65SGarrett D'Amore  * eb2_addr()
413*68c47f65SGarrett D'Amore  *
414*68c47f65SGarrett D'Amore  * Description:
415*68c47f65SGarrett D'Amore  *	This routine returns the current DMA address for the engine (the
416*68c47f65SGarrett D'Amore  *	next address being accessed).
417*68c47f65SGarrett D'Amore  *
418*68c47f65SGarrett D'Amore  * Arguments:
419*68c47f65SGarrett D'Amore  *	CS_engine_t	*eng		The engine
420*68c47f65SGarrett D'Amore  *
421*68c47f65SGarrett D'Amore  * Returns:
422*68c47f65SGarrett D'Amore  *	Physical DMA address for current transfer.
423*68c47f65SGarrett D'Amore  */
424*68c47f65SGarrett D'Amore static uint32_t
eb2_addr(CS_engine_t * eng)425*68c47f65SGarrett D'Amore eb2_addr(CS_engine_t *eng)
426*68c47f65SGarrett D'Amore {
427*68c47f65SGarrett D'Amore 	ddi_acc_handle_t	handle = eng->ce_regsh;
428*68c47f65SGarrett D'Amore 	cs4231_eb2regs_t	*regs = eng->ce_eb2regs;
42988447a05SGarrett D'Amore 
430*68c47f65SGarrett D'Amore 	return (ddi_get32(handle, &regs->eb2acr));
43188447a05SGarrett D'Amore }
432