]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
media: smiapp-pll: Rename as ccs-pll
authorSakari Ailus <sakari.ailus@linux.intel.com>
Wed, 27 May 2020 21:59:40 +0000 (23:59 +0200)
committerMauro Carvalho Chehab <mchehab+huawei@kernel.org>
Thu, 3 Dec 2020 11:27:31 +0000 (12:27 +0100)
MIPI CCS replaces SMIA and SMIA++ as the current standard. CCS brings new
features while existing functionality will be supported. Rename the
smiapp-pll as ccs-pll accordingly.

Also add Intel copyright to the files.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
MAINTAINERS
drivers/media/i2c/Kconfig
drivers/media/i2c/Makefile
drivers/media/i2c/ccs-pll.c [new file with mode: 0644]
drivers/media/i2c/ccs-pll.h [new file with mode: 0644]
drivers/media/i2c/ccs/Kconfig
drivers/media/i2c/ccs/ccs-core.c
drivers/media/i2c/ccs/ccs-quirk.c
drivers/media/i2c/ccs/ccs.h
drivers/media/i2c/smiapp-pll.c [deleted file]
drivers/media/i2c/smiapp-pll.h [deleted file]

index dce790484d29d8e55759e0280fed51433c39024e..6380b54bf726a94414e62bf62bde2ac5103263e1 100644 (file)
@@ -11635,9 +11635,9 @@ L:      linux-media@vger.kernel.org
 S:     Maintained
 F:     Documentation/devicetree/bindings/media/i2c/mipi-ccs.yaml
 F:     Documentation/driver-api/media/drivers/ccs/
+F:     drivers/media/i2c/ccs-pll.c
+F:     drivers/media/i2c/ccs-pll.h
 F:     drivers/media/i2c/ccs/
-F:     drivers/media/i2c/smiapp-pll.c
-F:     drivers/media/i2c/smiapp-pll.h
 F:     include/uapi/linux/smiapp.h
 
 MIPS
index 92ff66c34f9340ead22e481bcb9b344069eac89d..2b9d81e4794a4ff9aebce2685b994cf93fc7de50 100644 (file)
@@ -722,7 +722,7 @@ menu "Camera sensor devices"
 config VIDEO_APTINA_PLL
        tristate
 
-config VIDEO_SMIAPP_PLL
+config VIDEO_CCS_PLL
        tristate
 
 config VIDEO_HI556
index bf9fd1bb6bc9ec29a5af982c19c5aaccd785de75..a3149dce21bbc3ac679d9a3b391e304383cebc7d 100644 (file)
@@ -106,7 +106,7 @@ obj-$(CONFIG_VIDEO_S5C73M3) += s5c73m3/
 obj-$(CONFIG_VIDEO_ADP1653)    += adp1653.o
 obj-$(CONFIG_VIDEO_LM3560)     += lm3560.o
 obj-$(CONFIG_VIDEO_LM3646)     += lm3646.o
-obj-$(CONFIG_VIDEO_SMIAPP_PLL) += smiapp-pll.o
+obj-$(CONFIG_VIDEO_CCS_PLL)    += ccs-pll.o
 obj-$(CONFIG_VIDEO_AK881X)             += ak881x.o
 obj-$(CONFIG_VIDEO_IR_I2C)  += ir-kbd-i2c.o
 obj-$(CONFIG_VIDEO_I2C)                += video-i2c.o
diff --git a/drivers/media/i2c/ccs-pll.c b/drivers/media/i2c/ccs-pll.c
new file mode 100644 (file)
index 0000000..d2f0f73
--- /dev/null
@@ -0,0 +1,480 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * drivers/media/i2c/ccs-pll.c
+ *
+ * Generic MIPI CCS/SMIA/SMIA++ PLL calculator
+ *
+ * Copyright (C) 2020 Intel Corporation
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@iki.fi>
+ */
+
+#include <linux/device.h>
+#include <linux/gcd.h>
+#include <linux/lcm.h>
+#include <linux/module.h>
+
+#include "ccs-pll.h"
+
+/* Return an even number or one. */
+static inline uint32_t clk_div_even(uint32_t a)
+{
+       return max_t(uint32_t, 1, a & ~1);
+}
+
+/* Return an even number or one. */
+static inline uint32_t clk_div_even_up(uint32_t a)
+{
+       if (a == 1)
+               return 1;
+       return (a + 1) & ~1;
+}
+
+static inline uint32_t is_one_or_even(uint32_t a)
+{
+       if (a == 1)
+               return 1;
+       if (a & 1)
+               return 0;
+
+       return 1;
+}
+
+static int bounds_check(struct device *dev, uint32_t val,
+                       uint32_t min, uint32_t max, char *str)
+{
+       if (val >= min && val <= max)
+               return 0;
+
+       dev_dbg(dev, "%s out of bounds: %d (%d--%d)\n", str, val, min, max);
+
+       return -EINVAL;
+}
+
+static void print_pll(struct device *dev, struct ccs_pll *pll)
+{
+       dev_dbg(dev, "pre_pll_clk_div\t%u\n",  pll->pre_pll_clk_div);
+       dev_dbg(dev, "pll_multiplier \t%u\n",  pll->pll_multiplier);
+       if (!(pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS)) {
+               dev_dbg(dev, "op_sys_clk_div \t%u\n", pll->op.sys_clk_div);
+               dev_dbg(dev, "op_pix_clk_div \t%u\n", pll->op.pix_clk_div);
+       }
+       dev_dbg(dev, "vt_sys_clk_div \t%u\n",  pll->vt.sys_clk_div);
+       dev_dbg(dev, "vt_pix_clk_div \t%u\n",  pll->vt.pix_clk_div);
+
+       dev_dbg(dev, "ext_clk_freq_hz \t%u\n", pll->ext_clk_freq_hz);
+       dev_dbg(dev, "pll_ip_clk_freq_hz \t%u\n", pll->pll_ip_clk_freq_hz);
+       dev_dbg(dev, "pll_op_clk_freq_hz \t%u\n", pll->pll_op_clk_freq_hz);
+       if (!(pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS)) {
+               dev_dbg(dev, "op_sys_clk_freq_hz \t%u\n",
+                       pll->op.sys_clk_freq_hz);
+               dev_dbg(dev, "op_pix_clk_freq_hz \t%u\n",
+                       pll->op.pix_clk_freq_hz);
+       }
+       dev_dbg(dev, "vt_sys_clk_freq_hz \t%u\n", pll->vt.sys_clk_freq_hz);
+       dev_dbg(dev, "vt_pix_clk_freq_hz \t%u\n", pll->vt.pix_clk_freq_hz);
+}
+
+static int check_all_bounds(struct device *dev,
+                           const struct ccs_pll_limits *limits,
+                           const struct ccs_pll_branch_limits *op_limits,
+                           struct ccs_pll *pll, struct ccs_pll_branch *op_pll)
+{
+       int rval;
+
+       rval = bounds_check(dev, pll->pll_ip_clk_freq_hz,
+                           limits->min_pll_ip_freq_hz,
+                           limits->max_pll_ip_freq_hz,
+                           "pll_ip_clk_freq_hz");
+       if (!rval)
+               rval = bounds_check(
+                       dev, pll->pll_multiplier,
+                       limits->min_pll_multiplier, limits->max_pll_multiplier,
+                       "pll_multiplier");
+       if (!rval)
+               rval = bounds_check(
+                       dev, pll->pll_op_clk_freq_hz,
+                       limits->min_pll_op_freq_hz, limits->max_pll_op_freq_hz,
+                       "pll_op_clk_freq_hz");
+       if (!rval)
+               rval = bounds_check(
+                       dev, op_pll->sys_clk_div,
+                       op_limits->min_sys_clk_div, op_limits->max_sys_clk_div,
+                       "op_sys_clk_div");
+       if (!rval)
+               rval = bounds_check(
+                       dev, op_pll->sys_clk_freq_hz,
+                       op_limits->min_sys_clk_freq_hz,
+                       op_limits->max_sys_clk_freq_hz,
+                       "op_sys_clk_freq_hz");
+       if (!rval)
+               rval = bounds_check(
+                       dev, op_pll->pix_clk_freq_hz,
+                       op_limits->min_pix_clk_freq_hz,
+                       op_limits->max_pix_clk_freq_hz,
+                       "op_pix_clk_freq_hz");
+
+       /*
+        * If there are no OP clocks, the VT clocks are contained in
+        * the OP clock struct.
+        */
+       if (pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS)
+               return rval;
+
+       if (!rval)
+               rval = bounds_check(
+                       dev, pll->vt.sys_clk_freq_hz,
+                       limits->vt.min_sys_clk_freq_hz,
+                       limits->vt.max_sys_clk_freq_hz,
+                       "vt_sys_clk_freq_hz");
+       if (!rval)
+               rval = bounds_check(
+                       dev, pll->vt.pix_clk_freq_hz,
+                       limits->vt.min_pix_clk_freq_hz,
+                       limits->vt.max_pix_clk_freq_hz,
+                       "vt_pix_clk_freq_hz");
+
+       return rval;
+}
+
+/*
+ * Heuristically guess the PLL tree for a given common multiplier and
+ * divisor. Begin with the operational timing and continue to video
+ * timing once operational timing has been verified.
+ *
+ * @mul is the PLL multiplier and @div is the common divisor
+ * (pre_pll_clk_div and op_sys_clk_div combined). The final PLL
+ * multiplier will be a multiple of @mul.
+ *
+ * @return Zero on success, error code on error.
+ */
+static int
+__ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *limits,
+                   const struct ccs_pll_branch_limits *op_limits,
+                   struct ccs_pll *pll, struct ccs_pll_branch *op_pll,
+                   uint32_t mul, uint32_t div, uint32_t lane_op_clock_ratio)
+{
+       uint32_t sys_div;
+       uint32_t best_pix_div = INT_MAX >> 1;
+       uint32_t vt_op_binning_div;
+       /*
+        * Higher multipliers (and divisors) are often required than
+        * necessitated by the external clock and the output clocks.
+        * There are limits for all values in the clock tree. These
+        * are the minimum and maximum multiplier for mul.
+        */
+       uint32_t more_mul_min, more_mul_max;
+       uint32_t more_mul_factor;
+       uint32_t min_vt_div, max_vt_div, vt_div;
+       uint32_t min_sys_div, max_sys_div;
+       unsigned int i;
+
+       /*
+        * Get pre_pll_clk_div so that our pll_op_clk_freq_hz won't be
+        * too high.
+        */
+       dev_dbg(dev, "pre_pll_clk_div %u\n", pll->pre_pll_clk_div);
+
+       /* Don't go above max pll multiplier. */
+       more_mul_max = limits->max_pll_multiplier / mul;
+       dev_dbg(dev, "more_mul_max: max_pll_multiplier check: %u\n",
+               more_mul_max);
+       /* Don't go above max pll op frequency. */
+       more_mul_max =
+               min_t(uint32_t,
+                     more_mul_max,
+                     limits->max_pll_op_freq_hz
+                     / (pll->ext_clk_freq_hz / pll->pre_pll_clk_div * mul));
+       dev_dbg(dev, "more_mul_max: max_pll_op_freq_hz check: %u\n",
+               more_mul_max);
+       /* Don't go above the division capability of op sys clock divider. */
+       more_mul_max = min(more_mul_max,
+                          op_limits->max_sys_clk_div * pll->pre_pll_clk_div
+                          / div);
+       dev_dbg(dev, "more_mul_max: max_op_sys_clk_div check: %u\n",
+               more_mul_max);
+       /* Ensure we won't go above min_pll_multiplier. */
+       more_mul_max = min(more_mul_max,
+                          DIV_ROUND_UP(limits->max_pll_multiplier, mul));
+       dev_dbg(dev, "more_mul_max: min_pll_multiplier check: %u\n",
+               more_mul_max);
+
+       /* Ensure we won't go below min_pll_op_freq_hz. */
+       more_mul_min = DIV_ROUND_UP(limits->min_pll_op_freq_hz,
+                                   pll->ext_clk_freq_hz / pll->pre_pll_clk_div
+                                   * mul);
+       dev_dbg(dev, "more_mul_min: min_pll_op_freq_hz check: %u\n",
+               more_mul_min);
+       /* Ensure we won't go below min_pll_multiplier. */
+       more_mul_min = max(more_mul_min,
+                          DIV_ROUND_UP(limits->min_pll_multiplier, mul));
+       dev_dbg(dev, "more_mul_min: min_pll_multiplier check: %u\n",
+               more_mul_min);
+
+       if (more_mul_min > more_mul_max) {
+               dev_dbg(dev,
+                       "unable to compute more_mul_min and more_mul_max\n");
+               return -EINVAL;
+       }
+
+       more_mul_factor = lcm(div, pll->pre_pll_clk_div) / div;
+       dev_dbg(dev, "more_mul_factor: %u\n", more_mul_factor);
+       more_mul_factor = lcm(more_mul_factor, op_limits->min_sys_clk_div);
+       dev_dbg(dev, "more_mul_factor: min_op_sys_clk_div: %d\n",
+               more_mul_factor);
+       i = roundup(more_mul_min, more_mul_factor);
+       if (!is_one_or_even(i))
+               i <<= 1;
+
+       dev_dbg(dev, "final more_mul: %u\n", i);
+       if (i > more_mul_max) {
+               dev_dbg(dev, "final more_mul is bad, max %u\n", more_mul_max);
+               return -EINVAL;
+       }
+
+       pll->pll_multiplier = mul * i;
+       op_pll->sys_clk_div = div * i / pll->pre_pll_clk_div;
+       dev_dbg(dev, "op_sys_clk_div: %u\n", op_pll->sys_clk_div);
+
+       pll->pll_ip_clk_freq_hz = pll->ext_clk_freq_hz
+               / pll->pre_pll_clk_div;
+
+       pll->pll_op_clk_freq_hz = pll->pll_ip_clk_freq_hz
+               * pll->pll_multiplier;
+
+       /* Derive pll_op_clk_freq_hz. */
+       op_pll->sys_clk_freq_hz =
+               pll->pll_op_clk_freq_hz / op_pll->sys_clk_div;
+
+       op_pll->pix_clk_div = pll->bits_per_pixel;
+       dev_dbg(dev, "op_pix_clk_div: %u\n", op_pll->pix_clk_div);
+
+       op_pll->pix_clk_freq_hz =
+               op_pll->sys_clk_freq_hz / op_pll->pix_clk_div;
+
+       if (pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS) {
+               /* No OP clocks --- VT clocks are used instead. */
+               goto out_skip_vt_calc;
+       }
+
+       /*
+        * Some sensors perform analogue binning and some do this
+        * digitally. The ones doing this digitally can be roughly be
+        * found out using this formula. The ones doing this digitally
+        * should run at higher clock rate, so smaller divisor is used
+        * on video timing side.
+        */
+       if (limits->min_line_length_pck_bin > limits->min_line_length_pck
+           / pll->binning_horizontal)
+               vt_op_binning_div = pll->binning_horizontal;
+       else
+               vt_op_binning_div = 1;
+       dev_dbg(dev, "vt_op_binning_div: %u\n", vt_op_binning_div);
+
+       /*
+        * Profile 2 supports vt_pix_clk_div E [4, 10]
+        *
+        * Horizontal binning can be used as a base for difference in
+        * divisors. One must make sure that horizontal blanking is
+        * enough to accommodate the CSI-2 sync codes.
+        *
+        * Take scaling factor into account as well.
+        *
+        * Find absolute limits for the factor of vt divider.
+        */
+       dev_dbg(dev, "scale_m: %u\n", pll->scale_m);
+       min_vt_div = DIV_ROUND_UP(op_pll->pix_clk_div * op_pll->sys_clk_div
+                                 * pll->scale_n,
+                                 lane_op_clock_ratio * vt_op_binning_div
+                                 * pll->scale_m);
+
+       /* Find smallest and biggest allowed vt divisor. */
+       dev_dbg(dev, "min_vt_div: %u\n", min_vt_div);
+       min_vt_div = max(min_vt_div,
+                        DIV_ROUND_UP(pll->pll_op_clk_freq_hz,
+                                     limits->vt.max_pix_clk_freq_hz));
+       dev_dbg(dev, "min_vt_div: max_vt_pix_clk_freq_hz: %u\n",
+               min_vt_div);
+       min_vt_div = max_t(uint32_t, min_vt_div,
+                          limits->vt.min_pix_clk_div
+                          * limits->vt.min_sys_clk_div);
+       dev_dbg(dev, "min_vt_div: min_vt_clk_div: %u\n", min_vt_div);
+
+       max_vt_div = limits->vt.max_sys_clk_div * limits->vt.max_pix_clk_div;
+       dev_dbg(dev, "max_vt_div: %u\n", max_vt_div);
+       max_vt_div = min(max_vt_div,
+                        DIV_ROUND_UP(pll->pll_op_clk_freq_hz,
+                                     limits->vt.min_pix_clk_freq_hz));
+       dev_dbg(dev, "max_vt_div: min_vt_pix_clk_freq_hz: %u\n",
+               max_vt_div);
+
+       /*
+        * Find limitsits for sys_clk_div. Not all values are possible
+        * with all values of pix_clk_div.
+        */
+       min_sys_div = limits->vt.min_sys_clk_div;
+       dev_dbg(dev, "min_sys_div: %u\n", min_sys_div);
+       min_sys_div = max(min_sys_div,
+                         DIV_ROUND_UP(min_vt_div,
+                                      limits->vt.max_pix_clk_div));
+       dev_dbg(dev, "min_sys_div: max_vt_pix_clk_div: %u\n", min_sys_div);
+       min_sys_div = max(min_sys_div,
+                         pll->pll_op_clk_freq_hz
+                         / limits->vt.max_sys_clk_freq_hz);
+       dev_dbg(dev, "min_sys_div: max_pll_op_clk_freq_hz: %u\n", min_sys_div);
+       min_sys_div = clk_div_even_up(min_sys_div);
+       dev_dbg(dev, "min_sys_div: one or even: %u\n", min_sys_div);
+
+       max_sys_div = limits->vt.max_sys_clk_div;
+       dev_dbg(dev, "max_sys_div: %u\n", max_sys_div);
+       max_sys_div = min(max_sys_div,
+                         DIV_ROUND_UP(max_vt_div,
+                                      limits->vt.min_pix_clk_div));
+       dev_dbg(dev, "max_sys_div: min_vt_pix_clk_div: %u\n", max_sys_div);
+       max_sys_div = min(max_sys_div,
+                         DIV_ROUND_UP(pll->pll_op_clk_freq_hz,
+                                      limits->vt.min_pix_clk_freq_hz));
+       dev_dbg(dev, "max_sys_div: min_vt_pix_clk_freq_hz: %u\n", max_sys_div);
+
+       /*
+        * Find pix_div such that a legal pix_div * sys_div results
+        * into a value which is not smaller than div, the desired
+        * divisor.
+        */
+       for (vt_div = min_vt_div; vt_div <= max_vt_div;
+            vt_div += 2 - (vt_div & 1)) {
+               for (sys_div = min_sys_div;
+                    sys_div <= max_sys_div;
+                    sys_div += 2 - (sys_div & 1)) {
+                       uint16_t pix_div = DIV_ROUND_UP(vt_div, sys_div);
+
+                       if (pix_div < limits->vt.min_pix_clk_div
+                           || pix_div > limits->vt.max_pix_clk_div) {
+                               dev_dbg(dev,
+                                       "pix_div %u too small or too big (%u--%u)\n",
+                                       pix_div,
+                                       limits->vt.min_pix_clk_div,
+                                       limits->vt.max_pix_clk_div);
+                               continue;
+                       }
+
+                       /* Check if this one is better. */
+                       if (pix_div * sys_div
+                           <= roundup(min_vt_div, best_pix_div))
+                               best_pix_div = pix_div;
+               }
+               if (best_pix_div < INT_MAX >> 1)
+                       break;
+       }
+
+       pll->vt.sys_clk_div = DIV_ROUND_UP(min_vt_div, best_pix_div);
+       pll->vt.pix_clk_div = best_pix_div;
+
+       pll->vt.sys_clk_freq_hz =
+               pll->pll_op_clk_freq_hz / pll->vt.sys_clk_div;
+       pll->vt.pix_clk_freq_hz =
+               pll->vt.sys_clk_freq_hz / pll->vt.pix_clk_div;
+
+out_skip_vt_calc:
+       pll->pixel_rate_csi =
+               op_pll->pix_clk_freq_hz * lane_op_clock_ratio;
+       pll->pixel_rate_pixel_array = pll->vt.pix_clk_freq_hz;
+
+       return check_all_bounds(dev, limits, op_limits, pll, op_pll);
+}
+
+int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *limits,
+                     struct ccs_pll *pll)
+{
+       const struct ccs_pll_branch_limits *op_limits = &limits->op;
+       struct ccs_pll_branch *op_pll = &pll->op;
+       uint16_t min_pre_pll_clk_div;
+       uint16_t max_pre_pll_clk_div;
+       uint32_t lane_op_clock_ratio;
+       uint32_t mul, div;
+       unsigned int i;
+       int rval = -EINVAL;
+
+       if (pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS) {
+               /*
+                * If there's no OP PLL at all, use the VT values
+                * instead. The OP values are ignored for the rest of
+                * the PLL calculation.
+                */
+               op_limits = &limits->vt;
+               op_pll = &pll->vt;
+       }
+
+       if (pll->flags & CCS_PLL_FLAG_OP_PIX_CLOCK_PER_LANE)
+               lane_op_clock_ratio = pll->csi2.lanes;
+       else
+               lane_op_clock_ratio = 1;
+       dev_dbg(dev, "lane_op_clock_ratio: %u\n", lane_op_clock_ratio);
+
+       dev_dbg(dev, "binning: %ux%u\n", pll->binning_horizontal,
+               pll->binning_vertical);
+
+       switch (pll->bus_type) {
+       case CCS_PLL_BUS_TYPE_CSI2:
+               /* CSI transfers 2 bits per clock per lane; thus times 2 */
+               pll->pll_op_clk_freq_hz = pll->link_freq * 2
+                       * (pll->csi2.lanes / lane_op_clock_ratio);
+               break;
+       case CCS_PLL_BUS_TYPE_PARALLEL:
+               pll->pll_op_clk_freq_hz = pll->link_freq * pll->bits_per_pixel
+                       / DIV_ROUND_UP(pll->bits_per_pixel,
+                                      pll->parallel.bus_width);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Figure out limits for pre-pll divider based on extclk */
+       dev_dbg(dev, "min / max pre_pll_clk_div: %u / %u\n",
+               limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div);
+       max_pre_pll_clk_div =
+               min_t(uint16_t, limits->max_pre_pll_clk_div,
+                     clk_div_even(pll->ext_clk_freq_hz /
+                                  limits->min_pll_ip_freq_hz));
+       min_pre_pll_clk_div =
+               max_t(uint16_t, limits->min_pre_pll_clk_div,
+                     clk_div_even_up(
+                             DIV_ROUND_UP(pll->ext_clk_freq_hz,
+                                          limits->max_pll_ip_freq_hz)));
+       dev_dbg(dev, "pre-pll check: min / max pre_pll_clk_div: %u / %u\n",
+               min_pre_pll_clk_div, max_pre_pll_clk_div);
+
+       i = gcd(pll->pll_op_clk_freq_hz, pll->ext_clk_freq_hz);
+       mul = div_u64(pll->pll_op_clk_freq_hz, i);
+       div = pll->ext_clk_freq_hz / i;
+       dev_dbg(dev, "mul %u / div %u\n", mul, div);
+
+       min_pre_pll_clk_div =
+               max_t(uint16_t, min_pre_pll_clk_div,
+                     clk_div_even_up(
+                             DIV_ROUND_UP(mul * pll->ext_clk_freq_hz,
+                                          limits->max_pll_op_freq_hz)));
+       dev_dbg(dev, "pll_op check: min / max pre_pll_clk_div: %u / %u\n",
+               min_pre_pll_clk_div, max_pre_pll_clk_div);
+
+       for (pll->pre_pll_clk_div = min_pre_pll_clk_div;
+            pll->pre_pll_clk_div <= max_pre_pll_clk_div;
+            pll->pre_pll_clk_div += 2 - (pll->pre_pll_clk_div & 1)) {
+               rval = __ccs_pll_calculate(dev, limits, op_limits, pll, op_pll,
+                                          mul, div, lane_op_clock_ratio);
+               if (rval)
+                       continue;
+
+               print_pll(dev, pll);
+               return 0;
+       }
+
+       dev_dbg(dev, "unable to compute pre_pll divisor\n");
+
+       return rval;
+}
+EXPORT_SYMBOL_GPL(ccs_pll_calculate);
+
+MODULE_AUTHOR("Sakari Ailus <sakari.ailus@iki.fi>");
+MODULE_DESCRIPTION("Generic MIPI CCS/SMIA/SMIA++ PLL calculator");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/ccs-pll.h b/drivers/media/i2c/ccs-pll.h
new file mode 100644 (file)
index 0000000..88d641e
--- /dev/null
@@ -0,0 +1,99 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * drivers/media/i2c/ccs-pll.h
+ *
+ * Generic MIPI CCS/SMIA/SMIA++ PLL calculator
+ *
+ * Copyright (C) 2020 Intel Corporation
+ * Copyright (C) 2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@iki.fi>
+ */
+
+#ifndef CCS_PLL_H
+#define CCS_PLL_H
+
+/* CSI-2 or CCP-2 */
+#define CCS_PLL_BUS_TYPE_CSI2                          0x00
+#define CCS_PLL_BUS_TYPE_PARALLEL                              0x01
+
+/* op pix clock is for all lanes in total normally */
+#define CCS_PLL_FLAG_OP_PIX_CLOCK_PER_LANE                     (1 << 0)
+#define CCS_PLL_FLAG_NO_OP_CLOCKS                              (1 << 1)
+
+struct ccs_pll_branch {
+       uint16_t sys_clk_div;
+       uint16_t pix_clk_div;
+       uint32_t sys_clk_freq_hz;
+       uint32_t pix_clk_freq_hz;
+};
+
+struct ccs_pll {
+       /* input values */
+       uint8_t bus_type;
+       union {
+               struct {
+                       uint8_t lanes;
+               } csi2;
+               struct {
+                       uint8_t bus_width;
+               } parallel;
+       };
+       unsigned long flags;
+       uint8_t binning_horizontal;
+       uint8_t binning_vertical;
+       uint8_t scale_m;
+       uint8_t scale_n;
+       uint8_t bits_per_pixel;
+       uint32_t link_freq;
+       uint32_t ext_clk_freq_hz;
+
+       /* output values */
+       uint16_t pre_pll_clk_div;
+       uint16_t pll_multiplier;
+       uint32_t pll_ip_clk_freq_hz;
+       uint32_t pll_op_clk_freq_hz;
+       struct ccs_pll_branch vt;
+       struct ccs_pll_branch op;
+
+       uint32_t pixel_rate_csi;
+       uint32_t pixel_rate_pixel_array;
+};
+
+struct ccs_pll_branch_limits {
+       uint16_t min_sys_clk_div;
+       uint16_t max_sys_clk_div;
+       uint32_t min_sys_clk_freq_hz;
+       uint32_t max_sys_clk_freq_hz;
+       uint16_t min_pix_clk_div;
+       uint16_t max_pix_clk_div;
+       uint32_t min_pix_clk_freq_hz;
+       uint32_t max_pix_clk_freq_hz;
+};
+
+struct ccs_pll_limits {
+       /* Strict PLL limits */
+       uint32_t min_ext_clk_freq_hz;
+       uint32_t max_ext_clk_freq_hz;
+       uint16_t min_pre_pll_clk_div;
+       uint16_t max_pre_pll_clk_div;
+       uint32_t min_pll_ip_freq_hz;
+       uint32_t max_pll_ip_freq_hz;
+       uint16_t min_pll_multiplier;
+       uint16_t max_pll_multiplier;
+       uint32_t min_pll_op_freq_hz;
+       uint32_t max_pll_op_freq_hz;
+
+       struct ccs_pll_branch_limits vt;
+       struct ccs_pll_branch_limits op;
+
+       /* Other relevant limits */
+       uint32_t min_line_length_pck_bin;
+       uint32_t min_line_length_pck;
+};
+
+struct device;
+
+int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *limits,
+                     struct ccs_pll *pll);
+
+#endif /* CCS_PLL_H */
index b4f8b10da42049fbc02a03ef521101aca874c1e6..59f35b33ddc1862d38b4cb7a750e6b285c5970a8 100644 (file)
@@ -4,7 +4,7 @@ config VIDEO_CCS
        depends on I2C && VIDEO_V4L2 && HAVE_CLK
        select MEDIA_CONTROLLER
        select VIDEO_V4L2_SUBDEV_API
-       select VIDEO_SMIAPP_PLL
+       select VIDEO_CCS_PLL
        select V4L2_FWNODE
        help
          This is a generic driver for MIPI CCS, SMIA++ and SMIA compliant
index 074b246538d29eab715359d32aa1a1e479b0ecca..6c8528e6ac962361c04e367b947ffb5dc4b6aa72 100644 (file)
@@ -363,7 +363,7 @@ static int ccs_read_frame_fmt(struct ccs_sensor *sensor)
 
 static int ccs_pll_configure(struct ccs_sensor *sensor)
 {
-       struct smiapp_pll *pll = &sensor->pll;
+       struct ccs_pll *pll = &sensor->pll;
        int rval;
 
        rval = ccs_write(sensor, VT_PIX_CLK_DIV, pll->vt.pix_clk_div);
@@ -386,7 +386,7 @@ static int ccs_pll_configure(struct ccs_sensor *sensor)
        rval = ccs_write(sensor, REQUESTED_LINK_RATE,
                         DIV_ROUND_UP(pll->op.sys_clk_freq_hz,
                                      1000000 / 256 / 256));
-       if (rval < 0 || sensor->pll.flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS)
+       if (rval < 0 || sensor->pll.flags & CCS_PLL_FLAG_NO_OP_CLOCKS)
                return rval;
 
        rval = ccs_write(sensor, OP_PIX_CLK_DIV, pll->op.pix_clk_div);
@@ -396,10 +396,10 @@ static int ccs_pll_configure(struct ccs_sensor *sensor)
        return ccs_write(sensor, OP_SYS_CLK_DIV, pll->op.sys_clk_div);
 }
 
-static int ccs_pll_try(struct ccs_sensor *sensor, struct smiapp_pll *pll)
+static int ccs_pll_try(struct ccs_sensor *sensor, struct ccs_pll *pll)
 {
        struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
-       struct smiapp_pll_limits lim = {
+       struct ccs_pll_limits lim = {
                .min_pre_pll_clk_div = CCS_LIM(sensor, MIN_PRE_PLL_CLK_DIV),
                .max_pre_pll_clk_div = CCS_LIM(sensor, MAX_PRE_PLL_CLK_DIV),
                .min_pll_ip_freq_hz = CCS_LIM(sensor, MIN_PLL_IP_CLK_FREQ_MHZ),
@@ -431,12 +431,12 @@ static int ccs_pll_try(struct ccs_sensor *sensor, struct smiapp_pll *pll)
                .min_line_length_pck = CCS_LIM(sensor, MIN_LINE_LENGTH_PCK),
        };
 
-       return smiapp_pll_calculate(&client->dev, &lim, pll);
+       return ccs_pll_calculate(&client->dev, &lim, pll);
 }
 
 static int ccs_pll_update(struct ccs_sensor *sensor)
 {
-       struct smiapp_pll *pll = &sensor->pll;
+       struct ccs_pll *pll = &sensor->pll;
        int rval;
 
        pll->binning_horizontal = sensor->binning_horizontal;
@@ -829,7 +829,7 @@ static void ccs_free_controls(struct ccs_sensor *sensor)
 static int ccs_get_mbus_formats(struct ccs_sensor *sensor)
 {
        struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
-       struct smiapp_pll *pll = &sensor->pll;
+       struct ccs_pll *pll = &sensor->pll;
        u8 compressed_max_bpp = 0;
        unsigned int type, n;
        unsigned int i, pixel_order;
@@ -3155,7 +3155,7 @@ static int ccs_probe(struct i2c_client *client)
            !CCS_LIM(sensor, MIN_OP_PIX_CLK_DIV) ||
            !CCS_LIM(sensor, MAX_OP_PIX_CLK_DIV)) {
                /* No OP clock branch */
-               sensor->pll.flags |= SMIAPP_PLL_FLAG_NO_OP_CLOCKS;
+               sensor->pll.flags |= CCS_PLL_FLAG_NO_OP_CLOCKS;
        } else if (CCS_LIM(sensor, SCALING_CAPABILITY)
                   != CCS_SCALING_CAPABILITY_NONE ||
                   CCS_LIM(sensor, DIGITAL_CROP_CAPABILITY)
@@ -3172,7 +3172,7 @@ static int ccs_probe(struct i2c_client *client)
        sensor->scale_m = CCS_LIM(sensor, SCALER_N_MIN);
 
        /* prepare PLL configuration input values */
-       sensor->pll.bus_type = SMIAPP_PLL_BUS_TYPE_CSI2;
+       sensor->pll.bus_type = CCS_PLL_BUS_TYPE_CSI2;
        sensor->pll.csi2.lanes = sensor->hwcfg.lanes;
        sensor->pll.ext_clk_freq_hz = sensor->hwcfg.ext_clk;
        sensor->pll.scale_n = CCS_LIM(sensor, SCALER_N_MIN);
index 07c5733b424495565a9f0f38c2861c0e6ee1e908..8b4fa60044b2d0e820f94f7af24c7ff688972245 100644 (file)
@@ -190,7 +190,7 @@ static int jt8ev1_post_streamoff(struct ccs_sensor *sensor)
 
 static int jt8ev1_init(struct ccs_sensor *sensor)
 {
-       sensor->pll.flags |= SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE;
+       sensor->pll.flags |= CCS_PLL_FLAG_OP_PIX_CLOCK_PER_LANE;
 
        return 0;
 }
index f60d1801c46995b4e4c0ee9735ef3d1dbb1fb2f8..c8a9f4ee093e0732dead9a984f7c09422660b8f5 100644 (file)
@@ -21,7 +21,7 @@
 #include "ccs-quirk.h"
 #include "ccs-regs.h"
 #include "ccs-reg-access.h"
-#include "../smiapp-pll.h"
+#include "../ccs-pll.h"
 #include "smiapp-reg-defs.h"
 
 /*
@@ -256,7 +256,7 @@ struct ccs_sensor {
 
        struct ccs_module_info minfo;
 
-       struct smiapp_pll pll;
+       struct ccs_pll pll;
 
        /* Is a default format supported for a given BPP? */
        unsigned long *valid_link_freqs;
diff --git a/drivers/media/i2c/smiapp-pll.c b/drivers/media/i2c/smiapp-pll.c
deleted file mode 100644 (file)
index 690abe8..0000000
+++ /dev/null
@@ -1,482 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * drivers/media/i2c/smiapp-pll.c
- *
- * Generic driver for SMIA/SMIA++ compliant camera modules
- *
- * Copyright (C) 2011--2012 Nokia Corporation
- * Contact: Sakari Ailus <sakari.ailus@iki.fi>
- */
-
-#include <linux/device.h>
-#include <linux/gcd.h>
-#include <linux/lcm.h>
-#include <linux/module.h>
-
-#include "smiapp-pll.h"
-
-/* Return an even number or one. */
-static inline uint32_t clk_div_even(uint32_t a)
-{
-       return max_t(uint32_t, 1, a & ~1);
-}
-
-/* Return an even number or one. */
-static inline uint32_t clk_div_even_up(uint32_t a)
-{
-       if (a == 1)
-               return 1;
-       return (a + 1) & ~1;
-}
-
-static inline uint32_t is_one_or_even(uint32_t a)
-{
-       if (a == 1)
-               return 1;
-       if (a & 1)
-               return 0;
-
-       return 1;
-}
-
-static int bounds_check(struct device *dev, uint32_t val,
-                       uint32_t min, uint32_t max, char *str)
-{
-       if (val >= min && val <= max)
-               return 0;
-
-       dev_dbg(dev, "%s out of bounds: %d (%d--%d)\n", str, val, min, max);
-
-       return -EINVAL;
-}
-
-static void print_pll(struct device *dev, struct smiapp_pll *pll)
-{
-       dev_dbg(dev, "pre_pll_clk_div\t%u\n",  pll->pre_pll_clk_div);
-       dev_dbg(dev, "pll_multiplier \t%u\n",  pll->pll_multiplier);
-       if (!(pll->flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS)) {
-               dev_dbg(dev, "op_sys_clk_div \t%u\n", pll->op.sys_clk_div);
-               dev_dbg(dev, "op_pix_clk_div \t%u\n", pll->op.pix_clk_div);
-       }
-       dev_dbg(dev, "vt_sys_clk_div \t%u\n",  pll->vt.sys_clk_div);
-       dev_dbg(dev, "vt_pix_clk_div \t%u\n",  pll->vt.pix_clk_div);
-
-       dev_dbg(dev, "ext_clk_freq_hz \t%u\n", pll->ext_clk_freq_hz);
-       dev_dbg(dev, "pll_ip_clk_freq_hz \t%u\n", pll->pll_ip_clk_freq_hz);
-       dev_dbg(dev, "pll_op_clk_freq_hz \t%u\n", pll->pll_op_clk_freq_hz);
-       if (!(pll->flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS)) {
-               dev_dbg(dev, "op_sys_clk_freq_hz \t%u\n",
-                       pll->op.sys_clk_freq_hz);
-               dev_dbg(dev, "op_pix_clk_freq_hz \t%u\n",
-                       pll->op.pix_clk_freq_hz);
-       }
-       dev_dbg(dev, "vt_sys_clk_freq_hz \t%u\n", pll->vt.sys_clk_freq_hz);
-       dev_dbg(dev, "vt_pix_clk_freq_hz \t%u\n", pll->vt.pix_clk_freq_hz);
-}
-
-static int check_all_bounds(struct device *dev,
-                           const struct smiapp_pll_limits *limits,
-                           const struct smiapp_pll_branch_limits *op_limits,
-                           struct smiapp_pll *pll,
-                           struct smiapp_pll_branch *op_pll)
-{
-       int rval;
-
-       rval = bounds_check(dev, pll->pll_ip_clk_freq_hz,
-                           limits->min_pll_ip_freq_hz,
-                           limits->max_pll_ip_freq_hz,
-                           "pll_ip_clk_freq_hz");
-       if (!rval)
-               rval = bounds_check(
-                       dev, pll->pll_multiplier,
-                       limits->min_pll_multiplier, limits->max_pll_multiplier,
-                       "pll_multiplier");
-       if (!rval)
-               rval = bounds_check(
-                       dev, pll->pll_op_clk_freq_hz,
-                       limits->min_pll_op_freq_hz, limits->max_pll_op_freq_hz,
-                       "pll_op_clk_freq_hz");
-       if (!rval)
-               rval = bounds_check(
-                       dev, op_pll->sys_clk_div,
-                       op_limits->min_sys_clk_div, op_limits->max_sys_clk_div,
-                       "op_sys_clk_div");
-       if (!rval)
-               rval = bounds_check(
-                       dev, op_pll->sys_clk_freq_hz,
-                       op_limits->min_sys_clk_freq_hz,
-                       op_limits->max_sys_clk_freq_hz,
-                       "op_sys_clk_freq_hz");
-       if (!rval)
-               rval = bounds_check(
-                       dev, op_pll->pix_clk_freq_hz,
-                       op_limits->min_pix_clk_freq_hz,
-                       op_limits->max_pix_clk_freq_hz,
-                       "op_pix_clk_freq_hz");
-
-       /*
-        * If there are no OP clocks, the VT clocks are contained in
-        * the OP clock struct.
-        */
-       if (pll->flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS)
-               return rval;
-
-       if (!rval)
-               rval = bounds_check(
-                       dev, pll->vt.sys_clk_freq_hz,
-                       limits->vt.min_sys_clk_freq_hz,
-                       limits->vt.max_sys_clk_freq_hz,
-                       "vt_sys_clk_freq_hz");
-       if (!rval)
-               rval = bounds_check(
-                       dev, pll->vt.pix_clk_freq_hz,
-                       limits->vt.min_pix_clk_freq_hz,
-                       limits->vt.max_pix_clk_freq_hz,
-                       "vt_pix_clk_freq_hz");
-
-       return rval;
-}
-
-/*
- * Heuristically guess the PLL tree for a given common multiplier and
- * divisor. Begin with the operational timing and continue to video
- * timing once operational timing has been verified.
- *
- * @mul is the PLL multiplier and @div is the common divisor
- * (pre_pll_clk_div and op_sys_clk_div combined). The final PLL
- * multiplier will be a multiple of @mul.
- *
- * @return Zero on success, error code on error.
- */
-static int __smiapp_pll_calculate(
-       struct device *dev, const struct smiapp_pll_limits *limits,
-       const struct smiapp_pll_branch_limits *op_limits,
-       struct smiapp_pll *pll, struct smiapp_pll_branch *op_pll, uint32_t mul,
-       uint32_t div, uint32_t lane_op_clock_ratio)
-{
-       uint32_t sys_div;
-       uint32_t best_pix_div = INT_MAX >> 1;
-       uint32_t vt_op_binning_div;
-       /*
-        * Higher multipliers (and divisors) are often required than
-        * necessitated by the external clock and the output clocks.
-        * There are limits for all values in the clock tree. These
-        * are the minimum and maximum multiplier for mul.
-        */
-       uint32_t more_mul_min, more_mul_max;
-       uint32_t more_mul_factor;
-       uint32_t min_vt_div, max_vt_div, vt_div;
-       uint32_t min_sys_div, max_sys_div;
-       unsigned int i;
-
-       /*
-        * Get pre_pll_clk_div so that our pll_op_clk_freq_hz won't be
-        * too high.
-        */
-       dev_dbg(dev, "pre_pll_clk_div %u\n", pll->pre_pll_clk_div);
-
-       /* Don't go above max pll multiplier. */
-       more_mul_max = limits->max_pll_multiplier / mul;
-       dev_dbg(dev, "more_mul_max: max_pll_multiplier check: %u\n",
-               more_mul_max);
-       /* Don't go above max pll op frequency. */
-       more_mul_max =
-               min_t(uint32_t,
-                     more_mul_max,
-                     limits->max_pll_op_freq_hz
-                     / (pll->ext_clk_freq_hz / pll->pre_pll_clk_div * mul));
-       dev_dbg(dev, "more_mul_max: max_pll_op_freq_hz check: %u\n",
-               more_mul_max);
-       /* Don't go above the division capability of op sys clock divider. */
-       more_mul_max = min(more_mul_max,
-                          op_limits->max_sys_clk_div * pll->pre_pll_clk_div
-                          / div);
-       dev_dbg(dev, "more_mul_max: max_op_sys_clk_div check: %u\n",
-               more_mul_max);
-       /* Ensure we won't go above min_pll_multiplier. */
-       more_mul_max = min(more_mul_max,
-                          DIV_ROUND_UP(limits->max_pll_multiplier, mul));
-       dev_dbg(dev, "more_mul_max: min_pll_multiplier check: %u\n",
-               more_mul_max);
-
-       /* Ensure we won't go below min_pll_op_freq_hz. */
-       more_mul_min = DIV_ROUND_UP(limits->min_pll_op_freq_hz,
-                                   pll->ext_clk_freq_hz / pll->pre_pll_clk_div
-                                   * mul);
-       dev_dbg(dev, "more_mul_min: min_pll_op_freq_hz check: %u\n",
-               more_mul_min);
-       /* Ensure we won't go below min_pll_multiplier. */
-       more_mul_min = max(more_mul_min,
-                          DIV_ROUND_UP(limits->min_pll_multiplier, mul));
-       dev_dbg(dev, "more_mul_min: min_pll_multiplier check: %u\n",
-               more_mul_min);
-
-       if (more_mul_min > more_mul_max) {
-               dev_dbg(dev,
-                       "unable to compute more_mul_min and more_mul_max\n");
-               return -EINVAL;
-       }
-
-       more_mul_factor = lcm(div, pll->pre_pll_clk_div) / div;
-       dev_dbg(dev, "more_mul_factor: %u\n", more_mul_factor);
-       more_mul_factor = lcm(more_mul_factor, op_limits->min_sys_clk_div);
-       dev_dbg(dev, "more_mul_factor: min_op_sys_clk_div: %d\n",
-               more_mul_factor);
-       i = roundup(more_mul_min, more_mul_factor);
-       if (!is_one_or_even(i))
-               i <<= 1;
-
-       dev_dbg(dev, "final more_mul: %u\n", i);
-       if (i > more_mul_max) {
-               dev_dbg(dev, "final more_mul is bad, max %u\n", more_mul_max);
-               return -EINVAL;
-       }
-
-       pll->pll_multiplier = mul * i;
-       op_pll->sys_clk_div = div * i / pll->pre_pll_clk_div;
-       dev_dbg(dev, "op_sys_clk_div: %u\n", op_pll->sys_clk_div);
-
-       pll->pll_ip_clk_freq_hz = pll->ext_clk_freq_hz
-               / pll->pre_pll_clk_div;
-
-       pll->pll_op_clk_freq_hz = pll->pll_ip_clk_freq_hz
-               * pll->pll_multiplier;
-
-       /* Derive pll_op_clk_freq_hz. */
-       op_pll->sys_clk_freq_hz =
-               pll->pll_op_clk_freq_hz / op_pll->sys_clk_div;
-
-       op_pll->pix_clk_div = pll->bits_per_pixel;
-       dev_dbg(dev, "op_pix_clk_div: %u\n", op_pll->pix_clk_div);
-
-       op_pll->pix_clk_freq_hz =
-               op_pll->sys_clk_freq_hz / op_pll->pix_clk_div;
-
-       if (pll->flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS) {
-               /* No OP clocks --- VT clocks are used instead. */
-               goto out_skip_vt_calc;
-       }
-
-       /*
-        * Some sensors perform analogue binning and some do this
-        * digitally. The ones doing this digitally can be roughly be
-        * found out using this formula. The ones doing this digitally
-        * should run at higher clock rate, so smaller divisor is used
-        * on video timing side.
-        */
-       if (limits->min_line_length_pck_bin > limits->min_line_length_pck
-           / pll->binning_horizontal)
-               vt_op_binning_div = pll->binning_horizontal;
-       else
-               vt_op_binning_div = 1;
-       dev_dbg(dev, "vt_op_binning_div: %u\n", vt_op_binning_div);
-
-       /*
-        * Profile 2 supports vt_pix_clk_div E [4, 10]
-        *
-        * Horizontal binning can be used as a base for difference in
-        * divisors. One must make sure that horizontal blanking is
-        * enough to accommodate the CSI-2 sync codes.
-        *
-        * Take scaling factor into account as well.
-        *
-        * Find absolute limits for the factor of vt divider.
-        */
-       dev_dbg(dev, "scale_m: %u\n", pll->scale_m);
-       min_vt_div = DIV_ROUND_UP(op_pll->pix_clk_div * op_pll->sys_clk_div
-                                 * pll->scale_n,
-                                 lane_op_clock_ratio * vt_op_binning_div
-                                 * pll->scale_m);
-
-       /* Find smallest and biggest allowed vt divisor. */
-       dev_dbg(dev, "min_vt_div: %u\n", min_vt_div);
-       min_vt_div = max(min_vt_div,
-                        DIV_ROUND_UP(pll->pll_op_clk_freq_hz,
-                                     limits->vt.max_pix_clk_freq_hz));
-       dev_dbg(dev, "min_vt_div: max_vt_pix_clk_freq_hz: %u\n",
-               min_vt_div);
-       min_vt_div = max_t(uint32_t, min_vt_div,
-                          limits->vt.min_pix_clk_div
-                          * limits->vt.min_sys_clk_div);
-       dev_dbg(dev, "min_vt_div: min_vt_clk_div: %u\n", min_vt_div);
-
-       max_vt_div = limits->vt.max_sys_clk_div * limits->vt.max_pix_clk_div;
-       dev_dbg(dev, "max_vt_div: %u\n", max_vt_div);
-       max_vt_div = min(max_vt_div,
-                        DIV_ROUND_UP(pll->pll_op_clk_freq_hz,
-                                     limits->vt.min_pix_clk_freq_hz));
-       dev_dbg(dev, "max_vt_div: min_vt_pix_clk_freq_hz: %u\n",
-               max_vt_div);
-
-       /*
-        * Find limitsits for sys_clk_div. Not all values are possible
-        * with all values of pix_clk_div.
-        */
-       min_sys_div = limits->vt.min_sys_clk_div;
-       dev_dbg(dev, "min_sys_div: %u\n", min_sys_div);
-       min_sys_div = max(min_sys_div,
-                         DIV_ROUND_UP(min_vt_div,
-                                      limits->vt.max_pix_clk_div));
-       dev_dbg(dev, "min_sys_div: max_vt_pix_clk_div: %u\n", min_sys_div);
-       min_sys_div = max(min_sys_div,
-                         pll->pll_op_clk_freq_hz
-                         / limits->vt.max_sys_clk_freq_hz);
-       dev_dbg(dev, "min_sys_div: max_pll_op_clk_freq_hz: %u\n", min_sys_div);
-       min_sys_div = clk_div_even_up(min_sys_div);
-       dev_dbg(dev, "min_sys_div: one or even: %u\n", min_sys_div);
-
-       max_sys_div = limits->vt.max_sys_clk_div;
-       dev_dbg(dev, "max_sys_div: %u\n", max_sys_div);
-       max_sys_div = min(max_sys_div,
-                         DIV_ROUND_UP(max_vt_div,
-                                      limits->vt.min_pix_clk_div));
-       dev_dbg(dev, "max_sys_div: min_vt_pix_clk_div: %u\n", max_sys_div);
-       max_sys_div = min(max_sys_div,
-                         DIV_ROUND_UP(pll->pll_op_clk_freq_hz,
-                                      limits->vt.min_pix_clk_freq_hz));
-       dev_dbg(dev, "max_sys_div: min_vt_pix_clk_freq_hz: %u\n", max_sys_div);
-
-       /*
-        * Find pix_div such that a legal pix_div * sys_div results
-        * into a value which is not smaller than div, the desired
-        * divisor.
-        */
-       for (vt_div = min_vt_div; vt_div <= max_vt_div;
-            vt_div += 2 - (vt_div & 1)) {
-               for (sys_div = min_sys_div;
-                    sys_div <= max_sys_div;
-                    sys_div += 2 - (sys_div & 1)) {
-                       uint16_t pix_div = DIV_ROUND_UP(vt_div, sys_div);
-
-                       if (pix_div < limits->vt.min_pix_clk_div
-                           || pix_div > limits->vt.max_pix_clk_div) {
-                               dev_dbg(dev,
-                                       "pix_div %u too small or too big (%u--%u)\n",
-                                       pix_div,
-                                       limits->vt.min_pix_clk_div,
-                                       limits->vt.max_pix_clk_div);
-                               continue;
-                       }
-
-                       /* Check if this one is better. */
-                       if (pix_div * sys_div
-                           <= roundup(min_vt_div, best_pix_div))
-                               best_pix_div = pix_div;
-               }
-               if (best_pix_div < INT_MAX >> 1)
-                       break;
-       }
-
-       pll->vt.sys_clk_div = DIV_ROUND_UP(min_vt_div, best_pix_div);
-       pll->vt.pix_clk_div = best_pix_div;
-
-       pll->vt.sys_clk_freq_hz =
-               pll->pll_op_clk_freq_hz / pll->vt.sys_clk_div;
-       pll->vt.pix_clk_freq_hz =
-               pll->vt.sys_clk_freq_hz / pll->vt.pix_clk_div;
-
-out_skip_vt_calc:
-       pll->pixel_rate_csi =
-               op_pll->pix_clk_freq_hz * lane_op_clock_ratio;
-       pll->pixel_rate_pixel_array = pll->vt.pix_clk_freq_hz;
-
-       return check_all_bounds(dev, limits, op_limits, pll, op_pll);
-}
-
-int smiapp_pll_calculate(struct device *dev,
-                        const struct smiapp_pll_limits *limits,
-                        struct smiapp_pll *pll)
-{
-       const struct smiapp_pll_branch_limits *op_limits = &limits->op;
-       struct smiapp_pll_branch *op_pll = &pll->op;
-       uint16_t min_pre_pll_clk_div;
-       uint16_t max_pre_pll_clk_div;
-       uint32_t lane_op_clock_ratio;
-       uint32_t mul, div;
-       unsigned int i;
-       int rval = -EINVAL;
-
-       if (pll->flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS) {
-               /*
-                * If there's no OP PLL at all, use the VT values
-                * instead. The OP values are ignored for the rest of
-                * the PLL calculation.
-                */
-               op_limits = &limits->vt;
-               op_pll = &pll->vt;
-       }
-
-       if (pll->flags & SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE)
-               lane_op_clock_ratio = pll->csi2.lanes;
-       else
-               lane_op_clock_ratio = 1;
-       dev_dbg(dev, "lane_op_clock_ratio: %u\n", lane_op_clock_ratio);
-
-       dev_dbg(dev, "binning: %ux%u\n", pll->binning_horizontal,
-               pll->binning_vertical);
-
-       switch (pll->bus_type) {
-       case SMIAPP_PLL_BUS_TYPE_CSI2:
-               /* CSI transfers 2 bits per clock per lane; thus times 2 */
-               pll->pll_op_clk_freq_hz = pll->link_freq * 2
-                       * (pll->csi2.lanes / lane_op_clock_ratio);
-               break;
-       case SMIAPP_PLL_BUS_TYPE_PARALLEL:
-               pll->pll_op_clk_freq_hz = pll->link_freq * pll->bits_per_pixel
-                       / DIV_ROUND_UP(pll->bits_per_pixel,
-                                      pll->parallel.bus_width);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       /* Figure out limits for pre-pll divider based on extclk */
-       dev_dbg(dev, "min / max pre_pll_clk_div: %u / %u\n",
-               limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div);
-       max_pre_pll_clk_div =
-               min_t(uint16_t, limits->max_pre_pll_clk_div,
-                     clk_div_even(pll->ext_clk_freq_hz /
-                                  limits->min_pll_ip_freq_hz));
-       min_pre_pll_clk_div =
-               max_t(uint16_t, limits->min_pre_pll_clk_div,
-                     clk_div_even_up(
-                             DIV_ROUND_UP(pll->ext_clk_freq_hz,
-                                          limits->max_pll_ip_freq_hz)));
-       dev_dbg(dev, "pre-pll check: min / max pre_pll_clk_div: %u / %u\n",
-               min_pre_pll_clk_div, max_pre_pll_clk_div);
-
-       i = gcd(pll->pll_op_clk_freq_hz, pll->ext_clk_freq_hz);
-       mul = div_u64(pll->pll_op_clk_freq_hz, i);
-       div = pll->ext_clk_freq_hz / i;
-       dev_dbg(dev, "mul %u / div %u\n", mul, div);
-
-       min_pre_pll_clk_div =
-               max_t(uint16_t, min_pre_pll_clk_div,
-                     clk_div_even_up(
-                             DIV_ROUND_UP(mul * pll->ext_clk_freq_hz,
-                                          limits->max_pll_op_freq_hz)));
-       dev_dbg(dev, "pll_op check: min / max pre_pll_clk_div: %u / %u\n",
-               min_pre_pll_clk_div, max_pre_pll_clk_div);
-
-       for (pll->pre_pll_clk_div = min_pre_pll_clk_div;
-            pll->pre_pll_clk_div <= max_pre_pll_clk_div;
-            pll->pre_pll_clk_div += 2 - (pll->pre_pll_clk_div & 1)) {
-               rval = __smiapp_pll_calculate(dev, limits, op_limits, pll,
-                                             op_pll, mul, div,
-                                             lane_op_clock_ratio);
-               if (rval)
-                       continue;
-
-               print_pll(dev, pll);
-               return 0;
-       }
-
-       dev_dbg(dev, "unable to compute pre_pll divisor\n");
-
-       return rval;
-}
-EXPORT_SYMBOL_GPL(smiapp_pll_calculate);
-
-MODULE_AUTHOR("Sakari Ailus <sakari.ailus@iki.fi>");
-MODULE_DESCRIPTION("Generic SMIA/SMIA++ PLL calculator");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/smiapp-pll.h b/drivers/media/i2c/smiapp-pll.h
deleted file mode 100644 (file)
index bd6902f..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * drivers/media/i2c/smiapp-pll.h
- *
- * Generic driver for SMIA/SMIA++ compliant camera modules
- *
- * Copyright (C) 2012 Nokia Corporation
- * Contact: Sakari Ailus <sakari.ailus@iki.fi>
- */
-
-#ifndef SMIAPP_PLL_H
-#define SMIAPP_PLL_H
-
-/* CSI-2 or CCP-2 */
-#define SMIAPP_PLL_BUS_TYPE_CSI2                               0x00
-#define SMIAPP_PLL_BUS_TYPE_PARALLEL                           0x01
-
-/* op pix clock is for all lanes in total normally */
-#define SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE                  (1 << 0)
-#define SMIAPP_PLL_FLAG_NO_OP_CLOCKS                           (1 << 1)
-
-struct smiapp_pll_branch {
-       uint16_t sys_clk_div;
-       uint16_t pix_clk_div;
-       uint32_t sys_clk_freq_hz;
-       uint32_t pix_clk_freq_hz;
-};
-
-struct smiapp_pll {
-       /* input values */
-       uint8_t bus_type;
-       union {
-               struct {
-                       uint8_t lanes;
-               } csi2;
-               struct {
-                       uint8_t bus_width;
-               } parallel;
-       };
-       unsigned long flags;
-       uint8_t binning_horizontal;
-       uint8_t binning_vertical;
-       uint8_t scale_m;
-       uint8_t scale_n;
-       uint8_t bits_per_pixel;
-       uint32_t link_freq;
-       uint32_t ext_clk_freq_hz;
-
-       /* output values */
-       uint16_t pre_pll_clk_div;
-       uint16_t pll_multiplier;
-       uint32_t pll_ip_clk_freq_hz;
-       uint32_t pll_op_clk_freq_hz;
-       struct smiapp_pll_branch vt;
-       struct smiapp_pll_branch op;
-
-       uint32_t pixel_rate_csi;
-       uint32_t pixel_rate_pixel_array;
-};
-
-struct smiapp_pll_branch_limits {
-       uint16_t min_sys_clk_div;
-       uint16_t max_sys_clk_div;
-       uint32_t min_sys_clk_freq_hz;
-       uint32_t max_sys_clk_freq_hz;
-       uint16_t min_pix_clk_div;
-       uint16_t max_pix_clk_div;
-       uint32_t min_pix_clk_freq_hz;
-       uint32_t max_pix_clk_freq_hz;
-};
-
-struct smiapp_pll_limits {
-       /* Strict PLL limits */
-       uint32_t min_ext_clk_freq_hz;
-       uint32_t max_ext_clk_freq_hz;
-       uint16_t min_pre_pll_clk_div;
-       uint16_t max_pre_pll_clk_div;
-       uint32_t min_pll_ip_freq_hz;
-       uint32_t max_pll_ip_freq_hz;
-       uint16_t min_pll_multiplier;
-       uint16_t max_pll_multiplier;
-       uint32_t min_pll_op_freq_hz;
-       uint32_t max_pll_op_freq_hz;
-
-       struct smiapp_pll_branch_limits vt;
-       struct smiapp_pll_branch_limits op;
-
-       /* Other relevant limits */
-       uint32_t min_line_length_pck_bin;
-       uint32_t min_line_length_pck;
-};
-
-struct device;
-
-int smiapp_pll_calculate(struct device *dev,
-                        const struct smiapp_pll_limits *limits,
-                        struct smiapp_pll *pll);
-
-#endif /* SMIAPP_PLL_H */