721 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2013--2024 Intel Corporation4 */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 kbytes33 * only 2 phys for TGL U and Y34 */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 104struct phy_reg {105 u32 reg;106 u32 val;107};108 109static 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 129static 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 153static 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 177static 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 201static 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 225static 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 259static 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 293static 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 326static 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 360static 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 414static const struct phy_reg x4_port1_config_regs[] = {415 {0x00000000, 0x00000000}416};417 418static 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 472static const struct phy_reg x4_port3_config_regs[] = {473 {0x00000000, 0x00000000}474};475 476static 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_regs481};482 483static 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_regs488};489 490static 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_regs495};496 497static const struct phy_reg **config_regs[3] = {498 x1_config_regs,499 x2_config_regs,500 x4_config_regs501};502 503static 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 523static 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 540static 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 else549 val &= ~(CSI_REG_HUB_GPREG_PHY_CTL_RESET);550 551 writel(val, isys_base + CSI_REG_HUB_GPREG_PHY_CTL(id));552}553 554static 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 570static 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 592static 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 622static 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 2663static refcount_t phy_power_ref_count[CSI_MCD_PHY_NUM];664 665int 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