loongson2_clock.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. /*
  2. * Copyright (C) 2006 - 2008 Lemote Inc. & Insititute of Computing Technology
  3. * Author: Yanhua, yanh@lemote.com
  4. *
  5. * This file is subject to the terms and conditions of the GNU General Public
  6. * License. See the file "COPYING" in the main directory of this archive
  7. * for more details.
  8. */
  9. #include <linux/cpufreq.h>
  10. #include <linux/platform_device.h>
  11. #include <asm/clock.h>
  12. #include <loongson.h>
  13. static LIST_HEAD(clock_list);
  14. static DEFINE_SPINLOCK(clock_lock);
  15. static DEFINE_MUTEX(clock_list_sem);
  16. /* Minimum CLK support */
  17. enum {
  18. DC_ZERO, DC_25PT = 2, DC_37PT, DC_50PT, DC_62PT, DC_75PT,
  19. DC_87PT, DC_DISABLE, DC_RESV
  20. };
  21. struct cpufreq_frequency_table loongson2_clockmod_table[] = {
  22. {DC_RESV, CPUFREQ_ENTRY_INVALID},
  23. {DC_ZERO, CPUFREQ_ENTRY_INVALID},
  24. {DC_25PT, 0},
  25. {DC_37PT, 0},
  26. {DC_50PT, 0},
  27. {DC_62PT, 0},
  28. {DC_75PT, 0},
  29. {DC_87PT, 0},
  30. {DC_DISABLE, 0},
  31. {DC_RESV, CPUFREQ_TABLE_END},
  32. };
  33. EXPORT_SYMBOL_GPL(loongson2_clockmod_table);
  34. static struct clk cpu_clk = {
  35. .name = "cpu_clk",
  36. .flags = CLK_ALWAYS_ENABLED | CLK_RATE_PROPAGATES,
  37. .rate = 800000000,
  38. };
  39. struct clk *clk_get(struct device *dev, const char *id)
  40. {
  41. return &cpu_clk;
  42. }
  43. EXPORT_SYMBOL(clk_get);
  44. static void propagate_rate(struct clk *clk)
  45. {
  46. struct clk *clkp;
  47. list_for_each_entry(clkp, &clock_list, node) {
  48. if (likely(clkp->parent != clk))
  49. continue;
  50. if (likely(clkp->ops && clkp->ops->recalc))
  51. clkp->ops->recalc(clkp);
  52. if (unlikely(clkp->flags & CLK_RATE_PROPAGATES))
  53. propagate_rate(clkp);
  54. }
  55. }
  56. int clk_enable(struct clk *clk)
  57. {
  58. return 0;
  59. }
  60. EXPORT_SYMBOL(clk_enable);
  61. void clk_disable(struct clk *clk)
  62. {
  63. }
  64. EXPORT_SYMBOL(clk_disable);
  65. unsigned long clk_get_rate(struct clk *clk)
  66. {
  67. return (unsigned long)clk->rate;
  68. }
  69. EXPORT_SYMBOL(clk_get_rate);
  70. void clk_put(struct clk *clk)
  71. {
  72. }
  73. EXPORT_SYMBOL(clk_put);
  74. int clk_set_rate(struct clk *clk, unsigned long rate)
  75. {
  76. return clk_set_rate_ex(clk, rate, 0);
  77. }
  78. EXPORT_SYMBOL_GPL(clk_set_rate);
  79. int clk_set_rate_ex(struct clk *clk, unsigned long rate, int algo_id)
  80. {
  81. int ret = 0;
  82. int regval;
  83. int i;
  84. if (likely(clk->ops && clk->ops->set_rate)) {
  85. unsigned long flags;
  86. spin_lock_irqsave(&clock_lock, flags);
  87. ret = clk->ops->set_rate(clk, rate, algo_id);
  88. spin_unlock_irqrestore(&clock_lock, flags);
  89. }
  90. if (unlikely(clk->flags & CLK_RATE_PROPAGATES))
  91. propagate_rate(clk);
  92. for (i = 0; loongson2_clockmod_table[i].frequency != CPUFREQ_TABLE_END;
  93. i++) {
  94. if (loongson2_clockmod_table[i].frequency ==
  95. CPUFREQ_ENTRY_INVALID)
  96. continue;
  97. if (rate == loongson2_clockmod_table[i].frequency)
  98. break;
  99. }
  100. if (rate != loongson2_clockmod_table[i].frequency)
  101. return -ENOTSUPP;
  102. clk->rate = rate;
  103. regval = LOONGSON_CHIPCFG0;
  104. regval = (regval & ~0x7) | (loongson2_clockmod_table[i].index - 1);
  105. LOONGSON_CHIPCFG0 = regval;
  106. return ret;
  107. }
  108. EXPORT_SYMBOL_GPL(clk_set_rate_ex);
  109. long clk_round_rate(struct clk *clk, unsigned long rate)
  110. {
  111. if (likely(clk->ops && clk->ops->round_rate)) {
  112. unsigned long flags, rounded;
  113. spin_lock_irqsave(&clock_lock, flags);
  114. rounded = clk->ops->round_rate(clk, rate);
  115. spin_unlock_irqrestore(&clock_lock, flags);
  116. return rounded;
  117. }
  118. return rate;
  119. }
  120. EXPORT_SYMBOL_GPL(clk_round_rate);
  121. /*
  122. * This is the simple version of Loongson-2 wait, Maybe we need do this in
  123. * interrupt disabled content
  124. */
  125. DEFINE_SPINLOCK(loongson2_wait_lock);
  126. void loongson2_cpu_wait(void)
  127. {
  128. u32 cpu_freq;
  129. unsigned long flags;
  130. spin_lock_irqsave(&loongson2_wait_lock, flags);
  131. cpu_freq = LOONGSON_CHIPCFG0;
  132. LOONGSON_CHIPCFG0 &= ~0x7; /* Put CPU into wait mode */
  133. LOONGSON_CHIPCFG0 = cpu_freq; /* Restore CPU state */
  134. spin_unlock_irqrestore(&loongson2_wait_lock, flags);
  135. }
  136. EXPORT_SYMBOL_GPL(loongson2_cpu_wait);