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/chips/mc_clock.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  * Mach Operating System
    3  * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University
    4  * All Rights Reserved.
    5  * 
    6  * Permission to use, copy, modify and distribute this software and its
    7  * documentation is hereby granted, provided that both the copyright
    8  * notice and this permission notice appear in all copies of the
    9  * software, derivative works or modified versions, and any portions
   10  * thereof, and that both notices appear in supporting documentation.
   11  * 
   12  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
   13  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
   14  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
   15  * 
   16  * Carnegie Mellon requests users of this software to return to
   17  * 
   18  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
   19  *  School of Computer Science
   20  *  Carnegie Mellon University
   21  *  Pittsburgh PA 15213-3890
   22  * 
   23  * any improvements or extensions that they make and grant Carnegie Mellon
   24  * the rights to redistribute these changes.
   25  */
   26 /*
   27  * HISTORY
   28  * $Log:        mc_clock.c,v $
   29  * Revision 2.16  93/11/17  16:12:25  dbg
   30  *      Added autoconfiguration structures for PS2.
   31  *      [93/09/09            dbg]
   32  *      Fixed setting CLOCK_RESOLUTION: mc_setstat was passing an
   33  *      uninitialized variable to log2.  Changed mc_setstat to
   34  *      pick the available resolution closest to the one requested,
   35  *      not just the next higher power of 2.
   36  *      [93/08/30            dbg]
   37  * 
   38  *      Probe routine now sets the clock address for all machines.
   39  *      [93/07/15            dbg]
   40  * 
   41  *      Century is in a different place on the PS2.
   42  *      [93/07/13            dbg]
   43  * 
   44  *      Update clock->check_seconds when reading clock at initialization.
   45  *      [93/06/18            dbg]
   46  * 
   47  *      Use routines from device/clock_dev.c.
   48  *      [93/06/02            dbg]
   49  * 
   50  *      Changed mmap routines to return physical address instead of
   51  *      physical page number.
   52  *      [93/05/24            dbg]
   53  * 
   54  *      Adapted for new Mach clocks and timers, based on Stefan Savage's
   55  *      code.  Generalized to be usable for i386 machines, also.
   56  *      [93/05/21            dbg]
   57  * 
   58  * Revision 2.15  93/05/17  15:11:48  rvb
   59  *      Type casts, etc to quiet gcc 2.3.3 warnings
   60  *      [93/05/17            rvb]
   61  * 
   62  * Revision 2.14  93/05/15  19:37:12  mrt
   63  *      machparam.h -> machspl.h
   64  * 
   65  * Revision 2.13  93/05/10  20:08:19  rvb
   66  *      Fixed types. Define what is exported and what not.
   67  *      [93/05/06  09:57:45  af]
   68  * 
   69  * Revision 2.12  93/02/05  08:05:43  danner
   70  *      Heavy cosmetic changes to make it look like a device after all.
   71  *      Flamingo uses it too.
   72  *      [93/02/04  01:30:53  af]
   73  * 
   74  *      Proper spl typing.
   75  *      [92/11/30            af]
   76  * 
   77  * Revision 2.11  92/02/19  16:45:57  elf
   78  *      Wait for uip before stopping the chip, too.
   79  *      [92/01/22            af]
   80  * 
   81  * Revision 2.10  91/08/24  11:52:28  af
   82  *      Fixed spl munging, for 3min.
   83  *      [91/08/02  01:49:09  af]
   84  * 
   85  * Revision 2.9  91/06/25  20:54:18  rpd
   86  *      Tweaks to make gcc happy.
   87  * 
   88  * Revision 2.8  91/06/19  11:53:54  rvb
   89  *      mips->DECSTATION; vax->VAXSTATION
   90  *      [91/06/12  14:01:54  rvb]
   91  * 
   92  *      File moved here from mips/PMAX since it tries to be generic;
   93  *      it is used on the PMAX and could be used on the Vax3100.
   94  *      It would need a few ifdef vax & ifdef mips for the latter.
   95  *      [91/06/04            rvb]
   96  * 
   97  * Revision 2.7  91/05/14  17:24:22  mrt
   98  *      Correcting copyright
   99  * 
  100  * Revision 2.6  91/02/14  14:34:41  mrt
  101  *      Factored out delay() function, and made it box-indep.
  102  *      Added accurate_config_delay() which calls delay()'s
  103  *      configuration code.  Modified ackrtclock() to
  104  *      invoke it on first call.
  105  *      Tell the user what the CPU clock speed loks like, 
  106  *      distinguish between DS3100 and DS2100 based on clock speed.
  107  *      [91/02/12  13:03:16  af]
  108  * 
  109  * Revision 2.5  91/02/05  17:42:35  mrt
  110  *      Added author notices
  111  *      [91/02/04  11:15:06  mrt]
  112  * 
  113  *      Changed to use new Mach copyright
  114  *      [91/02/02  12:13:45  mrt]
  115  * 
  116  * Revision 2.4  90/12/05  23:32:39  af
  117  * 
  118  * 
  119  * Revision 2.3  90/12/05  20:47:31  af
  120  *      Made file conditional.
  121  *      [90/12/03  23:28:03  af]
  122  * 
  123  * Revision 2.2  90/08/27  22:06:05  dbg
  124  *      Initialized cpu_speed to a non-zero value.  Apparently,
  125  *      we need delays much earlier than we can possibly know
  126  *      what this machine looks like.  I know this will bite back.
  127  *      [90/08/21            af]
  128  *      Made apparent who is resetting the clock back to 1972.
  129  *      [90/08/20  10:30:19  af]
  130  * 
  131  *      Created, from Motorola's MC146818 specs.
  132  *      [90/08/17            af]
  133  * 
  134  */
  135 /*
  136  *      File:   mc_clock.c
  137  *      Author: Alessandro Forin
  138  *      Date:   8/90
  139  *
  140  *      Driver for the MC146818 Clock
  141  */
  142 
  143 #include <mc.h>
  144 #if     NMC > 0
  145 #include <platforms.h>
  146 
  147 #include <mach/boolean.h>
  148 #include <mach/time_spec.h>
  149 #include <mach/machine/vm_types.h>
  150 
  151 #include <kern/clock.h>
  152 #include <kern/kern_io.h>
  153 
  154 #ifdef  PS2
  155 #include <i386ps2/bus.h>                /* PS2 autoconf */
  156 #else
  157 #include <chips/busses.h>               /* standard autoconf */
  158 #endif
  159 #include <device/device_types.h>
  160 #include <device/clock_status.h>
  161 #include <device/clock_dev.h>
  162 
  163 #include <machine/machspl.h>
  164 
  165 #define private static
  166 #define public
  167 
  168 /*
  169  *      Real-Time Clock plus non-volatile RAM (MC146818)
  170  */
  171 
  172 /*
  173  *      Registers are accessed by number.
  174  */
  175 #define MC_SECOND               0x00
  176 #define MC_ALARM_SECOND         0x01
  177 #define MC_MINUTE               0x02
  178 #define MC_ALARM_MINUTE         0x03
  179 #define MC_HOUR                 0x04
  180 #define MC_ALARM_HOUR           0x05
  181 #define MC_DAY_OF_WEEK          0x06    /* range 1..7  */
  182 #define MC_DAY_OF_MONTH         0x07    /* range 1..31 */
  183 #define MC_MONTH                0x08
  184 #define MC_YEAR                 0x09
  185 #define MC_REG_A                0x0a
  186 #define MC_REG_B                0x0b
  187 #define MC_REG_C                0x0c
  188 #define MC_REG_D                0x0d
  189 
  190 /*
  191  * Register A defines (read/write)
  192  */
  193 
  194 #define MC_REG_A_RS     0x0f            /* Interrupt rate (and SQwave) select */
  195 #define MC_REG_A_DV     0x70            /* Divider select */
  196 #define MC_REG_A_UIP    0x80            /* Update In Progress (read-only bit) */
  197 
  198 /* Time base configuration */
  199 #define MC_BASE_4_MHz   0x00
  200 #define MC_BASE_1_MHz   0x10
  201 #define MC_BASE_32_KHz  0x20
  202 #define MC_BASE_NONE    0x60            /* actually, both of these reset */
  203 #define MC_BASE_RESET   0x70
  204 
  205 /* Interrupt rate table */
  206 #define MC_RATE_NONE    0x0             /* disabled */
  207 #define MC_RATE_1       0x1             /* 256Hz if MC_BASE_32_KHz,
  208                                            else 32768Hz */
  209 #define MC_RATE_2       0x2             /* 128Hz if MC_BASE_32_KHz,
  210                                            else 16384Hz */
  211 #define MC_RATE_8192_Hz 0x3             /* Tpi: 122.070 usecs */
  212 #define MC_RATE_4096_Hz 0x4             /* Tpi: 244.141 usecs */
  213 #define MC_RATE_2048_Hz 0x5             /* Tpi: 488.281 usecs */
  214 #define MC_RATE_1024_Hz 0x6             /* Tpi: 976.562 usecs */
  215 #define MC_RATE_512_Hz  0x7             /* Tpi: 1.953125 ms */
  216 #define MC_RATE_256_Hz  0x8             /* Tpi: 3.90625 ms */
  217 #define MC_RATE_128_Hz  0x9             /* Tpi: 7.8125 ms */
  218 #define MC_RATE_64_Hz   0xa             /* Tpi: 15.625 ms */
  219 #define MC_RATE_32_Hz   0xb             /* Tpi: 31.25 ms */
  220 #define MC_RATE_16_Hz   0xc             /* Tpi: 62.5 ms */
  221 #define MC_RATE_8_Hz    0xd             /* Tpi: 125 ms */
  222 #define MC_RATE_4_Hz    0xe             /* Tpi: 250 ms */
  223 #define MC_RATE_2_Hz    0xf             /* Tpi: 500 ms */
  224 
  225 /* Update cycle time */
  226 #define MC_UPD_4_MHz     248            /* usecs */
  227 #define MC_UPD_1_MHz     248            /* usecs */
  228 #define MC_UPD_32_KHz   1984            /* usecs */
  229 #define MC_UPD_MINIMUM   244            /* usecs, guaranteed if UIP=0 */
  230 
  231 /*
  232  * Register B defines (read/write)
  233  */
  234 
  235 #define MC_REG_B_DSE    0x01            /* obsolete (Daylight Savings Enable) */
  236 #define MC_REG_B_24HM   0x02            /* 24/12 Hour Mode */
  237 #define MC_REG_B_DM     0x04            /* Data Mode, 1=Binary 0=BCD */
  238 #define MC_REG_B_SQWE   0x08            /* Square Wave Enable */
  239 #define MC_REG_B_UIE    0x10            /* Update-ended Interrupt Enable */
  240 #define MC_REG_B_AIE    0x20            /* Alarm Interrupt Enable */
  241 #define MC_REG_B_PIE    0x40            /* Periodic Interrupt Enable */
  242 #define MC_REG_B_SET    0x80            /* Set NVram info, e.g.
  243                                            update time or ..*/
  244 #define MC_REG_B_STOP   MC_REG_B_SET    /* Stop updating the timing info */
  245 
  246 /*
  247  * Register C defines (read-only)
  248  */
  249 
  250 #define MC_REG_C_ZEROES 0x0f            /* Reads as zero bits  */
  251 #define MC_REG_C_UF     0x10            /* Update-ended interrupt flag */
  252 #define MC_REG_C_AF     0x20            /* Alarm interrupt flag */
  253 #define MC_REG_C_PF     0x40            /* Periodic interrupt flag */
  254 #define MC_REG_C_IRQF   0x80            /* Interrupt request flag */
  255 
  256 /*
  257  * Register D defines (read-only)
  258  */
  259 
  260 #define MC_REG_D_ZEROES 0x7f            /* Reads as zero bits  */
  261 #define MC_REG_D_VRT    0x80            /* Valid RAM and Time */
  262 
  263 /*
  264  *      Different machines map the chip registers in different
  265  *      ways.
  266  */
  267 
  268 #ifdef  DECSTATION
  269 #include <mips/mips_cpu.h>
  270 
  271 #define MC_DEFAULT_ADDRESS      PHYS_TO_K1SEG(0x1d000000)
  272 #define MC_DOES_DELAYS          1
  273 
  274 /*
  275  * Both the Pmax and the 3max implementations of the chip map
  276  * bytes of the chip's RAM to 32 bit words (low byte).
  277  * For convenience, we redefine here the chip's RAM layout
  278  * making padding explicit. 
  279  */
  280 
  281 typedef struct {
  282         struct {
  283                 volatile unsigned char  real_reg;
  284                 char                    pad[3];
  285         } regs[64];
  286 } * mc_clock_t;
  287 
  288 #define mc_read(clock, reg)     (clock->regs[reg].real_reg)
  289 #define mc_write(clock, reg, data) \
  290                                 (clock->regs[reg].real_reg = (data))
  291 
  292 #endif  /* DECSTATION */
  293 
  294 #ifdef  FLAMINGO
  295 #define MC_DEFAULT_ADDRESS      0L
  296 
  297 /*
  298  *      Clock is not padded
  299  */
  300 typedef struct {
  301         volatile unsigned char  regs[64];
  302 } * mc_clock_t;
  303 
  304 #define mc_read(clock, reg)     (clock->regs[reg])
  305 #define mc_write(clock, reg, data) \
  306                                 (clock->regs[reg] = (data))
  307 
  308 #endif  /* FLAMINGO */
  309 
  310 #if     defined(AT386) || defined(PS2)
  311 
  312 #include <i386/pio.h>
  313 #define wbflush()
  314 
  315 /*
  316  *      The RTC is accessed through IO ports.
  317  */
  318 #define MC_ADDR         0x70            /* high bit is NMI enable! */
  319 #define MC_DATA         0x71
  320 
  321 /*
  322  *      Delay is needed between outb and inb.
  323  */
  324 #ifdef  __GNUC__
  325 #define spin()  asm volatile(" jmp 0f; 0: ")
  326 #endif
  327 
  328 #define mc_read(clock, reg)     \
  329         ({ outb(MC_ADDR, reg); spin(); inb(MC_DATA);})
  330 
  331 #define mc_write(clock, reg, data) \
  332         ({ outb(MC_ADDR, reg); spin(); outb(MC_DATA, data); (void)0;})
  333 
  334 /*
  335  *      Need typedef anyway.
  336  */
  337 typedef volatile unsigned char* mc_clock_t;
  338 
  339 #define MC_DEFAULT_ADDRESS      MC_ADDR
  340 
  341 /*
  342  *      We keep time in BCD
  343  */
  344 #define MC_CLOCK_BCD    1
  345 
  346 /*
  347  *      And there is a place to put the century (!)
  348  */
  349 #ifdef  AT386
  350 #define MC_CENTURY      0x32
  351 #endif
  352 #ifdef  PS2
  353 #define MC_CENTURY      0x37
  354 #endif
  355 
  356 #endif  /* AT386 || PS2 */
  357 
  358 /*
  359  *      We configure the clock to run in 24 hour mode,
  360  *      and to deliver periodic interrupts that we
  361  *      use as clock interrupts.
  362  *      If some other OS wants time to be kept in BCD,
  363  *      we do that to.
  364  *      But we keep time in UTC, not local time.
  365  */
  366 
  367 #ifdef  MC_CLOCK_BCD
  368 #define MC_REG_B_CONFIGURE      (MC_REG_B_24HM)
  369 #else
  370 #define MC_REG_B_CONFIGURE      (MC_REG_B_24HM | MC_REG_B_DM)
  371 #endif
  372 
  373 /*
  374  *      Minimum and maximum resolution for clock.
  375  */
  376 #define MC_CLOCK_DEFAULT_RESOLUTION     (NANOSEC_PER_SEC/128)
  377 #define MC_CLOCK_MAX_RESOLUTION         (16000000)
  378 #define MC_CLOCK_MIN_RESOLUTION         (125000)
  379 
  380 /*
  381  *      We have only one per machine.
  382  */
  383 mach_clock_data_t               mc_clock0;
  384 
  385 mach_clock_t                    mc_clock[] = {&mc_clock0};
  386 
  387 void    mc_clock_setresolution(mach_clock_t);           /* forward */
  388 void    mc_clock_write(mach_clock_t, time_spec_t);
  389 void    mc_clock_enable_interrupts(mach_clock_t);
  390 time_spec_t mc_clock_read(mach_clock_t);
  391 void    mc_wait_for_uip(mc_clock_t clock);
  392 
  393 struct clock_ops mc_clock_ops = {
  394         mc_clock_setresolution,
  395         mc_clock_write,
  396         mc_clock_enable_interrupts
  397 };
  398 
  399 #ifdef  PS2
  400 /*
  401  *      PS2 autoconf
  402  */
  403 int     mc_probe(), mc_attach();
  404 extern  mc_intr();
  405 
  406 char *  mc_std[] = { (char *) 0x70, 0 };
  407 
  408 struct i386_dev *mc_info[NMC];
  409 struct i386_driver mcdriver =
  410         /* probe slave attach    dname  dinfo mname minfo */
  411         { mc_probe, 0, mc_attach, "mc", mc_info, 0, 0 };
  412 int (*mcintrs[])() = {mc_intr, 0};
  413 
  414 #else   /* PS2 */
  415 /*
  416  *      Standard Configuration
  417  */
  418 boolean_t mc_probe(
  419         vm_offset_t             addr,
  420         struct bus_device       *dev);
  421 void mc_attach(
  422         struct bus_device       *dev);
  423 
  424 static vm_offset_t              mc_std[] = { MC_DEFAULT_ADDRESS, 0 };
  425 static struct bus_device        *mc_info[NMC];
  426 
  427 struct bus_driver               mc_driver = {
  428         mc_probe, 0, mc_attach, 0, mc_std, "mc",
  429         mc_info, 0, 0, 0};
  430 
  431 #endif  /* PS2 */
  432 
  433 #if     defined(AT386) || defined(PS2)
  434 extern mc_sysintr();            /* MC system clock interrupt */
  435 #endif
  436 
  437 /*
  438  *      Where is the chip`s RAM mapped?
  439  */
  440 mc_clock_t      rt_clock = (mc_clock_t) MC_DEFAULT_ADDRESS;
  441 
  442 /*
  443  *      status
  444  */
  445 int             mc_interrupt_enabled = 0;       /* OR with reg B */
  446 boolean_t       mc_new_century = FALSE;         /* patch after Dec 31, 1999 */
  447 
  448 /*
  449  *      Probe to see whether the device exists.
  450  */
  451 #ifdef  PS2
  452 int mc_probe(addr, dev)
  453         vm_offset_t     addr;
  454         struct i386_dev *dev;
  455 #else
  456 boolean_t mc_probe(
  457         vm_offset_t             addr,
  458         struct bus_device       *dev)
  459 #endif
  460 {
  461 #ifdef  PS2
  462         int     unit = dev->dev_unit;
  463 #else
  464         int     unit = dev->unit;
  465 #endif
  466 
  467         if (unit < 0 || unit >= NMC) {
  468             printf("mc%d out of range\n", unit);
  469             return FALSE;
  470         }
  471 
  472         /*
  473          *      We assume that we always have exactly one
  474          *      clock chip.
  475          *
  476          *      Set the clock`s address.
  477          */
  478         rt_clock = (mc_clock_t) addr;
  479         return TRUE;
  480 }
  481 
  482 /*
  483  *      Attach the clock device:
  484  *      set up the clock structure and read
  485  *      the current time from the hardware.
  486  */
  487 #ifdef  PS2
  488 mc_attach(dev)
  489         struct i386_dev *dev;
  490 #else
  491 void mc_attach(
  492         struct bus_device       *dev)
  493 #endif
  494 {
  495 #ifdef  PS2
  496         int             unit = dev->dev_unit;
  497 #else
  498         int             unit = dev->unit;
  499 #endif
  500         mach_clock_t    clock = mc_clock[unit];
  501         time_spec_t     cur_time;
  502 
  503         printf(": MC146818 (or the like) Time-of-Year chip");
  504 
  505         clock_init(clock, &mc_clock_ops);
  506 
  507         clock->resolution = MC_CLOCK_DEFAULT_RESOLUTION;        /* @128 hz */
  508         mc_clock_setresolution(clock);
  509 
  510         printf(", resolution = %u nsecs", clock->resolution);
  511 
  512         if (sys_clock == 0) {
  513             /*
  514              *  If no system clock already, use this as system clock.
  515              */
  516             sys_clock = &mc_clock0;
  517 #if     defined(AT386) || defined(PS2)
  518 #ifdef  PS2
  519             mcintrs[0] = mc_sysintr;
  520 #else
  521             dev->intr = mc_sysintr;     /* use system clock interrupt */
  522 #endif
  523             dev_change_indirect("clock_priv", "mc", unit);
  524                                         /* set generic clock device */
  525             set_clock_unpriv();         /* and 'unprivileged' clock */
  526 #endif
  527         }
  528 
  529 #ifdef  AT386
  530         take_dev_irq(mc_info[0]);       /* XXX */
  531 #endif
  532 #ifdef  PS2
  533         take_dev_irq(dev);
  534 #endif
  535 
  536         /*
  537          *      Read the current time from the chip
  538          */
  539         cur_time = mc_clock_read(clock);
  540         if (!time_spec_valid(cur_time)) {
  541             /*
  542              *  Battery dead - no time
  543              */
  544             printf("\n*** Dead Battery *** Time Unknown ***");
  545             clock->check_seconds = 0;
  546             clock->time.nanoseconds = 0;
  547             clock->time.seconds = 0;
  548         }
  549         else {
  550             clock->check_seconds = cur_time.seconds;
  551             clock->time.nanoseconds = cur_time.nanoseconds;
  552             clock->time.seconds = cur_time.seconds;
  553 
  554             /*
  555              *  If the year is less than 1990, someone
  556              *  has clobbered the clock.
  557              */
  558             if (clock->time.seconds < (60*60*24*365) * (1990 - 1970))
  559                 printf("\n*** The PROM has clobbered the clock ***");
  560         }
  561 }
  562 
  563 /*
  564  *      Enable interrupts from MC clock chip
  565  */
  566 void mc_clock_enable_interrupts(
  567         mach_clock_t    clock)
  568 {
  569         mc_interrupt_enabled = MC_REG_B_PIE;
  570         mc_clock_setresolution(clock);  /* turns on interrupts */
  571 }
  572 
  573 io_return_t mc_open(
  574         int     dev)
  575 {
  576         if (dev < 0 || dev >= NMC)
  577             return D_NO_SUCH_DEVICE;
  578 
  579         return clock_open(mc_clock[dev]);
  580 }
  581 
  582 io_return_t mc_close(
  583         int     dev)
  584 {
  585         return D_SUCCESS;
  586 }
  587 
  588 io_return_t mc_getstat(
  589         int             dev,
  590         int             flavor,
  591         dev_status_t    stat,
  592         natural_t       *count)
  593 {
  594         return clock_getstat(mc_clock[dev], flavor, stat, count);
  595 }
  596 
  597 io_return_t mc_setstat(
  598         int             dev,
  599         int             flavor,
  600         dev_status_t    stat,
  601         natural_t       count)
  602 {
  603         mach_clock_t    clock = mc_clock[dev];
  604         unsigned int    res_request;
  605         unsigned int    res_ceiling, res_floor, res_closest;
  606         int             diff_ceiling, diff_floor, diff_closest;
  607         spl_t           s;
  608 
  609         switch (flavor) {
  610             case CLOCK_RESOLUTION:
  611             {
  612                 clock_resolution_t      request;
  613 
  614                 if (count < CLOCK_RESOLUTION_COUNT)
  615                     return D_INVALID_SIZE;
  616 
  617                 /*
  618                  * Clock can only interrupt at frequencies of
  619                  * 2**n hz, 1 <= n <= 13.
  620                  */
  621 
  622                 request = (clock_resolution_t)stat;
  623                 res_request = request->resolution;
  624 
  625                 if (res_request < MC_CLOCK_MIN_RESOLUTION ||
  626                     res_request > MC_CLOCK_MAX_RESOLUTION)
  627                 {
  628                     return D_INVALID_SIZE;
  629                 }
  630                         
  631                 /*
  632                  *      Find the first available resolution
  633                  *      (NANOSEC_PER_SEC / 2**n) smaller than
  634                  *      the requested resolution.  We already
  635                  *      checked that resolution is above the
  636                  *      hardware`s minimum.
  637                  */
  638                 for (res_floor = NANOSEC_PER_SEC;
  639                      res_floor >= res_request;
  640                      res_floor >>= 1)
  641                     continue;
  642 
  643                 /*
  644                  *      Calculate the next possible resolution
  645                  *      above the request.
  646                  */
  647                 res_ceiling = res_floor << 1;
  648 
  649                 /*
  650                  *      Find the difference between the requested
  651                  *      resolution and the available resolutions
  652                  *      that bracket it, and pick the smaller one.
  653                  */
  654 
  655                 diff_floor = (int) res_floor - (int) res_request;
  656                 if (diff_floor < 0)
  657                     diff_floor = -diff_floor;
  658 
  659                 diff_ceiling = (int) res_ceiling - (int) res_request;
  660                 if (diff_ceiling < 0)
  661                     diff_ceiling = -diff_floor;
  662 
  663                 if (diff_floor < diff_ceiling) {
  664                     res_closest = res_floor;
  665                     diff_closest = diff_floor;
  666                 }
  667                 else {
  668                     res_closest = res_ceiling;
  669                     diff_closest = diff_ceiling;
  670                 }
  671 
  672                 /*
  673                  *      If the closer value is still outside
  674                  *      the tolerance ('skew'), reject the request.
  675                  */
  676                 if (diff_closest > request->skew)
  677                     return D_INVALID_SIZE;
  678 
  679                 /*
  680                  *      Now we have the new resolution to set.
  681                  *      Save it to take effect at the next
  682                  *      clock interrupt.
  683                  */
  684                 s = splsched();
  685                 clock_queue_lock(clock);
  686 
  687                 clock->new_resolution = res_closest;
  688                 clock->new_skew = diff_closest;
  689 
  690                 clock_queue_unlock(clock);
  691                 splx(s);
  692 
  693                 return D_SUCCESS;
  694             }
  695 
  696             default:
  697                 return clock_setstat(clock, flavor, stat, count);
  698         }
  699 }
  700 
  701 
  702 vm_offset_t mc_mmap(
  703         int             dev,
  704         vm_offset_t     off,
  705         vm_prot_t       prot)
  706 {
  707         return clock_map_page(mc_clock[dev], off, prot);
  708 }
  709 
  710 io_return_t mc_devinfo(
  711         int             dev,
  712         int             flavor,
  713         mach_clock_t    *info)
  714 {
  715         if (flavor == D_INFO_CLOCK) {
  716             *info = mc_clock[dev];
  717             return D_SUCCESS;
  718         }
  719         else {
  720             return D_INVALID_OPERATION;
  721         }
  722 }
  723 
  724 void mc_clock_setresolution(
  725         mach_clock_t    clock)
  726 {
  727         int             index, temp;
  728         unsigned int    resolution, res;
  729         
  730         /*
  731          *      Convert the resolution to a rate index
  732          *      for the chip.
  733          */
  734         resolution = clock->resolution;
  735         for (res = NANOSEC_PER_SEC/2, index = MC_RATE_2_Hz;
  736              res > resolution && index > MC_RATE_8192_Hz;
  737              res >>=1, index--)
  738             continue;
  739 
  740 
  741         /*
  742          * Stop updates while we fix it 
  743          */
  744         while (mc_read(rt_clock, MC_REG_A) & MC_REG_A_UIP)
  745             delay(MC_UPD_MINIMUM >> 2);
  746         mc_write(rt_clock, MC_REG_B, MC_REG_B_STOP);
  747         wbflush();
  748 
  749         /*
  750          * Ack any pending interrupts 
  751          */
  752         temp = mc_read(rt_clock, MC_REG_C);
  753 
  754         /*
  755          * Reset the frequency divider, in case we are changing it. 
  756          */
  757         mc_write(rt_clock, MC_REG_A, MC_BASE_RESET);
  758 
  759         /*
  760          * Spec says the VRT bit can be validated, but does not say how. I
  761          * assume it is via reading the register. 
  762          */
  763         temp = mc_read(rt_clock, MC_REG_D);
  764 
  765         /*
  766          * Reconfigure the chip and get it started again 
  767          */
  768         mc_write(rt_clock, MC_REG_A,
  769                            MC_BASE_32_KHz | index);
  770         mc_write(rt_clock, MC_REG_B,
  771                            MC_REG_B_CONFIGURE | mc_interrupt_enabled);
  772 }
  773 
  774 #ifdef  MC_CLOCK_BCD
  775 int bcd_to_int(int bcd)
  776 {
  777         return (bcd >> 4) * 10 + (bcd & 0xf);
  778 }
  779 
  780 int int_to_bcd(int intval)
  781 {
  782         return ((intval / 10) << 4) + (intval % 10);
  783 }
  784 #endif
  785 
  786 /*
  787  *      Read time from clock chip.  If battery was dead,
  788  *      return an invalid time_spec.
  789  */
  790 time_spec_t mc_clock_read(
  791         mach_clock_t    clock)
  792 {
  793         unsigned int years, months, days, hours, minutes, seconds;
  794 #ifdef  MC_CENTURY
  795         unsigned int century;
  796 #endif
  797         time_spec_t   clock_time;
  798         spl_t   s;
  799 
  800         /*
  801          *      Check the battery.
  802          */
  803         if ((mc_read(rt_clock, MC_REG_D) && MC_REG_D_VRT) == 0) {
  804             /*
  805              *  No time.
  806              */
  807             clock_time.seconds = 0;
  808             clock_time.nanoseconds = NANOSEC_PER_SEC + 1; /* invalid */
  809             return clock_time;
  810         }
  811 
  812         /*
  813          *      Wait for update to finish
  814          */
  815         s = splhigh();
  816 
  817         while (mc_read(rt_clock, MC_REG_A) & MC_REG_A_UIP)
  818             delay(MC_UPD_MINIMUM >> 2);
  819 
  820         /*
  821          *      Grab the date and time
  822          */
  823 #ifdef  MC_CENTURY
  824         century = mc_read(rt_clock, MC_CENTURY);
  825 #endif
  826         years   = mc_read(rt_clock, MC_YEAR);
  827         months  = mc_read(rt_clock, MC_MONTH);
  828         days    = mc_read(rt_clock, MC_DAY_OF_MONTH);
  829         hours   = mc_read(rt_clock, MC_HOUR);
  830         minutes = mc_read(rt_clock, MC_MINUTE);
  831         seconds = mc_read(rt_clock, MC_SECOND);
  832 
  833         splx(s);
  834 
  835 #ifdef  MC_CLOCK_BCD
  836         /*
  837          *      Convert the numbers from BCD to binary.
  838          */
  839 #ifdef  MC_CENTURY
  840         century = bcd_to_int(century);
  841 #endif
  842         years   = bcd_to_int(years);
  843         months  = bcd_to_int(months);
  844         days    = bcd_to_int(days);
  845         hours   = bcd_to_int(hours);
  846         minutes = bcd_to_int(minutes);
  847         seconds = bcd_to_int(seconds);
  848 #endif
  849 
  850         /*
  851          *      Convert to seconds from 1970.
  852          */
  853 #ifdef  MC_CENTURY
  854         years += century * 100;
  855 #else
  856         if (years < 70 || mc_new_century)
  857             years += 2000;      /* it`s coming soon... */
  858         else
  859             years += 1900;
  860 #endif
  861 
  862         clock_time.seconds = ymd_to_seconds(
  863                 years, months, days, hours, minutes, seconds);
  864         clock_time.nanoseconds = 0;
  865 
  866         return clock_time;
  867 }
  868 
  869 /*
  870  *      Set real-time-clock-chip from supplied time.
  871  *      Clock has already been updated.
  872  */
  873 void mc_clock_write(
  874         mach_clock_t    clock,
  875         time_spec_t     new_time)
  876 {
  877         unsigned int years, months, days, hours, minutes, seconds;
  878         unsigned int day_of_week, temp;
  879 #ifdef  MC_CENTURY
  880         unsigned int century;
  881 #endif
  882         spl_t   s;
  883 
  884         /*
  885          *      Update hardware, to nearest second
  886          */
  887         seconds_to_ymd(new_time.seconds,
  888                 &years, &months, &days, &hours, &minutes, &seconds,
  889                 &day_of_week);
  890 
  891 #ifdef  MC_CENTURY
  892         /*
  893          *      Keep track of century
  894          */
  895         century = years / 100;
  896 #endif
  897         years %= 100;
  898 
  899         /*
  900          * Check for "hot dates" (chip bugs)
  901          */
  902         if (days >= 28 && days <= 30 &&
  903             hours == 23 && minutes == 59 &&
  904             seconds >= 58)
  905                 seconds = 57;
  906 
  907 #if     MC_CLOCK_BCD
  908         /*
  909          *      DOS keeps the time in BCD.  Convert numbers from decimal.
  910          */
  911 #ifdef  MC_CENTURY
  912         century = int_to_bcd(century);
  913 #endif
  914         years   = int_to_bcd(years);
  915         months  = int_to_bcd(months);
  916         days    = int_to_bcd(days);
  917         hours   = int_to_bcd(hours);
  918         minutes = int_to_bcd(minutes);
  919         seconds = int_to_bcd(seconds);
  920 #endif
  921 
  922         /*
  923          *      Stop updates while we change the time
  924          */
  925         s = splhigh();
  926 
  927         while (mc_read(rt_clock, MC_REG_A) & MC_REG_A_UIP)
  928             delay(MC_UPD_MINIMUM >> 2);
  929 
  930         mc_write(rt_clock, MC_REG_B, MC_REG_B_STOP);
  931 
  932         /*
  933          *      Ack any pending interrupts
  934          */
  935         temp = mc_read(rt_clock, MC_REG_C);
  936 
  937         /*
  938          *      Update the time
  939          */
  940 #ifdef  MC_CENTURY
  941         mc_write(rt_clock, MC_CENTURY, century);
  942 #endif
  943         mc_write(rt_clock, MC_YEAR, years);
  944         mc_write(rt_clock, MC_MONTH, months);
  945         mc_write(rt_clock, MC_DAY_OF_MONTH, days);
  946         mc_write(rt_clock, MC_HOUR, hours);
  947         mc_write(rt_clock, MC_MINUTE, minutes);
  948         mc_write(rt_clock, MC_SECOND, seconds);
  949 
  950         mc_write(rt_clock, MC_DAY_OF_WEEK, day_of_week+1); /* 1..7 */
  951 
  952         /*
  953          *      Restart the chip
  954          */
  955         mc_write(rt_clock, MC_REG_B, MC_REG_B_CONFIGURE | mc_interrupt_enabled);
  956 
  957         splx(s);
  958 }
  959 
  960 /****************************************************************/
  961 
  962 #if     defined(DECSTATION) || defined(FLAMINGO)
  963 /*
  964  *      Interrupt routines
  965  */
  966 
  967 #if     MC_DOES_DELAYS
  968 
  969 #ifdef  DECSTATION
  970 
  971 #include <kern/machine.h>
  972 #define MC_DELAY_PMAX   8
  973 #define MC_DELAY_3MAX   12
  974 
  975 #endif
  976 
  977 /*
  978  * Timed delays
  979  */
  980 
  981 static int              config_step = 0;        /* configure when clock
  982                                                    interrupts are first
  983                                                    enabled */
  984 static volatile int     had_intr;
  985 
  986 extern unsigned int cpu_speed;
  987 
  988 void
  989 config_delay(unsigned int speed)
  990 {
  991         /*
  992          * This is just an initial estimate, later on with the clock
  993          * running we'll tune it more accurately.
  994          */
  995         cpu_speed = speed;
  996 }
  997 
  998 void accurate_config_delay(
  999         spl_t           spllevel)
 1000 {
 1001         register unsigned int   i;
 1002         register spl_t          s;
 1003         int                     inner_loop_count;
 1004         int                     clock_ticks_per_second;
 1005 
 1006 #ifdef  mips
 1007         /* find "spllevel - 1" */
 1008         s = spllevel | ((spllevel >> 1) & SR_INT_MASK);
 1009         splx(s);
 1010 #else
 1011 #endif
 1012 
 1013         /* wait till we have an interrupt pending */
 1014         had_intr = 0;
 1015         while (!had_intr)
 1016                 continue;
 1017 
 1018         had_intr = 0;
 1019         i = delay_timing_function(1, &had_intr, &inner_loop_count);
 1020 
 1021         splx(spllevel);
 1022 
 1023         /* split calculation to avoid overflow */
 1024         clock_ticks_per_second = (NANOSEC_PER_SEC / mc_clock0.resolution);
 1025         i *= clock_ticks_per_second;
 1026 
 1027         cpu_speed = i / (inner_loop_count * 1000000);
 1028 
 1029         /* roundup clock speed */
 1030         i /= 100000;
 1031         if ((i % 10) >= 5)
 1032                 i += 5;
 1033         printf("Estimating CPU clock at %d Mhz\n", i / 10);
 1034         if (isa_pmax() && cpu_speed != MC_DELAY_PMAX) {
 1035                 printf("%s\n", "This machine looks like a DEC 2100");
 1036                 machine_slot[cpu_number()].cpu_subtype = CPU_SUBTYPE_MIPS_R2000;
 1037         }
 1038 }
 1039 
 1040 int mc_intr(
 1041         spl_t   spllevel)
 1042 {
 1043         /*
 1044          * Interrupt flags are read-to-clear.
 1045          */
 1046         if (config_step > 2)
 1047                 return (mc_read(rt_clock,MC_REG_C) & MC_REG_C_IRQF);
 1048         had_intr = (mc_read(rt_clock,MC_REG_C) & MC_REG_C_IRQF) ? 1 : 0;
 1049         if (config_step++ == 0)
 1050                 accurate_config_delay(spllevel);
 1051         return had_intr;
 1052 }
 1053 
 1054 #else   /* MC_DOES_DELAYS */
 1055 
 1056 int mc_intr(spl_t       spllevel)
 1057 {
 1058         return mc_read(rt_clock, MC_REG_C);     /* clear intr */
 1059 }
 1060 
 1061 #endif  /* MC_DOES_DELAYS */
 1062 
 1063 
 1064 #endif  /* defined(DECSTATION) || defined(FLAMINGO) */
 1065 
 1066 #endif  /* NMC > 0 */

Cache object: 1a2fc1c7dc5e98c59c694aaf89e3e1e3


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