aw_gate.c revision 305436
1/*-
2 * Copyright (c) 2016 Jared McNeill <jmcneill@invisible.ca>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
21 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: stable/11/sys/arm/allwinner/clk/aw_gate.c 305436 2016-09-05 20:17:18Z manu $
27 */
28
29/*
30 * Allwinner clock gates
31 */
32
33#include <sys/cdefs.h>
34__FBSDID("$FreeBSD: stable/11/sys/arm/allwinner/clk/aw_gate.c 305436 2016-09-05 20:17:18Z manu $");
35
36#include <sys/param.h>
37#include <sys/systm.h>
38#include <sys/bus.h>
39#include <sys/rman.h>
40#include <sys/kernel.h>
41#include <sys/module.h>
42#include <machine/bus.h>
43
44#include <dev/ofw/ofw_bus.h>
45#include <dev/ofw/ofw_bus_subr.h>
46#include <dev/ofw/ofw_subr.h>
47
48#include <dev/extres/clk/clk_gate.h>
49
50#define	GATE_OFFSET(index)	((index / 32) * 4)
51#define	GATE_SHIFT(index)	(index % 32)
52
53static struct ofw_compat_data compat_data[] = {
54	{ "allwinner,sun4i-a10-dram-gates-clk",
55	  (uintptr_t)"Allwinner DRAM Clock Gates" },
56	{ "allwinner,sun4i-a10-ahb-gates-clk",
57	  (uintptr_t)"Allwinner AHB Clock Gates" },
58	{ "allwinner,sun4i-a10-apb0-gates-clk",
59	  (uintptr_t)"Allwinner APB0 Clock Gates" },
60	{ "allwinner,sun4i-a10-apb1-gates-clk",
61	  (uintptr_t)"Allwinner APB1 Clock Gates" },
62
63	{ "allwinner,sun5i-a13-ahb-gates-clk",
64	  (uintptr_t)"Allwinner AHB Clock Gates" },
65	{ "allwinner,sun5i-a13-apb0-gates-clk",
66	  (uintptr_t)"Allwinner APB0 Clock Gates" },
67	{ "allwinner,sun5i-a13-apb1-gates-clk",
68	  (uintptr_t)"Allwinner APB1 Clock Gates" },
69
70	{ "allwinner,sun7i-a20-ahb-gates-clk",
71	  (uintptr_t)"Allwinner AHB Clock Gates" },
72	{ "allwinner,sun7i-a20-apb0-gates-clk",
73	  (uintptr_t)"Allwinner APB0 Clock Gates" },
74	{ "allwinner,sun7i-a20-apb1-gates-clk",
75	  (uintptr_t)"Allwinner APB1 Clock Gates" },
76
77	{ "allwinner,sun6i-a31-ahb1-gates-clk",
78	  (uintptr_t)"Allwinner AHB1 Clock Gates" },
79	{ "allwinner,sun6i-a31-apb0-gates-clk",
80	  (uintptr_t)"Allwinner APB0 Clock Gates" },
81	{ "allwinner,sun6i-a31-apb1-gates-clk",
82	  (uintptr_t)"Allwinner APB1 Clock Gates" },
83	{ "allwinner,sun6i-a31-apb2-gates-clk",
84	  (uintptr_t)"Allwinner APB2 Clock Gates" },
85
86	{ "allwinner,sun8i-a83t-bus-gates-clk",
87	  (uintptr_t)"Allwinner Bus Clock Gates" },
88	{ "allwinner,sun8i-a83t-apb0-gates-clk",
89	  (uintptr_t)"Allwinner APB0 Clock Gates" },
90
91	{ "allwinner,sun8i-h3-bus-gates-clk",
92	  (uintptr_t)"Allwinner Bus Clock Gates"},
93
94	{ "allwinner,sun9i-a80-apbs-gates-clk",
95	  (uintptr_t)"Allwinner APBS Clock Gates" },
96
97	{ NULL, 0 }
98};
99
100static int
101aw_gate_create(device_t dev, bus_addr_t paddr, struct clkdom *clkdom,
102    const char *pclkname, const char *clkname, int index)
103{
104	const char *parent_names[1] = { pclkname };
105	struct clk_gate_def def;
106
107	memset(&def, 0, sizeof(def));
108	def.clkdef.id = index;
109	def.clkdef.name = clkname;
110	def.clkdef.parent_names = parent_names;
111	def.clkdef.parent_cnt = 1;
112	def.offset = paddr + GATE_OFFSET(index);
113	def.shift = GATE_SHIFT(index);
114	def.mask = 1;
115	def.on_value = 1;
116	def.off_value = 0;
117
118	return (clknode_gate_register(clkdom, &def));
119}
120
121static int
122aw_gate_probe(device_t dev)
123{
124	const char *d;
125
126	if (!ofw_bus_status_okay(dev))
127		return (ENXIO);
128
129	d = (const char *)ofw_bus_search_compatible(dev, compat_data)->ocd_data;
130	if (d == NULL)
131		return (ENXIO);
132
133	device_set_desc(dev, d);
134	return (BUS_PROBE_DEFAULT);
135}
136
137static int
138aw_gate_attach(device_t dev)
139{
140	struct clkdom *clkdom;
141	const char **names;
142	int index, nout, error;
143	uint32_t *indices;
144	clk_t clk_parent;
145	bus_addr_t paddr;
146	bus_size_t psize;
147	phandle_t node;
148
149	node = ofw_bus_get_node(dev);
150	indices = NULL;
151
152	if (ofw_reg_to_paddr(node, 0, &paddr, &psize, NULL) != 0) {
153		device_printf(dev, "cannot parse 'reg' property\n");
154		return (ENXIO);
155	}
156
157	clkdom = clkdom_create(dev);
158
159	nout = clk_parse_ofw_out_names(dev, node, &names, &indices);
160	if (nout == 0) {
161		device_printf(dev, "no clock outputs found\n");
162		error = ENOENT;
163		goto fail;
164	}
165	if (indices == NULL) {
166		device_printf(dev, "no clock-indices property\n");
167		error = ENXIO;
168		goto fail;
169	}
170
171	error = clk_get_by_ofw_index(dev, 0, &clk_parent);
172	if (error != 0) {
173		device_printf(dev, "cannot parse clock parent\n");
174		return (ENXIO);
175	}
176
177	for (index = 0; index < nout; index++) {
178		error = aw_gate_create(dev, paddr, clkdom,
179		    clk_get_name(clk_parent), names[index], indices[index]);
180		if (error)
181			goto fail;
182	}
183
184	if (clkdom_finit(clkdom) != 0) {
185		device_printf(dev, "cannot finalize clkdom initialization\n");
186		error = ENXIO;
187		goto fail;
188	}
189
190	if (bootverbose)
191		clkdom_dump(clkdom);
192
193	return (0);
194
195fail:
196	return (error);
197}
198
199static device_method_t aw_gate_methods[] = {
200	/* Device interface */
201	DEVMETHOD(device_probe,		aw_gate_probe),
202	DEVMETHOD(device_attach,	aw_gate_attach),
203
204	DEVMETHOD_END
205};
206
207static driver_t aw_gate_driver = {
208	"aw_gate",
209	aw_gate_methods,
210	0
211};
212
213static devclass_t aw_gate_devclass;
214
215EARLY_DRIVER_MODULE(aw_gate, simplebus, aw_gate_driver,
216    aw_gate_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
217