X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=drivers%2Fclk%2Frenesas%2Fclk-rcar-gen3.c;h=1697867ff0be55ae303e5cbe08bc84b76356c62e;hb=605bc145f91d2a28ba2e517cae4e53e255e34b6f;hp=6cf07fb41874cc5b0b50395c86754f0a66042922;hpb=90c2fd2af8189e2e2682c90cd72a48b65191b467;p=platform%2Fkernel%2Fu-boot.git diff --git a/drivers/clk/renesas/clk-rcar-gen3.c b/drivers/clk/renesas/clk-rcar-gen3.c index 6cf07fb..1697867 100644 --- a/drivers/clk/renesas/clk-rcar-gen3.c +++ b/drivers/clk/renesas/clk-rcar-gen3.c @@ -13,83 +13,49 @@ #include #include #include +#include +#include #include #include #include #include #include +#include #include +#include +#include #include #include "renesas-cpg-mssr.h" #include "rcar-gen3-cpg.h" +#include "rcar-cpg-lib.h" #define CPG_PLL0CR 0x00d8 #define CPG_PLL2CR 0x002c #define CPG_PLL4CR 0x01f4 -#define CPG_RPC_PREDIV_MASK 0x3 -#define CPG_RPC_PREDIV_OFFSET 3 -#define CPG_RPC_POSTDIV_MASK 0x7 -#define CPG_RPC_POSTDIV_OFFSET 0 - -/* - * 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, stp_ck, sd_srcfc, sd_fc, sd_div) \ -{ \ - .val = ((stp_hck) ? CPG_SD_STP_HCK : 0) | \ - ((stp_ck) ? CPG_SD_STP_CK : 0) | \ - ((sd_srcfc) << 2) | \ - ((sd_fc) << 0), \ - .div = (sd_div), \ -} +static const struct clk_div_table cpg_rpcsrc_div_table[] = { + { 2, 5 }, { 3, 6 }, { 0, 0 }, +}; -struct sd_div_table { - u32 val; - unsigned int div; +static const struct clk_div_table r8a77970_cpg_sd0h_div_table[] = { + { 0, 2 }, { 1, 3 }, { 2, 4 }, { 3, 6 }, + { 4, 8 }, { 5, 12 }, { 6, 16 }, { 7, 18 }, + { 8, 24 }, { 10, 36 }, { 11, 48 }, { 0, 0 }, }; -/* SDn divider - * sd_srcfc sd_fc div - * stp_hck stp_ck (div) (div) = sd_srcfc x sd_fc - *------------------------------------------------------------------- - * 0 0 0 (1) 1 (4) 4 - * 0 0 1 (2) 1 (4) 8 - * 1 0 2 (4) 1 (4) 16 - * 1 0 3 (8) 1 (4) 32 - * 1 0 4 (16) 1 (4) 64 - * 0 0 0 (1) 0 (2) 2 - * 0 0 1 (2) 0 (2) 4 - * 1 0 2 (4) 0 (2) 8 - * 1 0 3 (8) 0 (2) 16 - * 1 0 4 (16) 0 (2) 32 - */ -static const struct sd_div_table cpg_sd_div_table[] = { -/* CPG_SD_DIV_TABLE_DATA(stp_hck, stp_ck, sd_srcfc, sd_fc, sd_div) */ - CPG_SD_DIV_TABLE_DATA(0, 0, 0, 1, 4), - CPG_SD_DIV_TABLE_DATA(0, 0, 1, 1, 8), - CPG_SD_DIV_TABLE_DATA(1, 0, 2, 1, 16), - CPG_SD_DIV_TABLE_DATA(1, 0, 3, 1, 32), - CPG_SD_DIV_TABLE_DATA(1, 0, 4, 1, 64), - CPG_SD_DIV_TABLE_DATA(0, 0, 0, 0, 2), - CPG_SD_DIV_TABLE_DATA(0, 0, 1, 0, 4), - CPG_SD_DIV_TABLE_DATA(1, 0, 2, 0, 8), - CPG_SD_DIV_TABLE_DATA(1, 0, 3, 0, 16), - CPG_SD_DIV_TABLE_DATA(1, 0, 4, 0, 32), +static const struct clk_div_table r8a77970_cpg_sd0_div_table[] = { + { 4, 8 }, { 5, 12 }, { 6, 16 }, { 7, 18 }, + { 8, 24 }, { 10, 36 }, { 11, 48 }, { 12, 10 }, + { 0, 0 }, }; static int gen3_clk_get_parent(struct gen3_clk_priv *priv, struct clk *clk, struct cpg_mssr_info *info, struct clk *parent) { const struct cpg_core_clk *core; + u8 shift; int ret; if (!renesas_clk_is_mod(clk)) { @@ -98,8 +64,9 @@ static int gen3_clk_get_parent(struct gen3_clk_priv *priv, struct clk *clk, return ret; if (core->type == CLK_TYPE_GEN3_MDSEL) { + shift = priv->cpg_mode & BIT(core->offset) ? 16 : 0; parent->dev = clk->dev; - parent->id = core->parent >> (priv->sscg ? 16 : 0); + parent->id = core->parent >> shift; parent->id &= 0xffff; return 0; } @@ -108,18 +75,44 @@ static int gen3_clk_get_parent(struct gen3_clk_priv *priv, struct clk *clk, return renesas_clk_get_parent(clk, info, parent); } +static int gen3_clk_enable(struct clk *clk) +{ + struct gen3_clk_priv *priv = dev_get_priv(clk->dev); + + return renesas_clk_endisable(clk, priv->base, priv->info, true); +} + +static int gen3_clk_disable(struct clk *clk) +{ + struct gen3_clk_priv *priv = dev_get_priv(clk->dev); + + return renesas_clk_endisable(clk, priv->base, priv->info, false); +} + +static u64 gen3_clk_get_rate64(struct clk *clk); + static int gen3_clk_setup_sdif_div(struct clk *clk, ulong rate) { 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; + struct clk parent, grandparent; int ret; - ret = gen3_clk_get_parent(priv, clk, info, &parent); - if (ret) { - printf("%s[%i] parent fail, ret=%i\n", __func__, __LINE__, ret); - return ret; + /* + * The clk may be either CPG_MOD or core clock, in case this is MOD + * clock, use core clock one level up, otherwise use the clock as-is. + * Note that parent clock here always represents core clock. Also note + * that grandparent clock are the parent clock of the core clock here. + */ + if (renesas_clk_is_mod(clk)) { + ret = gen3_clk_get_parent(priv, clk, info, &parent); + if (ret) { + printf("%s[%i] parent fail, ret=%i\n", __func__, __LINE__, ret); + return ret; + } + } else { + parent = *clk; } if (renesas_clk_is_mod(&parent)) @@ -129,35 +122,40 @@ static int gen3_clk_setup_sdif_div(struct clk *clk, ulong rate) if (ret) return ret; - if (core->type != CLK_TYPE_GEN3_SD) - return 0; + ret = renesas_clk_get_parent(&parent, info, &grandparent); + if (ret) { + printf("%s[%i] grandparent fail, ret=%i\n", __func__, __LINE__, ret); + return ret; + } - debug("%s[%i] SDIF offset=%x\n", __func__, __LINE__, core->offset); + switch (core->type) { + case CLK_TYPE_GEN3_SDH: + fallthrough; + case CLK_TYPE_GEN4_SDH: + return rcar_clk_set_rate64_sdh(core->parent, + gen3_clk_get_rate64(&grandparent), + rate, priv->base + core->offset); - writel((rate == 400000000) ? 0x4 : 0x1, priv->base + core->offset); + case CLK_TYPE_GEN3_SD: + fallthrough; + case CLK_TYPE_GEN4_SD: + return rcar_clk_set_rate64_sd(core->parent, + gen3_clk_get_rate64(&grandparent), + rate, priv->base + core->offset); + + case CLK_TYPE_R8A77970_SD0: + return rcar_clk_set_rate64_div_table(core->parent, + gen3_clk_get_rate64(&grandparent), + rate, priv->base + core->offset, + CPG_SDCKCR_SD0FC_MASK, + r8a77970_cpg_sd0_div_table, "SD"); + } return 0; } -static int gen3_clk_enable(struct clk *clk) -{ - struct gen3_clk_priv *priv = dev_get_priv(clk->dev); - - return renesas_clk_endisable(clk, priv->base, priv->info, true); -} - -static int gen3_clk_disable(struct clk *clk) -{ - struct gen3_clk_priv *priv = dev_get_priv(clk->dev); - - return renesas_clk_endisable(clk, priv->base, priv->info, false); -} - -static u64 gen3_clk_get_rate64(struct clk *clk); - static u64 gen3_clk_get_rate64_pll_mul_reg(struct gen3_clk_priv *priv, struct clk *parent, - const struct cpg_core_clk *core, u32 mul_reg, u32 mult, u32 div, char *name) { @@ -172,8 +170,8 @@ static u64 gen3_clk_get_rate64_pll_mul_reg(struct gen3_clk_priv *priv, rate = (gen3_clk_get_rate64(parent) * mult) / div; - debug("%s[%i] %s clk: parent=%i mult=%u div=%u => rate=%llu\n", - __func__, __LINE__, name, core->parent, mult, div, rate); + debug("%s[%i] %s clk: mult=%u div=%u => rate=%llu\n", + __func__, __LINE__, name, mult, div, rate); return rate; } @@ -185,9 +183,10 @@ static u64 gen3_clk_get_rate64(struct clk *clk) const struct cpg_core_clk *core; const struct rcar_gen3_cpg_pll_config *pll_config = priv->cpg_pll_config; - u32 value, div, prediv, postdiv; + u32 value, div; u64 rate = 0; - int i, ret; + u8 shift; + int ret; debug("%s[%i] Clock: id=%lu\n", __func__, __LINE__, clk->id); @@ -227,121 +226,144 @@ static u64 gen3_clk_get_rate64(struct clk *clk) return -EINVAL; case CLK_TYPE_GEN3_MAIN: - return gen3_clk_get_rate64_pll_mul_reg(priv, &parent, core, + return gen3_clk_get_rate64_pll_mul_reg(priv, &parent, 0, 1, pll_config->extal_div, "MAIN"); case CLK_TYPE_GEN3_PLL0: - return gen3_clk_get_rate64_pll_mul_reg(priv, &parent, core, + return gen3_clk_get_rate64_pll_mul_reg(priv, &parent, CPG_PLL0CR, 0, 0, "PLL0"); case CLK_TYPE_GEN3_PLL1: - return gen3_clk_get_rate64_pll_mul_reg(priv, &parent, core, + return gen3_clk_get_rate64_pll_mul_reg(priv, &parent, 0, pll_config->pll1_mult, pll_config->pll1_div, "PLL1"); case CLK_TYPE_GEN3_PLL2: - return gen3_clk_get_rate64_pll_mul_reg(priv, &parent, core, + return gen3_clk_get_rate64_pll_mul_reg(priv, &parent, CPG_PLL2CR, 0, 0, "PLL2"); case CLK_TYPE_GEN3_PLL3: - return gen3_clk_get_rate64_pll_mul_reg(priv, &parent, core, + return gen3_clk_get_rate64_pll_mul_reg(priv, &parent, 0, pll_config->pll3_mult, pll_config->pll3_div, "PLL3"); case CLK_TYPE_GEN3_PLL4: - return gen3_clk_get_rate64_pll_mul_reg(priv, &parent, core, + return gen3_clk_get_rate64_pll_mul_reg(priv, &parent, CPG_PLL4CR, 0, 0, "PLL4"); - case CLK_TYPE_R8A779A0_MAIN: - return gen3_clk_get_rate64_pll_mul_reg(priv, &parent, core, + case CLK_TYPE_GEN4_MAIN: + return gen3_clk_get_rate64_pll_mul_reg(priv, &parent, 0, 1, pll_config->extal_div, "V3U_MAIN"); - case CLK_TYPE_R8A779A0_PLL1: - return gen3_clk_get_rate64_pll_mul_reg(priv, &parent, core, + case CLK_TYPE_GEN4_PLL1: + return gen3_clk_get_rate64_pll_mul_reg(priv, &parent, 0, pll_config->pll1_mult, pll_config->pll1_div, "V3U_PLL1"); - case CLK_TYPE_R8A779A0_PLL2X_3X: - return gen3_clk_get_rate64_pll_mul_reg(priv, &parent, core, + case CLK_TYPE_GEN4_PLL2X_3X: + return gen3_clk_get_rate64_pll_mul_reg(priv, &parent, core->offset, 0, 0, "V3U_PLL2X_3X"); - case CLK_TYPE_R8A779A0_PLL5: - return gen3_clk_get_rate64_pll_mul_reg(priv, &parent, core, + case CLK_TYPE_GEN4_PLL5: + return gen3_clk_get_rate64_pll_mul_reg(priv, &parent, 0, pll_config->pll5_mult, pll_config->pll5_div, "V3U_PLL5"); case CLK_TYPE_FF: - return gen3_clk_get_rate64_pll_mul_reg(priv, &parent, core, + return gen3_clk_get_rate64_pll_mul_reg(priv, &parent, 0, core->mult, core->div, "FIXED"); case CLK_TYPE_GEN3_MDSEL: - div = (core->div >> (priv->sscg ? 16 : 0)) & 0xffff; + shift = priv->cpg_mode & BIT(core->offset) ? 16 : 0; + div = (core->div >> shift) & 0xffff; rate = gen3_clk_get_rate64(&parent) / div; debug("%s[%i] PE clk: parent=%i div=%u => rate=%llu\n", - __func__, __LINE__, - (core->parent >> (priv->sscg ? 16 : 0)) & 0xffff, + __func__, __LINE__, (core->parent >> shift) & 0xffff, div, rate); return rate; - case CLK_TYPE_GEN3_SD: /* FIXME */ + case CLK_TYPE_GEN3_SDH: /* Fixed factor 1:1 */ fallthrough; - case CLK_TYPE_R8A779A0_SD: - value = readl(priv->base + core->offset); - value &= CPG_SD_STP_MASK | CPG_SD_FC_MASK; - - for (i = 0; i < ARRAY_SIZE(cpg_sd_div_table); i++) { - if (cpg_sd_div_table[i].val != value) - continue; - - rate = gen3_clk_get_rate64(&parent) / - cpg_sd_div_table[i].div; - debug("%s[%i] SD clk: parent=%i div=%i => rate=%llu\n", - __func__, __LINE__, - core->parent, cpg_sd_div_table[i].div, rate); - - return rate; + case CLK_TYPE_GEN4_SDH: /* Fixed factor 1:1 */ + return rcar_clk_get_rate64_sdh(core->parent, + gen3_clk_get_rate64(&parent), + priv->base + core->offset); + + case CLK_TYPE_R8A77970_SD0H: + return rcar_clk_get_rate64_div_table(core->parent, + gen3_clk_get_rate64(&parent), + priv->base + core->offset, + CPG_SDCKCR_SDHFC_MASK, + r8a77970_cpg_sd0h_div_table, "SDH"); + + case CLK_TYPE_GEN3_SD: + fallthrough; + case CLK_TYPE_GEN4_SD: + return rcar_clk_get_rate64_sd(core->parent, + gen3_clk_get_rate64(&parent), + priv->base + core->offset); + + case CLK_TYPE_R8A77970_SD0: + return rcar_clk_get_rate64_div_table(core->parent, + gen3_clk_get_rate64(&parent), + priv->base + core->offset, + CPG_SDCKCR_SD0FC_MASK, + r8a77970_cpg_sd0_div_table, "SD"); + + case CLK_TYPE_GEN3_RPCSRC: + return rcar_clk_get_rate64_div_table(core->parent, + gen3_clk_get_rate64(&parent), + priv->base + CPG_RPCCKCR, + CPG_RPCCKCR_DIV_POST_MASK, + cpg_rpcsrc_div_table, "RPCSRC"); + + case CLK_TYPE_GEN3_D3_RPCSRC: + case CLK_TYPE_GEN3_E3_RPCSRC: + /* + * Register RPCSRC as fixed factor clock based on the + * MD[4:1] pins and CPG_RPCCKCR[4:3] register value for + * which has been set prior to booting the kernel. + */ + value = (readl(priv->base + CPG_RPCCKCR) & GENMASK(4, 3)) >> 3; + + switch (value) { + case 0: + div = 5; + break; + case 1: + div = 3; + break; + case 2: + div = core->div; + break; + case 3: + default: + div = 2; + break; } - return -EINVAL; - - case CLK_TYPE_GEN3_RPC: - case CLK_TYPE_GEN3_RPCD2: - rate = gen3_clk_get_rate64(&parent); - - value = readl(priv->base + core->offset); - - prediv = (value >> CPG_RPC_PREDIV_OFFSET) & - CPG_RPC_PREDIV_MASK; - if (prediv == 2) - rate /= 5; - else if (prediv == 3) - rate /= 6; - else - return -EINVAL; - - postdiv = (value >> CPG_RPC_POSTDIV_OFFSET) & - CPG_RPC_POSTDIV_MASK; - - if (postdiv % 2 != 0) { - rate /= postdiv + 1; - - if (core->type == CLK_TYPE_GEN3_RPCD2) - rate /= 2; + rate = gen3_clk_get_rate64(&parent) / div; + debug("%s[%i] E3/D3 RPCSRC clk: parent=%i div=%u => rate=%llu\n", + __func__, __LINE__, (core->parent >> 16) & 0xffff, div, rate); - debug("%s[%i] RPC clk: parent=%i prediv=%i postdiv=%i => rate=%llu\n", - __func__, __LINE__, - core->parent, prediv, postdiv, rate); + return rate; - return rate; - } + case CLK_TYPE_GEN3_RPC: + case CLK_TYPE_GEN4_RPC: + return rcar_clk_get_rate64_rpc(core->parent, + gen3_clk_get_rate64(&parent), + priv->base + CPG_RPCCKCR); - return -EINVAL; + case CLK_TYPE_GEN3_RPCD2: + case CLK_TYPE_GEN4_RPCD2: + return rcar_clk_get_rate64_rpcd2(core->parent, + gen3_clk_get_rate64(&parent)); } @@ -365,7 +387,7 @@ static ulong gen3_clk_set_rate(struct clk *clk, ulong rate) static int gen3_clk_of_xlate(struct clk *clk, struct ofnode_phandle_args *args) { if (args->args_count != 2) { - debug("Invaild args_count: %d\n", args->args_count); + debug("Invalid args_count: %d\n", args->args_count); return -EINVAL; } @@ -382,13 +404,12 @@ const struct clk_ops gen3_clk_ops = { .of_xlate = gen3_clk_of_xlate, }; -int gen3_clk_probe(struct udevice *dev) +static int gen3_clk_probe(struct udevice *dev) { struct gen3_clk_priv *priv = dev_get_priv(dev); struct cpg_mssr_info *info = (struct cpg_mssr_info *)dev_get_driver_data(dev); fdt_addr_t rst_base; - u32 cpg_mode; int ret; priv->base = dev_read_addr_ptr(dev); @@ -404,15 +425,13 @@ int gen3_clk_probe(struct udevice *dev) if (rst_base == FDT_ADDR_T_NONE) return -EINVAL; - cpg_mode = readl(rst_base + info->reset_modemr_offset); + priv->cpg_mode = readl(rst_base + info->reset_modemr_offset); priv->cpg_pll_config = - (struct rcar_gen3_cpg_pll_config *)info->get_pll_config(cpg_mode); + (struct rcar_gen3_cpg_pll_config *)info->get_pll_config(priv->cpg_mode); if (!priv->cpg_pll_config->extal_div) return -EINVAL; - priv->sscg = !(cpg_mode & BIT(12)); - if (info->reg_layout == CLK_REG_LAYOUT_RCAR_GEN2_AND_GEN3) { priv->info->status_regs = mstpsr; priv->info->control_regs = smstpcr; @@ -440,9 +459,86 @@ int gen3_clk_probe(struct udevice *dev) return 0; } -int gen3_clk_remove(struct udevice *dev) +static int gen3_clk_remove(struct udevice *dev) { struct gen3_clk_priv *priv = dev_get_priv(dev); return renesas_clk_remove(priv->base, priv->info); } + +U_BOOT_DRIVER(clk_gen3) = { + .name = "clk_gen3", + .id = UCLASS_CLK, + .priv_auto = sizeof(struct gen3_clk_priv), + .ops = &gen3_clk_ops, + .probe = gen3_clk_probe, + .remove = gen3_clk_remove, +}; + +static int gen3_reset_assert(struct reset_ctl *reset_ctl) +{ + struct udevice *cdev = (struct udevice *)dev_get_driver_data(reset_ctl->dev); + struct gen3_clk_priv *priv = dev_get_priv(cdev); + unsigned int packed_id = MOD_CLK_PACK(reset_ctl->id); + unsigned int reg = packed_id / 32; + unsigned int bit = packed_id % 32; + u32 bitmask = BIT(bit); + + writel(bitmask, priv->base + priv->info->reset_regs[reg]); + + return 0; +} + +static int gen3_reset_deassert(struct reset_ctl *reset_ctl) +{ + struct udevice *cdev = (struct udevice *)dev_get_driver_data(reset_ctl->dev); + struct gen3_clk_priv *priv = dev_get_priv(cdev); + unsigned int packed_id = MOD_CLK_PACK(reset_ctl->id); + unsigned int reg = packed_id / 32; + unsigned int bit = packed_id % 32; + u32 bitmask = BIT(bit); + + writel(bitmask, priv->base + priv->info->reset_clear_regs[reg]); + + return 0; +} + +static const struct reset_ops rst_gen3_ops = { + .rst_assert = gen3_reset_assert, + .rst_deassert = gen3_reset_deassert, +}; + +U_BOOT_DRIVER(rst_gen3) = { + .name = "rst_gen3", + .id = UCLASS_RESET, + .ops = &rst_gen3_ops, +}; + +int gen3_cpg_bind(struct udevice *parent) +{ + struct cpg_mssr_info *info = + (struct cpg_mssr_info *)dev_get_driver_data(parent); + struct udevice *cdev, *rdev; + struct driver *drv; + int ret; + + drv = lists_driver_lookup_name("clk_gen3"); + if (!drv) + return -ENOENT; + + ret = device_bind_with_driver_data(parent, drv, "clk_gen3", (ulong)info, + dev_ofnode(parent), &cdev); + if (ret) + return ret; + + drv = lists_driver_lookup_name("rst_gen3"); + if (!drv) + return -ENOENT; + + ret = device_bind_with_driver_data(parent, drv, "rst_gen3", (ulong)cdev, + dev_ofnode(parent), &rdev); + if (ret) + device_unbind(cdev); + + return ret; +}