From 245cfdf358d939bc01fa1e60696dad404d4a3b31 Mon Sep 17 00:00:00 2001 From: Grazvydas Ignotas Date: Tue, 9 Oct 2012 00:38:57 +0300 Subject: [PATCH] OMAPDSS: add hacky gamma table support --- drivers/video/omap2/dss/dispc.c | 35 +++++++++++++++++++++++++++ drivers/video/omap2/dss/display.c | 40 +++++++++++++++++++++++++++++++ drivers/video/omap2/dss/dss.h | 1 + 3 files changed, 76 insertions(+) diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index e943465cfa83..601427c7e7e9 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -58,6 +58,8 @@ #define DISPC_MAX_NR_ISRS 8 +#define TABLE_SIZE (256 * 4) + struct omap_dispc_isr_data { omap_dispc_isr_t isr; void *arg; @@ -118,6 +120,10 @@ static struct { bool ctx_valid; u32 ctx[DISPC_SZ_REGS / sizeof(u32)]; + /* palette/gamma table */ + void *table_virt; + dma_addr_t table_phys; + #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS spinlock_t irq_stats_lock; struct dispc_irq_stats irq_stats; @@ -1030,6 +1036,20 @@ void dispc_enable_gamma_table(bool enable) REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9); } +void dispc_set_gamma_table(void *table, u32 size) +{ + if (table == NULL || size == 0 || size > TABLE_SIZE) { + REG_FLD_MOD(DISPC_CONFIG, 0, 3, 3); + return; + } + + memcpy(dispc.table_virt, table, size); + + dispc_write_reg(DISPC_OVL_TABLE_BA(0), dispc.table_phys); + dispc_set_loadmode(OMAP_DSS_LOAD_CLUT_ONCE_FRAME); + REG_FLD_MOD(DISPC_CONFIG, 1, 3, 3); +} + void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable) { u16 reg; @@ -3463,6 +3483,15 @@ static int omap_dispchw_probe(struct platform_device *pdev) goto err_irq; } + pdev->dev.coherent_dma_mask = ~0; + dispc.table_virt = dma_alloc_writecombine(&pdev->dev, + TABLE_SIZE, &dispc.table_phys, GFP_KERNEL); + if (dispc.table_virt == NULL) { + dev_err(&pdev->dev, "failed to alloc palette memory\n"); + goto err_palette; + } + memset(dispc.table_virt, 0, TABLE_SIZE); + pm_runtime_enable(&pdev->dev); r = dispc_runtime_get(); @@ -3483,6 +3512,9 @@ static int omap_dispchw_probe(struct platform_device *pdev) err_runtime_get: pm_runtime_disable(&pdev->dev); + dma_free_writecombine(&pdev->dev, TABLE_SIZE, + dispc.table_virt, dispc.table_phys); +err_palette: free_irq(dispc.irq, dispc.pdev); err_irq: iounmap(dispc.base); @@ -3496,6 +3528,9 @@ static int omap_dispchw_remove(struct platform_device *pdev) { pm_runtime_disable(&pdev->dev); + dma_free_writecombine(&pdev->dev, TABLE_SIZE, + dispc.table_virt, dispc.table_phys); + clk_put(dispc.dss_clk); free_irq(dispc.irq, dispc.pdev); diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c index 0878e0a1dca8..b4506d7eeedd 100644 --- a/drivers/video/omap2/dss/display.c +++ b/drivers/video/omap2/dss/display.c @@ -248,6 +248,38 @@ static ssize_t display_wss_store(struct device *dev, return size; } +#include + +static ssize_t display_dss_gamma_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct omap_dss_device *dssdev = to_dss_device(dev); + unsigned int table[256]; + char *end = NULL; + int i; + + for (i = 0; i < 256; ) { + table[i++] = simple_strtoul(buf, &end, 0); + while (isspace(*end)) + end++; + if (*end == 0) + break; + buf = end; + } + + if (i == 1 && table[0] == 0) + dispc_set_gamma_table(NULL, 0); + else if (i < 256) { + dev_err(dev, "not enough gamma values supplied (%d)\n", i); + dispc_set_gamma_table(NULL, 0); + } else + dispc_set_gamma_table(table, 256 * 4); + + dispc_mgr_go(dssdev->manager->id); + + return size; +} + static DEVICE_ATTR(enabled, S_IRUGO|S_IWUSR, display_enabled_show, display_enabled_store); static DEVICE_ATTR(tear_elim, S_IRUGO|S_IWUSR, @@ -260,6 +292,8 @@ static DEVICE_ATTR(mirror, S_IRUGO|S_IWUSR, display_mirror_show, display_mirror_store); static DEVICE_ATTR(wss, S_IRUGO|S_IWUSR, display_wss_show, display_wss_store); +static DEVICE_ATTR(dss_gamma, S_IRUGO|S_IWUSR, + NULL, display_dss_gamma_store); static struct device_attribute *display_sysfs_attrs[] = { &dev_attr_enabled, @@ -417,6 +451,12 @@ void dss_init_device(struct platform_device *pdev, DSSERR("failed to create sysfs file\n"); } + if (dssdev->channel == OMAP_DSS_CHANNEL_LCD) { + r = device_create_file(&dssdev->dev, &dev_attr_dss_gamma); + if (r) + DSSERR("failed to create sysfs file\n"); + } + /* create display? sysfs links */ r = sysfs_create_link(&pdev->dev.kobj, &dssdev->dev.kobj, dev_name(&dssdev->dev)); diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 55c9490e33f5..c7eaa80694bf 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -389,6 +389,7 @@ void dispc_pck_free_enable(bool enable); void dispc_set_digit_size(u16 width, u16 height); void dispc_enable_fifomerge(bool enable); void dispc_enable_gamma_table(bool enable); +void dispc_set_gamma_table(void *table, u32 size); void dispc_set_loadmode(enum omap_dss_load_mode mode); bool dispc_lcd_timings_ok(struct omap_video_timings *timings); -- 2.39.2