Message ID | 1427825817-26773-1-git-send-email-s.hauer@pengutronix.de |
---|---|
State | New |
Headers | show |
Hi Sascha, 2015-03-31 20:16 GMT+02:00 Sascha Hauer <s.hauer@pengutronix.de>: > > The following changes since commit 9eccca0843205f87c00404b663188b88eb248051: > > Linux 4.0-rc3 (2015-03-08 16:09:09 -0700) > > are available in the git repository at: > > git://git.pengutronix.de/git/imx/linux-2.6.git tags/v4.0-clk-mediatek-v11 > > for you to fetch changes up to ae9129219143cfdefe8b3a463deb8c5cb8955525: > > dt-bindings: ARM: Mediatek: Document devicetree bindings for clock/reset controllers (2015-03-31 20:08:46 +0200) > > ---------------------------------------------------------------- > This patchset contains the initial common clock support for Mediatek SoCs. > Mediatek SoC's clock architecture comprises of various PLLs, dividers, muxes > and clock gates. I tried the patch set on my mt8135 eval board. I used the dts bindings from a former version of this set [1], but it does not boot the board (based on v4.0-rc7). Do you have any hint, what is happening, or are the bindings wrong? Best regards, Matthias [1] http://lists.infradead.org/pipermail/linux-arm-kernel/2015-February/322813.html
2015-03-31 20:16 GMT+02:00 Sascha Hauer <s.hauer@pengutronix.de>: > The clk functions and structs declare the parent_name arrays as > 'const char **parent_names' which means the parent name strings > are const, but the array itself is not. Use > 'const char * const * parent_names' instead which also makes > the array const. This allows us to put the parent_name arrays into > the __initconst section. > > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> Reviewed-by: Krzysztof Kozlowski <k.kozlowski@samsung.com> and tested: Tested-by: Krzysztof Kozlowski <k.kozlowski@samsung.com> Best regards, Krzysztof
2015-03-31 20:16 GMT+02:00 Sascha Hauer <s.hauer@pengutronix.de>: > From: James Liao <jamesjj.liao@mediatek.com> > > This patch adds common clock support for Mediatek SoCs, including plls, > muxes and clock gates. > > Signed-off-by: James Liao <jamesjj.liao@mediatek.com> > Signed-off-by: Henry Chen <henryc.chen@mediatek.com> > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> > --- > drivers/clk/Makefile | 1 + > drivers/clk/mediatek/Makefile | 1 + > drivers/clk/mediatek/clk-gate.c | 137 ++++++++++++++++ > drivers/clk/mediatek/clk-gate.h | 49 ++++++ > drivers/clk/mediatek/clk-mtk.c | 197 +++++++++++++++++++++++ > drivers/clk/mediatek/clk-mtk.h | 155 +++++++++++++++++++ > drivers/clk/mediatek/clk-pll.c | 335 ++++++++++++++++++++++++++++++++++++++++ > 7 files changed, 875 insertions(+) > create mode 100644 drivers/clk/mediatek/Makefile > create mode 100644 drivers/clk/mediatek/clk-gate.c > create mode 100644 drivers/clk/mediatek/clk-gate.h > create mode 100644 drivers/clk/mediatek/clk-mtk.c > create mode 100644 drivers/clk/mediatek/clk-mtk.h > create mode 100644 drivers/clk/mediatek/clk-pll.c > > diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile > index d478ceb..6d97203 100644 > --- a/drivers/clk/Makefile > +++ b/drivers/clk/Makefile > @@ -49,6 +49,7 @@ obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/ > obj-$(CONFIG_ARCH_HIP04) += hisilicon/ > obj-$(CONFIG_ARCH_HIX5HD2) += hisilicon/ > obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/ > +obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/ > ifeq ($(CONFIG_COMMON_CLK), y) > obj-$(CONFIG_ARCH_MMP) += mmp/ > endif > diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile > new file mode 100644 > index 0000000..c384e97 > --- /dev/null > +++ b/drivers/clk/mediatek/Makefile > @@ -0,0 +1 @@ > +obj-y += clk-mtk.o clk-pll.o clk-gate.o > diff --git a/drivers/clk/mediatek/clk-gate.c b/drivers/clk/mediatek/clk-gate.c > new file mode 100644 > index 0000000..9d77ee3 > --- /dev/null > +++ b/drivers/clk/mediatek/clk-gate.c > @@ -0,0 +1,137 @@ > +/* > + * Copyright (c) 2014 MediaTek Inc. > + * Author: James Liao <jamesjj.liao@mediatek.com> > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License 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/of.h> > +#include <linux/of_address.h> > + > +#include <linux/io.h> > +#include <linux/slab.h> > +#include <linux/delay.h> > +#include <linux/clkdev.h> > + > +#include "clk-mtk.h" > +#include "clk-gate.h" > + > +static int mtk_cg_bit_is_cleared(struct clk_hw *hw) > +{ > + struct mtk_clk_gate *cg = to_clk_gate(hw); > + u32 val; > + > + regmap_read(cg->regmap, cg->sta_ofs, &val); > + > + val &= BIT(cg->bit); > + > + return val == 0; > +} > + > +static int mtk_cg_bit_is_set(struct clk_hw *hw) > +{ > + struct mtk_clk_gate *cg = to_clk_gate(hw); > + u32 val; > + > + regmap_read(cg->regmap, cg->sta_ofs, &val); > + > + val &= BIT(cg->bit); > + > + return val != 0; > +} > + > +static void mtk_cg_set_bit(struct clk_hw *hw) > +{ > + struct mtk_clk_gate *cg = to_clk_gate(hw); > + > + regmap_write(cg->regmap, cg->set_ofs, BIT(cg->bit)); > +} > + > +static void mtk_cg_clr_bit(struct clk_hw *hw) > +{ > + struct mtk_clk_gate *cg = to_clk_gate(hw); > + > + regmap_write(cg->regmap, cg->clr_ofs, BIT(cg->bit)); > +} > + > +static int mtk_cg_enable(struct clk_hw *hw) > +{ > + mtk_cg_clr_bit(hw); > + > + return 0; > +} > + > +static void mtk_cg_disable(struct clk_hw *hw) > +{ > + mtk_cg_set_bit(hw); > +} > + > +static int mtk_cg_enable_inv(struct clk_hw *hw) > +{ > + mtk_cg_set_bit(hw); > + > + return 0; > +} > + > +static void mtk_cg_disable_inv(struct clk_hw *hw) > +{ > + mtk_cg_clr_bit(hw); > +} > + > +const struct clk_ops mtk_clk_gate_ops_setclr = { > + .is_enabled = mtk_cg_bit_is_cleared, > + .enable = mtk_cg_enable, > + .disable = mtk_cg_disable, > +}; > + > +const struct clk_ops mtk_clk_gate_ops_setclr_inv = { > + .is_enabled = mtk_cg_bit_is_set, > + .enable = mtk_cg_enable_inv, > + .disable = mtk_cg_disable_inv, > +}; > + > +struct clk *mtk_clk_register_gate( > + const char *name, > + const char *parent_name, > + struct regmap *regmap, > + int set_ofs, > + int clr_ofs, > + int sta_ofs, > + u8 bit, > + const struct clk_ops *ops) > +{ > + struct mtk_clk_gate *cg; > + struct clk *clk; > + struct clk_init_data init; > + > + cg = kzalloc(sizeof(*cg), GFP_KERNEL); > + if (!cg) > + return ERR_PTR(-ENOMEM); > + > + init.name = name; > + init.flags = CLK_SET_RATE_PARENT; > + init.parent_names = parent_name ? &parent_name : NULL; > + init.num_parents = parent_name ? 1 : 0; > + init.ops = ops; > + > + cg->regmap = regmap; > + cg->set_ofs = set_ofs; > + cg->clr_ofs = clr_ofs; > + cg->sta_ofs = sta_ofs; > + cg->bit = bit; > + > + cg->hw.init = &init; > + > + clk = clk_register(NULL, &cg->hw); > + if (IS_ERR(clk)) > + kfree(cg); > + > + return clk; > +} > diff --git a/drivers/clk/mediatek/clk-gate.h b/drivers/clk/mediatek/clk-gate.h > new file mode 100644 > index 0000000..6b6780b > --- /dev/null > +++ b/drivers/clk/mediatek/clk-gate.h > @@ -0,0 +1,49 @@ > +/* > + * Copyright (c) 2014 MediaTek Inc. > + * Author: James Liao <jamesjj.liao@mediatek.com> > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License 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 __DRV_CLK_GATE_H > +#define __DRV_CLK_GATE_H > + > +#include <linux/regmap.h> > +#include <linux/clk.h> > +#include <linux/clk-provider.h> > + > +struct mtk_clk_gate { > + struct clk_hw hw; > + struct regmap *regmap; > + int set_ofs; > + int clr_ofs; > + int sta_ofs; > + u8 bit; > +}; > + > +static inline struct mtk_clk_gate *to_clk_gate(struct clk_hw *hw) > +{ > + return container_of(hw, struct mtk_clk_gate, hw); > +} > + > +extern const struct clk_ops mtk_clk_gate_ops_setclr; > +extern const struct clk_ops mtk_clk_gate_ops_setclr_inv; > + > +struct clk *mtk_clk_register_gate( > + const char *name, > + const char *parent_name, > + struct regmap *regmap, > + int set_ofs, > + int clr_ofs, > + int sta_ofs, > + u8 bit, > + const struct clk_ops *ops); > + > +#endif /* __DRV_CLK_GATE_H */ > diff --git a/drivers/clk/mediatek/clk-mtk.c b/drivers/clk/mediatek/clk-mtk.c > new file mode 100644 > index 0000000..746bb34 > --- /dev/null > +++ b/drivers/clk/mediatek/clk-mtk.c > @@ -0,0 +1,197 @@ > +/* > + * Copyright (c) 2014 MediaTek Inc. > + * Author: James Liao <jamesjj.liao@mediatek.com> > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License 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/of.h> > +#include <linux/of_address.h> > +#include <linux/err.h> > +#include <linux/io.h> > +#include <linux/slab.h> > +#include <linux/delay.h> > +#include <linux/clkdev.h> > +#include <linux/mfd/syscon.h> > + > +#include "clk-mtk.h" > +#include "clk-gate.h" > + > +struct clk_onecell_data *mtk_alloc_clk_data(unsigned int clk_num) > +{ > + int i; > + struct clk_onecell_data *clk_data; > + > + clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); > + if (!clk_data) > + return NULL; > + > + clk_data->clks = kcalloc(clk_num, sizeof(*clk_data->clks), GFP_KERNEL); > + if (!clk_data->clks) > + goto err_out; > + > + clk_data->clk_num = clk_num; > + > + for (i = 0; i < clk_num; i++) > + clk_data->clks[i] = ERR_PTR(-ENOENT); > + > + return clk_data; > +err_out: > + kfree(clk_data); > + > + return NULL; > +} > + > +void mtk_clk_register_factors(const struct mtk_fixed_factor *clks, int num, > + struct clk_onecell_data *clk_data) > +{ > + int i; > + struct clk *clk; > + > + for (i = 0; i < num; i++) { > + const struct mtk_fixed_factor *ff = &clks[i]; > + > + clk = clk_register_fixed_factor(NULL, ff->name, ff->parent_name, > + CLK_SET_RATE_PARENT, ff->mult, ff->div); > + > + if (IS_ERR(clk)) { > + pr_err("Failed to register clk %s: %ld\n", > + ff->name, PTR_ERR(clk)); > + continue; > + } > + > + if (clk_data) > + clk_data->clks[ff->id] = clk; > + } > +} > + > +int mtk_clk_register_gates(struct device_node *node, const struct mtk_gate *clks, > + int num, struct clk_onecell_data *clk_data) > +{ > + int i; > + struct clk *clk; > + struct regmap *regmap; > + > + if (!clk_data) > + return -ENOMEM; > + > + regmap = syscon_node_to_regmap(node); > + if (IS_ERR(regmap)) { > + pr_err("Cannot find regmap for %s: %ld\n", node->full_name, > + PTR_ERR(regmap)); > + return PTR_ERR(regmap); > + } > + > + for (i = 0; i < num; i++) { > + const struct mtk_gate *gate = &clks[i]; > + > + clk = mtk_clk_register_gate(gate->name, gate->parent_name, > + regmap, > + gate->regs->set_ofs, > + gate->regs->clr_ofs, > + gate->regs->sta_ofs, > + gate->shift, gate->ops); > + > + if (IS_ERR(clk)) { > + pr_err("Failed to register clk %s: %ld\n", > + gate->name, PTR_ERR(clk)); > + continue; > + } > + > + clk_data->clks[gate->id] = clk; > + } > + > + return 0; > +} > + > +struct clk *mtk_clk_register_composite(const struct mtk_composite *mc, > + void __iomem *base, spinlock_t *lock) > +{ > + struct clk *clk; > + struct clk_mux *mux = NULL; > + struct clk_gate *gate = NULL; > + struct clk_divider *div = NULL; > + struct clk_hw *mux_hw = NULL, *gate_hw = NULL, *div_hw = NULL; > + const struct clk_ops *mux_ops = NULL, *gate_ops = NULL, *div_ops = NULL; > + const char * const *parent_names; > + const char *parent; > + int num_parents; > + int ret; > + > + if (mc->mux_shift >= 0) { > + mux = kzalloc(sizeof(*mux), GFP_KERNEL); > + if (!mux) > + return ERR_PTR(-ENOMEM); > + > + mux->reg = base + mc->mux_reg; > + mux->mask = BIT(mc->mux_width) - 1; > + mux->shift = mc->mux_shift; > + mux->lock = lock; > + > + mux_hw = &mux->hw; > + mux_ops = &clk_mux_ops; > + > + parent_names = mc->parent_names; > + num_parents = mc->num_parents; > + } else { > + parent = mc->parent; > + parent_names = &parent; > + num_parents = 1; > + } > + > + if (mc->gate_shift >= 0) { > + gate = kzalloc(sizeof(*gate), GFP_KERNEL); > + if (!gate) { > + ret = -ENOMEM; > + goto err_out; > + } > + > + gate->reg = base + mc->gate_reg; > + gate->bit_idx = mc->gate_shift; > + gate->flags = CLK_GATE_SET_TO_DISABLE; > + gate->lock = lock; > + > + gate_hw = &gate->hw; > + gate_ops = &clk_gate_ops; > + } > + > + if (mc->divider_shift >= 0) { > + div = kzalloc(sizeof(*div), GFP_KERNEL); > + if (!div) { > + ret = -ENOMEM; > + goto err_out; > + } > + > + div->reg = base + mc->divider_reg; > + div->shift = mc->divider_shift; > + div->width = mc->divider_width; > + div->lock = lock; > + > + div_hw = &div->hw; > + div_ops = &clk_divider_ops; > + } > + > + clk = clk_register_composite(NULL, mc->name, parent_names, num_parents, > + mux_hw, mux_ops, > + div_hw, div_ops, > + gate_hw, gate_ops, > + mc->flags); > + > + if (IS_ERR(clk)) { > + kfree(gate); > + kfree(mux); > + } > + > + return clk; > +err_out: > + kfree(mux); > + > + return ERR_PTR(ret); > +} > diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h > new file mode 100644 > index 0000000..5aaba81 > --- /dev/null > +++ b/drivers/clk/mediatek/clk-mtk.h > @@ -0,0 +1,155 @@ > +/* > + * Copyright (c) 2014 MediaTek Inc. > + * Author: James Liao <jamesjj.liao@mediatek.com> > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License 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 __DRV_CLK_MTK_H > +#define __DRV_CLK_MTK_H > + > +#include <linux/regmap.h> > +#include <linux/bitops.h> > +#include <linux/clk.h> > +#include <linux/clk-provider.h> > + > +#define MAX_MUX_GATE_BIT 31 > +#define INVALID_MUX_GATE_BIT (MAX_MUX_GATE_BIT + 1) > + > +#define MHZ (1000 * 1000) > + > +struct mtk_fixed_factor { > + int id; > + const char *name; > + const char *parent_name; > + int mult; > + int div; > +}; > + > +#define FACTOR(_id, _name, _parent, _mult, _div) { \ > + .id = _id, \ > + .name = _name, \ > + .parent_name = _parent, \ > + .mult = _mult, \ > + .div = _div, \ > + } > + > +extern void mtk_clk_register_factors(const struct mtk_fixed_factor *clks, > + int num, struct clk_onecell_data *clk_data); > + > +struct mtk_composite { > + int id; > + const char *name; > + const char * const * parent_names; > + const char *parent; > + unsigned flags; > + > + uint32_t mux_reg; > + uint32_t divider_reg; > + uint32_t gate_reg; > + > + signed char mux_shift; > + signed char mux_width; > + signed char gate_shift; > + > + signed char divider_shift; > + signed char divider_width; > + > + signed char num_parents; > +}; > + > +#define MUX_GATE(_id, _name, _parents, _reg, _shift, _width, _gate) { \ > + .id = _id, \ > + .name = _name, \ > + .mux_reg = _reg, \ > + .mux_shift = _shift, \ > + .mux_width = _width, \ > + .gate_reg = _reg, \ > + .gate_shift = _gate, \ > + .divider_shift = -1, \ > + .parent_names = _parents, \ > + .num_parents = ARRAY_SIZE(_parents), \ > + .flags = CLK_SET_RATE_PARENT, \ > + } > + > +#define MUX(_id, _name, _parents, _reg, _shift, _width) { \ > + .id = _id, \ > + .name = _name, \ > + .mux_reg = _reg, \ > + .mux_shift = _shift, \ > + .mux_width = _width, \ > + .gate_shift = -1, \ > + .divider_shift = -1, \ > + .parent_names = _parents, \ > + .num_parents = ARRAY_SIZE(_parents), \ > + .flags = CLK_SET_RATE_PARENT, \ > + } > + > +#define DIV_GATE(_id, _name, _parent, _gate_reg, _gate_shift, _div_reg, _div_width, _div_shift) { \ > + .id = _id, \ > + .parent = _parent, \ > + .name = _name, \ > + .divider_reg = _div_reg, \ > + .divider_shift = _div_shift, \ > + .divider_width = _div_width, \ > + .gate_reg = _gate_reg, \ > + .gate_shift = _gate_shift, \ > + .mux_shift = -1, \ > + .flags = 0, \ > + } > + > +struct clk *mtk_clk_register_composite(const struct mtk_composite *mc, > + void __iomem *base, spinlock_t *lock); > + > +struct mtk_gate_regs { > + u32 sta_ofs; > + u32 clr_ofs; > + u32 set_ofs; > +}; > + > +struct mtk_gate { > + int id; > + const char *name; > + const char *parent_name; > + const struct mtk_gate_regs *regs; > + int shift; > + const struct clk_ops *ops; > +}; > + > +int mtk_clk_register_gates(struct device_node *node, const struct mtk_gate *clks, > + int num, struct clk_onecell_data *clk_data); > + > +struct clk_onecell_data *mtk_alloc_clk_data(unsigned int clk_num); > + > +#define HAVE_RST_BAR BIT(0) > + > +struct mtk_pll_data { > + int id; > + const char *name; > + uint32_t reg; > + uint32_t pwr_reg; > + uint32_t en_mask; > + uint32_t pd_reg; > + uint32_t tuner_reg; > + int pd_shift; > + unsigned int flags; > + const struct clk_ops *ops; > + u32 rst_bar_mask; > + unsigned long fmax; > + int pcwbits; > + uint32_t pcw_reg; > + int pcw_shift; > +}; > + > +void __init mtk_clk_register_plls(struct device_node *node, > + const struct mtk_pll_data *plls, int num_plls, > + struct clk_onecell_data *clk_data); > + > +#endif /* __DRV_CLK_MTK_H */ > diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c > new file mode 100644 > index 0000000..3ef6b21 > --- /dev/null > +++ b/drivers/clk/mediatek/clk-pll.c > @@ -0,0 +1,335 @@ > +/* > + * Copyright (c) 2014 MediaTek Inc. > + * Author: James Liao <jamesjj.liao@mediatek.com> > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License 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/of.h> > +#include <linux/of_address.h> > +#include <linux/io.h> > +#include <linux/slab.h> > +#include <linux/clkdev.h> > +#include <linux/delay.h> > + > +#include "clk-mtk.h" > + > +#define REG_CON0 0 > +#define REG_CON1 4 > + > +#define CON0_BASE_EN BIT(0) > +#define CON0_PWR_ON BIT(0) > +#define CON0_ISO_EN BIT(1) > +#define CON0_PCW_CHG BIT(31) > + > +#define AUDPLL_TUNER_EN BIT(31) > + > +#define POSTDIV_MASK 0x7 > +#define INTEGER_BITS 7 > + > +/* > + * MediaTek PLLs are configured through their pcw value. The pcw value describes > + * a divider in the PLL feedback loop which consists of 7 bits for the integer > + * part and the remaining bits (if present) for the fractional part. Also they > + * have a 3 bit power-of-two post divider. > + */ > + > +struct mtk_clk_pll { > + struct clk_hw hw; > + void __iomem *base_addr; > + void __iomem *pd_addr; > + void __iomem *pwr_addr; > + void __iomem *tuner_addr; > + void __iomem *pcw_addr; > + const struct mtk_pll_data *data; > +}; > + > +static inline struct mtk_clk_pll *to_mtk_clk_pll(struct clk_hw *hw) > +{ > + return container_of(hw, struct mtk_clk_pll, hw); > +} > + > +static int mtk_pll_is_prepared(struct clk_hw *hw) > +{ > + struct mtk_clk_pll *pll = to_mtk_clk_pll(hw); > + > + return (readl(pll->base_addr + REG_CON0) & CON0_BASE_EN) != 0; > +} > + > +static unsigned long __mtk_pll_recalc_rate(struct mtk_clk_pll *pll, u32 fin, > + u32 pcw, int postdiv) > +{ > + int pcwbits = pll->data->pcwbits; > + int pcwfbits; > + u64 vco; > + u8 c = 0; > + > + /* The fractional part of the PLL divider. */ > + pcwfbits = pcwbits > INTEGER_BITS ? pcwbits - INTEGER_BITS : 0; > + > + vco = (u64)fin * pcw; > + > + if (pcwfbits && (vco & GENMASK(pcwfbits - 1, 0))) > + c = 1; > + > + vco >>= pcwfbits; > + > + if (c) > + vco++; > + > + return ((unsigned long)vco + postdiv - 1) / postdiv; > +} > + > +static void mtk_pll_set_rate_regs(struct clk_hw *hw, u32 pcw, > + int postdiv) > +{ > + struct mtk_clk_pll *pll = to_mtk_clk_pll(hw); >From mtk_pll_set_rate we can pass a pointer to mtk_clk_pll instead of clk_hw. > + u32 con1, pd, val; > + int pll_en; > + > + /* set postdiv */ > + pd = readl(pll->pd_addr); > + pd &= ~(POSTDIV_MASK << pll->data->pd_shift); > + pd |= (ffs(postdiv) - 1) << pll->data->pd_shift; > + writel(pd, pll->pd_addr); > + > + pll_en = readl(pll->base_addr + REG_CON0) & CON0_BASE_EN; > + > + /* set pcw */ > + val = readl(pll->pcw_addr); > + > + val &= ~GENMASK(pll->data->pcw_shift + pll->data->pcwbits - 1, > + pll->data->pcw_shift); > + val |= pcw << pll->data->pcw_shift; > + writel(val, pll->pcw_addr); > + > + con1 = readl(pll->base_addr + REG_CON1); > + > + if (pll_en) > + con1 |= CON0_PCW_CHG; > + > + writel(con1, pll->base_addr + REG_CON1); > + if (pll->tuner_addr) > + writel(con1 + 1, pll->tuner_addr); > + > + if (pll_en) > + usleep_range(20, 1000); > +} > + > +/* > + * mtk_pll_calc_values - calculate good values for a given input frequency. > + * @pll: The pll > + * @pcw: The pcw value (output) > + * @postdiv: The post divider (output) > + * @freq: The desired target frequency > + * @fin: The input frequency > + * > + */ > +static void mtk_pll_calc_values(struct mtk_clk_pll *pll, u32 *pcw, u32 *postdiv, > + u32 freq, u32 fin) > +{ > + unsigned long fmin = 1000 * MHZ; > + u64 _pcw; > + u32 val; > + > + if (freq > pll->data->fmax) > + freq = pll->data->fmax; > + > + for (val = 0; val < 4; val++) { > + *postdiv = 1 << val; > + if (freq * *postdiv >= fmin) > + break; > + } > + > + /* _pcw = freq * postdiv / fin * 2^pcwfbits */ > + _pcw = ((u64)freq << val) << (pll->data->pcwbits - INTEGER_BITS); > + do_div(_pcw, fin); > + > + *pcw = (u32)_pcw; > +} > + > +static int mtk_pll_set_rate(struct clk_hw *hw, unsigned long rate, > + unsigned long parent_rate) > +{ > + struct mtk_clk_pll *pll = to_mtk_clk_pll(hw); > + u32 pcw = 0; > + u32 postdiv; > + > + mtk_pll_calc_values(pll, &pcw, &postdiv, rate, parent_rate); > + mtk_pll_set_rate_regs(hw, pcw, postdiv); > + > + return 0; > +} > + > +static unsigned long mtk_pll_recalc_rate(struct clk_hw *hw, > + unsigned long parent_rate) > +{ > + struct mtk_clk_pll *pll = to_mtk_clk_pll(hw); > + u32 postdiv; > + u32 pcw; > + > + postdiv = (readl(pll->pd_addr) >> pll->data->pd_shift) & POSTDIV_MASK; > + postdiv = 1 << postdiv; > + > + pcw = readl(pll->pcw_addr) >> pll->data->pcw_shift; > + pcw &= GENMASK(pll->data->pcwbits - 1, 0); > + > + return __mtk_pll_recalc_rate(pll, parent_rate, pcw, postdiv); > +} > + > +static long mtk_pll_round_rate(struct clk_hw *hw, unsigned long rate, > + unsigned long *prate) > +{ > + struct mtk_clk_pll *pll = to_mtk_clk_pll(hw); > + u32 pcw = 0; > + int postdiv; > + > + mtk_pll_calc_values(pll, &pcw, &postdiv, rate, *prate); > + > + return __mtk_pll_recalc_rate(pll, *prate, pcw, postdiv); > +} > + > +static int mtk_pll_prepare(struct clk_hw *hw) > +{ > + struct mtk_clk_pll *pll = to_mtk_clk_pll(hw); > + u32 r; > + > + r = readl(pll->pwr_addr) | CON0_PWR_ON; > + writel(r, pll->pwr_addr); > + usleep_range(1, 100); > + > + r = readl(pll->pwr_addr) & ~CON0_ISO_EN; > + writel(r, pll->pwr_addr); > + usleep_range(1, 100); > + > + r = readl(pll->base_addr + REG_CON0); > + r |= pll->data->en_mask; > + writel(r, pll->base_addr + REG_CON0); > + > + if (pll->tuner_addr) { > + r = readl(pll->tuner_addr) | AUDPLL_TUNER_EN; > + writel(r, pll->tuner_addr); > + } > + > + usleep_range(20, 1000); > + > + if (pll->data->flags & HAVE_RST_BAR) { > + r = readl(pll->base_addr + REG_CON0); > + r |= pll->data->rst_bar_mask; > + writel(r, pll->base_addr + REG_CON0); > + } > + > + return 0; > +} > + > +static void mtk_pll_unprepare(struct clk_hw *hw) > +{ > + struct mtk_clk_pll *pll = to_mtk_clk_pll(hw); > + u32 r; > + > + if (pll->data->flags & HAVE_RST_BAR) { > + r = readl(pll->base_addr + REG_CON0); > + r &= ~pll->data->rst_bar_mask; > + writel(r, pll->base_addr + REG_CON0); > + } > + > + if (pll->tuner_addr) { > + r = readl(pll->tuner_addr) & ~AUDPLL_TUNER_EN; > + writel(r, pll->tuner_addr); > + } > + > + r = readl(pll->base_addr + REG_CON0); > + r &= ~CON0_BASE_EN; > + writel(r, pll->base_addr + REG_CON0); > + > + r = readl(pll->pwr_addr) | CON0_ISO_EN; > + writel(r, pll->pwr_addr); > + > + r = readl(pll->pwr_addr) & ~CON0_PWR_ON; > + writel(r, pll->pwr_addr); > +} > + > +static const struct clk_ops mtk_pll_ops = { > + .is_prepared = mtk_pll_is_prepared, > + .prepare = mtk_pll_prepare, > + .unprepare = mtk_pll_unprepare, > + .recalc_rate = mtk_pll_recalc_rate, > + .round_rate = mtk_pll_round_rate, > + .set_rate = mtk_pll_set_rate, > +}; > + > +static struct clk *mtk_clk_register_pll(const struct mtk_pll_data *data, > + void __iomem *base) > +{ > + struct mtk_clk_pll *pll; > + struct clk_init_data init; > + struct clk *clk; > + const char *parent_name = "clk26m"; > + > + pr_debug("%s(): name: %s\n", __func__, data->name); Please please make this more descriptive or delete the debug message. > + > + pll = kzalloc(sizeof(*pll), GFP_KERNEL); > + if (!pll) > + return ERR_PTR(-ENOMEM); > + > + pll->base_addr = base + data->reg; > + pll->pwr_addr = base + data->pwr_reg; > + pll->pd_addr = base + data->pd_reg; > + pll->pcw_addr = base + data->pcw_reg; > + if (data->tuner_reg) > + pll->tuner_addr = base + data->tuner_reg; > + pll->hw.init = &init; > + pll->data = data; > + > + init.name = data->name; > + init.ops = &mtk_pll_ops; > + init.parent_names = &parent_name; > + init.num_parents = 1; > + > + clk = clk_register(NULL, &pll->hw); > + > + if (IS_ERR(clk)) > + kfree(pll); > + > + return clk; > +} > + > +void __init mtk_clk_register_plls(struct device_node *node, > + const struct mtk_pll_data *plls, int num_plls, struct clk_onecell_data *clk_data) > +{ > + void __iomem *base; > + int r, i; > + struct clk *clk; > + > + base = of_iomap(node, 0); > + if (!base) { > + pr_err("%s(): ioremap failed\n", __func__); > + return; > + } > + > + for (i = 0; i < num_plls; i++) { > + const struct mtk_pll_data *pll = &plls[i]; > + > + clk = mtk_clk_register_pll(pll, base); > + > + if (IS_ERR(clk)) { > + pr_err("Failed to register clk %s: %ld\n", > + pll->name, PTR_ERR(clk)); > + continue; > + } > + > + clk_data->clks[pll->id] = clk; > + } > + > + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); > + if (r) > + pr_err("%s(): could not register clock provider: %d\n", > + __func__, r); > +} > -- > 2.1.4 >
2015-03-31 20:16 GMT+02:00 Sascha Hauer <s.hauer@pengutronix.de>: > From: James Liao <jamesjj.liao@mediatek.com> > > This patch adds basic clocks for MT8135, including TOPCKGEN, PLLs, > INFRA and PERI clocks. > > Signed-off-by: James Liao <jamesjj.liao@mediatek.com> > Signed-off-by: Henry Chen <henryc.chen@mediatek.com> > Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> > --- > drivers/clk/mediatek/Makefile | 1 + > drivers/clk/mediatek/clk-mt8135.c | 640 +++++++++++++++++++++ > include/dt-bindings/clock/mt8135-clk.h | 190 ++++++ > .../dt-bindings/reset-controller/mt8135-resets.h | 64 +++ > 4 files changed, 895 insertions(+) > create mode 100644 drivers/clk/mediatek/clk-mt8135.c > create mode 100644 include/dt-bindings/clock/mt8135-clk.h > create mode 100644 include/dt-bindings/reset-controller/mt8135-resets.h > > diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile > index 0b6f1c3..12ce576 100644 > --- a/drivers/clk/mediatek/Makefile > +++ b/drivers/clk/mediatek/Makefile > @@ -1,2 +1,3 @@ > obj-y += clk-mtk.o clk-pll.o clk-gate.o > obj-$(CONFIG_RESET_CONTROLLER) += reset.o > +obj-y += clk-mt8135.o > diff --git a/drivers/clk/mediatek/clk-mt8135.c b/drivers/clk/mediatek/clk-mt8135.c > new file mode 100644 > index 0000000..a08f2fe > --- /dev/null > +++ b/drivers/clk/mediatek/clk-mt8135.c > @@ -0,0 +1,640 @@ > +/* > + * Copyright (c) 2014 MediaTek Inc. > + * Author: James Liao <jamesjj.liao@mediatek.com> > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License 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/of.h> > +#include <linux/of_address.h> > +#include <linux/slab.h> > +#include <linux/mfd/syscon.h> > +#include <dt-bindings/clock/mt8135-clk.h> > + > +#include "clk-mtk.h" > +#include "clk-gate.h" > + > +static DEFINE_SPINLOCK(mt8135_clk_lock); > + > +static const struct mtk_fixed_factor root_clk_alias[] __initconst = { > + FACTOR(TOP_DSI0_LNTC_DSICLK, "dsi0_lntc_dsiclk", "clk_null", 1, 1), > + FACTOR(TOP_HDMITX_CLKDIG_CTS, "hdmitx_clkdig_cts", "clk_null", 1, 1), > + FACTOR(TOP_CLKPH_MCK, "clkph_mck", "clk_null", 1, 1), > + FACTOR(TOP_CPUM_TCK_IN, "cpum_tck_in", "clk_null", 1, 1), > +}; > + > +static const struct mtk_fixed_factor top_divs[] __initconst = { > + FACTOR(TOP_MAINPLL_806M, "mainpll_806m", "mainpll", 1, 2), > + FACTOR(TOP_MAINPLL_537P3M, "mainpll_537p3m", "mainpll", 1, 3), > + FACTOR(TOP_MAINPLL_322P4M, "mainpll_322p4m", "mainpll", 1, 5), > + FACTOR(TOP_MAINPLL_230P3M, "mainpll_230p3m", "mainpll", 1, 7), > + > + FACTOR(TOP_UNIVPLL_624M, "univpll_624m", "univpll", 1, 2), > + FACTOR(TOP_UNIVPLL_416M, "univpll_416m", "univpll", 1, 3), > + FACTOR(TOP_UNIVPLL_249P6M, "univpll_249p6m", "univpll", 1, 5), > + FACTOR(TOP_UNIVPLL_178P3M, "univpll_178p3m", "univpll", 1, 7), > + FACTOR(TOP_UNIVPLL_48M, "univpll_48m", "univpll", 1, 26), > + > + FACTOR(TOP_MMPLL_D2, "mmpll_d2", "mmpll", 1, 2), > + FACTOR(TOP_MMPLL_D3, "mmpll_d3", "mmpll", 1, 3), > + FACTOR(TOP_MMPLL_D5, "mmpll_d5", "mmpll", 1, 5), > + FACTOR(TOP_MMPLL_D7, "mmpll_d7", "mmpll", 1, 7), > + FACTOR(TOP_MMPLL_D4, "mmpll_d4", "mmpll_d2", 1, 2), > + FACTOR(TOP_MMPLL_D6, "mmpll_d6", "mmpll_d3", 1, 2), > + > + FACTOR(TOP_SYSPLL_D2, "syspll_d2", "mainpll_806m", 1, 1), > + FACTOR(TOP_SYSPLL_D4, "syspll_d4", "mainpll_806m", 1, 2), > + FACTOR(TOP_SYSPLL_D6, "syspll_d6", "mainpll_806m", 1, 3), > + FACTOR(TOP_SYSPLL_D8, "syspll_d8", "mainpll_806m", 1, 4), > + FACTOR(TOP_SYSPLL_D10, "syspll_d10", "mainpll_806m", 1, 5), > + FACTOR(TOP_SYSPLL_D12, "syspll_d12", "mainpll_806m", 1, 6), > + FACTOR(TOP_SYSPLL_D16, "syspll_d16", "mainpll_806m", 1, 8), > + FACTOR(TOP_SYSPLL_D24, "syspll_d24", "mainpll_806m", 1, 12), > + > + FACTOR(TOP_SYSPLL_D3, "syspll_d3", "mainpll_537p3m", 1, 1), > + > + FACTOR(TOP_SYSPLL_D2P5, "syspll_d2p5", "mainpll_322p4m", 2, 1), > + FACTOR(TOP_SYSPLL_D5, "syspll_d5", "mainpll_322p4m", 1, 1), > + > + FACTOR(TOP_SYSPLL_D3P5, "syspll_d3p5", "mainpll_230p3m", 2, 1), > + > + FACTOR(TOP_UNIVPLL1_D2, "univpll1_d2", "univpll_624m", 1, 2), > + FACTOR(TOP_UNIVPLL1_D4, "univpll1_d4", "univpll_624m", 1, 4), > + FACTOR(TOP_UNIVPLL1_D6, "univpll1_d6", "univpll_624m", 1, 6), > + FACTOR(TOP_UNIVPLL1_D8, "univpll1_d8", "univpll_624m", 1, 8), > + FACTOR(TOP_UNIVPLL1_D10, "univpll1_d10", "univpll_624m", 1, 10), > + > + FACTOR(TOP_UNIVPLL2_D2, "univpll2_d2", "univpll_416m", 1, 2), > + FACTOR(TOP_UNIVPLL2_D4, "univpll2_d4", "univpll_416m", 1, 4), > + FACTOR(TOP_UNIVPLL2_D6, "univpll2_d6", "univpll_416m", 1, 6), > + FACTOR(TOP_UNIVPLL2_D8, "univpll2_d8", "univpll_416m", 1, 8), > + > + FACTOR(TOP_UNIVPLL_D3, "univpll_d3", "univpll_416m", 1, 1), > + FACTOR(TOP_UNIVPLL_D5, "univpll_d5", "univpll_249p6m", 1, 1), > + FACTOR(TOP_UNIVPLL_D7, "univpll_d7", "univpll_178p3m", 1, 1), > + FACTOR(TOP_UNIVPLL_D10, "univpll_d10", "univpll_249p6m", 1, 5), shouldn't that be FACTOR(TOP_UNIVPLL_D10, "univpll_d10", "univpll_249p6m", 1, 2), as univpll_249p6m is univpll divided by 5?
On Thu, Apr 09, 2015 at 07:05:22PM +0200, Matthias Brugger wrote: > 2015-03-31 20:16 GMT+02:00 Sascha Hauer <s.hauer@pengutronix.de>: > > + > > + FACTOR(TOP_UNIVPLL_D3, "univpll_d3", "univpll_416m", 1, 1), > > + FACTOR(TOP_UNIVPLL_D5, "univpll_d5", "univpll_249p6m", 1, 1), > > + FACTOR(TOP_UNIVPLL_D7, "univpll_d7", "univpll_178p3m", 1, 1), > > + FACTOR(TOP_UNIVPLL_D10, "univpll_d10", "univpll_249p6m", 1, 5), > > shouldn't that be > FACTOR(TOP_UNIVPLL_D10, "univpll_d10", "univpll_249p6m", 1, 2), > as univpll_249p6m is univpll divided by 5? Yes, fixed. Sascha
On Tue, Apr 07, 2015 at 01:47:58PM +0200, Matthias Brugger wrote: > Hi Sascha, > > > 2015-03-31 20:16 GMT+02:00 Sascha Hauer <s.hauer@pengutronix.de>: > > > > The following changes since commit 9eccca0843205f87c00404b663188b88eb248051: > > > > Linux 4.0-rc3 (2015-03-08 16:09:09 -0700) > > > > are available in the git repository at: > > > > git://git.pengutronix.de/git/imx/linux-2.6.git tags/v4.0-clk-mediatek-v11 > > > > for you to fetch changes up to ae9129219143cfdefe8b3a463deb8c5cb8955525: > > > > dt-bindings: ARM: Mediatek: Document devicetree bindings for clock/reset controllers (2015-03-31 20:08:46 +0200) > > > > ---------------------------------------------------------------- > > This patchset contains the initial common clock support for Mediatek SoCs. > > Mediatek SoC's clock architecture comprises of various PLLs, dividers, muxes > > and clock gates. > > I tried the patch set on my mt8135 eval board. I used the dts bindings > from a former version of this set [1], but it does not boot the board > (based on v4.0-rc7). > Do you have any hint, what is happening, or are the bindings wrong? I can give this a test tomorrow. Sascha
Hi Matthias, On Tue, Apr 07, 2015 at 01:47:58PM +0200, Matthias Brugger wrote: > Hi Sascha, > > > 2015-03-31 20:16 GMT+02:00 Sascha Hauer <s.hauer@pengutronix.de>: > > > > The following changes since commit 9eccca0843205f87c00404b663188b88eb248051: > > > > Linux 4.0-rc3 (2015-03-08 16:09:09 -0700) > > > > are available in the git repository at: > > > > git://git.pengutronix.de/git/imx/linux-2.6.git tags/v4.0-clk-mediatek-v11 > > > > for you to fetch changes up to ae9129219143cfdefe8b3a463deb8c5cb8955525: > > > > dt-bindings: ARM: Mediatek: Document devicetree bindings for clock/reset controllers (2015-03-31 20:08:46 +0200) > > > > ---------------------------------------------------------------- > > This patchset contains the initial common clock support for Mediatek SoCs. > > Mediatek SoC's clock architecture comprises of various PLLs, dividers, muxes > > and clock gates. > > I tried the patch set on my mt8135 eval board. I used the dts bindings > from a former version of this set [1], but it does not boot the board > (based on v4.0-rc7). > Do you have any hint, what is happening, or are the bindings wrong? I just tried on a v4.0 with - this series applied - the dts patch applied (which is still up-to-date) - multi_v7_defconfig And it still works. What do you mean with "does not boot the board"? No console output? Could you try with earlyprintk? Sascha
Hi Sascha, 2015-04-14 12:08 GMT+02:00 Sascha Hauer <s.hauer@pengutronix.de>: > Hi Matthias, > > On Tue, Apr 07, 2015 at 01:47:58PM +0200, Matthias Brugger wrote: >> Hi Sascha, >> >> >> 2015-03-31 20:16 GMT+02:00 Sascha Hauer <s.hauer@pengutronix.de>: >> > >> > The following changes since commit 9eccca0843205f87c00404b663188b88eb248051: >> > >> > Linux 4.0-rc3 (2015-03-08 16:09:09 -0700) >> > >> > are available in the git repository at: >> > >> > git://git.pengutronix.de/git/imx/linux-2.6.git tags/v4.0-clk-mediatek-v11 >> > >> > for you to fetch changes up to ae9129219143cfdefe8b3a463deb8c5cb8955525: >> > >> > dt-bindings: ARM: Mediatek: Document devicetree bindings for clock/reset controllers (2015-03-31 20:08:46 +0200) >> > >> > ---------------------------------------------------------------- >> > This patchset contains the initial common clock support for Mediatek SoCs. >> > Mediatek SoC's clock architecture comprises of various PLLs, dividers, muxes >> > and clock gates. >> >> I tried the patch set on my mt8135 eval board. I used the dts bindings >> from a former version of this set [1], but it does not boot the board >> (based on v4.0-rc7). >> Do you have any hint, what is happening, or are the bindings wrong? > > I just tried on a v4.0 with > - this series applied > - the dts patch applied (which is still up-to-date) > - multi_v7_defconfig > > And it still works. What do you mean with "does not boot the board"? No > console output? Could you try with earlyprintk? The probelms I see is, that with the clock patches, I'm not able to boot into a initramfs [1]. Whereas if I just comment topckgen and preicfg in the dts, I'm able to get the a serial console of my initramfs [2]. I wonder if you are able to get serial console from the initramfs with the clock patches + dts patch? Cheers, Matthias [1] http://pastebin.com/wmmsbdNp [2] http://pastebin.com/jZHrxmmT
On Tue, Apr 14, 2015 at 01:01:30PM +0200, Matthias Brugger wrote: > Hi Sascha, > > 2015-04-14 12:08 GMT+02:00 Sascha Hauer <s.hauer@pengutronix.de>: > > Hi Matthias, > > > > On Tue, Apr 07, 2015 at 01:47:58PM +0200, Matthias Brugger wrote: > >> Hi Sascha, > >> > >> > >> 2015-03-31 20:16 GMT+02:00 Sascha Hauer <s.hauer@pengutronix.de>: > >> > > >> > The following changes since commit 9eccca0843205f87c00404b663188b88eb248051: > >> > > >> > Linux 4.0-rc3 (2015-03-08 16:09:09 -0700) > >> > > >> > are available in the git repository at: > >> > > >> > git://git.pengutronix.de/git/imx/linux-2.6.git tags/v4.0-clk-mediatek-v11 > >> > > >> > for you to fetch changes up to ae9129219143cfdefe8b3a463deb8c5cb8955525: > >> > > >> > dt-bindings: ARM: Mediatek: Document devicetree bindings for clock/reset controllers (2015-03-31 20:08:46 +0200) > >> > > >> > ---------------------------------------------------------------- > >> > This patchset contains the initial common clock support for Mediatek SoCs. > >> > Mediatek SoC's clock architecture comprises of various PLLs, dividers, muxes > >> > and clock gates. > >> > >> I tried the patch set on my mt8135 eval board. I used the dts bindings > >> from a former version of this set [1], but it does not boot the board > >> (based on v4.0-rc7). > >> Do you have any hint, what is happening, or are the bindings wrong? > > > > I just tried on a v4.0 with > > - this series applied > > - the dts patch applied (which is still up-to-date) > > - multi_v7_defconfig > > > > And it still works. What do you mean with "does not boot the board"? No > > console output? Could you try with earlyprintk? > > The probelms I see is, that with the clock patches, I'm not able to > boot into a initramfs [1]. > Whereas if I just comment topckgen and preicfg in the dts, I'm able to > get the a serial console of my initramfs [2]. > > I wonder if you are able to get serial console from the initramfs with > the clock patches + dts patch? So you get kernel messages but no output from initramfs? In this case the kernel disables the unused clocks in a late_initcall. The UART driver still uses the dummy clock provided in the dtsi, so the real UART clk gets disabled in the initcall. Try passing clk_ignore_unused to the kernel Sascha
2015-04-14 13:57 GMT+02:00 Sascha Hauer <s.hauer@pengutronix.de>: > On Tue, Apr 14, 2015 at 01:01:30PM +0200, Matthias Brugger wrote: >> Hi Sascha, >> >> 2015-04-14 12:08 GMT+02:00 Sascha Hauer <s.hauer@pengutronix.de>: >> > Hi Matthias, >> > >> > On Tue, Apr 07, 2015 at 01:47:58PM +0200, Matthias Brugger wrote: >> >> Hi Sascha, >> >> >> >> >> >> 2015-03-31 20:16 GMT+02:00 Sascha Hauer <s.hauer@pengutronix.de>: >> >> > >> >> > The following changes since commit 9eccca0843205f87c00404b663188b88eb248051: >> >> > >> >> > Linux 4.0-rc3 (2015-03-08 16:09:09 -0700) >> >> > >> >> > are available in the git repository at: >> >> > >> >> > git://git.pengutronix.de/git/imx/linux-2.6.git tags/v4.0-clk-mediatek-v11 >> >> > >> >> > for you to fetch changes up to ae9129219143cfdefe8b3a463deb8c5cb8955525: >> >> > >> >> > dt-bindings: ARM: Mediatek: Document devicetree bindings for clock/reset controllers (2015-03-31 20:08:46 +0200) >> >> > >> >> > ---------------------------------------------------------------- >> >> > This patchset contains the initial common clock support for Mediatek SoCs. >> >> > Mediatek SoC's clock architecture comprises of various PLLs, dividers, muxes >> >> > and clock gates. >> >> >> >> I tried the patch set on my mt8135 eval board. I used the dts bindings >> >> from a former version of this set [1], but it does not boot the board >> >> (based on v4.0-rc7). >> >> Do you have any hint, what is happening, or are the bindings wrong? >> > >> > I just tried on a v4.0 with >> > - this series applied >> > - the dts patch applied (which is still up-to-date) >> > - multi_v7_defconfig >> > >> > And it still works. What do you mean with "does not boot the board"? No >> > console output? Could you try with earlyprintk? >> >> The probelms I see is, that with the clock patches, I'm not able to >> boot into a initramfs [1]. >> Whereas if I just comment topckgen and preicfg in the dts, I'm able to >> get the a serial console of my initramfs [2]. >> >> I wonder if you are able to get serial console from the initramfs with >> the clock patches + dts patch? > > So you get kernel messages but no output from initramfs? In this case > the kernel disables the unused clocks in a late_initcall. The UART > driver still uses the dummy clock provided in the dtsi, so the real > UART clk gets disabled in the initcall. Try passing clk_ignore_unused to > the kernel OK, I can boot to the initramfs with this kernel parameter, but it fails to boot, when I change the uart clock. I suppose that PERI_UART3 for debug port uart3 should be fine, but it looks like it doesn't work. I can see on the mt6589 datasheet that you have a register PERI_UART_CK_SOURCE_SEL where you can decide if you want a 26 MHz or a 52 MHz clock for the UART block. Does this register exists on mt8135? If so, why is it not implemented?
2015-04-15 17:11 GMT+02:00 Matthias Brugger <matthias.bgg@gmail.com>: > 2015-04-14 13:57 GMT+02:00 Sascha Hauer <s.hauer@pengutronix.de>: >> On Tue, Apr 14, 2015 at 01:01:30PM +0200, Matthias Brugger wrote: >>> Hi Sascha, >>> >>> 2015-04-14 12:08 GMT+02:00 Sascha Hauer <s.hauer@pengutronix.de>: >>> > Hi Matthias, >>> > >>> > On Tue, Apr 07, 2015 at 01:47:58PM +0200, Matthias Brugger wrote: >>> >> Hi Sascha, >>> >> >>> >> >>> >> 2015-03-31 20:16 GMT+02:00 Sascha Hauer <s.hauer@pengutronix.de>: >>> >> > >>> >> > The following changes since commit 9eccca0843205f87c00404b663188b88eb248051: >>> >> > >>> >> > Linux 4.0-rc3 (2015-03-08 16:09:09 -0700) >>> >> > >>> >> > are available in the git repository at: >>> >> > >>> >> > git://git.pengutronix.de/git/imx/linux-2.6.git tags/v4.0-clk-mediatek-v11 >>> >> > >>> >> > for you to fetch changes up to ae9129219143cfdefe8b3a463deb8c5cb8955525: >>> >> > >>> >> > dt-bindings: ARM: Mediatek: Document devicetree bindings for clock/reset controllers (2015-03-31 20:08:46 +0200) >>> >> > >>> >> > ---------------------------------------------------------------- >>> >> > This patchset contains the initial common clock support for Mediatek SoCs. >>> >> > Mediatek SoC's clock architecture comprises of various PLLs, dividers, muxes >>> >> > and clock gates. >>> >> >>> >> I tried the patch set on my mt8135 eval board. I used the dts bindings >>> >> from a former version of this set [1], but it does not boot the board >>> >> (based on v4.0-rc7). >>> >> Do you have any hint, what is happening, or are the bindings wrong? >>> > >>> > I just tried on a v4.0 with >>> > - this series applied >>> > - the dts patch applied (which is still up-to-date) >>> > - multi_v7_defconfig >>> > >>> > And it still works. What do you mean with "does not boot the board"? No >>> > console output? Could you try with earlyprintk? >>> >>> The probelms I see is, that with the clock patches, I'm not able to >>> boot into a initramfs [1]. >>> Whereas if I just comment topckgen and preicfg in the dts, I'm able to >>> get the a serial console of my initramfs [2]. >>> >>> I wonder if you are able to get serial console from the initramfs with >>> the clock patches + dts patch? >> >> So you get kernel messages but no output from initramfs? In this case >> the kernel disables the unused clocks in a late_initcall. The UART >> driver still uses the dummy clock provided in the dtsi, so the real >> UART clk gets disabled in the initcall. Try passing clk_ignore_unused to >> the kernel > > OK, I can boot to the initramfs with this kernel parameter, but it > fails to boot, when I change the uart clock. I suppose that PERI_UART3 > for debug port uart3 should be fine, but it looks like it doesn't > work. > I can see on the mt6589 datasheet that you have a register > PERI_UART_CK_SOURCE_SEL where you can decide if you want a 26 MHz or a > 52 MHz clock for the UART block. > Does this register exists on mt8135? If so, why is it not implemented? I found that PERI_UARTx_CK is connected to axi_sel but should be connected to uart_sel. Like this I'm able to reach to initramfs console, but the baud rate values are screwed up. As uart_sel is at 52 MHz, I suppose we need to change the entries in PERI_UART_CK_SOURCE_SEL. Cheers, Matthias
On Wed, Apr 15, 2015 at 05:48:08PM +0200, Matthias Brugger wrote: > 2015-04-15 17:11 GMT+02:00 Matthias Brugger <matthias.bgg@gmail.com>: > > 2015-04-14 13:57 GMT+02:00 Sascha Hauer <s.hauer@pengutronix.de>: > >> On Tue, Apr 14, 2015 at 01:01:30PM +0200, Matthias Brugger wrote: > >>> Hi Sascha, > >>> > >>> 2015-04-14 12:08 GMT+02:00 Sascha Hauer <s.hauer@pengutronix.de>: > >>> > Hi Matthias, > >>> > > >>> > On Tue, Apr 07, 2015 at 01:47:58PM +0200, Matthias Brugger wrote: > >>> >> Hi Sascha, > >>> >> > >>> >> > >>> >> 2015-03-31 20:16 GMT+02:00 Sascha Hauer <s.hauer@pengutronix.de>: > >>> >> > > >>> >> > The following changes since commit 9eccca0843205f87c00404b663188b88eb248051: > >>> >> > > >>> >> > Linux 4.0-rc3 (2015-03-08 16:09:09 -0700) > >>> >> > > >>> >> > are available in the git repository at: > >>> >> > > >>> >> > git://git.pengutronix.de/git/imx/linux-2.6.git tags/v4.0-clk-mediatek-v11 > >>> >> > > >>> >> > for you to fetch changes up to ae9129219143cfdefe8b3a463deb8c5cb8955525: > >>> >> > > >>> >> > dt-bindings: ARM: Mediatek: Document devicetree bindings for clock/reset controllers (2015-03-31 20:08:46 +0200) > >>> >> > > >>> >> > ---------------------------------------------------------------- > >>> >> > This patchset contains the initial common clock support for Mediatek SoCs. > >>> >> > Mediatek SoC's clock architecture comprises of various PLLs, dividers, muxes > >>> >> > and clock gates. > >>> >> > >>> >> I tried the patch set on my mt8135 eval board. I used the dts bindings > >>> >> from a former version of this set [1], but it does not boot the board > >>> >> (based on v4.0-rc7). > >>> >> Do you have any hint, what is happening, or are the bindings wrong? > >>> > > >>> > I just tried on a v4.0 with > >>> > - this series applied > >>> > - the dts patch applied (which is still up-to-date) > >>> > - multi_v7_defconfig > >>> > > >>> > And it still works. What do you mean with "does not boot the board"? No > >>> > console output? Could you try with earlyprintk? > >>> > >>> The probelms I see is, that with the clock patches, I'm not able to > >>> boot into a initramfs [1]. > >>> Whereas if I just comment topckgen and preicfg in the dts, I'm able to > >>> get the a serial console of my initramfs [2]. > >>> > >>> I wonder if you are able to get serial console from the initramfs with > >>> the clock patches + dts patch? > >> > >> So you get kernel messages but no output from initramfs? In this case > >> the kernel disables the unused clocks in a late_initcall. The UART > >> driver still uses the dummy clock provided in the dtsi, so the real > >> UART clk gets disabled in the initcall. Try passing clk_ignore_unused to > >> the kernel > > > > OK, I can boot to the initramfs with this kernel parameter, but it > > fails to boot, when I change the uart clock. I suppose that PERI_UART3 > > for debug port uart3 should be fine, but it looks like it doesn't > > work. > > I can see on the mt6589 datasheet that you have a register > > PERI_UART_CK_SOURCE_SEL where you can decide if you want a 26 MHz or a > > 52 MHz clock for the UART block. > > Does this register exists on mt8135? If so, why is it not implemented? > > I found that PERI_UARTx_CK is connected to axi_sel but should be > connected to uart_sel. Like this I'm able to reach to initramfs > console, but the baud rate values are screwed up. > As uart_sel is at 52 MHz, I suppose we need to change the entries in > PERI_UART_CK_SOURCE_SEL. I just asked the Mediatek guys for clarification, lets see what they tell me. There is a PERI_UART_CK_SOURCE_SEL on MT8135/MT8173, I have no idea why this is not implemented. I also don't know where the clocks I can select in the PERI_UART_CK_SOURCE_SEL register are derived from. It's also unclear to me how the real UART clock topology looks like. Sascha
On Wed, Apr 15, 2015 at 05:48:08PM +0200, Matthias Brugger wrote: > 2015-04-15 17:11 GMT+02:00 Matthias Brugger <matthias.bgg@gmail.com>: > > 2015-04-14 13:57 GMT+02:00 Sascha Hauer <s.hauer@pengutronix.de>: > >> On Tue, Apr 14, 2015 at 01:01:30PM +0200, Matthias Brugger wrote: > >>> Hi Sascha, > >>> > >>> 2015-04-14 12:08 GMT+02:00 Sascha Hauer <s.hauer@pengutronix.de>: > >>> > Hi Matthias, > >>> > > >>> > On Tue, Apr 07, 2015 at 01:47:58PM +0200, Matthias Brugger wrote: > >>> >> Hi Sascha, > >>> >> > >>> >> > >>> >> 2015-03-31 20:16 GMT+02:00 Sascha Hauer <s.hauer@pengutronix.de>: > >>> >> > > >>> >> > The following changes since commit 9eccca0843205f87c00404b663188b88eb248051: > >>> >> > > >>> >> > Linux 4.0-rc3 (2015-03-08 16:09:09 -0700) > >>> >> > > >>> >> > are available in the git repository at: > >>> >> > > >>> >> > git://git.pengutronix.de/git/imx/linux-2.6.git tags/v4.0-clk-mediatek-v11 > >>> >> > > >>> >> > for you to fetch changes up to ae9129219143cfdefe8b3a463deb8c5cb8955525: > >>> >> > > >>> >> > dt-bindings: ARM: Mediatek: Document devicetree bindings for clock/reset controllers (2015-03-31 20:08:46 +0200) > >>> >> > > >>> >> > ---------------------------------------------------------------- > >>> >> > This patchset contains the initial common clock support for Mediatek SoCs. > >>> >> > Mediatek SoC's clock architecture comprises of various PLLs, dividers, muxes > >>> >> > and clock gates. > >>> >> > >>> >> I tried the patch set on my mt8135 eval board. I used the dts bindings > >>> >> from a former version of this set [1], but it does not boot the board > >>> >> (based on v4.0-rc7). > >>> >> Do you have any hint, what is happening, or are the bindings wrong? > >>> > > >>> > I just tried on a v4.0 with > >>> > - this series applied > >>> > - the dts patch applied (which is still up-to-date) > >>> > - multi_v7_defconfig > >>> > > >>> > And it still works. What do you mean with "does not boot the board"? No > >>> > console output? Could you try with earlyprintk? > >>> > >>> The probelms I see is, that with the clock patches, I'm not able to > >>> boot into a initramfs [1]. > >>> Whereas if I just comment topckgen and preicfg in the dts, I'm able to > >>> get the a serial console of my initramfs [2]. > >>> > >>> I wonder if you are able to get serial console from the initramfs with > >>> the clock patches + dts patch? > >> > >> So you get kernel messages but no output from initramfs? In this case > >> the kernel disables the unused clocks in a late_initcall. The UART > >> driver still uses the dummy clock provided in the dtsi, so the real > >> UART clk gets disabled in the initcall. Try passing clk_ignore_unused to > >> the kernel > > > > OK, I can boot to the initramfs with this kernel parameter, but it > > fails to boot, when I change the uart clock. I suppose that PERI_UART3 > > for debug port uart3 should be fine, but it looks like it doesn't > > work. > > I can see on the mt6589 datasheet that you have a register > > PERI_UART_CK_SOURCE_SEL where you can decide if you want a 26 MHz or a > > 52 MHz clock for the UART block. > > Does this register exists on mt8135? If so, why is it not implemented? > > I found that PERI_UARTx_CK is connected to axi_sel but should be > connected to uart_sel. Like this I'm able to reach to initramfs > console, but the baud rate values are screwed up. > As uart_sel is at 52 MHz, I suppose we need to change the entries in > PERI_UART_CK_SOURCE_SEL. I sorted the UART clock stuff out. I sent out three series, with all of them merged together you should get UART + common clock support working properly on MT835. Sascha