summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Frattaroli <nicolas.frattaroli@collabora.com>2026-06-09 14:43:54 +0200
committerDaniel Stone <daniels@collabora.com>2026-06-09 21:03:50 +0100
commit3f0f770ccc8d724fa3b1f5b4bde5addfc4b843b8 (patch)
tree053e161237fa9af0dbe4ac937a81bd7954477c4e
parentf5873533bf99ee98237141f33ba15e04170498f4 (diff)
downloadlinux-3f0f770ccc8d724fa3b1f5b4bde5addfc4b843b8.tar.gz
linux-3f0f770ccc8d724fa3b1f5b4bde5addfc4b843b8.zip
drm/atomic-helper: Add HDMI bridge output bus formats helper
The drm_bridge_funcs atomic_get_output_bus_fmts operation should be the same for likely every HDMI connector bridge, unless such an HDMI connector bridge has some special hardware restrictions that I cannot envision yet. To avoid code duplication and standardize on a set of media bus formats that the HDMI output color formats translate to, add a common helper function that implements this operation to the drm bridge helpers. The function returns a list of output bus formats based on the HDMI bridge's current output bits-per-component, and its bitmask of supported color formats. To guard against future expansion of DRM_OUTPUT_COLOR_FORMAT outgrowing the hweight8 call, add a BUILD_BUG_ON statement where it's used that checks for DRM_OUTPUT_COLOR_FORMAT_COUNT. The justification for not using hweight32 in all cases is that not all ISAs have a popcount instruction, and will benefit from a smaller/faster software implementation that doesn't have to operate across all bits. The justification for not defining an hweight_color depending on the value of DRM_OUTPUT_COLOR_FORMAT_COUNT is that this count enum value is only known at compile time, not at preprocessor time. Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com> Reviewed-by: Daniel Stone <daniel@fooishbar.org> Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com> Link: https://patch.msgid.link/20260609-color-format-v17-7-35739b5782cc@collabora.com Signed-off-by: Daniel Stone <daniels@collabora.com>
-rw-r--r--drivers/gpu/drm/drm_atomic_helper.c81
-rw-r--r--include/drm/drm_atomic_helper.h7
2 files changed, 88 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 3547f797a850..285aac3554df 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -28,6 +28,7 @@
#include <linux/export.h>
#include <linux/dma-fence.h>
#include <linux/ktime.h>
+#include <linux/media-bus-format.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
@@ -4107,3 +4108,83 @@ drm_atomic_helper_bridge_propagate_bus_fmt(struct drm_bridge *bridge,
return input_fmts;
}
EXPORT_SYMBOL(drm_atomic_helper_bridge_propagate_bus_fmt);
+
+/**
+ * drm_atomic_helper_bridge_get_hdmi_output_bus_fmts - helper implementing
+ * atomic_get_output_bus_fmts for HDMI
+ * @bridge: pointer to &struct drm_bridge
+ * @bridge_state: pointer to the current bridge state
+ * @crtc_state: pointer to the current CRTC state
+ * @conn_state: pointer to the current connector state
+ * @num_output_fmts: pointer to where the number of entries in the returned array
+ * will be stored. Set to 0 if unsuccessful.
+ *
+ * Common implementation for the &drm_bridge_funcs.atomic_get_output_bus_fmts
+ * operation that's applicable to HDMI connectors.
+ *
+ * Returns: a newly allocated array of u32 values of length \*@num_output_fmts,
+ * representing all the MEDIA_BUS_FMTS\_ for the current connector state's
+ * chosen HDMI output bits per compoennt, or %NULL if it fails to allocate one.
+ */
+u32 *
+drm_atomic_helper_bridge_get_hdmi_output_bus_fmts(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state,
+ unsigned int *num_output_fmts)
+{
+ unsigned int num_fmts = 0;
+ u32 *out_fmts;
+
+ /*
+ * bridge->supported_formats is a bit field of BIT(enum drm_output_color_format)
+ * values. The smallest hweight that is smaller than or equal to
+ * %DRM_OUTPUT_COLOR_FORMAT_COUNT will do for counting set bits here.
+ */
+ BUILD_BUG_ON(const_true(DRM_OUTPUT_COLOR_FORMAT_COUNT > 8));
+ out_fmts = kmalloc_array(hweight8(bridge->supported_formats),
+ sizeof(u32), GFP_KERNEL);
+ if (!out_fmts) {
+ *num_output_fmts = 0;
+ return NULL;
+ }
+
+ switch (conn_state->hdmi.output_bpc) {
+ case 12:
+ if (bridge->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444))
+ out_fmts[num_fmts++] = MEDIA_BUS_FMT_RGB121212_1X36;
+ if (bridge->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444))
+ out_fmts[num_fmts++] = MEDIA_BUS_FMT_YUV12_1X36;
+ if (bridge->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422))
+ out_fmts[num_fmts++] = MEDIA_BUS_FMT_UYVY12_1X24;
+ if (bridge->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420))
+ out_fmts[num_fmts++] = MEDIA_BUS_FMT_UYYVYY12_0_5X36;
+ break;
+ case 10:
+ if (bridge->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444))
+ out_fmts[num_fmts++] = MEDIA_BUS_FMT_RGB101010_1X30;
+ if (bridge->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444))
+ out_fmts[num_fmts++] = MEDIA_BUS_FMT_YUV10_1X30;
+ if (bridge->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422))
+ out_fmts[num_fmts++] = MEDIA_BUS_FMT_UYVY10_1X20;
+ if (bridge->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420))
+ out_fmts[num_fmts++] = MEDIA_BUS_FMT_UYYVYY10_0_5X30;
+ break;
+ default:
+ if (bridge->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444))
+ out_fmts[num_fmts++] = MEDIA_BUS_FMT_RGB888_1X24;
+ if (bridge->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444))
+ out_fmts[num_fmts++] = MEDIA_BUS_FMT_YUV8_1X24;
+ if (bridge->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422))
+ out_fmts[num_fmts++] = MEDIA_BUS_FMT_UYVY8_1X16;
+ if (bridge->supported_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420))
+ out_fmts[num_fmts++] = MEDIA_BUS_FMT_UYYVYY8_0_5X24;
+ break;
+ }
+
+ *num_output_fmts = num_fmts;
+
+ return out_fmts;
+}
+EXPORT_SYMBOL(drm_atomic_helper_bridge_get_hdmi_output_bus_fmts);
+
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index b84152810abb..4cfeec70d648 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -295,4 +295,11 @@ drm_atomic_helper_bridge_propagate_bus_fmt(struct drm_bridge *bridge,
u32 output_fmt,
unsigned int *num_input_fmts);
+u32 *
+drm_atomic_helper_bridge_get_hdmi_output_bus_fmts(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state,
+ unsigned int *num_output_fmts);
+
#endif /* DRM_ATOMIC_HELPER_H_ */