The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/arm/ti/ti_scm.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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: releng/10.1/sys/arm/ti/ti_scm.c 266152 2014-05-15 16:11:06Z ian $");
   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/resource.h>
   65 
   66 #include <dev/fdt/fdt_common.h>
   67 #include <dev/ofw/openfirm.h>
   68 #include <dev/ofw/ofw_bus.h>
   69 #include <dev/ofw/ofw_bus_subr.h>
   70 
   71 #include "ti_scm.h"
   72 
   73 static struct resource_spec ti_scm_res_spec[] = {
   74         { SYS_RES_MEMORY,       0,      RF_ACTIVE },    /* Control memory window */
   75         { -1, 0 }
   76 };
   77 
   78 static struct ti_scm_softc *ti_scm_sc;
   79 
   80 #define ti_scm_read_2(sc, reg)          \
   81     bus_space_read_2((sc)->sc_bst, (sc)->sc_bsh, (reg))
   82 #define ti_scm_write_2(sc, reg, val)            \
   83     bus_space_write_2((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
   84 #define ti_scm_read_4(sc, reg)          \
   85     bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
   86 #define ti_scm_write_4(sc, reg, val)            \
   87     bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
   88 
   89 
   90 /**
   91  *      ti_padconf_devmap - Array of pins, should be defined one per SoC
   92  *
   93  *      This array is typically defined in one of the targeted *_scm_pinumx.c
   94  *      files and is specific to the given SoC platform. Each entry in the array
   95  *      corresponds to an individual pin.
   96  */
   97 extern const struct ti_scm_device ti_scm_dev;
   98 
   99 
  100 /**
  101  *      ti_scm_padconf_from_name - searches the list of pads and returns entry
  102  *                                   with matching ball name.
  103  *      @ballname: the name of the ball
  104  *
  105  *      RETURNS:
  106  *      A pointer to the matching padconf or NULL if the ball wasn't found.
  107  */
  108 static const struct ti_scm_padconf*
  109 ti_scm_padconf_from_name(const char *ballname)
  110 {
  111         const struct ti_scm_padconf *padconf;
  112 
  113         padconf = ti_scm_dev.padconf;
  114         while (padconf->ballname != NULL) {
  115                 if (strcmp(ballname, padconf->ballname) == 0)
  116                         return(padconf);
  117                 padconf++;
  118         }
  119         
  120         return (NULL);
  121 }
  122 
  123 /**
  124  *      ti_scm_padconf_set_internal - sets the muxmode and state for a pad/pin
  125  *      @padconf: pointer to the pad structure
  126  *      @muxmode: the name of the mode to use for the pin, i.e. "uart1_rx"
  127  *      @state: the state to put the pad/pin in, i.e. PADCONF_PIN_???
  128  *      
  129  *
  130  *      LOCKING:
  131  *      Internally locks it's own context.
  132  *
  133  *      RETURNS:
  134  *      0 on success.
  135  *      EINVAL if pin requested is outside valid range or already in use.
  136  */
  137 static int
  138 ti_scm_padconf_set_internal(struct ti_scm_softc *sc,
  139     const struct ti_scm_padconf *padconf,
  140     const char *muxmode, unsigned int state)
  141 {
  142         unsigned int mode;
  143         uint16_t reg_val;
  144 
  145         /* populate the new value for the PADCONF register */
  146         reg_val = (uint16_t)(state & ti_scm_dev.padconf_sate_mask);
  147 
  148         /* find the new mode requested */
  149         for (mode = 0; mode < 8; mode++) {
  150                 if ((padconf->muxmodes[mode] != NULL) &&
  151                     (strcmp(padconf->muxmodes[mode], muxmode) == 0)) {
  152                         break;
  153                 }
  154         }
  155 
  156         /* couldn't find the mux mode */
  157         if (mode >= 8) {
  158                 printf("Invalid mode \"%s\"\n", muxmode);
  159                 return (EINVAL);
  160         }
  161 
  162         /* set the mux mode */
  163         reg_val |= (uint16_t)(mode & ti_scm_dev.padconf_muxmode_mask);
  164         
  165         if (bootverbose)
  166                 device_printf(sc->sc_dev, "setting internal %x for %s\n", 
  167                     reg_val, muxmode);
  168         /* write the register value (16-bit writes) */
  169         ti_scm_write_2(sc, padconf->reg_off, reg_val);
  170         
  171         return (0);
  172 }
  173 
  174 /**
  175  *      ti_scm_padconf_set - sets the muxmode and state for a pad/pin
  176  *      @padname: the name of the pad, i.e. "c12"
  177  *      @muxmode: the name of the mode to use for the pin, i.e. "uart1_rx"
  178  *      @state: the state to put the pad/pin in, i.e. PADCONF_PIN_???
  179  *      
  180  *
  181  *      LOCKING:
  182  *      Internally locks it's own context.
  183  *
  184  *      RETURNS:
  185  *      0 on success.
  186  *      EINVAL if pin requested is outside valid range or already in use.
  187  */
  188 int
  189 ti_scm_padconf_set(const char *padname, const char *muxmode, unsigned int state)
  190 {
  191         const struct ti_scm_padconf *padconf;
  192 
  193         if (!ti_scm_sc)
  194                 return (ENXIO);
  195 
  196         /* find the pin in the devmap */
  197         padconf = ti_scm_padconf_from_name(padname);
  198         if (padconf == NULL)
  199                 return (EINVAL);
  200         
  201         return (ti_scm_padconf_set_internal(ti_scm_sc, padconf, muxmode, state));
  202 }
  203 
  204 /**
  205  *      ti_scm_padconf_get - gets the muxmode and state for a pad/pin
  206  *      @padname: the name of the pad, i.e. "c12"
  207  *      @muxmode: upon return will contain the name of the muxmode of the pin
  208  *      @state: upon return will contain the state of the pad/pin
  209  *      
  210  *
  211  *      LOCKING:
  212  *      Internally locks it's own context.
  213  *
  214  *      RETURNS:
  215  *      0 on success.
  216  *      EINVAL if pin requested is outside valid range or already in use.
  217  */
  218 int
  219 ti_scm_padconf_get(const char *padname, const char **muxmode,
  220     unsigned int *state)
  221 {
  222         const struct ti_scm_padconf *padconf;
  223         uint16_t reg_val;
  224 
  225         if (!ti_scm_sc)
  226                 return (ENXIO);
  227 
  228         /* find the pin in the devmap */
  229         padconf = ti_scm_padconf_from_name(padname);
  230         if (padconf == NULL)
  231                 return (EINVAL);
  232         
  233         /* read the register value (16-bit reads) */
  234         reg_val = ti_scm_read_2(ti_scm_sc, padconf->reg_off);
  235 
  236         /* save the state */
  237         if (state)
  238                 *state = (reg_val & ti_scm_dev.padconf_sate_mask);
  239 
  240         /* save the mode */
  241         if (muxmode)
  242                 *muxmode = padconf->muxmodes[(reg_val & ti_scm_dev.padconf_muxmode_mask)];
  243         
  244         return (0);
  245 }
  246 
  247 /**
  248  *      ti_scm_padconf_set_gpiomode - converts a pad to GPIO mode.
  249  *      @gpio: the GPIO pin number (0-195)
  250  *      @state: the state to put the pad/pin in, i.e. PADCONF_PIN_???
  251  *
  252  *      
  253  *
  254  *      LOCKING:
  255  *      Internally locks it's own context.
  256  *
  257  *      RETURNS:
  258  *      0 on success.
  259  *      EINVAL if pin requested is outside valid range or already in use.
  260  */
  261 int
  262 ti_scm_padconf_set_gpiomode(uint32_t gpio, unsigned int state)
  263 {
  264         const struct ti_scm_padconf *padconf;
  265         uint16_t reg_val;
  266 
  267         if (!ti_scm_sc)
  268                 return (ENXIO);
  269         
  270         /* find the gpio pin in the padconf array */
  271         padconf = ti_scm_dev.padconf;
  272         while (padconf->ballname != NULL) {
  273                 if (padconf->gpio_pin == gpio)
  274                         break;
  275                 padconf++;
  276         }
  277         if (padconf->ballname == NULL)
  278                 return (EINVAL);
  279 
  280         /* populate the new value for the PADCONF register */
  281         reg_val = (uint16_t)(state & ti_scm_dev.padconf_sate_mask);
  282 
  283         /* set the mux mode */
  284         reg_val |= (uint16_t)(padconf->gpio_mode & ti_scm_dev.padconf_muxmode_mask);
  285 
  286         /* write the register value (16-bit writes) */
  287         ti_scm_write_2(ti_scm_sc, padconf->reg_off, reg_val);
  288 
  289         return (0);
  290 }
  291 
  292 /**
  293  *      ti_scm_padconf_get_gpiomode - gets the current GPIO mode of the pin
  294  *      @gpio: the GPIO pin number (0-195)
  295  *      @state: upon return will contain the state
  296  *
  297  *      
  298  *
  299  *      LOCKING:
  300  *      Internally locks it's own context.
  301  *
  302  *      RETURNS:
  303  *      0 on success.
  304  *      EINVAL if pin requested is outside valid range or not configured as GPIO.
  305  */
  306 int
  307 ti_scm_padconf_get_gpiomode(uint32_t gpio, unsigned int *state)
  308 {
  309         const struct ti_scm_padconf *padconf;
  310         uint16_t reg_val;
  311 
  312         if (!ti_scm_sc)
  313                 return (ENXIO);
  314         
  315         /* find the gpio pin in the padconf array */
  316         padconf = ti_scm_dev.padconf;
  317         while (padconf->ballname != NULL) {
  318                 if (padconf->gpio_pin == gpio)
  319                         break;
  320                 padconf++;
  321         }
  322         if (padconf->ballname == NULL)
  323                 return (EINVAL);
  324 
  325         /* read the current register settings */
  326         reg_val = ti_scm_read_2(ti_scm_sc, padconf->reg_off);
  327         
  328         /* check to make sure the pins is configured as GPIO in the first state */
  329         if ((reg_val & ti_scm_dev.padconf_muxmode_mask) != padconf->gpio_mode)
  330                 return (EINVAL);
  331         
  332         /* read and store the reset of the state, i.e. pull-up, pull-down, etc */
  333         if (state)
  334                 *state = (reg_val & ti_scm_dev.padconf_sate_mask);
  335         
  336         return (0);
  337 }
  338 
  339 /**
  340  *      ti_scm_padconf_init_from_hints - processes the hints for padconf
  341  *      @sc: the driver soft context
  342  *
  343  *      
  344  *
  345  *      LOCKING:
  346  *      Internally locks it's own context.
  347  *
  348  *      RETURNS:
  349  *      0 on success.
  350  *      EINVAL if pin requested is outside valid range or already in use.
  351  */
  352 static int
  353 ti_scm_padconf_init_from_fdt(struct ti_scm_softc *sc)
  354 {
  355         const struct ti_scm_padconf *padconf;
  356         const struct ti_scm_padstate *padstates;
  357         int err;
  358         phandle_t node;
  359         int len;
  360         char *fdt_pad_config;
  361         int i;
  362         char *padname, *muxname, *padstate;
  363 
  364         node = ofw_bus_get_node(sc->sc_dev);
  365         len = OF_getproplen(node, "scm-pad-config");
  366         OF_getprop_alloc(node, "scm-pad-config", 1, (void **)&fdt_pad_config);
  367 
  368         i = len;
  369         while (i > 0) {
  370                 padname = fdt_pad_config;
  371                 fdt_pad_config += strlen(padname) + 1;
  372                 i -= strlen(padname) + 1;
  373                 if (i <= 0)
  374                         break;
  375 
  376                 muxname = fdt_pad_config;
  377                 fdt_pad_config += strlen(muxname) + 1;
  378                 i -= strlen(muxname) + 1;
  379                 if (i <= 0)
  380                         break;
  381 
  382                 padstate = fdt_pad_config;
  383                 fdt_pad_config += strlen(padstate) + 1;
  384                 i -= strlen(padstate) + 1;
  385                 if (i < 0)
  386                         break;
  387 
  388                 padconf = ti_scm_dev.padconf;
  389 
  390                 while (padconf->ballname != NULL) {
  391                         if (strcmp(padconf->ballname, padname) == 0) {
  392                                 padstates = ti_scm_dev.padstate;
  393                                 err = 1;
  394                                 while (padstates->state != NULL) {
  395                                         if (strcmp(padstates->state, padstate) == 0) {
  396                                                 err = ti_scm_padconf_set_internal(sc,
  397                                                     padconf, muxname, padstates->reg);
  398                                         }
  399                                         padstates++;
  400                                 }
  401                                 if (err)
  402                                         device_printf(sc->sc_dev,
  403                                             "err: failed to configure "
  404                                             "pin \"%s\" as \"%s\"\n",
  405                                             padconf->ballname,
  406                                             muxname);
  407                         }
  408                         padconf++;
  409                 }
  410         }
  411         return (0);
  412 }
  413 
  414 /*
  415  * Device part of OMAP SCM driver
  416  */
  417 
  418 static int
  419 ti_scm_probe(device_t dev)
  420 {
  421 
  422         if (!ofw_bus_status_okay(dev))
  423                 return (ENXIO);
  424 
  425         if (!ofw_bus_is_compatible(dev, "ti,scm"))
  426                 return (ENXIO);
  427 
  428         device_set_desc(dev, "TI Control Module");
  429         return (BUS_PROBE_DEFAULT);
  430 }
  431 
  432 /**
  433  *      ti_scm_attach - attaches the timer to the simplebus
  434  *      @dev: new device
  435  *
  436  *      Reserves memory and interrupt resources, stores the softc structure
  437  *      globally and registers both the timecount and eventtimer objects.
  438  *
  439  *      RETURNS
  440  *      Zero on sucess or ENXIO if an error occuried.
  441  */
  442 static int
  443 ti_scm_attach(device_t dev)
  444 {
  445         struct ti_scm_softc *sc = device_get_softc(dev);
  446 
  447         if (ti_scm_sc)
  448                 return (ENXIO);
  449 
  450         sc->sc_dev = dev;
  451 
  452         if (bus_alloc_resources(dev, ti_scm_res_spec, sc->sc_res)) {
  453                 device_printf(dev, "could not allocate resources\n");
  454                 return (ENXIO);
  455         }
  456 
  457         /* Global timer interface */
  458         sc->sc_bst = rman_get_bustag(sc->sc_res[0]);
  459         sc->sc_bsh = rman_get_bushandle(sc->sc_res[0]);
  460 
  461         ti_scm_sc = sc;
  462 
  463         ti_scm_padconf_init_from_fdt(sc);
  464 
  465         return (0);
  466 }
  467 
  468 int
  469 ti_scm_reg_read_4(uint32_t reg, uint32_t *val)
  470 {
  471         if (!ti_scm_sc)
  472                 return (ENXIO);
  473 
  474         *val = ti_scm_read_4(ti_scm_sc, reg);
  475         return (0);
  476 }
  477 
  478 int
  479 ti_scm_reg_write_4(uint32_t reg, uint32_t val)
  480 {
  481         if (!ti_scm_sc)
  482                 return (ENXIO);
  483 
  484         ti_scm_write_4(ti_scm_sc, reg, val);
  485         return (0);
  486 }
  487 
  488 
  489 static device_method_t ti_scm_methods[] = {
  490         DEVMETHOD(device_probe,         ti_scm_probe),
  491         DEVMETHOD(device_attach,        ti_scm_attach),
  492         { 0, 0 }
  493 };
  494 
  495 static driver_t ti_scm_driver = {
  496         "ti_scm",
  497         ti_scm_methods,
  498         sizeof(struct ti_scm_softc),
  499 };
  500 
  501 static devclass_t ti_scm_devclass;
  502 
  503 DRIVER_MODULE(ti_scm, simplebus, ti_scm_driver, ti_scm_devclass, 0, 0);

Cache object: e4a55e2149586a5c49c54f42d4a25551


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.