88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CDDL HEADER START
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * The contents of this file are subject to the terms of the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Common Development and Distribution License (the "License").
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * You may not use this file except in compliance with the License.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * or http://www.opensolaris.org/os/licensing.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * See the License for the specific language governing permissions
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * and limitations under the License.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * When distributing Covered Code, include this CDDL HEADER in each
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * If applicable, add the following below this CDDL HEADER, with the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * fields enclosed by brackets "[]" replaced with your own identifying
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * information: Portions Copyright [yyyy] [name of copyright owner]
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CDDL HEADER END
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Use is subject to license terms.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Platform specifc code for the APC DMA controller. The APC is an SBus
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * IC that includes play and record DMA engines and an interface for
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * the CS4231.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Attribute structure for the APC, used to create DMA handles.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x0000000000000fffLL, /* DMA counter register */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x0000000000000001LL, /* DMA address alignment */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x0000000000000fffLL, /* maximum transfer size, 8k */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x000000000000ffffLL, /* segment boundary, 32k */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x00000001, /* granularity of device, don't care */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0 /* DMA flags */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DMA ops vector functions
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "APC DMA controller",
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * apc_map_regs()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This routine allocates the DMA handles and the memory for the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DMA engines to use. It then binds each of the buffers to its
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * respective handle, getting a DMA cookie. Finally, the registers
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * are mapped in.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * NOTE: All of the ddi_dma_... routines sleep if they cannot get
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * memory. This means these calls will almost always succeed.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CS_state_t *state The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * AUDIO_SUCCESS Registers successfully mapped
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * AUDIO_FAILURE Registers not successfully mapped
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* map in the registers, getting a handle */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ddi_regs_map_setup(dip, 0, (caddr_t *)&state->cs_regs, 0,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore sizeof (cs4231_regs_t), &acc_attr, handle) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(state->cs_adev, "ddi_regs_map_setup() failed");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* clear the CSR so we have all interrupts disabled */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put32(*handle, &APC_DMACSR, APC_CLEAR_RESET_VALUE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore} /* apc_map_regs() */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * apc_unmap_regs()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This routine unmaps the Codec's and DMA engine's registers.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * It must be idempotent.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CS_state_t *state The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore} /* apc_unmap_regs() */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * apc_reset()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Reset both the play and record DMA engines. The engines are left
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * with interrupts and the DMA engine disabled.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * dev_info_t *dip Pointer to the device's devinfo structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CS_state_t *state The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * The APC has a bug where the reset is not done
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * until you do the next pio to the APC. This
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * next write to the CSR causes the posted reset to
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put32(handle, &APC_DMACSR, APC_CLEAR_RESET_VALUE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore} /* apc_reset() */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * apc_start_engine()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This routine starts the DMA engine.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * For hard starts the DMA engine is started by programming the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Next Virtual Address and then the Next Counter twice, and
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * finally enabling the DMA engine.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * NOTE: The state structure must be locked before this routine is called.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CAUTION: ?!? This routine doesn't start the Codec because the first
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * interrupt causes a recursive mutex_enter.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CS_engine_t *eng The engine to start
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_SUCCESS The DMA engine was started
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE The DMA engine was not started
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* make sure it's okay to program the Next Address/Count registers */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (x = 0; !(csr & dirty) && x < CS4231_TIMEOUT; x++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore drv_usecwait(1); /* no reason to beat on the bus */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "timeout waiting for engine, not started!");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Program the first fragment.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Start the DMA engine, including interrupts.
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * Program the double buffering.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * apc_stop_engine()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This routine stops the engine.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * The DMA engine is stopped by using the CAP_ABORT bit.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * NOTE: The state structure must be locked before this routine is called.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CS_engine_t *eng The engine to sotp
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* first, abort the DMA engine */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* wait for the pipeline to empty */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int x = 0; (!(reg & drainbit)) && (x < CS4231_TIMEOUT); x++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* now clear the enable and abort bits */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore AND_SET_WORD(handle, &APC_DMACSR, ~(abort|disable));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * apc_power()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This routine turns the Codec off by using the COD_PDWN bit in the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * apc chip. To turn power on we have to reset the APC, which clears
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * the COD_PDWN bit. However, this is a settling bug in the APC which
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * requires the driver to delay quite a while before we may continue.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Since this is the first time this feature has actually been used
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * it isn't too surprising that it has some problems.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * NOTE: The state structure must be locked when this routine is called.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CS_state_t *state Ptr to the device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * int level Power level to set
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (level == CS4231_PWR_ON) { /* turn power on */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore AND_SET_WORD(handle, &APC_DMACSR, ~APC_COD_PDWN);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore OR_SET_WORD(handle, &APC_DMACSR, APC_RESET);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore AND_SET_WORD(handle, &APC_DMACSR, ~APC_RESET);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * wait for state change,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else { /* turn power off */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore OR_SET_WORD(handle, &APC_DMACSR, APC_COD_PDWN);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore} /* apc_power() */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* if we can't load another address, then don't */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((ddi_get32(handle, &APC_DMACSR) & dirty) == 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* read the NVA, as per APC document */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* write the address of the next fragment */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore eng->ce_paddr + (CS4231_FRAGSZ * eng->ce_curidx));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* now program the NC reg., which enables the state machine */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * Description:
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * This routine returns the current DMA address for the engine (the
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * next address being accessed).
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * CS_engine_t *eng The engine
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * Physical DMA address for current transfer.