xref: /openbmc/linux/drivers/clk/meson/meson8-ddr.c (revision 64aa7008)
164aa7008SMartin Blumenstingl // SPDX-License-Identifier: GPL-2.0+
264aa7008SMartin Blumenstingl /*
364aa7008SMartin Blumenstingl  * Amlogic Meson8 DDR clock controller
464aa7008SMartin Blumenstingl  *
564aa7008SMartin Blumenstingl  * Copyright (C) 2019 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
664aa7008SMartin Blumenstingl  */
764aa7008SMartin Blumenstingl 
864aa7008SMartin Blumenstingl #include <dt-bindings/clock/meson8-ddr-clkc.h>
964aa7008SMartin Blumenstingl 
1064aa7008SMartin Blumenstingl #include <linux/clk-provider.h>
1164aa7008SMartin Blumenstingl #include <linux/platform_device.h>
1264aa7008SMartin Blumenstingl 
1364aa7008SMartin Blumenstingl #include "clk-regmap.h"
1464aa7008SMartin Blumenstingl #include "clk-pll.h"
1564aa7008SMartin Blumenstingl 
1664aa7008SMartin Blumenstingl #define AM_DDR_PLL_CNTL			0x00
1764aa7008SMartin Blumenstingl #define AM_DDR_PLL_CNTL1		0x04
1864aa7008SMartin Blumenstingl #define AM_DDR_PLL_CNTL2		0x08
1964aa7008SMartin Blumenstingl #define AM_DDR_PLL_CNTL3		0x0c
2064aa7008SMartin Blumenstingl #define AM_DDR_PLL_CNTL4		0x10
2164aa7008SMartin Blumenstingl #define AM_DDR_PLL_STS			0x14
2264aa7008SMartin Blumenstingl #define DDR_CLK_CNTL			0x18
2364aa7008SMartin Blumenstingl #define DDR_CLK_STS			0x1c
2464aa7008SMartin Blumenstingl 
2564aa7008SMartin Blumenstingl static struct clk_regmap meson8_ddr_pll_dco = {
2664aa7008SMartin Blumenstingl 	.data = &(struct meson_clk_pll_data){
2764aa7008SMartin Blumenstingl 		.en = {
2864aa7008SMartin Blumenstingl 			.reg_off = AM_DDR_PLL_CNTL,
2964aa7008SMartin Blumenstingl 			.shift   = 30,
3064aa7008SMartin Blumenstingl 			.width   = 1,
3164aa7008SMartin Blumenstingl 		},
3264aa7008SMartin Blumenstingl 		.m = {
3364aa7008SMartin Blumenstingl 			.reg_off = AM_DDR_PLL_CNTL,
3464aa7008SMartin Blumenstingl 			.shift   = 0,
3564aa7008SMartin Blumenstingl 			.width   = 9,
3664aa7008SMartin Blumenstingl 		},
3764aa7008SMartin Blumenstingl 		.n = {
3864aa7008SMartin Blumenstingl 			.reg_off = AM_DDR_PLL_CNTL,
3964aa7008SMartin Blumenstingl 			.shift   = 9,
4064aa7008SMartin Blumenstingl 			.width   = 5,
4164aa7008SMartin Blumenstingl 		},
4264aa7008SMartin Blumenstingl 		.l = {
4364aa7008SMartin Blumenstingl 			.reg_off = AM_DDR_PLL_CNTL,
4464aa7008SMartin Blumenstingl 			.shift   = 31,
4564aa7008SMartin Blumenstingl 			.width   = 1,
4664aa7008SMartin Blumenstingl 		},
4764aa7008SMartin Blumenstingl 		.rst = {
4864aa7008SMartin Blumenstingl 			.reg_off = AM_DDR_PLL_CNTL,
4964aa7008SMartin Blumenstingl 			.shift   = 29,
5064aa7008SMartin Blumenstingl 			.width   = 1,
5164aa7008SMartin Blumenstingl 		},
5264aa7008SMartin Blumenstingl 	},
5364aa7008SMartin Blumenstingl 	.hw.init = &(struct clk_init_data){
5464aa7008SMartin Blumenstingl 		.name = "ddr_pll_dco",
5564aa7008SMartin Blumenstingl 		.ops = &meson_clk_pll_ro_ops,
5664aa7008SMartin Blumenstingl 		.parent_data = &(const struct clk_parent_data) {
5764aa7008SMartin Blumenstingl 			.fw_name = "xtal",
5864aa7008SMartin Blumenstingl 		},
5964aa7008SMartin Blumenstingl 		.num_parents = 1,
6064aa7008SMartin Blumenstingl 	},
6164aa7008SMartin Blumenstingl };
6264aa7008SMartin Blumenstingl 
6364aa7008SMartin Blumenstingl static struct clk_regmap meson8_ddr_pll = {
6464aa7008SMartin Blumenstingl 	.data = &(struct clk_regmap_div_data){
6564aa7008SMartin Blumenstingl 		.offset = AM_DDR_PLL_CNTL,
6664aa7008SMartin Blumenstingl 		.shift = 16,
6764aa7008SMartin Blumenstingl 		.width = 2,
6864aa7008SMartin Blumenstingl 		.flags = CLK_DIVIDER_POWER_OF_TWO,
6964aa7008SMartin Blumenstingl 	},
7064aa7008SMartin Blumenstingl 	.hw.init = &(struct clk_init_data){
7164aa7008SMartin Blumenstingl 		.name = "ddr_pll",
7264aa7008SMartin Blumenstingl 		.ops = &clk_regmap_divider_ro_ops,
7364aa7008SMartin Blumenstingl 		.parent_hws = (const struct clk_hw *[]) {
7464aa7008SMartin Blumenstingl 			&meson8_ddr_pll_dco.hw
7564aa7008SMartin Blumenstingl 		},
7664aa7008SMartin Blumenstingl 		.num_parents = 1,
7764aa7008SMartin Blumenstingl 	},
7864aa7008SMartin Blumenstingl };
7964aa7008SMartin Blumenstingl 
8064aa7008SMartin Blumenstingl static struct clk_hw_onecell_data meson8_ddr_clk_hw_onecell_data = {
8164aa7008SMartin Blumenstingl 	.hws = {
8264aa7008SMartin Blumenstingl 		[DDR_CLKID_DDR_PLL_DCO]		= &meson8_ddr_pll_dco.hw,
8364aa7008SMartin Blumenstingl 		[DDR_CLKID_DDR_PLL]		= &meson8_ddr_pll.hw,
8464aa7008SMartin Blumenstingl 	},
8564aa7008SMartin Blumenstingl 	.num = 2,
8664aa7008SMartin Blumenstingl };
8764aa7008SMartin Blumenstingl 
8864aa7008SMartin Blumenstingl static struct clk_regmap *const meson8_ddr_clk_regmaps[] = {
8964aa7008SMartin Blumenstingl 	&meson8_ddr_pll_dco,
9064aa7008SMartin Blumenstingl 	&meson8_ddr_pll,
9164aa7008SMartin Blumenstingl };
9264aa7008SMartin Blumenstingl 
9364aa7008SMartin Blumenstingl static const struct regmap_config meson8_ddr_clkc_regmap_config = {
9464aa7008SMartin Blumenstingl 	.reg_bits = 8,
9564aa7008SMartin Blumenstingl 	.val_bits = 32,
9664aa7008SMartin Blumenstingl 	.reg_stride = 4,
9764aa7008SMartin Blumenstingl 	.max_register = DDR_CLK_STS,
9864aa7008SMartin Blumenstingl };
9964aa7008SMartin Blumenstingl 
meson8_ddr_clkc_probe(struct platform_device * pdev)10064aa7008SMartin Blumenstingl static int meson8_ddr_clkc_probe(struct platform_device *pdev)
10164aa7008SMartin Blumenstingl {
10264aa7008SMartin Blumenstingl 	struct regmap *regmap;
10364aa7008SMartin Blumenstingl 	void __iomem *base;
10464aa7008SMartin Blumenstingl 	struct clk_hw *hw;
10564aa7008SMartin Blumenstingl 	int ret, i;
10664aa7008SMartin Blumenstingl 
10764aa7008SMartin Blumenstingl 	base = devm_platform_ioremap_resource(pdev, 0);
10864aa7008SMartin Blumenstingl 	if (IS_ERR(base))
10964aa7008SMartin Blumenstingl 		return PTR_ERR(base);
11064aa7008SMartin Blumenstingl 
11164aa7008SMartin Blumenstingl 	regmap = devm_regmap_init_mmio(&pdev->dev, base,
11264aa7008SMartin Blumenstingl 				       &meson8_ddr_clkc_regmap_config);
11364aa7008SMartin Blumenstingl 	if (IS_ERR(regmap))
11464aa7008SMartin Blumenstingl 		return PTR_ERR(regmap);
11564aa7008SMartin Blumenstingl 
11664aa7008SMartin Blumenstingl 	/* Populate regmap */
11764aa7008SMartin Blumenstingl 	for (i = 0; i < ARRAY_SIZE(meson8_ddr_clk_regmaps); i++)
11864aa7008SMartin Blumenstingl 		meson8_ddr_clk_regmaps[i]->map = regmap;
11964aa7008SMartin Blumenstingl 
12064aa7008SMartin Blumenstingl 	/* Register all clks */
12164aa7008SMartin Blumenstingl 	for (i = 0; i < meson8_ddr_clk_hw_onecell_data.num; i++) {
12264aa7008SMartin Blumenstingl 		hw = meson8_ddr_clk_hw_onecell_data.hws[i];
12364aa7008SMartin Blumenstingl 
12464aa7008SMartin Blumenstingl 		ret = devm_clk_hw_register(&pdev->dev, hw);
12564aa7008SMartin Blumenstingl 		if (ret) {
12664aa7008SMartin Blumenstingl 			dev_err(&pdev->dev, "Clock registration failed\n");
12764aa7008SMartin Blumenstingl 			return ret;
12864aa7008SMartin Blumenstingl 		}
12964aa7008SMartin Blumenstingl 	}
13064aa7008SMartin Blumenstingl 
13164aa7008SMartin Blumenstingl 	return devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_onecell_get,
13264aa7008SMartin Blumenstingl 					   &meson8_ddr_clk_hw_onecell_data);
13364aa7008SMartin Blumenstingl }
13464aa7008SMartin Blumenstingl 
13564aa7008SMartin Blumenstingl static const struct of_device_id meson8_ddr_clkc_match_table[] = {
13664aa7008SMartin Blumenstingl 	{ .compatible = "amlogic,meson8-ddr-clkc" },
13764aa7008SMartin Blumenstingl 	{ .compatible = "amlogic,meson8b-ddr-clkc" },
13864aa7008SMartin Blumenstingl 	{ /* sentinel */ }
13964aa7008SMartin Blumenstingl };
14064aa7008SMartin Blumenstingl 
14164aa7008SMartin Blumenstingl static struct platform_driver meson8_ddr_clkc_driver = {
14264aa7008SMartin Blumenstingl 	.probe		= meson8_ddr_clkc_probe,
14364aa7008SMartin Blumenstingl 	.driver		= {
14464aa7008SMartin Blumenstingl 		.name	= "meson8-ddr-clkc",
14564aa7008SMartin Blumenstingl 		.of_match_table = meson8_ddr_clkc_match_table,
14664aa7008SMartin Blumenstingl 	},
14764aa7008SMartin Blumenstingl };
14864aa7008SMartin Blumenstingl 
14964aa7008SMartin Blumenstingl builtin_platform_driver(meson8_ddr_clkc_driver);
150