From d26286715f879baeb77e6abae67ed5bf44045aad Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 15 Jan 2018 16:44:39 +0100 Subject: [PATCH] clk: renesas: Split out code shared between Gen2 and Gen3 Pull code which is common for RCar Gen2 and RCar Gen3 into separate source file. No functional change. Signed-off-by: Marek Vasut Cc: Nobuhiro Iwamatsu --- drivers/clk/renesas/Makefile | 1 + drivers/clk/renesas/clk-rcar-gen3.c | 184 +++---------------------- drivers/clk/renesas/renesas-cpg-mssr.c | 175 +++++++++++++++++++++++ drivers/clk/renesas/renesas-cpg-mssr.h | 10 ++ 4 files changed, 203 insertions(+), 167 deletions(-) create mode 100644 drivers/clk/renesas/renesas-cpg-mssr.c diff --git a/drivers/clk/renesas/Makefile b/drivers/clk/renesas/Makefile index 0b8585b850..4be9852729 100644 --- a/drivers/clk/renesas/Makefile +++ b/drivers/clk/renesas/Makefile @@ -1,3 +1,4 @@ +obj-$(CONFIG_CLK_RENESAS) += renesas-cpg-mssr.o obj-$(CONFIG_CLK_RCAR_GEN3) += clk-rcar-gen3.o obj-$(CONFIG_CLK_R8A7795) += r8a7795-cpg-mssr.o obj-$(CONFIG_CLK_R8A7796) += r8a7796-cpg-mssr.o diff --git a/drivers/clk/renesas/clk-rcar-gen3.c b/drivers/clk/renesas/clk-rcar-gen3.c index ba3c6da326..0c394a8a71 100644 --- a/drivers/clk/renesas/clk-rcar-gen3.c +++ b/drivers/clk/renesas/clk-rcar-gen3.c @@ -21,6 +21,7 @@ #include #include "renesas-cpg-mssr.h" +#include "rcar-gen3-cpg.h" #define CPG_RST_MODEMR 0x0060 @@ -33,47 +34,6 @@ #define CPG_RPC_POSTDIV_MASK 0x7 #define CPG_RPC_POSTDIV_OFFSET 0 -/* - * Module Standby and Software Reset register offets. - * - * If the registers exist, these are valid for SH-Mobile, R-Mobile, - * R-Car Gen2, R-Car Gen3, and RZ/G1. - * These are NOT valid for R-Car Gen1 and RZ/A1! - */ - -/* - * Module Stop Status Register offsets - */ - -static const u16 mstpsr[] = { - 0x030, 0x038, 0x040, 0x048, 0x04C, 0x03C, 0x1C0, 0x1C4, - 0x9A0, 0x9A4, 0x9A8, 0x9AC, -}; - -#define MSTPSR(i) mstpsr[i] - - -/* - * System Module Stop Control Register offsets - */ - -static const u16 smstpcr[] = { - 0x130, 0x134, 0x138, 0x13C, 0x140, 0x144, 0x148, 0x14C, - 0x990, 0x994, 0x998, 0x99C, -}; - -#define SMSTPCR(i) smstpcr[i] - - -/* Realtime Module Stop Control Register offsets */ -#define RMSTPCR(i) (smstpcr[i] - 0x20) - -/* Modem Module Stop Control Register offsets (r8a73a4) */ -#define MMSTPCR(i) (smstpcr[i] + 0x20) - -/* Software Reset Clearing Register offsets */ -#define SRSTCLR(i) (0x940 + (i) * 4) - /* * SDn Clock */ @@ -126,99 +86,24 @@ static const struct sd_div_table cpg_sd_div_table[] = { CPG_SD_DIV_TABLE_DATA(1, 0, 4, 0, 32), }; -static bool gen3_clk_is_mod(struct clk *clk) -{ - return (clk->id >> 16) == CPG_MOD; -} - -static int gen3_clk_get_mod(struct clk *clk, const struct mssr_mod_clk **mssr) -{ - struct gen3_clk_priv *priv = dev_get_priv(clk->dev); - struct cpg_mssr_info *info = priv->info; - const unsigned long clkid = clk->id & 0xffff; - int i; - - if (!gen3_clk_is_mod(clk)) - return -EINVAL; - - for (i = 0; i < info->mod_clk_size; i++) { - if (info->mod_clk[i].id != - (info->mod_clk_base + MOD_CLK_PACK(clkid))) - continue; - - *mssr = &info->mod_clk[i]; - return 0; - } - - return -ENODEV; -} - -static int gen3_clk_get_core(struct clk *clk, const struct cpg_core_clk **core) -{ - struct gen3_clk_priv *priv = dev_get_priv(clk->dev); - struct cpg_mssr_info *info = priv->info; - const unsigned long clkid = clk->id & 0xffff; - int i; - - if (gen3_clk_is_mod(clk)) - return -EINVAL; - - for (i = 0; i < info->core_clk_size; i++) { - if (info->core_clk[i].id != clkid) - continue; - - *core = &info->core_clk[i]; - return 0; - } - - return -ENODEV; -} - -static int gen3_clk_get_parent(struct clk *clk, struct clk *parent) -{ - const struct cpg_core_clk *core; - const struct mssr_mod_clk *mssr; - int ret; - - if (gen3_clk_is_mod(clk)) { - ret = gen3_clk_get_mod(clk, &mssr); - if (ret) - return ret; - - parent->id = mssr->parent; - } else { - ret = gen3_clk_get_core(clk, &core); - if (ret) - return ret; - - if (core->type == CLK_TYPE_IN) - parent->id = ~0; /* Top-level clock */ - else - parent->id = core->parent; - } - - parent->dev = clk->dev; - - return 0; -} - static int gen3_clk_setup_sdif_div(struct clk *clk) { struct gen3_clk_priv *priv = dev_get_priv(clk->dev); + struct cpg_mssr_info *info = priv->info; const struct cpg_core_clk *core; struct clk parent; int ret; - ret = gen3_clk_get_parent(clk, &parent); + ret = renesas_clk_get_parent(clk, info, &parent); if (ret) { printf("%s[%i] parent fail, ret=%i\n", __func__, __LINE__, ret); return ret; } - if (gen3_clk_is_mod(&parent)) + if (renesas_clk_is_mod(&parent)) return 0; - ret = gen3_clk_get_core(&parent, &core); + ret = renesas_clk_get_core(&parent, info, &core); if (ret) return ret; @@ -232,42 +117,22 @@ static int gen3_clk_setup_sdif_div(struct clk *clk) return 0; } -static int gen3_clk_endisable(struct clk *clk, bool enable) +static int gen3_clk_enable(struct clk *clk) { struct gen3_clk_priv *priv = dev_get_priv(clk->dev); - const unsigned long clkid = clk->id & 0xffff; - const unsigned int reg = clkid / 100; - const unsigned int bit = clkid % 100; - const u32 bitmask = BIT(bit); - int ret; - - if (!gen3_clk_is_mod(clk)) - return -EINVAL; - - debug("%s[%i] MSTP %lu=%02u/%02u %s\n", __func__, __LINE__, - clkid, reg, bit, enable ? "ON" : "OFF"); + int ret = gen3_clk_setup_sdif_div(clk); - if (enable) { - ret = gen3_clk_setup_sdif_div(clk); - if (ret) - return ret; - clrbits_le32(priv->base + SMSTPCR(reg), bitmask); - return wait_for_bit("MSTP", priv->base + MSTPSR(reg), - bitmask, 0, 100, 0); - } else { - setbits_le32(priv->base + SMSTPCR(reg), bitmask); - return 0; - } -} + if (ret) + return ret; -static int gen3_clk_enable(struct clk *clk) -{ - return gen3_clk_endisable(clk, true); + return renesas_clk_endisable(clk, priv->base, true); } static int gen3_clk_disable(struct clk *clk) { - return gen3_clk_endisable(clk, false); + struct gen3_clk_priv *priv = dev_get_priv(clk->dev); + + return renesas_clk_endisable(clk, priv->base, false); } static ulong gen3_clk_get_rate(struct clk *clk) @@ -283,20 +148,20 @@ static ulong gen3_clk_get_rate(struct clk *clk) debug("%s[%i] Clock: id=%lu\n", __func__, __LINE__, clk->id); - ret = gen3_clk_get_parent(clk, &parent); + ret = renesas_clk_get_parent(clk, info, &parent); if (ret) { printf("%s[%i] parent fail, ret=%i\n", __func__, __LINE__, ret); return ret; } - if (gen3_clk_is_mod(clk)) { + if (renesas_clk_is_mod(clk)) { rate = gen3_clk_get_rate(&parent); debug("%s[%i] MOD clk: parent=%lu => rate=%u\n", __func__, __LINE__, parent.id, rate); return rate; } - ret = gen3_clk_get_core(clk, &core); + ret = renesas_clk_get_core(clk, info, &core); if (ret) return ret; @@ -491,21 +356,6 @@ int gen3_clk_probe(struct udevice *dev) int gen3_clk_remove(struct udevice *dev) { struct gen3_clk_priv *priv = dev_get_priv(dev); - struct cpg_mssr_info *info = priv->info; - unsigned int i; - - /* Stop TMU0 */ - clrbits_le32(TMU_BASE + TSTR0, TSTR0_STR0); - - /* Stop module clock */ - for (i = 0; i < info->mstp_table_size; i++) { - clrsetbits_le32(priv->base + SMSTPCR(i), - info->mstp_table[i].sdis, - info->mstp_table[i].sen); - clrsetbits_le32(priv->base + RMSTPCR(i), - info->mstp_table[i].rdis, - info->mstp_table[i].ren); - } - return 0; + return renesas_clk_remove(priv->base, priv->info); } diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c new file mode 100644 index 0000000000..73da75b004 --- /dev/null +++ b/drivers/clk/renesas/renesas-cpg-mssr.c @@ -0,0 +1,175 @@ +/* + * Renesas RCar Gen3 CPG MSSR driver + * + * Copyright (C) 2018 Marek Vasut + * + * Based on the following driver from Linux kernel: + * r8a7796 Clock Pulse Generator / Module Standby and Software Reset + * + * Copyright (C) 2016 Glider bvba + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include +#include +#include +#include +#include +#include + +#include + +#include "renesas-cpg-mssr.h" + +/* + * Module Standby and Software Reset register offets. + * + * If the registers exist, these are valid for SH-Mobile, R-Mobile, + * R-Car Gen2, R-Car Gen3, and RZ/G1. + * These are NOT valid for R-Car Gen1 and RZ/A1! + */ + +/* + * Module Stop Status Register offsets + */ + +static const u16 mstpsr[] = { + 0x030, 0x038, 0x040, 0x048, 0x04C, 0x03C, 0x1C0, 0x1C4, + 0x9A0, 0x9A4, 0x9A8, 0x9AC, +}; + +#define MSTPSR(i) mstpsr[i] + + +/* + * System Module Stop Control Register offsets + */ + +static const u16 smstpcr[] = { + 0x130, 0x134, 0x138, 0x13C, 0x140, 0x144, 0x148, 0x14C, + 0x990, 0x994, 0x998, 0x99C, +}; + +#define SMSTPCR(i) smstpcr[i] + + +/* Realtime Module Stop Control Register offsets */ +#define RMSTPCR(i) (smstpcr[i] - 0x20) + +/* Modem Module Stop Control Register offsets (r8a73a4) */ +#define MMSTPCR(i) (smstpcr[i] + 0x20) + +/* Software Reset Clearing Register offsets */ +#define SRSTCLR(i) (0x940 + (i) * 4) + +bool renesas_clk_is_mod(struct clk *clk) +{ + return (clk->id >> 16) == CPG_MOD; +} + +int renesas_clk_get_mod(struct clk *clk, struct cpg_mssr_info *info, + const struct mssr_mod_clk **mssr) +{ + const unsigned long clkid = clk->id & 0xffff; + int i; + + for (i = 0; i < info->mod_clk_size; i++) { + if (info->mod_clk[i].id != + (info->mod_clk_base + MOD_CLK_PACK(clkid))) + continue; + + *mssr = &info->mod_clk[i]; + return 0; + } + + return -ENODEV; +} + +int renesas_clk_get_core(struct clk *clk, struct cpg_mssr_info *info, + const struct cpg_core_clk **core) +{ + const unsigned long clkid = clk->id & 0xffff; + int i; + + for (i = 0; i < info->core_clk_size; i++) { + if (info->core_clk[i].id != clkid) + continue; + + *core = &info->core_clk[i]; + return 0; + } + + return -ENODEV; +} + +int renesas_clk_get_parent(struct clk *clk, struct cpg_mssr_info *info, + struct clk *parent) +{ + const struct cpg_core_clk *core; + const struct mssr_mod_clk *mssr; + int ret; + + if (renesas_clk_is_mod(clk)) { + ret = renesas_clk_get_mod(clk, info, &mssr); + if (ret) + return ret; + + parent->id = mssr->parent; + } else { + ret = renesas_clk_get_core(clk, info, &core); + if (ret) + return ret; + + if (core->type == CLK_TYPE_IN) + parent->id = ~0; /* Top-level clock */ + else + parent->id = core->parent; + } + + parent->dev = clk->dev; + + return 0; +} + +int renesas_clk_endisable(struct clk *clk, void __iomem *base, bool enable) +{ + const unsigned long clkid = clk->id & 0xffff; + const unsigned int reg = clkid / 100; + const unsigned int bit = clkid % 100; + const u32 bitmask = BIT(bit); + + if (!renesas_clk_is_mod(clk)) + return -EINVAL; + + debug("%s[%i] MSTP %lu=%02u/%02u %s\n", __func__, __LINE__, + clkid, reg, bit, enable ? "ON" : "OFF"); + + if (enable) { + clrbits_le32(base + SMSTPCR(reg), bitmask); + return wait_for_bit("MSTP", base + MSTPSR(reg), + bitmask, 0, 100, 0); + } else { + setbits_le32(base + SMSTPCR(reg), bitmask); + return 0; + } +} + +int renesas_clk_remove(void __iomem *base, struct cpg_mssr_info *info) +{ + unsigned int i; + + /* Stop TMU0 */ + clrbits_le32(TMU_BASE + TSTR0, TSTR0_STR0); + + /* Stop module clock */ + for (i = 0; i < info->mstp_table_size; i++) { + clrsetbits_le32(base + SMSTPCR(i), + info->mstp_table[i].sdis, + info->mstp_table[i].sen); + clrsetbits_le32(base + RMSTPCR(i), + info->mstp_table[i].rdis, + info->mstp_table[i].ren); + } + + return 0; +} diff --git a/drivers/clk/renesas/renesas-cpg-mssr.h b/drivers/clk/renesas/renesas-cpg-mssr.h index a169345be8..d11145ad90 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.h +++ b/drivers/clk/renesas/renesas-cpg-mssr.h @@ -95,4 +95,14 @@ struct mstp_stop_table { #define TSTR0 0x04 #define TSTR0_STR0 BIT(0) +bool renesas_clk_is_mod(struct clk *clk); +int renesas_clk_get_mod(struct clk *clk, struct cpg_mssr_info *info, + const struct mssr_mod_clk **mssr); +int renesas_clk_get_core(struct clk *clk, struct cpg_mssr_info *info, + const struct cpg_core_clk **core); +int renesas_clk_get_parent(struct clk *clk, struct cpg_mssr_info *info, + struct clk *parent); +int renesas_clk_endisable(struct clk *clk, void __iomem *base, bool enable); +int renesas_clk_remove(void __iomem *base, struct cpg_mssr_info *info); + #endif /* __DRIVERS_CLK_RENESAS_CPG_MSSR__ */ -- 2.25.1