0001
0002
0003
0004
0005 #include <linux/slab.h>
0006 #include <linux/clk-provider.h>
0007 #include <linux/io.h>
0008
0009 #include "stratix10-clk.h"
0010 #include "clk.h"
0011
0012 #define CLK_MGR_FREE_SHIFT 16
0013 #define CLK_MGR_FREE_MASK 0x7
0014 #define SWCTRLBTCLKSEN_SHIFT 8
0015
0016 #define to_periph_clk(p) container_of(p, struct socfpga_periph_clk, hw.hw)
0017
0018 static unsigned long n5x_clk_peri_c_clk_recalc_rate(struct clk_hw *hwclk,
0019 unsigned long parent_rate)
0020 {
0021 struct socfpga_periph_clk *socfpgaclk = to_periph_clk(hwclk);
0022 unsigned long div;
0023 unsigned long shift = socfpgaclk->shift;
0024 u32 val;
0025
0026 val = readl(socfpgaclk->hw.reg);
0027 val &= (0x1f << shift);
0028 div = (val >> shift) + 1;
0029
0030 return parent_rate / div;
0031 }
0032
0033 static unsigned long clk_peri_c_clk_recalc_rate(struct clk_hw *hwclk,
0034 unsigned long parent_rate)
0035 {
0036 struct socfpga_periph_clk *socfpgaclk = to_periph_clk(hwclk);
0037 unsigned long div = 1;
0038 u32 val;
0039
0040 val = readl(socfpgaclk->hw.reg);
0041 val &= GENMASK(SWCTRLBTCLKSEN_SHIFT - 1, 0);
0042 parent_rate /= val;
0043
0044 return parent_rate / div;
0045 }
0046
0047 static unsigned long clk_peri_cnt_clk_recalc_rate(struct clk_hw *hwclk,
0048 unsigned long parent_rate)
0049 {
0050 struct socfpga_periph_clk *socfpgaclk = to_periph_clk(hwclk);
0051 unsigned long div = 1;
0052
0053 if (socfpgaclk->fixed_div) {
0054 div = socfpgaclk->fixed_div;
0055 } else {
0056 if (socfpgaclk->hw.reg)
0057 div = ((readl(socfpgaclk->hw.reg) & 0x7ff) + 1);
0058 }
0059
0060 return parent_rate / div;
0061 }
0062
0063 static u8 clk_periclk_get_parent(struct clk_hw *hwclk)
0064 {
0065 struct socfpga_periph_clk *socfpgaclk = to_periph_clk(hwclk);
0066 u32 clk_src, mask;
0067 u8 parent = 0;
0068
0069
0070 if (socfpgaclk->bypass_reg) {
0071 mask = (0x1 << socfpgaclk->bypass_shift);
0072 parent = ((readl(socfpgaclk->bypass_reg) & mask) >>
0073 socfpgaclk->bypass_shift);
0074 if (parent)
0075 return parent;
0076 }
0077
0078 if (socfpgaclk->hw.reg) {
0079 clk_src = readl(socfpgaclk->hw.reg);
0080 parent = (clk_src >> CLK_MGR_FREE_SHIFT) &
0081 CLK_MGR_FREE_MASK;
0082 }
0083 return parent;
0084 }
0085
0086 static const struct clk_ops n5x_peri_c_clk_ops = {
0087 .recalc_rate = n5x_clk_peri_c_clk_recalc_rate,
0088 .get_parent = clk_periclk_get_parent,
0089 };
0090
0091 static const struct clk_ops peri_c_clk_ops = {
0092 .recalc_rate = clk_peri_c_clk_recalc_rate,
0093 .get_parent = clk_periclk_get_parent,
0094 };
0095
0096 static const struct clk_ops peri_cnt_clk_ops = {
0097 .recalc_rate = clk_peri_cnt_clk_recalc_rate,
0098 .get_parent = clk_periclk_get_parent,
0099 };
0100
0101 struct clk_hw *s10_register_periph(const struct stratix10_perip_c_clock *clks,
0102 void __iomem *reg)
0103 {
0104 struct clk_hw *hw_clk;
0105 struct socfpga_periph_clk *periph_clk;
0106 struct clk_init_data init;
0107 const char *name = clks->name;
0108 const char *parent_name = clks->parent_name;
0109 int ret;
0110
0111 periph_clk = kzalloc(sizeof(*periph_clk), GFP_KERNEL);
0112 if (WARN_ON(!periph_clk))
0113 return NULL;
0114
0115 periph_clk->hw.reg = reg + clks->offset;
0116
0117 init.name = name;
0118 init.ops = &peri_c_clk_ops;
0119 init.flags = clks->flags;
0120
0121 init.num_parents = clks->num_parents;
0122 init.parent_names = parent_name ? &parent_name : NULL;
0123 if (init.parent_names == NULL)
0124 init.parent_data = clks->parent_data;
0125
0126 periph_clk->hw.hw.init = &init;
0127 hw_clk = &periph_clk->hw.hw;
0128
0129 ret = clk_hw_register(NULL, hw_clk);
0130 if (ret) {
0131 kfree(periph_clk);
0132 return ERR_PTR(ret);
0133 }
0134 return hw_clk;
0135 }
0136
0137 struct clk_hw *n5x_register_periph(const struct n5x_perip_c_clock *clks,
0138 void __iomem *regbase)
0139 {
0140 struct clk_hw *hw_clk;
0141 struct socfpga_periph_clk *periph_clk;
0142 struct clk_init_data init;
0143 const char *name = clks->name;
0144 const char *parent_name = clks->parent_name;
0145 int ret;
0146
0147 periph_clk = kzalloc(sizeof(*periph_clk), GFP_KERNEL);
0148 if (WARN_ON(!periph_clk))
0149 return NULL;
0150
0151 periph_clk->hw.reg = regbase + clks->offset;
0152 periph_clk->shift = clks->shift;
0153
0154 init.name = name;
0155 init.ops = &n5x_peri_c_clk_ops;
0156 init.flags = clks->flags;
0157
0158 init.num_parents = clks->num_parents;
0159 init.parent_names = parent_name ? &parent_name : NULL;
0160
0161 periph_clk->hw.hw.init = &init;
0162 hw_clk = &periph_clk->hw.hw;
0163
0164 ret = clk_hw_register(NULL, hw_clk);
0165 if (ret) {
0166 kfree(periph_clk);
0167 return ERR_PTR(ret);
0168 }
0169 return hw_clk;
0170 }
0171
0172 struct clk_hw *s10_register_cnt_periph(const struct stratix10_perip_cnt_clock *clks,
0173 void __iomem *regbase)
0174 {
0175 struct clk_hw *hw_clk;
0176 struct socfpga_periph_clk *periph_clk;
0177 struct clk_init_data init;
0178 const char *name = clks->name;
0179 const char *parent_name = clks->parent_name;
0180 int ret;
0181
0182 periph_clk = kzalloc(sizeof(*periph_clk), GFP_KERNEL);
0183 if (WARN_ON(!periph_clk))
0184 return NULL;
0185
0186 if (clks->offset)
0187 periph_clk->hw.reg = regbase + clks->offset;
0188 else
0189 periph_clk->hw.reg = NULL;
0190
0191 if (clks->bypass_reg)
0192 periph_clk->bypass_reg = regbase + clks->bypass_reg;
0193 else
0194 periph_clk->bypass_reg = NULL;
0195 periph_clk->bypass_shift = clks->bypass_shift;
0196 periph_clk->fixed_div = clks->fixed_divider;
0197
0198 init.name = name;
0199 init.ops = &peri_cnt_clk_ops;
0200 init.flags = clks->flags;
0201
0202 init.num_parents = clks->num_parents;
0203 init.parent_names = parent_name ? &parent_name : NULL;
0204 if (init.parent_names == NULL)
0205 init.parent_data = clks->parent_data;
0206
0207 periph_clk->hw.hw.init = &init;
0208 hw_clk = &periph_clk->hw.hw;
0209
0210 ret = clk_hw_register(NULL, hw_clk);
0211 if (ret) {
0212 kfree(periph_clk);
0213 return ERR_PTR(ret);
0214 }
0215 return hw_clk;
0216 }