/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Purpose: Definitions for the CMedia 8788 driver.
*/
/*
* This file is part of Open Sound System
*
* Copyright (C) 4Front Technologies 1996-2011.
*
* This software is released under CDDL 1.0 source license.
* See the COPYING file included in the main directory of this source
* distribution for the license terms and conditions.
*/
#ifndef CMEDIAHD_H
#define CMEDIAHD_H
#define CMEDIAHD_NAME "audiocmihd"
#define CMEDIAHD_NUM_PORTC 2
#define CMEDIAHD_PLAY 0
#define CMEDIAHD_REC 1
/*
* Number of fragments must be multiple of 2 because the
* hardware supports only full and half buffer interrupts. In
* addition it looks like 8 fragments is the minimum.
*/
#define CMEDIAHD_BUF_LEN (65536)
#define PCI_VENDOR_ID_CMEDIA 0x13F6
#define PCI_DEVICE_ID_CMEDIAHD 0x8788
#define CMEDIAHD_MAX_INTRS 512
#define CMEDIAHD_MIN_INTRS 48
#define CMEDIAHD_INTRS 100
/*
* PCI registers
*/
#define RECA_ADDR (devc->base+0x00)
#define RECA_SIZE (devc->base+0x04)
#define RECA_FRAG (devc->base+0x06)
#define RECB_ADDR (devc->base+0x08)
#define RECB_SIZE (devc->base+0x0C)
#define RECB_FRAG (devc->base+0x0E)
#define RECC_ADDR (devc->base+0x10)
#define RECC_SIZE (devc->base+0x14)
#define RECC_FRAG (devc->base+0x16)
#define SPDIF_ADDR (devc->base+0x18)
#define SPDIF_SIZE (devc->base+0x1C)
#define SPDIF_FRAG (devc->base+0x1E)
#define MULTICH_ADDR (devc->base+0x20)
#define MULTICH_SIZE (devc->base+0x24)
#define MULTICH_FRAG (devc->base+0x28)
#define FPOUT_ADDR (devc->base+0x30)
#define FPOUT_SIZE (devc->base+0x34)
#define FPOUT_FRAG (devc->base+0x36)
#define DMA_START (devc->base+0x40)
#define CHAN_RESET (devc->base+0x42)
#define MULTICH_MODE (devc->base+0x43)
#define IRQ_MASK (devc->base+0x44)
#define IRQ_STAT (devc->base+0x46)
#define MISC_REG (devc->base+0x48)
#define REC_FORMAT (devc->base+0x4A)
#define PLAY_FORMAT (devc->base+0x4B)
#define REC_MODE (devc->base+0x4C)
#define FUNCTION (devc->base+0x50)
#define I2S_MULTICH_DAC (devc->base+0x60)
#define I2S_ADC1 (devc->base+0x62)
#define I2S_ADC2 (devc->base+0x64)
#define I2S_ADC3 (devc->base+0x66)
#define SPDIF_FUNC (devc->base+0x70)
#define SPDIFOUT_CHAN_STAT (devc->base+0x74)
#define SPDIFIN_CHAN_STAT (devc->base+0x78)
#define TWO_WIRE_ADDR (devc->base+0x90)
#define TWO_WIRE_MAP (devc->base+0x91)
#define TWO_WIRE_DATA (devc->base+0x92)
#define TWO_WIRE_CTRL (devc->base+0x94)
#define SPI_CONTROL (devc->base+0x98)
#define SPI_DATA (devc->base+0x99)
#define MPU401_DATA (devc->base+0xA0)
#define MPU401_COMMAND (devc->base+0xA1)
#define MPU401_CONTROL (devc->base+0xA2)
#define GPI_DATA (devc->base+0xA4)
#define GPI_IRQ_MASK (devc->base+0xA5)
#define GPIO_DATA (devc->base+0xA6)
#define GPIO_CONTROL (devc->base+0xA8)
#define GPIO_IRQ_MASK (devc->base+0xAA)
#define DEVICE_SENSE (devc->base+0xAC)
#define PLAY_ROUTING (devc->base+0xC0)
#define REC_ROUTING (devc->base+0xC2)
#define REC_MONITOR (devc->base+0xC3)
#define MONITOR_ROUTING (devc->base+0xC4)
#define AC97_CTRL (devc->base+0xD0)
#define AC97_INTR_MASK (devc->base+0xD2)
#define AC97_INTR_STAT (devc->base+0xD3)
#define AC97_OUT_CHAN_CONFIG (devc->base+0xD4)
#define AC97_IN_CHAN_CONFIG (devc->base+0xD8)
#define AC97_CMD_DATA (devc->base+0xDC)
#define CODEC_VERSION (devc->base+0xE4)
#define CTRL_VERSION (devc->base+0xE6)
/* Device IDs */
#define ASUS_VENDOR_ID 0x1043
#define SUBID_XONAR_D2 0x8269
#define SUBID_XONAR_D2X 0x82b7
#define SUBID_XONAR_D1 0x834f
#define SUBID_XONAR_DX 0x8275
#define SUBID_XONAR_STX 0x835c
#define SUBID_XONAR_DS 0x838e
#define SUBID_GENERIC 0x0000
/* Xonar specific */
#define XONAR_DX_FRONTDAC 0x9e
#define XONAR_DX_SURRDAC 0x30
#define XONAR_STX_FRONTDAC 0x98
#define XONAR_DS_FRONTDAC 0x1
#define XONAR_DS_SURRDAC 0x0
/* defs for AKM 4396 DAC */
#define AK4396_CTL1 0x00
#define AK4396_CTL2 0x01
#define AK4396_CTL3 0x02
#define AK4396_LchATTCtl 0x03
#define AK4396_RchATTCtl 0x04
/* defs for CS4398 DAC */
#define CS4398_CHIP_ID 0x01
#define CS4398_MODE_CTRL 0x02
#define CS4398_MIXING 0x03
#define CS4398_MUTE_CTRL 0x04
#define CS4398_VOLA 0x05
#define CS4398_VOLB 0x06
#define CS4398_RAMP_CTRL 0x07
#define CS4398_MISC_CTRL 0x08
#define CS4398_MISC2_CTRL 0x09
#define CS4398_POWER_DOWN (1<<7) /* Obvious */
#define CS4398_CPEN (1<<6) /* Control Port Enable */
#define CS4398_FREEZE (1<<5) /* Freezes registers, unfreeze to */
/* accept changed registers */
#define CS4398_MCLKDIV2 (1<<4) /* Divide MCLK by 2 */
#define CS4398_MCLKDIV3 (1<<3) /* Divive MCLK by 3 */
#define CS4398_I2S (1<<4) /* Set I2S mode */
/* defs for CS4362A DAC */
#define CS4362A_MODE1_CTRL 0x01
#define CS4362A_MODE2_CTRL 0x02
#define CS4362A_MODE3_CTRL 0x03
#define CS4362A_FILTER_CTRL 0x04
#define CS4362A_INVERT_CTRL 0x05
#define CS4362A_MIX1_CTRL 0x06
#define CS4362A_VOLA_1 0x07
#define CS4362A_VOLB_1 0x08
#define CS4362A_MIX2_CTRL 0x09
#define CS4362A_VOLA_2 0x0A
#define CS4362A_VOLB_2 0x0B
#define CS4362A_MIX3_CTRL 0x0C
#define CS4362A_VOLA_3 0x0D
#define CS4362A_VOLB_3 0x0E
#define CS4362A_CHIP_REV 0x12
/* CS4362A Reg 01h */
#define CS4362A_CPEN (1<<7)
#define CS4362A_FREEZE (1<<6)
#define CS4362A_MCLKDIV (1<<5)
#define CS4362A_DAC3_ENABLE (1<<3)
#define CS4362A_DAC2_ENABLE (1<<2)
#define CS4362A_DAC1_ENABLE (1<<1)
#define CS4362A_POWER_DOWN (1)
/* CS4362A Reg 02h */
#define CS4362A_DIF_LJUST 0x00
#define CS4362A_DIF_I2S 0x10
#define CS4362A_DIF_RJUST16 0x20
#define CS4362A_DIF_RJUST24 0x30
#define CS4362A_DIF_RJUST20 0x40
#define CS4362A_DIF_RJUST18 0x50
/* CS4362A Reg 03h */
#define CS4362A_RAMP_IMMEDIATE 0x00
#define CS4362A_RAMP_ZEROCROSS 0x40
#define CS4362A_RAMP_SOFT 0x80
#define CS4362A_RAMP_SOFTZERO 0xC0
#define CS4362A_SINGLE_VOL 0x20
#define CS4362A_RAMP_ERROR 0x10
#define CS4362A_MUTEC_POL 0x08
#define CS4362A_AUTOMUTE 0x04
#define CS4362A_SIX_MUTE 0x00
#define CS4362A_ONE_MUTE 0x01
#define CS4362A_THREE_MUTE 0x03
/* CS4362A Reg 04h */
#define CS4362A_FILT_SEL 0x10
#define CS4362A_DEM_NONE 0x00
#define CS4362A_DEM_44KHZ 0x02
#define CS4362A_DEM_48KHZ 0x04
#define CS4362A_DEM_32KHZ 0x06
#define CS4362A_RAMPDOWN 0x01
/* CS4362A Reg 05h */
#define CS4362A_INV_A3 (1<<4)
#define CS4362A_INV_B3 (1<<5)
#define CS4362A_INV_A2 (1<<2)
#define CS4362A_INV_B2 (1<<3)
#define CS4362A_INV_A1 (1)
#define CS4362A_INV_B1 (1<<1)
/* CS4362A Reg 06h, 09h, 0Ch */
/* ATAPI crap, does anyone still use analog CD playback? */
/* CS4362A Reg 07h, 08h, 0Ah, 0Bh, 0Dh, 0Eh */
/* Volume registers */
#define CS4362A_VOL_MUTE 0x80
/* 0-100. Start at -96dB. */
#define CS4398_VOL(x) \
((x) == 0 ? 0xFF : (0xC0 - ((x)*192/100)))
/* 0-100. Start at -96dB. Bit 7 is mute. */
#define CS4362A_VOL(x) \
(char)((x) == 0 ? 0xFF : (0x60 - ((x)*96/100)))
/* Xonar D2/D2X codec remap */
static const char xd2_codec_map[4] = {
0, 1, 2, 4
};
typedef struct _cmediahd_devc_t cmediahd_devc_t;
typedef struct _cmediahd_portc_t cmediahd_portc_t;
typedef enum {
CTL_VOLUME = 0,
CTL_FRONT,
CTL_REAR,
CTL_CENTER,
CTL_LFE,
CTL_SURROUND,
CTL_MONITOR,
CTL_RECSRC,
CTL_RECGAIN,
CTL_MICVOL,
CTL_AUXVOL,
CTL_CDVOL,
CTL_LOOP,
CTL_SPREAD,
CTL_NUM /* must be last */
} cmediahd_ctrl_num_t;
typedef struct cmediahd_ctrl
{
cmediahd_devc_t *devc;
audio_ctrl_t *ctrl;
cmediahd_ctrl_num_t num;
uint64_t val;
} cmediahd_ctrl_t;
typedef struct cmediahd_regs
{
caddr_t addr; /* base address */
caddr_t size; /* current count */
caddr_t frag; /* terminal count */
caddr_t i2s; /* i2s reg */
int chan; /* rec a/b/c, play spdif/multi/front */
#define REC_A 0
#define REC_B 1
#define REC_C 2
#define PLAY_SPDIF 3
#define PLAY_MULTI 4
#define PLAY_FRONT 5
} cmediahd_regs_t;
struct _cmediahd_portc_t
{
cmediahd_devc_t *devc;
audio_engine_t *engine;
int chans;
int direction;
ddi_dma_handle_t buf_dmah; /* dma for buffers */
ddi_acc_handle_t buf_acch;
uint32_t paddr;
caddr_t kaddr;
size_t buf_size;
size_t buf_frames; /* Buffer size in frames */
unsigned fragfr;
unsigned nfrags;
unsigned nframes;
unsigned bufsz;
size_t offset;
uint64_t count;
int syncdir;
};
struct _cmediahd_devc_t
{
dev_info_t *dip;
audio_dev_t *adev;
boolean_t has_ac97, has_fp_ac97;
int model;
ac97_t *ac97, *fp_ac97;
boolean_t suspended;
ddi_acc_handle_t pcih;
ddi_acc_handle_t regsh;
caddr_t base;
kmutex_t mutex; /* For normal locking */
kmutex_t low_mutex; /* For low level routines */
cmediahd_regs_t rec_eng; /* which rec engine to use */
cmediahd_portc_t *portc[CMEDIAHD_NUM_PORTC];
int gpio_mic, gpio_out, gpio_codec, gpio_alt;
cmediahd_ctrl_t controls[CTL_NUM];
};
#define INB(devc, reg) ddi_get8(devc->regsh, (void *)(reg))
#define OUTB(devc, val, reg) ddi_put8(devc->regsh, (void *)(reg), (val))
#define INW(devc, reg) ddi_get16(devc->regsh, (void *)(reg))
#define OUTW(devc, val, reg) ddi_put16(devc->regsh, (void *)(reg), (val))
#define INL(devc, reg) ddi_get32(devc->regsh, (void *)(reg))
#define OUTL(devc, val, reg) ddi_put32(devc->regsh, (void *)(reg), (val))
#endif /* CMEDIAHD_H */