^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2017, Intel Corporation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/clk-provider.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include "stratix10-clk.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include "clk.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #define CLK_MGR_FREE_SHIFT 16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #define CLK_MGR_FREE_MASK 0x7
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #define SWCTRLBTCLKSEN_SHIFT 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #define to_periph_clk(p) container_of(p, struct socfpga_periph_clk, hw.hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) static unsigned long clk_peri_c_clk_recalc_rate(struct clk_hw *hwclk,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) unsigned long parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) struct socfpga_periph_clk *socfpgaclk = to_periph_clk(hwclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) unsigned long div = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) val = readl(socfpgaclk->hw.reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) val &= GENMASK(SWCTRLBTCLKSEN_SHIFT - 1, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) parent_rate /= val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) return parent_rate / div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) static unsigned long clk_peri_cnt_clk_recalc_rate(struct clk_hw *hwclk,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) unsigned long parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) struct socfpga_periph_clk *socfpgaclk = to_periph_clk(hwclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) unsigned long div = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) if (socfpgaclk->fixed_div) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) div = socfpgaclk->fixed_div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) if (socfpgaclk->hw.reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) div = ((readl(socfpgaclk->hw.reg) & 0x7ff) + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) return parent_rate / div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static u8 clk_periclk_get_parent(struct clk_hw *hwclk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) struct socfpga_periph_clk *socfpgaclk = to_periph_clk(hwclk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) u32 clk_src, mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) u8 parent = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) /* handle the bypass first */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) if (socfpgaclk->bypass_reg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) mask = (0x1 << socfpgaclk->bypass_shift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) parent = ((readl(socfpgaclk->bypass_reg) & mask) >>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) socfpgaclk->bypass_shift);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) if (parent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) return parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) if (socfpgaclk->hw.reg) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) clk_src = readl(socfpgaclk->hw.reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) parent = (clk_src >> CLK_MGR_FREE_SHIFT) &
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) CLK_MGR_FREE_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) return parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) static const struct clk_ops peri_c_clk_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) .recalc_rate = clk_peri_c_clk_recalc_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) .get_parent = clk_periclk_get_parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) static const struct clk_ops peri_cnt_clk_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) .recalc_rate = clk_peri_cnt_clk_recalc_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) .get_parent = clk_periclk_get_parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) struct clk *s10_register_periph(const struct stratix10_perip_c_clock *clks,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) void __iomem *reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) struct clk *clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) struct socfpga_periph_clk *periph_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) struct clk_init_data init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) const char *name = clks->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) const char *parent_name = clks->parent_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) periph_clk = kzalloc(sizeof(*periph_clk), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) if (WARN_ON(!periph_clk))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) periph_clk->hw.reg = reg + clks->offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) init.name = name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) init.ops = &peri_c_clk_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) init.flags = clks->flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) init.num_parents = clks->num_parents;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) init.parent_names = parent_name ? &parent_name : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) if (init.parent_names == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) init.parent_data = clks->parent_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) periph_clk->hw.hw.init = &init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) clk = clk_register(NULL, &periph_clk->hw.hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) if (WARN_ON(IS_ERR(clk))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) kfree(periph_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) return clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) struct clk *s10_register_cnt_periph(const struct stratix10_perip_cnt_clock *clks,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) void __iomem *regbase)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) struct clk *clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) struct socfpga_periph_clk *periph_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) struct clk_init_data init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) const char *name = clks->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) const char *parent_name = clks->parent_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) periph_clk = kzalloc(sizeof(*periph_clk), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) if (WARN_ON(!periph_clk))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) if (clks->offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) periph_clk->hw.reg = regbase + clks->offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) periph_clk->hw.reg = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) if (clks->bypass_reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) periph_clk->bypass_reg = regbase + clks->bypass_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) periph_clk->bypass_reg = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) periph_clk->bypass_shift = clks->bypass_shift;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) periph_clk->fixed_div = clks->fixed_divider;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) init.name = name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) init.ops = &peri_cnt_clk_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) init.flags = clks->flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) init.num_parents = clks->num_parents;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) init.parent_names = parent_name ? &parent_name : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) if (init.parent_names == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) init.parent_data = clks->parent_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) periph_clk->hw.hw.init = &init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) clk = clk_register(NULL, &periph_clk->hw.hw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) if (WARN_ON(IS_ERR(clk))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) kfree(periph_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) return clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) }