188447a05SGarrett D'Amore /*
288447a05SGarrett D'Amore * CDDL HEADER START
388447a05SGarrett D'Amore *
488447a05SGarrett D'Amore * The contents of this file are subject to the terms of the
588447a05SGarrett D'Amore * Common Development and Distribution License (the "License").
688447a05SGarrett D'Amore * You may not use this file except in compliance with the License.
788447a05SGarrett D'Amore *
888447a05SGarrett D'Amore * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
988447a05SGarrett D'Amore * or http://www.opensolaris.org/os/licensing.
1088447a05SGarrett D'Amore * See the License for the specific language governing permissions
1188447a05SGarrett D'Amore * and limitations under the License.
1288447a05SGarrett D'Amore *
1388447a05SGarrett D'Amore * When distributing Covered Code, include this CDDL HEADER in each
1488447a05SGarrett D'Amore * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1588447a05SGarrett D'Amore * If applicable, add the following below this CDDL HEADER, with the
1688447a05SGarrett D'Amore * fields enclosed by brackets "[]" replaced with your own identifying
1788447a05SGarrett D'Amore * information: Portions Copyright [yyyy] [name of copyright owner]
1888447a05SGarrett D'Amore *
1988447a05SGarrett D'Amore * CDDL HEADER END
2088447a05SGarrett D'Amore */
2188447a05SGarrett D'Amore /*
22*68c47f65SGarrett D'Amore * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
2388447a05SGarrett D'Amore * Use is subject to license terms.
2488447a05SGarrett D'Amore */
2588447a05SGarrett D'Amore
2688447a05SGarrett D'Amore
2788447a05SGarrett D'Amore /*
2888447a05SGarrett D'Amore * audio1575 Audio Driver
2988447a05SGarrett D'Amore *
3088447a05SGarrett D'Amore * The driver is primarily targeted at providing audio support for
3188447a05SGarrett D'Amore * those systems which use the Uli M1575 audio core.
3288447a05SGarrett D'Amore *
3388447a05SGarrett D'Amore * The M1575 audio core, in AC'97 controller mode, has independent
3488447a05SGarrett D'Amore * channels for PCM in, PCM out, mic in, modem in, and modem out.
3588447a05SGarrett D'Amore *
3688447a05SGarrett D'Amore * The AC'97 controller is a PCI bus master with scatter/gather
3788447a05SGarrett D'Amore * support. Each channel has a DMA engine. Currently, we use only
3888447a05SGarrett D'Amore * the PCM in and PCM out channels. Each DMA engine uses one buffer
3988447a05SGarrett D'Amore * descriptor list. And the buffer descriptor list is an array of up
4088447a05SGarrett D'Amore * to 32 entries, each of which describes a data buffer. Each entry
4188447a05SGarrett D'Amore * contains a pointer to a data buffer, control bits, and the length
4288447a05SGarrett D'Amore * of the buffer being pointed to, where the length is expressed as
4388447a05SGarrett D'Amore * the number of samples. This, combined with the 16-bit sample size,
4488447a05SGarrett D'Amore * gives the actual physical length of the buffer.
4588447a05SGarrett D'Amore *
4688447a05SGarrett D'Amore * NOTE:
4788447a05SGarrett D'Amore * This driver depends on the drv/audio, misc/ac97
4888447a05SGarrett D'Amore * modules being loaded first.
4988447a05SGarrett D'Amore */
5088447a05SGarrett D'Amore
5188447a05SGarrett D'Amore #include <sys/types.h>
5288447a05SGarrett D'Amore #include <sys/modctl.h>
5388447a05SGarrett D'Amore #include <sys/kmem.h>
5488447a05SGarrett D'Amore #include <sys/conf.h>
5588447a05SGarrett D'Amore #include <sys/ddi.h>
5688447a05SGarrett D'Amore #include <sys/sunddi.h>
5788447a05SGarrett D'Amore #include <sys/pci.h>
5888447a05SGarrett D'Amore #include <sys/note.h>
5988447a05SGarrett D'Amore #include <sys/audio/audio_driver.h>
6088447a05SGarrett D'Amore #include <sys/audio/ac97.h>
6188447a05SGarrett D'Amore #include "audio1575.h"
6288447a05SGarrett D'Amore
6388447a05SGarrett D'Amore /*
6488447a05SGarrett D'Amore * Module linkage routines for the kernel
6588447a05SGarrett D'Amore */
6688447a05SGarrett D'Amore static int audio1575_ddi_attach(dev_info_t *, ddi_attach_cmd_t);
6788447a05SGarrett D'Amore static int audio1575_ddi_detach(dev_info_t *, ddi_detach_cmd_t);
680e7a77f3SGarrett D'Amore static int audio1575_ddi_quiesce(dev_info_t *);
6988447a05SGarrett D'Amore
7088447a05SGarrett D'Amore /*
7188447a05SGarrett D'Amore * Entry point routine prototypes
7288447a05SGarrett D'Amore */
73*68c47f65SGarrett D'Amore static int audio1575_open(void *, int, unsigned *, caddr_t *);
7488447a05SGarrett D'Amore static void audio1575_close(void *);
7588447a05SGarrett D'Amore static int audio1575_start(void *);
7688447a05SGarrett D'Amore static void audio1575_stop(void *);
7788447a05SGarrett D'Amore static int audio1575_format(void *);
7888447a05SGarrett D'Amore static int audio1575_channels(void *);
7988447a05SGarrett D'Amore static int audio1575_rate(void *);
8088447a05SGarrett D'Amore static uint64_t audio1575_count(void *);
8188447a05SGarrett D'Amore static void audio1575_sync(void *, unsigned);
8288447a05SGarrett D'Amore
8388447a05SGarrett D'Amore static audio_engine_ops_t audio1575_engine_ops = {
8488447a05SGarrett D'Amore AUDIO_ENGINE_VERSION,
8588447a05SGarrett D'Amore audio1575_open,
8688447a05SGarrett D'Amore audio1575_close,
8788447a05SGarrett D'Amore audio1575_start,
8888447a05SGarrett D'Amore audio1575_stop,
8988447a05SGarrett D'Amore audio1575_count,
9088447a05SGarrett D'Amore audio1575_format,
9188447a05SGarrett D'Amore audio1575_channels,
9288447a05SGarrett D'Amore audio1575_rate,
9388447a05SGarrett D'Amore audio1575_sync,
94f9ead4a5SGarrett D'Amore NULL,
95f9ead4a5SGarrett D'Amore NULL,
96f9ead4a5SGarrett D'Amore NULL
9788447a05SGarrett D'Amore };
9888447a05SGarrett D'Amore
9988447a05SGarrett D'Amore /*
10088447a05SGarrett D'Amore * Local Routine Prototypes
10188447a05SGarrett D'Amore */
10288447a05SGarrett D'Amore static int audio1575_attach(dev_info_t *);
10388447a05SGarrett D'Amore static int audio1575_resume(dev_info_t *);
10488447a05SGarrett D'Amore static int audio1575_detach(dev_info_t *);
10588447a05SGarrett D'Amore static int audio1575_suspend(dev_info_t *);
10688447a05SGarrett D'Amore
1070e7a77f3SGarrett D'Amore static int audio1575_alloc_port(audio1575_state_t *, int, uint8_t);
10888447a05SGarrett D'Amore static void audio1575_free_port(audio1575_port_t *);
10988447a05SGarrett D'Amore
11088447a05SGarrett D'Amore static int audio1575_codec_sync(audio1575_state_t *);
11188447a05SGarrett D'Amore static void audio1575_write_ac97(void *, uint8_t, uint16_t);
11288447a05SGarrett D'Amore static uint16_t audio1575_read_ac97(void *, uint8_t);
11388447a05SGarrett D'Amore static int audio1575_chip_init(audio1575_state_t *);
11488447a05SGarrett D'Amore static int audio1575_map_regs(audio1575_state_t *);
11588447a05SGarrett D'Amore static void audio1575_unmap_regs(audio1575_state_t *);
1160e7a77f3SGarrett D'Amore static void audio1575_dma_stop(audio1575_state_t *, boolean_t);
11788447a05SGarrett D'Amore static void audio1575_pci_enable(audio1575_state_t *);
11888447a05SGarrett D'Amore static void audio1575_pci_disable(audio1575_state_t *);
11988447a05SGarrett D'Amore
12088447a05SGarrett D'Amore static void audio1575_destroy(audio1575_state_t *);
12188447a05SGarrett D'Amore
12288447a05SGarrett D'Amore /*
12388447a05SGarrett D'Amore * Global variables, but used only by this file.
12488447a05SGarrett D'Amore */
12588447a05SGarrett D'Amore
12688447a05SGarrett D'Amore /*
12788447a05SGarrett D'Amore * DDI Structures
12888447a05SGarrett D'Amore */
12988447a05SGarrett D'Amore
13088447a05SGarrett D'Amore
13188447a05SGarrett D'Amore /* Device operations structure */
13288447a05SGarrett D'Amore static struct dev_ops audio1575_dev_ops = {
13388447a05SGarrett D'Amore DEVO_REV, /* devo_rev */
13488447a05SGarrett D'Amore 0, /* devo_refcnt */
13588447a05SGarrett D'Amore NULL, /* devo_getinfo */
13688447a05SGarrett D'Amore nulldev, /* devo_identify - obsolete */
13788447a05SGarrett D'Amore nulldev, /* devo_probe */
13888447a05SGarrett D'Amore audio1575_ddi_attach, /* devo_attach */
13988447a05SGarrett D'Amore audio1575_ddi_detach, /* devo_detach */
14088447a05SGarrett D'Amore nodev, /* devo_reset */
14188447a05SGarrett D'Amore NULL, /* devi_cb_ops */
14288447a05SGarrett D'Amore NULL, /* devo_bus_ops */
14388447a05SGarrett D'Amore NULL, /* devo_power */
1440e7a77f3SGarrett D'Amore audio1575_ddi_quiesce, /* devo_quiesce */
14588447a05SGarrett D'Amore };
14688447a05SGarrett D'Amore
14788447a05SGarrett D'Amore /* Linkage structure for loadable drivers */
14888447a05SGarrett D'Amore static struct modldrv audio1575_modldrv = {
14988447a05SGarrett D'Amore &mod_driverops, /* drv_modops */
15088447a05SGarrett D'Amore M1575_MOD_NAME, /* drv_linkinfo */
15188447a05SGarrett D'Amore &audio1575_dev_ops, /* drv_dev_ops */
15288447a05SGarrett D'Amore };
15388447a05SGarrett D'Amore
15488447a05SGarrett D'Amore /* Module linkage structure */
15588447a05SGarrett D'Amore static struct modlinkage audio1575_modlinkage = {
15688447a05SGarrett D'Amore MODREV_1, /* ml_rev */
15788447a05SGarrett D'Amore (void *)&audio1575_modldrv, /* ml_linkage */
15888447a05SGarrett D'Amore NULL /* NULL terminates the list */
15988447a05SGarrett D'Amore };
16088447a05SGarrett D'Amore
16188447a05SGarrett D'Amore
16288447a05SGarrett D'Amore /*
16388447a05SGarrett D'Amore * device access attributes for register mapping
16488447a05SGarrett D'Amore */
16588447a05SGarrett D'Amore static struct ddi_device_acc_attr dev_attr = {
16688447a05SGarrett D'Amore DDI_DEVICE_ATTR_V0,
16788447a05SGarrett D'Amore DDI_STRUCTURE_LE_ACC,
16888447a05SGarrett D'Amore DDI_STRICTORDER_ACC
16988447a05SGarrett D'Amore };
17088447a05SGarrett D'Amore
17188447a05SGarrett D'Amore static struct ddi_device_acc_attr buf_attr = {
17288447a05SGarrett D'Amore DDI_DEVICE_ATTR_V0,
17388447a05SGarrett D'Amore DDI_NEVERSWAP_ACC,
17488447a05SGarrett D'Amore DDI_STRICTORDER_ACC
17588447a05SGarrett D'Amore };
17688447a05SGarrett D'Amore
17788447a05SGarrett D'Amore /*
17888447a05SGarrett D'Amore * DMA attributes of buffer descriptor list
17988447a05SGarrett D'Amore */
18088447a05SGarrett D'Amore static ddi_dma_attr_t bdlist_dma_attr = {
18188447a05SGarrett D'Amore DMA_ATTR_V0, /* version */
18288447a05SGarrett D'Amore 0x0000000000000000LL, /* dlim_addr_lo */
18388447a05SGarrett D'Amore 0x00000000ffffffffLL, /* dlim_addr_hi */
18488447a05SGarrett D'Amore 0x000000000000ffffLL, /* DMA counter register - 64 bits */
18588447a05SGarrett D'Amore 0x0000000000000008LL, /* DMA address align must be 8-bytes */
18688447a05SGarrett D'Amore 0x0000003c, /* 1 through 64 byte burst sizes */
18788447a05SGarrett D'Amore 0x00000008, /* min xfer DMA size BDList entry */
18888447a05SGarrett D'Amore 0x00000000000ffffLL, /* max xfer size, 64K */
18988447a05SGarrett D'Amore 0x000000000001fffLL, /* seg, set to PAGESIZE */
19088447a05SGarrett D'Amore 0x00000001, /* s/g list length, no s/g */
19188447a05SGarrett D'Amore 0x00000008, /* granularity of device minxfer */
19288447a05SGarrett D'Amore 0 /* DMA flags use virtual address */
19388447a05SGarrett D'Amore };
19488447a05SGarrett D'Amore
19588447a05SGarrett D'Amore /*
19688447a05SGarrett D'Amore * DMA attributes of buffers to be used to receive/send audio data
19788447a05SGarrett D'Amore */
19888447a05SGarrett D'Amore static ddi_dma_attr_t sample_buf_dma_attr = {
19988447a05SGarrett D'Amore DMA_ATTR_V0,
20088447a05SGarrett D'Amore 0x0000000000000000LL, /* dlim_addr_lo */
20188447a05SGarrett D'Amore 0x00000000ffffffffLL, /* dlim_addr_hi */
20288447a05SGarrett D'Amore 0x000000000001fffeLL, /* DMA counter register - 16 bits */
20388447a05SGarrett D'Amore 0x0000000000000004LL, /* DMA address align 2-byte boundary */
20488447a05SGarrett D'Amore 0x0000003c, /* 1 through 60 byte burst sizes */
20588447a05SGarrett D'Amore 0x00000004, /* min xfer DMA size BDList entry */
20688447a05SGarrett D'Amore 0x000000000001ffffLL, /* max xfer size, 64K */
20788447a05SGarrett D'Amore 0x000000000001ffffLL, /* seg, set to 64K */
20888447a05SGarrett D'Amore 0x00000001, /* s/g list length, no s/g */
20988447a05SGarrett D'Amore 0x00000004, /* granularity of device minxfer */
21088447a05SGarrett D'Amore 0 /* DMA flags use virtual address */
21188447a05SGarrett D'Amore };
21288447a05SGarrett D'Amore
21388447a05SGarrett D'Amore /*
21488447a05SGarrett D'Amore * _init()
21588447a05SGarrett D'Amore *
21688447a05SGarrett D'Amore * Description:
21788447a05SGarrett D'Amore * Driver initialization, called when driver is first loaded.
21888447a05SGarrett D'Amore * This is how access is initially given to all the static structures.
21988447a05SGarrett D'Amore *
22088447a05SGarrett D'Amore * Arguments:
22188447a05SGarrett D'Amore * None
22288447a05SGarrett D'Amore *
22388447a05SGarrett D'Amore * Returns:
22488447a05SGarrett D'Amore * mod_install() status, see mod_install(9f)
22588447a05SGarrett D'Amore */
22688447a05SGarrett D'Amore int
_init(void)22788447a05SGarrett D'Amore _init(void)
22888447a05SGarrett D'Amore {
22988447a05SGarrett D'Amore int error;
23088447a05SGarrett D'Amore
23188447a05SGarrett D'Amore audio_init_ops(&audio1575_dev_ops, M1575_NAME);
23288447a05SGarrett D'Amore
23388447a05SGarrett D'Amore if ((error = mod_install(&audio1575_modlinkage)) != 0) {
23488447a05SGarrett D'Amore audio_fini_ops(&audio1575_dev_ops);
23588447a05SGarrett D'Amore }
23688447a05SGarrett D'Amore
23788447a05SGarrett D'Amore return (error);
23888447a05SGarrett D'Amore }
23988447a05SGarrett D'Amore
24088447a05SGarrett D'Amore /*
24188447a05SGarrett D'Amore * _fini()
24288447a05SGarrett D'Amore *
24388447a05SGarrett D'Amore * Description:
24488447a05SGarrett D'Amore * Module de-initialization, called when the driver is to be unloaded.
24588447a05SGarrett D'Amore *
24688447a05SGarrett D'Amore * Arguments:
24788447a05SGarrett D'Amore * None
24888447a05SGarrett D'Amore *
24988447a05SGarrett D'Amore * Returns:
25088447a05SGarrett D'Amore * mod_remove() status, see mod_remove(9f)
25188447a05SGarrett D'Amore */
25288447a05SGarrett D'Amore int
_fini(void)25388447a05SGarrett D'Amore _fini(void)
25488447a05SGarrett D'Amore {
25588447a05SGarrett D'Amore int error;
25688447a05SGarrett D'Amore
25788447a05SGarrett D'Amore if ((error = mod_remove(&audio1575_modlinkage)) != 0) {
25888447a05SGarrett D'Amore return (error);
25988447a05SGarrett D'Amore }
26088447a05SGarrett D'Amore
26188447a05SGarrett D'Amore /* clean up ops */
26288447a05SGarrett D'Amore audio_fini_ops(&audio1575_dev_ops);
26388447a05SGarrett D'Amore
26488447a05SGarrett D'Amore return (0);
26588447a05SGarrett D'Amore }
26688447a05SGarrett D'Amore
26788447a05SGarrett D'Amore /*
26888447a05SGarrett D'Amore * _info()
26988447a05SGarrett D'Amore *
27088447a05SGarrett D'Amore * Description:
27188447a05SGarrett D'Amore * Module information, returns information about the driver.
27288447a05SGarrett D'Amore *
27388447a05SGarrett D'Amore * Arguments:
27488447a05SGarrett D'Amore * modinfo *modinfop Pointer to the opaque modinfo structure
27588447a05SGarrett D'Amore *
27688447a05SGarrett D'Amore * Returns:
27788447a05SGarrett D'Amore * mod_info() status, see mod_info(9f)
27888447a05SGarrett D'Amore */
27988447a05SGarrett D'Amore int
_info(struct modinfo * modinfop)28088447a05SGarrett D'Amore _info(struct modinfo *modinfop)
28188447a05SGarrett D'Amore {
28288447a05SGarrett D'Amore return (mod_info(&audio1575_modlinkage, modinfop));
28388447a05SGarrett D'Amore }
28488447a05SGarrett D'Amore
28588447a05SGarrett D'Amore
28688447a05SGarrett D'Amore /* ******************* Driver Entry Points ********************************* */
28788447a05SGarrett D'Amore
28888447a05SGarrett D'Amore /*
28988447a05SGarrett D'Amore * audio1575_ddi_attach()
29088447a05SGarrett D'Amore *
29188447a05SGarrett D'Amore * Description:
29288447a05SGarrett D'Amore * Implements the DDI attach(9e) entry point.
29388447a05SGarrett D'Amore *
29488447a05SGarrett D'Amore * Arguments:
29588447a05SGarrett D'Amore * dev_info_t *dip Pointer to the device's dev_info struct
29688447a05SGarrett D'Amore * ddi_attach_cmd_t cmd Attach command
29788447a05SGarrett D'Amore *
29888447a05SGarrett D'Amore * Returns:
29988447a05SGarrett D'Amore * DDI_SUCCESS The driver was initialized properly
30088447a05SGarrett D'Amore * DDI_FAILURE The driver couldn't be initialized properly
30188447a05SGarrett D'Amore */
30288447a05SGarrett D'Amore static int
audio1575_ddi_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)30388447a05SGarrett D'Amore audio1575_ddi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
30488447a05SGarrett D'Amore {
30588447a05SGarrett D'Amore switch (cmd) {
30688447a05SGarrett D'Amore case DDI_ATTACH:
30788447a05SGarrett D'Amore return (audio1575_attach(dip));
30888447a05SGarrett D'Amore
30988447a05SGarrett D'Amore case DDI_RESUME:
31088447a05SGarrett D'Amore return (audio1575_resume(dip));
31188447a05SGarrett D'Amore }
31288447a05SGarrett D'Amore return (DDI_FAILURE);
31388447a05SGarrett D'Amore }
31488447a05SGarrett D'Amore
31588447a05SGarrett D'Amore /*
31688447a05SGarrett D'Amore * audio1575_ddi_detach()
31788447a05SGarrett D'Amore *
31888447a05SGarrett D'Amore * Description:
31988447a05SGarrett D'Amore * Implements the detach(9e) entry point.
32088447a05SGarrett D'Amore *
32188447a05SGarrett D'Amore * Arguments:
32288447a05SGarrett D'Amore * dev_info_t *dip Pointer to the device's dev_info struct
32388447a05SGarrett D'Amore * ddi_detach_cmd_t cmd Detach command
32488447a05SGarrett D'Amore *
32588447a05SGarrett D'Amore * Returns:
32688447a05SGarrett D'Amore * DDI_SUCCESS The driver was detached
32788447a05SGarrett D'Amore * DDI_FAILURE The driver couldn't be detached
32888447a05SGarrett D'Amore */
32988447a05SGarrett D'Amore static int
audio1575_ddi_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)33088447a05SGarrett D'Amore audio1575_ddi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
33188447a05SGarrett D'Amore {
33288447a05SGarrett D'Amore switch (cmd) {
33388447a05SGarrett D'Amore case DDI_DETACH:
33488447a05SGarrett D'Amore return (audio1575_detach(dip));
33588447a05SGarrett D'Amore
33688447a05SGarrett D'Amore case DDI_SUSPEND:
33788447a05SGarrett D'Amore return (audio1575_suspend(dip));
33888447a05SGarrett D'Amore }
33988447a05SGarrett D'Amore return (DDI_FAILURE);
34088447a05SGarrett D'Amore }
34188447a05SGarrett D'Amore
3420e7a77f3SGarrett D'Amore /*
3430e7a77f3SGarrett D'Amore * audio1575_ddi_quiesce()
3440e7a77f3SGarrett D'Amore *
3450e7a77f3SGarrett D'Amore * Description:
3460e7a77f3SGarrett D'Amore * Implements the quiesce(9e) entry point.
3470e7a77f3SGarrett D'Amore *
3480e7a77f3SGarrett D'Amore * Arguments:
3490e7a77f3SGarrett D'Amore * dev_info_t *dip Pointer to the device's dev_info struct
3500e7a77f3SGarrett D'Amore *
3510e7a77f3SGarrett D'Amore * Returns:
3520e7a77f3SGarrett D'Amore * DDI_SUCCESS The driver was quiesced
3530e7a77f3SGarrett D'Amore * DDI_FAILURE The driver couldn't be quiesced
3540e7a77f3SGarrett D'Amore */
3550e7a77f3SGarrett D'Amore static int
audio1575_ddi_quiesce(dev_info_t * dip)3560e7a77f3SGarrett D'Amore audio1575_ddi_quiesce(dev_info_t *dip)
3570e7a77f3SGarrett D'Amore {
3580e7a77f3SGarrett D'Amore audio1575_state_t *statep;
3590e7a77f3SGarrett D'Amore
3600e7a77f3SGarrett D'Amore if ((statep = ddi_get_driver_private(dip)) == NULL)
3610e7a77f3SGarrett D'Amore return (DDI_FAILURE);
3620e7a77f3SGarrett D'Amore
3630e7a77f3SGarrett D'Amore audio1575_dma_stop(statep, B_TRUE);
3640e7a77f3SGarrett D'Amore return (DDI_SUCCESS);
3650e7a77f3SGarrett D'Amore }
3660e7a77f3SGarrett D'Amore
36788447a05SGarrett D'Amore /*
36888447a05SGarrett D'Amore * audio1575_open()
36988447a05SGarrett D'Amore *
37088447a05SGarrett D'Amore * Description:
37188447a05SGarrett D'Amore * Opens a DMA engine for use.
37288447a05SGarrett D'Amore *
37388447a05SGarrett D'Amore * Arguments:
37488447a05SGarrett D'Amore * void *arg The DMA engine to set up
37588447a05SGarrett D'Amore * int flag Open flags
376*68c47f65SGarrett D'Amore * unsigned *nframesp Receives number of frames
37788447a05SGarrett D'Amore * caddr_t *bufp Receives kernel data buffer
37888447a05SGarrett D'Amore *
37988447a05SGarrett D'Amore * Returns:
38088447a05SGarrett D'Amore * 0 on success
38188447a05SGarrett D'Amore * errno on failure
38288447a05SGarrett D'Amore */
38388447a05SGarrett D'Amore static int
audio1575_open(void * arg,int flag,unsigned * nframesp,caddr_t * bufp)384*68c47f65SGarrett D'Amore audio1575_open(void *arg, int flag, unsigned *nframesp, caddr_t *bufp)
38588447a05SGarrett D'Amore {
38688447a05SGarrett D'Amore audio1575_port_t *port = arg;
38788447a05SGarrett D'Amore
38888447a05SGarrett D'Amore _NOTE(ARGUNUSED(flag));
38988447a05SGarrett D'Amore
39088447a05SGarrett D'Amore port->count = 0;
391*68c47f65SGarrett D'Amore *nframesp = port->nframes;
39288447a05SGarrett D'Amore *bufp = port->samp_kaddr;
39388447a05SGarrett D'Amore
39488447a05SGarrett D'Amore return (0);
39588447a05SGarrett D'Amore }
39688447a05SGarrett D'Amore
39788447a05SGarrett D'Amore
39888447a05SGarrett D'Amore /*
39988447a05SGarrett D'Amore * audio1575_close()
40088447a05SGarrett D'Amore *
40188447a05SGarrett D'Amore * Description:
40288447a05SGarrett D'Amore * Closes an audio DMA engine that was previously opened. Since
40388447a05SGarrett D'Amore * nobody is using it, we take this opportunity to possibly power
40488447a05SGarrett D'Amore * down the entire device.
40588447a05SGarrett D'Amore *
40688447a05SGarrett D'Amore * Arguments:
40788447a05SGarrett D'Amore * void *arg The DMA engine to shut down
40888447a05SGarrett D'Amore */
40988447a05SGarrett D'Amore static void
audio1575_close(void * arg)41088447a05SGarrett D'Amore audio1575_close(void *arg)
41188447a05SGarrett D'Amore {
412*68c47f65SGarrett D'Amore _NOTE(ARGUNUSED(arg));
41388447a05SGarrett D'Amore }
41488447a05SGarrett D'Amore
41588447a05SGarrett D'Amore /*
41688447a05SGarrett D'Amore * audio1575_stop()
41788447a05SGarrett D'Amore *
41888447a05SGarrett D'Amore * Description:
41988447a05SGarrett D'Amore * This is called by the framework to stop a port that is
42088447a05SGarrett D'Amore * transferring data.
42188447a05SGarrett D'Amore *
42288447a05SGarrett D'Amore * Arguments:
42388447a05SGarrett D'Amore * void *arg The DMA engine to stop
42488447a05SGarrett D'Amore */
42588447a05SGarrett D'Amore static void
audio1575_stop(void * arg)42688447a05SGarrett D'Amore audio1575_stop(void *arg)
42788447a05SGarrett D'Amore {
42888447a05SGarrett D'Amore audio1575_port_t *port = arg;
42988447a05SGarrett D'Amore audio1575_state_t *statep = port->statep;
43088447a05SGarrett D'Amore
43188447a05SGarrett D'Amore mutex_enter(&statep->lock);
432*68c47f65SGarrett D'Amore if (port->num == M1575_REC) {
433*68c47f65SGarrett D'Amore SET32(M1575_DMACR_REG, M1575_DMACR_PCMIPAUSE);
434*68c47f65SGarrett D'Amore } else {
435*68c47f65SGarrett D'Amore SET32(M1575_DMACR_REG, M1575_DMACR_PCMOPAUSE);
43688447a05SGarrett D'Amore }
43788447a05SGarrett D'Amore mutex_exit(&statep->lock);
43888447a05SGarrett D'Amore }
43988447a05SGarrett D'Amore
44088447a05SGarrett D'Amore /*
44188447a05SGarrett D'Amore * audio1575_start()
44288447a05SGarrett D'Amore *
44388447a05SGarrett D'Amore * Description:
44488447a05SGarrett D'Amore * This is called by the framework to start a port transferring data.
44588447a05SGarrett D'Amore *
44688447a05SGarrett D'Amore * Arguments:
44788447a05SGarrett D'Amore * void *arg The DMA engine to start
44888447a05SGarrett D'Amore *
44988447a05SGarrett D'Amore * Returns:
45088447a05SGarrett D'Amore * 0 on success (never fails, errno if it did)
45188447a05SGarrett D'Amore */
45288447a05SGarrett D'Amore static int
audio1575_start(void * arg)45388447a05SGarrett D'Amore audio1575_start(void *arg)
45488447a05SGarrett D'Amore {
45588447a05SGarrett D'Amore audio1575_port_t *port = arg;
45688447a05SGarrett D'Amore audio1575_state_t *statep = port->statep;
45788447a05SGarrett D'Amore
45888447a05SGarrett D'Amore mutex_enter(&statep->lock);
459*68c47f65SGarrett D'Amore
460*68c47f65SGarrett D'Amore port->offset = 0;
461*68c47f65SGarrett D'Amore
462*68c47f65SGarrett D'Amore if (port->num == M1575_REC) {
463*68c47f65SGarrett D'Amore /* Uli FIFO madness ... */
464*68c47f65SGarrett D'Amore SET32(M1575_FIFOCR1_REG, M1575_FIFOCR1_PCMIRST);
465*68c47f65SGarrett D'Amore SET32(M1575_DMACR_REG, M1575_DMACR_PCMIPAUSE);
466*68c47f65SGarrett D'Amore
467*68c47f65SGarrett D'Amore PUT8(M1575_PCMICR_REG, 0);
468*68c47f65SGarrett D'Amore PUT8(M1575_PCMICR_REG, M1575_CR_RR);
469*68c47f65SGarrett D'Amore
470*68c47f65SGarrett D'Amore PUT32(M1575_PCMIBDBAR_REG, port->bdl_paddr);
471*68c47f65SGarrett D'Amore PUT8(M1575_PCMILVIV_REG, M1575_BD_NUMS - 1);
472*68c47f65SGarrett D'Amore
473*68c47f65SGarrett D'Amore CLR32(M1575_DMACR_REG, M1575_DMACR_PCMIPAUSE);
474*68c47f65SGarrett D'Amore
475*68c47f65SGarrett D'Amore /* ULi says do fifo resets here */
476*68c47f65SGarrett D'Amore SET32(M1575_FIFOCR1_REG, M1575_FIFOCR1_PCMIRST);
477*68c47f65SGarrett D'Amore CLR32(M1575_DMACR_REG, M1575_DMACR_PCMIPAUSE);
478*68c47f65SGarrett D'Amore PUT8(M1575_PCMICR_REG, 0);
479*68c47f65SGarrett D'Amore SET32(M1575_DMACR_REG, M1575_DMACR_PCMISTART);
480*68c47f65SGarrett D'Amore
481*68c47f65SGarrett D'Amore } else {
482*68c47f65SGarrett D'Amore
483*68c47f65SGarrett D'Amore uint32_t scr;
484*68c47f65SGarrett D'Amore
485*68c47f65SGarrett D'Amore /* Uli FIFO madness ... */
486*68c47f65SGarrett D'Amore SET32(M1575_FIFOCR1_REG, M1575_FIFOCR1_PCMORST);
487*68c47f65SGarrett D'Amore SET32(M1575_DMACR_REG, M1575_DMACR_PCMOPAUSE);
488*68c47f65SGarrett D'Amore
489*68c47f65SGarrett D'Amore /* configure the number of channels properly */
490*68c47f65SGarrett D'Amore scr = GET32(M1575_SCR_REG);
491*68c47f65SGarrett D'Amore scr &= ~(M1575_SCR_6CHL_MASK | M1575_SCR_CHAMOD_MASK);
492*68c47f65SGarrett D'Amore scr |= M1575_SCR_6CHL_2; /* select our proper ordering */
493*68c47f65SGarrett D'Amore switch (port->nchan) {
494*68c47f65SGarrett D'Amore case 2:
495*68c47f65SGarrett D'Amore scr |= M1575_SCR_CHAMOD_2;
496*68c47f65SGarrett D'Amore break;
497*68c47f65SGarrett D'Amore case 4:
498*68c47f65SGarrett D'Amore scr |= M1575_SCR_CHAMOD_4;
499*68c47f65SGarrett D'Amore break;
500*68c47f65SGarrett D'Amore case 6:
501*68c47f65SGarrett D'Amore scr |= M1575_SCR_CHAMOD_6;
502*68c47f65SGarrett D'Amore break;
503*68c47f65SGarrett D'Amore }
504*68c47f65SGarrett D'Amore PUT32(M1575_SCR_REG, scr);
505*68c47f65SGarrett D'Amore
506*68c47f65SGarrett D'Amore PUT8(M1575_PCMOCR_REG, 0);
507*68c47f65SGarrett D'Amore PUT8(M1575_PCMOCR_REG, M1575_CR_RR);
508*68c47f65SGarrett D'Amore
509*68c47f65SGarrett D'Amore PUT32(M1575_PCMOBDBAR_REG, port->bdl_paddr);
510*68c47f65SGarrett D'Amore PUT8(M1575_PCMOLVIV_REG, M1575_BD_NUMS - 1);
511*68c47f65SGarrett D'Amore
512*68c47f65SGarrett D'Amore CLR32(M1575_DMACR_REG, M1575_DMACR_PCMOPAUSE);
513*68c47f65SGarrett D'Amore PUT8(M1575_PCMOCR_REG, 0);
514*68c47f65SGarrett D'Amore SET32(M1575_DMACR_REG, M1575_DMACR_PCMOSTART);
51588447a05SGarrett D'Amore }
516*68c47f65SGarrett D'Amore
51788447a05SGarrett D'Amore mutex_exit(&statep->lock);
51888447a05SGarrett D'Amore return (0);
51988447a05SGarrett D'Amore }
52088447a05SGarrett D'Amore
521*68c47f65SGarrett D'Amore
522*68c47f65SGarrett D'Amore
52388447a05SGarrett D'Amore /*
52488447a05SGarrett D'Amore * audio1575_format()
52588447a05SGarrett D'Amore *
52688447a05SGarrett D'Amore * Description:
52788447a05SGarrett D'Amore * Called by the framework to query the format for the device.
52888447a05SGarrett D'Amore *
52988447a05SGarrett D'Amore * Arguments:
53088447a05SGarrett D'Amore * void *arg The DMA engine to query
53188447a05SGarrett D'Amore *
53288447a05SGarrett D'Amore * Returns:
53388447a05SGarrett D'Amore * AUDIO_FORMAT_S16_LE
53488447a05SGarrett D'Amore */
53588447a05SGarrett D'Amore static int
audio1575_format(void * arg)53688447a05SGarrett D'Amore audio1575_format(void *arg)
53788447a05SGarrett D'Amore {
53888447a05SGarrett D'Amore _NOTE(ARGUNUSED(arg));
53988447a05SGarrett D'Amore
54088447a05SGarrett D'Amore return (AUDIO_FORMAT_S16_LE);
54188447a05SGarrett D'Amore }
54288447a05SGarrett D'Amore
54388447a05SGarrett D'Amore /*
54488447a05SGarrett D'Amore * audio1575_channels()
54588447a05SGarrett D'Amore *
54688447a05SGarrett D'Amore * Description:
54788447a05SGarrett D'Amore * Called by the framework to query the channels for the device.
54888447a05SGarrett D'Amore *
54988447a05SGarrett D'Amore * Arguments:
55088447a05SGarrett D'Amore * void *arg The DMA engine to query
55188447a05SGarrett D'Amore *
55288447a05SGarrett D'Amore * Returns:
55388447a05SGarrett D'Amore * Number of channels for the device
55488447a05SGarrett D'Amore */
55588447a05SGarrett D'Amore static int
audio1575_channels(void * arg)55688447a05SGarrett D'Amore audio1575_channels(void *arg)
55788447a05SGarrett D'Amore {
55888447a05SGarrett D'Amore audio1575_port_t *port = arg;
55988447a05SGarrett D'Amore
56088447a05SGarrett D'Amore return (port->nchan);
56188447a05SGarrett D'Amore }
56288447a05SGarrett D'Amore
56388447a05SGarrett D'Amore /*
56488447a05SGarrett D'Amore * audio1575_rate()
56588447a05SGarrett D'Amore *
56688447a05SGarrett D'Amore * Description:
56788447a05SGarrett D'Amore * Called by the framework to query the sample rate for the device.
56888447a05SGarrett D'Amore *
56988447a05SGarrett D'Amore * Arguments:
57088447a05SGarrett D'Amore * void *arg The DMA engine to query
57188447a05SGarrett D'Amore *
57288447a05SGarrett D'Amore * Returns:
57388447a05SGarrett D'Amore * 48000
57488447a05SGarrett D'Amore */
57588447a05SGarrett D'Amore static int
audio1575_rate(void * arg)57688447a05SGarrett D'Amore audio1575_rate(void *arg)
57788447a05SGarrett D'Amore {
57888447a05SGarrett D'Amore _NOTE(ARGUNUSED(arg));
57988447a05SGarrett D'Amore
58088447a05SGarrett D'Amore return (48000);
58188447a05SGarrett D'Amore }
58288447a05SGarrett D'Amore
58388447a05SGarrett D'Amore /*
58488447a05SGarrett D'Amore * audio1575_count()
58588447a05SGarrett D'Amore *
58688447a05SGarrett D'Amore * Description:
58788447a05SGarrett D'Amore * This is called by the framework to get the engine's frame counter
58888447a05SGarrett D'Amore *
58988447a05SGarrett D'Amore * Arguments:
59088447a05SGarrett D'Amore * void *arg The DMA engine to query
59188447a05SGarrett D'Amore *
59288447a05SGarrett D'Amore * Returns:
59388447a05SGarrett D'Amore * frame count for current engine
59488447a05SGarrett D'Amore */
59588447a05SGarrett D'Amore static uint64_t
audio1575_count(void * arg)59688447a05SGarrett D'Amore audio1575_count(void *arg)
59788447a05SGarrett D'Amore {
59888447a05SGarrett D'Amore audio1575_port_t *port = arg;
59988447a05SGarrett D'Amore audio1575_state_t *statep = port->statep;
60088447a05SGarrett D'Amore uint64_t val;
601*68c47f65SGarrett D'Amore uint8_t civ;
602*68c47f65SGarrett D'Amore unsigned n;
603*68c47f65SGarrett D'Amore int civoff;
604*68c47f65SGarrett D'Amore int lvioff;
605*68c47f65SGarrett D'Amore int picoff;
60688447a05SGarrett D'Amore
60788447a05SGarrett D'Amore mutex_enter(&statep->lock);
608*68c47f65SGarrett D'Amore
609*68c47f65SGarrett D'Amore if (port->num == M1575_REC) {
610*68c47f65SGarrett D'Amore civoff = M1575_PCMICIV_REG;
611*68c47f65SGarrett D'Amore lvioff = M1575_PCMILVIV_REG;
612*68c47f65SGarrett D'Amore picoff = M1575_PCMIPICB_REG;
613*68c47f65SGarrett D'Amore } else {
614*68c47f65SGarrett D'Amore civoff = M1575_PCMOCIV_REG;
615*68c47f65SGarrett D'Amore lvioff = M1575_PCMOLVIV_REG;
616*68c47f65SGarrett D'Amore picoff = M1575_PCMOPICB_REG;
617*68c47f65SGarrett D'Amore }
618*68c47f65SGarrett D'Amore
619*68c47f65SGarrett D'Amore /*
620*68c47f65SGarrett D'Amore * Read the position counters. We also take this opportunity
621*68c47f65SGarrett D'Amore * to update the last valid index to the one just previous to
622*68c47f65SGarrett D'Amore * the one we're working on (so we'll fully loop.)
623*68c47f65SGarrett D'Amore */
624*68c47f65SGarrett D'Amore n = GET16(picoff);
625*68c47f65SGarrett D'Amore civ = GET8(civoff);
626*68c47f65SGarrett D'Amore PUT8(lvioff, (civ - 1) % M1575_BD_NUMS);
627*68c47f65SGarrett D'Amore
628*68c47f65SGarrett D'Amore n = port->samp_size - (n * sizeof (int16_t));
629*68c47f65SGarrett D'Amore if (n < port->offset) {
630*68c47f65SGarrett D'Amore val = (port->samp_size - port->offset) + n;
631*68c47f65SGarrett D'Amore } else {
632*68c47f65SGarrett D'Amore val = n - port->offset;
633*68c47f65SGarrett D'Amore }
634*68c47f65SGarrett D'Amore port->offset = n;
635*68c47f65SGarrett D'Amore port->count += (val / (port->nchan * sizeof (int16_t)));
636*68c47f65SGarrett D'Amore val = port->count;
63788447a05SGarrett D'Amore mutex_exit(&statep->lock);
63888447a05SGarrett D'Amore
63988447a05SGarrett D'Amore return (val);
64088447a05SGarrett D'Amore }
64188447a05SGarrett D'Amore
64288447a05SGarrett D'Amore /*
64388447a05SGarrett D'Amore * audio1575_sync()
64488447a05SGarrett D'Amore *
64588447a05SGarrett D'Amore * Description:
64688447a05SGarrett D'Amore * This is called by the framework to synchronize DMA caches.
64788447a05SGarrett D'Amore *
64888447a05SGarrett D'Amore * Arguments:
64988447a05SGarrett D'Amore * void *arg The DMA engine to sync
65088447a05SGarrett D'Amore */
65188447a05SGarrett D'Amore static void
audio1575_sync(void * arg,unsigned nframes)65288447a05SGarrett D'Amore audio1575_sync(void *arg, unsigned nframes)
65388447a05SGarrett D'Amore {
65488447a05SGarrett D'Amore audio1575_port_t *port = arg;
65588447a05SGarrett D'Amore _NOTE(ARGUNUSED(nframes));
65688447a05SGarrett D'Amore
65788447a05SGarrett D'Amore (void) ddi_dma_sync(port->samp_dmah, 0, 0, port->sync_dir);
65888447a05SGarrett D'Amore }
65988447a05SGarrett D'Amore
66088447a05SGarrett D'Amore /*
66188447a05SGarrett D'Amore * audio1575_attach()
66288447a05SGarrett D'Amore *
66388447a05SGarrett D'Amore * Description:
66488447a05SGarrett D'Amore * Attach an instance of the audio1575 driver. This routine does the
66588447a05SGarrett D'Amore * device dependent attach tasks. When it is completed, it registers
66688447a05SGarrett D'Amore * with the audio framework.
66788447a05SGarrett D'Amore *
66888447a05SGarrett D'Amore * Arguments:
66988447a05SGarrett D'Amore * dev_info_t *dip Pointer to the device's dev_info struct
67088447a05SGarrett D'Amore *
67188447a05SGarrett D'Amore * Returns:
67288447a05SGarrett D'Amore * DDI_SUCCESS The driver was initialized properly
67388447a05SGarrett D'Amore * DDI_FAILURE The driver couldn't be initialized properly
67488447a05SGarrett D'Amore */
67588447a05SGarrett D'Amore static int
audio1575_attach(dev_info_t * dip)67688447a05SGarrett D'Amore audio1575_attach(dev_info_t *dip)
67788447a05SGarrett D'Amore {
67888447a05SGarrett D'Amore audio1575_state_t *statep;
67988447a05SGarrett D'Amore audio_dev_t *adev;
68088447a05SGarrett D'Amore uint32_t devid;
68188447a05SGarrett D'Amore const char *name;
68288447a05SGarrett D'Amore const char *rev;
6830e7a77f3SGarrett D'Amore int maxch;
68488447a05SGarrett D'Amore
68588447a05SGarrett D'Amore /* allocate the soft state structure */
68688447a05SGarrett D'Amore statep = kmem_zalloc(sizeof (*statep), KM_SLEEP);
68788447a05SGarrett D'Amore ddi_set_driver_private(dip, statep);
68888447a05SGarrett D'Amore statep->dip = dip;
68988447a05SGarrett D'Amore
69088447a05SGarrett D'Amore /*
69188447a05SGarrett D'Amore * We want the micboost enabled by default as well.
69288447a05SGarrett D'Amore */
693cf6aa9d8SGarrett D'Amore (void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, AC97_PROP_MICBOOST, 1);
69488447a05SGarrett D'Amore
69588447a05SGarrett D'Amore /* allocate common audio dev structure */
69688447a05SGarrett D'Amore adev = audio_dev_alloc(dip, 0);
69788447a05SGarrett D'Amore if (adev == NULL) {
69888447a05SGarrett D'Amore audio_dev_warn(NULL, "unable to allocate audio dev");
69988447a05SGarrett D'Amore goto error;
70088447a05SGarrett D'Amore }
70188447a05SGarrett D'Amore statep->adev = adev;
70288447a05SGarrett D'Amore
70388447a05SGarrett D'Amore /* map in the audio registers */
70488447a05SGarrett D'Amore if (audio1575_map_regs(statep) != DDI_SUCCESS) {
70588447a05SGarrett D'Amore audio_dev_warn(adev, "couldn't map registers");
70688447a05SGarrett D'Amore goto error;
70788447a05SGarrett D'Amore }
70888447a05SGarrett D'Amore
70988447a05SGarrett D'Amore /* Enable PCI I/O and Memory Spaces */
71088447a05SGarrett D'Amore audio1575_pci_enable(statep);
71188447a05SGarrett D'Amore
71288447a05SGarrett D'Amore devid = (pci_config_get16(statep->pcih, PCI_CONF_VENID) << 16) |
71388447a05SGarrett D'Amore pci_config_get16(statep->pcih, PCI_CONF_DEVID);
71488447a05SGarrett D'Amore switch (devid) {
71588447a05SGarrett D'Amore case 0x10b95455:
71688447a05SGarrett D'Amore name = "Uli M1575 AC'97";
71788447a05SGarrett D'Amore rev = "M5455";
71888447a05SGarrett D'Amore break;
71988447a05SGarrett D'Amore default:
72088447a05SGarrett D'Amore name = "Uli AC'97";
72188447a05SGarrett D'Amore rev = "Unknown";
72288447a05SGarrett D'Amore break;
72388447a05SGarrett D'Amore }
72488447a05SGarrett D'Amore /* set device information -- this should check PCI config space */
72588447a05SGarrett D'Amore audio_dev_set_description(adev, name);
72688447a05SGarrett D'Amore audio_dev_set_version(adev, rev);
72788447a05SGarrett D'Amore
7280e7a77f3SGarrett D'Amore statep->ac97 = ac97_alloc(dip, audio1575_read_ac97,
7290e7a77f3SGarrett D'Amore audio1575_write_ac97, statep);
7300e7a77f3SGarrett D'Amore ASSERT(statep->ac97 != NULL);
7310e7a77f3SGarrett D'Amore
7320e7a77f3SGarrett D'Amore /*
7330e7a77f3SGarrett D'Amore * Override "max-channels" property to prevent configuration
7340e7a77f3SGarrett D'Amore * of 4 or 6 (or possibly even 8!) channel audio. The default
7350e7a77f3SGarrett D'Amore * is to support as many channels as the hardware can do.
7360e7a77f3SGarrett D'Amore */
7370e7a77f3SGarrett D'Amore maxch = ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
7380e7a77f3SGarrett D'Amore "max-channels", ac97_num_channels(statep->ac97));
7390e7a77f3SGarrett D'Amore if (maxch < 2) {
7400e7a77f3SGarrett D'Amore maxch = 2;
7410e7a77f3SGarrett D'Amore }
7420e7a77f3SGarrett D'Amore
7430e7a77f3SGarrett D'Amore statep->maxch = min(maxch, 6) & ~1;
74488447a05SGarrett D'Amore
74588447a05SGarrett D'Amore /* allocate port structures */
7460e7a77f3SGarrett D'Amore if ((audio1575_alloc_port(statep, M1575_PLAY, statep->maxch) !=
7470e7a77f3SGarrett D'Amore DDI_SUCCESS) ||
7480e7a77f3SGarrett D'Amore (audio1575_alloc_port(statep, M1575_REC, 2) != DDI_SUCCESS)) {
74988447a05SGarrett D'Amore goto error;
75088447a05SGarrett D'Amore }
75188447a05SGarrett D'Amore
75288447a05SGarrett D'Amore if (audio1575_chip_init(statep) != DDI_SUCCESS) {
75388447a05SGarrett D'Amore audio_dev_warn(adev, "failed to init chip");
75488447a05SGarrett D'Amore goto error;
75588447a05SGarrett D'Amore }
75688447a05SGarrett D'Amore
75788447a05SGarrett D'Amore if (ac97_init(statep->ac97, adev) != DDI_SUCCESS) {
75888447a05SGarrett D'Amore audio_dev_warn(adev, "ac'97 initialization failed");
75988447a05SGarrett D'Amore goto error;
76088447a05SGarrett D'Amore }
76188447a05SGarrett D'Amore
76288447a05SGarrett D'Amore /* register with the framework */
76388447a05SGarrett D'Amore if (audio_dev_register(adev) != DDI_SUCCESS) {
76488447a05SGarrett D'Amore audio_dev_warn(adev, "unable to register with framework");
76588447a05SGarrett D'Amore goto error;
76688447a05SGarrett D'Amore }
76788447a05SGarrett D'Amore
76888447a05SGarrett D'Amore /* everything worked out, so report the device */
76988447a05SGarrett D'Amore ddi_report_dev(dip);
77088447a05SGarrett D'Amore
77188447a05SGarrett D'Amore return (DDI_SUCCESS);
77288447a05SGarrett D'Amore
77388447a05SGarrett D'Amore error:
77488447a05SGarrett D'Amore audio1575_destroy(statep);
77588447a05SGarrett D'Amore return (DDI_FAILURE);
77688447a05SGarrett D'Amore }
77788447a05SGarrett D'Amore
77888447a05SGarrett D'Amore /*
77988447a05SGarrett D'Amore * audio1575_detach()
78088447a05SGarrett D'Amore *
78188447a05SGarrett D'Amore * Description:
78288447a05SGarrett D'Amore * Detach an instance of the audio1575 driver.
78388447a05SGarrett D'Amore *
78488447a05SGarrett D'Amore * Arguments:
78588447a05SGarrett D'Amore * dev_info_t *dip Pointer to the device's dev_info struct
78688447a05SGarrett D'Amore *
78788447a05SGarrett D'Amore * Returns:
78888447a05SGarrett D'Amore * DDI_SUCCESS The driver was detached
78988447a05SGarrett D'Amore * DDI_FAILURE The driver couldn't be detached
79088447a05SGarrett D'Amore */
79188447a05SGarrett D'Amore static int
audio1575_detach(dev_info_t * dip)79288447a05SGarrett D'Amore audio1575_detach(dev_info_t *dip)
79388447a05SGarrett D'Amore {
79488447a05SGarrett D'Amore audio1575_state_t *statep;
79588447a05SGarrett D'Amore
79688447a05SGarrett D'Amore statep = ddi_get_driver_private(dip);
79788447a05SGarrett D'Amore
79888447a05SGarrett D'Amore if (audio_dev_unregister(statep->adev) != DDI_SUCCESS) {
79988447a05SGarrett D'Amore return (DDI_FAILURE);
80088447a05SGarrett D'Amore }
80188447a05SGarrett D'Amore
80288447a05SGarrett D'Amore audio1575_destroy(statep);
80388447a05SGarrett D'Amore return (DDI_SUCCESS);
80488447a05SGarrett D'Amore }
80588447a05SGarrett D'Amore
80688447a05SGarrett D'Amore /* *********************** Local Routines *************************** */
80788447a05SGarrett D'Amore
80888447a05SGarrett D'Amore /*
80988447a05SGarrett D'Amore * audio1575_alloc_port()
81088447a05SGarrett D'Amore *
81188447a05SGarrett D'Amore * Description:
81288447a05SGarrett D'Amore * This routine allocates the DMA handles and the memory for the
81388447a05SGarrett D'Amore * DMA engines to use. It also configures the BDL lists properly
81488447a05SGarrett D'Amore * for use.
81588447a05SGarrett D'Amore *
81688447a05SGarrett D'Amore * Arguments:
81788447a05SGarrett D'Amore * dev_info_t *dip Pointer to the device's devinfo
8180e7a77f3SGarrett D'Amore * int num M1575_PLAY or M1575_REC
8190e7a77f3SGarrett D'Amore * uint8_t nchan Number of channels (2 = stereo, 6 = 5.1, etc.)
82088447a05SGarrett D'Amore *
82188447a05SGarrett D'Amore * Returns:
82288447a05SGarrett D'Amore * DDI_SUCCESS Registers successfully mapped
82388447a05SGarrett D'Amore * DDI_FAILURE Registers not successfully mapped
82488447a05SGarrett D'Amore */
82588447a05SGarrett D'Amore static int
audio1575_alloc_port(audio1575_state_t * statep,int num,uint8_t nchan)8260e7a77f3SGarrett D'Amore audio1575_alloc_port(audio1575_state_t *statep, int num, uint8_t nchan)
82788447a05SGarrett D'Amore {
82888447a05SGarrett D'Amore ddi_dma_cookie_t cookie;
82988447a05SGarrett D'Amore uint_t count;
83088447a05SGarrett D'Amore int dir;
83188447a05SGarrett D'Amore unsigned caps;
83288447a05SGarrett D'Amore audio_dev_t *adev;
83388447a05SGarrett D'Amore audio1575_port_t *port;
83488447a05SGarrett D'Amore uint32_t *kaddr;
83588447a05SGarrett D'Amore int rc;
83688447a05SGarrett D'Amore dev_info_t *dip;
83788447a05SGarrett D'Amore
83888447a05SGarrett D'Amore adev = statep->adev;
83988447a05SGarrett D'Amore dip = statep->dip;
84088447a05SGarrett D'Amore
84188447a05SGarrett D'Amore port = kmem_zalloc(sizeof (*port), KM_SLEEP);
84288447a05SGarrett D'Amore statep->ports[num] = port;
84388447a05SGarrett D'Amore port->num = num;
84488447a05SGarrett D'Amore port->statep = statep;
8450e7a77f3SGarrett D'Amore port->nchan = nchan;
84688447a05SGarrett D'Amore
84788447a05SGarrett D'Amore if (num == M1575_REC) {
84888447a05SGarrett D'Amore dir = DDI_DMA_READ;
84988447a05SGarrett D'Amore caps = ENGINE_INPUT_CAP;
85088447a05SGarrett D'Amore port->sync_dir = DDI_DMA_SYNC_FORKERNEL;
85188447a05SGarrett D'Amore } else {
85288447a05SGarrett D'Amore dir = DDI_DMA_WRITE;
85388447a05SGarrett D'Amore caps = ENGINE_OUTPUT_CAP;
85488447a05SGarrett D'Amore port->sync_dir = DDI_DMA_SYNC_FORDEV;
85588447a05SGarrett D'Amore }
85688447a05SGarrett D'Amore
85788447a05SGarrett D'Amore /*
858*68c47f65SGarrett D'Amore * We use one big sample area. The sample area must be larger
859*68c47f65SGarrett D'Amore * than about 1.5 framework fragment sizes. (Currently 480 *
860*68c47f65SGarrett D'Amore * 1.5 = 720 frames.) This is necessary to ensure that we
861*68c47f65SGarrett D'Amore * don't have to involve an interrupt service routine on our
862*68c47f65SGarrett D'Amore * own, to keep the last valid index updated reasonably.
86388447a05SGarrett D'Amore */
864*68c47f65SGarrett D'Amore port->nframes = 2048;
865*68c47f65SGarrett D'Amore port->samp_size = port->nframes * port->nchan * sizeof (int16_t);
86688447a05SGarrett D'Amore
86788447a05SGarrett D'Amore /* allocate dma handle */
86888447a05SGarrett D'Amore rc = ddi_dma_alloc_handle(dip, &sample_buf_dma_attr, DDI_DMA_SLEEP,
86988447a05SGarrett D'Amore NULL, &port->samp_dmah);
87088447a05SGarrett D'Amore if (rc != DDI_SUCCESS) {
87188447a05SGarrett D'Amore audio_dev_warn(adev, "ddi_dma_alloc_handle failed: %d", rc);
87288447a05SGarrett D'Amore return (DDI_FAILURE);
87388447a05SGarrett D'Amore }
87488447a05SGarrett D'Amore /* allocate DMA buffer */
87588447a05SGarrett D'Amore rc = ddi_dma_mem_alloc(port->samp_dmah, port->samp_size, &buf_attr,
87688447a05SGarrett D'Amore DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &port->samp_kaddr,
87788447a05SGarrett D'Amore &port->samp_size, &port->samp_acch);
87888447a05SGarrett D'Amore if (rc == DDI_FAILURE) {
87988447a05SGarrett D'Amore audio_dev_warn(adev, "dma_mem_alloc failed");
88088447a05SGarrett D'Amore return (DDI_FAILURE);
88188447a05SGarrett D'Amore }
88288447a05SGarrett D'Amore
88388447a05SGarrett D'Amore /* bind DMA buffer */
88488447a05SGarrett D'Amore rc = ddi_dma_addr_bind_handle(port->samp_dmah, NULL,
88588447a05SGarrett D'Amore port->samp_kaddr, port->samp_size, dir|DDI_DMA_CONSISTENT,
88688447a05SGarrett D'Amore DDI_DMA_SLEEP, NULL, &cookie, &count);
88788447a05SGarrett D'Amore if ((rc != DDI_DMA_MAPPED) || (count != 1)) {
88888447a05SGarrett D'Amore audio_dev_warn(adev,
88988447a05SGarrett D'Amore "ddi_dma_addr_bind_handle failed: %d", rc);
89088447a05SGarrett D'Amore return (DDI_FAILURE);
89188447a05SGarrett D'Amore }
89288447a05SGarrett D'Amore port->samp_paddr = cookie.dmac_address;
89388447a05SGarrett D'Amore
89488447a05SGarrett D'Amore /*
89588447a05SGarrett D'Amore * now, from here we allocate DMA memory for buffer descriptor list.
89688447a05SGarrett D'Amore * we allocate adjacent DMA memory for all DMA engines.
89788447a05SGarrett D'Amore */
89888447a05SGarrett D'Amore rc = ddi_dma_alloc_handle(dip, &bdlist_dma_attr, DDI_DMA_SLEEP,
89988447a05SGarrett D'Amore NULL, &port->bdl_dmah);
90088447a05SGarrett D'Amore if (rc != DDI_SUCCESS) {
90188447a05SGarrett D'Amore audio_dev_warn(adev, "ddi_dma_alloc_handle(bdlist) failed");
90288447a05SGarrett D'Amore return (DDI_FAILURE);
90388447a05SGarrett D'Amore }
90488447a05SGarrett D'Amore
90588447a05SGarrett D'Amore /*
90688447a05SGarrett D'Amore * we allocate all buffer descriptors lists in continuous dma memory.
90788447a05SGarrett D'Amore */
90888447a05SGarrett D'Amore port->bdl_size = sizeof (m1575_bd_entry_t) * M1575_BD_NUMS;
90988447a05SGarrett D'Amore rc = ddi_dma_mem_alloc(port->bdl_dmah, port->bdl_size,
91088447a05SGarrett D'Amore &dev_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
91188447a05SGarrett D'Amore &port->bdl_kaddr, &port->bdl_size, &port->bdl_acch);
91288447a05SGarrett D'Amore if (rc != DDI_SUCCESS) {
91388447a05SGarrett D'Amore audio_dev_warn(adev, "ddi_dma_mem_alloc(bdlist) failed");
91488447a05SGarrett D'Amore return (DDI_FAILURE);
91588447a05SGarrett D'Amore }
91688447a05SGarrett D'Amore
91788447a05SGarrett D'Amore /*
91888447a05SGarrett D'Amore * Wire up the BD list. We do this *before* binding the BD list
91988447a05SGarrett D'Amore * so that we don't have to do an extra ddi_dma_sync.
92088447a05SGarrett D'Amore */
92188447a05SGarrett D'Amore kaddr = (void *)port->bdl_kaddr;
92288447a05SGarrett D'Amore for (int i = 0; i < M1575_BD_NUMS; i++) {
92388447a05SGarrett D'Amore
92488447a05SGarrett D'Amore /* set base address of buffer */
925*68c47f65SGarrett D'Amore ddi_put32(port->bdl_acch, kaddr, port->samp_paddr);
92688447a05SGarrett D'Amore kaddr++;
92788447a05SGarrett D'Amore
92888447a05SGarrett D'Amore /* set size in frames, and enable IOC interrupt */
92988447a05SGarrett D'Amore ddi_put32(port->bdl_acch, kaddr,
930*68c47f65SGarrett D'Amore ((port->samp_size / sizeof (int16_t)) | (1U << 31)));
93188447a05SGarrett D'Amore kaddr++;
93288447a05SGarrett D'Amore }
93388447a05SGarrett D'Amore
93488447a05SGarrett D'Amore rc = ddi_dma_addr_bind_handle(port->bdl_dmah, NULL, port->bdl_kaddr,
93588447a05SGarrett D'Amore port->bdl_size, DDI_DMA_WRITE|DDI_DMA_CONSISTENT, DDI_DMA_SLEEP,
93688447a05SGarrett D'Amore NULL, &cookie, &count);
93788447a05SGarrett D'Amore if ((rc != DDI_DMA_MAPPED) || (count != 1)) {
93888447a05SGarrett D'Amore audio_dev_warn(adev, "addr_bind_handle failed");
93988447a05SGarrett D'Amore return (DDI_FAILURE);
94088447a05SGarrett D'Amore }
94188447a05SGarrett D'Amore port->bdl_paddr = cookie.dmac_address;
94288447a05SGarrett D'Amore
94388447a05SGarrett D'Amore port->engine = audio_engine_alloc(&audio1575_engine_ops, caps);
94488447a05SGarrett D'Amore if (port->engine == NULL) {
94588447a05SGarrett D'Amore audio_dev_warn(adev, "audio_engine_alloc failed");
94688447a05SGarrett D'Amore return (DDI_FAILURE);
94788447a05SGarrett D'Amore }
94888447a05SGarrett D'Amore
94988447a05SGarrett D'Amore audio_engine_set_private(port->engine, port);
95088447a05SGarrett D'Amore audio_dev_add_engine(adev, port->engine);
95188447a05SGarrett D'Amore
95288447a05SGarrett D'Amore return (DDI_SUCCESS);
95388447a05SGarrett D'Amore }
95488447a05SGarrett D'Amore
95588447a05SGarrett D'Amore /*
95688447a05SGarrett D'Amore * audio1575_free_port()
95788447a05SGarrett D'Amore *
95888447a05SGarrett D'Amore * Description:
95988447a05SGarrett D'Amore * This routine unbinds the DMA cookies, frees the DMA buffers,
96088447a05SGarrett D'Amore * deallocates the DMA handles.
96188447a05SGarrett D'Amore *
96288447a05SGarrett D'Amore * Arguments:
963*68c47f65SGarrett D'Amore * audio1575_port_t *port The port structure for a DMA engine.
96488447a05SGarrett D'Amore */
96588447a05SGarrett D'Amore static void
audio1575_free_port(audio1575_port_t * port)96688447a05SGarrett D'Amore audio1575_free_port(audio1575_port_t *port)
96788447a05SGarrett D'Amore {
96888447a05SGarrett D'Amore if (port == NULL)
96988447a05SGarrett D'Amore return;
97088447a05SGarrett D'Amore
97188447a05SGarrett D'Amore if (port->engine) {
97288447a05SGarrett D'Amore audio_dev_remove_engine(port->statep->adev, port->engine);
97388447a05SGarrett D'Amore audio_engine_free(port->engine);
97488447a05SGarrett D'Amore }
97588447a05SGarrett D'Amore if (port->bdl_paddr) {
97688447a05SGarrett D'Amore (void) ddi_dma_unbind_handle(port->bdl_dmah);
97788447a05SGarrett D'Amore }
97888447a05SGarrett D'Amore if (port->bdl_acch) {
97988447a05SGarrett D'Amore ddi_dma_mem_free(&port->bdl_acch);
98088447a05SGarrett D'Amore }
98188447a05SGarrett D'Amore if (port->bdl_dmah) {
98288447a05SGarrett D'Amore ddi_dma_free_handle(&port->bdl_dmah);
98388447a05SGarrett D'Amore }
98488447a05SGarrett D'Amore if (port->samp_paddr) {
98588447a05SGarrett D'Amore (void) ddi_dma_unbind_handle(port->samp_dmah);
98688447a05SGarrett D'Amore }
98788447a05SGarrett D'Amore if (port->samp_acch) {
98888447a05SGarrett D'Amore ddi_dma_mem_free(&port->samp_acch);
98988447a05SGarrett D'Amore }
99088447a05SGarrett D'Amore if (port->samp_dmah) {
99188447a05SGarrett D'Amore ddi_dma_free_handle(&port->samp_dmah);
99288447a05SGarrett D'Amore }
99388447a05SGarrett D'Amore kmem_free(port, sizeof (*port));
99488447a05SGarrett D'Amore }
99588447a05SGarrett D'Amore
99688447a05SGarrett D'Amore /*
99788447a05SGarrett D'Amore * audio1575_map_regs()
99888447a05SGarrett D'Amore *
99988447a05SGarrett D'Amore * Description:
100088447a05SGarrett D'Amore * The registers are mapped in.
100188447a05SGarrett D'Amore *
100288447a05SGarrett D'Amore * Arguments:
100388447a05SGarrett D'Amore * dev_info_t *dip Pointer to the device's devinfo
100488447a05SGarrett D'Amore *
100588447a05SGarrett D'Amore * Returns:
100688447a05SGarrett D'Amore * DDI_SUCCESS Registers successfully mapped
100788447a05SGarrett D'Amore * DDI_FAILURE Registers not successfully mapped
100888447a05SGarrett D'Amore */
100988447a05SGarrett D'Amore static int
audio1575_map_regs(audio1575_state_t * statep)101088447a05SGarrett D'Amore audio1575_map_regs(audio1575_state_t *statep)
101188447a05SGarrett D'Amore {
101288447a05SGarrett D'Amore dev_info_t *dip = statep->dip;
101388447a05SGarrett D'Amore
101488447a05SGarrett D'Amore /* map the M1575 Audio PCI Cfg Space */
101588447a05SGarrett D'Amore if (pci_config_setup(dip, &statep->pcih) != DDI_SUCCESS) {
101688447a05SGarrett D'Amore audio_dev_warn(statep->adev, "PCI config map failure");
101788447a05SGarrett D'Amore goto error;
101888447a05SGarrett D'Amore }
101988447a05SGarrett D'Amore
102088447a05SGarrett D'Amore /* map the M1575 Audio registers in PCI IO Space */
102188447a05SGarrett D'Amore if ((ddi_regs_map_setup(dip, M1575_AUDIO_IO_SPACE, &statep->regsp,
102288447a05SGarrett D'Amore 0, 0, &dev_attr, &statep->regsh)) != DDI_SUCCESS) {
102388447a05SGarrett D'Amore audio_dev_warn(statep->adev, "Audio IO mapping failure");
102488447a05SGarrett D'Amore goto error;
102588447a05SGarrett D'Amore }
102688447a05SGarrett D'Amore return (DDI_SUCCESS);
102788447a05SGarrett D'Amore
102888447a05SGarrett D'Amore error:
102988447a05SGarrett D'Amore audio1575_unmap_regs(statep);
103088447a05SGarrett D'Amore
103188447a05SGarrett D'Amore return (DDI_FAILURE);
103288447a05SGarrett D'Amore }
103388447a05SGarrett D'Amore
103488447a05SGarrett D'Amore /*
103588447a05SGarrett D'Amore * audio1575_unmap_regs()
103688447a05SGarrett D'Amore *
103788447a05SGarrett D'Amore * Description:
103888447a05SGarrett D'Amore * This routine unmaps control registers.
103988447a05SGarrett D'Amore *
104088447a05SGarrett D'Amore * Arguments:
104188447a05SGarrett D'Amore * audio1575_state_t *state The device's state structure
104288447a05SGarrett D'Amore */
104388447a05SGarrett D'Amore static void
audio1575_unmap_regs(audio1575_state_t * statep)104488447a05SGarrett D'Amore audio1575_unmap_regs(audio1575_state_t *statep)
104588447a05SGarrett D'Amore {
104688447a05SGarrett D'Amore if (statep->regsh) {
104788447a05SGarrett D'Amore ddi_regs_map_free(&statep->regsh);
104888447a05SGarrett D'Amore }
104988447a05SGarrett D'Amore
105088447a05SGarrett D'Amore if (statep->pcih) {
105188447a05SGarrett D'Amore pci_config_teardown(&statep->pcih);
105288447a05SGarrett D'Amore }
105388447a05SGarrett D'Amore }
105488447a05SGarrett D'Amore
105588447a05SGarrett D'Amore /*
105688447a05SGarrett D'Amore * audio1575_chip_init()
105788447a05SGarrett D'Amore *
105888447a05SGarrett D'Amore * Description:
105988447a05SGarrett D'Amore * This routine initializes the M1575 AC97 audio controller and the AC97
106088447a05SGarrett D'Amore * codec. The AC97 codec registers are programmed from codec_shadow[].
106188447a05SGarrett D'Amore * If we are not doing a restore, we initialize codec_shadow[], otherwise
106288447a05SGarrett D'Amore * we use the current values of shadow. This routine expects that the
106388447a05SGarrett D'Amore * PCI IO and Memory spaces have been mapped and enabled already.
106488447a05SGarrett D'Amore * Arguments:
106588447a05SGarrett D'Amore * audio1575_state_t *state The device's state structure
106688447a05SGarrett D'Amore * restore from codec_shadow[]
106788447a05SGarrett D'Amore * Returns:
106888447a05SGarrett D'Amore * DDI_SUCCESS The hardware was initialized properly
106988447a05SGarrett D'Amore * DDI_FAILURE The hardware couldn't be initialized properly
107088447a05SGarrett D'Amore */
107188447a05SGarrett D'Amore static int
audio1575_chip_init(audio1575_state_t * statep)107288447a05SGarrett D'Amore audio1575_chip_init(audio1575_state_t *statep)
107388447a05SGarrett D'Amore {
107488447a05SGarrett D'Amore uint32_t ssr;
107588447a05SGarrett D'Amore uint32_t rtsr;
107688447a05SGarrett D'Amore uint32_t intrsr;
107788447a05SGarrett D'Amore int i;
107888447a05SGarrett D'Amore int j;
10790e7a77f3SGarrett D'Amore #ifdef __sparc
108088447a05SGarrett D'Amore uint8_t clk_detect;
108188447a05SGarrett D'Amore ddi_acc_handle_t pcih;
10820e7a77f3SGarrett D'Amore #endif
10830e7a77f3SGarrett D'Amore clock_t ticks;
108488447a05SGarrett D'Amore
108588447a05SGarrett D'Amore /*
108688447a05SGarrett D'Amore * clear the interrupt control and status register
108788447a05SGarrett D'Amore * READ/WRITE/READ workaround required
108888447a05SGarrett D'Amore * for buggy hardware
108988447a05SGarrett D'Amore */
109088447a05SGarrett D'Amore
109188447a05SGarrett D'Amore PUT32(M1575_INTRCR_REG, 0);
109288447a05SGarrett D'Amore (void) GET32(M1575_INTRCR_REG);
109388447a05SGarrett D'Amore
109488447a05SGarrett D'Amore intrsr = GET32(M1575_INTRSR_REG);
109588447a05SGarrett D'Amore PUT32(M1575_INTRSR_REG, (intrsr & M1575_INTR_MASK));
109688447a05SGarrett D'Amore (void) GET32(M1575_INTRSR_REG);
109788447a05SGarrett D'Amore
109888447a05SGarrett D'Amore ticks = drv_usectohz(M1575_LOOP_CTR);
109988447a05SGarrett D'Amore
110088447a05SGarrett D'Amore /*
110188447a05SGarrett D'Amore * SADA only supports stereo, so we set the channel bits
110288447a05SGarrett D'Amore * to "00" to select 2 channels.
110388447a05SGarrett D'Amore * will also set the following:
110488447a05SGarrett D'Amore *
110588447a05SGarrett D'Amore * Disable double rate enable
110688447a05SGarrett D'Amore * no SPDIF output selected
110788447a05SGarrett D'Amore * 16 bit audio record mode
110888447a05SGarrett D'Amore * 16 bit pcm out mode
110988447a05SGarrett D'Amore * PCM Out 6 chan mode FL FR CEN BL BR LFE
111088447a05SGarrett D'Amore * PCM Out 2 channel mode (00)
111188447a05SGarrett D'Amore */
111288447a05SGarrett D'Amore for (i = 0; i < M1575_LOOP_CTR; i++) {
111388447a05SGarrett D'Amore /* Reset the AC97 Codec and default to 2 channel 16 bit mode */
111488447a05SGarrett D'Amore PUT32(M1575_SCR_REG, M1575_SCR_COLDRST);
111588447a05SGarrett D'Amore delay(ticks<<1);
111688447a05SGarrett D'Amore
111788447a05SGarrett D'Amore /* Read the System Status Reg */
111888447a05SGarrett D'Amore ssr = GET32(M1575_SSR_REG);
111988447a05SGarrett D'Amore
112088447a05SGarrett D'Amore /* make sure and release the blocked reset bit */
112188447a05SGarrett D'Amore if (ssr & M1575_SSR_RSTBLK) {
112288447a05SGarrett D'Amore SET32(M1575_INTFCR_REG, M1575_INTFCR_RSTREL);
112388447a05SGarrett D'Amore delay(ticks);
112488447a05SGarrett D'Amore
112588447a05SGarrett D'Amore /* Read the System Status Reg */
112688447a05SGarrett D'Amore ssr = GET32(M1575_SSR_REG);
112788447a05SGarrett D'Amore
112888447a05SGarrett D'Amore /* make sure and release the blocked reset bit */
112988447a05SGarrett D'Amore if (ssr & M1575_SSR_RSTBLK) {
113088447a05SGarrett D'Amore return (DDI_FAILURE);
113188447a05SGarrett D'Amore }
113288447a05SGarrett D'Amore
113388447a05SGarrett D'Amore /* Reset the controller */
113488447a05SGarrett D'Amore PUT32(M1575_SCR_REG, M1575_SCR_COLDRST);
113588447a05SGarrett D'Amore delay(ticks);
113688447a05SGarrett D'Amore }
113788447a05SGarrett D'Amore
113888447a05SGarrett D'Amore /* according AC'97 spec, wait for codec reset */
113988447a05SGarrett D'Amore for (j = 0; j < M1575_LOOP_CTR; j++) {
114088447a05SGarrett D'Amore if ((GET32(M1575_SCR_REG) & M1575_SCR_COLDRST) == 0) {
114188447a05SGarrett D'Amore break;
114288447a05SGarrett D'Amore }
114388447a05SGarrett D'Amore delay(ticks);
114488447a05SGarrett D'Amore }
114588447a05SGarrett D'Amore
114688447a05SGarrett D'Amore /* codec reset failed */
114788447a05SGarrett D'Amore if (j >= M1575_LOOP_CTR) {
114888447a05SGarrett D'Amore audio_dev_warn(statep->adev,
114988447a05SGarrett D'Amore "failure to reset codec");
115088447a05SGarrett D'Amore return (DDI_FAILURE);
115188447a05SGarrett D'Amore }
115288447a05SGarrett D'Amore
115388447a05SGarrett D'Amore /*
115488447a05SGarrett D'Amore * Wait for FACRDY First codec ready. The hardware can
115588447a05SGarrett D'Amore * provide the state of
115688447a05SGarrett D'Amore * codec ready bit on SDATA_IN[0] and as reflected in
115788447a05SGarrett D'Amore * the Recv Tag Slot Reg.
115888447a05SGarrett D'Amore */
115988447a05SGarrett D'Amore rtsr = GET32(M1575_RTSR_REG);
116088447a05SGarrett D'Amore if (rtsr & M1575_RTSR_FACRDY) {
116188447a05SGarrett D'Amore break;
116288447a05SGarrett D'Amore } else { /* reset the status and wait for new status to set */
116388447a05SGarrett D'Amore rtsr |= M1575_RTSR_FACRDY;
116488447a05SGarrett D'Amore PUT32(M1575_RTSR_REG, rtsr);
116588447a05SGarrett D'Amore drv_usecwait(10);
116688447a05SGarrett D'Amore }
116788447a05SGarrett D'Amore }
116888447a05SGarrett D'Amore
116988447a05SGarrett D'Amore /* if we could not reset the AC97 codec then report failure */
117088447a05SGarrett D'Amore if (i >= M1575_LOOP_CTR) {
117188447a05SGarrett D'Amore audio_dev_warn(statep->adev,
117288447a05SGarrett D'Amore "no codec ready signal received");
117388447a05SGarrett D'Amore return (DDI_FAILURE);
117488447a05SGarrett D'Amore }
117588447a05SGarrett D'Amore
11760e7a77f3SGarrett D'Amore #ifdef __sparc
117788447a05SGarrett D'Amore /* Magic code from ULi to Turn on the AC_LINK clock */
117888447a05SGarrett D'Amore pcih = statep->pcih;
117988447a05SGarrett D'Amore pci_config_put8(pcih, M1575_PCIACD_REG, 0);
118088447a05SGarrett D'Amore pci_config_put8(pcih, M1575_PCIACD_REG, 4);
118188447a05SGarrett D'Amore pci_config_put8(pcih, M1575_PCIACD_REG, 0);
118288447a05SGarrett D'Amore (void) pci_config_get8(pcih, M1575_PCIACD_REG);
118388447a05SGarrett D'Amore pci_config_put8(pcih, M1575_PCIACD_REG, 2);
118488447a05SGarrett D'Amore pci_config_put8(pcih, M1575_PCIACD_REG, 0);
118588447a05SGarrett D'Amore clk_detect = pci_config_get8(pcih, M1575_PCIACD_REG);
118688447a05SGarrett D'Amore
118788447a05SGarrett D'Amore if (clk_detect != 1) {
118888447a05SGarrett D'Amore audio_dev_warn(statep->adev, "No AC97 Clock Detected");
118988447a05SGarrett D'Amore return (DDI_FAILURE);
119088447a05SGarrett D'Amore }
11910e7a77f3SGarrett D'Amore #endif
119288447a05SGarrett D'Amore
119388447a05SGarrett D'Amore /* Magic code from Uli to Init FIFO1 and FIFO2 */
119488447a05SGarrett D'Amore PUT32(M1575_FIFOCR1_REG, 0x81818181);
119588447a05SGarrett D'Amore PUT32(M1575_FIFOCR2_REG, 0x81818181);
119688447a05SGarrett D'Amore PUT32(M1575_FIFOCR3_REG, 0x81818181);
119788447a05SGarrett D'Amore
119888447a05SGarrett D'Amore /* Make sure that PCM in and PCM out are enabled */
119988447a05SGarrett D'Amore SET32(M1575_INTFCR_REG, (M1575_INTFCR_PCMIENB | M1575_INTFCR_PCMOENB));
120088447a05SGarrett D'Amore
12010e7a77f3SGarrett D'Amore audio1575_dma_stop(statep, B_FALSE);
120288447a05SGarrett D'Amore
120388447a05SGarrett D'Amore return (DDI_SUCCESS);
120488447a05SGarrett D'Amore }
120588447a05SGarrett D'Amore
120688447a05SGarrett D'Amore /*
120788447a05SGarrett D'Amore * audio1575_dma_stop()
120888447a05SGarrett D'Amore *
120988447a05SGarrett D'Amore * Description:
121088447a05SGarrett D'Amore * This routine is used to put each DMA engine into the quiet state.
121188447a05SGarrett D'Amore *
121288447a05SGarrett D'Amore * Arguments:
121388447a05SGarrett D'Amore * audio1575_state_t *statep The device's state structure
121488447a05SGarrett D'Amore */
121588447a05SGarrett D'Amore static void
audio1575_dma_stop(audio1575_state_t * statep,boolean_t quiesce)12160e7a77f3SGarrett D'Amore audio1575_dma_stop(audio1575_state_t *statep, boolean_t quiesce)
121788447a05SGarrett D'Amore {
121888447a05SGarrett D'Amore uint32_t intrsr;
121988447a05SGarrett D'Amore int i;
122088447a05SGarrett D'Amore
122188447a05SGarrett D'Amore if (statep->regsh == NULL) {
122288447a05SGarrett D'Amore return;
122388447a05SGarrett D'Amore }
122488447a05SGarrett D'Amore
122588447a05SGarrett D'Amore /* pause bus master (needed for the following reset register) */
122688447a05SGarrett D'Amore for (i = 0; i < M1575_LOOP_CTR; i++) {
122788447a05SGarrett D'Amore
122888447a05SGarrett D'Amore SET32(M1575_DMACR_REG, M1575_DMACR_PAUSE_ALL);
122988447a05SGarrett D'Amore if (GET32(M1575_DMACR_REG) & M1575_DMACR_PAUSE_ALL) {
123088447a05SGarrett D'Amore break;
123188447a05SGarrett D'Amore }
123288447a05SGarrett D'Amore drv_usecwait(10);
123388447a05SGarrett D'Amore }
123488447a05SGarrett D'Amore
123588447a05SGarrett D'Amore if (i >= M1575_LOOP_CTR) {
12360e7a77f3SGarrett D'Amore if (!quiesce)
12370e7a77f3SGarrett D'Amore audio_dev_warn(statep->adev, "failed to stop DMA");
123888447a05SGarrett D'Amore return;
123988447a05SGarrett D'Amore }
124088447a05SGarrett D'Amore
124188447a05SGarrett D'Amore /* Pause bus master (needed for the following reset register) */
124288447a05SGarrett D'Amore PUT8(M1575_PCMICR_REG, 0);
124388447a05SGarrett D'Amore PUT8(M1575_PCMOCR_REG, 0);
124488447a05SGarrett D'Amore PUT8(M1575_MICICR_REG, 0);
124588447a05SGarrett D'Amore PUT8(M1575_CSPOCR_REG, 0);
124688447a05SGarrett D'Amore PUT8(M1575_PCMI2CR_RR, 0);
124788447a05SGarrett D'Amore PUT8(M1575_MICI2CR_RR, 0);
124888447a05SGarrett D'Amore
124988447a05SGarrett D'Amore /* Reset the bus master registers for all DMA engines */
125088447a05SGarrett D'Amore PUT8(M1575_PCMICR_REG, M1575_PCMICR_RR);
125188447a05SGarrett D'Amore PUT8(M1575_PCMOCR_REG, M1575_PCMOCR_RR);
125288447a05SGarrett D'Amore PUT8(M1575_MICICR_REG, M1575_MICICR_RR);
125388447a05SGarrett D'Amore PUT8(M1575_CSPOCR_REG, M1575_CSPOCR_RR);
125488447a05SGarrett D'Amore PUT8(M1575_PCMI2CR_REG, M1575_PCMI2CR_RR);
125588447a05SGarrett D'Amore PUT8(M1575_MICI2CR_REG, M1575_MICI2CR_RR);
125688447a05SGarrett D'Amore
125788447a05SGarrett D'Amore /* Reset FIFOS */
125888447a05SGarrett D'Amore PUT32(M1575_FIFOCR1_REG, 0x81818181);
125988447a05SGarrett D'Amore PUT32(M1575_FIFOCR2_REG, 0x81818181);
126088447a05SGarrett D'Amore PUT32(M1575_FIFOCR3_REG, 0x81818181);
126188447a05SGarrett D'Amore
126288447a05SGarrett D'Amore /* Clear Interrupts */
126388447a05SGarrett D'Amore SET16(M1575_PCMISR_REG, M1575_SR_CLR);
126488447a05SGarrett D'Amore SET16(M1575_PCMOSR_REG, M1575_SR_CLR);
126588447a05SGarrett D'Amore SET16(M1575_MICISR_REG, M1575_SR_CLR);
126688447a05SGarrett D'Amore SET16(M1575_CSPOSR_REG, M1575_SR_CLR);
126788447a05SGarrett D'Amore SET16(M1575_PCMI2SR_REG, M1575_SR_CLR);
126888447a05SGarrett D'Amore SET16(M1575_MICI2SR_REG, M1575_SR_CLR);
126988447a05SGarrett D'Amore
127088447a05SGarrett D'Amore /*
127188447a05SGarrett D'Amore * clear the interrupt control and status register
1272*68c47f65SGarrett D'Amore * READ/WRITE/READ workaround required to flush PCI caches
127388447a05SGarrett D'Amore */
127488447a05SGarrett D'Amore
127588447a05SGarrett D'Amore PUT32(M1575_INTRCR_REG, 0);
127688447a05SGarrett D'Amore (void) GET32(M1575_INTRCR_REG);
127788447a05SGarrett D'Amore
127888447a05SGarrett D'Amore intrsr = GET32(M1575_INTRSR_REG);
127988447a05SGarrett D'Amore PUT32(M1575_INTRSR_REG, (intrsr & M1575_INTR_MASK));
128088447a05SGarrett D'Amore (void) GET32(M1575_INTRSR_REG);
128188447a05SGarrett D'Amore }
128288447a05SGarrett D'Amore
128388447a05SGarrett D'Amore /*
128488447a05SGarrett D'Amore * audio1575_codec_sync()
128588447a05SGarrett D'Amore *
128688447a05SGarrett D'Amore * Description:
128788447a05SGarrett D'Amore * Serialize access to the AC97 audio mixer registers.
128888447a05SGarrett D'Amore *
128988447a05SGarrett D'Amore * Arguments:
129088447a05SGarrett D'Amore * audio1575_state_t *state The device's state structure
129188447a05SGarrett D'Amore *
129288447a05SGarrett D'Amore * Returns:
129388447a05SGarrett D'Amore * DDI_SUCCESS Ready for an I/O access to the codec
129488447a05SGarrett D'Amore * DDI_FAILURE An I/O access is currently in progress, can't
129588447a05SGarrett D'Amore * perform another I/O access.
129688447a05SGarrett D'Amore */
129788447a05SGarrett D'Amore static int
audio1575_codec_sync(audio1575_state_t * statep)129888447a05SGarrett D'Amore audio1575_codec_sync(audio1575_state_t *statep)
129988447a05SGarrett D'Amore {
130088447a05SGarrett D'Amore /* do the Uli Shuffle ... */
130188447a05SGarrett D'Amore for (int i = 0; i < M1575_LOOP_CTR; i++) {
130288447a05SGarrett D'Amore /* Read the semaphore, and loop till we own it */
130388447a05SGarrett D'Amore if ((GET32(M1575_CASR_REG) & 1) == 0) {
130488447a05SGarrett D'Amore for (int j = 0; j < M1575_LOOP_CTR; j++) {
130588447a05SGarrett D'Amore /* Wait for CWRSUCC 0x8 */
130688447a05SGarrett D'Amore if (GET32(M1575_CSPSR_REG) &
130788447a05SGarrett D'Amore M1575_CSPSR_SUCC) {
130888447a05SGarrett D'Amore return (DDI_SUCCESS);
130988447a05SGarrett D'Amore }
131088447a05SGarrett D'Amore drv_usecwait(1);
131188447a05SGarrett D'Amore }
131288447a05SGarrett D'Amore }
131388447a05SGarrett D'Amore drv_usecwait(10);
131488447a05SGarrett D'Amore }
131588447a05SGarrett D'Amore
131688447a05SGarrett D'Amore return (DDI_FAILURE);
131788447a05SGarrett D'Amore }
131888447a05SGarrett D'Amore
131988447a05SGarrett D'Amore /*
132088447a05SGarrett D'Amore * audio1575_write_ac97()
132188447a05SGarrett D'Amore *
132288447a05SGarrett D'Amore * Description:
132388447a05SGarrett D'Amore * Set the specific AC97 Codec register.
132488447a05SGarrett D'Amore *
132588447a05SGarrett D'Amore * Arguments:
132688447a05SGarrett D'Amore * void *arg The device's state structure
132788447a05SGarrett D'Amore * uint8_t reg AC97 register number
132888447a05SGarrett D'Amore * uint16_t data The data want to be set
132988447a05SGarrett D'Amore */
133088447a05SGarrett D'Amore static void
audio1575_write_ac97(void * arg,uint8_t reg,uint16_t data)133188447a05SGarrett D'Amore audio1575_write_ac97(void *arg, uint8_t reg, uint16_t data)
133288447a05SGarrett D'Amore {
133388447a05SGarrett D'Amore audio1575_state_t *statep = arg;
133488447a05SGarrett D'Amore int i;
133588447a05SGarrett D'Amore
133688447a05SGarrett D'Amore if (audio1575_codec_sync(statep) != DDI_SUCCESS) {
133788447a05SGarrett D'Amore return;
133888447a05SGarrett D'Amore }
133988447a05SGarrett D'Amore
134088447a05SGarrett D'Amore /* write the data to WRITE to the lo word of the CPR register */
134188447a05SGarrett D'Amore PUT16(M1575_CPR_REG, data);
134288447a05SGarrett D'Amore
134388447a05SGarrett D'Amore /* write the address to WRITE to the hi word of the CPR register */
134488447a05SGarrett D'Amore PUT16(M1575_CPR_REG+2, reg);
134588447a05SGarrett D'Amore
134688447a05SGarrett D'Amore /* wait until command is completed sucessfully */
134788447a05SGarrett D'Amore for (i = 0; i < M1575_LOOP_CTR; i++) {
134888447a05SGarrett D'Amore /* Wait for Write Ready 0x01 */
134988447a05SGarrett D'Amore if (GET32(M1575_CSPSR_REG) & M1575_CSPSR_WRRDY) {
135088447a05SGarrett D'Amore break;
135188447a05SGarrett D'Amore }
135288447a05SGarrett D'Amore drv_usecwait(1);
135388447a05SGarrett D'Amore }
135488447a05SGarrett D'Amore
135588447a05SGarrett D'Amore if (i < M1575_LOOP_CTR) {
135688447a05SGarrett D'Amore (void) audio1575_read_ac97(statep, reg);
135788447a05SGarrett D'Amore }
135888447a05SGarrett D'Amore }
135988447a05SGarrett D'Amore
136088447a05SGarrett D'Amore /*
136188447a05SGarrett D'Amore * audio1575_read_ac97()
136288447a05SGarrett D'Amore *
136388447a05SGarrett D'Amore * Description:
136488447a05SGarrett D'Amore * Get the specific AC97 Codec register. It also updates codec_shadow[]
136588447a05SGarrett D'Amore * with the register value.
136688447a05SGarrett D'Amore *
136788447a05SGarrett D'Amore * Arguments:
136888447a05SGarrett D'Amore * void *arg The device's state structure
136988447a05SGarrett D'Amore * uint8_t reg AC97 register number
137088447a05SGarrett D'Amore *
137188447a05SGarrett D'Amore * Returns:
137288447a05SGarrett D'Amore * Value of AC97 register. (0xffff in failure situations).
137388447a05SGarrett D'Amore */
137488447a05SGarrett D'Amore static uint16_t
audio1575_read_ac97(void * arg,uint8_t reg)137588447a05SGarrett D'Amore audio1575_read_ac97(void *arg, uint8_t reg)
137688447a05SGarrett D'Amore {
137788447a05SGarrett D'Amore audio1575_state_t *statep = arg;
137888447a05SGarrett D'Amore uint16_t addr = 0;
137988447a05SGarrett D'Amore uint16_t data = 0xffff;
138088447a05SGarrett D'Amore int i;
138188447a05SGarrett D'Amore
138288447a05SGarrett D'Amore if ((audio1575_codec_sync(statep)) != DDI_SUCCESS) {
138388447a05SGarrett D'Amore return (data);
138488447a05SGarrett D'Amore }
138588447a05SGarrett D'Amore
138688447a05SGarrett D'Amore /*
138788447a05SGarrett D'Amore * at this point we have the CASR semaphore
138888447a05SGarrett D'Amore * and the codec is r/w ready
138988447a05SGarrett D'Amore * OR in the READ opcode into the address field
139088447a05SGarrett D'Amore */
139188447a05SGarrett D'Amore
139288447a05SGarrett D'Amore addr = (reg | M1575_CPR_READ);
139388447a05SGarrett D'Amore
139488447a05SGarrett D'Amore /* write the address to READ to the hi word of the CPR register */
139588447a05SGarrett D'Amore PUT16(M1575_CPR_REG+2, addr);
139688447a05SGarrett D'Amore
139788447a05SGarrett D'Amore /* wait until command is completed sucessfully */
139888447a05SGarrett D'Amore for (i = 0; i < M1575_LOOP_CTR; i++) {
139988447a05SGarrett D'Amore /* Wait for Read Ready 0x02 */
140088447a05SGarrett D'Amore if (GET32(M1575_CSPSR_REG) & M1575_CSPSR_RDRDY) {
140188447a05SGarrett D'Amore break;
140288447a05SGarrett D'Amore }
140388447a05SGarrett D'Amore drv_usecwait(1);
140488447a05SGarrett D'Amore }
140588447a05SGarrett D'Amore
140688447a05SGarrett D'Amore if (i < M1575_LOOP_CTR) {
140788447a05SGarrett D'Amore /* read back the data and address */
140888447a05SGarrett D'Amore data = GET16(M1575_SPR_REG);
140988447a05SGarrett D'Amore addr = GET16(M1575_SPR_REG+2);
141088447a05SGarrett D'Amore if (addr != reg) {
141188447a05SGarrett D'Amore data = 0xffff;
141288447a05SGarrett D'Amore }
141388447a05SGarrett D'Amore }
141488447a05SGarrett D'Amore
141588447a05SGarrett D'Amore return (data);
141688447a05SGarrett D'Amore }
141788447a05SGarrett D'Amore
141888447a05SGarrett D'Amore /*
141988447a05SGarrett D'Amore * audio1575_pci_enable()
142088447a05SGarrett D'Amore *
142188447a05SGarrett D'Amore * Description:
142288447a05SGarrett D'Amore * This routine Enables all PCI IO and MEMORY accesses
142388447a05SGarrett D'Amore *
142488447a05SGarrett D'Amore * Arguments:
142588447a05SGarrett D'Amore * audio1575_state_t *statep The device's state structure
142688447a05SGarrett D'Amore */
142788447a05SGarrett D'Amore static void
audio1575_pci_enable(audio1575_state_t * statep)142888447a05SGarrett D'Amore audio1575_pci_enable(audio1575_state_t *statep)
142988447a05SGarrett D'Amore {
143088447a05SGarrett D'Amore uint16_t pcics_reg;
143188447a05SGarrett D'Amore
143288447a05SGarrett D'Amore pcics_reg = pci_config_get16(statep->pcih, PCI_CONF_COMM);
143388447a05SGarrett D'Amore pcics_reg |= (PCI_COMM_IO | PCI_COMM_MAE | PCI_COMM_ME);
143488447a05SGarrett D'Amore pci_config_put16(statep->pcih, PCI_CONF_COMM, pcics_reg);
143588447a05SGarrett D'Amore }
143688447a05SGarrett D'Amore
143788447a05SGarrett D'Amore /*
143888447a05SGarrett D'Amore * audio1575_pci_disable()
143988447a05SGarrett D'Amore *
144088447a05SGarrett D'Amore * Description:
144188447a05SGarrett D'Amore * This routine Disables all PCI IO and MEMORY accesses
144288447a05SGarrett D'Amore *
144388447a05SGarrett D'Amore * Arguments:
144488447a05SGarrett D'Amore * audio1575_state_t *statep The device's state structure
144588447a05SGarrett D'Amore */
144688447a05SGarrett D'Amore static void
audio1575_pci_disable(audio1575_state_t * statep)144788447a05SGarrett D'Amore audio1575_pci_disable(audio1575_state_t *statep)
144888447a05SGarrett D'Amore {
144988447a05SGarrett D'Amore uint16_t pcics_reg;
145088447a05SGarrett D'Amore
145188447a05SGarrett D'Amore if (statep->pcih == NULL)
145288447a05SGarrett D'Amore return;
145388447a05SGarrett D'Amore pcics_reg = pci_config_get16(statep->pcih, PCI_CONF_COMM);
145488447a05SGarrett D'Amore pcics_reg &= ~(PCI_COMM_IO | PCI_COMM_MAE | PCI_COMM_ME);
145588447a05SGarrett D'Amore pci_config_put16(statep->pcih, PCI_CONF_COMM, pcics_reg);
145688447a05SGarrett D'Amore }
145788447a05SGarrett D'Amore
145888447a05SGarrett D'Amore /*
145988447a05SGarrett D'Amore * audio1575_resume()
146088447a05SGarrett D'Amore *
146188447a05SGarrett D'Amore * Description:
146288447a05SGarrett D'Amore * Resume operation of the device after sleeping or hibernating.
146388447a05SGarrett D'Amore * Note that this should never fail, even if hardware goes wonky,
146488447a05SGarrett D'Amore * because the current PM framework will panic if it does.
146588447a05SGarrett D'Amore *
146688447a05SGarrett D'Amore * Arguments:
146788447a05SGarrett D'Amore * dev_info_t *dip Pointer to the device's dev_info struct
146888447a05SGarrett D'Amore *
146988447a05SGarrett D'Amore * Returns:
147088447a05SGarrett D'Amore * DDI_SUCCESS The driver was resumed
147188447a05SGarrett D'Amore */
147288447a05SGarrett D'Amore static int
audio1575_resume(dev_info_t * dip)147388447a05SGarrett D'Amore audio1575_resume(dev_info_t *dip)
147488447a05SGarrett D'Amore {
147588447a05SGarrett D'Amore audio1575_state_t *statep;
147688447a05SGarrett D'Amore audio_dev_t *adev;
147788447a05SGarrett D'Amore
147888447a05SGarrett D'Amore /* we've already allocated the state structure so get ptr */
147988447a05SGarrett D'Amore statep = ddi_get_driver_private(dip);
148088447a05SGarrett D'Amore adev = statep->adev;
148188447a05SGarrett D'Amore ASSERT(!mutex_owned(&statep->lock));
148288447a05SGarrett D'Amore
148388447a05SGarrett D'Amore if (audio1575_chip_init(statep) != DDI_SUCCESS) {
148488447a05SGarrett D'Amore /*
148588447a05SGarrett D'Amore * Note that PM gurus say we should return
148688447a05SGarrett D'Amore * success here. Failure of audio shouldn't
148788447a05SGarrett D'Amore * be considered FATAL to the system. The
148888447a05SGarrett D'Amore * upshot is that audio will not progress.
148988447a05SGarrett D'Amore */
149088447a05SGarrett D'Amore audio_dev_warn(adev, "DDI_RESUME failed to init chip");
149188447a05SGarrett D'Amore return (DDI_SUCCESS);
149288447a05SGarrett D'Amore }
149388447a05SGarrett D'Amore
149488447a05SGarrett D'Amore /* allow ac97 operations again */
1495*68c47f65SGarrett D'Amore ac97_reset(statep->ac97);
149688447a05SGarrett D'Amore
1497*68c47f65SGarrett D'Amore audio_dev_resume(adev);
149888447a05SGarrett D'Amore
149988447a05SGarrett D'Amore return (DDI_SUCCESS);
150088447a05SGarrett D'Amore }
150188447a05SGarrett D'Amore
150288447a05SGarrett D'Amore /*
150388447a05SGarrett D'Amore * audio1575_suspend()
150488447a05SGarrett D'Amore *
150588447a05SGarrett D'Amore * Description:
150688447a05SGarrett D'Amore * Suspend an instance of the audio1575 driver.
150788447a05SGarrett D'Amore *
150888447a05SGarrett D'Amore * Arguments:
150988447a05SGarrett D'Amore * dev_info_t *dip Pointer to the device's dev_info struct
151088447a05SGarrett D'Amore *
151188447a05SGarrett D'Amore * Returns:
151288447a05SGarrett D'Amore * DDI_SUCCESS The driver was suspended
151388447a05SGarrett D'Amore */
151488447a05SGarrett D'Amore static int
audio1575_suspend(dev_info_t * dip)151588447a05SGarrett D'Amore audio1575_suspend(dev_info_t *dip)
151688447a05SGarrett D'Amore {
151788447a05SGarrett D'Amore audio1575_state_t *statep;
151888447a05SGarrett D'Amore
151988447a05SGarrett D'Amore statep = ddi_get_driver_private(dip);
152088447a05SGarrett D'Amore
1521*68c47f65SGarrett D'Amore audio_dev_suspend(statep->adev);
152288447a05SGarrett D'Amore
152388447a05SGarrett D'Amore return (DDI_SUCCESS);
152488447a05SGarrett D'Amore }
152588447a05SGarrett D'Amore
152688447a05SGarrett D'Amore /*
152788447a05SGarrett D'Amore * audio1575_destroy()
152888447a05SGarrett D'Amore *
152988447a05SGarrett D'Amore * Description:
153088447a05SGarrett D'Amore * This routine releases all resources held by the device instance,
153188447a05SGarrett D'Amore * as part of either detach or a failure in attach.
153288447a05SGarrett D'Amore *
153388447a05SGarrett D'Amore * Arguments:
153488447a05SGarrett D'Amore * audio1575_state_t *state The device soft state.
153588447a05SGarrett D'Amore */
153688447a05SGarrett D'Amore void
audio1575_destroy(audio1575_state_t * statep)153788447a05SGarrett D'Amore audio1575_destroy(audio1575_state_t *statep)
153888447a05SGarrett D'Amore {
153988447a05SGarrett D'Amore ddi_acc_handle_t pcih;
154088447a05SGarrett D'Amore
154188447a05SGarrett D'Amore /* stop DMA engines */
15420e7a77f3SGarrett D'Amore audio1575_dma_stop(statep, B_FALSE);
154388447a05SGarrett D'Amore
154488447a05SGarrett D'Amore if (statep->regsh != NULL) {
154588447a05SGarrett D'Amore /* reset the codec */
154688447a05SGarrett D'Amore PUT32(M1575_SCR_REG, M1575_SCR_COLDRST);
154788447a05SGarrett D'Amore }
154888447a05SGarrett D'Amore
154988447a05SGarrett D'Amore if ((pcih = statep->pcih) != NULL) {
155088447a05SGarrett D'Amore /* turn off the AC_LINK clock */
155188447a05SGarrett D'Amore pci_config_put8(pcih, M1575_PCIACD_REG, 0);
155288447a05SGarrett D'Amore pci_config_put8(pcih, M1575_PCIACD_REG, 4);
155388447a05SGarrett D'Amore pci_config_put8(pcih, M1575_PCIACD_REG, 0);
155488447a05SGarrett D'Amore }
155588447a05SGarrett D'Amore
155688447a05SGarrett D'Amore /* Disable PCI I/O and Memory Spaces */
155788447a05SGarrett D'Amore audio1575_pci_disable(statep);
155888447a05SGarrett D'Amore
155988447a05SGarrett D'Amore audio1575_free_port(statep->ports[M1575_PLAY]);
156088447a05SGarrett D'Amore audio1575_free_port(statep->ports[M1575_REC]);
156188447a05SGarrett D'Amore
156288447a05SGarrett D'Amore audio1575_unmap_regs(statep);
156388447a05SGarrett D'Amore
156488447a05SGarrett D'Amore if (statep->ac97 != NULL) {
156588447a05SGarrett D'Amore ac97_free(statep->ac97);
156688447a05SGarrett D'Amore }
156788447a05SGarrett D'Amore
156888447a05SGarrett D'Amore if (statep->adev != NULL) {
156988447a05SGarrett D'Amore audio_dev_free(statep->adev);
157088447a05SGarrett D'Amore }
157188447a05SGarrett D'Amore
157288447a05SGarrett D'Amore kmem_free(statep, sizeof (*statep));
157388447a05SGarrett D'Amore }
1574