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