1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright 2016 Maxime Ripard
4 *
5 * Maxime Ripard <maxime.ripard@free-electrons.com>
6 */
7 #include "ccu.h"
8 #include "ccu_common.h"
9 #include "ccu_gate.h"
10 #include "ccu_reset.h"
11 #include <hal_log.h>
12 #include <hal_timer.h>
13 #include <stdlib.h>
14
15 /* FIXME: use udelay provided by OS */
__clk_udelay(u32 ns)16 static void __clk_udelay(u32 ns)
17 {
18 u32 i;
19 ns *= 100;
20 for (i = 0; i < ns; i ++)
21 {
22 ;
23 }
24 }
25
ccu_helper_wait_for_lock(struct ccu_common * common,u32 lock)26 void ccu_helper_wait_for_lock(struct ccu_common *common, u32 lock)
27 {
28 unsigned long addr;
29 u32 reg, loop = 5000;
30
31 if (!lock)
32 {
33 return;
34 }
35
36 if (common->features & CCU_FEATURE_LOCK_REG)
37 {
38 addr = common->base + common->lock_reg;
39 }
40 else
41 {
42 addr = common->base + common->reg;
43 }
44
45 while (--loop)
46 {
47 reg = readl(addr);
48 if (reg & lock)
49 {
50 __clk_udelay(20);
51 break;
52 }
53 __clk_udelay(1);
54 }
55 if (!loop)
56 {
57 hal_log_warn("ccu wait for lock failed\n");
58 }
59 }
60
ccu_common_init(unsigned long reg,const struct sunxi_ccu_desc * desc)61 int ccu_common_init(unsigned long reg, const struct sunxi_ccu_desc *desc)
62 {
63 struct ccu_reset *reset;
64 int i;
65 int ret;
66
67 if (!desc)
68 {
69 return 0;
70 }
71
72 for (i = 0; i < desc->num_ccu_clks; i++)
73 {
74 struct ccu_common *cclk = desc->ccu_clks[i];
75
76 if (!cclk)
77 {
78 continue;
79 }
80
81 cclk->base = reg;
82 }
83
84 for (i = 0; i < desc->hw_clks->num; i++)
85 {
86 struct clk_hw *hw = desc->hw_clks->hws[i];
87 const char *name;
88
89 if (!hw)
90 {
91 break;
92 }
93
94 name = hw->init->name;
95 hw->type = desc->clk_type;
96 hw->id = i;
97 ret = clk_hw_register(hw);
98 if (ret)
99 {
100 printf("Couldn't register clock %d - %s\n", i, name);
101 goto err_clk_unreg;
102 }
103
104 }
105
106 reset = (struct ccu_reset *)malloc(sizeof(*reset));
107 if (!reset)
108 {
109 hal_log_err("can't malloc reset struct!\n");
110 ret = -1;
111 goto err_clk_unreg;
112 }
113 reset->base = reg;
114 reset->reset_map = desc->resets;
115 reset->rcdev.ops = &ccu_reset_ops;
116 reset->rcdev.type = desc->reset_type;
117 reset->rcdev.nr_resets = desc->num_resets;
118
119 ret = reset_control_register(&reset->rcdev);
120 if (ret)
121 {
122 goto err_rst_unreg;
123 }
124
125 return ret;
126
127 err_rst_unreg:
128
129 free(reset);
130
131 err_clk_unreg:
132 while (i-- >= 0)
133 {
134 struct clk_hw *hw = desc->hw_clks->hws[i];
135
136 clk_hw_unregister(hw);
137 }
138
139 return ret;
140 }
141
set_reg(unsigned long addr,u32 val,u8 bw,u8 bs)142 void set_reg(unsigned long addr, u32 val, u8 bw, u8 bs)
143 {
144 u32 mask = (1UL << bw) - 1UL;
145 u32 tmp = 0;
146
147 tmp = readl(addr);
148 tmp &= ~(mask << bs);
149
150 writel(tmp | ((val & mask) << bs), addr);
151 }
152
set_reg_key(unsigned long addr,u32 key,u8 kbw,u8 kbs,u32 val,u8 bw,u8 bs)153 void set_reg_key(unsigned long addr,
154 u32 key, u8 kbw, u8 kbs,
155 u32 val, u8 bw, u8 bs)
156 {
157 u32 mask = (1UL << bw) - 1UL;
158 u32 kmask = (1UL << kbw) - 1UL;
159 u32 tmp = 0;
160
161 tmp = readl(addr);
162 tmp &= ~(mask << bs);
163
164 writel(tmp | ((val & mask) << bs) | ((key & kmask) << kbs), addr);
165 }
166
167