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/9.1/sys/arm/s3c2xx0/s3c24x0.c 210458 2010-07-24 23:41:09Z andrew $");
   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                 arm_unmask_irq(irq);
  224         }
  225         return (0);
  226 }
  227 
  228 static int
  229 s3c24x0_teardown_intr(device_t dev, device_t child, struct resource *res,
  230         void *cookie)
  231 {
  232         return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, res, cookie));
  233 }
  234 
  235 static int
  236 s3c24x0_config_intr(device_t dev, int irq, enum intr_trigger trig,
  237         enum intr_polarity pol)
  238 {
  239         uint32_t mask, reg, value;
  240         int offset;
  241 
  242         /* Only external interrupts can be configured */
  243         if (irq < S3C24X0_EXTIRQ_MIN || irq > S3C24X0_EXTIRQ_MAX)
  244                 return (EINVAL);
  245 
  246         /* There is no standard trigger or polarity for the bus */
  247         if (trig == INTR_TRIGGER_CONFORM || pol == INTR_POLARITY_CONFORM)
  248                 return (EINVAL);
  249 
  250         irq -= S3C24X0_EXTIRQ_MIN;
  251 
  252         /* Get the bits to set */
  253         mask = 0;
  254         if (pol == INTR_POLARITY_LOW) {
  255                 mask = 2;
  256         } else if (pol == INTR_POLARITY_HIGH) {
  257                 mask = 4;
  258         }
  259         if (trig == INTR_TRIGGER_LEVEL) {
  260                 mask >>= 2;
  261         }
  262 
  263         /* Get the register to set */
  264         if (irq <= 7) {
  265                 reg = GPIO_EXTINT(0);
  266                 offset = irq * 4;
  267         } else if (irq <= 15) {
  268                 reg = GPIO_EXTINT(1);
  269                 offset = (irq - 8) * 4;
  270         } else if (irq <= 23) {
  271                 reg = GPIO_EXTINT(2);
  272                 offset = (irq - 16) * 4;
  273         } else {
  274                 return (EINVAL);
  275         }
  276 
  277         /* Set the new signaling method */
  278         value = bus_space_read_4(s3c2xx0_softc->sc_iot,
  279             s3c2xx0_softc->sc_gpio_ioh, reg);
  280         value &= ~(7 << offset);
  281         value |= mask << offset;
  282         bus_space_write_4(s3c2xx0_softc->sc_iot,
  283             s3c2xx0_softc->sc_gpio_ioh, reg, value);
  284 
  285         return (0);
  286 } 
  287 
  288 static struct resource *
  289 s3c24x0_alloc_resource(device_t bus, device_t child, int type, int *rid,
  290         u_long start, u_long end, u_long count, u_int flags)
  291 {
  292         struct resource_list_entry *rle;
  293         struct s3c2xx0_ivar *ivar = device_get_ivars(child);
  294         struct resource_list *rl = &ivar->resources;
  295         struct resource *res = NULL;
  296 
  297         if (device_get_parent(child) != bus)
  298                 return (BUS_ALLOC_RESOURCE(device_get_parent(bus), child,
  299                     type, rid, start, end, count, flags));
  300 
  301         rle = resource_list_find(rl, type, *rid);
  302         if (rle != NULL) {
  303                 /* There is a resource list. Use it */
  304                 if (rle->res)
  305                         panic("Resource rid %d type %d already in use", *rid,
  306                             type);
  307                 if (start == 0UL && end == ~0UL) {
  308                         start = rle->start;
  309                         count = ulmax(count, rle->count);
  310                         end = ulmax(rle->end, start + count - 1);
  311                 }
  312                 /*
  313                  * When allocating an irq with children irq's really
  314                  * allocate the children as it is those we are interested
  315                  * in receiving, not the parent.
  316                  */
  317                 if (type == SYS_RES_IRQ && start == end) {
  318                         switch (start) {
  319                         case S3C24X0_INT_ADCTC:
  320                                 start = S3C24X0_INT_TC;
  321                                 end = S3C24X0_INT_ADC;
  322                                 break;
  323 #ifdef S3C2440_INT_CAM
  324                         case S3C2440_INT_CAM:
  325                                 start = S3C2440_INT_CAM_C;
  326                                 end = S3C2440_INT_CAM_P;
  327                                 break;
  328 #endif
  329                         default:
  330                                 break;
  331                         }
  332                         count = end - start + 1;
  333                 }
  334         }
  335 
  336         switch (type) {
  337         case SYS_RES_IRQ:
  338                 res = rman_reserve_resource(
  339                     &s3c2xx0_softc->s3c2xx0_irq_rman, start, end,
  340                     count, flags, child);
  341                 break;
  342 
  343         case SYS_RES_IOPORT:
  344         case SYS_RES_MEMORY:
  345                 res = rman_reserve_resource(
  346                     &s3c2xx0_softc->s3c2xx0_mem_rman,
  347                     start, end, count, flags, child);
  348                 if (res == NULL)
  349                         panic("Unable to map address space %#lX-%#lX", start,
  350                             end);
  351 
  352                 rman_set_bustag(res, &s3c2xx0_bs_tag);
  353                 rman_set_bushandle(res, start);
  354                 if (flags & RF_ACTIVE) {
  355                         if (bus_activate_resource(child, type, *rid, res)) {
  356                                 rman_release_resource(res);
  357                                 return (NULL);
  358                         }
  359                 } 
  360                 break;
  361         }
  362 
  363         if (res != NULL) {
  364                 rman_set_rid(res, *rid);
  365                 if (rle != NULL) {
  366                         rle->res = res;
  367                         rle->start = rman_get_start(res);
  368                         rle->end = rman_get_end(res);
  369                         rle->count = count;
  370                 }
  371         }
  372 
  373         return (res);
  374 }
  375 
  376 static int
  377 s3c24x0_activate_resource(device_t bus, device_t child, int type, int rid,
  378         struct resource *r)
  379 {
  380         bus_space_handle_t p;
  381         int error;
  382 
  383         if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) {
  384                 error = bus_space_map(rman_get_bustag(r),
  385                     rman_get_bushandle(r), rman_get_size(r), 0, &p);
  386                 if (error)
  387                         return (error);
  388                 rman_set_bushandle(r, p);
  389         }
  390         return (rman_activate_resource(r));
  391 }
  392 
  393 static int
  394 s3c24x0_release_resource(device_t bus, device_t child, int type, int rid,
  395         struct resource *r)
  396 {
  397         struct s3c2xx0_ivar *ivar = device_get_ivars(child);
  398         struct resource_list *rl = &ivar->resources;
  399         struct resource_list_entry *rle;
  400 
  401         if (rl == NULL)
  402                 return (EINVAL);
  403 
  404         rle = resource_list_find(rl, type, rid);
  405         if (rle == NULL)
  406                 return (EINVAL);
  407 
  408         rman_release_resource(r);
  409         rle->res = NULL;
  410 
  411         return 0;
  412 }
  413 
  414 static struct resource_list *
  415 s3c24x0_get_resource_list(device_t dev, device_t child)
  416 {
  417         struct s3c2xx0_ivar *ivar;
  418 
  419         ivar = device_get_ivars(child);
  420         return (&(ivar->resources));
  421 }
  422 
  423 void
  424 s3c24x0_identify(driver_t *driver, device_t parent)
  425 {
  426         
  427         BUS_ADD_CHILD(parent, 0, "s3c24x0", 0);
  428 }
  429 
  430 int
  431 s3c24x0_probe(device_t dev)
  432 {
  433         return 0;
  434 }
  435 
  436 int
  437 s3c24x0_attach(device_t dev)
  438 {
  439         struct s3c24x0_softc *sc = device_get_softc(dev);
  440         bus_space_tag_t iot;
  441         device_t child;
  442         unsigned int i, j;
  443         u_long irqmax;
  444 
  445         s3c2xx0_softc = &(sc->sc_sx);
  446         sc->sc_sx.sc_iot = iot = &s3c2xx0_bs_tag;
  447         s3c2xx0_softc->s3c2xx0_irq_rman.rm_type = RMAN_ARRAY;
  448         s3c2xx0_softc->s3c2xx0_irq_rman.rm_descr = "S3C24X0 IRQs";
  449         s3c2xx0_softc->s3c2xx0_mem_rman.rm_type = RMAN_ARRAY;
  450         s3c2xx0_softc->s3c2xx0_mem_rman.rm_descr = "S3C24X0 Device Registers";
  451         /* Manage the registor memory space */
  452         if ((rman_init(&s3c2xx0_softc->s3c2xx0_mem_rman) != 0) ||
  453             (rman_manage_region(&s3c2xx0_softc->s3c2xx0_mem_rman,
  454               S3C24X0_DEV_VA_OFFSET,
  455               S3C24X0_DEV_VA_OFFSET + S3C24X0_DEV_VA_SIZE) != 0) ||
  456             (rman_manage_region(&s3c2xx0_softc->s3c2xx0_mem_rman,
  457               S3C24X0_DEV_START, S3C24X0_DEV_STOP) != 0))
  458                 panic("s3c24x0_attach: failed to set up register rman");
  459 
  460         /* These are needed for things without a proper device to attach to */
  461         sc->sc_sx.sc_intctl_ioh = S3C24X0_INTCTL_BASE;
  462         sc->sc_sx.sc_gpio_ioh = S3C24X0_GPIO_BASE;
  463         sc->sc_sx.sc_clkman_ioh = S3C24X0_CLKMAN_BASE;
  464         sc->sc_sx.sc_wdt_ioh = S3C24X0_WDT_BASE;
  465         sc->sc_timer_ioh = S3C24X0_TIMER_BASE;
  466 
  467         /*
  468          * Identify the CPU
  469          */
  470         s3c24x0_identify_cpu(dev);
  471 
  472         /*
  473          * Manage the interrupt space.
  474          * We need to put this after s3c24x0_identify_cpu as the avaliable
  475          * interrupts change depending on which CPU we have.
  476          */
  477         if (sc->sc_sx.sc_cpu == CPU_S3C2410)
  478                 irqmax = S3C2410_SUBIRQ_MAX;
  479         else
  480                 irqmax = S3C2440_SUBIRQ_MAX;
  481         if (rman_init(&s3c2xx0_softc->s3c2xx0_irq_rman) != 0 ||
  482             rman_manage_region(&s3c2xx0_softc->s3c2xx0_irq_rman, 0,
  483             irqmax) != 0 ||
  484             rman_manage_region(&s3c2xx0_softc->s3c2xx0_irq_rman,
  485             S3C24X0_EXTIRQ_MIN, S3C24X0_EXTIRQ_MAX))
  486                 panic("s3c24x0_attach: failed to set up IRQ rman");
  487 
  488         /* calculate current clock frequency */
  489         s3c24x0_clock_freq(&sc->sc_sx);
  490         device_printf(dev, "fclk %d MHz hclk %d MHz pclk %d MHz\n",
  491                sc->sc_sx.sc_fclk / 1000000, sc->sc_sx.sc_hclk / 1000000,
  492                sc->sc_sx.sc_pclk / 1000000);
  493 
  494         /*
  495          * Attach children devices
  496          */
  497 
  498         for (i = 0; s3c24x0_children[i].name != NULL; i++) {
  499                 child = s3c24x0_add_child(dev, s3c24x0_children[i].prio,
  500                     s3c24x0_children[i].name, s3c24x0_children[i].unit);
  501                 for (j = 0; j < sizeof(s3c24x0_children[i].res) /
  502                      sizeof(s3c24x0_children[i].res[0]) &&
  503                      s3c24x0_children[i].res[j].type != 0; j++) {
  504                         bus_set_resource(child,
  505                             s3c24x0_children[i].res[j].type, 0,
  506                             s3c24x0_children[i].res[j].start,
  507                             s3c24x0_children[i].res[j].count);
  508                 }
  509         }
  510 
  511         bus_generic_probe(dev);
  512         bus_generic_attach(dev);
  513 
  514         return (0);
  515 }
  516 
  517 static void
  518 s3c24x0_identify_cpu(device_t dev)
  519 {
  520         struct s3c24x0_softc *sc = device_get_softc(dev);
  521         uint32_t idcode;
  522         int i;
  523 
  524         idcode = bus_space_read_4(sc->sc_sx.sc_iot, sc->sc_sx.sc_gpio_ioh,
  525             GPIO_GSTATUS1);
  526 
  527         for (i = 0; s3c2x0_cpu_id[i].name != NULL; i++) {
  528                 if (s3c2x0_cpu_id[i].idcode == idcode)
  529                         break;
  530         }
  531         if (s3c2x0_cpu_id[i].name == NULL)
  532                 panic("Unknown CPU detected ((Chip ID: %#X)", idcode);
  533         device_printf(dev, "Found %s CPU (Chip ID: %#X)\n",
  534             s3c2x0_cpu_id[i].name, idcode);
  535         sc->sc_sx.sc_cpu = s3c2x0_cpu_id[i].cpu;
  536 }
  537 
  538 /*
  539  * fill sc_pclk, sc_hclk, sc_fclk from values of clock controller register.
  540  *
  541  * s3c24{1,4}0_clock_freq2() is meant to be called from kernel startup routines.
  542  * s3c24x0_clock_freq() is for after kernel initialization is done.
  543  *
  544  * Because they can be called before bus_space is available we need to use
  545  * volatile pointers rather than bus_space_read.
  546  */
  547 void
  548 s3c2410_clock_freq2(vm_offset_t clkman_base, int *fclk, int *hclk, int *pclk)
  549 {
  550         uint32_t pllcon, divn;
  551         unsigned int mdiv, pdiv, sdiv;
  552         unsigned int f, h, p;
  553 
  554         pllcon = *(volatile uint32_t *)(clkman_base + CLKMAN_MPLLCON);
  555         divn = *(volatile uint32_t *)(clkman_base + CLKMAN_CLKDIVN);
  556 
  557         mdiv = (pllcon & PLLCON_MDIV_MASK) >> PLLCON_MDIV_SHIFT;
  558         pdiv = (pllcon & PLLCON_PDIV_MASK) >> PLLCON_PDIV_SHIFT;
  559         sdiv = (pllcon & PLLCON_SDIV_MASK) >> PLLCON_SDIV_SHIFT;
  560 
  561         f = ((mdiv + 8) * S3C2XX0_XTAL_CLK) / ((pdiv + 2) * (1 << sdiv));
  562         h = f;
  563         if (divn & S3C2410_CLKDIVN_HDIVN)
  564                 h /= 2;
  565         p = h;
  566         if (divn & CLKDIVN_PDIVN)
  567                 p /= 2;
  568 
  569         if (fclk) *fclk = f;
  570         if (hclk) *hclk = h;
  571         if (pclk) *pclk = p;
  572 }
  573 
  574 void
  575 s3c2440_clock_freq2(vm_offset_t clkman_base, int *fclk, int *hclk, int *pclk)
  576 {
  577         uint32_t pllcon, divn, camdivn;
  578         unsigned int mdiv, pdiv, sdiv;
  579         unsigned int f, h, p;
  580 
  581         pllcon = *(volatile uint32_t *)(clkman_base + CLKMAN_MPLLCON);
  582         divn = *(volatile uint32_t *)(clkman_base + CLKMAN_CLKDIVN);
  583         camdivn = *(volatile uint32_t *)(clkman_base + S3C2440_CLKMAN_CAMDIVN);
  584 
  585         mdiv = (pllcon & PLLCON_MDIV_MASK) >> PLLCON_MDIV_SHIFT;
  586         pdiv = (pllcon & PLLCON_PDIV_MASK) >> PLLCON_PDIV_SHIFT;
  587         sdiv = (pllcon & PLLCON_SDIV_MASK) >> PLLCON_SDIV_SHIFT;
  588 
  589         f = (2 * (mdiv + 8) * S3C2XX0_XTAL_CLK) / ((pdiv + 2) * (1 << sdiv));
  590         h = f;
  591         switch((divn >> 1) & 3) {
  592         case 0:
  593                 break;
  594         case 1:
  595                 h /= 2;
  596                 break;
  597         case 2:
  598                 if ((camdivn & S3C2440_CAMDIVN_HCLK4_HALF) ==
  599                     S3C2440_CAMDIVN_HCLK4_HALF)
  600                         h /= 8;
  601                 else
  602                         h /= 4;
  603                 break;
  604         case 3:
  605                 if ((camdivn & S3C2440_CAMDIVN_HCLK3_HALF) ==
  606                     S3C2440_CAMDIVN_HCLK3_HALF)
  607                         h /= 6;
  608                 else
  609                         h /= 3;
  610                 break;
  611         }
  612         p = h;
  613         if (divn & CLKDIVN_PDIVN)
  614                 p /= 2;
  615 
  616         if (fclk) *fclk = f;
  617         if (hclk) *hclk = h;
  618         if (pclk) *pclk = p;
  619 }
  620 
  621 void
  622 s3c24x0_clock_freq(struct s3c2xx0_softc *sc)
  623 {
  624         vm_offset_t va;
  625         
  626         va = sc->sc_clkman_ioh;
  627         switch(sc->sc_cpu) {
  628         case CPU_S3C2410:
  629                 s3c2410_clock_freq2(va, &sc->sc_fclk, &sc->sc_hclk,
  630                     &sc->sc_pclk);
  631                 break;
  632         case CPU_S3C2440:
  633                 s3c2440_clock_freq2(va, &sc->sc_fclk, &sc->sc_hclk,
  634                     &sc->sc_pclk);
  635                 break;
  636         }
  637 }
  638 
  639 void
  640 cpu_reset(void)
  641 {
  642         (void) disable_interrupts(I32_bit|F32_bit);
  643 
  644         bus_space_write_4(&s3c2xx0_bs_tag, s3c2xx0_softc->sc_wdt_ioh, WDT_WTCON,
  645             WTCON_ENABLE | WTCON_CLKSEL_16 | WTCON_ENRST);
  646         for(;;);
  647 }
  648 
  649 void
  650 s3c24x0_sleep(int mode __unused)
  651 {
  652         int reg;
  653 
  654         reg = bus_space_read_4(&s3c2xx0_bs_tag, s3c2xx0_softc->sc_clkman_ioh,
  655             CLKMAN_CLKCON);
  656         bus_space_write_4(&s3c2xx0_bs_tag, s3c2xx0_softc->sc_clkman_ioh,
  657             CLKMAN_CLKCON, reg | CLKCON_IDLE);
  658 }
  659 
  660 
  661 int
  662 arm_get_next_irq(int last __unused)
  663 {
  664         uint32_t intpnd;
  665         int irq, subirq;
  666 
  667         if ((irq = bus_space_read_4(&s3c2xx0_bs_tag,
  668             s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTOFFSET)) != 0) {
  669 
  670                 /* Clear the pending bit */
  671                 intpnd = bus_space_read_4(&s3c2xx0_bs_tag,
  672                     s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTPND);
  673                 bus_space_write_4(&s3c2xx0_bs_tag, s3c2xx0_softc->sc_intctl_ioh,
  674                     INTCTL_SRCPND, intpnd);
  675                 bus_space_write_4(&s3c2xx0_bs_tag, s3c2xx0_softc->sc_intctl_ioh,
  676                     INTCTL_INTPND, intpnd);
  677 
  678                 switch (irq) {
  679                 case S3C24X0_INT_ADCTC:
  680                 case S3C24X0_INT_UART0:
  681                 case S3C24X0_INT_UART1:
  682                 case S3C24X0_INT_UART2:
  683                         /* Find the sub IRQ */
  684                         subirq = 0x7ff;
  685                         subirq &= bus_space_read_4(&s3c2xx0_bs_tag,
  686                             s3c2xx0_softc->sc_intctl_ioh, INTCTL_SUBSRCPND);
  687                         subirq &= ~(bus_space_read_4(&s3c2xx0_bs_tag,
  688                             s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTSUBMSK));
  689                         if (subirq == 0)
  690                                 return (irq);
  691 
  692                         subirq = ffs(subirq) - 1;
  693 
  694                         /* Clear the sub irq pending bit */
  695                         bus_space_write_4(&s3c2xx0_bs_tag,
  696                             s3c2xx0_softc->sc_intctl_ioh, INTCTL_SUBSRCPND,
  697                             (1 << subirq));
  698 
  699                         /*
  700                          * Return the parent IRQ for UART
  701                          * as it is all we ever need
  702                          */
  703                         if (subirq <= 8)
  704                                 return (irq);
  705 
  706                         return (S3C24X0_SUBIRQ_MIN + subirq);
  707 
  708                 case S3C24X0_INT_0:
  709                 case S3C24X0_INT_1:
  710                 case S3C24X0_INT_2:
  711                 case S3C24X0_INT_3:
  712                         /* There is a 1:1 mapping to the IRQ we are handling */
  713                         return S3C24X0_INT_EXT(irq);
  714 
  715                 case S3C24X0_INT_4_7:
  716                 case S3C24X0_INT_8_23:
  717                         /* Find the external interrupt being called */
  718                         subirq = 0x7fffff;
  719                         subirq &= bus_space_read_4(&s3c2xx0_bs_tag,
  720                             s3c2xx0_softc->sc_gpio_ioh, GPIO_EINTPEND);
  721                         subirq &= ~bus_space_read_4(&s3c2xx0_bs_tag,
  722                             s3c2xx0_softc->sc_gpio_ioh, GPIO_EINTMASK);
  723                         if (subirq == 0)
  724                                 return (irq);
  725 
  726                         subirq = ffs(subirq) - 1;
  727 
  728                         /* Clear the external irq pending bit */
  729                         bus_space_write_4(&s3c2xx0_bs_tag,
  730                             s3c2xx0_softc->sc_gpio_ioh, GPIO_EINTPEND,
  731                             (1 << subirq));
  732 
  733                         return S3C24X0_INT_EXT(subirq);
  734                 }
  735 
  736                 return (irq);
  737         }
  738         return (-1);
  739 }
  740 
  741 void
  742 arm_mask_irq(uintptr_t irq)
  743 {
  744         u_int32_t mask;
  745 
  746         if (irq >= S3C24X0_INT_EXT(0) && irq <= S3C24X0_INT_EXT(3)) {
  747                 /* External interrupt 0..3 are directly mapped to irq 0..3 */
  748                 irq -= S3C24X0_EXTIRQ_MIN;
  749         }
  750         if (irq < S3C24X0_SUBIRQ_MIN) {
  751                 mask = bus_space_read_4(&s3c2xx0_bs_tag,
  752                     s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTMSK);
  753                 mask |= (1 << irq);
  754                 bus_space_write_4(&s3c2xx0_bs_tag, 
  755                     s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTMSK, mask);
  756         } else if (irq < S3C24X0_EXTIRQ_MIN) {
  757                 mask = bus_space_read_4(&s3c2xx0_bs_tag,
  758                     s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTSUBMSK);
  759                 mask |= (1 << (irq - S3C24X0_SUBIRQ_MIN));
  760                 bus_space_write_4(&s3c2xx0_bs_tag, 
  761                     s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTSUBMSK, mask);
  762         } else {
  763                 mask = bus_space_read_4(&s3c2xx0_bs_tag,
  764                     s3c2xx0_softc->sc_gpio_ioh, GPIO_EINTMASK);
  765                 mask |= (1 << (irq - S3C24X0_EXTIRQ_MIN));
  766                 bus_space_write_4(&s3c2xx0_bs_tag, 
  767                     s3c2xx0_softc->sc_intctl_ioh, GPIO_EINTMASK, mask);
  768         }
  769 }
  770 
  771 void
  772 arm_unmask_irq(uintptr_t irq)
  773 {
  774         u_int32_t mask;
  775 
  776         if (irq >= S3C24X0_INT_EXT(0) && irq <= S3C24X0_INT_EXT(3)) {
  777                 /* External interrupt 0..3 are directly mapped to irq 0..3 */
  778                 irq -= S3C24X0_EXTIRQ_MIN;
  779         }
  780         if (irq < S3C24X0_SUBIRQ_MIN) {
  781                 mask = bus_space_read_4(&s3c2xx0_bs_tag,
  782                     s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTMSK);
  783                 mask &= ~(1 << irq);
  784                 bus_space_write_4(&s3c2xx0_bs_tag,
  785                     s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTMSK, mask);
  786         } else if (irq < S3C24X0_EXTIRQ_MIN) {
  787                 mask = bus_space_read_4(&s3c2xx0_bs_tag,
  788                     s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTSUBMSK);
  789                 mask &= ~(1 << (irq - S3C24X0_SUBIRQ_MIN));
  790                 bus_space_write_4(&s3c2xx0_bs_tag, 
  791                     s3c2xx0_softc->sc_intctl_ioh, INTCTL_INTSUBMSK, mask);
  792         } else {
  793                 mask = bus_space_read_4(&s3c2xx0_bs_tag,
  794                     s3c2xx0_softc->sc_gpio_ioh, GPIO_EINTMASK);
  795                 mask &= ~(1 << (irq - S3C24X0_EXTIRQ_MIN));
  796                 bus_space_write_4(&s3c2xx0_bs_tag, 
  797                     s3c2xx0_softc->sc_intctl_ioh, GPIO_EINTMASK, mask);
  798         }
  799 }

Cache object: fb2634b8b942487d256504f8c7383699


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