1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2013--2024 Intel Corporation 4 */ 5 6 #include <linux/bits.h> 7 #include <linux/container_of.h> 8 #include <linux/device.h> 9 #include <linux/iopoll.h> 10 #include <linux/list.h> 11 #include <linux/refcount.h> 12 #include <linux/time64.h> 13 14 #include <media/v4l2-async.h> 15 16 #include "ipu6.h" 17 #include "ipu6-bus.h" 18 #include "ipu6-isys.h" 19 #include "ipu6-isys-csi2.h" 20 #include "ipu6-platform-isys-csi2-reg.h" 21 22 #define CSI_REG_HUB_GPREG_PHY_CTL(id) (CSI_REG_BASE + 0x18008 + (id) * 0x8) 23 #define CSI_REG_HUB_GPREG_PHY_CTL_RESET BIT(4) 24 #define CSI_REG_HUB_GPREG_PHY_CTL_PWR_EN BIT(0) 25 #define CSI_REG_HUB_GPREG_PHY_STATUS(id) (CSI_REG_BASE + 0x1800c + (id) * 0x8) 26 #define CSI_REG_HUB_GPREG_PHY_POWER_ACK BIT(0) 27 #define CSI_REG_HUB_GPREG_PHY_READY BIT(4) 28 29 #define MCD_PHY_POWER_STATUS_TIMEOUT (200 * USEC_PER_MSEC) 30 31 /* 32 * bridge to phy in buttress reg map, each phy has 16 kbytes 33 * only 2 phys for TGL U and Y 34 */ 35 #define IPU6_ISYS_MCD_PHY_BASE(i) (0x10000 + (i) * 0x4000) 36 37 /* 38 * There are 2 MCD DPHY instances on TGL and 1 MCD DPHY instance on ADL. 39 * Each MCD PHY has 12-lanes which has 8 data lanes and 4 clock lanes. 40 * CSI port 1, 3 (5, 7) can support max 2 data lanes. 41 * CSI port 0, 2 (4, 6) can support max 4 data lanes. 42 * PHY configurations are PPI based instead of port. 43 * Left: 44 * +---------+---------+---------+---------+--------+---------+----------+ 45 * | | | | | | | | 46 * | PPI | PPI5 | PPI4 | PPI3 | PPI2 | PPI1 | PPI0 | 47 * +---------+---------+---------+---------+--------+---------+----------+ 48 * | | | | | | | | 49 * | x4 | unused | D3 | D2 | C0 | D0 | D1 | 50 * |---------+---------+---------+---------+--------+---------+----------+ 51 * | | | | | | | | 52 * | x2x2 | C1 | D0 | D1 | C0 | D0 | D1 | 53 * ----------+---------+---------+---------+--------+---------+----------+ 54 * | | | | | | | | 55 * | x2x1 | C1 | D0 | unused | C0 | D0 | D1 | 56 * +---------+---------+---------+---------+--------+---------+----------+ 57 * | | | | | | | | 58 * | x1x1 | C1 | D0 | unused | C0 | D0 | unused | 59 * +---------+---------+---------+---------+--------+---------+----------+ 60 * | | | | | | | | 61 * | x1x2 | C1 | D0 | D1 | C0 | D0 | unused | 62 * +---------+---------+---------+---------+--------+---------+----------+ 63 * 64 * Right: 65 * +---------+---------+---------+---------+--------+---------+----------+ 66 * | | | | | | | | 67 * | PPI | PPI6 | PPI7 | PPI8 | PPI9 | PPI10 | PPI11 | 68 * +---------+---------+---------+---------+--------+---------+----------+ 69 * | | | | | | | | 70 * | x4 | D1 | D0 | C2 | D2 | D3 | unused | 71 * |---------+---------+---------+---------+--------+---------+----------+ 72 * | | | | | | | | 73 * | x2x2 | D1 | D0 | C2 | D1 | D0 | C3 | 74 * ----------+---------+---------+---------+--------+---------+----------+ 75 * | | | | | | | | 76 * | x2x1 | D1 | D0 | C2 | unused | D0 | C3 | 77 * +---------+---------+---------+---------+--------+---------+----------+ 78 * | | | | | | | | 79 * | x1x1 | unused | D0 | C2 | unused | D0 | C3 | 80 * +---------+---------+---------+---------+--------+---------+----------+ 81 * | | | | | | | | 82 * | x1x2 | unused | D0 | C2 | D1 | D0 | C3 | 83 * +---------+---------+---------+---------+--------+---------+----------+ 84 * 85 * ppi mapping per phy : 86 * 87 * x4 + x4: 88 * Left : port0 - PPI range {0, 1, 2, 3, 4} 89 * Right: port2 - PPI range {6, 7, 8, 9, 10} 90 * 91 * x4 + x2x2: 92 * Left: port0 - PPI range {0, 1, 2, 3, 4} 93 * Right: port2 - PPI range {6, 7, 8}, port3 - PPI range {9, 10, 11} 94 * 95 * x2x2 + x4: 96 * Left: port0 - PPI range {0, 1, 2}, port1 - PPI range {3, 4, 5} 97 * Right: port2 - PPI range {6, 7, 8, 9, 10} 98 * 99 * x2x2 + x2x2: 100 * Left : port0 - PPI range {0, 1, 2}, port1 - PPI range {3, 4, 5} 101 * Right: port2 - PPI range {6, 7, 8}, port3 - PPI range {9, 10, 11} 102 */ 103 104 struct phy_reg { 105 u32 reg; 106 u32 val; 107 }; 108 109 static const struct phy_reg common_init_regs[] = { 110 /* for TGL-U, use 0x80000000 */ 111 {0x00000040, 0x80000000}, 112 {0x00000044, 0x00a80880}, 113 {0x00000044, 0x00b80880}, 114 {0x00000010, 0x0000078c}, 115 {0x00000344, 0x2f4401e2}, 116 {0x00000544, 0x924401e2}, 117 {0x00000744, 0x594401e2}, 118 {0x00000944, 0x624401e2}, 119 {0x00000b44, 0xfc4401e2}, 120 {0x00000d44, 0xc54401e2}, 121 {0x00000f44, 0x034401e2}, 122 {0x00001144, 0x8f4401e2}, 123 {0x00001344, 0x754401e2}, 124 {0x00001544, 0xe94401e2}, 125 {0x00001744, 0xcb4401e2}, 126 {0x00001944, 0xfa4401e2} 127 }; 128 129 static const struct phy_reg x1_port0_config_regs[] = { 130 {0x00000694, 0xc80060fa}, 131 {0x00000680, 0x3d4f78ea}, 132 {0x00000690, 0x10a0140b}, 133 {0x000006a8, 0xdf04010a}, 134 {0x00000700, 0x57050060}, 135 {0x00000710, 0x0030001c}, 136 {0x00000738, 0x5f004444}, 137 {0x0000073c, 0x78464204}, 138 {0x00000748, 0x7821f940}, 139 {0x0000074c, 0xb2000433}, 140 {0x00000494, 0xfe6030fa}, 141 {0x00000480, 0x29ef5ed0}, 142 {0x00000490, 0x10a0540b}, 143 {0x000004a8, 0x7a01010a}, 144 {0x00000500, 0xef053460}, 145 {0x00000510, 0xe030101c}, 146 {0x00000538, 0xdf808444}, 147 {0x0000053c, 0xc8422204}, 148 {0x00000540, 0x0180088c}, 149 {0x00000574, 0x00000000}, 150 {0x00000000, 0x00000000} 151 }; 152 153 static const struct phy_reg x1_port1_config_regs[] = { 154 {0x00000c94, 0xc80060fa}, 155 {0x00000c80, 0xcf47abea}, 156 {0x00000c90, 0x10a0840b}, 157 {0x00000ca8, 0xdf04010a}, 158 {0x00000d00, 0x57050060}, 159 {0x00000d10, 0x0030001c}, 160 {0x00000d38, 0x5f004444}, 161 {0x00000d3c, 0x78464204}, 162 {0x00000d48, 0x7821f940}, 163 {0x00000d4c, 0xb2000433}, 164 {0x00000a94, 0xc91030fa}, 165 {0x00000a80, 0x5a166ed0}, 166 {0x00000a90, 0x10a0540b}, 167 {0x00000aa8, 0x5d060100}, 168 {0x00000b00, 0xef053460}, 169 {0x00000b10, 0xa030101c}, 170 {0x00000b38, 0xdf808444}, 171 {0x00000b3c, 0xc8422204}, 172 {0x00000b40, 0x0180088c}, 173 {0x00000b74, 0x00000000}, 174 {0x00000000, 0x00000000} 175 }; 176 177 static const struct phy_reg x1_port2_config_regs[] = { 178 {0x00001294, 0x28f000fa}, 179 {0x00001280, 0x08130cea}, 180 {0x00001290, 0x10a0140b}, 181 {0x000012a8, 0xd704010a}, 182 {0x00001300, 0x8d050060}, 183 {0x00001310, 0x0030001c}, 184 {0x00001338, 0xdf008444}, 185 {0x0000133c, 0x78422204}, 186 {0x00001348, 0x7821f940}, 187 {0x0000134c, 0x5a000433}, 188 {0x00001094, 0x2d20b0fa}, 189 {0x00001080, 0xade75dd0}, 190 {0x00001090, 0x10a0540b}, 191 {0x000010a8, 0xb101010a}, 192 {0x00001100, 0x33053460}, 193 {0x00001110, 0x0030101c}, 194 {0x00001138, 0xdf808444}, 195 {0x0000113c, 0xc8422204}, 196 {0x00001140, 0x8180088c}, 197 {0x00001174, 0x00000000}, 198 {0x00000000, 0x00000000} 199 }; 200 201 static const struct phy_reg x1_port3_config_regs[] = { 202 {0x00001894, 0xc80060fa}, 203 {0x00001880, 0x0f90fd6a}, 204 {0x00001890, 0x10a0840b}, 205 {0x000018a8, 0xdf04010a}, 206 {0x00001900, 0x57050060}, 207 {0x00001910, 0x0030001c}, 208 {0x00001938, 0x5f004444}, 209 {0x0000193c, 0x78464204}, 210 {0x00001948, 0x7821f940}, 211 {0x0000194c, 0xb2000433}, 212 {0x00001694, 0x3050d0fa}, 213 {0x00001680, 0x0ef6d050}, 214 {0x00001690, 0x10a0540b}, 215 {0x000016a8, 0xe301010a}, 216 {0x00001700, 0x69053460}, 217 {0x00001710, 0xa030101c}, 218 {0x00001738, 0xdf808444}, 219 {0x0000173c, 0xc8422204}, 220 {0x00001740, 0x0180088c}, 221 {0x00001774, 0x00000000}, 222 {0x00000000, 0x00000000} 223 }; 224 225 static const struct phy_reg x2_port0_config_regs[] = { 226 {0x00000694, 0xc80060fa}, 227 {0x00000680, 0x3d4f78ea}, 228 {0x00000690, 0x10a0140b}, 229 {0x000006a8, 0xdf04010a}, 230 {0x00000700, 0x57050060}, 231 {0x00000710, 0x0030001c}, 232 {0x00000738, 0x5f004444}, 233 {0x0000073c, 0x78464204}, 234 {0x00000748, 0x7821f940}, 235 {0x0000074c, 0xb2000433}, 236 {0x00000494, 0xc80060fa}, 237 {0x00000480, 0x29ef5ed8}, 238 {0x00000490, 0x10a0540b}, 239 {0x000004a8, 0x7a01010a}, 240 {0x00000500, 0xef053460}, 241 {0x00000510, 0xe030101c}, 242 {0x00000538, 0xdf808444}, 243 {0x0000053c, 0xc8422204}, 244 {0x00000540, 0x0180088c}, 245 {0x00000574, 0x00000000}, 246 {0x00000294, 0xc80060fa}, 247 {0x00000280, 0xcb45b950}, 248 {0x00000290, 0x10a0540b}, 249 {0x000002a8, 0x8c01010a}, 250 {0x00000300, 0xef053460}, 251 {0x00000310, 0x8030101c}, 252 {0x00000338, 0x41808444}, 253 {0x0000033c, 0x32422204}, 254 {0x00000340, 0x0180088c}, 255 {0x00000374, 0x00000000}, 256 {0x00000000, 0x00000000} 257 }; 258 259 static const struct phy_reg x2_port1_config_regs[] = { 260 {0x00000c94, 0xc80060fa}, 261 {0x00000c80, 0xcf47abea}, 262 {0x00000c90, 0x10a0840b}, 263 {0x00000ca8, 0xdf04010a}, 264 {0x00000d00, 0x57050060}, 265 {0x00000d10, 0x0030001c}, 266 {0x00000d38, 0x5f004444}, 267 {0x00000d3c, 0x78464204}, 268 {0x00000d48, 0x7821f940}, 269 {0x00000d4c, 0xb2000433}, 270 {0x00000a94, 0xc80060fa}, 271 {0x00000a80, 0x5a166ed8}, 272 {0x00000a90, 0x10a0540b}, 273 {0x00000aa8, 0x7a01010a}, 274 {0x00000b00, 0xef053460}, 275 {0x00000b10, 0xa030101c}, 276 {0x00000b38, 0xdf808444}, 277 {0x00000b3c, 0xc8422204}, 278 {0x00000b40, 0x0180088c}, 279 {0x00000b74, 0x00000000}, 280 {0x00000894, 0xc80060fa}, 281 {0x00000880, 0x4d4f21d0}, 282 {0x00000890, 0x10a0540b}, 283 {0x000008a8, 0x5601010a}, 284 {0x00000900, 0xef053460}, 285 {0x00000910, 0x8030101c}, 286 {0x00000938, 0xdf808444}, 287 {0x0000093c, 0xc8422204}, 288 {0x00000940, 0x0180088c}, 289 {0x00000974, 0x00000000}, 290 {0x00000000, 0x00000000} 291 }; 292 293 static const struct phy_reg x2_port2_config_regs[] = { 294 {0x00001294, 0xc80060fa}, 295 {0x00001280, 0x08130cea}, 296 {0x00001290, 0x10a0140b}, 297 {0x000012a8, 0xd704010a}, 298 {0x00001300, 0x8d050060}, 299 {0x00001310, 0x0030001c}, 300 {0x00001338, 0xdf008444}, 301 {0x0000133c, 0x78422204}, 302 {0x00001348, 0x7821f940}, 303 {0x0000134c, 0x5a000433}, 304 {0x00001094, 0xc80060fa}, 305 {0x00001080, 0xade75dd8}, 306 {0x00001090, 0x10a0540b}, 307 {0x000010a8, 0xb101010a}, 308 {0x00001100, 0x33053460}, 309 {0x00001110, 0x0030101c}, 310 {0x00001138, 0xdf808444}, 311 {0x0000113c, 0xc8422204}, 312 {0x00001140, 0x8180088c}, 313 {0x00001174, 0x00000000}, 314 {0x00000e94, 0xc80060fa}, 315 {0x00000e80, 0x0fbf16d0}, 316 {0x00000e90, 0x10a0540b}, 317 {0x00000ea8, 0x7a01010a}, 318 {0x00000f00, 0xf5053460}, 319 {0x00000f10, 0xc030101c}, 320 {0x00000f38, 0xdf808444}, 321 {0x00000f3c, 0xc8422204}, 322 {0x00000f40, 0x8180088c}, 323 {0x00000000, 0x00000000} 324 }; 325 326 static const struct phy_reg x2_port3_config_regs[] = { 327 {0x00001894, 0xc80060fa}, 328 {0x00001880, 0x0f90fd6a}, 329 {0x00001890, 0x10a0840b}, 330 {0x000018a8, 0xdf04010a}, 331 {0x00001900, 0x57050060}, 332 {0x00001910, 0x0030001c}, 333 {0x00001938, 0x5f004444}, 334 {0x0000193c, 0x78464204}, 335 {0x00001948, 0x7821f940}, 336 {0x0000194c, 0xb2000433}, 337 {0x00001694, 0xc80060fa}, 338 {0x00001680, 0x0ef6d058}, 339 {0x00001690, 0x10a0540b}, 340 {0x000016a8, 0x7a01010a}, 341 {0x00001700, 0x69053460}, 342 {0x00001710, 0xa030101c}, 343 {0x00001738, 0xdf808444}, 344 {0x0000173c, 0xc8422204}, 345 {0x00001740, 0x0180088c}, 346 {0x00001774, 0x00000000}, 347 {0x00001494, 0xc80060fa}, 348 {0x00001480, 0xf9d34bd0}, 349 {0x00001490, 0x10a0540b}, 350 {0x000014a8, 0x7a01010a}, 351 {0x00001500, 0x1b053460}, 352 {0x00001510, 0x0030101c}, 353 {0x00001538, 0xdf808444}, 354 {0x0000153c, 0xc8422204}, 355 {0x00001540, 0x8180088c}, 356 {0x00001574, 0x00000000}, 357 {0x00000000, 0x00000000} 358 }; 359 360 static const struct phy_reg x4_port0_config_regs[] = { 361 {0x00000694, 0xc80060fa}, 362 {0x00000680, 0x3d4f78fa}, 363 {0x00000690, 0x10a0140b}, 364 {0x000006a8, 0xdf04010a}, 365 {0x00000700, 0x57050060}, 366 {0x00000710, 0x0030001c}, 367 {0x00000738, 0x5f004444}, 368 {0x0000073c, 0x78464204}, 369 {0x00000748, 0x7821f940}, 370 {0x0000074c, 0xb2000433}, 371 {0x00000494, 0xfe6030fa}, 372 {0x00000480, 0x29ef5ed8}, 373 {0x00000490, 0x10a0540b}, 374 {0x000004a8, 0x7a01010a}, 375 {0x00000500, 0xef053460}, 376 {0x00000510, 0xe030101c}, 377 {0x00000538, 0xdf808444}, 378 {0x0000053c, 0xc8422204}, 379 {0x00000540, 0x0180088c}, 380 {0x00000574, 0x00000004}, 381 {0x00000294, 0x23e030fa}, 382 {0x00000280, 0xcb45b950}, 383 {0x00000290, 0x10a0540b}, 384 {0x000002a8, 0x8c01010a}, 385 {0x00000300, 0xef053460}, 386 {0x00000310, 0x8030101c}, 387 {0x00000338, 0x41808444}, 388 {0x0000033c, 0x32422204}, 389 {0x00000340, 0x0180088c}, 390 {0x00000374, 0x00000004}, 391 {0x00000894, 0x5620b0fa}, 392 {0x00000880, 0x4d4f21dc}, 393 {0x00000890, 0x10a0540b}, 394 {0x000008a8, 0x5601010a}, 395 {0x00000900, 0xef053460}, 396 {0x00000910, 0x8030101c}, 397 {0x00000938, 0xdf808444}, 398 {0x0000093c, 0xc8422204}, 399 {0x00000940, 0x0180088c}, 400 {0x00000974, 0x00000004}, 401 {0x00000a94, 0xc91030fa}, 402 {0x00000a80, 0x5a166ecc}, 403 {0x00000a90, 0x10a0540b}, 404 {0x00000aa8, 0x5d01010a}, 405 {0x00000b00, 0xef053460}, 406 {0x00000b10, 0xa030101c}, 407 {0x00000b38, 0xdf808444}, 408 {0x00000b3c, 0xc8422204}, 409 {0x00000b40, 0x0180088c}, 410 {0x00000b74, 0x00000004}, 411 {0x00000000, 0x00000000} 412 }; 413 414 static const struct phy_reg x4_port1_config_regs[] = { 415 {0x00000000, 0x00000000} 416 }; 417 418 static const struct phy_reg x4_port2_config_regs[] = { 419 {0x00001294, 0x28f000fa}, 420 {0x00001280, 0x08130cfa}, 421 {0x00001290, 0x10c0140b}, 422 {0x000012a8, 0xd704010a}, 423 {0x00001300, 0x8d050060}, 424 {0x00001310, 0x0030001c}, 425 {0x00001338, 0xdf008444}, 426 {0x0000133c, 0x78422204}, 427 {0x00001348, 0x7821f940}, 428 {0x0000134c, 0x5a000433}, 429 {0x00001094, 0x2d20b0fa}, 430 {0x00001080, 0xade75dd8}, 431 {0x00001090, 0x10a0540b}, 432 {0x000010a8, 0xb101010a}, 433 {0x00001100, 0x33053460}, 434 {0x00001110, 0x0030101c}, 435 {0x00001138, 0xdf808444}, 436 {0x0000113c, 0xc8422204}, 437 {0x00001140, 0x8180088c}, 438 {0x00001174, 0x00000004}, 439 {0x00000e94, 0xd308d0fa}, 440 {0x00000e80, 0x0fbf16d0}, 441 {0x00000e90, 0x10a0540b}, 442 {0x00000ea8, 0x2c01010a}, 443 {0x00000f00, 0xf5053460}, 444 {0x00000f10, 0xc030101c}, 445 {0x00000f38, 0xdf808444}, 446 {0x00000f3c, 0xc8422204}, 447 {0x00000f40, 0x8180088c}, 448 {0x00000f74, 0x00000004}, 449 {0x00001494, 0x136850fa}, 450 {0x00001480, 0xf9d34bdc}, 451 {0x00001490, 0x10a0540b}, 452 {0x000014a8, 0x5a01010a}, 453 {0x00001500, 0x1b053460}, 454 {0x00001510, 0x0030101c}, 455 {0x00001538, 0xdf808444}, 456 {0x0000153c, 0xc8422204}, 457 {0x00001540, 0x8180088c}, 458 {0x00001574, 0x00000004}, 459 {0x00001694, 0x3050d0fa}, 460 {0x00001680, 0x0ef6d04c}, 461 {0x00001690, 0x10a0540b}, 462 {0x000016a8, 0xe301010a}, 463 {0x00001700, 0x69053460}, 464 {0x00001710, 0xa030101c}, 465 {0x00001738, 0xdf808444}, 466 {0x0000173c, 0xc8422204}, 467 {0x00001740, 0x0180088c}, 468 {0x00001774, 0x00000004}, 469 {0x00000000, 0x00000000} 470 }; 471 472 static const struct phy_reg x4_port3_config_regs[] = { 473 {0x00000000, 0x00000000} 474 }; 475 476 static const struct phy_reg *x1_config_regs[4] = { 477 x1_port0_config_regs, 478 x1_port1_config_regs, 479 x1_port2_config_regs, 480 x1_port3_config_regs 481 }; 482 483 static const struct phy_reg *x2_config_regs[4] = { 484 x2_port0_config_regs, 485 x2_port1_config_regs, 486 x2_port2_config_regs, 487 x2_port3_config_regs 488 }; 489 490 static const struct phy_reg *x4_config_regs[4] = { 491 x4_port0_config_regs, 492 x4_port1_config_regs, 493 x4_port2_config_regs, 494 x4_port3_config_regs 495 }; 496 497 static const struct phy_reg **config_regs[3] = { 498 x1_config_regs, 499 x2_config_regs, 500 x4_config_regs 501 }; 502 503 static int ipu6_isys_mcd_phy_powerup_ack(struct ipu6_isys *isys, u8 id) 504 { 505 struct device *dev = &isys->adev->auxdev.dev; 506 void __iomem *isys_base = isys->pdata->base; 507 u32 val; 508 int ret; 509 510 val = readl(isys_base + CSI_REG_HUB_GPREG_PHY_CTL(id)); 511 val |= CSI_REG_HUB_GPREG_PHY_CTL_PWR_EN; 512 writel(val, isys_base + CSI_REG_HUB_GPREG_PHY_CTL(id)); 513 514 ret = readl_poll_timeout(isys_base + CSI_REG_HUB_GPREG_PHY_STATUS(id), 515 val, val & CSI_REG_HUB_GPREG_PHY_POWER_ACK, 516 200, MCD_PHY_POWER_STATUS_TIMEOUT); 517 if (ret) 518 dev_err(dev, "PHY%d powerup ack timeout", id); 519 520 return ret; 521 } 522 523 static int ipu6_isys_mcd_phy_powerdown_ack(struct ipu6_isys *isys, u8 id) 524 { 525 struct device *dev = &isys->adev->auxdev.dev; 526 void __iomem *isys_base = isys->pdata->base; 527 u32 val; 528 int ret; 529 530 writel(0, isys_base + CSI_REG_HUB_GPREG_PHY_CTL(id)); 531 ret = readl_poll_timeout(isys_base + CSI_REG_HUB_GPREG_PHY_STATUS(id), 532 val, !(val & CSI_REG_HUB_GPREG_PHY_POWER_ACK), 533 200, MCD_PHY_POWER_STATUS_TIMEOUT); 534 if (ret) 535 dev_err(dev, "PHY%d powerdown ack timeout", id); 536 537 return ret; 538 } 539 540 static void ipu6_isys_mcd_phy_reset(struct ipu6_isys *isys, u8 id, bool assert) 541 { 542 void __iomem *isys_base = isys->pdata->base; 543 u32 val; 544 545 val = readl(isys_base + CSI_REG_HUB_GPREG_PHY_CTL(id)); 546 if (assert) 547 val |= CSI_REG_HUB_GPREG_PHY_CTL_RESET; 548 else 549 val &= ~(CSI_REG_HUB_GPREG_PHY_CTL_RESET); 550 551 writel(val, isys_base + CSI_REG_HUB_GPREG_PHY_CTL(id)); 552 } 553 554 static int ipu6_isys_mcd_phy_ready(struct ipu6_isys *isys, u8 id) 555 { 556 struct device *dev = &isys->adev->auxdev.dev; 557 void __iomem *isys_base = isys->pdata->base; 558 u32 val; 559 int ret; 560 561 ret = readl_poll_timeout(isys_base + CSI_REG_HUB_GPREG_PHY_STATUS(id), 562 val, val & CSI_REG_HUB_GPREG_PHY_READY, 563 200, MCD_PHY_POWER_STATUS_TIMEOUT); 564 if (ret) 565 dev_err(dev, "PHY%d ready ack timeout", id); 566 567 return ret; 568 } 569 570 static void ipu6_isys_mcd_phy_common_init(struct ipu6_isys *isys) 571 { 572 struct ipu6_bus_device *adev = isys->adev; 573 struct ipu6_device *isp = adev->isp; 574 void __iomem *isp_base = isp->base; 575 struct sensor_async_sd *s_asd; 576 struct v4l2_async_connection *asc; 577 void __iomem *phy_base; 578 unsigned int i; 579 u8 phy_id; 580 581 list_for_each_entry(asc, &isys->notifier.done_list, asc_entry) { 582 s_asd = container_of(asc, struct sensor_async_sd, asc); 583 phy_id = s_asd->csi2.port / 4; 584 phy_base = isp_base + IPU6_ISYS_MCD_PHY_BASE(phy_id); 585 586 for (i = 0; i < ARRAY_SIZE(common_init_regs); i++) 587 writel(common_init_regs[i].val, 588 phy_base + common_init_regs[i].reg); 589 } 590 } 591 592 static int ipu6_isys_driver_port_to_phy_port(struct ipu6_isys_csi2_config *cfg) 593 { 594 int phy_port; 595 int ret; 596 597 if (!(cfg->nlanes == 4 || cfg->nlanes == 2 || cfg->nlanes == 1)) 598 return -EINVAL; 599 600 /* B,F -> C0 A,E -> C1 C,G -> C2 D,H -> C4 */ 601 /* normalize driver port number */ 602 phy_port = cfg->port % 4; 603 604 /* swap port number only for A and B */ 605 if (phy_port == 0) 606 phy_port = 1; 607 else if (phy_port == 1) 608 phy_port = 0; 609 610 ret = phy_port; 611 612 /* check validity per lane configuration */ 613 if (cfg->nlanes == 4 && !(phy_port == 0 || phy_port == 2)) 614 ret = -EINVAL; 615 else if ((cfg->nlanes == 2 || cfg->nlanes == 1) && 616 !(phy_port >= 0 && phy_port <= 3)) 617 ret = -EINVAL; 618 619 return ret; 620 } 621 622 static int ipu6_isys_mcd_phy_config(struct ipu6_isys *isys) 623 { 624 struct device *dev = &isys->adev->auxdev.dev; 625 struct ipu6_bus_device *adev = isys->adev; 626 const struct phy_reg **phy_config_regs; 627 struct ipu6_device *isp = adev->isp; 628 void __iomem *isp_base = isp->base; 629 struct sensor_async_sd *s_asd; 630 struct ipu6_isys_csi2_config cfg; 631 struct v4l2_async_connection *asc; 632 int phy_port, phy_id; 633 unsigned int i; 634 void __iomem *phy_base; 635 636 list_for_each_entry(asc, &isys->notifier.done_list, asc_entry) { 637 s_asd = container_of(asc, struct sensor_async_sd, asc); 638 cfg.port = s_asd->csi2.port; 639 cfg.nlanes = s_asd->csi2.nlanes; 640 phy_port = ipu6_isys_driver_port_to_phy_port(&cfg); 641 if (phy_port < 0) { 642 dev_err(dev, "invalid port %d for lane %d", cfg.port, 643 cfg.nlanes); 644 return -ENXIO; 645 } 646 647 phy_id = cfg.port / 4; 648 phy_base = isp_base + IPU6_ISYS_MCD_PHY_BASE(phy_id); 649 dev_dbg(dev, "port%d PHY%u lanes %u\n", cfg.port, phy_id, 650 cfg.nlanes); 651 652 phy_config_regs = config_regs[cfg.nlanes / 2]; 653 cfg.port = phy_port; 654 for (i = 0; phy_config_regs[cfg.port][i].reg; i++) 655 writel(phy_config_regs[cfg.port][i].val, 656 phy_base + phy_config_regs[cfg.port][i].reg); 657 } 658 659 return 0; 660 } 661 662 #define CSI_MCD_PHY_NUM 2 663 static refcount_t phy_power_ref_count[CSI_MCD_PHY_NUM]; 664 665 int ipu6_isys_mcd_phy_set_power(struct ipu6_isys *isys, 666 struct ipu6_isys_csi2_config *cfg, 667 const struct ipu6_isys_csi2_timing *timing, 668 bool on) 669 { 670 struct device *dev = &isys->adev->auxdev.dev; 671 void __iomem *isys_base = isys->pdata->base; 672 u8 port, phy_id; 673 refcount_t *ref; 674 int ret; 675 676 port = cfg->port; 677 phy_id = port / 4; 678 679 ref = &phy_power_ref_count[phy_id]; 680 681 dev_dbg(dev, "for phy %d port %d, lanes: %d\n", phy_id, port, 682 cfg->nlanes); 683 684 if (!isys_base || port >= isys->pdata->ipdata->csi2.nports) { 685 dev_warn(dev, "invalid port ID %d\n", port); 686 return -EINVAL; 687 } 688 689 if (on) { 690 if (refcount_read(ref)) { 691 dev_dbg(dev, "for phy %d is already UP", phy_id); 692 refcount_inc(ref); 693 return 0; 694 } 695 696 ret = ipu6_isys_mcd_phy_powerup_ack(isys, phy_id); 697 if (ret) 698 return ret; 699 700 ipu6_isys_mcd_phy_reset(isys, phy_id, 0); 701 ipu6_isys_mcd_phy_common_init(isys); 702 703 ret = ipu6_isys_mcd_phy_config(isys); 704 if (ret) 705 return ret; 706 707 ipu6_isys_mcd_phy_reset(isys, phy_id, 1); 708 ret = ipu6_isys_mcd_phy_ready(isys, phy_id); 709 if (ret) 710 return ret; 711 712 refcount_set(ref, 1); 713 return 0; 714 } 715 716 if (!refcount_dec_and_test(ref)) 717 return 0; 718 719 return ipu6_isys_mcd_phy_powerdown_ack(isys, phy_id); 720 } 721