index 43c3f6ebaad6a9b5dd049fbfacef7d8156c15262..c5ee62113323f8bdec44c58ff882b0295d2248f2 100644 (file)
--- a/drivers/video/da8xx-fb.c
+++ b/drivers/video/da8xx-fb.c
#include <linux/console.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
#include <video/da8xx-fb.h>
#include <asm/mach-types.h>
#define RIGHT_MARGIN 64
#define UPPER_MARGIN 32
#define LOWER_MARGIN 32
+#define WAIT_FOR_FRAME_DONE true
+#define NO_WAIT_FOR_FRAME_DONE false
static resource_size_t da8xx_fb_reg_base;
static struct resource *lcdc_regs;
static inline unsigned int lcdc_read(unsigned int addr)
{
- return (unsigned int)__raw_readl(da8xx_fb_reg_base + (addr));
+ return (unsigned int)readl(da8xx_fb_reg_base + (addr));
}
static inline void lcdc_write(unsigned int val, unsigned int addr)
{
- __raw_writel(val, da8xx_fb_reg_base + (addr));
+ writel(val, da8xx_fb_reg_base + (addr));
}
struct da8xx_fb_par {
+ struct device *dev;
resource_size_t p_palette_base;
unsigned char *v_palette_base;
dma_addr_t vram_phys;
}
/* Disable the Raster Engine of the LCD Controller */
-static inline void lcd_disable_raster(void)
+static inline void lcd_disable_raster(bool wait_for_frame_done)
{
u32 reg;
+ u32 loop_cnt = 0;
+ u32 stat;
+ u32 i = 0;
+
+ if (wait_for_frame_done)
+ loop_cnt = 5000;
reg = lcdc_read(LCD_RASTER_CTRL_REG);
if (reg & LCD_RASTER_ENABLE)
lcdc_write(reg & ~LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG);
+ /* Wait for the current frame to complete */
+ do {
+ if (lcd_revision == LCD_VERSION_1)
+ stat = lcdc_read(LCD_STAT_REG);
+ else
+ stat = lcdc_read(LCD_RAW_STAT_REG);
+
+ mdelay(1);
+ } while (!(stat & BIT(0)) && (i++ < loop_cnt));
+
+ if (lcd_revision == LCD_VERSION_1)
+ lcdc_write(stat, LCD_STAT_REG);
+ else
+ lcdc_write(stat, LCD_MASKED_STAT_REG);
+
+ if ((loop_cnt != 0) && (i >= loop_cnt)) {
+ printk(KERN_ERR "LCD Controller timed out\n");
+ return;
+ }
+
if (lcd_revision == LCD_VERSION_2)
/* Write 1 to reset LCDC */
lcdc_write(LCD_CLK_MAIN_RESET, LCD_CLK_RESET_REG);
} else {
reg_int = lcdc_read(LCD_INT_ENABLE_SET_REG) |
LCD_V2_END_OF_FRAME0_INT_ENA |
- LCD_V2_END_OF_FRAME1_INT_ENA;
+ LCD_V2_END_OF_FRAME1_INT_ENA |
+ LCD_V2_UNDERFLOW_INT_ENA | LCD_SYNC_LOST;
lcdc_write(reg_int, LCD_INT_ENABLE_SET_REG);
}
reg_dma |= LCD_DUAL_FRAME_BUFFER_ENABLE;
static void lcd_reset(struct da8xx_fb_par *par)
{
/* Disable the Raster if previously Enabled */
- lcd_disable_raster();
+ lcd_disable_raster(NO_WAIT_FOR_FRAME_DONE);
/* DMA has to be disabled */
lcdc_write(0, LCD_DMA_CTRL_REG);
{
struct da8xx_fb_par *par = arg;
u32 stat = lcdc_read(LCD_MASKED_STAT_REG);
+ struct device *dev = par->dev;
u32 reg_int;
if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) {
printk(KERN_ERR "LCDC sync lost or underflow error occured\n");
- lcd_disable_raster();
- clk_disable(par->lcdc_clk);
+ lcd_disable_raster(NO_WAIT_FOR_FRAME_DONE);
+ pm_runtime_put_sync(dev);
lcdc_write(stat, LCD_MASKED_STAT_REG);
lcd_enable_raster();
- clk_enable(par->lcdc_clk);
+ pm_runtime_get_sync(dev);
} else if (stat & LCD_PL_LOAD_DONE) {
/*
* Must disable raster before changing state of any control bit.
* interrupt via the following write to the status register. If
* this is done after then one gets multiple PL done interrupts.
*/
- lcd_disable_raster();
+ lcd_disable_raster(NO_WAIT_FOR_FRAME_DONE);
lcdc_write(stat, LCD_MASKED_STAT_REG);
if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) {
printk(KERN_ERR "LCDC sync lost or underflow error occured\n");
- lcd_disable_raster();
+ lcd_disable_raster(NO_WAIT_FOR_FRAME_DONE);
clk_disable(par->lcdc_clk);
lcdc_write(stat, LCD_STAT_REG);
lcd_enable_raster();
* interrupt via the following write to the status register. If
* this is done after then one gets multiple PL done interrupts.
*/
- lcd_disable_raster();
+ lcd_disable_raster(NO_WAIT_FOR_FRAME_DONE);
lcdc_write(stat, LCD_STAT_REG);
par = container_of(nb, struct da8xx_fb_par, freq_transition);
if (val == CPUFREQ_POSTCHANGE) {
if (par->lcd_fck_rate != clk_get_rate(par->lcdc_clk)) {
- lcd_disable_raster();
+ lcd_disable_raster(WAIT_FOR_FRAME_DONE);
lcd_calc_clk_divider(par);
lcd_enable_raster();
}
if (par->panel_power_ctrl)
par->panel_power_ctrl(0);
- lcd_disable_raster();
+ lcd_disable_raster(WAIT_FOR_FRAME_DONE);
lcdc_write(0, LCD_RASTER_CTRL_REG);
/* disable DMA */
dma_free_coherent(NULL, par->vram_size, par->vram_virt,
par->vram_phys);
free_irq(par->irq, par);
- clk_disable(par->lcdc_clk);
- clk_put(par->lcdc_clk);
+ pm_runtime_put_sync(&dev->dev);
+ pm_runtime_disable(&dev->dev);
framebuffer_release(info);
iounmap((void __iomem *)da8xx_fb_reg_base);
release_mem_region(lcdc_regs->start, resource_size(lcdc_regs));
if (par->panel_power_ctrl)
par->panel_power_ctrl(0);
- lcd_disable_raster();
+ lcd_disable_raster(WAIT_FOR_FRAME_DONE);
break;
default:
ret = -EINVAL;
return ret;
}
-static int alloc_fbmem(struct da8xx_fb_par *par)
-{
- unsigned int order, size;
- unsigned long addr;
-
- size = PAGE_ALIGN(par->vram_size);
- order = get_order(size);
- par->vram_virt = (void*) __get_free_pages(GFP_KERNEL, order);
- addr = (unsigned long) par->vram_virt;
- if (addr) {
- while (size > 0) {
- SetPageReserved(virt_to_page(addr));
- addr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
- par->vram_phys = (u32) virt_to_phys((void *) par->vram_virt);
- return 0;
- }
- return -ENOMEM;
-}
-
static struct fb_ops da8xx_fb_ops = {
.owner = THIS_MODULE,
.fb_check_var = fb_check_var,
struct da8xx_panel *lcdc_info;
struct fb_info *da8xx_fb_info;
struct clk *fb_clk = NULL;
- struct clk *lcdc_ick = NULL;
struct da8xx_fb_par *par;
resource_size_t len;
int ret, i;
goto err_request_mem;
}
- /*
- * Some SoC will not have seperate interface clock,
- * so make lazy check here
- */
- lcdc_ick = clk_get(&device->dev, "lcdc_ick");
- if (IS_ERR(lcdc_ick))
- dev_err(&device->dev, "Can not get lcdc_ick\n");
-
- ret = clk_enable(lcdc_ick);
- if (ret)
- dev_err(&device->dev, "failed to enable lcdc_ick\n");
-
fb_clk = clk_get(&device->dev, NULL);
if (IS_ERR(fb_clk)) {
dev_err(&device->dev, "Can not get device clock\n");
ret = -ENODEV;
goto err_ioremap;
}
- ret = clk_enable(fb_clk);
- if (ret)
- goto err_clk_put;
+
+ pm_runtime_irq_safe(&device->dev);
+ pm_runtime_enable(&device->dev);
+ pm_runtime_get_sync(&device->dev);
+
/* Determine LCD IP Version */
switch (lcdc_read(LCD_PID_REG)) {
if (i == ARRAY_SIZE(known_lcd_panels)) {
dev_err(&device->dev, "GLCD: No valid panel found\n");
ret = -ENODEV;
- goto err_clk_disable;
+ goto err_pm_runtime_disable;
} else
dev_info(&device->dev, "GLCD: Found %s panel\n",
fb_pdata->type);
if (!da8xx_fb_info) {
dev_dbg(&device->dev, "Memory allocation failed for fb_info\n");
ret = -ENOMEM;
- goto err_clk_disable;
+ goto err_pm_runtime_disable;
}
par = da8xx_fb_info->par;
+ par->dev = &device->dev;
par->lcdc_clk = fb_clk;
#ifdef CONFIG_CPU_FREQ
par->lcd_fck_rate = clk_get_rate(fb_clk);
par->vram_size = PAGE_ALIGN(par->vram_size/8);
par->vram_size = par->vram_size * LCD_NUM_BUFFERS;
- ret = alloc_fbmem(par);
- if (ret) {
+ par->vram_virt = dma_alloc_coherent(NULL,
+ par->vram_size,
+ (resource_size_t *) &par->vram_phys,
+ GFP_KERNEL | GFP_DMA);
+ if (!par->vram_virt) {
dev_err(&device->dev,
"GLCD: kmalloc for frame buffer failed\n");
ret = -EINVAL;
err_release_fb:
framebuffer_release(da8xx_fb_info);
-err_clk_disable:
- clk_disable(fb_clk);
-
-err_clk_put:
- clk_put(fb_clk);
+err_pm_runtime_disable:
+ pm_runtime_put_sync(&device->dev);
+ pm_runtime_disable(&device->dev);
err_ioremap:
+
iounmap((void __iomem *)da8xx_fb_reg_base);
err_request_mem:
}
#ifdef CONFIG_PM
+
+struct lcdc_context {
+ u32 clk_enable;
+ u32 ctrl;
+ u32 dma_ctrl;
+ u32 raster_timing_0;
+ u32 raster_timing_1;
+ u32 raster_timing_2;
+ u32 int_enable_set;
+ u32 dma_frm_buf_base_addr_0;
+ u32 dma_frm_buf_ceiling_addr_0;
+ u32 dma_frm_buf_base_addr_1;
+ u32 dma_frm_buf_ceiling_addr_1;
+ u32 raster_ctrl;
+} reg_context;
+
+static void lcd_context_save(void)
+{
+ reg_context.clk_enable = lcdc_read(LCD_CLK_ENABLE_REG);
+ reg_context.ctrl = lcdc_read(LCD_CTRL_REG);
+ reg_context.dma_ctrl = lcdc_read(LCD_DMA_CTRL_REG);
+ reg_context.raster_timing_0 = lcdc_read(LCD_RASTER_TIMING_0_REG);
+ reg_context.raster_timing_1 = lcdc_read(LCD_RASTER_TIMING_1_REG);
+ reg_context.raster_timing_2 = lcdc_read(LCD_RASTER_TIMING_2_REG);
+ reg_context.int_enable_set = lcdc_read(LCD_INT_ENABLE_SET_REG);
+ reg_context.dma_frm_buf_base_addr_0 =
+ lcdc_read(LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
+ reg_context.dma_frm_buf_ceiling_addr_0 =
+ lcdc_read(LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
+ reg_context.dma_frm_buf_base_addr_1 =
+ lcdc_read(LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);
+ reg_context.dma_frm_buf_ceiling_addr_1 =
+ lcdc_read(LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG);
+ reg_context.raster_ctrl = lcdc_read(LCD_RASTER_CTRL_REG);
+ return;
+}
+
+static void lcd_context_restore(void)
+{
+ lcdc_write(reg_context.clk_enable, LCD_CLK_ENABLE_REG);
+ lcdc_write(reg_context.ctrl, LCD_CTRL_REG);
+ lcdc_write(reg_context.dma_ctrl, LCD_DMA_CTRL_REG);
+ lcdc_write(reg_context.raster_timing_0, LCD_RASTER_TIMING_0_REG);
+ lcdc_write(reg_context.raster_timing_1, LCD_RASTER_TIMING_1_REG);
+ lcdc_write(reg_context.raster_timing_2, LCD_RASTER_TIMING_2_REG);
+ lcdc_write(reg_context.int_enable_set, LCD_INT_ENABLE_SET_REG);
+ lcdc_write(reg_context.dma_frm_buf_base_addr_0,
+ LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
+ lcdc_write(reg_context.dma_frm_buf_ceiling_addr_0,
+ LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
+ lcdc_write(reg_context.dma_frm_buf_base_addr_1,
+ LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);
+ lcdc_write(reg_context.dma_frm_buf_ceiling_addr_1,
+ LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG);
+ lcdc_write(reg_context.raster_ctrl, LCD_RASTER_CTRL_REG);
+ return;
+}
+
static int fb_suspend(struct platform_device *dev, pm_message_t state)
{
struct fb_info *info = platform_get_drvdata(dev);
struct da8xx_fb_par *par = info->par;
- unsigned long timeo = jiffies + msecs_to_jiffies(5000);
- u32 stat;
console_lock();
if (par->panel_power_ctrl)
par->panel_power_ctrl(0);
fb_set_suspend(info, 1);
- lcd_disable_raster();
-
- /* Wait for the current frame to complete */
- do {
- if (lcd_revision == LCD_VERSION_1)
- stat = lcdc_read(LCD_STAT_REG);
- else
- stat = lcdc_read(LCD_MASKED_STAT_REG);
- cpu_relax();
- } while (!(stat & BIT(0)) && time_before(jiffies, timeo));
-
- if (lcd_revision == LCD_VERSION_1)
- lcdc_write(stat, LCD_STAT_REG);
- else
- lcdc_write(stat, LCD_MASKED_STAT_REG);
-
- if (time_after_eq(jiffies, timeo)) {
- dev_err(&dev->dev, "controller timed out\n");
- return -ETIMEDOUT;
- }
+ lcd_disable_raster(WAIT_FOR_FRAME_DONE);
+ lcd_context_save();
- clk_disable(par->lcdc_clk);
+ pm_runtime_put_sync(&dev->dev);
console_unlock();
return 0;
if (par->panel_power_ctrl)
par->panel_power_ctrl(1);
- clk_enable(par->lcdc_clk);
+ pm_runtime_get_sync(&dev->dev);
+ lcd_context_restore();
lcd_enable_raster();
if (par->panel_power_ctrl)