2020-11-11 16:34:20

by Sergio Paracuellos

[permalink] [raw]
Subject: [PATCH 0/7] MIPS: ralink: add CPU clock detection and clock gate driver for MT7621

This patchset ports CPU clock detection for MT7621 from OpenWrt
and adds a complete clock plan for the mt7621 SOC.

The documentation for this SOC only talks about two registers
regarding to the clocks:
* SYSC_REG_CPLL_CLKCFG0 - provides some information about boostrapped
refclock. PLL and dividers used for CPU and some sort of BUS (AHB?).
* SYSC_REG_CPLL_CLKCFG1 - a banch of gates to enable/disable clocks for
all or some ip cores.

No documentation about a probably existant set of dividers for each ip
core is included in the datasheets. So we cannot make anything better,
AFAICT.

Looking into driver code, there is another frequency which is used in
some drivers (uart, sd...) which for any reason is always hardcoded to
50 MHz. Taking this into account this patchset provides three main fixed
clocks to the SOC in 'mt7621-pll' which are:
- "cpu": with detected frequency (900 MHz in my board).
- "ahb": cpu / 4 = 225 Mhz.
- "apb": 50 Mhz.

PLL controller cannot be manipulatedbecause there is no info about
how to do it. Because of this, there is nothing related with registers
in the included binding.

It also provides a clock gate driver 'mt7621-clk' as a platform driver
to allow to enable and disable some clocks in the different ip cores.
The parent clocks for this clock gates have also set taking into account
existant device tree and driver code resulting in the followings:
- "hsdma": "ahb"
- "fe": "ahb"
- "sp_divtx": "ahb"
- "timer": "cpu"
- "int": "cpu"
- "mc": "ahb"
- "pcm": "ahb"
- "pio": "ahb"
- "gdma": "ahb"
- "nand": "ahb"
- "i2c": "ahb"
- "i2s": "ahb"
- "spi": "ahb"
- "uart1": "apb"
- "uart2": "apb"
- "uart3": "apb"
- "eth": "ahb"
- "pcie0": "ahb"
- "pcie1": "ahb"
- "pcie2": "ahb"
- "crypto": "ahb"
- "shxc": "ahb"

There was a previous attempt of doing this here[0] but the author
did not wanted to make assumptions of a clock plan for the platform.

I do really want this to be upstreamed so according to the comments
in previous attempt[0] from Oleksij Rempel I have tried to do this
by myself.

All of this patches have been tested in a GNUBee PC1 resulting in a
working platform.

[0]: https://www.lkml.org/lkml/2019/7/23/1044

Sergio Paracuellos (7):
dt-bindings: clock: add dt binding header for mt7621 clocks
dt: bindings: add mt7621-pll device tree binding documentation
dt: bindings: add mt7621-clk device tree binding documentation
MIPS: ralink: add clock device providing cpu/ahb/apb clock for mt7621
clk: ralink: add clock gate driver for mt7621 SoC
staging: mt7621-dts: make use of new 'mt7621-pll' and 'mt7621-clk'
MAINTAINERS: add MT7621 CLOCK maintainer

.../bindings/clock/mediatek,mt7621-clk.yaml | 52 ++++
.../bindings/clock/mediatek,mt7621-pll.yaml | 51 ++++
MAINTAINERS | 8 +
arch/mips/include/asm/mach-ralink/mt7621.h | 20 ++
arch/mips/ralink/mt7621.c | 87 ++++++
drivers/clk/Kconfig | 1 +
drivers/clk/Makefile | 1 +
drivers/clk/ralink/Kconfig | 14 +
drivers/clk/ralink/Makefile | 2 +
drivers/clk/ralink/clk-mt7621.c | 258 ++++++++++++++++++
drivers/staging/mt7621-dts/gbpc1.dts | 11 -
drivers/staging/mt7621-dts/mt7621.dtsi | 71 +++--
include/dt-bindings/clock/mt7621-clk.h | 39 +++
13 files changed, 567 insertions(+), 48 deletions(-)
create mode 100644 Documentation/devicetree/bindings/clock/mediatek,mt7621-clk.yaml
create mode 100644 Documentation/devicetree/bindings/clock/mediatek,mt7621-pll.yaml
create mode 100644 drivers/clk/ralink/Kconfig
create mode 100644 drivers/clk/ralink/Makefile
create mode 100644 drivers/clk/ralink/clk-mt7621.c
create mode 100644 include/dt-bindings/clock/mt7621-clk.h

--
2.25.1


2020-11-11 16:34:35

by Sergio Paracuellos

[permalink] [raw]
Subject: [PATCH 4/7] MIPS: ralink: add clock device providing cpu/ahb/apb clock for mt7621

For a long time the mt7621 uses a fixed cpu clock which causes a problem
if the cpu frequency is not 880MHz.
This patch adds cpu/ahb/apb clock calculation code and binds clocks to
mt7621-pll node.

Adapted from OpenWrt:
c7ca224299 ramips: fix cpu clock of mt7621 and add dt clk devices

Signed-off-by: Weijie Gao <[email protected]>
Signed-off-by: Chuanhong Guo <[email protected]>
Signed-off-by: Sergio Paracuellos <[email protected]>
---
arch/mips/include/asm/mach-ralink/mt7621.h | 20 +++++
arch/mips/ralink/mt7621.c | 87 ++++++++++++++++++++++
2 files changed, 107 insertions(+)

diff --git a/arch/mips/include/asm/mach-ralink/mt7621.h b/arch/mips/include/asm/mach-ralink/mt7621.h
index e1af1ba50bd8..a9f3febddf1c 100644
--- a/arch/mips/include/asm/mach-ralink/mt7621.h
+++ b/arch/mips/include/asm/mach-ralink/mt7621.h
@@ -17,6 +17,10 @@
#define SYSC_REG_CHIP_REV 0x0c
#define SYSC_REG_SYSTEM_CONFIG0 0x10
#define SYSC_REG_SYSTEM_CONFIG1 0x14
+#define SYSC_REG_CLKCFG0 0x2c
+#define SYSC_REG_CUR_CLK_STS 0x44
+
+#define MEMC_REG_CPU_PLL 0x648

#define CHIP_REV_PKG_MASK 0x1
#define CHIP_REV_PKG_SHIFT 16
@@ -24,6 +28,22 @@
#define CHIP_REV_VER_SHIFT 8
#define CHIP_REV_ECO_MASK 0xf

+#define XTAL_MODE_SEL_MASK 0x7
+#define XTAL_MODE_SEL_SHIFT 6
+
+#define CPU_CLK_SEL_MASK 0x3
+#define CPU_CLK_SEL_SHIFT 30
+
+#define CUR_CPU_FDIV_MASK 0x1f
+#define CUR_CPU_FDIV_SHIFT 8
+#define CUR_CPU_FFRAC_MASK 0x1f
+#define CUR_CPU_FFRAC_SHIFT 0
+
+#define CPU_PLL_PREDIV_MASK 0x3
+#define CPU_PLL_PREDIV_SHIFT 12
+#define CPU_PLL_FBDIV_MASK 0x7f
+#define CPU_PLL_FBDIV_SHIFT 4
+
#define MT7621_DRAM_BASE 0x0
#define MT7621_DDR2_SIZE_MIN 32
#define MT7621_DDR2_SIZE_MAX 256
diff --git a/arch/mips/ralink/mt7621.c b/arch/mips/ralink/mt7621.c
index ca0ac607b0f3..4fce37e5ea7a 100644
--- a/arch/mips/ralink/mt7621.c
+++ b/arch/mips/ralink/mt7621.c
@@ -9,12 +9,17 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/sys_soc.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <dt-bindings/clock/mt7621-clk.h>

#include <asm/mipsregs.h>
#include <asm/smp-ops.h>
#include <asm/mips-cps.h>
#include <asm/mach-ralink/ralink_regs.h>
#include <asm/mach-ralink/mt7621.h>
+#include <asm/time.h>

#include <pinmux.h>

@@ -105,11 +110,93 @@ static struct rt2880_pmx_group mt7621_pinmux_data[] = {
{ 0 }
};

+static struct clk *clks[MT7621_CLK_MAX];
+static struct clk_onecell_data clk_data = {
+ .clks = clks,
+ .clk_num = ARRAY_SIZE(clks),
+};
+
phys_addr_t mips_cpc_default_phys_base(void)
{
panic("Cannot detect cpc address");
}

+static struct clk *__init mt7621_add_sys_clkdev(
+ const char *id, const char *parent_id, unsigned long rate)
+{
+ struct clk *clk;
+ int err;
+
+ clk = clk_register_fixed_rate(NULL, id, parent_id, 0, rate);
+ if (IS_ERR(clk))
+ panic("failed to allocate %s clock structure", id);
+
+ err = clk_register_clkdev(clk, id, NULL);
+ if (err)
+ panic("unable to register %s clock device", id);
+
+ return clk;
+}
+
+#define MHZ(x) ((x) * 1000 * 1000)
+
+void __init ralink_clk_init(void)
+{
+ u32 syscfg, xtal_sel, clkcfg, clk_sel, curclk, ffiv, ffrac;
+ u32 pll, prediv, fbdiv;
+ u32 xtal_clk, cpu_clk, ahb_clk, apb_clk;
+ static const u32 prediv_tbl[] = { 0, 1, 2, 2 };
+
+ syscfg = rt_sysc_r32(SYSC_REG_SYSTEM_CONFIG0);
+ xtal_sel = (syscfg >> XTAL_MODE_SEL_SHIFT) & XTAL_MODE_SEL_MASK;
+
+ clkcfg = rt_sysc_r32(SYSC_REG_CLKCFG0);
+ clk_sel = (clkcfg >> CPU_CLK_SEL_SHIFT) & CPU_CLK_SEL_MASK;
+
+ curclk = rt_sysc_r32(SYSC_REG_CUR_CLK_STS);
+ ffiv = (curclk >> CUR_CPU_FDIV_SHIFT) & CUR_CPU_FDIV_MASK;
+ ffrac = (curclk >> CUR_CPU_FFRAC_SHIFT) & CUR_CPU_FFRAC_MASK;
+
+ if (xtal_sel <= 2)
+ xtal_clk = MHZ(20);
+ else if (xtal_sel <= 5)
+ xtal_clk = MHZ(40);
+ else
+ xtal_clk = MHZ(25);
+
+ switch (clk_sel) {
+ case 0:
+ cpu_clk = MHZ(500);
+ break;
+ case 1:
+ pll = rt_memc_r32(MEMC_REG_CPU_PLL);
+ fbdiv = (pll >> CPU_PLL_FBDIV_SHIFT) & CPU_PLL_FBDIV_MASK;
+ prediv = (pll >> CPU_PLL_PREDIV_SHIFT) & CPU_PLL_PREDIV_MASK;
+ cpu_clk = ((fbdiv + 1) * xtal_clk) >> prediv_tbl[prediv];
+ break;
+ default:
+ cpu_clk = xtal_clk;
+ }
+
+ cpu_clk = cpu_clk / ffiv * ffrac;
+ ahb_clk = cpu_clk / 4;
+ apb_clk = MHZ(50);
+
+ clks[MT7621_CLK_CPU] = mt7621_add_sys_clkdev("cpu", NULL, cpu_clk);
+ clks[MT7621_CLK_AHB] = mt7621_add_sys_clkdev("ahb", NULL, ahb_clk);
+ clks[MT7621_CLK_APB] = mt7621_add_sys_clkdev("apb", NULL, apb_clk);
+
+ pr_info("CPU Clock: %dMHz\n", cpu_clk / 1000000);
+ mips_hpt_frequency = cpu_clk / 2;
+}
+
+static void __init mt7621_clocks_init_dt(struct device_node *np)
+{
+ of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+}
+
+CLK_OF_DECLARE(ar7100, "mediatek,mt7621-pll", mt7621_clocks_init_dt);
+
void __init ralink_of_remap(void)
{
rt_sysc_membase = plat_of_remap_node("mtk,mt7621-sysc");
--
2.25.1

2020-11-11 16:34:53

by Sergio Paracuellos

[permalink] [raw]
Subject: [PATCH 6/7] staging: mt7621-dts: make use of new 'mt7621-pll' and 'mt7621-clk'

Clocks for SoC mt7621 have been properly integrated so there is
no need to declare fixed clocks at all in the device tree. Remove
all of them, add new device tree nodes for new mt7621-pll and mt7621-clk
and update the rest of the nodes to use them.

Signed-off-by: Sergio Paracuellos <[email protected]>
---
drivers/staging/mt7621-dts/gbpc1.dts | 11 ----
drivers/staging/mt7621-dts/mt7621.dtsi | 71 ++++++++++++--------------
2 files changed, 34 insertions(+), 48 deletions(-)

diff --git a/drivers/staging/mt7621-dts/gbpc1.dts b/drivers/staging/mt7621-dts/gbpc1.dts
index a7c0d3115d72..7716d0efe524 100644
--- a/drivers/staging/mt7621-dts/gbpc1.dts
+++ b/drivers/staging/mt7621-dts/gbpc1.dts
@@ -100,17 +100,6 @@ partition@50000 {
};
};

-&sysclock {
- compatible = "fixed-clock";
- /* This is normally 1/4 of cpuclock */
- clock-frequency = <225000000>;
-};
-
-&cpuclock {
- compatible = "fixed-clock";
- clock-frequency = <900000000>;
-};
-
&pcie {
pinctrl-names = "default";
pinctrl-0 = <&pcie_pins>;
diff --git a/drivers/staging/mt7621-dts/mt7621.dtsi b/drivers/staging/mt7621-dts/mt7621.dtsi
index 82aa93634eda..e615139d2ccb 100644
--- a/drivers/staging/mt7621-dts/mt7621.dtsi
+++ b/drivers/staging/mt7621-dts/mt7621.dtsi
@@ -1,5 +1,6 @@
#include <dt-bindings/interrupt-controller/mips-gic.h>
#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/clock/mt7621-clk.h>

/ {
#address-cells = <1>;
@@ -27,26 +28,16 @@ aliases {
serial0 = &uartlite;
};

- cpuclock: cpuclock@0 {
- #clock-cells = <0>;
- compatible = "fixed-clock";
-
- /* FIXME: there should be way to detect this */
- clock-frequency = <880000000>;
- };
-
- sysclock: sysclock@0 {
- #clock-cells = <0>;
- compatible = "fixed-clock";
-
- /* This is normally 1/4 of cpuclock */
- clock-frequency = <220000000>;
+ pll: pll {
+ compatible = "mediatek,mt7621-pll";
+ #clock-cells = <1>;
+ clock-output-names = "cpu", "ahb", "apb";
};

- mmc_clock: mmc_clock@0 {
- #clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <48000000>;
+ clkctrl: clkctrl {
+ compatible = "mediatek,mt7621-clk";
+ #clock-cells = <1>;
+ ralink,sysctl = <&sysc>;
};

mmc_fixed_3v3: fixedregulator@0 {
@@ -76,7 +67,7 @@ palmbus: palmbus@1E000000 {
#size-cells = <1>;

sysc: sysc@0 {
- compatible = "mtk,mt7621-sysc";
+ compatible = "mtk,mt7621-sysc", "syscon";
reg = <0x0 0x100>;
};

@@ -100,8 +91,8 @@ i2c: i2c@900 {
compatible = "mediatek,mt7621-i2c";
reg = <0x900 0x100>;

- clocks = <&sysclock>;
-
+ clocks = <&clkctrl MT7621_CLK_I2C>;
+ clock-names = "i2c";
resets = <&rstctrl 16>;
reset-names = "i2c";

@@ -118,8 +109,8 @@ i2s: i2s@a00 {
compatible = "mediatek,mt7621-i2s";
reg = <0xa00 0x100>;

- clocks = <&sysclock>;
-
+ clocks = <&clkctrl MT7621_CLK_I2S>;
+ clock-names = "i2s";
resets = <&rstctrl 17>;
reset-names = "i2s";

@@ -155,8 +146,8 @@ uartlite: uartlite@c00 {
compatible = "ns16550a";
reg = <0xc00 0x100>;

- clocks = <&sysclock>;
- clock-frequency = <50000000>;
+ clocks = <&clkctrl MT7621_CLK_UART1>;
+ clock-names = "uart1";

interrupt-parent = <&gic>;
interrupts = <GIC_SHARED 26 IRQ_TYPE_LEVEL_HIGH>;
@@ -172,7 +163,7 @@ spi0: spi@b00 {
compatible = "ralink,mt7621-spi";
reg = <0xb00 0x100>;

- clocks = <&sysclock>;
+ clocks = <&pll MT7621_CLK_AHB>;

resets = <&rstctrl 18>;
reset-names = "spi";
@@ -188,6 +179,8 @@ gdma: gdma@2800 {
compatible = "ralink,rt3883-gdma";
reg = <0x2800 0x800>;

+ clocks = <&clkctrl MT7621_CLK_GDMA>;
+ clock-names = "gdma";
resets = <&rstctrl 14>;
reset-names = "dma";

@@ -205,6 +198,8 @@ hsdma: hsdma@7000 {
compatible = "mediatek,mt7621-hsdma";
reg = <0x7000 0x1000>;

+ clocks = <&clkctrl MT7621_CLK_HSDMA>;
+ clock-names = "hsdma";
resets = <&rstctrl 5>;
reset-names = "hsdma";

@@ -315,11 +310,6 @@ rstctrl: rstctrl {
#reset-cells = <1>;
};

- clkctrl: clkctrl {
- compatible = "ralink,rt2880-clock";
- #clock-cells = <1>;
- };
-
sdhci: sdhci@1E130000 {
status = "disabled";

@@ -338,7 +328,8 @@ sdhci: sdhci@1E130000 {
pinctrl-0 = <&sdhci_pins>;
pinctrl-1 = <&sdhci_pins>;

- clocks = <&mmc_clock &mmc_clock>;
+ clocks = <&pll MT7621_CLK_APB>,
+ <&pll MT7621_CLK_APB>;
clock-names = "source", "hclk";

interrupt-parent = <&gic>;
@@ -353,7 +344,7 @@ xhci: xhci@1E1C0000 {
0x1e1d0700 0x0100>;
reg-names = "mac", "ippc";

- clocks = <&sysclock>;
+ clocks = <&pll MT7621_CLK_AHB>;
clock-names = "sys_ck";

interrupt-parent = <&gic>;
@@ -372,7 +363,7 @@ gic: interrupt-controller@1fbc0000 {
timer {
compatible = "mti,gic-timer";
interrupts = <GIC_LOCAL 1 IRQ_TYPE_NONE>;
- clocks = <&cpuclock>;
+ clocks = <&pll MT7621_CLK_CPU>;
};
};

@@ -385,6 +376,9 @@ nand: nand@1e003000 {
0x1e003800 0x800>;
#address-cells = <1>;
#size-cells = <1>;
+
+ clocks = <&clkctrl MT7621_CLK_NAND>;
+ clock-names = "nand";
};

ethsys: syscon@1e000000 {
@@ -398,8 +392,9 @@ ethernet: ethernet@1e100000 {
compatible = "mediatek,mt7621-eth";
reg = <0x1e100000 0x10000>;

- clocks = <&sysclock>;
- clock-names = "ethif";
+ clocks = <&pll MT7621_CLK_AHB>,
+ <&clkctrl MT7621_CLK_ETH>;
+ clock-names = "ethif", "eth";

#address-cells = <1>;
#size-cells = <0>;
@@ -532,7 +527,9 @@ GIC_SHARED 24 IRQ_TYPE_LEVEL_HIGH

resets = <&rstctrl 24 &rstctrl 25 &rstctrl 26>;
reset-names = "pcie0", "pcie1", "pcie2";
- clocks = <&clkctrl 24 &clkctrl 25 &clkctrl 26>;
+ clocks = <&clkctrl MT7621_CLK_PCIE0>,
+ <&clkctrl MT7621_CLK_PCIE1>,
+ <&clkctrl MT7621_CLK_PCIE2>;
clock-names = "pcie0", "pcie1", "pcie2";
phys = <&pcie0_phy 1>, <&pcie2_phy 0>;
phy-names = "pcie-phy0", "pcie-phy2";
--
2.25.1

2020-11-11 16:35:07

by Sergio Paracuellos

[permalink] [raw]
Subject: [PATCH 5/7] clk: ralink: add clock gate driver for mt7621 SoC

In mt7621 SoC register 'SYSC_REG_CPLL_CLKCFG1' allows to
handle a bunch of gates to enable/disable clocks for
all or some ip cores. Add a driver to properly handle them.
Parent clocks for this gates are not documented at all in
the SoC documentation so all of them have been assumed looking
into the clock frequencies used in its related driver code.
There are three main clocks which are "cpu", "ahb" and "apb"
from the 'mt7621-pll'.

The following parents are set to each GATE:
* "hsdma": "ahb"
* "fe": "ahb"
* "sp_divtx": "ahb"
* "timer": "cpu"
* "int": "cpu"
* "mc": "ahb"
* "pcm": "ahb"
* "pio": "ahb"
* "gdma": "ahb"
* "nand": "ahb"
* "i2c": "ahb"
* "i2s": "ahb"
* "spi": "ahb"
* "uart1": "apb"
* "uart2": "apb"
* "uart3": "apb"
* "eth": "ahb"
* "pcie0": "ahb"
* "pcie1": "ahb"
* "pcie2": "ahb"
* "crypto": "ahb"
* "shxc": "ahb"

With this information the clk driver will provide gate functionality
from a a set of hardcoded clocks allowing to define a nice device
tree without fixed clocks.

Signed-off-by: Sergio Paracuellos <[email protected]>
---
drivers/clk/Kconfig | 1 +
drivers/clk/Makefile | 1 +
drivers/clk/ralink/Kconfig | 14 ++
drivers/clk/ralink/Makefile | 2 +
drivers/clk/ralink/clk-mt7621.c | 258 ++++++++++++++++++++++++++++++++
5 files changed, 276 insertions(+)
create mode 100644 drivers/clk/ralink/Kconfig
create mode 100644 drivers/clk/ralink/Makefile
create mode 100644 drivers/clk/ralink/clk-mt7621.c

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index c715d4681a0b..5f94c4329033 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -372,6 +372,7 @@ source "drivers/clk/mediatek/Kconfig"
source "drivers/clk/meson/Kconfig"
source "drivers/clk/mvebu/Kconfig"
source "drivers/clk/qcom/Kconfig"
+source "drivers/clk/ralink/Kconfig"
source "drivers/clk/renesas/Kconfig"
source "drivers/clk/rockchip/Kconfig"
source "drivers/clk/samsung/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index da8fcf147eb1..6578e167b047 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -100,6 +100,7 @@ obj-$(CONFIG_COMMON_CLK_NXP) += nxp/
obj-$(CONFIG_MACH_PISTACHIO) += pistachio/
obj-$(CONFIG_COMMON_CLK_PXA) += pxa/
obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/
+obj-y += ralink/
obj-y += renesas/
obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/
diff --git a/drivers/clk/ralink/Kconfig b/drivers/clk/ralink/Kconfig
new file mode 100644
index 000000000000..7e8697327e0c
--- /dev/null
+++ b/drivers/clk/ralink/Kconfig
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# MediaTek Mt7621 Clock Driver
+#
+menu "Clock driver for mediatek mt7621 SoC"
+ depends on SOC_MT7621 || COMPILE_TEST
+
+config CLK_MT7621
+ bool "Clock driver for MediaTek MT7621"
+ depends on SOC_MT7621 || COMPILE_TEST
+ default SOC_MT7621
+ help
+ This driver supports MediaTek MT7621 basic clocks.
+endmenu
diff --git a/drivers/clk/ralink/Makefile b/drivers/clk/ralink/Makefile
new file mode 100644
index 000000000000..cf6f9216379d
--- /dev/null
+++ b/drivers/clk/ralink/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_CLK_MT7621) += clk-mt7621.o
diff --git a/drivers/clk/ralink/clk-mt7621.c b/drivers/clk/ralink/clk-mt7621.c
new file mode 100644
index 000000000000..f7279d784a36
--- /dev/null
+++ b/drivers/clk/ralink/clk-mt7621.c
@@ -0,0 +1,258 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Mediatek MT7621 Clock gate Driver
+ * Author: Sergio Paracuellos <[email protected]>
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk-provider.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <dt-bindings/clock/mt7621-clk.h>
+
+/* clock gate configuration register */
+#define SYSC_REG_CLKCFG1 0x30
+
+/* Gate register enable bits */
+#define MT7621_HSDMA_CLK_EN BIT(5)
+#define MT7621_FE_CLK_EN BIT(6)
+#define MT7621_SP_DIVTX_CLK_EN BIT(7)
+#define MT7621_TIMER_CLK_EN BIT(8)
+#define MT7621_INT_CLK_EN BIT(9)
+#define MT7621_MC_CLK_EN BIT(10)
+#define MT7621_PCM_CLK_EN BIT(11)
+#define MT7621_PIO_CLK_EN BIT(13)
+#define MT7621_GDMA_CLK_EN BIT(14)
+#define MT7621_NAND_CLK_EN BIT(15)
+#define MT7621_I2C_CLK_EN BIT(16)
+#define MT7621_I2S_CLK_EN BIT(17)
+#define MT7621_SPI_CLK_EN BIT(18)
+#define MT7621_UART1_CLK_EN BIT(19)
+#define MT7621_UART2_CLK_EN BIT(20)
+#define MT7621_UART3_CLK_EN BIT(21)
+#define MT7621_ETH_CLK_EN BIT(23)
+#define MT7621_PCIE0_CLK_EN BIT(24)
+#define MT7621_PCIE1_CLK_EN BIT(25)
+#define MT7621_PCIE2_CLK_EN BIT(26)
+#define MT7621_CRYPTO_CLK_EN BIT(29)
+#define MT7621_SHXC_CLK_EN BIT(30)
+
+struct mt7621_clk_provider {
+ struct device_node *node;
+ struct device *dev;
+ struct regmap *syscon_regmap;
+ struct clk_hw_onecell_data *clk_data;
+};
+
+struct mt7621_gate {
+ u8 idx;
+ const char *name;
+ const char *parent_name;
+ struct mt7621_clk_provider *clk_prov;
+ struct clk_hw hw;
+ u32 bit_idx;
+};
+
+struct mt7621_gate_data {
+ u8 idx;
+ const char *name;
+ const char *parent_name;
+ u32 bit_idx;
+};
+
+#define GATE(_id, _name, _pname, _shift) \
+ { \
+ .idx = _id, \
+ .name = _name, \
+ .parent_name = _pname, \
+ .bit_idx = _shift \
+ }
+
+static const struct mt7621_gate mt7621_gates[] = {
+ GATE(MT7621_CLK_HSDMA, "hsdma", "ahb", MT7621_HSDMA_CLK_EN),
+ GATE(MT7621_CLK_FE, "fe", "ahb", MT7621_FE_CLK_EN),
+ GATE(MT7621_CLK_SP_DIVTX, "sp_divtx", "ahb", MT7621_SP_DIVTX_CLK_EN),
+ GATE(MT7621_CLK_TIMER, "timer", "cpu", MT7621_TIMER_CLK_EN),
+ GATE(MT7621_CLK_INT, "int", "cpu", MT7621_INT_CLK_EN),
+ GATE(MT7621_CLK_MC, "mc", "ahb", MT7621_MC_CLK_EN),
+ GATE(MT7621_CLK_PCM, "pcm", "ahb", MT7621_PCM_CLK_EN),
+ GATE(MT7621_CLK_PIO, "pio", "ahb", MT7621_PIO_CLK_EN),
+ GATE(MT7621_CLK_GDMA, "gdma", "ahb", MT7621_GDMA_CLK_EN),
+ GATE(MT7621_CLK_NAND, "nand", "ahb", MT7621_NAND_CLK_EN),
+ GATE(MT7621_CLK_I2C, "i2c", "ahb", MT7621_I2C_CLK_EN),
+ GATE(MT7621_CLK_I2S, "i2s", "ahb", MT7621_I2S_CLK_EN),
+ GATE(MT7621_CLK_SPI, "spi", "ahb", MT7621_SPI_CLK_EN),
+ GATE(MT7621_CLK_UART1, "uart1", "apb", MT7621_UART1_CLK_EN),
+ GATE(MT7621_CLK_UART2, "uart2", "apb", MT7621_UART2_CLK_EN),
+ GATE(MT7621_CLK_UART3, "uart3", "apb", MT7621_UART3_CLK_EN),
+ GATE(MT7621_CLK_ETH, "eth", "ahb", MT7621_ETH_CLK_EN),
+ GATE(MT7621_CLK_PCIE0, "pcie0", "ahb", MT7621_PCIE0_CLK_EN),
+ GATE(MT7621_CLK_PCIE1, "pcie1", "ahb", MT7621_PCIE1_CLK_EN),
+ GATE(MT7621_CLK_PCIE2, "pcie2", "ahb", MT7621_PCIE2_CLK_EN),
+ GATE(MT7621_CLK_CRYPTO, "crypto", "ahb", MT7621_CRYPTO_CLK_EN),
+ GATE(MT7621_CLK_SHXC, "shxc", "ahb", MT7621_SHXC_CLK_EN)
+};
+
+static inline struct mt7621_gate *to_mt7621_gate(struct clk_hw *hw)
+{
+ return container_of(hw, struct mt7621_gate, hw);
+}
+
+static int mt7621_gate_enable(struct clk_hw *hw)
+{
+ struct mt7621_gate *clk_gate = to_mt7621_gate(hw);
+ struct regmap *scon = clk_gate->clk_prov->syscon_regmap;
+
+ return regmap_update_bits(scon, SYSC_REG_CLKCFG1,
+ clk_gate->bit_idx, clk_gate->bit_idx);
+}
+
+static void mt7621_gate_disable(struct clk_hw *hw)
+{
+ struct mt7621_gate *clk_gate = to_mt7621_gate(hw);
+ struct regmap *scon = clk_gate->clk_prov->syscon_regmap;
+
+ regmap_update_bits(scon, SYSC_REG_CLKCFG1, clk_gate->bit_idx, 0);
+}
+
+static int mt7621_gate_is_enabled(struct clk_hw *hw)
+{
+ struct mt7621_gate *clk_gate = to_mt7621_gate(hw);
+ struct regmap *scon = clk_gate->clk_prov->syscon_regmap;
+ unsigned int val;
+
+ if (regmap_read(scon, SYSC_REG_CLKCFG1, &val))
+ return 0;
+
+ return val & clk_gate->bit_idx;
+}
+
+static const struct clk_ops mt7621_gate_ops = {
+ .enable = mt7621_gate_enable,
+ .disable = mt7621_gate_disable,
+ .is_enabled = mt7621_gate_is_enabled,
+};
+
+static int mt7621_gate_ops_init(struct device *dev, struct mt7621_gate *sclk)
+{
+ struct clk_init_data init = {
+ .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+ .num_parents = 1,
+ .parent_names = &sclk->parent_name,
+ .ops = &mt7621_gate_ops,
+ .name = sclk->name,
+ };
+
+ sclk->hw.init = &init;
+ return devm_clk_hw_register(dev, &sclk->hw);
+}
+
+static int mt7621_register_gates(struct mt7621_clk_provider *clk_prov)
+{
+ struct clk_hw_onecell_data **clk_data = &clk_prov->clk_data;
+ struct device *dev = clk_prov->dev;
+ int idx, err, count;
+ struct clk_hw **hws;
+
+ count = ARRAY_SIZE(mt7621_gates);
+ *clk_data = devm_kzalloc(dev, struct_size(*clk_data, hws, count),
+ GFP_KERNEL);
+ if (!*clk_data)
+ return -ENOMEM;
+
+ (*clk_data)->num = count;
+ hws = (*clk_data)->hws;
+
+ for (idx = 0; idx < ARRAY_SIZE(mt7621_gates); idx++) {
+ struct mt7621_gate *sclk;
+
+ sclk = devm_kzalloc(dev, sizeof(*sclk), GFP_KERNEL);
+ if (!sclk)
+ return -ENOMEM;
+
+ sclk->idx = mt7621_gates[idx].idx;
+ sclk->name = mt7621_gates[idx].name;
+ sclk->parent_name = mt7621_gates[idx].parent_name;
+ sclk->bit_idx = mt7621_gates[idx].bit_idx;
+ sclk->clk_prov = clk_prov;
+
+ err = mt7621_gate_ops_init(dev, sclk);
+ if (err) {
+ dev_err(dev, "failed to register clock %d\n", idx);
+ devm_kfree(dev, sclk);
+ hws[idx] = NULL;
+ } else {
+ dev_info(dev, "Registered clock gate: %s\n",
+ mt7621_gates[idx].name);
+ hws[idx] = &sclk->hw;
+ }
+ }
+
+ return 0;
+}
+
+static int mt7621_clk_init(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *node = pdev->dev.of_node;
+ struct mt7621_clk_provider *clk_provider;
+ int ret;
+
+ clk_provider = devm_kzalloc(dev, sizeof(*clk_provider), GFP_KERNEL);
+ if (!clk_provider)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, clk_provider);
+ clk_provider->syscon_regmap = syscon_regmap_lookup_by_phandle(node, "ralink,sysctl");
+ if (IS_ERR(clk_provider->syscon_regmap)) {
+ dev_err(dev, "Could not get syscon regmap\n");
+ return -EINVAL;
+ }
+
+ clk_provider->node = node;
+ clk_provider->dev = dev;
+
+ ret = mt7621_register_gates(clk_provider);
+ if (ret) {
+ dev_err(dev, "Error registering gates\n");
+ return ret;
+ }
+
+ return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
+ clk_provider->clk_data);
+}
+
+static int clk_mt7621_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ int ret;
+
+ ret = mt7621_clk_init(pdev);
+ if (ret) {
+ dev_err(dev, "Could not register clock provider: %s: %d\n",
+ pdev->name, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id of_match_clk_mt7621[] = {
+ { .compatible = "mediatek,mt7621-clk", .data = mt7621_clk_init },
+ {}
+};
+
+static struct platform_driver clk_mt7621_drv = {
+ .probe = clk_mt7621_probe,
+ .driver = {
+ .name = "clk-mt7621",
+ .of_match_table = of_match_clk_mt7621,
+ },
+};
+builtin_platform_driver(clk_mt7621_drv);
+
+MODULE_AUTHOR("Sergio Paracuellos <[email protected]>");
+MODULE_DESCRIPTION("Mediatek Mt7621 clock gate driver");
+MODULE_LICENSE("GPL v2");
--
2.25.1

2020-11-12 01:46:00

by Chuanhong Guo

[permalink] [raw]
Subject: Re: [PATCH 0/7] MIPS: ralink: add CPU clock detection and clock gate driver for MT7621

Hi!

On Thu, Nov 12, 2020 at 12:30 AM Sergio Paracuellos
<[email protected]> wrote:
>
> This patchset ports CPU clock detection for MT7621 from OpenWrt
> and adds a complete clock plan for the mt7621 SOC.
>
> The documentation for this SOC only talks about two registers
> regarding to the clocks:
> * SYSC_REG_CPLL_CLKCFG0 - provides some information about boostrapped
> refclock. PLL and dividers used for CPU and some sort of BUS (AHB?).
> * SYSC_REG_CPLL_CLKCFG1 - a banch of gates to enable/disable clocks for
> all or some ip cores.
>
> No documentation about a probably existant set of dividers for each ip
> core is included in the datasheets. So we cannot make anything better,
> AFAICT.
>
> Looking into driver code, there is another frequency which is used in
> some drivers (uart, sd...) which for any reason is always hardcoded to
> 50 MHz. Taking this into account this patchset provides three main fixed
> clocks to the SOC in 'mt7621-pll' which are:
> - "cpu": with detected frequency (900 MHz in my board).
> - "ahb": cpu / 4 = 225 Mhz.
> - "apb": 50 Mhz.
>
> PLL controller cannot be manipulatedbecause there is no info about
> how to do it. Because of this, there is nothing related with registers
> in the included binding.
>
> It also provides a clock gate driver 'mt7621-clk' as a platform driver
> to allow to enable and disable some clocks in the different ip cores.
> The parent clocks for this clock gates have also set taking into account
> existant device tree and driver code resulting in the followings:
> - "hsdma": "ahb"
> - "fe": "ahb"
> - "sp_divtx": "ahb"
> - "timer": "cpu"
> - "int": "cpu"
> - "mc": "ahb"
> - "pcm": "ahb"
> - "pio": "ahb"
> - "gdma": "ahb"
> - "nand": "ahb"
> - "i2c": "ahb"
> - "i2s": "ahb"
> - "spi": "ahb"
> - "uart1": "apb"
> - "uart2": "apb"
> - "uart3": "apb"
> - "eth": "ahb"
> - "pcie0": "ahb"
> - "pcie1": "ahb"
> - "pcie2": "ahb"
> - "crypto": "ahb"
> - "shxc": "ahb"
>
> There was a previous attempt of doing this here[0] but the author
> did not wanted to make assumptions of a clock plan for the platform.

I've already said in previous threads that clock assignment in
current linux kernel is not trustworthy.
I've got the clock plan for mt7621 now. (Can't share it, sorry.)
Most of your clock assumptions above are incorrect.
I've made a clock driver with gate support a few months ago.[0]
but I don't have much time to really finish it.
Maybe you could rework your clock gate driver based on it.

[0] https://github.com/981213/linux/commit/2eca1f045e4c3db18c941135464c0d7422ad8133
--
Regards,
Chuanhong Guo

2020-11-12 05:41:25

by Sergio Paracuellos

[permalink] [raw]
Subject: Re: [PATCH 0/7] MIPS: ralink: add CPU clock detection and clock gate driver for MT7621

Hi Chuanhong,

On Thu, Nov 12, 2020 at 2:26 AM Chuanhong Guo <[email protected]> wrote:
[snip]
>
> I've already said in previous threads that clock assignment in
> current linux kernel is not trustworthy.
> I've got the clock plan for mt7621 now. (Can't share it, sorry.)
> Most of your clock assumptions above are incorrect.

Well, that was of course expected, without a real clock plan this
driver was only taking into account Oleksij Rempel suggestions to try
to make a driver good enough to properly be maintained :).

> I've made a clock driver with gate support a few months ago.[0]
> but I don't have much time to really finish it.
> Maybe you could rework your clock gate driver based on it.
>
> [0] https://github.com/981213/linux/commit/2eca1f045e4c3db18c941135464c0d7422ad8133

Thanks for the link, I see there are three more clocks there with
frequencies of 125, 250 and 270 Mhz. all of them having main xtal as
parent. Ok, I will take this real information into account and will
send v2 after a bit of more feedback comes.

> --
> Regards,
> Chuanhong Guo

Best regards,
Sergio Paracuellos

2020-11-12 05:42:08

by Sergio Paracuellos

[permalink] [raw]
Subject: Re: [PATCH 0/7] MIPS: ralink: add CPU clock detection and clock gate driver for MT7621

Hi,

On Thu, Nov 12, 2020 at 2:34 AM Chuanhong Guo <[email protected]> wrote:
>
> On Thu, Nov 12, 2020 at 9:26 AM Chuanhong Guo <[email protected]> wrote:
> >
> > I've already said in previous threads that clock assignment in
> > current linux kernel is not trustworthy.
> > I've got the clock plan for mt7621 now. (Can't share it, sorry.)
> > Most of your clock assumptions above are incorrect.
> > I've made a clock driver with gate support a few months ago.[0]
> > but I don't have much time to really finish it.
> > Maybe you could rework your clock gate driver based on it.
> >
> > [0] https://github.com/981213/linux/commit/2eca1f045e4c3db18c941135464c0d7422ad8133
>
> hsdma/eth/pio clocks are still missing in mediatek doc and
> I just made them up in the driver. Correct clock frequency for
> them aren't really important for them to work though.
> And another part I didn't finish is checking clock support for
> every drivers mt7621 used. Many drivers don't explicitly
> enable the clock and may be problematic when kernel
> gates unused clocks.
>

Well, I think they are not important either. Also, by default gate
register has all the gate bits enabled. When a gate driver is added,
the kernel by default will try to disable those clocks that haven't
been requested. To avoid weird behaviour because of some drivers are
not using properly clocks we have the CLK_IGNORED_UNUSED, which as you
can see is currently being used in my code. Using that all seems to
work as expected as it is now.

> --
> Regards,
> Chuanhong Guo

Best regards,
Sergio Paracuellos

2020-11-12 05:47:32

by Chuanhong Guo

[permalink] [raw]
Subject: Re: [PATCH 0/7] MIPS: ralink: add CPU clock detection and clock gate driver for MT7621

On Thu, Nov 12, 2020 at 9:26 AM Chuanhong Guo <[email protected]> wrote:
>
> I've already said in previous threads that clock assignment in
> current linux kernel is not trustworthy.
> I've got the clock plan for mt7621 now. (Can't share it, sorry.)
> Most of your clock assumptions above are incorrect.
> I've made a clock driver with gate support a few months ago.[0]
> but I don't have much time to really finish it.
> Maybe you could rework your clock gate driver based on it.
>
> [0] https://github.com/981213/linux/commit/2eca1f045e4c3db18c941135464c0d7422ad8133

hsdma/eth/pio clocks are still missing in mediatek doc and
I just made them up in the driver. Correct clock frequency for
them aren't really important for them to work though.
And another part I didn't finish is checking clock support for
every drivers mt7621 used. Many drivers don't explicitly
enable the clock and may be problematic when kernel
gates unused clocks.

--
Regards,
Chuanhong Guo

2020-11-13 00:44:40

by Chuanhong Guo

[permalink] [raw]
Subject: Re: [PATCH 0/7] MIPS: ralink: add CPU clock detection and clock gate driver for MT7621

On Thu, Nov 12, 2020 at 1:23 PM Sergio Paracuellos
<[email protected]> wrote:
>
> To avoid weird behaviour because of some drivers are
> not using properly clocks we have the CLK_IGNORED_UNUSED, which as you
> can see is currently being used in my code. Using that all seems to
> work as expected as it is now.

The whole point of having a clock gate driver is to gate unused
clocks to save (maybe a tiny bit of) power. It's other peripheral
drivers' fault that it doesn't enable clocks properly and we shouldn't
just work-around the problem in the clock driver by disallowing auto
clock gating.

--
Regards,
Chuanhong Guo

2020-11-13 05:35:08

by Sergio Paracuellos

[permalink] [raw]
Subject: Re: [PATCH 0/7] MIPS: ralink: add CPU clock detection and clock gate driver for MT7621

On Fri, Nov 13, 2020 at 1:40 AM Chuanhong Guo <[email protected]> wrote:
>
> On Thu, Nov 12, 2020 at 1:23 PM Sergio Paracuellos
> <[email protected]> wrote:
> >
> > To avoid weird behaviour because of some drivers are
> > not using properly clocks we have the CLK_IGNORED_UNUSED, which as you
> > can see is currently being used in my code. Using that all seems to
> > work as expected as it is now.
>
> The whole point of having a clock gate driver is to gate unused
> clocks to save (maybe a tiny bit of) power. It's other peripheral
> drivers' fault that it doesn't enable clocks properly and we shouldn't
> just work-around the problem in the clock driver by disallowing auto
> clock gating.
>

Totally agreed with what you are saying here but I don't really think
using the flag is a workaround. It is just a way to ensure no
regressions occurred until all drivers are adapted and also having all
of them enabled is the behaviour. For me adapt the rest of driver code
should be a different patch set after this driver is properly
finished and mainlined.

> --
> Regards,
> Chuanhong Guo

Best regards,
Sergio Paracuellos