1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2020 Oskar Holmlund <oskar.holmlund@ohdata.se>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/bus.h>
31 #include <sys/malloc.h>
32
33 #include <dev/clk/clk.h>
34
35 #include <arm/ti/clk/ti_clk_clkctrl.h>
36
37 #include "clkdev_if.h"
38
39 #if 0
40 #define DPRINTF(dev, msg...) device_printf(dev, msg)
41 #else
42 #define DPRINTF(dev, msg...)
43 #endif
44
45 /*
46 * clknode for clkctrl, implements gate and mux (for gpioc)
47 */
48
49 #define GPIO_X_GDBCLK_MASK 0x00040000
50 #define IDLEST_MASK 0x00030000
51 #define MODULEMODE_MASK 0x00000003
52
53 #define GPIOX_GDBCLK_ENABLE 0x00040000
54 #define GPIOX_GDBCLK_DISABLE 0x00000000
55 #define IDLEST_FUNC 0x00000000
56 #define IDLEST_TRANS 0x00010000
57 #define IDLEST_IDLE 0x00020000
58 #define IDLEST_DISABLE 0x00030000
59
60 #define MODULEMODE_DISABLE 0x0
61 #define MODULEMODE_ENABLE 0x2
62
63 struct ti_clkctrl_clknode_sc {
64 device_t dev;
65 bool gdbclk;
66 /* omap4-cm range.host + ti,clkctrl reg[0] */
67 uint32_t register_offset;
68 };
69
70 #define WRITE4(_clk, off, val) \
71 CLKDEV_WRITE_4(clknode_get_device(_clk), off, val)
72 #define READ4(_clk, off, val) \
73 CLKDEV_READ_4(clknode_get_device(_clk), off, val)
74 #define DEVICE_LOCK(_clk) \
75 CLKDEV_DEVICE_LOCK(clknode_get_device(_clk))
76 #define DEVICE_UNLOCK(_clk) \
77 CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))
78
79 static int
ti_clkctrl_init(struct clknode * clk,device_t dev)80 ti_clkctrl_init(struct clknode *clk, device_t dev)
81 {
82 struct ti_clkctrl_clknode_sc *sc;
83
84 sc = clknode_get_softc(clk);
85 sc->dev = dev;
86
87 clknode_init_parent_idx(clk, 0);
88 return (0);
89 }
90
91 static int
ti_clkctrl_set_gdbclk_gate(struct clknode * clk,bool enable)92 ti_clkctrl_set_gdbclk_gate(struct clknode *clk, bool enable)
93 {
94 struct ti_clkctrl_clknode_sc *sc;
95 uint32_t val, gpio_x_gdbclk;
96 uint32_t timeout = 100;
97
98 sc = clknode_get_softc(clk);
99
100 READ4(clk, sc->register_offset, &val);
101 DPRINTF(sc->dev, "val(%x) & (%x | %x = %x)\n",
102 val, GPIO_X_GDBCLK_MASK, MODULEMODE_MASK,
103 GPIO_X_GDBCLK_MASK | MODULEMODE_MASK);
104
105 if (enable) {
106 val = val & MODULEMODE_MASK;
107 val |= GPIOX_GDBCLK_ENABLE;
108 } else {
109 val = val & MODULEMODE_MASK;
110 val |= GPIOX_GDBCLK_DISABLE;
111 }
112
113 DPRINTF(sc->dev, "val %x\n", val);
114 WRITE4(clk, sc->register_offset, val);
115
116 /* Wait */
117 while (timeout) {
118 READ4(clk, sc->register_offset, &val);
119 gpio_x_gdbclk = val & GPIO_X_GDBCLK_MASK;
120 if (enable && (gpio_x_gdbclk == GPIOX_GDBCLK_ENABLE))
121 break;
122 else if (!enable && (gpio_x_gdbclk == GPIOX_GDBCLK_DISABLE))
123 break;
124 DELAY(10);
125 timeout--;
126 }
127 if (timeout == 0) {
128 device_printf(sc->dev, "ti_clkctrl_set_gdbclk_gate: Timeout\n");
129 return (1);
130 }
131
132 return (0);
133 }
134
135 static int
ti_clkctrl_set_gate(struct clknode * clk,bool enable)136 ti_clkctrl_set_gate(struct clknode *clk, bool enable)
137 {
138 struct ti_clkctrl_clknode_sc *sc;
139 uint32_t val, idlest, module;
140 uint32_t timeout=100;
141 int err;
142
143 sc = clknode_get_softc(clk);
144
145 if (sc->gdbclk) {
146 err = ti_clkctrl_set_gdbclk_gate(clk, enable);
147 return (err);
148 }
149
150 READ4(clk, sc->register_offset, &val);
151
152 if (enable)
153 WRITE4(clk, sc->register_offset, MODULEMODE_ENABLE);
154 else
155 WRITE4(clk, sc->register_offset, MODULEMODE_DISABLE);
156
157 while (timeout) {
158 READ4(clk, sc->register_offset, &val);
159 idlest = val & IDLEST_MASK;
160 module = val & MODULEMODE_MASK;
161 if (enable &&
162 (idlest == IDLEST_FUNC || idlest == IDLEST_TRANS) &&
163 module == MODULEMODE_ENABLE)
164 break;
165 else if (!enable &&
166 idlest == IDLEST_DISABLE &&
167 module == MODULEMODE_DISABLE)
168 break;
169 DELAY(10);
170 timeout--;
171 }
172
173 if (timeout == 0) {
174 device_printf(sc->dev, "ti_clkctrl_set_gate: Timeout\n");
175 return (1);
176 }
177
178 return (0);
179 }
180
181 static clknode_method_t ti_clkctrl_clknode_methods[] = {
182 /* Device interface */
183 CLKNODEMETHOD(clknode_init, ti_clkctrl_init),
184 CLKNODEMETHOD(clknode_set_gate, ti_clkctrl_set_gate),
185 CLKNODEMETHOD_END
186 };
187
188 DEFINE_CLASS_1(ti_clkctrl_clknode, ti_clkctrl_clknode_class,
189 ti_clkctrl_clknode_methods, sizeof(struct ti_clkctrl_clknode_sc),
190 clknode_class);
191
192 int
ti_clknode_clkctrl_register(struct clkdom * clkdom,struct ti_clk_clkctrl_def * clkdef)193 ti_clknode_clkctrl_register(struct clkdom *clkdom,
194 struct ti_clk_clkctrl_def *clkdef)
195 {
196 struct clknode *clk;
197 struct ti_clkctrl_clknode_sc *sc;
198
199 clk = clknode_create(clkdom, &ti_clkctrl_clknode_class,
200 &clkdef->clkdef);
201
202 if (clk == NULL) {
203 return (1);
204 }
205
206 sc = clknode_get_softc(clk);
207 sc->register_offset = clkdef->register_offset;
208 sc->gdbclk = clkdef->gdbclk;
209
210 if (clknode_register(clkdom, clk) == NULL) {
211 return (2);
212 }
213 return (0);
214 }
215