File Index
Files and directories
Sign in
FILE

ipu7-isys-csi-phy.c

File preview with syntax highlighting.

linux-6.19.14/drivers/staging/media/ipu7/ipu7-isys-csi-phy.c C
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2013 - 2025 Intel Corporation
   4 */
   5
   6#include <linux/bitmap.h>
   7#include <linux/bug.h>
   8#include <linux/delay.h>
   9#include <linux/device.h>
  10#include <linux/iopoll.h>
  11#include <linux/kernel.h>
  12#include <linux/types.h>
  13
  14#include <media/mipi-csi2.h>
  15#include <media/v4l2-device.h>
  16
  17#include "ipu7.h"
  18#include "ipu7-bus.h"
  19#include "ipu7-buttress.h"
  20#include "ipu7-isys.h"
  21#include "ipu7-isys-csi2.h"
  22#include "ipu7-isys-csi2-regs.h"
  23#include "ipu7-platform-regs.h"
  24#include "ipu7-isys-csi-phy.h"
  25
  26#define PORT_A		0U
  27#define PORT_B		1U
  28#define PORT_C		2U
  29#define PORT_D		3U
  30
  31#define N_DATA_IDS	8U
  32static DECLARE_BITMAP(data_ids, N_DATA_IDS);
  33
  34struct ddlcal_counter_ref_s {
  35	u16 min_mbps;
  36	u16 max_mbps;
  37
  38	u16 ddlcal_counter_ref;
  39};
  40
  41struct ddlcal_params {
  42	u16 min_mbps;
  43	u16 max_mbps;
  44	u16 oa_lanex_hsrx_cdphy_sel_fast;
  45	u16 ddlcal_max_phase;
  46	u16 phase_bound;
  47	u16 ddlcal_dll_fbk;
  48	u16 ddlcal_ddl_coarse_bank;
  49	u16 fjump_deskew;
  50	u16 min_eye_opening_deskew;
  51};
  52
  53struct i_thssettle_params {
  54	u16 min_mbps;
  55	u16 max_mbps;
  56	u16 i_thssettle;
  57};
  58
  59 /* lane2 for 4l3t, lane1 for 2l2t */
  60struct oa_lane_clk_div_params {
  61	u16 min_mbps;
  62	u16 max_mbps;
  63	u16 oa_lane_hsrx_hs_clk_div;
  64};
  65
  66struct cdr_fbk_cap_prog_params {
  67	u16 min_mbps;
  68	u16 max_mbps;
  69	u16 val;
  70};
  71
  72static const struct ddlcal_counter_ref_s table0[] = {
  73	{ 1500, 1999, 118 },
  74	{ 2000, 2499, 157 },
  75	{ 2500, 3499, 196 },
  76	{ 3500, 4499, 274 },
  77	{ 4500, 4500, 352 },
  78	{ }
  79};
  80
  81static const struct ddlcal_params table1[] = {
  82	{ 1500, 1587, 0, 143, 167, 17, 3, 4, 29 },
  83	{ 1588, 1687, 0, 135, 167, 15, 3, 4, 27 },
  84	{ 1688, 1799, 0, 127, 135, 15, 2, 4, 26 },
  85	{ 1800, 1928, 0, 119, 135, 13, 2, 3, 24 },
  86	{ 1929, 2076, 0, 111, 135, 13, 2, 3, 23 },
  87	{ 2077, 2249, 0, 103, 135, 11, 2, 3, 21 },
  88	{ 2250, 2454, 0, 95, 103, 11, 1, 3, 19 },
  89	{ 2455, 2699, 0, 87, 103, 9, 1, 3, 18 },
  90	{ 2700, 2999, 0, 79, 103, 9, 1, 2, 16 },
  91	{ 3000, 3229, 0, 71, 71, 7, 1, 2, 15 },
  92	{ 3230, 3599, 1, 87, 103, 9, 1, 3, 18 },
  93	{ 3600, 3999, 1, 79, 103, 9, 1, 2, 16 },
  94	{ 4000, 4499, 1, 71, 103, 7, 1, 2, 15 },
  95	{ 4500, 4500, 1, 63, 71, 7, 0, 2, 13 },
  96	{ }
  97};
  98
  99static const struct i_thssettle_params table2[] = {
 100	{ 80, 124, 24 },
 101	{ 125, 249, 20 },
 102	{ 250, 499, 16 },
 103	{ 500, 749, 14 },
 104	{ 750, 1499, 13 },
 105	{ 1500, 4500, 12 },
 106	{ }
 107};
 108
 109static const struct oa_lane_clk_div_params table6[] = {
 110	{ 80, 159, 0x1 },
 111	{ 160, 319, 0x2 },
 112	{ 320, 639, 0x3 },
 113	{ 640, 1279, 0x4 },
 114	{ 1280, 2560, 0x5 },
 115	{ 2561, 4500, 0x6 },
 116	{ }
 117};
 118
 119static const struct cdr_fbk_cap_prog_params table7[] = {
 120	{ 80, 919, 0 },
 121	{ 920, 1029, 1 },
 122	{ 1030, 1169, 2 },
 123	{ 1170, 1349, 3 },
 124	{ 1350, 1589, 4 },
 125	{ 1590, 1949, 5 },
 126	{ 1950, 2499, 6 },
 127	{ 2500, 3500, 7 },
 128	{ }
 129};
 130
 131static void dwc_phy_write(struct ipu7_isys *isys, u32 id, u32 addr, u16 data)
 132{
 133	void __iomem *isys_base = isys->pdata->base;
 134	void __iomem *base = isys_base + IS_IO_CDPHY_BASE(id);
 135
 136	dev_dbg(&isys->adev->auxdev.dev, "phy write: reg 0x%zx = data 0x%04x",
 137		base + addr - isys_base, data);
 138	writew(data, base + addr);
 139}
 140
 141static u16 dwc_phy_read(struct ipu7_isys *isys, u32 id, u32 addr)
 142{
 143	void __iomem *isys_base = isys->pdata->base;
 144	void __iomem *base = isys_base + IS_IO_CDPHY_BASE(id);
 145	u16 data;
 146
 147	data = readw(base + addr);
 148	dev_dbg(&isys->adev->auxdev.dev, "phy read: reg 0x%zx = data 0x%04x",
 149		base + addr - isys_base, data);
 150
 151	return data;
 152}
 153
 154static void dwc_csi_write(struct ipu7_isys *isys, u32 id, u32 addr, u32 data)
 155{
 156	void __iomem *isys_base = isys->pdata->base;
 157	void __iomem *base = isys_base + IS_IO_CSI2_HOST_BASE(id);
 158	struct device *dev = &isys->adev->auxdev.dev;
 159
 160	dev_dbg(dev, "csi write: reg 0x%zx = data 0x%08x",
 161		base + addr - isys_base, data);
 162	writel(data, base + addr);
 163	dev_dbg(dev, "csi read: reg 0x%zx = data 0x%08x",
 164		base + addr - isys_base, readl(base + addr));
 165}
 166
 167static void gpreg_write(struct ipu7_isys *isys, u32 id, u32 addr, u32 data)
 168{
 169	void __iomem *isys_base = isys->pdata->base;
 170	u32 gpreg = isys->pdata->ipdata->csi2.gpreg;
 171	void __iomem *base = isys_base + gpreg + 0x1000 * id;
 172	struct device *dev = &isys->adev->auxdev.dev;
 173
 174	dev_dbg(dev, "gpreg write: reg 0x%zx = data 0x%08x",
 175		base + addr - isys_base, data);
 176	writel(data, base + addr);
 177	dev_dbg(dev, "gpreg read: reg 0x%zx = data 0x%08x",
 178		base + addr - isys_base, readl(base + addr));
 179}
 180
 181static u32 dwc_csi_read(struct ipu7_isys *isys, u32 id, u32 addr)
 182{
 183	void __iomem *isys_base = isys->pdata->base;
 184	void __iomem *base = isys_base + IS_IO_CSI2_HOST_BASE(id);
 185	u32 data;
 186
 187	data = readl(base + addr);
 188	dev_dbg(&isys->adev->auxdev.dev, "csi read: reg 0x%zx = data 0x%x",
 189		base + addr - isys_base, data);
 190
 191	return data;
 192}
 193
 194static void dwc_phy_write_mask(struct ipu7_isys *isys, u32 id, u32 addr,
 195			       u16 val, u8 lo, u8 hi)
 196{
 197	u32 temp, mask;
 198
 199	WARN_ON(lo > hi);
 200	WARN_ON(hi > 15);
 201
 202	mask = ((~0U - (1U << lo) + 1U)) & (~0U >> (31 - hi));
 203	temp = dwc_phy_read(isys, id, addr);
 204	temp &= ~mask;
 205	temp |= (val << lo) & mask;
 206	dwc_phy_write(isys, id, addr, temp);
 207}
 208
 209static void dwc_csi_write_mask(struct ipu7_isys *isys, u32 id, u32 addr,
 210			       u32 val, u8 hi, u8 lo)
 211{
 212	u32 temp, mask;
 213
 214	WARN_ON(lo > hi);
 215
 216	mask = ((~0U - (1U << lo) + 1U)) & (~0U >> (31 - hi));
 217	temp = dwc_csi_read(isys, id, addr);
 218	temp &= ~mask;
 219	temp |= (val << lo) & mask;
 220	dwc_csi_write(isys, id, addr, temp);
 221}
 222
 223static void ipu7_isys_csi_ctrl_cfg(struct ipu7_isys_csi2 *csi2)
 224{
 225	struct ipu7_isys *isys = csi2->isys;
 226	struct device *dev = &isys->adev->auxdev.dev;
 227	u32 id, lanes, phy_mode;
 228	u32 val;
 229
 230	id = csi2->port;
 231	lanes = csi2->nlanes;
 232	phy_mode = csi2->phy_mode;
 233	dev_dbg(dev, "csi-%d controller init with %u lanes, phy mode %u",
 234		id, lanes, phy_mode);
 235
 236	val = dwc_csi_read(isys, id, VERSION);
 237	dev_dbg(dev, "csi-%d controller version = 0x%x", id, val);
 238
 239	/* num of active data lanes */
 240	dwc_csi_write(isys, id, N_LANES, lanes - 1);
 241	dwc_csi_write(isys, id, CDPHY_MODE, phy_mode);
 242	dwc_csi_write(isys, id, VC_EXTENSION, 0);
 243
 244	/* only mask PHY_FATAL and PKT_FATAL interrupts */
 245	dwc_csi_write(isys, id, INT_MSK_PHY_FATAL, 0xff);
 246	dwc_csi_write(isys, id, INT_MSK_PKT_FATAL, 0x3);
 247	dwc_csi_write(isys, id, INT_MSK_PHY, 0x0);
 248	dwc_csi_write(isys, id, INT_MSK_LINE, 0x0);
 249	dwc_csi_write(isys, id, INT_MSK_BNDRY_FRAME_FATAL, 0x0);
 250	dwc_csi_write(isys, id, INT_MSK_SEQ_FRAME_FATAL, 0x0);
 251	dwc_csi_write(isys, id, INT_MSK_CRC_FRAME_FATAL, 0x0);
 252	dwc_csi_write(isys, id, INT_MSK_PLD_CRC_FATAL, 0x0);
 253	dwc_csi_write(isys, id, INT_MSK_DATA_ID, 0x0);
 254	dwc_csi_write(isys, id, INT_MSK_ECC_CORRECTED, 0x0);
 255}
 256
 257static void ipu7_isys_csi_phy_reset(struct ipu7_isys *isys, u32 id)
 258{
 259	dwc_csi_write(isys, id, PHY_SHUTDOWNZ, 0);
 260	dwc_csi_write(isys, id, DPHY_RSTZ, 0);
 261	dwc_csi_write(isys, id, CSI2_RESETN, 0);
 262	gpreg_write(isys, id, PHY_RESET, 0);
 263	gpreg_write(isys, id, PHY_SHUTDOWN, 0);
 264}
 265
 266/* 8 Data ID monitors, each Data ID is composed by pair of VC and data type */
 267static int __dids_config(struct ipu7_isys_csi2 *csi2, u32 id, u8 vc, u8 dt)
 268{
 269	struct ipu7_isys *isys = csi2->isys;
 270	u32 reg, n;
 271	u8 lo, hi;
 272	int ret;
 273
 274	dev_dbg(&isys->adev->auxdev.dev, "config CSI-%u with vc:%u dt:0x%02x\n",
 275		id, vc, dt);
 276
 277	dwc_csi_write(isys, id, VC_EXTENSION, 0x0);
 278	n = find_first_zero_bit(data_ids, N_DATA_IDS);
 279	if (n == N_DATA_IDS)
 280		return -ENOSPC;
 281
 282	ret = test_and_set_bit(n, data_ids);
 283	if (ret)
 284		return -EBUSY;
 285
 286	reg = n < 4 ? DATA_IDS_VC_1 : DATA_IDS_VC_2;
 287	lo = (n % 4) * 8;
 288	hi = lo + 4;
 289	dwc_csi_write_mask(isys, id, reg, vc & GENMASK(4, 0), hi, lo);
 290
 291	reg = n < 4 ? DATA_IDS_1 : DATA_IDS_2;
 292	lo = (n % 4) * 8;
 293	hi = lo + 5;
 294	dwc_csi_write_mask(isys, id, reg, dt & GENMASK(5, 0), hi, lo);
 295
 296	return 0;
 297}
 298
 299static int ipu7_isys_csi_ctrl_dids_config(struct ipu7_isys_csi2 *csi2, u32 id)
 300{
 301	struct v4l2_mbus_frame_desc_entry *desc_entry = NULL;
 302	struct device *dev = &csi2->isys->adev->auxdev.dev;
 303	struct v4l2_mbus_frame_desc desc;
 304	struct v4l2_subdev *ext_sd;
 305	struct media_pad *pad;
 306	unsigned int i;
 307	int ret;
 308
 309	pad = media_entity_remote_source_pad_unique(&csi2->asd.sd.entity);
 310	if (IS_ERR(pad)) {
 311		dev_warn(dev, "can't get remote source pad of %s (%pe)\n",
 312			 csi2->asd.sd.name, pad);
 313		return PTR_ERR(pad);
 314	}
 315
 316	ext_sd = media_entity_to_v4l2_subdev(pad->entity);
 317	if (WARN(!ext_sd, "Failed to get subdev for entity %s\n",
 318		 pad->entity->name))
 319		return -ENODEV;
 320
 321	ret = v4l2_subdev_call(ext_sd, pad, get_frame_desc, pad->index, &desc);
 322	if (ret)
 323		return ret;
 324
 325	if (desc.type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) {
 326		dev_warn(dev, "Unsupported frame descriptor type\n");
 327		return -EINVAL;
 328	}
 329
 330	for (i = 0; i < desc.num_entries; i++) {
 331		desc_entry = &desc.entry[i];
 332		if (desc_entry->bus.csi2.vc < IPU7_NR_OF_CSI2_VC) {
 333			ret = __dids_config(csi2, id, desc_entry->bus.csi2.vc,
 334					    desc_entry->bus.csi2.dt);
 335			if (ret)
 336				return ret;
 337		}
 338	}
 339
 340	return 0;
 341}
 342
 343#define CDPHY_TIMEOUT 5000000U
 344static int ipu7_isys_phy_ready(struct ipu7_isys *isys, u32 id)
 345{
 346	void __iomem *isys_base = isys->pdata->base;
 347	u32 gpreg_offset = isys->pdata->ipdata->csi2.gpreg;
 348	void __iomem *gpreg = isys_base + gpreg_offset + 0x1000 * id;
 349	struct device *dev = &isys->adev->auxdev.dev;
 350	unsigned int i;
 351	u32 phy_ready;
 352	u32 reg, rext;
 353	int ret;
 354
 355	dev_dbg(dev, "waiting phy ready...\n");
 356	ret = readl_poll_timeout(gpreg + PHY_READY, phy_ready,
 357				 phy_ready & BIT(0) && phy_ready != ~0U,
 358				 100, CDPHY_TIMEOUT);
 359	dev_dbg(dev, "phy %u ready = 0x%08x\n", id, readl(gpreg + PHY_READY));
 360	dev_dbg(dev, "csi %u PHY_RX = 0x%08x\n", id,
 361		dwc_csi_read(isys, id, PHY_RX));
 362	dev_dbg(dev, "csi %u PHY_STOPSTATE = 0x%08x\n", id,
 363		dwc_csi_read(isys, id, PHY_STOPSTATE));
 364	dev_dbg(dev, "csi %u PHY_CAL = 0x%08x\n", id,
 365		dwc_csi_read(isys, id, PHY_CAL));
 366	for (i = 0; i < 4U; i++) {
 367		reg = CORE_DIG_DLANE_0_R_HS_RX_0 + (i * 0x400U);
 368		dev_dbg(dev, "phy %u DLANE%u skewcal = 0x%04x\n",
 369			id, i, dwc_phy_read(isys, id, reg));
 370	}
 371	dev_dbg(dev, "phy %u DDLCAL = 0x%04x\n", id,
 372		dwc_phy_read(isys, id, PPI_CALIBCTRL_R_COMMON_CALIBCTRL_2_5));
 373	dev_dbg(dev, "phy %u TERMCAL = 0x%04x\n", id,
 374		dwc_phy_read(isys, id, PPI_R_TERMCAL_DEBUG_0));
 375	dev_dbg(dev, "phy %u LPDCOCAL = 0x%04x\n", id,
 376		dwc_phy_read(isys, id, PPI_R_LPDCOCAL_DEBUG_RB));
 377	dev_dbg(dev, "phy %u HSDCOCAL = 0x%04x\n", id,
 378		dwc_phy_read(isys, id, PPI_R_HSDCOCAL_DEBUG_RB));
 379	dev_dbg(dev, "phy %u LPDCOCAL_VT = 0x%04x\n", id,
 380		dwc_phy_read(isys, id, PPI_R_LPDCOCAL_DEBUG_VT));
 381
 382	if (!ret) {
 383		if (id) {
 384			dev_dbg(dev, "ignore phy %u rext\n", id);
 385			return 0;
 386		}
 387
 388		rext = dwc_phy_read(isys, id,
 389				    CORE_DIG_IOCTRL_R_AFE_CB_CTRL_2_15) & 0xfU;
 390		dev_dbg(dev, "phy %u rext value = %u\n", id, rext);
 391		isys->phy_rext_cal = (rext ? rext : 5);
 392
 393		return 0;
 394	}
 395
 396	dev_err(dev, "wait phy ready timeout!\n");
 397
 398	return ret;
 399}
 400
 401static int lookup_table1(u64 mbps)
 402{
 403	unsigned int i;
 404
 405	for (i = 0; i < ARRAY_SIZE(table1); i++) {
 406		if (mbps >= table1[i].min_mbps && mbps <= table1[i].max_mbps)
 407			return i;
 408	}
 409
 410	return -ENXIO;
 411}
 412
 413static const u16 deskew_fine_mem[] = {
 414	0x0404, 0x040c, 0x0414, 0x041c,
 415	0x0423, 0x0429, 0x0430, 0x043a,
 416	0x0445, 0x044a, 0x0450, 0x045a,
 417	0x0465, 0x0469, 0x0472, 0x047a,
 418	0x0485, 0x0489, 0x0490, 0x049a,
 419	0x04a4, 0x04ac, 0x04b4, 0x04bc,
 420	0x04c4, 0x04cc, 0x04d4, 0x04dc,
 421	0x04e4, 0x04ec, 0x04f4, 0x04fc,
 422	0x0504, 0x050c, 0x0514, 0x051c,
 423	0x0523, 0x0529, 0x0530, 0x053a,
 424	0x0545, 0x054a, 0x0550, 0x055a,
 425	0x0565, 0x0569, 0x0572, 0x057a,
 426	0x0585, 0x0589, 0x0590, 0x059a,
 427	0x05a4, 0x05ac, 0x05b4, 0x05bc,
 428	0x05c4, 0x05cc, 0x05d4, 0x05dc,
 429	0x05e4, 0x05ec, 0x05f4, 0x05fc,
 430	0x0604, 0x060c, 0x0614, 0x061c,
 431	0x0623, 0x0629, 0x0632, 0x063a,
 432	0x0645, 0x064a, 0x0650, 0x065a,
 433	0x0665, 0x0669, 0x0672, 0x067a,
 434	0x0685, 0x0689, 0x0690, 0x069a,
 435	0x06a4, 0x06ac, 0x06b4, 0x06bc,
 436	0x06c4, 0x06cc, 0x06d4, 0x06dc,
 437	0x06e4, 0x06ec, 0x06f4, 0x06fc,
 438	0x0704, 0x070c, 0x0714, 0x071c,
 439	0x0723, 0x072a, 0x0730, 0x073a,
 440	0x0745, 0x074a, 0x0750, 0x075a,
 441	0x0765, 0x0769, 0x0772, 0x077a,
 442	0x0785, 0x0789, 0x0790, 0x079a,
 443	0x07a4, 0x07ac, 0x07b4, 0x07bc,
 444	0x07c4, 0x07cc, 0x07d4, 0x07dc,
 445	0x07e4, 0x07ec, 0x07f4, 0x07fc,
 446};
 447
 448static void ipu7_isys_dphy_config(struct ipu7_isys *isys, u8 id, u8 lanes,
 449				  bool aggregation, u64 mbps)
 450{
 451	u16 hsrxval0 = 0;
 452	u16 hsrxval1 = 0;
 453	u16 hsrxval2 = 0;
 454	int index;
 455	u16 reg;
 456	u16 val;
 457	u32 i;
 458
 459	dwc_phy_write_mask(isys, id, CORE_DIG_RW_COMMON_7, 0, 0, 9);
 460	if (mbps > 1500)
 461		dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_7,
 462				   40, 0, 7);
 463	else
 464		dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_7,
 465				   104, 0, 7);
 466
 467	dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_8, 80, 0, 7);
 468	dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_0, 191, 0, 9);
 469	dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_7, 34, 7, 12);
 470	dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_1, 38, 8, 15);
 471	dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_2, 4, 12, 15);
 472	dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_2, 2, 10, 11);
 473	dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_2, 1, 8, 8);
 474	dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_2, 38, 0, 7);
 475	dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_2, 1, 9, 9);
 476	dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_4, 10, 0, 9);
 477	dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_6, 20, 0, 9);
 478	dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_7, 19, 0, 6);
 479
 480	for (i = 0; i < ARRAY_SIZE(table0); i++) {
 481		if (mbps >= table0[i].min_mbps && mbps <= table0[i].max_mbps) {
 482			dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_3,
 483					   table0[i].ddlcal_counter_ref,
 484					   0, 9);
 485			break;
 486		}
 487	}
 488
 489	index = lookup_table1(mbps);
 490	if (index >= 0) {
 491		dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_1,
 492				   table1[index].phase_bound, 0, 7);
 493		dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_5,
 494				   table1[index].ddlcal_dll_fbk, 4, 9);
 495		dwc_phy_write_mask(isys, id, PPI_RW_DDLCAL_CFG_5,
 496				   table1[index].ddlcal_ddl_coarse_bank, 0, 3);
 497
 498		reg = CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_8;
 499		val = table1[index].oa_lanex_hsrx_cdphy_sel_fast;
 500		for (i = 0; i < lanes + 1; i++)
 501			dwc_phy_write_mask(isys, id, reg + (i * 0x400), val,
 502					   12, 12);
 503	}
 504
 505	reg = CORE_DIG_DLANE_0_RW_LP_0;
 506	for (i = 0; i < lanes; i++)
 507		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 6, 8, 11);
 508
 509	dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_2,
 510			   0, 0, 0);
 511	if (!is_ipu7(isys->adev->isp->hw_ver) ||
 512	    id == PORT_B || id == PORT_C) {
 513		dwc_phy_write_mask(isys, id,
 514				   CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_2,
 515				   1, 0, 0);
 516		dwc_phy_write_mask(isys, id,
 517				   CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_2,
 518				   0, 0, 0);
 519	} else {
 520		dwc_phy_write_mask(isys, id,
 521				   CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_2,
 522				   0, 0, 0);
 523		dwc_phy_write_mask(isys, id,
 524				   CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_2,
 525				   1, 0, 0);
 526	}
 527
 528	if (lanes == 4 && is_ipu7(isys->adev->isp->hw_ver)) {
 529		dwc_phy_write_mask(isys, id,
 530				   CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_2,
 531				   0, 0, 0);
 532		dwc_phy_write_mask(isys, id,
 533				   CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_2,
 534				   0, 0, 0);
 535	}
 536
 537	dwc_phy_write_mask(isys, id, CORE_DIG_RW_COMMON_6, 1, 0, 2);
 538	dwc_phy_write_mask(isys, id, CORE_DIG_RW_COMMON_6, 1, 3, 5);
 539
 540	reg = CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_12;
 541	val = (mbps > 1500) ? 0 : 1;
 542	for (i = 0; i < lanes + 1; i++) {
 543		dwc_phy_write_mask(isys, id, reg + (i * 0x400), val, 1, 1);
 544		dwc_phy_write_mask(isys, id, reg + (i * 0x400), !val, 3, 3);
 545	}
 546
 547	reg = CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_13;
 548	val = (mbps > 1500) ? 0 : 1;
 549	for (i = 0; i < lanes + 1; i++) {
 550		dwc_phy_write_mask(isys, id, reg + (i * 0x400), val, 1, 1);
 551		dwc_phy_write_mask(isys, id, reg + (i * 0x400), val, 3, 3);
 552	}
 553
 554	if (!is_ipu7(isys->adev->isp->hw_ver) || id == PORT_B || id == PORT_C)
 555		reg = CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_9;
 556	else
 557		reg = CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_9;
 558
 559	for (i = 0; i < ARRAY_SIZE(table6); i++) {
 560		if (mbps >= table6[i].min_mbps && mbps <= table6[i].max_mbps) {
 561			dwc_phy_write_mask(isys, id, reg,
 562					   table6[i].oa_lane_hsrx_hs_clk_div,
 563					   5, 7);
 564			break;
 565		}
 566	}
 567
 568	if (aggregation) {
 569		dwc_phy_write_mask(isys, id, CORE_DIG_RW_COMMON_0, 1,
 570				   1, 1);
 571
 572		reg = CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_15;
 573		dwc_phy_write_mask(isys, id, reg, 3, 3, 4);
 574
 575		val = (id == PORT_A) ? 3 : 0;
 576		reg = CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_15;
 577		dwc_phy_write_mask(isys, id, reg, val, 3, 4);
 578
 579		reg = CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_15;
 580		dwc_phy_write_mask(isys, id, reg, 3, 3, 4);
 581	}
 582
 583	dwc_phy_write_mask(isys, id, CORE_DIG_DLANE_CLK_RW_HS_RX_0, 28, 0, 7);
 584	dwc_phy_write_mask(isys, id, CORE_DIG_DLANE_CLK_RW_HS_RX_7, 6, 0, 7);
 585
 586	reg = CORE_DIG_DLANE_0_RW_HS_RX_0;
 587	for (i = 0; i < ARRAY_SIZE(table2); i++) {
 588		if (mbps >= table2[i].min_mbps && mbps <= table2[i].max_mbps) {
 589			u8 j;
 590
 591			for (j = 0; j < lanes; j++)
 592				dwc_phy_write_mask(isys, id, reg + (j * 0x400),
 593						   table2[i].i_thssettle,
 594						   8, 15);
 595			break;
 596		}
 597	}
 598
 599	/* deskew */
 600	for (i = 0; i < lanes; i++) {
 601		reg = CORE_DIG_DLANE_0_RW_CFG_1;
 602		dwc_phy_write_mask(isys, id, reg + (i * 0x400),
 603				   ((mbps > 1500) ? 0x1 : 0x2), 2, 3);
 604
 605		reg = CORE_DIG_DLANE_0_RW_HS_RX_2;
 606		dwc_phy_write_mask(isys, id, reg + (i * 0x400),
 607				   ((mbps > 2500) ? 0 : 1), 15, 15);
 608		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 1, 13, 13);
 609		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 7, 9, 12);
 610
 611		reg = CORE_DIG_DLANE_0_RW_LP_0;
 612		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 1, 12, 15);
 613
 614		reg = CORE_DIG_DLANE_0_RW_LP_2;
 615		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 0, 0, 0);
 616
 617		reg = CORE_DIG_DLANE_0_RW_HS_RX_1;
 618		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 16, 0, 7);
 619
 620		reg = CORE_DIG_DLANE_0_RW_HS_RX_3;
 621		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 2, 0, 2);
 622		index = lookup_table1(mbps);
 623		if (index >= 0) {
 624			val = table1[index].fjump_deskew;
 625			dwc_phy_write_mask(isys, id, reg + (i * 0x400), val,
 626					   3, 8);
 627		}
 628
 629		reg = CORE_DIG_DLANE_0_RW_HS_RX_4;
 630		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 150, 0, 15);
 631
 632		reg = CORE_DIG_DLANE_0_RW_HS_RX_5;
 633		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 0, 0, 7);
 634		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 1, 8, 15);
 635
 636		reg = CORE_DIG_DLANE_0_RW_HS_RX_6;
 637		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 2, 0, 7);
 638		index = lookup_table1(mbps);
 639		if (index >= 0) {
 640			val = table1[index].min_eye_opening_deskew;
 641			dwc_phy_write_mask(isys, id, reg + (i * 0x400), val,
 642					   8, 15);
 643		}
 644		reg = CORE_DIG_DLANE_0_RW_HS_RX_7;
 645		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 0, 13, 13);
 646		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 0, 15, 15);
 647
 648		reg = CORE_DIG_DLANE_0_RW_HS_RX_9;
 649		index = lookup_table1(mbps);
 650		if (index >= 0) {
 651			val = table1[index].ddlcal_max_phase;
 652			dwc_phy_write_mask(isys, id, reg + (i * 0x400),
 653					   val, 0, 7);
 654		}
 655	}
 656
 657	dwc_phy_write_mask(isys, id, CORE_DIG_DLANE_CLK_RW_LP_0, 1, 12, 15);
 658	dwc_phy_write_mask(isys, id, CORE_DIG_DLANE_CLK_RW_LP_2, 0, 0, 0);
 659
 660	for (i = 0; i < ARRAY_SIZE(deskew_fine_mem); i++)
 661		dwc_phy_write_mask(isys, id, CORE_DIG_COMMON_RW_DESKEW_FINE_MEM,
 662				   deskew_fine_mem[i], 0, 15);
 663
 664	if (mbps > 1500) {
 665		hsrxval0 = 4;
 666		hsrxval2 = 3;
 667	}
 668
 669	if (mbps > 2500)
 670		hsrxval1 = 2;
 671
 672	dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_9,
 673			   hsrxval0, 0, 2);
 674	dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_9,
 675			   hsrxval0, 0, 2);
 676	dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_9,
 677			   hsrxval0, 0, 2);
 678	if (lanes == 4 && is_ipu7(isys->adev->isp->hw_ver)) {
 679		dwc_phy_write_mask(isys, id,
 680				   CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_9,
 681				   hsrxval0, 0, 2);
 682		dwc_phy_write_mask(isys, id,
 683				   CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_9,
 684				   hsrxval0, 0, 2);
 685	}
 686
 687	dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_9,
 688			   hsrxval1, 3, 4);
 689	dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_9,
 690			   hsrxval1, 3, 4);
 691	dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_9,
 692			   hsrxval1, 3, 4);
 693	if (lanes == 4 && is_ipu7(isys->adev->isp->hw_ver)) {
 694		dwc_phy_write_mask(isys, id,
 695				   CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_9,
 696				   hsrxval1, 3, 4);
 697		dwc_phy_write_mask(isys, id,
 698				   CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_9,
 699				   hsrxval1, 3, 4);
 700	}
 701
 702	dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_15,
 703			   hsrxval2, 0, 2);
 704	dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_15,
 705			   hsrxval2, 0, 2);
 706	dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_15,
 707			   hsrxval2, 0, 2);
 708	if (lanes == 4 && is_ipu7(isys->adev->isp->hw_ver)) {
 709		dwc_phy_write_mask(isys, id,
 710				   CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_15,
 711				   hsrxval2, 0, 2);
 712		dwc_phy_write_mask(isys, id,
 713				   CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_15,
 714				   hsrxval2, 0, 2);
 715	}
 716
 717	/* force and override rext */
 718	if (isys->phy_rext_cal && id) {
 719		dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_8,
 720				   isys->phy_rext_cal, 0, 3);
 721		dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_7,
 722				   1, 11, 11);
 723	}
 724}
 725
 726static void ipu7_isys_cphy_config(struct ipu7_isys *isys, u8 id, u8 lanes,
 727				  bool aggregation, u64 mbps)
 728{
 729	u8 trios = 2;
 730	u16 coarse_target;
 731	u16 deass_thresh;
 732	u16 delay_thresh;
 733	u16 reset_thresh;
 734	u16 cap_prog = 6U;
 735	u16 reg;
 736	u16 val;
 737	u32 i;
 738	u64 r64;
 739	u32 r;
 740
 741	if (is_ipu7p5(isys->adev->isp->hw_ver))
 742		val = 0x15;
 743	else
 744		val = 0x155;
 745
 746	if (is_ipu7(isys->adev->isp->hw_ver))
 747		trios = 3;
 748
 749	dwc_phy_write_mask(isys, id, CORE_DIG_RW_COMMON_7, val, 0, 9);
 750	dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_7, 104, 0, 7);
 751	dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_8, 16, 0, 7);
 752
 753	reg = CORE_DIG_CLANE_0_RW_LP_0;
 754	for (i = 0; i < trios; i++)
 755		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 6, 8, 11);
 756
 757	val = (mbps > 900U) ? 1U : 0U;
 758	for (i = 0; i < trios; i++) {
 759		reg = CORE_DIG_CLANE_0_RW_HS_RX_0;
 760		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 1, 0, 0);
 761		dwc_phy_write_mask(isys, id, reg + (i * 0x400), val, 1, 1);
 762
 763		reg = CORE_DIG_CLANE_0_RW_HS_RX_1;
 764		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 38, 0, 15);
 765
 766		reg = CORE_DIG_CLANE_0_RW_HS_RX_5;
 767		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 38, 0, 15);
 768
 769		reg = CORE_DIG_CLANE_0_RW_HS_RX_6;
 770		dwc_phy_write_mask(isys, id, reg + (i * 0x400), 10, 0, 15);
 771	}
 772
 773	/*
 774	 * Below 900Msps, always use the same value.
 775	 * The formula is suitable for data rate 80-3500Msps.
 776	 * Timebase (us) = 1, DIV = 32, TDDL (UI) = 0.5
 777	 */
 778	if (mbps >= 80U)
 779		coarse_target = DIV_ROUND_UP_ULL(mbps, 16) - 1;
 780	else
 781		coarse_target = 56;
 782
 783	for (i = 0; i < trios; i++) {
 784		reg = CORE_DIG_CLANE_0_RW_HS_RX_2 + i * 0x400;
 785		dwc_phy_write_mask(isys, id, reg, coarse_target, 0, 15);
 786	}
 787
 788	dwc_phy_write_mask(isys, id,
 789			   CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_2, 1, 0, 0);
 790	dwc_phy_write_mask(isys, id,
 791			   CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_2, 0, 0, 0);
 792	dwc_phy_write_mask(isys, id,
 793			   CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_2, 1, 0, 0);
 794
 795	if (!is_ipu7p5(isys->adev->isp->hw_ver) && lanes == 4) {
 796		dwc_phy_write_mask(isys, id,
 797				   CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_2,
 798				   1, 0, 0);
 799		dwc_phy_write_mask(isys, id,
 800				   CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_2,
 801				   0, 0, 0);
 802	}
 803
 804	for (i = 0; i < trios; i++) {
 805		reg = CORE_DIG_RW_TRIO0_0 + i * 0x400;
 806		dwc_phy_write_mask(isys, id, reg, 1, 6, 8);
 807		dwc_phy_write_mask(isys, id, reg, 1, 3, 5);
 808		dwc_phy_write_mask(isys, id, reg, 2, 0, 2);
 809	}
 810
 811	deass_thresh = (u16)div64_u64_rem(7 * 1000 * 6, mbps * 5U, &r64) + 1;
 812	if (r64 != 0)
 813		deass_thresh++;
 814
 815	reg = CORE_DIG_RW_TRIO0_2;
 816	for (i = 0; i < trios; i++)
 817		dwc_phy_write_mask(isys, id, reg + 0x400 * i,
 818				   deass_thresh, 0, 7);
 819
 820	delay_thresh = div64_u64((224U - (9U * 7U)) * 1000U, 5U * mbps) - 7u;
 821
 822	if (delay_thresh < 1)
 823		delay_thresh = 1;
 824
 825	reg = CORE_DIG_RW_TRIO0_1;
 826	for (i = 0; i < trios; i++)
 827		dwc_phy_write_mask(isys, id, reg + 0x400 * i,
 828				   delay_thresh, 0, 15);
 829
 830	reset_thresh = (u16)div_u64_rem(2U * 5U * mbps, 7U * 1000U, &r);
 831	if (!r)
 832		reset_thresh--;
 833
 834	if (reset_thresh < 1)
 835		reset_thresh = 1;
 836
 837	reg = CORE_DIG_RW_TRIO0_0;
 838	for (i = 0; i < trios; i++)
 839		dwc_phy_write_mask(isys, id, reg + 0x400 * i,
 840				   reset_thresh, 9, 11);
 841
 842	/* Tuning ITMINRX to 2 for CPHY */
 843	reg = CORE_DIG_CLANE_0_RW_LP_0;
 844	for (i = 0; i < trios; i++)
 845		dwc_phy_write_mask(isys, id, reg + 0x400 * i, 2, 12, 15);
 846
 847	reg = CORE_DIG_CLANE_0_RW_LP_2;
 848	for (i = 0; i < trios; i++)
 849		dwc_phy_write_mask(isys, id, reg + 0x400 * i, 0, 0, 0);
 850
 851	reg = CORE_DIG_CLANE_0_RW_HS_RX_0;
 852	for (i = 0; i < trios; i++)
 853		dwc_phy_write_mask(isys, id, reg + 0x400 * i, 12, 2, 6);
 854
 855	for (i = 0; i < ARRAY_SIZE(table7); i++) {
 856		if (mbps >= table7[i].min_mbps && mbps <= table7[i].max_mbps) {
 857			cap_prog = table7[i].val;
 858			break;
 859		}
 860	}
 861
 862	for (i = 0; i < (lanes + 1); i++) {
 863		reg = CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_9 + 0x400 * i;
 864		dwc_phy_write_mask(isys, id, reg, 4U, 0, 2);
 865		/* Set GMODE to 2 when CPHY >= 1.5Gsps */
 866		if (mbps >= 1500)
 867			dwc_phy_write_mask(isys, id, reg, 2U, 3, 4);
 868		else
 869			dwc_phy_write_mask(isys, id, reg, 0U, 3, 4);
 870
 871		reg = CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_7 + 0x400 * i;
 872		dwc_phy_write_mask(isys, id, reg, cap_prog, 10, 12);
 873	}
 874}
 875
 876static int ipu7_isys_phy_config(struct ipu7_isys *isys, u8 id, u8 lanes,
 877				bool aggregation)
 878{
 879	struct device *dev = &isys->adev->auxdev.dev;
 880	u32 phy_mode;
 881	s64 link_freq;
 882	u64 mbps;
 883
 884	if (aggregation)
 885		link_freq = ipu7_isys_csi2_get_link_freq(&isys->csi2[0]);
 886	else
 887		link_freq = ipu7_isys_csi2_get_link_freq(&isys->csi2[id]);
 888
 889	if (link_freq < 0) {
 890		dev_err(dev, "get link freq failed (%lld)\n", link_freq);
 891		return link_freq;
 892	}
 893
 894	mbps = div_u64(link_freq, 500000);
 895	dev_dbg(dev, "config phy %u with lanes %u aggregation %d mbps %lld\n",
 896		id, lanes, aggregation, mbps);
 897
 898	dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_10, 48, 0, 7);
 899	dwc_phy_write_mask(isys, id, CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_2,
 900			   1, 12, 13);
 901	dwc_phy_write_mask(isys, id, CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_0,
 902			   63, 2, 7);
 903	dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_STARTUP_1_1,
 904			   563, 0, 11);
 905	dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_2, 5, 0, 7);
 906	/* bypass the RCAL state (bit6) */
 907	if (aggregation && id != PORT_A)
 908		dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_2, 0x45,
 909				   0, 7);
 910
 911	dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_6, 39, 0, 7);
 912	dwc_phy_write_mask(isys, id, PPI_CALIBCTRL_RW_COMMON_BG_0, 500, 0, 8);
 913	dwc_phy_write_mask(isys, id, PPI_RW_TERMCAL_CFG_0, 38, 0, 6);
 914	dwc_phy_write_mask(isys, id, PPI_RW_OFFSETCAL_CFG_0, 7, 0, 4);
 915	dwc_phy_write_mask(isys, id, PPI_RW_LPDCOCAL_TIMEBASE, 153, 0, 9);
 916	dwc_phy_write_mask(isys, id, PPI_RW_LPDCOCAL_NREF, 800, 0, 10);
 917	dwc_phy_write_mask(isys, id, PPI_RW_LPDCOCAL_NREF_RANGE, 27, 0, 4);
 918	dwc_phy_write_mask(isys, id, PPI_RW_LPDCOCAL_TWAIT_CONFIG, 47, 0, 8);
 919	dwc_phy_write_mask(isys, id, PPI_RW_LPDCOCAL_TWAIT_CONFIG, 127, 9, 15);
 920	dwc_phy_write_mask(isys, id, PPI_RW_LPDCOCAL_VT_CONFIG, 47, 7, 15);
 921	dwc_phy_write_mask(isys, id, PPI_RW_LPDCOCAL_VT_CONFIG, 27, 2, 6);
 922	dwc_phy_write_mask(isys, id, PPI_RW_LPDCOCAL_VT_CONFIG, 3, 0, 1);
 923	dwc_phy_write_mask(isys, id, PPI_RW_LPDCOCAL_COARSE_CFG, 1, 0, 1);
 924	dwc_phy_write_mask(isys, id, PPI_RW_COMMON_CFG, 3, 0, 1);
 925	dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_0,
 926			   0, 10, 10);
 927	dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_1,
 928			   1, 10, 10);
 929	dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_1,
 930			   0, 15, 15);
 931	dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_3,
 932			   3, 8, 9);
 933	dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_0,
 934			   0, 15, 15);
 935	dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_6,
 936			   7, 12, 14);
 937	dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_7,
 938			   0, 8, 10);
 939	/* resistance tuning: 1 for 45ohm, 0 for 50ohm */
 940	dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_5,
 941			   1, 8, 8);
 942
 943	if (aggregation)
 944		phy_mode = isys->csi2[0].phy_mode;
 945	else
 946		phy_mode = isys->csi2[id].phy_mode;
 947
 948	if (phy_mode == PHY_MODE_DPHY) {
 949		ipu7_isys_dphy_config(isys, id, lanes, aggregation, mbps);
 950	} else if (phy_mode == PHY_MODE_CPHY) {
 951		ipu7_isys_cphy_config(isys, id, lanes, aggregation, mbps);
 952	} else {
 953		dev_err(dev, "unsupported phy mode %d!\n",
 954			isys->csi2[id].phy_mode);
 955	}
 956
 957	return 0;
 958}
 959
 960int ipu7_isys_csi_phy_powerup(struct ipu7_isys_csi2 *csi2)
 961{
 962	struct ipu7_isys *isys = csi2->isys;
 963	u32 lanes = csi2->nlanes;
 964	bool aggregation = false;
 965	u32 id = csi2->port;
 966	int ret;
 967
 968	/* lanes remapping for aggregation (port AB) mode */
 969	if (!is_ipu7(isys->adev->isp->hw_ver) && lanes > 2 && id == PORT_A) {
 970		aggregation = true;
 971		lanes = 2;
 972	}
 973
 974	ipu7_isys_csi_phy_reset(isys, id);
 975	gpreg_write(isys, id, PHY_CLK_LANE_CONTROL, 0x1);
 976	gpreg_write(isys, id, PHY_CLK_LANE_FORCE_CONTROL, 0x2);
 977	gpreg_write(isys, id, PHY_LANE_CONTROL_EN, (1U << lanes) - 1U);
 978	gpreg_write(isys, id, PHY_LANE_FORCE_CONTROL, 0xf);
 979	gpreg_write(isys, id, PHY_MODE, csi2->phy_mode);
 980
 981	/* config PORT_B if aggregation mode */
 982	if (aggregation) {
 983		ipu7_isys_csi_phy_reset(isys, PORT_B);
 984		gpreg_write(isys, PORT_B, PHY_CLK_LANE_CONTROL, 0x0);
 985		gpreg_write(isys, PORT_B, PHY_LANE_CONTROL_EN, 0x3);
 986		gpreg_write(isys, PORT_B, PHY_CLK_LANE_FORCE_CONTROL, 0x2);
 987		gpreg_write(isys, PORT_B, PHY_LANE_FORCE_CONTROL, 0xf);
 988		gpreg_write(isys, PORT_B, PHY_MODE, csi2->phy_mode);
 989	}
 990
 991	ipu7_isys_csi_ctrl_cfg(csi2);
 992	ipu7_isys_csi_ctrl_dids_config(csi2, id);
 993
 994	ret = ipu7_isys_phy_config(isys, id, lanes, aggregation);
 995	if (ret < 0)
 996		return ret;
 997
 998	gpreg_write(isys, id, PHY_RESET, 1);
 999	gpreg_write(isys, id, PHY_SHUTDOWN, 1);
1000	dwc_csi_write(isys, id, DPHY_RSTZ, 1);
1001	dwc_csi_write(isys, id, PHY_SHUTDOWNZ, 1);
1002	dwc_csi_write(isys, id, CSI2_RESETN, 1);
1003
1004	ret = ipu7_isys_phy_ready(isys, id);
1005	if (ret < 0)
1006		return ret;
1007
1008	gpreg_write(isys, id, PHY_LANE_FORCE_CONTROL, 0);
1009	gpreg_write(isys, id, PHY_CLK_LANE_FORCE_CONTROL, 0);
1010
1011	/* config PORT_B if aggregation mode */
1012	if (aggregation) {
1013		ret = ipu7_isys_phy_config(isys, PORT_B, 2, aggregation);
1014		if (ret < 0)
1015			return ret;
1016
1017		gpreg_write(isys, PORT_B, PHY_RESET, 1);
1018		gpreg_write(isys, PORT_B, PHY_SHUTDOWN, 1);
1019		dwc_csi_write(isys, PORT_B, DPHY_RSTZ, 1);
1020		dwc_csi_write(isys, PORT_B, PHY_SHUTDOWNZ, 1);
1021		dwc_csi_write(isys, PORT_B, CSI2_RESETN, 1);
1022		ret = ipu7_isys_phy_ready(isys, PORT_B);
1023		if (ret < 0)
1024			return ret;
1025
1026		gpreg_write(isys, PORT_B, PHY_LANE_FORCE_CONTROL, 0);
1027		gpreg_write(isys, PORT_B, PHY_CLK_LANE_FORCE_CONTROL, 0);
1028	}
1029
1030	return 0;
1031}
1032
1033void ipu7_isys_csi_phy_powerdown(struct ipu7_isys_csi2 *csi2)
1034{
1035	struct ipu7_isys *isys = csi2->isys;
1036
1037	ipu7_isys_csi_phy_reset(isys, csi2->port);
1038	if (!is_ipu7(isys->adev->isp->hw_ver) &&
1039	    csi2->nlanes > 2U && csi2->port == PORT_A)
1040		ipu7_isys_csi_phy_reset(isys, PORT_B);
1041}
~/ Read-only file preview.