blob: bc8574137137f1cae311649b36563164695fc37a [file] [log] [blame]
Sébastien Szymanski9c153e462023-07-25 10:08:53 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2022 NXP
4 *
5 * Peng Fan <peng.fan@nxp.com>
6 */
7
8#include <common.h>
9#include <asm/io.h>
10#include <malloc.h>
11#include <clk-uclass.h>
12#include <dm/device.h>
13#include <dm/devres.h>
14#include <linux/bug.h>
15#include <linux/clk-provider.h>
16#include <clk.h>
17#include "clk.h"
18#include <linux/err.h>
19
20#define UBOOT_DM_CLK_IMX_GATE93 "imx_clk_gate93"
21
22#define DIRECT_OFFSET 0x0
23
24/*
25 * 0b000 - LPCG will be OFF in any CPU mode.
26 * 0b100 - LPCG will be ON in any CPU mode.
27 */
28#define LPM_SETTING_OFF 0x0
29#define LPM_SETTING_ON 0x4
30
31#define LPM_CUR_OFFSET 0x1c
32
33#define AUTHEN_OFFSET 0x30
34#define CPULPM_EN BIT(2)
35#define TZ_NS_SHIFT 9
36#define TZ_NS_MASK BIT(9)
37
38#define WHITE_LIST_SHIFT 16
39
40struct imx93_clk_gate {
41 struct clk clk;
42 void __iomem *reg;
43 u32 bit_idx;
44 u32 val;
45 u32 mask;
46 unsigned int *share_count;
47};
48
49#define to_imx93_clk_gate(_clk) container_of(_clk, struct imx93_clk_gate, clk)
50
51static void imx93_clk_gate_do_hardware(struct clk *clk, bool enable)
52{
53 struct imx93_clk_gate *gate = to_imx93_clk_gate(clk);
54 u32 val;
55
56 val = readl(gate->reg + AUTHEN_OFFSET);
57 if (val & CPULPM_EN) {
58 val = enable ? LPM_SETTING_ON : LPM_SETTING_OFF;
59 writel(val, gate->reg + LPM_CUR_OFFSET);
60 } else {
61 val = readl(gate->reg + DIRECT_OFFSET);
62 val &= ~(gate->mask << gate->bit_idx);
63 if (enable)
64 val |= (gate->val & gate->mask) << gate->bit_idx;
65 writel(val, gate->reg + DIRECT_OFFSET);
66 }
67}
68
69static int imx93_clk_gate_enable(struct clk *clk)
70{
71 struct imx93_clk_gate *gate = to_imx93_clk_gate(clk);
72
73 if (gate->share_count && (*gate->share_count)++ > 0)
74 return 0;
75
76 imx93_clk_gate_do_hardware(clk, true);
77
78 return 0;
79}
80
81static int imx93_clk_gate_disable(struct clk *clk)
82{
83 struct imx93_clk_gate *gate = to_imx93_clk_gate(clk);
84
85 if (gate->share_count) {
86 if (WARN_ON(*gate->share_count == 0))
87 return 0;
88 else if (--(*gate->share_count) > 0)
89 return 0;
90 }
91
92 imx93_clk_gate_do_hardware(clk, false);
93
94 return 0;
95}
96
97static ulong imx93_clk_set_rate(struct clk *clk, ulong rate)
98{
99 struct clk *parent = clk_get_parent(clk);
100
101 if (parent)
102 return clk_set_rate(parent, rate);
103
104 return -ENODEV;
105}
106
107static const struct clk_ops imx93_clk_gate_ops = {
108 .enable = imx93_clk_gate_enable,
109 .disable = imx93_clk_gate_disable,
110 .get_rate = clk_generic_get_rate,
111 .set_rate = imx93_clk_set_rate,
112};
113
114struct clk *imx93_clk_gate(struct device *dev, const char *name, const char *parent_name,
115 unsigned long flags, void __iomem *reg, u32 bit_idx, u32 val,
116 u32 mask, u32 domain_id, unsigned int *share_count)
117{
118 struct imx93_clk_gate *gate;
119 struct clk *clk;
120 int ret;
121
122 gate = kzalloc(sizeof(*gate), GFP_KERNEL);
123 if (!gate)
124 return ERR_PTR(-ENOMEM);
125
126 gate->reg = reg;
127 gate->bit_idx = bit_idx;
128 gate->val = val;
129 gate->mask = mask;
130 gate->share_count = share_count;
131
132 clk = &gate->clk;
133
134 ret = clk_register(clk, UBOOT_DM_CLK_IMX_GATE93, name, parent_name);
135 if (ret) {
136 kfree(gate);
137 return ERR_PTR(ret);
138 }
139
140 return clk;
141}
142
143U_BOOT_DRIVER(clk_gate93) = {
144 .name = UBOOT_DM_CLK_IMX_GATE93,
145 .id = UCLASS_CLK,
146 .ops = &imx93_clk_gate_ops,
147 .flags = DM_FLAG_PRE_RELOC,
148};