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