1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright 2022 NXP 4 * 5 * Peng Fan <peng.fan@nxp.com> 6 */ 7 8 #include <linux/clk-provider.h> 9 #include <linux/errno.h> 10 #include <linux/export.h> 11 #include <linux/io.h> 12 #include <linux/iopoll.h> 13 #include <linux/slab.h> 14 15 #include "clk.h" 16 17 #define DIRECT_OFFSET 0x0 18 19 /* 20 * 0b000 - LPCG will be OFF in any CPU mode. 21 * 0b100 - LPCG will be ON in any CPU mode. 22 */ 23 #define LPM_SETTING_OFF 0x0 24 #define LPM_SETTING_ON 0x4 25 26 #define LPM_CUR_OFFSET 0x1c 27 28 #define AUTHEN_OFFSET 0x30 29 #define CPULPM_EN BIT(2) 30 #define TZ_NS_SHIFT 9 31 #define TZ_NS_MASK BIT(9) 32 33 #define WHITE_LIST_SHIFT 16 34 35 struct imx93_clk_gate { 36 struct clk_hw hw; 37 void __iomem *reg; 38 u32 bit_idx; 39 u32 val; 40 u32 mask; 41 spinlock_t *lock; 42 unsigned int *share_count; 43 }; 44 45 #define to_imx93_clk_gate(_hw) container_of(_hw, struct imx93_clk_gate, hw) 46 47 static void imx93_clk_gate_do_hardware(struct clk_hw *hw, bool enable) 48 { 49 struct imx93_clk_gate *gate = to_imx93_clk_gate(hw); 50 u32 val; 51 52 val = readl(gate->reg + AUTHEN_OFFSET); 53 if (val & CPULPM_EN) { 54 val = enable ? LPM_SETTING_ON : LPM_SETTING_OFF; 55 writel(val, gate->reg + LPM_CUR_OFFSET); 56 } else { 57 val = readl(gate->reg + DIRECT_OFFSET); 58 val &= ~(gate->mask << gate->bit_idx); 59 if (enable) 60 val |= (gate->val & gate->mask) << gate->bit_idx; 61 writel(val, gate->reg + DIRECT_OFFSET); 62 } 63 } 64 65 static int imx93_clk_gate_enable(struct clk_hw *hw) 66 { 67 struct imx93_clk_gate *gate = to_imx93_clk_gate(hw); 68 unsigned long flags; 69 70 spin_lock_irqsave(gate->lock, flags); 71 72 if (gate->share_count && (*gate->share_count)++ > 0) 73 goto out; 74 75 imx93_clk_gate_do_hardware(hw, true); 76 out: 77 spin_unlock_irqrestore(gate->lock, flags); 78 79 return 0; 80 } 81 82 static void imx93_clk_gate_disable(struct clk_hw *hw) 83 { 84 struct imx93_clk_gate *gate = to_imx93_clk_gate(hw); 85 unsigned long flags; 86 87 spin_lock_irqsave(gate->lock, flags); 88 89 if (gate->share_count) { 90 if (WARN_ON(*gate->share_count == 0)) 91 goto out; 92 else if (--(*gate->share_count) > 0) 93 goto out; 94 } 95 96 imx93_clk_gate_do_hardware(hw, false); 97 out: 98 spin_unlock_irqrestore(gate->lock, flags); 99 } 100 101 static int imx93_clk_gate_reg_is_enabled(struct imx93_clk_gate *gate) 102 { 103 u32 val = readl(gate->reg + AUTHEN_OFFSET); 104 105 if (val & CPULPM_EN) { 106 val = readl(gate->reg + LPM_CUR_OFFSET); 107 if (val == LPM_SETTING_ON) 108 return 1; 109 } else { 110 val = readl(gate->reg); 111 if (((val >> gate->bit_idx) & gate->mask) == gate->val) 112 return 1; 113 } 114 115 return 0; 116 } 117 118 static int imx93_clk_gate_is_enabled(struct clk_hw *hw) 119 { 120 struct imx93_clk_gate *gate = to_imx93_clk_gate(hw); 121 unsigned long flags; 122 int ret; 123 124 spin_lock_irqsave(gate->lock, flags); 125 126 ret = imx93_clk_gate_reg_is_enabled(gate); 127 128 spin_unlock_irqrestore(gate->lock, flags); 129 130 return ret; 131 } 132 133 static void imx93_clk_gate_disable_unused(struct clk_hw *hw) 134 { 135 struct imx93_clk_gate *gate = to_imx93_clk_gate(hw); 136 unsigned long flags; 137 138 spin_lock_irqsave(gate->lock, flags); 139 140 if (!gate->share_count || *gate->share_count == 0) 141 imx93_clk_gate_do_hardware(hw, false); 142 143 spin_unlock_irqrestore(gate->lock, flags); 144 } 145 146 static const struct clk_ops imx93_clk_gate_ops = { 147 .enable = imx93_clk_gate_enable, 148 .disable = imx93_clk_gate_disable, 149 .disable_unused = imx93_clk_gate_disable_unused, 150 .is_enabled = imx93_clk_gate_is_enabled, 151 }; 152 153 static const struct clk_ops imx93_clk_gate_ro_ops = { 154 .is_enabled = imx93_clk_gate_is_enabled, 155 }; 156 157 struct clk_hw *imx93_clk_gate(struct device *dev, const char *name, const char *parent_name, 158 unsigned long flags, void __iomem *reg, u32 bit_idx, u32 val, 159 u32 mask, u32 domain_id, unsigned int *share_count) 160 { 161 struct imx93_clk_gate *gate; 162 struct clk_hw *hw; 163 struct clk_init_data init; 164 int ret; 165 u32 authen; 166 167 gate = kzalloc(sizeof(struct imx93_clk_gate), GFP_KERNEL); 168 if (!gate) 169 return ERR_PTR(-ENOMEM); 170 171 gate->reg = reg; 172 gate->lock = &imx_ccm_lock; 173 gate->bit_idx = bit_idx; 174 gate->val = val; 175 gate->mask = mask; 176 gate->share_count = share_count; 177 178 init.name = name; 179 init.ops = &imx93_clk_gate_ops; 180 init.flags = flags | CLK_SET_RATE_PARENT | CLK_OPS_PARENT_ENABLE; 181 init.parent_names = parent_name ? &parent_name : NULL; 182 init.num_parents = parent_name ? 1 : 0; 183 184 gate->hw.init = &init; 185 hw = &gate->hw; 186 187 authen = readl(reg + AUTHEN_OFFSET); 188 if (!(authen & TZ_NS_MASK) || !(authen & BIT(WHITE_LIST_SHIFT + domain_id))) 189 init.ops = &imx93_clk_gate_ro_ops; 190 191 ret = clk_hw_register(dev, hw); 192 if (ret) { 193 kfree(gate); 194 return ERR_PTR(ret); 195 } 196 197 return hw; 198 } 199 EXPORT_SYMBOL_GPL(imx93_clk_gate); 200