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