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