312-MIPS-ralink-add-cpu-frequency-scaling.patch 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. From bd30f19a006fb52bac80c6463c49dd2f4159f4ac Mon Sep 17 00:00:00 2001
  2. From: John Crispin <[email protected]>
  3. Date: Sun, 28 Jul 2013 16:26:41 +0200
  4. Subject: [PATCH 06/53] MIPS: ralink: add cpu frequency scaling
  5. This feature will break udelay() and cause the delay loop to have longer delays
  6. when the frequency is scaled causing a performance hit.
  7. Signed-off-by: John Crispin <[email protected]>
  8. ---
  9. arch/mips/ralink/cevt-rt3352.c | 38 ++++++++++++++++++++++++++++++++++++++
  10. 1 file changed, 38 insertions(+)
  11. --- a/arch/mips/ralink/cevt-rt3352.c
  12. +++ b/arch/mips/ralink/cevt-rt3352.c
  13. @@ -29,6 +29,10 @@
  14. /* enable the counter */
  15. #define CFG_CNT_EN 0x1
  16. +/* mt7620 frequency scaling defines */
  17. +#define CLK_LUT_CFG 0x40
  18. +#define SLEEP_EN BIT(31)
  19. +
  20. struct systick_device {
  21. void __iomem *membase;
  22. struct clock_event_device dev;
  23. @@ -36,21 +40,53 @@ struct systick_device {
  24. int freq_scale;
  25. };
  26. +static void (*systick_freq_scaling)(struct systick_device *sdev, int status);
  27. +
  28. static int systick_set_oneshot(struct clock_event_device *evt);
  29. static int systick_shutdown(struct clock_event_device *evt);
  30. +static inline void mt7620_freq_scaling(struct systick_device *sdev, int status)
  31. +{
  32. + if (sdev->freq_scale == status)
  33. + return;
  34. +
  35. + sdev->freq_scale = status;
  36. +
  37. + pr_info("%s: %s autosleep mode\n", sdev->dev.name,
  38. + (status) ? ("enable") : ("disable"));
  39. + if (status)
  40. + rt_sysc_w32(rt_sysc_r32(CLK_LUT_CFG) | SLEEP_EN, CLK_LUT_CFG);
  41. + else
  42. + rt_sysc_w32(rt_sysc_r32(CLK_LUT_CFG) & ~SLEEP_EN, CLK_LUT_CFG);
  43. +}
  44. +
  45. +static inline unsigned int read_count(struct systick_device *sdev)
  46. +{
  47. + return ioread32(sdev->membase + SYSTICK_COUNT);
  48. +}
  49. +
  50. +static inline unsigned int read_compare(struct systick_device *sdev)
  51. +{
  52. + return ioread32(sdev->membase + SYSTICK_COMPARE);
  53. +}
  54. +
  55. +static inline void write_compare(struct systick_device *sdev, unsigned int val)
  56. +{
  57. + iowrite32(val, sdev->membase + SYSTICK_COMPARE);
  58. +}
  59. +
  60. static int systick_next_event(unsigned long delta,
  61. struct clock_event_device *evt)
  62. {
  63. struct systick_device *sdev;
  64. - u32 count;
  65. + int res;
  66. sdev = container_of(evt, struct systick_device, dev);
  67. - count = ioread32(sdev->membase + SYSTICK_COUNT);
  68. - count = (count + delta) % SYSTICK_FREQ;
  69. - iowrite32(count, sdev->membase + SYSTICK_COMPARE);
  70. + delta += read_count(sdev);
  71. + write_compare(sdev, delta);
  72. + res = ((int)(read_count(sdev) - delta) >= 0) ? -ETIME : 0;
  73. - return 0;
  74. + return res;
  75. }
  76. static void systick_event_handler(struct clock_event_device *dev)
  77. @@ -60,20 +96,25 @@ static void systick_event_handler(struct
  78. static irqreturn_t systick_interrupt(int irq, void *dev_id)
  79. {
  80. - struct clock_event_device *dev = (struct clock_event_device *) dev_id;
  81. + int ret = 0;
  82. + struct clock_event_device *cdev;
  83. + struct systick_device *sdev;
  84. - dev->event_handler(dev);
  85. + if (read_c0_cause() & STATUSF_IP7) {
  86. + cdev = (struct clock_event_device *) dev_id;
  87. + sdev = container_of(cdev, struct systick_device, dev);
  88. +
  89. + /* Clear Count/Compare Interrupt */
  90. + write_compare(sdev, read_compare(sdev));
  91. + cdev->event_handler(cdev);
  92. + ret = 1;
  93. + }
  94. - return IRQ_HANDLED;
  95. + return IRQ_RETVAL(ret);
  96. }
  97. static struct systick_device systick = {
  98. .dev = {
  99. - /*
  100. - * cevt-r4k uses 300, make sure systick
  101. - * gets used if available
  102. - */
  103. - .rating = 310,
  104. .features = CLOCK_EVT_FEAT_ONESHOT,
  105. .set_next_event = systick_next_event,
  106. .set_state_shutdown = systick_shutdown,
  107. @@ -91,7 +132,13 @@ static int systick_shutdown(struct clock
  108. if (sdev->irq_requested)
  109. free_irq(systick.dev.irq, &systick.dev);
  110. sdev->irq_requested = 0;
  111. - iowrite32(0, systick.membase + SYSTICK_CONFIG);
  112. + iowrite32(CFG_CNT_EN, systick.membase + SYSTICK_CONFIG);
  113. +
  114. + if (systick_freq_scaling)
  115. + systick_freq_scaling(sdev, 0);
  116. +
  117. + if (systick_freq_scaling)
  118. + systick_freq_scaling(sdev, 1);
  119. return 0;
  120. }
  121. @@ -116,33 +163,46 @@ static int systick_set_oneshot(struct cl
  122. return 0;
  123. }
  124. +static const struct of_device_id systick_match[] = {
  125. + { .compatible = "ralink,mt7620a-systick", .data = mt7620_freq_scaling},
  126. + {},
  127. +};
  128. +
  129. static int __init ralink_systick_init(struct device_node *np)
  130. {
  131. - int ret;
  132. + const struct of_device_id *match;
  133. + int rating = 200;
  134. systick.membase = of_iomap(np, 0);
  135. if (!systick.membase)
  136. return -ENXIO;
  137. - systick.dev.name = np->name;
  138. - clockevents_calc_mult_shift(&systick.dev, SYSTICK_FREQ, 60);
  139. - systick.dev.max_delta_ns = clockevent_delta2ns(0x7fff, &systick.dev);
  140. - systick.dev.max_delta_ticks = 0x7fff;
  141. - systick.dev.min_delta_ns = clockevent_delta2ns(0x3, &systick.dev);
  142. - systick.dev.min_delta_ticks = 0x3;
  143. + match = of_match_node(systick_match, np);
  144. + if (match) {
  145. + systick_freq_scaling = match->data;
  146. + /*
  147. + * cevt-r4k uses 300, make sure systick
  148. + * gets used if available
  149. + */
  150. + rating = 310;
  151. + }
  152. +
  153. + /* enable counter than register clock source */
  154. + iowrite32(CFG_CNT_EN, systick.membase + SYSTICK_CONFIG);
  155. + clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name,
  156. + SYSTICK_FREQ, rating, 16, clocksource_mmio_readl_up);
  157. +
  158. + /* register clock event */
  159. systick.dev.irq = irq_of_parse_and_map(np, 0);
  160. if (!systick.dev.irq) {
  161. pr_err("%pOFn: request_irq failed", np);
  162. return -EINVAL;
  163. }
  164. - ret = clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name,
  165. - SYSTICK_FREQ, 301, 16,
  166. - clocksource_mmio_readl_up);
  167. - if (ret)
  168. - return ret;
  169. -
  170. - clockevents_register_device(&systick.dev);
  171. + systick.dev.name = np->name;
  172. + systick.dev.rating = rating;
  173. + systick.dev.cpumask = cpumask_of(0);
  174. + clockevents_config_and_register(&systick.dev, SYSTICK_FREQ, 0x3, 0x7fff);
  175. pr_info("%pOFn: running - mult: %d, shift: %d\n",
  176. np, systick.dev.mult, systick.dev.shift);