video: tegra: Added initial smartdimmer support
Laurence Harrison [Wed, 16 Mar 2011 04:43:45 +0000 (21:43 -0700)]
includes:
1.) changes to DC init to add SD functionality
2.) changes to DC flip to add SD functionality

Original-Change-Id: I8c729e16e2b8a5a4158697b99cc4b3d07bf02001
Reviewed-on: http://git-master/r/21452
Reviewed-by: Scott Williams <scwilliams@nvidia.com>
Reviewed-by: Jonathan Mayo <jmayo@nvidia.com>
Tested-by: Jonathan Mayo <jmayo@nvidia.com>
Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>
Original-Change-Id: I4ad3ee3778a0e859e0d2b0c36ee6369193795cd3

Rebase-Id: Rd133da1af5c8b283b1886b025b8b1880ec61fde0

arch/arm/mach-tegra/include/mach/dc.h
drivers/video/tegra/dc/Makefile
drivers/video/tegra/dc/dc.c
drivers/video/tegra/dc/dc_reg.h
drivers/video/tegra/dc/nvsd.c [new file with mode: 0644]
drivers/video/tegra/dc/nvsd.h [new file with mode: 0644]

index e7aeb8c..65fc068 100644 (file)
@@ -21,6 +21,7 @@
 #define __MACH_TEGRA_DC_H
 
 #include <linux/pm.h>
+#include <linux/types.h>
 
 #define TEGRA_MAX_DC           2
 #define DC_N_WINDOWS           3
@@ -193,6 +194,41 @@ enum {
        TEGRA_DC_ERRDIFF_DITHER,
 };
 
+struct tegra_dc_sd_blp {
+       u16 time_constant;
+       u8 step;
+};
+
+struct tegra_dc_sd_fc {
+       u8 time_limit;
+       u8 threshold;
+};
+
+struct tegra_dc_sd_rgb {
+       u8 r;
+       u8 g;
+       u8 b;
+};
+
+struct tegra_dc_sd_settings {
+       unsigned enable;
+       bool use_auto_pwm;
+       u8 hw_update_delay;
+       unsigned bin_width;
+       u8 aggressiveness;
+
+       bool use_vid_luma;
+       struct tegra_dc_sd_rgb coeff;
+
+       struct tegra_dc_sd_fc fc;
+       struct tegra_dc_sd_blp blp;
+       u8 bltf[4][4];
+       struct tegra_dc_sd_rgb lut[9];
+
+       atomic_t *sd_brightness;
+       struct platform_device *bl_device;
+};
+
 enum {
        TEGRA_PIN_OUT_CONFIG_SEL_LHP0_LD21,
        TEGRA_PIN_OUT_CONFIG_SEL_LHP1_LD18,
@@ -211,31 +247,33 @@ enum {
 };
 
 struct tegra_dc_out {
-       int                     type;
-       unsigned                flags;
+       int                             type;
+       unsigned                        flags;
 
        /* size in mm */
-       unsigned                h_size;
-       unsigned                v_size;
+       unsigned                        h_size;
+       unsigned                        v_size;
+
+       int                             dcc_bus;
+       int                             hotplug_gpio;
 
-       int                     dcc_bus;
-       int                     hotplug_gpio;
+       unsigned                        order;
+       unsigned                        align;
+       unsigned                        depth;
+       unsigned                        dither;
 
-       unsigned                order;
-       unsigned                align;
-       unsigned                depth;
-       unsigned                dither;
+       struct tegra_dc_mode            *modes;
+       int                             n_modes;
 
-       unsigned                height; /* mm */
-       unsigned                width; /* mm */
+       struct tegra_dsi_out            *dsi;
 
-       struct tegra_dc_mode    *modes;
-       int                     n_modes;
+       unsigned                        height; /* mm */
+       unsigned                        width; /* mm */
 
-       struct tegra_dsi_out    *dsi;
+       struct tegra_dc_out_pin         *out_pins;
+       unsigned                        n_out_pins;
 
-       struct tegra_dc_out_pin *out_pins;
-       unsigned                n_out_pins;
+       struct tegra_dc_sd_settings     *sd_settings;
 
        u8                      *out_sel_configs;
        unsigned                n_out_sel_configs;
index db675fd..ea7671e 100644 (file)
@@ -3,5 +3,6 @@ obj-y += rgb.o
 obj-y += hdmi.o
 obj-y += nvhdcp.o
 obj-y += edid.o
+obj-y += nvsd.o
 obj-$(CONFIG_TEGRA_DSI) += dsi.o
 obj-$(CONFIG_TEGRA_OVERLAY) += overlay.o
index 541346a..0ba41a8 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/ktime.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
+#include <linux/backlight.h>
 
 #include <mach/clk.h>
 #include <mach/dc.h>
@@ -40,6 +41,7 @@
 #include "dc_reg.h"
 #include "dc_priv.h"
 #include "overlay.h"
+#include "nvsd.h"
 
 static int no_vsync;
 
@@ -482,6 +484,7 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
        unsigned long update_mask = GENERAL_ACT_REQ;
        unsigned long val;
        bool update_blend = false;
+       bool nvsd_updated = false;
        int i;
 
        dc = windows[0]->dc;
@@ -643,8 +646,22 @@ int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
        }
 
        tegra_dc_writel(dc, update_mask, DC_CMD_STATE_CONTROL);
+
+       /* Update the SD brightness */
+       nvsd_updated = nvsd_update_brightness(dc);
+
        mutex_unlock(&dc->lock);
 
+       /* Do the actual brightness update outside of the mutex */
+       if (nvsd_updated && dc->out->sd_settings &&
+           dc->out->sd_settings->bl_device) {
+
+               struct platform_device *pdev = dc->out->sd_settings->bl_device;
+               struct backlight_device *bl = platform_get_drvdata(pdev);
+               if (bl)
+                       backlight_update_status(bl);
+       }
+
        return 0;
 }
 EXPORT_SYMBOL(tegra_dc_update_windows);
@@ -1353,6 +1370,10 @@ static void tegra_dc_init(struct tegra_dc *dc)
 
        if (dc->mode.pclk)
                tegra_dc_program_mode(dc, &dc->mode);
+
+       /* Initialize SD AFTER the modeset.
+          nvsd_init handles the sd_settings = NULL case. */
+       nvsd_init(dc, dc->out->sd_settings);
 }
 
 static bool _tegra_dc_controller_enable(struct tegra_dc *dc)
index 11bce9a..c7f4a30 100644 (file)
 #define DC_WINBUF_ADDR_V_OFFSET_NS             0x809
 #define DC_WINBUF_UFLOW_STATUS                 0x80a
 
+
+#define DC_DISP_SD_CONTROL                     0x4c2
+#define  SD_ENABLE_NORMAL              (1 << 0)
+#define  SD_ENABLE_ONESHOT             (2 << 0)
+#define  SD_USE_VID_LUMA               (1 << 2)
+#define  SD_BIN_WIDTH_ONE              (0 << 3)
+#define  SD_BIN_WIDTH_TWO              (1 << 3)
+#define  SD_BIN_WIDTH_FOUR             (2 << 3)
+#define  SD_BIN_WIDTH_EIGHT            (3 << 3)
+#define  SD_AGGRESSIVENESS(x)          (((x) & 0x7) << 5)
+#define  SD_HW_UPDATE_DLY(x)           (((x) & 0x3) << 8)
+#define  SD_ONESHOT_ENABLE             (1 << 10)
+#define  SD_CORRECTION_MODE_AUTO       (0 << 11)
+#define  SD_CORRECTION_MODE_MAN                (1 << 11)
+
+#define DC_DISP_SD_CSC_COEFF                   0x4c3
+#define  SD_CSC_COEFF_R(x)             (((x) & 0xf) << 4)
+#define  SD_CSC_COEFF_G(x)             (((x) & 0xf) << 12)
+#define  SD_CSC_COEFF_B(x)             (((x) & 0xf) << 20)
+
+#define DC_DISP_SD_LUT(i)                      (0x4c4 + i)
+#define DC_DISP_SD_LUT_NUM                     9
+#define  SD_LUT_R(x)                   (((x) & 0xff) << 0)
+#define  SD_LUT_G(x)                   (((x) & 0xff) << 8)
+#define  SD_LUT_B(x)                   (((x) & 0xff) << 16)
+
+#define DC_DISP_SD_FLICKER_CONTROL             0x4cd
+#define  SD_FC_TIME_LIMIT(x)           (((x) & 0xff) << 0)
+#define  SD_FC_THRESHOLD(x)            (((x) & 0xff) << 8)
+
+#define DC_DISP_SD_PIXEL_COUNT                 0x4ce
+
+#define DC_DISP_SD_HISTOGRAM(i)                        (0x4cf + i)
+#define DC_DISP_SD_HISTOGRAM_NUM               8
+#define  SD_HISTOGRAM_BIN_0(val)       (((val) & (0xff << 0)) >> 0)
+#define  SD_HISTOGRAM_BIN_1(val)       (((val) & (0xff << 8)) >> 8)
+#define  SD_HISTOGRAM_BIN_2(val)       (((val) & (0xff << 16)) >> 16)
+#define  SD_HISTOGRAM_BIN_3(val)       (((val) & (0xff << 24)) >> 24)
+
+#define DC_DISP_SD_BL_PARAMETERS               0x4d7
+#define  SD_BLP_TIME_CONSTANT(x)       (((x) & 0x7ff) << 0)
+#define  SD_BLP_STEP(x)                        (((x) & 0xff) << 8)
+
+#define DC_DISP_SD_BL_TF(i)                    (0x4d8 + i)
+#define DC_DISP_SD_BL_TF_NUM                   4
+#define  SD_BL_TF_POINT_0(x)           (((x) & 0xff) << 0)
+#define  SD_BL_TF_POINT_1(x)           (((x) & 0xff) << 8)
+#define  SD_BL_TF_POINT_2(x)           (((x) & 0xff) << 16)
+#define  SD_BL_TF_POINT_3(x)           (((x) & 0xff) << 24)
+
+#define DC_DISP_SD_BL_CONTROL                  0x4dc
+#define  SD_BLC_MODE_MAN               (0 << 0)
+#define  SD_BLC_MODE_AUTO              (1 << 1)
+#define  SD_BLC_BRIGHTNESS(val)                (((val) & (0xff << 8)) >> 8)
+
+#define DC_DISP_SD_HW_K_VALUES                 0x4dd
+#define  SD_HW_K_R(val)                        (((val) & (0x3ff << 0)) >> 0)
+#define  SD_HW_K_G(val)                        (((val) & (0x3ff << 10)) >> 10)
+#define  SD_HW_K_B(val)                        (((val) & (0x3ff << 20)) >> 20)
+
+#define DC_DISP_SD_MAN_K_VALUES                        0x4de
+#define  SD_MAN_K_R(x)                 (((x) & 0x3ff) << 0)
+#define  SD_MAN_K_G(x)                 (((x) & 0x3ff) << 10)
+#define  SD_MAN_K_B(x)                 (((x) & 0x3ff) << 20)
+
 #endif
diff --git a/drivers/video/tegra/dc/nvsd.c b/drivers/video/tegra/dc/nvsd.c
new file mode 100644 (file)
index 0000000..40ab9c1
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * drivers/video/tegra/dc/nvsd.c
+ *
+ * Copyright (c) 2010-2011, NVIDIA Corporation.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <mach/dc.h>
+#include <linux/types.h>
+
+#include "dc_reg.h"
+#include "dc_priv.h"
+#include "nvsd.h"
+
+static atomic_t *sd_brightness = NULL;
+
+void nvsd_init(struct tegra_dc *dc, struct tegra_dc_sd_settings *settings) {
+       u32 i = 0, val = 0;
+       /* TODO: check if HW says SD's available */
+
+       /* If SD's not present or disabled, clear the register and return. */
+       if (!settings || settings->enable == 0) {
+               /* clear the brightness val, too. */
+               if (sd_brightness)
+                       atomic_set(sd_brightness, 255);
+               sd_brightness = NULL;
+
+               tegra_dc_writel(dc, 0, DC_DISP_SD_CONTROL);
+               return;
+       }
+
+       dev_dbg(&dc->ndev->dev, "===================\n");
+       dev_dbg(&dc->ndev->dev, "**** NVSD_INIT ****\n");
+
+       /* Write LUT */
+       for (i = 0; i < DC_DISP_SD_LUT_NUM; i++) {
+               val =   SD_LUT_R(settings->lut[i].r) |
+                       SD_LUT_G(settings->lut[i].g) |
+                       SD_LUT_B(settings->lut[i].b);
+               tegra_dc_writel(dc, val, DC_DISP_SD_LUT(i));
+
+               dev_dbg(&dc->ndev->dev, "LUT(%d): 0x%08x\n", i, val);
+       }
+
+       /* Write BL TF */
+       for (i = 0; i < DC_DISP_SD_BL_TF_NUM; i++) {
+               val =   SD_BL_TF_POINT_0(settings->bltf[i][0]) |
+                       SD_BL_TF_POINT_1(settings->bltf[i][1]) |
+                       SD_BL_TF_POINT_2(settings->bltf[i][2]) |
+                       SD_BL_TF_POINT_3(settings->bltf[i][3]);
+               tegra_dc_writel(dc, val, DC_DISP_SD_BL_TF(i));
+
+               dev_dbg(&dc->ndev->dev, "BL_TF(%d): 0x%08x\n", i, val);
+       }
+
+       /* Write Coeff */
+       val =   SD_CSC_COEFF_R(settings->coeff.r) |
+               SD_CSC_COEFF_G(settings->coeff.g) |
+               SD_CSC_COEFF_B(settings->coeff.b);
+       tegra_dc_writel(dc, val, DC_DISP_SD_CSC_COEFF);
+       dev_dbg(&dc->ndev->dev, "COEFF: 0x%08x\n", val);
+
+       /* Write BL Params */
+       val =   SD_BLP_TIME_CONSTANT(settings->blp.time_constant) |
+               SD_BLP_STEP(settings->blp.step);
+       tegra_dc_writel(dc, val, DC_DISP_SD_BL_PARAMETERS);
+       dev_dbg(&dc->ndev->dev, "BLP: 0x%08x\n", val);
+
+       /* Write Auto/Manual PWM */
+       val = (settings->use_auto_pwm) ? SD_BLC_MODE_AUTO : SD_BLC_MODE_MAN;
+       tegra_dc_writel(dc, val, DC_DISP_SD_BL_CONTROL);
+       dev_dbg(&dc->ndev->dev, "BL_CONTROL: 0x%08x\n", val);
+
+       /* Write Flicker Control */
+       val =   SD_FC_TIME_LIMIT(settings->fc.time_limit) |
+               SD_FC_THRESHOLD(settings->fc.threshold);
+       tegra_dc_writel(dc, val, DC_DISP_SD_FLICKER_CONTROL);
+       dev_dbg(&dc->ndev->dev, "FLICKER_CONTROL: 0x%08x\n", val);
+
+       /* Manage SD Control */
+       val = 0;
+       /* Enable / One-Shot */
+       val |= (settings->enable == 2) ?
+                       (SD_ENABLE_ONESHOT | SD_ONESHOT_ENABLE) :
+                       SD_ENABLE_NORMAL;
+       /* HW Update Delay */
+       val |= SD_HW_UPDATE_DLY(settings->hw_update_delay);
+       /* Video Luma */
+       val |= (settings->use_vid_luma) ? SD_USE_VID_LUMA : 0;
+       /* Aggressiveness */
+       val |= SD_AGGRESSIVENESS(settings->aggressiveness);
+       /* Bin Width */
+       switch (settings->bin_width) {
+               default: case 0:
+                       /* A 0 bin-width indicates 'automatic'
+                          based upon aggressiveness. */
+                       switch (settings->aggressiveness) {
+                               default: case 0: case 1:
+                                       val |= SD_BIN_WIDTH_ONE;
+                                       break;
+                               case 2: case 3: case 4:
+                                       val |= SD_BIN_WIDTH_TWO;
+                                       break;
+                               case 5:
+                                       val |= SD_BIN_WIDTH_FOUR;
+                                       break;
+                       }
+                       break;
+               case 1: val |= SD_BIN_WIDTH_ONE; break;
+               case 2: val |= SD_BIN_WIDTH_TWO; break;
+               case 4: val |= SD_BIN_WIDTH_FOUR; break;
+               case 8: val |= SD_BIN_WIDTH_EIGHT; break;
+       }
+
+       /* TODO: histogram reset WAR? */
+
+       /* Finally, Write SD Control */
+       tegra_dc_writel(dc, val, DC_DISP_SD_CONTROL);
+       dev_dbg(&dc->ndev->dev, "SD_CONTROL: 0x%08x\n", val);
+
+       /* set the brightness pointer */
+       sd_brightness = settings->sd_brightness;
+       dev_dbg(&dc->ndev->dev, "sd_brightness: 0x%08x\n", (u32)sd_brightness);
+
+       dev_dbg(&dc->ndev->dev, "*******************\n");
+       dev_dbg(&dc->ndev->dev, "===================\n");
+}
+
+bool nvsd_update_brightness(struct tegra_dc *dc) {
+       u32 val = 0;
+       int cur_sd_brightness;
+
+       if (sd_brightness) {
+               /* TODO: histogram reset WAR? */
+
+               cur_sd_brightness = atomic_read(sd_brightness);
+
+               /* read brightness value */
+               val = tegra_dc_readl(dc, DC_DISP_SD_BL_CONTROL);
+               val = SD_BLC_BRIGHTNESS(val);
+
+               if (val != (u32)cur_sd_brightness)
+               {
+                       /* set brightness value and note the update */
+                       atomic_set(sd_brightness, (int)val);
+                       return true;
+               }
+               /* TODO: log? */
+       }
+
+       /* No update needed. */
+       return false;
+}
diff --git a/drivers/video/tegra/dc/nvsd.h b/drivers/video/tegra/dc/nvsd.h
new file mode 100644 (file)
index 0000000..6d08226
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * drivers/video/tegra/dc/nvsd.h
+ *
+ * Copyright (c) 2010-2011, NVIDIA Corporation.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __DRIVERS_VIDEO_TEGRA_DC_NVSD_H
+#define __DRIVERS_VIDEO_TEGRA_DC_NVSD_H
+
+void nvsd_init(struct tegra_dc *dc, struct tegra_dc_sd_settings *settings);
+bool nvsd_update_brightness(struct tegra_dc *dc);
+
+#endif