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