/* handle the commands that may be invoked for phase_in_settings */ static void nvsd_cmd_handler(struct tegra_dc_sd_settings *settings, struct tegra_dc *dc) { u32 val; u8 bw_idx, bw; if (settings->cmd & ENABLE) { settings->phase_settings_step++; if (settings->phase_settings_step >= settings->num_phase_in_steps) settings->cmd &= ~ENABLE; nvsd_phase_in_luts(settings, dc); } if (settings->cmd & DISABLE) { settings->phase_settings_step--; nvsd_phase_in_luts(settings, dc); if (settings->phase_settings_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--; /* Update aggressiveness value in HW */ val = tegra_dc_readl(dc, DC_DISP_SD_CONTROL); val &= ~SD_AGGRESSIVENESS(0x7); val |= SD_AGGRESSIVENESS(settings->aggressiveness); /* Adjust bin_width for automatic setting */ if (settings->bin_width == -1) { bw_idx = nvsd_get_bw_idx(settings); bw = bw_idx << 3; val &= ~SD_BIN_WIDTH_MASK; val |= bw; } tegra_dc_writel(dc, val, DC_DISP_SD_CONTROL); nvsd_phase_in_luts(settings, dc); } } }
/* Functional initialization */ void nvsd_init(struct tegra_dc *dc, struct tegra_dc_sd_settings *settings) { u32 i = 0; u32 val = 0; u32 bw_idx = 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; if (settings) settings->phase_settings_step = 0; tegra_dc_writel(dc, 0, DC_DISP_SD_CONTROL); return; } dev_dbg(&dc->ndev->dev, "NVSD Init:\n"); /* init agg_priorities */ if (!settings->agg_priorities.agg[0]) settings->agg_priorities.agg[0] = settings->aggressiveness; /* WAR: Settings will not be valid until the next flip. * Thus, set manual K to either HW's current value (if * we're already enabled) or a non-effective value (if * we're about to enable). */ val = tegra_dc_readl(dc, DC_DISP_SD_CONTROL); if (val & SD_ENABLE_NORMAL) if (settings->phase_in_adjustments) i = tegra_dc_readl(dc, DC_DISP_SD_MAN_K_VALUES); else i = tegra_dc_readl(dc, DC_DISP_SD_HW_K_VALUES); else i = 0; /* 0 values for RGB = 1.0, i.e. non-affected */ tegra_dc_writel(dc, i, DC_DISP_SD_MAN_K_VALUES); /* Enable manual correction mode here so that changing the * settings won't immediately impact display dehavior. */ val |= SD_CORRECTION_MODE_MAN; tegra_dc_writel(dc, val, DC_DISP_SD_CONTROL); bw_idx = nvsd_get_bw_idx(settings); /* Values of SD LUT & BL TF are different according to bin_width on T30 * due to HW bug. Therefore we use bin_width to select the correct table * on T30. */ #ifdef CONFIG_TEGRA_SD_GEN2 bw_idx = 0; #endif /* Write LUT */ 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)); dev_dbg(&dc->ndev->dev, " %d: 0x%08x\n", i, val); } } /* Write BL TF */ 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)); 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); } } /* Set step correctly on init */ if (!settings->cmd && settings->phase_in_settings) { settings->num_phase_in_steps = STEPS_PER_AGG_LVL * settings->aggressiveness; settings->phase_settings_step = settings->enable ? settings->num_phase_in_steps : 0; } /* 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); #ifdef CONFIG_TEGRA_SD_GEN2 /* Write K limit */ if (settings->k_limit_enable) { val = settings->k_limit; if (val < 128) val = 128; else if (val > 255) val = 255; val = SD_K_LIMIT(val); tegra_dc_writel(dc, val, DC_DISP_SD_K_LIMIT); dev_dbg(&dc->ndev->dev, " K_LIMIT: 0x%08x\n", val); } if (settings->sd_window_enable) { /* Write sd window */ val = SD_WIN_H_POSITION(settings->sd_window.h_position) | SD_WIN_V_POSITION(settings->sd_window.v_position); tegra_dc_writel(dc, val, DC_DISP_SD_WINDOW_POSITION); dev_dbg(&dc->ndev->dev, " SD_WINDOW_POSITION: 0x%08x\n", val); val = SD_WIN_H_POSITION(settings->sd_window.h_size) | SD_WIN_V_POSITION(settings->sd_window.v_size); tegra_dc_writel(dc, val, DC_DISP_SD_WINDOW_SIZE); dev_dbg(&dc->ndev->dev, " SD_WINDOW_SIZE: 0x%08x\n", val); } if (settings->soft_clipping_enable) { /* Write soft clipping */ val = (64 * 1024) / (256 - settings->soft_clipping_threshold); val = SD_SOFT_CLIPPING_RECIP(val) | SD_SOFT_CLIPPING_THRESHOLD(settings->soft_clipping_threshold); tegra_dc_writel(dc, val, DC_DISP_SD_SOFT_CLIPPING); dev_dbg(&dc->ndev->dev, " SOFT_CLIPPING: 0x%08x\n", val); } if (settings->smooth_k_enable) { /* Write K incr value */ val = SD_SMOOTH_K_INCR(settings->smooth_k_incr); tegra_dc_writel(dc, val, DC_DISP_SD_SMOOTH_K); dev_dbg(&dc->ndev->dev, " SMOOTH_K: 0x%08x\n", val); } #endif /* Manage SD Control */ val = 0; /* Stay in manual correction mode until the next flip. */ val |= SD_CORRECTION_MODE_MAN; /* 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 (value derived from bw_idx) */ val |= bw_idx << 3; #ifdef CONFIG_TEGRA_SD_GEN2 /* K limit enable */ val |= (settings->k_limit_enable) ? SD_K_LIMIT_ENABLE : 0; /* Programmable sd window enable */ val |= (settings->sd_window_enable) ? SD_WINDOW_ENABLE : 0; /* Soft clipping enable */ val |= (settings->soft_clipping_enable) ? SD_SOFT_CLIPPING_ENABLE : 0; /* Smooth K enable */ val |= (settings->smooth_k_enable) ? SD_SMOOTH_K_ENABLE : 0; /* SD proc control */ val |= (settings->use_vpulse2) ? SD_VPULSE2 : SD_VSYNC; #endif /* 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; /* note that we're in manual K until the next flip */ atomic_set(&man_k_until_blank, 1); }
/* Functional initialization */ void nvsd_init(struct tegra_dc *dc, struct tegra_dc_sd_settings *settings) { u32 i = 0; u32 val = 0; u32 bw_idx = 0; u32 bw = 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, "NVSD Init:\n"); /* WAR: Settings will not be valid until the next flip. * Thus, set manual K to either HW's current value (if * we're already enabled) or a non-effective value (if * we're about to enable). */ val = tegra_dc_readl(dc, DC_DISP_SD_CONTROL); if (val & SD_ENABLE_NORMAL) i = tegra_dc_readl(dc, DC_DISP_SD_HW_K_VALUES); else i = 0; /* 0 values for RGB = 1.0, i.e. non-affected */ tegra_dc_writel(dc, i, DC_DISP_SD_MAN_K_VALUES); /* Enable manual correction mode here so that changing the * settings won't immediately impact display dehavior. */ 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; /* Write LUT */ 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)); dev_dbg(&dc->ndev->dev, " %d: 0x%08x\n", i, val); } /* Write BL TF */ 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)); dev_dbg(&dc->ndev->dev, " %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; /* Stay in manual correction mode until the next flip. */ val |= SD_CORRECTION_MODE_MAN; /* 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 (value derived above) */ val |= bw; /* 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; /* note that we're in manual K until the next flip */ atomic_set(&man_k_until_blank, 1); }
/* Functional initialization */ void nvsd_init(struct tegra_dc *dc, struct tegra_dc_sd_settings *settings) { u32 i = 0; u32 val = 0; u32 bw_idx = 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; if (settings) settings->phase_settings_step = 0; tegra_dc_writel(dc, 0, DC_DISP_SD_CONTROL); return; } dev_dbg(&dc->ndev->dev, "NVSD Init:\n"); /* init agg_priorities */ if (!settings->agg_priorities.agg[0]) settings->agg_priorities.agg[0] = settings->aggressiveness; /* WAR: Settings will not be valid until the next flip. * Thus, set manual K to either HW's current value (if * we're already enabled) or a non-effective value (if * we're about to enable). */ val = tegra_dc_readl(dc, DC_DISP_SD_CONTROL); if (val & SD_ENABLE_NORMAL) i = tegra_dc_readl(dc, DC_DISP_SD_HW_K_VALUES); else i = 0; /* 0 values for RGB = 1.0, i.e. non-affected */ tegra_dc_writel(dc, i, DC_DISP_SD_MAN_K_VALUES); /* Enable manual correction mode here so that changing the * settings won't immediately impact display dehavior. */ val |= SD_CORRECTION_MODE_MAN; tegra_dc_writel(dc, val, DC_DISP_SD_CONTROL); bw_idx = nvsd_get_bw_idx(settings); /* Write LUT */ 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)); dev_dbg(&dc->ndev->dev, " %d: 0x%08x\n", i, val); } } /* Write BL TF */ 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)); 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); } } /* Set step correctly on init */ if (!settings->cmd && settings->phase_in_settings) { settings->num_phase_in_steps = STEPS_PER_AGG_LVL * settings->aggressiveness; settings->phase_settings_step = settings->enable ? settings->num_phase_in_steps : 0; } /* 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; /* Stay in manual correction mode until the next flip. */ val |= SD_CORRECTION_MODE_MAN; /* 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 (value derived from bw_idx) */ val |= bw_idx << 3; /* 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; /* note that we're in manual K until the next flip */ atomic_set(&man_k_until_blank, 1); }