Skip to contentSkip to conversation

ARM: meson: add clock/reset controller

PATCH New Carlo Caione 2 participants 9 messages Nov 19, 2014

Subsystems (6)
lore
Share & tools
lore
#0 lore raw

cover ARM: meson: add clock/reset controller

This patchset introduces preliminary support for the clock/reset controller found on Amlogic MesonX SoCs and enables it for the Meson6.

The reset controller is in charge of shutting off the clock to disable modules and submodules within the chip. Unfortunately the documentation we have does not explicit which clock is gated but only which peripheral is reset so the clocks introduced are not gated but the peripherals are reset using the reset controller.

DTS patches will follow.

Carlo Caione (4):
ARM: meson: add basic infrastructure for clocks
ARM: meson: add reset controller
ARM: meson: enable reset controller in kconfig
ARM: meson: add documentation for reset/clock controller

 .../bindings/clock/amlogic,meson6-clkc.txt         |  45 ++++
 arch/arm/mach-meson/Kconfig                        |   2 +
 drivers/clk/Makefile                               |   1 +
 drivers/clk/meson/Makefile                         |   8 +
 drivers/clk/meson/clk-pll.c                        | 298 +++++++++++++++++++++
 drivers/clk/meson/clkc.c                           | 151 +++++++++++
 drivers/clk/meson/clkc.h                           | 174 ++++++++++++
 drivers/clk/meson/meson6-clkc.c                    | 178 ++++++++++++
 drivers/clk/meson/rstc.c                           | 152 +++++++++++
 include/dt-bindings/clock/meson6-clkc.h            |  18 ++
 10 files changed, 1027 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/amlogic,meson6-clkc.txt
 create mode 100644 drivers/clk/meson/Makefile
 create mode 100644 drivers/clk/meson/clk-pll.c
 create mode 100644 drivers/clk/meson/clkc.c
 create mode 100644 drivers/clk/meson/clkc.h
 create mode 100644 drivers/clk/meson/meson6-clkc.c
 create mode 100644 drivers/clk/meson/rstc.c
 create mode 100644 include/dt-bindings/clock/meson6-clkc.h
Signature · 1 line
1.9.1
#1 lore raw

PATCH 1/4 ARM: meson: add basic infrastructure for clocks

This patchset adds the infrastructure for registering and managing the core clocks found on Amlogic MesonX SoCs and also adds the support for the basic Meson6 clocks.

---
 drivers/clk/Makefile                    |   1 +
 drivers/clk/meson/Makefile              |   7 +
 drivers/clk/meson/clk-pll.c             | 298 ++++++++++++++++++++++++++++++++
 drivers/clk/meson/clkc.c                | 151 ++++++++++++++++
 drivers/clk/meson/clkc.h                | 159 +++++++++++++++++
 drivers/clk/meson/meson6-clkc.c         | 160 +++++++++++++++++
 include/dt-bindings/clock/meson6-clkc.h |  18 ++
 7 files changed, 794 insertions(+)
 create mode 100644 drivers/clk/meson/Makefile
 create mode 100644 drivers/clk/meson/clk-pll.c
 create mode 100644 drivers/clk/meson/clkc.c
 create mode 100644 drivers/clk/meson/clkc.h
 create mode 100644 drivers/clk/meson/meson6-clkc.c
 create mode 100644 include/dt-bindings/clock/meson6-clkc.h
drivers/clk/Makefile +1 -0
index d5fba5b..e93d134 100644
@@ -51,6 +51,7 @@ ifeq ($(CONFIG_COMMON_CLK), y)
 obj-$(CONFIG_ARCH_MMP)			+= mmp/
 endif
 obj-$(CONFIG_PLAT_ORION)		+= mvebu/
+obj-$(CONFIG_ARCH_MESON)		+= meson/
 obj-$(CONFIG_ARCH_MXS)			+= mxs/
 obj-$(CONFIG_COMMON_CLK_PXA)		+= pxa/
 obj-$(CONFIG_COMMON_CLK_QCOM)		+= qcom/
drivers/clk/meson/Makefile new file +7 -0
new file mode 100644
index 0000000..8f102e4
@@ -0,0 +1,7 @@
+#
+# Makefile for Meson specific clk
+#
+
+obj-y += clkc.o
+obj-y += meson6-clkc.o
+obj-y += clk-pll.o
drivers/clk/meson/clk-pll.c new file +298 -0

298 lines not on this page · raw message

drivers/clk/meson/clkc.c new file +151 -0

151 lines not on this page · raw message

drivers/clk/meson/clkc.h new file +159 -0

159 lines not on this page · raw message

drivers/clk/meson/meson6-clkc.c new file +160 -0

160 lines not on this page · raw message

include/dt-bindings/clock/meson6-clkc.h new file +18 -0
new file mode 100644
index 0000000..06efef3
@@ -0,0 +1,18 @@
+/*
+ * Meson6 clock tree IDs
+ */
+
+#define CLKID_XTAL		1
+#define CLKID_RTC_XTAL		2
+#define CLKID_DPLL_SYS		3
+#define CLKID_DPLL_DDR		4
+#define CLKID_DPLL_VID2		5
+#define CLKID_MPLL_FIXED	6
+#define CLKID_HPLL_HDMI		7
+#define CLKID_HPLL_LVDS		8
+#define CLKID_FCLK_DIV2		9
+#define CLKID_FCLK_DIV3		10
+#define CLKID_FCLK_DIV5		11
+#define CLKID_CLK81		12
+
+#define CLK_NR_CLKS		(CLKID_CLK81 + 1)
Signature · 1 line
1.9.1
#2 lore raw

PATCH 1/4 ARM: meson: add basic infrastructure for clocks

Quoting Carlo Caione (2014-11-19 02:32:20)

Quoted 3 lines

This patchset adds the infrastructure for registering and managing the core clocks found on Amlogic MesonX SoCs and also adds the support for the basic Meson6 clocks.

Minor nitpick: typically the $SUBJECT starts with "arm:" if the patch primarily deals with code under arch/arm. Since this code lives in drivers/clk it might be better to use something like:

clk: meson: add basic infrastructure for clocks

<snip>

Quoted 50 lines
drivers/clk/meson/clk-pll.c new file +50 -0
+static void meson_clk_pll_get_parms(struct meson_clk_pll *pll,
+                                   unsigned long *rate, unsigned long p_rate,
+                                   u16 *best_n, u16 *best_m, u16 *best_od_fb)
+{
+       unsigned long rate_mhz, p_rate_mhz;
+       unsigned long pll_vco_min_mhz, pll_vco_max_mhz;
+       unsigned long cur_rate_mhz, best_rate_mhz;
+       u16 m, m_min, m_max, m_mask;
+       u16 n, n_min, n_max, n_mask, _n_min, _n_max;
+       u16 od_fb, od_fb_max;
+
+       rate_mhz = *rate / 1000000;
+       p_rate_mhz = p_rate / 1000000;
+       pll_vco_min_mhz = pll->conf->vco_min_mhz;
+       pll_vco_max_mhz = pll->conf->vco_max_mhz;
+       best_rate_mhz = ULONG_MAX;
+       *best_n = 0;
+       *best_m = 0;
+       *best_od_fb = 1;
+
+       m_mask = PMASK(pll->conf->m.width);
+       n_mask = PMASK(pll->conf->n.width);
+
+       /* FREF = P_RATE / N */
+       n_min = max_t(u16, DIV_ROUND_UP(p_rate_mhz, MESON_FREF_MAX_MHZ), 1);
+       n_max = min_t(u16, p_rate_mhz / MESON_FREF_MIN_MHZ, n_mask);
+
+       od_fb_max = 1 << PMASK(pll->conf->od_fb.width);
+
+       for (od_fb = 1; od_fb <= od_fb_max; od_fb <<= 1) {
+
+               /* VCO = P_RATE * M * OD_FB / N */
+               m_min = max_t(u16, DIV_ROUND_UP(pll_vco_min_mhz,
+                             p_rate_mhz * od_fb) * n_min, 1);
+               m_max = min_t(u16, (pll_vco_max_mhz * n_max) /
+                             (p_rate_mhz * od_fb), m_mask);
+
+
+               for (m = m_min; m <= m_max; m++) {
+                       _n_min = max_t(u16, n_min,
+                                      DIV_ROUND_UP(p_rate_mhz * m * od_fb,
+                                      pll_vco_max_mhz));
+                       _n_max = min_t(u16, n_max,
+                                      p_rate_mhz * m * od_fb / pll_vco_min_mhz);
+
+                       for (n = _n_min; n <= _n_max; n++) {
+                               cur_rate_mhz = p_rate_mhz * m * od_fb / n;
+
+                               if (abs(cur_rate_mhz - rate_mhz) <
+                                  abs(best_rate_mhz - rate_mhz)) {

drivers/clk/meson/clk-pll.c line 126

Quoted 10 lines
drivers/clk/meson/clk-pll.c new file +10 -0
+                                       best_rate_mhz = cur_rate_mhz;
+                                       *best_n = n;
+                                       *best_m = m;
+                                       *best_od_fb = od_fb;
+                                       if (best_rate_mhz == rate_mhz)
+                                               goto done;
+                               }
+                       }
+               }
+       }

Nothing strictly wrong with the above, but is is n^3 complexity. If your tables are large then you might be spending a non-trivial amount time calculating the pll parameters.

<snip>

Quoted 41 lines
drivers/clk/meson/clk-pll.c new file +41 -0
+
+done:
+       *best_od_fb >>= 1;
+       *rate = best_rate_mhz * 1000000;
+       return;
+
+}
+
+static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw,
+                                               unsigned long parent_rate)
+{
+       struct meson_clk_pll *pll = to_meson_clk_pll(hw);
+       struct parm *p_n, *p_m, *p_od_fb;
+       unsigned long parent_rate_mhz = parent_rate / 1000000;
+       unsigned long rate_mhz;
+       u16 n, m, od_fb = 1;
+       u32 reg_n, reg_m, reg_od_fb;
+
+       p_n = &pll->conf->n;
+       p_m = &pll->conf->m;
+       p_od_fb = &pll->conf->od_fb;
+
+       reg_n = readl(pll->base + p_n->reg_off);
+       n = PARM_GET(p_n->width, p_n->shift, reg_n);
+
+       reg_m = readl(pll->base + p_m->reg_off);
+       m = PARM_GET(p_m->width, p_m->shift, reg_m);
+
+       if (p_od_fb->width != MESON_PARM_NOT_APPLICABLE) {
+               reg_od_fb = readl(pll->base + p_od_fb->reg_off);
+               od_fb = PARM_GET(p_od_fb->width, p_od_fb->shift, reg_od_fb);
+               od_fb = 1 << od_fb;
+       }
+
+       rate_mhz = parent_rate_mhz * m * od_fb / n;
+
+       return rate_mhz * 1000000;
+}
+
+static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+                                     unsigned long *parent_rate)

drivers/clk/meson/clk-pll.c line 177

Quoted 10 lines
drivers/clk/meson/clk-pll.c new file +10 -0
+{
+       struct meson_clk_pll *pll = to_meson_clk_pll(hw);
+       u16 m, n, od_fb;
+
+       meson_clk_pll_get_parms(pll, &rate, *parent_rate, &n, &m, &od_fb);
+       if (m == 0 || n == 0)
+               return -EINVAL;
+
+       return rate;
+}

Can the clock signal input to your pll by multiplexed? Are there multiple possible parents to a pll? If so you might want to use .determine_rate over .round_rate.

<snip>

Quoted 24 lines
drivers/clk/meson/clkc.h new file +18 -0
new file mode 100644
index 0000000..6c0f611
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2014 Carlo Caione <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __CLKC_H
+#define __CLKC_H

<snip>

drivers/clk/meson/clkc.h line 159

Quoted 10 lines
drivers/clk/meson/clkc.h new file +10 -0
+void meson_clk_init(struct device_node *np, unsigned long nr_clks);
+void meson_clk_add_lookup(struct clk *clk, unsigned int id);
+void meson_clk_register_pll_divs(struct pll_div_conf *pll_divs,
+                                unsigned int nr_pll_divs,
+                                void __iomem *reg_base);
+void meson_clk_register_pll_div(struct pll_div_conf *pll_div_conf,
+                               void __iomem *reg_base, spinlock_t *lock);
+void meson_clk_register_clks(struct clk_conf *clk_confs,
+                            unsigned int nr_confs,
+                            void __iomem *clk_base);

Missing #endif here causes compile failure.

Regards,
Mike

#3 lore raw

PATCH 1/4 ARM: meson: add basic infrastructure for clocks

Quoted 10 lines · Mike Turquette

Quoting Carlo Caione (2014-11-19 02:32:20)

Quoted 3 lines

This patchset adds the infrastructure for registering and managing the core clocks found on Amlogic MesonX SoCs and also adds the support for the basic Meson6 clocks.

Minor nitpick: typically the $SUBJECT starts with "arm:" if the patch primarily deals with code under arch/arm. Since this code lives in drivers/clk it might be better to use something like:

clk: meson: add basic infrastructure for clocks

Good to know. Thanks.

Quoted 56 lines
Quoted 56 lines
drivers/clk/meson/clk-pll.c new file +56 -0
+static void meson_clk_pll_get_parms(struct meson_clk_pll *pll,
+                                   unsigned long *rate, unsigned long p_rate,
+                                   u16 *best_n, u16 *best_m, u16 *best_od_fb)
+{
+       unsigned long rate_mhz, p_rate_mhz;
+       unsigned long pll_vco_min_mhz, pll_vco_max_mhz;
+       unsigned long cur_rate_mhz, best_rate_mhz;
+       u16 m, m_min, m_max, m_mask;
+       u16 n, n_min, n_max, n_mask, _n_min, _n_max;
+       u16 od_fb, od_fb_max;
+
+       rate_mhz = *rate / 1000000;
+       p_rate_mhz = p_rate / 1000000;
+       pll_vco_min_mhz = pll->conf->vco_min_mhz;
+       pll_vco_max_mhz = pll->conf->vco_max_mhz;
+       best_rate_mhz = ULONG_MAX;
+       *best_n = 0;
+       *best_m = 0;
+       *best_od_fb = 1;
+
+       m_mask = PMASK(pll->conf->m.width);
+       n_mask = PMASK(pll->conf->n.width);
+
+       /* FREF = P_RATE / N */
+       n_min = max_t(u16, DIV_ROUND_UP(p_rate_mhz, MESON_FREF_MAX_MHZ), 1);
+       n_max = min_t(u16, p_rate_mhz / MESON_FREF_MIN_MHZ, n_mask);
+
+       od_fb_max = 1 << PMASK(pll->conf->od_fb.width);
+
+       for (od_fb = 1; od_fb <= od_fb_max; od_fb <<= 1) {
+
+               /* VCO = P_RATE * M * OD_FB / N */
+               m_min = max_t(u16, DIV_ROUND_UP(pll_vco_min_mhz,
+                             p_rate_mhz * od_fb) * n_min, 1);
+               m_max = min_t(u16, (pll_vco_max_mhz * n_max) /
+                             (p_rate_mhz * od_fb), m_mask);
+
+
+               for (m = m_min; m <= m_max; m++) {
+                       _n_min = max_t(u16, n_min,
+                                      DIV_ROUND_UP(p_rate_mhz * m * od_fb,
+                                      pll_vco_max_mhz));
+                       _n_max = min_t(u16, n_max,
+                                      p_rate_mhz * m * od_fb / pll_vco_min_mhz);
+
+                       for (n = _n_min; n <= _n_max; n++) {
+                               cur_rate_mhz = p_rate_mhz * m * od_fb / n;
+
+                               if (abs(cur_rate_mhz - rate_mhz) <
+                                  abs(best_rate_mhz - rate_mhz)) {
+                                       best_rate_mhz = cur_rate_mhz;
+                                       *best_n = n;
+                                       *best_m = m;
+                                       *best_od_fb = od_fb;
+                                       if (best_rate_mhz == rate_mhz)
+                                               goto done;
Quoted 8 lines

drivers/clk/meson/clk-pll.c line 126

Quoted 4 lines
drivers/clk/meson/clk-pll.c new file +4 -0
+                               }
+                       }
+               }
+       }

Nothing strictly wrong with the above, but is is n^3 complexity. If your tables are large then you might be spending a non-trivial amount time calculating the pll parameters.

Actually od_fb il always quite small (maximum /1, /2, /4, /8 maximum). But I see the problem.
I'll investigate a bit to check if there is a way to make it simpler (and shorter)

Quoted 47 lines
Quoted 47 lines
drivers/clk/meson/clk-pll.c new file +47 -0
+
+done:
+       *best_od_fb >>= 1;
+       *rate = best_rate_mhz * 1000000;
+       return;
+
+}
+
+static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw,
+                                               unsigned long parent_rate)
+{
+       struct meson_clk_pll *pll = to_meson_clk_pll(hw);
+       struct parm *p_n, *p_m, *p_od_fb;
+       unsigned long parent_rate_mhz = parent_rate / 1000000;
+       unsigned long rate_mhz;
+       u16 n, m, od_fb = 1;
+       u32 reg_n, reg_m, reg_od_fb;
+
+       p_n = &pll->conf->n;
+       p_m = &pll->conf->m;
+       p_od_fb = &pll->conf->od_fb;
+
+       reg_n = readl(pll->base + p_n->reg_off);
+       n = PARM_GET(p_n->width, p_n->shift, reg_n);
+
+       reg_m = readl(pll->base + p_m->reg_off);
+       m = PARM_GET(p_m->width, p_m->shift, reg_m);
+
+       if (p_od_fb->width != MESON_PARM_NOT_APPLICABLE) {
+               reg_od_fb = readl(pll->base + p_od_fb->reg_off);
+               od_fb = PARM_GET(p_od_fb->width, p_od_fb->shift, reg_od_fb);
+               od_fb = 1 << od_fb;
+       }
+
+       rate_mhz = parent_rate_mhz * m * od_fb / n;
+
+       return rate_mhz * 1000000;
+}
+
+static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+                                     unsigned long *parent_rate)
+{
+       struct meson_clk_pll *pll = to_meson_clk_pll(hw);
+       u16 m, n, od_fb;
+
+       meson_clk_pll_get_parms(pll, &rate, *parent_rate, &n, &m, &od_fb);
+       if (m == 0 || n == 0)
Quoted 8 lines

drivers/clk/meson/clk-pll.c line 177

Quoted 4 lines
drivers/clk/meson/clk-pll.c new file +4 -0
+               return -EINVAL;
+
+       return rate;
+}

Can the clock signal input to your pll by multiplexed? Are there multiple possible parents to a pll? If so you might want to use .determine_rate over .round_rate.

The input to the PLLs is always unique for both Meson6 and Meson8.

Quoted 29 lines

<snip>

Quoted 24 lines
drivers/clk/meson/clkc.h new file +18 -0
new file mode 100644
index 0000000..6c0f611
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2014 Carlo Caione <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __CLKC_H
+#define __CLKC_H

<snip>

Quoted 12 lines

drivers/clk/meson/clkc.h line 159

Quoted 10 lines
drivers/clk/meson/clkc.h new file +10 -0
+void meson_clk_init(struct device_node *np, unsigned long nr_clks);
+void meson_clk_add_lookup(struct clk *clk, unsigned int id);
+void meson_clk_register_pll_divs(struct pll_div_conf *pll_divs,
+                                unsigned int nr_pll_divs,
+                                void __iomem *reg_base);
+void meson_clk_register_pll_div(struct pll_div_conf *pll_div_conf,
+                               void __iomem *reg_base, spinlock_t *lock);
+void meson_clk_register_clks(struct clk_conf *clk_confs,
+                            unsigned int nr_confs,
+                            void __iomem *clk_base);

Missing #endif here causes compile failure.

Ah, then you will find a double #endif in the reset controller patch. I screwed up separating the patches.

Thank you for the review.

Signature · 1 line
Carlo Caione
#4 lore raw

PATCH 1/4 ARM: meson: add basic infrastructure for clocks

In reply to Carlo Caione

Quoting Carlo Caione (2014-11-19 02:32:20)

Quoted 16 lines
drivers/clk/meson/clk-pll.c new file +10 -0
new file mode 100644
index 0000000..5b6d064
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 2014 Carlo Caione <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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

drivers/clk/meson/clk-pll.c line 20

Quoted 10 lines
drivers/clk/meson/clk-pll.c new file +10 -0
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/delay.h>
+#include <linux/err.h>

All of the headers below are unnecessary. Copy/paste? I didn't bother to check the ones above.

drivers/clk/meson/clk-pll.c line 25

Quoted 5 lines
drivers/clk/meson/clk-pll.c new file +5 -0
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/string.h>

Regards,
Mike

#5 lore raw

PATCH 1/4 ARM: meson: add basic infrastructure for clocks

Quoted 22 lines · Mike Turquette

Quoting Carlo Caione (2014-11-19 02:32:20)

Quoted 21 lines
drivers/clk/meson/clk-pll.c new file +15 -0
new file mode 100644
index 0000000..5b6d064
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 2014 Carlo Caione <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
Quoted 8 lines

drivers/clk/meson/clk-pll.c line 20

Quoted 5 lines
drivers/clk/meson/clk-pll.c new file +5 -0
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/delay.h>
+#include <linux/err.h>

All of the headers below are unnecessary. Copy/paste? I didn't bother to check the ones above.

No prob. I'll fix them also.

Quoted 8 lines

drivers/clk/meson/clk-pll.c line 25

Quoted 5 lines
drivers/clk/meson/clk-pll.c new file +5 -0
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/string.h>

Regards,
Mike

Thanks,

Signature · 1 line
Carlo Caione
#6 lore raw

PATCH 2/4 ARM: meson: add reset controller

In reply to Carlo Caione

Modules and submodules within Meson6 and Meson8 SoCs can be disabled by shutting off the clock. The control for these clocks comes from several registers that are mapped contiguously except a special register that controls peripherals in the AO (Always-On) power domain. The reset controller manages both the cases according to the reset ID.

---
 drivers/clk/meson/Makefile      |   1 +
 drivers/clk/meson/clkc.h        |  15 ++++
 drivers/clk/meson/meson6-clkc.c |  18 +++++
 drivers/clk/meson/rstc.c        | 152 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 186 insertions(+)
 create mode 100644 drivers/clk/meson/rstc.c
drivers/clk/meson/Makefile +1 -0
index 8f102e4..a962d57 100644
@@ -5,3 +5,4 @@
 obj-y += clkc.o
 obj-y += meson6-clkc.o
 obj-y += clk-pll.o
+obj-$(CONFIG_RESET_CONTROLLER)  += rstc.o
drivers/clk/meson/clkc.h +15 -0
index 6c0f611..41e92df 100644
@@ -157,3 +157,18 @@ void meson_clk_register_pll_div(struct pll_div_conf *pll_div_conf,
 void meson_clk_register_clks(struct clk_conf *clk_confs,
 			     unsigned int nr_confs,
 			     void __iomem *clk_base);
+
+#ifdef CONFIG_RESET_CONTROLLER
+void meson_register_rstc(struct device_node *np, unsigned int num_regs,
+			 void __iomem *ao_base, void __iomem *ot_base,
+			 unsigned int ao_off_id, u8 flags);
+#else
+static inline void meson_register_rstc(struct device_node *np,
+				       unsigned int num_regs,
+				       void __iomem *ao_base,
+				       void __iomem *ot_base,
+				       unsigned int ao_off_id, u8 flags)
+{
+}
+#endif
+#endif /* __CLKC_H */
drivers/clk/meson/meson6-clkc.c +18 -0
index 9f809e1..177c6fa 100644
@@ -30,9 +30,16 @@
 #define MESON6_REG_DPLL_VID2	0x011c
 #define MESON6_REG_HPLL		0x0270
 #define MESON6_REG_HHI_MPEG	0x0174
+#define MESON6_REG_RSTC		0x0140
 
 #define MESON6_XTAL		"xtal"
 
+/*
+ * Every reset ID >= 163 is mapped to the AO domain register
+ */
+#define MESON6_RSTC_N_REGS	6
+#define MESON6_AO_OFF		((MESON6_RSTC_N_REGS - 1) * BITS_PER_LONG + 3)
+
 static struct pll_conf dpll_conf = PLL_CONF2(750, 1512, PARM(0x00, 0, 9),
 							PARM(0x00, 9, 5));
 
@@ -129,6 +136,7 @@ static struct clk_conf meson_clk_confs[] __initdata = {
 static void __init meson_clkc_init(struct device_node *np)
 {
 	void __iomem *clk_base;
+	void __iomem *ao_base;
 	u32 xtal_rate;
 
 	/* XTAL */
@@ -156,5 +164,15 @@ static void __init meson_clkc_init(struct device_node *np)
 				clk_base);
 	meson_clk_register_pll_divs(meson_pll_divs, ARRAY_SIZE(meson_pll_divs),
 				    clk_base);
+
+	/* Reset controller */
+	ao_base = of_iomap(np, 2);
+	if (!ao_base) {
+		pr_warn("%s: Unable to map ao domain base for reset controller\n", __func__);
+		return;
+	}
+
+	meson_register_rstc(np, MESON6_RSTC_N_REGS, ao_base,
+			    clk_base + MESON6_REG_RSTC, MESON6_AO_OFF, 0);
 }
 CLK_OF_DECLARE(meson6_clock, "amlogic,meson6-clkc", meson_clkc_init);
drivers/clk/meson/rstc.c new file +152 -0

152 lines not on this page · raw message

Signature · 1 line
1.9.1
#7 lore raw

PATCH 3/4 ARM: meson: enable reset controller in kconfig

In reply to Carlo Caione

Modify the arch Kconfig to enable the reset controller

---
 arch/arm/mach-meson/Kconfig | 2 ++
 1 file changed, 2 insertions(+)
arch/arm/mach-meson/Kconfig +2 -0
index 18301dc..af2ad93 100644
@@ -10,6 +10,8 @@ config MACH_MESON6
 	bool "Amlogic Meson6 (8726MX) SoCs support"
 	default ARCH_MESON
 	select MESON6_TIMER
+	select ARCH_HAS_RESET_CONTROLLER
+	select RESET_CONTROLLER
 
 config MACH_MESON8
 	bool "Amlogic Meson8 SoCs support"
Signature · 1 line
1.9.1
#8 lore raw

PATCH 4/4 ARM: meson: add documentation for reset/clock controller

In reply to Carlo Caione

Add documentation for the reset and clock controller

---
 .../bindings/clock/amlogic,meson6-clkc.txt         | 45 ++++++++++++++++++++++
 1 file changed, 45 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/amlogic,meson6-clkc.txt
Documentation/devicetree/bindings/clock/amlogic,meson6-clkc.txt new file +45 -0
new file mode 100644
index 0000000..b4a8813
@@ -0,0 +1,45 @@
+* Amlogic Meson6 Clock and Reset Unit
+
+The Amlogic Meson6 clock controller generates and supplies clock to various
+controllers within the SoC and also implements a reset controller for SoC
+peripherals.
+
+Required Properties:
+
+- compatible: should be "amlogic,meson6-clkc"
+- reg: it must be composed by three tuples:
+	0) physical base address of the xtal register and length of memory
+	   mapped region.
+	1) physical base address of the clock controller and length of memory
+	   mapped region.
+	2) physical base address of the AO domain reset register and length
+	   of memory mapped region.
+
+- #clock-cells: should be 1.
+- #reset-cells: should be 1.
+
+Each clock is assigned an identifier and client nodes can use this identifier
+to specify the clock which they consume. All available clocks are defined as
+preprocessor macros in the dt-bindings/clock/meson6-clkc.h header and can be
+used in device tree sources.
+
+Example: Clock controller node:
+
+	clkc: clock-controller at c1104000 {
+		#clock-cells = <1>;
+		#reset-cells = <1>;
+		compatible = "amlogic,meson6-clkc";
+		reg = <0xc1108000 0x4>, <0xc1104000 0x460>, <0xc8100040 0x4>;
+	};
+
+
+Example: UART controller node that consumes the clock generated by the clock
+  controller:
+
+	uart_AO: serial at c81004c0 {
+		compatible = "amlogic,meson-uart";
+		reg = <0xc81004c0 0x14>;
+		interrupts = <0 90 1>;
+		clocks = <&clkc CLKID_CLK81>;
+		status = "disabled";
+	};
Signature · 1 line
1.9.1