11ec17c26SLiu Ying // SPDX-License-Identifier: GPL-2.0+
21ec17c26SLiu Ying
31ec17c26SLiu Ying /*
41ec17c26SLiu Ying * Copyright 2020,2022 NXP
51ec17c26SLiu Ying */
61ec17c26SLiu Ying
71ec17c26SLiu Ying #include <linux/firmware/imx/svc/misc.h>
872bd9ea3SVille Syrjälä #include <linux/media-bus-format.h>
91ec17c26SLiu Ying #include <linux/module.h>
101ec17c26SLiu Ying #include <linux/of.h>
111ec17c26SLiu Ying #include <linux/of_graph.h>
121ec17c26SLiu Ying #include <linux/platform_device.h>
131ec17c26SLiu Ying
141ec17c26SLiu Ying #include <drm/drm_atomic_state_helper.h>
151ec17c26SLiu Ying #include <drm/drm_bridge.h>
161ec17c26SLiu Ying #include <drm/drm_print.h>
171ec17c26SLiu Ying
181ec17c26SLiu Ying #include <dt-bindings/firmware/imx/rsrc.h>
191ec17c26SLiu Ying
201ec17c26SLiu Ying #define DRIVER_NAME "imx8qxp-display-pixel-link"
211ec17c26SLiu Ying #define PL_MAX_MST_ADDR 3
221ec17c26SLiu Ying #define PL_MAX_NEXT_BRIDGES 2
231ec17c26SLiu Ying
241ec17c26SLiu Ying struct imx8qxp_pixel_link {
251ec17c26SLiu Ying struct drm_bridge bridge;
261ec17c26SLiu Ying struct drm_bridge *next_bridge;
271ec17c26SLiu Ying struct device *dev;
281ec17c26SLiu Ying struct imx_sc_ipc *ipc_handle;
291ec17c26SLiu Ying u8 stream_id;
301ec17c26SLiu Ying u8 dc_id;
311ec17c26SLiu Ying u32 sink_rsc;
321ec17c26SLiu Ying u32 mst_addr;
331ec17c26SLiu Ying u8 mst_addr_ctrl;
341ec17c26SLiu Ying u8 mst_en_ctrl;
351ec17c26SLiu Ying u8 mst_vld_ctrl;
361ec17c26SLiu Ying u8 sync_ctrl;
371ec17c26SLiu Ying };
381ec17c26SLiu Ying
imx8qxp_pixel_link_enable_mst_en(struct imx8qxp_pixel_link * pl)391ec17c26SLiu Ying static void imx8qxp_pixel_link_enable_mst_en(struct imx8qxp_pixel_link *pl)
401ec17c26SLiu Ying {
411ec17c26SLiu Ying int ret;
421ec17c26SLiu Ying
431ec17c26SLiu Ying ret = imx_sc_misc_set_control(pl->ipc_handle, pl->sink_rsc,
441ec17c26SLiu Ying pl->mst_en_ctrl, true);
451ec17c26SLiu Ying if (ret)
461ec17c26SLiu Ying DRM_DEV_ERROR(pl->dev,
471ec17c26SLiu Ying "failed to enable DC%u stream%u pixel link mst_en: %d\n",
481ec17c26SLiu Ying pl->dc_id, pl->stream_id, ret);
491ec17c26SLiu Ying }
501ec17c26SLiu Ying
imx8qxp_pixel_link_enable_mst_vld(struct imx8qxp_pixel_link * pl)511ec17c26SLiu Ying static void imx8qxp_pixel_link_enable_mst_vld(struct imx8qxp_pixel_link *pl)
521ec17c26SLiu Ying {
531ec17c26SLiu Ying int ret;
541ec17c26SLiu Ying
551ec17c26SLiu Ying ret = imx_sc_misc_set_control(pl->ipc_handle, pl->sink_rsc,
561ec17c26SLiu Ying pl->mst_vld_ctrl, true);
571ec17c26SLiu Ying if (ret)
581ec17c26SLiu Ying DRM_DEV_ERROR(pl->dev,
591ec17c26SLiu Ying "failed to enable DC%u stream%u pixel link mst_vld: %d\n",
601ec17c26SLiu Ying pl->dc_id, pl->stream_id, ret);
611ec17c26SLiu Ying }
621ec17c26SLiu Ying
imx8qxp_pixel_link_enable_sync(struct imx8qxp_pixel_link * pl)631ec17c26SLiu Ying static void imx8qxp_pixel_link_enable_sync(struct imx8qxp_pixel_link *pl)
641ec17c26SLiu Ying {
651ec17c26SLiu Ying int ret;
661ec17c26SLiu Ying
671ec17c26SLiu Ying ret = imx_sc_misc_set_control(pl->ipc_handle, pl->sink_rsc,
681ec17c26SLiu Ying pl->sync_ctrl, true);
691ec17c26SLiu Ying if (ret)
701ec17c26SLiu Ying DRM_DEV_ERROR(pl->dev,
711ec17c26SLiu Ying "failed to enable DC%u stream%u pixel link sync: %d\n",
721ec17c26SLiu Ying pl->dc_id, pl->stream_id, ret);
731ec17c26SLiu Ying }
741ec17c26SLiu Ying
imx8qxp_pixel_link_disable_mst_en(struct imx8qxp_pixel_link * pl)751ec17c26SLiu Ying static int imx8qxp_pixel_link_disable_mst_en(struct imx8qxp_pixel_link *pl)
761ec17c26SLiu Ying {
771ec17c26SLiu Ying int ret;
781ec17c26SLiu Ying
791ec17c26SLiu Ying ret = imx_sc_misc_set_control(pl->ipc_handle, pl->sink_rsc,
801ec17c26SLiu Ying pl->mst_en_ctrl, false);
811ec17c26SLiu Ying if (ret)
821ec17c26SLiu Ying DRM_DEV_ERROR(pl->dev,
831ec17c26SLiu Ying "failed to disable DC%u stream%u pixel link mst_en: %d\n",
841ec17c26SLiu Ying pl->dc_id, pl->stream_id, ret);
851ec17c26SLiu Ying
861ec17c26SLiu Ying return ret;
871ec17c26SLiu Ying }
881ec17c26SLiu Ying
imx8qxp_pixel_link_disable_mst_vld(struct imx8qxp_pixel_link * pl)891ec17c26SLiu Ying static int imx8qxp_pixel_link_disable_mst_vld(struct imx8qxp_pixel_link *pl)
901ec17c26SLiu Ying {
911ec17c26SLiu Ying int ret;
921ec17c26SLiu Ying
931ec17c26SLiu Ying ret = imx_sc_misc_set_control(pl->ipc_handle, pl->sink_rsc,
941ec17c26SLiu Ying pl->mst_vld_ctrl, false);
951ec17c26SLiu Ying if (ret)
961ec17c26SLiu Ying DRM_DEV_ERROR(pl->dev,
971ec17c26SLiu Ying "failed to disable DC%u stream%u pixel link mst_vld: %d\n",
981ec17c26SLiu Ying pl->dc_id, pl->stream_id, ret);
991ec17c26SLiu Ying
1001ec17c26SLiu Ying return ret;
1011ec17c26SLiu Ying }
1021ec17c26SLiu Ying
imx8qxp_pixel_link_disable_sync(struct imx8qxp_pixel_link * pl)1031ec17c26SLiu Ying static int imx8qxp_pixel_link_disable_sync(struct imx8qxp_pixel_link *pl)
1041ec17c26SLiu Ying {
1051ec17c26SLiu Ying int ret;
1061ec17c26SLiu Ying
1071ec17c26SLiu Ying ret = imx_sc_misc_set_control(pl->ipc_handle, pl->sink_rsc,
1081ec17c26SLiu Ying pl->sync_ctrl, false);
1091ec17c26SLiu Ying if (ret)
1101ec17c26SLiu Ying DRM_DEV_ERROR(pl->dev,
1111ec17c26SLiu Ying "failed to disable DC%u stream%u pixel link sync: %d\n",
1121ec17c26SLiu Ying pl->dc_id, pl->stream_id, ret);
1131ec17c26SLiu Ying
1141ec17c26SLiu Ying return ret;
1151ec17c26SLiu Ying }
1161ec17c26SLiu Ying
imx8qxp_pixel_link_set_mst_addr(struct imx8qxp_pixel_link * pl)1171ec17c26SLiu Ying static void imx8qxp_pixel_link_set_mst_addr(struct imx8qxp_pixel_link *pl)
1181ec17c26SLiu Ying {
1191ec17c26SLiu Ying int ret;
1201ec17c26SLiu Ying
1211ec17c26SLiu Ying ret = imx_sc_misc_set_control(pl->ipc_handle,
1221ec17c26SLiu Ying pl->sink_rsc, pl->mst_addr_ctrl,
1231ec17c26SLiu Ying pl->mst_addr);
1241ec17c26SLiu Ying if (ret)
1251ec17c26SLiu Ying DRM_DEV_ERROR(pl->dev,
1261ec17c26SLiu Ying "failed to set DC%u stream%u pixel link mst addr(%u): %d\n",
1271ec17c26SLiu Ying pl->dc_id, pl->stream_id, pl->mst_addr, ret);
1281ec17c26SLiu Ying }
1291ec17c26SLiu Ying
imx8qxp_pixel_link_bridge_attach(struct drm_bridge * bridge,enum drm_bridge_attach_flags flags)1301ec17c26SLiu Ying static int imx8qxp_pixel_link_bridge_attach(struct drm_bridge *bridge,
1311ec17c26SLiu Ying enum drm_bridge_attach_flags flags)
1321ec17c26SLiu Ying {
1331ec17c26SLiu Ying struct imx8qxp_pixel_link *pl = bridge->driver_private;
1341ec17c26SLiu Ying
1351ec17c26SLiu Ying if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
1361ec17c26SLiu Ying DRM_DEV_ERROR(pl->dev,
1371ec17c26SLiu Ying "do not support creating a drm_connector\n");
1381ec17c26SLiu Ying return -EINVAL;
1391ec17c26SLiu Ying }
1401ec17c26SLiu Ying
1411ec17c26SLiu Ying if (!bridge->encoder) {
1421ec17c26SLiu Ying DRM_DEV_ERROR(pl->dev, "missing encoder\n");
1431ec17c26SLiu Ying return -ENODEV;
1441ec17c26SLiu Ying }
1451ec17c26SLiu Ying
1461ec17c26SLiu Ying return drm_bridge_attach(bridge->encoder,
1471ec17c26SLiu Ying pl->next_bridge, bridge,
1481ec17c26SLiu Ying DRM_BRIDGE_ATTACH_NO_CONNECTOR);
1491ec17c26SLiu Ying }
1501ec17c26SLiu Ying
1511ec17c26SLiu Ying static void
imx8qxp_pixel_link_bridge_mode_set(struct drm_bridge * bridge,const struct drm_display_mode * mode,const struct drm_display_mode * adjusted_mode)1521ec17c26SLiu Ying imx8qxp_pixel_link_bridge_mode_set(struct drm_bridge *bridge,
1531ec17c26SLiu Ying const struct drm_display_mode *mode,
1541ec17c26SLiu Ying const struct drm_display_mode *adjusted_mode)
1551ec17c26SLiu Ying {
1561ec17c26SLiu Ying struct imx8qxp_pixel_link *pl = bridge->driver_private;
1571ec17c26SLiu Ying
1581ec17c26SLiu Ying imx8qxp_pixel_link_set_mst_addr(pl);
1591ec17c26SLiu Ying }
1601ec17c26SLiu Ying
1611ec17c26SLiu Ying static void
imx8qxp_pixel_link_bridge_atomic_enable(struct drm_bridge * bridge,struct drm_bridge_state * old_bridge_state)1621ec17c26SLiu Ying imx8qxp_pixel_link_bridge_atomic_enable(struct drm_bridge *bridge,
1631ec17c26SLiu Ying struct drm_bridge_state *old_bridge_state)
1641ec17c26SLiu Ying {
1651ec17c26SLiu Ying struct imx8qxp_pixel_link *pl = bridge->driver_private;
1661ec17c26SLiu Ying
1671ec17c26SLiu Ying imx8qxp_pixel_link_enable_mst_en(pl);
1681ec17c26SLiu Ying imx8qxp_pixel_link_enable_mst_vld(pl);
1691ec17c26SLiu Ying imx8qxp_pixel_link_enable_sync(pl);
1701ec17c26SLiu Ying }
1711ec17c26SLiu Ying
1721ec17c26SLiu Ying static void
imx8qxp_pixel_link_bridge_atomic_disable(struct drm_bridge * bridge,struct drm_bridge_state * old_bridge_state)1731ec17c26SLiu Ying imx8qxp_pixel_link_bridge_atomic_disable(struct drm_bridge *bridge,
1741ec17c26SLiu Ying struct drm_bridge_state *old_bridge_state)
1751ec17c26SLiu Ying {
1761ec17c26SLiu Ying struct imx8qxp_pixel_link *pl = bridge->driver_private;
1771ec17c26SLiu Ying
1781ec17c26SLiu Ying imx8qxp_pixel_link_disable_mst_en(pl);
1791ec17c26SLiu Ying imx8qxp_pixel_link_disable_mst_vld(pl);
1801ec17c26SLiu Ying imx8qxp_pixel_link_disable_sync(pl);
1811ec17c26SLiu Ying }
1821ec17c26SLiu Ying
1831ec17c26SLiu Ying static const u32 imx8qxp_pixel_link_bus_output_fmts[] = {
1841ec17c26SLiu Ying MEDIA_BUS_FMT_RGB888_1X36_CPADLO,
1851ec17c26SLiu Ying MEDIA_BUS_FMT_RGB666_1X36_CPADLO,
1861ec17c26SLiu Ying };
1871ec17c26SLiu Ying
imx8qxp_pixel_link_bus_output_fmt_supported(u32 fmt)1881ec17c26SLiu Ying static bool imx8qxp_pixel_link_bus_output_fmt_supported(u32 fmt)
1891ec17c26SLiu Ying {
1901ec17c26SLiu Ying int i;
1911ec17c26SLiu Ying
1921ec17c26SLiu Ying for (i = 0; i < ARRAY_SIZE(imx8qxp_pixel_link_bus_output_fmts); i++) {
1931ec17c26SLiu Ying if (imx8qxp_pixel_link_bus_output_fmts[i] == fmt)
1941ec17c26SLiu Ying return true;
1951ec17c26SLiu Ying }
1961ec17c26SLiu Ying
1971ec17c26SLiu Ying return false;
1981ec17c26SLiu Ying }
1991ec17c26SLiu Ying
2001ec17c26SLiu Ying static u32 *
imx8qxp_pixel_link_bridge_atomic_get_input_bus_fmts(struct drm_bridge * bridge,struct drm_bridge_state * bridge_state,struct drm_crtc_state * crtc_state,struct drm_connector_state * conn_state,u32 output_fmt,unsigned int * num_input_fmts)2011ec17c26SLiu Ying imx8qxp_pixel_link_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
2021ec17c26SLiu Ying struct drm_bridge_state *bridge_state,
2031ec17c26SLiu Ying struct drm_crtc_state *crtc_state,
2041ec17c26SLiu Ying struct drm_connector_state *conn_state,
2051ec17c26SLiu Ying u32 output_fmt,
2061ec17c26SLiu Ying unsigned int *num_input_fmts)
2071ec17c26SLiu Ying {
2081ec17c26SLiu Ying u32 *input_fmts;
2091ec17c26SLiu Ying
2101ec17c26SLiu Ying if (!imx8qxp_pixel_link_bus_output_fmt_supported(output_fmt))
2111ec17c26SLiu Ying return NULL;
2121ec17c26SLiu Ying
2131ec17c26SLiu Ying *num_input_fmts = 1;
2141ec17c26SLiu Ying
2151ec17c26SLiu Ying input_fmts = kmalloc(sizeof(*input_fmts), GFP_KERNEL);
2161ec17c26SLiu Ying if (!input_fmts)
2171ec17c26SLiu Ying return NULL;
2181ec17c26SLiu Ying
2191ec17c26SLiu Ying input_fmts[0] = output_fmt;
2201ec17c26SLiu Ying
2211ec17c26SLiu Ying return input_fmts;
2221ec17c26SLiu Ying }
2231ec17c26SLiu Ying
2241ec17c26SLiu Ying static u32 *
imx8qxp_pixel_link_bridge_atomic_get_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)2251ec17c26SLiu Ying imx8qxp_pixel_link_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
2261ec17c26SLiu Ying struct drm_bridge_state *bridge_state,
2271ec17c26SLiu Ying struct drm_crtc_state *crtc_state,
2281ec17c26SLiu Ying struct drm_connector_state *conn_state,
2291ec17c26SLiu Ying unsigned int *num_output_fmts)
2301ec17c26SLiu Ying {
2311ec17c26SLiu Ying *num_output_fmts = ARRAY_SIZE(imx8qxp_pixel_link_bus_output_fmts);
2321ec17c26SLiu Ying return kmemdup(imx8qxp_pixel_link_bus_output_fmts,
2331ec17c26SLiu Ying sizeof(imx8qxp_pixel_link_bus_output_fmts), GFP_KERNEL);
2341ec17c26SLiu Ying }
2351ec17c26SLiu Ying
2361ec17c26SLiu Ying static const struct drm_bridge_funcs imx8qxp_pixel_link_bridge_funcs = {
2371ec17c26SLiu Ying .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
2381ec17c26SLiu Ying .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
2391ec17c26SLiu Ying .atomic_reset = drm_atomic_helper_bridge_reset,
2401ec17c26SLiu Ying .attach = imx8qxp_pixel_link_bridge_attach,
2411ec17c26SLiu Ying .mode_set = imx8qxp_pixel_link_bridge_mode_set,
2421ec17c26SLiu Ying .atomic_enable = imx8qxp_pixel_link_bridge_atomic_enable,
2431ec17c26SLiu Ying .atomic_disable = imx8qxp_pixel_link_bridge_atomic_disable,
2441ec17c26SLiu Ying .atomic_get_input_bus_fmts =
2451ec17c26SLiu Ying imx8qxp_pixel_link_bridge_atomic_get_input_bus_fmts,
2461ec17c26SLiu Ying .atomic_get_output_bus_fmts =
2471ec17c26SLiu Ying imx8qxp_pixel_link_bridge_atomic_get_output_bus_fmts,
2481ec17c26SLiu Ying };
2491ec17c26SLiu Ying
imx8qxp_pixel_link_disable_all_controls(struct imx8qxp_pixel_link * pl)2501ec17c26SLiu Ying static int imx8qxp_pixel_link_disable_all_controls(struct imx8qxp_pixel_link *pl)
2511ec17c26SLiu Ying {
2521ec17c26SLiu Ying int ret;
2531ec17c26SLiu Ying
2541ec17c26SLiu Ying ret = imx8qxp_pixel_link_disable_mst_en(pl);
2551ec17c26SLiu Ying if (ret)
2561ec17c26SLiu Ying return ret;
2571ec17c26SLiu Ying
2581ec17c26SLiu Ying ret = imx8qxp_pixel_link_disable_mst_vld(pl);
2591ec17c26SLiu Ying if (ret)
2601ec17c26SLiu Ying return ret;
2611ec17c26SLiu Ying
2621ec17c26SLiu Ying return imx8qxp_pixel_link_disable_sync(pl);
2631ec17c26SLiu Ying }
2641ec17c26SLiu Ying
2651ec17c26SLiu Ying static struct drm_bridge *
imx8qxp_pixel_link_find_next_bridge(struct imx8qxp_pixel_link * pl)2661ec17c26SLiu Ying imx8qxp_pixel_link_find_next_bridge(struct imx8qxp_pixel_link *pl)
2671ec17c26SLiu Ying {
2681ec17c26SLiu Ying struct device_node *np = pl->dev->of_node;
2691ec17c26SLiu Ying struct device_node *port, *remote;
2701ec17c26SLiu Ying struct drm_bridge *next_bridge[PL_MAX_NEXT_BRIDGES];
2711ec17c26SLiu Ying u32 port_id;
2721ec17c26SLiu Ying bool found_port = false;
2731ec17c26SLiu Ying int reg, ep_cnt = 0;
2741ec17c26SLiu Ying /* select the first next bridge by default */
2751ec17c26SLiu Ying int bridge_sel = 0;
2761ec17c26SLiu Ying
2771ec17c26SLiu Ying for (port_id = 1; port_id <= PL_MAX_MST_ADDR + 1; port_id++) {
2781ec17c26SLiu Ying port = of_graph_get_port_by_id(np, port_id);
2791ec17c26SLiu Ying if (!port)
2801ec17c26SLiu Ying continue;
2811ec17c26SLiu Ying
2821ec17c26SLiu Ying if (of_device_is_available(port)) {
2831ec17c26SLiu Ying found_port = true;
2841ec17c26SLiu Ying of_node_put(port);
2851ec17c26SLiu Ying break;
2861ec17c26SLiu Ying }
2871ec17c26SLiu Ying
2881ec17c26SLiu Ying of_node_put(port);
2891ec17c26SLiu Ying }
2901ec17c26SLiu Ying
2911ec17c26SLiu Ying if (!found_port) {
2921ec17c26SLiu Ying DRM_DEV_ERROR(pl->dev, "no available output port\n");
2931ec17c26SLiu Ying return ERR_PTR(-ENODEV);
2941ec17c26SLiu Ying }
2951ec17c26SLiu Ying
2961ec17c26SLiu Ying for (reg = 0; reg < PL_MAX_NEXT_BRIDGES; reg++) {
2971ec17c26SLiu Ying remote = of_graph_get_remote_node(np, port_id, reg);
2981ec17c26SLiu Ying if (!remote)
2991ec17c26SLiu Ying continue;
3001ec17c26SLiu Ying
3011ec17c26SLiu Ying if (!of_device_is_available(remote->parent)) {
3021ec17c26SLiu Ying DRM_DEV_DEBUG(pl->dev,
3031ec17c26SLiu Ying "port%u endpoint%u remote parent is not available\n",
3041ec17c26SLiu Ying port_id, reg);
3051ec17c26SLiu Ying of_node_put(remote);
3061ec17c26SLiu Ying continue;
3071ec17c26SLiu Ying }
3081ec17c26SLiu Ying
3091ec17c26SLiu Ying next_bridge[ep_cnt] = of_drm_find_bridge(remote);
3101ec17c26SLiu Ying if (!next_bridge[ep_cnt]) {
3111ec17c26SLiu Ying of_node_put(remote);
3121ec17c26SLiu Ying return ERR_PTR(-EPROBE_DEFER);
3131ec17c26SLiu Ying }
3141ec17c26SLiu Ying
3151ec17c26SLiu Ying /* specially select the next bridge with companion PXL2DPI */
316*7fa5047aSRob Herring if (of_property_present(remote, "fsl,companion-pxl2dpi"))
3171ec17c26SLiu Ying bridge_sel = ep_cnt;
3181ec17c26SLiu Ying
3191ec17c26SLiu Ying ep_cnt++;
3201ec17c26SLiu Ying
3211ec17c26SLiu Ying of_node_put(remote);
3221ec17c26SLiu Ying }
3231ec17c26SLiu Ying
3241ec17c26SLiu Ying pl->mst_addr = port_id - 1;
3251ec17c26SLiu Ying
3261ec17c26SLiu Ying return next_bridge[bridge_sel];
3271ec17c26SLiu Ying }
3281ec17c26SLiu Ying
imx8qxp_pixel_link_bridge_probe(struct platform_device * pdev)3291ec17c26SLiu Ying static int imx8qxp_pixel_link_bridge_probe(struct platform_device *pdev)
3301ec17c26SLiu Ying {
3311ec17c26SLiu Ying struct imx8qxp_pixel_link *pl;
3321ec17c26SLiu Ying struct device *dev = &pdev->dev;
3331ec17c26SLiu Ying struct device_node *np = dev->of_node;
3341ec17c26SLiu Ying int ret;
3351ec17c26SLiu Ying
3361ec17c26SLiu Ying pl = devm_kzalloc(dev, sizeof(*pl), GFP_KERNEL);
3371ec17c26SLiu Ying if (!pl)
3381ec17c26SLiu Ying return -ENOMEM;
3391ec17c26SLiu Ying
3401ec17c26SLiu Ying ret = imx_scu_get_handle(&pl->ipc_handle);
3411ec17c26SLiu Ying if (ret) {
3421ec17c26SLiu Ying if (ret != -EPROBE_DEFER)
3431ec17c26SLiu Ying DRM_DEV_ERROR(dev, "failed to get SCU ipc handle: %d\n",
3441ec17c26SLiu Ying ret);
3451ec17c26SLiu Ying return ret;
3461ec17c26SLiu Ying }
3471ec17c26SLiu Ying
3481ec17c26SLiu Ying ret = of_property_read_u8(np, "fsl,dc-id", &pl->dc_id);
3491ec17c26SLiu Ying if (ret) {
3501ec17c26SLiu Ying DRM_DEV_ERROR(dev, "failed to get DC index: %d\n", ret);
3511ec17c26SLiu Ying return ret;
3521ec17c26SLiu Ying }
3531ec17c26SLiu Ying
3541ec17c26SLiu Ying ret = of_property_read_u8(np, "fsl,dc-stream-id", &pl->stream_id);
3551ec17c26SLiu Ying if (ret) {
3561ec17c26SLiu Ying DRM_DEV_ERROR(dev, "failed to get DC stream index: %d\n", ret);
3571ec17c26SLiu Ying return ret;
3581ec17c26SLiu Ying }
3591ec17c26SLiu Ying
3601ec17c26SLiu Ying pl->dev = dev;
3611ec17c26SLiu Ying
3621ec17c26SLiu Ying pl->sink_rsc = pl->dc_id ? IMX_SC_R_DC_1 : IMX_SC_R_DC_0;
3631ec17c26SLiu Ying
3641ec17c26SLiu Ying if (pl->stream_id == 0) {
3651ec17c26SLiu Ying pl->mst_addr_ctrl = IMX_SC_C_PXL_LINK_MST1_ADDR;
3661ec17c26SLiu Ying pl->mst_en_ctrl = IMX_SC_C_PXL_LINK_MST1_ENB;
3671ec17c26SLiu Ying pl->mst_vld_ctrl = IMX_SC_C_PXL_LINK_MST1_VLD;
3681ec17c26SLiu Ying pl->sync_ctrl = IMX_SC_C_SYNC_CTRL0;
3691ec17c26SLiu Ying } else {
3701ec17c26SLiu Ying pl->mst_addr_ctrl = IMX_SC_C_PXL_LINK_MST2_ADDR;
3711ec17c26SLiu Ying pl->mst_en_ctrl = IMX_SC_C_PXL_LINK_MST2_ENB;
3721ec17c26SLiu Ying pl->mst_vld_ctrl = IMX_SC_C_PXL_LINK_MST2_VLD;
3731ec17c26SLiu Ying pl->sync_ctrl = IMX_SC_C_SYNC_CTRL1;
3741ec17c26SLiu Ying }
3751ec17c26SLiu Ying
3761ec17c26SLiu Ying /* disable all controls to POR default */
3771ec17c26SLiu Ying ret = imx8qxp_pixel_link_disable_all_controls(pl);
3781ec17c26SLiu Ying if (ret)
3791ec17c26SLiu Ying return ret;
3801ec17c26SLiu Ying
3811ec17c26SLiu Ying pl->next_bridge = imx8qxp_pixel_link_find_next_bridge(pl);
3821ec17c26SLiu Ying if (IS_ERR(pl->next_bridge)) {
3831ec17c26SLiu Ying ret = PTR_ERR(pl->next_bridge);
3841ec17c26SLiu Ying if (ret != -EPROBE_DEFER)
3851ec17c26SLiu Ying DRM_DEV_ERROR(dev, "failed to find next bridge: %d\n",
3861ec17c26SLiu Ying ret);
3871ec17c26SLiu Ying return ret;
3881ec17c26SLiu Ying }
3891ec17c26SLiu Ying
3901ec17c26SLiu Ying platform_set_drvdata(pdev, pl);
3911ec17c26SLiu Ying
3921ec17c26SLiu Ying pl->bridge.driver_private = pl;
3931ec17c26SLiu Ying pl->bridge.funcs = &imx8qxp_pixel_link_bridge_funcs;
3941ec17c26SLiu Ying pl->bridge.of_node = np;
3951ec17c26SLiu Ying
3961ec17c26SLiu Ying drm_bridge_add(&pl->bridge);
3971ec17c26SLiu Ying
3981ec17c26SLiu Ying return ret;
3991ec17c26SLiu Ying }
4001ec17c26SLiu Ying
imx8qxp_pixel_link_bridge_remove(struct platform_device * pdev)4012b438065SUwe Kleine-König static void imx8qxp_pixel_link_bridge_remove(struct platform_device *pdev)
4021ec17c26SLiu Ying {
4031ec17c26SLiu Ying struct imx8qxp_pixel_link *pl = platform_get_drvdata(pdev);
4041ec17c26SLiu Ying
4051ec17c26SLiu Ying drm_bridge_remove(&pl->bridge);
4061ec17c26SLiu Ying }
4071ec17c26SLiu Ying
4081ec17c26SLiu Ying static const struct of_device_id imx8qxp_pixel_link_dt_ids[] = {
4091ec17c26SLiu Ying { .compatible = "fsl,imx8qm-dc-pixel-link", },
4101ec17c26SLiu Ying { .compatible = "fsl,imx8qxp-dc-pixel-link", },
4111ec17c26SLiu Ying { /* sentinel */ }
4121ec17c26SLiu Ying };
4131ec17c26SLiu Ying MODULE_DEVICE_TABLE(of, imx8qxp_pixel_link_dt_ids);
4141ec17c26SLiu Ying
4151ec17c26SLiu Ying static struct platform_driver imx8qxp_pixel_link_bridge_driver = {
4161ec17c26SLiu Ying .probe = imx8qxp_pixel_link_bridge_probe,
4172b438065SUwe Kleine-König .remove_new = imx8qxp_pixel_link_bridge_remove,
4181ec17c26SLiu Ying .driver = {
4191ec17c26SLiu Ying .of_match_table = imx8qxp_pixel_link_dt_ids,
4201ec17c26SLiu Ying .name = DRIVER_NAME,
4211ec17c26SLiu Ying },
4221ec17c26SLiu Ying };
4231ec17c26SLiu Ying module_platform_driver(imx8qxp_pixel_link_bridge_driver);
4241ec17c26SLiu Ying
4251ec17c26SLiu Ying MODULE_DESCRIPTION("i.MX8QXP/QM display pixel link bridge driver");
4261ec17c26SLiu Ying MODULE_AUTHOR("Liu Ying <victor.liu@nxp.com>");
4271ec17c26SLiu Ying MODULE_LICENSE("GPL v2");
4281ec17c26SLiu Ying MODULE_ALIAS("platform:" DRIVER_NAME);
429