clk-generated.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (C) 2016 Atmel Corporation
  4. * Wenyou.Yang <wenyou.yang@atmel.com>
  5. */
  6. #include <common.h>
  7. #include <clk-uclass.h>
  8. #include <dm.h>
  9. #include <log.h>
  10. #include <malloc.h>
  11. #include <linux/err.h>
  12. #include <linux/io.h>
  13. #include <mach/at91_pmc.h>
  14. #include "pmc.h"
  15. DECLARE_GLOBAL_DATA_PTR;
  16. #define GENERATED_SOURCE_MAX 6
  17. #define GENERATED_MAX_DIV 255
  18. /**
  19. * generated_clk_bind() - for the generated clock driver
  20. * Recursively bind its children as clk devices.
  21. *
  22. * @return: 0 on success, or negative error code on failure
  23. */
  24. static int generated_clk_bind(struct udevice *dev)
  25. {
  26. return at91_clk_sub_device_bind(dev, "generic-clk");
  27. }
  28. static const struct udevice_id generated_clk_match[] = {
  29. { .compatible = "atmel,sama5d2-clk-generated" },
  30. {}
  31. };
  32. U_BOOT_DRIVER(generated_clk) = {
  33. .name = "generated-clk",
  34. .id = UCLASS_MISC,
  35. .of_match = generated_clk_match,
  36. .bind = generated_clk_bind,
  37. };
  38. /*-------------------------------------------------------------*/
  39. struct generic_clk_priv {
  40. u32 num_parents;
  41. };
  42. static ulong generic_clk_get_rate(struct clk *clk)
  43. {
  44. struct pmc_platdata *plat = dev_get_platdata(clk->dev);
  45. struct at91_pmc *pmc = plat->reg_base;
  46. struct clk parent;
  47. ulong clk_rate;
  48. u32 tmp, gckdiv;
  49. u8 clock_source, parent_index;
  50. int ret;
  51. writel(clk->id & AT91_PMC_PCR_PID_MASK, &pmc->pcr);
  52. tmp = readl(&pmc->pcr);
  53. clock_source = (tmp >> AT91_PMC_PCR_GCKCSS_OFFSET) &
  54. AT91_PMC_PCR_GCKCSS_MASK;
  55. gckdiv = (tmp >> AT91_PMC_PCR_GCKDIV_OFFSET) & AT91_PMC_PCR_GCKDIV_MASK;
  56. parent_index = clock_source - 1;
  57. ret = clk_get_by_index(dev_get_parent(clk->dev), parent_index, &parent);
  58. if (ret)
  59. return 0;
  60. clk_rate = clk_get_rate(&parent) / (gckdiv + 1);
  61. clk_free(&parent);
  62. return clk_rate;
  63. }
  64. static ulong generic_clk_set_rate(struct clk *clk, ulong rate)
  65. {
  66. struct pmc_platdata *plat = dev_get_platdata(clk->dev);
  67. struct at91_pmc *pmc = plat->reg_base;
  68. struct generic_clk_priv *priv = dev_get_priv(clk->dev);
  69. struct clk parent, best_parent;
  70. ulong tmp_rate, best_rate = rate, parent_rate;
  71. int tmp_diff, best_diff = -1;
  72. u32 div, best_div = 0;
  73. u8 best_parent_index, best_clock_source = 0;
  74. u8 i;
  75. u32 tmp;
  76. int ret;
  77. for (i = 0; i < priv->num_parents; i++) {
  78. ret = clk_get_by_index(dev_get_parent(clk->dev), i, &parent);
  79. if (ret)
  80. return ret;
  81. parent_rate = clk_get_rate(&parent);
  82. if (IS_ERR_VALUE(parent_rate))
  83. return parent_rate;
  84. for (div = 1; div < GENERATED_MAX_DIV + 2; div++) {
  85. tmp_rate = DIV_ROUND_CLOSEST(parent_rate, div);
  86. tmp_diff = abs(rate - tmp_rate);
  87. if (best_diff < 0 || best_diff > tmp_diff) {
  88. best_rate = tmp_rate;
  89. best_diff = tmp_diff;
  90. best_div = div - 1;
  91. best_parent = parent;
  92. best_parent_index = i;
  93. best_clock_source = best_parent_index + 1;
  94. }
  95. if (!best_diff || tmp_rate < rate)
  96. break;
  97. }
  98. if (!best_diff)
  99. break;
  100. }
  101. debug("GCK: best parent: %s, best_rate = %ld, best_div = %d\n",
  102. best_parent.dev->name, best_rate, best_div);
  103. ret = clk_enable(&best_parent);
  104. if (ret)
  105. return ret;
  106. writel(clk->id & AT91_PMC_PCR_PID_MASK, &pmc->pcr);
  107. tmp = readl(&pmc->pcr);
  108. tmp &= ~(AT91_PMC_PCR_GCKDIV | AT91_PMC_PCR_GCKCSS);
  109. tmp |= AT91_PMC_PCR_GCKCSS_(best_clock_source) |
  110. AT91_PMC_PCR_CMD_WRITE |
  111. AT91_PMC_PCR_GCKDIV_(best_div) |
  112. AT91_PMC_PCR_GCKEN;
  113. writel(tmp, &pmc->pcr);
  114. while (!(readl(&pmc->sr) & AT91_PMC_GCKRDY))
  115. ;
  116. return 0;
  117. }
  118. static struct clk_ops generic_clk_ops = {
  119. .of_xlate = at91_clk_of_xlate,
  120. .get_rate = generic_clk_get_rate,
  121. .set_rate = generic_clk_set_rate,
  122. };
  123. static int generic_clk_ofdata_to_platdata(struct udevice *dev)
  124. {
  125. struct generic_clk_priv *priv = dev_get_priv(dev);
  126. u32 cells[GENERATED_SOURCE_MAX];
  127. u32 num_parents;
  128. num_parents = fdtdec_get_int_array_count(gd->fdt_blob,
  129. dev_of_offset(dev_get_parent(dev)), "clocks", cells,
  130. GENERATED_SOURCE_MAX);
  131. if (!num_parents)
  132. return -1;
  133. priv->num_parents = num_parents;
  134. return 0;
  135. }
  136. U_BOOT_DRIVER(generic_clk) = {
  137. .name = "generic-clk",
  138. .id = UCLASS_CLK,
  139. .probe = at91_clk_probe,
  140. .ofdata_to_platdata = generic_clk_ofdata_to_platdata,
  141. .priv_auto_alloc_size = sizeof(struct generic_clk_priv),
  142. .platdata_auto_alloc_size = sizeof(struct pmc_platdata),
  143. .ops = &generic_clk_ops,
  144. };