media: ccs-pll: Add support for DDR OP system and pixel clocks
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> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
This commit is contained in:
parent
b41f270841
commit
900c33e86e
|
@ -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(LANE_SPEED_MODEL) ? " lane-speed" : "",
|
||||||
pll->flags & PLL_FL(LINK_DECOUPLED) ? " link-decoupled" : "",
|
pll->flags & PLL_FL(LINK_DECOUPLED) ? " link-decoupled" : "",
|
||||||
pll->flags & PLL_FL(EXT_IP_PLL_DIVIDER) ?
|
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" : "",
|
" flexible-op-pix-div" : "",
|
||||||
pll->flags & PLL_FL(FIFO_DERATING) ? " fifo-derating" : "",
|
pll->flags & PLL_FL(FIFO_DERATING) ? " fifo-derating" : "",
|
||||||
pll->flags & PLL_FL(FIFO_OVERRATING) ? " fifo-overrating" : "",
|
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,
|
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)) {
|
if (!(pll->flags & CCS_PLL_FLAG_FIFO_DERATING)) {
|
||||||
min_vt_div =
|
min_vt_div =
|
||||||
op_pll_bk->sys_clk_div * op_pll_bk->pix_clk_div
|
op_pll_bk->sys_clk_div * op_pll_bk->pix_clk_div
|
||||||
* pll->vt_lanes * phy_const
|
* pll->vt_lanes * phy_const / pll->op_lanes
|
||||||
/ pll->op_lanes / PHY_CONST_DIV;
|
/ (PHY_CONST_DIV << op_pix_ddr(pll->flags));
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* Some sensors perform analogue binning and some do this
|
* 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 ?
|
CCS_PLL_FLAG_LANE_SPEED_MODEL ?
|
||||||
pll->csi2.lanes : 1)
|
pll->csi2.lanes : 1)
|
||||||
* vt_op_binning_div * pll->scale_m
|
* 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. */
|
/* 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,
|
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 *pll, struct ccs_pll_branch_fr *op_pll_fr,
|
||||||
struct ccs_pll_branch_bk *op_pll_bk, uint32_t mul,
|
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
|
* 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;
|
* op_pll_fr->pll_multiplier;
|
||||||
|
|
||||||
if (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL)
|
if (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL)
|
||||||
op_pll_bk->pix_clk_div = pll->bits_per_pixel
|
op_pll_bk->pix_clk_div =
|
||||||
* pll->op_lanes * phy_const
|
(pll->bits_per_pixel
|
||||||
/ PHY_CONST_DIV / pll->csi2.lanes / l;
|
* pll->op_lanes * (phy_const << op_sys_ddr(pll->flags))
|
||||||
|
/ PHY_CONST_DIV / pll->csi2.lanes / l)
|
||||||
|
>> op_pix_ddr(pll->flags);
|
||||||
else
|
else
|
||||||
op_pll_bk->pix_clk_div =
|
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->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);
|
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;
|
struct ccs_pll_branch_bk *op_pll_bk;
|
||||||
bool cphy = pll->bus_type == CCS_PLL_BUS_TYPE_CSI2_CPHY;
|
bool cphy = pll->bus_type == CCS_PLL_BUS_TYPE_CSI2_CPHY;
|
||||||
uint32_t phy_const = cphy ? CPHY_CONST : DPHY_CONST;
|
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 min_op_pre_pll_clk_div;
|
||||||
uint16_t max_op_pre_pll_clk_div;
|
uint16_t max_op_pre_pll_clk_div;
|
||||||
uint32_t mul, 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
|
* op_pix_clk_div is supported
|
||||||
*/
|
*/
|
||||||
if (!(pll->flags & CCS_PLL_FLAG_FLEXIBLE_OP_PIX_CLK_DIV) &&
|
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",
|
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);
|
pll->bits_per_pixel, pll->op_lanes, pll->csi2.lanes, l);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -746,12 +768,12 @@ int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim,
|
||||||
switch (pll->bus_type) {
|
switch (pll->bus_type) {
|
||||||
case CCS_PLL_BUS_TYPE_CSI2_DPHY:
|
case CCS_PLL_BUS_TYPE_CSI2_DPHY:
|
||||||
/* CSI transfers 2 bits per clock per lane; thus times 2 */
|
/* 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 ?
|
* (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL ?
|
||||||
1 : pll->csi2.lanes);
|
1 : pll->csi2.lanes);
|
||||||
break;
|
break;
|
||||||
case CCS_PLL_BUS_TYPE_CSI2_CPHY:
|
case CCS_PLL_BUS_TYPE_CSI2_CPHY:
|
||||||
op_pll_bk->sys_clk_freq_hz =
|
op_sys_clk_freq_hz_sdr =
|
||||||
pll->link_freq
|
pll->link_freq
|
||||||
* (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL ?
|
* (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL ?
|
||||||
1 : pll->csi2.lanes);
|
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 =
|
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->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL ?
|
||||||
pll->csi2.lanes : 1) * PHY_CONST_DIV,
|
pll->csi2.lanes : 1) * PHY_CONST_DIV,
|
||||||
phy_const * pll->bits_per_pixel * l);
|
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",
|
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);
|
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);
|
i = gcd(op_sys_clk_freq_hz_sdr,
|
||||||
mul = op_pll_bk->sys_clk_freq_hz / i;
|
pll->ext_clk_freq_hz << op_pix_ddr(pll->flags));
|
||||||
div = pll->ext_clk_freq_hz / i;
|
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);
|
dev_dbg(dev, "mul %u / div %u\n", mul, div);
|
||||||
|
|
||||||
min_op_pre_pll_clk_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 :
|
(pll->flags & CCS_PLL_FLAG_EXT_IP_PLL_DIVIDER) ? 1 :
|
||||||
2 - (op_pll_fr->pre_pll_clk_div & 1)) {
|
2 - (op_pll_fr->pre_pll_clk_div & 1)) {
|
||||||
rval = ccs_pll_calculate_op(dev, lim, op_lim_fr, op_lim_bk, pll,
|
rval = ccs_pll_calculate_op(dev, lim, op_lim_fr, op_lim_bk, pll,
|
||||||
op_pll_fr, op_pll_bk, mul, div, l,
|
op_pll_fr, op_pll_bk, mul, div,
|
||||||
cphy, phy_const);
|
op_sys_clk_freq_hz_sdr, l, cphy,
|
||||||
|
phy_const);
|
||||||
if (rval)
|
if (rval)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,8 @@
|
||||||
#define CCS_PLL_FLAG_FIFO_DERATING BIT(6)
|
#define CCS_PLL_FLAG_FIFO_DERATING BIT(6)
|
||||||
#define CCS_PLL_FLAG_FIFO_OVERRATING BIT(7)
|
#define CCS_PLL_FLAG_FIFO_OVERRATING BIT(7)
|
||||||
#define CCS_PLL_FLAG_DUAL_PLL BIT(8)
|
#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)
|
* struct ccs_pll_branch_fr - CCS PLL configuration (front)
|
||||||
|
|
Loading…
Reference in New Issue