0001
0002
0003
0004
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
0153 imx8qxp_pc_write_clr(pc, PC_CTRL_REG,
0154 PC_DISP_HSYNC_POLARITY(ch->stream_id));
0155
0156
0157 imx8qxp_pc_write_clr(pc, PC_CTRL_REG,
0158 PC_DISP_VSYNC_POLARITY(ch->stream_id));
0159
0160
0161 imx8qxp_pc_write_set(pc, PC_CTRL_REG,
0162 PC_DISP_DVALID_POLARITY(ch->stream_id));
0163
0164
0165 imx8qxp_pc_write_set(pc, PC_CTRL_REG, PC_VSYNC_MASK_ENABLE);
0166
0167
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
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
0393 imx8qxp_pc_write_clr(pc, PC_SW_RESET_REG, PC_FULL_RESET_N);
0394
0395 clk_disable_unprepare(pc->clk_apb);
0396
0397
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
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 { }
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);