1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (C) 2013--2024 Intel Corporation
4 */
5
6#include <linux/bitfield.h>
7#include <linux/bits.h>
8#include <linux/delay.h>
9#include <linux/device.h>
10#include <linux/iopoll.h>
11#include <linux/math64.h>
12
13#include "ipu6-bus.h"
14#include "ipu6-isys.h"
15#include "ipu6-platform-isys-csi2-reg.h"
16
17#define IPU6_DWC_DPHY_BASE(i)			(0x238038 + 0x34 * (i))
18#define IPU6_DWC_DPHY_RSTZ			0x00
19#define IPU6_DWC_DPHY_SHUTDOWNZ			0x04
20#define IPU6_DWC_DPHY_HSFREQRANGE		0x08
21#define IPU6_DWC_DPHY_CFGCLKFREQRANGE		0x0c
22#define IPU6_DWC_DPHY_TEST_IFC_ACCESS_MODE	0x10
23#define IPU6_DWC_DPHY_TEST_IFC_REQ		0x14
24#define IPU6_DWC_DPHY_TEST_IFC_REQ_COMPLETION	0x18
25#define IPU6_DWC_DPHY_DFT_CTRL0			0x28
26#define IPU6_DWC_DPHY_DFT_CTRL1			0x2c
27#define IPU6_DWC_DPHY_DFT_CTRL2			0x30
28
29/*
30 * test IFC request definition:
31 * - req: 0 for read, 1 for write
32 * - 12 bits address
33 * - 8bits data (will ignore for read)
34 * --24----16------4-----0
35 * --|-data-|-addr-|-req-|
36 */
37#define IFC_REQ(req, addr, data) (FIELD_PREP(GENMASK(23, 16), data) | \
38				  FIELD_PREP(GENMASK(15, 4), addr) | \
39				  FIELD_PREP(GENMASK(1, 0), req))
40
41#define TEST_IFC_REQ_READ	0
42#define TEST_IFC_REQ_WRITE	1
43#define TEST_IFC_REQ_RESET	2
44
45#define TEST_IFC_ACCESS_MODE_FSM	0
46#define TEST_IFC_ACCESS_MODE_IFC_CTL	1
47
48enum phy_fsm_state {
49	PHY_FSM_STATE_POWERON = 0,
50	PHY_FSM_STATE_BGPON = 1,
51	PHY_FSM_STATE_CAL_TYPE = 2,
52	PHY_FSM_STATE_BURNIN_CAL = 3,
53	PHY_FSM_STATE_TERMCAL = 4,
54	PHY_FSM_STATE_OFFSETCAL = 5,
55	PHY_FSM_STATE_OFFSET_LANE = 6,
56	PHY_FSM_STATE_IDLE = 7,
57	PHY_FSM_STATE_ULP = 8,
58	PHY_FSM_STATE_DDLTUNNING = 9,
59	PHY_FSM_STATE_SKEW_BACKWARD = 10,
60	PHY_FSM_STATE_INVALID,
61};
62
63static void dwc_dphy_write(struct ipu6_isys *isys, u32 phy_id, u32 addr,
64			   u32 data)
65{
66	struct device *dev = &isys->adev->auxdev.dev;
67	void __iomem *isys_base = isys->pdata->base;
68	void __iomem *base = isys_base + IPU6_DWC_DPHY_BASE(phy_id);
69
70	dev_dbg(dev, "write: reg 0x%lx = data 0x%x", base + addr - isys_base,
71		data);
72	writel(data, base + addr);
73}
74
75static u32 dwc_dphy_read(struct ipu6_isys *isys, u32 phy_id, u32 addr)
76{
77	struct device *dev = &isys->adev->auxdev.dev;
78	void __iomem *isys_base = isys->pdata->base;
79	void __iomem *base = isys_base + IPU6_DWC_DPHY_BASE(phy_id);
80	u32 data;
81
82	data = readl(base + addr);
83	dev_dbg(dev, "read: reg 0x%lx = data 0x%x", base + addr - isys_base,
84		data);
85
86	return data;
87}
88
89static void dwc_dphy_write_mask(struct ipu6_isys *isys, u32 phy_id, u32 addr,
90				u32 data, u8 shift, u8 width)
91{
92	u32 temp;
93	u32 mask;
94
95	mask = (1 << width) - 1;
96	temp = dwc_dphy_read(isys, phy_id, addr);
97	temp &= ~(mask << shift);
98	temp |= (data & mask) << shift;
99	dwc_dphy_write(isys, phy_id, addr, temp);
100}
101
102static u32 __maybe_unused dwc_dphy_read_mask(struct ipu6_isys *isys, u32 phy_id,
103					     u32 addr, u8 shift,  u8 width)
104{
105	u32 val;
106
107	val = dwc_dphy_read(isys, phy_id, addr) >> shift;
108	return val & ((1 << width) - 1);
109}
110
111#define DWC_DPHY_TIMEOUT (5 * USEC_PER_SEC)
112static int dwc_dphy_ifc_read(struct ipu6_isys *isys, u32 phy_id, u32 addr,
113			     u32 *val)
114{
115	struct device *dev = &isys->adev->auxdev.dev;
116	void __iomem *isys_base = isys->pdata->base;
117	void __iomem *base = isys_base + IPU6_DWC_DPHY_BASE(phy_id);
118	void __iomem *reg;
119	u32 completion;
120	int ret;
121
122	dwc_dphy_write(isys, phy_id, IPU6_DWC_DPHY_TEST_IFC_REQ,
123		       IFC_REQ(TEST_IFC_REQ_READ, addr, 0));
124	reg = base + IPU6_DWC_DPHY_TEST_IFC_REQ_COMPLETION;
125	ret = readl_poll_timeout(reg, completion, !(completion & BIT(0)),
126				 10, DWC_DPHY_TIMEOUT);
127	if (ret) {
128		dev_err(dev, "DWC ifc request read timeout\n");
129		return ret;
130	}
131
132	*val = completion >> 8 & 0xff;
133	*val = FIELD_GET(GENMASK(15, 8), completion);
134	dev_dbg(dev, "DWC ifc read 0x%x = 0x%x", addr, *val);
135
136	return 0;
137}
138
139static int dwc_dphy_ifc_write(struct ipu6_isys *isys, u32 phy_id, u32 addr,
140			      u32 data)
141{
142	struct device *dev = &isys->adev->auxdev.dev;
143	void __iomem *isys_base = isys->pdata->base;
144	void __iomem *base = isys_base + IPU6_DWC_DPHY_BASE(phy_id);
145	void __iomem *reg;
146	u32 completion;
147	int ret;
148
149	dwc_dphy_write(isys, phy_id, IPU6_DWC_DPHY_TEST_IFC_REQ,
150		       IFC_REQ(TEST_IFC_REQ_WRITE, addr, data));
151	completion = readl(base + IPU6_DWC_DPHY_TEST_IFC_REQ_COMPLETION);
152	reg = base + IPU6_DWC_DPHY_TEST_IFC_REQ_COMPLETION;
153	ret = readl_poll_timeout(reg, completion, !(completion & BIT(0)),
154				 10, DWC_DPHY_TIMEOUT);
155	if (ret)
156		dev_err(dev, "DWC ifc request write timeout\n");
157
158	return ret;
159}
160
161static void dwc_dphy_ifc_write_mask(struct ipu6_isys *isys, u32 phy_id,
162				    u32 addr, u32 data, u8 shift, u8 width)
163{
164	u32 temp, mask;
165	int ret;
166
167	ret = dwc_dphy_ifc_read(isys, phy_id, addr, &temp);
168	if (ret)
169		return;
170
171	mask = (1 << width) - 1;
172	temp &= ~(mask << shift);
173	temp |= (data & mask) << shift;
174	dwc_dphy_ifc_write(isys, phy_id, addr, temp);
175}
176
177static u32 dwc_dphy_ifc_read_mask(struct ipu6_isys *isys, u32 phy_id, u32 addr,
178				  u8 shift, u8 width)
179{
180	int ret;
181	u32 val;
182
183	ret = dwc_dphy_ifc_read(isys, phy_id, addr, &val);
184	if (ret)
185		return 0;
186
187	return ((val >> shift) & ((1 << width) - 1));
188}
189
190static int dwc_dphy_pwr_up(struct ipu6_isys *isys, u32 phy_id)
191{
192	struct device *dev = &isys->adev->auxdev.dev;
193	u32 fsm_state;
194	int ret;
195
196	dwc_dphy_write(isys, phy_id, IPU6_DWC_DPHY_RSTZ, 1);
197	usleep_range(10, 20);
198	dwc_dphy_write(isys, phy_id, IPU6_DWC_DPHY_SHUTDOWNZ, 1);
199
200	ret = read_poll_timeout(dwc_dphy_ifc_read_mask, fsm_state,
201				(fsm_state == PHY_FSM_STATE_IDLE ||
202				 fsm_state == PHY_FSM_STATE_ULP),
203				100, DWC_DPHY_TIMEOUT, false, isys,
204				phy_id, 0x1e, 0, 4);
205
206	if (ret)
207		dev_err(dev, "Dphy %d power up failed, state 0x%x", phy_id,
208			fsm_state);
209
210	return ret;
211}
212
213struct dwc_dphy_freq_range {
214	u8 hsfreq;
215	u16 min;
216	u16 max;
217	u16 default_mbps;
218	u16 osc_freq_target;
219};
220
221#define DPHY_FREQ_RANGE_NUM		(63)
222#define DPHY_FREQ_RANGE_INVALID_INDEX	(0xff)
223static const struct dwc_dphy_freq_range freqranges[DPHY_FREQ_RANGE_NUM] = {
224	{0x00,	80,	97,	80,	335},
225	{0x10,	80,	107,	90,	335},
226	{0x20,	84,	118,	100,	335},
227	{0x30,	93,	128,	110,	335},
228	{0x01,	103,	139,	120,	335},
229	{0x11,	112,	149,	130,	335},
230	{0x21,	122,	160,	140,	335},
231	{0x31,	131,	170,	150,	335},
232	{0x02,	141,	181,	160,	335},
233	{0x12,	150,	191,	170,	335},
234	{0x22,	160,	202,	180,	335},
235	{0x32,	169,	212,	190,	335},
236	{0x03,	183,	228,	205,	335},
237	{0x13,	198,	244,	220,	335},
238	{0x23,	212,	259,	235,	335},
239	{0x33,	226,	275,	250,	335},
240	{0x04,	250,	301,	275,	335},
241	{0x14,	274,	328,	300,	335},
242	{0x25,	297,	354,	325,	335},
243	{0x35,	321,	380,	350,	335},
244	{0x05,	369,	433,	400,	335},
245	{0x16,	416,	485,	450,	335},
246	{0x26,	464,	538,	500,	335},
247	{0x37,	511,	590,	550,	335},
248	{0x07,	559,	643,	600,	335},
249	{0x18,	606,	695,	650,	335},
250	{0x28,	654,	748,	700,	335},
251	{0x39,	701,	800,	750,	335},
252	{0x09,	749,	853,	800,	335},
253	{0x19,	796,	905,	850,	335},
254	{0x29,	844,	958,	900,	335},
255	{0x3a,	891,	1010,	950,	335},
256	{0x0a,	939,	1063,	1000,	335},
257	{0x1a,	986,	1115,	1050,	335},
258	{0x2a,	1034,	1168,	1100,	335},
259	{0x3b,	1081,	1220,	1150,	335},
260	{0x0b,	1129,	1273,	1200,	335},
261	{0x1b,	1176,	1325,	1250,	335},
262	{0x2b,	1224,	1378,	1300,	335},
263	{0x3c,	1271,	1430,	1350,	335},
264	{0x0c,	1319,	1483,	1400,	335},
265	{0x1c,	1366,	1535,	1450,	335},
266	{0x2c,	1414,	1588,	1500,	335},
267	{0x3d,	1461,	1640,	1550,	208},
268	{0x0d,	1509,	1693,	1600,	214},
269	{0x1d,	1556,	1745,	1650,	221},
270	{0x2e,	1604,	1798,	1700,	228},
271	{0x3e,	1651,	1850,	1750,	234},
272	{0x0e,	1699,	1903,	1800,	241},
273	{0x1e,	1746,	1955,	1850,	248},
274	{0x2f,	1794,	2008,	1900,	255},
275	{0x3f,	1841,	2060,	1950,	261},
276	{0x0f,	1889,	2113,	2000,	268},
277	{0x40,	1936,	2165,	2050,	275},
278	{0x41,	1984,	2218,	2100,	281},
279	{0x42,	2031,	2270,	2150,	288},
280	{0x43,	2079,	2323,	2200,	294},
281	{0x44,	2126,	2375,	2250,	302},
282	{0x45,	2174,	2428,	2300,	308},
283	{0x46,	2221,	2480,	2350,	315},
284	{0x47,	2269,	2500,	2400,	321},
285	{0x48,	2316,	2500,	2450,	328},
286	{0x49,	2364,	2500,	2500,	335}
287};
288
289static u16 get_hsfreq_by_mbps(u32 mbps)
290{
291	unsigned int i = DPHY_FREQ_RANGE_NUM;
292
293	while (i--) {
294		if (freqranges[i].default_mbps == mbps ||
295		    (mbps >= freqranges[i].min && mbps <= freqranges[i].max))
296			return i;
297	}
298
299	return DPHY_FREQ_RANGE_INVALID_INDEX;
300}
301
302static int ipu6_isys_dwc_phy_config(struct ipu6_isys *isys,
303				    u32 phy_id, u32 mbps)
304{
305	struct ipu6_bus_device *adev = isys->adev;
306	struct device *dev = &adev->auxdev.dev;
307	struct ipu6_device *isp = adev->isp;
308	u32 cfg_clk_freqrange;
309	u32 osc_freq_target;
310	u32 index;
311
312	dev_dbg(dev, "config Dphy %u with %u mbps", phy_id, mbps);
313
314	index = get_hsfreq_by_mbps(mbps);
315	if (index == DPHY_FREQ_RANGE_INVALID_INDEX) {
316		dev_err(dev, "link freq not found for mbps %u", mbps);
317		return -EINVAL;
318	}
319
320	dwc_dphy_write_mask(isys, phy_id, IPU6_DWC_DPHY_HSFREQRANGE,
321			    freqranges[index].hsfreq, 0, 7);
322
323	/* Force termination Calibration */
324	if (isys->phy_termcal_val) {
325		dwc_dphy_ifc_write_mask(isys, phy_id, 0x20a, 0x1, 0, 1);
326		dwc_dphy_ifc_write_mask(isys, phy_id, 0x209, 0x3, 0, 2);
327		dwc_dphy_ifc_write_mask(isys, phy_id, 0x209,
328					isys->phy_termcal_val, 4, 4);
329	}
330
331	/*
332	 * Enable override to configure the DDL target oscillation
333	 * frequency on bit 0 of register 0xe4
334	 */
335	dwc_dphy_ifc_write_mask(isys, phy_id, 0xe4, 0x1, 0, 1);
336	/*
337	 * configure registers 0xe2, 0xe3 with the
338	 * appropriate DDL target oscillation frequency
339	 * 0x1cc(460)
340	 */
341	osc_freq_target = freqranges[index].osc_freq_target;
342	dwc_dphy_ifc_write_mask(isys, phy_id, 0xe2,
343				osc_freq_target & 0xff, 0, 8);
344	dwc_dphy_ifc_write_mask(isys, phy_id, 0xe3,
345				(osc_freq_target >> 8) & 0xf, 0, 4);
346
347	if (mbps < 1500) {
348		/* deskew_polarity_rw, for < 1.5Gbps */
349		dwc_dphy_ifc_write_mask(isys, phy_id, 0x8, 0x1, 5, 1);
350	}
351
352	/*
353	 * Set cfgclkfreqrange[5:0] = round[(Fcfg_clk(MHz)-17)*4]
354	 * (38.4 - 17) * 4 = ~85 (0x55)
355	 */
356	cfg_clk_freqrange = (isp->buttress.ref_clk - 170) * 4 / 10;
357	dev_dbg(dev, "ref_clk = %u clk_freqrange = %u",
358		isp->buttress.ref_clk, cfg_clk_freqrange);
359	dwc_dphy_write_mask(isys, phy_id, IPU6_DWC_DPHY_CFGCLKFREQRANGE,
360			    cfg_clk_freqrange, 0, 8);
361
362	dwc_dphy_write_mask(isys, phy_id, IPU6_DWC_DPHY_DFT_CTRL2, 0x1, 4, 1);
363	dwc_dphy_write_mask(isys, phy_id, IPU6_DWC_DPHY_DFT_CTRL2, 0x1, 8, 1);
364
365	return 0;
366}
367
368static void ipu6_isys_dwc_phy_aggr_setup(struct ipu6_isys *isys, u32 master,
369					 u32 slave, u32 mbps)
370{
371	/* Config mastermacro */
372	dwc_dphy_ifc_write_mask(isys, master, 0x133, 0x1, 0, 1);
373	dwc_dphy_ifc_write_mask(isys, slave, 0x133, 0x0, 0, 1);
374
375	/* Config master PHY clk lane to drive long channel clk */
376	dwc_dphy_ifc_write_mask(isys, master, 0x307, 0x1, 2, 1);
377	dwc_dphy_ifc_write_mask(isys, slave, 0x307, 0x0, 2, 1);
378
379	/* Config both PHYs data lanes to get clk from long channel */
380	dwc_dphy_ifc_write_mask(isys, master, 0x508, 0x1, 5, 1);
381	dwc_dphy_ifc_write_mask(isys, slave, 0x508, 0x1, 5, 1);
382	dwc_dphy_ifc_write_mask(isys, master, 0x708, 0x1, 5, 1);
383	dwc_dphy_ifc_write_mask(isys, slave, 0x708, 0x1, 5, 1);
384
385	/* Config slave PHY clk lane to bypass long channel clk to DDR clk */
386	dwc_dphy_ifc_write_mask(isys, master, 0x308, 0x0, 3, 1);
387	dwc_dphy_ifc_write_mask(isys, slave, 0x308, 0x1, 3, 1);
388
389	/* Override slave PHY clk lane enable (DPHYRXCLK_CLL_demux module) */
390	dwc_dphy_ifc_write_mask(isys, slave, 0xe0, 0x3, 0, 2);
391
392	/* Override slave PHY DDR clk lane enable (DPHYHSRX_div124 module) */
393	dwc_dphy_ifc_write_mask(isys, slave, 0xe1, 0x1, 1, 1);
394	dwc_dphy_ifc_write_mask(isys, slave, 0x307, 0x1, 3, 1);
395
396	/* Turn off slave PHY LP-RX clk lane */
397	dwc_dphy_ifc_write_mask(isys, slave, 0x304, 0x1, 7, 1);
398	dwc_dphy_ifc_write_mask(isys, slave, 0x305, 0xa, 0, 5);
399}
400
401#define PHY_E	4
402static int ipu6_isys_dwc_phy_powerup_ack(struct ipu6_isys *isys, u32 phy_id)
403{
404	struct device *dev = &isys->adev->auxdev.dev;
405	u32 rescal_done;
406	int ret;
407
408	ret = dwc_dphy_pwr_up(isys, phy_id);
409	if (ret != 0) {
410		dev_err(dev, "Dphy %u power up failed(%d)", phy_id, ret);
411		return ret;
412	}
413
414	/* reset forcerxmode */
415	dwc_dphy_write_mask(isys, phy_id, IPU6_DWC_DPHY_DFT_CTRL2, 0, 4, 1);
416	dwc_dphy_write_mask(isys, phy_id, IPU6_DWC_DPHY_DFT_CTRL2, 0, 8, 1);
417
418	dev_dbg(dev, "Dphy %u is ready!", phy_id);
419
420	if (phy_id != PHY_E || isys->phy_termcal_val)
421		return 0;
422
423	usleep_range(100, 200);
424	rescal_done = dwc_dphy_ifc_read_mask(isys, phy_id, 0x221, 7, 1);
425	if (rescal_done) {
426		isys->phy_termcal_val = dwc_dphy_ifc_read_mask(isys, phy_id,
427							       0x220, 2, 4);
428		dev_dbg(dev, "termcal done with value = %u",
429			isys->phy_termcal_val);
430	}
431
432	return 0;
433}
434
435static void ipu6_isys_dwc_phy_reset(struct ipu6_isys *isys, u32 phy_id)
436{
437	dev_dbg(&isys->adev->auxdev.dev, "Reset phy %u", phy_id);
438
439	dwc_dphy_write(isys, phy_id, IPU6_DWC_DPHY_SHUTDOWNZ, 0);
440	dwc_dphy_write(isys, phy_id, IPU6_DWC_DPHY_RSTZ, 0);
441	dwc_dphy_write(isys, phy_id, IPU6_DWC_DPHY_TEST_IFC_ACCESS_MODE,
442		       TEST_IFC_ACCESS_MODE_FSM);
443	dwc_dphy_write(isys, phy_id, IPU6_DWC_DPHY_TEST_IFC_REQ,
444		       TEST_IFC_REQ_RESET);
445}
446
447int ipu6_isys_dwc_phy_set_power(struct ipu6_isys *isys,
448				struct ipu6_isys_csi2_config *cfg,
449				const struct ipu6_isys_csi2_timing *timing,
450				bool on)
451{
452	struct device *dev = &isys->adev->auxdev.dev;
453	void __iomem *isys_base = isys->pdata->base;
454	u32 phy_id, primary, secondary;
455	u32 nlanes, port, mbps;
456	s64 link_freq;
457	int ret;
458
459	port = cfg->port;
460
461	if (!isys_base || port >= isys->pdata->ipdata->csi2.nports) {
462		dev_warn(dev, "invalid port ID %d\n", port);
463		return -EINVAL;
464	}
465
466	nlanes = cfg->nlanes;
467	/* only port 0, 2 and 4 support 4 lanes */
468	if (nlanes == 4 && port % 2) {
469		dev_err(dev, "invalid csi-port %u with %u lanes\n", port,
470			nlanes);
471		return -EINVAL;
472	}
473
474	link_freq = ipu6_isys_csi2_get_link_freq(&isys->csi2[port]);
475	if (link_freq < 0) {
476		dev_err(dev, "get link freq failed(%lld).\n", link_freq);
477		return link_freq;
478	}
479
480	mbps = div_u64(link_freq, 500000);
481
482	phy_id = port;
483	primary = port & ~1;
484	secondary = primary + 1;
485	if (on) {
486		if (nlanes == 4) {
487			dev_dbg(dev, "config phy %u and %u in aggr mode\n",
488				primary, secondary);
489
490			ipu6_isys_dwc_phy_reset(isys, primary);
491			ipu6_isys_dwc_phy_reset(isys, secondary);
492			ipu6_isys_dwc_phy_aggr_setup(isys, primary,
493						     secondary, mbps);
494
495			ret = ipu6_isys_dwc_phy_config(isys, primary, mbps);
496			if (ret)
497				return ret;
498			ret = ipu6_isys_dwc_phy_config(isys, secondary, mbps);
499			if (ret)
500				return ret;
501
502			ret = ipu6_isys_dwc_phy_powerup_ack(isys, primary);
503			if (ret)
504				return ret;
505
506			ret = ipu6_isys_dwc_phy_powerup_ack(isys, secondary);
507			return ret;
508		}
509
510		dev_dbg(dev, "config phy %u with %u lanes in non-aggr mode\n",
511			phy_id, nlanes);
512
513		ipu6_isys_dwc_phy_reset(isys, phy_id);
514		ret = ipu6_isys_dwc_phy_config(isys, phy_id, mbps);
515		if (ret)
516			return ret;
517
518		ret = ipu6_isys_dwc_phy_powerup_ack(isys, phy_id);
519		return ret;
520	}
521
522	if (nlanes == 4) {
523		dev_dbg(dev, "Power down phy %u and phy %u for port %u\n",
524			primary, secondary, port);
525		ipu6_isys_dwc_phy_reset(isys, secondary);
526		ipu6_isys_dwc_phy_reset(isys, primary);
527
528		return 0;
529	}
530
531	dev_dbg(dev, "Powerdown phy %u with %u lanes\n", phy_id, nlanes);
532
533	ipu6_isys_dwc_phy_reset(isys, phy_id);
534
535	return 0;
536}
537