armada-38x.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  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. 0, 0, 0, 0,
  43. 1066 * 1000 * 1000, 0, 0, 0,
  44. 1332 * 1000 * 1000, 0, 0, 0,
  45. 1600 * 1000 * 1000,
  46. };
  47. static u32 __init armada_38x_get_cpu_freq(void __iomem *sar)
  48. {
  49. u8 cpu_freq_select;
  50. cpu_freq_select = ((readl(sar) >> SAR_A380_CPU_DDR_L2_FREQ_OPT) &
  51. SAR_A380_CPU_DDR_L2_FREQ_OPT_MASK);
  52. if (cpu_freq_select >= ARRAY_SIZE(armada_38x_cpu_frequencies)) {
  53. pr_err("Selected CPU frequency (%d) unsupported\n",
  54. cpu_freq_select);
  55. return 0;
  56. }
  57. return armada_38x_cpu_frequencies[cpu_freq_select];
  58. }
  59. enum { A380_CPU_TO_DDR, A380_CPU_TO_L2 };
  60. static const struct coreclk_ratio armada_38x_coreclk_ratios[] __initconst = {
  61. { .id = A380_CPU_TO_L2, .name = "l2clk" },
  62. { .id = A380_CPU_TO_DDR, .name = "ddrclk" },
  63. };
  64. static const int armada_38x_cpu_l2_ratios[32][2] __initconst = {
  65. {0, 1}, {0, 1}, {0, 1}, {0, 1},
  66. {1, 2}, {0, 1}, {0, 1}, {0, 1},
  67. {1, 2}, {0, 1}, {0, 1}, {0, 1},
  68. {1, 2}, {0, 1}, {0, 1}, {0, 1},
  69. {0, 1}, {0, 1}, {0, 1}, {0, 1},
  70. {0, 1}, {0, 1}, {0, 1}, {0, 1},
  71. {0, 1}, {0, 1}, {0, 1}, {0, 1},
  72. {0, 1}, {0, 1}, {0, 1}, {0, 1},
  73. };
  74. static const int armada_38x_cpu_ddr_ratios[32][2] __initconst = {
  75. {0, 1}, {0, 1}, {0, 1}, {0, 1},
  76. {1, 2}, {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. {0, 1}, {0, 1}, {0, 1}, {0, 1},
  80. {0, 1}, {0, 1}, {0, 1}, {0, 1},
  81. {0, 1}, {0, 1}, {0, 1}, {0, 1},
  82. {0, 1}, {0, 1}, {0, 1}, {0, 1},
  83. };
  84. static void __init armada_38x_get_clk_ratio(
  85. void __iomem *sar, int id, int *mult, int *div)
  86. {
  87. u32 opt = ((readl(sar) >> SAR_A380_CPU_DDR_L2_FREQ_OPT) &
  88. SAR_A380_CPU_DDR_L2_FREQ_OPT_MASK);
  89. switch (id) {
  90. case A380_CPU_TO_L2:
  91. *mult = armada_38x_cpu_l2_ratios[opt][0];
  92. *div = armada_38x_cpu_l2_ratios[opt][1];
  93. break;
  94. case A380_CPU_TO_DDR:
  95. *mult = armada_38x_cpu_ddr_ratios[opt][0];
  96. *div = armada_38x_cpu_ddr_ratios[opt][1];
  97. break;
  98. }
  99. }
  100. static const struct coreclk_soc_desc armada_38x_coreclks = {
  101. .get_tclk_freq = armada_38x_get_tclk_freq,
  102. .get_cpu_freq = armada_38x_get_cpu_freq,
  103. .get_clk_ratio = armada_38x_get_clk_ratio,
  104. .ratios = armada_38x_coreclk_ratios,
  105. .num_ratios = ARRAY_SIZE(armada_38x_coreclk_ratios),
  106. };
  107. static void __init armada_38x_coreclk_init(struct device_node *np)
  108. {
  109. mvebu_coreclk_setup(np, &armada_38x_coreclks);
  110. }
  111. CLK_OF_DECLARE(armada_38x_core_clk, "marvell,armada-380-core-clock",
  112. armada_38x_coreclk_init);
  113. /*
  114. * Clock Gating Control
  115. */
  116. static const struct clk_gating_soc_desc armada_38x_gating_desc[] __initconst = {
  117. { "audio", NULL, 0 },
  118. { "ge2", NULL, 2 },
  119. { "ge1", NULL, 3 },
  120. { "ge0", NULL, 4 },
  121. { "pex1", NULL, 5 },
  122. { "pex2", NULL, 6 },
  123. { "pex3", NULL, 7 },
  124. { "pex0", NULL, 8 },
  125. { "usb3h0", NULL, 9 },
  126. { "usb3h1", NULL, 10 },
  127. { "usb3d", NULL, 11 },
  128. { "bm", NULL, 13 },
  129. { "crypto0z", NULL, 14 },
  130. { "sata0", NULL, 15 },
  131. { "crypto1z", NULL, 16 },
  132. { "sdio", NULL, 17 },
  133. { "usb2", NULL, 18 },
  134. { "crypto1", NULL, 21 },
  135. { "xor0", NULL, 22 },
  136. { "crypto0", NULL, 23 },
  137. { "tdm", NULL, 25 },
  138. { "xor1", NULL, 28 },
  139. { "sata1", NULL, 30 },
  140. { }
  141. };
  142. static void __init armada_38x_clk_gating_init(struct device_node *np)
  143. {
  144. mvebu_clk_gating_setup(np, armada_38x_gating_desc);
  145. }
  146. CLK_OF_DECLARE(armada_38x_clk_gating, "marvell,armada-380-gating-clock",
  147. armada_38x_clk_gating_init);