From 693dc842d3de41683bc915b1458a45b514d05d9d Mon Sep 17 00:00:00 2001 From: Vasiliy Yakovlev Date: Mon, 18 May 2026 06:51:00 +0300 Subject: [PATCH 1/3] clk: hisilicon: add hi3516cv200 / hi3518ev20x CRG driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit V2 generation (ARM926EJ-S, ARMv5TE) SoC family — Hi3516CV200, Hi3518EV200, Hi3518EV201 — all share the same CRG layout at 0x20030000 and the same sysctrl block at 0x20050000. The vendor 4.9 BSP drove these via drivers/clk/hisilicon/clk-hi3518ev20x.c; port the full clock topology onto the modern crg- platform_driver scaffold that crg-hi3516cv300.c established for the V3 sibling. Adds: - 25 fixed-rate roots (3 / 6 / 24 / 25 / 27 / 37.125 / 49.5 / 50 / 54 / 74.25 / 99 / 125 / 148.5 / 198 / 200 / 250 / 297 / 300 / 396 / 540 / 594 / 600 / 650 / 750 / 1188 MHz) - 5 muxes (uart/fmc/mmc0-1/eth) - 1 divider (sysapb) - 13 gates (uart0-3, spi0-1, fmc, mmc0-1, eth, dmac, usb2 utmi/hrst) - 4 sysctrl timer muxes registered via a separate provider Two CLK_OF_DECLARE entries make TIMER/APB/UART/ETH available before the platform_driver model is alive, so SP804 / PL011 / FEMAC don't defer-forever or read clk_get_rate() == 0: - hisilicon,hi3518ev20x-sysctrl → TIMER fixed-rate (3 MHz) - hisilicon,hi3518ev20x-clock → sysapb / UART0-3 / ETH fixed-rate The reset controller stays no-op but registers an explicit 2-cell xlate so reset_controller_register doesn't force of_reset_n_cells = 1 (which had silently broken FEMAC on cv300 before that same fix — this avoids the same trap on cv200). dt-bindings/clock/hi3516cv200-clock.h is the matching clock-ID header; the DT added in a later patch in this series references it verbatim from cv200 + sibling boards. Tested booting Linux 7.0 on a hi3516cv200 machine model under qemu-hisilicon: SP804 ticks, FEMAC DHCP succeeds (10.0.2.15 / 10.0.2.2 via SLIRP), userspace reaches \`openipc-hi3516cv200 login:\`, no Oops / panic / BUG / Trace. --- drivers/clk/hisilicon/Kconfig | 10 + drivers/clk/hisilicon/Makefile | 1 + drivers/clk/hisilicon/crg-hi3516cv200.c | 333 ++++++++++++++++++ include/dt-bindings/clock/hi3516cv200-clock.h | 78 ++++ 4 files changed, 422 insertions(+) create mode 100644 drivers/clk/hisilicon/crg-hi3516cv200.c create mode 100644 include/dt-bindings/clock/hi3516cv200-clock.h diff --git a/drivers/clk/hisilicon/Kconfig b/drivers/clk/hisilicon/Kconfig index 858ccf96f88..7b9ef47dcaa 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 59f20e63f6b..3643b72e397 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 00000000000..2caf6742c2d --- /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 00000000000..d46af68ceb3 --- /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 */ From 189c84c3fd59e12abf0ac48981841b5719ae6999 Mon Sep 17 00:00:00 2001 From: Vasiliy Yakovlev Date: Mon, 18 May 2026 06:51:11 +0300 Subject: [PATCH 2/3] arm: dts: hisilicon: add hi3516cv200 SoC and DEMB board MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Port the vendor 4.9 BSP hi3518ev20x DT to a 7.x-clean form and hook the DEMB reference board into the hisilicon dtb Makefile. Same SoC family as the vendor BSP (Hi3516CV200 / Hi3518EV200 / Hi3518EV201); keep the vendor compatible strings ("hisilicon,hi3518ev20x-clock", "-sysctrl") so the BSP DT remains drop-in compatible with this driver. SoC dtsi (hi3516cv200.dtsi): - drop legacy skeleton.dtsi (removed upstream in 4.18) - SP804 dual_timer with explicit clock-frequency = <3000000>: sp804 driver reads clk_get_rate() during start_kernel; without the property it would see 0 and refuse to register - hisi-femac-mdio: clock-names = "mdio" (modern devm_clk_get(dev, "mdio") needs a named clock; older bindings tolerated nameless) - hisi_femac: hisilicon,phy-reset-delays-us = <10000 10000 30000> required by the modern femac driver when a "phy" reset is declared DEMB board (hi3516cv200-demb.dts): - 64 MiB DDR @ 0x80000000 — matches production cv200 cameras that typically ship with 64 MiB total. The vendor mmz allocator is expected to claim the upper 32 MiB via `mmz=...` bootargs; the kernel uses 32 MiB. - bootargs configured for serial console + initrd handoff from U-Boot, matching the (future) cv200_neo firmware defconfig - phy@1 attached under &mdio with phy-mode = "mii" - i2c_bus0 / spi_bus0 / uart0 enabled for cv200 reference platforms Tested under qemu-hisilicon -M hi3516cv200 with a minimal initramfs: kernel boots through SP804 + PL011, mounts squashfs initrd, FEMAC DHCP succeeds, ntpd syncs the wall clock, no console errors. ARCH_HI3516CV200 is selected via the Kconfig change in the next patch in this series. --- arch/arm/boot/dts/hisilicon/Makefile | 2 + .../boot/dts/hisilicon/hi3516cv200-demb.dts | 59 +++++ arch/arm/boot/dts/hisilicon/hi3516cv200.dtsi | 234 ++++++++++++++++++ 3 files changed, 295 insertions(+) create mode 100644 arch/arm/boot/dts/hisilicon/hi3516cv200-demb.dts create mode 100644 arch/arm/boot/dts/hisilicon/hi3516cv200.dtsi diff --git a/arch/arm/boot/dts/hisilicon/Makefile b/arch/arm/boot/dts/hisilicon/Makefile index 9c7f83117b6..db8bbbe6d87 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 00000000000..cbbb9c036e6 --- /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 00000000000..5c537227d64 --- /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>; + }; + }; +}; From 29aeeafc10a20b90b538776cd02cfa63dc709660 Mon Sep 17 00:00:00 2001 From: Vasiliy Yakovlev Date: Mon, 18 May 2026 06:51:20 +0300 Subject: [PATCH 3/3] arm: hibvt: add ARCH_HI3516CV200 Kconfig entry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wire the V2 SoC family (Hi3516CV200 / Hi3518EV200 / Hi3518EV201) into the hibvt platform choice. Selects: - ARM_VIC, ARM_TIMER_SP804 — interrupt + timer hardware - PINCTRL — required by hibvt pinctrl - COMMON_CLK_HI3516CV200 — the CRG driver added earlier in this series - ARCH_HAS_RESET_CONTROLLER + RESET_CONTROLLER — femac resets Depends on ARCH_MULTI_V5 (ARM926EJ-S, ARMv5TE) + CPU_LITTLE_ENDIAN — matches the existing ARCH_HI3516CV300 sibling. After this patch, the kernel boots end-to-end on the cv200 machine model in qemu-hisilicon. Real hardware verification is gated on the openhisilicon-side OSAL shim work that resolves blob-import gaps for do_gettimeofday / register_sysctl_table / strlcpy on modern kernels (separate openhisilicon PR, doesn't affect the kernel-side support landing here). --- arch/arm/mach-hibvt/Kconfig | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/arm/mach-hibvt/Kconfig b/arch/arm/mach-hibvt/Kconfig index 1651d4797c8..5f9284700d7 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