Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * i.MX drm driver - parallel display implementation
0004  *
0005  * Copyright (C) 2012 Sascha Hauer, Pengutronix
0006  */
0007 
0008 #include <linux/component.h>
0009 #include <linux/media-bus-format.h>
0010 #include <linux/module.h>
0011 #include <linux/platform_device.h>
0012 #include <linux/videodev2.h>
0013 
0014 #include <video/of_display_timing.h>
0015 
0016 #include <drm/drm_atomic_helper.h>
0017 #include <drm/drm_bridge.h>
0018 #include <drm/drm_edid.h>
0019 #include <drm/drm_fb_helper.h>
0020 #include <drm/drm_managed.h>
0021 #include <drm/drm_of.h>
0022 #include <drm/drm_panel.h>
0023 #include <drm/drm_probe_helper.h>
0024 #include <drm/drm_simple_kms_helper.h>
0025 
0026 #include "imx-drm.h"
0027 
0028 struct imx_parallel_display_encoder {
0029     struct drm_connector connector;
0030     struct drm_encoder encoder;
0031     struct drm_bridge bridge;
0032     struct imx_parallel_display *pd;
0033 };
0034 
0035 struct imx_parallel_display {
0036     struct device *dev;
0037     void *edid;
0038     u32 bus_format;
0039     u32 bus_flags;
0040     struct drm_display_mode mode;
0041     struct drm_panel *panel;
0042     struct drm_bridge *next_bridge;
0043 };
0044 
0045 static inline struct imx_parallel_display *con_to_imxpd(struct drm_connector *c)
0046 {
0047     return container_of(c, struct imx_parallel_display_encoder, connector)->pd;
0048 }
0049 
0050 static inline struct imx_parallel_display *bridge_to_imxpd(struct drm_bridge *b)
0051 {
0052     return container_of(b, struct imx_parallel_display_encoder, bridge)->pd;
0053 }
0054 
0055 static int imx_pd_connector_get_modes(struct drm_connector *connector)
0056 {
0057     struct imx_parallel_display *imxpd = con_to_imxpd(connector);
0058     struct device_node *np = imxpd->dev->of_node;
0059     int num_modes;
0060 
0061     num_modes = drm_panel_get_modes(imxpd->panel, connector);
0062     if (num_modes > 0)
0063         return num_modes;
0064 
0065     if (imxpd->edid) {
0066         drm_connector_update_edid_property(connector, imxpd->edid);
0067         num_modes = drm_add_edid_modes(connector, imxpd->edid);
0068     }
0069 
0070     if (np) {
0071         struct drm_display_mode *mode = drm_mode_create(connector->dev);
0072         int ret;
0073 
0074         if (!mode)
0075             return -EINVAL;
0076 
0077         ret = of_get_drm_display_mode(np, &imxpd->mode,
0078                           &imxpd->bus_flags,
0079                           OF_USE_NATIVE_MODE);
0080         if (ret) {
0081             drm_mode_destroy(connector->dev, mode);
0082             return ret;
0083         }
0084 
0085         drm_mode_copy(mode, &imxpd->mode);
0086         mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
0087         drm_mode_probed_add(connector, mode);
0088         num_modes++;
0089     }
0090 
0091     return num_modes;
0092 }
0093 
0094 static void imx_pd_bridge_enable(struct drm_bridge *bridge)
0095 {
0096     struct imx_parallel_display *imxpd = bridge_to_imxpd(bridge);
0097 
0098     drm_panel_prepare(imxpd->panel);
0099     drm_panel_enable(imxpd->panel);
0100 }
0101 
0102 static void imx_pd_bridge_disable(struct drm_bridge *bridge)
0103 {
0104     struct imx_parallel_display *imxpd = bridge_to_imxpd(bridge);
0105 
0106     drm_panel_disable(imxpd->panel);
0107     drm_panel_unprepare(imxpd->panel);
0108 }
0109 
0110 static const u32 imx_pd_bus_fmts[] = {
0111     MEDIA_BUS_FMT_RGB888_1X24,
0112     MEDIA_BUS_FMT_BGR888_1X24,
0113     MEDIA_BUS_FMT_GBR888_1X24,
0114     MEDIA_BUS_FMT_RGB666_1X18,
0115     MEDIA_BUS_FMT_RGB666_1X24_CPADHI,
0116     MEDIA_BUS_FMT_RGB565_1X16,
0117 };
0118 
0119 static u32 *
0120 imx_pd_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
0121                      struct drm_bridge_state *bridge_state,
0122                      struct drm_crtc_state *crtc_state,
0123                      struct drm_connector_state *conn_state,
0124                      unsigned int *num_output_fmts)
0125 {
0126     struct drm_display_info *di = &conn_state->connector->display_info;
0127     struct imx_parallel_display *imxpd = bridge_to_imxpd(bridge);
0128     u32 *output_fmts;
0129 
0130     if (!imxpd->bus_format && !di->num_bus_formats) {
0131         *num_output_fmts = ARRAY_SIZE(imx_pd_bus_fmts);
0132         return kmemdup(imx_pd_bus_fmts, sizeof(imx_pd_bus_fmts),
0133                    GFP_KERNEL);
0134     }
0135 
0136     *num_output_fmts = 1;
0137     output_fmts = kmalloc(sizeof(*output_fmts), GFP_KERNEL);
0138     if (!output_fmts)
0139         return NULL;
0140 
0141     if (!imxpd->bus_format && di->num_bus_formats)
0142         output_fmts[0] = di->bus_formats[0];
0143     else
0144         output_fmts[0] = imxpd->bus_format;
0145 
0146     return output_fmts;
0147 }
0148 
0149 static bool imx_pd_format_supported(u32 output_fmt)
0150 {
0151     unsigned int i;
0152 
0153     for (i = 0; i < ARRAY_SIZE(imx_pd_bus_fmts); i++) {
0154         if (imx_pd_bus_fmts[i] == output_fmt)
0155             return true;
0156     }
0157 
0158     return false;
0159 }
0160 
0161 static u32 *
0162 imx_pd_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
0163                     struct drm_bridge_state *bridge_state,
0164                     struct drm_crtc_state *crtc_state,
0165                     struct drm_connector_state *conn_state,
0166                     u32 output_fmt,
0167                     unsigned int *num_input_fmts)
0168 {
0169     struct imx_parallel_display *imxpd = bridge_to_imxpd(bridge);
0170     u32 *input_fmts;
0171 
0172     /*
0173      * If the next bridge does not support bus format negotiation, let's
0174      * use the static bus format definition (imxpd->bus_format) if it's
0175      * specified, RGB888 when it's not.
0176      */
0177     if (output_fmt == MEDIA_BUS_FMT_FIXED)
0178         output_fmt = imxpd->bus_format ? : MEDIA_BUS_FMT_RGB888_1X24;
0179 
0180     /* Now make sure the requested output format is supported. */
0181     if ((imxpd->bus_format && imxpd->bus_format != output_fmt) ||
0182         !imx_pd_format_supported(output_fmt)) {
0183         *num_input_fmts = 0;
0184         return NULL;
0185     }
0186 
0187     *num_input_fmts = 1;
0188     input_fmts = kmalloc(sizeof(*input_fmts), GFP_KERNEL);
0189     if (!input_fmts)
0190         return NULL;
0191 
0192     input_fmts[0] = output_fmt;
0193     return input_fmts;
0194 }
0195 
0196 static int imx_pd_bridge_atomic_check(struct drm_bridge *bridge,
0197                       struct drm_bridge_state *bridge_state,
0198                       struct drm_crtc_state *crtc_state,
0199                       struct drm_connector_state *conn_state)
0200 {
0201     struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state);
0202     struct drm_display_info *di = &conn_state->connector->display_info;
0203     struct imx_parallel_display *imxpd = bridge_to_imxpd(bridge);
0204     struct drm_bridge_state *next_bridge_state = NULL;
0205     struct drm_bridge *next_bridge;
0206     u32 bus_flags, bus_fmt;
0207 
0208     next_bridge = drm_bridge_get_next_bridge(bridge);
0209     if (next_bridge)
0210         next_bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state,
0211                                     next_bridge);
0212 
0213     if (next_bridge_state)
0214         bus_flags = next_bridge_state->input_bus_cfg.flags;
0215     else if (di->num_bus_formats)
0216         bus_flags = di->bus_flags;
0217     else
0218         bus_flags = imxpd->bus_flags;
0219 
0220     bus_fmt = bridge_state->input_bus_cfg.format;
0221     if (!imx_pd_format_supported(bus_fmt))
0222         return -EINVAL;
0223 
0224     bridge_state->output_bus_cfg.flags = bus_flags;
0225     bridge_state->input_bus_cfg.flags = bus_flags;
0226     imx_crtc_state->bus_flags = bus_flags;
0227     imx_crtc_state->bus_format = bridge_state->input_bus_cfg.format;
0228     imx_crtc_state->di_hsync_pin = 2;
0229     imx_crtc_state->di_vsync_pin = 3;
0230 
0231     return 0;
0232 }
0233 
0234 static const struct drm_connector_funcs imx_pd_connector_funcs = {
0235     .fill_modes = drm_helper_probe_single_connector_modes,
0236     .destroy = imx_drm_connector_destroy,
0237     .reset = drm_atomic_helper_connector_reset,
0238     .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
0239     .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
0240 };
0241 
0242 static const struct drm_connector_helper_funcs imx_pd_connector_helper_funcs = {
0243     .get_modes = imx_pd_connector_get_modes,
0244 };
0245 
0246 static const struct drm_bridge_funcs imx_pd_bridge_funcs = {
0247     .enable = imx_pd_bridge_enable,
0248     .disable = imx_pd_bridge_disable,
0249     .atomic_reset = drm_atomic_helper_bridge_reset,
0250     .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
0251     .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
0252     .atomic_check = imx_pd_bridge_atomic_check,
0253     .atomic_get_input_bus_fmts = imx_pd_bridge_atomic_get_input_bus_fmts,
0254     .atomic_get_output_bus_fmts = imx_pd_bridge_atomic_get_output_bus_fmts,
0255 };
0256 
0257 static int imx_pd_bind(struct device *dev, struct device *master, void *data)
0258 {
0259     struct drm_device *drm = data;
0260     struct imx_parallel_display *imxpd = dev_get_drvdata(dev);
0261     struct imx_parallel_display_encoder *imxpd_encoder;
0262     struct drm_connector *connector;
0263     struct drm_encoder *encoder;
0264     struct drm_bridge *bridge;
0265     int ret;
0266 
0267     imxpd_encoder = drmm_simple_encoder_alloc(drm, struct imx_parallel_display_encoder,
0268                           encoder, DRM_MODE_ENCODER_NONE);
0269     if (IS_ERR(imxpd_encoder))
0270         return PTR_ERR(imxpd_encoder);
0271 
0272     imxpd_encoder->pd = imxpd;
0273     connector = &imxpd_encoder->connector;
0274     encoder = &imxpd_encoder->encoder;
0275     bridge = &imxpd_encoder->bridge;
0276 
0277     ret = imx_drm_encoder_parse_of(drm, encoder, imxpd->dev->of_node);
0278     if (ret)
0279         return ret;
0280 
0281     /* set the connector's dpms to OFF so that
0282      * drm_helper_connector_dpms() won't return
0283      * immediately since the current state is ON
0284      * at this point.
0285      */
0286     connector->dpms = DRM_MODE_DPMS_OFF;
0287 
0288     bridge->funcs = &imx_pd_bridge_funcs;
0289     drm_bridge_attach(encoder, bridge, NULL, 0);
0290 
0291     if (imxpd->next_bridge) {
0292         ret = drm_bridge_attach(encoder, imxpd->next_bridge, bridge, 0);
0293         if (ret < 0)
0294             return ret;
0295     } else {
0296         drm_connector_helper_add(connector,
0297                      &imx_pd_connector_helper_funcs);
0298         drm_connector_init(drm, connector, &imx_pd_connector_funcs,
0299                    DRM_MODE_CONNECTOR_DPI);
0300 
0301         drm_connector_attach_encoder(connector, encoder);
0302     }
0303 
0304     return 0;
0305 }
0306 
0307 static const struct component_ops imx_pd_ops = {
0308     .bind   = imx_pd_bind,
0309 };
0310 
0311 static int imx_pd_probe(struct platform_device *pdev)
0312 {
0313     struct device *dev = &pdev->dev;
0314     struct device_node *np = dev->of_node;
0315     const u8 *edidp;
0316     struct imx_parallel_display *imxpd;
0317     int edid_len;
0318     int ret;
0319     u32 bus_format = 0;
0320     const char *fmt;
0321 
0322     imxpd = devm_kzalloc(dev, sizeof(*imxpd), GFP_KERNEL);
0323     if (!imxpd)
0324         return -ENOMEM;
0325 
0326     /* port@1 is the output port */
0327     ret = drm_of_find_panel_or_bridge(np, 1, 0, &imxpd->panel,
0328                       &imxpd->next_bridge);
0329     if (ret && ret != -ENODEV)
0330         return ret;
0331 
0332     edidp = of_get_property(np, "edid", &edid_len);
0333     if (edidp)
0334         imxpd->edid = devm_kmemdup(dev, edidp, edid_len, GFP_KERNEL);
0335 
0336     ret = of_property_read_string(np, "interface-pix-fmt", &fmt);
0337     if (!ret) {
0338         if (!strcmp(fmt, "rgb24"))
0339             bus_format = MEDIA_BUS_FMT_RGB888_1X24;
0340         else if (!strcmp(fmt, "rgb565"))
0341             bus_format = MEDIA_BUS_FMT_RGB565_1X16;
0342         else if (!strcmp(fmt, "bgr666"))
0343             bus_format = MEDIA_BUS_FMT_RGB666_1X18;
0344         else if (!strcmp(fmt, "lvds666"))
0345             bus_format = MEDIA_BUS_FMT_RGB666_1X24_CPADHI;
0346     }
0347     imxpd->bus_format = bus_format;
0348 
0349     imxpd->dev = dev;
0350 
0351     platform_set_drvdata(pdev, imxpd);
0352 
0353     return component_add(dev, &imx_pd_ops);
0354 }
0355 
0356 static int imx_pd_remove(struct platform_device *pdev)
0357 {
0358     component_del(&pdev->dev, &imx_pd_ops);
0359 
0360     return 0;
0361 }
0362 
0363 static const struct of_device_id imx_pd_dt_ids[] = {
0364     { .compatible = "fsl,imx-parallel-display", },
0365     { /* sentinel */ }
0366 };
0367 MODULE_DEVICE_TABLE(of, imx_pd_dt_ids);
0368 
0369 static struct platform_driver imx_pd_driver = {
0370     .probe      = imx_pd_probe,
0371     .remove     = imx_pd_remove,
0372     .driver     = {
0373         .of_match_table = imx_pd_dt_ids,
0374         .name   = "imx-parallel-display",
0375     },
0376 };
0377 
0378 module_platform_driver(imx_pd_driver);
0379 
0380 MODULE_DESCRIPTION("i.MX parallel display driver");
0381 MODULE_AUTHOR("Sascha Hauer, Pengutronix");
0382 MODULE_LICENSE("GPL");
0383 MODULE_ALIAS("platform:imx-parallel-display");