efi-rtc.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:5k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * This file is subject to the terms and conditions of the GNU General Public
  3.  * License.  See the file "COPYING" in the main directory of this archive
  4.  * for more details.
  5.  *
  6.  * Copyright (C) 2001 Silicon Graphics, Inc.
  7.  * Copyright (C) 2001 by Ralf Baechle
  8.  */
  9. #include <linux/kernel.h>
  10. #include <linux/types.h>
  11. #include <linux/spinlock.h>
  12. #include <linux/init.h>
  13. #include <linux/pci.h>
  14. #include <linux/errno.h>
  15. #include <linux/efi.h>
  16. #include <asm/sn/klclock.h>
  17. /*
  18.  * No locking necessary when this is called from efirtc which protects us
  19.  * from racing by efi_rtc_lock.
  20.  */
  21. #define __swizzle(addr) ((u8 *)((unsigned long)(addr) ^ 3))
  22. #define read_io_port(addr) (*(volatile u8 *) __swizzle(addr))
  23. #define write_io_port(addr, data) (*(volatile u8 *) __swizzle(addr) = (data))
  24. #define TOD_SGS_M48T35 1
  25. #define TOD_DALLAS_DS1386 2
  26. static unsigned long nvram_base = 0;
  27. static int tod_chip_type;
  28. static int
  29. get_tod_chip_type(void)
  30. {
  31. unsigned char testval;
  32. write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_DISABLE);
  33. write_io_port(RTC_DAL_DAY_ADDR, 0xff);
  34. write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_ENABLE);
  35. testval = read_io_port(RTC_DAL_DAY_ADDR);
  36. if (testval == 0xff)
  37. return TOD_SGS_M48T35;
  38. return TOD_DALLAS_DS1386;
  39. }
  40. efi_status_t
  41. ioc3_get_time(efi_time_t *time, efi_time_cap_t *caps)
  42. {
  43. if (!nvram_base) {
  44. printk(KERN_CRIT "nvram_base is zeron");
  45. return EFI_UNSUPPORTED;
  46. }
  47. memset(time, 0, sizeof(*time));
  48. switch (tod_chip_type) {
  49. case TOD_SGS_M48T35:
  50. write_io_port(RTC_SGS_CONTROL_ADDR, RTC_SGS_READ_PROTECT);
  51. time->year = BCD_TO_INT(read_io_port(RTC_SGS_YEAR_ADDR)) + YRREF;
  52. time->month = BCD_TO_INT(read_io_port(RTC_SGS_MONTH_ADDR));
  53. time->day = BCD_TO_INT(read_io_port(RTC_SGS_DATE_ADDR));
  54. time->hour = BCD_TO_INT(read_io_port(RTC_SGS_HOUR_ADDR));
  55. time->minute = BCD_TO_INT(read_io_port(RTC_SGS_MIN_ADDR));
  56. time->second = BCD_TO_INT(read_io_port(RTC_SGS_SEC_ADDR));
  57. time->nanosecond = 0;
  58. write_io_port(RTC_SGS_CONTROL_ADDR, 0);
  59. break;
  60. case TOD_DALLAS_DS1386:
  61. write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_DISABLE);
  62. time->nanosecond = 0;
  63. time->second = BCD_TO_INT(read_io_port(RTC_DAL_SEC_ADDR));
  64. time->minute = BCD_TO_INT(read_io_port(RTC_DAL_MIN_ADDR));
  65. time->hour = BCD_TO_INT(read_io_port(RTC_DAL_HOUR_ADDR));
  66. time->day = BCD_TO_INT(read_io_port(RTC_DAL_DATE_ADDR));
  67. time->month = BCD_TO_INT(read_io_port(RTC_DAL_MONTH_ADDR));
  68. time->year = BCD_TO_INT(read_io_port(RTC_DAL_YEAR_ADDR)) + YRREF;
  69. write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_ENABLE);
  70. break;
  71. default:
  72. break;
  73. }
  74. if (caps) {
  75. caps->resolution = 50000000; /*  50PPM */
  76. caps->accuracy = 1000; /*  1ms */
  77. caps->sets_to_zero = 0;
  78. }
  79. return EFI_SUCCESS;
  80. }
  81. static efi_status_t ioc3_set_time (efi_time_t *t)
  82. {
  83. if (!nvram_base) {
  84. printk(KERN_CRIT "nvram_base is zeron");
  85. return EFI_UNSUPPORTED;
  86. }
  87. switch (tod_chip_type) {
  88. case TOD_SGS_M48T35:
  89. write_io_port(RTC_SGS_CONTROL_ADDR, RTC_SGS_WRITE_ENABLE);
  90.          write_io_port(RTC_SGS_YEAR_ADDR, INT_TO_BCD((t->year - YRREF)));
  91. write_io_port(RTC_SGS_MONTH_ADDR,INT_TO_BCD(t->month));
  92. write_io_port(RTC_SGS_DATE_ADDR, INT_TO_BCD(t->day));
  93. write_io_port(RTC_SGS_HOUR_ADDR, INT_TO_BCD(t->hour));
  94. write_io_port(RTC_SGS_MIN_ADDR,  INT_TO_BCD(t->minute));
  95. write_io_port(RTC_SGS_SEC_ADDR,  INT_TO_BCD(t->second));
  96. write_io_port(RTC_SGS_CONTROL_ADDR, 0);
  97. break;
  98. case TOD_DALLAS_DS1386:
  99. write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_DISABLE);
  100. write_io_port(RTC_DAL_SEC_ADDR,  INT_TO_BCD(t->second));
  101. write_io_port(RTC_DAL_MIN_ADDR,  INT_TO_BCD(t->minute));
  102. write_io_port(RTC_DAL_HOUR_ADDR, INT_TO_BCD(t->hour));
  103. write_io_port(RTC_DAL_DATE_ADDR, INT_TO_BCD(t->day));
  104. write_io_port(RTC_DAL_MONTH_ADDR,INT_TO_BCD(t->month));
  105. write_io_port(RTC_DAL_YEAR_ADDR, INT_TO_BCD((t->year - YRREF)));
  106. write_io_port(RTC_DAL_CONTROL_ADDR, RTC_DAL_UPDATE_ENABLE);
  107. break;
  108. default:
  109. break;
  110. }
  111. return EFI_SUCCESS;
  112. }
  113. /* The following two are not supported atm.  */
  114. static efi_status_t
  115. ioc3_get_wakeup_time (efi_bool_t *enabled, efi_bool_t *pending, efi_time_t *tm)
  116. {
  117. return EFI_UNSUPPORTED;
  118. }
  119. static efi_status_t
  120. ioc3_set_wakeup_time (efi_bool_t enabled, efi_time_t *tm)
  121. {
  122. return EFI_UNSUPPORTED;
  123. }
  124. /*
  125.  * It looks like the master IOC3 is usually on bus 0, device 4.  Hope
  126.  * that's right
  127.  */
  128. static __init int efi_ioc3_time_init(void)
  129. {
  130. struct pci_dev *dev;
  131. static struct ioc3 *ioc3;
  132. dev = pci_find_slot(0, PCI_DEVFN(4, 0));
  133. if (!dev) {
  134. printk(KERN_CRIT "Couldn't find master IOC3n");
  135. return -ENODEV;
  136. }
  137. ioc3 = ioremap(pci_resource_start(dev, 0), pci_resource_len(dev, 0));
  138. nvram_base = (unsigned long) ioc3 + IOC3_BYTEBUS_DEV0;
  139. tod_chip_type = get_tod_chip_type();
  140. if (tod_chip_type == 1)
  141. printk(KERN_NOTICE "TOD type is SGS M48T35n");
  142. else if (tod_chip_type == 2)
  143. printk(KERN_NOTICE "TOD type is Dallas DS1386n");
  144. else
  145. printk(KERN_CRIT "No or unknown TODn");
  146. efi.get_time = ioc3_get_time;
  147. efi.set_time = ioc3_set_time;
  148. efi.get_wakeup_time = ioc3_get_wakeup_time;
  149. efi.set_wakeup_time = ioc3_set_wakeup_time;
  150. return 0;
  151. }
  152. module_init(efi_ioc3_time_init);