// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013--2024 Intel Corporation */ #include <linux/bits.h> #include <linux/container_of.h> #include <linux/device.h> #include <linux/iopoll.h> #include <linux/list.h> #include <linux/refcount.h> #include <linux/time64.h> #include <media/v4l2-async.h> #include "ipu6.h" #include "ipu6-bus.h" #include "ipu6-isys.h" #include "ipu6-isys-csi2.h" #include "ipu6-platform-isys-csi2-reg.h" #define CSI_REG_HUB_GPREG_PHY_CTL(id) … #define CSI_REG_HUB_GPREG_PHY_CTL_RESET … #define CSI_REG_HUB_GPREG_PHY_CTL_PWR_EN … #define CSI_REG_HUB_GPREG_PHY_STATUS(id) … #define CSI_REG_HUB_GPREG_PHY_POWER_ACK … #define CSI_REG_HUB_GPREG_PHY_READY … #define MCD_PHY_POWER_STATUS_TIMEOUT … /* * bridge to phy in buttress reg map, each phy has 16 kbytes * only 2 phys for TGL U and Y */ #define IPU6_ISYS_MCD_PHY_BASE(i) … /* * There are 2 MCD DPHY instances on TGL and 1 MCD DPHY instance on ADL. * Each MCD PHY has 12-lanes which has 8 data lanes and 4 clock lanes. * CSI port 1, 3 (5, 7) can support max 2 data lanes. * CSI port 0, 2 (4, 6) can support max 4 data lanes. * PHY configurations are PPI based instead of port. * Left: * +---------+---------+---------+---------+--------+---------+----------+ * | | | | | | | | * | PPI | PPI5 | PPI4 | PPI3 | PPI2 | PPI1 | PPI0 | * +---------+---------+---------+---------+--------+---------+----------+ * | | | | | | | | * | x4 | unused | D3 | D2 | C0 | D0 | D1 | * |---------+---------+---------+---------+--------+---------+----------+ * | | | | | | | | * | x2x2 | C1 | D0 | D1 | C0 | D0 | D1 | * ----------+---------+---------+---------+--------+---------+----------+ * | | | | | | | | * | x2x1 | C1 | D0 | unused | C0 | D0 | D1 | * +---------+---------+---------+---------+--------+---------+----------+ * | | | | | | | | * | x1x1 | C1 | D0 | unused | C0 | D0 | unused | * +---------+---------+---------+---------+--------+---------+----------+ * | | | | | | | | * | x1x2 | C1 | D0 | D1 | C0 | D0 | unused | * +---------+---------+---------+---------+--------+---------+----------+ * * Right: * +---------+---------+---------+---------+--------+---------+----------+ * | | | | | | | | * | PPI | PPI6 | PPI7 | PPI8 | PPI9 | PPI10 | PPI11 | * +---------+---------+---------+---------+--------+---------+----------+ * | | | | | | | | * | x4 | D1 | D0 | C2 | D2 | D3 | unused | * |---------+---------+---------+---------+--------+---------+----------+ * | | | | | | | | * | x2x2 | D1 | D0 | C2 | D1 | D0 | C3 | * ----------+---------+---------+---------+--------+---------+----------+ * | | | | | | | | * | x2x1 | D1 | D0 | C2 | unused | D0 | C3 | * +---------+---------+---------+---------+--------+---------+----------+ * | | | | | | | | * | x1x1 | unused | D0 | C2 | unused | D0 | C3 | * +---------+---------+---------+---------+--------+---------+----------+ * | | | | | | | | * | x1x2 | unused | D0 | C2 | D1 | D0 | C3 | * +---------+---------+---------+---------+--------+---------+----------+ * * ppi mapping per phy : * * x4 + x4: * Left : port0 - PPI range {0, 1, 2, 3, 4} * Right: port2 - PPI range {6, 7, 8, 9, 10} * * x4 + x2x2: * Left: port0 - PPI range {0, 1, 2, 3, 4} * Right: port2 - PPI range {6, 7, 8}, port3 - PPI range {9, 10, 11} * * x2x2 + x4: * Left: port0 - PPI range {0, 1, 2}, port1 - PPI range {3, 4, 5} * Right: port2 - PPI range {6, 7, 8, 9, 10} * * x2x2 + x2x2: * Left : port0 - PPI range {0, 1, 2}, port1 - PPI range {3, 4, 5} * Right: port2 - PPI range {6, 7, 8}, port3 - PPI range {9, 10, 11} */ struct phy_reg { … }; static const struct phy_reg common_init_regs[] = …; static const struct phy_reg x1_port0_config_regs[] = …; static const struct phy_reg x1_port1_config_regs[] = …; static const struct phy_reg x1_port2_config_regs[] = …; static const struct phy_reg x1_port3_config_regs[] = …; static const struct phy_reg x2_port0_config_regs[] = …; static const struct phy_reg x2_port1_config_regs[] = …; static const struct phy_reg x2_port2_config_regs[] = …; static const struct phy_reg x2_port3_config_regs[] = …; static const struct phy_reg x4_port0_config_regs[] = …; static const struct phy_reg x4_port1_config_regs[] = …; static const struct phy_reg x4_port2_config_regs[] = …; static const struct phy_reg x4_port3_config_regs[] = …; static const struct phy_reg *x1_config_regs[4] = …; static const struct phy_reg *x2_config_regs[4] = …; static const struct phy_reg *x4_config_regs[4] = …; static const struct phy_reg **config_regs[3] = …; static int ipu6_isys_mcd_phy_powerup_ack(struct ipu6_isys *isys, u8 id) { … } static int ipu6_isys_mcd_phy_powerdown_ack(struct ipu6_isys *isys, u8 id) { … } static void ipu6_isys_mcd_phy_reset(struct ipu6_isys *isys, u8 id, bool assert) { … } static int ipu6_isys_mcd_phy_ready(struct ipu6_isys *isys, u8 id) { … } static void ipu6_isys_mcd_phy_common_init(struct ipu6_isys *isys) { … } static int ipu6_isys_driver_port_to_phy_port(struct ipu6_isys_csi2_config *cfg) { … } static int ipu6_isys_mcd_phy_config(struct ipu6_isys *isys) { … } #define CSI_MCD_PHY_NUM … static refcount_t phy_power_ref_count[CSI_MCD_PHY_NUM]; int ipu6_isys_mcd_phy_set_power(struct ipu6_isys *isys, struct ipu6_isys_csi2_config *cfg, const struct ipu6_isys_csi2_timing *timing, bool on) { … }