summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormohit singh <mpsingh@nvidia.com>2011-02-21 20:41:40 +0530
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:44:58 -0800
commit67aa36027995922c88e2204c101922931441d611 (patch)
tree487242f682d75eba8f9ed9f50e82beb26fb85556
parent93e875914dd058ee0051766d75346cbaf23fd301 (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.c169
-rw-r--r--drivers/video/tegra/dc/hdmi.h17
-rw-r--r--drivers/video/tegra/dc/hdmi_reg.h8
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)