armada-38x.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. /*
  2. * Marvell Armada 380/385 SoC clocks
  3. *
  4. * Copyright (C) 2014 Marvell
  5. *
  6. * Gregory CLEMENT <gregory.clement@free-electrons.com>
  7. * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
  8. * Andrew Lunn <andrew@lunn.ch>
  9. *
  10. * This file is licensed under the terms of the GNU General Public
  11. * License version 2. This program is licensed "as is" without any
  12. * warranty of any kind, whether express or implied.
  13. */
  14. #include <linux/kernel.h>
  15. #include <linux/clk-provider.h>
  16. #include <linux/io.h>
  17. #include <linux/of.h>
  18. #include "common.h"
  19. /*
  20. * SAR[14:10] : Ratios between PCLK0, NBCLK, HCLK and DRAM clocks
  21. *
  22. * SAR[15] : TCLK frequency
  23. * 0 = 250 MHz
  24. * 1 = 200 MHz
  25. */
  26. #define SAR_A380_TCLK_FREQ_OPT 15
  27. #define SAR_A380_TCLK_FREQ_OPT_MASK 0x1
  28. #define SAR_A380_CPU_DDR_L2_FREQ_OPT 10
  29. #define SAR_A380_CPU_DDR_L2_FREQ_OPT_MASK 0x1F
  30. static const u32 armada_38x_tclk_frequencies[] __initconst = {
  31. 250000000,
  32. 200000000,
  33. };
  34. static u32 __init armada_38x_get_tclk_freq(void __iomem *sar)
  35. {
  36. u8 tclk_freq_select;
  37. tclk_freq_select = ((readl(sar) >> SAR_A380_TCLK_FREQ_OPT) &
  38. SAR_A380_TCLK_FREQ_OPT_MASK);
  39. return armada_38x_tclk_frequencies[tclk_freq_select];
  40. }
  41. static const u32 armada_38x_cpu_frequencies[] __initconst = {
  42. 666 * 1000 * 1000, 0, 800 * 1000 * 1000, 0,
  43. 1066 * 1000 * 1000, 0, 1200 * 1000 * 1000, 0,
  44. 1332 * 1000 * 1000, 0, 0, 0,
  45. 1600 * 1000 * 1000, 0, 0, 0,
  46. 1866 * 1000 * 1000, 0, 0, 2000 * 1000 * 1000,
  47. };
  48. static u32 __init armada_38x_get_cpu_freq(void __iomem *sar)
  49. {
  50. u8 cpu_freq_select;
  51. cpu_freq_select = ((readl(sar) >> SAR_A380_CPU_DDR_L2_FREQ_OPT) &
  52. SAR_A380_CPU_DDR_L2_FREQ_OPT_MASK);
  53. if (cpu_freq_select >= ARRAY_SIZE(armada_38x_cpu_frequencies)) {
  54. pr_err("Selected CPU frequency (%d) unsupported\n",
  55. cpu_freq_select);
  56. return 0;
  57. }
  58. return armada_38x_cpu_frequencies[cpu_freq_select];
  59. }
  60. enum { A380_CPU_TO_DDR, A380_CPU_TO_L2 };
  61. static const struct coreclk_ratio armada_38x_coreclk_ratios[] __initconst = {
  62. { .id = A380_CPU_TO_L2, .name = "l2clk" },
  63. { .id = A380_CPU_TO_DDR, .name = "ddrclk" },
  64. };
  65. static const int armada_38x_cpu_l2_ratios[32][2] __initconst = {
  66. {1, 2}, {0, 1}, {1, 2}, {0, 1},
  67. {1, 2}, {0, 1}, {1, 2}, {0, 1},
  68. {1, 2}, {0, 1}, {0, 1}, {0, 1},
  69. {1, 2}, {0, 1}, {0, 1}, {0, 1},
  70. {1, 2}, {0, 1}, {0, 1}, {1, 2},
  71. {0, 1}, {0, 1}, {0, 1}, {0, 1},
  72. {0, 1}, {0, 1}, {0, 1}, {0, 1},
  73. {0, 1}, {0, 1}, {0, 1}, {0, 1},
  74. };
  75. static const int armada_38x_cpu_ddr_ratios[32][2] __initconst = {
  76. {0, 1}, {0, 1}, {0, 1}, {0, 1},
  77. {1, 2}, {0, 1}, {0, 1}, {0, 1},
  78. {1, 2}, {0, 1}, {0, 1}, {0, 1},
  79. {1, 2}, {0, 1}, {0, 1}, {0, 1},
  80. {1, 2}, {0, 1}, {0, 1}, {7, 15},
  81. {0, 1}, {0, 1}, {0, 1}, {0, 1},
  82. {0, 1}, {0, 1}, {0, 1}, {0, 1},
  83. {0, 1}, {0, 1}, {0, 1}, {0, 1},
  84. };
  85. static void __init armada_38x_get_clk_ratio(
  86. void __iomem *sar, int id, int *mult, int *div)
  87. {
  88. u32 opt = ((readl(sar) >> SAR_A380_CPU_DDR_L2_FREQ_OPT) &
  89. SAR_A380_CPU_DDR_L2_FREQ_OPT_MASK);
  90. switch (id) {
  91. case A380_CPU_TO_L2:
  92. *mult = armada_38x_cpu_l2_ratios[opt][0];
  93. *div = armada_38x_cpu_l2_ratios[opt][1];
  94. break;
  95. case A380_CPU_TO_DDR:
  96. *mult = armada_38x_cpu_ddr_ratios[opt][0];
  97. *div = armada_38x_cpu_ddr_ratios[opt][1];
  98. break;
  99. }
  100. }
  101. static const struct coreclk_soc_desc armada_38x_coreclks = {
  102. .get_tclk_freq = armada_38x_get_tclk_freq,
  103. .get_cpu_freq = armada_38x_get_cpu_freq,
  104. .get_clk_ratio = armada_38x_get_clk_ratio,
  105. .ratios = armada_38x_coreclk_ratios,
  106. .num_ratios = ARRAY_SIZE(armada_38x_coreclk_ratios),
  107. };
  108. static void __init armada_38x_coreclk_init(struct device_node *np)
  109. {
  110. mvebu_coreclk_setup(np, &armada_38x_coreclks);
  111. }
  112. CLK_OF_DECLARE(armada_38x_core_clk, "marvell,armada-380-core-clock",
  113. armada_38x_coreclk_init);
  114. /*
  115. * Clock Gating Control
  116. */
  117. static const struct clk_gating_soc_desc armada_38x_gating_desc[] __initconst = {
  118. { "audio", NULL, 0 },
  119. { "ge2", NULL, 2 },
  120. { "ge1", NULL, 3 },
  121. { "ge0", NULL, 4 },
  122. { "pex1", NULL, 5 },
  123. { "pex2", NULL, 6 },
  124. { "pex3", NULL, 7 },
  125. { "pex0", NULL, 8 },
  126. { "usb3h0", NULL, 9 },
  127. { "usb3h1", NULL, 10 },
  128. { "usb3d", NULL, 11 },
  129. { "bm", NULL, 13 },
  130. { "crypto0z", NULL, 14 },
  131. { "sata0", NULL, 15 },
  132. { "crypto1z", NULL, 16 },
  133. { "sdio", NULL, 17 },
  134. { "usb2", NULL, 18 },
  135. { "crypto1", NULL, 21 },
  136. { "xor0", NULL, 22 },
  137. { "crypto0", NULL, 23 },
  138. { "tdm", NULL, 25 },
  139. { "xor1", NULL, 28 },
  140. { "sata1", NULL, 30 },
  141. { }
  142. };
  143. static void __init armada_38x_clk_gating_init(struct device_node *np)
  144. {
  145. mvebu_clk_gating_setup(np, armada_38x_gating_desc);
  146. }
  147. CLK_OF_DECLARE(armada_38x_clk_gating, "marvell,armada-380-gating-clock",
  148. armada_38x_clk_gating_init);