m48t59y.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. /*
  2. * SGS M48-T59Y TOD/NVRAM Driver
  3. *
  4. * (C) Copyright 2000
  5. * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
  6. *
  7. * (C) Copyright 1999, by Curt McDowell, 08-06-99, Broadcom Corp.
  8. *
  9. * (C) Copyright 2001, James Dougherty, 07/18/01, Broadcom Corp.
  10. *
  11. * See file CREDITS for list of people who contributed to this
  12. * project.
  13. *
  14. * This program is free software; you can redistribute it and/or
  15. * modify it under the terms of the GNU General Public License as
  16. * published by the Free Software Foundation; either version 2 of
  17. * the License, or (at your option) any later version.
  18. *
  19. * This program is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. * GNU General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU General Public License
  25. * along with this program; if not, write to the Free Software
  26. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  27. * MA 02111-1307 USA
  28. */
  29. /*
  30. * SGS M48-T59Y TOD/NVRAM Driver
  31. *
  32. * The SGS M48 an 8K NVRAM starting at offset M48_BASE_ADDR and
  33. * continuing for 8176 bytes. After that starts the Time-Of-Day (TOD)
  34. * registers which are used to set/get the internal date/time functions.
  35. *
  36. * This module implements Y2K compliance by taking full year numbers
  37. * and translating back and forth from the TOD 2-digit year.
  38. *
  39. * NOTE: for proper interaction with an operating system, the TOD should
  40. * be used to store Universal Coordinated Time (GMT) and timezone
  41. * conversions should be used.
  42. *
  43. * Here is a diagram of the memory layout:
  44. *
  45. * +---------------------------------------------+ 0xffe0a000
  46. * | Non-volatile memory | .
  47. * | | .
  48. * | (8176 bytes of Non-volatile memory) | .
  49. * | | .
  50. * +---------------------------------------------+ 0xffe0bff0
  51. * | Flags |
  52. * +---------------------------------------------+ 0xffe0bff1
  53. * | Unused |
  54. * +---------------------------------------------+ 0xffe0bff2
  55. * | Alarm Seconds |
  56. * +---------------------------------------------+ 0xffe0bff3
  57. * | Alarm Minutes |
  58. * +---------------------------------------------+ 0xffe0bff4
  59. * | Alarm Date |
  60. * +---------------------------------------------+ 0xffe0bff5
  61. * | Interrupts |
  62. * +---------------------------------------------+ 0xffe0bff6
  63. * | WatchDog |
  64. * +---------------------------------------------+ 0xffe0bff7
  65. * | Calibration |
  66. * +---------------------------------------------+ 0xffe0bff8
  67. * | Seconds |
  68. * +---------------------------------------------+ 0xffe0bff9
  69. * | Minutes |
  70. * +---------------------------------------------+ 0xffe0bffa
  71. * | Hours |
  72. * +---------------------------------------------+ 0xffe0bffb
  73. * | Day |
  74. * +---------------------------------------------+ 0xffe0bffc
  75. * | Date |
  76. * +---------------------------------------------+ 0xffe0bffd
  77. * | Month |
  78. * +---------------------------------------------+ 0xffe0bffe
  79. * | Year (2 digits only) |
  80. * +---------------------------------------------+ 0xffe0bfff
  81. */
  82. #include <common.h>
  83. #include <rtc.h>
  84. #include "mousse.h"
  85. /*
  86. * Imported from mousse.h:
  87. *
  88. * TOD_REG_BASE Base of m48t59y TOD registers
  89. * SYS_TOD_UNPROTECT() Disable NVRAM write protect
  90. * SYS_TOD_PROTECT() Re-enable NVRAM write protect
  91. */
  92. #define YEAR 0xf
  93. #define MONTH 0xe
  94. #define DAY 0xd
  95. #define DAY_OF_WEEK 0xc
  96. #define HOUR 0xb
  97. #define MINUTE 0xa
  98. #define SECOND 0x9
  99. #define CONTROL 0x8
  100. #define WATCH 0x7
  101. #define INTCTL 0x6
  102. #define WD_DATE 0x5
  103. #define WD_HOUR 0x4
  104. #define WD_MIN 0x3
  105. #define WD_SEC 0x2
  106. #define _UNUSED 0x1
  107. #define FLAGS 0x0
  108. #define M48_ADDR ((volatile unsigned char *) TOD_REG_BASE)
  109. int m48_tod_init(void)
  110. {
  111. SYS_TOD_UNPROTECT();
  112. M48_ADDR[CONTROL] = 0;
  113. M48_ADDR[WATCH] = 0;
  114. M48_ADDR[INTCTL] = 0;
  115. /*
  116. * If the oscillator is currently stopped (as on a new part shipped
  117. * from the factory), start it running.
  118. *
  119. * Here is an example of the TOD bytes on a brand new M48T59Y part:
  120. * 00 00 00 00 00 00 00 00 00 88 8c c3 bf c8 f5 01
  121. */
  122. if (M48_ADDR[SECOND] & 0x80)
  123. M48_ADDR[SECOND] = 0;
  124. /* Is battery low */
  125. if ( M48_ADDR[FLAGS] & 0x10) {
  126. printf("NOTICE: Battery low on Real-Time Clock (replace SNAPHAT).\n");
  127. }
  128. SYS_TOD_PROTECT();
  129. return 0;
  130. }
  131. /*
  132. * m48_tod_set
  133. */
  134. static int to_bcd(int value)
  135. {
  136. return value / 10 * 16 + value % 10;
  137. }
  138. static int from_bcd(int value)
  139. {
  140. return value / 16 * 10 + value % 16;
  141. }
  142. static int day_of_week(int y, int m, int d) /* 0-6 ==> Sun-Sat */
  143. {
  144. static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
  145. y -= m < 3;
  146. return (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7;
  147. }
  148. /*
  149. * Note: the TOD should store the current GMT
  150. */
  151. int m48_tod_set(int year, /* 1980-2079 */
  152. int month, /* 01-12 */
  153. int day, /* 01-31 */
  154. int hour, /* 00-23 */
  155. int minute, /* 00-59 */
  156. int second) /* 00-59 */
  157. {
  158. SYS_TOD_UNPROTECT();
  159. M48_ADDR[CONTROL] |= 0x80; /* Set WRITE bit */
  160. M48_ADDR[YEAR] = to_bcd(year % 100);
  161. M48_ADDR[MONTH] = to_bcd(month);
  162. M48_ADDR[DAY] = to_bcd(day);
  163. M48_ADDR[DAY_OF_WEEK] = day_of_week(year, month, day) + 1;
  164. M48_ADDR[HOUR] = to_bcd(hour);
  165. M48_ADDR[MINUTE] = to_bcd(minute);
  166. M48_ADDR[SECOND] = to_bcd(second);
  167. M48_ADDR[CONTROL] &= ~0x80; /* Clear WRITE bit */
  168. SYS_TOD_PROTECT();
  169. return 0;
  170. }
  171. /*
  172. * Note: the TOD should store the current GMT
  173. */
  174. int m48_tod_get(int *year, /* 1980-2079 */
  175. int *month, /* 01-12 */
  176. int *day, /* 01-31 */
  177. int *hour, /* 00-23 */
  178. int *minute, /* 00-59 */
  179. int *second) /* 00-59 */
  180. {
  181. int y;
  182. SYS_TOD_UNPROTECT();
  183. M48_ADDR[CONTROL] |= 0x40; /* Set READ bit */
  184. y = from_bcd(M48_ADDR[YEAR]);
  185. *year = y < 80 ? 2000 + y : 1900 + y;
  186. *month = from_bcd(M48_ADDR[MONTH]);
  187. *day = from_bcd(M48_ADDR[DAY]);
  188. /* day_of_week = M48_ADDR[DAY_OF_WEEK] & 0xf; */
  189. *hour = from_bcd(M48_ADDR[HOUR]);
  190. *minute = from_bcd(M48_ADDR[MINUTE]);
  191. *second = from_bcd(M48_ADDR[SECOND] & 0x7f);
  192. M48_ADDR[CONTROL] &= ~0x40; /* Clear READ bit */
  193. SYS_TOD_PROTECT();
  194. return 0;
  195. }
  196. int m48_tod_get_second(void)
  197. {
  198. return from_bcd(M48_ADDR[SECOND] & 0x7f);
  199. }
  200. /*
  201. * Watchdog function
  202. *
  203. * If usec is 0, the watchdog timer is disarmed.
  204. *
  205. * If usec is non-zero, the watchdog timer is armed (or re-armed) for
  206. * approximately usec microseconds (if the exact requested usec is
  207. * not supported by the chip, the next higher available value is used).
  208. *
  209. * Minimum watchdog timeout = 62500 usec
  210. * Maximum watchdog timeout = 124 sec (124000000 usec)
  211. */
  212. void m48_watchdog_arm(int usec)
  213. {
  214. int mpy, res;
  215. SYS_TOD_UNPROTECT();
  216. if (usec == 0) {
  217. res = 0;
  218. mpy = 0;
  219. } else if (usec < 2000000) { /* Resolution: 1/16s if below 2s */
  220. res = 0;
  221. mpy = (usec + 62499) / 62500;
  222. } else if (usec < 8000000) { /* Resolution: 1/4s if below 8s */
  223. res = 1;
  224. mpy = (usec + 249999) / 250000;
  225. } else if (usec < 32000000) { /* Resolution: 1s if below 32s */
  226. res = 2;
  227. mpy = (usec + 999999) / 1000000;
  228. } else { /* Resolution: 4s up to 124s */
  229. res = 3;
  230. mpy = (usec + 3999999) / 4000000;
  231. if (mpy > 31)
  232. mpy = 31;
  233. }
  234. M48_ADDR[WATCH] = (0x80 | /* Steer to RST signal (IRQ = N/C) */
  235. mpy << 2 |
  236. res);
  237. SYS_TOD_PROTECT();
  238. }
  239. /*
  240. * U-Boot RTC support.
  241. */
  242. int
  243. rtc_get( struct rtc_time *tmp )
  244. {
  245. m48_tod_get(&tmp->tm_year,
  246. &tmp->tm_mon,
  247. &tmp->tm_mday,
  248. &tmp->tm_hour,
  249. &tmp->tm_min,
  250. &tmp->tm_sec);
  251. tmp->tm_yday = 0;
  252. tmp->tm_isdst= 0;
  253. #ifdef RTC_DEBUG
  254. printf( "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
  255. tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
  256. tmp->tm_hour, tmp->tm_min, tmp->tm_sec );
  257. #endif
  258. return 0;
  259. }
  260. int rtc_set( struct rtc_time *tmp )
  261. {
  262. m48_tod_set(tmp->tm_year, /* 1980-2079 */
  263. tmp->tm_mon, /* 01-12 */
  264. tmp->tm_mday, /* 01-31 */
  265. tmp->tm_hour, /* 00-23 */
  266. tmp->tm_min, /* 00-59 */
  267. tmp->tm_sec); /* 00-59 */
  268. #ifdef RTC_DEBUG
  269. printf( "Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
  270. tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
  271. tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
  272. #endif
  273. return 0;
  274. }
  275. void
  276. rtc_reset (void)
  277. {
  278. m48_tod_init();
  279. }