1// SPDX-License-Identifier: GPL-2.0+
2/**
3 * PCIe SERDES driver for AM654x SoC
4 *
5 * Copyright (C) 2018 Texas Instruments
6 * Author: Kishon Vijay Abraham I <kishon@ti.com>
7 */
8
9#include <common.h>
10#include <clk-uclass.h>
11#include <dm.h>
12#include <log.h>
13#include <dm/device.h>
14#include <dm/device_compat.h>
15#include <dm/lists.h>
16#include <dt-bindings/phy/phy.h>
17#include <generic-phy.h>
18#include <asm/io.h>
19#include <power-domain.h>
20#include <regmap.h>
21#include <syscon.h>
22#include <linux/bitops.h>
23#include <linux/delay.h>
24#include <linux/err.h>
25
26#define CMU_R07C		0x7c
27#define CMU_MASTER_CDN_O	BIT(24)
28
29#define COMLANE_R138		0xb38
30#define CFG_VERSION_REG_MASK	GENMASK(23, 16)
31#define CFG_VERSION_REG_SHIFT 16
32#define VERSION			0x70
33
34#define COMLANE_R190		0xb90
35#define L1_MASTER_CDN_O		BIT(9)
36
37#define COMLANE_R194		0xb94
38#define CMU_OK_I_0		BIT(19)
39
40#define SERDES_CTRL		0x1fd0
41#define POR_EN			BIT(29)
42
43#define WIZ_LANEXCTL_STS	0x1fe0
44#define TX0_ENABLE_OVL		BIT(31)
45#define TX0_ENABLE_MASK		GENMASK(30, 29)
46#define TX0_ENABLE_SHIFT	29
47#define TX0_DISABLE_STATE	0x0
48#define TX0_SLEEP_STATE		0x1
49#define TX0_SNOOZE_STATE	0x2
50#define TX0_ENABLE_STATE	0x3
51#define RX0_ENABLE_OVL		BIT(15)
52#define RX0_ENABLE_MASK		GENMASK(14, 13)
53#define RX0_ENABLE_SHIFT	13
54#define RX0_DISABLE_STATE	0x0
55#define RX0_SLEEP_STATE		0x1
56#define RX0_SNOOZE_STATE	0x2
57#define RX0_ENABLE_STATE	0x3
58
59#define WIZ_PLL_CTRL		0x1ff4
60#define PLL_ENABLE_OVL		BIT(31)
61#define PLL_ENABLE_MASK		GENMASK(30, 29)
62#define PLL_ENABLE_SHIFT	29
63#define PLL_DISABLE_STATE	0x0
64#define PLL_SLEEP_STATE		0x1
65#define PLL_SNOOZE_STATE	0x2
66#define PLL_ENABLE_STATE	0x3
67#define PLL_OK			BIT(28)
68
69#define PLL_LOCK_TIME		1000	/* in milliseconds */
70#define SLEEP_TIME		100	/* in microseconds */
71
72#define LANE_USB3		0x0
73#define LANE_PCIE0_LANE0	0x1
74
75#define LANE_PCIE1_LANE0	0x0
76#define LANE_PCIE0_LANE1	0x1
77
78#define SERDES_NUM_CLOCKS	3
79
80/* SERDES control MMR bit offsets */
81#define SERDES_CTL_LANE_FUNC_SEL_SHIFT	0
82#define SERDES_CTL_LANE_FUNC_SEL_MASK	GENMASK(1, 0)
83#define SERDES_CTL_CLK_SEL_SHIFT	4
84#define SERDES_CTL_CLK_SEL_MASK		GENMASK(7, 4)
85
86/**
87 * struct serdes_am654_mux_clk_data - clock controller information structure
88 */
89struct serdes_am654_mux_clk_data {
90	struct regmap *regmap;
91	struct clk_bulk parents;
92};
93
94static int serdes_am654_mux_clk_probe(struct udevice *dev)
95{
96	struct serdes_am654_mux_clk_data *data = dev_get_priv(dev);
97	struct udevice *syscon;
98	struct regmap *regmap;
99	int ret;
100
101	debug("%s(dev=%s)\n", __func__, dev->name);
102
103	if (!data)
104		return -ENOMEM;
105
106	ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
107					   "ti,serdes-clk", &syscon);
108	if (ret) {
109		dev_err(dev, "unable to find syscon device\n");
110		return ret;
111	}
112
113	regmap = syscon_get_regmap(syscon);
114	if (IS_ERR(regmap)) {
115		dev_err(dev, "Fail to get Syscon regmap\n");
116		return PTR_ERR(regmap);
117	}
118
119	data->regmap = regmap;
120
121	ret = clk_get_bulk(dev, &data->parents);
122	if (ret) {
123		dev_err(dev, "Failed to obtain parent clocks\n");
124		return ret;
125	}
126
127	return 0;
128}
129
130static int mux_table[SERDES_NUM_CLOCKS][3] = {
131	/*
132	 * The entries represent values for selecting between
133	 * {left input, external reference clock, right input}
134	 * Only one of Left Output or Right Output should be used since
135	 * both left and right output clock uses the same bits and modifying
136	 * one clock will impact the other.
137	 */
138	{ BIT(2),               0, BIT(0) }, /* Mux of CMU refclk */
139	{     -1,          BIT(3), BIT(1) }, /* Mux of Left Output */
140	{ BIT(1), BIT(3) | BIT(1),     -1 }, /* Mux of Right Output */
141};
142
143static int serdes_am654_mux_clk_set_parent(struct clk *clk, struct clk *parent)
144{
145	struct serdes_am654_mux_clk_data *data = dev_get_priv(clk->dev);
146	u32 val;
147	int i;
148
149	debug("%s(clk=%s, parent=%s)\n", __func__, clk->dev->name,
150	      parent->dev->name);
151
152	/*
153	 * Since we have the same device-tree node represent both the
154	 * clock and serdes device, we have two devices associated with
155	 * the serdes node. assigned-clocks for this node is processed twice,
156	 * once for the clock device and another time for the serdes
157	 * device. When it is processed for the clock device, it is before
158	 * the probe for clock device has been called. We ignore this case
159	 * and rely on assigned-clocks to be processed correctly for the
160	 * serdes case.
161	 */
162	if (!data->regmap)
163		return 0;
164
165	for (i = 0; i < data->parents.count; i++) {
166		if (clk_is_match(&data->parents.clks[i], parent))
167			break;
168	}
169
170	if (i >= data->parents.count)
171		return -EINVAL;
172
173	val = mux_table[clk->id][i];
174	val <<= SERDES_CTL_CLK_SEL_SHIFT;
175
176	regmap_update_bits(data->regmap, 0, SERDES_CTL_CLK_SEL_MASK, val);
177
178	return 0;
179}
180
181static struct clk_ops serdes_am654_mux_clk_ops = {
182	.set_parent = serdes_am654_mux_clk_set_parent,
183};
184
185U_BOOT_DRIVER(serdes_am654_mux_clk) = {
186	.name = "ti-serdes-am654-mux-clk",
187	.id = UCLASS_CLK,
188	.probe = serdes_am654_mux_clk_probe,
189	.priv_auto	= sizeof(struct serdes_am654_mux_clk_data),
190	.ops = &serdes_am654_mux_clk_ops,
191};
192
193struct serdes_am654 {
194	struct regmap *regmap;
195	struct regmap *serdes_ctl;
196};
197
198static int serdes_am654_enable_pll(struct serdes_am654 *phy)
199{
200	u32 mask = PLL_ENABLE_OVL | PLL_ENABLE_MASK;
201	u32 val = PLL_ENABLE_OVL | (PLL_ENABLE_STATE << PLL_ENABLE_SHIFT);
202
203	regmap_update_bits(phy->regmap, WIZ_PLL_CTRL, mask, val);
204
205	return regmap_read_poll_timeout(phy->regmap, WIZ_PLL_CTRL, val,
206					val & PLL_OK, 1000, PLL_LOCK_TIME);
207}
208
209static void serdes_am654_disable_pll(struct serdes_am654 *phy)
210{
211	u32 mask = PLL_ENABLE_OVL | PLL_ENABLE_MASK;
212
213	regmap_update_bits(phy->regmap, WIZ_PLL_CTRL, mask, 0);
214}
215
216static int serdes_am654_enable_txrx(struct serdes_am654 *phy)
217{
218	u32 mask;
219	u32 val;
220
221	/* Enable TX */
222	mask = TX0_ENABLE_OVL | TX0_ENABLE_MASK;
223	val = TX0_ENABLE_OVL | (TX0_ENABLE_STATE << TX0_ENABLE_SHIFT);
224	regmap_update_bits(phy->regmap, WIZ_LANEXCTL_STS, mask, val);
225
226	/* Enable RX */
227	mask = RX0_ENABLE_OVL | RX0_ENABLE_MASK;
228	val = RX0_ENABLE_OVL | (RX0_ENABLE_STATE << RX0_ENABLE_SHIFT);
229	regmap_update_bits(phy->regmap, WIZ_LANEXCTL_STS, mask, val);
230
231	return 0;
232}
233
234static int serdes_am654_disable_txrx(struct serdes_am654 *phy)
235{
236	u32 mask;
237
238	/* Disable TX */
239	mask = TX0_ENABLE_OVL | TX0_ENABLE_MASK;
240	regmap_update_bits(phy->regmap, WIZ_LANEXCTL_STS, mask, 0);
241
242	/* Disable RX */
243	mask = RX0_ENABLE_OVL | RX0_ENABLE_MASK;
244	regmap_update_bits(phy->regmap, WIZ_LANEXCTL_STS, mask, 0);
245
246	return 0;
247}
248
249static int serdes_am654_power_on(struct phy *x)
250{
251	struct serdes_am654 *phy = dev_get_priv(x->dev);
252	int ret;
253	u32 val;
254
255	ret = serdes_am654_enable_pll(phy);
256	if (ret) {
257		dev_err(x->dev, "Failed to enable PLL\n");
258		return ret;
259	}
260
261	ret = serdes_am654_enable_txrx(phy);
262	if (ret) {
263		dev_err(x->dev, "Failed to enable TX RX\n");
264		return ret;
265	}
266
267	return regmap_read_poll_timeout(phy->regmap, COMLANE_R194, val,
268					val & CMU_OK_I_0, SLEEP_TIME,
269					PLL_LOCK_TIME);
270}
271
272static int serdes_am654_power_off(struct phy *x)
273{
274	struct serdes_am654 *phy = dev_get_priv(x->dev);
275
276	serdes_am654_disable_txrx(phy);
277	serdes_am654_disable_pll(phy);
278
279	return 0;
280}
281
282static int serdes_am654_init(struct phy *x)
283{
284	struct serdes_am654 *phy = dev_get_priv(x->dev);
285	u32 mask;
286	u32 val;
287
288	mask = CFG_VERSION_REG_MASK;
289	val = VERSION << CFG_VERSION_REG_SHIFT;
290	regmap_update_bits(phy->regmap, COMLANE_R138, mask, val);
291
292	val = CMU_MASTER_CDN_O;
293	regmap_update_bits(phy->regmap, CMU_R07C, val, val);
294
295	val = L1_MASTER_CDN_O;
296	regmap_update_bits(phy->regmap, COMLANE_R190, val, val);
297
298	return 0;
299}
300
301static int serdes_am654_reset(struct phy *x)
302{
303	struct serdes_am654 *phy = dev_get_priv(x->dev);
304	u32 val;
305
306	val = POR_EN;
307	regmap_update_bits(phy->regmap, SERDES_CTRL, val, val);
308	mdelay(1);
309	regmap_update_bits(phy->regmap, SERDES_CTRL, val, 0);
310
311	return 0;
312}
313
314static int serdes_am654_of_xlate(struct phy *x,
315				 struct ofnode_phandle_args *args)
316{
317	struct serdes_am654 *phy = dev_get_priv(x->dev);
318
319	if (args->args_count != 2) {
320		dev_err(x->dev, "Invalid DT PHY argument count: %d\n",
321			args->args_count);
322		return -EINVAL;
323	}
324
325	if (args->args[0] != PHY_TYPE_PCIE) {
326		dev_err(x->dev, "Unrecognized PHY type: %d\n",
327			args->args[0]);
328		return -EINVAL;
329	}
330
331	x->id = args->args[0] | (args->args[1] << 16);
332
333	/* Setup mux mode using second argument */
334	regmap_update_bits(phy->serdes_ctl, 0, SERDES_CTL_LANE_FUNC_SEL_MASK,
335			   args->args[1]);
336
337	return 0;
338}
339
340static int serdes_am654_bind(struct udevice *dev)
341{
342	int ret;
343
344	ret = device_bind_driver_to_node(dev->parent,
345					 "ti-serdes-am654-mux-clk",
346					 dev_read_name(dev), dev_ofnode(dev),
347					 NULL);
348	if (ret) {
349		dev_err(dev, "%s: not able to bind clock driver\n", __func__);
350		return ret;
351	}
352
353	return 0;
354}
355
356static int serdes_am654_probe(struct udevice *dev)
357{
358	struct serdes_am654 *phy = dev_get_priv(dev);
359	struct power_domain serdes_pwrdmn;
360	struct regmap *serdes_ctl;
361	struct regmap *map;
362	int ret;
363
364	ret = regmap_init_mem(dev_ofnode(dev), &map);
365	if (ret)
366		return ret;
367
368	phy->regmap = map;
369
370	serdes_ctl = syscon_regmap_lookup_by_phandle(dev, "ti,serdes-clk");
371	if (IS_ERR(serdes_ctl)) {
372		dev_err(dev, "unable to find syscon device\n");
373		return PTR_ERR(serdes_ctl);
374	}
375
376	phy->serdes_ctl = serdes_ctl;
377
378	ret = power_domain_get_by_index(dev, &serdes_pwrdmn, 0);
379	if (ret) {
380		dev_err(dev, "failed to get power domain\n");
381		return ret;
382	}
383
384	ret = power_domain_on(&serdes_pwrdmn);
385	if (ret) {
386		dev_err(dev, "Power domain on failed\n");
387		return ret;
388	}
389
390	return 0;
391}
392
393static const struct udevice_id serdes_am654_phy_ids[] = {
394	{
395		.compatible = "ti,phy-am654-serdes",
396	},
397};
398
399static const struct phy_ops serdes_am654_phy_ops = {
400	.reset		= serdes_am654_reset,
401	.init		= serdes_am654_init,
402	.power_on	= serdes_am654_power_on,
403	.power_off	= serdes_am654_power_off,
404	.of_xlate	= serdes_am654_of_xlate,
405};
406
407U_BOOT_DRIVER(am654_serdes_phy) = {
408	.name	= "am654_serdes_phy",
409	.id	= UCLASS_PHY,
410	.of_match = serdes_am654_phy_ids,
411	.bind = serdes_am654_bind,
412	.ops = &serdes_am654_phy_ops,
413	.probe = serdes_am654_probe,
414	.priv_auto	= sizeof(struct serdes_am654),
415};
416