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 35#include <video/omapdss.h> 36 37#include <plat/cpu.h> 38#include <plat/clock.h> 39 40#include "dss.h" 41#include "dss_features.h" 42 43#define DSS_SZ_REGS SZ_512 44 45struct dss_reg { 46 u16 idx; 47}; 48 49#define DSS_REG(idx) ((const struct dss_reg) { idx }) 50 51#define DSS_REVISION DSS_REG(0x0000) 52#define DSS_SYSCONFIG DSS_REG(0x0010) 53#define DSS_SYSSTATUS DSS_REG(0x0014) 54#define DSS_CONTROL DSS_REG(0x0040) 55#define DSS_SDI_CONTROL DSS_REG(0x0044) 56#define DSS_PLL_CONTROL DSS_REG(0x0048) 57#define DSS_SDI_STATUS DSS_REG(0x005C) 58 59#define REG_GET(idx, start, end) \ 60 FLD_GET(dss_read_reg(idx), start, end) 61 62#define REG_FLD_MOD(idx, val, start, end) \ 63 dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end)) 64 65static struct { 66 struct platform_device *pdev; 67 void __iomem *base; 68 69 struct clk *dpll4_m4_ck; 70 struct clk *dss_clk; 71 72 unsigned long cache_req_pck; 73 unsigned long cache_prate; 74 struct dss_clock_info cache_dss_cinfo; 75 struct dispc_clock_info cache_dispc_cinfo; 76 77 enum omap_dss_clk_source dsi_clk_source[MAX_NUM_DSI]; 78 enum omap_dss_clk_source dispc_clk_source; 79 enum omap_dss_clk_source lcd_clk_source[MAX_DSS_LCD_MANAGERS]; 80 81 bool ctx_valid; 82 u32 ctx[DSS_SZ_REGS / sizeof(u32)]; 83} dss; 84 85static const char * const dss_generic_clk_source_names[] = { 86 [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DSI_PLL_HSDIV_DISPC", 87 [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DSI_PLL_HSDIV_DSI", 88 [OMAP_DSS_CLK_SRC_FCK] = "DSS_FCK", 89}; 90 91static inline void dss_write_reg(const struct dss_reg idx, u32 val) 92{ 93 __raw_writel(val, dss.base + idx.idx); 94} 95 96static inline u32 dss_read_reg(const struct dss_reg idx) 97{ 98 return __raw_readl(dss.base + idx.idx); 99} 100 101#define SR(reg) \ 102 dss.ctx[(DSS_##reg).idx / sizeof(u32)] = dss_read_reg(DSS_##reg) 103#define RR(reg) \ 104 dss_write_reg(DSS_##reg, dss.ctx[(DSS_##reg).idx / sizeof(u32)]) 105 106static void dss_save_context(void) 107{ 108 DSSDBG("dss_save_context\n"); 109 110 SR(CONTROL); 111 112 if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) & 113 OMAP_DISPLAY_TYPE_SDI) { 114 SR(SDI_CONTROL); 115 SR(PLL_CONTROL); 116 } 117 118 dss.ctx_valid = true; 119 120 DSSDBG("context saved\n"); 121} 122 123static void dss_restore_context(void) 124{ 125 DSSDBG("dss_restore_context\n"); 126 127 if (!dss.ctx_valid) 128 return; 129 130 RR(CONTROL); 131 132 if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) & 133 OMAP_DISPLAY_TYPE_SDI) { 134 RR(SDI_CONTROL); 135 RR(PLL_CONTROL); 136 } 137 138 DSSDBG("context restored\n"); 139} 140 141#undef SR 142#undef RR 143 144void dss_sdi_init(u8 datapairs) 145{ 146 u32 l; 147 148 BUG_ON(datapairs > 3 || datapairs < 1); 149 150 l = dss_read_reg(DSS_SDI_CONTROL); 151 l = FLD_MOD(l, 0xf, 19, 15); /* SDI_PDIV */ 152 l = FLD_MOD(l, datapairs-1, 3, 2); /* SDI_PRSEL */ 153 l = FLD_MOD(l, 2, 1, 0); /* SDI_BWSEL */ 154 dss_write_reg(DSS_SDI_CONTROL, l); 155 156 l = dss_read_reg(DSS_PLL_CONTROL); 157 l = FLD_MOD(l, 0x7, 25, 22); /* SDI_PLL_FREQSEL */ 158 l = FLD_MOD(l, 0xb, 16, 11); /* SDI_PLL_REGN */ 159 l = FLD_MOD(l, 0xb4, 10, 1); /* SDI_PLL_REGM */ 160 dss_write_reg(DSS_PLL_CONTROL, l); 161} 162 163int dss_sdi_enable(void) 164{ 165 unsigned long timeout; 166 167 dispc_pck_free_enable(1); 168 169 /* Reset SDI PLL */ 170 REG_FLD_MOD(DSS_PLL_CONTROL, 1, 18, 18); /* SDI_PLL_SYSRESET */ 171 udelay(1); /* wait 2x PCLK */ 172 173 /* Lock SDI PLL */ 174 REG_FLD_MOD(DSS_PLL_CONTROL, 1, 28, 28); /* SDI_PLL_GOBIT */ 175 176 /* Waiting for PLL lock request to complete */ 177 timeout = jiffies + msecs_to_jiffies(500); 178 while (dss_read_reg(DSS_SDI_STATUS) & (1 << 6)) { 179 if (time_after_eq(jiffies, timeout)) { 180 DSSERR("PLL lock request timed out\n"); 181 goto err1; 182 } 183 } 184 185 /* Clearing PLL_GO bit */ 186 REG_FLD_MOD(DSS_PLL_CONTROL, 0, 28, 28); 187 188 /* Waiting for PLL to lock */ 189 timeout = jiffies + msecs_to_jiffies(500); 190 while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 5))) { 191 if (time_after_eq(jiffies, timeout)) { 192 DSSERR("PLL lock timed out\n"); 193 goto err1; 194 } 195 } 196 197 dispc_lcd_enable_signal(1); 198 199 /* Waiting for SDI reset to complete */ 200 timeout = jiffies + msecs_to_jiffies(500); 201 while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 2))) { 202 if (time_after_eq(jiffies, timeout)) { 203 DSSERR("SDI reset timed out\n"); 204 goto err2; 205 } 206 } 207 208 return 0; 209 210 err2: 211 dispc_lcd_enable_signal(0); 212 err1: 213 /* Reset SDI PLL */ 214 REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */ 215 216 dispc_pck_free_enable(0); 217 218 return -ETIMEDOUT; 219} 220 221void dss_sdi_disable(void) 222{ 223 dispc_lcd_enable_signal(0); 224 225 dispc_pck_free_enable(0); 226 227 /* Reset SDI PLL */ 228 REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */ 229} 230 231const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src) 232{ 233 return dss_generic_clk_source_names[clk_src]; 234} 235 236 237void dss_dump_clocks(struct seq_file *s) 238{ 239 unsigned long dpll4_ck_rate; 240 unsigned long dpll4_m4_ck_rate; 241 const char *fclk_name, *fclk_real_name; 242 unsigned long fclk_rate; 243 244 if (dss_runtime_get()) 245 return; 246 247 seq_printf(s, "- DSS -\n"); 248 249 fclk_name = dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_FCK); 250 fclk_real_name = dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_FCK); 251 fclk_rate = clk_get_rate(dss.dss_clk); 252 253 if (dss.dpll4_m4_ck) { 254 dpll4_ck_rate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); 255 dpll4_m4_ck_rate = clk_get_rate(dss.dpll4_m4_ck); 256 257 seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate); 258 259 if (cpu_is_omap3630() || cpu_is_omap44xx()) 260 seq_printf(s, "%s (%s) = %lu / %lu = %lu\n", 261 fclk_name, fclk_real_name, 262 dpll4_ck_rate, 263 dpll4_ck_rate / dpll4_m4_ck_rate, 264 fclk_rate); 265 else 266 seq_printf(s, "%s (%s) = %lu / %lu * 2 = %lu\n", 267 fclk_name, fclk_real_name, 268 dpll4_ck_rate, 269 dpll4_ck_rate / dpll4_m4_ck_rate, 270 fclk_rate); 271 } else { 272 seq_printf(s, "%s (%s) = %lu\n", 273 fclk_name, fclk_real_name, 274 fclk_rate); 275 } 276 277 dss_runtime_put(); 278} 279 280void dss_dump_regs(struct seq_file *s) 281{ 282#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r)) 283 284 if (dss_runtime_get()) 285 return; 286 287 DUMPREG(DSS_REVISION); 288 DUMPREG(DSS_SYSCONFIG); 289 DUMPREG(DSS_SYSSTATUS); 290 DUMPREG(DSS_CONTROL); 291 292 if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) & 293 OMAP_DISPLAY_TYPE_SDI) { 294 DUMPREG(DSS_SDI_CONTROL); 295 DUMPREG(DSS_PLL_CONTROL); 296 DUMPREG(DSS_SDI_STATUS); 297 } 298 299 dss_runtime_put(); 300#undef DUMPREG 301} 302 303void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src) 304{ 305 struct platform_device *dsidev; 306 int b; 307 u8 start, end; 308 309 switch (clk_src) { 310 case OMAP_DSS_CLK_SRC_FCK: 311 b = 0; 312 break; 313 case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: 314 b = 1; 315 dsidev = dsi_get_dsidev_from_id(0); 316 dsi_wait_pll_hsdiv_dispc_active(dsidev); 317 break; 318 case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC: 319 b = 2; 320 dsidev = dsi_get_dsidev_from_id(1); 321 dsi_wait_pll_hsdiv_dispc_active(dsidev); 322 break; 323 default: 324 BUG(); 325 } 326 327 dss_feat_get_reg_field(FEAT_REG_DISPC_CLK_SWITCH, &start, &end); 328 329 REG_FLD_MOD(DSS_CONTROL, b, start, end); /* DISPC_CLK_SWITCH */ 330 331 dss.dispc_clk_source = clk_src; 332} 333 334void dss_select_dsi_clk_source(int dsi_module, 335 enum omap_dss_clk_source clk_src) 336{ 337 struct platform_device *dsidev; 338 int b; 339 340 switch (clk_src) { 341 case OMAP_DSS_CLK_SRC_FCK: 342 b = 0; 343 break; 344 case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI: 345 BUG_ON(dsi_module != 0); 346 b = 1; 347 dsidev = dsi_get_dsidev_from_id(0); 348 dsi_wait_pll_hsdiv_dsi_active(dsidev); 349 break; 350 case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI: 351 BUG_ON(dsi_module != 1); 352 b = 1; 353 dsidev = dsi_get_dsidev_from_id(1); 354 dsi_wait_pll_hsdiv_dsi_active(dsidev); 355 break; 356 default: 357 BUG(); 358 } 359 360 REG_FLD_MOD(DSS_CONTROL, b, 1, 1); /* DSI_CLK_SWITCH */ 361 362 dss.dsi_clk_source[dsi_module] = clk_src; 363} 364 365void dss_select_lcd_clk_source(enum omap_channel channel, 366 enum omap_dss_clk_source clk_src) 367{ 368 struct platform_device *dsidev; 369 int b, ix, pos; 370 371 if (!dss_has_feature(FEAT_LCD_CLK_SRC)) 372 return; 373 374 switch (clk_src) { 375 case OMAP_DSS_CLK_SRC_FCK: 376 b = 0; 377 break; 378 case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: 379 BUG_ON(channel != OMAP_DSS_CHANNEL_LCD); 380 b = 1; 381 dsidev = dsi_get_dsidev_from_id(0); 382 dsi_wait_pll_hsdiv_dispc_active(dsidev); 383 break; 384 case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC: 385 BUG_ON(channel != OMAP_DSS_CHANNEL_LCD2); 386 b = 1; 387 dsidev = dsi_get_dsidev_from_id(1); 388 dsi_wait_pll_hsdiv_dispc_active(dsidev); 389 break; 390 default: 391 BUG(); 392 } 393 394 pos = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 12; 395 REG_FLD_MOD(DSS_CONTROL, b, pos, pos); /* LCDx_CLK_SWITCH */ 396 397 ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 1; 398 dss.lcd_clk_source[ix] = clk_src; 399} 400 401enum omap_dss_clk_source dss_get_dispc_clk_source(void) 402{ 403 return dss.dispc_clk_source; 404} 405 406enum omap_dss_clk_source dss_get_dsi_clk_source(int dsi_module) 407{ 408 return dss.dsi_clk_source[dsi_module]; 409} 410 411enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel) 412{ 413 if (dss_has_feature(FEAT_LCD_CLK_SRC)) { 414 int ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 1; 415 return dss.lcd_clk_source[ix]; 416 } else { 417 /* LCD_CLK source is the same as DISPC_FCLK source for 418 * OMAP2 and OMAP3 */ 419 return dss.dispc_clk_source; 420 } 421} 422 423/* calculate clock rates using dividers in cinfo */ 424int dss_calc_clock_rates(struct dss_clock_info *cinfo) 425{ 426 if (dss.dpll4_m4_ck) { 427 unsigned long prate; 428 u16 fck_div_max = 16; 429 430 if (cpu_is_omap3630() || cpu_is_omap44xx()) 431 fck_div_max = 32; 432 433 if (cinfo->fck_div > fck_div_max || cinfo->fck_div == 0) 434 return -EINVAL; 435 436 prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); 437 438 cinfo->fck = prate / cinfo->fck_div; 439 } else { 440 if (cinfo->fck_div != 0) 441 return -EINVAL; 442 cinfo->fck = clk_get_rate(dss.dss_clk); 443 } 444 445 return 0; 446} 447 448int dss_set_clock_div(struct dss_clock_info *cinfo) 449{ 450 if (dss.dpll4_m4_ck) { 451 unsigned long prate; 452 int r; 453 454 prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); 455 DSSDBG("dpll4_m4 = %ld\n", prate); 456 457 r = clk_set_rate(dss.dpll4_m4_ck, prate / cinfo->fck_div); 458 if (r) 459 return r; 460 } else { 461 if (cinfo->fck_div != 0) 462 return -EINVAL; 463 } 464 465 DSSDBG("fck = %ld (%d)\n", cinfo->fck, cinfo->fck_div); 466 467 return 0; 468} 469 470int dss_get_clock_div(struct dss_clock_info *cinfo) 471{ 472 cinfo->fck = clk_get_rate(dss.dss_clk); 473 474 if (dss.dpll4_m4_ck) { 475 unsigned long prate; 476 477 prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); 478 479 if (cpu_is_omap3630() || cpu_is_omap44xx()) 480 cinfo->fck_div = prate / (cinfo->fck); 481 else 482 cinfo->fck_div = prate / (cinfo->fck / 2); 483 } else { 484 cinfo->fck_div = 0; 485 } 486 487 return 0; 488} 489 490unsigned long dss_get_dpll4_rate(void) 491{ 492 if (dss.dpll4_m4_ck) 493 return clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); 494 else 495 return 0; 496} 497 498int dss_calc_clock_div(bool is_tft, unsigned long req_pck, 499 struct dss_clock_info *dss_cinfo, 500 struct dispc_clock_info *dispc_cinfo) 501{ 502 unsigned long prate; 503 struct dss_clock_info best_dss; 504 struct dispc_clock_info best_dispc; 505 506 unsigned long fck, max_dss_fck; 507 508 u16 fck_div, fck_div_max = 16; 509 510 int match = 0; 511 int min_fck_per_pck; 512 513 prate = dss_get_dpll4_rate(); 514 515 max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); 516 517 fck = clk_get_rate(dss.dss_clk); 518 if (req_pck == dss.cache_req_pck && 519 ((cpu_is_omap34xx() && prate == dss.cache_prate) || 520 dss.cache_dss_cinfo.fck == fck)) { 521 DSSDBG("dispc clock info found from cache.\n"); 522 *dss_cinfo = dss.cache_dss_cinfo; 523 *dispc_cinfo = dss.cache_dispc_cinfo; 524 return 0; 525 } 526 527 min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK; 528 529 if (min_fck_per_pck && 530 req_pck * min_fck_per_pck > max_dss_fck) { 531 DSSERR("Requested pixel clock not possible with the current " 532 "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning " 533 "the constraint off.\n"); 534 min_fck_per_pck = 0; 535 } 536 537retry: 538 memset(&best_dss, 0, sizeof(best_dss)); 539 memset(&best_dispc, 0, sizeof(best_dispc)); 540 541 if (dss.dpll4_m4_ck == NULL) { 542 struct dispc_clock_info cur_dispc; 543 /* XXX can we change the clock on omap2? */ 544 fck = clk_get_rate(dss.dss_clk); 545 fck_div = 1; 546 547 dispc_find_clk_divs(is_tft, req_pck, fck, &cur_dispc); 548 match = 1; 549 550 best_dss.fck = fck; 551 best_dss.fck_div = fck_div; 552 553 best_dispc = cur_dispc; 554 555 goto found; 556 } else { 557 if (cpu_is_omap3630() || cpu_is_omap44xx()) 558 fck_div_max = 32; 559 560 for (fck_div = fck_div_max; fck_div > 0; --fck_div) { 561 struct dispc_clock_info cur_dispc; 562 563 if (fck_div_max == 32) 564 fck = prate / fck_div; 565 else 566 fck = prate / fck_div * 2; 567 568 if (fck > max_dss_fck) 569 continue; 570 571 if (min_fck_per_pck && 572 fck < req_pck * min_fck_per_pck) 573 continue; 574 575 match = 1; 576 577 dispc_find_clk_divs(is_tft, req_pck, fck, &cur_dispc); 578 579 if (abs(cur_dispc.pck - req_pck) < 580 abs(best_dispc.pck - req_pck)) { 581 582 best_dss.fck = fck; 583 best_dss.fck_div = fck_div; 584 585 best_dispc = cur_dispc; 586 587 if (cur_dispc.pck == req_pck) 588 goto found; 589 } 590 } 591 } 592 593found: 594 if (!match) { 595 if (min_fck_per_pck) { 596 DSSERR("Could not find suitable clock settings.\n" 597 "Turning FCK/PCK constraint off and" 598 "trying again.\n"); 599 min_fck_per_pck = 0; 600 goto retry; 601 } 602 603 DSSERR("Could not find suitable clock settings.\n"); 604 605 return -EINVAL; 606 } 607 608 if (dss_cinfo) 609 *dss_cinfo = best_dss; 610 if (dispc_cinfo) 611 *dispc_cinfo = best_dispc; 612 613 dss.cache_req_pck = req_pck; 614 dss.cache_prate = prate; 615 dss.cache_dss_cinfo = best_dss; 616 dss.cache_dispc_cinfo = best_dispc; 617 618 return 0; 619} 620 621void dss_set_venc_output(enum omap_dss_venc_type type) 622{ 623 int l = 0; 624 625 if (type == OMAP_DSS_VENC_TYPE_COMPOSITE) 626 l = 0; 627 else if (type == OMAP_DSS_VENC_TYPE_SVIDEO) 628 l = 1; 629 else 630 BUG(); 631 632 /* venc out selection. 0 = comp, 1 = svideo */ 633 REG_FLD_MOD(DSS_CONTROL, l, 6, 6); 634} 635 636void dss_set_dac_pwrdn_bgz(bool enable) 637{ 638 REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */ 639} 640 641void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select hdmi) 642{ 643 REG_FLD_MOD(DSS_CONTROL, hdmi, 15, 15); /* VENC_HDMI_SWITCH */ 644} 645 646enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void) 647{ 648 enum omap_display_type displays; 649 650 displays = dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_DIGIT); 651 if ((displays & OMAP_DISPLAY_TYPE_HDMI) == 0) 652 return DSS_VENC_TV_CLK; 653 654 return REG_GET(DSS_CONTROL, 15, 15); 655} 656 657static int dss_get_clocks(void) 658{ 659 struct clk *clk; 660 int r; 661 662 clk = clk_get(&dss.pdev->dev, "fck"); 663 if (IS_ERR(clk)) { 664 DSSERR("can't get clock fck\n"); 665 r = PTR_ERR(clk); 666 goto err; 667 } 668 669 dss.dss_clk = clk; 670 671 if (cpu_is_omap34xx()) { 672 clk = clk_get(NULL, "dpll4_m4_ck"); 673 if (IS_ERR(clk)) { 674 DSSERR("Failed to get dpll4_m4_ck\n"); 675 r = PTR_ERR(clk); 676 goto err; 677 } 678 } else if (cpu_is_omap44xx()) { 679 clk = clk_get(NULL, "dpll_per_m5x2_ck"); 680 if (IS_ERR(clk)) { 681 DSSERR("Failed to get dpll_per_m5x2_ck\n"); 682 r = PTR_ERR(clk); 683 goto err; 684 } 685 } else { /* omap24xx */ 686 clk = NULL; 687 } 688 689 dss.dpll4_m4_ck = clk; 690 691 return 0; 692 693err: 694 if (dss.dss_clk) 695 clk_put(dss.dss_clk); 696 if (dss.dpll4_m4_ck) 697 clk_put(dss.dpll4_m4_ck); 698 699 return r; 700} 701 702static void dss_put_clocks(void) 703{ 704 if (dss.dpll4_m4_ck) 705 clk_put(dss.dpll4_m4_ck); 706 clk_put(dss.dss_clk); 707} 708 709int dss_runtime_get(void) 710{ 711 int r; 712 713 DSSDBG("dss_runtime_get\n"); 714 715 r = pm_runtime_get_sync(&dss.pdev->dev); 716 WARN_ON(r < 0); 717 return r < 0 ? r : 0; 718} 719 720void dss_runtime_put(void) 721{ 722 int r; 723 724 DSSDBG("dss_runtime_put\n"); 725 726 r = pm_runtime_put_sync(&dss.pdev->dev); 727 WARN_ON(r < 0); 728} 729 730/* DEBUGFS */ 731#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) 732void dss_debug_dump_clocks(struct seq_file *s) 733{ 734 dss_dump_clocks(s); 735 dispc_dump_clocks(s); 736#ifdef CONFIG_OMAP2_DSS_DSI 737 dsi_dump_clocks(s); 738#endif 739} 740#endif 741 742/* DSS HW IP initialisation */ 743static int omap_dsshw_probe(struct platform_device *pdev) 744{ 745 struct resource *dss_mem; 746 u32 rev; 747 int r; 748 749 dss.pdev = pdev; 750 751 dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0); 752 if (!dss_mem) { 753 DSSERR("can't get IORESOURCE_MEM DSS\n"); 754 return -EINVAL; 755 } 756 757 dss.base = devm_ioremap(&pdev->dev, dss_mem->start, 758 resource_size(dss_mem)); 759 if (!dss.base) { 760 DSSERR("can't ioremap DSS\n"); 761 return -ENOMEM; 762 } 763 764 r = dss_get_clocks(); 765 if (r) 766 return r; 767 768 pm_runtime_enable(&pdev->dev); 769 770 r = dss_runtime_get(); 771 if (r) 772 goto err_runtime_get; 773 774 /* Select DPLL */ 775 REG_FLD_MOD(DSS_CONTROL, 0, 0, 0); 776 777#ifdef CONFIG_OMAP2_DSS_VENC 778 REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */ 779 REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */ 780 REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */ 781#endif 782 dss.dsi_clk_source[0] = OMAP_DSS_CLK_SRC_FCK; 783 dss.dsi_clk_source[1] = OMAP_DSS_CLK_SRC_FCK; 784 dss.dispc_clk_source = OMAP_DSS_CLK_SRC_FCK; 785 dss.lcd_clk_source[0] = OMAP_DSS_CLK_SRC_FCK; 786 dss.lcd_clk_source[1] = OMAP_DSS_CLK_SRC_FCK; 787 788 r = dpi_init(); 789 if (r) { 790 DSSERR("Failed to initialize DPI\n"); 791 goto err_dpi; 792 } 793 794 r = sdi_init(); 795 if (r) { 796 DSSERR("Failed to initialize SDI\n"); 797 goto err_sdi; 798 } 799 800 rev = dss_read_reg(DSS_REVISION); 801 printk(KERN_INFO "OMAP DSS rev %d.%d\n", 802 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); 803 804 dss_runtime_put(); 805 806 return 0; 807err_sdi: 808 dpi_exit(); 809err_dpi: 810 dss_runtime_put(); 811err_runtime_get: 812 pm_runtime_disable(&pdev->dev); 813 dss_put_clocks(); 814 return r; 815} 816 817static int omap_dsshw_remove(struct platform_device *pdev) 818{ 819 dpi_exit(); 820 sdi_exit(); 821 822 pm_runtime_disable(&pdev->dev); 823 824 dss_put_clocks(); 825 826 return 0; 827} 828 829static int dss_runtime_suspend(struct device *dev) 830{ 831 dss_save_context(); 832 return 0; 833} 834 835static int dss_runtime_resume(struct device *dev) 836{ 837 dss_restore_context(); 838 return 0; 839} 840 841static const struct dev_pm_ops dss_pm_ops = { 842 .runtime_suspend = dss_runtime_suspend, 843 .runtime_resume = dss_runtime_resume, 844}; 845 846static struct platform_driver omap_dsshw_driver = { 847 .probe = omap_dsshw_probe, 848 .remove = omap_dsshw_remove, 849 .driver = { 850 .name = "omapdss_dss", 851 .owner = THIS_MODULE, 852 .pm = &dss_pm_ops, 853 }, 854}; 855 856int dss_init_platform_driver(void) 857{ 858 return platform_driver_register(&omap_dsshw_driver); 859} 860 861void dss_uninit_platform_driver(void) 862{ 863 return platform_driver_unregister(&omap_dsshw_driver); 864} 865