On Fri, May 23, 2014 at 1:34 PM, Dylan Reid <dgreid@xxxxxxxxxxxx> wrote: > On Fri, May 23, 2014 at 12:05 PM, Stephen Warren <swarren@xxxxxxxxxxxxx> wrote: >> On 05/22/2014 09:55 PM, Dylan Reid wrote: >> ... >>>>>>>>>> On Tue, May 20, 2014 at 2:55 PM, Stephen Warren <swarren@xxxxxxxxxxxxx> wrote: >> ... >>>>>>>>>>> Now I have the same results as Thierry; speaker-test looks like it >>>>>>>>>>> should be working, yet I don't hear any audio from the monitor. I know >>>>>>>>>>> the monitor works, since I've used it extensively for testing GeForce >>>>>>>>>>> GPU HDMI audio. >> ... >>> Took all day, but I did get to try this. >>> >>> on U-Boot commit d7782d0, flashed with Stephen's u-boot flasher from github. >>> >>> And kernel at 81d0207 - ARM: tegra: enable HD-Audio controller in defconfig >>> plus the addition of the hda node "okay" to the jetson-tk1 DT. >>> >>> I can hear the jetson's audio on the TV. This is currently a sample >>> size of one TV, I'll set up the Quantum Data tomorrow and check that >>> it works there as well. >> >> I tried that same U-Boot commit (with a few device-mode USB patches on >> top that shouldn't affect anything since I didn't use USB device mode) >> and have the same results. >> >> My monitor is a Dell U2410 with sound bar. I found one of these. I also didn't hear any audio. In fact I couldn't get audio out of most monitors, TV sets worked fine. hdmi.c couldn't configure audio for the pixel clock generated for the monitor. Luckily I found a patch in our downstream tree that fixes it. video: tegra: Calculate HDMI audio CTS/N/AVAL values -- 7/25/11 author swarren =) Thanks for fixing this for me! I can send this up unless you'd rather send it yourself. I appended the patch moved to the new location of hdmi.c: video: tegra: Calculate HDMI audio CTS/N/AVAL values The current table-drive approach for determining the CTS/N/AVAL values required for HDMI audio limits audio availability to a small set of pixel clock frequencies. Allow audio in other cases by calculating the CTS and N value dynamically where the tables don't contain pre-calculated values. --- drivers/gpu/drm/tegra/hdmi.c | 143 +++++++++++-------------------------------- 1 file changed, 35 insertions(+), 108 deletions(-) diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index fec1a63..453e515 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -9,6 +9,7 @@ #include <linux/clk.h> #include <linux/debugfs.h> +#include <linux/gcd.h> #include <linux/hdmi.h> #include <linux/regulator/consumer.h> #include <linux/reset.h> @@ -104,61 +105,34 @@ struct tegra_hdmi_audio_config { unsigned int aval; }; -static const struct tegra_hdmi_audio_config tegra_hdmi_audio_32k[] = { - { 25200000, 4096, 25200, 24000 }, - { 27000000, 4096, 27000, 24000 }, - { 74250000, 4096, 74250, 24000 }, - { 148500000, 4096, 148500, 24000 }, - { 0, 0, 0, 0 }, -}; - -static const struct tegra_hdmi_audio_config tegra_hdmi_audio_44_1k[] = { - { 25200000, 5880, 26250, 25000 }, - { 27000000, 5880, 28125, 25000 }, - { 74250000, 4704, 61875, 20000 }, - { 148500000, 4704, 123750, 20000 }, - { 0, 0, 0, 0 }, -}; - -static const struct tegra_hdmi_audio_config tegra_hdmi_audio_48k[] = { - { 25200000, 6144, 25200, 24000 }, - { 27000000, 6144, 27000, 24000 }, - { 74250000, 6144, 74250, 24000 }, - { 148500000, 6144, 148500, 24000 }, - { 0, 0, 0, 0 }, -}; - -static 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, 0 }, -}; - -static 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, 0 }, -}; +static int tegra_hdmi_calc_audio_cts_n(unsigned fs, unsigned pixel_rate, + unsigned *hda_cts, unsigned *hda_n, + unsigned *hda_aval) +{ + /* Ideal ACR interval is 1000 hz (1 ms) */ + unsigned n_ideal = (128 * fs) / 1000; + unsigned cts = pixel_rate; + unsigned n = 128 * fs; + unsigned common_divisor = gcd(cts, n); + unsigned mult; + + cts /= common_divisor; + n /= common_divisor; + mult = n_ideal / n; + if (mult) { + n *= mult; + cts *= mult; + } -static 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, 0 }, -}; + if (cts < (1 << 20)) { + *hda_cts = cts; + *hda_n = n; + *hda_aval = 240000UL * n / (128 * fs / 100); + return 0; + } -static 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, 0 }, -}; + return -EINVAL; +} static const struct tmds_config tegra20_tmds_config[] = { { /* slow pixel clock modes */ @@ -397,54 +371,6 @@ static const struct tmds_config tegra124_tmds_config[] = { }, }; -static const struct tegra_hdmi_audio_config * -tegra_hdmi_get_audio_config(unsigned int audio_freq, unsigned int pclk) -{ - const struct tegra_hdmi_audio_config *table; - - switch (audio_freq) { - case 32000: - table = tegra_hdmi_audio_32k; - break; - - case 44100: - table = tegra_hdmi_audio_44_1k; - break; - - case 48000: - table = tegra_hdmi_audio_48k; - break; - - case 88200: - table = tegra_hdmi_audio_88_2k; - break; - - case 96000: - table = tegra_hdmi_audio_96k; - break; - - case 176400: - table = tegra_hdmi_audio_176_4k; - break; - - case 192000: - table = tegra_hdmi_audio_192k; - break; - - default: - return NULL; - } - - while (table->pclk) { - if (table->pclk == pclk) - return table; - - table++; - } - - return NULL; -} - static void tegra_hdmi_setup_audio_fs_tables(struct tegra_hdmi *hdmi) { const unsigned int freqs[] = { @@ -475,7 +401,7 @@ static void tegra_hdmi_setup_audio_fs_tables(struct tegra_hdmi *hdmi) static int tegra_hdmi_setup_audio(struct tegra_hdmi *hdmi, unsigned int pclk) { struct device_node *node = hdmi->dev->of_node; - const struct tegra_hdmi_audio_config *config; + unsigned hda_n, hda_cts, hda_aval; unsigned int offset = 0; unsigned long value; @@ -506,8 +432,9 @@ static int tegra_hdmi_setup_audio(struct tegra_hdmi *hdmi, unsigned int pclk) tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_AUDIO_CNTRL0); } - config = tegra_hdmi_get_audio_config(hdmi->audio_freq, pclk); - if (!config) { + if (tegra_hdmi_calc_audio_cts_n(hdmi->audio_freq, + clk_get_rate(hdmi->clk), + &hda_cts, &hda_n, &hda_aval) < 0) { dev_err(hdmi->dev, "cannot set audio to %u at %u pclk\n", hdmi->audio_freq, pclk); return -EINVAL; @@ -516,13 +443,13 @@ static int tegra_hdmi_setup_audio(struct tegra_hdmi *hdmi, unsigned int pclk) tegra_hdmi_writel(hdmi, 0, HDMI_NV_PDISP_HDMI_ACR_CTRL); value = AUDIO_N_RESETF | AUDIO_N_GENERATE_ALTERNATE | - AUDIO_N_VALUE(config->n - 1); + AUDIO_N_VALUE(hda_n - 1); tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_AUDIO_N); - tegra_hdmi_writel(hdmi, ACR_SUBPACK_N(config->n) | ACR_ENABLE, + tegra_hdmi_writel(hdmi, ACR_SUBPACK_N(hda_n) | ACR_ENABLE, HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_HIGH); - value = ACR_SUBPACK_CTS(config->cts); + value = ACR_SUBPACK_CTS(hda_cts); tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_LOW); value = SPARE_HW_CTS | SPARE_FORCE_SW_CTS | SPARE_CTS_RESET_VAL(1); @@ -563,7 +490,7 @@ static int tegra_hdmi_setup_audio(struct tegra_hdmi *hdmi, unsigned int pclk) break; } - tegra_hdmi_writel(hdmi, config->aval, offset); + tegra_hdmi_writel(hdmi, hda_aval, offset); } tegra_hdmi_setup_audio_fs_tables(hdmi); -- 1.8.1.3.605.g02339dd -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html