/** * 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); }
static void tda998x_write_aif(struct tda998x_priv *priv, struct tda998x_encoder_params *p) { union hdmi_infoframe frame; hdmi_audio_infoframe_init(&frame.audio); frame.audio.channels = p->audio_frame[1] & 0x07; frame.audio.channel_allocation = p->audio_frame[4]; frame.audio.level_shift_value = (p->audio_frame[5] & 0x78) >> 3; frame.audio.downmix_inhibit = (p->audio_frame[5] & 0x80) >> 7; /* * L-PCM and IEC61937 compressed audio shall always set sample * frequency to "refer to stream". For others, see the HDMI * specification. */ frame.audio.sample_frequency = (p->audio_frame[2] & 0x1c) >> 2; tda998x_write_if(priv, DIP_IF_FLAGS_IF4, REG_IF4_HB0, &frame); }
/* * 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); }
/* Second part of initialization, the drm/kms level modeset_init, * constructs/initializes mode objects, etc, is called from master * driver (not hdmi sub-device's probe/bind!) * * Any resource (regulator/clk/etc) which could be missing at boot * should be handled in msm_hdmi_init() so that failure happens from * hdmi sub-device's probe. */ int msm_hdmi_modeset_init(struct hdmi *hdmi, struct drm_device *dev, struct drm_encoder *encoder) { struct msm_drm_private *priv = dev->dev_private; struct platform_device *pdev = hdmi->pdev; int ret; hdmi->dev = dev; hdmi->encoder = encoder; hdmi_audio_infoframe_init(&hdmi->audio.infoframe); hdmi->bridge = msm_hdmi_bridge_init(hdmi); if (IS_ERR(hdmi->bridge)) { ret = PTR_ERR(hdmi->bridge); dev_err(dev->dev, "failed to create HDMI bridge: %d\n", ret); hdmi->bridge = NULL; goto fail; } hdmi->connector = msm_hdmi_connector_init(hdmi); if (IS_ERR(hdmi->connector)) { ret = PTR_ERR(hdmi->connector); dev_err(dev->dev, "failed to create HDMI connector: %d\n", ret); hdmi->connector = NULL; goto fail; } hdmi->irq = irq_of_parse_and_map(pdev->dev.of_node, 0); if (hdmi->irq < 0) { ret = hdmi->irq; dev_err(dev->dev, "failed to get irq: %d\n", ret); goto fail; } ret = devm_request_irq(&pdev->dev, hdmi->irq, msm_hdmi_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "hdmi_isr", hdmi); if (ret < 0) { dev_err(dev->dev, "failed to request IRQ%u: %d\n", hdmi->irq, ret); goto fail; } encoder->bridge = hdmi->bridge; priv->bridges[priv->num_bridges++] = hdmi->bridge; priv->connectors[priv->num_connectors++] = hdmi->connector; platform_set_drvdata(pdev, hdmi); return 0; fail: /* bridge is normally destroyed by drm: */ if (hdmi->bridge) { msm_hdmi_bridge_destroy(hdmi->bridge); hdmi->bridge = NULL; } if (hdmi->connector) { hdmi->connector->funcs->destroy(hdmi->connector); hdmi->connector = NULL; } return ret; }
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; }
/* initialize connector */ struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder) { struct hdmi *hdmi = NULL; struct msm_drm_private *priv = dev->dev_private; struct platform_device *pdev = priv->hdmi_pdev; struct hdmi_platform_config *config; int i, ret; if (!pdev) { dev_err(dev->dev, "no hdmi device\n"); ret = -ENXIO; goto fail; } config = pdev->dev.platform_data; hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL); if (!hdmi) { ret = -ENOMEM; goto fail; } kref_init(&hdmi->refcount); hdmi->dev = dev; hdmi->pdev = pdev; hdmi->config = config; hdmi->encoder = encoder; hdmi_audio_infoframe_init(&hdmi->audio.infoframe); /* not sure about which phy maps to which msm.. probably I miss some */ if (config->phy_init) hdmi->phy = config->phy_init(hdmi); else hdmi->phy = ERR_PTR(-ENXIO); if (IS_ERR(hdmi->phy)) { ret = PTR_ERR(hdmi->phy); dev_err(dev->dev, "failed to load phy: %d\n", ret); hdmi->phy = NULL; goto fail; } hdmi->mmio = msm_ioremap(pdev, config->mmio_name, "HDMI"); if (IS_ERR(hdmi->mmio)) { ret = PTR_ERR(hdmi->mmio); goto fail; } BUG_ON(config->hpd_reg_cnt > ARRAY_SIZE(hdmi->hpd_regs)); for (i = 0; i < config->hpd_reg_cnt; i++) { struct regulator *reg; reg = devm_regulator_get(&pdev->dev, config->hpd_reg_names[i]); if (IS_ERR(reg)) { ret = PTR_ERR(reg); dev_err(dev->dev, "failed to get hpd regulator: %s (%d)\n", config->hpd_reg_names[i], ret); goto fail; } hdmi->hpd_regs[i] = reg; } BUG_ON(config->pwr_reg_cnt > ARRAY_SIZE(hdmi->pwr_regs)); for (i = 0; i < config->pwr_reg_cnt; i++) { struct regulator *reg; reg = devm_regulator_get(&pdev->dev, config->pwr_reg_names[i]); if (IS_ERR(reg)) { ret = PTR_ERR(reg); dev_err(dev->dev, "failed to get pwr regulator: %s (%d)\n", config->pwr_reg_names[i], ret); goto fail; } hdmi->pwr_regs[i] = reg; } BUG_ON(config->hpd_clk_cnt > ARRAY_SIZE(hdmi->hpd_clks)); for (i = 0; i < config->hpd_clk_cnt; i++) { struct clk *clk; clk = devm_clk_get(&pdev->dev, config->hpd_clk_names[i]); if (IS_ERR(clk)) { ret = PTR_ERR(clk); dev_err(dev->dev, "failed to get hpd clk: %s (%d)\n", config->hpd_clk_names[i], ret); goto fail; } hdmi->hpd_clks[i] = clk; } BUG_ON(config->pwr_clk_cnt > ARRAY_SIZE(hdmi->pwr_clks)); for (i = 0; i < config->pwr_clk_cnt; i++) { struct clk *clk; clk = devm_clk_get(&pdev->dev, config->pwr_clk_names[i]); if (IS_ERR(clk)) { ret = PTR_ERR(clk); dev_err(dev->dev, "failed to get pwr clk: %s (%d)\n", config->pwr_clk_names[i], ret); goto fail; } hdmi->pwr_clks[i] = clk; } hdmi->i2c = hdmi_i2c_init(hdmi); if (IS_ERR(hdmi->i2c)) { ret = PTR_ERR(hdmi->i2c); dev_err(dev->dev, "failed to get i2c: %d\n", ret); hdmi->i2c = NULL; goto fail; } hdmi->bridge = hdmi_bridge_init(hdmi); if (IS_ERR(hdmi->bridge)) { ret = PTR_ERR(hdmi->bridge); dev_err(dev->dev, "failed to create HDMI bridge: %d\n", ret); hdmi->bridge = NULL; goto fail; } hdmi->connector = hdmi_connector_init(hdmi); if (IS_ERR(hdmi->connector)) { ret = PTR_ERR(hdmi->connector); dev_err(dev->dev, "failed to create HDMI connector: %d\n", ret); hdmi->connector = NULL; goto fail; } if (!config->shared_irq) { hdmi->irq = platform_get_irq(pdev, 0); if (hdmi->irq < 0) { ret = hdmi->irq; dev_err(dev->dev, "failed to get irq: %d\n", ret); goto fail; } ret = devm_request_threaded_irq(&pdev->dev, hdmi->irq, NULL, hdmi_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "hdmi_isr", hdmi); if (ret < 0) { dev_err(dev->dev, "failed to request IRQ%u: %d\n", hdmi->irq, ret); goto fail; } } encoder->bridge = hdmi->bridge; priv->bridges[priv->num_bridges++] = hdmi->bridge; priv->connectors[priv->num_connectors++] = hdmi->connector; platform_set_drvdata(pdev, hdmi); return hdmi; fail: if (hdmi) { /* bridge/connector are normally destroyed by drm: */ if (hdmi->bridge) hdmi->bridge->funcs->destroy(hdmi->bridge); if (hdmi->connector) hdmi->connector->funcs->destroy(hdmi->connector); hdmi_destroy(&hdmi->refcount); } return ERR_PTR(ret); }