diff options
Diffstat (limited to 'drivers/clk/qcom')
-rw-r--r-- | drivers/clk/qcom/Kconfig | 9 | ||||
-rw-r--r-- | drivers/clk/qcom/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/qcom/clk-rcg.c | 230 | ||||
-rw-r--r-- | drivers/clk/qcom/clk-rcg.h | 8 | ||||
-rw-r--r-- | drivers/clk/qcom/clk-rcg2.c | 170 | ||||
-rw-r--r-- | drivers/clk/qcom/common.c | 42 | ||||
-rw-r--r-- | drivers/clk/qcom/common.h | 4 | ||||
-rw-r--r-- | drivers/clk/qcom/gcc-apq8084.c | 49 | ||||
-rw-r--r-- | drivers/clk/qcom/gcc-ipq806x.c | 7 | ||||
-rw-r--r-- | drivers/clk/qcom/gcc-msm8660.c | 7 | ||||
-rw-r--r-- | drivers/clk/qcom/gcc-msm8916.c | 569 | ||||
-rw-r--r-- | drivers/clk/qcom/gcc-msm8960.c | 20 | ||||
-rw-r--r-- | drivers/clk/qcom/gcc-msm8974.c | 22 | ||||
-rw-r--r-- | drivers/clk/qcom/gdsc.c | 237 | ||||
-rw-r--r-- | drivers/clk/qcom/gdsc.h | 68 | ||||
-rw-r--r-- | drivers/clk/qcom/lcc-ipq806x.c | 7 | ||||
-rw-r--r-- | drivers/clk/qcom/lcc-msm8960.c | 7 | ||||
-rw-r--r-- | drivers/clk/qcom/mmcc-apq8084.c | 111 | ||||
-rw-r--r-- | drivers/clk/qcom/mmcc-msm8960.c | 411 | ||||
-rw-r--r-- | drivers/clk/qcom/mmcc-msm8974.c | 92 |
20 files changed, 1944 insertions, 127 deletions
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 59d16668b..ee4c83aab 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -1,3 +1,7 @@ +config QCOM_GDSC + bool + select PM_GENERIC_DOMAINS if PM + config COMMON_CLK_QCOM tristate "Support for Qualcomm's clock controllers" depends on OF @@ -7,6 +11,7 @@ config COMMON_CLK_QCOM config APQ_GCC_8084 tristate "APQ8084 Global Clock Controller" + select QCOM_GDSC depends on COMMON_CLK_QCOM help Support for the global clock controller on apq8084 devices. @@ -16,6 +21,7 @@ config APQ_GCC_8084 config APQ_MMCC_8084 tristate "APQ8084 Multimedia Clock Controller" select APQ_GCC_8084 + select QCOM_GDSC depends on COMMON_CLK_QCOM help Support for the multimedia clock controller on apq8084 devices. @@ -49,6 +55,7 @@ config MSM_GCC_8660 config MSM_GCC_8916 tristate "MSM8916 Global Clock Controller" + select QCOM_GDSC depends on COMMON_CLK_QCOM help Support for the global clock controller on msm8916 devices. @@ -83,6 +90,7 @@ config MSM_MMCC_8960 config MSM_GCC_8974 tristate "MSM8974 Global Clock Controller" + select QCOM_GDSC depends on COMMON_CLK_QCOM help Support for the global clock controller on msm8974 devices. @@ -92,6 +100,7 @@ config MSM_GCC_8974 config MSM_MMCC_8974 tristate "MSM8974 Multimedia Clock Controller" select MSM_GCC_8974 + select QCOM_GDSC depends on COMMON_CLK_QCOM help Support for the multimedia clock controller on msm8974 devices. diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 50b337a24..fe6252349 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -9,6 +9,7 @@ clk-qcom-y += clk-branch.o clk-qcom-y += clk-regmap-divider.o clk-qcom-y += clk-regmap-mux.o clk-qcom-y += reset.o +clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o obj-$(CONFIG_APQ_MMCC_8084) += mmcc-apq8084.o diff --git a/drivers/clk/qcom/clk-rcg.c b/drivers/clk/qcom/clk-rcg.c index bccedc4b5..bfbb28f45 100644 --- a/drivers/clk/qcom/clk-rcg.c +++ b/drivers/clk/qcom/clk-rcg.c @@ -542,6 +542,200 @@ static int clk_rcg_bypass_set_rate(struct clk_hw *hw, unsigned long rate, return __clk_rcg_set_rate(rcg, rcg->freq_tbl); } +static int clk_rcg_bypass2_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_hw *p; + + p = req->best_parent_hw; + req->best_parent_rate = clk_hw_round_rate(p, req->rate); + req->rate = req->best_parent_rate; + + return 0; +} + +static int clk_rcg_bypass2_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_rcg *rcg = to_clk_rcg(hw); + struct freq_tbl f = { 0 }; + u32 ns, src; + int i, ret, num_parents = clk_hw_get_num_parents(hw); + + ret = regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns); + if (ret) + return ret; + + src = ns_to_src(&rcg->s, ns); + f.pre_div = ns_to_pre_div(&rcg->p, ns) + 1; + + for (i = 0; i < num_parents; i++) { + if (src == rcg->s.parent_map[i].cfg) { + f.src = rcg->s.parent_map[i].src; + return __clk_rcg_set_rate(rcg, &f); + } + } + + return -EINVAL; +} + +static int clk_rcg_bypass2_set_rate_and_parent(struct clk_hw *hw, + unsigned long rate, unsigned long parent_rate, u8 index) +{ + /* Read the hardware to determine parent during set_rate */ + return clk_rcg_bypass2_set_rate(hw, rate, parent_rate); +} + +struct frac_entry { + int num; + int den; +}; + +static const struct frac_entry pixel_table[] = { + { 1, 2 }, + { 1, 3 }, + { 3, 16 }, + { } +}; + +static int clk_rcg_pixel_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + int delta = 100000; + const struct frac_entry *frac = pixel_table; + unsigned long request, src_rate; + + for (; frac->num; frac++) { + request = (req->rate * frac->den) / frac->num; + + src_rate = clk_hw_round_rate(req->best_parent_hw, request); + + if ((src_rate < (request - delta)) || + (src_rate > (request + delta))) + continue; + + req->best_parent_rate = src_rate; + req->rate = (src_rate * frac->num) / frac->den; + return 0; + } + + return -EINVAL; +} + +static int clk_rcg_pixel_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_rcg *rcg = to_clk_rcg(hw); + int delta = 100000; + const struct frac_entry *frac = pixel_table; + unsigned long request; + struct freq_tbl f = { 0 }; + u32 ns, src; + int i, ret, num_parents = clk_hw_get_num_parents(hw); + + ret = regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns); + if (ret) + return ret; + + src = ns_to_src(&rcg->s, ns); + f.pre_div = ns_to_pre_div(&rcg->p, ns) + 1; + + for (i = 0; i < num_parents; i++) { + if (src == rcg->s.parent_map[i].cfg) { + f.src = rcg->s.parent_map[i].src; + break; + } + } + + /* let us find appropriate m/n values for this */ + for (; frac->num; frac++) { + request = (rate * frac->den) / frac->num; + + if ((parent_rate < (request - delta)) || + (parent_rate > (request + delta))) + continue; + + f.m = frac->num; + f.n = frac->den; + + return __clk_rcg_set_rate(rcg, &f); + } + + return -EINVAL; +} + +static int clk_rcg_pixel_set_rate_and_parent(struct clk_hw *hw, + unsigned long rate, unsigned long parent_rate, u8 index) +{ + return clk_rcg_pixel_set_rate(hw, rate, parent_rate); +} + +static int clk_rcg_esc_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_rcg *rcg = to_clk_rcg(hw); + int pre_div_max = BIT(rcg->p.pre_div_width); + int div; + unsigned long src_rate; + + if (req->rate == 0) + return -EINVAL; + + src_rate = clk_hw_get_rate(req->best_parent_hw); + + div = src_rate / req->rate; + + if (div >= 1 && div <= pre_div_max) { + req->best_parent_rate = src_rate; + req->rate = src_rate / div; + return 0; + } + + return -EINVAL; +} + +static int clk_rcg_esc_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_rcg *rcg = to_clk_rcg(hw); + struct freq_tbl f = { 0 }; + int pre_div_max = BIT(rcg->p.pre_div_width); + int div; + u32 ns; + int i, ret, num_parents = clk_hw_get_num_parents(hw); + + if (rate == 0) + return -EINVAL; + + ret = regmap_read(rcg->clkr.regmap, rcg->ns_reg, &ns); + if (ret) + return ret; + + ns = ns_to_src(&rcg->s, ns); + + for (i = 0; i < num_parents; i++) { + if (ns == rcg->s.parent_map[i].cfg) { + f.src = rcg->s.parent_map[i].src; + break; + } + } + + div = parent_rate / rate; + + if (div >= 1 && div <= pre_div_max) { + f.pre_div = div; + return __clk_rcg_set_rate(rcg, &f); + } + + return -EINVAL; +} + +static int clk_rcg_esc_set_rate_and_parent(struct clk_hw *hw, + unsigned long rate, unsigned long parent_rate, u8 index) +{ + return clk_rcg_esc_set_rate(hw, rate, parent_rate); +} + /* * This type of clock has a glitch-free mux that switches between the output of * the M/N counter and an always on clock source (XO). When clk_set_rate() is @@ -639,6 +833,42 @@ const struct clk_ops clk_rcg_bypass_ops = { }; EXPORT_SYMBOL_GPL(clk_rcg_bypass_ops); +const struct clk_ops clk_rcg_bypass2_ops = { + .enable = clk_enable_regmap, + .disable = clk_disable_regmap, + .get_parent = clk_rcg_get_parent, + .set_parent = clk_rcg_set_parent, + .recalc_rate = clk_rcg_recalc_rate, + .determine_rate = clk_rcg_bypass2_determine_rate, + .set_rate = clk_rcg_bypass2_set_rate, + .set_rate_and_parent = clk_rcg_bypass2_set_rate_and_parent, +}; +EXPORT_SYMBOL_GPL(clk_rcg_bypass2_ops); + +const struct clk_ops clk_rcg_pixel_ops = { + .enable = clk_enable_regmap, + .disable = clk_disable_regmap, + .get_parent = clk_rcg_get_parent, + .set_parent = clk_rcg_set_parent, + .recalc_rate = clk_rcg_recalc_rate, + .determine_rate = clk_rcg_pixel_determine_rate, + .set_rate = clk_rcg_pixel_set_rate, + .set_rate_and_parent = clk_rcg_pixel_set_rate_and_parent, +}; +EXPORT_SYMBOL_GPL(clk_rcg_pixel_ops); + +const struct clk_ops clk_rcg_esc_ops = { + .enable = clk_enable_regmap, + .disable = clk_disable_regmap, + .get_parent = clk_rcg_get_parent, + .set_parent = clk_rcg_set_parent, + .recalc_rate = clk_rcg_recalc_rate, + .determine_rate = clk_rcg_esc_determine_rate, + .set_rate = clk_rcg_esc_set_rate, + .set_rate_and_parent = clk_rcg_esc_set_rate_and_parent, +}; +EXPORT_SYMBOL_GPL(clk_rcg_esc_ops); + const struct clk_ops clk_rcg_lcc_ops = { .enable = clk_rcg_lcc_enable, .disable = clk_rcg_lcc_disable, diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h index 56028bb31..4b1e94bdf 100644 --- a/drivers/clk/qcom/clk-rcg.h +++ b/drivers/clk/qcom/clk-rcg.h @@ -106,6 +106,9 @@ struct clk_rcg { extern const struct clk_ops clk_rcg_ops; extern const struct clk_ops clk_rcg_bypass_ops; +extern const struct clk_ops clk_rcg_bypass2_ops; +extern const struct clk_ops clk_rcg_pixel_ops; +extern const struct clk_ops clk_rcg_esc_ops; extern const struct clk_ops clk_rcg_lcc_ops; #define to_clk_rcg(_hw) container_of(to_clk_regmap(_hw), struct clk_rcg, clkr) @@ -153,8 +156,8 @@ extern const struct clk_ops clk_dyn_rcg_ops; * @hid_width: number of bits in half integer divider * @parent_map: map from software's parent index to hardware's src_sel field * @freq_tbl: frequency table + * @current_freq: last cached frequency when using branches with shared RCGs * @clkr: regmap clock handle - * @lock: register lock * */ struct clk_rcg2 { @@ -163,14 +166,17 @@ struct clk_rcg2 { u8 hid_width; const struct parent_map *parent_map; const struct freq_tbl *freq_tbl; + unsigned long current_freq; struct clk_regmap clkr; }; #define to_clk_rcg2(_hw) container_of(to_clk_regmap(_hw), struct clk_rcg2, clkr) extern const struct clk_ops clk_rcg2_ops; +extern const struct clk_ops clk_rcg2_shared_ops; extern const struct clk_ops clk_edp_pixel_ops; extern const struct clk_ops clk_byte_ops; +extern const struct clk_ops clk_byte2_ops; extern const struct clk_ops clk_pixel_ops; #endif diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index 9aec1761f..b544bb302 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -300,6 +300,85 @@ const struct clk_ops clk_rcg2_ops = { }; EXPORT_SYMBOL_GPL(clk_rcg2_ops); +static int clk_rcg2_shared_force_enable(struct clk_hw *hw, unsigned long rate) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + const char *name = clk_hw_get_name(hw); + int ret, count; + + /* force enable RCG */ + ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG, + CMD_ROOT_EN, CMD_ROOT_EN); + if (ret) + return ret; + + /* wait for RCG to turn ON */ + for (count = 500; count > 0; count--) { + ret = clk_rcg2_is_enabled(hw); + if (ret) + break; + udelay(1); + } + if (!count) + pr_err("%s: RCG did not turn on\n", name); + + /* set clock rate */ + ret = __clk_rcg2_set_rate(hw, rate); + if (ret) + return ret; + + /* clear force enable RCG */ + return regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG, + CMD_ROOT_EN, 0); +} + +static int clk_rcg2_shared_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + + /* cache the rate */ + rcg->current_freq = rate; + + if (!__clk_is_enabled(hw->clk)) + return 0; + + return clk_rcg2_shared_force_enable(hw, rcg->current_freq); +} + +static unsigned long +clk_rcg2_shared_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + + return rcg->current_freq = clk_rcg2_recalc_rate(hw, parent_rate); +} + +static int clk_rcg2_shared_enable(struct clk_hw *hw) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + + return clk_rcg2_shared_force_enable(hw, rcg->current_freq); +} + +static void clk_rcg2_shared_disable(struct clk_hw *hw) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + + /* switch to XO, which is the lowest entry in the freq table */ + clk_rcg2_shared_set_rate(hw, rcg->freq_tbl[0].freq, 0); +} + +const struct clk_ops clk_rcg2_shared_ops = { + .enable = clk_rcg2_shared_enable, + .disable = clk_rcg2_shared_disable, + .get_parent = clk_rcg2_get_parent, + .recalc_rate = clk_rcg2_shared_recalc_rate, + .determine_rate = clk_rcg2_determine_rate, + .set_rate = clk_rcg2_shared_set_rate, +}; +EXPORT_SYMBOL_GPL(clk_rcg2_shared_ops); + struct frac_entry { int num; int den; @@ -485,6 +564,76 @@ const struct clk_ops clk_byte_ops = { }; EXPORT_SYMBOL_GPL(clk_byte_ops); +static int clk_byte2_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + unsigned long parent_rate, div; + u32 mask = BIT(rcg->hid_width) - 1; + struct clk_hw *p; + unsigned long rate = req->rate; + + if (rate == 0) + return -EINVAL; + + p = req->best_parent_hw; + req->best_parent_rate = parent_rate = clk_hw_round_rate(p, rate); + + div = DIV_ROUND_UP((2 * parent_rate), rate) - 1; + div = min_t(u32, div, mask); + + req->rate = calc_rate(parent_rate, 0, 0, 0, div); + + return 0; +} + +static int clk_byte2_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + struct freq_tbl f = { 0 }; + unsigned long div; + int i, num_parents = clk_hw_get_num_parents(hw); + u32 mask = BIT(rcg->hid_width) - 1; + u32 cfg; + + div = DIV_ROUND_UP((2 * parent_rate), rate) - 1; + div = min_t(u32, div, mask); + + f.pre_div = div; + + regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg); + cfg &= CFG_SRC_SEL_MASK; + cfg >>= CFG_SRC_SEL_SHIFT; + + for (i = 0; i < num_parents; i++) { + if (cfg == rcg->parent_map[i].cfg) { + f.src = rcg->parent_map[i].src; + return clk_rcg2_configure(rcg, &f); + } + } + + return -EINVAL; +} + +static int clk_byte2_set_rate_and_parent(struct clk_hw *hw, + unsigned long rate, unsigned long parent_rate, u8 index) +{ + /* Read the hardware to determine parent during set_rate */ + return clk_byte2_set_rate(hw, rate, parent_rate); +} + +const struct clk_ops clk_byte2_ops = { + .is_enabled = clk_rcg2_is_enabled, + .get_parent = clk_rcg2_get_parent, + .set_parent = clk_rcg2_set_parent, + .recalc_rate = clk_rcg2_recalc_rate, + .set_rate = clk_byte2_set_rate, + .set_rate_and_parent = clk_byte2_set_rate_and_parent, + .determine_rate = clk_byte2_determine_rate, +}; +EXPORT_SYMBOL_GPL(clk_byte2_ops); + static const struct frac_entry frac_table_pixel[] = { { 3, 8 }, { 2, 9 }, @@ -496,14 +645,9 @@ static const struct frac_entry frac_table_pixel[] = { static int clk_pixel_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) { - struct clk_rcg2 *rcg = to_clk_rcg2(hw); unsigned long request, src_rate; int delta = 100000; - const struct freq_tbl *f = rcg->freq_tbl; const struct frac_entry *frac = frac_table_pixel; - int index = qcom_find_src_index(hw, rcg->parent_map, f->src); - - req->best_parent_hw = clk_hw_get_parent_by_index(hw, index); for (; frac->num; frac++) { request = (req->rate * frac->den) / frac->num; @@ -525,12 +669,23 @@ static int clk_pixel_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); - struct freq_tbl f = *rcg->freq_tbl; + struct freq_tbl f = { 0 }; const struct frac_entry *frac = frac_table_pixel; unsigned long request; int delta = 100000; u32 mask = BIT(rcg->hid_width) - 1; - u32 hid_div; + u32 hid_div, cfg; + int i, num_parents = clk_hw_get_num_parents(hw); + + regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg); + cfg &= CFG_SRC_SEL_MASK; + cfg >>= CFG_SRC_SEL_SHIFT; + + for (i = 0; i < num_parents; i++) + if (cfg == rcg->parent_map[i].cfg) { + f.src = rcg->parent_map[i].src; + break; + } for (; frac->num; frac++) { request = (rate * frac->den) / frac->num; @@ -555,7 +710,6 @@ static int clk_pixel_set_rate(struct clk_hw *hw, unsigned long rate, static int clk_pixel_set_rate_and_parent(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate, u8 index) { - /* Parent index is set statically in frequency table */ return clk_pixel_set_rate(hw, rate, parent_rate); } diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c index 2dedceefd..8fa477293 100644 --- a/drivers/clk/qcom/common.c +++ b/drivers/clk/qcom/common.c @@ -22,6 +22,7 @@ #include "clk-rcg.h" #include "clk-regmap.h" #include "reset.h" +#include "gdsc.h" struct qcom_cc { struct qcom_reset_controller reset; @@ -72,6 +73,21 @@ qcom_cc_map(struct platform_device *pdev, const struct qcom_cc_desc *desc) } EXPORT_SYMBOL_GPL(qcom_cc_map); +static void qcom_cc_del_clk_provider(void *data) +{ + of_clk_del_provider(data); +} + +static void qcom_cc_reset_unregister(void *data) +{ + reset_controller_unregister(data); +} + +static void qcom_cc_gdsc_unregister(void *data) +{ + gdsc_unregister(data); +} + int qcom_cc_really_probe(struct platform_device *pdev, const struct qcom_cc_desc *desc, struct regmap *regmap) { @@ -110,6 +126,8 @@ int qcom_cc_really_probe(struct platform_device *pdev, if (ret) return ret; + devm_add_action(dev, qcom_cc_del_clk_provider, pdev->dev.of_node); + reset = &cc->reset; reset->rcdev.of_node = dev->of_node; reset->rcdev.ops = &qcom_reset_ops; @@ -117,13 +135,24 @@ int qcom_cc_really_probe(struct platform_device *pdev, reset->rcdev.nr_resets = desc->num_resets; reset->regmap = regmap; reset->reset_map = desc->resets; - platform_set_drvdata(pdev, &reset->rcdev); ret = reset_controller_register(&reset->rcdev); if (ret) - of_clk_del_provider(dev->of_node); + return ret; + + devm_add_action(dev, qcom_cc_reset_unregister, &reset->rcdev); + + if (desc->gdscs && desc->num_gdscs) { + ret = gdsc_register(dev, desc->gdscs, desc->num_gdscs, + &reset->rcdev, regmap); + if (ret) + return ret; + } + + devm_add_action(dev, qcom_cc_gdsc_unregister, dev); - return ret; + + return 0; } EXPORT_SYMBOL_GPL(qcom_cc_really_probe); @@ -139,11 +168,4 @@ int qcom_cc_probe(struct platform_device *pdev, const struct qcom_cc_desc *desc) } EXPORT_SYMBOL_GPL(qcom_cc_probe); -void qcom_cc_remove(struct platform_device *pdev) -{ - of_clk_del_provider(pdev->dev.of_node); - reset_controller_unregister(platform_get_drvdata(pdev)); -} -EXPORT_SYMBOL_GPL(qcom_cc_remove); - MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h index 7a0e73713..7c1fba3eb 100644 --- a/drivers/clk/qcom/common.h +++ b/drivers/clk/qcom/common.h @@ -28,6 +28,8 @@ struct qcom_cc_desc { size_t num_clks; const struct qcom_reset_map *resets; size_t num_resets; + struct gdsc **gdscs; + size_t num_gdscs; }; extern const struct freq_tbl *qcom_find_freq(const struct freq_tbl *f, @@ -43,6 +45,4 @@ extern int qcom_cc_really_probe(struct platform_device *pdev, extern int qcom_cc_probe(struct platform_device *pdev, const struct qcom_cc_desc *desc); -extern void qcom_cc_remove(struct platform_device *pdev); - #endif diff --git a/drivers/clk/qcom/gcc-apq8084.c b/drivers/clk/qcom/gcc-apq8084.c index 3563019b8..1567c3a79 100644 --- a/drivers/clk/qcom/gcc-apq8084.c +++ b/drivers/clk/qcom/gcc-apq8084.c @@ -31,6 +31,7 @@ #include "clk-rcg.h" #include "clk-branch.h" #include "reset.h" +#include "gdsc.h" enum { P_XO, @@ -3254,6 +3255,38 @@ static struct clk_branch gcc_usb_hsic_system_clk = { }, }; +static struct gdsc usb_hs_hsic_gdsc = { + .gdscr = 0x404, + .pd = { + .name = "usb_hs_hsic", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc pcie0_gdsc = { + .gdscr = 0x1ac4, + .pd = { + .name = "pcie0", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc pcie1_gdsc = { + .gdscr = 0x1b44, + .pd = { + .name = "pcie1", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc usb30_gdsc = { + .gdscr = 0x1e84, + .pd = { + .name = "usb30", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + static struct clk_regmap *gcc_apq8084_clocks[] = { [GPLL0] = &gpll0.clkr, [GPLL0_VOTE] = &gpll0_vote, @@ -3447,6 +3480,13 @@ static struct clk_regmap *gcc_apq8084_clocks[] = { [GCC_USB_HSIC_SYSTEM_CLK] = &gcc_usb_hsic_system_clk.clkr, }; +static struct gdsc *gcc_apq8084_gdscs[] = { + [USB_HS_HSIC_GDSC] = &usb_hs_hsic_gdsc, + [PCIE0_GDSC] = &pcie0_gdsc, + [PCIE1_GDSC] = &pcie1_gdsc, + [USB30_GDSC] = &usb30_gdsc, +}; + static const struct qcom_reset_map gcc_apq8084_resets[] = { [GCC_SYSTEM_NOC_BCR] = { 0x0100 }, [GCC_CONFIG_NOC_BCR] = { 0x0140 }, @@ -3555,6 +3595,8 @@ static const struct qcom_cc_desc gcc_apq8084_desc = { .num_clks = ARRAY_SIZE(gcc_apq8084_clocks), .resets = gcc_apq8084_resets, .num_resets = ARRAY_SIZE(gcc_apq8084_resets), + .gdscs = gcc_apq8084_gdscs, + .num_gdscs = ARRAY_SIZE(gcc_apq8084_gdscs), }; static const struct of_device_id gcc_apq8084_match_table[] = { @@ -3581,15 +3623,8 @@ static int gcc_apq8084_probe(struct platform_device *pdev) return qcom_cc_probe(pdev, &gcc_apq8084_desc); } -static int gcc_apq8084_remove(struct platform_device *pdev) -{ - qcom_cc_remove(pdev); - return 0; -} - static struct platform_driver gcc_apq8084_driver = { .probe = gcc_apq8084_probe, - .remove = gcc_apq8084_remove, .driver = { .name = "gcc-apq8084", .of_match_table = gcc_apq8084_match_table, diff --git a/drivers/clk/qcom/gcc-ipq806x.c b/drivers/clk/qcom/gcc-ipq806x.c index 40e480220..16fc64c08 100644 --- a/drivers/clk/qcom/gcc-ipq806x.c +++ b/drivers/clk/qcom/gcc-ipq806x.c @@ -3058,15 +3058,8 @@ static int gcc_ipq806x_probe(struct platform_device *pdev) return 0; } -static int gcc_ipq806x_remove(struct platform_device *pdev) -{ - qcom_cc_remove(pdev); - return 0; -} - static struct platform_driver gcc_ipq806x_driver = { .probe = gcc_ipq806x_probe, - .remove = gcc_ipq806x_remove, .driver = { .name = "gcc-ipq806x", .of_match_table = gcc_ipq806x_match_table, diff --git a/drivers/clk/qcom/gcc-msm8660.c b/drivers/clk/qcom/gcc-msm8660.c index b02826ed7..f110bb5a1 100644 --- a/drivers/clk/qcom/gcc-msm8660.c +++ b/drivers/clk/qcom/gcc-msm8660.c @@ -2735,15 +2735,8 @@ static int gcc_msm8660_probe(struct platform_device *pdev) return qcom_cc_probe(pdev, &gcc_msm8660_desc); } -static int gcc_msm8660_remove(struct platform_device *pdev) -{ - qcom_cc_remove(pdev); - return 0; -} - static struct platform_driver gcc_msm8660_driver = { .probe = gcc_msm8660_probe, - .remove = gcc_msm8660_remove, .driver = { .name = "gcc-msm8660", .of_match_table = gcc_msm8660_match_table, diff --git a/drivers/clk/qcom/gcc-msm8916.c b/drivers/clk/qcom/gcc-msm8916.c index 22a4e1e73..d0a0313d6 100644 --- a/drivers/clk/qcom/gcc-msm8916.c +++ b/drivers/clk/qcom/gcc-msm8916.c @@ -31,6 +31,7 @@ #include "clk-rcg.h" #include "clk-branch.h" #include "reset.h" +#include "gdsc.h" enum { P_XO, @@ -44,6 +45,9 @@ enum { P_SLEEP_CLK, P_DSI0_PHYPLL_BYTE, P_DSI0_PHYPLL_DSI, + P_EXT_PRI_I2S, + P_EXT_SEC_I2S, + P_EXT_MCLK, }; static const struct parent_map gcc_xo_gpll0_map[] = { @@ -190,6 +194,76 @@ static const char * const gcc_xo_gpll0a_gpll1_gpll2[] = { "gpll2_vote", }; +static const struct parent_map gcc_xo_gpll0_gpll1_sleep_map[] = { + { P_XO, 0 }, + { P_GPLL0, 1 }, + { P_GPLL1, 2 }, + { P_SLEEP_CLK, 6 } +}; + +static const char * const gcc_xo_gpll0_gpll1_sleep[] = { + "xo", + "gpll0_vote", + "gpll1_vote", + "sleep_clk", +}; + +static const struct parent_map gcc_xo_gpll1_epi2s_emclk_sleep_map[] = { + { P_XO, 0 }, + { P_GPLL1, 1 }, + { P_EXT_PRI_I2S, 2 }, + { P_EXT_MCLK, 3 }, + { P_SLEEP_CLK, 6 } +}; + +static const char * const gcc_xo_gpll1_epi2s_emclk_sleep[] = { + "xo", + "gpll1_vote", + "ext_pri_i2s", + "ext_mclk", + "sleep_clk", +}; + +static const struct parent_map gcc_xo_gpll1_esi2s_emclk_sleep_map[] = { + { P_XO, 0 }, + { P_GPLL1, 1 }, + { P_EXT_SEC_I2S, 2 }, + { P_EXT_MCLK, 3 }, + { P_SLEEP_CLK, 6 } +}; + +static const char * const gcc_xo_gpll1_esi2s_emclk_sleep[] = { + "xo", + "gpll1_vote", + "ext_sec_i2s", + "ext_mclk", + "sleep_clk", +}; + +static const struct parent_map gcc_xo_sleep_map[] = { + { P_XO, 0 }, + { P_SLEEP_CLK, 6 } +}; + +static const char * const gcc_xo_sleep[] = { + "xo", + "sleep_clk", +}; + +static const struct parent_map gcc_xo_gpll1_emclk_sleep_map[] = { + { P_XO, 0 }, + { P_GPLL1, 1 }, + { P_EXT_MCLK, 2 }, + { P_SLEEP_CLK, 6 } +}; + +static const char * const gcc_xo_gpll1_emclk_sleep[] = { + "xo", + "gpll1_vote", + "ext_mclk", + "sleep_clk", +}; + #define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } static struct clk_pll gpll0 = { @@ -906,21 +980,15 @@ static struct clk_rcg2 gp3_clk_src = { }, }; -static struct freq_tbl ftbl_gcc_mdss_byte0_clk[] = { - { .src = P_DSI0_PHYPLL_BYTE }, - { } -}; - static struct clk_rcg2 byte0_clk_src = { .cmd_rcgr = 0x4d044, .hid_width = 5, .parent_map = gcc_xo_gpll0a_dsibyte_map, - .freq_tbl = ftbl_gcc_mdss_byte0_clk, .clkr.hw.init = &(struct clk_init_data){ .name = "byte0_clk_src", .parent_names = gcc_xo_gpll0a_dsibyte, .num_parents = 3, - .ops = &clk_byte_ops, + .ops = &clk_byte2_ops, .flags = CLK_SET_RATE_PARENT, }, }; @@ -968,17 +1036,11 @@ static struct clk_rcg2 mdp_clk_src = { }, }; -static struct freq_tbl ftbl_gcc_mdss_pclk[] = { - { .src = P_DSI0_PHYPLL_DSI }, - { } -}; - static struct clk_rcg2 pclk0_clk_src = { .cmd_rcgr = 0x4d000, .mnd_width = 8, .hid_width = 5, .parent_map = gcc_xo_gpll0a_dsiphy_map, - .freq_tbl = ftbl_gcc_mdss_pclk, .clkr.hw.init = &(struct clk_init_data){ .name = "pclk0_clk_src", .parent_names = gcc_xo_gpll0a_dsiphy, @@ -1094,6 +1156,30 @@ static struct clk_rcg2 apss_tcu_clk_src = { }, }; +static const struct freq_tbl ftbl_gcc_bimc_gpu_clk[] = { + F(19200000, P_XO, 1, 0, 0), + F(100000000, P_GPLL0, 8, 0, 0), + F(200000000, P_GPLL0, 4, 0, 0), + F(266500000, P_BIMC, 4, 0, 0), + F(400000000, P_GPLL0, 2, 0, 0), + F(533000000, P_BIMC, 2, 0, 0), + { } +}; + +static struct clk_rcg2 bimc_gpu_clk_src = { + .cmd_rcgr = 0x31028, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_bimc_map, + .freq_tbl = ftbl_gcc_bimc_gpu_clk, + .clkr.hw.init = &(struct clk_init_data){ + .name = "bimc_gpu_clk_src", + .parent_names = gcc_xo_gpll0_bimc, + .num_parents = 3, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_rcg2_shared_ops, + }, +}; + static const struct freq_tbl ftbl_gcc_usb_hs_system_clk[] = { F(80000000, P_GPLL0, 10, 0, 0), { } @@ -1112,6 +1198,305 @@ static struct clk_rcg2 usb_hs_system_clk_src = { }, }; +static const struct freq_tbl ftbl_gcc_ultaudio_ahb_clk[] = { + F(3200000, P_XO, 6, 0, 0), + F(6400000, P_XO, 3, 0, 0), + F(9600000, P_XO, 2, 0, 0), + F(19200000, P_XO, 1, 0, 0), + F(40000000, P_GPLL0, 10, 1, 2), + F(66670000, P_GPLL0, 12, 0, 0), + F(80000000, P_GPLL0, 10, 0, 0), + F(100000000, P_GPLL0, 8, 0, 0), + { } +}; + +static struct clk_rcg2 ultaudio_ahbfabric_clk_src = { + .cmd_rcgr = 0x1c010, + .hid_width = 5, + .mnd_width = 8, + .parent_map = gcc_xo_gpll0_gpll1_sleep_map, + .freq_tbl = ftbl_gcc_ultaudio_ahb_clk, + .clkr.hw.init = &(struct clk_init_data){ + .name = "ultaudio_ahbfabric_clk_src", + .parent_names = gcc_xo_gpll0_gpll1_sleep, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_ultaudio_ahbfabric_ixfabric_clk = { + .halt_reg = 0x1c028, + .clkr = { + .enable_reg = 0x1c028, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ultaudio_ahbfabric_ixfabric_clk", + .parent_names = (const char *[]){ + "ultaudio_ahbfabric_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ultaudio_ahbfabric_ixfabric_lpm_clk = { + .halt_reg = 0x1c024, + .clkr = { + .enable_reg = 0x1c024, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ultaudio_ahbfabric_ixfabric_lpm_clk", + .parent_names = (const char *[]){ + "ultaudio_ahbfabric_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_gcc_ultaudio_lpaif_i2s_clk[] = { + F(256000, P_XO, 5, 1, 15), + F(512000, P_XO, 5, 2, 15), + F(705600, P_GPLL1, 16, 1, 80), + F(768000, P_XO, 5, 1, 5), + F(800000, P_XO, 5, 5, 24), + F(1024000, P_GPLL1, 14, 1, 63), + F(1152000, P_XO, 1, 3, 50), + F(1411200, P_GPLL1, 16, 1, 40), + F(1536000, P_XO, 1, 2, 25), + F(1600000, P_XO, 12, 0, 0), + F(2048000, P_GPLL1, 9, 1, 49), + F(2400000, P_XO, 8, 0, 0), + F(2822400, P_GPLL1, 16, 1, 20), + F(3072000, P_GPLL1, 14, 1, 21), + F(4096000, P_GPLL1, 9, 2, 49), + F(4800000, P_XO, 4, 0, 0), + F(5644800, P_GPLL1, 16, 1, 10), + F(6144000, P_GPLL1, 7, 1, 21), + F(8192000, P_GPLL1, 9, 4, 49), + F(9600000, P_XO, 2, 0, 0), + F(11289600, P_GPLL1, 16, 1, 5), + F(12288000, P_GPLL1, 7, 2, 21), + { } +}; + +static struct clk_rcg2 ultaudio_lpaif_pri_i2s_clk_src = { + .cmd_rcgr = 0x1c054, + .hid_width = 5, + .mnd_width = 8, + .parent_map = gcc_xo_gpll1_epi2s_emclk_sleep_map, + .freq_tbl = ftbl_gcc_ultaudio_lpaif_i2s_clk, + .clkr.hw.init = &(struct clk_init_data){ + .name = "ultaudio_lpaif_pri_i2s_clk_src", + .parent_names = gcc_xo_gpll1_epi2s_emclk_sleep, + .num_parents = 5, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_ultaudio_lpaif_pri_i2s_clk = { + .halt_reg = 0x1c068, + .clkr = { + .enable_reg = 0x1c068, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ultaudio_lpaif_pri_i2s_clk", + .parent_names = (const char *[]){ + "ultaudio_lpaif_pri_i2s_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_rcg2 ultaudio_lpaif_sec_i2s_clk_src = { + .cmd_rcgr = 0x1c06c, + .hid_width = 5, + .mnd_width = 8, + .parent_map = gcc_xo_gpll1_esi2s_emclk_sleep_map, + .freq_tbl = ftbl_gcc_ultaudio_lpaif_i2s_clk, + .clkr.hw.init = &(struct clk_init_data){ + .name = "ultaudio_lpaif_sec_i2s_clk_src", + .parent_names = gcc_xo_gpll1_esi2s_emclk_sleep, + .num_parents = 5, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_ultaudio_lpaif_sec_i2s_clk = { + .halt_reg = 0x1c080, + .clkr = { + .enable_reg = 0x1c080, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ultaudio_lpaif_sec_i2s_clk", + .parent_names = (const char *[]){ + "ultaudio_lpaif_sec_i2s_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_rcg2 ultaudio_lpaif_aux_i2s_clk_src = { + .cmd_rcgr = 0x1c084, + .hid_width = 5, + .mnd_width = 8, + .parent_map = gcc_xo_gpll1_emclk_sleep_map, + .freq_tbl = ftbl_gcc_ultaudio_lpaif_i2s_clk, + .clkr.hw.init = &(struct clk_init_data){ + .name = "ultaudio_lpaif_aux_i2s_clk_src", + .parent_names = gcc_xo_gpll1_esi2s_emclk_sleep, + .num_parents = 5, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_ultaudio_lpaif_aux_i2s_clk = { + .halt_reg = 0x1c098, + .clkr = { + .enable_reg = 0x1c098, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ultaudio_lpaif_aux_i2s_clk", + .parent_names = (const char *[]){ + "ultaudio_lpaif_aux_i2s_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_gcc_ultaudio_xo_clk[] = { + F(19200000, P_XO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 ultaudio_xo_clk_src = { + .cmd_rcgr = 0x1c034, + .hid_width = 5, + .parent_map = gcc_xo_sleep_map, + .freq_tbl = ftbl_gcc_ultaudio_xo_clk, + .clkr.hw.init = &(struct clk_init_data){ + .name = "ultaudio_xo_clk_src", + .parent_names = gcc_xo_sleep, + .num_parents = 2, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_ultaudio_avsync_xo_clk = { + .halt_reg = 0x1c04c, + .clkr = { + .enable_reg = 0x1c04c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ultaudio_avsync_xo_clk", + .parent_names = (const char *[]){ + "ultaudio_xo_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ultaudio_stc_xo_clk = { + .halt_reg = 0x1c050, + .clkr = { + .enable_reg = 0x1c050, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ultaudio_stc_xo_clk", + .parent_names = (const char *[]){ + "ultaudio_xo_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static const struct freq_tbl ftbl_codec_clk[] = { + F(19200000, P_XO, 1, 0, 0), + F(11289600, P_EXT_MCLK, 1, 0, 0), + { } +}; + +static struct clk_rcg2 codec_digcodec_clk_src = { + .cmd_rcgr = 0x1c09c, + .hid_width = 5, + .parent_map = gcc_xo_gpll1_emclk_sleep_map, + .freq_tbl = ftbl_codec_clk, + .clkr.hw.init = &(struct clk_init_data){ + .name = "codec_digcodec_clk_src", + .parent_names = gcc_xo_gpll1_emclk_sleep, + .num_parents = 4, + .ops = &clk_rcg2_ops, + }, +}; + +static struct clk_branch gcc_codec_digcodec_clk = { + .halt_reg = 0x1c0b0, + .clkr = { + .enable_reg = 0x1c0b0, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ultaudio_codec_digcodec_clk", + .parent_names = (const char *[]){ + "codec_digcodec_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ultaudio_pcnoc_mport_clk = { + .halt_reg = 0x1c000, + .clkr = { + .enable_reg = 0x1c000, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ultaudio_pcnoc_mport_clk", + .parent_names = (const char *[]){ + "pcnoc_bfdcd_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_ultaudio_pcnoc_sway_clk = { + .halt_reg = 0x1c004, + .clkr = { + .enable_reg = 0x1c004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ultaudio_pcnoc_sway_clk", + .parent_names = (const char *[]){ + "pcnoc_bfdcd_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + static const struct freq_tbl ftbl_gcc_venus0_vcodec0_clk[] = { F(100000000, P_GPLL0, 8, 0, 0), F(160000000, P_GPLL0, 5, 0, 0), @@ -2358,6 +2743,51 @@ static struct clk_branch gcc_sdcc2_apps_clk = { }, }; +static struct clk_rcg2 bimc_ddr_clk_src = { + .cmd_rcgr = 0x32004, + .hid_width = 5, + .parent_map = gcc_xo_gpll0_bimc_map, + .clkr.hw.init = &(struct clk_init_data){ + .name = "bimc_ddr_clk_src", + .parent_names = gcc_xo_gpll0_bimc, + .num_parents = 3, + .ops = &clk_rcg2_ops, + .flags = CLK_GET_RATE_NOCACHE, + }, +}; + +static struct clk_branch gcc_apss_tcu_clk = { + .halt_reg = 0x12018, + .clkr = { + .enable_reg = 0x4500c, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gcc_apss_tcu_clk", + .parent_names = (const char *[]){ + "bimc_ddr_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_gfx_tcu_clk = { + .halt_reg = 0x12020, + .clkr = { + .enable_reg = 0x4500c, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "gcc_gfx_tcu_clk", + .parent_names = (const char *[]){ + "bimc_ddr_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + static struct clk_branch gcc_gtcu_ahb_clk = { .halt_reg = 0x12044, .clkr = { @@ -2375,6 +2805,40 @@ static struct clk_branch gcc_gtcu_ahb_clk = { }, }; +static struct clk_branch gcc_bimc_gfx_clk = { + .halt_reg = 0x31024, + .clkr = { + .enable_reg = 0x31024, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_bimc_gfx_clk", + .parent_names = (const char *[]){ + "bimc_gpu_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_bimc_gpu_clk = { + .halt_reg = 0x31040, + .clkr = { + .enable_reg = 0x31040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_bimc_gpu_clk", + .parent_names = (const char *[]){ + "bimc_gpu_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + static struct clk_branch gcc_jpeg_tbu_clk = { .halt_reg = 0x12034, .clkr = { @@ -2562,6 +3026,46 @@ static struct clk_branch gcc_venus0_vcodec0_clk = { }, }; +static struct gdsc venus_gdsc = { + .gdscr = 0x4c018, + .pd = { + .name = "venus", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc mdss_gdsc = { + .gdscr = 0x4d078, + .pd = { + .name = "mdss", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc jpeg_gdsc = { + .gdscr = 0x5701c, + .pd = { + .name = "jpeg", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc vfe_gdsc = { + .gdscr = 0x58034, + .pd = { + .name = "vfe", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc oxili_gdsc = { + .gdscr = 0x5901c, + .pd = { + .name = "oxili", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + static struct clk_regmap *gcc_msm8916_clocks[] = { [GPLL0] = &gpll0.clkr, [GPLL0_VOTE] = &gpll0_vote, @@ -2701,6 +3205,36 @@ static struct clk_regmap *gcc_msm8916_clocks[] = { [GCC_VENUS0_AHB_CLK] = &gcc_venus0_ahb_clk.clkr, [GCC_VENUS0_AXI_CLK] = &gcc_venus0_axi_clk.clkr, [GCC_VENUS0_VCODEC0_CLK] = &gcc_venus0_vcodec0_clk.clkr, + [BIMC_DDR_CLK_SRC] = &bimc_ddr_clk_src.clkr, + [GCC_APSS_TCU_CLK] = &gcc_apss_tcu_clk.clkr, + [GCC_GFX_TCU_CLK] = &gcc_gfx_tcu_clk.clkr, + [BIMC_GPU_CLK_SRC] = &bimc_gpu_clk_src.clkr, + [GCC_BIMC_GFX_CLK] = &gcc_bimc_gfx_clk.clkr, + [GCC_BIMC_GPU_CLK] = &gcc_bimc_gpu_clk.clkr, + [ULTAUDIO_AHBFABRIC_CLK_SRC] = &ultaudio_ahbfabric_clk_src.clkr, + [ULTAUDIO_LPAIF_PRI_I2S_CLK_SRC] = &ultaudio_lpaif_pri_i2s_clk_src.clkr, + [ULTAUDIO_LPAIF_SEC_I2S_CLK_SRC] = &ultaudio_lpaif_sec_i2s_clk_src.clkr, + [ULTAUDIO_LPAIF_AUX_I2S_CLK_SRC] = &ultaudio_lpaif_aux_i2s_clk_src.clkr, + [ULTAUDIO_XO_CLK_SRC] = &ultaudio_xo_clk_src.clkr, + [CODEC_DIGCODEC_CLK_SRC] = &codec_digcodec_clk_src.clkr, + [GCC_ULTAUDIO_PCNOC_MPORT_CLK] = &gcc_ultaudio_pcnoc_mport_clk.clkr, + [GCC_ULTAUDIO_PCNOC_SWAY_CLK] = &gcc_ultaudio_pcnoc_sway_clk.clkr, + [GCC_ULTAUDIO_AVSYNC_XO_CLK] = &gcc_ultaudio_avsync_xo_clk.clkr, + [GCC_ULTAUDIO_STC_XO_CLK] = &gcc_ultaudio_stc_xo_clk.clkr, + [GCC_ULTAUDIO_AHBFABRIC_IXFABRIC_CLK] = &gcc_ultaudio_ahbfabric_ixfabric_clk.clkr, + [GCC_ULTAUDIO_AHBFABRIC_IXFABRIC_LPM_CLK] = &gcc_ultaudio_ahbfabric_ixfabric_lpm_clk.clkr, + [GCC_ULTAUDIO_LPAIF_PRI_I2S_CLK] = &gcc_ultaudio_lpaif_pri_i2s_clk.clkr, + [GCC_ULTAUDIO_LPAIF_SEC_I2S_CLK] = &gcc_ultaudio_lpaif_sec_i2s_clk.clkr, + [GCC_ULTAUDIO_LPAIF_AUX_I2S_CLK] = &gcc_ultaudio_lpaif_aux_i2s_clk.clkr, + [GCC_CODEC_DIGCODEC_CLK] = &gcc_codec_digcodec_clk.clkr, +}; + +static struct gdsc *gcc_msm8916_gdscs[] = { + [VENUS_GDSC] = &venus_gdsc, + [MDSS_GDSC] = &mdss_gdsc, + [JPEG_GDSC] = &jpeg_gdsc, + [VFE_GDSC] = &vfe_gdsc, + [OXILI_GDSC] = &oxili_gdsc, }; static const struct qcom_reset_map gcc_msm8916_resets[] = { @@ -2810,6 +3344,8 @@ static const struct qcom_cc_desc gcc_msm8916_desc = { .num_clks = ARRAY_SIZE(gcc_msm8916_clocks), .resets = gcc_msm8916_resets, .num_resets = ARRAY_SIZE(gcc_msm8916_resets), + .gdscs = gcc_msm8916_gdscs, + .num_gdscs = ARRAY_SIZE(gcc_msm8916_gdscs), }; static const struct of_device_id gcc_msm8916_match_table[] = { @@ -2836,15 +3372,8 @@ static int gcc_msm8916_probe(struct platform_device *pdev) return qcom_cc_probe(pdev, &gcc_msm8916_desc); } -static int gcc_msm8916_remove(struct platform_device *pdev) -{ - qcom_cc_remove(pdev); - return 0; -} - static struct platform_driver gcc_msm8916_driver = { .probe = gcc_msm8916_probe, - .remove = gcc_msm8916_remove, .driver = { .name = "gcc-msm8916", .of_match_table = gcc_msm8916_match_table, diff --git a/drivers/clk/qcom/gcc-msm8960.c b/drivers/clk/qcom/gcc-msm8960.c index aa294b1ba..66c18bc97 100644 --- a/drivers/clk/qcom/gcc-msm8960.c +++ b/drivers/clk/qcom/gcc-msm8960.c @@ -3506,6 +3506,8 @@ static int gcc_msm8960_probe(struct platform_device *pdev) struct clk *clk; struct device *dev = &pdev->dev; const struct of_device_id *match; + struct platform_device *tsens; + int ret; match = of_match_device(gcc_msm8960_match_table, &pdev->dev); if (!match) @@ -3520,12 +3522,26 @@ static int gcc_msm8960_probe(struct platform_device *pdev) if (IS_ERR(clk)) return PTR_ERR(clk); - return qcom_cc_probe(pdev, match->data); + ret = qcom_cc_probe(pdev, match->data); + if (ret) + return ret; + + tsens = platform_device_register_data(&pdev->dev, "qcom-tsens", -1, + NULL, 0); + if (IS_ERR(tsens)) + return PTR_ERR(tsens); + + platform_set_drvdata(pdev, tsens); + + return 0; } static int gcc_msm8960_remove(struct platform_device *pdev) { - qcom_cc_remove(pdev); + struct platform_device *tsens = platform_get_drvdata(pdev); + + platform_device_unregister(tsens); + return 0; } diff --git a/drivers/clk/qcom/gcc-msm8974.c b/drivers/clk/qcom/gcc-msm8974.c index 2bcf87538..28abb8f8f 100644 --- a/drivers/clk/qcom/gcc-msm8974.c +++ b/drivers/clk/qcom/gcc-msm8974.c @@ -31,6 +31,7 @@ #include "clk-rcg.h" #include "clk-branch.h" #include "reset.h" +#include "gdsc.h" enum { P_XO, @@ -2432,6 +2433,14 @@ static struct clk_branch gcc_usb_hsic_system_clk = { }, }; +static struct gdsc usb_hs_hsic_gdsc = { + .gdscr = 0x404, + .pd = { + .name = "usb_hs_hsic", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + static struct clk_regmap *gcc_msm8974_clocks[] = { [GPLL0] = &gpll0.clkr, [GPLL0_VOTE] = &gpll0_vote, @@ -2661,6 +2670,10 @@ static const struct qcom_reset_map gcc_msm8974_resets[] = { [GCC_VENUS_RESTART] = { 0x1740 }, }; +static struct gdsc *gcc_msm8974_gdscs[] = { + [USB_HS_HSIC_GDSC] = &usb_hs_hsic_gdsc, +}; + static const struct regmap_config gcc_msm8974_regmap_config = { .reg_bits = 32, .reg_stride = 4, @@ -2675,6 +2688,8 @@ static const struct qcom_cc_desc gcc_msm8974_desc = { .num_clks = ARRAY_SIZE(gcc_msm8974_clocks), .resets = gcc_msm8974_resets, .num_resets = ARRAY_SIZE(gcc_msm8974_resets), + .gdscs = gcc_msm8974_gdscs, + .num_gdscs = ARRAY_SIZE(gcc_msm8974_gdscs), }; static const struct of_device_id gcc_msm8974_match_table[] = { @@ -2729,15 +2744,8 @@ static int gcc_msm8974_probe(struct platform_device *pdev) return qcom_cc_probe(pdev, &gcc_msm8974_desc); } -static int gcc_msm8974_remove(struct platform_device *pdev) -{ - qcom_cc_remove(pdev); - return 0; -} - static struct platform_driver gcc_msm8974_driver = { .probe = gcc_msm8974_probe, - .remove = gcc_msm8974_remove, .driver = { .name = "gcc-msm8974", .of_match_table = gcc_msm8974_match_table, diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c new file mode 100644 index 000000000..da9fad8b6 --- /dev/null +++ b/drivers/clk/qcom/gdsc.c @@ -0,0 +1,237 @@ +/* + * Copyright (c) 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. + */ + +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/jiffies.h> +#include <linux/kernel.h> +#include <linux/pm_domain.h> +#include <linux/regmap.h> +#include <linux/reset-controller.h> +#include <linux/slab.h> +#include "gdsc.h" + +#define PWR_ON_MASK BIT(31) +#define EN_REST_WAIT_MASK GENMASK_ULL(23, 20) +#define EN_FEW_WAIT_MASK GENMASK_ULL(19, 16) +#define CLK_DIS_WAIT_MASK GENMASK_ULL(15, 12) +#define SW_OVERRIDE_MASK BIT(2) +#define HW_CONTROL_MASK BIT(1) +#define SW_COLLAPSE_MASK BIT(0) + +/* Wait 2^n CXO cycles between all states. Here, n=2 (4 cycles). */ +#define EN_REST_WAIT_VAL (0x2 << 20) +#define EN_FEW_WAIT_VAL (0x8 << 16) +#define CLK_DIS_WAIT_VAL (0x2 << 12) + +#define RETAIN_MEM BIT(14) +#define RETAIN_PERIPH BIT(13) + +#define TIMEOUT_US 100 + +#define domain_to_gdsc(domain) container_of(domain, struct gdsc, pd) + +static int gdsc_is_enabled(struct gdsc *sc) +{ + u32 val; + int ret; + + ret = regmap_read(sc->regmap, sc->gdscr, &val); + if (ret) + return ret; + + return !!(val & PWR_ON_MASK); +} + +static int gdsc_toggle_logic(struct gdsc *sc, bool en) +{ + int ret; + u32 val = en ? 0 : SW_COLLAPSE_MASK; + u32 check = en ? PWR_ON_MASK : 0; + unsigned long timeout; + + ret = regmap_update_bits(sc->regmap, sc->gdscr, SW_COLLAPSE_MASK, val); + if (ret) + return ret; + + timeout = jiffies + usecs_to_jiffies(TIMEOUT_US); + do { + ret = regmap_read(sc->regmap, sc->gdscr, &val); + if (ret) + return ret; + + if ((val & PWR_ON_MASK) == check) + return 0; + } while (time_before(jiffies, timeout)); + + ret = regmap_read(sc->regmap, sc->gdscr, &val); + if (ret) + return ret; + + if ((val & PWR_ON_MASK) == check) + return 0; + + return -ETIMEDOUT; +} + +static inline int gdsc_deassert_reset(struct gdsc *sc) +{ + int i; + + for (i = 0; i < sc->reset_count; i++) + sc->rcdev->ops->deassert(sc->rcdev, sc->resets[i]); + return 0; +} + +static inline int gdsc_assert_reset(struct gdsc *sc) +{ + int i; + + for (i = 0; i < sc->reset_count; i++) + sc->rcdev->ops->assert(sc->rcdev, sc->resets[i]); + return 0; +} + +static inline void gdsc_force_mem_on(struct gdsc *sc) +{ + int i; + u32 mask = RETAIN_MEM | RETAIN_PERIPH; + + for (i = 0; i < sc->cxc_count; i++) + regmap_update_bits(sc->regmap, sc->cxcs[i], mask, mask); +} + +static inline void gdsc_clear_mem_on(struct gdsc *sc) +{ + int i; + u32 mask = RETAIN_MEM | RETAIN_PERIPH; + + for (i = 0; i < sc->cxc_count; i++) + regmap_update_bits(sc->regmap, sc->cxcs[i], mask, 0); +} + +static int gdsc_enable(struct generic_pm_domain *domain) +{ + struct gdsc *sc = domain_to_gdsc(domain); + int ret; + + if (sc->pwrsts == PWRSTS_ON) + return gdsc_deassert_reset(sc); + + ret = gdsc_toggle_logic(sc, true); + if (ret) + return ret; + + if (sc->pwrsts & PWRSTS_OFF) + gdsc_force_mem_on(sc); + + /* + * If clocks to this power domain were already on, they will take an + * additional 4 clock cycles to re-enable after the power domain is + * enabled. Delay to account for this. A delay is also needed to ensure + * clocks are not enabled within 400ns of enabling power to the + * memories. + */ + udelay(1); + + return 0; +} + +static int gdsc_disable(struct generic_pm_domain *domain) +{ + struct gdsc *sc = domain_to_gdsc(domain); + + if (sc->pwrsts == PWRSTS_ON) + return gdsc_assert_reset(sc); + + if (sc->pwrsts & PWRSTS_OFF) + gdsc_clear_mem_on(sc); + + return gdsc_toggle_logic(sc, false); +} + +static int gdsc_init(struct gdsc *sc) +{ + u32 mask, val; + int on, ret; + + /* + * Disable HW trigger: collapse/restore occur based on registers writes. + * Disable SW override: Use hardware state-machine for sequencing. + * Configure wait time between states. + */ + mask = HW_CONTROL_MASK | SW_OVERRIDE_MASK | + EN_REST_WAIT_MASK | EN_FEW_WAIT_MASK | CLK_DIS_WAIT_MASK; + val = EN_REST_WAIT_VAL | EN_FEW_WAIT_VAL | CLK_DIS_WAIT_VAL; + ret = regmap_update_bits(sc->regmap, sc->gdscr, mask, val); + if (ret) + return ret; + + /* Force gdsc ON if only ON state is supported */ + if (sc->pwrsts == PWRSTS_ON) { + ret = gdsc_toggle_logic(sc, true); + if (ret) + return ret; + } + + on = gdsc_is_enabled(sc); + if (on < 0) + return on; + + if (on || (sc->pwrsts & PWRSTS_RET)) + gdsc_force_mem_on(sc); + else + gdsc_clear_mem_on(sc); + + sc->pd.power_off = gdsc_disable; + sc->pd.power_on = gdsc_enable; + pm_genpd_init(&sc->pd, NULL, !on); + + return 0; +} + +int gdsc_register(struct device *dev, struct gdsc **scs, size_t num, + struct reset_controller_dev *rcdev, struct regmap *regmap) +{ + int i, ret; + struct genpd_onecell_data *data; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->domains = devm_kcalloc(dev, num, sizeof(*data->domains), + GFP_KERNEL); + if (!data->domains) + return -ENOMEM; + + data->num_domains = num; + for (i = 0; i < num; i++) { + if (!scs[i]) + continue; + scs[i]->regmap = regmap; + scs[i]->rcdev = rcdev; + ret = gdsc_init(scs[i]); + if (ret) + return ret; + data->domains[i] = &scs[i]->pd; + } + + return of_genpd_add_provider_onecell(dev->of_node, data); +} + +void gdsc_unregister(struct device *dev) +{ + of_genpd_del_provider(dev->of_node); +} diff --git a/drivers/clk/qcom/gdsc.h b/drivers/clk/qcom/gdsc.h new file mode 100644 index 000000000..5ded26884 --- /dev/null +++ b/drivers/clk/qcom/gdsc.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 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 __QCOM_GDSC_H__ +#define __QCOM_GDSC_H__ + +#include <linux/err.h> +#include <linux/pm_domain.h> + +struct regmap; +struct reset_controller_dev; + +/* Powerdomain allowable state bitfields */ +#define PWRSTS_OFF BIT(0) +#define PWRSTS_RET BIT(1) +#define PWRSTS_ON BIT(2) +#define PWRSTS_OFF_ON (PWRSTS_OFF | PWRSTS_ON) +#define PWRSTS_RET_ON (PWRSTS_RET | PWRSTS_ON) + +/** + * struct gdsc - Globally Distributed Switch Controller + * @pd: generic power domain + * @regmap: regmap for MMIO accesses + * @gdscr: gsdc control register + * @cxcs: offsets of branch registers to toggle mem/periph bits in + * @cxc_count: number of @cxcs + * @pwrsts: Possible powerdomain power states + * @resets: ids of resets associated with this gdsc + * @reset_count: number of @resets + * @rcdev: reset controller + */ +struct gdsc { + struct generic_pm_domain pd; + struct regmap *regmap; + unsigned int gdscr; + unsigned int *cxcs; + unsigned int cxc_count; + const u8 pwrsts; + struct reset_controller_dev *rcdev; + unsigned int *resets; + unsigned int reset_count; +}; + +#ifdef CONFIG_QCOM_GDSC +int gdsc_register(struct device *, struct gdsc **, size_t n, + struct reset_controller_dev *, struct regmap *); +void gdsc_unregister(struct device *); +#else +static inline int gdsc_register(struct device *d, struct gdsc **g, size_t n, + struct reset_controller_dev *rcdev, + struct regmap *r) +{ + return -ENOSYS; +} + +static inline void gdsc_unregister(struct device *d) {}; +#endif /* CONFIG_QCOM_GDSC */ +#endif /* __QCOM_GDSC_H__ */ diff --git a/drivers/clk/qcom/lcc-ipq806x.c b/drivers/clk/qcom/lcc-ipq806x.c index 93ad42b14..db3998e5e 100644 --- a/drivers/clk/qcom/lcc-ipq806x.c +++ b/drivers/clk/qcom/lcc-ipq806x.c @@ -452,15 +452,8 @@ static int lcc_ipq806x_probe(struct platform_device *pdev) return qcom_cc_really_probe(pdev, &lcc_ipq806x_desc, regmap); } -static int lcc_ipq806x_remove(struct platform_device *pdev) -{ - qcom_cc_remove(pdev); - return 0; -} - static struct platform_driver lcc_ipq806x_driver = { .probe = lcc_ipq806x_probe, - .remove = lcc_ipq806x_remove, .driver = { .name = "lcc-ipq806x", .of_match_table = lcc_ipq806x_match_table, diff --git a/drivers/clk/qcom/lcc-msm8960.c b/drivers/clk/qcom/lcc-msm8960.c index ecb96c284..4fcf9d1d2 100644 --- a/drivers/clk/qcom/lcc-msm8960.c +++ b/drivers/clk/qcom/lcc-msm8960.c @@ -565,15 +565,8 @@ static int lcc_msm8960_probe(struct platform_device *pdev) return qcom_cc_really_probe(pdev, &lcc_msm8960_desc, regmap); } -static int lcc_msm8960_remove(struct platform_device *pdev) -{ - qcom_cc_remove(pdev); - return 0; -} - static struct platform_driver lcc_msm8960_driver = { .probe = lcc_msm8960_probe, - .remove = lcc_msm8960_remove, .driver = { .name = "lcc-msm8960", .of_match_table = lcc_msm8960_match_table, diff --git a/drivers/clk/qcom/mmcc-apq8084.c b/drivers/clk/qcom/mmcc-apq8084.c index f0ee6bde1..30777f9f1 100644 --- a/drivers/clk/qcom/mmcc-apq8084.c +++ b/drivers/clk/qcom/mmcc-apq8084.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2015, The Linux Foundation. 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 @@ -26,6 +26,7 @@ #include "clk-rcg.h" #include "clk-branch.h" #include "reset.h" +#include "gdsc.h" enum { P_XO, @@ -571,17 +572,11 @@ static struct clk_rcg2 jpeg2_clk_src = { }, }; -static struct freq_tbl pixel_freq_tbl[] = { - { .src = P_DSI0PLL }, - { } -}; - static struct clk_rcg2 pclk0_clk_src = { .cmd_rcgr = 0x2000, .mnd_width = 8, .hid_width = 5, .parent_map = mmcc_xo_dsi_hdmi_edp_gpll0_map, - .freq_tbl = pixel_freq_tbl, .clkr.hw.init = &(struct clk_init_data){ .name = "pclk0_clk_src", .parent_names = mmcc_xo_dsi_hdmi_edp_gpll0, @@ -596,7 +591,6 @@ static struct clk_rcg2 pclk1_clk_src = { .mnd_width = 8, .hid_width = 5, .parent_map = mmcc_xo_dsi_hdmi_edp_gpll0_map, - .freq_tbl = pixel_freq_tbl, .clkr.hw.init = &(struct clk_init_data){ .name = "pclk1_clk_src", .parent_names = mmcc_xo_dsi_hdmi_edp_gpll0, @@ -844,21 +838,15 @@ static struct clk_rcg2 cpp_clk_src = { }, }; -static struct freq_tbl byte_freq_tbl[] = { - { .src = P_DSI0PLL_BYTE }, - { } -}; - static struct clk_rcg2 byte0_clk_src = { .cmd_rcgr = 0x2120, .hid_width = 5, .parent_map = mmcc_xo_dsibyte_hdmi_edp_gpll0_map, - .freq_tbl = byte_freq_tbl, .clkr.hw.init = &(struct clk_init_data){ .name = "byte0_clk_src", .parent_names = mmcc_xo_dsibyte_hdmi_edp_gpll0, .num_parents = 6, - .ops = &clk_byte_ops, + .ops = &clk_byte2_ops, .flags = CLK_SET_RATE_PARENT, }, }; @@ -867,12 +855,11 @@ static struct clk_rcg2 byte1_clk_src = { .cmd_rcgr = 0x2140, .hid_width = 5, .parent_map = mmcc_xo_dsibyte_hdmi_edp_gpll0_map, - .freq_tbl = byte_freq_tbl, .clkr.hw.init = &(struct clk_init_data){ .name = "byte1_clk_src", .parent_names = mmcc_xo_dsibyte_hdmi_edp_gpll0, .num_parents = 6, - .ops = &clk_byte_ops, + .ops = &clk_byte2_ops, .flags = CLK_SET_RATE_PARENT, }, }; @@ -3077,6 +3064,76 @@ static const struct pll_config mmpll3_config = { .aux_output_mask = BIT(1), }; +static struct gdsc venus0_gdsc = { + .gdscr = 0x1024, + .pd = { + .name = "venus0", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc venus0_core0_gdsc = { + .gdscr = 0x1040, + .pd = { + .name = "venus0_core0", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc venus0_core1_gdsc = { + .gdscr = 0x1044, + .pd = { + .name = "venus0_core1", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc mdss_gdsc = { + .gdscr = 0x2304, + .cxcs = (unsigned int []){ 0x231c, 0x2320 }, + .cxc_count = 2, + .pd = { + .name = "mdss", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc camss_jpeg_gdsc = { + .gdscr = 0x35a4, + .pd = { + .name = "camss_jpeg", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc camss_vfe_gdsc = { + .gdscr = 0x36a4, + .cxcs = (unsigned int []){ 0x36a8, 0x36ac, 0x36b0 }, + .cxc_count = 3, + .pd = { + .name = "camss_vfe", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc oxili_gdsc = { + .gdscr = 0x4024, + .cxcs = (unsigned int []){ 0x4028 }, + .cxc_count = 1, + .pd = { + .name = "oxili", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc oxilicx_gdsc = { + .gdscr = 0x4034, + .pd = { + .name = "oxilicx", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + static struct clk_regmap *mmcc_apq8084_clocks[] = { [MMSS_AHB_CLK_SRC] = &mmss_ahb_clk_src.clkr, [MMSS_AXI_CLK_SRC] = &mmss_axi_clk_src.clkr, @@ -3294,6 +3351,17 @@ static const struct qcom_reset_map mmcc_apq8084_resets[] = { [MMSSNOCAXI_RESET] = { 0x5060 }, }; +static struct gdsc *mmcc_apq8084_gdscs[] = { + [VENUS0_GDSC] = &venus0_gdsc, + [VENUS0_CORE0_GDSC] = &venus0_core0_gdsc, + [VENUS0_CORE1_GDSC] = &venus0_core1_gdsc, + [MDSS_GDSC] = &mdss_gdsc, + [CAMSS_JPEG_GDSC] = &camss_jpeg_gdsc, + [CAMSS_VFE_GDSC] = &camss_vfe_gdsc, + [OXILI_GDSC] = &oxili_gdsc, + [OXILICX_GDSC] = &oxilicx_gdsc, +}; + static const struct regmap_config mmcc_apq8084_regmap_config = { .reg_bits = 32, .reg_stride = 4, @@ -3308,6 +3376,8 @@ static const struct qcom_cc_desc mmcc_apq8084_desc = { .num_clks = ARRAY_SIZE(mmcc_apq8084_clocks), .resets = mmcc_apq8084_resets, .num_resets = ARRAY_SIZE(mmcc_apq8084_resets), + .gdscs = mmcc_apq8084_gdscs, + .num_gdscs = ARRAY_SIZE(mmcc_apq8084_gdscs), }; static const struct of_device_id mmcc_apq8084_match_table[] = { @@ -3332,15 +3402,8 @@ static int mmcc_apq8084_probe(struct platform_device *pdev) return 0; } -static int mmcc_apq8084_remove(struct platform_device *pdev) -{ - qcom_cc_remove(pdev); - return 0; -} - static struct platform_driver mmcc_apq8084_driver = { .probe = mmcc_apq8084_probe, - .remove = mmcc_apq8084_remove, .driver = { .name = "mmcc-apq8084", .of_match_table = mmcc_apq8084_match_table, diff --git a/drivers/clk/qcom/mmcc-msm8960.c b/drivers/clk/qcom/mmcc-msm8960.c index bad02aebf..00e36192a 100644 --- a/drivers/clk/qcom/mmcc-msm8960.c +++ b/drivers/clk/qcom/mmcc-msm8960.c @@ -41,6 +41,10 @@ enum { P_PLL3, P_PLL15, P_HDMI_PLL, + P_DSI1_PLL_DSICLK, + P_DSI2_PLL_DSICLK, + P_DSI1_PLL_BYTECLK, + P_DSI2_PLL_BYTECLK, }; #define F_MN(f, s, _m, _n) { .freq = f, .src = s, .m = _m, .n = _n } @@ -85,6 +89,30 @@ static const char * const mmcc_pxo_pll8_pll2_pll3[] = { "pll3", }; +static const struct parent_map mmcc_pxo_dsi2_dsi1_map[] = { + { P_PXO, 0 }, + { P_DSI2_PLL_DSICLK, 1 }, + { P_DSI1_PLL_DSICLK, 3 }, +}; + +static const char * const mmcc_pxo_dsi2_dsi1[] = { + "pxo", + "dsi2pll", + "dsi1pll", +}; + +static const struct parent_map mmcc_pxo_dsi1_dsi2_byte_map[] = { + { P_PXO, 0 }, + { P_DSI1_PLL_BYTECLK, 1 }, + { P_DSI2_PLL_BYTECLK, 2 }, +}; + +static const char * const mmcc_pxo_dsi1_dsi2_byte[] = { + "pxo", + "dsi1pllbyte", + "dsi2pllbyte", +}; + static struct clk_pll pll2 = { .l_reg = 0x320, .m_reg = 0x324, @@ -2042,6 +2070,350 @@ static struct clk_branch dsi2_s_ahb_clk = { }, }; +static struct clk_rcg dsi1_src = { + .ns_reg = 0x0054, + .md_reg = 0x0050, + .mn = { + .mnctr_en_bit = 5, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 6, + .n_val_shift = 24, + .m_val_shift = 8, + .width = 8, + }, + .p = { + .pre_div_shift = 14, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = mmcc_pxo_dsi2_dsi1_map, + }, + .clkr = { + .enable_reg = 0x004c, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "dsi1_src", + .parent_names = mmcc_pxo_dsi2_dsi1, + .num_parents = 3, + .ops = &clk_rcg_bypass2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_branch dsi1_clk = { + .halt_reg = 0x01d0, + .halt_bit = 2, + .clkr = { + .enable_reg = 0x004c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "dsi1_clk", + .parent_names = (const char *[]){ "dsi1_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg dsi2_src = { + .ns_reg = 0x012c, + .md_reg = 0x00a8, + .mn = { + .mnctr_en_bit = 5, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 6, + .n_val_shift = 24, + .m_val_shift = 8, + .width = 8, + }, + .p = { + .pre_div_shift = 14, + .pre_div_width = 2, + }, + .s = { + .src_sel_shift = 0, + .parent_map = mmcc_pxo_dsi2_dsi1_map, + }, + .clkr = { + .enable_reg = 0x003c, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "dsi2_src", + .parent_names = mmcc_pxo_dsi2_dsi1, + .num_parents = 3, + .ops = &clk_rcg_bypass2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_branch dsi2_clk = { + .halt_reg = 0x01d0, + .halt_bit = 20, + .clkr = { + .enable_reg = 0x003c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "dsi2_clk", + .parent_names = (const char *[]){ "dsi2_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg dsi1_byte_src = { + .ns_reg = 0x00b0, + .p = { + .pre_div_shift = 12, + .pre_div_width = 4, + }, + .s = { + .src_sel_shift = 0, + .parent_map = mmcc_pxo_dsi1_dsi2_byte_map, + }, + .clkr = { + .enable_reg = 0x0090, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "dsi1_byte_src", + .parent_names = mmcc_pxo_dsi1_dsi2_byte, + .num_parents = 3, + .ops = &clk_rcg_bypass2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_branch dsi1_byte_clk = { + .halt_reg = 0x01cc, + .halt_bit = 21, + .clkr = { + .enable_reg = 0x0090, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "dsi1_byte_clk", + .parent_names = (const char *[]){ "dsi1_byte_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg dsi2_byte_src = { + .ns_reg = 0x012c, + .p = { + .pre_div_shift = 12, + .pre_div_width = 4, + }, + .s = { + .src_sel_shift = 0, + .parent_map = mmcc_pxo_dsi1_dsi2_byte_map, + }, + .clkr = { + .enable_reg = 0x0130, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "dsi2_byte_src", + .parent_names = mmcc_pxo_dsi1_dsi2_byte, + .num_parents = 3, + .ops = &clk_rcg_bypass2_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_branch dsi2_byte_clk = { + .halt_reg = 0x01cc, + .halt_bit = 20, + .clkr = { + .enable_reg = 0x00b4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "dsi2_byte_clk", + .parent_names = (const char *[]){ "dsi2_byte_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg dsi1_esc_src = { + .ns_reg = 0x0011c, + .p = { + .pre_div_shift = 12, + .pre_div_width = 4, + }, + .s = { + .src_sel_shift = 0, + .parent_map = mmcc_pxo_dsi1_dsi2_byte_map, + }, + .clkr = { + .enable_reg = 0x00cc, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "dsi1_esc_src", + .parent_names = mmcc_pxo_dsi1_dsi2_byte, + .num_parents = 3, + .ops = &clk_rcg_esc_ops, + }, + }, +}; + +static struct clk_branch dsi1_esc_clk = { + .halt_reg = 0x01e8, + .halt_bit = 1, + .clkr = { + .enable_reg = 0x00cc, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "dsi1_esc_clk", + .parent_names = (const char *[]){ "dsi1_esc_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg dsi2_esc_src = { + .ns_reg = 0x0150, + .p = { + .pre_div_shift = 12, + .pre_div_width = 4, + }, + .s = { + .src_sel_shift = 0, + .parent_map = mmcc_pxo_dsi1_dsi2_byte_map, + }, + .clkr = { + .enable_reg = 0x013c, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "dsi2_esc_src", + .parent_names = mmcc_pxo_dsi1_dsi2_byte, + .num_parents = 3, + .ops = &clk_rcg_esc_ops, + }, + }, +}; + +static struct clk_branch dsi2_esc_clk = { + .halt_reg = 0x01e8, + .halt_bit = 3, + .clkr = { + .enable_reg = 0x013c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "dsi2_esc_clk", + .parent_names = (const char *[]){ "dsi2_esc_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg dsi1_pixel_src = { + .ns_reg = 0x0138, + .md_reg = 0x0134, + .mn = { + .mnctr_en_bit = 5, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 6, + .n_val_shift = 16, + .m_val_shift = 8, + .width = 8, + }, + .p = { + .pre_div_shift = 12, + .pre_div_width = 4, + }, + .s = { + .src_sel_shift = 0, + .parent_map = mmcc_pxo_dsi2_dsi1_map, + }, + .clkr = { + .enable_reg = 0x0130, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "dsi1_pixel_src", + .parent_names = mmcc_pxo_dsi2_dsi1, + .num_parents = 3, + .ops = &clk_rcg_pixel_ops, + }, + }, +}; + +static struct clk_branch dsi1_pixel_clk = { + .halt_reg = 0x01d0, + .halt_bit = 6, + .clkr = { + .enable_reg = 0x0130, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mdp_pclk1_clk", + .parent_names = (const char *[]){ "dsi1_pixel_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + +static struct clk_rcg dsi2_pixel_src = { + .ns_reg = 0x00e4, + .md_reg = 0x00b8, + .mn = { + .mnctr_en_bit = 5, + .mnctr_reset_bit = 7, + .mnctr_mode_shift = 6, + .n_val_shift = 16, + .m_val_shift = 8, + .width = 8, + }, + .p = { + .pre_div_shift = 12, + .pre_div_width = 4, + }, + .s = { + .src_sel_shift = 0, + .parent_map = mmcc_pxo_dsi2_dsi1_map, + }, + .clkr = { + .enable_reg = 0x0094, + .enable_mask = BIT(2), + .hw.init = &(struct clk_init_data){ + .name = "dsi2_pixel_src", + .parent_names = mmcc_pxo_dsi2_dsi1, + .num_parents = 3, + .ops = &clk_rcg_pixel_ops, + }, + }, +}; + +static struct clk_branch dsi2_pixel_clk = { + .halt_reg = 0x01d0, + .halt_bit = 19, + .clkr = { + .enable_reg = 0x0094, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "mdp_pclk2_clk", + .parent_names = (const char *[]){ "dsi2_pixel_src" }, + .num_parents = 1, + .ops = &clk_branch_ops, + .flags = CLK_SET_RATE_PARENT, + }, + }, +}; + static struct clk_branch gfx2d0_ahb_clk = { .hwcg_reg = 0x0038, .hwcg_bit = 28, @@ -2325,6 +2697,8 @@ static struct clk_regmap *mmcc_msm8960_clks[] = { [CSI2_SRC] = &csi2_src.clkr, [CSI2_CLK] = &csi2_clk.clkr, [CSI2_PHY_CLK] = &csi2_phy_clk.clkr, + [DSI_SRC] = &dsi1_src.clkr, + [DSI_CLK] = &dsi1_clk.clkr, [CSI_PIX_CLK] = &csi_pix_clk.clkr, [CSI_RDI_CLK] = &csi_rdi_clk.clkr, [MDP_VSYNC_CLK] = &mdp_vsync_clk.clkr, @@ -2345,6 +2719,18 @@ static struct clk_regmap *mmcc_msm8960_clks[] = { [MDP_SRC] = &mdp_src.clkr, [MDP_CLK] = &mdp_clk.clkr, [MDP_LUT_CLK] = &mdp_lut_clk.clkr, + [DSI2_PIXEL_SRC] = &dsi2_pixel_src.clkr, + [DSI2_PIXEL_CLK] = &dsi2_pixel_clk.clkr, + [DSI2_SRC] = &dsi2_src.clkr, + [DSI2_CLK] = &dsi2_clk.clkr, + [DSI1_BYTE_SRC] = &dsi1_byte_src.clkr, + [DSI1_BYTE_CLK] = &dsi1_byte_clk.clkr, + [DSI2_BYTE_SRC] = &dsi2_byte_src.clkr, + [DSI2_BYTE_CLK] = &dsi2_byte_clk.clkr, + [DSI1_ESC_SRC] = &dsi1_esc_src.clkr, + [DSI1_ESC_CLK] = &dsi1_esc_clk.clkr, + [DSI2_ESC_SRC] = &dsi2_esc_src.clkr, + [DSI2_ESC_CLK] = &dsi2_esc_clk.clkr, [ROT_SRC] = &rot_src.clkr, [ROT_CLK] = &rot_clk.clkr, [TV_ENC_CLK] = &tv_enc_clk.clkr, @@ -2359,6 +2745,8 @@ static struct clk_regmap *mmcc_msm8960_clks[] = { [VFE_CSI_CLK] = &vfe_csi_clk.clkr, [VPE_SRC] = &vpe_src.clkr, [VPE_CLK] = &vpe_clk.clkr, + [DSI_PIXEL_SRC] = &dsi1_pixel_src.clkr, + [DSI_PIXEL_CLK] = &dsi1_pixel_clk.clkr, [CAMCLK0_SRC] = &camclk0_src.clkr, [CAMCLK0_CLK] = &camclk0_clk.clkr, [CAMCLK1_SRC] = &camclk1_src.clkr, @@ -2490,6 +2878,8 @@ static struct clk_regmap *mmcc_apq8064_clks[] = { [CSI2_SRC] = &csi2_src.clkr, [CSI2_CLK] = &csi2_clk.clkr, [CSI2_PHY_CLK] = &csi2_phy_clk.clkr, + [DSI_SRC] = &dsi1_src.clkr, + [DSI_CLK] = &dsi1_clk.clkr, [CSI_PIX_CLK] = &csi_pix_clk.clkr, [CSI_RDI_CLK] = &csi_rdi_clk.clkr, [MDP_VSYNC_CLK] = &mdp_vsync_clk.clkr, @@ -2506,6 +2896,18 @@ static struct clk_regmap *mmcc_apq8064_clks[] = { [MDP_SRC] = &mdp_src.clkr, [MDP_CLK] = &mdp_clk.clkr, [MDP_LUT_CLK] = &mdp_lut_clk.clkr, + [DSI2_PIXEL_SRC] = &dsi2_pixel_src.clkr, + [DSI2_PIXEL_CLK] = &dsi2_pixel_clk.clkr, + [DSI2_SRC] = &dsi2_src.clkr, + [DSI2_CLK] = &dsi2_clk.clkr, + [DSI1_BYTE_SRC] = &dsi1_byte_src.clkr, + [DSI1_BYTE_CLK] = &dsi1_byte_clk.clkr, + [DSI2_BYTE_SRC] = &dsi2_byte_src.clkr, + [DSI2_BYTE_CLK] = &dsi2_byte_clk.clkr, + [DSI1_ESC_SRC] = &dsi1_esc_src.clkr, + [DSI1_ESC_CLK] = &dsi1_esc_clk.clkr, + [DSI2_ESC_SRC] = &dsi2_esc_src.clkr, + [DSI2_ESC_CLK] = &dsi2_esc_clk.clkr, [ROT_SRC] = &rot_src.clkr, [ROT_CLK] = &rot_clk.clkr, [TV_DAC_CLK] = &tv_dac_clk.clkr, @@ -2519,6 +2921,8 @@ static struct clk_regmap *mmcc_apq8064_clks[] = { [VFE_CSI_CLK] = &vfe_csi_clk.clkr, [VPE_SRC] = &vpe_src.clkr, [VPE_CLK] = &vpe_clk.clkr, + [DSI_PIXEL_SRC] = &dsi1_pixel_src.clkr, + [DSI_PIXEL_CLK] = &dsi1_pixel_clk.clkr, [CAMCLK0_SRC] = &camclk0_src.clkr, [CAMCLK0_CLK] = &camclk0_clk.clkr, [CAMCLK1_SRC] = &camclk1_src.clkr, @@ -2686,15 +3090,8 @@ static int mmcc_msm8960_probe(struct platform_device *pdev) return qcom_cc_really_probe(pdev, match->data, regmap); } -static int mmcc_msm8960_remove(struct platform_device *pdev) -{ - qcom_cc_remove(pdev); - return 0; -} - static struct platform_driver mmcc_msm8960_driver = { .probe = mmcc_msm8960_probe, - .remove = mmcc_msm8960_remove, .driver = { .name = "mmcc-msm8960", .of_match_table = mmcc_msm8960_match_table, diff --git a/drivers/clk/qcom/mmcc-msm8974.c b/drivers/clk/qcom/mmcc-msm8974.c index 0987bf443..9d790bcad 100644 --- a/drivers/clk/qcom/mmcc-msm8974.c +++ b/drivers/clk/qcom/mmcc-msm8974.c @@ -31,6 +31,7 @@ #include "clk-rcg.h" #include "clk-branch.h" #include "reset.h" +#include "gdsc.h" enum { P_XO, @@ -522,17 +523,11 @@ static struct clk_rcg2 jpeg2_clk_src = { }, }; -static struct freq_tbl pixel_freq_tbl[] = { - { .src = P_DSI0PLL }, - { } -}; - static struct clk_rcg2 pclk0_clk_src = { .cmd_rcgr = 0x2000, .mnd_width = 8, .hid_width = 5, .parent_map = mmcc_xo_dsi_hdmi_edp_gpll0_map, - .freq_tbl = pixel_freq_tbl, .clkr.hw.init = &(struct clk_init_data){ .name = "pclk0_clk_src", .parent_names = mmcc_xo_dsi_hdmi_edp_gpll0, @@ -547,7 +542,6 @@ static struct clk_rcg2 pclk1_clk_src = { .mnd_width = 8, .hid_width = 5, .parent_map = mmcc_xo_dsi_hdmi_edp_gpll0_map, - .freq_tbl = pixel_freq_tbl, .clkr.hw.init = &(struct clk_init_data){ .name = "pclk1_clk_src", .parent_names = mmcc_xo_dsi_hdmi_edp_gpll0, @@ -785,7 +779,7 @@ static struct clk_rcg2 byte0_clk_src = { .name = "byte0_clk_src", .parent_names = mmcc_xo_dsibyte_hdmi_edp_gpll0, .num_parents = 6, - .ops = &clk_byte_ops, + .ops = &clk_byte2_ops, .flags = CLK_SET_RATE_PARENT, }, }; @@ -799,7 +793,7 @@ static struct clk_rcg2 byte1_clk_src = { .name = "byte1_clk_src", .parent_names = mmcc_xo_dsibyte_hdmi_edp_gpll0, .num_parents = 6, - .ops = &clk_byte_ops, + .ops = &clk_byte2_ops, .flags = CLK_SET_RATE_PARENT, }, }; @@ -2349,6 +2343,66 @@ static struct pll_config mmpll3_config = { .aux_output_mask = BIT(1), }; +static struct gdsc venus0_gdsc = { + .gdscr = 0x1024, + .cxcs = (unsigned int []){ 0x1028 }, + .cxc_count = 1, + .resets = (unsigned int []){ VENUS0_RESET }, + .reset_count = 1, + .pd = { + .name = "venus0", + }, + .pwrsts = PWRSTS_ON, +}; + +static struct gdsc mdss_gdsc = { + .gdscr = 0x2304, + .cxcs = (unsigned int []){ 0x231c, 0x2320 }, + .cxc_count = 2, + .pd = { + .name = "mdss", + }, + .pwrsts = PWRSTS_RET_ON, +}; + +static struct gdsc camss_jpeg_gdsc = { + .gdscr = 0x35a4, + .cxcs = (unsigned int []){ 0x35a8, 0x35ac, 0x35b0 }, + .cxc_count = 3, + .pd = { + .name = "camss_jpeg", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc camss_vfe_gdsc = { + .gdscr = 0x36a4, + .cxcs = (unsigned int []){ 0x36a8, 0x36ac, 0x3704, 0x3714, 0x36b0 }, + .cxc_count = 5, + .pd = { + .name = "camss_vfe", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc oxili_gdsc = { + .gdscr = 0x4024, + .cxcs = (unsigned int []){ 0x4028 }, + .cxc_count = 1, + .pd = { + .name = "oxili", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + +static struct gdsc oxilicx_gdsc = { + .gdscr = 0x4034, + .pd = { + .name = "oxilicx", + }, + .pwrsts = PWRSTS_OFF_ON, +}; + static struct clk_regmap *mmcc_msm8974_clocks[] = { [MMSS_AHB_CLK_SRC] = &mmss_ahb_clk_src.clkr, [MMSS_AXI_CLK_SRC] = &mmss_axi_clk_src.clkr, @@ -2525,6 +2579,15 @@ static const struct qcom_reset_map mmcc_msm8974_resets[] = { [OCMEMNOC_RESET] = { 0x50b0 }, }; +static struct gdsc *mmcc_msm8974_gdscs[] = { + [VENUS0_GDSC] = &venus0_gdsc, + [MDSS_GDSC] = &mdss_gdsc, + [CAMSS_JPEG_GDSC] = &camss_jpeg_gdsc, + [CAMSS_VFE_GDSC] = &camss_vfe_gdsc, + [OXILI_GDSC] = &oxili_gdsc, + [OXILICX_GDSC] = &oxilicx_gdsc, +}; + static const struct regmap_config mmcc_msm8974_regmap_config = { .reg_bits = 32, .reg_stride = 4, @@ -2539,6 +2602,8 @@ static const struct qcom_cc_desc mmcc_msm8974_desc = { .num_clks = ARRAY_SIZE(mmcc_msm8974_clocks), .resets = mmcc_msm8974_resets, .num_resets = ARRAY_SIZE(mmcc_msm8974_resets), + .gdscs = mmcc_msm8974_gdscs, + .num_gdscs = ARRAY_SIZE(mmcc_msm8974_gdscs), }; static const struct of_device_id mmcc_msm8974_match_table[] = { @@ -2550,6 +2615,7 @@ MODULE_DEVICE_TABLE(of, mmcc_msm8974_match_table); static int mmcc_msm8974_probe(struct platform_device *pdev) { struct regmap *regmap; + int ret; regmap = qcom_cc_map(pdev, &mmcc_msm8974_desc); if (IS_ERR(regmap)) @@ -2558,12 +2624,16 @@ static int mmcc_msm8974_probe(struct platform_device *pdev) clk_pll_configure_sr_hpm_lp(&mmpll1, regmap, &mmpll1_config, true); clk_pll_configure_sr_hpm_lp(&mmpll3, regmap, &mmpll3_config, false); - return qcom_cc_really_probe(pdev, &mmcc_msm8974_desc, regmap); + ret = qcom_cc_really_probe(pdev, &mmcc_msm8974_desc, regmap); + if (ret) + return ret; + + return pm_genpd_add_subdomain(&oxili_gdsc.pd, &oxilicx_gdsc.pd); } static int mmcc_msm8974_remove(struct platform_device *pdev) { - qcom_cc_remove(pdev); + pm_genpd_remove_subdomain(&oxili_gdsc.pd, &oxilicx_gdsc.pd); return 0; } |