clk-xlnx-clock-wizard.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Xilinx 'Clocking Wizard' driver
  4. *
  5. * Copyright (c) 2021 Macronix Inc.
  6. *
  7. * Author: Zhengxun Li <zhengxunli@mxic.com.tw>
  8. */
  9. #include <common.h>
  10. #include <clk-uclass.h>
  11. #include <dm.h>
  12. #include <div64.h>
  13. #include <dm/device_compat.h>
  14. #include <linux/iopoll.h>
  15. #include <linux/bitfield.h>
  16. #define SRR 0x0
  17. #define SR 0x4
  18. #define SR_LOCKED BIT(0)
  19. #define CCR(x) (0x200 + ((x) * 4))
  20. #define FBOUT_CFG CCR(0)
  21. #define FBOUT_DIV(x) (x)
  22. #define FBOUT_DIV_MASK GENMASK(7, 0)
  23. #define FBOUT_GET_DIV(x) FIELD_GET(FBOUT_DIV_MASK, x)
  24. #define FBOUT_MUL(x) ((x) << 8)
  25. #define FBOUT_MUL_MASK GENMASK(15, 8)
  26. #define FBOUT_GET_MUL(x) FIELD_GET(FBOUT_MUL_MASK, x)
  27. #define FBOUT_FRAC(x) ((x) << 16)
  28. #define FBOUT_FRAC_MASK GENMASK(25, 16)
  29. #define FBOUT_GET_FRAC(x) FIELD_GET(FBOUT_FRAC_MASK, x)
  30. #define FBOUT_FRAC_EN BIT(26)
  31. #define FBOUT_PHASE CCR(1)
  32. #define OUT_CFG(x) CCR(2 + ((x) * 3))
  33. #define OUT_DIV(x) (x)
  34. #define OUT_DIV_MASK GENMASK(7, 0)
  35. #define OUT_GET_DIV(x) FIELD_GET(OUT_DIV_MASK, x)
  36. #define OUT_FRAC(x) ((x) << 8)
  37. #define OUT_GET_MASK GENMASK(17, 8)
  38. #define OUT_GET_FRAC(x) FIELD_GET(OUT_GET_MASK, x)
  39. #define OUT_FRAC_EN BIT(18)
  40. #define OUT_PHASE(x) CCR(3 + ((x) * 3))
  41. #define OUT_DUTY(x) CCR(4 + ((x) * 3))
  42. #define CTRL CCR(23)
  43. #define CTRL_SEN BIT(2)
  44. #define CTRL_SADDR BIT(1)
  45. #define CTRL_LOAD BIT(0)
  46. /**
  47. * struct clkwzrd - Clock wizard private data structure
  48. *
  49. * @base: memory base
  50. * @vco_clk: voltage-controlled oscillator frequency
  51. *
  52. */
  53. struct clkwzd {
  54. void *base;
  55. u64 vco_clk;
  56. };
  57. struct clkwzd_plat {
  58. fdt_addr_t addr;
  59. };
  60. static int clk_wzrd_enable(struct clk *clk)
  61. {
  62. struct clkwzd *priv = dev_get_priv(clk->dev);
  63. int ret;
  64. u32 val;
  65. ret = readl_poll_sleep_timeout(priv->base + SR, val, val & SR_LOCKED,
  66. 1, 100);
  67. if (!ret) {
  68. writel(CTRL_SEN | CTRL_SADDR | CTRL_LOAD, priv->base + CTRL);
  69. writel(CTRL_SADDR, priv->base + CTRL);
  70. ret = readl_poll_sleep_timeout(priv->base + SR, val,
  71. val & SR_LOCKED, 1, 100);
  72. }
  73. return ret;
  74. }
  75. static unsigned long clk_wzrd_set_rate(struct clk *clk, ulong rate)
  76. {
  77. struct clkwzd *priv = dev_get_priv(clk->dev);
  78. u64 div;
  79. u32 cfg;
  80. /* Get output clock divide value */
  81. div = DIV_ROUND_DOWN_ULL(priv->vco_clk * 1000, rate);
  82. if (div < 1000 || div > 255999)
  83. return -EINVAL;
  84. cfg = OUT_DIV((u32)div / 1000);
  85. writel(cfg, priv->base + OUT_CFG(clk->id));
  86. return 0;
  87. }
  88. static struct clk_ops clk_wzrd_ops = {
  89. .enable = clk_wzrd_enable,
  90. .set_rate = clk_wzrd_set_rate,
  91. };
  92. static int clk_wzrd_probe(struct udevice *dev)
  93. {
  94. struct clkwzd_plat *plat = dev_get_plat(dev);
  95. struct clkwzd *priv = dev_get_priv(dev);
  96. struct clk clk_in1;
  97. u64 clock, vco_clk;
  98. u32 cfg;
  99. int ret;
  100. priv->base = (void *)plat->addr;
  101. ret = clk_get_by_name(dev, "clk_in1", &clk_in1);
  102. if (ret < 0) {
  103. dev_err(dev, "failed to get clock\n");
  104. return ret;
  105. }
  106. clock = clk_get_rate(&clk_in1);
  107. if (IS_ERR_VALUE(clock)) {
  108. dev_err(dev, "failed to get rate\n");
  109. return clock;
  110. }
  111. ret = clk_enable(&clk_in1);
  112. if (ret) {
  113. dev_err(dev, "failed to enable clock\n");
  114. clk_free(&clk_in1);
  115. return ret;
  116. }
  117. /* Read clock configuration registers */
  118. cfg = readl(priv->base + FBOUT_CFG);
  119. /* Recalculate VCO rate */
  120. if (cfg & FBOUT_FRAC_EN)
  121. vco_clk = DIV_ROUND_DOWN_ULL(clock *
  122. ((FBOUT_GET_MUL(cfg) * 1000) +
  123. FBOUT_GET_FRAC(cfg)),
  124. 1000);
  125. else
  126. vco_clk = clock * FBOUT_GET_MUL(cfg);
  127. priv->vco_clk = DIV_ROUND_DOWN_ULL(vco_clk, FBOUT_GET_DIV(cfg));
  128. return 0;
  129. }
  130. static int clk_wzrd_of_to_plat(struct udevice *dev)
  131. {
  132. struct clkwzd_plat *plat = dev_get_plat(dev);
  133. plat->addr = dev_read_addr(dev);
  134. if (plat->addr == FDT_ADDR_T_NONE)
  135. return -EINVAL;
  136. return 0;
  137. }
  138. static const struct udevice_id clk_wzrd_ids[] = {
  139. { .compatible = "xlnx,clocking-wizard" },
  140. { /* sentinel */ }
  141. };
  142. U_BOOT_DRIVER(clk_wzrd) = {
  143. .name = "zynq-clk-wizard",
  144. .id = UCLASS_CLK,
  145. .of_match = clk_wzrd_ids,
  146. .ops = &clk_wzrd_ops,
  147. .probe = clk_wzrd_probe,
  148. .of_to_plat = clk_wzrd_of_to_plat,
  149. .priv_auto = sizeof(struct clkwzd),
  150. .plat_auto = sizeof(struct clkwzd_plat),
  151. };