mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-05 10:31:46 +09:00
media: i2c: rk628: add hdr support
Signed-off-by: Chen Shunqing <csq@rock-chips.com> Change-Id: I90ae0d96391185b5e79a5a7a8733a42964684dd0
This commit is contained in:
@@ -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),
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#ifndef __RK628_HDMIRX_H
|
||||
#define __RK628_HDMIRX_H
|
||||
|
||||
#include <drm/drm_mode.h>
|
||||
#include <linux/hdmi.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <media/cec.h>
|
||||
#include <media/cec-notifier.h>
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user