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