xref: /freebsd/sys/arm/ti/clk/ti_clk_clkctrl.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
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/cdefs.h>
29 __FBSDID("$FreeBSD$");
30 
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/bus.h>
34 #include <sys/malloc.h>
35 
36 #include <dev/extres/clk/clk.h>
37 
38 #include <arm/ti/clk/ti_clk_clkctrl.h>
39 
40 #include "clkdev_if.h"
41 
42 #if 0
43 #define DPRINTF(dev, msg...) device_printf(dev, msg)
44 #else
45 #define DPRINTF(dev, msg...)
46 #endif
47 
48 /*
49  * clknode for clkctrl, implements gate and mux (for gpioc)
50  */
51 
52 #define GPIO_X_GDBCLK_MASK	0x00040000
53 #define IDLEST_MASK		0x00030000
54 #define MODULEMODE_MASK		0x00000003
55 
56 #define GPIOX_GDBCLK_ENABLE	0x00040000
57 #define GPIOX_GDBCLK_DISABLE	0x00000000
58 #define IDLEST_FUNC		0x00000000
59 #define IDLEST_TRANS		0x00010000
60 #define IDLEST_IDLE		0x00020000
61 #define IDLEST_DISABLE		0x00030000
62 
63 #define MODULEMODE_DISABLE	0x0
64 #define MODULEMODE_ENABLE	0x2
65 
66 struct ti_clkctrl_clknode_sc {
67 	device_t	dev;
68 	bool		gdbclk;
69 	/* omap4-cm range.host + ti,clkctrl reg[0] */
70 	uint32_t	register_offset;
71 };
72 
73 #define	WRITE4(_clk, off, val)						\
74 	CLKDEV_WRITE_4(clknode_get_device(_clk), off, val)
75 #define	READ4(_clk, off, val)						\
76 	CLKDEV_READ_4(clknode_get_device(_clk), off, val)
77 #define	DEVICE_LOCK(_clk)						\
78 	CLKDEV_DEVICE_LOCK(clknode_get_device(_clk))
79 #define	DEVICE_UNLOCK(_clk)						\
80 	CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))
81 
82 static int
83 ti_clkctrl_init(struct clknode *clk, device_t dev)
84 {
85 	struct ti_clkctrl_clknode_sc *sc;
86 
87 	sc = clknode_get_softc(clk);
88 	sc->dev = dev;
89 
90 	clknode_init_parent_idx(clk, 0);
91 	return (0);
92 }
93 
94 static int
95 ti_clkctrl_set_gdbclk_gate(struct clknode *clk, bool enable)
96 {
97 	struct ti_clkctrl_clknode_sc *sc;
98 	uint32_t val, gpio_x_gdbclk;
99 	uint32_t timeout = 100;
100 
101 	sc = clknode_get_softc(clk);
102 
103 	READ4(clk, sc->register_offset, &val);
104 	DPRINTF(sc->dev, "val(%x) & (%x | %x = %x)\n",
105 	    val, GPIO_X_GDBCLK_MASK, MODULEMODE_MASK,
106 	    GPIO_X_GDBCLK_MASK | MODULEMODE_MASK);
107 
108 	if (enable) {
109 		val = val & MODULEMODE_MASK;
110 		val |= GPIOX_GDBCLK_ENABLE;
111 	} else {
112 		val = val & MODULEMODE_MASK;
113 		val |= GPIOX_GDBCLK_DISABLE;
114 	}
115 
116 	DPRINTF(sc->dev, "val %x\n", val);
117 	WRITE4(clk, sc->register_offset, val);
118 
119 	/* Wait */
120 	while (timeout) {
121 		READ4(clk, sc->register_offset, &val);
122 		gpio_x_gdbclk = val & GPIO_X_GDBCLK_MASK;
123 		if (enable && (gpio_x_gdbclk == GPIOX_GDBCLK_ENABLE))
124 			break;
125 		else if (!enable && (gpio_x_gdbclk == GPIOX_GDBCLK_DISABLE))
126 			break;
127 		DELAY(10);
128 		timeout--;
129 	}
130 	if (timeout == 0) {
131 		device_printf(sc->dev, "ti_clkctrl_set_gdbclk_gate: Timeout\n");
132 		return (1);
133 	}
134 
135 	return (0);
136 }
137 
138 static int
139 ti_clkctrl_set_gate(struct clknode *clk, bool enable)
140 {
141 	struct ti_clkctrl_clknode_sc *sc;
142 	uint32_t	val, idlest, module;
143 	uint32_t timeout=100;
144 	int err;
145 
146 	sc = clknode_get_softc(clk);
147 
148 	if (sc->gdbclk) {
149 		err = ti_clkctrl_set_gdbclk_gate(clk, enable);
150 		return (err);
151 	}
152 
153 	READ4(clk, sc->register_offset, &val);
154 
155 	if (enable)
156 		WRITE4(clk, sc->register_offset, MODULEMODE_ENABLE);
157 	else
158 		WRITE4(clk, sc->register_offset, MODULEMODE_DISABLE);
159 
160 	while (timeout) {
161 		READ4(clk, sc->register_offset, &val);
162 		idlest = val & IDLEST_MASK;
163 		module = val & MODULEMODE_MASK;
164 		if (enable &&
165 		    (idlest == IDLEST_FUNC || idlest == IDLEST_TRANS) &&
166 		    module == MODULEMODE_ENABLE)
167 			break;
168 		else if (!enable &&
169 		    idlest == IDLEST_DISABLE &&
170 		    module == MODULEMODE_DISABLE)
171 			break;
172 		DELAY(10);
173 		timeout--;
174 	}
175 
176 	if (timeout == 0) {
177 		device_printf(sc->dev, "ti_clkctrl_set_gate: Timeout\n");
178 		return (1);
179 	}
180 
181 	return (0);
182 }
183 
184 static clknode_method_t ti_clkctrl_clknode_methods[] = {
185 	/* Device interface */
186 	CLKNODEMETHOD(clknode_init,	ti_clkctrl_init),
187 	CLKNODEMETHOD(clknode_set_gate, ti_clkctrl_set_gate),
188 	CLKNODEMETHOD_END
189 };
190 
191 DEFINE_CLASS_1(ti_clkctrl_clknode, ti_clkctrl_clknode_class,
192     ti_clkctrl_clknode_methods, sizeof(struct ti_clkctrl_clknode_sc),
193     clknode_class);
194 
195 int
196 ti_clknode_clkctrl_register(struct clkdom *clkdom,
197     struct ti_clk_clkctrl_def *clkdef)
198 {
199 	struct clknode *clk;
200 	struct ti_clkctrl_clknode_sc *sc;
201 
202 	clk = clknode_create(clkdom, &ti_clkctrl_clknode_class,
203 	    &clkdef->clkdef);
204 
205 	if (clk == NULL) {
206 		return (1);
207 	}
208 
209 	sc = clknode_get_softc(clk);
210 	sc->register_offset = clkdef->register_offset;
211 	sc->gdbclk = clkdef->gdbclk;
212 
213 	if (clknode_register(clkdom, clk) == NULL) {
214 		return (2);
215 	}
216 	return (0);
217 }
218