* [PATCH 0/5] clk: sunxi-ng: Add support for A83T CCU
@ 2017-02-14 3:35 ` Chen-Yu Tsai
0 siblings, 0 replies; 38+ messages in thread
From: Chen-Yu Tsai @ 2017-02-14 3:35 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Maxime Ripard
Cc: Chen-Yu Tsai, linux-clk, linux-arm-kernel, linux-kernel
Hi everyone,
This is yet another series that adds support for the A83T CCU.
The A83T CCU has a mix of new styled (like the A80) clocks at
old (like A3x) offsets. Some differences include:
- D1/D2 style PLL clocks
- divisible audio module clocks
- new timing mode for mmc2 module clock
Patch 1 fixes the mp style clock to take into account pre-dividers
for the .set_rate and .recalc_rate callbacks.
Patch 2 makes the gate clocks support common pre-dividers. This is
used to make the HSIC 12M clock have the right clock rate.
Patch 3 adds a compatible string for the A83T CCU to the sunxi-ccu
bindings.
Patch 4 adds the driver for the A83T CCU.
Patch 5 adds the CCU device nodes, and fixes up any existing clock
phandles in the dtsi.
Let me know what you think.
Regards
ChenYu
Chen-Yu Tsai (5):
clk: sunxi-ng: mp: Adjust parent rate for pre-dividers
clk: sunxi-ng: gate: Support common pre-dividers
clk: sunxi-ng: Add compatible string for A83T CCU to bindings
clk: sunxi-ng: Add driver for A83T CCU
ARM: dts: sun8i-a83t: Add CCU device nodes
.../devicetree/bindings/clock/sunxi-ccu.txt | 1 +
arch/arm/boot/dts/sun8i-a83t.dtsi | 18 +-
drivers/clk/sunxi-ng/Kconfig | 10 +
drivers/clk/sunxi-ng/Makefile | 1 +
drivers/clk/sunxi-ng/ccu-sun8i-a83t.c | 898 +++++++++++++++++++++
drivers/clk/sunxi-ng/ccu-sun8i-a83t.h | 65 ++
drivers/clk/sunxi-ng/ccu_gate.c | 47 ++
drivers/clk/sunxi-ng/ccu_mp.c | 8 +
include/dt-bindings/clock/sun8i-a83t-ccu.h | 138 ++++
include/dt-bindings/reset/sun8i-a83t-ccu.h | 98 +++
10 files changed, 1282 insertions(+), 2 deletions(-)
create mode 100644 drivers/clk/sunxi-ng/ccu-sun8i-a83t.c
create mode 100644 drivers/clk/sunxi-ng/ccu-sun8i-a83t.h
create mode 100644 include/dt-bindings/clock/sun8i-a83t-ccu.h
create mode 100644 include/dt-bindings/reset/sun8i-a83t-ccu.h
--
2.11.0
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 0/5] clk: sunxi-ng: Add support for A83T CCU
@ 2017-02-14 3:35 ` Chen-Yu Tsai
0 siblings, 0 replies; 38+ messages in thread
From: Chen-Yu Tsai @ 2017-02-14 3:35 UTC (permalink / raw)
To: linux-arm-kernel
Hi everyone,
This is yet another series that adds support for the A83T CCU.
The A83T CCU has a mix of new styled (like the A80) clocks at
old (like A3x) offsets. Some differences include:
- D1/D2 style PLL clocks
- divisible audio module clocks
- new timing mode for mmc2 module clock
Patch 1 fixes the mp style clock to take into account pre-dividers
for the .set_rate and .recalc_rate callbacks.
Patch 2 makes the gate clocks support common pre-dividers. This is
used to make the HSIC 12M clock have the right clock rate.
Patch 3 adds a compatible string for the A83T CCU to the sunxi-ccu
bindings.
Patch 4 adds the driver for the A83T CCU.
Patch 5 adds the CCU device nodes, and fixes up any existing clock
phandles in the dtsi.
Let me know what you think.
Regards
ChenYu
Chen-Yu Tsai (5):
clk: sunxi-ng: mp: Adjust parent rate for pre-dividers
clk: sunxi-ng: gate: Support common pre-dividers
clk: sunxi-ng: Add compatible string for A83T CCU to bindings
clk: sunxi-ng: Add driver for A83T CCU
ARM: dts: sun8i-a83t: Add CCU device nodes
.../devicetree/bindings/clock/sunxi-ccu.txt | 1 +
arch/arm/boot/dts/sun8i-a83t.dtsi | 18 +-
drivers/clk/sunxi-ng/Kconfig | 10 +
drivers/clk/sunxi-ng/Makefile | 1 +
drivers/clk/sunxi-ng/ccu-sun8i-a83t.c | 898 +++++++++++++++++++++
drivers/clk/sunxi-ng/ccu-sun8i-a83t.h | 65 ++
drivers/clk/sunxi-ng/ccu_gate.c | 47 ++
drivers/clk/sunxi-ng/ccu_mp.c | 8 +
include/dt-bindings/clock/sun8i-a83t-ccu.h | 138 ++++
include/dt-bindings/reset/sun8i-a83t-ccu.h | 98 +++
10 files changed, 1282 insertions(+), 2 deletions(-)
create mode 100644 drivers/clk/sunxi-ng/ccu-sun8i-a83t.c
create mode 100644 drivers/clk/sunxi-ng/ccu-sun8i-a83t.h
create mode 100644 include/dt-bindings/clock/sun8i-a83t-ccu.h
create mode 100644 include/dt-bindings/reset/sun8i-a83t-ccu.h
--
2.11.0
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 1/5] clk: sunxi-ng: mp: Adjust parent rate for pre-dividers
2017-02-14 3:35 ` Chen-Yu Tsai
@ 2017-02-14 3:35 ` Chen-Yu Tsai
-1 siblings, 0 replies; 38+ messages in thread
From: Chen-Yu Tsai @ 2017-02-14 3:35 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Maxime Ripard
Cc: Chen-Yu Tsai, linux-clk, linux-arm-kernel, linux-kernel
The MP style clocks support an mux with pre-dividers. While the driver
correctly accounted for them in the .determine_rate callback, it did
not in the .recalc_rate and .set_rate callbacks.
This means when calculating the factors in the .set_rate callback, they
would be off by a factor of the active pre-divider. Same goes for
reading back the clock rate after it is set.
Fixes: 2ab836db5097 ("clk: sunxi-ng: Add M-P factor clock support")
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
Maybe we want to Cc stable for this one?
drivers/clk/sunxi-ng/ccu_mp.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/clk/sunxi-ng/ccu_mp.c b/drivers/clk/sunxi-ng/ccu_mp.c
index 22c2ca7a2a22..b583f186a804 100644
--- a/drivers/clk/sunxi-ng/ccu_mp.c
+++ b/drivers/clk/sunxi-ng/ccu_mp.c
@@ -85,6 +85,10 @@ static unsigned long ccu_mp_recalc_rate(struct clk_hw *hw,
unsigned int m, p;
u32 reg;
+ /* Adjust parent_rate according to pre-dividers */
+ ccu_mux_helper_adjust_parent_for_prediv(&cmp->common, &cmp->mux,
+ -1, &parent_rate);
+
reg = readl(cmp->common.base + cmp->common.reg);
m = reg >> cmp->m.shift;
@@ -117,6 +121,10 @@ static int ccu_mp_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned int m, p;
u32 reg;
+ /* Adjust parent_rate according to pre-dividers */
+ ccu_mux_helper_adjust_parent_for_prediv(&cmp->common, &cmp->mux,
+ -1, &parent_rate);
+
max_m = cmp->m.max ?: 1 << cmp->m.width;
max_p = cmp->p.max ?: 1 << ((1 << cmp->p.width) - 1);
--
2.11.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 1/5] clk: sunxi-ng: mp: Adjust parent rate for pre-dividers
@ 2017-02-14 3:35 ` Chen-Yu Tsai
0 siblings, 0 replies; 38+ messages in thread
From: Chen-Yu Tsai @ 2017-02-14 3:35 UTC (permalink / raw)
To: linux-arm-kernel
The MP style clocks support an mux with pre-dividers. While the driver
correctly accounted for them in the .determine_rate callback, it did
not in the .recalc_rate and .set_rate callbacks.
This means when calculating the factors in the .set_rate callback, they
would be off by a factor of the active pre-divider. Same goes for
reading back the clock rate after it is set.
Fixes: 2ab836db5097 ("clk: sunxi-ng: Add M-P factor clock support")
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
Maybe we want to Cc stable for this one?
drivers/clk/sunxi-ng/ccu_mp.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/clk/sunxi-ng/ccu_mp.c b/drivers/clk/sunxi-ng/ccu_mp.c
index 22c2ca7a2a22..b583f186a804 100644
--- a/drivers/clk/sunxi-ng/ccu_mp.c
+++ b/drivers/clk/sunxi-ng/ccu_mp.c
@@ -85,6 +85,10 @@ static unsigned long ccu_mp_recalc_rate(struct clk_hw *hw,
unsigned int m, p;
u32 reg;
+ /* Adjust parent_rate according to pre-dividers */
+ ccu_mux_helper_adjust_parent_for_prediv(&cmp->common, &cmp->mux,
+ -1, &parent_rate);
+
reg = readl(cmp->common.base + cmp->common.reg);
m = reg >> cmp->m.shift;
@@ -117,6 +121,10 @@ static int ccu_mp_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned int m, p;
u32 reg;
+ /* Adjust parent_rate according to pre-dividers */
+ ccu_mux_helper_adjust_parent_for_prediv(&cmp->common, &cmp->mux,
+ -1, &parent_rate);
+
max_m = cmp->m.max ?: 1 << cmp->m.width;
max_p = cmp->p.max ?: 1 << ((1 << cmp->p.width) - 1);
--
2.11.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 2/5] clk: sunxi-ng: gate: Support common pre-dividers
2017-02-14 3:35 ` Chen-Yu Tsai
@ 2017-02-14 3:35 ` Chen-Yu Tsai
-1 siblings, 0 replies; 38+ messages in thread
From: Chen-Yu Tsai @ 2017-02-14 3:35 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Maxime Ripard
Cc: Chen-Yu Tsai, linux-clk, linux-arm-kernel, linux-kernel
Some clock gates have a pre-divider between the source input and the
gate itself. A notable example is the HSIC 12 MHz clock found on the
A83T, which has the 24 MHz main oscillator as its input, and a /2
pre-divider.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
drivers/clk/sunxi-ng/ccu_gate.c | 47 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 47 insertions(+)
diff --git a/drivers/clk/sunxi-ng/ccu_gate.c b/drivers/clk/sunxi-ng/ccu_gate.c
index 8a81f9d4a89f..cd069d5da215 100644
--- a/drivers/clk/sunxi-ng/ccu_gate.c
+++ b/drivers/clk/sunxi-ng/ccu_gate.c
@@ -75,8 +75,55 @@ static int ccu_gate_is_enabled(struct clk_hw *hw)
return ccu_gate_helper_is_enabled(&cg->common, cg->enable);
}
+static unsigned long ccu_gate_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct ccu_gate *cg = hw_to_ccu_gate(hw);
+ unsigned long rate = parent_rate;
+
+ if (cg->common.features & CCU_FEATURE_ALL_PREDIV)
+ rate /= cg->common.prediv;
+
+ return rate;
+}
+
+static long ccu_gate_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct ccu_gate *cg = hw_to_ccu_gate(hw);
+ int div = 1;
+
+ if (cg->common.features & CCU_FEATURE_ALL_PREDIV)
+ div = cg->common.prediv;
+
+ if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
+ unsigned long best_parent = rate;
+
+ if (cg->common.features & CCU_FEATURE_ALL_PREDIV)
+ best_parent *= div;
+ *prate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent);
+ }
+
+ return *prate / div;
+}
+
+static int ccu_gate_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ /*
+ * We must report success but we can do so unconditionally because
+ * clk_factor_round_rate returns values that ensure this call is a
+ * nop.
+ */
+
+ return 0;
+}
+
const struct clk_ops ccu_gate_ops = {
.disable = ccu_gate_disable,
.enable = ccu_gate_enable,
.is_enabled = ccu_gate_is_enabled,
+ .round_rate = ccu_gate_round_rate,
+ .set_rate = ccu_gate_set_rate,
+ .recalc_rate = ccu_gate_recalc_rate,
};
--
2.11.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 2/5] clk: sunxi-ng: gate: Support common pre-dividers
@ 2017-02-14 3:35 ` Chen-Yu Tsai
0 siblings, 0 replies; 38+ messages in thread
From: Chen-Yu Tsai @ 2017-02-14 3:35 UTC (permalink / raw)
To: linux-arm-kernel
Some clock gates have a pre-divider between the source input and the
gate itself. A notable example is the HSIC 12 MHz clock found on the
A83T, which has the 24 MHz main oscillator as its input, and a /2
pre-divider.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
drivers/clk/sunxi-ng/ccu_gate.c | 47 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 47 insertions(+)
diff --git a/drivers/clk/sunxi-ng/ccu_gate.c b/drivers/clk/sunxi-ng/ccu_gate.c
index 8a81f9d4a89f..cd069d5da215 100644
--- a/drivers/clk/sunxi-ng/ccu_gate.c
+++ b/drivers/clk/sunxi-ng/ccu_gate.c
@@ -75,8 +75,55 @@ static int ccu_gate_is_enabled(struct clk_hw *hw)
return ccu_gate_helper_is_enabled(&cg->common, cg->enable);
}
+static unsigned long ccu_gate_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct ccu_gate *cg = hw_to_ccu_gate(hw);
+ unsigned long rate = parent_rate;
+
+ if (cg->common.features & CCU_FEATURE_ALL_PREDIV)
+ rate /= cg->common.prediv;
+
+ return rate;
+}
+
+static long ccu_gate_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct ccu_gate *cg = hw_to_ccu_gate(hw);
+ int div = 1;
+
+ if (cg->common.features & CCU_FEATURE_ALL_PREDIV)
+ div = cg->common.prediv;
+
+ if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
+ unsigned long best_parent = rate;
+
+ if (cg->common.features & CCU_FEATURE_ALL_PREDIV)
+ best_parent *= div;
+ *prate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent);
+ }
+
+ return *prate / div;
+}
+
+static int ccu_gate_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ /*
+ * We must report success but we can do so unconditionally because
+ * clk_factor_round_rate returns values that ensure this call is a
+ * nop.
+ */
+
+ return 0;
+}
+
const struct clk_ops ccu_gate_ops = {
.disable = ccu_gate_disable,
.enable = ccu_gate_enable,
.is_enabled = ccu_gate_is_enabled,
+ .round_rate = ccu_gate_round_rate,
+ .set_rate = ccu_gate_set_rate,
+ .recalc_rate = ccu_gate_recalc_rate,
};
--
2.11.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 3/5] clk: sunxi-ng: Add compatible string for A83T CCU to bindings
2017-02-14 3:35 ` Chen-Yu Tsai
@ 2017-02-14 3:35 ` Chen-Yu Tsai
-1 siblings, 0 replies; 38+ messages in thread
From: Chen-Yu Tsai @ 2017-02-14 3:35 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Maxime Ripard
Cc: Chen-Yu Tsai, linux-clk, linux-arm-kernel, linux-kernel
The A83T clock control unit is a hybrid of some new style clock designs
from the A80, and old style layout from the other Allwinner SoCs.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
Documentation/devicetree/bindings/clock/sunxi-ccu.txt | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/clock/sunxi-ccu.txt b/Documentation/devicetree/bindings/clock/sunxi-ccu.txt
index bae5668cf427..a6144f913f17 100644
--- a/Documentation/devicetree/bindings/clock/sunxi-ccu.txt
+++ b/Documentation/devicetree/bindings/clock/sunxi-ccu.txt
@@ -6,6 +6,7 @@ Required properties :
- "allwinner,sun6i-a31-ccu"
- "allwinner,sun8i-a23-ccu"
- "allwinner,sun8i-a33-ccu"
+ - "allwinner,sun8i-a83t-ccu"
- "allwinner,sun8i-h3-ccu"
- "allwinner,sun8i-v3s-ccu"
- "allwinner,sun9i-a80-ccu"
--
2.11.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 3/5] clk: sunxi-ng: Add compatible string for A83T CCU to bindings
@ 2017-02-14 3:35 ` Chen-Yu Tsai
0 siblings, 0 replies; 38+ messages in thread
From: Chen-Yu Tsai @ 2017-02-14 3:35 UTC (permalink / raw)
To: linux-arm-kernel
The A83T clock control unit is a hybrid of some new style clock designs
from the A80, and old style layout from the other Allwinner SoCs.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
Documentation/devicetree/bindings/clock/sunxi-ccu.txt | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/clock/sunxi-ccu.txt b/Documentation/devicetree/bindings/clock/sunxi-ccu.txt
index bae5668cf427..a6144f913f17 100644
--- a/Documentation/devicetree/bindings/clock/sunxi-ccu.txt
+++ b/Documentation/devicetree/bindings/clock/sunxi-ccu.txt
@@ -6,6 +6,7 @@ Required properties :
- "allwinner,sun6i-a31-ccu"
- "allwinner,sun8i-a23-ccu"
- "allwinner,sun8i-a33-ccu"
+ - "allwinner,sun8i-a83t-ccu"
- "allwinner,sun8i-h3-ccu"
- "allwinner,sun8i-v3s-ccu"
- "allwinner,sun9i-a80-ccu"
--
2.11.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 4/5] clk: sunxi-ng: Add driver for A83T CCU
2017-02-14 3:35 ` Chen-Yu Tsai
@ 2017-02-14 3:35 ` Chen-Yu Tsai
-1 siblings, 0 replies; 38+ messages in thread
From: Chen-Yu Tsai @ 2017-02-14 3:35 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Maxime Ripard
Cc: Chen-Yu Tsai, linux-clk, linux-arm-kernel, linux-kernel
The A83T clock control unit is a hybrid of some new style clock designs
from the A80, and old style layout from the other Allwinner SoCs.
The mmc2 module clock supports a new timing mode. This mode outputs the
clock at half the set rate, and moves the output and sample delays into
the mmc controller. The mmc controller must also be set to use the new
timing mode. In this patch we force the mmc2 module clock to the new
mode, and drop the output and sample phase clocks for it.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
drivers/clk/sunxi-ng/Kconfig | 10 +
drivers/clk/sunxi-ng/Makefile | 1 +
drivers/clk/sunxi-ng/ccu-sun8i-a83t.c | 898 +++++++++++++++++++++++++++++
drivers/clk/sunxi-ng/ccu-sun8i-a83t.h | 65 +++
include/dt-bindings/clock/sun8i-a83t-ccu.h | 138 +++++
include/dt-bindings/reset/sun8i-a83t-ccu.h | 98 ++++
6 files changed, 1210 insertions(+)
create mode 100644 drivers/clk/sunxi-ng/ccu-sun8i-a83t.c
create mode 100644 drivers/clk/sunxi-ng/ccu-sun8i-a83t.h
create mode 100644 include/dt-bindings/clock/sun8i-a83t-ccu.h
create mode 100644 include/dt-bindings/reset/sun8i-a83t-ccu.h
diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig
index 695bbf9ef428..55f34bedfe65 100644
--- a/drivers/clk/sunxi-ng/Kconfig
+++ b/drivers/clk/sunxi-ng/Kconfig
@@ -109,6 +109,16 @@ config SUN8I_A33_CCU
select SUNXI_CCU_PHASE
default MACH_SUN8I
+config SUN8I_A83T_CCU
+ bool "Support for the Allwinner A83T CCU"
+ select SUNXI_CCU_DIV
+ select SUNXI_CCU_GATE
+ select SUNXI_CCU_NKMP
+ select SUNXI_CCU_NM
+ select SUNXI_CCU_MP
+ select SUNXI_CCU_PHASE
+ default MACH_SUN8I
+
config SUN8I_H3_CCU
bool "Support for the Allwinner H3 CCU"
select SUNXI_CCU_DIV
diff --git a/drivers/clk/sunxi-ng/Makefile b/drivers/clk/sunxi-ng/Makefile
index 6feaac0c5600..ac381ebfd98d 100644
--- a/drivers/clk/sunxi-ng/Makefile
+++ b/drivers/clk/sunxi-ng/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_SUN5I_CCU) += ccu-sun5i.o
obj-$(CONFIG_SUN6I_A31_CCU) += ccu-sun6i-a31.o
obj-$(CONFIG_SUN8I_A23_CCU) += ccu-sun8i-a23.o
obj-$(CONFIG_SUN8I_A33_CCU) += ccu-sun8i-a33.o
+obj-$(CONFIG_SUN8I_A83T_CCU) += ccu-sun8i-a83t.o
obj-$(CONFIG_SUN8I_H3_CCU) += ccu-sun8i-h3.o
obj-$(CONFIG_SUN8I_V3S_CCU) += ccu-sun8i-v3s.o
obj-$(CONFIG_SUN9I_A80_CCU) += ccu-sun9i-a80.o
diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c
new file mode 100644
index 000000000000..b2c1da1b4322
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c
@@ -0,0 +1,898 @@
+/*
+ * Copyright (c) 2017 Chen-Yu Tsai. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+
+#include "ccu_common.h"
+#include "ccu_reset.h"
+
+#include "ccu_div.h"
+#include "ccu_gate.h"
+#include "ccu_mp.h"
+#include "ccu_nkmp.h"
+#include "ccu_nm.h"
+#include "ccu_phase.h"
+
+#include "ccu-sun8i-a83t.h"
+
+#define CCU_SUN8I_A83T_LOCK_REG 0x208
+
+static struct clk_div_table pll_cpux_p_div_table[] = {
+ { .val = 0, .div = 1 },
+ { .val = 1, .div = 4 },
+ { /* Sentinel */ },
+};
+
+/*
+ * The CPU PLLs are actually NP clocks, but P is /1 or /4, so here we
+ * use the NM clocks with a divider table for M.
+ */
+static struct ccu_nm pll_c0cpux_clk = {
+ .enable = BIT(31),
+ .lock = BIT(0),
+ .n = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 12, 0),
+ .m = _SUNXI_CCU_DIV_TABLE(16, 1, pll_cpux_p_div_table),
+ .common = {
+ .reg = 0x000,
+ .lock_reg = CCU_SUN8I_A83T_LOCK_REG,
+ .features = CCU_FEATURE_LOCK_REG,
+ .hw.init = CLK_HW_INIT("pll-c0cpux", "osc24M",
+ &ccu_nm_ops, CLK_SET_RATE_UNGATE),
+ },
+};
+
+static struct ccu_nm pll_c1cpux_clk = {
+ .enable = BIT(31),
+ .lock = BIT(1),
+ .n = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 12, 0),
+ .m = _SUNXI_CCU_DIV_TABLE(16, 1, pll_cpux_p_div_table),
+ .common = {
+ .reg = 0x004,
+ .lock_reg = CCU_SUN8I_A83T_LOCK_REG,
+ .features = CCU_FEATURE_LOCK_REG,
+ .hw.init = CLK_HW_INIT("pll-c1cpux", "osc24M",
+ &ccu_nm_ops, CLK_SET_RATE_UNGATE),
+ },
+};
+
+/*
+ * The Audio PLL has d1, d2 dividers in addition to the usual N, M
+ * factors. Since we only need 2 frequencies from this PLL: 22.5792 MHz
+ * and 24.576 MHz, ignore them for now. Enforce the default for them,
+ * which is d1 = 0, d2 = 1.
+ */
+#define SUN8I_A83T_PLL_AUDIO_REG 0x008
+
+static struct ccu_nm pll_audio_clk = {
+ .enable = BIT(31),
+ .lock = BIT(2),
+ .n = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 12, 0),
+ .m = _SUNXI_CCU_DIV_OFFSET(0, 6, 0),
+ .common = {
+ .reg = SUN8I_A83T_PLL_AUDIO_REG,
+ .lock_reg = CCU_SUN8I_A83T_LOCK_REG,
+ .features = CCU_FEATURE_LOCK_REG,
+ .hw.init = CLK_HW_INIT("pll-audio", "osc24M",
+ &ccu_nm_ops, CLK_SET_RATE_UNGATE),
+ },
+};
+
+/* Some PLLs are input * N / div1 / P. Model them as NKMP with no K */
+static struct ccu_nkmp pll_video0_clk = {
+ .enable = BIT(31),
+ .lock = BIT(3),
+ .n = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 12, 0),
+ .m = _SUNXI_CCU_DIV(16, 1), /* input divider */
+ .p = _SUNXI_CCU_DIV(0, 2), /* output divider */
+ .common = {
+ .reg = 0x010,
+ .lock_reg = CCU_SUN8I_A83T_LOCK_REG,
+ .features = CCU_FEATURE_LOCK_REG,
+ .hw.init = CLK_HW_INIT("pll-video0", "osc24M",
+ &ccu_nkmp_ops,
+ CLK_SET_RATE_UNGATE),
+ },
+};
+
+static struct ccu_nkmp pll_ve_clk = {
+ .enable = BIT(31),
+ .lock = BIT(4),
+ .n = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 12, 0),
+ .m = _SUNXI_CCU_DIV(16, 1), /* input divider */
+ .p = _SUNXI_CCU_DIV(18, 1), /* output divider */
+ .common = {
+ .reg = 0x018,
+ .lock_reg = CCU_SUN8I_A83T_LOCK_REG,
+ .features = CCU_FEATURE_LOCK_REG,
+ .hw.init = CLK_HW_INIT("pll-ve", "osc24M",
+ &ccu_nkmp_ops,
+ CLK_SET_RATE_UNGATE),
+ },
+};
+
+static struct ccu_nkmp pll_ddr_clk = {
+ .enable = BIT(31),
+ .lock = BIT(5),
+ .n = _SUNXI_CCU_MULT_MIN(8, 8, 12),
+ .m = _SUNXI_CCU_DIV(16, 1), /* input divider */
+ .p = _SUNXI_CCU_DIV(18, 1), /* output divider */
+ .common = {
+ .reg = 0x020,
+ .lock_reg = CCU_SUN8I_A83T_LOCK_REG,
+ .features = CCU_FEATURE_LOCK_REG,
+ .hw.init = CLK_HW_INIT("pll-ddr", "osc24M",
+ &ccu_nkmp_ops,
+ CLK_SET_RATE_UNGATE),
+ },
+};
+
+static struct ccu_nkmp pll_periph_clk = {
+ .enable = BIT(31),
+ .lock = BIT(6),
+ .n = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 12, 0),
+ .m = _SUNXI_CCU_DIV(16, 1), /* input divider */
+ .p = _SUNXI_CCU_DIV(18, 1), /* output divider */
+ .common = {
+ .reg = 0x028,
+ .lock_reg = CCU_SUN8I_A83T_LOCK_REG,
+ .features = CCU_FEATURE_LOCK_REG,
+ .hw.init = CLK_HW_INIT("pll-periph", "osc24M",
+ &ccu_nkmp_ops,
+ CLK_SET_RATE_UNGATE),
+ },
+};
+
+static struct ccu_nkmp pll_gpu_clk = {
+ .enable = BIT(31),
+ .lock = BIT(7),
+ .n = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 12, 0),
+ .m = _SUNXI_CCU_DIV(16, 1), /* input divider */
+ .p = _SUNXI_CCU_DIV(18, 1), /* output divider */
+ .common = {
+ .reg = 0x038,
+ .lock_reg = CCU_SUN8I_A83T_LOCK_REG,
+ .features = CCU_FEATURE_LOCK_REG,
+ .hw.init = CLK_HW_INIT("pll-gpu", "osc24M",
+ &ccu_nkmp_ops,
+ CLK_SET_RATE_UNGATE),
+ },
+};
+
+static struct ccu_nkmp pll_hsic_clk = {
+ .enable = BIT(31),
+ .lock = BIT(8),
+ .n = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 12, 0),
+ .m = _SUNXI_CCU_DIV(16, 1), /* input divider */
+ .p = _SUNXI_CCU_DIV(18, 1), /* output divider */
+ .common = {
+ .reg = 0x044,
+ .lock_reg = CCU_SUN8I_A83T_LOCK_REG,
+ .features = CCU_FEATURE_LOCK_REG,
+ .hw.init = CLK_HW_INIT("pll-hsic", "osc24M",
+ &ccu_nkmp_ops,
+ CLK_SET_RATE_UNGATE),
+ },
+};
+
+static struct ccu_nkmp pll_de_clk = {
+ .enable = BIT(31),
+ .lock = BIT(9),
+ .n = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 12, 0),
+ .m = _SUNXI_CCU_DIV(16, 1), /* input divider */
+ .p = _SUNXI_CCU_DIV(18, 1), /* output divider */
+ .common = {
+ .reg = 0x048,
+ .lock_reg = CCU_SUN8I_A83T_LOCK_REG,
+ .features = CCU_FEATURE_LOCK_REG,
+ .hw.init = CLK_HW_INIT("pll-de", "osc24M",
+ &ccu_nkmp_ops,
+ CLK_SET_RATE_UNGATE),
+ },
+};
+
+static struct ccu_nkmp pll_video1_clk = {
+ .enable = BIT(31),
+ .lock = BIT(10),
+ .n = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 12, 0),
+ .m = _SUNXI_CCU_DIV(16, 1), /* input divider */
+ .p = _SUNXI_CCU_DIV(0, 2), /* external divider p */
+ .common = {
+ .reg = 0x04c,
+ .lock_reg = CCU_SUN8I_A83T_LOCK_REG,
+ .features = CCU_FEATURE_LOCK_REG,
+ .hw.init = CLK_HW_INIT("pll-video1", "osc24M",
+ &ccu_nkmp_ops,
+ CLK_SET_RATE_UNGATE),
+ },
+};
+
+static const char * const c0cpux_parents[] = { "osc24M", "pll-c0cpux" };
+static SUNXI_CCU_MUX(c0cpux_clk, "c0cpux", c0cpux_parents,
+ 0x50, 12, 1, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
+
+static const char * const c1cpux_parents[] = { "osc24M", "pll-c1cpux" };
+static SUNXI_CCU_MUX(c1cpux_clk, "c1cpux", c1cpux_parents,
+ 0x50, 28, 1, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
+
+static SUNXI_CCU_M(axi0_clk, "axi0", "c0cpux", 0x050, 0, 2, 0);
+static SUNXI_CCU_M(axi1_clk, "axi1", "c1cpux", 0x050, 16, 2, 0);
+
+/* Use a separate clock for the pre-divider on the AHB1 PLL-PERIPH input */
+static SUNXI_CCU_M(pll_periph_ahb1_clk, "pll-periph-ahb1", "pll-periph",
+ 0x054, 6, 2, 0);
+
+static const char * const ahb1_parents[] = { "osc16M-d512", "osc24M",
+ "pll-periph-ahb1",
+ "pll-periph-ahb1" };
+static struct ccu_div ahb1_clk = {
+ .div = _SUNXI_CCU_DIV_FLAGS(4, 2, CLK_DIVIDER_POWER_OF_TWO),
+ .mux = _SUNXI_CCU_MUX(12, 2),
+ .common = {
+ .reg = 0x054,
+ .hw.init = CLK_HW_INIT_PARENTS("ahb1",
+ ahb1_parents,
+ &ccu_div_ops,
+ 0),
+ },
+};
+
+static SUNXI_CCU_M(apb1_clk, "apb1", "ahb1", 0x054, 8, 2, 0);
+
+static const char * const apb2_parents[] = { "osc16M-d512", "osc24M",
+ "pll-periph", "pll-periph" };
+
+static SUNXI_CCU_MP_WITH_MUX(apb2_clk, "apb2", apb2_parents, 0x058,
+ 0, 5, /* M */
+ 16, 2, /* P */
+ 24, 2, /* mux */
+ 0);
+
+static const char * const ahb2_parents[] = { "ahb1", "pll-periph" };
+static const struct ccu_mux_fixed_prediv ahb2_prediv = {
+ .index = 1, .div = 2
+};
+static struct ccu_mux ahb2_clk = {
+ .mux = {
+ .shift = 0,
+ .width = 2,
+ .fixed_predivs = &ahb2_prediv,
+ .n_predivs = 1,
+ },
+ .common = {
+ .reg = 0x05c,
+ .hw.init = CLK_HW_INIT_PARENTS("ahb2",
+ ahb2_parents,
+ &ccu_mux_ops,
+ 0),
+ },
+};
+
+static SUNXI_CCU_GATE(bus_mipi_dsi_clk, "bus-mipi-dsi", "ahb1",
+ 0x060, BIT(1), 0);
+static SUNXI_CCU_GATE(bus_ss_clk, "bus-ss", "ahb1",
+ 0x060, BIT(5), 0);
+static SUNXI_CCU_GATE(bus_dma_clk, "bus-dma", "ahb1",
+ 0x060, BIT(6), 0);
+static SUNXI_CCU_GATE(bus_mmc0_clk, "bus-mmc0", "ahb1",
+ 0x060, BIT(8), 0);
+static SUNXI_CCU_GATE(bus_mmc1_clk, "bus-mmc1", "ahb1",
+ 0x060, BIT(9), 0);
+static SUNXI_CCU_GATE(bus_mmc2_clk, "bus-mmc2", "ahb1",
+ 0x060, BIT(10), 0);
+static SUNXI_CCU_GATE(bus_nand_clk, "bus-nand", "ahb1",
+ 0x060, BIT(13), 0);
+static SUNXI_CCU_GATE(bus_dram_clk, "bus-dram", "ahb1",
+ 0x060, BIT(14), 0);
+static SUNXI_CCU_GATE(bus_emac_clk, "bus-emac", "ahb2",
+ 0x060, BIT(17), 0);
+static SUNXI_CCU_GATE(bus_hstimer_clk, "bus-hstimer", "ahb1",
+ 0x060, BIT(19), 0);
+static SUNXI_CCU_GATE(bus_spi0_clk, "bus-spi0", "ahb1",
+ 0x060, BIT(20), 0);
+static SUNXI_CCU_GATE(bus_spi1_clk, "bus-spi1", "ahb1",
+ 0x060, BIT(21), 0);
+static SUNXI_CCU_GATE(bus_otg_clk, "bus-otg", "ahb1",
+ 0x060, BIT(24), 0);
+static SUNXI_CCU_GATE(bus_ehci0_clk, "bus-ehci0", "ahb2",
+ 0x060, BIT(26), 0);
+static SUNXI_CCU_GATE(bus_ehci1_clk, "bus-ehci1", "ahb2",
+ 0x060, BIT(27), 0);
+static SUNXI_CCU_GATE(bus_ohci0_clk, "bus-ohci0", "ahb2",
+ 0x060, BIT(29), 0);
+
+static SUNXI_CCU_GATE(bus_ve_clk, "bus-ve", "ahb1",
+ 0x064, BIT(0), 0);
+static SUNXI_CCU_GATE(bus_tcon0_clk, "bus-tcon0", "ahb1",
+ 0x064, BIT(4), 0);
+static SUNXI_CCU_GATE(bus_tcon1_clk, "bus-tcon1", "ahb1",
+ 0x064, BIT(5), 0);
+static SUNXI_CCU_GATE(bus_csi_clk, "bus-csi", "ahb1",
+ 0x064, BIT(8), 0);
+static SUNXI_CCU_GATE(bus_hdmi_clk, "bus-hdmi", "ahb1",
+ 0x064, BIT(11), 0);
+static SUNXI_CCU_GATE(bus_de_clk, "bus-de", "ahb1",
+ 0x064, BIT(12), 0);
+static SUNXI_CCU_GATE(bus_gpu_clk, "bus-gpu", "ahb1",
+ 0x064, BIT(20), 0);
+static SUNXI_CCU_GATE(bus_msgbox_clk, "bus-msgbox", "ahb1",
+ 0x064, BIT(21), 0);
+static SUNXI_CCU_GATE(bus_spinlock_clk, "bus-spinlock", "ahb1",
+ 0x064, BIT(22), 0);
+
+static SUNXI_CCU_GATE(bus_spdif_clk, "bus-spdif", "apb1",
+ 0x068, BIT(1), 0);
+static SUNXI_CCU_GATE(bus_pio_clk, "bus-pio", "apb1",
+ 0x068, BIT(5), 0);
+static SUNXI_CCU_GATE(bus_i2s0_clk, "bus-i2s0", "apb1",
+ 0x068, BIT(12), 0);
+static SUNXI_CCU_GATE(bus_i2s1_clk, "bus-i2s1", "apb1",
+ 0x068, BIT(13), 0);
+static SUNXI_CCU_GATE(bus_i2s2_clk, "bus-i2s2", "apb1",
+ 0x068, BIT(14), 0);
+static SUNXI_CCU_GATE(bus_tdm_clk, "bus-tdm", "apb1",
+ 0x068, BIT(15), 0);
+
+static SUNXI_CCU_GATE(bus_i2c0_clk, "bus-i2c0", "apb2",
+ 0x06c, BIT(0), 0);
+static SUNXI_CCU_GATE(bus_i2c1_clk, "bus-i2c1", "apb2",
+ 0x06c, BIT(0), 0);
+static SUNXI_CCU_GATE(bus_i2c2_clk, "bus-i2c2", "apb2",
+ 0x06c, BIT(0), 0);
+static SUNXI_CCU_GATE(bus_uart0_clk, "bus-uart0", "apb2",
+ 0x06c, BIT(16), 0);
+static SUNXI_CCU_GATE(bus_uart1_clk, "bus-uart1", "apb2",
+ 0x06c, BIT(17), 0);
+static SUNXI_CCU_GATE(bus_uart2_clk, "bus-uart2", "apb2",
+ 0x06c, BIT(18), 0);
+static SUNXI_CCU_GATE(bus_uart3_clk, "bus-uart3", "apb2",
+ 0x06c, BIT(19), 0);
+static SUNXI_CCU_GATE(bus_uart4_clk, "bus-uart4", "apb2",
+ 0x06c, BIT(20), 0);
+
+static const char * const cci400_parents[] = { "osc24M", "pll-periph",
+ "pll-hsic" };
+static struct ccu_div cci400_clk = {
+ .div = _SUNXI_CCU_DIV_FLAGS(0, 2, 0),
+ .mux = _SUNXI_CCU_MUX(24, 2),
+ .common = {
+ .reg = 0x078,
+ .hw.init = CLK_HW_INIT_PARENTS("cci400",
+ cci400_parents,
+ &ccu_div_ops,
+ CLK_IS_CRITICAL),
+ },
+};
+
+static const char * const mod0_default_parents[] = { "osc24M", "pll-periph" };
+
+static SUNXI_CCU_MP_WITH_MUX_GATE(nand_clk, "nand", mod0_default_parents,
+ 0x080,
+ 0, 4, /* M */
+ 16, 2, /* P */
+ 24, 2, /* mux */
+ BIT(31), /* gate */
+ 0);
+
+static SUNXI_CCU_MP_WITH_MUX_GATE(mmc0_clk, "mmc0", mod0_default_parents,
+ 0x088,
+ 0, 4, /* M */
+ 16, 2, /* P */
+ 24, 2, /* mux */
+ BIT(31), /* gate */
+ 0);
+
+static SUNXI_CCU_PHASE(mmc0_sample_clk, "mmc0-sample", "mmc0",
+ 0x088, 20, 3, 0);
+static SUNXI_CCU_PHASE(mmc0_output_clk, "mmc0-output", "mmc0",
+ 0x088, 8, 3, 0);
+
+static SUNXI_CCU_MP_WITH_MUX_GATE(mmc1_clk, "mmc1", mod0_default_parents,
+ 0x08c,
+ 0, 4, /* M */
+ 16, 2, /* P */
+ 24, 2, /* mux */
+ BIT(31), /* gate */
+ 0);
+
+static SUNXI_CCU_PHASE(mmc1_sample_clk, "mmc1-sample", "mmc1",
+ 0x08c, 20, 3, 0);
+static SUNXI_CCU_PHASE(mmc1_output_clk, "mmc1-output", "mmc1",
+ 0x08c, 8, 3, 0);
+
+/*
+ * MMC2 supports what's called the "new timing mode". The CCU and the MMC
+ * controller must be in sync about which mode is used. The new mode moves
+ * the clock delay controls (and possibly the delay lines) into the MMC
+ * block. Also, the output of the clock is divided by 2. The output and
+ * sample phase clocks are unused under this mode.
+ *
+ * This new mode seems to be preferred. Hence we force this clock to the
+ * new mode. And we don't add the phase clocks.
+ */
+#define SUN8I_A83T_MMC2_REG 0x090
+
+static struct ccu_mp mmc2_clk = {
+ .enable = BIT(31),
+ .m = _SUNXI_CCU_DIV(0, 4),
+ .p = _SUNXI_CCU_DIV(16, 2),
+ .mux = _SUNXI_CCU_MUX(24, 2),
+ .common = {
+ .reg = SUN8I_A83T_MMC2_REG,
+ .prediv = 2,
+ .features = CCU_FEATURE_ALL_PREDIV,
+ .hw.init = CLK_HW_INIT_PARENTS("mmc2",
+ mod0_default_parents,
+ &ccu_mp_ops,
+ 0)
+ }
+};
+
+static SUNXI_CCU_MP_WITH_MUX_GATE(ss_clk, "ss", mod0_default_parents,
+ 0x09c,
+ 0, 4, /* M */
+ 16, 2, /* P */
+ 24, 2, /* mux */
+ BIT(31), /* gate */
+ 0);
+
+static SUNXI_CCU_MP_WITH_MUX_GATE(spi0_clk, "spi0", mod0_default_parents,
+ 0x0a0,
+ 0, 4, /* M */
+ 16, 2, /* P */
+ 24, 4, /* mux */
+ BIT(31), /* gate */
+ 0);
+
+static SUNXI_CCU_MP_WITH_MUX_GATE(spi1_clk, "spi1", mod0_default_parents,
+ 0x0a4,
+ 0, 4, /* M */
+ 16, 2, /* P */
+ 24, 4, /* mux */
+ BIT(31), /* gate */
+ 0);
+
+static SUNXI_CCU_M_WITH_GATE(i2s0_clk, "i2s0", "pll-audio",
+ 0x0b0, 0, 4, BIT(31), CLK_SET_RATE_PARENT);
+static SUNXI_CCU_M_WITH_GATE(i2s1_clk, "i2s1", "pll-audio",
+ 0x0b4, 0, 4, BIT(31), CLK_SET_RATE_PARENT);
+static SUNXI_CCU_M_WITH_GATE(i2s2_clk, "i2s2", "pll-audio",
+ 0x0b8, 0, 4, BIT(31), CLK_SET_RATE_PARENT);
+static SUNXI_CCU_M_WITH_GATE(tdm_clk, "tdm", "pll-audio",
+ 0x0bc, 0, 4, BIT(31), CLK_SET_RATE_PARENT);
+static SUNXI_CCU_M_WITH_GATE(spdif_clk, "spdif", "pll-audio",
+ 0x0c0, 0, 4, BIT(31), CLK_SET_RATE_PARENT);
+
+static SUNXI_CCU_GATE(usb_phy0_clk, "usb-phy0", "osc24M",
+ 0x0cc, BIT(8), 0);
+static SUNXI_CCU_GATE(usb_phy1_clk, "usb-phy1", "osc24M",
+ 0x0cc, BIT(9), 0);
+static SUNXI_CCU_GATE(usb_hsic_clk, "usb-hsic", "pll-hsic",
+ 0x0cc, BIT(10), 0);
+static struct ccu_gate usb_hsic_12m_clk = {
+ .enable = BIT(11),
+ .common = {
+ .reg = 0x0cc,
+ .prediv = 2,
+ .features = CCU_FEATURE_ALL_PREDIV,
+ .hw.init = CLK_HW_INIT("usb-hsic-12m", "osc24M",
+ &ccu_gate_ops, 0),
+ }
+};
+static SUNXI_CCU_GATE(usb_ohci0_clk, "usb-ohci0", "osc24M",
+ 0x0cc, BIT(16), 0);
+
+/* TODO divider has minimum of 2 */
+static SUNXI_CCU_M(dram_clk, "dram", "pll-ddr", 0x0f4, 0, 4, CLK_IS_CRITICAL);
+
+static SUNXI_CCU_GATE(dram_ve_clk, "dram-ve", "dram",
+ 0x100, BIT(0), 0);
+static SUNXI_CCU_GATE(dram_csi_clk, "dram-csi", "dram",
+ 0x100, BIT(1), 0);
+
+static const char * const tcon0_parents[] = { "pll-video0" };
+static SUNXI_CCU_MUX_WITH_GATE(tcon0_clk, "tcon0", tcon0_parents,
+ 0x118, 24, 3, BIT(31), CLK_SET_RATE_PARENT);
+
+static const char * const tcon1_parents[] = { "pll-video1" };
+static SUNXI_CCU_MUX_WITH_GATE(tcon1_clk, "tcon1", tcon1_parents,
+ 0x11c, 24, 3, BIT(31), CLK_SET_RATE_PARENT);
+
+static SUNXI_CCU_GATE(csi_misc_clk, "csi-misc", "osc24M", 0x130, BIT(16), 0);
+
+static SUNXI_CCU_GATE(mipi_csi_clk, "mipi-csi", "osc24M", 0x130, BIT(31), 0);
+
+static const char * const csi_mclk_parents[] = { "pll-de", "osc24M" };
+static const u8 csi_mclk_table[] = { 3, 5 };
+static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(csi_mclk_clk, "csi-mclk",
+ csi_mclk_parents, csi_mclk_table,
+ 0x134,
+ 0, 5, /* M */
+ 10, 3, /* mux */
+ BIT(15), /* gate */
+ 0);
+
+static const char * const csi_sclk_parents[] = { "pll-periph", "pll-ve" };
+static const u8 csi_sclk_table[] = { 0, 5 };
+static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(csi_sclk_clk, "csi-sclk",
+ csi_sclk_parents, csi_sclk_table,
+ 0x134,
+ 16, 4, /* M */
+ 24, 3, /* mux */
+ BIT(31), /* gate */
+ 0);
+
+static SUNXI_CCU_M_WITH_GATE(ve_clk, "ve", "pll-ve", 0x13c,
+ 16, 3, BIT(31), CLK_SET_RATE_PARENT);
+
+static SUNXI_CCU_GATE(avs_clk, "avs", "osc24M", 0x144, BIT(31), 0);
+
+static const char * const hdmi_parents[] = { "pll-video1" };
+static SUNXI_CCU_M_WITH_MUX_GATE(hdmi_clk, "hdmi", hdmi_parents,
+ 0x150,
+ 0, 4, /* M */
+ 24, 2, /* mux */
+ BIT(31), /* gate */
+ CLK_SET_RATE_PARENT);
+
+static SUNXI_CCU_GATE(hdmi_slow_clk, "hdmi-slow", "osc24M", 0x154, BIT(31), 0);
+
+static const char * const mbus_parents[] = { "osc24M", "pll-periph",
+ "pll-ddr" };
+static SUNXI_CCU_M_WITH_MUX_GATE(mbus_clk, "mbus", mbus_parents,
+ 0x15c,
+ 0, 3, /* M */
+ 24, 2, /* mux */
+ BIT(31), /* gate */
+ CLK_IS_CRITICAL);
+
+static const char * const mipi_dsi0_parents[] = { "pll-video0" };
+static const u8 mipi_dsi0_table[] = { 8 };
+static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(mipi_dsi0_clk, "mipi-dsi0",
+ mipi_dsi0_parents, mipi_dsi0_table,
+ 0x168,
+ 0, 4, /* M */
+ 24, 4, /* mux */
+ BIT(31), /* gate */
+ CLK_SET_RATE_PARENT);
+
+static const char * const mipi_dsi1_parents[] = { "osc24M", "pll-video0" };
+static const u8 mipi_dsi1_table[] = { 0, 9 };
+static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(mipi_dsi1_clk, "mipi-dsi1",
+ mipi_dsi1_parents, mipi_dsi1_table,
+ 0x16c,
+ 0, 4, /* M */
+ 24, 4, /* mux */
+ BIT(31), /* gate */
+ CLK_SET_RATE_PARENT);
+
+static SUNXI_CCU_M_WITH_GATE(gpu_core_clk, "gpu-core", "pll-gpu", 0x1a0,
+ 0, 3, BIT(31), CLK_SET_RATE_PARENT);
+
+static const char * const gpu_memory_parents[] = { "pll-gpu", "pll-ddr" };
+static SUNXI_CCU_M_WITH_MUX_GATE(gpu_memory_clk, "gpu-memory",
+ gpu_memory_parents,
+ 0x1a4,
+ 0, 3, /* M */
+ 24, 1, /* mux */
+ BIT(31), /* gate */
+ CLK_SET_RATE_PARENT);
+
+static SUNXI_CCU_M_WITH_GATE(gpu_hyd_clk, "gpu-hyd", "pll-gpu", 0x1a8,
+ 0, 3, BIT(31), CLK_SET_RATE_PARENT);
+
+static struct ccu_common *sun8i_a83t_ccu_clks[] = {
+ &pll_c0cpux_clk.common,
+ &pll_c1cpux_clk.common,
+ &pll_audio_clk.common,
+ &pll_video0_clk.common,
+ &pll_ve_clk.common,
+ &pll_ddr_clk.common,
+ &pll_periph_clk.common,
+ &pll_gpu_clk.common,
+ &pll_hsic_clk.common,
+ &pll_de_clk.common,
+ &pll_video1_clk.common,
+ &c0cpux_clk.common,
+ &c1cpux_clk.common,
+ &axi0_clk.common,
+ &axi1_clk.common,
+ &pll_periph_ahb1_clk.common,
+ &ahb1_clk.common,
+ &ahb2_clk.common,
+ &apb1_clk.common,
+ &apb2_clk.common,
+ &bus_mipi_dsi_clk.common,
+ &bus_ss_clk.common,
+ &bus_dma_clk.common,
+ &bus_mmc0_clk.common,
+ &bus_mmc1_clk.common,
+ &bus_mmc2_clk.common,
+ &bus_nand_clk.common,
+ &bus_dram_clk.common,
+ &bus_emac_clk.common,
+ &bus_hstimer_clk.common,
+ &bus_spi0_clk.common,
+ &bus_spi1_clk.common,
+ &bus_otg_clk.common,
+ &bus_ehci0_clk.common,
+ &bus_ehci1_clk.common,
+ &bus_ohci0_clk.common,
+ &bus_ve_clk.common,
+ &bus_tcon0_clk.common,
+ &bus_tcon1_clk.common,
+ &bus_csi_clk.common,
+ &bus_hdmi_clk.common,
+ &bus_de_clk.common,
+ &bus_gpu_clk.common,
+ &bus_msgbox_clk.common,
+ &bus_spinlock_clk.common,
+ &bus_spdif_clk.common,
+ &bus_pio_clk.common,
+ &bus_i2s0_clk.common,
+ &bus_i2s1_clk.common,
+ &bus_i2s2_clk.common,
+ &bus_tdm_clk.common,
+ &bus_i2c0_clk.common,
+ &bus_i2c1_clk.common,
+ &bus_i2c2_clk.common,
+ &bus_uart0_clk.common,
+ &bus_uart1_clk.common,
+ &bus_uart2_clk.common,
+ &bus_uart3_clk.common,
+ &bus_uart4_clk.common,
+ &cci400_clk.common,
+ &nand_clk.common,
+ &mmc0_clk.common,
+ &mmc0_sample_clk.common,
+ &mmc0_output_clk.common,
+ &mmc1_clk.common,
+ &mmc1_sample_clk.common,
+ &mmc1_output_clk.common,
+ &mmc2_clk.common,
+ &ss_clk.common,
+ &spi0_clk.common,
+ &spi1_clk.common,
+ &i2s0_clk.common,
+ &i2s1_clk.common,
+ &i2s2_clk.common,
+ &tdm_clk.common,
+ &spdif_clk.common,
+ &usb_phy0_clk.common,
+ &usb_phy1_clk.common,
+ &usb_hsic_clk.common,
+ &usb_hsic_12m_clk.common,
+ &usb_ohci0_clk.common,
+ &dram_clk.common,
+ &dram_ve_clk.common,
+ &dram_csi_clk.common,
+ &tcon0_clk.common,
+ &tcon1_clk.common,
+ &csi_misc_clk.common,
+ &mipi_csi_clk.common,
+ &csi_mclk_clk.common,
+ &csi_sclk_clk.common,
+ &ve_clk.common,
+ &avs_clk.common,
+ &hdmi_clk.common,
+ &hdmi_slow_clk.common,
+ &mbus_clk.common,
+ &mipi_dsi0_clk.common,
+ &mipi_dsi1_clk.common,
+ &gpu_core_clk.common,
+ &gpu_memory_clk.common,
+ &gpu_hyd_clk.common,
+};
+
+static struct clk_hw_onecell_data sun8i_a83t_hw_clks = {
+ .hws = {
+ [CLK_PLL_C0CPUX] = &pll_c0cpux_clk.common.hw,
+ [CLK_PLL_C1CPUX] = &pll_c1cpux_clk.common.hw,
+ [CLK_PLL_AUDIO] = &pll_audio_clk.common.hw,
+ [CLK_PLL_VIDEO0] = &pll_video0_clk.common.hw,
+ [CLK_PLL_VE] = &pll_ve_clk.common.hw,
+ [CLK_PLL_DDR] = &pll_ddr_clk.common.hw,
+ [CLK_PLL_PERIPH] = &pll_periph_clk.common.hw,
+ [CLK_PLL_GPU] = &pll_gpu_clk.common.hw,
+ [CLK_PLL_HSIC] = &pll_hsic_clk.common.hw,
+ [CLK_PLL_DE] = &pll_de_clk.common.hw,
+ [CLK_PLL_VIDEO1] = &pll_video1_clk.common.hw,
+ [CLK_C0CPUX] = &c0cpux_clk.common.hw,
+ [CLK_C1CPUX] = &c1cpux_clk.common.hw,
+ [CLK_AXI0] = &axi0_clk.common.hw,
+ [CLK_AXI1] = &axi1_clk.common.hw,
+ [CLK_PLL_PERIPH_AHB1] = &pll_periph_ahb1_clk.common.hw,
+ [CLK_AHB1] = &ahb1_clk.common.hw,
+ [CLK_AHB2] = &ahb2_clk.common.hw,
+ [CLK_APB1] = &apb1_clk.common.hw,
+ [CLK_APB2] = &apb2_clk.common.hw,
+ [CLK_BUS_MIPI_DSI] = &bus_mipi_dsi_clk.common.hw,
+ [CLK_BUS_SS] = &bus_ss_clk.common.hw,
+ [CLK_BUS_DMA] = &bus_dma_clk.common.hw,
+ [CLK_BUS_MMC0] = &bus_mmc0_clk.common.hw,
+ [CLK_BUS_MMC1] = &bus_mmc1_clk.common.hw,
+ [CLK_BUS_MMC2] = &bus_mmc2_clk.common.hw,
+ [CLK_BUS_NAND] = &bus_nand_clk.common.hw,
+ [CLK_BUS_DRAM] = &bus_dram_clk.common.hw,
+ [CLK_BUS_EMAC] = &bus_emac_clk.common.hw,
+ [CLK_BUS_HSTIMER] = &bus_hstimer_clk.common.hw,
+ [CLK_BUS_SPI0] = &bus_spi0_clk.common.hw,
+ [CLK_BUS_SPI1] = &bus_spi1_clk.common.hw,
+ [CLK_BUS_OTG] = &bus_otg_clk.common.hw,
+ [CLK_BUS_EHCI0] = &bus_ehci0_clk.common.hw,
+ [CLK_BUS_EHCI1] = &bus_ehci1_clk.common.hw,
+ [CLK_BUS_OHCI0] = &bus_ohci0_clk.common.hw,
+ [CLK_BUS_VE] = &bus_ve_clk.common.hw,
+ [CLK_BUS_TCON0] = &bus_tcon0_clk.common.hw,
+ [CLK_BUS_TCON1] = &bus_tcon1_clk.common.hw,
+ [CLK_BUS_CSI] = &bus_csi_clk.common.hw,
+ [CLK_BUS_HDMI] = &bus_hdmi_clk.common.hw,
+ [CLK_BUS_DE] = &bus_de_clk.common.hw,
+ [CLK_BUS_GPU] = &bus_gpu_clk.common.hw,
+ [CLK_BUS_MSGBOX] = &bus_msgbox_clk.common.hw,
+ [CLK_BUS_SPINLOCK] = &bus_spinlock_clk.common.hw,
+ [CLK_BUS_SPDIF] = &bus_spdif_clk.common.hw,
+ [CLK_BUS_PIO] = &bus_pio_clk.common.hw,
+ [CLK_BUS_I2S0] = &bus_i2s0_clk.common.hw,
+ [CLK_BUS_I2S1] = &bus_i2s1_clk.common.hw,
+ [CLK_BUS_I2S2] = &bus_i2s2_clk.common.hw,
+ [CLK_BUS_TDM] = &bus_tdm_clk.common.hw,
+ [CLK_BUS_I2C0] = &bus_i2c0_clk.common.hw,
+ [CLK_BUS_I2C1] = &bus_i2c1_clk.common.hw,
+ [CLK_BUS_I2C2] = &bus_i2c2_clk.common.hw,
+ [CLK_BUS_UART0] = &bus_uart0_clk.common.hw,
+ [CLK_BUS_UART1] = &bus_uart1_clk.common.hw,
+ [CLK_BUS_UART2] = &bus_uart2_clk.common.hw,
+ [CLK_BUS_UART3] = &bus_uart3_clk.common.hw,
+ [CLK_BUS_UART4] = &bus_uart4_clk.common.hw,
+ [CLK_CCI400] = &cci400_clk.common.hw,
+ [CLK_NAND] = &nand_clk.common.hw,
+ [CLK_MMC0] = &mmc0_clk.common.hw,
+ [CLK_MMC0_SAMPLE] = &mmc0_sample_clk.common.hw,
+ [CLK_MMC0_OUTPUT] = &mmc0_output_clk.common.hw,
+ [CLK_MMC1] = &mmc1_clk.common.hw,
+ [CLK_MMC1_SAMPLE] = &mmc1_sample_clk.common.hw,
+ [CLK_MMC1_OUTPUT] = &mmc1_output_clk.common.hw,
+ [CLK_MMC2] = &mmc2_clk.common.hw,
+ [CLK_SS] = &ss_clk.common.hw,
+ [CLK_SPI0] = &spi0_clk.common.hw,
+ [CLK_SPI1] = &spi1_clk.common.hw,
+ [CLK_I2S0] = &i2s0_clk.common.hw,
+ [CLK_I2S1] = &i2s1_clk.common.hw,
+ [CLK_I2S2] = &i2s2_clk.common.hw,
+ [CLK_TDM] = &tdm_clk.common.hw,
+ [CLK_SPDIF] = &spdif_clk.common.hw,
+ [CLK_USB_PHY0] = &usb_phy0_clk.common.hw,
+ [CLK_USB_PHY1] = &usb_phy1_clk.common.hw,
+ [CLK_USB_HSIC] = &usb_hsic_clk.common.hw,
+ [CLK_USB_HSIC_12M] = &usb_hsic_12m_clk.common.hw,
+ [CLK_USB_OHCI0] = &usb_ohci0_clk.common.hw,
+ [CLK_DRAM] = &dram_clk.common.hw,
+ [CLK_DRAM_VE] = &dram_ve_clk.common.hw,
+ [CLK_DRAM_CSI] = &dram_csi_clk.common.hw,
+ [CLK_TCON0] = &tcon0_clk.common.hw,
+ [CLK_TCON1] = &tcon1_clk.common.hw,
+ [CLK_CSI_MISC] = &csi_misc_clk.common.hw,
+ [CLK_MIPI_CSI] = &mipi_csi_clk.common.hw,
+ [CLK_CSI_MCLK] = &csi_mclk_clk.common.hw,
+ [CLK_CSI_SCLK] = &csi_sclk_clk.common.hw,
+ [CLK_VE] = &ve_clk.common.hw,
+ [CLK_AVS] = &avs_clk.common.hw,
+ [CLK_HDMI] = &hdmi_clk.common.hw,
+ [CLK_HDMI_SLOW] = &hdmi_slow_clk.common.hw,
+ [CLK_MBUS] = &mbus_clk.common.hw,
+ [CLK_MIPI_DSI0] = &mipi_dsi0_clk.common.hw,
+ [CLK_MIPI_DSI1] = &mipi_dsi1_clk.common.hw,
+ [CLK_GPU_CORE] = &gpu_core_clk.common.hw,
+ [CLK_GPU_MEMORY] = &gpu_memory_clk.common.hw,
+ [CLK_GPU_HYD] = &gpu_hyd_clk.common.hw,
+ },
+ .num = CLK_NUMBER,
+};
+
+static struct ccu_reset_map sun8i_a83t_ccu_resets[] = {
+ [RST_USB_PHY0] = { 0x0cc, BIT(0) },
+ [RST_USB_PHY1] = { 0x0cc, BIT(1) },
+ [RST_USB_HSIC] = { 0x0cc, BIT(2) },
+ [RST_DRAM] = { 0x0f4, BIT(31) },
+ [RST_MBUS] = { 0x0fc, BIT(31) },
+ [RST_BUS_MIPI_DSI] = { 0x2c0, BIT(1) },
+ [RST_BUS_SS] = { 0x2c0, BIT(5) },
+ [RST_BUS_DMA] = { 0x2c0, BIT(6) },
+ [RST_BUS_MMC0] = { 0x2c0, BIT(8) },
+ [RST_BUS_MMC1] = { 0x2c0, BIT(9) },
+ [RST_BUS_MMC2] = { 0x2c0, BIT(10) },
+ [RST_BUS_NAND] = { 0x2c0, BIT(13) },
+ [RST_BUS_DRAM] = { 0x2c0, BIT(14) },
+ [RST_BUS_EMAC] = { 0x2c0, BIT(17) },
+ [RST_BUS_HSTIMER] = { 0x2c0, BIT(19) },
+ [RST_BUS_SPI0] = { 0x2c0, BIT(20) },
+ [RST_BUS_SPI1] = { 0x2c0, BIT(21) },
+ [RST_BUS_OTG] = { 0x2c0, BIT(24) },
+ [RST_BUS_EHCI0] = { 0x2c0, BIT(26) },
+ [RST_BUS_EHCI1] = { 0x2c0, BIT(27) },
+ [RST_BUS_OHCI0] = { 0x2c0, BIT(29) },
+ [RST_BUS_VE] = { 0x2c4, BIT(0) },
+ [RST_BUS_TCON0] = { 0x2c4, BIT(4) },
+ [RST_BUS_TCON1] = { 0x2c4, BIT(5) },
+ [RST_BUS_CSI] = { 0x2c4, BIT(8) },
+ [RST_BUS_HDMI0] = { 0x2c4, BIT(10) },
+ [RST_BUS_HDMI1] = { 0x2c4, BIT(11) },
+ [RST_BUS_DE] = { 0x2c4, BIT(12) },
+ [RST_BUS_GPU] = { 0x2c4, BIT(20) },
+ [RST_BUS_MSGBOX] = { 0x2c4, BIT(21) },
+ [RST_BUS_SPINLOCK] = { 0x2c4, BIT(22) },
+ [RST_BUS_LVDS] = { 0x2c8, BIT(0) },
+ [RST_BUS_SPDIF] = { 0x2d0, BIT(1) },
+ [RST_BUS_I2S0] = { 0x2d0, BIT(12) },
+ [RST_BUS_I2S1] = { 0x2d0, BIT(13) },
+ [RST_BUS_I2S2] = { 0x2d0, BIT(14) },
+ [RST_BUS_TDM] = { 0x2d0, BIT(15) },
+ [RST_BUS_I2C0] = { 0x2d8, BIT(0) },
+ [RST_BUS_I2C1] = { 0x2d8, BIT(1) },
+ [RST_BUS_I2C2] = { 0x2d8, BIT(2) },
+ [RST_BUS_UART0] = { 0x2d8, BIT(16) },
+ [RST_BUS_UART1] = { 0x2d8, BIT(17) },
+ [RST_BUS_UART2] = { 0x2d8, BIT(18) },
+ [RST_BUS_UART3] = { 0x2d8, BIT(19) },
+ [RST_BUS_UART4] = { 0x2d8, BIT(20) },
+};
+
+static const struct sunxi_ccu_desc sun8i_a83t_ccu_desc = {
+ .ccu_clks = sun8i_a83t_ccu_clks,
+ .num_ccu_clks = ARRAY_SIZE(sun8i_a83t_ccu_clks),
+
+ .hw_clks = &sun8i_a83t_hw_clks,
+
+ .resets = sun8i_a83t_ccu_resets,
+ .num_resets = ARRAY_SIZE(sun8i_a83t_ccu_resets),
+};
+
+static int sun8i_a83t_ccu_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ void __iomem *reg;
+ u32 val;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ reg = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(reg))
+ return PTR_ERR(reg);
+
+ /* Enforce d1 = 0, d2 = 0 for Audio PLL */
+ val = readl(reg + SUN8I_A83T_PLL_AUDIO_REG);
+ val &= (BIT(16) & BIT(18));
+ writel(val, reg + SUN8I_A83T_PLL_AUDIO_REG);
+
+ /* Enforce new timing mode for MMC2 */
+ val = readl(reg + SUN8I_A83T_MMC2_REG);
+ val |= BIT(30);
+ writel(val, reg + SUN8I_A83T_MMC2_REG);
+
+ return sunxi_ccu_probe(pdev->dev.of_node, reg, &sun8i_a83t_ccu_desc);
+}
+
+static const struct of_device_id sun8i_a83t_ccu_ids[] = {
+ { .compatible = "allwinner,sun8i-a83t-ccu" },
+ { }
+};
+
+static struct platform_driver sun8i_a83t_ccu_driver = {
+ .probe = sun8i_a83t_ccu_probe,
+ .driver = {
+ .name = "sun8i-a83t-ccu",
+ .of_match_table = sun8i_a83t_ccu_ids,
+ },
+};
+builtin_platform_driver(sun8i_a83t_ccu_driver);
diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.h b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.h
new file mode 100644
index 000000000000..fe7e6b347061
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2016 Chen-Yu Tsai
+ *
+ * Chen-Yu Tsai <wens@csie.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CCU_SUN8I_A83T_H_
+#define _CCU_SUN8I_A83T_H_
+
+#include <dt-bindings/clock/sun8i-a83t-ccu.h>
+#include <dt-bindings/reset/sun8i-a83t-ccu.h>
+
+#define CLK_PLL_C0CPUX 0
+#define CLK_PLL_C1CPUX 1
+#define CLK_PLL_AUDIO 2
+#define CLK_PLL_VIDEO0 3
+#define CLK_PLL_VE 4
+#define CLK_PLL_DDR 5
+
+/* pll-periph is exported to the PRCM block */
+
+#define CLK_PLL_GPU 7
+#define CLK_PLL_HSIC 8
+
+/* pll-de is exported for the display engine */
+
+#define CLK_PLL_VIDEO1 10
+
+/* The CPUX clocks are exported */
+
+#define CLK_AXI0 13
+#define CLK_AXI1 14
+#define CLK_PLL_PERIPH_AHB1 15
+#define CLK_AHB1 16
+#define CLK_AHB2 17
+#define CLK_APB1 18
+#define CLK_APB2 19
+
+/* bus gates exported */
+
+#define CLK_CCI400 59
+
+/* module and usb clocks exported */
+
+#define CLK_DRAM 81
+
+/* dram gates and more module clocks exported */
+
+#define CLK_MBUS 94
+
+/* more module clocks exported */
+
+#define CLK_NUMBER (CLK_GPU_HYD + 1)
+
+#endif /* _CCU_SUN8I_A83T_H_ */
diff --git a/include/dt-bindings/clock/sun8i-a83t-ccu.h b/include/dt-bindings/clock/sun8i-a83t-ccu.h
new file mode 100644
index 000000000000..e30c40e01dd4
--- /dev/null
+++ b/include/dt-bindings/clock/sun8i-a83t-ccu.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2017 Chen-Yu Tsai <wens@csie.org>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _DT_BINDINGS_CLOCK_SUN8I_A83T_CCU_H_
+#define _DT_BINDINGS_CLOCK_SUN8I_A83T_CCU_H_
+
+#define CLK_PLL_PERIPH 6
+
+#define CLK_PLL_DE 9
+
+#define CLK_C0CPUX 11
+#define CLK_C1CPUX 12
+
+#define CLK_BUS_MIPI_DSI 20
+#define CLK_BUS_SS 21
+#define CLK_BUS_DMA 22
+#define CLK_BUS_MMC0 23
+#define CLK_BUS_MMC1 24
+#define CLK_BUS_MMC2 25
+#define CLK_BUS_NAND 26
+#define CLK_BUS_DRAM 27
+#define CLK_BUS_EMAC 28
+#define CLK_BUS_HSTIMER 29
+#define CLK_BUS_SPI0 30
+#define CLK_BUS_SPI1 31
+#define CLK_BUS_OTG 32
+#define CLK_BUS_EHCI0 33
+#define CLK_BUS_EHCI1 34
+#define CLK_BUS_OHCI0 35
+
+#define CLK_BUS_VE 36
+#define CLK_BUS_TCON0 37
+#define CLK_BUS_TCON1 38
+#define CLK_BUS_CSI 39
+#define CLK_BUS_HDMI 40
+#define CLK_BUS_DE 41
+#define CLK_BUS_GPU 42
+#define CLK_BUS_MSGBOX 43
+#define CLK_BUS_SPINLOCK 44
+
+#define CLK_BUS_SPDIF 45
+#define CLK_BUS_PIO 46
+#define CLK_BUS_I2S0 47
+#define CLK_BUS_I2S1 48
+#define CLK_BUS_I2S2 49
+#define CLK_BUS_TDM 50
+
+#define CLK_BUS_I2C0 51
+#define CLK_BUS_I2C1 52
+#define CLK_BUS_I2C2 53
+#define CLK_BUS_UART0 54
+#define CLK_BUS_UART1 55
+#define CLK_BUS_UART2 56
+#define CLK_BUS_UART3 57
+#define CLK_BUS_UART4 58
+
+#define CLK_NAND 60
+#define CLK_MMC0 61
+#define CLK_MMC0_SAMPLE 62
+#define CLK_MMC0_OUTPUT 63
+#define CLK_MMC1 64
+#define CLK_MMC1_SAMPLE 65
+#define CLK_MMC1_OUTPUT 66
+#define CLK_MMC2 67
+#define CLK_SS 68
+#define CLK_SPI0 69
+#define CLK_SPI1 70
+#define CLK_I2S0 71
+#define CLK_I2S1 72
+#define CLK_I2S2 73
+#define CLK_TDM 74
+#define CLK_SPDIF 75
+#define CLK_USB_PHY0 76
+#define CLK_USB_PHY1 77
+#define CLK_USB_HSIC 78
+#define CLK_USB_HSIC_12M 79
+#define CLK_USB_OHCI0 80
+
+#define CLK_DRAM_VE 82
+#define CLK_DRAM_CSI 83
+
+#define CLK_TCON0 84
+#define CLK_TCON1 85
+#define CLK_CSI_MISC 86
+#define CLK_MIPI_CSI 87
+#define CLK_CSI_MCLK 88
+#define CLK_CSI_SCLK 89
+#define CLK_VE 90
+#define CLK_AVS 91
+#define CLK_HDMI 92
+#define CLK_HDMI_SLOW 93
+
+#define CLK_MIPI_DSI0 95
+#define CLK_MIPI_DSI1 96
+#define CLK_GPU_CORE 97
+#define CLK_GPU_MEMORY 98
+#define CLK_GPU_HYD 99
+
+#endif /* _DT_BINDINGS_CLOCK_SUN8I_A83T_CCU_H_ */
diff --git a/include/dt-bindings/reset/sun8i-a83t-ccu.h b/include/dt-bindings/reset/sun8i-a83t-ccu.h
new file mode 100644
index 000000000000..784f6e11664e
--- /dev/null
+++ b/include/dt-bindings/reset/sun8i-a83t-ccu.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2017 Chen-Yu Tsai <wens@csie.org>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _DT_BINDINGS_RESET_SUN8I_A83T_CCU_H_
+#define _DT_BINDINGS_RESET_SUN8I_A83T_CCU_H_
+
+#define RST_USB_PHY0 0
+#define RST_USB_PHY1 1
+#define RST_USB_HSIC 2
+
+#define RST_DRAM 3
+#define RST_MBUS 4
+
+#define RST_BUS_MIPI_DSI 5
+#define RST_BUS_SS 6
+#define RST_BUS_DMA 7
+#define RST_BUS_MMC0 8
+#define RST_BUS_MMC1 9
+#define RST_BUS_MMC2 10
+#define RST_BUS_NAND 11
+#define RST_BUS_DRAM 12
+#define RST_BUS_EMAC 13
+#define RST_BUS_HSTIMER 14
+#define RST_BUS_SPI0 15
+#define RST_BUS_SPI1 16
+#define RST_BUS_OTG 17
+#define RST_BUS_EHCI0 18
+#define RST_BUS_EHCI1 19
+#define RST_BUS_OHCI0 20
+
+#define RST_BUS_VE 21
+#define RST_BUS_TCON0 22
+#define RST_BUS_TCON1 23
+#define RST_BUS_CSI 24
+#define RST_BUS_HDMI0 25
+#define RST_BUS_HDMI1 26
+#define RST_BUS_DE 27
+#define RST_BUS_GPU 28
+#define RST_BUS_MSGBOX 29
+#define RST_BUS_SPINLOCK 30
+
+#define RST_BUS_LVDS 31
+
+#define RST_BUS_SPDIF 32
+#define RST_BUS_I2S0 33
+#define RST_BUS_I2S1 34
+#define RST_BUS_I2S2 35
+#define RST_BUS_TDM 36
+
+#define RST_BUS_I2C0 37
+#define RST_BUS_I2C1 38
+#define RST_BUS_I2C2 39
+#define RST_BUS_UART0 40
+#define RST_BUS_UART1 41
+#define RST_BUS_UART2 42
+#define RST_BUS_UART3 43
+#define RST_BUS_UART4 44
+
+#endif /* _DT_BINDINGS_RESET_SUN8I_A83T_CCU_H_ */
--
2.11.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 4/5] clk: sunxi-ng: Add driver for A83T CCU
@ 2017-02-14 3:35 ` Chen-Yu Tsai
0 siblings, 0 replies; 38+ messages in thread
From: Chen-Yu Tsai @ 2017-02-14 3:35 UTC (permalink / raw)
To: linux-arm-kernel
The A83T clock control unit is a hybrid of some new style clock designs
from the A80, and old style layout from the other Allwinner SoCs.
The mmc2 module clock supports a new timing mode. This mode outputs the
clock at half the set rate, and moves the output and sample delays into
the mmc controller. The mmc controller must also be set to use the new
timing mode. In this patch we force the mmc2 module clock to the new
mode, and drop the output and sample phase clocks for it.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
drivers/clk/sunxi-ng/Kconfig | 10 +
drivers/clk/sunxi-ng/Makefile | 1 +
drivers/clk/sunxi-ng/ccu-sun8i-a83t.c | 898 +++++++++++++++++++++++++++++
drivers/clk/sunxi-ng/ccu-sun8i-a83t.h | 65 +++
include/dt-bindings/clock/sun8i-a83t-ccu.h | 138 +++++
include/dt-bindings/reset/sun8i-a83t-ccu.h | 98 ++++
6 files changed, 1210 insertions(+)
create mode 100644 drivers/clk/sunxi-ng/ccu-sun8i-a83t.c
create mode 100644 drivers/clk/sunxi-ng/ccu-sun8i-a83t.h
create mode 100644 include/dt-bindings/clock/sun8i-a83t-ccu.h
create mode 100644 include/dt-bindings/reset/sun8i-a83t-ccu.h
diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig
index 695bbf9ef428..55f34bedfe65 100644
--- a/drivers/clk/sunxi-ng/Kconfig
+++ b/drivers/clk/sunxi-ng/Kconfig
@@ -109,6 +109,16 @@ config SUN8I_A33_CCU
select SUNXI_CCU_PHASE
default MACH_SUN8I
+config SUN8I_A83T_CCU
+ bool "Support for the Allwinner A83T CCU"
+ select SUNXI_CCU_DIV
+ select SUNXI_CCU_GATE
+ select SUNXI_CCU_NKMP
+ select SUNXI_CCU_NM
+ select SUNXI_CCU_MP
+ select SUNXI_CCU_PHASE
+ default MACH_SUN8I
+
config SUN8I_H3_CCU
bool "Support for the Allwinner H3 CCU"
select SUNXI_CCU_DIV
diff --git a/drivers/clk/sunxi-ng/Makefile b/drivers/clk/sunxi-ng/Makefile
index 6feaac0c5600..ac381ebfd98d 100644
--- a/drivers/clk/sunxi-ng/Makefile
+++ b/drivers/clk/sunxi-ng/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_SUN5I_CCU) += ccu-sun5i.o
obj-$(CONFIG_SUN6I_A31_CCU) += ccu-sun6i-a31.o
obj-$(CONFIG_SUN8I_A23_CCU) += ccu-sun8i-a23.o
obj-$(CONFIG_SUN8I_A33_CCU) += ccu-sun8i-a33.o
+obj-$(CONFIG_SUN8I_A83T_CCU) += ccu-sun8i-a83t.o
obj-$(CONFIG_SUN8I_H3_CCU) += ccu-sun8i-h3.o
obj-$(CONFIG_SUN8I_V3S_CCU) += ccu-sun8i-v3s.o
obj-$(CONFIG_SUN9I_A80_CCU) += ccu-sun9i-a80.o
diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c
new file mode 100644
index 000000000000..b2c1da1b4322
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c
@@ -0,0 +1,898 @@
+/*
+ * Copyright (c) 2017 Chen-Yu Tsai. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+
+#include "ccu_common.h"
+#include "ccu_reset.h"
+
+#include "ccu_div.h"
+#include "ccu_gate.h"
+#include "ccu_mp.h"
+#include "ccu_nkmp.h"
+#include "ccu_nm.h"
+#include "ccu_phase.h"
+
+#include "ccu-sun8i-a83t.h"
+
+#define CCU_SUN8I_A83T_LOCK_REG 0x208
+
+static struct clk_div_table pll_cpux_p_div_table[] = {
+ { .val = 0, .div = 1 },
+ { .val = 1, .div = 4 },
+ { /* Sentinel */ },
+};
+
+/*
+ * The CPU PLLs are actually NP clocks, but P is /1 or /4, so here we
+ * use the NM clocks with a divider table for M.
+ */
+static struct ccu_nm pll_c0cpux_clk = {
+ .enable = BIT(31),
+ .lock = BIT(0),
+ .n = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 12, 0),
+ .m = _SUNXI_CCU_DIV_TABLE(16, 1, pll_cpux_p_div_table),
+ .common = {
+ .reg = 0x000,
+ .lock_reg = CCU_SUN8I_A83T_LOCK_REG,
+ .features = CCU_FEATURE_LOCK_REG,
+ .hw.init = CLK_HW_INIT("pll-c0cpux", "osc24M",
+ &ccu_nm_ops, CLK_SET_RATE_UNGATE),
+ },
+};
+
+static struct ccu_nm pll_c1cpux_clk = {
+ .enable = BIT(31),
+ .lock = BIT(1),
+ .n = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 12, 0),
+ .m = _SUNXI_CCU_DIV_TABLE(16, 1, pll_cpux_p_div_table),
+ .common = {
+ .reg = 0x004,
+ .lock_reg = CCU_SUN8I_A83T_LOCK_REG,
+ .features = CCU_FEATURE_LOCK_REG,
+ .hw.init = CLK_HW_INIT("pll-c1cpux", "osc24M",
+ &ccu_nm_ops, CLK_SET_RATE_UNGATE),
+ },
+};
+
+/*
+ * The Audio PLL has d1, d2 dividers in addition to the usual N, M
+ * factors. Since we only need 2 frequencies from this PLL: 22.5792 MHz
+ * and 24.576 MHz, ignore them for now. Enforce the default for them,
+ * which is d1 = 0, d2 = 1.
+ */
+#define SUN8I_A83T_PLL_AUDIO_REG 0x008
+
+static struct ccu_nm pll_audio_clk = {
+ .enable = BIT(31),
+ .lock = BIT(2),
+ .n = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 12, 0),
+ .m = _SUNXI_CCU_DIV_OFFSET(0, 6, 0),
+ .common = {
+ .reg = SUN8I_A83T_PLL_AUDIO_REG,
+ .lock_reg = CCU_SUN8I_A83T_LOCK_REG,
+ .features = CCU_FEATURE_LOCK_REG,
+ .hw.init = CLK_HW_INIT("pll-audio", "osc24M",
+ &ccu_nm_ops, CLK_SET_RATE_UNGATE),
+ },
+};
+
+/* Some PLLs are input * N / div1 / P. Model them as NKMP with no K */
+static struct ccu_nkmp pll_video0_clk = {
+ .enable = BIT(31),
+ .lock = BIT(3),
+ .n = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 12, 0),
+ .m = _SUNXI_CCU_DIV(16, 1), /* input divider */
+ .p = _SUNXI_CCU_DIV(0, 2), /* output divider */
+ .common = {
+ .reg = 0x010,
+ .lock_reg = CCU_SUN8I_A83T_LOCK_REG,
+ .features = CCU_FEATURE_LOCK_REG,
+ .hw.init = CLK_HW_INIT("pll-video0", "osc24M",
+ &ccu_nkmp_ops,
+ CLK_SET_RATE_UNGATE),
+ },
+};
+
+static struct ccu_nkmp pll_ve_clk = {
+ .enable = BIT(31),
+ .lock = BIT(4),
+ .n = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 12, 0),
+ .m = _SUNXI_CCU_DIV(16, 1), /* input divider */
+ .p = _SUNXI_CCU_DIV(18, 1), /* output divider */
+ .common = {
+ .reg = 0x018,
+ .lock_reg = CCU_SUN8I_A83T_LOCK_REG,
+ .features = CCU_FEATURE_LOCK_REG,
+ .hw.init = CLK_HW_INIT("pll-ve", "osc24M",
+ &ccu_nkmp_ops,
+ CLK_SET_RATE_UNGATE),
+ },
+};
+
+static struct ccu_nkmp pll_ddr_clk = {
+ .enable = BIT(31),
+ .lock = BIT(5),
+ .n = _SUNXI_CCU_MULT_MIN(8, 8, 12),
+ .m = _SUNXI_CCU_DIV(16, 1), /* input divider */
+ .p = _SUNXI_CCU_DIV(18, 1), /* output divider */
+ .common = {
+ .reg = 0x020,
+ .lock_reg = CCU_SUN8I_A83T_LOCK_REG,
+ .features = CCU_FEATURE_LOCK_REG,
+ .hw.init = CLK_HW_INIT("pll-ddr", "osc24M",
+ &ccu_nkmp_ops,
+ CLK_SET_RATE_UNGATE),
+ },
+};
+
+static struct ccu_nkmp pll_periph_clk = {
+ .enable = BIT(31),
+ .lock = BIT(6),
+ .n = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 12, 0),
+ .m = _SUNXI_CCU_DIV(16, 1), /* input divider */
+ .p = _SUNXI_CCU_DIV(18, 1), /* output divider */
+ .common = {
+ .reg = 0x028,
+ .lock_reg = CCU_SUN8I_A83T_LOCK_REG,
+ .features = CCU_FEATURE_LOCK_REG,
+ .hw.init = CLK_HW_INIT("pll-periph", "osc24M",
+ &ccu_nkmp_ops,
+ CLK_SET_RATE_UNGATE),
+ },
+};
+
+static struct ccu_nkmp pll_gpu_clk = {
+ .enable = BIT(31),
+ .lock = BIT(7),
+ .n = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 12, 0),
+ .m = _SUNXI_CCU_DIV(16, 1), /* input divider */
+ .p = _SUNXI_CCU_DIV(18, 1), /* output divider */
+ .common = {
+ .reg = 0x038,
+ .lock_reg = CCU_SUN8I_A83T_LOCK_REG,
+ .features = CCU_FEATURE_LOCK_REG,
+ .hw.init = CLK_HW_INIT("pll-gpu", "osc24M",
+ &ccu_nkmp_ops,
+ CLK_SET_RATE_UNGATE),
+ },
+};
+
+static struct ccu_nkmp pll_hsic_clk = {
+ .enable = BIT(31),
+ .lock = BIT(8),
+ .n = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 12, 0),
+ .m = _SUNXI_CCU_DIV(16, 1), /* input divider */
+ .p = _SUNXI_CCU_DIV(18, 1), /* output divider */
+ .common = {
+ .reg = 0x044,
+ .lock_reg = CCU_SUN8I_A83T_LOCK_REG,
+ .features = CCU_FEATURE_LOCK_REG,
+ .hw.init = CLK_HW_INIT("pll-hsic", "osc24M",
+ &ccu_nkmp_ops,
+ CLK_SET_RATE_UNGATE),
+ },
+};
+
+static struct ccu_nkmp pll_de_clk = {
+ .enable = BIT(31),
+ .lock = BIT(9),
+ .n = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 12, 0),
+ .m = _SUNXI_CCU_DIV(16, 1), /* input divider */
+ .p = _SUNXI_CCU_DIV(18, 1), /* output divider */
+ .common = {
+ .reg = 0x048,
+ .lock_reg = CCU_SUN8I_A83T_LOCK_REG,
+ .features = CCU_FEATURE_LOCK_REG,
+ .hw.init = CLK_HW_INIT("pll-de", "osc24M",
+ &ccu_nkmp_ops,
+ CLK_SET_RATE_UNGATE),
+ },
+};
+
+static struct ccu_nkmp pll_video1_clk = {
+ .enable = BIT(31),
+ .lock = BIT(10),
+ .n = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 12, 0),
+ .m = _SUNXI_CCU_DIV(16, 1), /* input divider */
+ .p = _SUNXI_CCU_DIV(0, 2), /* external divider p */
+ .common = {
+ .reg = 0x04c,
+ .lock_reg = CCU_SUN8I_A83T_LOCK_REG,
+ .features = CCU_FEATURE_LOCK_REG,
+ .hw.init = CLK_HW_INIT("pll-video1", "osc24M",
+ &ccu_nkmp_ops,
+ CLK_SET_RATE_UNGATE),
+ },
+};
+
+static const char * const c0cpux_parents[] = { "osc24M", "pll-c0cpux" };
+static SUNXI_CCU_MUX(c0cpux_clk, "c0cpux", c0cpux_parents,
+ 0x50, 12, 1, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
+
+static const char * const c1cpux_parents[] = { "osc24M", "pll-c1cpux" };
+static SUNXI_CCU_MUX(c1cpux_clk, "c1cpux", c1cpux_parents,
+ 0x50, 28, 1, CLK_SET_RATE_PARENT | CLK_IS_CRITICAL);
+
+static SUNXI_CCU_M(axi0_clk, "axi0", "c0cpux", 0x050, 0, 2, 0);
+static SUNXI_CCU_M(axi1_clk, "axi1", "c1cpux", 0x050, 16, 2, 0);
+
+/* Use a separate clock for the pre-divider on the AHB1 PLL-PERIPH input */
+static SUNXI_CCU_M(pll_periph_ahb1_clk, "pll-periph-ahb1", "pll-periph",
+ 0x054, 6, 2, 0);
+
+static const char * const ahb1_parents[] = { "osc16M-d512", "osc24M",
+ "pll-periph-ahb1",
+ "pll-periph-ahb1" };
+static struct ccu_div ahb1_clk = {
+ .div = _SUNXI_CCU_DIV_FLAGS(4, 2, CLK_DIVIDER_POWER_OF_TWO),
+ .mux = _SUNXI_CCU_MUX(12, 2),
+ .common = {
+ .reg = 0x054,
+ .hw.init = CLK_HW_INIT_PARENTS("ahb1",
+ ahb1_parents,
+ &ccu_div_ops,
+ 0),
+ },
+};
+
+static SUNXI_CCU_M(apb1_clk, "apb1", "ahb1", 0x054, 8, 2, 0);
+
+static const char * const apb2_parents[] = { "osc16M-d512", "osc24M",
+ "pll-periph", "pll-periph" };
+
+static SUNXI_CCU_MP_WITH_MUX(apb2_clk, "apb2", apb2_parents, 0x058,
+ 0, 5, /* M */
+ 16, 2, /* P */
+ 24, 2, /* mux */
+ 0);
+
+static const char * const ahb2_parents[] = { "ahb1", "pll-periph" };
+static const struct ccu_mux_fixed_prediv ahb2_prediv = {
+ .index = 1, .div = 2
+};
+static struct ccu_mux ahb2_clk = {
+ .mux = {
+ .shift = 0,
+ .width = 2,
+ .fixed_predivs = &ahb2_prediv,
+ .n_predivs = 1,
+ },
+ .common = {
+ .reg = 0x05c,
+ .hw.init = CLK_HW_INIT_PARENTS("ahb2",
+ ahb2_parents,
+ &ccu_mux_ops,
+ 0),
+ },
+};
+
+static SUNXI_CCU_GATE(bus_mipi_dsi_clk, "bus-mipi-dsi", "ahb1",
+ 0x060, BIT(1), 0);
+static SUNXI_CCU_GATE(bus_ss_clk, "bus-ss", "ahb1",
+ 0x060, BIT(5), 0);
+static SUNXI_CCU_GATE(bus_dma_clk, "bus-dma", "ahb1",
+ 0x060, BIT(6), 0);
+static SUNXI_CCU_GATE(bus_mmc0_clk, "bus-mmc0", "ahb1",
+ 0x060, BIT(8), 0);
+static SUNXI_CCU_GATE(bus_mmc1_clk, "bus-mmc1", "ahb1",
+ 0x060, BIT(9), 0);
+static SUNXI_CCU_GATE(bus_mmc2_clk, "bus-mmc2", "ahb1",
+ 0x060, BIT(10), 0);
+static SUNXI_CCU_GATE(bus_nand_clk, "bus-nand", "ahb1",
+ 0x060, BIT(13), 0);
+static SUNXI_CCU_GATE(bus_dram_clk, "bus-dram", "ahb1",
+ 0x060, BIT(14), 0);
+static SUNXI_CCU_GATE(bus_emac_clk, "bus-emac", "ahb2",
+ 0x060, BIT(17), 0);
+static SUNXI_CCU_GATE(bus_hstimer_clk, "bus-hstimer", "ahb1",
+ 0x060, BIT(19), 0);
+static SUNXI_CCU_GATE(bus_spi0_clk, "bus-spi0", "ahb1",
+ 0x060, BIT(20), 0);
+static SUNXI_CCU_GATE(bus_spi1_clk, "bus-spi1", "ahb1",
+ 0x060, BIT(21), 0);
+static SUNXI_CCU_GATE(bus_otg_clk, "bus-otg", "ahb1",
+ 0x060, BIT(24), 0);
+static SUNXI_CCU_GATE(bus_ehci0_clk, "bus-ehci0", "ahb2",
+ 0x060, BIT(26), 0);
+static SUNXI_CCU_GATE(bus_ehci1_clk, "bus-ehci1", "ahb2",
+ 0x060, BIT(27), 0);
+static SUNXI_CCU_GATE(bus_ohci0_clk, "bus-ohci0", "ahb2",
+ 0x060, BIT(29), 0);
+
+static SUNXI_CCU_GATE(bus_ve_clk, "bus-ve", "ahb1",
+ 0x064, BIT(0), 0);
+static SUNXI_CCU_GATE(bus_tcon0_clk, "bus-tcon0", "ahb1",
+ 0x064, BIT(4), 0);
+static SUNXI_CCU_GATE(bus_tcon1_clk, "bus-tcon1", "ahb1",
+ 0x064, BIT(5), 0);
+static SUNXI_CCU_GATE(bus_csi_clk, "bus-csi", "ahb1",
+ 0x064, BIT(8), 0);
+static SUNXI_CCU_GATE(bus_hdmi_clk, "bus-hdmi", "ahb1",
+ 0x064, BIT(11), 0);
+static SUNXI_CCU_GATE(bus_de_clk, "bus-de", "ahb1",
+ 0x064, BIT(12), 0);
+static SUNXI_CCU_GATE(bus_gpu_clk, "bus-gpu", "ahb1",
+ 0x064, BIT(20), 0);
+static SUNXI_CCU_GATE(bus_msgbox_clk, "bus-msgbox", "ahb1",
+ 0x064, BIT(21), 0);
+static SUNXI_CCU_GATE(bus_spinlock_clk, "bus-spinlock", "ahb1",
+ 0x064, BIT(22), 0);
+
+static SUNXI_CCU_GATE(bus_spdif_clk, "bus-spdif", "apb1",
+ 0x068, BIT(1), 0);
+static SUNXI_CCU_GATE(bus_pio_clk, "bus-pio", "apb1",
+ 0x068, BIT(5), 0);
+static SUNXI_CCU_GATE(bus_i2s0_clk, "bus-i2s0", "apb1",
+ 0x068, BIT(12), 0);
+static SUNXI_CCU_GATE(bus_i2s1_clk, "bus-i2s1", "apb1",
+ 0x068, BIT(13), 0);
+static SUNXI_CCU_GATE(bus_i2s2_clk, "bus-i2s2", "apb1",
+ 0x068, BIT(14), 0);
+static SUNXI_CCU_GATE(bus_tdm_clk, "bus-tdm", "apb1",
+ 0x068, BIT(15), 0);
+
+static SUNXI_CCU_GATE(bus_i2c0_clk, "bus-i2c0", "apb2",
+ 0x06c, BIT(0), 0);
+static SUNXI_CCU_GATE(bus_i2c1_clk, "bus-i2c1", "apb2",
+ 0x06c, BIT(0), 0);
+static SUNXI_CCU_GATE(bus_i2c2_clk, "bus-i2c2", "apb2",
+ 0x06c, BIT(0), 0);
+static SUNXI_CCU_GATE(bus_uart0_clk, "bus-uart0", "apb2",
+ 0x06c, BIT(16), 0);
+static SUNXI_CCU_GATE(bus_uart1_clk, "bus-uart1", "apb2",
+ 0x06c, BIT(17), 0);
+static SUNXI_CCU_GATE(bus_uart2_clk, "bus-uart2", "apb2",
+ 0x06c, BIT(18), 0);
+static SUNXI_CCU_GATE(bus_uart3_clk, "bus-uart3", "apb2",
+ 0x06c, BIT(19), 0);
+static SUNXI_CCU_GATE(bus_uart4_clk, "bus-uart4", "apb2",
+ 0x06c, BIT(20), 0);
+
+static const char * const cci400_parents[] = { "osc24M", "pll-periph",
+ "pll-hsic" };
+static struct ccu_div cci400_clk = {
+ .div = _SUNXI_CCU_DIV_FLAGS(0, 2, 0),
+ .mux = _SUNXI_CCU_MUX(24, 2),
+ .common = {
+ .reg = 0x078,
+ .hw.init = CLK_HW_INIT_PARENTS("cci400",
+ cci400_parents,
+ &ccu_div_ops,
+ CLK_IS_CRITICAL),
+ },
+};
+
+static const char * const mod0_default_parents[] = { "osc24M", "pll-periph" };
+
+static SUNXI_CCU_MP_WITH_MUX_GATE(nand_clk, "nand", mod0_default_parents,
+ 0x080,
+ 0, 4, /* M */
+ 16, 2, /* P */
+ 24, 2, /* mux */
+ BIT(31), /* gate */
+ 0);
+
+static SUNXI_CCU_MP_WITH_MUX_GATE(mmc0_clk, "mmc0", mod0_default_parents,
+ 0x088,
+ 0, 4, /* M */
+ 16, 2, /* P */
+ 24, 2, /* mux */
+ BIT(31), /* gate */
+ 0);
+
+static SUNXI_CCU_PHASE(mmc0_sample_clk, "mmc0-sample", "mmc0",
+ 0x088, 20, 3, 0);
+static SUNXI_CCU_PHASE(mmc0_output_clk, "mmc0-output", "mmc0",
+ 0x088, 8, 3, 0);
+
+static SUNXI_CCU_MP_WITH_MUX_GATE(mmc1_clk, "mmc1", mod0_default_parents,
+ 0x08c,
+ 0, 4, /* M */
+ 16, 2, /* P */
+ 24, 2, /* mux */
+ BIT(31), /* gate */
+ 0);
+
+static SUNXI_CCU_PHASE(mmc1_sample_clk, "mmc1-sample", "mmc1",
+ 0x08c, 20, 3, 0);
+static SUNXI_CCU_PHASE(mmc1_output_clk, "mmc1-output", "mmc1",
+ 0x08c, 8, 3, 0);
+
+/*
+ * MMC2 supports what's called the "new timing mode". The CCU and the MMC
+ * controller must be in sync about which mode is used. The new mode moves
+ * the clock delay controls (and possibly the delay lines) into the MMC
+ * block. Also, the output of the clock is divided by 2. The output and
+ * sample phase clocks are unused under this mode.
+ *
+ * This new mode seems to be preferred. Hence we force this clock to the
+ * new mode. And we don't add the phase clocks.
+ */
+#define SUN8I_A83T_MMC2_REG 0x090
+
+static struct ccu_mp mmc2_clk = {
+ .enable = BIT(31),
+ .m = _SUNXI_CCU_DIV(0, 4),
+ .p = _SUNXI_CCU_DIV(16, 2),
+ .mux = _SUNXI_CCU_MUX(24, 2),
+ .common = {
+ .reg = SUN8I_A83T_MMC2_REG,
+ .prediv = 2,
+ .features = CCU_FEATURE_ALL_PREDIV,
+ .hw.init = CLK_HW_INIT_PARENTS("mmc2",
+ mod0_default_parents,
+ &ccu_mp_ops,
+ 0)
+ }
+};
+
+static SUNXI_CCU_MP_WITH_MUX_GATE(ss_clk, "ss", mod0_default_parents,
+ 0x09c,
+ 0, 4, /* M */
+ 16, 2, /* P */
+ 24, 2, /* mux */
+ BIT(31), /* gate */
+ 0);
+
+static SUNXI_CCU_MP_WITH_MUX_GATE(spi0_clk, "spi0", mod0_default_parents,
+ 0x0a0,
+ 0, 4, /* M */
+ 16, 2, /* P */
+ 24, 4, /* mux */
+ BIT(31), /* gate */
+ 0);
+
+static SUNXI_CCU_MP_WITH_MUX_GATE(spi1_clk, "spi1", mod0_default_parents,
+ 0x0a4,
+ 0, 4, /* M */
+ 16, 2, /* P */
+ 24, 4, /* mux */
+ BIT(31), /* gate */
+ 0);
+
+static SUNXI_CCU_M_WITH_GATE(i2s0_clk, "i2s0", "pll-audio",
+ 0x0b0, 0, 4, BIT(31), CLK_SET_RATE_PARENT);
+static SUNXI_CCU_M_WITH_GATE(i2s1_clk, "i2s1", "pll-audio",
+ 0x0b4, 0, 4, BIT(31), CLK_SET_RATE_PARENT);
+static SUNXI_CCU_M_WITH_GATE(i2s2_clk, "i2s2", "pll-audio",
+ 0x0b8, 0, 4, BIT(31), CLK_SET_RATE_PARENT);
+static SUNXI_CCU_M_WITH_GATE(tdm_clk, "tdm", "pll-audio",
+ 0x0bc, 0, 4, BIT(31), CLK_SET_RATE_PARENT);
+static SUNXI_CCU_M_WITH_GATE(spdif_clk, "spdif", "pll-audio",
+ 0x0c0, 0, 4, BIT(31), CLK_SET_RATE_PARENT);
+
+static SUNXI_CCU_GATE(usb_phy0_clk, "usb-phy0", "osc24M",
+ 0x0cc, BIT(8), 0);
+static SUNXI_CCU_GATE(usb_phy1_clk, "usb-phy1", "osc24M",
+ 0x0cc, BIT(9), 0);
+static SUNXI_CCU_GATE(usb_hsic_clk, "usb-hsic", "pll-hsic",
+ 0x0cc, BIT(10), 0);
+static struct ccu_gate usb_hsic_12m_clk = {
+ .enable = BIT(11),
+ .common = {
+ .reg = 0x0cc,
+ .prediv = 2,
+ .features = CCU_FEATURE_ALL_PREDIV,
+ .hw.init = CLK_HW_INIT("usb-hsic-12m", "osc24M",
+ &ccu_gate_ops, 0),
+ }
+};
+static SUNXI_CCU_GATE(usb_ohci0_clk, "usb-ohci0", "osc24M",
+ 0x0cc, BIT(16), 0);
+
+/* TODO divider has minimum of 2 */
+static SUNXI_CCU_M(dram_clk, "dram", "pll-ddr", 0x0f4, 0, 4, CLK_IS_CRITICAL);
+
+static SUNXI_CCU_GATE(dram_ve_clk, "dram-ve", "dram",
+ 0x100, BIT(0), 0);
+static SUNXI_CCU_GATE(dram_csi_clk, "dram-csi", "dram",
+ 0x100, BIT(1), 0);
+
+static const char * const tcon0_parents[] = { "pll-video0" };
+static SUNXI_CCU_MUX_WITH_GATE(tcon0_clk, "tcon0", tcon0_parents,
+ 0x118, 24, 3, BIT(31), CLK_SET_RATE_PARENT);
+
+static const char * const tcon1_parents[] = { "pll-video1" };
+static SUNXI_CCU_MUX_WITH_GATE(tcon1_clk, "tcon1", tcon1_parents,
+ 0x11c, 24, 3, BIT(31), CLK_SET_RATE_PARENT);
+
+static SUNXI_CCU_GATE(csi_misc_clk, "csi-misc", "osc24M", 0x130, BIT(16), 0);
+
+static SUNXI_CCU_GATE(mipi_csi_clk, "mipi-csi", "osc24M", 0x130, BIT(31), 0);
+
+static const char * const csi_mclk_parents[] = { "pll-de", "osc24M" };
+static const u8 csi_mclk_table[] = { 3, 5 };
+static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(csi_mclk_clk, "csi-mclk",
+ csi_mclk_parents, csi_mclk_table,
+ 0x134,
+ 0, 5, /* M */
+ 10, 3, /* mux */
+ BIT(15), /* gate */
+ 0);
+
+static const char * const csi_sclk_parents[] = { "pll-periph", "pll-ve" };
+static const u8 csi_sclk_table[] = { 0, 5 };
+static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(csi_sclk_clk, "csi-sclk",
+ csi_sclk_parents, csi_sclk_table,
+ 0x134,
+ 16, 4, /* M */
+ 24, 3, /* mux */
+ BIT(31), /* gate */
+ 0);
+
+static SUNXI_CCU_M_WITH_GATE(ve_clk, "ve", "pll-ve", 0x13c,
+ 16, 3, BIT(31), CLK_SET_RATE_PARENT);
+
+static SUNXI_CCU_GATE(avs_clk, "avs", "osc24M", 0x144, BIT(31), 0);
+
+static const char * const hdmi_parents[] = { "pll-video1" };
+static SUNXI_CCU_M_WITH_MUX_GATE(hdmi_clk, "hdmi", hdmi_parents,
+ 0x150,
+ 0, 4, /* M */
+ 24, 2, /* mux */
+ BIT(31), /* gate */
+ CLK_SET_RATE_PARENT);
+
+static SUNXI_CCU_GATE(hdmi_slow_clk, "hdmi-slow", "osc24M", 0x154, BIT(31), 0);
+
+static const char * const mbus_parents[] = { "osc24M", "pll-periph",
+ "pll-ddr" };
+static SUNXI_CCU_M_WITH_MUX_GATE(mbus_clk, "mbus", mbus_parents,
+ 0x15c,
+ 0, 3, /* M */
+ 24, 2, /* mux */
+ BIT(31), /* gate */
+ CLK_IS_CRITICAL);
+
+static const char * const mipi_dsi0_parents[] = { "pll-video0" };
+static const u8 mipi_dsi0_table[] = { 8 };
+static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(mipi_dsi0_clk, "mipi-dsi0",
+ mipi_dsi0_parents, mipi_dsi0_table,
+ 0x168,
+ 0, 4, /* M */
+ 24, 4, /* mux */
+ BIT(31), /* gate */
+ CLK_SET_RATE_PARENT);
+
+static const char * const mipi_dsi1_parents[] = { "osc24M", "pll-video0" };
+static const u8 mipi_dsi1_table[] = { 0, 9 };
+static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(mipi_dsi1_clk, "mipi-dsi1",
+ mipi_dsi1_parents, mipi_dsi1_table,
+ 0x16c,
+ 0, 4, /* M */
+ 24, 4, /* mux */
+ BIT(31), /* gate */
+ CLK_SET_RATE_PARENT);
+
+static SUNXI_CCU_M_WITH_GATE(gpu_core_clk, "gpu-core", "pll-gpu", 0x1a0,
+ 0, 3, BIT(31), CLK_SET_RATE_PARENT);
+
+static const char * const gpu_memory_parents[] = { "pll-gpu", "pll-ddr" };
+static SUNXI_CCU_M_WITH_MUX_GATE(gpu_memory_clk, "gpu-memory",
+ gpu_memory_parents,
+ 0x1a4,
+ 0, 3, /* M */
+ 24, 1, /* mux */
+ BIT(31), /* gate */
+ CLK_SET_RATE_PARENT);
+
+static SUNXI_CCU_M_WITH_GATE(gpu_hyd_clk, "gpu-hyd", "pll-gpu", 0x1a8,
+ 0, 3, BIT(31), CLK_SET_RATE_PARENT);
+
+static struct ccu_common *sun8i_a83t_ccu_clks[] = {
+ &pll_c0cpux_clk.common,
+ &pll_c1cpux_clk.common,
+ &pll_audio_clk.common,
+ &pll_video0_clk.common,
+ &pll_ve_clk.common,
+ &pll_ddr_clk.common,
+ &pll_periph_clk.common,
+ &pll_gpu_clk.common,
+ &pll_hsic_clk.common,
+ &pll_de_clk.common,
+ &pll_video1_clk.common,
+ &c0cpux_clk.common,
+ &c1cpux_clk.common,
+ &axi0_clk.common,
+ &axi1_clk.common,
+ &pll_periph_ahb1_clk.common,
+ &ahb1_clk.common,
+ &ahb2_clk.common,
+ &apb1_clk.common,
+ &apb2_clk.common,
+ &bus_mipi_dsi_clk.common,
+ &bus_ss_clk.common,
+ &bus_dma_clk.common,
+ &bus_mmc0_clk.common,
+ &bus_mmc1_clk.common,
+ &bus_mmc2_clk.common,
+ &bus_nand_clk.common,
+ &bus_dram_clk.common,
+ &bus_emac_clk.common,
+ &bus_hstimer_clk.common,
+ &bus_spi0_clk.common,
+ &bus_spi1_clk.common,
+ &bus_otg_clk.common,
+ &bus_ehci0_clk.common,
+ &bus_ehci1_clk.common,
+ &bus_ohci0_clk.common,
+ &bus_ve_clk.common,
+ &bus_tcon0_clk.common,
+ &bus_tcon1_clk.common,
+ &bus_csi_clk.common,
+ &bus_hdmi_clk.common,
+ &bus_de_clk.common,
+ &bus_gpu_clk.common,
+ &bus_msgbox_clk.common,
+ &bus_spinlock_clk.common,
+ &bus_spdif_clk.common,
+ &bus_pio_clk.common,
+ &bus_i2s0_clk.common,
+ &bus_i2s1_clk.common,
+ &bus_i2s2_clk.common,
+ &bus_tdm_clk.common,
+ &bus_i2c0_clk.common,
+ &bus_i2c1_clk.common,
+ &bus_i2c2_clk.common,
+ &bus_uart0_clk.common,
+ &bus_uart1_clk.common,
+ &bus_uart2_clk.common,
+ &bus_uart3_clk.common,
+ &bus_uart4_clk.common,
+ &cci400_clk.common,
+ &nand_clk.common,
+ &mmc0_clk.common,
+ &mmc0_sample_clk.common,
+ &mmc0_output_clk.common,
+ &mmc1_clk.common,
+ &mmc1_sample_clk.common,
+ &mmc1_output_clk.common,
+ &mmc2_clk.common,
+ &ss_clk.common,
+ &spi0_clk.common,
+ &spi1_clk.common,
+ &i2s0_clk.common,
+ &i2s1_clk.common,
+ &i2s2_clk.common,
+ &tdm_clk.common,
+ &spdif_clk.common,
+ &usb_phy0_clk.common,
+ &usb_phy1_clk.common,
+ &usb_hsic_clk.common,
+ &usb_hsic_12m_clk.common,
+ &usb_ohci0_clk.common,
+ &dram_clk.common,
+ &dram_ve_clk.common,
+ &dram_csi_clk.common,
+ &tcon0_clk.common,
+ &tcon1_clk.common,
+ &csi_misc_clk.common,
+ &mipi_csi_clk.common,
+ &csi_mclk_clk.common,
+ &csi_sclk_clk.common,
+ &ve_clk.common,
+ &avs_clk.common,
+ &hdmi_clk.common,
+ &hdmi_slow_clk.common,
+ &mbus_clk.common,
+ &mipi_dsi0_clk.common,
+ &mipi_dsi1_clk.common,
+ &gpu_core_clk.common,
+ &gpu_memory_clk.common,
+ &gpu_hyd_clk.common,
+};
+
+static struct clk_hw_onecell_data sun8i_a83t_hw_clks = {
+ .hws = {
+ [CLK_PLL_C0CPUX] = &pll_c0cpux_clk.common.hw,
+ [CLK_PLL_C1CPUX] = &pll_c1cpux_clk.common.hw,
+ [CLK_PLL_AUDIO] = &pll_audio_clk.common.hw,
+ [CLK_PLL_VIDEO0] = &pll_video0_clk.common.hw,
+ [CLK_PLL_VE] = &pll_ve_clk.common.hw,
+ [CLK_PLL_DDR] = &pll_ddr_clk.common.hw,
+ [CLK_PLL_PERIPH] = &pll_periph_clk.common.hw,
+ [CLK_PLL_GPU] = &pll_gpu_clk.common.hw,
+ [CLK_PLL_HSIC] = &pll_hsic_clk.common.hw,
+ [CLK_PLL_DE] = &pll_de_clk.common.hw,
+ [CLK_PLL_VIDEO1] = &pll_video1_clk.common.hw,
+ [CLK_C0CPUX] = &c0cpux_clk.common.hw,
+ [CLK_C1CPUX] = &c1cpux_clk.common.hw,
+ [CLK_AXI0] = &axi0_clk.common.hw,
+ [CLK_AXI1] = &axi1_clk.common.hw,
+ [CLK_PLL_PERIPH_AHB1] = &pll_periph_ahb1_clk.common.hw,
+ [CLK_AHB1] = &ahb1_clk.common.hw,
+ [CLK_AHB2] = &ahb2_clk.common.hw,
+ [CLK_APB1] = &apb1_clk.common.hw,
+ [CLK_APB2] = &apb2_clk.common.hw,
+ [CLK_BUS_MIPI_DSI] = &bus_mipi_dsi_clk.common.hw,
+ [CLK_BUS_SS] = &bus_ss_clk.common.hw,
+ [CLK_BUS_DMA] = &bus_dma_clk.common.hw,
+ [CLK_BUS_MMC0] = &bus_mmc0_clk.common.hw,
+ [CLK_BUS_MMC1] = &bus_mmc1_clk.common.hw,
+ [CLK_BUS_MMC2] = &bus_mmc2_clk.common.hw,
+ [CLK_BUS_NAND] = &bus_nand_clk.common.hw,
+ [CLK_BUS_DRAM] = &bus_dram_clk.common.hw,
+ [CLK_BUS_EMAC] = &bus_emac_clk.common.hw,
+ [CLK_BUS_HSTIMER] = &bus_hstimer_clk.common.hw,
+ [CLK_BUS_SPI0] = &bus_spi0_clk.common.hw,
+ [CLK_BUS_SPI1] = &bus_spi1_clk.common.hw,
+ [CLK_BUS_OTG] = &bus_otg_clk.common.hw,
+ [CLK_BUS_EHCI0] = &bus_ehci0_clk.common.hw,
+ [CLK_BUS_EHCI1] = &bus_ehci1_clk.common.hw,
+ [CLK_BUS_OHCI0] = &bus_ohci0_clk.common.hw,
+ [CLK_BUS_VE] = &bus_ve_clk.common.hw,
+ [CLK_BUS_TCON0] = &bus_tcon0_clk.common.hw,
+ [CLK_BUS_TCON1] = &bus_tcon1_clk.common.hw,
+ [CLK_BUS_CSI] = &bus_csi_clk.common.hw,
+ [CLK_BUS_HDMI] = &bus_hdmi_clk.common.hw,
+ [CLK_BUS_DE] = &bus_de_clk.common.hw,
+ [CLK_BUS_GPU] = &bus_gpu_clk.common.hw,
+ [CLK_BUS_MSGBOX] = &bus_msgbox_clk.common.hw,
+ [CLK_BUS_SPINLOCK] = &bus_spinlock_clk.common.hw,
+ [CLK_BUS_SPDIF] = &bus_spdif_clk.common.hw,
+ [CLK_BUS_PIO] = &bus_pio_clk.common.hw,
+ [CLK_BUS_I2S0] = &bus_i2s0_clk.common.hw,
+ [CLK_BUS_I2S1] = &bus_i2s1_clk.common.hw,
+ [CLK_BUS_I2S2] = &bus_i2s2_clk.common.hw,
+ [CLK_BUS_TDM] = &bus_tdm_clk.common.hw,
+ [CLK_BUS_I2C0] = &bus_i2c0_clk.common.hw,
+ [CLK_BUS_I2C1] = &bus_i2c1_clk.common.hw,
+ [CLK_BUS_I2C2] = &bus_i2c2_clk.common.hw,
+ [CLK_BUS_UART0] = &bus_uart0_clk.common.hw,
+ [CLK_BUS_UART1] = &bus_uart1_clk.common.hw,
+ [CLK_BUS_UART2] = &bus_uart2_clk.common.hw,
+ [CLK_BUS_UART3] = &bus_uart3_clk.common.hw,
+ [CLK_BUS_UART4] = &bus_uart4_clk.common.hw,
+ [CLK_CCI400] = &cci400_clk.common.hw,
+ [CLK_NAND] = &nand_clk.common.hw,
+ [CLK_MMC0] = &mmc0_clk.common.hw,
+ [CLK_MMC0_SAMPLE] = &mmc0_sample_clk.common.hw,
+ [CLK_MMC0_OUTPUT] = &mmc0_output_clk.common.hw,
+ [CLK_MMC1] = &mmc1_clk.common.hw,
+ [CLK_MMC1_SAMPLE] = &mmc1_sample_clk.common.hw,
+ [CLK_MMC1_OUTPUT] = &mmc1_output_clk.common.hw,
+ [CLK_MMC2] = &mmc2_clk.common.hw,
+ [CLK_SS] = &ss_clk.common.hw,
+ [CLK_SPI0] = &spi0_clk.common.hw,
+ [CLK_SPI1] = &spi1_clk.common.hw,
+ [CLK_I2S0] = &i2s0_clk.common.hw,
+ [CLK_I2S1] = &i2s1_clk.common.hw,
+ [CLK_I2S2] = &i2s2_clk.common.hw,
+ [CLK_TDM] = &tdm_clk.common.hw,
+ [CLK_SPDIF] = &spdif_clk.common.hw,
+ [CLK_USB_PHY0] = &usb_phy0_clk.common.hw,
+ [CLK_USB_PHY1] = &usb_phy1_clk.common.hw,
+ [CLK_USB_HSIC] = &usb_hsic_clk.common.hw,
+ [CLK_USB_HSIC_12M] = &usb_hsic_12m_clk.common.hw,
+ [CLK_USB_OHCI0] = &usb_ohci0_clk.common.hw,
+ [CLK_DRAM] = &dram_clk.common.hw,
+ [CLK_DRAM_VE] = &dram_ve_clk.common.hw,
+ [CLK_DRAM_CSI] = &dram_csi_clk.common.hw,
+ [CLK_TCON0] = &tcon0_clk.common.hw,
+ [CLK_TCON1] = &tcon1_clk.common.hw,
+ [CLK_CSI_MISC] = &csi_misc_clk.common.hw,
+ [CLK_MIPI_CSI] = &mipi_csi_clk.common.hw,
+ [CLK_CSI_MCLK] = &csi_mclk_clk.common.hw,
+ [CLK_CSI_SCLK] = &csi_sclk_clk.common.hw,
+ [CLK_VE] = &ve_clk.common.hw,
+ [CLK_AVS] = &avs_clk.common.hw,
+ [CLK_HDMI] = &hdmi_clk.common.hw,
+ [CLK_HDMI_SLOW] = &hdmi_slow_clk.common.hw,
+ [CLK_MBUS] = &mbus_clk.common.hw,
+ [CLK_MIPI_DSI0] = &mipi_dsi0_clk.common.hw,
+ [CLK_MIPI_DSI1] = &mipi_dsi1_clk.common.hw,
+ [CLK_GPU_CORE] = &gpu_core_clk.common.hw,
+ [CLK_GPU_MEMORY] = &gpu_memory_clk.common.hw,
+ [CLK_GPU_HYD] = &gpu_hyd_clk.common.hw,
+ },
+ .num = CLK_NUMBER,
+};
+
+static struct ccu_reset_map sun8i_a83t_ccu_resets[] = {
+ [RST_USB_PHY0] = { 0x0cc, BIT(0) },
+ [RST_USB_PHY1] = { 0x0cc, BIT(1) },
+ [RST_USB_HSIC] = { 0x0cc, BIT(2) },
+ [RST_DRAM] = { 0x0f4, BIT(31) },
+ [RST_MBUS] = { 0x0fc, BIT(31) },
+ [RST_BUS_MIPI_DSI] = { 0x2c0, BIT(1) },
+ [RST_BUS_SS] = { 0x2c0, BIT(5) },
+ [RST_BUS_DMA] = { 0x2c0, BIT(6) },
+ [RST_BUS_MMC0] = { 0x2c0, BIT(8) },
+ [RST_BUS_MMC1] = { 0x2c0, BIT(9) },
+ [RST_BUS_MMC2] = { 0x2c0, BIT(10) },
+ [RST_BUS_NAND] = { 0x2c0, BIT(13) },
+ [RST_BUS_DRAM] = { 0x2c0, BIT(14) },
+ [RST_BUS_EMAC] = { 0x2c0, BIT(17) },
+ [RST_BUS_HSTIMER] = { 0x2c0, BIT(19) },
+ [RST_BUS_SPI0] = { 0x2c0, BIT(20) },
+ [RST_BUS_SPI1] = { 0x2c0, BIT(21) },
+ [RST_BUS_OTG] = { 0x2c0, BIT(24) },
+ [RST_BUS_EHCI0] = { 0x2c0, BIT(26) },
+ [RST_BUS_EHCI1] = { 0x2c0, BIT(27) },
+ [RST_BUS_OHCI0] = { 0x2c0, BIT(29) },
+ [RST_BUS_VE] = { 0x2c4, BIT(0) },
+ [RST_BUS_TCON0] = { 0x2c4, BIT(4) },
+ [RST_BUS_TCON1] = { 0x2c4, BIT(5) },
+ [RST_BUS_CSI] = { 0x2c4, BIT(8) },
+ [RST_BUS_HDMI0] = { 0x2c4, BIT(10) },
+ [RST_BUS_HDMI1] = { 0x2c4, BIT(11) },
+ [RST_BUS_DE] = { 0x2c4, BIT(12) },
+ [RST_BUS_GPU] = { 0x2c4, BIT(20) },
+ [RST_BUS_MSGBOX] = { 0x2c4, BIT(21) },
+ [RST_BUS_SPINLOCK] = { 0x2c4, BIT(22) },
+ [RST_BUS_LVDS] = { 0x2c8, BIT(0) },
+ [RST_BUS_SPDIF] = { 0x2d0, BIT(1) },
+ [RST_BUS_I2S0] = { 0x2d0, BIT(12) },
+ [RST_BUS_I2S1] = { 0x2d0, BIT(13) },
+ [RST_BUS_I2S2] = { 0x2d0, BIT(14) },
+ [RST_BUS_TDM] = { 0x2d0, BIT(15) },
+ [RST_BUS_I2C0] = { 0x2d8, BIT(0) },
+ [RST_BUS_I2C1] = { 0x2d8, BIT(1) },
+ [RST_BUS_I2C2] = { 0x2d8, BIT(2) },
+ [RST_BUS_UART0] = { 0x2d8, BIT(16) },
+ [RST_BUS_UART1] = { 0x2d8, BIT(17) },
+ [RST_BUS_UART2] = { 0x2d8, BIT(18) },
+ [RST_BUS_UART3] = { 0x2d8, BIT(19) },
+ [RST_BUS_UART4] = { 0x2d8, BIT(20) },
+};
+
+static const struct sunxi_ccu_desc sun8i_a83t_ccu_desc = {
+ .ccu_clks = sun8i_a83t_ccu_clks,
+ .num_ccu_clks = ARRAY_SIZE(sun8i_a83t_ccu_clks),
+
+ .hw_clks = &sun8i_a83t_hw_clks,
+
+ .resets = sun8i_a83t_ccu_resets,
+ .num_resets = ARRAY_SIZE(sun8i_a83t_ccu_resets),
+};
+
+static int sun8i_a83t_ccu_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ void __iomem *reg;
+ u32 val;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ reg = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(reg))
+ return PTR_ERR(reg);
+
+ /* Enforce d1 = 0, d2 = 0 for Audio PLL */
+ val = readl(reg + SUN8I_A83T_PLL_AUDIO_REG);
+ val &= (BIT(16) & BIT(18));
+ writel(val, reg + SUN8I_A83T_PLL_AUDIO_REG);
+
+ /* Enforce new timing mode for MMC2 */
+ val = readl(reg + SUN8I_A83T_MMC2_REG);
+ val |= BIT(30);
+ writel(val, reg + SUN8I_A83T_MMC2_REG);
+
+ return sunxi_ccu_probe(pdev->dev.of_node, reg, &sun8i_a83t_ccu_desc);
+}
+
+static const struct of_device_id sun8i_a83t_ccu_ids[] = {
+ { .compatible = "allwinner,sun8i-a83t-ccu" },
+ { }
+};
+
+static struct platform_driver sun8i_a83t_ccu_driver = {
+ .probe = sun8i_a83t_ccu_probe,
+ .driver = {
+ .name = "sun8i-a83t-ccu",
+ .of_match_table = sun8i_a83t_ccu_ids,
+ },
+};
+builtin_platform_driver(sun8i_a83t_ccu_driver);
diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.h b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.h
new file mode 100644
index 000000000000..fe7e6b347061
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2016 Chen-Yu Tsai
+ *
+ * Chen-Yu Tsai <wens@csie.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CCU_SUN8I_A83T_H_
+#define _CCU_SUN8I_A83T_H_
+
+#include <dt-bindings/clock/sun8i-a83t-ccu.h>
+#include <dt-bindings/reset/sun8i-a83t-ccu.h>
+
+#define CLK_PLL_C0CPUX 0
+#define CLK_PLL_C1CPUX 1
+#define CLK_PLL_AUDIO 2
+#define CLK_PLL_VIDEO0 3
+#define CLK_PLL_VE 4
+#define CLK_PLL_DDR 5
+
+/* pll-periph is exported to the PRCM block */
+
+#define CLK_PLL_GPU 7
+#define CLK_PLL_HSIC 8
+
+/* pll-de is exported for the display engine */
+
+#define CLK_PLL_VIDEO1 10
+
+/* The CPUX clocks are exported */
+
+#define CLK_AXI0 13
+#define CLK_AXI1 14
+#define CLK_PLL_PERIPH_AHB1 15
+#define CLK_AHB1 16
+#define CLK_AHB2 17
+#define CLK_APB1 18
+#define CLK_APB2 19
+
+/* bus gates exported */
+
+#define CLK_CCI400 59
+
+/* module and usb clocks exported */
+
+#define CLK_DRAM 81
+
+/* dram gates and more module clocks exported */
+
+#define CLK_MBUS 94
+
+/* more module clocks exported */
+
+#define CLK_NUMBER (CLK_GPU_HYD + 1)
+
+#endif /* _CCU_SUN8I_A83T_H_ */
diff --git a/include/dt-bindings/clock/sun8i-a83t-ccu.h b/include/dt-bindings/clock/sun8i-a83t-ccu.h
new file mode 100644
index 000000000000..e30c40e01dd4
--- /dev/null
+++ b/include/dt-bindings/clock/sun8i-a83t-ccu.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2017 Chen-Yu Tsai <wens@csie.org>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _DT_BINDINGS_CLOCK_SUN8I_A83T_CCU_H_
+#define _DT_BINDINGS_CLOCK_SUN8I_A83T_CCU_H_
+
+#define CLK_PLL_PERIPH 6
+
+#define CLK_PLL_DE 9
+
+#define CLK_C0CPUX 11
+#define CLK_C1CPUX 12
+
+#define CLK_BUS_MIPI_DSI 20
+#define CLK_BUS_SS 21
+#define CLK_BUS_DMA 22
+#define CLK_BUS_MMC0 23
+#define CLK_BUS_MMC1 24
+#define CLK_BUS_MMC2 25
+#define CLK_BUS_NAND 26
+#define CLK_BUS_DRAM 27
+#define CLK_BUS_EMAC 28
+#define CLK_BUS_HSTIMER 29
+#define CLK_BUS_SPI0 30
+#define CLK_BUS_SPI1 31
+#define CLK_BUS_OTG 32
+#define CLK_BUS_EHCI0 33
+#define CLK_BUS_EHCI1 34
+#define CLK_BUS_OHCI0 35
+
+#define CLK_BUS_VE 36
+#define CLK_BUS_TCON0 37
+#define CLK_BUS_TCON1 38
+#define CLK_BUS_CSI 39
+#define CLK_BUS_HDMI 40
+#define CLK_BUS_DE 41
+#define CLK_BUS_GPU 42
+#define CLK_BUS_MSGBOX 43
+#define CLK_BUS_SPINLOCK 44
+
+#define CLK_BUS_SPDIF 45
+#define CLK_BUS_PIO 46
+#define CLK_BUS_I2S0 47
+#define CLK_BUS_I2S1 48
+#define CLK_BUS_I2S2 49
+#define CLK_BUS_TDM 50
+
+#define CLK_BUS_I2C0 51
+#define CLK_BUS_I2C1 52
+#define CLK_BUS_I2C2 53
+#define CLK_BUS_UART0 54
+#define CLK_BUS_UART1 55
+#define CLK_BUS_UART2 56
+#define CLK_BUS_UART3 57
+#define CLK_BUS_UART4 58
+
+#define CLK_NAND 60
+#define CLK_MMC0 61
+#define CLK_MMC0_SAMPLE 62
+#define CLK_MMC0_OUTPUT 63
+#define CLK_MMC1 64
+#define CLK_MMC1_SAMPLE 65
+#define CLK_MMC1_OUTPUT 66
+#define CLK_MMC2 67
+#define CLK_SS 68
+#define CLK_SPI0 69
+#define CLK_SPI1 70
+#define CLK_I2S0 71
+#define CLK_I2S1 72
+#define CLK_I2S2 73
+#define CLK_TDM 74
+#define CLK_SPDIF 75
+#define CLK_USB_PHY0 76
+#define CLK_USB_PHY1 77
+#define CLK_USB_HSIC 78
+#define CLK_USB_HSIC_12M 79
+#define CLK_USB_OHCI0 80
+
+#define CLK_DRAM_VE 82
+#define CLK_DRAM_CSI 83
+
+#define CLK_TCON0 84
+#define CLK_TCON1 85
+#define CLK_CSI_MISC 86
+#define CLK_MIPI_CSI 87
+#define CLK_CSI_MCLK 88
+#define CLK_CSI_SCLK 89
+#define CLK_VE 90
+#define CLK_AVS 91
+#define CLK_HDMI 92
+#define CLK_HDMI_SLOW 93
+
+#define CLK_MIPI_DSI0 95
+#define CLK_MIPI_DSI1 96
+#define CLK_GPU_CORE 97
+#define CLK_GPU_MEMORY 98
+#define CLK_GPU_HYD 99
+
+#endif /* _DT_BINDINGS_CLOCK_SUN8I_A83T_CCU_H_ */
diff --git a/include/dt-bindings/reset/sun8i-a83t-ccu.h b/include/dt-bindings/reset/sun8i-a83t-ccu.h
new file mode 100644
index 000000000000..784f6e11664e
--- /dev/null
+++ b/include/dt-bindings/reset/sun8i-a83t-ccu.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2017 Chen-Yu Tsai <wens@csie.org>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _DT_BINDINGS_RESET_SUN8I_A83T_CCU_H_
+#define _DT_BINDINGS_RESET_SUN8I_A83T_CCU_H_
+
+#define RST_USB_PHY0 0
+#define RST_USB_PHY1 1
+#define RST_USB_HSIC 2
+
+#define RST_DRAM 3
+#define RST_MBUS 4
+
+#define RST_BUS_MIPI_DSI 5
+#define RST_BUS_SS 6
+#define RST_BUS_DMA 7
+#define RST_BUS_MMC0 8
+#define RST_BUS_MMC1 9
+#define RST_BUS_MMC2 10
+#define RST_BUS_NAND 11
+#define RST_BUS_DRAM 12
+#define RST_BUS_EMAC 13
+#define RST_BUS_HSTIMER 14
+#define RST_BUS_SPI0 15
+#define RST_BUS_SPI1 16
+#define RST_BUS_OTG 17
+#define RST_BUS_EHCI0 18
+#define RST_BUS_EHCI1 19
+#define RST_BUS_OHCI0 20
+
+#define RST_BUS_VE 21
+#define RST_BUS_TCON0 22
+#define RST_BUS_TCON1 23
+#define RST_BUS_CSI 24
+#define RST_BUS_HDMI0 25
+#define RST_BUS_HDMI1 26
+#define RST_BUS_DE 27
+#define RST_BUS_GPU 28
+#define RST_BUS_MSGBOX 29
+#define RST_BUS_SPINLOCK 30
+
+#define RST_BUS_LVDS 31
+
+#define RST_BUS_SPDIF 32
+#define RST_BUS_I2S0 33
+#define RST_BUS_I2S1 34
+#define RST_BUS_I2S2 35
+#define RST_BUS_TDM 36
+
+#define RST_BUS_I2C0 37
+#define RST_BUS_I2C1 38
+#define RST_BUS_I2C2 39
+#define RST_BUS_UART0 40
+#define RST_BUS_UART1 41
+#define RST_BUS_UART2 42
+#define RST_BUS_UART3 43
+#define RST_BUS_UART4 44
+
+#endif /* _DT_BINDINGS_RESET_SUN8I_A83T_CCU_H_ */
--
2.11.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 5/5] ARM: dts: sun8i-a83t: Add CCU device nodes
2017-02-14 3:35 ` Chen-Yu Tsai
@ 2017-02-14 3:35 ` Chen-Yu Tsai
-1 siblings, 0 replies; 38+ messages in thread
From: Chen-Yu Tsai @ 2017-02-14 3:35 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Maxime Ripard
Cc: Chen-Yu Tsai, linux-clk, linux-arm-kernel, linux-kernel
Now that we have support for the A83T CCU, add a device node for it,
and replace any existing placeholder clock phandles with the correct
ones.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
arch/arm/boot/dts/sun8i-a83t.dtsi | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boot/dts/sun8i-a83t.dtsi b/arch/arm/boot/dts/sun8i-a83t.dtsi
index 79eaa7139f43..b78c831e8294 100644
--- a/arch/arm/boot/dts/sun8i-a83t.dtsi
+++ b/arch/arm/boot/dts/sun8i-a83t.dtsi
@@ -47,7 +47,9 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/clock/sun8i-a83t-ccu.h>
#include <dt-bindings/pinctrl/sun4i-a10.h>
+#include <dt-bindings/reset/sun8i-a83t-ccu.h>
/ {
interrupt-parent = <&gic>;
@@ -123,6 +125,7 @@
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <24000000>;
+ clock-accuracy = <50000>;
clock-output-names = "osc24M";
};
@@ -154,13 +157,23 @@
#size-cells = <1>;
ranges;
+ ccu: clock@01c20000 {
+ compatible = "allwinner,sun8i-a83t-ccu";
+ reg = <0x01c20000 0x400>;
+ clocks = <&osc24M>, <&osc16Md512>;
+ clock-names = "hosc", "losc";
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
pio: pinctrl@01c20800 {
compatible = "allwinner,sun8i-a83t-pinctrl";
interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
reg = <0x01c20800 0x400>;
- clocks = <&osc24M>;
+ clocks = <&ccu CLK_BUS_PIO>, <&osc24M>, <&osc16Md512>;
+ clock-names = "apb", "hosc", "losc";
gpio-controller;
interrupt-controller;
#interrupt-cells = <3>;
@@ -206,7 +219,8 @@
interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
reg-io-width = <4>;
- clocks = <&osc24M>;
+ clocks = <&ccu CLK_BUS_UART0>;
+ resets = <&ccu RST_BUS_UART0>;
status = "disabled";
};
--
2.11.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 5/5] ARM: dts: sun8i-a83t: Add CCU device nodes
@ 2017-02-14 3:35 ` Chen-Yu Tsai
0 siblings, 0 replies; 38+ messages in thread
From: Chen-Yu Tsai @ 2017-02-14 3:35 UTC (permalink / raw)
To: linux-arm-kernel
Now that we have support for the A83T CCU, add a device node for it,
and replace any existing placeholder clock phandles with the correct
ones.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
---
arch/arm/boot/dts/sun8i-a83t.dtsi | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boot/dts/sun8i-a83t.dtsi b/arch/arm/boot/dts/sun8i-a83t.dtsi
index 79eaa7139f43..b78c831e8294 100644
--- a/arch/arm/boot/dts/sun8i-a83t.dtsi
+++ b/arch/arm/boot/dts/sun8i-a83t.dtsi
@@ -47,7 +47,9 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/clock/sun8i-a83t-ccu.h>
#include <dt-bindings/pinctrl/sun4i-a10.h>
+#include <dt-bindings/reset/sun8i-a83t-ccu.h>
/ {
interrupt-parent = <&gic>;
@@ -123,6 +125,7 @@
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <24000000>;
+ clock-accuracy = <50000>;
clock-output-names = "osc24M";
};
@@ -154,13 +157,23 @@
#size-cells = <1>;
ranges;
+ ccu: clock at 01c20000 {
+ compatible = "allwinner,sun8i-a83t-ccu";
+ reg = <0x01c20000 0x400>;
+ clocks = <&osc24M>, <&osc16Md512>;
+ clock-names = "hosc", "losc";
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
pio: pinctrl at 01c20800 {
compatible = "allwinner,sun8i-a83t-pinctrl";
interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
reg = <0x01c20800 0x400>;
- clocks = <&osc24M>;
+ clocks = <&ccu CLK_BUS_PIO>, <&osc24M>, <&osc16Md512>;
+ clock-names = "apb", "hosc", "losc";
gpio-controller;
interrupt-controller;
#interrupt-cells = <3>;
@@ -206,7 +219,8 @@
interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
reg-io-width = <4>;
- clocks = <&osc24M>;
+ clocks = <&ccu CLK_BUS_UART0>;
+ resets = <&ccu RST_BUS_UART0>;
status = "disabled";
};
--
2.11.0
^ permalink raw reply related [flat|nested] 38+ messages in thread
* Re: [PATCH 1/5] clk: sunxi-ng: mp: Adjust parent rate for pre-dividers
2017-02-14 3:35 ` Chen-Yu Tsai
@ 2017-02-14 9:34 ` Maxime Ripard
-1 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2017-02-14 9:34 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: Michael Turquette, Stephen Boyd, linux-clk, linux-arm-kernel,
linux-kernel
[-- Attachment #1: Type: text/plain, Size: 794 bytes --]
On Tue, Feb 14, 2017 at 11:35:22AM +0800, Chen-Yu Tsai wrote:
> The MP style clocks support an mux with pre-dividers. While the driver
> correctly accounted for them in the .determine_rate callback, it did
> not in the .recalc_rate and .set_rate callbacks.
>
> This means when calculating the factors in the .set_rate callback, they
> would be off by a factor of the active pre-divider. Same goes for
> reading back the clock rate after it is set.
>
> Fixes: 2ab836db5097 ("clk: sunxi-ng: Add M-P factor clock support")
> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
> ---
>
> Maybe we want to Cc stable for this one?
I've applied it and added the Cc.
Thanks!
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 1/5] clk: sunxi-ng: mp: Adjust parent rate for pre-dividers
@ 2017-02-14 9:34 ` Maxime Ripard
0 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2017-02-14 9:34 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, Feb 14, 2017 at 11:35:22AM +0800, Chen-Yu Tsai wrote:
> The MP style clocks support an mux with pre-dividers. While the driver
> correctly accounted for them in the .determine_rate callback, it did
> not in the .recalc_rate and .set_rate callbacks.
>
> This means when calculating the factors in the .set_rate callback, they
> would be off by a factor of the active pre-divider. Same goes for
> reading back the clock rate after it is set.
>
> Fixes: 2ab836db5097 ("clk: sunxi-ng: Add M-P factor clock support")
> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
> ---
>
> Maybe we want to Cc stable for this one?
I've applied it and added the Cc.
Thanks!
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20170214/1643bd2a/attachment.sig>
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 2/5] clk: sunxi-ng: gate: Support common pre-dividers
2017-02-14 3:35 ` Chen-Yu Tsai
@ 2017-02-14 9:39 ` Maxime Ripard
-1 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2017-02-14 9:39 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: Michael Turquette, Stephen Boyd, linux-clk, linux-arm-kernel,
linux-kernel
[-- Attachment #1: Type: text/plain, Size: 475 bytes --]
On Tue, Feb 14, 2017 at 11:35:23AM +0800, Chen-Yu Tsai wrote:
> Some clock gates have a pre-divider between the source input and the
> gate itself. A notable example is the HSIC 12 MHz clock found on the
> A83T, which has the 24 MHz main oscillator as its input, and a /2
> pre-divider.
>
> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
Applied, thanks!
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 2/5] clk: sunxi-ng: gate: Support common pre-dividers
@ 2017-02-14 9:39 ` Maxime Ripard
0 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2017-02-14 9:39 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, Feb 14, 2017 at 11:35:23AM +0800, Chen-Yu Tsai wrote:
> Some clock gates have a pre-divider between the source input and the
> gate itself. A notable example is the HSIC 12 MHz clock found on the
> A83T, which has the 24 MHz main oscillator as its input, and a /2
> pre-divider.
>
> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
Applied, thanks!
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20170214/1967bfcd/attachment-0001.sig>
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 4/5] clk: sunxi-ng: Add driver for A83T CCU
2017-02-14 3:35 ` Chen-Yu Tsai
@ 2017-02-14 9:58 ` Maxime Ripard
-1 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2017-02-14 9:58 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: Michael Turquette, Stephen Boyd, linux-clk, linux-arm-kernel,
linux-kernel
[-- Attachment #1: Type: text/plain, Size: 2845 bytes --]
On Tue, Feb 14, 2017 at 11:35:25AM +0800, Chen-Yu Tsai wrote:
> +/* Some PLLs are input * N / div1 / P. Model them as NKMP with no K */
Is that even working?
I'm not quite sure we want to do that. We might model it as a NP clock
with a variable prediv?
> +/* Use a separate clock for the pre-divider on the AHB1 PLL-PERIPH input */
> +static SUNXI_CCU_M(pll_periph_ahb1_clk, "pll-periph-ahb1", "pll-periph",
> + 0x054, 6, 2, 0);
> +
> +static const char * const ahb1_parents[] = { "osc16M-d512", "osc24M",
> + "pll-periph-ahb1",
> + "pll-periph-ahb1" };
> +static struct ccu_div ahb1_clk = {
> + .div = _SUNXI_CCU_DIV_FLAGS(4, 2, CLK_DIVIDER_POWER_OF_TWO),
> + .mux = _SUNXI_CCU_MUX(12, 2),
> + .common = {
> + .reg = 0x054,
> + .hw.init = CLK_HW_INIT_PARENTS("ahb1",
> + ahb1_parents,
> + &ccu_div_ops,
> + 0),
> + },
> +};
What's different from a pre divider only for a given index here?
> +/*
> + * MMC2 supports what's called the "new timing mode". The CCU and the MMC
> + * controller must be in sync about which mode is used. The new mode moves
> + * the clock delay controls (and possibly the delay lines) into the MMC
> + * block. Also, the output of the clock is divided by 2. The output and
> + * sample phase clocks are unused under this mode.
> + *
> + * This new mode seems to be preferred. Hence we force this clock to the
> + * new mode. And we don't add the phase clocks.
> + */
I'm sorry, but I said this several times, this isn't working. We
should model it properly, and not hack this around in the clock
driver.
As you say in your comment, the MMC driver needs to be aware about
which mode is used, in order to also set a bit in one of its registers
accordingly, and modify its sampling behaviour.
The new timing is preferred, but our previous clock implementations
didn't hardcode it, so we can't even rely on that behaviour to always
write it in our driver.
This is not something specific to the A83T, but is found in all the
SoCs since the A23, so we need to come up with a good solution to
address that.
I'm not sure what a good solution would be though. One would be to
just have a private function of our own to switch in the new mode (if
relevant, because only the MMC2 controllers have it), but that would
lead to troubles with !sunxi-ng. Not something we can't deal with, but
some extra precautions should be taken (make sure to protect the call
through an ifdef / IS_DEFINED, check that the sunxi-ng driver has been
probed, etc.)
Or we could introduce a new clk_ops function pointer, but I'm not sure
if Mike and Stephen are going to be happy with that.
Thanks,
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 4/5] clk: sunxi-ng: Add driver for A83T CCU
@ 2017-02-14 9:58 ` Maxime Ripard
0 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2017-02-14 9:58 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, Feb 14, 2017 at 11:35:25AM +0800, Chen-Yu Tsai wrote:
> +/* Some PLLs are input * N / div1 / P. Model them as NKMP with no K */
Is that even working?
I'm not quite sure we want to do that. We might model it as a NP clock
with a variable prediv?
> +/* Use a separate clock for the pre-divider on the AHB1 PLL-PERIPH input */
> +static SUNXI_CCU_M(pll_periph_ahb1_clk, "pll-periph-ahb1", "pll-periph",
> + 0x054, 6, 2, 0);
> +
> +static const char * const ahb1_parents[] = { "osc16M-d512", "osc24M",
> + "pll-periph-ahb1",
> + "pll-periph-ahb1" };
> +static struct ccu_div ahb1_clk = {
> + .div = _SUNXI_CCU_DIV_FLAGS(4, 2, CLK_DIVIDER_POWER_OF_TWO),
> + .mux = _SUNXI_CCU_MUX(12, 2),
> + .common = {
> + .reg = 0x054,
> + .hw.init = CLK_HW_INIT_PARENTS("ahb1",
> + ahb1_parents,
> + &ccu_div_ops,
> + 0),
> + },
> +};
What's different from a pre divider only for a given index here?
> +/*
> + * MMC2 supports what's called the "new timing mode". The CCU and the MMC
> + * controller must be in sync about which mode is used. The new mode moves
> + * the clock delay controls (and possibly the delay lines) into the MMC
> + * block. Also, the output of the clock is divided by 2. The output and
> + * sample phase clocks are unused under this mode.
> + *
> + * This new mode seems to be preferred. Hence we force this clock to the
> + * new mode. And we don't add the phase clocks.
> + */
I'm sorry, but I said this several times, this isn't working. We
should model it properly, and not hack this around in the clock
driver.
As you say in your comment, the MMC driver needs to be aware about
which mode is used, in order to also set a bit in one of its registers
accordingly, and modify its sampling behaviour.
The new timing is preferred, but our previous clock implementations
didn't hardcode it, so we can't even rely on that behaviour to always
write it in our driver.
This is not something specific to the A83T, but is found in all the
SoCs since the A23, so we need to come up with a good solution to
address that.
I'm not sure what a good solution would be though. One would be to
just have a private function of our own to switch in the new mode (if
relevant, because only the MMC2 controllers have it), but that would
lead to troubles with !sunxi-ng. Not something we can't deal with, but
some extra precautions should be taken (make sure to protect the call
through an ifdef / IS_DEFINED, check that the sunxi-ng driver has been
probed, etc.)
Or we could introduce a new clk_ops function pointer, but I'm not sure
if Mike and Stephen are going to be happy with that.
Thanks,
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20170214/8bfdcb83/attachment-0001.sig>
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 4/5] clk: sunxi-ng: Add driver for A83T CCU
2017-02-14 9:58 ` Maxime Ripard
@ 2017-02-14 10:26 ` Chen-Yu Tsai
-1 siblings, 0 replies; 38+ messages in thread
From: Chen-Yu Tsai @ 2017-02-14 10:26 UTC (permalink / raw)
To: Maxime Ripard
Cc: Chen-Yu Tsai, Michael Turquette, Stephen Boyd, linux-clk,
linux-arm-kernel, linux-kernel
On Tue, Feb 14, 2017 at 5:58 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> On Tue, Feb 14, 2017 at 11:35:25AM +0800, Chen-Yu Tsai wrote:
>> +/* Some PLLs are input * N / div1 / P. Model them as NKMP with no K */
>
> Is that even working?
Looking at the nkmp clock code, only .recalc_rate will work properly though.
Maybe I could fix up the code so it handles zero width factors.
> I'm not quite sure we want to do that. We might model it as a NP clock
> with a variable prediv?
There's no NP clock type yet. And a problem with a variable prediv is that
it doesn't participate in factor calculation. It's effectively fixed.
I did this for the A80 as well though. Fixing up the NKMP clock might be
easier.
>
>> +/* Use a separate clock for the pre-divider on the AHB1 PLL-PERIPH input */
>> +static SUNXI_CCU_M(pll_periph_ahb1_clk, "pll-periph-ahb1", "pll-periph",
>> + 0x054, 6, 2, 0);
>> +
>> +static const char * const ahb1_parents[] = { "osc16M-d512", "osc24M",
>> + "pll-periph-ahb1",
>> + "pll-periph-ahb1" };
>> +static struct ccu_div ahb1_clk = {
>> + .div = _SUNXI_CCU_DIV_FLAGS(4, 2, CLK_DIVIDER_POWER_OF_TWO),
>> + .mux = _SUNXI_CCU_MUX(12, 2),
>> + .common = {
>> + .reg = 0x054,
>> + .hw.init = CLK_HW_INIT_PARENTS("ahb1",
>> + ahb1_parents,
>> + &ccu_div_ops,
>> + 0),
>> + },
>> +};
>
> What's different from a pre divider only for a given index here?
The variable pre-divider is shared for both pll-periph mux inputs.
This is one way to handle it. The other would be to extend ccu_mux
to handle multiple variable pre-dividers. I don't really want to do
that if this is the only instance that needs it though.
>
>> +/*
>> + * MMC2 supports what's called the "new timing mode". The CCU and the MMC
>> + * controller must be in sync about which mode is used. The new mode moves
>> + * the clock delay controls (and possibly the delay lines) into the MMC
>> + * block. Also, the output of the clock is divided by 2. The output and
>> + * sample phase clocks are unused under this mode.
>> + *
>> + * This new mode seems to be preferred. Hence we force this clock to the
>> + * new mode. And we don't add the phase clocks.
>> + */
>
> I'm sorry, but I said this several times, this isn't working. We
> should model it properly, and not hack this around in the clock
> driver.
>
> As you say in your comment, the MMC driver needs to be aware about
> which mode is used, in order to also set a bit in one of its registers
> accordingly, and modify its sampling behaviour.
>
> The new timing is preferred, but our previous clock implementations
> didn't hardcode it, so we can't even rely on that behaviour to always
> write it in our driver.
Correct. With the A83T there has never been a merged clock driver though.
I realize this is a one off thing.
> This is not something specific to the A83T, but is found in all the
> SoCs since the A23, so we need to come up with a good solution to
> address that.
>
> I'm not sure what a good solution would be though. One would be to
> just have a private function of our own to switch in the new mode (if
> relevant, because only the MMC2 controllers have it), but that would
> lead to troubles with !sunxi-ng. Not something we can't deal with, but
> some extra precautions should be taken (make sure to protect the call
> through an ifdef / IS_DEFINED, check that the sunxi-ng driver has been
> probed, etc.)
If the custom function route is acceptable, I'll come up with something.
Regards
ChenYu
>
> Or we could introduce a new clk_ops function pointer, but I'm not sure
> if Mike and Stephen are going to be happy with that.
>
> Thanks,
> Maxime
>
> --
> Maxime Ripard, Free Electrons
> Embedded Linux and Kernel engineering
> http://free-electrons.com
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 4/5] clk: sunxi-ng: Add driver for A83T CCU
@ 2017-02-14 10:26 ` Chen-Yu Tsai
0 siblings, 0 replies; 38+ messages in thread
From: Chen-Yu Tsai @ 2017-02-14 10:26 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, Feb 14, 2017 at 5:58 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> On Tue, Feb 14, 2017 at 11:35:25AM +0800, Chen-Yu Tsai wrote:
>> +/* Some PLLs are input * N / div1 / P. Model them as NKMP with no K */
>
> Is that even working?
Looking at the nkmp clock code, only .recalc_rate will work properly though.
Maybe I could fix up the code so it handles zero width factors.
> I'm not quite sure we want to do that. We might model it as a NP clock
> with a variable prediv?
There's no NP clock type yet. And a problem with a variable prediv is that
it doesn't participate in factor calculation. It's effectively fixed.
I did this for the A80 as well though. Fixing up the NKMP clock might be
easier.
>
>> +/* Use a separate clock for the pre-divider on the AHB1 PLL-PERIPH input */
>> +static SUNXI_CCU_M(pll_periph_ahb1_clk, "pll-periph-ahb1", "pll-periph",
>> + 0x054, 6, 2, 0);
>> +
>> +static const char * const ahb1_parents[] = { "osc16M-d512", "osc24M",
>> + "pll-periph-ahb1",
>> + "pll-periph-ahb1" };
>> +static struct ccu_div ahb1_clk = {
>> + .div = _SUNXI_CCU_DIV_FLAGS(4, 2, CLK_DIVIDER_POWER_OF_TWO),
>> + .mux = _SUNXI_CCU_MUX(12, 2),
>> + .common = {
>> + .reg = 0x054,
>> + .hw.init = CLK_HW_INIT_PARENTS("ahb1",
>> + ahb1_parents,
>> + &ccu_div_ops,
>> + 0),
>> + },
>> +};
>
> What's different from a pre divider only for a given index here?
The variable pre-divider is shared for both pll-periph mux inputs.
This is one way to handle it. The other would be to extend ccu_mux
to handle multiple variable pre-dividers. I don't really want to do
that if this is the only instance that needs it though.
>
>> +/*
>> + * MMC2 supports what's called the "new timing mode". The CCU and the MMC
>> + * controller must be in sync about which mode is used. The new mode moves
>> + * the clock delay controls (and possibly the delay lines) into the MMC
>> + * block. Also, the output of the clock is divided by 2. The output and
>> + * sample phase clocks are unused under this mode.
>> + *
>> + * This new mode seems to be preferred. Hence we force this clock to the
>> + * new mode. And we don't add the phase clocks.
>> + */
>
> I'm sorry, but I said this several times, this isn't working. We
> should model it properly, and not hack this around in the clock
> driver.
>
> As you say in your comment, the MMC driver needs to be aware about
> which mode is used, in order to also set a bit in one of its registers
> accordingly, and modify its sampling behaviour.
>
> The new timing is preferred, but our previous clock implementations
> didn't hardcode it, so we can't even rely on that behaviour to always
> write it in our driver.
Correct. With the A83T there has never been a merged clock driver though.
I realize this is a one off thing.
> This is not something specific to the A83T, but is found in all the
> SoCs since the A23, so we need to come up with a good solution to
> address that.
>
> I'm not sure what a good solution would be though. One would be to
> just have a private function of our own to switch in the new mode (if
> relevant, because only the MMC2 controllers have it), but that would
> lead to troubles with !sunxi-ng. Not something we can't deal with, but
> some extra precautions should be taken (make sure to protect the call
> through an ifdef / IS_DEFINED, check that the sunxi-ng driver has been
> probed, etc.)
If the custom function route is acceptable, I'll come up with something.
Regards
ChenYu
>
> Or we could introduce a new clk_ops function pointer, but I'm not sure
> if Mike and Stephen are going to be happy with that.
>
> Thanks,
> Maxime
>
> --
> Maxime Ripard, Free Electrons
> Embedded Linux and Kernel engineering
> http://free-electrons.com
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 4/5] clk: sunxi-ng: Add driver for A83T CCU
2017-02-14 10:26 ` Chen-Yu Tsai
@ 2017-02-15 9:49 ` Maxime Ripard
-1 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2017-02-15 9:49 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: Michael Turquette, Stephen Boyd, linux-clk, linux-arm-kernel,
linux-kernel
[-- Attachment #1: Type: text/plain, Size: 4780 bytes --]
On Tue, Feb 14, 2017 at 06:26:39PM +0800, Chen-Yu Tsai wrote:
> On Tue, Feb 14, 2017 at 5:58 PM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
> > On Tue, Feb 14, 2017 at 11:35:25AM +0800, Chen-Yu Tsai wrote:
> >> +/* Some PLLs are input * N / div1 / P. Model them as NKMP with no K */
> >
> > Is that even working?
>
> Looking at the nkmp clock code, only .recalc_rate will work properly though.
> Maybe I could fix up the code so it handles zero width factors.
>
> > I'm not quite sure we want to do that. We might model it as a NP clock
> > with a variable prediv?
>
> There's no NP clock type yet. And a problem with a variable prediv is that
> it doesn't participate in factor calculation. It's effectively fixed.
>
> I did this for the A80 as well though. Fixing up the NKMP clock might be
> easier.
Then maybe we just need a NMP clock type then. What I'm really afraid
of is that we'll just end up in a clk-factors situation that was
simply impossible to maintain without breaking anything, hence why we
had different clock types then.
> >
> >> +/* Use a separate clock for the pre-divider on the AHB1 PLL-PERIPH input */
> >> +static SUNXI_CCU_M(pll_periph_ahb1_clk, "pll-periph-ahb1", "pll-periph",
> >> + 0x054, 6, 2, 0);
> >> +
> >> +static const char * const ahb1_parents[] = { "osc16M-d512", "osc24M",
> >> + "pll-periph-ahb1",
> >> + "pll-periph-ahb1" };
> >> +static struct ccu_div ahb1_clk = {
> >> + .div = _SUNXI_CCU_DIV_FLAGS(4, 2, CLK_DIVIDER_POWER_OF_TWO),
> >> + .mux = _SUNXI_CCU_MUX(12, 2),
> >> + .common = {
> >> + .reg = 0x054,
> >> + .hw.init = CLK_HW_INIT_PARENTS("ahb1",
> >> + ahb1_parents,
> >> + &ccu_div_ops,
> >> + 0),
> >> + },
> >> +};
> >
> > What's different from a pre divider only for a given index here?
>
> The variable pre-divider is shared for both pll-periph mux inputs.
> This is one way to handle it. The other would be to extend ccu_mux
> to handle multiple variable pre-dividers. I don't really want to do
> that if this is the only instance that needs it though.
Every addition we made was only needed by one instance at first :)
We are working that way for fixed pre-dividers already, I don't see
why we can't have it for variable ones too.
> >> +/*
> >> + * MMC2 supports what's called the "new timing mode". The CCU and the MMC
> >> + * controller must be in sync about which mode is used. The new mode moves
> >> + * the clock delay controls (and possibly the delay lines) into the MMC
> >> + * block. Also, the output of the clock is divided by 2. The output and
> >> + * sample phase clocks are unused under this mode.
> >> + *
> >> + * This new mode seems to be preferred. Hence we force this clock to the
> >> + * new mode. And we don't add the phase clocks.
> >> + */
> >
> > I'm sorry, but I said this several times, this isn't working. We
> > should model it properly, and not hack this around in the clock
> > driver.
> >
> > As you say in your comment, the MMC driver needs to be aware about
> > which mode is used, in order to also set a bit in one of its registers
> > accordingly, and modify its sampling behaviour.
> >
> > The new timing is preferred, but our previous clock implementations
> > didn't hardcode it, so we can't even rely on that behaviour to always
> > write it in our driver.
>
> Correct. With the A83T there has never been a merged clock driver though.
> I realize this is a one off thing.
>
> > This is not something specific to the A83T, but is found in all the
> > SoCs since the A23, so we need to come up with a good solution to
> > address that.
> >
> > I'm not sure what a good solution would be though. One would be to
> > just have a private function of our own to switch in the new mode (if
> > relevant, because only the MMC2 controllers have it), but that would
> > lead to troubles with !sunxi-ng. Not something we can't deal with, but
> > some extra precautions should be taken (make sure to protect the call
> > through an ifdef / IS_DEFINED, check that the sunxi-ng driver has been
> > probed, etc.)
>
> If the custom function route is acceptable, I'll come up with something.
I think it would be a great start yes. I'll try to discuss it with
Mike and Stephen at ELC and see what they think about that.
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 4/5] clk: sunxi-ng: Add driver for A83T CCU
@ 2017-02-15 9:49 ` Maxime Ripard
0 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2017-02-15 9:49 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, Feb 14, 2017 at 06:26:39PM +0800, Chen-Yu Tsai wrote:
> On Tue, Feb 14, 2017 at 5:58 PM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
> > On Tue, Feb 14, 2017 at 11:35:25AM +0800, Chen-Yu Tsai wrote:
> >> +/* Some PLLs are input * N / div1 / P. Model them as NKMP with no K */
> >
> > Is that even working?
>
> Looking at the nkmp clock code, only .recalc_rate will work properly though.
> Maybe I could fix up the code so it handles zero width factors.
>
> > I'm not quite sure we want to do that. We might model it as a NP clock
> > with a variable prediv?
>
> There's no NP clock type yet. And a problem with a variable prediv is that
> it doesn't participate in factor calculation. It's effectively fixed.
>
> I did this for the A80 as well though. Fixing up the NKMP clock might be
> easier.
Then maybe we just need a NMP clock type then. What I'm really afraid
of is that we'll just end up in a clk-factors situation that was
simply impossible to maintain without breaking anything, hence why we
had different clock types then.
> >
> >> +/* Use a separate clock for the pre-divider on the AHB1 PLL-PERIPH input */
> >> +static SUNXI_CCU_M(pll_periph_ahb1_clk, "pll-periph-ahb1", "pll-periph",
> >> + 0x054, 6, 2, 0);
> >> +
> >> +static const char * const ahb1_parents[] = { "osc16M-d512", "osc24M",
> >> + "pll-periph-ahb1",
> >> + "pll-periph-ahb1" };
> >> +static struct ccu_div ahb1_clk = {
> >> + .div = _SUNXI_CCU_DIV_FLAGS(4, 2, CLK_DIVIDER_POWER_OF_TWO),
> >> + .mux = _SUNXI_CCU_MUX(12, 2),
> >> + .common = {
> >> + .reg = 0x054,
> >> + .hw.init = CLK_HW_INIT_PARENTS("ahb1",
> >> + ahb1_parents,
> >> + &ccu_div_ops,
> >> + 0),
> >> + },
> >> +};
> >
> > What's different from a pre divider only for a given index here?
>
> The variable pre-divider is shared for both pll-periph mux inputs.
> This is one way to handle it. The other would be to extend ccu_mux
> to handle multiple variable pre-dividers. I don't really want to do
> that if this is the only instance that needs it though.
Every addition we made was only needed by one instance at first :)
We are working that way for fixed pre-dividers already, I don't see
why we can't have it for variable ones too.
> >> +/*
> >> + * MMC2 supports what's called the "new timing mode". The CCU and the MMC
> >> + * controller must be in sync about which mode is used. The new mode moves
> >> + * the clock delay controls (and possibly the delay lines) into the MMC
> >> + * block. Also, the output of the clock is divided by 2. The output and
> >> + * sample phase clocks are unused under this mode.
> >> + *
> >> + * This new mode seems to be preferred. Hence we force this clock to the
> >> + * new mode. And we don't add the phase clocks.
> >> + */
> >
> > I'm sorry, but I said this several times, this isn't working. We
> > should model it properly, and not hack this around in the clock
> > driver.
> >
> > As you say in your comment, the MMC driver needs to be aware about
> > which mode is used, in order to also set a bit in one of its registers
> > accordingly, and modify its sampling behaviour.
> >
> > The new timing is preferred, but our previous clock implementations
> > didn't hardcode it, so we can't even rely on that behaviour to always
> > write it in our driver.
>
> Correct. With the A83T there has never been a merged clock driver though.
> I realize this is a one off thing.
>
> > This is not something specific to the A83T, but is found in all the
> > SoCs since the A23, so we need to come up with a good solution to
> > address that.
> >
> > I'm not sure what a good solution would be though. One would be to
> > just have a private function of our own to switch in the new mode (if
> > relevant, because only the MMC2 controllers have it), but that would
> > lead to troubles with !sunxi-ng. Not something we can't deal with, but
> > some extra precautions should be taken (make sure to protect the call
> > through an ifdef / IS_DEFINED, check that the sunxi-ng driver has been
> > probed, etc.)
>
> If the custom function route is acceptable, I'll come up with something.
I think it would be a great start yes. I'll try to discuss it with
Mike and Stephen at ELC and see what they think about that.
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20170215/ef3f162e/attachment-0001.sig>
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 4/5] clk: sunxi-ng: Add driver for A83T CCU
2017-02-15 9:49 ` Maxime Ripard
@ 2017-03-01 19:17 ` Stephen Boyd
-1 siblings, 0 replies; 38+ messages in thread
From: Stephen Boyd @ 2017-03-01 19:17 UTC (permalink / raw)
To: Maxime Ripard
Cc: Chen-Yu Tsai, Michael Turquette, linux-clk, linux-arm-kernel,
linux-kernel
On 02/15, Maxime Ripard wrote:
> On Tue, Feb 14, 2017 at 06:26:39PM +0800, Chen-Yu Tsai wrote:
> > On Tue, Feb 14, 2017 at 5:58 PM, Maxime Ripard
> > <maxime.ripard@free-electrons.com> wrote:
> > > On Tue, Feb 14, 2017 at 11:35:25AM +0800, Chen-Yu Tsai wrote:
> > >> +/*
> > >> + * MMC2 supports what's called the "new timing mode". The CCU and the MMC
> > >> + * controller must be in sync about which mode is used. The new mode moves
> > >> + * the clock delay controls (and possibly the delay lines) into the MMC
> > >> + * block. Also, the output of the clock is divided by 2. The output and
> > >> + * sample phase clocks are unused under this mode.
> > >> + *
> > >> + * This new mode seems to be preferred. Hence we force this clock to the
> > >> + * new mode. And we don't add the phase clocks.
> > >> + */
> > >
> > > I'm sorry, but I said this several times, this isn't working. We
> > > should model it properly, and not hack this around in the clock
> > > driver.
> > >
> > > As you say in your comment, the MMC driver needs to be aware about
> > > which mode is used, in order to also set a bit in one of its registers
> > > accordingly, and modify its sampling behaviour.
> > >
> > > The new timing is preferred, but our previous clock implementations
> > > didn't hardcode it, so we can't even rely on that behaviour to always
> > > write it in our driver.
> >
> > Correct. With the A83T there has never been a merged clock driver though.
> > I realize this is a one off thing.
> >
> > > This is not something specific to the A83T, but is found in all the
> > > SoCs since the A23, so we need to come up with a good solution to
> > > address that.
> > >
> > > I'm not sure what a good solution would be though. One would be to
> > > just have a private function of our own to switch in the new mode (if
> > > relevant, because only the MMC2 controllers have it), but that would
> > > lead to troubles with !sunxi-ng. Not something we can't deal with, but
> > > some extra precautions should be taken (make sure to protect the call
> > > through an ifdef / IS_DEFINED, check that the sunxi-ng driver has been
> > > probed, etc.)
> >
> > If the custom function route is acceptable, I'll come up with something.
>
> I think it would be a great start yes. I'll try to discuss it with
> Mike and Stephen at ELC and see what they think about that.
>
I didn't hear anything at ELC. Can someone explain what the issue
is? Could something like clk_get_phase() + clk_get_rate() tell us
if we're in one mode vs. the other?
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 4/5] clk: sunxi-ng: Add driver for A83T CCU
@ 2017-03-01 19:17 ` Stephen Boyd
0 siblings, 0 replies; 38+ messages in thread
From: Stephen Boyd @ 2017-03-01 19:17 UTC (permalink / raw)
To: linux-arm-kernel
On 02/15, Maxime Ripard wrote:
> On Tue, Feb 14, 2017 at 06:26:39PM +0800, Chen-Yu Tsai wrote:
> > On Tue, Feb 14, 2017 at 5:58 PM, Maxime Ripard
> > <maxime.ripard@free-electrons.com> wrote:
> > > On Tue, Feb 14, 2017 at 11:35:25AM +0800, Chen-Yu Tsai wrote:
> > >> +/*
> > >> + * MMC2 supports what's called the "new timing mode". The CCU and the MMC
> > >> + * controller must be in sync about which mode is used. The new mode moves
> > >> + * the clock delay controls (and possibly the delay lines) into the MMC
> > >> + * block. Also, the output of the clock is divided by 2. The output and
> > >> + * sample phase clocks are unused under this mode.
> > >> + *
> > >> + * This new mode seems to be preferred. Hence we force this clock to the
> > >> + * new mode. And we don't add the phase clocks.
> > >> + */
> > >
> > > I'm sorry, but I said this several times, this isn't working. We
> > > should model it properly, and not hack this around in the clock
> > > driver.
> > >
> > > As you say in your comment, the MMC driver needs to be aware about
> > > which mode is used, in order to also set a bit in one of its registers
> > > accordingly, and modify its sampling behaviour.
> > >
> > > The new timing is preferred, but our previous clock implementations
> > > didn't hardcode it, so we can't even rely on that behaviour to always
> > > write it in our driver.
> >
> > Correct. With the A83T there has never been a merged clock driver though.
> > I realize this is a one off thing.
> >
> > > This is not something specific to the A83T, but is found in all the
> > > SoCs since the A23, so we need to come up with a good solution to
> > > address that.
> > >
> > > I'm not sure what a good solution would be though. One would be to
> > > just have a private function of our own to switch in the new mode (if
> > > relevant, because only the MMC2 controllers have it), but that would
> > > lead to troubles with !sunxi-ng. Not something we can't deal with, but
> > > some extra precautions should be taken (make sure to protect the call
> > > through an ifdef / IS_DEFINED, check that the sunxi-ng driver has been
> > > probed, etc.)
> >
> > If the custom function route is acceptable, I'll come up with something.
>
> I think it would be a great start yes. I'll try to discuss it with
> Mike and Stephen at ELC and see what they think about that.
>
I didn't hear anything at ELC. Can someone explain what the issue
is? Could something like clk_get_phase() + clk_get_rate() tell us
if we're in one mode vs. the other?
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 4/5] clk: sunxi-ng: Add driver for A83T CCU
2017-03-01 19:17 ` Stephen Boyd
@ 2017-03-03 9:53 ` Maxime Ripard
-1 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2017-03-03 9:53 UTC (permalink / raw)
To: Stephen Boyd
Cc: Chen-Yu Tsai, Michael Turquette, linux-clk, linux-arm-kernel,
linux-kernel
[-- Attachment #1: Type: text/plain, Size: 3928 bytes --]
Hi Stephen
On Wed, Mar 01, 2017 at 11:17:05AM -0800, Stephen Boyd wrote:
> On 02/15, Maxime Ripard wrote:
> > On Tue, Feb 14, 2017 at 06:26:39PM +0800, Chen-Yu Tsai wrote:
> > > On Tue, Feb 14, 2017 at 5:58 PM, Maxime Ripard
> > > <maxime.ripard@free-electrons.com> wrote:
> > > > On Tue, Feb 14, 2017 at 11:35:25AM +0800, Chen-Yu Tsai wrote:
> > > >> +/*
> > > >> + * MMC2 supports what's called the "new timing mode". The CCU and the MMC
> > > >> + * controller must be in sync about which mode is used. The new mode moves
> > > >> + * the clock delay controls (and possibly the delay lines) into the MMC
> > > >> + * block. Also, the output of the clock is divided by 2. The output and
> > > >> + * sample phase clocks are unused under this mode.
> > > >> + *
> > > >> + * This new mode seems to be preferred. Hence we force this clock to the
> > > >> + * new mode. And we don't add the phase clocks.
> > > >> + */
> > > >
> > > > I'm sorry, but I said this several times, this isn't working. We
> > > > should model it properly, and not hack this around in the clock
> > > > driver.
> > > >
> > > > As you say in your comment, the MMC driver needs to be aware about
> > > > which mode is used, in order to also set a bit in one of its registers
> > > > accordingly, and modify its sampling behaviour.
> > > >
> > > > The new timing is preferred, but our previous clock implementations
> > > > didn't hardcode it, so we can't even rely on that behaviour to always
> > > > write it in our driver.
> > >
> > > Correct. With the A83T there has never been a merged clock driver though.
> > > I realize this is a one off thing.
> > >
> > > > This is not something specific to the A83T, but is found in all the
> > > > SoCs since the A23, so we need to come up with a good solution to
> > > > address that.
> > > >
> > > > I'm not sure what a good solution would be though. One would be to
> > > > just have a private function of our own to switch in the new mode (if
> > > > relevant, because only the MMC2 controllers have it), but that would
> > > > lead to troubles with !sunxi-ng. Not something we can't deal with, but
> > > > some extra precautions should be taken (make sure to protect the call
> > > > through an ifdef / IS_DEFINED, check that the sunxi-ng driver has been
> > > > probed, etc.)
> > >
> > > If the custom function route is acceptable, I'll come up with something.
> >
> > I think it would be a great start yes. I'll try to discuss it with
> > Mike and Stephen at ELC and see what they think about that.
> >
>
> I didn't hear anything at ELC.
Yeah, sorry, I ended up discussing this with Mike.
> Can someone explain what the issue is? Could something like
> clk_get_phase() + clk_get_rate() tell us if we're in one mode
> vs. the other?
So we have two modes of operation for that clock, old vs new (I know,
I didn't pick the names).
The old mode is what we support right now. It has a combination of a
linear multiplier and divider, plus some phase controls.
The new mode however disables the phase controls and adds post-divider
of 2 on the rate.
We cannot really rely on the rate itself, since there's a huge overlap
between the rates we can obtain in the old and new modes. Same thing
for the phase, having a 0 deg phase is achieved both in the old and
new modes.
To make things worse, the new mode is only available on one out of
three MMC controllers (and associated clocks), and that MMC controller
needs to set a bit as well to switch to the new mode if needed. So we
definitely needs some synchronisation there, and also to be able to
retrieve if the mode switching is available, and if we're already
using that mode.
Mike agreed that the easiest way forward was to use a custom function.
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 4/5] clk: sunxi-ng: Add driver for A83T CCU
@ 2017-03-03 9:53 ` Maxime Ripard
0 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2017-03-03 9:53 UTC (permalink / raw)
To: linux-arm-kernel
Hi Stephen
On Wed, Mar 01, 2017 at 11:17:05AM -0800, Stephen Boyd wrote:
> On 02/15, Maxime Ripard wrote:
> > On Tue, Feb 14, 2017 at 06:26:39PM +0800, Chen-Yu Tsai wrote:
> > > On Tue, Feb 14, 2017 at 5:58 PM, Maxime Ripard
> > > <maxime.ripard@free-electrons.com> wrote:
> > > > On Tue, Feb 14, 2017 at 11:35:25AM +0800, Chen-Yu Tsai wrote:
> > > >> +/*
> > > >> + * MMC2 supports what's called the "new timing mode". The CCU and the MMC
> > > >> + * controller must be in sync about which mode is used. The new mode moves
> > > >> + * the clock delay controls (and possibly the delay lines) into the MMC
> > > >> + * block. Also, the output of the clock is divided by 2. The output and
> > > >> + * sample phase clocks are unused under this mode.
> > > >> + *
> > > >> + * This new mode seems to be preferred. Hence we force this clock to the
> > > >> + * new mode. And we don't add the phase clocks.
> > > >> + */
> > > >
> > > > I'm sorry, but I said this several times, this isn't working. We
> > > > should model it properly, and not hack this around in the clock
> > > > driver.
> > > >
> > > > As you say in your comment, the MMC driver needs to be aware about
> > > > which mode is used, in order to also set a bit in one of its registers
> > > > accordingly, and modify its sampling behaviour.
> > > >
> > > > The new timing is preferred, but our previous clock implementations
> > > > didn't hardcode it, so we can't even rely on that behaviour to always
> > > > write it in our driver.
> > >
> > > Correct. With the A83T there has never been a merged clock driver though.
> > > I realize this is a one off thing.
> > >
> > > > This is not something specific to the A83T, but is found in all the
> > > > SoCs since the A23, so we need to come up with a good solution to
> > > > address that.
> > > >
> > > > I'm not sure what a good solution would be though. One would be to
> > > > just have a private function of our own to switch in the new mode (if
> > > > relevant, because only the MMC2 controllers have it), but that would
> > > > lead to troubles with !sunxi-ng. Not something we can't deal with, but
> > > > some extra precautions should be taken (make sure to protect the call
> > > > through an ifdef / IS_DEFINED, check that the sunxi-ng driver has been
> > > > probed, etc.)
> > >
> > > If the custom function route is acceptable, I'll come up with something.
> >
> > I think it would be a great start yes. I'll try to discuss it with
> > Mike and Stephen at ELC and see what they think about that.
> >
>
> I didn't hear anything at ELC.
Yeah, sorry, I ended up discussing this with Mike.
> Can someone explain what the issue is? Could something like
> clk_get_phase() + clk_get_rate() tell us if we're in one mode
> vs. the other?
So we have two modes of operation for that clock, old vs new (I know,
I didn't pick the names).
The old mode is what we support right now. It has a combination of a
linear multiplier and divider, plus some phase controls.
The new mode however disables the phase controls and adds post-divider
of 2 on the rate.
We cannot really rely on the rate itself, since there's a huge overlap
between the rates we can obtain in the old and new modes. Same thing
for the phase, having a 0 deg phase is achieved both in the old and
new modes.
To make things worse, the new mode is only available on one out of
three MMC controllers (and associated clocks), and that MMC controller
needs to set a bit as well to switch to the new mode if needed. So we
definitely needs some synchronisation there, and also to be able to
retrieve if the mode switching is available, and if we're already
using that mode.
Mike agreed that the easiest way forward was to use a custom function.
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20170303/09254849/attachment.sig>
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 4/5] clk: sunxi-ng: Add driver for A83T CCU
2017-03-03 9:53 ` Maxime Ripard
@ 2017-03-03 23:56 ` Stephen Boyd
-1 siblings, 0 replies; 38+ messages in thread
From: Stephen Boyd @ 2017-03-03 23:56 UTC (permalink / raw)
To: Maxime Ripard
Cc: Chen-Yu Tsai, Michael Turquette, linux-clk, linux-arm-kernel,
linux-kernel
On 03/03, Maxime Ripard wrote:
> On Wed, Mar 01, 2017 at 11:17:05AM -0800, Stephen Boyd wrote:
>
> > Can someone explain what the issue is? Could something like
> > clk_get_phase() + clk_get_rate() tell us if we're in one mode
> > vs. the other?
>
> So we have two modes of operation for that clock, old vs new (I know,
> I didn't pick the names).
>
> The old mode is what we support right now. It has a combination of a
> linear multiplier and divider, plus some phase controls.
>
> The new mode however disables the phase controls and adds post-divider
> of 2 on the rate.
>
> We cannot really rely on the rate itself, since there's a huge overlap
> between the rates we can obtain in the old and new modes. Same thing
> for the phase, having a 0 deg phase is achieved both in the old and
> new modes.
>
> To make things worse, the new mode is only available on one out of
> three MMC controllers (and associated clocks), and that MMC controller
> needs to set a bit as well to switch to the new mode if needed. So we
> definitely needs some synchronisation there, and also to be able to
> retrieve if the mode switching is available, and if we're already
> using that mode.
>
> Mike agreed that the easiest way forward was to use a custom function.
>
Ok. Is there any need to change the mode dynamically at runtime?
Or could it be decided once at clk driver probe time/boot time
and detected via set_phase() failing when we're in the new mode?
At least, it sounds like set_phase() should bail out there
because it doesn't exist, although it could be argued that
setting the phase to something it already is set to is valid and
shouldn't return an error.
I'm not saying I'm opposed to the custom function, just thinking
of alternatives if MMC maintainers don't agree with the custom
function.
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 4/5] clk: sunxi-ng: Add driver for A83T CCU
@ 2017-03-03 23:56 ` Stephen Boyd
0 siblings, 0 replies; 38+ messages in thread
From: Stephen Boyd @ 2017-03-03 23:56 UTC (permalink / raw)
To: linux-arm-kernel
On 03/03, Maxime Ripard wrote:
> On Wed, Mar 01, 2017 at 11:17:05AM -0800, Stephen Boyd wrote:
>
> > Can someone explain what the issue is? Could something like
> > clk_get_phase() + clk_get_rate() tell us if we're in one mode
> > vs. the other?
>
> So we have two modes of operation for that clock, old vs new (I know,
> I didn't pick the names).
>
> The old mode is what we support right now. It has a combination of a
> linear multiplier and divider, plus some phase controls.
>
> The new mode however disables the phase controls and adds post-divider
> of 2 on the rate.
>
> We cannot really rely on the rate itself, since there's a huge overlap
> between the rates we can obtain in the old and new modes. Same thing
> for the phase, having a 0 deg phase is achieved both in the old and
> new modes.
>
> To make things worse, the new mode is only available on one out of
> three MMC controllers (and associated clocks), and that MMC controller
> needs to set a bit as well to switch to the new mode if needed. So we
> definitely needs some synchronisation there, and also to be able to
> retrieve if the mode switching is available, and if we're already
> using that mode.
>
> Mike agreed that the easiest way forward was to use a custom function.
>
Ok. Is there any need to change the mode dynamically at runtime?
Or could it be decided once at clk driver probe time/boot time
and detected via set_phase() failing when we're in the new mode?
At least, it sounds like set_phase() should bail out there
because it doesn't exist, although it could be argued that
setting the phase to something it already is set to is valid and
shouldn't return an error.
I'm not saying I'm opposed to the custom function, just thinking
of alternatives if MMC maintainers don't agree with the custom
function.
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 4/5] clk: sunxi-ng: Add driver for A83T CCU
2017-03-03 23:56 ` Stephen Boyd
@ 2017-03-07 14:58 ` Maxime Ripard
-1 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2017-03-07 14:58 UTC (permalink / raw)
To: Stephen Boyd
Cc: Chen-Yu Tsai, Michael Turquette, linux-clk, linux-arm-kernel,
linux-kernel
[-- Attachment #1: Type: text/plain, Size: 2655 bytes --]
Hi Stephen,
On Fri, Mar 03, 2017 at 03:56:39PM -0800, Stephen Boyd wrote:
> On 03/03, Maxime Ripard wrote:
> > On Wed, Mar 01, 2017 at 11:17:05AM -0800, Stephen Boyd wrote:
> >
> > > Can someone explain what the issue is? Could something like
> > > clk_get_phase() + clk_get_rate() tell us if we're in one mode
> > > vs. the other?
> >
> > So we have two modes of operation for that clock, old vs new (I know,
> > I didn't pick the names).
> >
> > The old mode is what we support right now. It has a combination of a
> > linear multiplier and divider, plus some phase controls.
> >
> > The new mode however disables the phase controls and adds post-divider
> > of 2 on the rate.
> >
> > We cannot really rely on the rate itself, since there's a huge overlap
> > between the rates we can obtain in the old and new modes. Same thing
> > for the phase, having a 0 deg phase is achieved both in the old and
> > new modes.
> >
> > To make things worse, the new mode is only available on one out of
> > three MMC controllers (and associated clocks), and that MMC controller
> > needs to set a bit as well to switch to the new mode if needed. So we
> > definitely needs some synchronisation there, and also to be able to
> > retrieve if the mode switching is available, and if we're already
> > using that mode.
> >
> > Mike agreed that the easiest way forward was to use a custom function.
>
> Ok. Is there any need to change the mode dynamically at runtime?
> Or could it be decided once at clk driver probe time/boot time
> and detected via set_phase() failing when we're in the new mode?
One thing I forgot to mention is that we also still have to support
the old DTs that use our old clock drivers, that will probably never
get to see this new mode. So the first thing we need is being able to
tell whether that mode is supported and if it's already enabled.
And if it's supported, and not enabled, enable it, both in the clock
and MMC drivers.
> At least, it sounds like set_phase() should bail out there
> because it doesn't exist, although it could be argued that
> setting the phase to something it already is set to is valid and
> shouldn't return an error.
Yep, once the new mode is set (disregarding how we do it), we should
prevent any clk_set_phase != 0. We'll also need to adjust the reported
clock rate.
> I'm not saying I'm opposed to the custom function, just thinking
> of alternatives if MMC maintainers don't agree with the custom
> function.
Ok, thanks!
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 4/5] clk: sunxi-ng: Add driver for A83T CCU
@ 2017-03-07 14:58 ` Maxime Ripard
0 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2017-03-07 14:58 UTC (permalink / raw)
To: linux-arm-kernel
Hi Stephen,
On Fri, Mar 03, 2017 at 03:56:39PM -0800, Stephen Boyd wrote:
> On 03/03, Maxime Ripard wrote:
> > On Wed, Mar 01, 2017 at 11:17:05AM -0800, Stephen Boyd wrote:
> >
> > > Can someone explain what the issue is? Could something like
> > > clk_get_phase() + clk_get_rate() tell us if we're in one mode
> > > vs. the other?
> >
> > So we have two modes of operation for that clock, old vs new (I know,
> > I didn't pick the names).
> >
> > The old mode is what we support right now. It has a combination of a
> > linear multiplier and divider, plus some phase controls.
> >
> > The new mode however disables the phase controls and adds post-divider
> > of 2 on the rate.
> >
> > We cannot really rely on the rate itself, since there's a huge overlap
> > between the rates we can obtain in the old and new modes. Same thing
> > for the phase, having a 0 deg phase is achieved both in the old and
> > new modes.
> >
> > To make things worse, the new mode is only available on one out of
> > three MMC controllers (and associated clocks), and that MMC controller
> > needs to set a bit as well to switch to the new mode if needed. So we
> > definitely needs some synchronisation there, and also to be able to
> > retrieve if the mode switching is available, and if we're already
> > using that mode.
> >
> > Mike agreed that the easiest way forward was to use a custom function.
>
> Ok. Is there any need to change the mode dynamically at runtime?
> Or could it be decided once at clk driver probe time/boot time
> and detected via set_phase() failing when we're in the new mode?
One thing I forgot to mention is that we also still have to support
the old DTs that use our old clock drivers, that will probably never
get to see this new mode. So the first thing we need is being able to
tell whether that mode is supported and if it's already enabled.
And if it's supported, and not enabled, enable it, both in the clock
and MMC drivers.
> At least, it sounds like set_phase() should bail out there
> because it doesn't exist, although it could be argued that
> setting the phase to something it already is set to is valid and
> shouldn't return an error.
Yep, once the new mode is set (disregarding how we do it), we should
prevent any clk_set_phase != 0. We'll also need to adjust the reported
clock rate.
> I'm not saying I'm opposed to the custom function, just thinking
> of alternatives if MMC maintainers don't agree with the custom
> function.
Ok, thanks!
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20170307/3c5f8057/attachment.sig>
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 4/5] clk: sunxi-ng: Add driver for A83T CCU
2017-02-15 9:49 ` Maxime Ripard
@ 2017-03-22 6:50 ` Chen-Yu Tsai
-1 siblings, 0 replies; 38+ messages in thread
From: Chen-Yu Tsai @ 2017-03-22 6:50 UTC (permalink / raw)
To: Maxime Ripard
Cc: Chen-Yu Tsai, Michael Turquette, Stephen Boyd, linux-clk,
linux-arm-kernel, linux-kernel
On Wed, Feb 15, 2017 at 5:49 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> On Tue, Feb 14, 2017 at 06:26:39PM +0800, Chen-Yu Tsai wrote:
>> On Tue, Feb 14, 2017 at 5:58 PM, Maxime Ripard
>> <maxime.ripard@free-electrons.com> wrote:
>> > On Tue, Feb 14, 2017 at 11:35:25AM +0800, Chen-Yu Tsai wrote:
>> >> +/* Some PLLs are input * N / div1 / P. Model them as NKMP with no K */
>> >
>> > Is that even working?
>>
>> Looking at the nkmp clock code, only .recalc_rate will work properly though.
>> Maybe I could fix up the code so it handles zero width factors.
>>
>> > I'm not quite sure we want to do that. We might model it as a NP clock
>> > with a variable prediv?
>>
>> There's no NP clock type yet. And a problem with a variable prediv is that
>> it doesn't participate in factor calculation. It's effectively fixed.
>>
>> I did this for the A80 as well though. Fixing up the NKMP clock might be
>> easier.
>
> Then maybe we just need a NMP clock type then. What I'm really afraid
> of is that we'll just end up in a clk-factors situation that was
> simply impossible to maintain without breaking anything, hence why we
> had different clock types then.
Upon further review, I think it will work. I did notice a discrepancy
between .set_rate and .round_rate though. Will send fixes later.
About the old clk-factors situation, I'm not exactly sure what part
you're referring to. To me it seems the "factors" bits are mostly the
same. Differences are mostly with parent-specific pre-dividers,
clock post-dividers, and non-standard factors. The first is nicely
handled by the new mux wrapper, the second is currently only used
with NK types, and the last is currently only supported by single
factor divider or multiplier clocks with tables.
Non-standard factors are probably the trickiest one, but given we will
support full factor tables for some of the tricky CPU PLLs, this is
probably solved, even if not implemented yet.
I'll start with the NP style clocks, which only use P when the output
is under a certain frequency.
Regards
ChenYu
>> >
>> >> +/* Use a separate clock for the pre-divider on the AHB1 PLL-PERIPH input */
>> >> +static SUNXI_CCU_M(pll_periph_ahb1_clk, "pll-periph-ahb1", "pll-periph",
>> >> + 0x054, 6, 2, 0);
>> >> +
>> >> +static const char * const ahb1_parents[] = { "osc16M-d512", "osc24M",
>> >> + "pll-periph-ahb1",
>> >> + "pll-periph-ahb1" };
>> >> +static struct ccu_div ahb1_clk = {
>> >> + .div = _SUNXI_CCU_DIV_FLAGS(4, 2, CLK_DIVIDER_POWER_OF_TWO),
>> >> + .mux = _SUNXI_CCU_MUX(12, 2),
>> >> + .common = {
>> >> + .reg = 0x054,
>> >> + .hw.init = CLK_HW_INIT_PARENTS("ahb1",
>> >> + ahb1_parents,
>> >> + &ccu_div_ops,
>> >> + 0),
>> >> + },
>> >> +};
>> >
>> > What's different from a pre divider only for a given index here?
>>
>> The variable pre-divider is shared for both pll-periph mux inputs.
>> This is one way to handle it. The other would be to extend ccu_mux
>> to handle multiple variable pre-dividers. I don't really want to do
>> that if this is the only instance that needs it though.
>
> Every addition we made was only needed by one instance at first :)
>
> We are working that way for fixed pre-dividers already, I don't see
> why we can't have it for variable ones too.
>
>> >> +/*
>> >> + * MMC2 supports what's called the "new timing mode". The CCU and the MMC
>> >> + * controller must be in sync about which mode is used. The new mode moves
>> >> + * the clock delay controls (and possibly the delay lines) into the MMC
>> >> + * block. Also, the output of the clock is divided by 2. The output and
>> >> + * sample phase clocks are unused under this mode.
>> >> + *
>> >> + * This new mode seems to be preferred. Hence we force this clock to the
>> >> + * new mode. And we don't add the phase clocks.
>> >> + */
>> >
>> > I'm sorry, but I said this several times, this isn't working. We
>> > should model it properly, and not hack this around in the clock
>> > driver.
>> >
>> > As you say in your comment, the MMC driver needs to be aware about
>> > which mode is used, in order to also set a bit in one of its registers
>> > accordingly, and modify its sampling behaviour.
>> >
>> > The new timing is preferred, but our previous clock implementations
>> > didn't hardcode it, so we can't even rely on that behaviour to always
>> > write it in our driver.
>>
>> Correct. With the A83T there has never been a merged clock driver though.
>> I realize this is a one off thing.
>>
>> > This is not something specific to the A83T, but is found in all the
>> > SoCs since the A23, so we need to come up with a good solution to
>> > address that.
>> >
>> > I'm not sure what a good solution would be though. One would be to
>> > just have a private function of our own to switch in the new mode (if
>> > relevant, because only the MMC2 controllers have it), but that would
>> > lead to troubles with !sunxi-ng. Not something we can't deal with, but
>> > some extra precautions should be taken (make sure to protect the call
>> > through an ifdef / IS_DEFINED, check that the sunxi-ng driver has been
>> > probed, etc.)
>>
>> If the custom function route is acceptable, I'll come up with something.
>
> I think it would be a great start yes. I'll try to discuss it with
> Mike and Stephen at ELC and see what they think about that.
>
> Maxime
>
> --
> Maxime Ripard, Free Electrons
> Embedded Linux and Kernel engineering
> http://free-electrons.com
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 4/5] clk: sunxi-ng: Add driver for A83T CCU
@ 2017-03-22 6:50 ` Chen-Yu Tsai
0 siblings, 0 replies; 38+ messages in thread
From: Chen-Yu Tsai @ 2017-03-22 6:50 UTC (permalink / raw)
To: linux-arm-kernel
On Wed, Feb 15, 2017 at 5:49 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> On Tue, Feb 14, 2017 at 06:26:39PM +0800, Chen-Yu Tsai wrote:
>> On Tue, Feb 14, 2017 at 5:58 PM, Maxime Ripard
>> <maxime.ripard@free-electrons.com> wrote:
>> > On Tue, Feb 14, 2017 at 11:35:25AM +0800, Chen-Yu Tsai wrote:
>> >> +/* Some PLLs are input * N / div1 / P. Model them as NKMP with no K */
>> >
>> > Is that even working?
>>
>> Looking at the nkmp clock code, only .recalc_rate will work properly though.
>> Maybe I could fix up the code so it handles zero width factors.
>>
>> > I'm not quite sure we want to do that. We might model it as a NP clock
>> > with a variable prediv?
>>
>> There's no NP clock type yet. And a problem with a variable prediv is that
>> it doesn't participate in factor calculation. It's effectively fixed.
>>
>> I did this for the A80 as well though. Fixing up the NKMP clock might be
>> easier.
>
> Then maybe we just need a NMP clock type then. What I'm really afraid
> of is that we'll just end up in a clk-factors situation that was
> simply impossible to maintain without breaking anything, hence why we
> had different clock types then.
Upon further review, I think it will work. I did notice a discrepancy
between .set_rate and .round_rate though. Will send fixes later.
About the old clk-factors situation, I'm not exactly sure what part
you're referring to. To me it seems the "factors" bits are mostly the
same. Differences are mostly with parent-specific pre-dividers,
clock post-dividers, and non-standard factors. The first is nicely
handled by the new mux wrapper, the second is currently only used
with NK types, and the last is currently only supported by single
factor divider or multiplier clocks with tables.
Non-standard factors are probably the trickiest one, but given we will
support full factor tables for some of the tricky CPU PLLs, this is
probably solved, even if not implemented yet.
I'll start with the NP style clocks, which only use P when the output
is under a certain frequency.
Regards
ChenYu
>> >
>> >> +/* Use a separate clock for the pre-divider on the AHB1 PLL-PERIPH input */
>> >> +static SUNXI_CCU_M(pll_periph_ahb1_clk, "pll-periph-ahb1", "pll-periph",
>> >> + 0x054, 6, 2, 0);
>> >> +
>> >> +static const char * const ahb1_parents[] = { "osc16M-d512", "osc24M",
>> >> + "pll-periph-ahb1",
>> >> + "pll-periph-ahb1" };
>> >> +static struct ccu_div ahb1_clk = {
>> >> + .div = _SUNXI_CCU_DIV_FLAGS(4, 2, CLK_DIVIDER_POWER_OF_TWO),
>> >> + .mux = _SUNXI_CCU_MUX(12, 2),
>> >> + .common = {
>> >> + .reg = 0x054,
>> >> + .hw.init = CLK_HW_INIT_PARENTS("ahb1",
>> >> + ahb1_parents,
>> >> + &ccu_div_ops,
>> >> + 0),
>> >> + },
>> >> +};
>> >
>> > What's different from a pre divider only for a given index here?
>>
>> The variable pre-divider is shared for both pll-periph mux inputs.
>> This is one way to handle it. The other would be to extend ccu_mux
>> to handle multiple variable pre-dividers. I don't really want to do
>> that if this is the only instance that needs it though.
>
> Every addition we made was only needed by one instance at first :)
>
> We are working that way for fixed pre-dividers already, I don't see
> why we can't have it for variable ones too.
>
>> >> +/*
>> >> + * MMC2 supports what's called the "new timing mode". The CCU and the MMC
>> >> + * controller must be in sync about which mode is used. The new mode moves
>> >> + * the clock delay controls (and possibly the delay lines) into the MMC
>> >> + * block. Also, the output of the clock is divided by 2. The output and
>> >> + * sample phase clocks are unused under this mode.
>> >> + *
>> >> + * This new mode seems to be preferred. Hence we force this clock to the
>> >> + * new mode. And we don't add the phase clocks.
>> >> + */
>> >
>> > I'm sorry, but I said this several times, this isn't working. We
>> > should model it properly, and not hack this around in the clock
>> > driver.
>> >
>> > As you say in your comment, the MMC driver needs to be aware about
>> > which mode is used, in order to also set a bit in one of its registers
>> > accordingly, and modify its sampling behaviour.
>> >
>> > The new timing is preferred, but our previous clock implementations
>> > didn't hardcode it, so we can't even rely on that behaviour to always
>> > write it in our driver.
>>
>> Correct. With the A83T there has never been a merged clock driver though.
>> I realize this is a one off thing.
>>
>> > This is not something specific to the A83T, but is found in all the
>> > SoCs since the A23, so we need to come up with a good solution to
>> > address that.
>> >
>> > I'm not sure what a good solution would be though. One would be to
>> > just have a private function of our own to switch in the new mode (if
>> > relevant, because only the MMC2 controllers have it), but that would
>> > lead to troubles with !sunxi-ng. Not something we can't deal with, but
>> > some extra precautions should be taken (make sure to protect the call
>> > through an ifdef / IS_DEFINED, check that the sunxi-ng driver has been
>> > probed, etc.)
>>
>> If the custom function route is acceptable, I'll come up with something.
>
> I think it would be a great start yes. I'll try to discuss it with
> Mike and Stephen at ELC and see what they think about that.
>
> Maxime
>
> --
> Maxime Ripard, Free Electrons
> Embedded Linux and Kernel engineering
> http://free-electrons.com
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 4/5] clk: sunxi-ng: Add driver for A83T CCU
2017-03-22 6:50 ` Chen-Yu Tsai
@ 2017-03-26 20:51 ` Maxime Ripard
-1 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2017-03-26 20:51 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: Michael Turquette, Stephen Boyd, linux-clk, linux-arm-kernel,
linux-kernel
[-- Attachment #1: Type: text/plain, Size: 2702 bytes --]
Hi Chen-Yu,
On Wed, Mar 22, 2017 at 02:50:31PM +0800, Chen-Yu Tsai wrote:
> On Wed, Feb 15, 2017 at 5:49 PM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
> > On Tue, Feb 14, 2017 at 06:26:39PM +0800, Chen-Yu Tsai wrote:
> >> On Tue, Feb 14, 2017 at 5:58 PM, Maxime Ripard
> >> <maxime.ripard@free-electrons.com> wrote:
> >> > On Tue, Feb 14, 2017 at 11:35:25AM +0800, Chen-Yu Tsai wrote:
> >> >> +/* Some PLLs are input * N / div1 / P. Model them as NKMP with no K */
> >> >
> >> > Is that even working?
> >>
> >> Looking at the nkmp clock code, only .recalc_rate will work properly though.
> >> Maybe I could fix up the code so it handles zero width factors.
> >>
> >> > I'm not quite sure we want to do that. We might model it as a NP clock
> >> > with a variable prediv?
> >>
> >> There's no NP clock type yet. And a problem with a variable prediv is that
> >> it doesn't participate in factor calculation. It's effectively fixed.
> >>
> >> I did this for the A80 as well though. Fixing up the NKMP clock might be
> >> easier.
> >
> > Then maybe we just need a NMP clock type then. What I'm really afraid
> > of is that we'll just end up in a clk-factors situation that was
> > simply impossible to maintain without breaking anything, hence why we
> > had different clock types then.
>
> Upon further review, I think it will work. I did notice a discrepancy
> between .set_rate and .round_rate though. Will send fixes later.
>
> About the old clk-factors situation, I'm not exactly sure what part
> you're referring to.
We need to be able to support old DTs, which will still use the old
clock code. Whatever solution we come up with need to take that into
account.
> To me it seems the "factors" bits are mostly the same. Differences
> are mostly with parent-specific pre-dividers, clock post-dividers,
> and non-standard factors. The first is nicely handled by the new mux
> wrapper, the second is currently only used with NK types, and the
> last is currently only supported by single factor divider or
> multiplier clocks with tables.
>
> Non-standard factors are probably the trickiest one, but given we will
> support full factor tables for some of the tricky CPU PLLs, this is
> probably solved, even if not implemented yet.
>
> I'll start with the NP style clocks, which only use P when the output
> is under a certain frequency.
Do we need to use a P factor? I mean, we can just create a custom
clock for that, I'd realy don't want to cripple the generic code for a
completely non-generic problem.
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 4/5] clk: sunxi-ng: Add driver for A83T CCU
@ 2017-03-26 20:51 ` Maxime Ripard
0 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2017-03-26 20:51 UTC (permalink / raw)
To: linux-arm-kernel
Hi Chen-Yu,
On Wed, Mar 22, 2017 at 02:50:31PM +0800, Chen-Yu Tsai wrote:
> On Wed, Feb 15, 2017 at 5:49 PM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
> > On Tue, Feb 14, 2017 at 06:26:39PM +0800, Chen-Yu Tsai wrote:
> >> On Tue, Feb 14, 2017 at 5:58 PM, Maxime Ripard
> >> <maxime.ripard@free-electrons.com> wrote:
> >> > On Tue, Feb 14, 2017 at 11:35:25AM +0800, Chen-Yu Tsai wrote:
> >> >> +/* Some PLLs are input * N / div1 / P. Model them as NKMP with no K */
> >> >
> >> > Is that even working?
> >>
> >> Looking at the nkmp clock code, only .recalc_rate will work properly though.
> >> Maybe I could fix up the code so it handles zero width factors.
> >>
> >> > I'm not quite sure we want to do that. We might model it as a NP clock
> >> > with a variable prediv?
> >>
> >> There's no NP clock type yet. And a problem with a variable prediv is that
> >> it doesn't participate in factor calculation. It's effectively fixed.
> >>
> >> I did this for the A80 as well though. Fixing up the NKMP clock might be
> >> easier.
> >
> > Then maybe we just need a NMP clock type then. What I'm really afraid
> > of is that we'll just end up in a clk-factors situation that was
> > simply impossible to maintain without breaking anything, hence why we
> > had different clock types then.
>
> Upon further review, I think it will work. I did notice a discrepancy
> between .set_rate and .round_rate though. Will send fixes later.
>
> About the old clk-factors situation, I'm not exactly sure what part
> you're referring to.
We need to be able to support old DTs, which will still use the old
clock code. Whatever solution we come up with need to take that into
account.
> To me it seems the "factors" bits are mostly the same. Differences
> are mostly with parent-specific pre-dividers, clock post-dividers,
> and non-standard factors. The first is nicely handled by the new mux
> wrapper, the second is currently only used with NK types, and the
> last is currently only supported by single factor divider or
> multiplier clocks with tables.
>
> Non-standard factors are probably the trickiest one, but given we will
> support full factor tables for some of the tricky CPU PLLs, this is
> probably solved, even if not implemented yet.
>
> I'll start with the NP style clocks, which only use P when the output
> is under a certain frequency.
Do we need to use a P factor? I mean, we can just create a custom
clock for that, I'd realy don't want to cripple the generic code for a
completely non-generic problem.
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20170326/c2e28624/attachment-0001.sig>
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 4/5] clk: sunxi-ng: Add driver for A83T CCU
2017-03-26 20:51 ` Maxime Ripard
@ 2017-03-27 8:53 ` Chen-Yu Tsai
-1 siblings, 0 replies; 38+ messages in thread
From: Chen-Yu Tsai @ 2017-03-27 8:53 UTC (permalink / raw)
To: Maxime Ripard
Cc: Chen-Yu Tsai, Michael Turquette, Stephen Boyd, linux-clk,
linux-arm-kernel, linux-kernel
On Mon, Mar 27, 2017 at 4:51 AM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> Hi Chen-Yu,
>
> On Wed, Mar 22, 2017 at 02:50:31PM +0800, Chen-Yu Tsai wrote:
>> On Wed, Feb 15, 2017 at 5:49 PM, Maxime Ripard
>> <maxime.ripard@free-electrons.com> wrote:
>> > On Tue, Feb 14, 2017 at 06:26:39PM +0800, Chen-Yu Tsai wrote:
>> >> On Tue, Feb 14, 2017 at 5:58 PM, Maxime Ripard
>> >> <maxime.ripard@free-electrons.com> wrote:
>> >> > On Tue, Feb 14, 2017 at 11:35:25AM +0800, Chen-Yu Tsai wrote:
>> >> >> +/* Some PLLs are input * N / div1 / P. Model them as NKMP with no K */
>> >> >
>> >> > Is that even working?
>> >>
>> >> Looking at the nkmp clock code, only .recalc_rate will work properly though.
>> >> Maybe I could fix up the code so it handles zero width factors.
>> >>
>> >> > I'm not quite sure we want to do that. We might model it as a NP clock
>> >> > with a variable prediv?
>> >>
>> >> There's no NP clock type yet. And a problem with a variable prediv is that
>> >> it doesn't participate in factor calculation. It's effectively fixed.
>> >>
>> >> I did this for the A80 as well though. Fixing up the NKMP clock might be
>> >> easier.
>> >
>> > Then maybe we just need a NMP clock type then. What I'm really afraid
>> > of is that we'll just end up in a clk-factors situation that was
>> > simply impossible to maintain without breaking anything, hence why we
>> > had different clock types then.
>>
>> Upon further review, I think it will work. I did notice a discrepancy
>> between .set_rate and .round_rate though. Will send fixes later.
>>
>> About the old clk-factors situation, I'm not exactly sure what part
>> you're referring to.
>
> We need to be able to support old DTs, which will still use the old
> clock code. Whatever solution we come up with need to take that into
> account.
>
>> To me it seems the "factors" bits are mostly the same. Differences
>> are mostly with parent-specific pre-dividers, clock post-dividers,
>> and non-standard factors. The first is nicely handled by the new mux
>> wrapper, the second is currently only used with NK types, and the
>> last is currently only supported by single factor divider or
>> multiplier clocks with tables.
>>
>> Non-standard factors are probably the trickiest one, but given we will
>> support full factor tables for some of the tricky CPU PLLs, this is
>> probably solved, even if not implemented yet.
>>
>> I'll start with the NP style clocks, which only use P when the output
>> is under a certain frequency.
>
> Do we need to use a P factor? I mean, we can just create a custom
> clock for that, I'd realy don't want to cripple the generic code for a
> completely non-generic problem.
I'm not sure. AFAIK the vendor BSP cpufreq doesn't use frequencies
low enough to require the P divider, so we could just ignore it. But
then we need to make sure it's set to 1 at probe time, while keeping
the output frequency usable, which would kind of bloat the probe
function. FYI I'm in favor of doing it this way.
ChenYu
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 4/5] clk: sunxi-ng: Add driver for A83T CCU
@ 2017-03-27 8:53 ` Chen-Yu Tsai
0 siblings, 0 replies; 38+ messages in thread
From: Chen-Yu Tsai @ 2017-03-27 8:53 UTC (permalink / raw)
To: linux-arm-kernel
On Mon, Mar 27, 2017 at 4:51 AM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> Hi Chen-Yu,
>
> On Wed, Mar 22, 2017 at 02:50:31PM +0800, Chen-Yu Tsai wrote:
>> On Wed, Feb 15, 2017 at 5:49 PM, Maxime Ripard
>> <maxime.ripard@free-electrons.com> wrote:
>> > On Tue, Feb 14, 2017 at 06:26:39PM +0800, Chen-Yu Tsai wrote:
>> >> On Tue, Feb 14, 2017 at 5:58 PM, Maxime Ripard
>> >> <maxime.ripard@free-electrons.com> wrote:
>> >> > On Tue, Feb 14, 2017 at 11:35:25AM +0800, Chen-Yu Tsai wrote:
>> >> >> +/* Some PLLs are input * N / div1 / P. Model them as NKMP with no K */
>> >> >
>> >> > Is that even working?
>> >>
>> >> Looking at the nkmp clock code, only .recalc_rate will work properly though.
>> >> Maybe I could fix up the code so it handles zero width factors.
>> >>
>> >> > I'm not quite sure we want to do that. We might model it as a NP clock
>> >> > with a variable prediv?
>> >>
>> >> There's no NP clock type yet. And a problem with a variable prediv is that
>> >> it doesn't participate in factor calculation. It's effectively fixed.
>> >>
>> >> I did this for the A80 as well though. Fixing up the NKMP clock might be
>> >> easier.
>> >
>> > Then maybe we just need a NMP clock type then. What I'm really afraid
>> > of is that we'll just end up in a clk-factors situation that was
>> > simply impossible to maintain without breaking anything, hence why we
>> > had different clock types then.
>>
>> Upon further review, I think it will work. I did notice a discrepancy
>> between .set_rate and .round_rate though. Will send fixes later.
>>
>> About the old clk-factors situation, I'm not exactly sure what part
>> you're referring to.
>
> We need to be able to support old DTs, which will still use the old
> clock code. Whatever solution we come up with need to take that into
> account.
>
>> To me it seems the "factors" bits are mostly the same. Differences
>> are mostly with parent-specific pre-dividers, clock post-dividers,
>> and non-standard factors. The first is nicely handled by the new mux
>> wrapper, the second is currently only used with NK types, and the
>> last is currently only supported by single factor divider or
>> multiplier clocks with tables.
>>
>> Non-standard factors are probably the trickiest one, but given we will
>> support full factor tables for some of the tricky CPU PLLs, this is
>> probably solved, even if not implemented yet.
>>
>> I'll start with the NP style clocks, which only use P when the output
>> is under a certain frequency.
>
> Do we need to use a P factor? I mean, we can just create a custom
> clock for that, I'd realy don't want to cripple the generic code for a
> completely non-generic problem.
I'm not sure. AFAIK the vendor BSP cpufreq doesn't use frequencies
low enough to require the P divider, so we could just ignore it. But
then we need to make sure it's set to 1 at probe time, while keeping
the output frequency usable, which would kind of bloat the probe
function. FYI I'm in favor of doing it this way.
ChenYu
^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 4/5] clk: sunxi-ng: Add driver for A83T CCU
2017-03-27 8:53 ` Chen-Yu Tsai
@ 2017-04-03 7:53 ` Maxime Ripard
-1 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2017-04-03 7:53 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: Michael Turquette, Stephen Boyd, linux-clk, linux-arm-kernel,
linux-kernel
[-- Attachment #1: Type: text/plain, Size: 2030 bytes --]
On Mon, Mar 27, 2017 at 04:53:05PM +0800, Chen-Yu Tsai wrote:
> >> To me it seems the "factors" bits are mostly the same. Differences
> >> are mostly with parent-specific pre-dividers, clock post-dividers,
> >> and non-standard factors. The first is nicely handled by the new mux
> >> wrapper, the second is currently only used with NK types, and the
> >> last is currently only supported by single factor divider or
> >> multiplier clocks with tables.
> >>
> >> Non-standard factors are probably the trickiest one, but given we will
> >> support full factor tables for some of the tricky CPU PLLs, this is
> >> probably solved, even if not implemented yet.
> >>
> >> I'll start with the NP style clocks, which only use P when the output
> >> is under a certain frequency.
> >
> > Do we need to use a P factor? I mean, we can just create a custom
> > clock for that, I'd realy don't want to cripple the generic code for a
> > completely non-generic problem.
>
> I'm not sure. AFAIK the vendor BSP cpufreq doesn't use frequencies
> low enough to require the P divider, so we could just ignore it. But
> then we need to make sure it's set to 1 at probe time, while keeping
> the output frequency usable, which would kind of bloat the probe
> function. FYI I'm in favor of doing it this way.
Hmmm, I don't know why I replied that anymore, I thought you were
still talking about MMC, while you were clearly talking about
CPU_PLLs...
The question still remains though. If we're not using P yet, and if
the BSP doesn't either, then we can just hardcode it.
We can always come up with something later if we need to use it,
either an NP-class, or a table. The only thing we need to care about
would be to pay attention to what the P factor already is, before
forcing it to 1. If it's set to 4, that would mean multiplying the CPU
clock by 4, which is probably not such a great idea.
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 4/5] clk: sunxi-ng: Add driver for A83T CCU
@ 2017-04-03 7:53 ` Maxime Ripard
0 siblings, 0 replies; 38+ messages in thread
From: Maxime Ripard @ 2017-04-03 7:53 UTC (permalink / raw)
To: linux-arm-kernel
On Mon, Mar 27, 2017 at 04:53:05PM +0800, Chen-Yu Tsai wrote:
> >> To me it seems the "factors" bits are mostly the same. Differences
> >> are mostly with parent-specific pre-dividers, clock post-dividers,
> >> and non-standard factors. The first is nicely handled by the new mux
> >> wrapper, the second is currently only used with NK types, and the
> >> last is currently only supported by single factor divider or
> >> multiplier clocks with tables.
> >>
> >> Non-standard factors are probably the trickiest one, but given we will
> >> support full factor tables for some of the tricky CPU PLLs, this is
> >> probably solved, even if not implemented yet.
> >>
> >> I'll start with the NP style clocks, which only use P when the output
> >> is under a certain frequency.
> >
> > Do we need to use a P factor? I mean, we can just create a custom
> > clock for that, I'd realy don't want to cripple the generic code for a
> > completely non-generic problem.
>
> I'm not sure. AFAIK the vendor BSP cpufreq doesn't use frequencies
> low enough to require the P divider, so we could just ignore it. But
> then we need to make sure it's set to 1 at probe time, while keeping
> the output frequency usable, which would kind of bloat the probe
> function. FYI I'm in favor of doing it this way.
Hmmm, I don't know why I replied that anymore, I thought you were
still talking about MMC, while you were clearly talking about
CPU_PLLs...
The question still remains though. If we're not using P yet, and if
the BSP doesn't either, then we can just hardcode it.
We can always come up with something later if we need to use it,
either an NP-class, or a table. The only thing we need to care about
would be to pay attention to what the P factor already is, before
forcing it to 1. If it's set to 4, that would mean multiplying the CPU
clock by 4, which is probably not such a great idea.
Maxime
--
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20170403/59f79643/attachment-0001.sig>
^ permalink raw reply [flat|nested] 38+ messages in thread
end of thread, other threads:[~2017-04-03 7:54 UTC | newest]
Thread overview: 38+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-02-14 3:35 [PATCH 0/5] clk: sunxi-ng: Add support for A83T CCU Chen-Yu Tsai
2017-02-14 3:35 ` Chen-Yu Tsai
2017-02-14 3:35 ` [PATCH 1/5] clk: sunxi-ng: mp: Adjust parent rate for pre-dividers Chen-Yu Tsai
2017-02-14 3:35 ` Chen-Yu Tsai
2017-02-14 9:34 ` Maxime Ripard
2017-02-14 9:34 ` Maxime Ripard
2017-02-14 3:35 ` [PATCH 2/5] clk: sunxi-ng: gate: Support common pre-dividers Chen-Yu Tsai
2017-02-14 3:35 ` Chen-Yu Tsai
2017-02-14 9:39 ` Maxime Ripard
2017-02-14 9:39 ` Maxime Ripard
2017-02-14 3:35 ` [PATCH 3/5] clk: sunxi-ng: Add compatible string for A83T CCU to bindings Chen-Yu Tsai
2017-02-14 3:35 ` Chen-Yu Tsai
2017-02-14 3:35 ` [PATCH 4/5] clk: sunxi-ng: Add driver for A83T CCU Chen-Yu Tsai
2017-02-14 3:35 ` Chen-Yu Tsai
2017-02-14 9:58 ` Maxime Ripard
2017-02-14 9:58 ` Maxime Ripard
2017-02-14 10:26 ` Chen-Yu Tsai
2017-02-14 10:26 ` Chen-Yu Tsai
2017-02-15 9:49 ` Maxime Ripard
2017-02-15 9:49 ` Maxime Ripard
2017-03-01 19:17 ` Stephen Boyd
2017-03-01 19:17 ` Stephen Boyd
2017-03-03 9:53 ` Maxime Ripard
2017-03-03 9:53 ` Maxime Ripard
2017-03-03 23:56 ` Stephen Boyd
2017-03-03 23:56 ` Stephen Boyd
2017-03-07 14:58 ` Maxime Ripard
2017-03-07 14:58 ` Maxime Ripard
2017-03-22 6:50 ` Chen-Yu Tsai
2017-03-22 6:50 ` Chen-Yu Tsai
2017-03-26 20:51 ` Maxime Ripard
2017-03-26 20:51 ` Maxime Ripard
2017-03-27 8:53 ` Chen-Yu Tsai
2017-03-27 8:53 ` Chen-Yu Tsai
2017-04-03 7:53 ` Maxime Ripard
2017-04-03 7:53 ` Maxime Ripard
2017-02-14 3:35 ` [PATCH 5/5] ARM: dts: sun8i-a83t: Add CCU device nodes Chen-Yu Tsai
2017-02-14 3:35 ` Chen-Yu Tsai
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.