Merge branches 'clk-optional', 'clk-devm-clkdev-register', 'clk-allwinner', 'clk...
authorStephen Boyd <sboyd@kernel.org>
Fri, 8 Mar 2019 18:27:21 +0000 (10:27 -0800)
committerStephen Boyd <sboyd@kernel.org>
Fri, 8 Mar 2019 18:27:21 +0000 (10:27 -0800)
 - Add a {devm_}clk_get_optional() API
 - Add devm_clk_hw_register_clkdev() API to manage clkdev lookups

* clk-optional:
  clk: Add (devm_)clk_get_optional() functions
  clk: Add comment about __of_clk_get_by_name() error values

* clk-devm-clkdev-register:
  clk: clk-st: avoid clkdev lookup leak at remove
  clk: clk-max77686: Clean clkdev lookup leak and use devm
  clkdev: add managed clkdev lookup registration

* clk-allwinner:
  clk: sunxi-ng: sun8i-a23: Enable PLL-MIPI LDOs when ungating it

* clk-meson: (22 commits)
  clk: meson: meson8b: fix the naming of the APB clocks
  dt-bindings: clock: meson8b: add APB clock definition
  clk: meson: Add G12A AO Clock + Reset Controller
  dt-bindings: clk: add G12A AO Clock and Reset Bindings
  clk: meson: factorise meson64 peripheral clock controller drivers
  clk: meson: g12a: add peripheral clock controller
  dt-bindings: clk: meson: add g12a periph clock controller bindings
  clk: meson: pll: update driver for the g12a
  clk: meson: rework and clean drivers dependencies
  clk: meson: axg-audio does not require syscon
  clk: meson: use CONFIG_ARCH_MESON to enter meson clk directory
  clk: export some clk_hw function symbols for module drivers
  clk: meson: ao-clkc: claim clock controller input clocks from DT
  clk: meson: axg: claim clock controller input clock from DT
  clk: meson: gxbb: claim clock controller input clock from DT
  clk: meson: meson8b: add the GPU clock tree
  clk: meson: meson8b: use a separate clock table for Meson8
  clk: meson: axg-ao: add 32k generation subtree
  clk: meson: gxbb-ao: replace cec-32k with the dual divider
  clk: meson: add dual divider clock driver
  ...

* clk-renesas:
  clk: renesas: r8a774a1: Fix LAST_DT_CORE_CLK
  clk: renesas: r8a774c0: Fix LAST_DT_CORE_CLK
  clk: renesas: r8a774c0: Add TMU clock
  clk: renesas: r8a77980: Add RPC clocks
  clk: renesas: rcar-gen3: Add RPC clocks
  clk: renesas: rcar-gen3: Add spinlock
  clk: renesas: rcar-gen3: Factor out cpg_reg_modify()
  clk: renesas: r8a774c0: Correct parent clock of DU
  clk: renesas: r8a774a1: Add missing CANFD clock
  clk: renesas: r8a774c0: Add missing CANFD clock

65 files changed:
Documentation/devicetree/bindings/clock/amlogic,gxbb-aoclkc.txt
Documentation/devicetree/bindings/clock/amlogic,gxbb-clkc.txt
Documentation/driver-model/devres.txt
drivers/clk/Makefile
drivers/clk/clk-devres.c
drivers/clk/clk-max77686.c
drivers/clk/clk.c
drivers/clk/clkdev.c
drivers/clk/meson/Kconfig
drivers/clk/meson/Makefile
drivers/clk/meson/axg-aoclk.c
drivers/clk/meson/axg-aoclk.h
drivers/clk/meson/axg-audio.c
drivers/clk/meson/axg.c
drivers/clk/meson/clk-dualdiv.c [new file with mode: 0644]
drivers/clk/meson/clk-dualdiv.h [new file with mode: 0644]
drivers/clk/meson/clk-input.c
drivers/clk/meson/clk-input.h [new file with mode: 0644]
drivers/clk/meson/clk-mpll.c
drivers/clk/meson/clk-mpll.h [new file with mode: 0644]
drivers/clk/meson/clk-phase.c
drivers/clk/meson/clk-phase.h [new file with mode: 0644]
drivers/clk/meson/clk-pll.c
drivers/clk/meson/clk-pll.h [new file with mode: 0644]
drivers/clk/meson/clk-regmap.c
drivers/clk/meson/clk-regmap.h
drivers/clk/meson/clk-triphase.c [deleted file]
drivers/clk/meson/clkc-audio.h [deleted file]
drivers/clk/meson/clkc.h [deleted file]
drivers/clk/meson/g12a-aoclk.c [new file with mode: 0644]
drivers/clk/meson/g12a-aoclk.h [new file with mode: 0644]
drivers/clk/meson/g12a.c [new file with mode: 0644]
drivers/clk/meson/g12a.h [new file with mode: 0644]
drivers/clk/meson/gxbb-aoclk-32k.c [deleted file]
drivers/clk/meson/gxbb-aoclk.c
drivers/clk/meson/gxbb-aoclk.h
drivers/clk/meson/gxbb.c
drivers/clk/meson/meson-aoclk.c
drivers/clk/meson/meson-aoclk.h
drivers/clk/meson/meson-eeclk.c [new file with mode: 0644]
drivers/clk/meson/meson-eeclk.h [new file with mode: 0644]
drivers/clk/meson/meson8b.c
drivers/clk/meson/meson8b.h
drivers/clk/meson/parm.h [new file with mode: 0644]
drivers/clk/meson/sclk-div.c
drivers/clk/meson/sclk-div.h [new file with mode: 0644]
drivers/clk/meson/vid-pll-div.c
drivers/clk/meson/vid-pll-div.h [new file with mode: 0644]
drivers/clk/renesas/r8a774a1-cpg-mssr.c
drivers/clk/renesas/r8a774c0-cpg-mssr.c
drivers/clk/renesas/r8a77980-cpg-mssr.c
drivers/clk/renesas/rcar-gen3-cpg.c
drivers/clk/renesas/rcar-gen3-cpg.h
drivers/clk/sunxi-ng/ccu-sun8i-a23.c
drivers/clk/x86/clk-st.c
include/dt-bindings/clock/axg-aoclkc.h
include/dt-bindings/clock/g12a-aoclkc.h [new file with mode: 0644]
include/dt-bindings/clock/g12a-clkc.h [new file with mode: 0644]
include/dt-bindings/clock/gxbb-aoclkc.h
include/dt-bindings/clock/meson8b-clkc.h
include/dt-bindings/clock/r8a774a1-cpg-mssr.h
include/dt-bindings/clock/r8a774c0-cpg-mssr.h
include/dt-bindings/reset/g12a-aoclkc.h [new file with mode: 0644]
include/linux/clk.h
include/linux/clkdev.h

index 79511d7..c41f0be 100644 (file)
@@ -10,6 +10,7 @@ Required Properties:
        - GXL (S905X, S905D) : "amlogic,meson-gxl-aoclkc"
        - GXM (S912) : "amlogic,meson-gxm-aoclkc"
        - AXG (A113D, A113X) : "amlogic,meson-axg-aoclkc"
+       - G12A (S905X2, S905D2, S905Y2) : "amlogic,meson-g12a-aoclkc"
        followed by the common "amlogic,meson-gx-aoclkc"
 - clocks: list of clock phandle, one for each entry clock-names.
 - clock-names: should contain the following:
index a687195..5c8b105 100644 (file)
@@ -9,6 +9,7 @@ Required Properties:
                "amlogic,gxbb-clkc" for GXBB SoC,
                "amlogic,gxl-clkc" for GXL and GXM SoC,
                "amlogic,axg-clkc" for AXG SoC.
+               "amlogic,g12a-clkc" for G12A SoC.
 - clocks : list of clock phandle, one for each entry clock-names.
 - clock-names : should contain the following:
   * "xtal": the platform xtal
index b277caf..d7d6f01 100644 (file)
@@ -242,9 +242,11 @@ certainly invest a bit more effort into libata core layer).
 
 CLOCK
   devm_clk_get()
+  devm_clk_get_optional()
   devm_clk_put()
   devm_clk_hw_register()
   devm_of_clk_add_hw_provider()
+  devm_clk_hw_register_clkdev()
 
 DMA
   dmaenginem_async_device_register()
index d6cd32b..1db1336 100644 (file)
@@ -79,7 +79,7 @@ obj-$(CONFIG_ARCH_K3)                 += keystone/
 obj-$(CONFIG_ARCH_KEYSTONE)            += keystone/
 obj-$(CONFIG_MACH_LOONGSON32)          += loongson1/
 obj-y                                  += mediatek/
-obj-$(CONFIG_COMMON_CLK_AMLOGIC)       += meson/
+obj-$(CONFIG_ARCH_MESON)               += meson/
 obj-$(CONFIG_MACH_PIC32)               += microchip/
 ifeq ($(CONFIG_COMMON_CLK), y)
 obj-$(CONFIG_ARCH_MMP)                 += mmp/
index c9a8615..daa1fc8 100644 (file)
@@ -29,6 +29,17 @@ struct clk *devm_clk_get(struct device *dev, const char *id)
 }
 EXPORT_SYMBOL(devm_clk_get);
 
+struct clk *devm_clk_get_optional(struct device *dev, const char *id)
+{
+       struct clk *clk = devm_clk_get(dev, id);
+
+       if (clk == ERR_PTR(-ENOENT))
+               return NULL;
+
+       return clk;
+}
+EXPORT_SYMBOL(devm_clk_get_optional);
+
 struct clk_bulk_devres {
        struct clk_bulk_data *clks;
        int num_clks;
index 22c9376..3727d54 100644 (file)
@@ -235,8 +235,9 @@ static int max77686_clk_probe(struct platform_device *pdev)
                        return ret;
                }
 
-               ret = clk_hw_register_clkdev(&max_clk_data->hw,
-                                            max_clk_data->clk_idata.name, NULL);
+               ret = devm_clk_hw_register_clkdev(dev, &max_clk_data->hw,
+                                                 max_clk_data->clk_idata.name,
+                                                 NULL);
                if (ret < 0) {
                        dev_err(dev, "Failed to clkdev register: %d\n", ret);
                        return ret;
@@ -244,8 +245,8 @@ static int max77686_clk_probe(struct platform_device *pdev)
        }
 
        if (parent->of_node) {
-               ret = of_clk_add_hw_provider(parent->of_node, of_clk_max77686_get,
-                                            drv_data);
+               ret = devm_of_clk_add_hw_provider(dev, of_clk_max77686_get,
+                                                 drv_data);
 
                if (ret < 0) {
                        dev_err(dev, "Failed to register OF clock provider: %d\n",
@@ -261,27 +262,11 @@ static int max77686_clk_probe(struct platform_device *pdev)
                                         1 << MAX77802_CLOCK_LOW_JITTER_SHIFT);
                if (ret < 0) {
                        dev_err(dev, "Failed to config low-jitter: %d\n", ret);
-                       goto remove_of_clk_provider;
+                       return ret;
                }
        }
 
        return 0;
-
-remove_of_clk_provider:
-       if (parent->of_node)
-               of_clk_del_provider(parent->of_node);
-
-       return ret;
-}
-
-static int max77686_clk_remove(struct platform_device *pdev)
-{
-       struct device *parent = pdev->dev.parent;
-
-       if (parent->of_node)
-               of_clk_del_provider(parent->of_node);
-
-       return 0;
 }
 
 static const struct platform_device_id max77686_clk_id[] = {
@@ -297,7 +282,6 @@ static struct platform_driver max77686_clk_driver = {
                .name  = "max77686-clk",
        },
        .probe = max77686_clk_probe,
-       .remove = max77686_clk_remove,
        .id_table = max77686_clk_id,
 };
 
index d2477a5..af3882f 100644 (file)
@@ -394,16 +394,19 @@ bool clk_hw_is_prepared(const struct clk_hw *hw)
 {
        return clk_core_is_prepared(hw->core);
 }
+EXPORT_SYMBOL_GPL(clk_hw_is_prepared);
 
 bool clk_hw_rate_is_protected(const struct clk_hw *hw)
 {
        return clk_core_rate_is_protected(hw->core);
 }
+EXPORT_SYMBOL_GPL(clk_hw_rate_is_protected);
 
 bool clk_hw_is_enabled(const struct clk_hw *hw)
 {
        return clk_core_is_enabled(hw->core);
 }
+EXPORT_SYMBOL_GPL(clk_hw_is_enabled);
 
 bool __clk_is_enabled(struct clk *clk)
 {
index 9ab3db8..4cfe396 100644 (file)
@@ -52,6 +52,12 @@ struct clk *of_clk_get(struct device_node *np, int index)
 }
 EXPORT_SYMBOL(of_clk_get);
 
+/*
+ * Beware the return values when np is valid, but no clock provider is found.
+ * If name == NULL, the function returns -ENOENT.
+ * If name != NULL, the function returns -EINVAL. This is because __of_clk_get()
+ * is called even if of_property_match_string() returns an error.
+ */
 static struct clk *__of_clk_get_by_name(struct device_node *np,
                                        const char *dev_id,
                                        const char *name)
@@ -401,6 +407,23 @@ static struct clk_lookup *__clk_register_clkdev(struct clk_hw *hw,
        return cl;
 }
 
+static int do_clk_register_clkdev(struct clk_hw *hw,
+       struct clk_lookup **cl, const char *con_id, const char *dev_id)
+{
+       if (IS_ERR(hw))
+               return PTR_ERR(hw);
+       /*
+        * Since dev_id can be NULL, and NULL is handled specially, we must
+        * pass it as either a NULL format string, or with "%s".
+        */
+       if (dev_id)
+               *cl = __clk_register_clkdev(hw, con_id, "%s", dev_id);
+       else
+               *cl = __clk_register_clkdev(hw, con_id, NULL);
+
+       return *cl ? 0 : -ENOMEM;
+}
+
 /**
  * clk_register_clkdev - register one clock lookup for a struct clk
  * @clk: struct clk to associate with all clk_lookups
@@ -423,17 +446,8 @@ int clk_register_clkdev(struct clk *clk, const char *con_id,
        if (IS_ERR(clk))
                return PTR_ERR(clk);
 
-       /*
-        * Since dev_id can be NULL, and NULL is handled specially, we must
-        * pass it as either a NULL format string, or with "%s".
-        */
-       if (dev_id)
-               cl = __clk_register_clkdev(__clk_get_hw(clk), con_id, "%s",
-                                          dev_id);
-       else
-               cl = __clk_register_clkdev(__clk_get_hw(clk), con_id, NULL);
-
-       return cl ? 0 : -ENOMEM;
+       return do_clk_register_clkdev(__clk_get_hw(clk), &cl, con_id,
+                                             dev_id);
 }
 EXPORT_SYMBOL(clk_register_clkdev);
 
@@ -456,18 +470,75 @@ int clk_hw_register_clkdev(struct clk_hw *hw, const char *con_id,
 {
        struct clk_lookup *cl;
 
-       if (IS_ERR(hw))
-               return PTR_ERR(hw);
+       return do_clk_register_clkdev(hw, &cl, con_id, dev_id);
+}
+EXPORT_SYMBOL(clk_hw_register_clkdev);
 
-       /*
-        * Since dev_id can be NULL, and NULL is handled specially, we must
-        * pass it as either a NULL format string, or with "%s".
-        */
-       if (dev_id)
-               cl = __clk_register_clkdev(hw, con_id, "%s", dev_id);
-       else
-               cl = __clk_register_clkdev(hw, con_id, NULL);
+static void devm_clkdev_release(struct device *dev, void *res)
+{
+       clkdev_drop(*(struct clk_lookup **)res);
+}
+
+static int devm_clk_match_clkdev(struct device *dev, void *res, void *data)
+{
+       struct clk_lookup **l = res;
 
-       return cl ? 0 : -ENOMEM;
+       return *l == data;
 }
-EXPORT_SYMBOL(clk_hw_register_clkdev);
+
+/**
+ * devm_clk_release_clkdev - Resource managed clkdev lookup release
+ * @dev: device this lookup is bound
+ * @con_id: connection ID string on device
+ * @dev_id: format string describing device name
+ *
+ * Drop the clkdev lookup created with devm_clk_hw_register_clkdev.
+ * Normally this function will not need to be called and the resource
+ * management code will ensure that the resource is freed.
+ */
+void devm_clk_release_clkdev(struct device *dev, const char *con_id,
+                            const char *dev_id)
+{
+       struct clk_lookup *cl;
+       int rval;
+
+       cl = clk_find(dev_id, con_id);
+       WARN_ON(!cl);
+       rval = devres_release(dev, devm_clkdev_release,
+                             devm_clk_match_clkdev, cl);
+       WARN_ON(rval);
+}
+EXPORT_SYMBOL(devm_clk_release_clkdev);
+
+/**
+ * devm_clk_hw_register_clkdev - managed clk lookup registration for clk_hw
+ * @dev: device this lookup is bound
+ * @hw: struct clk_hw to associate with all clk_lookups
+ * @con_id: connection ID string on device
+ * @dev_id: format string describing device name
+ *
+ * con_id or dev_id may be NULL as a wildcard, just as in the rest of
+ * clkdev.
+ *
+ * To make things easier for mass registration, we detect error clk_hws
+ * from a previous clk_hw_register_*() call, and return the error code for
+ * those.  This is to permit this function to be called immediately
+ * after clk_hw_register_*().
+ */
+int devm_clk_hw_register_clkdev(struct device *dev, struct clk_hw *hw,
+                               const char *con_id, const char *dev_id)
+{
+       int rval = -ENOMEM;
+       struct clk_lookup **cl;
+
+       cl = devres_alloc(devm_clkdev_release, sizeof(*cl), GFP_KERNEL);
+       if (cl) {
+               rval = do_clk_register_clkdev(hw, cl, con_id, dev_id);
+               if (!rval)
+                       devres_add(dev, cl);
+               else
+                       devres_free(cl);
+       }
+       return rval;
+}
+EXPORT_SYMBOL(devm_clk_hw_register_clkdev);
index efaa70f..3858747 100644 (file)
@@ -1,27 +1,52 @@
-config COMMON_CLK_AMLOGIC
-       bool
-       depends on ARCH_MESON || COMPILE_TEST
-       select COMMON_CLK_REGMAP_MESON
+config COMMON_CLK_MESON_INPUT
+       tristate
 
-config COMMON_CLK_AMLOGIC_AUDIO
-       bool
-       depends on ARCH_MESON || COMPILE_TEST
-       select COMMON_CLK_AMLOGIC
+config COMMON_CLK_MESON_REGMAP
+       tristate
+       select REGMAP
 
-config COMMON_CLK_MESON_AO
-       bool
-       depends on OF
-       depends on ARCH_MESON || COMPILE_TEST
-       select COMMON_CLK_REGMAP_MESON
+config COMMON_CLK_MESON_DUALDIV
+       tristate
+       select COMMON_CLK_MESON_REGMAP
+
+config COMMON_CLK_MESON_MPLL
+       tristate
+       select COMMON_CLK_MESON_REGMAP
+
+config COMMON_CLK_MESON_PHASE
+       tristate
+       select COMMON_CLK_MESON_REGMAP
+
+config COMMON_CLK_MESON_PLL
+       tristate
+       select COMMON_CLK_MESON_REGMAP
+
+config COMMON_CLK_MESON_SCLK_DIV
+       tristate
+       select COMMON_CLK_MESON_REGMAP
+
+config COMMON_CLK_MESON_VID_PLL_DIV
+       tristate
+       select COMMON_CLK_MESON_REGMAP
+
+config COMMON_CLK_MESON_AO_CLKC
+       tristate
+       select COMMON_CLK_MESON_REGMAP
+       select COMMON_CLK_MESON_INPUT
        select RESET_CONTROLLER
 
-config COMMON_CLK_REGMAP_MESON
-       bool
-       select REGMAP
+config COMMON_CLK_MESON_EE_CLKC
+       tristate
+       select COMMON_CLK_MESON_REGMAP
+       select COMMON_CLK_MESON_INPUT
 
 config COMMON_CLK_MESON8B
        bool
-       select COMMON_CLK_AMLOGIC
+       depends on ARCH_MESON
+       select COMMON_CLK_MESON_REGMAP
+       select COMMON_CLK_MESON_MPLL
+       select COMMON_CLK_MESON_PLL
+       select MFD_SYSCON
        select RESET_CONTROLLER
        help
          Support for the clock controller on AmLogic S802 (Meson8),
@@ -30,8 +55,14 @@ config COMMON_CLK_MESON8B
 
 config COMMON_CLK_GXBB
        bool
-       select COMMON_CLK_AMLOGIC
-       select COMMON_CLK_MESON_AO
+       depends on ARCH_MESON
+       select COMMON_CLK_MESON_REGMAP
+       select COMMON_CLK_MESON_DUALDIV
+       select COMMON_CLK_MESON_VID_PLL_DIV
+       select COMMON_CLK_MESON_MPLL
+       select COMMON_CLK_MESON_PLL
+       select COMMON_CLK_MESON_AO_CLKC
+       select COMMON_CLK_MESON_EE_CLKC
        select MFD_SYSCON
        help
          Support for the clock controller on AmLogic S905 devices, aka gxbb.
@@ -39,8 +70,13 @@ config COMMON_CLK_GXBB
 
 config COMMON_CLK_AXG
        bool
-       select COMMON_CLK_AMLOGIC
-       select COMMON_CLK_MESON_AO
+       depends on ARCH_MESON
+       select COMMON_CLK_MESON_REGMAP
+       select COMMON_CLK_MESON_DUALDIV
+       select COMMON_CLK_MESON_MPLL
+       select COMMON_CLK_MESON_PLL
+       select COMMON_CLK_MESON_AO_CLKC
+       select COMMON_CLK_MESON_EE_CLKC
        select MFD_SYSCON
        help
          Support for the clock controller on AmLogic A113D devices, aka axg.
@@ -48,9 +84,26 @@ config COMMON_CLK_AXG
 
 config COMMON_CLK_AXG_AUDIO
        tristate "Meson AXG Audio Clock Controller Driver"
-       depends on COMMON_CLK_AXG
-       select COMMON_CLK_AMLOGIC_AUDIO
-       select MFD_SYSCON
+       depends on ARCH_MESON
+       select COMMON_CLK_MESON_INPUT
+       select COMMON_CLK_MESON_REGMAP
+       select COMMON_CLK_MESON_PHASE
+       select COMMON_CLK_MESON_SCLK_DIV
+       select REGMAP_MMIO
        help
          Support for the audio clock controller on AmLogic A113D devices,
          aka axg, Say Y if you want audio subsystem to work.
+
+config COMMON_CLK_G12A
+       bool
+       depends on ARCH_MESON
+       select COMMON_CLK_MESON_REGMAP
+       select COMMON_CLK_MESON_DUALDIV
+       select COMMON_CLK_MESON_MPLL
+       select COMMON_CLK_MESON_PLL
+       select COMMON_CLK_MESON_AO_CLKC
+       select COMMON_CLK_MESON_EE_CLKC
+       select MFD_SYSCON
+       help
+         Support for the clock controller on Amlogic S905D2, S905X2 and S905Y2
+         devices, aka g12a. Say Y if you want peripherals to work.
index a849aa8..021fc29 100644 (file)
@@ -1,13 +1,20 @@
-#
-# Makefile for Meson specific clk
-#
+# Amlogic clock drivers
 
-obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-mpll.o clk-phase.o vid-pll-div.o
-obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-input.o
-obj-$(CONFIG_COMMON_CLK_AMLOGIC_AUDIO) += clk-triphase.o sclk-div.o
-obj-$(CONFIG_COMMON_CLK_MESON_AO) += meson-aoclk.o
+obj-$(CONFIG_COMMON_CLK_MESON_AO_CLKC) += meson-aoclk.o
+obj-$(CONFIG_COMMON_CLK_MESON_DUALDIV) += clk-dualdiv.o
+obj-$(CONFIG_COMMON_CLK_MESON_EE_CLKC) += meson-eeclk.o
+obj-$(CONFIG_COMMON_CLK_MESON_INPUT) += clk-input.o
+obj-$(CONFIG_COMMON_CLK_MESON_MPLL) += clk-mpll.o
+obj-$(CONFIG_COMMON_CLK_MESON_PHASE) += clk-phase.o
+obj-$(CONFIG_COMMON_CLK_MESON_PLL) += clk-pll.o
+obj-$(CONFIG_COMMON_CLK_MESON_REGMAP) += clk-regmap.o
+obj-$(CONFIG_COMMON_CLK_MESON_SCLK_DIV) += sclk-div.o
+obj-$(CONFIG_COMMON_CLK_MESON_VID_PLL_DIV) += vid-pll-div.o
+
+# Amlogic Clock controllers
+
+obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o
+obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
+obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
+obj-$(CONFIG_COMMON_CLK_G12A) += g12a.o g12a-aoclk.o
 obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
-obj-$(CONFIG_COMMON_CLK_GXBB)   += gxbb.o gxbb-aoclk.o gxbb-aoclk-32k.o
-obj-$(CONFIG_COMMON_CLK_AXG)    += axg.o axg-aoclk.o
-obj-$(CONFIG_COMMON_CLK_AXG_AUDIO)     += axg-audio.o
-obj-$(CONFIG_COMMON_CLK_REGMAP_MESON)  += clk-regmap.o
index 29e0885..0086f31 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/reset-controller.h>
 #include <linux/mfd/syscon.h>
-#include "clk-regmap.h"
 #include "meson-aoclk.h"
 #include "axg-aoclk.h"
 
+#include "clk-regmap.h"
+#include "clk-dualdiv.h"
+
+#define IN_PREFIX "ao-in-"
+
+/*
+ * AO Configuration Clock registers offsets
+ * Register offsets from the data sheet must be multiplied by 4.
+ */
+#define AO_RTI_PWR_CNTL_REG1   0x0C
+#define AO_RTI_PWR_CNTL_REG0   0x10
+#define AO_RTI_GEN_CNTL_REG0   0x40
+#define AO_OSCIN_CNTL          0x58
+#define AO_CRT_CLK_CNTL1       0x68
+#define AO_SAR_CLK             0x90
+#define AO_RTC_ALT_CLK_CNTL0   0x94
+#define AO_RTC_ALT_CLK_CNTL1   0x98
+
 #define AXG_AO_GATE(_name, _bit)                                       \
 static struct clk_regmap axg_aoclk_##_name = {                         \
        .data = &(struct clk_regmap_gate_data) {                        \
@@ -25,7 +42,7 @@ static struct clk_regmap axg_aoclk_##_name = {                                \
        .hw.init = &(struct clk_init_data) {                            \
                .name =  "axg_ao_" #_name,                              \
                .ops = &clk_regmap_gate_ops,                            \
-               .parent_names = (const char *[]){ "clk81" },            \
+               .parent_names = (const char *[]){ IN_PREFIX "mpeg-clk" }, \
                .num_parents = 1,                                       \
                .flags = CLK_IGNORE_UNUSED,                             \
        },                                                              \
@@ -39,17 +56,141 @@ AXG_AO_GATE(uart2, 5);
 AXG_AO_GATE(ir_blaster, 6);
 AXG_AO_GATE(saradc, 7);
 
+static struct clk_regmap axg_aoclk_cts_oscin = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = AO_RTI_PWR_CNTL_REG0,
+               .bit_idx = 14,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cts_oscin",
+               .ops = &clk_regmap_gate_ro_ops,
+               .parent_names = (const char *[]){ IN_PREFIX "xtal" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_regmap axg_aoclk_32k_pre = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = AO_RTC_ALT_CLK_CNTL0,
+               .bit_idx = 31,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "axg_ao_32k_pre",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "cts_oscin" },
+               .num_parents = 1,
+       },
+};
+
+static const struct meson_clk_dualdiv_param axg_32k_div_table[] = {
+       {
+               .dual   = 1,
+               .n1     = 733,
+               .m1     = 8,
+               .n2     = 732,
+               .m2     = 11,
+       }, {}
+};
+
+static struct clk_regmap axg_aoclk_32k_div = {
+       .data = &(struct meson_clk_dualdiv_data){
+               .n1 = {
+                       .reg_off = AO_RTC_ALT_CLK_CNTL0,
+                       .shift   = 0,
+                       .width   = 12,
+               },
+               .n2 = {
+                       .reg_off = AO_RTC_ALT_CLK_CNTL0,
+                       .shift   = 12,
+                       .width   = 12,
+               },
+               .m1 = {
+                       .reg_off = AO_RTC_ALT_CLK_CNTL1,
+                       .shift   = 0,
+                       .width   = 12,
+               },
+               .m2 = {
+                       .reg_off = AO_RTC_ALT_CLK_CNTL1,
+                       .shift   = 12,
+                       .width   = 12,
+               },
+               .dual = {
+                       .reg_off = AO_RTC_ALT_CLK_CNTL0,
+                       .shift   = 28,
+                       .width   = 1,
+               },
+               .table = axg_32k_div_table,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "axg_ao_32k_div",
+               .ops = &meson_clk_dualdiv_ops,
+               .parent_names = (const char *[]){ "axg_ao_32k_pre" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_regmap axg_aoclk_32k_sel = {
+       .data = &(struct clk_regmap_mux_data) {
+               .offset = AO_RTC_ALT_CLK_CNTL1,
+               .mask = 0x1,
+               .shift = 24,
+               .flags = CLK_MUX_ROUND_CLOSEST,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "axg_ao_32k_sel",
+               .ops = &clk_regmap_mux_ops,
+               .parent_names = (const char *[]){ "axg_ao_32k_div",
+                                                 "axg_ao_32k_pre" },
+               .num_parents = 2,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap axg_aoclk_32k = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = AO_RTC_ALT_CLK_CNTL0,
+               .bit_idx = 30,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "axg_ao_32k",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "axg_ao_32k_sel" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap axg_aoclk_cts_rtc_oscin = {
+       .data = &(struct clk_regmap_mux_data) {
+               .offset = AO_RTI_PWR_CNTL_REG0,
+               .mask = 0x1,
+               .shift = 10,
+               .flags = CLK_MUX_ROUND_CLOSEST,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "axg_ao_cts_rtc_oscin",
+               .ops = &clk_regmap_mux_ops,
+               .parent_names = (const char *[]){ "axg_ao_32k",
+                                                 IN_PREFIX "ext_32k-0" },
+               .num_parents = 2,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
 static struct clk_regmap axg_aoclk_clk81 = {
        .data = &(struct clk_regmap_mux_data) {
                .offset = AO_RTI_PWR_CNTL_REG0,
                .mask = 0x1,
                .shift = 8,
+               .flags = CLK_MUX_ROUND_CLOSEST,
        },
        .hw.init = &(struct clk_init_data){
                .name = "axg_ao_clk81",
                .ops = &clk_regmap_mux_ro_ops,
-               .parent_names = (const char *[]){ "clk81", "ao_alt_xtal"},
+               .parent_names = (const char *[]){ IN_PREFIX "mpeg-clk",
+                                                 "axg_ao_cts_rtc_oscin"},
                .num_parents = 2,
+               .flags = CLK_SET_RATE_PARENT,
        },
 };
 
@@ -62,7 +203,8 @@ static struct clk_regmap axg_aoclk_saradc_mux = {
        .hw.init = &(struct clk_init_data){
                .name = "axg_ao_saradc_mux",
                .ops = &clk_regmap_mux_ops,
-               .parent_names = (const char *[]){ "xtal", "axg_ao_clk81" },
+               .parent_names = (const char *[]){ IN_PREFIX "xtal",
+                                                 "axg_ao_clk81" },
                .num_parents = 2,
        },
 };
@@ -106,17 +248,23 @@ static const unsigned int axg_aoclk_reset[] = {
 };
 
 static struct clk_regmap *axg_aoclk_regmap[] = {
-       [CLKID_AO_REMOTE]       = &axg_aoclk_remote,
-       [CLKID_AO_I2C_MASTER]   = &axg_aoclk_i2c_master,
-       [CLKID_AO_I2C_SLAVE]    = &axg_aoclk_i2c_slave,
-       [CLKID_AO_UART1]        = &axg_aoclk_uart1,
-       [CLKID_AO_UART2]        = &axg_aoclk_uart2,
-       [CLKID_AO_IR_BLASTER]   = &axg_aoclk_ir_blaster,
-       [CLKID_AO_SAR_ADC]      = &axg_aoclk_saradc,
-       [CLKID_AO_CLK81]        = &axg_aoclk_clk81,
-       [CLKID_AO_SAR_ADC_SEL]  = &axg_aoclk_saradc_mux,
-       [CLKID_AO_SAR_ADC_DIV]  = &axg_aoclk_saradc_div,
-       [CLKID_AO_SAR_ADC_CLK]  = &axg_aoclk_saradc_gate,
+       &axg_aoclk_remote,
+       &axg_aoclk_i2c_master,
+       &axg_aoclk_i2c_slave,
+       &axg_aoclk_uart1,
+       &axg_aoclk_uart2,
+       &axg_aoclk_ir_blaster,
+       &axg_aoclk_saradc,
+       &axg_aoclk_cts_oscin,
+       &axg_aoclk_32k_pre,
+       &axg_aoclk_32k_div,
+       &axg_aoclk_32k_sel,
+       &axg_aoclk_32k,
+       &axg_aoclk_cts_rtc_oscin,
+       &axg_aoclk_clk81,
+       &axg_aoclk_saradc_mux,
+       &axg_aoclk_saradc_div,
+       &axg_aoclk_saradc_gate,
 };
 
 static const struct clk_hw_onecell_data axg_aoclk_onecell_data = {
@@ -132,10 +280,22 @@ static const struct clk_hw_onecell_data axg_aoclk_onecell_data = {
                [CLKID_AO_SAR_ADC_SEL]  = &axg_aoclk_saradc_mux.hw,
                [CLKID_AO_SAR_ADC_DIV]  = &axg_aoclk_saradc_div.hw,
                [CLKID_AO_SAR_ADC_CLK]  = &axg_aoclk_saradc_gate.hw,
+               [CLKID_AO_CTS_OSCIN]    = &axg_aoclk_cts_oscin.hw,
+               [CLKID_AO_32K_PRE]      = &axg_aoclk_32k_pre.hw,
+               [CLKID_AO_32K_DIV]      = &axg_aoclk_32k_div.hw,
+               [CLKID_AO_32K_SEL]      = &axg_aoclk_32k_sel.hw,
+               [CLKID_AO_32K]          = &axg_aoclk_32k.hw,
+               [CLKID_AO_CTS_RTC_OSCIN] = &axg_aoclk_cts_rtc_oscin.hw,
        },
        .num = NR_CLKS,
 };
 
+static const struct meson_aoclk_input axg_aoclk_inputs[] = {
+       { .name = "xtal",       .required = true  },
+       { .name = "mpeg-clk",   .required = true  },
+       { .name = "ext-32k-0",  .required = false },
+};
+
 static const struct meson_aoclk_data axg_aoclkc_data = {
        .reset_reg      = AO_RTI_GEN_CNTL_REG0,
        .num_reset      = ARRAY_SIZE(axg_aoclk_reset),
@@ -143,6 +303,9 @@ static const struct meson_aoclk_data axg_aoclkc_data = {
        .num_clks       = ARRAY_SIZE(axg_aoclk_regmap),
        .clks           = axg_aoclk_regmap,
        .hw_data        = &axg_aoclk_onecell_data,
+       .inputs         = axg_aoclk_inputs,
+       .num_inputs     = ARRAY_SIZE(axg_aoclk_inputs),
+       .input_prefix   = IN_PREFIX,
 };
 
 static const struct of_device_id axg_aoclkc_match_table[] = {
index 91384d8..3cc27e8 100644 (file)
 #ifndef __AXG_AOCLKC_H
 #define __AXG_AOCLKC_H
 
-#define NR_CLKS        11
-/* AO Configuration Clock registers offsets
- * Register offsets from the data sheet must be multiplied by 4.
- */
-#define AO_RTI_PWR_CNTL_REG1   0x0C
-#define AO_RTI_PWR_CNTL_REG0   0x10
-#define AO_RTI_GEN_CNTL_REG0   0x40
-#define AO_OSCIN_CNTL          0x58
-#define AO_CRT_CLK_CNTL1       0x68
-#define AO_SAR_CLK             0x90
-#define AO_RTC_ALT_CLK_CNTL0   0x94
-#define AO_RTC_ALT_CLK_CNTL1   0x98
+#define NR_CLKS        17
 
 #include <dt-bindings/clock/axg-aoclkc.h>
 #include <dt-bindings/reset/axg-aoclkc.h>
index 8ac3a22..7ab200b 100644 (file)
 #include <linux/reset.h>
 #include <linux/slab.h>
 
-#include "clkc-audio.h"
 #include "axg-audio.h"
+#include "clk-input.h"
+#include "clk-regmap.h"
+#include "clk-phase.h"
+#include "sclk-div.h"
 
 #define AXG_MST_IN_COUNT       8
 #define AXG_SLV_SCLK_COUNT     10
index 792735d..7a8ef80 100644 (file)
@@ -9,16 +9,17 @@
  * Author: Qiufang Dai <qiufang.dai@amlogic.com>
  */
 
-#include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/init.h>
 #include <linux/of_device.h>
-#include <linux/mfd/syscon.h>
 #include <linux/platform_device.h>
-#include <linux/regmap.h>
 
-#include "clkc.h"
+#include "clk-input.h"
+#include "clk-regmap.h"
+#include "clk-pll.h"
+#include "clk-mpll.h"
 #include "axg.h"
+#include "meson-eeclk.h"
 
 static DEFINE_SPINLOCK(meson_clk_lock);
 
@@ -58,7 +59,7 @@ static struct clk_regmap axg_fixed_pll_dco = {
        .hw.init = &(struct clk_init_data){
                .name = "fixed_pll_dco",
                .ops = &meson_clk_pll_ro_ops,
-               .parent_names = (const char *[]){ "xtal" },
+               .parent_names = (const char *[]){ IN_PREFIX "xtal" },
                .num_parents = 1,
        },
 };
@@ -113,7 +114,7 @@ static struct clk_regmap axg_sys_pll_dco = {
        .hw.init = &(struct clk_init_data){
                .name = "sys_pll_dco",
                .ops = &meson_clk_pll_ro_ops,
-               .parent_names = (const char *[]){ "xtal" },
+               .parent_names = (const char *[]){ IN_PREFIX "xtal" },
                .num_parents = 1,
        },
 };
@@ -214,7 +215,7 @@ static struct clk_regmap axg_gp0_pll_dco = {
        .hw.init = &(struct clk_init_data){
                .name = "gp0_pll_dco",
                .ops = &meson_clk_pll_ops,
-               .parent_names = (const char *[]){ "xtal" },
+               .parent_names = (const char *[]){ IN_PREFIX "xtal" },
                .num_parents = 1,
        },
 };
@@ -283,7 +284,7 @@ static struct clk_regmap axg_hifi_pll_dco = {
        .hw.init = &(struct clk_init_data){
                .name = "hifi_pll_dco",
                .ops = &meson_clk_pll_ops,
-               .parent_names = (const char *[]){ "xtal" },
+               .parent_names = (const char *[]){ IN_PREFIX "xtal" },
                .num_parents = 1,
        },
 };
@@ -701,7 +702,7 @@ static struct clk_regmap axg_pcie_pll_dco = {
        .hw.init = &(struct clk_init_data){
                .name = "pcie_pll_dco",
                .ops = &meson_clk_pll_ops,
-               .parent_names = (const char *[]){ "xtal" },
+               .parent_names = (const char *[]){ IN_PREFIX "xtal" },
                .num_parents = 1,
        },
 };
@@ -803,7 +804,7 @@ static struct clk_regmap axg_pcie_cml_en1 = {
 
 static u32 mux_table_clk81[]   = { 0, 2, 3, 4, 5, 6, 7 };
 static const char * const clk81_parent_names[] = {
-       "xtal", "fclk_div7", "mpll1", "mpll2", "fclk_div4",
+       IN_PREFIX "xtal", "fclk_div7", "mpll1", "mpll2", "fclk_div4",
        "fclk_div3", "fclk_div5"
 };
 
@@ -852,7 +853,7 @@ static struct clk_regmap axg_clk81 = {
 };
 
 static const char * const axg_sd_emmc_clk0_parent_names[] = {
-       "xtal", "fclk_div2", "fclk_div3", "fclk_div5", "fclk_div7",
+       IN_PREFIX "xtal", "fclk_div2", "fclk_div3", "fclk_div5", "fclk_div7",
 
        /*
         * Following these parent clocks, we should also have had mpll2, mpll3
@@ -957,7 +958,7 @@ static struct clk_regmap axg_sd_emmc_c_clk0 = {
 static u32 mux_table_gen_clk[] = { 0, 4, 5, 6, 7, 8,
                                    9, 10, 11, 13, 14, };
 static const char * const gen_clk_parent_names[] = {
-       "xtal", "hifi_pll", "mpll0", "mpll1", "mpll2", "mpll3",
+       IN_PREFIX "xtal", "hifi_pll", "mpll0", "mpll1", "mpll2", "mpll3",
        "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7", "gp0_pll",
 };
 
@@ -1255,46 +1256,20 @@ static struct clk_regmap *const axg_clk_regmaps[] = {
        &axg_pcie_pll_od,
 };
 
+static const struct meson_eeclkc_data axg_clkc_data = {
+       .regmap_clks = axg_clk_regmaps,
+       .regmap_clk_num = ARRAY_SIZE(axg_clk_regmaps),
+       .hw_onecell_data = &axg_hw_onecell_data,
+};
+
+
 static const struct of_device_id clkc_match_table[] = {
-       { .compatible = "amlogic,axg-clkc" },
+       { .compatible = "amlogic,axg-clkc", .data = &axg_clkc_data },
        {}
 };
 
-static int axg_clkc_probe(struct platform_device *pdev)
-{
-       struct device *dev = &pdev->dev;
-       struct regmap *map;
-       int ret, i;
-
-       /* Get the hhi system controller node if available */
-       map = syscon_node_to_regmap(of_get_parent(dev->of_node));
-       if (IS_ERR(map)) {
-               dev_err(dev, "failed to get HHI regmap\n");
-               return PTR_ERR(map);
-       }
-
-       /* Populate regmap for the regmap backed clocks */
-       for (i = 0; i < ARRAY_SIZE(axg_clk_regmaps); i++)
-               axg_clk_regmaps[i]->map = map;
-
-       for (i = 0; i < axg_hw_onecell_data.num; i++) {
-               /* array might be sparse */
-               if (!axg_hw_onecell_data.hws[i])
-                       continue;
-
-               ret = devm_clk_hw_register(dev, axg_hw_onecell_data.hws[i]);
-               if (ret) {
-                       dev_err(dev, "Clock registration failed\n");
-                       return ret;
-               }
-       }
-
-       return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
-                                          &axg_hw_onecell_data);
-}
-
 static struct platform_driver axg_driver = {
-       .probe          = axg_clkc_probe,
+       .probe          = meson_eeclkc_probe,
        .driver         = {
                .name   = "axg-clkc",
                .of_match_table = clkc_match_table,
diff --git a/drivers/clk/meson/clk-dualdiv.c b/drivers/clk/meson/clk-dualdiv.c
new file mode 100644 (file)
index 0000000..c5ca23a
--- /dev/null
@@ -0,0 +1,138 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2017 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
+ */
+
+/*
+ * The AO Domain embeds a dual/divider to generate a more precise
+ * 32,768KHz clock for low-power suspend mode and CEC.
+ *     ______   ______
+ *    |      | |      |
+ *    | Div1 |-| Cnt1 |
+ *   /|______| |______|\
+ * -|  ______   ______  X--> Out
+ *   \|      | |      |/
+ *    | Div2 |-| Cnt2 |
+ *    |______| |______|
+ *
+ * The dividing can be switched to single or dual, with a counter
+ * for each divider to set when the switching is done.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+
+#include "clk-regmap.h"
+#include "clk-dualdiv.h"
+
+static inline struct meson_clk_dualdiv_data *
+meson_clk_dualdiv_data(struct clk_regmap *clk)
+{
+       return (struct meson_clk_dualdiv_data *)clk->data;
+}
+
+static unsigned long
+__dualdiv_param_to_rate(unsigned long parent_rate,
+                       const struct meson_clk_dualdiv_param *p)
+{
+       if (!p->dual)
+               return DIV_ROUND_CLOSEST(parent_rate, p->n1);
+
+       return DIV_ROUND_CLOSEST(parent_rate * (p->m1 + p->m2),
+                                p->n1 * p->m1 + p->n2 * p->m2);
+}
+
+static unsigned long meson_clk_dualdiv_recalc_rate(struct clk_hw *hw,
+                                                  unsigned long parent_rate)
+{
+       struct clk_regmap *clk = to_clk_regmap(hw);
+       struct meson_clk_dualdiv_data *dualdiv = meson_clk_dualdiv_data(clk);
+       struct meson_clk_dualdiv_param setting;
+
+       setting.dual = meson_parm_read(clk->map, &dualdiv->dual);
+       setting.n1 = meson_parm_read(clk->map, &dualdiv->n1) + 1;
+       setting.m1 = meson_parm_read(clk->map, &dualdiv->m1) + 1;
+       setting.n2 = meson_parm_read(clk->map, &dualdiv->n2) + 1;
+       setting.m2 = meson_parm_read(clk->map, &dualdiv->m2) + 1;
+
+       return __dualdiv_param_to_rate(parent_rate, &setting);
+}
+
+static const struct meson_clk_dualdiv_param *
+__dualdiv_get_setting(unsigned long rate, unsigned long parent_rate,
+                     struct meson_clk_dualdiv_data *dualdiv)
+{
+       const struct meson_clk_dualdiv_param *table = dualdiv->table;
+       unsigned long best = 0, now = 0;
+       unsigned int i, best_i = 0;
+
+       if (!table)
+               return NULL;
+
+       for (i = 0; table[i].n1; i++) {
+               now = __dualdiv_param_to_rate(parent_rate, &table[i]);
+
+               /* If we get an exact match, don't bother any further */
+               if (now == rate) {
+                       return &table[i];
+               } else if (abs(now - rate) < abs(best - rate)) {
+                       best = now;
+                       best_i = i;
+               }
+       }
+
+       return (struct meson_clk_dualdiv_param *)&table[best_i];
+}
+
+static long meson_clk_dualdiv_round_rate(struct clk_hw *hw, unsigned long rate,
+                                        unsigned long *parent_rate)
+{
+       struct clk_regmap *clk = to_clk_regmap(hw);
+       struct meson_clk_dualdiv_data *dualdiv = meson_clk_dualdiv_data(clk);
+       const struct meson_clk_dualdiv_param *setting =
+               __dualdiv_get_setting(rate, *parent_rate, dualdiv);
+
+       if (!setting)
+               return meson_clk_dualdiv_recalc_rate(hw, *parent_rate);
+
+       return __dualdiv_param_to_rate(*parent_rate, setting);
+}
+
+static int meson_clk_dualdiv_set_rate(struct clk_hw *hw, unsigned long rate,
+                                     unsigned long parent_rate)
+{
+       struct clk_regmap *clk = to_clk_regmap(hw);
+       struct meson_clk_dualdiv_data *dualdiv = meson_clk_dualdiv_data(clk);
+       const struct meson_clk_dualdiv_param *setting =
+               __dualdiv_get_setting(rate, parent_rate, dualdiv);
+
+       if (!setting)
+               return -EINVAL;
+
+       meson_parm_write(clk->map, &dualdiv->dual, setting->dual);
+       meson_parm_write(clk->map, &dualdiv->n1, setting->n1 - 1);
+       meson_parm_write(clk->map, &dualdiv->m1, setting->m1 - 1);
+       meson_parm_write(clk->map, &dualdiv->n2, setting->n2 - 1);
+       meson_parm_write(clk->map, &dualdiv->m2, setting->m2 - 1);
+
+       return 0;
+}
+
+const struct clk_ops meson_clk_dualdiv_ops = {
+       .recalc_rate    = meson_clk_dualdiv_recalc_rate,
+       .round_rate     = meson_clk_dualdiv_round_rate,
+       .set_rate       = meson_clk_dualdiv_set_rate,
+};
+EXPORT_SYMBOL_GPL(meson_clk_dualdiv_ops);
+
+const struct clk_ops meson_clk_dualdiv_ro_ops = {
+       .recalc_rate    = meson_clk_dualdiv_recalc_rate,
+};
+EXPORT_SYMBOL_GPL(meson_clk_dualdiv_ro_ops);
+
+MODULE_DESCRIPTION("Amlogic dual divider driver");
+MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/meson/clk-dualdiv.h b/drivers/clk/meson/clk-dualdiv.h
new file mode 100644 (file)
index 0000000..4aa9390
--- /dev/null
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 BayLibre, SAS.
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
+ */
+
+#ifndef __MESON_CLK_DUALDIV_H
+#define __MESON_CLK_DUALDIV_H
+
+#include <linux/clk-provider.h>
+#include "parm.h"
+
+struct meson_clk_dualdiv_param {
+       unsigned int n1;
+       unsigned int n2;
+       unsigned int m1;
+       unsigned int m2;
+       unsigned int dual;
+};
+
+struct meson_clk_dualdiv_data {
+       struct parm n1;
+       struct parm n2;
+       struct parm m1;
+       struct parm m2;
+       struct parm dual;
+       const struct meson_clk_dualdiv_param *table;
+};
+
+extern const struct clk_ops meson_clk_dualdiv_ops;
+extern const struct clk_ops meson_clk_dualdiv_ro_ops;
+
+#endif /* __MESON_CLK_DUALDIV_H */
index 06b3e3b..086226e 100644 (file)
@@ -7,7 +7,8 @@
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/device.h>
-#include "clkc.h"
+#include <linux/module.h>
+#include "clk-input.h"
 
 static const struct clk_ops meson_clk_no_ops = {};
 
@@ -42,3 +43,7 @@ struct clk_hw *meson_clk_hw_register_input(struct device *dev,
        return ret ? ERR_PTR(ret) : hw;
 }
 EXPORT_SYMBOL_GPL(meson_clk_hw_register_input);
+
+MODULE_DESCRIPTION("Amlogic clock input helper");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/meson/clk-input.h b/drivers/clk/meson/clk-input.h
new file mode 100644 (file)
index 0000000..4a541b9
--- /dev/null
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 BayLibre, SAS.
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
+ */
+
+#ifndef __MESON_CLK_INPUT_H
+#define __MESON_CLK_INPUT_H
+
+#include <linux/clk-provider.h>
+
+struct device;
+
+struct clk_hw *meson_clk_hw_register_input(struct device *dev,
+                                          const char *of_name,
+                                          const char *clk_name,
+                                          unsigned long flags);
+
+#endif /* __MESON_CLK_INPUT_H */
index 650f75c..f76850d 100644 (file)
  */
 
 #include <linux/clk-provider.h>
-#include "clkc.h"
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+#include "clk-regmap.h"
+#include "clk-mpll.h"
 
 #define SDM_DEN 16384
 #define N2_MIN 4
@@ -138,9 +142,15 @@ const struct clk_ops meson_clk_mpll_ro_ops = {
        .recalc_rate    = mpll_recalc_rate,
        .round_rate     = mpll_round_rate,
 };
+EXPORT_SYMBOL_GPL(meson_clk_mpll_ro_ops);
 
 const struct clk_ops meson_clk_mpll_ops = {
        .recalc_rate    = mpll_recalc_rate,
        .round_rate     = mpll_round_rate,
        .set_rate       = mpll_set_rate,
 };
+EXPORT_SYMBOL_GPL(meson_clk_mpll_ops);
+
+MODULE_DESCRIPTION("Amlogic MPLL driver");
+MODULE_AUTHOR("Michael Turquette <mturquette@baylibre.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/meson/clk-mpll.h b/drivers/clk/meson/clk-mpll.h
new file mode 100644 (file)
index 0000000..cf79340
--- /dev/null
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 BayLibre, SAS.
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
+ */
+
+#ifndef __MESON_CLK_MPLL_H
+#define __MESON_CLK_MPLL_H
+
+#include <linux/clk-provider.h>
+#include <linux/spinlock.h>
+
+#include "parm.h"
+
+struct meson_clk_mpll_data {
+       struct parm sdm;
+       struct parm sdm_en;
+       struct parm n2;
+       struct parm ssen;
+       struct parm misc;
+       spinlock_t *lock;
+       u8 flags;
+};
+
+#define CLK_MESON_MPLL_ROUND_CLOSEST   BIT(0)
+
+extern const struct clk_ops meson_clk_mpll_ro_ops;
+extern const struct clk_ops meson_clk_mpll_ops;
+
+#endif /* __MESON_CLK_MPLL_H */
index cba4374..80c3ada 100644 (file)
@@ -5,7 +5,10 @@
  */
 
 #include <linux/clk-provider.h>
-#include "clkc.h"
+#include <linux/module.h>
+
+#include "clk-regmap.h"
+#include "clk-phase.h"
 
 #define phase_step(_width) (360 / (1 << (_width)))
 
@@ -15,13 +18,12 @@ meson_clk_phase_data(struct clk_regmap *clk)
        return (struct meson_clk_phase_data *)clk->data;
 }
 
-int meson_clk_degrees_from_val(unsigned int val, unsigned int width)
+static int meson_clk_degrees_from_val(unsigned int val, unsigned int width)
 {
        return phase_step(width) * val;
 }
-EXPORT_SYMBOL_GPL(meson_clk_degrees_from_val);
 
-unsigned int meson_clk_degrees_to_val(int degrees, unsigned int width)
+static unsigned int meson_clk_degrees_to_val(int degrees, unsigned int width)
 {
        unsigned int val = DIV_ROUND_CLOSEST(degrees, phase_step(width));
 
@@ -31,7 +33,6 @@ unsigned int meson_clk_degrees_to_val(int degrees, unsigned int width)
         */
        return val % (1 << width);
 }
-EXPORT_SYMBOL_GPL(meson_clk_degrees_to_val);
 
 static int meson_clk_phase_get_phase(struct clk_hw *hw)
 {
@@ -61,3 +62,67 @@ const struct clk_ops meson_clk_phase_ops = {
        .set_phase      = meson_clk_phase_set_phase,
 };
 EXPORT_SYMBOL_GPL(meson_clk_phase_ops);
+
+/*
+ * This is a special clock for the audio controller.
+ * The phase of mst_sclk clock output can be controlled independently
+ * for the outside world (ph0), the tdmout (ph1) and tdmin (ph2).
+ * Controlling these 3 phases as just one makes things simpler and
+ * give the same clock view to all the element on the i2s bus.
+ * If necessary, we can still control the phase in the tdm block
+ * which makes these independent control redundant.
+ */
+static inline struct meson_clk_triphase_data *
+meson_clk_triphase_data(struct clk_regmap *clk)
+{
+       return (struct meson_clk_triphase_data *)clk->data;
+}
+
+static void meson_clk_triphase_sync(struct clk_hw *hw)
+{
+       struct clk_regmap *clk = to_clk_regmap(hw);
+       struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk);
+       unsigned int val;
+
+       /* Get phase 0 and sync it to phase 1 and 2 */
+       val = meson_parm_read(clk->map, &tph->ph0);
+       meson_parm_write(clk->map, &tph->ph1, val);
+       meson_parm_write(clk->map, &tph->ph2, val);
+}
+
+static int meson_clk_triphase_get_phase(struct clk_hw *hw)
+{
+       struct clk_regmap *clk = to_clk_regmap(hw);
+       struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk);
+       unsigned int val;
+
+       /* Phase are in sync, reading phase 0 is enough */
+       val = meson_parm_read(clk->map, &tph->ph0);
+
+       return meson_clk_degrees_from_val(val, tph->ph0.width);
+}
+
+static int meson_clk_triphase_set_phase(struct clk_hw *hw, int degrees)
+{
+       struct clk_regmap *clk = to_clk_regmap(hw);
+       struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk);
+       unsigned int val;
+
+       val = meson_clk_degrees_to_val(degrees, tph->ph0.width);
+       meson_parm_write(clk->map, &tph->ph0, val);
+       meson_parm_write(clk->map, &tph->ph1, val);
+       meson_parm_write(clk->map, &tph->ph2, val);
+
+       return 0;
+}
+
+const struct clk_ops meson_clk_triphase_ops = {
+       .init           = meson_clk_triphase_sync,
+       .get_phase      = meson_clk_triphase_get_phase,
+       .set_phase      = meson_clk_triphase_set_phase,
+};
+EXPORT_SYMBOL_GPL(meson_clk_triphase_ops);
+
+MODULE_DESCRIPTION("Amlogic phase driver");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/meson/clk-phase.h b/drivers/clk/meson/clk-phase.h
new file mode 100644 (file)
index 0000000..5579f9c
--- /dev/null
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 BayLibre, SAS.
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
+ */
+
+#ifndef __MESON_CLK_PHASE_H
+#define __MESON_CLK_PHASE_H
+
+#include <linux/clk-provider.h>
+#include "parm.h"
+
+struct meson_clk_phase_data {
+       struct parm ph;
+};
+
+struct meson_clk_triphase_data {
+       struct parm ph0;
+       struct parm ph1;
+       struct parm ph2;
+};
+
+extern const struct clk_ops meson_clk_phase_ops;
+extern const struct clk_ops meson_clk_triphase_ops;
+
+#endif /* __MESON_CLK_PHASE_H */
index afffc15..41e16dd 100644 (file)
 #include <linux/io.h>
 #include <linux/math64.h>
 #include <linux/module.h>
-#include <linux/of_address.h>
-#include <linux/slab.h>
-#include <linux/string.h>
+#include <linux/rational.h>
 
-#include "clkc.h"
+#include "clk-regmap.h"
+#include "clk-pll.h"
 
 static inline struct meson_clk_pll_data *
 meson_clk_pll_data(struct clk_regmap *clk)
@@ -44,12 +43,21 @@ meson_clk_pll_data(struct clk_regmap *clk)
        return (struct meson_clk_pll_data *)clk->data;
 }
 
+static int __pll_round_closest_mult(struct meson_clk_pll_data *pll)
+{
+       if ((pll->flags & CLK_MESON_PLL_ROUND_CLOSEST) &&
+           !MESON_PARM_APPLICABLE(&pll->frac))
+               return 1;
+
+       return 0;
+}
+
 static unsigned long __pll_params_to_rate(unsigned long parent_rate,
-                                         const struct pll_params_table *pllt,
-                                         u16 frac,
+                                         unsigned int m, unsigned int n,
+                                         unsigned int frac,
                                          struct meson_clk_pll_data *pll)
 {
-       u64 rate = (u64)parent_rate * pllt->m;
+       u64 rate = (u64)parent_rate * m;
 
        if (frac && MESON_PARM_APPLICABLE(&pll->frac)) {
                u64 frac_rate = (u64)parent_rate * frac;
@@ -58,7 +66,7 @@ static unsigned long __pll_params_to_rate(unsigned long parent_rate,
                                         (1 << pll->frac.width));
        }
 
-       return DIV_ROUND_UP_ULL(rate, pllt->n);
+       return DIV_ROUND_UP_ULL(rate, n);
 }
 
 static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw,
@@ -66,35 +74,39 @@ static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw,
 {
        struct clk_regmap *clk = to_clk_regmap(hw);
        struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
-       struct pll_params_table pllt;
-       u16 frac;
+       unsigned int m, n, frac;
 
-       pllt.n = meson_parm_read(clk->map, &pll->n);
-       pllt.m = meson_parm_read(clk->map, &pll->m);
+       n = meson_parm_read(clk->map, &pll->n);
+       m = meson_parm_read(clk->map, &pll->m);
 
        frac = MESON_PARM_APPLICABLE(&pll->frac) ?
                meson_parm_read(clk->map, &pll->frac) :
                0;
 
-       return __pll_params_to_rate(parent_rate, &pllt, frac, pll);
+       return __pll_params_to_rate(parent_rate, m, n, frac, pll);
 }
 
-static u16 __pll_params_with_frac(unsigned long rate,
-                                 unsigned long parent_rate,
-                                 const struct pll_params_table *pllt,
-                                 struct meson_clk_pll_data *pll)
+static unsigned int __pll_params_with_frac(unsigned long rate,
+                                          unsigned long parent_rate,
+                                          unsigned int m,
+                                          unsigned int n,
+                                          struct meson_clk_pll_data *pll)
 {
-       u16 frac_max = (1 << pll->frac.width);
-       u64 val = (u64)rate * pllt->n;
+       unsigned int frac_max = (1 << pll->frac.width);
+       u64 val = (u64)rate * n;
+
+       /* Bail out if we are already over the requested rate */
+       if (rate < parent_rate * m / n)
+               return 0;
 
        if (pll->flags & CLK_MESON_PLL_ROUND_CLOSEST)
                val = DIV_ROUND_CLOSEST_ULL(val * frac_max, parent_rate);
        else
                val = div_u64(val * frac_max, parent_rate);
 
-       val -= pllt->m * frac_max;
+       val -= m * frac_max;
 
-       return min((u16)val, (u16)(frac_max - 1));
+       return min((unsigned int)val, (frac_max - 1));
 }
 
 static bool meson_clk_pll_is_better(unsigned long rate,
@@ -102,45 +114,123 @@ static bool meson_clk_pll_is_better(unsigned long rate,
                                    unsigned long now,
                                    struct meson_clk_pll_data *pll)
 {
-       if (!(pll->flags & CLK_MESON_PLL_ROUND_CLOSEST) ||
-           MESON_PARM_APPLICABLE(&pll->frac)) {
-               /* Round down */
-               if (now < rate && best < now)
-                       return true;
-       } else {
+       if (__pll_round_closest_mult(pll)) {
                /* Round Closest */
                if (abs(now - rate) < abs(best - rate))
                        return true;
+       } else {
+               /* Round down */
+               if (now < rate && best < now)
+                       return true;
        }
 
        return false;
 }
 
-static const struct pll_params_table *
-meson_clk_get_pll_settings(unsigned long rate,
-                          unsigned long parent_rate,
-                          struct meson_clk_pll_data *pll)
+static int meson_clk_get_pll_table_index(unsigned int index,
+                                        unsigned int *m,
+                                        unsigned int *n,
+                                        struct meson_clk_pll_data *pll)
 {
-       const struct pll_params_table *table = pll->table;
-       unsigned long best = 0, now = 0;
-       unsigned int i, best_i = 0;
+       if (!pll->table[index].n)
+               return -EINVAL;
+
+       *m = pll->table[index].m;
+       *n = pll->table[index].n;
+
+       return 0;
+}
+
+static unsigned int meson_clk_get_pll_range_m(unsigned long rate,
+                                             unsigned long parent_rate,
+                                             unsigned int n,
+                                             struct meson_clk_pll_data *pll)
+{
+       u64 val = (u64)rate * n;
 
-       if (!table)
-               return NULL;
+       if (__pll_round_closest_mult(pll))
+               return DIV_ROUND_CLOSEST_ULL(val, parent_rate);
 
-       for (i = 0; table[i].n; i++) {
-               now = __pll_params_to_rate(parent_rate, &table[i], 0, pll);
+       return div_u64(val,  parent_rate);
+}
 
-               /* If we get an exact match, don't bother any further */
-               if (now == rate) {
-                       return &table[i];
-               } else if (meson_clk_pll_is_better(rate, best, now, pll)) {
+static int meson_clk_get_pll_range_index(unsigned long rate,
+                                        unsigned long parent_rate,
+                                        unsigned int index,
+                                        unsigned int *m,
+                                        unsigned int *n,
+                                        struct meson_clk_pll_data *pll)
+{
+       *n = index + 1;
+
+       /* Check the predivider range */
+       if (*n >= (1 << pll->n.width))
+               return -EINVAL;
+
+       if (*n == 1) {
+               /* Get the boundaries out the way */
+               if (rate <= pll->range->min * parent_rate) {
+                       *m = pll->range->min;
+                       return -ENODATA;
+               } else if (rate >= pll->range->max * parent_rate) {
+                       *m = pll->range->max;
+                       return -ENODATA;
+               }
+       }
+
+       *m = meson_clk_get_pll_range_m(rate, parent_rate, *n, pll);
+
+       /* the pre-divider gives a multiplier too big - stop */
+       if (*m >= (1 << pll->m.width))
+               return -EINVAL;
+
+       return 0;
+}
+
+static int meson_clk_get_pll_get_index(unsigned long rate,
+                                      unsigned long parent_rate,
+                                      unsigned int index,
+                                      unsigned int *m,
+                                      unsigned int *n,
+                                      struct meson_clk_pll_data *pll)
+{
+       if (pll->range)
+               return meson_clk_get_pll_range_index(rate, parent_rate,
+                                                    index, m, n, pll);
+       else if (pll->table)
+               return meson_clk_get_pll_table_index(index, m, n, pll);
+
+       return -EINVAL;
+}
+
+static int meson_clk_get_pll_settings(unsigned long rate,
+                                     unsigned long parent_rate,
+                                     unsigned int *best_m,
+                                     unsigned int *best_n,
+                                     struct meson_clk_pll_data *pll)
+{
+       unsigned long best = 0, now = 0;
+       unsigned int i, m, n;
+       int ret;
+
+       for (i = 0, ret = 0; !ret; i++) {
+               ret = meson_clk_get_pll_get_index(rate, parent_rate,
+                                                 i, &m, &n, pll);
+               if (ret == -EINVAL)
+                       break;
+
+               now = __pll_params_to_rate(parent_rate, m, n, 0, pll);
+               if (meson_clk_pll_is_better(rate, best, now, pll)) {
                        best = now;
-                       best_i = i;
+                       *best_m = m;
+                       *best_n = n;
+
+                       if (now == rate)
+                               break;
                }
        }
 
-       return (struct pll_params_table *)&table[best_i];
+       return best ? 0 : -EINVAL;
 }
 
 static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
@@ -148,15 +238,15 @@ static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
 {
        struct clk_regmap *clk = to_clk_regmap(hw);
        struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
-       const struct pll_params_table *pllt =
-               meson_clk_get_pll_settings(rate, *parent_rate, pll);
+       unsigned int m, n, frac;
        unsigned long round;
-       u16 frac;
+       int ret;
 
-       if (!pllt)
+       ret = meson_clk_get_pll_settings(rate, *parent_rate, &m, &n, pll);
+       if (ret)
                return meson_clk_pll_recalc_rate(hw, *parent_rate);
 
-       round = __pll_params_to_rate(*parent_rate, pllt, 0, pll);
+       round = __pll_params_to_rate(*parent_rate, m, n, 0, pll);
 
        if (!MESON_PARM_APPLICABLE(&pll->frac) || rate == round)
                return round;
@@ -165,9 +255,9 @@ static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
         * The rate provided by the setting is not an exact match, let's
         * try to improve the result using the fractional parameter
         */
-       frac = __pll_params_with_frac(rate, *parent_rate, pllt, pll);
+       frac = __pll_params_with_frac(rate, *parent_rate, m, n, pll);
 
-       return __pll_params_to_rate(*parent_rate, pllt, frac, pll);
+       return __pll_params_to_rate(*parent_rate, m, n, frac, pll);
 }
 
 static int meson_clk_pll_wait_lock(struct clk_hw *hw)
@@ -254,30 +344,27 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
 {
        struct clk_regmap *clk = to_clk_regmap(hw);
        struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
-       const struct pll_params_table *pllt;
-       unsigned int enabled;
+       unsigned int enabled, m, n, frac = 0, ret;
        unsigned long old_rate;
-       u16 frac = 0;
 
        if (parent_rate == 0 || rate == 0)
                return -EINVAL;
 
        old_rate = rate;
 
-       pllt = meson_clk_get_pll_settings(rate, parent_rate, pll);
-       if (!pllt)
-               return -EINVAL;
+       ret = meson_clk_get_pll_settings(rate, parent_rate, &m, &n, pll);
+       if (ret)
+               return ret;
 
        enabled = meson_parm_read(clk->map, &pll->en);
        if (enabled)
                meson_clk_pll_disable(hw);
 
-       meson_parm_write(clk->map, &pll->n, pllt->n);
-       meson_parm_write(clk->map, &pll->m, pllt->m);
-
+       meson_parm_write(clk->map, &pll->n, n);
+       meson_parm_write(clk->map, &pll->m, m);
 
        if (MESON_PARM_APPLICABLE(&pll->frac)) {
-               frac = __pll_params_with_frac(rate, parent_rate, pllt, pll);
+               frac = __pll_params_with_frac(rate, parent_rate, m, n, pll);
                meson_parm_write(clk->map, &pll->frac, frac);
        }
 
@@ -309,8 +396,15 @@ const struct clk_ops meson_clk_pll_ops = {
        .enable         = meson_clk_pll_enable,
        .disable        = meson_clk_pll_disable
 };
+EXPORT_SYMBOL_GPL(meson_clk_pll_ops);
 
 const struct clk_ops meson_clk_pll_ro_ops = {
        .recalc_rate    = meson_clk_pll_recalc_rate,
        .is_enabled     = meson_clk_pll_is_enabled,
 };
+EXPORT_SYMBOL_GPL(meson_clk_pll_ro_ops);
+
+MODULE_DESCRIPTION("Amlogic PLL driver");
+MODULE_AUTHOR("Carlo Caione <carlo@endlessm.com>");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/meson/clk-pll.h b/drivers/clk/meson/clk-pll.h
new file mode 100644 (file)
index 0000000..55af2e2
--- /dev/null
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 BayLibre, SAS.
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
+ */
+
+#ifndef __MESON_CLK_PLL_H
+#define __MESON_CLK_PLL_H
+
+#include <linux/clk-provider.h>
+#include <linux/regmap.h>
+#include "parm.h"
+
+struct pll_params_table {
+       unsigned int    m;
+       unsigned int    n;
+};
+
+struct pll_mult_range {
+       unsigned int    min;
+       unsigned int    max;
+};
+
+#define PLL_PARAMS(_m, _n)                                             \
+       {                                                               \
+               .m              = (_m),                                 \
+               .n              = (_n),                                 \
+       }
+
+#define CLK_MESON_PLL_ROUND_CLOSEST    BIT(0)
+
+struct meson_clk_pll_data {
+       struct parm en;
+       struct parm m;
+       struct parm n;
+       struct parm frac;
+       struct parm l;
+       struct parm rst;
+       const struct reg_sequence *init_regs;
+       unsigned int init_count;
+       const struct pll_params_table *table;
+       const struct pll_mult_range *range;
+       u8 flags;
+};
+
+extern const struct clk_ops meson_clk_pll_ro_ops;
+extern const struct clk_ops meson_clk_pll_ops;
+
+#endif /* __MESON_CLK_PLL_H */
index c515f67..dcd1757 100644 (file)
@@ -4,6 +4,7 @@
  * Author: Jerome Brunet <jbrunet@baylibre.com>
  */
 
+#include <linux/module.h>
 #include "clk-regmap.h"
 
 static int clk_regmap_gate_endisable(struct clk_hw *hw, int enable)
@@ -180,3 +181,7 @@ const struct clk_ops clk_regmap_mux_ro_ops = {
        .get_parent = clk_regmap_mux_get_parent,
 };
 EXPORT_SYMBOL_GPL(clk_regmap_mux_ro_ops);
+
+MODULE_DESCRIPTION("Amlogic regmap backed clock driver");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL v2");
index e9c5728..1dd0abe 100644 (file)
@@ -111,4 +111,24 @@ clk_get_regmap_mux_data(struct clk_regmap *clk)
 extern const struct clk_ops clk_regmap_mux_ops;
 extern const struct clk_ops clk_regmap_mux_ro_ops;
 
+#define __MESON_GATE(_name, _reg, _bit, _ops)                          \
+struct clk_regmap _name = {                                            \
+       .data = &(struct clk_regmap_gate_data){                         \
+               .offset = (_reg),                                       \
+               .bit_idx = (_bit),                                      \
+       },                                                              \
+       .hw.init = &(struct clk_init_data) {                            \
+               .name = #_name,                                         \
+               .ops = _ops,                                            \
+               .parent_names = (const char *[]){ "clk81" },            \
+               .num_parents = 1,                                       \
+               .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED),     \
+       },                                                              \
+}
+
+#define MESON_GATE(_name, _reg, _bit)  \
+       __MESON_GATE(_name, _reg, _bit, &clk_regmap_gate_ops)
+
+#define MESON_GATE_RO(_name, _reg, _bit)       \
+       __MESON_GATE(_name, _reg, _bit, &clk_regmap_gate_ro_ops)
 #endif /* __CLK_REGMAP_H */
diff --git a/drivers/clk/meson/clk-triphase.c b/drivers/clk/meson/clk-triphase.c
deleted file mode 100644 (file)
index 4a59936..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-// SPDX-License-Identifier: (GPL-2.0 OR MIT)
-/*
- * Copyright (c) 2018 BayLibre, SAS.
- * Author: Jerome Brunet <jbrunet@baylibre.com>
- */
-
-#include <linux/clk-provider.h>
-#include "clkc-audio.h"
-
-/*
- * This is a special clock for the audio controller.
- * The phase of mst_sclk clock output can be controlled independently
- * for the outside world (ph0), the tdmout (ph1) and tdmin (ph2).
- * Controlling these 3 phases as just one makes things simpler and
- * give the same clock view to all the element on the i2s bus.
- * If necessary, we can still control the phase in the tdm block
- * which makes these independent control redundant.
- */
-static inline struct meson_clk_triphase_data *
-meson_clk_triphase_data(struct clk_regmap *clk)
-{
-       return (struct meson_clk_triphase_data *)clk->data;
-}
-
-static void meson_clk_triphase_sync(struct clk_hw *hw)
-{
-       struct clk_regmap *clk = to_clk_regmap(hw);
-       struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk);
-       unsigned int val;
-
-       /* Get phase 0 and sync it to phase 1 and 2 */
-       val = meson_parm_read(clk->map, &tph->ph0);
-       meson_parm_write(clk->map, &tph->ph1, val);
-       meson_parm_write(clk->map, &tph->ph2, val);
-}
-
-static int meson_clk_triphase_get_phase(struct clk_hw *hw)
-{
-       struct clk_regmap *clk = to_clk_regmap(hw);
-       struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk);
-       unsigned int val;
-
-       /* Phase are in sync, reading phase 0 is enough */
-       val = meson_parm_read(clk->map, &tph->ph0);
-
-       return meson_clk_degrees_from_val(val, tph->ph0.width);
-}
-
-static int meson_clk_triphase_set_phase(struct clk_hw *hw, int degrees)
-{
-       struct clk_regmap *clk = to_clk_regmap(hw);
-       struct meson_clk_triphase_data *tph = meson_clk_triphase_data(clk);
-       unsigned int val;
-
-       val = meson_clk_degrees_to_val(degrees, tph->ph0.width);
-       meson_parm_write(clk->map, &tph->ph0, val);
-       meson_parm_write(clk->map, &tph->ph1, val);
-       meson_parm_write(clk->map, &tph->ph2, val);
-
-       return 0;
-}
-
-const struct clk_ops meson_clk_triphase_ops = {
-       .init           = meson_clk_triphase_sync,
-       .get_phase      = meson_clk_triphase_get_phase,
-       .set_phase      = meson_clk_triphase_set_phase,
-};
-EXPORT_SYMBOL_GPL(meson_clk_triphase_ops);
diff --git a/drivers/clk/meson/clkc-audio.h b/drivers/clk/meson/clkc-audio.h
deleted file mode 100644 (file)
index 0a7c157..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (c) 2018 BayLibre, SAS.
- * Author: Jerome Brunet <jbrunet@baylibre.com>
- */
-
-#ifndef __MESON_CLKC_AUDIO_H
-#define __MESON_CLKC_AUDIO_H
-
-#include "clkc.h"
-
-struct meson_clk_triphase_data {
-       struct parm ph0;
-       struct parm ph1;
-       struct parm ph2;
-};
-
-struct meson_sclk_div_data {
-       struct parm div;
-       struct parm hi;
-       unsigned int cached_div;
-       struct clk_duty cached_duty;
-};
-
-extern const struct clk_ops meson_clk_triphase_ops;
-extern const struct clk_ops meson_sclk_div_ops;
-
-#endif /* __MESON_CLKC_AUDIO_H */
diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h
deleted file mode 100644 (file)
index 6183b22..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (c) 2015 Endless Mobile, Inc.
- * Author: Carlo Caione <carlo@endlessm.com>
- */
-
-#ifndef __CLKC_H
-#define __CLKC_H
-
-#include <linux/clk-provider.h>
-#include "clk-regmap.h"
-
-#define PMASK(width)                   GENMASK(width - 1, 0)
-#define SETPMASK(width, shift)         GENMASK(shift + width - 1, shift)
-#define CLRPMASK(width, shift)         (~SETPMASK(width, shift))
-
-#define PARM_GET(width, shift, reg)                                    \
-       (((reg) & SETPMASK(width, shift)) >> (shift))
-#define PARM_SET(width, shift, reg, val)                               \
-       (((reg) & CLRPMASK(width, shift)) | ((val) << (shift)))
-
-#define MESON_PARM_APPLICABLE(p)               (!!((p)->width))
-
-struct parm {
-       u16     reg_off;
-       u8      shift;
-       u8      width;
-};
-
-static inline unsigned int meson_parm_read(struct regmap *map, struct parm *p)
-{
-       unsigned int val;
-
-       regmap_read(map, p->reg_off, &val);
-       return PARM_GET(p->width, p->shift, val);
-}
-
-static inline void meson_parm_write(struct regmap *map, struct parm *p,
-                                   unsigned int val)
-{
-       regmap_update_bits(map, p->reg_off, SETPMASK(p->width, p->shift),
-                          val << p->shift);
-}
-
-
-struct pll_params_table {
-       u16             m;
-       u16             n;
-};
-
-#define PLL_PARAMS(_m, _n)                                             \
-       {                                                               \
-               .m              = (_m),                                 \
-               .n              = (_n),                                 \
-       }
-
-#define CLK_MESON_PLL_ROUND_CLOSEST    BIT(0)
-
-struct meson_clk_pll_data {
-       struct parm en;
-       struct parm m;
-       struct parm n;
-       struct parm frac;
-       struct parm l;
-       struct parm rst;
-       const struct reg_sequence *init_regs;
-       unsigned int init_count;
-       const struct pll_params_table *table;
-       u8 flags;
-};
-
-#define to_meson_clk_pll(_hw) container_of(_hw, struct meson_clk_pll, hw)
-
-struct meson_clk_mpll_data {
-       struct parm sdm;
-       struct parm sdm_en;
-       struct parm n2;
-       struct parm ssen;
-       struct parm misc;
-       spinlock_t *lock;
-       u8 flags;
-};
-
-#define CLK_MESON_MPLL_ROUND_CLOSEST   BIT(0)
-
-struct meson_clk_phase_data {
-       struct parm ph;
-};
-
-int meson_clk_degrees_from_val(unsigned int val, unsigned int width);
-unsigned int meson_clk_degrees_to_val(int degrees, unsigned int width);
-
-struct meson_vid_pll_div_data {
-       struct parm val;
-       struct parm sel;
-};
-
-#define MESON_GATE(_name, _reg, _bit)                                  \
-struct clk_regmap _name = {                                            \
-       .data = &(struct clk_regmap_gate_data){                         \
-               .offset = (_reg),                                       \
-               .bit_idx = (_bit),                                      \
-       },                                                              \
-       .hw.init = &(struct clk_init_data) {                            \
-               .name = #_name,                                         \
-               .ops = &clk_regmap_gate_ops,                            \
-               .parent_names = (const char *[]){ "clk81" },            \
-               .num_parents = 1,                                       \
-               .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED),     \
-       },                                                              \
-};
-
-/* clk_ops */
-extern const struct clk_ops meson_clk_pll_ro_ops;
-extern const struct clk_ops meson_clk_pll_ops;
-extern const struct clk_ops meson_clk_cpu_ops;
-extern const struct clk_ops meson_clk_mpll_ro_ops;
-extern const struct clk_ops meson_clk_mpll_ops;
-extern const struct clk_ops meson_clk_phase_ops;
-extern const struct clk_ops meson_vid_pll_div_ro_ops;
-
-struct clk_hw *meson_clk_hw_register_input(struct device *dev,
-                                          const char *of_name,
-                                          const char *clk_name,
-                                          unsigned long flags);
-
-#endif /* __CLKC_H */
diff --git a/drivers/clk/meson/g12a-aoclk.c b/drivers/clk/meson/g12a-aoclk.c
new file mode 100644 (file)
index 0000000..1994e73
--- /dev/null
@@ -0,0 +1,454 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Amlogic Meson-AXG Clock Controller Driver
+ *
+ * Copyright (c) 2016 Baylibre SAS.
+ * Author: Michael Turquette <mturquette@baylibre.com>
+ *
+ * Copyright (c) 2019 Baylibre SAS.
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ */
+#include <linux/clk-provider.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/mfd/syscon.h>
+#include "meson-aoclk.h"
+#include "g12a-aoclk.h"
+
+#include "clk-regmap.h"
+#include "clk-dualdiv.h"
+
+#define IN_PREFIX "ao-in-"
+
+/*
+ * AO Configuration Clock registers offsets
+ * Register offsets from the data sheet must be multiplied by 4.
+ */
+#define AO_RTI_STATUS_REG3     0x0C
+#define AO_RTI_PWR_CNTL_REG0   0x10
+#define AO_RTI_GEN_CNTL_REG0   0x40
+#define AO_CLK_GATE0           0x4c
+#define AO_CLK_GATE0_SP                0x50
+#define AO_OSCIN_CNTL          0x58
+#define AO_CEC_CLK_CNTL_REG0   0x74
+#define AO_CEC_CLK_CNTL_REG1   0x78
+#define AO_SAR_CLK             0x90
+#define AO_RTC_ALT_CLK_CNTL0   0x94
+#define AO_RTC_ALT_CLK_CNTL1   0x98
+
+/*
+ * Like every other peripheral clock gate in Amlogic Clock drivers,
+ * we are using CLK_IGNORE_UNUSED here, so we keep the state of the
+ * bootloader. The goal is to remove this flag at some point.
+ * Actually removing it will require some extensive test to be done safely.
+ */
+#define AXG_AO_GATE(_name, _reg, _bit)                                 \
+static struct clk_regmap g12a_aoclk_##_name = {                                \
+       .data = &(struct clk_regmap_gate_data) {                        \
+               .offset = (_reg),                                       \
+               .bit_idx = (_bit),                                      \
+       },                                                              \
+       .hw.init = &(struct clk_init_data) {                            \
+               .name =  "g12a_ao_" #_name,                             \
+               .ops = &clk_regmap_gate_ops,                            \
+               .parent_names = (const char *[]){ IN_PREFIX "mpeg-clk" }, \
+               .num_parents = 1,                                       \
+               .flags = CLK_IGNORE_UNUSED,                             \
+       },                                                              \
+}
+
+AXG_AO_GATE(ahb, AO_CLK_GATE0, 0);
+AXG_AO_GATE(ir_in, AO_CLK_GATE0, 1);
+AXG_AO_GATE(i2c_m0, AO_CLK_GATE0, 2);
+AXG_AO_GATE(i2c_s0, AO_CLK_GATE0, 3);
+AXG_AO_GATE(uart, AO_CLK_GATE0, 4);
+AXG_AO_GATE(prod_i2c, AO_CLK_GATE0, 5);
+AXG_AO_GATE(uart2, AO_CLK_GATE0, 6);
+AXG_AO_GATE(ir_out, AO_CLK_GATE0, 7);
+AXG_AO_GATE(saradc, AO_CLK_GATE0, 8);
+AXG_AO_GATE(mailbox, AO_CLK_GATE0_SP, 0);
+AXG_AO_GATE(m3, AO_CLK_GATE0_SP, 1);
+AXG_AO_GATE(ahb_sram, AO_CLK_GATE0_SP, 2);
+AXG_AO_GATE(rti, AO_CLK_GATE0_SP, 3);
+AXG_AO_GATE(m4_fclk, AO_CLK_GATE0_SP, 4);
+AXG_AO_GATE(m4_hclk, AO_CLK_GATE0_SP, 5);
+
+static struct clk_regmap g12a_aoclk_cts_oscin = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = AO_RTI_PWR_CNTL_REG0,
+               .bit_idx = 14,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cts_oscin",
+               .ops = &clk_regmap_gate_ro_ops,
+               .parent_names = (const char *[]){ IN_PREFIX "xtal" },
+               .num_parents = 1,
+       },
+};
+
+static const struct meson_clk_dualdiv_param g12a_32k_div_table[] = {
+       {
+               .dual   = 1,
+               .n1     = 733,
+               .m1     = 8,
+               .n2     = 732,
+               .m2     = 11,
+       }, {}
+};
+
+/* 32k_by_oscin clock */
+
+static struct clk_regmap g12a_aoclk_32k_by_oscin_pre = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = AO_RTC_ALT_CLK_CNTL0,
+               .bit_idx = 31,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "g12a_ao_32k_by_oscin_pre",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "cts_oscin" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_regmap g12a_aoclk_32k_by_oscin_div = {
+       .data = &(struct meson_clk_dualdiv_data){
+               .n1 = {
+                       .reg_off = AO_RTC_ALT_CLK_CNTL0,
+                       .shift   = 0,
+                       .width   = 12,
+               },
+               .n2 = {
+                       .reg_off = AO_RTC_ALT_CLK_CNTL0,
+                       .shift   = 12,
+                       .width   = 12,
+               },
+               .m1 = {
+                       .reg_off = AO_RTC_ALT_CLK_CNTL1,
+                       .shift   = 0,
+                       .width   = 12,
+               },
+               .m2 = {
+                       .reg_off = AO_RTC_ALT_CLK_CNTL1,
+                       .shift   = 12,
+                       .width   = 12,
+               },
+               .dual = {
+                       .reg_off = AO_RTC_ALT_CLK_CNTL0,
+                       .shift   = 28,
+                       .width   = 1,
+               },
+               .table = g12a_32k_div_table,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "g12a_ao_32k_by_oscin_div",
+               .ops = &meson_clk_dualdiv_ops,
+               .parent_names = (const char *[]){ "g12a_ao_32k_by_oscin_pre" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_regmap g12a_aoclk_32k_by_oscin_sel = {
+       .data = &(struct clk_regmap_mux_data) {
+               .offset = AO_RTC_ALT_CLK_CNTL1,
+               .mask = 0x1,
+               .shift = 24,
+               .flags = CLK_MUX_ROUND_CLOSEST,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "g12a_ao_32k_by_oscin_sel",
+               .ops = &clk_regmap_mux_ops,
+               .parent_names = (const char *[]){ "g12a_ao_32k_by_oscin_div",
+                                                 "g12a_ao_32k_by_oscin_pre" },
+               .num_parents = 2,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap g12a_aoclk_32k_by_oscin = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = AO_RTC_ALT_CLK_CNTL0,
+               .bit_idx = 30,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "g12a_ao_32k_by_oscin",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "g12a_ao_32k_by_oscin_sel" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+/* cec clock */
+
+static struct clk_regmap g12a_aoclk_cec_pre = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = AO_CEC_CLK_CNTL_REG0,
+               .bit_idx = 31,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "g12a_ao_cec_pre",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "cts_oscin" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_regmap g12a_aoclk_cec_div = {
+       .data = &(struct meson_clk_dualdiv_data){
+               .n1 = {
+                       .reg_off = AO_CEC_CLK_CNTL_REG0,
+                       .shift   = 0,
+                       .width   = 12,
+               },
+               .n2 = {
+                       .reg_off = AO_CEC_CLK_CNTL_REG0,
+                       .shift   = 12,
+                       .width   = 12,
+               },
+               .m1 = {
+                       .reg_off = AO_CEC_CLK_CNTL_REG1,
+                       .shift   = 0,
+                       .width   = 12,
+               },
+               .m2 = {
+                       .reg_off = AO_CEC_CLK_CNTL_REG1,
+                       .shift   = 12,
+                       .width   = 12,
+               },
+               .dual = {
+                       .reg_off = AO_CEC_CLK_CNTL_REG0,
+                       .shift   = 28,
+                       .width   = 1,
+               },
+               .table = g12a_32k_div_table,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "g12a_ao_cec_div",
+               .ops = &meson_clk_dualdiv_ops,
+               .parent_names = (const char *[]){ "g12a_ao_cec_pre" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_regmap g12a_aoclk_cec_sel = {
+       .data = &(struct clk_regmap_mux_data) {
+               .offset = AO_CEC_CLK_CNTL_REG1,
+               .mask = 0x1,
+               .shift = 24,
+               .flags = CLK_MUX_ROUND_CLOSEST,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "g12a_ao_cec_sel",
+               .ops = &clk_regmap_mux_ops,
+               .parent_names = (const char *[]){ "g12a_ao_cec_div",
+                                                 "g12a_ao_cec_pre" },
+               .num_parents = 2,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap g12a_aoclk_cec = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = AO_CEC_CLK_CNTL_REG0,
+               .bit_idx = 30,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "g12a_ao_cec",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "g12a_ao_cec_sel" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap g12a_aoclk_cts_rtc_oscin = {
+       .data = &(struct clk_regmap_mux_data) {
+               .offset = AO_RTI_PWR_CNTL_REG0,
+               .mask = 0x1,
+               .shift = 10,
+               .flags = CLK_MUX_ROUND_CLOSEST,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "g12a_ao_cts_rtc_oscin",
+               .ops = &clk_regmap_mux_ops,
+               .parent_names = (const char *[]){ "g12a_ao_32k_by_oscin",
+                                                 IN_PREFIX "ext_32k-0" },
+               .num_parents = 2,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap g12a_aoclk_clk81 = {
+       .data = &(struct clk_regmap_mux_data) {
+               .offset = AO_RTI_PWR_CNTL_REG0,
+               .mask = 0x1,
+               .shift = 8,
+               .flags = CLK_MUX_ROUND_CLOSEST,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "g12a_ao_clk81",
+               .ops = &clk_regmap_mux_ro_ops,
+               .parent_names = (const char *[]){ IN_PREFIX "mpeg-clk",
+                                                 "g12a_ao_cts_rtc_oscin"},
+               .num_parents = 2,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap g12a_aoclk_saradc_mux = {
+       .data = &(struct clk_regmap_mux_data) {
+               .offset = AO_SAR_CLK,
+               .mask = 0x3,
+               .shift = 9,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "g12a_ao_saradc_mux",
+               .ops = &clk_regmap_mux_ops,
+               .parent_names = (const char *[]){ IN_PREFIX "xtal",
+                                                 "g12a_ao_clk81" },
+               .num_parents = 2,
+       },
+};
+
+static struct clk_regmap g12a_aoclk_saradc_div = {
+       .data = &(struct clk_regmap_div_data) {
+               .offset = AO_SAR_CLK,
+               .shift = 0,
+               .width = 8,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "g12a_ao_saradc_div",
+               .ops = &clk_regmap_divider_ops,
+               .parent_names = (const char *[]){ "g12a_ao_saradc_mux" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap g12a_aoclk_saradc_gate = {
+       .data = &(struct clk_regmap_gate_data) {
+               .offset = AO_SAR_CLK,
+               .bit_idx = 8,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "g12a_ao_saradc_gate",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "g12a_ao_saradc_div" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static const unsigned int g12a_aoclk_reset[] = {
+       [RESET_AO_IR_IN]        = 16,
+       [RESET_AO_UART]         = 17,
+       [RESET_AO_I2C_M]        = 18,
+       [RESET_AO_I2C_S]        = 19,
+       [RESET_AO_SAR_ADC]      = 20,
+       [RESET_AO_UART2]        = 22,
+       [RESET_AO_IR_OUT]       = 23,
+};
+
+static struct clk_regmap *g12a_aoclk_regmap[] = {
+       &g12a_aoclk_ahb,
+       &g12a_aoclk_ir_in,
+       &g12a_aoclk_i2c_m0,
+       &g12a_aoclk_i2c_s0,
+       &g12a_aoclk_uart,
+       &g12a_aoclk_prod_i2c,
+       &g12a_aoclk_uart2,
+       &g12a_aoclk_ir_out,
+       &g12a_aoclk_saradc,
+       &g12a_aoclk_mailbox,
+       &g12a_aoclk_m3,
+       &g12a_aoclk_ahb_sram,
+       &g12a_aoclk_rti,
+       &g12a_aoclk_m4_fclk,
+       &g12a_aoclk_m4_hclk,
+       &g12a_aoclk_cts_oscin,
+       &g12a_aoclk_32k_by_oscin_pre,
+       &g12a_aoclk_32k_by_oscin_div,
+       &g12a_aoclk_32k_by_oscin_sel,
+       &g12a_aoclk_32k_by_oscin,
+       &g12a_aoclk_cec_pre,
+       &g12a_aoclk_cec_div,
+       &g12a_aoclk_cec_sel,
+       &g12a_aoclk_cec,
+       &g12a_aoclk_cts_rtc_oscin,
+       &g12a_aoclk_clk81,
+       &g12a_aoclk_saradc_mux,
+       &g12a_aoclk_saradc_div,
+       &g12a_aoclk_saradc_gate,
+};
+
+static const struct clk_hw_onecell_data g12a_aoclk_onecell_data = {
+       .hws = {
+               [CLKID_AO_AHB]          = &g12a_aoclk_ahb.hw,
+               [CLKID_AO_IR_IN]        = &g12a_aoclk_ir_in.hw,
+               [CLKID_AO_I2C_M0]       = &g12a_aoclk_i2c_m0.hw,
+               [CLKID_AO_I2C_S0]       = &g12a_aoclk_i2c_s0.hw,
+               [CLKID_AO_UART]         = &g12a_aoclk_uart.hw,
+               [CLKID_AO_PROD_I2C]     = &g12a_aoclk_prod_i2c.hw,
+               [CLKID_AO_UART2]        = &g12a_aoclk_uart2.hw,
+               [CLKID_AO_IR_OUT]       = &g12a_aoclk_ir_out.hw,
+               [CLKID_AO_SAR_ADC]      = &g12a_aoclk_saradc.hw,
+               [CLKID_AO_MAILBOX]      = &g12a_aoclk_mailbox.hw,
+               [CLKID_AO_M3]           = &g12a_aoclk_m3.hw,
+               [CLKID_AO_AHB_SRAM]     = &g12a_aoclk_ahb_sram.hw,
+               [CLKID_AO_RTI]          = &g12a_aoclk_rti.hw,
+               [CLKID_AO_M4_FCLK]      = &g12a_aoclk_m4_fclk.hw,
+               [CLKID_AO_M4_HCLK]      = &g12a_aoclk_m4_hclk.hw,
+               [CLKID_AO_CLK81]        = &g12a_aoclk_clk81.hw,
+               [CLKID_AO_SAR_ADC_SEL]  = &g12a_aoclk_saradc_mux.hw,
+               [CLKID_AO_SAR_ADC_DIV]  = &g12a_aoclk_saradc_div.hw,
+               [CLKID_AO_SAR_ADC_CLK]  = &g12a_aoclk_saradc_gate.hw,
+               [CLKID_AO_CTS_OSCIN]    = &g12a_aoclk_cts_oscin.hw,
+               [CLKID_AO_32K_PRE]      = &g12a_aoclk_32k_by_oscin_pre.hw,
+               [CLKID_AO_32K_DIV]      = &g12a_aoclk_32k_by_oscin_div.hw,
+               [CLKID_AO_32K_SEL]      = &g12a_aoclk_32k_by_oscin_sel.hw,
+               [CLKID_AO_32K]          = &g12a_aoclk_32k_by_oscin.hw,
+               [CLKID_AO_CEC_PRE]      = &g12a_aoclk_cec_pre.hw,
+               [CLKID_AO_CEC_DIV]      = &g12a_aoclk_cec_div.hw,
+               [CLKID_AO_CEC_SEL]      = &g12a_aoclk_cec_sel.hw,
+               [CLKID_AO_CEC]          = &g12a_aoclk_cec.hw,
+               [CLKID_AO_CTS_RTC_OSCIN] = &g12a_aoclk_cts_rtc_oscin.hw,
+       },
+       .num = NR_CLKS,
+};
+
+static const struct meson_aoclk_input g12a_aoclk_inputs[] = {
+       { .name = "xtal",       .required = true  },
+       { .name = "mpeg-clk",   .required = true  },
+       { .name = "ext-32k-0",  .required = false },
+};
+
+static const struct meson_aoclk_data g12a_aoclkc_data = {
+       .reset_reg      = AO_RTI_GEN_CNTL_REG0,
+       .num_reset      = ARRAY_SIZE(g12a_aoclk_reset),
+       .reset          = g12a_aoclk_reset,
+       .num_clks       = ARRAY_SIZE(g12a_aoclk_regmap),
+       .clks           = g12a_aoclk_regmap,
+       .hw_data        = &g12a_aoclk_onecell_data,
+       .inputs         = g12a_aoclk_inputs,
+       .num_inputs     = ARRAY_SIZE(g12a_aoclk_inputs),
+       .input_prefix   = IN_PREFIX,
+};
+
+static const struct of_device_id g12a_aoclkc_match_table[] = {
+       {
+               .compatible     = "amlogic,meson-g12a-aoclkc",
+               .data           = &g12a_aoclkc_data,
+       },
+       { }
+};
+
+static struct platform_driver g12a_aoclkc_driver = {
+       .probe          = meson_aoclkc_probe,
+       .driver         = {
+               .name   = "g12a-aoclkc",
+               .of_match_table = g12a_aoclkc_match_table,
+       },
+};
+
+builtin_platform_driver(g12a_aoclkc_driver);
diff --git a/drivers/clk/meson/g12a-aoclk.h b/drivers/clk/meson/g12a-aoclk.h
new file mode 100644 (file)
index 0000000..04b0d55
--- /dev/null
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Copyright (c) 2019 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ */
+
+#ifndef __G12A_AOCLKC_H
+#define __G12A_AOCLKC_H
+
+/*
+ * CLKID index values
+ *
+ * These indices are entirely contrived and do not map onto the hardware.
+ * It has now been decided to expose everything by default in the DT header:
+ * include/dt-bindings/clock/g12a-aoclkc.h. Only the clocks ids we don't want
+ * to expose, such as the internal muxes and dividers of composite clocks,
+ * will remain defined here.
+ */
+#define CLKID_AO_SAR_ADC_SEL   16
+#define CLKID_AO_SAR_ADC_DIV   17
+#define CLKID_AO_CTS_OSCIN     19
+#define CLKID_AO_32K_PRE       20
+#define CLKID_AO_32K_DIV       21
+#define CLKID_AO_32K_SEL       22
+#define CLKID_AO_CEC_PRE       24
+#define CLKID_AO_CEC_DIV       25
+#define CLKID_AO_CEC_SEL       26
+
+#define NR_CLKS        29
+
+#include <dt-bindings/clock/g12a-aoclkc.h>
+#include <dt-bindings/reset/g12a-aoclkc.h>
+
+#endif /* __G12A_AOCLKC_H */
diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c
new file mode 100644 (file)
index 0000000..0e1ce8c
--- /dev/null
@@ -0,0 +1,2359 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Amlogic Meson-G12A Clock Controller Driver
+ *
+ * Copyright (c) 2016 Baylibre SAS.
+ * Author: Michael Turquette <mturquette@baylibre.com>
+ *
+ * Copyright (c) 2018 Amlogic, inc.
+ * Author: Qiufang Dai <qiufang.dai@amlogic.com>
+ * Author: Jian Hu <jian.hu@amlogic.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/init.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#include "clk-input.h"
+#include "clk-mpll.h"
+#include "clk-pll.h"
+#include "clk-regmap.h"
+#include "vid-pll-div.h"
+#include "meson-eeclk.h"
+#include "g12a.h"
+
+static DEFINE_SPINLOCK(meson_clk_lock);
+
+static struct clk_regmap g12a_fixed_pll_dco = {
+       .data = &(struct meson_clk_pll_data){
+               .en = {
+                       .reg_off = HHI_FIX_PLL_CNTL0,
+                       .shift   = 28,
+                       .width   = 1,
+               },
+               .m = {
+                       .reg_off = HHI_FIX_PLL_CNTL0,
+                       .shift   = 0,
+                       .width   = 8,
+               },
+               .n = {
+                       .reg_off = HHI_FIX_PLL_CNTL0,
+                       .shift   = 10,
+                       .width   = 5,
+               },
+               .frac = {
+                       .reg_off = HHI_FIX_PLL_CNTL1,
+                       .shift   = 0,
+                       .width   = 17,
+               },
+               .l = {
+                       .reg_off = HHI_FIX_PLL_CNTL0,
+                       .shift   = 31,
+                       .width   = 1,
+               },
+               .rst = {
+                       .reg_off = HHI_FIX_PLL_CNTL0,
+                       .shift   = 29,
+                       .width   = 1,
+               },
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "fixed_pll_dco",
+               .ops = &meson_clk_pll_ro_ops,
+               .parent_names = (const char *[]){ IN_PREFIX "xtal" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_regmap g12a_fixed_pll = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_FIX_PLL_CNTL0,
+               .shift = 16,
+               .width = 2,
+               .flags = CLK_DIVIDER_POWER_OF_TWO,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "fixed_pll",
+               .ops = &clk_regmap_divider_ro_ops,
+               .parent_names = (const char *[]){ "fixed_pll_dco" },
+               .num_parents = 1,
+               /*
+                * This clock won't ever change at runtime so
+                * CLK_SET_RATE_PARENT is not required
+                */
+       },
+};
+
+/*
+ * Internal sys pll emulation configuration parameters
+ */
+static const struct reg_sequence g12a_sys_init_regs[] = {
+       { .reg = HHI_SYS_PLL_CNTL1,     .def = 0x00000000 },
+       { .reg = HHI_SYS_PLL_CNTL2,     .def = 0x00000000 },
+       { .reg = HHI_SYS_PLL_CNTL3,     .def = 0x48681c00 },
+       { .reg = HHI_SYS_PLL_CNTL4,     .def = 0x88770290 },
+       { .reg = HHI_SYS_PLL_CNTL5,     .def = 0x39272000 },
+       { .reg = HHI_SYS_PLL_CNTL6,     .def = 0x56540000 },
+};
+
+static struct clk_regmap g12a_sys_pll_dco = {
+       .data = &(struct meson_clk_pll_data){
+               .en = {
+                       .reg_off = HHI_SYS_PLL_CNTL0,
+                       .shift   = 28,
+                       .width   = 1,
+               },
+               .m = {
+                       .reg_off = HHI_SYS_PLL_CNTL0,
+                       .shift   = 0,
+                       .width   = 8,
+               },
+               .n = {
+                       .reg_off = HHI_SYS_PLL_CNTL0,
+                       .shift   = 10,
+                       .width   = 5,
+               },
+               .l = {
+                       .reg_off = HHI_SYS_PLL_CNTL0,
+                       .shift   = 31,
+                       .width   = 1,
+               },
+               .rst = {
+                       .reg_off = HHI_SYS_PLL_CNTL0,
+                       .shift   = 29,
+                       .width   = 1,
+               },
+               .init_regs = g12a_sys_init_regs,
+               .init_count = ARRAY_SIZE(g12a_sys_init_regs),
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "sys_pll_dco",
+               .ops = &meson_clk_pll_ro_ops,
+               .parent_names = (const char *[]){ IN_PREFIX "xtal" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_regmap g12a_sys_pll = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_SYS_PLL_CNTL0,
+               .shift = 16,
+               .width = 3,
+               .flags = CLK_DIVIDER_POWER_OF_TWO,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "sys_pll",
+               .ops = &clk_regmap_divider_ro_ops,
+               .parent_names = (const char *[]){ "sys_pll_dco" },
+               .num_parents = 1,
+       },
+};
+
+static const struct pll_mult_range g12a_gp0_pll_mult_range = {
+       .min = 55,
+       .max = 255,
+};
+
+/*
+ * Internal gp0 pll emulation configuration parameters
+ */
+static const struct reg_sequence g12a_gp0_init_regs[] = {
+       { .reg = HHI_GP0_PLL_CNTL1,     .def = 0x00000000 },
+       { .reg = HHI_GP0_PLL_CNTL2,     .def = 0x00000000 },
+       { .reg = HHI_GP0_PLL_CNTL3,     .def = 0x48681c00 },
+       { .reg = HHI_GP0_PLL_CNTL4,     .def = 0x33771290 },
+       { .reg = HHI_GP0_PLL_CNTL5,     .def = 0x39272000 },
+       { .reg = HHI_GP0_PLL_CNTL6,     .def = 0x56540000 },
+};
+
+static struct clk_regmap g12a_gp0_pll_dco = {
+       .data = &(struct meson_clk_pll_data){
+               .en = {
+                       .reg_off = HHI_GP0_PLL_CNTL0,
+                       .shift   = 28,
+                       .width   = 1,
+               },
+               .m = {
+                       .reg_off = HHI_GP0_PLL_CNTL0,
+                       .shift   = 0,
+                       .width   = 8,
+               },
+               .n = {
+                       .reg_off = HHI_GP0_PLL_CNTL0,
+                       .shift   = 10,
+                       .width   = 5,
+               },
+               .frac = {
+                       .reg_off = HHI_GP0_PLL_CNTL1,
+                       .shift   = 0,
+                       .width   = 17,
+               },
+               .l = {
+                       .reg_off = HHI_GP0_PLL_CNTL0,
+                       .shift   = 31,
+                       .width   = 1,
+               },
+               .rst = {
+                       .reg_off = HHI_GP0_PLL_CNTL0,
+                       .shift   = 29,
+                       .width   = 1,
+               },
+               .range = &g12a_gp0_pll_mult_range,
+               .init_regs = g12a_gp0_init_regs,
+               .init_count = ARRAY_SIZE(g12a_gp0_init_regs),
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "gp0_pll_dco",
+               .ops = &meson_clk_pll_ops,
+               .parent_names = (const char *[]){ IN_PREFIX "xtal" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_regmap g12a_gp0_pll = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_GP0_PLL_CNTL0,
+               .shift = 16,
+               .width = 3,
+               .flags = (CLK_DIVIDER_POWER_OF_TWO |
+                         CLK_DIVIDER_ROUND_CLOSEST),
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "gp0_pll",
+               .ops = &clk_regmap_divider_ops,
+               .parent_names = (const char *[]){ "gp0_pll_dco" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+/*
+ * Internal hifi pll emulation configuration parameters
+ */
+static const struct reg_sequence g12a_hifi_init_regs[] = {
+       { .reg = HHI_HIFI_PLL_CNTL1,    .def = 0x00000000 },
+       { .reg = HHI_HIFI_PLL_CNTL2,    .def = 0x00000000 },
+       { .reg = HHI_HIFI_PLL_CNTL3,    .def = 0x6a285c00 },
+       { .reg = HHI_HIFI_PLL_CNTL4,    .def = 0x65771290 },
+       { .reg = HHI_HIFI_PLL_CNTL5,    .def = 0x39272000 },
+       { .reg = HHI_HIFI_PLL_CNTL6,    .def = 0x56540000 },
+};
+
+static struct clk_regmap g12a_hifi_pll_dco = {
+       .data = &(struct meson_clk_pll_data){
+               .en = {
+                       .reg_off = HHI_HIFI_PLL_CNTL0,
+                       .shift   = 28,
+                       .width   = 1,
+               },
+               .m = {
+                       .reg_off = HHI_HIFI_PLL_CNTL0,
+                       .shift   = 0,
+                       .width   = 8,
+               },
+               .n = {
+                       .reg_off = HHI_HIFI_PLL_CNTL0,
+                       .shift   = 10,
+                       .width   = 5,
+               },
+               .frac = {
+                       .reg_off = HHI_HIFI_PLL_CNTL1,
+                       .shift   = 0,
+                       .width   = 17,
+               },
+               .l = {
+                       .reg_off = HHI_HIFI_PLL_CNTL0,
+                       .shift   = 31,
+                       .width   = 1,
+               },
+               .rst = {
+                       .reg_off = HHI_HIFI_PLL_CNTL0,
+                       .shift   = 29,
+                       .width   = 1,
+               },
+               .range = &g12a_gp0_pll_mult_range,
+               .init_regs = g12a_hifi_init_regs,
+               .init_count = ARRAY_SIZE(g12a_hifi_init_regs),
+               .flags = CLK_MESON_PLL_ROUND_CLOSEST,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "hifi_pll_dco",
+               .ops = &meson_clk_pll_ops,
+               .parent_names = (const char *[]){ IN_PREFIX "xtal" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_regmap g12a_hifi_pll = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_HIFI_PLL_CNTL0,
+               .shift = 16,
+               .width = 2,
+               .flags = (CLK_DIVIDER_POWER_OF_TWO |
+                         CLK_DIVIDER_ROUND_CLOSEST),
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "hifi_pll",
+               .ops = &clk_regmap_divider_ops,
+               .parent_names = (const char *[]){ "hifi_pll_dco" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap g12a_hdmi_pll_dco = {
+       .data = &(struct meson_clk_pll_data){
+               .en = {
+                       .reg_off = HHI_HDMI_PLL_CNTL0,
+                       .shift   = 28,
+                       .width   = 1,
+               },
+               .m = {
+                       .reg_off = HHI_HDMI_PLL_CNTL0,
+                       .shift   = 0,
+                       .width   = 8,
+               },
+               .n = {
+                       .reg_off = HHI_HDMI_PLL_CNTL0,
+                       .shift   = 10,
+                       .width   = 5,
+               },
+               .frac = {
+                       .reg_off = HHI_HDMI_PLL_CNTL1,
+                       .shift   = 0,
+                       .width   = 16,
+               },
+               .l = {
+                       .reg_off = HHI_HDMI_PLL_CNTL0,
+                       .shift   = 30,
+                       .width   = 1,
+               },
+               .rst = {
+                       .reg_off = HHI_HDMI_PLL_CNTL0,
+                       .shift   = 29,
+                       .width   = 1,
+               },
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "hdmi_pll_dco",
+               .ops = &meson_clk_pll_ro_ops,
+               .parent_names = (const char *[]){ IN_PREFIX "xtal" },
+               .num_parents = 1,
+               /*
+                * Display directly handle hdmi pll registers ATM, we need
+                * NOCACHE to keep our view of the clock as accurate as possible
+                */
+               .flags = CLK_GET_RATE_NOCACHE,
+       },
+};
+
+static struct clk_regmap g12a_hdmi_pll_od = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_HDMI_PLL_CNTL0,
+               .shift = 16,
+               .width = 2,
+               .flags = CLK_DIVIDER_POWER_OF_TWO,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "hdmi_pll_od",
+               .ops = &clk_regmap_divider_ro_ops,
+               .parent_names = (const char *[]){ "hdmi_pll_dco" },
+               .num_parents = 1,
+               .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap g12a_hdmi_pll_od2 = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_HDMI_PLL_CNTL0,
+               .shift = 18,
+               .width = 2,
+               .flags = CLK_DIVIDER_POWER_OF_TWO,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "hdmi_pll_od2",
+               .ops = &clk_regmap_divider_ro_ops,
+               .parent_names = (const char *[]){ "hdmi_pll_od" },
+               .num_parents = 1,
+               .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap g12a_hdmi_pll = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_HDMI_PLL_CNTL0,
+               .shift = 20,
+               .width = 2,
+               .flags = CLK_DIVIDER_POWER_OF_TWO,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "hdmi_pll",
+               .ops = &clk_regmap_divider_ro_ops,
+               .parent_names = (const char *[]){ "hdmi_pll_od2" },
+               .num_parents = 1,
+               .flags = CLK_GET_RATE_NOCACHE | CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_fixed_factor g12a_fclk_div2_div = {
+       .mult = 1,
+       .div = 2,
+       .hw.init = &(struct clk_init_data){
+               .name = "fclk_div2_div",
+               .ops = &clk_fixed_factor_ops,
+               .parent_names = (const char *[]){ "fixed_pll" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_regmap g12a_fclk_div2 = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_FIX_PLL_CNTL1,
+               .bit_idx = 24,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "fclk_div2",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "fclk_div2_div" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_fixed_factor g12a_fclk_div3_div = {
+       .mult = 1,
+       .div = 3,
+       .hw.init = &(struct clk_init_data){
+               .name = "fclk_div3_div",
+               .ops = &clk_fixed_factor_ops,
+               .parent_names = (const char *[]){ "fixed_pll" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_regmap g12a_fclk_div3 = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_FIX_PLL_CNTL1,
+               .bit_idx = 20,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "fclk_div3",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "fclk_div3_div" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_fixed_factor g12a_fclk_div4_div = {
+       .mult = 1,
+       .div = 4,
+       .hw.init = &(struct clk_init_data){
+               .name = "fclk_div4_div",
+               .ops = &clk_fixed_factor_ops,
+               .parent_names = (const char *[]){ "fixed_pll" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_regmap g12a_fclk_div4 = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_FIX_PLL_CNTL1,
+               .bit_idx = 21,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "fclk_div4",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "fclk_div4_div" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_fixed_factor g12a_fclk_div5_div = {
+       .mult = 1,
+       .div = 5,
+       .hw.init = &(struct clk_init_data){
+               .name = "fclk_div5_div",
+               .ops = &clk_fixed_factor_ops,
+               .parent_names = (const char *[]){ "fixed_pll" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_regmap g12a_fclk_div5 = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_FIX_PLL_CNTL1,
+               .bit_idx = 22,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "fclk_div5",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "fclk_div5_div" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_fixed_factor g12a_fclk_div7_div = {
+       .mult = 1,
+       .div = 7,
+       .hw.init = &(struct clk_init_data){
+               .name = "fclk_div7_div",
+               .ops = &clk_fixed_factor_ops,
+               .parent_names = (const char *[]){ "fixed_pll" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_regmap g12a_fclk_div7 = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_FIX_PLL_CNTL1,
+               .bit_idx = 23,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "fclk_div7",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "fclk_div7_div" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_fixed_factor g12a_fclk_div2p5_div = {
+       .mult = 1,
+       .div = 5,
+       .hw.init = &(struct clk_init_data){
+               .name = "fclk_div2p5_div",
+               .ops = &clk_fixed_factor_ops,
+               .parent_names = (const char *[]){ "fixed_pll_dco" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_regmap g12a_fclk_div2p5 = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_FIX_PLL_CNTL1,
+               .bit_idx = 25,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "fclk_div2p5",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "fclk_div2p5_div" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_fixed_factor g12a_mpll_50m_div = {
+       .mult = 1,
+       .div = 80,
+       .hw.init = &(struct clk_init_data){
+               .name = "mpll_50m_div",
+               .ops = &clk_fixed_factor_ops,
+               .parent_names = (const char *[]){ "fixed_pll_dco" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_regmap g12a_mpll_50m = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_FIX_PLL_CNTL3,
+               .mask = 0x1,
+               .shift = 5,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "mpll_50m",
+               .ops = &clk_regmap_mux_ro_ops,
+               .parent_names = (const char *[]){ IN_PREFIX "xtal",
+                                                 "mpll_50m_div" },
+               .num_parents = 2,
+       },
+};
+
+static struct clk_fixed_factor g12a_mpll_prediv = {
+       .mult = 1,
+       .div = 2,
+       .hw.init = &(struct clk_init_data){
+               .name = "mpll_prediv",
+               .ops = &clk_fixed_factor_ops,
+               .parent_names = (const char *[]){ "fixed_pll_dco" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_regmap g12a_mpll0_div = {
+       .data = &(struct meson_clk_mpll_data){
+               .sdm = {
+                       .reg_off = HHI_MPLL_CNTL1,
+                       .shift   = 0,
+                       .width   = 14,
+               },
+               .sdm_en = {
+                       .reg_off = HHI_MPLL_CNTL1,
+                       .shift   = 30,
+                       .width   = 1,
+               },
+               .n2 = {
+                       .reg_off = HHI_MPLL_CNTL1,
+                       .shift   = 20,
+                       .width   = 9,
+               },
+               .ssen = {
+                       .reg_off = HHI_MPLL_CNTL1,
+                       .shift   = 29,
+                       .width   = 1,
+               },
+               .lock = &meson_clk_lock,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "mpll0_div",
+               .ops = &meson_clk_mpll_ops,
+               .parent_names = (const char *[]){ "mpll_prediv" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_regmap g12a_mpll0 = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_MPLL_CNTL1,
+               .bit_idx = 31,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "mpll0",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "mpll0_div" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap g12a_mpll1_div = {
+       .data = &(struct meson_clk_mpll_data){
+               .sdm = {
+                       .reg_off = HHI_MPLL_CNTL3,
+                       .shift   = 0,
+                       .width   = 14,
+               },
+               .sdm_en = {
+                       .reg_off = HHI_MPLL_CNTL3,
+                       .shift   = 30,
+                       .width   = 1,
+               },
+               .n2 = {
+                       .reg_off = HHI_MPLL_CNTL3,
+                       .shift   = 20,
+                       .width   = 9,
+               },
+               .ssen = {
+                       .reg_off = HHI_MPLL_CNTL3,
+                       .shift   = 29,
+                       .width   = 1,
+               },
+               .lock = &meson_clk_lock,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "mpll1_div",
+               .ops = &meson_clk_mpll_ops,
+               .parent_names = (const char *[]){ "mpll_prediv" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_regmap g12a_mpll1 = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_MPLL_CNTL3,
+               .bit_idx = 31,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "mpll1",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "mpll1_div" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap g12a_mpll2_div = {
+       .data = &(struct meson_clk_mpll_data){
+               .sdm = {
+                       .reg_off = HHI_MPLL_CNTL5,
+                       .shift   = 0,
+                       .width   = 14,
+               },
+               .sdm_en = {
+                       .reg_off = HHI_MPLL_CNTL5,
+                       .shift   = 30,
+                       .width   = 1,
+               },
+               .n2 = {
+                       .reg_off = HHI_MPLL_CNTL5,
+                       .shift   = 20,
+                       .width   = 9,
+               },
+               .ssen = {
+                       .reg_off = HHI_MPLL_CNTL5,
+                       .shift   = 29,
+                       .width   = 1,
+               },
+               .lock = &meson_clk_lock,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "mpll2_div",
+               .ops = &meson_clk_mpll_ops,
+               .parent_names = (const char *[]){ "mpll_prediv" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_regmap g12a_mpll2 = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_MPLL_CNTL5,
+               .bit_idx = 31,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "mpll2",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "mpll2_div" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap g12a_mpll3_div = {
+       .data = &(struct meson_clk_mpll_data){
+               .sdm = {
+                       .reg_off = HHI_MPLL_CNTL7,
+                       .shift   = 0,
+                       .width   = 14,
+               },
+               .sdm_en = {
+                       .reg_off = HHI_MPLL_CNTL7,
+                       .shift   = 30,
+                       .width   = 1,
+               },
+               .n2 = {
+                       .reg_off = HHI_MPLL_CNTL7,
+                       .shift   = 20,
+                       .width   = 9,
+               },
+               .ssen = {
+                       .reg_off = HHI_MPLL_CNTL7,
+                       .shift   = 29,
+                       .width   = 1,
+               },
+               .lock = &meson_clk_lock,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "mpll3_div",
+               .ops = &meson_clk_mpll_ops,
+               .parent_names = (const char *[]){ "mpll_prediv" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_regmap g12a_mpll3 = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_MPLL_CNTL7,
+               .bit_idx = 31,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "mpll3",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "mpll3_div" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static u32 mux_table_clk81[]   = { 0, 2, 3, 4, 5, 6, 7 };
+static const char * const clk81_parent_names[] = {
+       IN_PREFIX "xtal", "fclk_div7", "mpll1", "mpll2", "fclk_div4",
+       "fclk_div3", "fclk_div5"
+};
+
+static struct clk_regmap g12a_mpeg_clk_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_MPEG_CLK_CNTL,
+               .mask = 0x7,
+               .shift = 12,
+               .table = mux_table_clk81,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "mpeg_clk_sel",
+               .ops = &clk_regmap_mux_ro_ops,
+               .parent_names = clk81_parent_names,
+               .num_parents = ARRAY_SIZE(clk81_parent_names),
+       },
+};
+
+static struct clk_regmap g12a_mpeg_clk_div = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_MPEG_CLK_CNTL,
+               .shift = 0,
+               .width = 7,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "mpeg_clk_div",
+               .ops = &clk_regmap_divider_ops,
+               .parent_names = (const char *[]){ "mpeg_clk_sel" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap g12a_clk81 = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_MPEG_CLK_CNTL,
+               .bit_idx = 7,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "clk81",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "mpeg_clk_div" },
+               .num_parents = 1,
+               .flags = (CLK_SET_RATE_PARENT | CLK_IS_CRITICAL),
+       },
+};
+
+static const char * const g12a_sd_emmc_clk0_parent_names[] = {
+       IN_PREFIX "xtal", "fclk_div2", "fclk_div3", "fclk_div5", "fclk_div7",
+
+       /*
+        * Following these parent clocks, we should also have had mpll2, mpll3
+        * and gp0_pll but these clocks are too precious to be used here. All
+        * the necessary rates for MMC and NAND operation can be acheived using
+        * g12a_ee_core or fclk_div clocks
+        */
+};
+
+/* SDIO clock */
+static struct clk_regmap g12a_sd_emmc_a_clk0_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_SD_EMMC_CLK_CNTL,
+               .mask = 0x7,
+               .shift = 9,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "sd_emmc_a_clk0_sel",
+               .ops = &clk_regmap_mux_ops,
+               .parent_names = g12a_sd_emmc_clk0_parent_names,
+               .num_parents = ARRAY_SIZE(g12a_sd_emmc_clk0_parent_names),
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap g12a_sd_emmc_a_clk0_div = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_SD_EMMC_CLK_CNTL,
+               .shift = 0,
+               .width = 7,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "sd_emmc_a_clk0_div",
+               .ops = &clk_regmap_divider_ops,
+               .parent_names = (const char *[]){ "sd_emmc_a_clk0_sel" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap g12a_sd_emmc_a_clk0 = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_SD_EMMC_CLK_CNTL,
+               .bit_idx = 7,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "sd_emmc_a_clk0",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "sd_emmc_a_clk0_div" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+/* SDcard clock */
+static struct clk_regmap g12a_sd_emmc_b_clk0_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_SD_EMMC_CLK_CNTL,
+               .mask = 0x7,
+               .shift = 25,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "sd_emmc_b_clk0_sel",
+               .ops = &clk_regmap_mux_ops,
+               .parent_names = g12a_sd_emmc_clk0_parent_names,
+               .num_parents = ARRAY_SIZE(g12a_sd_emmc_clk0_parent_names),
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap g12a_sd_emmc_b_clk0_div = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_SD_EMMC_CLK_CNTL,
+               .shift = 16,
+               .width = 7,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "sd_emmc_b_clk0_div",
+               .ops = &clk_regmap_divider_ops,
+               .parent_names = (const char *[]){ "sd_emmc_b_clk0_sel" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap g12a_sd_emmc_b_clk0 = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_SD_EMMC_CLK_CNTL,
+               .bit_idx = 23,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "sd_emmc_b_clk0",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "sd_emmc_b_clk0_div" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+/* EMMC/NAND clock */
+static struct clk_regmap g12a_sd_emmc_c_clk0_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_NAND_CLK_CNTL,
+               .mask = 0x7,
+               .shift = 9,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "sd_emmc_c_clk0_sel",
+               .ops = &clk_regmap_mux_ops,
+               .parent_names = g12a_sd_emmc_clk0_parent_names,
+               .num_parents = ARRAY_SIZE(g12a_sd_emmc_clk0_parent_names),
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap g12a_sd_emmc_c_clk0_div = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_NAND_CLK_CNTL,
+               .shift = 0,
+               .width = 7,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "sd_emmc_c_clk0_div",
+               .ops = &clk_regmap_divider_ops,
+               .parent_names = (const char *[]){ "sd_emmc_c_clk0_sel" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap g12a_sd_emmc_c_clk0 = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_NAND_CLK_CNTL,
+               .bit_idx = 7,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "sd_emmc_c_clk0",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "sd_emmc_c_clk0_div" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+/* VPU Clock */
+
+static const char * const g12a_vpu_parent_names[] = {
+       "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7",
+       "mpll1", "vid_pll", "hifi_pll", "gp0_pll",
+};
+
+static struct clk_regmap g12a_vpu_0_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_VPU_CLK_CNTL,
+               .mask = 0x3,
+               .shift = 9,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "vpu_0_sel",
+               .ops = &clk_regmap_mux_ops,
+               .parent_names = g12a_vpu_parent_names,
+               .num_parents = ARRAY_SIZE(g12a_vpu_parent_names),
+               .flags = CLK_SET_RATE_NO_REPARENT,
+       },
+};
+
+static struct clk_regmap g12a_vpu_0_div = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_VPU_CLK_CNTL,
+               .shift = 0,
+               .width = 7,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "vpu_0_div",
+               .ops = &clk_regmap_divider_ops,
+               .parent_names = (const char *[]){ "vpu_0_sel" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap g12a_vpu_0 = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VPU_CLK_CNTL,
+               .bit_idx = 8,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vpu_0",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "vpu_0_div" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_regmap g12a_vpu_1_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_VPU_CLK_CNTL,
+               .mask = 0x3,
+               .shift = 25,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "vpu_1_sel",
+               .ops = &clk_regmap_mux_ops,
+               .parent_names = g12a_vpu_parent_names,
+               .num_parents = ARRAY_SIZE(g12a_vpu_parent_names),
+               .flags = CLK_SET_RATE_NO_REPARENT,
+       },
+};
+
+static struct clk_regmap g12a_vpu_1_div = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_VPU_CLK_CNTL,
+               .shift = 16,
+               .width = 7,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "vpu_1_div",
+               .ops = &clk_regmap_divider_ops,
+               .parent_names = (const char *[]){ "vpu_1_sel" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap g12a_vpu_1 = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VPU_CLK_CNTL,
+               .bit_idx = 24,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vpu_1",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "vpu_1_div" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_regmap g12a_vpu = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_VPU_CLK_CNTL,
+               .mask = 1,
+               .shift = 31,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "vpu",
+               .ops = &clk_regmap_mux_ops,
+               /*
+                * bit 31 selects from 2 possible parents:
+                * vpu_0 or vpu_1
+                */
+               .parent_names = (const char *[]){ "vpu_0", "vpu_1" },
+               .num_parents = 2,
+               .flags = CLK_SET_RATE_NO_REPARENT,
+       },
+};
+
+/* VAPB Clock */
+
+static const char * const g12a_vapb_parent_names[] = {
+       "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7",
+       "mpll1", "vid_pll", "mpll2", "fclk_div2p5",
+};
+
+static struct clk_regmap g12a_vapb_0_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_VAPBCLK_CNTL,
+               .mask = 0x3,
+               .shift = 9,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "vapb_0_sel",
+               .ops = &clk_regmap_mux_ops,
+               .parent_names = g12a_vapb_parent_names,
+               .num_parents = ARRAY_SIZE(g12a_vapb_parent_names),
+               .flags = CLK_SET_RATE_NO_REPARENT,
+       },
+};
+
+static struct clk_regmap g12a_vapb_0_div = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_VAPBCLK_CNTL,
+               .shift = 0,
+               .width = 7,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "vapb_0_div",
+               .ops = &clk_regmap_divider_ops,
+               .parent_names = (const char *[]){ "vapb_0_sel" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap g12a_vapb_0 = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VAPBCLK_CNTL,
+               .bit_idx = 8,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vapb_0",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "vapb_0_div" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_regmap g12a_vapb_1_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_VAPBCLK_CNTL,
+               .mask = 0x3,
+               .shift = 25,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "vapb_1_sel",
+               .ops = &clk_regmap_mux_ops,
+               .parent_names = g12a_vapb_parent_names,
+               .num_parents = ARRAY_SIZE(g12a_vapb_parent_names),
+               .flags = CLK_SET_RATE_NO_REPARENT,
+       },
+};
+
+static struct clk_regmap g12a_vapb_1_div = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_VAPBCLK_CNTL,
+               .shift = 16,
+               .width = 7,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "vapb_1_div",
+               .ops = &clk_regmap_divider_ops,
+               .parent_names = (const char *[]){ "vapb_1_sel" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap g12a_vapb_1 = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VAPBCLK_CNTL,
+               .bit_idx = 24,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vapb_1",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "vapb_1_div" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_regmap g12a_vapb_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_VAPBCLK_CNTL,
+               .mask = 1,
+               .shift = 31,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "vapb_sel",
+               .ops = &clk_regmap_mux_ops,
+               /*
+                * bit 31 selects from 2 possible parents:
+                * vapb_0 or vapb_1
+                */
+               .parent_names = (const char *[]){ "vapb_0", "vapb_1" },
+               .num_parents = 2,
+               .flags = CLK_SET_RATE_NO_REPARENT,
+       },
+};
+
+static struct clk_regmap g12a_vapb = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VAPBCLK_CNTL,
+               .bit_idx = 30,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vapb",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "vapb_sel" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+/* Video Clocks */
+
+static struct clk_regmap g12a_vid_pll_div = {
+       .data = &(struct meson_vid_pll_div_data){
+               .val = {
+                       .reg_off = HHI_VID_PLL_CLK_DIV,
+                       .shift   = 0,
+                       .width   = 15,
+               },
+               .sel = {
+                       .reg_off = HHI_VID_PLL_CLK_DIV,
+                       .shift   = 16,
+                       .width   = 2,
+               },
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vid_pll_div",
+               .ops = &meson_vid_pll_div_ro_ops,
+               .parent_names = (const char *[]){ "hdmi_pll" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
+       },
+};
+
+static const char * const g12a_vid_pll_parent_names[] = { "vid_pll_div",
+                                                         "hdmi_pll" };
+
+static struct clk_regmap g12a_vid_pll_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_VID_PLL_CLK_DIV,
+               .mask = 0x1,
+               .shift = 18,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "vid_pll_sel",
+               .ops = &clk_regmap_mux_ops,
+               /*
+                * bit 18 selects from 2 possible parents:
+                * vid_pll_div or hdmi_pll
+                */
+               .parent_names = g12a_vid_pll_parent_names,
+               .num_parents = ARRAY_SIZE(g12a_vid_pll_parent_names),
+               .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
+       },
+};
+
+static struct clk_regmap g12a_vid_pll = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VID_PLL_CLK_DIV,
+               .bit_idx = 19,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vid_pll",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "vid_pll_sel" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static const char * const g12a_vclk_parent_names[] = {
+       "vid_pll", "gp0_pll", "hifi_pll", "mpll1", "fclk_div3", "fclk_div4",
+       "fclk_div5", "fclk_div7"
+};
+
+static struct clk_regmap g12a_vclk_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_VID_CLK_CNTL,
+               .mask = 0x7,
+               .shift = 16,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "vclk_sel",
+               .ops = &clk_regmap_mux_ops,
+               .parent_names = g12a_vclk_parent_names,
+               .num_parents = ARRAY_SIZE(g12a_vclk_parent_names),
+               .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
+       },
+};
+
+static struct clk_regmap g12a_vclk2_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_VIID_CLK_CNTL,
+               .mask = 0x7,
+               .shift = 16,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "vclk2_sel",
+               .ops = &clk_regmap_mux_ops,
+               .parent_names = g12a_vclk_parent_names,
+               .num_parents = ARRAY_SIZE(g12a_vclk_parent_names),
+               .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
+       },
+};
+
+static struct clk_regmap g12a_vclk_input = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VID_CLK_DIV,
+               .bit_idx = 16,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vclk_input",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "vclk_sel" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_regmap g12a_vclk2_input = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VIID_CLK_DIV,
+               .bit_idx = 16,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vclk2_input",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "vclk2_sel" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_regmap g12a_vclk_div = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_VID_CLK_DIV,
+               .shift = 0,
+               .width = 8,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "vclk_div",
+               .ops = &clk_regmap_divider_ops,
+               .parent_names = (const char *[]){ "vclk_input" },
+               .num_parents = 1,
+               .flags = CLK_GET_RATE_NOCACHE,
+       },
+};
+
+static struct clk_regmap g12a_vclk2_div = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_VIID_CLK_DIV,
+               .shift = 0,
+               .width = 8,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "vclk2_div",
+               .ops = &clk_regmap_divider_ops,
+               .parent_names = (const char *[]){ "vclk2_input" },
+               .num_parents = 1,
+               .flags = CLK_GET_RATE_NOCACHE,
+       },
+};
+
+static struct clk_regmap g12a_vclk = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VID_CLK_CNTL,
+               .bit_idx = 19,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vclk",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "vclk_div" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_regmap g12a_vclk2 = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VIID_CLK_CNTL,
+               .bit_idx = 19,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vclk2",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "vclk2_div" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_regmap g12a_vclk_div1 = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VID_CLK_CNTL,
+               .bit_idx = 0,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vclk_div1",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "vclk" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_regmap g12a_vclk_div2_en = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VID_CLK_CNTL,
+               .bit_idx = 1,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vclk_div2_en",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "vclk" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_regmap g12a_vclk_div4_en = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VID_CLK_CNTL,
+               .bit_idx = 2,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vclk_div4_en",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "vclk" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_regmap g12a_vclk_div6_en = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VID_CLK_CNTL,
+               .bit_idx = 3,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vclk_div6_en",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "vclk" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_regmap g12a_vclk_div12_en = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VID_CLK_CNTL,
+               .bit_idx = 4,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vclk_div12_en",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "vclk" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_regmap g12a_vclk2_div1 = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VIID_CLK_CNTL,
+               .bit_idx = 0,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vclk2_div1",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "vclk2" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_regmap g12a_vclk2_div2_en = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VIID_CLK_CNTL,
+               .bit_idx = 1,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vclk2_div2_en",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "vclk2" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_regmap g12a_vclk2_div4_en = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VIID_CLK_CNTL,
+               .bit_idx = 2,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vclk2_div4_en",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "vclk2" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_regmap g12a_vclk2_div6_en = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VIID_CLK_CNTL,
+               .bit_idx = 3,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vclk2_div6_en",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "vclk2" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_regmap g12a_vclk2_div12_en = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VIID_CLK_CNTL,
+               .bit_idx = 4,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "vclk2_div12_en",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "vclk2" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_fixed_factor g12a_vclk_div2 = {
+       .mult = 1,
+       .div = 2,
+       .hw.init = &(struct clk_init_data){
+               .name = "vclk_div2",
+               .ops = &clk_fixed_factor_ops,
+               .parent_names = (const char *[]){ "vclk_div2_en" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_fixed_factor g12a_vclk_div4 = {
+       .mult = 1,
+       .div = 4,
+       .hw.init = &(struct clk_init_data){
+               .name = "vclk_div4",
+               .ops = &clk_fixed_factor_ops,
+               .parent_names = (const char *[]){ "vclk_div4_en" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_fixed_factor g12a_vclk_div6 = {
+       .mult = 1,
+       .div = 6,
+       .hw.init = &(struct clk_init_data){
+               .name = "vclk_div6",
+               .ops = &clk_fixed_factor_ops,
+               .parent_names = (const char *[]){ "vclk_div6_en" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_fixed_factor g12a_vclk_div12 = {
+       .mult = 1,
+       .div = 12,
+       .hw.init = &(struct clk_init_data){
+               .name = "vclk_div12",
+               .ops = &clk_fixed_factor_ops,
+               .parent_names = (const char *[]){ "vclk_div12_en" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_fixed_factor g12a_vclk2_div2 = {
+       .mult = 1,
+       .div = 2,
+       .hw.init = &(struct clk_init_data){
+               .name = "vclk2_div2",
+               .ops = &clk_fixed_factor_ops,
+               .parent_names = (const char *[]){ "vclk2_div2_en" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_fixed_factor g12a_vclk2_div4 = {
+       .mult = 1,
+       .div = 4,
+       .hw.init = &(struct clk_init_data){
+               .name = "vclk2_div4",
+               .ops = &clk_fixed_factor_ops,
+               .parent_names = (const char *[]){ "vclk2_div4_en" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_fixed_factor g12a_vclk2_div6 = {
+       .mult = 1,
+       .div = 6,
+       .hw.init = &(struct clk_init_data){
+               .name = "vclk2_div6",
+               .ops = &clk_fixed_factor_ops,
+               .parent_names = (const char *[]){ "vclk2_div6_en" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_fixed_factor g12a_vclk2_div12 = {
+       .mult = 1,
+       .div = 12,
+       .hw.init = &(struct clk_init_data){
+               .name = "vclk2_div12",
+               .ops = &clk_fixed_factor_ops,
+               .parent_names = (const char *[]){ "vclk2_div12_en" },
+               .num_parents = 1,
+       },
+};
+
+static u32 mux_table_cts_sel[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 };
+static const char * const g12a_cts_parent_names[] = {
+       "vclk_div1", "vclk_div2", "vclk_div4", "vclk_div6",
+       "vclk_div12", "vclk2_div1", "vclk2_div2", "vclk2_div4",
+       "vclk2_div6", "vclk2_div12"
+};
+
+static struct clk_regmap g12a_cts_enci_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_VID_CLK_DIV,
+               .mask = 0xf,
+               .shift = 28,
+               .table = mux_table_cts_sel,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cts_enci_sel",
+               .ops = &clk_regmap_mux_ops,
+               .parent_names = g12a_cts_parent_names,
+               .num_parents = ARRAY_SIZE(g12a_cts_parent_names),
+               .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
+       },
+};
+
+static struct clk_regmap g12a_cts_encp_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_VID_CLK_DIV,
+               .mask = 0xf,
+               .shift = 20,
+               .table = mux_table_cts_sel,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cts_encp_sel",
+               .ops = &clk_regmap_mux_ops,
+               .parent_names = g12a_cts_parent_names,
+               .num_parents = ARRAY_SIZE(g12a_cts_parent_names),
+               .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
+       },
+};
+
+static struct clk_regmap g12a_cts_vdac_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_VIID_CLK_DIV,
+               .mask = 0xf,
+               .shift = 28,
+               .table = mux_table_cts_sel,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "cts_vdac_sel",
+               .ops = &clk_regmap_mux_ops,
+               .parent_names = g12a_cts_parent_names,
+               .num_parents = ARRAY_SIZE(g12a_cts_parent_names),
+               .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
+       },
+};
+
+/* TOFIX: add support for cts_tcon */
+static u32 mux_table_hdmi_tx_sel[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 };
+static const char * const g12a_cts_hdmi_tx_parent_names[] = {
+       "vclk_div1", "vclk_div2", "vclk_div4", "vclk_div6",
+       "vclk_div12", "vclk2_div1", "vclk2_div2", "vclk2_div4",
+       "vclk2_div6", "vclk2_div12"
+};
+
+static struct clk_regmap g12a_hdmi_tx_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_HDMI_CLK_CNTL,
+               .mask = 0xf,
+               .shift = 16,
+               .table = mux_table_hdmi_tx_sel,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "hdmi_tx_sel",
+               .ops = &clk_regmap_mux_ops,
+               .parent_names = g12a_cts_hdmi_tx_parent_names,
+               .num_parents = ARRAY_SIZE(g12a_cts_hdmi_tx_parent_names),
+               .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
+       },
+};
+
+static struct clk_regmap g12a_cts_enci = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VID_CLK_CNTL2,
+               .bit_idx = 0,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "cts_enci",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "cts_enci_sel" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_regmap g12a_cts_encp = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VID_CLK_CNTL2,
+               .bit_idx = 2,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "cts_encp",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "cts_encp_sel" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_regmap g12a_cts_vdac = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VID_CLK_CNTL2,
+               .bit_idx = 4,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "cts_vdac",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "cts_vdac_sel" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+static struct clk_regmap g12a_hdmi_tx = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_VID_CLK_CNTL2,
+               .bit_idx = 5,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "hdmi_tx",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "hdmi_tx_sel" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+/* HDMI Clocks */
+
+static const char * const g12a_hdmi_parent_names[] = {
+       IN_PREFIX "xtal", "fclk_div4", "fclk_div3", "fclk_div5"
+};
+
+static struct clk_regmap g12a_hdmi_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_HDMI_CLK_CNTL,
+               .mask = 0x3,
+               .shift = 9,
+               .flags = CLK_MUX_ROUND_CLOSEST,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "hdmi_sel",
+               .ops = &clk_regmap_mux_ops,
+               .parent_names = g12a_hdmi_parent_names,
+               .num_parents = ARRAY_SIZE(g12a_hdmi_parent_names),
+               .flags = CLK_SET_RATE_NO_REPARENT | CLK_GET_RATE_NOCACHE,
+       },
+};
+
+static struct clk_regmap g12a_hdmi_div = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_HDMI_CLK_CNTL,
+               .shift = 0,
+               .width = 7,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "hdmi_div",
+               .ops = &clk_regmap_divider_ops,
+               .parent_names = (const char *[]){ "hdmi_sel" },
+               .num_parents = 1,
+               .flags = CLK_GET_RATE_NOCACHE,
+       },
+};
+
+static struct clk_regmap g12a_hdmi = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_HDMI_CLK_CNTL,
+               .bit_idx = 8,
+       },
+       .hw.init = &(struct clk_init_data) {
+               .name = "hdmi",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "hdmi_div" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+       },
+};
+
+/*
+ * The MALI IP is clocked by two identical clocks (mali_0 and mali_1)
+ * muxed by a glitch-free switch.
+ */
+
+static const char * const g12a_mali_0_1_parent_names[] = {
+       IN_PREFIX "xtal", "gp0_pll", "hihi_pll", "fclk_div2p5",
+       "fclk_div3", "fclk_div4", "fclk_div5", "fclk_div7"
+};
+
+static struct clk_regmap g12a_mali_0_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_MALI_CLK_CNTL,
+               .mask = 0x7,
+               .shift = 9,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "mali_0_sel",
+               .ops = &clk_regmap_mux_ops,
+               .parent_names = g12a_mali_0_1_parent_names,
+               .num_parents = 8,
+               .flags = CLK_SET_RATE_NO_REPARENT,
+       },
+};
+
+static struct clk_regmap g12a_mali_0_div = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_MALI_CLK_CNTL,
+               .shift = 0,
+               .width = 7,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "mali_0_div",
+               .ops = &clk_regmap_divider_ops,
+               .parent_names = (const char *[]){ "mali_0_sel" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_NO_REPARENT,
+       },
+};
+
+static struct clk_regmap g12a_mali_0 = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_MALI_CLK_CNTL,
+               .bit_idx = 8,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "mali_0",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "mali_0_div" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap g12a_mali_1_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_MALI_CLK_CNTL,
+               .mask = 0x7,
+               .shift = 25,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "mali_1_sel",
+               .ops = &clk_regmap_mux_ops,
+               .parent_names = g12a_mali_0_1_parent_names,
+               .num_parents = 8,
+               .flags = CLK_SET_RATE_NO_REPARENT,
+       },
+};
+
+static struct clk_regmap g12a_mali_1_div = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_MALI_CLK_CNTL,
+               .shift = 16,
+               .width = 7,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "mali_1_div",
+               .ops = &clk_regmap_divider_ops,
+               .parent_names = (const char *[]){ "mali_1_sel" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_NO_REPARENT,
+       },
+};
+
+static struct clk_regmap g12a_mali_1 = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_MALI_CLK_CNTL,
+               .bit_idx = 24,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "mali_1",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "mali_1_div" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static const char * const g12a_mali_parent_names[] = {
+       "mali_0", "mali_1"
+};
+
+static struct clk_regmap g12a_mali = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_MALI_CLK_CNTL,
+               .mask = 1,
+               .shift = 31,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "mali",
+               .ops = &clk_regmap_mux_ops,
+               .parent_names = g12a_mali_parent_names,
+               .num_parents = 2,
+               .flags = CLK_SET_RATE_NO_REPARENT,
+       },
+};
+
+/* Everything Else (EE) domain gates */
+static MESON_GATE(g12a_ddr,                    HHI_GCLK_MPEG0, 0);
+static MESON_GATE(g12a_dos,                    HHI_GCLK_MPEG0, 1);
+static MESON_GATE(g12a_audio_locker,           HHI_GCLK_MPEG0, 2);
+static MESON_GATE(g12a_mipi_dsi_host,          HHI_GCLK_MPEG0, 3);
+static MESON_GATE(g12a_eth_phy,                        HHI_GCLK_MPEG0, 4);
+static MESON_GATE(g12a_isa,                    HHI_GCLK_MPEG0, 5);
+static MESON_GATE(g12a_pl301,                  HHI_GCLK_MPEG0, 6);
+static MESON_GATE(g12a_periphs,                        HHI_GCLK_MPEG0, 7);
+static MESON_GATE(g12a_spicc_0,                        HHI_GCLK_MPEG0, 8);
+static MESON_GATE(g12a_i2c,                    HHI_GCLK_MPEG0, 9);
+static MESON_GATE(g12a_sana,                   HHI_GCLK_MPEG0, 10);
+static MESON_GATE(g12a_sd,                     HHI_GCLK_MPEG0, 11);
+static MESON_GATE(g12a_rng0,                   HHI_GCLK_MPEG0, 12);
+static MESON_GATE(g12a_uart0,                  HHI_GCLK_MPEG0, 13);
+static MESON_GATE(g12a_spicc_1,                        HHI_GCLK_MPEG0, 14);
+static MESON_GATE(g12a_hiu_reg,                        HHI_GCLK_MPEG0, 19);
+static MESON_GATE(g12a_mipi_dsi_phy,           HHI_GCLK_MPEG0, 20);
+static MESON_GATE(g12a_assist_misc,            HHI_GCLK_MPEG0, 23);
+static MESON_GATE(g12a_emmc_a,                 HHI_GCLK_MPEG0, 4);
+static MESON_GATE(g12a_emmc_b,                 HHI_GCLK_MPEG0, 25);
+static MESON_GATE(g12a_emmc_c,                 HHI_GCLK_MPEG0, 26);
+static MESON_GATE(g12a_audio_codec,            HHI_GCLK_MPEG0, 28);
+
+static MESON_GATE(g12a_audio,                  HHI_GCLK_MPEG1, 0);
+static MESON_GATE(g12a_eth_core,               HHI_GCLK_MPEG1, 3);
+static MESON_GATE(g12a_demux,                  HHI_GCLK_MPEG1, 4);
+static MESON_GATE(g12a_audio_ififo,            HHI_GCLK_MPEG1, 11);
+static MESON_GATE(g12a_adc,                    HHI_GCLK_MPEG1, 13);
+static MESON_GATE(g12a_uart1,                  HHI_GCLK_MPEG1, 16);
+static MESON_GATE(g12a_g2d,                    HHI_GCLK_MPEG1, 20);
+static MESON_GATE(g12a_reset,                  HHI_GCLK_MPEG1, 23);
+static MESON_GATE(g12a_pcie_comb,              HHI_GCLK_MPEG1, 24);
+static MESON_GATE(g12a_parser,                 HHI_GCLK_MPEG1, 25);
+static MESON_GATE(g12a_usb_general,            HHI_GCLK_MPEG1, 26);
+static MESON_GATE(g12a_pcie_phy,               HHI_GCLK_MPEG1, 27);
+static MESON_GATE(g12a_ahb_arb0,               HHI_GCLK_MPEG1, 29);
+
+static MESON_GATE(g12a_ahb_data_bus,           HHI_GCLK_MPEG2, 1);
+static MESON_GATE(g12a_ahb_ctrl_bus,           HHI_GCLK_MPEG2, 2);
+static MESON_GATE(g12a_htx_hdcp22,             HHI_GCLK_MPEG2, 3);
+static MESON_GATE(g12a_htx_pclk,               HHI_GCLK_MPEG2, 4);
+static MESON_GATE(g12a_bt656,                  HHI_GCLK_MPEG2, 6);
+static MESON_GATE(g12a_usb1_to_ddr,            HHI_GCLK_MPEG2, 8);
+static MESON_GATE(g12a_mmc_pclk,               HHI_GCLK_MPEG2, 11);
+static MESON_GATE(g12a_uart2,                  HHI_GCLK_MPEG2, 15);
+static MESON_GATE(g12a_vpu_intr,               HHI_GCLK_MPEG2, 25);
+static MESON_GATE(g12a_gic,                    HHI_GCLK_MPEG2, 30);
+
+static MESON_GATE(g12a_vclk2_venci0,           HHI_GCLK_OTHER, 1);
+static MESON_GATE(g12a_vclk2_venci1,           HHI_GCLK_OTHER, 2);
+static MESON_GATE(g12a_vclk2_vencp0,           HHI_GCLK_OTHER, 3);
+static MESON_GATE(g12a_vclk2_vencp1,           HHI_GCLK_OTHER, 4);
+static MESON_GATE(g12a_vclk2_venct0,           HHI_GCLK_OTHER, 5);
+static MESON_GATE(g12a_vclk2_venct1,           HHI_GCLK_OTHER, 6);
+static MESON_GATE(g12a_vclk2_other,            HHI_GCLK_OTHER, 7);
+static MESON_GATE(g12a_vclk2_enci,             HHI_GCLK_OTHER, 8);
+static MESON_GATE(g12a_vclk2_encp,             HHI_GCLK_OTHER, 9);
+static MESON_GATE(g12a_dac_clk,                        HHI_GCLK_OTHER, 10);
+static MESON_GATE(g12a_aoclk_gate,             HHI_GCLK_OTHER, 14);
+static MESON_GATE(g12a_iec958_gate,            HHI_GCLK_OTHER, 16);
+static MESON_GATE(g12a_enc480p,                        HHI_GCLK_OTHER, 20);
+static MESON_GATE(g12a_rng1,                   HHI_GCLK_OTHER, 21);
+static MESON_GATE(g12a_vclk2_enct,             HHI_GCLK_OTHER, 22);
+static MESON_GATE(g12a_vclk2_encl,             HHI_GCLK_OTHER, 23);
+static MESON_GATE(g12a_vclk2_venclmmc,         HHI_GCLK_OTHER, 24);
+static MESON_GATE(g12a_vclk2_vencl,            HHI_GCLK_OTHER, 25);
+static MESON_GATE(g12a_vclk2_other1,           HHI_GCLK_OTHER, 26);
+
+static MESON_GATE_RO(g12a_dma,                 HHI_GCLK_OTHER2, 0);
+static MESON_GATE_RO(g12a_efuse,               HHI_GCLK_OTHER2, 1);
+static MESON_GATE_RO(g12a_rom_boot,            HHI_GCLK_OTHER2, 2);
+static MESON_GATE_RO(g12a_reset_sec,           HHI_GCLK_OTHER2, 3);
+static MESON_GATE_RO(g12a_sec_ahb_apb3,                HHI_GCLK_OTHER2, 4);
+
+/* Array of all clocks provided by this provider */
+static struct clk_hw_onecell_data g12a_hw_onecell_data = {
+       .hws = {
+               [CLKID_SYS_PLL]                 = &g12a_sys_pll.hw,
+               [CLKID_FIXED_PLL]               = &g12a_fixed_pll.hw,
+               [CLKID_FCLK_DIV2]               = &g12a_fclk_div2.hw,
+               [CLKID_FCLK_DIV3]               = &g12a_fclk_div3.hw,
+               [CLKID_FCLK_DIV4]               = &g12a_fclk_div4.hw,
+               [CLKID_FCLK_DIV5]               = &g12a_fclk_div5.hw,
+               [CLKID_FCLK_DIV7]               = &g12a_fclk_div7.hw,
+               [CLKID_FCLK_DIV2P5]             = &g12a_fclk_div2p5.hw,
+               [CLKID_GP0_PLL]                 = &g12a_gp0_pll.hw,
+               [CLKID_MPEG_SEL]                = &g12a_mpeg_clk_sel.hw,
+               [CLKID_MPEG_DIV]                = &g12a_mpeg_clk_div.hw,
+               [CLKID_CLK81]                   = &g12a_clk81.hw,
+               [CLKID_MPLL0]                   = &g12a_mpll0.hw,
+               [CLKID_MPLL1]                   = &g12a_mpll1.hw,
+               [CLKID_MPLL2]                   = &g12a_mpll2.hw,
+               [CLKID_MPLL3]                   = &g12a_mpll3.hw,
+               [CLKID_DDR]                     = &g12a_ddr.hw,
+               [CLKID_DOS]                     = &g12a_dos.hw,
+               [CLKID_AUDIO_LOCKER]            = &g12a_audio_locker.hw,
+               [CLKID_MIPI_DSI_HOST]           = &g12a_mipi_dsi_host.hw,
+               [CLKID_ETH_PHY]                 = &g12a_eth_phy.hw,
+               [CLKID_ISA]                     = &g12a_isa.hw,
+               [CLKID_PL301]                   = &g12a_pl301.hw,
+               [CLKID_PERIPHS]                 = &g12a_periphs.hw,
+               [CLKID_SPICC0]                  = &g12a_spicc_0.hw,
+               [CLKID_I2C]                     = &g12a_i2c.hw,
+               [CLKID_SANA]                    = &g12a_sana.hw,
+               [CLKID_SD]                      = &g12a_sd.hw,
+               [CLKID_RNG0]                    = &g12a_rng0.hw,
+               [CLKID_UART0]                   = &g12a_uart0.hw,
+               [CLKID_SPICC1]                  = &g12a_spicc_1.hw,
+               [CLKID_HIU_IFACE]               = &g12a_hiu_reg.hw,
+               [CLKID_MIPI_DSI_PHY]            = &g12a_mipi_dsi_phy.hw,
+               [CLKID_ASSIST_MISC]             = &g12a_assist_misc.hw,
+               [CLKID_SD_EMMC_A]               = &g12a_emmc_a.hw,
+               [CLKID_SD_EMMC_B]               = &g12a_emmc_b.hw,
+               [CLKID_SD_EMMC_C]               = &g12a_emmc_c.hw,
+               [CLKID_AUDIO_CODEC]             = &g12a_audio_codec.hw,
+               [CLKID_AUDIO]                   = &g12a_audio.hw,
+               [CLKID_ETH]                     = &g12a_eth_core.hw,
+               [CLKID_DEMUX]                   = &g12a_demux.hw,
+               [CLKID_AUDIO_IFIFO]             = &g12a_audio_ififo.hw,
+               [CLKID_ADC]                     = &g12a_adc.hw,
+               [CLKID_UART1]                   = &g12a_uart1.hw,
+               [CLKID_G2D]                     = &g12a_g2d.hw,
+               [CLKID_RESET]                   = &g12a_reset.hw,
+               [CLKID_PCIE_COMB]               = &g12a_pcie_comb.hw,
+               [CLKID_PARSER]                  = &g12a_parser.hw,
+               [CLKID_USB]                     = &g12a_usb_general.hw,
+               [CLKID_PCIE_PHY]                = &g12a_pcie_phy.hw,
+               [CLKID_AHB_ARB0]                = &g12a_ahb_arb0.hw,
+               [CLKID_AHB_DATA_BUS]            = &g12a_ahb_data_bus.hw,
+               [CLKID_AHB_CTRL_BUS]            = &g12a_ahb_ctrl_bus.hw,
+               [CLKID_HTX_HDCP22]              = &g12a_htx_hdcp22.hw,
+               [CLKID_HTX_PCLK]                = &g12a_htx_pclk.hw,
+               [CLKID_BT656]                   = &g12a_bt656.hw,
+               [CLKID_USB1_DDR_BRIDGE]         = &g12a_usb1_to_ddr.hw,
+               [CLKID_MMC_PCLK]                = &g12a_mmc_pclk.hw,
+               [CLKID_UART2]                   = &g12a_uart2.hw,
+               [CLKID_VPU_INTR]                = &g12a_vpu_intr.hw,
+               [CLKID_GIC]                     = &g12a_gic.hw,
+               [CLKID_SD_EMMC_A_CLK0_SEL]      = &g12a_sd_emmc_a_clk0_sel.hw,
+               [CLKID_SD_EMMC_A_CLK0_DIV]      = &g12a_sd_emmc_a_clk0_div.hw,
+               [CLKID_SD_EMMC_A_CLK0]          = &g12a_sd_emmc_a_clk0.hw,
+               [CLKID_SD_EMMC_B_CLK0_SEL]      = &g12a_sd_emmc_b_clk0_sel.hw,
+               [CLKID_SD_EMMC_B_CLK0_DIV]      = &g12a_sd_emmc_b_clk0_div.hw,
+               [CLKID_SD_EMMC_B_CLK0]          = &g12a_sd_emmc_b_clk0.hw,
+               [CLKID_SD_EMMC_C_CLK0_SEL]      = &g12a_sd_emmc_c_clk0_sel.hw,
+               [CLKID_SD_EMMC_C_CLK0_DIV]      = &g12a_sd_emmc_c_clk0_div.hw,
+               [CLKID_SD_EMMC_C_CLK0]          = &g12a_sd_emmc_c_clk0.hw,
+               [CLKID_MPLL0_DIV]               = &g12a_mpll0_div.hw,
+               [CLKID_MPLL1_DIV]               = &g12a_mpll1_div.hw,
+               [CLKID_MPLL2_DIV]               = &g12a_mpll2_div.hw,
+               [CLKID_MPLL3_DIV]               = &g12a_mpll3_div.hw,
+               [CLKID_FCLK_DIV2_DIV]           = &g12a_fclk_div2_div.hw,
+               [CLKID_FCLK_DIV3_DIV]           = &g12a_fclk_div3_div.hw,
+               [CLKID_FCLK_DIV4_DIV]           = &g12a_fclk_div4_div.hw,
+               [CLKID_FCLK_DIV5_DIV]           = &g12a_fclk_div5_div.hw,
+               [CLKID_FCLK_DIV7_DIV]           = &g12a_fclk_div7_div.hw,
+               [CLKID_FCLK_DIV2P5_DIV]         = &g12a_fclk_div2p5_div.hw,
+               [CLKID_HIFI_PLL]                = &g12a_hifi_pll.hw,
+               [CLKID_VCLK2_VENCI0]            = &g12a_vclk2_venci0.hw,
+               [CLKID_VCLK2_VENCI1]            = &g12a_vclk2_venci1.hw,
+               [CLKID_VCLK2_VENCP0]            = &g12a_vclk2_vencp0.hw,
+               [CLKID_VCLK2_VENCP1]            = &g12a_vclk2_vencp1.hw,
+               [CLKID_VCLK2_VENCT0]            = &g12a_vclk2_venct0.hw,
+               [CLKID_VCLK2_VENCT1]            = &g12a_vclk2_venct1.hw,
+               [CLKID_VCLK2_OTHER]             = &g12a_vclk2_other.hw,
+               [CLKID_VCLK2_ENCI]              = &g12a_vclk2_enci.hw,
+               [CLKID_VCLK2_ENCP]              = &g12a_vclk2_encp.hw,
+               [CLKID_DAC_CLK]                 = &g12a_dac_clk.hw,
+               [CLKID_AOCLK]                   = &g12a_aoclk_gate.hw,
+               [CLKID_IEC958]                  = &g12a_iec958_gate.hw,
+               [CLKID_ENC480P]                 = &g12a_enc480p.hw,
+               [CLKID_RNG1]                    = &g12a_rng1.hw,
+               [CLKID_VCLK2_ENCT]              = &g12a_vclk2_enct.hw,
+               [CLKID_VCLK2_ENCL]              = &g12a_vclk2_encl.hw,
+               [CLKID_VCLK2_VENCLMMC]          = &g12a_vclk2_venclmmc.hw,
+               [CLKID_VCLK2_VENCL]             = &g12a_vclk2_vencl.hw,
+               [CLKID_VCLK2_OTHER1]            = &g12a_vclk2_other1.hw,
+               [CLKID_FIXED_PLL_DCO]           = &g12a_fixed_pll_dco.hw,
+               [CLKID_SYS_PLL_DCO]             = &g12a_sys_pll_dco.hw,
+               [CLKID_GP0_PLL_DCO]             = &g12a_gp0_pll_dco.hw,
+               [CLKID_HIFI_PLL_DCO]            = &g12a_hifi_pll_dco.hw,
+               [CLKID_DMA]                     = &g12a_dma.hw,
+               [CLKID_EFUSE]                   = &g12a_efuse.hw,
+               [CLKID_ROM_BOOT]                = &g12a_rom_boot.hw,
+               [CLKID_RESET_SEC]               = &g12a_reset_sec.hw,
+               [CLKID_SEC_AHB_APB3]            = &g12a_sec_ahb_apb3.hw,
+               [CLKID_MPLL_PREDIV]             = &g12a_mpll_prediv.hw,
+               [CLKID_VPU_0_SEL]               = &g12a_vpu_0_sel.hw,
+               [CLKID_VPU_0_DIV]               = &g12a_vpu_0_div.hw,
+               [CLKID_VPU_0]                   = &g12a_vpu_0.hw,
+               [CLKID_VPU_1_SEL]               = &g12a_vpu_1_sel.hw,
+               [CLKID_VPU_1_DIV]               = &g12a_vpu_1_div.hw,
+               [CLKID_VPU_1]                   = &g12a_vpu_1.hw,
+               [CLKID_VPU]                     = &g12a_vpu.hw,
+               [CLKID_VAPB_0_SEL]              = &g12a_vapb_0_sel.hw,
+               [CLKID_VAPB_0_DIV]              = &g12a_vapb_0_div.hw,
+               [CLKID_VAPB_0]                  = &g12a_vapb_0.hw,
+               [CLKID_VAPB_1_SEL]              = &g12a_vapb_1_sel.hw,
+               [CLKID_VAPB_1_DIV]              = &g12a_vapb_1_div.hw,
+               [CLKID_VAPB_1]                  = &g12a_vapb_1.hw,
+               [CLKID_VAPB_SEL]                = &g12a_vapb_sel.hw,
+               [CLKID_VAPB]                    = &g12a_vapb.hw,
+               [CLKID_HDMI_PLL_DCO]            = &g12a_hdmi_pll_dco.hw,
+               [CLKID_HDMI_PLL_OD]             = &g12a_hdmi_pll_od.hw,
+               [CLKID_HDMI_PLL_OD2]            = &g12a_hdmi_pll_od2.hw,
+               [CLKID_HDMI_PLL]                = &g12a_hdmi_pll.hw,
+               [CLKID_VID_PLL]                 = &g12a_vid_pll_div.hw,
+               [CLKID_VID_PLL_SEL]             = &g12a_vid_pll_sel.hw,
+               [CLKID_VID_PLL_DIV]             = &g12a_vid_pll.hw,
+               [CLKID_VCLK_SEL]                = &g12a_vclk_sel.hw,
+               [CLKID_VCLK2_SEL]               = &g12a_vclk2_sel.hw,
+               [CLKID_VCLK_INPUT]              = &g12a_vclk_input.hw,
+               [CLKID_VCLK2_INPUT]             = &g12a_vclk2_input.hw,
+               [CLKID_VCLK_DIV]                = &g12a_vclk_div.hw,
+               [CLKID_VCLK2_DIV]               = &g12a_vclk2_div.hw,
+               [CLKID_VCLK]                    = &g12a_vclk.hw,
+               [CLKID_VCLK2]                   = &g12a_vclk2.hw,
+               [CLKID_VCLK_DIV1]               = &g12a_vclk_div1.hw,
+               [CLKID_VCLK_DIV2_EN]            = &g12a_vclk_div2_en.hw,
+               [CLKID_VCLK_DIV4_EN]            = &g12a_vclk_div4_en.hw,
+               [CLKID_VCLK_DIV6_EN]            = &g12a_vclk_div6_en.hw,
+               [CLKID_VCLK_DIV12_EN]           = &g12a_vclk_div12_en.hw,
+               [CLKID_VCLK2_DIV1]              = &g12a_vclk2_div1.hw,
+               [CLKID_VCLK2_DIV2_EN]           = &g12a_vclk2_div2_en.hw,
+               [CLKID_VCLK2_DIV4_EN]           = &g12a_vclk2_div4_en.hw,
+               [CLKID_VCLK2_DIV6_EN]           = &g12a_vclk2_div6_en.hw,
+               [CLKID_VCLK2_DIV12_EN]          = &g12a_vclk2_div12_en.hw,
+               [CLKID_VCLK_DIV2]               = &g12a_vclk_div2.hw,
+               [CLKID_VCLK_DIV4]               = &g12a_vclk_div4.hw,
+               [CLKID_VCLK_DIV6]               = &g12a_vclk_div6.hw,
+               [CLKID_VCLK_DIV12]              = &g12a_vclk_div12.hw,
+               [CLKID_VCLK2_DIV2]              = &g12a_vclk2_div2.hw,
+               [CLKID_VCLK2_DIV4]              = &g12a_vclk2_div4.hw,
+               [CLKID_VCLK2_DIV6]              = &g12a_vclk2_div6.hw,
+               [CLKID_VCLK2_DIV12]             = &g12a_vclk2_div12.hw,
+               [CLKID_CTS_ENCI_SEL]            = &g12a_cts_enci_sel.hw,
+               [CLKID_CTS_ENCP_SEL]            = &g12a_cts_encp_sel.hw,
+               [CLKID_CTS_VDAC_SEL]            = &g12a_cts_vdac_sel.hw,
+               [CLKID_HDMI_TX_SEL]             = &g12a_hdmi_tx_sel.hw,
+               [CLKID_CTS_ENCI]                = &g12a_cts_enci.hw,
+               [CLKID_CTS_ENCP]                = &g12a_cts_encp.hw,
+               [CLKID_CTS_VDAC]                = &g12a_cts_vdac.hw,
+               [CLKID_HDMI_TX]                 = &g12a_hdmi_tx.hw,
+               [CLKID_HDMI_SEL]                = &g12a_hdmi_sel.hw,
+               [CLKID_HDMI_DIV]                = &g12a_hdmi_div.hw,
+               [CLKID_HDMI]                    = &g12a_hdmi.hw,
+               [CLKID_MALI_0_SEL]              = &g12a_mali_0_sel.hw,
+               [CLKID_MALI_0_DIV]              = &g12a_mali_0_div.hw,
+               [CLKID_MALI_0]                  = &g12a_mali_0.hw,
+               [CLKID_MALI_1_SEL]              = &g12a_mali_1_sel.hw,
+               [CLKID_MALI_1_DIV]              = &g12a_mali_1_div.hw,
+               [CLKID_MALI_1]                  = &g12a_mali_1.hw,
+               [CLKID_MALI]                    = &g12a_mali.hw,
+               [CLKID_MPLL_5OM_DIV]            = &g12a_mpll_50m_div.hw,
+               [CLKID_MPLL_5OM]                = &g12a_mpll_50m.hw,
+               [NR_CLKS]                       = NULL,
+       },
+       .num = NR_CLKS,
+};
+
+/* Convenience table to populate regmap in .probe */
+static struct clk_regmap *const g12a_clk_regmaps[] = {
+       &g12a_clk81,
+       &g12a_dos,
+       &g12a_ddr,
+       &g12a_audio_locker,
+       &g12a_mipi_dsi_host,
+       &g12a_eth_phy,
+       &g12a_isa,
+       &g12a_pl301,
+       &g12a_periphs,
+       &g12a_spicc_0,
+       &g12a_i2c,
+       &g12a_sana,
+       &g12a_sd,
+       &g12a_rng0,
+       &g12a_uart0,
+       &g12a_spicc_1,
+       &g12a_hiu_reg,
+       &g12a_mipi_dsi_phy,
+       &g12a_assist_misc,
+       &g12a_emmc_a,
+       &g12a_emmc_b,
+       &g12a_emmc_c,
+       &g12a_audio_codec,
+       &g12a_audio,
+       &g12a_eth_core,
+       &g12a_demux,
+       &g12a_audio_ififo,
+       &g12a_adc,
+       &g12a_uart1,
+       &g12a_g2d,
+       &g12a_reset,
+       &g12a_pcie_comb,
+       &g12a_parser,
+       &g12a_usb_general,
+       &g12a_pcie_phy,
+       &g12a_ahb_arb0,
+       &g12a_ahb_data_bus,
+       &g12a_ahb_ctrl_bus,
+       &g12a_htx_hdcp22,
+       &g12a_htx_pclk,
+       &g12a_bt656,
+       &g12a_usb1_to_ddr,
+       &g12a_mmc_pclk,
+       &g12a_vpu_intr,
+       &g12a_gic,
+       &g12a_sd_emmc_a_clk0,
+       &g12a_sd_emmc_b_clk0,
+       &g12a_sd_emmc_c_clk0,
+       &g12a_mpeg_clk_div,
+       &g12a_sd_emmc_a_clk0_div,
+       &g12a_sd_emmc_b_clk0_div,
+       &g12a_sd_emmc_c_clk0_div,
+       &g12a_mpeg_clk_sel,
+       &g12a_sd_emmc_a_clk0_sel,
+       &g12a_sd_emmc_b_clk0_sel,
+       &g12a_sd_emmc_c_clk0_sel,
+       &g12a_mpll0,
+       &g12a_mpll1,
+       &g12a_mpll2,
+       &g12a_mpll3,
+       &g12a_mpll0_div,
+       &g12a_mpll1_div,
+       &g12a_mpll2_div,
+       &g12a_mpll3_div,
+       &g12a_fixed_pll,
+       &g12a_sys_pll,
+       &g12a_gp0_pll,
+       &g12a_hifi_pll,
+       &g12a_vclk2_venci0,
+       &g12a_vclk2_venci1,
+       &g12a_vclk2_vencp0,
+       &g12a_vclk2_vencp1,
+       &g12a_vclk2_venct0,
+       &g12a_vclk2_venct1,
+       &g12a_vclk2_other,
+       &g12a_vclk2_enci,
+       &g12a_vclk2_encp,
+       &g12a_dac_clk,
+       &g12a_aoclk_gate,
+       &g12a_iec958_gate,
+       &g12a_enc480p,
+       &g12a_rng1,
+       &g12a_vclk2_enct,
+       &g12a_vclk2_encl,
+       &g12a_vclk2_venclmmc,
+       &g12a_vclk2_vencl,
+       &g12a_vclk2_other1,
+       &g12a_fixed_pll_dco,
+       &g12a_sys_pll_dco,
+       &g12a_gp0_pll_dco,
+       &g12a_hifi_pll_dco,
+       &g12a_fclk_div2,
+       &g12a_fclk_div3,
+       &g12a_fclk_div4,
+       &g12a_fclk_div5,
+       &g12a_fclk_div7,
+       &g12a_fclk_div2p5,
+       &g12a_dma,
+       &g12a_efuse,
+       &g12a_rom_boot,
+       &g12a_reset_sec,
+       &g12a_sec_ahb_apb3,
+       &g12a_vpu_0_sel,
+       &g12a_vpu_0_div,
+       &g12a_vpu_0,
+       &g12a_vpu_1_sel,
+       &g12a_vpu_1_div,
+       &g12a_vpu_1,
+       &g12a_vpu,
+       &g12a_vapb_0_sel,
+       &g12a_vapb_0_div,
+       &g12a_vapb_0,
+       &g12a_vapb_1_sel,
+       &g12a_vapb_1_div,
+       &g12a_vapb_1,
+       &g12a_vapb_sel,
+       &g12a_vapb,
+       &g12a_hdmi_pll_dco,
+       &g12a_hdmi_pll_od,
+       &g12a_hdmi_pll_od2,
+       &g12a_hdmi_pll,
+       &g12a_vid_pll_div,
+       &g12a_vid_pll_sel,
+       &g12a_vid_pll,
+       &g12a_vclk_sel,
+       &g12a_vclk2_sel,
+       &g12a_vclk_input,
+       &g12a_vclk2_input,
+       &g12a_vclk_div,
+       &g12a_vclk2_div,
+       &g12a_vclk,
+       &g12a_vclk2,
+       &g12a_vclk_div1,
+       &g12a_vclk_div2_en,
+       &g12a_vclk_div4_en,
+       &g12a_vclk_div6_en,
+       &g12a_vclk_div12_en,
+       &g12a_vclk2_div1,
+       &g12a_vclk2_div2_en,
+       &g12a_vclk2_div4_en,
+       &g12a_vclk2_div6_en,
+       &g12a_vclk2_div12_en,
+       &g12a_cts_enci_sel,
+       &g12a_cts_encp_sel,
+       &g12a_cts_vdac_sel,
+       &g12a_hdmi_tx_sel,
+       &g12a_cts_enci,
+       &g12a_cts_encp,
+       &g12a_cts_vdac,
+       &g12a_hdmi_tx,
+       &g12a_hdmi_sel,
+       &g12a_hdmi_div,
+       &g12a_hdmi,
+       &g12a_mali_0_sel,
+       &g12a_mali_0_div,
+       &g12a_mali_0,
+       &g12a_mali_1_sel,
+       &g12a_mali_1_div,
+       &g12a_mali_1,
+       &g12a_mali,
+       &g12a_mpll_50m,
+};
+
+static const struct meson_eeclkc_data g12a_clkc_data = {
+       .regmap_clks = g12a_clk_regmaps,
+       .regmap_clk_num = ARRAY_SIZE(g12a_clk_regmaps),
+       .hw_onecell_data = &g12a_hw_onecell_data
+};
+
+static const struct of_device_id clkc_match_table[] = {
+       { .compatible = "amlogic,g12a-clkc", .data = &g12a_clkc_data },
+       {}
+};
+
+static struct platform_driver g12a_driver = {
+       .probe          = meson_eeclkc_probe,
+       .driver         = {
+               .name   = "g12a-clkc",
+               .of_match_table = clkc_match_table,
+       },
+};
+
+builtin_platform_driver(g12a_driver);
diff --git a/drivers/clk/meson/g12a.h b/drivers/clk/meson/g12a.h
new file mode 100644 (file)
index 0000000..f399dfe
--- /dev/null
@@ -0,0 +1,175 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Copyright (c) 2016 Amlogic, Inc.
+ * Author: Michael Turquette <mturquette@baylibre.com>
+ *
+ * Copyright (c) 2018 Amlogic, inc.
+ * Author: Qiufang Dai <qiufang.dai@amlogic.com>
+ * Author: Jian Hu <jian.hu@amlogic.com>
+ *
+ */
+#ifndef __G12A_H
+#define __G12A_H
+
+/*
+ * Clock controller register offsets
+ *
+ * Register offsets from the data sheet must be multiplied by 4 before
+ * adding them to the base address to get the right value.
+ */
+#define HHI_MIPI_CNTL0                 0x000
+#define HHI_MIPI_CNTL1                 0x004
+#define HHI_MIPI_CNTL2                 0x008
+#define HHI_MIPI_STS                   0x00C
+#define HHI_GP0_PLL_CNTL0              0x040
+#define HHI_GP0_PLL_CNTL1              0x044
+#define HHI_GP0_PLL_CNTL2              0x048
+#define HHI_GP0_PLL_CNTL3              0x04C
+#define HHI_GP0_PLL_CNTL4              0x050
+#define HHI_GP0_PLL_CNTL5              0x054
+#define HHI_GP0_PLL_CNTL6              0x058
+#define HHI_GP0_PLL_STS                        0x05C
+#define HHI_PCIE_PLL_CNTL0             0x098
+#define HHI_PCIE_PLL_CNTL1             0x09C
+#define HHI_PCIE_PLL_CNTL2             0x0A0
+#define HHI_PCIE_PLL_CNTL3             0x0A4
+#define HHI_PCIE_PLL_CNTL4             0x0A8
+#define HHI_PCIE_PLL_CNTL5             0x0AC
+#define HHI_PCIE_PLL_STS               0x0B8
+#define HHI_HIFI_PLL_CNTL0             0x0D8
+#define HHI_HIFI_PLL_CNTL1             0x0DC
+#define HHI_HIFI_PLL_CNTL2             0x0E0
+#define HHI_HIFI_PLL_CNTL3             0x0E4
+#define HHI_HIFI_PLL_CNTL4             0x0E8
+#define HHI_HIFI_PLL_CNTL5             0x0EC
+#define HHI_HIFI_PLL_CNTL6             0x0F0
+#define HHI_VIID_CLK_DIV               0x128
+#define HHI_VIID_CLK_CNTL              0x12C
+#define HHI_GCLK_MPEG0                 0x140
+#define HHI_GCLK_MPEG1                 0x144
+#define HHI_GCLK_MPEG2                 0x148
+#define HHI_GCLK_OTHER                 0x150
+#define HHI_GCLK_OTHER2                        0x154
+#define HHI_VID_CLK_DIV                        0x164
+#define HHI_MPEG_CLK_CNTL              0x174
+#define HHI_AUD_CLK_CNTL               0x178
+#define HHI_VID_CLK_CNTL               0x17c
+#define HHI_TS_CLK_CNTL                        0x190
+#define HHI_VID_CLK_CNTL2              0x194
+#define HHI_SYS_CPU_CLK_CNTL0          0x19c
+#define HHI_VID_PLL_CLK_DIV            0x1A0
+#define HHI_MALI_CLK_CNTL              0x1b0
+#define HHI_VPU_CLKC_CNTL              0x1b4
+#define HHI_VPU_CLK_CNTL               0x1bC
+#define HHI_HDMI_CLK_CNTL              0x1CC
+#define HHI_VDEC_CLK_CNTL              0x1E0
+#define HHI_VDEC2_CLK_CNTL             0x1E4
+#define HHI_VDEC3_CLK_CNTL             0x1E8
+#define HHI_VDEC4_CLK_CNTL             0x1EC
+#define HHI_HDCP22_CLK_CNTL            0x1F0
+#define HHI_VAPBCLK_CNTL               0x1F4
+#define HHI_VPU_CLKB_CNTL              0x20C
+#define HHI_GEN_CLK_CNTL               0x228
+#define HHI_VDIN_MEAS_CLK_CNTL         0x250
+#define HHI_MIPIDSI_PHY_CLK_CNTL       0x254
+#define HHI_NAND_CLK_CNTL              0x25C
+#define HHI_SD_EMMC_CLK_CNTL           0x264
+#define HHI_MPLL_CNTL0                 0x278
+#define HHI_MPLL_CNTL1                 0x27C
+#define HHI_MPLL_CNTL2                 0x280
+#define HHI_MPLL_CNTL3                 0x284
+#define HHI_MPLL_CNTL4                 0x288
+#define HHI_MPLL_CNTL5                 0x28c
+#define HHI_MPLL_CNTL6                 0x290
+#define HHI_MPLL_CNTL7                 0x294
+#define HHI_MPLL_CNTL8                 0x298
+#define HHI_FIX_PLL_CNTL0              0x2A0
+#define HHI_FIX_PLL_CNTL1              0x2A4
+#define HHI_FIX_PLL_CNTL3              0x2AC
+#define HHI_SYS_PLL_CNTL0              0x2f4
+#define HHI_SYS_PLL_CNTL1              0x2f8
+#define HHI_SYS_PLL_CNTL2              0x2fc
+#define HHI_SYS_PLL_CNTL3              0x300
+#define HHI_SYS_PLL_CNTL4              0x304
+#define HHI_SYS_PLL_CNTL5              0x308
+#define HHI_SYS_PLL_CNTL6              0x30c
+#define HHI_HDMI_PLL_CNTL0             0x320
+#define HHI_HDMI_PLL_CNTL1             0x324
+#define HHI_HDMI_PLL_CNTL2             0x328
+#define HHI_HDMI_PLL_CNTL3             0x32c
+#define HHI_HDMI_PLL_CNTL4             0x330
+#define HHI_HDMI_PLL_CNTL5             0x334
+#define HHI_HDMI_PLL_CNTL6             0x338
+#define HHI_SPICC_CLK_CNTL             0x3dc
+
+/*
+ * CLKID index values
+ *
+ * These indices are entirely contrived and do not map onto the hardware.
+ * It has now been decided to expose everything by default in the DT header:
+ * include/dt-bindings/clock/g12a-clkc.h. Only the clocks ids we don't want
+ * to expose, such as the internal muxes and dividers of composite clocks,
+ * will remain defined here.
+ */
+#define CLKID_MPEG_SEL                         8
+#define CLKID_MPEG_DIV                         9
+#define CLKID_SD_EMMC_A_CLK0_SEL               63
+#define CLKID_SD_EMMC_A_CLK0_DIV               64
+#define CLKID_SD_EMMC_B_CLK0_SEL               65
+#define CLKID_SD_EMMC_B_CLK0_DIV               66
+#define CLKID_SD_EMMC_C_CLK0_SEL               67
+#define CLKID_SD_EMMC_C_CLK0_DIV               68
+#define CLKID_MPLL0_DIV                                69
+#define CLKID_MPLL1_DIV                                70
+#define CLKID_MPLL2_DIV                                71
+#define CLKID_MPLL3_DIV                                72
+#define CLKID_MPLL_PREDIV                      73
+#define CLKID_FCLK_DIV2_DIV                    75
+#define CLKID_FCLK_DIV3_DIV                    76
+#define CLKID_FCLK_DIV4_DIV                    77
+#define CLKID_FCLK_DIV5_DIV                    78
+#define CLKID_FCLK_DIV7_DIV                    79
+#define CLKID_FCLK_DIV2P5_DIV                  100
+#define CLKID_FIXED_PLL_DCO                    101
+#define CLKID_SYS_PLL_DCO                      102
+#define CLKID_GP0_PLL_DCO                      103
+#define CLKID_HIFI_PLL_DCO                     104
+#define CLKID_VPU_0_DIV                                111
+#define CLKID_VPU_1_DIV                                114
+#define CLKID_VAPB_0_DIV                       118
+#define CLKID_VAPB_1_DIV                       121
+#define CLKID_HDMI_PLL_DCO                     125
+#define CLKID_HDMI_PLL_OD                      126
+#define CLKID_HDMI_PLL_OD2                     127
+#define CLKID_VID_PLL_SEL                      130
+#define CLKID_VID_PLL_DIV                      131
+#define CLKID_VCLK_SEL                         132
+#define CLKID_VCLK2_SEL                                133
+#define CLKID_VCLK_INPUT                       134
+#define CLKID_VCLK2_INPUT                      135
+#define CLKID_VCLK_DIV                         136
+#define CLKID_VCLK2_DIV                                137
+#define CLKID_VCLK_DIV2_EN                     140
+#define CLKID_VCLK_DIV4_EN                     141
+#define CLKID_VCLK_DIV6_EN                     142
+#define CLKID_VCLK_DIV12_EN                    143
+#define CLKID_VCLK2_DIV2_EN                    144
+#define CLKID_VCLK2_DIV4_EN                    145
+#define CLKID_VCLK2_DIV6_EN                    146
+#define CLKID_VCLK2_DIV12_EN                   147
+#define CLKID_CTS_ENCI_SEL                     158
+#define CLKID_CTS_ENCP_SEL                     159
+#define CLKID_CTS_VDAC_SEL                     160
+#define CLKID_HDMI_TX_SEL                      161
+#define CLKID_HDMI_SEL                         166
+#define CLKID_HDMI_DIV                         167
+#define CLKID_MALI_0_DIV                       170
+#define CLKID_MALI_1_DIV                       173
+#define CLKID_MPLL_5OM_DIV                     176
+
+#define NR_CLKS                                        178
+
+/* include the CLKIDs that have been made part of the DT binding */
+#include <dt-bindings/clock/g12a-clkc.h>
+
+#endif /* __G12A_H */
diff --git a/drivers/clk/meson/gxbb-aoclk-32k.c b/drivers/clk/meson/gxbb-aoclk-32k.c
deleted file mode 100644 (file)
index 6804671..0000000
+++ /dev/null
@@ -1,193 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (c) 2017 BayLibre, SAS.
- * Author: Neil Armstrong <narmstrong@baylibre.com>
- */
-
-#include <linux/clk-provider.h>
-#include <linux/bitfield.h>
-#include <linux/regmap.h>
-#include "gxbb-aoclk.h"
-
-/*
- * The AO Domain embeds a dual/divider to generate a more precise
- * 32,768KHz clock for low-power suspend mode and CEC.
- *                      ______   ______
- *                     |      | |      |
- *         ______      | Div1 |-| Cnt1 |       ______
- *        |      |    /|______| |______|\     |      |
- * Xtal-->| Gate |---|  ______   ______  X-X--| Gate |-->
- *        |______| |  \|      | |      |/  |  |______|
- *                 |   | Div2 |-| Cnt2 |   |
- *                 |   |______| |______|   |
- *                 |_______________________|
- *
- * The dividing can be switched to single or dual, with a counter
- * for each divider to set when the switching is done.
- * The entire dividing mechanism can be also bypassed.
- */
-
-#define CLK_CNTL0_N1_MASK      GENMASK(11, 0)
-#define CLK_CNTL0_N2_MASK      GENMASK(23, 12)
-#define CLK_CNTL0_DUALDIV_EN   BIT(28)
-#define CLK_CNTL0_OUT_GATE_EN  BIT(30)
-#define CLK_CNTL0_IN_GATE_EN   BIT(31)
-
-#define CLK_CNTL1_M1_MASK      GENMASK(11, 0)
-#define CLK_CNTL1_M2_MASK      GENMASK(23, 12)
-#define CLK_CNTL1_BYPASS_EN    BIT(24)
-#define CLK_CNTL1_SELECT_OSC   BIT(27)
-
-#define PWR_CNTL_ALT_32K_SEL   GENMASK(13, 10)
-
-struct cec_32k_freq_table {
-       unsigned long parent_rate;
-       unsigned long target_rate;
-       bool dualdiv;
-       unsigned int n1;
-       unsigned int n2;
-       unsigned int m1;
-       unsigned int m2;
-};
-
-static const struct cec_32k_freq_table aoclk_cec_32k_table[] = {
-       [0] = {
-               .parent_rate = 24000000,
-               .target_rate = 32768,
-               .dualdiv = true,
-               .n1 = 733,
-               .n2 = 732,
-               .m1 = 8,
-               .m2 = 11,
-       },
-};
-
-/*
- * If CLK_CNTL0_DUALDIV_EN == 0
- *  - will use N1 divider only
- * If CLK_CNTL0_DUALDIV_EN == 1
- *  - hold M1 cycles of N1 divider then changes to N2
- *  - hold M2 cycles of N2 divider then changes to N1
- * Then we can get more accurate division.
- */
-static unsigned long aoclk_cec_32k_recalc_rate(struct clk_hw *hw,
-                                              unsigned long parent_rate)
-{
-       struct aoclk_cec_32k *cec_32k = to_aoclk_cec_32k(hw);
-       unsigned long n1;
-       u32 reg0, reg1;
-
-       regmap_read(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL0, &reg0);
-       regmap_read(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL1, &reg1);
-
-       if (reg1 & CLK_CNTL1_BYPASS_EN)
-               return parent_rate;
-
-       if (reg0 & CLK_CNTL0_DUALDIV_EN) {
-               unsigned long n2, m1, m2, f1, f2, p1, p2;
-
-               n1 = FIELD_GET(CLK_CNTL0_N1_MASK, reg0) + 1;
-               n2 = FIELD_GET(CLK_CNTL0_N2_MASK, reg0) + 1;
-
-               m1 = FIELD_GET(CLK_CNTL1_M1_MASK, reg1) + 1;
-               m2 = FIELD_GET(CLK_CNTL1_M2_MASK, reg1) + 1;
-
-               f1 = DIV_ROUND_CLOSEST(parent_rate, n1);
-               f2 = DIV_ROUND_CLOSEST(parent_rate, n2);
-
-               p1 = DIV_ROUND_CLOSEST(100000000 * m1, f1 * (m1 + m2));
-               p2 = DIV_ROUND_CLOSEST(100000000 * m2, f2 * (m1 + m2));
-
-               return DIV_ROUND_UP(100000000, p1 + p2);
-       }
-
-       n1 = FIELD_GET(CLK_CNTL0_N1_MASK, reg0) + 1;
-
-       return DIV_ROUND_CLOSEST(parent_rate, n1);
-}
-
-static const struct cec_32k_freq_table *find_cec_32k_freq(unsigned long rate,
-                                                         unsigned long prate)
-{
-       int i;
-
-       for (i = 0 ; i < ARRAY_SIZE(aoclk_cec_32k_table) ; ++i)
-               if (aoclk_cec_32k_table[i].parent_rate == prate &&
-                   aoclk_cec_32k_table[i].target_rate == rate)
-                       return &aoclk_cec_32k_table[i];
-
-       return NULL;
-}
-
-static long aoclk_cec_32k_round_rate(struct clk_hw *hw, unsigned long rate,
-                                    unsigned long *prate)
-{
-       const struct cec_32k_freq_table *freq = find_cec_32k_freq(rate,
-                                                                 *prate);
-
-       /* If invalid return first one */
-       if (!freq)
-               return aoclk_cec_32k_table[0].target_rate;
-
-       return freq->target_rate;
-}
-
-/*
- * From the Amlogic init procedure, the IN and OUT gates needs to be handled
- * in the init procedure to avoid any glitches.
- */
-
-static int aoclk_cec_32k_set_rate(struct clk_hw *hw, unsigned long rate,
-                                 unsigned long parent_rate)
-{
-       const struct cec_32k_freq_table *freq = find_cec_32k_freq(rate,
-                                                                 parent_rate);
-       struct aoclk_cec_32k *cec_32k = to_aoclk_cec_32k(hw);
-       u32 reg = 0;
-
-       if (!freq)
-               return -EINVAL;
-
-       /* Disable clock */
-       regmap_update_bits(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL0,
-                          CLK_CNTL0_IN_GATE_EN | CLK_CNTL0_OUT_GATE_EN, 0);
-
-       reg = FIELD_PREP(CLK_CNTL0_N1_MASK, freq->n1 - 1);
-       if (freq->dualdiv)
-               reg |= CLK_CNTL0_DUALDIV_EN |
-                      FIELD_PREP(CLK_CNTL0_N2_MASK, freq->n2 - 1);
-
-       regmap_write(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL0, reg);
-
-       reg = FIELD_PREP(CLK_CNTL1_M1_MASK, freq->m1 - 1);
-       if (freq->dualdiv)
-               reg |= FIELD_PREP(CLK_CNTL1_M2_MASK, freq->m2 - 1);
-
-       regmap_write(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL1, reg);
-
-       /* Enable clock */
-       regmap_update_bits(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL0,
-                          CLK_CNTL0_IN_GATE_EN, CLK_CNTL0_IN_GATE_EN);
-
-       udelay(200);
-
-       regmap_update_bits(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL0,
-                          CLK_CNTL0_OUT_GATE_EN, CLK_CNTL0_OUT_GATE_EN);
-
-       regmap_update_bits(cec_32k->regmap, AO_CRT_CLK_CNTL1,
-                          CLK_CNTL1_SELECT_OSC, CLK_CNTL1_SELECT_OSC);
-
-       /* Select 32k from XTAL */
-       regmap_update_bits(cec_32k->regmap,
-                         AO_RTI_PWR_CNTL_REG0,
-                         PWR_CNTL_ALT_32K_SEL,
-                         FIELD_PREP(PWR_CNTL_ALT_32K_SEL, 4));
-
-       return 0;
-}
-
-const struct clk_ops meson_aoclk_cec_32k_ops = {
-       .recalc_rate = aoclk_cec_32k_recalc_rate,
-       .round_rate = aoclk_cec_32k_round_rate,
-       .set_rate = aoclk_cec_32k_set_rate,
-};
index 42ed61d..449f6ac 100644 (file)
@@ -5,10 +5,23 @@
  */
 #include <linux/platform_device.h>
 #include <linux/mfd/syscon.h>
-#include "clk-regmap.h"
 #include "meson-aoclk.h"
 #include "gxbb-aoclk.h"
 
+#include "clk-regmap.h"
+#include "clk-dualdiv.h"
+
+#define IN_PREFIX "ao-in-"
+
+/* AO Configuration Clock registers offsets */
+#define AO_RTI_PWR_CNTL_REG1   0x0c
+#define AO_RTI_PWR_CNTL_REG0   0x10
+#define AO_RTI_GEN_CNTL_REG0   0x40
+#define AO_OSCIN_CNTL          0x58
+#define AO_CRT_CLK_CNTL1       0x68
+#define AO_RTC_ALT_CLK_CNTL0   0x94
+#define AO_RTC_ALT_CLK_CNTL1   0x98
+
 #define GXBB_AO_GATE(_name, _bit)                                      \
 static struct clk_regmap _name##_ao = {                                        \
        .data = &(struct clk_regmap_gate_data) {                        \
@@ -18,7 +31,7 @@ static struct clk_regmap _name##_ao = {                                       \
        .hw.init = &(struct clk_init_data) {                            \
                .name = #_name "_ao",                                   \
                .ops = &clk_regmap_gate_ops,                            \
-               .parent_names = (const char *[]){ "clk81" },            \
+               .parent_names = (const char *[]){ IN_PREFIX "mpeg-clk" }, \
                .num_parents = 1,                                       \
                .flags = CLK_IGNORE_UNUSED,                             \
        },                                                              \
@@ -31,13 +44,174 @@ GXBB_AO_GATE(uart1, 3);
 GXBB_AO_GATE(uart2, 5);
 GXBB_AO_GATE(ir_blaster, 6);
 
-static struct aoclk_cec_32k cec_32k_ao = {
-       .hw.init = &(struct clk_init_data) {
-               .name = "cec_32k_ao",
-               .ops = &meson_aoclk_cec_32k_ops,
-               .parent_names = (const char *[]){ "xtal" },
+static struct clk_regmap ao_cts_oscin = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = AO_RTI_PWR_CNTL_REG0,
+               .bit_idx = 6,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "ao_cts_oscin",
+               .ops = &clk_regmap_gate_ro_ops,
+               .parent_names = (const char *[]){ IN_PREFIX "xtal" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_regmap ao_32k_pre = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = AO_RTC_ALT_CLK_CNTL0,
+               .bit_idx = 31,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "ao_32k_pre",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "ao_cts_oscin" },
+               .num_parents = 1,
+       },
+};
+
+static const struct meson_clk_dualdiv_param gxbb_32k_div_table[] = {
+       {
+               .dual   = 1,
+               .n1     = 733,
+               .m1     = 8,
+               .n2     = 732,
+               .m2     = 11,
+       }, {}
+};
+
+static struct clk_regmap ao_32k_div = {
+       .data = &(struct meson_clk_dualdiv_data){
+               .n1 = {
+                       .reg_off = AO_RTC_ALT_CLK_CNTL0,
+                       .shift   = 0,
+                       .width   = 12,
+               },
+               .n2 = {
+                       .reg_off = AO_RTC_ALT_CLK_CNTL0,
+                       .shift   = 12,
+                       .width   = 12,
+               },
+               .m1 = {
+                       .reg_off = AO_RTC_ALT_CLK_CNTL1,
+                       .shift   = 0,
+                       .width   = 12,
+               },
+               .m2 = {
+                       .reg_off = AO_RTC_ALT_CLK_CNTL1,
+                       .shift   = 12,
+                       .width   = 12,
+               },
+               .dual = {
+                       .reg_off = AO_RTC_ALT_CLK_CNTL0,
+                       .shift   = 28,
+                       .width   = 1,
+               },
+               .table = gxbb_32k_div_table,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "ao_32k_div",
+               .ops = &meson_clk_dualdiv_ops,
+               .parent_names = (const char *[]){ "ao_32k_pre" },
+               .num_parents = 1,
+       },
+};
+
+static struct clk_regmap ao_32k_sel = {
+       .data = &(struct clk_regmap_mux_data) {
+               .offset = AO_RTC_ALT_CLK_CNTL1,
+               .mask = 0x1,
+               .shift = 24,
+               .flags = CLK_MUX_ROUND_CLOSEST,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "ao_32k_sel",
+               .ops = &clk_regmap_mux_ops,
+               .parent_names = (const char *[]){ "ao_32k_div",
+                                                 "ao_32k_pre" },
+               .num_parents = 2,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap ao_32k = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = AO_RTC_ALT_CLK_CNTL0,
+               .bit_idx = 30,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "ao_32k",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "ao_32k_sel" },
                .num_parents = 1,
-               .flags = CLK_IGNORE_UNUSED,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap ao_cts_rtc_oscin = {
+       .data = &(struct clk_regmap_mux_data) {
+               .offset = AO_RTI_PWR_CNTL_REG0,
+               .mask = 0x7,
+               .shift = 10,
+               .table = (u32[]){ 1, 2, 3, 4 },
+               .flags = CLK_MUX_ROUND_CLOSEST,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "ao_cts_rtc_oscin",
+               .ops = &clk_regmap_mux_ops,
+               .parent_names = (const char *[]){ IN_PREFIX "ext-32k-0",
+                                                 IN_PREFIX "ext-32k-1",
+                                                 IN_PREFIX "ext-32k-2",
+                                                 "ao_32k" },
+               .num_parents = 4,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap ao_clk81 = {
+       .data = &(struct clk_regmap_mux_data) {
+               .offset = AO_RTI_PWR_CNTL_REG0,
+               .mask = 0x1,
+               .shift = 0,
+               .flags = CLK_MUX_ROUND_CLOSEST,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "ao_clk81",
+               .ops = &clk_regmap_mux_ro_ops,
+               .parent_names = (const char *[]){ IN_PREFIX "mpeg-clk",
+                                                 "ao_cts_rtc_oscin" },
+               .num_parents = 2,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap ao_cts_cec = {
+       .data = &(struct clk_regmap_mux_data) {
+               .offset = AO_CRT_CLK_CNTL1,
+               .mask = 0x1,
+               .shift = 27,
+               .flags = CLK_MUX_ROUND_CLOSEST,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "ao_cts_cec",
+               .ops = &clk_regmap_mux_ops,
+               /*
+                * FIXME: The 'fixme' parent obviously does not exist.
+                *
+                * ATM, CCF won't call get_parent() if num_parents is 1. It
+                * does not allow NULL as a parent name either.
+                *
+                * On this particular mux, we only know the input #1 parent
+                * but, on boot, unknown input #0 is set, so it is critical
+                * to call .get_parent() on it
+                *
+                * Until CCF gets fixed, adding this fake parent that won't
+                * ever be registered should work around the problem
+                */
+               .parent_names = (const char *[]){ "fixme",
+                                                 "ao_cts_rtc_oscin" },
+               .num_parents = 2,
+               .flags = CLK_SET_RATE_PARENT,
        },
 };
 
@@ -50,13 +224,21 @@ static const unsigned int gxbb_aoclk_reset[] = {
        [RESET_AO_IR_BLASTER] = 23,
 };
 
-static struct clk_regmap *gxbb_aoclk_gate[] = {
-       [CLKID_AO_REMOTE] = &remote_ao,
-       [CLKID_AO_I2C_MASTER] = &i2c_master_ao,
-       [CLKID_AO_I2C_SLAVE] = &i2c_slave_ao,
-       [CLKID_AO_UART1] = &uart1_ao,
-       [CLKID_AO_UART2] = &uart2_ao,
-       [CLKID_AO_IR_BLASTER] = &ir_blaster_ao,
+static struct clk_regmap *gxbb_aoclk[] = {
+       &remote_ao,
+       &i2c_master_ao,
+       &i2c_slave_ao,
+       &uart1_ao,
+       &uart2_ao,
+       &ir_blaster_ao,
+       &ao_cts_oscin,
+       &ao_32k_pre,
+       &ao_32k_div,
+       &ao_32k_sel,
+       &ao_32k,
+       &ao_cts_rtc_oscin,
+       &ao_clk81,
+       &ao_cts_cec,
 };
 
 static const struct clk_hw_onecell_data gxbb_aoclk_onecell_data = {
@@ -67,52 +249,38 @@ static const struct clk_hw_onecell_data gxbb_aoclk_onecell_data = {
                [CLKID_AO_UART1] = &uart1_ao.hw,
                [CLKID_AO_UART2] = &uart2_ao.hw,
                [CLKID_AO_IR_BLASTER] = &ir_blaster_ao.hw,
-               [CLKID_AO_CEC_32K] = &cec_32k_ao.hw,
+               [CLKID_AO_CEC_32K] = &ao_cts_cec.hw,
+               [CLKID_AO_CTS_OSCIN] = &ao_cts_oscin.hw,
+               [CLKID_AO_32K_PRE] = &ao_32k_pre.hw,
+               [CLKID_AO_32K_DIV] = &ao_32k_div.hw,
+               [CLKID_AO_32K_SEL] = &ao_32k_sel.hw,
+               [CLKID_AO_32K] = &ao_32k.hw,
+               [CLKID_AO_CTS_RTC_OSCIN] = &ao_cts_rtc_oscin.hw,
+               [CLKID_AO_CLK81] = &ao_clk81.hw,
        },
        .num = NR_CLKS,
 };
 
-static int gxbb_register_cec_ao_32k(struct platform_device *pdev)
-{
-       struct device *dev = &pdev->dev;
-       struct regmap *regmap;
-       int ret;
-
-       regmap = syscon_node_to_regmap(of_get_parent(dev->of_node));
-       if (IS_ERR(regmap)) {
-               dev_err(dev, "failed to get regmap\n");
-               return PTR_ERR(regmap);
-       }
-
-       /* Specific clocks */
-       cec_32k_ao.regmap = regmap;
-       ret = devm_clk_hw_register(dev, &cec_32k_ao.hw);
-       if (ret) {
-               dev_err(&pdev->dev, "clk cec_32k_ao register failed.\n");
-               return ret;
-       }
-
-       return 0;
-}
+static const struct meson_aoclk_input gxbb_aoclk_inputs[] = {
+       { .name = "xtal",       .required = true,  },
+       { .name = "mpeg-clk",   .required = true,  },
+       {. name = "ext-32k-0",  .required = false, },
+       {. name = "ext-32k-1",  .required = false, },
+       {. name = "ext-32k-2",  .required = false, },
+};
 
 static const struct meson_aoclk_data gxbb_aoclkc_data = {
        .reset_reg      = AO_RTI_GEN_CNTL_REG0,
        .num_reset      = ARRAY_SIZE(gxbb_aoclk_reset),
        .reset          = gxbb_aoclk_reset,
-       .num_clks       = ARRAY_SIZE(gxbb_aoclk_gate),
-       .clks           = gxbb_aoclk_gate,
+       .num_clks       = ARRAY_SIZE(gxbb_aoclk),
+       .clks           = gxbb_aoclk,
        .hw_data        = &gxbb_aoclk_onecell_data,
+       .inputs         = gxbb_aoclk_inputs,
+       .num_inputs     = ARRAY_SIZE(gxbb_aoclk_inputs),
+       .input_prefix   = IN_PREFIX,
 };
 
-static int gxbb_aoclkc_probe(struct platform_device *pdev)
-{
-       int ret = gxbb_register_cec_ao_32k(pdev);
-       if (ret)
-               return ret;
-
-       return meson_aoclkc_probe(pdev);
-}
-
 static const struct of_device_id gxbb_aoclkc_match_table[] = {
        {
                .compatible     = "amlogic,meson-gx-aoclkc",
@@ -122,7 +290,7 @@ static const struct of_device_id gxbb_aoclkc_match_table[] = {
 };
 
 static struct platform_driver gxbb_aoclkc_driver = {
-       .probe          = gxbb_aoclkc_probe,
+       .probe          = meson_aoclkc_probe,
        .driver         = {
                .name   = "gxbb-aoclkc",
                .of_match_table = gxbb_aoclkc_match_table,
index c514493..1db16f9 100644 (file)
@@ -7,25 +7,7 @@
 #ifndef __GXBB_AOCLKC_H
 #define __GXBB_AOCLKC_H
 
-#define NR_CLKS        7
-
-/* AO Configuration Clock registers offsets */
-#define AO_RTI_PWR_CNTL_REG1   0x0c
-#define AO_RTI_PWR_CNTL_REG0   0x10
-#define AO_RTI_GEN_CNTL_REG0   0x40
-#define AO_OSCIN_CNTL          0x58
-#define AO_CRT_CLK_CNTL1       0x68
-#define AO_RTC_ALT_CLK_CNTL0   0x94
-#define AO_RTC_ALT_CLK_CNTL1   0x98
-
-struct aoclk_cec_32k {
-       struct clk_hw hw;
-       struct regmap *regmap;
-};
-
-#define to_aoclk_cec_32k(_hw) container_of(_hw, struct aoclk_cec_32k, hw)
-
-extern const struct clk_ops meson_aoclk_cec_32k_ops;
+#define NR_CLKS        14
 
 #include <dt-bindings/clock/gxbb-aoclkc.h>
 #include <dt-bindings/reset/gxbb-aoclkc.h>
index 65f2599..04df2e2 100644 (file)
@@ -4,17 +4,20 @@
  * Michael Turquette <mturquette@baylibre.com>
  */
 
-#include <linux/clk.h>
 #include <linux/clk-provider.h>
 #include <linux/init.h>
 #include <linux/of_device.h>
-#include <linux/mfd/syscon.h>
 #include <linux/platform_device.h>
-#include <linux/regmap.h>
 
-#include "clkc.h"
 #include "gxbb.h"
+#include "clk-input.h"
 #include "clk-regmap.h"
+#include "clk-pll.h"
+#include "clk-mpll.h"
+#include "meson-eeclk.h"
+#include "vid-pll-div.h"
+
+#define IN_PREFIX "ee-in-"
 
 static DEFINE_SPINLOCK(meson_clk_lock);
 
@@ -118,7 +121,7 @@ static struct clk_regmap gxbb_fixed_pll_dco = {
        .hw.init = &(struct clk_init_data){
                .name = "fixed_pll_dco",
                .ops = &meson_clk_pll_ro_ops,
-               .parent_names = (const char *[]){ "xtal" },
+               .parent_names = (const char *[]){ IN_PREFIX "xtal" },
                .num_parents = 1,
        },
 };
@@ -148,7 +151,7 @@ static struct clk_fixed_factor gxbb_hdmi_pll_pre_mult = {
        .hw.init = &(struct clk_init_data){
                .name = "hdmi_pll_pre_mult",
                .ops = &clk_fixed_factor_ops,
-               .parent_names = (const char *[]){ "xtal" },
+               .parent_names = (const char *[]){ IN_PREFIX "xtal" },
                .num_parents = 1,
        },
 };
@@ -241,7 +244,7 @@ static struct clk_regmap gxl_hdmi_pll_dco = {
        .hw.init = &(struct clk_init_data){
                .name = "hdmi_pll_dco",
                .ops = &meson_clk_pll_ro_ops,
-               .parent_names = (const char *[]){ "xtal" },
+               .parent_names = (const char *[]){ IN_PREFIX "xtal" },
                .num_parents = 1,
                /*
                 * Display directly handle hdmi pll registers ATM, we need
@@ -378,7 +381,7 @@ static struct clk_regmap gxbb_sys_pll_dco = {
        .hw.init = &(struct clk_init_data){
                .name = "sys_pll_dco",
                .ops = &meson_clk_pll_ro_ops,
-               .parent_names = (const char *[]){ "xtal" },
+               .parent_names = (const char *[]){ IN_PREFIX "xtal" },
                .num_parents = 1,
        },
 };
@@ -439,7 +442,7 @@ static struct clk_regmap gxbb_gp0_pll_dco = {
        .hw.init = &(struct clk_init_data){
                .name = "gp0_pll_dco",
                .ops = &meson_clk_pll_ops,
-               .parent_names = (const char *[]){ "xtal" },
+               .parent_names = (const char *[]){ IN_PREFIX "xtal" },
                .num_parents = 1,
        },
 };
@@ -491,7 +494,7 @@ static struct clk_regmap gxl_gp0_pll_dco = {
        .hw.init = &(struct clk_init_data){
                .name = "gp0_pll_dco",
                .ops = &meson_clk_pll_ops,
-               .parent_names = (const char *[]){ "xtal" },
+               .parent_names = (const char *[]){ IN_PREFIX "xtal" },
                .num_parents = 1,
        },
 };
@@ -789,7 +792,7 @@ static struct clk_regmap gxbb_mpll2 = {
 
 static u32 mux_table_clk81[]   = { 0, 2, 3, 4, 5, 6, 7 };
 static const char * const clk81_parent_names[] = {
-       "xtal", "fclk_div7", "mpll1", "mpll2", "fclk_div4",
+       IN_PREFIX "xtal", "fclk_div7", "mpll1", "mpll2", "fclk_div4",
        "fclk_div3", "fclk_div5"
 };
 
@@ -852,7 +855,7 @@ static struct clk_regmap gxbb_sar_adc_clk_sel = {
                .name = "sar_adc_clk_sel",
                .ops = &clk_regmap_mux_ops,
                /* NOTE: The datasheet doesn't list the parents for bit 10 */
-               .parent_names = (const char *[]){ "xtal", "clk81", },
+               .parent_names = (const char *[]){ IN_PREFIX "xtal", "clk81", },
                .num_parents = 2,
        },
 };
@@ -891,7 +894,7 @@ static struct clk_regmap gxbb_sar_adc_clk = {
  */
 
 static const char * const gxbb_mali_0_1_parent_names[] = {
-       "xtal", "gp0_pll", "mpll2", "mpll1", "fclk_div7",
+       IN_PREFIX "xtal", "gp0_pll", "mpll2", "mpll1", "fclk_div7",
        "fclk_div4", "fclk_div3", "fclk_div5"
 };
 
@@ -1153,7 +1156,7 @@ static struct clk_regmap gxbb_32k_clk = {
 };
 
 static const char * const gxbb_32k_clk_parent_names[] = {
-       "xtal", "cts_slow_oscin", "fclk_div3", "fclk_div5"
+       IN_PREFIX "xtal", "cts_slow_oscin", "fclk_div3", "fclk_div5"
 };
 
 static struct clk_regmap gxbb_32k_clk_sel = {
@@ -1172,7 +1175,7 @@ static struct clk_regmap gxbb_32k_clk_sel = {
 };
 
 static const char * const gxbb_sd_emmc_clk0_parent_names[] = {
-       "xtal", "fclk_div2", "fclk_div3", "fclk_div5", "fclk_div7",
+       IN_PREFIX "xtal", "fclk_div2", "fclk_div3", "fclk_div5", "fclk_div7",
 
        /*
         * Following these parent clocks, we should also have had mpll2, mpll3
@@ -2138,7 +2141,7 @@ static struct clk_regmap gxbb_hdmi_tx = {
 /* HDMI Clocks */
 
 static const char * const gxbb_hdmi_parent_names[] = {
-       "xtal", "fclk_div4", "fclk_div3", "fclk_div5"
+       IN_PREFIX "xtal", "fclk_div4", "fclk_div3", "fclk_div5"
 };
 
 static struct clk_regmap gxbb_hdmi_sel = {
@@ -2285,7 +2288,7 @@ static struct clk_regmap gxbb_vdec_hevc = {
 static u32 mux_table_gen_clk[] = { 0, 4, 5, 6, 7, 8,
                                    9, 10, 11, 13, 14, };
 static const char * const gen_clk_parent_names[] = {
-       "xtal", "vdec_1", "vdec_hevc", "mpll0", "mpll1", "mpll2",
+       IN_PREFIX "xtal", "vdec_1", "vdec_hevc", "mpll0", "mpll1", "mpll2",
        "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7", "gp0_pll",
 };
 
@@ -2854,6 +2857,192 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = {
 };
 
 static struct clk_regmap *const gxbb_clk_regmaps[] = {
+       &gxbb_clk81,
+       &gxbb_ddr,
+       &gxbb_dos,
+       &gxbb_isa,
+       &gxbb_pl301,
+       &gxbb_periphs,
+       &gxbb_spicc,
+       &gxbb_i2c,
+       &gxbb_sar_adc,
+       &gxbb_smart_card,
+       &gxbb_rng0,
+       &gxbb_uart0,
+       &gxbb_sdhc,
+       &gxbb_stream,
+       &gxbb_async_fifo,
+       &gxbb_sdio,
+       &gxbb_abuf,
+       &gxbb_hiu_iface,
+       &gxbb_assist_misc,
+       &gxbb_spi,
+       &gxbb_i2s_spdif,
+       &gxbb_eth,
+       &gxbb_demux,
+       &gxbb_aiu_glue,
+       &gxbb_iec958,
+       &gxbb_i2s_out,
+       &gxbb_amclk,
+       &gxbb_aififo2,
+       &gxbb_mixer,
+       &gxbb_mixer_iface,
+       &gxbb_adc,
+       &gxbb_blkmv,
+       &gxbb_aiu,
+       &gxbb_uart1,
+       &gxbb_g2d,
+       &gxbb_usb0,
+       &gxbb_usb1,
+       &gxbb_reset,
+       &gxbb_nand,
+       &gxbb_dos_parser,
+       &gxbb_usb,
+       &gxbb_vdin1,
+       &gxbb_ahb_arb0,
+       &gxbb_efuse,
+       &gxbb_boot_rom,
+       &gxbb_ahb_data_bus,
+       &gxbb_ahb_ctrl_bus,
+       &gxbb_hdmi_intr_sync,
+       &gxbb_hdmi_pclk,
+       &gxbb_usb1_ddr_bridge,
+       &gxbb_usb0_ddr_bridge,
+       &gxbb_mmc_pclk,
+       &gxbb_dvin,
+       &gxbb_uart2,
+       &gxbb_sana,
+       &gxbb_vpu_intr,
+       &gxbb_sec_ahb_ahb3_bridge,
+       &gxbb_clk81_a53,
+       &gxbb_vclk2_venci0,
+       &gxbb_vclk2_venci1,
+       &gxbb_vclk2_vencp0,
+       &gxbb_vclk2_vencp1,
+       &gxbb_gclk_venci_int0,
+       &gxbb_gclk_vencp_int,
+       &gxbb_dac_clk,
+       &gxbb_aoclk_gate,
+       &gxbb_iec958_gate,
+       &gxbb_enc480p,
+       &gxbb_rng1,
+       &gxbb_gclk_venci_int1,
+       &gxbb_vclk2_venclmcc,
+       &gxbb_vclk2_vencl,
+       &gxbb_vclk_other,
+       &gxbb_edp,
+       &gxbb_ao_media_cpu,
+       &gxbb_ao_ahb_sram,
+       &gxbb_ao_ahb_bus,
+       &gxbb_ao_iface,
+       &gxbb_ao_i2c,
+       &gxbb_emmc_a,
+       &gxbb_emmc_b,
+       &gxbb_emmc_c,
+       &gxbb_sar_adc_clk,
+       &gxbb_mali_0,
+       &gxbb_mali_1,
+       &gxbb_cts_amclk,
+       &gxbb_cts_mclk_i958,
+       &gxbb_32k_clk,
+       &gxbb_sd_emmc_a_clk0,
+       &gxbb_sd_emmc_b_clk0,
+       &gxbb_sd_emmc_c_clk0,
+       &gxbb_vpu_0,
+       &gxbb_vpu_1,
+       &gxbb_vapb_0,
+       &gxbb_vapb_1,
+       &gxbb_vapb,
+       &gxbb_mpeg_clk_div,
+       &gxbb_sar_adc_clk_div,
+       &gxbb_mali_0_div,
+       &gxbb_mali_1_div,
+       &gxbb_cts_mclk_i958_div,
+       &gxbb_32k_clk_div,
+       &gxbb_sd_emmc_a_clk0_div,
+       &gxbb_sd_emmc_b_clk0_div,
+       &gxbb_sd_emmc_c_clk0_div,
+       &gxbb_vpu_0_div,
+       &gxbb_vpu_1_div,
+       &gxbb_vapb_0_div,
+       &gxbb_vapb_1_div,
+       &gxbb_mpeg_clk_sel,
+       &gxbb_sar_adc_clk_sel,
+       &gxbb_mali_0_sel,
+       &gxbb_mali_1_sel,
+       &gxbb_mali,
+       &gxbb_cts_amclk_sel,
+       &gxbb_cts_mclk_i958_sel,
+       &gxbb_cts_i958,
+       &gxbb_32k_clk_sel,
+       &gxbb_sd_emmc_a_clk0_sel,
+       &gxbb_sd_emmc_b_clk0_sel,
+       &gxbb_sd_emmc_c_clk0_sel,
+       &gxbb_vpu_0_sel,
+       &gxbb_vpu_1_sel,
+       &gxbb_vpu,
+       &gxbb_vapb_0_sel,
+       &gxbb_vapb_1_sel,
+       &gxbb_vapb_sel,
+       &gxbb_mpll0,
+       &gxbb_mpll1,
+       &gxbb_mpll2,
+       &gxbb_mpll0_div,
+       &gxbb_mpll1_div,
+       &gxbb_mpll2_div,
+       &gxbb_cts_amclk_div,
+       &gxbb_fixed_pll,
+       &gxbb_sys_pll,
+       &gxbb_mpll_prediv,
+       &gxbb_fclk_div2,
+       &gxbb_fclk_div3,
+       &gxbb_fclk_div4,
+       &gxbb_fclk_div5,
+       &gxbb_fclk_div7,
+       &gxbb_vdec_1_sel,
+       &gxbb_vdec_1_div,
+       &gxbb_vdec_1,
+       &gxbb_vdec_hevc_sel,
+       &gxbb_vdec_hevc_div,
+       &gxbb_vdec_hevc,
+       &gxbb_gen_clk_sel,
+       &gxbb_gen_clk_div,
+       &gxbb_gen_clk,
+       &gxbb_fixed_pll_dco,
+       &gxbb_sys_pll_dco,
+       &gxbb_gp0_pll,
+       &gxbb_vid_pll,
+       &gxbb_vid_pll_sel,
+       &gxbb_vid_pll_div,
+       &gxbb_vclk,
+       &gxbb_vclk_sel,
+       &gxbb_vclk_div,
+       &gxbb_vclk_input,
+       &gxbb_vclk_div1,
+       &gxbb_vclk_div2_en,
+       &gxbb_vclk_div4_en,
+       &gxbb_vclk_div6_en,
+       &gxbb_vclk_div12_en,
+       &gxbb_vclk2,
+       &gxbb_vclk2_sel,
+       &gxbb_vclk2_div,
+       &gxbb_vclk2_input,
+       &gxbb_vclk2_div1,
+       &gxbb_vclk2_div2_en,
+       &gxbb_vclk2_div4_en,
+       &gxbb_vclk2_div6_en,
+       &gxbb_vclk2_div12_en,
+       &gxbb_cts_enci,
+       &gxbb_cts_enci_sel,
+       &gxbb_cts_encp,
+       &gxbb_cts_encp_sel,
+       &gxbb_cts_vdac,
+       &gxbb_cts_vdac_sel,
+       &gxbb_hdmi_tx,
+       &gxbb_hdmi_tx_sel,
+       &gxbb_hdmi_sel,
+       &gxbb_hdmi_div,
+       &gxbb_hdmi,
        &gxbb_gp0_pll_dco,
        &gxbb_hdmi_pll,
        &gxbb_hdmi_pll_od,
@@ -2862,14 +3051,6 @@ static struct clk_regmap *const gxbb_clk_regmaps[] = {
 };
 
 static struct clk_regmap *const gxl_clk_regmaps[] = {
-       &gxl_gp0_pll_dco,
-       &gxl_hdmi_pll,
-       &gxl_hdmi_pll_od,
-       &gxl_hdmi_pll_od2,
-       &gxl_hdmi_pll_dco,
-};
-
-static struct clk_regmap *const gx_clk_regmaps[] = {
        &gxbb_clk81,
        &gxbb_ddr,
        &gxbb_dos,
@@ -3056,23 +3237,22 @@ static struct clk_regmap *const gx_clk_regmaps[] = {
        &gxbb_hdmi_sel,
        &gxbb_hdmi_div,
        &gxbb_hdmi,
+       &gxl_gp0_pll_dco,
+       &gxl_hdmi_pll,
+       &gxl_hdmi_pll_od,
+       &gxl_hdmi_pll_od2,
+       &gxl_hdmi_pll_dco,
 };
 
-struct clkc_data {
-       struct clk_regmap *const *regmap_clks;
-       unsigned int regmap_clks_count;
-       struct clk_hw_onecell_data *hw_onecell_data;
-};
-
-static const struct clkc_data gxbb_clkc_data = {
+static const struct meson_eeclkc_data gxbb_clkc_data = {
        .regmap_clks = gxbb_clk_regmaps,
-       .regmap_clks_count = ARRAY_SIZE(gxbb_clk_regmaps),
+       .regmap_clk_num = ARRAY_SIZE(gxbb_clk_regmaps),
        .hw_onecell_data = &gxbb_hw_onecell_data,
 };
 
-static const struct clkc_data gxl_clkc_data = {
+static const struct meson_eeclkc_data gxl_clkc_data = {
        .regmap_clks = gxl_clk_regmaps,
-       .regmap_clks_count = ARRAY_SIZE(gxl_clk_regmaps),
+       .regmap_clk_num = ARRAY_SIZE(gxl_clk_regmaps),
        .hw_onecell_data = &gxl_hw_onecell_data,
 };
 
@@ -3082,52 +3262,8 @@ static const struct of_device_id clkc_match_table[] = {
        {},
 };
 
-static int gxbb_clkc_probe(struct platform_device *pdev)
-{
-       const struct clkc_data *clkc_data;
-       struct regmap *map;
-       int ret, i;
-       struct device *dev = &pdev->dev;
-
-       clkc_data = of_device_get_match_data(dev);
-       if (!clkc_data)
-               return -EINVAL;
-
-       /* Get the hhi system controller node if available */
-       map = syscon_node_to_regmap(of_get_parent(dev->of_node));
-       if (IS_ERR(map)) {
-               dev_err(dev, "failed to get HHI regmap\n");
-               return PTR_ERR(map);
-       }
-
-       /* Populate regmap for the common regmap backed clocks */
-       for (i = 0; i < ARRAY_SIZE(gx_clk_regmaps); i++)
-               gx_clk_regmaps[i]->map = map;
-
-       /* Populate regmap for soc specific clocks */
-       for (i = 0; i < clkc_data->regmap_clks_count; i++)
-               clkc_data->regmap_clks[i]->map = map;
-
-       /* Register all clks */
-       for (i = 0; i < clkc_data->hw_onecell_data->num; i++) {
-               /* array might be sparse */
-               if (!clkc_data->hw_onecell_data->hws[i])
-                       continue;
-
-               ret = devm_clk_hw_register(dev,
-                                          clkc_data->hw_onecell_data->hws[i]);
-               if (ret) {
-                       dev_err(dev, "Clock registration failed\n");
-                       return ret;
-               }
-       }
-
-       return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
-                                          clkc_data->hw_onecell_data);
-}
-
 static struct platform_driver gxbb_driver = {
-       .probe          = gxbb_clkc_probe,
+       .probe          = meson_eeclkc_probe,
        .driver         = {
                .name   = "gxbb-clkc",
                .of_match_table = clkc_match_table,
index f965845..b679519 100644 (file)
 #include <linux/reset-controller.h>
 #include <linux/mfd/syscon.h>
 #include <linux/of_device.h>
-#include "clk-regmap.h"
+#include <linux/slab.h>
 #include "meson-aoclk.h"
 
+#include "clk-input.h"
+
 static int meson_aoclk_do_reset(struct reset_controller_dev *rcdev,
                               unsigned long id)
 {
@@ -31,6 +33,37 @@ static const struct reset_control_ops meson_aoclk_reset_ops = {
        .reset = meson_aoclk_do_reset,
 };
 
+static int meson_aoclkc_register_inputs(struct device *dev,
+                                       struct meson_aoclk_data *data)
+{
+       struct clk_hw *hw;
+       char *str;
+       int i;
+
+       for (i = 0; i < data->num_inputs; i++) {
+               const struct meson_aoclk_input *in = &data->inputs[i];
+
+               str = kasprintf(GFP_KERNEL, "%s%s", data->input_prefix,
+                               in->name);
+               if (!str)
+                       return -ENOMEM;
+
+               hw = meson_clk_hw_register_input(dev, in->name, str, 0);
+               kfree(str);
+
+               if (IS_ERR(hw)) {
+                       if (!in->required && PTR_ERR(hw) == -ENOENT)
+                               continue;
+                       else if (PTR_ERR(hw) != -EPROBE_DEFER)
+                               dev_err(dev, "failed to register input %s\n",
+                                       in->name);
+                       return PTR_ERR(hw);
+               }
+       }
+
+       return 0;
+}
+
 int meson_aoclkc_probe(struct platform_device *pdev)
 {
        struct meson_aoclk_reset_controller *rstc;
@@ -53,6 +86,10 @@ int meson_aoclkc_probe(struct platform_device *pdev)
                return PTR_ERR(regmap);
        }
 
+       ret = meson_aoclkc_register_inputs(dev, data);
+       if (ret)
+               return ret;
+
        /* Reset Controller */
        rstc->data = data;
        rstc->regmap = regmap;
@@ -65,15 +102,20 @@ int meson_aoclkc_probe(struct platform_device *pdev)
                return ret;
        }
 
-       /*
-        * Populate regmap and register all clks
-        */
-       for (clkid = 0; clkid < data->num_clks; clkid++) {
+       /* Populate regmap */
+       for (clkid = 0; clkid < data->num_clks; clkid++)
                data->clks[clkid]->map = regmap;
 
+       /* Register all clks */
+       for (clkid = 0; clkid < data->hw_data->num; clkid++) {
+               if (!data->hw_data->hws[clkid])
+                       continue;
+
                ret = devm_clk_hw_register(dev, data->hw_data->hws[clkid]);
-               if (ret)
+               if (ret) {
+                       dev_err(dev, "Clock registration failed\n");
                        return ret;
+               }
        }
 
        return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
index ab2819e..999cde3 100644 (file)
 #ifndef __MESON_AOCLK_H__
 #define __MESON_AOCLK_H__
 
+#include <linux/clk-provider.h>
 #include <linux/platform_device.h>
+#include <linux/regmap.h>
 #include <linux/reset-controller.h>
+
 #include "clk-regmap.h"
 
+struct meson_aoclk_input {
+       const char *name;
+       bool required;
+};
+
 struct meson_aoclk_data {
        const unsigned int                      reset_reg;
        const int                               num_reset;
        const unsigned int                      *reset;
-       int                                     num_clks;
+       const int                               num_clks;
        struct clk_regmap                       **clks;
+       const int                               num_inputs;
+       const struct meson_aoclk_input          *inputs;
+       const char                              *input_prefix;
        const struct clk_hw_onecell_data        *hw_data;
 };
 
diff --git a/drivers/clk/meson/meson-eeclk.c b/drivers/clk/meson/meson-eeclk.c
new file mode 100644 (file)
index 0000000..37a34c9
--- /dev/null
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 BayLibre, SAS.
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+
+#include "clk-input.h"
+#include "clk-regmap.h"
+#include "meson-eeclk.h"
+
+int meson_eeclkc_probe(struct platform_device *pdev)
+{
+       const struct meson_eeclkc_data *data;
+       struct device *dev = &pdev->dev;
+       struct clk_hw *input;
+       struct regmap *map;
+       int ret, i;
+
+       data = of_device_get_match_data(dev);
+       if (!data)
+               return -EINVAL;
+
+       /* Get the hhi system controller node */
+       map = syscon_node_to_regmap(of_get_parent(dev->of_node));
+       if (IS_ERR(map)) {
+               dev_err(dev,
+                       "failed to get HHI regmap\n");
+               return PTR_ERR(map);
+       }
+
+       input = meson_clk_hw_register_input(dev, "xtal", IN_PREFIX "xtal", 0);
+       if (IS_ERR(input)) {
+               ret = PTR_ERR(input);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(dev, "failed to get input clock");
+               return ret;
+       }
+
+       /* Populate regmap for the regmap backed clocks */
+       for (i = 0; i < data->regmap_clk_num; i++)
+               data->regmap_clks[i]->map = map;
+
+       for (i = 0; i < data->hw_onecell_data->num; i++) {
+               /* array might be sparse */
+               if (!data->hw_onecell_data->hws[i])
+                       continue;
+
+               ret = devm_clk_hw_register(dev, data->hw_onecell_data->hws[i]);
+               if (ret) {
+                       dev_err(dev, "Clock registration failed\n");
+                       return ret;
+               }
+       }
+
+       return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
+                                          data->hw_onecell_data);
+}
diff --git a/drivers/clk/meson/meson-eeclk.h b/drivers/clk/meson/meson-eeclk.h
new file mode 100644 (file)
index 0000000..1b809b1
--- /dev/null
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 BayLibre, SAS.
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
+ */
+
+#ifndef __MESON_CLKC_H
+#define __MESON_CLKC_H
+
+#include <linux/clk-provider.h>
+#include "clk-regmap.h"
+
+#define IN_PREFIX "ee-in-"
+
+struct platform_device;
+
+struct meson_eeclkc_data {
+       struct clk_regmap *const        *regmap_clks;
+       unsigned int                    regmap_clk_num;
+       struct clk_hw_onecell_data      *hw_onecell_data;
+};
+
+int meson_eeclkc_probe(struct platform_device *pdev);
+
+#endif /* __MESON_CLKC_H */
index 950d0e5..576ad42 100644 (file)
 #include <linux/slab.h>
 #include <linux/regmap.h>
 
-#include "clkc.h"
 #include "meson8b.h"
 #include "clk-regmap.h"
+#include "clk-pll.h"
+#include "clk-mpll.h"
 
 static DEFINE_SPINLOCK(meson_clk_lock);
 
@@ -803,16 +804,16 @@ static struct clk_fixed_factor meson8b_cpu_clk_div8 = {
        },
 };
 
-static u32 mux_table_abp[] = { 1, 2, 3, 4, 5, 6, 7 };
-static struct clk_regmap meson8b_abp_clk_sel = {
+static u32 mux_table_apb[] = { 1, 2, 3, 4, 5, 6, 7 };
+static struct clk_regmap meson8b_apb_clk_sel = {
        .data = &(struct clk_regmap_mux_data){
                .offset = HHI_SYS_CPU_CLK_CNTL1,
                .mask = 0x7,
                .shift = 3,
-               .table = mux_table_abp,
+               .table = mux_table_apb,
        },
        .hw.init = &(struct clk_init_data){
-               .name = "abp_clk_sel",
+               .name = "apb_clk_sel",
                .ops = &clk_regmap_mux_ops,
                .parent_names = (const char *[]){ "cpu_clk_div2",
                                                  "cpu_clk_div3",
@@ -825,16 +826,16 @@ static struct clk_regmap meson8b_abp_clk_sel = {
        },
 };
 
-static struct clk_regmap meson8b_abp_clk_gate = {
+static struct clk_regmap meson8b_apb_clk_gate = {
        .data = &(struct clk_regmap_gate_data){
                .offset = HHI_SYS_CPU_CLK_CNTL1,
                .bit_idx = 16,
                .flags = CLK_GATE_SET_TO_DISABLE,
        },
        .hw.init = &(struct clk_init_data){
-               .name = "abp_clk_dis",
+               .name = "apb_clk_dis",
                .ops = &clk_regmap_gate_ro_ops,
-               .parent_names = (const char *[]){ "abp_clk_sel" },
+               .parent_names = (const char *[]){ "apb_clk_sel" },
                .num_parents = 1,
                .flags = CLK_SET_RATE_PARENT,
        },
@@ -1573,6 +1574,135 @@ static struct clk_regmap meson8b_hdmi_sys = {
        },
 };
 
+/*
+ * The MALI IP is clocked by two identical clocks (mali_0 and mali_1)
+ * muxed by a glitch-free switch on Meson8b and Meson8m2. Meson8 only
+ * has mali_0 and no glitch-free mux.
+ */
+static const char * const meson8b_mali_0_1_parent_names[] = {
+       "xtal", "mpll2", "mpll1", "fclk_div7", "fclk_div4", "fclk_div3",
+       "fclk_div5"
+};
+
+static u32 meson8b_mali_0_1_mux_table[] = { 0, 2, 3, 4, 5, 6, 7 };
+
+static struct clk_regmap meson8b_mali_0_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_MALI_CLK_CNTL,
+               .mask = 0x7,
+               .shift = 9,
+               .table = meson8b_mali_0_1_mux_table,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "mali_0_sel",
+               .ops = &clk_regmap_mux_ops,
+               .parent_names = meson8b_mali_0_1_parent_names,
+               .num_parents = ARRAY_SIZE(meson8b_mali_0_1_parent_names),
+               /*
+                * Don't propagate rate changes up because the only changeable
+                * parents are mpll1 and mpll2 but we need those for audio and
+                * RGMII (Ethernet). We don't want to change the audio or
+                * Ethernet clocks when setting the GPU frequency.
+                */
+               .flags = 0,
+       },
+};
+
+static struct clk_regmap meson8b_mali_0_div = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_MALI_CLK_CNTL,
+               .shift = 0,
+               .width = 7,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "mali_0_div",
+               .ops = &clk_regmap_divider_ops,
+               .parent_names = (const char *[]){ "mali_0_sel" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap meson8b_mali_0 = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_MALI_CLK_CNTL,
+               .bit_idx = 8,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "mali_0",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "mali_0_div" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap meson8b_mali_1_sel = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_MALI_CLK_CNTL,
+               .mask = 0x7,
+               .shift = 25,
+               .table = meson8b_mali_0_1_mux_table,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "mali_1_sel",
+               .ops = &clk_regmap_mux_ops,
+               .parent_names = meson8b_mali_0_1_parent_names,
+               .num_parents = ARRAY_SIZE(meson8b_mali_0_1_parent_names),
+               /*
+                * Don't propagate rate changes up because the only changeable
+                * parents are mpll1 and mpll2 but we need those for audio and
+                * RGMII (Ethernet). We don't want to change the audio or
+                * Ethernet clocks when setting the GPU frequency.
+                */
+               .flags = 0,
+       },
+};
+
+static struct clk_regmap meson8b_mali_1_div = {
+       .data = &(struct clk_regmap_div_data){
+               .offset = HHI_MALI_CLK_CNTL,
+               .shift = 16,
+               .width = 7,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "mali_1_div",
+               .ops = &clk_regmap_divider_ops,
+               .parent_names = (const char *[]){ "mali_1_sel" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap meson8b_mali_1 = {
+       .data = &(struct clk_regmap_gate_data){
+               .offset = HHI_MALI_CLK_CNTL,
+               .bit_idx = 24,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "mali_1",
+               .ops = &clk_regmap_gate_ops,
+               .parent_names = (const char *[]){ "mali_1_div" },
+               .num_parents = 1,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
+static struct clk_regmap meson8b_mali = {
+       .data = &(struct clk_regmap_mux_data){
+               .offset = HHI_MALI_CLK_CNTL,
+               .mask = 1,
+               .shift = 31,
+       },
+       .hw.init = &(struct clk_init_data){
+               .name = "mali",
+               .ops = &clk_regmap_mux_ops,
+               .parent_names = (const char *[]){ "mali_0", "mali_1" },
+               .num_parents = 2,
+               .flags = CLK_SET_RATE_PARENT,
+       },
+};
+
 /* Everything Else (EE) domain gates */
 
 static MESON_GATE(meson8b_ddr, HHI_GCLK_MPEG0, 0);
@@ -1659,6 +1789,188 @@ static MESON_GATE(meson8b_ao_ahb_sram, HHI_GCLK_AO, 1);
 static MESON_GATE(meson8b_ao_ahb_bus, HHI_GCLK_AO, 2);
 static MESON_GATE(meson8b_ao_iface, HHI_GCLK_AO, 3);
 
+static struct clk_hw_onecell_data meson8_hw_onecell_data = {
+       .hws = {
+               [CLKID_XTAL] = &meson8b_xtal.hw,
+               [CLKID_PLL_FIXED] = &meson8b_fixed_pll.hw,
+               [CLKID_PLL_VID] = &meson8b_vid_pll.hw,
+               [CLKID_PLL_SYS] = &meson8b_sys_pll.hw,
+               [CLKID_FCLK_DIV2] = &meson8b_fclk_div2.hw,
+               [CLKID_FCLK_DIV3] = &meson8b_fclk_div3.hw,
+               [CLKID_FCLK_DIV4] = &meson8b_fclk_div4.hw,
+               [CLKID_FCLK_DIV5] = &meson8b_fclk_div5.hw,
+               [CLKID_FCLK_DIV7] = &meson8b_fclk_div7.hw,
+               [CLKID_CPUCLK] = &meson8b_cpu_clk.hw,
+               [CLKID_MPEG_SEL] = &meson8b_mpeg_clk_sel.hw,
+               [CLKID_MPEG_DIV] = &meson8b_mpeg_clk_div.hw,
+               [CLKID_CLK81] = &meson8b_clk81.hw,
+               [CLKID_DDR]                 = &meson8b_ddr.hw,
+               [CLKID_DOS]                 = &meson8b_dos.hw,
+               [CLKID_ISA]                 = &meson8b_isa.hw,
+               [CLKID_PL301]               = &meson8b_pl301.hw,
+               [CLKID_PERIPHS]             = &meson8b_periphs.hw,
+               [CLKID_SPICC]               = &meson8b_spicc.hw,
+               [CLKID_I2C]                 = &meson8b_i2c.hw,
+               [CLKID_SAR_ADC]             = &meson8b_sar_adc.hw,
+               [CLKID_SMART_CARD]          = &meson8b_smart_card.hw,
+               [CLKID_RNG0]                = &meson8b_rng0.hw,
+               [CLKID_UART0]               = &meson8b_uart0.hw,
+               [CLKID_SDHC]                = &meson8b_sdhc.hw,
+               [CLKID_STREAM]              = &meson8b_stream.hw,
+               [CLKID_ASYNC_FIFO]          = &meson8b_async_fifo.hw,
+               [CLKID_SDIO]                = &meson8b_sdio.hw,
+               [CLKID_ABUF]                = &meson8b_abuf.hw,
+               [CLKID_HIU_IFACE]           = &meson8b_hiu_iface.hw,
+               [CLKID_ASSIST_MISC]         = &meson8b_assist_misc.hw,
+               [CLKID_SPI]                 = &meson8b_spi.hw,
+               [CLKID_I2S_SPDIF]           = &meson8b_i2s_spdif.hw,
+               [CLKID_ETH]                 = &meson8b_eth.hw,
+               [CLKID_DEMUX]               = &meson8b_demux.hw,
+               [CLKID_AIU_GLUE]            = &meson8b_aiu_glue.hw,
+               [CLKID_IEC958]              = &meson8b_iec958.hw,
+               [CLKID_I2S_OUT]             = &meson8b_i2s_out.hw,
+               [CLKID_AMCLK]               = &meson8b_amclk.hw,
+               [CLKID_AIFIFO2]             = &meson8b_aififo2.hw,
+               [CLKID_MIXER]               = &meson8b_mixer.hw,
+               [CLKID_MIXER_IFACE]         = &meson8b_mixer_iface.hw,
+               [CLKID_ADC]                 = &meson8b_adc.hw,
+               [CLKID_BLKMV]               = &meson8b_blkmv.hw,
+               [CLKID_AIU]                 = &meson8b_aiu.hw,
+               [CLKID_UART1]               = &meson8b_uart1.hw,
+               [CLKID_G2D]                 = &meson8b_g2d.hw,
+               [CLKID_USB0]                = &meson8b_usb0.hw,
+               [CLKID_USB1]                = &meson8b_usb1.hw,
+               [CLKID_RESET]               = &meson8b_reset.hw,
+               [CLKID_NAND]                = &meson8b_nand.hw,
+               [CLKID_DOS_PARSER]          = &meson8b_dos_parser.hw,
+               [CLKID_USB]                 = &meson8b_usb.hw,
+               [CLKID_VDIN1]               = &meson8b_vdin1.hw,
+               [CLKID_AHB_ARB0]            = &meson8b_ahb_arb0.hw,
+               [CLKID_EFUSE]               = &meson8b_efuse.hw,
+               [CLKID_BOOT_ROM]            = &meson8b_boot_rom.hw,
+               [CLKID_AHB_DATA_BUS]        = &meson8b_ahb_data_bus.hw,
+               [CLKID_AHB_CTRL_BUS]        = &meson8b_ahb_ctrl_bus.hw,
+               [CLKID_HDMI_INTR_SYNC]      = &meson8b_hdmi_intr_sync.hw,
+               [CLKID_HDMI_PCLK]           = &meson8b_hdmi_pclk.hw,
+               [CLKID_USB1_DDR_BRIDGE]     = &meson8b_usb1_ddr_bridge.hw,
+               [CLKID_USB0_DDR_BRIDGE]     = &meson8b_usb0_ddr_bridge.hw,
+               [CLKID_MMC_PCLK]            = &meson8b_mmc_pclk.hw,
+               [CLKID_DVIN]                = &meson8b_dvin.hw,
+               [CLKID_UART2]               = &meson8b_uart2.hw,
+               [CLKID_SANA]                = &meson8b_sana.hw,
+               [CLKID_VPU_INTR]            = &meson8b_vpu_intr.hw,
+               [CLKID_SEC_AHB_AHB3_BRIDGE] = &meson8b_sec_ahb_ahb3_bridge.hw,
+               [CLKID_CLK81_A9]            = &meson8b_clk81_a9.hw,
+               [CLKID_VCLK2_VENCI0]        = &meson8b_vclk2_venci0.hw,
+               [CLKID_VCLK2_VENCI1]        = &meson8b_vclk2_venci1.hw,
+               [CLKID_VCLK2_VENCP0]        = &meson8b_vclk2_vencp0.hw,
+               [CLKID_VCLK2_VENCP1]        = &meson8b_vclk2_vencp1.hw,
+               [CLKID_GCLK_VENCI_INT]      = &meson8b_gclk_venci_int.hw,
+               [CLKID_GCLK_VENCP_INT]      = &meson8b_gclk_vencp_int.hw,
+               [CLKID_DAC_CLK]             = &meson8b_dac_clk.hw,
+               [CLKID_AOCLK_GATE]          = &meson8b_aoclk_gate.hw,
+               [CLKID_IEC958_GATE]         = &meson8b_iec958_gate.hw,
+               [CLKID_ENC480P]             = &meson8b_enc480p.hw,
+               [CLKID_RNG1]                = &meson8b_rng1.hw,
+               [CLKID_GCLK_VENCL_INT]      = &meson8b_gclk_vencl_int.hw,
+               [CLKID_VCLK2_VENCLMCC]      = &meson8b_vclk2_venclmcc.hw,
+               [CLKID_VCLK2_VENCL]         = &meson8b_vclk2_vencl.hw,
+               [CLKID_VCLK2_OTHER]         = &meson8b_vclk2_other.hw,
+               [CLKID_EDP]                 = &meson8b_edp.hw,
+               [CLKID_AO_MEDIA_CPU]        = &meson8b_ao_media_cpu.hw,
+               [CLKID_AO_AHB_SRAM]         = &meson8b_ao_ahb_sram.hw,
+               [CLKID_AO_AHB_BUS]          = &meson8b_ao_ahb_bus.hw,
+               [CLKID_AO_IFACE]            = &meson8b_ao_iface.hw,
+               [CLKID_MPLL0]               = &meson8b_mpll0.hw,
+               [CLKID_MPLL1]               = &meson8b_mpll1.hw,
+               [CLKID_MPLL2]               = &meson8b_mpll2.hw,
+               [CLKID_MPLL0_DIV]           = &meson8b_mpll0_div.hw,
+               [CLKID_MPLL1_DIV]           = &meson8b_mpll1_div.hw,
+               [CLKID_MPLL2_DIV]           = &meson8b_mpll2_div.hw,
+               [CLKID_CPU_IN_SEL]          = &meson8b_cpu_in_sel.hw,
+               [CLKID_CPU_IN_DIV2]         = &meson8b_cpu_in_div2.hw,
+               [CLKID_CPU_IN_DIV3]         = &meson8b_cpu_in_div3.hw,
+               [CLKID_CPU_SCALE_DIV]       = &meson8b_cpu_scale_div.hw,
+               [CLKID_CPU_SCALE_OUT_SEL]   = &meson8b_cpu_scale_out_sel.hw,
+               [CLKID_MPLL_PREDIV]         = &meson8b_mpll_prediv.hw,
+               [CLKID_FCLK_DIV2_DIV]       = &meson8b_fclk_div2_div.hw,
+               [CLKID_FCLK_DIV3_DIV]       = &meson8b_fclk_div3_div.hw,
+               [CLKID_FCLK_DIV4_DIV]       = &meson8b_fclk_div4_div.hw,
+               [CLKID_FCLK_DIV5_DIV]       = &meson8b_fclk_div5_div.hw,
+               [CLKID_FCLK_DIV7_DIV]       = &meson8b_fclk_div7_div.hw,
+               [CLKID_NAND_SEL]            = &meson8b_nand_clk_sel.hw,
+               [CLKID_NAND_DIV]            = &meson8b_nand_clk_div.hw,
+               [CLKID_NAND_CLK]            = &meson8b_nand_clk_gate.hw,
+               [CLKID_PLL_FIXED_DCO]       = &meson8b_fixed_pll_dco.hw,
+               [CLKID_HDMI_PLL_DCO]        = &meson8b_hdmi_pll_dco.hw,
+               [CLKID_PLL_SYS_DCO]         = &meson8b_sys_pll_dco.hw,
+               [CLKID_CPU_CLK_DIV2]        = &meson8b_cpu_clk_div2.hw,
+               [CLKID_CPU_CLK_DIV3]        = &meson8b_cpu_clk_div3.hw,
+               [CLKID_CPU_CLK_DIV4]        = &meson8b_cpu_clk_div4.hw,
+               [CLKID_CPU_CLK_DIV5]        = &meson8b_cpu_clk_div5.hw,
+               [CLKID_CPU_CLK_DIV6]        = &meson8b_cpu_clk_div6.hw,
+               [CLKID_CPU_CLK_DIV7]        = &meson8b_cpu_clk_div7.hw,
+               [CLKID_CPU_CLK_DIV8]        = &meson8b_cpu_clk_div8.hw,
+               [CLKID_APB_SEL]             = &meson8b_apb_clk_sel.hw,
+               [CLKID_APB]                 = &meson8b_apb_clk_gate.hw,
+               [CLKID_PERIPH_SEL]          = &meson8b_periph_clk_sel.hw,
+               [CLKID_PERIPH]              = &meson8b_periph_clk_gate.hw,
+               [CLKID_AXI_SEL]             = &meson8b_axi_clk_sel.hw,
+               [CLKID_AXI]                 = &meson8b_axi_clk_gate.hw,
+               [CLKID_L2_DRAM_SEL]         = &meson8b_l2_dram_clk_sel.hw,
+               [CLKID_L2_DRAM]             = &meson8b_l2_dram_clk_gate.hw,
+               [CLKID_HDMI_PLL_LVDS_OUT]   = &meson8b_hdmi_pll_lvds_out.hw,
+               [CLKID_HDMI_PLL_HDMI_OUT]   = &meson8b_hdmi_pll_hdmi_out.hw,
+               [CLKID_VID_PLL_IN_SEL]      = &meson8b_vid_pll_in_sel.hw,
+               [CLKID_VID_PLL_IN_EN]       = &meson8b_vid_pll_in_en.hw,
+               [CLKID_VID_PLL_PRE_DIV]     = &meson8b_vid_pll_pre_div.hw,
+               [CLKID_VID_PLL_POST_DIV]    = &meson8b_vid_pll_post_div.hw,
+               [CLKID_VID_PLL_FINAL_DIV]   = &meson8b_vid_pll_final_div.hw,
+               [CLKID_VCLK_IN_SEL]         = &meson8b_vclk_in_sel.hw,
+               [CLKID_VCLK_IN_EN]          = &meson8b_vclk_in_en.hw,
+               [CLKID_VCLK_DIV1]           = &meson8b_vclk_div1_gate.hw,
+               [CLKID_VCLK_DIV2_DIV]       = &meson8b_vclk_div2_div.hw,
+               [CLKID_VCLK_DIV2]           = &meson8b_vclk_div2_div_gate.hw,
+               [CLKID_VCLK_DIV4_DIV]       = &meson8b_vclk_div4_div.hw,
+               [CLKID_VCLK_DIV4]           = &meson8b_vclk_div4_div_gate.hw,
+               [CLKID_VCLK_DIV6_DIV]       = &meson8b_vclk_div6_div.hw,
+               [CLKID_VCLK_DIV6]           = &meson8b_vclk_div6_div_gate.hw,
+               [CLKID_VCLK_DIV12_DIV]      = &meson8b_vclk_div12_div.hw,
+               [CLKID_VCLK_DIV12]          = &meson8b_vclk_div12_div_gate.hw,
+               [CLKID_VCLK2_IN_SEL]        = &meson8b_vclk2_in_sel.hw,
+               [CLKID_VCLK2_IN_EN]         = &meson8b_vclk2_clk_in_en.hw,
+               [CLKID_VCLK2_DIV1]          = &meson8b_vclk2_div1_gate.hw,
+               [CLKID_VCLK2_DIV2_DIV]      = &meson8b_vclk2_div2_div.hw,
+               [CLKID_VCLK2_DIV2]          = &meson8b_vclk2_div2_div_gate.hw,
+               [CLKID_VCLK2_DIV4_DIV]      = &meson8b_vclk2_div4_div.hw,
+               [CLKID_VCLK2_DIV4]          = &meson8b_vclk2_div4_div_gate.hw,
+               [CLKID_VCLK2_DIV6_DIV]      = &meson8b_vclk2_div6_div.hw,
+               [CLKID_VCLK2_DIV6]          = &meson8b_vclk2_div6_div_gate.hw,
+               [CLKID_VCLK2_DIV12_DIV]     = &meson8b_vclk2_div12_div.hw,
+               [CLKID_VCLK2_DIV12]         = &meson8b_vclk2_div12_div_gate.hw,
+               [CLKID_CTS_ENCT_SEL]        = &meson8b_cts_enct_sel.hw,
+               [CLKID_CTS_ENCT]            = &meson8b_cts_enct.hw,
+               [CLKID_CTS_ENCP_SEL]        = &meson8b_cts_encp_sel.hw,
+               [CLKID_CTS_ENCP]            = &meson8b_cts_encp.hw,
+               [CLKID_CTS_ENCI_SEL]        = &meson8b_cts_enci_sel.hw,
+               [CLKID_CTS_ENCI]            = &meson8b_cts_enci.hw,
+               [CLKID_HDMI_TX_PIXEL_SEL]   = &meson8b_hdmi_tx_pixel_sel.hw,
+               [CLKID_HDMI_TX_PIXEL]       = &meson8b_hdmi_tx_pixel.hw,
+               [CLKID_CTS_ENCL_SEL]        = &meson8b_cts_encl_sel.hw,
+               [CLKID_CTS_ENCL]            = &meson8b_cts_encl.hw,
+               [CLKID_CTS_VDAC0_SEL]       = &meson8b_cts_vdac0_sel.hw,
+               [CLKID_CTS_VDAC0]           = &meson8b_cts_vdac0.hw,
+               [CLKID_HDMI_SYS_SEL]        = &meson8b_hdmi_sys_sel.hw,
+               [CLKID_HDMI_SYS_DIV]        = &meson8b_hdmi_sys_div.hw,
+               [CLKID_HDMI_SYS]            = &meson8b_hdmi_sys.hw,
+               [CLKID_MALI_0_SEL]          = &meson8b_mali_0_sel.hw,
+               [CLKID_MALI_0_DIV]          = &meson8b_mali_0_div.hw,
+               [CLKID_MALI]                = &meson8b_mali_0.hw,
+               [CLK_NR_CLKS]               = NULL,
+       },
+       .num = CLK_NR_CLKS,
+};
+
 static struct clk_hw_onecell_data meson8b_hw_onecell_data = {
        .hws = {
                [CLKID_XTAL] = &meson8b_xtal.hw,
@@ -1781,8 +2093,8 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = {
                [CLKID_CPU_CLK_DIV6]        = &meson8b_cpu_clk_div6.hw,
                [CLKID_CPU_CLK_DIV7]        = &meson8b_cpu_clk_div7.hw,
                [CLKID_CPU_CLK_DIV8]        = &meson8b_cpu_clk_div8.hw,
-               [CLKID_ABP_SEL]             = &meson8b_abp_clk_sel.hw,
-               [CLKID_ABP]                 = &meson8b_abp_clk_gate.hw,
+               [CLKID_APB_SEL]             = &meson8b_apb_clk_sel.hw,
+               [CLKID_APB]                 = &meson8b_apb_clk_gate.hw,
                [CLKID_PERIPH_SEL]          = &meson8b_periph_clk_sel.hw,
                [CLKID_PERIPH]              = &meson8b_periph_clk_gate.hw,
                [CLKID_AXI_SEL]             = &meson8b_axi_clk_sel.hw,
@@ -1833,6 +2145,13 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = {
                [CLKID_HDMI_SYS_SEL]        = &meson8b_hdmi_sys_sel.hw,
                [CLKID_HDMI_SYS_DIV]        = &meson8b_hdmi_sys_div.hw,
                [CLKID_HDMI_SYS]            = &meson8b_hdmi_sys.hw,
+               [CLKID_MALI_0_SEL]          = &meson8b_mali_0_sel.hw,
+               [CLKID_MALI_0_DIV]          = &meson8b_mali_0_div.hw,
+               [CLKID_MALI_0]              = &meson8b_mali_0.hw,
+               [CLKID_MALI_1_SEL]          = &meson8b_mali_1_sel.hw,
+               [CLKID_MALI_1_DIV]          = &meson8b_mali_1_div.hw,
+               [CLKID_MALI_1]              = &meson8b_mali_1.hw,
+               [CLKID_MALI]                = &meson8b_mali.hw,
                [CLK_NR_CLKS]               = NULL,
        },
        .num = CLK_NR_CLKS,
@@ -1943,8 +2262,8 @@ static struct clk_regmap *const meson8b_clk_regmaps[] = {
        &meson8b_fixed_pll_dco,
        &meson8b_hdmi_pll_dco,
        &meson8b_sys_pll_dco,
-       &meson8b_abp_clk_sel,
-       &meson8b_abp_clk_gate,
+       &meson8b_apb_clk_sel,
+       &meson8b_apb_clk_gate,
        &meson8b_periph_clk_sel,
        &meson8b_periph_clk_gate,
        &meson8b_axi_clk_sel,
@@ -1988,6 +2307,13 @@ static struct clk_regmap *const meson8b_clk_regmaps[] = {
        &meson8b_hdmi_sys_sel,
        &meson8b_hdmi_sys_div,
        &meson8b_hdmi_sys,
+       &meson8b_mali_0_sel,
+       &meson8b_mali_0_div,
+       &meson8b_mali_0,
+       &meson8b_mali_1_sel,
+       &meson8b_mali_1_div,
+       &meson8b_mali_1,
+       &meson8b_mali,
 };
 
 static const struct meson8b_clk_reset_line {
@@ -2132,7 +2458,6 @@ static int meson8b_cpu_clk_notifier_cb(struct notifier_block *nb,
 
 static struct meson8b_nb_data meson8b_cpu_nb_data = {
        .nb.notifier_call = meson8b_cpu_clk_notifier_cb,
-       .onecell_data = &meson8b_hw_onecell_data,
 };
 
 static const struct regmap_config clkc_regmap_config = {
@@ -2141,7 +2466,8 @@ static const struct regmap_config clkc_regmap_config = {
        .reg_stride     = 4,
 };
 
-static void __init meson8b_clkc_init(struct device_node *np)
+static void __init meson8b_clkc_init_common(struct device_node *np,
+                       struct clk_hw_onecell_data *clk_hw_onecell_data)
 {
        struct meson8b_clk_reset *rstc;
        const char *notifier_clk_name;
@@ -2192,14 +2518,16 @@ static void __init meson8b_clkc_init(struct device_node *np)
         */
        for (i = CLKID_XTAL; i < CLK_NR_CLKS; i++) {
                /* array might be sparse */
-               if (!meson8b_hw_onecell_data.hws[i])
+               if (!clk_hw_onecell_data->hws[i])
                        continue;
 
-               ret = clk_hw_register(NULL, meson8b_hw_onecell_data.hws[i]);
+               ret = clk_hw_register(NULL, clk_hw_onecell_data->hws[i]);
                if (ret)
                        return;
        }
 
+       meson8b_cpu_nb_data.onecell_data = clk_hw_onecell_data;
+
        /*
         * FIXME we shouldn't program the muxes in notifier handlers. The
         * tricky programming sequence will be handled by the forthcoming
@@ -2215,13 +2543,23 @@ static void __init meson8b_clkc_init(struct device_node *np)
        }
 
        ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get,
-                                    &meson8b_hw_onecell_data);
+                                    clk_hw_onecell_data);
        if (ret)
                pr_err("%s: failed to register clock provider\n", __func__);
 }
 
+static void __init meson8_clkc_init(struct device_node *np)
+{
+       return meson8b_clkc_init_common(np, &meson8_hw_onecell_data);
+}
+
+static void __init meson8b_clkc_init(struct device_node *np)
+{
+       return meson8b_clkc_init_common(np, &meson8b_hw_onecell_data);
+}
+
 CLK_OF_DECLARE_DRIVER(meson8_clkc, "amlogic,meson8-clkc",
-                     meson8b_clkc_init);
+                     meson8_clkc_init);
 CLK_OF_DECLARE_DRIVER(meson8b_clkc, "amlogic,meson8b-clkc",
                      meson8b_clkc_init);
 CLK_OF_DECLARE_DRIVER(meson8m2_clkc, "amlogic,meson8m2-clkc",
index 87fba73..b8c58fa 100644 (file)
@@ -33,6 +33,7 @@
 #define HHI_VID_CLK_CNTL2              0x194 /* 0x65 offset in data sheet */
 #define HHI_VID_DIVIDER_CNTL           0x198 /* 0x66 offset in data sheet */
 #define HHI_SYS_CPU_CLK_CNTL0          0x19c /* 0x67 offset in data sheet */
+#define HHI_MALI_CLK_CNTL              0x1b0 /* 0x6c offset in data sheet */
 #define HHI_HDMI_CLK_CNTL              0x1cc /* 0x73 offset in data sheet */
 #define HHI_NAND_CLK_CNTL              0x25c /* 0x97 offset in data sheet */
 #define HHI_MPLL_CNTL                  0x280 /* 0xa0 offset in data sheet */
@@ -91,7 +92,7 @@
 #define CLKID_CPU_CLK_DIV6     120
 #define CLKID_CPU_CLK_DIV7     121
 #define CLKID_CPU_CLK_DIV8     122
-#define CLKID_ABP_SEL          123
+#define CLKID_APB_SEL          123
 #define CLKID_PERIPH_SEL       125
 #define CLKID_AXI_SEL          127
 #define CLKID_L2_DRAM_SEL      129
 #define CLKID_HDMI_SYS_SEL     172
 #define CLKID_HDMI_SYS_DIV     173
 #define CLKID_HDMI_SYS         174
+#define CLKID_MALI_0_SEL       175
+#define CLKID_MALI_0_DIV       176
+#define CLKID_MALI_0           177
+#define CLKID_MALI_1_SEL       178
+#define CLKID_MALI_1_DIV       179
+#define CLKID_MALI_1           180
 
-#define CLK_NR_CLKS            175
+#define CLK_NR_CLKS            181
 
 /*
  * include the CLKID and RESETID that have
diff --git a/drivers/clk/meson/parm.h b/drivers/clk/meson/parm.h
new file mode 100644 (file)
index 0000000..3c9ef1b
--- /dev/null
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2015 Endless Mobile, Inc.
+ * Author: Carlo Caione <carlo@endlessm.com>
+ */
+
+#ifndef __MESON_PARM_H
+#define __MESON_PARM_H
+
+#include <linux/bits.h>
+#include <linux/regmap.h>
+
+#define PMASK(width)                   GENMASK(width - 1, 0)
+#define SETPMASK(width, shift)         GENMASK(shift + width - 1, shift)
+#define CLRPMASK(width, shift)         (~SETPMASK(width, shift))
+
+#define PARM_GET(width, shift, reg)                                    \
+       (((reg) & SETPMASK(width, shift)) >> (shift))
+#define PARM_SET(width, shift, reg, val)                               \
+       (((reg) & CLRPMASK(width, shift)) | ((val) << (shift)))
+
+#define MESON_PARM_APPLICABLE(p)               (!!((p)->width))
+
+struct parm {
+       u16     reg_off;
+       u8      shift;
+       u8      width;
+};
+
+static inline unsigned int meson_parm_read(struct regmap *map, struct parm *p)
+{
+       unsigned int val;
+
+       regmap_read(map, p->reg_off, &val);
+       return PARM_GET(p->width, p->shift, val);
+}
+
+static inline void meson_parm_write(struct regmap *map, struct parm *p,
+                                   unsigned int val)
+{
+       regmap_update_bits(map, p->reg_off, SETPMASK(p->width, p->shift),
+                          val << p->shift);
+}
+
+#endif /* __MESON_PARM_H */
+
index bc64019..3acf037 100644 (file)
  * duty_cycle = (1 + hi) / (1 + val)
  */
 
-#include "clkc-audio.h"
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+
+#include "clk-regmap.h"
+#include "sclk-div.h"
 
 static inline struct meson_sclk_div_data *
 meson_sclk_div_data(struct clk_regmap *clk)
@@ -241,3 +245,7 @@ const struct clk_ops meson_sclk_div_ops = {
        .init           = sclk_div_init,
 };
 EXPORT_SYMBOL_GPL(meson_sclk_div_ops);
+
+MODULE_DESCRIPTION("Amlogic Sample divider driver");
+MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/meson/sclk-div.h b/drivers/clk/meson/sclk-div.h
new file mode 100644 (file)
index 0000000..b64b2a3
--- /dev/null
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018 BayLibre, SAS.
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
+ */
+
+#ifndef __MESON_SCLK_DIV_H
+#define __MESON_SCLK_DIV_H
+
+#include <linux/clk-provider.h>
+#include "parm.h"
+
+struct meson_sclk_div_data {
+       struct parm div;
+       struct parm hi;
+       unsigned int cached_div;
+       struct clk_duty cached_duty;
+};
+
+extern const struct clk_ops meson_sclk_div_ops;
+
+#endif /* __MESON_SCLK_DIV_H */
index 88af0e2..08bcc01 100644 (file)
@@ -5,7 +5,10 @@
  */
 
 #include <linux/clk-provider.h>
-#include "clkc.h"
+#include <linux/module.h>
+
+#include "clk-regmap.h"
+#include "vid-pll-div.h"
 
 static inline struct meson_vid_pll_div_data *
 meson_vid_pll_div_data(struct clk_regmap *clk)
@@ -89,3 +92,8 @@ static unsigned long meson_vid_pll_div_recalc_rate(struct clk_hw *hw,
 const struct clk_ops meson_vid_pll_div_ro_ops = {
        .recalc_rate    = meson_vid_pll_div_recalc_rate,
 };
+EXPORT_SYMBOL_GPL(meson_vid_pll_div_ro_ops);
+
+MODULE_DESCRIPTION("Amlogic video pll divider driver");
+MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/meson/vid-pll-div.h b/drivers/clk/meson/vid-pll-div.h
new file mode 100644 (file)
index 0000000..c0128e3
--- /dev/null
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2019 BayLibre, SAS.
+ * Author: Jerome Brunet <jbrunet@baylibre.com>
+ */
+
+#ifndef __MESON_VID_PLL_DIV_H
+#define __MESON_VID_PLL_DIV_H
+
+#include <linux/clk-provider.h>
+#include "parm.h"
+
+struct meson_vid_pll_div_data {
+       struct parm val;
+       struct parm sel;
+};
+
+extern const struct clk_ops meson_vid_pll_div_ro_ops;
+
+#endif /* __MESON_VID_PLL_DIV_H */
index 10e8525..4d92b27 100644 (file)
@@ -21,7 +21,7 @@
 
 enum clk_ids {
        /* Core Clock Outputs exported to DT */
-       LAST_DT_CORE_CLK = R8A774A1_CLK_OSC,
+       LAST_DT_CORE_CLK = R8A774A1_CLK_CANFD,
 
        /* External Input Clocks */
        CLK_EXTAL,
@@ -102,6 +102,7 @@ static const struct cpg_core_clk r8a774a1_core_clks[] __initconst = {
        DEF_FIXED("cp",         R8A774A1_CLK_CP,    CLK_EXTAL,      2, 1),
        DEF_FIXED("cpex",       R8A774A1_CLK_CPEX,  CLK_EXTAL,      2, 1),
 
+       DEF_DIV6P1("canfd",     R8A774A1_CLK_CANFD, CLK_PLL1_DIV4, 0x244),
        DEF_DIV6P1("csi0",      R8A774A1_CLK_CSI0,  CLK_PLL1_DIV4, 0x00c),
        DEF_DIV6P1("mso",       R8A774A1_CLK_MSO,   CLK_PLL1_DIV4, 0x014),
        DEF_DIV6P1("hdmi",      R8A774A1_CLK_HDMI,  CLK_PLL1_DIV4, 0x250),
@@ -191,6 +192,7 @@ static const struct mssr_mod_clk r8a774a1_mod_clks[] __initconst = {
        DEF_MOD("gpio2",                 910,   R8A774A1_CLK_S3D4),
        DEF_MOD("gpio1",                 911,   R8A774A1_CLK_S3D4),
        DEF_MOD("gpio0",                 912,   R8A774A1_CLK_S3D4),
+       DEF_MOD("can-fd",                914,   R8A774A1_CLK_S3D2),
        DEF_MOD("can-if1",               915,   R8A774A1_CLK_S3D4),
        DEF_MOD("can-if0",               916,   R8A774A1_CLK_S3D4),
        DEF_MOD("i2c6",                  918,   R8A774A1_CLK_S0D6),
index 10b9689..34e274f 100644 (file)
@@ -22,7 +22,7 @@
 
 enum clk_ids {
        /* Core Clock Outputs exported to DT */
-       LAST_DT_CORE_CLK = R8A774C0_CLK_CPEX,
+       LAST_DT_CORE_CLK = R8A774C0_CLK_CANFD,
 
        /* External Input Clocks */
        CLK_EXTAL,
@@ -33,6 +33,7 @@ enum clk_ids {
        CLK_PLL1,
        CLK_PLL3,
        CLK_PLL0D4,
+       CLK_PLL0D6,
        CLK_PLL0D8,
        CLK_PLL0D20,
        CLK_PLL0D24,
@@ -61,6 +62,7 @@ static const struct cpg_core_clk r8a774c0_core_clks[] __initconst = {
 
        DEF_FIXED(".pll0",     CLK_PLL0,           CLK_MAIN,       1, 100),
        DEF_FIXED(".pll0d4",   CLK_PLL0D4,         CLK_PLL0,       4, 1),
+       DEF_FIXED(".pll0d6",   CLK_PLL0D6,         CLK_PLL0,       6, 1),
        DEF_FIXED(".pll0d8",   CLK_PLL0D8,         CLK_PLL0,       8, 1),
        DEF_FIXED(".pll0d20",  CLK_PLL0D20,        CLK_PLL0,      20, 1),
        DEF_FIXED(".pll0d24",  CLK_PLL0D24,        CLK_PLL0,      24, 1),
@@ -112,6 +114,7 @@ static const struct cpg_core_clk r8a774c0_core_clks[] __initconst = {
        DEF_GEN3_PE("s3d2c",   R8A774C0_CLK_S3D2C, CLK_S3, 2, CLK_PE, 2),
        DEF_GEN3_PE("s3d4c",   R8A774C0_CLK_S3D4C, CLK_S3, 4, CLK_PE, 4),
 
+       DEF_DIV6P1("canfd",    R8A774C0_CLK_CANFD, CLK_PLL0D6, 0x244),
        DEF_DIV6P1("csi0",     R8A774C0_CLK_CSI0,  CLK_PLL1D2, 0x00c),
        DEF_DIV6P1("mso",      R8A774C0_CLK_MSO,   CLK_PLL1D2, 0x014),
 
@@ -119,6 +122,11 @@ static const struct cpg_core_clk r8a774c0_core_clks[] __initconst = {
 };
 
 static const struct mssr_mod_clk r8a774c0_mod_clks[] __initconst = {
+       DEF_MOD("tmu4",                  121,   R8A774C0_CLK_S0D6C),
+       DEF_MOD("tmu3",                  122,   R8A774C0_CLK_S3D2C),
+       DEF_MOD("tmu2",                  123,   R8A774C0_CLK_S3D2C),
+       DEF_MOD("tmu1",                  124,   R8A774C0_CLK_S3D2C),
+       DEF_MOD("tmu0",                  125,   R8A774C0_CLK_CP),
        DEF_MOD("scif5",                 202,   R8A774C0_CLK_S3D4C),
        DEF_MOD("scif4",                 203,   R8A774C0_CLK_S3D4C),
        DEF_MOD("scif3",                 204,   R8A774C0_CLK_S3D4C),
@@ -172,8 +180,8 @@ static const struct mssr_mod_clk r8a774c0_mod_clks[] __initconst = {
        DEF_MOD("ehci0",                 703,   R8A774C0_CLK_S3D4),
        DEF_MOD("hsusb",                 704,   R8A774C0_CLK_S3D4),
        DEF_MOD("csi40",                 716,   R8A774C0_CLK_CSI0),
-       DEF_MOD("du1",                   723,   R8A774C0_CLK_S2D1),
-       DEF_MOD("du0",                   724,   R8A774C0_CLK_S2D1),
+       DEF_MOD("du1",                   723,   R8A774C0_CLK_S1D1),
+       DEF_MOD("du0",                   724,   R8A774C0_CLK_S1D1),
        DEF_MOD("lvds",                  727,   R8A774C0_CLK_S2D1),
 
        DEF_MOD("vin5",                  806,   R8A774C0_CLK_S1D2),
@@ -187,6 +195,7 @@ static const struct mssr_mod_clk r8a774c0_mod_clks[] __initconst = {
        DEF_MOD("gpio2",                 910,   R8A774C0_CLK_S3D4),
        DEF_MOD("gpio1",                 911,   R8A774C0_CLK_S3D4),
        DEF_MOD("gpio0",                 912,   R8A774C0_CLK_S3D4),
+       DEF_MOD("can-fd",                914,   R8A774C0_CLK_S3D2),
        DEF_MOD("can-if1",               915,   R8A774C0_CLK_S3D4),
        DEF_MOD("can-if0",               916,   R8A774C0_CLK_S3D4),
        DEF_MOD("i2c6",                  918,   R8A774C0_CLK_S3D2),
index 25a3083..f9e07fc 100644 (file)
@@ -41,6 +41,7 @@ enum clk_ids {
        CLK_S2,
        CLK_S3,
        CLK_SDSRC,
+       CLK_RPCSRC,
        CLK_OCO,
 
        /* Module Clocks */
@@ -65,8 +66,14 @@ static const struct cpg_core_clk r8a77980_core_clks[] __initconst = {
        DEF_FIXED(".s2",        CLK_S2,            CLK_PLL1_DIV2,  4, 1),
        DEF_FIXED(".s3",        CLK_S3,            CLK_PLL1_DIV2,  6, 1),
        DEF_FIXED(".sdsrc",     CLK_SDSRC,         CLK_PLL1_DIV2,  2, 1),
+       DEF_BASE(".rpcsrc",     CLK_RPCSRC, CLK_TYPE_GEN3_RPCSRC, CLK_PLL1),
        DEF_RATE(".oco",        CLK_OCO,           32768),
 
+       DEF_BASE("rpc",         R8A77980_CLK_RPC, CLK_TYPE_GEN3_RPC,
+                CLK_RPCSRC),
+       DEF_BASE("rpcd2",       R8A77980_CLK_RPCD2, CLK_TYPE_GEN3_RPCD2,
+                R8A77980_CLK_RPC),
+
        /* Core Clock Outputs */
        DEF_FIXED("ztr",        R8A77980_CLK_ZTR,   CLK_PLL1_DIV2,  6, 1),
        DEF_FIXED("ztrd2",      R8A77980_CLK_ZTRD2, CLK_PLL1_DIV2, 12, 1),
@@ -164,6 +171,7 @@ static const struct mssr_mod_clk r8a77980_mod_clks[] __initconst = {
        DEF_MOD("gpio1",                 911,   R8A77980_CLK_CP),
        DEF_MOD("gpio0",                 912,   R8A77980_CLK_CP),
        DEF_MOD("can-fd",                914,   R8A77980_CLK_S3D2),
+       DEF_MOD("rpc-if",                917,   R8A77980_CLK_RPC),
        DEF_MOD("i2c4",                  927,   R8A77980_CLK_S0D6),
        DEF_MOD("i2c3",                  928,   R8A77980_CLK_S0D6),
        DEF_MOD("i2c2",                  929,   R8A77980_CLK_S3D2),
index be2ccbd..9a8071a 100644 (file)
 
 #define CPG_RCKCR_CKSEL        BIT(15) /* RCLK Clock Source Select */
 
+static spinlock_t cpg_lock;
+
+static void cpg_reg_modify(void __iomem *reg, u32 clear, u32 set)
+{
+       unsigned long flags;
+       u32 val;
+
+       spin_lock_irqsave(&cpg_lock, flags);
+       val = readl(reg);
+       val &= ~clear;
+       val |= set;
+       writel(val, reg);
+       spin_unlock_irqrestore(&cpg_lock, flags);
+};
+
 struct cpg_simple_notifier {
        struct notifier_block nb;
        void __iomem *reg;
@@ -118,7 +133,6 @@ static int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate,
        struct cpg_z_clk *zclk = to_z_clk(hw);
        unsigned int mult;
        unsigned int i;
-       u32 val, kick;
 
        /* Factor of 2 is for fixed divider */
        mult = DIV_ROUND_CLOSEST_ULL(rate * 32ULL * 2, parent_rate);
@@ -127,17 +141,14 @@ static int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate,
        if (readl(zclk->kick_reg) & CPG_FRQCRB_KICK)
                return -EBUSY;
 
-       val = readl(zclk->reg) & ~zclk->mask;
-       val |= ((32 - mult) << __ffs(zclk->mask)) & zclk->mask;
-       writel(val, zclk->reg);
+       cpg_reg_modify(zclk->reg, zclk->mask,
+                      ((32 - mult) << __ffs(zclk->mask)) & zclk->mask);
 
        /*
         * Set KICK bit in FRQCRB to update hardware setting and wait for
         * clock change completion.
         */
-       kick = readl(zclk->kick_reg);
-       kick |= CPG_FRQCRB_KICK;
-       writel(kick, zclk->kick_reg);
+       cpg_reg_modify(zclk->kick_reg, 0, CPG_FRQCRB_KICK);
 
        /*
         * Note: There is no HW information about the worst case latency.
@@ -266,12 +277,10 @@ static const struct sd_div_table cpg_sd_div_table[] = {
 static int cpg_sd_clock_enable(struct clk_hw *hw)
 {
        struct sd_clock *clock = to_sd_clock(hw);
-       u32 val = readl(clock->csn.reg);
-
-       val &= ~(CPG_SD_STP_MASK);
-       val |= clock->div_table[clock->cur_div_idx].val & CPG_SD_STP_MASK;
 
-       writel(val, clock->csn.reg);
+       cpg_reg_modify(clock->csn.reg, CPG_SD_STP_MASK,
+                      clock->div_table[clock->cur_div_idx].val &
+                      CPG_SD_STP_MASK);
 
        return 0;
 }
@@ -280,7 +289,7 @@ static void cpg_sd_clock_disable(struct clk_hw *hw)
 {
        struct sd_clock *clock = to_sd_clock(hw);
 
-       writel(readl(clock->csn.reg) | CPG_SD_STP_MASK, clock->csn.reg);
+       cpg_reg_modify(clock->csn.reg, 0, CPG_SD_STP_MASK);
 }
 
 static int cpg_sd_clock_is_enabled(struct clk_hw *hw)
@@ -327,7 +336,6 @@ static int cpg_sd_clock_set_rate(struct clk_hw *hw, unsigned long rate,
 {
        struct sd_clock *clock = to_sd_clock(hw);
        unsigned int div = cpg_sd_clock_calc_div(clock, rate, parent_rate);
-       u32 val;
        unsigned int i;
 
        for (i = 0; i < clock->div_num; i++)
@@ -339,10 +347,9 @@ static int cpg_sd_clock_set_rate(struct clk_hw *hw, unsigned long rate,
 
        clock->cur_div_idx = i;
 
-       val = readl(clock->csn.reg);
-       val &= ~(CPG_SD_STP_MASK | CPG_SD_FC_MASK);
-       val |= clock->div_table[i].val & (CPG_SD_STP_MASK | CPG_SD_FC_MASK);
-       writel(val, clock->csn.reg);
+       cpg_reg_modify(clock->csn.reg, CPG_SD_STP_MASK | CPG_SD_FC_MASK,
+                      clock->div_table[i].val &
+                      (CPG_SD_STP_MASK | CPG_SD_FC_MASK));
 
        return 0;
 }
@@ -415,6 +422,92 @@ free_clock:
        return clk;
 }
 
+struct rpc_clock {
+       struct clk_divider div;
+       struct clk_gate gate;
+       /*
+        * One notifier covers both RPC and RPCD2 clocks as they are both
+        * controlled by the same RPCCKCR register...
+        */
+       struct cpg_simple_notifier csn;
+};
+
+static const struct clk_div_table cpg_rpcsrc_div_table[] = {
+       { 2, 5 }, { 3, 6 }, { 0, 0 },
+};
+
+static const struct clk_div_table cpg_rpc_div_table[] = {
+       { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 }, { 0, 0 },
+};
+
+static struct clk * __init cpg_rpc_clk_register(const char *name,
+       void __iomem *base, const char *parent_name,
+       struct raw_notifier_head *notifiers)
+{
+       struct rpc_clock *rpc;
+       struct clk *clk;
+
+       rpc = kzalloc(sizeof(*rpc), GFP_KERNEL);
+       if (!rpc)
+               return ERR_PTR(-ENOMEM);
+
+       rpc->div.reg = base + CPG_RPCCKCR;
+       rpc->div.width = 3;
+       rpc->div.table = cpg_rpc_div_table;
+       rpc->div.lock = &cpg_lock;
+
+       rpc->gate.reg = base + CPG_RPCCKCR;
+       rpc->gate.bit_idx = 8;
+       rpc->gate.flags = CLK_GATE_SET_TO_DISABLE;
+       rpc->gate.lock = &cpg_lock;
+
+       rpc->csn.reg = base + CPG_RPCCKCR;
+
+       clk = clk_register_composite(NULL, name, &parent_name, 1, NULL, NULL,
+                                    &rpc->div.hw,  &clk_divider_ops,
+                                    &rpc->gate.hw, &clk_gate_ops, 0);
+       if (IS_ERR(clk)) {
+               kfree(rpc);
+               return clk;
+       }
+
+       cpg_simple_notifier_register(notifiers, &rpc->csn);
+       return clk;
+}
+
+struct rpcd2_clock {
+       struct clk_fixed_factor fixed;
+       struct clk_gate gate;
+};
+
+static struct clk * __init cpg_rpcd2_clk_register(const char *name,
+                                                 void __iomem *base,
+                                                 const char *parent_name)
+{
+       struct rpcd2_clock *rpcd2;
+       struct clk *clk;
+
+       rpcd2 = kzalloc(sizeof(*rpcd2), GFP_KERNEL);
+       if (!rpcd2)
+               return ERR_PTR(-ENOMEM);
+
+       rpcd2->fixed.mult = 1;
+       rpcd2->fixed.div = 2;
+
+       rpcd2->gate.reg = base + CPG_RPCCKCR;
+       rpcd2->gate.bit_idx = 9;
+       rpcd2->gate.flags = CLK_GATE_SET_TO_DISABLE;
+       rpcd2->gate.lock = &cpg_lock;
+
+       clk = clk_register_composite(NULL, name, &parent_name, 1, NULL, NULL,
+                                    &rpcd2->fixed.hw, &clk_fixed_factor_ops,
+                                    &rpcd2->gate.hw, &clk_gate_ops, 0);
+       if (IS_ERR(clk))
+               kfree(rpcd2);
+
+       return clk;
+}
+
 
 static const struct rcar_gen3_cpg_pll_config *cpg_pll_config __initdata;
 static unsigned int cpg_clk_extalr __initdata;
@@ -593,6 +686,21 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev,
                }
                break;
 
+       case CLK_TYPE_GEN3_RPCSRC:
+               return clk_register_divider_table(NULL, core->name,
+                                                 __clk_get_name(parent), 0,
+                                                 base + CPG_RPCCKCR, 3, 2, 0,
+                                                 cpg_rpcsrc_div_table,
+                                                 &cpg_lock);
+
+       case CLK_TYPE_GEN3_RPC:
+               return cpg_rpc_clk_register(core->name, base,
+                                           __clk_get_name(parent), notifiers);
+
+       case CLK_TYPE_GEN3_RPCD2:
+               return cpg_rpcd2_clk_register(core->name, base,
+                                             __clk_get_name(parent));
+
        default:
                return ERR_PTR(-EINVAL);
        }
@@ -613,5 +721,8 @@ int __init rcar_gen3_cpg_init(const struct rcar_gen3_cpg_pll_config *config,
        if (attr)
                cpg_quirks = (uintptr_t)attr->data;
        pr_debug("%s: mode = 0x%x quirks = 0x%x\n", __func__, mode, cpg_quirks);
+
+       spin_lock_init(&cpg_lock);
+
        return 0;
 }
index f4fb6cf..eac1b05 100644 (file)
@@ -23,6 +23,9 @@ enum rcar_gen3_clk_types {
        CLK_TYPE_GEN3_Z2,
        CLK_TYPE_GEN3_OSC,      /* OSC EXTAL predivider and fixed divider */
        CLK_TYPE_GEN3_RCKSEL,   /* Select parent/divider using RCKCR.CKSEL */
+       CLK_TYPE_GEN3_RPCSRC,
+       CLK_TYPE_GEN3_RPC,
+       CLK_TYPE_GEN3_RPCD2,
 
        /* SoC specific definitions start here */
        CLK_TYPE_GEN3_SOC_BASE,
@@ -57,6 +60,7 @@ struct rcar_gen3_cpg_pll_config {
        u8 osc_prediv;
 };
 
+#define CPG_RPCCKCR    0x238
 #define CPG_RCKCR      0x240
 
 struct clk *rcar_gen3_cpg_clk_register(struct device *dev,
index a4fa294..4b5f8f4 100644 (file)
@@ -144,7 +144,7 @@ static SUNXI_CCU_NKM_WITH_GATE_LOCK(pll_mipi_clk, "pll-mipi",
                                    8, 4,               /* N */
                                    4, 2,               /* K */
                                    0, 4,               /* M */
-                                   BIT(31),            /* gate */
+                                   BIT(31) | BIT(23) | BIT(22), /* gate */
                                    BIT(28),            /* lock */
                                    CLK_SET_RATE_UNGATE);
 
index 3a0996f..25d4b97 100644 (file)
@@ -52,7 +52,8 @@ static int st_clk_probe(struct platform_device *pdev)
                0, st_data->base + MISCCLKCNTL1, OSCCLKENB,
                CLK_GATE_SET_TO_DISABLE, NULL);
 
-       clk_hw_register_clkdev(hws[ST_CLK_GATE], "oscout1", NULL);
+       devm_clk_hw_register_clkdev(&pdev->dev, hws[ST_CLK_GATE], "oscout1",
+                                   NULL);
 
        return 0;
 }
index 6195501..8ec4a26 100644 (file)
 #define CLKID_AO_SAR_ADC_SEL   8
 #define CLKID_AO_SAR_ADC_DIV   9
 #define CLKID_AO_SAR_ADC_CLK   10
-#define CLKID_AO_ALT_XTAL      11
+#define CLKID_AO_CTS_OSCIN     11
+#define CLKID_AO_32K_PRE       12
+#define CLKID_AO_32K_DIV       13
+#define CLKID_AO_32K_SEL       14
+#define CLKID_AO_32K           15
+#define CLKID_AO_CTS_RTC_OSCIN 16
 
 #endif
diff --git a/include/dt-bindings/clock/g12a-aoclkc.h b/include/dt-bindings/clock/g12a-aoclkc.h
new file mode 100644 (file)
index 0000000..8db01ff
--- /dev/null
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+/*
+ * Copyright (c) 2016 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * Copyright (c) 2018 Amlogic, inc.
+ * Author: Qiufang Dai <qiufang.dai@amlogic.com>
+ */
+
+#ifndef DT_BINDINGS_CLOCK_AMLOGIC_MESON_G12A_AOCLK
+#define DT_BINDINGS_CLOCK_AMLOGIC_MESON_G12A_AOCLK
+
+#define CLKID_AO_AHB           0
+#define CLKID_AO_IR_IN         1
+#define CLKID_AO_I2C_M0                2
+#define CLKID_AO_I2C_S0                3
+#define CLKID_AO_UART          4
+#define CLKID_AO_PROD_I2C      5
+#define CLKID_AO_UART2         6
+#define CLKID_AO_IR_OUT                7
+#define CLKID_AO_SAR_ADC       8
+#define CLKID_AO_MAILBOX       9
+#define CLKID_AO_M3            10
+#define CLKID_AO_AHB_SRAM      11
+#define CLKID_AO_RTI           12
+#define CLKID_AO_M4_FCLK       13
+#define CLKID_AO_M4_HCLK       14
+#define CLKID_AO_CLK81         15
+#define CLKID_AO_SAR_ADC_CLK   18
+#define CLKID_AO_32K           23
+#define CLKID_AO_CEC           27
+#define CLKID_AO_CTS_RTC_OSCIN 28
+
+#endif
diff --git a/include/dt-bindings/clock/g12a-clkc.h b/include/dt-bindings/clock/g12a-clkc.h
new file mode 100644 (file)
index 0000000..83b6570
--- /dev/null
@@ -0,0 +1,135 @@
+/* SPDX-License-Identifier: GPL-2.0+ OR MIT */
+/*
+ * Meson-G12A clock tree IDs
+ *
+ * Copyright (c) 2018 Amlogic, Inc. All rights reserved.
+ */
+
+#ifndef __G12A_CLKC_H
+#define __G12A_CLKC_H
+
+#define CLKID_SYS_PLL                          0
+#define CLKID_FIXED_PLL                                1
+#define CLKID_FCLK_DIV2                                2
+#define CLKID_FCLK_DIV3                                3
+#define CLKID_FCLK_DIV4                                4
+#define CLKID_FCLK_DIV5                                5
+#define CLKID_FCLK_DIV7                                6
+#define CLKID_GP0_PLL                          7
+#define CLKID_CLK81                            10
+#define CLKID_MPLL0                            11
+#define CLKID_MPLL1                            12
+#define CLKID_MPLL2                            13
+#define CLKID_MPLL3                            14
+#define CLKID_DDR                              15
+#define CLKID_DOS                              16
+#define CLKID_AUDIO_LOCKER                     17
+#define CLKID_MIPI_DSI_HOST                    18
+#define CLKID_ETH_PHY                          19
+#define CLKID_ISA                              20
+#define CLKID_PL301                            21
+#define CLKID_PERIPHS                          22
+#define CLKID_SPICC0                           23
+#define CLKID_I2C                              24
+#define CLKID_SANA                             25
+#define CLKID_SD                               26
+#define CLKID_RNG0                             27
+#define CLKID_UART0                            28
+#define CLKID_SPICC1                           29
+#define CLKID_HIU_IFACE                                30
+#define CLKID_MIPI_DSI_PHY                     31
+#define CLKID_ASSIST_MISC                      32
+#define CLKID_SD_EMMC_A                                33
+#define CLKID_SD_EMMC_B                                34
+#define CLKID_SD_EMMC_C                                35
+#define CLKID_AUDIO_CODEC                      36
+#define CLKID_AUDIO                            37
+#define CLKID_ETH                              38
+#define CLKID_DEMUX                            39
+#define CLKID_AUDIO_IFIFO                      40
+#define CLKID_ADC                              41
+#define CLKID_UART1                            42
+#define CLKID_G2D                              43
+#define CLKID_RESET                            44
+#define CLKID_PCIE_COMB                                45
+#define CLKID_PARSER                           46
+#define CLKID_USB                              47
+#define CLKID_PCIE_PHY                         48
+#define CLKID_AHB_ARB0                         49
+#define CLKID_AHB_DATA_BUS                     50
+#define CLKID_AHB_CTRL_BUS                     51
+#define CLKID_HTX_HDCP22                       52
+#define CLKID_HTX_PCLK                         53
+#define CLKID_BT656                            54
+#define CLKID_USB1_DDR_BRIDGE                  55
+#define CLKID_MMC_PCLK                         56
+#define CLKID_UART2                            57
+#define CLKID_VPU_INTR                         58
+#define CLKID_GIC                              59
+#define CLKID_SD_EMMC_A_CLK0                   60
+#define CLKID_SD_EMMC_B_CLK0                   61
+#define CLKID_SD_EMMC_C_CLK0                   62
+#define CLKID_HIFI_PLL                         74
+#define CLKID_VCLK2_VENCI0                     80
+#define CLKID_VCLK2_VENCI1                     81
+#define CLKID_VCLK2_VENCP0                     82
+#define CLKID_VCLK2_VENCP1                     83
+#define CLKID_VCLK2_VENCT0                     84
+#define CLKID_VCLK2_VENCT1                     85
+#define CLKID_VCLK2_OTHER                      86
+#define CLKID_VCLK2_ENCI                       87
+#define CLKID_VCLK2_ENCP                       88
+#define CLKID_DAC_CLK                          89
+#define CLKID_AOCLK                            90
+#define CLKID_IEC958                           91
+#define CLKID_ENC480P                          92
+#define CLKID_RNG1                             93
+#define CLKID_VCLK2_ENCT                       94
+#define CLKID_VCLK2_ENCL                       95
+#define CLKID_VCLK2_VENCLMMC                   96
+#define CLKID_VCLK2_VENCL                      97
+#define CLKID_VCLK2_OTHER1                     98
+#define CLKID_FCLK_DIV2P5                      99
+#define CLKID_DMA                              105
+#define CLKID_EFUSE                            106
+#define CLKID_ROM_BOOT                         107
+#define CLKID_RESET_SEC                                108
+#define CLKID_SEC_AHB_APB3                     109
+#define CLKID_VPU_0_SEL                                110
+#define CLKID_VPU_0                            112
+#define CLKID_VPU_1_SEL                                113
+#define CLKID_VPU_1                            115
+#define CLKID_VPU                              116
+#define CLKID_VAPB_0_SEL                       117
+#define CLKID_VAPB_0                           119
+#define CLKID_VAPB_1_SEL                       120
+#define CLKID_VAPB_1                           122
+#define CLKID_VAPB_SEL                         123
+#define CLKID_VAPB                             124
+#define CLKID_HDMI_PLL                         128
+#define CLKID_VID_PLL                          129
+#define CLKID_VCLK                             138
+#define CLKID_VCLK2                            139
+#define CLKID_VCLK_DIV1                                148
+#define CLKID_VCLK_DIV2                                149
+#define CLKID_VCLK_DIV4                                150
+#define CLKID_VCLK_DIV6                                151
+#define CLKID_VCLK_DIV12                       152
+#define CLKID_VCLK2_DIV1                       153
+#define CLKID_VCLK2_DIV2                       154
+#define CLKID_VCLK2_DIV4                       155
+#define CLKID_VCLK2_DIV6                       156
+#define CLKID_VCLK2_DIV12                      157
+#define CLKID_CTS_ENCI                         162
+#define CLKID_CTS_ENCP                         163
+#define CLKID_CTS_VDAC                         164
+#define CLKID_HDMI_TX                          165
+#define CLKID_HDMI                             168
+#define CLKID_MALI_0_SEL                       169
+#define CLKID_MALI_0                           171
+#define CLKID_MALI_1_SEL                       172
+#define CLKID_MALI_1                           174
+#define CLKID_MALI                             175
+#define CLKID_MPLL_5OM                         177
+
+#endif /* __G12A_CLKC_H */
index 9d15e22..ec3b263 100644 (file)
 #define CLKID_AO_UART2         4
 #define CLKID_AO_IR_BLASTER    5
 #define CLKID_AO_CEC_32K       6
+#define CLKID_AO_CTS_OSCIN     7
+#define CLKID_AO_32K_PRE       8
+#define CLKID_AO_32K_DIV       9
+#define CLKID_AO_32K_SEL       10
+#define CLKID_AO_32K           11
+#define CLKID_AO_CTS_RTC_OSCIN 12
+#define CLKID_AO_CLK81         13
 
 #endif
index 5fe2923..8067077 100644 (file)
 #define CLKID_MPLL2            95
 #define CLKID_NAND_CLK         112
 #define CLKID_ABP              124
+#define CLKID_APB              124
 #define CLKID_PERIPH           126
 #define CLKID_AXI              128
 #define CLKID_L2_DRAM          130
index 9bc5d45..e355363 100644 (file)
@@ -54,5 +54,6 @@
 #define R8A774A1_CLK_CPEX              43
 #define R8A774A1_CLK_R                 44
 #define R8A774A1_CLK_OSC               45
+#define R8A774A1_CLK_CANFD             46
 
 #endif /* __DT_BINDINGS_CLOCK_R8A774A1_CPG_MSSR_H__ */
index 8fe51b6..8ad9cd6 100644 (file)
@@ -56,5 +56,6 @@
 #define R8A774C0_CLK_CSI0              45
 #define R8A774C0_CLK_CP                        46
 #define R8A774C0_CLK_CPEX              47
+#define R8A774C0_CLK_CANFD             48
 
 #endif /* __DT_BINDINGS_CLOCK_R8A774C0_CPG_MSSR_H__ */
diff --git a/include/dt-bindings/reset/g12a-aoclkc.h b/include/dt-bindings/reset/g12a-aoclkc.h
new file mode 100644 (file)
index 0000000..bd2e233
--- /dev/null
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+/*
+ * Copyright (c) 2016 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ */
+
+#ifndef DT_BINDINGS_RESET_AMLOGIC_MESON_G12A_AOCLK
+#define DT_BINDINGS_RESET_AMLOGIC_MESON_G12A_AOCLK
+
+#define RESET_AO_IR_IN         0
+#define RESET_AO_UART          1
+#define RESET_AO_I2C_M         2
+#define RESET_AO_I2C_S         3
+#define RESET_AO_SAR_ADC       4
+#define RESET_AO_UART2         5
+#define RESET_AO_IR_OUT                6
+
+#endif
index a7773b5..d8bc1a8 100644 (file)
@@ -383,6 +383,17 @@ int __must_check devm_clk_bulk_get_all(struct device *dev,
  */
 struct clk *devm_clk_get(struct device *dev, const char *id);
 
+/**
+ * devm_clk_get_optional - lookup and obtain a managed reference to an optional
+ *                        clock producer.
+ * @dev: device for clock "consumer"
+ * @id: clock consumer ID
+ *
+ * Behaves the same as devm_clk_get() except where there is no clock producer.
+ * In this case, instead of returning -ENOENT, the function returns NULL.
+ */
+struct clk *devm_clk_get_optional(struct device *dev, const char *id);
+
 /**
  * devm_get_clk_from_child - lookup and obtain a managed reference to a
  *                          clock producer from child node.
@@ -718,6 +729,12 @@ static inline struct clk *devm_clk_get(struct device *dev, const char *id)
        return NULL;
 }
 
+static inline struct clk *devm_clk_get_optional(struct device *dev,
+                                               const char *id)
+{
+       return NULL;
+}
+
 static inline int __must_check devm_clk_bulk_get(struct device *dev, int num_clks,
                                                 struct clk_bulk_data *clks)
 {
@@ -862,6 +879,25 @@ static inline void clk_bulk_disable_unprepare(int num_clks,
        clk_bulk_unprepare(num_clks, clks);
 }
 
+/**
+ * clk_get_optional - lookup and obtain a reference to an optional clock
+ *                   producer.
+ * @dev: device for clock "consumer"
+ * @id: clock consumer ID
+ *
+ * Behaves the same as clk_get() except where there is no clock producer. In
+ * this case, instead of returning -ENOENT, the function returns NULL.
+ */
+static inline struct clk *clk_get_optional(struct device *dev, const char *id)
+{
+       struct clk *clk = clk_get(dev, id);
+
+       if (clk == ERR_PTR(-ENOENT))
+               return NULL;
+
+       return clk;
+}
+
 #if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK)
 struct clk *of_clk_get(struct device_node *np, int index);
 struct clk *of_clk_get_by_name(struct device_node *np, const char *name);
index 4890ff0..ccb32af 100644 (file)
@@ -52,4 +52,8 @@ int clk_add_alias(const char *, const char *, const char *, struct device *);
 int clk_register_clkdev(struct clk *, const char *, const char *);
 int clk_hw_register_clkdev(struct clk_hw *, const char *, const char *);
 
+int devm_clk_hw_register_clkdev(struct device *dev, struct clk_hw *hw,
+                               const char *con_id, const char *dev_id);
+void devm_clk_release_clkdev(struct device *dev, const char *con_id,
+                            const char *dev_id);
 #endif