246 lines
7.1 KiB
C
246 lines
7.1 KiB
C
/*
|
|
* Copyright (c) 2013, 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,
|
|
* version 2, as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope 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.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifndef _TEGRA_DVFS_H_
|
|
#define _TEGRA_DVFS_H_
|
|
|
|
#define MAX_DVFS_FREQS 40
|
|
#define DVFS_RAIL_STATS_TOP_BIN 100
|
|
#define DVFS_RAIL_STATS_BIN 12500
|
|
#define MAX_THERMAL_LIMITS 8
|
|
|
|
/*
|
|
* dvfs_relationship between to rails, "from" and "to"
|
|
* when the rail changes, it will call dvfs_rail_update on the rails
|
|
* in the relationship_to list.
|
|
* when determining the voltage to set a rail to, it will consider each
|
|
* rail in the relationship_from list.
|
|
*/
|
|
struct dvfs_relationship {
|
|
struct dvfs_rail *to;
|
|
struct dvfs_rail *from;
|
|
int (*solve)(struct dvfs_rail *, struct dvfs_rail *);
|
|
|
|
struct list_head to_node; /* node in relationship_to list */
|
|
struct list_head from_node; /* node in relationship_from list */
|
|
bool solved_at_nominal;
|
|
};
|
|
|
|
struct cpu_pll_fv_table {
|
|
int freq;
|
|
int volt;
|
|
};
|
|
|
|
struct cpu_dvfs {
|
|
int speedo_id;
|
|
int process_id;
|
|
|
|
int max_mv;
|
|
int min_mv;
|
|
struct cpu_pll_fv_table fv_table[MAX_DVFS_FREQS];
|
|
};
|
|
|
|
struct rail_stats {
|
|
ktime_t time_at_mv[DVFS_RAIL_STATS_TOP_BIN + 1];
|
|
ktime_t last_update;
|
|
int last_index;
|
|
bool off;
|
|
int bin_uv;
|
|
};
|
|
|
|
struct rail_alignment {
|
|
int offset_uv;
|
|
int step_uv;
|
|
};
|
|
|
|
struct dvfs_rail {
|
|
const char *reg_id;
|
|
int min_millivolts;
|
|
int max_millivolts;
|
|
int nominal_millivolts;
|
|
int override_millivolts;
|
|
|
|
int step;
|
|
int step_up;
|
|
bool jmp_to_zero;
|
|
bool disabled;
|
|
bool resolving_to;
|
|
|
|
struct list_head node; /* node in dvfs_rail_list */
|
|
struct list_head dvfs; /* list head of attached dvfs clocks */
|
|
struct list_head relationships_to;
|
|
struct list_head relationships_from;
|
|
struct regulator *reg;
|
|
int millivolts;
|
|
int new_millivolts;
|
|
int disable_millivolts;
|
|
int suspend_millivolts;
|
|
|
|
bool suspended;
|
|
bool dfll_mode;
|
|
|
|
struct rail_alignment alignment;
|
|
struct rail_stats stats;
|
|
|
|
const int *therm_mv_floors;
|
|
int therm_mv_floors_num;
|
|
|
|
int therm_floor_idx;
|
|
struct tegra_cooling_device *vmin_cdev;
|
|
};
|
|
|
|
enum dfll_range {
|
|
DFLL_RANGE_NONE = 0,
|
|
DFLL_RANGE_ALL_RATES,
|
|
DFLL_RANGE_HIGH_RATES,
|
|
};
|
|
|
|
struct dvfs {
|
|
const char *clk_name;
|
|
struct clk *clk;
|
|
int speedo_id;
|
|
int process_id;
|
|
|
|
int freqs_mult;
|
|
unsigned long freqs[MAX_DVFS_FREQS];
|
|
const int *millivolts;
|
|
const int *dfll_millivolts;
|
|
struct dvfs_rail *dvfs_rail;
|
|
bool auto_dvfs;
|
|
|
|
int max_millivolts;
|
|
int num_freqs;
|
|
|
|
enum dfll_range range;
|
|
unsigned long use_dfll_rate_min;
|
|
|
|
int cur_millivolts;
|
|
unsigned long cur_rate;
|
|
struct list_head node;
|
|
struct list_head reg_node;
|
|
};
|
|
|
|
static inline bool tegra_dvfs_rail_is_dfll_mode(struct dvfs_rail *rail)
|
|
{
|
|
return rail ? rail->dfll_mode : false;
|
|
}
|
|
|
|
static inline bool tegra_dvfs_is_dfll_range_entry(struct dvfs *d,
|
|
unsigned long rate)
|
|
{
|
|
return d->cur_rate && d->dvfs_rail && (!d->dvfs_rail->dfll_mode) &&
|
|
(d->range == DFLL_RANGE_HIGH_RATES) &&
|
|
(rate >= d->use_dfll_rate_min) &&
|
|
(d->cur_rate < d->use_dfll_rate_min);
|
|
}
|
|
|
|
static inline bool tegra_dvfs_is_dfll_scale(struct dvfs *d, unsigned long rate)
|
|
{
|
|
return tegra_dvfs_rail_is_dfll_mode(d->dvfs_rail) ||
|
|
tegra_dvfs_is_dfll_range_entry(d, rate);
|
|
}
|
|
|
|
static inline bool dvfs_is_dfll_range(struct dvfs *d, unsigned long rate)
|
|
{
|
|
return (d->range == DFLL_RANGE_ALL_RATES) ||
|
|
((d->range == DFLL_RANGE_HIGH_RATES) &&
|
|
(rate >= d->use_dfll_rate_min));
|
|
}
|
|
|
|
#ifdef CONFIG_TEGRA_DVFS
|
|
int tegra_dvfs_init(void);
|
|
int tegra_dvfs_dfll_mode_set(struct clk *c, unsigned long rate);
|
|
int tegra_dvfs_dfll_mode_clear(struct clk *c, unsigned long rate);
|
|
int tegra_dvfs_get_dfll_threshold(struct clk *c, unsigned long *rate);
|
|
int tegra_dvfs_set_rate(struct clk *c, unsigned long rate);
|
|
unsigned long tegra_dvfs_get_rate(struct clk *c);
|
|
int tegra_dvfs_get_freqs(struct clk *c, unsigned long **freqs, int *num_freqs);
|
|
int tegra_setup_dvfs(struct clk *c, struct dvfs *d);
|
|
int tegra_dvfs_init_rails(struct dvfs_rail *dvfs_rails[], int n);
|
|
void tegra_dvfs_add_relationships(struct dvfs_relationship *rels, int n);
|
|
void tegra_dvfs_rail_enable(struct dvfs_rail *rail);
|
|
void tegra_dvfs_rail_disable(struct dvfs_rail *rail);
|
|
int tegra_dvfs_predict_millivolts(struct clk *c, unsigned long rate);
|
|
bool tegra_dvfs_is_dfll_range(struct clk *c, unsigned long rate);
|
|
int tegra_dvfs_set_dfll_range(struct clk *c, int range);
|
|
void tegra_dvfs_rail_init_vmin_thermal_profile(int *therm_trips_table,
|
|
int *therm_floors_table, struct dvfs_rail *rail);
|
|
struct tegra_cooling_device *tegra_dvfs_get_core_vmin_cdev(void);
|
|
void tegra_dvfs_core_lock(void);
|
|
void tegra_dvfs_core_unlock(void);
|
|
int tegra_dvfs_set_fmax_at_vmin(struct clk *c, unsigned long f_max, int v_min);
|
|
int tegra_dvfs_get_core_nominal_millivolts(void);
|
|
#else
|
|
static inline int tegra_dvfs_init(void)
|
|
{ return 0; }
|
|
static inline int tegra_dvfs_dfll_mode_set(struct clk *c, unsigned long rate)
|
|
{ return -EINVAL; }
|
|
static inline int tegra_dvfs_dfll_mode_clear(struct clk *c, unsigned long rate)
|
|
{ return -EINVAL; }
|
|
static inline int tegra_dvfs_get_dfll_threshold(
|
|
struct clk *c, unsigned long *rate)
|
|
{ return -EINVAL; }
|
|
static inline int tegra_dvfs_set_rate(struct clk *c, unsigned long rate)
|
|
{ return 0; }
|
|
static inline unsigned long tegra_dvfs_get_rate(struct clk *c)
|
|
{ return 0; }
|
|
static inline int tegra_dvfs_get_freqs(
|
|
struct clk *c, unsigned long **freqs, int *num_freqs)
|
|
{ return -EINVAL; }
|
|
static inline int tegra_setup_dvfs(struct clk *c, struct dvfs *d)
|
|
{ return -EINVAL; }
|
|
static inline int tegra_dvfs_init_rails(struct dvfs_rail *dvfs_rails[], int n)
|
|
{ return -EINVAL; }
|
|
static inline void tegra_dvfs_add_relationships(
|
|
struct dvfs_relationship *rels, int n)
|
|
{ return; }
|
|
static inline void tegra_dvfs_rail_enable(struct dvfs_rail *rail)
|
|
{ return; }
|
|
static inline void tegra_dvfs_rail_disable(struct dvfs_rail *rail)
|
|
{ return; }
|
|
static inline int tegra_dvfs_predict_millivolts(
|
|
struct clk *c, unsigned long rate)
|
|
{ return -EINVAL; }
|
|
static inline bool tegra_dvfs_is_dfll_range(struct clk *c, unsigned long rate)
|
|
{ return false; }
|
|
static inline int tegra_dvfs_set_dfll_range(struct clk *c, int range)
|
|
{ return -EINVAL; }
|
|
static inline void tegra_dvfs_rail_init_vmin_thermal_profile(
|
|
int *therm_trips_table, int *therm_floors_table,
|
|
struct dvfs_rail *rail)
|
|
{ return; }
|
|
static inline struct tegra_cooling_device *tegra_dvfs_get_core_vmin_cdev(void)
|
|
{ return ERR_PTR(-EINVAL); }
|
|
static inline void tegra_dvfs_core_lock(void)
|
|
{ return; }
|
|
static inline void tegra_dvfs_core_unlock(void)
|
|
{ return; }
|
|
static inline int tegra_dvfs_set_fmax_at_vmin(struct clk *c,
|
|
unsigned long f_max, int v_min)
|
|
{ return -EINVAL; }
|
|
static inline int tegra_dvfs_get_core_nominal_millivolts(void)
|
|
{ return -ENOENT; }
|
|
#endif
|
|
|
|
#ifdef CONFIG_TEGRA_124_DVFS
|
|
int tegra124_init_dvfs(void);
|
|
#else
|
|
static inline int tegra124_init_dvfs(void)
|
|
{ return -EINVAL; }
|
|
#endif
|
|
|
|
#endif
|