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/s3c2xx0/s3c24x0.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 /*      $NetBSD: s3c2410.c,v 1.4 2003/08/27 03:46:05 bsh Exp $ */
    2 
    3 /*
    4  * Copyright (c) 2003  Genetec corporation.  All rights reserved.
    5  * Written by Hiroyuki Bessho for Genetec corporation.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. The name of Genetec corporation may not be used to endorse
   16  *    or promote products derived from this software without specific prior
   17  *    written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY GENETEC CORP. ``AS IS'' AND
   20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL GENETEC CORP.
   23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29  * POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 
   32 #include <sys/cdefs.h>
   33 __FBSDID("$FreeBSD: releng/10.0/sys/arm/s3c2xx0/s3c24x0.c 238545 2012-07-17 03:18:12Z gonzo $");
   34 
   35 #include <sys/param.h>
   36 #include <sys/systm.h>
   37 #include <sys/kernel.h>
   38 #include <sys/reboot.h>
   39 #include <sys/malloc.h>
   40 #include <sys/module.h>
   41 #include <sys/bus.h>
   42 
   43 #include <vm/vm.h>
   44 #include <vm/pmap.h>
   45 
   46 #include <machine/cpu.h>
   47 #include <machine/bus.h>
   48 
   49 #include <machine/cpufunc.h>
   50 #include <machine/intr.h>
   51 #include <arm/s3c2xx0/s3c2410reg.h>
   52 #include <arm/s3c2xx0/s3c2440reg.h>
   53 #include <arm/s3c2xx0/s3c24x0var.h>
   54 #include <sys/rman.h>
   55 
   56 #define S3C2XX0_XTAL_CLK 12000000
   57 
   58 #define IPL_LEVELS 13
   59 u_int irqmasks[IPL_LEVELS];
   60 
   61 static struct {
   62         uint32_t        idcode;
   63         const char      *name;
   64         s3c2xx0_cpu     cpu;
   65 } s3c2x0_cpu_id[] = {
   66         { CHIPID_S3C2410A, "S3C2410A", CPU_S3C2410 },
   67         { CHIPID_S3C2440A, "S3C2440A", CPU_S3C2440 },
   68         { CHIPID_S3C2442B, "S3C2442B", CPU_S3C2440 },
   69 
   70         { 0, NULL }
   71 };
   72 
   73 static struct {
   74         const char *name;
   75         int prio;
   76         int unit;
   77         struct {
   78                 int type;
   79                 u_long start;
   80                 u_long count;
   81         } res[2];
   82 } s3c24x0_children[] = {
   83         { "rtc", 0, -1, {
   84                 { SYS_RES_IOPORT, S3C24X0_RTC_PA_BASE, S3C24X0_RTC_SIZE },
   85                 { 0 },
   86         } },
   87         { "timer", 0, -1, { { 0 }, } },
   88         { "uart", 1, 0, {
   89                 { SYS_RES_IRQ, S3C24X0_INT_UART0, 1 },
   90                 { SYS_RES_IOPORT, S3C24X0_UART_PA_BASE(0),
   91                   S3C24X0_UART_BASE(1) - S3C24X0_UART_BASE(0) },
   92         } },
   93         { "uart", 1, 1, {
   94                 { SYS_RES_IRQ, S3C24X0_INT_UART1, 1 },
   95                 { SYS_RES_IOPORT, S3C24X0_UART_PA_BASE(1),
   96                   S3C24X0_UART_BASE(2) - S3C24X0_UART_BASE(1) },
   97         } },
   98         { "uart", 1, 2, {
   99                 { SYS_RES_IRQ, S3C24X0_INT_UART2, 1 },
  100                 { SYS_RES_IOPORT, S3C24X0_UART_PA_BASE(2),
  101                   S3C24X0_UART_BASE(3) - S3C24X0_UART_BASE(2) },
  102         } },
  103         { "ohci", 0, -1, {
  104                 { SYS_RES_IRQ, S3C24X0_INT_USBH, 0 },
  105                 { SYS_RES_IOPORT, S3C24X0_USBHC_PA_BASE, S3C24X0_USBHC_SIZE },
  106         } },
  107         { NULL },
  108 };
  109 
  110 
  111 /* prototypes */
  112 static device_t s3c24x0_add_child(device_t, int, const char *, int);
  113 
  114 static int      s3c24x0_probe(device_t);
  115 static int      s3c24x0_attach(device_t);
  116 static void     s3c24x0_identify(driver_t *, device_t);
  117 static int      s3c24x0_setup_intr(device_t, device_t, struct resource *, int,
  118         driver_filter_t *, driver_intr_t *, void *, void **);
  119 static int      s3c24x0_teardown_intr(device_t, device_t, struct resource *,
  120         void *);
  121 static int      s3c24x0_config_intr(device_t, int, enum intr_trigger,
  122         enum intr_polarity);
  123 static struct resource *s3c24x0_alloc_resource(device_t, device_t, int, int *,
  124         u_long, u_long, u_long, u_int);
  125 static int s3c24x0_activate_resource(device_t, device_t, int, int,
  126         struct resource *);
  127 static int s3c24x0_release_resource(device_t, device_t, int, int,
  128         struct resource *);
  129 static struct resource_list *s3c24x0_get_resource_list(device_t, device_t);
  130 
  131 static void s3c24x0_identify_cpu(device_t);
  132 
  133 static device_method_t s3c24x0_methods[] = {
  134         DEVMETHOD(device_probe, s3c24x0_probe),
  135         DEVMETHOD(device_attach, s3c24x0_attach),
  136         DEVMETHOD(device_identify, s3c24x0_identify),
  137         DEVMETHOD(bus_setup_intr, s3c24x0_setup_intr),
  138         DEVMETHOD(bus_teardown_intr, s3c24x0_teardown_intr),
  139         DEVMETHOD(bus_config_intr, s3c24x0_config_intr),
  140         DEVMETHOD(bus_alloc_resource, s3c24x0_alloc_resource),
  141         DEVMETHOD(bus_activate_resource, s3c24x0_activate_resource),
  142         DEVMETHOD(bus_release_resource, s3c24x0_release_resource),
  143         DEVMETHOD(bus_get_resource_list,s3c24x0_get_resource_list),
  144         DEVMETHOD(bus_set_resource,     bus_generic_rl_set_resource),
  145         DEVMETHOD(bus_get_resource,     bus_generic_rl_get_resource),
  146         {0, 0},
  147 };
  148 
  149 static driver_t s3c24x0_driver = {
  150         "s3c24x0",
  151         s3c24x0_methods,
  152         sizeof(struct s3c24x0_softc),
  153 };
  154 static devclass_t s3c24x0_devclass;
  155 
  156 DRIVER_MODULE(s3c24x0, nexus, s3c24x0_driver, s3c24x0_devclass, 0, 0);
  157 
  158 struct s3c2xx0_softc *s3c2xx0_softc = NULL;
  159 
  160 static device_t
  161 s3c24x0_add_child(device_t bus, int prio, const char *name, int unit)
  162 {
  163         device_t child;
  164         struct s3c2xx0_ivar *ivar;
  165 
  166         child = device_add_child_ordered(bus, prio, name, unit);
  167         if (child == NULL)
  168                 return (NULL);
  169 
  170         ivar = malloc(sizeof(*ivar), M_DEVBUF, M_NOWAIT | M_ZERO);
  171         if (ivar == NULL) {
  172                 device_delete_child(bus, child);
  173                 printf("Can't add alloc ivar\n");
  174                 return (NULL);
  175         }
  176         device_set_ivars(child, ivar);
  177         resource_list_init(&ivar->resources);
  178 
  179         return (child);
  180 }
  181 
  182 static void
  183 s3c24x0_enable_ext_intr(unsigned int irq)
  184 {
  185         uint32_t reg, value;
  186         int offset;
  187 
  188         if (irq <= 7) {
  189                 reg = GPIO_PFCON;
  190                 offset = irq * 2;
  191         } else if (irq <= 23) {
  192                 reg = GPIO_PGCON;
  193                 offset = (irq - 8) * 2;
  194         } else
  195                 return;
  196 
  197         /* Make the pin an interrupt source */
  198         value = bus_space_read_4(s3c2xx0_softc->sc_iot,
  199             s3c2xx0_softc->sc_gpio_ioh, reg);
  200         value &= ~(3 << offset);
  201         value |= 2 << offset;
  202         bus_space_write_4(s3c2xx0_softc->sc_iot, s3c2xx0_softc->sc_gpio_ioh,
  203             reg, value);
  204 }
  205 
  206 static int
  207 s3c24x0_setup_intr(device_t dev, device_t child,
  208         struct resource *ires,  int flags, driver_filter_t *filt,
  209         driver_intr_t *intr, void *arg, void **cookiep)
  210 {
  211         int error, irq;
  212 
  213         error = BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags, filt,
  214             intr, arg, cookiep);
  215         if (error != 0)
  216                 return (error);
  217 
  218         for (irq = rman_get_start(ires); irq <= rman_get_end(ires); irq++) {
  219                 if (irq >= S3C24X0_EXTIRQ_MIN && irq <= S3C24X0_EXTIRQ_MAX) {
  220                         /* Enable the external interrupt pin */
  221                         s3c24x0_enable_ext_intr(irq - S3C24X0_EXTIRQ_MIN);
  222                 }
  223         }
  224         return (0);
  225 }
  226 
  227 static int
  228 s3c24x0_teardown_intr(device_t dev, device_t child, struct resource *res,
  229         void *cookie)
  230 {
  231         return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, res, cookie));
  232 }
  233 
  234 static int
  235 s3c24x0_config_intr(device_t dev, int irq, enum intr_trigger trig,
  236         enum intr_polarity pol)
  237 {
  238         uint32_t mask, reg, value;
  239         int offset;
  240 
  241         /* Only external interrupts can be configured */
  242         if (irq < S3C24X0_EXTIRQ_MIN || irq > S3C24X0_EXTIRQ_MAX)
  243                 return (EINVAL);
  244 
  245         /* There is no standard trigger or polarity for the bus */
  246         if (trig == INTR_TRIGGER_CONFORM || pol == INTR_POLARITY_CONFORM)
  247                 return (EINVAL);
  248 
  249         irq -= S3C24X0_EXTIRQ_MIN;
  250 
  251         /* Get the bits to set */
  252         mask = 0;
  253         if (pol == INTR_POLARITY_LOW) {
  254                 mask = 2;
  255         } else if (pol == INTR_POLARITY_HIGH) {
  256                 mask = 4;
  257         }
  258         if (trig == INTR_TRIGGER_LEVEL) {
  259                 mask >>= 2;
  260         }
  261 
  262         /* Get the register to set */
  263         if (irq <= 7) {
  264                 reg = GPIO_EXTINT(0);
  265                 offset = irq * 4;
  266         } else if (irq <= 15) {
  267                 reg = GPIO_EXTINT(1);
  268                 offset = (irq - 8) * 4;
  269         } else if (irq <= 23) {
  270                 reg = GPIO_EXTINT(2);
  271                 offset = (irq - 16) * 4;
  272         } else {
  273                 return (EINVAL);
  274         }
  275 
  276         /* Set the new signaling method */
  277         value = bus_space_read_4(s3c2xx0_softc->sc_iot,
  278             s3c2xx0_softc->sc_gpio_ioh, reg);
  279         value &= ~(7 << offset);
  280         value |= mask << offset;
  281         bus_space_write_4(s3c2xx0_softc->sc_iot,
  282             s3c2xx0_softc->sc_gpio_ioh, reg, value);
  283 
  284         return (0);
  285 }
  286 
  287 static struct resource *
  288 s3c24x0_alloc_resource(device_t bus, device_t child, int type, int *rid,
  289         u_long start, u_long end, u_long count, u_int flags)
  290 {
  291         struct resource_list_entry *rle;
  292         struct s3c2xx0_ivar *ivar = device_get_ivars(child);
  293         struct resource_list *rl = &ivar->resources;
  294         struct resource *res = NULL;
  295 
  296         if (device_get_parent(child) != bus)
  297                 return (BUS_ALLOC_RESOURCE(device_get_parent(bus), child,
  298                     type, rid, start, end, count, flags));
  299 
  300         rle = resource_list_find(rl, type, *rid);
  301         if (rle != NULL) {
  302                 /* There is a resource list. Use it */
  303                 if (rle->res)
  304                         panic("Resource rid %d type %d already in use", *rid,
  305                             type);
  306                 if (start == 0UL && end == ~0UL) {
  307                         start = rle->start;
  308                         count = ulmax(count, rle->count);
  309                         end = ulmax(rle->end, start + count - 1);
  310                 }
  311                 /*
  312                  * When allocating an irq with children irq's really
  313                  * allocate the children as it is those we are interested
  314                  * in receiving, not the parent.
  315                  */
  316                 if (type == SYS_RES_IRQ && start == end) {
  317                         switch (start) {
  318                         case S3C24X0_INT_ADCTC:
  319                                 start = S3C24X0_INT_TC;
  320                                 end = S3C24X0_INT_ADC;
  321                                 break;
  322 #ifdef S3C2440_INT_CAM
  323                         case S3C2440_INT_CAM:
  324                                 start = S3C2440_INT_CAM_C;
  325                                 end = S3C2440_INT_CAM_P;
  326                                 break;
  327 #endif
  328                         default:
  329                                 break;
  330                         }
  331                         count = end - start + 1;
  332                 }
  333         }
  334 
  335         switch (type) {
  336         case SYS_RES_IRQ:
  337                 res = rman_reserve_resource(
  338                     &s3c2xx0_softc->s3c2xx0_irq_rman, start, end,
  339                     count, flags, child);
  340                 break;
  341 
  342         case SYS_RES_IOPORT:
  343         case SYS_RES_MEMORY:
  344                 res = rman_reserve_resource(
  345                     &s3c2xx0_softc->s3c2xx0_mem_rman,
  346                     start, end, count, flags, child);
  347                 if (res == NULL)
  348                         panic("Unable to map address space %#lX-%#lX", start,
  349                             end);
  350 
  351                 rman_set_bustag(res, &s3c2xx0_bs_tag);
  352                 rman_set_bushandle(res, start);
  353                 if (flags & RF_ACTIVE) {
  354                         if (bus_activate_resource(child, type, *rid, res)) {
  355                                 rman_release_resource(res);
  356                                 return (NULL);
  357                         }
  358                 }
  359                 break;
  360         }
  361 
  362         if (res != NULL) {
  363                 rman_set_rid(res, *rid);
  364                 if (rle != NULL) {
  365                         rle->res = res;
  366                         rle->start = rman_get_start(res);
  367                         rle->end = rman_get_end(res);
  368                         rle->count = count;
  369                 }
  370         }
  371 
  372         return (res);
  373 }
  374 
  375 static int
  376 s3c24x0_activate_resource(device_t bus, device_t child, int type, int rid,
  377         struct resource *r)
  378 {
  379         bus_space_handle_t p;
  380         int error;
  381 
  382         if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) {
  383                 error = bus_space_map(rman_get_bustag(r),
  384                     rman_get_bushandle(r), rman_get_size(r), 0, &p);
  385                 if (error)
  386                         return (error);
  387                 rman_set_bushandle(r, p);
  388         }
  389         return (rman_activate_resource(r));
  390 }
  391 
  392 static int
  393 s3c24x0_release_resource(device_t bus, device_t child, int type, int rid,
  394         struct resource *r)
  395 {
  396         struct s3c2xx0_ivar *ivar = device_get_ivars(child);
  397         struct resource_list *rl = &ivar->resources;
  398         struct resource_list_entry *rle;
  399 
  400         if (rl == NULL)
  401                 return (EINVAL);
  402 
  403         rle = resource_list_find(rl, type, rid);
  404         if (rle == NULL)
  405                 return (EINVAL);
  406 
  407         rman_release_resource(r);
  408         rle->res = NULL;
  409 
  410         return 0;
  411 }
  412 
  413 static struct resource_list *
  414 s3c24x0_get_resource_list(device_t dev, device_t child)
  415 {
  416         struct s3c2xx0_ivar *ivar;
  417 
  418         ivar = device_get_ivars(child);
  419         return (&(ivar->resources));
  420 }
  421 
  422 void
  423 s3c24x0_identify(driver_t *driver, device_t parent)
  424 {
  425         
  426         BUS_ADD_CHILD(parent, 0, "s3c24x0", 0);
  427 }
  428 
  429 int
  430 s3c24x0_probe(device_t dev)
  431 {
  432         return 0;
  433 }
  434 
  435 int
  436 s3c24x0_attach(device_t dev)
  437 {
  438         struct s3c24x0_softc *sc = device_get_softc(dev);
  439         bus_space_tag_t iot;
  440         device_t child;
  441         unsigned int i, j;
  442         u_long irqmax;
  443 
  444         s3c2xx0_softc = &(sc->sc_sx);
  445         sc->sc_sx.sc_iot = iot = &s3c2xx0_bs_tag;
  446         s3c2xx0_softc->s3c2xx0_irq_rman.rm_type = RMAN_ARRAY;
  447         s3c2xx0_softc->s3c2xx0_irq_rman.rm_descr = "S3C24X0 IRQs";
  448         s3c2xx0_softc->s3c2xx0_mem_rman.rm_type = RMAN_ARRAY;
  449         s3c2xx0_softc->s3c2xx0_mem_rman.rm_descr = "S3C24X0 Device Registers";
  450         /* Manage the registor memory space */
  451         if ((rman_init(&s3c2xx0_softc->s3c2xx0_mem_rman) != 0) ||
  452             (rman_manage_region(&s3c2xx0_softc->s3c2xx0_mem_rman,
  453               S3C24X0_DEV_VA_OFFSET,
  454               S3C24X0_DEV_VA_OFFSET + S3C24X0_DEV_VA_SIZE) != 0) ||
  455             (rman_manage_region(&s3c2xx0_softc->s3c2xx0_mem_rman,
  456               S3C24X0_DEV_START, S3C24X0_DEV_STOP) != 0))
  457                 panic("s3c24x0_attach: failed to set up register rman");
  458 
  459         /* These are needed for things without a proper device to attach to */
  460         sc->sc_sx.sc_intctl_ioh = S3C24X0_INTCTL_BASE;
  461         sc->sc_sx.sc_gpio_ioh = S3C24X0_GPIO_BASE;
  462         sc->sc_sx.sc_clkman_ioh = S3C24X0_CLKMAN_BASE;
  463         sc->sc_sx.sc_wdt_ioh = S3C24X0_WDT_BASE;
  464         sc->sc_timer_ioh = S3C24X0_TIMER_BASE;
  465 
  466         /*
  467          * Identify the CPU
  468          */
  469         s3c24x0_identify_cpu(dev);
  470 
  471         /*
  472          * Manage the interrupt space.
  473          * We need to put this after s3c24x0_identify_cpu as the avaliable
  474          * interrupts change depending on which CPU we have.
  475          */
  476         if (sc->sc_sx.sc_cpu == CPU_S3C2410)
  477                 irqmax = S3C2410_SUBIRQ_MAX;
  478         else
  479                 irqmax = S3C2440_SUBIRQ_MAX;
  480         if (rman_init(&s3c2xx0_softc->s3c2xx0_irq_rman) != 0 ||
  481             rman_manage_region(&s3c2xx0_softc->s3c2xx0_irq_rman, 0,
  482             irqmax) != 0 ||
  483             rman_manage_region(&s3c2xx0_softc->s3c2xx0_irq_rman,
  484             S3C24X0_EXTIRQ_MIN, S3C24X0_EXTIRQ_MAX))
  485                 panic("s3c24x0_attach: failed to set up IRQ rman");
  486 
  487         /* calculate current clock frequency */
  488         s3c24x0_clock_freq(&sc->sc_sx);
  489         device_printf(dev, "fclk %d MHz hclk %d MHz pclk %d MHz\n",
  490                sc->sc_sx.sc_fclk / 1000000, sc->sc_sx.sc_hclk / 1000000,
  491                sc->sc_sx.sc_pclk / 1000000);
  492 
  493         /*
  494          * Attach children devices
  495          */
  496 
  497         for (i = 0; s3c24x0_children[i].name != NULL; i++) {
  498                 child = s3c24x0_add_child(dev, s3c24x0_children[i].prio,
  499                     s3c24x0_children[i].name, s3c24x0_children[i].unit);
  500                 for (j = 0; j < sizeof(s3c24x0_children[i].res) /
  501                      sizeof(s3c24x0_children[i].res[0]) &&
  502                      s3c24x0_children[i].res[j].type != 0; j++) {
  503                         bus_set_resource(child,
  504                             s3c24x0_children[i].res[j].type, 0,
  505                             s3c24x0_children[i].res[j].start,
  506                             s3c24x0_children[i].res[j].count);
  507                 }
  508         }
  509 
  510         bus_generic_probe(dev);
  511         bus_generic_attach(dev);
  512 
  513         return (0);
  514 }
  515 
  516 static void
  517 s3c24x0_identify_cpu(device_t dev)
  518 {
  519         struct s3c24x0_softc *sc = device_get_softc(dev);
  520         uint32_t idcode;
  521         int i;
  522 
  523         idcode = bus_space_read_4(sc->sc_sx.sc_iot, sc->sc_sx.sc_gpio_ioh,
  524             GPIO_GSTATUS1);
  525 
  526         for (i = 0; s3c2x0_cpu_id[i].name != NULL; i++) {
  527                 if (s3c2x0_cpu_id[i].idcode == idcode)
  528                         break;
  529         }
  530         if (s3c2x0_cpu_id[i].name == NULL)
  531                 panic("Unknown CPU detected ((Chip ID: %#X)", idcode);
  532         device_printf(dev, "Found %s CPU (Chip ID: %#X)\n",
  533             s3c2x0_cpu_id[i].name, idcode);
  534         sc->sc_sx.sc_cpu = s3c2x0_cpu_id[i].cpu;
  535 }
  536 
  537 /*
  538  * fill sc_pclk, sc_hclk, sc_fclk from values of clock controller register.
  539  *
  540  * s3c24{1,4}0_clock_freq2() is meant to be called from kernel startup routines.
  541  * s3c24x0_clock_freq() is for after kernel initialization is done.
  542  *
  543  * Because they can be called before bus_space is available we need to use
  544  * volatile pointers rather than bus_space_read.
  545  */
  546 void
  547 s3c2410_clock_freq2(vm_offset_t clkman_base, int *fclk, int *hclk, int *pclk)
  548 {
  549         uint32_t pllcon, divn;
  550         unsigned int mdiv, pdiv, sdiv;
  551         unsigned int f, h, p;
  552 
  553         pllcon = *(volatile uint32_t *)(clkman_base + CLKMAN_MPLLCON);
  554         divn = *(volatile uint32_t *)(clkman_base + CLKMAN_CLKDIVN);
  555 
  556         mdiv = (pllcon & PLLCON_MDIV_MASK) >> PLLCON_MDIV_SHIFT;
  557         pdiv = (pllcon & PLLCON_PDIV_MASK) >> PLLCON_PDIV_SHIFT;
  558         sdiv = (pllcon & PLLCON_SDIV_MASK) >> PLLCON_SDIV_SHIFT;
  559 
  560         f = ((mdiv + 8) * S3C2XX0_XTAL_CLK) / ((pdiv + 2) * (1 << sdiv));
  561         h = f;
  562         if (divn & S3C2410_CLKDIVN_HDIVN)
  563                 h /= 2;
  564         p = h;
  565         if (divn & CLKDIVN_PDIVN)
  566                 p /= 2;
  567 
  568         if (fclk) *fclk = f;
  569         if (hclk) *hclk = h;
  570         if (pclk) *pclk = p;
  571 }
  572 
  573 void
  574 s3c2440_clock_freq2(vm_offset_t clkman_base, int *fclk, int *hclk, int *pclk)
  575 {
  576         uint32_t pllcon, divn, camdivn;
  577         unsigned int mdiv, pdiv, sdiv;
  578         unsigned int f, h, p;
  579 
  580         pllcon = *(volatile uint32_t *)(clkman_base + CLKMAN_MPLLCON);
  581         divn = *(volatile uint32_t *)(clkman_base + CLKMAN_CLKDIVN);
  582         camdivn = *(volatile uint32_t *)(clkman_base + S3C2440_CLKMAN_CAMDIVN);
  583 
  584         mdiv = (pllcon & PLLCON_MDIV_MASK) >> PLLCON_MDIV_SHIFT;
  585         pdiv = (pllcon & PLLCON_PDIV_MASK) >> PLLCON_PDIV_SHIFT;
  586         sdiv = (pllcon & PLLCON_SDIV_MASK) >> PLLCON_SDIV_SHIFT;
  587 
  588         f = (2 * (mdiv + 8) * S3C2XX0_XTAL_CLK) / ((pdiv + 2) * (1 << sdiv));
  589         h = f;
  590         switch((divn >> 1) & 3) {
  591         case 0:
  592                 break;
  593         case 1:
  594                 h /= 2;
  595                 break;
  596         case 2:
  597                 if ((camdivn & S3C2440_CAMDIVN_HCLK4_HALF) ==
  598                     S3C2440_CAMDIVN_HCLK4_HALF)
  599                         h /= 8;
  600                 else
  601                         h /= 4;
  602                 break;
  603         case 3:
  604                 if ((camdivn & S3C2440_CAMDIVN_HCLK3_HALF) ==
  605                     S3C2440_CAMDIVN_HCLK3_HALF)
  606                         h /= 6;
  607                 else
  608                         h /= 3;
  609                 break;
  610         }
  611         p = h;
  612         if (divn & CLKDIVN_PDIVN)
  613                 p /= 2;
  614 
  615         if (fclk) *fclk = f;
  616         if (hclk) *hclk = h;
  617         if (pclk) *pclk = p;
  618 }
  619 
  620 void
  621 s3c24x0_clock_freq(struct s3c2xx0_softc *sc)
  622 {
  623         vm_offset_t va;
  624         
  625         va = sc->sc_clkman_ioh;
  626         switch(sc->sc_cpu) {
  627         case CPU_S3C2410:
  628                 s3c2410_clock_freq2(va, &sc->sc_fclk, &sc->sc_hclk,
  629                     &sc->sc_pclk);
  630                 break;
  631         case CPU_S3C2440:
  632                 s3c2440_clock_freq2(va, &sc->sc_fclk, &sc->sc_hclk,
  633                     &sc->sc_pclk);
  634                 break;
  635         }
  636 }
  637 
  638 void
  639 cpu_reset(void)
  640 {
  641         (void) disable_interrupts(I32_bit|F32_bit);
  642 
  643         bus_space_write_4(&s3c2xx0_bs_tag, s3c2xx0_softc->sc_wdt_ioh, WDT_WTCON,
  644             WTCON_ENABLE | WTCON_CLKSEL_16 | WTCON_ENRST);
  645         for(;;);
  646 }
  647 
  648 void
  649 s3c24x0_sleep(int mode __unused)
  650 {
  651         int reg;
  652 
  653         reg = bus_space_read_4(&s3c2xx0_bs_tag, s3c2xx0_softc->sc_clkman_ioh,
  654             CLKMAN_CLKCON);
  655         bus_space_write_4(&s3c2xx0_bs_tag, s3c2xx0_softc->sc_clkman_ioh,
  656             CLKMAN_CLKCON, reg | CLKCON_IDLE);
  657 }
  658 
  659 
  660 int
  661 arm_get_next_irq(int last __unused)
  662 {
  663         uint32_t intpnd;
  664         int irq, subirq;
  665 
  666         if ((irq = bus_space_read_4(&s3c2xx0_bs_tag,
  667             s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTOFFSET)) != 0) {
  668 
  669                 /* Clear the pending bit */
  670                 intpnd = bus_space_read_4(&s3c2xx0_bs_tag,
  671                     s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTPND);
  672                 bus_space_write_4(&s3c2xx0_bs_tag, s3c2xx0_softc->sc_intctl_ioh,
  673                     INTCTL_SRCPND, intpnd);
  674                 bus_space_write_4(&s3c2xx0_bs_tag, s3c2xx0_softc->sc_intctl_ioh,
  675                     INTCTL_INTPND, intpnd);
  676 
  677                 switch (irq) {
  678                 case S3C24X0_INT_ADCTC:
  679                 case S3C24X0_INT_UART0:
  680                 case S3C24X0_INT_UART1:
  681                 case S3C24X0_INT_UART2:
  682                         /* Find the sub IRQ */
  683                         subirq = 0x7ff;
  684                         subirq &= bus_space_read_4(&s3c2xx0_bs_tag,
  685                             s3c2xx0_softc->sc_intctl_ioh, INTCTL_SUBSRCPND);
  686                         subirq &= ~(bus_space_read_4(&s3c2xx0_bs_tag,
  687                             s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTSUBMSK));
  688                         if (subirq == 0)
  689                                 return (irq);
  690 
  691                         subirq = ffs(subirq) - 1;
  692 
  693                         /* Clear the sub irq pending bit */
  694                         bus_space_write_4(&s3c2xx0_bs_tag,
  695                             s3c2xx0_softc->sc_intctl_ioh, INTCTL_SUBSRCPND,
  696                             (1 << subirq));
  697 
  698                         /*
  699                          * Return the parent IRQ for UART
  700                          * as it is all we ever need
  701                          */
  702                         if (subirq <= 8)
  703                                 return (irq);
  704 
  705                         return (S3C24X0_SUBIRQ_MIN + subirq);
  706 
  707                 case S3C24X0_INT_0:
  708                 case S3C24X0_INT_1:
  709                 case S3C24X0_INT_2:
  710                 case S3C24X0_INT_3:
  711                         /* There is a 1:1 mapping to the IRQ we are handling */
  712                         return S3C24X0_INT_EXT(irq);
  713 
  714                 case S3C24X0_INT_4_7:
  715                 case S3C24X0_INT_8_23:
  716                         /* Find the external interrupt being called */
  717                         subirq = 0x7fffff;
  718                         subirq &= bus_space_read_4(&s3c2xx0_bs_tag,
  719                             s3c2xx0_softc->sc_gpio_ioh, GPIO_EINTPEND);
  720                         subirq &= ~bus_space_read_4(&s3c2xx0_bs_tag,
  721                             s3c2xx0_softc->sc_gpio_ioh, GPIO_EINTMASK);
  722                         if (subirq == 0)
  723                                 return (irq);
  724 
  725                         subirq = ffs(subirq) - 1;
  726 
  727                         /* Clear the external irq pending bit */
  728                         bus_space_write_4(&s3c2xx0_bs_tag,
  729                             s3c2xx0_softc->sc_gpio_ioh, GPIO_EINTPEND,
  730                             (1 << subirq));
  731 
  732                         return S3C24X0_INT_EXT(subirq);
  733                 }
  734 
  735                 return (irq);
  736         }
  737         return (-1);
  738 }
  739 
  740 void
  741 arm_mask_irq(uintptr_t irq)
  742 {
  743         u_int32_t mask;
  744 
  745         if (irq >= S3C24X0_INT_EXT(0) && irq <= S3C24X0_INT_EXT(3)) {
  746                 /* External interrupt 0..3 are directly mapped to irq 0..3 */
  747                 irq -= S3C24X0_EXTIRQ_MIN;
  748         }
  749         if (irq < S3C24X0_SUBIRQ_MIN) {
  750                 mask = bus_space_read_4(&s3c2xx0_bs_tag,
  751                     s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTMSK);
  752                 mask |= (1 << irq);
  753                 bus_space_write_4(&s3c2xx0_bs_tag,
  754                     s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTMSK, mask);
  755         } else if (irq < S3C24X0_EXTIRQ_MIN) {
  756                 mask = bus_space_read_4(&s3c2xx0_bs_tag,
  757                     s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTSUBMSK);
  758                 mask |= (1 << (irq - S3C24X0_SUBIRQ_MIN));
  759                 bus_space_write_4(&s3c2xx0_bs_tag,
  760                     s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTSUBMSK, mask);
  761         } else {
  762                 mask = bus_space_read_4(&s3c2xx0_bs_tag,
  763                     s3c2xx0_softc->sc_gpio_ioh, GPIO_EINTMASK);
  764                 mask |= (1 << (irq - S3C24X0_EXTIRQ_MIN));
  765                 bus_space_write_4(&s3c2xx0_bs_tag,
  766                     s3c2xx0_softc->sc_intctl_ioh, GPIO_EINTMASK, mask);
  767         }
  768 }
  769 
  770 void
  771 arm_unmask_irq(uintptr_t irq)
  772 {
  773         u_int32_t mask;
  774 
  775         if (irq >= S3C24X0_INT_EXT(0) && irq <= S3C24X0_INT_EXT(3)) {
  776                 /* External interrupt 0..3 are directly mapped to irq 0..3 */
  777                 irq -= S3C24X0_EXTIRQ_MIN;
  778         }
  779         if (irq < S3C24X0_SUBIRQ_MIN) {
  780                 mask = bus_space_read_4(&s3c2xx0_bs_tag,
  781                     s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTMSK);
  782                 mask &= ~(1 << irq);
  783                 bus_space_write_4(&s3c2xx0_bs_tag,
  784                     s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTMSK, mask);
  785         } else if (irq < S3C24X0_EXTIRQ_MIN) {
  786                 mask = bus_space_read_4(&s3c2xx0_bs_tag,
  787                     s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTSUBMSK);
  788                 mask &= ~(1 << (irq - S3C24X0_SUBIRQ_MIN));
  789                 bus_space_write_4(&s3c2xx0_bs_tag,
  790                     s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTSUBMSK, mask);
  791         } else {
  792                 mask = bus_space_read_4(&s3c2xx0_bs_tag,
  793                     s3c2xx0_softc->sc_gpio_ioh, GPIO_EINTMASK);
  794                 mask &= ~(1 << (irq - S3C24X0_EXTIRQ_MIN));
  795                 bus_space_write_4(&s3c2xx0_bs_tag,
  796                     s3c2xx0_softc->sc_intctl_ioh, GPIO_EINTMASK, mask);
  797         }
  798 }

Cache object: b1d5cc8d6688ed9c1df0290b5f99cac6


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