/** * r600_hdmi_update_audio_settings - Update audio infoframe * * @encoder: drm encoder * * Gets info about current audio stream and updates audio infoframe. */ void r600_hdmi_update_audio_settings(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; struct r600_audio_pin audio = r600_audio_status(rdev); uint8_t buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AUDIO_INFOFRAME_SIZE]; struct hdmi_audio_infoframe frame; uint32_t offset; uint32_t value; ssize_t err; if (!dig->afmt || !dig->afmt->enabled) return; offset = dig->afmt->offset; DRM_DEBUG("%s with %d channels, %d Hz sampling rate, %d bits per sample,\n", r600_hdmi_is_audio_buffer_filled(encoder) ? "playing" : "stopped", audio.channels, audio.rate, audio.bits_per_sample); DRM_DEBUG("0x%02X IEC60958 status bits and 0x%02X category code\n", (int)audio.status_bits, (int)audio.category_code); err = hdmi_audio_infoframe_init(&frame); if (err < 0) { DRM_ERROR("failed to setup audio infoframe\n"); return; } frame.channels = audio.channels; err = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer)); if (err < 0) { DRM_ERROR("failed to pack audio infoframe\n"); return; } value = RREG32(HDMI0_AUDIO_PACKET_CONTROL + offset); if (value & HDMI0_AUDIO_TEST_EN) WREG32(HDMI0_AUDIO_PACKET_CONTROL + offset, value & ~HDMI0_AUDIO_TEST_EN); WREG32_OR(HDMI0_CONTROL + offset, HDMI0_ERROR_ACK); WREG32_AND(HDMI0_INFOFRAME_CONTROL0 + offset, ~HDMI0_AUDIO_INFO_SOURCE); r600_hdmi_update_audio_infoframe(encoder, buffer, sizeof(buffer)); WREG32_OR(HDMI0_INFOFRAME_CONTROL0 + offset, HDMI0_AUDIO_INFO_CONT | HDMI0_AUDIO_INFO_UPDATE); }
/* * update settings with current parameters from audio engine */ void r600_hdmi_update_audio_settings(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; struct r600_audio audio = r600_audio_status(rdev); uint8_t buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AUDIO_INFOFRAME_SIZE]; struct hdmi_audio_infoframe frame; uint32_t offset; uint32_t iec; ssize_t err; if (!dig->afmt || !dig->afmt->enabled) return; offset = dig->afmt->offset; DRM_DEBUG("%s with %d channels, %d Hz sampling rate, %d bits per sample,\n", r600_hdmi_is_audio_buffer_filled(encoder) ? "playing" : "stopped", audio.channels, audio.rate, audio.bits_per_sample); DRM_DEBUG("0x%02X IEC60958 status bits and 0x%02X category code\n", (int)audio.status_bits, (int)audio.category_code); iec = 0; if (audio.status_bits & AUDIO_STATUS_PROFESSIONAL) iec |= 1 << 0; if (audio.status_bits & AUDIO_STATUS_NONAUDIO) iec |= 1 << 1; if (audio.status_bits & AUDIO_STATUS_COPYRIGHT) iec |= 1 << 2; if (audio.status_bits & AUDIO_STATUS_EMPHASIS) iec |= 1 << 3; iec |= HDMI0_60958_CS_CATEGORY_CODE(audio.category_code); switch (audio.rate) { case 32000: iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0x3); break; case 44100: iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0x0); break; case 48000: iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0x2); break; case 88200: iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0x8); break; case 96000: iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0xa); break; case 176400: iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0xc); break; case 192000: iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0xe); break; } WREG32(HDMI0_60958_0 + offset, iec); iec = 0; switch (audio.bits_per_sample) { case 16: iec |= HDMI0_60958_CS_WORD_LENGTH(0x2); break; case 20: iec |= HDMI0_60958_CS_WORD_LENGTH(0x3); break; case 24: iec |= HDMI0_60958_CS_WORD_LENGTH(0xb); break; } if (audio.status_bits & AUDIO_STATUS_V) iec |= 0x5 << 16; WREG32_P(HDMI0_60958_1 + offset, iec, ~0x5000f); err = hdmi_audio_infoframe_init(&frame); if (err < 0) { DRM_ERROR("failed to setup audio infoframe\n"); return; } frame.channels = audio.channels; err = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer)); if (err < 0) { DRM_ERROR("failed to pack audio infoframe\n"); return; } r600_hdmi_update_audio_infoframe(encoder, buffer, sizeof(buffer)); r600_hdmi_audio_workaround(encoder); }
static int sii9022_audio_start(struct snd_soc_dai *dai, struct snd_pcm_hw_params *params) { struct panel_drv_data *dd = dev_get_drvdata(dai->dev); u8 i2s_config_reg = TPI_I2S_SD_DIRECTION_MSB_FIRST; u8 config_byte3_reg = TPI_AUDIO_CHANNEL_STREAM; u8 i2s_strm_hdr_reg[5] = { IEC958_AES0_CON_NOT_COPYRIGHT, IEC958_AES1_CON_GENERAL, IEC958_AES2_CON_SOURCE_UNSPEC, IEC958_AES3_CON_CLOCK_VARIABLE, 0 }; u8 infoframe_buf[HDMI_INFOFRAME_SIZE(AUDIO)]; struct hdmi_audio_infoframe infoframe; int ret, i; hdmi_audio_infoframe_init(&infoframe); dd->audio->channels = params_channels(params); switch (dd->audio->fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: break; default: dev_err(dai->dev, "Unsupported daifmt (0x%x) master\n", dd->audio->fmt); return -EINVAL; } switch (dd->audio->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: i2s_config_reg |= TPI_I2S_FIRST_BIT_SHIFT_YES | TPI_I2S_SD_JUSTIFY_LEFT; break; case SND_SOC_DAIFMT_LEFT_J: i2s_config_reg |= TPI_I2S_SD_JUSTIFY_LEFT; break; case SND_SOC_DAIFMT_RIGHT_J: i2s_config_reg |= TPI_I2S_SD_JUSTIFY_RIGHT; break; default: dev_err(dai->dev, "Unsupported daifmt (0x%x) format\n", dd->audio->fmt); return -EINVAL; } switch (dd->audio->fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_NB_NF: i2s_config_reg |= TPI_I2S_WS_POLARITY_HIGH | TPI_I2S_SCK_EDGE_RISING; break; case SND_SOC_DAIFMT_IB_NF: i2s_config_reg |= TPI_I2S_WS_POLARITY_HIGH | TPI_I2S_SCK_EDGE_FALLING; break; case SND_SOC_DAIFMT_NB_IF: i2s_config_reg |= TPI_I2S_WS_POLARITY_LOW | TPI_I2S_SCK_EDGE_RISING; break; case SND_SOC_DAIFMT_IB_IF: i2s_config_reg |= TPI_I2S_WS_POLARITY_LOW | TPI_I2S_SCK_EDGE_FALLING; break; } switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: config_byte3_reg |= TPI_AUDIO_SAMPLE_SIZE_16; i2s_strm_hdr_reg[4] |= IEC958_AES4_CON_WORDLEN_20_16; infoframe.sample_size = HDMI_AUDIO_SAMPLE_SIZE_16; break; case SNDRV_PCM_FORMAT_S20_3LE: config_byte3_reg |= TPI_AUDIO_SAMPLE_SIZE_20; i2s_strm_hdr_reg[4] |= IEC958_AES4_CON_WORDLEN_24_20; infoframe.sample_size = HDMI_AUDIO_SAMPLE_SIZE_20; break; case SNDRV_PCM_FORMAT_S24_3LE: case SNDRV_PCM_FORMAT_S24_LE: case SNDRV_PCM_FORMAT_S32_LE: config_byte3_reg |= TPI_AUDIO_SAMPLE_SIZE_24; i2s_strm_hdr_reg[4] |= IEC958_AES4_CON_MAX_WORDLEN_24 | IEC958_AES4_CON_WORDLEN_24_20; infoframe.sample_size = HDMI_AUDIO_SAMPLE_SIZE_24; break; default: dev_err(dai->dev, "Unsupported sample format %d\n", params_format(params)); return -EINVAL; } ret = sii9022_select_mclk_div(&i2s_config_reg, params_rate(params), dd->audio->mclk); if (ret) dev_warn(dai->dev, "Inaccurate reference clock (%u/%d != %u)\n", dd->audio->mclk, ret, params_rate(params)); switch (params_rate(params)) { case 32000: i2s_strm_hdr_reg[3] |= IEC958_AES3_CON_FS_32000; i2s_strm_hdr_reg[4] |= IEC958_AES4_CON_ORIGFS_32000; infoframe.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_32000; break; case 44100: i2s_strm_hdr_reg[3] |= IEC958_AES3_CON_FS_44100; i2s_strm_hdr_reg[4] |= IEC958_AES4_CON_ORIGFS_44100; infoframe.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_44100; break; case 48000: i2s_strm_hdr_reg[3] |= IEC958_AES3_CON_FS_48000; i2s_strm_hdr_reg[4] |= IEC958_AES4_CON_ORIGFS_48000; infoframe.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_48000; break; case 88200: i2s_strm_hdr_reg[3] |= IEC958_AES3_CON_FS_88200; i2s_strm_hdr_reg[4] |= IEC958_AES4_CON_ORIGFS_88200; infoframe.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_88200; break; case 96000: i2s_strm_hdr_reg[3] |= IEC958_AES3_CON_FS_96000; i2s_strm_hdr_reg[4] |= IEC958_AES4_CON_ORIGFS_96000; infoframe.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_96000; break; case 176400: i2s_strm_hdr_reg[3] |= IEC958_AES3_CON_FS_176400; i2s_strm_hdr_reg[4] |= IEC958_AES4_CON_ORIGFS_176400; infoframe.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_176400; break; case 192000: i2s_strm_hdr_reg[3] |= IEC958_AES3_CON_FS_192000; i2s_strm_hdr_reg[4] |= IEC958_AES4_CON_ORIGFS_192000; infoframe.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_192000; break; default: dev_err(dai->dev, "Unsupported sample rate %d\n", params_rate(params)); return -EINVAL; } ret = sii9022_mute(dai, true); if (ret < 0) return ret; regmap_write(dd->regmap, HDMI_TPI_I2S_INPUT_CONFIG_REG, i2s_config_reg); for (i = 0; i < ARRAY_SIZE(dd->audio->i2s_fifo_routing); i++) regmap_write(dd->regmap, HDMI_TPI_I2S_ENABLE_MAPPING_REG, dd->audio->i2s_fifo_routing[i]); regmap_write(dd->regmap, HDMI_TPI_AUDIO_CONFIG_BYTE3_REG, config_byte3_reg); regmap_bulk_write(dd->regmap, HDMI_TPI_I2S_STRM_HDR_BASE, i2s_strm_hdr_reg, ARRAY_SIZE(i2s_strm_hdr_reg)); infoframe.channels = params_channels(params); infoframe.coding_type = HDMI_AUDIO_CODING_TYPE_PCM; ret = hdmi_audio_infoframe_pack(&infoframe, infoframe_buf, sizeof(infoframe_buf)); if (ret < 0) { dev_err(dai->dev, "Failed to pack audio infoframe: %d\n", ret); return ret; } regmap_bulk_write(dd->regmap, HDMI_CPI_MISC_IF_SELECT_REG, infoframe_buf, ret); /* Decode Level 0 Packets */ regmap_write(dd->regmap, HDMI_IND_SET_PAGE, 0x02); regmap_write(dd->regmap, HDMI_IND_OFFSET, 0x24); regmap_write(dd->regmap, HDMI_IND_VALUE, 0x02); dev_dbg(dai->dev, "hdmi audio enabled\n"); return 0; }