Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 
0003 /*
0004  * Copyright 2020,2022 NXP
0005  */
0006 
0007 #include <linux/firmware/imx/svc/misc.h>
0008 #include <linux/media-bus-format.h>
0009 #include <linux/module.h>
0010 #include <linux/of.h>
0011 #include <linux/of_graph.h>
0012 #include <linux/platform_device.h>
0013 
0014 #include <drm/drm_atomic_state_helper.h>
0015 #include <drm/drm_bridge.h>
0016 #include <drm/drm_print.h>
0017 
0018 #include <dt-bindings/firmware/imx/rsrc.h>
0019 
0020 #define DRIVER_NAME     "imx8qxp-display-pixel-link"
0021 #define PL_MAX_MST_ADDR     3
0022 #define PL_MAX_NEXT_BRIDGES 2
0023 
0024 struct imx8qxp_pixel_link {
0025     struct drm_bridge bridge;
0026     struct drm_bridge *next_bridge;
0027     struct device *dev;
0028     struct imx_sc_ipc *ipc_handle;
0029     u8 stream_id;
0030     u8 dc_id;
0031     u32 sink_rsc;
0032     u32 mst_addr;
0033     u8 mst_addr_ctrl;
0034     u8 mst_en_ctrl;
0035     u8 mst_vld_ctrl;
0036     u8 sync_ctrl;
0037 };
0038 
0039 static void imx8qxp_pixel_link_enable_mst_en(struct imx8qxp_pixel_link *pl)
0040 {
0041     int ret;
0042 
0043     ret = imx_sc_misc_set_control(pl->ipc_handle, pl->sink_rsc,
0044                       pl->mst_en_ctrl, true);
0045     if (ret)
0046         DRM_DEV_ERROR(pl->dev,
0047                   "failed to enable DC%u stream%u pixel link mst_en: %d\n",
0048                   pl->dc_id, pl->stream_id, ret);
0049 }
0050 
0051 static void imx8qxp_pixel_link_enable_mst_vld(struct imx8qxp_pixel_link *pl)
0052 {
0053     int ret;
0054 
0055     ret = imx_sc_misc_set_control(pl->ipc_handle, pl->sink_rsc,
0056                       pl->mst_vld_ctrl, true);
0057     if (ret)
0058         DRM_DEV_ERROR(pl->dev,
0059                   "failed to enable DC%u stream%u pixel link mst_vld: %d\n",
0060                   pl->dc_id, pl->stream_id, ret);
0061 }
0062 
0063 static void imx8qxp_pixel_link_enable_sync(struct imx8qxp_pixel_link *pl)
0064 {
0065     int ret;
0066 
0067     ret = imx_sc_misc_set_control(pl->ipc_handle, pl->sink_rsc,
0068                       pl->sync_ctrl, true);
0069     if (ret)
0070         DRM_DEV_ERROR(pl->dev,
0071                   "failed to enable DC%u stream%u pixel link sync: %d\n",
0072                   pl->dc_id, pl->stream_id, ret);
0073 }
0074 
0075 static int imx8qxp_pixel_link_disable_mst_en(struct imx8qxp_pixel_link *pl)
0076 {
0077     int ret;
0078 
0079     ret = imx_sc_misc_set_control(pl->ipc_handle, pl->sink_rsc,
0080                       pl->mst_en_ctrl, false);
0081     if (ret)
0082         DRM_DEV_ERROR(pl->dev,
0083                   "failed to disable DC%u stream%u pixel link mst_en: %d\n",
0084                   pl->dc_id, pl->stream_id, ret);
0085 
0086     return ret;
0087 }
0088 
0089 static int imx8qxp_pixel_link_disable_mst_vld(struct imx8qxp_pixel_link *pl)
0090 {
0091     int ret;
0092 
0093     ret = imx_sc_misc_set_control(pl->ipc_handle, pl->sink_rsc,
0094                       pl->mst_vld_ctrl, false);
0095     if (ret)
0096         DRM_DEV_ERROR(pl->dev,
0097                   "failed to disable DC%u stream%u pixel link mst_vld: %d\n",
0098                   pl->dc_id, pl->stream_id, ret);
0099 
0100     return ret;
0101 }
0102 
0103 static int imx8qxp_pixel_link_disable_sync(struct imx8qxp_pixel_link *pl)
0104 {
0105     int ret;
0106 
0107     ret = imx_sc_misc_set_control(pl->ipc_handle, pl->sink_rsc,
0108                       pl->sync_ctrl, false);
0109     if (ret)
0110         DRM_DEV_ERROR(pl->dev,
0111                   "failed to disable DC%u stream%u pixel link sync: %d\n",
0112                   pl->dc_id, pl->stream_id, ret);
0113 
0114     return ret;
0115 }
0116 
0117 static void imx8qxp_pixel_link_set_mst_addr(struct imx8qxp_pixel_link *pl)
0118 {
0119     int ret;
0120 
0121     ret = imx_sc_misc_set_control(pl->ipc_handle,
0122                       pl->sink_rsc, pl->mst_addr_ctrl,
0123                       pl->mst_addr);
0124     if (ret)
0125         DRM_DEV_ERROR(pl->dev,
0126                   "failed to set DC%u stream%u pixel link mst addr(%u): %d\n",
0127                   pl->dc_id, pl->stream_id, pl->mst_addr, ret);
0128 }
0129 
0130 static int imx8qxp_pixel_link_bridge_attach(struct drm_bridge *bridge,
0131                         enum drm_bridge_attach_flags flags)
0132 {
0133     struct imx8qxp_pixel_link *pl = bridge->driver_private;
0134 
0135     if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
0136         DRM_DEV_ERROR(pl->dev,
0137                   "do not support creating a drm_connector\n");
0138         return -EINVAL;
0139     }
0140 
0141     if (!bridge->encoder) {
0142         DRM_DEV_ERROR(pl->dev, "missing encoder\n");
0143         return -ENODEV;
0144     }
0145 
0146     return drm_bridge_attach(bridge->encoder,
0147                  pl->next_bridge, bridge,
0148                  DRM_BRIDGE_ATTACH_NO_CONNECTOR);
0149 }
0150 
0151 static void
0152 imx8qxp_pixel_link_bridge_mode_set(struct drm_bridge *bridge,
0153                    const struct drm_display_mode *mode,
0154                    const struct drm_display_mode *adjusted_mode)
0155 {
0156     struct imx8qxp_pixel_link *pl = bridge->driver_private;
0157 
0158     imx8qxp_pixel_link_set_mst_addr(pl);
0159 }
0160 
0161 static void
0162 imx8qxp_pixel_link_bridge_atomic_enable(struct drm_bridge *bridge,
0163                     struct drm_bridge_state *old_bridge_state)
0164 {
0165     struct imx8qxp_pixel_link *pl = bridge->driver_private;
0166 
0167     imx8qxp_pixel_link_enable_mst_en(pl);
0168     imx8qxp_pixel_link_enable_mst_vld(pl);
0169     imx8qxp_pixel_link_enable_sync(pl);
0170 }
0171 
0172 static void
0173 imx8qxp_pixel_link_bridge_atomic_disable(struct drm_bridge *bridge,
0174                      struct drm_bridge_state *old_bridge_state)
0175 {
0176     struct imx8qxp_pixel_link *pl = bridge->driver_private;
0177 
0178     imx8qxp_pixel_link_disable_mst_en(pl);
0179     imx8qxp_pixel_link_disable_mst_vld(pl);
0180     imx8qxp_pixel_link_disable_sync(pl);
0181 }
0182 
0183 static const u32 imx8qxp_pixel_link_bus_output_fmts[] = {
0184     MEDIA_BUS_FMT_RGB888_1X36_CPADLO,
0185     MEDIA_BUS_FMT_RGB666_1X36_CPADLO,
0186 };
0187 
0188 static bool imx8qxp_pixel_link_bus_output_fmt_supported(u32 fmt)
0189 {
0190     int i;
0191 
0192     for (i = 0; i < ARRAY_SIZE(imx8qxp_pixel_link_bus_output_fmts); i++) {
0193         if (imx8qxp_pixel_link_bus_output_fmts[i] == fmt)
0194             return true;
0195     }
0196 
0197     return false;
0198 }
0199 
0200 static u32 *
0201 imx8qxp_pixel_link_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
0202                             struct drm_bridge_state *bridge_state,
0203                             struct drm_crtc_state *crtc_state,
0204                             struct drm_connector_state *conn_state,
0205                             u32 output_fmt,
0206                             unsigned int *num_input_fmts)
0207 {
0208     u32 *input_fmts;
0209 
0210     if (!imx8qxp_pixel_link_bus_output_fmt_supported(output_fmt))
0211         return NULL;
0212 
0213     *num_input_fmts = 1;
0214 
0215     input_fmts = kmalloc(sizeof(*input_fmts), GFP_KERNEL);
0216     if (!input_fmts)
0217         return NULL;
0218 
0219     input_fmts[0] = output_fmt;
0220 
0221     return input_fmts;
0222 }
0223 
0224 static u32 *
0225 imx8qxp_pixel_link_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
0226                              struct drm_bridge_state *bridge_state,
0227                              struct drm_crtc_state *crtc_state,
0228                              struct drm_connector_state *conn_state,
0229                              unsigned int *num_output_fmts)
0230 {
0231     *num_output_fmts = ARRAY_SIZE(imx8qxp_pixel_link_bus_output_fmts);
0232     return kmemdup(imx8qxp_pixel_link_bus_output_fmts,
0233             sizeof(imx8qxp_pixel_link_bus_output_fmts), GFP_KERNEL);
0234 }
0235 
0236 static const struct drm_bridge_funcs imx8qxp_pixel_link_bridge_funcs = {
0237     .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
0238     .atomic_destroy_state   = drm_atomic_helper_bridge_destroy_state,
0239     .atomic_reset       = drm_atomic_helper_bridge_reset,
0240     .attach         = imx8qxp_pixel_link_bridge_attach,
0241     .mode_set       = imx8qxp_pixel_link_bridge_mode_set,
0242     .atomic_enable      = imx8qxp_pixel_link_bridge_atomic_enable,
0243     .atomic_disable     = imx8qxp_pixel_link_bridge_atomic_disable,
0244     .atomic_get_input_bus_fmts =
0245             imx8qxp_pixel_link_bridge_atomic_get_input_bus_fmts,
0246     .atomic_get_output_bus_fmts =
0247             imx8qxp_pixel_link_bridge_atomic_get_output_bus_fmts,
0248 };
0249 
0250 static int imx8qxp_pixel_link_disable_all_controls(struct imx8qxp_pixel_link *pl)
0251 {
0252     int ret;
0253 
0254     ret = imx8qxp_pixel_link_disable_mst_en(pl);
0255     if (ret)
0256         return ret;
0257 
0258     ret = imx8qxp_pixel_link_disable_mst_vld(pl);
0259     if (ret)
0260         return ret;
0261 
0262     return imx8qxp_pixel_link_disable_sync(pl);
0263 }
0264 
0265 static struct drm_bridge *
0266 imx8qxp_pixel_link_find_next_bridge(struct imx8qxp_pixel_link *pl)
0267 {
0268     struct device_node *np = pl->dev->of_node;
0269     struct device_node *port, *remote;
0270     struct drm_bridge *next_bridge[PL_MAX_NEXT_BRIDGES];
0271     u32 port_id;
0272     bool found_port = false;
0273     int reg, ep_cnt = 0;
0274     /* select the first next bridge by default */
0275     int bridge_sel = 0;
0276 
0277     for (port_id = 1; port_id <= PL_MAX_MST_ADDR + 1; port_id++) {
0278         port = of_graph_get_port_by_id(np, port_id);
0279         if (!port)
0280             continue;
0281 
0282         if (of_device_is_available(port)) {
0283             found_port = true;
0284             of_node_put(port);
0285             break;
0286         }
0287 
0288         of_node_put(port);
0289     }
0290 
0291     if (!found_port) {
0292         DRM_DEV_ERROR(pl->dev, "no available output port\n");
0293         return ERR_PTR(-ENODEV);
0294     }
0295 
0296     for (reg = 0; reg < PL_MAX_NEXT_BRIDGES; reg++) {
0297         remote = of_graph_get_remote_node(np, port_id, reg);
0298         if (!remote)
0299             continue;
0300 
0301         if (!of_device_is_available(remote->parent)) {
0302             DRM_DEV_DEBUG(pl->dev,
0303                       "port%u endpoint%u remote parent is not available\n",
0304                       port_id, reg);
0305             of_node_put(remote);
0306             continue;
0307         }
0308 
0309         next_bridge[ep_cnt] = of_drm_find_bridge(remote);
0310         if (!next_bridge[ep_cnt]) {
0311             of_node_put(remote);
0312             return ERR_PTR(-EPROBE_DEFER);
0313         }
0314 
0315         /* specially select the next bridge with companion PXL2DPI */
0316         if (of_find_property(remote, "fsl,companion-pxl2dpi", NULL))
0317             bridge_sel = ep_cnt;
0318 
0319         ep_cnt++;
0320 
0321         of_node_put(remote);
0322     }
0323 
0324     pl->mst_addr = port_id - 1;
0325 
0326     return next_bridge[bridge_sel];
0327 }
0328 
0329 static int imx8qxp_pixel_link_bridge_probe(struct platform_device *pdev)
0330 {
0331     struct imx8qxp_pixel_link *pl;
0332     struct device *dev = &pdev->dev;
0333     struct device_node *np = dev->of_node;
0334     int ret;
0335 
0336     pl = devm_kzalloc(dev, sizeof(*pl), GFP_KERNEL);
0337     if (!pl)
0338         return -ENOMEM;
0339 
0340     ret = imx_scu_get_handle(&pl->ipc_handle);
0341     if (ret) {
0342         if (ret != -EPROBE_DEFER)
0343             DRM_DEV_ERROR(dev, "failed to get SCU ipc handle: %d\n",
0344                       ret);
0345         return ret;
0346     }
0347 
0348     ret = of_property_read_u8(np, "fsl,dc-id", &pl->dc_id);
0349     if (ret) {
0350         DRM_DEV_ERROR(dev, "failed to get DC index: %d\n", ret);
0351         return ret;
0352     }
0353 
0354     ret = of_property_read_u8(np, "fsl,dc-stream-id", &pl->stream_id);
0355     if (ret) {
0356         DRM_DEV_ERROR(dev, "failed to get DC stream index: %d\n", ret);
0357         return ret;
0358     }
0359 
0360     pl->dev = dev;
0361 
0362     pl->sink_rsc = pl->dc_id ? IMX_SC_R_DC_1 : IMX_SC_R_DC_0;
0363 
0364     if (pl->stream_id == 0) {
0365         pl->mst_addr_ctrl = IMX_SC_C_PXL_LINK_MST1_ADDR;
0366         pl->mst_en_ctrl   = IMX_SC_C_PXL_LINK_MST1_ENB;
0367         pl->mst_vld_ctrl  = IMX_SC_C_PXL_LINK_MST1_VLD;
0368         pl->sync_ctrl     = IMX_SC_C_SYNC_CTRL0;
0369     } else {
0370         pl->mst_addr_ctrl = IMX_SC_C_PXL_LINK_MST2_ADDR;
0371         pl->mst_en_ctrl   = IMX_SC_C_PXL_LINK_MST2_ENB;
0372         pl->mst_vld_ctrl  = IMX_SC_C_PXL_LINK_MST2_VLD;
0373         pl->sync_ctrl     = IMX_SC_C_SYNC_CTRL1;
0374     }
0375 
0376     /* disable all controls to POR default */
0377     ret = imx8qxp_pixel_link_disable_all_controls(pl);
0378     if (ret)
0379         return ret;
0380 
0381     pl->next_bridge = imx8qxp_pixel_link_find_next_bridge(pl);
0382     if (IS_ERR(pl->next_bridge)) {
0383         ret = PTR_ERR(pl->next_bridge);
0384         if (ret != -EPROBE_DEFER)
0385             DRM_DEV_ERROR(dev, "failed to find next bridge: %d\n",
0386                       ret);
0387         return ret;
0388     }
0389 
0390     platform_set_drvdata(pdev, pl);
0391 
0392     pl->bridge.driver_private = pl;
0393     pl->bridge.funcs = &imx8qxp_pixel_link_bridge_funcs;
0394     pl->bridge.of_node = np;
0395 
0396     drm_bridge_add(&pl->bridge);
0397 
0398     return ret;
0399 }
0400 
0401 static int imx8qxp_pixel_link_bridge_remove(struct platform_device *pdev)
0402 {
0403     struct imx8qxp_pixel_link *pl = platform_get_drvdata(pdev);
0404 
0405     drm_bridge_remove(&pl->bridge);
0406 
0407     return 0;
0408 }
0409 
0410 static const struct of_device_id imx8qxp_pixel_link_dt_ids[] = {
0411     { .compatible = "fsl,imx8qm-dc-pixel-link", },
0412     { .compatible = "fsl,imx8qxp-dc-pixel-link", },
0413     { /* sentinel */ }
0414 };
0415 MODULE_DEVICE_TABLE(of, imx8qxp_pixel_link_dt_ids);
0416 
0417 static struct platform_driver imx8qxp_pixel_link_bridge_driver = {
0418     .probe  = imx8qxp_pixel_link_bridge_probe,
0419     .remove = imx8qxp_pixel_link_bridge_remove,
0420     .driver = {
0421         .of_match_table = imx8qxp_pixel_link_dt_ids,
0422         .name = DRIVER_NAME,
0423     },
0424 };
0425 module_platform_driver(imx8qxp_pixel_link_bridge_driver);
0426 
0427 MODULE_DESCRIPTION("i.MX8QXP/QM display pixel link bridge driver");
0428 MODULE_AUTHOR("Liu Ying <victor.liu@nxp.com>");
0429 MODULE_LICENSE("GPL v2");
0430 MODULE_ALIAS("platform:" DRIVER_NAME);