diff --git a/drivers/media/i2c/rk628/rk628_hdmirx.c b/drivers/media/i2c/rk628/rk628_hdmirx.c index 1df0c40e9a75..378b25bdf2a0 100644 --- a/drivers/media/i2c/rk628/rk628_hdmirx.c +++ b/drivers/media/i2c/rk628/rk628_hdmirx.c @@ -1552,6 +1552,44 @@ u32 rk628_hdmirx_get_tmdsclk_cnt(struct rk628 *rk628) } EXPORT_SYMBOL(rk628_hdmirx_get_tmdsclk_cnt); +struct rk628_timings { + int vic; + int hactive; + int hfp; + int hsync; + int hbp; + int htotal; + int vactive; + int vfp; + int vsync; + int vbp; + int vtotal; + int clock; +}; + +static const struct rk628_timings pre_timing[] = { + { 2, 720, 16, 62, 60, 858, 480, 9, 6, 30, 525, 27000000 }, + { 3, 720, 16, 62, 60, 858, 480, 9, 6, 30, 525, 27000000 }, + { 4, 1280, 110, 40, 220, 1650, 720, 5, 5, 20, 750, 74250000}, + { 16, 1920, 88, 44, 148, 2200, 1080, 4, 5, 36, 1125, 148500000 }, + { 19, 1280, 440, 40, 220, 1980, 720, 5, 5, 20, 750, 74250000}, + { 31, 1920, 528, 44, 148, 2640, 1080, 4, 5, 36, 1125, 148500000}, + { 32, 1920, 638, 44, 148, 2750, 1080, 4, 5, 36, 1125, 74250000}, + { 33, 1920, 528, 44, 148, 2640, 1080, 4, 5, 36, 1125, 74250000}, + { 34, 1920, 88, 44, 148, 2200, 1080, 4, 5, 36, 1125, 74250000}, + { 62, 1280, 1760, 40, 220, 3300, 720, 5, 5, 20, 750, 74250000}, + { 93, 3840, 1276, 88, 296, 5500, 2160, 8, 10, 72, 2250, 297000000 }, + { 94, 3840, 1056, 88, 296, 5280, 2160, 8, 10, 72, 2250, 297000000 }, + { 95, 3840, 176, 88, 296, 4400, 2160, 8, 10, 72, 2250, 297000000 }, + { 96, 3840, 1056, 88, 296, 5280, 2160, 8, 10, 72, 2250, 594000000 }, + { 97, 3840, 176, 88, 296, 4400, 2160, 8, 10, 72, 2250, 594000000 }, + { 103, 3840, 1276, 88, 296, 5500, 2160, 8, 10, 72, 2250, 297000000 }, + { 104, 3840, 1056, 88, 296, 5280, 2160, 8, 10, 72, 2250, 297000000 }, + { 105, 3840, 176, 88, 296, 4400, 2160, 8, 10, 72, 2250, 297000000 }, + { 106, 3840, 1056, 88, 296, 5280, 2160, 8, 10, 72, 2250, 594000000 }, + { 107, 3840, 176, 88, 296, 4400, 2160, 8, 10, 72, 2250, 594000000 }, +}; + static int rk628_hdmirx_read_timing(struct rk628 *rk628, struct v4l2_dv_timings *timings) { @@ -1564,6 +1602,7 @@ static int rk628_hdmirx_read_timing(struct rk628 *rk628, u64 tmp_data; u8 video_fmt, vic, color_range, color_space; u32 format; + int i, match = 0; memset(timings, 0, sizeof(struct v4l2_dv_timings)); timings->type = V4L2_DV_BT_656_1120; @@ -1574,55 +1613,6 @@ static int rk628_hdmirx_read_timing(struct rk628 *rk628, bt->interlaced = val & ILACE_STS ? V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE; - rk628_i2c_read(rk628, HDMI_RX_MD_HACT_PX, &val); - hact = val & 0xffff; - rk628_i2c_read(rk628, HDMI_RX_MD_VAL, &val); - vact = val & 0xffff; - rk628_i2c_read(rk628, HDMI_RX_MD_HT1, &val); - htotal = (val >> 16) & 0xffff; - rk628_i2c_read(rk628, HDMI_RX_MD_VTL, &val); - vtotal = val & 0xffff; - rk628_i2c_read(rk628, HDMI_RX_MD_HT1, &val); - hofs_pix = val & 0xffff; - rk628_i2c_read(rk628, HDMI_RX_MD_VOL, &val); - vbp = (val & 0xffff) + 1; - - tmdsclk_cnt = rk628_hdmirx_get_tmdsclk_cnt(rk628); - tmp_data = tmdsclk_cnt; - tmp_data = ((tmp_data * HDMIRX_MODETCLK_HZ) + HDMIRX_MODETCLK_CNT_NUM / 2); - do_div(tmp_data, HDMIRX_MODETCLK_CNT_NUM); - tmds_clk = tmp_data; - if (!htotal || !vtotal || bt->interlaced || vtotal > 3000) { - dev_err(rk628->dev, "timing err, %s htotal:%d, vtotal:%d\n", - bt->interlaced ? "interlaced is not supported," : "", - htotal, vtotal); - goto TIMING_ERR; - } - if (rk628->version >= RK628F_VERSION) - fps = tmds_clk / (htotal * vtotal); - else - fps = (tmds_clk + (htotal * vtotal) / 2) / (htotal * vtotal); - - rk628_i2c_read(rk628, HDMI_RX_MD_HT0, &val); - modetclk_cnt_hs = val & 0xffff; - hs = (tmdsclk_cnt * modetclk_cnt_hs + HDMIRX_MODETCLK_CNT_NUM / 2) / - HDMIRX_MODETCLK_CNT_NUM; - - rk628_i2c_read(rk628, HDMI_RX_MD_VSC, &val); - modetclk_cnt_vs = val & 0xffff; - vs = (tmdsclk_cnt * modetclk_cnt_vs + HDMIRX_MODETCLK_CNT_NUM / 2) / - HDMIRX_MODETCLK_CNT_NUM; - vs = (vs + htotal / 2) / htotal; - - if ((hofs_pix < hs) || (htotal < (hact + hofs_pix)) || - (vtotal < (vact + vs + vbp)) || !vs) { - dev_err(rk628->dev, "timing err, total:%dx%d, act:%dx%d, hofs:%d, hs:%d, vs:%d, vbp:%d\n", - htotal, vtotal, hact, vact, hofs_pix, hs, vs, vbp); - goto TIMING_ERR; - } - hbp = hofs_pix - hs; - hfp = htotal - hact - hofs_pix; - vfp = vtotal - vact - vs - vbp; rk628_i2c_read(rk628, HDMI_RX_PDEC_AVI_PB, &val); vic = (val & VID_IDENT_CODE_MASK) >> 24; @@ -1637,28 +1627,101 @@ static int rk628_hdmirx_read_timing(struct rk628 *rk628, rk628->color_space = color_space; rk628_i2c_read(rk628, HDMI_RX_PDEC_STS, &val); rk628->dvi_mode = val & DVI_DET; - if (video_fmt == BUS_FMT_YUV420) { - //format:color depth, 5: 10bit, 4: 8bit - if (format == 5) { - htotal = htotal * 2 * 8 / 10; - hact = hact * 2 * 8 / 10; - hfp = hfp * 2 * 8 / 10; - hbp = hbp * 2 * 8 / 10; - hs = hs * 2 * 8 / 10; - } else { - htotal *= 2; - hact *= 2; - hfp *= 2; - hbp *= 2; - hs *= 2; + + for (i = 0; vic && i < ARRAY_SIZE(pre_timing); i++) { + if (vic == pre_timing[i].vic) { + hact = pre_timing[i].hactive; + hfp = pre_timing[i].hfp; + hs = pre_timing[i].hsync; + hbp = pre_timing[i].hbp; + htotal = pre_timing[i].htotal; + vact = pre_timing[i].vactive; + vfp = pre_timing[i].vfp; + vs = pre_timing[i].vsync; + vbp = pre_timing[i].vbp; + vtotal = pre_timing[i].vtotal; + tmds_clk = pre_timing[i].clock; + match = 1; + break; } } - rk628_dbg(rk628, "cnt_num:%d, tmds_cnt:%d, hs_cnt:%d, vs_cnt:%d, hofs:%d\n", - HDMIRX_MODETCLK_CNT_NUM, tmdsclk_cnt, modetclk_cnt_hs, modetclk_cnt_vs, hofs_pix); + if (!match) { + rk628_i2c_read(rk628, HDMI_RX_MD_HACT_PX, &val); + hact = val & 0xffff; + rk628_i2c_read(rk628, HDMI_RX_MD_VAL, &val); + vact = val & 0xffff; + rk628_i2c_read(rk628, HDMI_RX_MD_HT1, &val); + htotal = (val >> 16) & 0xffff; + rk628_i2c_read(rk628, HDMI_RX_MD_VTL, &val); + vtotal = val & 0xffff; + rk628_i2c_read(rk628, HDMI_RX_MD_HT1, &val); + hofs_pix = val & 0xffff; + rk628_i2c_read(rk628, HDMI_RX_MD_VOL, &val); + vbp = (val & 0xffff) + 1; + + tmdsclk_cnt = rk628_hdmirx_get_tmdsclk_cnt(rk628); + tmp_data = tmdsclk_cnt; + tmp_data = ((tmp_data * HDMIRX_MODETCLK_HZ) + HDMIRX_MODETCLK_CNT_NUM / 2); + do_div(tmp_data, HDMIRX_MODETCLK_CNT_NUM); + tmds_clk = tmp_data; + if (!htotal || !vtotal || bt->interlaced || vtotal > 3000) { + dev_err(rk628->dev, "timing err, %s htotal:%d, vtotal:%d\n", + bt->interlaced ? "interlaced is not supported," : "", + htotal, vtotal); + goto TIMING_ERR; + } + + rk628_i2c_read(rk628, HDMI_RX_MD_HT0, &val); + modetclk_cnt_hs = val & 0xffff; + hs = (tmdsclk_cnt * modetclk_cnt_hs + HDMIRX_MODETCLK_CNT_NUM / 2) / + HDMIRX_MODETCLK_CNT_NUM; + + rk628_i2c_read(rk628, HDMI_RX_MD_VSC, &val); + modetclk_cnt_vs = val & 0xffff; + vs = (tmdsclk_cnt * modetclk_cnt_vs + HDMIRX_MODETCLK_CNT_NUM / 2) / + HDMIRX_MODETCLK_CNT_NUM; + vs = (vs + htotal / 2) / htotal; + + if ((hofs_pix < hs) || (htotal < (hact + hofs_pix)) || + (vtotal < (vact + vs + vbp)) || !vs) { + dev_err(rk628->dev, "timing err, total:%dx%d, act:%dx%d, hofs:%d, hs:%d, vs:%d, vbp:%d\n", + htotal, vtotal, hact, vact, hofs_pix, hs, vs, vbp); + goto TIMING_ERR; + } + hbp = hofs_pix - hs; + hfp = htotal - hact - hofs_pix; + vfp = vtotal - vact - vs - vbp; + + if (video_fmt == BUS_FMT_YUV420) { + //format:color depth, 5: 10bit, 4: 8bit + if (format == 5) { + htotal = htotal * 2 * 8 / 10; + hact = hact * 2 * 8 / 10; + hfp = hfp * 2 * 8 / 10; + hbp = hbp * 2 * 8 / 10; + hs = hs * 2 * 8 / 10; + } else { + htotal *= 2; + hact *= 2; + hfp *= 2; + hbp *= 2; + hs *= 2; + } + } + + rk628_dbg(rk628, "cnt_num:%d, tmds_cnt:%d, hs_cnt:%d, vs_cnt:%d, hofs:%d\n", + HDMIRX_MODETCLK_CNT_NUM, tmdsclk_cnt, modetclk_cnt_hs, + modetclk_cnt_vs, hofs_pix); + } + rk628_dbg(rk628, "get current aviif: vic:%d, color_range: %s, color_space %s", vic, bus_color_range_str[color_range], bus_color_space_str[color_space]); + if (rk628->version >= RK628F_VERSION) + fps = tmds_clk / (htotal * vtotal); + else + fps = (tmds_clk + (htotal * vtotal) / 2) / (htotal * vtotal); bt->width = hact; bt->height = vact; bt->hfrontporch = hfp; @@ -1677,12 +1740,14 @@ static int rk628_hdmirx_read_timing(struct rk628 *rk628, bt->il_vsync = bt->vsync + 1; bt->pixelclock /= 2; } - if (video_fmt == BUS_FMT_YUV420) { - if (format == 5) { - bt->pixelclock = bt->pixelclock * 8 * 2; - do_div(bt->pixelclock, 10); - } else { - bt->pixelclock *= 2; + if (!match) { + if (video_fmt == BUS_FMT_YUV420) { + if (format == 5) { + bt->pixelclock = bt->pixelclock * 8 * 2; + do_div(bt->pixelclock, 10); + } else { + bt->pixelclock *= 2; + } } }