Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2017, Intel Corporation
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     /* handle the bypass first */
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 }