These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / clk / rockchip / clk-mmc-phase.c
index c842e3b..2685644 100644 (file)
  */
 
 #include <linux/slab.h>
+#include <linux/clk.h>
 #include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
 #include "clk.h"
 
 struct rockchip_mmc_clock {
@@ -38,12 +41,14 @@ static unsigned long rockchip_mmc_recalc(struct clk_hw *hw,
 #define ROCKCHIP_MMC_DEGREE_MASK 0x3
 #define ROCKCHIP_MMC_DELAYNUM_OFFSET 2
 #define ROCKCHIP_MMC_DELAYNUM_MASK (0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET)
+#define ROCKCHIP_MMC_INIT_STATE_RESET 0x1
+#define ROCKCHIP_MMC_INIT_STATE_SHIFT 1
 
 #define PSECS_PER_SEC 1000000000000LL
 
 /*
- * Each fine delay is between 40ps-80ps. Assume each fine delay is 60ps to
- * simplify calculations. So 45degs could be anywhere between 33deg and 66deg.
+ * Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to
+ * simplify calculations. So 45degs could be anywhere between 33deg and 57.8deg.
  */
 #define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60
 
@@ -66,7 +71,7 @@ static int rockchip_mmc_get_phase(struct clk_hw *hw)
 
                delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK);
                delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET;
-               degrees += delay_num * factor / 10000;
+               degrees += DIV_ROUND_CLOSEST(delay_num * factor, 10000);
        }
 
        return degrees % 360;
@@ -79,25 +84,41 @@ static int rockchip_mmc_set_phase(struct clk_hw *hw, int degrees)
        u8 nineties, remainder;
        u8 delay_num;
        u32 raw_value;
-       u64 delay;
-
-       /* allow 22 to be 22.5 */
-       degrees++;
-       /* floor to 22.5 increment */
-       degrees -= ((degrees) * 10 % 225) / 10;
+       u32 delay;
 
        nineties = degrees / 90;
-       /* 22.5 multiples */
-       remainder = (degrees % 90) / 22;
-
-       delay = PSECS_PER_SEC;
-       do_div(delay, rate);
-       /* / 360 / 22.5 */
-       do_div(delay, 16);
-       do_div(delay, ROCKCHIP_MMC_DELAY_ELEMENT_PSEC);
-
+       remainder = (degrees % 90);
+
+       /*
+        * Due to the inexact nature of the "fine" delay, we might
+        * actually go non-monotonic.  We don't go _too_ monotonic
+        * though, so we should be OK.  Here are options of how we may
+        * work:
+        *
+        * Ideally we end up with:
+        *   1.0, 2.0, ..., 69.0, 70.0, ...,  89.0, 90.0
+        *
+        * On one extreme (if delay is actually 44ps):
+        *   .73, 1.5, ..., 50.6, 51.3, ...,  65.3, 90.0
+        * The other (if delay is actually 77ps):
+        *   1.3, 2.6, ..., 88.6. 89.8, ..., 114.0, 90
+        *
+        * It's possible we might make a delay that is up to 25
+        * degrees off from what we think we're making.  That's OK
+        * though because we should be REALLY far from any bad range.
+        */
+
+       /*
+        * Convert to delay; do a little extra work to make sure we
+        * don't overflow 32-bit / 64-bit numbers.
+        */
+       delay = 10000000; /* PSECS_PER_SEC / 10000 / 10 */
        delay *= remainder;
-       delay_num = (u8) min(delay, 255ULL);
+       delay = DIV_ROUND_CLOSEST(delay,
+                       (rate / 1000) * 36 *
+                               (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10));
+
+       delay_num = (u8) min_t(u32, delay, 255);
 
        raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0;
        raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET;
@@ -105,7 +126,7 @@ static int rockchip_mmc_set_phase(struct clk_hw *hw, int degrees)
        writel(HIWORD_UPDATE(raw_value, 0x07ff, mmc_clock->shift), mmc_clock->reg);
 
        pr_debug("%s->set_phase(%d) delay_nums=%u reg[0x%p]=0x%03x actual_degrees=%d\n",
-               __clk_get_name(hw->clk), degrees, delay_num,
+               clk_hw_get_name(hw), degrees, delay_num,
                mmc_clock->reg, raw_value>>(mmc_clock->shift),
                rockchip_mmc_get_phase(hw)
        );
@@ -120,7 +141,7 @@ static const struct clk_ops rockchip_mmc_clk_ops = {
 };
 
 struct clk *rockchip_clk_register_mmc(const char *name,
-                               const char **parent_names, u8 num_parents,
+                               const char *const *parent_names, u8 num_parents,
                                void __iomem *reg, int shift)
 {
        struct clk_init_data init;
@@ -131,6 +152,7 @@ struct clk *rockchip_clk_register_mmc(const char *name,
        if (!mmc_clock)
                return NULL;
 
+       init.name = name;
        init.num_parents = num_parents;
        init.parent_names = parent_names;
        init.ops = &rockchip_mmc_clk_ops;
@@ -139,8 +161,14 @@ struct clk *rockchip_clk_register_mmc(const char *name,
        mmc_clock->reg = reg;
        mmc_clock->shift = shift;
 
-       if (name)
-               init.name = name;
+       /*
+        * Assert init_state to soft reset the CLKGEN
+        * for mmc tuning phase and degree
+        */
+       if (mmc_clock->shift == ROCKCHIP_MMC_INIT_STATE_SHIFT)
+               writel(HIWORD_UPDATE(ROCKCHIP_MMC_INIT_STATE_RESET,
+                                    ROCKCHIP_MMC_INIT_STATE_RESET,
+                                    mmc_clock->shift), mmc_clock->reg);
 
        clk = clk_register(NULL, &mmc_clock->hw);
        if (IS_ERR(clk))