clk-generated.c 4.1 KB

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