OMAPDSS: add hacky gamma table support
authorGrazvydas Ignotas <notasas@gmail.com>
Mon, 8 Oct 2012 21:38:57 +0000 (00:38 +0300)
committerGrazvydas Ignotas <notasas@gmail.com>
Mon, 8 Oct 2012 21:38:57 +0000 (00:38 +0300)
drivers/video/omap2/dss/dispc.c
drivers/video/omap2/dss/display.c
drivers/video/omap2/dss/dss.h

index e943465..601427c 100644 (file)
@@ -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);
index 0878e0a..b4506d7 100644 (file)
@@ -248,6 +248,38 @@ static ssize_t display_wss_store(struct device *dev,
        return size;
 }
 
+#include <linux/ctype.h>
+
+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));
index 55c9490..c7eaa80 100644 (file)
@@ -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);