clk: rockchip: support setting ddr clock via SCPI APIs
[firefly-linux-kernel-4.4.55.git] / drivers / clk / rockchip / clk.h
index dc8ecb2673b7b2a249befe3de93a4b39493f3134..c1e49b2767ec46d1343e184e4c49699442ae4b6b 100644 (file)
@@ -2,6 +2,9 @@
  * Copyright (c) 2014 MundoReader S.L.
  * Author: Heiko Stuebner <heiko@sntech.de>
  *
+ * Copyright (c) 2015 Rockchip Electronics Co. Ltd.
+ * Author: Xing Zheng <zhengxing@rock-chips.com>
+ *
  * based on
  *
  * samsung/clk.h
 #define CLK_ROCKCHIP_CLK_H
 
 #include <linux/io.h>
+#include <linux/clk-provider.h>
 
 struct clk;
 
 #define HIWORD_UPDATE(val, mask, shift) \
                ((val) << (shift) | (mask) << ((shift) + 16))
 
-/* register positions shared by RK2928, RK3066 and RK3188 */
+/* register positions shared by RK2928, RK3036, RK3066, RK3188 and RK3228 */
 #define RK2928_PLL_CON(x)              ((x) * 0x4)
 #define RK2928_MODE_CON                0x40
 #define RK2928_CLKSEL_CON(x)   ((x) * 0x4 + 0x44)
@@ -40,6 +44,22 @@ struct clk;
 #define RK2928_SOFTRST_CON(x)  ((x) * 0x4 + 0x110)
 #define RK2928_MISC_CON                0x134
 
+#define RK3036_SDMMC_CON0              0x144
+#define RK3036_SDMMC_CON1              0x148
+#define RK3036_SDIO_CON0               0x14c
+#define RK3036_SDIO_CON1               0x150
+#define RK3036_EMMC_CON0               0x154
+#define RK3036_EMMC_CON1               0x158
+
+#define RK3228_GLB_SRST_FST            0x1f0
+#define RK3228_GLB_SRST_SND            0x1f4
+#define RK3228_SDMMC_CON0              0x1c0
+#define RK3228_SDMMC_CON1              0x1c4
+#define RK3228_SDIO_CON0               0x1c8
+#define RK3228_SDIO_CON1               0x1cc
+#define RK3228_EMMC_CON0               0x1d8
+#define RK3228_EMMC_CON1               0x1dc
+
 #define RK3288_PLL_CON(x)              RK2928_PLL_CON(x)
 #define RK3288_MODE_CON                        0x50
 #define RK3288_CLKSEL_CON(x)           ((x) * 0x4 + 0x60)
@@ -57,6 +77,24 @@ struct clk;
 #define RK3288_EMMC_CON0               0x218
 #define RK3288_EMMC_CON1               0x21c
 
+#define RK3328_PLL_CON(x)              RK2928_PLL_CON(x)
+#define RK3328_CLKSEL_CON(x)           ((x) * 0x4 + 0x100)
+#define RK3328_CLKGATE_CON(x)          ((x) * 0x4 + 0x200)
+#define RK3328_GRFCLKSEL_CON(x)                ((x) * 0x4 + 0x100)
+#define RK3328_GLB_SRST_FST            0x9c
+#define RK3328_GLB_SRST_SND            0x98
+#define RK3328_SOFTRST_CON(x)          ((x) * 0x4 + 0x300)
+#define RK3328_MODE_CON                        0x80
+#define RK3328_MISC_CON                        0x84
+#define RK3328_SDMMC_CON0              0x380
+#define RK3328_SDMMC_CON1              0x384
+#define RK3328_SDIO_CON0               0x388
+#define RK3328_SDIO_CON1               0x38c
+#define RK3328_EMMC_CON0               0x390
+#define RK3328_EMMC_CON1               0x394
+#define RK3328_SDMMC_EXT_CON0          0x398
+#define RK3328_SDMMC_EXT_CON1          0x39C
+
 #define RK3368_PLL_CON(x)              RK2928_PLL_CON(x)
 #define RK3368_CLKSEL_CON(x)           ((x) * 0x4 + 0x100)
 #define RK3368_CLKGATE_CON(x)          ((x) * 0x4 + 0x200)
@@ -73,10 +111,48 @@ struct clk;
 #define RK3368_EMMC_CON0               0x418
 #define RK3368_EMMC_CON1               0x41c
 
+#define RK3399_PLL_CON(x)              RK2928_PLL_CON(x)
+#define RK3399_CLKSEL_CON(x)           ((x) * 0x4 + 0x100)
+#define RK3399_CLKGATE_CON(x)          ((x) * 0x4 + 0x300)
+#define RK3399_SOFTRST_CON(x)          ((x) * 0x4 + 0x400)
+#define RK3399_GLB_SRST_FST            0x500
+#define RK3399_GLB_SRST_SND            0x504
+#define RK3399_GLB_CNT_TH              0x508
+#define RK3399_MISC_CON                        0x50c
+#define RK3399_RST_CON                 0x510
+#define RK3399_RST_ST                  0x514
+#define RK3399_SDMMC_CON0              0x580
+#define RK3399_SDMMC_CON1              0x584
+#define RK3399_SDIO_CON0               0x588
+#define RK3399_SDIO_CON1               0x58c
+
+#define RK3399_PMU_PLL_CON(x)          RK2928_PLL_CON(x)
+#define RK3399_PMU_CLKSEL_CON(x)       ((x) * 0x4 + 0x80)
+#define RK3399_PMU_CLKGATE_CON(x)      ((x) * 0x4 + 0x100)
+#define RK3399_PMU_SOFTRST_CON(x)      ((x) * 0x4 + 0x110)
+#define RK3399_PMU_RSTNHOLD_CON(x)     ((x) * 0x4 + 0x120)
+#define RK3399_PMU_GATEDIS_CON(x)      ((x) * 0x4 + 0x130)
+
 enum rockchip_pll_type {
+       pll_rk3036,
        pll_rk3066,
+       pll_rk3328,
+       pll_rk3366,
+       pll_rk3399,
 };
 
+#define RK3036_PLL_RATE(_rate, _refdiv, _fbdiv, _postdiv1,     \
+                       _postdiv2, _dsmpd, _frac)               \
+{                                                              \
+       .rate   = _rate##U,                                     \
+       .fbdiv = _fbdiv,                                        \
+       .postdiv1 = _postdiv1,                                  \
+       .refdiv = _refdiv,                                      \
+       .postdiv2 = _postdiv2,                                  \
+       .dsmpd = _dsmpd,                                        \
+       .frac = _frac,                                          \
+}
+
 #define RK3066_PLL_RATE(_rate, _nr, _nf, _no)  \
 {                                              \
        .rate   = _rate##U,                     \
@@ -95,19 +171,43 @@ enum rockchip_pll_type {
        .nb = _nb,                                              \
 }
 
+/**
+ * struct rockchip_clk_provider - information about clock provider
+ * @reg_base: virtual address for the register base.
+ * @clk_data: holds clock related data like clk* and number of clocks.
+ * @cru_node: device-node of the clock-provider
+ * @grf: regmap of the general-register-files syscon
+ * @lock: maintains exclusion between callbacks for a given clock-provider.
+ */
+struct rockchip_clk_provider {
+       void __iomem *reg_base;
+       struct clk_onecell_data clk_data;
+       struct device_node *cru_node;
+       struct regmap *grf;
+       spinlock_t lock;
+};
+
 struct rockchip_pll_rate_table {
        unsigned long rate;
        unsigned int nr;
        unsigned int nf;
        unsigned int no;
        unsigned int nb;
+       /* for RK3036/RK3399 */
+       unsigned int fbdiv;
+       unsigned int postdiv1;
+       unsigned int refdiv;
+       unsigned int postdiv2;
+       unsigned int dsmpd;
+       unsigned int frac;
 };
 
 /**
- * struct rockchip_pll_clock: information about pll clock
+ * struct rockchip_pll_clock - information about pll clock
  * @id: platform specific id of the clock.
  * @name: name of this pll clock.
- * @parent_name: name of the parent clock.
+ * @parent_names: name of the parent clock.
+ * @num_parents: number of parents
  * @flags: optional flags for basic clock.
  * @con_offset: offset of the register for configuring the PLL.
  * @mode_offset: offset of the register for configuring the PLL-mode.
@@ -155,12 +255,13 @@ struct rockchip_pll_clock {
                .rate_table     = _rtable,                              \
        }
 
-struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type,
+struct clk *rockchip_clk_register_pll(struct rockchip_clk_provider *ctx,
+               enum rockchip_pll_type pll_type,
                const char *name, const char *const *parent_names,
-               u8 num_parents, void __iomem *base, int con_offset,
-               int grf_lock_offset, int lock_shift, int reg_mode,
-               int mode_shift, struct rockchip_pll_rate_table *rate_table,
-               u8 clk_pll_flags, spinlock_t *lock);
+               u8 num_parents, int con_offset, int grf_lock_offset,
+               int lock_shift, int mode_offset, int mode_shift,
+               struct rockchip_pll_rate_table *rate_table,
+               unsigned long flags, u8 clk_pll_flags);
 
 struct rockchip_cpuclk_clksel {
        int reg;
@@ -174,18 +275,23 @@ struct rockchip_cpuclk_rate_table {
 };
 
 /**
- * struct rockchip_cpuclk_reg_data: describes register offsets and masks of the cpuclock
+ * struct rockchip_cpuclk_reg_data - describes register offsets and masks of the cpuclock
  * @core_reg:          register offset of the core settings register
  * @div_core_shift:    core divider offset used to divide the pll value
  * @div_core_mask:     core divider mask
+ * @mux_core_alt:      mux value to select alternate parent
+ * @mux_core_main:     mux value to select main parent of core
  * @mux_core_shift:    offset of the core multiplexer
+ * @mux_core_mask:     core multiplexer mask
  */
 struct rockchip_cpuclk_reg_data {
        int             core_reg;
        u8              div_core_shift;
        u32             div_core_mask;
-       int             mux_core_reg;
+       u8              mux_core_alt;
+       u8              mux_core_main;
        u8              mux_core_shift;
+       u32             mux_core_mask;
 };
 
 struct clk *rockchip_clk_register_cpuclk(const char *name,
@@ -198,6 +304,24 @@ struct clk *rockchip_clk_register_mmc(const char *name,
                                const char *const *parent_names, u8 num_parents,
                                void __iomem *reg, int shift);
 
+/*
+ * for COMPOSITE_DDRCLK div_flag,
+ * there may have serval ways to set ddr clock, use
+ * this flag to distinguish them.
+ * ROCKCHIP_DDRCLK_SIP: use SIP call to bl31 to change ddrclk rate.
+ * ROCKCHIP_DDRCLK_SCPI: use SCPI APIs to let mcu change ddrclk rate.
+ */
+#define ROCKCHIP_DDRCLK_SIP            0x01
+#define ROCKCHIP_DDRCLK_SCPI           0x02
+
+struct clk *rockchip_clk_register_ddrclk(const char *name, int flags,
+                                        const char *const *parent_names,
+                                        u8 num_parents, int mux_offset,
+                                        int mux_shift, int mux_width,
+                                        int div_shift, int div_width,
+                                        int ddr_flags, void __iomem *reg_base,
+                                        spinlock_t *lock);
+
 #define ROCKCHIP_INVERTER_HIWORD_MASK  BIT(0)
 
 struct clk *rockchip_clk_register_inverter(const char *name,
@@ -205,16 +329,24 @@ struct clk *rockchip_clk_register_inverter(const char *name,
                                void __iomem *reg, int shift, int flags,
                                spinlock_t *lock);
 
+struct clk *rockchip_clk_register_muxgrf(const char *name,
+                               const char *const *parent_names, u8 num_parents,
+                               int flags, struct regmap *grf, int reg,
+                               int shift, int width, int mux_flags);
+
 #define PNAME(x) static const char *const x[] __initconst
 
 enum rockchip_clk_branch_type {
        branch_composite,
        branch_mux,
+       branch_muxgrf,
        branch_divider,
        branch_fraction_divider,
        branch_gate,
        branch_mmc,
        branch_inverter,
+       branch_factor,
+       branch_ddrc,
 };
 
 struct rockchip_clk_branch {
@@ -235,6 +367,7 @@ struct rockchip_clk_branch {
        int                             gate_offset;
        u8                              gate_shift;
        u8                              gate_flags;
+       struct rockchip_clk_branch      *child;
 };
 
 #define COMPOSITE(_id, cname, pnames, f, mo, ms, mw, mf, ds, dw,\
@@ -369,6 +502,58 @@ struct rockchip_clk_branch {
                .gate_flags     = gf,                           \
        }
 
+#define COMPOSITE_FRACMUX(_id, cname, pname, f, mo, df, go, gs, gf, ch) \
+       {                                                       \
+               .id             = _id,                          \
+               .branch_type    = branch_fraction_divider,      \
+               .name           = cname,                        \
+               .parent_names   = (const char *[]){ pname },    \
+               .num_parents    = 1,                            \
+               .flags          = f,                            \
+               .muxdiv_offset  = mo,                           \
+               .div_shift      = 16,                           \
+               .div_width      = 16,                           \
+               .div_flags      = df,                           \
+               .gate_offset    = go,                           \
+               .gate_shift     = gs,                           \
+               .gate_flags     = gf,                           \
+               .child          = ch,                           \
+       }
+
+#define COMPOSITE_FRACMUX_NOGATE(_id, cname, pname, f, mo, df, ch) \
+       {                                                       \
+               .id             = _id,                          \
+               .branch_type    = branch_fraction_divider,      \
+               .name           = cname,                        \
+               .parent_names   = (const char *[]){ pname },    \
+               .num_parents    = 1,                            \
+               .flags          = f,                            \
+               .muxdiv_offset  = mo,                           \
+               .div_shift      = 16,                           \
+               .div_width      = 16,                           \
+               .div_flags      = df,                           \
+               .gate_offset    = -1,                           \
+               .child          = ch,                           \
+       }
+
+#define COMPOSITE_DDRCLK(_id, cname, pnames, f, mo, ms, mw,    \
+                        ds, dw, df)                            \
+       {                                                       \
+               .id             = _id,                          \
+               .branch_type    = branch_ddrc,                  \
+               .name           = cname,                        \
+               .parent_names   = pnames,                       \
+               .num_parents    = ARRAY_SIZE(pnames),           \
+               .flags          = f,                            \
+               .muxdiv_offset  = mo,                           \
+               .mux_shift      = ms,                           \
+               .mux_width      = mw,                           \
+               .div_shift      = ds,                           \
+               .div_width      = dw,                           \
+               .div_flags      = df,                           \
+               .gate_offset    = -1,                           \
+       }
+
 #define MUX(_id, cname, pnames, f, o, s, w, mf)                        \
        {                                                       \
                .id             = _id,                          \
@@ -384,6 +569,21 @@ struct rockchip_clk_branch {
                .gate_offset    = -1,                           \
        }
 
+#define MUXGRF(_id, cname, pnames, f, o, s, w, mf)             \
+       {                                                       \
+               .id             = _id,                          \
+               .branch_type    = branch_muxgrf,                \
+               .name           = cname,                        \
+               .parent_names   = pnames,                       \
+               .num_parents    = ARRAY_SIZE(pnames),           \
+               .flags          = f,                            \
+               .muxdiv_offset  = o,                            \
+               .mux_shift      = s,                            \
+               .mux_width      = w,                            \
+               .mux_flags      = mf,                           \
+               .gate_offset    = -1,                           \
+       }
+
 #define DIV(_id, cname, pname, f, o, s, w, df)                 \
        {                                                       \
                .id             = _id,                          \
@@ -450,21 +650,55 @@ struct rockchip_clk_branch {
                .div_flags      = if,                           \
        }
 
-void rockchip_clk_init(struct device_node *np, void __iomem *base,
-                      unsigned long nr_clks);
-struct regmap *rockchip_clk_get_grf(void);
-void rockchip_clk_add_lookup(struct clk *clk, unsigned int id);
-void rockchip_clk_register_branches(struct rockchip_clk_branch *clk_list,
+#define FACTOR(_id, cname, pname,  f, fm, fd)                  \
+       {                                                       \
+               .id             = _id,                          \
+               .branch_type    = branch_factor,                \
+               .name           = cname,                        \
+               .parent_names   = (const char *[]){ pname },    \
+               .num_parents    = 1,                            \
+               .flags          = f,                            \
+               .div_shift      = fm,                           \
+               .div_width      = fd,                           \
+       }
+
+#define FACTOR_GATE(_id, cname, pname,  f, fm, fd, go, gb, gf) \
+       {                                                       \
+               .id             = _id,                          \
+               .branch_type    = branch_factor,                \
+               .name           = cname,                        \
+               .parent_names   = (const char *[]){ pname },    \
+               .num_parents    = 1,                            \
+               .flags          = f,                            \
+               .div_shift      = fm,                           \
+               .div_width      = fd,                           \
+               .gate_offset    = go,                           \
+               .gate_shift     = gb,                           \
+               .gate_flags     = gf,                           \
+       }
+
+struct rockchip_clk_provider *rockchip_clk_init(struct device_node *np,
+                       void __iomem *base, unsigned long nr_clks);
+void rockchip_clk_of_add_provider(struct device_node *np,
+                               struct rockchip_clk_provider *ctx);
+struct regmap *rockchip_clk_get_grf(struct rockchip_clk_provider *ctx);
+void rockchip_clk_add_lookup(struct rockchip_clk_provider *ctx,
+                            struct clk *clk, unsigned int id);
+void rockchip_clk_register_branches(struct rockchip_clk_provider *ctx,
+                                   struct rockchip_clk_branch *list,
                                    unsigned int nr_clk);
-void rockchip_clk_register_plls(struct rockchip_pll_clock *pll_list,
+void rockchip_clk_register_plls(struct rockchip_clk_provider *ctx,
+                               struct rockchip_pll_clock *pll_list,
                                unsigned int nr_pll, int grf_lock_offset);
-void rockchip_clk_register_armclk(unsigned int lookup_id, const char *name,
+void rockchip_clk_register_armclk(struct rockchip_clk_provider *ctx,
+                       unsigned int lookup_id, const char *name,
                        const char *const *parent_names, u8 num_parents,
                        const struct rockchip_cpuclk_reg_data *reg_data,
                        const struct rockchip_cpuclk_rate_table *rates,
                        int nrates);
 void rockchip_clk_protect_critical(const char *const clocks[], int nclocks);
-void rockchip_register_restart_notifier(unsigned int reg);
+void rockchip_register_restart_notifier(struct rockchip_clk_provider *ctx,
+                                       unsigned int reg, void (*cb)(void));
 
 #define ROCKCHIP_SOFTRST_HIWORD_MASK   BIT(0)