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