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/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiots Audio Driver
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This Audio Driver controls the T2 audio core in the ALI M1553
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * southbridge chip. This chip supports multiple play streams, but just
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * a single record stream. It also supports wave table synthesis and
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * hardware MIDI and joystick ports. Unfortunately the MIDI ports are
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * not available because their pins have been re-assigned to expose
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * interrupts. We also aren't going to do anything with the joystick
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * ports. The audio core controls an AC-97 V2.1 Codec.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * The DMA engine uses a single buffer which is large enough to hold
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * two interrupts worth of data. When it gets to the mid point an
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * interrupt is generated and data is either sent (for record) or
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * requested and put in that half of the buffer (for play). When the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * second half is played we do the same, but the audio core loops the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * pointer back to the beginning.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * The audio core has a bug in silicon that doesn't let it read the AC-97
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Codec's register. T2 has provided an algorithm that attempts to read the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * the Codec several times. This is probably heuristic and thus isn't
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * absolutely guaranteed to work. However we do have to place a limit on
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * the looping, otherwise when we read a valid 0x00 we would never exit
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * the loop. Unfortunately there is also a problem with writing the AC-97
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Codec's registers as well. Thus we read it back to verify the write.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * The AC'97 common code provides shadow state for AC'97 registers for us,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * so we only need to read those registers during early startup (primarily
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * to determine codec id and capabilities.)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * We don't save any of the audio controller registers during normal
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * operation. When we need to save register state we only have to save
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * the aram and eram. The rest of the controller state is never modified
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * from the initial programming. Thus restoring the controller state
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * can be done from audiots_chip_init() as well.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * WARNING: The SME birdsnest platform uses a PCI bridge chip between the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CPU and the southbridge containing the audio core. There is
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * a bug in silicon that causes a bogus parity error. With the mixer
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * reimplementation project, Bug 4374774, the audio driver is always
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * set to the best precision and number of channels. Thus when turning
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * the mixer on and off the only thing that changes is the sample rate.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This change in programming doesn't trigger the silicon error.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Thus the supported channels must always be 2 and the precision
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * must always be 16-bits. This will keep any future change in the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * mixer from exposing this bug.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Due to a hardware bug, system power management is not supported by this
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * driver.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CAUTION: If audio controller state is changed outside of aram
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * and eram then that information must be saved and restored
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * during power management shutdown and bringup.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * NOTE: The AC-97 Codec's reset pin is set to PCI reset, so we
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * can't power down the Codec all the way.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * NOTE: This driver depends on the drv/audio and misc/ac97
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * modules being loaded first.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * NOTE: Don't OR the ap_stop register to stop a play or record. This
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * will just stop all active channels because a read of ap_stop
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * returns ap_start. Just set the ap_stop register with the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * channels you want to stop. The same goes for ap_start.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * NOTE: There is a hardware problem with P2 rev motherboards. After
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * prolonged use, reading the AC97 register will always return
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * busy. The AC97 register is now useless. Consequently, we are no
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * longer able to program the Codec. This work around disables
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audio when this state is detected. It's not great, but its
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * better than having audio blasting out at 100% all the time.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * NOTE: Power Management testing has also exposed this AC97 timeout
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * problem. Management has decided this is too risky for customers
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * and hence they want power management support removed from the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audio subsystem. All PM support is now removed.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore/*
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * Synchronization notes:
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore *
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * The audio framework guarantees that our entry points are exclusive
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * with suspend and resume. This includes data flow and control entry
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * points alike.
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore *
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * The audio framework guarantees that only one control is being
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * accessed on any given audio device at a time.
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore *
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * The audio framework guarantees that entry points are themselves
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * serialized for a given engine.
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore *
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * We have no interrupt routine or other internal asynchronous routines.
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore *
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * Our device uses completely separate registers for each engine,
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * except for the start/stop registers, which are implemented in a
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * manner that allows for them to be accessed concurrently safely from
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * different threads.
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore *
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * Hence, it turns out that we simply don't need any locking in this
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * driver.
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/modctl.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/kmem.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/pci.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/ddi.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/sunddi.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/debug.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/note.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/audio/audio_driver.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include <sys/audio/ac97.h>
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore#include "audiots.h"
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Module linkage routines for the kernel
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audiots_attach(dev_info_t *, ddi_attach_cmd_t);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audiots_detach(dev_info_t *, ddi_detach_cmd_t);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audiots_quiesce(dev_info_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Entry point routine prototypes
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amorestatic int audiots_open(void *, int, unsigned *, caddr_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audiots_close(void *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audiots_start(void *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audiots_stop(void *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audiots_format(void *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audiots_channels(void *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audiots_rate(void *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audiots_chinfo(void *, int, unsigned *, unsigned *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic uint64_t audiots_count(void *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audiots_sync(void *, unsigned);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic audio_engine_ops_t audiots_engine_ops = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore AUDIO_ENGINE_VERSION,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiots_open,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiots_close,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiots_start,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiots_stop,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiots_count,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiots_format,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiots_channels,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiots_rate,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiots_sync,
f9ead4a57883f3ef04ef20d83cc47987d98c0687Garrett D'Amore NULL,
f9ead4a57883f3ef04ef20d83cc47987d98c0687Garrett D'Amore audiots_chinfo,
f9ead4a57883f3ef04ef20d83cc47987d98c0687Garrett D'Amore NULL,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore};
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Local Routine Prototypes
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audiots_power_up(audiots_state_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audiots_chip_init(audiots_state_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic uint16_t audiots_get_ac97(void *, uint8_t);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audiots_set_ac97(void *, uint8_t, uint16_t);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audiots_init_state(audiots_state_t *, dev_info_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audiots_map_regs(dev_info_t *, audiots_state_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic uint16_t audiots_read_ac97(audiots_state_t *, int);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audiots_stop_everything(audiots_state_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void audiots_destroy(audiots_state_t *);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int audiots_alloc_port(audiots_state_t *, int);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Global variables, but viewable only by this file.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/* anchor for soft state structures */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void *audiots_statep;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI Structures
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/* Device operations structure */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic struct dev_ops audiots_dev_ops = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DEVO_REV, /* devo_rev */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0, /* devo_refcnt */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore NULL, /* devo_getinfo */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore nulldev, /* devo_identify - obsolete */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore nulldev, /* devo_probe */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiots_attach, /* devo_attach */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiots_detach, /* devo_detach */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore nodev, /* devo_reset */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore NULL, /* devo_cb_ops */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore NULL, /* devo_bus_ops */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore NULL, /* devo_power */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiots_quiesce, /* devo_quiesce */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore};
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/* Linkage structure for loadable drivers */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic struct modldrv audiots_modldrv = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore &mod_driverops, /* drv_modops */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore TS_MOD_NAME, /* drv_linkinfo */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore &audiots_dev_ops /* drv_dev_ops */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore};
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/* Module linkage structure */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic struct modlinkage audiots_modlinkage = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore MODREV_1, /* ml_rev */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (void *)&audiots_modldrv, /* ml_linkage */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore NULL /* NULL terminates the list */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore};
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * NOTE: Grover OBP v4.0.166 and rev G of the ALI Southbridge chip force the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiots driver to use the upper 2 GB DMA address range. However to maintain
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * backwards compatibility with older systems/OBP, we're going to try the full
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * 4 GB DMA range.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Eventually, this will be set back to using the proper high 2 GB DMA range.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/* Device attribute structure - full 4 gig address range */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic ddi_dma_attr_t audiots_attr = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DMA_ATTR_VERSION, /* version */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x0000000000000000LL, /* dlim_addr_lo */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x00000000ffffffffLL, /* dlim_addr_hi */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x0000000000003fffLL, /* DMA counter register - 16 bits */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x0000000000000008LL, /* DMA address alignment, 64-bit */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x0000007f, /* 1 through 64 byte burst sizes */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x00000001, /* min effective DMA size */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x0000000000003fffLL, /* maximum transfer size, 16k */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 0x000000000000ffffLL, /* segment boundary, 64k */
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 ts_acc_attr = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DDI_DEVICE_ATTR_V0,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DDI_NEVERSWAP_ACC,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DDI_STRICTORDER_ACC
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore};
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic ddi_device_acc_attr_t ts_regs_attr = {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DDI_DEVICE_ATTR_V0,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DDI_STRUCTURE_LE_ACC,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DDI_STRICTORDER_ACC
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore};
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * _init()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Driver initialization, called when driver is first loaded.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This is how access is initially given to all the static structures.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * None
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * ddi_soft_state_init() status, see ddi_soft_state_init(9f), or
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * mod_install() status, see mod_install(9f)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreint
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore_init(void)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int error;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_init_ops(&audiots_dev_ops, TS_NAME);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* initialize the soft state */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((error = ddi_soft_state_init(&audiots_statep,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore sizeof (audiots_state_t), 1)) != 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_fini_ops(&audiots_dev_ops);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (error);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((error = mod_install(&audiots_modlinkage)) != 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_fini_ops(&audiots_dev_ops);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_soft_state_fini(&audiots_statep);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (error);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * _fini()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Module de-initialization, called when the driver is to be unloaded.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * None
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * mod_remove() status, see mod_remove(9f)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreint
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore_fini(void)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int error;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((error = mod_remove(&audiots_modlinkage)) != 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (error);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* free the soft state internal structures */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_soft_state_fini(&audiots_statep);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* clean up ops */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_fini_ops(&audiots_dev_ops);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * _info()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Module information, returns infomation about the driver.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * modinfo *modinfop Pointer to the opaque modinfo structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * mod_info() status, see mod_info(9f)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreint
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore_info(struct modinfo *modinfop)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int error;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore error = mod_info(&audiots_modlinkage, modinfop);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (error);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiots_attach()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Attach an instance of the audiots driver. This routine does the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * device dependent attach tasks.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * dev_info_t *dip Pointer to the device's dev_info struct
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * ddi_attach_cmd_t cmd Attach command
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_SUCCESS The driver was initialized properly
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE The driver couldn't be initialized properly
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiots_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiots_state_t *state;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int instance;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore instance = ddi_get_instance(dip);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore switch (cmd) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case DDI_ATTACH:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case DDI_RESUME:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* we've already allocated the state structure so get ptr */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore state = ddi_get_soft_state(audiots_statep, instance);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ASSERT(dip == state->ts_dip);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* suspend/resume resets the chip, so we have no more faults */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (state->ts_flags & TS_AUDIO_READ_FAILED) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_dev_report_fault(state->ts_dip,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DDI_SERVICE_RESTORED,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DDI_DEVICE_FAULT,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "check port, gain, balance, and mute settings");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* and clear the fault state flags */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore state->ts_flags &=
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ~(TS_AUDIO_READ_FAILED|TS_READ_FAILURE_PRINTED);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiots_power_up(state);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiots_chip_init(state);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore ac97_reset(state->ts_ac97);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore audio_dev_resume(state->ts_adev);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_SUCCESS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore default:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* before we do anything make sure that we haven't had a h/w failure */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ddi_get_devstate(dip) == DDI_DEVSTATE_DOWN) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore cmn_err(CE_WARN, "%s%d: The audio hardware has "
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore "been disabled.", ddi_driver_name(dip), instance);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore cmn_err(CE_CONT, "Please reboot to restore audio.");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* allocate the state structure */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ddi_soft_state_zalloc(audiots_statep, instance) == DDI_FAILURE) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore cmn_err(CE_WARN, "!%s%d: soft state allocate failed",
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore ddi_driver_name(dip), instance);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * WARNING: From here on all errors require that we free memory,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * including the state structure.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* get the state structure - cannot fail */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore state = ddi_get_soft_state(audiots_statep, instance);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ASSERT(state != NULL);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((state->ts_adev = audio_dev_alloc(dip, 0)) == NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore cmn_err(CE_WARN, "unable to allocate audio dev");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore goto error;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* map in the registers, allocate DMA buffers, etc. */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (audiots_map_regs(dip, state) == DDI_FAILURE) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(state->ts_adev, "unable to map registers");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore goto error;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* initialize the audio state structures */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (audiots_init_state(state, dip) == DDI_FAILURE) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(state->ts_adev, "init state structure failed");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore goto error;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* power up */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiots_power_up(state);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* initialize the audio controller */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiots_chip_init(state);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* initialize the AC-97 Codec */
505c7a699305ccafcfecc1ab0e7d4a25e2bfd1c2Garrett D'Amore if (ac97_init(state->ts_ac97, state->ts_adev) != 0) {
505c7a699305ccafcfecc1ab0e7d4a25e2bfd1c2Garrett D'Amore goto error;
505c7a699305ccafcfecc1ab0e7d4a25e2bfd1c2Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* put the engine interrupts into a known state -- all off */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put32(state->ts_acch, &state->ts_regs->aud_regs.ap_ainten,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore TS_ALL_DMA_OFF);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* call the framework attach routine */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (audio_dev_register(state->ts_adev) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(state->ts_adev, "unable to register audio");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore goto error;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* everything worked out, so report the device */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_report_dev(dip);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_SUCCESS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreerror:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiots_destroy(state);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiots_detach()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Detach an instance of the audiots driver.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * dev_info_t *dip Pointer to the device's dev_info struct
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * ddi_detach_cmd_t cmd Detach command
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_SUCCESS The driver was detached
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE The driver couldn't be detached
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiots_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiots_state_t *state;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int instance;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore instance = ddi_get_instance(dip);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* get the state structure */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((state = ddi_get_soft_state(audiots_statep, instance)) == NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore cmn_err(CE_WARN, "!%s%d: detach get soft state failed",
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore ddi_driver_name(dip), instance);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore switch (cmd) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case DDI_DETACH:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case DDI_SUSPEND:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore audio_dev_suspend(state->ts_adev);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* stop playing and recording */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (void) audiots_stop_everything(state);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_SUCCESS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore default:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* attempt to unregister from the framework first */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (audio_dev_unregister(state->ts_adev) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiots_destroy(state);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_SUCCESS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiots_quiesce()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Quiesce an instance of the audiots driver. Stops all DMA and
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * interrupts.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * dev_info_t *dip Pointer to the device's dev_info struct
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_SUCCESS The driver was quiesced
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_SUCCESS The driver was NOT quiesced
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiots_quiesce(dev_info_t *dip)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiots_state_t *state;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int instance;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore instance = ddi_get_instance(dip);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* get the state structure */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((state = ddi_get_soft_state(audiots_statep, instance)) == NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiots_stop_everything(state);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_SUCCESS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiots_power_up()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Ensure that the device is running in PCI power state D0.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiots_power_up(audiots_state_t *state)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_acc_handle_t pcih = state->ts_pcih;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint8_t ptr;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint16_t pmcsr;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((pci_config_get16(pcih, PCI_CONF_STAT) & PCI_STAT_CAP) == 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* does not implement PCI capabilities -- no PM */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ptr = pci_config_get8(pcih, PCI_CONF_CAP_PTR);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (;;) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ptr == PCI_CAP_NEXT_PTR_NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* PM capability not found */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (pci_config_get8(pcih, ptr + PCI_CAP_ID) == PCI_CAP_ID_PM) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* found it */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ptr = pci_config_get8(pcih, ptr + PCI_CAP_NEXT_PTR);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* if we got here, then got valid PMCSR pointer */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ptr += PCI_PMCSR;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* check to see if we are already in state D0 */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore pmcsr = pci_config_get16(pcih, ptr);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((pmcsr & PCI_PMCSR_STATE_MASK) != PCI_PMCSR_D0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* D3hot (or any other state) -> D0 */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore pmcsr &= ~PCI_PMCSR_STATE_MASK;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore pmcsr |= PCI_PMCSR_D0;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore pci_config_put16(pcih, ptr, pmcsr);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Wait for it to power up - PCI spec says 10 ms is enough.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * We double it. Note that no locks are held when this routine
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * is called, so we can sleep (we are in attach context only).
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * We do this delay even if already powerd up, just to make
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * sure we aren't seeing something that *just* transitioned
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * into D0 state.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore delay(drv_usectohz(TS_20MS));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* clear PME# flag */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore pmcsr = pci_config_get16(pcih, ptr);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore pci_config_put16(pcih, ptr, pmcsr | PCI_PMCSR_PME_STAT);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiots_chip_init()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Initialize the audio core.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiots_state_t *state The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiots_chip_init(audiots_state_t *state)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_acc_handle_t handle = state->ts_acch;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiots_regs_t *regs = state->ts_regs;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int str;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* start with all interrupts & dma channels disabled */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put32(handle, &regs->aud_regs.ap_stop, TS_ALL_DMA_ENGINES);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put32(handle, &regs->aud_regs.ap_ainten, TS_ALL_DMA_OFF);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* set global music and wave volume to 0dB */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put32(handle, &regs->aud_regs.ap_volume, 0x0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* enable end interrupts for all channels. */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put32(handle, &regs->aud_regs.ap_cir_gc, AP_CIR_GC_ENDLP_IE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* for each stream, set gain and vol settings */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (str = 0; str < TS_MAX_HW_CHANNELS; str++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Set volume to all off, 1st left and then right.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * These are never changed, so we don't have to save them.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put16(handle,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore &regs->aud_ram[str].eram.eram_gvsel_pan_vol,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (ERAM_WAVE_VOL|ERAM_PAN_LEFT|ERAM_PAN_0dB|
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ERAM_VOL_MAX_ATTEN));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put16(handle,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore &regs->aud_ram[str].eram.eram_gvsel_pan_vol,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (ERAM_WAVE_VOL|ERAM_PAN_RIGHT|ERAM_PAN_0dB|
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ERAM_VOL_MAX_ATTEN));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * The envelope engine *MUST* remain in still mode (off).
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Otherwise bad things like gain randomly disappearing might
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * happen. See bug #4332773.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put32(handle, &regs->aud_ram[str].eram.eram_ebuf1,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ERAM_EBUF_STILL);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put32(handle, &regs->aud_ram[str].eram.eram_ebuf2,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ERAM_EBUF_STILL);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* program the initial eram and aram rate */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put16(handle, &regs->aud_ram[str].aram.aram_delta,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore 1 << TS_SRC_SHIFT);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put16(handle, &regs->aud_ram[str].eram.eram_ctrl_ec,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ERAM_16_BITS | ERAM_STEREO | ERAM_LOOP_MODE |
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ERAM_SIGNED_PCM);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* program channel 31 for record */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore OR_SET_WORD(handle, &state->ts_regs->aud_regs.ap_global_control,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (AP_CLOGAL_CTRL_E_PCMIN_CH31|AP_CLOGAL_CTRL_PCM_OUT_AC97|
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore AP_CLOGAL_CTRL_MMC_FROM_MIXER|AP_CLOGAL_CTRL_PCM_OUT_TO_AC97));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* do a warm reset, which powers up the Codec */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore OR_SET_WORD(handle, &state->ts_regs->aud_regs.ap_sctrl,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore AP_SCTRL_WRST_CODEC);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore drv_usecwait(2);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore AND_SET_WORD(handle, &state->ts_regs->aud_regs.ap_sctrl,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ~AP_SCTRL_WRST_CODEC);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* do a warm reset via the Codec, yes, I'm being paranoid! */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiots_set_ac97(state, AC97_RESET_REGISTER, 0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Make sure the Codec is powered up. */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int i = TS_WAIT_CNT;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore while ((audiots_get_ac97(state, AC97_POWERDOWN_CTRL_STAT_REGISTER) &
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore PCSR_POWERD_UP) != PCSR_POWERD_UP && i--) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore drv_usecwait(1);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiots_get_ac97()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Get the value in the specified AC-97 Codec register. There is a
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * bug in silicon which forces us to do multiple reads of the Codec's
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * register. This algorithm was provided by T2 and is heuristic in
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * nature. Unfortunately we have no guarantees that the real answer
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * isn't 0x0000, which is what we get when a read fails. So we loop
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * TS_LOOP_CNT times before we give up. We just have to hope this is
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * sufficient to give us the correct value.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiots_state_t *state The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * int reg AC-97 register number
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * unsigned short The value in the specified register
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic uint16_t
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiots_get_ac97(void *arg, uint8_t reg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiots_state_t *state = arg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_acc_handle_t handle = state->ts_acch;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint16_t *data;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int count;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int delay;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint16_t first;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint16_t next;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (state->ts_revid == AC_REV_ID1) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore data = &state->ts_regs->aud_regs.ap_acrd_35D_data;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore data = &state->ts_regs->aud_regs.ap_acrdwr_data;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* make sure the register is good */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore reg &= AP_ACRD_INDEX_MASK;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (count = TS_LOOP_CNT; count--; ) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((first = audiots_read_ac97(state, reg)) != 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore next = first;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore delay = TS_DELAY_CNT;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore while (delay--) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (void) ddi_get16(handle, data);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((next = audiots_read_ac97(state, reg)) != 0) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arggg, if you let the next read happen too soon then it fails.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * 12 usec fails, 13 usec succeeds. So set it to 20 for safety.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore drv_usecwait(TS_20US);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (next);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiots_init_state()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This routine initializes the audio driver's state structure.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This includes reading the properties.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CAUTION: This routine cannot allocate resources, unless it frees
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * them before returning for an error. Also, error_destroy:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * in audiots_attach() would need to be fixed as well.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * NOTE: birdsnest supports CD ROM input. We check for the cdrom
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * property. If there we turn it on.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiots_state_t *state The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * dev_info_t *dip Pointer to the device's dev_info struct
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_SUCCESS State structure initialized
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE State structure not initialized
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiots_init_state(audiots_state_t *state, dev_info_t *dip)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore state->ts_ac97 = ac97_alloc(dip, audiots_get_ac97,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiots_set_ac97, state);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (state->ts_ac97 == NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* save the device info pointer */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore state->ts_dip = dip;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = 0; i < TS_NUM_PORTS; i++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (audiots_alloc_port(state, i) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_SUCCESS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiots_map_regs()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This routine maps the registers in.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Once the config space registers are mapped in we determine if the
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audio core may be power managed. It should, but if it doesn't,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * then trying to may cause the core to hang.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CAUTION: Make sure all errors call audio_dev_warn().
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * dev_info_t *dip Pointer to the device's devinfo
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiots_state_t *state The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_SUCCESS Registers successfully mapped
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE Registers not successfully mapped
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiots_map_regs(dev_info_t *dip, audiots_state_t *state)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore char rev[16];
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore char *name;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* map in the registers, the config and memory mapped registers */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (pci_config_setup(dip, &state->ts_pcih) != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(state->ts_adev,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "unable to map PCI configuration space");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Read the Audio Controller's vendor, device, and revision IDs */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore state->ts_devid =
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (pci_config_get16(state->ts_pcih, PCI_CONF_VENID) << 16) |
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore pci_config_get16(state->ts_pcih, PCI_CONF_DEVID);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore state->ts_revid = pci_config_get8(state->ts_pcih, PCI_CONF_REVID);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (ddi_regs_map_setup(dip, TS_MEM_MAPPED_REGS,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (caddr_t *)&state->ts_regs, 0, 0, &ts_regs_attr, &state->ts_acch) !=
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(state->ts_adev,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "unable to map PCI device registers");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore switch (state->ts_devid) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore case 0x10b95451:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore name = "ALI M5451";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore default:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore name = "audiots";
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (void) snprintf(rev, sizeof (rev), "Rev %x", state->ts_revid);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_set_description(state->ts_adev, name);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_set_version(state->ts_adev, rev);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_SUCCESS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiots_alloc_port()
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.
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 should always succeed.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * NOTE: ddi_dma_alloc_handle() attempts to use the full 4 GB DMA address
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * range. This is to work around Southbridge rev E/G OBP issues.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * (See Grover OBP note above)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * CAUTION: Make sure all errors call audio_dev_warn().
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiots_port_t *state The port structure for a device stream
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * int num The port number
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_SUCCESS DMA resources mapped
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * DDI_FAILURE DMA resources not successfully mapped
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreint
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiots_alloc_port(audiots_state_t *state, int num)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiots_port_t *port;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dev_info_t *dip = state->ts_dip;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_t *adev = state->ts_adev;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int dir;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore unsigned caps;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_dma_cookie_t cookie;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore unsigned count;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int rc;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_acc_handle_t regsh = state->ts_acch;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t *gcptr = &state->ts_regs->aud_regs.ap_cir_gc;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port = kmem_zalloc(sizeof (*port), KM_SLEEP);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore state->ts_ports[num] = port;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->tp_num = num;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->tp_state = state;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore port->tp_rate = TS_RATE;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (num == TS_INPUT_PORT) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dir = DDI_DMA_READ;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore caps = ENGINE_INPUT_CAP;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->tp_dma_stream = 31;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->tp_sync_dir = DDI_DMA_SYNC_FORKERNEL;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore dir = DDI_DMA_WRITE;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore caps = ENGINE_OUTPUT_CAP;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->tp_dma_stream = 0;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->tp_sync_dir = DDI_DMA_SYNC_FORDEV;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore port->tp_dma_mask = (1U << port->tp_dma_stream);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore port->tp_nframes = 4096;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore port->tp_size = port->tp_nframes * TS_FRAMESZ;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* allocate dma handle */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore rc = ddi_dma_alloc_handle(dip, &audiots_attr, DDI_DMA_SLEEP,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore NULL, &port->tp_dmah);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (rc != DDI_SUCCESS) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(adev, "ddi_dma_alloc_handle failed: %d", rc);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* allocate DMA buffer */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore rc = ddi_dma_mem_alloc(port->tp_dmah, port->tp_size, &ts_acc_attr,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &port->tp_kaddr,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore &port->tp_size, &port->tp_acch);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (rc == DDI_FAILURE) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(adev, "dma_mem_alloc failed");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* bind DMA buffer */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore rc = ddi_dma_addr_bind_handle(port->tp_dmah, NULL,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->tp_kaddr, port->tp_size, dir|DDI_DMA_CONSISTENT,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DDI_DMA_SLEEP, NULL, &cookie, &count);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (rc != DDI_DMA_MAPPED) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(adev,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "ddi_dma_addr_bind_handle failed: %d", rc);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ASSERT(count == 1);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->tp_paddr = cookie.dmac_address;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if ((unsigned)port->tp_paddr & 0x80000000U) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put32(regsh, gcptr,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_get32(regsh, gcptr) | AP_CIR_GC_SYS_MEM_4G_ENABLE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put32(regsh, gcptr,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_get32(regsh, gcptr) & ~(AP_CIR_GC_SYS_MEM_4G_ENABLE));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->tp_engine = audio_engine_alloc(&audiots_engine_ops, caps);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (port->tp_engine == NULL) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(adev, "audio_engine_alloc failed");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_FAILURE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_engine_set_private(port->tp_engine, port);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_add_engine(adev, port->tp_engine);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (DDI_SUCCESS);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiots_read_ac97()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This routine actually reads the AC-97 Codec's register. It may
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * be called several times to succeed.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * NOTE:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Revision M1535D B1-C of the ALI SouthBridge includes a workaround for
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * the broken busy flag. Resetting the busy flag requires a software tweak
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * to go with the worked around hardware. When we detect failure, we make
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * 10 attempts to reset the chip before we fail. This should reset the new
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * SB systems. On all SB systems, this will increse the read delay
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * slightly, but shouldn't bother it otherwise.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiots_state_t *state The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * int reg AC-97 register number
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * unsigned short The value in the specified register
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic uint16_t
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiots_read_ac97(audiots_state_t *state, int reg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_acc_handle_t acch = state->ts_acch;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint16_t *addr;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint16_t *data;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t *stimer = &state->ts_regs->aud_regs.ap_stimer;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t chk1;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint32_t chk2;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int resets = 0;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int i;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (state->ts_revid == AC_REV_ID1) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore addr = &state->ts_regs->aud_regs.ap_acrd_35D_reg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore data = &state->ts_regs->aud_regs.ap_acrd_35D_data;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore addr = &state->ts_regs->aud_regs.ap_acrdwr_reg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore data = &state->ts_regs->aud_regs.ap_acrdwr_data;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorefirst_read:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* wait for ready to send read request */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (i = 0; i < TS_READ_TRIES; i++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (!(ddi_get16(acch, addr) & AP_ACRD_R_READ_BUSY)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* don't beat on the bus */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore drv_usecwait(1);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (i >= TS_READ_TRIES) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (resets < TS_RESET_TRIES) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Attempt to reset */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore drv_usecwait(TS_20US);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put16(acch, addr, TS_SB_RESET);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore resets++;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore goto first_read;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore state->ts_flags |= TS_AUDIO_READ_FAILED;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (!(state->ts_flags & TS_READ_FAILURE_PRINTED)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_dev_report_fault(state->ts_dip,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DDI_SERVICE_LOST, DDI_DEVICE_FAULT,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "Unable to communicate with AC97 CODEC");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(state->ts_adev,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "The audio AC97 register has timed out.");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(state->ts_adev,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "Audio is now disabled.");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(state->ts_adev,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "Please reboot to restore audio.");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Don't flood the console */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore state->ts_flags |= TS_READ_FAILURE_PRINTED;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* program the register to read */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put16(acch, addr, (reg|AP_ACRD_W_PRIMARY_CODEC|
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore AP_ACRD_W_READ_MIXER_REG|AP_ACRD_W_AUDIO_READ_REQ&
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (~AP_ACWR_W_SELECT_WRITE)));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* hardware bug work around */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore chk1 = ddi_get32(acch, stimer);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore chk2 = ddi_get32(acch, stimer);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore i = TS_WAIT_CNT;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore while (chk1 == chk2 && i) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore chk2 = ddi_get32(acch, stimer);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore i--;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore OR_SET_SHORT(acch, addr, AP_ACRD_W_READ_MIXER_REG);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore resets = 0;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoresecond_read:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* wait again for read to send read request */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (i = 0; i < TS_READ_TRIES; i++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (!(ddi_get16(acch, addr) & AP_ACRD_R_READ_BUSY)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* don't beat on the bus */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore drv_usecwait(1);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (i >= TS_READ_TRIES) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (resets < TS_RESET_TRIES) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Attempt to reset */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore drv_usecwait(TS_20US);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put16(acch, addr, TS_SB_RESET);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore resets++;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore goto second_read;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore state->ts_flags |= TS_AUDIO_READ_FAILED;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (!(state->ts_flags & TS_READ_FAILURE_PRINTED)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_dev_report_fault(state->ts_dip,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore DDI_SERVICE_LOST, DDI_DEVICE_FAULT,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "Unable to communicate with AC97 CODEC");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(state->ts_adev,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "The audio AC97 register has timed out.");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(state->ts_adev,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "Audio is now disabled.");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_warn(state->ts_adev,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore "Please reboot to restore audio.");
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Don't flood the console */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore state->ts_flags |= TS_READ_FAILURE_PRINTED;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (ddi_get16(acch, data));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore} /* audiots_read_ac97() */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiots_set_ac97()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Set the value in the specified AC-97 Codec register. Just like
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * reading the AC-97 Codec, it is possible there is a problem writing
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * it as well. So we loop.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiots_state_t *state The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * int reg AC-97 register number
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * uint16_t value The value to write
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiots_set_ac97(void *arg, uint8_t reg8, uint16_t data)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiots_state_t *state = arg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_acc_handle_t handle = state->ts_acch;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint16_t *data_addr = &state->ts_regs->aud_regs.ap_acrdwr_data;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint16_t *reg_addr = &state->ts_regs->aud_regs.ap_acrdwr_reg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int count;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore int i;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint16_t tmp_short;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint16_t reg = reg8;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore reg &= AP_ACWR_INDEX_MASK;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Don't touch the reserved bits on the pre 35D+ SouthBridge */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (state->ts_revid == AC_REV_ID1) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore reg |= AP_ACWR_W_PRIMARY_CODEC|AP_ACWR_W_WRITE_MIXER_REG;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore } else {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore reg |= AP_ACWR_W_PRIMARY_CODEC|AP_ACWR_W_WRITE_MIXER_REG|
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore AP_ACWR_W_SELECT_WRITE;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (count = TS_LOOP_CNT; count--; ) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* wait for ready to write */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (i = 0; i < TS_WAIT_CNT; i++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (!(ddi_get16(handle, reg_addr) &
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore AP_ACWR_R_WRITE_BUSY)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* ready to write */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put16(handle, reg_addr, reg);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* Write the data */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put16(handle, data_addr, data);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (i >= TS_WAIT_CNT) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* try again */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore continue;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* wait for write to complete */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (i = 0; i < TS_WAIT_CNT; i++) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (!(ddi_get16(handle, reg_addr) &
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore AP_ACWR_R_WRITE_BUSY)) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* done writing */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore break;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* verify the value written */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore tmp_short = audiots_get_ac97(state, reg8);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (data == tmp_short) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore /* successfully loaded, so we can return */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore} /* audiots_set_ac97() */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiots_open()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Opens a DMA engine for use. Will also ensure the device is powered
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * up if not already done so.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The DMA engine to set up
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * int flag Open flags
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * unsigned *nframesp Receives number of frames
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * caddr_t *bufp Receives kernel data buffer
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * 0 on success
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * errno on failure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amoreaudiots_open(void *arg, int flag, unsigned *nframesp, caddr_t *bufp)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiots_port_t *port = arg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore _NOTE(ARGUNUSED(flag));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->tp_count = 0;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->tp_cso = 0;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore *nframesp = port->tp_nframes;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *bufp = port->tp_kaddr;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiots_close()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Closes an audio DMA engine that was previously opened. Since
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * nobody is using it, we could take this opportunity to possibly power
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore * down the entire device, or at least the DMA engine.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The DMA engine to shut down
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiots_close(void *arg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore _NOTE(ARGUNUSED(arg));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiots_stop()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This is called by the framework to stop a port that is
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * transferring data.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The DMA engine to stop
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiots_stop(void *arg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiots_port_t *port = arg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiots_state_t *state = port->tp_state;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore ddi_put32(state->ts_acch, &state->ts_regs->aud_regs.ap_stop,
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore port->tp_dma_mask);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiots_start()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This is called by the framework to start a port transferring data.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The DMA engine to start
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * 0 on success (never fails, errno if it did)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiots_start(void *arg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore audiots_port_t *port = arg;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore audiots_state_t *state = port->tp_state;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore ddi_acc_handle_t handle = state->ts_acch;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore audiots_regs_t *regs = state->ts_regs;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore audiots_aram_t *aram;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore audiots_eram_t *eram;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore unsigned delta;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore uint16_t ctrl;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore uint16_t gvsel;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore uint16_t eso;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore aram = &regs->aud_ram[port->tp_dma_stream].aram;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore eram = &regs->aud_ram[port->tp_dma_stream].eram;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore port->tp_cso = 0;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore gvsel = ERAM_WAVE_VOL | ERAM_PAN_0dB | ERAM_VOL_DEFAULT;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore ctrl = ERAM_16_BITS | ERAM_STEREO | ERAM_LOOP_MODE | ERAM_SIGNED_PCM;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore delta = (port->tp_rate << TS_SRC_SHIFT) / TS_RATE;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore if (port->tp_num == TS_INPUT_PORT) {
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore delta = (TS_RATE << TS_SRC_SHIFT) / port->tp_rate;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore eso = port->tp_nframes - 1;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore /* program the sample rate */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore ddi_put16(handle, &aram->aram_delta, (uint16_t)delta);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore /* program the precision, number of channels and loop mode */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore ddi_put16(handle, &eram->eram_ctrl_ec, ctrl);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore /* program the volume settings */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore ddi_put16(handle, &eram->eram_gvsel_pan_vol, gvsel);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore /* set ALPHA and FMS to 0 */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore ddi_put16(handle, &aram->aram_alpha_fms, 0x0);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore /* set CSO to 0 */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore ddi_put16(handle, &aram->aram_cso, 0x0);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore /* set LBA */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore ddi_put32(handle, &aram->aram_cptr_lba,
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore port->tp_paddr & ARAM_LBA_MASK);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore /* set ESO */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore ddi_put16(handle, &aram->aram_eso, eso);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore /* stop the DMA engines */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore ddi_put32(handle, &regs->aud_regs.ap_stop, port->tp_dma_mask);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore /* now make sure it starts playing */
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore ddi_put32(handle, &regs->aud_regs.ap_start, port->tp_dma_mask);
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (0);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiots_chinfo()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This is called by the framework to query the channel offsets
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * and ordering.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The DMA engine to query
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * int chan Channel number.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * unsigned *offset Starting offset of channel.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * unsigned *incr Increment (in samples) between frames.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * 0 indicating rate array is range instead of enumeration
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiots_chinfo(void *arg, int chan, unsigned *offset, unsigned *incr)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
807e8f10a5bd74064a2c6ed98b73c845df2f834eGarrett D'Amore _NOTE(ARGUNUSED(arg));
807e8f10a5bd74064a2c6ed98b73c845df2f834eGarrett D'Amore *offset = chan;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *incr = 2;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiots_format()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Called by the framework to query the format for the device.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The DMA engine to query
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * AUDIO_FORMAT_S16_LE.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiots_format(void *arg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore _NOTE(ARGUNUSED(arg));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (AUDIO_FORMAT_S16_LE);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiots_channels()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Called by the framework to query the channnels for the device.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The DMA engine to query
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * 2 (Stereo).
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiots_channels(void *arg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore _NOTE(ARGUNUSED(arg));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (2);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiots_rate()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Called by the framework to query the sample rates for the device.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The DMA engine to query
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Sample rate in HZ (always 48000).
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic int
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiots_rate(void *arg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiots_port_t *port = arg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (port->tp_rate);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiots_count()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This is called by the framework to get the engine's frame counter
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The DMA engine to query
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Returns:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * frame count for current engine
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic uint64_t
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiots_count(void *arg)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiots_port_t *port = arg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiots_state_t *state = port->tp_state;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore uint64_t val;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore uint16_t cso;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore unsigned n;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore cso = ddi_get16(state->ts_acch,
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore &state->ts_regs->aud_ram[port->tp_dma_stream].aram.aram_cso);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore n = (cso >= port->tp_cso) ?
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore cso - port->tp_cso :
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore cso + port->tp_nframes - port->tp_cso;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore port->tp_cso = cso;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore port->tp_count += n;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore val = port->tp_count;
68c47f65208790c466e5e484f2293d3baed71c6aGarrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return (val);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiots_sync()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This is called by the framework to synchronize DMA caches.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * void *arg The DMA engine to sync
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiots_sync(void *arg, unsigned nframes)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiots_port_t *port = arg;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore _NOTE(ARGUNUSED(nframes));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (void) ddi_dma_sync(port->tp_dmah, 0, 0, port->tp_sync_dir);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiots_stop_everything()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This routine disables the address engine interrupt for all 32 DMA
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * engines. Just to be sure, it then explicitly issues a stop command to
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * the address engine and envelope engines for all 32 channels.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * NOTE:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * There is a hardware bug that generates a spurious interrupt
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * when the DMA engines are stopped. It's not consistent - it
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * happens every 1 out of 6 stops or so. It will show up as a
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * record interrupt. The problem is that once the driver is
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * detached or if the system goes into low power mode, nobody
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * will service that interrupt. The system will eventually become
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * unusable.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiots_state_t *state The device's state structure
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorestatic void
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiots_stop_everything(audiots_state_t *state)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (state->ts_acch == NULL)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put32(state->ts_acch, &state->ts_regs->aud_regs.ap_ainten,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore TS_ALL_DMA_OFF);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put32(state->ts_acch, &state->ts_regs->aud_regs.ap_stop,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore TS_ALL_DMA_ENGINES);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_put32(state->ts_acch, &state->ts_regs->aud_regs.ap_aint,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore TS_ALL_DMA_ENGINES);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiots_free_port()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This routine unbinds the DMA cookies, frees the DMA buffers,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * deallocates the DMA handles.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiots_port_t *port The port structure for a device stream.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorevoid
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiots_free_port(audiots_port_t *port)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (port == NULL)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore return;
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (port->tp_engine) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_remove_engine(port->tp_state->ts_adev,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore port->tp_engine);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_engine_free(port->tp_engine);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (port->tp_paddr) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore (void) ddi_dma_unbind_handle(port->tp_dmah);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (port->tp_acch) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_dma_mem_free(&port->tp_acch);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (port->tp_dmah) {
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_dma_free_handle(&port->tp_dmah);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore }
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore kmem_free(port, sizeof (*port));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore/*
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiots_destroy()
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Description:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * This routine releases all resources held by the device instance,
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * as part of either detach or a failure in attach.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore *
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * Arguments:
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore * audiots_state_t *state The device soft state.
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore */
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amorevoid
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amoreaudiots_destroy(audiots_state_t *state)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore{
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiots_stop_everything(state);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore for (int i = 0; i < TS_NUM_PORTS; i++)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audiots_free_port(state->ts_ports[i]);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (state->ts_acch)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_regs_map_free(&state->ts_acch);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (state->ts_pcih)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore pci_config_teardown(&state->ts_pcih);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (state->ts_ac97)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ac97_free(state->ts_ac97);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore if (state->ts_adev)
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore audio_dev_free(state->ts_adev);
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore ddi_soft_state_free(audiots_statep, ddi_get_instance(state->ts_dip));
88447a05f537aabe9a1bc3d5313f22581ec992a7Garrett D'Amore}