video: tegra: dc: add advanced cursor support
Kevin Huang [Fri, 25 Jan 2013 19:31:17 +0000 (11:31 -0800)]
Support advanced display cursor for t11x.

Change-Id: If5ef50401b8a2b2fd22500636d07506983aee0b5
Signed-off-by: Michael I Gold <gold@nvidia.com>
Reviewed-on: http://git-master/r/213743
Reviewed-by: Kevin Huang (Eng-SW) <kevinh@nvidia.com>
Reviewed-by: Robert Morell <rmorell@nvidia.com>

drivers/video/tegra/Kconfig
drivers/video/tegra/dc/dc_reg.h
drivers/video/tegra/dc/dc_sysfs.c
drivers/video/tegra/dc/ext/cursor.c
include/video/tegra_dc_ext.h

index 9ee0b54..ed50ee4 100644 (file)
@@ -42,6 +42,11 @@ config TEGRA_DC_CMU
     default n if ARCH_TEGRA_2x_SOC || ARCH_TEGRA_3x_SOC
     default y
 
+config TEGRA_DC_WIN_H
+    bool
+    default y if ARCH_TEGRA_14x_SOC
+    default n
+
 config TEGRA_MIPI_CAL
     bool
     default n if ARCH_TEGRA_2x_SOC || ARCH_TEGRA_3x_SOC
index 1fdf7e0..7ad07e4 100644 (file)
 #define  WINDOW_A_SELECT               (1 << 4)
 #define  WINDOW_B_SELECT               (1 << 5)
 #define  WINDOW_C_SELECT               (1 << 6)
+#define  WINDOW_D_SELECT               (1 << 7)
+#define  WINDOW_H_SELECT               (1 << 8)
 
 #define DC_CMD_REG_ACT_CONTROL                 0x043
 
 #define DC_DISP_CURSOR_START_ADDR_NS           0x43f
 #define   CURSOR_START_ADDR_MASK       (((1 << 22) - 1) << 10)
 #define   CURSOR_START_ADDR(_addr)     ((_addr) >> 10)
-#define          CURSOR_SIZE_64                (1 << 24)
+#define   CURSOR_SIZE_64               (0x1 << 24)
+#define   CURSOR_SIZE_128              (0x2 << 24)
+#define   CURSOR_SIZE_256              (0x3 << 24)
 
 #define DC_DISP_CURSOR_POSITION                        0x440
 #define   CURSOR_POSITION(_x, _y)              \
 #define  NUM_AGG_PRI_LVLS              4
 #define  SD_AGG_PRI_LVL(x)             ((x) >> 3)
 #define  SD_GET_AGG(x)                 ((x) & 0x7)
+
+#define DC_DISP_BLEND_CURSOR_CONTROL           0x4f1
+#define  CURSOR_MODE_SELECT(x)         (((x) & 0x1) << 24)
+
 #endif
index 6b34c43..f3dfd68 100644 (file)
@@ -136,6 +136,62 @@ static ssize_t enable_store(struct device *dev,
 
 static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR, enable_show, enable_store);
 
+#ifdef CONFIG_TEGRA_DC_WIN_H
+static ssize_t win_h_show(struct device *device,
+       struct device_attribute *attr, char *buf)
+{
+       struct platform_device *ndev = to_platform_device(device);
+       struct tegra_dc *dc = platform_get_drvdata(ndev);
+       unsigned long val = 0;
+
+       mutex_lock(&dc->lock);
+       tegra_dc_io_start(dc);
+
+       val = tegra_dc_readl(dc, DC_DISP_BLEND_CURSOR_CONTROL);
+
+       tegra_dc_io_end(dc);
+       mutex_unlock(&dc->lock);
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", !!(val & WINH_CURS_SELECT(1)));
+}
+
+/* win_h sysfs controls hybrid window.
+ *
+ * 0 = cursor mode and 1 = window mode (default on T14x) */
+static ssize_t win_h_store(struct device *dev,
+       struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct platform_device *ndev = to_platform_device(dev);
+       struct tegra_dc *dc = platform_get_drvdata(ndev);
+       unsigned int val = 0;
+       unsigned long cursor_val = 0;
+
+       if (!dc->enabled) {
+               dev_err(&dc->ndev->dev, "%s: DC not enabled.\n", __func__);
+               return -EFAULT;
+       }
+
+       if (kstrtouint(buf, 10, &val) < 0)
+               return -EINVAL;
+
+       mutex_lock(&dc->lock);
+       tegra_dc_io_start(dc);
+
+       cursor_val = tegra_dc_readl(dc, DC_DISP_BLEND_CURSOR_CONTROL);
+       cursor_val &= ~WINH_CURS_SELECT(1);
+       if (val)
+               cursor_val |= WINH_CURS_SELECT(1);
+       tegra_dc_writel(dc, cursor_val, DC_DISP_BLEND_CURSOR_CONTROL);
+
+       tegra_dc_io_end(dc);
+       mutex_unlock(&dc->lock);
+
+       return count;
+}
+
+static DEVICE_ATTR(win_h, S_IRUGO|S_IWUSR, win_h_show, win_h_store);
+#endif
+
 static ssize_t crc_checksum_latched_show(struct device *device,
        struct device_attribute *attr, char *buf)
 {
@@ -458,6 +514,9 @@ void __devexit tegra_dc_remove_sysfs(struct device *dev)
        device_remove_file(dev, &dev_attr_stats_enable);
        device_remove_file(dev, &dev_attr_crc_checksum_latched);
        device_remove_file(dev, &dev_attr_colorbar);
+#ifdef CONFIG_TEGRA_DC_WIN_H
+       device_remove_file(dev, &dev_attr_win_h);
+#endif
 #ifdef CONFIG_TEGRA_DC_CMU
        device_remove_file(dev, &dev_attr_cmu_enable);
 #endif
@@ -487,6 +546,9 @@ void tegra_dc_create_sysfs(struct device *dev)
        error |= device_create_file(dev, &dev_attr_stats_enable);
        error |= device_create_file(dev, &dev_attr_crc_checksum_latched);
        error |= device_create_file(dev, &dev_attr_colorbar);
+#ifdef CONFIG_TEGRA_DC_WIN_H
+       error |= device_create_file(dev, &dev_attr_win_h);
+#endif
 #ifdef CONFIG_TEGRA_DC_CMU
        error |= device_create_file(dev, &dev_attr_cmu_enable);
 #endif
index ebfa6eb..17ce70f 100644 (file)
@@ -62,6 +62,7 @@ static void set_cursor_image_hw(struct tegra_dc *dc,
                                struct tegra_dc_ext_cursor_image *args,
                                dma_addr_t phys_addr)
 {
+       unsigned long val;
        int clip_win;
 
        tegra_dc_writel(dc,
@@ -77,15 +78,37 @@ static void set_cursor_image_hw(struct tegra_dc *dc,
 
        BUG_ON(phys_addr & ~CURSOR_START_ADDR_MASK);
 
+       switch (TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE(args->flags)) {
+       case TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_64x64:
+               val = CURSOR_SIZE_64;
+               break;
+       case TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_128x128:
+               val = CURSOR_SIZE_128;
+               break;
+       case TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_256x256:
+               val = CURSOR_SIZE_256;
+               break;
+       default:
+               val = 0;
+       }
+
        /* Get the cursor clip window number */
        clip_win = CURSOR_CLIP_GET_WINDOW(tegra_dc_readl(dc,
                                          DC_DISP_CURSOR_START_ADDR));
+       val |= clip_win;
 
-       tegra_dc_writel(dc, CURSOR_CLIP_SHIFT_BITS(clip_win) |
-               CURSOR_START_ADDR(((unsigned long) phys_addr)) |
-               ((args->flags & TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_64x64) ?
-                       CURSOR_SIZE_64 : 0),
+       tegra_dc_writel(dc,
+               val | CURSOR_START_ADDR(((unsigned long) phys_addr)),
                DC_DISP_CURSOR_START_ADDR);
+
+       if (args->flags & TEGRA_DC_EXT_CURSOR_FLAGS_RGBA_NORMAL)
+               tegra_dc_writel(dc,
+                               CURSOR_MODE_SELECT(1),
+                               DC_DISP_BLEND_CURSOR_CONTROL);
+       else
+               tegra_dc_writel(dc,
+                               CURSOR_MODE_SELECT(0),
+                               DC_DISP_BLEND_CURSOR_CONTROL);
 }
 
 int tegra_dc_ext_set_cursor_image(struct tegra_dc_ext_user *user,
@@ -101,12 +124,23 @@ int tegra_dc_ext_set_cursor_image(struct tegra_dc_ext_user *user,
        if (!user->nvmap)
                return -EFAULT;
 
-       size = args->flags & (TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_32x32 |
-                             TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_64x64);
-
+       size = TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE(args->flags);
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
        if (size != TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_32x32 &&
            size !=  TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_64x64)
                return -EINVAL;
+#else
+       if (size != TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_32x32 &&
+           size !=  TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_64x64 &&
+           size !=  TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_128x128 &&
+           size !=  TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_256x256)
+               return -EINVAL;
+#endif
+
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
+       if (args->flags && TEGRA_DC_EXT_CURSOR_FLAGS_RGBA_NORMAL)
+               return -EINVAL;
+#endif
 
        mutex_lock(&ext->cursor.lock);
 
@@ -163,7 +197,7 @@ int tegra_dc_ext_set_cursor(struct tegra_dc_ext_user *user,
 {
        struct tegra_dc_ext *ext = user->ext;
        struct tegra_dc *dc = ext->dc;
-       u32 win_options;
+       u32 val;
        bool enable;
        int ret;
 
@@ -185,12 +219,12 @@ int tegra_dc_ext_set_cursor(struct tegra_dc_ext_user *user,
        tegra_dc_io_start(dc);
        tegra_dc_hold_dc_out(dc);
 
-       win_options = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
-       if (!!(win_options & CURSOR_ENABLE) != enable) {
-               win_options &= ~CURSOR_ENABLE;
+       val = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
+       if (!!(val & CURSOR_ENABLE) != enable) {
+               val &= ~CURSOR_ENABLE;
                if (enable)
-                       win_options |= CURSOR_ENABLE;
-               tegra_dc_writel(dc, win_options, DC_DISP_DISP_WIN_OPTIONS);
+                       val |= CURSOR_ENABLE;
+               tegra_dc_writel(dc, val, DC_DISP_DISP_WIN_OPTIONS);
        }
 
        tegra_dc_writel(dc, CURSOR_POSITION(args->x, args->y),
index 52c9f21..1306b2f 100644 (file)
@@ -122,8 +122,14 @@ struct tegra_dc_ext_flip {
  *               0        1    foreground color
  * - Exactly one of the SIZE flags must be specified.
  */
-#define TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_32x32     1
-#define TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_64x64     2
+
+#define TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_32x32     ((1 & 0x7) << 0)
+#define TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_64x64     ((2 & 0x7) << 0)
+#define TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_128x128   ((3 & 0x7) << 0)
+#define TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_256x256   ((4 & 0x7) << 0)
+#define TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE(x)                (((x) & 0x7) >> 0)
+#define TEGRA_DC_EXT_CURSOR_FLAGS_2BIT_LEGACY          (0 << 16)
+#define TEGRA_DC_EXT_CURSOR_FLAGS_RGBA_NORMAL          (1 << 16)
 struct tegra_dc_ext_cursor_image {
        struct {
                __u8    r;
@@ -135,7 +141,7 @@ struct tegra_dc_ext_cursor_image {
 };
 
 /* Possible flags for struct nvdc_cursor's flags field */
-#define TEGRA_DC_EXT_CURSOR_FLAGS_VISIBLE      1
+#define TEGRA_DC_EXT_CURSOR_FLAGS_VISIBLE      (1 << 0)
 
 struct tegra_dc_ext_cursor {
        __s16 x;