Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 
0003 /*
0004  * Copyright 2020 NXP
0005  */
0006 
0007 #include <linux/bitfield.h>
0008 #include <linux/clk.h>
0009 #include <linux/delay.h>
0010 #include <linux/io.h>
0011 #include <linux/media-bus-format.h>
0012 #include <linux/module.h>
0013 #include <linux/of.h>
0014 #include <linux/of_graph.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/pm_runtime.h>
0017 
0018 #include <drm/drm_atomic_state_helper.h>
0019 #include <drm/drm_bridge.h>
0020 #include <drm/drm_print.h>
0021 
0022 #define PC_CTRL_REG         0x0
0023 #define  PC_COMBINE_ENABLE      BIT(0)
0024 #define  PC_DISP_BYPASS(n)      BIT(1 + 21 * (n))
0025 #define  PC_DISP_HSYNC_POLARITY(n)  BIT(2 + 11 * (n))
0026 #define  PC_DISP_HSYNC_POLARITY_POS(n)  DISP_HSYNC_POLARITY(n)
0027 #define  PC_DISP_VSYNC_POLARITY(n)  BIT(3 + 11 * (n))
0028 #define  PC_DISP_VSYNC_POLARITY_POS(n)  DISP_VSYNC_POLARITY(n)
0029 #define  PC_DISP_DVALID_POLARITY(n) BIT(4 + 11 * (n))
0030 #define  PC_DISP_DVALID_POLARITY_POS(n) DISP_DVALID_POLARITY(n)
0031 #define  PC_VSYNC_MASK_ENABLE       BIT(5)
0032 #define  PC_SKIP_MODE           BIT(6)
0033 #define  PC_SKIP_NUMBER_MASK        GENMASK(12, 7)
0034 #define  PC_SKIP_NUMBER(n)      FIELD_PREP(PC_SKIP_NUMBER_MASK, (n))
0035 #define  PC_DISP0_PIX_DATA_FORMAT_MASK  GENMASK(18, 16)
0036 #define  PC_DISP0_PIX_DATA_FORMAT(fmt)  \
0037                 FIELD_PREP(PC_DISP0_PIX_DATA_FORMAT_MASK, (fmt))
0038 #define  PC_DISP1_PIX_DATA_FORMAT_MASK  GENMASK(21, 19)
0039 #define  PC_DISP1_PIX_DATA_FORMAT(fmt)  \
0040                 FIELD_PREP(PC_DISP1_PIX_DATA_FORMAT_MASK, (fmt))
0041 
0042 #define PC_SW_RESET_REG         0x20
0043 #define  PC_SW_RESET_N          BIT(0)
0044 #define  PC_DISP_SW_RESET_N(n)      BIT(1 + (n))
0045 #define  PC_FULL_RESET_N        (PC_SW_RESET_N |        \
0046                      PC_DISP_SW_RESET_N(0) |    \
0047                      PC_DISP_SW_RESET_N(1))
0048 
0049 #define PC_REG_SET          0x4
0050 #define PC_REG_CLR          0x8
0051 
0052 #define DRIVER_NAME         "imx8qxp-pixel-combiner"
0053 
0054 enum imx8qxp_pc_pix_data_format {
0055     RGB,
0056     YUV444,
0057     YUV422,
0058     SPLIT_RGB,
0059 };
0060 
0061 struct imx8qxp_pc_channel {
0062     struct drm_bridge bridge;
0063     struct drm_bridge *next_bridge;
0064     struct imx8qxp_pc *pc;
0065     unsigned int stream_id;
0066     bool is_available;
0067 };
0068 
0069 struct imx8qxp_pc {
0070     struct device *dev;
0071     struct imx8qxp_pc_channel ch[2];
0072     struct clk *clk_apb;
0073     void __iomem *base;
0074 };
0075 
0076 static inline u32 imx8qxp_pc_read(struct imx8qxp_pc *pc, unsigned int offset)
0077 {
0078     return readl(pc->base + offset);
0079 }
0080 
0081 static inline void
0082 imx8qxp_pc_write(struct imx8qxp_pc *pc, unsigned int offset, u32 value)
0083 {
0084     writel(value, pc->base + offset);
0085 }
0086 
0087 static inline void
0088 imx8qxp_pc_write_set(struct imx8qxp_pc *pc, unsigned int offset, u32 value)
0089 {
0090     imx8qxp_pc_write(pc, offset + PC_REG_SET, value);
0091 }
0092 
0093 static inline void
0094 imx8qxp_pc_write_clr(struct imx8qxp_pc *pc, unsigned int offset, u32 value)
0095 {
0096     imx8qxp_pc_write(pc, offset + PC_REG_CLR, value);
0097 }
0098 
0099 static enum drm_mode_status
0100 imx8qxp_pc_bridge_mode_valid(struct drm_bridge *bridge,
0101                  const struct drm_display_info *info,
0102                  const struct drm_display_mode *mode)
0103 {
0104     if (mode->hdisplay > 2560)
0105         return MODE_BAD_HVALUE;
0106 
0107     return MODE_OK;
0108 }
0109 
0110 static int imx8qxp_pc_bridge_attach(struct drm_bridge *bridge,
0111                     enum drm_bridge_attach_flags flags)
0112 {
0113     struct imx8qxp_pc_channel *ch = bridge->driver_private;
0114     struct imx8qxp_pc *pc = ch->pc;
0115 
0116     if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
0117         DRM_DEV_ERROR(pc->dev,
0118                   "do not support creating a drm_connector\n");
0119         return -EINVAL;
0120     }
0121 
0122     if (!bridge->encoder) {
0123         DRM_DEV_ERROR(pc->dev, "missing encoder\n");
0124         return -ENODEV;
0125     }
0126 
0127     return drm_bridge_attach(bridge->encoder,
0128                  ch->next_bridge, bridge,
0129                  DRM_BRIDGE_ATTACH_NO_CONNECTOR);
0130 }
0131 
0132 static void
0133 imx8qxp_pc_bridge_mode_set(struct drm_bridge *bridge,
0134                const struct drm_display_mode *mode,
0135                const struct drm_display_mode *adjusted_mode)
0136 {
0137     struct imx8qxp_pc_channel *ch = bridge->driver_private;
0138     struct imx8qxp_pc *pc = ch->pc;
0139     u32 val;
0140     int ret;
0141 
0142     ret = pm_runtime_get_sync(pc->dev);
0143     if (ret < 0)
0144         DRM_DEV_ERROR(pc->dev,
0145                   "failed to get runtime PM sync: %d\n", ret);
0146 
0147     ret = clk_prepare_enable(pc->clk_apb);
0148     if (ret)
0149         DRM_DEV_ERROR(pc->dev, "%s: failed to enable apb clock: %d\n",
0150                   __func__,  ret);
0151 
0152     /* HSYNC to pixel link is active low. */
0153     imx8qxp_pc_write_clr(pc, PC_CTRL_REG,
0154                  PC_DISP_HSYNC_POLARITY(ch->stream_id));
0155 
0156     /* VSYNC to pixel link is active low. */
0157     imx8qxp_pc_write_clr(pc, PC_CTRL_REG,
0158                  PC_DISP_VSYNC_POLARITY(ch->stream_id));
0159 
0160     /* Data enable to pixel link is active high. */
0161     imx8qxp_pc_write_set(pc, PC_CTRL_REG,
0162                  PC_DISP_DVALID_POLARITY(ch->stream_id));
0163 
0164     /* Mask the first frame output which may be incomplete. */
0165     imx8qxp_pc_write_set(pc, PC_CTRL_REG, PC_VSYNC_MASK_ENABLE);
0166 
0167     /* Only support RGB currently. */
0168     val = imx8qxp_pc_read(pc, PC_CTRL_REG);
0169     if (ch->stream_id == 0) {
0170         val &= ~PC_DISP0_PIX_DATA_FORMAT_MASK;
0171         val |= PC_DISP0_PIX_DATA_FORMAT(RGB);
0172     } else {
0173         val &= ~PC_DISP1_PIX_DATA_FORMAT_MASK;
0174         val |= PC_DISP1_PIX_DATA_FORMAT(RGB);
0175     }
0176     imx8qxp_pc_write(pc, PC_CTRL_REG, val);
0177 
0178     /* Only support bypass mode currently. */
0179     imx8qxp_pc_write_set(pc, PC_CTRL_REG, PC_DISP_BYPASS(ch->stream_id));
0180 
0181     clk_disable_unprepare(pc->clk_apb);
0182 }
0183 
0184 static void
0185 imx8qxp_pc_bridge_atomic_disable(struct drm_bridge *bridge,
0186                  struct drm_bridge_state *old_bridge_state)
0187 {
0188     struct imx8qxp_pc_channel *ch = bridge->driver_private;
0189     struct imx8qxp_pc *pc = ch->pc;
0190     int ret;
0191 
0192     ret = pm_runtime_put(pc->dev);
0193     if (ret < 0)
0194         DRM_DEV_ERROR(pc->dev, "failed to put runtime PM: %d\n", ret);
0195 }
0196 
0197 static const u32 imx8qxp_pc_bus_output_fmts[] = {
0198     MEDIA_BUS_FMT_RGB888_1X36_CPADLO,
0199     MEDIA_BUS_FMT_RGB666_1X36_CPADLO,
0200 };
0201 
0202 static bool imx8qxp_pc_bus_output_fmt_supported(u32 fmt)
0203 {
0204     int i;
0205 
0206     for (i = 0; i < ARRAY_SIZE(imx8qxp_pc_bus_output_fmts); i++) {
0207         if (imx8qxp_pc_bus_output_fmts[i] == fmt)
0208             return true;
0209     }
0210 
0211     return false;
0212 }
0213 
0214 static u32 *
0215 imx8qxp_pc_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
0216                         struct drm_bridge_state *bridge_state,
0217                         struct drm_crtc_state *crtc_state,
0218                         struct drm_connector_state *conn_state,
0219                         u32 output_fmt,
0220                         unsigned int *num_input_fmts)
0221 {
0222     u32 *input_fmts;
0223 
0224     if (!imx8qxp_pc_bus_output_fmt_supported(output_fmt))
0225         return NULL;
0226 
0227     *num_input_fmts = 1;
0228 
0229     input_fmts = kmalloc(sizeof(*input_fmts), GFP_KERNEL);
0230     if (!input_fmts)
0231         return NULL;
0232 
0233     switch (output_fmt) {
0234     case MEDIA_BUS_FMT_RGB888_1X36_CPADLO:
0235         input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X30_CPADLO;
0236         break;
0237     case MEDIA_BUS_FMT_RGB666_1X36_CPADLO:
0238         input_fmts[0] = MEDIA_BUS_FMT_RGB666_1X30_CPADLO;
0239         break;
0240     default:
0241         kfree(input_fmts);
0242         input_fmts = NULL;
0243         break;
0244     }
0245 
0246     return input_fmts;
0247 }
0248 
0249 static u32 *
0250 imx8qxp_pc_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
0251                          struct drm_bridge_state *bridge_state,
0252                          struct drm_crtc_state *crtc_state,
0253                          struct drm_connector_state *conn_state,
0254                          unsigned int *num_output_fmts)
0255 {
0256     *num_output_fmts = ARRAY_SIZE(imx8qxp_pc_bus_output_fmts);
0257     return kmemdup(imx8qxp_pc_bus_output_fmts,
0258             sizeof(imx8qxp_pc_bus_output_fmts), GFP_KERNEL);
0259 }
0260 
0261 static const struct drm_bridge_funcs imx8qxp_pc_bridge_funcs = {
0262     .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
0263     .atomic_destroy_state   = drm_atomic_helper_bridge_destroy_state,
0264     .atomic_reset       = drm_atomic_helper_bridge_reset,
0265     .mode_valid     = imx8qxp_pc_bridge_mode_valid,
0266     .attach         = imx8qxp_pc_bridge_attach,
0267     .mode_set       = imx8qxp_pc_bridge_mode_set,
0268     .atomic_disable     = imx8qxp_pc_bridge_atomic_disable,
0269     .atomic_get_input_bus_fmts =
0270                 imx8qxp_pc_bridge_atomic_get_input_bus_fmts,
0271     .atomic_get_output_bus_fmts =
0272                 imx8qxp_pc_bridge_atomic_get_output_bus_fmts,
0273 };
0274 
0275 static int imx8qxp_pc_bridge_probe(struct platform_device *pdev)
0276 {
0277     struct imx8qxp_pc *pc;
0278     struct imx8qxp_pc_channel *ch;
0279     struct device *dev = &pdev->dev;
0280     struct device_node *np = dev->of_node;
0281     struct device_node *child, *remote;
0282     u32 i;
0283     int ret;
0284 
0285     pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL);
0286     if (!pc)
0287         return -ENOMEM;
0288 
0289     pc->base = devm_platform_ioremap_resource(pdev, 0);
0290     if (IS_ERR(pc->base))
0291         return PTR_ERR(pc->base);
0292 
0293     pc->dev = dev;
0294 
0295     pc->clk_apb = devm_clk_get(dev, "apb");
0296     if (IS_ERR(pc->clk_apb)) {
0297         ret = PTR_ERR(pc->clk_apb);
0298         if (ret != -EPROBE_DEFER)
0299             DRM_DEV_ERROR(dev, "failed to get apb clock: %d\n", ret);
0300         return ret;
0301     }
0302 
0303     platform_set_drvdata(pdev, pc);
0304     pm_runtime_enable(dev);
0305 
0306     for_each_available_child_of_node(np, child) {
0307         ret = of_property_read_u32(child, "reg", &i);
0308         if (ret || i > 1) {
0309             ret = -EINVAL;
0310             DRM_DEV_ERROR(dev,
0311                       "invalid channel(%u) node address\n", i);
0312             goto free_child;
0313         }
0314 
0315         ch = &pc->ch[i];
0316         ch->pc = pc;
0317         ch->stream_id = i;
0318 
0319         remote = of_graph_get_remote_node(child, 1, 0);
0320         if (!remote) {
0321             ret = -ENODEV;
0322             DRM_DEV_ERROR(dev,
0323                       "channel%u failed to get port1's remote node: %d\n",
0324                       i, ret);
0325             goto free_child;
0326         }
0327 
0328         ch->next_bridge = of_drm_find_bridge(remote);
0329         if (!ch->next_bridge) {
0330             of_node_put(remote);
0331             ret = -EPROBE_DEFER;
0332             DRM_DEV_DEBUG_DRIVER(dev,
0333                          "channel%u failed to find next bridge: %d\n",
0334                          i, ret);
0335             goto free_child;
0336         }
0337 
0338         of_node_put(remote);
0339 
0340         ch->bridge.driver_private = ch;
0341         ch->bridge.funcs = &imx8qxp_pc_bridge_funcs;
0342         ch->bridge.of_node = child;
0343         ch->is_available = true;
0344 
0345         drm_bridge_add(&ch->bridge);
0346     }
0347 
0348     return 0;
0349 
0350 free_child:
0351     of_node_put(child);
0352 
0353     if (i == 1 && pc->ch[0].next_bridge)
0354         drm_bridge_remove(&pc->ch[0].bridge);
0355 
0356     pm_runtime_disable(dev);
0357     return ret;
0358 }
0359 
0360 static int imx8qxp_pc_bridge_remove(struct platform_device *pdev)
0361 {
0362     struct imx8qxp_pc *pc = platform_get_drvdata(pdev);
0363     struct imx8qxp_pc_channel *ch;
0364     int i;
0365 
0366     for (i = 0; i < 2; i++) {
0367         ch = &pc->ch[i];
0368 
0369         if (!ch->is_available)
0370             continue;
0371 
0372         drm_bridge_remove(&ch->bridge);
0373         ch->is_available = false;
0374     }
0375 
0376     pm_runtime_disable(&pdev->dev);
0377 
0378     return 0;
0379 }
0380 
0381 static int __maybe_unused imx8qxp_pc_runtime_suspend(struct device *dev)
0382 {
0383     struct platform_device *pdev = to_platform_device(dev);
0384     struct imx8qxp_pc *pc = platform_get_drvdata(pdev);
0385     int ret;
0386 
0387     ret = clk_prepare_enable(pc->clk_apb);
0388     if (ret)
0389         DRM_DEV_ERROR(pc->dev, "%s: failed to enable apb clock: %d\n",
0390                   __func__,  ret);
0391 
0392     /* Disable pixel combiner by full reset. */
0393     imx8qxp_pc_write_clr(pc, PC_SW_RESET_REG, PC_FULL_RESET_N);
0394 
0395     clk_disable_unprepare(pc->clk_apb);
0396 
0397     /* Ensure the reset takes effect. */
0398     usleep_range(10, 20);
0399 
0400     return ret;
0401 }
0402 
0403 static int __maybe_unused imx8qxp_pc_runtime_resume(struct device *dev)
0404 {
0405     struct platform_device *pdev = to_platform_device(dev);
0406     struct imx8qxp_pc *pc = platform_get_drvdata(pdev);
0407     int ret;
0408 
0409     ret = clk_prepare_enable(pc->clk_apb);
0410     if (ret) {
0411         DRM_DEV_ERROR(pc->dev, "%s: failed to enable apb clock: %d\n",
0412                   __func__, ret);
0413         return ret;
0414     }
0415 
0416     /* out of reset */
0417     imx8qxp_pc_write_set(pc, PC_SW_RESET_REG, PC_FULL_RESET_N);
0418 
0419     clk_disable_unprepare(pc->clk_apb);
0420 
0421     return ret;
0422 }
0423 
0424 static const struct dev_pm_ops imx8qxp_pc_pm_ops = {
0425     SET_RUNTIME_PM_OPS(imx8qxp_pc_runtime_suspend,
0426                imx8qxp_pc_runtime_resume, NULL)
0427 };
0428 
0429 static const struct of_device_id imx8qxp_pc_dt_ids[] = {
0430     { .compatible = "fsl,imx8qm-pixel-combiner", },
0431     { .compatible = "fsl,imx8qxp-pixel-combiner", },
0432     { /* sentinel */ }
0433 };
0434 MODULE_DEVICE_TABLE(of, imx8qxp_pc_dt_ids);
0435 
0436 static struct platform_driver imx8qxp_pc_bridge_driver = {
0437     .probe  = imx8qxp_pc_bridge_probe,
0438     .remove = imx8qxp_pc_bridge_remove,
0439     .driver = {
0440         .pm = &imx8qxp_pc_pm_ops,
0441         .name = DRIVER_NAME,
0442         .of_match_table = imx8qxp_pc_dt_ids,
0443     },
0444 };
0445 module_platform_driver(imx8qxp_pc_bridge_driver);
0446 
0447 MODULE_DESCRIPTION("i.MX8QM/QXP pixel combiner bridge driver");
0448 MODULE_AUTHOR("Liu Ying <victor.liu@nxp.com>");
0449 MODULE_LICENSE("GPL v2");
0450 MODULE_ALIAS("platform:" DRIVER_NAME);