// SPDX-License-Identifier: GPL-2.0+ /* * Copyright 2022 NXP * * Peng Fan */ #include #include #include #include #include #include #include #include #include "clk.h" #include #define UBOOT_DM_CLK_IMX_GATE93 "imx_clk_gate93" #define DIRECT_OFFSET 0x0 /* * 0b000 - LPCG will be OFF in any CPU mode. * 0b100 - LPCG will be ON in any CPU mode. */ #define LPM_SETTING_OFF 0x0 #define LPM_SETTING_ON 0x4 #define LPM_CUR_OFFSET 0x1c #define AUTHEN_OFFSET 0x30 #define CPULPM_EN BIT(2) #define TZ_NS_SHIFT 9 #define TZ_NS_MASK BIT(9) #define WHITE_LIST_SHIFT 16 struct imx93_clk_gate { struct clk clk; void __iomem *reg; u32 bit_idx; u32 val; u32 mask; unsigned int *share_count; }; #define to_imx93_clk_gate(_clk) container_of(_clk, struct imx93_clk_gate, clk) static void imx93_clk_gate_do_hardware(struct clk *clk, bool enable) { struct imx93_clk_gate *gate = to_imx93_clk_gate(clk); u32 val; val = readl(gate->reg + AUTHEN_OFFSET); if (val & CPULPM_EN) { val = enable ? LPM_SETTING_ON : LPM_SETTING_OFF; writel(val, gate->reg + LPM_CUR_OFFSET); } else { val = readl(gate->reg + DIRECT_OFFSET); val &= ~(gate->mask << gate->bit_idx); if (enable) val |= (gate->val & gate->mask) << gate->bit_idx; writel(val, gate->reg + DIRECT_OFFSET); } } static int imx93_clk_gate_enable(struct clk *clk) { struct imx93_clk_gate *gate = to_imx93_clk_gate(clk); if (gate->share_count && (*gate->share_count)++ > 0) return 0; imx93_clk_gate_do_hardware(clk, true); return 0; } static int imx93_clk_gate_disable(struct clk *clk) { struct imx93_clk_gate *gate = to_imx93_clk_gate(clk); if (gate->share_count) { if (WARN_ON(*gate->share_count == 0)) return 0; else if (--(*gate->share_count) > 0) return 0; } imx93_clk_gate_do_hardware(clk, false); return 0; } static ulong imx93_clk_set_rate(struct clk *clk, ulong rate) { struct clk *parent = clk_get_parent(clk); if (parent) return clk_set_rate(parent, rate); return -ENODEV; } static const struct clk_ops imx93_clk_gate_ops = { .enable = imx93_clk_gate_enable, .disable = imx93_clk_gate_disable, .get_rate = clk_generic_get_rate, .set_rate = imx93_clk_set_rate, }; struct clk *imx93_clk_gate(struct device *dev, const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, u32 bit_idx, u32 val, u32 mask, u32 domain_id, unsigned int *share_count) { struct imx93_clk_gate *gate; struct clk *clk; int ret; gate = kzalloc(sizeof(*gate), GFP_KERNEL); if (!gate) return ERR_PTR(-ENOMEM); gate->reg = reg; gate->bit_idx = bit_idx; gate->val = val; gate->mask = mask; gate->share_count = share_count; clk = &gate->clk; ret = clk_register(clk, UBOOT_DM_CLK_IMX_GATE93, name, parent_name); if (ret) { kfree(gate); return ERR_PTR(ret); } return clk; } U_BOOT_DRIVER(clk_gate93) = { .name = UBOOT_DM_CLK_IMX_GATE93, .id = UCLASS_CLK, .ops = &imx93_clk_gate_ops, .flags = DM_FLAG_PRE_RELOC, };