diff options
Diffstat (limited to 'drivers/video/omap2/dss/hdmi.c')
-rw-r--r-- | drivers/video/omap2/dss/hdmi.c | 278 |
1 files changed, 126 insertions, 152 deletions
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index a36b934b2db..c4b4f6950a9 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c @@ -58,8 +58,6 @@ #define EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR 4 #define EDID_SIZE_BLOCK1_TIMING_DESCRIPTOR 4 -#define OMAP_HDMI_TIMINGS_NB 34 - #define HDMI_DEFAULT_REGN 16 #define HDMI_DEFAULT_REGM2 1 @@ -68,8 +66,6 @@ static struct { struct omap_display_platform_data *pdata; struct platform_device *pdev; struct hdmi_ip_data ip_data; - int code; - int mode; struct clk *sys_clk; } hdmi; @@ -88,77 +84,46 @@ static struct { * map it to corresponding CEA or VESA index. */ -static const struct hdmi_timings cea_vesa_timings[OMAP_HDMI_TIMINGS_NB] = { - { {640, 480, 25200, 96, 16, 48, 2, 10, 33} , 0 , 0}, - { {1280, 720, 74250, 40, 440, 220, 5, 5, 20}, 1, 1}, - { {1280, 720, 74250, 40, 110, 220, 5, 5, 20}, 1, 1}, - { {720, 480, 27027, 62, 16, 60, 6, 9, 30}, 0, 0}, - { {2880, 576, 108000, 256, 48, 272, 5, 5, 39}, 0, 0}, - { {1440, 240, 27027, 124, 38, 114, 3, 4, 15}, 0, 0}, - { {1440, 288, 27000, 126, 24, 138, 3, 2, 19}, 0, 0}, - { {1920, 540, 74250, 44, 528, 148, 5, 2, 15}, 1, 1}, - { {1920, 540, 74250, 44, 88, 148, 5, 2, 15}, 1, 1}, - { {1920, 1080, 148500, 44, 88, 148, 5, 4, 36}, 1, 1}, - { {720, 576, 27000, 64, 12, 68, 5, 5, 39}, 0, 0}, - { {1440, 576, 54000, 128, 24, 136, 5, 5, 39}, 0, 0}, - { {1920, 1080, 148500, 44, 528, 148, 5, 4, 36}, 1, 1}, - { {2880, 480, 108108, 248, 64, 240, 6, 9, 30}, 0, 0}, - { {1920, 1080, 74250, 44, 638, 148, 5, 4, 36}, 1, 1}, - /* VESA From Here */ - { {640, 480, 25175, 96, 16, 48, 2 , 11, 31}, 0, 0}, - { {800, 600, 40000, 128, 40, 88, 4 , 1, 23}, 1, 1}, - { {848, 480, 33750, 112, 16, 112, 8 , 6, 23}, 1, 1}, - { {1280, 768, 79500, 128, 64, 192, 7 , 3, 20}, 1, 0}, - { {1280, 800, 83500, 128, 72, 200, 6 , 3, 22}, 1, 0}, - { {1360, 768, 85500, 112, 64, 256, 6 , 3, 18}, 1, 1}, - { {1280, 960, 108000, 112, 96, 312, 3 , 1, 36}, 1, 1}, - { {1280, 1024, 108000, 112, 48, 248, 3 , 1, 38}, 1, 1}, - { {1024, 768, 65000, 136, 24, 160, 6, 3, 29}, 0, 0}, - { {1400, 1050, 121750, 144, 88, 232, 4, 3, 32}, 1, 0}, - { {1440, 900, 106500, 152, 80, 232, 6, 3, 25}, 1, 0}, - { {1680, 1050, 146250, 176 , 104, 280, 6, 3, 30}, 1, 0}, - { {1366, 768, 85500, 143, 70, 213, 3, 3, 24}, 1, 1}, - { {1920, 1080, 148500, 44, 148, 80, 5, 4, 36}, 1, 1}, - { {1280, 768, 68250, 32, 48, 80, 7, 3, 12}, 0, 1}, - { {1400, 1050, 101000, 32, 48, 80, 4, 3, 23}, 0, 1}, - { {1680, 1050, 119000, 32, 48, 80, 6, 3, 21}, 0, 1}, - { {1280, 800, 79500, 32, 48, 80, 6, 3, 14}, 0, 1}, - { {1280, 720, 74250, 40, 110, 220, 5, 5, 20}, 1, 1} -}; - -/* - * This is a static mapping array which maps the timing values - * with corresponding CEA / VESA code - */ -static const int code_index[OMAP_HDMI_TIMINGS_NB] = { - 1, 19, 4, 2, 37, 6, 21, 20, 5, 16, 17, 29, 31, 35, 32, - /* <--15 CEA 17--> vesa*/ - 4, 9, 0xE, 0x17, 0x1C, 0x27, 0x20, 0x23, 0x10, 0x2A, - 0X2F, 0x3A, 0X51, 0X52, 0x16, 0x29, 0x39, 0x1B +static const struct hdmi_config cea_timings[] = { +{ {640, 480, 25200, 96, 16, 48, 2, 10, 33, 0, 0, 0}, {1, HDMI_HDMI} }, +{ {720, 480, 27027, 62, 16, 60, 6, 9, 30, 0, 0, 0}, {2, HDMI_HDMI} }, +{ {1280, 720, 74250, 40, 110, 220, 5, 5, 20, 1, 1, 0}, {4, HDMI_HDMI} }, +{ {1920, 540, 74250, 44, 88, 148, 5, 2, 15, 1, 1, 1}, {5, HDMI_HDMI} }, +{ {1440, 240, 27027, 124, 38, 114, 3, 4, 15, 0, 0, 1}, {6, HDMI_HDMI} }, +{ {1920, 1080, 148500, 44, 88, 148, 5, 4, 36, 1, 1, 0}, {16, HDMI_HDMI} }, +{ {720, 576, 27000, 64, 12, 68, 5, 5, 39, 0, 0, 0}, {17, HDMI_HDMI} }, +{ {1280, 720, 74250, 40, 440, 220, 5, 5, 20, 1, 1, 0}, {19, HDMI_HDMI} }, +{ {1920, 540, 74250, 44, 528, 148, 5, 2, 15, 1, 1, 1}, {20, HDMI_HDMI} }, +{ {1440, 288, 27000, 126, 24, 138, 3, 2, 19, 0, 0, 1}, {21, HDMI_HDMI} }, +{ {1440, 576, 54000, 128, 24, 136, 5, 5, 39, 0, 0, 0}, {29, HDMI_HDMI} }, +{ {1920, 1080, 148500, 44, 528, 148, 5, 4, 36, 1, 1, 0}, {31, HDMI_HDMI} }, +{ {1920, 1080, 74250, 44, 638, 148, 5, 4, 36, 1, 1, 0}, {32, HDMI_HDMI} }, +{ {2880, 480, 108108, 248, 64, 240, 6, 9, 30, 0, 0, 0}, {35, HDMI_HDMI} }, +{ {2880, 576, 108000, 256, 48, 272, 5, 5, 39, 0, 0, 0}, {37, HDMI_HDMI} }, }; - -/* - * This is reverse static mapping which maps the CEA / VESA code - * to the corresponding timing values - */ -static const int code_cea[39] = { - -1, 0, 3, 3, 2, 8, 5, 5, -1, -1, - -1, -1, -1, -1, -1, -1, 9, 10, 10, 1, - 7, 6, 6, -1, -1, -1, -1, -1, -1, 11, - 11, 12, 14, -1, -1, 13, 13, 4, 4 +static const struct hdmi_config vesa_timings[] = { +/* VESA From Here */ +{ {640, 480, 25175, 96, 16, 48, 2 , 11, 31, 0, 0, 0}, {4, HDMI_DVI} }, +{ {800, 600, 40000, 128, 40, 88, 4 , 1, 23, 1, 1, 0}, {9, HDMI_DVI} }, +{ {848, 480, 33750, 112, 16, 112, 8 , 6, 23, 1, 1, 0}, {0xE, HDMI_DVI} }, +{ {1280, 768, 79500, 128, 64, 192, 7 , 3, 20, 1, 0, 0}, {0x17, HDMI_DVI} }, +{ {1280, 800, 83500, 128, 72, 200, 6 , 3, 22, 1, 0, 0}, {0x1C, HDMI_DVI} }, +{ {1360, 768, 85500, 112, 64, 256, 6 , 3, 18, 1, 1, 0}, {0x27, HDMI_DVI} }, +{ {1280, 960, 108000, 112, 96, 312, 3 , 1, 36, 1, 1, 0}, {0x20, HDMI_DVI} }, +{ {1280, 1024, 108000, 112, 48, 248, 3 , 1, 38, 1, 1, 0}, {0x23, HDMI_DVI} }, +{ {1024, 768, 65000, 136, 24, 160, 6, 3, 29, 0, 0, 0}, {0x10, HDMI_DVI} }, +{ {1400, 1050, 121750, 144, 88, 232, 4, 3, 32, 1, 0, 0}, {0x2A, HDMI_DVI} }, +{ {1440, 900, 106500, 152, 80, 232, 6, 3, 25, 1, 0, 0}, {0x2F, HDMI_DVI} }, +{ {1680, 1050, 146250, 176 , 104, 280, 6, 3, 30, 1, 0, 0}, {0x3A, HDMI_DVI} }, +{ {1366, 768, 85500, 143, 70, 213, 3, 3, 24, 1, 1, 0}, {0x51, HDMI_DVI} }, +{ {1920, 1080, 148500, 44, 148, 80, 5, 4, 36, 1, 1, 0}, {0x52, HDMI_DVI} }, +{ {1280, 768, 68250, 32, 48, 80, 7, 3, 12, 0, 1, 0}, {0x16, HDMI_DVI} }, +{ {1400, 1050, 101000, 32, 48, 80, 4, 3, 23, 0, 1, 0}, {0x29, HDMI_DVI} }, +{ {1680, 1050, 119000, 32, 48, 80, 6, 3, 21, 0, 1, 0}, {0x39, HDMI_DVI} }, +{ {1280, 800, 79500, 32, 48, 80, 6, 3, 14, 0, 1, 0}, {0x1B, HDMI_DVI} }, +{ {1280, 720, 74250, 40, 110, 220, 5, 5, 20, 1, 1, 0}, {0x55, HDMI_DVI} } }; -static const int code_vesa[85] = { - -1, -1, -1, -1, 15, -1, -1, -1, -1, 16, - -1, -1, -1, -1, 17, -1, 23, -1, -1, -1, - -1, -1, 29, 18, -1, -1, -1, 32, 19, -1, - -1, -1, 21, -1, -1, 22, -1, -1, -1, 20, - -1, 30, 24, -1, -1, -1, -1, 25, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 31, 26, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 27, 28, -1, 33}; - static int hdmi_runtime_get(void) { int r; @@ -210,88 +175,89 @@ int hdmi_init_display(struct omap_dss_device *dssdev) return 0; } -static int get_timings_index(void) +static const struct hdmi_config *hdmi_find_timing( + const struct hdmi_config *timings_arr, + int len) { - int code; + int i; - if (hdmi.mode == 0) - code = code_vesa[hdmi.code]; - else - code = code_cea[hdmi.code]; + for (i = 0; i < len; i++) { + if (timings_arr[i].cm.code == hdmi.ip_data.cfg.cm.code) + return &timings_arr[i]; + } + return NULL; +} - if (code == -1) { - /* HDMI code 4 corresponds to 640 * 480 VGA */ - hdmi.code = 4; - /* DVI mode 1 corresponds to HDMI 0 to DVI */ - hdmi.mode = HDMI_DVI; +static const struct hdmi_config *hdmi_get_timings(void) +{ + const struct hdmi_config *arr; + int len; + + if (hdmi.ip_data.cfg.cm.mode == HDMI_DVI) { + arr = vesa_timings; + len = ARRAY_SIZE(vesa_timings); + } else { + arr = cea_timings; + len = ARRAY_SIZE(cea_timings); + } + + return hdmi_find_timing(arr, len); +} + +static bool hdmi_timings_compare(struct omap_video_timings *timing1, + const struct hdmi_video_timings *timing2) +{ + int timing1_vsync, timing1_hsync, timing2_vsync, timing2_hsync; - code = code_vesa[hdmi.code]; + if ((timing2->pixel_clock == timing1->pixel_clock) && + (timing2->x_res == timing1->x_res) && + (timing2->y_res == timing1->y_res)) { + + timing2_hsync = timing2->hfp + timing2->hsw + timing2->hbp; + timing1_hsync = timing1->hfp + timing1->hsw + timing1->hbp; + timing2_vsync = timing2->vfp + timing2->vsw + timing2->vbp; + timing1_vsync = timing2->vfp + timing2->vsw + timing2->vbp; + + DSSDBG("timing1_hsync = %d timing1_vsync = %d"\ + "timing2_hsync = %d timing2_vsync = %d\n", + timing1_hsync, timing1_vsync, + timing2_hsync, timing2_vsync); + + if ((timing1_hsync == timing2_hsync) && + (timing1_vsync == timing2_vsync)) { + return true; + } } - return code; + return false; } static struct hdmi_cm hdmi_get_code(struct omap_video_timings *timing) { - int i = 0, code = -1, temp_vsync = 0, temp_hsync = 0; - int timing_vsync = 0, timing_hsync = 0; - struct hdmi_video_timings temp; + int i; struct hdmi_cm cm = {-1}; DSSDBG("hdmi_get_code\n"); - for (i = 0; i < OMAP_HDMI_TIMINGS_NB; i++) { - temp = cea_vesa_timings[i].timings; - if ((temp.pixel_clock == timing->pixel_clock) && - (temp.x_res == timing->x_res) && - (temp.y_res == timing->y_res)) { - - temp_hsync = temp.hfp + temp.hsw + temp.hbp; - timing_hsync = timing->hfp + timing->hsw + timing->hbp; - temp_vsync = temp.vfp + temp.vsw + temp.vbp; - timing_vsync = timing->vfp + timing->vsw + timing->vbp; - - DSSDBG("temp_hsync = %d , temp_vsync = %d" - "timing_hsync = %d, timing_vsync = %d\n", - temp_hsync, temp_hsync, - timing_hsync, timing_vsync); - - if ((temp_hsync == timing_hsync) && - (temp_vsync == timing_vsync)) { - code = i; - cm.code = code_index[i]; - if (code < 14) - cm.mode = HDMI_HDMI; - else - cm.mode = HDMI_DVI; - DSSDBG("Hdmi_code = %d mode = %d\n", - cm.code, cm.mode); - break; - } + for (i = 0; i < ARRAY_SIZE(cea_timings); i++) { + if (hdmi_timings_compare(timing, &cea_timings[i].timings)) { + cm = cea_timings[i].cm; + goto end; + } + } + for (i = 0; i < ARRAY_SIZE(vesa_timings); i++) { + if (hdmi_timings_compare(timing, &vesa_timings[i].timings)) { + cm = vesa_timings[i].cm; + goto end; } } - return cm; -} +end: return cm; -static void update_hdmi_timings(struct hdmi_config *cfg, - struct omap_video_timings *timings, int code) -{ - cfg->timings.timings.x_res = timings->x_res; - cfg->timings.timings.y_res = timings->y_res; - cfg->timings.timings.hbp = timings->hbp; - cfg->timings.timings.hfp = timings->hfp; - cfg->timings.timings.hsw = timings->hsw; - cfg->timings.timings.vbp = timings->vbp; - cfg->timings.timings.vfp = timings->vfp; - cfg->timings.timings.vsw = timings->vsw; - cfg->timings.timings.pixel_clock = timings->pixel_clock; - cfg->timings.vsync_pol = cea_vesa_timings[code].vsync_pol; - cfg->timings.hsync_pol = cea_vesa_timings[code].hsync_pol; } unsigned long hdmi_get_pixel_clock(void) { /* HDMI Pixel Clock in Mhz */ - return hdmi.ip_data.cfg.timings.timings.pixel_clock * 1000; + return hdmi.ip_data.cfg.timings.pixel_clock * 1000; } static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, @@ -312,24 +278,24 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, refclk = clkin / pi->regn; - /* - * multiplier is pixel_clk/ref_clk - * Multiplying by 100 to avoid fractional part removal - */ - pi->regm = (phy * 100 / (refclk)) / 100; - if (dssdev->clocks.hdmi.regm2 == 0) pi->regm2 = HDMI_DEFAULT_REGM2; else pi->regm2 = dssdev->clocks.hdmi.regm2; /* + * multiplier is pixel_clk/ref_clk + * Multiplying by 100 to avoid fractional part removal + */ + pi->regm = phy * pi->regm2 / refclk; + + /* * fractional multiplier is remainder of the difference between * multiplier and actual phy(required pixel clock thus should be * multiplied by 2^18(262144) divided by the reference clock */ - mf = (phy - pi->regm * refclk) * 262144; - pi->regmf = mf / (refclk); + mf = (phy - pi->regm / pi->regm2 * refclk) * 262144; + pi->regmf = pi->regm2 * mf / refclk; /* * Dcofreq should be set to 1 if required pixel clock @@ -347,7 +313,8 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, static int hdmi_power_on(struct omap_dss_device *dssdev) { - int r, code = 0; + int r; + const struct hdmi_config *timing; struct omap_video_timings *p; unsigned long phy; @@ -363,9 +330,16 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) dssdev->panel.timings.x_res, dssdev->panel.timings.y_res); - code = get_timings_index(); - update_hdmi_timings(&hdmi.ip_data.cfg, p, code); - + timing = hdmi_get_timings(); + if (timing == NULL) { + /* HDMI code 4 corresponds to 640 * 480 VGA */ + hdmi.ip_data.cfg.cm.code = 4; + /* DVI mode 1 corresponds to HDMI 0 to DVI */ + hdmi.ip_data.cfg.cm.mode = HDMI_DVI; + hdmi.ip_data.cfg = vesa_timings[0]; + } else { + hdmi.ip_data.cfg = *timing; + } phy = p->pixel_clock; hdmi_compute_pll(dssdev, phy, &hdmi.ip_data.pll_data); @@ -385,8 +359,6 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) goto err; } - hdmi.ip_data.cfg.cm.mode = hdmi.mode; - hdmi.ip_data.cfg.cm.code = hdmi.code; hdmi.ip_data.ops->video_configure(&hdmi.ip_data); /* Make selection of HDMI in DSS */ @@ -453,8 +425,8 @@ void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev) struct hdmi_cm cm; cm = hdmi_get_code(&dssdev->panel.timings); - hdmi.code = cm.code; - hdmi.mode = cm.mode; + hdmi.ip_data.cfg.cm.code = cm.code; + hdmi.ip_data.cfg.cm.mode = cm.mode; if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { int r; @@ -717,13 +689,15 @@ static int hdmi_audio_hw_params(struct snd_pcm_substream *substream, if (dss_has_feature(FEAT_HDMI_CTS_SWMODE)) { core_cfg.aud_par_busclk = 0; core_cfg.cts_mode = HDMI_AUDIO_CTS_MODE_SW; - core_cfg.use_mclk = false; + core_cfg.use_mclk = dss_has_feature(FEAT_HDMI_AUDIO_USE_MCLK); } else { core_cfg.aud_par_busclk = (((128 * 31) - 1) << 8); core_cfg.cts_mode = HDMI_AUDIO_CTS_MODE_HW; core_cfg.use_mclk = true; - core_cfg.mclk_mode = HDMI_AUDIO_MCLK_128FS; } + + if (core_cfg.use_mclk) + core_cfg.mclk_mode = HDMI_AUDIO_MCLK_128FS; core_cfg.layout = HDMI_AUDIO_LAYOUT_2CH; core_cfg.en_spdif = false; /* Use sample frequency from channel status word */ @@ -756,7 +730,7 @@ static int hdmi_audio_hw_params(struct snd_pcm_substream *substream, static int hdmi_audio_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - if (!hdmi.mode) { + if (!hdmi.ip_data.cfg.cm.mode) { pr_err("Current video settings do not support audio.\n"); return -EIO; } |