xref: /OK3568_Linux_fs/kernel/drivers/clk/baikal-t1/clk-ccu-pll.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (C) 2020 BAIKAL ELECTRONICS, JSC
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Authors:
6*4882a593Smuzhiyun  *   Serge Semin <Sergey.Semin@baikalelectronics.ru>
7*4882a593Smuzhiyun  *   Dmitry Dunaev <dmitry.dunaev@baikalelectronics.ru>
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * Baikal-T1 CCU PLL clocks driver
10*4882a593Smuzhiyun  */
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #define pr_fmt(fmt) "bt1-ccu-pll: " fmt
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun #include <linux/kernel.h>
15*4882a593Smuzhiyun #include <linux/printk.h>
16*4882a593Smuzhiyun #include <linux/slab.h>
17*4882a593Smuzhiyun #include <linux/clk-provider.h>
18*4882a593Smuzhiyun #include <linux/mfd/syscon.h>
19*4882a593Smuzhiyun #include <linux/of.h>
20*4882a593Smuzhiyun #include <linux/of_address.h>
21*4882a593Smuzhiyun #include <linux/ioport.h>
22*4882a593Smuzhiyun #include <linux/regmap.h>
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun #include <dt-bindings/clock/bt1-ccu.h>
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun #include "ccu-pll.h"
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun #define CCU_CPU_PLL_BASE		0x000
29*4882a593Smuzhiyun #define CCU_SATA_PLL_BASE		0x008
30*4882a593Smuzhiyun #define CCU_DDR_PLL_BASE		0x010
31*4882a593Smuzhiyun #define CCU_PCIE_PLL_BASE		0x018
32*4882a593Smuzhiyun #define CCU_ETH_PLL_BASE		0x020
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun #define CCU_PLL_INFO(_id, _name, _pname, _base, _flags)	\
35*4882a593Smuzhiyun 	{						\
36*4882a593Smuzhiyun 		.id = _id,				\
37*4882a593Smuzhiyun 		.name = _name,				\
38*4882a593Smuzhiyun 		.parent_name = _pname,			\
39*4882a593Smuzhiyun 		.base = _base,				\
40*4882a593Smuzhiyun 		.flags = _flags				\
41*4882a593Smuzhiyun 	}
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun #define CCU_PLL_NUM			ARRAY_SIZE(pll_info)
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun struct ccu_pll_info {
46*4882a593Smuzhiyun 	unsigned int id;
47*4882a593Smuzhiyun 	const char *name;
48*4882a593Smuzhiyun 	const char *parent_name;
49*4882a593Smuzhiyun 	unsigned int base;
50*4882a593Smuzhiyun 	unsigned long flags;
51*4882a593Smuzhiyun };
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun /*
54*4882a593Smuzhiyun  * Alas we have to mark all PLLs as critical. CPU and DDR PLLs are sources of
55*4882a593Smuzhiyun  * CPU cores and DDR controller reference clocks, due to which they obviously
56*4882a593Smuzhiyun  * shouldn't be ever gated. SATA and PCIe PLLs are the parents of APB-bus and
57*4882a593Smuzhiyun  * DDR controller AXI-bus clocks. If they are gated the system will be
58*4882a593Smuzhiyun  * unusable. Moreover disabling SATA and Ethernet PLLs causes automatic reset
59*4882a593Smuzhiyun  * of the corresponding subsystems. So until we aren't ready to re-initialize
60*4882a593Smuzhiyun  * all the devices consuming those PLLs, they will be marked as critical too.
61*4882a593Smuzhiyun  */
62*4882a593Smuzhiyun static const struct ccu_pll_info pll_info[] = {
63*4882a593Smuzhiyun 	CCU_PLL_INFO(CCU_CPU_PLL, "cpu_pll", "ref_clk", CCU_CPU_PLL_BASE,
64*4882a593Smuzhiyun 		     CLK_IS_CRITICAL),
65*4882a593Smuzhiyun 	CCU_PLL_INFO(CCU_SATA_PLL, "sata_pll", "ref_clk", CCU_SATA_PLL_BASE,
66*4882a593Smuzhiyun 		     CLK_IS_CRITICAL | CLK_SET_RATE_GATE),
67*4882a593Smuzhiyun 	CCU_PLL_INFO(CCU_DDR_PLL, "ddr_pll", "ref_clk", CCU_DDR_PLL_BASE,
68*4882a593Smuzhiyun 		     CLK_IS_CRITICAL | CLK_SET_RATE_GATE),
69*4882a593Smuzhiyun 	CCU_PLL_INFO(CCU_PCIE_PLL, "pcie_pll", "ref_clk", CCU_PCIE_PLL_BASE,
70*4882a593Smuzhiyun 		     CLK_IS_CRITICAL),
71*4882a593Smuzhiyun 	CCU_PLL_INFO(CCU_ETH_PLL, "eth_pll", "ref_clk", CCU_ETH_PLL_BASE,
72*4882a593Smuzhiyun 		     CLK_IS_CRITICAL | CLK_SET_RATE_GATE)
73*4882a593Smuzhiyun };
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun struct ccu_pll_data {
76*4882a593Smuzhiyun 	struct device_node *np;
77*4882a593Smuzhiyun 	struct regmap *sys_regs;
78*4882a593Smuzhiyun 	struct ccu_pll *plls[CCU_PLL_NUM];
79*4882a593Smuzhiyun };
80*4882a593Smuzhiyun 
ccu_pll_find_desc(struct ccu_pll_data * data,unsigned int clk_id)81*4882a593Smuzhiyun static struct ccu_pll *ccu_pll_find_desc(struct ccu_pll_data *data,
82*4882a593Smuzhiyun 					 unsigned int clk_id)
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun 	struct ccu_pll *pll;
85*4882a593Smuzhiyun 	int idx;
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	for (idx = 0; idx < CCU_PLL_NUM; ++idx) {
88*4882a593Smuzhiyun 		pll = data->plls[idx];
89*4882a593Smuzhiyun 		if (pll && pll->id == clk_id)
90*4882a593Smuzhiyun 			return pll;
91*4882a593Smuzhiyun 	}
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	return ERR_PTR(-EINVAL);
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun 
ccu_pll_create_data(struct device_node * np)96*4882a593Smuzhiyun static struct ccu_pll_data *ccu_pll_create_data(struct device_node *np)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun 	struct ccu_pll_data *data;
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	data = kzalloc(sizeof(*data), GFP_KERNEL);
101*4882a593Smuzhiyun 	if (!data)
102*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 	data->np = np;
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun 	return data;
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun 
ccu_pll_free_data(struct ccu_pll_data * data)109*4882a593Smuzhiyun static void ccu_pll_free_data(struct ccu_pll_data *data)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun 	kfree(data);
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun 
ccu_pll_find_sys_regs(struct ccu_pll_data * data)114*4882a593Smuzhiyun static int ccu_pll_find_sys_regs(struct ccu_pll_data *data)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun 	data->sys_regs = syscon_node_to_regmap(data->np->parent);
117*4882a593Smuzhiyun 	if (IS_ERR(data->sys_regs)) {
118*4882a593Smuzhiyun 		pr_err("Failed to find syscon regs for '%s'\n",
119*4882a593Smuzhiyun 			of_node_full_name(data->np));
120*4882a593Smuzhiyun 		return PTR_ERR(data->sys_regs);
121*4882a593Smuzhiyun 	}
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	return 0;
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun 
ccu_pll_of_clk_hw_get(struct of_phandle_args * clkspec,void * priv)126*4882a593Smuzhiyun static struct clk_hw *ccu_pll_of_clk_hw_get(struct of_phandle_args *clkspec,
127*4882a593Smuzhiyun 					    void *priv)
128*4882a593Smuzhiyun {
129*4882a593Smuzhiyun 	struct ccu_pll_data *data = priv;
130*4882a593Smuzhiyun 	struct ccu_pll *pll;
131*4882a593Smuzhiyun 	unsigned int clk_id;
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	clk_id = clkspec->args[0];
134*4882a593Smuzhiyun 	pll = ccu_pll_find_desc(data, clk_id);
135*4882a593Smuzhiyun 	if (IS_ERR(pll)) {
136*4882a593Smuzhiyun 		pr_info("Invalid PLL clock ID %d specified\n", clk_id);
137*4882a593Smuzhiyun 		return ERR_CAST(pll);
138*4882a593Smuzhiyun 	}
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	return ccu_pll_get_clk_hw(pll);
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun 
ccu_pll_clk_register(struct ccu_pll_data * data)143*4882a593Smuzhiyun static int ccu_pll_clk_register(struct ccu_pll_data *data)
144*4882a593Smuzhiyun {
145*4882a593Smuzhiyun 	int idx, ret;
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	for (idx = 0; idx < CCU_PLL_NUM; ++idx) {
148*4882a593Smuzhiyun 		const struct ccu_pll_info *info = &pll_info[idx];
149*4882a593Smuzhiyun 		struct ccu_pll_init_data init = {0};
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 		init.id = info->id;
152*4882a593Smuzhiyun 		init.name = info->name;
153*4882a593Smuzhiyun 		init.parent_name = info->parent_name;
154*4882a593Smuzhiyun 		init.base = info->base;
155*4882a593Smuzhiyun 		init.sys_regs = data->sys_regs;
156*4882a593Smuzhiyun 		init.np = data->np;
157*4882a593Smuzhiyun 		init.flags = info->flags;
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 		data->plls[idx] = ccu_pll_hw_register(&init);
160*4882a593Smuzhiyun 		if (IS_ERR(data->plls[idx])) {
161*4882a593Smuzhiyun 			ret = PTR_ERR(data->plls[idx]);
162*4882a593Smuzhiyun 			pr_err("Couldn't register PLL hw '%s'\n",
163*4882a593Smuzhiyun 				init.name);
164*4882a593Smuzhiyun 			goto err_hw_unregister;
165*4882a593Smuzhiyun 		}
166*4882a593Smuzhiyun 	}
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 	ret = of_clk_add_hw_provider(data->np, ccu_pll_of_clk_hw_get, data);
169*4882a593Smuzhiyun 	if (ret) {
170*4882a593Smuzhiyun 		pr_err("Couldn't register PLL provider of '%s'\n",
171*4882a593Smuzhiyun 			of_node_full_name(data->np));
172*4882a593Smuzhiyun 		goto err_hw_unregister;
173*4882a593Smuzhiyun 	}
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	return 0;
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun err_hw_unregister:
178*4882a593Smuzhiyun 	for (--idx; idx >= 0; --idx)
179*4882a593Smuzhiyun 		ccu_pll_hw_unregister(data->plls[idx]);
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	return ret;
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun 
ccu_pll_init(struct device_node * np)184*4882a593Smuzhiyun static __init void ccu_pll_init(struct device_node *np)
185*4882a593Smuzhiyun {
186*4882a593Smuzhiyun 	struct ccu_pll_data *data;
187*4882a593Smuzhiyun 	int ret;
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 	data = ccu_pll_create_data(np);
190*4882a593Smuzhiyun 	if (IS_ERR(data))
191*4882a593Smuzhiyun 		return;
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	ret = ccu_pll_find_sys_regs(data);
194*4882a593Smuzhiyun 	if (ret)
195*4882a593Smuzhiyun 		goto err_free_data;
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	ret = ccu_pll_clk_register(data);
198*4882a593Smuzhiyun 	if (ret)
199*4882a593Smuzhiyun 		goto err_free_data;
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	return;
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun err_free_data:
204*4882a593Smuzhiyun 	ccu_pll_free_data(data);
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun CLK_OF_DECLARE(ccu_pll, "baikal,bt1-ccu-pll", ccu_pll_init);
207