@@ -344,6 +344,14 @@
#define COLOR_BAR_MODE_BARS 2
#define PLL_DBG 0x0a04
+enum tc_mode {
+ mode_dpi_to_edp = BIT(1) | BIT(2),
+ mode_dpi_to_dp = BIT(1),
+ mode_dsi_to_edp = BIT(0) | BIT(2),
+ mode_dsi_to_dp = BIT(0),
+ mode_dsi_to_dpi = BIT(0) | BIT(1),
+};
+
static bool tc_test_pattern;
module_param_named(test, tc_test_pattern, bool, 0644);
@@ -2327,7 +2335,6 @@ static int tc_probe_dpi_bridge_endpoint(struct tc_data *tc)
if (bridge) {
tc->panel_bridge = bridge;
tc->bridge.type = DRM_MODE_CONNECTOR_DPI;
- tc->bridge.funcs = &tc_dpi_bridge_funcs;
return 0;
}
@@ -2360,7 +2367,6 @@ static int tc_probe_edp_bridge_endpoint(struct tc_data *tc)
tc->bridge.type = DRM_MODE_CONNECTOR_DisplayPort;
}
- tc->bridge.funcs = &tc_edp_bridge_funcs;
if (tc->hpd_pin >= 0)
tc->bridge.ops |= DRM_BRIDGE_OP_DETECT;
tc->bridge.ops |= DRM_BRIDGE_OP_EDID;
@@ -2368,17 +2374,11 @@ static int tc_probe_edp_bridge_endpoint(struct tc_data *tc)
return 0;
}
-static int tc_probe_bridge_endpoint(struct tc_data *tc)
+static enum tc_mode tc_probe_get_mode(struct device *dev)
{
- struct device *dev = tc->dev;
struct of_endpoint endpoint;
struct device_node *node = NULL;
- const u8 mode_dpi_to_edp = BIT(1) | BIT(2);
- const u8 mode_dpi_to_dp = BIT(1);
- const u8 mode_dsi_to_edp = BIT(0) | BIT(2);
- const u8 mode_dsi_to_dp = BIT(0);
- const u8 mode_dsi_to_dpi = BIT(0) | BIT(1);
- u8 mode = 0;
+ enum tc_mode mode = 0;
/*
* Determine bridge configuration.
@@ -2401,7 +2401,27 @@ static int tc_probe_bridge_endpoint(struct tc_data *tc)
return -EINVAL;
}
mode |= BIT(endpoint.port);
+ }
+
+ if (mode != mode_dpi_to_edp &&
+ mode != mode_dpi_to_dp &&
+ mode != mode_dsi_to_dpi &&
+ mode != mode_dsi_to_edp &&
+ mode != mode_dsi_to_dp) {
+ dev_warn(dev, "Invalid mode (0x%x) is not supported!\n", mode);
+ return -EINVAL;
+ }
+
+ return mode;
+}
+static int tc_probe_bridge_endpoint(struct tc_data *tc, enum tc_mode mode)
+{
+ struct device *dev = tc->dev;
+ struct of_endpoint endpoint;
+ struct device_node *node = NULL;
+
+ for_each_endpoint_of_node(dev->of_node, node) {
if (endpoint.port == 2) {
of_property_read_u8_array(node, "toshiba,pre-emphasis",
tc->pre_emphasis,
@@ -2427,24 +2447,28 @@ static int tc_probe_bridge_endpoint(struct tc_data *tc)
return tc_probe_edp_bridge_endpoint(tc);
}
- dev_warn(dev, "Invalid mode (0x%x) is not supported!\n", mode);
-
+ /* Should never happen, mode was validated by tc_probe_get_mode() */
return -EINVAL;
}
static int tc_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
+ const struct drm_bridge_funcs *funcs;
struct tc_data *tc;
+ int mode;
int ret;
- tc = devm_kzalloc(dev, sizeof(*tc), GFP_KERNEL);
- if (!tc)
- return -ENOMEM;
+ mode = tc_probe_get_mode(dev);
+ funcs = (mode == mode_dsi_to_dpi) ? &tc_dpi_bridge_funcs : &tc_edp_bridge_funcs;
+
+ tc = devm_drm_bridge_alloc(dev, struct tc_data, bridge, funcs);
+ if (IS_ERR(tc))
+ return PTR_ERR(tc);
tc->dev = dev;
- ret = tc_probe_bridge_endpoint(tc);
+ ret = tc_probe_bridge_endpoint(tc, mode);
if (ret)
return ret;
This is the new API for allocating DRM bridges. Converting this driver is a bit convoluted because the drm_bridge funcs pointer differs based on the bridge mode. So the current code does: * tc_probe() * devm_kzalloc() private struct embedding drm_bridge * call tc_probe_bridge_endpoint() which * parses DT description into struct fields * computes the mode * calls different bridge init functions based on the mode * each sets a different bridge.funcs pointer The new API expects the funcs pointer to be known at alloc time, which does not fit in the current code structure. Solve this by moving the part of tc_probe_bridge_endpoint() computing the mode into a separate function, tc_probe_get_mode(), which does not need the private driver structure. So now the mode is known before allocation and so is the funcs pointer, while all other operations are still happening after allocation, directly into the private struct data, as they used to. This solution is chosen to minimize the changes in the driver logical code flow. The drawback is we now iterate twice over the endpoints. Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com> --- To: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> To: Maxime Ripard <mripard@kernel.org> To: Thomas Zimmermann <tzimmermann@suse.de> To: David Airlie <airlied@gmail.com> To: Simona Vetter <simona@ffwll.ch> To: Andrzej Hajda <andrzej.hajda@intel.com> To: Neil Armstrong <neil.armstrong@linaro.org> To: Robert Foss <rfoss@kernel.org> To: Laurent Pinchart <Laurent.pinchart@ideasonboard.com> To: Jonas Karlman <jonas@kwiboo.se> To: Jernej Skrabec <jernej.skrabec@gmail.com> To: Jagan Teki <jagan@amarulasolutions.com> To: Shawn Guo <shawnguo@kernel.org> To: Sascha Hauer <s.hauer@pengutronix.de> To: Pengutronix Kernel Team <kernel@pengutronix.de> To: Fabio Estevam <festevam@gmail.com> To: Douglas Anderson <dianders@chromium.org> To: Chun-Kuang Hu <chunkuang.hu@kernel.org> To: Krzysztof Kozlowski <krzk@kernel.org> To: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> Cc: Anusha Srivatsa <asrivats@redhat.com> Cc: Paul Kocialkowski <paulk@sys-base.io> Cc: Dmitry Baryshkov <lumag@kernel.org> Cc: Hervé Codina <herve.codina@bootlin.com> Cc: Hui Pu <Hui.Pu@gehealthcare.com> Cc: Thomas Petazzoni <thomas.petazzoni@bootlin.com> Cc: dri-devel@lists.freedesktop.org Cc: asahi@lists.linux.dev Cc: linux-kernel@vger.kernel.org Cc: chrome-platform@lists.linux.dev Cc: imx@lists.linux.dev Cc: linux-arm-kernel@lists.infradead.org Cc: linux-mediatek@lists.infradead.org Cc: linux-amlogic@lists.infradead.org Cc: linux-renesas-soc@vger.kernel.org Cc: platform-driver-x86@vger.kernel.org Cc: linux-samsung-soc@vger.kernel.org Cc: linux-arm-msm@vger.kernel.org Cc: freedreno@lists.freedesktop.org Cc: linux-stm32@st-md-mailman.stormreply.com --- drivers/gpu/drm/bridge/tc358767.c | 56 ++++++++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 16 deletions(-)