/* * include/linux/platform/tegra/clock.h * * Copyright (C) 2010 Google, Inc. * * Author: * Colin Cross * * Copyright (c) 2010-2016, NVIDIA Corporation. All rights reserved. * * 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 #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_PRE_LOCK_DELAY 2 /* Delay 1st lock bit read after pll enabled */ #define USE_PLLE_SWCTL 0 /* Use s/w controls for PLLE */ #define PLL_POST_LOCK_DELAY 10 /* Safety delay after lock is detected */ #define RESET_PROPAGATION_DELAY 5 #ifndef __ASSEMBLY__ #include #include #include #include #include #include #include #include #include #include #define MAX_SAME_LIMIT_SKU_IDS 16 #define STATS_USERS_LIST_SIZE 16 struct clk; #define DIV_BUS (1 << 0) /* system bus clock */ #define DIV_U71 (1 << 1) /* divider is U7.1 (N/2 + 1) */ #define DIV_U71_FIXED (1 << 2) /* divider is U7.1 and fixed unless reprogrammed by SW */ #define DIV_2 (1 << 3) /* clock output is divided by 2 */ #define DIV_U16 (1 << 4) /* divider is (N + 1) */ #define PLL_FIXED (1 << 5) /* PLL runs at fixed rate */ #define PLL_HAS_CPCON (1 << 6) /* PLL has CPCON value in its configuration register */ #define MUX (1 << 7) /* this clock uses a mux to select one of the input sources */ #define PLLD (1 << 8) /* clock is PLLD */ #define PERIPH_NO_RESET (1 << 9) /* doesn't have separate reset bit in the register */ #define PERIPH_NO_ENB (1 << 10) /* does not have clock enable bit in the register */ #define PERIPH_EMC_ENB (1 << 11) /* this peripheral clock is EMC */ #define PERIPH_MANUAL_RESET (1 << 12) /* don't take module out of reset automatically, when enabling clock */ #define PLL_ALT_MISC_REG (1 << 13) /* use alternate offset for PLL misc registers */ #define PLLU (1 << 14) /* PLL is PLLU */ #define PLLX (1 << 15) /* PLL is PLLX */ #define MUX_PWM (1 << 16) /* deprecated for T124 onwards */ #define MUX8 (1 << 17) /* used in simulator setting for T124 onwards */ #define DIV_U151_UART (1 << 18) /* 16-bit uart divider with dual CAR/UART control */ #define MUX_CLK_OUT (1 << 19) /* used to locate extperiph clock registers */ #define PLLM (1 << 20) /* PLL is PLLM */ #define DIV_U71_INT (1 << 21) /* fractional divider is not allowed for this clock */ #define DIV_U71_IDLE (1 << 22) /* clock has a separate idle state divider that is automatically engaged when module is idle */ #define DIV_U151 (1 << 23) /* divider will be U15.1 for this clock */ #define DFLL (1 << 24) /* this clock has closed loop control in h/w */ #define ENABLE_ON_INIT (1 << 28) /* enable during initialization (deprecated) */ #define PERIPH_ON_APB (1 << 29) /* this peripheral is on APB */ #define PERIPH_ON_CBUS (1 << 30) /* this peripheral is on one of the PLLCx bus */ #define BUS_RATE_LIMIT (1 << 31) /* Clock used to apply constraints on shared buses (don't propagate enable/disable to the bus) */ #define SHARED_BUS_RETENTION (1 << 0) #define SHARED_BUS_USE_SKIPPERS (1 << 1) #define PERIPH_DIV (DIV_U71 | DIV_U151 | DIV_U16) #define PERIPH_INIT_SAFE_RATE 12000000 #ifdef CONFIG_COMMON_CLK struct clk_tegra; #define to_clk_tegra(_hw) container_of(_hw, struct clk_tegra, hw) #endif struct clk_mux_sel { struct clk *input; u32 value; }; struct clk_backup { struct clk *input; u32 value; unsigned long bus_rate; }; struct clk_pll_freq_table { unsigned long input_rate; unsigned long output_rate; u16 n; u16 m; u8 p; u8 cpcon; u16 sdm_data; }; struct clk_pll_div_layout { /* base dividers */ u32 ndiv_shift; u32 ndiv_mask; u32 mdiv_shift; u32 mdiv_mask; u32 pdiv_shift; u32 pdiv_mask; u8 *pdiv_to_p; u8 pdiv_max; /* misc dividers */ u32 ndiv_new_shift; u32 ndiv_new_reg_idx; u32 sdm_din_mask; u32 sdm_din_shift; u32 sdm_din_reg_idx; }; struct clk_pll_controls { u32 enable_mask; u32 bypass_mask; u32 reset_mask; u32 reset_reg_idx; u32 iddq_mask; u32 iddq_reg_idx; u32 lock_mask; u32 lock_reg_idx; u32 dramp_en_mask; u32 dramp_done_mask; u32 dramp_ctrl_reg_idx; u32 sdm_en_mask; u32 ssc_en_mask; u32 sdm_ctrl_reg_idx; }; enum pll_reg_indx { PLL_BASE_IDX = 0, PLL_MISC0_IDX, PLL_MISC1_IDX, PLL_MISC2_IDX, PLL_MISC3_IDX, PLL_MISC4_IDX, PLL_MISC5_IDX, }; enum clk_state { UNINITIALIZED = 0, ON, OFF, }; struct tegra_pto_table { char *name; int divider; u32 pto_id; u32 presel_value; u32 presel_reg; u32 presel_mask; }; #ifndef CONFIG_COMMON_CLK 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); void (*reset)(struct clk *, bool); int (*shared_bus_update)(struct clk *); int (*clk_cfg_ex)(struct clk *, enum tegra_clk_ex_param, u32); long (*round_rate_updown)(struct clk *, unsigned long, bool); }; struct bus_stats { cputime64_t *time_table; struct clk *users_list[STATS_USERS_LIST_SIZE]; int users_num; int rates_num; int new_cap_idx; int new_floor_idx; int new_rate_idx; int last_user_idx; int last_rate_idx; u64 last_update; }; struct clk_stats { struct bus_stats *histogram; 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, SHARED_OVERRIDE, SHARED_ISO_BW, SHARED_CEILING_BUT_ISO, }; 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; struct tegra_pto_table *pto_entry; #endif bool set; struct clk_ops *ops; unsigned long dvfs_rate; unsigned long rate; unsigned long boot_rate; unsigned long max_rate; unsigned long min_rate; bool auto_dvfs; bool cansleep; bool set_disabled_div; u32 flags; u32 clk_id; const char *name; u32 refcnt; enum clk_state state; struct clk *parent; u32 div; u32 mul; struct clk *skipper; struct clk_stats stats; const struct clk_mux_sel *inputs; u32 reg; u32 reg_shift; #ifdef CONFIG_LOCKDEP struct lock_class_key lockdep_class; #endif struct list_head shared_bus_list; struct clk_backup shared_bus_backup; struct clk *child_bus; unsigned long override_rate; u32 shared_bus_flags; union { struct { unsigned int clk_num; u32 src_mask; u32 src_shift; struct clk *pll_low; struct clk *pll_high; struct clk *pll_selected; unsigned long threshold; int min_div_low; int min_div_high; } 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; u16 mdiv_default; u8 cpcon_default; const struct clk_pll_freq_table *freq_table; int lock_delay; unsigned long fixed_rate; u32 misc0; u32 misc1; u32 misc2; u32 misc3; u32 misc4; u32 misc5; bool defaults_set; bool vco_out; struct clk_pll_controls *controls; struct clk_pll_div_layout *div_layout; u32 (*round_p_to_pdiv)(u32 p, u32 *pdiv); int (*dyn_ramp)(struct clk *c, struct clk_pll_freq_table *cfg); void (*set_defaults)(struct clk *c, unsigned long input_rate); } pll; struct { void *cl_dvfs; struct clk *consumer; } dfll; struct { unsigned long default_rate; } pll_div; struct { u32 sel; u32 reg_mask; } mux; struct { struct clk *main; struct clk *backup; struct clk *dynamic; unsigned long edp_safe_rate; unsigned long backup_rate; seqcount_t backup_seqcnt; 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 clk *top_user; struct clk *slow_user; } cbus; 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; u32 usage_flag; int stats_idx; } shared_bus_user; struct { struct tegra_clk_export_ops *ops; } export_clk; } u; struct raw_notifier_head *rate_change_nh; wait_queue_head_t *debug_poll_qh; int rate_changed; struct mutex *cross_clk_mutex; struct mutex mutex; spinlock_t spinlock; unsigned long fixed_target_rate; }; #else struct clk_tegra { /* node for master clocks list */ struct list_head node; /* node for list of all clocks */ struct clk_lookup lookup; struct clk_hw hw; bool set; unsigned long fixed_rate; unsigned long max_rate; unsigned long min_rate; u32 flags; const char *name; enum clk_state state; u32 div; u32 mul; u32 reg; u32 reg_shift; struct list_head shared_bus_list; 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 { u32 sel; u32 reg_mask; } mux; struct { struct clk *main; struct clk *backup; } cpu; struct { struct list_head node; bool enabled; unsigned long rate; } shared_bus_user; } u; void (*reset)(struct clk_hw *, bool); int (*clk_cfg_ex)(struct clk_hw *, enum tegra_clk_ex_param, u32); }; #endif /* !CONFIG_COMMON_CLK */ 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; unsigned long platform; struct clk *c; /* clock to be initialized */ struct clk *p; /* clock parent specified in the table */ }; #define TEGRA_CLK_INIT_PLATFORM_ALL 0 #define TEGRA_CLK_INIT_PLATFORM_SI BIT(0) #define TEGRA_CLK_INIT_PLATFORM_QT BIT(1) #define TEGRA_CLK_INIT_PLATFORM_FPGA BIT(2) #define TEGRA_CLK_INIT_PLATFORM_LINSIM BIT(3) #define TEGRA_CLK_INIT_CPU_ASIM BIT(4) #define TEGRA_CLK_INIT_PLATFORM_NON_SI (BIT(1) | BIT(2) | BIT(3)) #ifndef CONFIG_COMMON_CLK void tegra_init_max_rate(struct clk *c, unsigned long max_rate); void tegra_init_min_rate(struct clk *c, unsigned long min_rate); void tegra_clk_preset_emc_monitor(unsigned long rate); void tegra_periph_clk_safe_rate_init(struct clk *c); void tegra_clk_verify_parents(void); void tegra_clk_set_disabled_div_all(void); void clk_init(struct clk *clk); unsigned long tegra_clk_measure_input_freq(void); unsigned long clk_get_rate_locked(struct clk *c); void tegra_clk_init_from_dt(const char *dt_table_name); void tegra_clk_init_cbus_plls_from_table(struct tegra_clk_init_table *table); void clk_set_cansleep(struct clk *c); unsigned long clk_get_min_rate(struct clk *c); unsigned long clk_get_max_rate(struct clk *c); bool tegra_is_clk_initialized(struct clk *c); int clk_set_rate_locked(struct clk *c, unsigned long rate); int clk_rate_change_notify(struct clk *c, unsigned long rate); int clk_set_parent_locked(struct clk *c, struct clk *parent); int clk_reparent(struct clk *c, struct clk *parent); long clk_round_rate_locked(struct clk *c, unsigned long rate); int tegra_clk_shared_bus_update(struct clk *c); int tegra_clk_shared_bus_update_locked(struct clk *c); void tegra3_set_cpu_skipper_delay(int delay); unsigned long tegra_clk_measure_input_freq(void); int clk_enable_locked(struct clk *c); void clk_disable_locked(struct clk *c); bool tegra_clk_is_parent_allowed(struct clk *c, struct clk *p); #endif /* !CONFIG_COMMON_CLK */ struct tegra_sku_rate_limit { const char *clk_name; unsigned long max_rate; int sku_ids[MAX_SAME_LIMIT_SKU_IDS]; }; void tegra2_init_clocks(void); void tegra30_init_clocks(void); void tegra11x_init_clocks(void); void tegra12x_init_clocks(void); void tegra21x_init_clocks(void); void tegra11x_clk_init_la(void); void tegra_common_init_clock(void); struct clk *tegra_get_clock_by_name(const char *name); void tegra_clk_init_from_table(struct tegra_clk_init_table *table); /* Reset driver through Reset framework */ extern int tegra_non_dt_clock_reset_init(void); /** * Returns dfll requested booting frequency, which * is configured by bootloader as cpu clock source. * If booting with different cpu clock source then, * returns 0. */ unsigned long int tegra_dfll_boot_req_khz(void); #ifndef CONFIG_COMMON_CLK void tegra_shared_bus_stats_allocate(struct clk *c, struct bus_stats *stats); int tegra_shared_bus_stats_copy_to_buffer( struct clk *c, struct bus_stats *stats, char *buf, int len); void tegra_shared_bus_stats_update( struct bus_stats *stats, int user_idx, int rate_idx); int clk_config_cpu_edp_safe_rate(struct clk *cpu, struct clk *cluster_clk, unsigned long rate); static inline unsigned long clk_get_cpu_edp_safe_rate(struct clk *cluster_clk) { return cluster_clk->u.cpu.edp_safe_rate; } static inline void tegra_dfll_set_cl_dvfs_data(struct clk *c, void *cld) { if (c->flags & DFLL) c->u.dfll.cl_dvfs = cld; } static inline void *tegra_dfll_get_cl_dvfs_data(struct clk *c) { return c->flags & DFLL ? c->u.dfll.cl_dvfs : ERR_PTR(-ENODATA); } 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 bool clk_can_set_disabled_div(struct clk *c) { return c->set_disabled_div; } static inline void clk_lock_save(struct clk *c, unsigned long *flags) { if (clk_cansleep(c)) { *flags = 0; mutex_lock(&c->mutex); if (c->cross_clk_mutex) mutex_lock(c->cross_clk_mutex); } else { spin_lock_irqsave(&c->spinlock, *flags); } } static inline void clk_unlock_restore(struct clk *c, unsigned long *flags) { if (clk_cansleep(c)) { if (c->cross_clk_mutex) mutex_unlock(c->cross_clk_mutex); mutex_unlock(&c->mutex); } else { spin_unlock_irqrestore(&c->spinlock, *flags); } } static inline int tegra_clk_prepare_enable(struct clk *c) { if (clk_cansleep(c)) return clk_prepare_enable(c); return clk_enable(c); } static inline void tegra_clk_disable_unprepare(struct clk *c) { if (clk_cansleep(c)) clk_disable_unprepare(c); else clk_disable(c); } static inline void clk_lock_init(struct clk *c) { mutex_init(&c->mutex); spin_lock_init(&c->spinlock); } #endif #ifdef CONFIG_DEBUG_FS /* Extended version of the standard macro with poll function setting */ #define DEFINE_SIMPLE_POLL_ATTRIBUTE(__fops, __get, __set, __poll, __fmt) \ static int __fops ## _open(struct inode *inode, struct file *file) \ { \ __simple_attr_check_format(__fmt, 0ull); \ return simple_attr_open(inode, file, __get, __set, __fmt); \ } \ static const struct file_operations __fops = { \ .owner = THIS_MODULE, \ .open = __fops ## _open, \ .release = simple_attr_release, \ .read = simple_attr_read, \ .write = simple_attr_write, \ .llseek = generic_file_llseek, \ .poll = __poll, \ }; void tegra_clk_add_pto_entries(struct tegra_pto_table *pto_table); #endif #endif #endif