2015-02-05 09:22:43

by Bintian

[permalink] [raw]
Subject: [PATCH 0/3] arm64,hi6220: Enable Hisilicon Hi6220 SoC

Hello,

Hi6220 is one mobile solution of Hisilicon, this patchset contains
initial support for Hi6220 SoC and HiKey development board, which
is based on ARM Cortex A53 architecture. Initial support is minimal
and includes just the arch configuration, clock driver, device tree
configuration.

Many peripheral drivers will be submitted later.

Any comments will be appreciated!

Thanks,

Bintian Wang (3):
arm64: Enable Hisilicon ARMv8 SoC family in Kconfig and defconfig
clk: hi6220: Clock driver support for Hisilicon hi6220 SoC
arm64: dts: Add dts files for Hisilicon Hi6220 SoC

.../bindings/arm/hisilicon/hisilicon.txt | 33 +++
.../devicetree/bindings/clock/hi6220-clock.txt | 30 +++
arch/arm64/Kconfig | 6 +
arch/arm64/boot/dts/Makefile | 1 +
arch/arm64/boot/dts/hisilicon/Makefile | 5 +
arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts | 31 +++
arch/arm64/boot/dts/hisilicon/hi6220.dtsi | 204 ++++++++++++++
arch/arm64/configs/defconfig | 1 +
drivers/clk/Kconfig | 2 +
drivers/clk/Makefile | 4 +-
drivers/clk/hisilicon/Kconfig | 5 +
drivers/clk/hisilicon/Makefile | 1 +
drivers/clk/hisilicon/clk-hi6220.c | 284 ++++++++++++++++++++
drivers/clk/hisilicon/clk.c | 29 ++
drivers/clk/hisilicon/clk.h | 17 ++
drivers/clk/hisilicon/clkdivider-hi6220.c | 273 +++++++++++++++++++
include/dt-bindings/clock/hi6220-clock.h | 172 ++++++++++++
17 files changed, 1095 insertions(+), 3 deletions(-)
create mode 100644 Documentation/devicetree/bindings/clock/hi6220-clock.txt
create mode 100644 arch/arm64/boot/dts/hisilicon/Makefile
create mode 100644 arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts
create mode 100644 arch/arm64/boot/dts/hisilicon/hi6220.dtsi
create mode 100644 drivers/clk/hisilicon/Kconfig
create mode 100644 drivers/clk/hisilicon/clk-hi6220.c
create mode 100644 drivers/clk/hisilicon/clkdivider-hi6220.c
create mode 100644 include/dt-bindings/clock/hi6220-clock.h

--
1.7.9.5


2015-02-05 09:22:48

by Bintian

[permalink] [raw]
Subject: [PATCH 1/3] arm64: Enable Hisilicon ARMv8 SoC family in Kconfig and defconfig

This patch introduces ARCH_HISI to enable Hisilicon SoC family in
Kconfig and defconfig.

Signed-off-by: Bintian Wang <[email protected]>
Reviewed-by: Haojian Zhuang <[email protected]>
Reviewed-by: Wei Xu <[email protected]>
---
arch/arm64/Kconfig | 5 +++++
arch/arm64/configs/defconfig | 1 +
2 files changed, 6 insertions(+)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index b1f9a20..78cd41c8 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -173,6 +173,11 @@ config ARCH_XGENE
help
This enables support for AppliedMicro X-Gene SOC Family

+config ARCH_HISI
+ bool "Hisilicon SoC Family"
+ help
+ This enables support for Hisilicon ARMv8 Family of SoCs.
+
endmenu

menu "Bus support"
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 5376d90..a829774 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -34,6 +34,7 @@ CONFIG_MODULE_UNLOAD=y
CONFIG_ARCH_THUNDER=y
CONFIG_ARCH_VEXPRESS=y
CONFIG_ARCH_XGENE=y
+CONFIG_ARCH_HISI=y
CONFIG_PCI=y
CONFIG_PCI_MSI=y
CONFIG_PCI_XGENE=y
--
1.7.9.5

2015-02-05 09:22:55

by Bintian

[permalink] [raw]
Subject: [PATCH 2/3] clk: hi6220: Clock driver support for Hisilicon hi6220 SoC

Add clock drivers for hi6220 SoC, this driver controls the SoC
registers to supply different clocks to different IPs in the SoC.

We add one divider clock for hi6220 because the divider in hi6220
also has a mask bit but it doesnot obey the rule defined by flag
"CLK_DIVIDER_HIWORD_MASK", we can not get index of the mask bit by
left shift fixed bits (e.g. 16 bits), so we add this divider clock
to handle it.

This patch also enables this clock driver for ARCH_HISI and document
devicetree bindings.

Signed-off-by: Bintian Wang <[email protected]>
Reviewed-by: Haojian Zhuang <[email protected]>
Reviewed-by: Zhangfei Gao <[email protected]>
---
.../devicetree/bindings/clock/hi6220-clock.txt | 30 +++
arch/arm64/Kconfig | 1 +
drivers/clk/Kconfig | 2 +
drivers/clk/Makefile | 4 +-
drivers/clk/hisilicon/Kconfig | 5 +
drivers/clk/hisilicon/Makefile | 1 +
drivers/clk/hisilicon/clk-hi6220.c | 284 ++++++++++++++++++++
drivers/clk/hisilicon/clk.c | 29 ++
drivers/clk/hisilicon/clk.h | 17 ++
drivers/clk/hisilicon/clkdivider-hi6220.c | 273 +++++++++++++++++++
include/dt-bindings/clock/hi6220-clock.h | 172 ++++++++++++
11 files changed, 815 insertions(+), 3 deletions(-)
create mode 100644 Documentation/devicetree/bindings/clock/hi6220-clock.txt
create mode 100644 drivers/clk/hisilicon/Kconfig
create mode 100644 drivers/clk/hisilicon/clk-hi6220.c
create mode 100644 drivers/clk/hisilicon/clkdivider-hi6220.c
create mode 100644 include/dt-bindings/clock/hi6220-clock.h

diff --git a/Documentation/devicetree/bindings/clock/hi6220-clock.txt b/Documentation/devicetree/bindings/clock/hi6220-clock.txt
new file mode 100644
index 0000000..a3ddda1
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/hi6220-clock.txt
@@ -0,0 +1,30 @@
+* Hisilicon Hi6220 Clock Controller
+
+The hi6220 clock controller generates and supplies clock to various
+controllers within the hi6220 SoC.
+
+Required Properties:
+
+- compatible: should be one of the following:
+ - "hisilicon,hi6220-clock-ao" - controller for those clocks under SoC
+ power always on(AO) domain, it is the sub node of SoC power AO
+ controller in dts file.
+ - "hisilicon,hi6220-clock-sys" - controller for those clocks under SoC
+ system control domain, it is the sub node of SoC system controller
+ in dts file.
+ - "hisilicon,hi6220-clock-media" - controller for those clocks under
+ SoC media control domain, it is the sub node of SoC media controller
+ in dts file.
+ - "hisilicon,hi6220-clock-power" - controller for those clocks under
+ SoC power control domain, it is the sub node of SoC power controller
+ in dts file.
+
+- reg: physical base address of the controller and length of memory mapped
+ region.
+
+- #clock-cells: should be 1.
+
+Each clock is assigned an identifier and client nodes use this identifier
+to specify the clock which they consume.
+
+All these identifier could be found in <dt-bindings/clock/hi6220-clock.h>.
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 78cd41c8..6efc3e3 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -175,6 +175,7 @@ config ARCH_XGENE

config ARCH_HISI
bool "Hisilicon SoC Family"
+ select COMMON_CLK_HI6220
help
This enables support for Hisilicon ARMv8 Family of SoCs.

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 3f44f29..b52c95c 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -136,6 +136,8 @@ config COMMON_CLK_PXA

source "drivers/clk/qcom/Kconfig"

+source "drivers/clk/hisilicon/Kconfig"
+
endmenu

source "drivers/clk/bcm/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index d5fba5b..c58703b 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -43,9 +43,7 @@ obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o
obj-$(CONFIG_COMMON_CLK_AT91) += at91/
obj-$(CONFIG_ARCH_BCM_MOBILE) += bcm/
obj-$(CONFIG_ARCH_BERLIN) += berlin/
-obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/
-obj-$(CONFIG_ARCH_HIP04) += hisilicon/
-obj-$(CONFIG_ARCH_HIX5HD2) += hisilicon/
+obj-$(CONFIG_ARCH_HISI) += hisilicon/
obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/
ifeq ($(CONFIG_COMMON_CLK), y)
obj-$(CONFIG_ARCH_MMP) += mmp/
diff --git a/drivers/clk/hisilicon/Kconfig b/drivers/clk/hisilicon/Kconfig
new file mode 100644
index 0000000..e3ead46
--- /dev/null
+++ b/drivers/clk/hisilicon/Kconfig
@@ -0,0 +1,5 @@
+config COMMON_CLK_HI6220
+ tristate "Hi6220 Clock Driver"
+ depends on OF && ARCH_HISI
+ help
+ Build the Hisilicon Hi6220 clock driver based on the common clock framework.
diff --git a/drivers/clk/hisilicon/Makefile b/drivers/clk/hisilicon/Makefile
index 038c02f..bbf0539 100644
--- a/drivers/clk/hisilicon/Makefile
+++ b/drivers/clk/hisilicon/Makefile
@@ -7,3 +7,4 @@ obj-y += clk.o clkgate-separated.o
obj-$(CONFIG_ARCH_HI3xxx) += clk-hi3620.o
obj-$(CONFIG_ARCH_HIP04) += clk-hip04.o
obj-$(CONFIG_ARCH_HIX5HD2) += clk-hix5hd2.o
+obj-$(CONFIG_COMMON_CLK_HI6220) += clkdivider-hi6220.o clk-hi6220.o
diff --git a/drivers/clk/hisilicon/clk-hi6220.c b/drivers/clk/hisilicon/clk-hi6220.c
new file mode 100644
index 0000000..01d0c46
--- /dev/null
+++ b/drivers/clk/hisilicon/clk-hi6220.c
@@ -0,0 +1,284 @@
+/*
+ * Hisilicon Hi6220 clock driver
+ *
+ * Copyright (c) 2015 Hisilicon Limited.
+ *
+ * Author: Bintian Wang <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+
+#include <dt-bindings/clock/hi6220-clock.h>
+
+#include "clk.h"
+
+
+/* clocks in AO (always on) controller */
+static struct hisi_fixed_rate_clock hi6220_fixed_rate_clks[] __initdata = {
+ { HI6220_REF32K, "ref32k", NULL, CLK_IS_ROOT, 32764, },
+ { HI6220_CLK_TCXO, "clk_tcxo", NULL, CLK_IS_ROOT, 19200000, },
+ { HI6220_MMC1_PAD, "mmc1_pad", NULL, CLK_IS_ROOT, 100000000, },
+ { HI6220_MMC2_PAD, "mmc2_pad", NULL, CLK_IS_ROOT, 100000000, },
+ { HI6220_MMC0_PAD, "mmc0_pad", NULL, CLK_IS_ROOT, 200000000, },
+ { HI6220_PLL_BBP, "bbppll0", NULL, CLK_IS_ROOT, 245760000, },
+ { HI6220_PLL_GPU, "gpupll", NULL, CLK_IS_ROOT, 1000000000,},
+ { HI6220_PLL1_DDR, "ddrpll1", NULL, CLK_IS_ROOT, 1066000000,},
+ { HI6220_PLL_SYS, "syspll", NULL, CLK_IS_ROOT, 1200000000,},
+ { HI6220_PLL_SYS_MEDIA, "media_syspll", NULL, CLK_IS_ROOT, 1200000000,},
+ { HI6220_DDR_SRC, "ddr_sel_src", NULL, CLK_IS_ROOT, 1200000000,},
+ { HI6220_PLL_MEDIA, "media_pll", NULL, CLK_IS_ROOT, 1440000000,},
+ { HI6220_PLL_DDR, "ddrpll0", NULL, CLK_IS_ROOT, 1600000000,},
+};
+
+static struct hisi_fixed_factor_clock hi6220_fixed_factor_clks[] __initdata = {
+ { HI6220_300M, "clk_300m", "syspll", 1, 4, 0, },
+ { HI6220_150M, "clk_150m", "clk_300m", 1, 2, 0, },
+ { HI6220_PICOPHY_SRC, "picophy_src", "clk_150m", 1, 4, 0, },
+ { HI6220_MMC0_SRC_SEL, "mmc0srcsel", "mmc0_sel", 1, 8, 0, },
+ { HI6220_MMC1_SRC_SEL, "mmc1srcsel", "mmc1_sel", 1, 8, 0, },
+ { HI6220_MMC2_SRC_SEL, "mmc2srcsel", "mmc2_sel", 1, 8, 0, },
+ { HI6220_VPU_CODEC, "vpucodec", "codec_jpeg_aclk", 1, 2, 0, },
+ { HI6220_MMC0_SMP, "mmc0_sample", "mmc0_sel", 1, 8, 0, },
+ { HI6220_MMC1_SMP, "mmc1_sample", "mmc1_sel", 1, 8, 0, },
+ { HI6220_MMC2_SMP, "mmc2_sample", "mmc2_sel", 1, 8, 0, },
+};
+
+static struct hisi_gate_clock hi6220_separated_gate_clks_ao[] __initdata = {
+ { HI6220_WDT0_PCLK, "wdt0_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 12, 0, },
+ { HI6220_WDT1_PCLK, "wdt1_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 13, 0, },
+ { HI6220_WDT2_PCLK, "wdt2_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 14, 0, },
+ { HI6220_TIMER0_PCLK, "timer0_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 15, 0, },
+ { HI6220_TIMER1_PCLK, "timer1_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 16, 0, },
+ { HI6220_TIMER2_PCLK, "timer2_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 17, 0, },
+ { HI6220_TIMER3_PCLK, "timer3_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 18, 0, },
+ { HI6220_TIMER4_PCLK, "timer4_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 19, 0, },
+ { HI6220_TIMER5_PCLK, "timer5_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 20, 0, },
+ { HI6220_TIMER6_PCLK, "timer6_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 21, 0, },
+ { HI6220_TIMER7_PCLK, "timer7_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 22, 0, },
+ { HI6220_TIMER8_PCLK, "timer8_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 23, 0, },
+ { HI6220_UART0_PCLK, "uart0_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 24, 0, },
+};
+
+static void __init hi6220_clk_ao_init(struct device_node *np)
+{
+ struct hisi_clock_data *clk_data;
+
+ clk_data = hisi_clk_init(np, HI6220_AO_NR_CLKS);
+ if (!clk_data)
+ return;
+
+ hisi_clk_register_fixed_rate(hi6220_fixed_rate_clks,
+ ARRAY_SIZE(hi6220_fixed_rate_clks), clk_data);
+
+ hisi_clk_register_fixed_factor(hi6220_fixed_factor_clks,
+ ARRAY_SIZE(hi6220_fixed_factor_clks), clk_data);
+
+ hisi_clk_register_gate_sep(hi6220_separated_gate_clks_ao,
+ ARRAY_SIZE(hi6220_separated_gate_clks_ao), clk_data);
+}
+CLK_OF_DECLARE(hi6220_clk_ao, "hisilicon,hi6220-clock-ao", hi6220_clk_ao_init);
+
+
+/* clocks in sysctrl */
+static const char *mmc0_mux0_p[] __initconst = { "pll_ddr_gate", "syspll", };
+static const char *mmc0_mux1_p[] __initconst = { "mmc0_mux0", "pll_media_gate", };
+static const char *mmc0_src_p[] __initconst = { "mmc0srcsel", "mmc0_div", };
+static const char *mmc1_mux0_p[] __initconst = { "pll_ddr_gate", "syspll", };
+static const char *mmc1_mux1_p[] __initconst = { "mmc1_mux0", "pll_media_gate", };
+static const char *mmc1_src_p[] __initconst = { "mmc1srcsel", "mmc1_div", };
+static const char *mmc2_mux0_p[] __initconst = { "pll_ddr_gate", "syspll", };
+static const char *mmc2_mux1_p[] __initconst = { "mmc2_mux0", "pll_media_gate", };
+static const char *mmc2_src_p[] __initconst = { "mmc2srcsel", "mmc2_div", };
+static const char *mmc0_sample_in[] __initconst = { "mmc0_sample", "mmc0_pad", };
+static const char *mmc1_sample_in[] __initconst = { "mmc1_sample", "mmc1_pad", };
+static const char *mmc2_sample_in[] __initconst = { "mmc2_sample", "mmc2_pad", };
+static const char *uart1_src[] __initconst = { "clk_tcxo", "clk_150m", };
+static const char *uart2_src[] __initconst = { "clk_tcxo", "clk_150m", };
+static const char *uart3_src[] __initconst = { "clk_tcxo", "clk_150m", };
+static const char *uart4_src[] __initconst = { "clk_tcxo", "clk_150m", };
+static const char *hifi_src[] __initconst = { "syspll", "pll_media_gate", };
+
+static struct hisi_gate_clock hi6220_separated_gate_clks_sys[] __initdata = {
+ { HI6220_MMC0_CLK, "mmc0_clk", "mmc0_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 0, 0, },
+ { HI6220_MMC0_CIUCLK, "mmc0_ciuclk", "mmc0_smp_in", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 0, 0, },
+ { HI6220_MMC1_CLK, "mmc1_clk", "mmc1_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 1, 0, },
+ { HI6220_MMC1_CIUCLK, "mmc1_ciuclk", "mmc1_smp_in", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 1, 0, },
+ { HI6220_MMC2_CLK, "mmc2_clk", "mmc2_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 2, 0, },
+ { HI6220_MMC2_CIUCLK, "mmc2_ciuclk", "mmc2_smp_in", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 2, 0, },
+ { HI6220_USBOTG_HCLK, "usbotg_hclk", "clk_bus", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 4, 0, },
+ { HI6220_CLK_PICOPHY, "clk_picophy", "cs_dapb", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 5, 0, },
+ { HI6220_HIFI, "hifi_clk", "hifi_div", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x210, 0, 0, },
+ { HI6220_DACODEC_PCLK, "dacodec_pclk", "clk_bus", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x210, 5, 0, },
+ { HI6220_EDMAC_ACLK, "edmac_aclk", "clk_bus", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x220, 2, 0, },
+ { HI6220_CS_ATB, "cs_atb", "cs_atb_div", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 0, 0, },
+ { HI6220_I2C0_CLK, "i2c0_clk", "clk_150m", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 1, 0, },
+ { HI6220_I2C1_CLK, "i2c1_clk", "clk_150m", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 2, 0, },
+ { HI6220_I2C2_CLK, "i2c2_clk", "clk_150m", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 3, 0, },
+ { HI6220_I2C3_CLK, "i2c3_clk", "clk_150m", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 4, 0, },
+ { HI6220_UART1_PCLK, "uart1_pclk", "uart1_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 5, 0, },
+ { HI6220_UART2_PCLK, "uart2_pclk", "uart2_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 6, 0, },
+ { HI6220_UART3_PCLK, "uart3_pclk", "uart3_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 7, 0, },
+ { HI6220_UART4_PCLK, "uart4_pclk", "uart4_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 8, 0, },
+ { HI6220_SPI_CLK, "spi_clk", "clk_150m", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 9, 0, },
+ { HI6220_MMU_CLK, "mmu_clk", "ddrc_axi1", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x240, 11, 0, },
+ { HI6220_HIFI_SEL, "hifi_sel", "hifi_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 0, 0, },
+ { HI6220_MMC0_SYSPLL, "mmc0_syspll", "syspll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 1, 0, },
+ { HI6220_MMC1_SYSPLL, "mmc1_syspll", "syspll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 2, 0, },
+ { HI6220_MMC2_SYSPLL, "mmc2_syspll", "syspll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 3, 0, },
+ { HI6220_MMC0_SEL, "mmc0_sel", "mmc0_mux1", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 6, 0, },
+ { HI6220_MMC1_SEL, "mmc1_sel", "mmc1_mux1", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 7, 0, },
+ { HI6220_BBPPLL_SEL, "bbppll_sel", "pll0_bbp_gate", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 9, 0, },
+ { HI6220_MEDIA_PLL_SRC, "media_pll_src", "pll_media_gate", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 10, 0, },
+ { HI6220_MMC2_SEL, "mmc2_sel", "mmc2_mux1", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 11, 0, },
+ { HI6220_CS_ATB_SYSPLL, "cs_atb_syspll", "syspll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 12, 0, },
+};
+
+static struct hisi_mux_clock hi6220_mux_clks_sys[] __initdata = {
+ { HI6220_MMC0_SRC, "mmc0_src", mmc0_src_p, ARRAY_SIZE(mmc0_src_p), CLK_SET_RATE_PARENT, 0x4, 0, 1, 0, },
+ { HI6220_MMC0_SMP_IN, "mmc0_smp_in", mmc0_sample_in, ARRAY_SIZE(mmc0_sample_in), CLK_SET_RATE_PARENT, 0x4, 0, 1, 0, },
+ { HI6220_MMC1_SRC, "mmc1_src", mmc1_src_p, ARRAY_SIZE(mmc1_src_p), CLK_SET_RATE_PARENT, 0x4, 2, 1, 0, },
+ { HI6220_MMC1_SMP_IN, "mmc1_smp_in", mmc1_sample_in, ARRAY_SIZE(mmc1_sample_in), CLK_SET_RATE_PARENT, 0x4, 2, 1, 0, },
+ { HI6220_MMC2_SRC, "mmc2_src", mmc2_src_p, ARRAY_SIZE(mmc2_src_p), CLK_SET_RATE_PARENT, 0x4, 4, 1, 0, },
+ { HI6220_MMC2_SMP_IN, "mmc2_smp_in", mmc2_sample_in, ARRAY_SIZE(mmc2_sample_in), CLK_SET_RATE_PARENT, 0x4, 4, 1, 0, },
+ { HI6220_HIFI_SRC, "hifi_src", hifi_src, ARRAY_SIZE(hifi_src), CLK_SET_RATE_PARENT, 0x400, 0, 1, CLK_MUX_HIWORD_MASK,},
+ { HI6220_UART1_SRC, "uart1_src", uart1_src, ARRAY_SIZE(uart1_src), CLK_SET_RATE_PARENT, 0x400, 1, 1, CLK_MUX_HIWORD_MASK,},
+ { HI6220_UART2_SRC, "uart2_src", uart2_src, ARRAY_SIZE(uart2_src), CLK_SET_RATE_PARENT, 0x400, 2, 1, CLK_MUX_HIWORD_MASK,},
+ { HI6220_UART3_SRC, "uart3_src", uart3_src, ARRAY_SIZE(uart3_src), CLK_SET_RATE_PARENT, 0x400, 3, 1, CLK_MUX_HIWORD_MASK,},
+ { HI6220_UART4_SRC, "uart4_src", uart4_src, ARRAY_SIZE(uart4_src), CLK_SET_RATE_PARENT, 0x400, 4, 1, CLK_MUX_HIWORD_MASK,},
+ { HI6220_MMC0_MUX0, "mmc0_mux0", mmc0_mux0_p, ARRAY_SIZE(mmc0_mux0_p), CLK_SET_RATE_PARENT, 0x400, 5, 1, CLK_MUX_HIWORD_MASK,},
+ { HI6220_MMC1_MUX0, "mmc1_mux0", mmc1_mux0_p, ARRAY_SIZE(mmc1_mux0_p), CLK_SET_RATE_PARENT, 0x400, 11, 1, CLK_MUX_HIWORD_MASK,},
+ { HI6220_MMC2_MUX0, "mmc2_mux0", mmc2_mux0_p, ARRAY_SIZE(mmc2_mux0_p), CLK_SET_RATE_PARENT, 0x400, 12, 1, CLK_MUX_HIWORD_MASK,},
+ { HI6220_MMC0_MUX1, "mmc0_mux1", mmc0_mux1_p, ARRAY_SIZE(mmc0_mux1_p), CLK_SET_RATE_PARENT, 0x400, 13, 1, CLK_MUX_HIWORD_MASK,},
+ { HI6220_MMC1_MUX1, "mmc1_mux1", mmc1_mux1_p, ARRAY_SIZE(mmc1_mux1_p), CLK_SET_RATE_PARENT, 0x400, 14, 1, CLK_MUX_HIWORD_MASK,},
+ { HI6220_MMC2_MUX1, "mmc2_mux1", mmc2_mux1_p, ARRAY_SIZE(mmc2_mux1_p), CLK_SET_RATE_PARENT, 0x400, 15, 1, CLK_MUX_HIWORD_MASK,},
+};
+
+static struct hi6220_divider_clock hi6220_div_clks_sys[] __initdata = {
+ { HI6220_CLK_BUS, "clk_bus", "clk_300m", CLK_SET_RATE_PARENT, 0x490, 0, 4, 7, },
+ { HI6220_MMC0_DIV, "mmc0_div", "mmc0_syspll", CLK_SET_RATE_PARENT, 0x494, 0, 6, 7, },
+ { HI6220_MMC1_DIV, "mmc1_div", "mmc1_syspll", CLK_SET_RATE_PARENT, 0x498, 0, 6, 7, },
+ { HI6220_MMC2_DIV, "mmc2_div", "mmc2_syspll", CLK_SET_RATE_PARENT, 0x49c, 0, 6, 7, },
+ { HI6220_HIFI_DIV, "hifi_div", "hifi_sel", CLK_SET_RATE_PARENT, 0x4a0, 0, 4, 7, },
+ { HI6220_BBPPLL0_DIV, "bbppll0_div", "bbppll_sel", CLK_SET_RATE_PARENT, 0x4a0, 8, 6, 15,},
+ { HI6220_CS_DAPB, "cs_dapb", "picophy_src", CLK_SET_RATE_PARENT, 0x4a0, 24, 2, 31,},
+ { HI6220_CS_ATB_DIV, "cs_atb_div", "cs_atb_syspll", CLK_SET_RATE_PARENT, 0x4a4, 0, 4, 7, },
+};
+
+static void __init hi6220_clk_sys_init(struct device_node *np)
+{
+ struct hisi_clock_data *clk_data;
+
+ clk_data = hisi_clk_init(np, HI6220_SYS_NR_CLKS);
+ if (!clk_data)
+ return;
+
+ hisi_clk_register_gate_sep(hi6220_separated_gate_clks_sys,
+ ARRAY_SIZE(hi6220_separated_gate_clks_sys), clk_data);
+
+ hisi_clk_register_mux(hi6220_mux_clks_sys,
+ ARRAY_SIZE(hi6220_mux_clks_sys), clk_data);
+
+ hi6220_clk_register_divider(hi6220_div_clks_sys,
+ ARRAY_SIZE(hi6220_div_clks_sys), clk_data);
+}
+CLK_OF_DECLARE(hi6220_clk_sys, "hisilicon,hi6220-clock-sys", hi6220_clk_sys_init);
+
+
+/* clocks in media controller */
+static const char *clk_1000_1200_src[] __initconst = { "pll_gpu_gate", "media_syspll_src", };
+static const char *clk_1440_1200_src[] __initconst = { "media_syspll_src", "media_pll_src", };
+static const char *clk_1000_1440_src[] __initconst = { "pll_gpu_gate", "media_pll_src", };
+
+static struct hisi_gate_clock hi6220_separated_gate_clks_media[] __initdata = {
+ { HI6220_DSI_PCLK, "dsi_pclk", "vpucodec", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 0, 0, },
+ { HI6220_G3D_PCLK, "g3d_pclk", "vpucodec", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 1, 0, },
+ { HI6220_ACLK_CODEC_VPU, "aclk_codec_vpu", "ade_core_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 3, 0, },
+ { HI6220_ISP_SCLK, "isp_sclk", "isp_sclk_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 5, 0, },
+ { HI6220_ADE_CORE, "ade_core", "ade_core_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 6, 0, },
+ { HI6220_MED_MMU, "media_mmu", "mmu_clk", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 8, 0, },
+ { HI6220_CFG_CSI4PHY, "cfg_csi4phy", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 9, 0, },
+ { HI6220_CFG_CSI2PHY, "cfg_csi2phy", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 10, 0, },
+ { HI6220_ISP_SCLK_GATE, "isp_sclk_gate", "media_pll_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 11, 0, },
+ { HI6220_ISP_SCLK_GATE1, "isp_sclk_gate1", "media_pll_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 12, 0, },
+ { HI6220_ADE_CORE_GATE, "ade_core_gate", "media_pll_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 14, 0, },
+ { HI6220_CODEC_VPU_GATE, "codec_vpu_gate", "clk_1000_1440", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 15, 0, },
+ { HI6220_MED_SYSPLL, "media_syspll_src", "media_syspll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 17, 0, },
+};
+
+static struct hisi_mux_clock hi6220_mux_clks_media[] __initdata = {
+ { HI6220_1440_1200, "clk_1440_1200", clk_1440_1200_src, ARRAY_SIZE(clk_1440_1200_src), CLK_SET_RATE_PARENT, 0x51c, 0, 1, 0, },
+ { HI6220_1000_1200, "clk_1000_1200", clk_1000_1200_src, ARRAY_SIZE(clk_1000_1200_src), CLK_SET_RATE_PARENT, 0x51c, 1, 1, 0, },
+ { HI6220_1000_1440, "clk_1000_1440", clk_1000_1440_src, ARRAY_SIZE(clk_1000_1440_src), CLK_SET_RATE_PARENT, 0x51c, 6, 1, 0, },
+};
+
+static struct hi6220_divider_clock hi6220_div_clks_media[] __initdata = {
+ { HI6220_CODEC_JPEG, "codec_jpeg_aclk", "media_pll_src", CLK_SET_RATE_PARENT, 0xcbc, 0, 4, 23, },
+ { HI6220_ISP_SCLK_SRC, "isp_sclk_src", "isp_sclk_gate", CLK_SET_RATE_PARENT, 0xcbc, 8, 4, 15, },
+ { HI6220_ISP_SCLK1, "isp_sclk1", "isp_sclk_gate1", CLK_SET_RATE_PARENT, 0xcbc, 24, 4, 31, },
+ { HI6220_ADE_CORE_SRC, "ade_core_src", "ade_core_gate", CLK_SET_RATE_PARENT, 0xcc0, 16, 3, 23, },
+ { HI6220_ADE_PIX_SRC, "ade_pix_src", "clk_1440_1200", CLK_SET_RATE_PARENT, 0xcc0, 24, 6, 31, },
+ { HI6220_G3D_CLK, "g3d_clk", "clk_1000_1200", CLK_SET_RATE_PARENT, 0xcc4, 8, 4, 15, },
+ { HI6220_CODEC_VPU_SRC, "codec_vpu_src", "codec_vpu_gate", CLK_SET_RATE_PARENT, 0xcc4, 24, 6, 31, },
+};
+
+static void __init hi6220_clk_media_init(struct device_node *np)
+{
+ struct hisi_clock_data *clk_data;
+
+ clk_data = hisi_clk_init(np, HI6220_MEDIA_NR_CLKS);
+ if (!clk_data)
+ return;
+
+ hisi_clk_register_gate_sep(hi6220_separated_gate_clks_media,
+ ARRAY_SIZE(hi6220_separated_gate_clks_media), clk_data);
+
+ hisi_clk_register_mux(hi6220_mux_clks_media,
+ ARRAY_SIZE(hi6220_mux_clks_media), clk_data);
+
+ hi6220_clk_register_divider(hi6220_div_clks_media,
+ ARRAY_SIZE(hi6220_div_clks_media), clk_data);
+}
+CLK_OF_DECLARE(hi6220_clk_media, "hisilicon,hi6220-clock-media", hi6220_clk_media_init);
+
+
+/* clocks in pmctrl */
+static struct hisi_gate_clock hi6220_gate_clks_power[] __initdata = {
+ { HI6220_PLL_GPU_GATE, "pll_gpu_gate", "gpupll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x8, 0, 0, },
+ { HI6220_PLL1_DDR_GATE, "pll1_ddr_gate", "ddrpll1", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x10, 0, 0, },
+ { HI6220_PLL_DDR_GATE, "pll_ddr_gate", "ddrpll0", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x18, 0, 0, },
+ { HI6220_PLL_MEDIA_GATE, "pll_media_gate", "media_pll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x38, 0, 0, },
+ { HI6220_PLL0_BBP_GATE, "pll0_bbp_gate", "bbppll0", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x48, 0, 0, },
+};
+
+static struct hi6220_divider_clock hi6220_div_clks_power[] __initdata = {
+ { HI6220_DDRC_SRC, "ddrc_src", "ddr_sel_src", CLK_SET_RATE_PARENT, 0x5a8, 0, 4, 0, },
+ { HI6220_DDRC_AXI1, "ddrc_axi1", "ddrc_src", CLK_SET_RATE_PARENT, 0x5a8, 8, 2, 0, },
+};
+
+static void __init hi6220_clk_power_init(struct device_node *np)
+{
+ struct hisi_clock_data *clk_data;
+
+ clk_data = hisi_clk_init(np, HI6220_POWER_NR_CLKS);
+ if (!clk_data)
+ return;
+
+ hisi_clk_register_gate(hi6220_gate_clks_power,
+ ARRAY_SIZE(hi6220_gate_clks_power), clk_data);
+
+ hi6220_clk_register_divider(hi6220_div_clks_power,
+ ARRAY_SIZE(hi6220_div_clks_power), clk_data);
+}
+CLK_OF_DECLARE(hi6220_clk_power, "hisilicon,hi6220-clock-power", hi6220_clk_power_init);
diff --git a/drivers/clk/hisilicon/clk.c b/drivers/clk/hisilicon/clk.c
index a078e84..5d2305c 100644
--- a/drivers/clk/hisilicon/clk.c
+++ b/drivers/clk/hisilicon/clk.c
@@ -232,3 +232,32 @@ void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *clks,
data->clk_data.clks[clks[i].id] = clk;
}
}
+
+void __init hi6220_clk_register_divider(struct hi6220_divider_clock *clks,
+ int nums, struct hisi_clock_data *data)
+{
+ struct clk *clk;
+ void __iomem *base = data->base;
+ int i;
+
+ for (i = 0; i < nums; i++) {
+ clk = hi6220_register_clkdiv(NULL, clks[i].name,
+ clks[i].parent_name,
+ clks[i].flags,
+ base + clks[i].offset,
+ clks[i].shift,
+ clks[i].width,
+ clks[i].mask_bit,
+ &hisi_clk_lock);
+ if (IS_ERR(clk)) {
+ pr_err("%s: failed to register clock %s\n",
+ __func__, clks[i].name);
+ continue;
+ }
+
+ if (clks[i].alias)
+ clk_register_clkdev(clk, clks[i].alias, NULL);
+
+ data->clk_data.clks[clks[i].id] = clk;
+ }
+}
diff --git a/drivers/clk/hisilicon/clk.h b/drivers/clk/hisilicon/clk.h
index 31083ff..462a570 100644
--- a/drivers/clk/hisilicon/clk.h
+++ b/drivers/clk/hisilicon/clk.h
@@ -79,6 +79,18 @@ struct hisi_divider_clock {
const char *alias;
};

+struct hi6220_divider_clock {
+ unsigned int id;
+ const char *name;
+ const char *parent_name;
+ unsigned long flags;
+ unsigned long offset;
+ u8 shift;
+ u8 width;
+ u32 mask_bit;
+ const char *alias;
+};
+
struct hisi_gate_clock {
unsigned int id;
const char *name;
@@ -94,6 +106,9 @@ struct clk *hisi_register_clkgate_sep(struct device *, const char *,
const char *, unsigned long,
void __iomem *, u8,
u8, spinlock_t *);
+struct clk *hi6220_register_clkdiv(struct device *dev, const char *name,
+ const char *parent_name, unsigned long flags, void __iomem *reg,
+ u8 shift, u8 width, u32 mask_bit, spinlock_t *lock);

struct hisi_clock_data __init *hisi_clk_init(struct device_node *, int);
void __init hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *,
@@ -108,4 +123,6 @@ void __init hisi_clk_register_gate(struct hisi_gate_clock *,
int, struct hisi_clock_data *);
void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *,
int, struct hisi_clock_data *);
+void __init hi6220_clk_register_divider(struct hi6220_divider_clock *,
+ int, struct hisi_clock_data *);
#endif /* __HISI_CLK_H */
diff --git a/drivers/clk/hisilicon/clkdivider-hi6220.c b/drivers/clk/hisilicon/clkdivider-hi6220.c
new file mode 100644
index 0000000..9e3825b
--- /dev/null
+++ b/drivers/clk/hisilicon/clkdivider-hi6220.c
@@ -0,0 +1,273 @@
+/*
+ * Hisilicon hi6220 SoC divider clock driver
+ *
+ * Copyright (c) 2015 Hisilicon Limited.
+ *
+ * Author: Bintian Wang <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+
+#define div_mask(width) ((1 << (width)) - 1)
+
+/*
+ * The reverse of DIV_ROUND_UP: The maximum number which
+ * divided by m is r
+ */
+#define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1)
+
+/**
+ * struct hi6220_clk_divider - divider clock for hi6220
+ *
+ * @hw: handle between common and hardware-specific interfaces
+ * @reg: register containing divider
+ * @shift: shift to the divider bit field
+ * @width: width of the divider bit field
+ * @mask: mask for setting divider rate
+ * @table: the div table that the divider supports
+ * @lock: register lock
+ */
+struct hi6220_clk_divider {
+ struct clk_hw hw;
+ void __iomem *reg;
+ u8 shift;
+ u8 width;
+ u32 mask;
+ const struct clk_div_table *table;
+ spinlock_t *lock;
+};
+
+#define to_hi6220_clk_divider(_hw) \
+ container_of(_hw, struct hi6220_clk_divider, hw)
+
+static unsigned int hi6220_get_table_maxdiv(const struct clk_div_table *table)
+{
+ unsigned int maxdiv = 0;
+ const struct clk_div_table *clkt;
+
+ for (clkt = table; clkt->div; clkt++)
+ if (clkt->div > maxdiv)
+ maxdiv = clkt->div;
+ return maxdiv;
+}
+
+static unsigned int hi6220_get_table_div(const struct clk_div_table *table,
+ unsigned int val)
+{
+ const struct clk_div_table *clkt;
+
+ for (clkt = table; clkt->div; clkt++)
+ if (clkt->val == val)
+ return clkt->div;
+
+ return 0;
+}
+
+static unsigned int hi6220_get_table_val(const struct clk_div_table *table,
+ unsigned int div)
+{
+ const struct clk_div_table *clkt;
+
+ for (clkt = table; clkt->div; clkt++)
+ if (clkt->div == div)
+ return clkt->val;
+ return 0;
+}
+
+static unsigned long hi6220_clkdiv_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ unsigned int div, val;
+ struct hi6220_clk_divider *dclk = to_hi6220_clk_divider(hw);
+
+ val = readl_relaxed(dclk->reg) >> dclk->shift;
+ val &= div_mask(dclk->width);
+
+ div = hi6220_get_table_div(dclk->table, val);
+ if (!div) {
+ pr_warn("%s: Invalid divisor for clock %s\n", __func__,
+ __clk_get_name(hw->clk));
+ return parent_rate;
+ }
+
+ return parent_rate / div;
+}
+
+static bool hi6220_is_valid_div(const struct clk_div_table *table,
+ unsigned int div)
+{
+ const struct clk_div_table *clkt;
+
+ for (clkt = table; clkt->div; clkt++)
+ if (clkt->div == div)
+ return true;
+ return false;
+}
+
+static int hi6220_clkdiv_bestdiv(struct clk_hw *hw, unsigned long rate,
+ unsigned long *best_parent_rate)
+{
+ unsigned int i, bestdiv = 0;
+ unsigned long parent_rate, best = 0, now, maxdiv;
+
+ struct hi6220_clk_divider *dclk = to_hi6220_clk_divider(hw);
+ struct clk *clk_parent = __clk_get_parent(hw->clk);
+
+ maxdiv = hi6220_get_table_maxdiv(dclk->table);
+
+ if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) {
+ parent_rate = *best_parent_rate;
+ bestdiv = DIV_ROUND_UP(parent_rate, rate);
+ bestdiv = (bestdiv == 0) ? 1 : bestdiv;
+ bestdiv = (bestdiv > maxdiv) ? maxdiv : bestdiv;
+ return bestdiv;
+ }
+
+ /*
+ * The maximum divider we can use without overflowing
+ * unsigned long in rate * i below
+ */
+ maxdiv = min(ULONG_MAX / rate, maxdiv);
+
+ for (i = 1; i <= maxdiv; i++) {
+ if (!hi6220_is_valid_div(dclk->table, i))
+ continue;
+ parent_rate = __clk_round_rate(clk_parent,
+ MULT_ROUND_UP(rate, i));
+ now = parent_rate / i;
+ if (now <= rate && now > best) {
+ bestdiv = i;
+ best = now;
+ *best_parent_rate = parent_rate;
+ }
+ }
+
+ if (!bestdiv) {
+ bestdiv = hi6220_get_table_maxdiv(dclk->table);
+ *best_parent_rate = __clk_round_rate(clk_parent, 1);
+ }
+
+ return bestdiv;
+}
+
+static long hi6220_clkdiv_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ int div;
+
+ if (!rate)
+ rate = 1;
+
+ div = hi6220_clkdiv_bestdiv(hw, rate, prate);
+
+ return *prate / div;
+}
+
+static int hi6220_clkdiv_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ unsigned int div, value;
+ unsigned long flags = 0;
+ u32 data;
+ struct hi6220_clk_divider *dclk = to_hi6220_clk_divider(hw);
+
+ div = parent_rate / rate;
+
+ if (!hi6220_is_valid_div(dclk->table, div))
+ return -EINVAL;
+
+ value = hi6220_get_table_val(dclk->table, div);
+
+ if (value > div_mask(dclk->width))
+ value = div_mask(dclk->width);
+
+ if (dclk->lock)
+ spin_lock_irqsave(dclk->lock, flags);
+
+ data = readl_relaxed(dclk->reg);
+ data &= ~(div_mask(dclk->width) << dclk->shift);
+ data |= value << dclk->shift;
+ data |= dclk->mask;
+
+ writel_relaxed(data, dclk->reg);
+
+ if (dclk->lock)
+ spin_unlock_irqrestore(dclk->lock, flags);
+
+ return 0;
+}
+
+static struct clk_ops hi6220_clkdiv_ops = {
+ .recalc_rate = hi6220_clkdiv_recalc_rate,
+ .round_rate = hi6220_clkdiv_round_rate,
+ .set_rate = hi6220_clkdiv_set_rate,
+};
+
+struct clk *hi6220_register_clkdiv(struct device *dev, const char *name,
+ const char *parent_name, unsigned long flags, void __iomem *reg,
+ u8 shift, u8 width, u32 mask_bit, spinlock_t *lock)
+{
+ struct hi6220_clk_divider *div;
+ struct clk *clk;
+ struct clk_init_data init;
+ struct clk_div_table *table;
+ u32 max_div, min_div;
+ int i;
+
+ /* allocate the divider */
+ div = kzalloc(sizeof(struct hi6220_clk_divider), GFP_KERNEL);
+ if (!div) {
+ pr_err("%s: could not allocate divider clk\n", __func__);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ /* Init the divider table */
+ max_div = div_mask(width) + 1;
+ min_div = 1;
+
+ table = kzalloc(sizeof(struct clk_div_table) * (max_div + 1), GFP_KERNEL);
+ if (!table) {
+ kfree(div);
+ pr_err("%s: failed to alloc divider table!\n", __func__);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ for (i = 0; i < max_div; i++) {
+ table[i].div = min_div + i;
+ table[i].val = table[i].div - 1;
+ }
+
+ init.name = name;
+ init.ops = &hi6220_clkdiv_ops;
+ init.flags = flags | CLK_IS_BASIC;
+ init.parent_names = parent_name ? &parent_name : NULL;
+ init.num_parents = parent_name ? 1 : 0;
+
+ /* struct hi6220_clk_divider assignments */
+ div->reg = reg;
+ div->shift = shift;
+ div->width = width;
+ div->mask = mask_bit ? BIT(mask_bit) : 0;
+ div->lock = lock;
+ div->hw.init = &init;
+ div->table = table;
+
+ /* register the clock */
+ clk = clk_register(dev, &div->hw);
+
+ if (IS_ERR(clk)) {
+ kfree(table);
+ kfree(div);
+ }
+
+ return clk;
+}
diff --git a/include/dt-bindings/clock/hi6220-clock.h b/include/dt-bindings/clock/hi6220-clock.h
new file mode 100644
index 0000000..05033e7
--- /dev/null
+++ b/include/dt-bindings/clock/hi6220-clock.h
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2015 Hisilicon Limited.
+ *
+ * Author: Bintian Wang <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __DT_BINDINGS_CLOCK_HI6220_H
+#define __DT_BINDINGS_CLOCK_HI6220_H
+
+/* clk in AO (always on) controller */
+#define HI6220_NONE_CLOCK 0
+
+/* fixed rate clocks */
+#define HI6220_REF32K 1
+#define HI6220_CLK_TCXO 2
+#define HI6220_MMC1_PAD 3
+#define HI6220_MMC2_PAD 4
+#define HI6220_MMC0_PAD 5
+#define HI6220_PLL_BBP 6
+#define HI6220_PLL_GPU 7
+#define HI6220_PLL1_DDR 8
+#define HI6220_PLL_SYS 9
+#define HI6220_PLL_SYS_MEDIA 10
+#define HI6220_DDR_SRC 11
+#define HI6220_PLL_MEDIA 12
+#define HI6220_PLL_DDR 13
+
+/* fixed factor clocks */
+#define HI6220_300M 16
+#define HI6220_150M 17
+#define HI6220_PICOPHY_SRC 18
+#define HI6220_MMC0_SRC_SEL 19
+#define HI6220_MMC1_SRC_SEL 20
+#define HI6220_MMC2_SRC_SEL 21
+#define HI6220_VPU_CODEC 22
+#define HI6220_MMC0_SMP 23
+#define HI6220_MMC1_SMP 24
+#define HI6220_MMC2_SMP 25
+
+/* gate clocks */
+#define HI6220_WDT0_PCLK 28
+#define HI6220_WDT1_PCLK 29
+#define HI6220_WDT2_PCLK 30
+#define HI6220_TIMER0_PCLK 31
+#define HI6220_TIMER1_PCLK 32
+#define HI6220_TIMER2_PCLK 33
+#define HI6220_TIMER3_PCLK 34
+#define HI6220_TIMER4_PCLK 35
+#define HI6220_TIMER5_PCLK 36
+#define HI6220_TIMER6_PCLK 37
+#define HI6220_TIMER7_PCLK 38
+#define HI6220_TIMER8_PCLK 39
+#define HI6220_UART0_PCLK 40
+
+#define HI6220_AO_NR_CLKS 48
+
+/* clk in systrl */
+/* gate clock */
+#define HI6220_MMC0_CLK 1
+#define HI6220_MMC0_CIUCLK 2
+#define HI6220_MMC1_CLK 3
+#define HI6220_MMC1_CIUCLK 4
+#define HI6220_MMC2_CLK 5
+#define HI6220_MMC2_CIUCLK 6
+#define HI6220_USBOTG_HCLK 7
+#define HI6220_CLK_PICOPHY 8
+#define HI6220_HIFI 9
+#define HI6220_DACODEC_PCLK 10
+#define HI6220_EDMAC_ACLK 11
+#define HI6220_CS_ATB 12
+#define HI6220_I2C0_CLK 13
+#define HI6220_I2C1_CLK 14
+#define HI6220_I2C2_CLK 15
+#define HI6220_I2C3_CLK 16
+#define HI6220_UART1_PCLK 17
+#define HI6220_UART2_PCLK 18
+#define HI6220_UART3_PCLK 19
+#define HI6220_UART4_PCLK 20
+#define HI6220_SPI_CLK 21
+#define HI6220_MMU_CLK 22
+#define HI6220_HIFI_SEL 23
+#define HI6220_MMC0_SYSPLL 24
+#define HI6220_MMC1_SYSPLL 25
+#define HI6220_MMC2_SYSPLL 26
+#define HI6220_MMC0_SEL 27
+#define HI6220_MMC1_SEL 28
+#define HI6220_BBPPLL_SEL 29
+#define HI6220_MEDIA_PLL_SRC 30
+#define HI6220_MMC2_SEL 31
+#define HI6220_CS_ATB_SYSPLL 32
+
+/* mux clocks */
+#define HI6220_MMC0_SRC 35
+#define HI6220_MMC0_SMP_IN 36
+#define HI6220_MMC1_SRC 37
+#define HI6220_MMC1_SMP_IN 38
+#define HI6220_MMC2_SRC 39
+#define HI6220_MMC2_SMP_IN 40
+#define HI6220_HIFI_SRC 41
+#define HI6220_UART1_SRC 42
+#define HI6220_UART2_SRC 43
+#define HI6220_UART3_SRC 44
+#define HI6220_UART4_SRC 45
+#define HI6220_MMC0_MUX0 46
+#define HI6220_MMC1_MUX0 47
+#define HI6220_MMC2_MUX0 48
+#define HI6220_MMC0_MUX1 49
+#define HI6220_MMC1_MUX1 50
+#define HI6220_MMC2_MUX1 51
+
+/* divider clocks */
+#define HI6220_CLK_BUS 54
+#define HI6220_MMC0_DIV 55
+#define HI6220_MMC1_DIV 56
+#define HI6220_MMC2_DIV 57
+#define HI6220_HIFI_DIV 58
+#define HI6220_BBPPLL0_DIV 59
+#define HI6220_CS_DAPB 60
+#define HI6220_CS_ATB_DIV 61
+
+#define HI6220_SYS_NR_CLKS 64
+
+/* clk in media controller */
+/* gate clocks */
+#define HI6220_DSI_PCLK 1
+#define HI6220_G3D_PCLK 2
+#define HI6220_ACLK_CODEC_VPU 3
+#define HI6220_ISP_SCLK 4
+#define HI6220_ADE_CORE 5
+#define HI6220_MED_MMU 6
+#define HI6220_CFG_CSI4PHY 7
+#define HI6220_CFG_CSI2PHY 8
+#define HI6220_ISP_SCLK_GATE 9
+#define HI6220_ISP_SCLK_GATE1 10
+#define HI6220_ADE_CORE_GATE 11
+#define HI6220_CODEC_VPU_GATE 12
+#define HI6220_MED_SYSPLL 13
+
+/* mux clocks */
+#define HI6220_1440_1200 20
+#define HI6220_1000_1200 21
+#define HI6220_1000_1440 22
+
+/* divider clocks */
+#define HI6220_CODEC_JPEG 30
+#define HI6220_ISP_SCLK_SRC 31
+#define HI6220_ISP_SCLK1 32
+#define HI6220_ADE_CORE_SRC 33
+#define HI6220_ADE_PIX_SRC 34
+#define HI6220_G3D_CLK 35
+#define HI6220_CODEC_VPU_SRC 36
+
+#define HI6220_MEDIA_NR_CLKS 40
+
+/* clk in power controller */
+/* gate clocks */
+#define HI6220_PLL_GPU_GATE 1
+#define HI6220_PLL1_DDR_GATE 2
+#define HI6220_PLL_DDR_GATE 3
+#define HI6220_PLL_MEDIA_GATE 4
+#define HI6220_PLL0_BBP_GATE 5
+
+/* divider clocks */
+#define HI6220_DDRC_SRC 10
+#define HI6220_DDRC_AXI1 11
+
+#define HI6220_POWER_NR_CLKS 16
+#endif
--
1.7.9.5

2015-02-05 09:22:41

by Bintian

[permalink] [raw]
Subject: [PATCH 3/3] arm64: dts: Add dts files for Hisilicon Hi6220 SoC

Add initial dtsi file to support Hisilicon Hi6220 SoC with
support of Octal core CPUs in two clusters and each cluster
has quard Cortex-A53.

We now use the "spin-table" method for SMP, and it will be
changed to PSCI later.

Also add dts file to support HiKey development board which
based on Hi6220 SoC and document the devicetree bindings.

These dts files will be changed later and more nodes will be
added to describe other devices.

Signed-off-by: Bintian Wang <[email protected]>
Reviewed-by: Haojian Zhuang <[email protected]>
Reviewed-by: Yiping Xu <[email protected]>
---
.../bindings/arm/hisilicon/hisilicon.txt | 33 ++++
arch/arm64/boot/dts/Makefile | 1 +
arch/arm64/boot/dts/hisilicon/Makefile | 5 +
arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts | 31 +++
arch/arm64/boot/dts/hisilicon/hi6220.dtsi | 204 ++++++++++++++++++++
5 files changed, 274 insertions(+)
create mode 100644 arch/arm64/boot/dts/hisilicon/Makefile
create mode 100644 arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts
create mode 100644 arch/arm64/boot/dts/hisilicon/hi6220.dtsi

diff --git a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
index f717c7b..5eb6b41 100644
--- a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
+++ b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
@@ -9,6 +9,9 @@ HiP04 D01 Board
Required root node properties:
- compatible = "hisilicon,hip04-d01";

+HiKey Board
+Required root node properties:
+ - compatible = "hisilicon,hi6220-hikey";

Hisilicon system controller

@@ -62,6 +65,36 @@ Example:
};

-----------------------------------------------------------------------
+Hisilicon Power Always ON domain controller
+
+Required properties:
+- compatible : "hisilicon,aoctrl"
+- reg : Register address and size
+
+Some clock registers are defined in power always on system controller,
+especially in Hi6220 SoC which is used for mobile platform.
+
+-----------------------------------------------------------------------
+Hisilicon Media domain controller
+
+Required properties:
+- compatible : "hisilicon,mediactrl"
+- reg : Register address and size
+
+Some clock registers of media module are defined in media system
+controller, especially in Hi6220 SoC which is used for mobile platform.
+
+-----------------------------------------------------------------------
+Hisilicon Power Management domain controller
+
+Required properties:
+- compatible : "hisilicon,pmctrl"
+- reg : Register address and size
+
+Some clock registers and PMU registers are defined in power management
+controller, especially in Hin6220 SoC which is used for mobile platform.
+
+-----------------------------------------------------------------------
Fabric:

Required Properties:
diff --git a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile
index c62b0f4..bffd6b7 100644
--- a/arch/arm64/boot/dts/Makefile
+++ b/arch/arm64/boot/dts/Makefile
@@ -2,5 +2,6 @@ dts-dirs += amd
dts-dirs += apm
dts-dirs += arm
dts-dirs += cavium
+dts-dirs += hisilicon

subdir-y := $(dts-dirs)
diff --git a/arch/arm64/boot/dts/hisilicon/Makefile b/arch/arm64/boot/dts/hisilicon/Makefile
new file mode 100644
index 0000000..fa81a6e
--- /dev/null
+++ b/arch/arm64/boot/dts/hisilicon/Makefile
@@ -0,0 +1,5 @@
+dtb-$(CONFIG_ARCH_HISI) += hi6220-hikey.dtb
+
+always := $(dtb-y)
+subdir-y := $(dts-dirs)
+clean-files := *.dtb
diff --git a/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts b/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts
new file mode 100644
index 0000000..a94da84
--- /dev/null
+++ b/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts
@@ -0,0 +1,31 @@
+/*
+ * dts file for Hisilicon HiKey Development Board
+ *
+ * Copyright (C) 2015, Hisilicon Ltd.
+ *
+ */
+
+/dts-v1/;
+
+/memreserve/ 0x0740f000 0x1000;
+
+#include "hi6220.dtsi"
+
+/ {
+ model = "HiKey Development Board";
+ compatible = "hisilicon,hi6220-hikey";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ interrupt-parent = <&gic>;
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen { };
+
+ memory@7400000 {
+ device_type = "memory";
+ reg = <0x0 0x07400000 0x0 0x38c00000>;
+ };
+};
diff --git a/arch/arm64/boot/dts/hisilicon/hi6220.dtsi b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
new file mode 100644
index 0000000..53ba9cf
--- /dev/null
+++ b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
@@ -0,0 +1,204 @@
+/*
+ * dts file for Hisilicon Hi6220 SoC
+ *
+ * Copyright (C) 2015, Hisilicon Ltd.
+ */
+
+#include <dt-bindings/clock/hi6220-clock.h>
+
+/ {
+ cpu-map {
+ cluster0 {
+ core0 {
+ cpu = <&cpu0>;
+ };
+ core1 {
+ cpu = <&cpu1>;
+ };
+ core2 {
+ cpu = <&cpu2>;
+ };
+ core3 {
+ cpu = <&cpu3>;
+ };
+ };
+ cluster1 {
+ core0 {
+ cpu = <&cpu4>;
+ };
+ core1 {
+ cpu = <&cpu5>;
+ };
+ core2 {
+ cpu = <&cpu6>;
+ };
+ core3 {
+ cpu = <&cpu7>;
+ };
+ };
+ };
+
+ cpus {
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ cpu0: cpu@000 {
+ compatible = "arm,cortex-a53", "arm,armv8";
+ device_type = "cpu";
+ reg = <0x0 0x0>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0x0 0x740fff8>;
+ clock-latency = <0>;
+ };
+ cpu1: cpu@001 {
+ compatible = "arm,cortex-a53", "arm,armv8";
+ device_type = "cpu";
+ reg = <0x0 0x1>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0x0 0x740fff8>;
+ clock-latency = <0>;
+ };
+ cpu2: cpu@002 {
+ compatible = "arm,cortex-a53", "arm,armv8";
+ device_type = "cpu";
+ reg = <0x0 0x2>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0x0 0x740fff8>;
+ clock-latency = <0>;
+ };
+ cpu3: cpu@003 {
+ compatible = "arm,cortex-a53", "arm,armv8";
+ device_type = "cpu";
+ reg = <0x0 0x3>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0x0 0x740fff8>;
+ clock-latency = <0>;
+ };
+ cpu4: cpu@100 {
+ compatible = "arm,cortex-a53", "arm,armv8";
+ device_type = "cpu";
+ reg = <0x0 0x100>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0x0 0x740fff8>;
+ clock-latency = <0>;
+ };
+ cpu5: cpu@101 {
+ compatible = "arm,cortex-a53", "arm,armv8";
+ device_type = "cpu";
+ reg = <0x0 0x101>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0x0 0x740fff8>;
+ clock-latency = <0>;
+ };
+ cpu6: cpu@102 {
+ compatible = "arm,cortex-a53", "arm,armv8";
+ device_type = "cpu";
+ reg = <0x0 0x102>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0x0 0x740fff8>;
+ clock-latency = <0>;
+ };
+ cpu7: cpu@103 {
+ compatible = "arm,cortex-a53", "arm,armv8";
+ device_type = "cpu";
+ reg = <0x0 0x103>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0x0 0x740fff8>;
+ clock-latency = <0>;
+ };
+ };
+
+ gic: interrupt-controller@f6800000 {
+ compatible = "arm,gic-400", "arm,cortex-a15-gic";
+ reg = <0x0 0xf6801000 0x0 0x1000>, /* GICD */
+ <0x0 0xf6802000 0x0 0x2000>, /* GICC */
+ <0x0 0xf6804000 0x0 0x2000>, /* GICH */
+ <0x0 0xf6806000 0x0 0x2000>; /* GICV */
+ #interrupt-cells = <3>;
+ #address-cells = <0>;
+ interrupt-controller;
+ };
+
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupt-parent = <&gic>;
+ interrupts = <1 13 0xff08>,
+ <1 14 0xff08>,
+ <1 11 0xff08>,
+ <1 10 0xff08>;
+ clock-frequency = <1200000>;
+ };
+
+ soc {
+ compatible = "simple-bus";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ interrupt-parent = <&gic>;
+ ranges;
+
+ ao_ctrl: ao_ctrl {
+ compatible = "hisilicon,aoctrl", "syscon";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x0 0xf7800000 0x0 0x2000>;
+ ranges = <0 0x0 0xf7800000 0x2000>;
+
+ clock_ao: clock0@0 {
+ compatible = "hisilicon,hi6220-clock-ao";
+ reg = <0 0x1000>;
+ #clock-cells = <1>;
+ };
+ };
+
+ sys_ctrl: sys_ctrl {
+ compatible = "hisilicon,sysctrl", "syscon";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x0 0xf7030000 0x0 0x2000>;
+ ranges = <0 0x0 0xf7030000 0x2000>;
+
+ clock_sys: clock1@0 {
+ compatible = "hisilicon,hi6220-clock-sys";
+ reg = <0 0x1000>;
+ #clock-cells = <1>;
+ };
+ };
+
+ media_ctrl: media_ctrl {
+ compatible = "hisilicon,mediactrl", "syscon";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x0 0xf4410000 0x0 0x1000>;
+ ranges = <0 0x0 0xf4410000 0x1000>;
+
+ clock_media: clock2@0 {
+ compatible = "hisilicon,hi6220-clock-media";
+ reg = <0 0x1000>;
+ #clock-cells = <1>;
+ };
+ };
+
+ pm_ctrl: pm_ctrl {
+ compatible = "hisilicon,pmctrl", "syscon";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x0 0xf7032000 0x0 0x1000>;
+ ranges = <0 0x0 0xf7032000 0x1000>;
+
+ clock_power: clock3@0 {
+ compatible = "hisilicon,hi6220-clock-power";
+ reg = <0 0x1000>;
+ #clock-cells = <1>;
+ };
+ };
+
+ uart0: uart@f8015000 { /* console */
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x0 0xf8015000 0x0 0x1000>;
+ interrupts = <0 36 4>;
+ clocks = <&clock_ao HI6220_UART0_PCLK>, <&clock_ao HI6220_UART0_PCLK>;
+ clock-names = "uartclk", "apb_pclk";
+ };
+ };
+};
--
1.7.9.5

2015-02-05 18:46:35

by Tyler Baker

[permalink] [raw]
Subject: Re: [PATCH 0/3] arm64,hi6220: Enable Hisilicon Hi6220 SoC

Hi Bintian,

On 5 February 2015 at 01:24, Bintian Wang <[email protected]> wrote:
> Hello,
>
> Hi6220 is one mobile solution of Hisilicon, this patchset contains
> initial support for Hi6220 SoC and HiKey development board, which
> is based on ARM Cortex A53 architecture. Initial support is minimal
> and includes just the arch configuration, clock driver, device tree
> configuration.
>
> Many peripheral drivers will be submitted later.
>
> Any comments will be appreciated!
>
> Thanks,
>
> Bintian Wang (3):
> arm64: Enable Hisilicon ARMv8 SoC family in Kconfig and defconfig
> clk: hi6220: Clock driver support for Hisilicon hi6220 SoC
> arm64: dts: Add dts files for Hisilicon Hi6220 SoC

Thanks for posting these! I've applied this series on top of
next-20150204, however there was some fuzz that needed to be cleaned
up on 3/3 [1]. I've confirmed the platform is booting to a basic user
space without issue.

Tested-by: Tyler Baker <[email protected]>

>
> .../bindings/arm/hisilicon/hisilicon.txt | 33 +++
> .../devicetree/bindings/clock/hi6220-clock.txt | 30 +++
> arch/arm64/Kconfig | 6 +
> arch/arm64/boot/dts/Makefile | 1 +
> arch/arm64/boot/dts/hisilicon/Makefile | 5 +
> arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts | 31 +++
> arch/arm64/boot/dts/hisilicon/hi6220.dtsi | 204 ++++++++++++++
> arch/arm64/configs/defconfig | 1 +
> drivers/clk/Kconfig | 2 +
> drivers/clk/Makefile | 4 +-
> drivers/clk/hisilicon/Kconfig | 5 +
> drivers/clk/hisilicon/Makefile | 1 +
> drivers/clk/hisilicon/clk-hi6220.c | 284 ++++++++++++++++++++
> drivers/clk/hisilicon/clk.c | 29 ++
> drivers/clk/hisilicon/clk.h | 17 ++
> drivers/clk/hisilicon/clkdivider-hi6220.c | 273 +++++++++++++++++++
> include/dt-bindings/clock/hi6220-clock.h | 172 ++++++++++++
> 17 files changed, 1095 insertions(+), 3 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/clock/hi6220-clock.txt
> create mode 100644 arch/arm64/boot/dts/hisilicon/Makefile
> create mode 100644 arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts
> create mode 100644 arch/arm64/boot/dts/hisilicon/hi6220.dtsi
> create mode 100644 drivers/clk/hisilicon/Kconfig
> create mode 100644 drivers/clk/hisilicon/clk-hi6220.c
> create mode 100644 drivers/clk/hisilicon/clkdivider-hi6220.c
> create mode 100644 include/dt-bindings/clock/hi6220-clock.h
>
> --
> 1.7.9.5
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Cheers,

Tyler

[1] https://git.linaro.org/people/tyler.baker/linux.git/commitdiff/e9ab7b08e844009c66ba5ecf946d4b3e23551f73?hp=fcfe654f30cf75c847f69b2965c6b9e4d01c5b08

2015-02-05 19:02:10

by Olof Johansson

[permalink] [raw]
Subject: Re: [PATCH 0/3] arm64,hi6220: Enable Hisilicon Hi6220 SoC

On Thu, Feb 5, 2015 at 10:46 AM, Tyler Baker <[email protected]> wrote:
> Hi Bintian,
>
> On 5 February 2015 at 01:24, Bintian Wang <[email protected]> wrote:
>> Hello,
>>
>> Hi6220 is one mobile solution of Hisilicon, this patchset contains
>> initial support for Hi6220 SoC and HiKey development board, which
>> is based on ARM Cortex A53 architecture. Initial support is minimal
>> and includes just the arch configuration, clock driver, device tree
>> configuration.
>>
>> Many peripheral drivers will be submitted later.
>>
>> Any comments will be appreciated!
>>
>> Thanks,
>>
>> Bintian Wang (3):
>> arm64: Enable Hisilicon ARMv8 SoC family in Kconfig and defconfig
>> clk: hi6220: Clock driver support for Hisilicon hi6220 SoC
>> arm64: dts: Add dts files for Hisilicon Hi6220 SoC
>
> Thanks for posting these! I've applied this series on top of
> next-20150204, however there was some fuzz that needed to be cleaned
> up on 3/3 [1]. I've confirmed the platform is booting to a basic user
> space without issue.

>From ramdisk only, right? Given the timing of the posting of this
patch set, I'm not going to merge it for 3.20. Hopefully for 3.21
there will be some more peripheral support as well -- at least some
sort of storage device.


-Olof

2015-02-05 19:26:08

by Mark Rutland

[permalink] [raw]
Subject: Re: [PATCH 2/3] clk: hi6220: Clock driver support for Hisilicon hi6220 SoC

On Thu, Feb 05, 2015 at 09:24:36AM +0000, Bintian Wang wrote:
> Add clock drivers for hi6220 SoC, this driver controls the SoC
> registers to supply different clocks to different IPs in the SoC.
>
> We add one divider clock for hi6220 because the divider in hi6220
> also has a mask bit but it doesnot obey the rule defined by flag
> "CLK_DIVIDER_HIWORD_MASK", we can not get index of the mask bit by
> left shift fixed bits (e.g. 16 bits), so we add this divider clock
> to handle it.
>
> This patch also enables this clock driver for ARCH_HISI and document
> devicetree bindings.
>
> Signed-off-by: Bintian Wang <[email protected]>
> Reviewed-by: Haojian Zhuang <[email protected]>
> Reviewed-by: Zhangfei Gao <[email protected]>
> ---
> .../devicetree/bindings/clock/hi6220-clock.txt | 30 +++
> arch/arm64/Kconfig | 1 +
> drivers/clk/Kconfig | 2 +
> drivers/clk/Makefile | 4 +-
> drivers/clk/hisilicon/Kconfig | 5 +
> drivers/clk/hisilicon/Makefile | 1 +
> drivers/clk/hisilicon/clk-hi6220.c | 284 ++++++++++++++++++++
> drivers/clk/hisilicon/clk.c | 29 ++
> drivers/clk/hisilicon/clk.h | 17 ++
> drivers/clk/hisilicon/clkdivider-hi6220.c | 273 +++++++++++++++++++
> include/dt-bindings/clock/hi6220-clock.h | 172 ++++++++++++
> 11 files changed, 815 insertions(+), 3 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/clock/hi6220-clock.txt
> create mode 100644 drivers/clk/hisilicon/Kconfig
> create mode 100644 drivers/clk/hisilicon/clk-hi6220.c
> create mode 100644 drivers/clk/hisilicon/clkdivider-hi6220.c
> create mode 100644 include/dt-bindings/clock/hi6220-clock.h
>
> diff --git a/Documentation/devicetree/bindings/clock/hi6220-clock.txt b/Documentation/devicetree/bindings/clock/hi6220-clock.txt
> new file mode 100644
> index 0000000..a3ddda1
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/hi6220-clock.txt
> @@ -0,0 +1,30 @@
> +* Hisilicon Hi6220 Clock Controller
> +
> +The hi6220 clock controller generates and supplies clock to various
> +controllers within the hi6220 SoC.
> +
> +Required Properties:
> +
> +- compatible: should be one of the following:
> + - "hisilicon,hi6220-clock-ao" - controller for those clocks under SoC
> + power always on(AO) domain, it is the sub node of SoC power AO
> + controller in dts file.
> + - "hisilicon,hi6220-clock-sys" - controller for those clocks under SoC
> + system control domain, it is the sub node of SoC system controller
> + in dts file.
> + - "hisilicon,hi6220-clock-media" - controller for those clocks under
> + SoC media control domain, it is the sub node of SoC media controller
> + in dts file.
> + - "hisilicon,hi6220-clock-power" - controller for those clocks under
> + SoC power control domain, it is the sub node of SoC power controller
> + in dts file.

These all refer to things which aren't documented (yet).

Please sort out your patches so that any documentation you depend on
comes earlier.

Please also separate documentation from code. Note that dt includes are
_bindings_ and should be added with the relevant documentation.

Thanks,
Mark.

2015-02-05 19:30:57

by Mark Rutland

[permalink] [raw]
Subject: Re: [PATCH 3/3] arm64: dts: Add dts files for Hisilicon Hi6220 SoC

On Thu, Feb 05, 2015 at 09:24:37AM +0000, Bintian Wang wrote:
> Add initial dtsi file to support Hisilicon Hi6220 SoC with
> support of Octal core CPUs in two clusters and each cluster
> has quard Cortex-A53.
>
> We now use the "spin-table" method for SMP, and it will be
> changed to PSCI later.

If that's the case, please don't place the enable-method and related
properties in this file. Get your bootloader to add the appropriate
properties for its boot protocol.

When is PSCI likely to appear?

Are we certain of the split between components the PSCI implementation
must touch and those the kernel must touch?

> Also add dts file to support HiKey development board which
> based on Hi6220 SoC and document the devicetree bindings.
>
> These dts files will be changed later and more nodes will be
> added to describe other devices.

How is this going to be changed other than the addition of nodes?

Will this DTB continue to work in future? Or do you intend to make
changes that will break support?

> Signed-off-by: Bintian Wang <[email protected]>
> Reviewed-by: Haojian Zhuang <[email protected]>
> Reviewed-by: Yiping Xu <[email protected]>
> ---
> .../bindings/arm/hisilicon/hisilicon.txt | 33 ++++
> arch/arm64/boot/dts/Makefile | 1 +
> arch/arm64/boot/dts/hisilicon/Makefile | 5 +
> arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts | 31 +++
> arch/arm64/boot/dts/hisilicon/hi6220.dtsi | 204 ++++++++++++++++++++
> 5 files changed, 274 insertions(+)
> create mode 100644 arch/arm64/boot/dts/hisilicon/Makefile
> create mode 100644 arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts
> create mode 100644 arch/arm64/boot/dts/hisilicon/hi6220.dtsi
>
> diff --git a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
> index f717c7b..5eb6b41 100644
> --- a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
> +++ b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
> @@ -9,6 +9,9 @@ HiP04 D01 Board
> Required root node properties:
> - compatible = "hisilicon,hip04-d01";
>
> +HiKey Board
> +Required root node properties:
> + - compatible = "hisilicon,hi6220-hikey";
>
> Hisilicon system controller
>
> @@ -62,6 +65,36 @@ Example:
> };
>
> -----------------------------------------------------------------------
> +Hisilicon Power Always ON domain controller
> +
> +Required properties:
> +- compatible : "hisilicon,aoctrl"
> +- reg : Register address and size
> +
> +Some clock registers are defined in power always on system controller,
> +especially in Hi6220 SoC which is used for mobile platform.
> +
> +-----------------------------------------------------------------------
> +Hisilicon Media domain controller
> +
> +Required properties:
> +- compatible : "hisilicon,mediactrl"
> +- reg : Register address and size
> +
> +Some clock registers of media module are defined in media system
> +controller, especially in Hi6220 SoC which is used for mobile platform.
> +
> +-----------------------------------------------------------------------
> +Hisilicon Power Management domain controller
> +
> +Required properties:
> +- compatible : "hisilicon,pmctrl"
> +- reg : Register address and size
> +
> +Some clock registers and PMU registers are defined in power management
> +controller, especially in Hin6220 SoC which is used for mobile platform.
> +
> +-----------------------------------------------------------------------

Looking at the dts below, none of these binding docs are sufficient.

Define _all_ the properties and what they mean.

Please also split documentation into earlier patches.

> Fabric:
>
> Required Properties:
> diff --git a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile
> index c62b0f4..bffd6b7 100644
> --- a/arch/arm64/boot/dts/Makefile
> +++ b/arch/arm64/boot/dts/Makefile
> @@ -2,5 +2,6 @@ dts-dirs += amd
> dts-dirs += apm
> dts-dirs += arm
> dts-dirs += cavium
> +dts-dirs += hisilicon
>
> subdir-y := $(dts-dirs)
> diff --git a/arch/arm64/boot/dts/hisilicon/Makefile b/arch/arm64/boot/dts/hisilicon/Makefile
> new file mode 100644
> index 0000000..fa81a6e
> --- /dev/null
> +++ b/arch/arm64/boot/dts/hisilicon/Makefile
> @@ -0,0 +1,5 @@
> +dtb-$(CONFIG_ARCH_HISI) += hi6220-hikey.dtb
> +
> +always := $(dtb-y)
> +subdir-y := $(dts-dirs)
> +clean-files := *.dtb
> diff --git a/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts b/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts
> new file mode 100644
> index 0000000..a94da84
> --- /dev/null
> +++ b/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts
> @@ -0,0 +1,31 @@
> +/*
> + * dts file for Hisilicon HiKey Development Board
> + *
> + * Copyright (C) 2015, Hisilicon Ltd.
> + *
> + */
> +
> +/dts-v1/;
> +
> +/memreserve/ 0x0740f000 0x1000;

If you're going to use /memreserve/, please add a comment regarding what
it is intended to protect, and why that's in memory given to the kernel
to begin with.

> +
> +#include "hi6220.dtsi"
> +
> +/ {
> + model = "HiKey Development Board";
> + compatible = "hisilicon,hi6220-hikey";
> + #address-cells = <2>;
> + #size-cells = <2>;
> + interrupt-parent = <&gic>;
> +
> + aliases {
> + serial0 = &uart0;
> + };
> +
> + chosen { };

You should use stdout-path here, ideally with the full UART
configuration.

> +
> + memory@7400000 {
> + device_type = "memory";
> + reg = <0x0 0x07400000 0x0 0x38c00000>;
> + };
> +};
> diff --git a/arch/arm64/boot/dts/hisilicon/hi6220.dtsi b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
> new file mode 100644
> index 0000000..53ba9cf
> --- /dev/null
> +++ b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
> @@ -0,0 +1,204 @@
> +/*
> + * dts file for Hisilicon Hi6220 SoC
> + *
> + * Copyright (C) 2015, Hisilicon Ltd.
> + */
> +
> +#include <dt-bindings/clock/hi6220-clock.h>
> +
> +/ {
> + cpu-map {

Per the binding, this must live under /cpus.

Move this within the /cpus node.

> + cluster0 {
> + core0 {
> + cpu = <&cpu0>;
> + };
> + core1 {
> + cpu = <&cpu1>;
> + };
> + core2 {
> + cpu = <&cpu2>;
> + };
> + core3 {
> + cpu = <&cpu3>;
> + };
> + };
> + cluster1 {
> + core0 {
> + cpu = <&cpu4>;
> + };
> + core1 {
> + cpu = <&cpu5>;
> + };
> + core2 {
> + cpu = <&cpu6>;
> + };
> + core3 {
> + cpu = <&cpu7>;
> + };
> + };
> + };
> +
> + cpus {
> + #address-cells = <2>;
> + #size-cells = <0>;
> +
> + cpu0: cpu@000 {
> + compatible = "arm,cortex-a53", "arm,armv8";
> + device_type = "cpu";
> + reg = <0x0 0x0>;
> + enable-method = "spin-table";
> + cpu-release-addr = <0x0 0x740fff8>;

If you _must_ use spin-table, please give each CPU a unique release
address. Using a shared address was a mistake, and we should learn from
it.

Which CPU does the system boot on?

> + clock-latency = <0>;

Why is this here?

There is no reason for this to be on any CPU node.

> + };

[...]

> + gic: interrupt-controller@f6800000 {
> + compatible = "arm,gic-400", "arm,cortex-a15-gic";

Surely there's no need for the "arm,cortex-a15-gic" fallback entry? What
am I missing?

> + reg = <0x0 0xf6801000 0x0 0x1000>, /* GICD */

This doesn't match the unit-address.

> + <0x0 0xf6802000 0x0 0x2000>, /* GICC */
> + <0x0 0xf6804000 0x0 0x2000>, /* GICH */
> + <0x0 0xf6806000 0x0 0x2000>; /* GICV */

I guess no-one's bothered to consider 64k pages?

Given GICH and GICV, I hope that this platform is booted at EL2?

> + #interrupt-cells = <3>;
> + #address-cells = <0>;
> + interrupt-controller;
> + };
> +
> +
> + timer {
> + compatible = "arm,armv8-timer";
> + interrupt-parent = <&gic>;
> + interrupts = <1 13 0xff08>,
> + <1 14 0xff08>,
> + <1 11 0xff08>,
> + <1 10 0xff08>;
> + clock-frequency = <1200000>;
> + };

NAK. Fix your firmware to configure CNTFRQ, on all CPUs.

That frequency also looks a bit low; timekeeping isn't going to be very
precise.

> + soc {
> + compatible = "simple-bus";
> + #address-cells = <2>;
> + #size-cells = <2>;
> + interrupt-parent = <&gic>;
> + ranges;
> +
> + ao_ctrl: ao_ctrl {
> + compatible = "hisilicon,aoctrl", "syscon";
> + #address-cells = <1>;
> + #size-cells = <1>;
> + reg = <0x0 0xf7800000 0x0 0x2000>;
> + ranges = <0 0x0 0xf7800000 0x2000>;
> +
> + clock_ao: clock0@0 {
> + compatible = "hisilicon,hi6220-clock-ao";
> + reg = <0 0x1000>;
> + #clock-cells = <1>;
> + };
> + };
> +
> + sys_ctrl: sys_ctrl {
> + compatible = "hisilicon,sysctrl", "syscon";
> + #address-cells = <1>;
> + #size-cells = <1>;
> + reg = <0x0 0xf7030000 0x0 0x2000>;
> + ranges = <0 0x0 0xf7030000 0x2000>;
> +
> + clock_sys: clock1@0 {
> + compatible = "hisilicon,hi6220-clock-sys";
> + reg = <0 0x1000>;
> + #clock-cells = <1>;
> + };
> + };
> +
> + media_ctrl: media_ctrl {
> + compatible = "hisilicon,mediactrl", "syscon";
> + #address-cells = <1>;
> + #size-cells = <1>;
> + reg = <0x0 0xf4410000 0x0 0x1000>;
> + ranges = <0 0x0 0xf4410000 0x1000>;
> +
> + clock_media: clock2@0 {
> + compatible = "hisilicon,hi6220-clock-media";
> + reg = <0 0x1000>;
> + #clock-cells = <1>;
> + };
> + };
> +
> + pm_ctrl: pm_ctrl {
> + compatible = "hisilicon,pmctrl", "syscon";
> + #address-cells = <1>;
> + #size-cells = <1>;
> + reg = <0x0 0xf7032000 0x0 0x1000>;
> + ranges = <0 0x0 0xf7032000 0x1000>;
> +
> + clock_power: clock3@0 {
> + compatible = "hisilicon,hi6220-clock-power";
> + reg = <0 0x1000>;
> + #clock-cells = <1>;
> + };
> + };

I really doesn't see the point in having a sub-device that covers the
entirely of the register space of the containing node, and that being
the case I am extremely concerned that the containers are marked as
syscon compatible.

Why are these marked as being syscon devices? Per the dts _all_ their
registers are clearly owned by their child nodes, and shouldn't be poked
by anything else.

Thanks,
Mark.

2015-02-05 23:52:52

by Tyler Baker

[permalink] [raw]
Subject: Re: [PATCH 0/3] arm64,hi6220: Enable Hisilicon Hi6220 SoC

On 5 February 2015 at 11:02, Olof Johansson <[email protected]> wrote:
> On Thu, Feb 5, 2015 at 10:46 AM, Tyler Baker <[email protected]> wrote:
>> Hi Bintian,
>>
>> On 5 February 2015 at 01:24, Bintian Wang <[email protected]> wrote:
>>> Hello,
>>>
>>> Hi6220 is one mobile solution of Hisilicon, this patchset contains
>>> initial support for Hi6220 SoC and HiKey development board, which
>>> is based on ARM Cortex A53 architecture. Initial support is minimal
>>> and includes just the arch configuration, clock driver, device tree
>>> configuration.
>>>
>>> Many peripheral drivers will be submitted later.
>>>
>>> Any comments will be appreciated!
>>>
>>> Thanks,
>>>
>>> Bintian Wang (3):
>>> arm64: Enable Hisilicon ARMv8 SoC family in Kconfig and defconfig
>>> clk: hi6220: Clock driver support for Hisilicon hi6220 SoC
>>> arm64: dts: Add dts files for Hisilicon Hi6220 SoC
>>
>> Thanks for posting these! I've applied this series on top of
>> next-20150204, however there was some fuzz that needed to be cleaned
>> up on 3/3 [1]. I've confirmed the platform is booting to a basic user
>> space without issue.
>
> From ramdisk only, right?

Correct, ramdisk only.

> Given the timing of the posting of this
> patch set, I'm not going to merge it for 3.20. Hopefully for 3.21
> there will be some more peripheral support as well -- at least some
> sort of storage device.

Seem fair to me. I also hope to see more patches posted shortly.

>
>
> -Olof

Cheers,

Tyler

2015-02-06 06:18:20

by Olof Johansson

[permalink] [raw]
Subject: Re: [PATCH 0/3] arm64,hi6220: Enable Hisilicon Hi6220 SoC

On Thu, Feb 5, 2015 at 8:21 PM, Brent Wang <[email protected]> wrote:
> Hello Olof and Tyler,
>
> 2015-02-06 7:52 GMT+08:00 Tyler Baker <[email protected]>:
>>
>> On 5 February 2015 at 11:02, Olof Johansson <[email protected]> wrote:
>> > On Thu, Feb 5, 2015 at 10:46 AM, Tyler Baker <[email protected]>
>> > wrote:
>> >> Hi Bintian,
>> >>
>> >> On 5 February 2015 at 01:24, Bintian Wang <[email protected]>
>> >> wrote:
>> >>> Hello,
>> >>>
>> >>> Hi6220 is one mobile solution of Hisilicon, this patchset contains
>> >>> initial support for Hi6220 SoC and HiKey development board, which
>> >>> is based on ARM Cortex A53 architecture. Initial support is minimal
>> >>> and includes just the arch configuration, clock driver, device tree
>> >>> configuration.
>> >>>
>> >>> Many peripheral drivers will be submitted later.
>> >>>
>> >>> Any comments will be appreciated!
>> >>>
>> >>> Thanks,
>> >>>
>> >>> Bintian Wang (3):
>> >>> arm64: Enable Hisilicon ARMv8 SoC family in Kconfig and defconfig
>> >>> clk: hi6220: Clock driver support for Hisilicon hi6220 SoC
>> >>> arm64: dts: Add dts files for Hisilicon Hi6220 SoC
>> >>
>> >> Thanks for posting these! I've applied this series on top of
>> >> next-20150204, however there was some fuzz that needed to be cleaned
>> >> up on 3/3 [1]. I've confirmed the platform is booting to a basic user
>> >> space without issue.
>> >
>> > From ramdisk only, right?
>>
>> Correct, ramdisk only.
>>
>> > Given the timing of the posting of this
>> > patch set, I'm not going to merge it for 3.20. Hopefully for 3.21
>> > there will be some more peripheral support as well -- at least some
>> > sort of storage device.
>>
>> Seem fair to me. I also hope to see more patches posted shortly.
>
> Yes, the mmc and sd drivers will be submitted soon, should they be included
> in this patchset? I have thought submitting this patch first for review, if
> there
> is no problem for this patchset and then submit other drivers, you know,
> other
> drivers will depend on this patchset.


The drivers should ideally not depend on the SoC patchset -- the
driver can go in independently. The DTS updates to specify the
hardware should go in through arm-soc even if the driver itself (and
the binding document update) should go in through the driver subsystem
instead.


So, you can choose if you want to post everything as a long series,
and cc different maintainers on the various parts of the series -- or
you can post each driver or subsystem as a patchset on its own and let
that get merged through respective maintainer. The latter is most
common these days.


-Olof

2015-02-06 06:35:39

by Brent Wang

[permalink] [raw]
Subject: Re: [PATCH 0/3] arm64,hi6220: Enable Hisilicon Hi6220 SoC

Hello Olof,

2015-02-06 14:18 GMT+08:00 Olof Johansson <[email protected]>:
>
> On Thu, Feb 5, 2015 at 8:21 PM, Brent Wang <[email protected]> wrote:
> > Hello Olof and Tyler,
> >
> > 2015-02-06 7:52 GMT+08:00 Tyler Baker <[email protected]>:
> >>
> >> On 5 February 2015 at 11:02, Olof Johansson <[email protected]> wrote:
> >> > On Thu, Feb 5, 2015 at 10:46 AM, Tyler Baker <[email protected]>
> >> > wrote:
> >> >> Hi Bintian,
> >> >>
> >> >> On 5 February 2015 at 01:24, Bintian Wang <[email protected]>
> >> >> wrote:
> >> >>> Hello,
> >> >>>
> >> >>> Hi6220 is one mobile solution of Hisilicon, this patchset contains
> >> >>> initial support for Hi6220 SoC and HiKey development board, which
> >> >>> is based on ARM Cortex A53 architecture. Initial support is minimal
> >> >>> and includes just the arch configuration, clock driver, device tree
> >> >>> configuration.
> >> >>>
> >> >>> Many peripheral drivers will be submitted later.
> >> >>>
> >> >>> Any comments will be appreciated!
> >> >>>
> >> >>> Thanks,
> >> >>>
> >> >>> Bintian Wang (3):
> >> >>> arm64: Enable Hisilicon ARMv8 SoC family in Kconfig and defconfig
> >> >>> clk: hi6220: Clock driver support for Hisilicon hi6220 SoC
> >> >>> arm64: dts: Add dts files for Hisilicon Hi6220 SoC
> >> >>
> >> >> Thanks for posting these! I've applied this series on top of
> >> >> next-20150204, however there was some fuzz that needed to be cleaned
> >> >> up on 3/3 [1]. I've confirmed the platform is booting to a basic user
> >> >> space without issue.
> >> >
> >> > From ramdisk only, right?
> >>
> >> Correct, ramdisk only.
> >>
> >> > Given the timing of the posting of this
> >> > patch set, I'm not going to merge it for 3.20. Hopefully for 3.21
> >> > there will be some more peripheral support as well -- at least some
> >> > sort of storage device.
> >>
> >> Seem fair to me. I also hope to see more patches posted shortly.
> >
> > Yes, the mmc and sd drivers will be submitted soon, should they be included
> > in this patchset? I have thought submitting this patch first for review, if
> > there
> > is no problem for this patchset and then submit other drivers, you know,
> > other
> > drivers will depend on this patchset.
>
>
> The drivers should ideally not depend on the SoC patchset -- the
> driver can go in independently. The DTS updates to specify the
> hardware should go in through arm-soc even if the driver itself (and
> the binding document update) should go in through the driver subsystem
> instead.
>
>
> So, you can choose if you want to post everything as a long series,
> and cc different maintainers on the various parts of the series -- or
> you can post each driver or subsystem as a patchset on its own and let
> that get merged through respective maintainer. The latter is most
> common these days.
I think the latter is a better way, thank you!

>
>
>
> -Olof

--
Best Regards,

Bintian
===========================
Don't be nervous, just be happy!

2015-02-06 07:32:16

by Brent Wang

[permalink] [raw]
Subject: Re: [PATCH 2/3] clk: hi6220: Clock driver support for Hisilicon hi6220 SoC

Hi Mark,

2015-02-06 3:25 GMT+08:00 Mark Rutland <[email protected]>:
> On Thu, Feb 05, 2015 at 09:24:36AM +0000, Bintian Wang wrote:
>> Add clock drivers for hi6220 SoC, this driver controls the SoC
>> registers to supply different clocks to different IPs in the SoC.
>>
>> We add one divider clock for hi6220 because the divider in hi6220
>> also has a mask bit but it doesnot obey the rule defined by flag
>> "CLK_DIVIDER_HIWORD_MASK", we can not get index of the mask bit by
>> left shift fixed bits (e.g. 16 bits), so we add this divider clock
>> to handle it.
>>
>> This patch also enables this clock driver for ARCH_HISI and document
>> devicetree bindings.
>>
>> Signed-off-by: Bintian Wang <[email protected]>
>> Reviewed-by: Haojian Zhuang <[email protected]>
>> Reviewed-by: Zhangfei Gao <[email protected]>
>> ---
>> .../devicetree/bindings/clock/hi6220-clock.txt | 30 +++
>> arch/arm64/Kconfig | 1 +
>> drivers/clk/Kconfig | 2 +
>> drivers/clk/Makefile | 4 +-
>> drivers/clk/hisilicon/Kconfig | 5 +
>> drivers/clk/hisilicon/Makefile | 1 +
>> drivers/clk/hisilicon/clk-hi6220.c | 284 ++++++++++++++++++++
>> drivers/clk/hisilicon/clk.c | 29 ++
>> drivers/clk/hisilicon/clk.h | 17 ++
>> drivers/clk/hisilicon/clkdivider-hi6220.c | 273 +++++++++++++++++++
>> include/dt-bindings/clock/hi6220-clock.h | 172 ++++++++++++
>> 11 files changed, 815 insertions(+), 3 deletions(-)
>> create mode 100644 Documentation/devicetree/bindings/clock/hi6220-clock.txt
>> create mode 100644 drivers/clk/hisilicon/Kconfig
>> create mode 100644 drivers/clk/hisilicon/clk-hi6220.c
>> create mode 100644 drivers/clk/hisilicon/clkdivider-hi6220.c
>> create mode 100644 include/dt-bindings/clock/hi6220-clock.h
>>
>> diff --git a/Documentation/devicetree/bindings/clock/hi6220-clock.txt b/Documentation/devicetree/bindings/clock/hi6220-clock.txt
>> new file mode 100644
>> index 0000000..a3ddda1
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/clock/hi6220-clock.txt
>> @@ -0,0 +1,30 @@
>> +* Hisilicon Hi6220 Clock Controller
>> +
>> +The hi6220 clock controller generates and supplies clock to various
>> +controllers within the hi6220 SoC.
>> +
>> +Required Properties:
>> +
>> +- compatible: should be one of the following:
>> + - "hisilicon,hi6220-clock-ao" - controller for those clocks under SoC
>> + power always on(AO) domain, it is the sub node of SoC power AO
>> + controller in dts file.
>> + - "hisilicon,hi6220-clock-sys" - controller for those clocks under SoC
>> + system control domain, it is the sub node of SoC system controller
>> + in dts file.
>> + - "hisilicon,hi6220-clock-media" - controller for those clocks under
>> + SoC media control domain, it is the sub node of SoC media controller
>> + in dts file.
>> + - "hisilicon,hi6220-clock-power" - controller for those clocks under
>> + SoC power control domain, it is the sub node of SoC power controller
>> + in dts file.
>
> These all refer to things which aren't documented (yet).
>
> Please sort out your patches so that any documentation you depend on
> comes earlier.
>
> Please also separate documentation from code. Note that dt includes are
> _bindings_ and should be added with the relevant documentation.
Thanks for help to review, I also think separate documentation from
code is better
way, it will be fixed in next version.

Thanks,

Bintian
> Thanks,
> Mark.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/

2015-02-06 08:42:26

by Brent Wang

[permalink] [raw]
Subject: Re: [PATCH 3/3] arm64: dts: Add dts files for Hisilicon Hi6220 SoC

Hello Mark,

2015-02-06 3:30 GMT+08:00 Mark Rutland <[email protected]>:
> On Thu, Feb 05, 2015 at 09:24:37AM +0000, Bintian Wang wrote:
>> Add initial dtsi file to support Hisilicon Hi6220 SoC with
>> support of Octal core CPUs in two clusters and each cluster
>> has quard Cortex-A53.
>>
>> We now use the "spin-table" method for SMP, and it will be
>> changed to PSCI later.
>
> If that's the case, please don't place the enable-method and related
> properties in this file. Get your bootloader to add the appropriate
> properties for its boot protocol.
>
> When is PSCI likely to appear?
PSCI is under development.

>
> Are we certain of the split between components the PSCI implementation
> must touch and those the kernel must touch?
>
>> Also add dts file to support HiKey development board which
>> based on Hi6220 SoC and document the devicetree bindings.
>>
>> These dts files will be changed later and more nodes will be
>> added to describe other devices.
>
> How is this going to be changed other than the addition of nodes?
>
> Will this DTB continue to work in future? Or do you intend to make
> changes that will break support?
My original idea is: use spin-table for SMP now, when firmware is OK to
support PSCI, we submit another patch to replace the spin-table with PSCI.

If DTB should continue to work in the future, we really need to remove
the spin-table
from current dts file, how about just enable one core now?

Which one do you favor or any other suggestion?

>
>> Signed-off-by: Bintian Wang <[email protected]>
>> Reviewed-by: Haojian Zhuang <[email protected]>
>> Reviewed-by: Yiping Xu <[email protected]>
>> ---
>> .../bindings/arm/hisilicon/hisilicon.txt | 33 ++++
>> arch/arm64/boot/dts/Makefile | 1 +
>> arch/arm64/boot/dts/hisilicon/Makefile | 5 +
>> arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts | 31 +++
>> arch/arm64/boot/dts/hisilicon/hi6220.dtsi | 204 ++++++++++++++++++++
>> 5 files changed, 274 insertions(+)
>> create mode 100644 arch/arm64/boot/dts/hisilicon/Makefile
>> create mode 100644 arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts
>> create mode 100644 arch/arm64/boot/dts/hisilicon/hi6220.dtsi
>>
>> diff --git a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
>> index f717c7b..5eb6b41 100644
>> --- a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
>> +++ b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
>> @@ -9,6 +9,9 @@ HiP04 D01 Board
>> Required root node properties:
>> - compatible = "hisilicon,hip04-d01";
>>
>> +HiKey Board
>> +Required root node properties:
>> + - compatible = "hisilicon,hi6220-hikey";
>>
>> Hisilicon system controller
>>
>> @@ -62,6 +65,36 @@ Example:
>> };
>>
>> -----------------------------------------------------------------------
>> +Hisilicon Power Always ON domain controller
>> +
>> +Required properties:
>> +- compatible : "hisilicon,aoctrl"
>> +- reg : Register address and size
>> +
>> +Some clock registers are defined in power always on system controller,
>> +especially in Hi6220 SoC which is used for mobile platform.
>> +
>> +-----------------------------------------------------------------------
>> +Hisilicon Media domain controller
>> +
>> +Required properties:
>> +- compatible : "hisilicon,mediactrl"
>> +- reg : Register address and size
>> +
>> +Some clock registers of media module are defined in media system
>> +controller, especially in Hi6220 SoC which is used for mobile platform.
>> +
>> +-----------------------------------------------------------------------
>> +Hisilicon Power Management domain controller
>> +
>> +Required properties:
>> +- compatible : "hisilicon,pmctrl"
>> +- reg : Register address and size
>> +
>> +Some clock registers and PMU registers are defined in power management
>> +controller, especially in Hin6220 SoC which is used for mobile platform.
>> +
>> +-----------------------------------------------------------------------
>
> Looking at the dts below, none of these binding docs are sufficient.
>
> Define _all_ the properties and what they mean.
In fact, Hisilicon designs several system controllers for different
function domains,
we can control different functions(e.g. clk gate on or off /IP reset)
based on the base
address of controller + offset, I will give more description in next version.

> Please also split documentation into earlier patches.
OK, separate document and code in next version.

>
>> Fabric:
>>
>> Required Properties:
>> diff --git a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile
>> index c62b0f4..bffd6b7 100644
>> --- a/arch/arm64/boot/dts/Makefile
>> +++ b/arch/arm64/boot/dts/Makefile
>> @@ -2,5 +2,6 @@ dts-dirs += amd
>> dts-dirs += apm
>> dts-dirs += arm
>> dts-dirs += cavium
>> +dts-dirs += hisilicon
>>
>> subdir-y := $(dts-dirs)
>> diff --git a/arch/arm64/boot/dts/hisilicon/Makefile b/arch/arm64/boot/dts/hisilicon/Makefile
>> new file mode 100644
>> index 0000000..fa81a6e
>> --- /dev/null
>> +++ b/arch/arm64/boot/dts/hisilicon/Makefile
>> @@ -0,0 +1,5 @@
>> +dtb-$(CONFIG_ARCH_HISI) += hi6220-hikey.dtb
>> +
>> +always := $(dtb-y)
>> +subdir-y := $(dts-dirs)
>> +clean-files := *.dtb
>> diff --git a/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts b/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts
>> new file mode 100644
>> index 0000000..a94da84
>> --- /dev/null
>> +++ b/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts
>> @@ -0,0 +1,31 @@
>> +/*
>> + * dts file for Hisilicon HiKey Development Board
>> + *
>> + * Copyright (C) 2015, Hisilicon Ltd.
>> + *
>> + */
>> +
>> +/dts-v1/;
>> +
>> +/memreserve/ 0x0740f000 0x1000;
>
> If you're going to use /memreserve/, please add a comment regarding what
> it is intended to protect, and why that's in memory given to the kernel
> to begin with.
>
>> +
>> +#include "hi6220.dtsi"
>> +
>> +/ {
>> + model = "HiKey Development Board";
>> + compatible = "hisilicon,hi6220-hikey";
>> + #address-cells = <2>;
>> + #size-cells = <2>;
>> + interrupt-parent = <&gic>;
>> +
>> + aliases {
>> + serial0 = &uart0;
>> + };
>> +
>> + chosen { };
>
> You should use stdout-path here, ideally with the full UART
> configuration.
Add in next version.

>> +
>> + memory@7400000 {
>> + device_type = "memory";
>> + reg = <0x0 0x07400000 0x0 0x38c00000>;
>> + };
>> +};
>> diff --git a/arch/arm64/boot/dts/hisilicon/hi6220.dtsi b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
>> new file mode 100644
>> index 0000000..53ba9cf
>> --- /dev/null
>> +++ b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
>> @@ -0,0 +1,204 @@
>> +/*
>> + * dts file for Hisilicon Hi6220 SoC
>> + *
>> + * Copyright (C) 2015, Hisilicon Ltd.
>> + */
>> +
>> +#include <dt-bindings/clock/hi6220-clock.h>
>> +
>> +/ {
>> + cpu-map {
>
> Per the binding, this must live under /cpus.
>
> Move this within the /cpus node.
>
>> + cluster0 {
>> + core0 {
>> + cpu = <&cpu0>;
>> + };
>> + core1 {
>> + cpu = <&cpu1>;
>> + };
>> + core2 {
>> + cpu = <&cpu2>;
>> + };
>> + core3 {
>> + cpu = <&cpu3>;
>> + };
>> + };
>> + cluster1 {
>> + core0 {
>> + cpu = <&cpu4>;
>> + };
>> + core1 {
>> + cpu = <&cpu5>;
>> + };
>> + core2 {
>> + cpu = <&cpu6>;
>> + };
>> + core3 {
>> + cpu = <&cpu7>;
>> + };
>> + };
>> + };
>> +
>> + cpus {
>> + #address-cells = <2>;
>> + #size-cells = <0>;
>> +
>> + cpu0: cpu@000 {
>> + compatible = "arm,cortex-a53", "arm,armv8";
>> + device_type = "cpu";
>> + reg = <0x0 0x0>;
>> + enable-method = "spin-table";
>> + cpu-release-addr = <0x0 0x740fff8>;
>
> If you _must_ use spin-table, please give each CPU a unique release
> address. Using a shared address was a mistake, and we should learn from
> it.
>
> Which CPU does the system boot on?
>
>> + clock-latency = <0>;
>
> Why is this here?
>
> There is no reason for this to be on any CPU node.
Fix in next version.

>
>> + };
>
> [...]
>
>> + gic: interrupt-controller@f6800000 {
>> + compatible = "arm,gic-400", "arm,cortex-a15-gic";
>
> Surely there's no need for the "arm,cortex-a15-gic" fallback entry? What
> am I missing?
Remove it in next version.

>
>> + reg = <0x0 0xf6801000 0x0 0x1000>, /* GICD */
>
> This doesn't match the unit-address.
Do you mean change to "<0x0 0xf6801000 0 0x1000>" ?

>
>> + <0x0 0xf6802000 0x0 0x2000>, /* GICC */
>> + <0x0 0xf6804000 0x0 0x2000>, /* GICH */
>> + <0x0 0xf6806000 0x0 0x2000>; /* GICV */
>
> I guess no-one's bothered to consider 64k pages?
>
> Given GICH and GICV, I hope that this platform is booted at EL2?
Transfer from EL3 to EL1 directly, keep these two just for future use.

>
>> + #interrupt-cells = <3>;
>> + #address-cells = <0>;
>> + interrupt-controller;
>> + };
>> +
>> +
>> + timer {
>> + compatible = "arm,armv8-timer";
>> + interrupt-parent = <&gic>;
>> + interrupts = <1 13 0xff08>,
>> + <1 14 0xff08>,
>> + <1 11 0xff08>,
>> + <1 10 0xff08>;
>> + clock-frequency = <1200000>;
>> + };
>
> NAK. Fix your firmware to configure CNTFRQ, on all CPUs.
Fix in next version, maybe it will take some time to change firmware.

>
> That frequency also looks a bit low; timekeeping isn't going to be very
> precise.
>
>> + soc {
>> + compatible = "simple-bus";
>> + #address-cells = <2>;
>> + #size-cells = <2>;
>> + interrupt-parent = <&gic>;
>> + ranges;
>> +
>> + ao_ctrl: ao_ctrl {
>> + compatible = "hisilicon,aoctrl", "syscon";
>> + #address-cells = <1>;
>> + #size-cells = <1>;
>> + reg = <0x0 0xf7800000 0x0 0x2000>;
>> + ranges = <0 0x0 0xf7800000 0x2000>;
>> +
>> + clock_ao: clock0@0 {
>> + compatible = "hisilicon,hi6220-clock-ao";
>> + reg = <0 0x1000>;
>> + #clock-cells = <1>;
>> + };
>> + };
>> +
>> + sys_ctrl: sys_ctrl {
>> + compatible = "hisilicon,sysctrl", "syscon";
>> + #address-cells = <1>;
>> + #size-cells = <1>;
>> + reg = <0x0 0xf7030000 0x0 0x2000>;
>> + ranges = <0 0x0 0xf7030000 0x2000>;
>> +
>> + clock_sys: clock1@0 {
>> + compatible = "hisilicon,hi6220-clock-sys";
>> + reg = <0 0x1000>;
>> + #clock-cells = <1>;
>> + };
>> + };
>> +
>> + media_ctrl: media_ctrl {
>> + compatible = "hisilicon,mediactrl", "syscon";
>> + #address-cells = <1>;
>> + #size-cells = <1>;
>> + reg = <0x0 0xf4410000 0x0 0x1000>;
>> + ranges = <0 0x0 0xf4410000 0x1000>;
>> +
>> + clock_media: clock2@0 {
>> + compatible = "hisilicon,hi6220-clock-media";
>> + reg = <0 0x1000>;
>> + #clock-cells = <1>;
>> + };
>> + };
>> +
>> + pm_ctrl: pm_ctrl {
>> + compatible = "hisilicon,pmctrl", "syscon";
>> + #address-cells = <1>;
>> + #size-cells = <1>;
>> + reg = <0x0 0xf7032000 0x0 0x1000>;
>> + ranges = <0 0x0 0xf7032000 0x1000>;
>> +
>> + clock_power: clock3@0 {
>> + compatible = "hisilicon,hi6220-clock-power";
>> + reg = <0 0x1000>;
>> + #clock-cells = <1>;
>> + };
>> + };
>
> I really doesn't see the point in having a sub-device that covers the
> entirely of the register space of the containing node, and that being
> the case I am extremely concerned that the containers are marked as
> syscon compatible.
The SoC clocks are designed and placed under different system controllers,
so I define corresponding nodes under different controllers for clock operation.

>
> Why are these marked as being syscon devices? Per the dts _all_ their
> registers are clearly owned by their child nodes, and shouldn't be poked
> by anything else.
>
> Thanks,
> Mark.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/

--
Best Regards,

Bintian
===========================
Don't be nervous, just be happy!

2015-02-06 09:07:27

by Marc Zyngier

[permalink] [raw]
Subject: Re: [PATCH 3/3] arm64: dts: Add dts files for Hisilicon Hi6220 SoC

On 06/02/15 08:42, Brent Wang wrote:

[...]

>>
>>> + <0x0 0xf6802000 0x0 0x2000>, /* GICC */
>>> + <0x0 0xf6804000 0x0 0x2000>, /* GICH */
>>> + <0x0 0xf6806000 0x0 0x2000>; /* GICV */
>>
>> I guess no-one's bothered to consider 64k pages?
>>
>> Given GICH and GICV, I hope that this platform is booted at EL2?
> Transfer from EL3 to EL1 directly, keep these two just for future use.

That's a real shame, as it keeps users away from some key aspects of the
ARMv8 architecture.

>>
>>> + #interrupt-cells = <3>;
>>> + #address-cells = <0>;
>>> + interrupt-controller;

And if you're keeping GICH/GICV, where is the maintenance interrupt?

>>> + };
>>> +
>>> +
>>> + timer {
>>> + compatible = "arm,armv8-timer";
>>> + interrupt-parent = <&gic>;
>>> + interrupts = <1 13 0xff08>,
>>> + <1 14 0xff08>,
>>> + <1 11 0xff08>,
>>> + <1 10 0xff08>;
>>> + clock-frequency = <1200000>;
>>> + };
>>
>> NAK. Fix your firmware to configure CNTFRQ, on all CPUs.
> Fix in next version, maybe it will take some time to change firmware.

While you're at it, make sure CNTVOFF_EL2 is set to zero on all CPUs
before dropping to EL1. This tends to be overlooked.

Thanks,

M.
--
Jazz is not dead. It just smells funny...

2015-02-06 10:31:57

by Mark Rutland

[permalink] [raw]
Subject: Re: [PATCH 3/3] arm64: dts: Add dts files for Hisilicon Hi6220 SoC

On Fri, Feb 06, 2015 at 09:07:10AM +0000, Marc Zyngier wrote:
> On 06/02/15 08:42, Brent Wang wrote:
>
> [...]
>
> >>
> >>> + <0x0 0xf6802000 0x0 0x2000>, /* GICC */
> >>> + <0x0 0xf6804000 0x0 0x2000>, /* GICH */
> >>> + <0x0 0xf6806000 0x0 0x2000>; /* GICV */
> >>
> >> I guess no-one's bothered to consider 64k pages?
> >>
> >> Given GICH and GICV, I hope that this platform is booted at EL2?
> > Transfer from EL3 to EL1 directly, keep these two just for future use.
>
> That's a real shame, as it keeps users away from some key aspects of the
> ARMv8 architecture.

More importantly (and regardless of whether you wish to use the features
provided by EL2), booting at EL2 means that the FW/bootloader needs to
set up far less, and that the kernel can fix up some issues that might
not be immediately apparent...

[...]

> >>> + timer {
> >>> + compatible = "arm,armv8-timer";
> >>> + interrupt-parent = <&gic>;
> >>> + interrupts = <1 13 0xff08>,
> >>> + <1 14 0xff08>,
> >>> + <1 11 0xff08>,
> >>> + <1 10 0xff08>;
> >>> + clock-frequency = <1200000>;
> >>> + };
> >>
> >> NAK. Fix your firmware to configure CNTFRQ, on all CPUs.
> > Fix in next version, maybe it will take some time to change firmware.
>
> While you're at it, make sure CNTVOFF_EL2 is set to zero on all CPUs
> before dropping to EL1. This tends to be overlooked.

...like differing values of CNTVOFF_EL2.

There seems to be a common misconception that booting at EL2 is a bad
thing to do, when in reality booting at EL1 is more likely to result in
bugs we can't work around.

Is there any reason that you do not wish to boot at EL2, or were you
simply unaware that booting at EL2 was possible/preferred?

Thanks,
Mark.

2015-02-06 10:45:00

by Mark Rutland

[permalink] [raw]
Subject: Re: [PATCH 3/3] arm64: dts: Add dts files for Hisilicon Hi6220 SoC

On Fri, Feb 06, 2015 at 08:42:22AM +0000, Brent Wang wrote:
> Hello Mark,
>
> 2015-02-06 3:30 GMT+08:00 Mark Rutland <[email protected]>:
> > On Thu, Feb 05, 2015 at 09:24:37AM +0000, Bintian Wang wrote:
> >> Add initial dtsi file to support Hisilicon Hi6220 SoC with
> >> support of Octal core CPUs in two clusters and each cluster
> >> has quard Cortex-A53.
> >>
> >> We now use the "spin-table" method for SMP, and it will be
> >> changed to PSCI later.
> >
> > If that's the case, please don't place the enable-method and related
> > properties in this file. Get your bootloader to add the appropriate
> > properties for its boot protocol.
> >
> > When is PSCI likely to appear?
> PSCI is under development.

Sure. Do you have an estimate as to when it will appear?

What are you using for your PSCI implementation? The ARM Trusted
Firmware?

How are you testing it?

> > Are we certain of the split between components the PSCI implementation
> > must touch and those the kernel must touch?
> >
> >> Also add dts file to support HiKey development board which
> >> based on Hi6220 SoC and document the devicetree bindings.
> >>
> >> These dts files will be changed later and more nodes will be
> >> added to describe other devices.
> >
> > How is this going to be changed other than the addition of nodes?
> >
> > Will this DTB continue to work in future? Or do you intend to make
> > changes that will break support?
> My original idea is: use spin-table for SMP now, when firmware is OK to
> support PSCI, we submit another patch to replace the spin-table with PSCI.

For any users who have not updated their FW, this will break booting.

This is why I suggest having hte bootloader/FW fill this in as it should
know what enable-method the FW supports.

> If DTB should continue to work in the future, we really need to remove
> the spin-table
> from current dts file, how about just enable one core now?
>
> Which one do you favor or any other suggestion?

If spin-table is just for testing while you await PSCI, drop spin-table
from the dts for now.

[...]

> >> + timer {
> >> + compatible = "arm,armv8-timer";
> >> + interrupt-parent = <&gic>;
> >> + interrupts = <1 13 0xff08>,
> >> + <1 14 0xff08>,
> >> + <1 11 0xff08>,
> >> + <1 10 0xff08>;
> >> + clock-frequency = <1200000>;
> >> + };
> >
> > NAK. Fix your firmware to configure CNTFRQ, on all CPUs.
> Fix in next version, maybe it will take some time to change firmware.

Thanks. This _must_ be fixed.

[...]

> >> + pm_ctrl: pm_ctrl {
> >> + compatible = "hisilicon,pmctrl", "syscon";
> >> + #address-cells = <1>;
> >> + #size-cells = <1>;
> >> + reg = <0x0 0xf7032000 0x0 0x1000>;
> >> + ranges = <0 0x0 0xf7032000 0x1000>;
> >> +
> >> + clock_power: clock3@0 {
> >> + compatible = "hisilicon,hi6220-clock-power";
> >> + reg = <0 0x1000>;
> >> + #clock-cells = <1>;
> >> + };
> >> + };
> >
> > I really doesn't see the point in having a sub-device that covers the
> > entirely of the register space of the containing node, and that being
> > the case I am extremely concerned that the containers are marked as
> > syscon compatible.
> The SoC clocks are designed and placed under different system controllers,
> so I define corresponding nodes under different controllers for clock operation.

What I'm concerned wit hhere is that the pm_ctrl node and the clock3@0
sub-node have the _exact_ same register space.

Given this should mean that the clock3@0 node owns that register space,
having the container node export this as syscon does not make sense. And
the split between pm_ctrl and clock3@) doesn't seem to make sense given
they cover the same space.

As I asked before, why is pm_ctrl marked as a syscon, and what's the
point of the separate sub-node?

Thanks,
Mark.

2015-02-06 15:37:56

by Brent Wang

[permalink] [raw]
Subject: Re: [PATCH 3/3] arm64: dts: Add dts files for Hisilicon Hi6220 SoC

Hello Mark,

2015-02-06 18:44 GMT+08:00 Mark Rutland <[email protected]>:
> On Fri, Feb 06, 2015 at 08:42:22AM +0000, Brent Wang wrote:
>> Hello Mark,
>>
>> 2015-02-06 3:30 GMT+08:00 Mark Rutland <[email protected]>:
>> > On Thu, Feb 05, 2015 at 09:24:37AM +0000, Bintian Wang wrote:
>> >> Add initial dtsi file to support Hisilicon Hi6220 SoC with
>> >> support of Octal core CPUs in two clusters and each cluster
>> >> has quard Cortex-A53.
>> >>
>> >> We now use the "spin-table" method for SMP, and it will be
>> >> changed to PSCI later.
>> >
>> > If that's the case, please don't place the enable-method and related
>> > properties in this file. Get your bootloader to add the appropriate
>> > properties for its boot protocol.
>> >
>> > When is PSCI likely to appear?
>> PSCI is under development.
>
> Sure. Do you have an estimate as to when it will appear?
Another team will do the job, I can not give my estimation now.

> What are you using for your PSCI implementation? The ARM Trusted
> Firmware?
Yes, ATF.
>
> How are you testing it?
I think cpu hotplug can test it.

>
>> > Are we certain of the split between components the PSCI implementation
>> > must touch and those the kernel must touch?
>> >
>> >> Also add dts file to support HiKey development board which
>> >> based on Hi6220 SoC and document the devicetree bindings.
>> >>
>> >> These dts files will be changed later and more nodes will be
>> >> added to describe other devices.
>> >
>> > How is this going to be changed other than the addition of nodes?
>> >
>> > Will this DTB continue to work in future? Or do you intend to make
>> > changes that will break support?
>> My original idea is: use spin-table for SMP now, when firmware is OK to
>> support PSCI, we submit another patch to replace the spin-table with PSCI.
>
> For any users who have not updated their FW, this will break booting.
>
> This is why I suggest having hte bootloader/FW fill this in as it should
> know what enable-method the FW supports.
>
>> If DTB should continue to work in the future, we really need to remove
>> the spin-table
>> from current dts file, how about just enable one core now?
>>
>> Which one do you favor or any other suggestion?
>
> If spin-table is just for testing while you await PSCI, drop spin-table
> from the dts for now.
So, just booting one core may be the right choice now, right?

>
> [...]
>
>> >> + timer {
>> >> + compatible = "arm,armv8-timer";
>> >> + interrupt-parent = <&gic>;
>> >> + interrupts = <1 13 0xff08>,
>> >> + <1 14 0xff08>,
>> >> + <1 11 0xff08>,
>> >> + <1 10 0xff08>;
>> >> + clock-frequency = <1200000>;
>> >> + };
>> >
>> > NAK. Fix your firmware to configure CNTFRQ, on all CPUs.
>> Fix in next version, maybe it will take some time to change firmware.
>
> Thanks. This _must_ be fixed.
>
> [...]
>
>> >> + pm_ctrl: pm_ctrl {
>> >> + compatible = "hisilicon,pmctrl", "syscon";
>> >> + #address-cells = <1>;
>> >> + #size-cells = <1>;
>> >> + reg = <0x0 0xf7032000 0x0 0x1000>;
>> >> + ranges = <0 0x0 0xf7032000 0x1000>;
>> >> +
>> >> + clock_power: clock3@0 {
>> >> + compatible = "hisilicon,hi6220-clock-power";
>> >> + reg = <0 0x1000>;
>> >> + #clock-cells = <1>;
>> >> + };
>> >> + };
>> >
>> > I really doesn't see the point in having a sub-device that covers the
>> > entirely of the register space of the containing node, and that being
>> > the case I am extremely concerned that the containers are marked as
>> > syscon compatible.
>> The SoC clocks are designed and placed under different system controllers,
>> so I define corresponding nodes under different controllers for clock operation.
>
> What I'm concerned wit hhere is that the pm_ctrl node and the clock3@0
> sub-node have the _exact_ same register space.
>
> Given this should mean that the clock3@0 node owns that register space,
> having the container node export this as syscon does not make sense. And
> the split between pm_ctrl and clock3@) doesn't seem to make sense given
> they cover the same space.
I understand your worry and will find the max offset of those clocks
under this controller.

>
> As I asked before, why is pm_ctrl marked as a syscon, and what's the
> point of the separate sub-node?
There is no big difference between pm_ctrl and other controller, they
are all designed as
the base address to control some functions of other modules (certainly
include some clock gates).

Maybe only one node is enough, not one node plus one sub-node ?

>
> Thanks,
> Mark.

--
Best Regards,

Bintian
===========================
Don't be nervous, just be happy!

2015-02-06 18:10:28

by Tyler Baker

[permalink] [raw]
Subject: Re: [PATCH 2/3] clk: hi6220: Clock driver support for Hisilicon hi6220 SoC

Hi Bintian,

This patch applied to next-20150204 is producing build failures on
various ARM defconfigs[1]. I received the following error in all
cases:

drivers/built-in.o: In function `hi6220_clk_register_divider':
:(.init.text+0x1a84c): undefined reference to `hi6220_register_clkdiv'
Makefile:925: recipe for target 'vmlinux' failed
make: *** [vmlinux] Error 1


On 5 February 2015 at 01:24, Bintian Wang <[email protected]> wrote:
> Add clock drivers for hi6220 SoC, this driver controls the SoC
> registers to supply different clocks to different IPs in the SoC.
>
> We add one divider clock for hi6220 because the divider in hi6220
> also has a mask bit but it doesnot obey the rule defined by flag
> "CLK_DIVIDER_HIWORD_MASK", we can not get index of the mask bit by
> left shift fixed bits (e.g. 16 bits), so we add this divider clock
> to handle it.
>
> This patch also enables this clock driver for ARCH_HISI and document
> devicetree bindings.
>
> Signed-off-by: Bintian Wang <[email protected]>
> Reviewed-by: Haojian Zhuang <[email protected]>
> Reviewed-by: Zhangfei Gao <[email protected]>
> ---
> .../devicetree/bindings/clock/hi6220-clock.txt | 30 +++
> arch/arm64/Kconfig | 1 +
> drivers/clk/Kconfig | 2 +
> drivers/clk/Makefile | 4 +-
> drivers/clk/hisilicon/Kconfig | 5 +
> drivers/clk/hisilicon/Makefile | 1 +
> drivers/clk/hisilicon/clk-hi6220.c | 284 ++++++++++++++++++++
> drivers/clk/hisilicon/clk.c | 29 ++
> drivers/clk/hisilicon/clk.h | 17 ++
> drivers/clk/hisilicon/clkdivider-hi6220.c | 273 +++++++++++++++++++
> include/dt-bindings/clock/hi6220-clock.h | 172 ++++++++++++
> 11 files changed, 815 insertions(+), 3 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/clock/hi6220-clock.txt
> create mode 100644 drivers/clk/hisilicon/Kconfig
> create mode 100644 drivers/clk/hisilicon/clk-hi6220.c
> create mode 100644 drivers/clk/hisilicon/clkdivider-hi6220.c
> create mode 100644 include/dt-bindings/clock/hi6220-clock.h
>
> diff --git a/Documentation/devicetree/bindings/clock/hi6220-clock.txt b/Documentation/devicetree/bindings/clock/hi6220-clock.txt
> new file mode 100644
> index 0000000..a3ddda1
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/hi6220-clock.txt
> @@ -0,0 +1,30 @@
> +* Hisilicon Hi6220 Clock Controller
> +
> +The hi6220 clock controller generates and supplies clock to various
> +controllers within the hi6220 SoC.
> +
> +Required Properties:
> +
> +- compatible: should be one of the following:
> + - "hisilicon,hi6220-clock-ao" - controller for those clocks under SoC
> + power always on(AO) domain, it is the sub node of SoC power AO
> + controller in dts file.
> + - "hisilicon,hi6220-clock-sys" - controller for those clocks under SoC
> + system control domain, it is the sub node of SoC system controller
> + in dts file.
> + - "hisilicon,hi6220-clock-media" - controller for those clocks under
> + SoC media control domain, it is the sub node of SoC media controller
> + in dts file.
> + - "hisilicon,hi6220-clock-power" - controller for those clocks under
> + SoC power control domain, it is the sub node of SoC power controller
> + in dts file.
> +
> +- reg: physical base address of the controller and length of memory mapped
> + region.
> +
> +- #clock-cells: should be 1.
> +
> +Each clock is assigned an identifier and client nodes use this identifier
> +to specify the clock which they consume.
> +
> +All these identifier could be found in <dt-bindings/clock/hi6220-clock.h>.
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index 78cd41c8..6efc3e3 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -175,6 +175,7 @@ config ARCH_XGENE
>
> config ARCH_HISI
> bool "Hisilicon SoC Family"
> + select COMMON_CLK_HI6220
> help
> This enables support for Hisilicon ARMv8 Family of SoCs.
>
> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
> index 3f44f29..b52c95c 100644
> --- a/drivers/clk/Kconfig
> +++ b/drivers/clk/Kconfig
> @@ -136,6 +136,8 @@ config COMMON_CLK_PXA
>
> source "drivers/clk/qcom/Kconfig"
>
> +source "drivers/clk/hisilicon/Kconfig"
> +
> endmenu
>
> source "drivers/clk/bcm/Kconfig"
> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> index d5fba5b..c58703b 100644
> --- a/drivers/clk/Makefile
> +++ b/drivers/clk/Makefile
> @@ -43,9 +43,7 @@ obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o
> obj-$(CONFIG_COMMON_CLK_AT91) += at91/
> obj-$(CONFIG_ARCH_BCM_MOBILE) += bcm/
> obj-$(CONFIG_ARCH_BERLIN) += berlin/
> -obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/
> -obj-$(CONFIG_ARCH_HIP04) += hisilicon/
> -obj-$(CONFIG_ARCH_HIX5HD2) += hisilicon/
> +obj-$(CONFIG_ARCH_HISI) += hisilicon/
> obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/
> ifeq ($(CONFIG_COMMON_CLK), y)
> obj-$(CONFIG_ARCH_MMP) += mmp/
> diff --git a/drivers/clk/hisilicon/Kconfig b/drivers/clk/hisilicon/Kconfig
> new file mode 100644
> index 0000000..e3ead46
> --- /dev/null
> +++ b/drivers/clk/hisilicon/Kconfig
> @@ -0,0 +1,5 @@
> +config COMMON_CLK_HI6220
> + tristate "Hi6220 Clock Driver"
> + depends on OF && ARCH_HISI
> + help
> + Build the Hisilicon Hi6220 clock driver based on the common clock framework.
> diff --git a/drivers/clk/hisilicon/Makefile b/drivers/clk/hisilicon/Makefile
> index 038c02f..bbf0539 100644
> --- a/drivers/clk/hisilicon/Makefile
> +++ b/drivers/clk/hisilicon/Makefile
> @@ -7,3 +7,4 @@ obj-y += clk.o clkgate-separated.o
> obj-$(CONFIG_ARCH_HI3xxx) += clk-hi3620.o
> obj-$(CONFIG_ARCH_HIP04) += clk-hip04.o
> obj-$(CONFIG_ARCH_HIX5HD2) += clk-hix5hd2.o
> +obj-$(CONFIG_COMMON_CLK_HI6220) += clkdivider-hi6220.o clk-hi6220.o
> diff --git a/drivers/clk/hisilicon/clk-hi6220.c b/drivers/clk/hisilicon/clk-hi6220.c
> new file mode 100644
> index 0000000..01d0c46
> --- /dev/null
> +++ b/drivers/clk/hisilicon/clk-hi6220.c
> @@ -0,0 +1,284 @@
> +/*
> + * Hisilicon Hi6220 clock driver
> + *
> + * Copyright (c) 2015 Hisilicon Limited.
> + *
> + * Author: Bintian Wang <[email protected]>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/clk-provider.h>
> +#include <linux/clkdev.h>
> +#include <linux/io.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_device.h>
> +#include <linux/slab.h>
> +#include <linux/clk.h>
> +
> +#include <dt-bindings/clock/hi6220-clock.h>
> +
> +#include "clk.h"
> +
> +
> +/* clocks in AO (always on) controller */
> +static struct hisi_fixed_rate_clock hi6220_fixed_rate_clks[] __initdata = {
> + { HI6220_REF32K, "ref32k", NULL, CLK_IS_ROOT, 32764, },
> + { HI6220_CLK_TCXO, "clk_tcxo", NULL, CLK_IS_ROOT, 19200000, },
> + { HI6220_MMC1_PAD, "mmc1_pad", NULL, CLK_IS_ROOT, 100000000, },
> + { HI6220_MMC2_PAD, "mmc2_pad", NULL, CLK_IS_ROOT, 100000000, },
> + { HI6220_MMC0_PAD, "mmc0_pad", NULL, CLK_IS_ROOT, 200000000, },
> + { HI6220_PLL_BBP, "bbppll0", NULL, CLK_IS_ROOT, 245760000, },
> + { HI6220_PLL_GPU, "gpupll", NULL, CLK_IS_ROOT, 1000000000,},
> + { HI6220_PLL1_DDR, "ddrpll1", NULL, CLK_IS_ROOT, 1066000000,},
> + { HI6220_PLL_SYS, "syspll", NULL, CLK_IS_ROOT, 1200000000,},
> + { HI6220_PLL_SYS_MEDIA, "media_syspll", NULL, CLK_IS_ROOT, 1200000000,},
> + { HI6220_DDR_SRC, "ddr_sel_src", NULL, CLK_IS_ROOT, 1200000000,},
> + { HI6220_PLL_MEDIA, "media_pll", NULL, CLK_IS_ROOT, 1440000000,},
> + { HI6220_PLL_DDR, "ddrpll0", NULL, CLK_IS_ROOT, 1600000000,},
> +};
> +
> +static struct hisi_fixed_factor_clock hi6220_fixed_factor_clks[] __initdata = {
> + { HI6220_300M, "clk_300m", "syspll", 1, 4, 0, },
> + { HI6220_150M, "clk_150m", "clk_300m", 1, 2, 0, },
> + { HI6220_PICOPHY_SRC, "picophy_src", "clk_150m", 1, 4, 0, },
> + { HI6220_MMC0_SRC_SEL, "mmc0srcsel", "mmc0_sel", 1, 8, 0, },
> + { HI6220_MMC1_SRC_SEL, "mmc1srcsel", "mmc1_sel", 1, 8, 0, },
> + { HI6220_MMC2_SRC_SEL, "mmc2srcsel", "mmc2_sel", 1, 8, 0, },
> + { HI6220_VPU_CODEC, "vpucodec", "codec_jpeg_aclk", 1, 2, 0, },
> + { HI6220_MMC0_SMP, "mmc0_sample", "mmc0_sel", 1, 8, 0, },
> + { HI6220_MMC1_SMP, "mmc1_sample", "mmc1_sel", 1, 8, 0, },
> + { HI6220_MMC2_SMP, "mmc2_sample", "mmc2_sel", 1, 8, 0, },
> +};
> +
> +static struct hisi_gate_clock hi6220_separated_gate_clks_ao[] __initdata = {
> + { HI6220_WDT0_PCLK, "wdt0_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 12, 0, },
> + { HI6220_WDT1_PCLK, "wdt1_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 13, 0, },
> + { HI6220_WDT2_PCLK, "wdt2_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 14, 0, },
> + { HI6220_TIMER0_PCLK, "timer0_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 15, 0, },
> + { HI6220_TIMER1_PCLK, "timer1_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 16, 0, },
> + { HI6220_TIMER2_PCLK, "timer2_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 17, 0, },
> + { HI6220_TIMER3_PCLK, "timer3_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 18, 0, },
> + { HI6220_TIMER4_PCLK, "timer4_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 19, 0, },
> + { HI6220_TIMER5_PCLK, "timer5_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 20, 0, },
> + { HI6220_TIMER6_PCLK, "timer6_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 21, 0, },
> + { HI6220_TIMER7_PCLK, "timer7_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 22, 0, },
> + { HI6220_TIMER8_PCLK, "timer8_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 23, 0, },
> + { HI6220_UART0_PCLK, "uart0_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 24, 0, },
> +};
> +
> +static void __init hi6220_clk_ao_init(struct device_node *np)
> +{
> + struct hisi_clock_data *clk_data;
> +
> + clk_data = hisi_clk_init(np, HI6220_AO_NR_CLKS);
> + if (!clk_data)
> + return;
> +
> + hisi_clk_register_fixed_rate(hi6220_fixed_rate_clks,
> + ARRAY_SIZE(hi6220_fixed_rate_clks), clk_data);
> +
> + hisi_clk_register_fixed_factor(hi6220_fixed_factor_clks,
> + ARRAY_SIZE(hi6220_fixed_factor_clks), clk_data);
> +
> + hisi_clk_register_gate_sep(hi6220_separated_gate_clks_ao,
> + ARRAY_SIZE(hi6220_separated_gate_clks_ao), clk_data);
> +}
> +CLK_OF_DECLARE(hi6220_clk_ao, "hisilicon,hi6220-clock-ao", hi6220_clk_ao_init);
> +
> +
> +/* clocks in sysctrl */
> +static const char *mmc0_mux0_p[] __initconst = { "pll_ddr_gate", "syspll", };
> +static const char *mmc0_mux1_p[] __initconst = { "mmc0_mux0", "pll_media_gate", };
> +static const char *mmc0_src_p[] __initconst = { "mmc0srcsel", "mmc0_div", };
> +static const char *mmc1_mux0_p[] __initconst = { "pll_ddr_gate", "syspll", };
> +static const char *mmc1_mux1_p[] __initconst = { "mmc1_mux0", "pll_media_gate", };
> +static const char *mmc1_src_p[] __initconst = { "mmc1srcsel", "mmc1_div", };
> +static const char *mmc2_mux0_p[] __initconst = { "pll_ddr_gate", "syspll", };
> +static const char *mmc2_mux1_p[] __initconst = { "mmc2_mux0", "pll_media_gate", };
> +static const char *mmc2_src_p[] __initconst = { "mmc2srcsel", "mmc2_div", };
> +static const char *mmc0_sample_in[] __initconst = { "mmc0_sample", "mmc0_pad", };
> +static const char *mmc1_sample_in[] __initconst = { "mmc1_sample", "mmc1_pad", };
> +static const char *mmc2_sample_in[] __initconst = { "mmc2_sample", "mmc2_pad", };
> +static const char *uart1_src[] __initconst = { "clk_tcxo", "clk_150m", };
> +static const char *uart2_src[] __initconst = { "clk_tcxo", "clk_150m", };
> +static const char *uart3_src[] __initconst = { "clk_tcxo", "clk_150m", };
> +static const char *uart4_src[] __initconst = { "clk_tcxo", "clk_150m", };
> +static const char *hifi_src[] __initconst = { "syspll", "pll_media_gate", };
> +
> +static struct hisi_gate_clock hi6220_separated_gate_clks_sys[] __initdata = {
> + { HI6220_MMC0_CLK, "mmc0_clk", "mmc0_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 0, 0, },
> + { HI6220_MMC0_CIUCLK, "mmc0_ciuclk", "mmc0_smp_in", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 0, 0, },
> + { HI6220_MMC1_CLK, "mmc1_clk", "mmc1_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 1, 0, },
> + { HI6220_MMC1_CIUCLK, "mmc1_ciuclk", "mmc1_smp_in", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 1, 0, },
> + { HI6220_MMC2_CLK, "mmc2_clk", "mmc2_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 2, 0, },
> + { HI6220_MMC2_CIUCLK, "mmc2_ciuclk", "mmc2_smp_in", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 2, 0, },
> + { HI6220_USBOTG_HCLK, "usbotg_hclk", "clk_bus", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 4, 0, },
> + { HI6220_CLK_PICOPHY, "clk_picophy", "cs_dapb", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 5, 0, },
> + { HI6220_HIFI, "hifi_clk", "hifi_div", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x210, 0, 0, },
> + { HI6220_DACODEC_PCLK, "dacodec_pclk", "clk_bus", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x210, 5, 0, },
> + { HI6220_EDMAC_ACLK, "edmac_aclk", "clk_bus", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x220, 2, 0, },
> + { HI6220_CS_ATB, "cs_atb", "cs_atb_div", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 0, 0, },
> + { HI6220_I2C0_CLK, "i2c0_clk", "clk_150m", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 1, 0, },
> + { HI6220_I2C1_CLK, "i2c1_clk", "clk_150m", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 2, 0, },
> + { HI6220_I2C2_CLK, "i2c2_clk", "clk_150m", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 3, 0, },
> + { HI6220_I2C3_CLK, "i2c3_clk", "clk_150m", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 4, 0, },
> + { HI6220_UART1_PCLK, "uart1_pclk", "uart1_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 5, 0, },
> + { HI6220_UART2_PCLK, "uart2_pclk", "uart2_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 6, 0, },
> + { HI6220_UART3_PCLK, "uart3_pclk", "uart3_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 7, 0, },
> + { HI6220_UART4_PCLK, "uart4_pclk", "uart4_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 8, 0, },
> + { HI6220_SPI_CLK, "spi_clk", "clk_150m", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 9, 0, },
> + { HI6220_MMU_CLK, "mmu_clk", "ddrc_axi1", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x240, 11, 0, },
> + { HI6220_HIFI_SEL, "hifi_sel", "hifi_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 0, 0, },
> + { HI6220_MMC0_SYSPLL, "mmc0_syspll", "syspll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 1, 0, },
> + { HI6220_MMC1_SYSPLL, "mmc1_syspll", "syspll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 2, 0, },
> + { HI6220_MMC2_SYSPLL, "mmc2_syspll", "syspll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 3, 0, },
> + { HI6220_MMC0_SEL, "mmc0_sel", "mmc0_mux1", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 6, 0, },
> + { HI6220_MMC1_SEL, "mmc1_sel", "mmc1_mux1", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 7, 0, },
> + { HI6220_BBPPLL_SEL, "bbppll_sel", "pll0_bbp_gate", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 9, 0, },
> + { HI6220_MEDIA_PLL_SRC, "media_pll_src", "pll_media_gate", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 10, 0, },
> + { HI6220_MMC2_SEL, "mmc2_sel", "mmc2_mux1", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 11, 0, },
> + { HI6220_CS_ATB_SYSPLL, "cs_atb_syspll", "syspll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 12, 0, },
> +};
> +
> +static struct hisi_mux_clock hi6220_mux_clks_sys[] __initdata = {
> + { HI6220_MMC0_SRC, "mmc0_src", mmc0_src_p, ARRAY_SIZE(mmc0_src_p), CLK_SET_RATE_PARENT, 0x4, 0, 1, 0, },
> + { HI6220_MMC0_SMP_IN, "mmc0_smp_in", mmc0_sample_in, ARRAY_SIZE(mmc0_sample_in), CLK_SET_RATE_PARENT, 0x4, 0, 1, 0, },
> + { HI6220_MMC1_SRC, "mmc1_src", mmc1_src_p, ARRAY_SIZE(mmc1_src_p), CLK_SET_RATE_PARENT, 0x4, 2, 1, 0, },
> + { HI6220_MMC1_SMP_IN, "mmc1_smp_in", mmc1_sample_in, ARRAY_SIZE(mmc1_sample_in), CLK_SET_RATE_PARENT, 0x4, 2, 1, 0, },
> + { HI6220_MMC2_SRC, "mmc2_src", mmc2_src_p, ARRAY_SIZE(mmc2_src_p), CLK_SET_RATE_PARENT, 0x4, 4, 1, 0, },
> + { HI6220_MMC2_SMP_IN, "mmc2_smp_in", mmc2_sample_in, ARRAY_SIZE(mmc2_sample_in), CLK_SET_RATE_PARENT, 0x4, 4, 1, 0, },
> + { HI6220_HIFI_SRC, "hifi_src", hifi_src, ARRAY_SIZE(hifi_src), CLK_SET_RATE_PARENT, 0x400, 0, 1, CLK_MUX_HIWORD_MASK,},
> + { HI6220_UART1_SRC, "uart1_src", uart1_src, ARRAY_SIZE(uart1_src), CLK_SET_RATE_PARENT, 0x400, 1, 1, CLK_MUX_HIWORD_MASK,},
> + { HI6220_UART2_SRC, "uart2_src", uart2_src, ARRAY_SIZE(uart2_src), CLK_SET_RATE_PARENT, 0x400, 2, 1, CLK_MUX_HIWORD_MASK,},
> + { HI6220_UART3_SRC, "uart3_src", uart3_src, ARRAY_SIZE(uart3_src), CLK_SET_RATE_PARENT, 0x400, 3, 1, CLK_MUX_HIWORD_MASK,},
> + { HI6220_UART4_SRC, "uart4_src", uart4_src, ARRAY_SIZE(uart4_src), CLK_SET_RATE_PARENT, 0x400, 4, 1, CLK_MUX_HIWORD_MASK,},
> + { HI6220_MMC0_MUX0, "mmc0_mux0", mmc0_mux0_p, ARRAY_SIZE(mmc0_mux0_p), CLK_SET_RATE_PARENT, 0x400, 5, 1, CLK_MUX_HIWORD_MASK,},
> + { HI6220_MMC1_MUX0, "mmc1_mux0", mmc1_mux0_p, ARRAY_SIZE(mmc1_mux0_p), CLK_SET_RATE_PARENT, 0x400, 11, 1, CLK_MUX_HIWORD_MASK,},
> + { HI6220_MMC2_MUX0, "mmc2_mux0", mmc2_mux0_p, ARRAY_SIZE(mmc2_mux0_p), CLK_SET_RATE_PARENT, 0x400, 12, 1, CLK_MUX_HIWORD_MASK,},
> + { HI6220_MMC0_MUX1, "mmc0_mux1", mmc0_mux1_p, ARRAY_SIZE(mmc0_mux1_p), CLK_SET_RATE_PARENT, 0x400, 13, 1, CLK_MUX_HIWORD_MASK,},
> + { HI6220_MMC1_MUX1, "mmc1_mux1", mmc1_mux1_p, ARRAY_SIZE(mmc1_mux1_p), CLK_SET_RATE_PARENT, 0x400, 14, 1, CLK_MUX_HIWORD_MASK,},
> + { HI6220_MMC2_MUX1, "mmc2_mux1", mmc2_mux1_p, ARRAY_SIZE(mmc2_mux1_p), CLK_SET_RATE_PARENT, 0x400, 15, 1, CLK_MUX_HIWORD_MASK,},
> +};
> +
> +static struct hi6220_divider_clock hi6220_div_clks_sys[] __initdata = {
> + { HI6220_CLK_BUS, "clk_bus", "clk_300m", CLK_SET_RATE_PARENT, 0x490, 0, 4, 7, },
> + { HI6220_MMC0_DIV, "mmc0_div", "mmc0_syspll", CLK_SET_RATE_PARENT, 0x494, 0, 6, 7, },
> + { HI6220_MMC1_DIV, "mmc1_div", "mmc1_syspll", CLK_SET_RATE_PARENT, 0x498, 0, 6, 7, },
> + { HI6220_MMC2_DIV, "mmc2_div", "mmc2_syspll", CLK_SET_RATE_PARENT, 0x49c, 0, 6, 7, },
> + { HI6220_HIFI_DIV, "hifi_div", "hifi_sel", CLK_SET_RATE_PARENT, 0x4a0, 0, 4, 7, },
> + { HI6220_BBPPLL0_DIV, "bbppll0_div", "bbppll_sel", CLK_SET_RATE_PARENT, 0x4a0, 8, 6, 15,},
> + { HI6220_CS_DAPB, "cs_dapb", "picophy_src", CLK_SET_RATE_PARENT, 0x4a0, 24, 2, 31,},
> + { HI6220_CS_ATB_DIV, "cs_atb_div", "cs_atb_syspll", CLK_SET_RATE_PARENT, 0x4a4, 0, 4, 7, },
> +};
> +
> +static void __init hi6220_clk_sys_init(struct device_node *np)
> +{
> + struct hisi_clock_data *clk_data;
> +
> + clk_data = hisi_clk_init(np, HI6220_SYS_NR_CLKS);
> + if (!clk_data)
> + return;
> +
> + hisi_clk_register_gate_sep(hi6220_separated_gate_clks_sys,
> + ARRAY_SIZE(hi6220_separated_gate_clks_sys), clk_data);
> +
> + hisi_clk_register_mux(hi6220_mux_clks_sys,
> + ARRAY_SIZE(hi6220_mux_clks_sys), clk_data);
> +
> + hi6220_clk_register_divider(hi6220_div_clks_sys,
> + ARRAY_SIZE(hi6220_div_clks_sys), clk_data);
> +}
> +CLK_OF_DECLARE(hi6220_clk_sys, "hisilicon,hi6220-clock-sys", hi6220_clk_sys_init);
> +
> +
> +/* clocks in media controller */
> +static const char *clk_1000_1200_src[] __initconst = { "pll_gpu_gate", "media_syspll_src", };
> +static const char *clk_1440_1200_src[] __initconst = { "media_syspll_src", "media_pll_src", };
> +static const char *clk_1000_1440_src[] __initconst = { "pll_gpu_gate", "media_pll_src", };
> +
> +static struct hisi_gate_clock hi6220_separated_gate_clks_media[] __initdata = {
> + { HI6220_DSI_PCLK, "dsi_pclk", "vpucodec", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 0, 0, },
> + { HI6220_G3D_PCLK, "g3d_pclk", "vpucodec", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 1, 0, },
> + { HI6220_ACLK_CODEC_VPU, "aclk_codec_vpu", "ade_core_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 3, 0, },
> + { HI6220_ISP_SCLK, "isp_sclk", "isp_sclk_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 5, 0, },
> + { HI6220_ADE_CORE, "ade_core", "ade_core_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 6, 0, },
> + { HI6220_MED_MMU, "media_mmu", "mmu_clk", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 8, 0, },
> + { HI6220_CFG_CSI4PHY, "cfg_csi4phy", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 9, 0, },
> + { HI6220_CFG_CSI2PHY, "cfg_csi2phy", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 10, 0, },
> + { HI6220_ISP_SCLK_GATE, "isp_sclk_gate", "media_pll_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 11, 0, },
> + { HI6220_ISP_SCLK_GATE1, "isp_sclk_gate1", "media_pll_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 12, 0, },
> + { HI6220_ADE_CORE_GATE, "ade_core_gate", "media_pll_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 14, 0, },
> + { HI6220_CODEC_VPU_GATE, "codec_vpu_gate", "clk_1000_1440", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 15, 0, },
> + { HI6220_MED_SYSPLL, "media_syspll_src", "media_syspll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 17, 0, },
> +};
> +
> +static struct hisi_mux_clock hi6220_mux_clks_media[] __initdata = {
> + { HI6220_1440_1200, "clk_1440_1200", clk_1440_1200_src, ARRAY_SIZE(clk_1440_1200_src), CLK_SET_RATE_PARENT, 0x51c, 0, 1, 0, },
> + { HI6220_1000_1200, "clk_1000_1200", clk_1000_1200_src, ARRAY_SIZE(clk_1000_1200_src), CLK_SET_RATE_PARENT, 0x51c, 1, 1, 0, },
> + { HI6220_1000_1440, "clk_1000_1440", clk_1000_1440_src, ARRAY_SIZE(clk_1000_1440_src), CLK_SET_RATE_PARENT, 0x51c, 6, 1, 0, },
> +};
> +
> +static struct hi6220_divider_clock hi6220_div_clks_media[] __initdata = {
> + { HI6220_CODEC_JPEG, "codec_jpeg_aclk", "media_pll_src", CLK_SET_RATE_PARENT, 0xcbc, 0, 4, 23, },
> + { HI6220_ISP_SCLK_SRC, "isp_sclk_src", "isp_sclk_gate", CLK_SET_RATE_PARENT, 0xcbc, 8, 4, 15, },
> + { HI6220_ISP_SCLK1, "isp_sclk1", "isp_sclk_gate1", CLK_SET_RATE_PARENT, 0xcbc, 24, 4, 31, },
> + { HI6220_ADE_CORE_SRC, "ade_core_src", "ade_core_gate", CLK_SET_RATE_PARENT, 0xcc0, 16, 3, 23, },
> + { HI6220_ADE_PIX_SRC, "ade_pix_src", "clk_1440_1200", CLK_SET_RATE_PARENT, 0xcc0, 24, 6, 31, },
> + { HI6220_G3D_CLK, "g3d_clk", "clk_1000_1200", CLK_SET_RATE_PARENT, 0xcc4, 8, 4, 15, },
> + { HI6220_CODEC_VPU_SRC, "codec_vpu_src", "codec_vpu_gate", CLK_SET_RATE_PARENT, 0xcc4, 24, 6, 31, },
> +};
> +
> +static void __init hi6220_clk_media_init(struct device_node *np)
> +{
> + struct hisi_clock_data *clk_data;
> +
> + clk_data = hisi_clk_init(np, HI6220_MEDIA_NR_CLKS);
> + if (!clk_data)
> + return;
> +
> + hisi_clk_register_gate_sep(hi6220_separated_gate_clks_media,
> + ARRAY_SIZE(hi6220_separated_gate_clks_media), clk_data);
> +
> + hisi_clk_register_mux(hi6220_mux_clks_media,
> + ARRAY_SIZE(hi6220_mux_clks_media), clk_data);
> +
> + hi6220_clk_register_divider(hi6220_div_clks_media,
> + ARRAY_SIZE(hi6220_div_clks_media), clk_data);
> +}
> +CLK_OF_DECLARE(hi6220_clk_media, "hisilicon,hi6220-clock-media", hi6220_clk_media_init);
> +
> +
> +/* clocks in pmctrl */
> +static struct hisi_gate_clock hi6220_gate_clks_power[] __initdata = {
> + { HI6220_PLL_GPU_GATE, "pll_gpu_gate", "gpupll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x8, 0, 0, },
> + { HI6220_PLL1_DDR_GATE, "pll1_ddr_gate", "ddrpll1", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x10, 0, 0, },
> + { HI6220_PLL_DDR_GATE, "pll_ddr_gate", "ddrpll0", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x18, 0, 0, },
> + { HI6220_PLL_MEDIA_GATE, "pll_media_gate", "media_pll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x38, 0, 0, },
> + { HI6220_PLL0_BBP_GATE, "pll0_bbp_gate", "bbppll0", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x48, 0, 0, },
> +};
> +
> +static struct hi6220_divider_clock hi6220_div_clks_power[] __initdata = {
> + { HI6220_DDRC_SRC, "ddrc_src", "ddr_sel_src", CLK_SET_RATE_PARENT, 0x5a8, 0, 4, 0, },
> + { HI6220_DDRC_AXI1, "ddrc_axi1", "ddrc_src", CLK_SET_RATE_PARENT, 0x5a8, 8, 2, 0, },
> +};
> +
> +static void __init hi6220_clk_power_init(struct device_node *np)
> +{
> + struct hisi_clock_data *clk_data;
> +
> + clk_data = hisi_clk_init(np, HI6220_POWER_NR_CLKS);
> + if (!clk_data)
> + return;
> +
> + hisi_clk_register_gate(hi6220_gate_clks_power,
> + ARRAY_SIZE(hi6220_gate_clks_power), clk_data);
> +
> + hi6220_clk_register_divider(hi6220_div_clks_power,
> + ARRAY_SIZE(hi6220_div_clks_power), clk_data);
> +}
> +CLK_OF_DECLARE(hi6220_clk_power, "hisilicon,hi6220-clock-power", hi6220_clk_power_init);
> diff --git a/drivers/clk/hisilicon/clk.c b/drivers/clk/hisilicon/clk.c
> index a078e84..5d2305c 100644
> --- a/drivers/clk/hisilicon/clk.c
> +++ b/drivers/clk/hisilicon/clk.c
> @@ -232,3 +232,32 @@ void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *clks,
> data->clk_data.clks[clks[i].id] = clk;
> }
> }
> +
> +void __init hi6220_clk_register_divider(struct hi6220_divider_clock *clks,
> + int nums, struct hisi_clock_data *data)
> +{
> + struct clk *clk;
> + void __iomem *base = data->base;
> + int i;
> +
> + for (i = 0; i < nums; i++) {
> + clk = hi6220_register_clkdiv(NULL, clks[i].name,
> + clks[i].parent_name,
> + clks[i].flags,
> + base + clks[i].offset,
> + clks[i].shift,
> + clks[i].width,
> + clks[i].mask_bit,
> + &hisi_clk_lock);
> + if (IS_ERR(clk)) {
> + pr_err("%s: failed to register clock %s\n",
> + __func__, clks[i].name);
> + continue;
> + }
> +
> + if (clks[i].alias)
> + clk_register_clkdev(clk, clks[i].alias, NULL);
> +
> + data->clk_data.clks[clks[i].id] = clk;
> + }
> +}
> diff --git a/drivers/clk/hisilicon/clk.h b/drivers/clk/hisilicon/clk.h
> index 31083ff..462a570 100644
> --- a/drivers/clk/hisilicon/clk.h
> +++ b/drivers/clk/hisilicon/clk.h
> @@ -79,6 +79,18 @@ struct hisi_divider_clock {
> const char *alias;
> };
>
> +struct hi6220_divider_clock {
> + unsigned int id;
> + const char *name;
> + const char *parent_name;
> + unsigned long flags;
> + unsigned long offset;
> + u8 shift;
> + u8 width;
> + u32 mask_bit;
> + const char *alias;
> +};
> +
> struct hisi_gate_clock {
> unsigned int id;
> const char *name;
> @@ -94,6 +106,9 @@ struct clk *hisi_register_clkgate_sep(struct device *, const char *,
> const char *, unsigned long,
> void __iomem *, u8,
> u8, spinlock_t *);
> +struct clk *hi6220_register_clkdiv(struct device *dev, const char *name,
> + const char *parent_name, unsigned long flags, void __iomem *reg,
> + u8 shift, u8 width, u32 mask_bit, spinlock_t *lock);
>
> struct hisi_clock_data __init *hisi_clk_init(struct device_node *, int);
> void __init hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *,
> @@ -108,4 +123,6 @@ void __init hisi_clk_register_gate(struct hisi_gate_clock *,
> int, struct hisi_clock_data *);
> void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *,
> int, struct hisi_clock_data *);
> +void __init hi6220_clk_register_divider(struct hi6220_divider_clock *,
> + int, struct hisi_clock_data *);
> #endif /* __HISI_CLK_H */
> diff --git a/drivers/clk/hisilicon/clkdivider-hi6220.c b/drivers/clk/hisilicon/clkdivider-hi6220.c
> new file mode 100644
> index 0000000..9e3825b
> --- /dev/null
> +++ b/drivers/clk/hisilicon/clkdivider-hi6220.c
> @@ -0,0 +1,273 @@
> +/*
> + * Hisilicon hi6220 SoC divider clock driver
> + *
> + * Copyright (c) 2015 Hisilicon Limited.
> + *
> + * Author: Bintian Wang <[email protected]>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/clk-provider.h>
> +#include <linux/slab.h>
> +#include <linux/io.h>
> +#include <linux/err.h>
> +
> +#define div_mask(width) ((1 << (width)) - 1)
> +
> +/*
> + * The reverse of DIV_ROUND_UP: The maximum number which
> + * divided by m is r
> + */
> +#define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1)
> +
> +/**
> + * struct hi6220_clk_divider - divider clock for hi6220
> + *
> + * @hw: handle between common and hardware-specific interfaces
> + * @reg: register containing divider
> + * @shift: shift to the divider bit field
> + * @width: width of the divider bit field
> + * @mask: mask for setting divider rate
> + * @table: the div table that the divider supports
> + * @lock: register lock
> + */
> +struct hi6220_clk_divider {
> + struct clk_hw hw;
> + void __iomem *reg;
> + u8 shift;
> + u8 width;
> + u32 mask;
> + const struct clk_div_table *table;
> + spinlock_t *lock;
> +};
> +
> +#define to_hi6220_clk_divider(_hw) \
> + container_of(_hw, struct hi6220_clk_divider, hw)
> +
> +static unsigned int hi6220_get_table_maxdiv(const struct clk_div_table *table)
> +{
> + unsigned int maxdiv = 0;
> + const struct clk_div_table *clkt;
> +
> + for (clkt = table; clkt->div; clkt++)
> + if (clkt->div > maxdiv)
> + maxdiv = clkt->div;
> + return maxdiv;
> +}
> +
> +static unsigned int hi6220_get_table_div(const struct clk_div_table *table,
> + unsigned int val)
> +{
> + const struct clk_div_table *clkt;
> +
> + for (clkt = table; clkt->div; clkt++)
> + if (clkt->val == val)
> + return clkt->div;
> +
> + return 0;
> +}
> +
> +static unsigned int hi6220_get_table_val(const struct clk_div_table *table,
> + unsigned int div)
> +{
> + const struct clk_div_table *clkt;
> +
> + for (clkt = table; clkt->div; clkt++)
> + if (clkt->div == div)
> + return clkt->val;
> + return 0;
> +}
> +
> +static unsigned long hi6220_clkdiv_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + unsigned int div, val;
> + struct hi6220_clk_divider *dclk = to_hi6220_clk_divider(hw);
> +
> + val = readl_relaxed(dclk->reg) >> dclk->shift;
> + val &= div_mask(dclk->width);
> +
> + div = hi6220_get_table_div(dclk->table, val);
> + if (!div) {
> + pr_warn("%s: Invalid divisor for clock %s\n", __func__,
> + __clk_get_name(hw->clk));
> + return parent_rate;
> + }
> +
> + return parent_rate / div;
> +}
> +
> +static bool hi6220_is_valid_div(const struct clk_div_table *table,
> + unsigned int div)
> +{
> + const struct clk_div_table *clkt;
> +
> + for (clkt = table; clkt->div; clkt++)
> + if (clkt->div == div)
> + return true;
> + return false;
> +}
> +
> +static int hi6220_clkdiv_bestdiv(struct clk_hw *hw, unsigned long rate,
> + unsigned long *best_parent_rate)
> +{
> + unsigned int i, bestdiv = 0;
> + unsigned long parent_rate, best = 0, now, maxdiv;
> +
> + struct hi6220_clk_divider *dclk = to_hi6220_clk_divider(hw);
> + struct clk *clk_parent = __clk_get_parent(hw->clk);
> +
> + maxdiv = hi6220_get_table_maxdiv(dclk->table);
> +
> + if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) {
> + parent_rate = *best_parent_rate;
> + bestdiv = DIV_ROUND_UP(parent_rate, rate);
> + bestdiv = (bestdiv == 0) ? 1 : bestdiv;
> + bestdiv = (bestdiv > maxdiv) ? maxdiv : bestdiv;
> + return bestdiv;
> + }
> +
> + /*
> + * The maximum divider we can use without overflowing
> + * unsigned long in rate * i below
> + */
> + maxdiv = min(ULONG_MAX / rate, maxdiv);
> +
> + for (i = 1; i <= maxdiv; i++) {
> + if (!hi6220_is_valid_div(dclk->table, i))
> + continue;
> + parent_rate = __clk_round_rate(clk_parent,
> + MULT_ROUND_UP(rate, i));
> + now = parent_rate / i;
> + if (now <= rate && now > best) {
> + bestdiv = i;
> + best = now;
> + *best_parent_rate = parent_rate;
> + }
> + }
> +
> + if (!bestdiv) {
> + bestdiv = hi6220_get_table_maxdiv(dclk->table);
> + *best_parent_rate = __clk_round_rate(clk_parent, 1);
> + }
> +
> + return bestdiv;
> +}
> +
> +static long hi6220_clkdiv_round_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long *prate)
> +{
> + int div;
> +
> + if (!rate)
> + rate = 1;
> +
> + div = hi6220_clkdiv_bestdiv(hw, rate, prate);
> +
> + return *prate / div;
> +}
> +
> +static int hi6220_clkdiv_set_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long parent_rate)
> +{
> + unsigned int div, value;
> + unsigned long flags = 0;
> + u32 data;
> + struct hi6220_clk_divider *dclk = to_hi6220_clk_divider(hw);
> +
> + div = parent_rate / rate;
> +
> + if (!hi6220_is_valid_div(dclk->table, div))
> + return -EINVAL;
> +
> + value = hi6220_get_table_val(dclk->table, div);
> +
> + if (value > div_mask(dclk->width))
> + value = div_mask(dclk->width);
> +
> + if (dclk->lock)
> + spin_lock_irqsave(dclk->lock, flags);
> +
> + data = readl_relaxed(dclk->reg);
> + data &= ~(div_mask(dclk->width) << dclk->shift);
> + data |= value << dclk->shift;
> + data |= dclk->mask;
> +
> + writel_relaxed(data, dclk->reg);
> +
> + if (dclk->lock)
> + spin_unlock_irqrestore(dclk->lock, flags);
> +
> + return 0;
> +}
> +
> +static struct clk_ops hi6220_clkdiv_ops = {
> + .recalc_rate = hi6220_clkdiv_recalc_rate,
> + .round_rate = hi6220_clkdiv_round_rate,
> + .set_rate = hi6220_clkdiv_set_rate,
> +};
> +
> +struct clk *hi6220_register_clkdiv(struct device *dev, const char *name,
> + const char *parent_name, unsigned long flags, void __iomem *reg,
> + u8 shift, u8 width, u32 mask_bit, spinlock_t *lock)
> +{
> + struct hi6220_clk_divider *div;
> + struct clk *clk;
> + struct clk_init_data init;
> + struct clk_div_table *table;
> + u32 max_div, min_div;
> + int i;
> +
> + /* allocate the divider */
> + div = kzalloc(sizeof(struct hi6220_clk_divider), GFP_KERNEL);
> + if (!div) {
> + pr_err("%s: could not allocate divider clk\n", __func__);
> + return ERR_PTR(-ENOMEM);
> + }
> +
> + /* Init the divider table */
> + max_div = div_mask(width) + 1;
> + min_div = 1;
> +
> + table = kzalloc(sizeof(struct clk_div_table) * (max_div + 1), GFP_KERNEL);
> + if (!table) {
> + kfree(div);
> + pr_err("%s: failed to alloc divider table!\n", __func__);
> + return ERR_PTR(-ENOMEM);
> + }
> +
> + for (i = 0; i < max_div; i++) {
> + table[i].div = min_div + i;
> + table[i].val = table[i].div - 1;
> + }
> +
> + init.name = name;
> + init.ops = &hi6220_clkdiv_ops;
> + init.flags = flags | CLK_IS_BASIC;
> + init.parent_names = parent_name ? &parent_name : NULL;
> + init.num_parents = parent_name ? 1 : 0;
> +
> + /* struct hi6220_clk_divider assignments */
> + div->reg = reg;
> + div->shift = shift;
> + div->width = width;
> + div->mask = mask_bit ? BIT(mask_bit) : 0;
> + div->lock = lock;
> + div->hw.init = &init;
> + div->table = table;
> +
> + /* register the clock */
> + clk = clk_register(dev, &div->hw);
> +
> + if (IS_ERR(clk)) {
> + kfree(table);
> + kfree(div);
> + }
> +
> + return clk;
> +}
> diff --git a/include/dt-bindings/clock/hi6220-clock.h b/include/dt-bindings/clock/hi6220-clock.h
> new file mode 100644
> index 0000000..05033e7
> --- /dev/null
> +++ b/include/dt-bindings/clock/hi6220-clock.h
> @@ -0,0 +1,172 @@
> +/*
> + * Copyright (c) 2015 Hisilicon Limited.
> + *
> + * Author: Bintian Wang <[email protected]>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#ifndef __DT_BINDINGS_CLOCK_HI6220_H
> +#define __DT_BINDINGS_CLOCK_HI6220_H
> +
> +/* clk in AO (always on) controller */
> +#define HI6220_NONE_CLOCK 0
> +
> +/* fixed rate clocks */
> +#define HI6220_REF32K 1
> +#define HI6220_CLK_TCXO 2
> +#define HI6220_MMC1_PAD 3
> +#define HI6220_MMC2_PAD 4
> +#define HI6220_MMC0_PAD 5
> +#define HI6220_PLL_BBP 6
> +#define HI6220_PLL_GPU 7
> +#define HI6220_PLL1_DDR 8
> +#define HI6220_PLL_SYS 9
> +#define HI6220_PLL_SYS_MEDIA 10
> +#define HI6220_DDR_SRC 11
> +#define HI6220_PLL_MEDIA 12
> +#define HI6220_PLL_DDR 13
> +
> +/* fixed factor clocks */
> +#define HI6220_300M 16
> +#define HI6220_150M 17
> +#define HI6220_PICOPHY_SRC 18
> +#define HI6220_MMC0_SRC_SEL 19
> +#define HI6220_MMC1_SRC_SEL 20
> +#define HI6220_MMC2_SRC_SEL 21
> +#define HI6220_VPU_CODEC 22
> +#define HI6220_MMC0_SMP 23
> +#define HI6220_MMC1_SMP 24
> +#define HI6220_MMC2_SMP 25
> +
> +/* gate clocks */
> +#define HI6220_WDT0_PCLK 28
> +#define HI6220_WDT1_PCLK 29
> +#define HI6220_WDT2_PCLK 30
> +#define HI6220_TIMER0_PCLK 31
> +#define HI6220_TIMER1_PCLK 32
> +#define HI6220_TIMER2_PCLK 33
> +#define HI6220_TIMER3_PCLK 34
> +#define HI6220_TIMER4_PCLK 35
> +#define HI6220_TIMER5_PCLK 36
> +#define HI6220_TIMER6_PCLK 37
> +#define HI6220_TIMER7_PCLK 38
> +#define HI6220_TIMER8_PCLK 39
> +#define HI6220_UART0_PCLK 40
> +
> +#define HI6220_AO_NR_CLKS 48
> +
> +/* clk in systrl */
> +/* gate clock */
> +#define HI6220_MMC0_CLK 1
> +#define HI6220_MMC0_CIUCLK 2
> +#define HI6220_MMC1_CLK 3
> +#define HI6220_MMC1_CIUCLK 4
> +#define HI6220_MMC2_CLK 5
> +#define HI6220_MMC2_CIUCLK 6
> +#define HI6220_USBOTG_HCLK 7
> +#define HI6220_CLK_PICOPHY 8
> +#define HI6220_HIFI 9
> +#define HI6220_DACODEC_PCLK 10
> +#define HI6220_EDMAC_ACLK 11
> +#define HI6220_CS_ATB 12
> +#define HI6220_I2C0_CLK 13
> +#define HI6220_I2C1_CLK 14
> +#define HI6220_I2C2_CLK 15
> +#define HI6220_I2C3_CLK 16
> +#define HI6220_UART1_PCLK 17
> +#define HI6220_UART2_PCLK 18
> +#define HI6220_UART3_PCLK 19
> +#define HI6220_UART4_PCLK 20
> +#define HI6220_SPI_CLK 21
> +#define HI6220_MMU_CLK 22
> +#define HI6220_HIFI_SEL 23
> +#define HI6220_MMC0_SYSPLL 24
> +#define HI6220_MMC1_SYSPLL 25
> +#define HI6220_MMC2_SYSPLL 26
> +#define HI6220_MMC0_SEL 27
> +#define HI6220_MMC1_SEL 28
> +#define HI6220_BBPPLL_SEL 29
> +#define HI6220_MEDIA_PLL_SRC 30
> +#define HI6220_MMC2_SEL 31
> +#define HI6220_CS_ATB_SYSPLL 32
> +
> +/* mux clocks */
> +#define HI6220_MMC0_SRC 35
> +#define HI6220_MMC0_SMP_IN 36
> +#define HI6220_MMC1_SRC 37
> +#define HI6220_MMC1_SMP_IN 38
> +#define HI6220_MMC2_SRC 39
> +#define HI6220_MMC2_SMP_IN 40
> +#define HI6220_HIFI_SRC 41
> +#define HI6220_UART1_SRC 42
> +#define HI6220_UART2_SRC 43
> +#define HI6220_UART3_SRC 44
> +#define HI6220_UART4_SRC 45
> +#define HI6220_MMC0_MUX0 46
> +#define HI6220_MMC1_MUX0 47
> +#define HI6220_MMC2_MUX0 48
> +#define HI6220_MMC0_MUX1 49
> +#define HI6220_MMC1_MUX1 50
> +#define HI6220_MMC2_MUX1 51
> +
> +/* divider clocks */
> +#define HI6220_CLK_BUS 54
> +#define HI6220_MMC0_DIV 55
> +#define HI6220_MMC1_DIV 56
> +#define HI6220_MMC2_DIV 57
> +#define HI6220_HIFI_DIV 58
> +#define HI6220_BBPPLL0_DIV 59
> +#define HI6220_CS_DAPB 60
> +#define HI6220_CS_ATB_DIV 61
> +
> +#define HI6220_SYS_NR_CLKS 64
> +
> +/* clk in media controller */
> +/* gate clocks */
> +#define HI6220_DSI_PCLK 1
> +#define HI6220_G3D_PCLK 2
> +#define HI6220_ACLK_CODEC_VPU 3
> +#define HI6220_ISP_SCLK 4
> +#define HI6220_ADE_CORE 5
> +#define HI6220_MED_MMU 6
> +#define HI6220_CFG_CSI4PHY 7
> +#define HI6220_CFG_CSI2PHY 8
> +#define HI6220_ISP_SCLK_GATE 9
> +#define HI6220_ISP_SCLK_GATE1 10
> +#define HI6220_ADE_CORE_GATE 11
> +#define HI6220_CODEC_VPU_GATE 12
> +#define HI6220_MED_SYSPLL 13
> +
> +/* mux clocks */
> +#define HI6220_1440_1200 20
> +#define HI6220_1000_1200 21
> +#define HI6220_1000_1440 22
> +
> +/* divider clocks */
> +#define HI6220_CODEC_JPEG 30
> +#define HI6220_ISP_SCLK_SRC 31
> +#define HI6220_ISP_SCLK1 32
> +#define HI6220_ADE_CORE_SRC 33
> +#define HI6220_ADE_PIX_SRC 34
> +#define HI6220_G3D_CLK 35
> +#define HI6220_CODEC_VPU_SRC 36
> +
> +#define HI6220_MEDIA_NR_CLKS 40
> +
> +/* clk in power controller */
> +/* gate clocks */
> +#define HI6220_PLL_GPU_GATE 1
> +#define HI6220_PLL1_DDR_GATE 2
> +#define HI6220_PLL_DDR_GATE 3
> +#define HI6220_PLL_MEDIA_GATE 4
> +#define HI6220_PLL0_BBP_GATE 5
> +
> +/* divider clocks */
> +#define HI6220_DDRC_SRC 10
> +#define HI6220_DDRC_AXI1 11
> +
> +#define HI6220_POWER_NR_CLKS 16
> +#endif
> --
> 1.7.9.5
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Cheers,

- Tyler

[1] http://kernelci.org/build/tbaker/kernel/v3.19-rc7-8241-g7b08f7b75c01/

2015-02-07 02:05:52

by Brent Wang

[permalink] [raw]
Subject: Re: [PATCH 2/3] clk: hi6220: Clock driver support for Hisilicon hi6220 SoC

Hello Tyler,

Thank you very much for helping test this patchset!

2015-02-07 2:10 GMT+08:00 Tyler Baker <[email protected]>:
> Hi Bintian,
>
> This patch applied to next-20150204 is producing build failures on
> various ARM defconfigs[1]. I received the following error in all
> cases:
>
> drivers/built-in.o: In function `hi6220_clk_register_divider':
> :(.init.text+0x1a84c): undefined reference to `hi6220_register_clkdiv'
> Makefile:925: recipe for target 'vmlinux' failed
> make: *** [vmlinux] Error 1
It's my fault, I just test on ARM64, The following patch can fix this error:
=====================
diff --git a/drivers/clk/hisilicon/Makefile b/drivers/clk/hisilicon/Makefile
index bbf0539..48f0116 100644
--- a/drivers/clk/hisilicon/Makefile
+++ b/drivers/clk/hisilicon/Makefile
@@ -2,9 +2,9 @@
# Hisilicon Clock specific Makefile
#

-obj-y += clk.o clkgate-separated.o
+obj-y += clk.o clkgate-separated.o clkdivider-hi6220.o

obj-$(CONFIG_ARCH_HI3xxx) += clk-hi3620.o
obj-$(CONFIG_ARCH_HIP04) += clk-hip04.o
obj-$(CONFIG_ARCH_HIX5HD2) += clk-hix5hd2.o
-obj-$(CONFIG_COMMON_CLK_HI6220) += clkdivider-hi6220.o clk-hi6220.o
+obj-$(CONFIG_COMMON_CLK_HI6220) += clk-hi6220.o
======================

I will fix this problem in next version.

Thanks,

Bintian


>
> On 5 February 2015 at 01:24, Bintian Wang <[email protected]> wrote:
>> Add clock drivers for hi6220 SoC, this driver controls the SoC
>> registers to supply different clocks to different IPs in the SoC.
>>
>> We add one divider clock for hi6220 because the divider in hi6220
>> also has a mask bit but it doesnot obey the rule defined by flag
>> "CLK_DIVIDER_HIWORD_MASK", we can not get index of the mask bit by
>> left shift fixed bits (e.g. 16 bits), so we add this divider clock
>> to handle it.
>>
>> This patch also enables this clock driver for ARCH_HISI and document
>> devicetree bindings.
>>
>> Signed-off-by: Bintian Wang <[email protected]>
>> Reviewed-by: Haojian Zhuang <[email protected]>
>> Reviewed-by: Zhangfei Gao <[email protected]>
>> ---
>> .../devicetree/bindings/clock/hi6220-clock.txt | 30 +++
>> arch/arm64/Kconfig | 1 +
>> drivers/clk/Kconfig | 2 +
>> drivers/clk/Makefile | 4 +-
>> drivers/clk/hisilicon/Kconfig | 5 +
>> drivers/clk/hisilicon/Makefile | 1 +
>> drivers/clk/hisilicon/clk-hi6220.c | 284 ++++++++++++++++++++
>> drivers/clk/hisilicon/clk.c | 29 ++
>> drivers/clk/hisilicon/clk.h | 17 ++
>> drivers/clk/hisilicon/clkdivider-hi6220.c | 273 +++++++++++++++++++
>> include/dt-bindings/clock/hi6220-clock.h | 172 ++++++++++++
>> 11 files changed, 815 insertions(+), 3 deletions(-)
>> create mode 100644 Documentation/devicetree/bindings/clock/hi6220-clock.txt
>> create mode 100644 drivers/clk/hisilicon/Kconfig
>> create mode 100644 drivers/clk/hisilicon/clk-hi6220.c
>> create mode 100644 drivers/clk/hisilicon/clkdivider-hi6220.c
>> create mode 100644 include/dt-bindings/clock/hi6220-clock.h
>>
>> diff --git a/Documentation/devicetree/bindings/clock/hi6220-clock.txt b/Documentation/devicetree/bindings/clock/hi6220-clock.txt
>> new file mode 100644
>> index 0000000..a3ddda1
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/clock/hi6220-clock.txt
>> @@ -0,0 +1,30 @@
>> +* Hisilicon Hi6220 Clock Controller
>> +
>> +The hi6220 clock controller generates and supplies clock to various
>> +controllers within the hi6220 SoC.
>> +
>> +Required Properties:
>> +
>> +- compatible: should be one of the following:
>> + - "hisilicon,hi6220-clock-ao" - controller for those clocks under SoC
>> + power always on(AO) domain, it is the sub node of SoC power AO
>> + controller in dts file.
>> + - "hisilicon,hi6220-clock-sys" - controller for those clocks under SoC
>> + system control domain, it is the sub node of SoC system controller
>> + in dts file.
>> + - "hisilicon,hi6220-clock-media" - controller for those clocks under
>> + SoC media control domain, it is the sub node of SoC media controller
>> + in dts file.
>> + - "hisilicon,hi6220-clock-power" - controller for those clocks under
>> + SoC power control domain, it is the sub node of SoC power controller
>> + in dts file.
>> +
>> +- reg: physical base address of the controller and length of memory mapped
>> + region.
>> +
>> +- #clock-cells: should be 1.
>> +
>> +Each clock is assigned an identifier and client nodes use this identifier
>> +to specify the clock which they consume.
>> +
>> +All these identifier could be found in <dt-bindings/clock/hi6220-clock.h>.
>> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
>> index 78cd41c8..6efc3e3 100644
>> --- a/arch/arm64/Kconfig
>> +++ b/arch/arm64/Kconfig
>> @@ -175,6 +175,7 @@ config ARCH_XGENE
>>
>> config ARCH_HISI
>> bool "Hisilicon SoC Family"
>> + select COMMON_CLK_HI6220
>> help
>> This enables support for Hisilicon ARMv8 Family of SoCs.
>>
>> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
>> index 3f44f29..b52c95c 100644
>> --- a/drivers/clk/Kconfig
>> +++ b/drivers/clk/Kconfig
>> @@ -136,6 +136,8 @@ config COMMON_CLK_PXA
>>
>> source "drivers/clk/qcom/Kconfig"
>>
>> +source "drivers/clk/hisilicon/Kconfig"
>> +
>> endmenu
>>
>> source "drivers/clk/bcm/Kconfig"
>> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
>> index d5fba5b..c58703b 100644
>> --- a/drivers/clk/Makefile
>> +++ b/drivers/clk/Makefile
>> @@ -43,9 +43,7 @@ obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o
>> obj-$(CONFIG_COMMON_CLK_AT91) += at91/
>> obj-$(CONFIG_ARCH_BCM_MOBILE) += bcm/
>> obj-$(CONFIG_ARCH_BERLIN) += berlin/
>> -obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/
>> -obj-$(CONFIG_ARCH_HIP04) += hisilicon/
>> -obj-$(CONFIG_ARCH_HIX5HD2) += hisilicon/
>> +obj-$(CONFIG_ARCH_HISI) += hisilicon/
>> obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/
>> ifeq ($(CONFIG_COMMON_CLK), y)
>> obj-$(CONFIG_ARCH_MMP) += mmp/
>> diff --git a/drivers/clk/hisilicon/Kconfig b/drivers/clk/hisilicon/Kconfig
>> new file mode 100644
>> index 0000000..e3ead46
>> --- /dev/null
>> +++ b/drivers/clk/hisilicon/Kconfig
>> @@ -0,0 +1,5 @@
>> +config COMMON_CLK_HI6220
>> + tristate "Hi6220 Clock Driver"
>> + depends on OF && ARCH_HISI
>> + help
>> + Build the Hisilicon Hi6220 clock driver based on the common clock framework.
>> diff --git a/drivers/clk/hisilicon/Makefile b/drivers/clk/hisilicon/Makefile
>> index 038c02f..bbf0539 100644
>> --- a/drivers/clk/hisilicon/Makefile
>> +++ b/drivers/clk/hisilicon/Makefile
>> @@ -7,3 +7,4 @@ obj-y += clk.o clkgate-separated.o
>> obj-$(CONFIG_ARCH_HI3xxx) += clk-hi3620.o
>> obj-$(CONFIG_ARCH_HIP04) += clk-hip04.o
>> obj-$(CONFIG_ARCH_HIX5HD2) += clk-hix5hd2.o
>> +obj-$(CONFIG_COMMON_CLK_HI6220) += clkdivider-hi6220.o clk-hi6220.o
>> diff --git a/drivers/clk/hisilicon/clk-hi6220.c b/drivers/clk/hisilicon/clk-hi6220.c
>> new file mode 100644
>> index 0000000..01d0c46
>> --- /dev/null
>> +++ b/drivers/clk/hisilicon/clk-hi6220.c
>> @@ -0,0 +1,284 @@
>> +/*
>> + * Hisilicon Hi6220 clock driver
>> + *
>> + * Copyright (c) 2015 Hisilicon Limited.
>> + *
>> + * Author: Bintian Wang <[email protected]>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/clk-provider.h>
>> +#include <linux/clkdev.h>
>> +#include <linux/io.h>
>> +#include <linux/of.h>
>> +#include <linux/of_address.h>
>> +#include <linux/of_device.h>
>> +#include <linux/slab.h>
>> +#include <linux/clk.h>
>> +
>> +#include <dt-bindings/clock/hi6220-clock.h>
>> +
>> +#include "clk.h"
>> +
>> +
>> +/* clocks in AO (always on) controller */
>> +static struct hisi_fixed_rate_clock hi6220_fixed_rate_clks[] __initdata = {
>> + { HI6220_REF32K, "ref32k", NULL, CLK_IS_ROOT, 32764, },
>> + { HI6220_CLK_TCXO, "clk_tcxo", NULL, CLK_IS_ROOT, 19200000, },
>> + { HI6220_MMC1_PAD, "mmc1_pad", NULL, CLK_IS_ROOT, 100000000, },
>> + { HI6220_MMC2_PAD, "mmc2_pad", NULL, CLK_IS_ROOT, 100000000, },
>> + { HI6220_MMC0_PAD, "mmc0_pad", NULL, CLK_IS_ROOT, 200000000, },
>> + { HI6220_PLL_BBP, "bbppll0", NULL, CLK_IS_ROOT, 245760000, },
>> + { HI6220_PLL_GPU, "gpupll", NULL, CLK_IS_ROOT, 1000000000,},
>> + { HI6220_PLL1_DDR, "ddrpll1", NULL, CLK_IS_ROOT, 1066000000,},
>> + { HI6220_PLL_SYS, "syspll", NULL, CLK_IS_ROOT, 1200000000,},
>> + { HI6220_PLL_SYS_MEDIA, "media_syspll", NULL, CLK_IS_ROOT, 1200000000,},
>> + { HI6220_DDR_SRC, "ddr_sel_src", NULL, CLK_IS_ROOT, 1200000000,},
>> + { HI6220_PLL_MEDIA, "media_pll", NULL, CLK_IS_ROOT, 1440000000,},
>> + { HI6220_PLL_DDR, "ddrpll0", NULL, CLK_IS_ROOT, 1600000000,},
>> +};
>> +
>> +static struct hisi_fixed_factor_clock hi6220_fixed_factor_clks[] __initdata = {
>> + { HI6220_300M, "clk_300m", "syspll", 1, 4, 0, },
>> + { HI6220_150M, "clk_150m", "clk_300m", 1, 2, 0, },
>> + { HI6220_PICOPHY_SRC, "picophy_src", "clk_150m", 1, 4, 0, },
>> + { HI6220_MMC0_SRC_SEL, "mmc0srcsel", "mmc0_sel", 1, 8, 0, },
>> + { HI6220_MMC1_SRC_SEL, "mmc1srcsel", "mmc1_sel", 1, 8, 0, },
>> + { HI6220_MMC2_SRC_SEL, "mmc2srcsel", "mmc2_sel", 1, 8, 0, },
>> + { HI6220_VPU_CODEC, "vpucodec", "codec_jpeg_aclk", 1, 2, 0, },
>> + { HI6220_MMC0_SMP, "mmc0_sample", "mmc0_sel", 1, 8, 0, },
>> + { HI6220_MMC1_SMP, "mmc1_sample", "mmc1_sel", 1, 8, 0, },
>> + { HI6220_MMC2_SMP, "mmc2_sample", "mmc2_sel", 1, 8, 0, },
>> +};
>> +
>> +static struct hisi_gate_clock hi6220_separated_gate_clks_ao[] __initdata = {
>> + { HI6220_WDT0_PCLK, "wdt0_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 12, 0, },
>> + { HI6220_WDT1_PCLK, "wdt1_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 13, 0, },
>> + { HI6220_WDT2_PCLK, "wdt2_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 14, 0, },
>> + { HI6220_TIMER0_PCLK, "timer0_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 15, 0, },
>> + { HI6220_TIMER1_PCLK, "timer1_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 16, 0, },
>> + { HI6220_TIMER2_PCLK, "timer2_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 17, 0, },
>> + { HI6220_TIMER3_PCLK, "timer3_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 18, 0, },
>> + { HI6220_TIMER4_PCLK, "timer4_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 19, 0, },
>> + { HI6220_TIMER5_PCLK, "timer5_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 20, 0, },
>> + { HI6220_TIMER6_PCLK, "timer6_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 21, 0, },
>> + { HI6220_TIMER7_PCLK, "timer7_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 22, 0, },
>> + { HI6220_TIMER8_PCLK, "timer8_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 23, 0, },
>> + { HI6220_UART0_PCLK, "uart0_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 24, 0, },
>> +};
>> +
>> +static void __init hi6220_clk_ao_init(struct device_node *np)
>> +{
>> + struct hisi_clock_data *clk_data;
>> +
>> + clk_data = hisi_clk_init(np, HI6220_AO_NR_CLKS);
>> + if (!clk_data)
>> + return;
>> +
>> + hisi_clk_register_fixed_rate(hi6220_fixed_rate_clks,
>> + ARRAY_SIZE(hi6220_fixed_rate_clks), clk_data);
>> +
>> + hisi_clk_register_fixed_factor(hi6220_fixed_factor_clks,
>> + ARRAY_SIZE(hi6220_fixed_factor_clks), clk_data);
>> +
>> + hisi_clk_register_gate_sep(hi6220_separated_gate_clks_ao,
>> + ARRAY_SIZE(hi6220_separated_gate_clks_ao), clk_data);
>> +}
>> +CLK_OF_DECLARE(hi6220_clk_ao, "hisilicon,hi6220-clock-ao", hi6220_clk_ao_init);
>> +
>> +
>> +/* clocks in sysctrl */
>> +static const char *mmc0_mux0_p[] __initconst = { "pll_ddr_gate", "syspll", };
>> +static const char *mmc0_mux1_p[] __initconst = { "mmc0_mux0", "pll_media_gate", };
>> +static const char *mmc0_src_p[] __initconst = { "mmc0srcsel", "mmc0_div", };
>> +static const char *mmc1_mux0_p[] __initconst = { "pll_ddr_gate", "syspll", };
>> +static const char *mmc1_mux1_p[] __initconst = { "mmc1_mux0", "pll_media_gate", };
>> +static const char *mmc1_src_p[] __initconst = { "mmc1srcsel", "mmc1_div", };
>> +static const char *mmc2_mux0_p[] __initconst = { "pll_ddr_gate", "syspll", };
>> +static const char *mmc2_mux1_p[] __initconst = { "mmc2_mux0", "pll_media_gate", };
>> +static const char *mmc2_src_p[] __initconst = { "mmc2srcsel", "mmc2_div", };
>> +static const char *mmc0_sample_in[] __initconst = { "mmc0_sample", "mmc0_pad", };
>> +static const char *mmc1_sample_in[] __initconst = { "mmc1_sample", "mmc1_pad", };
>> +static const char *mmc2_sample_in[] __initconst = { "mmc2_sample", "mmc2_pad", };
>> +static const char *uart1_src[] __initconst = { "clk_tcxo", "clk_150m", };
>> +static const char *uart2_src[] __initconst = { "clk_tcxo", "clk_150m", };
>> +static const char *uart3_src[] __initconst = { "clk_tcxo", "clk_150m", };
>> +static const char *uart4_src[] __initconst = { "clk_tcxo", "clk_150m", };
>> +static const char *hifi_src[] __initconst = { "syspll", "pll_media_gate", };
>> +
>> +static struct hisi_gate_clock hi6220_separated_gate_clks_sys[] __initdata = {
>> + { HI6220_MMC0_CLK, "mmc0_clk", "mmc0_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 0, 0, },
>> + { HI6220_MMC0_CIUCLK, "mmc0_ciuclk", "mmc0_smp_in", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 0, 0, },
>> + { HI6220_MMC1_CLK, "mmc1_clk", "mmc1_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 1, 0, },
>> + { HI6220_MMC1_CIUCLK, "mmc1_ciuclk", "mmc1_smp_in", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 1, 0, },
>> + { HI6220_MMC2_CLK, "mmc2_clk", "mmc2_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 2, 0, },
>> + { HI6220_MMC2_CIUCLK, "mmc2_ciuclk", "mmc2_smp_in", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 2, 0, },
>> + { HI6220_USBOTG_HCLK, "usbotg_hclk", "clk_bus", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 4, 0, },
>> + { HI6220_CLK_PICOPHY, "clk_picophy", "cs_dapb", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 5, 0, },
>> + { HI6220_HIFI, "hifi_clk", "hifi_div", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x210, 0, 0, },
>> + { HI6220_DACODEC_PCLK, "dacodec_pclk", "clk_bus", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x210, 5, 0, },
>> + { HI6220_EDMAC_ACLK, "edmac_aclk", "clk_bus", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x220, 2, 0, },
>> + { HI6220_CS_ATB, "cs_atb", "cs_atb_div", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 0, 0, },
>> + { HI6220_I2C0_CLK, "i2c0_clk", "clk_150m", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 1, 0, },
>> + { HI6220_I2C1_CLK, "i2c1_clk", "clk_150m", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 2, 0, },
>> + { HI6220_I2C2_CLK, "i2c2_clk", "clk_150m", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 3, 0, },
>> + { HI6220_I2C3_CLK, "i2c3_clk", "clk_150m", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 4, 0, },
>> + { HI6220_UART1_PCLK, "uart1_pclk", "uart1_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 5, 0, },
>> + { HI6220_UART2_PCLK, "uart2_pclk", "uart2_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 6, 0, },
>> + { HI6220_UART3_PCLK, "uart3_pclk", "uart3_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 7, 0, },
>> + { HI6220_UART4_PCLK, "uart4_pclk", "uart4_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 8, 0, },
>> + { HI6220_SPI_CLK, "spi_clk", "clk_150m", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 9, 0, },
>> + { HI6220_MMU_CLK, "mmu_clk", "ddrc_axi1", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x240, 11, 0, },
>> + { HI6220_HIFI_SEL, "hifi_sel", "hifi_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 0, 0, },
>> + { HI6220_MMC0_SYSPLL, "mmc0_syspll", "syspll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 1, 0, },
>> + { HI6220_MMC1_SYSPLL, "mmc1_syspll", "syspll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 2, 0, },
>> + { HI6220_MMC2_SYSPLL, "mmc2_syspll", "syspll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 3, 0, },
>> + { HI6220_MMC0_SEL, "mmc0_sel", "mmc0_mux1", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 6, 0, },
>> + { HI6220_MMC1_SEL, "mmc1_sel", "mmc1_mux1", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 7, 0, },
>> + { HI6220_BBPPLL_SEL, "bbppll_sel", "pll0_bbp_gate", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 9, 0, },
>> + { HI6220_MEDIA_PLL_SRC, "media_pll_src", "pll_media_gate", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 10, 0, },
>> + { HI6220_MMC2_SEL, "mmc2_sel", "mmc2_mux1", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 11, 0, },
>> + { HI6220_CS_ATB_SYSPLL, "cs_atb_syspll", "syspll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 12, 0, },
>> +};
>> +
>> +static struct hisi_mux_clock hi6220_mux_clks_sys[] __initdata = {
>> + { HI6220_MMC0_SRC, "mmc0_src", mmc0_src_p, ARRAY_SIZE(mmc0_src_p), CLK_SET_RATE_PARENT, 0x4, 0, 1, 0, },
>> + { HI6220_MMC0_SMP_IN, "mmc0_smp_in", mmc0_sample_in, ARRAY_SIZE(mmc0_sample_in), CLK_SET_RATE_PARENT, 0x4, 0, 1, 0, },
>> + { HI6220_MMC1_SRC, "mmc1_src", mmc1_src_p, ARRAY_SIZE(mmc1_src_p), CLK_SET_RATE_PARENT, 0x4, 2, 1, 0, },
>> + { HI6220_MMC1_SMP_IN, "mmc1_smp_in", mmc1_sample_in, ARRAY_SIZE(mmc1_sample_in), CLK_SET_RATE_PARENT, 0x4, 2, 1, 0, },
>> + { HI6220_MMC2_SRC, "mmc2_src", mmc2_src_p, ARRAY_SIZE(mmc2_src_p), CLK_SET_RATE_PARENT, 0x4, 4, 1, 0, },
>> + { HI6220_MMC2_SMP_IN, "mmc2_smp_in", mmc2_sample_in, ARRAY_SIZE(mmc2_sample_in), CLK_SET_RATE_PARENT, 0x4, 4, 1, 0, },
>> + { HI6220_HIFI_SRC, "hifi_src", hifi_src, ARRAY_SIZE(hifi_src), CLK_SET_RATE_PARENT, 0x400, 0, 1, CLK_MUX_HIWORD_MASK,},
>> + { HI6220_UART1_SRC, "uart1_src", uart1_src, ARRAY_SIZE(uart1_src), CLK_SET_RATE_PARENT, 0x400, 1, 1, CLK_MUX_HIWORD_MASK,},
>> + { HI6220_UART2_SRC, "uart2_src", uart2_src, ARRAY_SIZE(uart2_src), CLK_SET_RATE_PARENT, 0x400, 2, 1, CLK_MUX_HIWORD_MASK,},
>> + { HI6220_UART3_SRC, "uart3_src", uart3_src, ARRAY_SIZE(uart3_src), CLK_SET_RATE_PARENT, 0x400, 3, 1, CLK_MUX_HIWORD_MASK,},
>> + { HI6220_UART4_SRC, "uart4_src", uart4_src, ARRAY_SIZE(uart4_src), CLK_SET_RATE_PARENT, 0x400, 4, 1, CLK_MUX_HIWORD_MASK,},
>> + { HI6220_MMC0_MUX0, "mmc0_mux0", mmc0_mux0_p, ARRAY_SIZE(mmc0_mux0_p), CLK_SET_RATE_PARENT, 0x400, 5, 1, CLK_MUX_HIWORD_MASK,},
>> + { HI6220_MMC1_MUX0, "mmc1_mux0", mmc1_mux0_p, ARRAY_SIZE(mmc1_mux0_p), CLK_SET_RATE_PARENT, 0x400, 11, 1, CLK_MUX_HIWORD_MASK,},
>> + { HI6220_MMC2_MUX0, "mmc2_mux0", mmc2_mux0_p, ARRAY_SIZE(mmc2_mux0_p), CLK_SET_RATE_PARENT, 0x400, 12, 1, CLK_MUX_HIWORD_MASK,},
>> + { HI6220_MMC0_MUX1, "mmc0_mux1", mmc0_mux1_p, ARRAY_SIZE(mmc0_mux1_p), CLK_SET_RATE_PARENT, 0x400, 13, 1, CLK_MUX_HIWORD_MASK,},
>> + { HI6220_MMC1_MUX1, "mmc1_mux1", mmc1_mux1_p, ARRAY_SIZE(mmc1_mux1_p), CLK_SET_RATE_PARENT, 0x400, 14, 1, CLK_MUX_HIWORD_MASK,},
>> + { HI6220_MMC2_MUX1, "mmc2_mux1", mmc2_mux1_p, ARRAY_SIZE(mmc2_mux1_p), CLK_SET_RATE_PARENT, 0x400, 15, 1, CLK_MUX_HIWORD_MASK,},
>> +};
>> +
>> +static struct hi6220_divider_clock hi6220_div_clks_sys[] __initdata = {
>> + { HI6220_CLK_BUS, "clk_bus", "clk_300m", CLK_SET_RATE_PARENT, 0x490, 0, 4, 7, },
>> + { HI6220_MMC0_DIV, "mmc0_div", "mmc0_syspll", CLK_SET_RATE_PARENT, 0x494, 0, 6, 7, },
>> + { HI6220_MMC1_DIV, "mmc1_div", "mmc1_syspll", CLK_SET_RATE_PARENT, 0x498, 0, 6, 7, },
>> + { HI6220_MMC2_DIV, "mmc2_div", "mmc2_syspll", CLK_SET_RATE_PARENT, 0x49c, 0, 6, 7, },
>> + { HI6220_HIFI_DIV, "hifi_div", "hifi_sel", CLK_SET_RATE_PARENT, 0x4a0, 0, 4, 7, },
>> + { HI6220_BBPPLL0_DIV, "bbppll0_div", "bbppll_sel", CLK_SET_RATE_PARENT, 0x4a0, 8, 6, 15,},
>> + { HI6220_CS_DAPB, "cs_dapb", "picophy_src", CLK_SET_RATE_PARENT, 0x4a0, 24, 2, 31,},
>> + { HI6220_CS_ATB_DIV, "cs_atb_div", "cs_atb_syspll", CLK_SET_RATE_PARENT, 0x4a4, 0, 4, 7, },
>> +};
>> +
>> +static void __init hi6220_clk_sys_init(struct device_node *np)
>> +{
>> + struct hisi_clock_data *clk_data;
>> +
>> + clk_data = hisi_clk_init(np, HI6220_SYS_NR_CLKS);
>> + if (!clk_data)
>> + return;
>> +
>> + hisi_clk_register_gate_sep(hi6220_separated_gate_clks_sys,
>> + ARRAY_SIZE(hi6220_separated_gate_clks_sys), clk_data);
>> +
>> + hisi_clk_register_mux(hi6220_mux_clks_sys,
>> + ARRAY_SIZE(hi6220_mux_clks_sys), clk_data);
>> +
>> + hi6220_clk_register_divider(hi6220_div_clks_sys,
>> + ARRAY_SIZE(hi6220_div_clks_sys), clk_data);
>> +}
>> +CLK_OF_DECLARE(hi6220_clk_sys, "hisilicon,hi6220-clock-sys", hi6220_clk_sys_init);
>> +
>> +
>> +/* clocks in media controller */
>> +static const char *clk_1000_1200_src[] __initconst = { "pll_gpu_gate", "media_syspll_src", };
>> +static const char *clk_1440_1200_src[] __initconst = { "media_syspll_src", "media_pll_src", };
>> +static const char *clk_1000_1440_src[] __initconst = { "pll_gpu_gate", "media_pll_src", };
>> +
>> +static struct hisi_gate_clock hi6220_separated_gate_clks_media[] __initdata = {
>> + { HI6220_DSI_PCLK, "dsi_pclk", "vpucodec", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 0, 0, },
>> + { HI6220_G3D_PCLK, "g3d_pclk", "vpucodec", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 1, 0, },
>> + { HI6220_ACLK_CODEC_VPU, "aclk_codec_vpu", "ade_core_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 3, 0, },
>> + { HI6220_ISP_SCLK, "isp_sclk", "isp_sclk_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 5, 0, },
>> + { HI6220_ADE_CORE, "ade_core", "ade_core_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 6, 0, },
>> + { HI6220_MED_MMU, "media_mmu", "mmu_clk", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 8, 0, },
>> + { HI6220_CFG_CSI4PHY, "cfg_csi4phy", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 9, 0, },
>> + { HI6220_CFG_CSI2PHY, "cfg_csi2phy", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 10, 0, },
>> + { HI6220_ISP_SCLK_GATE, "isp_sclk_gate", "media_pll_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 11, 0, },
>> + { HI6220_ISP_SCLK_GATE1, "isp_sclk_gate1", "media_pll_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 12, 0, },
>> + { HI6220_ADE_CORE_GATE, "ade_core_gate", "media_pll_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 14, 0, },
>> + { HI6220_CODEC_VPU_GATE, "codec_vpu_gate", "clk_1000_1440", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 15, 0, },
>> + { HI6220_MED_SYSPLL, "media_syspll_src", "media_syspll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 17, 0, },
>> +};
>> +
>> +static struct hisi_mux_clock hi6220_mux_clks_media[] __initdata = {
>> + { HI6220_1440_1200, "clk_1440_1200", clk_1440_1200_src, ARRAY_SIZE(clk_1440_1200_src), CLK_SET_RATE_PARENT, 0x51c, 0, 1, 0, },
>> + { HI6220_1000_1200, "clk_1000_1200", clk_1000_1200_src, ARRAY_SIZE(clk_1000_1200_src), CLK_SET_RATE_PARENT, 0x51c, 1, 1, 0, },
>> + { HI6220_1000_1440, "clk_1000_1440", clk_1000_1440_src, ARRAY_SIZE(clk_1000_1440_src), CLK_SET_RATE_PARENT, 0x51c, 6, 1, 0, },
>> +};
>> +
>> +static struct hi6220_divider_clock hi6220_div_clks_media[] __initdata = {
>> + { HI6220_CODEC_JPEG, "codec_jpeg_aclk", "media_pll_src", CLK_SET_RATE_PARENT, 0xcbc, 0, 4, 23, },
>> + { HI6220_ISP_SCLK_SRC, "isp_sclk_src", "isp_sclk_gate", CLK_SET_RATE_PARENT, 0xcbc, 8, 4, 15, },
>> + { HI6220_ISP_SCLK1, "isp_sclk1", "isp_sclk_gate1", CLK_SET_RATE_PARENT, 0xcbc, 24, 4, 31, },
>> + { HI6220_ADE_CORE_SRC, "ade_core_src", "ade_core_gate", CLK_SET_RATE_PARENT, 0xcc0, 16, 3, 23, },
>> + { HI6220_ADE_PIX_SRC, "ade_pix_src", "clk_1440_1200", CLK_SET_RATE_PARENT, 0xcc0, 24, 6, 31, },
>> + { HI6220_G3D_CLK, "g3d_clk", "clk_1000_1200", CLK_SET_RATE_PARENT, 0xcc4, 8, 4, 15, },
>> + { HI6220_CODEC_VPU_SRC, "codec_vpu_src", "codec_vpu_gate", CLK_SET_RATE_PARENT, 0xcc4, 24, 6, 31, },
>> +};
>> +
>> +static void __init hi6220_clk_media_init(struct device_node *np)
>> +{
>> + struct hisi_clock_data *clk_data;
>> +
>> + clk_data = hisi_clk_init(np, HI6220_MEDIA_NR_CLKS);
>> + if (!clk_data)
>> + return;
>> +
>> + hisi_clk_register_gate_sep(hi6220_separated_gate_clks_media,
>> + ARRAY_SIZE(hi6220_separated_gate_clks_media), clk_data);
>> +
>> + hisi_clk_register_mux(hi6220_mux_clks_media,
>> + ARRAY_SIZE(hi6220_mux_clks_media), clk_data);
>> +
>> + hi6220_clk_register_divider(hi6220_div_clks_media,
>> + ARRAY_SIZE(hi6220_div_clks_media), clk_data);
>> +}
>> +CLK_OF_DECLARE(hi6220_clk_media, "hisilicon,hi6220-clock-media", hi6220_clk_media_init);
>> +
>> +
>> +/* clocks in pmctrl */
>> +static struct hisi_gate_clock hi6220_gate_clks_power[] __initdata = {
>> + { HI6220_PLL_GPU_GATE, "pll_gpu_gate", "gpupll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x8, 0, 0, },
>> + { HI6220_PLL1_DDR_GATE, "pll1_ddr_gate", "ddrpll1", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x10, 0, 0, },
>> + { HI6220_PLL_DDR_GATE, "pll_ddr_gate", "ddrpll0", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x18, 0, 0, },
>> + { HI6220_PLL_MEDIA_GATE, "pll_media_gate", "media_pll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x38, 0, 0, },
>> + { HI6220_PLL0_BBP_GATE, "pll0_bbp_gate", "bbppll0", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x48, 0, 0, },
>> +};
>> +
>> +static struct hi6220_divider_clock hi6220_div_clks_power[] __initdata = {
>> + { HI6220_DDRC_SRC, "ddrc_src", "ddr_sel_src", CLK_SET_RATE_PARENT, 0x5a8, 0, 4, 0, },
>> + { HI6220_DDRC_AXI1, "ddrc_axi1", "ddrc_src", CLK_SET_RATE_PARENT, 0x5a8, 8, 2, 0, },
>> +};
>> +
>> +static void __init hi6220_clk_power_init(struct device_node *np)
>> +{
>> + struct hisi_clock_data *clk_data;
>> +
>> + clk_data = hisi_clk_init(np, HI6220_POWER_NR_CLKS);
>> + if (!clk_data)
>> + return;
>> +
>> + hisi_clk_register_gate(hi6220_gate_clks_power,
>> + ARRAY_SIZE(hi6220_gate_clks_power), clk_data);
>> +
>> + hi6220_clk_register_divider(hi6220_div_clks_power,
>> + ARRAY_SIZE(hi6220_div_clks_power), clk_data);
>> +}
>> +CLK_OF_DECLARE(hi6220_clk_power, "hisilicon,hi6220-clock-power", hi6220_clk_power_init);
>> diff --git a/drivers/clk/hisilicon/clk.c b/drivers/clk/hisilicon/clk.c
>> index a078e84..5d2305c 100644
>> --- a/drivers/clk/hisilicon/clk.c
>> +++ b/drivers/clk/hisilicon/clk.c
>> @@ -232,3 +232,32 @@ void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *clks,
>> data->clk_data.clks[clks[i].id] = clk;
>> }
>> }
>> +
>> +void __init hi6220_clk_register_divider(struct hi6220_divider_clock *clks,
>> + int nums, struct hisi_clock_data *data)
>> +{
>> + struct clk *clk;
>> + void __iomem *base = data->base;
>> + int i;
>> +
>> + for (i = 0; i < nums; i++) {
>> + clk = hi6220_register_clkdiv(NULL, clks[i].name,
>> + clks[i].parent_name,
>> + clks[i].flags,
>> + base + clks[i].offset,
>> + clks[i].shift,
>> + clks[i].width,
>> + clks[i].mask_bit,
>> + &hisi_clk_lock);
>> + if (IS_ERR(clk)) {
>> + pr_err("%s: failed to register clock %s\n",
>> + __func__, clks[i].name);
>> + continue;
>> + }
>> +
>> + if (clks[i].alias)
>> + clk_register_clkdev(clk, clks[i].alias, NULL);
>> +
>> + data->clk_data.clks[clks[i].id] = clk;
>> + }
>> +}
>> diff --git a/drivers/clk/hisilicon/clk.h b/drivers/clk/hisilicon/clk.h
>> index 31083ff..462a570 100644
>> --- a/drivers/clk/hisilicon/clk.h
>> +++ b/drivers/clk/hisilicon/clk.h
>> @@ -79,6 +79,18 @@ struct hisi_divider_clock {
>> const char *alias;
>> };
>>
>> +struct hi6220_divider_clock {
>> + unsigned int id;
>> + const char *name;
>> + const char *parent_name;
>> + unsigned long flags;
>> + unsigned long offset;
>> + u8 shift;
>> + u8 width;
>> + u32 mask_bit;
>> + const char *alias;
>> +};
>> +
>> struct hisi_gate_clock {
>> unsigned int id;
>> const char *name;
>> @@ -94,6 +106,9 @@ struct clk *hisi_register_clkgate_sep(struct device *, const char *,
>> const char *, unsigned long,
>> void __iomem *, u8,
>> u8, spinlock_t *);
>> +struct clk *hi6220_register_clkdiv(struct device *dev, const char *name,
>> + const char *parent_name, unsigned long flags, void __iomem *reg,
>> + u8 shift, u8 width, u32 mask_bit, spinlock_t *lock);
>>
>> struct hisi_clock_data __init *hisi_clk_init(struct device_node *, int);
>> void __init hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *,
>> @@ -108,4 +123,6 @@ void __init hisi_clk_register_gate(struct hisi_gate_clock *,
>> int, struct hisi_clock_data *);
>> void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *,
>> int, struct hisi_clock_data *);
>> +void __init hi6220_clk_register_divider(struct hi6220_divider_clock *,
>> + int, struct hisi_clock_data *);
>> #endif /* __HISI_CLK_H */
>> diff --git a/drivers/clk/hisilicon/clkdivider-hi6220.c b/drivers/clk/hisilicon/clkdivider-hi6220.c
>> new file mode 100644
>> index 0000000..9e3825b
>> --- /dev/null
>> +++ b/drivers/clk/hisilicon/clkdivider-hi6220.c
>> @@ -0,0 +1,273 @@
>> +/*
>> + * Hisilicon hi6220 SoC divider clock driver
>> + *
>> + * Copyright (c) 2015 Hisilicon Limited.
>> + *
>> + * Author: Bintian Wang <[email protected]>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/clk-provider.h>
>> +#include <linux/slab.h>
>> +#include <linux/io.h>
>> +#include <linux/err.h>
>> +
>> +#define div_mask(width) ((1 << (width)) - 1)
>> +
>> +/*
>> + * The reverse of DIV_ROUND_UP: The maximum number which
>> + * divided by m is r
>> + */
>> +#define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1)
>> +
>> +/**
>> + * struct hi6220_clk_divider - divider clock for hi6220
>> + *
>> + * @hw: handle between common and hardware-specific interfaces
>> + * @reg: register containing divider
>> + * @shift: shift to the divider bit field
>> + * @width: width of the divider bit field
>> + * @mask: mask for setting divider rate
>> + * @table: the div table that the divider supports
>> + * @lock: register lock
>> + */
>> +struct hi6220_clk_divider {
>> + struct clk_hw hw;
>> + void __iomem *reg;
>> + u8 shift;
>> + u8 width;
>> + u32 mask;
>> + const struct clk_div_table *table;
>> + spinlock_t *lock;
>> +};
>> +
>> +#define to_hi6220_clk_divider(_hw) \
>> + container_of(_hw, struct hi6220_clk_divider, hw)
>> +
>> +static unsigned int hi6220_get_table_maxdiv(const struct clk_div_table *table)
>> +{
>> + unsigned int maxdiv = 0;
>> + const struct clk_div_table *clkt;
>> +
>> + for (clkt = table; clkt->div; clkt++)
>> + if (clkt->div > maxdiv)
>> + maxdiv = clkt->div;
>> + return maxdiv;
>> +}
>> +
>> +static unsigned int hi6220_get_table_div(const struct clk_div_table *table,
>> + unsigned int val)
>> +{
>> + const struct clk_div_table *clkt;
>> +
>> + for (clkt = table; clkt->div; clkt++)
>> + if (clkt->val == val)
>> + return clkt->div;
>> +
>> + return 0;
>> +}
>> +
>> +static unsigned int hi6220_get_table_val(const struct clk_div_table *table,
>> + unsigned int div)
>> +{
>> + const struct clk_div_table *clkt;
>> +
>> + for (clkt = table; clkt->div; clkt++)
>> + if (clkt->div == div)
>> + return clkt->val;
>> + return 0;
>> +}
>> +
>> +static unsigned long hi6220_clkdiv_recalc_rate(struct clk_hw *hw,
>> + unsigned long parent_rate)
>> +{
>> + unsigned int div, val;
>> + struct hi6220_clk_divider *dclk = to_hi6220_clk_divider(hw);
>> +
>> + val = readl_relaxed(dclk->reg) >> dclk->shift;
>> + val &= div_mask(dclk->width);
>> +
>> + div = hi6220_get_table_div(dclk->table, val);
>> + if (!div) {
>> + pr_warn("%s: Invalid divisor for clock %s\n", __func__,
>> + __clk_get_name(hw->clk));
>> + return parent_rate;
>> + }
>> +
>> + return parent_rate / div;
>> +}
>> +
>> +static bool hi6220_is_valid_div(const struct clk_div_table *table,
>> + unsigned int div)
>> +{
>> + const struct clk_div_table *clkt;
>> +
>> + for (clkt = table; clkt->div; clkt++)
>> + if (clkt->div == div)
>> + return true;
>> + return false;
>> +}
>> +
>> +static int hi6220_clkdiv_bestdiv(struct clk_hw *hw, unsigned long rate,
>> + unsigned long *best_parent_rate)
>> +{
>> + unsigned int i, bestdiv = 0;
>> + unsigned long parent_rate, best = 0, now, maxdiv;
>> +
>> + struct hi6220_clk_divider *dclk = to_hi6220_clk_divider(hw);
>> + struct clk *clk_parent = __clk_get_parent(hw->clk);
>> +
>> + maxdiv = hi6220_get_table_maxdiv(dclk->table);
>> +
>> + if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) {
>> + parent_rate = *best_parent_rate;
>> + bestdiv = DIV_ROUND_UP(parent_rate, rate);
>> + bestdiv = (bestdiv == 0) ? 1 : bestdiv;
>> + bestdiv = (bestdiv > maxdiv) ? maxdiv : bestdiv;
>> + return bestdiv;
>> + }
>> +
>> + /*
>> + * The maximum divider we can use without overflowing
>> + * unsigned long in rate * i below
>> + */
>> + maxdiv = min(ULONG_MAX / rate, maxdiv);
>> +
>> + for (i = 1; i <= maxdiv; i++) {
>> + if (!hi6220_is_valid_div(dclk->table, i))
>> + continue;
>> + parent_rate = __clk_round_rate(clk_parent,
>> + MULT_ROUND_UP(rate, i));
>> + now = parent_rate / i;
>> + if (now <= rate && now > best) {
>> + bestdiv = i;
>> + best = now;
>> + *best_parent_rate = parent_rate;
>> + }
>> + }
>> +
>> + if (!bestdiv) {
>> + bestdiv = hi6220_get_table_maxdiv(dclk->table);
>> + *best_parent_rate = __clk_round_rate(clk_parent, 1);
>> + }
>> +
>> + return bestdiv;
>> +}
>> +
>> +static long hi6220_clkdiv_round_rate(struct clk_hw *hw, unsigned long rate,
>> + unsigned long *prate)
>> +{
>> + int div;
>> +
>> + if (!rate)
>> + rate = 1;
>> +
>> + div = hi6220_clkdiv_bestdiv(hw, rate, prate);
>> +
>> + return *prate / div;
>> +}
>> +
>> +static int hi6220_clkdiv_set_rate(struct clk_hw *hw, unsigned long rate,
>> + unsigned long parent_rate)
>> +{
>> + unsigned int div, value;
>> + unsigned long flags = 0;
>> + u32 data;
>> + struct hi6220_clk_divider *dclk = to_hi6220_clk_divider(hw);
>> +
>> + div = parent_rate / rate;
>> +
>> + if (!hi6220_is_valid_div(dclk->table, div))
>> + return -EINVAL;
>> +
>> + value = hi6220_get_table_val(dclk->table, div);
>> +
>> + if (value > div_mask(dclk->width))
>> + value = div_mask(dclk->width);
>> +
>> + if (dclk->lock)
>> + spin_lock_irqsave(dclk->lock, flags);
>> +
>> + data = readl_relaxed(dclk->reg);
>> + data &= ~(div_mask(dclk->width) << dclk->shift);
>> + data |= value << dclk->shift;
>> + data |= dclk->mask;
>> +
>> + writel_relaxed(data, dclk->reg);
>> +
>> + if (dclk->lock)
>> + spin_unlock_irqrestore(dclk->lock, flags);
>> +
>> + return 0;
>> +}
>> +
>> +static struct clk_ops hi6220_clkdiv_ops = {
>> + .recalc_rate = hi6220_clkdiv_recalc_rate,
>> + .round_rate = hi6220_clkdiv_round_rate,
>> + .set_rate = hi6220_clkdiv_set_rate,
>> +};
>> +
>> +struct clk *hi6220_register_clkdiv(struct device *dev, const char *name,
>> + const char *parent_name, unsigned long flags, void __iomem *reg,
>> + u8 shift, u8 width, u32 mask_bit, spinlock_t *lock)
>> +{
>> + struct hi6220_clk_divider *div;
>> + struct clk *clk;
>> + struct clk_init_data init;
>> + struct clk_div_table *table;
>> + u32 max_div, min_div;
>> + int i;
>> +
>> + /* allocate the divider */
>> + div = kzalloc(sizeof(struct hi6220_clk_divider), GFP_KERNEL);
>> + if (!div) {
>> + pr_err("%s: could not allocate divider clk\n", __func__);
>> + return ERR_PTR(-ENOMEM);
>> + }
>> +
>> + /* Init the divider table */
>> + max_div = div_mask(width) + 1;
>> + min_div = 1;
>> +
>> + table = kzalloc(sizeof(struct clk_div_table) * (max_div + 1), GFP_KERNEL);
>> + if (!table) {
>> + kfree(div);
>> + pr_err("%s: failed to alloc divider table!\n", __func__);
>> + return ERR_PTR(-ENOMEM);
>> + }
>> +
>> + for (i = 0; i < max_div; i++) {
>> + table[i].div = min_div + i;
>> + table[i].val = table[i].div - 1;
>> + }
>> +
>> + init.name = name;
>> + init.ops = &hi6220_clkdiv_ops;
>> + init.flags = flags | CLK_IS_BASIC;
>> + init.parent_names = parent_name ? &parent_name : NULL;
>> + init.num_parents = parent_name ? 1 : 0;
>> +
>> + /* struct hi6220_clk_divider assignments */
>> + div->reg = reg;
>> + div->shift = shift;
>> + div->width = width;
>> + div->mask = mask_bit ? BIT(mask_bit) : 0;
>> + div->lock = lock;
>> + div->hw.init = &init;
>> + div->table = table;
>> +
>> + /* register the clock */
>> + clk = clk_register(dev, &div->hw);
>> +
>> + if (IS_ERR(clk)) {
>> + kfree(table);
>> + kfree(div);
>> + }
>> +
>> + return clk;
>> +}
>> diff --git a/include/dt-bindings/clock/hi6220-clock.h b/include/dt-bindings/clock/hi6220-clock.h
>> new file mode 100644
>> index 0000000..05033e7
>> --- /dev/null
>> +++ b/include/dt-bindings/clock/hi6220-clock.h
>> @@ -0,0 +1,172 @@
>> +/*
>> + * Copyright (c) 2015 Hisilicon Limited.
>> + *
>> + * Author: Bintian Wang <[email protected]>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +#ifndef __DT_BINDINGS_CLOCK_HI6220_H
>> +#define __DT_BINDINGS_CLOCK_HI6220_H
>> +
>> +/* clk in AO (always on) controller */
>> +#define HI6220_NONE_CLOCK 0
>> +
>> +/* fixed rate clocks */
>> +#define HI6220_REF32K 1
>> +#define HI6220_CLK_TCXO 2
>> +#define HI6220_MMC1_PAD 3
>> +#define HI6220_MMC2_PAD 4
>> +#define HI6220_MMC0_PAD 5
>> +#define HI6220_PLL_BBP 6
>> +#define HI6220_PLL_GPU 7
>> +#define HI6220_PLL1_DDR 8
>> +#define HI6220_PLL_SYS 9
>> +#define HI6220_PLL_SYS_MEDIA 10
>> +#define HI6220_DDR_SRC 11
>> +#define HI6220_PLL_MEDIA 12
>> +#define HI6220_PLL_DDR 13
>> +
>> +/* fixed factor clocks */
>> +#define HI6220_300M 16
>> +#define HI6220_150M 17
>> +#define HI6220_PICOPHY_SRC 18
>> +#define HI6220_MMC0_SRC_SEL 19
>> +#define HI6220_MMC1_SRC_SEL 20
>> +#define HI6220_MMC2_SRC_SEL 21
>> +#define HI6220_VPU_CODEC 22
>> +#define HI6220_MMC0_SMP 23
>> +#define HI6220_MMC1_SMP 24
>> +#define HI6220_MMC2_SMP 25
>> +
>> +/* gate clocks */
>> +#define HI6220_WDT0_PCLK 28
>> +#define HI6220_WDT1_PCLK 29
>> +#define HI6220_WDT2_PCLK 30
>> +#define HI6220_TIMER0_PCLK 31
>> +#define HI6220_TIMER1_PCLK 32
>> +#define HI6220_TIMER2_PCLK 33
>> +#define HI6220_TIMER3_PCLK 34
>> +#define HI6220_TIMER4_PCLK 35
>> +#define HI6220_TIMER5_PCLK 36
>> +#define HI6220_TIMER6_PCLK 37
>> +#define HI6220_TIMER7_PCLK 38
>> +#define HI6220_TIMER8_PCLK 39
>> +#define HI6220_UART0_PCLK 40
>> +
>> +#define HI6220_AO_NR_CLKS 48
>> +
>> +/* clk in systrl */
>> +/* gate clock */
>> +#define HI6220_MMC0_CLK 1
>> +#define HI6220_MMC0_CIUCLK 2
>> +#define HI6220_MMC1_CLK 3
>> +#define HI6220_MMC1_CIUCLK 4
>> +#define HI6220_MMC2_CLK 5
>> +#define HI6220_MMC2_CIUCLK 6
>> +#define HI6220_USBOTG_HCLK 7
>> +#define HI6220_CLK_PICOPHY 8
>> +#define HI6220_HIFI 9
>> +#define HI6220_DACODEC_PCLK 10
>> +#define HI6220_EDMAC_ACLK 11
>> +#define HI6220_CS_ATB 12
>> +#define HI6220_I2C0_CLK 13
>> +#define HI6220_I2C1_CLK 14
>> +#define HI6220_I2C2_CLK 15
>> +#define HI6220_I2C3_CLK 16
>> +#define HI6220_UART1_PCLK 17
>> +#define HI6220_UART2_PCLK 18
>> +#define HI6220_UART3_PCLK 19
>> +#define HI6220_UART4_PCLK 20
>> +#define HI6220_SPI_CLK 21
>> +#define HI6220_MMU_CLK 22
>> +#define HI6220_HIFI_SEL 23
>> +#define HI6220_MMC0_SYSPLL 24
>> +#define HI6220_MMC1_SYSPLL 25
>> +#define HI6220_MMC2_SYSPLL 26
>> +#define HI6220_MMC0_SEL 27
>> +#define HI6220_MMC1_SEL 28
>> +#define HI6220_BBPPLL_SEL 29
>> +#define HI6220_MEDIA_PLL_SRC 30
>> +#define HI6220_MMC2_SEL 31
>> +#define HI6220_CS_ATB_SYSPLL 32
>> +
>> +/* mux clocks */
>> +#define HI6220_MMC0_SRC 35
>> +#define HI6220_MMC0_SMP_IN 36
>> +#define HI6220_MMC1_SRC 37
>> +#define HI6220_MMC1_SMP_IN 38
>> +#define HI6220_MMC2_SRC 39
>> +#define HI6220_MMC2_SMP_IN 40
>> +#define HI6220_HIFI_SRC 41
>> +#define HI6220_UART1_SRC 42
>> +#define HI6220_UART2_SRC 43
>> +#define HI6220_UART3_SRC 44
>> +#define HI6220_UART4_SRC 45
>> +#define HI6220_MMC0_MUX0 46
>> +#define HI6220_MMC1_MUX0 47
>> +#define HI6220_MMC2_MUX0 48
>> +#define HI6220_MMC0_MUX1 49
>> +#define HI6220_MMC1_MUX1 50
>> +#define HI6220_MMC2_MUX1 51
>> +
>> +/* divider clocks */
>> +#define HI6220_CLK_BUS 54
>> +#define HI6220_MMC0_DIV 55
>> +#define HI6220_MMC1_DIV 56
>> +#define HI6220_MMC2_DIV 57
>> +#define HI6220_HIFI_DIV 58
>> +#define HI6220_BBPPLL0_DIV 59
>> +#define HI6220_CS_DAPB 60
>> +#define HI6220_CS_ATB_DIV 61
>> +
>> +#define HI6220_SYS_NR_CLKS 64
>> +
>> +/* clk in media controller */
>> +/* gate clocks */
>> +#define HI6220_DSI_PCLK 1
>> +#define HI6220_G3D_PCLK 2
>> +#define HI6220_ACLK_CODEC_VPU 3
>> +#define HI6220_ISP_SCLK 4
>> +#define HI6220_ADE_CORE 5
>> +#define HI6220_MED_MMU 6
>> +#define HI6220_CFG_CSI4PHY 7
>> +#define HI6220_CFG_CSI2PHY 8
>> +#define HI6220_ISP_SCLK_GATE 9
>> +#define HI6220_ISP_SCLK_GATE1 10
>> +#define HI6220_ADE_CORE_GATE 11
>> +#define HI6220_CODEC_VPU_GATE 12
>> +#define HI6220_MED_SYSPLL 13
>> +
>> +/* mux clocks */
>> +#define HI6220_1440_1200 20
>> +#define HI6220_1000_1200 21
>> +#define HI6220_1000_1440 22
>> +
>> +/* divider clocks */
>> +#define HI6220_CODEC_JPEG 30
>> +#define HI6220_ISP_SCLK_SRC 31
>> +#define HI6220_ISP_SCLK1 32
>> +#define HI6220_ADE_CORE_SRC 33
>> +#define HI6220_ADE_PIX_SRC 34
>> +#define HI6220_G3D_CLK 35
>> +#define HI6220_CODEC_VPU_SRC 36
>> +
>> +#define HI6220_MEDIA_NR_CLKS 40
>> +
>> +/* clk in power controller */
>> +/* gate clocks */
>> +#define HI6220_PLL_GPU_GATE 1
>> +#define HI6220_PLL1_DDR_GATE 2
>> +#define HI6220_PLL_DDR_GATE 3
>> +#define HI6220_PLL_MEDIA_GATE 4
>> +#define HI6220_PLL0_BBP_GATE 5
>> +
>> +/* divider clocks */
>> +#define HI6220_DDRC_SRC 10
>> +#define HI6220_DDRC_AXI1 11
>> +
>> +#define HI6220_POWER_NR_CLKS 16
>> +#endif
>> --
>> 1.7.9.5
>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> [email protected]
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
> Cheers,
>
> - Tyler
>
> [1] http://kernelci.org/build/tbaker/kernel/v3.19-rc7-8241-g7b08f7b75c01/
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/



--
Best Regards,

Bintian
===========================
Don't be nervous, just be happy!

2015-02-07 22:05:59

by Tyler Baker

[permalink] [raw]
Subject: Re: [PATCH 2/3] clk: hi6220: Clock driver support for Hisilicon hi6220 SoC

Hi Bintian,

On 7 February 2015 at 10:05, Brent Wang <[email protected]> wrote:
> Hello Tyler,
>
> Thank you very much for helping test this patchset!

Not a problem.

>
> 2015-02-07 2:10 GMT+08:00 Tyler Baker <[email protected]>:
>> Hi Bintian,
>>
>> This patch applied to next-20150204 is producing build failures on
>> various ARM defconfigs[1]. I received the following error in all
>> cases:
>>
>> drivers/built-in.o: In function `hi6220_clk_register_divider':
>> :(.init.text+0x1a84c): undefined reference to `hi6220_register_clkdiv'
>> Makefile:925: recipe for target 'vmlinux' failed
>> make: *** [vmlinux] Error 1
> It's my fault, I just test on ARM64, The following patch can fix this error:
> =====================
> diff --git a/drivers/clk/hisilicon/Makefile b/drivers/clk/hisilicon/Makefile
> index bbf0539..48f0116 100644
> --- a/drivers/clk/hisilicon/Makefile
> +++ b/drivers/clk/hisilicon/Makefile
> @@ -2,9 +2,9 @@
> # Hisilicon Clock specific Makefile
> #
>
> -obj-y += clk.o clkgate-separated.o
> +obj-y += clk.o clkgate-separated.o clkdivider-hi6220.o
>
> obj-$(CONFIG_ARCH_HI3xxx) += clk-hi3620.o
> obj-$(CONFIG_ARCH_HIP04) += clk-hip04.o
> obj-$(CONFIG_ARCH_HIX5HD2) += clk-hix5hd2.o
> -obj-$(CONFIG_COMMON_CLK_HI6220) += clkdivider-hi6220.o clk-hi6220.o
> +obj-$(CONFIG_COMMON_CLK_HI6220) += clk-hi6220.o
> ======================
>
> I will fix this problem in next version.

Great, thank you. I quickly tested your change above, and it gets the
ARM defconfigs building again.

>
> Thanks,
>
> Bintian
>
>
>>
>> On 5 February 2015 at 01:24, Bintian Wang <[email protected]> wrote:
>>> Add clock drivers for hi6220 SoC, this driver controls the SoC
>>> registers to supply different clocks to different IPs in the SoC.
>>>
>>> We add one divider clock for hi6220 because the divider in hi6220
>>> also has a mask bit but it doesnot obey the rule defined by flag
>>> "CLK_DIVIDER_HIWORD_MASK", we can not get index of the mask bit by
>>> left shift fixed bits (e.g. 16 bits), so we add this divider clock
>>> to handle it.
>>>
>>> This patch also enables this clock driver for ARCH_HISI and document
>>> devicetree bindings.
>>>
>>> Signed-off-by: Bintian Wang <[email protected]>
>>> Reviewed-by: Haojian Zhuang <[email protected]>
>>> Reviewed-by: Zhangfei Gao <[email protected]>
>>> ---
>>> .../devicetree/bindings/clock/hi6220-clock.txt | 30 +++
>>> arch/arm64/Kconfig | 1 +
>>> drivers/clk/Kconfig | 2 +
>>> drivers/clk/Makefile | 4 +-
>>> drivers/clk/hisilicon/Kconfig | 5 +
>>> drivers/clk/hisilicon/Makefile | 1 +
>>> drivers/clk/hisilicon/clk-hi6220.c | 284 ++++++++++++++++++++
>>> drivers/clk/hisilicon/clk.c | 29 ++
>>> drivers/clk/hisilicon/clk.h | 17 ++
>>> drivers/clk/hisilicon/clkdivider-hi6220.c | 273 +++++++++++++++++++
>>> include/dt-bindings/clock/hi6220-clock.h | 172 ++++++++++++
>>> 11 files changed, 815 insertions(+), 3 deletions(-)
>>> create mode 100644 Documentation/devicetree/bindings/clock/hi6220-clock.txt
>>> create mode 100644 drivers/clk/hisilicon/Kconfig
>>> create mode 100644 drivers/clk/hisilicon/clk-hi6220.c
>>> create mode 100644 drivers/clk/hisilicon/clkdivider-hi6220.c
>>> create mode 100644 include/dt-bindings/clock/hi6220-clock.h
>>>
>>> diff --git a/Documentation/devicetree/bindings/clock/hi6220-clock.txt b/Documentation/devicetree/bindings/clock/hi6220-clock.txt
>>> new file mode 100644
>>> index 0000000..a3ddda1
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/clock/hi6220-clock.txt
>>> @@ -0,0 +1,30 @@
>>> +* Hisilicon Hi6220 Clock Controller
>>> +
>>> +The hi6220 clock controller generates and supplies clock to various
>>> +controllers within the hi6220 SoC.
>>> +
>>> +Required Properties:
>>> +
>>> +- compatible: should be one of the following:
>>> + - "hisilicon,hi6220-clock-ao" - controller for those clocks under SoC
>>> + power always on(AO) domain, it is the sub node of SoC power AO
>>> + controller in dts file.
>>> + - "hisilicon,hi6220-clock-sys" - controller for those clocks under SoC
>>> + system control domain, it is the sub node of SoC system controller
>>> + in dts file.
>>> + - "hisilicon,hi6220-clock-media" - controller for those clocks under
>>> + SoC media control domain, it is the sub node of SoC media controller
>>> + in dts file.
>>> + - "hisilicon,hi6220-clock-power" - controller for those clocks under
>>> + SoC power control domain, it is the sub node of SoC power controller
>>> + in dts file.
>>> +
>>> +- reg: physical base address of the controller and length of memory mapped
>>> + region.
>>> +
>>> +- #clock-cells: should be 1.
>>> +
>>> +Each clock is assigned an identifier and client nodes use this identifier
>>> +to specify the clock which they consume.
>>> +
>>> +All these identifier could be found in <dt-bindings/clock/hi6220-clock.h>.
>>> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
>>> index 78cd41c8..6efc3e3 100644
>>> --- a/arch/arm64/Kconfig
>>> +++ b/arch/arm64/Kconfig
>>> @@ -175,6 +175,7 @@ config ARCH_XGENE
>>>
>>> config ARCH_HISI
>>> bool "Hisilicon SoC Family"
>>> + select COMMON_CLK_HI6220
>>> help
>>> This enables support for Hisilicon ARMv8 Family of SoCs.
>>>
>>> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
>>> index 3f44f29..b52c95c 100644
>>> --- a/drivers/clk/Kconfig
>>> +++ b/drivers/clk/Kconfig
>>> @@ -136,6 +136,8 @@ config COMMON_CLK_PXA
>>>
>>> source "drivers/clk/qcom/Kconfig"
>>>
>>> +source "drivers/clk/hisilicon/Kconfig"
>>> +
>>> endmenu
>>>
>>> source "drivers/clk/bcm/Kconfig"
>>> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
>>> index d5fba5b..c58703b 100644
>>> --- a/drivers/clk/Makefile
>>> +++ b/drivers/clk/Makefile
>>> @@ -43,9 +43,7 @@ obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o
>>> obj-$(CONFIG_COMMON_CLK_AT91) += at91/
>>> obj-$(CONFIG_ARCH_BCM_MOBILE) += bcm/
>>> obj-$(CONFIG_ARCH_BERLIN) += berlin/
>>> -obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/
>>> -obj-$(CONFIG_ARCH_HIP04) += hisilicon/
>>> -obj-$(CONFIG_ARCH_HIX5HD2) += hisilicon/
>>> +obj-$(CONFIG_ARCH_HISI) += hisilicon/
>>> obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/
>>> ifeq ($(CONFIG_COMMON_CLK), y)
>>> obj-$(CONFIG_ARCH_MMP) += mmp/
>>> diff --git a/drivers/clk/hisilicon/Kconfig b/drivers/clk/hisilicon/Kconfig
>>> new file mode 100644
>>> index 0000000..e3ead46
>>> --- /dev/null
>>> +++ b/drivers/clk/hisilicon/Kconfig
>>> @@ -0,0 +1,5 @@
>>> +config COMMON_CLK_HI6220
>>> + tristate "Hi6220 Clock Driver"
>>> + depends on OF && ARCH_HISI
>>> + help
>>> + Build the Hisilicon Hi6220 clock driver based on the common clock framework.
>>> diff --git a/drivers/clk/hisilicon/Makefile b/drivers/clk/hisilicon/Makefile
>>> index 038c02f..bbf0539 100644
>>> --- a/drivers/clk/hisilicon/Makefile
>>> +++ b/drivers/clk/hisilicon/Makefile
>>> @@ -7,3 +7,4 @@ obj-y += clk.o clkgate-separated.o
>>> obj-$(CONFIG_ARCH_HI3xxx) += clk-hi3620.o
>>> obj-$(CONFIG_ARCH_HIP04) += clk-hip04.o
>>> obj-$(CONFIG_ARCH_HIX5HD2) += clk-hix5hd2.o
>>> +obj-$(CONFIG_COMMON_CLK_HI6220) += clkdivider-hi6220.o clk-hi6220.o
>>> diff --git a/drivers/clk/hisilicon/clk-hi6220.c b/drivers/clk/hisilicon/clk-hi6220.c
>>> new file mode 100644
>>> index 0000000..01d0c46
>>> --- /dev/null
>>> +++ b/drivers/clk/hisilicon/clk-hi6220.c
>>> @@ -0,0 +1,284 @@
>>> +/*
>>> + * Hisilicon Hi6220 clock driver
>>> + *
>>> + * Copyright (c) 2015 Hisilicon Limited.
>>> + *
>>> + * Author: Bintian Wang <[email protected]>
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify
>>> + * it under the terms of the GNU General Public License version 2 as
>>> + * published by the Free Software Foundation.
>>> + */
>>> +
>>> +#include <linux/kernel.h>
>>> +#include <linux/clk-provider.h>
>>> +#include <linux/clkdev.h>
>>> +#include <linux/io.h>
>>> +#include <linux/of.h>
>>> +#include <linux/of_address.h>
>>> +#include <linux/of_device.h>
>>> +#include <linux/slab.h>
>>> +#include <linux/clk.h>
>>> +
>>> +#include <dt-bindings/clock/hi6220-clock.h>
>>> +
>>> +#include "clk.h"
>>> +
>>> +
>>> +/* clocks in AO (always on) controller */
>>> +static struct hisi_fixed_rate_clock hi6220_fixed_rate_clks[] __initdata = {
>>> + { HI6220_REF32K, "ref32k", NULL, CLK_IS_ROOT, 32764, },
>>> + { HI6220_CLK_TCXO, "clk_tcxo", NULL, CLK_IS_ROOT, 19200000, },
>>> + { HI6220_MMC1_PAD, "mmc1_pad", NULL, CLK_IS_ROOT, 100000000, },
>>> + { HI6220_MMC2_PAD, "mmc2_pad", NULL, CLK_IS_ROOT, 100000000, },
>>> + { HI6220_MMC0_PAD, "mmc0_pad", NULL, CLK_IS_ROOT, 200000000, },
>>> + { HI6220_PLL_BBP, "bbppll0", NULL, CLK_IS_ROOT, 245760000, },
>>> + { HI6220_PLL_GPU, "gpupll", NULL, CLK_IS_ROOT, 1000000000,},
>>> + { HI6220_PLL1_DDR, "ddrpll1", NULL, CLK_IS_ROOT, 1066000000,},
>>> + { HI6220_PLL_SYS, "syspll", NULL, CLK_IS_ROOT, 1200000000,},
>>> + { HI6220_PLL_SYS_MEDIA, "media_syspll", NULL, CLK_IS_ROOT, 1200000000,},
>>> + { HI6220_DDR_SRC, "ddr_sel_src", NULL, CLK_IS_ROOT, 1200000000,},
>>> + { HI6220_PLL_MEDIA, "media_pll", NULL, CLK_IS_ROOT, 1440000000,},
>>> + { HI6220_PLL_DDR, "ddrpll0", NULL, CLK_IS_ROOT, 1600000000,},
>>> +};
>>> +
>>> +static struct hisi_fixed_factor_clock hi6220_fixed_factor_clks[] __initdata = {
>>> + { HI6220_300M, "clk_300m", "syspll", 1, 4, 0, },
>>> + { HI6220_150M, "clk_150m", "clk_300m", 1, 2, 0, },
>>> + { HI6220_PICOPHY_SRC, "picophy_src", "clk_150m", 1, 4, 0, },
>>> + { HI6220_MMC0_SRC_SEL, "mmc0srcsel", "mmc0_sel", 1, 8, 0, },
>>> + { HI6220_MMC1_SRC_SEL, "mmc1srcsel", "mmc1_sel", 1, 8, 0, },
>>> + { HI6220_MMC2_SRC_SEL, "mmc2srcsel", "mmc2_sel", 1, 8, 0, },
>>> + { HI6220_VPU_CODEC, "vpucodec", "codec_jpeg_aclk", 1, 2, 0, },
>>> + { HI6220_MMC0_SMP, "mmc0_sample", "mmc0_sel", 1, 8, 0, },
>>> + { HI6220_MMC1_SMP, "mmc1_sample", "mmc1_sel", 1, 8, 0, },
>>> + { HI6220_MMC2_SMP, "mmc2_sample", "mmc2_sel", 1, 8, 0, },
>>> +};
>>> +
>>> +static struct hisi_gate_clock hi6220_separated_gate_clks_ao[] __initdata = {
>>> + { HI6220_WDT0_PCLK, "wdt0_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 12, 0, },
>>> + { HI6220_WDT1_PCLK, "wdt1_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 13, 0, },
>>> + { HI6220_WDT2_PCLK, "wdt2_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 14, 0, },
>>> + { HI6220_TIMER0_PCLK, "timer0_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 15, 0, },
>>> + { HI6220_TIMER1_PCLK, "timer1_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 16, 0, },
>>> + { HI6220_TIMER2_PCLK, "timer2_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 17, 0, },
>>> + { HI6220_TIMER3_PCLK, "timer3_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 18, 0, },
>>> + { HI6220_TIMER4_PCLK, "timer4_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 19, 0, },
>>> + { HI6220_TIMER5_PCLK, "timer5_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 20, 0, },
>>> + { HI6220_TIMER6_PCLK, "timer6_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 21, 0, },
>>> + { HI6220_TIMER7_PCLK, "timer7_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 22, 0, },
>>> + { HI6220_TIMER8_PCLK, "timer8_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 23, 0, },
>>> + { HI6220_UART0_PCLK, "uart0_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 24, 0, },
>>> +};
>>> +
>>> +static void __init hi6220_clk_ao_init(struct device_node *np)
>>> +{
>>> + struct hisi_clock_data *clk_data;
>>> +
>>> + clk_data = hisi_clk_init(np, HI6220_AO_NR_CLKS);
>>> + if (!clk_data)
>>> + return;
>>> +
>>> + hisi_clk_register_fixed_rate(hi6220_fixed_rate_clks,
>>> + ARRAY_SIZE(hi6220_fixed_rate_clks), clk_data);
>>> +
>>> + hisi_clk_register_fixed_factor(hi6220_fixed_factor_clks,
>>> + ARRAY_SIZE(hi6220_fixed_factor_clks), clk_data);
>>> +
>>> + hisi_clk_register_gate_sep(hi6220_separated_gate_clks_ao,
>>> + ARRAY_SIZE(hi6220_separated_gate_clks_ao), clk_data);
>>> +}
>>> +CLK_OF_DECLARE(hi6220_clk_ao, "hisilicon,hi6220-clock-ao", hi6220_clk_ao_init);
>>> +
>>> +
>>> +/* clocks in sysctrl */
>>> +static const char *mmc0_mux0_p[] __initconst = { "pll_ddr_gate", "syspll", };
>>> +static const char *mmc0_mux1_p[] __initconst = { "mmc0_mux0", "pll_media_gate", };
>>> +static const char *mmc0_src_p[] __initconst = { "mmc0srcsel", "mmc0_div", };
>>> +static const char *mmc1_mux0_p[] __initconst = { "pll_ddr_gate", "syspll", };
>>> +static const char *mmc1_mux1_p[] __initconst = { "mmc1_mux0", "pll_media_gate", };
>>> +static const char *mmc1_src_p[] __initconst = { "mmc1srcsel", "mmc1_div", };
>>> +static const char *mmc2_mux0_p[] __initconst = { "pll_ddr_gate", "syspll", };
>>> +static const char *mmc2_mux1_p[] __initconst = { "mmc2_mux0", "pll_media_gate", };
>>> +static const char *mmc2_src_p[] __initconst = { "mmc2srcsel", "mmc2_div", };
>>> +static const char *mmc0_sample_in[] __initconst = { "mmc0_sample", "mmc0_pad", };
>>> +static const char *mmc1_sample_in[] __initconst = { "mmc1_sample", "mmc1_pad", };
>>> +static const char *mmc2_sample_in[] __initconst = { "mmc2_sample", "mmc2_pad", };
>>> +static const char *uart1_src[] __initconst = { "clk_tcxo", "clk_150m", };
>>> +static const char *uart2_src[] __initconst = { "clk_tcxo", "clk_150m", };
>>> +static const char *uart3_src[] __initconst = { "clk_tcxo", "clk_150m", };
>>> +static const char *uart4_src[] __initconst = { "clk_tcxo", "clk_150m", };
>>> +static const char *hifi_src[] __initconst = { "syspll", "pll_media_gate", };
>>> +
>>> +static struct hisi_gate_clock hi6220_separated_gate_clks_sys[] __initdata = {
>>> + { HI6220_MMC0_CLK, "mmc0_clk", "mmc0_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 0, 0, },
>>> + { HI6220_MMC0_CIUCLK, "mmc0_ciuclk", "mmc0_smp_in", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 0, 0, },
>>> + { HI6220_MMC1_CLK, "mmc1_clk", "mmc1_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 1, 0, },
>>> + { HI6220_MMC1_CIUCLK, "mmc1_ciuclk", "mmc1_smp_in", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 1, 0, },
>>> + { HI6220_MMC2_CLK, "mmc2_clk", "mmc2_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 2, 0, },
>>> + { HI6220_MMC2_CIUCLK, "mmc2_ciuclk", "mmc2_smp_in", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 2, 0, },
>>> + { HI6220_USBOTG_HCLK, "usbotg_hclk", "clk_bus", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 4, 0, },
>>> + { HI6220_CLK_PICOPHY, "clk_picophy", "cs_dapb", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x200, 5, 0, },
>>> + { HI6220_HIFI, "hifi_clk", "hifi_div", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x210, 0, 0, },
>>> + { HI6220_DACODEC_PCLK, "dacodec_pclk", "clk_bus", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x210, 5, 0, },
>>> + { HI6220_EDMAC_ACLK, "edmac_aclk", "clk_bus", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x220, 2, 0, },
>>> + { HI6220_CS_ATB, "cs_atb", "cs_atb_div", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 0, 0, },
>>> + { HI6220_I2C0_CLK, "i2c0_clk", "clk_150m", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 1, 0, },
>>> + { HI6220_I2C1_CLK, "i2c1_clk", "clk_150m", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 2, 0, },
>>> + { HI6220_I2C2_CLK, "i2c2_clk", "clk_150m", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 3, 0, },
>>> + { HI6220_I2C3_CLK, "i2c3_clk", "clk_150m", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 4, 0, },
>>> + { HI6220_UART1_PCLK, "uart1_pclk", "uart1_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 5, 0, },
>>> + { HI6220_UART2_PCLK, "uart2_pclk", "uart2_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 6, 0, },
>>> + { HI6220_UART3_PCLK, "uart3_pclk", "uart3_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 7, 0, },
>>> + { HI6220_UART4_PCLK, "uart4_pclk", "uart4_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 8, 0, },
>>> + { HI6220_SPI_CLK, "spi_clk", "clk_150m", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x230, 9, 0, },
>>> + { HI6220_MMU_CLK, "mmu_clk", "ddrc_axi1", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x240, 11, 0, },
>>> + { HI6220_HIFI_SEL, "hifi_sel", "hifi_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 0, 0, },
>>> + { HI6220_MMC0_SYSPLL, "mmc0_syspll", "syspll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 1, 0, },
>>> + { HI6220_MMC1_SYSPLL, "mmc1_syspll", "syspll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 2, 0, },
>>> + { HI6220_MMC2_SYSPLL, "mmc2_syspll", "syspll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 3, 0, },
>>> + { HI6220_MMC0_SEL, "mmc0_sel", "mmc0_mux1", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 6, 0, },
>>> + { HI6220_MMC1_SEL, "mmc1_sel", "mmc1_mux1", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 7, 0, },
>>> + { HI6220_BBPPLL_SEL, "bbppll_sel", "pll0_bbp_gate", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 9, 0, },
>>> + { HI6220_MEDIA_PLL_SRC, "media_pll_src", "pll_media_gate", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 10, 0, },
>>> + { HI6220_MMC2_SEL, "mmc2_sel", "mmc2_mux1", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 11, 0, },
>>> + { HI6220_CS_ATB_SYSPLL, "cs_atb_syspll", "syspll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 12, 0, },
>>> +};
>>> +
>>> +static struct hisi_mux_clock hi6220_mux_clks_sys[] __initdata = {
>>> + { HI6220_MMC0_SRC, "mmc0_src", mmc0_src_p, ARRAY_SIZE(mmc0_src_p), CLK_SET_RATE_PARENT, 0x4, 0, 1, 0, },
>>> + { HI6220_MMC0_SMP_IN, "mmc0_smp_in", mmc0_sample_in, ARRAY_SIZE(mmc0_sample_in), CLK_SET_RATE_PARENT, 0x4, 0, 1, 0, },
>>> + { HI6220_MMC1_SRC, "mmc1_src", mmc1_src_p, ARRAY_SIZE(mmc1_src_p), CLK_SET_RATE_PARENT, 0x4, 2, 1, 0, },
>>> + { HI6220_MMC1_SMP_IN, "mmc1_smp_in", mmc1_sample_in, ARRAY_SIZE(mmc1_sample_in), CLK_SET_RATE_PARENT, 0x4, 2, 1, 0, },
>>> + { HI6220_MMC2_SRC, "mmc2_src", mmc2_src_p, ARRAY_SIZE(mmc2_src_p), CLK_SET_RATE_PARENT, 0x4, 4, 1, 0, },
>>> + { HI6220_MMC2_SMP_IN, "mmc2_smp_in", mmc2_sample_in, ARRAY_SIZE(mmc2_sample_in), CLK_SET_RATE_PARENT, 0x4, 4, 1, 0, },
>>> + { HI6220_HIFI_SRC, "hifi_src", hifi_src, ARRAY_SIZE(hifi_src), CLK_SET_RATE_PARENT, 0x400, 0, 1, CLK_MUX_HIWORD_MASK,},
>>> + { HI6220_UART1_SRC, "uart1_src", uart1_src, ARRAY_SIZE(uart1_src), CLK_SET_RATE_PARENT, 0x400, 1, 1, CLK_MUX_HIWORD_MASK,},
>>> + { HI6220_UART2_SRC, "uart2_src", uart2_src, ARRAY_SIZE(uart2_src), CLK_SET_RATE_PARENT, 0x400, 2, 1, CLK_MUX_HIWORD_MASK,},
>>> + { HI6220_UART3_SRC, "uart3_src", uart3_src, ARRAY_SIZE(uart3_src), CLK_SET_RATE_PARENT, 0x400, 3, 1, CLK_MUX_HIWORD_MASK,},
>>> + { HI6220_UART4_SRC, "uart4_src", uart4_src, ARRAY_SIZE(uart4_src), CLK_SET_RATE_PARENT, 0x400, 4, 1, CLK_MUX_HIWORD_MASK,},
>>> + { HI6220_MMC0_MUX0, "mmc0_mux0", mmc0_mux0_p, ARRAY_SIZE(mmc0_mux0_p), CLK_SET_RATE_PARENT, 0x400, 5, 1, CLK_MUX_HIWORD_MASK,},
>>> + { HI6220_MMC1_MUX0, "mmc1_mux0", mmc1_mux0_p, ARRAY_SIZE(mmc1_mux0_p), CLK_SET_RATE_PARENT, 0x400, 11, 1, CLK_MUX_HIWORD_MASK,},
>>> + { HI6220_MMC2_MUX0, "mmc2_mux0", mmc2_mux0_p, ARRAY_SIZE(mmc2_mux0_p), CLK_SET_RATE_PARENT, 0x400, 12, 1, CLK_MUX_HIWORD_MASK,},
>>> + { HI6220_MMC0_MUX1, "mmc0_mux1", mmc0_mux1_p, ARRAY_SIZE(mmc0_mux1_p), CLK_SET_RATE_PARENT, 0x400, 13, 1, CLK_MUX_HIWORD_MASK,},
>>> + { HI6220_MMC1_MUX1, "mmc1_mux1", mmc1_mux1_p, ARRAY_SIZE(mmc1_mux1_p), CLK_SET_RATE_PARENT, 0x400, 14, 1, CLK_MUX_HIWORD_MASK,},
>>> + { HI6220_MMC2_MUX1, "mmc2_mux1", mmc2_mux1_p, ARRAY_SIZE(mmc2_mux1_p), CLK_SET_RATE_PARENT, 0x400, 15, 1, CLK_MUX_HIWORD_MASK,},
>>> +};
>>> +
>>> +static struct hi6220_divider_clock hi6220_div_clks_sys[] __initdata = {
>>> + { HI6220_CLK_BUS, "clk_bus", "clk_300m", CLK_SET_RATE_PARENT, 0x490, 0, 4, 7, },
>>> + { HI6220_MMC0_DIV, "mmc0_div", "mmc0_syspll", CLK_SET_RATE_PARENT, 0x494, 0, 6, 7, },
>>> + { HI6220_MMC1_DIV, "mmc1_div", "mmc1_syspll", CLK_SET_RATE_PARENT, 0x498, 0, 6, 7, },
>>> + { HI6220_MMC2_DIV, "mmc2_div", "mmc2_syspll", CLK_SET_RATE_PARENT, 0x49c, 0, 6, 7, },
>>> + { HI6220_HIFI_DIV, "hifi_div", "hifi_sel", CLK_SET_RATE_PARENT, 0x4a0, 0, 4, 7, },
>>> + { HI6220_BBPPLL0_DIV, "bbppll0_div", "bbppll_sel", CLK_SET_RATE_PARENT, 0x4a0, 8, 6, 15,},
>>> + { HI6220_CS_DAPB, "cs_dapb", "picophy_src", CLK_SET_RATE_PARENT, 0x4a0, 24, 2, 31,},
>>> + { HI6220_CS_ATB_DIV, "cs_atb_div", "cs_atb_syspll", CLK_SET_RATE_PARENT, 0x4a4, 0, 4, 7, },
>>> +};
>>> +
>>> +static void __init hi6220_clk_sys_init(struct device_node *np)
>>> +{
>>> + struct hisi_clock_data *clk_data;
>>> +
>>> + clk_data = hisi_clk_init(np, HI6220_SYS_NR_CLKS);
>>> + if (!clk_data)
>>> + return;
>>> +
>>> + hisi_clk_register_gate_sep(hi6220_separated_gate_clks_sys,
>>> + ARRAY_SIZE(hi6220_separated_gate_clks_sys), clk_data);
>>> +
>>> + hisi_clk_register_mux(hi6220_mux_clks_sys,
>>> + ARRAY_SIZE(hi6220_mux_clks_sys), clk_data);
>>> +
>>> + hi6220_clk_register_divider(hi6220_div_clks_sys,
>>> + ARRAY_SIZE(hi6220_div_clks_sys), clk_data);
>>> +}
>>> +CLK_OF_DECLARE(hi6220_clk_sys, "hisilicon,hi6220-clock-sys", hi6220_clk_sys_init);
>>> +
>>> +
>>> +/* clocks in media controller */
>>> +static const char *clk_1000_1200_src[] __initconst = { "pll_gpu_gate", "media_syspll_src", };
>>> +static const char *clk_1440_1200_src[] __initconst = { "media_syspll_src", "media_pll_src", };
>>> +static const char *clk_1000_1440_src[] __initconst = { "pll_gpu_gate", "media_pll_src", };
>>> +
>>> +static struct hisi_gate_clock hi6220_separated_gate_clks_media[] __initdata = {
>>> + { HI6220_DSI_PCLK, "dsi_pclk", "vpucodec", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 0, 0, },
>>> + { HI6220_G3D_PCLK, "g3d_pclk", "vpucodec", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 1, 0, },
>>> + { HI6220_ACLK_CODEC_VPU, "aclk_codec_vpu", "ade_core_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 3, 0, },
>>> + { HI6220_ISP_SCLK, "isp_sclk", "isp_sclk_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 5, 0, },
>>> + { HI6220_ADE_CORE, "ade_core", "ade_core_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 6, 0, },
>>> + { HI6220_MED_MMU, "media_mmu", "mmu_clk", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 8, 0, },
>>> + { HI6220_CFG_CSI4PHY, "cfg_csi4phy", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 9, 0, },
>>> + { HI6220_CFG_CSI2PHY, "cfg_csi2phy", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 10, 0, },
>>> + { HI6220_ISP_SCLK_GATE, "isp_sclk_gate", "media_pll_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 11, 0, },
>>> + { HI6220_ISP_SCLK_GATE1, "isp_sclk_gate1", "media_pll_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 12, 0, },
>>> + { HI6220_ADE_CORE_GATE, "ade_core_gate", "media_pll_src", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 14, 0, },
>>> + { HI6220_CODEC_VPU_GATE, "codec_vpu_gate", "clk_1000_1440", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 15, 0, },
>>> + { HI6220_MED_SYSPLL, "media_syspll_src", "media_syspll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x520, 17, 0, },
>>> +};
>>> +
>>> +static struct hisi_mux_clock hi6220_mux_clks_media[] __initdata = {
>>> + { HI6220_1440_1200, "clk_1440_1200", clk_1440_1200_src, ARRAY_SIZE(clk_1440_1200_src), CLK_SET_RATE_PARENT, 0x51c, 0, 1, 0, },
>>> + { HI6220_1000_1200, "clk_1000_1200", clk_1000_1200_src, ARRAY_SIZE(clk_1000_1200_src), CLK_SET_RATE_PARENT, 0x51c, 1, 1, 0, },
>>> + { HI6220_1000_1440, "clk_1000_1440", clk_1000_1440_src, ARRAY_SIZE(clk_1000_1440_src), CLK_SET_RATE_PARENT, 0x51c, 6, 1, 0, },
>>> +};
>>> +
>>> +static struct hi6220_divider_clock hi6220_div_clks_media[] __initdata = {
>>> + { HI6220_CODEC_JPEG, "codec_jpeg_aclk", "media_pll_src", CLK_SET_RATE_PARENT, 0xcbc, 0, 4, 23, },
>>> + { HI6220_ISP_SCLK_SRC, "isp_sclk_src", "isp_sclk_gate", CLK_SET_RATE_PARENT, 0xcbc, 8, 4, 15, },
>>> + { HI6220_ISP_SCLK1, "isp_sclk1", "isp_sclk_gate1", CLK_SET_RATE_PARENT, 0xcbc, 24, 4, 31, },
>>> + { HI6220_ADE_CORE_SRC, "ade_core_src", "ade_core_gate", CLK_SET_RATE_PARENT, 0xcc0, 16, 3, 23, },
>>> + { HI6220_ADE_PIX_SRC, "ade_pix_src", "clk_1440_1200", CLK_SET_RATE_PARENT, 0xcc0, 24, 6, 31, },
>>> + { HI6220_G3D_CLK, "g3d_clk", "clk_1000_1200", CLK_SET_RATE_PARENT, 0xcc4, 8, 4, 15, },
>>> + { HI6220_CODEC_VPU_SRC, "codec_vpu_src", "codec_vpu_gate", CLK_SET_RATE_PARENT, 0xcc4, 24, 6, 31, },
>>> +};
>>> +
>>> +static void __init hi6220_clk_media_init(struct device_node *np)
>>> +{
>>> + struct hisi_clock_data *clk_data;
>>> +
>>> + clk_data = hisi_clk_init(np, HI6220_MEDIA_NR_CLKS);
>>> + if (!clk_data)
>>> + return;
>>> +
>>> + hisi_clk_register_gate_sep(hi6220_separated_gate_clks_media,
>>> + ARRAY_SIZE(hi6220_separated_gate_clks_media), clk_data);
>>> +
>>> + hisi_clk_register_mux(hi6220_mux_clks_media,
>>> + ARRAY_SIZE(hi6220_mux_clks_media), clk_data);
>>> +
>>> + hi6220_clk_register_divider(hi6220_div_clks_media,
>>> + ARRAY_SIZE(hi6220_div_clks_media), clk_data);
>>> +}
>>> +CLK_OF_DECLARE(hi6220_clk_media, "hisilicon,hi6220-clock-media", hi6220_clk_media_init);
>>> +
>>> +
>>> +/* clocks in pmctrl */
>>> +static struct hisi_gate_clock hi6220_gate_clks_power[] __initdata = {
>>> + { HI6220_PLL_GPU_GATE, "pll_gpu_gate", "gpupll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x8, 0, 0, },
>>> + { HI6220_PLL1_DDR_GATE, "pll1_ddr_gate", "ddrpll1", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x10, 0, 0, },
>>> + { HI6220_PLL_DDR_GATE, "pll_ddr_gate", "ddrpll0", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x18, 0, 0, },
>>> + { HI6220_PLL_MEDIA_GATE, "pll_media_gate", "media_pll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x38, 0, 0, },
>>> + { HI6220_PLL0_BBP_GATE, "pll0_bbp_gate", "bbppll0", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x48, 0, 0, },
>>> +};
>>> +
>>> +static struct hi6220_divider_clock hi6220_div_clks_power[] __initdata = {
>>> + { HI6220_DDRC_SRC, "ddrc_src", "ddr_sel_src", CLK_SET_RATE_PARENT, 0x5a8, 0, 4, 0, },
>>> + { HI6220_DDRC_AXI1, "ddrc_axi1", "ddrc_src", CLK_SET_RATE_PARENT, 0x5a8, 8, 2, 0, },
>>> +};
>>> +
>>> +static void __init hi6220_clk_power_init(struct device_node *np)
>>> +{
>>> + struct hisi_clock_data *clk_data;
>>> +
>>> + clk_data = hisi_clk_init(np, HI6220_POWER_NR_CLKS);
>>> + if (!clk_data)
>>> + return;
>>> +
>>> + hisi_clk_register_gate(hi6220_gate_clks_power,
>>> + ARRAY_SIZE(hi6220_gate_clks_power), clk_data);
>>> +
>>> + hi6220_clk_register_divider(hi6220_div_clks_power,
>>> + ARRAY_SIZE(hi6220_div_clks_power), clk_data);
>>> +}
>>> +CLK_OF_DECLARE(hi6220_clk_power, "hisilicon,hi6220-clock-power", hi6220_clk_power_init);
>>> diff --git a/drivers/clk/hisilicon/clk.c b/drivers/clk/hisilicon/clk.c
>>> index a078e84..5d2305c 100644
>>> --- a/drivers/clk/hisilicon/clk.c
>>> +++ b/drivers/clk/hisilicon/clk.c
>>> @@ -232,3 +232,32 @@ void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *clks,
>>> data->clk_data.clks[clks[i].id] = clk;
>>> }
>>> }
>>> +
>>> +void __init hi6220_clk_register_divider(struct hi6220_divider_clock *clks,
>>> + int nums, struct hisi_clock_data *data)
>>> +{
>>> + struct clk *clk;
>>> + void __iomem *base = data->base;
>>> + int i;
>>> +
>>> + for (i = 0; i < nums; i++) {
>>> + clk = hi6220_register_clkdiv(NULL, clks[i].name,
>>> + clks[i].parent_name,
>>> + clks[i].flags,
>>> + base + clks[i].offset,
>>> + clks[i].shift,
>>> + clks[i].width,
>>> + clks[i].mask_bit,
>>> + &hisi_clk_lock);
>>> + if (IS_ERR(clk)) {
>>> + pr_err("%s: failed to register clock %s\n",
>>> + __func__, clks[i].name);
>>> + continue;
>>> + }
>>> +
>>> + if (clks[i].alias)
>>> + clk_register_clkdev(clk, clks[i].alias, NULL);
>>> +
>>> + data->clk_data.clks[clks[i].id] = clk;
>>> + }
>>> +}
>>> diff --git a/drivers/clk/hisilicon/clk.h b/drivers/clk/hisilicon/clk.h
>>> index 31083ff..462a570 100644
>>> --- a/drivers/clk/hisilicon/clk.h
>>> +++ b/drivers/clk/hisilicon/clk.h
>>> @@ -79,6 +79,18 @@ struct hisi_divider_clock {
>>> const char *alias;
>>> };
>>>
>>> +struct hi6220_divider_clock {
>>> + unsigned int id;
>>> + const char *name;
>>> + const char *parent_name;
>>> + unsigned long flags;
>>> + unsigned long offset;
>>> + u8 shift;
>>> + u8 width;
>>> + u32 mask_bit;
>>> + const char *alias;
>>> +};
>>> +
>>> struct hisi_gate_clock {
>>> unsigned int id;
>>> const char *name;
>>> @@ -94,6 +106,9 @@ struct clk *hisi_register_clkgate_sep(struct device *, const char *,
>>> const char *, unsigned long,
>>> void __iomem *, u8,
>>> u8, spinlock_t *);
>>> +struct clk *hi6220_register_clkdiv(struct device *dev, const char *name,
>>> + const char *parent_name, unsigned long flags, void __iomem *reg,
>>> + u8 shift, u8 width, u32 mask_bit, spinlock_t *lock);
>>>
>>> struct hisi_clock_data __init *hisi_clk_init(struct device_node *, int);
>>> void __init hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *,
>>> @@ -108,4 +123,6 @@ void __init hisi_clk_register_gate(struct hisi_gate_clock *,
>>> int, struct hisi_clock_data *);
>>> void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *,
>>> int, struct hisi_clock_data *);
>>> +void __init hi6220_clk_register_divider(struct hi6220_divider_clock *,
>>> + int, struct hisi_clock_data *);
>>> #endif /* __HISI_CLK_H */
>>> diff --git a/drivers/clk/hisilicon/clkdivider-hi6220.c b/drivers/clk/hisilicon/clkdivider-hi6220.c
>>> new file mode 100644
>>> index 0000000..9e3825b
>>> --- /dev/null
>>> +++ b/drivers/clk/hisilicon/clkdivider-hi6220.c
>>> @@ -0,0 +1,273 @@
>>> +/*
>>> + * Hisilicon hi6220 SoC divider clock driver
>>> + *
>>> + * Copyright (c) 2015 Hisilicon Limited.
>>> + *
>>> + * Author: Bintian Wang <[email protected]>
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify
>>> + * it under the terms of the GNU General Public License version 2 as
>>> + * published by the Free Software Foundation.
>>> + *
>>> + */
>>> +
>>> +#include <linux/kernel.h>
>>> +#include <linux/clk-provider.h>
>>> +#include <linux/slab.h>
>>> +#include <linux/io.h>
>>> +#include <linux/err.h>
>>> +
>>> +#define div_mask(width) ((1 << (width)) - 1)
>>> +
>>> +/*
>>> + * The reverse of DIV_ROUND_UP: The maximum number which
>>> + * divided by m is r
>>> + */
>>> +#define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1)
>>> +
>>> +/**
>>> + * struct hi6220_clk_divider - divider clock for hi6220
>>> + *
>>> + * @hw: handle between common and hardware-specific interfaces
>>> + * @reg: register containing divider
>>> + * @shift: shift to the divider bit field
>>> + * @width: width of the divider bit field
>>> + * @mask: mask for setting divider rate
>>> + * @table: the div table that the divider supports
>>> + * @lock: register lock
>>> + */
>>> +struct hi6220_clk_divider {
>>> + struct clk_hw hw;
>>> + void __iomem *reg;
>>> + u8 shift;
>>> + u8 width;
>>> + u32 mask;
>>> + const struct clk_div_table *table;
>>> + spinlock_t *lock;
>>> +};
>>> +
>>> +#define to_hi6220_clk_divider(_hw) \
>>> + container_of(_hw, struct hi6220_clk_divider, hw)
>>> +
>>> +static unsigned int hi6220_get_table_maxdiv(const struct clk_div_table *table)
>>> +{
>>> + unsigned int maxdiv = 0;
>>> + const struct clk_div_table *clkt;
>>> +
>>> + for (clkt = table; clkt->div; clkt++)
>>> + if (clkt->div > maxdiv)
>>> + maxdiv = clkt->div;
>>> + return maxdiv;
>>> +}
>>> +
>>> +static unsigned int hi6220_get_table_div(const struct clk_div_table *table,
>>> + unsigned int val)
>>> +{
>>> + const struct clk_div_table *clkt;
>>> +
>>> + for (clkt = table; clkt->div; clkt++)
>>> + if (clkt->val == val)
>>> + return clkt->div;
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static unsigned int hi6220_get_table_val(const struct clk_div_table *table,
>>> + unsigned int div)
>>> +{
>>> + const struct clk_div_table *clkt;
>>> +
>>> + for (clkt = table; clkt->div; clkt++)
>>> + if (clkt->div == div)
>>> + return clkt->val;
>>> + return 0;
>>> +}
>>> +
>>> +static unsigned long hi6220_clkdiv_recalc_rate(struct clk_hw *hw,
>>> + unsigned long parent_rate)
>>> +{
>>> + unsigned int div, val;
>>> + struct hi6220_clk_divider *dclk = to_hi6220_clk_divider(hw);
>>> +
>>> + val = readl_relaxed(dclk->reg) >> dclk->shift;
>>> + val &= div_mask(dclk->width);
>>> +
>>> + div = hi6220_get_table_div(dclk->table, val);
>>> + if (!div) {
>>> + pr_warn("%s: Invalid divisor for clock %s\n", __func__,
>>> + __clk_get_name(hw->clk));
>>> + return parent_rate;
>>> + }
>>> +
>>> + return parent_rate / div;
>>> +}
>>> +
>>> +static bool hi6220_is_valid_div(const struct clk_div_table *table,
>>> + unsigned int div)
>>> +{
>>> + const struct clk_div_table *clkt;
>>> +
>>> + for (clkt = table; clkt->div; clkt++)
>>> + if (clkt->div == div)
>>> + return true;
>>> + return false;
>>> +}
>>> +
>>> +static int hi6220_clkdiv_bestdiv(struct clk_hw *hw, unsigned long rate,
>>> + unsigned long *best_parent_rate)
>>> +{
>>> + unsigned int i, bestdiv = 0;
>>> + unsigned long parent_rate, best = 0, now, maxdiv;
>>> +
>>> + struct hi6220_clk_divider *dclk = to_hi6220_clk_divider(hw);
>>> + struct clk *clk_parent = __clk_get_parent(hw->clk);
>>> +
>>> + maxdiv = hi6220_get_table_maxdiv(dclk->table);
>>> +
>>> + if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) {
>>> + parent_rate = *best_parent_rate;
>>> + bestdiv = DIV_ROUND_UP(parent_rate, rate);
>>> + bestdiv = (bestdiv == 0) ? 1 : bestdiv;
>>> + bestdiv = (bestdiv > maxdiv) ? maxdiv : bestdiv;
>>> + return bestdiv;
>>> + }
>>> +
>>> + /*
>>> + * The maximum divider we can use without overflowing
>>> + * unsigned long in rate * i below
>>> + */
>>> + maxdiv = min(ULONG_MAX / rate, maxdiv);
>>> +
>>> + for (i = 1; i <= maxdiv; i++) {
>>> + if (!hi6220_is_valid_div(dclk->table, i))
>>> + continue;
>>> + parent_rate = __clk_round_rate(clk_parent,
>>> + MULT_ROUND_UP(rate, i));
>>> + now = parent_rate / i;
>>> + if (now <= rate && now > best) {
>>> + bestdiv = i;
>>> + best = now;
>>> + *best_parent_rate = parent_rate;
>>> + }
>>> + }
>>> +
>>> + if (!bestdiv) {
>>> + bestdiv = hi6220_get_table_maxdiv(dclk->table);
>>> + *best_parent_rate = __clk_round_rate(clk_parent, 1);
>>> + }
>>> +
>>> + return bestdiv;
>>> +}
>>> +
>>> +static long hi6220_clkdiv_round_rate(struct clk_hw *hw, unsigned long rate,
>>> + unsigned long *prate)
>>> +{
>>> + int div;
>>> +
>>> + if (!rate)
>>> + rate = 1;
>>> +
>>> + div = hi6220_clkdiv_bestdiv(hw, rate, prate);
>>> +
>>> + return *prate / div;
>>> +}
>>> +
>>> +static int hi6220_clkdiv_set_rate(struct clk_hw *hw, unsigned long rate,
>>> + unsigned long parent_rate)
>>> +{
>>> + unsigned int div, value;
>>> + unsigned long flags = 0;
>>> + u32 data;
>>> + struct hi6220_clk_divider *dclk = to_hi6220_clk_divider(hw);
>>> +
>>> + div = parent_rate / rate;
>>> +
>>> + if (!hi6220_is_valid_div(dclk->table, div))
>>> + return -EINVAL;
>>> +
>>> + value = hi6220_get_table_val(dclk->table, div);
>>> +
>>> + if (value > div_mask(dclk->width))
>>> + value = div_mask(dclk->width);
>>> +
>>> + if (dclk->lock)
>>> + spin_lock_irqsave(dclk->lock, flags);
>>> +
>>> + data = readl_relaxed(dclk->reg);
>>> + data &= ~(div_mask(dclk->width) << dclk->shift);
>>> + data |= value << dclk->shift;
>>> + data |= dclk->mask;
>>> +
>>> + writel_relaxed(data, dclk->reg);
>>> +
>>> + if (dclk->lock)
>>> + spin_unlock_irqrestore(dclk->lock, flags);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static struct clk_ops hi6220_clkdiv_ops = {
>>> + .recalc_rate = hi6220_clkdiv_recalc_rate,
>>> + .round_rate = hi6220_clkdiv_round_rate,
>>> + .set_rate = hi6220_clkdiv_set_rate,
>>> +};
>>> +
>>> +struct clk *hi6220_register_clkdiv(struct device *dev, const char *name,
>>> + const char *parent_name, unsigned long flags, void __iomem *reg,
>>> + u8 shift, u8 width, u32 mask_bit, spinlock_t *lock)
>>> +{
>>> + struct hi6220_clk_divider *div;
>>> + struct clk *clk;
>>> + struct clk_init_data init;
>>> + struct clk_div_table *table;
>>> + u32 max_div, min_div;
>>> + int i;
>>> +
>>> + /* allocate the divider */
>>> + div = kzalloc(sizeof(struct hi6220_clk_divider), GFP_KERNEL);
>>> + if (!div) {
>>> + pr_err("%s: could not allocate divider clk\n", __func__);
>>> + return ERR_PTR(-ENOMEM);
>>> + }
>>> +
>>> + /* Init the divider table */
>>> + max_div = div_mask(width) + 1;
>>> + min_div = 1;
>>> +
>>> + table = kzalloc(sizeof(struct clk_div_table) * (max_div + 1), GFP_KERNEL);
>>> + if (!table) {
>>> + kfree(div);
>>> + pr_err("%s: failed to alloc divider table!\n", __func__);
>>> + return ERR_PTR(-ENOMEM);
>>> + }
>>> +
>>> + for (i = 0; i < max_div; i++) {
>>> + table[i].div = min_div + i;
>>> + table[i].val = table[i].div - 1;
>>> + }
>>> +
>>> + init.name = name;
>>> + init.ops = &hi6220_clkdiv_ops;
>>> + init.flags = flags | CLK_IS_BASIC;
>>> + init.parent_names = parent_name ? &parent_name : NULL;
>>> + init.num_parents = parent_name ? 1 : 0;
>>> +
>>> + /* struct hi6220_clk_divider assignments */
>>> + div->reg = reg;
>>> + div->shift = shift;
>>> + div->width = width;
>>> + div->mask = mask_bit ? BIT(mask_bit) : 0;
>>> + div->lock = lock;
>>> + div->hw.init = &init;
>>> + div->table = table;
>>> +
>>> + /* register the clock */
>>> + clk = clk_register(dev, &div->hw);
>>> +
>>> + if (IS_ERR(clk)) {
>>> + kfree(table);
>>> + kfree(div);
>>> + }
>>> +
>>> + return clk;
>>> +}
>>> diff --git a/include/dt-bindings/clock/hi6220-clock.h b/include/dt-bindings/clock/hi6220-clock.h
>>> new file mode 100644
>>> index 0000000..05033e7
>>> --- /dev/null
>>> +++ b/include/dt-bindings/clock/hi6220-clock.h
>>> @@ -0,0 +1,172 @@
>>> +/*
>>> + * Copyright (c) 2015 Hisilicon Limited.
>>> + *
>>> + * Author: Bintian Wang <[email protected]>
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify
>>> + * it under the terms of the GNU General Public License version 2 as
>>> + * published by the Free Software Foundation.
>>> + */
>>> +
>>> +#ifndef __DT_BINDINGS_CLOCK_HI6220_H
>>> +#define __DT_BINDINGS_CLOCK_HI6220_H
>>> +
>>> +/* clk in AO (always on) controller */
>>> +#define HI6220_NONE_CLOCK 0
>>> +
>>> +/* fixed rate clocks */
>>> +#define HI6220_REF32K 1
>>> +#define HI6220_CLK_TCXO 2
>>> +#define HI6220_MMC1_PAD 3
>>> +#define HI6220_MMC2_PAD 4
>>> +#define HI6220_MMC0_PAD 5
>>> +#define HI6220_PLL_BBP 6
>>> +#define HI6220_PLL_GPU 7
>>> +#define HI6220_PLL1_DDR 8
>>> +#define HI6220_PLL_SYS 9
>>> +#define HI6220_PLL_SYS_MEDIA 10
>>> +#define HI6220_DDR_SRC 11
>>> +#define HI6220_PLL_MEDIA 12
>>> +#define HI6220_PLL_DDR 13
>>> +
>>> +/* fixed factor clocks */
>>> +#define HI6220_300M 16
>>> +#define HI6220_150M 17
>>> +#define HI6220_PICOPHY_SRC 18
>>> +#define HI6220_MMC0_SRC_SEL 19
>>> +#define HI6220_MMC1_SRC_SEL 20
>>> +#define HI6220_MMC2_SRC_SEL 21
>>> +#define HI6220_VPU_CODEC 22
>>> +#define HI6220_MMC0_SMP 23
>>> +#define HI6220_MMC1_SMP 24
>>> +#define HI6220_MMC2_SMP 25
>>> +
>>> +/* gate clocks */
>>> +#define HI6220_WDT0_PCLK 28
>>> +#define HI6220_WDT1_PCLK 29
>>> +#define HI6220_WDT2_PCLK 30
>>> +#define HI6220_TIMER0_PCLK 31
>>> +#define HI6220_TIMER1_PCLK 32
>>> +#define HI6220_TIMER2_PCLK 33
>>> +#define HI6220_TIMER3_PCLK 34
>>> +#define HI6220_TIMER4_PCLK 35
>>> +#define HI6220_TIMER5_PCLK 36
>>> +#define HI6220_TIMER6_PCLK 37
>>> +#define HI6220_TIMER7_PCLK 38
>>> +#define HI6220_TIMER8_PCLK 39
>>> +#define HI6220_UART0_PCLK 40
>>> +
>>> +#define HI6220_AO_NR_CLKS 48
>>> +
>>> +/* clk in systrl */
>>> +/* gate clock */
>>> +#define HI6220_MMC0_CLK 1
>>> +#define HI6220_MMC0_CIUCLK 2
>>> +#define HI6220_MMC1_CLK 3
>>> +#define HI6220_MMC1_CIUCLK 4
>>> +#define HI6220_MMC2_CLK 5
>>> +#define HI6220_MMC2_CIUCLK 6
>>> +#define HI6220_USBOTG_HCLK 7
>>> +#define HI6220_CLK_PICOPHY 8
>>> +#define HI6220_HIFI 9
>>> +#define HI6220_DACODEC_PCLK 10
>>> +#define HI6220_EDMAC_ACLK 11
>>> +#define HI6220_CS_ATB 12
>>> +#define HI6220_I2C0_CLK 13
>>> +#define HI6220_I2C1_CLK 14
>>> +#define HI6220_I2C2_CLK 15
>>> +#define HI6220_I2C3_CLK 16
>>> +#define HI6220_UART1_PCLK 17
>>> +#define HI6220_UART2_PCLK 18
>>> +#define HI6220_UART3_PCLK 19
>>> +#define HI6220_UART4_PCLK 20
>>> +#define HI6220_SPI_CLK 21
>>> +#define HI6220_MMU_CLK 22
>>> +#define HI6220_HIFI_SEL 23
>>> +#define HI6220_MMC0_SYSPLL 24
>>> +#define HI6220_MMC1_SYSPLL 25
>>> +#define HI6220_MMC2_SYSPLL 26
>>> +#define HI6220_MMC0_SEL 27
>>> +#define HI6220_MMC1_SEL 28
>>> +#define HI6220_BBPPLL_SEL 29
>>> +#define HI6220_MEDIA_PLL_SRC 30
>>> +#define HI6220_MMC2_SEL 31
>>> +#define HI6220_CS_ATB_SYSPLL 32
>>> +
>>> +/* mux clocks */
>>> +#define HI6220_MMC0_SRC 35
>>> +#define HI6220_MMC0_SMP_IN 36
>>> +#define HI6220_MMC1_SRC 37
>>> +#define HI6220_MMC1_SMP_IN 38
>>> +#define HI6220_MMC2_SRC 39
>>> +#define HI6220_MMC2_SMP_IN 40
>>> +#define HI6220_HIFI_SRC 41
>>> +#define HI6220_UART1_SRC 42
>>> +#define HI6220_UART2_SRC 43
>>> +#define HI6220_UART3_SRC 44
>>> +#define HI6220_UART4_SRC 45
>>> +#define HI6220_MMC0_MUX0 46
>>> +#define HI6220_MMC1_MUX0 47
>>> +#define HI6220_MMC2_MUX0 48
>>> +#define HI6220_MMC0_MUX1 49
>>> +#define HI6220_MMC1_MUX1 50
>>> +#define HI6220_MMC2_MUX1 51
>>> +
>>> +/* divider clocks */
>>> +#define HI6220_CLK_BUS 54
>>> +#define HI6220_MMC0_DIV 55
>>> +#define HI6220_MMC1_DIV 56
>>> +#define HI6220_MMC2_DIV 57
>>> +#define HI6220_HIFI_DIV 58
>>> +#define HI6220_BBPPLL0_DIV 59
>>> +#define HI6220_CS_DAPB 60
>>> +#define HI6220_CS_ATB_DIV 61
>>> +
>>> +#define HI6220_SYS_NR_CLKS 64
>>> +
>>> +/* clk in media controller */
>>> +/* gate clocks */
>>> +#define HI6220_DSI_PCLK 1
>>> +#define HI6220_G3D_PCLK 2
>>> +#define HI6220_ACLK_CODEC_VPU 3
>>> +#define HI6220_ISP_SCLK 4
>>> +#define HI6220_ADE_CORE 5
>>> +#define HI6220_MED_MMU 6
>>> +#define HI6220_CFG_CSI4PHY 7
>>> +#define HI6220_CFG_CSI2PHY 8
>>> +#define HI6220_ISP_SCLK_GATE 9
>>> +#define HI6220_ISP_SCLK_GATE1 10
>>> +#define HI6220_ADE_CORE_GATE 11
>>> +#define HI6220_CODEC_VPU_GATE 12
>>> +#define HI6220_MED_SYSPLL 13
>>> +
>>> +/* mux clocks */
>>> +#define HI6220_1440_1200 20
>>> +#define HI6220_1000_1200 21
>>> +#define HI6220_1000_1440 22
>>> +
>>> +/* divider clocks */
>>> +#define HI6220_CODEC_JPEG 30
>>> +#define HI6220_ISP_SCLK_SRC 31
>>> +#define HI6220_ISP_SCLK1 32
>>> +#define HI6220_ADE_CORE_SRC 33
>>> +#define HI6220_ADE_PIX_SRC 34
>>> +#define HI6220_G3D_CLK 35
>>> +#define HI6220_CODEC_VPU_SRC 36
>>> +
>>> +#define HI6220_MEDIA_NR_CLKS 40
>>> +
>>> +/* clk in power controller */
>>> +/* gate clocks */
>>> +#define HI6220_PLL_GPU_GATE 1
>>> +#define HI6220_PLL1_DDR_GATE 2
>>> +#define HI6220_PLL_DDR_GATE 3
>>> +#define HI6220_PLL_MEDIA_GATE 4
>>> +#define HI6220_PLL0_BBP_GATE 5
>>> +
>>> +/* divider clocks */
>>> +#define HI6220_DDRC_SRC 10
>>> +#define HI6220_DDRC_AXI1 11
>>> +
>>> +#define HI6220_POWER_NR_CLKS 16
>>> +#endif
>>> --
>>> 1.7.9.5
>>>
>>>
>>> _______________________________________________
>>> linux-arm-kernel mailing list
>>> [email protected]
>>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>>
>> Cheers,
>>
>> - Tyler
>>
>> [1] http://kernelci.org/build/tbaker/kernel/v3.19-rc7-8241-g7b08f7b75c01/
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
>> the body of a message to [email protected]
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>> Please read the FAQ at http://www.tux.org/lkml/
>
>
>
> --
> Best Regards,
>
> Bintian
> ===========================
> Don't be nervous, just be happy!

Cheers,

- Tyler

2015-02-09 03:26:59

by Brent Wang

[permalink] [raw]
Subject: Re: [PATCH 3/3] arm64: dts: Add dts files for Hisilicon Hi6220 SoC

Hello Marc,

2015-02-06 17:07 GMT+08:00 Marc Zyngier <[email protected]>:
> On 06/02/15 08:42, Brent Wang wrote:
>
> [...]
>
>>>
>>>> + <0x0 0xf6802000 0x0 0x2000>, /* GICC */
>>>> + <0x0 0xf6804000 0x0 0x2000>, /* GICH */
>>>> + <0x0 0xf6806000 0x0 0x2000>; /* GICV */
>>>
>>> I guess no-one's bothered to consider 64k pages?
>>>
>>> Given GICH and GICV, I hope that this platform is booted at EL2?
>> Transfer from EL3 to EL1 directly, keep these two just for future use.
>
> That's a real shame, as it keeps users away from some key aspects of the
> ARMv8 architecture.
>
>>>
>>>> + #interrupt-cells = <3>;
>>>> + #address-cells = <0>;
>>>> + interrupt-controller;
>
> And if you're keeping GICH/GICV, where is the maintenance interrupt?
>
>>>> + };
>>>> +
>>>> +
>>>> + timer {
>>>> + compatible = "arm,armv8-timer";
>>>> + interrupt-parent = <&gic>;
>>>> + interrupts = <1 13 0xff08>,
>>>> + <1 14 0xff08>,
>>>> + <1 11 0xff08>,
>>>> + <1 10 0xff08>;
>>>> + clock-frequency = <1200000>;
>>>> + };
>>>
>>> NAK. Fix your firmware to configure CNTFRQ, on all CPUs.
>> Fix in next version, maybe it will take some time to change firmware.
>
> While you're at it, make sure CNTVOFF_EL2 is set to zero on all CPUs
> before dropping to EL1. This tends to be overlooked.
Thank you for reminding me, I will keep that in mind.

Thanks,

>
> Thanks,
>
> M.
> --
> Jazz is not dead. It just smells funny...

--
Best Regards,

Bintian
===========================
Don't be nervous, just be happy!

2015-02-10 13:38:11

by Mark Rutland

[permalink] [raw]
Subject: Re: [PATCH 3/3] arm64: dts: Add dts files for Hisilicon Hi6220 SoC

On Fri, Feb 06, 2015 at 03:37:52PM +0000, Brent Wang wrote:
> Hello Mark,
>
> 2015-02-06 18:44 GMT+08:00 Mark Rutland <[email protected]>:
> > On Fri, Feb 06, 2015 at 08:42:22AM +0000, Brent Wang wrote:
> >> Hello Mark,
> >>
> >> 2015-02-06 3:30 GMT+08:00 Mark Rutland <[email protected]>:
> >> > On Thu, Feb 05, 2015 at 09:24:37AM +0000, Bintian Wang wrote:
> >> >> Add initial dtsi file to support Hisilicon Hi6220 SoC with
> >> >> support of Octal core CPUs in two clusters and each cluster
> >> >> has quard Cortex-A53.
> >> >>
> >> >> We now use the "spin-table" method for SMP, and it will be
> >> >> changed to PSCI later.
> >> >
> >> > If that's the case, please don't place the enable-method and related
> >> > properties in this file. Get your bootloader to add the appropriate
> >> > properties for its boot protocol.
> >> >
> >> > When is PSCI likely to appear?
> >> PSCI is under development.
> >
> > Sure. Do you have an estimate as to when it will appear?
> Another team will do the job, I can not give my estimation now.

Ok.

> > What are you using for your PSCI implementation? The ARM Trusted
> > Firmware?
> Yes, ATF.
> >
> > How are you testing it?
> I think cpu hotplug can test it.
>
> >
> >> > Are we certain of the split between components the PSCI implementation
> >> > must touch and those the kernel must touch?
> >> >
> >> >> Also add dts file to support HiKey development board which
> >> >> based on Hi6220 SoC and document the devicetree bindings.
> >> >>
> >> >> These dts files will be changed later and more nodes will be
> >> >> added to describe other devices.
> >> >
> >> > How is this going to be changed other than the addition of nodes?
> >> >
> >> > Will this DTB continue to work in future? Or do you intend to make
> >> > changes that will break support?
> >> My original idea is: use spin-table for SMP now, when firmware is OK to
> >> support PSCI, we submit another patch to replace the spin-table with PSCI.
> >
> > For any users who have not updated their FW, this will break booting.
> >
> > This is why I suggest having hte bootloader/FW fill this in as it should
> > know what enable-method the FW supports.
> >
> >> If DTB should continue to work in the future, we really need to remove
> >> the spin-table
> >> from current dts file, how about just enable one core now?
> >>
> >> Which one do you favor or any other suggestion?
> >
> > If spin-table is just for testing while you await PSCI, drop spin-table
> > from the dts for now.
> So, just booting one core may be the right choice now, right?

Without an enable-method for secondary CPUs, that will be all that's
possible. If your FW/bootlaoder injects the appropriate enable-method,
then you could gain spin-table based SMP bringup while awaiting PSCI,
without there being a DTB compatibility issue.

[...]

> >> >> + pm_ctrl: pm_ctrl {
> >> >> + compatible = "hisilicon,pmctrl", "syscon";
> >> >> + #address-cells = <1>;
> >> >> + #size-cells = <1>;
> >> >> + reg = <0x0 0xf7032000 0x0 0x1000>;
> >> >> + ranges = <0 0x0 0xf7032000 0x1000>;
> >> >> +
> >> >> + clock_power: clock3@0 {
> >> >> + compatible = "hisilicon,hi6220-clock-power";
> >> >> + reg = <0 0x1000>;
> >> >> + #clock-cells = <1>;
> >> >> + };
> >> >> + };
> >> >
> >> > I really doesn't see the point in having a sub-device that covers the
> >> > entirely of the register space of the containing node, and that being
> >> > the case I am extremely concerned that the containers are marked as
> >> > syscon compatible.
> >> The SoC clocks are designed and placed under different system controllers,
> >> so I define corresponding nodes under different controllers for clock operation.
> >
> > What I'm concerned wit hhere is that the pm_ctrl node and the clock3@0
> > sub-node have the _exact_ same register space.
> >
> > Given this should mean that the clock3@0 node owns that register space,
> > having the container node export this as syscon does not make sense. And
> > the split between pm_ctrl and clock3@) doesn't seem to make sense given
> > they cover the same space.
> I understand your worry and will find the max offset of those clocks
> under this controller.
>
> >
> > As I asked before, why is pm_ctrl marked as a syscon, and what's the
> > point of the separate sub-node?
> There is no big difference between pm_ctrl and other controller, they
> are all designed as
> the base address to control some functions of other modules (certainly
> include some clock gates).

Are they just different instances of the same IP block, or are there
fundamental differences between them?

> Maybe only one node is enough, not one node plus one sub-node ?

At least in the case above, I cannot see a reason to have more than a
single node without a child.

Thanks,
Mark.

2015-02-10 14:20:49

by Brent Wang

[permalink] [raw]
Subject: Re: [PATCH 3/3] arm64: dts: Add dts files for Hisilicon Hi6220 SoC

Hello Mark,

2015-02-10 21:37 GMT+08:00 Mark Rutland <[email protected]>:
> On Fri, Feb 06, 2015 at 03:37:52PM +0000, Brent Wang wrote:
>> Hello Mark,
>>
>> 2015-02-06 18:44 GMT+08:00 Mark Rutland <[email protected]>:
>> > On Fri, Feb 06, 2015 at 08:42:22AM +0000, Brent Wang wrote:
>> >> Hello Mark,
>> >>
>> >> 2015-02-06 3:30 GMT+08:00 Mark Rutland <[email protected]>:
>> >> > On Thu, Feb 05, 2015 at 09:24:37AM +0000, Bintian Wang wrote:
>> >> >> Add initial dtsi file to support Hisilicon Hi6220 SoC with
>> >> >> support of Octal core CPUs in two clusters and each cluster
>> >> >> has quard Cortex-A53.
>> >> >>
>> >> >> We now use the "spin-table" method for SMP, and it will be
>> >> >> changed to PSCI later.
>> >> >
>> >> > If that's the case, please don't place the enable-method and related
>> >> > properties in this file. Get your bootloader to add the appropriate
>> >> > properties for its boot protocol.
>> >> >
>> >> > When is PSCI likely to appear?
>> >> PSCI is under development.
>> >
>> > Sure. Do you have an estimate as to when it will appear?
>> Another team will do the job, I can not give my estimation now.
>
> Ok.
>
>> > What are you using for your PSCI implementation? The ARM Trusted
>> > Firmware?
>> Yes, ATF.
>> >
>> > How are you testing it?
>> I think cpu hotplug can test it.
>>
>> >
>> >> > Are we certain of the split between components the PSCI implementation
>> >> > must touch and those the kernel must touch?
>> >> >
>> >> >> Also add dts file to support HiKey development board which
>> >> >> based on Hi6220 SoC and document the devicetree bindings.
>> >> >>
>> >> >> These dts files will be changed later and more nodes will be
>> >> >> added to describe other devices.
>> >> >
>> >> > How is this going to be changed other than the addition of nodes?
>> >> >
>> >> > Will this DTB continue to work in future? Or do you intend to make
>> >> > changes that will break support?
>> >> My original idea is: use spin-table for SMP now, when firmware is OK to
>> >> support PSCI, we submit another patch to replace the spin-table with PSCI.
>> >
>> > For any users who have not updated their FW, this will break booting.
>> >
>> > This is why I suggest having hte bootloader/FW fill this in as it should
>> > know what enable-method the FW supports.
>> >
>> >> If DTB should continue to work in the future, we really need to remove
>> >> the spin-table
>> >> from current dts file, how about just enable one core now?
>> >>
>> >> Which one do you favor or any other suggestion?
>> >
>> > If spin-table is just for testing while you await PSCI, drop spin-table
>> > from the dts for now.
>> So, just booting one core may be the right choice now, right?
>
> Without an enable-method for secondary CPUs, that will be all that's
> possible. If your FW/bootlaoder injects the appropriate enable-method,
> then you could gain spin-table based SMP bringup while awaiting PSCI,
> without there being a DTB compatibility issue.
For DTB compatibility issue, how about just describe one core in dts
file? when PSCI
is OK, we can add the CPU topology to the dts file again.

>
> [...]
>
>> >> >> + pm_ctrl: pm_ctrl {
>> >> >> + compatible = "hisilicon,pmctrl", "syscon";
>> >> >> + #address-cells = <1>;
>> >> >> + #size-cells = <1>;
>> >> >> + reg = <0x0 0xf7032000 0x0 0x1000>;
>> >> >> + ranges = <0 0x0 0xf7032000 0x1000>;
>> >> >> +
>> >> >> + clock_power: clock3@0 {
>> >> >> + compatible = "hisilicon,hi6220-clock-power";
>> >> >> + reg = <0 0x1000>;
>> >> >> + #clock-cells = <1>;
>> >> >> + };
>> >> >> + };
>> >> >
>> >> > I really doesn't see the point in having a sub-device that covers the
>> >> > entirely of the register space of the containing node, and that being
>> >> > the case I am extremely concerned that the containers are marked as
>> >> > syscon compatible.
>> >> The SoC clocks are designed and placed under different system controllers,
>> >> so I define corresponding nodes under different controllers for clock operation.
>> >
>> > What I'm concerned wit hhere is that the pm_ctrl node and the clock3@0
>> > sub-node have the _exact_ same register space.
>> >
>> > Given this should mean that the clock3@0 node owns that register space,
>> > having the container node export this as syscon does not make sense. And
>> > the split between pm_ctrl and clock3@) doesn't seem to make sense given
>> > they cover the same space.
>> I understand your worry and will find the max offset of those clocks
>> under this controller.
>>
>> >
>> > As I asked before, why is pm_ctrl marked as a syscon, and what's the
>> > point of the separate sub-node?
>> There is no big difference between pm_ctrl and other controller, they
>> are all designed as
>> the base address to control some functions of other modules (certainly
>> include some clock gates).
>
> Are they just different instances of the same IP block, or are there
> fundamental differences between them?
You can understand it as a different instance of the same IP block,
there is no fundamental
differences between them.

>
>> Maybe only one node is enough, not one node plus one sub-node ?
>
> At least in the case above, I cannot see a reason to have more than a
> single node without a child.
I will fix to one node in next version.

Thank you Mark,

BR,

Bintian

>
> Thanks,
> Mark.

2015-02-10 15:28:00

by Mark Rutland

[permalink] [raw]
Subject: Re: [PATCH 3/3] arm64: dts: Add dts files for Hisilicon Hi6220 SoC

> >> >> > Are we certain of the split between components the PSCI implementation
> >> >> > must touch and those the kernel must touch?
> >> >> >
> >> >> >> Also add dts file to support HiKey development board which
> >> >> >> based on Hi6220 SoC and document the devicetree bindings.
> >> >> >>
> >> >> >> These dts files will be changed later and more nodes will be
> >> >> >> added to describe other devices.
> >> >> >
> >> >> > How is this going to be changed other than the addition of nodes?
> >> >> >
> >> >> > Will this DTB continue to work in future? Or do you intend to make
> >> >> > changes that will break support?
> >> >> My original idea is: use spin-table for SMP now, when firmware is OK to
> >> >> support PSCI, we submit another patch to replace the spin-table with PSCI.
> >> >
> >> > For any users who have not updated their FW, this will break booting.
> >> >
> >> > This is why I suggest having hte bootloader/FW fill this in as it should
> >> > know what enable-method the FW supports.
> >> >
> >> >> If DTB should continue to work in the future, we really need to remove
> >> >> the spin-table
> >> >> from current dts file, how about just enable one core now?
> >> >>
> >> >> Which one do you favor or any other suggestion?
> >> >
> >> > If spin-table is just for testing while you await PSCI, drop spin-table
> >> > from the dts for now.
> >> So, just booting one core may be the right choice now, right?
> >
> > Without an enable-method for secondary CPUs, that will be all that's
> > possible. If your FW/bootlaoder injects the appropriate enable-method,
> > then you could gain spin-table based SMP bringup while awaiting PSCI,
> > without there being a DTB compatibility issue.
> For DTB compatibility issue, how about just describe one core in dts
> file? when PSCI
> is OK, we can add the CPU topology to the dts file again.

Given that we won't boot secondary CPUs without an enable-method, we
could leave them in, but in a currently-unusable state. That would allow
a bootloader to patch in the relevant properties to boot them.

If you add the nodes later with PSCI properties, users with existing
firmware will expect their board to boot. So I'd recommendd that the
bootloader patches that in, or that the firmware is ready prior to this
being merged. I suspect that the former is more likely to be possible.

> > [...]
> >
> >> >> >> + pm_ctrl: pm_ctrl {
> >> >> >> + compatible = "hisilicon,pmctrl", "syscon";
> >> >> >> + #address-cells = <1>;
> >> >> >> + #size-cells = <1>;
> >> >> >> + reg = <0x0 0xf7032000 0x0 0x1000>;
> >> >> >> + ranges = <0 0x0 0xf7032000 0x1000>;
> >> >> >> +
> >> >> >> + clock_power: clock3@0 {
> >> >> >> + compatible = "hisilicon,hi6220-clock-power";
> >> >> >> + reg = <0 0x1000>;
> >> >> >> + #clock-cells = <1>;
> >> >> >> + };
> >> >> >> + };
> >> >> >
> >> >> > I really doesn't see the point in having a sub-device that covers the
> >> >> > entirely of the register space of the containing node, and that being
> >> >> > the case I am extremely concerned that the containers are marked as
> >> >> > syscon compatible.
> >> >> The SoC clocks are designed and placed under different system controllers,
> >> >> so I define corresponding nodes under different controllers for clock operation.
> >> >
> >> > What I'm concerned wit hhere is that the pm_ctrl node and the clock3@0
> >> > sub-node have the _exact_ same register space.
> >> >
> >> > Given this should mean that the clock3@0 node owns that register space,
> >> > having the container node export this as syscon does not make sense. And
> >> > the split between pm_ctrl and clock3@) doesn't seem to make sense given
> >> > they cover the same space.
> >> I understand your worry and will find the max offset of those clocks
> >> under this controller.
> >>
> >> >
> >> > As I asked before, why is pm_ctrl marked as a syscon, and what's the
> >> > point of the separate sub-node?
> >> There is no big difference between pm_ctrl and other controller, they
> >> are all designed as
> >> the base address to control some functions of other modules (certainly
> >> include some clock gates).
> >
> > Are they just different instances of the same IP block, or are there
> > fundamental differences between them?
> You can understand it as a different instance of the same IP block,
> there is no fundamental
> differences between them.

Ok. If that's the case each should have the same compatible string.

Thanks,
Mark.

2015-02-11 01:49:29

by Brent Wang

[permalink] [raw]
Subject: Re: [PATCH 3/3] arm64: dts: Add dts files for Hisilicon Hi6220 SoC

Hello Mark,

2015-02-10 23:27 GMT+08:00 Mark Rutland <[email protected]>:
[...]
>> >
>> >> >> >> + pm_ctrl: pm_ctrl {
>> >> >> >> + compatible = "hisilicon,pmctrl", "syscon";
>> >> >> >> + #address-cells = <1>;
>> >> >> >> + #size-cells = <1>;
>> >> >> >> + reg = <0x0 0xf7032000 0x0 0x1000>;
>> >> >> >> + ranges = <0 0x0 0xf7032000 0x1000>;
>> >> >> >> +
>> >> >> >> + clock_power: clock3@0 {
>> >> >> >> + compatible = "hisilicon,hi6220-clock-power";
>> >> >> >> + reg = <0 0x1000>;
>> >> >> >> + #clock-cells = <1>;
>> >> >> >> + };
>> >> >> >> + };
>> >> >> >
>> >> >> > I really doesn't see the point in having a sub-device that covers the
>> >> >> > entirely of the register space of the containing node, and that being
>> >> >> > the case I am extremely concerned that the containers are marked as
>> >> >> > syscon compatible.
>> >> >> The SoC clocks are designed and placed under different system controllers,
>> >> >> so I define corresponding nodes under different controllers for clock operation.
>> >> >
>> >> > What I'm concerned wit hhere is that the pm_ctrl node and the clock3@0
>> >> > sub-node have the _exact_ same register space.
>> >> >
>> >> > Given this should mean that the clock3@0 node owns that register space,
>> >> > having the container node export this as syscon does not make sense. And
>> >> > the split between pm_ctrl and clock3@) doesn't seem to make sense given
>> >> > they cover the same space.
>> >> I understand your worry and will find the max offset of those clocks
>> >> under this controller.
>> >>
>> >> >
>> >> > As I asked before, why is pm_ctrl marked as a syscon, and what's the
>> >> > point of the separate sub-node?
>> >> There is no big difference between pm_ctrl and other controller, they
>> >> are all designed as
>> >> the base address to control some functions of other modules (certainly
>> >> include some clock gates).
>> >
>> > Are they just different instances of the same IP block, or are there
>> > fundamental differences between them?
>> You can understand it as a different instance of the same IP block,
>> there is no fundamental
>> differences between them.
>
> Ok. If that's the case each should have the same compatible string.
Although they have same function, they control different domain, I
should use different compatible string to distinguish different
domains.

Thanks,

Bintian
>
> Thanks,
> Mark.



--
Best Regards,

Bintian
===========================
Don't be nervous, just be happy!

2015-04-12 06:40:51

by Brent Wang

[permalink] [raw]
Subject: Re: [PATCH 3/3] arm64: dts: Add dts files for Hisilicon Hi6220 SoC

Hello Mark,

2015-02-06 16:42 GMT+08:00 Brent Wang <[email protected]>:
[...]
>>
>>> + gic: interrupt-controller@f6800000 {
>>> + compatible = "arm,gic-400", "arm,cortex-a15-gic";
>>
>> Surely there's no need for the "arm,cortex-a15-gic" fallback entry? What
>> am I missing?
> Remove it in next version.
After remove "arm,cortex-a15-gic", I get the following error during
kernel booting:
-----
kvm [1]: Using HYP init bounce page @396d9000
kvm [1]: error: no compatible GIC node found
kvm [1]: error initializing Hyp mode: -19
-----

Check code "virt/kvm/arm/vgic.c", gicv2 only "cortex-a15-gic" and
gicv3 support kvm now,
so I think we should keep it, how about your idea?

Thanks,

Bintian

>>
>>> + reg = <0x0 0xf6801000 0x0 0x1000>, /* GICD */
>>
>> This doesn't match the unit-address.
> Do you mean change to "<0x0 0xf6801000 0 0x1000>" ?
>
>>
>>> + <0x0 0xf6802000 0x0 0x2000>, /* GICC */
>>> + <0x0 0xf6804000 0x0 0x2000>, /* GICH */
>>> + <0x0 0xf6806000 0x0 0x2000>; /* GICV */
>>
>> I guess no-one's bothered to consider 64k pages?
>>
>> Given GICH and GICV, I hope that this platform is booted at EL2?
> Transfer from EL3 to EL1 directly, keep these two just for future use.
>
>>
>>> + #interrupt-cells = <3>;
>>> + #address-cells = <0>;
>>> + interrupt-controller;
>>> + };
>>> +
>>> +
[...]

2015-04-12 10:58:11

by Marc Zyngier

[permalink] [raw]
Subject: Re: [PATCH 3/3] arm64: dts: Add dts files for Hisilicon Hi6220 SoC

On 2015-04-12 07:40, Brent Wang wrote:
> Hello Mark,
>
> 2015-02-06 16:42 GMT+08:00 Brent Wang <[email protected]>:
> [...]
>>>
>>>> + gic: interrupt-controller@f6800000 {
>>>> + compatible = "arm,gic-400", "arm,cortex-a15-gic";
>>>
>>> Surely there's no need for the "arm,cortex-a15-gic" fallback entry?
>>> What
>>> am I missing?
>> Remove it in next version.
> After remove "arm,cortex-a15-gic", I get the following error during
> kernel booting:
> -----
> kvm [1]: Using HYP init bounce page @396d9000
> kvm [1]: error: no compatible GIC node found
> kvm [1]: error initializing Hyp mode: -19
> -----
>
> Check code "virt/kvm/arm/vgic.c", gicv2 only "cortex-a15-gic" and
> gicv3 support kvm now,
> so I think we should keep it, how about your idea?

Please look at commit 0f37247574b3 that is queued for merge in 4.1.
It adds the required compatibility strings to KVM, so Mark is perfectly
right to ask you to drop this "cortex-a15-gic" from your DT.

This DT won't be merged before 4.1 anyway, so there is no point trying
to make it work with older kernels.

Thanks,

M.
--
Fast, cheap, reliable. Pick two.

2015-04-12 13:07:52

by Brent Wang

[permalink] [raw]
Subject: Re: [PATCH 3/3] arm64: dts: Add dts files for Hisilicon Hi6220 SoC

Hello Marc,

2015-04-12 18:57 GMT+08:00 Marc Zyngier <[email protected]>:
> On 2015-04-12 07:40, Brent Wang wrote:
>>
>> Hello Mark,
>>
>> 2015-02-06 16:42 GMT+08:00 Brent Wang <[email protected]>:
>> [...]
>>>>
>>>>
>>>>> + gic: interrupt-controller@f6800000 {
>>>>> + compatible = "arm,gic-400", "arm,cortex-a15-gic";
>>>>
>>>>
>>>> Surely there's no need for the "arm,cortex-a15-gic" fallback entry? What
>>>> am I missing?
>>>
>>> Remove it in next version.
>>
>> After remove "arm,cortex-a15-gic", I get the following error during
>> kernel booting:
>> -----
>> kvm [1]: Using HYP init bounce page @396d9000
>> kvm [1]: error: no compatible GIC node found
>> kvm [1]: error initializing Hyp mode: -19
>> -----
>>
>> Check code "virt/kvm/arm/vgic.c", gicv2 only "cortex-a15-gic" and
>> gicv3 support kvm now,
>> so I think we should keep it, how about your idea?
>
>
> Please look at commit 0f37247574b3 that is queued for merge in 4.1.
> It adds the required compatibility strings to KVM, so Mark is perfectly
> right to ask you to drop this "cortex-a15-gic" from your DT.

Thanks for the information.

> This DT won't be merged before 4.1 anyway, so there is no point trying
> to make it work with older kernels.
>
> Thanks,
>
> M.
> --
> Fast, cheap, reliable. Pick two.



--
Best Regards,

Bintian
===========================
Don't be nervous, just be happy!