]> nv-tegra.nvidia Code Review - linux-4.9.git/commitdiff
drivers: allow dvfs to set external vmin to dfll
authorMartin Gao <marting@nvidia.com>
Sat, 6 Oct 2018 21:53:25 +0000 (14:53 -0700)
committermobile promotions <svcmobile_promotions@nvidia.com>
Fri, 2 Nov 2018 12:50:59 +0000 (05:50 -0700)
- added field named external_floor_output in tegra_dfll struct, and API to
  allow dvfs to set Vmin in CLDVFS mode
- added field named joint_rail_with_dfll in dvfs_rail struct, so
  external floor is only enforced on rail connected with dfll
- this feature should only be enabled on merge rail platform, and it's
  controlbed by DT chosen "nvidia,tegra-joint_xpu_rail". Also cc3/cc4
  need to be disabled

Bug 2412305

Change-Id: Ia3995f7a64d768d77bee75014d883118c5334444
Signed-off-by: Martin Gao <marting@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1922563
(cherry picked from commit 1445eaacccde408f39f948811a81d85f37a4ebb9)
Reviewed-on: https://git-master.nvidia.com/r/1940547
GVS: Gerrit_Virtual_Submit
Reviewed-by: Vinayak Pane <vpane@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
drivers/clk/tegra/clk-dfll.c
drivers/soc/tegra/tegra-dvfs.c
drivers/soc/tegra/tegra210-dvfs.c
include/soc/tegra/tegra-dfll.h
include/soc/tegra/tegra-dvfs.h

index 416983d99ca62749b0f374055e19d2ee6f7daf06..f17014b9c38dba221ef89afca4ea76eb580b5d37 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * clk-dfll.c - Tegra DFLL clock source common code
  *
- * Copyright (C) 2012-2014 NVIDIA Corporation. All rights reserved.
+ * Copyright (C) 2012-2018 NVIDIA Corporation. All rights reserved.
  *
  * Aleksandr Frid <afrid@nvidia.com>
  * Paul Walmsley <pwalmsley@nvidia.com>
@@ -424,6 +424,9 @@ struct tegra_dfll {
        /* spinlock protecting register accesses */
        spinlock_t                      lock;
 
+       /* Vmin set from external rail connected to dfll */
+       unsigned int                    external_floor_output;
+
        /* Thermal parameters */
        unsigned int                    thermal_floor_output;
        unsigned int                    thermal_floor_index;
@@ -553,7 +556,8 @@ static u8 dfll_get_output_min(struct tegra_dfll *td)
 
        tune_min = td->tune_range == DFLL_TUNE_LOW ?
                        td->lut_bottom : td->tune_high_out_min;
-       return max(tune_min, td->thermal_floor_output);
+       return max_t(unsigned int, max(tune_min, td->thermal_floor_output),
+                       td->external_floor_output);
 }
 
 static void set_force_out_min(struct tegra_dfll *td)
@@ -1682,6 +1686,7 @@ static void dfll_init_out_if(struct tegra_dfll *td)
        u32 val;
        int index, mv;
 
+       td->external_floor_output = 0;
        td->thermal_floor_output = 0;
        if (td->soc->thermal_floor_table_size) {
                index = 0;
@@ -2412,6 +2417,51 @@ static void dfll_unregister_clk(struct tegra_dfll *td)
        td->dfll_clk = NULL;
 }
 
+/*
+ * External floor interface
+ */
+
+/**
+ * tegra_dfll_set_external_floor_mv - get Vmin setting from external
+ * rail, which is physically connected to cpu dfll rail
+ * @external_floor_mv: Vmin requested by connected external rail
+ */
+int tegra_dfll_set_external_floor_mv(int external_floor_mv)
+{
+       unsigned long flags;
+       unsigned int max;
+       u8 new_output;
+
+       if (!tegra_dfll_dev) {
+               pr_err("%s: null tegra dfll dev.\n", __func__);
+               return -EINVAL;
+       }
+
+       max = tegra_dfll_dev->lut_uv[tegra_dfll_dev->lut_max] / 1000;
+       if (external_floor_mv < 0 || external_floor_mv > max) {
+               pr_err("%s: invalid external vmin requested %d\n",
+                               __func__, external_floor_mv);
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&tegra_dfll_dev->lock, flags);
+
+       new_output = find_mv_out_cap(tegra_dfll_dev, external_floor_mv);
+       if (tegra_dfll_dev->external_floor_output != new_output) {
+               tegra_dfll_dev->external_floor_output = new_output;
+               if (tegra_dfll_dev->mode == DFLL_CLOSED_LOOP)
+                       dfll_request_rate(tegra_dfll_dev,
+                                       dfll_request_get(tegra_dfll_dev));
+       }
+
+       spin_unlock_irqrestore(&tegra_dfll_dev->lock, flags);
+
+       /* Add delay to ensure new Vmin delivery is finished before return */
+       udelay(2 * DIV_ROUND_UP(1000000, tegra_dfll_dev->sample_rate));
+
+       return 0;
+}
+
 /*
  * Thermal interface
  */
@@ -3266,6 +3316,24 @@ static int fout_mv_set(void *data, u64 val)
 }
 DEFINE_SIMPLE_ATTRIBUTE(fout_mv_fops, fout_mv_get, fout_mv_set, "%llu\n");
 
+static int external_floor_mv_get(void *data, u64 *val)
+{
+       struct tegra_dfll *td = data;
+
+       *val = td->lut_uv[td->external_floor_output] / 1000;
+
+       return 0;
+}
+
+static int external_floor_mv_set(void *data, u64 val)
+{
+       tegra_dfll_set_external_floor_mv((int)val);
+
+       return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(external_floor_mv_fops, external_floor_mv_get,
+               external_floor_mv_set, "%llu\n");
+
 static int undershoot_get(void *data, u64 *val)
 {
        struct tegra_dfll *td = data;
@@ -3570,6 +3638,8 @@ static struct {
        { "enable", S_IRUGO | S_IWUSR, &enable_fops },
        { "lock", S_IRUGO | S_IWUSR, &lock_fops },
        { "force_out_mv", S_IRUGO | S_IWUSR, &fout_mv_fops },
+       { "external_floor_mv", S_IRUGO | S_IWUSR,
+               &external_floor_mv_fops },
        { "pmu_undershoot_gb", S_IRUGO | S_IWUSR, &undershoot_fops },
        { "tune_high_mv", S_IRUGO | S_IWUSR, &tune_high_mv_fops },
        { "calibr_delay", S_IRUGO | S_IWUSR, &calibr_delay_fops },
index 4545a659128d2adcea7d7d7fec3a59305632e302..0483b550437da9b5dbba2c2ffa1f84fae9f6c706 100644 (file)
@@ -4,7 +4,7 @@
  * Author:
  *     Colin Cross <ccross@google.com>
  *
- * Copyright (c) 2014-2017, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2014-2018, NVIDIA CORPORATION.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -190,6 +190,9 @@ static int dvfs_rail_set_voltage_reg(struct dvfs_rail *rail, int millivolts)
 {
        int ret;
 
+       if (rail->joint_rail_with_dfll)
+               tegra_dfll_set_external_floor_mv(rail->new_millivolts);
+
        ret = regulator_set_voltage(rail->reg,
                millivolts * 1000,
                rail->max_millivolts * 1000);
index 78442eb5f99f46d7d93a34dff1b4c4d06322d071..ffa352d1665f2d432fc3dd06840990ad3ecc8b5c 100644 (file)
@@ -2266,6 +2266,9 @@ static int tegra210x_init_dvfs(struct device *dev, bool cpu_lp_init)
        /* Init rail structures and dependencies */
        tegra_dvfs_init_rails(vdd_dvfs_rails, dvfs_data->rails_num);
 
+       if (of_property_read_bool(of_chosen, "nvidia,tegra-joint_xpu_rail"))
+               vdd_dvfs_rails[VDD_GPU_INDEX]->joint_rail_with_dfll = true;
+
        /*
         * Initialize matching cpu dvfs entry already found when nominal
         * voltage was determined
index cbbd6732b22fa73423767fc8fbc46c1d9bab823d..904dce59013ed1f83990354584e58c5f7d87e07f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2017, NVIDIA Corporation. All rights reserved.
+ * Copyright (c) 2014-2018, NVIDIA Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -36,6 +36,7 @@ extern int tegra_dfll_get_thermal_index(struct tegra_dfll *td,
                        enum tegra_dfll_thermal_type type);
 extern int tegra_dfll_count_thermal_states(struct tegra_dfll *td,
                        enum tegra_dfll_thermal_type type);
+int tegra_dfll_set_external_floor_mv(int external_floor_mv);
 u32 tegra_dfll_get_thermal_floor_mv(void);
 u32 tegra_dfll_get_peak_thermal_floor_mv(void);
 u32 tegra_dfll_get_thermal_cap_mv(void);
index 1fe112b2f3abbfba1d8bed0e49c67fa0788aa484..ff48e9858f69412ec034f00d7ce62161ad7b299d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2017, NVIDIA Corporation. All rights reserved.
+ * Copyright (c) 2014-2018, NVIDIA Corporation. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -107,6 +107,7 @@ struct dvfs_rail {
 
        bool suspended;
        bool dfll_mode;
+       bool joint_rail_with_dfll;
 
        struct rail_alignment alignment;
        struct rail_stats stats;