blob: 2cf20be2ccae356e116677076fd9276b47d2d79e [file] [log] [blame]
Sébastien Szymanski8d163f52023-07-25 10:08:53 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2021 NXP
4 *
5 * Peng Fan <peng.fan@nxp.com>
6 */
Sébastien Szymanski8d163f52023-07-25 10:08:53 +02007#include <log.h>
8#include <asm/io.h>
9#include <malloc.h>
10#include <clk-uclass.h>
11#include <dm/device.h>
12#include <dm/devres.h>
13#include <linux/iopoll.h>
14#include <linux/clk-provider.h>
15#include <clk.h>
16#include "clk.h"
17#include <linux/err.h>
18
19#define TIMEOUT_US 500U
20
21#define CCM_DIV_SHIFT 0
22#define CCM_DIV_WIDTH 8
23#define CCM_MUX_SHIFT 8
24#define CCM_MUX_MASK 3
25#define CCM_OFF_SHIFT 24
26#define CCM_BUSY_SHIFT 28
27
28#define STAT_OFFSET 0x4
29#define AUTHEN_OFFSET 0x30
30#define TZ_NS_SHIFT 9
31#define TZ_NS_MASK BIT(9)
32
33#define WHITE_LIST_SHIFT 16
34
35#define readl_poll_timeout_atomic readl_poll_timeout
36
37static int imx93_clk_composite_wait_ready(struct clk *clk, void __iomem *reg)
38{
39 int ret;
40 u32 val;
41
42 ret = readl_poll_timeout_atomic(reg + STAT_OFFSET, val, !(val & BIT(CCM_BUSY_SHIFT)),
43 TIMEOUT_US);
44 if (ret)
45 pr_err("Slice[%s] busy timeout\n", "TODO");
46
47 return ret;
48}
49
50static void imx93_clk_composite_gate_endisable(struct clk *clk, int enable)
51{
52 struct clk_gate *gate = to_clk_gate(clk);
53 u32 reg;
54
55 reg = readl(gate->reg);
56
57 if (enable)
58 reg &= ~BIT(gate->bit_idx);
59 else
60 reg |= BIT(gate->bit_idx);
61
62 writel(reg, gate->reg);
63
64 imx93_clk_composite_wait_ready(clk, gate->reg);
65}
66
67static int imx93_clk_composite_gate_enable(struct clk *clk)
68{
69 imx93_clk_composite_gate_endisable(clk, 1);
70
71 return 0;
72}
73
74static int imx93_clk_composite_gate_disable(struct clk *clk)
75{
76 imx93_clk_composite_gate_endisable(clk, 0);
77
78 return 0;
79}
80
81static const struct clk_ops imx93_clk_composite_gate_ops = {
82 .enable = imx93_clk_composite_gate_enable,
83 .disable = imx93_clk_composite_gate_disable,
84};
85
86struct clk *imx93_clk_composite_flags(const char *name,
87 const char * const *parent_names,
88 int num_parents, void __iomem *reg, u32 domain_id,
89 unsigned long flags)
90{
91 struct clk *clk = ERR_PTR(-ENOMEM);
92 struct clk_divider *div = NULL;
93 struct clk_gate *gate = NULL;
94 struct clk_mux *mux = NULL;
95
96 mux = kzalloc(sizeof(*mux), GFP_KERNEL);
97 if (!mux)
98 goto fail;
99
100 mux->reg = reg;
101 mux->shift = CCM_MUX_SHIFT;
102 mux->mask = CCM_MUX_MASK;
103 mux->num_parents = num_parents;
104 mux->parent_names = parent_names;
105 mux->flags = flags;
106
107 div = kzalloc(sizeof(*div), GFP_KERNEL);
108 if (!div)
109 goto fail;
110
111 div->reg = reg;
112 div->shift = CCM_DIV_SHIFT;
113 div->width = CCM_DIV_WIDTH;
114 div->flags = CLK_DIVIDER_ROUND_CLOSEST | flags;
115
116 gate = kzalloc(sizeof(*gate), GFP_KERNEL);
117 if (!gate)
118 goto fail;
119
120 gate->reg = reg;
121 gate->bit_idx = CCM_OFF_SHIFT;
122 gate->flags = flags;
123
124 clk = clk_register_composite(NULL, name,
125 parent_names, num_parents,
126 &mux->clk, &clk_mux_ops,
127 &div->clk, &clk_divider_ops,
128 &gate->clk, &imx93_clk_composite_gate_ops,
129 flags);
130
131 if (IS_ERR(clk))
132 goto fail;
133
134 return clk;
135
136fail:
137 kfree(gate);
138 kfree(div);
139 kfree(mux);
140 return ERR_CAST(clk);
141}