linux/drivers/gpu/drm/omapdrm/dss/dpi.c
<<
>>
Prefs
   1/*
   2 * linux/drivers/video/omap2/dss/dpi.c
   3 *
   4 * Copyright (C) 2009 Nokia Corporation
   5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
   6 *
   7 * Some code and ideas taken from drivers/video/omap/ driver
   8 * by Imre Deak.
   9 *
  10 * This program is free software; you can redistribute it and/or modify it
  11 * under the terms of the GNU General Public License version 2 as published by
  12 * the Free Software Foundation.
  13 *
  14 * This program is distributed in the hope that it will be useful, but WITHOUT
  15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  16 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  17 * more details.
  18 *
  19 * You should have received a copy of the GNU General Public License along with
  20 * this program.  If not, see <http://www.gnu.org/licenses/>.
  21 */
  22
  23#define DSS_SUBSYS_NAME "DPI"
  24
  25#include <linux/kernel.h>
  26#include <linux/delay.h>
  27#include <linux/export.h>
  28#include <linux/err.h>
  29#include <linux/errno.h>
  30#include <linux/platform_device.h>
  31#include <linux/regulator/consumer.h>
  32#include <linux/string.h>
  33#include <linux/of.h>
  34#include <linux/clk.h>
  35
  36#include "omapdss.h"
  37#include "dss.h"
  38#include "dss_features.h"
  39
  40struct dpi_data {
  41        struct platform_device *pdev;
  42
  43        struct regulator *vdds_dsi_reg;
  44        enum dss_clk_source clk_src;
  45        struct dss_pll *pll;
  46
  47        struct mutex lock;
  48
  49        struct videomode vm;
  50        struct dss_lcd_mgr_config mgr_config;
  51        int data_lines;
  52
  53        struct omap_dss_device output;
  54
  55        bool port_initialized;
  56};
  57
  58static struct dpi_data *dpi_get_data_from_dssdev(struct omap_dss_device *dssdev)
  59{
  60        return container_of(dssdev, struct dpi_data, output);
  61}
  62
  63static enum dss_clk_source dpi_get_clk_src_dra7xx(enum omap_channel channel)
  64{
  65        /*
  66         * Possible clock sources:
  67         * LCD1: FCK/PLL1_1/HDMI_PLL
  68         * LCD2: FCK/PLL1_3/HDMI_PLL (DRA74x: PLL2_3)
  69         * LCD3: FCK/PLL1_3/HDMI_PLL (DRA74x: PLL2_1)
  70         */
  71
  72        switch (channel) {
  73        case OMAP_DSS_CHANNEL_LCD:
  74        {
  75                if (dss_pll_find_by_src(DSS_CLK_SRC_PLL1_1))
  76                        return DSS_CLK_SRC_PLL1_1;
  77                break;
  78        }
  79        case OMAP_DSS_CHANNEL_LCD2:
  80        {
  81                if (dss_pll_find_by_src(DSS_CLK_SRC_PLL1_3))
  82                        return DSS_CLK_SRC_PLL1_3;
  83                if (dss_pll_find_by_src(DSS_CLK_SRC_PLL2_3))
  84                        return DSS_CLK_SRC_PLL2_3;
  85                break;
  86        }
  87        case OMAP_DSS_CHANNEL_LCD3:
  88        {
  89                if (dss_pll_find_by_src(DSS_CLK_SRC_PLL2_1))
  90                        return DSS_CLK_SRC_PLL2_1;
  91                if (dss_pll_find_by_src(DSS_CLK_SRC_PLL1_3))
  92                        return DSS_CLK_SRC_PLL1_3;
  93                break;
  94        }
  95        default:
  96                break;
  97        }
  98
  99        return DSS_CLK_SRC_FCK;
 100}
 101
 102static enum dss_clk_source dpi_get_clk_src(enum omap_channel channel)
 103{
 104        /*
 105         * XXX we can't currently use DSI PLL for DPI with OMAP3, as the DSI PLL
 106         * would also be used for DISPC fclk. Meaning, when the DPI output is
 107         * disabled, DISPC clock will be disabled, and TV out will stop.
 108         */
 109        switch (omapdss_get_version()) {
 110        case OMAPDSS_VER_OMAP24xx:
 111        case OMAPDSS_VER_OMAP34xx_ES1:
 112        case OMAPDSS_VER_OMAP34xx_ES3:
 113        case OMAPDSS_VER_OMAP3630:
 114        case OMAPDSS_VER_AM35xx:
 115        case OMAPDSS_VER_AM43xx:
 116                return DSS_CLK_SRC_FCK;
 117
 118        case OMAPDSS_VER_OMAP4430_ES1:
 119        case OMAPDSS_VER_OMAP4430_ES2:
 120        case OMAPDSS_VER_OMAP4:
 121                switch (channel) {
 122                case OMAP_DSS_CHANNEL_LCD:
 123                        return DSS_CLK_SRC_PLL1_1;
 124                case OMAP_DSS_CHANNEL_LCD2:
 125                        return DSS_CLK_SRC_PLL2_1;
 126                default:
 127                        return DSS_CLK_SRC_FCK;
 128                }
 129
 130        case OMAPDSS_VER_OMAP5:
 131                switch (channel) {
 132                case OMAP_DSS_CHANNEL_LCD:
 133                        return DSS_CLK_SRC_PLL1_1;
 134                case OMAP_DSS_CHANNEL_LCD3:
 135                        return DSS_CLK_SRC_PLL2_1;
 136                case OMAP_DSS_CHANNEL_LCD2:
 137                default:
 138                        return DSS_CLK_SRC_FCK;
 139                }
 140
 141        case OMAPDSS_VER_DRA7xx:
 142                return dpi_get_clk_src_dra7xx(channel);
 143
 144        default:
 145                return DSS_CLK_SRC_FCK;
 146        }
 147}
 148
 149struct dpi_clk_calc_ctx {
 150        struct dss_pll *pll;
 151        unsigned clkout_idx;
 152
 153        /* inputs */
 154
 155        unsigned long pck_min, pck_max;
 156
 157        /* outputs */
 158
 159        struct dss_pll_clock_info pll_cinfo;
 160        unsigned long fck;
 161        struct dispc_clock_info dispc_cinfo;
 162};
 163
 164static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
 165                unsigned long pck, void *data)
 166{
 167        struct dpi_clk_calc_ctx *ctx = data;
 168
 169        /*
 170         * Odd dividers give us uneven duty cycle, causing problem when level
 171         * shifted. So skip all odd dividers when the pixel clock is on the
 172         * higher side.
 173         */
 174        if (ctx->pck_min >= 100000000) {
 175                if (lckd > 1 && lckd % 2 != 0)
 176                        return false;
 177
 178                if (pckd > 1 && pckd % 2 != 0)
 179                        return false;
 180        }
 181
 182        ctx->dispc_cinfo.lck_div = lckd;
 183        ctx->dispc_cinfo.pck_div = pckd;
 184        ctx->dispc_cinfo.lck = lck;
 185        ctx->dispc_cinfo.pck = pck;
 186
 187        return true;
 188}
 189
 190
 191static bool dpi_calc_hsdiv_cb(int m_dispc, unsigned long dispc,
 192                void *data)
 193{
 194        struct dpi_clk_calc_ctx *ctx = data;
 195
 196        ctx->pll_cinfo.mX[ctx->clkout_idx] = m_dispc;
 197        ctx->pll_cinfo.clkout[ctx->clkout_idx] = dispc;
 198
 199        return dispc_div_calc(dispc, ctx->pck_min, ctx->pck_max,
 200                        dpi_calc_dispc_cb, ctx);
 201}
 202
 203
 204static bool dpi_calc_pll_cb(int n, int m, unsigned long fint,
 205                unsigned long clkdco,
 206                void *data)
 207{
 208        struct dpi_clk_calc_ctx *ctx = data;
 209
 210        ctx->pll_cinfo.n = n;
 211        ctx->pll_cinfo.m = m;
 212        ctx->pll_cinfo.fint = fint;
 213        ctx->pll_cinfo.clkdco = clkdco;
 214
 215        return dss_pll_hsdiv_calc_a(ctx->pll, clkdco,
 216                ctx->pck_min, dss_feat_get_param_max(FEAT_PARAM_DSS_FCK),
 217                dpi_calc_hsdiv_cb, ctx);
 218}
 219
 220static bool dpi_calc_dss_cb(unsigned long fck, void *data)
 221{
 222        struct dpi_clk_calc_ctx *ctx = data;
 223
 224        ctx->fck = fck;
 225
 226        return dispc_div_calc(fck, ctx->pck_min, ctx->pck_max,
 227                        dpi_calc_dispc_cb, ctx);
 228}
 229
 230static bool dpi_pll_clk_calc(struct dpi_data *dpi, unsigned long pck,
 231                struct dpi_clk_calc_ctx *ctx)
 232{
 233        unsigned long clkin;
 234
 235        memset(ctx, 0, sizeof(*ctx));
 236        ctx->pll = dpi->pll;
 237        ctx->clkout_idx = dss_pll_get_clkout_idx_for_src(dpi->clk_src);
 238
 239        clkin = clk_get_rate(dpi->pll->clkin);
 240
 241        if (dpi->pll->hw->type == DSS_PLL_TYPE_A) {
 242                unsigned long pll_min, pll_max;
 243
 244                ctx->pck_min = pck - 1000;
 245                ctx->pck_max = pck + 1000;
 246
 247                pll_min = 0;
 248                pll_max = 0;
 249
 250                return dss_pll_calc_a(ctx->pll, clkin,
 251                                pll_min, pll_max,
 252                                dpi_calc_pll_cb, ctx);
 253        } else { /* DSS_PLL_TYPE_B */
 254                dss_pll_calc_b(dpi->pll, clkin, pck, &ctx->pll_cinfo);
 255
 256                ctx->dispc_cinfo.lck_div = 1;
 257                ctx->dispc_cinfo.pck_div = 1;
 258                ctx->dispc_cinfo.lck = ctx->pll_cinfo.clkout[0];
 259                ctx->dispc_cinfo.pck = ctx->dispc_cinfo.lck;
 260
 261                return true;
 262        }
 263}
 264
 265static bool dpi_dss_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx)
 266{
 267        int i;
 268
 269        /*
 270         * DSS fck gives us very few possibilities, so finding a good pixel
 271         * clock may not be possible. We try multiple times to find the clock,
 272         * each time widening the pixel clock range we look for, up to
 273         * +/- ~15MHz.
 274         */
 275
 276        for (i = 0; i < 25; ++i) {
 277                bool ok;
 278
 279                memset(ctx, 0, sizeof(*ctx));
 280                if (pck > 1000 * i * i * i)
 281                        ctx->pck_min = max(pck - 1000 * i * i * i, 0lu);
 282                else
 283                        ctx->pck_min = 0;
 284                ctx->pck_max = pck + 1000 * i * i * i;
 285
 286                ok = dss_div_calc(pck, ctx->pck_min, dpi_calc_dss_cb, ctx);
 287                if (ok)
 288                        return ok;
 289        }
 290
 291        return false;
 292}
 293
 294
 295
 296static int dpi_set_pll_clk(struct dpi_data *dpi, enum omap_channel channel,
 297                unsigned long pck_req, unsigned long *fck, int *lck_div,
 298                int *pck_div)
 299{
 300        struct dpi_clk_calc_ctx ctx;
 301        int r;
 302        bool ok;
 303
 304        ok = dpi_pll_clk_calc(dpi, pck_req, &ctx);
 305        if (!ok)
 306                return -EINVAL;
 307
 308        r = dss_pll_set_config(dpi->pll, &ctx.pll_cinfo);
 309        if (r)
 310                return r;
 311
 312        dss_select_lcd_clk_source(channel, dpi->clk_src);
 313
 314        dpi->mgr_config.clock_info = ctx.dispc_cinfo;
 315
 316        *fck = ctx.pll_cinfo.clkout[ctx.clkout_idx];
 317        *lck_div = ctx.dispc_cinfo.lck_div;
 318        *pck_div = ctx.dispc_cinfo.pck_div;
 319
 320        return 0;
 321}
 322
 323static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req,
 324                unsigned long *fck, int *lck_div, int *pck_div)
 325{
 326        struct dpi_clk_calc_ctx ctx;
 327        int r;
 328        bool ok;
 329
 330        ok = dpi_dss_clk_calc(pck_req, &ctx);
 331        if (!ok)
 332                return -EINVAL;
 333
 334        r = dss_set_fck_rate(ctx.fck);
 335        if (r)
 336                return r;
 337
 338        dpi->mgr_config.clock_info = ctx.dispc_cinfo;
 339
 340        *fck = ctx.fck;
 341        *lck_div = ctx.dispc_cinfo.lck_div;
 342        *pck_div = ctx.dispc_cinfo.pck_div;
 343
 344        return 0;
 345}
 346
 347static int dpi_set_mode(struct dpi_data *dpi)
 348{
 349        struct omap_dss_device *out = &dpi->output;
 350        enum omap_channel channel = out->dispc_channel;
 351        struct videomode *vm = &dpi->vm;
 352        int lck_div = 0, pck_div = 0;
 353        unsigned long fck = 0;
 354        unsigned long pck;
 355        int r = 0;
 356
 357        if (dpi->pll)
 358                r = dpi_set_pll_clk(dpi, channel, vm->pixelclock, &fck,
 359                                &lck_div, &pck_div);
 360        else
 361                r = dpi_set_dispc_clk(dpi, vm->pixelclock, &fck,
 362                                &lck_div, &pck_div);
 363        if (r)
 364                return r;
 365
 366        pck = fck / lck_div / pck_div;
 367
 368        if (pck != vm->pixelclock) {
 369                DSSWARN("Could not find exact pixel clock. Requested %lu Hz, got %lu Hz\n",
 370                        vm->pixelclock, pck);
 371
 372                vm->pixelclock = pck;
 373        }
 374
 375        dss_mgr_set_timings(channel, vm);
 376
 377        return 0;
 378}
 379
 380static void dpi_config_lcd_manager(struct dpi_data *dpi)
 381{
 382        struct omap_dss_device *out = &dpi->output;
 383        enum omap_channel channel = out->dispc_channel;
 384
 385        dpi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
 386
 387        dpi->mgr_config.stallmode = false;
 388        dpi->mgr_config.fifohandcheck = false;
 389
 390        dpi->mgr_config.video_port_width = dpi->data_lines;
 391
 392        dpi->mgr_config.lcden_sig_polarity = 0;
 393
 394        dss_mgr_set_lcd_config(channel, &dpi->mgr_config);
 395}
 396
 397static int dpi_display_enable(struct omap_dss_device *dssdev)
 398{
 399        struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
 400        struct omap_dss_device *out = &dpi->output;
 401        enum omap_channel channel = out->dispc_channel;
 402        int r;
 403
 404        mutex_lock(&dpi->lock);
 405
 406        if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && !dpi->vdds_dsi_reg) {
 407                DSSERR("no VDSS_DSI regulator\n");
 408                r = -ENODEV;
 409                goto err_no_reg;
 410        }
 411
 412        if (!out->dispc_channel_connected) {
 413                DSSERR("failed to enable display: no output/manager\n");
 414                r = -ENODEV;
 415                goto err_no_out_mgr;
 416        }
 417
 418        if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) {
 419                r = regulator_enable(dpi->vdds_dsi_reg);
 420                if (r)
 421                        goto err_reg_enable;
 422        }
 423
 424        r = dispc_runtime_get();
 425        if (r)
 426                goto err_get_dispc;
 427
 428        r = dss_dpi_select_source(out->port_num, channel);
 429        if (r)
 430                goto err_src_sel;
 431
 432        if (dpi->pll) {
 433                r = dss_pll_enable(dpi->pll);
 434                if (r)
 435                        goto err_pll_init;
 436        }
 437
 438        r = dpi_set_mode(dpi);
 439        if (r)
 440                goto err_set_mode;
 441
 442        dpi_config_lcd_manager(dpi);
 443
 444        mdelay(2);
 445
 446        r = dss_mgr_enable(channel);
 447        if (r)
 448                goto err_mgr_enable;
 449
 450        mutex_unlock(&dpi->lock);
 451
 452        return 0;
 453
 454err_mgr_enable:
 455err_set_mode:
 456        if (dpi->pll)
 457                dss_pll_disable(dpi->pll);
 458err_pll_init:
 459err_src_sel:
 460        dispc_runtime_put();
 461err_get_dispc:
 462        if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
 463                regulator_disable(dpi->vdds_dsi_reg);
 464err_reg_enable:
 465err_no_out_mgr:
 466err_no_reg:
 467        mutex_unlock(&dpi->lock);
 468        return r;
 469}
 470
 471static void dpi_display_disable(struct omap_dss_device *dssdev)
 472{
 473        struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
 474        enum omap_channel channel = dpi->output.dispc_channel;
 475
 476        mutex_lock(&dpi->lock);
 477
 478        dss_mgr_disable(channel);
 479
 480        if (dpi->pll) {
 481                dss_select_lcd_clk_source(channel, DSS_CLK_SRC_FCK);
 482                dss_pll_disable(dpi->pll);
 483        }
 484
 485        dispc_runtime_put();
 486
 487        if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
 488                regulator_disable(dpi->vdds_dsi_reg);
 489
 490        mutex_unlock(&dpi->lock);
 491}
 492
 493static void dpi_set_timings(struct omap_dss_device *dssdev,
 494                            struct videomode *vm)
 495{
 496        struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
 497
 498        DSSDBG("dpi_set_timings\n");
 499
 500        mutex_lock(&dpi->lock);
 501
 502        dpi->vm = *vm;
 503
 504        mutex_unlock(&dpi->lock);
 505}
 506
 507static void dpi_get_timings(struct omap_dss_device *dssdev,
 508                            struct videomode *vm)
 509{
 510        struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
 511
 512        mutex_lock(&dpi->lock);
 513
 514        *vm = dpi->vm;
 515
 516        mutex_unlock(&dpi->lock);
 517}
 518
 519static int dpi_check_timings(struct omap_dss_device *dssdev,
 520                             struct videomode *vm)
 521{
 522        struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
 523        enum omap_channel channel = dpi->output.dispc_channel;
 524        int lck_div, pck_div;
 525        unsigned long fck;
 526        unsigned long pck;
 527        struct dpi_clk_calc_ctx ctx;
 528        bool ok;
 529
 530        if (vm->hactive % 8 != 0)
 531                return -EINVAL;
 532
 533        if (!dispc_mgr_timings_ok(channel, vm))
 534                return -EINVAL;
 535
 536        if (vm->pixelclock == 0)
 537                return -EINVAL;
 538
 539        if (dpi->pll) {
 540                ok = dpi_pll_clk_calc(dpi, vm->pixelclock, &ctx);
 541                if (!ok)
 542                        return -EINVAL;
 543
 544                fck = ctx.pll_cinfo.clkout[ctx.clkout_idx];
 545        } else {
 546                ok = dpi_dss_clk_calc(vm->pixelclock, &ctx);
 547                if (!ok)
 548                        return -EINVAL;
 549
 550                fck = ctx.fck;
 551        }
 552
 553        lck_div = ctx.dispc_cinfo.lck_div;
 554        pck_div = ctx.dispc_cinfo.pck_div;
 555
 556        pck = fck / lck_div / pck_div;
 557
 558        vm->pixelclock = pck;
 559
 560        return 0;
 561}
 562
 563static int dpi_verify_pll(struct dss_pll *pll)
 564{
 565        int r;
 566
 567        /* do initial setup with the PLL to see if it is operational */
 568
 569        r = dss_pll_enable(pll);
 570        if (r)
 571                return r;
 572
 573        dss_pll_disable(pll);
 574
 575        return 0;
 576}
 577
 578static int dpi_init_regulator(struct dpi_data *dpi)
 579{
 580        struct regulator *vdds_dsi;
 581
 582        if (!dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
 583                return 0;
 584
 585        if (dpi->vdds_dsi_reg)
 586                return 0;
 587
 588        vdds_dsi = devm_regulator_get(&dpi->pdev->dev, "vdds_dsi");
 589        if (IS_ERR(vdds_dsi)) {
 590                if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER)
 591                        DSSERR("can't get VDDS_DSI regulator\n");
 592                return PTR_ERR(vdds_dsi);
 593        }
 594
 595        dpi->vdds_dsi_reg = vdds_dsi;
 596
 597        return 0;
 598}
 599
 600static void dpi_init_pll(struct dpi_data *dpi)
 601{
 602        struct dss_pll *pll;
 603
 604        if (dpi->pll)
 605                return;
 606
 607        dpi->clk_src = dpi_get_clk_src(dpi->output.dispc_channel);
 608
 609        pll = dss_pll_find_by_src(dpi->clk_src);
 610        if (!pll)
 611                return;
 612
 613        if (dpi_verify_pll(pll)) {
 614                DSSWARN("PLL not operational\n");
 615                return;
 616        }
 617
 618        dpi->pll = pll;
 619}
 620
 621/*
 622 * Return a hardcoded channel for the DPI output. This should work for
 623 * current use cases, but this can be later expanded to either resolve
 624 * the channel in some more dynamic manner, or get the channel as a user
 625 * parameter.
 626 */
 627static enum omap_channel dpi_get_channel(int port_num)
 628{
 629        switch (omapdss_get_version()) {
 630        case OMAPDSS_VER_OMAP24xx:
 631        case OMAPDSS_VER_OMAP34xx_ES1:
 632        case OMAPDSS_VER_OMAP34xx_ES3:
 633        case OMAPDSS_VER_OMAP3630:
 634        case OMAPDSS_VER_AM35xx:
 635        case OMAPDSS_VER_AM43xx:
 636                return OMAP_DSS_CHANNEL_LCD;
 637
 638        case OMAPDSS_VER_DRA7xx:
 639                switch (port_num) {
 640                case 2:
 641                        return OMAP_DSS_CHANNEL_LCD3;
 642                case 1:
 643                        return OMAP_DSS_CHANNEL_LCD2;
 644                case 0:
 645                default:
 646                        return OMAP_DSS_CHANNEL_LCD;
 647                }
 648
 649        case OMAPDSS_VER_OMAP4430_ES1:
 650        case OMAPDSS_VER_OMAP4430_ES2:
 651        case OMAPDSS_VER_OMAP4:
 652                return OMAP_DSS_CHANNEL_LCD2;
 653
 654        case OMAPDSS_VER_OMAP5:
 655                return OMAP_DSS_CHANNEL_LCD3;
 656
 657        default:
 658                DSSWARN("unsupported DSS version\n");
 659                return OMAP_DSS_CHANNEL_LCD;
 660        }
 661}
 662
 663static int dpi_connect(struct omap_dss_device *dssdev,
 664                struct omap_dss_device *dst)
 665{
 666        struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
 667        enum omap_channel channel = dpi->output.dispc_channel;
 668        int r;
 669
 670        r = dpi_init_regulator(dpi);
 671        if (r)
 672                return r;
 673
 674        dpi_init_pll(dpi);
 675
 676        r = dss_mgr_connect(channel, dssdev);
 677        if (r)
 678                return r;
 679
 680        r = omapdss_output_set_device(dssdev, dst);
 681        if (r) {
 682                DSSERR("failed to connect output to new device: %s\n",
 683                                dst->name);
 684                dss_mgr_disconnect(channel, dssdev);
 685                return r;
 686        }
 687
 688        return 0;
 689}
 690
 691static void dpi_disconnect(struct omap_dss_device *dssdev,
 692                struct omap_dss_device *dst)
 693{
 694        struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
 695        enum omap_channel channel = dpi->output.dispc_channel;
 696
 697        WARN_ON(dst != dssdev->dst);
 698
 699        if (dst != dssdev->dst)
 700                return;
 701
 702        omapdss_output_unset_device(dssdev);
 703
 704        dss_mgr_disconnect(channel, dssdev);
 705}
 706
 707static const struct omapdss_dpi_ops dpi_ops = {
 708        .connect = dpi_connect,
 709        .disconnect = dpi_disconnect,
 710
 711        .enable = dpi_display_enable,
 712        .disable = dpi_display_disable,
 713
 714        .check_timings = dpi_check_timings,
 715        .set_timings = dpi_set_timings,
 716        .get_timings = dpi_get_timings,
 717};
 718
 719static void dpi_init_output_port(struct platform_device *pdev,
 720        struct device_node *port)
 721{
 722        struct dpi_data *dpi = port->data;
 723        struct omap_dss_device *out = &dpi->output;
 724        int r;
 725        u32 port_num;
 726
 727        r = of_property_read_u32(port, "reg", &port_num);
 728        if (r)
 729                port_num = 0;
 730
 731        switch (port_num) {
 732        case 2:
 733                out->name = "dpi.2";
 734                break;
 735        case 1:
 736                out->name = "dpi.1";
 737                break;
 738        case 0:
 739        default:
 740                out->name = "dpi.0";
 741                break;
 742        }
 743
 744        out->dev = &pdev->dev;
 745        out->id = OMAP_DSS_OUTPUT_DPI;
 746        out->output_type = OMAP_DISPLAY_TYPE_DPI;
 747        out->dispc_channel = dpi_get_channel(port_num);
 748        out->port_num = port_num;
 749        out->ops.dpi = &dpi_ops;
 750        out->owner = THIS_MODULE;
 751
 752        omapdss_register_output(out);
 753}
 754
 755static void dpi_uninit_output_port(struct device_node *port)
 756{
 757        struct dpi_data *dpi = port->data;
 758        struct omap_dss_device *out = &dpi->output;
 759
 760        omapdss_unregister_output(out);
 761}
 762
 763int dpi_init_port(struct platform_device *pdev, struct device_node *port)
 764{
 765        struct dpi_data *dpi;
 766        struct device_node *ep;
 767        u32 datalines;
 768        int r;
 769
 770        dpi = devm_kzalloc(&pdev->dev, sizeof(*dpi), GFP_KERNEL);
 771        if (!dpi)
 772                return -ENOMEM;
 773
 774        ep = of_get_next_child(port, NULL);
 775        if (!ep)
 776                return 0;
 777
 778        r = of_property_read_u32(ep, "data-lines", &datalines);
 779        if (r) {
 780                DSSERR("failed to parse datalines\n");
 781                goto err_datalines;
 782        }
 783
 784        dpi->data_lines = datalines;
 785
 786        of_node_put(ep);
 787
 788        dpi->pdev = pdev;
 789        port->data = dpi;
 790
 791        mutex_init(&dpi->lock);
 792
 793        dpi_init_output_port(pdev, port);
 794
 795        dpi->port_initialized = true;
 796
 797        return 0;
 798
 799err_datalines:
 800        of_node_put(ep);
 801
 802        return r;
 803}
 804
 805void dpi_uninit_port(struct device_node *port)
 806{
 807        struct dpi_data *dpi = port->data;
 808
 809        if (!dpi->port_initialized)
 810                return;
 811
 812        dpi_uninit_output_port(port);
 813}
 814