Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clk: mediatek: fhctl: Add support for older fhctl register layout

The Frequency Hopping Controller (FHCTL) seems to have different
versions, as it has a slightly different register layout on some
older SoCs like MT6795, MT8173, MT8183 (and others).

This driver is indeed compatible with at least some of those older
IP revisions, so all we need to do is to add a way to select the
right register layout at registration time.

Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Link: https://lore.kernel.org/r/20230206100105.861720-2-angelogioacchino.delregno@collabora.com
Reviewed-by: Chen-Yu Tsai <wenst@chromium.org>
Signed-off-by: Stephen Boyd <sboyd@kernel.org>

authored by

AngeloGioacchino Del Regno and committed by
Stephen Boyd
8da312d6 fe15c26e

+52 -9
+23 -3
drivers/clk/mediatek/clk-fhctl.c
··· 14 14 #define PERCENT_TO_DDSLMT(dds, percent_m10) \ 15 15 ((((dds) * (percent_m10)) >> 5) / 100) 16 16 17 - static const struct fhctl_offset fhctl_offset = { 17 + const struct fhctl_offset fhctl_offset_v1 = { 18 + .offset_hp_en = 0x0, 19 + .offset_clk_con = 0x4, 20 + .offset_rst_con = 0x8, 21 + .offset_slope0 = 0xc, 22 + .offset_slope1 = 0x10, 23 + .offset_cfg = 0x0, 24 + .offset_updnlmt = 0x4, 25 + .offset_dds = 0x8, 26 + .offset_dvfs = 0xc, 27 + .offset_mon = 0x10, 28 + }; 29 + 30 + const struct fhctl_offset fhctl_offset_v2 = { 18 31 .offset_hp_en = 0x0, 19 32 .offset_clk_con = 0x8, 20 33 .offset_rst_con = 0xc, ··· 40 27 .offset_mon = 0x10, 41 28 }; 42 29 43 - const struct fhctl_offset *fhctl_get_offset_table(void) 30 + const struct fhctl_offset *fhctl_get_offset_table(enum fhctl_variant v) 44 31 { 45 - return &fhctl_offset; 32 + switch (v) { 33 + case FHCTL_PLLFH_V1: 34 + return &fhctl_offset_v1; 35 + case FHCTL_PLLFH_V2: 36 + return &fhctl_offset_v2; 37 + default: 38 + return ERR_PTR(-EINVAL); 39 + }; 46 40 } 47 41 48 42 static void dump_hw(struct mtk_clk_pll *pll, struct fh_pll_regs *regs,
+8 -1
drivers/clk/mediatek/clk-fhctl.h
··· 7 7 #ifndef __CLK_FHCTL_H 8 8 #define __CLK_FHCTL_H 9 9 10 + #include "clk-pllfh.h" 11 + 12 + enum fhctl_variant { 13 + FHCTL_PLLFH_V1, 14 + FHCTL_PLLFH_V2, 15 + }; 16 + 10 17 struct fhctl_offset { 11 18 u32 offset_hp_en; 12 19 u32 offset_clk_con; ··· 26 19 u32 offset_dvfs; 27 20 u32 offset_mon; 28 21 }; 29 - const struct fhctl_offset *fhctl_get_offset_table(void); 22 + const struct fhctl_offset *fhctl_get_offset_table(enum fhctl_variant v); 30 23 const struct fh_operation *fhctl_get_ops(void); 31 24 void fhctl_hw_init(struct mtk_fh *fh); 32 25
+2
drivers/clk/mediatek/clk-mt8186-apmixedsys.c
··· 7 7 #include <linux/platform_device.h> 8 8 #include <dt-bindings/clock/mt8186-clk.h> 9 9 10 + #include "clk-fhctl.h" 10 11 #include "clk-mtk.h" 11 12 #include "clk-pll.h" 12 13 #include "clk-pllfh.h" ··· 99 98 .data = { \ 100 99 .pll_id = _pllid, \ 101 100 .fh_id = _fhid, \ 101 + .fh_ver = FHCTL_PLLFH_V2, \ 102 102 .fhx_offset = _offset, \ 103 103 .dds_mask = GENMASK(21, 0), \ 104 104 .slope0_value = 0x6003c97, \
+18 -5
drivers/clk/mediatek/clk-pllfh.c
··· 104 104 } 105 105 } 106 106 107 - static void pllfh_init(struct mtk_fh *fh, struct mtk_pllfh_data *pllfh_data) 107 + static int pllfh_init(struct mtk_fh *fh, struct mtk_pllfh_data *pllfh_data) 108 108 { 109 109 struct fh_pll_regs *regs = &fh->regs; 110 110 const struct fhctl_offset *offset; 111 111 void __iomem *base = pllfh_data->state.base; 112 112 void __iomem *fhx_base = base + pllfh_data->data.fhx_offset; 113 113 114 - offset = fhctl_get_offset_table(); 114 + offset = fhctl_get_offset_table(pllfh_data->data.fh_ver); 115 + if (IS_ERR(offset)) 116 + return PTR_ERR(offset); 115 117 116 118 regs->reg_hp_en = base + offset->offset_hp_en; 117 119 regs->reg_clk_con = base + offset->offset_clk_con; ··· 131 129 fh->lock = &pllfh_lock; 132 130 133 131 fh->ops = fhctl_get_ops(); 132 + 133 + return 0; 134 134 } 135 135 136 136 static bool fhctl_is_supported_and_enabled(const struct mtk_pllfh_data *pllfh) ··· 146 142 { 147 143 struct clk_hw *hw; 148 144 struct mtk_fh *fh; 145 + int ret; 149 146 150 147 fh = kzalloc(sizeof(*fh), GFP_KERNEL); 151 148 if (!fh) 152 149 return ERR_PTR(-ENOMEM); 153 150 154 - pllfh_init(fh, pllfh_data); 151 + ret = pllfh_init(fh, pllfh_data); 152 + if (ret) { 153 + hw = ERR_PTR(ret); 154 + goto out; 155 + } 155 156 156 157 hw = mtk_clk_register_pll_ops(&fh->clk_pll, pll_data, base, 157 158 &mtk_pllfh_ops); 158 159 159 160 if (IS_ERR(hw)) 161 + goto out; 162 + 163 + fhctl_hw_init(fh); 164 + 165 + out: 166 + if (IS_ERR(hw)) 160 167 kfree(fh); 161 - else 162 - fhctl_hw_init(fh); 163 168 164 169 return hw; 165 170 }
+1
drivers/clk/mediatek/clk-pllfh.h
··· 18 18 struct fh_pll_data { 19 19 int pll_id; 20 20 int fh_id; 21 + int fh_ver; 21 22 u32 fhx_offset; 22 23 u32 dds_mask; 23 24 u32 slope0_value;