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 APC DMA controller. The APC is an SBus
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 apc_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 	0x0000000000000fffLL,		/* DMA counter register */
4788447a05SGarrett D'Amore 	0x0000000000000001LL,		/* DMA address alignment */
4888447a05SGarrett D'Amore 	0x00000014,			/* 4 and 16 byte burst sizes */
4988447a05SGarrett D'Amore 	0x00000001,			/* min effective DMA size */
5088447a05SGarrett D'Amore 	0x0000000000000fffLL,		/* 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 acc_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 /*
6488447a05SGarrett D'Amore  * DMA ops vector functions
6588447a05SGarrett D'Amore  */
6688447a05SGarrett D'Amore static int apc_map_regs(CS_state_t *);
6788447a05SGarrett D'Amore static void apc_unmap_regs(CS_state_t *);
6888447a05SGarrett D'Amore static void apc_reset(CS_state_t *);
6988447a05SGarrett D'Amore static int apc_start_engine(CS_engine_t *);
7088447a05SGarrett D'Amore static void apc_stop_engine(CS_engine_t *);
7188447a05SGarrett D'Amore static void apc_power(CS_state_t *, int);
72*68c47f65SGarrett D'Amore static void apc_reload(CS_engine_t *);
73*68c47f65SGarrett D'Amore static uint32_t apc_addr(CS_engine_t *);
7488447a05SGarrett D'Amore 
7588447a05SGarrett D'Amore cs4231_dma_ops_t cs4231_apcdma_ops = {
7688447a05SGarrett D'Amore 	"APC DMA controller",
7788447a05SGarrett D'Amore 	&apc_dma_attr,
7888447a05SGarrett D'Amore 	apc_map_regs,
7988447a05SGarrett D'Amore 	apc_unmap_regs,
8088447a05SGarrett D'Amore 	apc_reset,
8188447a05SGarrett D'Amore 	apc_start_engine,
8288447a05SGarrett D'Amore 	apc_stop_engine,
8388447a05SGarrett D'Amore 	apc_power,
84*68c47f65SGarrett D'Amore 	apc_reload,
85*68c47f65SGarrett D'Amore 	apc_addr,
8688447a05SGarrett D'Amore };
8788447a05SGarrett D'Amore 
8888447a05SGarrett D'Amore /*
8988447a05SGarrett D'Amore  * apc_map_regs()
9088447a05SGarrett D'Amore  *
9188447a05SGarrett D'Amore  * Description:
9288447a05SGarrett D'Amore  *	This routine allocates the DMA handles and the memory for the
9388447a05SGarrett D'Amore  *	DMA engines to use. It then binds each of the buffers to its
9488447a05SGarrett D'Amore  *	respective handle, getting a DMA cookie. Finally, the registers
9588447a05SGarrett D'Amore  *	are mapped in.
9688447a05SGarrett D'Amore  *
9788447a05SGarrett D'Amore  *	NOTE: All of the ddi_dma_... routines sleep if they cannot get
9888447a05SGarrett D'Amore  *		memory. This means these calls will almost always succeed.
9988447a05SGarrett D'Amore  *
10088447a05SGarrett D'Amore  * Arguments:
10188447a05SGarrett D'Amore  *	CS_state_t	*state		The device's state structure
10288447a05SGarrett D'Amore  *
10388447a05SGarrett D'Amore  * Returns:
10488447a05SGarrett D'Amore  *	AUDIO_SUCCESS		Registers successfully mapped
10588447a05SGarrett D'Amore  *	AUDIO_FAILURE		Registers not successfully mapped
10688447a05SGarrett D'Amore  */
10788447a05SGarrett D'Amore static int
apc_map_regs(CS_state_t * state)10888447a05SGarrett D'Amore apc_map_regs(CS_state_t *state)
10988447a05SGarrett D'Amore {
11088447a05SGarrett D'Amore 	ddi_acc_handle_t	*handle = &APC_HANDLE;
11188447a05SGarrett D'Amore 	dev_info_t		*dip = state->cs_dip;
11288447a05SGarrett D'Amore 
11388447a05SGarrett D'Amore 	/* map in the registers, getting a handle */
11488447a05SGarrett D'Amore 	if (ddi_regs_map_setup(dip, 0, (caddr_t *)&state->cs_regs, 0,
11588447a05SGarrett D'Amore 	    sizeof (cs4231_regs_t), &acc_attr, handle) != DDI_SUCCESS) {
11688447a05SGarrett D'Amore 		audio_dev_warn(state->cs_adev, "ddi_regs_map_setup() failed");
11788447a05SGarrett D'Amore 		return (DDI_FAILURE);
11888447a05SGarrett D'Amore 	}
11988447a05SGarrett D'Amore 
12088447a05SGarrett D'Amore 	/* clear the CSR so we have all interrupts disabled */
12188447a05SGarrett D'Amore 	ddi_put32(*handle, &APC_DMACSR, APC_CLEAR_RESET_VALUE);
12288447a05SGarrett D'Amore 
12388447a05SGarrett D'Amore 	return (DDI_SUCCESS);
12488447a05SGarrett D'Amore }	/* apc_map_regs() */
12588447a05SGarrett D'Amore 
12688447a05SGarrett D'Amore /*
12788447a05SGarrett D'Amore  * apc_unmap_regs()
12888447a05SGarrett D'Amore  *
12988447a05SGarrett D'Amore  * Description:
13088447a05SGarrett D'Amore  *	This routine unmaps the Codec's and DMA engine's registers.
13188447a05SGarrett D'Amore  *	It must be idempotent.
13288447a05SGarrett D'Amore  *
13388447a05SGarrett D'Amore  * Arguments:
13488447a05SGarrett D'Amore  *	CS_state_t	*state	The device's state structure
13588447a05SGarrett D'Amore  *
13688447a05SGarrett D'Amore  * Returns:
13788447a05SGarrett D'Amore  *	void
13888447a05SGarrett D'Amore  */
13988447a05SGarrett D'Amore static void
apc_unmap_regs(CS_state_t * state)14088447a05SGarrett D'Amore apc_unmap_regs(CS_state_t *state)
14188447a05SGarrett D'Amore {
14288447a05SGarrett D'Amore 	if (APC_HANDLE)
14388447a05SGarrett D'Amore 		ddi_regs_map_free(&APC_HANDLE);
14488447a05SGarrett D'Amore 
14588447a05SGarrett D'Amore }	/* apc_unmap_regs() */
14688447a05SGarrett D'Amore 
14788447a05SGarrett D'Amore /*
14888447a05SGarrett D'Amore  * apc_reset()
14988447a05SGarrett D'Amore  *
15088447a05SGarrett D'Amore  * Description:
15188447a05SGarrett D'Amore  *	Reset both the play and record DMA engines. The engines are left
15288447a05SGarrett D'Amore  *	with interrupts and the DMA engine disabled.
15388447a05SGarrett D'Amore  *
15488447a05SGarrett D'Amore  * Arguments:
15588447a05SGarrett D'Amore  *	dev_info_t	*dip	Pointer to the device's devinfo structure
15688447a05SGarrett D'Amore  *	CS_state_t	*state	The device's state structure
15788447a05SGarrett D'Amore  *
15888447a05SGarrett D'Amore  * Returns:
15988447a05SGarrett D'Amore  *	void
16088447a05SGarrett D'Amore  */
16188447a05SGarrett D'Amore static void
apc_reset(CS_state_t * state)16288447a05SGarrett D'Amore apc_reset(CS_state_t *state)
16388447a05SGarrett D'Amore {
16488447a05SGarrett D'Amore 	ddi_acc_handle_t	handle = APC_HANDLE;
16588447a05SGarrett D'Amore 
16688447a05SGarrett D'Amore 	/*
16788447a05SGarrett D'Amore 	 * The APC has a bug where the reset is not done
16888447a05SGarrett D'Amore 	 * until you do the next pio to the APC. This
16988447a05SGarrett D'Amore 	 * next write to the CSR causes the posted reset to
17088447a05SGarrett D'Amore 	 * happen.
17188447a05SGarrett D'Amore 	 */
17288447a05SGarrett D'Amore 
17388447a05SGarrett D'Amore 	ddi_put32(handle, &APC_DMACSR, APC_RESET);
17488447a05SGarrett D'Amore 	ddi_put32(handle, &APC_DMACSR, APC_CLEAR_RESET_VALUE);
17588447a05SGarrett D'Amore 
17688447a05SGarrett D'Amore }	/* apc_reset() */
17788447a05SGarrett D'Amore 
17888447a05SGarrett D'Amore /*
17988447a05SGarrett D'Amore  * apc_start_engine()
18088447a05SGarrett D'Amore  *
18188447a05SGarrett D'Amore  * Description:
18288447a05SGarrett D'Amore  *	This routine starts the DMA engine.
18388447a05SGarrett D'Amore  *
18488447a05SGarrett D'Amore  *	For hard starts the DMA engine is started by programming the
18588447a05SGarrett D'Amore  *	Next Virtual Address and then the Next Counter twice, and
18688447a05SGarrett D'Amore  *	finally enabling the DMA engine.
18788447a05SGarrett D'Amore  *
18888447a05SGarrett D'Amore  *	NOTE: The state structure must be locked before this routine is called.
18988447a05SGarrett D'Amore  *
19088447a05SGarrett D'Amore  *	CAUTION: ?!? This routine doesn't start the Codec because the first
19188447a05SGarrett D'Amore  *		interrupt causes a recursive mutex_enter.
19288447a05SGarrett D'Amore  *
19388447a05SGarrett D'Amore  * Arguments:
19488447a05SGarrett D'Amore  *	CS_engine_t	*eng	The engine to start
19588447a05SGarrett D'Amore  *
19688447a05SGarrett D'Amore  * Returns:
19788447a05SGarrett D'Amore  *	DDI_SUCCESS		The DMA engine was started
19888447a05SGarrett D'Amore  *	DDI_FAILURE		The DMA engine was not started
19988447a05SGarrett D'Amore  */
20088447a05SGarrett D'Amore static int
apc_start_engine(CS_engine_t * eng)20188447a05SGarrett D'Amore apc_start_engine(CS_engine_t *eng)
20288447a05SGarrett D'Amore {
20388447a05SGarrett D'Amore 	CS_state_t		*state = eng->ce_state;
20488447a05SGarrett D'Amore 	ddi_acc_handle_t	handle = APC_HANDLE;
20588447a05SGarrett D'Amore 	uint32_t		csr;
20688447a05SGarrett D'Amore 	uint32_t		enable;
20788447a05SGarrett D'Amore 	uint32_t		dirty;
20888447a05SGarrett D'Amore 	int			x;
20988447a05SGarrett D'Amore 
21088447a05SGarrett D'Amore 	ASSERT(mutex_owned(&state->cs_lock));
21188447a05SGarrett D'Amore 
21288447a05SGarrett D'Amore 	if (eng->ce_num == CS4231_PLAY) {
213*68c47f65SGarrett D'Amore 		enable = APC_PDMA_GO;
21488447a05SGarrett D'Amore 		dirty = APC_PD;
21588447a05SGarrett D'Amore 	} else {
216*68c47f65SGarrett D'Amore 		enable = APC_CDMA_GO;
21788447a05SGarrett D'Amore 		dirty = APC_CD;
21888447a05SGarrett D'Amore 	}
21988447a05SGarrett D'Amore 
22088447a05SGarrett D'Amore 	/* make sure it's okay to program the Next Address/Count registers */
22188447a05SGarrett D'Amore 	csr = ddi_get32(handle, &APC_DMACSR);
22288447a05SGarrett D'Amore 	for (x = 0; !(csr & dirty) && x < CS4231_TIMEOUT; x++) {
22388447a05SGarrett D'Amore 		drv_usecwait(1);	/* no reason to beat on the bus */
22488447a05SGarrett D'Amore 		csr = ddi_get32(handle, &APC_DMACSR);
22588447a05SGarrett D'Amore 	}
22688447a05SGarrett D'Amore 	if (x >= CS4231_TIMEOUT) {
22788447a05SGarrett D'Amore 		audio_dev_warn(state->cs_adev,
22888447a05SGarrett D'Amore 		    "timeout waiting for engine, not started!");
22988447a05SGarrett D'Amore 		return (DDI_FAILURE);
23088447a05SGarrett D'Amore 	}
23188447a05SGarrett D'Amore 
23288447a05SGarrett D'Amore 	/*
23388447a05SGarrett D'Amore 	 * Program the first fragment.
23488447a05SGarrett D'Amore 	 */
235*68c47f65SGarrett D'Amore 	apc_reload(eng);
23688447a05SGarrett D'Amore 
23788447a05SGarrett D'Amore 	/*
23888447a05SGarrett D'Amore 	 * Start the DMA engine, including interrupts.
23988447a05SGarrett D'Amore 	 */
24088447a05SGarrett D'Amore 	OR_SET_WORD(handle, &APC_DMACSR, enable);
24188447a05SGarrett D'Amore 
24288447a05SGarrett D'Amore 	/*
243*68c47f65SGarrett D'Amore 	 * Program the double buffering.
24488447a05SGarrett D'Amore 	 */
245*68c47f65SGarrett D'Amore 	apc_reload(eng);
24688447a05SGarrett D'Amore 
24788447a05SGarrett D'Amore 	return (DDI_SUCCESS);
24888447a05SGarrett D'Amore }
24988447a05SGarrett D'Amore 
25088447a05SGarrett D'Amore /*
25188447a05SGarrett D'Amore  * apc_stop_engine()
25288447a05SGarrett D'Amore  *
25388447a05SGarrett D'Amore  * Description:
25488447a05SGarrett D'Amore  *	This routine stops the engine.
25588447a05SGarrett D'Amore  *
25688447a05SGarrett D'Amore  *	The DMA engine is stopped by using the CAP_ABORT bit.
25788447a05SGarrett D'Amore  *
25888447a05SGarrett D'Amore  *	NOTE: The state structure must be locked before this routine is called.
25988447a05SGarrett D'Amore  *
26088447a05SGarrett D'Amore  * Arguments:
26188447a05SGarrett D'Amore  *	CS_engine_t	*eng	The engine to sotp
26288447a05SGarrett D'Amore  *
26388447a05SGarrett D'Amore  * Returns:
26488447a05SGarrett D'Amore  *	void
26588447a05SGarrett D'Amore  */
26688447a05SGarrett D'Amore static void
apc_stop_engine(CS_engine_t * eng)26788447a05SGarrett D'Amore apc_stop_engine(CS_engine_t *eng)
26888447a05SGarrett D'Amore {
26988447a05SGarrett D'Amore 	CS_state_t		*state = eng->ce_state;
27088447a05SGarrett D'Amore 	ddi_acc_handle_t	handle = APC_HANDLE;
27188447a05SGarrett D'Amore 	uint32_t		reg;
27288447a05SGarrett D'Amore 	uint32_t		abort;
27388447a05SGarrett D'Amore 	uint32_t		drainbit;
27488447a05SGarrett D'Amore 	uint32_t		disable;
27588447a05SGarrett D'Amore 
27688447a05SGarrett D'Amore 	ASSERT(mutex_owned(&state->cs_lock));
27788447a05SGarrett D'Amore 
27888447a05SGarrett D'Amore 	if (eng->ce_num == CS4231_PLAY) {
27988447a05SGarrett D'Amore 		abort = APC_P_ABORT;
28088447a05SGarrett D'Amore 		drainbit = APC_PM;
28188447a05SGarrett D'Amore 		disable = APC_PLAY_DISABLE;
28288447a05SGarrett D'Amore 	} else {
28388447a05SGarrett D'Amore 		abort = APC_C_ABORT;
28488447a05SGarrett D'Amore 		drainbit = APC_CX;
28588447a05SGarrett D'Amore 		disable = APC_CAP_DISABLE;
28688447a05SGarrett D'Amore 	}
28788447a05SGarrett D'Amore 
28888447a05SGarrett D'Amore 	/* first, abort the DMA engine */
28988447a05SGarrett D'Amore 	OR_SET_WORD(handle, &APC_DMACSR, abort);
29088447a05SGarrett D'Amore 
29188447a05SGarrett D'Amore 	/* wait for the pipeline to empty */
29288447a05SGarrett D'Amore 	reg = ddi_get32(handle, &APC_DMACSR);
29388447a05SGarrett D'Amore 	for (int x = 0; (!(reg & drainbit)) && (x < CS4231_TIMEOUT); x++) {
29488447a05SGarrett D'Amore 		drv_usecwait(1);	/* don't beat on bus */
29588447a05SGarrett D'Amore 		reg = ddi_get32(handle, &APC_DMACSR);
29688447a05SGarrett D'Amore 	}
29788447a05SGarrett D'Amore 
29888447a05SGarrett D'Amore 	/* now clear the enable and abort bits */
29988447a05SGarrett D'Amore 	AND_SET_WORD(handle, &APC_DMACSR, ~(abort|disable));
30088447a05SGarrett D'Amore }
30188447a05SGarrett D'Amore 
30288447a05SGarrett D'Amore 
30388447a05SGarrett D'Amore /*
30488447a05SGarrett D'Amore  * apc_power()
30588447a05SGarrett D'Amore  *
30688447a05SGarrett D'Amore  * Description:
30788447a05SGarrett D'Amore  *	This routine turns the Codec off by using the COD_PDWN bit in the
30888447a05SGarrett D'Amore  *	apc chip. To turn power on we have to reset the APC, which clears
30988447a05SGarrett D'Amore  *	the COD_PDWN bit. However, this is a settling bug in the APC which
31088447a05SGarrett D'Amore  *	requires the driver to delay quite a while before we may continue.
31188447a05SGarrett D'Amore  *	Since this is the first time this feature has actually been used
31288447a05SGarrett D'Amore  *	it isn't too surprising that it has some problems.
31388447a05SGarrett D'Amore  *
31488447a05SGarrett D'Amore  *	NOTE: The state structure must be locked when this routine is called.
31588447a05SGarrett D'Amore  *
31688447a05SGarrett D'Amore  * Arguments:
31788447a05SGarrett D'Amore  *	CS_state_t	*state		Ptr to the device's state structure
31888447a05SGarrett D'Amore  *	int		level		Power level to set
31988447a05SGarrett D'Amore  */
32088447a05SGarrett D'Amore static void
apc_power(CS_state_t * state,int level)32188447a05SGarrett D'Amore apc_power(CS_state_t *state, int level)
32288447a05SGarrett D'Amore {
32388447a05SGarrett D'Amore 	ddi_acc_handle_t	handle = APC_HANDLE;
32488447a05SGarrett D'Amore 
32588447a05SGarrett D'Amore 	if (level == CS4231_PWR_ON) {	/* turn power on */
32688447a05SGarrett D'Amore 		AND_SET_WORD(handle, &APC_DMACSR, ~APC_COD_PDWN);
32788447a05SGarrett D'Amore 		OR_SET_WORD(handle, &APC_DMACSR, APC_RESET);
32888447a05SGarrett D'Amore 		AND_SET_WORD(handle, &APC_DMACSR, ~APC_RESET);
32988447a05SGarrett D'Amore 
33088447a05SGarrett D'Amore 		/*
33188447a05SGarrett D'Amore 		 * wait for state change,
33288447a05SGarrett D'Amore 		 */
33388447a05SGarrett D'Amore 		delay(drv_usectohz(CS4231_300MS));
33488447a05SGarrett D'Amore 	} else {	/* turn power off */
33588447a05SGarrett D'Amore 		ASSERT(level == CS4231_PWR_OFF);
33688447a05SGarrett D'Amore 		OR_SET_WORD(handle, &APC_DMACSR, APC_COD_PDWN);
33788447a05SGarrett D'Amore 	}
33888447a05SGarrett D'Amore 
33988447a05SGarrett D'Amore }	/* apc_power() */
34088447a05SGarrett D'Amore 
34188447a05SGarrett D'Amore 
34288447a05SGarrett D'Amore static void
apc_reload(CS_engine_t * eng)343*68c47f65SGarrett D'Amore apc_reload(CS_engine_t *eng)
34488447a05SGarrett D'Amore {
34588447a05SGarrett D'Amore 	CS_state_t		*state = eng->ce_state;
34688447a05SGarrett D'Amore 	ddi_acc_handle_t	handle = APC_HANDLE;
34788447a05SGarrett D'Amore 	uint32_t		dirty;
34888447a05SGarrett D'Amore 	uint32_t		*nva;	/* next VA reg */
34988447a05SGarrett D'Amore 	uint32_t		*nc;	/* next count reg */
35088447a05SGarrett D'Amore 
35188447a05SGarrett D'Amore 	if (eng->ce_num == CS4231_PLAY) {
35288447a05SGarrett D'Amore 		dirty = APC_PD;
35388447a05SGarrett D'Amore 		nva = &APC_DMAPNVA;
35488447a05SGarrett D'Amore 		nc = &APC_DMAPNC;
35588447a05SGarrett D'Amore 	} else {
35688447a05SGarrett D'Amore 		dirty = APC_CD;
35788447a05SGarrett D'Amore 		nva = &APC_DMACNVA;
35888447a05SGarrett D'Amore 		nc = &APC_DMACNC;
35988447a05SGarrett D'Amore 	}
36088447a05SGarrett D'Amore 
36188447a05SGarrett D'Amore 	/* if we can't load another address, then don't */
36288447a05SGarrett D'Amore 	if ((ddi_get32(handle, &APC_DMACSR) & dirty) == 0) {
36388447a05SGarrett D'Amore 		return;
36488447a05SGarrett D'Amore 	}
36588447a05SGarrett D'Amore 
36688447a05SGarrett D'Amore 	/* read the NVA, as per APC document */
36788447a05SGarrett D'Amore 	(void) ddi_get32(handle, nva);
36888447a05SGarrett D'Amore 
36988447a05SGarrett D'Amore 	/* write the address of the next fragment */
370*68c47f65SGarrett D'Amore 	ddi_put32(handle, nva,
371*68c47f65SGarrett D'Amore 	    eng->ce_paddr + (CS4231_FRAGSZ * eng->ce_curidx));
372*68c47f65SGarrett D'Amore 	eng->ce_curidx++;
373*68c47f65SGarrett D'Amore 	eng->ce_curidx %= CS4231_NFRAGS;
37488447a05SGarrett D'Amore 
37588447a05SGarrett D'Amore 	/* now program the NC reg., which enables the state machine */
376*68c47f65SGarrett D'Amore 	ddi_put32(handle, nc, CS4231_FRAGSZ);
377*68c47f65SGarrett D'Amore }
37888447a05SGarrett D'Amore 
379*68c47f65SGarrett D'Amore /*
380*68c47f65SGarrett D'Amore  * apc_addr()
381*68c47f65SGarrett D'Amore  *
382*68c47f65SGarrett D'Amore  * Description:
383*68c47f65SGarrett D'Amore  *	This routine returns the current DMA address for the engine (the
384*68c47f65SGarrett D'Amore  *	next address being accessed).
385*68c47f65SGarrett D'Amore  *
386*68c47f65SGarrett D'Amore  * Arguments:
387*68c47f65SGarrett D'Amore  *	CS_engine_t	*eng		The engine
388*68c47f65SGarrett D'Amore  *
389*68c47f65SGarrett D'Amore  * Returns:
390*68c47f65SGarrett D'Amore  *	Physical DMA address for current transfer.
391*68c47f65SGarrett D'Amore  */
392*68c47f65SGarrett D'Amore static uint32_t
apc_addr(CS_engine_t * eng)393*68c47f65SGarrett D'Amore apc_addr(CS_engine_t *eng)
394*68c47f65SGarrett D'Amore {
395*68c47f65SGarrett D'Amore 	CS_state_t		*state = eng->ce_state;
396*68c47f65SGarrett D'Amore 	ddi_acc_handle_t	handle = APC_HANDLE;
397*68c47f65SGarrett D'Amore 	uint32_t		*va;	/* VA reg */
398*68c47f65SGarrett D'Amore 
399*68c47f65SGarrett D'Amore 	if (eng->ce_num == CS4231_PLAY) {
400*68c47f65SGarrett D'Amore 		va = &APC_DMAPVA;
401*68c47f65SGarrett D'Amore 	} else {
402*68c47f65SGarrett D'Amore 		va = &APC_DMACVA;
403*68c47f65SGarrett D'Amore 	}
404*68c47f65SGarrett D'Amore 
405*68c47f65SGarrett D'Amore 	return (ddi_get32(handle, va));
40688447a05SGarrett D'Amore }
407