|
@@ -444,3 +444,123 @@ static void dispc_disable_outputs(void)
|
|
|
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;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* store value of LCDENABLE for LCD3 */
|
|
|
+ if (da->manager_count > 3) {
|
|
|
+ v = omap_hwmod_read(oh, DISPC_CONTROL3);
|
|
|
+ lcd3_en = v & LCD_EN_MASK;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!(lcd_en | digit_en | lcd2_en | lcd3_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;
|
|
|
+ if (lcd3_en)
|
|
|
+ irq_mask |= 1 << FRAMEDONE3_IRQ_SHIFT;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * clear any previous FRAMEDONE, FRAMEDONETV,
|
|
|
+ * EVSYNC_EVEN/ODD, FRAMEDONE2 or FRAMEDONE3 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);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* disable LCD3 manager */
|
|
|
+ if (da->manager_count > 3) {
|
|
|
+ v = omap_hwmod_read(oh, DISPC_CONTROL3);
|
|
|
+ v &= ~LCD_EN_MASK;
|
|
|
+ omap_hwmod_write(v, oh, DISPC_CONTROL3);
|
|
|
+ }
|
|
|
+
|
|
|
+ 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/3 or TV interrupt\n");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ mdelay(1);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+int omap_dss_reset(struct omap_hwmod *oh)
|
|
|
+{
|
|
|
+ struct omap_hwmod_opt_clk *oc;
|
|
|
+ int c = 0;
|
|
|
+ int i, r;
|
|
|
+
|
|
|
+ if (!(oh->class->sysc->sysc_flags & SYSS_HAS_RESET_STATUS)) {
|
|
|
+ pr_err("dss_core: hwmod data doesn't contain reset data\n");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++)
|
|
|
+ if (oc->_clk)
|
|
|
+ clk_prepare_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);
|
|
|
+
|
|
|
+ if (c == MAX_MODULE_SOFTRESET_WAIT)
|
|
|
+ pr_warning("dss_core: waiting for reset to finish failed\n");
|
|
|
+ else
|
|
|
+ pr_debug("dss_core: softreset done\n");
|
|
|
+
|
|
|
+ for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++)
|
|
|
+ if (oc->_clk)
|
|
|
+ clk_disable_unprepare(oc->_clk);
|
|
|
+
|
|
|
+ r = (c == MAX_MODULE_SOFTRESET_WAIT) ? -ETIMEDOUT : 0;
|
|
|
+
|
|
|
+ return r;
|
|
|
+}
|