summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorMatt Wagner <mwagner@nvidia.com>2011-09-01 15:09:40 -0700
committerRyan Wong <ryanw@nvidia.com>2011-09-07 11:24:11 -0700
commite66968c944f2b99eba5a8ea40306c81bc148923e (patch)
tree72b110b4b3f6c62c0a062da1191694528a75a43f /drivers
parente1fa6f8826cdd1674745b54dcad8042f5d5acce5 (diff)
Settings in DIDIM driver are now phased in over a defined number of steps in order to minimize the perception of changes to the settings during runtime Bug 840155 Change-Id: Id1a354dc153a432cdd08d54f197adb6b37d2fdb0 Reviewed-on: http://git-master/r/50926 Tested-by: Matt Wagner <mwagner@nvidia.com> Reviewed-by: Ryan Wong <ryanw@nvidia.com> Tested-by: Ryan Wong <ryanw@nvidia.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/video/tegra/dc/dc.c2
-rw-r--r--drivers/video/tegra/dc/dc_reg.h3
-rw-r--r--drivers/video/tegra/dc/nvsd.c292
3 files changed, 240 insertions, 57 deletions
diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c
index 94580d90aff1..54d8a9f7ede1 100644
--- a/drivers/video/tegra/dc/dc.c
+++ b/drivers/video/tegra/dc/dc.c
@@ -1822,7 +1822,7 @@ static void tegra_dc_vblank(struct work_struct *work)
tegra_dc_program_bandwidth(dc);
/* Update the SD brightness */
- if (dc->enabled)
+ if (dc->enabled && dc->out->sd_settings)
nvsd_updated = nvsd_update_brightness(dc);
mutex_unlock(&dc->lock);
diff --git a/drivers/video/tegra/dc/dc_reg.h b/drivers/video/tegra/dc/dc_reg.h
index d5fb4fd7c547..0d3436ea4f05 100644
--- a/drivers/video/tegra/dc/dc_reg.h
+++ b/drivers/video/tegra/dc/dc_reg.h
@@ -487,6 +487,9 @@
#define SD_CORRECTION_MODE_MAN (1 << 11)
#define NUM_BIN_WIDTHS 4
+#define STEPS_PER_AGG_LVL 32
+#define STEPS_PER_AGG_CHG_LOG2 4
+#define STEPS_PER_AGG_CHG (1<<STEPS_PER_AGG_CHG_LOG2)
#define DC_DISP_SD_CSC_COEFF 0x4c3
#define SD_CSC_COEFF_R(x) (((x) & 0xf) << 4)
diff --git a/drivers/video/tegra/dc/nvsd.c b/drivers/video/tegra/dc/nvsd.c
index 97d687508a1e..6c214b2b4596 100644
--- a/drivers/video/tegra/dc/nvsd.c
+++ b/drivers/video/tegra/dc/nvsd.c
@@ -42,6 +42,7 @@ static ssize_t nvsd_registers_show(struct kobject *kobj,
NVSD_ATTR(enable);
NVSD_ATTR(aggressiveness);
+NVSD_ATTR(phase_in);
NVSD_ATTR(bin_width);
NVSD_ATTR(hw_update_delay);
NVSD_ATTR(use_vid_luma);
@@ -58,6 +59,7 @@ static struct kobj_attribute nvsd_attr_registers =
static struct attribute *nvsd_attrs[] = {
NVSD_ATTRS_ENTRY(enable),
NVSD_ATTRS_ENTRY(aggressiveness),
+ NVSD_ATTRS_ENTRY(phase_in),
NVSD_ATTRS_ENTRY(bin_width),
NVSD_ATTRS_ENTRY(hw_update_delay),
NVSD_ATTRS_ENTRY(use_vid_luma),
@@ -83,6 +85,156 @@ static atomic_t *sd_brightness = NULL;
/* shared boolean for manual K workaround */
static atomic_t man_k_until_blank = ATOMIC_INIT(0);
+static u8 nvsd_get_bw_idx(struct tegra_dc_sd_settings *settings)
+{
+ u8 bw;
+
+ switch (settings->bin_width) {
+ default:
+ case -1:
+ /* A -1 bin-width indicates 'automatic'
+ based upon aggressiveness. */
+ settings->bin_width = -1;
+ switch (settings->aggressiveness) {
+ default:
+ case 0:
+ case 1:
+ bw = SD_BIN_WIDTH_ONE;
+ break;
+ case 2:
+ case 3:
+ case 4:
+ bw = SD_BIN_WIDTH_TWO;
+ break;
+ case 5:
+ bw = SD_BIN_WIDTH_FOUR;
+ break;
+ }
+ break;
+ case 1:
+ bw = SD_BIN_WIDTH_ONE;
+ break;
+ case 2:
+ bw = SD_BIN_WIDTH_TWO;
+ break;
+ case 4:
+ bw = SD_BIN_WIDTH_FOUR;
+ break;
+ case 8:
+ bw = SD_BIN_WIDTH_EIGHT;
+ break;
+ }
+ return bw >> 3;
+
+}
+
+/* phase in the luts based on the current and max step */
+static void nvsd_phase_in_luts(struct tegra_dc_sd_settings *settings,
+ struct tegra_dc *dc)
+{
+ u32 val;
+ u8 bw_idx;
+ int i;
+ u16 cur_phase_step = settings->cur_phase_step;
+ u16 phase_in_steps = settings->phase_in_steps;
+
+ bw_idx = nvsd_get_bw_idx(settings);
+
+ /* Phase in Final LUT */
+ for (i = 0; i < DC_DISP_SD_LUT_NUM; i++) {
+ val = SD_LUT_R((settings->lut[bw_idx][i].r *
+ cur_phase_step)/phase_in_steps) |
+ SD_LUT_G((settings->lut[bw_idx][i].g *
+ cur_phase_step)/phase_in_steps) |
+ SD_LUT_B((settings->lut[bw_idx][i].b *
+ cur_phase_step)/phase_in_steps);
+
+ tegra_dc_writel(dc, val, DC_DISP_SD_LUT(i));
+ }
+ /* Phase in Final BLTF */
+ for (i = 0; i < DC_DISP_SD_BL_TF_NUM; i++) {
+ val = SD_BL_TF_POINT_0(255-((255-settings->bltf[bw_idx][i][0])
+ * cur_phase_step)/phase_in_steps) |
+ SD_BL_TF_POINT_1(255-((255-settings->bltf[bw_idx][i][1])
+ * cur_phase_step)/phase_in_steps) |
+ SD_BL_TF_POINT_2(255-((255-settings->bltf[bw_idx][i][2])
+ * cur_phase_step)/phase_in_steps) |
+ SD_BL_TF_POINT_3(255-((255-settings->bltf[bw_idx][i][3])
+ * cur_phase_step)/phase_in_steps);
+
+ tegra_dc_writel(dc, val, DC_DISP_SD_BL_TF(i));
+ }
+}
+
+/* handle the commands that may be invoked for phase_in */
+static void nvsd_cmd_handler(struct tegra_dc_sd_settings *settings,
+ struct tegra_dc *dc)
+{
+ u32 val;
+
+ if (settings->cmd & ENABLE) {
+ settings->cur_phase_step++;
+ if (settings->cur_phase_step >= settings->phase_in_steps)
+ settings->cmd &= ~ENABLE;
+
+ nvsd_phase_in_luts(settings, dc);
+ }
+ if (settings->cmd & DISABLE) {
+ settings->cur_phase_step--;
+ nvsd_phase_in_luts(settings, dc);
+ if (settings->cur_phase_step == 0) {
+ /* finish up aggressiveness phase in */
+ if (settings->cmd & AGG_CHG)
+ settings->aggressiveness = settings->final_agg;
+ settings->cmd = NO_CMD;
+ settings->enable = 0;
+ nvsd_init(dc, settings);
+ }
+ }
+ if (settings->cmd & AGG_CHG) {
+ if (settings->aggressiveness == settings->final_agg)
+ settings->cmd &= ~AGG_CHG;
+ if ((settings->cur_agg_step++ & (STEPS_PER_AGG_CHG - 1)) == 0) {
+ settings->final_agg > settings->aggressiveness ?
+ settings->aggressiveness++ :
+ settings->aggressiveness--;
+
+ val = tegra_dc_readl(dc, DC_DISP_SD_CONTROL);
+ val &= ~SD_AGGRESSIVENESS(0x7);
+ val |= SD_AGGRESSIVENESS(settings->aggressiveness);
+
+ tegra_dc_writel(dc, val, DC_DISP_SD_CONTROL);
+
+ nvsd_phase_in_luts(settings, dc);
+ }
+ }
+}
+
+static bool nvsd_update_enable(struct tegra_dc_sd_settings *settings,
+ int enable_val)
+{
+
+ if (enable_val != 1 && enable_val != 0)
+ return false;
+
+ if (!settings->cmd) {
+ settings->phase_in_steps =
+ STEPS_PER_AGG_LVL*settings->aggressiveness;
+ settings->cur_phase_step = enable_val ?
+ 0 : settings->phase_in_steps;
+ }
+
+ if (settings->enable != enable_val || settings->cmd & DISABLE) {
+ settings->cmd &= ~(ENABLE | DISABLE);
+ if (!settings->enable && enable_val)
+ settings->cmd |= PHASE_IN;
+ settings->cmd |= enable_val ? ENABLE : DISABLE;
+ return true;
+ }
+
+ return false;
+}
+
/* Functional initialization */
void nvsd_init(struct tegra_dc *dc, struct tegra_dc_sd_settings *settings)
{
@@ -100,6 +252,8 @@ void nvsd_init(struct tegra_dc *dc, struct tegra_dc_sd_settings *settings)
sd_brightness = NULL;
+ if (settings)
+ settings->cur_phase_step = 0;
tegra_dc_writel(dc, 0, DC_DISP_SD_CONTROL);
return;
}
@@ -123,69 +277,57 @@ void nvsd_init(struct tegra_dc *dc, struct tegra_dc_sd_settings *settings)
val |= SD_CORRECTION_MODE_MAN;
tegra_dc_writel(dc, val, DC_DISP_SD_CONTROL);
- switch (settings->bin_width) {
- default:
- case -1:
- /* A -1 bin-width indicates 'automatic'
- * based upon aggressiveness. */
- settings->bin_width = -1;
-
- switch (settings->aggressiveness) {
- default:
- case 0:
- case 1:
- bw = SD_BIN_WIDTH_ONE;
- break;
- case 2:
- case 3:
- case 4:
- bw = SD_BIN_WIDTH_TWO;
- break;
- case 5:
- bw = SD_BIN_WIDTH_FOUR;
- break;
- }
-
- break;
- case 1:
- bw = SD_BIN_WIDTH_ONE;
- break;
- case 2:
- bw = SD_BIN_WIDTH_TWO;
- break;
- case 4:
- bw = SD_BIN_WIDTH_FOUR;
- break;
- case 8:
- bw = SD_BIN_WIDTH_EIGHT;
- break;
- }
-
- bw_idx = bw >> 3;
+ bw_idx = nvsd_get_bw_idx(settings);
/* Write LUT */
- dev_dbg(&dc->ndev->dev, " LUT:\n");
+ if (!settings->cmd) {
+ dev_dbg(&dc->ndev->dev, " LUT:\n");
- for (i = 0; i < DC_DISP_SD_LUT_NUM; i++) {
- val = SD_LUT_R(settings->lut[bw_idx][i].r) |
- SD_LUT_G(settings->lut[bw_idx][i].g) |
- SD_LUT_B(settings->lut[bw_idx][i].b);
- tegra_dc_writel(dc, val, DC_DISP_SD_LUT(i));
+ for (i = 0; i < DC_DISP_SD_LUT_NUM; i++) {
+ val = SD_LUT_R(settings->lut[bw_idx][i].r) |
+ SD_LUT_G(settings->lut[bw_idx][i].g) |
+ SD_LUT_B(settings->lut[bw_idx][i].b);
+ tegra_dc_writel(dc, val, DC_DISP_SD_LUT(i));
- dev_dbg(&dc->ndev->dev, " %d: 0x%08x\n", i, val);
+ dev_dbg(&dc->ndev->dev, " %d: 0x%08x\n", i, val);
+ }
}
/* Write BL TF */
- dev_dbg(&dc->ndev->dev, " BL_TF:\n");
+ if (!settings->cmd) {
+ dev_dbg(&dc->ndev->dev, " BL_TF:\n");
- for (i = 0; i < DC_DISP_SD_BL_TF_NUM; i++) {
- val = SD_BL_TF_POINT_0(settings->bltf[bw_idx][i][0]) |
- SD_BL_TF_POINT_1(settings->bltf[bw_idx][i][1]) |
- SD_BL_TF_POINT_2(settings->bltf[bw_idx][i][2]) |
- SD_BL_TF_POINT_3(settings->bltf[bw_idx][i][3]);
- tegra_dc_writel(dc, val, DC_DISP_SD_BL_TF(i));
+ for (i = 0; i < DC_DISP_SD_BL_TF_NUM; i++) {
+ val = SD_BL_TF_POINT_0(settings->bltf[bw_idx][i][0]) |
+ SD_BL_TF_POINT_1(settings->bltf[bw_idx][i][1]) |
+ SD_BL_TF_POINT_2(settings->bltf[bw_idx][i][2]) |
+ SD_BL_TF_POINT_3(settings->bltf[bw_idx][i][3]);
+
+ tegra_dc_writel(dc, val, DC_DISP_SD_BL_TF(i));
+
+ dev_dbg(&dc->ndev->dev, " %d: 0x%08x\n", i, val);
+ }
+ } else if ((settings->cmd & PHASE_IN)) {
+ settings->cmd &= ~PHASE_IN;
+ /* Write NO_OP values for BLTF */
+ for (i = 0; i < DC_DISP_SD_BL_TF_NUM; i++) {
+ val = SD_BL_TF_POINT_0(0xFF) |
+ SD_BL_TF_POINT_1(0xFF) |
+ SD_BL_TF_POINT_2(0xFF) |
+ SD_BL_TF_POINT_3(0xFF);
+
+ tegra_dc_writel(dc, val, DC_DISP_SD_BL_TF(i));
+
+ dev_dbg(&dc->ndev->dev, " %d: 0x%08x\n", i, val);
+ }
+ }
- dev_dbg(&dc->ndev->dev, " %d: 0x%08x\n", i, val);
+ /* Set step correctly on init */
+ if (!settings->cmd) {
+ settings->phase_in_steps = STEPS_PER_AGG_LVL *
+ settings->aggressiveness;
+ settings->cur_phase_step = settings->enable ?
+ settings->phase_in_steps : 0;
}
/* Write Coeff */
@@ -244,6 +386,7 @@ bool nvsd_update_brightness(struct tegra_dc *dc)
{
u32 val = 0;
int cur_sd_brightness;
+ struct tegra_dc_sd_settings *settings = dc->out->sd_settings;
if (sd_brightness) {
if (atomic_read(&man_k_until_blank)) {
@@ -253,6 +396,13 @@ bool nvsd_update_brightness(struct tegra_dc *dc)
atomic_set(&man_k_until_blank, 0);
}
+ if (settings->cmd)
+ nvsd_cmd_handler(settings, dc);
+
+ /* nvsd_cmd_handler may turn off didim */
+ if (!settings->enable)
+ return true;
+
cur_sd_brightness = atomic_read(sd_brightness);
/* read brightness value */
@@ -334,6 +484,9 @@ static ssize_t nvsd_settings_show(struct kobject *kobj,
else if (IS_NVSD_ATTR(aggressiveness))
res = snprintf(buf, PAGE_SIZE, "%d\n",
sd_settings->aggressiveness);
+ else if (IS_NVSD_ATTR(phase_in))
+ res = snprintf(buf, PAGE_SIZE, "%d\n",
+ sd_settings->phase_in);
else if (IS_NVSD_ATTR(bin_width))
res = snprintf(buf, PAGE_SIZE, "%d\n",
sd_settings->bin_width);
@@ -462,12 +615,39 @@ static ssize_t nvsd_settings_store(struct kobject *kobj,
struct tegra_dc_sd_settings *sd_settings = dc->out->sd_settings;
ssize_t res = count;
bool settings_updated = false;
+ int result;
+ int err;
if (sd_settings) {
if (IS_NVSD_ATTR(enable)) {
- nvsd_check_and_update(0, 1, enable);
+ if (sd_settings->phase_in) {
+ err = strict_strtol(buf, 10, &result);
+ if (err)
+ return err;
+
+ if (nvsd_update_enable(sd_settings, result))
+ nvsd_check_and_update(1, 1, enable);
+
+ } else {
+ nvsd_check_and_update(0, 1, enable);
+ }
} else if (IS_NVSD_ATTR(aggressiveness)) {
- nvsd_check_and_update(1, 5, aggressiveness);
+ if (sd_settings->phase_in && sd_settings->enable) {
+ err = strict_strtol(buf, 10, &result);
+ if (err)
+ return err;
+
+ if (result > 0 && result <= 5 &&
+ result != sd_settings->aggressiveness) {
+
+ sd_settings->cmd |= AGG_CHG;
+ sd_settings->final_agg = result;
+ sd_settings->cur_agg_step = 0;
+ }
+ } else
+ nvsd_check_and_update(1, 5, aggressiveness);
+ } else if (IS_NVSD_ATTR(phase_in)) {
+ nvsd_check_and_update(0, 1, phase_in);
} else if (IS_NVSD_ATTR(bin_width)) {
nvsd_check_and_update(0, 8, bin_width);
} else if (IS_NVSD_ATTR(hw_update_delay)) {