]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/arm/ti/ti_scm.c
Copy head (r256279) to stable/10 as part of the 10.0-RELEASE cycle.
[FreeBSD/stable/10.git] / sys / arm / ti / ti_scm.c
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);