88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CDDL HEADER START
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
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 *
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 *
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 *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CDDL HEADER END
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Use is subject to license terms.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
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 */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/systm.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/ddi.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/sunddi.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/note.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/audio/audio_driver.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include "audio_4231.h"
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Attribute structure for the APC, used to create DMA handles.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic ddi_dma_attr_t apc_dma_attr = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DMA_ATTR_V0, /* version */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x0000000000000000LL, /* dlim_addr_lo */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x00000000ffffffffLL, /* dlim_addr_hi */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x0000000000000fffLL, /* DMA counter register */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x0000000000000001LL, /* DMA address alignment */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x00000014, /* 4 and 16 byte burst sizes */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x00000001, /* min effective DMA size */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x0000000000000fffLL, /* maximum transfer size, 8k */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x000000000000ffffLL, /* segment boundary, 32k */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x00000001, /* s/g list length, no s/g */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x00000001, /* granularity of device, don't care */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0 /* DMA flags */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore};
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic ddi_device_acc_attr_t acc_attr = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DDI_DEVICE_ATTR_V0,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DDI_STRUCTURE_BE_ACC,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DDI_STRICTORDER_ACC
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore};
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DMA ops vector functions
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int apc_map_regs(CS_state_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void apc_unmap_regs(CS_state_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void apc_reset(CS_state_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int apc_start_engine(CS_engine_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void apc_stop_engine(CS_engine_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void apc_power(CS_state_t *, int);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amorestatic void apc_reload(CS_engine_t *);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amorestatic uint32_t apc_addr(CS_engine_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorecs4231_dma_ops_t cs4231_apcdma_ops = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "APC DMA controller",
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore &apc_dma_attr,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore apc_map_regs,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore apc_unmap_regs,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore apc_reset,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore apc_start_engine,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore apc_stop_engine,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore apc_power,
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore apc_reload,
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore apc_addr,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore};
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * apc_map_regs()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
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 *
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 *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CS_state_t *state The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * AUDIO_SUCCESS Registers successfully mapped
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * AUDIO_FAILURE Registers not successfully mapped
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreapc_map_regs(CS_state_t *state)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_acc_handle_t *handle = &APC_HANDLE;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dev_info_t *dip = state->cs_dip;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
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 return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
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
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_SUCCESS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore} /* apc_map_regs() */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * apc_unmap_regs()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
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 *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CS_state_t *state The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreapc_unmap_regs(CS_state_t *state)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (APC_HANDLE)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_regs_map_free(&APC_HANDLE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore} /* apc_unmap_regs() */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * apc_reset()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
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 *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
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 *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreapc_reset(CS_state_t *state)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_acc_handle_t handle = APC_HANDLE;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
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 * happen.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put32(handle, &APC_DMACSR, APC_RESET);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put32(handle, &APC_DMACSR, APC_CLEAR_RESET_VALUE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore} /* apc_reset() */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * apc_start_engine()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This routine starts the DMA engine.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
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 *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * NOTE: The state structure must be locked before this routine is called.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
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 *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CS_engine_t *eng The engine to start
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_SUCCESS The DMA engine was started
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE The DMA engine was not started
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreapc_start_engine(CS_engine_t *eng)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore CS_state_t *state = eng->ce_state;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_acc_handle_t handle = APC_HANDLE;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t csr;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t enable;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t dirty;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int x;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ASSERT(mutex_owned(&state->cs_lock));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (eng->ce_num == CS4231_PLAY) {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore enable = APC_PDMA_GO;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dirty = APC_PD;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore enable = APC_CDMA_GO;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dirty = APC_CD;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* make sure it's okay to program the Next Address/Count registers */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore csr = ddi_get32(handle, &APC_DMACSR);
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 csr = ddi_get32(handle, &APC_DMACSR);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (x >= CS4231_TIMEOUT) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(state->cs_adev,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "timeout waiting for engine, not started!");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Program the first fragment.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore apc_reload(eng);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Start the DMA engine, including interrupts.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore OR_SET_WORD(handle, &APC_DMACSR, enable);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * Program the double buffering.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore apc_reload(eng);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_SUCCESS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * apc_stop_engine()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This routine stops the engine.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * The DMA engine is stopped by using the CAP_ABORT bit.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * NOTE: The state structure must be locked before this routine is called.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CS_engine_t *eng The engine to sotp
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreapc_stop_engine(CS_engine_t *eng)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore CS_state_t *state = eng->ce_state;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_acc_handle_t handle = APC_HANDLE;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t reg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t abort;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t drainbit;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t disable;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ASSERT(mutex_owned(&state->cs_lock));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (eng->ce_num == CS4231_PLAY) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore abort = APC_P_ABORT;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore drainbit = APC_PM;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore disable = APC_PLAY_DISABLE;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore abort = APC_C_ABORT;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore drainbit = APC_CX;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore disable = APC_CAP_DISABLE;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* first, abort the DMA engine */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore OR_SET_WORD(handle, &APC_DMACSR, abort);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* wait for the pipeline to empty */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore reg = ddi_get32(handle, &APC_DMACSR);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int x = 0; (!(reg & drainbit)) && (x < CS4231_TIMEOUT); x++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore drv_usecwait(1); /* don't beat on bus */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore reg = ddi_get32(handle, &APC_DMACSR);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* now clear the enable and abort bits */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore AND_SET_WORD(handle, &APC_DMACSR, ~(abort|disable));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * apc_power()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
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 *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * NOTE: The state structure must be locked when this routine is called.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
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 */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreapc_power(CS_state_t *state, int level)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_acc_handle_t handle = APC_HANDLE;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
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
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * wait for state change,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore delay(drv_usectohz(CS4231_300MS));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else { /* turn power off */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ASSERT(level == CS4231_PWR_OFF);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore OR_SET_WORD(handle, &APC_DMACSR, APC_COD_PDWN);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore} /* apc_power() */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amoreapc_reload(CS_engine_t *eng)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore CS_state_t *state = eng->ce_state;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_acc_handle_t handle = APC_HANDLE;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t dirty;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t *nva; /* next VA reg */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t *nc; /* next count reg */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (eng->ce_num == CS4231_PLAY) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dirty = APC_PD;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore nva = &APC_DMAPNVA;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore nc = &APC_DMAPNC;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dirty = APC_CD;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore nva = &APC_DMACNVA;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore nc = &APC_DMACNC;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
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 return;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* read the NVA, as per APC document */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (void) ddi_get32(handle, nva);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* write the address of the next fragment */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore ddi_put32(handle, nva,
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore eng->ce_paddr + (CS4231_FRAGSZ * eng->ce_curidx));
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore eng->ce_curidx++;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore eng->ce_curidx %= CS4231_NFRAGS;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* now program the NC reg., which enables the state machine */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore ddi_put32(handle, nc, CS4231_FRAGSZ);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore}
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore/*
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * apc_addr()
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore *
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 *
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * Arguments:
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * CS_engine_t *eng The engine
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore *
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * Returns:
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * Physical DMA address for current transfer.
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amorestatic uint32_t
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amoreapc_addr(CS_engine_t *eng)
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore{
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore CS_state_t *state = eng->ce_state;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore ddi_acc_handle_t handle = APC_HANDLE;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore uint32_t *va; /* VA reg */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore if (eng->ce_num == CS4231_PLAY) {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore va = &APC_DMAPVA;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore } else {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore va = &APC_DMACVA;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore return (ddi_get32(handle, va));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}