diff --git a/drivers/media/i2c/rk628/rk628.c b/drivers/media/i2c/rk628/rk628.c index ab354f8d015e..b57dbc8e326a 100644 --- a/drivers/media/i2c/rk628/rk628.c +++ b/drivers/media/i2c/rk628/rk628.c @@ -78,6 +78,8 @@ static const struct regmap_range rk628_hdmirx_readable_ranges[] = { regmap_reg_range(HDMI_RX_PDEC_ACR_CTS, HDMI_RX_PDEC_ACR_N), regmap_reg_range(HDMI_RX_PDEC_AVI_HB, HDMI_RX_PDEC_AVI_PB), regmap_reg_range(HDMI_RX_PDEC_AIF_CTRL, HDMI_RX_PDEC_AIF_PB0), + regmap_reg_range(HDMI_RX_PDEC_GMD_HB0, HDMI_RX_PDEC_GMD_PB0), + regmap_reg_range(HDMI_RX_PDEC_DRM_HB, HDMI_RX_PDEC_DRM_PAYLOAD6), regmap_reg_range(HDMI_RX_HDMI20_CONTROL, HDMI_RX_CHLOCK_CONFIG), regmap_reg_range(HDMI_RX_SCDC_REGS0, HDMI_RX_SCDC_REGS2), regmap_reg_range(HDMI_RX_SCDC_WRDATA0, HDMI_RX_SCDC_WRDATA0), diff --git a/drivers/media/i2c/rk628/rk628_csi_v4l2.c b/drivers/media/i2c/rk628/rk628_csi_v4l2.c index f699966f89cb..a10a381bc69c 100644 --- a/drivers/media/i2c/rk628/rk628_csi_v4l2.c +++ b/drivers/media/i2c/rk628/rk628_csi_v4l2.c @@ -133,6 +133,7 @@ struct rk628_csi { bool is_streaming; bool csi_ints_en; bool dual_mipi_use; + bool hdr_support; enum user_color_range user_color_range; }; @@ -240,6 +241,41 @@ static u8 rk628f_edid_init_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, }; +static u8 rk628f_hdr_edid_init_data[] = { + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, + 0x24, 0xD0, 0x8F, 0x62, 0x01, 0x00, 0x00, 0x00, + 0x2D, 0x21, 0x01, 0x03, 0x80, 0x78, 0x44, 0x78, + 0x0A, 0xCF, 0x74, 0xA3, 0x57, 0x4C, 0xB0, 0x23, + 0x09, 0x48, 0x4C, 0x21, 0x08, 0x00, 0x61, 0x40, + 0x01, 0x01, 0x81, 0x00, 0x95, 0x00, 0xA9, 0xC0, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x08, 0xE8, + 0x00, 0x30, 0xF2, 0x70, 0x5A, 0x80, 0xB0, 0x58, + 0x8A, 0x00, 0xC4, 0x8E, 0x21, 0x00, 0x00, 0x1E, + 0x02, 0x3A, 0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, + 0x58, 0x2C, 0x45, 0x00, 0xB9, 0xA8, 0x42, 0x00, + 0x00, 0x1E, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x49, + 0x46, 0x50, 0x20, 0x44, 0x69, 0x73, 0x70, 0x6C, + 0x61, 0x79, 0x0A, 0x20, 0x00, 0x00, 0x00, 0xFD, + 0x00, 0x3B, 0x46, 0x1F, 0x8C, 0x3C, 0x00, 0x0A, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0xA8, + + 0x02, 0x03, 0x40, 0xF2, 0x4D, 0x01, 0x03, 0x12, + 0x13, 0x84, 0x22, 0x1F, 0x90, 0x5D, 0x5E, 0x5F, + 0x60, 0x61, 0x23, 0x09, 0x07, 0x07, 0x83, 0x01, + 0x00, 0x00, 0x6D, 0x03, 0x0C, 0x00, 0x10, 0x00, + 0x18, 0x44, 0x20, 0x00, 0x60, 0x03, 0x02, 0x01, + 0x67, 0xD8, 0x5D, 0xC4, 0x01, 0x78, 0x80, 0x00, + 0xE3, 0x05, 0xE3, 0x01, 0xE4, 0x0F, 0x00, 0x18, + 0x00, 0xE2, 0x00, 0xCB, 0xE3, 0x06, 0x0D, 0x01, + 0x02, 0x3A, 0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, + 0x58, 0x2C, 0x45, 0x00, 0xB9, 0xA8, 0x42, 0x00, + 0x00, 0x1E, 0x08, 0xE8, 0x00, 0x30, 0xF2, 0x70, + 0x5A, 0x80, 0xB0, 0x58, 0x8A, 0x00, 0xC4, 0x8E, + 0x21, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, +}; static struct rk628_edid edid_data[] = { { @@ -250,6 +286,10 @@ static struct rk628_edid edid_data[] = { .version = 2, .data = rk628f_edid_init_data, }, + { + .version = 3, + .data = rk628f_hdr_edid_init_data, + }, }; static const unsigned int rk628_csi_extcon_cable[] = { @@ -1473,6 +1513,10 @@ static void rk628_csi_initial(struct v4l2_subdev *sd) def_edid.edid = edid_init_data; csi->edid_version = 1; } + if (csi->hdr_support && csi->rk628->version >= RK628F_VERSION) { + def_edid.edid = rk628f_hdr_edid_init_data; + csi->edid_version = 3; + } rk628_csi_s_edid(sd, &def_edid); } @@ -2521,6 +2565,7 @@ static long rk628_csi_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) struct rkmodule_capture_info *capture_info; u32 stream = 0; int edid_version, i; + struct hdr_metadata_infoframe hdmi_metadata; switch (cmd) { case RKMODULE_GET_MODULE_INFO: @@ -2619,6 +2664,10 @@ static long rk628_csi_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) } v4l2_info(sd, "the edid version is not supported: %d\n", edid_version); return -EINVAL; + case RK_HDMIRX_CMD_GET_HDR_METADATA: + rk628_hdmirx_get_hdr_matedata(csi->rk628, &hdmi_metadata); + memcpy(arg, &hdmi_metadata, sizeof(hdmi_metadata)); + break; default: ret = -ENOIOCTLCMD; break; @@ -3223,6 +3272,9 @@ static int rk628_csi_probe_of(struct rk628_csi *csi) if (of_property_read_bool(dev->of_node, "cec-enable")) csi->cec_enable = true; + if (of_property_read_bool(dev->of_node, "hdr-support")) + csi->hdr_support = true; + if (of_property_read_bool(dev->of_node, "i2s-enable-default")) i2s_enable_default = true; diff --git a/drivers/media/i2c/rk628/rk628_hdmirx.c b/drivers/media/i2c/rk628/rk628_hdmirx.c index 9c48ab6257fd..1cd59b023287 100644 --- a/drivers/media/i2c/rk628/rk628_hdmirx.c +++ b/drivers/media/i2c/rk628/rk628_hdmirx.c @@ -1572,6 +1572,38 @@ u32 rk628_hdmirx_get_tmdsclk_cnt(struct rk628 *rk628) } EXPORT_SYMBOL(rk628_hdmirx_get_tmdsclk_cnt); +int rk628_hdmirx_get_hdr_matedata(struct rk628 *rk628, + struct hdr_metadata_infoframe *hdmi_metadata) +{ + u32 val; + int i; + + rk628_i2c_read(rk628, HDMI_RX_PDEC_DRM_HB, &val); + if (!val) + return -EINVAL; + + rk628_i2c_read(rk628, HDMI_RX_PDEC_DRM_PAYLOAD0, &val); + hdmi_metadata->eotf = (val >> 8) & 0xff; + hdmi_metadata->metadata_type = (val >> 16) & 0xff; + for (i = 0; i < 3; i++) { + rk628_i2c_read(rk628, HDMI_RX_PDEC_DRM_PAYLOAD1 + i * 4, &val); + hdmi_metadata->display_primaries[i].x = val & 0xffff; + hdmi_metadata->display_primaries[i].y = (val >> 16) & 0xffff; + } + rk628_i2c_read(rk628, HDMI_RX_PDEC_DRM_PAYLOAD4, &val); + hdmi_metadata->white_point.x = val & 0xffff; + hdmi_metadata->white_point.y = (val >> 16) & 0xffff; + rk628_i2c_read(rk628, HDMI_RX_PDEC_DRM_PAYLOAD5, &val); + hdmi_metadata->max_display_mastering_luminance = val & 0xffff; + hdmi_metadata->min_display_mastering_luminance = (val >> 16) & 0xffff; + rk628_i2c_read(rk628, HDMI_RX_PDEC_DRM_PAYLOAD6, &val); + hdmi_metadata->max_cll = val & 0xffff; + hdmi_metadata->max_fall = (val >> 16) & 0xffff; + + return 0; +} +EXPORT_SYMBOL(rk628_hdmirx_get_hdr_matedata); + struct rk628_timings { int vic; int hactive; @@ -2205,6 +2237,7 @@ static int rk628_hdmirx_status_show(struct seq_file *s, void *v) bool plugin; u32 val, htot, vtot, fps, format; u8 fmt, range, space; + struct hdr_metadata_infoframe hdmi_metadata; plugin = rk628_hdmirx_tx_5v_power_detect(rk628->hdmirx_det_gpio); seq_printf(s, "status: %s\n", plugin ? "plugin" : "plugout"); @@ -2265,6 +2298,41 @@ static int rk628_hdmirx_status_show(struct seq_file *s, void *v) else seq_puts(s, "Unknown\n"); + seq_puts(s, "EOTF: "); + if (!rk628_hdmirx_get_hdr_matedata(rk628, &hdmi_metadata)) { + switch (hdmi_metadata.eotf & 0x7) { + case HDMI_EOTF_TRADITIONAL_GAMMA_SDR: + seq_puts(s, "SDR"); + break; + case HDMI_EOTF_TRADITIONAL_GAMMA_HDR: + seq_puts(s, "HDR"); + break; + case HDMI_EOTF_SMPTE_ST2084: + seq_puts(s, "ST2084"); + break; + case HDMI_EOTF_BT_2100_HLG: + seq_puts(s, "HLG"); + break; + default: + seq_puts(s, "Not Defined\n"); + return 0; + } + seq_printf(s, "\nx0: %d", hdmi_metadata.display_primaries[0].x); + seq_printf(s, "\t\t\t\ty0: %d\n", hdmi_metadata.display_primaries[0].y); + seq_printf(s, "x1: %d", hdmi_metadata.display_primaries[1].x); + seq_printf(s, "\t\t\t\ty1: %d\n", hdmi_metadata.display_primaries[1].y); + seq_printf(s, "x2: %d", hdmi_metadata.display_primaries[2].x); + seq_printf(s, "\t\t\t\ty2: %d\n", hdmi_metadata.display_primaries[2].y); + seq_printf(s, "white x: %d", hdmi_metadata.white_point.x); + seq_printf(s, "\t\t\twhite y: %d\n", hdmi_metadata.white_point.y); + seq_printf(s, "max lum: %d", hdmi_metadata.max_display_mastering_luminance); + seq_printf(s, "\t\t\tmin lum: %d\n", hdmi_metadata.min_display_mastering_luminance); + seq_printf(s, "max cll: %d", hdmi_metadata.max_cll); + seq_printf(s, "\t\t\tmax fall: %d\n", hdmi_metadata.max_fall); + } else { + seq_puts(s, "Off\n"); + } + return 0; } diff --git a/drivers/media/i2c/rk628/rk628_hdmirx.h b/drivers/media/i2c/rk628/rk628_hdmirx.h index 99090e1841ff..ed72aa6d8007 100644 --- a/drivers/media/i2c/rk628/rk628_hdmirx.h +++ b/drivers/media/i2c/rk628/rk628_hdmirx.h @@ -8,6 +8,8 @@ #ifndef __RK628_HDMIRX_H #define __RK628_HDMIRX_H +#include +#include #include #include #include @@ -280,6 +282,16 @@ #define HDMI_RX_PDEC_AIF_CTRL (HDMI_RX_BASE + 0x03c0) #define FC_LFE_EXCHG(x) UPDATE(x, 18, 18) #define HDMI_RX_PDEC_AIF_PB0 (HDMI_RX_BASE + 0x03c8) +#define HDMI_RX_PDEC_GMD_HB0 (HDMI_RX_BASE + 0x03d0) +#define HDMI_RX_PDEC_GMD_PB0 (HDMI_RX_BASE + 0x03d4) +#define HDMI_RX_PDEC_DRM_HB (HDMI_RX_BASE + 0x04c0) +#define HDMI_RX_PDEC_DRM_PAYLOAD0 (HDMI_RX_BASE + 0x04c4) +#define HDMI_RX_PDEC_DRM_PAYLOAD1 (HDMI_RX_BASE + 0x04c8) +#define HDMI_RX_PDEC_DRM_PAYLOAD2 (HDMI_RX_BASE + 0x04cc) +#define HDMI_RX_PDEC_DRM_PAYLOAD3 (HDMI_RX_BASE + 0x04d0) +#define HDMI_RX_PDEC_DRM_PAYLOAD4 (HDMI_RX_BASE + 0x04d4) +#define HDMI_RX_PDEC_DRM_PAYLOAD5 (HDMI_RX_BASE + 0x04d8) +#define HDMI_RX_PDEC_DRM_PAYLOAD6 (HDMI_RX_BASE + 0x04dc) #define HDMI_RX_HDMI20_CONTROL (HDMI_RX_BASE + 0x0800) #define PVO1UNMUTE(x) UPDATE(x, 29, 29) @@ -545,6 +557,8 @@ int rk628_hdmirx_get_timings(struct rk628 *rk628, u8 rk628_hdmirx_get_range(struct rk628 *rk628); u8 rk628_hdmirx_get_color_space(struct rk628 *rk628); int rk628_hdmirx_get_hdcp_enc_status(struct rk628 *rk628); +int rk628_hdmirx_get_hdr_matedata(struct rk628 *rk628, + struct hdr_metadata_infoframe *hdmi_metadata); void rk628_hdmirx_controller_reset(struct rk628 *rk628); bool rk628_hdmirx_scdc_ced_err(struct rk628 *rk628); bool rk628_hdmirx_is_locked(struct rk628 *rk628);