cyclone.c 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. #include <linux/module.h>
  2. #include <linux/smp.h>
  3. #include <linux/time.h>
  4. #include <linux/errno.h>
  5. #include <linux/timex.h>
  6. #include <asm/io.h>
  7. /* IBM Summit (EXA) Cyclone counter code*/
  8. #define CYCLONE_CBAR_ADDR 0xFEB00CD0
  9. #define CYCLONE_PMCC_OFFSET 0x51A0
  10. #define CYCLONE_MPMC_OFFSET 0x51D0
  11. #define CYCLONE_MPCS_OFFSET 0x51A8
  12. #define CYCLONE_TIMER_FREQ 100000000
  13. int use_cyclone;
  14. void __init cyclone_setup(void)
  15. {
  16. use_cyclone = 1;
  17. }
  18. struct time_interpolator cyclone_interpolator = {
  19. .source = TIME_SOURCE_MMIO64,
  20. .shift = 16,
  21. .frequency = CYCLONE_TIMER_FREQ,
  22. .drift = -100,
  23. .mask = (1LL << 40) - 1
  24. };
  25. int __init init_cyclone_clock(void)
  26. {
  27. u64* reg;
  28. u64 base; /* saved cyclone base address */
  29. u64 offset; /* offset from pageaddr to cyclone_timer register */
  30. int i;
  31. u32* volatile cyclone_timer; /* Cyclone MPMC0 register */
  32. if (!use_cyclone)
  33. return -ENODEV;
  34. printk(KERN_INFO "Summit chipset: Starting Cyclone Counter.\n");
  35. /* find base address */
  36. offset = (CYCLONE_CBAR_ADDR);
  37. reg = (u64*)ioremap_nocache(offset, sizeof(u64));
  38. if(!reg){
  39. printk(KERN_ERR "Summit chipset: Could not find valid CBAR register.\n");
  40. use_cyclone = 0;
  41. return -ENODEV;
  42. }
  43. base = readq(reg);
  44. if(!base){
  45. printk(KERN_ERR "Summit chipset: Could not find valid CBAR value.\n");
  46. use_cyclone = 0;
  47. return -ENODEV;
  48. }
  49. iounmap(reg);
  50. /* setup PMCC */
  51. offset = (base + CYCLONE_PMCC_OFFSET);
  52. reg = (u64*)ioremap_nocache(offset, sizeof(u64));
  53. if(!reg){
  54. printk(KERN_ERR "Summit chipset: Could not find valid PMCC register.\n");
  55. use_cyclone = 0;
  56. return -ENODEV;
  57. }
  58. writel(0x00000001,reg);
  59. iounmap(reg);
  60. /* setup MPCS */
  61. offset = (base + CYCLONE_MPCS_OFFSET);
  62. reg = (u64*)ioremap_nocache(offset, sizeof(u64));
  63. if(!reg){
  64. printk(KERN_ERR "Summit chipset: Could not find valid MPCS register.\n");
  65. use_cyclone = 0;
  66. return -ENODEV;
  67. }
  68. writel(0x00000001,reg);
  69. iounmap(reg);
  70. /* map in cyclone_timer */
  71. offset = (base + CYCLONE_MPMC_OFFSET);
  72. cyclone_timer = (u32*)ioremap_nocache(offset, sizeof(u32));
  73. if(!cyclone_timer){
  74. printk(KERN_ERR "Summit chipset: Could not find valid MPMC register.\n");
  75. use_cyclone = 0;
  76. return -ENODEV;
  77. }
  78. /*quick test to make sure its ticking*/
  79. for(i=0; i<3; i++){
  80. u32 old = readl(cyclone_timer);
  81. int stall = 100;
  82. while(stall--) barrier();
  83. if(readl(cyclone_timer) == old){
  84. printk(KERN_ERR "Summit chipset: Counter not counting! DISABLED\n");
  85. iounmap(cyclone_timer);
  86. cyclone_timer = 0;
  87. use_cyclone = 0;
  88. return -ENODEV;
  89. }
  90. }
  91. /* initialize last tick */
  92. cyclone_interpolator.addr = cyclone_timer;
  93. register_time_interpolator(&cyclone_interpolator);
  94. return 0;
  95. }
  96. __initcall(init_cyclone_clock);