diff --git a/drivers/media/pci/intel/ipu7/ipu7-isys-csi-phy.c b/drivers/media/pci/intel/ipu7/ipu7-isys-csi-phy.c index a56aeec..52288bf 100644 --- a/drivers/media/pci/intel/ipu7/ipu7-isys-csi-phy.c +++ b/drivers/media/pci/intel/ipu7/ipu7-isys-csi-phy.c @@ -748,6 +748,13 @@ static void ipu7_isys_cphy_config(struct ipu7_isys *isys, u8 id, u8 lanes, if (is_ipu7(isys->adev->isp->hw_ver)) trios = 3; + /* + * An aggregated port A+B is a single 5-pair macro carrying 3 trios: + * port A's three pairs hold trios 0-1, port B's two hold trio 2. + */ + if (aggregation && id != PORT_A) + trios = 1; + dwc_phy_write_mask(isys, id, CORE_DIG_RW_COMMON_7, val, 0, 9); dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_7, 104, 0, 7); dwc_phy_write_mask(isys, id, PPI_STARTUP_RW_COMMON_DPHY_8, 16, 0, 7); @@ -873,6 +880,27 @@ static void ipu7_isys_cphy_config(struct ipu7_isys *isys, u8 id, u8 lanes, reg = CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_7 + 0x400 * i; dwc_phy_write_mask(isys, id, reg, cap_prog, 10, 12); } + + if (aggregation) { + dwc_phy_write_mask(isys, id, CORE_DIG_RW_COMMON_0, 1, 1, 1); + + /* + * C-PHY has no clock lane, so unlike D-PHY no AFE lane is the + * shared clock that has to follow port A. + */ + for (i = 0; i < (lanes + 1); i++) { + reg = CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_15 + 0x400 * i; + dwc_phy_write_mask(isys, id, reg, 3, 3, 4); + } + } + + /* Only port A runs rext calibration; other ports reuse its result. */ + if (isys->phy_rext_cal && id) { + dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_8, + isys->phy_rext_cal, 0, 3); + dwc_phy_write_mask(isys, id, CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_7, + 1, 11, 11); + } } static int ipu7_isys_phy_config(struct ipu7_isys *isys, u8 id, u8 lanes, diff --git a/drivers/media/pci/intel/ipu7/ipu7-isys-csi2.c b/drivers/media/pci/intel/ipu7/ipu7-isys-csi2.c index 6ba21c3..caec6c4 100644 --- a/drivers/media/pci/intel/ipu7/ipu7-isys-csi2.c +++ b/drivers/media/pci/intel/ipu7/ipu7-isys-csi2.c @@ -175,6 +175,11 @@ static void ipu7_isys_csi2_disable_stream(struct ipu7_isys_csi2 *csi2) ipu7_isys_csi_phy_powerdown(csi2); + if (csi2->port == 0U && csi2->nlanes > 2U && + !is_ipu7(isys->adev->isp->hw_ver)) + writel(0x0, isys_base + IS_IO_GPREGS_BASE + + CSI_PORTAB_AGGREGATION); + writel(0x4, isys_base + IS_IO_GPREGS_BASE + CLK_DIV_FACTOR_APB_CLK); csi2_irq_disable(csi2); } @@ -195,7 +200,7 @@ static int ipu7_isys_csi2_enable_stream(struct ipu7_isys_csi2 *csi2) dev_dbg(dev, "port %u CLK_GATE = 0x%04x DIV_FACTOR_APB_CLK=0x%04x\n", port, readl(isys_base + offset + CSI_PORT_CLK_GATE), readl(isys_base + offset + CLK_DIV_FACTOR_APB_CLK)); - if (port == 0U && nlanes == 4U && !is_ipu7(isys->adev->isp->hw_ver)) { + if (port == 0U && nlanes > 2U && !is_ipu7(isys->adev->isp->hw_ver)) { dev_dbg(dev, "CSI port %u in aggregation mode\n", port); writel(0x1, isys_base + offset + CSI_PORTAB_AGGREGATION); }