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) 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.15  93/05/17  15:11:48  rvb
   30  *      Type casts, etc to quiet gcc 2.3.3 warnings
   31  *      [93/05/17            rvb]
   32  * 
   33  * Revision 2.14  93/05/15  19:37:12  mrt
   34  *      machparam.h -> machspl.h
   35  * 
   36  * Revision 2.13  93/05/10  20:08:19  rvb
   37  *      Fixed types. Define what is exported and what not.
   38  *      [93/05/06  09:57:45  af]
   39  * 
   40  * Revision 2.12  93/02/05  08:05:43  danner
   41  *      Heavy cosmetic changes to make it look like a device after all.
   42  *      Flamingo uses it too.
   43  *      [93/02/04  01:30:53  af]
   44  * 
   45  *      Proper spl typing.
   46  *      [92/11/30            af]
   47  * 
   48  * Revision 2.11  92/02/19  16:45:57  elf
   49  *      Wait for uip before stopping the chip, too.
   50  *      [92/01/22            af]
   51  * 
   52  * Revision 2.10  91/08/24  11:52:28  af
   53  *      Fixed spl munging, for 3min.
   54  *      [91/08/02  01:49:09  af]
   55  * 
   56  * Revision 2.9  91/06/25  20:54:18  rpd
   57  *      Tweaks to make gcc happy.
   58  * 
   59  * Revision 2.8  91/06/19  11:53:54  rvb
   60  *      mips->DECSTATION; vax->VAXSTATION
   61  *      [91/06/12  14:01:54  rvb]
   62  * 
   63  *      File moved here from mips/PMAX since it tries to be generic;
   64  *      it is used on the PMAX and could be used on the Vax3100.
   65  *      It would need a few ifdef vax & ifdef mips for the latter.
   66  *      [91/06/04            rvb]
   67  * 
   68  * Revision 2.7  91/05/14  17:24:22  mrt
   69  *      Correcting copyright
   70  * 
   71  * Revision 2.6  91/02/14  14:34:41  mrt
   72  *      Factored out delay() function, and made it box-indep.
   73  *      Added accurate_config_delay() which calls delay()'s
   74  *      configuration code.  Modified ackrtclock() to
   75  *      invoke it on first call.
   76  *      Tell the user what the CPU clock speed loks like, 
   77  *      distinguish between DS3100 and DS2100 based on clock speed.
   78  *      [91/02/12  13:03:16  af]
   79  * 
   80  * Revision 2.5  91/02/05  17:42:35  mrt
   81  *      Added author notices
   82  *      [91/02/04  11:15:06  mrt]
   83  * 
   84  *      Changed to use new Mach copyright
   85  *      [91/02/02  12:13:45  mrt]
   86  * 
   87  * Revision 2.4  90/12/05  23:32:39  af
   88  * 
   89  * 
   90  * Revision 2.3  90/12/05  20:47:31  af
   91  *      Made file conditional.
   92  *      [90/12/03  23:28:03  af]
   93  * 
   94  * Revision 2.2  90/08/27  22:06:05  dbg
   95  *      Initialized cpu_speed to a non-zero value.  Apparently,
   96  *      we need delays much earlier than we can possibly know
   97  *      what this machine looks like.  I know this will bite back.
   98  *      [90/08/21            af]
   99  *      Made apparent who is resetting the clock back to 1972.
  100  *      [90/08/20  10:30:19  af]
  101  * 
  102  *      Created, from Motorola's MC146818 specs.
  103  *      [90/08/17            af]
  104  * 
  105  */
  106 /*
  107  *      File:   mc_clock.c
  108  *      Author: Alessandro Forin
  109  *      Date:   8/90
  110  *
  111  *      Driver for the MC146818 Clock
  112  */
  113 
  114 #include <mc.h>
  115 #if     NMC > 0
  116 #include <platforms.h>
  117 
  118 #include <mach/std_types.h>
  119 #include <machine/machspl.h>            /* spl definitions */
  120 #include <chips/busses.h>
  121 
  122 #include <sys/time.h>
  123 #include <kern/time_out.h>
  124 #include <chips/mc_clock.h>
  125 
  126 #ifdef  DECSTATION
  127 #include <mips/mips_cpu.h>
  128 #include <mips/clock.h>
  129 #endif  /*DECSTATION*/
  130 
  131 #ifdef  FLAMINGO
  132 #include <alpha/clock.h>
  133 #endif  /*FLAMINGO*/
  134 
  135 #define private static
  136 #define public
  137 
  138 
  139 /* Architecture-specific defines */
  140 
  141 #ifdef  DECSTATION
  142 
  143 #define MC_DEFAULT_ADDRESS      (mc_clock_ram_t *)PHYS_TO_K1SEG(0x1d000000)
  144 #define MC_DOES_DELAYS          1
  145 
  146 /*
  147  * Both the Pmax and the 3max implementations of the chip map
  148  * bytes of the chip's RAM to 32 bit words (low byte).
  149  * For convenience, we redefine here the chip's RAM layout
  150  * making padding explicit. 
  151  */
  152 
  153 typedef struct {
  154         volatile unsigned char  mc_second;
  155                                                                 char pad0[3];
  156         volatile unsigned char  mc_alarm_second;
  157                                                                 char pad1[3];
  158         volatile unsigned char  mc_minute;
  159                                                                 char pad2[3];
  160         volatile unsigned char  mc_alarm_minute;
  161                                                                 char pad3[3];
  162         volatile unsigned char  mc_hour;
  163                                                                 char pad4[3];
  164         volatile unsigned char  mc_alarm_hour;
  165                                                                 char pad5[3];
  166         volatile unsigned char  mc_day_of_week;
  167                                                                 char pad6[3];
  168         volatile unsigned char  mc_day_of_month;
  169                                                                 char pad7[3];
  170         volatile unsigned char  mc_month;
  171                                                                 char pad8[3];
  172         volatile unsigned char  mc_year;
  173                                                                 char pad9[3];
  174         volatile unsigned char  mc_register_A;
  175                                                                 char pad10[3];
  176         volatile unsigned char  mc_register_B;
  177                                                                 char pad11[3];
  178         volatile unsigned char  mc_register_C;
  179                                                                 char pad12[3];
  180         volatile unsigned char  mc_register_D;
  181                                                                 char pad13[3];
  182         unsigned char           mc_non_volatile_ram[50 * 4];    /* unused */
  183 } mc_clock_ram_t;
  184 
  185 #define MC_CLOCK_PADDED 1
  186 
  187 #endif  /*DECSTATION*/
  188 
  189 
  190 #ifdef  FLAMINGO
  191 #define MC_DEFAULT_ADDRESS      0L
  192 
  193 /* padded, later */
  194 
  195 #endif  /* FLAMINGO */
  196 
  197 
  198 
  199 #ifndef MC_CLOCK_PADDED
  200 typedef mc_clock_t mc_clock_ram_t;      /* No padding needed */
  201 #endif
  202 
  203 /*
  204  * Functions provided herein
  205  */
  206 int mc_probe( vm_offset_t addr, struct bus_ctlr * );
  207 private void mc_attach();
  208 
  209 int mc_intr();
  210 
  211 void mc_open(), mc_close(), mc_write();
  212 private unsigned int mc_read();
  213 
  214 private void mc_wait_for_uip( mc_clock_ram_t *clock );
  215 
  216 
  217 /*
  218  * Status
  219  */
  220 boolean_t mc_running = FALSE;
  221 boolean_t mc_new_century = FALSE;       /* "year" info overfloweth */
  222 
  223 private int days_per_month[12] = {
  224         31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  225 };
  226 
  227 private unsigned int    mc_read();              /* forward */
  228 private void            mc_wait_for_uip();
  229 
  230 /*
  231  * Where is the chip's RAM mapped
  232  */
  233 private mc_clock_ram_t  *rt_clock = MC_DEFAULT_ADDRESS;
  234 
  235 /*
  236  * (Auto?)Configuration
  237  */
  238 private vm_offset_t mc_std[NMC] = { 0 };
  239 private struct bus_device *mc_info[NMC];
  240 
  241 struct bus_driver mc_driver =
  242        { mc_probe, 0, mc_attach, 0, mc_std, "mc", mc_info, };
  243 
  244 
  245 mc_probe(vm_offset_t addr, struct bus_ctlr *ui)
  246 {
  247         rt_clock = (mc_clock_ram_t *)addr;
  248         return 1;
  249 }
  250 
  251 private void
  252 mc_attach()
  253 {
  254         printf(": MC146818 or like Time-Of-Year chip");
  255 }
  256 
  257 /*
  258  *      Interrupt routine
  259  */
  260 #if     MC_DOES_DELAYS
  261 
  262 private int             config_step = 3;
  263 private volatile int    had_intr;
  264 
  265 mc_intr(spllevel)
  266         spl_t   spllevel;
  267 {
  268         /*
  269          * Interrupt flags are read-to-clear.
  270          */
  271         if (config_step > 2)
  272                 return (rt_clock->mc_register_C & MC_REG_C_IRQF);
  273         had_intr = (rt_clock->mc_register_C & MC_REG_C_IRQF) ? 1 : 0;
  274         if (config_step++ == 0)
  275                 accurate_config_delay(spllevel);
  276         return had_intr;
  277 }
  278 #else   /* MC_DOES_DELAYS */
  279 
  280 mc_intr()
  281 {
  282         return (rt_clock->mc_register_C);       /* clear intr */
  283 }
  284 
  285 #endif  /* MC_DOES_DELAYS */
  286 
  287 /*
  288  * Start real-time clock.
  289  */
  290 void
  291 mc_open()
  292 {
  293         /*
  294          * All we should need to do is to enable interrupts, but
  295          * since we do not know what OS last ran on this box
  296          * we'll reset it all over again.  Just kidding..
  297          */
  298         unsigned        unix_seconds_now;
  299 
  300         /*
  301          * Check for battery backup power.  If we do not have it,
  302          * warn the user.  Time will be bogus only after power up.
  303          */
  304         if ((rt_clock->mc_register_D & MC_REG_D_VRT) == 0)
  305                 printf("WARNING: clock batteries are low\n");
  306 
  307         /*
  308          * Read the current time settings, check if the year info
  309          * has been screwed up.  
  310          */
  311         unix_seconds_now = mc_read();
  312 
  313         if (unix_seconds_now < (SECYR * (1990 - YRREF)))
  314                 printf("The prom has clobbered the clock\n");
  315 
  316         time.tv_sec = (long)unix_seconds_now;
  317         mc_write();
  318 
  319         mc_running = TRUE;
  320 }
  321 
  322 void
  323 mc_close()
  324 {
  325         /*
  326          * Disable interrupts, but keep the chip running.
  327          * Note we are called at splhigh and an interrupt
  328          * might be pending already.
  329          */
  330 
  331         mc_intr(0);
  332         rt_clock->mc_register_B &= ~(MC_REG_B_UIE|MC_REG_B_AIE|MC_REG_B_PIE);
  333         mc_running = FALSE;
  334 #if     MC_DOES_DELAYS
  335         config_step = 0;
  336 #endif
  337 }
  338 
  339 
  340 /*
  341  * Set time-of-day.  Must be called at splhigh()
  342  */
  343 void
  344 mc_write()
  345 {
  346         register mc_clock_ram_t *clock = rt_clock;
  347         register unsigned years, months, days, hours, minutes, seconds;
  348         register unsigned unix_seconds = time.tv_sec;
  349         int             frequence_selector, temp;
  350         int             bogus_hz = 0;
  351 
  352         /*
  353          * Convert U*x time into absolute time 
  354          */
  355 
  356         years = YRREF;
  357         while (1) {
  358                 seconds = SECYR;
  359                 if (LEAPYEAR(years))
  360                         seconds += SECDAY;
  361                 if (unix_seconds < seconds)
  362                         break;
  363                 unix_seconds -= seconds;
  364                 years++;
  365         }
  366 
  367         months = 0;
  368         while (1) {
  369                 seconds = days_per_month[months++] * SECDAY;
  370                 if (months == 2 /* February */ && LEAPYEAR(years))
  371                         seconds += SECDAY;
  372                 if (unix_seconds < seconds)
  373                         break;
  374                 unix_seconds -= seconds;
  375         }
  376 
  377         days = unix_seconds / SECDAY;
  378         unix_seconds -= SECDAY * days++;
  379 
  380         hours = unix_seconds / SECHOUR;
  381         unix_seconds -= SECHOUR * hours;
  382 
  383         minutes = unix_seconds / SECMIN;
  384         unix_seconds -= SECMIN * minutes;
  385 
  386         seconds = unix_seconds;
  387 
  388         /*
  389          * Trim years into 0-99 range.
  390          */
  391         if ((years -= 1900) > 99) {
  392                 years -= 100;
  393                 mc_new_century = TRUE;
  394         }
  395 
  396         /*
  397          * Check for "hot dates" 
  398          */
  399         if (days >= 28 && days <= 30 &&
  400             hours == 23 && minutes == 59 &&
  401             seconds >= 58)
  402                 seconds = 57;
  403 
  404         /*
  405          * Select the interrupt frequency based on system params 
  406          */
  407         switch (hz) {
  408         case 1024:
  409                 frequence_selector = MC_BASE_32_KHz | MC_RATE_1024_Hz;
  410                 break;
  411         case 512:
  412                 frequence_selector = MC_BASE_32_KHz | MC_RATE_512_Hz;
  413                 break;
  414         case 256:
  415                 frequence_selector = MC_BASE_32_KHz | MC_RATE_256_Hz;
  416                 break;
  417         case 128:
  418                 frequence_selector = MC_BASE_32_KHz | MC_RATE_128_Hz;
  419                 break;
  420         case 64:
  421 default_frequence:
  422                 frequence_selector = MC_BASE_32_KHz | MC_RATE_64_Hz;
  423                 break;
  424         default:
  425                 bogus_hz = hz;
  426                 hz = 64;
  427                 tick = 1000000 / 64;
  428                 goto default_frequence;
  429         }
  430 
  431         /*
  432          * Stop updates while we fix it 
  433          */
  434         mc_wait_for_uip(clock);
  435         clock->mc_register_B = MC_REG_B_STOP;
  436         wbflush();
  437 
  438         /*
  439          * Ack any pending interrupts 
  440          */
  441         temp = clock->mc_register_C;
  442 
  443         /*
  444          * Reset the frequency divider, in case we are changing it. 
  445          */
  446         clock->mc_register_A = MC_BASE_RESET;
  447 
  448         /*
  449          * Now update the time 
  450          */
  451         clock->mc_second = seconds;
  452         clock->mc_minute = minutes;
  453         clock->mc_hour   = hours;
  454         clock->mc_day_of_month = days;
  455         clock->mc_month  = months;
  456         clock->mc_year   = years;
  457 
  458         /*
  459          * Spec says the VRT bit can be validated, but does not say how. I
  460          * assume it is via reading the register. 
  461          */
  462         temp = clock->mc_register_D;
  463 
  464         /*
  465          * Reconfigure the chip and get it started again 
  466          */
  467         clock->mc_register_A = frequence_selector;
  468         clock->mc_register_B = MC_REG_B_24HM | MC_REG_B_DM | MC_REG_B_PIE;
  469 
  470         /*
  471          * Print warnings, if we have to 
  472          */
  473         if (bogus_hz != 0)
  474                 printf("Unacceptable value (%d Hz) for hz, reset to %d Hz\n",
  475                         bogus_hz, hz);
  476 }
  477 
  478 
  479 /*
  480  * Internal functions
  481  */
  482 
  483 private void
  484 mc_wait_for_uip(clock)
  485         mc_clock_ram_t *clock;
  486 {
  487         while (clock->mc_register_A & MC_REG_A_UIP)
  488                 delay(MC_UPD_MINIMUM >> 2);
  489 }
  490 
  491 private unsigned int
  492 mc_read()
  493 {
  494         /*
  495          * Note we only do this at boot time
  496          */
  497         register unsigned years, months, days, hours, minutes, seconds;
  498         register mc_clock_ram_t *clock = rt_clock;;
  499 
  500         /*
  501          * If the chip is updating, wait 
  502          */
  503         mc_wait_for_uip(clock);
  504 
  505         years = clock->mc_year;
  506         months = clock->mc_month;
  507         days = clock->mc_day_of_month;
  508         hours = clock->mc_hour;
  509         minutes = clock->mc_minute;
  510         seconds = clock->mc_second;
  511 
  512         /*
  513          * Convert to Unix time 
  514          */
  515         seconds += minutes * SECMIN;
  516         seconds += hours * SECHOUR;
  517         seconds += (days - 1) * SECDAY;
  518         if (months > 2 /* February */ && LEAPYEAR(years))
  519                 seconds += SECDAY;
  520         while (months > 1)
  521                 seconds += days_per_month[--months - 1];
  522 
  523         /*
  524          * Note that in ten years from today (Aug,1990) the new century will
  525          * cause the trouble that mc_new_century attempts to avoid. 
  526          */
  527         if (mc_new_century)
  528                 years += 100;
  529         years += 1900;  /* chip base year in YRREF's century */
  530 
  531         for (--years; years >= YRREF; years--) {
  532                 seconds += SECYR;
  533                 if (LEAPYEAR(years))
  534                         seconds += SECDAY;
  535         }
  536 
  537         return seconds;
  538 }
  539 
  540 #ifdef  MC_DOES_DELAYS
  541 
  542 /*
  543  * Timed delays
  544  */
  545 extern unsigned int cpu_speed;
  546 
  547 void
  548 config_delay(speed)
  549 {
  550         /*
  551          * This is just an initial estimate, later on with the clock
  552          * running we'll tune it more accurately.
  553          */
  554         cpu_speed = speed;
  555 }
  556 
  557 accurate_config_delay(spllevel)
  558         spl_t           spllevel;
  559 {
  560         register unsigned int   i;
  561         register spl_t          s;
  562         int                     inner_loop_count;
  563 
  564 #ifdef  mips
  565         /* find "spllevel - 1" */
  566         s = spllevel | ((spllevel >> 1) & SR_INT_MASK);
  567         splx(s);
  568 #else
  569 #endif
  570 
  571         /* wait till we have an interrupt pending */
  572         had_intr = 0;
  573         while (!had_intr)
  574                 continue;
  575 
  576         had_intr = 0;
  577         i = delay_timing_function(1, &had_intr, &inner_loop_count);
  578 
  579         splx(spllevel);
  580 
  581         i *= hz;
  582         cpu_speed = i / (inner_loop_count * 1000000);
  583 
  584         /* roundup clock speed */
  585         i /= 100000;
  586         if ((i % 10) >= 5)
  587                 i += 5;
  588         printf("Estimating CPU clock at %d Mhz\n", i / 10);
  589         if (isa_pmax() && cpu_speed != MC_DELAY_PMAX) {
  590                 printf("%s\n", "This machine looks like a DEC 2100");
  591                 machine_slot[cpu_number()].cpu_subtype = CPU_SUBTYPE_MIPS_R2000;
  592         }
  593 }
  594 #endif  /* MC_DOES_DELAYS */
  595 
  596 #endif  NMC > 0

Cache object: c5c4b5cb05030461e747582b79ab13b6


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