cyclone.c 3.0 KB

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