meson8-ddr.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Amlogic Meson8 DDR clock controller
  4. *
  5. * Copyright (C) 2019 Martin Blumenstingl <[email protected]>
  6. */
  7. #include <dt-bindings/clock/meson8-ddr-clkc.h>
  8. #include <linux/clk-provider.h>
  9. #include <linux/platform_device.h>
  10. #include "clk-regmap.h"
  11. #include "clk-pll.h"
  12. #define AM_DDR_PLL_CNTL 0x00
  13. #define AM_DDR_PLL_CNTL1 0x04
  14. #define AM_DDR_PLL_CNTL2 0x08
  15. #define AM_DDR_PLL_CNTL3 0x0c
  16. #define AM_DDR_PLL_CNTL4 0x10
  17. #define AM_DDR_PLL_STS 0x14
  18. #define DDR_CLK_CNTL 0x18
  19. #define DDR_CLK_STS 0x1c
  20. static struct clk_regmap meson8_ddr_pll_dco = {
  21. .data = &(struct meson_clk_pll_data){
  22. .en = {
  23. .reg_off = AM_DDR_PLL_CNTL,
  24. .shift = 30,
  25. .width = 1,
  26. },
  27. .m = {
  28. .reg_off = AM_DDR_PLL_CNTL,
  29. .shift = 0,
  30. .width = 9,
  31. },
  32. .n = {
  33. .reg_off = AM_DDR_PLL_CNTL,
  34. .shift = 9,
  35. .width = 5,
  36. },
  37. .l = {
  38. .reg_off = AM_DDR_PLL_CNTL,
  39. .shift = 31,
  40. .width = 1,
  41. },
  42. .rst = {
  43. .reg_off = AM_DDR_PLL_CNTL,
  44. .shift = 29,
  45. .width = 1,
  46. },
  47. },
  48. .hw.init = &(struct clk_init_data){
  49. .name = "ddr_pll_dco",
  50. .ops = &meson_clk_pll_ro_ops,
  51. .parent_data = &(const struct clk_parent_data) {
  52. .fw_name = "xtal",
  53. },
  54. .num_parents = 1,
  55. },
  56. };
  57. static struct clk_regmap meson8_ddr_pll = {
  58. .data = &(struct clk_regmap_div_data){
  59. .offset = AM_DDR_PLL_CNTL,
  60. .shift = 16,
  61. .width = 2,
  62. .flags = CLK_DIVIDER_POWER_OF_TWO,
  63. },
  64. .hw.init = &(struct clk_init_data){
  65. .name = "ddr_pll",
  66. .ops = &clk_regmap_divider_ro_ops,
  67. .parent_hws = (const struct clk_hw *[]) {
  68. &meson8_ddr_pll_dco.hw
  69. },
  70. .num_parents = 1,
  71. },
  72. };
  73. static struct clk_hw_onecell_data meson8_ddr_clk_hw_onecell_data = {
  74. .hws = {
  75. [DDR_CLKID_DDR_PLL_DCO] = &meson8_ddr_pll_dco.hw,
  76. [DDR_CLKID_DDR_PLL] = &meson8_ddr_pll.hw,
  77. },
  78. .num = 2,
  79. };
  80. static struct clk_regmap *const meson8_ddr_clk_regmaps[] = {
  81. &meson8_ddr_pll_dco,
  82. &meson8_ddr_pll,
  83. };
  84. static const struct regmap_config meson8_ddr_clkc_regmap_config = {
  85. .reg_bits = 8,
  86. .val_bits = 32,
  87. .reg_stride = 4,
  88. .max_register = DDR_CLK_STS,
  89. };
  90. static int meson8_ddr_clkc_probe(struct platform_device *pdev)
  91. {
  92. struct regmap *regmap;
  93. void __iomem *base;
  94. struct clk_hw *hw;
  95. int ret, i;
  96. base = devm_platform_ioremap_resource(pdev, 0);
  97. if (IS_ERR(base))
  98. return PTR_ERR(base);
  99. regmap = devm_regmap_init_mmio(&pdev->dev, base,
  100. &meson8_ddr_clkc_regmap_config);
  101. if (IS_ERR(regmap))
  102. return PTR_ERR(regmap);
  103. /* Populate regmap */
  104. for (i = 0; i < ARRAY_SIZE(meson8_ddr_clk_regmaps); i++)
  105. meson8_ddr_clk_regmaps[i]->map = regmap;
  106. /* Register all clks */
  107. for (i = 0; i < meson8_ddr_clk_hw_onecell_data.num; i++) {
  108. hw = meson8_ddr_clk_hw_onecell_data.hws[i];
  109. ret = devm_clk_hw_register(&pdev->dev, hw);
  110. if (ret) {
  111. dev_err(&pdev->dev, "Clock registration failed\n");
  112. return ret;
  113. }
  114. }
  115. return devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_onecell_get,
  116. &meson8_ddr_clk_hw_onecell_data);
  117. }
  118. static const struct of_device_id meson8_ddr_clkc_match_table[] = {
  119. { .compatible = "amlogic,meson8-ddr-clkc" },
  120. { .compatible = "amlogic,meson8b-ddr-clkc" },
  121. { /* sentinel */ }
  122. };
  123. static struct platform_driver meson8_ddr_clkc_driver = {
  124. .probe = meson8_ddr_clkc_probe,
  125. .driver = {
  126. .name = "meson8-ddr-clkc",
  127. .of_match_table = meson8_ddr_clkc_match_table,
  128. },
  129. };
  130. builtin_platform_driver(meson8_ddr_clkc_driver);