Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (c) 2014 Marvell Technology Group Ltd.
0004  *
0005  * Alexandre Belloni <alexandre.belloni@free-electrons.com>
0006  * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
0007  */
0008 #include <linux/bitops.h>
0009 #include <linux/clk-provider.h>
0010 #include <linux/io.h>
0011 #include <linux/of.h>
0012 #include <linux/of_address.h>
0013 #include <linux/slab.h>
0014 #include <linux/spinlock.h>
0015 
0016 #include "berlin2-div.h"
0017 
0018 /*
0019  * Clock dividers in Berlin2 SoCs comprise a complex cell to select
0020  * input pll and divider. The virtual structure as it is used in Marvell
0021  * BSP code can be seen as:
0022  *
0023  *                      +---+
0024  * pll0 --------------->| 0 |                   +---+
0025  *           +---+      |(B)|--+--------------->| 0 |      +---+
0026  * pll1.0 -->| 0 |  +-->| 1 |  |   +--------+   |(E)|----->| 0 |   +---+
0027  * pll1.1 -->| 1 |  |   +---+  +-->|(C) 1:M |-->| 1 |      |(F)|-->|(G)|->
0028  * ...    -->|(A)|--+          |   +--------+   +---+  +-->| 1 |   +---+
0029  * ...    -->|   |             +-->|(D) 1:3 |----------+   +---+
0030  * pll1.N -->| N |                 +---------
0031  *           +---+
0032  *
0033  * (A) input pll clock mux controlled by               <PllSelect[1:n]>
0034  * (B) input pll bypass mux controlled by              <PllSwitch>
0035  * (C) programmable clock divider controlled by        <Select[1:n]>
0036  * (D) constant div-by-3 clock divider
0037  * (E) programmable clock divider bypass controlled by <Switch>
0038  * (F) constant div-by-3 clock mux controlled by       <D3Switch>
0039  * (G) clock gate controlled by                        <Enable>
0040  *
0041  * For whatever reason, above control signals come in two flavors:
0042  * - single register dividers with all bits in one register
0043  * - shared register dividers with bits spread over multiple registers
0044  *   (including signals for the same cell spread over consecutive registers)
0045  *
0046  * Also, clock gate and pll mux is not available on every div cell, so
0047  * we have to deal with those, too. We reuse common clock composite driver
0048  * for it.
0049  */
0050 
0051 #define PLL_SELECT_MASK 0x7
0052 #define DIV_SELECT_MASK 0x7
0053 
0054 struct berlin2_div {
0055     struct clk_hw hw;
0056     void __iomem *base;
0057     struct berlin2_div_map map;
0058     spinlock_t *lock;
0059 };
0060 
0061 #define to_berlin2_div(hw) container_of(hw, struct berlin2_div, hw)
0062 
0063 static u8 clk_div[] = { 1, 2, 4, 6, 8, 12, 1, 1 };
0064 
0065 static int berlin2_div_is_enabled(struct clk_hw *hw)
0066 {
0067     struct berlin2_div *div = to_berlin2_div(hw);
0068     struct berlin2_div_map *map = &div->map;
0069     u32 reg;
0070 
0071     if (div->lock)
0072         spin_lock(div->lock);
0073 
0074     reg = readl_relaxed(div->base + map->gate_offs);
0075     reg >>= map->gate_shift;
0076 
0077     if (div->lock)
0078         spin_unlock(div->lock);
0079 
0080     return (reg & 0x1);
0081 }
0082 
0083 static int berlin2_div_enable(struct clk_hw *hw)
0084 {
0085     struct berlin2_div *div = to_berlin2_div(hw);
0086     struct berlin2_div_map *map = &div->map;
0087     u32 reg;
0088 
0089     if (div->lock)
0090         spin_lock(div->lock);
0091 
0092     reg = readl_relaxed(div->base + map->gate_offs);
0093     reg |= BIT(map->gate_shift);
0094     writel_relaxed(reg, div->base + map->gate_offs);
0095 
0096     if (div->lock)
0097         spin_unlock(div->lock);
0098 
0099     return 0;
0100 }
0101 
0102 static void berlin2_div_disable(struct clk_hw *hw)
0103 {
0104     struct berlin2_div *div = to_berlin2_div(hw);
0105     struct berlin2_div_map *map = &div->map;
0106     u32 reg;
0107 
0108     if (div->lock)
0109         spin_lock(div->lock);
0110 
0111     reg = readl_relaxed(div->base + map->gate_offs);
0112     reg &= ~BIT(map->gate_shift);
0113     writel_relaxed(reg, div->base + map->gate_offs);
0114 
0115     if (div->lock)
0116         spin_unlock(div->lock);
0117 }
0118 
0119 static int berlin2_div_set_parent(struct clk_hw *hw, u8 index)
0120 {
0121     struct berlin2_div *div = to_berlin2_div(hw);
0122     struct berlin2_div_map *map = &div->map;
0123     u32 reg;
0124 
0125     if (div->lock)
0126         spin_lock(div->lock);
0127 
0128     /* index == 0 is PLL_SWITCH */
0129     reg = readl_relaxed(div->base + map->pll_switch_offs);
0130     if (index == 0)
0131         reg &= ~BIT(map->pll_switch_shift);
0132     else
0133         reg |= BIT(map->pll_switch_shift);
0134     writel_relaxed(reg, div->base + map->pll_switch_offs);
0135 
0136     /* index > 0 is PLL_SELECT */
0137     if (index > 0) {
0138         reg = readl_relaxed(div->base + map->pll_select_offs);
0139         reg &= ~(PLL_SELECT_MASK << map->pll_select_shift);
0140         reg |= (index - 1) << map->pll_select_shift;
0141         writel_relaxed(reg, div->base + map->pll_select_offs);
0142     }
0143 
0144     if (div->lock)
0145         spin_unlock(div->lock);
0146 
0147     return 0;
0148 }
0149 
0150 static u8 berlin2_div_get_parent(struct clk_hw *hw)
0151 {
0152     struct berlin2_div *div = to_berlin2_div(hw);
0153     struct berlin2_div_map *map = &div->map;
0154     u32 reg;
0155     u8 index = 0;
0156 
0157     if (div->lock)
0158         spin_lock(div->lock);
0159 
0160     /* PLL_SWITCH == 0 is index 0 */
0161     reg = readl_relaxed(div->base + map->pll_switch_offs);
0162     reg &= BIT(map->pll_switch_shift);
0163     if (reg) {
0164         reg = readl_relaxed(div->base + map->pll_select_offs);
0165         reg >>= map->pll_select_shift;
0166         reg &= PLL_SELECT_MASK;
0167         index = 1 + reg;
0168     }
0169 
0170     if (div->lock)
0171         spin_unlock(div->lock);
0172 
0173     return index;
0174 }
0175 
0176 static unsigned long berlin2_div_recalc_rate(struct clk_hw *hw,
0177                          unsigned long parent_rate)
0178 {
0179     struct berlin2_div *div = to_berlin2_div(hw);
0180     struct berlin2_div_map *map = &div->map;
0181     u32 divsw, div3sw, divider = 1;
0182 
0183     if (div->lock)
0184         spin_lock(div->lock);
0185 
0186     divsw = readl_relaxed(div->base + map->div_switch_offs) &
0187         (1 << map->div_switch_shift);
0188     div3sw = readl_relaxed(div->base + map->div3_switch_offs) &
0189         (1 << map->div3_switch_shift);
0190 
0191     /* constant divide-by-3 (dominant) */
0192     if (div3sw != 0) {
0193         divider = 3;
0194     /* divider can be bypassed with DIV_SWITCH == 0 */
0195     } else if (divsw == 0) {
0196         divider = 1;
0197     /* clock divider determined by DIV_SELECT */
0198     } else {
0199         u32 reg;
0200         reg = readl_relaxed(div->base + map->div_select_offs);
0201         reg >>= map->div_select_shift;
0202         reg &= DIV_SELECT_MASK;
0203         divider = clk_div[reg];
0204     }
0205 
0206     if (div->lock)
0207         spin_unlock(div->lock);
0208 
0209     return parent_rate / divider;
0210 }
0211 
0212 static const struct clk_ops berlin2_div_rate_ops = {
0213     .recalc_rate    = berlin2_div_recalc_rate,
0214 };
0215 
0216 static const struct clk_ops berlin2_div_gate_ops = {
0217     .is_enabled = berlin2_div_is_enabled,
0218     .enable     = berlin2_div_enable,
0219     .disable    = berlin2_div_disable,
0220 };
0221 
0222 static const struct clk_ops berlin2_div_mux_ops = {
0223     .set_parent = berlin2_div_set_parent,
0224     .get_parent = berlin2_div_get_parent,
0225 };
0226 
0227 struct clk_hw * __init
0228 berlin2_div_register(const struct berlin2_div_map *map,
0229              void __iomem *base, const char *name, u8 div_flags,
0230              const char **parent_names, int num_parents,
0231              unsigned long flags, spinlock_t *lock)
0232 {
0233     const struct clk_ops *mux_ops = &berlin2_div_mux_ops;
0234     const struct clk_ops *rate_ops = &berlin2_div_rate_ops;
0235     const struct clk_ops *gate_ops = &berlin2_div_gate_ops;
0236     struct berlin2_div *div;
0237 
0238     div = kzalloc(sizeof(*div), GFP_KERNEL);
0239     if (!div)
0240         return ERR_PTR(-ENOMEM);
0241 
0242     /* copy div_map to allow __initconst */
0243     memcpy(&div->map, map, sizeof(*map));
0244     div->base = base;
0245     div->lock = lock;
0246 
0247     if ((div_flags & BERLIN2_DIV_HAS_GATE) == 0)
0248         gate_ops = NULL;
0249     if ((div_flags & BERLIN2_DIV_HAS_MUX) == 0)
0250         mux_ops = NULL;
0251 
0252     return clk_hw_register_composite(NULL, name, parent_names, num_parents,
0253                       &div->hw, mux_ops, &div->hw, rate_ops,
0254                       &div->hw, gate_ops, flags);
0255 }