Exemplo n.º 1
0
/**
 * 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);
}
Exemplo n.º 2
0
/*
 * 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;
}