linux/drivers/video/fbdev/omap2/dss/dss.c
<<
>>
Prefs
   1/*
   2 * linux/drivers/video/omap2/dss/dss.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 "DSS"
  24
  25#include <linux/kernel.h>
  26#include <linux/module.h>
  27#include <linux/io.h>
  28#include <linux/export.h>
  29#include <linux/err.h>
  30#include <linux/delay.h>
  31#include <linux/seq_file.h>
  32#include <linux/clk.h>
  33#include <linux/platform_device.h>
  34#include <linux/pm_runtime.h>
  35#include <linux/gfp.h>
  36#include <linux/sizes.h>
  37#include <linux/of.h>
  38
  39#include <video/omapdss.h>
  40
  41#include "dss.h"
  42#include "dss_features.h"
  43
  44#define DSS_SZ_REGS                     SZ_512
  45
  46struct dss_reg {
  47        u16 idx;
  48};
  49
  50#define DSS_REG(idx)                    ((const struct dss_reg) { idx })
  51
  52#define DSS_REVISION                    DSS_REG(0x0000)
  53#define DSS_SYSCONFIG                   DSS_REG(0x0010)
  54#define DSS_SYSSTATUS                   DSS_REG(0x0014)
  55#define DSS_CONTROL                     DSS_REG(0x0040)
  56#define DSS_SDI_CONTROL                 DSS_REG(0x0044)
  57#define DSS_PLL_CONTROL                 DSS_REG(0x0048)
  58#define DSS_SDI_STATUS                  DSS_REG(0x005C)
  59
  60#define REG_GET(idx, start, end) \
  61        FLD_GET(dss_read_reg(idx), start, end)
  62
  63#define REG_FLD_MOD(idx, val, start, end) \
  64        dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end))
  65
  66static int dss_runtime_get(void);
  67static void dss_runtime_put(void);
  68
  69struct dss_features {
  70        u8 fck_div_max;
  71        u8 dss_fck_multiplier;
  72        const char *parent_clk_name;
  73        enum omap_display_type *ports;
  74        int num_ports;
  75        int (*dpi_select_source)(int port, enum omap_channel channel);
  76};
  77
  78static struct {
  79        struct platform_device *pdev;
  80        void __iomem    *base;
  81
  82        struct clk      *parent_clk;
  83        struct clk      *dss_clk;
  84        unsigned long   dss_clk_rate;
  85
  86        unsigned long   cache_req_pck;
  87        unsigned long   cache_prate;
  88        struct dispc_clock_info cache_dispc_cinfo;
  89
  90        enum omap_dss_clk_source dsi_clk_source[MAX_NUM_DSI];
  91        enum omap_dss_clk_source dispc_clk_source;
  92        enum omap_dss_clk_source lcd_clk_source[MAX_DSS_LCD_MANAGERS];
  93
  94        bool            ctx_valid;
  95        u32             ctx[DSS_SZ_REGS / sizeof(u32)];
  96
  97        const struct dss_features *feat;
  98} dss;
  99
 100static const char * const dss_generic_clk_source_names[] = {
 101        [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC]  = "DSI_PLL_HSDIV_DISPC",
 102        [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI]    = "DSI_PLL_HSDIV_DSI",
 103        [OMAP_DSS_CLK_SRC_FCK]                  = "DSS_FCK",
 104        [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC] = "DSI_PLL2_HSDIV_DISPC",
 105        [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI]   = "DSI_PLL2_HSDIV_DSI",
 106};
 107
 108static inline void dss_write_reg(const struct dss_reg idx, u32 val)
 109{
 110        __raw_writel(val, dss.base + idx.idx);
 111}
 112
 113static inline u32 dss_read_reg(const struct dss_reg idx)
 114{
 115        return __raw_readl(dss.base + idx.idx);
 116}
 117
 118#define SR(reg) \
 119        dss.ctx[(DSS_##reg).idx / sizeof(u32)] = dss_read_reg(DSS_##reg)
 120#define RR(reg) \
 121        dss_write_reg(DSS_##reg, dss.ctx[(DSS_##reg).idx / sizeof(u32)])
 122
 123static void dss_save_context(void)
 124{
 125        DSSDBG("dss_save_context\n");
 126
 127        SR(CONTROL);
 128
 129        if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
 130                        OMAP_DISPLAY_TYPE_SDI) {
 131                SR(SDI_CONTROL);
 132                SR(PLL_CONTROL);
 133        }
 134
 135        dss.ctx_valid = true;
 136
 137        DSSDBG("context saved\n");
 138}
 139
 140static void dss_restore_context(void)
 141{
 142        DSSDBG("dss_restore_context\n");
 143
 144        if (!dss.ctx_valid)
 145                return;
 146
 147        RR(CONTROL);
 148
 149        if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
 150                        OMAP_DISPLAY_TYPE_SDI) {
 151                RR(SDI_CONTROL);
 152                RR(PLL_CONTROL);
 153        }
 154
 155        DSSDBG("context restored\n");
 156}
 157
 158#undef SR
 159#undef RR
 160
 161void dss_sdi_init(int datapairs)
 162{
 163        u32 l;
 164
 165        BUG_ON(datapairs > 3 || datapairs < 1);
 166
 167        l = dss_read_reg(DSS_SDI_CONTROL);
 168        l = FLD_MOD(l, 0xf, 19, 15);            /* SDI_PDIV */
 169        l = FLD_MOD(l, datapairs-1, 3, 2);      /* SDI_PRSEL */
 170        l = FLD_MOD(l, 2, 1, 0);                /* SDI_BWSEL */
 171        dss_write_reg(DSS_SDI_CONTROL, l);
 172
 173        l = dss_read_reg(DSS_PLL_CONTROL);
 174        l = FLD_MOD(l, 0x7, 25, 22);    /* SDI_PLL_FREQSEL */
 175        l = FLD_MOD(l, 0xb, 16, 11);    /* SDI_PLL_REGN */
 176        l = FLD_MOD(l, 0xb4, 10, 1);    /* SDI_PLL_REGM */
 177        dss_write_reg(DSS_PLL_CONTROL, l);
 178}
 179
 180int dss_sdi_enable(void)
 181{
 182        unsigned long timeout;
 183
 184        dispc_pck_free_enable(1);
 185
 186        /* Reset SDI PLL */
 187        REG_FLD_MOD(DSS_PLL_CONTROL, 1, 18, 18); /* SDI_PLL_SYSRESET */
 188        udelay(1);      /* wait 2x PCLK */
 189
 190        /* Lock SDI PLL */
 191        REG_FLD_MOD(DSS_PLL_CONTROL, 1, 28, 28); /* SDI_PLL_GOBIT */
 192
 193        /* Waiting for PLL lock request to complete */
 194        timeout = jiffies + msecs_to_jiffies(500);
 195        while (dss_read_reg(DSS_SDI_STATUS) & (1 << 6)) {
 196                if (time_after_eq(jiffies, timeout)) {
 197                        DSSERR("PLL lock request timed out\n");
 198                        goto err1;
 199                }
 200        }
 201
 202        /* Clearing PLL_GO bit */
 203        REG_FLD_MOD(DSS_PLL_CONTROL, 0, 28, 28);
 204
 205        /* Waiting for PLL to lock */
 206        timeout = jiffies + msecs_to_jiffies(500);
 207        while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 5))) {
 208                if (time_after_eq(jiffies, timeout)) {
 209                        DSSERR("PLL lock timed out\n");
 210                        goto err1;
 211                }
 212        }
 213
 214        dispc_lcd_enable_signal(1);
 215
 216        /* Waiting for SDI reset to complete */
 217        timeout = jiffies + msecs_to_jiffies(500);
 218        while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 2))) {
 219                if (time_after_eq(jiffies, timeout)) {
 220                        DSSERR("SDI reset timed out\n");
 221                        goto err2;
 222                }
 223        }
 224
 225        return 0;
 226
 227 err2:
 228        dispc_lcd_enable_signal(0);
 229 err1:
 230        /* Reset SDI PLL */
 231        REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
 232
 233        dispc_pck_free_enable(0);
 234
 235        return -ETIMEDOUT;
 236}
 237
 238void dss_sdi_disable(void)
 239{
 240        dispc_lcd_enable_signal(0);
 241
 242        dispc_pck_free_enable(0);
 243
 244        /* Reset SDI PLL */
 245        REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
 246}
 247
 248const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src)
 249{
 250        return dss_generic_clk_source_names[clk_src];
 251}
 252
 253void dss_dump_clocks(struct seq_file *s)
 254{
 255        const char *fclk_name, *fclk_real_name;
 256        unsigned long fclk_rate;
 257
 258        if (dss_runtime_get())
 259                return;
 260
 261        seq_printf(s, "- DSS -\n");
 262
 263        fclk_name = dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_FCK);
 264        fclk_real_name = dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_FCK);
 265        fclk_rate = clk_get_rate(dss.dss_clk);
 266
 267        seq_printf(s, "%s (%s) = %lu\n",
 268                        fclk_name, fclk_real_name,
 269                        fclk_rate);
 270
 271        dss_runtime_put();
 272}
 273
 274static void dss_dump_regs(struct seq_file *s)
 275{
 276#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r))
 277
 278        if (dss_runtime_get())
 279                return;
 280
 281        DUMPREG(DSS_REVISION);
 282        DUMPREG(DSS_SYSCONFIG);
 283        DUMPREG(DSS_SYSSTATUS);
 284        DUMPREG(DSS_CONTROL);
 285
 286        if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) &
 287                        OMAP_DISPLAY_TYPE_SDI) {
 288                DUMPREG(DSS_SDI_CONTROL);
 289                DUMPREG(DSS_PLL_CONTROL);
 290                DUMPREG(DSS_SDI_STATUS);
 291        }
 292
 293        dss_runtime_put();
 294#undef DUMPREG
 295}
 296
 297static void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src)
 298{
 299        int b;
 300        u8 start, end;
 301
 302        switch (clk_src) {
 303        case OMAP_DSS_CLK_SRC_FCK:
 304                b = 0;
 305                break;
 306        case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
 307                b = 1;
 308                break;
 309        case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
 310                b = 2;
 311                break;
 312        default:
 313                BUG();
 314                return;
 315        }
 316
 317        dss_feat_get_reg_field(FEAT_REG_DISPC_CLK_SWITCH, &start, &end);
 318
 319        REG_FLD_MOD(DSS_CONTROL, b, start, end);        /* DISPC_CLK_SWITCH */
 320
 321        dss.dispc_clk_source = clk_src;
 322}
 323
 324void dss_select_dsi_clk_source(int dsi_module,
 325                enum omap_dss_clk_source clk_src)
 326{
 327        int b, pos;
 328
 329        switch (clk_src) {
 330        case OMAP_DSS_CLK_SRC_FCK:
 331                b = 0;
 332                break;
 333        case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI:
 334                BUG_ON(dsi_module != 0);
 335                b = 1;
 336                break;
 337        case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI:
 338                BUG_ON(dsi_module != 1);
 339                b = 1;
 340                break;
 341        default:
 342                BUG();
 343                return;
 344        }
 345
 346        pos = dsi_module == 0 ? 1 : 10;
 347        REG_FLD_MOD(DSS_CONTROL, b, pos, pos);  /* DSIx_CLK_SWITCH */
 348
 349        dss.dsi_clk_source[dsi_module] = clk_src;
 350}
 351
 352void dss_select_lcd_clk_source(enum omap_channel channel,
 353                enum omap_dss_clk_source clk_src)
 354{
 355        int b, ix, pos;
 356
 357        if (!dss_has_feature(FEAT_LCD_CLK_SRC)) {
 358                dss_select_dispc_clk_source(clk_src);
 359                return;
 360        }
 361
 362        switch (clk_src) {
 363        case OMAP_DSS_CLK_SRC_FCK:
 364                b = 0;
 365                break;
 366        case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
 367                BUG_ON(channel != OMAP_DSS_CHANNEL_LCD);
 368                b = 1;
 369                break;
 370        case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
 371                BUG_ON(channel != OMAP_DSS_CHANNEL_LCD2 &&
 372                       channel != OMAP_DSS_CHANNEL_LCD3);
 373                b = 1;
 374                break;
 375        default:
 376                BUG();
 377                return;
 378        }
 379
 380        pos = channel == OMAP_DSS_CHANNEL_LCD ? 0 :
 381             (channel == OMAP_DSS_CHANNEL_LCD2 ? 12 : 19);
 382        REG_FLD_MOD(DSS_CONTROL, b, pos, pos);  /* LCDx_CLK_SWITCH */
 383
 384        ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 :
 385            (channel == OMAP_DSS_CHANNEL_LCD2 ? 1 : 2);
 386        dss.lcd_clk_source[ix] = clk_src;
 387}
 388
 389enum omap_dss_clk_source dss_get_dispc_clk_source(void)
 390{
 391        return dss.dispc_clk_source;
 392}
 393
 394enum omap_dss_clk_source dss_get_dsi_clk_source(int dsi_module)
 395{
 396        return dss.dsi_clk_source[dsi_module];
 397}
 398
 399enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel)
 400{
 401        if (dss_has_feature(FEAT_LCD_CLK_SRC)) {
 402                int ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 :
 403                        (channel == OMAP_DSS_CHANNEL_LCD2 ? 1 : 2);
 404                return dss.lcd_clk_source[ix];
 405        } else {
 406                /* LCD_CLK source is the same as DISPC_FCLK source for
 407                 * OMAP2 and OMAP3 */
 408                return dss.dispc_clk_source;
 409        }
 410}
 411
 412bool dss_div_calc(unsigned long pck, unsigned long fck_min,
 413                dss_div_calc_func func, void *data)
 414{
 415        int fckd, fckd_start, fckd_stop;
 416        unsigned long fck;
 417        unsigned long fck_hw_max;
 418        unsigned long fckd_hw_max;
 419        unsigned long prate;
 420        unsigned m;
 421
 422        fck_hw_max = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
 423
 424        if (dss.parent_clk == NULL) {
 425                unsigned pckd;
 426
 427                pckd = fck_hw_max / pck;
 428
 429                fck = pck * pckd;
 430
 431                fck = clk_round_rate(dss.dss_clk, fck);
 432
 433                return func(fck, data);
 434        }
 435
 436        fckd_hw_max = dss.feat->fck_div_max;
 437
 438        m = dss.feat->dss_fck_multiplier;
 439        prate = clk_get_rate(dss.parent_clk);
 440
 441        fck_min = fck_min ? fck_min : 1;
 442
 443        fckd_start = min(prate * m / fck_min, fckd_hw_max);
 444        fckd_stop = max(DIV_ROUND_UP(prate * m, fck_hw_max), 1ul);
 445
 446        for (fckd = fckd_start; fckd >= fckd_stop; --fckd) {
 447                fck = DIV_ROUND_UP(prate, fckd) * m;
 448
 449                if (func(fck, data))
 450                        return true;
 451        }
 452
 453        return false;
 454}
 455
 456int dss_set_fck_rate(unsigned long rate)
 457{
 458        int r;
 459
 460        DSSDBG("set fck to %lu\n", rate);
 461
 462        r = clk_set_rate(dss.dss_clk, rate);
 463        if (r)
 464                return r;
 465
 466        dss.dss_clk_rate = clk_get_rate(dss.dss_clk);
 467
 468        WARN_ONCE(dss.dss_clk_rate != rate,
 469                        "clk rate mismatch: %lu != %lu", dss.dss_clk_rate,
 470                        rate);
 471
 472        return 0;
 473}
 474
 475unsigned long dss_get_dispc_clk_rate(void)
 476{
 477        return dss.dss_clk_rate;
 478}
 479
 480static int dss_setup_default_clock(void)
 481{
 482        unsigned long max_dss_fck, prate;
 483        unsigned long fck;
 484        unsigned fck_div;
 485        int r;
 486
 487        max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
 488
 489        if (dss.parent_clk == NULL) {
 490                fck = clk_round_rate(dss.dss_clk, max_dss_fck);
 491        } else {
 492                prate = clk_get_rate(dss.parent_clk);
 493
 494                fck_div = DIV_ROUND_UP(prate * dss.feat->dss_fck_multiplier,
 495                                max_dss_fck);
 496                fck = DIV_ROUND_UP(prate, fck_div) * dss.feat->dss_fck_multiplier;
 497        }
 498
 499        r = dss_set_fck_rate(fck);
 500        if (r)
 501                return r;
 502
 503        return 0;
 504}
 505
 506void dss_set_venc_output(enum omap_dss_venc_type type)
 507{
 508        int l = 0;
 509
 510        if (type == OMAP_DSS_VENC_TYPE_COMPOSITE)
 511                l = 0;
 512        else if (type == OMAP_DSS_VENC_TYPE_SVIDEO)
 513                l = 1;
 514        else
 515                BUG();
 516
 517        /* venc out selection. 0 = comp, 1 = svideo */
 518        REG_FLD_MOD(DSS_CONTROL, l, 6, 6);
 519}
 520
 521void dss_set_dac_pwrdn_bgz(bool enable)
 522{
 523        REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */
 524}
 525
 526void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select src)
 527{
 528        enum omap_display_type dp;
 529        dp = dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_DIGIT);
 530
 531        /* Complain about invalid selections */
 532        WARN_ON((src == DSS_VENC_TV_CLK) && !(dp & OMAP_DISPLAY_TYPE_VENC));
 533        WARN_ON((src == DSS_HDMI_M_PCLK) && !(dp & OMAP_DISPLAY_TYPE_HDMI));
 534
 535        /* Select only if we have options */
 536        if ((dp & OMAP_DISPLAY_TYPE_VENC) && (dp & OMAP_DISPLAY_TYPE_HDMI))
 537                REG_FLD_MOD(DSS_CONTROL, src, 15, 15);  /* VENC_HDMI_SWITCH */
 538}
 539
 540enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void)
 541{
 542        enum omap_display_type displays;
 543
 544        displays = dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_DIGIT);
 545        if ((displays & OMAP_DISPLAY_TYPE_HDMI) == 0)
 546                return DSS_VENC_TV_CLK;
 547
 548        if ((displays & OMAP_DISPLAY_TYPE_VENC) == 0)
 549                return DSS_HDMI_M_PCLK;
 550
 551        return REG_GET(DSS_CONTROL, 15, 15);
 552}
 553
 554static int dss_dpi_select_source_omap2_omap3(int port, enum omap_channel channel)
 555{
 556        if (channel != OMAP_DSS_CHANNEL_LCD)
 557                return -EINVAL;
 558
 559        return 0;
 560}
 561
 562static int dss_dpi_select_source_omap4(int port, enum omap_channel channel)
 563{
 564        int val;
 565
 566        switch (channel) {
 567        case OMAP_DSS_CHANNEL_LCD2:
 568                val = 0;
 569                break;
 570        case OMAP_DSS_CHANNEL_DIGIT:
 571                val = 1;
 572                break;
 573        default:
 574                return -EINVAL;
 575        }
 576
 577        REG_FLD_MOD(DSS_CONTROL, val, 17, 17);
 578
 579        return 0;
 580}
 581
 582static int dss_dpi_select_source_omap5(int port, enum omap_channel channel)
 583{
 584        int val;
 585
 586        switch (channel) {
 587        case OMAP_DSS_CHANNEL_LCD:
 588                val = 1;
 589                break;
 590        case OMAP_DSS_CHANNEL_LCD2:
 591                val = 2;
 592                break;
 593        case OMAP_DSS_CHANNEL_LCD3:
 594                val = 3;
 595                break;
 596        case OMAP_DSS_CHANNEL_DIGIT:
 597                val = 0;
 598                break;
 599        default:
 600                return -EINVAL;
 601        }
 602
 603        REG_FLD_MOD(DSS_CONTROL, val, 17, 16);
 604
 605        return 0;
 606}
 607
 608int dss_dpi_select_source(int port, enum omap_channel channel)
 609{
 610        return dss.feat->dpi_select_source(port, channel);
 611}
 612
 613static int dss_get_clocks(void)
 614{
 615        struct clk *clk;
 616
 617        clk = devm_clk_get(&dss.pdev->dev, "fck");
 618        if (IS_ERR(clk)) {
 619                DSSERR("can't get clock fck\n");
 620                return PTR_ERR(clk);
 621        }
 622
 623        dss.dss_clk = clk;
 624
 625        if (dss.feat->parent_clk_name) {
 626                clk = clk_get(NULL, dss.feat->parent_clk_name);
 627                if (IS_ERR(clk)) {
 628                        DSSERR("Failed to get %s\n", dss.feat->parent_clk_name);
 629                        return PTR_ERR(clk);
 630                }
 631        } else {
 632                clk = NULL;
 633        }
 634
 635        dss.parent_clk = clk;
 636
 637        return 0;
 638}
 639
 640static void dss_put_clocks(void)
 641{
 642        if (dss.parent_clk)
 643                clk_put(dss.parent_clk);
 644}
 645
 646static int dss_runtime_get(void)
 647{
 648        int r;
 649
 650        DSSDBG("dss_runtime_get\n");
 651
 652        r = pm_runtime_get_sync(&dss.pdev->dev);
 653        WARN_ON(r < 0);
 654        return r < 0 ? r : 0;
 655}
 656
 657static void dss_runtime_put(void)
 658{
 659        int r;
 660
 661        DSSDBG("dss_runtime_put\n");
 662
 663        r = pm_runtime_put_sync(&dss.pdev->dev);
 664        WARN_ON(r < 0 && r != -ENOSYS && r != -EBUSY);
 665}
 666
 667/* DEBUGFS */
 668#if defined(CONFIG_OMAP2_DSS_DEBUGFS)
 669void dss_debug_dump_clocks(struct seq_file *s)
 670{
 671        dss_dump_clocks(s);
 672        dispc_dump_clocks(s);
 673#ifdef CONFIG_OMAP2_DSS_DSI
 674        dsi_dump_clocks(s);
 675#endif
 676}
 677#endif
 678
 679
 680static enum omap_display_type omap2plus_ports[] = {
 681        OMAP_DISPLAY_TYPE_DPI,
 682};
 683
 684static enum omap_display_type omap34xx_ports[] = {
 685        OMAP_DISPLAY_TYPE_DPI,
 686        OMAP_DISPLAY_TYPE_SDI,
 687};
 688
 689static const struct dss_features omap24xx_dss_feats __initconst = {
 690        /*
 691         * fck div max is really 16, but the divider range has gaps. The range
 692         * from 1 to 6 has no gaps, so let's use that as a max.
 693         */
 694        .fck_div_max            =       6,
 695        .dss_fck_multiplier     =       2,
 696        .parent_clk_name        =       "core_ck",
 697        .dpi_select_source      =       &dss_dpi_select_source_omap2_omap3,
 698        .ports                  =       omap2plus_ports,
 699        .num_ports              =       ARRAY_SIZE(omap2plus_ports),
 700};
 701
 702static const struct dss_features omap34xx_dss_feats __initconst = {
 703        .fck_div_max            =       16,
 704        .dss_fck_multiplier     =       2,
 705        .parent_clk_name        =       "dpll4_ck",
 706        .dpi_select_source      =       &dss_dpi_select_source_omap2_omap3,
 707        .ports                  =       omap34xx_ports,
 708        .num_ports              =       ARRAY_SIZE(omap34xx_ports),
 709};
 710
 711static const struct dss_features omap3630_dss_feats __initconst = {
 712        .fck_div_max            =       32,
 713        .dss_fck_multiplier     =       1,
 714        .parent_clk_name        =       "dpll4_ck",
 715        .dpi_select_source      =       &dss_dpi_select_source_omap2_omap3,
 716        .ports                  =       omap2plus_ports,
 717        .num_ports              =       ARRAY_SIZE(omap2plus_ports),
 718};
 719
 720static const struct dss_features omap44xx_dss_feats __initconst = {
 721        .fck_div_max            =       32,
 722        .dss_fck_multiplier     =       1,
 723        .parent_clk_name        =       "dpll_per_x2_ck",
 724        .dpi_select_source      =       &dss_dpi_select_source_omap4,
 725        .ports                  =       omap2plus_ports,
 726        .num_ports              =       ARRAY_SIZE(omap2plus_ports),
 727};
 728
 729static const struct dss_features omap54xx_dss_feats __initconst = {
 730        .fck_div_max            =       64,
 731        .dss_fck_multiplier     =       1,
 732        .parent_clk_name        =       "dpll_per_x2_ck",
 733        .dpi_select_source      =       &dss_dpi_select_source_omap5,
 734        .ports                  =       omap2plus_ports,
 735        .num_ports              =       ARRAY_SIZE(omap2plus_ports),
 736};
 737
 738static const struct dss_features am43xx_dss_feats __initconst = {
 739        .fck_div_max            =       0,
 740        .dss_fck_multiplier     =       0,
 741        .parent_clk_name        =       NULL,
 742        .dpi_select_source      =       &dss_dpi_select_source_omap2_omap3,
 743        .ports                  =       omap2plus_ports,
 744        .num_ports              =       ARRAY_SIZE(omap2plus_ports),
 745};
 746
 747static int __init dss_init_features(struct platform_device *pdev)
 748{
 749        const struct dss_features *src;
 750        struct dss_features *dst;
 751
 752        dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL);
 753        if (!dst) {
 754                dev_err(&pdev->dev, "Failed to allocate local DSS Features\n");
 755                return -ENOMEM;
 756        }
 757
 758        switch (omapdss_get_version()) {
 759        case OMAPDSS_VER_OMAP24xx:
 760                src = &omap24xx_dss_feats;
 761                break;
 762
 763        case OMAPDSS_VER_OMAP34xx_ES1:
 764        case OMAPDSS_VER_OMAP34xx_ES3:
 765        case OMAPDSS_VER_AM35xx:
 766                src = &omap34xx_dss_feats;
 767                break;
 768
 769        case OMAPDSS_VER_OMAP3630:
 770                src = &omap3630_dss_feats;
 771                break;
 772
 773        case OMAPDSS_VER_OMAP4430_ES1:
 774        case OMAPDSS_VER_OMAP4430_ES2:
 775        case OMAPDSS_VER_OMAP4:
 776                src = &omap44xx_dss_feats;
 777                break;
 778
 779        case OMAPDSS_VER_OMAP5:
 780                src = &omap54xx_dss_feats;
 781                break;
 782
 783        case OMAPDSS_VER_AM43xx:
 784                src = &am43xx_dss_feats;
 785                break;
 786
 787        default:
 788                return -ENODEV;
 789        }
 790
 791        memcpy(dst, src, sizeof(*dst));
 792        dss.feat = dst;
 793
 794        return 0;
 795}
 796
 797static int __init dss_init_ports(struct platform_device *pdev)
 798{
 799        struct device_node *parent = pdev->dev.of_node;
 800        struct device_node *port;
 801        int r;
 802
 803        if (parent == NULL)
 804                return 0;
 805
 806        port = omapdss_of_get_next_port(parent, NULL);
 807        if (!port)
 808                return 0;
 809
 810        if (dss.feat->num_ports == 0)
 811                return 0;
 812
 813        do {
 814                enum omap_display_type port_type;
 815                u32 reg;
 816
 817                r = of_property_read_u32(port, "reg", &reg);
 818                if (r)
 819                        reg = 0;
 820
 821                if (reg >= dss.feat->num_ports)
 822                        continue;
 823
 824                port_type = dss.feat->ports[reg];
 825
 826                switch (port_type) {
 827                case OMAP_DISPLAY_TYPE_DPI:
 828                        dpi_init_port(pdev, port);
 829                        break;
 830                case OMAP_DISPLAY_TYPE_SDI:
 831                        sdi_init_port(pdev, port);
 832                        break;
 833                default:
 834                        break;
 835                }
 836        } while ((port = omapdss_of_get_next_port(parent, port)) != NULL);
 837
 838        return 0;
 839}
 840
 841static void __exit dss_uninit_ports(struct platform_device *pdev)
 842{
 843        struct device_node *parent = pdev->dev.of_node;
 844        struct device_node *port;
 845
 846        if (parent == NULL)
 847                return;
 848
 849        port = omapdss_of_get_next_port(parent, NULL);
 850        if (!port)
 851                return;
 852
 853        if (dss.feat->num_ports == 0)
 854                return;
 855
 856        do {
 857                enum omap_display_type port_type;
 858                u32 reg;
 859                int r;
 860
 861                r = of_property_read_u32(port, "reg", &reg);
 862                if (r)
 863                        reg = 0;
 864
 865                if (reg >= dss.feat->num_ports)
 866                        continue;
 867
 868                port_type = dss.feat->ports[reg];
 869
 870                switch (port_type) {
 871                case OMAP_DISPLAY_TYPE_DPI:
 872                        dpi_uninit_port(port);
 873                        break;
 874                case OMAP_DISPLAY_TYPE_SDI:
 875                        sdi_uninit_port(port);
 876                        break;
 877                default:
 878                        break;
 879                }
 880        } while ((port = omapdss_of_get_next_port(parent, port)) != NULL);
 881}
 882
 883/* DSS HW IP initialisation */
 884static int __init omap_dsshw_probe(struct platform_device *pdev)
 885{
 886        struct resource *dss_mem;
 887        u32 rev;
 888        int r;
 889
 890        dss.pdev = pdev;
 891
 892        r = dss_init_features(dss.pdev);
 893        if (r)
 894                return r;
 895
 896        dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0);
 897        if (!dss_mem) {
 898                DSSERR("can't get IORESOURCE_MEM DSS\n");
 899                return -EINVAL;
 900        }
 901
 902        dss.base = devm_ioremap(&pdev->dev, dss_mem->start,
 903                                resource_size(dss_mem));
 904        if (!dss.base) {
 905                DSSERR("can't ioremap DSS\n");
 906                return -ENOMEM;
 907        }
 908
 909        r = dss_get_clocks();
 910        if (r)
 911                return r;
 912
 913        r = dss_setup_default_clock();
 914        if (r)
 915                goto err_setup_clocks;
 916
 917        pm_runtime_enable(&pdev->dev);
 918
 919        r = dss_runtime_get();
 920        if (r)
 921                goto err_runtime_get;
 922
 923        dss.dss_clk_rate = clk_get_rate(dss.dss_clk);
 924
 925        /* Select DPLL */
 926        REG_FLD_MOD(DSS_CONTROL, 0, 0, 0);
 927
 928        dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
 929
 930#ifdef CONFIG_OMAP2_DSS_VENC
 931        REG_FLD_MOD(DSS_CONTROL, 1, 4, 4);      /* venc dac demen */
 932        REG_FLD_MOD(DSS_CONTROL, 1, 3, 3);      /* venc clock 4x enable */
 933        REG_FLD_MOD(DSS_CONTROL, 0, 2, 2);      /* venc clock mode = normal */
 934#endif
 935        dss.dsi_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
 936        dss.dsi_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
 937        dss.dispc_clk_source = OMAP_DSS_CLK_SRC_FCK;
 938        dss.lcd_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
 939        dss.lcd_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
 940
 941        dss_init_ports(pdev);
 942
 943        rev = dss_read_reg(DSS_REVISION);
 944        printk(KERN_INFO "OMAP DSS rev %d.%d\n",
 945                        FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
 946
 947        dss_runtime_put();
 948
 949        dss_debugfs_create_file("dss", dss_dump_regs);
 950
 951        return 0;
 952
 953err_runtime_get:
 954        pm_runtime_disable(&pdev->dev);
 955err_setup_clocks:
 956        dss_put_clocks();
 957        return r;
 958}
 959
 960static int __exit omap_dsshw_remove(struct platform_device *pdev)
 961{
 962        dss_uninit_ports(pdev);
 963
 964        pm_runtime_disable(&pdev->dev);
 965
 966        dss_put_clocks();
 967
 968        return 0;
 969}
 970
 971static int dss_runtime_suspend(struct device *dev)
 972{
 973        dss_save_context();
 974        dss_set_min_bus_tput(dev, 0);
 975        return 0;
 976}
 977
 978static int dss_runtime_resume(struct device *dev)
 979{
 980        int r;
 981        /*
 982         * Set an arbitrarily high tput request to ensure OPP100.
 983         * What we should really do is to make a request to stay in OPP100,
 984         * without any tput requirements, but that is not currently possible
 985         * via the PM layer.
 986         */
 987
 988        r = dss_set_min_bus_tput(dev, 1000000000);
 989        if (r)
 990                return r;
 991
 992        dss_restore_context();
 993        return 0;
 994}
 995
 996static const struct dev_pm_ops dss_pm_ops = {
 997        .runtime_suspend = dss_runtime_suspend,
 998        .runtime_resume = dss_runtime_resume,
 999};
1000
1001static const struct of_device_id dss_of_match[] = {
1002        { .compatible = "ti,omap2-dss", },
1003        { .compatible = "ti,omap3-dss", },
1004        { .compatible = "ti,omap4-dss", },
1005        { .compatible = "ti,omap5-dss", },
1006        {},
1007};
1008
1009MODULE_DEVICE_TABLE(of, dss_of_match);
1010
1011static struct platform_driver omap_dsshw_driver = {
1012        .remove         = __exit_p(omap_dsshw_remove),
1013        .driver         = {
1014                .name   = "omapdss_dss",
1015                .pm     = &dss_pm_ops,
1016                .of_match_table = dss_of_match,
1017                .suppress_bind_attrs = true,
1018        },
1019};
1020
1021int __init dss_init_platform_driver(void)
1022{
1023        return platform_driver_probe(&omap_dsshw_driver, omap_dsshw_probe);
1024}
1025
1026void dss_uninit_platform_driver(void)
1027{
1028        platform_driver_unregister(&omap_dsshw_driver);
1029}
1030
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.