Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * MVEBU Core divider clock
0004  *
0005  * Copyright (C) 2013 Marvell
0006  *
0007  * Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
0008  *
0009  */
0010 
0011 #include <linux/kernel.h>
0012 #include <linux/clk-provider.h>
0013 #include <linux/io.h>
0014 #include <linux/of_address.h>
0015 #include <linux/slab.h>
0016 #include <linux/delay.h>
0017 #include "common.h"
0018 
0019 #define CORE_CLK_DIV_RATIO_MASK     0xff
0020 
0021 /*
0022  * This structure describes the hardware details (bit offset and mask)
0023  * to configure one particular core divider clock. Those hardware
0024  * details may differ from one SoC to another. This structure is
0025  * therefore typically instantiated statically to describe the
0026  * hardware details.
0027  */
0028 struct clk_corediv_desc {
0029     unsigned int mask;
0030     unsigned int offset;
0031     unsigned int fieldbit;
0032 };
0033 
0034 /*
0035  * This structure describes the hardware details to configure the core
0036  * divider clocks on a given SoC. Amongst others, it points to the
0037  * array of core divider clock descriptors for this SoC, as well as
0038  * the corresponding operations to manipulate them.
0039  */
0040 struct clk_corediv_soc_desc {
0041     const struct clk_corediv_desc *descs;
0042     unsigned int ndescs;
0043     const struct clk_ops ops;
0044     u32 ratio_reload;
0045     u32 enable_bit_offset;
0046     u32 ratio_offset;
0047 };
0048 
0049 /*
0050  * This structure represents one core divider clock for the clock
0051  * framework, and is dynamically allocated for each core divider clock
0052  * existing in the current SoC.
0053  */
0054 struct clk_corediv {
0055     struct clk_hw hw;
0056     void __iomem *reg;
0057     const struct clk_corediv_desc *desc;
0058     const struct clk_corediv_soc_desc *soc_desc;
0059     spinlock_t lock;
0060 };
0061 
0062 static struct clk_onecell_data clk_data;
0063 
0064 /*
0065  * Description of the core divider clocks available. For now, we
0066  * support only NAND, and it is available at the same register
0067  * locations regardless of the SoC.
0068  */
0069 static const struct clk_corediv_desc mvebu_corediv_desc[] = {
0070     { .mask = 0x3f, .offset = 8, .fieldbit = 1 }, /* NAND clock */
0071 };
0072 
0073 static const struct clk_corediv_desc mv98dx3236_corediv_desc[] = {
0074     { .mask = 0x0f, .offset = 6, .fieldbit = 27 }, /* NAND clock */
0075 };
0076 
0077 #define to_corediv_clk(p) container_of(p, struct clk_corediv, hw)
0078 
0079 static int clk_corediv_is_enabled(struct clk_hw *hwclk)
0080 {
0081     struct clk_corediv *corediv = to_corediv_clk(hwclk);
0082     const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc;
0083     const struct clk_corediv_desc *desc = corediv->desc;
0084     u32 enable_mask = BIT(desc->fieldbit) << soc_desc->enable_bit_offset;
0085 
0086     return !!(readl(corediv->reg) & enable_mask);
0087 }
0088 
0089 static int clk_corediv_enable(struct clk_hw *hwclk)
0090 {
0091     struct clk_corediv *corediv = to_corediv_clk(hwclk);
0092     const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc;
0093     const struct clk_corediv_desc *desc = corediv->desc;
0094     unsigned long flags = 0;
0095     u32 reg;
0096 
0097     spin_lock_irqsave(&corediv->lock, flags);
0098 
0099     reg = readl(corediv->reg);
0100     reg |= (BIT(desc->fieldbit) << soc_desc->enable_bit_offset);
0101     writel(reg, corediv->reg);
0102 
0103     spin_unlock_irqrestore(&corediv->lock, flags);
0104 
0105     return 0;
0106 }
0107 
0108 static void clk_corediv_disable(struct clk_hw *hwclk)
0109 {
0110     struct clk_corediv *corediv = to_corediv_clk(hwclk);
0111     const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc;
0112     const struct clk_corediv_desc *desc = corediv->desc;
0113     unsigned long flags = 0;
0114     u32 reg;
0115 
0116     spin_lock_irqsave(&corediv->lock, flags);
0117 
0118     reg = readl(corediv->reg);
0119     reg &= ~(BIT(desc->fieldbit) << soc_desc->enable_bit_offset);
0120     writel(reg, corediv->reg);
0121 
0122     spin_unlock_irqrestore(&corediv->lock, flags);
0123 }
0124 
0125 static unsigned long clk_corediv_recalc_rate(struct clk_hw *hwclk,
0126                      unsigned long parent_rate)
0127 {
0128     struct clk_corediv *corediv = to_corediv_clk(hwclk);
0129     const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc;
0130     const struct clk_corediv_desc *desc = corediv->desc;
0131     u32 reg, div;
0132 
0133     reg = readl(corediv->reg + soc_desc->ratio_offset);
0134     div = (reg >> desc->offset) & desc->mask;
0135     return parent_rate / div;
0136 }
0137 
0138 static long clk_corediv_round_rate(struct clk_hw *hwclk, unsigned long rate,
0139                    unsigned long *parent_rate)
0140 {
0141     /* Valid ratio are 1:4, 1:5, 1:6 and 1:8 */
0142     u32 div;
0143 
0144     div = *parent_rate / rate;
0145     if (div < 4)
0146         div = 4;
0147     else if (div > 6)
0148         div = 8;
0149 
0150     return *parent_rate / div;
0151 }
0152 
0153 static int clk_corediv_set_rate(struct clk_hw *hwclk, unsigned long rate,
0154                 unsigned long parent_rate)
0155 {
0156     struct clk_corediv *corediv = to_corediv_clk(hwclk);
0157     const struct clk_corediv_soc_desc *soc_desc = corediv->soc_desc;
0158     const struct clk_corediv_desc *desc = corediv->desc;
0159     unsigned long flags = 0;
0160     u32 reg, div;
0161 
0162     div = parent_rate / rate;
0163 
0164     spin_lock_irqsave(&corediv->lock, flags);
0165 
0166     /* Write new divider to the divider ratio register */
0167     reg = readl(corediv->reg + soc_desc->ratio_offset);
0168     reg &= ~(desc->mask << desc->offset);
0169     reg |= (div & desc->mask) << desc->offset;
0170     writel(reg, corediv->reg + soc_desc->ratio_offset);
0171 
0172     /* Set reload-force for this clock */
0173     reg = readl(corediv->reg) | BIT(desc->fieldbit);
0174     writel(reg, corediv->reg);
0175 
0176     /* Now trigger the clock update */
0177     reg = readl(corediv->reg) | soc_desc->ratio_reload;
0178     writel(reg, corediv->reg);
0179 
0180     /*
0181      * Wait for clocks to settle down, and then clear all the
0182      * ratios request and the reload request.
0183      */
0184     udelay(1000);
0185     reg &= ~(CORE_CLK_DIV_RATIO_MASK | soc_desc->ratio_reload);
0186     writel(reg, corediv->reg);
0187     udelay(1000);
0188 
0189     spin_unlock_irqrestore(&corediv->lock, flags);
0190 
0191     return 0;
0192 }
0193 
0194 static const struct clk_corediv_soc_desc armada370_corediv_soc = {
0195     .descs = mvebu_corediv_desc,
0196     .ndescs = ARRAY_SIZE(mvebu_corediv_desc),
0197     .ops = {
0198         .enable = clk_corediv_enable,
0199         .disable = clk_corediv_disable,
0200         .is_enabled = clk_corediv_is_enabled,
0201         .recalc_rate = clk_corediv_recalc_rate,
0202         .round_rate = clk_corediv_round_rate,
0203         .set_rate = clk_corediv_set_rate,
0204     },
0205     .ratio_reload = BIT(8),
0206     .enable_bit_offset = 24,
0207     .ratio_offset = 0x8,
0208 };
0209 
0210 static const struct clk_corediv_soc_desc armada380_corediv_soc = {
0211     .descs = mvebu_corediv_desc,
0212     .ndescs = ARRAY_SIZE(mvebu_corediv_desc),
0213     .ops = {
0214         .enable = clk_corediv_enable,
0215         .disable = clk_corediv_disable,
0216         .is_enabled = clk_corediv_is_enabled,
0217         .recalc_rate = clk_corediv_recalc_rate,
0218         .round_rate = clk_corediv_round_rate,
0219         .set_rate = clk_corediv_set_rate,
0220     },
0221     .ratio_reload = BIT(8),
0222     .enable_bit_offset = 16,
0223     .ratio_offset = 0x4,
0224 };
0225 
0226 static const struct clk_corediv_soc_desc armada375_corediv_soc = {
0227     .descs = mvebu_corediv_desc,
0228     .ndescs = ARRAY_SIZE(mvebu_corediv_desc),
0229     .ops = {
0230         .recalc_rate = clk_corediv_recalc_rate,
0231         .round_rate = clk_corediv_round_rate,
0232         .set_rate = clk_corediv_set_rate,
0233     },
0234     .ratio_reload = BIT(8),
0235     .ratio_offset = 0x4,
0236 };
0237 
0238 static const struct clk_corediv_soc_desc mv98dx3236_corediv_soc = {
0239     .descs = mv98dx3236_corediv_desc,
0240     .ndescs = ARRAY_SIZE(mv98dx3236_corediv_desc),
0241     .ops = {
0242         .recalc_rate = clk_corediv_recalc_rate,
0243         .round_rate = clk_corediv_round_rate,
0244         .set_rate = clk_corediv_set_rate,
0245     },
0246     .ratio_reload = BIT(10),
0247     .ratio_offset = 0x8,
0248 };
0249 
0250 static void __init
0251 mvebu_corediv_clk_init(struct device_node *node,
0252                const struct clk_corediv_soc_desc *soc_desc)
0253 {
0254     struct clk_init_data init;
0255     struct clk_corediv *corediv;
0256     struct clk **clks;
0257     void __iomem *base;
0258     const char *parent_name;
0259     const char *clk_name;
0260     int i;
0261 
0262     base = of_iomap(node, 0);
0263     if (WARN_ON(!base))
0264         return;
0265 
0266     parent_name = of_clk_get_parent_name(node, 0);
0267 
0268     clk_data.clk_num = soc_desc->ndescs;
0269 
0270     /* clks holds the clock array */
0271     clks = kcalloc(clk_data.clk_num, sizeof(struct clk *),
0272                 GFP_KERNEL);
0273     if (WARN_ON(!clks))
0274         goto err_unmap;
0275     /* corediv holds the clock specific array */
0276     corediv = kcalloc(clk_data.clk_num, sizeof(struct clk_corediv),
0277                 GFP_KERNEL);
0278     if (WARN_ON(!corediv))
0279         goto err_free_clks;
0280 
0281     spin_lock_init(&corediv->lock);
0282 
0283     for (i = 0; i < clk_data.clk_num; i++) {
0284         of_property_read_string_index(node, "clock-output-names",
0285                           i, &clk_name);
0286         init.num_parents = 1;
0287         init.parent_names = &parent_name;
0288         init.name = clk_name;
0289         init.ops = &soc_desc->ops;
0290         init.flags = 0;
0291 
0292         corediv[i].soc_desc = soc_desc;
0293         corediv[i].desc = soc_desc->descs + i;
0294         corediv[i].reg = base;
0295         corediv[i].hw.init = &init;
0296 
0297         clks[i] = clk_register(NULL, &corediv[i].hw);
0298         WARN_ON(IS_ERR(clks[i]));
0299     }
0300 
0301     clk_data.clks = clks;
0302     of_clk_add_provider(node, of_clk_src_onecell_get, &clk_data);
0303     return;
0304 
0305 err_free_clks:
0306     kfree(clks);
0307 err_unmap:
0308     iounmap(base);
0309 }
0310 
0311 static void __init armada370_corediv_clk_init(struct device_node *node)
0312 {
0313     return mvebu_corediv_clk_init(node, &armada370_corediv_soc);
0314 }
0315 CLK_OF_DECLARE(armada370_corediv_clk, "marvell,armada-370-corediv-clock",
0316            armada370_corediv_clk_init);
0317 
0318 static void __init armada375_corediv_clk_init(struct device_node *node)
0319 {
0320     return mvebu_corediv_clk_init(node, &armada375_corediv_soc);
0321 }
0322 CLK_OF_DECLARE(armada375_corediv_clk, "marvell,armada-375-corediv-clock",
0323            armada375_corediv_clk_init);
0324 
0325 static void __init armada380_corediv_clk_init(struct device_node *node)
0326 {
0327     return mvebu_corediv_clk_init(node, &armada380_corediv_soc);
0328 }
0329 CLK_OF_DECLARE(armada380_corediv_clk, "marvell,armada-380-corediv-clock",
0330            armada380_corediv_clk_init);
0331 
0332 static void __init mv98dx3236_corediv_clk_init(struct device_node *node)
0333 {
0334     return mvebu_corediv_clk_init(node, &mv98dx3236_corediv_soc);
0335 }
0336 CLK_OF_DECLARE(mv98dx3236_corediv_clk, "marvell,mv98dx3236-corediv-clock",
0337            mv98dx3236_corediv_clk_init);