hdmitx: add validate mode api [1/1]

PD#SWPL-132959

Problem:
mode validation is in many functions and
checked many times.

Solution:
abstract the mode validate api and cleanup
the flow in tx20.

Verify:
verify on ohm.

Test:
DRM-TX-27, DRM-TX-26,DRM-TX-28,DRM-TX-25,DRM-TX-20

Change-Id: I9ddd17718fa43ac7a670192ba72a48d9bc0a6dc5
Signed-off-by: sky zhou <sky.zhou@amlogic.com>
This commit is contained in:
sky zhou
2023-08-15 16:58:42 +08:00
committed by gerrit autosubmit
parent dfd329f86c
commit 3f4940271b
11 changed files with 296 additions and 467 deletions
@@ -31,8 +31,6 @@
#include "hw/common.h"
#include <linux/amlogic/media/vout/hdmitx_common/hdmitx_edid.h>
const struct hdmi_timing *hdmitx_mode_match_timing_name(const char *name);
#define CEA_DATA_BLOCK_COLLECTION_ADDR_1STP 0x04
#define VIDEO_TAG 0x40
#define AUDIO_TAG 0x20
@@ -2287,38 +2285,6 @@ static bool is_rx_support_y420(struct hdmitx_dev *hdev, enum hdmi_vic vic)
return 0;
}
static bool hdmitx_check_4x3_16x9_mode(struct hdmitx_dev *hdev,
enum hdmi_vic vic)
{
bool flag = 0;
int j;
struct rx_cap *prxcap = NULL;
prxcap = &hdev->tx_comm.rxcap;
if (vic == HDMI_720x480p60_4x3 ||
vic == HDMI_720x480i60_4x3 ||
vic == HDMI_720x576p50_4x3 ||
vic == HDMI_720x576i50_4x3) {
for (j = 0; (j < prxcap->VIC_count) && (j < VIC_MAX_NUM); j++) {
if ((vic + 1) == (prxcap->VIC[j] & 0xff)) {
flag = 1;
break;
}
}
} else if (vic == HDMI_720x480p60_16x9 ||
vic == HDMI_720x480i60_16x9 ||
vic == HDMI_720x576p50_16x9 ||
vic == HDMI_720x576i50_16x9) {
for (j = 0; (j < prxcap->VIC_count) && (j < VIC_MAX_NUM); j++) {
if ((vic - 1) == (prxcap->VIC[j] & 0xff)) {
flag = 1;
break;
}
}
}
return flag;
}
/* For some TV's EDID, there maybe exist some information ambiguous.
* Such as EDID declare support 2160p60hz(Y444 8bit), but no valid
* Max_TMDS_Clock2 to indicate that it can support 5.94G signal.
@@ -2329,11 +2295,8 @@ bool hdmitx_edid_check_valid_mode(struct hdmitx_dev *hdev,
bool valid = 0;
struct rx_cap *prxcap = NULL;
const struct dv_info *dv = &hdev->tx_comm.rxcap.dv_info;
enum hdmi_vic *vesa_t = &hdev->tx_comm.rxcap.vesa_timing[0];
unsigned int rx_max_tmds_clk = 0;
unsigned int calc_tmds_clk = 0;
int i = 0;
int svd_flag = 0;
/* Default max color depth is 24 bit */
enum hdmi_color_depth rx_y444_max_dc = COLORDEPTH_24B;
enum hdmi_color_depth rx_rgb_max_dc = COLORDEPTH_24B;
@@ -2341,19 +2304,9 @@ bool hdmitx_edid_check_valid_mode(struct hdmitx_dev *hdev,
if (!hdev || !para)
return 0;
/* if current limits to 1080p, here will check the freshrate and
* 4k resolution
*/
if (hdmitx_limited_1080p()) {
if (is_vic_over_limited_1080p(para->vic)) {
pr_err("over limited vic%d in %s\n", para->vic, __func__);
return 0;
}
}
if (para->vic == HDMI_0_UNKNOWN)
return 0;
if (para->sname)
if (strcmp(para->sname, "invalid") == 0)
return 0;
/* exclude such as: 2160p60hz YCbCr444 10bit */
switch (para->vic) {
case HDMI_3840x2160p50_16x9:
@@ -2383,38 +2336,6 @@ bool hdmitx_edid_check_valid_mode(struct hdmitx_dev *hdev,
return 0;
}
/* target mode is not contained at RX SVD */
for (i = 0; (i < prxcap->VIC_count) && (i < VIC_MAX_NUM); i++) {
if (para->vic == prxcap->VIC[i]) {
svd_flag = 1;
break;
} else if (hdmitx_check_4x3_16x9_mode(hdev, para->vic & 0xff)) {
svd_flag = 1;
break;
}
}
if (para->vic >= HDMITX_VESA_OFFSET) {
if (para->cd != COLORDEPTH_24B)
return 0;
if (para->cs != HDMI_COLORSPACE_RGB)
return 0;
for (i = 0; vesa_t[i] && i < VESA_MAX_TIMING; i++) {
const struct hdmi_timing *timing =
hdmitx_mode_vic_to_hdmi_timing(vesa_t[i]);
if (timing) {
if (timing->vic >= HDMITX_VESA_OFFSET &&
para->vic == timing->vic) {
svd_flag = 1;
break;
}
}
}
}
if (svd_flag == 0)
return 0;
/* Get RX Max_TMDS_Clock */
if (prxcap->Max_TMDS_Clock2) {
rx_max_tmds_clk = prxcap->Max_TMDS_Clock2 * 5;
@@ -2424,11 +2345,12 @@ bool hdmitx_edid_check_valid_mode(struct hdmitx_dev *hdev,
prxcap->Max_TMDS_Clock1 = 0x1e;
rx_max_tmds_clk = prxcap->Max_TMDS_Clock1 * 5;
}
/* if current status already limited to 1080p, so here also needs to
* limit the rx_max_tmds_clk as 150 * 1.5 = 225 to make the valid mode
* checking works
*/
if (hdmitx_limited_1080p()) {
if (false /*hdmitx_limited_1080p()*/) {
if (rx_max_tmds_clk > 225)
rx_max_tmds_clk = 225;
}
@@ -2511,110 +2433,6 @@ bool hdmitx_edid_check_valid_mode(struct hdmitx_dev *hdev,
return valid;
}
static bool check_sd(struct rx_cap *prxcap, const char *_mode,
const char *mode, const unsigned int _vic,
unsigned int *vic)
{
int i;
bool check1 = 0;
bool check2 = 0;
if (strcmp(_mode, mode) == 0) {
for (i = 0 ; i < prxcap->VIC_count ; i++) {
if (prxcap->VIC[i] == _vic)
check1 = 1;
}
for (i = 0 ; i < prxcap->VIC_count ; i++) {
if (prxcap->VIC[i] == (_vic + 1))
check2 = 1;
}
if (check1 == 1 && check2 == 0) {
*vic = _vic;
return 1;
}
}
return 0;
}
/* For some TV only support 480p 4:3,
*then consider it also supports in disp_cap
*/
static bool is_sink_only_sd_4x3(struct hdmitx_dev *hdev,
const char *mode, unsigned int *vic)
{
struct rx_cap *prxcap = &hdev->tx_comm.rxcap;
if (check_sd(prxcap, "480i60hz", mode, HDMI_720x480i60_4x3, vic))
return 1;
if (check_sd(prxcap, "480p60hz", mode, HDMI_720x480p60_4x3, vic))
return 1;
if (check_sd(prxcap, "576i50hz", mode, HDMI_720x576i50_4x3, vic))
return 1;
if (check_sd(prxcap, "576p50hz", mode, HDMI_720x576p50_4x3, vic))
return 1;
return 0;
}
/* force_flag: 0 means check with RX's edid */
/* 1 means no check with RX's edid */
enum hdmi_vic hdmitx_edid_get_VIC(struct hdmitx_dev *hdev,
const char *disp_mode,
char force_flag)
{
const struct hdmi_timing *timing;
enum hdmi_vic vic = HDMI_0_UNKNOWN;
struct rx_cap *prxcap = &hdev->tx_comm.rxcap;
enum hdmi_vic *vesa_t = &prxcap->vesa_timing[0];
enum hdmi_vic vesa_vic;
int j;
timing = hdmitx_mode_match_timing_name(disp_mode);
if (!timing || timing->vic == HDMI_0_UNKNOWN)
return HDMI_0_UNKNOWN;
if (hdmitx_hw_validate_mode(&hdev->tx_hw, timing->vic) != 0)
return HDMI_0_UNKNOWN;
vic = timing->vic;
if (vic >= HDMITX_VESA_OFFSET)
vesa_vic = vic;
else
vesa_vic = HDMI_0_UNKNOWN;
if (vic != HDMI_0_UNKNOWN) {
if (force_flag == 0) {
for (j = 0 ; j < prxcap->VIC_count; j++) {
if (prxcap->VIC[j] == vic)
break;
}
if (j >= prxcap->VIC_count)
vic = HDMI_0_UNKNOWN;
}
/* if TV only supports 480p/2, add 480p60hz as well */
if (is_sink_only_sd_4x3(hdev, disp_mode, &vic)) {
; /* pr_debug("hdmitx: find SD only 4x3\n"); */
}
}
if (vic == HDMI_UNKNOWN && vesa_vic != HDMI_UNKNOWN) {
for (j = 0; vesa_t[j] && j < VESA_MAX_TIMING; j++) {
timing = hdmitx_mode_vic_to_hdmi_timing(vesa_t[j]);
if (timing) {
if (timing->vic >= HDMITX_VESA_OFFSET &&
vesa_vic == timing->vic) {
vic = timing->vic;
break;
}
}
}
}
return vic;
}
/* Clear HDMI Hardware Module EDID RAM and EDID Buffer */
void hdmitx_edid_ram_buffer_clear(struct hdmitx_dev *hdmitx_device)
{
@@ -200,8 +200,6 @@ static bool hdmitx_edid_done;
* when switch DV(LL)->HLG
*/
static int hdr_mute_frame = 20;
static unsigned int res_1080p;
static u32 max_refreshrate = 60;
static char suspend_fmt_attr[16];
struct vout_device_s hdmitx_vdev = {
@@ -520,25 +518,22 @@ static int set_disp_mode(const char *mode)
{
int ret = -1;
enum hdmi_vic vic;
const struct hdmi_timing *timing = 0;
vic = hdmitx_edid_get_VIC(&hdmitx_device, mode, 1);
if (strncmp(mode, "2160p30hz", strlen("2160p30hz")) == 0)
vic = HDMI_3840x2160p30_16x9;
else if (strncmp(mode, "2160p25hz", strlen("2160p25hz")) == 0)
vic = HDMI_3840x2160p25_16x9;
else if (strncmp(mode, "2160p24hz", strlen("2160p24hz")) == 0)
vic = HDMI_3840x2160p24_16x9;
else if (strncmp(mode, "smpte24hz", strlen("smpte24hz")) == 0)
vic = HDMI_4096x2160p24_256x135;
else
;/* nothing */
/*function for debug, only get vic and check if ip can support, skip rx cap check.*/
timing = hdmitx_mode_match_timing_name(mode);
if (!timing || timing->vic == HDMI_0_UNKNOWN) {
pr_err("unknown mode %s\n", mode);
return -EINVAL;
}
if (strncmp(mode, "1080p60hz", strlen("1080p60hz")) == 0)
vic = HDMI_1080p60;
if (strncmp(mode, "1080p50hz", strlen("1080p50hz")) == 0)
vic = HDMI_1080p50;
vic = timing->vic;
if (hdmitx_common_validate_mode(&hdmitx_device.tx_comm, timing->vic) != 0) {
pr_err("ip cannot support mode %s. %d\n", mode, timing->vic);
return -EINVAL;
}
if (vic != HDMI_UNKNOWN) {
if (vic != HDMI_0_UNKNOWN) {
hdmitx_device.mux_hpd_if_pin_high_flag = 1;
if (hdmitx_device.vic_count == 0) {
if (hdmitx_device.unplug_powerdown)
@@ -1177,24 +1172,12 @@ static unsigned int hdmitx_get_frame_duration(void)
return frame_duration;
}
static int hdmitx_check_vic(int vic)
{
struct hdmitx_dev *hdev = &hdmitx_device;
int i;
for (i = 0; i < hdev->tx_comm.rxcap.VIC_count && i < VIC_MAX_NUM; i++) {
if (vic == hdev->tx_comm.rxcap.VIC[i])
return 1;
}
return 0;
}
static int hdmitx_check_valid_aspect_ratio(enum hdmi_vic vic, int aspect_ratio)
{
switch (vic) {
case HDMI_720x480p60_4x3:
if (hdmitx_check_vic(HDMI_720x480p60_16x9)) {
if (hdmitx_edid_validate_mode(&hdmitx_device.tx_comm.rxcap,
HDMI_720x480p60_16x9) == 0) {
if (aspect_ratio == AR_16X9)
return 1;
pr_info("same aspect_ratio = %d\n", aspect_ratio);
@@ -1203,7 +1186,8 @@ static int hdmitx_check_valid_aspect_ratio(enum hdmi_vic vic, int aspect_ratio)
}
break;
case HDMI_720x480p60_16x9:
if (hdmitx_check_vic(HDMI_720x480p60_4x3)) {
if (hdmitx_edid_validate_mode(&hdmitx_device.tx_comm.rxcap,
HDMI_720x480p60_4x3) == 0) {
if (aspect_ratio == AR_4X3)
return 1;
pr_info("same aspect_ratio = %d\n", aspect_ratio);
@@ -1212,7 +1196,8 @@ static int hdmitx_check_valid_aspect_ratio(enum hdmi_vic vic, int aspect_ratio)
}
break;
case HDMI_720x576p50_4x3:
if (hdmitx_check_vic(HDMI_720x576p50_16x9)) {
if (hdmitx_edid_validate_mode(&hdmitx_device.tx_comm.rxcap,
HDMI_720x576p50_16x9) == 0) {
if (aspect_ratio == AR_16X9)
return 1;
pr_info("same aspect_ratio = %d\n", aspect_ratio);
@@ -1221,7 +1206,8 @@ static int hdmitx_check_valid_aspect_ratio(enum hdmi_vic vic, int aspect_ratio)
}
break;
case HDMI_720x576p50_16x9:
if (hdmitx_check_vic(HDMI_720x576p50_4x3)) {
if (hdmitx_edid_validate_mode(&hdmitx_device.tx_comm.rxcap,
HDMI_720x576p50_4x3) == 0) {
if (aspect_ratio == AR_4X3)
return 1;
pr_info("same aspect_ratio = %d\n", aspect_ratio);
@@ -1266,10 +1252,11 @@ struct aspect_ratio_list *hdmitx_get_support_ar_list(void)
{
static struct aspect_ratio_list ar_list[4];
int i = 0;
struct rx_cap *prxcap = &hdmitx_device.tx_comm.rxcap;
memset(ar_list, 0, sizeof(ar_list));
if (hdmitx_check_vic(HDMI_720x480p60_4x3) &&
hdmitx_check_vic(HDMI_720x480p60_16x9)) {
if (hdmitx_edid_validate_mode(prxcap, HDMI_720x480p60_4x3) == 0 &&
hdmitx_edid_validate_mode(prxcap, HDMI_720x480p60_16x9) == 0) {
ar_list[i].vic = HDMI_720x480p60_4x3;
ar_list[i].flag = TRUE;
ar_list[i].aspect_ratio_num = 4;
@@ -1282,8 +1269,8 @@ struct aspect_ratio_list *hdmitx_get_support_ar_list(void)
ar_list[i].aspect_ratio_den = 9;
i++;
}
if (hdmitx_check_vic(HDMI_720x576p50_4x3) &&
hdmitx_check_vic(HDMI_720x576p50_16x9)) {
if (hdmitx_edid_validate_mode(prxcap, HDMI_720x576p50_4x3) == 0 &&
hdmitx_edid_validate_mode(prxcap, HDMI_720x576p50_16x9) == 0) {
ar_list[i].vic = HDMI_720x576p50_4x3;
ar_list[i].flag = TRUE;
ar_list[i].aspect_ratio_num = 4;
@@ -1693,20 +1680,6 @@ static void hdmitx_set_drm_pkt(struct master_display_info_s *data)
spin_unlock_irqrestore(&hdev->edid_spinlock, flags);
}
static int hdmi_get_valid_fmt_para(struct hdmitx_dev *hdev,
char const *name, char const *attr, struct hdmi_format_para *para)
{
enum hdmi_vic vic = HDMI_0_UNKNOWN;
vic = hdmitx_edid_get_VIC(hdev, name, 0);
if (vic == HDMI_0_UNKNOWN) {
pr_err("%s: get vic from (%s) fail\n", __func__, name);
return -EINVAL;
}
return hdmi_get_fmt_para(vic, attr, para);
}
static int calc_vinfo_from_hdmi_timing(const struct hdmi_timing *timing, struct vinfo_s *tx_vinfo)
{
/* manually assign hdmitx_vinfo from timing */
@@ -1756,8 +1729,18 @@ static void update_para_from_mode(struct hdmitx_dev *hdev,
struct hdmi_format_para *update_para)
{
struct vinfo_s *vinfo = &hdev->tx_comm.hdmitx_vinfo;
enum hdmi_vic vic = HDMI_0_UNKNOWN;
if (hdmi_get_valid_fmt_para(hdev, name, fmt_attr, update_para) < 0) {
vic = hdmitx_parse_mode_vic(&hdev->tx_comm, name);
if (vic == HDMI_0_UNKNOWN) {
pr_err("%s: get vic from (%s) fail\n", __func__, name);
return;
}
if (hdmitx_common_validate_mode(&hdev->tx_comm, vic) != 0)
return;
if (hdmi_get_fmt_para(vic, fmt_attr, update_para) < 0) {
pr_err("get format para failed (%s,%s)\n", name, fmt_attr);
hdmitx_reset_format_para(update_para);
return;
@@ -1789,14 +1772,7 @@ static void update_current_para(struct hdmitx_dev *hdev)
if (!info || !info->name)
return;
memset(mode, 0, sizeof(mode));
if (!info || !info->name)
strncpy(mode, " ", sizeof(mode) - 1);
else
strncpy(mode, info->name, sizeof(mode) - 1);
if (strstr(hdev->tx_comm.fmt_attr, "420")) {
if (!strstr(mode, "420"))
strncat(mode, "420", sizeof(mode) - strlen("420") - 1);
}
strncpy(mode, info->name, sizeof(mode) - 1);
update_para_from_mode(hdev, mode,
hdev->tx_comm.fmt_attr, &hdev->tx_comm.fmt_para);
@@ -2890,104 +2866,6 @@ static ssize_t debug_store(struct device *dev,
return count;
}
/* check the resolution is over 1920x1080 or not */
static bool is_over_1080p(const struct hdmi_timing *timing)
{
if (!timing)
return 1;
if (timing->h_active > 1920 || timing->v_active > 1080)
return 1;
return 0;
}
/* check the fresh rate is over 60hz or not */
static bool is_over_60hz(const struct hdmi_timing *timing)
{
if (!timing)
return 1;
if (timing->v_freq > 60000)
return 1;
return 0;
}
/* test current vic is over 150MHz or not */
static bool is_over_pixel_150mhz(const struct hdmi_timing *timing)
{
if (!timing)
return 1;
if (timing->pixel_freq > 150000)
return 1;
return 0;
}
bool validate_mode_refreshrate(enum hdmi_vic vic, u32 maxfreq)
{
const struct hdmi_timing *timing = hdmitx_mode_vic_to_hdmi_timing(vic);
if (!timing || vic == HDMI_0_UNKNOWN)
return false;
/* if the vic equals to HDMI_UNKNOWN or VESA,
* then create it as over limited
*/
if (vic >= HDMITX_VESA_OFFSET)
return true;
if (timing->v_freq > (maxfreq * 1000)) {
pr_info("validate refreshrate (%s)-(%d) fail\n",
timing->name, timing->v_freq);
return false;
}
return true;
}
bool is_vic_over_limited_1080p(enum hdmi_vic vic)
{
const struct hdmi_timing *timing = hdmitx_mode_vic_to_hdmi_timing(vic);
if (!timing) {
pr_err("unsupported vic: %d\n", vic);
return 1;
}
/* if the vic equals to HDMI_UNKNOWN or VESA,
* then create it as over limited
*/
if (vic == HDMI_UNKNOWN || vic >= HDMITX_VESA_OFFSET)
return 1;
if (is_over_1080p(timing) || is_over_60hz(timing) ||
is_over_pixel_150mhz(timing)) {
pr_err("over limited vic: %d\n", vic);
return 1;
} else {
return 0;
}
}
/* the hdmitx output limits to 1080p */
bool hdmitx_limited_1080p(void)
{
return res_1080p;
}
bool hdmitx_validate_vic_para(enum hdmi_vic vic, const char *attr)
{
struct hdmi_format_para tst_para;
if (hdmi_get_fmt_para(vic, attr, &tst_para) < 0)
return false;
return hdmitx_edid_check_valid_mode(&hdmitx_device, &tst_para);
}
/* for some non-std TV, it declare 4k while MAX_TMDS_CLK
* not match 4K format, so filter out mode list by
* check if basic color space/depth is supported
@@ -2995,6 +2873,8 @@ bool hdmitx_validate_vic_para(enum hdmi_vic vic, const char *attr)
*/
static bool hdmitx_validate_vic(enum hdmi_vic vic)
{
struct hdmi_format_para tst_para;
if (vic == HDMI_0_UNKNOWN)
return false;
@@ -3002,22 +2882,23 @@ static bool hdmitx_validate_vic(enum hdmi_vic vic)
vic == HDMI_97_3840x2160p60_16x9 ||
vic == HDMI_101_4096x2160p50_256x135 ||
vic == HDMI_102_4096x2160p60_256x135) {
if (hdmitx_validate_vic_para(vic, "420,8bit"))
return true;
if (hdmitx_validate_vic_para(vic, "rgb,8bit"))
return true;
if (hdmitx_validate_vic_para(vic, "444,8bit"))
return true;
if (hdmitx_validate_vic_para(vic, "422,12bit"))
return true;
} else {
if (hdmitx_validate_vic_para(vic, "rgb,8bit"))
return true;
if (hdmitx_validate_vic_para(vic, "444,8bit"))
return true;
if (hdmitx_validate_vic_para(vic, "422,12bit"))
if (hdmi_get_fmt_para(vic, "420,8bit", &tst_para) == 0 &&
hdmitx_edid_check_valid_mode(&hdmitx_device, &tst_para))
return true;
}
if (hdmi_get_fmt_para(vic, "rgb,8bit", &tst_para) == 0 &&
hdmitx_edid_check_valid_mode(&hdmitx_device, &tst_para))
return true;
if (hdmi_get_fmt_para(vic, "444,8bit", &tst_para) == 0 &&
hdmitx_edid_check_valid_mode(&hdmitx_device, &tst_para))
return true;
if (hdmi_get_fmt_para(vic, "422,12bit", &tst_para) == 0 &&
hdmitx_edid_check_valid_mode(&hdmitx_device, &tst_para))
return true;
return false;
}
@@ -3053,7 +2934,8 @@ static ssize_t disp_cap_show(struct device *dev,
vic == HDMI_6_720x480i60_4x3 ||
vic == HDMI_17_720x576p50_4x3 ||
vic == HDMI_21_720x576i50_4x3) {
if (hdmitx_check_vic(vic + 1)) {
if (hdmitx_edid_validate_mode(&hdmitx_device.tx_comm.rxcap,
vic + 1) == 0) {
pr_info("%s: check vic exist, handle [%d] later.\n",
__func__, vic + 1);
continue;
@@ -3066,13 +2948,11 @@ static ssize_t disp_cap_show(struct device *dev,
continue;
}
/*filter 1080p max size.*/
if (hdmitx_limited_1080p() && is_vic_over_limited_1080p(vic))
continue;
/*filter max refreshrate.*/
if (validate_mode_refreshrate(vic, max_refreshrate) == false)
if (hdmitx_common_validate_mode(&hdmitx_device.tx_comm, vic) != 0) {
if (hdmitx_device.log_level & EDID_LOG)
pr_err("%s: vic[%d] over range.\n", __func__, vic);
continue;
}
mode_name = timing->sname ? timing->sname : timing->name;
@@ -3400,20 +3280,39 @@ static ssize_t dc_cap_show(struct device *dev,
return pos;
}
static bool pre_process_str(char *name)
static bool pre_process_str(const char *name, char *mode, char *attr)
{
int i;
unsigned int flag = 0;
char *color_format[4] = {"444", "422", "420", "rgb"};
char *search_pos = 0;
if (!mode || !attr)
return false;
for (i = 0 ; i < 4 ; i++) {
if (strstr(name, color_format[i]))
flag++;
search_pos = strstr(name, color_format[i]);
if (search_pos)
break;
}
if (flag >= 2)
/*no cs parsed, return error.*/
if (!search_pos)
return false;
else
return true;
/*search remaining color_formats, if have more than one cs string, return error.*/
i++;
for (; i < 4 ; i++) {
if (strstr(search_pos, color_format[i]))
return false;
}
/*copy mode name;*/
memcpy(mode, name, search_pos - name);
/*copy attr str;*/
memcpy(attr, search_pos, strlen(search_pos));
// pr_info("%s parse (%s,%s) from (%s)\n", __func__, mode, attr, name);
return true;
}
static ssize_t valid_mode_store(struct device *dev,
@@ -3423,30 +3322,37 @@ static ssize_t valid_mode_store(struct device *dev,
int ret;
bool valid_mode = false;
char cvalid_mode[32];
char modename[32], attrstr[32];
struct hdmi_format_para tst_para;
enum hdmi_vic vic = HDMI_0_UNKNOWN;
mutex_lock(&valid_mode_mutex);
memset(modename, 0, sizeof(modename));
memset(attrstr, 0, sizeof(attrstr));
memset(cvalid_mode, 0, sizeof(cvalid_mode));
strncpy(cvalid_mode, buf, sizeof(cvalid_mode));
cvalid_mode[31] = '\0';
if (cvalid_mode[0]) {
valid_mode = pre_process_str(cvalid_mode);
if (valid_mode) {
if (hdmi_get_valid_fmt_para(&hdmitx_device,
cvalid_mode, cvalid_mode, &tst_para) == 0)
valid_mode = true;
else
valid_mode = false;
}
if (cvalid_mode[0])
valid_mode = pre_process_str(cvalid_mode, modename, attrstr);
if (valid_mode) {
vic = hdmitx_parse_mode_vic(&hdmitx_device.tx_comm, modename);
if (vic == HDMI_0_UNKNOWN ||
hdmitx_common_validate_mode(&hdmitx_device.tx_comm, vic) != 0)
valid_mode = false;
}
if (valid_mode && hdmi_get_fmt_para(vic, attrstr, &tst_para) != 0)
valid_mode = false;
if (valid_mode)
valid_mode = hdmitx_edid_check_valid_mode(&hdmitx_device, &tst_para);
ret = valid_mode ? count : -1;
ret = valid_mode ? count : -1;
if (ret == -1)
pr_info("hdmitx: valid_mode %s fail\n", cvalid_mode);
pr_err("hdmitx: valid_mode %s fail\n", cvalid_mode);
mutex_unlock(&valid_mode_mutex);
@@ -6439,8 +6345,6 @@ int tv_audio_support(int type, struct rx_cap *prxcap)
static bool is_cur_tmds_div40(struct hdmitx_dev *hdev)
{
struct hdmitx_common *tx_comm = &hdev->tx_comm;
const struct hdmi_timing *timing = NULL;
const char *modename = NULL;
struct hdmi_format_para tst_para;
unsigned int act_clk = 0;
@@ -6449,19 +6353,12 @@ static bool is_cur_tmds_div40(struct hdmitx_dev *hdev)
pr_info("hdmitx: get vic %d cs,cd %s\n", hdev->tx_comm.cur_VIC, tx_comm->fmt_attr);
timing = hdmitx_mode_vic_to_hdmi_timing(hdev->tx_comm.cur_VIC);
if (!timing) {
pr_err("%s[%d] can't get timing from [%d]\n",
if (hdmi_get_fmt_para(hdev->tx_comm.cur_VIC, tx_comm->fmt_attr, &tst_para) < 0) {
pr_info("%s[%d] get mode fail [%d] exit.\n",
__func__, __LINE__, hdev->tx_comm.cur_VIC);
return 0;
}
modename = timing->sname ? timing->sname : timing->name;
if (hdmi_get_valid_fmt_para(hdev, modename, tx_comm->fmt_attr, &tst_para) < 0) {
pr_info("%s[%d] get mode fail [%s] exit.\n", __func__, __LINE__, modename);
return 0;
}
act_clk = tst_para.tmds_clk / 1000;
pr_info("hdmitx: %s original clock %d\n", __func__, act_clk);
@@ -6968,13 +6865,13 @@ static int amhdmitx_get_dt_info(struct platform_device *pdev)
hdmitx_device.dongle_mode);
/* Get res_1080p information */
ret = of_property_read_u32(pdev->dev.of_node, "res_1080p",
&res_1080p);
res_1080p = !!res_1080p;
&hdmitx_device.tx_comm.res_1080p);
hdmitx_device.tx_comm.res_1080p = !!hdmitx_device.tx_comm.res_1080p;
ret = of_property_read_u32(pdev->dev.of_node, "max_refreshrate",
&refreshrate_limit);
if (ret == 0 && refreshrate_limit > 0)
max_refreshrate = refreshrate_limit;
hdmitx_device.tx_comm.max_refreshrate = refreshrate_limit;
/* Get repeater_tx information */
ret = of_property_read_u32(pdev->dev.of_node,
@@ -7159,7 +7056,7 @@ static int amhdmitx_probe(struct platform_device *pdev)
struct hdmitx_common *tx_comm = &hdev->tx_comm;
pr_debug(SYS "%s start\n", __func__);
hdmitx_common_init(tx_comm);
hdmitx_common_init(tx_comm, &hdev->tx_hw);
amhdmitx_device_init(hdev, get_hdmitx_boot_params());
ret = amhdmitx_get_dt_info(pdev);
@@ -7585,26 +7482,19 @@ static int drm_hdmitx_get_vic_list(int **vics)
vic == HDMI_6_720x480i60_4x3 ||
vic == HDMI_17_720x576p50_4x3 ||
vic == HDMI_21_720x576i50_4x3) {
if (hdmitx_check_vic(vic + 1)) {
if (hdmitx_edid_validate_mode(&hdmitx_device.tx_comm.rxcap, vic + 1) == 0) {
pr_info("%s: check vic exist, handle [%d] later.\n",
__func__, vic + 1);
continue;
}
}
if (hdmitx_limited_1080p() && is_vic_over_limited_1080p(vic)) {
if (hdmitx_common_validate_mode(&hdmitx_device.tx_comm, vic) != 0) {
if (hdmitx_device.log_level & EDID_LOG)
pr_err("%s: vic[%d] over range.\n", __func__, vic);
continue;
}
if (validate_mode_refreshrate(vic, max_refreshrate) == false) {
if (hdmitx_device.log_level & EDID_LOG)
pr_err("%s: vic[%d] over refresh rate[%d].\n",
__func__, vic, max_refreshrate);
continue;
}
if (!hdmitx_validate_vic(vic)) {
if (hdmitx_device.log_level & EDID_LOG)
pr_err("%s: vic[%d] check fmt attr failed.\n", __func__, vic);
@@ -7768,15 +7658,15 @@ bool drm_hdmitx_chk_mode_attr_sup(char *mode, char *attr)
if (!mode || !attr)
return false;
if (!pre_process_str(attr))
return false;
vic = hdmitx_edid_get_VIC(&hdmitx_device, mode, 0);
vic = hdmitx_parse_mode_vic(&hdmitx_device.tx_comm, mode);
if (vic == HDMI_0_UNKNOWN) {
pr_err("%s: get vic from (%s) fail\n", __func__, mode);
return false;
}
if (hdmitx_common_validate_mode(&hdmitx_device.tx_comm, vic) != 0)
return false;
if (hdmi_get_fmt_para(vic, attr, &tst_para) < 0)
return false;
+1 -1
View File
@@ -6391,7 +6391,7 @@ static int amhdmitx_probe(struct platform_device *pdev)
struct hdmitx_dev *hdev = get_hdmitx21_device();
struct hdmitx_common *tx_comm = &hdev->tx_comm;
hdmitx_common_init(&hdev->tx_comm);
hdmitx_common_init(&hdev->tx_comm, &hdev->tx_hw);
pr_debug("amhdmitx_probe_start\n");
amhdmitx21_device_init(hdev);
+125 -10
View File
@@ -3,10 +3,13 @@
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/amlogic/media/vout/hdmitx_common/hdmitx_common.h>
#include <hdmitx_boot_parameters.h>
const struct hdmi_timing *hdmitx_mode_match_timing_name(const char *name);
struct hdmitx_base_state *hdmitx_get_mod_state(struct hdmitx_common *tx_common,
enum HDMITX_MODULE type)
{
@@ -27,31 +30,78 @@ void hdmitx_get_init_state(struct hdmitx_common *tx_common,
}
EXPORT_SYMBOL(hdmitx_get_init_state);
int hdmitx_common_init(struct hdmitx_common *tx_common)
int hdmitx_common_init(struct hdmitx_common *tx_comm, struct hdmitx_hw_common *hw_comm)
{
struct hdmitx_boot_param *boot_param = get_hdmitx_boot_params();
/*load tx boot params*/
tx_common->hdr_priority = boot_param->hdr_mask;
memcpy(tx_common->hdmichecksum, boot_param->edid_chksum, sizeof(tx_common->hdmichecksum));
tx_comm->hdr_priority = boot_param->hdr_mask;
memcpy(tx_comm->hdmichecksum, boot_param->edid_chksum, sizeof(tx_comm->hdmichecksum));
memcpy(tx_common->fmt_attr, boot_param->color_attr, sizeof(tx_common->fmt_attr));
memcpy(tx_common->backup_fmt_attr, boot_param->color_attr, sizeof(tx_common->fmt_attr));
memcpy(tx_comm->fmt_attr, boot_param->color_attr, sizeof(tx_comm->fmt_attr));
memcpy(tx_comm->backup_fmt_attr, boot_param->color_attr, sizeof(tx_comm->fmt_attr));
tx_common->frac_rate_policy = boot_param->fraction_refreshrate;
tx_common->backup_frac_rate_policy = boot_param->fraction_refreshrate;
tx_common->config_csc_en = boot_param->config_csc;
tx_comm->frac_rate_policy = boot_param->fraction_refreshrate;
tx_comm->backup_frac_rate_policy = boot_param->fraction_refreshrate;
tx_comm->config_csc_en = boot_param->config_csc;
tx_comm->res_1080p = 0;
tx_comm->max_refreshrate = 60;
tx_comm->tx_hw = hw_comm;
/*mutex init*/
mutex_init(&tx_common->setclk_mutex);
mutex_init(&tx_comm->setclk_mutex);
return 0;
}
int hdmitx_common_destroy(struct hdmitx_common *tx_common)
int hdmitx_common_destroy(struct hdmitx_common *tx_comm)
{
return 0;
}
int hdmitx_common_validate_mode(struct hdmitx_common *tx_comm, u32 vic)
{
const struct hdmi_timing *timing = hdmitx_mode_vic_to_hdmi_timing(vic);
if (!timing)
return -EINVAL;
/*soc level filter*/
/*filter 1080p max size.*/
if (tx_comm->res_1080p) {
/* if the vic equals to HDMI_UNKNOWN or VESA,
* then create it as over limited
*/
if (vic == HDMI_0_UNKNOWN || vic >= HDMITX_VESA_OFFSET)
return -ERANGE;
/* check the resolution is over 1920x1080 or not */
if (timing->h_active > 1920 || timing->v_active > 1080)
return -ERANGE;
/* check the fresh rate is over 60hz or not */
if (timing->v_freq > 60000)
return -ERANGE;
/* test current vic is over 150MHz or not */
if (timing->pixel_freq > 150000)
return -ERANGE;
}
/*filter max refreshrate.*/
if (timing->v_freq > (tx_comm->max_refreshrate * 1000)) {
pr_info("validate refreshrate (%s)-(%d) fail\n",
timing->name, timing->v_freq);
return -EACCES;
}
/*ip level filter*/
if (tx_comm->tx_hw->validatemode(vic) != 0)
return -EPERM;
return 0;
}
int hdmitx_hpd_notify_unlocked(struct hdmitx_common *tx_comm)
{
if (tx_comm->drm_hpd_cb.callback)
@@ -145,6 +195,71 @@ int hdmitx_update_edid_chksum(u8 *buf, u32 block_cnt, struct rx_cap *rxcap)
return 0;
}
static enum hdmi_vic get_alternate_ar_vic(enum hdmi_vic vic)
{
int i = 0;
struct {
u32 mode_16x9_vic;
u32 mode_4x3_vic;
} vic_pairs[] = {
{HDMI_7_720x480i60_16x9, HDMI_6_720x480i60_4x3},
{HDMI_3_720x480p60_16x9, HDMI_2_720x480p60_4x3},
{HDMI_22_720x576i50_16x9, HDMI_21_720x576i50_4x3},
{HDMI_18_720x576p50_16x9, HDMI_17_720x576p50_4x3},
};
for (i = 0; i < ARRAY_SIZE(vic_pairs); i++) {
if (vic_pairs[i].mode_16x9_vic == vic)
return vic_pairs[i].mode_4x3_vic;
if (vic_pairs[i].mode_4x3_vic == vic)
return vic_pairs[i].mode_16x9_vic;
}
return HDMI_0_UNKNOWN;
}
int hdmitx_parse_mode_vic(struct hdmitx_common *tx_comm, const char *mode)
{
const struct hdmi_timing *timing;
enum hdmi_vic vic = HDMI_0_UNKNOWN;
enum hdmi_vic alternate_vic = HDMI_0_UNKNOWN;
/*parse by name to find default mode*/
timing = hdmitx_mode_match_timing_name(mode);
if (!timing || timing->vic == HDMI_0_UNKNOWN)
return HDMI_0_UNKNOWN;
vic = timing->vic;
/* for compatibility: 480p/576p
* 480p/576p use same short name in hdmitx_timing table, so when match name, will return
* 4x3 mode fist. But user prefer 16x9 first, so try 16x9 first;
*/
alternate_vic = get_alternate_ar_vic(vic);
if (alternate_vic != HDMI_0_UNKNOWN) {
pr_info("get alternate vic %d->%d\n", vic, alternate_vic);
vic = alternate_vic;
}
/*check if vic supported by rx*/
if (hdmitx_edid_validate_mode(&tx_comm->rxcap, vic) == 0)
return vic;
/* for compatibility: 480p/576p, will get 0 if there is no alternate vic;*/
alternate_vic = get_alternate_ar_vic(vic);
if (alternate_vic != vic) {
pr_info("get alternate vic %d->%d\n", vic, alternate_vic);
vic = alternate_vic;
}
if (vic != HDMI_0_UNKNOWN && hdmitx_edid_validate_mode(&tx_comm->rxcap, vic) != 0)
vic = HDMI_0_UNKNOWN;
if (vic == HDMI_0_UNKNOWN)
pr_err("%s: parse mode %s fail\n", __func__, mode);
return vic;
}
/********************************Debug function***********************************/
int hdmitx_load_edid_file(char *path)
{
@@ -183,3 +183,31 @@ u32 hdmitx_edid_get_hdmi14_4k_vic(u32 vic)
return ret;
}
int hdmitx_edid_validate_mode(struct rx_cap *rxcap, u32 vic)
{
int i = 0;
bool edid_matched = false;
if (vic < HDMITX_VESA_OFFSET) {
/*check cea cap*/
for (i = 0 ; i < rxcap->VIC_count; i++) {
if (rxcap->VIC[i] == vic) {
edid_matched = true;
break;
}
}
} else {
enum hdmi_vic *vesa_t = &rxcap->vesa_timing[0];
/*check vesa mode.*/
for (i = 0; i < VESA_MAX_TIMING && vesa_t[i]; i++) {
if (vic == vesa_t[i]) {
edid_matched = true;
break;
}
}
}
return edid_matched ? 0 : -EINVAL;
}
@@ -24,10 +24,3 @@ int hdmitx_hw_set_phy(struct hdmitx_hw_common *tx_hw, int flag)
return 0;
}
int hdmitx_hw_validate_mode(struct hdmitx_hw_common *tx_hw,
u32 vic)
{
return tx_hw->validatemode(vic);
}
+4 -25
View File
@@ -24,7 +24,7 @@ static const struct hdmi_timing edid_cea_modes_0[] = {
{HDMI_0_UNKNOWN, "invalid", NULL},
{HDMI_1_640x480p60_4x3, "640x480p60hz", NULL, 1, 31469, 59940, 25175,
800, 160, 16, 96, 48, 640, 525, 45, 10, 2, 33, 480, 1, 0, 0, 4, 3, 1, 1},
{HDMI_2_720x480p60_4x3, "720x480p60hz", "480p60hz_4x3", 1, 31469, 59940, 27000,
{HDMI_2_720x480p60_4x3, "720x480p60hz", "480p60hz", 1, 31469, 59940, 27000,
858, 138, 16, 62, 60, 720, 525, 45, 9, 6, 30, 480, 7, 0, 0, 4, 3, 8, 9},
{HDMI_3_720x480p60_16x9, "720x480p60hz", "480p60hz", 1, 31469, 59940, 27000,
858, 138, 16, 62, 60, 720, 525, 45, 9, 6, 30, 480, 7, 0, 0, 16, 9, 32, 27},
@@ -54,7 +54,7 @@ static const struct hdmi_timing edid_cea_modes_0[] = {
1716, 276, 32, 124, 120, 1440, 525, 45, 9, 6, 30, 480, 7, 0, 0, 16, 9, 16, 27},
{HDMI_16_1920x1080p60_16x9, "1920x1080p60hz", "1080p60hz", 1, 67500, 60000, 148500,
2200, 280, 88, 44, 148, 1920, 1125, 45, 4, 5, 36, 1080, 1, 1, 1, 16, 9, 1, 1},
{HDMI_17_720x576p50_4x3, "720x576p50hz", "576p50hz_4x3", 1, 31250, 50000, 27000,
{HDMI_17_720x576p50_4x3, "720x576p50hz", "576p50hz", 1, 31250, 50000, 27000,
864, 144, 12, 64, 68, 720, 625, 49, 5, 5, 39, 576, 1, 0, 0, 4, 3, 16, 15},
{HDMI_18_720x576p50_16x9, "720x576p50hz", "576p50hz", 1, 31250, 50000, 27000,
864, 144, 12, 64, 68, 720, 625, 49, 5, 5, 39, 576, 1, 0, 0, 16, 9, 64, 65},
@@ -546,11 +546,11 @@ const struct hdmi_timing *hdmitx_mode_match_timing_name(const char *name)
break;
/* check sname first */
if (timing->sname && !strncmp(timing->sname, name, strlen(timing->sname)))
if (timing->sname && !strcmp(timing->sname, name))
return timing;
/* check full name first */
if (!strncmp(timing->name, name, strlen(timing->name)))
if (!strcmp(timing->name, name))
return timing;
i++;
@@ -636,27 +636,6 @@ int hdmitx_mode_update_timing(struct hdmi_timing *t,
return alternate_clock;
}
enum hdmi_vic hdmitx_mode_get_alternate_4x3_vic(enum hdmi_vic vic)
{
int i = 0;
struct {
u32 mode_16x9_vic;
u32 mode_4x3_vic;
} vic_pairs[] = {
{HDMI_7_720x480i60_16x9, HDMI_6_720x480i60_4x3},
{HDMI_3_720x480p60_16x9, HDMI_2_720x480p60_4x3},
{HDMI_22_720x576i50_16x9, HDMI_21_720x576i50_4x3},
{HDMI_18_720x576p50_16x9, HDMI_17_720x576p50_4x3},
};
for (i = 0; i < ARRAY_SIZE(vic_pairs); i++) {
if (vic_pairs[i].mode_16x9_vic == vic)
return vic_pairs[i].mode_4x3_vic;
}
return HDMI_0_UNKNOWN;
}
void hdmitx_mode_print_hdmi_timing(const struct hdmi_timing *t)
{
struct hdmi_timing alternate_t;
@@ -481,9 +481,6 @@ struct hdmitx_dev {
**********************************************************************/
int hdmitx_edid_parse(struct hdmitx_dev *hdmitx_device);
int check_dvi_hdmi_edid_valid(unsigned char *buf);
enum hdmi_vic hdmitx_edid_get_VIC(struct hdmitx_dev *hdmitx_device,
const char *disp_mode,
char force_flag);
bool hdmitx_edid_check_valid_mode(struct hdmitx_dev *hdev,
struct hdmi_format_para *para);
void hdmitx_edid_clear(struct hdmitx_dev *hdmitx_device);
@@ -507,11 +504,6 @@ bool is_hdmi14_4k(enum hdmi_vic vic);
*/
bool is_hdmi4k_support_420(enum hdmi_vic vic);
/* the hdmitx output limits to 1080p */
bool hdmitx_limited_1080p(void);
/* test current vic is over limited or not */
bool is_vic_over_limited_1080p(enum hdmi_vic vic);
/*
* HDMI Repeater TX I/F
* RX downstream Information from rptx to rprx
@@ -11,6 +11,7 @@
#include <linux/hdmi.h>
#include <drm/amlogic/meson_connector_dev.h>
#include <linux/amlogic/media/vout/hdmitx_common/hdmitx_hw_common.h>
#include <linux/amlogic/media/vout/hdmitx_common/hdmitx_edid.h>
#include <linux/amlogic/media/vout/hdmitx_common/hdmitx_types.h>
@@ -67,6 +68,12 @@ struct hdmitx_common {
struct hdmitx_base_state *states[HDMITX_MAX_MODULE];
struct hdmitx_base_state *old_states[HDMITX_MAX_MODULE];
/*soc limitation*/
int res_1080p;
int max_refreshrate;
struct hdmitx_hw_common *tx_hw;
};
struct hdmitx_base_state *hdmitx_get_mod_state(struct hdmitx_common *tx_common,
@@ -76,7 +83,7 @@ struct hdmitx_base_state *hdmitx_get_old_mod_state(struct hdmitx_common *tx_comm
void hdmitx_get_init_state(struct hdmitx_common *tx_common,
struct hdmitx_binding_state *state);
int hdmitx_common_init(struct hdmitx_common *tx_common);
int hdmitx_common_init(struct hdmitx_common *tx_common, struct hdmitx_hw_common *hw_comm);
int hdmitx_common_destroy(struct hdmitx_common *tx_common);
int hdmitx_hpd_notify_unlocked(struct hdmitx_common *tx_comm);
@@ -86,6 +93,13 @@ unsigned char *hdmitx_get_raw_edid(struct hdmitx_common *tx_comm);
int hdmitx_setup_attr(struct hdmitx_common *tx_comm, const char *buf);
int hdmitx_get_attr(struct hdmitx_common *tx_comm, char attr[16]);
/* modename policy: get vic from name and check if support by rx;
* return the vic of mode, if failed return HDMI_0_UNKNOWN;
*/
int hdmitx_parse_mode_vic(struct hdmitx_common *tx_comm, const char *mode);
int hdmitx_common_validate_mode(struct hdmitx_common *tx_comm, u32 vic);
int hdmitx_get_hdrinfo(struct hdmitx_common *tx_comm, struct hdr_info *hdrinfo);
/*edid related function.*/
@@ -248,6 +248,8 @@ enum vsif_type {
u32 hdmitx_edid_get_hdmi14_4k_vic(u32 vic);
void phy_addr_clear(struct vsdb_phyaddr *vsdb_phy_addr);
int hdmitx_edid_validate_mode(struct rx_cap *rxcap, u32 vic);
/*edid is good return 0, otherwise return < 0.*/
int hdmitx_edid_validate(unsigned char *rawedid);
bool hdmitx_edid_is_all_zeros(unsigned char *rawedid);
@@ -188,7 +188,5 @@ int hdmitx_hw_avmute(struct hdmitx_hw_common *tx_hw,
int muteflag);
int hdmitx_hw_set_phy(struct hdmitx_hw_common *tx_hw,
int flag);
int hdmitx_hw_validate_mode(struct hdmitx_hw_common *tx_hw,
u32 vic);
#endif