diff options
Diffstat (limited to 'drivers/clk/qcom')
-rw-r--r-- | drivers/clk/qcom/Kconfig | 4 | ||||
-rw-r--r-- | drivers/clk/qcom/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/qcom/clk-rcg.h | 3 | ||||
-rw-r--r-- | drivers/clk/qcom/clk-rcg2.c | 304 | ||||
-rw-r--r-- | drivers/clk/qcom/common.c | 101 | ||||
-rw-r--r-- | drivers/clk/qcom/common.h | 34 | ||||
-rw-r--r-- | drivers/clk/qcom/gcc-msm8660.c | 77 | ||||
-rw-r--r-- | drivers/clk/qcom/gcc-msm8960.c | 109 | ||||
-rw-r--r-- | drivers/clk/qcom/gcc-msm8974.c | 207 | ||||
-rw-r--r-- | drivers/clk/qcom/mmcc-msm8960.c | 78 | ||||
-rw-r--r-- | drivers/clk/qcom/mmcc-msm8974.c | 198 |
11 files changed, 705 insertions, 411 deletions
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 995bcfa..7f696b7 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -13,10 +13,10 @@ config MSM_GCC_8660 i2c, USB, SD/eMMC, etc. config MSM_GCC_8960 - tristate "MSM8960 Global Clock Controller" + tristate "APQ8064/MSM8960 Global Clock Controller" depends on COMMON_CLK_QCOM help - Support for the global clock controller on msm8960 devices. + Support for the global clock controller on apq8064/msm8960 devices. Say Y if you want to use peripheral devices such as UART, SPI, i2c, USB, SD/eMMC, SATA, PCIe, etc. diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index f60db2e..689e05b 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -1,5 +1,6 @@ obj-$(CONFIG_COMMON_CLK_QCOM) += clk-qcom.o +clk-qcom-y += common.o clk-qcom-y += clk-regmap.o clk-qcom-y += clk-pll.o clk-qcom-y += clk-rcg.o diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h index 1d6b6de..b9ec11d 100644 --- a/drivers/clk/qcom/clk-rcg.h +++ b/drivers/clk/qcom/clk-rcg.h @@ -155,5 +155,8 @@ struct clk_rcg2 { #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_edp_pixel_ops; +extern const struct clk_ops clk_byte_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 00f878a..cd185d5 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -19,6 +19,7 @@ #include <linux/clk-provider.h> #include <linux/delay.h> #include <linux/regmap.h> +#include <linux/math64.h> #include <asm/div64.h> @@ -55,7 +56,7 @@ static int clk_rcg2_is_enabled(struct clk_hw *hw) if (ret) return ret; - return (cmd & CMD_ROOT_OFF) != 0; + return (cmd & CMD_ROOT_OFF) == 0; } static u8 clk_rcg2_get_parent(struct clk_hw *hw) @@ -181,7 +182,8 @@ struct freq_tbl *find_freq(const struct freq_tbl *f, unsigned long rate) if (rate <= f->freq) return f; - return NULL; + /* Default to our fastest rate */ + return f - 1; } static long _freq_tbl_determine_rate(struct clk_hw *hw, @@ -224,31 +226,25 @@ static long clk_rcg2_determine_rate(struct clk_hw *hw, unsigned long rate, return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, p_rate, p); } -static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate) +static int clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f) { - struct clk_rcg2 *rcg = to_clk_rcg2(hw); - const struct freq_tbl *f; u32 cfg, mask; int ret; - f = find_freq(rcg->freq_tbl, rate); - if (!f) - return -EINVAL; - if (rcg->mnd_width && f->n) { mask = BIT(rcg->mnd_width) - 1; - ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + M_REG, - mask, f->m); + ret = regmap_update_bits(rcg->clkr.regmap, + rcg->cmd_rcgr + M_REG, mask, f->m); if (ret) return ret; - ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + N_REG, - mask, ~(f->n - f->m)); + ret = regmap_update_bits(rcg->clkr.regmap, + rcg->cmd_rcgr + N_REG, mask, ~(f->n - f->m)); if (ret) return ret; - ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + D_REG, - mask, ~f->n); + ret = regmap_update_bits(rcg->clkr.regmap, + rcg->cmd_rcgr + D_REG, mask, ~f->n); if (ret) return ret; } @@ -259,14 +255,26 @@ static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate) cfg |= rcg->parent_map[f->src] << CFG_SRC_SEL_SHIFT; if (rcg->mnd_width && f->n) cfg |= CFG_MODE_DUAL_EDGE; - ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, mask, - cfg); + ret = regmap_update_bits(rcg->clkr.regmap, + rcg->cmd_rcgr + CFG_REG, mask, cfg); if (ret) return ret; return update_config(rcg); } +static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + const struct freq_tbl *f; + + f = find_freq(rcg->freq_tbl, rate); + if (!f) + return -EINVAL; + + return clk_rcg2_configure(rcg, f); +} + static int clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { @@ -289,3 +297,265 @@ const struct clk_ops clk_rcg2_ops = { .set_rate_and_parent = clk_rcg2_set_rate_and_parent, }; EXPORT_SYMBOL_GPL(clk_rcg2_ops); + +struct frac_entry { + int num; + int den; +}; + +static const struct frac_entry frac_table_675m[] = { /* link rate of 270M */ + { 52, 295 }, /* 119 M */ + { 11, 57 }, /* 130.25 M */ + { 63, 307 }, /* 138.50 M */ + { 11, 50 }, /* 148.50 M */ + { 47, 206 }, /* 154 M */ + { 31, 100 }, /* 205.25 M */ + { 107, 269 }, /* 268.50 M */ + { }, +}; + +static struct frac_entry frac_table_810m[] = { /* Link rate of 162M */ + { 31, 211 }, /* 119 M */ + { 32, 199 }, /* 130.25 M */ + { 63, 307 }, /* 138.50 M */ + { 11, 60 }, /* 148.50 M */ + { 50, 263 }, /* 154 M */ + { 31, 120 }, /* 205.25 M */ + { 119, 359 }, /* 268.50 M */ + { }, +}; + +static int clk_edp_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; + const struct frac_entry *frac; + int delta = 100000; + s64 src_rate = parent_rate; + s64 request; + u32 mask = BIT(rcg->hid_width) - 1; + u32 hid_div; + + if (src_rate == 810000000) + frac = frac_table_810m; + else + frac = frac_table_675m; + + for (; frac->num; frac++) { + request = rate; + request *= frac->den; + request = div_s64(request, frac->num); + if ((src_rate < (request - delta)) || + (src_rate > (request + delta))) + continue; + + regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, + &hid_div); + f.pre_div = hid_div; + f.pre_div >>= CFG_SRC_DIV_SHIFT; + f.pre_div &= mask; + f.m = frac->num; + f.n = frac->den; + + return clk_rcg2_configure(rcg, &f); + } + + return -EINVAL; +} + +static int clk_edp_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_edp_pixel_set_rate(hw, rate, parent_rate); +} + +static long clk_edp_pixel_determine_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *p_rate, struct clk **p) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + const struct freq_tbl *f = rcg->freq_tbl; + const struct frac_entry *frac; + int delta = 100000; + s64 src_rate = *p_rate; + s64 request; + u32 mask = BIT(rcg->hid_width) - 1; + u32 hid_div; + + /* Force the correct parent */ + *p = clk_get_parent_by_index(hw->clk, f->src); + + if (src_rate == 810000000) + frac = frac_table_810m; + else + frac = frac_table_675m; + + for (; frac->num; frac++) { + request = rate; + request *= frac->den; + request = div_s64(request, frac->num); + if ((src_rate < (request - delta)) || + (src_rate > (request + delta))) + continue; + + regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, + &hid_div); + hid_div >>= CFG_SRC_DIV_SHIFT; + hid_div &= mask; + + return calc_rate(src_rate, frac->num, frac->den, !!frac->den, + hid_div); + } + + return -EINVAL; +} + +const struct clk_ops clk_edp_pixel_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_edp_pixel_set_rate, + .set_rate_and_parent = clk_edp_pixel_set_rate_and_parent, + .determine_rate = clk_edp_pixel_determine_rate, +}; +EXPORT_SYMBOL_GPL(clk_edp_pixel_ops); + +static long clk_byte_determine_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *p_rate, struct clk **p) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + const struct freq_tbl *f = rcg->freq_tbl; + unsigned long parent_rate, div; + u32 mask = BIT(rcg->hid_width) - 1; + + if (rate == 0) + return -EINVAL; + + *p = clk_get_parent_by_index(hw->clk, f->src); + *p_rate = parent_rate = __clk_round_rate(*p, rate); + + div = DIV_ROUND_UP((2 * parent_rate), rate) - 1; + div = min_t(u32, div, mask); + + return calc_rate(parent_rate, 0, 0, 0, div); +} + +static int clk_byte_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; + unsigned long div; + u32 mask = BIT(rcg->hid_width) - 1; + + div = DIV_ROUND_UP((2 * parent_rate), rate) - 1; + div = min_t(u32, div, mask); + + f.pre_div = div; + + return clk_rcg2_configure(rcg, &f); +} + +static int clk_byte_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_byte_set_rate(hw, rate, parent_rate); +} + +const struct clk_ops clk_byte_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_byte_set_rate, + .set_rate_and_parent = clk_byte_set_rate_and_parent, + .determine_rate = clk_byte_determine_rate, +}; +EXPORT_SYMBOL_GPL(clk_byte_ops); + +static const struct frac_entry frac_table_pixel[] = { + { 3, 8 }, + { 2, 9 }, + { 4, 9 }, + { 1, 1 }, + { } +}; + +static long clk_pixel_determine_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *p_rate, struct clk **p) +{ + 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; + struct clk *parent = *p = clk_get_parent_by_index(hw->clk, f->src); + + for (; frac->num; frac++) { + request = (rate * frac->den) / frac->num; + + src_rate = __clk_round_rate(parent, request); + if ((src_rate < (request - delta)) || + (src_rate > (request + delta))) + continue; + + *p_rate = src_rate; + return (src_rate * frac->num) / frac->den; + } + + return -EINVAL; +} + +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; + const struct frac_entry *frac = frac_table_pixel; + unsigned long request, src_rate; + int delta = 100000; + u32 mask = BIT(rcg->hid_width) - 1; + u32 hid_div; + struct clk *parent = clk_get_parent_by_index(hw->clk, f.src); + + for (; frac->num; frac++) { + request = (rate * frac->den) / frac->num; + + src_rate = __clk_round_rate(parent, request); + if ((src_rate < (request - delta)) || + (src_rate > (request + delta))) + continue; + + regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, + &hid_div); + f.pre_div = hid_div; + f.pre_div >>= CFG_SRC_DIV_SHIFT; + f.pre_div &= mask; + f.m = frac->num; + f.n = frac->den; + + return clk_rcg2_configure(rcg, &f); + } + return -EINVAL; +} + +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); +} + +const struct clk_ops clk_pixel_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_pixel_set_rate, + .set_rate_and_parent = clk_pixel_set_rate_and_parent, + .determine_rate = clk_pixel_determine_rate, +}; +EXPORT_SYMBOL_GPL(clk_pixel_ops); diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c new file mode 100644 index 0000000..9b5a1cf --- /dev/null +++ b/drivers/clk/qcom/common.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2013-2014, 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 + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/export.h> +#include <linux/regmap.h> +#include <linux/platform_device.h> +#include <linux/clk-provider.h> +#include <linux/reset-controller.h> + +#include "common.h" +#include "clk-regmap.h" +#include "reset.h" + +struct qcom_cc { + struct qcom_reset_controller reset; + struct clk_onecell_data data; + struct clk *clks[]; +}; + +int qcom_cc_probe(struct platform_device *pdev, const struct qcom_cc_desc *desc) +{ + void __iomem *base; + struct resource *res; + int i, ret; + struct device *dev = &pdev->dev; + struct clk *clk; + struct clk_onecell_data *data; + struct clk **clks; + struct regmap *regmap; + struct qcom_reset_controller *reset; + struct qcom_cc *cc; + size_t num_clks = desc->num_clks; + struct clk_regmap **rclks = desc->clks; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + regmap = devm_regmap_init_mmio(dev, base, desc->config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks, + GFP_KERNEL); + if (!cc) + return -ENOMEM; + + clks = cc->clks; + data = &cc->data; + data->clks = clks; + data->clk_num = num_clks; + + for (i = 0; i < num_clks; i++) { + if (!rclks[i]) { + clks[i] = ERR_PTR(-ENOENT); + continue; + } + clk = devm_clk_register_regmap(dev, rclks[i]); + if (IS_ERR(clk)) + return PTR_ERR(clk); + clks[i] = clk; + } + + ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data); + if (ret) + return ret; + + reset = &cc->reset; + reset->rcdev.of_node = dev->of_node; + reset->rcdev.ops = &qcom_reset_ops; + reset->rcdev.owner = dev->driver->owner; + 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; +} +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); diff --git a/drivers/clk/qcom/common.h b/drivers/clk/qcom/common.h new file mode 100644 index 0000000..2c3cfc8 --- /dev/null +++ b/drivers/clk/qcom/common.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014, 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 + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef __QCOM_CLK_COMMON_H__ +#define __QCOM_CLK_COMMON_H__ + +struct platform_device; +struct regmap_config; +struct clk_regmap; +struct qcom_reset_map; + +struct qcom_cc_desc { + const struct regmap_config *config; + struct clk_regmap **clks; + size_t num_clks; + const struct qcom_reset_map *resets; + size_t num_resets; +}; + +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-msm8660.c b/drivers/clk/qcom/gcc-msm8660.c index bc0b7f1..0c4b727 100644 --- a/drivers/clk/qcom/gcc-msm8660.c +++ b/drivers/clk/qcom/gcc-msm8660.c @@ -25,6 +25,7 @@ #include <dt-bindings/clock/qcom,gcc-msm8660.h> #include <dt-bindings/reset/qcom,gcc-msm8660.h> +#include "common.h" #include "clk-regmap.h" #include "clk-pll.h" #include "clk-rcg.h" @@ -2701,51 +2702,24 @@ static const struct regmap_config gcc_msm8660_regmap_config = { .fast_io = true, }; +static const struct qcom_cc_desc gcc_msm8660_desc = { + .config = &gcc_msm8660_regmap_config, + .clks = gcc_msm8660_clks, + .num_clks = ARRAY_SIZE(gcc_msm8660_clks), + .resets = gcc_msm8660_resets, + .num_resets = ARRAY_SIZE(gcc_msm8660_resets), +}; + static const struct of_device_id gcc_msm8660_match_table[] = { { .compatible = "qcom,gcc-msm8660" }, { } }; MODULE_DEVICE_TABLE(of, gcc_msm8660_match_table); -struct qcom_cc { - struct qcom_reset_controller reset; - struct clk_onecell_data data; - struct clk *clks[]; -}; - static int gcc_msm8660_probe(struct platform_device *pdev) { - void __iomem *base; - struct resource *res; - int i, ret; - struct device *dev = &pdev->dev; struct clk *clk; - struct clk_onecell_data *data; - struct clk **clks; - struct regmap *regmap; - size_t num_clks; - struct qcom_reset_controller *reset; - struct qcom_cc *cc; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(dev, res); - if (IS_ERR(base)) - return PTR_ERR(base); - - regmap = devm_regmap_init_mmio(dev, base, &gcc_msm8660_regmap_config); - if (IS_ERR(regmap)) - return PTR_ERR(regmap); - - num_clks = ARRAY_SIZE(gcc_msm8660_clks); - cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks, - GFP_KERNEL); - if (!cc) - return -ENOMEM; - - clks = cc->clks; - data = &cc->data; - data->clks = clks; - data->clk_num = num_clks; + struct device *dev = &pdev->dev; /* Temporary until RPM clocks supported */ clk = clk_register_fixed_rate(dev, "cxo", NULL, CLK_IS_ROOT, 19200000); @@ -2756,39 +2730,12 @@ static int gcc_msm8660_probe(struct platform_device *pdev) if (IS_ERR(clk)) return PTR_ERR(clk); - for (i = 0; i < num_clks; i++) { - if (!gcc_msm8660_clks[i]) - continue; - clk = devm_clk_register_regmap(dev, gcc_msm8660_clks[i]); - if (IS_ERR(clk)) - return PTR_ERR(clk); - clks[i] = clk; - } - - ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data); - if (ret) - return ret; - - reset = &cc->reset; - reset->rcdev.of_node = dev->of_node; - reset->rcdev.ops = &qcom_reset_ops, - reset->rcdev.owner = THIS_MODULE, - reset->rcdev.nr_resets = ARRAY_SIZE(gcc_msm8660_resets), - reset->regmap = regmap; - reset->reset_map = gcc_msm8660_resets, - platform_set_drvdata(pdev, &reset->rcdev); - - ret = reset_controller_register(&reset->rcdev); - if (ret) - of_clk_del_provider(dev->of_node); - - return ret; + return qcom_cc_probe(pdev, &gcc_msm8660_desc); } static int gcc_msm8660_remove(struct platform_device *pdev) { - of_clk_del_provider(pdev->dev.of_node); - reset_controller_unregister(platform_get_drvdata(pdev)); + qcom_cc_remove(pdev); return 0; } diff --git a/drivers/clk/qcom/gcc-msm8960.c b/drivers/clk/qcom/gcc-msm8960.c index fd446ab..f4ffd91 100644 --- a/drivers/clk/qcom/gcc-msm8960.c +++ b/drivers/clk/qcom/gcc-msm8960.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2014, 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 @@ -25,6 +25,7 @@ #include <dt-bindings/clock/qcom,gcc-msm8960.h> #include <dt-bindings/reset/qcom,gcc-msm8960.h> +#include "common.h" #include "clk-regmap.h" #include "clk-pll.h" #include "clk-rcg.h" @@ -2809,7 +2810,7 @@ static const struct qcom_reset_map gcc_msm8960_resets[] = { [PPSS_PROC_RESET] = { 0x2594, 1 }, [PPSS_RESET] = { 0x2594}, [DMA_BAM_RESET] = { 0x25c0, 7 }, - [SIC_TIC_RESET] = { 0x2600, 7 }, + [SPS_TIC_H_RESET] = { 0x2600, 7 }, [SLIMBUS_H_RESET] = { 0x2620, 7 }, [SFAB_CFPB_M_RESET] = { 0x2680, 7 }, [SFAB_CFPB_S_RESET] = { 0x26c0, 7 }, @@ -2822,7 +2823,7 @@ static const struct qcom_reset_map gcc_msm8960_resets[] = { [SFAB_SFPB_M_RESET] = { 0x2780, 7 }, [SFAB_SFPB_S_RESET] = { 0x27a0, 7 }, [RPM_PROC_RESET] = { 0x27c0, 7 }, - [PMIC_SSBI2_RESET] = { 0x270c, 12 }, + [PMIC_SSBI2_RESET] = { 0x280c, 12 }, [SDC1_RESET] = { 0x2830 }, [SDC2_RESET] = { 0x2850 }, [SDC3_RESET] = { 0x2870 }, @@ -2867,6 +2868,16 @@ static const struct qcom_reset_map gcc_msm8960_resets[] = { [RIVA_RESET] = { 0x35e0 }, }; +static struct clk_regmap *gcc_apq8064_clks[] = { + [PLL8] = &pll8.clkr, + [PLL8_VOTE] = &pll8_vote, + [GSBI7_UART_SRC] = &gsbi7_uart_src.clkr, + [GSBI7_UART_CLK] = &gsbi7_uart_clk.clkr, + [GSBI7_QUP_SRC] = &gsbi7_qup_src.clkr, + [GSBI7_QUP_CLK] = &gsbi7_qup_clk.clkr, + [GSBI7_H_CLK] = &gsbi7_h_clk.clkr, +}; + static const struct regmap_config gcc_msm8960_regmap_config = { .reg_bits = 32, .reg_stride = 4, @@ -2875,51 +2886,38 @@ static const struct regmap_config gcc_msm8960_regmap_config = { .fast_io = true, }; +static const struct qcom_cc_desc gcc_msm8960_desc = { + .config = &gcc_msm8960_regmap_config, + .clks = gcc_msm8960_clks, + .num_clks = ARRAY_SIZE(gcc_msm8960_clks), + .resets = gcc_msm8960_resets, + .num_resets = ARRAY_SIZE(gcc_msm8960_resets), +}; + +static const struct qcom_cc_desc gcc_apq8064_desc = { + .config = &gcc_msm8960_regmap_config, + .clks = gcc_apq8064_clks, + .num_clks = ARRAY_SIZE(gcc_apq8064_clks), + .resets = gcc_msm8960_resets, + .num_resets = ARRAY_SIZE(gcc_msm8960_resets), +}; + static const struct of_device_id gcc_msm8960_match_table[] = { - { .compatible = "qcom,gcc-msm8960" }, + { .compatible = "qcom,gcc-msm8960", .data = &gcc_msm8960_desc }, + { .compatible = "qcom,gcc-apq8064", .data = &gcc_apq8064_desc }, { } }; MODULE_DEVICE_TABLE(of, gcc_msm8960_match_table); -struct qcom_cc { - struct qcom_reset_controller reset; - struct clk_onecell_data data; - struct clk *clks[]; -}; - static int gcc_msm8960_probe(struct platform_device *pdev) { - void __iomem *base; - struct resource *res; - int i, ret; - struct device *dev = &pdev->dev; struct clk *clk; - struct clk_onecell_data *data; - struct clk **clks; - struct regmap *regmap; - size_t num_clks; - struct qcom_reset_controller *reset; - struct qcom_cc *cc; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(dev, res); - if (IS_ERR(base)) - return PTR_ERR(base); - - regmap = devm_regmap_init_mmio(dev, base, &gcc_msm8960_regmap_config); - if (IS_ERR(regmap)) - return PTR_ERR(regmap); - - num_clks = ARRAY_SIZE(gcc_msm8960_clks); - cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks, - GFP_KERNEL); - if (!cc) - return -ENOMEM; - - clks = cc->clks; - data = &cc->data; - data->clks = clks; - data->clk_num = num_clks; + struct device *dev = &pdev->dev; + const struct of_device_id *match; + + match = of_match_device(gcc_msm8960_match_table, &pdev->dev); + if (!match) + return -EINVAL; /* Temporary until RPM clocks supported */ clk = clk_register_fixed_rate(dev, "cxo", NULL, CLK_IS_ROOT, 19200000); @@ -2930,39 +2928,12 @@ static int gcc_msm8960_probe(struct platform_device *pdev) if (IS_ERR(clk)) return PTR_ERR(clk); - for (i = 0; i < num_clks; i++) { - if (!gcc_msm8960_clks[i]) - continue; - clk = devm_clk_register_regmap(dev, gcc_msm8960_clks[i]); - if (IS_ERR(clk)) - return PTR_ERR(clk); - clks[i] = clk; - } - - ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data); - if (ret) - return ret; - - reset = &cc->reset; - reset->rcdev.of_node = dev->of_node; - reset->rcdev.ops = &qcom_reset_ops, - reset->rcdev.owner = THIS_MODULE, - reset->rcdev.nr_resets = ARRAY_SIZE(gcc_msm8960_resets), - reset->regmap = regmap; - reset->reset_map = gcc_msm8960_resets, - platform_set_drvdata(pdev, &reset->rcdev); - - ret = reset_controller_register(&reset->rcdev); - if (ret) - of_clk_del_provider(dev->of_node); - - return ret; + return qcom_cc_probe(pdev, match->data); } static int gcc_msm8960_remove(struct platform_device *pdev) { - of_clk_del_provider(pdev->dev.of_node); - reset_controller_unregister(platform_get_drvdata(pdev)); + qcom_cc_remove(pdev); return 0; } diff --git a/drivers/clk/qcom/gcc-msm8974.c b/drivers/clk/qcom/gcc-msm8974.c index 51d457e..7af7c18 100644 --- a/drivers/clk/qcom/gcc-msm8974.c +++ b/drivers/clk/qcom/gcc-msm8974.c @@ -25,6 +25,7 @@ #include <dt-bindings/clock/qcom,gcc-msm8974.h> #include <dt-bindings/reset/qcom,gcc-msm8974.h> +#include "common.h" #include "clk-regmap.h" #include "clk-pll.h" #include "clk-rcg.h" @@ -34,6 +35,7 @@ #define P_XO 0 #define P_GPLL0 1 #define P_GPLL1 1 +#define P_GPLL4 2 static const u8 gcc_xo_gpll0_map[] = { [P_XO] = 0, @@ -45,6 +47,18 @@ static const char *gcc_xo_gpll0[] = { "gpll0_vote", }; +static const u8 gcc_xo_gpll0_gpll4_map[] = { + [P_XO] = 0, + [P_GPLL0] = 1, + [P_GPLL4] = 5, +}; + +static const char *gcc_xo_gpll0_gpll4[] = { + "xo", + "gpll0_vote", + "gpll4_vote", +}; + #define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } static struct clk_pll gpll0 = { @@ -137,6 +151,33 @@ static struct clk_regmap gpll1_vote = { }, }; +static struct clk_pll gpll4 = { + .l_reg = 0x1dc4, + .m_reg = 0x1dc8, + .n_reg = 0x1dcc, + .config_reg = 0x1dd4, + .mode_reg = 0x1dc0, + .status_reg = 0x1ddc, + .status_bit = 17, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpll4", + .parent_names = (const char *[]){ "xo" }, + .num_parents = 1, + .ops = &clk_pll_ops, + }, +}; + +static struct clk_regmap gpll4_vote = { + .enable_reg = 0x1480, + .enable_mask = BIT(4), + .hw.init = &(struct clk_init_data){ + .name = "gpll4_vote", + .parent_names = (const char *[]){ "gpll4" }, + .num_parents = 1, + .ops = &clk_pll_vote_ops, + }, +}; + static const struct freq_tbl ftbl_gcc_usb30_master_clk[] = { F(125000000, P_GPLL0, 1, 5, 24), { } @@ -811,18 +852,33 @@ static const struct freq_tbl ftbl_gcc_sdcc1_4_apps_clk[] = { { } }; +static const struct freq_tbl ftbl_gcc_sdcc1_apps_clk_pro[] = { + F(144000, P_XO, 16, 3, 25), + F(400000, P_XO, 12, 1, 4), + F(20000000, P_GPLL0, 15, 1, 2), + F(25000000, P_GPLL0, 12, 1, 2), + F(50000000, P_GPLL0, 12, 0, 0), + F(100000000, P_GPLL0, 6, 0, 0), + F(192000000, P_GPLL4, 4, 0, 0), + F(200000000, P_GPLL0, 3, 0, 0), + F(384000000, P_GPLL4, 2, 0, 0), + { } +}; + +static struct clk_init_data sdcc1_apps_clk_src_init = { + .name = "sdcc1_apps_clk_src", + .parent_names = gcc_xo_gpll0, + .num_parents = 2, + .ops = &clk_rcg2_ops, +}; + static struct clk_rcg2 sdcc1_apps_clk_src = { .cmd_rcgr = 0x04d0, .mnd_width = 8, .hid_width = 5, .parent_map = gcc_xo_gpll0_map, .freq_tbl = ftbl_gcc_sdcc1_4_apps_clk, - .clkr.hw.init = &(struct clk_init_data){ - .name = "sdcc1_apps_clk_src", - .parent_names = gcc_xo_gpll0, - .num_parents = 2, - .ops = &clk_rcg2_ops, - }, + .clkr.hw.init = &sdcc1_apps_clk_src_init, }; static struct clk_rcg2 sdcc2_apps_clk_src = { @@ -1340,7 +1396,7 @@ static struct clk_branch gcc_blsp1_uart6_apps_clk = { }; static struct clk_branch gcc_blsp2_ahb_clk = { - .halt_reg = 0x05c4, + .halt_reg = 0x0944, .halt_check = BRANCH_HALT_VOTED, .clkr = { .enable_reg = 0x1484, @@ -1994,6 +2050,38 @@ static struct clk_branch gcc_sdcc1_apps_clk = { }, }; +static struct clk_branch gcc_sdcc1_cdccal_ff_clk = { + .halt_reg = 0x04e8, + .clkr = { + .enable_reg = 0x04e8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc1_cdccal_ff_clk", + .parent_names = (const char *[]){ + "xo" + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc1_cdccal_sleep_clk = { + .halt_reg = 0x04e4, + .clkr = { + .enable_reg = 0x04e4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc1_cdccal_sleep_clk", + .parent_names = (const char *[]){ + "sleep_clk_src" + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + static struct clk_branch gcc_sdcc2_ahb_clk = { .halt_reg = 0x0508, .clkr = { @@ -2483,6 +2571,10 @@ static struct clk_regmap *gcc_msm8974_clocks[] = { [GCC_USB_HSIC_IO_CAL_SLEEP_CLK] = &gcc_usb_hsic_io_cal_sleep_clk.clkr, [GCC_USB_HSIC_SYSTEM_CLK] = &gcc_usb_hsic_system_clk.clkr, [GCC_MMSS_GPLL0_CLK_SRC] = &gcc_mmss_gpll0_clk_src, + [GPLL4] = NULL, + [GPLL4_VOTE] = NULL, + [GCC_SDCC1_CDCCAL_SLEEP_CLK] = NULL, + [GCC_SDCC1_CDCCAL_FF_CLK] = NULL, }; static const struct qcom_reset_map gcc_msm8974_resets[] = { @@ -2574,51 +2666,51 @@ static const struct regmap_config gcc_msm8974_regmap_config = { .fast_io = true, }; +static const struct qcom_cc_desc gcc_msm8974_desc = { + .config = &gcc_msm8974_regmap_config, + .clks = gcc_msm8974_clocks, + .num_clks = ARRAY_SIZE(gcc_msm8974_clocks), + .resets = gcc_msm8974_resets, + .num_resets = ARRAY_SIZE(gcc_msm8974_resets), +}; + static const struct of_device_id gcc_msm8974_match_table[] = { { .compatible = "qcom,gcc-msm8974" }, + { .compatible = "qcom,gcc-msm8974pro" , .data = (void *)1UL }, + { .compatible = "qcom,gcc-msm8974pro-ac", .data = (void *)1UL }, { } }; MODULE_DEVICE_TABLE(of, gcc_msm8974_match_table); -struct qcom_cc { - struct qcom_reset_controller reset; - struct clk_onecell_data data; - struct clk *clks[]; -}; +static void msm8974_pro_clock_override(void) +{ + sdcc1_apps_clk_src_init.parent_names = gcc_xo_gpll0_gpll4; + sdcc1_apps_clk_src_init.num_parents = 3; + sdcc1_apps_clk_src.freq_tbl = ftbl_gcc_sdcc1_apps_clk_pro; + sdcc1_apps_clk_src.parent_map = gcc_xo_gpll0_gpll4_map; + + gcc_msm8974_clocks[GPLL4] = &gpll4.clkr; + gcc_msm8974_clocks[GPLL4_VOTE] = &gpll4_vote; + gcc_msm8974_clocks[GCC_SDCC1_CDCCAL_SLEEP_CLK] = + &gcc_sdcc1_cdccal_sleep_clk.clkr; + gcc_msm8974_clocks[GCC_SDCC1_CDCCAL_FF_CLK] = + &gcc_sdcc1_cdccal_ff_clk.clkr; +} static int gcc_msm8974_probe(struct platform_device *pdev) { - void __iomem *base; - struct resource *res; - int i, ret; - struct device *dev = &pdev->dev; struct clk *clk; - struct clk_onecell_data *data; - struct clk **clks; - struct regmap *regmap; - size_t num_clks; - struct qcom_reset_controller *reset; - struct qcom_cc *cc; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(dev, res); - if (IS_ERR(base)) - return PTR_ERR(base); - - regmap = devm_regmap_init_mmio(dev, base, &gcc_msm8974_regmap_config); - if (IS_ERR(regmap)) - return PTR_ERR(regmap); - - num_clks = ARRAY_SIZE(gcc_msm8974_clocks); - cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks, - GFP_KERNEL); - if (!cc) - return -ENOMEM; - - clks = cc->clks; - data = &cc->data; - data->clks = clks; - data->clk_num = num_clks; + struct device *dev = &pdev->dev; + bool pro; + const struct of_device_id *id; + + id = of_match_device(gcc_msm8974_match_table, dev); + if (!id) + return -ENODEV; + pro = !!(id->data); + + if (pro) + msm8974_pro_clock_override(); /* Temporary until RPM clocks supported */ clk = clk_register_fixed_rate(dev, "xo", NULL, CLK_IS_ROOT, 19200000); @@ -2631,39 +2723,12 @@ static int gcc_msm8974_probe(struct platform_device *pdev) if (IS_ERR(clk)) return PTR_ERR(clk); - for (i = 0; i < num_clks; i++) { - if (!gcc_msm8974_clocks[i]) - continue; - clk = devm_clk_register_regmap(dev, gcc_msm8974_clocks[i]); - if (IS_ERR(clk)) - return PTR_ERR(clk); - clks[i] = clk; - } - - ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data); - if (ret) - return ret; - - reset = &cc->reset; - reset->rcdev.of_node = dev->of_node; - reset->rcdev.ops = &qcom_reset_ops, - reset->rcdev.owner = THIS_MODULE, - reset->rcdev.nr_resets = ARRAY_SIZE(gcc_msm8974_resets), - reset->regmap = regmap; - reset->reset_map = gcc_msm8974_resets, - platform_set_drvdata(pdev, &reset->rcdev); - - ret = reset_controller_register(&reset->rcdev); - if (ret) - of_clk_del_provider(dev->of_node); - - return ret; + return qcom_cc_probe(pdev, &gcc_msm8974_desc); } static int gcc_msm8974_remove(struct platform_device *pdev) { - of_clk_del_provider(pdev->dev.of_node); - reset_controller_unregister(platform_get_drvdata(pdev)); + qcom_cc_remove(pdev); return 0; } diff --git a/drivers/clk/qcom/mmcc-msm8960.c b/drivers/clk/qcom/mmcc-msm8960.c index f9b59c7..12f3c0b 100644 --- a/drivers/clk/qcom/mmcc-msm8960.c +++ b/drivers/clk/qcom/mmcc-msm8960.c @@ -26,6 +26,7 @@ #include <dt-bindings/clock/qcom,mmcc-msm8960.h> #include <dt-bindings/reset/qcom,mmcc-msm8960.h> +#include "common.h" #include "clk-regmap.h" #include "clk-pll.h" #include "clk-rcg.h" @@ -2222,85 +2223,28 @@ static const struct regmap_config mmcc_msm8960_regmap_config = { .fast_io = true, }; +static const struct qcom_cc_desc mmcc_msm8960_desc = { + .config = &mmcc_msm8960_regmap_config, + .clks = mmcc_msm8960_clks, + .num_clks = ARRAY_SIZE(mmcc_msm8960_clks), + .resets = mmcc_msm8960_resets, + .num_resets = ARRAY_SIZE(mmcc_msm8960_resets), +}; + static const struct of_device_id mmcc_msm8960_match_table[] = { { .compatible = "qcom,mmcc-msm8960" }, { } }; MODULE_DEVICE_TABLE(of, mmcc_msm8960_match_table); -struct qcom_cc { - struct qcom_reset_controller reset; - struct clk_onecell_data data; - struct clk *clks[]; -}; - static int mmcc_msm8960_probe(struct platform_device *pdev) { - void __iomem *base; - struct resource *res; - int i, ret; - struct device *dev = &pdev->dev; - struct clk *clk; - struct clk_onecell_data *data; - struct clk **clks; - struct regmap *regmap; - size_t num_clks; - struct qcom_reset_controller *reset; - struct qcom_cc *cc; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(dev, res); - if (IS_ERR(base)) - return PTR_ERR(base); - - regmap = devm_regmap_init_mmio(dev, base, &mmcc_msm8960_regmap_config); - if (IS_ERR(regmap)) - return PTR_ERR(regmap); - - num_clks = ARRAY_SIZE(mmcc_msm8960_clks); - cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks, - GFP_KERNEL); - if (!cc) - return -ENOMEM; - - clks = cc->clks; - data = &cc->data; - data->clks = clks; - data->clk_num = num_clks; - - for (i = 0; i < num_clks; i++) { - if (!mmcc_msm8960_clks[i]) - continue; - clk = devm_clk_register_regmap(dev, mmcc_msm8960_clks[i]); - if (IS_ERR(clk)) - return PTR_ERR(clk); - clks[i] = clk; - } - - ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data); - if (ret) - return ret; - - reset = &cc->reset; - reset->rcdev.of_node = dev->of_node; - reset->rcdev.ops = &qcom_reset_ops, - reset->rcdev.owner = THIS_MODULE, - reset->rcdev.nr_resets = ARRAY_SIZE(mmcc_msm8960_resets), - reset->regmap = regmap; - reset->reset_map = mmcc_msm8960_resets, - platform_set_drvdata(pdev, &reset->rcdev); - - ret = reset_controller_register(&reset->rcdev); - if (ret) - of_clk_del_provider(dev->of_node); - - return ret; + return qcom_cc_probe(pdev, &mmcc_msm8960_desc); } static int mmcc_msm8960_remove(struct platform_device *pdev) { - of_clk_del_provider(pdev->dev.of_node); - reset_controller_unregister(platform_get_drvdata(pdev)); + qcom_cc_remove(pdev); return 0; } diff --git a/drivers/clk/qcom/mmcc-msm8974.c b/drivers/clk/qcom/mmcc-msm8974.c index c957745..c65b905 100644 --- a/drivers/clk/qcom/mmcc-msm8974.c +++ b/drivers/clk/qcom/mmcc-msm8974.c @@ -25,6 +25,7 @@ #include <dt-bindings/clock/qcom,mmcc-msm8974.h> #include <dt-bindings/reset/qcom,mmcc-msm8974.h> +#include "common.h" #include "clk-regmap.h" #include "clk-pll.h" #include "clk-rcg.h" @@ -40,9 +41,11 @@ #define P_EDPVCO 3 #define P_GPLL1 4 #define P_DSI0PLL 4 +#define P_DSI0PLL_BYTE 4 #define P_MMPLL2 4 #define P_MMPLL3 4 #define P_DSI1PLL 5 +#define P_DSI1PLL_BYTE 5 static const u8 mmcc_xo_mmpll0_mmpll1_gpll0_map[] = { [P_XO] = 0, @@ -160,6 +163,24 @@ static const char *mmcc_xo_dsi_hdmi_edp_gpll0[] = { "dsi1pll", }; +static const u8 mmcc_xo_dsibyte_hdmi_edp_gpll0_map[] = { + [P_XO] = 0, + [P_EDPLINK] = 4, + [P_HDMIPLL] = 3, + [P_GPLL0] = 5, + [P_DSI0PLL_BYTE] = 1, + [P_DSI1PLL_BYTE] = 2, +}; + +static const char *mmcc_xo_dsibyte_hdmi_edp_gpll0[] = { + "xo", + "edp_link_clk", + "hdmipll", + "gpll0_vote", + "dsi0pllbyte", + "dsi1pllbyte", +}; + #define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } static struct clk_pll mmpll0 = { @@ -169,6 +190,7 @@ static struct clk_pll mmpll0 = { .config_reg = 0x0014, .mode_reg = 0x0000, .status_reg = 0x001c, + .status_bit = 17, .clkr.hw.init = &(struct clk_init_data){ .name = "mmpll0", .parent_names = (const char *[]){ "xo" }, @@ -192,9 +214,10 @@ static struct clk_pll mmpll1 = { .l_reg = 0x0044, .m_reg = 0x0048, .n_reg = 0x004c, - .config_reg = 0x0054, + .config_reg = 0x0050, .mode_reg = 0x0040, .status_reg = 0x005c, + .status_bit = 17, .clkr.hw.init = &(struct clk_init_data){ .name = "mmpll1", .parent_names = (const char *[]){ "xo" }, @@ -218,7 +241,7 @@ static struct clk_pll mmpll2 = { .l_reg = 0x4104, .m_reg = 0x4108, .n_reg = 0x410c, - .config_reg = 0x4114, + .config_reg = 0x4110, .mode_reg = 0x4100, .status_reg = 0x411c, .clkr.hw.init = &(struct clk_init_data){ @@ -233,9 +256,10 @@ static struct clk_pll mmpll3 = { .l_reg = 0x0084, .m_reg = 0x0088, .n_reg = 0x008c, - .config_reg = 0x0094, + .config_reg = 0x0090, .mode_reg = 0x0080, .status_reg = 0x009c, + .status_bit = 17, .clkr.hw.init = &(struct clk_init_data){ .name = "mmpll3", .parent_names = (const char *[]){ "xo" }, @@ -496,15 +520,8 @@ static struct clk_rcg2 jpeg2_clk_src = { }, }; -static struct freq_tbl ftbl_mdss_pclk0_clk[] = { - F(125000000, P_DSI0PLL, 2, 0, 0), - F(250000000, P_DSI0PLL, 1, 0, 0), - { } -}; - -static struct freq_tbl ftbl_mdss_pclk1_clk[] = { - F(125000000, P_DSI1PLL, 2, 0, 0), - F(250000000, P_DSI1PLL, 1, 0, 0), +static struct freq_tbl pixel_freq_tbl[] = { + { .src = P_DSI0PLL }, { } }; @@ -513,12 +530,13 @@ static struct clk_rcg2 pclk0_clk_src = { .mnd_width = 8, .hid_width = 5, .parent_map = mmcc_xo_dsi_hdmi_edp_gpll0_map, - .freq_tbl = ftbl_mdss_pclk0_clk, + .freq_tbl = pixel_freq_tbl, .clkr.hw.init = &(struct clk_init_data){ .name = "pclk0_clk_src", .parent_names = mmcc_xo_dsi_hdmi_edp_gpll0, .num_parents = 6, - .ops = &clk_rcg2_ops, + .ops = &clk_pixel_ops, + .flags = CLK_SET_RATE_PARENT, }, }; @@ -527,12 +545,13 @@ static struct clk_rcg2 pclk1_clk_src = { .mnd_width = 8, .hid_width = 5, .parent_map = mmcc_xo_dsi_hdmi_edp_gpll0_map, - .freq_tbl = ftbl_mdss_pclk1_clk, + .freq_tbl = pixel_freq_tbl, .clkr.hw.init = &(struct clk_init_data){ .name = "pclk1_clk_src", .parent_names = mmcc_xo_dsi_hdmi_edp_gpll0, .num_parents = 6, - .ops = &clk_rcg2_ops, + .ops = &clk_pixel_ops, + .flags = CLK_SET_RATE_PARENT, }, }; @@ -750,41 +769,36 @@ static struct clk_rcg2 cpp_clk_src = { }, }; -static struct freq_tbl ftbl_mdss_byte0_clk[] = { - F(93750000, P_DSI0PLL, 8, 0, 0), - F(187500000, P_DSI0PLL, 4, 0, 0), - { } -}; - -static struct freq_tbl ftbl_mdss_byte1_clk[] = { - F(93750000, P_DSI1PLL, 8, 0, 0), - F(187500000, P_DSI1PLL, 4, 0, 0), +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_dsi_hdmi_edp_gpll0_map, - .freq_tbl = ftbl_mdss_byte0_clk, + .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_dsi_hdmi_edp_gpll0, + .parent_names = mmcc_xo_dsibyte_hdmi_edp_gpll0, .num_parents = 6, - .ops = &clk_rcg2_ops, + .ops = &clk_byte_ops, + .flags = CLK_SET_RATE_PARENT, }, }; static struct clk_rcg2 byte1_clk_src = { .cmd_rcgr = 0x2140, .hid_width = 5, - .parent_map = mmcc_xo_dsi_hdmi_edp_gpll0_map, - .freq_tbl = ftbl_mdss_byte1_clk, + .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_dsi_hdmi_edp_gpll0, + .parent_names = mmcc_xo_dsibyte_hdmi_edp_gpll0, .num_parents = 6, - .ops = &clk_rcg2_ops, + .ops = &clk_byte_ops, + .flags = CLK_SET_RATE_PARENT, }, }; @@ -822,12 +836,12 @@ static struct clk_rcg2 edplink_clk_src = { .parent_names = mmcc_xo_dsi_hdmi_edp_gpll0, .num_parents = 6, .ops = &clk_rcg2_ops, + .flags = CLK_SET_RATE_PARENT, }, }; -static struct freq_tbl ftbl_mdss_edppixel_clk[] = { - F(175000000, P_EDPVCO, 2, 0, 0), - F(350000000, P_EDPVCO, 11, 0, 0), +static struct freq_tbl edp_pixel_freq_tbl[] = { + { .src = P_EDPVCO }, { } }; @@ -836,12 +850,12 @@ static struct clk_rcg2 edppixel_clk_src = { .mnd_width = 8, .hid_width = 5, .parent_map = mmcc_xo_dsi_hdmi_edp_map, - .freq_tbl = ftbl_mdss_edppixel_clk, + .freq_tbl = edp_pixel_freq_tbl, .clkr.hw.init = &(struct clk_init_data){ .name = "edppixel_clk_src", .parent_names = mmcc_xo_dsi_hdmi_edp, .num_parents = 6, - .ops = &clk_rcg2_ops, + .ops = &clk_edp_pixel_ops, }, }; @@ -853,11 +867,11 @@ static struct freq_tbl ftbl_mdss_esc0_1_clk[] = { static struct clk_rcg2 esc0_clk_src = { .cmd_rcgr = 0x2160, .hid_width = 5, - .parent_map = mmcc_xo_dsi_hdmi_edp_gpll0_map, + .parent_map = mmcc_xo_dsibyte_hdmi_edp_gpll0_map, .freq_tbl = ftbl_mdss_esc0_1_clk, .clkr.hw.init = &(struct clk_init_data){ .name = "esc0_clk_src", - .parent_names = mmcc_xo_dsi_hdmi_edp_gpll0, + .parent_names = mmcc_xo_dsibyte_hdmi_edp_gpll0, .num_parents = 6, .ops = &clk_rcg2_ops, }, @@ -866,26 +880,18 @@ static struct clk_rcg2 esc0_clk_src = { static struct clk_rcg2 esc1_clk_src = { .cmd_rcgr = 0x2180, .hid_width = 5, - .parent_map = mmcc_xo_dsi_hdmi_edp_gpll0_map, + .parent_map = mmcc_xo_dsibyte_hdmi_edp_gpll0_map, .freq_tbl = ftbl_mdss_esc0_1_clk, .clkr.hw.init = &(struct clk_init_data){ .name = "esc1_clk_src", - .parent_names = mmcc_xo_dsi_hdmi_edp_gpll0, + .parent_names = mmcc_xo_dsibyte_hdmi_edp_gpll0, .num_parents = 6, .ops = &clk_rcg2_ops, }, }; -static struct freq_tbl ftbl_mdss_extpclk_clk[] = { - F(25200000, P_HDMIPLL, 1, 0, 0), - F(27000000, P_HDMIPLL, 1, 0, 0), - F(27030000, P_HDMIPLL, 1, 0, 0), - F(65000000, P_HDMIPLL, 1, 0, 0), - F(74250000, P_HDMIPLL, 1, 0, 0), - F(108000000, P_HDMIPLL, 1, 0, 0), - F(148500000, P_HDMIPLL, 1, 0, 0), - F(268500000, P_HDMIPLL, 1, 0, 0), - F(297000000, P_HDMIPLL, 1, 0, 0), +static struct freq_tbl extpclk_freq_tbl[] = { + { .src = P_HDMIPLL }, { } }; @@ -893,12 +899,13 @@ static struct clk_rcg2 extpclk_clk_src = { .cmd_rcgr = 0x2060, .hid_width = 5, .parent_map = mmcc_xo_dsi_hdmi_edp_gpll0_map, - .freq_tbl = ftbl_mdss_extpclk_clk, + .freq_tbl = extpclk_freq_tbl, .clkr.hw.init = &(struct clk_init_data){ .name = "extpclk_clk_src", .parent_names = mmcc_xo_dsi_hdmi_edp_gpll0, .num_parents = 6, - .ops = &clk_rcg2_ops, + .ops = &clk_byte_ops, + .flags = CLK_SET_RATE_PARENT, }, }; @@ -2318,7 +2325,7 @@ static const struct pll_config mmpll1_config = { .vco_val = 0x0, .vco_mask = 0x3 << 20, .pre_div_val = 0x0, - .pre_div_mask = 0x3 << 12, + .pre_div_mask = 0x7 << 12, .post_div_val = 0x0, .post_div_mask = 0x3 << 8, .mn_ena_mask = BIT(24), @@ -2332,7 +2339,7 @@ static struct pll_config mmpll3_config = { .vco_val = 0x0, .vco_mask = 0x3 << 20, .pre_div_val = 0x0, - .pre_div_mask = 0x3 << 12, + .pre_div_mask = 0x7 << 12, .post_div_val = 0x0, .post_div_mask = 0x3 << 8, .mn_ena_mask = BIT(24), @@ -2524,88 +2531,39 @@ static const struct regmap_config mmcc_msm8974_regmap_config = { .fast_io = true, }; +static const struct qcom_cc_desc mmcc_msm8974_desc = { + .config = &mmcc_msm8974_regmap_config, + .clks = mmcc_msm8974_clocks, + .num_clks = ARRAY_SIZE(mmcc_msm8974_clocks), + .resets = mmcc_msm8974_resets, + .num_resets = ARRAY_SIZE(mmcc_msm8974_resets), +}; + static const struct of_device_id mmcc_msm8974_match_table[] = { { .compatible = "qcom,mmcc-msm8974" }, { } }; MODULE_DEVICE_TABLE(of, mmcc_msm8974_match_table); -struct qcom_cc { - struct qcom_reset_controller reset; - struct clk_onecell_data data; - struct clk *clks[]; -}; - static int mmcc_msm8974_probe(struct platform_device *pdev) { - void __iomem *base; - struct resource *res; - int i, ret; - struct device *dev = &pdev->dev; - struct clk *clk; - struct clk_onecell_data *data; - struct clk **clks; + int ret; struct regmap *regmap; - size_t num_clks; - struct qcom_reset_controller *reset; - struct qcom_cc *cc; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(dev, res); - if (IS_ERR(base)) - return PTR_ERR(base); - - regmap = devm_regmap_init_mmio(dev, base, &mmcc_msm8974_regmap_config); - if (IS_ERR(regmap)) - return PTR_ERR(regmap); - - num_clks = ARRAY_SIZE(mmcc_msm8974_clocks); - cc = devm_kzalloc(dev, sizeof(*cc) + sizeof(*clks) * num_clks, - GFP_KERNEL); - if (!cc) - return -ENOMEM; - - clks = cc->clks; - data = &cc->data; - data->clks = clks; - data->clk_num = num_clks; - - clk_pll_configure_sr_hpm_lp(&mmpll1, regmap, &mmpll1_config, true); - clk_pll_configure_sr_hpm_lp(&mmpll3, regmap, &mmpll3_config, false); - - for (i = 0; i < num_clks; i++) { - if (!mmcc_msm8974_clocks[i]) - continue; - clk = devm_clk_register_regmap(dev, mmcc_msm8974_clocks[i]); - if (IS_ERR(clk)) - return PTR_ERR(clk); - clks[i] = clk; - } - ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get, data); + ret = qcom_cc_probe(pdev, &mmcc_msm8974_desc); if (ret) return ret; - reset = &cc->reset; - reset->rcdev.of_node = dev->of_node; - reset->rcdev.ops = &qcom_reset_ops, - reset->rcdev.owner = THIS_MODULE, - reset->rcdev.nr_resets = ARRAY_SIZE(mmcc_msm8974_resets), - reset->regmap = regmap; - reset->reset_map = mmcc_msm8974_resets, - platform_set_drvdata(pdev, &reset->rcdev); - - ret = reset_controller_register(&reset->rcdev); - if (ret) - of_clk_del_provider(dev->of_node); + regmap = dev_get_regmap(&pdev->dev, NULL); + clk_pll_configure_sr_hpm_lp(&mmpll1, regmap, &mmpll1_config, true); + clk_pll_configure_sr_hpm_lp(&mmpll3, regmap, &mmpll3_config, false); - return ret; + return 0; } static int mmcc_msm8974_remove(struct platform_device *pdev) { - of_clk_del_provider(pdev->dev.of_node); - reset_controller_unregister(platform_get_drvdata(pdev)); + qcom_cc_remove(pdev); return 0; } |