ARM: tegra: dvfs: Add offset to rail alignment
Alex Frid [Fri, 2 Aug 2013 04:02:05 +0000 (21:02 -0700)]
With the introduction of analog PWM regulator on Tegra12 platforms,
minimum cpu voltage may not be exactly aligned with PWM steps. The
respective offset is specified by platform data early enough for dvfs
initialization, and accounted for when rounding dvfs cvb voltages.

Bug 1310396

Change-Id: I4ff570a5c0519b85085b3b5e22076b906e95068c
Signed-off-by: Alex Frid <afrid@nvidia.com>
Reviewed-on: http://git-master/r/257344
Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>

arch/arm/mach-tegra/board-ardbeg-power.c
arch/arm/mach-tegra/board-ardbeg.c
arch/arm/mach-tegra/board-ardbeg.h
arch/arm/mach-tegra/dvfs.h
arch/arm/mach-tegra/tegra12_dvfs.c

index 1ae4762..9f746a6 100644 (file)
@@ -37,6 +37,7 @@
 #include <asm/mach-types.h>
 
 #include "pm.h"
+#include "dvfs.h"
 #include "board.h"
 #include "tegra-board-id.h"
 #include "board-common.h"
@@ -1485,17 +1486,6 @@ static struct platform_device *pfixed_reg_devs[] = {
 
 #define ARDBEG_E1735_CVB_ALIGNMENT     18750
 #define ARDBEG_DEFAULT_CVB_ALIGNMENT   10000
-int tegra_get_cvb_alignment_uV(void)
-{
-       struct board_info pmu_board_info;
-
-       tegra_get_pmu_board_info(&pmu_board_info);
-
-       if (pmu_board_info.board_id == BOARD_E1735)
-               return ARDBEG_E1735_CVB_ALIGNMENT;
-       else
-               return ARDBEG_DEFAULT_CVB_ALIGNMENT;
-}
 
 #ifdef CONFIG_ARCH_TEGRA_HAS_CL_DVFS
 /* board parameters for cpu dfll */
@@ -1560,6 +1550,20 @@ static inline int ardbeg_cl_dvfs_init(u16 pmu_board_id)
 { return 0; }
 #endif
 
+int __init ardbeg_rail_alignment_init(void)
+{
+       struct board_info pmu_board_info;
+
+       tegra_get_pmu_board_info(&pmu_board_info);
+
+       if (pmu_board_info.board_id == BOARD_E1735)
+               tegra12x_vdd_cpu_align(ARDBEG_E1735_CVB_ALIGNMENT,
+                                      675000);
+       else
+               tegra12x_vdd_cpu_align(ARDBEG_DEFAULT_CVB_ALIGNMENT, 0);
+       return 0;
+}
+
 static int __init ardbeg_fixed_regulator_init(void)
 {
        struct board_info pmu_board_info;
index 22613ed..5e137ba 100644 (file)
@@ -1115,6 +1115,12 @@ static void __init ardbeg_ramconsole_reserve(unsigned long size)
        tegra_ram_console_debug_reserve(SZ_1M);
 }
 
+static void __init tegra_ardbeg_init_early(void)
+{
+       ardbeg_rail_alignment_init();
+       tegra12x_init_early();
+}
+
 static void __init tegra_ardbeg_dt_init(void)
 {
        tegra_get_board_info(&board_info);
@@ -1163,7 +1169,7 @@ DT_MACHINE_START(LAGUNA, "laguna")
        .smp            = smp_ops(tegra_smp_ops),
        .map_io         = tegra_map_common_io,
        .reserve        = tegra_ardbeg_reserve,
-       .init_early     = tegra12x_init_early,
+       .init_early     = tegra_ardbeg_init_early,
        .init_irq       = tegra_dt_init_irq,
        .init_time      = tegra_init_timer,
        .init_machine   = tegra_ardbeg_dt_init,
@@ -1176,7 +1182,7 @@ DT_MACHINE_START(TN8, "tn8")
        .smp            = smp_ops(tegra_smp_ops),
        .map_io         = tegra_map_common_io,
        .reserve        = tegra_ardbeg_reserve,
-       .init_early     = tegra12x_init_early,
+       .init_early     = tegra_ardbeg_init_early,
        .init_irq       = tegra_dt_init_irq,
        .init_time      = tegra_init_timer,
        .init_machine   = tegra_ardbeg_dt_init,
@@ -1190,7 +1196,7 @@ DT_MACHINE_START(ARDBEG, "ardbeg")
        .map_io         = tegra_map_common_io,
        .reserve        = tegra_ardbeg_reserve,
 #ifdef CONFIG_ARCH_TEGRA_12x_SOC
-       .init_early     = tegra12x_init_early,
+       .init_early     = tegra_ardbeg_init_early,
 #else
        .init_early     = tegra11x_init_early,
 #endif
index d1f7cf2..370b5ce 100644 (file)
@@ -34,6 +34,7 @@ int ardbeg_sensors_init(void);
 int ardbeg_regulator_init(void);
 int ardbeg_suspend_init(void);
 int ardbeg_pmon_init(void);
+int ardbeg_rail_alignment_init(void);
 
 /* Invensense MPU Definitions */
 #define MPU_GYRO_NAME          "mpu9250"
index 2b0014d..c543b4c 100644 (file)
@@ -57,6 +57,11 @@ struct rail_stats {
        int bin_uV;
 };
 
+struct rail_alignment {
+       int offset_uv;
+       int step_uv;
+};
+
 struct dvfs_rail {
        const char *reg_id;
        int min_millivolts;
@@ -92,6 +97,7 @@ struct dvfs_rail {
        int therm_floor_idx;
        struct tegra_cooling_device *vmin_cdev;
        struct tegra_cooling_device *vmax_cdev;
+       struct rail_alignment alignment;
        struct rail_stats stats;
 };
 
@@ -216,6 +222,7 @@ static inline int of_tegra_dvfs_init(const struct of_device_id *matches)
 void tegra11x_init_dvfs(void);
 void tegra12x_init_dvfs(void);
 void tegra14x_init_dvfs(void);
+void tegra12x_vdd_cpu_align(int step_uv, int offset_uv);
 int tegra_enable_dvfs_on_clk(struct clk *c, struct dvfs *d);
 int dvfs_debugfs_init(struct dentry *clk_debugfs_root);
 int tegra_dvfs_late_init(void);
index 74c02b0..7e918e7 100644 (file)
@@ -56,6 +56,12 @@ static struct dvfs_rail tegra12_dvfs_rail_vdd_cpu = {
        .step = VDD_SAFE_STEP,
        .jmp_to_zero = true,
        .vmin_cdev = &cpu_cdev,
+       .alignment = {
+               .step_uv = 10000, /* 10mV */
+       },
+       .stats = {
+               .bin_uV = 10000, /* 10mV */
+       }
 };
 
 static struct dvfs_rail tegra12_dvfs_rail_vdd_core = {
@@ -80,10 +86,10 @@ static struct dvfs_rail *tegra12_dvfs_rails[] = {
        &tegra12_dvfs_rail_vdd_gpu,
 };
 
-/* default cvb alignment on Tegra11 - 10mV */
-int __attribute__((weak)) tegra_get_cvb_alignment_uV(void)
+void __init tegra12x_vdd_cpu_align(int step_uv, int offset_uv)
 {
-       return 10000;
+       tegra12_dvfs_rail_vdd_cpu.alignment.step_uv = step_uv;
+       tegra12_dvfs_rail_vdd_cpu.alignment.offset_uv = offset_uv;
 }
 
 /* CPU DVFS tables */
@@ -477,13 +483,16 @@ static inline int get_cvb_voltage(int speedo, int s_scale,
        return mv;
 }
 
-static inline int round_cvb_voltage(int mv, int v_scale)
+static int round_cvb_voltage(int mv, int v_scale, struct rail_alignment *align)
 {
        /* combined: apply voltage scale and round to cvb alignment step */
-       int cvb_align_step_uv = tegra_get_cvb_alignment_uV();
+       int uv;
+       int step = (align->step_uv ? : 1000) * v_scale;
+       int offset = align->offset_uv * v_scale;
 
-       return DIV_ROUND_UP(mv * 1000, v_scale * cvb_align_step_uv) *
-               cvb_align_step_uv / 1000;
+       uv = max(mv * 1000, offset) - offset;
+       uv = DIV_ROUND_UP(uv, step) * align->step_uv + align->offset_uv;
+       return uv / 1000;
 }
 
 static int __init set_cpu_dvfs_data(
@@ -495,10 +504,11 @@ static int __init set_cpu_dvfs_data(
        unsigned long fmin_use_dfll = 0;
        struct cvb_dvfs_table *table = NULL;
        int speedo = tegra_cpu_speedo_value();
+       struct rail_alignment *align = &tegra12_dvfs_rail_vdd_cpu.alignment;
 
        min_dfll_mv = d->dfll_tune_data.min_millivolts;
-       min_dfll_mv =  round_cvb_voltage(min_dfll_mv * 1000, 1000);
-       d->max_mv = round_cvb_voltage(d->max_mv * 1000, 1000);
+       min_dfll_mv =  round_cvb_voltage(min_dfll_mv * 1000, 1000, align);
+       d->max_mv = round_cvb_voltage(d->max_mv * 1000, 1000, align);
        BUG_ON(min_dfll_mv < tegra12_dvfs_rail_vdd_cpu.min_millivolts);
 
        /*
@@ -519,13 +529,14 @@ static int __init set_cpu_dvfs_data(
 
                dfll_mv = get_cvb_voltage(
                        speedo, d->speedo_scale, &table->cvb_dfll_param);
+
                /* FIXME: Remove guardband later */
                dfll_mv = DIV_ROUND_CLOSEST(dfll_mv * 120, 100);
-               dfll_mv = round_cvb_voltage(dfll_mv, d->voltage_scale);
+               dfll_mv = round_cvb_voltage(dfll_mv, d->voltage_scale, align);
 
                mv = get_cvb_voltage(
                        speedo, d->speedo_scale, &table->cvb_pll_param);
-               mv = round_cvb_voltage(mv, d->voltage_scale);
+               mv = round_cvb_voltage(mv, d->voltage_scale, align);
 
                /*
                 * Check maximum frequency at minimum voltage for dfll source;
@@ -691,9 +702,6 @@ void __init tegra12x_init_dvfs(void)
 #ifndef CONFIG_TEGRA_GPU_DVFS
        tegra_dvfs_gpu_disabled = true;
 #endif
-       /* Setup rail bins */
-       tegra12_dvfs_rail_vdd_cpu.stats.bin_uV = tegra_get_cvb_alignment_uV();
-       tegra12_dvfs_rail_vdd_core.stats.bin_uV = tegra_get_cvb_alignment_uV();
 
        /*
         * Find nominal voltages for core (1st) and cpu rails before rail