clk-uniphier-core.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /*
  2. * Copyright (C) 2016 Socionext Inc.
  3. * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
  4. *
  5. * SPDX-License-Identifier: GPL-2.0+
  6. */
  7. #include <common.h>
  8. #include <clk-uclass.h>
  9. #include <dm.h>
  10. #include <linux/bitops.h>
  11. #include <linux/io.h>
  12. #include <linux/sizes.h>
  13. #include "clk-uniphier.h"
  14. /**
  15. * struct uniphier_clk_priv - private data for UniPhier clock driver
  16. *
  17. * @base: base address of the clock provider
  18. * @data: SoC specific data
  19. */
  20. struct uniphier_clk_priv {
  21. void __iomem *base;
  22. const struct uniphier_clk_data *data;
  23. };
  24. static int uniphier_clk_enable(struct clk *clk)
  25. {
  26. struct uniphier_clk_priv *priv = dev_get_priv(clk->dev);
  27. unsigned long id = clk->id;
  28. const struct uniphier_clk_gate_data *p;
  29. for (p = priv->data->gate; p->id != UNIPHIER_CLK_ID_END; p++) {
  30. u32 val;
  31. if (p->id != id)
  32. continue;
  33. val = readl(priv->base + p->reg);
  34. val |= BIT(p->bit);
  35. writel(val, priv->base + p->reg);
  36. return 0;
  37. }
  38. dev_err(priv->dev, "clk_id=%lu was not handled\n", id);
  39. return -EINVAL;
  40. }
  41. static const struct uniphier_clk_mux_data *
  42. uniphier_clk_get_mux_data(struct uniphier_clk_priv *priv, unsigned long id)
  43. {
  44. const struct uniphier_clk_mux_data *p;
  45. for (p = priv->data->mux; p->id != UNIPHIER_CLK_ID_END; p++) {
  46. if (p->id == id)
  47. return p;
  48. }
  49. return NULL;
  50. }
  51. static ulong uniphier_clk_get_rate(struct clk *clk)
  52. {
  53. struct uniphier_clk_priv *priv = dev_get_priv(clk->dev);
  54. const struct uniphier_clk_mux_data *mux;
  55. u32 val;
  56. int i;
  57. mux = uniphier_clk_get_mux_data(priv, clk->id);
  58. if (!mux)
  59. return 0;
  60. if (!mux->nr_muxs) /* fixed-rate */
  61. return mux->rates[0];
  62. val = readl(priv->base + mux->reg);
  63. for (i = 0; i < mux->nr_muxs; i++)
  64. if ((mux->masks[i] & val) == mux->vals[i])
  65. return mux->rates[i];
  66. return -EINVAL;
  67. }
  68. static ulong uniphier_clk_set_rate(struct clk *clk, ulong rate)
  69. {
  70. struct uniphier_clk_priv *priv = dev_get_priv(clk->dev);
  71. const struct uniphier_clk_mux_data *mux;
  72. u32 val;
  73. int i, best_rate_id = -1;
  74. ulong best_rate = 0;
  75. mux = uniphier_clk_get_mux_data(priv, clk->id);
  76. if (!mux)
  77. return 0;
  78. if (!mux->nr_muxs) /* fixed-rate */
  79. return mux->rates[0];
  80. /* first, decide the best match rate */
  81. for (i = 0; i < mux->nr_muxs; i++) {
  82. if (mux->rates[i] > best_rate && mux->rates[i] <= rate) {
  83. best_rate = mux->rates[i];
  84. best_rate_id = i;
  85. }
  86. }
  87. if (best_rate_id < 0)
  88. return -EINVAL;
  89. val = readl(priv->base + mux->reg);
  90. val &= ~mux->masks[best_rate_id];
  91. val |= mux->vals[best_rate_id];
  92. writel(val, priv->base + mux->reg);
  93. debug("%s: requested rate = %lu, set rate = %lu\n", __func__,
  94. rate, best_rate);
  95. return best_rate;
  96. }
  97. const struct clk_ops uniphier_clk_ops = {
  98. .enable = uniphier_clk_enable,
  99. .get_rate = uniphier_clk_get_rate,
  100. .set_rate = uniphier_clk_set_rate,
  101. };
  102. static int uniphier_clk_probe(struct udevice *dev)
  103. {
  104. struct uniphier_clk_priv *priv = dev_get_priv(dev);
  105. fdt_addr_t addr;
  106. addr = devfdt_get_addr(dev->parent);
  107. if (addr == FDT_ADDR_T_NONE)
  108. return -EINVAL;
  109. priv->base = devm_ioremap(dev, addr, SZ_4K);
  110. if (!priv->base)
  111. return -ENOMEM;
  112. priv->data = (void *)dev_get_driver_data(dev);
  113. return 0;
  114. }
  115. static const struct udevice_id uniphier_clk_match[] = {
  116. {
  117. .compatible = "socionext,uniphier-sld3-mio-clock",
  118. .data = (ulong)&uniphier_mio_clk_data,
  119. },
  120. {
  121. .compatible = "socionext,uniphier-ld4-mio-clock",
  122. .data = (ulong)&uniphier_mio_clk_data,
  123. },
  124. {
  125. .compatible = "socionext,uniphier-pro4-mio-clock",
  126. .data = (ulong)&uniphier_mio_clk_data,
  127. },
  128. {
  129. .compatible = "socionext,uniphier-sld8-mio-clock",
  130. .data = (ulong)&uniphier_mio_clk_data,
  131. },
  132. {
  133. .compatible = "socionext,uniphier-pro5-sd-clock",
  134. .data = (ulong)&uniphier_mio_clk_data,
  135. },
  136. {
  137. .compatible = "socionext,uniphier-pxs2-sd-clock",
  138. .data = (ulong)&uniphier_mio_clk_data,
  139. },
  140. {
  141. .compatible = "socionext,uniphier-ld11-mio-clock",
  142. .data = (ulong)&uniphier_mio_clk_data,
  143. },
  144. {
  145. .compatible = "socionext,uniphier-ld20-sd-clock",
  146. .data = (ulong)&uniphier_mio_clk_data,
  147. },
  148. { /* sentinel */ }
  149. };
  150. U_BOOT_DRIVER(uniphier_clk) = {
  151. .name = "uniphier-clk",
  152. .id = UCLASS_CLK,
  153. .of_match = uniphier_clk_match,
  154. .probe = uniphier_clk_probe,
  155. .priv_auto_alloc_size = sizeof(struct uniphier_clk_priv),
  156. .ops = &uniphier_clk_ops,
  157. };