diff --git a/arch/arm/mach-tegra/include/mach/dc.h b/arch/arm/mach-tegra/include/mach/dc.h index ce562e5634f7..49c09a177d00 100644 --- a/arch/arm/mach-tegra/include/mach/dc.h +++ b/arch/arm/mach-tegra/include/mach/dc.h @@ -86,6 +86,7 @@ struct tegra_dc_out { #define TEGRA_DC_ORDER_BLUE_RED 1 struct tegra_dc; +struct nvmap_handle_ref; struct tegra_dc_win { u8 idx; @@ -108,6 +109,8 @@ struct tegra_dc_win { int dirty; struct tegra_dc *dc; + + struct nvmap_handle_ref *surface; }; #define TEGRA_WIN_FLAG_ENABLED (1 << 0) @@ -165,6 +168,10 @@ struct tegra_dc_win *tegra_dc_get_window(struct tegra_dc *dc, unsigned win); void tegra_dc_enable(struct tegra_dc *dc); void tegra_dc_disable(struct tegra_dc *dc); +u32 tegra_dc_get_syncpt_id(const struct tegra_dc *dc); +u32 tegra_dc_incr_syncpt_max(struct tegra_dc *dc); +void tegra_dc_incr_syncpt_min(struct tegra_dc *dc, u32 val); + /* tegra_dc_update_windows and tegra_dc_sync_windows do not support windows * with differenct dcs in one call */ diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c index fadecf4796e1..16e6a454336d 100644 --- a/drivers/video/tegra/dc/dc.c +++ b/drivers/video/tegra/dc/dc.c @@ -102,6 +102,8 @@ static void _dump_regs(struct tegra_dc *dc, void *data, int i; char buff[256]; + tegra_dc_io_start(dc); + DUMP_REG(DC_CMD_DISPLAY_COMMAND_OPTION0); DUMP_REG(DC_CMD_DISPLAY_COMMAND); DUMP_REG(DC_CMD_SIGNAL_RAISE); @@ -225,6 +227,8 @@ static void _dump_regs(struct tegra_dc *dc, void *data, DUMP_REG(DC_WINBUF_ADDR_H_OFFSET); DUMP_REG(DC_WINBUF_ADDR_V_OFFSET); } + + tegra_dc_io_end(dc); } #undef DUMP_REG @@ -285,7 +289,6 @@ static void tegra_dc_dbg_add(struct tegra_dc *dc) snprintf(name, sizeof(name), "tegra_dc%d_regs", dc->ndev->id); (void) debugfs_create_file(name, S_IRUGO, NULL, dc, &dbg_fops); - } #else static void tegra_dc_dbg_add(struct tegra_dc *dc) {} @@ -533,13 +536,40 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n) } tegra_dc_writel(dc, update_mask, DC_CMD_STATE_CONTROL); - mutex_unlock(&dc->lock); return 0; } EXPORT_SYMBOL(tegra_dc_update_windows); +u32 tegra_dc_get_syncpt_id(const struct tegra_dc *dc) +{ + return dc->syncpt_id; +} +EXPORT_SYMBOL(tegra_dc_get_syncpt_id); + +u32 tegra_dc_incr_syncpt_max(struct tegra_dc *dc) +{ + u32 max; + + mutex_lock(&dc->lock); + max = nvhost_syncpt_incr_max(&dc->ndev->host->syncpt, dc->syncpt_id, 1); + dc->syncpt_max = max; + mutex_unlock(&dc->lock); + + return max; +} + +void tegra_dc_incr_syncpt_min(struct tegra_dc *dc, u32 val) +{ + mutex_lock(&dc->lock); + while (dc->syncpt_min < val) { + dc->syncpt_min++; + nvhost_syncpt_cpu_incr(&dc->ndev->host->syncpt, dc->syncpt_id); + } + mutex_unlock(&dc->lock); +} + static bool tegra_dc_windows_are_clean(struct tegra_dc_win *windows[], int n) { @@ -769,11 +799,18 @@ static void tegra_dc_set_color_control(struct tegra_dc *dc) static void tegra_dc_init(struct tegra_dc *dc) { + u32 disp_syncpt; + u32 vblank_syncpt; + tegra_dc_writel(dc, 0x00000100, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL); - if (dc->ndev->id == 0) - tegra_dc_writel(dc, 0x0000011a, DC_CMD_CONT_SYNCPT_VSYNC); - else - tegra_dc_writel(dc, 0x0000011b, DC_CMD_CONT_SYNCPT_VSYNC); + if (dc->ndev->id == 0) { + disp_syncpt = NVSYNCPT_DISP0; + vblank_syncpt = NVSYNCPT_VBLANK0; + } else if (dc->ndev->id == 1) { + disp_syncpt = NVSYNCPT_DISP1; + vblank_syncpt = NVSYNCPT_VBLANK1; + } + tegra_dc_writel(dc, 0x00000100 | vblank_syncpt, DC_CMD_CONT_SYNCPT_VSYNC); tegra_dc_writel(dc, 0x00004700, DC_CMD_INT_TYPE); tegra_dc_writel(dc, 0x0001c700, DC_CMD_INT_POLARITY); tegra_dc_writel(dc, 0x00000020, DC_DISP_MEM_HIGH_PRIORITY); @@ -786,18 +823,24 @@ static void tegra_dc_init(struct tegra_dc *dc) tegra_dc_set_color_control(dc); + dc->syncpt_id = disp_syncpt; + + dc->syncpt_min = dc->syncpt_max = + nvhost_syncpt_read(&dc->ndev->host->syncpt, disp_syncpt); + if (dc->mode.pclk) tegra_dc_program_mode(dc, &dc->mode); } static void _tegra_dc_enable(struct tegra_dc *dc) { + tegra_dc_io_start(dc); + if (dc->out && dc->out->enable) dc->out->enable(); tegra_dc_setup_clk(dc, dc->clk); - clk_enable(dc->host1x_clk); clk_enable(dc->clk); tegra_periph_reset_deassert(dc->clk); enable_irq(dc->irq); @@ -831,10 +874,17 @@ static void _tegra_dc_disable(struct tegra_dc *dc) disable_irq(dc->irq); tegra_periph_reset_assert(dc->clk); clk_disable(dc->clk); - clk_disable(dc->host1x_clk); if (dc->out && dc->out->disable) dc->out->disable(); + + /* flush any pending syncpt waits */ + while (dc->syncpt_min < dc->syncpt_max) { + dc->syncpt_min++; + nvhost_syncpt_cpu_incr(&dc->ndev->host->syncpt, dc->syncpt_id); + } + + tegra_dc_io_end(dc); } @@ -854,7 +904,6 @@ static int tegra_dc_probe(struct nvhost_device *ndev) { struct tegra_dc *dc; struct clk *clk; - struct clk *host1x_clk; struct resource *res; struct resource *base_res; struct resource *fb_mem = NULL; @@ -904,23 +953,14 @@ static int tegra_dc_probe(struct nvhost_device *ndev) fb_mem = nvhost_get_resource_byname(ndev, IORESOURCE_MEM, "fbmem"); - host1x_clk = clk_get(&ndev->dev, "host1x"); - if (IS_ERR_OR_NULL(host1x_clk)) { - dev_err(&ndev->dev, "can't get host1x clock\n"); - ret = -ENOENT; - goto err_iounmap_reg; - } - clk = clk_get(&ndev->dev, NULL); if (IS_ERR_OR_NULL(clk)) { dev_err(&ndev->dev, "can't get clock\n"); ret = -ENOENT; - - goto err_put_host1x_clk; + goto err_iounmap_reg; } dc->clk = clk; - dc->host1x_clk = host1x_clk; dc->base_res = base_res; dc->base = base; dc->irq = irq; @@ -984,8 +1024,6 @@ static int tegra_dc_probe(struct nvhost_device *ndev) free_irq(irq, dc); err_put_clk: clk_put(clk); -err_put_host1x_clk: - clk_put(host1x_clk); err_iounmap_reg: iounmap(base); if (fb_mem) @@ -1014,7 +1052,6 @@ static int tegra_dc_remove(struct nvhost_device *ndev) free_irq(dc->irq, dc); clk_put(dc->clk); - clk_put(dc->host1x_clk); iounmap(dc->base); if (dc->fb_mem) release_resource(dc->base_res); diff --git a/drivers/video/tegra/dc/dc_priv.h b/drivers/video/tegra/dc/dc_priv.h index 2297be40f030..39a03e8fb9c0 100644 --- a/drivers/video/tegra/dc/dc_priv.h +++ b/drivers/video/tegra/dc/dc_priv.h @@ -22,6 +22,7 @@ #include #include #include +#include "../host/dev.h" struct tegra_dc; @@ -54,7 +55,6 @@ struct tegra_dc { int irq; struct clk *clk; - struct clk *host1x_clk; bool enabled; @@ -74,17 +74,33 @@ struct tegra_dc { struct resource *fb_mem; struct tegra_fb_info *fb; + + u32 syncpt_id; + u32 syncpt_min; + u32 syncpt_max; }; +static inline void tegra_dc_io_start(struct tegra_dc *dc) +{ + nvhost_module_busy(&dc->ndev->host->mod); +} + +static inline void tegra_dc_io_end(struct tegra_dc *dc) +{ + nvhost_module_idle(&dc->ndev->host->mod); +} + static inline unsigned long tegra_dc_readl(struct tegra_dc *dc, unsigned long reg) { + BUG_ON(!nvhost_module_powered(&dc->ndev->host->mod)); return readl(dc->base + reg * 4); } static inline void tegra_dc_writel(struct tegra_dc *dc, unsigned long val, unsigned long reg) { + BUG_ON(!nvhost_module_powered(&dc->ndev->host->mod)); writel(val, dc->base + reg * 4); } diff --git a/drivers/video/tegra/fb.c b/drivers/video/tegra/fb.c index 7e4ffa8ba0b9..1656a6e49279 100644 --- a/drivers/video/tegra/fb.c +++ b/drivers/video/tegra/fb.c @@ -23,13 +23,22 @@ #include #include #include +#include #include +#include +#include #include +#include