cyclone.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  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 <linux/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(struct clocksource *cs)
  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. .flags = CLOCK_SOURCE_IS_CONTINUOUS,
  30. };
  31. int __init init_cyclone_clock(void)
  32. {
  33. u64 __iomem *reg;
  34. u64 base; /* saved cyclone base address */
  35. u64 offset; /* offset from pageaddr to cyclone_timer register */
  36. int i;
  37. u32 __iomem *cyclone_timer; /* Cyclone MPMC0 register */
  38. if (!use_cyclone)
  39. return 0;
  40. printk(KERN_INFO "Summit chipset: Starting Cyclone Counter.\n");
  41. /* find base address */
  42. offset = (CYCLONE_CBAR_ADDR);
  43. reg = ioremap_nocache(offset, sizeof(u64));
  44. if(!reg){
  45. printk(KERN_ERR "Summit chipset: Could not find valid CBAR"
  46. " register.\n");
  47. use_cyclone = 0;
  48. return -ENODEV;
  49. }
  50. base = readq(reg);
  51. iounmap(reg);
  52. if(!base){
  53. printk(KERN_ERR "Summit chipset: Could not find valid CBAR"
  54. " value.\n");
  55. use_cyclone = 0;
  56. return -ENODEV;
  57. }
  58. /* setup PMCC */
  59. offset = (base + CYCLONE_PMCC_OFFSET);
  60. reg = ioremap_nocache(offset, sizeof(u64));
  61. if(!reg){
  62. printk(KERN_ERR "Summit chipset: Could not find valid PMCC"
  63. " register.\n");
  64. use_cyclone = 0;
  65. return -ENODEV;
  66. }
  67. writel(0x00000001,reg);
  68. iounmap(reg);
  69. /* setup MPCS */
  70. offset = (base + CYCLONE_MPCS_OFFSET);
  71. reg = ioremap_nocache(offset, sizeof(u64));
  72. if(!reg){
  73. printk(KERN_ERR "Summit chipset: Could not find valid MPCS"
  74. " register.\n");
  75. use_cyclone = 0;
  76. return -ENODEV;
  77. }
  78. writel(0x00000001,reg);
  79. iounmap(reg);
  80. /* map in cyclone_timer */
  81. offset = (base + CYCLONE_MPMC_OFFSET);
  82. cyclone_timer = ioremap_nocache(offset, sizeof(u32));
  83. if(!cyclone_timer){
  84. printk(KERN_ERR "Summit chipset: Could not find valid MPMC"
  85. " register.\n");
  86. use_cyclone = 0;
  87. return -ENODEV;
  88. }
  89. /*quick test to make sure its ticking*/
  90. for(i=0; i<3; i++){
  91. u32 old = readl(cyclone_timer);
  92. int stall = 100;
  93. while(stall--) barrier();
  94. if(readl(cyclone_timer) == old){
  95. printk(KERN_ERR "Summit chipset: Counter not counting!"
  96. " DISABLED\n");
  97. iounmap(cyclone_timer);
  98. cyclone_timer = NULL;
  99. use_cyclone = 0;
  100. return -ENODEV;
  101. }
  102. }
  103. /* initialize last tick */
  104. cyclone_mc = cyclone_timer;
  105. clocksource_cyclone.archdata.fsys_mmio = cyclone_timer;
  106. clocksource_register_hz(&clocksource_cyclone, CYCLONE_TIMER_FREQ);
  107. return 0;
  108. }
  109. __initcall(init_cyclone_clock);