diff options
Diffstat (limited to 'drivers/gpu/drm/vc4')
-rw-r--r-- | drivers/gpu/drm/vc4/tests/vc4_mock.h | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/vc4/tests/vc4_mock_output.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/vc4/vc4_dpi.c | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/vc4/vc4_drv.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/vc4/vc4_drv.h | 65 | ||||
-rw-r--r-- | drivers/gpu/drm/vc4/vc4_dsi.c | 17 | ||||
-rw-r--r-- | drivers/gpu/drm/vc4/vc4_hdmi.c | 336 | ||||
-rw-r--r-- | drivers/gpu/drm/vc4/vc4_hdmi.h | 25 | ||||
-rw-r--r-- | drivers/gpu/drm/vc4/vc4_kms.c | 16 | ||||
-rw-r--r-- | drivers/gpu/drm/vc4/vc4_plane.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/vc4/vc4_txp.c | 12 | ||||
-rw-r--r-- | drivers/gpu/drm/vc4/vc4_vec.c | 14 |
12 files changed, 342 insertions, 162 deletions
diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock.h b/drivers/gpu/drm/vc4/tests/vc4_mock.h index db8e9a141ef8..2d0b339bd9f3 100644 --- a/drivers/gpu/drm/vc4/tests/vc4_mock.h +++ b/drivers/gpu/drm/vc4/tests/vc4_mock.h @@ -43,6 +43,9 @@ struct vc4_dummy_output { struct drm_connector connector; }; +#define encoder_to_vc4_dummy_output(_enc) \ + container_of_const(_enc, struct vc4_dummy_output, encoder.base) + struct vc4_dummy_output *vc4_dummy_output(struct kunit *test, struct drm_device *drm, struct drm_crtc *crtc, diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock_output.c b/drivers/gpu/drm/vc4/tests/vc4_mock_output.c index 8d33be828d9a..6e11fcc9ef45 100644 --- a/drivers/gpu/drm/vc4/tests/vc4_mock_output.c +++ b/drivers/gpu/drm/vc4/tests/vc4_mock_output.c @@ -80,7 +80,7 @@ int vc4_mock_atomic_add_output(struct kunit *test, crtc = vc4_find_crtc_for_encoder(test, drm, encoder); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc); - output = container_of(encoder, struct vc4_dummy_output, encoder.base); + output = encoder_to_vc4_dummy_output(encoder); conn = &output->connector; conn_state = drm_atomic_get_connector_state(state, conn); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state); @@ -126,7 +126,7 @@ int vc4_mock_atomic_del_output(struct kunit *test, ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL); KUNIT_ASSERT_EQ(test, ret, 0); - output = container_of(encoder, struct vc4_dummy_output, encoder.base); + output = encoder_to_vc4_dummy_output(encoder); conn = &output->connector; conn_state = drm_atomic_get_connector_state(state, conn); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state); diff --git a/drivers/gpu/drm/vc4/vc4_dpi.c b/drivers/gpu/drm/vc4/vc4_dpi.c index f518d6e59ed6..e68c07d86040 100644 --- a/drivers/gpu/drm/vc4/vc4_dpi.c +++ b/drivers/gpu/drm/vc4/vc4_dpi.c @@ -97,11 +97,8 @@ struct vc4_dpi { struct debugfs_regset32 regset; }; -static inline struct vc4_dpi * -to_vc4_dpi(struct drm_encoder *encoder) -{ - return container_of(encoder, struct vc4_dpi, encoder.base); -} +#define to_vc4_dpi(_encoder) \ + container_of_const(_encoder, struct vc4_dpi, encoder.base) #define DPI_READ(offset) \ ({ \ diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c index c8bf954042e0..823395c23cc3 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.c +++ b/drivers/gpu/drm/vc4/vc4_drv.c @@ -350,7 +350,7 @@ static int vc4_drm_bind(struct device *dev) return -EPROBE_DEFER; } - ret = drm_aperture_remove_framebuffers(false, driver); + ret = drm_aperture_remove_framebuffers(driver); if (ret) return ret; diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index 8768566c610b..bf66499765fb 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -232,11 +232,8 @@ struct vc4_dev { struct kref bin_bo_kref; }; -static inline struct vc4_dev * -to_vc4_dev(const struct drm_device *dev) -{ - return container_of(dev, struct vc4_dev, base); -} +#define to_vc4_dev(_dev) \ + container_of_const(_dev, struct vc4_dev, base) struct vc4_bo { struct drm_gem_dma_object base; @@ -285,11 +282,8 @@ struct vc4_bo { struct mutex madv_lock; }; -static inline struct vc4_bo * -to_vc4_bo(const struct drm_gem_object *bo) -{ - return container_of(to_drm_gem_dma_obj(bo), struct vc4_bo, base); -} +#define to_vc4_bo(_bo) \ + container_of_const(to_drm_gem_dma_obj(_bo), struct vc4_bo, base) struct vc4_fence { struct dma_fence base; @@ -298,11 +292,8 @@ struct vc4_fence { uint64_t seqno; }; -static inline struct vc4_fence * -to_vc4_fence(const struct dma_fence *fence) -{ - return container_of(fence, struct vc4_fence, base); -} +#define to_vc4_fence(_fence) \ + container_of_const(_fence, struct vc4_fence, base) struct vc4_seqno_cb { struct work_struct work; @@ -368,11 +359,8 @@ struct vc4_hvs_state { } fifo_state[HVS_NUM_CHANNELS]; }; -static inline struct vc4_hvs_state * -to_vc4_hvs_state(const struct drm_private_state *priv) -{ - return container_of(priv, struct vc4_hvs_state, base); -} +#define to_vc4_hvs_state(_state) \ + container_of_const(_state, struct vc4_hvs_state, base) struct vc4_hvs_state *vc4_hvs_get_global_state(struct drm_atomic_state *state); struct vc4_hvs_state *vc4_hvs_get_old_global_state(const struct drm_atomic_state *state); @@ -382,11 +370,8 @@ struct vc4_plane { struct drm_plane base; }; -static inline struct vc4_plane * -to_vc4_plane(const struct drm_plane *plane) -{ - return container_of(plane, struct vc4_plane, base); -} +#define to_vc4_plane(_plane) \ + container_of_const(_plane, struct vc4_plane, base) enum vc4_scaling_mode { VC4_SCALING_NONE, @@ -458,11 +443,8 @@ struct vc4_plane_state { u64 membus_load; }; -static inline struct vc4_plane_state * -to_vc4_plane_state(const struct drm_plane_state *state) -{ - return container_of(state, struct vc4_plane_state, base); -} +#define to_vc4_plane_state(_state) \ + container_of_const(_state, struct vc4_plane_state, base) enum vc4_encoder_type { VC4_ENCODER_TYPE_NONE, @@ -489,11 +471,8 @@ struct vc4_encoder { void (*post_crtc_powerdown)(struct drm_encoder *encoder, struct drm_atomic_state *state); }; -static inline struct vc4_encoder * -to_vc4_encoder(const struct drm_encoder *encoder) -{ - return container_of(encoder, struct vc4_encoder, base); -} +#define to_vc4_encoder(_encoder) \ + container_of_const(_encoder, struct vc4_encoder, base) static inline struct drm_encoder *vc4_find_encoder_by_type(struct drm_device *drm, @@ -591,11 +570,8 @@ struct vc4_crtc { unsigned int current_hvs_channel; }; -static inline struct vc4_crtc * -to_vc4_crtc(const struct drm_crtc *crtc) -{ - return container_of(crtc, struct vc4_crtc, base); -} +#define to_vc4_crtc(_crtc) \ + container_of_const(_crtc, struct vc4_crtc, base) static inline const struct vc4_crtc_data * vc4_crtc_to_vc4_crtc_data(const struct vc4_crtc *crtc) @@ -608,7 +584,7 @@ vc4_crtc_to_vc4_pv_data(const struct vc4_crtc *crtc) { const struct vc4_crtc_data *data = vc4_crtc_to_vc4_crtc_data(crtc); - return container_of(data, struct vc4_pv_data, base); + return container_of_const(data, struct vc4_pv_data, base); } struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc, @@ -636,11 +612,8 @@ struct vc4_crtc_state { #define VC4_HVS_CHANNEL_DISABLED ((unsigned int)-1) -static inline struct vc4_crtc_state * -to_vc4_crtc_state(const struct drm_crtc_state *crtc_state) -{ - return container_of(crtc_state, struct vc4_crtc_state, base); -} +#define to_vc4_crtc_state(_state) \ + container_of_const(_state, struct vc4_crtc_state, base) #define V3D_READ(offset) \ ({ \ diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c index a5c075f802e4..9e0c355b236f 100644 --- a/drivers/gpu/drm/vc4/vc4_dsi.c +++ b/drivers/gpu/drm/vc4/vc4_dsi.c @@ -600,19 +600,14 @@ struct vc4_dsi { struct debugfs_regset32 regset; }; -#define host_to_dsi(host) container_of(host, struct vc4_dsi, dsi_host) +#define host_to_dsi(host) \ + container_of_const(host, struct vc4_dsi, dsi_host) -static inline struct vc4_dsi * -to_vc4_dsi(struct drm_encoder *encoder) -{ - return container_of(encoder, struct vc4_dsi, encoder.base); -} +#define to_vc4_dsi(_encoder) \ + container_of_const(_encoder, struct vc4_dsi, encoder.base) -static inline struct vc4_dsi * -bridge_to_vc4_dsi(struct drm_bridge *bridge) -{ - return container_of(bridge, struct vc4_dsi, bridge); -} +#define bridge_to_vc4_dsi(_bridge) \ + container_of_const(_bridge, struct vc4_dsi, bridge) static inline void dsi_dma_workaround_write(struct vc4_dsi *dsi, u32 offset, u32 val) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 482397d5cb48..5261526d286f 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -153,11 +153,17 @@ static bool vc4_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode, return clock > HDMI_14_MAX_TMDS_CLK; } -static bool vc4_hdmi_is_full_range_rgb(struct vc4_hdmi *vc4_hdmi, - const struct drm_display_mode *mode) +static bool vc4_hdmi_is_full_range(struct vc4_hdmi *vc4_hdmi, + struct vc4_hdmi_connector_state *vc4_state) { + const struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; struct drm_display_info *display = &vc4_hdmi->connector.display_info; + if (vc4_state->broadcast_rgb == VC4_HDMI_BROADCAST_RGB_LIMITED) + return false; + else if (vc4_state->broadcast_rgb == VC4_HDMI_BROADCAST_RGB_FULL) + return true; + return !display->is_hdmi || drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_FULL; } @@ -528,14 +534,45 @@ static int vc4_hdmi_connector_atomic_check(struct drm_connector *connector, { struct drm_connector_state *old_state = drm_atomic_get_old_connector_state(state, connector); + struct vc4_hdmi_connector_state *old_vc4_state = + conn_state_to_vc4_hdmi_conn_state(old_state); struct drm_connector_state *new_state = drm_atomic_get_new_connector_state(state, connector); + struct vc4_hdmi_connector_state *new_vc4_state = + conn_state_to_vc4_hdmi_conn_state(new_state); struct drm_crtc *crtc = new_state->crtc; if (!crtc) return 0; + if (old_state->tv.margins.left != new_state->tv.margins.left || + old_state->tv.margins.right != new_state->tv.margins.right || + old_state->tv.margins.top != new_state->tv.margins.top || + old_state->tv.margins.bottom != new_state->tv.margins.bottom) { + struct drm_crtc_state *crtc_state; + int ret; + + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + /* + * Strictly speaking, we should be calling + * drm_atomic_helper_check_planes() after our call to + * drm_atomic_add_affected_planes(). However, the + * connector atomic_check is called as part of + * drm_atomic_helper_check_modeset() that already + * happens before a call to + * drm_atomic_helper_check_planes() in + * drm_atomic_helper_check(). + */ + ret = drm_atomic_add_affected_planes(state, crtc); + if (ret) + return ret; + } + if (old_state->colorspace != new_state->colorspace || + old_vc4_state->broadcast_rgb != new_vc4_state->broadcast_rgb || !drm_connector_atomic_hdr_metadata_equal(old_state, new_state)) { struct drm_crtc_state *crtc_state; @@ -549,6 +586,49 @@ static int vc4_hdmi_connector_atomic_check(struct drm_connector *connector, return 0; } +static int vc4_hdmi_connector_get_property(struct drm_connector *connector, + const struct drm_connector_state *state, + struct drm_property *property, + uint64_t *val) +{ + struct drm_device *drm = connector->dev; + struct vc4_hdmi *vc4_hdmi = + connector_to_vc4_hdmi(connector); + const struct vc4_hdmi_connector_state *vc4_conn_state = + conn_state_to_vc4_hdmi_conn_state(state); + + if (property == vc4_hdmi->broadcast_rgb_property) { + *val = vc4_conn_state->broadcast_rgb; + } else { + drm_dbg(drm, "Unknown property [PROP:%d:%s]\n", + property->base.id, property->name); + return -EINVAL; + } + + return 0; +} + +static int vc4_hdmi_connector_set_property(struct drm_connector *connector, + struct drm_connector_state *state, + struct drm_property *property, + uint64_t val) +{ + struct drm_device *drm = connector->dev; + struct vc4_hdmi *vc4_hdmi = + connector_to_vc4_hdmi(connector); + struct vc4_hdmi_connector_state *vc4_conn_state = + conn_state_to_vc4_hdmi_conn_state(state); + + if (property == vc4_hdmi->broadcast_rgb_property) { + vc4_conn_state->broadcast_rgb = val; + return 0; + } + + drm_dbg(drm, "Unknown property [PROP:%d:%s]\n", + property->base.id, property->name); + return -EINVAL; +} + static void vc4_hdmi_connector_reset(struct drm_connector *connector) { struct vc4_hdmi_connector_state *old_state = @@ -568,6 +648,7 @@ static void vc4_hdmi_connector_reset(struct drm_connector *connector) new_state->base.max_bpc = 8; new_state->base.max_requested_bpc = 8; new_state->output_format = VC4_HDMI_OUTPUT_RGB; + new_state->broadcast_rgb = VC4_HDMI_BROADCAST_RGB_AUTO; drm_atomic_helper_connector_tv_margins_reset(connector); } @@ -585,6 +666,7 @@ vc4_hdmi_connector_duplicate_state(struct drm_connector *connector) new_state->tmds_char_rate = vc4_state->tmds_char_rate; new_state->output_bpc = vc4_state->output_bpc; new_state->output_format = vc4_state->output_format; + new_state->broadcast_rgb = vc4_state->broadcast_rgb; __drm_atomic_helper_connector_duplicate_state(connector, &new_state->base); return &new_state->base; @@ -595,6 +677,8 @@ static const struct drm_connector_funcs vc4_hdmi_connector_funcs = { .reset = vc4_hdmi_connector_reset, .atomic_duplicate_state = vc4_hdmi_connector_duplicate_state, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, + .atomic_get_property = vc4_hdmi_connector_get_property, + .atomic_set_property = vc4_hdmi_connector_set_property, }; static const struct drm_connector_helper_funcs vc4_hdmi_connector_helper_funcs = { @@ -603,6 +687,33 @@ static const struct drm_connector_helper_funcs vc4_hdmi_connector_helper_funcs = .atomic_check = vc4_hdmi_connector_atomic_check, }; +static const struct drm_prop_enum_list broadcast_rgb_names[] = { + { VC4_HDMI_BROADCAST_RGB_AUTO, "Automatic" }, + { VC4_HDMI_BROADCAST_RGB_FULL, "Full" }, + { VC4_HDMI_BROADCAST_RGB_LIMITED, "Limited 16:235" }, +}; + +static void +vc4_hdmi_attach_broadcast_rgb_property(struct drm_device *dev, + struct vc4_hdmi *vc4_hdmi) +{ + struct drm_property *prop = vc4_hdmi->broadcast_rgb_property; + + if (!prop) { + prop = drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, + "Broadcast RGB", + broadcast_rgb_names, + ARRAY_SIZE(broadcast_rgb_names)); + if (!prop) + return; + + vc4_hdmi->broadcast_rgb_property = prop; + } + + drm_object_attach_property(&vc4_hdmi->connector.base, prop, + VC4_HDMI_BROADCAST_RGB_AUTO); +} + static int vc4_hdmi_connector_init(struct drm_device *dev, struct vc4_hdmi *vc4_hdmi) { @@ -649,6 +760,8 @@ static int vc4_hdmi_connector_init(struct drm_device *dev, if (vc4_hdmi->variant->supports_hdr) drm_connector_attach_hdr_output_metadata_property(connector); + vc4_hdmi_attach_broadcast_rgb_property(dev, vc4_hdmi); + drm_connector_attach_encoder(connector, encoder); return 0; @@ -803,7 +916,7 @@ static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder) drm_hdmi_avi_infoframe_quant_range(&frame.avi, connector, mode, - vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode) ? + vc4_hdmi_is_full_range(vc4_hdmi, vc4_state) ? HDMI_QUANTIZATION_RANGE_FULL : HDMI_QUANTIZATION_RANGE_LIMITED); drm_hdmi_avi_infoframe_colorimetry(&frame.avi, cstate); @@ -1046,6 +1159,8 @@ static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, struct drm_connector_state *state, const struct drm_display_mode *mode) { + struct vc4_hdmi_connector_state *vc4_state = + conn_state_to_vc4_hdmi_conn_state(state); struct drm_device *drm = vc4_hdmi->connector.dev; unsigned long flags; u32 csc_ctl; @@ -1059,7 +1174,7 @@ static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, csc_ctl = VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR, VC4_HD_CSC_CTL_ORDER); - if (!vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode)) { + if (!vc4_hdmi_is_full_range(vc4_hdmi, vc4_state)) { /* CEA VICs other than #1 requre limited range RGB * output unless overridden by an AVI infoframe. * Apply a colorspace conversion to squash 0-255 down @@ -1092,68 +1207,134 @@ static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, } /* - * If we need to output Full Range RGB, then use the unity matrix - * - * [ 1 0 0 0] - * [ 0 1 0 0] - * [ 0 0 1 0] + * Matrices for (internal) RGB to RGB output. * - * Matrix is signed 2p13 fixed point, with signed 9p6 offsets + * Matrices are signed 2p13 fixed point, with signed 9p6 offsets */ -static const u16 vc5_hdmi_csc_full_rgb_unity[3][4] = { - { 0x2000, 0x0000, 0x0000, 0x0000 }, - { 0x0000, 0x2000, 0x0000, 0x0000 }, - { 0x0000, 0x0000, 0x2000, 0x0000 }, +static const u16 vc5_hdmi_csc_full_rgb_to_rgb[2][3][4] = { + { + /* + * Full range - unity + * + * [ 1 0 0 0] + * [ 0 1 0 0] + * [ 0 0 1 0] + */ + { 0x2000, 0x0000, 0x0000, 0x0000 }, + { 0x0000, 0x2000, 0x0000, 0x0000 }, + { 0x0000, 0x0000, 0x2000, 0x0000 }, + }, + { + /* + * Limited range + * + * CEA VICs other than #1 require limited range RGB + * output unless overridden by an AVI infoframe. Apply a + * colorspace conversion to squash 0-255 down to 16-235. + * The matrix here is: + * + * [ 0.8594 0 0 16] + * [ 0 0.8594 0 16] + * [ 0 0 0.8594 16] + */ + { 0x1b80, 0x0000, 0x0000, 0x0400 }, + { 0x0000, 0x1b80, 0x0000, 0x0400 }, + { 0x0000, 0x0000, 0x1b80, 0x0400 }, + }, }; /* - * CEA VICs other than #1 require limited range RGB output unless - * overridden by an AVI infoframe. Apply a colorspace conversion to - * squash 0-255 down to 16-235. The matrix here is: - * - * [ 0.8594 0 0 16] - * [ 0 0.8594 0 16] - * [ 0 0 0.8594 16] + * Conversion between Full Range RGB and YUV using the BT.601 Colorspace * - * Matrix is signed 2p13 fixed point, with signed 9p6 offsets + * Matrices are signed 2p13 fixed point, with signed 9p6 offsets */ -static const u16 vc5_hdmi_csc_full_rgb_to_limited_rgb[3][4] = { - { 0x1b80, 0x0000, 0x0000, 0x0400 }, - { 0x0000, 0x1b80, 0x0000, 0x0400 }, - { 0x0000, 0x0000, 0x1b80, 0x0400 }, +static const u16 vc5_hdmi_csc_full_rgb_to_yuv_bt601[2][3][4] = { + { + /* + * Full Range + * + * [ 0.299000 0.587000 0.114000 0 ] + * [ -0.168736 -0.331264 0.500000 128 ] + * [ 0.500000 -0.418688 -0.081312 128 ] + */ + { 0x0991, 0x12c9, 0x03a6, 0x0000 }, + { 0xfa9b, 0xf567, 0x1000, 0x2000 }, + { 0x1000, 0xf29b, 0xfd67, 0x2000 }, + }, + { + /* Limited Range + * + * [ 0.255785 0.502160 0.097523 16 ] + * [ -0.147644 -0.289856 0.437500 128 ] + * [ 0.437500 -0.366352 -0.071148 128 ] + */ + { 0x082f, 0x1012, 0x031f, 0x0400 }, + { 0xfb48, 0xf6ba, 0x0e00, 0x2000 }, + { 0x0e00, 0xf448, 0xfdba, 0x2000 }, + }, }; /* - * Conversion between Full Range RGB and Full Range YUV422 using the - * BT.709 Colorspace + * Conversion between Full Range RGB and YUV using the BT.709 Colorspace * - * - * [ 0.181906 0.611804 0.061758 16 ] - * [ -0.100268 -0.337232 0.437500 128 ] - * [ 0.437500 -0.397386 -0.040114 128 ] - * - * Matrix is signed 2p13 fixed point, with signed 9p6 offsets + * Matrices are signed 2p13 fixed point, with signed 9p6 offsets */ -static const u16 vc5_hdmi_csc_full_rgb_to_limited_yuv422_bt709[3][4] = { - { 0x05d2, 0x1394, 0x01fa, 0x0400 }, - { 0xfccc, 0xf536, 0x0e00, 0x2000 }, - { 0x0e00, 0xf34a, 0xfeb8, 0x2000 }, +static const u16 vc5_hdmi_csc_full_rgb_to_yuv_bt709[2][3][4] = { + { + /* + * Full Range + * + * [ 0.212600 0.715200 0.072200 0 ] + * [ -0.114572 -0.385428 0.500000 128 ] + * [ 0.500000 -0.454153 -0.045847 128 ] + */ + { 0x06ce, 0x16e3, 0x024f, 0x0000 }, + { 0xfc56, 0xf3ac, 0x1000, 0x2000 }, + { 0x1000, 0xf179, 0xfe89, 0x2000 }, + }, + { + /* + * Limited Range + * + * [ 0.181906 0.611804 0.061758 16 ] + * [ -0.100268 -0.337232 0.437500 128 ] + * [ 0.437500 -0.397386 -0.040114 128 ] + */ + { 0x05d2, 0x1394, 0x01fa, 0x0400 }, + { 0xfccc, 0xf536, 0x0e00, 0x2000 }, + { 0x0e00, 0xf34a, 0xfeb8, 0x2000 }, + }, }; /* - * Conversion between Full Range RGB and Full Range YUV444 using the - * BT.709 Colorspace + * Conversion between Full Range RGB and YUV using the BT.2020 Colorspace * - * [ -0.100268 -0.337232 0.437500 128 ] - * [ 0.437500 -0.397386 -0.040114 128 ] - * [ 0.181906 0.611804 0.061758 16 ] - * - * Matrix is signed 2p13 fixed point, with signed 9p6 offsets + * Matrices are signed 2p13 fixed point, with signed 9p6 offsets */ -static const u16 vc5_hdmi_csc_full_rgb_to_limited_yuv444_bt709[3][4] = { - { 0xfccc, 0xf536, 0x0e00, 0x2000 }, - { 0x0e00, 0xf34a, 0xfeb8, 0x2000 }, - { 0x05d2, 0x1394, 0x01fa, 0x0400 }, +static const u16 vc5_hdmi_csc_full_rgb_to_yuv_bt2020[2][3][4] = { + { + /* + * Full Range + * + * [ 0.262700 0.678000 0.059300 0 ] + * [ -0.139630 -0.360370 0.500000 128 ] + * [ 0.500000 -0.459786 -0.040214 128 ] + */ + { 0x0868, 0x15b2, 0x01e6, 0x0000 }, + { 0xfb89, 0xf479, 0x1000, 0x2000 }, + { 0x1000, 0xf14a, 0xfeb8, 0x2000 }, + }, + { + /* Limited Range + * + * [ 0.224732 0.580008 0.050729 16 ] + * [ -0.122176 -0.315324 0.437500 128 ] + * [ 0.437500 -0.402312 -0.035188 128 ] + */ + { 0x082f, 0x1012, 0x031f, 0x0400 }, + { 0xfb48, 0xf6ba, 0x0e00, 0x2000 }, + { 0x0e00, 0xf448, 0xfdba, 0x2000 }, + }, }; static void vc5_hdmi_set_csc_coeffs(struct vc4_hdmi *vc4_hdmi, @@ -1169,6 +1350,48 @@ static void vc5_hdmi_set_csc_coeffs(struct vc4_hdmi *vc4_hdmi, HDMI_WRITE(HDMI_CSC_34_33, (coeffs[2][3] << 16) | coeffs[2][2]); } +static void vc5_hdmi_set_csc_coeffs_swap(struct vc4_hdmi *vc4_hdmi, + const u16 coeffs[3][4]) +{ + lockdep_assert_held(&vc4_hdmi->hw_lock); + + /* YUV444 needs the CSC matrices using the channels in a different order */ + HDMI_WRITE(HDMI_CSC_12_11, (coeffs[1][1] << 16) | coeffs[1][0]); + HDMI_WRITE(HDMI_CSC_14_13, (coeffs[1][3] << 16) | coeffs[1][2]); + HDMI_WRITE(HDMI_CSC_22_21, (coeffs[2][1] << 16) | coeffs[2][0]); + HDMI_WRITE(HDMI_CSC_24_23, (coeffs[2][3] << 16) | coeffs[2][2]); + HDMI_WRITE(HDMI_CSC_32_31, (coeffs[0][1] << 16) | coeffs[0][0]); + HDMI_WRITE(HDMI_CSC_34_33, (coeffs[0][3] << 16) | coeffs[0][2]); +} + +static const u16 +(*vc5_hdmi_find_yuv_csc_coeffs(struct vc4_hdmi *vc4_hdmi, u32 colorspace, bool limited))[4] +{ + switch (colorspace) { + case DRM_MODE_COLORIMETRY_SMPTE_170M_YCC: + case DRM_MODE_COLORIMETRY_XVYCC_601: + case DRM_MODE_COLORIMETRY_SYCC_601: + case DRM_MODE_COLORIMETRY_OPYCC_601: + case DRM_MODE_COLORIMETRY_BT601_YCC: + return vc5_hdmi_csc_full_rgb_to_yuv_bt601[limited]; + + default: + case DRM_MODE_COLORIMETRY_NO_DATA: + case DRM_MODE_COLORIMETRY_BT709_YCC: + case DRM_MODE_COLORIMETRY_XVYCC_709: + case DRM_MODE_COLORIMETRY_RGB_WIDE_FIXED: + case DRM_MODE_COLORIMETRY_RGB_WIDE_FLOAT: + return vc5_hdmi_csc_full_rgb_to_yuv_bt709[limited]; + + case DRM_MODE_COLORIMETRY_BT2020_CYCC: + case DRM_MODE_COLORIMETRY_BT2020_YCC: + case DRM_MODE_COLORIMETRY_BT2020_RGB: + case DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65: + case DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER: + return vc5_hdmi_csc_full_rgb_to_yuv_bt2020[limited]; + } +} + static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, struct drm_connector_state *state, const struct drm_display_mode *mode) @@ -1176,7 +1399,9 @@ static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, struct drm_device *drm = vc4_hdmi->connector.dev; struct vc4_hdmi_connector_state *vc4_state = conn_state_to_vc4_hdmi_conn_state(state); + unsigned int lim_range = vc4_hdmi_is_full_range(vc4_hdmi, vc4_state) ? 0 : 1; unsigned long flags; + const u16 (*csc)[4]; u32 if_cfg = 0; u32 if_xbar = 0x543210; u32 csc_chan_ctl = 0; @@ -1191,10 +1416,14 @@ static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, switch (vc4_state->output_format) { case VC4_HDMI_OUTPUT_YUV444: - vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_limited_yuv444_bt709); + csc = vc5_hdmi_find_yuv_csc_coeffs(vc4_hdmi, state->colorspace, !!lim_range); + + vc5_hdmi_set_csc_coeffs_swap(vc4_hdmi, csc); break; case VC4_HDMI_OUTPUT_YUV422: + csc = vc5_hdmi_find_yuv_csc_coeffs(vc4_hdmi, state->colorspace, !!lim_range); + csc_ctl |= VC4_SET_FIELD(VC5_MT_CP_CSC_CTL_FILTER_MODE_444_TO_422_STANDARD, VC5_MT_CP_CSC_CTL_FILTER_MODE_444_TO_422) | VC5_MT_CP_CSC_CTL_USE_444_TO_422 | @@ -1206,16 +1435,13 @@ static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, if_cfg |= VC4_SET_FIELD(VC5_DVP_HT_VEC_INTERFACE_CFG_SEL_422_FORMAT_422_LEGACY, VC5_DVP_HT_VEC_INTERFACE_CFG_SEL_422); - vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_limited_yuv422_bt709); + vc5_hdmi_set_csc_coeffs(vc4_hdmi, csc); break; case VC4_HDMI_OUTPUT_RGB: if_xbar = 0x354021; - if (!vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode)) - vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_limited_rgb); - else - vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_unity); + vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_rgb[lim_range]); break; default: diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h index e3619836ca17..934d5d61485a 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h @@ -117,6 +117,12 @@ enum vc4_hdmi_output_format { VC4_HDMI_OUTPUT_YUV420, }; +enum vc4_hdmi_broadcast_rgb { + VC4_HDMI_BROADCAST_RGB_AUTO, + VC4_HDMI_BROADCAST_RGB_FULL, + VC4_HDMI_BROADCAST_RGB_LIMITED, +}; + /* General HDMI hardware state. */ struct vc4_hdmi { struct vc4_hdmi_audio audio; @@ -129,6 +135,8 @@ struct vc4_hdmi { struct delayed_work scrambling_work; + struct drm_property *broadcast_rgb_property; + struct i2c_adapter *ddc; void __iomem *hdmicore_regs; void __iomem *hd_regs; @@ -222,17 +230,14 @@ struct vc4_hdmi { enum vc4_hdmi_output_format output_format; }; -static inline struct vc4_hdmi * -connector_to_vc4_hdmi(struct drm_connector *connector) -{ - return container_of(connector, struct vc4_hdmi, connector); -} +#define connector_to_vc4_hdmi(_connector) \ + container_of_const(_connector, struct vc4_hdmi, connector) static inline struct vc4_hdmi * encoder_to_vc4_hdmi(struct drm_encoder *encoder) { struct vc4_encoder *_encoder = to_vc4_encoder(encoder); - return container_of(_encoder, struct vc4_hdmi, encoder); + return container_of_const(_encoder, struct vc4_hdmi, encoder); } struct vc4_hdmi_connector_state { @@ -240,13 +245,11 @@ struct vc4_hdmi_connector_state { unsigned long long tmds_char_rate; unsigned int output_bpc; enum vc4_hdmi_output_format output_format; + enum vc4_hdmi_broadcast_rgb broadcast_rgb; }; -static inline struct vc4_hdmi_connector_state * -conn_state_to_vc4_hdmi_conn_state(struct drm_connector_state *conn_state) -{ - return container_of(conn_state, struct vc4_hdmi_connector_state, base); -} +#define conn_state_to_vc4_hdmi_conn_state(_state) \ + container_of_const(_state, struct vc4_hdmi_connector_state, base) void vc4_hdmi_phy_init(struct vc4_hdmi *vc4_hdmi, struct vc4_hdmi_connector_state *vc4_conn_state); diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c index a7e3d47c50f4..5495f2a94fa9 100644 --- a/drivers/gpu/drm/vc4/vc4_kms.c +++ b/drivers/gpu/drm/vc4/vc4_kms.c @@ -31,11 +31,8 @@ struct vc4_ctm_state { int fifo; }; -static struct vc4_ctm_state * -to_vc4_ctm_state(const struct drm_private_state *priv) -{ - return container_of(priv, struct vc4_ctm_state, base); -} +#define to_vc4_ctm_state(_state) \ + container_of_const(_state, struct vc4_ctm_state, base) struct vc4_load_tracker_state { struct drm_private_state base; @@ -43,11 +40,8 @@ struct vc4_load_tracker_state { u64 membus_load; }; -static struct vc4_load_tracker_state * -to_vc4_load_tracker_state(const struct drm_private_state *priv) -{ - return container_of(priv, struct vc4_load_tracker_state, base); -} +#define to_vc4_load_tracker_state(_state) \ + container_of_const(_state, struct vc4_load_tracker_state, base) static struct vc4_ctm_state *vc4_get_ctm_state(struct drm_atomic_state *state, struct drm_private_obj *manager) @@ -717,7 +711,7 @@ static void vc4_hvs_channels_destroy_state(struct drm_private_obj *obj, static void vc4_hvs_channels_print_state(struct drm_printer *p, const struct drm_private_state *state) { - struct vc4_hvs_state *hvs_state = to_vc4_hvs_state(state); + const struct vc4_hvs_state *hvs_state = to_vc4_hvs_state(state); unsigned int i; drm_printf(p, "HVS State\n"); diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 97c84a3f5a46..00e713faecd5 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -1334,8 +1334,7 @@ out: u32 vc4_plane_dlist_size(const struct drm_plane_state *state) { - const struct vc4_plane_state *vc4_state = - container_of(state, typeof(*vc4_state), base); + const struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); return vc4_state->dlist_count; } diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c index ef5cab2a3aa9..c5abdec03103 100644 --- a/drivers/gpu/drm/vc4/vc4_txp.c +++ b/drivers/gpu/drm/vc4/vc4_txp.c @@ -168,15 +168,11 @@ struct vc4_txp { void __iomem *regs; }; -static inline struct vc4_txp *encoder_to_vc4_txp(struct drm_encoder *encoder) -{ - return container_of(encoder, struct vc4_txp, encoder.base); -} +#define encoder_to_vc4_txp(_encoder) \ + container_of_const(_encoder, struct vc4_txp, encoder.base) -static inline struct vc4_txp *connector_to_vc4_txp(struct drm_connector *conn) -{ - return container_of(conn, struct vc4_txp, connector.base); -} +#define connector_to_vc4_txp(_connector) \ + container_of_const(_connector, struct vc4_txp, connector.base) static const struct debugfs_reg32 txp_regs[] = { VC4_REG32(TXP_DST_PTR), diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c index a3782d05cd66..d6e6a1a22eba 100644 --- a/drivers/gpu/drm/vc4/vc4_vec.c +++ b/drivers/gpu/drm/vc4/vc4_vec.c @@ -219,17 +219,11 @@ struct vc4_vec { writel(val, vec->regs + (offset)); \ } while (0) -static inline struct vc4_vec * -encoder_to_vc4_vec(struct drm_encoder *encoder) -{ - return container_of(encoder, struct vc4_vec, encoder.base); -} +#define encoder_to_vc4_vec(_encoder) \ + container_of_const(_encoder, struct vc4_vec, encoder.base) -static inline struct vc4_vec * -connector_to_vc4_vec(struct drm_connector *connector) -{ - return container_of(connector, struct vc4_vec, connector); -} +#define connector_to_vc4_vec(_connector) \ + container_of_const(_connector, struct vc4_vec, connector) enum vc4_vec_tv_mode_id { VC4_VEC_TV_MODE_NTSC, |