|
@@ -30,6 +30,32 @@
|
|
|
#include <plat/common.h>
|
|
|
|
|
|
#include "control.h"
|
|
|
+#include "display.h"
|
|
|
+
|
|
|
+#define DISPC_CONTROL 0x0040
|
|
|
+#define DISPC_CONTROL2 0x0238
|
|
|
+#define DISPC_IRQSTATUS 0x0018
|
|
|
+
|
|
|
+#define DSS_SYSCONFIG 0x10
|
|
|
+#define DSS_SYSSTATUS 0x14
|
|
|
+#define DSS_CONTROL 0x40
|
|
|
+#define DSS_SDI_CONTROL 0x44
|
|
|
+#define DSS_PLL_CONTROL 0x48
|
|
|
+
|
|
|
+#define LCD_EN_MASK (0x1 << 0)
|
|
|
+#define DIGIT_EN_MASK (0x1 << 1)
|
|
|
+
|
|
|
+#define FRAMEDONE_IRQ_SHIFT 0
|
|
|
+#define EVSYNC_EVEN_IRQ_SHIFT 2
|
|
|
+#define EVSYNC_ODD_IRQ_SHIFT 3
|
|
|
+#define FRAMEDONE2_IRQ_SHIFT 22
|
|
|
+#define FRAMEDONETV_IRQ_SHIFT 24
|
|
|
+
|
|
|
+/*
|
|
|
+ * FRAMEDONE_IRQ_TIMEOUT: how long (in milliseconds) to wait during DISPC
|
|
|
+ * reset before deciding that something has gone wrong
|
|
|
+ */
|
|
|
+#define FRAMEDONE_IRQ_TIMEOUT 100
|
|
|
|
|
|
static struct platform_device omap_display_device = {
|
|
|
.name = "omapdss",
|
|
@@ -174,6 +200,90 @@ int __init omap_display_init(struct omap_dss_board_info *board_data)
|
|
|
return r;
|
|
|
}
|
|
|
|
|
|
+static void dispc_disable_outputs(void)
|
|
|
+{
|
|
|
+ u32 v, irq_mask = 0;
|
|
|
+ bool lcd_en, digit_en, lcd2_en = false;
|
|
|
+ int i;
|
|
|
+ struct omap_dss_dispc_dev_attr *da;
|
|
|
+ struct omap_hwmod *oh;
|
|
|
+
|
|
|
+ oh = omap_hwmod_lookup("dss_dispc");
|
|
|
+ if (!oh) {
|
|
|
+ WARN(1, "display: could not disable outputs during reset - could not find dss_dispc hwmod\n");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!oh->dev_attr) {
|
|
|
+ pr_err("display: could not disable outputs during reset due to missing dev_attr\n");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ da = (struct omap_dss_dispc_dev_attr *)oh->dev_attr;
|
|
|
+
|
|
|
+ /* store value of LCDENABLE and DIGITENABLE bits */
|
|
|
+ v = omap_hwmod_read(oh, DISPC_CONTROL);
|
|
|
+ lcd_en = v & LCD_EN_MASK;
|
|
|
+ digit_en = v & DIGIT_EN_MASK;
|
|
|
+
|
|
|
+ /* store value of LCDENABLE for LCD2 */
|
|
|
+ if (da->manager_count > 2) {
|
|
|
+ v = omap_hwmod_read(oh, DISPC_CONTROL2);
|
|
|
+ lcd2_en = v & LCD_EN_MASK;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!(lcd_en | digit_en | lcd2_en))
|
|
|
+ return; /* no managers currently enabled */
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If any manager was enabled, we need to disable it before
|
|
|
+ * DSS clocks are disabled or DISPC module is reset
|
|
|
+ */
|
|
|
+ if (lcd_en)
|
|
|
+ irq_mask |= 1 << FRAMEDONE_IRQ_SHIFT;
|
|
|
+
|
|
|
+ if (digit_en) {
|
|
|
+ if (da->has_framedonetv_irq) {
|
|
|
+ irq_mask |= 1 << FRAMEDONETV_IRQ_SHIFT;
|
|
|
+ } else {
|
|
|
+ irq_mask |= 1 << EVSYNC_EVEN_IRQ_SHIFT |
|
|
|
+ 1 << EVSYNC_ODD_IRQ_SHIFT;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (lcd2_en)
|
|
|
+ irq_mask |= 1 << FRAMEDONE2_IRQ_SHIFT;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * clear any previous FRAMEDONE, FRAMEDONETV,
|
|
|
+ * EVSYNC_EVEN/ODD or FRAMEDONE2 interrupts
|
|
|
+ */
|
|
|
+ omap_hwmod_write(irq_mask, oh, DISPC_IRQSTATUS);
|
|
|
+
|
|
|
+ /* disable LCD and TV managers */
|
|
|
+ v = omap_hwmod_read(oh, DISPC_CONTROL);
|
|
|
+ v &= ~(LCD_EN_MASK | DIGIT_EN_MASK);
|
|
|
+ omap_hwmod_write(v, oh, DISPC_CONTROL);
|
|
|
+
|
|
|
+ /* disable LCD2 manager */
|
|
|
+ if (da->manager_count > 2) {
|
|
|
+ v = omap_hwmod_read(oh, DISPC_CONTROL2);
|
|
|
+ v &= ~LCD_EN_MASK;
|
|
|
+ omap_hwmod_write(v, oh, DISPC_CONTROL2);
|
|
|
+ }
|
|
|
+
|
|
|
+ i = 0;
|
|
|
+ while ((omap_hwmod_read(oh, DISPC_IRQSTATUS) & irq_mask) !=
|
|
|
+ irq_mask) {
|
|
|
+ i++;
|
|
|
+ if (i > FRAMEDONE_IRQ_TIMEOUT) {
|
|
|
+ pr_err("didn't get FRAMEDONE1/2 or TV interrupt\n");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ mdelay(1);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
#define MAX_MODULE_SOFTRESET_WAIT 10000
|
|
|
int omap_dss_reset(struct omap_hwmod *oh)
|
|
|
{
|
|
@@ -190,6 +300,20 @@ int omap_dss_reset(struct omap_hwmod *oh)
|
|
|
if (oc->_clk)
|
|
|
clk_enable(oc->_clk);
|
|
|
|
|
|
+ dispc_disable_outputs();
|
|
|
+
|
|
|
+ /* clear SDI registers */
|
|
|
+ if (cpu_is_omap3430()) {
|
|
|
+ omap_hwmod_write(0x0, oh, DSS_SDI_CONTROL);
|
|
|
+ omap_hwmod_write(0x0, oh, DSS_PLL_CONTROL);
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * clear DSS_CONTROL register to switch DSS clock sources to
|
|
|
+ * PRCM clock, if any
|
|
|
+ */
|
|
|
+ omap_hwmod_write(0x0, oh, DSS_CONTROL);
|
|
|
+
|
|
|
omap_test_timeout((omap_hwmod_read(oh, oh->class->sysc->syss_offs)
|
|
|
& SYSS_RESETDONE_MASK),
|
|
|
MAX_MODULE_SOFTRESET_WAIT, c);
|