sparc-us3-cpufreq.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. /* us3_cpufreq.c: UltraSPARC-III cpu frequency support
  2. *
  3. * Copyright (C) 2003 David S. Miller (davem@redhat.com)
  4. *
  5. * Many thanks to Dominik Brodowski for fixing up the cpufreq
  6. * infrastructure in order to make this driver easier to implement.
  7. */
  8. #include <linux/kernel.h>
  9. #include <linux/module.h>
  10. #include <linux/sched.h>
  11. #include <linux/smp.h>
  12. #include <linux/cpufreq.h>
  13. #include <linux/threads.h>
  14. #include <linux/slab.h>
  15. #include <linux/init.h>
  16. #include <asm/head.h>
  17. #include <asm/timer.h>
  18. static struct cpufreq_driver *cpufreq_us3_driver;
  19. struct us3_freq_percpu_info {
  20. struct cpufreq_frequency_table table[4];
  21. };
  22. /* Indexed by cpu number. */
  23. static struct us3_freq_percpu_info *us3_freq_table;
  24. /* UltraSPARC-III has three dividers: 1, 2, and 32. These are controlled
  25. * in the Safari config register.
  26. */
  27. #define SAFARI_CFG_DIV_1 0x0000000000000000UL
  28. #define SAFARI_CFG_DIV_2 0x0000000040000000UL
  29. #define SAFARI_CFG_DIV_32 0x0000000080000000UL
  30. #define SAFARI_CFG_DIV_MASK 0x00000000C0000000UL
  31. static void read_safari_cfg(void *arg)
  32. {
  33. unsigned long ret, *val = arg;
  34. __asm__ __volatile__("ldxa [%%g0] %1, %0"
  35. : "=&r" (ret)
  36. : "i" (ASI_SAFARI_CONFIG));
  37. *val = ret;
  38. }
  39. static void update_safari_cfg(void *arg)
  40. {
  41. unsigned long reg, *new_bits = arg;
  42. read_safari_cfg(&reg);
  43. reg &= ~SAFARI_CFG_DIV_MASK;
  44. reg |= *new_bits;
  45. __asm__ __volatile__("stxa %0, [%%g0] %1\n\t"
  46. "membar #Sync"
  47. : /* no outputs */
  48. : "r" (reg), "i" (ASI_SAFARI_CONFIG)
  49. : "memory");
  50. }
  51. static unsigned long get_current_freq(unsigned int cpu, unsigned long safari_cfg)
  52. {
  53. unsigned long clock_tick = sparc64_get_clock_tick(cpu) / 1000;
  54. unsigned long ret;
  55. switch (safari_cfg & SAFARI_CFG_DIV_MASK) {
  56. case SAFARI_CFG_DIV_1:
  57. ret = clock_tick / 1;
  58. break;
  59. case SAFARI_CFG_DIV_2:
  60. ret = clock_tick / 2;
  61. break;
  62. case SAFARI_CFG_DIV_32:
  63. ret = clock_tick / 32;
  64. break;
  65. default:
  66. BUG();
  67. }
  68. return ret;
  69. }
  70. static unsigned int us3_freq_get(unsigned int cpu)
  71. {
  72. unsigned long reg;
  73. if (smp_call_function_single(cpu, read_safari_cfg, &reg, 1))
  74. return 0;
  75. return get_current_freq(cpu, reg);
  76. }
  77. static int us3_freq_target(struct cpufreq_policy *policy, unsigned int index)
  78. {
  79. unsigned int cpu = policy->cpu;
  80. unsigned long new_bits, new_freq;
  81. new_freq = sparc64_get_clock_tick(cpu) / 1000;
  82. switch (index) {
  83. case 0:
  84. new_bits = SAFARI_CFG_DIV_1;
  85. new_freq /= 1;
  86. break;
  87. case 1:
  88. new_bits = SAFARI_CFG_DIV_2;
  89. new_freq /= 2;
  90. break;
  91. case 2:
  92. new_bits = SAFARI_CFG_DIV_32;
  93. new_freq /= 32;
  94. break;
  95. default:
  96. BUG();
  97. }
  98. return smp_call_function_single(cpu, update_safari_cfg, &new_bits, 1);
  99. }
  100. static int __init us3_freq_cpu_init(struct cpufreq_policy *policy)
  101. {
  102. unsigned int cpu = policy->cpu;
  103. unsigned long clock_tick = sparc64_get_clock_tick(cpu) / 1000;
  104. struct cpufreq_frequency_table *table =
  105. &us3_freq_table[cpu].table[0];
  106. table[0].driver_data = 0;
  107. table[0].frequency = clock_tick / 1;
  108. table[1].driver_data = 1;
  109. table[1].frequency = clock_tick / 2;
  110. table[2].driver_data = 2;
  111. table[2].frequency = clock_tick / 32;
  112. table[3].driver_data = 0;
  113. table[3].frequency = CPUFREQ_TABLE_END;
  114. policy->cpuinfo.transition_latency = 0;
  115. policy->cur = clock_tick;
  116. return cpufreq_table_validate_and_show(policy, table);
  117. }
  118. static int us3_freq_cpu_exit(struct cpufreq_policy *policy)
  119. {
  120. if (cpufreq_us3_driver)
  121. us3_freq_target(policy, 0);
  122. return 0;
  123. }
  124. static int __init us3_freq_init(void)
  125. {
  126. unsigned long manuf, impl, ver;
  127. int ret;
  128. if (tlb_type != cheetah && tlb_type != cheetah_plus)
  129. return -ENODEV;
  130. __asm__("rdpr %%ver, %0" : "=r" (ver));
  131. manuf = ((ver >> 48) & 0xffff);
  132. impl = ((ver >> 32) & 0xffff);
  133. if (manuf == CHEETAH_MANUF &&
  134. (impl == CHEETAH_IMPL ||
  135. impl == CHEETAH_PLUS_IMPL ||
  136. impl == JAGUAR_IMPL ||
  137. impl == PANTHER_IMPL)) {
  138. struct cpufreq_driver *driver;
  139. ret = -ENOMEM;
  140. driver = kzalloc(sizeof(*driver), GFP_KERNEL);
  141. if (!driver)
  142. goto err_out;
  143. us3_freq_table = kzalloc((NR_CPUS * sizeof(*us3_freq_table)),
  144. GFP_KERNEL);
  145. if (!us3_freq_table)
  146. goto err_out;
  147. driver->init = us3_freq_cpu_init;
  148. driver->verify = cpufreq_generic_frequency_table_verify;
  149. driver->target_index = us3_freq_target;
  150. driver->get = us3_freq_get;
  151. driver->exit = us3_freq_cpu_exit;
  152. strcpy(driver->name, "UltraSPARC-III");
  153. cpufreq_us3_driver = driver;
  154. ret = cpufreq_register_driver(driver);
  155. if (ret)
  156. goto err_out;
  157. return 0;
  158. err_out:
  159. if (driver) {
  160. kfree(driver);
  161. cpufreq_us3_driver = NULL;
  162. }
  163. kfree(us3_freq_table);
  164. us3_freq_table = NULL;
  165. return ret;
  166. }
  167. return -ENODEV;
  168. }
  169. static void __exit us3_freq_exit(void)
  170. {
  171. if (cpufreq_us3_driver) {
  172. cpufreq_unregister_driver(cpufreq_us3_driver);
  173. kfree(cpufreq_us3_driver);
  174. cpufreq_us3_driver = NULL;
  175. kfree(us3_freq_table);
  176. us3_freq_table = NULL;
  177. }
  178. }
  179. MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
  180. MODULE_DESCRIPTION("cpufreq driver for UltraSPARC-III");
  181. MODULE_LICENSE("GPL");
  182. module_init(us3_freq_init);
  183. module_exit(us3_freq_exit);