diff --git a/arch/arm/boot/dts/hisilicon/Makefile b/arch/arm/boot/dts/hisilicon/Makefile index 9c7f83117b..db8bbbe6d8 100644 --- a/arch/arm/boot/dts/hisilicon/Makefile +++ b/arch/arm/boot/dts/hisilicon/Makefile @@ -20,3 +20,5 @@ dtb-$(CONFIG_ARCH_HI3516DV300) += \ hi3516dv300-demb.dtb dtb-$(CONFIG_ARCH_HI3516CV300) += \ hi3516cv300-demb.dtb +dtb-$(CONFIG_ARCH_HI3516CV200) += \ + hi3516cv200-demb.dtb diff --git a/arch/arm/boot/dts/hisilicon/hi3516cv200-demb.dts b/arch/arm/boot/dts/hisilicon/hi3516cv200-demb.dts new file mode 100644 index 0000000000..cbbb9c036e --- /dev/null +++ b/arch/arm/boot/dts/hisilicon/hi3516cv200-demb.dts @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2016 HiSilicon Technologies Co., Ltd. + * + * Hi3516CV200 DEMO Board (DEMB) reference DT. + * Ported from the vendor 4.9 BSP arch/arm/boot/dts/hi3518ev20x-demb.dts. + * + * Production cameras pair this SoC with single MIPI sensors (IMX291, + * SC2135, JXF22, etc.) at 1080p; reference board is a generic eval kit. + */ + +/dts-v1/; +#include "hi3516cv200.dtsi" + +/ { + model = "Hisilicon Hi3516CV200 DEMO Board"; + compatible = "hisilicon,hi3516cv200"; + + memory { + device_type = "memory"; + /* 64 MiB DDR @ 0x80000000 — production cameras ship with + * 64 MiB total, kernel gets 32 MiB and the upper 32 MiB + * is reserved for the vendor MMZ media allocator (set via + * `mmz=` in the u-boot bootargs). */ + reg = <0x80000000 0x4000000>; + }; + + chosen { + bootargs = "mem=32M console=ttyAMA0,115200 root=/dev/mtdblock3 rootfstype=squashfs init=/init"; + stdout-path = "serial0:115200n8"; + }; +}; + +&uart0 { + status = "okay"; +}; + +&i2c_bus0 { + status = "okay"; +}; + +&spi_bus0 { + status = "okay"; +}; + +&mdio { + phy0: ethernet-phy@1 { + reg = <1>; + /* Most cv200 reference boards use an Internal FE PHY at + * MII address 1. Production boards vary; production DT + * fragments can override via a board-specific overlay. */ + }; +}; + +&hisi_femac { + phy-handle = <&phy0>; + phy-mode = "mii"; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/hisilicon/hi3516cv200.dtsi b/arch/arm/boot/dts/hisilicon/hi3516cv200.dtsi new file mode 100644 index 0000000000..5c537227d6 --- /dev/null +++ b/arch/arm/boot/dts/hisilicon/hi3516cv200.dtsi @@ -0,0 +1,234 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2016 HiSilicon Technologies Co., Ltd. + * + * Hi3516CV200 / Hi3518EV20x V2 SoC family (ARM926EJ-S, ARMv5TE). + * Ported from the vendor 4.9 BSP arch/arm/boot/dts/hi3518ev20x.dtsi + * onto the modern dt-bindings + crg- driver scaffold. The register map + * matches the vendor SDK byte-for-byte; only the dts-level scaffolding + * (skeleton.dtsi removal, clock-frequency on SP804, clock-names on + * MDIO, phy-reset-delays on FEMAC) is modernized. + * + * Sibling SoCs that re-use this dtsi: Hi3518EV200, Hi3518EV201. + */ + +#include + +/* skeleton.dtsi was removed in 4.18; root cells set explicitly below. */ +/ { + #address-cells = <1>; + #size-cells = <1>; + chosen { }; + + aliases { + serial0 = &uart0; + serial1 = &uart1; + serial2 = &uart2; + i2c0 = &i2c_bus0; + i2c1 = &i2c_bus1; + i2c2 = &i2c_bus2; + spi0 = &spi_bus0; + spi1 = &spi_bus1; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,arm926ej-s"; + reg = <0>; + }; + }; + + vic: interrupt-controller@100d0000 { + compatible = "arm,pl190-vic"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x100d0000 0x1000>; + }; + + soc { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + interrupt-parent = <&vic>; + ranges; + + /* Vendor names this node "clock" but the analogous block + * on cv300 is called "crg_ctrl" — keep vendor naming so the + * 4.9-era DT (which we want to be a drop-in) parses + * unchanged. The compatible matches the CRG driver's + * CLK_OF_DECLARE / platform_driver match_table. */ + crg_ctrl: clock@20030000 { + compatible = "hisilicon,hi3518ev20x-clock"; + reg = <0x20030000 0x1000>; + #clock-cells = <1>; + #reset-cells = <2>; + }; + + sys_ctrl: system-controller@20050000 { + compatible = "hisilicon,hi3518ev20x-sysctrl", "syscon"; + reg = <0x20050000 0x1000>; + #clock-cells = <1>; + }; + + reboot { + compatible = "syscon-reboot"; + regmap = <&sys_ctrl>; + offset = <0x4>; + mask = <0xdeadbeef>; + }; + + dual_timer0: dual_timer@20000000 { + compatible = "arm,sp804", "arm,primecell"; + reg = <0x20000000 0x1000>; + interrupts = <3>; + /* SP804 driver in 6.x uses clk_get_rate() which returns + * 0 if the clock provider isn't fully initialized when + * timer inits at start_kernel. clock-frequency + * overrides — matches the 3 MHz fixed-rate the sysctrl + * early init registers. */ + clock-frequency = <3000000>; + clocks = <&sys_ctrl HI3516CV200_TIME0_0_CLK>, + <&sys_ctrl HI3516CV200_TIME0_1_CLK>, + <&crg_ctrl HI3516CV200_SYSAPB_CLK>; + clock-names = "timer0", "timer1", "apb_pclk"; + }; + + dual_timer1: dual_timer@20010000 { + compatible = "arm,sp804", "arm,primecell"; + reg = <0x20010000 0x1000>; + interrupts = <4>; + clock-frequency = <3000000>; + clocks = <&sys_ctrl HI3516CV200_TIME1_2_CLK>, + <&sys_ctrl HI3516CV200_TIME1_3_CLK>, + <&crg_ctrl HI3516CV200_SYSAPB_CLK>; + clock-names = "timer2", "timer3", "apb_pclk"; + status = "disabled"; + }; + + uart0: uart@20080000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x20080000 0x1000>; + interrupts = <5>; + clocks = <&crg_ctrl HI3516CV200_UART0_CLK>; + clock-names = "apb_pclk"; + }; + + uart1: uart@20090000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x20090000 0x1000>; + interrupts = <30>; + clocks = <&crg_ctrl HI3516CV200_UART1_CLK>; + clock-names = "apb_pclk"; + status = "disabled"; + }; + + uart2: uart@200a0000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x200a0000 0x1000>; + interrupts = <25>; + clocks = <&crg_ctrl HI3516CV200_UART2_CLK>; + clock-names = "apb_pclk"; + status = "disabled"; + }; + + i2c_bus0: i2c@200d0000 { + compatible = "hisilicon,hisi-i2c-hisilicon"; + reg = <0x200d0000 0x100>; + interrupts = <20>; + clocks = <&crg_ctrl HI3516CV200_SYSAPB_CLK>; + clock-frequency = <100000>; + status = "disabled"; + }; + + i2c_bus1: i2c@20240000 { + compatible = "hisilicon,hisi-i2c-hisilicon"; + reg = <0x20240000 0x100>; + interrupts = <20>; + clocks = <&crg_ctrl HI3516CV200_SYSAPB_CLK>; + clock-frequency = <100000>; + status = "disabled"; + }; + + i2c_bus2: i2c@20250000 { + compatible = "hisilicon,hisi-i2c-hisilicon"; + reg = <0x20250000 0x100>; + interrupts = <20>; + clocks = <&crg_ctrl HI3516CV200_SYSAPB_CLK>; + clock-frequency = <100000>; + status = "disabled"; + }; + + spi_bus0: spi@200c0000 { + compatible = "arm,pl022", "arm,primecell"; + arm,primecell-periphid = <0x00800022>; + reg = <0x200c0000 0x1000>; + interrupts = <6>; + clocks = <&crg_ctrl HI3516CV200_SPI0_CLK>; + clock-names = "apb_pclk"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + spi_bus1: spi@200e0000 { + compatible = "arm,pl022", "arm,primecell"; + arm,primecell-periphid = <0x00800022>; + reg = <0x200e0000 0x1000>; + interrupts = <7>; + clocks = <&crg_ctrl HI3516CV200_SPI1_CLK>; + clock-names = "apb_pclk"; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + mdio: mdio@10091100 { + compatible = "hisilicon,hisi-femac-mdio"; + reg = <0x10091100 0x10>; + /* modern hisi-femac-mdio uses devm_clk_get(dev,"mdio") + * — needs a NAMED clock, not unnamed. */ + clocks = <&crg_ctrl HI3516CV200_ETH_CLK>; + clock-names = "mdio"; + #address-cells = <1>; + #size-cells = <0>; + }; + + hisi_femac: ethernet@10090000 { + compatible = "hisilicon,hi3518ev20x-femac", + "hisilicon,hisi-femac-v2"; + reg = <0x10090000 0x1000>, <0x10091300 0x200>; + interrupts = <12>; + clocks = <&crg_ctrl HI3516CV200_ETH_CLK>; + resets = <&crg_ctrl 0xec 0>; + reset-names = "mac"; + /* PHY reset delays required by hisi_femac when "phy" + * reset is present. phy-mode + phy-handle set in + * hi3516cv200-demb.dts. */ + hisilicon,phy-reset-delays-us = <10000 10000 30000>; + }; + + fmc: flash-memory-controller@10010000 { + compatible = "hisilicon,hisi-fmc"; + reg = <0x10010000 0x1000>, <0x58000000 0x10000>; + reg-names = "control", "memory"; + clocks = <&crg_ctrl HI3516CV200_FMC_CLK>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + pmux: pinmux@200f0000 { + compatible = "pinctrl-single"; + reg = <0x200f0000 0x108>; + #address-cells = <1>; + #size-cells = <1>; + ranges; + pinctrl-single,register-width = <32>; + pinctrl-single,function-mask = <7>; + }; + }; +}; diff --git a/arch/arm/mach-hibvt/Kconfig b/arch/arm/mach-hibvt/Kconfig index 1651d4797c..5f9284700d 100644 --- a/arch/arm/mach-hibvt/Kconfig +++ b/arch/arm/mach-hibvt/Kconfig @@ -34,6 +34,19 @@ config ARCH_HI3516CV300 Support for HiSilicon Hi3516CV300 camera SoC (ARM926EJ-S single-core, ARMv5TE). +config ARCH_HI3516CV200 + bool "Hisilicon Hi3516CV200 / Hi3518EV20x ARM926EJ-S family" + depends on ARCH_MULTI_V5 && CPU_LITTLE_ENDIAN + select ARM_VIC + select ARM_TIMER_SP804 + select PINCTRL + select COMMON_CLK_HI3516CV200 + select ARCH_HAS_RESET_CONTROLLER + select RESET_CONTROLLER + help + Support for HiSilicon Hi3516CV200 / Hi3518EV20x V2 camera + SoC family (ARM926EJ-S single-core, ARMv5TE). + config ARCH_HI3516CV500 bool "Hisilicon Hi3516CV500 Cortex-A7 family" depends on ARCH_MULTI_V7 diff --git a/drivers/clk/hisilicon/Kconfig b/drivers/clk/hisilicon/Kconfig index 858ccf96f8..7b9ef47dca 100644 --- a/drivers/clk/hisilicon/Kconfig +++ b/drivers/clk/hisilicon/Kconfig @@ -7,6 +7,16 @@ config COMMON_CLK_HI3516CV300 help Build the clock driver for hi3516cv300. +config COMMON_CLK_HI3516CV200 + tristate "HI3516CV200 / Hi3518EV20x Clock Driver" + depends on ARCH_HISI || ARCH_HISI_BVT || COMPILE_TEST + select RESET_HISI + default ARCH_HI3516CV200 + help + Build the clock driver for the V2 family — hi3516cv200, + hi3518ev200, hi3518ev201. Ports the vendor 4.9 BSP clock + topology onto the modern crg- platform_driver scaffold. + config COMMON_CLK_HI3519 tristate "Hi3519 Clock Driver" depends on ARCH_HISI || ARCH_HISI_BVT || COMPILE_TEST diff --git a/drivers/clk/hisilicon/Makefile b/drivers/clk/hisilicon/Makefile index 59f20e63f6..3643b72e39 100644 --- a/drivers/clk/hisilicon/Makefile +++ b/drivers/clk/hisilicon/Makefile @@ -9,6 +9,7 @@ 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_HI3516CV300) += crg-hi3516cv300.o +obj-$(CONFIG_COMMON_CLK_HI3516CV200) += crg-hi3516cv200.o obj-$(CONFIG_COMMON_CLK_HI3519) += clk-hi3519.o obj-$(CONFIG_COMMON_CLK_HI3559A) += clk-hi3559a.o obj-$(CONFIG_COMMON_CLK_HI3660) += clk-hi3660.o diff --git a/drivers/clk/hisilicon/crg-hi3516cv200.c b/drivers/clk/hisilicon/crg-hi3516cv200.c new file mode 100644 index 0000000000..2caf6742c2 --- /dev/null +++ b/drivers/clk/hisilicon/crg-hi3516cv200.c @@ -0,0 +1,333 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Hi3516CV200 / Hi3518EV20x Clock and Reset Generator Driver + * + * Copyright (c) 2016 HiSilicon Technologies Co., Ltd. + * + * Ported from the 4.9 vendor BSP (clk-hi3518ev20x.c) onto the modern + * crg- platform_driver scaffold, mirroring crg-hi3516cv300.c. Keeps the + * vendor DT (hi3518ev20x.dtsi / hi3516cv200.dtsi) compatible without + * modification. V2 generation — ARM926EJ-S, ARMv5TE. + * + * SoC sibling list (all share this CRG layout): Hi3516CV200, + * Hi3518EV200, Hi3518EV201. + */ + +#include +#include +#include +#include +#include +#include +#include "clk.h" +#include "crg.h" +#include "reset.h" + +/* ---------------- CRG block (hisilicon,hi3516cv200-clock) ---------------- */ + +static const struct hisi_fixed_rate_clock hi3516cv200_fixed_rate_clks[] = { + { HI3516CV200_FIXED_3M, "3m", NULL, 0, 3000000, }, + { HI3516CV200_FIXED_6M, "6m", NULL, 0, 6000000, }, + { HI3516CV200_FIXED_24M, "24m", NULL, 0, 24000000, }, + { HI3516CV200_FIXED_25M, "25m", NULL, 0, 25000000, }, + { HI3516CV200_FIXED_27M, "27m", NULL, 0, 27000000, }, + { HI3516CV200_FIXED_37P125M, "37.125m", NULL, 0, 37125000, }, + { HI3516CV200_FIXED_49P5M, "49.5m", NULL, 0, 49500000, }, + { HI3516CV200_FIXED_50M, "50m", NULL, 0, 50000000, }, + { HI3516CV200_FIXED_54M, "54m", NULL, 0, 54000000, }, + { HI3516CV200_FIXED_74P25M, "74.25m", NULL, 0, 74250000, }, + { HI3516CV200_FIXED_99M, "99m", NULL, 0, 99000000, }, + { HI3516CV200_FIXED_125M, "125m", NULL, 0, 125000000, }, + { HI3516CV200_FIXED_148P5M, "148.5m", NULL, 0, 148500000, }, + { HI3516CV200_FIXED_198M, "198m", NULL, 0, 198000000, }, + { HI3516CV200_FIXED_200M, "200m", NULL, 0, 200000000, }, + { HI3516CV200_FIXED_250M, "250m", NULL, 0, 250000000, }, + { HI3516CV200_FIXED_297M, "297m", NULL, 0, 297000000, }, + { HI3516CV200_FIXED_300M, "300m", NULL, 0, 300000000, }, + { HI3516CV200_FIXED_396M, "396m", NULL, 0, 396000000, }, + { HI3516CV200_FIXED_540M, "540m", NULL, 0, 540000000, }, + { HI3516CV200_FIXED_594M, "594m", NULL, 0, 594000000, }, + { HI3516CV200_FIXED_600M, "600m", NULL, 0, 600000000, }, + { HI3516CV200_FIXED_650M, "650m", NULL, 0, 650000000, }, + { HI3516CV200_FIXED_750M, "750m", NULL, 0, 750000000, }, + { HI3516CV200_FIXED_1188M, "1188m", NULL, 0, 1188000000, }, +}; + +static const char *const uart_mux_p[] = { "24m", "6m" }; +static const char *const fmc_mux_p[] = { "24m", "74.25m", "125m", "148.5m", "198m" }; +static const char *const mmc_mux_p[] = { "49.5m" }; +static const char *const eth_mux_p[] = { "297m", "375m" }; + +static u32 uart_mux_table[] = { 0, 1 }; +static u32 fmc_mux_table[] = { 0, 1, 2, 3, 4 }; +static u32 mmc_mux_table[] = { 0 }; +static u32 eth_mux_table[] = { 0, 1 }; + +static const struct hisi_mux_clock hi3516cv200_mux_clks[] = { + { HI3516CV200_UART_MUX, "uart_mux", uart_mux_p, ARRAY_SIZE(uart_mux_p), + CLK_SET_RATE_PARENT, 0xe4, 19, 1, 0, uart_mux_table, }, + { HI3516CV200_FMC_MUX, "fmc_mux", fmc_mux_p, ARRAY_SIZE(fmc_mux_p), + CLK_SET_RATE_PARENT, 0xc0, 2, 3, 0, fmc_mux_table, }, + { HI3516CV200_MMC0_MUX, "mmc0_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p), + CLK_SET_RATE_PARENT, 0xc4, 4, 2, 0, mmc_mux_table, }, + { HI3516CV200_MMC1_MUX, "mmc1_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p), + CLK_SET_RATE_PARENT, 0xc4, 12, 2, 0, mmc_mux_table, }, + { HI3516CV200_ETH_MUX, "eth_mux", eth_mux_p, ARRAY_SIZE(eth_mux_p), + CLK_SET_RATE_PARENT, 0xec, 2, 1, 0, eth_mux_table, }, +}; + +static const struct hisi_divider_clock hi3516cv200_div_clks[] = { + { HI3516CV200_SYSAPB_CLK, "sysapb", "50m", 0, 0x30, 0, 1, 0, NULL, }, +}; + +static const struct hisi_gate_clock hi3516cv200_gate_clks[] = { + /* uart */ + { HI3516CV200_UART0_CLK, "clk_uart0", "uart_mux", CLK_SET_RATE_PARENT, 0xe4, 15, 0, }, + { HI3516CV200_UART1_CLK, "clk_uart1", "uart_mux", CLK_SET_RATE_PARENT, 0xe4, 16, 0, }, + { HI3516CV200_UART2_CLK, "clk_uart2", "uart_mux", CLK_SET_RATE_PARENT, 0xe4, 17, 0, }, + { HI3516CV200_UART3_CLK, "clk_uart3", "uart_mux", CLK_SET_RATE_PARENT, 0xe4, 18, 0, }, + /* spi */ + { HI3516CV200_SPI0_CLK, "clk_spi0", "50m", CLK_SET_RATE_PARENT, 0xe4, 13, 0, }, + { HI3516CV200_SPI1_CLK, "clk_spi1", "50m", CLK_SET_RATE_PARENT, 0xe4, 14, 0, }, + /* fmc + mmc */ + { HI3516CV200_FMC_CLK, "clk_fmc", "fmc_mux", CLK_SET_RATE_PARENT, 0xc0, 1, 0, }, + { HI3516CV200_MMC0_CLK, "clk_mmc0", "mmc0_mux", CLK_SET_RATE_PARENT, 0xc4, 1, 0, }, + { HI3516CV200_MMC1_CLK, "clk_mmc1", "mmc1_mux", CLK_SET_RATE_PARENT, 0xc4, 9, 0, }, + /* ethernet */ + { HI3516CV200_ETH_CLK, "clk_eth", "eth_mux", 0, 0xec, 1, 0, }, + /* dmac */ + { HI3516CV200_DMAC_CLK, "clk_dmac", NULL, 0, 0xd8, 5, 0, }, + /* usb (both UTMI and HRST gate bits) */ + { HI3516CV200_USB2_CTRL_UTMI0_REQ, "clk_usb2_utmi0_req", NULL, + CLK_SET_RATE_PARENT, 0xb8, 11, 1, }, + { HI3516CV200_USB2_HRST_REQ, "clk_usb2_hrst_req", NULL, + CLK_SET_RATE_PARENT, 0xb8, 12, 1, }, +}; + +static struct hisi_clock_data *hi3516cv200_clk_register(struct platform_device *pdev) +{ + struct hisi_clock_data *clk_data; + int ret; + + clk_data = hisi_clk_alloc(pdev, HI3516CV200_CRG_NR_CLKS); + if (!clk_data) + return ERR_PTR(-ENOMEM); + + ret = hisi_clk_register_fixed_rate(hi3516cv200_fixed_rate_clks, + ARRAY_SIZE(hi3516cv200_fixed_rate_clks), clk_data); + if (ret) + return ERR_PTR(ret); + + ret = hisi_clk_register_mux(hi3516cv200_mux_clks, + ARRAY_SIZE(hi3516cv200_mux_clks), clk_data); + if (ret) + goto unregister_fixed_rate; + + ret = hisi_clk_register_divider(hi3516cv200_div_clks, + ARRAY_SIZE(hi3516cv200_div_clks), clk_data); + if (ret) + goto unregister_mux; + + ret = hisi_clk_register_gate(hi3516cv200_gate_clks, + ARRAY_SIZE(hi3516cv200_gate_clks), clk_data); + if (ret) + goto unregister_divider; + + ret = of_clk_add_provider(pdev->dev.of_node, + of_clk_src_onecell_get, &clk_data->clk_data); + if (ret) + goto unregister_gate; + + return clk_data; + +unregister_gate: + hisi_clk_unregister_gate(hi3516cv200_gate_clks, + ARRAY_SIZE(hi3516cv200_gate_clks), clk_data); +unregister_divider: + /* hisi_clk_unregister_divider() helper not exported; rely on probe cleanup. */ +unregister_mux: + hisi_clk_unregister_mux(hi3516cv200_mux_clks, + ARRAY_SIZE(hi3516cv200_mux_clks), clk_data); +unregister_fixed_rate: + hisi_clk_unregister_fixed_rate(hi3516cv200_fixed_rate_clks, + ARRAY_SIZE(hi3516cv200_fixed_rate_clks), clk_data); + return ERR_PTR(ret); +} + +static void hi3516cv200_clk_unregister(struct platform_device *pdev) +{ + struct hisi_crg_dev *crg = platform_get_drvdata(pdev); + + of_clk_del_provider(pdev->dev.of_node); + + hisi_clk_unregister_gate(hi3516cv200_gate_clks, + ARRAY_SIZE(hi3516cv200_gate_clks), crg->clk_data); + hisi_clk_unregister_mux(hi3516cv200_mux_clks, + ARRAY_SIZE(hi3516cv200_mux_clks), crg->clk_data); + hisi_clk_unregister_fixed_rate(hi3516cv200_fixed_rate_clks, + ARRAY_SIZE(hi3516cv200_fixed_rate_clks), crg->clk_data); +} + +static const struct hisi_crg_funcs hi3516cv200_crg_funcs = { + .register_clks = hi3516cv200_clk_register, + .unregister_clks = hi3516cv200_clk_unregister, +}; + +/* SP804 dual-timer is wired up before platform_driver probing. Register + * the minimum set of clocks that early consumers (SP804, PL011 console, + * FEMAC ethernet) demand via CLK_OF_DECLARE. Same approach cv300 uses. */ +static const struct hisi_fixed_rate_clock hi3516cv200_crg_early_fixed[] = { + { HI3516CV200_SYSAPB_CLK, "sysapb_early", NULL, 0, 50000000, }, + { HI3516CV200_UART0_CLK, "uart0_early", NULL, 0, 24000000, }, + { HI3516CV200_UART1_CLK, "uart1_early", NULL, 0, 24000000, }, + { HI3516CV200_UART2_CLK, "uart2_early", NULL, 0, 24000000, }, + { HI3516CV200_UART3_CLK, "uart3_early", NULL, 0, 24000000, }, + { HI3516CV200_ETH_CLK, "eth_early", NULL, 0, 50000000, }, +}; + +/* Minimal no-op reset controller — femac and other drivers may request + * reset_control on probe; without a registered provider, ethernet + * defers forever. Mirror cv300 with explicit 2-cell xlate so + * reset_controller_register doesn't force of_reset_n_cells = 1. */ + +static int hi3516cv200_crg_reset_noop(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return 0; +} + +static const struct reset_control_ops hi3516cv200_crg_reset_ops = { + .reset = hi3516cv200_crg_reset_noop, + .assert = hi3516cv200_crg_reset_noop, + .deassert = hi3516cv200_crg_reset_noop, +}; + +static int hi3516cv200_crg_reset_xlate(struct reset_controller_dev *rcdev, + const struct of_phandle_args *spec) +{ + return (spec->args[0] << 8) | (spec->args[1] & 0xff); +} + +static struct reset_controller_dev hi3516cv200_crg_reset_rcdev = { + .ops = &hi3516cv200_crg_reset_ops, + .nr_resets = 0x40000, + .of_reset_n_cells = 2, + .of_xlate = hi3516cv200_crg_reset_xlate, +}; + +static void __init hi3516cv200_crg_early_init(struct device_node *np) +{ + struct hisi_clock_data *clk_data; + + pr_info("hi3516cv200-clk: CLK_OF_DECLARE early init\n"); + clk_data = hisi_clk_init(np, HI3516CV200_CRG_NR_CLKS); + if (!clk_data) { + pr_err("hi3516cv200-clk: hisi_clk_init FAILED\n"); + return; + } + hisi_clk_register_fixed_rate(hi3516cv200_crg_early_fixed, + ARRAY_SIZE(hi3516cv200_crg_early_fixed), clk_data); + + hi3516cv200_crg_reset_rcdev.of_node = np; + hi3516cv200_crg_reset_rcdev.owner = THIS_MODULE; + if (reset_controller_register(&hi3516cv200_crg_reset_rcdev) < 0) + pr_err("hi3516cv200-clk: reset controller register failed\n"); +} +CLK_OF_DECLARE(hi3516cv200_clk_early, "hisilicon,hi3518ev20x-clock", + hi3516cv200_crg_early_init); + +/* ---------------- sys controller block (sysctrl@20050000) ---------------- */ + +/* SP804 timer DT references sysctrl-exposed TIME0_0..TIME1_3 clocks. + * Timer init runs at start_kernel — well before platform_driver probing. + * Register the timer clocks as fixed-rate 3 MHz (the value the vendor + * mux ultimately selects via timer_mux_p={"3m", "apb"} entry 0). + * Mirrors cv300's sysctrl_early_init exactly. */ +static const struct hisi_fixed_rate_clock hi3516cv200_sysctrl_early_fixed[] = { + { HI3516CV200_TIME0_0_CLK, "timer0_0_early", NULL, 0, 3000000, }, + { HI3516CV200_TIME0_1_CLK, "timer0_1_early", NULL, 0, 3000000, }, + { HI3516CV200_TIME1_2_CLK, "timer1_2_early", NULL, 0, 3000000, }, + { HI3516CV200_TIME1_3_CLK, "timer1_3_early", NULL, 0, 3000000, }, +}; + +static void __init hi3516cv200_sysctrl_early_init(struct device_node *np) +{ + struct hisi_clock_data *clk_data; + + pr_info("hi3516cv200-sys: CLK_OF_DECLARE early init\n"); + clk_data = hisi_clk_init(np, HI3516CV200_SC_NR_CLKS); + if (!clk_data) { + pr_err("hi3516cv200-sys: hisi_clk_init FAILED\n"); + return; + } + hisi_clk_register_fixed_rate(hi3516cv200_sysctrl_early_fixed, + ARRAY_SIZE(hi3516cv200_sysctrl_early_fixed), clk_data); +} +CLK_OF_DECLARE(hi3516cv200_sysctrl_early, "hisilicon,hi3518ev20x-sysctrl", + hi3516cv200_sysctrl_early_init); + +/* ---------------- platform driver (post-CLK_OF_DECLARE finalize) -------- */ + +static const struct of_device_id hi3516cv200_crg_match_table[] = { + { .compatible = "hisilicon,hi3518ev20x-clock", .data = &hi3516cv200_crg_funcs }, + { } +}; +MODULE_DEVICE_TABLE(of, hi3516cv200_crg_match_table); + +static int hi3516cv200_crg_probe(struct platform_device *pdev) +{ + struct hisi_crg_dev *crg; + + crg = devm_kmalloc(&pdev->dev, sizeof(*crg), GFP_KERNEL); + if (!crg) + return -ENOMEM; + + crg->funcs = of_device_get_match_data(&pdev->dev); + if (!crg->funcs) + return -ENOENT; + + crg->rstc = hisi_reset_init(pdev); + if (!crg->rstc) + return -ENOMEM; + + crg->clk_data = crg->funcs->register_clks(pdev); + if (IS_ERR(crg->clk_data)) { + hisi_reset_exit(crg->rstc); + return PTR_ERR(crg->clk_data); + } + + platform_set_drvdata(pdev, crg); + return 0; +} + +static void hi3516cv200_crg_remove(struct platform_device *pdev) +{ + struct hisi_crg_dev *crg = platform_get_drvdata(pdev); + + hisi_reset_exit(crg->rstc); + crg->funcs->unregister_clks(pdev); +} + +static struct platform_driver hi3516cv200_crg_driver = { + .probe = hi3516cv200_crg_probe, + .remove = hi3516cv200_crg_remove, + .driver = { + .name = "hi3516cv200-crg", + .of_match_table = hi3516cv200_crg_match_table, + }, +}; + +static int __init hi3516cv200_crg_init(void) +{ + return platform_driver_register(&hi3516cv200_crg_driver); +} +core_initcall(hi3516cv200_crg_init); + +static void __exit hi3516cv200_crg_exit(void) +{ + platform_driver_unregister(&hi3516cv200_crg_driver); +} +module_exit(hi3516cv200_crg_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("HiSilicon Hi3516CV200 / Hi3518EV20x CRG Driver"); diff --git a/include/dt-bindings/clock/hi3516cv200-clock.h b/include/dt-bindings/clock/hi3516cv200-clock.h new file mode 100644 index 0000000000..d46af68ceb --- /dev/null +++ b/include/dt-bindings/clock/hi3516cv200-clock.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2016 HiSilicon Technologies Co., Ltd. + * + * Hi3516CV200 / Hi3518EV20x V2 family clock IDs — kept aligned with the + * vendor BSP so its 4.9-era DT (arch/arm/boot/dts/hi3518ev20x{.dtsi,-demb.dts}) + * compiles unchanged against the modern crg-hi3516cv200.c driver. + * + * V2 generation (ARM926EJ-S / ARMv5TE) — siblings: Hi3516CV200, + * Hi3518EV200, Hi3518EV201. + */ + +#ifndef __DTS_HI3516CV200_CLOCK_H +#define __DTS_HI3516CV200_CLOCK_H + +/* fixed rate clocks */ +#define HI3516CV200_FIXED_3M 1 +#define HI3516CV200_FIXED_6M 2 +#define HI3516CV200_FIXED_24M 3 +#define HI3516CV200_FIXED_25M 4 +#define HI3516CV200_FIXED_27M 5 +#define HI3516CV200_FIXED_37P125M 6 +#define HI3516CV200_FIXED_49P5M 7 +#define HI3516CV200_FIXED_50M 8 +#define HI3516CV200_FIXED_54M 9 +#define HI3516CV200_FIXED_74P25M 10 +#define HI3516CV200_FIXED_99M 11 +#define HI3516CV200_FIXED_125M 12 +#define HI3516CV200_FIXED_148P5M 13 +#define HI3516CV200_FIXED_198M 14 +#define HI3516CV200_FIXED_200M 15 +#define HI3516CV200_FIXED_250M 16 +#define HI3516CV200_FIXED_297M 17 +#define HI3516CV200_FIXED_300M 18 +#define HI3516CV200_FIXED_396M 19 +#define HI3516CV200_FIXED_540M 20 +#define HI3516CV200_FIXED_594M 21 +#define HI3516CV200_FIXED_600M 22 +#define HI3516CV200_FIXED_650M 23 +#define HI3516CV200_FIXED_750M 24 +#define HI3516CV200_FIXED_1188M 25 + +/* mux clocks (parent of gates / dividers) */ +#define HI3516CV200_FMC_MUX 30 +#define HI3516CV200_UART_MUX 31 +#define HI3516CV200_ETH_MUX 32 +#define HI3516CV200_USB2_CTRL_UTMI0_REQ 33 +#define HI3516CV200_USB2_HRST_REQ 34 +#define HI3516CV200_MMC0_MUX 35 +#define HI3516CV200_MMC1_MUX 36 + +/* divider clocks */ +#define HI3516CV200_SYSAPB_CLK 40 + +/* gate clocks */ +#define HI3516CV200_FMC_CLK 50 +#define HI3516CV200_UART0_CLK 51 +#define HI3516CV200_UART1_CLK 52 +#define HI3516CV200_UART2_CLK 53 +#define HI3516CV200_UART3_CLK 54 +#define HI3516CV200_ETH_CLK 55 +#define HI3516CV200_MMC0_CLK 56 +#define HI3516CV200_MMC1_CLK 57 +#define HI3516CV200_SPI0_CLK 58 +#define HI3516CV200_SPI1_CLK 59 +#define HI3516CV200_DMAC_CLK 60 + +#define HI3516CV200_CRG_NR_CLKS 64 + +/* sysctrl (timer mux) clocks — exported via the system-controller provider */ +#define HI3516CV200_TIME0_0_CLK 1 +#define HI3516CV200_TIME0_1_CLK 2 +#define HI3516CV200_TIME1_2_CLK 3 +#define HI3516CV200_TIME1_3_CLK 4 + +#define HI3516CV200_SC_NR_CLKS 8 + +#endif /* __DTS_HI3516CV200_CLOCK_H */