cyclone.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  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 <linux/clocksource.h>
  7. #include <asm/io.h>
  8. /* IBM Summit (EXA) Cyclone counter code*/
  9. #define CYCLONE_CBAR_ADDR 0xFEB00CD0
  10. #define CYCLONE_PMCC_OFFSET 0x51A0
  11. #define CYCLONE_MPMC_OFFSET 0x51D0
  12. #define CYCLONE_MPCS_OFFSET 0x51A8
  13. #define CYCLONE_TIMER_FREQ 100000000
  14. int use_cyclone;
  15. void __init cyclone_setup(void)
  16. {
  17. use_cyclone = 1;
  18. }
  19. static void __iomem *cyclone_mc;
  20. static cycle_t read_cyclone(void)
  21. {
  22. return (cycle_t)readq((void __iomem *)cyclone_mc);
  23. }
  24. static struct clocksource clocksource_cyclone = {
  25. .name = "cyclone",
  26. .rating = 300,
  27. .read = read_cyclone,
  28. .mask = (1LL << 40) - 1,
  29. .mult = 0, /*to be caluclated*/
  30. .shift = 16,
  31. .flags = CLOCK_SOURCE_IS_CONTINUOUS,
  32. };
  33. int __init init_cyclone_clock(void)
  34. {
  35. u64 __iomem *reg;
  36. u64 base; /* saved cyclone base address */
  37. u64 offset; /* offset from pageaddr to cyclone_timer register */
  38. int i;
  39. u32 __iomem *cyclone_timer; /* Cyclone MPMC0 register */
  40. if (!use_cyclone)
  41. return 0;
  42. printk(KERN_INFO "Summit chipset: Starting Cyclone Counter.\n");
  43. /* find base address */
  44. offset = (CYCLONE_CBAR_ADDR);
  45. reg = ioremap_nocache(offset, sizeof(u64));
  46. if(!reg){
  47. printk(KERN_ERR "Summit chipset: Could not find valid CBAR"
  48. " register.\n");
  49. use_cyclone = 0;
  50. return -ENODEV;
  51. }
  52. base = readq(reg);
  53. if(!base){
  54. printk(KERN_ERR "Summit chipset: Could not find valid CBAR"
  55. " value.\n");
  56. use_cyclone = 0;
  57. return -ENODEV;
  58. }
  59. iounmap(reg);
  60. /* setup PMCC */
  61. offset = (base + CYCLONE_PMCC_OFFSET);
  62. reg = ioremap_nocache(offset, sizeof(u64));
  63. if(!reg){
  64. printk(KERN_ERR "Summit chipset: Could not find valid PMCC"
  65. " register.\n");
  66. use_cyclone = 0;
  67. return -ENODEV;
  68. }
  69. writel(0x00000001,reg);
  70. iounmap(reg);
  71. /* setup MPCS */
  72. offset = (base + CYCLONE_MPCS_OFFSET);
  73. reg = ioremap_nocache(offset, sizeof(u64));
  74. if(!reg){
  75. printk(KERN_ERR "Summit chipset: Could not find valid MPCS"
  76. " register.\n");
  77. use_cyclone = 0;
  78. return -ENODEV;
  79. }
  80. writel(0x00000001,reg);
  81. iounmap(reg);
  82. /* map in cyclone_timer */
  83. offset = (base + CYCLONE_MPMC_OFFSET);
  84. cyclone_timer = ioremap_nocache(offset, sizeof(u32));
  85. if(!cyclone_timer){
  86. printk(KERN_ERR "Summit chipset: Could not find valid MPMC"
  87. " register.\n");
  88. use_cyclone = 0;
  89. return -ENODEV;
  90. }
  91. /*quick test to make sure its ticking*/
  92. for(i=0; i<3; i++){
  93. u32 old = readl(cyclone_timer);
  94. int stall = 100;
  95. while(stall--) barrier();
  96. if(readl(cyclone_timer) == old){
  97. printk(KERN_ERR "Summit chipset: Counter not counting!"
  98. " DISABLED\n");
  99. iounmap(cyclone_timer);
  100. cyclone_timer = NULL;
  101. use_cyclone = 0;
  102. return -ENODEV;
  103. }
  104. }
  105. /* initialize last tick */
  106. cyclone_mc = cyclone_timer;
  107. clocksource_cyclone.fsys_mmio = cyclone_timer;
  108. clocksource_cyclone.mult = clocksource_hz2mult(CYCLONE_TIMER_FREQ,
  109. clocksource_cyclone.shift);
  110. clocksource_register(&clocksource_cyclone);
  111. return 0;
  112. }
  113. __initcall(init_cyclone_clock);