diff options
author | Stephen Boyd <sboyd@kernel.org> | 2021-02-04 22:30:22 +0300 |
---|---|---|
committer | Stephen Boyd <sboyd@kernel.org> | 2021-02-04 22:30:22 +0300 |
commit | 7907e69f31a51df9f20a3a2856d3cee912a1c186 (patch) | |
tree | fcd248cd0634053b738aaa39b432285a0484c77f /drivers/clk | |
parent | 5c8fe583cce542aa0b84adc939ce85293de36e5e (diff) | |
parent | 24ece96554a963d5eab597be7d65a1812d854d10 (diff) | |
download | linux-7907e69f31a51df9f20a3a2856d3cee912a1c186.tar.xz |
Merge tag 'renesas-clk-for-v5.12-tag2' of git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers into clk-renesas
Pull Renesas clk driver updates from Geert Uytterhoeven:
- Add I2c and Ethernet (RAVB) clocks on R-Car V3U
- Fix a kerneldoc issue
- Add timer (TMU) clocks on most R-Car Gen3 SoCs
- Add video-related (FCPVD/VSPD/VSPX), watchdog (RWDT), serial
(HSCIF), pincontrol/GPIO (PFC/GPIO), SPI (MSIOF), SDHI, and DMA
(SYS-DMAC) clocks on R-Car V3U
- Add support for the USB 2.0 clock selector on RZ/G2 SoCs
- Minor fixes and improvements
* tag 'renesas-clk-for-v5.12-tag2' of git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers: (21 commits)
clk: renesas: cpg-mssr: Fix formatting issues for 'smstpcr_saved's documentation
clk: renesas: r8a779a0: Add RAVB clocks
clk: renesas: r8a779a0: Add I2C clocks
dt-bindings: clock: renesas: rcar-usb2-clock-sel: Add support for RZ/G2 M/N/H
clk: renesas: r8a779a0: Add SYS-DMAC clocks
clk: renesas: r8a779a0: Add SDHI support
clk: renesas: rcar-gen3: Factor out CPG library
clk: renesas: rcar-gen3: Remove cpg_quirks access when registering SD clock
clk: renesas: r8a779a0: Add MSIOF clocks
clk: renesas: r8a779a0: Add PFC/GPIO clocks
clk: renesas: r8a779a0: Fix parent of CBFUSA clock
clk: renesas: r8a779a0: Remove non-existent S2 clock
clk: renesas: r8a779a0: Add HSCIF support
clk: renesas: r8a779a0: Add RWDT clocks
clk: renesas: r8a779a0: Add VSPX clock support
clk: renesas: r8a779a0: Add VSPD clock support
clk: renesas: r8a779a0: Add FCPVD clock support
clk: renesas: r8a77995: Add TMU clocks
clk: renesas: r8a77990: Add TMU clocks
clk: renesas: r8a77965: Add TMU clocks
...
Diffstat (limited to 'drivers/clk')
-rw-r--r-- | drivers/clk/renesas/Kconfig | 5 | ||||
-rw-r--r-- | drivers/clk/renesas/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/renesas/r8a7796-cpg-mssr.c | 5 | ||||
-rw-r--r-- | drivers/clk/renesas/r8a77965-cpg-mssr.c | 5 | ||||
-rw-r--r-- | drivers/clk/renesas/r8a77990-cpg-mssr.c | 5 | ||||
-rw-r--r-- | drivers/clk/renesas/r8a77995-cpg-mssr.c | 5 | ||||
-rw-r--r-- | drivers/clk/renesas/r8a779a0-cpg-mssr.c | 67 | ||||
-rw-r--r-- | drivers/clk/renesas/rcar-cpg-lib.c | 270 | ||||
-rw-r--r-- | drivers/clk/renesas/rcar-cpg-lib.h | 33 | ||||
-rw-r--r-- | drivers/clk/renesas/rcar-gen3-cpg.c | 267 | ||||
-rw-r--r-- | drivers/clk/renesas/renesas-cpg-mssr.c | 4 |
11 files changed, 403 insertions, 264 deletions
diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig index 18915d668a30..607e64a17d72 100644 --- a/drivers/clk/renesas/Kconfig +++ b/drivers/clk/renesas/Kconfig @@ -148,6 +148,7 @@ config CLK_R8A77995 config CLK_R8A779A0 bool "R-Car V3U clock support" if COMPILE_TEST + select CLK_RCAR_CPG_LIB select CLK_RENESAS_CPG_MSSR config CLK_R9A06G032 @@ -162,12 +163,16 @@ config CLK_SH73A0 # Family +config CLK_RCAR_CPG_LIB + bool "CPG/MSSR library functions" if COMPILE_TEST + config CLK_RCAR_GEN2_CPG bool "R-Car Gen2 CPG clock support" if COMPILE_TEST select CLK_RENESAS_CPG_MSSR config CLK_RCAR_GEN3_CPG bool "R-Car Gen3 and RZ/G2 CPG clock support" if COMPILE_TEST + select CLK_RCAR_CPG_LIB select CLK_RENESAS_CPG_MSSR config CLK_RCAR_USB2_CLOCK_SEL diff --git a/drivers/clk/renesas/Makefile b/drivers/clk/renesas/Makefile index c803912ef2ce..ef0d2bba92bf 100644 --- a/drivers/clk/renesas/Makefile +++ b/drivers/clk/renesas/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_CLK_R9A06G032) += r9a06g032-clocks.o obj-$(CONFIG_CLK_SH73A0) += clk-sh73a0.o # Family +obj-$(CONFIG_CLK_RCAR_CPG_LIB) += rcar-cpg-lib.o obj-$(CONFIG_CLK_RCAR_GEN2_CPG) += rcar-gen2-cpg.o obj-$(CONFIG_CLK_RCAR_GEN3_CPG) += rcar-gen3-cpg.o obj-$(CONFIG_CLK_RCAR_USB2_CLOCK_SEL) += rcar-usb2-clock-sel.o diff --git a/drivers/clk/renesas/r8a7796-cpg-mssr.c b/drivers/clk/renesas/r8a7796-cpg-mssr.c index 2cd6e3876fbd..41593c126faf 100644 --- a/drivers/clk/renesas/r8a7796-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7796-cpg-mssr.c @@ -128,6 +128,11 @@ static const struct cpg_core_clk r8a7796_core_clks[] __initconst = { static struct mssr_mod_clk r8a7796_mod_clks[] __initdata = { DEF_MOD("fdp1-0", 119, R8A7796_CLK_S0D1), + DEF_MOD("tmu4", 121, R8A7796_CLK_S0D6), + DEF_MOD("tmu3", 122, R8A7796_CLK_S3D2), + DEF_MOD("tmu2", 123, R8A7796_CLK_S3D2), + DEF_MOD("tmu1", 124, R8A7796_CLK_S3D2), + DEF_MOD("tmu0", 125, R8A7796_CLK_CP), DEF_MOD("scif5", 202, R8A7796_CLK_S3D4), DEF_MOD("scif4", 203, R8A7796_CLK_S3D4), DEF_MOD("scif3", 204, R8A7796_CLK_S3D4), diff --git a/drivers/clk/renesas/r8a77965-cpg-mssr.c b/drivers/clk/renesas/r8a77965-cpg-mssr.c index 2b55a06ac5cf..46a157732759 100644 --- a/drivers/clk/renesas/r8a77965-cpg-mssr.c +++ b/drivers/clk/renesas/r8a77965-cpg-mssr.c @@ -123,6 +123,11 @@ static const struct cpg_core_clk r8a77965_core_clks[] __initconst = { static const struct mssr_mod_clk r8a77965_mod_clks[] __initconst = { DEF_MOD("fdp1-0", 119, R8A77965_CLK_S0D1), + DEF_MOD("tmu4", 121, R8A77965_CLK_S0D6), + DEF_MOD("tmu3", 122, R8A77965_CLK_S3D2), + DEF_MOD("tmu2", 123, R8A77965_CLK_S3D2), + DEF_MOD("tmu1", 124, R8A77965_CLK_S3D2), + DEF_MOD("tmu0", 125, R8A77965_CLK_CP), DEF_MOD("scif5", 202, R8A77965_CLK_S3D4), DEF_MOD("scif4", 203, R8A77965_CLK_S3D4), DEF_MOD("scif3", 204, R8A77965_CLK_S3D4), diff --git a/drivers/clk/renesas/r8a77990-cpg-mssr.c b/drivers/clk/renesas/r8a77990-cpg-mssr.c index 2b97ab61d044..2d172f80b34c 100644 --- a/drivers/clk/renesas/r8a77990-cpg-mssr.c +++ b/drivers/clk/renesas/r8a77990-cpg-mssr.c @@ -124,6 +124,11 @@ static const struct cpg_core_clk r8a77990_core_clks[] __initconst = { }; static const struct mssr_mod_clk r8a77990_mod_clks[] __initconst = { + DEF_MOD("tmu4", 121, R8A77990_CLK_S0D6C), + DEF_MOD("tmu3", 122, R8A77990_CLK_S3D2C), + DEF_MOD("tmu2", 123, R8A77990_CLK_S3D2C), + DEF_MOD("tmu1", 124, R8A77990_CLK_S3D2C), + DEF_MOD("tmu0", 125, R8A77990_CLK_CP), DEF_MOD("scif5", 202, R8A77990_CLK_S3D4C), DEF_MOD("scif4", 203, R8A77990_CLK_S3D4C), DEF_MOD("scif3", 204, R8A77990_CLK_S3D4C), diff --git a/drivers/clk/renesas/r8a77995-cpg-mssr.c b/drivers/clk/renesas/r8a77995-cpg-mssr.c index 5b4691117b47..9cfd00cf4e69 100644 --- a/drivers/clk/renesas/r8a77995-cpg-mssr.c +++ b/drivers/clk/renesas/r8a77995-cpg-mssr.c @@ -111,6 +111,11 @@ static const struct cpg_core_clk r8a77995_core_clks[] __initconst = { }; static const struct mssr_mod_clk r8a77995_mod_clks[] __initconst = { + DEF_MOD("tmu4", 121, R8A77995_CLK_S1D4C), + DEF_MOD("tmu3", 122, R8A77995_CLK_S3D2C), + DEF_MOD("tmu2", 123, R8A77995_CLK_S3D2C), + DEF_MOD("tmu1", 124, R8A77995_CLK_S3D2C), + DEF_MOD("tmu0", 125, R8A77995_CLK_CP), DEF_MOD("scif5", 202, R8A77995_CLK_S3D4C), DEF_MOD("scif4", 203, R8A77995_CLK_S3D4C), DEF_MOD("scif3", 204, R8A77995_CLK_S3D4C), diff --git a/drivers/clk/renesas/r8a779a0-cpg-mssr.c b/drivers/clk/renesas/r8a779a0-cpg-mssr.c index aa5389b04d74..f23fe9d5e5e1 100644 --- a/drivers/clk/renesas/r8a779a0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a779a0-cpg-mssr.c @@ -25,6 +25,7 @@ #include <dt-bindings/clock/r8a779a0-cpg-mssr.h> +#include "rcar-cpg-lib.h" #include "renesas-cpg-mssr.h" enum rcar_r8a779a0_clk_types { @@ -32,6 +33,7 @@ enum rcar_r8a779a0_clk_types { CLK_TYPE_R8A779A0_PLL1, CLK_TYPE_R8A779A0_PLL2X_3X, /* PLL[23][01] */ CLK_TYPE_R8A779A0_PLL5, + CLK_TYPE_R8A779A0_SD, CLK_TYPE_R8A779A0_MDSEL, /* Select parent/divider using mode pin */ CLK_TYPE_R8A779A0_OSC, /* OSC EXTAL predivider and fixed divider */ }; @@ -69,7 +71,6 @@ enum clk_ids { CLK_PLL5_DIV2, CLK_PLL5_DIV4, CLK_S1, - CLK_S2, CLK_S3, CLK_SDSRC, CLK_RPCSRC, @@ -83,6 +84,9 @@ enum clk_ids { DEF_BASE(_name, _id, CLK_TYPE_R8A779A0_PLL2X_3X, CLK_MAIN, \ .offset = _offset) +#define DEF_SD(_name, _id, _parent, _offset) \ + DEF_BASE(_name, _id, CLK_TYPE_R8A779A0_SD, _parent, .offset = _offset) + #define DEF_MDSEL(_name, _id, _md, _parent0, _div0, _parent1, _div1) \ DEF_BASE(_name, _id, CLK_TYPE_R8A779A0_MDSEL, \ (_parent0) << 16 | (_parent1), \ @@ -114,6 +118,7 @@ static const struct cpg_core_clk r8a779a0_core_clks[] __initconst = { DEF_FIXED(".pll5_div4", CLK_PLL5_DIV4, CLK_PLL5_DIV2, 2, 1), DEF_FIXED(".s1", CLK_S1, CLK_PLL1_DIV2, 2, 1), DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 4, 1), + DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL5_DIV4, 1, 1), DEF_RATE(".oco", CLK_OCO, 32768), /* Core Clock Outputs */ @@ -137,7 +142,10 @@ static const struct cpg_core_clk r8a779a0_core_clks[] __initconst = { DEF_FIXED("icu", R8A779A0_CLK_ICU, CLK_PLL5_DIV4, 2, 1), DEF_FIXED("icud2", R8A779A0_CLK_ICUD2, CLK_PLL5_DIV4, 4, 1), DEF_FIXED("vcbus", R8A779A0_CLK_VCBUS, CLK_PLL5_DIV4, 1, 1), - DEF_FIXED("cbfusa", R8A779A0_CLK_CBFUSA, CLK_MAIN, 2, 1), + DEF_FIXED("cbfusa", R8A779A0_CLK_CBFUSA, CLK_EXTAL, 2, 1), + DEF_FIXED("cp", R8A779A0_CLK_CP, CLK_EXTAL, 2, 1), + + DEF_SD("sd0", R8A779A0_CLK_SD0, CLK_SDSRC, 0x870), DEF_DIV6P1("mso", R8A779A0_CLK_MSO, CLK_PLL5_DIV4, 0x87c), DEF_DIV6P1("canfd", R8A779A0_CLK_CANFD, CLK_PLL5_DIV4, 0x878), @@ -148,14 +156,42 @@ static const struct cpg_core_clk r8a779a0_core_clks[] __initconst = { }; static const struct mssr_mod_clk r8a779a0_mod_clks[] __initconst = { + DEF_MOD("avb0", 211, R8A779A0_CLK_S3D2), + DEF_MOD("avb1", 212, R8A779A0_CLK_S3D2), + DEF_MOD("avb2", 213, R8A779A0_CLK_S3D2), + DEF_MOD("avb3", 214, R8A779A0_CLK_S3D2), + DEF_MOD("avb4", 215, R8A779A0_CLK_S3D2), + DEF_MOD("avb5", 216, R8A779A0_CLK_S3D2), DEF_MOD("csi40", 331, R8A779A0_CLK_CSI0), DEF_MOD("csi41", 400, R8A779A0_CLK_CSI0), DEF_MOD("csi42", 401, R8A779A0_CLK_CSI0), DEF_MOD("csi43", 402, R8A779A0_CLK_CSI0), + DEF_MOD("fcpvd0", 508, R8A779A0_CLK_S3D1), + DEF_MOD("fcpvd1", 509, R8A779A0_CLK_S3D1), + DEF_MOD("hscif0", 514, R8A779A0_CLK_S1D2), + DEF_MOD("hscif1", 515, R8A779A0_CLK_S1D2), + DEF_MOD("hscif2", 516, R8A779A0_CLK_S1D2), + DEF_MOD("hscif3", 517, R8A779A0_CLK_S1D2), + DEF_MOD("i2c0", 518, R8A779A0_CLK_S1D4), + DEF_MOD("i2c1", 519, R8A779A0_CLK_S1D4), + DEF_MOD("i2c2", 520, R8A779A0_CLK_S1D4), + DEF_MOD("i2c3", 521, R8A779A0_CLK_S1D4), + DEF_MOD("i2c4", 522, R8A779A0_CLK_S1D4), + DEF_MOD("i2c5", 523, R8A779A0_CLK_S1D4), + DEF_MOD("i2c6", 524, R8A779A0_CLK_S1D4), + DEF_MOD("msi0", 618, R8A779A0_CLK_MSO), + DEF_MOD("msi1", 619, R8A779A0_CLK_MSO), + DEF_MOD("msi2", 620, R8A779A0_CLK_MSO), + DEF_MOD("msi3", 621, R8A779A0_CLK_MSO), + DEF_MOD("msi4", 622, R8A779A0_CLK_MSO), + DEF_MOD("msi5", 623, R8A779A0_CLK_MSO), DEF_MOD("scif0", 702, R8A779A0_CLK_S1D8), DEF_MOD("scif1", 703, R8A779A0_CLK_S1D8), DEF_MOD("scif3", 704, R8A779A0_CLK_S1D8), DEF_MOD("scif4", 705, R8A779A0_CLK_S1D8), + DEF_MOD("sdhi0", 706, R8A779A0_CLK_SD0), + DEF_MOD("sydm1", 709, R8A779A0_CLK_S1D2), + DEF_MOD("sydm2", 710, R8A779A0_CLK_S1D2), DEF_MOD("vin00", 730, R8A779A0_CLK_S1D1), DEF_MOD("vin01", 731, R8A779A0_CLK_S1D1), DEF_MOD("vin02", 800, R8A779A0_CLK_S1D1), @@ -188,10 +224,19 @@ static const struct mssr_mod_clk r8a779a0_mod_clks[] __initconst = { DEF_MOD("vin35", 827, R8A779A0_CLK_S1D1), DEF_MOD("vin36", 828, R8A779A0_CLK_S1D1), DEF_MOD("vin37", 829, R8A779A0_CLK_S1D1), + DEF_MOD("vspd0", 830, R8A779A0_CLK_S3D1), + DEF_MOD("vspd1", 831, R8A779A0_CLK_S3D1), + DEF_MOD("rwdt", 907, R8A779A0_CLK_R), + DEF_MOD("pfc0", 915, R8A779A0_CLK_CP), + DEF_MOD("pfc1", 916, R8A779A0_CLK_CP), + DEF_MOD("pfc2", 917, R8A779A0_CLK_CP), + DEF_MOD("pfc3", 918, R8A779A0_CLK_CP), + DEF_MOD("vspx0", 1028, R8A779A0_CLK_S1D1), + DEF_MOD("vspx1", 1029, R8A779A0_CLK_S1D1), + DEF_MOD("vspx2", 1030, R8A779A0_CLK_S1D1), + DEF_MOD("vspx3", 1031, R8A779A0_CLK_S1D1), }; -static spinlock_t cpg_lock; - static const struct rcar_r8a779a0_cpg_pll_config *cpg_pll_config __initdata; static unsigned int cpg_clk_extalr __initdata; static u32 cpg_mode __initdata; @@ -230,6 +275,12 @@ static struct clk * __init rcar_r8a779a0_cpg_clk_register(struct device *dev, div = cpg_pll_config->pll5_div; break; + case CLK_TYPE_R8A779A0_SD: + return cpg_sd_clk_register(core->name, base, core->offset, + __clk_get_name(parent), notifiers, + false); + break; + case CLK_TYPE_R8A779A0_MDSEL: /* * Clock selectable between two parents and two fixed dividers @@ -261,6 +312,10 @@ static struct clk * __init rcar_r8a779a0_cpg_clk_register(struct device *dev, __clk_get_name(parent), 0, mult, div); } +static const unsigned int r8a779a0_crit_mod_clks[] __initconst = { + MOD_CLK_ID(907), /* RWDT */ +}; + /* * CPG Clock Data */ @@ -311,6 +366,10 @@ const struct cpg_mssr_info r8a779a0_cpg_mssr_info __initconst = { .num_mod_clks = ARRAY_SIZE(r8a779a0_mod_clks), .num_hw_mod_clks = 15 * 32, + /* Critical Module Clocks */ + .crit_mod_clks = r8a779a0_crit_mod_clks, + .num_crit_mod_clks = ARRAY_SIZE(r8a779a0_crit_mod_clks), + /* Callbacks */ .init = r8a779a0_cpg_mssr_init, .cpg_clk_register = rcar_r8a779a0_cpg_clk_register, diff --git a/drivers/clk/renesas/rcar-cpg-lib.c b/drivers/clk/renesas/rcar-cpg-lib.c new file mode 100644 index 000000000000..7e7e5d1341d5 --- /dev/null +++ b/drivers/clk/renesas/rcar-cpg-lib.c @@ -0,0 +1,270 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * R-Car Gen3 Clock Pulse Generator Library + * + * Copyright (C) 2015-2018 Glider bvba + * Copyright (C) 2019 Renesas Electronics Corp. + * + * Based on clk-rcar-gen3.c + * + * Copyright (C) 2015 Renesas Electronics Corp. + */ + +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/pm.h> +#include <linux/slab.h> +#include <linux/sys_soc.h> + +#include "rcar-cpg-lib.h" + +spinlock_t cpg_lock; + +void cpg_reg_modify(void __iomem *reg, u32 clear, u32 set) +{ + unsigned long flags; + u32 val; + + spin_lock_irqsave(&cpg_lock, flags); + val = readl(reg); + val &= ~clear; + val |= set; + writel(val, reg); + spin_unlock_irqrestore(&cpg_lock, flags); +}; + +static int cpg_simple_notifier_call(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct cpg_simple_notifier *csn = + container_of(nb, struct cpg_simple_notifier, nb); + + switch (action) { + case PM_EVENT_SUSPEND: + csn->saved = readl(csn->reg); + return NOTIFY_OK; + + case PM_EVENT_RESUME: + writel(csn->saved, csn->reg); + return NOTIFY_OK; + } + return NOTIFY_DONE; +} + +void cpg_simple_notifier_register(struct raw_notifier_head *notifiers, + struct cpg_simple_notifier *csn) +{ + csn->nb.notifier_call = cpg_simple_notifier_call; + raw_notifier_chain_register(notifiers, &csn->nb); +} + +/* + * SDn Clock + */ +#define CPG_SD_STP_HCK BIT(9) +#define CPG_SD_STP_CK BIT(8) + +#define CPG_SD_STP_MASK (CPG_SD_STP_HCK | CPG_SD_STP_CK) +#define CPG_SD_FC_MASK (0x7 << 2 | 0x3 << 0) + +#define CPG_SD_DIV_TABLE_DATA(stp_hck, sd_srcfc, sd_fc, sd_div) \ +{ \ + .val = ((stp_hck) ? CPG_SD_STP_HCK : 0) | \ + ((sd_srcfc) << 2) | \ + ((sd_fc) << 0), \ + .div = (sd_div), \ +} + +struct sd_div_table { + u32 val; + unsigned int div; +}; + +struct sd_clock { + struct clk_hw hw; + const struct sd_div_table *div_table; + struct cpg_simple_notifier csn; + unsigned int div_num; + unsigned int cur_div_idx; +}; + +/* SDn divider + * sd_srcfc sd_fc div + * stp_hck (div) (div) = sd_srcfc x sd_fc + *--------------------------------------------------------- + * 0 0 (1) 1 (4) 4 : SDR104 / HS200 / HS400 (8 TAP) + * 0 1 (2) 1 (4) 8 : SDR50 + * 1 2 (4) 1 (4) 16 : HS / SDR25 + * 1 3 (8) 1 (4) 32 : NS / SDR12 + * 1 4 (16) 1 (4) 64 + * 0 0 (1) 0 (2) 2 + * 0 1 (2) 0 (2) 4 : SDR104 / HS200 / HS400 (4 TAP) + * 1 2 (4) 0 (2) 8 + * 1 3 (8) 0 (2) 16 + * 1 4 (16) 0 (2) 32 + * + * NOTE: There is a quirk option to ignore the first row of the dividers + * table when searching for suitable settings. This is because HS400 on + * early ES versions of H3 and M3-W requires a specific setting to work. + */ +static const struct sd_div_table cpg_sd_div_table[] = { +/* CPG_SD_DIV_TABLE_DATA(stp_hck, sd_srcfc, sd_fc, sd_div) */ + CPG_SD_DIV_TABLE_DATA(0, 0, 1, 4), + CPG_SD_DIV_TABLE_DATA(0, 1, 1, 8), + CPG_SD_DIV_TABLE_DATA(1, 2, 1, 16), + CPG_SD_DIV_TABLE_DATA(1, 3, 1, 32), + CPG_SD_DIV_TABLE_DATA(1, 4, 1, 64), + CPG_SD_DIV_TABLE_DATA(0, 0, 0, 2), + CPG_SD_DIV_TABLE_DATA(0, 1, 0, 4), + CPG_SD_DIV_TABLE_DATA(1, 2, 0, 8), + CPG_SD_DIV_TABLE_DATA(1, 3, 0, 16), + CPG_SD_DIV_TABLE_DATA(1, 4, 0, 32), +}; + +#define to_sd_clock(_hw) container_of(_hw, struct sd_clock, hw) + +static int cpg_sd_clock_enable(struct clk_hw *hw) +{ + struct sd_clock *clock = to_sd_clock(hw); + + cpg_reg_modify(clock->csn.reg, CPG_SD_STP_MASK, + clock->div_table[clock->cur_div_idx].val & + CPG_SD_STP_MASK); + + return 0; +} + +static void cpg_sd_clock_disable(struct clk_hw *hw) +{ + struct sd_clock *clock = to_sd_clock(hw); + + cpg_reg_modify(clock->csn.reg, 0, CPG_SD_STP_MASK); +} + +static int cpg_sd_clock_is_enabled(struct clk_hw *hw) +{ + struct sd_clock *clock = to_sd_clock(hw); + + return !(readl(clock->csn.reg) & CPG_SD_STP_MASK); +} + +static unsigned long cpg_sd_clock_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct sd_clock *clock = to_sd_clock(hw); + + return DIV_ROUND_CLOSEST(parent_rate, + clock->div_table[clock->cur_div_idx].div); +} + +static int cpg_sd_clock_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + unsigned long best_rate = ULONG_MAX, diff_min = ULONG_MAX; + struct sd_clock *clock = to_sd_clock(hw); + unsigned long calc_rate, diff; + unsigned int i; + + for (i = 0; i < clock->div_num; i++) { + calc_rate = DIV_ROUND_CLOSEST(req->best_parent_rate, + clock->div_table[i].div); + if (calc_rate < req->min_rate || calc_rate > req->max_rate) + continue; + + diff = calc_rate > req->rate ? calc_rate - req->rate + : req->rate - calc_rate; + if (diff < diff_min) { + best_rate = calc_rate; + diff_min = diff; + } + } + + if (best_rate == ULONG_MAX) + return -EINVAL; + + req->rate = best_rate; + return 0; +} + +static int cpg_sd_clock_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct sd_clock *clock = to_sd_clock(hw); + unsigned int i; + + for (i = 0; i < clock->div_num; i++) + if (rate == DIV_ROUND_CLOSEST(parent_rate, + clock->div_table[i].div)) + break; + + if (i >= clock->div_num) + return -EINVAL; + + clock->cur_div_idx = i; + + cpg_reg_modify(clock->csn.reg, CPG_SD_STP_MASK | CPG_SD_FC_MASK, + clock->div_table[i].val & + (CPG_SD_STP_MASK | CPG_SD_FC_MASK)); + + return 0; +} + +static const struct clk_ops cpg_sd_clock_ops = { + .enable = cpg_sd_clock_enable, + .disable = cpg_sd_clock_disable, + .is_enabled = cpg_sd_clock_is_enabled, + .recalc_rate = cpg_sd_clock_recalc_rate, + .determine_rate = cpg_sd_clock_determine_rate, + .set_rate = cpg_sd_clock_set_rate, +}; + +struct clk * __init cpg_sd_clk_register(const char *name, + void __iomem *base, unsigned int offset, const char *parent_name, + struct raw_notifier_head *notifiers, bool skip_first) +{ + struct clk_init_data init; + struct sd_clock *clock; + struct clk *clk; + u32 val; + + clock = kzalloc(sizeof(*clock), GFP_KERNEL); + if (!clock) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &cpg_sd_clock_ops; + init.flags = CLK_SET_RATE_PARENT; + init.parent_names = &parent_name; + init.num_parents = 1; + + clock->csn.reg = base + offset; + clock->hw.init = &init; + clock->div_table = cpg_sd_div_table; + clock->div_num = ARRAY_SIZE(cpg_sd_div_table); + + if (skip_first) { + clock->div_table++; + clock->div_num--; + } + + val = readl(clock->csn.reg) & ~CPG_SD_FC_MASK; + val |= CPG_SD_STP_MASK | (clock->div_table[0].val & CPG_SD_FC_MASK); + writel(val, clock->csn.reg); + + clk = clk_register(NULL, &clock->hw); + if (IS_ERR(clk)) + goto free_clock; + + cpg_simple_notifier_register(notifiers, &clock->csn); + return clk; + +free_clock: + kfree(clock); + return clk; +} + + diff --git a/drivers/clk/renesas/rcar-cpg-lib.h b/drivers/clk/renesas/rcar-cpg-lib.h new file mode 100644 index 000000000000..d00c91b116ca --- /dev/null +++ b/drivers/clk/renesas/rcar-cpg-lib.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * R-Car Gen3 Clock Pulse Generator Library + * + * Copyright (C) 2015-2018 Glider bvba + * Copyright (C) 2019 Renesas Electronics Corp. + * + * Based on clk-rcar-gen3.c + * + * Copyright (C) 2015 Renesas Electronics Corp. + */ + +#ifndef __CLK_RENESAS_RCAR_CPG_LIB_H__ +#define __CLK_RENESAS_RCAR_CPG_LIB_H__ + +extern spinlock_t cpg_lock; + +struct cpg_simple_notifier { + struct notifier_block nb; + void __iomem *reg; + u32 saved; +}; + +void cpg_simple_notifier_register(struct raw_notifier_head *notifiers, + struct cpg_simple_notifier *csn); + +void cpg_reg_modify(void __iomem *reg, u32 clear, u32 set); + +struct clk * __init cpg_sd_clk_register(const char *name, + void __iomem *base, unsigned int offset, const char *parent_name, + struct raw_notifier_head *notifiers, bool skip_first); + +#endif diff --git a/drivers/clk/renesas/rcar-gen3-cpg.c b/drivers/clk/renesas/rcar-gen3-cpg.c index 063b61151488..17826599e9dd 100644 --- a/drivers/clk/renesas/rcar-gen3-cpg.c +++ b/drivers/clk/renesas/rcar-gen3-cpg.c @@ -23,6 +23,7 @@ #include <linux/sys_soc.h> #include "renesas-cpg-mssr.h" +#include "rcar-cpg-lib.h" #include "rcar-gen3-cpg.h" #define CPG_PLL0CR 0x00d8 @@ -31,52 +32,6 @@ #define CPG_RCKCR_CKSEL BIT(15) /* RCLK Clock Source Select */ -static spinlock_t cpg_lock; - -static void cpg_reg_modify(void __iomem *reg, u32 clear, u32 set) -{ - unsigned long flags; - u32 val; - - spin_lock_irqsave(&cpg_lock, flags); - val = readl(reg); - val &= ~clear; - val |= set; - writel(val, reg); - spin_unlock_irqrestore(&cpg_lock, flags); -}; - -struct cpg_simple_notifier { - struct notifier_block nb; - void __iomem *reg; - u32 saved; -}; - -static int cpg_simple_notifier_call(struct notifier_block *nb, - unsigned long action, void *data) -{ - struct cpg_simple_notifier *csn = - container_of(nb, struct cpg_simple_notifier, nb); - - switch (action) { - case PM_EVENT_SUSPEND: - csn->saved = readl(csn->reg); - return NOTIFY_OK; - - case PM_EVENT_RESUME: - writel(csn->saved, csn->reg); - return NOTIFY_OK; - } - return NOTIFY_DONE; -} - -static void cpg_simple_notifier_register(struct raw_notifier_head *notifiers, - struct cpg_simple_notifier *csn) -{ - csn->nb.notifier_call = cpg_simple_notifier_call; - raw_notifier_chain_register(notifiers, &csn->nb); -} - /* * Z Clock & Z2 Clock * @@ -215,217 +170,6 @@ static struct clk * __init cpg_z_clk_register(const char *name, return clk; } -/* - * SDn Clock - */ -#define CPG_SD_STP_HCK BIT(9) -#define CPG_SD_STP_CK BIT(8) - -#define CPG_SD_STP_MASK (CPG_SD_STP_HCK | CPG_SD_STP_CK) -#define CPG_SD_FC_MASK (0x7 << 2 | 0x3 << 0) - -#define CPG_SD_DIV_TABLE_DATA(stp_hck, sd_srcfc, sd_fc, sd_div) \ -{ \ - .val = ((stp_hck) ? CPG_SD_STP_HCK : 0) | \ - ((sd_srcfc) << 2) | \ - ((sd_fc) << 0), \ - .div = (sd_div), \ -} - -struct sd_div_table { - u32 val; - unsigned int div; -}; - -struct sd_clock { - struct clk_hw hw; - const struct sd_div_table *div_table; - struct cpg_simple_notifier csn; - unsigned int div_num; - unsigned int cur_div_idx; -}; - -/* SDn divider - * sd_srcfc sd_fc div - * stp_hck (div) (div) = sd_srcfc x sd_fc - *--------------------------------------------------------- - * 0 0 (1) 1 (4) 4 : SDR104 / HS200 / HS400 (8 TAP) - * 0 1 (2) 1 (4) 8 : SDR50 - * 1 2 (4) 1 (4) 16 : HS / SDR25 - * 1 3 (8) 1 (4) 32 : NS / SDR12 - * 1 4 (16) 1 (4) 64 - * 0 0 (1) 0 (2) 2 - * 0 1 (2) 0 (2) 4 : SDR104 / HS200 / HS400 (4 TAP) - * 1 2 (4) 0 (2) 8 - * 1 3 (8) 0 (2) 16 - * 1 4 (16) 0 (2) 32 - * - * NOTE: There is a quirk option to ignore the first row of the dividers - * table when searching for suitable settings. This is because HS400 on - * early ES versions of H3 and M3-W requires a specific setting to work. - */ -static const struct sd_div_table cpg_sd_div_table[] = { -/* CPG_SD_DIV_TABLE_DATA(stp_hck, sd_srcfc, sd_fc, sd_div) */ - CPG_SD_DIV_TABLE_DATA(0, 0, 1, 4), - CPG_SD_DIV_TABLE_DATA(0, 1, 1, 8), - CPG_SD_DIV_TABLE_DATA(1, 2, 1, 16), - CPG_SD_DIV_TABLE_DATA(1, 3, 1, 32), - CPG_SD_DIV_TABLE_DATA(1, 4, 1, 64), - CPG_SD_DIV_TABLE_DATA(0, 0, 0, 2), - CPG_SD_DIV_TABLE_DATA(0, 1, 0, 4), - CPG_SD_DIV_TABLE_DATA(1, 2, 0, 8), - CPG_SD_DIV_TABLE_DATA(1, 3, 0, 16), - CPG_SD_DIV_TABLE_DATA(1, 4, 0, 32), -}; - -#define to_sd_clock(_hw) container_of(_hw, struct sd_clock, hw) - -static int cpg_sd_clock_enable(struct clk_hw *hw) -{ - struct sd_clock *clock = to_sd_clock(hw); - - cpg_reg_modify(clock->csn.reg, CPG_SD_STP_MASK, - clock->div_table[clock->cur_div_idx].val & - CPG_SD_STP_MASK); - - return 0; -} - -static void cpg_sd_clock_disable(struct clk_hw *hw) -{ - struct sd_clock *clock = to_sd_clock(hw); - - cpg_reg_modify(clock->csn.reg, 0, CPG_SD_STP_MASK); -} - -static int cpg_sd_clock_is_enabled(struct clk_hw *hw) -{ - struct sd_clock *clock = to_sd_clock(hw); - - return !(readl(clock->csn.reg) & CPG_SD_STP_MASK); -} - -static unsigned long cpg_sd_clock_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct sd_clock *clock = to_sd_clock(hw); - - return DIV_ROUND_CLOSEST(parent_rate, - clock->div_table[clock->cur_div_idx].div); -} - -static int cpg_sd_clock_determine_rate(struct clk_hw *hw, - struct clk_rate_request *req) -{ - unsigned long best_rate = ULONG_MAX, diff_min = ULONG_MAX; - struct sd_clock *clock = to_sd_clock(hw); - unsigned long calc_rate, diff; - unsigned int i; - - for (i = 0; i < clock->div_num; i++) { - calc_rate = DIV_ROUND_CLOSEST(req->best_parent_rate, - clock->div_table[i].div); - if (calc_rate < req->min_rate || calc_rate > req->max_rate) - continue; - - diff = calc_rate > req->rate ? calc_rate - req->rate - : req->rate - calc_rate; - if (diff < diff_min) { - best_rate = calc_rate; - diff_min = diff; - } - } - - if (best_rate == ULONG_MAX) - return -EINVAL; - - req->rate = best_rate; - return 0; -} - -static int cpg_sd_clock_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct sd_clock *clock = to_sd_clock(hw); - unsigned int i; - - for (i = 0; i < clock->div_num; i++) - if (rate == DIV_ROUND_CLOSEST(parent_rate, - clock->div_table[i].div)) - break; - - if (i >= clock->div_num) - return -EINVAL; - - clock->cur_div_idx = i; - - cpg_reg_modify(clock->csn.reg, CPG_SD_STP_MASK | CPG_SD_FC_MASK, - clock->div_table[i].val & - (CPG_SD_STP_MASK | CPG_SD_FC_MASK)); - - return 0; -} - -static const struct clk_ops cpg_sd_clock_ops = { - .enable = cpg_sd_clock_enable, - .disable = cpg_sd_clock_disable, - .is_enabled = cpg_sd_clock_is_enabled, - .recalc_rate = cpg_sd_clock_recalc_rate, - .determine_rate = cpg_sd_clock_determine_rate, - .set_rate = cpg_sd_clock_set_rate, -}; - -static u32 cpg_quirks __initdata; - -#define PLL_ERRATA BIT(0) /* Missing PLL0/2/4 post-divider */ -#define RCKCR_CKSEL BIT(1) /* Manual RCLK parent selection */ -#define SD_SKIP_FIRST BIT(2) /* Skip first clock in SD table */ - -static struct clk * __init cpg_sd_clk_register(const char *name, - void __iomem *base, unsigned int offset, const char *parent_name, - struct raw_notifier_head *notifiers) -{ - struct clk_init_data init; - struct sd_clock *clock; - struct clk *clk; - u32 val; - - clock = kzalloc(sizeof(*clock), GFP_KERNEL); - if (!clock) - return ERR_PTR(-ENOMEM); - - init.name = name; - init.ops = &cpg_sd_clock_ops; - init.flags = CLK_SET_RATE_PARENT; - init.parent_names = &parent_name; - init.num_parents = 1; - - clock->csn.reg = base + offset; - clock->hw.init = &init; - clock->div_table = cpg_sd_div_table; - clock->div_num = ARRAY_SIZE(cpg_sd_div_table); - - if (cpg_quirks & SD_SKIP_FIRST) { - clock->div_table++; - clock->div_num--; - } - - val = readl(clock->csn.reg) & ~CPG_SD_FC_MASK; - val |= CPG_SD_STP_MASK | (clock->div_table[0].val & CPG_SD_FC_MASK); - writel(val, clock->csn.reg); - - clk = clk_register(NULL, &clock->hw); - if (IS_ERR(clk)) - goto free_clock; - - cpg_simple_notifier_register(notifiers, &clock->csn); - return clk; - -free_clock: - kfree(clock); - return clk; -} - struct rpc_clock { struct clk_divider div; struct clk_gate gate; @@ -518,6 +262,12 @@ static struct clk * __init cpg_rpcd2_clk_register(const char *name, static const struct rcar_gen3_cpg_pll_config *cpg_pll_config __initdata; static unsigned int cpg_clk_extalr __initdata; static u32 cpg_mode __initdata; +static u32 cpg_quirks __initdata; + +#define PLL_ERRATA BIT(0) /* Missing PLL0/2/4 post-divider */ +#define RCKCR_CKSEL BIT(1) /* Manual RCLK parent selection */ +#define SD_SKIP_FIRST BIT(2) /* Skip first clock in SD table */ + static const struct soc_device_attribute cpg_quirks_match[] __initconst = { { @@ -613,7 +363,8 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev, case CLK_TYPE_GEN3_SD: return cpg_sd_clk_register(core->name, base, core->offset, - __clk_get_name(parent), notifiers); + __clk_get_name(parent), notifiers, + cpg_quirks & SD_SKIP_FIRST); case CLK_TYPE_GEN3_R: if (cpg_quirks & RCKCR_CKSEL) { diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c index 1c3215dc4877..bffbc3d2faf5 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.c +++ b/drivers/clk/renesas/renesas-cpg-mssr.c @@ -136,8 +136,8 @@ static const u16 srstclr_for_v3u[] = { * @control_regs: Pointer to control registers array * @reset_regs: Pointer to reset registers array * @reset_clear_regs: Pointer to reset clearing registers array - * @smstpcr_saved[].mask: Mask of SMSTPCR[] bits under our control - * @smstpcr_saved[].val: Saved values of SMSTPCR[] + * @smstpcr_saved: [].mask: Mask of SMSTPCR[] bits under our control + * [].val: Saved values of SMSTPCR[] * @clks: Array containing all Core and Module Clocks */ struct cpg_mssr_priv { |