audio_4231_apcdma.c revision 11936:54dc8a89ba0d
1279377Simp/*
2279377Simp * CDDL HEADER START
3279377Simp *
4279377Simp * The contents of this file are subject to the terms of the
5279377Simp * Common Development and Distribution License (the "License").
6279377Simp * You may not use this file except in compliance with the License.
7279377Simp *
8279377Simp * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9279377Simp * or http://www.opensolaris.org/os/licensing.
10279377Simp * See the License for the specific language governing permissions
11279377Simp * and limitations under the License.
12279377Simp *
13279377Simp * When distributing Covered Code, include this CDDL HEADER in each
14279377Simp * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15279377Simp * If applicable, add the following below this CDDL HEADER, with the
16279377Simp * fields enclosed by brackets "[]" replaced with your own identifying
17279377Simp * information: Portions Copyright [yyyy] [name of copyright owner]
18279377Simp *
19279377Simp * CDDL HEADER END
20279377Simp */
21279377Simp/*
22279377Simp * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23279377Simp * Use is subject to license terms.
24279377Simp */
25279377Simp
26279377Simp/*
27279377Simp * Platform specifc code for the APC DMA controller. The APC is an SBus
28279377Simp * IC that includes play and record DMA engines and an interface for
29279377Simp * the CS4231.
30279377Simp */
31279377Simp
32279377Simp#include <sys/systm.h>
33279377Simp#include <sys/ddi.h>
34279377Simp#include <sys/sunddi.h>
35279377Simp#include <sys/note.h>
36279377Simp#include <sys/audio/audio_driver.h>
37279377Simp#include "audio_4231.h"
38279377Simp
39279377Simp/*
40279377Simp * Attribute structure for the APC, used to create DMA handles.
41279377Simp */
42279377Simpstatic ddi_dma_attr_t apc_dma_attr = {
43279377Simp	DMA_ATTR_V0,			/* version */
44279377Simp	0x0000000000000000LL,		/* dlim_addr_lo */
45279377Simp	0x00000000ffffffffLL,		/* dlim_addr_hi */
46279377Simp	0x0000000000000fffLL,		/* DMA counter register */
47279377Simp	0x0000000000000001LL,		/* DMA address alignment */
48279377Simp	0x00000014,			/* 4 and 16 byte burst sizes */
49279377Simp	0x00000001,			/* min effective DMA size */
50279377Simp	0x0000000000000fffLL,		/* maximum transfer size, 8k */
51279377Simp	0x000000000000ffffLL,		/* segment boundary, 32k */
52279377Simp	0x00000001,			/* s/g list length, no s/g */
53279377Simp	0x00000001,			/* granularity of device, don't care */
54279377Simp	0				/* DMA flags */
55279377Simp};
56279377Simp
57279377Simpstatic ddi_device_acc_attr_t acc_attr = {
58279377Simp	DDI_DEVICE_ATTR_V0,
59279377Simp	DDI_STRUCTURE_BE_ACC,
60279377Simp	DDI_STRICTORDER_ACC
61279377Simp};
62279377Simp
63279377Simp/*
64279377Simp * DMA ops vector functions
65279377Simp */
66279377Simpstatic int apc_map_regs(CS_state_t *);
67279377Simpstatic void apc_unmap_regs(CS_state_t *);
68279377Simpstatic void apc_reset(CS_state_t *);
69279377Simpstatic int apc_start_engine(CS_engine_t *);
70279377Simpstatic void apc_stop_engine(CS_engine_t *);
71279377Simpstatic void apc_power(CS_state_t *, int);
72279377Simpstatic void apc_reload(CS_engine_t *);
73279377Simpstatic uint32_t apc_addr(CS_engine_t *);
74279377Simp
75279377Simpcs4231_dma_ops_t cs4231_apcdma_ops = {
76279377Simp	"APC DMA controller",
77279377Simp	&apc_dma_attr,
78279377Simp	apc_map_regs,
79279377Simp	apc_unmap_regs,
80279377Simp	apc_reset,
81279377Simp	apc_start_engine,
82279377Simp	apc_stop_engine,
83279377Simp	apc_power,
84279377Simp	apc_reload,
85279377Simp	apc_addr,
86279377Simp};
87279377Simp
88279377Simp/*
89279377Simp * apc_map_regs()
90279377Simp *
91279377Simp * Description:
92279377Simp *	This routine allocates the DMA handles and the memory for the
93279377Simp *	DMA engines to use. It then binds each of the buffers to its
94279377Simp *	respective handle, getting a DMA cookie. Finally, the registers
95279377Simp *	are mapped in.
96279377Simp *
97279377Simp *	NOTE: All of the ddi_dma_... routines sleep if they cannot get
98 *		memory. This means these calls will almost always succeed.
99 *
100 * Arguments:
101 *	CS_state_t	*state		The device's state structure
102 *
103 * Returns:
104 *	AUDIO_SUCCESS		Registers successfully mapped
105 *	AUDIO_FAILURE		Registers not successfully mapped
106 */
107static int
108apc_map_regs(CS_state_t *state)
109{
110	ddi_acc_handle_t	*handle = &APC_HANDLE;
111	dev_info_t		*dip = state->cs_dip;
112
113	/* map in the registers, getting a handle */
114	if (ddi_regs_map_setup(dip, 0, (caddr_t *)&state->cs_regs, 0,
115	    sizeof (cs4231_regs_t), &acc_attr, handle) != DDI_SUCCESS) {
116		audio_dev_warn(state->cs_adev, "ddi_regs_map_setup() failed");
117		return (DDI_FAILURE);
118	}
119
120	/* clear the CSR so we have all interrupts disabled */
121	ddi_put32(*handle, &APC_DMACSR, APC_CLEAR_RESET_VALUE);
122
123	return (DDI_SUCCESS);
124}	/* apc_map_regs() */
125
126/*
127 * apc_unmap_regs()
128 *
129 * Description:
130 *	This routine unmaps the Codec's and DMA engine's registers.
131 *	It must be idempotent.
132 *
133 * Arguments:
134 *	CS_state_t	*state	The device's state structure
135 *
136 * Returns:
137 *	void
138 */
139static void
140apc_unmap_regs(CS_state_t *state)
141{
142	if (APC_HANDLE)
143		ddi_regs_map_free(&APC_HANDLE);
144
145}	/* apc_unmap_regs() */
146
147/*
148 * apc_reset()
149 *
150 * Description:
151 *	Reset both the play and record DMA engines. The engines are left
152 *	with interrupts and the DMA engine disabled.
153 *
154 * Arguments:
155 *	dev_info_t	*dip	Pointer to the device's devinfo structure
156 *	CS_state_t	*state	The device's state structure
157 *
158 * Returns:
159 *	void
160 */
161static void
162apc_reset(CS_state_t *state)
163{
164	ddi_acc_handle_t	handle = APC_HANDLE;
165
166	/*
167	 * The APC has a bug where the reset is not done
168	 * until you do the next pio to the APC. This
169	 * next write to the CSR causes the posted reset to
170	 * happen.
171	 */
172
173	ddi_put32(handle, &APC_DMACSR, APC_RESET);
174	ddi_put32(handle, &APC_DMACSR, APC_CLEAR_RESET_VALUE);
175
176}	/* apc_reset() */
177
178/*
179 * apc_start_engine()
180 *
181 * Description:
182 *	This routine starts the DMA engine.
183 *
184 *	For hard starts the DMA engine is started by programming the
185 *	Next Virtual Address and then the Next Counter twice, and
186 *	finally enabling the DMA engine.
187 *
188 *	NOTE: The state structure must be locked before this routine is called.
189 *
190 *	CAUTION: ?!? This routine doesn't start the Codec because the first
191 *		interrupt causes a recursive mutex_enter.
192 *
193 * Arguments:
194 *	CS_engine_t	*eng	The engine to start
195 *
196 * Returns:
197 *	DDI_SUCCESS		The DMA engine was started
198 *	DDI_FAILURE		The DMA engine was not started
199 */
200static int
201apc_start_engine(CS_engine_t *eng)
202{
203	CS_state_t		*state = eng->ce_state;
204	ddi_acc_handle_t	handle = APC_HANDLE;
205	uint32_t		csr;
206	uint32_t		enable;
207	uint32_t		dirty;
208	int			x;
209
210	ASSERT(mutex_owned(&state->cs_lock));
211
212	if (eng->ce_num == CS4231_PLAY) {
213		enable = APC_PDMA_GO;
214		dirty = APC_PD;
215	} else {
216		enable = APC_CDMA_GO;
217		dirty = APC_CD;
218	}
219
220	/* make sure it's okay to program the Next Address/Count registers */
221	csr = ddi_get32(handle, &APC_DMACSR);
222	for (x = 0; !(csr & dirty) && x < CS4231_TIMEOUT; x++) {
223		drv_usecwait(1);	/* no reason to beat on the bus */
224		csr = ddi_get32(handle, &APC_DMACSR);
225	}
226	if (x >= CS4231_TIMEOUT) {
227		audio_dev_warn(state->cs_adev,
228		    "timeout waiting for engine, not started!");
229		return (DDI_FAILURE);
230	}
231
232	/*
233	 * Program the first fragment.
234	 */
235	apc_reload(eng);
236
237	/*
238	 * Start the DMA engine, including interrupts.
239	 */
240	OR_SET_WORD(handle, &APC_DMACSR, enable);
241
242	/*
243	 * Program the double buffering.
244	 */
245	apc_reload(eng);
246
247	return (DDI_SUCCESS);
248}
249
250/*
251 * apc_stop_engine()
252 *
253 * Description:
254 *	This routine stops the engine.
255 *
256 *	The DMA engine is stopped by using the CAP_ABORT bit.
257 *
258 *	NOTE: The state structure must be locked before this routine is called.
259 *
260 * Arguments:
261 *	CS_engine_t	*eng	The engine to sotp
262 *
263 * Returns:
264 *	void
265 */
266static void
267apc_stop_engine(CS_engine_t *eng)
268{
269	CS_state_t		*state = eng->ce_state;
270	ddi_acc_handle_t	handle = APC_HANDLE;
271	uint32_t		reg;
272	uint32_t		abort;
273	uint32_t		drainbit;
274	uint32_t		disable;
275
276	ASSERT(mutex_owned(&state->cs_lock));
277
278	if (eng->ce_num == CS4231_PLAY) {
279		abort = APC_P_ABORT;
280		drainbit = APC_PM;
281		disable = APC_PLAY_DISABLE;
282	} else {
283		abort = APC_C_ABORT;
284		drainbit = APC_CX;
285		disable = APC_CAP_DISABLE;
286	}
287
288	/* first, abort the DMA engine */
289	OR_SET_WORD(handle, &APC_DMACSR, abort);
290
291	/* wait for the pipeline to empty */
292	reg = ddi_get32(handle, &APC_DMACSR);
293	for (int x = 0; (!(reg & drainbit)) && (x < CS4231_TIMEOUT); x++) {
294		drv_usecwait(1);	/* don't beat on bus */
295		reg = ddi_get32(handle, &APC_DMACSR);
296	}
297
298	/* now clear the enable and abort bits */
299	AND_SET_WORD(handle, &APC_DMACSR, ~(abort|disable));
300}
301
302
303/*
304 * apc_power()
305 *
306 * Description:
307 *	This routine turns the Codec off by using the COD_PDWN bit in the
308 *	apc chip. To turn power on we have to reset the APC, which clears
309 *	the COD_PDWN bit. However, this is a settling bug in the APC which
310 *	requires the driver to delay quite a while before we may continue.
311 *	Since this is the first time this feature has actually been used
312 *	it isn't too surprising that it has some problems.
313 *
314 *	NOTE: The state structure must be locked when this routine is called.
315 *
316 * Arguments:
317 *	CS_state_t	*state		Ptr to the device's state structure
318 *	int		level		Power level to set
319 */
320static void
321apc_power(CS_state_t *state, int level)
322{
323	ddi_acc_handle_t	handle = APC_HANDLE;
324
325	if (level == CS4231_PWR_ON) {	/* turn power on */
326		AND_SET_WORD(handle, &APC_DMACSR, ~APC_COD_PDWN);
327		OR_SET_WORD(handle, &APC_DMACSR, APC_RESET);
328		AND_SET_WORD(handle, &APC_DMACSR, ~APC_RESET);
329
330		/*
331		 * wait for state change,
332		 */
333		delay(drv_usectohz(CS4231_300MS));
334	} else {	/* turn power off */
335		ASSERT(level == CS4231_PWR_OFF);
336		OR_SET_WORD(handle, &APC_DMACSR, APC_COD_PDWN);
337	}
338
339}	/* apc_power() */
340
341
342static void
343apc_reload(CS_engine_t *eng)
344{
345	CS_state_t		*state = eng->ce_state;
346	ddi_acc_handle_t	handle = APC_HANDLE;
347	uint32_t		dirty;
348	uint32_t		*nva;	/* next VA reg */
349	uint32_t		*nc;	/* next count reg */
350
351	if (eng->ce_num == CS4231_PLAY) {
352		dirty = APC_PD;
353		nva = &APC_DMAPNVA;
354		nc = &APC_DMAPNC;
355	} else {
356		dirty = APC_CD;
357		nva = &APC_DMACNVA;
358		nc = &APC_DMACNC;
359	}
360
361	/* if we can't load another address, then don't */
362	if ((ddi_get32(handle, &APC_DMACSR) & dirty) == 0) {
363		return;
364	}
365
366	/* read the NVA, as per APC document */
367	(void) ddi_get32(handle, nva);
368
369	/* write the address of the next fragment */
370	ddi_put32(handle, nva,
371	    eng->ce_paddr + (CS4231_FRAGSZ * eng->ce_curidx));
372	eng->ce_curidx++;
373	eng->ce_curidx %= CS4231_NFRAGS;
374
375	/* now program the NC reg., which enables the state machine */
376	ddi_put32(handle, nc, CS4231_FRAGSZ);
377}
378
379/*
380 * apc_addr()
381 *
382 * Description:
383 *	This routine returns the current DMA address for the engine (the
384 *	next address being accessed).
385 *
386 * Arguments:
387 *	CS_engine_t	*eng		The engine
388 *
389 * Returns:
390 *	Physical DMA address for current transfer.
391 */
392static uint32_t
393apc_addr(CS_engine_t *eng)
394{
395	CS_state_t		*state = eng->ce_state;
396	ddi_acc_handle_t	handle = APC_HANDLE;
397	uint32_t		*va;	/* VA reg */
398
399	if (eng->ce_num == CS4231_PLAY) {
400		va = &APC_DMAPVA;
401	} else {
402		va = &APC_DMACVA;
403	}
404
405	return (ddi_get32(handle, va));
406}
407