linux/drivers/gpu/drm/imx/parallel-display.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * i.MX drm driver - parallel display implementation
   4 *
   5 * Copyright (C) 2012 Sascha Hauer, Pengutronix
   6 */
   7
   8#include <linux/component.h>
   9#include <linux/module.h>
  10#include <linux/platform_device.h>
  11#include <linux/videodev2.h>
  12
  13#include <video/of_display_timing.h>
  14
  15#include <drm/drm_atomic_helper.h>
  16#include <drm/drm_bridge.h>
  17#include <drm/drm_fb_helper.h>
  18#include <drm/drm_of.h>
  19#include <drm/drm_panel.h>
  20#include <drm/drm_probe_helper.h>
  21
  22#include "imx-drm.h"
  23
  24struct imx_parallel_display {
  25        struct drm_connector connector;
  26        struct drm_encoder encoder;
  27        struct drm_bridge bridge;
  28        struct device *dev;
  29        void *edid;
  30        int edid_len;
  31        u32 bus_format;
  32        u32 bus_flags;
  33        struct drm_display_mode mode;
  34        struct drm_panel *panel;
  35        struct drm_bridge *next_bridge;
  36};
  37
  38static inline struct imx_parallel_display *con_to_imxpd(struct drm_connector *c)
  39{
  40        return container_of(c, struct imx_parallel_display, connector);
  41}
  42
  43static inline struct imx_parallel_display *enc_to_imxpd(struct drm_encoder *e)
  44{
  45        return container_of(e, struct imx_parallel_display, encoder);
  46}
  47
  48static inline struct imx_parallel_display *bridge_to_imxpd(struct drm_bridge *b)
  49{
  50        return container_of(b, struct imx_parallel_display, bridge);
  51}
  52
  53static int imx_pd_connector_get_modes(struct drm_connector *connector)
  54{
  55        struct imx_parallel_display *imxpd = con_to_imxpd(connector);
  56        struct device_node *np = imxpd->dev->of_node;
  57        int num_modes;
  58
  59        num_modes = drm_panel_get_modes(imxpd->panel, connector);
  60        if (num_modes > 0)
  61                return num_modes;
  62
  63        if (imxpd->edid) {
  64                drm_connector_update_edid_property(connector, imxpd->edid);
  65                num_modes = drm_add_edid_modes(connector, imxpd->edid);
  66        }
  67
  68        if (np) {
  69                struct drm_display_mode *mode = drm_mode_create(connector->dev);
  70                int ret;
  71
  72                if (!mode)
  73                        return -EINVAL;
  74
  75                ret = of_get_drm_display_mode(np, &imxpd->mode,
  76                                              &imxpd->bus_flags,
  77                                              OF_USE_NATIVE_MODE);
  78                if (ret)
  79                        return ret;
  80
  81                drm_mode_copy(mode, &imxpd->mode);
  82                mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
  83                drm_mode_probed_add(connector, mode);
  84                num_modes++;
  85        }
  86
  87        return num_modes;
  88}
  89
  90static struct drm_encoder *imx_pd_connector_best_encoder(
  91                struct drm_connector *connector)
  92{
  93        struct imx_parallel_display *imxpd = con_to_imxpd(connector);
  94
  95        return &imxpd->encoder;
  96}
  97
  98static void imx_pd_bridge_enable(struct drm_bridge *bridge)
  99{
 100        struct imx_parallel_display *imxpd = bridge_to_imxpd(bridge);
 101
 102        drm_panel_prepare(imxpd->panel);
 103        drm_panel_enable(imxpd->panel);
 104}
 105
 106static void imx_pd_bridge_disable(struct drm_bridge *bridge)
 107{
 108        struct imx_parallel_display *imxpd = bridge_to_imxpd(bridge);
 109
 110        drm_panel_disable(imxpd->panel);
 111        drm_panel_unprepare(imxpd->panel);
 112}
 113
 114static const u32 imx_pd_bus_fmts[] = {
 115        MEDIA_BUS_FMT_RGB888_1X24,
 116        MEDIA_BUS_FMT_BGR888_1X24,
 117        MEDIA_BUS_FMT_GBR888_1X24,
 118        MEDIA_BUS_FMT_RGB666_1X18,
 119        MEDIA_BUS_FMT_RGB666_1X24_CPADHI,
 120        MEDIA_BUS_FMT_RGB565_1X16,
 121};
 122
 123static u32 *
 124imx_pd_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
 125                                         struct drm_bridge_state *bridge_state,
 126                                         struct drm_crtc_state *crtc_state,
 127                                         struct drm_connector_state *conn_state,
 128                                         unsigned int *num_output_fmts)
 129{
 130        struct drm_display_info *di = &conn_state->connector->display_info;
 131        struct imx_parallel_display *imxpd = bridge_to_imxpd(bridge);
 132        u32 *output_fmts;
 133
 134        if (!imxpd->bus_format && !di->num_bus_formats) {
 135                *num_output_fmts = ARRAY_SIZE(imx_pd_bus_fmts);
 136                return kmemdup(imx_pd_bus_fmts, sizeof(imx_pd_bus_fmts),
 137                               GFP_KERNEL);
 138        }
 139
 140        *num_output_fmts = 1;
 141        output_fmts = kmalloc(sizeof(*output_fmts), GFP_KERNEL);
 142        if (!output_fmts)
 143                return NULL;
 144
 145        if (!imxpd->bus_format && di->num_bus_formats)
 146                output_fmts[0] = di->bus_formats[0];
 147        else
 148                output_fmts[0] = imxpd->bus_format;
 149
 150        return output_fmts;
 151}
 152
 153static bool imx_pd_format_supported(u32 output_fmt)
 154{
 155        unsigned int i;
 156
 157        for (i = 0; i < ARRAY_SIZE(imx_pd_bus_fmts); i++) {
 158                if (imx_pd_bus_fmts[i] == output_fmt)
 159                        return true;
 160        }
 161
 162        return false;
 163}
 164
 165static u32 *
 166imx_pd_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
 167                                        struct drm_bridge_state *bridge_state,
 168                                        struct drm_crtc_state *crtc_state,
 169                                        struct drm_connector_state *conn_state,
 170                                        u32 output_fmt,
 171                                        unsigned int *num_input_fmts)
 172{
 173        struct imx_parallel_display *imxpd = bridge_to_imxpd(bridge);
 174        u32 *input_fmts;
 175
 176        /*
 177         * If the next bridge does not support bus format negotiation, let's
 178         * use the static bus format definition (imxpd->bus_format) if it's
 179         * specified, RGB888 when it's not.
 180         */
 181        if (output_fmt == MEDIA_BUS_FMT_FIXED)
 182                output_fmt = imxpd->bus_format ? : MEDIA_BUS_FMT_RGB888_1X24;
 183
 184        /* Now make sure the requested output format is supported. */
 185        if ((imxpd->bus_format && imxpd->bus_format != output_fmt) ||
 186            !imx_pd_format_supported(output_fmt)) {
 187                *num_input_fmts = 0;
 188                return NULL;
 189        }
 190
 191        *num_input_fmts = 1;
 192        input_fmts = kmalloc(sizeof(*input_fmts), GFP_KERNEL);
 193        if (!input_fmts)
 194                return NULL;
 195
 196        input_fmts[0] = output_fmt;
 197        return input_fmts;
 198}
 199
 200static int imx_pd_bridge_atomic_check(struct drm_bridge *bridge,
 201                                      struct drm_bridge_state *bridge_state,
 202                                      struct drm_crtc_state *crtc_state,
 203                                      struct drm_connector_state *conn_state)
 204{
 205        struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state);
 206        struct drm_display_info *di = &conn_state->connector->display_info;
 207        struct imx_parallel_display *imxpd = bridge_to_imxpd(bridge);
 208        struct drm_bridge_state *next_bridge_state = NULL;
 209        struct drm_bridge *next_bridge;
 210        u32 bus_flags, bus_fmt;
 211
 212        next_bridge = drm_bridge_get_next_bridge(bridge);
 213        if (next_bridge)
 214                next_bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state,
 215                                                                    next_bridge);
 216
 217        if (next_bridge_state)
 218                bus_flags = next_bridge_state->input_bus_cfg.flags;
 219        else if (!imxpd->bus_format && di->num_bus_formats)
 220                bus_flags = di->bus_flags;
 221        else
 222                bus_flags = imxpd->bus_flags;
 223
 224        bus_fmt = bridge_state->input_bus_cfg.format;
 225        if (!imx_pd_format_supported(bus_fmt))
 226                return -EINVAL;
 227
 228        if (bus_flags &
 229            ~(DRM_BUS_FLAG_DE_LOW | DRM_BUS_FLAG_DE_HIGH |
 230              DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE |
 231              DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)) {
 232                dev_warn(imxpd->dev, "invalid bus_flags (%x)\n", bus_flags);
 233                return -EINVAL;
 234        }
 235
 236        bridge_state->output_bus_cfg.flags = bus_flags;
 237        bridge_state->input_bus_cfg.flags = bus_flags;
 238        imx_crtc_state->bus_flags = bus_flags;
 239        imx_crtc_state->bus_format = bridge_state->input_bus_cfg.format;
 240        imx_crtc_state->di_hsync_pin = 2;
 241        imx_crtc_state->di_vsync_pin = 3;
 242
 243        return 0;
 244}
 245
 246static const struct drm_connector_funcs imx_pd_connector_funcs = {
 247        .fill_modes = drm_helper_probe_single_connector_modes,
 248        .destroy = imx_drm_connector_destroy,
 249        .reset = drm_atomic_helper_connector_reset,
 250        .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 251        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 252};
 253
 254static const struct drm_connector_helper_funcs imx_pd_connector_helper_funcs = {
 255        .get_modes = imx_pd_connector_get_modes,
 256        .best_encoder = imx_pd_connector_best_encoder,
 257};
 258
 259static const struct drm_encoder_funcs imx_pd_encoder_funcs = {
 260        .destroy = imx_drm_encoder_destroy,
 261};
 262
 263static const struct drm_bridge_funcs imx_pd_bridge_funcs = {
 264        .enable = imx_pd_bridge_enable,
 265        .disable = imx_pd_bridge_disable,
 266        .atomic_reset = drm_atomic_helper_bridge_reset,
 267        .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
 268        .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
 269        .atomic_check = imx_pd_bridge_atomic_check,
 270        .atomic_get_input_bus_fmts = imx_pd_bridge_atomic_get_input_bus_fmts,
 271        .atomic_get_output_bus_fmts = imx_pd_bridge_atomic_get_output_bus_fmts,
 272};
 273
 274static int imx_pd_register(struct drm_device *drm,
 275        struct imx_parallel_display *imxpd)
 276{
 277        struct drm_encoder *encoder = &imxpd->encoder;
 278        int ret;
 279
 280        ret = imx_drm_encoder_parse_of(drm, encoder, imxpd->dev->of_node);
 281        if (ret)
 282                return ret;
 283
 284        /* set the connector's dpms to OFF so that
 285         * drm_helper_connector_dpms() won't return
 286         * immediately since the current state is ON
 287         * at this point.
 288         */
 289        imxpd->connector.dpms = DRM_MODE_DPMS_OFF;
 290
 291        drm_encoder_init(drm, encoder, &imx_pd_encoder_funcs,
 292                         DRM_MODE_ENCODER_NONE, NULL);
 293
 294        imxpd->bridge.funcs = &imx_pd_bridge_funcs;
 295        drm_bridge_attach(encoder, &imxpd->bridge, NULL, 0);
 296
 297        if (!imxpd->next_bridge) {
 298                drm_connector_helper_add(&imxpd->connector,
 299                                &imx_pd_connector_helper_funcs);
 300                drm_connector_init(drm, &imxpd->connector,
 301                                   &imx_pd_connector_funcs,
 302                                   DRM_MODE_CONNECTOR_DPI);
 303        }
 304
 305        if (imxpd->panel)
 306                drm_panel_attach(imxpd->panel, &imxpd->connector);
 307
 308        if (imxpd->next_bridge) {
 309                ret = drm_bridge_attach(encoder, imxpd->next_bridge,
 310                                        &imxpd->bridge, 0);
 311                if (ret < 0) {
 312                        dev_err(imxpd->dev, "failed to attach bridge: %d\n",
 313                                ret);
 314                        return ret;
 315                }
 316        } else {
 317                drm_connector_attach_encoder(&imxpd->connector, encoder);
 318        }
 319
 320        return 0;
 321}
 322
 323static int imx_pd_bind(struct device *dev, struct device *master, void *data)
 324{
 325        struct drm_device *drm = data;
 326        struct device_node *np = dev->of_node;
 327        const u8 *edidp;
 328        struct imx_parallel_display *imxpd;
 329        int ret;
 330        u32 bus_format = 0;
 331        const char *fmt;
 332
 333        imxpd = devm_kzalloc(dev, sizeof(*imxpd), GFP_KERNEL);
 334        if (!imxpd)
 335                return -ENOMEM;
 336
 337        edidp = of_get_property(np, "edid", &imxpd->edid_len);
 338        if (edidp)
 339                imxpd->edid = kmemdup(edidp, imxpd->edid_len, GFP_KERNEL);
 340
 341        ret = of_property_read_string(np, "interface-pix-fmt", &fmt);
 342        if (!ret) {
 343                if (!strcmp(fmt, "rgb24"))
 344                        bus_format = MEDIA_BUS_FMT_RGB888_1X24;
 345                else if (!strcmp(fmt, "rgb565"))
 346                        bus_format = MEDIA_BUS_FMT_RGB565_1X16;
 347                else if (!strcmp(fmt, "bgr666"))
 348                        bus_format = MEDIA_BUS_FMT_RGB666_1X18;
 349                else if (!strcmp(fmt, "lvds666"))
 350                        bus_format = MEDIA_BUS_FMT_RGB666_1X24_CPADHI;
 351        }
 352        imxpd->bus_format = bus_format;
 353
 354        /* port@1 is the output port */
 355        ret = drm_of_find_panel_or_bridge(np, 1, 0, &imxpd->panel,
 356                                          &imxpd->next_bridge);
 357        if (ret && ret != -ENODEV)
 358                return ret;
 359
 360        imxpd->dev = dev;
 361
 362        ret = imx_pd_register(drm, imxpd);
 363        if (ret)
 364                return ret;
 365
 366        dev_set_drvdata(dev, imxpd);
 367
 368        return 0;
 369}
 370
 371static void imx_pd_unbind(struct device *dev, struct device *master,
 372        void *data)
 373{
 374        struct imx_parallel_display *imxpd = dev_get_drvdata(dev);
 375
 376        if (imxpd->panel)
 377                drm_panel_detach(imxpd->panel);
 378
 379        kfree(imxpd->edid);
 380}
 381
 382static const struct component_ops imx_pd_ops = {
 383        .bind   = imx_pd_bind,
 384        .unbind = imx_pd_unbind,
 385};
 386
 387static int imx_pd_probe(struct platform_device *pdev)
 388{
 389        return component_add(&pdev->dev, &imx_pd_ops);
 390}
 391
 392static int imx_pd_remove(struct platform_device *pdev)
 393{
 394        component_del(&pdev->dev, &imx_pd_ops);
 395
 396        return 0;
 397}
 398
 399static const struct of_device_id imx_pd_dt_ids[] = {
 400        { .compatible = "fsl,imx-parallel-display", },
 401        { /* sentinel */ }
 402};
 403MODULE_DEVICE_TABLE(of, imx_pd_dt_ids);
 404
 405static struct platform_driver imx_pd_driver = {
 406        .probe          = imx_pd_probe,
 407        .remove         = imx_pd_remove,
 408        .driver         = {
 409                .of_match_table = imx_pd_dt_ids,
 410                .name   = "imx-parallel-display",
 411        },
 412};
 413
 414module_platform_driver(imx_pd_driver);
 415
 416MODULE_DESCRIPTION("i.MX parallel display driver");
 417MODULE_AUTHOR("Sascha Hauer, Pengutronix");
 418MODULE_LICENSE("GPL");
 419MODULE_ALIAS("platform:imx-parallel-display");
 420