aboutsummaryrefslogblamecommitdiffstats
path: root/arch/arm/mach-tegra/clock.h
blob: dde9e07292a7c045f01c03fd037e8f314bbc441b (plain) (tree)
1
2
3
4
5
6
7
8
9
10







                                           

                                               













                                                                       






                                                                               
 



                                        










                                         








                                         
                                         









                                         
 



                                  
 




                               
                           







                                    




























                                                                                  





                          
            
                                         

                                                                                 
                                       
 


                                      
                                    


                                          

                                         

                                          


                                      
                                       
                                      
                                        

                                    
                                      
 
                                                



                                                        
                                                          
















                                                                    


                                                                     





                                                                 

                                                                    

                        









                                                                   


                                                                



                                                                   


                                  



                                                                        
  
 











                                 








                                                                
                                                      

                                                    
                                                                   




























                                                                            
 
















































                                                                          
      
/*
 * arch/arm/mach-tegra/include/mach/clock.h
 *
 * Copyright (C) 2010 Google, Inc.
 *
 * Author:
 *	Colin Cross <ccross@google.com>
 *
 * Copyright (C) 2010-2012, NVIDIA Corporation.
 *
 * This software is licensed under the terms of the GNU General Public
 * License version 2, as published by the Free Software Foundation, and
 * may be copied, distributed, and modified under those terms.
 *
 * This program is distributed in the hope that 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.
 *
 */

#ifndef __MACH_TEGRA_CLOCK_H
#define __MACH_TEGRA_CLOCK_H

#ifdef CONFIG_ARCH_TEGRA_2x_SOC
#define USE_PLL_LOCK_BITS 0	/* Never use lock bits on Tegra2 */
#else
#define USE_PLL_LOCK_BITS 1	/* Use lock bits for PLL stabiliation */
#define USE_PLLE_SS 1		/* Use spread spectrum coefficients for PLLE */
#define PLL_POST_LOCK_DELAY 50	/* Safety delay after lock is detected */
#endif

#define DIV_BUS			(1 << 0)
#define DIV_U71			(1 << 1)
#define DIV_U71_FIXED		(1 << 2)
#define DIV_2			(1 << 3)
#define DIV_U16			(1 << 4)
#define PLL_FIXED		(1 << 5)
#define PLL_HAS_CPCON		(1 << 6)
#define MUX			(1 << 7)
#define PLLD			(1 << 8)
#define PERIPH_NO_RESET		(1 << 9)
#define PERIPH_NO_ENB		(1 << 10)
#define PERIPH_EMC_ENB		(1 << 11)
#define PERIPH_MANUAL_RESET	(1 << 12)
#define PLL_ALT_MISC_REG	(1 << 13)
#define PLLU			(1 << 14)
#define PLLX			(1 << 15)
#define MUX_PWM			(1 << 16)
#define MUX8			(1 << 17)
#define DIV_U151_UART		(1 << 18)
#define MUX_CLK_OUT		(1 << 19)
#define PLLM			(1 << 20)
#define DIV_U71_INT		(1 << 21)
#define DIV_U71_IDLE		(1 << 22)
#define DIV_U151		(1 << 23)
#define ENABLE_ON_INIT		(1 << 28)
#define PERIPH_ON_APB		(1 << 29)
#define PERIPH_ON_CBUS		(1 << 30)

#ifndef __ASSEMBLY__

#include <linux/clkdev.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
#include <asm/cputime.h>

#include <mach/clk.h>
#define MAX_SAME_LIMIT_SKU_IDS	16

struct clk;

struct clk_mux_sel {
	struct clk	*input;
	u32		value;
};

struct clk_pll_freq_table {
	unsigned long	input_rate;
	unsigned long	output_rate;
	u16		n;
	u16		m;
	u8		p;
	u8		cpcon;
};

struct clk_ops {
	void		(*init)(struct clk *);
	int		(*enable)(struct clk *);
	void		(*disable)(struct clk *);
	int		(*set_parent)(struct clk *, struct clk *);
	int		(*set_rate)(struct clk *, unsigned long);
	long		(*round_rate)(struct clk *, unsigned long);
	int		(*clk_cfg_ex)(struct clk *, enum tegra_clk_ex_param, u32);
	void		(*reset)(struct clk *, bool);
	int		(*shared_bus_update)(struct clk *);
};

struct clk_stats {
	cputime64_t 	time_on;
	u64 		last_update;
};

enum cpu_mode {
	MODE_G = 0,
	MODE_LP,
};

enum shared_bus_users_mode {
	SHARED_FLOOR = 0,
	SHARED_BW,
	SHARED_CEILING,
	SHARED_AUTO,
};

enum clk_state {
	UNINITIALIZED = 0,
	ON,
	OFF,
};

struct clk {
	/* node for master clocks list */
	struct list_head	node;		/* node for list of all clocks */
	struct dvfs 		*dvfs;
	struct clk_lookup	lookup;

#ifdef CONFIG_DEBUG_FS
	struct dentry		*dent;
#endif
	bool			set;
	struct clk_ops		*ops;
	unsigned long		dvfs_rate;
	unsigned long		rate;
	unsigned long		max_rate;
	unsigned long		min_rate;
	bool			auto_dvfs;
	bool			cansleep;
	u32			flags;
	const char		*name;

	u32			refcnt;
	enum clk_state		state;
	struct clk		*parent;
	u32			div;
	u32			mul;
	struct clk_stats 	stats;

	const struct clk_mux_sel	*inputs;
	u32				reg;
	u32				reg_shift;

	struct list_head		shared_bus_list;
	struct clk_mux_sel		shared_bus_backup;

	union {
		struct {
			unsigned int			clk_num;
		} periph;
		struct {
			unsigned long			input_min;
			unsigned long			input_max;
			unsigned long			cf_min;
			unsigned long			cf_max;
			unsigned long			vco_min;
			unsigned long			vco_max;
			const struct clk_pll_freq_table	*freq_table;
			int				lock_delay;
			unsigned long			fixed_rate;
		} pll;
		struct {
			unsigned long			default_rate;
		} pll_div;
		struct {
			u32				sel;
			u32				reg_mask;
		} mux;
		struct {
			struct clk			*main;
			struct clk			*backup;
			unsigned long			backup_rate;
			enum cpu_mode			mode;
		} cpu;
		struct {
			u32				div71;
		} cclk;
		struct {
			struct clk			*pclk;
			struct clk			*hclk;
			struct clk			*sclk_low;
			struct clk			*sclk_high;
			unsigned long			threshold;
		} system;
		struct {
			struct list_head		node;
			bool				enabled;
			unsigned long			rate;
			const char			*client_id;
			struct clk			*client;
			u32				client_div;
			enum shared_bus_users_mode	mode;
		} shared_bus_user;
	} u;

	struct raw_notifier_head			*rate_change_nh;

	struct mutex mutex;
	spinlock_t spinlock;
};

struct clk_duplicate {
	const char *name;
	struct clk_lookup lookup;
};

struct tegra_clk_init_table {
	const char *name;
	const char *parent;
	unsigned long rate;
	bool enabled;
};

struct tegra_sku_rate_limit {
	const char *clk_name;
	unsigned long max_rate;
	int sku_ids[MAX_SAME_LIMIT_SKU_IDS];
};

void tegra_soc_init_clocks(void);
void tegra_init_max_rate(struct clk *c, unsigned long max_rate);
void clk_init(struct clk *clk);
struct clk *tegra_get_clock_by_name(const char *name);
unsigned long tegra_clk_measure_input_freq(void);
int clk_reparent(struct clk *c, struct clk *parent);
void tegra_clk_init_from_table(struct tegra_clk_init_table *table);
void clk_set_cansleep(struct clk *c);
unsigned long clk_get_max_rate(struct clk *c);
unsigned long clk_get_min_rate(struct clk *c);
unsigned long clk_get_rate_locked(struct clk *c);
int clk_set_rate_locked(struct clk *c, unsigned long rate);
int clk_set_parent_locked(struct clk *c, struct clk *parent);
int tegra_clk_shared_bus_update(struct clk *c);
void tegra2_sdmmc_tap_delay(struct clk *c, int delay);
void tegra3_set_cpu_skipper_delay(int delay);
int tegra_emc_set_rate(unsigned long rate);
long tegra_emc_round_rate(unsigned long rate);
struct clk *tegra_emc_predict_parent(unsigned long rate, u32 *div_value);
void tegra_emc_timing_invalidate(void);
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
static inline bool tegra_clk_is_parent_allowed(struct clk *c, struct clk *p)
{ return true; }
#else
bool tegra_clk_is_parent_allowed(struct clk *c, struct clk *p);
#endif

static inline bool clk_is_auto_dvfs(struct clk *c)
{
	return c->auto_dvfs;
}

static inline bool clk_is_dvfs(struct clk *c)
{
	return (c->dvfs != NULL);
}

static inline bool clk_cansleep(struct clk *c)
{
	return c->cansleep;
}

static inline void clk_lock_save(struct clk *c, unsigned long *flags)
{
	if (clk_cansleep(c)) {
		*flags = 0;
		mutex_lock(&c->mutex);
	} else {
		spin_lock_irqsave(&c->spinlock, *flags);
	}
}

static inline void clk_unlock_restore(struct clk *c, unsigned long *flags)
{
	if (clk_cansleep(c))
		mutex_unlock(&c->mutex);
	else
		spin_unlock_irqrestore(&c->spinlock, *flags);
}

static inline void clk_lock_init(struct clk *c)
{
	mutex_init(&c->mutex);
	spin_lock_init(&c->spinlock);
}

#ifdef CONFIG_CPU_FREQ
struct cpufreq_frequency_table;

struct tegra_cpufreq_table_data {
	struct cpufreq_frequency_table *freq_table;
	int throttle_lowest_index;
	int throttle_highest_index;
	int suspend_index;
};
struct tegra_cpufreq_table_data *tegra_cpufreq_table_get(void);
unsigned long tegra_emc_to_cpu_ratio(unsigned long cpu_rate);
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
static inline int tegra_update_mselect_rate(unsigned long cpu_rate)
{ return 0; }
#else
int tegra_update_mselect_rate(unsigned long cpu_rate);
#endif
#endif

#endif
#endif