aboutsummaryrefslogtreecommitdiff
path: root/drivers/video
diff options
context:
space:
mode:
authorRicardo Neri <ricardo.neri@ti.com>2011-04-05 16:05:18 -0500
committerTomi Valkeinen <tomi.valkeinen@ti.com>2011-05-19 15:18:04 +0300
commit82335c4cc2edf57afece9399441a7480c2a1b055 (patch)
treef01ab452f41ef8bd2b6d6206a9052d9548bdd001 /drivers/video
parent5d8dbe4aa986526f9096bcdb27679c37f5c7b194 (diff)
OMAP4: DSS2: HDMI: Add functionality for audio configuration
Add functionality for relevant audio configuration. Functions to configure the audio FIFO and DMA as well as functions for the audio core and Audio Info frame are included. This functionality is to be used by the ASoC HDMI audio codec. Signed-off-by: Ricardo Neri <ricardo.neri@ti.com> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/omap2/dss/hdmi.c215
1 files changed, 215 insertions, 0 deletions
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c
index 76e1142e4b6..0b209d38a10 100644
--- a/drivers/video/omap2/dss/hdmi.c
+++ b/drivers/video/omap2/dss/hdmi.c
@@ -1274,6 +1274,221 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev)
mutex_unlock(&hdmi.lock);
}
+#if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \
+ defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE)
+static void hdmi_wp_audio_config_format(
+ struct hdmi_audio_format *aud_fmt)
+{
+ u32 r;
+
+ DSSDBG("Enter hdmi_wp_audio_config_format\n");
+
+ r = hdmi_read_reg(HDMI_WP_AUDIO_CFG);
+ r = FLD_MOD(r, aud_fmt->stereo_channels, 26, 24);
+ r = FLD_MOD(r, aud_fmt->active_chnnls_msk, 23, 16);
+ r = FLD_MOD(r, aud_fmt->en_sig_blk_strt_end, 5, 5);
+ r = FLD_MOD(r, aud_fmt->type, 4, 4);
+ r = FLD_MOD(r, aud_fmt->justification, 3, 3);
+ r = FLD_MOD(r, aud_fmt->sample_order, 2, 2);
+ r = FLD_MOD(r, aud_fmt->samples_per_word, 1, 1);
+ r = FLD_MOD(r, aud_fmt->sample_size, 0, 0);
+ hdmi_write_reg(HDMI_WP_AUDIO_CFG, r);
+}
+
+static void hdmi_wp_audio_config_dma(struct hdmi_audio_dma *aud_dma)
+{
+ u32 r;
+
+ DSSDBG("Enter hdmi_wp_audio_config_dma\n");
+
+ r = hdmi_read_reg(HDMI_WP_AUDIO_CFG2);
+ r = FLD_MOD(r, aud_dma->transfer_size, 15, 8);
+ r = FLD_MOD(r, aud_dma->block_size, 7, 0);
+ hdmi_write_reg(HDMI_WP_AUDIO_CFG2, r);
+
+ r = hdmi_read_reg(HDMI_WP_AUDIO_CTRL);
+ r = FLD_MOD(r, aud_dma->mode, 9, 9);
+ r = FLD_MOD(r, aud_dma->fifo_threshold, 8, 0);
+ hdmi_write_reg(HDMI_WP_AUDIO_CTRL, r);
+}
+
+static void hdmi_core_audio_config(struct hdmi_core_audio_config *cfg)
+{
+ u32 r;
+
+ /* audio clock recovery parameters */
+ r = hdmi_read_reg(HDMI_CORE_AV_ACR_CTRL);
+ r = FLD_MOD(r, cfg->use_mclk, 2, 2);
+ r = FLD_MOD(r, cfg->en_acr_pkt, 1, 1);
+ r = FLD_MOD(r, cfg->cts_mode, 0, 0);
+ hdmi_write_reg(HDMI_CORE_AV_ACR_CTRL, r);
+
+ REG_FLD_MOD(HDMI_CORE_AV_N_SVAL1, cfg->n, 7, 0);
+ REG_FLD_MOD(HDMI_CORE_AV_N_SVAL2, cfg->n >> 8, 7, 0);
+ REG_FLD_MOD(HDMI_CORE_AV_N_SVAL3, cfg->n >> 16, 7, 0);
+
+ if (cfg->cts_mode == HDMI_AUDIO_CTS_MODE_SW) {
+ REG_FLD_MOD(HDMI_CORE_AV_CTS_SVAL1, cfg->cts, 7, 0);
+ REG_FLD_MOD(HDMI_CORE_AV_CTS_SVAL2, cfg->cts >> 8, 7, 0);
+ REG_FLD_MOD(HDMI_CORE_AV_CTS_SVAL3, cfg->cts >> 16, 7, 0);
+ } else {
+ /*
+ * HDMI IP uses this configuration to divide the MCLK to
+ * update CTS value.
+ */
+ REG_FLD_MOD(HDMI_CORE_AV_FREQ_SVAL, cfg->mclk_mode, 2, 0);
+
+ /* Configure clock for audio packets */
+ REG_FLD_MOD(HDMI_CORE_AV_AUD_PAR_BUSCLK_1,
+ cfg->aud_par_busclk, 7, 0);
+ REG_FLD_MOD(HDMI_CORE_AV_AUD_PAR_BUSCLK_2,
+ (cfg->aud_par_busclk >> 8), 7, 0);
+ REG_FLD_MOD(HDMI_CORE_AV_AUD_PAR_BUSCLK_3,
+ (cfg->aud_par_busclk >> 16), 7, 0);
+ }
+
+ /* Override of SPDIF sample frequency with value in I2S_CHST4 */
+ REG_FLD_MOD(HDMI_CORE_AV_SPDIF_CTRL, cfg->fs_override, 1, 1);
+
+ /* I2S parameters */
+ REG_FLD_MOD(HDMI_CORE_AV_I2S_CHST4, cfg->freq_sample, 3, 0);
+
+ r = hdmi_read_reg(HDMI_CORE_AV_I2S_IN_CTRL);
+ r = FLD_MOD(r, cfg->i2s_cfg.en_high_bitrate_aud, 7, 7);
+ r = FLD_MOD(r, cfg->i2s_cfg.sck_edge_mode, 6, 6);
+ r = FLD_MOD(r, cfg->i2s_cfg.cbit_order, 5, 5);
+ r = FLD_MOD(r, cfg->i2s_cfg.vbit, 4, 4);
+ r = FLD_MOD(r, cfg->i2s_cfg.ws_polarity, 3, 3);
+ r = FLD_MOD(r, cfg->i2s_cfg.justification, 2, 2);
+ r = FLD_MOD(r, cfg->i2s_cfg.direction, 1, 1);
+ r = FLD_MOD(r, cfg->i2s_cfg.shift, 0, 0);
+ hdmi_write_reg(HDMI_CORE_AV_I2S_IN_CTRL, r);
+
+ r = hdmi_read_reg(HDMI_CORE_AV_I2S_CHST5);
+ r = FLD_MOD(r, cfg->freq_sample, 7, 4);
+ r = FLD_MOD(r, cfg->i2s_cfg.word_length, 3, 1);
+ r = FLD_MOD(r, cfg->i2s_cfg.word_max_length, 0, 0);
+ hdmi_write_reg(HDMI_CORE_AV_I2S_CHST5, r);
+
+ REG_FLD_MOD(HDMI_CORE_AV_I2S_IN_LEN, cfg->i2s_cfg.in_length_bits, 3, 0);
+
+ /* Audio channels and mode parameters */
+ REG_FLD_MOD(HDMI_CORE_AV_HDMI_CTRL, cfg->layout, 2, 1);
+ r = hdmi_read_reg(HDMI_CORE_AV_AUD_MODE);
+ r = FLD_MOD(r, cfg->i2s_cfg.active_sds, 7, 4);
+ r = FLD_MOD(r, cfg->en_dsd_audio, 3, 3);
+ r = FLD_MOD(r, cfg->en_parallel_aud_input, 2, 2);
+ r = FLD_MOD(r, cfg->en_spdif, 1, 1);
+ hdmi_write_reg(HDMI_CORE_AV_AUD_MODE, r);
+}
+
+static void hdmi_core_audio_infoframe_config(
+ struct hdmi_core_infoframe_audio *info_aud)
+{
+ u8 val;
+ u8 sum = 0, checksum = 0;
+
+ /*
+ * Set audio info frame type, version and length as
+ * described in HDMI 1.4a Section 8.2.2 specification.
+ * Checksum calculation is defined in Section 5.3.5.
+ */
+ hdmi_write_reg(HDMI_CORE_AV_AUDIO_TYPE, 0x84);
+ hdmi_write_reg(HDMI_CORE_AV_AUDIO_VERS, 0x01);
+ hdmi_write_reg(HDMI_CORE_AV_AUDIO_LEN, 0x0a);
+ sum += 0x84 + 0x001 + 0x00a;
+
+ val = (info_aud->db1_coding_type << 4)
+ | (info_aud->db1_channel_count - 1);
+ hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(0), val);
+ sum += val;
+
+ val = (info_aud->db2_sample_freq << 2) | info_aud->db2_sample_size;
+ hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(1), val);
+ sum += val;
+
+ hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(2), 0x00);
+
+ val = info_aud->db4_channel_alloc;
+ hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(3), val);
+ sum += val;
+
+ val = (info_aud->db5_downmix_inh << 7) | (info_aud->db5_lsv << 3);
+ hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(4), val);
+ sum += val;
+
+ hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(5), 0x00);
+ hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(6), 0x00);
+ hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(7), 0x00);
+ hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(8), 0x00);
+ hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(9), 0x00);
+
+ checksum = 0x100 - sum;
+ hdmi_write_reg(HDMI_CORE_AV_AUDIO_CHSUM, checksum);
+
+ /*
+ * TODO: Add MPEG and SPD enable and repeat cfg when EDID parsing
+ * is available.
+ */
+}
+
+static int hdmi_config_audio_acr(u32 sample_freq, u32 *n, u32 *cts)
+{
+ u32 r;
+ u32 deep_color = 0;
+ u32 pclk = hdmi.cfg.timings.timings.pixel_clock;
+
+ if (n == NULL || cts == NULL)
+ return -EINVAL;
+ /*
+ * Obtain current deep color configuration. This needed
+ * to calculate the TMDS clock based on the pixel clock.
+ */
+ r = REG_GET(HDMI_WP_VIDEO_CFG, 1, 0);
+ switch (r) {
+ case 1: /* No deep color selected */
+ deep_color = 100;
+ break;
+ case 2: /* 10-bit deep color selected */
+ deep_color = 125;
+ break;
+ case 3: /* 12-bit deep color selected */
+ deep_color = 150;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (sample_freq) {
+ case 32000:
+ if ((deep_color == 125) && ((pclk == 54054)
+ || (pclk == 74250)))
+ *n = 8192;
+ else
+ *n = 4096;
+ break;
+ case 44100:
+ *n = 6272;
+ break;
+ case 48000:
+ if ((deep_color == 125) && ((pclk == 54054)
+ || (pclk == 74250)))
+ *n = 8192;
+ else
+ *n = 6144;
+ break;
+ default:
+ *n = 0;
+ return -EINVAL;
+ }
+
+ /* Calculate CTS. See HDMI 1.3a or 1.4a specifications */
+ *cts = pclk * (*n / 128) * deep_color / (sample_freq / 10);
+
+ return 0;
+}
+#endif
+
/* HDMI HW IP initialisation */
static int omapdss_hdmihw_probe(struct platform_device *pdev)
{