diff options
Diffstat (limited to 'drivers/mxc/hdp/API_Audio.c')
-rw-r--r-- | drivers/mxc/hdp/API_Audio.c | 432 |
1 files changed, 432 insertions, 0 deletions
diff --git a/drivers/mxc/hdp/API_Audio.c b/drivers/mxc/hdp/API_Audio.c new file mode 100644 index 000000000000..b49b0765ae07 --- /dev/null +++ b/drivers/mxc/hdp/API_Audio.c @@ -0,0 +1,432 @@ +/****************************************************************************** + * + * Copyright (C) 2016-2017 Cadence Design Systems, Inc. + * All rights reserved worldwide. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Copyright 2017 NXP + * + ****************************************************************************** + * + * API_Audio.c + * + ****************************************************************************** + */ +#include "address.h" +#include "aif_pckt2smp.h" +#include "API_Audio.h" +#include "API_DPTX.h" +#include "API_General.h" +#include "clock_meters.h" +#include "dptx_stream.h" +#include "dptx_framer.h" +#include "source_aif_decoder.h" +#include "source_aif_smpl2pckt.h" +#include "source_car.h" +#include "util.h" + +CDN_API_STATUS CDN_API_AudioMute(state_struct *state, AUDIO_MUTE_MODE mode) +{ + return (CDN_API_General_Write_Field + (state, ADDR_DPTX_STREAM + (DP_VB_ID << 2), 4, 1, + (1 - mode) << 4)); +} + +CDN_API_STATUS CDN_API_AudioMute_blocking(state_struct *state, + AUDIO_MUTE_MODE mode) +{ + internal_block_function(&state->mutex, CDN_API_AudioMute(state, mode)); +} + +CDN_API_STATUS CDN_API_AudioMode(state_struct *state, AUDIO_MODE mode) +{ + return (CDN_API_General_Write_Register + (state, ADDR_DPTX_FRAMER + (AUDIO_PACK_CONTROL << 2), + F_AUDIO_PACK_EN(mode))); +} + +CDN_API_STATUS CDN_API_AudioMode_blocking(state_struct *state, AUDIO_MODE mode) +{ + internal_block_function(&state->mutex, CDN_API_AudioMode(state, mode)); +} + +CDN_API_STATUS CDN_API_AudioConfigCore(state_struct *state, + AUDIO_TYPE audioType, int numOfChannels, + AUDIO_FREQ freq, int lanes, + AUDIO_WIDTH width) +{ + int i; + int lanesParam; + u32 I2S_DEC_PORT_EN_Val; + + if (numOfChannels == 2) { + if (lanes == 1) + lanesParam = 1; + else + lanesParam = 3; + } else + lanesParam = 0; + + if (audioType == AUDIO_TYPE_I2S) { + cdn_apb_write(state, + ADDR_SOURCE_AIF_DECODER + (AUDIO_SRC_CNFG << 2), + 0x20000); + cdn_apb_write(state, + ADDR_SOURCE_AIF_SMPL2PCKT + (FIFO_CNTL << 2), 2); + cdn_apb_write(state, + ADDR_SOURCE_AIF_SMPL2PCKT + (SMPL2PKT_CNFG << 2), + F_MAX_NUM_CH(numOfChannels - 1) | + F_NUM_OF_I2S_PORTS_S((numOfChannels / 2) - 1) | + (1 << 8) | (lanesParam << 11)); + + if (numOfChannels == 2) + I2S_DEC_PORT_EN_Val = 1; + else if (numOfChannels == 4) + I2S_DEC_PORT_EN_Val = 3; + else + I2S_DEC_PORT_EN_Val = 0xF; + + /* 24 bit configuration + number of channels according to config */ + cdn_apb_write(state, + ADDR_SOURCE_AIF_DECODER + (AUDIO_SRC_CNFG << 2), + 0x01000 | F_AUDIO_SAMPLE_WIDTH(width) | + F_AUDIO_CH_NUM(numOfChannels - 1) | + F_I2S_DEC_PORT_EN(I2S_DEC_PORT_EN_Val)); + + for (i = 0; i < (numOfChannels + 1) / 2; i++) { + cdn_apb_write(state, ADDR_SOURCE_AIF_DECODER + + ((STTS_BIT_CH01 + i) << 2), + F_WORD_LENGTH_CH0(0x2) | + F_WORD_LENGTH_CH1(0x2) | + F_CHANNEL_NUM_CH0(i * 2) | + F_CHANNEL_NUM_CH1((i * 2) + 1)); + } + + /*set ch status bits */ + switch (freq) { + + case AUDIO_FREQ_32: + cdn_apb_write(state, ADDR_SOURCE_AIF_DECODER + + (COM_CH_STTS_BITS << 2), + 4 | F_SAMPLING_FREQ(0x3) | + F_ORIGINAL_SAMP_FREQ(0xC)); + break; + case AUDIO_FREQ_192: + cdn_apb_write(state, ADDR_SOURCE_AIF_DECODER + + (COM_CH_STTS_BITS << 2), + 4 | F_SAMPLING_FREQ(0xE) | + F_ORIGINAL_SAMP_FREQ(0x1)); + break; + + case AUDIO_FREQ_48: + cdn_apb_write(state, ADDR_SOURCE_AIF_DECODER + + (COM_CH_STTS_BITS << 2), + 4 | F_SAMPLING_FREQ(0x2) | + F_ORIGINAL_SAMP_FREQ(0xD)); + break; + case AUDIO_FREQ_96: + cdn_apb_write(state, ADDR_SOURCE_AIF_DECODER + + (COM_CH_STTS_BITS << 2), + 4 | F_SAMPLING_FREQ(0xA) | + F_ORIGINAL_SAMP_FREQ(0x5)); + break; + case AUDIO_FREQ_44_1: + cdn_apb_write(state, ADDR_SOURCE_AIF_DECODER + + (COM_CH_STTS_BITS << 2), + 4 | F_SAMPLING_FREQ(0x0) | + F_ORIGINAL_SAMP_FREQ(0xF)); + break; + case AUDIO_FREQ_88_2: + cdn_apb_write(state, ADDR_SOURCE_AIF_DECODER + + (COM_CH_STTS_BITS << 2), + 4 | F_SAMPLING_FREQ(0x8) | + F_ORIGINAL_SAMP_FREQ(0x7)); + break; + case AUDIO_FREQ_176_4: + cdn_apb_write(state, ADDR_SOURCE_AIF_DECODER + + (COM_CH_STTS_BITS << 2), + 4 | F_SAMPLING_FREQ(0xC) | + F_ORIGINAL_SAMP_FREQ(0x3)); + break; + } + + /* Enable I2S encoder */ + cdn_apb_write(state, + ADDR_SOURCE_AIF_DECODER + (AUDIO_SRC_CNTL << 2), 2); + /* Enable smpl2pkt */ + cdn_apb_write(state, + ADDR_SOURCE_AIF_SMPL2PCKT + (SMPL2PKT_CNTL << 2), 2); + } else { + + /* set spidif 2c en */ + cdn_apb_write(state, + ADDR_SOURCE_AIF_DECODER + (SPDIF_CTRL_ADDR << 2), + 0x1F0707); + cdn_apb_write(state, + ADDR_SOURCE_AIF_SMPL2PCKT + (FIFO_CNTL << 2), 2); + cdn_apb_write(state, + ADDR_SOURCE_AIF_SMPL2PCKT + (SMPL2PKT_CNFG << 2), + 0x101 | (lanesParam << 11)); + cdn_apb_write(state, + ADDR_SOURCE_AIF_SMPL2PCKT + (SMPL2PKT_CNTL << 2), 2); + cdn_apb_write(state, + ADDR_SOURCE_AIF_DECODER + (SPDIF_CTRL_ADDR << 2), + 0x3F0707); + } + return CDN_OK; +} + +CDN_API_STATUS CDN_API_AudioConfigCore_blocking(state_struct *state, + AUDIO_TYPE audioType, + int numOfChannels, + AUDIO_FREQ freq, int lanes, + AUDIO_WIDTH width) +{ + internal_block_function(&state->mutex, CDN_API_AudioConfigCore + (state, audioType, numOfChannels, freq, lanes, + width)); +} + +CDN_API_STATUS CDN_API_AudioAutoConfig(state_struct *state, + AUDIO_TYPE audioType, int numOfChannels, + AUDIO_FREQ freq, int lanes, + AUDIO_WIDTH width, + CDN_PROTOCOL_TYPE protocol, int ncts, + AUDIO_MUTE_MODE mode) +{ + + CDN_API_STATUS ret = CDN_BSY; + u32 REF_CYC_Val; + + switch (state->tmp) { + case 0: + if (protocol == CDN_DPTX) { + ret = + CDN_API_General_Write_Register(state, + ADDR_DPTX_FRAMER + + (AUDIO_PACK_STATUS << + 2), 0x11 << 16); + } else { + ret = CDN_OK; + } + break; + + case 1: + if (protocol == CDN_DPTX) { + REF_CYC_Val = 0x8000; + ret = + CDN_API_General_Write_Register(state, + ADDR_CLOCK_METERS + + (CM_LANE_CTRL << 2), + REF_CYC_Val); + } else { + /* hdmi mode */ + ret = + CDN_API_General_Write_Register(state, + ADDR_CLOCK_METERS + + (CM_CTRL << 2), 8); + + } + break; + case 2: + if ((protocol == CDN_HDMITX_TYPHOON) + || (protocol == CDN_HDMITX_KIRAN)) { + ret = + CDN_API_General_Write_Register(state, + ADDR_CLOCK_METERS + + (CM_I2S_CTRL << 2), + ncts | 0x4000000); + } else { + ret = CDN_OK; + } + + break; + + case 3: + if ((protocol == CDN_HDMITX_TYPHOON) + || (protocol == CDN_HDMITX_KIRAN)) { + ret = CDN_OK; + } else { + /* in dptx set audio on in dp framer */ + ret = CDN_API_AudioMode(state, 1); + } + break; + + case 4: + /* set car audio on _not reset */ + if (protocol == CDN_DPTX) { + /* TODO DK: try to merge case 3 and 4 */ + ret = CDN_OK; + } else { + ret = CDN_OK; + } + break; + + case 5: + if ((protocol == CDN_DPTX) && (audioType != AUDIO_TYPE_I2S)) { + ret = + CDN_API_General_Write_Register(state, + ADDR_SOURCE_CAR + + (SOURCE_AIF_CAR << + 2), 0xff); + } else { + ret = CDN_OK; + } + break; + case 6: + if (protocol == CDN_DPTX) { + ret = + CDN_API_General_Write_Register(state, + ADDR_CLOCK_METERS + + (CM_CTRL << 2), 0); + } else { + ret = CDN_OK; + } + break; + + case 7: + ret = + CDN_API_AudioConfigCore(state, audioType, numOfChannels, + freq, lanes, width); + break; + } + if (!state->tmp && ret == CDN_STARTED) + return CDN_STARTED; + switch (ret) { + case CDN_OK: + state->tmp++; + break; + case CDN_STARTED: + return CDN_BSY; + break; + default: + return ret; + } + if (state->tmp == 9) { + state->tmp = 0; + return CDN_OK; + } + return CDN_BSY; + +} + +CDN_API_STATUS CDN_API_AudioAutoConfig_blocking(state_struct *state, + AUDIO_TYPE audioType, + int numOfChannels, + AUDIO_FREQ freq, int lanes, + AUDIO_WIDTH width, + CDN_PROTOCOL_TYPE protocol, + int ncts, AUDIO_MUTE_MODE mode) +{ + internal_block_function(&state->mutex, CDN_API_AudioAutoConfig + (state, audioType, numOfChannels, freq, lanes, + width, protocol, ncts, mode)); +} + +CDN_API_STATUS CDN_API_AudioOff(state_struct *state, AUDIO_TYPE audioType) +{ + CDN_API_STATUS ret = CDN_BSY; + + switch (state->tmp) { + case 0: + cdn_apb_write(state, + ADDR_SOURCE_AIF_DECODER + (SPDIF_CTRL_ADDR << 2), + 0x1F0707); + cdn_apb_write(state, + ADDR_SOURCE_AIF_DECODER + (AUDIO_SRC_CNTL << 2), + 0); + cdn_apb_write(state, + ADDR_SOURCE_AIF_DECODER + (AUDIO_SRC_CNFG << 2), + 0); + cdn_apb_write(state, + ADDR_SOURCE_AIF_DECODER + (AUDIO_SRC_CNTL << 2), + 1); + cdn_apb_write(state, + ADDR_SOURCE_AIF_DECODER + (AUDIO_SRC_CNTL << 2), + 0); + cdn_apb_write(state, + ADDR_SOURCE_AIF_SMPL2PCKT + (SMPL2PKT_CNTL << 2), + 0); + cdn_apb_write(state, + ADDR_SOURCE_AIF_SMPL2PCKT + (SMPL2PKT_CNTL << 2), + 1); + cdn_apb_write(state, + ADDR_SOURCE_AIF_SMPL2PCKT + (SMPL2PKT_CNTL << 2), + 0); + cdn_apb_write(state, + ADDR_SOURCE_AIF_SMPL2PCKT + (FIFO_CNTL << 2), 1); + cdn_apb_write(state, + ADDR_SOURCE_AIF_SMPL2PCKT + (FIFO_CNTL << 2), 0); + ret = CDN_OK; + + break; + case 1: + ret = + CDN_API_General_Write_Register(state, ADDR_SOURCE_CAR + + (SOURCE_AIF_CAR << 2), 0x5f); + break; + case 2: + ret = + CDN_API_General_Write_Register(state, ADDR_SOURCE_CAR + + (SOURCE_AIF_CAR << 2), 0x0f); + break; + case 3: + ret = CDN_OK; + break; + } + + if (!state->tmp && ret == CDN_STARTED) + return CDN_STARTED; + switch (ret) { + case CDN_OK: + state->tmp++; + break; + case CDN_STARTED: + return CDN_BSY; + break; + default: + return ret; + } + if (state->tmp == 4) { + state->tmp = 0; + return CDN_OK; + } + return CDN_BSY; +} + +CDN_API_STATUS CDN_API_AudioOff_blocking(state_struct *state, + AUDIO_TYPE audioType) +{ + internal_block_function(&state->mutex, CDN_API_AudioOff(state, audioType)); +} |