xref: /freebsd/sys/arm/ti/ti_scm.c (revision cc16dea626cf2fc80cde667ac4798065108e596c)
1 /*
2  * Copyright (c) 2010
3  *	Ben Gray <ben.r.gray@gmail.com>.
4  * All rights reserved.
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  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *	This product includes software developed by Ben Gray.
17  * 4. The name of the company nor the name of the author may be used to
18  *    endorse or promote products derived from this software without specific
19  *    prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL BEN GRAY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
30  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /**
34  *	SCM - System Control Module
35  *
36  *	Hopefully in the end this module will contain a bunch of utility functions
37  *	for configuring and querying the general system control registers, but for
38  *	now it only does pin(pad) multiplexing.
39  *
40  *	This is different from the GPIO module in that it is used to configure the
41  *	pins between modules not just GPIO input/output.
42  *
43  *	This file contains the generic top level driver, however it relies on chip
44  *	specific settings and therefore expects an array of ti_scm_padconf structs
45  *	call ti_padconf_devmap to be located somewhere in the kernel.
46  *
47  */
48 #include <sys/cdefs.h>
49 __FBSDID("$FreeBSD$");
50 
51 #include <sys/param.h>
52 #include <sys/systm.h>
53 #include <sys/kernel.h>
54 #include <sys/module.h>
55 #include <sys/bus.h>
56 #include <sys/resource.h>
57 #include <sys/rman.h>
58 #include <sys/lock.h>
59 #include <sys/mutex.h>
60 
61 #include <machine/bus.h>
62 #include <machine/cpu.h>
63 #include <machine/cpufunc.h>
64 #include <machine/frame.h>
65 #include <machine/resource.h>
66 
67 #include <dev/fdt/fdt_common.h>
68 #include <dev/ofw/openfirm.h>
69 #include <dev/ofw/ofw_bus.h>
70 #include <dev/ofw/ofw_bus_subr.h>
71 
72 #include "ti_scm.h"
73 
74 static struct resource_spec ti_scm_res_spec[] = {
75 	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },	/* Control memory window */
76 	{ -1, 0 }
77 };
78 
79 static struct ti_scm_softc *ti_scm_sc;
80 
81 #define	ti_scm_read_2(sc, reg)		\
82     bus_space_read_2((sc)->sc_bst, (sc)->sc_bsh, (reg))
83 #define	ti_scm_write_2(sc, reg, val)		\
84     bus_space_write_2((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
85 #define	ti_scm_read_4(sc, reg)		\
86     bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
87 #define	ti_scm_write_4(sc, reg, val)		\
88     bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
89 
90 
91 /**
92  *	ti_padconf_devmap - Array of pins, should be defined one per SoC
93  *
94  *	This array is typically defined in one of the targeted *_scm_pinumx.c
95  *	files and is specific to the given SoC platform. Each entry in the array
96  *	corresponds to an individual pin.
97  */
98 extern const struct ti_scm_device ti_scm_dev;
99 
100 
101 /**
102  *	ti_scm_padconf_from_name - searches the list of pads and returns entry
103  *	                             with matching ball name.
104  *	@ballname: the name of the ball
105  *
106  *	RETURNS:
107  *	A pointer to the matching padconf or NULL if the ball wasn't found.
108  */
109 static const struct ti_scm_padconf*
110 ti_scm_padconf_from_name(const char *ballname)
111 {
112 	const struct ti_scm_padconf *padconf;
113 
114 	padconf = ti_scm_dev.padconf;
115 	while (padconf->ballname != NULL) {
116 		if (strcmp(ballname, padconf->ballname) == 0)
117 			return(padconf);
118 		padconf++;
119 	}
120 
121 	return (NULL);
122 }
123 
124 /**
125  *	ti_scm_padconf_set_internal - sets the muxmode and state for a pad/pin
126  *	@padconf: pointer to the pad structure
127  *	@muxmode: the name of the mode to use for the pin, i.e. "uart1_rx"
128  *	@state: the state to put the pad/pin in, i.e. PADCONF_PIN_???
129  *
130  *
131  *	LOCKING:
132  *	Internally locks it's own context.
133  *
134  *	RETURNS:
135  *	0 on success.
136  *	EINVAL if pin requested is outside valid range or already in use.
137  */
138 static int
139 ti_scm_padconf_set_internal(struct ti_scm_softc *sc,
140     const struct ti_scm_padconf *padconf,
141     const char *muxmode, unsigned int state)
142 {
143 	unsigned int mode;
144 	uint16_t reg_val;
145 
146 	/* populate the new value for the PADCONF register */
147 	reg_val = (uint16_t)(state & ti_scm_dev.padconf_sate_mask);
148 
149 	/* find the new mode requested */
150 	for (mode = 0; mode < 8; mode++) {
151 		if ((padconf->muxmodes[mode] != NULL) &&
152 		    (strcmp(padconf->muxmodes[mode], muxmode) == 0)) {
153 			break;
154 		}
155 	}
156 
157 	/* couldn't find the mux mode */
158 	if (mode >= 8) {
159 		printf("Invalid mode \"%s\"\n", muxmode);
160 		return (EINVAL);
161 	}
162 
163 	/* set the mux mode */
164 	reg_val |= (uint16_t)(mode & ti_scm_dev.padconf_muxmode_mask);
165 
166 	if (bootverbose)
167 		device_printf(sc->sc_dev, "setting internal %x for %s\n",
168 		    reg_val, muxmode);
169 	/* write the register value (16-bit writes) */
170 	ti_scm_write_2(sc, padconf->reg_off, reg_val);
171 
172 	return (0);
173 }
174 
175 /**
176  *	ti_scm_padconf_set - sets the muxmode and state for a pad/pin
177  *	@padname: the name of the pad, i.e. "c12"
178  *	@muxmode: the name of the mode to use for the pin, i.e. "uart1_rx"
179  *	@state: the state to put the pad/pin in, i.e. PADCONF_PIN_???
180  *
181  *
182  *	LOCKING:
183  *	Internally locks it's own context.
184  *
185  *	RETURNS:
186  *	0 on success.
187  *	EINVAL if pin requested is outside valid range or already in use.
188  */
189 int
190 ti_scm_padconf_set(const char *padname, const char *muxmode, unsigned int state)
191 {
192 	const struct ti_scm_padconf *padconf;
193 
194 	if (!ti_scm_sc)
195 		return (ENXIO);
196 
197 	/* find the pin in the devmap */
198 	padconf = ti_scm_padconf_from_name(padname);
199 	if (padconf == NULL)
200 		return (EINVAL);
201 
202 	return (ti_scm_padconf_set_internal(ti_scm_sc, padconf, muxmode, state));
203 }
204 
205 /**
206  *	ti_scm_padconf_get - gets the muxmode and state for a pad/pin
207  *	@padname: the name of the pad, i.e. "c12"
208  *	@muxmode: upon return will contain the name of the muxmode of the pin
209  *	@state: upon return will contain the state of the pad/pin
210  *
211  *
212  *	LOCKING:
213  *	Internally locks it's own context.
214  *
215  *	RETURNS:
216  *	0 on success.
217  *	EINVAL if pin requested is outside valid range or already in use.
218  */
219 int
220 ti_scm_padconf_get(const char *padname, const char **muxmode,
221     unsigned int *state)
222 {
223 	const struct ti_scm_padconf *padconf;
224 	uint16_t reg_val;
225 
226 	if (!ti_scm_sc)
227 		return (ENXIO);
228 
229 	/* find the pin in the devmap */
230 	padconf = ti_scm_padconf_from_name(padname);
231 	if (padconf == NULL)
232 		return (EINVAL);
233 
234 	/* read the register value (16-bit reads) */
235 	reg_val = ti_scm_read_2(ti_scm_sc, padconf->reg_off);
236 
237 	/* save the state */
238 	if (state)
239 		*state = (reg_val & ti_scm_dev.padconf_sate_mask);
240 
241 	/* save the mode */
242 	if (muxmode)
243 		*muxmode = padconf->muxmodes[(reg_val & ti_scm_dev.padconf_muxmode_mask)];
244 
245 	return (0);
246 }
247 
248 /**
249  *	ti_scm_padconf_set_gpiomode - converts a pad to GPIO mode.
250  *	@gpio: the GPIO pin number (0-195)
251  *	@state: the state to put the pad/pin in, i.e. PADCONF_PIN_???
252  *
253  *
254  *
255  *	LOCKING:
256  *	Internally locks it's own context.
257  *
258  *	RETURNS:
259  *	0 on success.
260  *	EINVAL if pin requested is outside valid range or already in use.
261  */
262 int
263 ti_scm_padconf_set_gpiomode(uint32_t gpio, unsigned int state)
264 {
265 	const struct ti_scm_padconf *padconf;
266 	uint16_t reg_val;
267 
268 	if (!ti_scm_sc)
269 		return (ENXIO);
270 
271 	/* find the gpio pin in the padconf array */
272 	padconf = ti_scm_dev.padconf;
273 	while (padconf->ballname != NULL) {
274 		if (padconf->gpio_pin == gpio)
275 			break;
276 		padconf++;
277 	}
278 	if (padconf->ballname == NULL)
279 		return (EINVAL);
280 
281 	/* populate the new value for the PADCONF register */
282 	reg_val = (uint16_t)(state & ti_scm_dev.padconf_sate_mask);
283 
284 	/* set the mux mode */
285 	reg_val |= (uint16_t)(padconf->gpio_mode & ti_scm_dev.padconf_muxmode_mask);
286 
287 	/* write the register value (16-bit writes) */
288 	ti_scm_write_2(ti_scm_sc, padconf->reg_off, reg_val);
289 
290 	return (0);
291 }
292 
293 /**
294  *	ti_scm_padconf_get_gpiomode - gets the current GPIO mode of the pin
295  *	@gpio: the GPIO pin number (0-195)
296  *	@state: upon return will contain the state
297  *
298  *
299  *
300  *	LOCKING:
301  *	Internally locks it's own context.
302  *
303  *	RETURNS:
304  *	0 on success.
305  *	EINVAL if pin requested is outside valid range or not configured as GPIO.
306  */
307 int
308 ti_scm_padconf_get_gpiomode(uint32_t gpio, unsigned int *state)
309 {
310 	const struct ti_scm_padconf *padconf;
311 	uint16_t reg_val;
312 
313 	if (!ti_scm_sc)
314 		return (ENXIO);
315 
316 	/* find the gpio pin in the padconf array */
317 	padconf = ti_scm_dev.padconf;
318 	while (padconf->ballname != NULL) {
319 		if (padconf->gpio_pin == gpio)
320 			break;
321 		padconf++;
322 	}
323 	if (padconf->ballname == NULL)
324 		return (EINVAL);
325 
326 	/* read the current register settings */
327 	reg_val = ti_scm_read_2(ti_scm_sc, padconf->reg_off);
328 
329 	/* check to make sure the pins is configured as GPIO in the first state */
330 	if ((reg_val & ti_scm_dev.padconf_muxmode_mask) != padconf->gpio_mode)
331 		return (EINVAL);
332 
333 	/* read and store the reset of the state, i.e. pull-up, pull-down, etc */
334 	if (state)
335 		*state = (reg_val & ti_scm_dev.padconf_sate_mask);
336 
337 	return (0);
338 }
339 
340 /**
341  *	ti_scm_padconf_init_from_hints - processes the hints for padconf
342  *	@sc: the driver soft context
343  *
344  *
345  *
346  *	LOCKING:
347  *	Internally locks it's own context.
348  *
349  *	RETURNS:
350  *	0 on success.
351  *	EINVAL if pin requested is outside valid range or already in use.
352  */
353 static int
354 ti_scm_padconf_init_from_fdt(struct ti_scm_softc *sc)
355 {
356 	const struct ti_scm_padconf *padconf;
357 	const struct ti_scm_padstate *padstates;
358 	int err;
359 	phandle_t node;
360 	int len;
361 	char *fdt_pad_config;
362 	int i;
363 	char *padname, *muxname, *padstate;
364 
365 	node = ofw_bus_get_node(sc->sc_dev);
366 	len = OF_getproplen(node, "scm-pad-config");
367         OF_getprop_alloc(node, "scm-pad-config", 1, (void **)&fdt_pad_config);
368 
369 	i = len;
370 	while (i > 0) {
371 		padname = fdt_pad_config;
372 		fdt_pad_config += strlen(padname) + 1;
373 		i -= strlen(padname) + 1;
374 		if (i <= 0)
375 			break;
376 
377 		muxname = fdt_pad_config;
378 		fdt_pad_config += strlen(muxname) + 1;
379 		i -= strlen(muxname) + 1;
380 		if (i <= 0)
381 			break;
382 
383 		padstate = fdt_pad_config;
384 		fdt_pad_config += strlen(padstate) + 1;
385 		i -= strlen(padstate) + 1;
386 		if (i < 0)
387 			break;
388 
389 		padconf = ti_scm_dev.padconf;
390 
391 		while (padconf->ballname != NULL) {
392 			if (strcmp(padconf->ballname, padname) == 0) {
393 				padstates = ti_scm_dev.padstate;
394 				err = 1;
395 				while (padstates->state != NULL) {
396 					if (strcmp(padstates->state, padstate) == 0) {
397 						err = ti_scm_padconf_set_internal(sc,
398 						    padconf, muxname, padstates->reg);
399 					}
400 					padstates++;
401 				}
402 				if (err)
403 					device_printf(sc->sc_dev,
404 					    "err: failed to configure "
405 					    "pin \"%s\" as \"%s\"\n",
406 					    padconf->ballname,
407 					    muxname);
408 			}
409 			padconf++;
410 		}
411 	}
412 	return (0);
413 }
414 
415 /*
416  * Device part of OMAP SCM driver
417  */
418 
419 static int
420 ti_scm_probe(device_t dev)
421 {
422 	if (!ofw_bus_is_compatible(dev, "ti,scm"))
423 		return (ENXIO);
424 
425 	device_set_desc(dev, "TI Control Module");
426 	return (BUS_PROBE_DEFAULT);
427 }
428 
429 /**
430  *	ti_scm_attach - attaches the timer to the simplebus
431  *	@dev: new device
432  *
433  *	Reserves memory and interrupt resources, stores the softc structure
434  *	globally and registers both the timecount and eventtimer objects.
435  *
436  *	RETURNS
437  *	Zero on sucess or ENXIO if an error occuried.
438  */
439 static int
440 ti_scm_attach(device_t dev)
441 {
442 	struct ti_scm_softc *sc = device_get_softc(dev);
443 
444 	if (ti_scm_sc)
445 		return (ENXIO);
446 
447 	sc->sc_dev = dev;
448 
449 	if (bus_alloc_resources(dev, ti_scm_res_spec, sc->sc_res)) {
450 		device_printf(dev, "could not allocate resources\n");
451 		return (ENXIO);
452 	}
453 
454 	/* Global timer interface */
455 	sc->sc_bst = rman_get_bustag(sc->sc_res[0]);
456 	sc->sc_bsh = rman_get_bushandle(sc->sc_res[0]);
457 
458 	ti_scm_sc = sc;
459 
460 	ti_scm_padconf_init_from_fdt(sc);
461 
462 	return (0);
463 }
464 
465 int
466 ti_scm_reg_read_4(uint32_t reg, uint32_t *val)
467 {
468 	if (!ti_scm_sc)
469 		return (ENXIO);
470 
471 	*val = ti_scm_read_4(ti_scm_sc, reg);
472 	return (0);
473 }
474 
475 int
476 ti_scm_reg_write_4(uint32_t reg, uint32_t val)
477 {
478 	if (!ti_scm_sc)
479 		return (ENXIO);
480 
481 	ti_scm_write_4(ti_scm_sc, reg, val);
482 	return (0);
483 }
484 
485 
486 static device_method_t ti_scm_methods[] = {
487 	DEVMETHOD(device_probe,		ti_scm_probe),
488 	DEVMETHOD(device_attach,	ti_scm_attach),
489 	{ 0, 0 }
490 };
491 
492 static driver_t ti_scm_driver = {
493 	"ti_scm",
494 	ti_scm_methods,
495 	sizeof(struct ti_scm_softc),
496 };
497 
498 static devclass_t ti_scm_devclass;
499 
500 DRIVER_MODULE(ti_scm, simplebus, ti_scm_driver, ti_scm_devclass, 0, 0);
501