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.0/sys/arm/ti/ti_scm.c 252229 2013-06-26 02:56:54Z rpaulo $");
   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);

Cache object: 6104da10f9d9fd8d666828d69f1db6fd


[ 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.