root/arch/arm/mach-omap2/display.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. omap4_dsi_mux_pads
  2. omap_dsi_enable_pads
  3. omap_dsi_disable_pads
  4. omap_display_get_version
  5. omapdss_init_fbdev
  6. omapdss_find_dss_of_node
  7. omapdss_init_of
  8. dispc_disable_outputs
  9. omap_dss_reset

   1 /*
   2  * OMAP2plus display device setup / initialization.
   3  *
   4  * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
   5  *      Senthilvadivu Guruswamy
   6  *      Sumit Semwal
   7  *
   8  * This program is free software; you can redistribute it and/or modify
   9  * it under the terms of the GNU General Public License version 2 as
  10  * published by the Free Software Foundation.
  11  *
  12  * This program is distributed "as is" WITHOUT ANY WARRANTY of any
  13  * kind, whether express or implied; without even the implied warranty
  14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15  * GNU General Public License for more details.
  16  */
  17 
  18 #include <linux/string.h>
  19 #include <linux/kernel.h>
  20 #include <linux/init.h>
  21 #include <linux/platform_device.h>
  22 #include <linux/io.h>
  23 #include <linux/clk.h>
  24 #include <linux/err.h>
  25 #include <linux/delay.h>
  26 #include <linux/of.h>
  27 #include <linux/of_platform.h>
  28 #include <linux/slab.h>
  29 #include <linux/mfd/syscon.h>
  30 #include <linux/regmap.h>
  31 
  32 #include <linux/platform_data/omapdss.h>
  33 #include "omap_hwmod.h"
  34 #include "omap_device.h"
  35 #include "common.h"
  36 
  37 #include "soc.h"
  38 #include "iomap.h"
  39 #include "control.h"
  40 #include "display.h"
  41 #include "prm.h"
  42 
  43 #define DISPC_CONTROL           0x0040
  44 #define DISPC_CONTROL2          0x0238
  45 #define DISPC_CONTROL3          0x0848
  46 #define DISPC_IRQSTATUS         0x0018
  47 
  48 #define DSS_CONTROL             0x40
  49 #define DSS_SDI_CONTROL         0x44
  50 #define DSS_PLL_CONTROL         0x48
  51 
  52 #define LCD_EN_MASK             (0x1 << 0)
  53 #define DIGIT_EN_MASK           (0x1 << 1)
  54 
  55 #define FRAMEDONE_IRQ_SHIFT     0
  56 #define EVSYNC_EVEN_IRQ_SHIFT   2
  57 #define EVSYNC_ODD_IRQ_SHIFT    3
  58 #define FRAMEDONE2_IRQ_SHIFT    22
  59 #define FRAMEDONE3_IRQ_SHIFT    30
  60 #define FRAMEDONETV_IRQ_SHIFT   24
  61 
  62 /*
  63  * FRAMEDONE_IRQ_TIMEOUT: how long (in milliseconds) to wait during DISPC
  64  *     reset before deciding that something has gone wrong
  65  */
  66 #define FRAMEDONE_IRQ_TIMEOUT           100
  67 
  68 #if defined(CONFIG_FB_OMAP2)
  69 static struct platform_device omap_display_device = {
  70         .name          = "omapdss",
  71         .id            = -1,
  72         .dev            = {
  73                 .platform_data = NULL,
  74         },
  75 };
  76 
  77 #define OMAP4_DSIPHY_SYSCON_OFFSET              0x78
  78 
  79 static struct regmap *omap4_dsi_mux_syscon;
  80 
  81 static int omap4_dsi_mux_pads(int dsi_id, unsigned lanes)
  82 {
  83         u32 enable_mask, enable_shift;
  84         u32 pipd_mask, pipd_shift;
  85         u32 reg;
  86         int ret;
  87 
  88         if (dsi_id == 0) {
  89                 enable_mask = OMAP4_DSI1_LANEENABLE_MASK;
  90                 enable_shift = OMAP4_DSI1_LANEENABLE_SHIFT;
  91                 pipd_mask = OMAP4_DSI1_PIPD_MASK;
  92                 pipd_shift = OMAP4_DSI1_PIPD_SHIFT;
  93         } else if (dsi_id == 1) {
  94                 enable_mask = OMAP4_DSI2_LANEENABLE_MASK;
  95                 enable_shift = OMAP4_DSI2_LANEENABLE_SHIFT;
  96                 pipd_mask = OMAP4_DSI2_PIPD_MASK;
  97                 pipd_shift = OMAP4_DSI2_PIPD_SHIFT;
  98         } else {
  99                 return -ENODEV;
 100         }
 101 
 102         ret = regmap_read(omap4_dsi_mux_syscon,
 103                                           OMAP4_DSIPHY_SYSCON_OFFSET,
 104                                           &reg);
 105         if (ret)
 106                 return ret;
 107 
 108         reg &= ~enable_mask;
 109         reg &= ~pipd_mask;
 110 
 111         reg |= (lanes << enable_shift) & enable_mask;
 112         reg |= (lanes << pipd_shift) & pipd_mask;
 113 
 114         regmap_write(omap4_dsi_mux_syscon, OMAP4_DSIPHY_SYSCON_OFFSET, reg);
 115 
 116         return 0;
 117 }
 118 
 119 static int omap_dsi_enable_pads(int dsi_id, unsigned lane_mask)
 120 {
 121         if (cpu_is_omap44xx())
 122                 return omap4_dsi_mux_pads(dsi_id, lane_mask);
 123 
 124         return 0;
 125 }
 126 
 127 static void omap_dsi_disable_pads(int dsi_id, unsigned lane_mask)
 128 {
 129         if (cpu_is_omap44xx())
 130                 omap4_dsi_mux_pads(dsi_id, 0);
 131 }
 132 
 133 static enum omapdss_version __init omap_display_get_version(void)
 134 {
 135         if (cpu_is_omap24xx())
 136                 return OMAPDSS_VER_OMAP24xx;
 137         else if (cpu_is_omap3630())
 138                 return OMAPDSS_VER_OMAP3630;
 139         else if (cpu_is_omap34xx()) {
 140                 if (soc_is_am35xx()) {
 141                         return OMAPDSS_VER_AM35xx;
 142                 } else {
 143                         if (omap_rev() < OMAP3430_REV_ES3_0)
 144                                 return OMAPDSS_VER_OMAP34xx_ES1;
 145                         else
 146                                 return OMAPDSS_VER_OMAP34xx_ES3;
 147                 }
 148         } else if (omap_rev() == OMAP4430_REV_ES1_0)
 149                 return OMAPDSS_VER_OMAP4430_ES1;
 150         else if (omap_rev() == OMAP4430_REV_ES2_0 ||
 151                         omap_rev() == OMAP4430_REV_ES2_1 ||
 152                         omap_rev() == OMAP4430_REV_ES2_2)
 153                 return OMAPDSS_VER_OMAP4430_ES2;
 154         else if (cpu_is_omap44xx())
 155                 return OMAPDSS_VER_OMAP4;
 156         else if (soc_is_omap54xx())
 157                 return OMAPDSS_VER_OMAP5;
 158         else if (soc_is_am43xx())
 159                 return OMAPDSS_VER_AM43xx;
 160         else if (soc_is_dra7xx())
 161                 return OMAPDSS_VER_DRA7xx;
 162         else
 163                 return OMAPDSS_VER_UNKNOWN;
 164 }
 165 
 166 static int __init omapdss_init_fbdev(void)
 167 {
 168         static struct omap_dss_board_info board_data = {
 169                 .dsi_enable_pads = omap_dsi_enable_pads,
 170                 .dsi_disable_pads = omap_dsi_disable_pads,
 171         };
 172         struct device_node *node;
 173         int r;
 174 
 175         board_data.version = omap_display_get_version();
 176         if (board_data.version == OMAPDSS_VER_UNKNOWN) {
 177                 pr_err("DSS not supported on this SoC\n");
 178                 return -ENODEV;
 179         }
 180 
 181         omap_display_device.dev.platform_data = &board_data;
 182 
 183         r = platform_device_register(&omap_display_device);
 184         if (r < 0) {
 185                 pr_err("Unable to register omapdss device\n");
 186                 return r;
 187         }
 188 
 189         /* create vrfb device */
 190         r = omap_init_vrfb();
 191         if (r < 0) {
 192                 pr_err("Unable to register omapvrfb device\n");
 193                 return r;
 194         }
 195 
 196         /* create FB device */
 197         r = omap_init_fb();
 198         if (r < 0) {
 199                 pr_err("Unable to register omapfb device\n");
 200                 return r;
 201         }
 202 
 203         /* create V4L2 display device */
 204         r = omap_init_vout();
 205         if (r < 0) {
 206                 pr_err("Unable to register omap_vout device\n");
 207                 return r;
 208         }
 209 
 210         /* add DSI info for omap4 */
 211         node = of_find_node_by_name(NULL, "omap4_padconf_global");
 212         if (node)
 213                 omap4_dsi_mux_syscon = syscon_node_to_regmap(node);
 214 
 215         return 0;
 216 }
 217 
 218 static const char * const omapdss_compat_names[] __initconst = {
 219         "ti,omap2-dss",
 220         "ti,omap3-dss",
 221         "ti,omap4-dss",
 222         "ti,omap5-dss",
 223         "ti,dra7-dss",
 224 };
 225 
 226 static struct device_node * __init omapdss_find_dss_of_node(void)
 227 {
 228         struct device_node *node;
 229         int i;
 230 
 231         for (i = 0; i < ARRAY_SIZE(omapdss_compat_names); ++i) {
 232                 node = of_find_compatible_node(NULL, NULL,
 233                         omapdss_compat_names[i]);
 234                 if (node)
 235                         return node;
 236         }
 237 
 238         return NULL;
 239 }
 240 
 241 static int __init omapdss_init_of(void)
 242 {
 243         int r;
 244         struct device_node *node;
 245         struct platform_device *pdev;
 246 
 247         /* only create dss helper devices if dss is enabled in the .dts */
 248 
 249         node = omapdss_find_dss_of_node();
 250         if (!node)
 251                 return 0;
 252 
 253         if (!of_device_is_available(node)) {
 254                 of_node_put(node);
 255                 return 0;
 256         }
 257 
 258         pdev = of_find_device_by_node(node);
 259 
 260         if (!pdev) {
 261                 pr_err("Unable to find DSS platform device\n");
 262                 return -ENODEV;
 263         }
 264 
 265         r = of_platform_populate(node, NULL, NULL, &pdev->dev);
 266         if (r) {
 267                 pr_err("Unable to populate DSS submodule devices\n");
 268                 put_device(&pdev->dev);
 269                 return r;
 270         }
 271 
 272         return omapdss_init_fbdev();
 273 }
 274 omap_device_initcall(omapdss_init_of);
 275 #endif /* CONFIG_FB_OMAP2 */
 276 
 277 static void dispc_disable_outputs(void)
 278 {
 279         u32 v, irq_mask = 0;
 280         bool lcd_en, digit_en, lcd2_en = false, lcd3_en = false;
 281         int i;
 282         struct omap_dss_dispc_dev_attr *da;
 283         struct omap_hwmod *oh;
 284 
 285         oh = omap_hwmod_lookup("dss_dispc");
 286         if (!oh) {
 287                 WARN(1, "display: could not disable outputs during reset - could not find dss_dispc hwmod\n");
 288                 return;
 289         }
 290 
 291         if (!oh->dev_attr) {
 292                 pr_err("display: could not disable outputs during reset due to missing dev_attr\n");
 293                 return;
 294         }
 295 
 296         da = (struct omap_dss_dispc_dev_attr *)oh->dev_attr;
 297 
 298         /* store value of LCDENABLE and DIGITENABLE bits */
 299         v = omap_hwmod_read(oh, DISPC_CONTROL);
 300         lcd_en = v & LCD_EN_MASK;
 301         digit_en = v & DIGIT_EN_MASK;
 302 
 303         /* store value of LCDENABLE for LCD2 */
 304         if (da->manager_count > 2) {
 305                 v = omap_hwmod_read(oh, DISPC_CONTROL2);
 306                 lcd2_en = v & LCD_EN_MASK;
 307         }
 308 
 309         /* store value of LCDENABLE for LCD3 */
 310         if (da->manager_count > 3) {
 311                 v = omap_hwmod_read(oh, DISPC_CONTROL3);
 312                 lcd3_en = v & LCD_EN_MASK;
 313         }
 314 
 315         if (!(lcd_en | digit_en | lcd2_en | lcd3_en))
 316                 return; /* no managers currently enabled */
 317 
 318         /*
 319          * If any manager was enabled, we need to disable it before
 320          * DSS clocks are disabled or DISPC module is reset
 321          */
 322         if (lcd_en)
 323                 irq_mask |= 1 << FRAMEDONE_IRQ_SHIFT;
 324 
 325         if (digit_en) {
 326                 if (da->has_framedonetv_irq) {
 327                         irq_mask |= 1 << FRAMEDONETV_IRQ_SHIFT;
 328                 } else {
 329                         irq_mask |= 1 << EVSYNC_EVEN_IRQ_SHIFT |
 330                                 1 << EVSYNC_ODD_IRQ_SHIFT;
 331                 }
 332         }
 333 
 334         if (lcd2_en)
 335                 irq_mask |= 1 << FRAMEDONE2_IRQ_SHIFT;
 336         if (lcd3_en)
 337                 irq_mask |= 1 << FRAMEDONE3_IRQ_SHIFT;
 338 
 339         /*
 340          * clear any previous FRAMEDONE, FRAMEDONETV,
 341          * EVSYNC_EVEN/ODD, FRAMEDONE2 or FRAMEDONE3 interrupts
 342          */
 343         omap_hwmod_write(irq_mask, oh, DISPC_IRQSTATUS);
 344 
 345         /* disable LCD and TV managers */
 346         v = omap_hwmod_read(oh, DISPC_CONTROL);
 347         v &= ~(LCD_EN_MASK | DIGIT_EN_MASK);
 348         omap_hwmod_write(v, oh, DISPC_CONTROL);
 349 
 350         /* disable LCD2 manager */
 351         if (da->manager_count > 2) {
 352                 v = omap_hwmod_read(oh, DISPC_CONTROL2);
 353                 v &= ~LCD_EN_MASK;
 354                 omap_hwmod_write(v, oh, DISPC_CONTROL2);
 355         }
 356 
 357         /* disable LCD3 manager */
 358         if (da->manager_count > 3) {
 359                 v = omap_hwmod_read(oh, DISPC_CONTROL3);
 360                 v &= ~LCD_EN_MASK;
 361                 omap_hwmod_write(v, oh, DISPC_CONTROL3);
 362         }
 363 
 364         i = 0;
 365         while ((omap_hwmod_read(oh, DISPC_IRQSTATUS) & irq_mask) !=
 366                irq_mask) {
 367                 i++;
 368                 if (i > FRAMEDONE_IRQ_TIMEOUT) {
 369                         pr_err("didn't get FRAMEDONE1/2/3 or TV interrupt\n");
 370                         break;
 371                 }
 372                 mdelay(1);
 373         }
 374 }
 375 
 376 int omap_dss_reset(struct omap_hwmod *oh)
 377 {
 378         struct omap_hwmod_opt_clk *oc;
 379         int c = 0;
 380         int i, r;
 381 
 382         if (!(oh->class->sysc->sysc_flags & SYSS_HAS_RESET_STATUS)) {
 383                 pr_err("dss_core: hwmod data doesn't contain reset data\n");
 384                 return -EINVAL;
 385         }
 386 
 387         for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++)
 388                 if (oc->_clk)
 389                         clk_prepare_enable(oc->_clk);
 390 
 391         dispc_disable_outputs();
 392 
 393         /* clear SDI registers */
 394         if (cpu_is_omap3430()) {
 395                 omap_hwmod_write(0x0, oh, DSS_SDI_CONTROL);
 396                 omap_hwmod_write(0x0, oh, DSS_PLL_CONTROL);
 397         }
 398 
 399         /*
 400          * clear DSS_CONTROL register to switch DSS clock sources to
 401          * PRCM clock, if any
 402          */
 403         omap_hwmod_write(0x0, oh, DSS_CONTROL);
 404 
 405         omap_test_timeout((omap_hwmod_read(oh, oh->class->sysc->syss_offs)
 406                                 & SYSS_RESETDONE_MASK),
 407                         MAX_MODULE_SOFTRESET_WAIT, c);
 408 
 409         if (c == MAX_MODULE_SOFTRESET_WAIT)
 410                 pr_warn("dss_core: waiting for reset to finish failed\n");
 411         else
 412                 pr_debug("dss_core: softreset done\n");
 413 
 414         for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++)
 415                 if (oc->_clk)
 416                         clk_disable_unprepare(oc->_clk);
 417 
 418         r = (c == MAX_MODULE_SOFTRESET_WAIT) ? -ETIMEDOUT : 0;
 419 
 420         return r;
 421 }

/* [<][>][^][v][top][bottom][index][help] */