diff options
| author | Taniya Das <tdas@codeaurora.org> | 2016-01-07 18:14:25 +0530 |
|---|---|---|
| committer | Rohit Vaswani <rvaswani@codeaurora.org> | 2016-03-01 13:00:24 -0800 |
| commit | 1ec7358a6161bdfe0482e4bd0d2b4448eea54449 (patch) | |
| tree | 13fabf9d4d7b06870ef3f0ac0031d04733b5967e /include/soc | |
| parent | edf938dde9457d3c45a70ed3228c4c4ff61f1e11 (diff) | |
clk: msm: Add support for MSM clocks
Support added for MSM clock and modifications in the clk framework to use
the MSM clock framework.
Change-Id: Ibbcf0ffbf9d30dde2dcb0e943225ad95dd4e857d
Signed-off-by: Taniya Das <tdas@codeaurora.org>
Diffstat (limited to 'include/soc')
| -rw-r--r-- | include/soc/qcom/clock-alpha-pll.h | 94 | ||||
| -rw-r--r-- | include/soc/qcom/clock-local2.h | 256 | ||||
| -rw-r--r-- | include/soc/qcom/clock-pll.h | 231 | ||||
| -rw-r--r-- | include/soc/qcom/clock-rpm.h | 180 | ||||
| -rw-r--r-- | include/soc/qcom/clock-voter.h | 51 | ||||
| -rw-r--r-- | include/soc/qcom/msm-clock-controller.h | 144 |
6 files changed, 956 insertions, 0 deletions
diff --git a/include/soc/qcom/clock-alpha-pll.h b/include/soc/qcom/clock-alpha-pll.h new file mode 100644 index 000000000000..b5a34b4cecb5 --- /dev/null +++ b/include/soc/qcom/clock-alpha-pll.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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 __ARCH_ARM_MACH_MSM_CLOCK_ALPHA_PLL_H +#define __ARCH_ARM_MACH_MSM_CLOCK_ALPHA_PLL_H + +#include <linux/spinlock.h> +#include <linux/clk/msm-clk-provider.h> + +struct alpha_pll_masks { + u32 lock_mask; /* lock_det bit */ + u32 active_mask; /* active_flag in FSM mode */ + u32 update_mask; /* update bit for dynamic update */ + u32 vco_mask; /* vco_sel bits */ + u32 vco_shift; + u32 alpha_en_mask; /* alpha_en bit */ + u32 output_mask; /* pllout_* bits */ + u32 post_div_mask; + + u32 test_ctl_lo_mask; + u32 test_ctl_hi_mask; +}; + +struct alpha_pll_vco_tbl { + u32 vco_val; + unsigned long min_freq; + unsigned long max_freq; +}; + +#define VCO(a, b, c) { \ + .vco_val = a,\ + .min_freq = b,\ + .max_freq = c,\ +} + +struct alpha_pll_clk { + struct alpha_pll_masks *masks; + void *const __iomem *base; + u32 offset; + + /* if fsm_en_mask is set, config PLL to FSM mode */ + u32 fsm_reg_offset; + u32 fsm_en_mask; + + u32 enable_config; /* bitmask of outputs to be enabled */ + u32 post_div_config; /* masked post divider setting */ + u32 config_ctl_val; /* config register init value */ + u32 test_ctl_lo_val; /* test control settings */ + u32 test_ctl_hi_val; + + struct alpha_pll_vco_tbl *vco_tbl; + u32 num_vco; + u32 current_vco_val; + bool inited; + bool slew; + bool no_prepared_reconfig; + + /* + * Some chipsets need the offline request bit to be + * cleared on a second write to the register, even though + * SW wants the bit to be set. Set this flag to indicate + * that the workaround is required. + */ + bool offline_bit_workaround; + bool is_fabia; + unsigned long min_supported_freq; + struct clk c; +}; + +static inline struct alpha_pll_clk *to_alpha_pll_clk(struct clk *c) +{ + return container_of(c, struct alpha_pll_clk, c); +} + + +#endif +extern void __init_alpha_pll(struct clk *c); +extern struct clk_ops clk_ops_alpha_pll; +extern struct clk_ops clk_ops_alpha_pll_hwfsm; +extern struct clk_ops clk_ops_fixed_alpha_pll; +extern struct clk_ops clk_ops_dyna_alpha_pll; +extern struct clk_ops clk_ops_fixed_fabia_alpha_pll; +extern struct clk_ops clk_ops_fabia_alpha_pll; diff --git a/include/soc/qcom/clock-local2.h b/include/soc/qcom/clock-local2.h new file mode 100644 index 000000000000..42c991194391 --- /dev/null +++ b/include/soc/qcom/clock-local2.h @@ -0,0 +1,256 @@ +/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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 __ARCH_ARM_MACH_MSM_CLOCK_LOCAL_2_H +#define __ARCH_ARM_MACH_MSM_CLOCK_LOCAL_2_H + +#include <linux/spinlock.h> +#include <linux/clk/msm-clk-provider.h> +#include <linux/clk/msm-clk.h> + +/* + * Generic frequency-definition structs and macros + */ + +/** + * @freq_hz: output rate + * @src_freq: source freq for dynamic pll. For fixed plls, set to 0. + * @src_clk: source clock for freq_hz + * @m_val: M value corresponding to freq_hz + * @n_val: N value corresponding to freq_hz + * @d_val: D value corresponding to freq_hz + * @div_src_val: Pre divider value and source selection mux index for freq_hz + * @sys_vdd: Voltage level required for freq_hz + */ +struct clk_freq_tbl { + unsigned long freq_hz; + unsigned long src_freq; + struct clk *src_clk; + u32 m_val; + u32 n_val; + u32 d_val; + u32 div_src_val; + const unsigned sys_vdd; +}; + +#define FREQ_END (ULONG_MAX-1) +#define F_END { .freq_hz = FREQ_END } +#define FIXED_CLK_SRC 0 +/* + * Generic clock-definition struct and macros + */ +/** + * struct rcg_clk - root clock generator + * @cmd_rcgr_reg: command register + * @set_rate: function to set frequency + * @freq_tbl: frequency table for this RCG + * @current_freq: current RCG frequency + * @c: generic clock data + * @non_local_children: set if RCG has at least one branch owned by a diff EE + * @force_enable_rcgr: set if RCG needs to be force enabled/disabled during + * power sequence + * @base: pointer to base address of ioremapped registers. + */ +struct rcg_clk { + u32 cmd_rcgr_reg; + + void (*set_rate)(struct rcg_clk *, struct clk_freq_tbl *); + + struct clk_freq_tbl *freq_tbl; + struct clk_freq_tbl *current_freq; + struct clk c; + + bool non_local_children; + bool force_enable_rcgr; + void *const __iomem *base; +}; + +static inline struct rcg_clk *to_rcg_clk(struct clk *clk) +{ + return container_of(clk, struct rcg_clk, c); +} + +extern struct clk_freq_tbl rcg_dummy_freq; + +/** + * struct branch_clk - branch clock + * @set_rate: Set the frequency of this branch clock. + * @c: clk + * @cbcr_reg: branch control register + * @bcr_reg: block reset register + * @has_sibling: true if other branches are derived from this branch's source + * @cur_div: current branch divider value + * @max_div: maximum branch divider value (if zero, no divider exists) + * @halt_check: halt checking type + * @toggle_memory: toggle memory during enable/disable if true + * @no_halt_check_on_disable: When set, do not check status bit during + * clk_disable(). + * @check_enable_bit: Check the enable bit to determine clock status + during handoff. + * @base: pointer to base address of ioremapped registers. + */ +struct branch_clk { + void (*set_rate)(struct branch_clk *, struct clk_freq_tbl *); + struct clk c; + u32 cbcr_reg; + u32 bcr_reg; + int has_sibling; + u32 cur_div; + u32 max_div; + const u32 halt_check; + bool toggle_memory; + bool no_halt_check_on_disable; + bool check_enable_bit; + void *const __iomem *base; +}; + +static inline struct branch_clk *to_branch_clk(struct clk *clk) +{ + return container_of(clk, struct branch_clk, c); +} + +/** + * struct local_vote_clk - Voteable branch clock + * @c: clk + * @cbcr_reg: branch control register + * @vote_reg: voting register + * @en_mask: enable mask + * @halt_check: halt checking type + * @base: pointer to base address of ioremapped registers. + * An on/off switch with a rate derived from the parent. + */ +struct local_vote_clk { + struct clk c; + u32 cbcr_reg; + u32 vote_reg; + u32 bcr_reg; + u32 en_mask; + const u32 halt_check; + void * __iomem *base; +}; + +static inline struct local_vote_clk *to_local_vote_clk(struct clk *clk) +{ + return container_of(clk, struct local_vote_clk, c); +} + +/** + * struct reset_clk - Reset clock + * @c: clk + * @reset_reg: block reset register + * @base: pointer to base address of ioremapped registers. + */ +struct reset_clk { + struct clk c; + u32 reset_reg; + void *__iomem *base; +}; + +static inline struct reset_clk *to_reset_clk(struct clk *clk) +{ + return container_of(clk, struct reset_clk, c); +} +/** + * struct measure_clk - for rate measurement debug use + * @sample_ticks: sample period in reference clock ticks + * @multiplier: measurement scale-up factor + * @divider: measurement scale-down factor + * @c: clk +*/ +struct measure_clk { + u64 sample_ticks; + u32 multiplier; + u32 divider; + + struct clk c; +}; + +struct measure_clk_data { + struct clk *cxo; + u32 plltest_reg; + u32 plltest_val; + u32 xo_div4_cbcr; + u32 ctl_reg; + u32 status_reg; + void *const __iomem *base; +}; + +static inline struct measure_clk *to_measure_clk(struct clk *clk) +{ + return container_of(clk, struct measure_clk, c); +} + +/** + * struct gate_clk + * @c: clk + * @en_mask: ORed with @en_reg to enable gate clk + * @en_reg: register used to enable/disable gate clk + * @base: pointer to base address of ioremapped registers + */ +struct gate_clk { + struct clk c; + u32 en_mask; + u32 en_reg; + unsigned int delay_us; + void *const __iomem *base; +}; + +static inline struct gate_clk *to_gate_clk(struct clk *clk) +{ + return container_of(clk, struct gate_clk, c); +} + +/* + * Generic set-rate implementations + */ +void set_rate_mnd(struct rcg_clk *clk, struct clk_freq_tbl *nf); +void set_rate_hid(struct rcg_clk *clk, struct clk_freq_tbl *nf); + +/* + * Variables from the clock-local driver + */ +extern spinlock_t local_clock_reg_lock; + +extern struct clk_ops clk_ops_empty; +extern struct clk_ops clk_ops_rcg; +extern struct clk_ops clk_ops_rcg_mnd; +extern struct clk_ops clk_ops_branch; +extern struct clk_ops clk_ops_vote; +extern struct clk_ops clk_ops_rcg_hdmi; +extern struct clk_ops clk_ops_rcg_edp; +extern struct clk_ops clk_ops_byte; +extern struct clk_ops clk_ops_pixel; +extern struct clk_ops clk_ops_byte_multiparent; +extern struct clk_ops clk_ops_pixel_multiparent; +extern struct clk_ops clk_ops_edppixel; +extern struct clk_ops clk_ops_gate; +extern struct clk_ops clk_ops_rst; +extern struct clk_mux_ops mux_reg_ops; +extern struct mux_div_ops rcg_mux_div_ops; +extern struct clk_div_ops postdiv_reg_ops; + +enum handoff pixel_rcg_handoff(struct clk *clk); +enum handoff byte_rcg_handoff(struct clk *clk); +unsigned long measure_get_rate(struct clk *c); + +/* + * Clock definition macros + */ +#define DEFINE_CLK_MEASURE(name) \ + struct clk name = { \ + .ops = &clk_ops_empty, \ + .dbg_name = #name, \ + CLK_INIT(name), \ + }; \ + +#endif /* __ARCH_ARM_MACH_MSM_CLOCK_LOCAL_2_H */ diff --git a/include/soc/qcom/clock-pll.h b/include/soc/qcom/clock-pll.h new file mode 100644 index 000000000000..c17376966a09 --- /dev/null +++ b/include/soc/qcom/clock-pll.h @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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 __ARCH_ARM_MACH_MSM_CLOCK_PLL_H +#define __ARCH_ARM_MACH_MSM_CLOCK_PLL_H + +#include <linux/clk/msm-clk-provider.h> + +/** + * struct pll_freq_tbl - generic PLL frequency definition + * @freq_hz: pll frequency in hz + * @l_val: pll l value + * @m_val: pll m value + * @n_val: pll n value + * @post_div_val: pll post divider value + * @pre_div_val: pll pre-divider value + * @vco_val: pll vco value + */ +struct pll_freq_tbl { + const u32 freq_hz; + const u32 l_val; + const u32 m_val; + const u32 n_val; + const u32 post_div_val; + const u32 pre_div_val; + const u32 vco_val; +}; + +/** + * struct pll_config_masks - PLL config masks struct + * @post_div_mask: mask for post divider bits location + * @pre_div_mask: mask for pre-divider bits location + * @vco_mask: mask for vco bits location + * @mn_en_mask: ORed with pll config register to enable the mn counter + * @main_output_mask: ORed with pll config register to enable the main output + * @apc_pdn_mask: ORed with pll config register to enable/disable APC PDN + * @lock_mask: Mask that indicates that the PLL has locked + */ +struct pll_config_masks { + u32 apc_pdn_mask; + u32 post_div_mask; + u32 pre_div_mask; + u32 vco_mask; + u32 mn_en_mask; + u32 main_output_mask; + u32 early_output_mask; + u32 lock_mask; +}; + +struct pll_config_vals { + u32 post_div_masked; + u32 pre_div_masked; + u32 config_ctl_val; + u32 config_ctl_hi_val; + u32 test_ctl_lo_val; + u32 test_ctl_hi_val; + u32 alpha_val; + bool enable_mn; +}; + +struct pll_spm_ctrl { + u32 offset; + u32 event_bit; + void __iomem *spm_base; +}; + +#define PLL_FREQ_END (UINT_MAX-1) +#define PLL_F_END { .freq_hz = PLL_FREQ_END } + +/** + * struct pll_vote_clk - phase locked loop (HW voteable) + * @soft_vote: soft voting variable for multiple PLL software instances + * @soft_vote_mask: soft voting mask for multiple PLL software instances + * @en_reg: enable register + * @en_mask: ORed with @en_reg to enable the clock + * @status_mask: ANDed with @status_reg to determine if PLL is active. + * @status_reg: status register + * @c: clock + */ +struct pll_vote_clk { + u32 *soft_vote; + u32 soft_vote_mask; + void __iomem *const en_reg; + u32 en_mask; + void __iomem *const status_reg; + u32 status_mask; + + struct clk c; + void *const __iomem *base; +}; + +extern struct clk_ops clk_ops_pll_vote; +extern struct clk_ops clk_ops_pll_acpu_vote; +extern struct clk_ops clk_ops_pll_sleep_vote; + +/* Soft voting values */ +#define PLL_SOFT_VOTE_PRIMARY BIT(0) +#define PLL_SOFT_VOTE_ACPU BIT(1) +#define PLL_SOFT_VOTE_AUX BIT(2) + +static inline struct pll_vote_clk *to_pll_vote_clk(struct clk *c) +{ + return container_of(c, struct pll_vote_clk, c); +} + +/** + * struct pll_clk - phase locked loop + * @mode_reg: enable register + * @l_reg: l value register + * @m_reg: m value register + * @n_reg: n value register + * @config_reg: configuration register, contains mn divider enable, pre divider, + * post divider and vco configuration. register name can be configure register + * or user_ctl register depending on targets + * @config_ctl_reg: "expert" configuration register + * @config_ctl_hi_reg: upper 32 bits of the "expert" configuration register + * @status_reg: status register, contains the lock detection bit + * @init_test_ctl: initialize the test control register + * @pgm_test_ctl_enable: program the test_ctl register in the enable sequence + * @test_ctl_dbg: if false will configure the test control registers. + * @masks: masks used for settings in config_reg + * @vals: configuration values to be written to PLL registers + * @freq_tbl: pll freq table + * @no_prepared_reconfig: Fail round_rate if pll is prepared + * @c: clk + * @base: pointer to base address of ioremapped registers. + */ +struct pll_clk { + void __iomem *const mode_reg; + void __iomem *const l_reg; + void __iomem *const m_reg; + void __iomem *const n_reg; + void __iomem *const alpha_reg; + void __iomem *const config_reg; + void __iomem *const config_ctl_reg; + void __iomem *const config_ctl_hi_reg; + void __iomem *const status_reg; + void __iomem *const alt_status_reg; + void __iomem *const test_ctl_lo_reg; + void __iomem *const test_ctl_hi_reg; + + bool init_test_ctl; + bool pgm_test_ctl_enable; + bool test_ctl_dbg; + + struct pll_config_masks masks; + struct pll_config_vals vals; + struct pll_freq_tbl *freq_tbl; + + unsigned long src_rate; + unsigned long min_rate; + unsigned long max_rate; + + bool inited; + bool no_prepared_reconfig; + + struct pll_spm_ctrl spm_ctrl; + struct clk c; + void *const __iomem *base; +}; + +extern struct clk_ops clk_ops_local_pll; +extern struct clk_ops clk_ops_sr2_pll; +extern struct clk_ops clk_ops_variable_rate_pll; +extern struct clk_ops clk_ops_variable_rate_pll_hwfsm; + +void __variable_rate_pll_init(struct clk *c); + +static inline struct pll_clk *to_pll_clk(struct clk *c) +{ + return container_of(c, struct pll_clk, c); +} + +int sr_pll_clk_enable(struct clk *c); +int sr_hpm_lp_pll_clk_enable(struct clk *c); + +struct pll_alt_config { + u32 val; + u32 mask; +}; + +struct pll_config { + u32 l; + u32 m; + u32 n; + u32 vco_val; + u32 vco_mask; + u32 pre_div_val; + u32 pre_div_mask; + u32 post_div_val; + u32 post_div_mask; + u32 mn_ena_val; + u32 mn_ena_mask; + u32 main_output_val; + u32 main_output_mask; + u32 aux_output_val; + u32 aux_output_mask; + u32 cfg_ctl_val; + /* SR2 PLL specific fields */ + u32 add_factor_val; + u32 add_factor_mask; + struct pll_alt_config alt_cfg; +}; + +struct pll_config_regs { + void __iomem *l_reg; + void __iomem *m_reg; + void __iomem *n_reg; + void __iomem *config_reg; + void __iomem *config_alt_reg; + void __iomem *config_ctl_reg; + void __iomem *mode_reg; + void *const __iomem *base; +}; + +void configure_sr_pll(struct pll_config *config, struct pll_config_regs *regs, + u32 ena_fsm_mode); +void configure_sr_hpm_lp_pll(struct pll_config *config, + struct pll_config_regs *, u32 ena_fsm_mode); +#endif diff --git a/include/soc/qcom/clock-rpm.h b/include/soc/qcom/clock-rpm.h new file mode 100644 index 000000000000..18fedd4c97f7 --- /dev/null +++ b/include/soc/qcom/clock-rpm.h @@ -0,0 +1,180 @@ +/* Copyright (c) 2010-2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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 __ARCH_ARM_MACH_MSM_CLOCK_RPM_H +#define __ARCH_ARM_MACH_MSM_CLOCK_RPM_H + +#include <linux/clk/msm-clk-provider.h> +#include <soc/qcom/rpm-smd.h> + +#define RPM_SMD_KEY_RATE 0x007A484B +#define RPM_SMD_KEY_ENABLE 0x62616E45 +#define RPM_SMD_KEY_STATE 0x54415453 + +#define RPM_CLK_BUFFER_A_REQ 0x616B6C63 +#define RPM_KEY_SOFTWARE_ENABLE 0x6E657773 +#define RPM_KEY_PIN_CTRL_CLK_BUFFER_ENABLE_KEY 0x62636370 + +struct clk_ops; +struct clk_rpmrs_data; +extern struct clk_ops clk_ops_rpm; +extern struct clk_ops clk_ops_rpm_branch; + +struct rpm_clk { + int rpm_res_type; + int rpm_key; + int rpm_clk_id; + const int rpm_status_id; + bool active_only; + bool enabled; + bool branch; /* true: RPM only accepts 1 for ON and 0 for OFF */ + struct clk_rpmrs_data *rpmrs_data; + struct rpm_clk *peer; + struct clk c; + uint32_t *last_active_set_vote; + uint32_t *last_sleep_set_vote; +}; + +static inline struct rpm_clk *to_rpm_clk(struct clk *clk) +{ + return container_of(clk, struct rpm_clk, c); +} + +/* + * RPM scaling enable function used for target that has an RPM resource for + * rpm clock scaling enable. + */ +int enable_rpm_scaling(void); + +int vote_bimc(struct rpm_clk *r, uint32_t value); + +extern struct clk_rpmrs_data clk_rpmrs_data_smd; + +/* + * A note on name##last_{active,sleep}_set_vote below: + * We track the last active and sleep set votes across both + * active-only and active+sleep set clocks. We use the same + * tracking variables for both clocks in order to keep both + * updated about the last vote irrespective of which clock + * actually made the request. This is the only way to allow + * optimizations that prevent duplicate requests from being sent + * to the RPM. Separate tracking does not work since it is not + * possible to know if the peer's last request was actually sent + * to the RPM. + */ + +#define __DEFINE_CLK_RPM(name, active, type, r_id, stat_id, dep, key, \ + rpmrsdata) \ + static struct rpm_clk active; \ + static uint32_t name##last_active_set_vote; \ + static uint32_t name##last_sleep_set_vote; \ + static struct rpm_clk name = { \ + .rpm_res_type = (type), \ + .rpm_clk_id = (r_id), \ + .rpm_status_id = (stat_id), \ + .rpm_key = (key), \ + .peer = &active, \ + .rpmrs_data = (rpmrsdata),\ + .last_active_set_vote = &name##last_active_set_vote, \ + .last_sleep_set_vote = &name##last_sleep_set_vote, \ + .c = { \ + .ops = &clk_ops_rpm, \ + .dbg_name = #name, \ + CLK_INIT(name.c), \ + .depends = dep, \ + }, \ + }; \ + static struct rpm_clk active = { \ + .rpm_res_type = (type), \ + .rpm_clk_id = (r_id), \ + .rpm_status_id = (stat_id), \ + .rpm_key = (key), \ + .peer = &name, \ + .active_only = true, \ + .rpmrs_data = (rpmrsdata),\ + .last_active_set_vote = &name##last_active_set_vote, \ + .last_sleep_set_vote = &name##last_sleep_set_vote, \ + .c = { \ + .ops = &clk_ops_rpm, \ + .dbg_name = #active, \ + CLK_INIT(active.c), \ + .depends = dep, \ + }, \ + }; + +#define __DEFINE_CLK_RPM_BRANCH(name, active, type, r_id, stat_id, r, \ + key, rpmrsdata) \ + static struct rpm_clk active; \ + static uint32_t name##last_active_set_vote; \ + static uint32_t name##last_sleep_set_vote; \ + static struct rpm_clk name = { \ + .rpm_res_type = (type), \ + .rpm_clk_id = (r_id), \ + .rpm_status_id = (stat_id), \ + .rpm_key = (key), \ + .peer = &active, \ + .branch = true, \ + .rpmrs_data = (rpmrsdata),\ + .last_active_set_vote = &name##last_active_set_vote, \ + .last_sleep_set_vote = &name##last_sleep_set_vote, \ + .c = { \ + .ops = &clk_ops_rpm_branch, \ + .dbg_name = #name, \ + .rate = (r), \ + CLK_INIT(name.c), \ + }, \ + }; \ + static struct rpm_clk active = { \ + .rpm_res_type = (type), \ + .rpm_clk_id = (r_id), \ + .rpm_status_id = (stat_id), \ + .rpm_key = (key), \ + .peer = &name, \ + .active_only = true, \ + .branch = true, \ + .rpmrs_data = (rpmrsdata),\ + .last_active_set_vote = &name##last_active_set_vote, \ + .last_sleep_set_vote = &name##last_sleep_set_vote, \ + .c = { \ + .ops = &clk_ops_rpm_branch, \ + .dbg_name = #active, \ + .rate = (r), \ + CLK_INIT(active.c), \ + }, \ + }; + +#define DEFINE_CLK_RPM_SMD(name, active, type, r_id, dep) \ + __DEFINE_CLK_RPM(name, active, type, r_id, 0, dep, \ + RPM_SMD_KEY_RATE, &clk_rpmrs_data_smd) + +#define DEFINE_CLK_RPM_SMD_BRANCH(name, active, type, r_id, r) \ + __DEFINE_CLK_RPM_BRANCH(name, active, type, r_id, 0, r, \ + RPM_SMD_KEY_ENABLE, &clk_rpmrs_data_smd) + +#define DEFINE_CLK_RPM_SMD_QDSS(name, active, type, r_id) \ + __DEFINE_CLK_RPM(name, active, type, r_id, \ + 0, 0, RPM_SMD_KEY_STATE, &clk_rpmrs_data_smd) +/* + * The RPM XO buffer clock management code aggregates votes for pin-control mode + * and software mode separately. Software-enable has higher priority over pin- + * control, and if the software-mode aggregation results in a 'disable', the + * buffer will be left in pin-control mode if a pin-control vote is in place. + */ +#define DEFINE_CLK_RPM_SMD_XO_BUFFER(name, active, r_id) \ + __DEFINE_CLK_RPM_BRANCH(name, active, RPM_CLK_BUFFER_A_REQ, r_id, 0, \ + 1000, RPM_KEY_SOFTWARE_ENABLE, &clk_rpmrs_data_smd) + +#define DEFINE_CLK_RPM_SMD_XO_BUFFER_PINCTRL(name, active, r_id) \ + __DEFINE_CLK_RPM_BRANCH(name, active, RPM_CLK_BUFFER_A_REQ, r_id, 0, \ + 1000, RPM_KEY_PIN_CTRL_CLK_BUFFER_ENABLE_KEY, &clk_rpmrs_data_smd) +#endif diff --git a/include/soc/qcom/clock-voter.h b/include/soc/qcom/clock-voter.h new file mode 100644 index 000000000000..9eb3898db1e8 --- /dev/null +++ b/include/soc/qcom/clock-voter.h @@ -0,0 +1,51 @@ +/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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 __ARCH_ARM_MACH_MSM_CLOCK_VOTER_H +#define __ARCH_ARM_MACH_MSM_CLOCK_VOTER_H + +#include <linux/clk/msm-clk-provider.h> + +struct clk_ops; +extern struct clk_ops clk_ops_voter; + +struct clk_voter { + int is_branch; + bool enabled; + struct clk c; +}; + +static inline struct clk_voter *to_clk_voter(struct clk *clk) +{ + return container_of(clk, struct clk_voter, c); +} + +#define __DEFINE_CLK_VOTER(clk_name, _parent, _default_rate, _is_branch) \ + struct clk_voter clk_name = { \ + .is_branch = (_is_branch), \ + .c = { \ + .parent = _parent, \ + .dbg_name = #clk_name, \ + .ops = &clk_ops_voter, \ + .rate = _default_rate, \ + CLK_INIT(clk_name.c), \ + }, \ + } + +#define DEFINE_CLK_VOTER(clk_name, _parent, _default_rate) \ + __DEFINE_CLK_VOTER(clk_name, _parent, _default_rate, 0) + +#define DEFINE_CLK_BRANCH_VOTER(clk_name, _parent) \ + __DEFINE_CLK_VOTER(clk_name, _parent, 1000, 1) + +#endif diff --git a/include/soc/qcom/msm-clock-controller.h b/include/soc/qcom/msm-clock-controller.h new file mode 100644 index 000000000000..d6bd4e03af0d --- /dev/null +++ b/include/soc/qcom/msm-clock-controller.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * 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 __ARCH_ARM_MSM_CLOCK_CONTROLLER_H +#define __ARCH_ARM_MSM_CLOCK_CONTROLLER_H + +#include <linux/list.h> +#include <linux/clkdev.h> +#include <linux/of.h> +#include <linux/platform_device.h> + +#define dt_err(np, fmt, ...) \ + pr_err("%s: " fmt, np->name, ##__VA_ARGS__) +#define dt_prop_err(np, str, fmt, ...) \ + dt_err(np, "%s: " fmt, str, ##__VA_ARGS__) + +/** + * struct msmclk_parser + * @compatible + * matches compatible property from devicetree + * @parsedt + * constructs & returns an instance of the appropriate obj based on + * the data from devicetree. + */ +struct msmclk_parser { + struct list_head list; + char *compatible; + void * (*parsedt)(struct device *dev, struct device_node *of); +}; + +#define MSMCLK_PARSER(fn, str, id) \ +static struct msmclk_parser _msmclk_##fn##id = { \ + .list = LIST_HEAD_INIT(_msmclk_##fn##id.list), \ + .compatible = str, \ + .parsedt = fn, \ +}; \ +static int __init _msmclk_init_##fn##id(void) \ +{ \ + msmclk_parser_register(&_msmclk_##fn##id); \ + return 0; \ +} \ +early_initcall(_msmclk_init_##fn##id) + +/* + * struct msmclk_data + * @base + * ioremapped region for sub_devices + * @list + * tracks all registered driver instances + * @htable + * tracks all registered child clocks + * @clk_tbl + * array of clk_lookup to be registered with the clock framework + */ +#define HASHTABLE_SIZE 200 +struct msmclk_data { + void __iomem *base; + struct device *dev; + struct list_head list; + struct hlist_head htable[HASHTABLE_SIZE]; + struct clk_lookup *clk_tbl; + int clk_tbl_size; + int max_clk_tbl_size; +}; + +#if defined(CONFIG_MSM_CLK_CONTROLLER_V2) + +/* Utility functions */ +int of_property_count_phandles(struct device_node *np, char *propname); +int of_property_read_phandle_index(struct device_node *np, char *propname, + int index, phandle *p); +void *msmclk_generic_clk_init(struct device *dev, struct device_node *np, + struct clk *c); + +/* + * msmclk_parser_register + * Registers a parser which will be matched with a node from dt + * according to the compatible string. + */ +void msmclk_parser_register(struct msmclk_parser *); + +/* + * msmclk_parse_phandle + * On hashtable miss, the corresponding entry will be retrieved from + * devicetree, and added to the hashtable. + */ +void *msmclk_parse_phandle(struct device *dev, phandle key); +/* + * msmclk_lookup_phandle + * Straightforward hashtable lookup + */ +void *msmclk_lookup_phandle(struct device *dev, phandle key); + +int __init msmclk_init(void); +#else + +static inline int of_property_count_phandles(struct device_node *np, + char *propname) +{ + return 0; +} + +static inline int of_property_read_phandle_index(struct device_node *np, + char *propname, int index, phandle *p) +{ + return 0; +} + +static inline void *msmclk_generic_clk_init(struct device *dev, + struct device_node *np, struct clk *c) +{ + return ERR_PTR(-EINVAL); +} + +static inline void msmclk_parser_register(struct msmclk_parser *p) {}; + +static inline void *msmclk_parse_phandle(struct device *dev, phandle key) +{ + return ERR_PTR(-EINVAL); +} + +static inline void *msmclk_lookup_phandle(struct device *dev, phandle key) +{ + return ERR_PTR(-EINVAL); +} + +static inline int __init msmclk_init(void) +{ + return 0; +} + +#endif /* CONFIG_MSM_CLK_CONTROLLER_V2 */ +#endif /* __ARCH_ARM_MSM_CLOCK_CONTROLLER_H */ |
