drm/rockchip: dw_hdmi: Add property MODE_COLOR_CAPACITY

This property is used to report the supported color format for each
resolution to userspace.

Change-Id: Ib2e8c712d7590b1cff77d03eb789bc49c18d6e74
Signed-off-by: Algea Cao <algea.cao@rock-chips.com>
This commit is contained in:
Algea Cao
2024-05-16 11:19:42 +08:00
committed by Tao Huang
parent c9ee08a32f
commit 03d21c720f
4 changed files with 172 additions and 2 deletions

View File

@@ -3308,8 +3308,25 @@ static void dw_hdmi_connector_force(struct drm_connector *connector)
mutex_unlock(&hdmi->mutex);
}
static int drm_hdmi_probe_single_connector_modes(struct drm_connector *connector,
uint32_t maxX, uint32_t maxY)
{
struct dw_hdmi_qp *hdmi =
container_of(connector, struct dw_hdmi_qp, connector);
struct drm_display_info *info = &connector->display_info;
void *data = hdmi->plat_data->phy_data;
int ret;
ret = drm_helper_probe_single_connector_modes(connector, maxX, maxY);
if (hdmi->plat_data->get_mode_color_caps)
hdmi->plat_data->get_mode_color_caps(connector, info, data);
return ret;
}
static const struct drm_connector_funcs dw_hdmi_connector_funcs = {
.fill_modes = drm_helper_probe_single_connector_modes,
.fill_modes = drm_hdmi_probe_single_connector_modes,
.detect = dw_hdmi_connector_detect,
.destroy = drm_connector_cleanup,
.force = dw_hdmi_connector_force,

View File

@@ -3622,8 +3622,25 @@ static void dw_hdmi_connector_force(struct drm_connector *connector)
mutex_unlock(&hdmi->mutex);
}
static int drm_hdmi_probe_single_connector_modes(struct drm_connector *connector,
uint32_t maxX, uint32_t maxY)
{
struct dw_hdmi *hdmi =
container_of(connector, struct dw_hdmi, connector);
struct drm_display_info *info = &connector->display_info;
void *data = hdmi->plat_data->phy_data;
int ret;
ret = drm_helper_probe_single_connector_modes(connector, maxX, maxY);
if (hdmi->plat_data->get_mode_color_caps)
hdmi->plat_data->get_mode_color_caps(connector, info, data);
return ret;
}
static const struct drm_connector_funcs dw_hdmi_connector_funcs = {
.fill_modes = drm_helper_probe_single_connector_modes,
.fill_modes = drm_hdmi_probe_single_connector_modes,
.detect = dw_hdmi_connector_detect,
.destroy = drm_connector_cleanup,
.force = dw_hdmi_connector_force,

View File

@@ -238,6 +238,22 @@ enum hdmi_frl_rate_per_lane {
FRL_3G_PER_LANE = 3,
};
enum mode_color_caps_mask {
RGB_8BIT = 0,
RGB_10BIT,
YUV444_8BIT,
YUV444_10BIT,
YUV422_8BIT,
YUV422_10BIT,
YUV420_8BIT,
YUV420_10BIT,
};
struct mode_color_caps {
struct drm_mode_modeinfo umode;
u8 color_caps;
};
struct rockchip_hdmi {
struct device *dev;
struct regmap *regmap;
@@ -295,9 +311,11 @@ struct rockchip_hdmi {
struct drm_property *allm_capacity;
struct drm_property *allm_enable;
struct drm_property *hdcp_state_property;
struct drm_property *mode_color_capacity;
struct drm_property_blob *hdr_panel_blob_ptr;
struct drm_property_blob *next_hdr_data_ptr;
struct drm_property_blob *mode_color_caps_ptr;
unsigned int colordepth;
unsigned int colorimetry;
@@ -324,6 +342,7 @@ struct rockchip_hdmi {
struct pinctrl *p;
struct pinctrl_state *idle_state;
struct pinctrl_state *default_state;
struct mode_color_caps *mode_color_caps;
bool timing_force_output;
struct drm_display_mode force_mode;
u32 force_bus_format;
@@ -3063,6 +3082,100 @@ static void dw_hdmi_rockchip_force_frl_rate(void *data, u8 rate)
phy_set_bus_width(hdmi->phy, hdmi->phy_bus_width);
}
static u8 mode_color_caps_init(struct drm_connector *connector, struct drm_display_mode *mode,
struct drm_display_info *info)
{
u8 color_caps_mask = RGB_8BIT;
if (info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_30)
color_caps_mask |= BIT(RGB_10BIT);
if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444) {
color_caps_mask |= BIT(YUV444_8BIT);
if (info->edid_hdmi_ycbcr444_dc_modes & DRM_EDID_HDMI_DC_30)
color_caps_mask |= BIT(YUV444_10BIT);
}
/* For hdmi, yuv422 8bit and 10bit are the same format */
if (info->color_formats & DRM_COLOR_FORMAT_YCBCR422) {
color_caps_mask |= BIT(YUV422_8BIT);
color_caps_mask |= BIT(YUV422_10BIT);
}
if (connector->ycbcr_420_allowed && drm_mode_is_420(info, mode)) {
color_caps_mask |= BIT(YUV420_8BIT);
if (info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30)
color_caps_mask |= BIT(YUV420_10BIT);
}
return color_caps_mask;
}
static void dw_hdmi_rockchip_get_mode_color_caps(struct drm_connector *connector,
struct drm_display_info *info,
void *data)
{
struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data;
struct drm_display_mode *mode;
u8 color_caps_mask;
u32 max_tmds_clock = info->max_tmds_clock;
u32 size = 0;
struct mode_color_caps *caps;
struct drm_property *property = hdmi->mode_color_capacity;
if (list_empty(&connector->modes))
return;
list_for_each_entry(mode, &connector->modes, head)
size++;
kfree(hdmi->mode_color_caps);
size = sizeof(struct mode_color_caps) * size;
hdmi->mode_color_caps = kmalloc(size, GFP_KERNEL);
if (!hdmi->mode_color_caps)
return;
caps = hdmi->mode_color_caps;
max_tmds_clock = min(max_tmds_clock, hdmi->max_tmdsclk);
list_for_each_entry(mode, &connector->modes, head) {
color_caps_mask = mode_color_caps_init(connector, mode, info);
drm_mode_convert_to_umode(&caps->umode, mode);
/* hdmi 2.1 frl mode */
if (mode->clock > 600000) {
if (mode->clock > 1188000)
color_caps_mask = BIT(YUV420_8BIT) | BIT(YUV420_10BIT);
caps->color_caps = color_caps_mask;
caps++;
continue;
}
/* RGB/YUV444 10BIT is out of range */
if ((mode->clock * 10 / 8) > max_tmds_clock && mode->clock <= max_tmds_clock) {
color_caps_mask &= ~(BIT(RGB_10BIT) | BIT(YUV444_10BIT));
/* only support YUV420 */
} else if (mode->clock > max_tmds_clock && (mode->clock / 2) <= max_tmds_clock) {
color_caps_mask &= ~(BIT(RGB_10BIT) | BIT(RGB_8BIT) | BIT(YUV444_10BIT) |
BIT(YUV444_8BIT) | BIT(YUV422_10BIT) |
BIT(YUV422_8BIT));
/* YUV420 10BIT is out of range */
if ((mode->clock / 2) * 10 / 8 > max_tmds_clock)
color_caps_mask &= ~BIT(YUV420_10BIT);
}
caps->color_caps = color_caps_mask;
caps++;
}
drm_property_replace_global_blob(connector->dev, &hdmi->mode_color_caps_ptr, size,
hdmi->mode_color_caps, &connector->base, property);
}
static const struct drm_prop_enum_list color_depth_enum_list[] = {
{ 0, "Automatic" }, /* Prefer highest color depth */
{ 8, "24bit" },
@@ -3259,6 +3372,13 @@ dw_hdmi_rockchip_attach_properties(struct drm_connector *connector,
}
hdmi->hdcp_state_property = prop;
drm_object_attach_property(&connector->base, prop, RK_IF_HDCP_ENCRYPTED_NONE);
prop = drm_property_create(connector->dev, DRM_MODE_PROP_BLOB | DRM_MODE_PROP_IMMUTABLE,
"MODE_COLOR_CAPACITY", 0);
if (prop) {
hdmi->mode_color_capacity = prop;
drm_object_attach_property(&connector->base, prop, 0);
}
}
static void
@@ -3331,6 +3451,13 @@ dw_hdmi_rockchip_destroy_properties(struct drm_connector *connector,
drm_property_destroy(connector->dev, hdmi->allm_enable);
hdmi->allm_enable = NULL;
}
if (hdmi->mode_color_capacity) {
kfree(hdmi->mode_color_caps);
hdmi->mode_color_caps = NULL;
drm_property_destroy(connector->dev, hdmi->mode_color_capacity);
hdmi->mode_color_capacity = NULL;
}
}
static int
@@ -3399,6 +3526,8 @@ dw_hdmi_rockchip_set_property(struct drm_connector *connector,
return 0;
} else if (property == hdmi->hdcp_state_property) {
return 0;
} else if (property == hdmi->mode_color_capacity) {
return 0;
}
DRM_ERROR("Unknown property [PROP:%d:%s]\n",
@@ -3482,6 +3611,9 @@ dw_hdmi_rockchip_get_property(struct drm_connector *connector,
else
*val = RK_IF_HDCP_ENCRYPTED_NONE;
return 0;
} else if (property == hdmi->mode_color_capacity) {
*val = hdmi->mode_color_caps_ptr ? hdmi->mode_color_caps_ptr->base.id : 0;
return 0;
}
DRM_ERROR("Unknown property [PROP:%d:%s]\n",
@@ -4205,6 +4337,8 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
dw_hdmi_rockchip_get_refclk_rate;
plat_data->force_frl_rate =
dw_hdmi_rockchip_force_frl_rate;
plat_data->get_mode_color_caps =
dw_hdmi_rockchip_get_mode_color_caps;
plat_data->property_ops = &dw_hdmi_rockchip_property_ops;
secondary = rockchip_hdmi_find_by_id(dev->driver, !hdmi->id);

View File

@@ -273,6 +273,8 @@ struct dw_hdmi_plat_data {
struct drm_display_mode *(*get_force_timing)(void *data);
u32 (*get_refclk_rate)(void *data);
void (*force_frl_rate)(void *data, u8 rate);
void (*get_mode_color_caps)(struct drm_connector *connector, struct drm_display_info *info,
void *data);
/* Vendor Property support */
const struct dw_hdmi_property_ops *property_ops;