linux/drivers/gpu/drm/imx/ipuv3-crtc.c
<<
>>
Prefs
   1/*
   2 * i.MX IPUv3 Graphics driver
   3 *
   4 * Copyright (C) 2011 Sascha Hauer, Pengutronix
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public License
   8 * as published by the Free Software Foundation; either version 2
   9 * of the License, or (at your option) any later version.
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 */
  15#include <linux/component.h>
  16#include <linux/module.h>
  17#include <linux/export.h>
  18#include <linux/device.h>
  19#include <linux/platform_device.h>
  20#include <drm/drmP.h>
  21#include <drm/drm_atomic.h>
  22#include <drm/drm_atomic_helper.h>
  23#include <drm/drm_crtc_helper.h>
  24#include <linux/clk.h>
  25#include <linux/errno.h>
  26#include <drm/drm_gem_cma_helper.h>
  27#include <drm/drm_fb_cma_helper.h>
  28
  29#include <video/imx-ipu-v3.h>
  30#include "imx-drm.h"
  31#include "ipuv3-plane.h"
  32
  33#define DRIVER_DESC             "i.MX IPUv3 Graphics"
  34
  35struct ipu_crtc {
  36        struct device           *dev;
  37        struct drm_crtc         base;
  38        struct imx_drm_crtc     *imx_crtc;
  39
  40        /* plane[0] is the full plane, plane[1] is the partial plane */
  41        struct ipu_plane        *plane[2];
  42
  43        struct ipu_dc           *dc;
  44        struct ipu_di           *di;
  45        int                     irq;
  46};
  47
  48static inline struct ipu_crtc *to_ipu_crtc(struct drm_crtc *crtc)
  49{
  50        return container_of(crtc, struct ipu_crtc, base);
  51}
  52
  53static void ipu_crtc_enable(struct drm_crtc *crtc)
  54{
  55        struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
  56        struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
  57
  58        ipu_dc_enable(ipu);
  59        ipu_dc_enable_channel(ipu_crtc->dc);
  60        ipu_di_enable(ipu_crtc->di);
  61}
  62
  63static void ipu_crtc_atomic_disable(struct drm_crtc *crtc,
  64                                    struct drm_crtc_state *old_crtc_state)
  65{
  66        struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
  67        struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
  68
  69        ipu_dc_disable_channel(ipu_crtc->dc);
  70        ipu_di_disable(ipu_crtc->di);
  71        /*
  72         * Planes must be disabled before DC clock is removed, as otherwise the
  73         * attached IDMACs will be left in undefined state, possibly hanging
  74         * the IPU or even system.
  75         */
  76        drm_atomic_helper_disable_planes_on_crtc(old_crtc_state, false);
  77        ipu_dc_disable(ipu);
  78
  79        spin_lock_irq(&crtc->dev->event_lock);
  80        if (crtc->state->event) {
  81                drm_crtc_send_vblank_event(crtc, crtc->state->event);
  82                crtc->state->event = NULL;
  83        }
  84        spin_unlock_irq(&crtc->dev->event_lock);
  85
  86        drm_crtc_vblank_off(crtc);
  87}
  88
  89static void imx_drm_crtc_reset(struct drm_crtc *crtc)
  90{
  91        struct imx_crtc_state *state;
  92
  93        if (crtc->state) {
  94                if (crtc->state->mode_blob)
  95                        drm_property_unreference_blob(crtc->state->mode_blob);
  96
  97                state = to_imx_crtc_state(crtc->state);
  98                memset(state, 0, sizeof(*state));
  99        } else {
 100                state = kzalloc(sizeof(*state), GFP_KERNEL);
 101                if (!state)
 102                        return;
 103                crtc->state = &state->base;
 104        }
 105
 106        state->base.crtc = crtc;
 107}
 108
 109static struct drm_crtc_state *imx_drm_crtc_duplicate_state(struct drm_crtc *crtc)
 110{
 111        struct imx_crtc_state *state;
 112
 113        state = kzalloc(sizeof(*state), GFP_KERNEL);
 114        if (!state)
 115                return NULL;
 116
 117        __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
 118
 119        WARN_ON(state->base.crtc != crtc);
 120        state->base.crtc = crtc;
 121
 122        return &state->base;
 123}
 124
 125static void imx_drm_crtc_destroy_state(struct drm_crtc *crtc,
 126                                       struct drm_crtc_state *state)
 127{
 128        __drm_atomic_helper_crtc_destroy_state(state);
 129        kfree(to_imx_crtc_state(state));
 130}
 131
 132static void imx_drm_crtc_destroy(struct drm_crtc *crtc)
 133{
 134        imx_drm_remove_crtc(to_ipu_crtc(crtc)->imx_crtc);
 135}
 136
 137static const struct drm_crtc_funcs ipu_crtc_funcs = {
 138        .set_config = drm_atomic_helper_set_config,
 139        .destroy = imx_drm_crtc_destroy,
 140        .page_flip = drm_atomic_helper_page_flip,
 141        .reset = imx_drm_crtc_reset,
 142        .atomic_duplicate_state = imx_drm_crtc_duplicate_state,
 143        .atomic_destroy_state = imx_drm_crtc_destroy_state,
 144};
 145
 146static irqreturn_t ipu_irq_handler(int irq, void *dev_id)
 147{
 148        struct ipu_crtc *ipu_crtc = dev_id;
 149
 150        drm_crtc_handle_vblank(&ipu_crtc->base);
 151
 152        return IRQ_HANDLED;
 153}
 154
 155static bool ipu_crtc_mode_fixup(struct drm_crtc *crtc,
 156                                  const struct drm_display_mode *mode,
 157                                  struct drm_display_mode *adjusted_mode)
 158{
 159        struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
 160        struct videomode vm;
 161        int ret;
 162
 163        drm_display_mode_to_videomode(adjusted_mode, &vm);
 164
 165        ret = ipu_di_adjust_videomode(ipu_crtc->di, &vm);
 166        if (ret)
 167                return false;
 168
 169        if ((vm.vsync_len == 0) || (vm.hsync_len == 0))
 170                return false;
 171
 172        drm_display_mode_from_videomode(&vm, adjusted_mode);
 173
 174        return true;
 175}
 176
 177static int ipu_crtc_atomic_check(struct drm_crtc *crtc,
 178                                 struct drm_crtc_state *state)
 179{
 180        u32 primary_plane_mask = 1 << drm_plane_index(crtc->primary);
 181
 182        if (state->active && (primary_plane_mask & state->plane_mask) == 0)
 183                return -EINVAL;
 184
 185        return 0;
 186}
 187
 188static void ipu_crtc_atomic_begin(struct drm_crtc *crtc,
 189                                  struct drm_crtc_state *old_crtc_state)
 190{
 191        drm_crtc_vblank_on(crtc);
 192
 193        spin_lock_irq(&crtc->dev->event_lock);
 194        if (crtc->state->event) {
 195                WARN_ON(drm_crtc_vblank_get(crtc));
 196                drm_crtc_arm_vblank_event(crtc, crtc->state->event);
 197                crtc->state->event = NULL;
 198        }
 199        spin_unlock_irq(&crtc->dev->event_lock);
 200}
 201
 202static void ipu_crtc_mode_set_nofb(struct drm_crtc *crtc)
 203{
 204        struct drm_device *dev = crtc->dev;
 205        struct drm_encoder *encoder;
 206        struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
 207        struct drm_display_mode *mode = &crtc->state->adjusted_mode;
 208        struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc->state);
 209        struct ipu_di_signal_cfg sig_cfg = {};
 210        unsigned long encoder_types = 0;
 211
 212        dev_dbg(ipu_crtc->dev, "%s: mode->hdisplay: %d\n", __func__,
 213                        mode->hdisplay);
 214        dev_dbg(ipu_crtc->dev, "%s: mode->vdisplay: %d\n", __func__,
 215                        mode->vdisplay);
 216
 217        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
 218                if (encoder->crtc == crtc)
 219                        encoder_types |= BIT(encoder->encoder_type);
 220        }
 221
 222        dev_dbg(ipu_crtc->dev, "%s: attached to encoder types 0x%lx\n",
 223                __func__, encoder_types);
 224
 225        /*
 226         * If we have DAC or LDB, then we need the IPU DI clock to be
 227         * the same as the LDB DI clock. For TVDAC, derive the IPU DI
 228         * clock from 27 MHz TVE_DI clock, but allow to divide it.
 229         */
 230        if (encoder_types & (BIT(DRM_MODE_ENCODER_DAC) |
 231                             BIT(DRM_MODE_ENCODER_LVDS)))
 232                sig_cfg.clkflags = IPU_DI_CLKMODE_SYNC | IPU_DI_CLKMODE_EXT;
 233        else if (encoder_types & BIT(DRM_MODE_ENCODER_TVDAC))
 234                sig_cfg.clkflags = IPU_DI_CLKMODE_EXT;
 235        else
 236                sig_cfg.clkflags = 0;
 237
 238        sig_cfg.enable_pol = !(imx_crtc_state->bus_flags & DRM_BUS_FLAG_DE_LOW);
 239        /* Default to driving pixel data on negative clock edges */
 240        sig_cfg.clk_pol = !!(imx_crtc_state->bus_flags &
 241                             DRM_BUS_FLAG_PIXDATA_POSEDGE);
 242        sig_cfg.bus_format = imx_crtc_state->bus_format;
 243        sig_cfg.v_to_h_sync = 0;
 244        sig_cfg.hsync_pin = imx_crtc_state->di_hsync_pin;
 245        sig_cfg.vsync_pin = imx_crtc_state->di_vsync_pin;
 246
 247        drm_display_mode_to_videomode(mode, &sig_cfg.mode);
 248
 249        ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di,
 250                         mode->flags & DRM_MODE_FLAG_INTERLACE,
 251                         imx_crtc_state->bus_format, mode->hdisplay);
 252        ipu_di_init_sync_panel(ipu_crtc->di, &sig_cfg);
 253}
 254
 255static const struct drm_crtc_helper_funcs ipu_helper_funcs = {
 256        .mode_fixup = ipu_crtc_mode_fixup,
 257        .mode_set_nofb = ipu_crtc_mode_set_nofb,
 258        .atomic_check = ipu_crtc_atomic_check,
 259        .atomic_begin = ipu_crtc_atomic_begin,
 260        .atomic_disable = ipu_crtc_atomic_disable,
 261        .enable = ipu_crtc_enable,
 262};
 263
 264static int ipu_enable_vblank(struct drm_crtc *crtc)
 265{
 266        struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
 267
 268        enable_irq(ipu_crtc->irq);
 269
 270        return 0;
 271}
 272
 273static void ipu_disable_vblank(struct drm_crtc *crtc)
 274{
 275        struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
 276
 277        disable_irq_nosync(ipu_crtc->irq);
 278}
 279
 280static const struct imx_drm_crtc_helper_funcs ipu_crtc_helper_funcs = {
 281        .enable_vblank = ipu_enable_vblank,
 282        .disable_vblank = ipu_disable_vblank,
 283        .crtc_funcs = &ipu_crtc_funcs,
 284        .crtc_helper_funcs = &ipu_helper_funcs,
 285};
 286
 287static void ipu_put_resources(struct ipu_crtc *ipu_crtc)
 288{
 289        if (!IS_ERR_OR_NULL(ipu_crtc->dc))
 290                ipu_dc_put(ipu_crtc->dc);
 291        if (!IS_ERR_OR_NULL(ipu_crtc->di))
 292                ipu_di_put(ipu_crtc->di);
 293}
 294
 295static int ipu_get_resources(struct ipu_crtc *ipu_crtc,
 296                struct ipu_client_platformdata *pdata)
 297{
 298        struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
 299        int ret;
 300
 301        ipu_crtc->dc = ipu_dc_get(ipu, pdata->dc);
 302        if (IS_ERR(ipu_crtc->dc)) {
 303                ret = PTR_ERR(ipu_crtc->dc);
 304                goto err_out;
 305        }
 306
 307        ipu_crtc->di = ipu_di_get(ipu, pdata->di);
 308        if (IS_ERR(ipu_crtc->di)) {
 309                ret = PTR_ERR(ipu_crtc->di);
 310                goto err_out;
 311        }
 312
 313        return 0;
 314err_out:
 315        ipu_put_resources(ipu_crtc);
 316
 317        return ret;
 318}
 319
 320static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
 321        struct ipu_client_platformdata *pdata, struct drm_device *drm)
 322{
 323        struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
 324        int dp = -EINVAL;
 325        int ret;
 326
 327        ret = ipu_get_resources(ipu_crtc, pdata);
 328        if (ret) {
 329                dev_err(ipu_crtc->dev, "getting resources failed with %d.\n",
 330                                ret);
 331                return ret;
 332        }
 333
 334        if (pdata->dp >= 0)
 335                dp = IPU_DP_FLOW_SYNC_BG;
 336        ipu_crtc->plane[0] = ipu_plane_init(drm, ipu, pdata->dma[0], dp, 0,
 337                                            DRM_PLANE_TYPE_PRIMARY);
 338        if (IS_ERR(ipu_crtc->plane[0])) {
 339                ret = PTR_ERR(ipu_crtc->plane[0]);
 340                goto err_put_resources;
 341        }
 342
 343        ret = imx_drm_add_crtc(drm, &ipu_crtc->base, &ipu_crtc->imx_crtc,
 344                        &ipu_crtc->plane[0]->base, &ipu_crtc_helper_funcs,
 345                        pdata->of_node);
 346        if (ret) {
 347                dev_err(ipu_crtc->dev, "adding crtc failed with %d.\n", ret);
 348                goto err_put_resources;
 349        }
 350
 351        ret = ipu_plane_get_resources(ipu_crtc->plane[0]);
 352        if (ret) {
 353                dev_err(ipu_crtc->dev, "getting plane 0 resources failed with %d.\n",
 354                        ret);
 355                goto err_remove_crtc;
 356        }
 357
 358        /* If this crtc is using the DP, add an overlay plane */
 359        if (pdata->dp >= 0 && pdata->dma[1] > 0) {
 360                ipu_crtc->plane[1] = ipu_plane_init(drm, ipu, pdata->dma[1],
 361                                                IPU_DP_FLOW_SYNC_FG,
 362                                                drm_crtc_mask(&ipu_crtc->base),
 363                                                DRM_PLANE_TYPE_OVERLAY);
 364                if (IS_ERR(ipu_crtc->plane[1])) {
 365                        ipu_crtc->plane[1] = NULL;
 366                } else {
 367                        ret = ipu_plane_get_resources(ipu_crtc->plane[1]);
 368                        if (ret) {
 369                                dev_err(ipu_crtc->dev, "getting plane 1 "
 370                                        "resources failed with %d.\n", ret);
 371                                goto err_put_plane0_res;
 372                        }
 373                }
 374        }
 375
 376        ipu_crtc->irq = ipu_plane_irq(ipu_crtc->plane[0]);
 377        ret = devm_request_irq(ipu_crtc->dev, ipu_crtc->irq, ipu_irq_handler, 0,
 378                        "imx_drm", ipu_crtc);
 379        if (ret < 0) {
 380                dev_err(ipu_crtc->dev, "irq request failed with %d.\n", ret);
 381                goto err_put_plane1_res;
 382        }
 383        /* Only enable IRQ when we actually need it to trigger work. */
 384        disable_irq(ipu_crtc->irq);
 385
 386        return 0;
 387
 388err_put_plane1_res:
 389        if (ipu_crtc->plane[1])
 390                ipu_plane_put_resources(ipu_crtc->plane[1]);
 391err_put_plane0_res:
 392        ipu_plane_put_resources(ipu_crtc->plane[0]);
 393err_remove_crtc:
 394        imx_drm_remove_crtc(ipu_crtc->imx_crtc);
 395err_put_resources:
 396        ipu_put_resources(ipu_crtc);
 397
 398        return ret;
 399}
 400
 401static int ipu_drm_bind(struct device *dev, struct device *master, void *data)
 402{
 403        struct ipu_client_platformdata *pdata = dev->platform_data;
 404        struct drm_device *drm = data;
 405        struct ipu_crtc *ipu_crtc;
 406        int ret;
 407
 408        ipu_crtc = devm_kzalloc(dev, sizeof(*ipu_crtc), GFP_KERNEL);
 409        if (!ipu_crtc)
 410                return -ENOMEM;
 411
 412        ipu_crtc->dev = dev;
 413
 414        ret = ipu_crtc_init(ipu_crtc, pdata, drm);
 415        if (ret)
 416                return ret;
 417
 418        dev_set_drvdata(dev, ipu_crtc);
 419
 420        return 0;
 421}
 422
 423static void ipu_drm_unbind(struct device *dev, struct device *master,
 424        void *data)
 425{
 426        struct ipu_crtc *ipu_crtc = dev_get_drvdata(dev);
 427
 428        ipu_put_resources(ipu_crtc);
 429        if (ipu_crtc->plane[1])
 430                ipu_plane_put_resources(ipu_crtc->plane[1]);
 431        ipu_plane_put_resources(ipu_crtc->plane[0]);
 432}
 433
 434static const struct component_ops ipu_crtc_ops = {
 435        .bind = ipu_drm_bind,
 436        .unbind = ipu_drm_unbind,
 437};
 438
 439static int ipu_drm_probe(struct platform_device *pdev)
 440{
 441        struct device *dev = &pdev->dev;
 442        int ret;
 443
 444        if (!dev->platform_data)
 445                return -EINVAL;
 446
 447        ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
 448        if (ret)
 449                return ret;
 450
 451        return component_add(dev, &ipu_crtc_ops);
 452}
 453
 454static int ipu_drm_remove(struct platform_device *pdev)
 455{
 456        component_del(&pdev->dev, &ipu_crtc_ops);
 457        return 0;
 458}
 459
 460static struct platform_driver ipu_drm_driver = {
 461        .driver = {
 462                .name = "imx-ipuv3-crtc",
 463        },
 464        .probe = ipu_drm_probe,
 465        .remove = ipu_drm_remove,
 466};
 467module_platform_driver(ipu_drm_driver);
 468
 469MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
 470MODULE_DESCRIPTION(DRIVER_DESC);
 471MODULE_LICENSE("GPL");
 472MODULE_ALIAS("platform:imx-ipuv3-crtc");
 473