diff mbox series

[v2,089/106] ccs-pll: Add support for DDR OP system and pixel clocks

Message ID 20201007084557.25843-80-sakari.ailus@linux.intel.com (mailing list archive)
State New, archived
Headers show
Series CCS driver | expand

Commit Message

Sakari Ailus Oct. 7, 2020, 8:45 a.m. UTC
Add support for dual data rate operational system and pixel clocks. This
is implemented using two PLL flags.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
 drivers/media/i2c/ccs-pll.c | 64 +++++++++++++++++++++++++------------
 drivers/media/i2c/ccs-pll.h |  2 ++
 2 files changed, 46 insertions(+), 20 deletions(-)
diff mbox series

Patch

diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c
index 7df7b96e78e6..5a0162347777 100644
--- a/drivers/media/i2c/ccs-pll.c
+++ b/drivers/media/i2c/ccs-pll.c
@@ -119,7 +119,7 @@  static void print_pll(struct device *dev, struct ccs_pll *pll)
 		}
 	}
 
-	dev_dbg(dev, "flags%s%s%s%s%s%s%s\n",
+	dev_dbg(dev, "flags%s%s%s%s%s%s%s%s%s\n",
 		pll->flags & PLL_FL(LANE_SPEED_MODEL) ? " lane-speed" : "",
 		pll->flags & PLL_FL(LINK_DECOUPLED) ? " link-decoupled" : "",
 		pll->flags & PLL_FL(EXT_IP_PLL_DIVIDER) ?
@@ -128,7 +128,19 @@  static void print_pll(struct device *dev, struct ccs_pll *pll)
 		" flexible-op-pix-div" : "",
 		pll->flags & PLL_FL(FIFO_DERATING) ? " fifo-derating" : "",
 		pll->flags & PLL_FL(FIFO_OVERRATING) ? " fifo-overrating" : "",
-		pll->flags & PLL_FL(DUAL_PLL) ? " dual-pll" : "");
+		pll->flags & PLL_FL(DUAL_PLL) ? " dual-pll" : "",
+		pll->flags & PLL_FL(OP_SYS_DDR) ? " op-sys-ddr" : "",
+		pll->flags & PLL_FL(OP_PIX_DDR) ? " op-pix-ddr" : "");
+}
+
+static uint32_t op_sys_ddr(uint32_t flags)
+{
+	return flags & CCS_PLL_FLAG_OP_SYS_DDR ? 1 : 0;
+}
+
+static uint32_t op_pix_ddr(uint32_t flags)
+{
+	return flags & CCS_PLL_FLAG_OP_PIX_DDR ? 1 : 0;
 }
 
 static int check_fr_bounds(struct device *dev,
@@ -441,8 +453,8 @@  ccs_pll_calculate_vt(struct device *dev, const struct ccs_pll_limits *lim,
 	if (!(pll->flags & CCS_PLL_FLAG_FIFO_DERATING)) {
 		min_vt_div =
 			op_pll_bk->sys_clk_div * op_pll_bk->pix_clk_div
-			* pll->vt_lanes * phy_const
-			/ pll->op_lanes / PHY_CONST_DIV;
+			* pll->vt_lanes * phy_const / pll->op_lanes
+			/ (PHY_CONST_DIV << op_pix_ddr(pll->flags));
 	} else {
 		/*
 		 * Some sensors perform analogue binning and some do this
@@ -478,7 +490,7 @@  ccs_pll_calculate_vt(struct device *dev, const struct ccs_pll_limits *lim,
 				      CCS_PLL_FLAG_LANE_SPEED_MODEL ?
 				      pll->csi2.lanes : 1)
 				     * vt_op_binning_div * pll->scale_m
-				     * PHY_CONST_DIV);
+				     * PHY_CONST_DIV << op_pix_ddr(pll->flags));
 	}
 
 	/* Find smallest and biggest allowed vt divisor. */
@@ -572,7 +584,8 @@  ccs_pll_calculate_op(struct device *dev, const struct ccs_pll_limits *lim,
 		     const struct ccs_pll_branch_limits_bk *op_lim_bk,
 		     struct ccs_pll *pll, struct ccs_pll_branch_fr *op_pll_fr,
 		     struct ccs_pll_branch_bk *op_pll_bk, uint32_t mul,
-		     uint32_t div, uint32_t l, bool cphy, uint32_t phy_const)
+		     uint32_t div, uint32_t op_sys_clk_freq_hz_sdr, uint32_t l,
+		     bool cphy, uint32_t phy_const)
 {
 	/*
 	 * Higher multipliers (and divisors) are often required than
@@ -658,15 +671,22 @@  ccs_pll_calculate_op(struct device *dev, const struct ccs_pll_limits *lim,
 		* op_pll_fr->pll_multiplier;
 
 	if (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL)
-		op_pll_bk->pix_clk_div = pll->bits_per_pixel
-			* pll->op_lanes * phy_const
-			/ PHY_CONST_DIV / pll->csi2.lanes / l;
+		op_pll_bk->pix_clk_div =
+			(pll->bits_per_pixel
+			 * pll->op_lanes * (phy_const << op_sys_ddr(pll->flags))
+			 / PHY_CONST_DIV / pll->csi2.lanes / l)
+			>> op_pix_ddr(pll->flags);
 	else
 		op_pll_bk->pix_clk_div =
-			pll->bits_per_pixel * phy_const / PHY_CONST_DIV / l;
+			(pll->bits_per_pixel
+			 * (phy_const << op_sys_ddr(pll->flags))
+			 / PHY_CONST_DIV / l) >> op_pix_ddr(pll->flags);
 
 	op_pll_bk->pix_clk_freq_hz =
-		op_pll_bk->sys_clk_freq_hz / op_pll_bk->pix_clk_div;
+		(op_sys_clk_freq_hz_sdr >> op_pix_ddr(pll->flags))
+		/ op_pll_bk->pix_clk_div;
+	op_pll_bk->sys_clk_freq_hz =
+		op_sys_clk_freq_hz_sdr >> op_sys_ddr(pll->flags);
 
 	dev_dbg(dev, "op_pix_clk_div: %u\n", op_pll_bk->pix_clk_div);
 
@@ -682,6 +702,7 @@  int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim,
 	struct ccs_pll_branch_bk *op_pll_bk;
 	bool cphy = pll->bus_type == CCS_PLL_BUS_TYPE_CSI2_CPHY;
 	uint32_t phy_const = cphy ? CPHY_CONST : DPHY_CONST;
+	uint32_t op_sys_clk_freq_hz_sdr;
 	uint16_t min_op_pre_pll_clk_div;
 	uint16_t max_op_pre_pll_clk_div;
 	uint32_t mul, div;
@@ -731,7 +752,8 @@  int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim,
 	 * op_pix_clk_div is supported
 	 */
 	if (!(pll->flags & CCS_PLL_FLAG_FLEXIBLE_OP_PIX_CLK_DIV) &&
-	    (pll->bits_per_pixel * pll->op_lanes) % (pll->csi2.lanes * l)) {
+	    (pll->bits_per_pixel * pll->op_lanes) %
+	    (pll->csi2.lanes * l << op_pix_ddr(pll->flags))) {
 		dev_dbg(dev, "op_pix_clk_div not an integer (bpp %u, op lanes %u, lanes %u, l %u)\n",
 			pll->bits_per_pixel, pll->op_lanes, pll->csi2.lanes, l);
 		return -EINVAL;
@@ -746,12 +768,12 @@  int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim,
 	switch (pll->bus_type) {
 	case CCS_PLL_BUS_TYPE_CSI2_DPHY:
 		/* CSI transfers 2 bits per clock per lane; thus times 2 */
-		op_pll_bk->sys_clk_freq_hz = pll->link_freq * 2
+		op_sys_clk_freq_hz_sdr = pll->link_freq * 2
 			* (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL ?
 			   1 : pll->csi2.lanes);
 		break;
 	case CCS_PLL_BUS_TYPE_CSI2_CPHY:
-		op_pll_bk->sys_clk_freq_hz =
+		op_sys_clk_freq_hz_sdr =
 			pll->link_freq
 			* (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL ?
 			   1 : pll->csi2.lanes);
@@ -761,7 +783,7 @@  int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim,
 	}
 
 	pll->pixel_rate_csi =
-		div_u64((uint64_t)op_pll_bk->sys_clk_freq_hz
+		div_u64((uint64_t)op_sys_clk_freq_hz_sdr
 			* (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL ?
 			   pll->csi2.lanes : 1) * PHY_CONST_DIV,
 			phy_const * pll->bits_per_pixel * l);
@@ -781,9 +803,10 @@  int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim,
 	dev_dbg(dev, "pre-pll check: min / max op_pre_pll_clk_div: %u / %u\n",
 		min_op_pre_pll_clk_div, max_op_pre_pll_clk_div);
 
-	i = gcd(op_pll_bk->sys_clk_freq_hz, pll->ext_clk_freq_hz);
-	mul = op_pll_bk->sys_clk_freq_hz / i;
-	div = pll->ext_clk_freq_hz / i;
+	i = gcd(op_sys_clk_freq_hz_sdr,
+		pll->ext_clk_freq_hz << op_pix_ddr(pll->flags));
+	mul = op_sys_clk_freq_hz_sdr / i;
+	div = (pll->ext_clk_freq_hz << op_pix_ddr(pll->flags)) / i;
 	dev_dbg(dev, "mul %u / div %u\n", mul, div);
 
 	min_op_pre_pll_clk_div =
@@ -802,8 +825,9 @@  int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim,
 		     (pll->flags & CCS_PLL_FLAG_EXT_IP_PLL_DIVIDER) ? 1 :
 		     2 - (op_pll_fr->pre_pll_clk_div & 1)) {
 		rval = ccs_pll_calculate_op(dev, lim, op_lim_fr, op_lim_bk, pll,
-					    op_pll_fr, op_pll_bk, mul, div, l,
-					    cphy, phy_const);
+					    op_pll_fr, op_pll_bk, mul, div,
+					    op_sys_clk_freq_hz_sdr, l, cphy,
+					    phy_const);
 		if (rval)
 			continue;
 
diff --git a/drivers/media/i2c/ccs-pll.h b/drivers/media/i2c/ccs-pll.h
index 1be8f300c860..7d1e6e3eaada 100644
--- a/drivers/media/i2c/ccs-pll.h
+++ b/drivers/media/i2c/ccs-pll.h
@@ -30,6 +30,8 @@ 
 #define CCS_PLL_FLAG_FIFO_DERATING				BIT(6)
 #define CCS_PLL_FLAG_FIFO_OVERRATING				BIT(7)
 #define CCS_PLL_FLAG_DUAL_PLL					BIT(8)
+#define CCS_PLL_FLAG_OP_SYS_DDR					BIT(9)
+#define CCS_PLL_FLAG_OP_PIX_DDR					BIT(10)
 
 /**
  * struct ccs_pll_branch_fr - CCS PLL configuration (front)