diff options
author | mohit singh <mpsingh@nvidia.com> | 2011-02-21 20:41:40 +0530 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:44:58 -0800 |
commit | 67aa36027995922c88e2204c101922931441d611 (patch) | |
tree | 487242f682d75eba8f9ed9f50e82beb26fb85556 | |
parent | 93e875914dd058ee0051766d75346cbaf23fd301 (diff) |
arm: tegra: hdmi:audio freq and source selection.
- provided an API for selecting source and
audio freq.
- bug 790232.
Original-Change-Id: I693e7291085c7c7a3c26ef4daa9490c0b80d51df
Reviewed-on: http://git-master/r/20312
Tested-by: Mohit Singh <mpsingh@nvidia.com>
Reviewed-by: Dara Ramesh <dramesh@nvidia.com>
Reviewed-by: Scott Peterson <speterson@nvidia.com>
Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>
Original-Change-Id: Ibf2b5a7bd298a550f0d8490a9386cd5f8c10bdc0
Rebase-Id: R6f54f7b337c7ee744c8054a8e37bc5cc73fdcdc6
-rw-r--r-- | drivers/video/tegra/dc/hdmi.c | 169 | ||||
-rw-r--r-- | drivers/video/tegra/dc/hdmi.h | 17 | ||||
-rw-r--r-- | drivers/video/tegra/dc/hdmi_reg.h | 8 |
3 files changed, 168 insertions, 26 deletions
diff --git a/drivers/video/tegra/dc/hdmi.c b/drivers/video/tegra/dc/hdmi.c index 935c91e4fd9b..398ca9aba610 100644 --- a/drivers/video/tegra/dc/hdmi.c +++ b/drivers/video/tegra/dc/hdmi.c @@ -57,6 +57,8 @@ #define HDMI_ELD_MANF_NAME_INDEX 16 #define HDMI_ELD_PRODUCT_CODE_INDEX 18 #define HDMI_ELD_MONITOR_NAME_INDEX 20 + + struct tegra_dc_hdmi_data { struct tegra_dc *dc; struct tegra_edid *edid; @@ -75,10 +77,15 @@ struct tegra_dc_hdmi_data { bool suspended; bool hpd_pending; bool eld_retrieved; + bool clk_enabled; + unsigned audio_freq; + unsigned audio_source; bool dvi; }; +struct tegra_dc_hdmi_data *dc_hdmi; + const struct fb_videomode tegra_dc_hdmi_supported_modes[] = { /* 1280x720p 60hz: EIA/CEA-861-B Format 4 */ { @@ -249,32 +256,63 @@ struct tegra_hdmi_audio_config { unsigned pix_clock; unsigned n; unsigned cts; + unsigned aval; }; + const struct tegra_hdmi_audio_config tegra_hdmi_audio_32k[] = { - {25200000, 4096, 25250}, - {27000000, 4096, 27000}, - {54000000, 4096, 54000}, - {74250000, 4096, 74250}, - {148500000, 4096, 148500}, + {25200000, 4096, 25200, 24000}, + {27000000, 4096, 27000, 24000}, + {74250000, 4096, 74250, 24000}, + {148500000, 4096, 148500, 24000}, {0, 0, 0}, }; const struct tegra_hdmi_audio_config tegra_hdmi_audio_44_1k[] = { - {25200000, 14112, 63125}, - {27000000, 6272, 30000}, - {54000000, 6272, 60000}, - {74250000, 6272, 82500}, - {148500000, 6272, 165000}, + {25200000, 5880, 26250, 25000}, + {27000000, 5880, 28125, 25000}, + {74250000, 4704, 61875, 20000}, + {148500000, 4704, 123750, 20000}, {0, 0, 0}, }; const struct tegra_hdmi_audio_config tegra_hdmi_audio_48k[] = { - {25200000, 6144, 25250}, - {27000000, 6144, 27000}, - {54000000, 6144, 54000}, - {74250000, 6144, 74250}, - {148500000, 6144, 148500}, + {25200000, 6144, 25200, 24000}, + {27000000, 6144, 27000, 24000}, + {74250000, 6144, 74250, 24000}, + {148500000, 6144, 148500, 24000}, + {0, 0, 0}, +}; + +const struct tegra_hdmi_audio_config tegra_hdmi_audio_88_2k[] = { + {25200000, 11760, 26250, 25000}, + {27000000, 11760, 28125, 25000}, + {74250000, 9408, 61875, 20000}, + {148500000, 9408, 123750,20000}, + {0, 0, 0}, +}; + +const struct tegra_hdmi_audio_config tegra_hdmi_audio_96k[] = { + {25200000, 12288, 25200, 24000}, + {27000000, 12288, 27000, 24000}, + {74250000, 12288, 74250, 24000}, + {148500000, 12288, 148500, 24000}, + {0, 0, 0}, +}; + +const struct tegra_hdmi_audio_config tegra_hdmi_audio_176_4k[] = { + {25200000, 23520, 26250, 25000}, + {27000000, 23520, 28125, 25000}, + {74250000, 18816, 61875, 20000}, + {148500000, 18816, 123750, 20000}, + {0, 0, 0}, +}; + +const struct tegra_hdmi_audio_config tegra_hdmi_audio_192k[] = { + {25200000, 24576, 25200, 24000}, + {27000000, 24576, 27000, 24000}, + {74250000, 24576, 74250, 24000}, + {148500000, 24576, 148500, 24000}, {0, 0, 0}, }; @@ -284,18 +322,27 @@ static const struct tegra_hdmi_audio_config const struct tegra_hdmi_audio_config *table; switch (audio_freq) { - case 32000: + case AUDIO_FREQ_32K: table = tegra_hdmi_audio_32k; break; - - case 44100: + case AUDIO_FREQ_44_1K: table = tegra_hdmi_audio_44_1k; break; - - case 48000: + case AUDIO_FREQ_48K: table = tegra_hdmi_audio_48k; break; - + case AUDIO_FREQ_88_2K: + table = tegra_hdmi_audio_88_2k; + break; + case AUDIO_FREQ_96K: + table = tegra_hdmi_audio_96k; + break; + case AUDIO_FREQ_176_4K: + table = tegra_hdmi_audio_176_4k; + break; + case AUDIO_FREQ_192K: + table = tegra_hdmi_audio_192k; + break; default: return NULL; } @@ -741,12 +788,17 @@ static int tegra_dc_hdmi_init(struct tegra_dc *dc) hdmi->suspended = false; hdmi->hpd_pending = false; hdmi->eld_retrieved= false; + hdmi->clk_enabled = false; + hdmi->audio_freq = 44100; + hdmi->audio_source = AUTO; spin_lock_init(&hdmi->suspend_lock); dc->out->depth = 24; tegra_dc_set_outdata(dc, hdmi); + dc_hdmi = hdmi; + /* boards can select default content protection policy */ if (dc->out->flags & TEGRA_DC_OUT_NVHDCP_POLICY_ON_DEMAND) { tegra_nvhdcp_set_policy(hdmi->nvhdcp, @@ -906,16 +958,22 @@ static void tegra_dc_hdmi_setup_eld_buff(struct tegra_dc *dc) } #endif -static int tegra_dc_hdmi_setup_audio(struct tegra_dc *dc) +static int tegra_dc_hdmi_setup_audio(struct tegra_dc *dc, unsigned audio_freq, + unsigned audio_source) { struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc); const struct tegra_hdmi_audio_config *config; unsigned long audio_n; - unsigned audio_freq = 44100; /* TODO: find some way of configuring this */ + unsigned long reg_addr = 0; + unsigned a_source = AUDIO_CNTRL0_SOURCE_SELECT_AUTO; + if (HDA == audio_source) + a_source = AUDIO_CNTRL0_SOURCE_SELECT_HDAL; + else if (SPDIF == audio_source) + a_source = AUDIO_CNTRL0_SOURCE_SELECT_SPDIF; #if !defined(CONFIG_ARCH_TEGRA_2x_SOC) - tegra_hdmi_writel(hdmi,AUDIO_CNTRL0_SOURCE_SELECT_AUTO, + tegra_hdmi_writel(hdmi,a_source, HDMI_NV_PDISP_SOR_AUDIO_CNTRL0_0); tegra_hdmi_writel(hdmi, AUDIO_CNTRL0_ERROR_TOLERANCE(6) | @@ -925,7 +983,7 @@ static int tegra_dc_hdmi_setup_audio(struct tegra_dc *dc) tegra_hdmi_writel(hdmi, AUDIO_CNTRL0_ERROR_TOLERANCE(6) | AUDIO_CNTRL0_FRAMES_PER_BLOCK(0xc0) | - AUDIO_CNTRL0_SOURCE_SELECT_AUTO, + a_source, HDMI_NV_PDISP_AUDIO_CNTRL0); #endif config = tegra_hdmi_get_audio_config(audio_freq, dc->mode.pclk); @@ -955,11 +1013,69 @@ static int tegra_dc_hdmi_setup_audio(struct tegra_dc *dc) audio_n &= ~AUDIO_N_RESETF; tegra_hdmi_writel(hdmi, audio_n, HDMI_NV_PDISP_AUDIO_N); +#if !defined(CONFIG_ARCH_TEGRA_2x_SOC) + switch (audio_freq) { + case AUDIO_FREQ_32K: + reg_addr = HDMI_NV_PDISP_SOR_AUDIO_AVAL_0320_0; + break; + case AUDIO_FREQ_44_1K: + reg_addr = HDMI_NV_PDISP_SOR_AUDIO_AVAL_0441_0; + break; + case AUDIO_FREQ_48K: + reg_addr = HDMI_NV_PDISP_SOR_AUDIO_AVAL_0480_0; + break; + case AUDIO_FREQ_88_2K: + reg_addr = HDMI_NV_PDISP_SOR_AUDIO_AVAL_0882_0; + break; + case AUDIO_FREQ_96K: + reg_addr = HDMI_NV_PDISP_SOR_AUDIO_AVAL_0960_0; + break; + case AUDIO_FREQ_176_4K: + reg_addr = HDMI_NV_PDISP_SOR_AUDIO_AVAL_1764_0; + break; + case AUDIO_FREQ_192K: + reg_addr = HDMI_NV_PDISP_SOR_AUDIO_AVAL_1920_0; + break; + } + + _tegra_hdmi_writel(hdmi, config->aval, reg_addr); +#endif tegra_dc_hdmi_setup_audio_fs_tables(dc); return 0; } +int tegra_hdmi_setup_audio_freq_source(unsigned audio_freq, unsigned audio_source) +{ + struct tegra_dc_hdmi_data *hdmi = dc_hdmi; + + if (!hdmi) + return -EAGAIN; + + /* check for know freq */ + if (AUDIO_FREQ_32K == audio_freq || + AUDIO_FREQ_44_1K== audio_freq || + AUDIO_FREQ_48K== audio_freq || + AUDIO_FREQ_88_2K== audio_freq || + AUDIO_FREQ_96K== audio_freq || + AUDIO_FREQ_176_4K== audio_freq || + AUDIO_FREQ_192K== audio_freq) { + /* If we can program HDMI, then proceed */ + if (hdmi->clk_enabled) + tegra_dc_hdmi_setup_audio(hdmi->dc, audio_freq,audio_source); + else { + /* Store it for using it in enable */ + hdmi->audio_freq = audio_freq; + hdmi->audio_source = audio_source; + } + } + else + return -EINVAL; + + return 0; +} +EXPORT_SYMBOL(tegra_hdmi_setup_audio_freq_source); + static void tegra_dc_hdmi_write_infopack(struct tegra_dc *dc, int header_reg, u8 type, u8 version, void *data, int len) { @@ -1212,6 +1328,7 @@ static void tegra_dc_hdmi_enable(struct tegra_dc *dc) HDMI_NV_PDISP_SOR_REFCLK); + hdmi->clk_enabled = true; if (!hdmi->dvi) { err = tegra_dc_hdmi_setup_audio(dc); @@ -1351,8 +1468,8 @@ static void tegra_dc_hdmi_disable(struct tegra_dc *dc) tegra_hdmi_writel(hdmi, 0, HDMI_NV_PDISP_SOR_AUDIO_HDA_PRESENSE_0); #endif hdmi->eld_retrieved = false; - tegra_periph_reset_assert(hdmi->clk); + hdmi->clk_enabled = false; clk_disable(hdmi->clk); } diff --git a/drivers/video/tegra/dc/hdmi.h b/drivers/video/tegra/dc/hdmi.h index f726f41f8dbc..8757ad8dfde8 100644 --- a/drivers/video/tegra/dc/hdmi.h +++ b/drivers/video/tegra/dc/hdmi.h @@ -212,9 +212,26 @@ struct hdmi_stereo_infoframe { struct tegra_dc_hdmi_data; +enum { + AUDIO_FREQ_32K = 32000, + AUDIO_FREQ_44_1K = 44100, + AUDIO_FREQ_48K = 48000, + AUDIO_FREQ_88_2K = 88200, + AUDIO_FREQ_96K = 96000, + AUDIO_FREQ_176_4K = 176400, + AUDIO_FREQ_192K = 192000, +}; + +enum { + AUTO = 0, + SPDIF, + HDA, +}; + unsigned long tegra_hdmi_readl(struct tegra_dc_hdmi_data *hdmi, unsigned long reg); void tegra_hdmi_writel(struct tegra_dc_hdmi_data *hdmi, unsigned long val, unsigned long reg); +int tegra_hdmi_setup_audio_freq_source(unsigned audio_freq, unsigned audio_source); #endif diff --git a/drivers/video/tegra/dc/hdmi_reg.h b/drivers/video/tegra/dc/hdmi_reg.h index 4468d1dc951b..7de5d869b93a 100644 --- a/drivers/video/tegra/dc/hdmi_reg.h +++ b/drivers/video/tegra/dc/hdmi_reg.h @@ -391,6 +391,14 @@ #define HDMI_NV_PDISP_SOR_AUDIO_CNTRL0_0 0xac #define HDMI_NV_PDISP_SOR_AUDIO_HDA_ELD_BUFWR_0 0xbc #define HDMI_NV_PDISP_SOR_AUDIO_HDA_PRESENSE_0 0xbd +#define HDMI_NV_PDISP_SOR_AUDIO_AVAL_0320_0 0xbf +#define HDMI_NV_PDISP_SOR_AUDIO_AVAL_0441_0 0xc0 +#define HDMI_NV_PDISP_SOR_AUDIO_AVAL_0882_0 0xc1 +#define HDMI_NV_PDISP_SOR_AUDIO_AVAL_1764_0 0xc2 +#define HDMI_NV_PDISP_SOR_AUDIO_AVAL_0480_0 0xc3 +#define HDMI_NV_PDISP_SOR_AUDIO_AVAL_0960_0 0xc4 +#define HDMI_NV_PDISP_SOR_AUDIO_AVAL_1920_0 0xc5 +#define HDMI_NV_PDISP_SOR_AUDIO_AVAL_DEFAULT_0 0xc6 #endif #define AUDIO_CNTRL0_ERROR_TOLERANCE(x) (((x) & 0xff) << 0) #define AUDIO_CNTRL0_SOFT_RESET (1 << 8) |