From 5a017c785808958b10a0b8a9e68b05e6b8bf67ee Mon Sep 17 00:00:00 2001 From: Zoltan HERPAI Date: Wed, 4 Oct 2023 17:28:54 +0200 Subject: [PATCH] cv18x0: add new target for Sophgo CV18x0 RISC-V SoCs Initially targeting the Milk-V Duo+dock board. Signed-off-by: Zoltan HERPAI --- package/boot/opensbi/Makefile | 6 +- package/boot/uboot-cv18x0/Makefile | 57 + ...-environment-for-dtc-binary-location.patch | 35 + .../patches/130-fix-mkimage-host-build.patch | 24 + .../patches/200-add-BL33-on-milkvduo.patch | 53 + package/boot/uboot-cv18x0/uEnv-default.txt | 5 + target/linux/cv18x0/Makefile | 22 + .../cv18x0/base-files/etc/board.d/01_leds | 21 + .../cv18x0/base-files/etc/board.d/02_network | 18 + target/linux/cv18x0/base-files/etc/inittab | 4 + .../base-files/lib/preinit/79_move_config | 19 + .../cv18x0/base-files/lib/upgrade/platform.sh | 86 + target/linux/cv18x0/config-6.6 | 392 ++ target/linux/cv18x0/generic/target.mk | 1 + target/linux/cv18x0/image/Config.in | 4 + target/linux/cv18x0/image/Makefile | 62 + .../cv18x0/image/gen_cv18x0_sdcard_img.sh | 28 + ...Sophgo-SoC-platform-hardware-support.patch | 30 + ...-add-initial-CV1800B-SoC-device-tree.patch | 147 + ...nitial-SOPHGO-SG2042-SoC-device-tree.patch | 2232 ++++++++++ ...-add-Milk-V-Pioneer-board-device-tre.patch | 76 + ...hgo-add-Milk-V-Duo-board-device-tree.patch | 74 + ...-add-initial-CV1812H-SoC-device-tree.patch | 48 + ...-Separate-compatible-specific-for-CV.patch | 282 ++ ...v-dts-sophgo-cv18xx-Add-gpio-devices.patch | 109 + ...i-of-dwcmshc-include-bitfield.h-for-.patch | 26 + ...mshc-Add-support-for-Sophgo-CV1800B-.patch | 122 + ...k-sophgo-Add-clock-controller-of-CV1.patch | 206 + ...V1800-SG2000-series-clock-controller.patch | 3743 +++++++++++++++++ ...hgo-add-sdcard-support-for-milkv-duo.patch | 80 + ...14-sophgo-add-reboot-shutdown-driver.patch | 174 + ...t-Add-binding-for-Sophgo-CV1800B-res.patch | 166 + ...controller-support-for-Sophgo-CV1800.patch | 117 + ...phgo-add-watchdog-dt-node-for-CV1800.patch | 58 + ...-sophgo-add-timer-dt-node-for-CV1800.patch | 103 + ...mshc-Add-tuning-support-for-Sophgo-C.patch | 158 + ...-dts-sophgo-use-real-clock-for-sdhci.patch | 48 + 37 files changed, 8833 insertions(+), 3 deletions(-) create mode 100644 package/boot/uboot-cv18x0/Makefile create mode 100644 package/boot/uboot-cv18x0/patches/100-mkimage-check-environment-for-dtc-binary-location.patch create mode 100644 package/boot/uboot-cv18x0/patches/130-fix-mkimage-host-build.patch create mode 100644 package/boot/uboot-cv18x0/patches/200-add-BL33-on-milkvduo.patch create mode 100644 package/boot/uboot-cv18x0/uEnv-default.txt create mode 100644 target/linux/cv18x0/Makefile create mode 100644 target/linux/cv18x0/base-files/etc/board.d/01_leds create mode 100644 target/linux/cv18x0/base-files/etc/board.d/02_network create mode 100644 target/linux/cv18x0/base-files/etc/inittab create mode 100644 target/linux/cv18x0/base-files/lib/preinit/79_move_config create mode 100644 target/linux/cv18x0/base-files/lib/upgrade/platform.sh create mode 100644 target/linux/cv18x0/config-6.6 create mode 100644 target/linux/cv18x0/generic/target.mk create mode 100644 target/linux/cv18x0/image/Config.in create mode 100644 target/linux/cv18x0/image/Makefile create mode 100755 target/linux/cv18x0/image/gen_cv18x0_sdcard_img.sh create mode 100644 target/linux/cv18x0/patches-6.6/0001-riscv-Add-Sophgo-SoC-platform-hardware-support.patch create mode 100644 target/linux/cv18x0/patches-6.6/0002-riscv-dts-sophgo-add-initial-CV1800B-SoC-device-tree.patch create mode 100644 target/linux/cv18x0/patches-6.6/0003-riscv-dts-add-initial-SOPHGO-SG2042-SoC-device-tree.patch create mode 100644 target/linux/cv18x0/patches-6.6/0004-riscv-dts-sophgo-add-Milk-V-Pioneer-board-device-tre.patch create mode 100644 target/linux/cv18x0/patches-6.6/0005-riscv-dts-sophgo-add-Milk-V-Duo-board-device-tree.patch create mode 100644 target/linux/cv18x0/patches-6.6/0006-riscv-dts-sophgo-add-initial-CV1812H-SoC-device-tree.patch create mode 100644 target/linux/cv18x0/patches-6.6/0007-riscv-dts-sophgo-Separate-compatible-specific-for-CV.patch create mode 100644 target/linux/cv18x0/patches-6.6/0008-riscv-dts-sophgo-cv18xx-Add-gpio-devices.patch create mode 100644 target/linux/cv18x0/patches-6.6/0009-drivers-mmc-sdhci-of-dwcmshc-include-bitfield.h-for-.patch create mode 100644 target/linux/cv18x0/patches-6.6/0010-mmc-sdhci-of-dwcmshc-Add-support-for-Sophgo-CV1800B-.patch create mode 100644 target/linux/cv18x0/patches-6.6/0011-dt-bindings-clock-sophgo-Add-clock-controller-of-CV1.patch create mode 100644 target/linux/cv18x0/patches-6.6/0012-clk-sophgo-Add-CV1800-SG2000-series-clock-controller.patch create mode 100644 target/linux/cv18x0/patches-6.6/0013-riscv-dts-sophgo-add-sdcard-support-for-milkv-duo.patch create mode 100644 target/linux/cv18x0/patches-6.6/0014-sophgo-add-reboot-shutdown-driver.patch create mode 100644 target/linux/cv18x0/patches-6.6/0015-dt-bindings-reset-Add-binding-for-Sophgo-CV1800B-res.patch create mode 100644 target/linux/cv18x0/patches-6.6/0016-reset-Add-reset-controller-support-for-Sophgo-CV1800.patch create mode 100644 target/linux/cv18x0/patches-6.6/0017-riscv-dts-sophgo-add-watchdog-dt-node-for-CV1800.patch create mode 100644 target/linux/cv18x0/patches-6.6/0018-riscv-dts-sophgo-add-timer-dt-node-for-CV1800.patch create mode 100644 target/linux/cv18x0/patches-6.6/0019-mmc-sdhci-of-dwcmshc-Add-tuning-support-for-Sophgo-C.patch create mode 100644 target/linux/cv18x0/patches-6.6/0020-riscv-dts-sophgo-use-real-clock-for-sdhci.patch diff --git a/package/boot/opensbi/Makefile b/package/boot/opensbi/Makefile index d77c00c884..9d62ae750b 100644 --- a/package/boot/opensbi/Makefile +++ b/package/boot/opensbi/Makefile @@ -41,7 +41,7 @@ define Package/opensbi_generic $(Package/opensbi) TITLE:=OpenSBI generic OPENSBI_IMAGE:=fw_dynamic.bin - DEPENDS:=@TARGET_cv18x0:u-boot-milkv_duo + DEPENDS:=+(TARGET_cv18x0):u-boot-milkv_duo PLAT:=generic endef @@ -50,8 +50,8 @@ export GCC_HONOUR_COPTS=s MAKE_VARS = \ CROSS_COMPILE="$(TARGET_CROSS)" -ifdef CONFIG_TARGET_cv18x0 -FW_FDT_PATH=$(STAGING_DIR_IMAGE)/asdasd.dtb +ifdef CONFIG_TARGET_DEVICE_cv18x0_generic_DEVICE_milkv_duo +FW_FDT_PATH=$(STAGING_DIR_IMAGE)/cv1800b-milkv-duo.dtb endif define Build/Compile diff --git a/package/boot/uboot-cv18x0/Makefile b/package/boot/uboot-cv18x0/Makefile new file mode 100644 index 0000000000..8aa33b759d --- /dev/null +++ b/package/boot/uboot-cv18x0/Makefile @@ -0,0 +1,57 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Copyright (C) 2024 OpenWrt.org +# + +include $(TOPDIR)/rules.mk +include $(INCLUDE_DIR)/kernel.mk + +PKG_RELEASE:=1 +PKG_VERSION:=2024.07-rc5 +PKG_SOURCE_PROTO:=git +PKG_SOURCE_URL:=https://github.com/u-boot/u-boot +PKG_SOURCE_VERSION:=9e9f78f7aa0124ef0e622532043acf87e84008dc + +UBOOT_USE_INTREE_DTC:=1 + +include $(INCLUDE_DIR)/u-boot.mk +include $(INCLUDE_DIR)/package.mk + +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.zst +PKG_MIRROR_HASH:=3d69884648f0412b500f5968c2d3014acb51b3a97bc256e306ff9cac99a5fec0 + +define U-Boot/Default + BUILD_TARGET:=cv18x0 + BUILD_DEVICES=$(1) + UBOOT_IMAGE:=u-boot.bin + DTS_DIR:=arch/riscv/dts + UENV:=default + DEFAULT:=y +endef + +define U-Boot/milkv_duo + NAME:=MilkV Duo + OPENSBI:=generic + DEPENDS:=+cv18xxlibs + UBOOT_DTS:=cv1800b-milkv-duo.dtb + BUILD_DEVICES:=milkv_duo +endef + +UBOOT_TARGETS := \ + milkv_duo + +#UBOOT_MAKE_FLAGS += \ +# OPENSBI=$(STAGING_DIR_IMAGE)/fw_dynamic-${OPENSBI}.bin + +define Build/Configure + $(call Build/Configure/U-Boot) + sed -i 's/CONFIG_TOOLS_LIBCRYPTO=y/# CONFIG_TOOLS_LIBCRYPTO is not set/' $(PKG_BUILD_DIR)/.config +endef + +define Build/InstallDev + $(INSTALL_DIR) $(STAGING_DIR_IMAGE) + $(INSTALL_BIN) $(PKG_BUILD_DIR)/$(UBOOT_IMAGE) $(STAGING_DIR_IMAGE)/$(BUILD_VARIANT)-$(UBOOT_IMAGE) + $(INSTALL_BIN) $(PKG_BUILD_DIR)/$(DTS_DIR)/$(UBOOT_DTS) $(STAGING_DIR_IMAGE)/$(UBOOT_DTS) +endef + +$(eval $(call BuildPackage/U-Boot)) diff --git a/package/boot/uboot-cv18x0/patches/100-mkimage-check-environment-for-dtc-binary-location.patch b/package/boot/uboot-cv18x0/patches/100-mkimage-check-environment-for-dtc-binary-location.patch new file mode 100644 index 0000000000..482aa1a369 --- /dev/null +++ b/package/boot/uboot-cv18x0/patches/100-mkimage-check-environment-for-dtc-binary-location.patch @@ -0,0 +1,35 @@ +From 637800493945ffed2f454756300437a4ec86e3b1 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +Date: Wed, 19 Jul 2017 22:23:15 +0200 +Subject: mkimage: check environment for dtc binary location + +Currently mkimage assumes the dtc binary is in the path and fails +otherwise. This patch makes it check the DTC environment variable first +for the dtc binary and then fall back to the default path. This makes +it possible to call the u-boot build with make DTC=... and build a fit +image with the dtc binary not being the the default path. + +Signed-off-by: Hauke Mehrtens +Cc: Simon Glass +--- + tools/fit_image.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +--- a/tools/fit_image.c ++++ b/tools/fit_image.c +@@ -726,9 +726,14 @@ static int fit_handle_file(struct image_ + } + *cmd = '\0'; + } else if (params->datafile) { ++ const char* dtc = getenv("DTC"); ++ ++ if (!dtc) ++ dtc = MKIMAGE_DTC; ++ + /* dtc -I dts -O dtb -p 500 -o tmpfile datafile */ + snprintf(cmd, sizeof(cmd), "%s %s -o \"%s\" \"%s\"", +- MKIMAGE_DTC, params->dtc, tmpfile, params->datafile); ++ dtc, params->dtc, tmpfile, params->datafile); + debug("Trying to execute \"%s\"\n", cmd); + } else { + snprintf(cmd, sizeof(cmd), "cp \"%s\" \"%s\"", diff --git a/package/boot/uboot-cv18x0/patches/130-fix-mkimage-host-build.patch b/package/boot/uboot-cv18x0/patches/130-fix-mkimage-host-build.patch new file mode 100644 index 0000000000..cd65c1321f --- /dev/null +++ b/package/boot/uboot-cv18x0/patches/130-fix-mkimage-host-build.patch @@ -0,0 +1,24 @@ +--- a/tools/image-host.c ++++ b/tools/image-host.c +@@ -1125,6 +1125,7 @@ static int fit_config_add_verification_d + * 2) get public key (X509_get_pubkey) + * 3) provide der format (d2i_RSAPublicKey) + */ ++#ifdef CONFIG_TOOLS_LIBCRYPTO + static int read_pub_key(const char *keydir, const void *name, + unsigned char **pubkey, int *pubkey_len) + { +@@ -1178,6 +1179,13 @@ err_cert: + fclose(f); + return ret; + } ++#else ++static int read_pub_key(const char *keydir, const void *name, ++ unsigned char **pubkey, int *pubkey_len) ++{ ++ return -ENOSYS; ++} ++#endif + + int fit_pre_load_data(const char *keydir, void *keydest, void *fit) + { diff --git a/package/boot/uboot-cv18x0/patches/200-add-BL33-on-milkvduo.patch b/package/boot/uboot-cv18x0/patches/200-add-BL33-on-milkvduo.patch new file mode 100644 index 0000000000..ae08fc5a28 --- /dev/null +++ b/package/boot/uboot-cv18x0/patches/200-add-BL33-on-milkvduo.patch @@ -0,0 +1,53 @@ +diff -ruN u-boot-2024-05-13.old/arch/riscv/cpu/start.S u-boot-2024-05-13/arch/riscv/cpu/start.S +--- u-boot-2024-05-13.old/arch/riscv/cpu/start.S 2024-05-13 17:15:46.000000000 +0200 ++++ u-boot-2024-05-13/arch/riscv/cpu/start.S 2024-05-14 11:31:51.924686607 +0200 +@@ -39,6 +39,10 @@ + .section .text + .globl _start + _start: ++#if CONFIG_IS_ENABLED(TARGET_MILKV_DUO) ++#include ++#endif ++_start_real: + #if CONFIG_IS_ENABLED(RISCV_MMODE) + csrr a0, CSR_MHARTID + #endif +diff -ruN u-boot-2024-05-13.old/arch/riscv/include/asm/boot0.h u-boot-2024-05-13/arch/riscv/include/asm/boot0.h +--- u-boot-2024-05-13.old/arch/riscv/include/asm/boot0.h 1970-01-01 01:00:00.000000000 +0100 ++++ u-boot-2024-05-13/arch/riscv/include/asm/boot0.h 2024-04-30 23:23:20.728599523 +0200 +@@ -0,0 +1,35 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * CVITEK u-boot header ++ */ ++ ++#ifndef __BOOT0_H__ ++#define __BOOT0_H__ ++ ++/* BOOT0 header information */ ++ j boot0_time_recode ++ .balign 4 ++ .word 0x33334c42 /* b'BL33' */ ++ .word 0xdeadbeea /* CKSUM */ ++ .word 0xdeadbeeb /* SIZE */ ++#ifdef CONFIG_SPL_BUILD ++ .quad CONFIG_TEXT_BASE ++#else ++ .quad CONFIG_TEXT_BASE ++#endif ++ .word 0xdeadbeec ++ .balign 4 ++ j boot0_time_recode ++ .balign 4 ++/* BOOT0 header end */ ++boot0_time_recode: ++ csrr x1, time ++ la x2, BOOT0_START_TIME ++ sw x1, 0(x2) ++ j _start_real ++ ++ .global BOOT0_START_TIME ++BOOT0_START_TIME: ++ .word 0 ++ ++#endif /* __BOOT0_H__ */ diff --git a/package/boot/uboot-cv18x0/uEnv-default.txt b/package/boot/uboot-cv18x0/uEnv-default.txt new file mode 100644 index 0000000000..8468a3cace --- /dev/null +++ b/package/boot/uboot-cv18x0/uEnv-default.txt @@ -0,0 +1,5 @@ +setenv loadkernel fatload mmc 0:3 \$kernel_addr_r Image +setenv loaddtb fatload mmc 0:3 \$fdt_addr_r dtb +setenv bootargs console=ttySIF0,115200 earlycon=sbi root=/dev/mmcblk0p4 rootwait +setenv uenvcmd run loadkernel \&\& run loaddtb \&\& booti \$kernel_addr_r - \$fdt_addr_r +run uenvcmd diff --git a/target/linux/cv18x0/Makefile b/target/linux/cv18x0/Makefile new file mode 100644 index 0000000000..9a757464a3 --- /dev/null +++ b/target/linux/cv18x0/Makefile @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Copyright (C) 2024 Toco Technologies +# +include $(TOPDIR)/rules.mk + +ARCH:=riscv64 +BOARD:=cv18x0 +BOARDNAME:=Cvitek CV180x boards +FEATURES:=ext4 +KERNELNAME:=Image dtbs +SUBTARGETS:=generic + +KERNEL_PATCHVER:=6.6 + +include $(INCLUDE_DIR)/target.mk + +define Target/Description + Build firmware images for the Cvitek CV1800/1810 boards +endef + +$(eval $(call BuildTarget)) diff --git a/target/linux/cv18x0/base-files/etc/board.d/01_leds b/target/linux/cv18x0/base-files/etc/board.d/01_leds new file mode 100644 index 0000000000..5610a791ec --- /dev/null +++ b/target/linux/cv18x0/base-files/etc/board.d/01_leds @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Copyright (C) 2022 OpenWrt.org +# + +. /lib/functions/uci-defaults.sh + +board_config_update + +case "$(board_name)" in +sifive,hifive-unleashed-a00) + ucidef_set_led_netdev "lan" "LAN" "green:d3" "eth0" + ;; +sifive,hifive-unmatched-a00) + ucidef_set_led_netdev "lan" "LAN" "green:d2" "eth0" + ;; +esac + +board_config_flush + +exit 0 diff --git a/target/linux/cv18x0/base-files/etc/board.d/02_network b/target/linux/cv18x0/base-files/etc/board.d/02_network new file mode 100644 index 0000000000..ca9f7f2008 --- /dev/null +++ b/target/linux/cv18x0/base-files/etc/board.d/02_network @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Copyright (C) 2022 OpenWrt.org +# + +. /lib/functions/uci-defaults.sh + +board_config_update + +case "$(board_name)" in +*) + ucidef_set_interface_lan 'eth0' + ;; +esac + +board_config_flush + +exit 0 diff --git a/target/linux/cv18x0/base-files/etc/inittab b/target/linux/cv18x0/base-files/etc/inittab new file mode 100644 index 0000000000..d1b5a0fa22 --- /dev/null +++ b/target/linux/cv18x0/base-files/etc/inittab @@ -0,0 +1,4 @@ +::sysinit:/etc/init.d/rcS S boot +::shutdown:/etc/init.d/rcS K shutdown +ttyS0::askfirst:/usr/libexec/login.sh +tty1::askfirst:/usr/libexec/login.sh diff --git a/target/linux/cv18x0/base-files/lib/preinit/79_move_config b/target/linux/cv18x0/base-files/lib/preinit/79_move_config new file mode 100644 index 0000000000..2796c4d01b --- /dev/null +++ b/target/linux/cv18x0/base-files/lib/preinit/79_move_config @@ -0,0 +1,19 @@ +# Copyright (C) 2012-2015 OpenWrt.org + +move_config() { + local partdev + + . /lib/upgrade/common.sh + + if export_bootdevice && export_partdevice partdev 3; then + if mount -t vfat -o rw,noatime "/dev/$partdev" /mnt; then + if [ -f "/mnt/$BACKUP_FILE" ]; then + mv -f "/mnt/$BACKUP_FILE" / + fi + umount /mnt + fi + fi +} + +boot_hook_add preinit_mount_root move_config + diff --git a/target/linux/cv18x0/base-files/lib/upgrade/platform.sh b/target/linux/cv18x0/base-files/lib/upgrade/platform.sh new file mode 100644 index 0000000000..b5f6bada41 --- /dev/null +++ b/target/linux/cv18x0/base-files/lib/upgrade/platform.sh @@ -0,0 +1,86 @@ +platform_check_image() { + local diskdev partdev diff + + export_bootdevice && export_partdevice diskdev 0 || { + echo "Unable to determine upgrade device" + return 1 + } + + get_partitions "/dev/$diskdev" bootdisk + + #extract the boot sector from the image + get_image "$@" | dd of=/tmp/image.bs count=1 bs=512b 2>/dev/null + + get_partitions /tmp/image.bs image + + #compare tables + diff="$(grep -F -x -v -f /tmp/partmap.bootdisk /tmp/partmap.image)" + + rm -f /tmp/image.bs /tmp/partmap.bootdisk /tmp/partmap.image + + if [ -n "$diff" ]; then + echo "Partition layout has changed. Full image will be written." + ask_bool 0 "Abort" && exit 1 + return 0 + fi +} + +platform_copy_config() { + local partdev + + if export_partdevice partdev 3; then + mount -t vfat -o rw,noatime "/dev/$partdev" /mnt + cp -af "$UPGRADE_BACKUP" "/mnt/$BACKUP_FILE" + umount /mnt + fi +} + +platform_do_upgrade() { + local diskdev partdev diff + + export_bootdevice && export_partdevice diskdev 0 || { + echo "Unable to determine upgrade device" + return 1 + } + + sync + + if [ "$UPGRADE_OPT_SAVE_PARTITIONS" = "1" ]; then + get_partitions "/dev/$diskdev" bootdisk + + #extract the boot sector from the image + get_image "$@" | dd of=/tmp/image.bs count=1 bs=512b + + get_partitions /tmp/image.bs image + + #compare tables + diff="$(grep -F -x -v -f /tmp/partmap.bootdisk /tmp/partmap.image)" + else + diff=1 + fi + + if [ -n "$diff" ]; then + get_image "$@" | dd of="/dev/$diskdev" bs=4096 conv=fsync + + # Separate removal and addtion is necessary; otherwise, partition 1 + # will be missing if it overlaps with the old partition 2 + partx -d - "/dev/$diskdev" + partx -a - "/dev/$diskdev" + + return 0 + fi + + #iterate over each partition from the image and write it to the boot disk + while read part start size; do + if export_partdevice partdev $part; then + echo "Writing image to /dev/$partdev..." + get_image "$@" | dd of="/dev/$partdev" ibs="512" obs=1M skip="$start" count="$size" conv=fsync + else + echo "Unable to find partition $part device, skipped." + fi + done < /tmp/partmap.image + + #copy partition uuid + echo "Writing new UUID to /dev/$diskdev..." + get_image "$@" | dd of="/dev/$diskdev" bs=1 skip=440 count=4 seek=440 conv=fsync +} diff --git a/target/linux/cv18x0/config-6.6 b/target/linux/cv18x0/config-6.6 new file mode 100644 index 0000000000..2a28e4ed4f --- /dev/null +++ b/target/linux/cv18x0/config-6.6 @@ -0,0 +1,392 @@ +CONFIG_64BIT=y +# CONFIG_ACPI is not set +CONFIG_ARCH_CLOCKSOURCE_INIT=y +CONFIG_ARCH_DMA_ADDR_T_64BIT=y +CONFIG_ARCH_MMAP_RND_BITS=18 +CONFIG_ARCH_MMAP_RND_BITS_MAX=24 +CONFIG_ARCH_MMAP_RND_BITS_MIN=18 +CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=17 +CONFIG_ARCH_OPTIONAL_KERNEL_RWX=y +CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT=y +CONFIG_ARCH_RV64I=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_SOPHGO=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_STACKWALK=y +CONFIG_ARCH_THEAD=y +CONFIG_ARCH_WANTS_THP_SWAP=y +CONFIG_ASN1=y +CONFIG_ASSOCIATIVE_ARRAY=y +CONFIG_ATA=y +CONFIG_ATA_VERBOSE_ERROR=y +# CONFIG_AX45MP_L2_CACHE is not set +CONFIG_BLK_DEV_SD=y +CONFIG_BLK_MQ_PCI=y +CONFIG_CAVIUM_PTP=y +CONFIG_CC_HAVE_STACKPROTECTOR_TLS=y +CONFIG_CC_IMPLICIT_FALLTHROUGH="-Wimplicit-fallthrough=5" +CONFIG_CC_NO_ARRAY_BOUNDS=y +CONFIG_CLONE_BACKWARDS=y +CONFIG_CLK_SOPHGO_CV1800=y +CONFIG_CLZ_TAB=y +CONFIG_CMODEL_MEDANY=y +# CONFIG_CMODEL_MEDLOW is not set +CONFIG_COMMON_CLK=y +CONFIG_COMPACT_UNEVICTABLE_DEFAULT=1 +# CONFIG_COMPAT_32BIT_TIME is not set +CONFIG_COMPAT_BRK=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_CONTEXT_TRACKING=y +CONFIG_CONTEXT_TRACKING_IDLE=y +CONFIG_COREDUMP=y +CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y +CONFIG_CPU_ISOLATION=y +CONFIG_CPU_RMAP=y +CONFIG_CRC16=y +# CONFIG_CRC32_SARWATE is not set +CONFIG_CRC32_SLICEBY8=y +CONFIG_CRC7=y +CONFIG_CRC_ITU_T=y +CONFIG_CRYPTO_CRC32C=y +CONFIG_CRYPTO_DRBG=y +CONFIG_CRYPTO_DRBG_HMAC=y +CONFIG_CRYPTO_DRBG_MENU=y +CONFIG_CRYPTO_ECHAINIV=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_JITTERENTROPY=y +CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y +CONFIG_CRYPTO_LIB_POLY1305_RSIZE=1 +CONFIG_CRYPTO_LIB_SHA1=y +CONFIG_CRYPTO_LIB_SHA256=y +CONFIG_CRYPTO_LIB_UTILS=y +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_RNG_DEFAULT=y +CONFIG_CRYPTO_RSA=y +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_SHA512=y +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_INFO=y +CONFIG_DECOMPRESS_GZIP=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +# CONFIG_DEVTMPFS_SAFE is not set +CONFIG_DMA_DIRECT_REMAP=y +CONFIG_DNOTIFY=y +CONFIG_DTC=y +CONFIG_DUMMY_CONSOLE=y +CONFIG_DW_APB_TIMER=y +CONFIG_DW_APB_TIMER_OF=y +CONFIG_DW_WATCHDOG=y +CONFIG_EDAC=y +# CONFIG_EDAC_DEBUG is not set +CONFIG_EDAC_LEGACY_SYSFS=y +CONFIG_EDAC_SUPPORT=y +CONFIG_EFI=y +CONFIG_EFIVAR_FS=m +# CONFIG_EFI_BOOTLOADER_CONTROL is not set +# CONFIG_EFI_CAPSULE_LOADER is not set +# CONFIG_EFI_COCO_SECRET is not set +# CONFIG_EFI_DISABLE_PCI_DMA is not set +# CONFIG_EFI_DISABLE_RUNTIME is not set +CONFIG_EFI_EARLYCON=y +CONFIG_EFI_ESRT=y +CONFIG_EFI_GENERIC_STUB=y +CONFIG_EFI_PARAMS_FROM_FDT=y +CONFIG_EFI_RUNTIME_WRAPPERS=y +CONFIG_EFI_STUB=y +# CONFIG_EFI_TEST is not set +# CONFIG_EFI_ZBOOT is not set +CONFIG_ELF_CORE=y +# CONFIG_ERRATA_ANDES is not set +CONFIG_ERRATA_SIFIVE=y +CONFIG_ERRATA_SIFIVE_CIP_1200=y +CONFIG_ERRATA_SIFIVE_CIP_453=y +CONFIG_ERRATA_THEAD=y +CONFIG_ERRATA_THEAD_PBMT=y +CONFIG_ERRATA_THEAD_CMO=y +CONFIG_EXCLUSIVE_SYSTEM_RAM=y +CONFIG_EXT4_FS=y +CONFIG_FAILOVER=y +CONFIG_FAT_FS=y +CONFIG_FHANDLE=y +CONFIG_FIXED_PHY=y +CONFIG_FIX_EARLYCON_MEM=y +CONFIG_FONT_8x16=y +CONFIG_FONT_AUTOSELECT=y +CONFIG_FONT_SUPPORT=y +CONFIG_FPU=y +CONFIG_FRAME_POINTER=y +CONFIG_FS_IOMAP=y +CONFIG_FS_MBCACHE=y +CONFIG_FWNODE_MDIO=y +CONFIG_FW_LOADER_PAGED_BUF=y +CONFIG_FW_LOADER_SYSFS=y +CONFIG_GCC11_NO_ARRAY_BOUNDS=y +CONFIG_GENERIC_ALLOCATOR=y +CONFIG_GENERIC_ARCH_TOPOLOGY=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y +CONFIG_GENERIC_CSUM=y +CONFIG_GENERIC_EARLY_IOREMAP=y +CONFIG_GENERIC_GETTIMEOFDAY=y +CONFIG_GENERIC_IDLE_POLL_SETUP=y +CONFIG_GENERIC_IOREMAP=y +CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y +CONFIG_GENERIC_IRQ_INJECTION=y +CONFIG_GENERIC_IRQ_MULTI_HANDLER=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_SHOW_LEVEL=y +CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED=y +CONFIG_GENERIC_MSI_IRQ=y +CONFIG_GENERIC_MSI_IRQ_DOMAIN=y +CONFIG_GENERIC_PCI_IOMAP=y +CONFIG_GENERIC_SCHED_CLOCK=y +CONFIG_GENERIC_SMP_IDLE_THREAD=y +CONFIG_GENERIC_STRNCPY_FROM_USER=y +CONFIG_GENERIC_STRNLEN_USER=y +CONFIG_GENERIC_TIME_VSYSCALL=y +CONFIG_GLOB=y +CONFIG_GPIOLIB_IRQCHIP=y +CONFIG_GPIO_CDEV=y +CONFIG_GPIO_CDEV_V1=y +CONFIG_GPIO_DWAPB=y +CONFIG_GPIO_GENERIC=y +CONFIG_GPIO_SIFIVE=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_HAS_DMA=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT_MAP=y +CONFIG_HID=y +CONFIG_HID_GENERIC=y +CONFIG_HOTPLUG_PCI=y +# CONFIG_HOTPLUG_PCI_CPCI is not set +CONFIG_HOTPLUG_PCI_PCIE=y +CONFIG_HOTPLUG_PCI_SHPC=y +CONFIG_HVC_DRIVER=y +CONFIG_HVC_RISCV_SBI=y +CONFIG_HW_CONSOLE=y +CONFIG_HZ_PERIODIC=y +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_OCORES=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_INPUT=y +# CONFIG_IOMMU_DEBUGFS is not set +# CONFIG_IOMMUFD is not set +CONFIG_IOMMU_SUPPORT=y +CONFIG_IO_URING=y +CONFIG_IRQ_STACKS=y +CONFIG_IRQCHIP=y +CONFIG_IRQ_DOMAIN=y +CONFIG_IRQ_DOMAIN_HIERARCHY=y +CONFIG_IRQ_FORCED_THREADING=y +CONFIG_IRQ_WORK=y +CONFIG_JBD2=y +CONFIG_KALLSYMS=y +CONFIG_KEYS=y +CONFIG_LEDS_PWM=y +CONFIG_LEDS_TRIGGER_DISK=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_LIBFDT=y +CONFIG_LOCALVERSION_AUTO=y +CONFIG_LOCK_DEBUGGING_SUPPORT=y +CONFIG_LOCK_SPIN_ON_OWNER=y +CONFIG_MACB=y +# CONFIG_MACB_PCI is not set +CONFIG_MACB_USE_HWSTAMP=y +CONFIG_MDIO_BUS=y +CONFIG_MDIO_DEVICE=y +CONFIG_MDIO_DEVRES=y +CONFIG_MEMFD_CREATE=y +CONFIG_MFD_SYSCON=y +CONFIG_MICROSEMI_PHY=y +CONFIG_MIGRATION=y +CONFIG_MMC=y +CONFIG_MMC_BLOCK=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_CADENCE=y +CONFIG_MMC_SDHCI_CV1800B=y +CONFIG_MMC_SDHCI_OF_DWCMSHC=y +# CONFIG_MMC_SDHCI_PCI is not set +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SPI=y +CONFIG_MMIOWB=y +CONFIG_MODULES_USE_ELF_RELA=y +CONFIG_MODULE_SECTIONS=y +CONFIG_MPILIB=y +CONFIG_MQ_IOSCHED_DEADLINE=y +CONFIG_MQ_IOSCHED_KYBER=y +CONFIG_MTD_SPI_NOR=y +CONFIG_MTD_SPI_NOR_USE_4K_SECTORS=y +CONFIG_MUTEX_SPIN_ON_OWNER=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_NET_FAILOVER=y +CONFIG_NET_FLOW_LIMIT=y +CONFIG_NET_PTP_CLASSIFY=y +CONFIG_NET_SELFTESTS=y +CONFIG_NLS=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +# CONFIG_NONPORTABLE is not set +CONFIG_NR_CPUS=8 +CONFIG_NVMEM=y +CONFIG_NVMEM_SYSFS=y +CONFIG_OF=y +CONFIG_OF_ADDRESS=y +CONFIG_OF_DMA_DEFAULT_COHERENT=y +CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_FLATTREE=y +CONFIG_OF_GPIO=y +CONFIG_OF_IRQ=y +CONFIG_OF_KOBJ=y +CONFIG_OF_MDIO=y +CONFIG_OID_REGISTRY=y +CONFIG_PADATA=y +CONFIG_PAGE_OFFSET=0xff60000000000000 +CONFIG_PAGE_POOL=y +CONFIG_PAGE_REPORTING=y +CONFIG_PAGE_SIZE_LESS_THAN_256KB=y +CONFIG_PAGE_SIZE_LESS_THAN_64KB=y +CONFIG_PGTABLE_LEVELS=5 +CONFIG_PHYLIB=y +CONFIG_PHYLINK=y +CONFIG_PHYS_ADDR_T_64BIT=y +CONFIG_PORTABLE=y +CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_GPIO=y +CONFIG_POWER_RESET_GPIO_RESTART=y +CONFIG_POWER_RESET_RESTART=y +CONFIG_POWER_RESET_SOPHGO=y +CONFIG_POWER_RESET_SYSCON=y +CONFIG_POWER_RESET_SYSCON_POWEROFF=y +CONFIG_PPS=y +CONFIG_PREEMPT_NONE_BUILD=y +CONFIG_PRINTK_TIME=y +CONFIG_PTP_1588_CLOCK=y +CONFIG_PTP_1588_CLOCK_OPTIONAL=y +CONFIG_PWM=y +CONFIG_PWM_SIFIVE=y +CONFIG_PWM_SYSFS=y +CONFIG_QUEUED_RWLOCKS=y +CONFIG_RANDSTRUCT_NONE=y +CONFIG_RAS=y +CONFIG_RATIONAL=y +CONFIG_RCU_TRACE=y +CONFIG_RD_GZIP=y +CONFIG_REALTEK_PHY=y +CONFIG_REGMAP=y +CONFIG_REGMAP_MMIO=y +# CONFIG_RESET_ATTACK_MITIGATION is not set +CONFIG_RESET_CONTROLLER=y +CONFIG_RESET_SIMPLE=y +CONFIG_RFS_ACCEL=y +CONFIG_RISCV=y +CONFIG_RISCV_ALTERNATIVE=y +# CONFIG_RISCV_BOOT_SPINWAIT is not set +CONFIG_RISCV_DMA_NONCOHERENT=y +CONFIG_RISCV_INTC=y +CONFIG_RISCV_ISA_C=y +CONFIG_RISCV_ISA_FALLBACK=y +CONFIG_RISCV_ISA_SVNAPOT=y +CONFIG_RISCV_ISA_SVPBMT=y +CONFIG_RISCV_ISA_V=y +CONFIG_RISCV_ISA_V_DEFAULT_ENABLE=y +CONFIG_RISCV_ISA_ZBB=y +CONFIG_RISCV_ISA_ZICBOZ=y +CONFIG_RISCV_ISA_ZICBOM=y +CONFIG_RISCV_SBI=y +CONFIG_RISCV_SBI_V01=y +CONFIG_RISCV_TIMER=y +CONFIG_RPS=y +CONFIG_RTC_CLASS=y +# CONFIG_RTC_DRV_EFI is not set +CONFIG_RTC_I2C_AND_SPI=y +CONFIG_RWSEM_SPIN_ON_OWNER=y +CONFIG_SCHED_DEBUG=y +CONFIG_SCSI=y +CONFIG_SCSI_COMMON=y +CONFIG_SERIAL_8250_DEPRECATED_OPTIONS=y +CONFIG_SERIAL_8250_DW=y +CONFIG_SERIAL_8250_DWLIB=y +CONFIG_SERIAL_8250_EXAR=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_PCI=y +CONFIG_SERIAL_8250_RUNTIME_UARTS=4 +CONFIG_SERIAL_EARLYCON_RISCV_SBI=y +CONFIG_SERIAL_MCTRL_GPIO=y +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_SERIAL_SIFIVE=y +CONFIG_SERIAL_SIFIVE_CONSOLE=y +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +CONFIG_SG_POOL=y +CONFIG_SIFIVE_PLIC=y +CONFIG_SLUB_DEBUG=y +CONFIG_SMP=y +CONFIG_SOCK_RX_QUEUE_MAPPING=y +# CONFIG_SOC_MICROCHIP_POLARFIRE is not set +# CONFIG_SOC_SIFIVE is not set +CONFIG_SOC_SOPHGO=y +# CONFIG_SOC_STARFIVE is not set +# CONFIG_SOC_VIRT is not set +CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y +CONFIG_SPARSE_IRQ=y +CONFIG_SPI=y +CONFIG_SPI_BITBANG=y +CONFIG_SPI_MASTER=y +CONFIG_SPI_MEM=y +CONFIG_SPI_SIFIVE=y +CONFIG_SRCU=y +CONFIG_STACKDEPOT=y +CONFIG_STACKTRACE=y +CONFIG_SWIOTLB=y +CONFIG_SWPHY=y +CONFIG_SYSCTL_EXCEPTION_TRACE=y +# CONFIG_SYSFB_SIMPLEFB is not set +CONFIG_THREAD_INFO_IN_TASK=y +CONFIG_THREAD_SIZE_ORDER=2 +CONFIG_TICK_CPU_ACCOUNTING=y +CONFIG_TIMER_OF=y +CONFIG_TIMER_PROBE=y +CONFIG_TOOLCHAIN_HAS_ZICBOM=y +CONFIG_TOOLCHAIN_HAS_ZIHINTPAUSE=y +CONFIG_TOOLCHAIN_NEEDS_EXPLICIT_ZICSR_ZIFENCEI=y +CONFIG_TRACE_CLOCK=y +CONFIG_TREE_RCU=y +CONFIG_TREE_SRCU=y +CONFIG_TUNE_GENERIC=y +CONFIG_UCS2_STRING=y +CONFIG_UEVENT_HELPER_PATH="" +CONFIG_USB=y +CONFIG_USB_COMMON=y +CONFIG_USB_EHCI_HCD=y +# CONFIG_USB_EHCI_HCD_PLATFORM is not set +CONFIG_USB_EHCI_PCI=y +CONFIG_USB_HID=y +CONFIG_USB_NET_DRIVERS=y +CONFIG_USB_PCI=y +CONFIG_USB_STORAGE=y +CONFIG_USB_SUPPORT=y +# CONFIG_USB_UHCI_HCD is not set +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_PCI=y +# CONFIG_USB_XHCI_PLATFORM is not set +CONFIG_VFAT_FS=y +CONFIG_VGA_ARB=y +CONFIG_VGA_ARB_MAX_GPUS=16 +CONFIG_VMAP_STACK=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +# CONFIG_VT_HW_CONSOLE_BINDING is not set +CONFIG_WATCHDOG_CORE=y +CONFIG_XPS=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZONE_DMA32=y diff --git a/target/linux/cv18x0/generic/target.mk b/target/linux/cv18x0/generic/target.mk new file mode 100644 index 0000000000..f5cb1fb19b --- /dev/null +++ b/target/linux/cv18x0/generic/target.mk @@ -0,0 +1 @@ +BOARDNAME:=Generic diff --git a/target/linux/cv18x0/image/Config.in b/target/linux/cv18x0/image/Config.in new file mode 100644 index 0000000000..1d88edc6b0 --- /dev/null +++ b/target/linux/cv18x0/image/Config.in @@ -0,0 +1,4 @@ +config CV18X0_SD_BOOT_PARTSIZE + int "Boot (SD Card) filesystem partition size (in MB)" + depends on TARGET_cv18x0 + default 32 diff --git a/target/linux/cv18x0/image/Makefile b/target/linux/cv18x0/image/Makefile new file mode 100644 index 0000000000..d3ec852f5a --- /dev/null +++ b/target/linux/cv18x0/image/Makefile @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Copyright (C) 2024 Toco Technologies +# +include $(TOPDIR)/rules.mk +include $(INCLUDE_DIR)/image.mk + +FAT32_BLOCK_SIZE=1024 +FAT32_BLOCKS=$(shell echo $$(($(CONFIG_CV18X0_SD_BOOT_PARTSIZE)*1024*1024/$(FAT32_BLOCK_SIZE)))) + +KERNEL_LOADADDR:=0x80200000 + +define Build/riscv-sdcard + rm -f $@.boot #$(KDIR_TMP)/$(IMG_PREFIX)-$(PROFILE)-boot.img + mkfs.fat $@.boot -C $(FAT32_BLOCKS) + + $(STAGING_DIR_HOST)/bin/fiptool --fsbl $(STAGING_DIR_IMAGE)/bl2_cv1800b_milkv_duo_sd.bin \ + --opensbi $(STAGING_DIR_IMAGE)/fw_dynamic-generic.bin \ + --uboot $(STAGING_DIR_IMAGE)/$(UBOOT)-u-boot.bin \ + --ddr_param $(STAGING_DIR_IMAGE)/$(DDRPARAM) \ + --rtos /dev/null \ + $(STAGING_DIR_IMAGE)/fip_milkv_duo.bin + + mcopy -i $@.boot $(STAGING_DIR_IMAGE)/fip_milkv_duo.bin ::fip.bin + mcopy -i $@.boot $(IMAGE_KERNEL) ::sd.boot + + ./gen_cv18x0_sdcard_img.sh \ + $@ \ + $@.boot \ + $(IMAGE_ROOTFS) \ + $(CONFIG_CV18X0_SD_BOOT_PARTSIZE) \ + $(CONFIG_TARGET_ROOTFS_PARTSIZE) +endef + +define Device/Default + PROFILES := Default + KERNEL_NAME := Image + DTS_DIR := $(DTS_DIR)/sophgo + DEVICE_DTS := $$(SOC)-$(subst _,-,$(1)) + IMAGES := sdcard.img.gz + IMAGE/sdcard.img.gz := riscv-sdcard | append-metadata | gzip +endef + +define Device/FitImageLzma + KERNEL_SUFFIX := -fit-uImage.itb + KERNEL = kernel-bin | lzma | fit lzma $$(DTS_DIR)/$$(DEVICE_DTS).dtb + KERNEL_NAME := Image +endef + +define Device/milkv_duo + $(call Device/FitImageLzma) + DEVICE_VENDOR := MilkV + DEVICE_MODEL := Duo + SOC := cv1800b + DEVICE_DTS := $$(SOC)-milkv-duo + DEVICE_PACKAGES := opensbi_generic + UBOOT := milkv_duo + DDRPARAM := cv181x_ddr_param.bin +endef +TARGET_DEVICES += milkv_duo + +$(eval $(call BuildImage)) diff --git a/target/linux/cv18x0/image/gen_cv18x0_sdcard_img.sh b/target/linux/cv18x0/image/gen_cv18x0_sdcard_img.sh new file mode 100755 index 0000000000..cc7804387d --- /dev/null +++ b/target/linux/cv18x0/image/gen_cv18x0_sdcard_img.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: GPL-2.0-only +# +# Copyright (C) 2022 OpenWrt.org +# + +set -ex +[ $# -eq 5 ] || { + echo "SYNTAX: $0 " + exit 1 +} + +OUTPUT="$1" +BOOTFS="$2" +ROOTFS="$3" +BOOTFSSIZE="$4" +ROOTFSSIZE="$5" + +head=4 +sect=63 + +set $(ptgen -o $OUTPUT -h $head -s $sect -l 1024 -t c -p ${BOOTFSSIZE}M -t 83 -p ${ROOTFSSIZE}M) + +BOOTOFFSET=$(($1 / 512 )) +ROOTFSOFFSET=$(($3 / 512)) + +dd bs=512 if="$BOOTFS" of="$OUTPUT" seek=${BOOTOFFSET} conv=notrunc +dd bs=512 if="$ROOTFS" of="$OUTPUT" seek=${ROOTFSOFFSET} conv=notrunc diff --git a/target/linux/cv18x0/patches-6.6/0001-riscv-Add-Sophgo-SoC-platform-hardware-support.patch b/target/linux/cv18x0/patches-6.6/0001-riscv-Add-Sophgo-SoC-platform-hardware-support.patch new file mode 100644 index 0000000000..355cd0a31b --- /dev/null +++ b/target/linux/cv18x0/patches-6.6/0001-riscv-Add-Sophgo-SoC-platform-hardware-support.patch @@ -0,0 +1,30 @@ +From 28ecd3215ebc6271584f3b7b186223cb30f6b05b Mon Sep 17 00:00:00 2001 +From: Xiaoguang Xing +Date: Thu, 31 Aug 2023 10:21:03 +0800 +Subject: [PATCH 01/18] riscv: Add Sophgo SoC platform hardware support + +Signed-off-by: Xiaoguang Xing +--- + arch/riscv/Kconfig.socs | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs +index 30fd6a512828..ad7e01a959e5 100644 +--- a/arch/riscv/Kconfig.socs ++++ b/arch/riscv/Kconfig.socs +@@ -111,4 +111,12 @@ config SOC_CANAAN_K210_DTB_SOURCE + + endif # ARCH_CANAAN + ++config ARCH_SOPHGO ++ def_bool SOC_SOPHGO ++ ++config SOC_SOPHGO ++ bool "Sophgo SoCs" ++ help ++ This enables support for Sophgo SoC platform hardware. ++ + endmenu # "SoC selection" +-- +2.20.1 + diff --git a/target/linux/cv18x0/patches-6.6/0002-riscv-dts-sophgo-add-initial-CV1800B-SoC-device-tree.patch b/target/linux/cv18x0/patches-6.6/0002-riscv-dts-sophgo-add-initial-CV1800B-SoC-device-tree.patch new file mode 100644 index 0000000000..658e0b8877 --- /dev/null +++ b/target/linux/cv18x0/patches-6.6/0002-riscv-dts-sophgo-add-initial-CV1800B-SoC-device-tree.patch @@ -0,0 +1,147 @@ +From 53b8b80fdc210e7722f8ffd41bdfbcc0f5aea574 Mon Sep 17 00:00:00 2001 +From: Jisheng Zhang +Date: Fri, 6 Oct 2023 20:14:48 +0800 +Subject: [PATCH 02/18] riscv: dts: sophgo: add initial CV1800B SoC device tree + +Add initial device tree for the CV1800B RISC-V SoC by SOPHGO. + +Signed-off-by: Jisheng Zhang +Acked-by: Chen Wang +Signed-off-by: Conor Dooley +--- + arch/riscv/boot/dts/sophgo/cv1800b.dtsi | 123 ++++++++++++++++++++++++ + 1 file changed, 123 insertions(+) + create mode 100644 arch/riscv/boot/dts/sophgo/cv1800b.dtsi + +diff --git a/arch/riscv/boot/dts/sophgo/cv1800b.dtsi b/arch/riscv/boot/dts/sophgo/cv1800b.dtsi +new file mode 100644 +index 000000000000..df40e87ee063 +--- /dev/null ++++ b/arch/riscv/boot/dts/sophgo/cv1800b.dtsi +@@ -0,0 +1,123 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright (C) 2023 Jisheng Zhang ++ */ ++ ++#include ++ ++/ { ++ compatible = "sophgo,cv1800b"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ cpus: cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ timebase-frequency = <25000000>; ++ ++ cpu0: cpu@0 { ++ compatible = "thead,c906", "riscv"; ++ device_type = "cpu"; ++ reg = <0>; ++ d-cache-block-size = <64>; ++ d-cache-sets = <512>; ++ d-cache-size = <65536>; ++ i-cache-block-size = <64>; ++ i-cache-sets = <128>; ++ i-cache-size = <32768>; ++ mmu-type = "riscv,sv39"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicntr", "zicsr", ++ "zifencei", "zihpm"; ++ ++ cpu0_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #address-cells = <0>; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ }; ++ ++ osc: oscillator { ++ compatible = "fixed-clock"; ++ clock-output-names = "osc_25m"; ++ #clock-cells = <0>; ++ }; ++ ++ soc { ++ compatible = "simple-bus"; ++ interrupt-parent = <&plic>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ dma-noncoherent; ++ ranges; ++ ++ uart0: serial@4140000 { ++ compatible = "snps,dw-apb-uart"; ++ reg = <0x04140000 0x100>; ++ interrupts = <44 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&osc>; ++ reg-shift = <2>; ++ reg-io-width = <4>; ++ status = "disabled"; ++ }; ++ ++ uart1: serial@4150000 { ++ compatible = "snps,dw-apb-uart"; ++ reg = <0x04150000 0x100>; ++ interrupts = <45 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&osc>; ++ reg-shift = <2>; ++ reg-io-width = <4>; ++ status = "disabled"; ++ }; ++ ++ uart2: serial@4160000 { ++ compatible = "snps,dw-apb-uart"; ++ reg = <0x04160000 0x100>; ++ interrupts = <46 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&osc>; ++ reg-shift = <2>; ++ reg-io-width = <4>; ++ status = "disabled"; ++ }; ++ ++ uart3: serial@4170000 { ++ compatible = "snps,dw-apb-uart"; ++ reg = <0x04170000 0x100>; ++ interrupts = <47 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&osc>; ++ reg-shift = <2>; ++ reg-io-width = <4>; ++ status = "disabled"; ++ }; ++ ++ uart4: serial@41c0000 { ++ compatible = "snps,dw-apb-uart"; ++ reg = <0x041c0000 0x100>; ++ interrupts = <48 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&osc>; ++ reg-shift = <2>; ++ reg-io-width = <4>; ++ status = "disabled"; ++ }; ++ ++ plic: interrupt-controller@70000000 { ++ compatible = "sophgo,cv1800b-plic", "thead,c900-plic"; ++ reg = <0x70000000 0x4000000>; ++ interrupts-extended = <&cpu0_intc 11>, <&cpu0_intc 9>; ++ interrupt-controller; ++ #address-cells = <0>; ++ #interrupt-cells = <2>; ++ riscv,ndev = <101>; ++ }; ++ ++ clint: timer@74000000 { ++ compatible = "sophgo,cv1800b-clint", "thead,c900-clint"; ++ reg = <0x74000000 0x10000>; ++ interrupts-extended = <&cpu0_intc 3>, <&cpu0_intc 7>; ++ }; ++ }; ++}; +-- +2.20.1 + diff --git a/target/linux/cv18x0/patches-6.6/0003-riscv-dts-add-initial-SOPHGO-SG2042-SoC-device-tree.patch b/target/linux/cv18x0/patches-6.6/0003-riscv-dts-add-initial-SOPHGO-SG2042-SoC-device-tree.patch new file mode 100644 index 0000000000..4209da961a --- /dev/null +++ b/target/linux/cv18x0/patches-6.6/0003-riscv-dts-add-initial-SOPHGO-SG2042-SoC-device-tree.patch @@ -0,0 +1,2232 @@ +From ad6de25748213578dc88100b0a7bf7bec4f44dff Mon Sep 17 00:00:00 2001 +From: Chen Wang +Date: Wed, 20 Sep 2023 14:40:32 +0800 +Subject: [PATCH 03/18] riscv: dts: add initial SOPHGO SG2042 SoC device tree + +Milk-V Pioneer motherboard is powered by SOPHON's SG2042. + +SG2042 is server grade chip with high performance, low power +consumption and high data throughput. +Key features: +- 64 RISC-V cpu cores which implements IMAFDC +- 4 cores per cluster, 16 clusters on chip +- ...... + +More info is available at [1]. + +[1]: https://en.sophgo.com/product/introduce/sg2042.html + +Currently only support booting into console with only uart, +other features will be added soon later. + +Acked-by: Xiaoguang Xing +Signed-off-by: Xiaoguang Xing +Signed-off-by: Inochi Amaoto +Signed-off-by: Emil Renner Berthing +Signed-off-by: Chen Wang +Reviewed-by: Guo Ren +--- + arch/riscv/boot/dts/sophgo/sg2042-cpus.dtsi | 1744 +++++++++++++++++++ + arch/riscv/boot/dts/sophgo/sg2042.dtsi | 439 +++++ + 2 files changed, 2183 insertions(+) + create mode 100644 arch/riscv/boot/dts/sophgo/sg2042-cpus.dtsi + create mode 100644 arch/riscv/boot/dts/sophgo/sg2042.dtsi + +diff --git a/arch/riscv/boot/dts/sophgo/sg2042-cpus.dtsi b/arch/riscv/boot/dts/sophgo/sg2042-cpus.dtsi +new file mode 100644 +index 000000000000..9fc79b1cf3bf +--- /dev/null ++++ b/arch/riscv/boot/dts/sophgo/sg2042-cpus.dtsi +@@ -0,0 +1,1744 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* ++ * Copyright (C) 2022 Sophgo Technology Inc. All rights reserved. ++ */ ++ ++/ { ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ timebase-frequency = <50000000>; ++ ++ cpu-map { ++ socket0 { ++ 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>; ++ }; ++ }; ++ ++ cluster2 { ++ core0 { ++ cpu = <&cpu16>; ++ }; ++ core1 { ++ cpu = <&cpu17>; ++ }; ++ core2 { ++ cpu = <&cpu18>; ++ }; ++ core3 { ++ cpu = <&cpu19>; ++ }; ++ }; ++ ++ cluster3 { ++ core0 { ++ cpu = <&cpu20>; ++ }; ++ core1 { ++ cpu = <&cpu21>; ++ }; ++ core2 { ++ cpu = <&cpu22>; ++ }; ++ core3 { ++ cpu = <&cpu23>; ++ }; ++ }; ++ ++ cluster4 { ++ core0 { ++ cpu = <&cpu8>; ++ }; ++ core1 { ++ cpu = <&cpu9>; ++ }; ++ core2 { ++ cpu = <&cpu10>; ++ }; ++ core3 { ++ cpu = <&cpu11>; ++ }; ++ }; ++ ++ cluster5 { ++ core0 { ++ cpu = <&cpu12>; ++ }; ++ core1 { ++ cpu = <&cpu13>; ++ }; ++ core2 { ++ cpu = <&cpu14>; ++ }; ++ core3 { ++ cpu = <&cpu15>; ++ }; ++ }; ++ ++ cluster6 { ++ core0 { ++ cpu = <&cpu24>; ++ }; ++ core1 { ++ cpu = <&cpu25>; ++ }; ++ core2 { ++ cpu = <&cpu26>; ++ }; ++ core3 { ++ cpu = <&cpu27>; ++ }; ++ }; ++ ++ cluster7 { ++ core0 { ++ cpu = <&cpu28>; ++ }; ++ core1 { ++ cpu = <&cpu29>; ++ }; ++ core2 { ++ cpu = <&cpu30>; ++ }; ++ core3 { ++ cpu = <&cpu31>; ++ }; ++ }; ++ ++ cluster8 { ++ core0 { ++ cpu = <&cpu32>; ++ }; ++ core1 { ++ cpu = <&cpu33>; ++ }; ++ core2 { ++ cpu = <&cpu34>; ++ }; ++ core3 { ++ cpu = <&cpu35>; ++ }; ++ }; ++ ++ cluster9 { ++ core0 { ++ cpu = <&cpu36>; ++ }; ++ core1 { ++ cpu = <&cpu37>; ++ }; ++ core2 { ++ cpu = <&cpu38>; ++ }; ++ core3 { ++ cpu = <&cpu39>; ++ }; ++ }; ++ ++ cluster10 { ++ core0 { ++ cpu = <&cpu48>; ++ }; ++ core1 { ++ cpu = <&cpu49>; ++ }; ++ core2 { ++ cpu = <&cpu50>; ++ }; ++ core3 { ++ cpu = <&cpu51>; ++ }; ++ }; ++ ++ cluster11 { ++ core0 { ++ cpu = <&cpu52>; ++ }; ++ core1 { ++ cpu = <&cpu53>; ++ }; ++ core2 { ++ cpu = <&cpu54>; ++ }; ++ core3 { ++ cpu = <&cpu55>; ++ }; ++ }; ++ ++ cluster12 { ++ core0 { ++ cpu = <&cpu40>; ++ }; ++ core1 { ++ cpu = <&cpu41>; ++ }; ++ core2 { ++ cpu = <&cpu42>; ++ }; ++ core3 { ++ cpu = <&cpu43>; ++ }; ++ }; ++ ++ cluster13 { ++ core0 { ++ cpu = <&cpu44>; ++ }; ++ core1 { ++ cpu = <&cpu45>; ++ }; ++ core2 { ++ cpu = <&cpu46>; ++ }; ++ core3 { ++ cpu = <&cpu47>; ++ }; ++ }; ++ ++ cluster14 { ++ core0 { ++ cpu = <&cpu56>; ++ }; ++ core1 { ++ cpu = <&cpu57>; ++ }; ++ core2 { ++ cpu = <&cpu58>; ++ }; ++ core3 { ++ cpu = <&cpu59>; ++ }; ++ }; ++ ++ cluster15 { ++ core0 { ++ cpu = <&cpu60>; ++ }; ++ core1 { ++ cpu = <&cpu61>; ++ }; ++ core2 { ++ cpu = <&cpu62>; ++ }; ++ core3 { ++ cpu = <&cpu63>; ++ }; ++ }; ++ }; ++ }; ++ ++ cpu0: cpu@0 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <0>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache0>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu0_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu1: cpu@1 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <1>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache0>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu1_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu2: cpu@2 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <2>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache0>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu2_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu3: cpu@3 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <3>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache0>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu3_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu4: cpu@4 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <4>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache1>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu4_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu5: cpu@5 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <5>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache1>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu5_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu6: cpu@6 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <6>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache1>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu6_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu7: cpu@7 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <7>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache1>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu7_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu8: cpu@8 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <8>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache4>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu8_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu9: cpu@9 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <9>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache4>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu9_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu10: cpu@10 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <10>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache4>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu10_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu11: cpu@11 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <11>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache4>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu11_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu12: cpu@12 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <12>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache5>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu12_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu13: cpu@13 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <13>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache5>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu13_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu14: cpu@14 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <14>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache5>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu14_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu15: cpu@15 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <15>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache5>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu15_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu16: cpu@16 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <16>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache2>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu16_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu17: cpu@17 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <17>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache2>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu17_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu18: cpu@18 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <18>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache2>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu18_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu19: cpu@19 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <19>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache2>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu19_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu20: cpu@20 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <20>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache3>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu20_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu21: cpu@21 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <21>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache3>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu21_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu22: cpu@22 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <22>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache3>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu22_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu23: cpu@23 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <23>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache3>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu23_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu24: cpu@24 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <24>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache6>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu24_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu25: cpu@25 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <25>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache6>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu25_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu26: cpu@26 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <26>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache6>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu26_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu27: cpu@27 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <27>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache6>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu27_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu28: cpu@28 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <28>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache7>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu28_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu29: cpu@29 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <29>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache7>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu29_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu30: cpu@30 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <30>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache7>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu30_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu31: cpu@31 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <31>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache7>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu31_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu32: cpu@32 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <32>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache8>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu32_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu33: cpu@33 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <33>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache8>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu33_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu34: cpu@34 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <34>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache8>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu34_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu35: cpu@35 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <35>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache8>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu35_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu36: cpu@36 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <36>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache9>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu36_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu37: cpu@37 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <37>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache9>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu37_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu38: cpu@38 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <38>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache9>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu38_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu39: cpu@39 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <39>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache9>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu39_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu40: cpu@40 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <40>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache12>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu40_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu41: cpu@41 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <41>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache12>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu41_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu42: cpu@42 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <42>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache12>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu42_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu43: cpu@43 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <43>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache12>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu43_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu44: cpu@44 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <44>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache13>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu44_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu45: cpu@45 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <45>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache13>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu45_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu46: cpu@46 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <46>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache13>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu46_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu47: cpu@47 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <47>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache13>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu47_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu48: cpu@48 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <48>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache10>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu48_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu49: cpu@49 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <49>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache10>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu49_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu50: cpu@50 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <50>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache10>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu50_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu51: cpu@51 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <51>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache10>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu51_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu52: cpu@52 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <52>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache11>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu52_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu53: cpu@53 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <53>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache11>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu53_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu54: cpu@54 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <54>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache11>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu54_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu55: cpu@55 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <55>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache11>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu55_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu56: cpu@56 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <56>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache14>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu56_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu57: cpu@57 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <57>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache14>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu57_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu58: cpu@58 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <58>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache14>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu58_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu59: cpu@59 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <59>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache14>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu59_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu60: cpu@60 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <60>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache15>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu60_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu61: cpu@61 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <61>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache15>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu61_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu62: cpu@62 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <62>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache15>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu62_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ cpu63: cpu@63 { ++ compatible = "thead,c920", "riscv"; ++ device_type = "cpu"; ++ riscv,isa = "rv64imafdc"; ++ reg = <63>; ++ i-cache-block-size = <64>; ++ i-cache-size = <65536>; ++ i-cache-sets = <512>; ++ d-cache-block-size = <64>; ++ d-cache-size = <65536>; ++ d-cache-sets = <512>; ++ next-level-cache = <&l2_cache15>; ++ mmu-type = "riscv,sv39"; ++ ++ cpu63_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ ++ l2_cache0: l2-cache@0 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ }; ++ ++ l2_cache1: l2-cache@1 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ }; ++ ++ l2_cache2: l2-cache@2 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ }; ++ ++ l2_cache3: l2-cache@3 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ }; ++ ++ l2_cache4: l2-cache@4 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ }; ++ ++ l2_cache5: l2-cache@5 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ }; ++ ++ l2_cache6: l2-cache@6 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ }; ++ ++ l2_cache7: l2-cache@7 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ }; ++ ++ l2_cache8: l2-cache@8 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ }; ++ ++ l2_cache9: l2-cache@9 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ }; ++ ++ l2_cache10: l2-cache@10 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ }; ++ ++ l2_cache11: l2-cache@11 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ }; ++ ++ l2_cache12: l2-cache@12 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ }; ++ ++ l2_cache13: l2-cache@13 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ }; ++ ++ l2_cache14: l2-cache@14 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ }; ++ ++ l2_cache15: l2-cache@15 { ++ compatible = "cache"; ++ cache-block-size = <64>; ++ cache-level = <2>; ++ cache-size = <1048576>; ++ cache-sets = <1024>; ++ cache-unified; ++ }; ++ }; ++}; +diff --git a/arch/riscv/boot/dts/sophgo/sg2042.dtsi b/arch/riscv/boot/dts/sophgo/sg2042.dtsi +new file mode 100644 +index 000000000000..747fd9764c95 +--- /dev/null ++++ b/arch/riscv/boot/dts/sophgo/sg2042.dtsi +@@ -0,0 +1,439 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* ++ * Copyright (C) 2022 Sophgo Technology Inc. All rights reserved. ++ */ ++ ++/dts-v1/; ++#include ++ ++#include "sg2042-cpus.dtsi" ++ ++#define SOC_PERIPHERAL_IRQ(nr) (nr) ++ ++/ { ++ compatible = "sophgo,sg2042"; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ dma-noncoherent; ++ ++ aliases { ++ serial0 = &uart0; ++ }; ++ ++ /* the mem node will be updated by ZSBL. */ ++ memory@0 { ++ device_type = "memory"; ++ reg = <0x00000000 0x00000000 0x00000000 0x00000000>; ++ }; ++ ++ memory@1 { ++ device_type = "memory"; ++ reg = <0x00000000 0x00000001 0x00000000 0x00000000>; ++ }; ++ ++ memory@2 { ++ device_type = "memory"; ++ reg = <0x00000000 0x00000002 0x00000000 0x00000000>; ++ }; ++ ++ memory@3 { ++ device_type = "memory"; ++ reg = <0x00000000 0x00000003 0x00000000 0x00000000>; ++ }; ++ ++ pmu { ++ compatible = "riscv,pmu"; ++ riscv,event-to-mhpmevent = ++ <0x00003 0x00000000 0x00000010>, ++ <0x00004 0x00000000 0x00000011>, ++ <0x00005 0x00000000 0x00000007>, ++ <0x00006 0x00000000 0x00000006>, ++ <0x00008 0x00000000 0x00000027>, ++ <0x00009 0x00000000 0x00000028>, ++ <0x10000 0x00000000 0x0000000c>, ++ <0x10001 0x00000000 0x0000000d>, ++ <0x10002 0x00000000 0x0000000e>, ++ <0x10003 0x00000000 0x0000000f>, ++ <0x10008 0x00000000 0x00000001>, ++ <0x10009 0x00000000 0x00000002>, ++ <0x10010 0x00000000 0x00000010>, ++ <0x10011 0x00000000 0x00000011>, ++ <0x10012 0x00000000 0x00000012>, ++ <0x10013 0x00000000 0x00000013>, ++ <0x10019 0x00000000 0x00000004>, ++ <0x10021 0x00000000 0x00000003>, ++ <0x10030 0x00000000 0x0000001c>, ++ <0x10031 0x00000000 0x0000001b>; ++ riscv,event-to-mhpmcounters = ++ <0x00003 0x00003 0xfffffff8>, ++ <0x00004 0x00004 0xfffffff8>, ++ <0x00005 0x00005 0xfffffff8>, ++ <0x00006 0x00006 0xfffffff8>, ++ <0x00007 0x00007 0xfffffff8>, ++ <0x00008 0x00008 0xfffffff8>, ++ <0x00009 0x00009 0xfffffff8>, ++ <0x0000a 0x0000a 0xfffffff8>, ++ <0x10000 0x10000 0xfffffff8>, ++ <0x10001 0x10001 0xfffffff8>, ++ <0x10002 0x10002 0xfffffff8>, ++ <0x10003 0x10003 0xfffffff8>, ++ <0x10008 0x10008 0xfffffff8>, ++ <0x10009 0x10009 0xfffffff8>, ++ <0x10010 0x10010 0xfffffff8>, ++ <0x10011 0x10011 0xfffffff8>, ++ <0x10012 0x10012 0xfffffff8>, ++ <0x10013 0x10013 0xfffffff8>, ++ <0x10019 0x10019 0xfffffff8>, ++ <0x10021 0x10021 0xfffffff8>, ++ <0x10030 0x10030 0xfffffff8>, ++ <0x10031 0x10031 0xfffffff8>; ++ riscv,raw-event-to-mhpmcounters = ++ <0x00000000 0x00000001 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000002 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000003 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000004 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000005 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000006 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000007 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000008 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000009 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x0000000a 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x0000000b 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x0000000c 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x0000000d 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x0000000e 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x0000000f 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000010 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000011 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000012 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000013 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000014 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000015 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000016 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000017 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000018 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000019 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x0000001a 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x0000001b 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x0000001c 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x0000001d 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x0000001e 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x0000001f 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000020 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000021 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000022 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000023 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000024 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000025 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000026 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000027 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000028 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x00000029 0xffffffff 0xffffffff 0xfffffff8>, ++ <0x00000000 0x0000002a 0xffffffff 0xffffffff 0xfffffff8>; ++ }; ++ ++ soc: soc { ++ compatible = "simple-bus"; ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ clint_mswi: interrupt-controller@7094000000 { ++ compatible = "sophgo,sg2042-clint-mswi", "thead,c900-clint-mswi"; ++ reg = <0x00000070 0x94000000 0x00000000 0x00004000>; ++ interrupts-extended = <&cpu0_intc 3>, ++ <&cpu1_intc 3>, ++ <&cpu2_intc 3>, ++ <&cpu3_intc 3>, ++ <&cpu4_intc 3>, ++ <&cpu5_intc 3>, ++ <&cpu6_intc 3>, ++ <&cpu7_intc 3>, ++ <&cpu8_intc 3>, ++ <&cpu9_intc 3>, ++ <&cpu10_intc 3>, ++ <&cpu11_intc 3>, ++ <&cpu12_intc 3>, ++ <&cpu13_intc 3>, ++ <&cpu14_intc 3>, ++ <&cpu15_intc 3>, ++ <&cpu16_intc 3>, ++ <&cpu17_intc 3>, ++ <&cpu18_intc 3>, ++ <&cpu19_intc 3>, ++ <&cpu20_intc 3>, ++ <&cpu21_intc 3>, ++ <&cpu22_intc 3>, ++ <&cpu23_intc 3>, ++ <&cpu24_intc 3>, ++ <&cpu25_intc 3>, ++ <&cpu26_intc 3>, ++ <&cpu27_intc 3>, ++ <&cpu28_intc 3>, ++ <&cpu29_intc 3>, ++ <&cpu30_intc 3>, ++ <&cpu31_intc 3>, ++ <&cpu32_intc 3>, ++ <&cpu33_intc 3>, ++ <&cpu34_intc 3>, ++ <&cpu35_intc 3>, ++ <&cpu36_intc 3>, ++ <&cpu37_intc 3>, ++ <&cpu38_intc 3>, ++ <&cpu39_intc 3>, ++ <&cpu40_intc 3>, ++ <&cpu41_intc 3>, ++ <&cpu42_intc 3>, ++ <&cpu43_intc 3>, ++ <&cpu44_intc 3>, ++ <&cpu45_intc 3>, ++ <&cpu46_intc 3>, ++ <&cpu47_intc 3>, ++ <&cpu48_intc 3>, ++ <&cpu49_intc 3>, ++ <&cpu50_intc 3>, ++ <&cpu51_intc 3>, ++ <&cpu52_intc 3>, ++ <&cpu53_intc 3>, ++ <&cpu54_intc 3>, ++ <&cpu55_intc 3>, ++ <&cpu56_intc 3>, ++ <&cpu57_intc 3>, ++ <&cpu58_intc 3>, ++ <&cpu59_intc 3>, ++ <&cpu60_intc 3>, ++ <&cpu61_intc 3>, ++ <&cpu62_intc 3>, ++ <&cpu63_intc 3>; ++ }; ++ ++ clint_mtimer0: timer@70ac000000 { ++ compatible = "sophgo,sg2042-clint-mtimer", "thead,c900-clint-mtimer"; ++ reg = <0x00000070 0xac000000 0x00000000 0x00007ff8>; ++ interrupts-extended = <&cpu0_intc 7>, ++ <&cpu1_intc 7>, ++ <&cpu2_intc 7>, ++ <&cpu3_intc 7>; ++ }; ++ ++ clint_mtimer1: timer@70ac010000 { ++ compatible = "sophgo,sg2042-clint-mtimer", "thead,c900-clint-mtimer"; ++ reg = <0x00000070 0xac010000 0x00000000 0x00007ff8>; ++ interrupts-extended = <&cpu4_intc 7>, ++ <&cpu5_intc 7>, ++ <&cpu6_intc 7>, ++ <&cpu7_intc 7>; ++ }; ++ ++ clint_mtimer2: timer@70ac020000 { ++ compatible = "sophgo,sg2042-clint-mtimer", "thead,c900-clint-mtimer"; ++ reg = <0x00000070 0xac020000 0x00000000 0x00007ff8>; ++ interrupts-extended = <&cpu8_intc 7>, ++ <&cpu9_intc 7>, ++ <&cpu10_intc 7>, ++ <&cpu11_intc 7>; ++ }; ++ ++ clint_mtimer3: timer@70ac030000 { ++ compatible = "sophgo,sg2042-clint-mtimer", "thead,c900-clint-mtimer"; ++ reg = <0x00000070 0xac030000 0x00000000 0x00007ff8>; ++ interrupts-extended = <&cpu12_intc 7>, ++ <&cpu13_intc 7>, ++ <&cpu14_intc 7>, ++ <&cpu15_intc 7>; ++ }; ++ ++ clint_mtimer4: timer@70ac040000 { ++ compatible = "sophgo,sg2042-clint-mtimer", "thead,c900-clint-mtimer"; ++ reg = <0x00000070 0xac040000 0x00000000 0x00007ff8>; ++ interrupts-extended = <&cpu16_intc 7>, ++ <&cpu17_intc 7>, ++ <&cpu18_intc 7>, ++ <&cpu19_intc 7>; ++ }; ++ ++ clint_mtimer5: timer@70ac050000 { ++ compatible = "sophgo,sg2042-clint-mtimer", "thead,c900-clint-mtimer"; ++ reg = <0x00000070 0xac050000 0x00000000 0x00007ff8>; ++ interrupts-extended = <&cpu20_intc 7>, ++ <&cpu21_intc 7>, ++ <&cpu22_intc 7>, ++ <&cpu23_intc 7>; ++ }; ++ ++ clint_mtimer6: timer@70ac060000 { ++ compatible = "sophgo,sg2042-clint-mtimer", "thead,c900-clint-mtimer"; ++ reg = <0x00000070 0xac060000 0x00000000 0x00007ff8>; ++ interrupts-extended = <&cpu24_intc 7>, ++ <&cpu25_intc 7>, ++ <&cpu26_intc 7>, ++ <&cpu27_intc 7>; ++ }; ++ ++ clint_mtimer7: timer@70ac070000 { ++ compatible = "sophgo,sg2042-clint-mtimer", "thead,c900-clint-mtimer"; ++ reg = <0x00000070 0xac070000 0x00000000 0x00007ff8>; ++ interrupts-extended = <&cpu28_intc 7>, ++ <&cpu29_intc 7>, ++ <&cpu30_intc 7>, ++ <&cpu31_intc 7>; ++ }; ++ ++ clint_mtimer8: timer@70ac080000 { ++ compatible = "sophgo,sg2042-clint-mtimer", "thead,c900-clint-mtimer"; ++ reg = <0x00000070 0xac080000 0x00000000 0x00007ff8>; ++ interrupts-extended = <&cpu32_intc 7>, ++ <&cpu33_intc 7>, ++ <&cpu34_intc 7>, ++ <&cpu35_intc 7>; ++ }; ++ ++ clint_mtimer9: timer@70ac090000 { ++ compatible = "sophgo,sg2042-clint-mtimer", "thead,c900-clint-mtimer"; ++ reg = <0x00000070 0xac090000 0x00000000 0x00007ff8>; ++ interrupts-extended = <&cpu36_intc 7>, ++ <&cpu37_intc 7>, ++ <&cpu38_intc 7>, ++ <&cpu39_intc 7>; ++ }; ++ ++ clint_mtimer10: timer@70ac0a0000 { ++ compatible = "sophgo,sg2042-clint-mtimer", "thead,c900-clint-mtimer"; ++ reg = <0x00000070 0xac0a0000 0x00000000 0x00007ff8>; ++ interrupts-extended = <&cpu40_intc 7>, ++ <&cpu41_intc 7>, ++ <&cpu42_intc 7>, ++ <&cpu43_intc 7>; ++ }; ++ ++ clint_mtimer11: timer@70ac0b0000 { ++ compatible = "sophgo,sg2042-clint-mtimer", "thead,c900-clint-mtimer"; ++ reg = <0x00000070 0xac0b0000 0x00000000 0x00007ff8>; ++ interrupts-extended = <&cpu44_intc 7>, ++ <&cpu45_intc 7>, ++ <&cpu46_intc 7>, ++ <&cpu47_intc 7>; ++ }; ++ ++ clint_mtimer12: timer@70ac0c0000 { ++ compatible = "sophgo,sg2042-clint-mtimer", "thead,c900-clint-mtimer"; ++ reg = <0x00000070 0xac0c0000 0x00000000 0x00007ff8>; ++ interrupts-extended = <&cpu48_intc 7>, ++ <&cpu49_intc 7>, ++ <&cpu50_intc 7>, ++ <&cpu51_intc 7>; ++ }; ++ ++ clint_mtimer13: timer@70ac0d0000 { ++ compatible = "sophgo,sg2042-clint-mtimer", "thead,c900-clint-mtimer"; ++ reg = <0x00000070 0xac0d0000 0x00000000 0x00007ff8>; ++ interrupts-extended = <&cpu52_intc 7>, ++ <&cpu53_intc 7>, ++ <&cpu54_intc 7>, ++ <&cpu55_intc 7>; ++ }; ++ ++ clint_mtimer14: timer@70ac0e0000 { ++ compatible = "sophgo,sg2042-clint-mtimer", "thead,c900-clint-mtimer"; ++ reg = <0x00000070 0xac0e0000 0x00000000 0x00007ff8>; ++ interrupts-extended = <&cpu56_intc 7>, ++ <&cpu57_intc 7>, ++ <&cpu58_intc 7>, ++ <&cpu59_intc 7>; ++ }; ++ ++ clint_mtimer15: timer@70ac0f0000 { ++ compatible = "sophgo,sg2042-clint-mtimer", "thead,c900-clint-mtimer"; ++ reg = <0x00000070 0xac0f0000 0x00000000 0x00007ff8>; ++ interrupts-extended = <&cpu60_intc 7>, ++ <&cpu61_intc 7>, ++ <&cpu62_intc 7>, ++ <&cpu63_intc 7>; ++ }; ++ ++ intc: interrupt-controller@7090000000 { ++ compatible = "sophgo,sg2042-plic", "thead,c900-plic"; ++ #address-cells = <0>; ++ #interrupt-cells = <2>; ++ reg = <0x00000070 0x90000000 0x00000000 0x04000000>; ++ interrupt-controller; ++ interrupts-extended = ++ <&cpu0_intc 0xffffffff>, <&cpu0_intc 9>, ++ <&cpu1_intc 0xffffffff>, <&cpu1_intc 9>, ++ <&cpu2_intc 0xffffffff>, <&cpu2_intc 9>, ++ <&cpu3_intc 0xffffffff>, <&cpu3_intc 9>, ++ <&cpu4_intc 0xffffffff>, <&cpu4_intc 9>, ++ <&cpu5_intc 0xffffffff>, <&cpu5_intc 9>, ++ <&cpu6_intc 0xffffffff>, <&cpu6_intc 9>, ++ <&cpu7_intc 0xffffffff>, <&cpu7_intc 9>, ++ <&cpu8_intc 0xffffffff>, <&cpu8_intc 9>, ++ <&cpu9_intc 0xffffffff>, <&cpu9_intc 9>, ++ <&cpu10_intc 0xffffffff>, <&cpu10_intc 9>, ++ <&cpu11_intc 0xffffffff>, <&cpu11_intc 9>, ++ <&cpu12_intc 0xffffffff>, <&cpu12_intc 9>, ++ <&cpu13_intc 0xffffffff>, <&cpu13_intc 9>, ++ <&cpu14_intc 0xffffffff>, <&cpu14_intc 9>, ++ <&cpu15_intc 0xffffffff>, <&cpu15_intc 9>, ++ <&cpu16_intc 0xffffffff>, <&cpu16_intc 9>, ++ <&cpu17_intc 0xffffffff>, <&cpu17_intc 9>, ++ <&cpu18_intc 0xffffffff>, <&cpu18_intc 9>, ++ <&cpu19_intc 0xffffffff>, <&cpu19_intc 9>, ++ <&cpu20_intc 0xffffffff>, <&cpu20_intc 9>, ++ <&cpu21_intc 0xffffffff>, <&cpu21_intc 9>, ++ <&cpu22_intc 0xffffffff>, <&cpu22_intc 9>, ++ <&cpu23_intc 0xffffffff>, <&cpu23_intc 9>, ++ <&cpu24_intc 0xffffffff>, <&cpu24_intc 9>, ++ <&cpu25_intc 0xffffffff>, <&cpu25_intc 9>, ++ <&cpu26_intc 0xffffffff>, <&cpu26_intc 9>, ++ <&cpu27_intc 0xffffffff>, <&cpu27_intc 9>, ++ <&cpu28_intc 0xffffffff>, <&cpu28_intc 9>, ++ <&cpu29_intc 0xffffffff>, <&cpu29_intc 9>, ++ <&cpu30_intc 0xffffffff>, <&cpu30_intc 9>, ++ <&cpu31_intc 0xffffffff>, <&cpu31_intc 9>, ++ <&cpu32_intc 0xffffffff>, <&cpu32_intc 9>, ++ <&cpu33_intc 0xffffffff>, <&cpu33_intc 9>, ++ <&cpu34_intc 0xffffffff>, <&cpu34_intc 9>, ++ <&cpu35_intc 0xffffffff>, <&cpu35_intc 9>, ++ <&cpu36_intc 0xffffffff>, <&cpu36_intc 9>, ++ <&cpu37_intc 0xffffffff>, <&cpu37_intc 9>, ++ <&cpu38_intc 0xffffffff>, <&cpu38_intc 9>, ++ <&cpu39_intc 0xffffffff>, <&cpu39_intc 9>, ++ <&cpu40_intc 0xffffffff>, <&cpu40_intc 9>, ++ <&cpu41_intc 0xffffffff>, <&cpu41_intc 9>, ++ <&cpu42_intc 0xffffffff>, <&cpu42_intc 9>, ++ <&cpu43_intc 0xffffffff>, <&cpu43_intc 9>, ++ <&cpu44_intc 0xffffffff>, <&cpu44_intc 9>, ++ <&cpu45_intc 0xffffffff>, <&cpu45_intc 9>, ++ <&cpu46_intc 0xffffffff>, <&cpu46_intc 9>, ++ <&cpu47_intc 0xffffffff>, <&cpu47_intc 9>, ++ <&cpu48_intc 0xffffffff>, <&cpu48_intc 9>, ++ <&cpu49_intc 0xffffffff>, <&cpu49_intc 9>, ++ <&cpu50_intc 0xffffffff>, <&cpu50_intc 9>, ++ <&cpu51_intc 0xffffffff>, <&cpu51_intc 9>, ++ <&cpu52_intc 0xffffffff>, <&cpu52_intc 9>, ++ <&cpu53_intc 0xffffffff>, <&cpu53_intc 9>, ++ <&cpu54_intc 0xffffffff>, <&cpu54_intc 9>, ++ <&cpu55_intc 0xffffffff>, <&cpu55_intc 9>, ++ <&cpu56_intc 0xffffffff>, <&cpu56_intc 9>, ++ <&cpu57_intc 0xffffffff>, <&cpu57_intc 9>, ++ <&cpu58_intc 0xffffffff>, <&cpu58_intc 9>, ++ <&cpu59_intc 0xffffffff>, <&cpu59_intc 9>, ++ <&cpu60_intc 0xffffffff>, <&cpu60_intc 9>, ++ <&cpu61_intc 0xffffffff>, <&cpu61_intc 9>, ++ <&cpu62_intc 0xffffffff>, <&cpu62_intc 9>, ++ <&cpu63_intc 0xffffffff>, <&cpu63_intc 9>; ++ riscv,ndev = <224>; ++ }; ++ ++ uart0: serial@7040000000 { ++ compatible = "sophgo,sg2042-uart", "snps,dw-apb-uart"; ++ reg = <0x00000070 0x40000000 0x00000000 0x00001000>; ++ interrupt-parent = <&intc>; ++ interrupts = ; ++ clock-frequency = <500000000>; ++ reg-shift = <2>; ++ reg-io-width = <4>; ++ status = "disabled"; ++ }; ++ }; ++}; +-- +2.20.1 + diff --git a/target/linux/cv18x0/patches-6.6/0004-riscv-dts-sophgo-add-Milk-V-Pioneer-board-device-tre.patch b/target/linux/cv18x0/patches-6.6/0004-riscv-dts-sophgo-add-Milk-V-Pioneer-board-device-tre.patch new file mode 100644 index 0000000000..83e367223f --- /dev/null +++ b/target/linux/cv18x0/patches-6.6/0004-riscv-dts-sophgo-add-Milk-V-Pioneer-board-device-tre.patch @@ -0,0 +1,76 @@ +From c43ee7ae03d60ca24e29ef1079be21dcd8023dfe Mon Sep 17 00:00:00 2001 +From: Chen Wang +Date: Wed, 20 Sep 2023 14:40:53 +0800 +Subject: [PATCH 04/18] riscv: dts: sophgo: add Milk-V Pioneer board device + tree + +Milk-V Pioneer [1] is a developer motherboard based on SOPHON +SG2042 in a standard mATX form factor. It is a good +choice for RISC-V developers and hardware pioneers to +experience the cutting edge technology of RISC-V. + +Currently only support booting into console with only uart +enabled, other features will be added soon later. + +[1]: https://milkv.io/pioneer + +Acked-by: Xiaoguang Xing +Signed-off-by: Chen Wang +Reviewed-by: Guo Ren +--- + arch/riscv/boot/dts/Makefile | 1 + + arch/riscv/boot/dts/sophgo/Makefile | 3 +++ + .../boot/dts/sophgo/sg2042-milkv-pioneer.dts | 19 +++++++++++++++++++ + 3 files changed, 23 insertions(+) + create mode 100644 arch/riscv/boot/dts/sophgo/Makefile + create mode 100644 arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts + +diff --git a/arch/riscv/boot/dts/Makefile b/arch/riscv/boot/dts/Makefile +index f60a280abb15..5da6736661da 100644 +--- a/arch/riscv/boot/dts/Makefile ++++ b/arch/riscv/boot/dts/Makefile +@@ -3,6 +3,7 @@ subdir-y += allwinner + subdir-y += canaan + subdir-y += microchip + subdir-y += renesas ++subdir-y += sophgo + subdir-y += sifive + subdir-y += starfive + subdir-y += thead +diff --git a/arch/riscv/boot/dts/sophgo/Makefile b/arch/riscv/boot/dts/sophgo/Makefile +new file mode 100644 +index 000000000000..5a471b19df22 +--- /dev/null ++++ b/arch/riscv/boot/dts/sophgo/Makefile +@@ -0,0 +1,3 @@ ++# SPDX-License-Identifier: GPL-2.0 ++dtb-$(CONFIG_ARCH_SOPHGO) += sg2042-milkv-pioneer.dtb ++ +diff --git a/arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts b/arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts +new file mode 100644 +index 000000000000..d6e8c0285d1e +--- /dev/null ++++ b/arch/riscv/boot/dts/sophgo/sg2042-milkv-pioneer.dts +@@ -0,0 +1,19 @@ ++// SPDX-License-Identifier: GPL-2.0 OR MIT ++/* ++ * Copyright (C) 2022 Sophgo Technology Inc. All rights reserved. ++ */ ++ ++#include "sg2042.dtsi" ++ ++/ { ++ model = "Milk-V Pioneer"; ++ compatible = "milkv,pioneer", "sophgo,sg2042"; ++ ++ chosen: chosen { ++ stdout-path = "serial0"; ++ }; ++}; ++ ++&uart0 { ++ status = "okay"; ++}; +-- +2.20.1 + diff --git a/target/linux/cv18x0/patches-6.6/0005-riscv-dts-sophgo-add-Milk-V-Duo-board-device-tree.patch b/target/linux/cv18x0/patches-6.6/0005-riscv-dts-sophgo-add-Milk-V-Duo-board-device-tree.patch new file mode 100644 index 0000000000..b015aee4da --- /dev/null +++ b/target/linux/cv18x0/patches-6.6/0005-riscv-dts-sophgo-add-Milk-V-Duo-board-device-tree.patch @@ -0,0 +1,74 @@ +From c3be09615d98340463c8aade13064459b9267bc9 Mon Sep 17 00:00:00 2001 +From: Jisheng Zhang +Date: Sat, 30 Sep 2023 20:39:37 +0800 +Subject: [PATCH 05/18] riscv: dts: sophgo: add Milk-V Duo board device tree + +Milk-V Duo[1] board is an embedded development platform based on the +CV1800B chip. Add minimal device tree files for the development board. + +Support basic uart drivers, so supports booting to a basic shell. + +Link: https://milkv.io/duo [1] +Signed-off-by: Jisheng Zhang +--- + arch/riscv/boot/dts/sophgo/Makefile | 2 +- + .../boot/dts/sophgo/cv1800b-milkv-duo.dts | 38 +++++++++++++++++++ + 2 files changed, 39 insertions(+), 1 deletion(-) + create mode 100644 arch/riscv/boot/dts/sophgo/cv1800b-milkv-duo.dts + +diff --git a/arch/riscv/boot/dts/sophgo/Makefile b/arch/riscv/boot/dts/sophgo/Makefile +index 5a471b19df22..5ea9ce398ff6 100644 +--- a/arch/riscv/boot/dts/sophgo/Makefile ++++ b/arch/riscv/boot/dts/sophgo/Makefile +@@ -1,3 +1,3 @@ + # SPDX-License-Identifier: GPL-2.0 + dtb-$(CONFIG_ARCH_SOPHGO) += sg2042-milkv-pioneer.dtb +- ++dtb-$(CONFIG_ARCH_SOPHGO) += cv1800b-milkv-duo.dtb +diff --git a/arch/riscv/boot/dts/sophgo/cv1800b-milkv-duo.dts b/arch/riscv/boot/dts/sophgo/cv1800b-milkv-duo.dts +new file mode 100644 +index 000000000000..3af9e34b3bc7 +--- /dev/null ++++ b/arch/riscv/boot/dts/sophgo/cv1800b-milkv-duo.dts +@@ -0,0 +1,38 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright (C) 2023 Jisheng Zhang ++ */ ++ ++/dts-v1/; ++ ++#include "cv1800b.dtsi" ++ ++/ { ++ model = "Milk-V Duo"; ++ compatible = "milkv,duo", "sophgo,cv1800b"; ++ ++ aliases { ++ serial0 = &uart0; ++ serial1 = &uart1; ++ serial2 = &uart2; ++ serial3 = &uart3; ++ serial4 = &uart4; ++ }; ++ ++ chosen { ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ memory@80000000 { ++ device_type = "memory"; ++ reg = <0x80000000 0x3f40000>; ++ }; ++}; ++ ++&osc { ++ clock-frequency = <25000000>; ++}; ++ ++&uart0 { ++ status = "okay"; ++}; +-- +2.20.1 + diff --git a/target/linux/cv18x0/patches-6.6/0006-riscv-dts-sophgo-add-initial-CV1812H-SoC-device-tree.patch b/target/linux/cv18x0/patches-6.6/0006-riscv-dts-sophgo-add-initial-CV1812H-SoC-device-tree.patch new file mode 100644 index 0000000000..cdb08e8c2b --- /dev/null +++ b/target/linux/cv18x0/patches-6.6/0006-riscv-dts-sophgo-add-initial-CV1812H-SoC-device-tree.patch @@ -0,0 +1,48 @@ +From 4f879141f6c39cada3681d5c86e335405f60f7d4 Mon Sep 17 00:00:00 2001 +From: Inochi Amaoto +Date: Thu, 19 Oct 2023 07:18:53 +0800 +Subject: [PATCH 06/18] riscv: dts: sophgo: add initial CV1812H SoC device tree + +Add initial device tree for the CV1812H RISC-V SoC by SOPHGO. + +Signed-off-by: Inochi Amaoto +Acked-by: Chen Wang +Signed-off-by: Conor Dooley +--- + arch/riscv/boot/dts/sophgo/cv1812h.dtsi | 24 ++++++++++++++++++++++++ + 1 file changed, 24 insertions(+) + create mode 100644 arch/riscv/boot/dts/sophgo/cv1812h.dtsi + +diff --git a/arch/riscv/boot/dts/sophgo/cv1812h.dtsi b/arch/riscv/boot/dts/sophgo/cv1812h.dtsi +new file mode 100644 +index 000000000000..3e7a942f5c1a +--- /dev/null ++++ b/arch/riscv/boot/dts/sophgo/cv1812h.dtsi +@@ -0,0 +1,24 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright (C) 2023 Inochi Amaoto ++ */ ++ ++#include ++#include "cv18xx.dtsi" ++ ++/ { ++ compatible = "sophgo,cv1812h"; ++ ++ memory@80000000 { ++ device_type = "memory"; ++ reg = <0x80000000 0x10000000>; ++ }; ++}; ++ ++&plic { ++ compatible = "sophgo,cv1812h-plic", "thead,c900-plic"; ++}; ++ ++&clint { ++ compatible = "sophgo,cv1812h-clint", "thead,c900-clint"; ++}; +-- +2.20.1 + diff --git a/target/linux/cv18x0/patches-6.6/0007-riscv-dts-sophgo-Separate-compatible-specific-for-CV.patch b/target/linux/cv18x0/patches-6.6/0007-riscv-dts-sophgo-Separate-compatible-specific-for-CV.patch new file mode 100644 index 0000000000..540261e7e3 --- /dev/null +++ b/target/linux/cv18x0/patches-6.6/0007-riscv-dts-sophgo-Separate-compatible-specific-for-CV.patch @@ -0,0 +1,282 @@ +From 9acf530cd767b5f980647717776d2c4c260cf3b6 Mon Sep 17 00:00:00 2001 +From: Inochi Amaoto +Date: Thu, 19 Oct 2023 07:18:51 +0800 +Subject: [PATCH 07/18] riscv: dts: sophgo: Separate compatible specific for + CV1800B soc + +As CV180x and CV181x have the identical layouts, it is OK to use the +cv1800b basic device tree for the whole series. +For CV1800B soc specific compatible, just move them out of the common +file. + +Signed-off-by: Inochi Amaoto +Acked-by: Chen Wang +Signed-off-by: Conor Dooley +--- + arch/riscv/boot/dts/sophgo/cv1800b.dtsi | 119 ++--------------------- + arch/riscv/boot/dts/sophgo/cv18xx.dtsi | 120 ++++++++++++++++++++++++ + 2 files changed, 127 insertions(+), 112 deletions(-) + create mode 100644 arch/riscv/boot/dts/sophgo/cv18xx.dtsi + +diff --git a/arch/riscv/boot/dts/sophgo/cv1800b.dtsi b/arch/riscv/boot/dts/sophgo/cv1800b.dtsi +index df40e87ee063..165e9e320a8c 100644 +--- a/arch/riscv/boot/dts/sophgo/cv1800b.dtsi ++++ b/arch/riscv/boot/dts/sophgo/cv1800b.dtsi +@@ -3,121 +3,16 @@ + * Copyright (C) 2023 Jisheng Zhang + */ + +-#include ++#include "cv18xx.dtsi" + + / { + compatible = "sophgo,cv1800b"; +- #address-cells = <1>; +- #size-cells = <1>; +- +- cpus: cpus { +- #address-cells = <1>; +- #size-cells = <0>; +- timebase-frequency = <25000000>; +- +- cpu0: cpu@0 { +- compatible = "thead,c906", "riscv"; +- device_type = "cpu"; +- reg = <0>; +- d-cache-block-size = <64>; +- d-cache-sets = <512>; +- d-cache-size = <65536>; +- i-cache-block-size = <64>; +- i-cache-sets = <128>; +- i-cache-size = <32768>; +- mmu-type = "riscv,sv39"; +- riscv,isa = "rv64imafdc"; +- riscv,isa-base = "rv64i"; +- riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicntr", "zicsr", +- "zifencei", "zihpm"; +- +- cpu0_intc: interrupt-controller { +- compatible = "riscv,cpu-intc"; +- interrupt-controller; +- #address-cells = <0>; +- #interrupt-cells = <1>; +- }; +- }; +- }; +- +- osc: oscillator { +- compatible = "fixed-clock"; +- clock-output-names = "osc_25m"; +- #clock-cells = <0>; +- }; +- +- soc { +- compatible = "simple-bus"; +- interrupt-parent = <&plic>; +- #address-cells = <1>; +- #size-cells = <1>; +- dma-noncoherent; +- ranges; +- +- uart0: serial@4140000 { +- compatible = "snps,dw-apb-uart"; +- reg = <0x04140000 0x100>; +- interrupts = <44 IRQ_TYPE_LEVEL_HIGH>; +- clocks = <&osc>; +- reg-shift = <2>; +- reg-io-width = <4>; +- status = "disabled"; +- }; +- +- uart1: serial@4150000 { +- compatible = "snps,dw-apb-uart"; +- reg = <0x04150000 0x100>; +- interrupts = <45 IRQ_TYPE_LEVEL_HIGH>; +- clocks = <&osc>; +- reg-shift = <2>; +- reg-io-width = <4>; +- status = "disabled"; +- }; +- +- uart2: serial@4160000 { +- compatible = "snps,dw-apb-uart"; +- reg = <0x04160000 0x100>; +- interrupts = <46 IRQ_TYPE_LEVEL_HIGH>; +- clocks = <&osc>; +- reg-shift = <2>; +- reg-io-width = <4>; +- status = "disabled"; +- }; +- +- uart3: serial@4170000 { +- compatible = "snps,dw-apb-uart"; +- reg = <0x04170000 0x100>; +- interrupts = <47 IRQ_TYPE_LEVEL_HIGH>; +- clocks = <&osc>; +- reg-shift = <2>; +- reg-io-width = <4>; +- status = "disabled"; +- }; +- +- uart4: serial@41c0000 { +- compatible = "snps,dw-apb-uart"; +- reg = <0x041c0000 0x100>; +- interrupts = <48 IRQ_TYPE_LEVEL_HIGH>; +- clocks = <&osc>; +- reg-shift = <2>; +- reg-io-width = <4>; +- status = "disabled"; +- }; ++}; + +- plic: interrupt-controller@70000000 { +- compatible = "sophgo,cv1800b-plic", "thead,c900-plic"; +- reg = <0x70000000 0x4000000>; +- interrupts-extended = <&cpu0_intc 11>, <&cpu0_intc 9>; +- interrupt-controller; +- #address-cells = <0>; +- #interrupt-cells = <2>; +- riscv,ndev = <101>; +- }; ++&plic { ++ compatible = "sophgo,cv1800b-plic", "thead,c900-plic"; ++}; + +- clint: timer@74000000 { +- compatible = "sophgo,cv1800b-clint", "thead,c900-clint"; +- reg = <0x74000000 0x10000>; +- interrupts-extended = <&cpu0_intc 3>, <&cpu0_intc 7>; +- }; +- }; ++&clint { ++ compatible = "sophgo,cv1800b-clint", "thead,c900-clint"; + }; +diff --git a/arch/riscv/boot/dts/sophgo/cv18xx.dtsi b/arch/riscv/boot/dts/sophgo/cv18xx.dtsi +new file mode 100644 +index 000000000000..55d4bc84faa0 +--- /dev/null ++++ b/arch/riscv/boot/dts/sophgo/cv18xx.dtsi +@@ -0,0 +1,120 @@ ++// SPDX-License-Identifier: (GPL-2.0 OR MIT) ++/* ++ * Copyright (C) 2023 Jisheng Zhang ++ */ ++ ++#include ++ ++/ { ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ++ cpus: cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ timebase-frequency = <25000000>; ++ ++ cpu0: cpu@0 { ++ compatible = "thead,c906", "riscv"; ++ device_type = "cpu"; ++ reg = <0>; ++ d-cache-block-size = <64>; ++ d-cache-sets = <512>; ++ d-cache-size = <65536>; ++ i-cache-block-size = <64>; ++ i-cache-sets = <128>; ++ i-cache-size = <32768>; ++ mmu-type = "riscv,sv39"; ++ riscv,isa = "rv64imafdc"; ++ riscv,isa-base = "rv64i"; ++ riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "zicntr", "zicsr", ++ "zifencei", "zihpm"; ++ ++ cpu0_intc: interrupt-controller { ++ compatible = "riscv,cpu-intc"; ++ interrupt-controller; ++ #address-cells = <0>; ++ #interrupt-cells = <1>; ++ }; ++ }; ++ }; ++ ++ osc: oscillator { ++ compatible = "fixed-clock"; ++ clock-output-names = "osc_25m"; ++ #clock-cells = <0>; ++ }; ++ ++ soc { ++ compatible = "simple-bus"; ++ interrupt-parent = <&plic>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ dma-noncoherent; ++ ranges; ++ ++ uart0: serial@4140000 { ++ compatible = "snps,dw-apb-uart"; ++ reg = <0x04140000 0x100>; ++ interrupts = <44 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&osc>; ++ reg-shift = <2>; ++ reg-io-width = <4>; ++ status = "disabled"; ++ }; ++ ++ uart1: serial@4150000 { ++ compatible = "snps,dw-apb-uart"; ++ reg = <0x04150000 0x100>; ++ interrupts = <45 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&osc>; ++ reg-shift = <2>; ++ reg-io-width = <4>; ++ status = "disabled"; ++ }; ++ ++ uart2: serial@4160000 { ++ compatible = "snps,dw-apb-uart"; ++ reg = <0x04160000 0x100>; ++ interrupts = <46 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&osc>; ++ reg-shift = <2>; ++ reg-io-width = <4>; ++ status = "disabled"; ++ }; ++ ++ uart3: serial@4170000 { ++ compatible = "snps,dw-apb-uart"; ++ reg = <0x04170000 0x100>; ++ interrupts = <47 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&osc>; ++ reg-shift = <2>; ++ reg-io-width = <4>; ++ status = "disabled"; ++ }; ++ ++ uart4: serial@41c0000 { ++ compatible = "snps,dw-apb-uart"; ++ reg = <0x041c0000 0x100>; ++ interrupts = <48 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&osc>; ++ reg-shift = <2>; ++ reg-io-width = <4>; ++ status = "disabled"; ++ }; ++ ++ plic: interrupt-controller@70000000 { ++ reg = <0x70000000 0x4000000>; ++ interrupts-extended = <&cpu0_intc 11>, <&cpu0_intc 9>; ++ interrupt-controller; ++ #address-cells = <0>; ++ #interrupt-cells = <2>; ++ riscv,ndev = <101>; ++ }; ++ ++ clint: timer@74000000 { ++ reg = <0x74000000 0x10000>; ++ interrupts-extended = <&cpu0_intc 3>, <&cpu0_intc 7>; ++ }; ++ }; ++}; +-- +2.20.1 + diff --git a/target/linux/cv18x0/patches-6.6/0008-riscv-dts-sophgo-cv18xx-Add-gpio-devices.patch b/target/linux/cv18x0/patches-6.6/0008-riscv-dts-sophgo-cv18xx-Add-gpio-devices.patch new file mode 100644 index 0000000000..bf243553b4 --- /dev/null +++ b/target/linux/cv18x0/patches-6.6/0008-riscv-dts-sophgo-cv18xx-Add-gpio-devices.patch @@ -0,0 +1,109 @@ +From 53ebe26713247df9cec482075cbc27795d386d79 Mon Sep 17 00:00:00 2001 +From: Zoltan HERPAI +Date: Fri, 28 Jun 2024 15:10:43 +0000 +Subject: [PATCH 08/18] riscv: dts: sophgo: cv18xx: Add gpio devices + +Add common GPIO devices for the CV180x and CV181x soc. + +Signed-off-by: Inochi Amaoto +Reviewed-by: Jisheng Zhang +Acked-by: Chen Wang +Signed-off-by: Conor Dooley +--- + arch/riscv/boot/dts/sophgo/cv18xx.dtsi | 73 ++++++++++++++++++++++++++ + 1 file changed, 73 insertions(+) + +diff --git a/arch/riscv/boot/dts/sophgo/cv18xx.dtsi b/arch/riscv/boot/dts/sophgo/cv18xx.dtsi +index 55d4bc84faa0..d415cc758def 100644 +--- a/arch/riscv/boot/dts/sophgo/cv18xx.dtsi ++++ b/arch/riscv/boot/dts/sophgo/cv18xx.dtsi +@@ -1,6 +1,7 @@ + // SPDX-License-Identifier: (GPL-2.0 OR MIT) + /* + * Copyright (C) 2023 Jisheng Zhang ++ * Copyright (C) 2023 Inochi Amaoto + */ + + #include +@@ -53,6 +54,78 @@ + dma-noncoherent; + ranges; + ++ gpio0: gpio@3020000 { ++ compatible = "snps,dw-apb-gpio"; ++ reg = <0x3020000 0x1000>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ porta: gpio-controller@0 { ++ compatible = "snps,dw-apb-gpio-port"; ++ gpio-controller; ++ #gpio-cells = <2>; ++ ngpios = <32>; ++ reg = <0>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ interrupts = <60 IRQ_TYPE_LEVEL_HIGH>; ++ }; ++ }; ++ ++ gpio1: gpio@3021000 { ++ compatible = "snps,dw-apb-gpio"; ++ reg = <0x3021000 0x1000>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ portb: gpio-controller@0 { ++ compatible = "snps,dw-apb-gpio-port"; ++ gpio-controller; ++ #gpio-cells = <2>; ++ ngpios = <32>; ++ reg = <0>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ interrupts = <61 IRQ_TYPE_LEVEL_HIGH>; ++ }; ++ }; ++ ++ gpio2: gpio@3022000 { ++ compatible = "snps,dw-apb-gpio"; ++ reg = <0x3022000 0x1000>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ portc: gpio-controller@0 { ++ compatible = "snps,dw-apb-gpio-port"; ++ gpio-controller; ++ #gpio-cells = <2>; ++ ngpios = <32>; ++ reg = <0>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ interrupts = <62 IRQ_TYPE_LEVEL_HIGH>; ++ }; ++ }; ++ ++ gpio3: gpio@3023000 { ++ compatible = "snps,dw-apb-gpio"; ++ reg = <0x3023000 0x1000>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ portd: gpio-controller@0 { ++ compatible = "snps,dw-apb-gpio-port"; ++ gpio-controller; ++ #gpio-cells = <2>; ++ ngpios = <32>; ++ reg = <0>; ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ interrupts = <63 IRQ_TYPE_LEVEL_HIGH>; ++ }; ++ }; ++ + uart0: serial@4140000 { + compatible = "snps,dw-apb-uart"; + reg = <0x04140000 0x100>; +-- +2.20.1 + diff --git a/target/linux/cv18x0/patches-6.6/0009-drivers-mmc-sdhci-of-dwcmshc-include-bitfield.h-for-.patch b/target/linux/cv18x0/patches-6.6/0009-drivers-mmc-sdhci-of-dwcmshc-include-bitfield.h-for-.patch new file mode 100644 index 0000000000..56619b941d --- /dev/null +++ b/target/linux/cv18x0/patches-6.6/0009-drivers-mmc-sdhci-of-dwcmshc-include-bitfield.h-for-.patch @@ -0,0 +1,26 @@ +From 1fc5411e948548ed58a082530f25a24edf1b7672 Mon Sep 17 00:00:00 2001 +From: Zoltan HERPAI +Date: Fri, 28 Jun 2024 15:11:04 +0000 +Subject: [PATCH 09/18] drivers: mmc: sdhci-of-dwcmshc: include bitfield.h for + FIELD_PREP + +Signed-off-by: Zoltan HERPAI +--- + drivers/mmc/host/sdhci-of-dwcmshc.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c +index a0524127ca07..2d19b1403879 100644 +--- a/drivers/mmc/host/sdhci-of-dwcmshc.c ++++ b/drivers/mmc/host/sdhci-of-dwcmshc.c +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + + #include "sdhci-pltfm.h" + +-- +2.20.1 + diff --git a/target/linux/cv18x0/patches-6.6/0010-mmc-sdhci-of-dwcmshc-Add-support-for-Sophgo-CV1800B-.patch b/target/linux/cv18x0/patches-6.6/0010-mmc-sdhci-of-dwcmshc-Add-support-for-Sophgo-CV1800B-.patch new file mode 100644 index 0000000000..b4d425fe8b --- /dev/null +++ b/target/linux/cv18x0/patches-6.6/0010-mmc-sdhci-of-dwcmshc-Add-support-for-Sophgo-CV1800B-.patch @@ -0,0 +1,122 @@ +From 9abc21706dbb37af1da7d4c95c21c131bbc2d512 Mon Sep 17 00:00:00 2001 +From: Jisheng Zhang +Date: Sat, 17 Feb 2024 22:42:02 +0800 +Subject: [PATCH 10/18] mmc: sdhci-of-dwcmshc: Add support for Sophgo CV1800B + and SG2002 + +Add support for the mmc controller in the Sophgo CV1800B and SG2002 +with corresponding new compatible strings. Implement custom sdhci_ops. + +Signed-off-by: Jisheng Zhang +--- + drivers/mmc/host/sdhci-of-dwcmshc.c | 66 +++++++++++++++++++++++++++++ + 1 file changed, 66 insertions(+) + +diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c +index 2d19b1403879..e473af22e585 100644 +--- a/drivers/mmc/host/sdhci-of-dwcmshc.c ++++ b/drivers/mmc/host/sdhci-of-dwcmshc.c +@@ -37,6 +37,20 @@ + #define DWCMSHC_ENHANCED_STROBE BIT(8) + #define DWCMSHC_EMMC_ATCTRL 0x40 + ++/* Sophgo CV18XX specific Registers */ ++#define CV18XX_SDHCI_MSHC_CTRL 0x00 ++#define CV18XX_EMMC_FUNC_EN BIT(0) ++#define CV18XX_LATANCY_1T BIT(1) ++#define CV18XX_SDHCI_PHY_TX_RX_DLY 0x40 ++#define CV18XX_PHY_TX_DLY_MSK GENMASK(6, 0) ++#define CV18XX_PHY_TX_SRC_MSK GENMASK(9, 8) ++#define CV18XX_PHY_TX_SRC_INVERT_CLK_TX 0x1 ++#define CV18XX_PHY_RX_DLY_MSK GENMASK(22, 16) ++#define CV18XX_PHY_RX_SRC_MSK GENMASK(25, 24) ++#define CV18XX_PHY_RX_SRC_INVERT_RX_CLK 0x1 ++#define CV18XX_SDHCI_PHY_CONFIG 0x4c ++#define CV18XX_PHY_TX_BPS BIT(0) ++ + /* Rockchip specific Registers */ + #define DWCMSHC_EMMC_DLL_CTRL 0x800 + #define DWCMSHC_EMMC_DLL_RXCLK 0x804 +@@ -339,6 +353,35 @@ static void rk35xx_sdhci_reset(struct sdhci_host *host, u8 mask) + sdhci_reset(host, mask); + } + ++static void cv18xx_sdhci_reset(struct sdhci_host *host, u8 mask) ++{ ++ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); ++ struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); ++ u32 val, emmc_caps = MMC_CAP2_NO_SD | MMC_CAP2_NO_SDIO; ++ ++ sdhci_reset(host, mask); ++ ++ if ((host->mmc->caps2 & emmc_caps) == emmc_caps) { ++ val = sdhci_readl(host, priv->vendor_specific_area1 + CV18XX_SDHCI_MSHC_CTRL); ++ val |= CV18XX_EMMC_FUNC_EN; ++ sdhci_writel(host, val, priv->vendor_specific_area1 + CV18XX_SDHCI_MSHC_CTRL); ++ } ++ ++ val = sdhci_readl(host, priv->vendor_specific_area1 + CV18XX_SDHCI_MSHC_CTRL); ++ val |= CV18XX_LATANCY_1T; ++ sdhci_writel(host, val, priv->vendor_specific_area1 + CV18XX_SDHCI_MSHC_CTRL); ++ ++ val = sdhci_readl(host, priv->vendor_specific_area1 + CV18XX_SDHCI_PHY_CONFIG); ++ val |= CV18XX_PHY_TX_BPS; ++ sdhci_writel(host, val, priv->vendor_specific_area1 + CV18XX_SDHCI_PHY_CONFIG); ++ ++ val = (FIELD_PREP(CV18XX_PHY_TX_DLY_MSK, 0) | ++ FIELD_PREP(CV18XX_PHY_TX_SRC_MSK, CV18XX_PHY_TX_SRC_INVERT_CLK_TX) | ++ FIELD_PREP(CV18XX_PHY_RX_DLY_MSK, 0) | ++ FIELD_PREP(CV18XX_PHY_RX_SRC_MSK, CV18XX_PHY_RX_SRC_INVERT_RX_CLK)); ++ sdhci_writel(host, val, priv->vendor_specific_area1 + CV18XX_SDHCI_PHY_TX_RX_DLY); ++} ++ + static const struct sdhci_ops sdhci_dwcmshc_ops = { + .set_clock = sdhci_set_clock, + .set_bus_width = sdhci_set_bus_width, +@@ -357,6 +400,15 @@ static const struct sdhci_ops sdhci_dwcmshc_rk35xx_ops = { + .adma_write_desc = dwcmshc_adma_write_desc, + }; + ++static const struct sdhci_ops sdhci_dwcmshc_cv18xx_ops = { ++ .set_clock = sdhci_set_clock, ++ .set_bus_width = sdhci_set_bus_width, ++ .set_uhs_signaling = dwcmshc_set_uhs_signaling, ++ .get_max_clock = dwcmshc_get_max_clock, ++ .reset = cv18xx_sdhci_reset, ++ .adma_write_desc = dwcmshc_adma_write_desc, ++}; ++ + static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = { + .ops = &sdhci_dwcmshc_ops, + .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, +@@ -380,6 +432,12 @@ static const struct sdhci_pltfm_data sdhci_dwcmshc_rk35xx_pdata = { + SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN, + }; + ++static const struct sdhci_pltfm_data sdhci_dwcmshc_cv18xx_pdata = { ++ .ops = &sdhci_dwcmshc_cv18xx_ops, ++ .quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, ++ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, ++}; ++ + static int dwcmshc_rk35xx_init(struct sdhci_host *host, struct dwcmshc_priv *dwc_priv) + { + int err; +@@ -444,6 +502,14 @@ static const struct of_device_id sdhci_dwcmshc_dt_ids[] = { + .compatible = "rockchip,rk3568-dwcmshc", + .data = &sdhci_dwcmshc_rk35xx_pdata, + }, ++ { ++ .compatible = "sophgo,cv1800b-dwcmshc", ++ .data = &sdhci_dwcmshc_cv18xx_pdata, ++ }, ++ { ++ .compatible = "sophgo,sg2002-dwcmshc", ++ .data = &sdhci_dwcmshc_cv18xx_pdata, ++ }, + { + .compatible = "snps,dwcmshc-sdhci", + .data = &sdhci_dwcmshc_pdata, +-- +2.20.1 + diff --git a/target/linux/cv18x0/patches-6.6/0011-dt-bindings-clock-sophgo-Add-clock-controller-of-CV1.patch b/target/linux/cv18x0/patches-6.6/0011-dt-bindings-clock-sophgo-Add-clock-controller-of-CV1.patch new file mode 100644 index 0000000000..74d1a6acfc --- /dev/null +++ b/target/linux/cv18x0/patches-6.6/0011-dt-bindings-clock-sophgo-Add-clock-controller-of-CV1.patch @@ -0,0 +1,206 @@ +From 7304fd40e7822e1d51229c532ad9271577b212f0 Mon Sep 17 00:00:00 2001 +From: Inochi Amaoto +Date: Mon, 18 Dec 2023 12:04:03 +0800 +Subject: [PATCH 11/18] dt-bindings: clock: sophgo: Add clock controller of + CV1800 series SoC + +Add definition for the clock controller of the CV1800 series SoC. + +For CV181X, it has a clock that CV180X does not have. To avoid misuse, +also add a compatible string to identify CV181X series SoC. + +Signed-off-by: Inochi Amaoto +Link: https://github.com/milkv-duo/duo-files/blob/main/hardware/CV1800B/CV1800B-CV1801B-Preliminary-Datasheet-full-en.pdf +Reviewed-by: Krzysztof Kozlowski +Link: https://lore.kernel.org/r/IA1PR20MB49535E448097F6FFC1218C39BB90A@IA1PR20MB4953.namprd20.prod.outlook.com +Signed-off-by: Stephen Boyd +--- + include/dt-bindings/clock/sophgo,cv1800.h | 176 ++++++++++++++++++++++ + 1 file changed, 176 insertions(+) + create mode 100644 include/dt-bindings/clock/sophgo,cv1800.h + +diff --git a/include/dt-bindings/clock/sophgo,cv1800.h b/include/dt-bindings/clock/sophgo,cv1800.h +new file mode 100644 +index 000000000000..cfbeca25a650 +--- /dev/null ++++ b/include/dt-bindings/clock/sophgo,cv1800.h +@@ -0,0 +1,176 @@ ++/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */ ++/* ++ * Copyright (C) 2023 Sophgo Ltd. ++ */ ++ ++#ifndef __DT_BINDINGS_SOPHGO_CV1800_CLK_H__ ++#define __DT_BINDINGS_SOPHGO_CV1800_CLK_H__ ++ ++#define CLK_MPLL 0 ++#define CLK_TPLL 1 ++#define CLK_FPLL 2 ++#define CLK_MIPIMPLL 3 ++#define CLK_A0PLL 4 ++#define CLK_DISPPLL 5 ++#define CLK_CAM0PLL 6 ++#define CLK_CAM1PLL 7 ++ ++#define CLK_MIPIMPLL_D3 8 ++#define CLK_CAM0PLL_D2 9 ++#define CLK_CAM0PLL_D3 10 ++ ++#define CLK_TPU 11 ++#define CLK_TPU_FAB 12 ++#define CLK_AHB_ROM 13 ++#define CLK_DDR_AXI_REG 14 ++#define CLK_RTC_25M 15 ++#define CLK_SRC_RTC_SYS_0 16 ++#define CLK_TEMPSEN 17 ++#define CLK_SARADC 18 ++#define CLK_EFUSE 19 ++#define CLK_APB_EFUSE 20 ++#define CLK_DEBUG 21 ++#define CLK_AP_DEBUG 22 ++#define CLK_XTAL_MISC 23 ++#define CLK_AXI4_EMMC 24 ++#define CLK_EMMC 25 ++#define CLK_EMMC_100K 26 ++#define CLK_AXI4_SD0 27 ++#define CLK_SD0 28 ++#define CLK_SD0_100K 29 ++#define CLK_AXI4_SD1 30 ++#define CLK_SD1 31 ++#define CLK_SD1_100K 32 ++#define CLK_SPI_NAND 33 ++#define CLK_ETH0_500M 34 ++#define CLK_AXI4_ETH0 35 ++#define CLK_ETH1_500M 36 ++#define CLK_AXI4_ETH1 37 ++#define CLK_APB_GPIO 38 ++#define CLK_APB_GPIO_INTR 39 ++#define CLK_GPIO_DB 40 ++#define CLK_AHB_SF 41 ++#define CLK_AHB_SF1 42 ++#define CLK_A24M 43 ++#define CLK_AUDSRC 44 ++#define CLK_APB_AUDSRC 45 ++#define CLK_SDMA_AXI 46 ++#define CLK_SDMA_AUD0 47 ++#define CLK_SDMA_AUD1 48 ++#define CLK_SDMA_AUD2 49 ++#define CLK_SDMA_AUD3 50 ++#define CLK_I2C 51 ++#define CLK_APB_I2C 52 ++#define CLK_APB_I2C0 53 ++#define CLK_APB_I2C1 54 ++#define CLK_APB_I2C2 55 ++#define CLK_APB_I2C3 56 ++#define CLK_APB_I2C4 57 ++#define CLK_APB_WDT 58 ++#define CLK_PWM_SRC 59 ++#define CLK_PWM 60 ++#define CLK_SPI 61 ++#define CLK_APB_SPI0 62 ++#define CLK_APB_SPI1 63 ++#define CLK_APB_SPI2 64 ++#define CLK_APB_SPI3 65 ++#define CLK_1M 66 ++#define CLK_CAM0_200 67 ++#define CLK_PM 68 ++#define CLK_TIMER0 69 ++#define CLK_TIMER1 70 ++#define CLK_TIMER2 71 ++#define CLK_TIMER3 72 ++#define CLK_TIMER4 73 ++#define CLK_TIMER5 74 ++#define CLK_TIMER6 75 ++#define CLK_TIMER7 76 ++#define CLK_UART0 77 ++#define CLK_APB_UART0 78 ++#define CLK_UART1 79 ++#define CLK_APB_UART1 80 ++#define CLK_UART2 81 ++#define CLK_APB_UART2 82 ++#define CLK_UART3 83 ++#define CLK_APB_UART3 84 ++#define CLK_UART4 85 ++#define CLK_APB_UART4 86 ++#define CLK_APB_I2S0 87 ++#define CLK_APB_I2S1 88 ++#define CLK_APB_I2S2 89 ++#define CLK_APB_I2S3 90 ++#define CLK_AXI4_USB 91 ++#define CLK_APB_USB 92 ++#define CLK_USB_125M 93 ++#define CLK_USB_33K 94 ++#define CLK_USB_12M 95 ++#define CLK_AXI4 96 ++#define CLK_AXI6 97 ++#define CLK_DSI_ESC 98 ++#define CLK_AXI_VIP 99 ++#define CLK_SRC_VIP_SYS_0 100 ++#define CLK_SRC_VIP_SYS_1 101 ++#define CLK_SRC_VIP_SYS_2 102 ++#define CLK_SRC_VIP_SYS_3 103 ++#define CLK_SRC_VIP_SYS_4 104 ++#define CLK_CSI_BE_VIP 105 ++#define CLK_CSI_MAC0_VIP 106 ++#define CLK_CSI_MAC1_VIP 107 ++#define CLK_CSI_MAC2_VIP 108 ++#define CLK_CSI0_RX_VIP 109 ++#define CLK_CSI1_RX_VIP 110 ++#define CLK_ISP_TOP_VIP 111 ++#define CLK_IMG_D_VIP 112 ++#define CLK_IMG_V_VIP 113 ++#define CLK_SC_TOP_VIP 114 ++#define CLK_SC_D_VIP 115 ++#define CLK_SC_V1_VIP 116 ++#define CLK_SC_V2_VIP 117 ++#define CLK_SC_V3_VIP 118 ++#define CLK_DWA_VIP 119 ++#define CLK_BT_VIP 120 ++#define CLK_DISP_VIP 121 ++#define CLK_DSI_MAC_VIP 122 ++#define CLK_LVDS0_VIP 123 ++#define CLK_LVDS1_VIP 124 ++#define CLK_PAD_VI_VIP 125 ++#define CLK_PAD_VI1_VIP 126 ++#define CLK_PAD_VI2_VIP 127 ++#define CLK_CFG_REG_VIP 128 ++#define CLK_VIP_IP0 129 ++#define CLK_VIP_IP1 130 ++#define CLK_VIP_IP2 131 ++#define CLK_VIP_IP3 132 ++#define CLK_IVE_VIP 133 ++#define CLK_RAW_VIP 134 ++#define CLK_OSDC_VIP 135 ++#define CLK_CAM0_VIP 136 ++#define CLK_AXI_VIDEO_CODEC 137 ++#define CLK_VC_SRC0 138 ++#define CLK_VC_SRC1 139 ++#define CLK_VC_SRC2 140 ++#define CLK_H264C 141 ++#define CLK_APB_H264C 142 ++#define CLK_H265C 143 ++#define CLK_APB_H265C 144 ++#define CLK_JPEG 145 ++#define CLK_APB_JPEG 146 ++#define CLK_CAM0 147 ++#define CLK_CAM1 148 ++#define CLK_WGN 149 ++#define CLK_WGN0 150 ++#define CLK_WGN1 151 ++#define CLK_WGN2 152 ++#define CLK_KEYSCAN 153 ++#define CLK_CFG_REG_VC 154 ++#define CLK_C906_0 155 ++#define CLK_C906_1 156 ++#define CLK_A53 157 ++#define CLK_CPU_AXI0 158 ++#define CLK_CPU_GIC 159 ++#define CLK_XTAL_AP 160 ++ ++// Only for CV181x ++#define CLK_DISP_SRC_VIP 161 ++ ++#endif /* __DT_BINDINGS_SOPHGO_CV1800_CLK_H__ */ +-- +2.20.1 + diff --git a/target/linux/cv18x0/patches-6.6/0012-clk-sophgo-Add-CV1800-SG2000-series-clock-controller.patch b/target/linux/cv18x0/patches-6.6/0012-clk-sophgo-Add-CV1800-SG2000-series-clock-controller.patch new file mode 100644 index 0000000000..dafe8b6a81 --- /dev/null +++ b/target/linux/cv18x0/patches-6.6/0012-clk-sophgo-Add-CV1800-SG2000-series-clock-controller.patch @@ -0,0 +1,3743 @@ +From ff1199b26c397a8dfd94a72565c515c20474f468 Mon Sep 17 00:00:00 2001 +From: Inochi Amaoto +Date: Tue, 13 Feb 2024 16:22:34 +0800 +Subject: [PATCH 12/18] clk: sophgo: Add CV1800/SG2000 series clock controller + driver skeleton + +Add driver skeleton for CV1800/SG2000 series clock controller. +The skeleton code includes: +1. common utility code for clk_ops implementation +2. basic probe code of the whole driver +3. helper structure for clk definition + +Signed-off-by: Inochi Amaoto +--- + arch/riscv/boot/dts/sophgo/cv1800b.dtsi | 4 + + arch/riscv/boot/dts/sophgo/cv1812h.dtsi | 4 + + arch/riscv/boot/dts/sophgo/cv18xx.dtsi | 22 +- + drivers/clk/Kconfig | 1 + + drivers/clk/Makefile | 1 + + drivers/clk/sophgo/Kconfig | 12 + + drivers/clk/sophgo/Makefile | 7 + + drivers/clk/sophgo/clk-cv1800.c | 1541 +++++++++++++++++++++++ + drivers/clk/sophgo/clk-cv1800.h | 123 ++ + drivers/clk/sophgo/clk-cv18xx-common.c | 66 + + drivers/clk/sophgo/clk-cv18xx-common.h | 81 ++ + drivers/clk/sophgo/clk-cv18xx-ip.c | 887 +++++++++++++ + drivers/clk/sophgo/clk-cv18xx-ip.h | 261 ++++ + drivers/clk/sophgo/clk-cv18xx-pll.c | 420 ++++++ + drivers/clk/sophgo/clk-cv18xx-pll.h | 118 ++ + 15 files changed, 3543 insertions(+), 5 deletions(-) + create mode 100644 drivers/clk/sophgo/Kconfig + create mode 100644 drivers/clk/sophgo/Makefile + create mode 100644 drivers/clk/sophgo/clk-cv1800.c + create mode 100644 drivers/clk/sophgo/clk-cv1800.h + create mode 100644 drivers/clk/sophgo/clk-cv18xx-common.c + create mode 100644 drivers/clk/sophgo/clk-cv18xx-common.h + create mode 100644 drivers/clk/sophgo/clk-cv18xx-ip.c + create mode 100644 drivers/clk/sophgo/clk-cv18xx-ip.h + create mode 100644 drivers/clk/sophgo/clk-cv18xx-pll.c + create mode 100644 drivers/clk/sophgo/clk-cv18xx-pll.h + +diff --git a/arch/riscv/boot/dts/sophgo/cv1800b.dtsi b/arch/riscv/boot/dts/sophgo/cv1800b.dtsi +index 165e9e320a8c..baf641829e72 100644 +--- a/arch/riscv/boot/dts/sophgo/cv1800b.dtsi ++++ b/arch/riscv/boot/dts/sophgo/cv1800b.dtsi +@@ -16,3 +16,7 @@ + &clint { + compatible = "sophgo,cv1800b-clint", "thead,c900-clint"; + }; ++ ++&clk { ++ compatible = "sophgo,cv1800-clk"; ++}; +diff --git a/arch/riscv/boot/dts/sophgo/cv1812h.dtsi b/arch/riscv/boot/dts/sophgo/cv1812h.dtsi +index 3e7a942f5c1a..7fa4c1e2d1da 100644 +--- a/arch/riscv/boot/dts/sophgo/cv1812h.dtsi ++++ b/arch/riscv/boot/dts/sophgo/cv1812h.dtsi +@@ -22,3 +22,7 @@ + &clint { + compatible = "sophgo,cv1812h-clint", "thead,c900-clint"; + }; ++ ++&clk { ++ compatible = "sophgo,cv1810-clk"; ++}; +diff --git a/arch/riscv/boot/dts/sophgo/cv18xx.dtsi b/arch/riscv/boot/dts/sophgo/cv18xx.dtsi +index d415cc758def..e375e9d9516e 100644 +--- a/arch/riscv/boot/dts/sophgo/cv18xx.dtsi ++++ b/arch/riscv/boot/dts/sophgo/cv18xx.dtsi +@@ -5,6 +5,7 @@ + */ + + #include ++#include + + / { + #address-cells = <1>; +@@ -54,6 +55,12 @@ + dma-noncoherent; + ranges; + ++ clk: clock-controller@3002000 { ++ reg = <0x03002000 0x1000>; ++ clocks = <&osc>; ++ #clock-cells = <1>; ++ }; ++ + gpio0: gpio@3020000 { + compatible = "snps,dw-apb-gpio"; + reg = <0x3020000 0x1000>; +@@ -130,7 +137,8 @@ + compatible = "snps,dw-apb-uart"; + reg = <0x04140000 0x100>; + interrupts = <44 IRQ_TYPE_LEVEL_HIGH>; +- clocks = <&osc>; ++ clocks = <&clk CLK_UART0>, <&clk CLK_APB_UART0>; ++ clock-names = "baudclk", "apb_pclk"; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; +@@ -140,7 +148,8 @@ + compatible = "snps,dw-apb-uart"; + reg = <0x04150000 0x100>; + interrupts = <45 IRQ_TYPE_LEVEL_HIGH>; +- clocks = <&osc>; ++ clocks = <&clk CLK_UART1>, <&clk CLK_APB_UART1>; ++ clock-names = "baudclk", "apb_pclk"; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; +@@ -150,7 +159,8 @@ + compatible = "snps,dw-apb-uart"; + reg = <0x04160000 0x100>; + interrupts = <46 IRQ_TYPE_LEVEL_HIGH>; +- clocks = <&osc>; ++ clocks = <&clk CLK_UART2>, <&clk CLK_APB_UART2>; ++ clock-names = "baudclk", "apb_pclk"; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; +@@ -160,7 +170,8 @@ + compatible = "snps,dw-apb-uart"; + reg = <0x04170000 0x100>; + interrupts = <47 IRQ_TYPE_LEVEL_HIGH>; +- clocks = <&osc>; ++ clocks = <&clk CLK_UART3>, <&clk CLK_APB_UART3>; ++ clock-names = "baudclk", "apb_pclk"; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; +@@ -170,7 +181,8 @@ + compatible = "snps,dw-apb-uart"; + reg = <0x041c0000 0x100>; + interrupts = <48 IRQ_TYPE_LEVEL_HIGH>; +- clocks = <&osc>; ++ clocks = <&clk CLK_UART4>, <&clk CLK_APB_UART4>; ++ clock-names = "baudclk", "apb_pclk"; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; +diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig +index c30099866174..f3ec23f22e3e 100644 +--- a/drivers/clk/Kconfig ++++ b/drivers/clk/Kconfig +@@ -490,6 +490,7 @@ source "drivers/clk/rockchip/Kconfig" + source "drivers/clk/samsung/Kconfig" + source "drivers/clk/sifive/Kconfig" + source "drivers/clk/socfpga/Kconfig" ++source "drivers/clk/sophgo/Kconfig" + source "drivers/clk/sprd/Kconfig" + source "drivers/clk/starfive/Kconfig" + source "drivers/clk/sunxi/Kconfig" +diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile +index 18969cbd4bb1..acac827d906a 100644 +--- a/drivers/clk/Makefile ++++ b/drivers/clk/Makefile +@@ -117,6 +117,7 @@ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ + obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/ + obj-$(CONFIG_CLK_SIFIVE) += sifive/ + obj-y += socfpga/ ++obj-y += sophgo/ + obj-$(CONFIG_PLAT_SPEAR) += spear/ + obj-y += sprd/ + obj-$(CONFIG_ARCH_STI) += st/ +diff --git a/drivers/clk/sophgo/Kconfig b/drivers/clk/sophgo/Kconfig +new file mode 100644 +index 000000000000..d67009fa749f +--- /dev/null ++++ b/drivers/clk/sophgo/Kconfig +@@ -0,0 +1,12 @@ ++# SPDX-License-Identifier: GPL-2.0 ++# common clock support for SOPHGO SoC family. ++ ++config CLK_SOPHGO_CV1800 ++ tristate "Support for the Sophgo CV1800 series SoCs clock controller" ++ default m ++ depends on ARCH_SOPHGO || COMPILE_TEST ++ help ++ This driver supports clock controller of Sophgo CV18XX series SoC. ++ The driver require a 25MHz Oscillator to function generate clock. ++ It includes PLLs, common clock function and some vendor clock for ++ IPs of CV18XX series SoC +diff --git a/drivers/clk/sophgo/Makefile b/drivers/clk/sophgo/Makefile +new file mode 100644 +index 000000000000..a50320764200 +--- /dev/null ++++ b/drivers/clk/sophgo/Makefile +@@ -0,0 +1,7 @@ ++# SPDX-License-Identifier: GPL-2.0 ++obj-$(CONFIG_CLK_SOPHGO_CV1800) += clk-sophgo-cv1800.o ++ ++clk-sophgo-cv1800-y += clk-cv1800.o ++clk-sophgo-cv1800-y += clk-cv18xx-common.o ++clk-sophgo-cv1800-y += clk-cv18xx-ip.o ++clk-sophgo-cv1800-y += clk-cv18xx-pll.o +diff --git a/drivers/clk/sophgo/clk-cv1800.c b/drivers/clk/sophgo/clk-cv1800.c +new file mode 100644 +index 000000000000..1aedf2df242c +--- /dev/null ++++ b/drivers/clk/sophgo/clk-cv1800.c +@@ -0,0 +1,1541 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2023 Inochi Amaoto ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "clk-cv1800.h" ++ ++#include "clk-cv18xx-common.h" ++#include "clk-cv18xx-ip.h" ++#include "clk-cv18xx-pll.h" ++ ++struct cv1800_clk_ctrl; ++ ++struct cv1800_clk_desc { ++ struct clk_hw_onecell_data *clks_data; ++ ++ int (*pre_init)(struct device *dev, void __iomem *base, ++ struct cv1800_clk_ctrl *ctrl, ++ const struct cv1800_clk_desc *desc); ++}; ++ ++struct cv1800_clk_ctrl { ++ const struct cv1800_clk_desc *desc; ++ spinlock_t lock; ++}; ++ ++#define CV1800_DIV_FLAG \ ++ (CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ROUND_CLOSEST) ++static const struct clk_parent_data osc_parents[] = { ++ { .index = 0 }, ++}; ++ ++static const struct cv1800_clk_pll_limit pll_limits[] = { ++ { ++ .pre_div = _CV1800_PLL_LIMIT(1, 127), ++ .div = _CV1800_PLL_LIMIT(6, 127), ++ .post_div = _CV1800_PLL_LIMIT(1, 127), ++ .ictrl = _CV1800_PLL_LIMIT(0, 7), ++ .mode = _CV1800_PLL_LIMIT(0, 3), ++ }, ++ { ++ .pre_div = _CV1800_PLL_LIMIT(1, 127), ++ .div = _CV1800_PLL_LIMIT(6, 127), ++ .post_div = _CV1800_PLL_LIMIT(1, 127), ++ .ictrl = _CV1800_PLL_LIMIT(0, 7), ++ .mode = _CV1800_PLL_LIMIT(0, 3), ++ }, ++}; ++ ++static CV1800_INTEGRAL_PLL(clk_fpll, osc_parents, ++ REG_FPLL_CSR, ++ REG_PLL_G6_CTRL, 8, ++ REG_PLL_G6_STATUS, 2, ++ pll_limits, ++ CLK_IS_CRITICAL); ++ ++static CV1800_INTEGRAL_PLL(clk_mipimpll, osc_parents, ++ REG_MIPIMPLL_CSR, ++ REG_PLL_G2_CTRL, 0, ++ REG_PLL_G2_STATUS, 0, ++ pll_limits, ++ CLK_IS_CRITICAL); ++ ++static const struct clk_parent_data clk_mipimpll_parents[] = { ++ { .hw = &clk_mipimpll.common.hw }, ++}; ++static const struct clk_parent_data clk_bypass_mipimpll_parents[] = { ++ { .index = 0 }, ++ { .hw = &clk_mipimpll.common.hw }, ++}; ++static const struct clk_parent_data clk_bypass_fpll_parents[] = { ++ { .index = 0 }, ++ { .hw = &clk_fpll.common.hw }, ++}; ++ ++struct cv1800_clk_pll_synthesizer clk_mpll_synthesizer = { ++ .en = CV1800_CLK_BIT(REG_PLL_G6_SSC_SYN_CTRL, 2), ++ .clk_half = CV1800_CLK_BIT(REG_PLL_G6_SSC_SYN_CTRL, 0), ++ .ctrl = REG_MPLL_SSC_SYN_CTRL, ++ .set = REG_MPLL_SSC_SYN_SET, ++}; ++static CV1800_FACTIONAL_PLL(clk_mpll, clk_bypass_mipimpll_parents, ++ REG_MPLL_CSR, ++ REG_PLL_G6_CTRL, 0, ++ REG_PLL_G6_STATUS, 0, ++ pll_limits, ++ &clk_mpll_synthesizer, ++ CLK_IS_CRITICAL); ++ ++struct cv1800_clk_pll_synthesizer clk_tpll_synthesizer = { ++ .en = CV1800_CLK_BIT(REG_PLL_G6_SSC_SYN_CTRL, 3), ++ .clk_half = CV1800_CLK_BIT(REG_PLL_G6_SSC_SYN_CTRL, 0), ++ .ctrl = REG_TPLL_SSC_SYN_CTRL, ++ .set = REG_TPLL_SSC_SYN_SET, ++}; ++static CV1800_FACTIONAL_PLL(clk_tpll, clk_bypass_mipimpll_parents, ++ REG_TPLL_CSR, ++ REG_PLL_G6_CTRL, 4, ++ REG_PLL_G6_STATUS, 1, ++ pll_limits, ++ &clk_tpll_synthesizer, ++ CLK_IS_CRITICAL); ++ ++struct cv1800_clk_pll_synthesizer clk_a0pll_synthesizer = { ++ .en = CV1800_CLK_BIT(REG_PLL_G2_SSC_SYN_CTRL, 2), ++ .clk_half = CV1800_CLK_BIT(REG_PLL_G2_SSC_SYN_CTRL, 0), ++ .ctrl = REG_A0PLL_SSC_SYN_CTRL, ++ .set = REG_A0PLL_SSC_SYN_SET, ++}; ++static CV1800_FACTIONAL_PLL(clk_a0pll, clk_bypass_mipimpll_parents, ++ REG_A0PLL_CSR, ++ REG_PLL_G2_CTRL, 4, ++ REG_PLL_G2_STATUS, 1, ++ pll_limits, ++ &clk_a0pll_synthesizer, ++ CLK_IS_CRITICAL); ++ ++struct cv1800_clk_pll_synthesizer clk_disppll_synthesizer = { ++ .en = CV1800_CLK_BIT(REG_PLL_G2_SSC_SYN_CTRL, 3), ++ .clk_half = CV1800_CLK_BIT(REG_PLL_G2_SSC_SYN_CTRL, 0), ++ .ctrl = REG_DISPPLL_SSC_SYN_CTRL, ++ .set = REG_DISPPLL_SSC_SYN_SET, ++}; ++static CV1800_FACTIONAL_PLL(clk_disppll, clk_bypass_mipimpll_parents, ++ REG_DISPPLL_CSR, ++ REG_PLL_G2_CTRL, 8, ++ REG_PLL_G2_STATUS, 2, ++ pll_limits, ++ &clk_disppll_synthesizer, ++ CLK_IS_CRITICAL); ++ ++struct cv1800_clk_pll_synthesizer clk_cam0pll_synthesizer = { ++ .en = CV1800_CLK_BIT(REG_PLL_G2_SSC_SYN_CTRL, 4), ++ .clk_half = CV1800_CLK_BIT(REG_PLL_G2_SSC_SYN_CTRL, 0), ++ .ctrl = REG_CAM0PLL_SSC_SYN_CTRL, ++ .set = REG_CAM0PLL_SSC_SYN_SET, ++}; ++static CV1800_FACTIONAL_PLL(clk_cam0pll, clk_bypass_mipimpll_parents, ++ REG_CAM0PLL_CSR, ++ REG_PLL_G2_CTRL, 12, ++ REG_PLL_G2_STATUS, 3, ++ pll_limits, ++ &clk_cam0pll_synthesizer, ++ CLK_IGNORE_UNUSED); ++ ++struct cv1800_clk_pll_synthesizer clk_cam1pll_synthesizer = { ++ .en = CV1800_CLK_BIT(REG_PLL_G2_SSC_SYN_CTRL, 5), ++ .clk_half = CV1800_CLK_BIT(REG_PLL_G2_SSC_SYN_CTRL, 0), ++ .ctrl = REG_CAM1PLL_SSC_SYN_CTRL, ++ .set = REG_CAM1PLL_SSC_SYN_SET, ++}; ++static CV1800_FACTIONAL_PLL(clk_cam1pll, clk_bypass_mipimpll_parents, ++ REG_CAM1PLL_CSR, ++ REG_PLL_G2_CTRL, 16, ++ REG_PLL_G2_STATUS, 4, ++ pll_limits, ++ &clk_cam1pll_synthesizer, ++ CLK_IS_CRITICAL); ++ ++static const struct clk_parent_data clk_cam0pll_parents[] = { ++ { .hw = &clk_cam0pll.common.hw }, ++}; ++ ++/* G2D */ ++static CV1800_FIXED_DIV(clk_cam0pll_d2, clk_cam0pll_parents, ++ REG_CAM0PLL_CLK_CSR, 1, ++ 2, ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED); ++static CV1800_FIXED_DIV(clk_cam0pll_d3, clk_cam0pll_parents, ++ REG_CAM0PLL_CLK_CSR, 2, ++ 3, ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED); ++static CV1800_FIXED_DIV(clk_mipimpll_d3, clk_mipimpll_parents, ++ REG_MIPIMPLL_CLK_CSR, 2, ++ 3, ++ CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED); ++ ++/* TPU */ ++static const struct clk_parent_data clk_tpu_parents[] = { ++ { .index = 0 }, ++ { .hw = &clk_tpll.common.hw }, ++ { .hw = &clk_a0pll.common.hw }, ++ { .hw = &clk_mipimpll.common.hw }, ++ { .hw = &clk_fpll.common.hw }, ++}; ++ ++static CV1800_BYPASS_MUX(clk_tpu, clk_tpu_parents, ++ REG_CLK_EN_0, 4, ++ REG_DIV_CLK_TPU, 16, 4, 3, CV1800_DIV_FLAG, ++ REG_DIV_CLK_TPU, 8, 2, ++ REG_CLK_BYP_0, 3, ++ 0); ++static CV1800_GATE(clk_tpu_fab, clk_mipimpll_parents, ++ REG_CLK_EN_0, 5, ++ 0); ++ ++/* FABRIC_AXI6 */ ++static CV1800_BYPASS_DIV(clk_axi6, clk_bypass_fpll_parents, ++ REG_CLK_EN_2, 2, ++ REG_DIV_CLK_AXI6, 16, 4, 15, CV1800_DIV_FLAG, ++ REG_CLK_BYP_0, 20, ++ CLK_IS_CRITICAL); ++ ++static const struct clk_parent_data clk_axi6_bus_parents[] = { ++ { .hw = &clk_axi6.div.common.hw }, ++}; ++static const struct clk_parent_data clk_bypass_axi6_bus_parents[] = { ++ { .index = 0 }, ++ { .hw = &clk_axi6.div.common.hw }, ++}; ++ ++/* FABRIC_AXI4 */ ++static const struct clk_parent_data clk_axi4_parents[] = { ++ { .index = 0 }, ++ { .hw = &clk_fpll.common.hw }, ++ { .hw = &clk_disppll.common.hw }, ++}; ++ ++static CV1800_BYPASS_MUX(clk_axi4, clk_axi4_parents, ++ REG_CLK_EN_2, 1, ++ REG_DIV_CLK_AXI4, 16, 4, 5, CV1800_DIV_FLAG, ++ REG_DIV_CLK_AXI4, 8, 2, ++ REG_CLK_BYP_0, 19, ++ CLK_IS_CRITICAL); ++ ++static const struct clk_parent_data clk_axi4_bus_parents[] = { ++ { .hw = &clk_axi4.mux.common.hw }, ++}; ++ ++/* XTAL_MISC */ ++static CV1800_GATE(clk_xtal_misc, osc_parents, ++ REG_CLK_EN_0, 14, ++ CLK_IS_CRITICAL); ++ ++static const struct clk_parent_data clk_timer_parents[] = { ++ { .hw = &clk_xtal_misc.common.hw }, ++}; ++ ++/* TOP */ ++static const struct clk_parent_data clk_cam0_200_parents[] = { ++ { .index = 0 }, ++ { .index = 0 }, ++ { .hw = &clk_disppll.common.hw }, ++}; ++ ++static CV1800_BYPASS_MUX(clk_cam0_200, clk_cam0_200_parents, ++ REG_CLK_EN_1, 13, ++ REG_DIV_CLK_CAM0_200, 16, 4, 1, CV1800_DIV_FLAG, ++ REG_DIV_CLK_CAM0_200, 8, 2, ++ REG_CLK_BYP_0, 16, ++ CLK_IS_CRITICAL); ++static CV1800_DIV(clk_1m, osc_parents, ++ REG_CLK_EN_3, 5, ++ REG_DIV_CLK_1M, 16, 6, 25, CV1800_DIV_FLAG, ++ CLK_IS_CRITICAL); ++static CV1800_GATE(clk_pm, clk_axi6_bus_parents, ++ REG_CLK_EN_3, 8, ++ CLK_IS_CRITICAL); ++static CV1800_GATE(clk_timer0, clk_timer_parents, ++ REG_CLK_EN_3, 9, ++ CLK_IS_CRITICAL); ++static CV1800_GATE(clk_timer1, clk_timer_parents, ++ REG_CLK_EN_3, 10, ++ CLK_IS_CRITICAL); ++static CV1800_GATE(clk_timer2, clk_timer_parents, ++ REG_CLK_EN_3, 11, ++ CLK_IS_CRITICAL); ++static CV1800_GATE(clk_timer3, clk_timer_parents, ++ REG_CLK_EN_3, 12, ++ CLK_IS_CRITICAL); ++static CV1800_GATE(clk_timer4, clk_timer_parents, ++ REG_CLK_EN_3, 13, ++ CLK_IS_CRITICAL); ++static CV1800_GATE(clk_timer5, clk_timer_parents, ++ REG_CLK_EN_3, 14, ++ CLK_IS_CRITICAL); ++static CV1800_GATE(clk_timer6, clk_timer_parents, ++ REG_CLK_EN_3, 15, ++ CLK_IS_CRITICAL); ++static CV1800_GATE(clk_timer7, clk_timer_parents, ++ REG_CLK_EN_3, 16, ++ CLK_IS_CRITICAL); ++ ++static const struct clk_parent_data clk_parents_1m[] = { ++ { .hw = &clk_1m.common.hw }, ++}; ++static const struct clk_parent_data clk_uart_parents[] = { ++ { .hw = &clk_cam0_200.mux.common.hw }, ++}; ++ ++/* AHB ROM */ ++static CV1800_GATE(clk_ahb_rom, clk_axi4_bus_parents, ++ REG_CLK_EN_0, 6, ++ 0); ++ ++/* RTC */ ++static CV1800_GATE(clk_rtc_25m, osc_parents, ++ REG_CLK_EN_0, 8, ++ CLK_IS_CRITICAL); ++static CV1800_BYPASS_DIV(clk_src_rtc_sys_0, clk_bypass_fpll_parents, ++ REG_CLK_EN_4, 6, ++ REG_DIV_CLK_RTCSYS_SRC_0, 16, 4, 5, CV1800_DIV_FLAG, ++ REG_CLK_BYP_1, 5, ++ CLK_IS_CRITICAL); ++ ++/* TEMPSEN */ ++static CV1800_GATE(clk_tempsen, osc_parents, ++ REG_CLK_EN_0, 9, ++ 0); ++ ++/* SARADC */ ++static CV1800_GATE(clk_saradc, osc_parents, ++ REG_CLK_EN_0, 10, ++ 0); ++ ++/* EFUSE */ ++static CV1800_GATE(clk_efuse, osc_parents, ++ REG_CLK_EN_0, 11, ++ 0); ++static CV1800_GATE(clk_apb_efuse, osc_parents, ++ REG_CLK_EN_0, 12, ++ 0); ++ ++/* WDT */ ++static CV1800_GATE(clk_apb_wdt, osc_parents, ++ REG_CLK_EN_1, 7, ++ CLK_IS_CRITICAL); ++ ++/* WGN */ ++static CV1800_GATE(clk_wgn, osc_parents, ++ REG_CLK_EN_3, 22, ++ 0); ++static CV1800_GATE(clk_wgn0, osc_parents, ++ REG_CLK_EN_3, 23, ++ 0); ++static CV1800_GATE(clk_wgn1, osc_parents, ++ REG_CLK_EN_3, 24, ++ 0); ++static CV1800_GATE(clk_wgn2, osc_parents, ++ REG_CLK_EN_3, 25, ++ 0); ++ ++/* KEYSCAN */ ++static CV1800_GATE(clk_keyscan, osc_parents, ++ REG_CLK_EN_3, 26, ++ 0); ++ ++/* EMMC */ ++static CV1800_GATE(clk_axi4_emmc, clk_axi4_bus_parents, ++ REG_CLK_EN_0, 15, ++ 0); ++static CV1800_BYPASS_MUX(clk_emmc, clk_axi4_parents, ++ REG_CLK_EN_0, 16, ++ REG_DIV_CLK_EMMC, 16, 5, 15, CV1800_DIV_FLAG, ++ REG_DIV_CLK_EMMC, 8, 2, ++ REG_CLK_BYP_0, 5, ++ 0); ++static CV1800_DIV(clk_emmc_100k, clk_parents_1m, ++ REG_CLK_EN_0, 17, ++ REG_DIV_CLK_EMMC_100K, 16, 8, 10, CV1800_DIV_FLAG, ++ 0); ++ ++/* SD */ ++static CV1800_GATE(clk_axi4_sd0, clk_axi4_bus_parents, ++ REG_CLK_EN_0, 18, ++ 0); ++static CV1800_BYPASS_MUX(clk_sd0, clk_axi4_parents, ++ REG_CLK_EN_0, 19, ++ REG_DIV_CLK_SD0, 16, 5, 15, CV1800_DIV_FLAG, ++ REG_DIV_CLK_SD0, 8, 2, ++ REG_CLK_BYP_0, 6, ++ 0); ++static CV1800_DIV(clk_sd0_100k, clk_parents_1m, ++ REG_CLK_EN_0, 20, ++ REG_DIV_CLK_SD0_100K, 16, 8, 10, CV1800_DIV_FLAG, ++ 0); ++static CV1800_GATE(clk_axi4_sd1, clk_axi4_bus_parents, ++ REG_CLK_EN_0, 21, ++ 0); ++static CV1800_BYPASS_MUX(clk_sd1, clk_axi4_parents, ++ REG_CLK_EN_0, 22, ++ REG_DIV_CLK_SD1, 16, 5, 15, CV1800_DIV_FLAG, ++ REG_DIV_CLK_SD1, 8, 2, ++ REG_CLK_BYP_0, 7, ++ 0); ++static CV1800_DIV(clk_sd1_100k, clk_parents_1m, ++ REG_CLK_EN_0, 23, ++ REG_DIV_CLK_SD1_100K, 16, 8, 10, CV1800_DIV_FLAG, ++ 0); ++ ++/* SPI NAND */ ++static CV1800_BYPASS_MUX(clk_spi_nand, clk_axi4_parents, ++ REG_CLK_EN_0, 24, ++ REG_DIV_CLK_SPI_NAND, 16, 5, 8, CV1800_DIV_FLAG, ++ REG_DIV_CLK_SPI_NAND, 8, 2, ++ REG_CLK_BYP_0, 8, ++ 0); ++ ++/* GPIO */ ++static CV1800_DIV(clk_gpio_db, clk_parents_1m, ++ REG_CLK_EN_0, 31, ++ REG_DIV_CLK_GPIO_DB, 16, 16, 10, CV1800_DIV_FLAG, ++ CLK_IS_CRITICAL); ++static CV1800_GATE(clk_apb_gpio, clk_axi6_bus_parents, ++ REG_CLK_EN_0, 29, ++ CLK_IS_CRITICAL); ++static CV1800_GATE(clk_apb_gpio_intr, clk_axi6_bus_parents, ++ REG_CLK_EN_0, 30, ++ CLK_IS_CRITICAL); ++ ++/* ETH */ ++static CV1800_BYPASS_DIV(clk_eth0_500m, clk_bypass_fpll_parents, ++ REG_CLK_EN_0, 25, ++ REG_DIV_CLK_GPIO_DB, 16, 4, 3, CV1800_DIV_FLAG, ++ REG_CLK_BYP_0, 9, ++ 0); ++static CV1800_GATE(clk_axi4_eth0, clk_axi4_bus_parents, ++ REG_CLK_EN_0, 26, ++ 0); ++static CV1800_BYPASS_DIV(clk_eth1_500m, clk_bypass_fpll_parents, ++ REG_CLK_EN_0, 27, ++ REG_DIV_CLK_GPIO_DB, 16, 4, 3, CV1800_DIV_FLAG, ++ REG_CLK_BYP_0, 10, ++ 0); ++static CV1800_GATE(clk_axi4_eth1, clk_axi4_bus_parents, ++ REG_CLK_EN_0, 28, ++ 0); ++ ++/* SF */ ++static CV1800_GATE(clk_ahb_sf, clk_axi4_bus_parents, ++ REG_CLK_EN_1, 0, ++ 0); ++static CV1800_GATE(clk_ahb_sf1, clk_axi4_bus_parents, ++ REG_CLK_EN_3, 27, ++ 0); ++ ++/* AUDSRC */ ++static CV1800_ACLK(clk_a24m, clk_mipimpll_parents, ++ REG_APLL_FRAC_DIV_CTRL, 0, ++ REG_APLL_FRAC_DIV_CTRL, 3, ++ REG_APLL_FRAC_DIV_CTRL, 1, ++ REG_APLL_FRAC_DIV_CTRL, 2, ++ REG_APLL_FRAC_DIV_M, 0, 22, CV1800_DIV_FLAG, ++ REG_APLL_FRAC_DIV_N, 0, 22, CV1800_DIV_FLAG, ++ 24576000, ++ 0); ++ ++static const struct clk_parent_data clk_aud_parents[] = { ++ { .index = 0 }, ++ { .hw = &clk_a0pll.common.hw }, ++ { .hw = &clk_a24m.common.hw }, ++}; ++ ++static CV1800_BYPASS_MUX(clk_audsrc, clk_aud_parents, ++ REG_CLK_EN_4, 1, ++ REG_DIV_CLK_AUDSRC, 16, 8, 18, CV1800_DIV_FLAG, ++ REG_DIV_CLK_AUDSRC, 8, 2, ++ REG_CLK_BYP_1, 2, ++ 0); ++static CV1800_GATE(clk_apb_audsrc, clk_axi4_bus_parents, ++ REG_CLK_EN_4, 2, ++ 0); ++ ++/* SDMA */ ++static CV1800_GATE(clk_sdma_axi, clk_axi4_bus_parents, ++ REG_CLK_EN_1, 1, ++ 0); ++static CV1800_BYPASS_MUX(clk_sdma_aud0, clk_aud_parents, ++ REG_CLK_EN_1, 2, ++ REG_DIV_CLK_SDMA_AUD0, 16, 8, 18, CV1800_DIV_FLAG, ++ REG_DIV_CLK_SDMA_AUD0, 8, 2, ++ REG_CLK_BYP_0, 11, ++ 0); ++static CV1800_BYPASS_MUX(clk_sdma_aud1, clk_aud_parents, ++ REG_CLK_EN_1, 3, ++ REG_DIV_CLK_SDMA_AUD1, 16, 8, 18, CV1800_DIV_FLAG, ++ REG_DIV_CLK_SDMA_AUD1, 8, 2, ++ REG_CLK_BYP_0, 12, ++ 0); ++static CV1800_BYPASS_MUX(clk_sdma_aud2, clk_aud_parents, ++ REG_CLK_EN_1, 3, ++ REG_DIV_CLK_SDMA_AUD2, 16, 8, 18, CV1800_DIV_FLAG, ++ REG_DIV_CLK_SDMA_AUD2, 8, 2, ++ REG_CLK_BYP_0, 13, ++ 0); ++static CV1800_BYPASS_MUX(clk_sdma_aud3, clk_aud_parents, ++ REG_CLK_EN_1, 3, ++ REG_DIV_CLK_SDMA_AUD3, 16, 8, 18, CV1800_DIV_FLAG, ++ REG_DIV_CLK_SDMA_AUD3, 8, 2, ++ REG_CLK_BYP_0, 14, ++ 0); ++ ++/* SPI */ ++static CV1800_GATE(clk_apb_spi0, clk_axi4_bus_parents, ++ REG_CLK_EN_1, 9, ++ 0); ++static CV1800_GATE(clk_apb_spi1, clk_axi4_bus_parents, ++ REG_CLK_EN_1, 10, ++ 0); ++static CV1800_GATE(clk_apb_spi2, clk_axi4_bus_parents, ++ REG_CLK_EN_1, 11, ++ 0); ++static CV1800_GATE(clk_apb_spi3, clk_axi4_bus_parents, ++ REG_CLK_EN_1, 12, ++ 0); ++static CV1800_BYPASS_DIV(clk_spi, clk_bypass_fpll_parents, ++ REG_CLK_EN_3, 6, ++ REG_DIV_CLK_SPI, 16, 6, 8, CV1800_DIV_FLAG, ++ REG_CLK_BYP_0, 30, ++ 0); ++ ++/* UART */ ++static CV1800_GATE(clk_uart0, clk_uart_parents, ++ REG_CLK_EN_1, 14, ++ CLK_IS_CRITICAL); ++static CV1800_GATE(clk_apb_uart0, clk_axi4_bus_parents, ++ REG_CLK_EN_1, 15, ++ CLK_IS_CRITICAL); ++static CV1800_GATE(clk_uart1, clk_uart_parents, ++ REG_CLK_EN_1, 16, ++ 0); ++static CV1800_GATE(clk_apb_uart1, clk_axi4_bus_parents, ++ REG_CLK_EN_1, 17, ++ 0); ++static CV1800_GATE(clk_uart2, clk_uart_parents, ++ REG_CLK_EN_1, 18, ++ 0); ++static CV1800_GATE(clk_apb_uart2, clk_axi4_bus_parents, ++ REG_CLK_EN_1, 19, ++ 0); ++static CV1800_GATE(clk_uart3, clk_uart_parents, ++ REG_CLK_EN_1, 20, ++ 0); ++static CV1800_GATE(clk_apb_uart3, clk_axi4_bus_parents, ++ REG_CLK_EN_1, 21, ++ 0); ++static CV1800_GATE(clk_uart4, clk_uart_parents, ++ REG_CLK_EN_1, 22, ++ 0); ++static CV1800_GATE(clk_apb_uart4, clk_axi4_bus_parents, ++ REG_CLK_EN_1, 23, ++ 0); ++ ++/* I2S */ ++static CV1800_GATE(clk_apb_i2s0, clk_axi4_bus_parents, ++ REG_CLK_EN_1, 24, ++ 0); ++static CV1800_GATE(clk_apb_i2s1, clk_axi4_bus_parents, ++ REG_CLK_EN_1, 25, ++ 0); ++static CV1800_GATE(clk_apb_i2s2, clk_axi4_bus_parents, ++ REG_CLK_EN_1, 26, ++ 0); ++static CV1800_GATE(clk_apb_i2s3, clk_axi4_bus_parents, ++ REG_CLK_EN_1, 27, ++ 0); ++ ++/* DEBUG */ ++static CV1800_GATE(clk_debug, osc_parents, ++ REG_CLK_EN_0, 13, ++ CLK_IS_CRITICAL); ++static CV1800_BYPASS_DIV(clk_ap_debug, clk_bypass_fpll_parents, ++ REG_CLK_EN_4, 5, ++ REG_DIV_CLK_AP_DEBUG, 16, 4, 5, CV1800_DIV_FLAG, ++ REG_CLK_BYP_1, 4, ++ CLK_IS_CRITICAL); ++ ++/* DDR */ ++static CV1800_GATE(clk_ddr_axi_reg, clk_axi6_bus_parents, ++ REG_CLK_EN_0, 7, ++ CLK_IS_CRITICAL); ++ ++/* I2C */ ++static CV1800_GATE(clk_apb_i2c, clk_axi4_bus_parents, ++ REG_CLK_EN_1, 6, ++ 0); ++static CV1800_BYPASS_DIV(clk_i2c, clk_bypass_axi6_bus_parents, ++ REG_CLK_EN_3, 7, ++ REG_DIV_CLK_I2C, 16, 4, 1, CV1800_DIV_FLAG, ++ REG_CLK_BYP_0, 31, ++ 0); ++static CV1800_GATE(clk_apb_i2c0, clk_axi4_bus_parents, ++ REG_CLK_EN_3, 17, ++ 0); ++static CV1800_GATE(clk_apb_i2c1, clk_axi4_bus_parents, ++ REG_CLK_EN_3, 18, ++ 0); ++static CV1800_GATE(clk_apb_i2c2, clk_axi4_bus_parents, ++ REG_CLK_EN_3, 19, ++ 0); ++static CV1800_GATE(clk_apb_i2c3, clk_axi4_bus_parents, ++ REG_CLK_EN_3, 20, ++ 0); ++static CV1800_GATE(clk_apb_i2c4, clk_axi4_bus_parents, ++ REG_CLK_EN_3, 21, ++ 0); ++ ++/* USB */ ++static CV1800_GATE(clk_axi4_usb, clk_axi4_bus_parents, ++ REG_CLK_EN_1, 28, ++ 0); ++static CV1800_GATE(clk_apb_usb, clk_axi4_bus_parents, ++ REG_CLK_EN_1, 29, ++ 0); ++static CV1800_BYPASS_FIXED_DIV(clk_usb_125m, clk_bypass_fpll_parents, ++ REG_CLK_EN_1, 30, ++ 12, ++ REG_CLK_BYP_0, 17, ++ CLK_SET_RATE_PARENT); ++static CV1800_FIXED_DIV(clk_usb_33k, clk_parents_1m, ++ REG_CLK_EN_1, 31, ++ 3, ++ 0); ++static CV1800_BYPASS_FIXED_DIV(clk_usb_12m, clk_bypass_fpll_parents, ++ REG_CLK_EN_2, 0, ++ 125, ++ REG_CLK_BYP_0, 18, ++ CLK_SET_RATE_PARENT); ++ ++/* VIP SYS */ ++static const struct clk_parent_data clk_vip_sys_parents[] = { ++ { .index = 0 }, ++ { .hw = &clk_mipimpll.common.hw }, ++ { .hw = &clk_cam0pll.common.hw }, ++ { .hw = &clk_disppll.common.hw }, ++ { .hw = &clk_fpll.common.hw }, ++}; ++static const struct clk_parent_data clk_disp_vip_parents[] = { ++ { .index = 0 }, ++ { .hw = &clk_disppll.common.hw }, ++}; ++ ++static CV1800_BYPASS_DIV(clk_dsi_esc, clk_bypass_axi6_bus_parents, ++ REG_CLK_EN_2, 3, ++ REG_DIV_CLK_DSI_ESC, 16, 4, 5, CV1800_DIV_FLAG, ++ REG_CLK_BYP_0, 21, ++ 0); ++static CV1800_BYPASS_MUX(clk_axi_vip, clk_vip_sys_parents, ++ REG_CLK_EN_2, 4, ++ REG_DIV_CLK_AXI_VIP, 16, 4, 3, CV1800_DIV_FLAG, ++ REG_DIV_CLK_AXI_VIP, 8, 2, ++ REG_CLK_BYP_0, 22, ++ 0); ++ ++static const struct clk_parent_data clk_axi_vip_bus_parents[] = { ++ { .hw = &clk_axi_vip.mux.common.hw }, ++}; ++ ++static CV1800_BYPASS_MUX(clk_src_vip_sys_0, clk_vip_sys_parents, ++ REG_CLK_EN_2, 5, ++ REG_DIV_CLK_SRC_VIP_SYS_0, 16, 4, 6, CV1800_DIV_FLAG, ++ REG_DIV_CLK_SRC_VIP_SYS_0, 8, 2, ++ REG_CLK_BYP_0, 23, ++ 0); ++static CV1800_BYPASS_MUX(clk_src_vip_sys_1, clk_vip_sys_parents, ++ REG_CLK_EN_2, 6, ++ REG_DIV_CLK_SRC_VIP_SYS_1, 16, 4, 6, CV1800_DIV_FLAG, ++ REG_DIV_CLK_SRC_VIP_SYS_1, 8, 2, ++ REG_CLK_BYP_0, 24, ++ 0); ++static CV1800_BYPASS_DIV(clk_disp_src_vip, clk_disp_vip_parents, ++ REG_CLK_EN_2, 7, ++ REG_DIV_CLK_DISP_SRC_VIP, 16, 4, 8, CV1800_DIV_FLAG, ++ REG_CLK_BYP_0, 25, ++ 0); ++static CV1800_BYPASS_MUX(clk_src_vip_sys_2, clk_vip_sys_parents, ++ REG_CLK_EN_3, 29, ++ REG_DIV_CLK_SRC_VIP_SYS_2, 16, 4, 2, CV1800_DIV_FLAG, ++ REG_DIV_CLK_SRC_VIP_SYS_2, 8, 2, ++ REG_CLK_BYP_1, 1, ++ 0); ++static CV1800_GATE(clk_csi_mac0_vip, clk_axi_vip_bus_parents, ++ REG_CLK_EN_2, 18, ++ 0); ++static CV1800_GATE(clk_csi_mac1_vip, clk_axi_vip_bus_parents, ++ REG_CLK_EN_2, 19, ++ 0); ++static CV1800_GATE(clk_isp_top_vip, clk_axi_vip_bus_parents, ++ REG_CLK_EN_2, 20, ++ 0); ++static CV1800_GATE(clk_img_d_vip, clk_axi_vip_bus_parents, ++ REG_CLK_EN_2, 21, ++ 0); ++static CV1800_GATE(clk_img_v_vip, clk_axi_vip_bus_parents, ++ REG_CLK_EN_2, 22, ++ 0); ++static CV1800_GATE(clk_sc_top_vip, clk_axi_vip_bus_parents, ++ REG_CLK_EN_2, 23, ++ 0); ++static CV1800_GATE(clk_sc_d_vip, clk_axi_vip_bus_parents, ++ REG_CLK_EN_2, 24, ++ 0); ++static CV1800_GATE(clk_sc_v1_vip, clk_axi_vip_bus_parents, ++ REG_CLK_EN_2, 25, ++ 0); ++static CV1800_GATE(clk_sc_v2_vip, clk_axi_vip_bus_parents, ++ REG_CLK_EN_2, 26, ++ 0); ++static CV1800_GATE(clk_sc_v3_vip, clk_axi_vip_bus_parents, ++ REG_CLK_EN_2, 27, ++ 0); ++static CV1800_GATE(clk_dwa_vip, clk_axi_vip_bus_parents, ++ REG_CLK_EN_2, 28, ++ 0); ++static CV1800_GATE(clk_bt_vip, clk_axi_vip_bus_parents, ++ REG_CLK_EN_2, 29, ++ 0); ++static CV1800_GATE(clk_disp_vip, clk_axi_vip_bus_parents, ++ REG_CLK_EN_2, 30, ++ 0); ++static CV1800_GATE(clk_dsi_mac_vip, clk_axi_vip_bus_parents, ++ REG_CLK_EN_2, 31, ++ 0); ++static CV1800_GATE(clk_lvds0_vip, clk_axi_vip_bus_parents, ++ REG_CLK_EN_3, 0, ++ 0); ++static CV1800_GATE(clk_lvds1_vip, clk_axi_vip_bus_parents, ++ REG_CLK_EN_3, 1, ++ 0); ++static CV1800_GATE(clk_csi0_rx_vip, clk_axi_vip_bus_parents, ++ REG_CLK_EN_3, 2, ++ 0); ++static CV1800_GATE(clk_csi1_rx_vip, clk_axi_vip_bus_parents, ++ REG_CLK_EN_3, 3, ++ 0); ++static CV1800_GATE(clk_pad_vi_vip, clk_axi_vip_bus_parents, ++ REG_CLK_EN_3, 4, ++ 0); ++static CV1800_GATE(clk_pad_vi1_vip, clk_axi_vip_bus_parents, ++ REG_CLK_EN_3, 30, ++ 0); ++static CV1800_GATE(clk_cfg_reg_vip, clk_axi6_bus_parents, ++ REG_CLK_EN_3, 31, ++ 0); ++static CV1800_GATE(clk_pad_vi2_vip, clk_axi_vip_bus_parents, ++ REG_CLK_EN_4, 7, ++ 0); ++static CV1800_GATE(clk_csi_be_vip, clk_axi_vip_bus_parents, ++ REG_CLK_EN_4, 8, ++ 0); ++static CV1800_GATE(clk_vip_ip0, clk_axi_vip_bus_parents, ++ REG_CLK_EN_4, 9, ++ 0); ++static CV1800_GATE(clk_vip_ip1, clk_axi_vip_bus_parents, ++ REG_CLK_EN_4, 10, ++ 0); ++static CV1800_GATE(clk_vip_ip2, clk_axi_vip_bus_parents, ++ REG_CLK_EN_4, 11, ++ 0); ++static CV1800_GATE(clk_vip_ip3, clk_axi_vip_bus_parents, ++ REG_CLK_EN_4, 12, ++ 0); ++static CV1800_BYPASS_MUX(clk_src_vip_sys_3, clk_vip_sys_parents, ++ REG_CLK_EN_4, 15, ++ REG_DIV_CLK_SRC_VIP_SYS_3, 16, 4, 2, CV1800_DIV_FLAG, ++ REG_DIV_CLK_SRC_VIP_SYS_3, 8, 2, ++ REG_CLK_BYP_1, 8, ++ 0); ++static CV1800_BYPASS_MUX(clk_src_vip_sys_4, clk_vip_sys_parents, ++ REG_CLK_EN_4, 16, ++ REG_DIV_CLK_SRC_VIP_SYS_4, 16, 4, 3, CV1800_DIV_FLAG, ++ REG_DIV_CLK_SRC_VIP_SYS_4, 8, 2, ++ REG_CLK_BYP_1, 9, ++ 0); ++static CV1800_GATE(clk_ive_vip, clk_axi_vip_bus_parents, ++ REG_CLK_EN_4, 17, ++ 0); ++static CV1800_GATE(clk_raw_vip, clk_axi_vip_bus_parents, ++ REG_CLK_EN_4, 18, ++ 0); ++static CV1800_GATE(clk_osdc_vip, clk_axi_vip_bus_parents, ++ REG_CLK_EN_4, 19, ++ 0); ++static CV1800_GATE(clk_csi_mac2_vip, clk_axi_vip_bus_parents, ++ REG_CLK_EN_4, 20, ++ 0); ++static CV1800_GATE(clk_cam0_vip, clk_axi_vip_bus_parents, ++ REG_CLK_EN_4, 21, ++ 0); ++ ++/* CAM OUT */ ++static const struct clk_parent_data clk_cam_parents[] = { ++ { .hw = &clk_cam0pll.common.hw }, ++ { .hw = &clk_cam0pll_d2.common.hw }, ++ { .hw = &clk_cam0pll_d3.common.hw }, ++ { .hw = &clk_mipimpll_d3.common.hw }, ++}; ++ ++static CV1800_MUX(clk_cam0, clk_cam_parents, ++ REG_CLK_EN_2, 16, ++ REG_CLK_CAM0_SRC_DIV, 16, 6, 0, CV1800_DIV_FLAG, ++ REG_CLK_CAM0_SRC_DIV, 8, 2, ++ CLK_IGNORE_UNUSED); ++static CV1800_MUX(clk_cam1, clk_cam_parents, ++ REG_CLK_EN_2, 17, ++ REG_CLK_CAM1_SRC_DIV, 16, 6, 0, CV1800_DIV_FLAG, ++ REG_CLK_CAM1_SRC_DIV, 8, 2, ++ CLK_IGNORE_UNUSED); ++ ++/* VIDEO SUBSYS */ ++static const struct clk_parent_data clk_axi_video_codec_parents[] = { ++ { .index = 0 }, ++ { .hw = &clk_a0pll.common.hw }, ++ { .hw = &clk_mipimpll.common.hw }, ++ { .hw = &clk_cam1pll.common.hw }, ++ { .hw = &clk_fpll.common.hw }, ++}; ++static const struct clk_parent_data clk_vc_src0_parents[] = { ++ { .index = 0 }, ++ { .hw = &clk_disppll.common.hw }, ++ { .hw = &clk_mipimpll.common.hw }, ++ { .hw = &clk_cam1pll.common.hw }, ++ { .hw = &clk_fpll.common.hw }, ++}; ++static const struct clk_parent_data clk_vc_src1_parents[] = { ++ { .index = 0 }, ++ { .hw = &clk_cam1pll.common.hw }, ++}; ++ ++static CV1800_BYPASS_MUX(clk_axi_video_codec, clk_axi_video_codec_parents, ++ REG_CLK_EN_2, 8, ++ REG_DIV_CLK_AXI_VIDEO_CODEC, 16, 4, 2, CV1800_DIV_FLAG, ++ REG_DIV_CLK_AXI_VIDEO_CODEC, 8, 2, ++ REG_CLK_BYP_0, 26, ++ 0); ++ ++static const struct clk_parent_data clk_axi_video_codec_bus_parents[] = { ++ { .hw = &clk_axi_video_codec.mux.common.hw }, ++}; ++ ++static CV1800_BYPASS_MUX(clk_vc_src0, clk_vc_src0_parents, ++ REG_CLK_EN_2, 9, ++ REG_DIV_CLK_VC_SRC0, 16, 4, 2, CV1800_DIV_FLAG, ++ REG_DIV_CLK_VC_SRC0, 8, 2, ++ REG_CLK_BYP_0, 27, ++ 0); ++ ++static CV1800_GATE(clk_h264c, clk_axi_video_codec_bus_parents, ++ REG_CLK_EN_2, 10, ++ 0); ++static CV1800_GATE(clk_h265c, clk_axi_video_codec_bus_parents, ++ REG_CLK_EN_2, 11, ++ 0); ++static CV1800_GATE(clk_jpeg, clk_axi_video_codec_bus_parents, ++ REG_CLK_EN_2, 12, ++ CLK_IGNORE_UNUSED); ++static CV1800_GATE(clk_apb_jpeg, clk_axi6_bus_parents, ++ REG_CLK_EN_2, 13, ++ CLK_IGNORE_UNUSED); ++static CV1800_GATE(clk_apb_h264c, clk_axi6_bus_parents, ++ REG_CLK_EN_2, 14, ++ 0); ++static CV1800_GATE(clk_apb_h265c, clk_axi6_bus_parents, ++ REG_CLK_EN_2, 15, ++ 0); ++static CV1800_BYPASS_FIXED_DIV(clk_vc_src1, clk_vc_src1_parents, ++ REG_CLK_EN_3, 28, ++ 2, ++ REG_CLK_BYP_1, 0, ++ CLK_SET_RATE_PARENT); ++static CV1800_BYPASS_FIXED_DIV(clk_vc_src2, clk_bypass_fpll_parents, ++ REG_CLK_EN_4, 3, ++ 3, ++ REG_CLK_BYP_1, 3, ++ CLK_SET_RATE_PARENT); ++ ++/* VC SYS */ ++static CV1800_GATE(clk_cfg_reg_vc, clk_axi6_bus_parents, ++ REG_CLK_EN_4, 0, ++ CLK_IGNORE_UNUSED); ++ ++/* PWM */ ++static CV1800_BYPASS_MUX(clk_pwm_src, clk_axi4_parents, ++ REG_CLK_EN_4, 4, ++ REG_DIV_CLK_PWM_SRC_0, 16, 6, 10, CV1800_DIV_FLAG, ++ REG_DIV_CLK_PWM_SRC_0, 8, 2, ++ REG_CLK_BYP_0, 15, ++ CLK_IS_CRITICAL); ++ ++static const struct clk_parent_data clk_pwm_parents[] = { ++ { .hw = &clk_pwm_src.mux.common.hw }, ++}; ++ ++static CV1800_GATE(clk_pwm, clk_pwm_parents, ++ REG_CLK_EN_1, 8, ++ CLK_IS_CRITICAL); ++ ++/* C906 */ ++static const struct clk_parent_data clk_c906_0_parents[] = { ++ { .index = 0 }, ++ { .hw = &clk_tpll.common.hw }, ++ { .hw = &clk_a0pll.common.hw }, ++ { .hw = &clk_mipimpll.common.hw }, ++ { .hw = &clk_mpll.common.hw }, ++ { .hw = &clk_fpll.common.hw }, ++}; ++static const struct clk_parent_data clk_c906_1_parents[] = { ++ { .index = 0 }, ++ { .hw = &clk_tpll.common.hw }, ++ { .hw = &clk_a0pll.common.hw }, ++ { .hw = &clk_disppll.common.hw }, ++ { .hw = &clk_mpll.common.hw }, ++ { .hw = &clk_fpll.common.hw }, ++}; ++ ++static const s8 clk_c906_parent2sel[] = { ++ -1, /* osc */ ++ 0, /* mux 0: clk_tpll(c906_0), clk_tpll(c906_1) */ ++ 0, /* mux 0: clk_a0pll(c906_0), clk_a0pll(c906_1) */ ++ 0, /* mux 0: clk_mipimpll(c906_0), clk_disppll(c906_1) */ ++ 0, /* mux 0: clk_mpll(c906_0), clk_mpll(c906_1) */ ++ 1 /* mux 1: clk_fpll(c906_0), clk_fpll(c906_1) */ ++}; ++ ++static const u8 clk_c906_sel2parent[2][4] = { ++ [0] = { ++ 1, ++ 2, ++ 3, ++ 4 ++ }, ++ [1] = { ++ 5, ++ 5, ++ 5, ++ 5 ++ }, ++}; ++ ++static CV1800_MMUX(clk_c906_0, clk_c906_0_parents, ++ REG_CLK_EN_4, 13, ++ REG_DIV_CLK_C906_0_0, 16, 4, 1, CV1800_DIV_FLAG, ++ REG_DIV_CLK_C906_0_1, 16, 4, 2, CV1800_DIV_FLAG, ++ REG_DIV_CLK_C906_0_0, 8, 2, ++ REG_DIV_CLK_C906_0_1, 8, 2, ++ REG_CLK_BYP_1, 6, ++ REG_CLK_SEL_0, 23, ++ clk_c906_parent2sel, ++ clk_c906_sel2parent[0], clk_c906_sel2parent[1], ++ CLK_IS_CRITICAL | CLK_GET_RATE_NOCACHE); ++static CV1800_MMUX(clk_c906_1, clk_c906_1_parents, ++ REG_CLK_EN_4, 14, ++ REG_DIV_CLK_C906_1_0, 16, 4, 2, CV1800_DIV_FLAG, ++ REG_DIV_CLK_C906_1_1, 16, 4, 3, CV1800_DIV_FLAG, ++ REG_DIV_CLK_C906_1_0, 8, 2, ++ REG_DIV_CLK_C906_1_1, 8, 2, ++ REG_CLK_BYP_1, 7, ++ REG_CLK_SEL_0, 24, ++ clk_c906_parent2sel, ++ clk_c906_sel2parent[0], clk_c906_sel2parent[1], ++ CLK_IS_CRITICAL | CLK_GET_RATE_NOCACHE); ++ ++/* A53 */ ++static CV1800_BYPASS_DIV(clk_cpu_axi0, clk_axi4_parents, ++ REG_CLK_EN_0, 1, ++ REG_DIV_CLK_CPU_AXI0, 16, 4, 3, CV1800_DIV_FLAG, ++ REG_CLK_BYP_0, 1, ++ CLK_IS_CRITICAL); ++static CV1800_BYPASS_DIV(clk_cpu_gic, clk_bypass_fpll_parents, ++ REG_CLK_EN_0, 2, ++ REG_DIV_CLK_CPU_GIC, 16, 4, 5, CV1800_DIV_FLAG, ++ REG_CLK_BYP_0, 2, ++ CLK_IS_CRITICAL); ++static CV1800_GATE(clk_xtal_ap, osc_parents, ++ REG_CLK_EN_0, 3, ++ CLK_IS_CRITICAL); ++ ++static const struct clk_parent_data clk_a53_parents[] = { ++ { .index = 0 }, ++ { .hw = &clk_tpll.common.hw }, ++ { .hw = &clk_a0pll.common.hw }, ++ { .hw = &clk_mipimpll.common.hw }, ++ { .hw = &clk_mpll.common.hw }, ++ { .hw = &clk_fpll.common.hw }, ++}; ++ ++static const s8 clk_a53_parent2sel[] = { ++ -1, /* osc */ ++ 0, /* mux 0: clk_tpll */ ++ 0, /* mux 0: clk_a0pll */ ++ 0, /* mux 0: clk_mipimpll */ ++ 0, /* mux 0: clk_mpll */ ++ 1 /* mux 1: clk_fpll */ ++}; ++ ++static const u8 clk_a53_sel2parent[2][4] = { ++ [0] = { ++ 1, ++ 2, ++ 3, ++ 4 ++ }, ++ [1] = { ++ 5, ++ 5, ++ 5, ++ 5 ++ }, ++}; ++ ++/* ++ * Clock for A53 cpu in the CV18XX/SG200X series. ++ * For CV180X and CV181X series, this clock is not used, but can not ++ * be set to bypass mode, or the SoC will hang. ++ */ ++static CV1800_MMUX(clk_a53, clk_a53_parents, ++ REG_CLK_EN_0, 0, ++ REG_DIV_CLK_A53_0, 16, 4, 1, CV1800_DIV_FLAG, ++ REG_DIV_CLK_A53_1, 16, 4, 2, CV1800_DIV_FLAG, ++ REG_DIV_CLK_A53_0, 8, 2, ++ REG_DIV_CLK_A53_1, 8, 2, ++ REG_CLK_BYP_0, 0, ++ REG_CLK_SEL_0, 0, ++ clk_a53_parent2sel, ++ clk_a53_sel2parent[0], clk_a53_sel2parent[1], ++ CLK_IS_CRITICAL | CLK_GET_RATE_NOCACHE); ++ ++static struct clk_hw_onecell_data cv1800_hw_clks = { ++ .num = CV1800_CLK_MAX, ++ .hws = { ++ [CLK_MPLL] = &clk_mpll.common.hw, ++ [CLK_TPLL] = &clk_tpll.common.hw, ++ [CLK_FPLL] = &clk_fpll.common.hw, ++ [CLK_MIPIMPLL] = &clk_mipimpll.common.hw, ++ [CLK_A0PLL] = &clk_a0pll.common.hw, ++ [CLK_DISPPLL] = &clk_disppll.common.hw, ++ [CLK_CAM0PLL] = &clk_cam0pll.common.hw, ++ [CLK_CAM1PLL] = &clk_cam1pll.common.hw, ++ ++ [CLK_MIPIMPLL_D3] = &clk_mipimpll_d3.common.hw, ++ [CLK_CAM0PLL_D2] = &clk_cam0pll_d2.common.hw, ++ [CLK_CAM0PLL_D3] = &clk_cam0pll_d3.common.hw, ++ ++ [CLK_TPU] = &clk_tpu.mux.common.hw, ++ [CLK_TPU_FAB] = &clk_tpu_fab.common.hw, ++ [CLK_AHB_ROM] = &clk_ahb_rom.common.hw, ++ [CLK_DDR_AXI_REG] = &clk_ddr_axi_reg.common.hw, ++ [CLK_RTC_25M] = &clk_rtc_25m.common.hw, ++ [CLK_SRC_RTC_SYS_0] = &clk_src_rtc_sys_0.div.common.hw, ++ [CLK_TEMPSEN] = &clk_tempsen.common.hw, ++ [CLK_SARADC] = &clk_saradc.common.hw, ++ [CLK_EFUSE] = &clk_efuse.common.hw, ++ [CLK_APB_EFUSE] = &clk_apb_efuse.common.hw, ++ [CLK_DEBUG] = &clk_debug.common.hw, ++ [CLK_AP_DEBUG] = &clk_ap_debug.div.common.hw, ++ [CLK_XTAL_MISC] = &clk_xtal_misc.common.hw, ++ [CLK_AXI4_EMMC] = &clk_axi4_emmc.common.hw, ++ [CLK_EMMC] = &clk_emmc.mux.common.hw, ++ [CLK_EMMC_100K] = &clk_emmc_100k.common.hw, ++ [CLK_AXI4_SD0] = &clk_axi4_sd0.common.hw, ++ [CLK_SD0] = &clk_sd0.mux.common.hw, ++ [CLK_SD0_100K] = &clk_sd0_100k.common.hw, ++ [CLK_AXI4_SD1] = &clk_axi4_sd1.common.hw, ++ [CLK_SD1] = &clk_sd1.mux.common.hw, ++ [CLK_SD1_100K] = &clk_sd1_100k.common.hw, ++ [CLK_SPI_NAND] = &clk_spi_nand.mux.common.hw, ++ [CLK_ETH0_500M] = &clk_eth0_500m.div.common.hw, ++ [CLK_AXI4_ETH0] = &clk_axi4_eth0.common.hw, ++ [CLK_ETH1_500M] = &clk_eth1_500m.div.common.hw, ++ [CLK_AXI4_ETH1] = &clk_axi4_eth1.common.hw, ++ [CLK_APB_GPIO] = &clk_apb_gpio.common.hw, ++ [CLK_APB_GPIO_INTR] = &clk_apb_gpio_intr.common.hw, ++ [CLK_GPIO_DB] = &clk_gpio_db.common.hw, ++ [CLK_AHB_SF] = &clk_ahb_sf.common.hw, ++ [CLK_AHB_SF1] = &clk_ahb_sf1.common.hw, ++ [CLK_A24M] = &clk_a24m.common.hw, ++ [CLK_AUDSRC] = &clk_audsrc.mux.common.hw, ++ [CLK_APB_AUDSRC] = &clk_apb_audsrc.common.hw, ++ [CLK_SDMA_AXI] = &clk_sdma_axi.common.hw, ++ [CLK_SDMA_AUD0] = &clk_sdma_aud0.mux.common.hw, ++ [CLK_SDMA_AUD1] = &clk_sdma_aud1.mux.common.hw, ++ [CLK_SDMA_AUD2] = &clk_sdma_aud2.mux.common.hw, ++ [CLK_SDMA_AUD3] = &clk_sdma_aud3.mux.common.hw, ++ [CLK_I2C] = &clk_i2c.div.common.hw, ++ [CLK_APB_I2C] = &clk_apb_i2c.common.hw, ++ [CLK_APB_I2C0] = &clk_apb_i2c0.common.hw, ++ [CLK_APB_I2C1] = &clk_apb_i2c1.common.hw, ++ [CLK_APB_I2C2] = &clk_apb_i2c2.common.hw, ++ [CLK_APB_I2C3] = &clk_apb_i2c3.common.hw, ++ [CLK_APB_I2C4] = &clk_apb_i2c4.common.hw, ++ [CLK_APB_WDT] = &clk_apb_wdt.common.hw, ++ [CLK_PWM_SRC] = &clk_pwm_src.mux.common.hw, ++ [CLK_PWM] = &clk_pwm.common.hw, ++ [CLK_SPI] = &clk_spi.div.common.hw, ++ [CLK_APB_SPI0] = &clk_apb_spi0.common.hw, ++ [CLK_APB_SPI1] = &clk_apb_spi1.common.hw, ++ [CLK_APB_SPI2] = &clk_apb_spi2.common.hw, ++ [CLK_APB_SPI3] = &clk_apb_spi3.common.hw, ++ [CLK_1M] = &clk_1m.common.hw, ++ [CLK_CAM0_200] = &clk_cam0_200.mux.common.hw, ++ [CLK_PM] = &clk_pm.common.hw, ++ [CLK_TIMER0] = &clk_timer0.common.hw, ++ [CLK_TIMER1] = &clk_timer1.common.hw, ++ [CLK_TIMER2] = &clk_timer2.common.hw, ++ [CLK_TIMER3] = &clk_timer3.common.hw, ++ [CLK_TIMER4] = &clk_timer4.common.hw, ++ [CLK_TIMER5] = &clk_timer5.common.hw, ++ [CLK_TIMER6] = &clk_timer6.common.hw, ++ [CLK_TIMER7] = &clk_timer7.common.hw, ++ [CLK_UART0] = &clk_uart0.common.hw, ++ [CLK_APB_UART0] = &clk_apb_uart0.common.hw, ++ [CLK_UART1] = &clk_uart1.common.hw, ++ [CLK_APB_UART1] = &clk_apb_uart1.common.hw, ++ [CLK_UART2] = &clk_uart2.common.hw, ++ [CLK_APB_UART2] = &clk_apb_uart2.common.hw, ++ [CLK_UART3] = &clk_uart3.common.hw, ++ [CLK_APB_UART3] = &clk_apb_uart3.common.hw, ++ [CLK_UART4] = &clk_uart4.common.hw, ++ [CLK_APB_UART4] = &clk_apb_uart4.common.hw, ++ [CLK_APB_I2S0] = &clk_apb_i2s0.common.hw, ++ [CLK_APB_I2S1] = &clk_apb_i2s1.common.hw, ++ [CLK_APB_I2S2] = &clk_apb_i2s2.common.hw, ++ [CLK_APB_I2S3] = &clk_apb_i2s3.common.hw, ++ [CLK_AXI4_USB] = &clk_axi4_usb.common.hw, ++ [CLK_APB_USB] = &clk_apb_usb.common.hw, ++ [CLK_USB_125M] = &clk_usb_125m.div.common.hw, ++ [CLK_USB_33K] = &clk_usb_33k.common.hw, ++ [CLK_USB_12M] = &clk_usb_12m.div.common.hw, ++ [CLK_AXI4] = &clk_axi4.mux.common.hw, ++ [CLK_AXI6] = &clk_axi6.div.common.hw, ++ [CLK_DSI_ESC] = &clk_dsi_esc.div.common.hw, ++ [CLK_AXI_VIP] = &clk_axi_vip.mux.common.hw, ++ [CLK_SRC_VIP_SYS_0] = &clk_src_vip_sys_0.mux.common.hw, ++ [CLK_SRC_VIP_SYS_1] = &clk_src_vip_sys_1.mux.common.hw, ++ [CLK_SRC_VIP_SYS_2] = &clk_src_vip_sys_2.mux.common.hw, ++ [CLK_SRC_VIP_SYS_3] = &clk_src_vip_sys_3.mux.common.hw, ++ [CLK_SRC_VIP_SYS_4] = &clk_src_vip_sys_4.mux.common.hw, ++ [CLK_CSI_BE_VIP] = &clk_csi_be_vip.common.hw, ++ [CLK_CSI_MAC0_VIP] = &clk_csi_mac0_vip.common.hw, ++ [CLK_CSI_MAC1_VIP] = &clk_csi_mac1_vip.common.hw, ++ [CLK_CSI_MAC2_VIP] = &clk_csi_mac2_vip.common.hw, ++ [CLK_CSI0_RX_VIP] = &clk_csi0_rx_vip.common.hw, ++ [CLK_CSI1_RX_VIP] = &clk_csi1_rx_vip.common.hw, ++ [CLK_ISP_TOP_VIP] = &clk_isp_top_vip.common.hw, ++ [CLK_IMG_D_VIP] = &clk_img_d_vip.common.hw, ++ [CLK_IMG_V_VIP] = &clk_img_v_vip.common.hw, ++ [CLK_SC_TOP_VIP] = &clk_sc_top_vip.common.hw, ++ [CLK_SC_D_VIP] = &clk_sc_d_vip.common.hw, ++ [CLK_SC_V1_VIP] = &clk_sc_v1_vip.common.hw, ++ [CLK_SC_V2_VIP] = &clk_sc_v2_vip.common.hw, ++ [CLK_SC_V3_VIP] = &clk_sc_v3_vip.common.hw, ++ [CLK_DWA_VIP] = &clk_dwa_vip.common.hw, ++ [CLK_BT_VIP] = &clk_bt_vip.common.hw, ++ [CLK_DISP_VIP] = &clk_disp_vip.common.hw, ++ [CLK_DSI_MAC_VIP] = &clk_dsi_mac_vip.common.hw, ++ [CLK_LVDS0_VIP] = &clk_lvds0_vip.common.hw, ++ [CLK_LVDS1_VIP] = &clk_lvds1_vip.common.hw, ++ [CLK_PAD_VI_VIP] = &clk_pad_vi_vip.common.hw, ++ [CLK_PAD_VI1_VIP] = &clk_pad_vi1_vip.common.hw, ++ [CLK_PAD_VI2_VIP] = &clk_pad_vi2_vip.common.hw, ++ [CLK_CFG_REG_VIP] = &clk_cfg_reg_vip.common.hw, ++ [CLK_VIP_IP0] = &clk_vip_ip0.common.hw, ++ [CLK_VIP_IP1] = &clk_vip_ip1.common.hw, ++ [CLK_VIP_IP2] = &clk_vip_ip2.common.hw, ++ [CLK_VIP_IP3] = &clk_vip_ip3.common.hw, ++ [CLK_IVE_VIP] = &clk_ive_vip.common.hw, ++ [CLK_RAW_VIP] = &clk_raw_vip.common.hw, ++ [CLK_OSDC_VIP] = &clk_osdc_vip.common.hw, ++ [CLK_CAM0_VIP] = &clk_cam0_vip.common.hw, ++ [CLK_AXI_VIDEO_CODEC] = &clk_axi_video_codec.mux.common.hw, ++ [CLK_VC_SRC0] = &clk_vc_src0.mux.common.hw, ++ [CLK_VC_SRC1] = &clk_vc_src1.div.common.hw, ++ [CLK_VC_SRC2] = &clk_vc_src2.div.common.hw, ++ [CLK_H264C] = &clk_h264c.common.hw, ++ [CLK_APB_H264C] = &clk_apb_h264c.common.hw, ++ [CLK_H265C] = &clk_h265c.common.hw, ++ [CLK_APB_H265C] = &clk_apb_h265c.common.hw, ++ [CLK_JPEG] = &clk_jpeg.common.hw, ++ [CLK_APB_JPEG] = &clk_apb_jpeg.common.hw, ++ [CLK_CAM0] = &clk_cam0.common.hw, ++ [CLK_CAM1] = &clk_cam1.common.hw, ++ [CLK_WGN] = &clk_wgn.common.hw, ++ [CLK_WGN0] = &clk_wgn0.common.hw, ++ [CLK_WGN1] = &clk_wgn1.common.hw, ++ [CLK_WGN2] = &clk_wgn2.common.hw, ++ [CLK_KEYSCAN] = &clk_keyscan.common.hw, ++ [CLK_CFG_REG_VC] = &clk_cfg_reg_vc.common.hw, ++ [CLK_C906_0] = &clk_c906_0.common.hw, ++ [CLK_C906_1] = &clk_c906_1.common.hw, ++ [CLK_A53] = &clk_a53.common.hw, ++ [CLK_CPU_AXI0] = &clk_cpu_axi0.div.common.hw, ++ [CLK_CPU_GIC] = &clk_cpu_gic.div.common.hw, ++ [CLK_XTAL_AP] = &clk_xtal_ap.common.hw, ++ }, ++}; ++ ++static void cv18xx_clk_disable_auto_pd(void __iomem *base) ++{ ++ static const u16 CV1800_PD_CLK[] = { ++ REG_MIPIMPLL_CLK_CSR, ++ REG_A0PLL_CLK_CSR, ++ REG_DISPPLL_CLK_CSR, ++ REG_CAM0PLL_CLK_CSR, ++ REG_CAM1PLL_CLK_CSR, ++ }; ++ ++ u32 val; ++ int i; ++ ++ /* disable auto power down */ ++ for (i = 0; i < ARRAY_SIZE(CV1800_PD_CLK); i++) { ++ u32 reg = CV1800_PD_CLK[i]; ++ ++ val = readl(base + reg); ++ val |= GENMASK(12, 9); ++ val &= ~BIT(8); ++ writel(val, base + reg); ++ } ++} ++ ++static void cv18xx_clk_disable_a53(void __iomem *base) ++{ ++ u32 val = readl(base + REG_CLK_BYP_0); ++ ++ /* Set bypass clock for clk_a53 */ ++ val |= BIT(0); ++ ++ /* Set bypass clock for clk_cpu_axi0 */ ++ val |= BIT(1); ++ ++ /* Set bypass clock for clk_cpu_gic */ ++ val |= BIT(2); ++ ++ writel(val, base + REG_CLK_BYP_0); ++} ++ ++static int cv1800_pre_init(struct device *dev, void __iomem *base, ++ struct cv1800_clk_ctrl *ctrl, ++ const struct cv1800_clk_desc *desc) ++{ ++ u32 val = readl(base + REG_CLK_EN_2); ++ ++ /* disable unsupported clk_disp_src_vip */ ++ val &= ~BIT(7); ++ ++ writel(val, base + REG_CLK_EN_2); ++ ++ cv18xx_clk_disable_a53(base); ++ cv18xx_clk_disable_auto_pd(base); ++ ++ return 0; ++} ++ ++static const struct cv1800_clk_desc cv1800_desc = { ++ .clks_data = &cv1800_hw_clks, ++ .pre_init = cv1800_pre_init, ++}; ++ ++static struct clk_hw_onecell_data cv1810_hw_clks = { ++ .num = CV1810_CLK_MAX, ++ .hws = { ++ [CLK_MPLL] = &clk_mpll.common.hw, ++ [CLK_TPLL] = &clk_tpll.common.hw, ++ [CLK_FPLL] = &clk_fpll.common.hw, ++ [CLK_MIPIMPLL] = &clk_mipimpll.common.hw, ++ [CLK_A0PLL] = &clk_a0pll.common.hw, ++ [CLK_DISPPLL] = &clk_disppll.common.hw, ++ [CLK_CAM0PLL] = &clk_cam0pll.common.hw, ++ [CLK_CAM1PLL] = &clk_cam1pll.common.hw, ++ ++ [CLK_MIPIMPLL_D3] = &clk_mipimpll_d3.common.hw, ++ [CLK_CAM0PLL_D2] = &clk_cam0pll_d2.common.hw, ++ [CLK_CAM0PLL_D3] = &clk_cam0pll_d3.common.hw, ++ ++ [CLK_TPU] = &clk_tpu.mux.common.hw, ++ [CLK_TPU_FAB] = &clk_tpu_fab.common.hw, ++ [CLK_AHB_ROM] = &clk_ahb_rom.common.hw, ++ [CLK_DDR_AXI_REG] = &clk_ddr_axi_reg.common.hw, ++ [CLK_RTC_25M] = &clk_rtc_25m.common.hw, ++ [CLK_SRC_RTC_SYS_0] = &clk_src_rtc_sys_0.div.common.hw, ++ [CLK_TEMPSEN] = &clk_tempsen.common.hw, ++ [CLK_SARADC] = &clk_saradc.common.hw, ++ [CLK_EFUSE] = &clk_efuse.common.hw, ++ [CLK_APB_EFUSE] = &clk_apb_efuse.common.hw, ++ [CLK_DEBUG] = &clk_debug.common.hw, ++ [CLK_AP_DEBUG] = &clk_ap_debug.div.common.hw, ++ [CLK_XTAL_MISC] = &clk_xtal_misc.common.hw, ++ [CLK_AXI4_EMMC] = &clk_axi4_emmc.common.hw, ++ [CLK_EMMC] = &clk_emmc.mux.common.hw, ++ [CLK_EMMC_100K] = &clk_emmc_100k.common.hw, ++ [CLK_AXI4_SD0] = &clk_axi4_sd0.common.hw, ++ [CLK_SD0] = &clk_sd0.mux.common.hw, ++ [CLK_SD0_100K] = &clk_sd0_100k.common.hw, ++ [CLK_AXI4_SD1] = &clk_axi4_sd1.common.hw, ++ [CLK_SD1] = &clk_sd1.mux.common.hw, ++ [CLK_SD1_100K] = &clk_sd1_100k.common.hw, ++ [CLK_SPI_NAND] = &clk_spi_nand.mux.common.hw, ++ [CLK_ETH0_500M] = &clk_eth0_500m.div.common.hw, ++ [CLK_AXI4_ETH0] = &clk_axi4_eth0.common.hw, ++ [CLK_ETH1_500M] = &clk_eth1_500m.div.common.hw, ++ [CLK_AXI4_ETH1] = &clk_axi4_eth1.common.hw, ++ [CLK_APB_GPIO] = &clk_apb_gpio.common.hw, ++ [CLK_APB_GPIO_INTR] = &clk_apb_gpio_intr.common.hw, ++ [CLK_GPIO_DB] = &clk_gpio_db.common.hw, ++ [CLK_AHB_SF] = &clk_ahb_sf.common.hw, ++ [CLK_AHB_SF1] = &clk_ahb_sf1.common.hw, ++ [CLK_A24M] = &clk_a24m.common.hw, ++ [CLK_AUDSRC] = &clk_audsrc.mux.common.hw, ++ [CLK_APB_AUDSRC] = &clk_apb_audsrc.common.hw, ++ [CLK_SDMA_AXI] = &clk_sdma_axi.common.hw, ++ [CLK_SDMA_AUD0] = &clk_sdma_aud0.mux.common.hw, ++ [CLK_SDMA_AUD1] = &clk_sdma_aud1.mux.common.hw, ++ [CLK_SDMA_AUD2] = &clk_sdma_aud2.mux.common.hw, ++ [CLK_SDMA_AUD3] = &clk_sdma_aud3.mux.common.hw, ++ [CLK_I2C] = &clk_i2c.div.common.hw, ++ [CLK_APB_I2C] = &clk_apb_i2c.common.hw, ++ [CLK_APB_I2C0] = &clk_apb_i2c0.common.hw, ++ [CLK_APB_I2C1] = &clk_apb_i2c1.common.hw, ++ [CLK_APB_I2C2] = &clk_apb_i2c2.common.hw, ++ [CLK_APB_I2C3] = &clk_apb_i2c3.common.hw, ++ [CLK_APB_I2C4] = &clk_apb_i2c4.common.hw, ++ [CLK_APB_WDT] = &clk_apb_wdt.common.hw, ++ [CLK_PWM_SRC] = &clk_pwm_src.mux.common.hw, ++ [CLK_PWM] = &clk_pwm.common.hw, ++ [CLK_SPI] = &clk_spi.div.common.hw, ++ [CLK_APB_SPI0] = &clk_apb_spi0.common.hw, ++ [CLK_APB_SPI1] = &clk_apb_spi1.common.hw, ++ [CLK_APB_SPI2] = &clk_apb_spi2.common.hw, ++ [CLK_APB_SPI3] = &clk_apb_spi3.common.hw, ++ [CLK_1M] = &clk_1m.common.hw, ++ [CLK_CAM0_200] = &clk_cam0_200.mux.common.hw, ++ [CLK_PM] = &clk_pm.common.hw, ++ [CLK_TIMER0] = &clk_timer0.common.hw, ++ [CLK_TIMER1] = &clk_timer1.common.hw, ++ [CLK_TIMER2] = &clk_timer2.common.hw, ++ [CLK_TIMER3] = &clk_timer3.common.hw, ++ [CLK_TIMER4] = &clk_timer4.common.hw, ++ [CLK_TIMER5] = &clk_timer5.common.hw, ++ [CLK_TIMER6] = &clk_timer6.common.hw, ++ [CLK_TIMER7] = &clk_timer7.common.hw, ++ [CLK_UART0] = &clk_uart0.common.hw, ++ [CLK_APB_UART0] = &clk_apb_uart0.common.hw, ++ [CLK_UART1] = &clk_uart1.common.hw, ++ [CLK_APB_UART1] = &clk_apb_uart1.common.hw, ++ [CLK_UART2] = &clk_uart2.common.hw, ++ [CLK_APB_UART2] = &clk_apb_uart2.common.hw, ++ [CLK_UART3] = &clk_uart3.common.hw, ++ [CLK_APB_UART3] = &clk_apb_uart3.common.hw, ++ [CLK_UART4] = &clk_uart4.common.hw, ++ [CLK_APB_UART4] = &clk_apb_uart4.common.hw, ++ [CLK_APB_I2S0] = &clk_apb_i2s0.common.hw, ++ [CLK_APB_I2S1] = &clk_apb_i2s1.common.hw, ++ [CLK_APB_I2S2] = &clk_apb_i2s2.common.hw, ++ [CLK_APB_I2S3] = &clk_apb_i2s3.common.hw, ++ [CLK_AXI4_USB] = &clk_axi4_usb.common.hw, ++ [CLK_APB_USB] = &clk_apb_usb.common.hw, ++ [CLK_USB_125M] = &clk_usb_125m.div.common.hw, ++ [CLK_USB_33K] = &clk_usb_33k.common.hw, ++ [CLK_USB_12M] = &clk_usb_12m.div.common.hw, ++ [CLK_AXI4] = &clk_axi4.mux.common.hw, ++ [CLK_AXI6] = &clk_axi6.div.common.hw, ++ [CLK_DSI_ESC] = &clk_dsi_esc.div.common.hw, ++ [CLK_AXI_VIP] = &clk_axi_vip.mux.common.hw, ++ [CLK_SRC_VIP_SYS_0] = &clk_src_vip_sys_0.mux.common.hw, ++ [CLK_SRC_VIP_SYS_1] = &clk_src_vip_sys_1.mux.common.hw, ++ [CLK_SRC_VIP_SYS_2] = &clk_src_vip_sys_2.mux.common.hw, ++ [CLK_SRC_VIP_SYS_3] = &clk_src_vip_sys_3.mux.common.hw, ++ [CLK_SRC_VIP_SYS_4] = &clk_src_vip_sys_4.mux.common.hw, ++ [CLK_CSI_BE_VIP] = &clk_csi_be_vip.common.hw, ++ [CLK_CSI_MAC0_VIP] = &clk_csi_mac0_vip.common.hw, ++ [CLK_CSI_MAC1_VIP] = &clk_csi_mac1_vip.common.hw, ++ [CLK_CSI_MAC2_VIP] = &clk_csi_mac2_vip.common.hw, ++ [CLK_CSI0_RX_VIP] = &clk_csi0_rx_vip.common.hw, ++ [CLK_CSI1_RX_VIP] = &clk_csi1_rx_vip.common.hw, ++ [CLK_ISP_TOP_VIP] = &clk_isp_top_vip.common.hw, ++ [CLK_IMG_D_VIP] = &clk_img_d_vip.common.hw, ++ [CLK_IMG_V_VIP] = &clk_img_v_vip.common.hw, ++ [CLK_SC_TOP_VIP] = &clk_sc_top_vip.common.hw, ++ [CLK_SC_D_VIP] = &clk_sc_d_vip.common.hw, ++ [CLK_SC_V1_VIP] = &clk_sc_v1_vip.common.hw, ++ [CLK_SC_V2_VIP] = &clk_sc_v2_vip.common.hw, ++ [CLK_SC_V3_VIP] = &clk_sc_v3_vip.common.hw, ++ [CLK_DWA_VIP] = &clk_dwa_vip.common.hw, ++ [CLK_BT_VIP] = &clk_bt_vip.common.hw, ++ [CLK_DISP_VIP] = &clk_disp_vip.common.hw, ++ [CLK_DSI_MAC_VIP] = &clk_dsi_mac_vip.common.hw, ++ [CLK_LVDS0_VIP] = &clk_lvds0_vip.common.hw, ++ [CLK_LVDS1_VIP] = &clk_lvds1_vip.common.hw, ++ [CLK_PAD_VI_VIP] = &clk_pad_vi_vip.common.hw, ++ [CLK_PAD_VI1_VIP] = &clk_pad_vi1_vip.common.hw, ++ [CLK_PAD_VI2_VIP] = &clk_pad_vi2_vip.common.hw, ++ [CLK_CFG_REG_VIP] = &clk_cfg_reg_vip.common.hw, ++ [CLK_VIP_IP0] = &clk_vip_ip0.common.hw, ++ [CLK_VIP_IP1] = &clk_vip_ip1.common.hw, ++ [CLK_VIP_IP2] = &clk_vip_ip2.common.hw, ++ [CLK_VIP_IP3] = &clk_vip_ip3.common.hw, ++ [CLK_IVE_VIP] = &clk_ive_vip.common.hw, ++ [CLK_RAW_VIP] = &clk_raw_vip.common.hw, ++ [CLK_OSDC_VIP] = &clk_osdc_vip.common.hw, ++ [CLK_CAM0_VIP] = &clk_cam0_vip.common.hw, ++ [CLK_AXI_VIDEO_CODEC] = &clk_axi_video_codec.mux.common.hw, ++ [CLK_VC_SRC0] = &clk_vc_src0.mux.common.hw, ++ [CLK_VC_SRC1] = &clk_vc_src1.div.common.hw, ++ [CLK_VC_SRC2] = &clk_vc_src2.div.common.hw, ++ [CLK_H264C] = &clk_h264c.common.hw, ++ [CLK_APB_H264C] = &clk_apb_h264c.common.hw, ++ [CLK_H265C] = &clk_h265c.common.hw, ++ [CLK_APB_H265C] = &clk_apb_h265c.common.hw, ++ [CLK_JPEG] = &clk_jpeg.common.hw, ++ [CLK_APB_JPEG] = &clk_apb_jpeg.common.hw, ++ [CLK_CAM0] = &clk_cam0.common.hw, ++ [CLK_CAM1] = &clk_cam1.common.hw, ++ [CLK_WGN] = &clk_wgn.common.hw, ++ [CLK_WGN0] = &clk_wgn0.common.hw, ++ [CLK_WGN1] = &clk_wgn1.common.hw, ++ [CLK_WGN2] = &clk_wgn2.common.hw, ++ [CLK_KEYSCAN] = &clk_keyscan.common.hw, ++ [CLK_CFG_REG_VC] = &clk_cfg_reg_vc.common.hw, ++ [CLK_C906_0] = &clk_c906_0.common.hw, ++ [CLK_C906_1] = &clk_c906_1.common.hw, ++ [CLK_A53] = &clk_a53.common.hw, ++ [CLK_CPU_AXI0] = &clk_cpu_axi0.div.common.hw, ++ [CLK_CPU_GIC] = &clk_cpu_gic.div.common.hw, ++ [CLK_XTAL_AP] = &clk_xtal_ap.common.hw, ++ [CLK_DISP_SRC_VIP] = &clk_disp_src_vip.div.common.hw, ++ }, ++}; ++ ++static int cv1810_pre_init(struct device *dev, void __iomem *base, ++ struct cv1800_clk_ctrl *ctrl, ++ const struct cv1800_clk_desc *desc) ++{ ++ cv18xx_clk_disable_a53(base); ++ cv18xx_clk_disable_auto_pd(base); ++ ++ return 0; ++} ++ ++static const struct cv1800_clk_desc cv1810_desc = { ++ .clks_data = &cv1810_hw_clks, ++ .pre_init = cv1810_pre_init, ++}; ++ ++static int sg2000_pre_init(struct device *dev, void __iomem *base, ++ struct cv1800_clk_ctrl *ctrl, ++ const struct cv1800_clk_desc *desc) ++{ ++ cv18xx_clk_disable_auto_pd(base); ++ ++ return 0; ++} ++ ++static const struct cv1800_clk_desc sg2000_desc = { ++ .clks_data = &cv1810_hw_clks, ++ .pre_init = sg2000_pre_init, ++}; ++ ++static int cv1800_clk_init_ctrl(struct device *dev, void __iomem *reg, ++ struct cv1800_clk_ctrl *ctrl, ++ const struct cv1800_clk_desc *desc) ++{ ++ int i, ret; ++ ++ ctrl->desc = desc; ++ spin_lock_init(&ctrl->lock); ++ ++ for (i = 0; i < desc->clks_data->num; i++) { ++ struct clk_hw *hw = desc->clks_data->hws[i]; ++ struct cv1800_clk_common *common; ++ const char *name; ++ ++ if (!hw) ++ continue; ++ ++ name = hw->init->name; ++ ++ common = hw_to_cv1800_clk_common(hw); ++ common->base = reg; ++ common->lock = &ctrl->lock; ++ ++ ret = devm_clk_hw_register(dev, hw); ++ if (ret) { ++ dev_err(dev, "Couldn't register clock %d - %s\n", ++ i, name); ++ return ret; ++ } ++ } ++ ++ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, ++ desc->clks_data); ++ ++ return ret; ++} ++ ++static int cv1800_clk_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ void __iomem *reg; ++ int ret; ++ const struct cv1800_clk_desc *desc; ++ struct cv1800_clk_ctrl *ctrl; ++ ++ reg = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(reg)) ++ return PTR_ERR(reg); ++ ++ desc = device_get_match_data(dev); ++ if (!desc) { ++ dev_err(dev, "no match data for platform\n"); ++ return -EINVAL; ++ } ++ ++ ctrl = devm_kmalloc(dev, sizeof(*ctrl), GFP_KERNEL); ++ if (!ctrl) ++ return -ENOMEM; ++ ++ if (desc->pre_init) { ++ ret = desc->pre_init(dev, reg, ctrl, desc); ++ if (ret) ++ return ret; ++ } ++ ++ ret = cv1800_clk_init_ctrl(dev, reg, ctrl, desc); ++ ++ return ret; ++} ++ ++static const struct of_device_id cv1800_clk_ids[] = { ++ { .compatible = "sophgo,cv1800-clk", .data = &cv1800_desc }, ++ { .compatible = "sophgo,cv1810-clk", .data = &cv1810_desc }, ++ { .compatible = "sophgo,sg2000-clk", .data = &sg2000_desc }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, cv1800_clk_ids); ++ ++static struct platform_driver cv1800_clk_driver = { ++ .probe = cv1800_clk_probe, ++ .driver = { ++ .name = "cv1800-clk", ++ .suppress_bind_attrs = true, ++ .of_match_table = cv1800_clk_ids, ++ }, ++}; ++module_platform_driver(cv1800_clk_driver); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/clk/sophgo/clk-cv1800.h b/drivers/clk/sophgo/clk-cv1800.h +new file mode 100644 +index 000000000000..1e7107b5d05e +--- /dev/null ++++ b/drivers/clk/sophgo/clk-cv1800.h +@@ -0,0 +1,123 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2023 Inochi Amaoto ++ */ ++ ++#ifndef _CLK_SOPHGO_CV1800_H_ ++#define _CLK_SOPHGO_CV1800_H_ ++ ++#include ++ ++#define CV1800_CLK_MAX (CLK_XTAL_AP + 1) ++#define CV1810_CLK_MAX (CLK_DISP_SRC_VIP + 1) ++ ++#define REG_PLL_G2_CTRL 0x800 ++#define REG_PLL_G2_STATUS 0x804 ++#define REG_MIPIMPLL_CSR 0x808 ++#define REG_A0PLL_CSR 0x80C ++#define REG_DISPPLL_CSR 0x810 ++#define REG_CAM0PLL_CSR 0x814 ++#define REG_CAM1PLL_CSR 0x818 ++#define REG_PLL_G2_SSC_SYN_CTRL 0x840 ++#define REG_A0PLL_SSC_SYN_CTRL 0x850 ++#define REG_A0PLL_SSC_SYN_SET 0x854 ++#define REG_A0PLL_SSC_SYN_SPAN 0x858 ++#define REG_A0PLL_SSC_SYN_STEP 0x85C ++#define REG_DISPPLL_SSC_SYN_CTRL 0x860 ++#define REG_DISPPLL_SSC_SYN_SET 0x864 ++#define REG_DISPPLL_SSC_SYN_SPAN 0x868 ++#define REG_DISPPLL_SSC_SYN_STEP 0x86C ++#define REG_CAM0PLL_SSC_SYN_CTRL 0x870 ++#define REG_CAM0PLL_SSC_SYN_SET 0x874 ++#define REG_CAM0PLL_SSC_SYN_SPAN 0x878 ++#define REG_CAM0PLL_SSC_SYN_STEP 0x87C ++#define REG_CAM1PLL_SSC_SYN_CTRL 0x880 ++#define REG_CAM1PLL_SSC_SYN_SET 0x884 ++#define REG_CAM1PLL_SSC_SYN_SPAN 0x888 ++#define REG_CAM1PLL_SSC_SYN_STEP 0x88C ++#define REG_APLL_FRAC_DIV_CTRL 0x890 ++#define REG_APLL_FRAC_DIV_M 0x894 ++#define REG_APLL_FRAC_DIV_N 0x898 ++#define REG_MIPIMPLL_CLK_CSR 0x8A0 ++#define REG_A0PLL_CLK_CSR 0x8A4 ++#define REG_DISPPLL_CLK_CSR 0x8A8 ++#define REG_CAM0PLL_CLK_CSR 0x8AC ++#define REG_CAM1PLL_CLK_CSR 0x8B0 ++#define REG_CLK_CAM0_SRC_DIV 0x8C0 ++#define REG_CLK_CAM1_SRC_DIV 0x8C4 ++ ++/* top_pll_g6 */ ++#define REG_PLL_G6_CTRL 0x900 ++#define REG_PLL_G6_STATUS 0x904 ++#define REG_MPLL_CSR 0x908 ++#define REG_TPLL_CSR 0x90C ++#define REG_FPLL_CSR 0x910 ++#define REG_PLL_G6_SSC_SYN_CTRL 0x940 ++#define REG_DPLL_SSC_SYN_CTRL 0x950 ++#define REG_DPLL_SSC_SYN_SET 0x954 ++#define REG_DPLL_SSC_SYN_SPAN 0x958 ++#define REG_DPLL_SSC_SYN_STEP 0x95C ++#define REG_MPLL_SSC_SYN_CTRL 0x960 ++#define REG_MPLL_SSC_SYN_SET 0x964 ++#define REG_MPLL_SSC_SYN_SPAN 0x968 ++#define REG_MPLL_SSC_SYN_STEP 0x96C ++#define REG_TPLL_SSC_SYN_CTRL 0x970 ++#define REG_TPLL_SSC_SYN_SET 0x974 ++#define REG_TPLL_SSC_SYN_SPAN 0x978 ++#define REG_TPLL_SSC_SYN_STEP 0x97C ++ ++/* clkgen */ ++#define REG_CLK_EN_0 0x000 ++#define REG_CLK_EN_1 0x004 ++#define REG_CLK_EN_2 0x008 ++#define REG_CLK_EN_3 0x00C ++#define REG_CLK_EN_4 0x010 ++#define REG_CLK_SEL_0 0x020 ++#define REG_CLK_BYP_0 0x030 ++#define REG_CLK_BYP_1 0x034 ++ ++#define REG_DIV_CLK_A53_0 0x040 ++#define REG_DIV_CLK_A53_1 0x044 ++#define REG_DIV_CLK_CPU_AXI0 0x048 ++#define REG_DIV_CLK_CPU_GIC 0x050 ++#define REG_DIV_CLK_TPU 0x054 ++#define REG_DIV_CLK_EMMC 0x064 ++#define REG_DIV_CLK_EMMC_100K 0x06C ++#define REG_DIV_CLK_SD0 0x070 ++#define REG_DIV_CLK_SD0_100K 0x078 ++#define REG_DIV_CLK_SD1 0x07C ++#define REG_DIV_CLK_SD1_100K 0x084 ++#define REG_DIV_CLK_SPI_NAND 0x088 ++#define REG_DIV_CLK_ETH0_500M 0x08C ++#define REG_DIV_CLK_ETH1_500M 0x090 ++#define REG_DIV_CLK_GPIO_DB 0x094 ++#define REG_DIV_CLK_SDMA_AUD0 0x098 ++#define REG_DIV_CLK_SDMA_AUD1 0x09C ++#define REG_DIV_CLK_SDMA_AUD2 0x0A0 ++#define REG_DIV_CLK_SDMA_AUD3 0x0A4 ++#define REG_DIV_CLK_CAM0_200 0x0A8 ++#define REG_DIV_CLK_AXI4 0x0B8 ++#define REG_DIV_CLK_AXI6 0x0BC ++#define REG_DIV_CLK_DSI_ESC 0x0C4 ++#define REG_DIV_CLK_AXI_VIP 0x0C8 ++#define REG_DIV_CLK_SRC_VIP_SYS_0 0x0D0 ++#define REG_DIV_CLK_SRC_VIP_SYS_1 0x0D8 ++#define REG_DIV_CLK_DISP_SRC_VIP 0x0E0 ++#define REG_DIV_CLK_AXI_VIDEO_CODEC 0x0E4 ++#define REG_DIV_CLK_VC_SRC0 0x0EC ++#define REG_DIV_CLK_1M 0x0FC ++#define REG_DIV_CLK_SPI 0x100 ++#define REG_DIV_CLK_I2C 0x104 ++#define REG_DIV_CLK_SRC_VIP_SYS_2 0x110 ++#define REG_DIV_CLK_AUDSRC 0x118 ++#define REG_DIV_CLK_PWM_SRC_0 0x120 ++#define REG_DIV_CLK_AP_DEBUG 0x128 ++#define REG_DIV_CLK_RTCSYS_SRC_0 0x12C ++#define REG_DIV_CLK_C906_0_0 0x130 ++#define REG_DIV_CLK_C906_0_1 0x134 ++#define REG_DIV_CLK_C906_1_0 0x138 ++#define REG_DIV_CLK_C906_1_1 0x13C ++#define REG_DIV_CLK_SRC_VIP_SYS_3 0x140 ++#define REG_DIV_CLK_SRC_VIP_SYS_4 0x144 ++ ++#endif /* _CLK_SOPHGO_CV1800_H_ */ +diff --git a/drivers/clk/sophgo/clk-cv18xx-common.c b/drivers/clk/sophgo/clk-cv18xx-common.c +new file mode 100644 +index 000000000000..cbcdd88f0e23 +--- /dev/null ++++ b/drivers/clk/sophgo/clk-cv18xx-common.c +@@ -0,0 +1,66 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2023 Inochi Amaoto ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "clk-cv18xx-common.h" ++ ++int cv1800_clk_setbit(struct cv1800_clk_common *common, ++ struct cv1800_clk_regbit *field) ++{ ++ u32 mask = BIT(field->shift); ++ u32 value; ++ unsigned long flags; ++ ++ spin_lock_irqsave(common->lock, flags); ++ ++ value = readl(common->base + field->reg); ++ writel(value | mask, common->base + field->reg); ++ ++ spin_unlock_irqrestore(common->lock, flags); ++ ++ return 0; ++} ++ ++int cv1800_clk_clearbit(struct cv1800_clk_common *common, ++ struct cv1800_clk_regbit *field) ++{ ++ u32 mask = BIT(field->shift); ++ u32 value; ++ unsigned long flags; ++ ++ spin_lock_irqsave(common->lock, flags); ++ ++ value = readl(common->base + field->reg); ++ writel(value & ~mask, common->base + field->reg); ++ ++ spin_unlock_irqrestore(common->lock, flags); ++ ++ return 0; ++} ++ ++int cv1800_clk_checkbit(struct cv1800_clk_common *common, ++ struct cv1800_clk_regbit *field) ++{ ++ return readl(common->base + field->reg) & BIT(field->shift); ++} ++ ++#define PLL_LOCK_TIMEOUT_US (200 * 1000) ++ ++void cv1800_clk_wait_for_lock(struct cv1800_clk_common *common, ++ u32 reg, u32 lock) ++{ ++ void __iomem *addr = common->base + reg; ++ u32 regval; ++ ++ if (!lock) ++ return; ++ ++ WARN_ON(readl_relaxed_poll_timeout(addr, regval, regval & lock, ++ 100, PLL_LOCK_TIMEOUT_US)); ++} +diff --git a/drivers/clk/sophgo/clk-cv18xx-common.h b/drivers/clk/sophgo/clk-cv18xx-common.h +new file mode 100644 +index 000000000000..2bfda02b2064 +--- /dev/null ++++ b/drivers/clk/sophgo/clk-cv18xx-common.h +@@ -0,0 +1,81 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2023 Inochi Amaoto ++ */ ++ ++#ifndef _CLK_SOPHGO_CV18XX_IP_H_ ++#define _CLK_SOPHGO_CV18XX_IP_H_ ++ ++#include ++#include ++#include ++ ++struct cv1800_clk_common { ++ void __iomem *base; ++ spinlock_t *lock; ++ struct clk_hw hw; ++ unsigned long features; ++}; ++ ++#define CV1800_CLK_COMMON(_name, _parents, _op, _flags) \ ++ { \ ++ .hw.init = CLK_HW_INIT_PARENTS_DATA(_name, _parents, \ ++ _op, _flags), \ ++ } ++ ++static inline struct cv1800_clk_common * ++hw_to_cv1800_clk_common(struct clk_hw *hw) ++{ ++ return container_of(hw, struct cv1800_clk_common, hw); ++} ++ ++struct cv1800_clk_regbit { ++ u16 reg; ++ s8 shift; ++}; ++ ++struct cv1800_clk_regfield { ++ u16 reg; ++ u8 shift; ++ u8 width; ++ s16 initval; ++ unsigned long flags; ++}; ++ ++#define CV1800_CLK_BIT(_reg, _shift) \ ++ { \ ++ .reg = _reg, \ ++ .shift = _shift, \ ++ } ++ ++#define CV1800_CLK_REG(_reg, _shift, _width, _initval, _flags) \ ++ { \ ++ .reg = _reg, \ ++ .shift = _shift, \ ++ .width = _width, \ ++ .initval = _initval, \ ++ .flags = _flags, \ ++ } ++ ++#define cv1800_clk_regfield_genmask(_reg) \ ++ GENMASK((_reg)->shift + (_reg)->width - 1, (_reg)->shift) ++#define cv1800_clk_regfield_get(_val, _reg) \ ++ (((_val) >> (_reg)->shift) & GENMASK((_reg)->width - 1, 0)) ++#define cv1800_clk_regfield_set(_val, _new, _reg) \ ++ (((_val) & ~cv1800_clk_regfield_genmask((_reg))) | \ ++ (((_new) & GENMASK((_reg)->width - 1, 0)) << (_reg)->shift)) ++ ++#define _CV1800_SET_FIELD(_reg, _val, _field) \ ++ (((_reg) & ~(_field)) | FIELD_PREP((_field), (_val))) ++ ++int cv1800_clk_setbit(struct cv1800_clk_common *common, ++ struct cv1800_clk_regbit *field); ++int cv1800_clk_clearbit(struct cv1800_clk_common *common, ++ struct cv1800_clk_regbit *field); ++int cv1800_clk_checkbit(struct cv1800_clk_common *common, ++ struct cv1800_clk_regbit *field); ++ ++void cv1800_clk_wait_for_lock(struct cv1800_clk_common *common, ++ u32 reg, u32 lock); ++ ++#endif // _CLK_SOPHGO_CV18XX_IP_H_ +diff --git a/drivers/clk/sophgo/clk-cv18xx-ip.c b/drivers/clk/sophgo/clk-cv18xx-ip.c +new file mode 100644 +index 000000000000..805f561725ae +--- /dev/null ++++ b/drivers/clk/sophgo/clk-cv18xx-ip.c +@@ -0,0 +1,887 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2023 Inochi Amaoto ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "clk-cv18xx-ip.h" ++ ++/* GATE */ ++static inline struct cv1800_clk_gate *hw_to_cv1800_clk_gate(struct clk_hw *hw) ++{ ++ struct cv1800_clk_common *common = hw_to_cv1800_clk_common(hw); ++ ++ return container_of(common, struct cv1800_clk_gate, common); ++} ++ ++static int gate_enable(struct clk_hw *hw) ++{ ++ struct cv1800_clk_gate *gate = hw_to_cv1800_clk_gate(hw); ++ ++ return cv1800_clk_setbit(&gate->common, &gate->gate); ++} ++ ++static void gate_disable(struct clk_hw *hw) ++{ ++ struct cv1800_clk_gate *gate = hw_to_cv1800_clk_gate(hw); ++ ++ cv1800_clk_clearbit(&gate->common, &gate->gate); ++} ++ ++static int gate_is_enabled(struct clk_hw *hw) ++{ ++ struct cv1800_clk_gate *gate = hw_to_cv1800_clk_gate(hw); ++ ++ return cv1800_clk_checkbit(&gate->common, &gate->gate); ++} ++ ++static unsigned long gate_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ return parent_rate; ++} ++ ++static long gate_round_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *parent_rate) ++{ ++ return *parent_rate; ++} ++ ++static int gate_set_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ return 0; ++} ++ ++const struct clk_ops cv1800_clk_gate_ops = { ++ .disable = gate_disable, ++ .enable = gate_enable, ++ .is_enabled = gate_is_enabled, ++ ++ .recalc_rate = gate_recalc_rate, ++ .round_rate = gate_round_rate, ++ .set_rate = gate_set_rate, ++}; ++ ++/* DIV */ ++#define _DIV_EN_CLK_DIV_FACTOR_FIELD BIT(3) ++ ++#define DIV_GET_EN_CLK_DIV_FACTOR(_reg) \ ++ FIELD_GET(_DIV_EN_CLK_DIV_FACTOR_FIELD, _reg) ++ ++#define DIV_SET_EN_DIV_FACTOR(_reg) \ ++ _CV1800_SET_FIELD(_reg, 1, _DIV_EN_CLK_DIV_FACTOR_FIELD) ++ ++static inline struct cv1800_clk_div *hw_to_cv1800_clk_div(struct clk_hw *hw) ++{ ++ struct cv1800_clk_common *common = hw_to_cv1800_clk_common(hw); ++ ++ return container_of(common, struct cv1800_clk_div, common); ++} ++ ++static int div_enable(struct clk_hw *hw) ++{ ++ struct cv1800_clk_div *div = hw_to_cv1800_clk_div(hw); ++ ++ return cv1800_clk_setbit(&div->common, &div->gate); ++} ++ ++static void div_disable(struct clk_hw *hw) ++{ ++ struct cv1800_clk_div *div = hw_to_cv1800_clk_div(hw); ++ ++ cv1800_clk_clearbit(&div->common, &div->gate); ++} ++ ++static int div_is_enabled(struct clk_hw *hw) ++{ ++ struct cv1800_clk_div *div = hw_to_cv1800_clk_div(hw); ++ ++ return cv1800_clk_checkbit(&div->common, &div->gate); ++} ++ ++static int div_helper_set_rate(struct cv1800_clk_common *common, ++ struct cv1800_clk_regfield *div, ++ unsigned long val) ++{ ++ unsigned long flags; ++ u32 reg; ++ ++ if (div->width == 0) ++ return 0; ++ ++ spin_lock_irqsave(common->lock, flags); ++ ++ reg = readl(common->base + div->reg); ++ reg = cv1800_clk_regfield_set(reg, val, div); ++ if (div->initval > 0) ++ reg = DIV_SET_EN_DIV_FACTOR(reg); ++ ++ writel(reg, common->base + div->reg); ++ ++ spin_unlock_irqrestore(common->lock, flags); ++ ++ return 0; ++} ++ ++static u32 div_helper_get_clockdiv(struct cv1800_clk_common *common, ++ struct cv1800_clk_regfield *div) ++{ ++ u32 clockdiv = 1; ++ u32 reg; ++ ++ if (!div || div->initval < 0 || (div->width == 0 && div->initval <= 0)) ++ return 1; ++ ++ if (div->width == 0 && div->initval > 0) ++ return div->initval; ++ ++ reg = readl(common->base + div->reg); ++ ++ if (div->initval == 0 || DIV_GET_EN_CLK_DIV_FACTOR(reg)) ++ clockdiv = cv1800_clk_regfield_get(reg, div); ++ else if (div->initval > 0) ++ clockdiv = div->initval; ++ ++ return clockdiv; ++} ++ ++static u32 div_helper_round_rate(struct cv1800_clk_regfield *div, ++ struct clk_hw *hw, struct clk_hw *parent, ++ unsigned long rate, unsigned long *prate) ++{ ++ if (div->width == 0) { ++ if (div->initval <= 0) ++ return DIV_ROUND_UP_ULL(*prate, 1); ++ else ++ return DIV_ROUND_UP_ULL(*prate, div->initval); ++ } ++ ++ return divider_round_rate_parent(hw, parent, rate, prate, NULL, ++ div->width, div->flags); ++} ++ ++static long div_round_rate(struct clk_hw *parent, unsigned long *parent_rate, ++ unsigned long rate, int id, void *data) ++{ ++ struct cv1800_clk_div *div = data; ++ ++ return div_helper_round_rate(&div->div, &div->common.hw, parent, ++ rate, parent_rate); ++} ++ ++static bool div_is_better_rate(struct cv1800_clk_common *common, ++ unsigned long target, unsigned long now, ++ unsigned long best) ++{ ++ if (common->features & CLK_DIVIDER_ROUND_CLOSEST) ++ return abs_diff(target, now) < abs_diff(target, best); ++ ++ return now <= target && now > best; ++} ++ ++static int mux_helper_determine_rate(struct cv1800_clk_common *common, ++ struct clk_rate_request *req, ++ long (*round)(struct clk_hw *, ++ unsigned long *, ++ unsigned long, ++ int, ++ void *), ++ void *data) ++{ ++ unsigned long best_parent_rate = 0, best_rate = 0; ++ struct clk_hw *best_parent, *hw = &common->hw; ++ unsigned int i; ++ ++ if (clk_hw_get_flags(hw) & CLK_SET_RATE_NO_REPARENT) { ++ unsigned long adj_parent_rate; ++ ++ best_parent = clk_hw_get_parent(hw); ++ best_parent_rate = clk_hw_get_rate(best_parent); ++ ++ best_rate = round(best_parent, &adj_parent_rate, ++ req->rate, -1, data); ++ ++ goto find; ++ } ++ ++ for (i = 0; i < clk_hw_get_num_parents(hw); i++) { ++ unsigned long tmp_rate, parent_rate; ++ struct clk_hw *parent; ++ ++ parent = clk_hw_get_parent_by_index(hw, i); ++ if (!parent) ++ continue; ++ ++ parent_rate = clk_hw_get_rate(parent); ++ ++ tmp_rate = round(parent, &parent_rate, req->rate, i, data); ++ ++ if (tmp_rate == req->rate) { ++ best_parent = parent; ++ best_parent_rate = parent_rate; ++ best_rate = tmp_rate; ++ goto find; ++ } ++ ++ if (div_is_better_rate(common, req->rate, ++ tmp_rate, best_rate)) { ++ best_parent = parent; ++ best_parent_rate = parent_rate; ++ best_rate = tmp_rate; ++ } ++ } ++ ++ if (best_rate == 0) ++ return -EINVAL; ++ ++find: ++ req->best_parent_hw = best_parent; ++ req->best_parent_rate = best_parent_rate; ++ req->rate = best_rate; ++ return 0; ++} ++ ++static int div_determine_rate(struct clk_hw *hw, ++ struct clk_rate_request *req) ++{ ++ struct cv1800_clk_div *div = hw_to_cv1800_clk_div(hw); ++ ++ return mux_helper_determine_rate(&div->common, req, ++ div_round_rate, div); ++} ++ ++static unsigned long div_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct cv1800_clk_div *div = hw_to_cv1800_clk_div(hw); ++ unsigned long val; ++ ++ val = div_helper_get_clockdiv(&div->common, &div->div); ++ if (val == 0) ++ return 0; ++ ++ return divider_recalc_rate(hw, parent_rate, val, NULL, ++ div->div.flags, div->div.width); ++} ++ ++static int div_set_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ struct cv1800_clk_div *div = hw_to_cv1800_clk_div(hw); ++ unsigned long val; ++ ++ val = divider_get_val(rate, parent_rate, NULL, ++ div->div.width, div->div.flags); ++ ++ return div_helper_set_rate(&div->common, &div->div, val); ++} ++ ++const struct clk_ops cv1800_clk_div_ops = { ++ .disable = div_disable, ++ .enable = div_enable, ++ .is_enabled = div_is_enabled, ++ ++ .determine_rate = div_determine_rate, ++ .recalc_rate = div_recalc_rate, ++ .set_rate = div_set_rate, ++}; ++ ++static inline struct cv1800_clk_bypass_div * ++hw_to_cv1800_clk_bypass_div(struct clk_hw *hw) ++{ ++ struct cv1800_clk_div *div = hw_to_cv1800_clk_div(hw); ++ ++ return container_of(div, struct cv1800_clk_bypass_div, div); ++} ++ ++static long bypass_div_round_rate(struct clk_hw *parent, ++ unsigned long *parent_rate, ++ unsigned long rate, int id, void *data) ++{ ++ struct cv1800_clk_bypass_div *div = data; ++ ++ if (id == -1) { ++ if (cv1800_clk_checkbit(&div->div.common, &div->bypass)) ++ return *parent_rate; ++ else ++ return div_round_rate(parent, parent_rate, rate, ++ -1, &div->div); ++ } ++ ++ if (id == 0) ++ return *parent_rate; ++ ++ return div_round_rate(parent, parent_rate, rate, id - 1, &div->div); ++} ++ ++static int bypass_div_determine_rate(struct clk_hw *hw, ++ struct clk_rate_request *req) ++{ ++ struct cv1800_clk_bypass_div *div = hw_to_cv1800_clk_bypass_div(hw); ++ ++ return mux_helper_determine_rate(&div->div.common, req, ++ bypass_div_round_rate, div); ++} ++ ++static unsigned long bypass_div_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct cv1800_clk_bypass_div *div = hw_to_cv1800_clk_bypass_div(hw); ++ ++ if (cv1800_clk_checkbit(&div->div.common, &div->bypass)) ++ return parent_rate; ++ ++ return div_recalc_rate(hw, parent_rate); ++} ++ ++static int bypass_div_set_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ struct cv1800_clk_bypass_div *div = hw_to_cv1800_clk_bypass_div(hw); ++ ++ if (cv1800_clk_checkbit(&div->div.common, &div->bypass)) ++ return 0; ++ ++ return div_set_rate(hw, rate, parent_rate); ++} ++ ++static u8 bypass_div_get_parent(struct clk_hw *hw) ++{ ++ struct cv1800_clk_bypass_div *div = hw_to_cv1800_clk_bypass_div(hw); ++ ++ if (cv1800_clk_checkbit(&div->div.common, &div->bypass)) ++ return 0; ++ ++ return 1; ++} ++ ++static int bypass_div_set_parent(struct clk_hw *hw, u8 index) ++{ ++ struct cv1800_clk_bypass_div *div = hw_to_cv1800_clk_bypass_div(hw); ++ ++ if (index) ++ return cv1800_clk_clearbit(&div->div.common, &div->bypass); ++ ++ return cv1800_clk_setbit(&div->div.common, &div->bypass); ++} ++ ++const struct clk_ops cv1800_clk_bypass_div_ops = { ++ .disable = div_disable, ++ .enable = div_enable, ++ .is_enabled = div_is_enabled, ++ ++ .determine_rate = bypass_div_determine_rate, ++ .recalc_rate = bypass_div_recalc_rate, ++ .set_rate = bypass_div_set_rate, ++ ++ .set_parent = bypass_div_set_parent, ++ .get_parent = bypass_div_get_parent, ++}; ++ ++/* MUX */ ++static inline struct cv1800_clk_mux *hw_to_cv1800_clk_mux(struct clk_hw *hw) ++{ ++ struct cv1800_clk_common *common = hw_to_cv1800_clk_common(hw); ++ ++ return container_of(common, struct cv1800_clk_mux, common); ++} ++ ++static int mux_enable(struct clk_hw *hw) ++{ ++ struct cv1800_clk_mux *mux = hw_to_cv1800_clk_mux(hw); ++ ++ return cv1800_clk_setbit(&mux->common, &mux->gate); ++} ++ ++static void mux_disable(struct clk_hw *hw) ++{ ++ struct cv1800_clk_mux *mux = hw_to_cv1800_clk_mux(hw); ++ ++ cv1800_clk_clearbit(&mux->common, &mux->gate); ++} ++ ++static int mux_is_enabled(struct clk_hw *hw) ++{ ++ struct cv1800_clk_mux *mux = hw_to_cv1800_clk_mux(hw); ++ ++ return cv1800_clk_checkbit(&mux->common, &mux->gate); ++} ++ ++static long mux_round_rate(struct clk_hw *parent, unsigned long *parent_rate, ++ unsigned long rate, int id, void *data) ++{ ++ struct cv1800_clk_mux *mux = data; ++ ++ return div_helper_round_rate(&mux->div, &mux->common.hw, parent, ++ rate, parent_rate); ++} ++ ++static int mux_determine_rate(struct clk_hw *hw, ++ struct clk_rate_request *req) ++{ ++ struct cv1800_clk_mux *mux = hw_to_cv1800_clk_mux(hw); ++ ++ return mux_helper_determine_rate(&mux->common, req, ++ mux_round_rate, mux); ++} ++ ++static unsigned long mux_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct cv1800_clk_mux *mux = hw_to_cv1800_clk_mux(hw); ++ unsigned long val; ++ ++ val = div_helper_get_clockdiv(&mux->common, &mux->div); ++ if (val == 0) ++ return 0; ++ ++ return divider_recalc_rate(hw, parent_rate, val, NULL, ++ mux->div.flags, mux->div.width); ++} ++ ++static int mux_set_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ struct cv1800_clk_mux *mux = hw_to_cv1800_clk_mux(hw); ++ unsigned long val; ++ ++ val = divider_get_val(rate, parent_rate, NULL, ++ mux->div.width, mux->div.flags); ++ ++ return div_helper_set_rate(&mux->common, &mux->div, val); ++} ++ ++static u8 mux_get_parent(struct clk_hw *hw) ++{ ++ struct cv1800_clk_mux *mux = hw_to_cv1800_clk_mux(hw); ++ u32 reg = readl(mux->common.base + mux->mux.reg); ++ ++ return cv1800_clk_regfield_get(reg, &mux->mux); ++} ++ ++static int _mux_set_parent(struct cv1800_clk_mux *mux, u8 index) ++{ ++ u32 reg; ++ ++ reg = readl(mux->common.base + mux->mux.reg); ++ reg = cv1800_clk_regfield_set(reg, index, &mux->mux); ++ writel(reg, mux->common.base + mux->mux.reg); ++ ++ return 0; ++} ++ ++static int mux_set_parent(struct clk_hw *hw, u8 index) ++{ ++ struct cv1800_clk_mux *mux = hw_to_cv1800_clk_mux(hw); ++ unsigned long flags; ++ ++ spin_lock_irqsave(mux->common.lock, flags); ++ ++ _mux_set_parent(mux, index); ++ ++ spin_unlock_irqrestore(mux->common.lock, flags); ++ ++ return 0; ++} ++ ++const struct clk_ops cv1800_clk_mux_ops = { ++ .disable = mux_disable, ++ .enable = mux_enable, ++ .is_enabled = mux_is_enabled, ++ ++ .determine_rate = mux_determine_rate, ++ .recalc_rate = mux_recalc_rate, ++ .set_rate = mux_set_rate, ++ ++ .set_parent = mux_set_parent, ++ .get_parent = mux_get_parent, ++}; ++ ++static inline struct cv1800_clk_bypass_mux * ++hw_to_cv1800_clk_bypass_mux(struct clk_hw *hw) ++{ ++ struct cv1800_clk_mux *mux = hw_to_cv1800_clk_mux(hw); ++ ++ return container_of(mux, struct cv1800_clk_bypass_mux, mux); ++} ++ ++static long bypass_mux_round_rate(struct clk_hw *parent, ++ unsigned long *parent_rate, ++ unsigned long rate, int id, void *data) ++{ ++ struct cv1800_clk_bypass_mux *mux = data; ++ ++ if (id == -1) { ++ if (cv1800_clk_checkbit(&mux->mux.common, &mux->bypass)) ++ return *parent_rate; ++ else ++ return mux_round_rate(parent, parent_rate, rate, ++ -1, &mux->mux); ++ } ++ ++ if (id == 0) ++ return *parent_rate; ++ ++ return mux_round_rate(parent, parent_rate, rate, id - 1, &mux->mux); ++} ++ ++static int bypass_mux_determine_rate(struct clk_hw *hw, ++ struct clk_rate_request *req) ++{ ++ struct cv1800_clk_bypass_mux *mux = hw_to_cv1800_clk_bypass_mux(hw); ++ ++ return mux_helper_determine_rate(&mux->mux.common, req, ++ bypass_mux_round_rate, mux); ++} ++ ++static unsigned long bypass_mux_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct cv1800_clk_bypass_mux *mux = hw_to_cv1800_clk_bypass_mux(hw); ++ ++ if (cv1800_clk_checkbit(&mux->mux.common, &mux->bypass)) ++ return parent_rate; ++ ++ return mux_recalc_rate(hw, parent_rate); ++} ++ ++static int bypass_mux_set_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ struct cv1800_clk_bypass_mux *mux = hw_to_cv1800_clk_bypass_mux(hw); ++ ++ if (cv1800_clk_checkbit(&mux->mux.common, &mux->bypass)) ++ return 0; ++ ++ return mux_set_rate(hw, rate, parent_rate); ++} ++ ++static u8 bypass_mux_get_parent(struct clk_hw *hw) ++{ ++ struct cv1800_clk_bypass_mux *mux = hw_to_cv1800_clk_bypass_mux(hw); ++ ++ if (cv1800_clk_checkbit(&mux->mux.common, &mux->bypass)) ++ return 0; ++ ++ return mux_get_parent(hw) + 1; ++} ++ ++static int bypass_mux_set_parent(struct clk_hw *hw, u8 index) ++{ ++ struct cv1800_clk_bypass_mux *mux = hw_to_cv1800_clk_bypass_mux(hw); ++ ++ if (index == 0) ++ return cv1800_clk_setbit(&mux->mux.common, &mux->bypass); ++ ++ return cv1800_clk_clearbit(&mux->mux.common, &mux->bypass); ++} ++ ++const struct clk_ops cv1800_clk_bypass_mux_ops = { ++ .disable = mux_disable, ++ .enable = mux_enable, ++ .is_enabled = mux_is_enabled, ++ ++ .determine_rate = bypass_mux_determine_rate, ++ .recalc_rate = bypass_mux_recalc_rate, ++ .set_rate = bypass_mux_set_rate, ++ ++ .set_parent = bypass_mux_set_parent, ++ .get_parent = bypass_mux_get_parent, ++}; ++ ++/* MMUX */ ++static inline struct cv1800_clk_mmux *hw_to_cv1800_clk_mmux(struct clk_hw *hw) ++{ ++ struct cv1800_clk_common *common = hw_to_cv1800_clk_common(hw); ++ ++ return container_of(common, struct cv1800_clk_mmux, common); ++} ++ ++static u8 mmux_get_parent_id(struct cv1800_clk_mmux *mmux) ++{ ++ struct clk_hw *hw = &mmux->common.hw; ++ struct clk_hw *parent = clk_hw_get_parent(hw); ++ unsigned int i; ++ ++ for (i = 0; i < clk_hw_get_num_parents(hw); i++) { ++ if (parent == clk_hw_get_parent_by_index(hw, i)) ++ return i; ++ } ++ ++ unreachable(); ++} ++ ++static int mmux_enable(struct clk_hw *hw) ++{ ++ struct cv1800_clk_mmux *mmux = hw_to_cv1800_clk_mmux(hw); ++ ++ return cv1800_clk_setbit(&mmux->common, &mmux->gate); ++} ++ ++static void mmux_disable(struct clk_hw *hw) ++{ ++ struct cv1800_clk_mmux *mmux = hw_to_cv1800_clk_mmux(hw); ++ ++ cv1800_clk_clearbit(&mmux->common, &mmux->gate); ++} ++ ++static int mmux_is_enabled(struct clk_hw *hw) ++{ ++ struct cv1800_clk_mmux *mmux = hw_to_cv1800_clk_mmux(hw); ++ ++ return cv1800_clk_checkbit(&mmux->common, &mmux->gate); ++} ++ ++static long mmux_round_rate(struct clk_hw *parent, unsigned long *parent_rate, ++ unsigned long rate, int id, void *data) ++{ ++ struct cv1800_clk_mmux *mmux = data; ++ s8 div_id; ++ ++ if (id == -1) { ++ if (cv1800_clk_checkbit(&mmux->common, &mmux->bypass)) ++ return *parent_rate; ++ ++ id = mmux_get_parent_id(mmux); ++ } ++ ++ div_id = mmux->parent2sel[id]; ++ ++ if (div_id < 0) ++ return *parent_rate; ++ ++ return div_helper_round_rate(&mmux->div[div_id], ++ &mmux->common.hw, parent, ++ rate, parent_rate); ++} ++ ++static int mmux_determine_rate(struct clk_hw *hw, ++ struct clk_rate_request *req) ++{ ++ struct cv1800_clk_mmux *mmux = hw_to_cv1800_clk_mmux(hw); ++ ++ return mux_helper_determine_rate(&mmux->common, req, ++ mmux_round_rate, mmux); ++} ++ ++static unsigned long mmux_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct cv1800_clk_mmux *mmux = hw_to_cv1800_clk_mmux(hw); ++ unsigned long val; ++ struct cv1800_clk_regfield *div; ++ ++ if (cv1800_clk_checkbit(&mmux->common, &mmux->bypass)) ++ return parent_rate; ++ ++ if (cv1800_clk_checkbit(&mmux->common, &mmux->clk_sel)) ++ div = &mmux->div[0]; ++ else ++ div = &mmux->div[1]; ++ ++ val = div_helper_get_clockdiv(&mmux->common, div); ++ if (val == 0) ++ return 0; ++ ++ return divider_recalc_rate(hw, parent_rate, val, NULL, ++ div->flags, div->width); ++} ++ ++static int mmux_set_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ struct cv1800_clk_mmux *mmux = hw_to_cv1800_clk_mmux(hw); ++ struct cv1800_clk_regfield *div; ++ unsigned long val; ++ ++ if (cv1800_clk_checkbit(&mmux->common, &mmux->bypass)) ++ return parent_rate; ++ ++ if (cv1800_clk_checkbit(&mmux->common, &mmux->clk_sel)) ++ div = &mmux->div[0]; ++ else ++ div = &mmux->div[1]; ++ ++ val = divider_get_val(rate, parent_rate, NULL, ++ div->width, div->flags); ++ ++ return div_helper_set_rate(&mmux->common, div, val); ++} ++ ++static u8 mmux_get_parent(struct clk_hw *hw) ++{ ++ struct cv1800_clk_mmux *mmux = hw_to_cv1800_clk_mmux(hw); ++ struct cv1800_clk_regfield *mux; ++ u32 reg; ++ s8 clk_sel; ++ ++ if (cv1800_clk_checkbit(&mmux->common, &mmux->bypass)) ++ return 0; ++ ++ if (cv1800_clk_checkbit(&mmux->common, &mmux->clk_sel)) ++ clk_sel = 0; ++ else ++ clk_sel = 1; ++ mux = &mmux->mux[clk_sel]; ++ ++ reg = readl(mmux->common.base + mux->reg); ++ ++ return mmux->sel2parent[clk_sel][cv1800_clk_regfield_get(reg, mux)]; ++} ++ ++static int mmux_set_parent(struct clk_hw *hw, u8 index) ++{ ++ struct cv1800_clk_mmux *mmux = hw_to_cv1800_clk_mmux(hw); ++ struct cv1800_clk_regfield *mux; ++ unsigned long flags; ++ u32 reg; ++ s8 clk_sel = mmux->parent2sel[index]; ++ ++ if (index == 0 || clk_sel == -1) { ++ cv1800_clk_setbit(&mmux->common, &mmux->bypass); ++ goto release; ++ } ++ ++ cv1800_clk_clearbit(&mmux->common, &mmux->bypass); ++ ++ if (clk_sel) ++ cv1800_clk_clearbit(&mmux->common, &mmux->clk_sel); ++ else ++ cv1800_clk_setbit(&mmux->common, &mmux->clk_sel); ++ ++ spin_lock_irqsave(mmux->common.lock, flags); ++ ++ mux = &mmux->mux[clk_sel]; ++ reg = readl(mmux->common.base + mux->reg); ++ reg = cv1800_clk_regfield_set(reg, index, mux); ++ ++ writel(reg, mmux->common.base + mux->reg); ++ ++ spin_unlock_irqrestore(mmux->common.lock, flags); ++ ++release: ++ return 0; ++} ++ ++const struct clk_ops cv1800_clk_mmux_ops = { ++ .disable = mmux_disable, ++ .enable = mmux_enable, ++ .is_enabled = mmux_is_enabled, ++ ++ .determine_rate = mmux_determine_rate, ++ .recalc_rate = mmux_recalc_rate, ++ .set_rate = mmux_set_rate, ++ ++ .set_parent = mmux_set_parent, ++ .get_parent = mmux_get_parent, ++}; ++ ++/* AUDIO CLK */ ++static inline struct cv1800_clk_audio * ++hw_to_cv1800_clk_audio(struct clk_hw *hw) ++{ ++ struct cv1800_clk_common *common = hw_to_cv1800_clk_common(hw); ++ ++ return container_of(common, struct cv1800_clk_audio, common); ++} ++ ++static int aclk_enable(struct clk_hw *hw) ++{ ++ struct cv1800_clk_audio *aclk = hw_to_cv1800_clk_audio(hw); ++ ++ cv1800_clk_setbit(&aclk->common, &aclk->src_en); ++ return cv1800_clk_setbit(&aclk->common, &aclk->output_en); ++} ++ ++static void aclk_disable(struct clk_hw *hw) ++{ ++ struct cv1800_clk_audio *aclk = hw_to_cv1800_clk_audio(hw); ++ ++ cv1800_clk_clearbit(&aclk->common, &aclk->output_en); ++ cv1800_clk_clearbit(&aclk->common, &aclk->src_en); ++} ++ ++static int aclk_is_enabled(struct clk_hw *hw) ++{ ++ struct cv1800_clk_audio *aclk = hw_to_cv1800_clk_audio(hw); ++ ++ return cv1800_clk_checkbit(&aclk->common, &aclk->output_en); ++} ++ ++static int aclk_determine_rate(struct clk_hw *hw, ++ struct clk_rate_request *req) ++{ ++ struct cv1800_clk_audio *aclk = hw_to_cv1800_clk_audio(hw); ++ ++ req->rate = aclk->target_rate; ++ ++ return 0; ++} ++ ++static unsigned long aclk_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct cv1800_clk_audio *aclk = hw_to_cv1800_clk_audio(hw); ++ u64 rate = parent_rate; ++ u64 factor = 2; ++ u32 regval; ++ ++ if (!cv1800_clk_checkbit(&aclk->common, &aclk->div_en)) ++ return 0; ++ ++ regval = readl(aclk->common.base + aclk->m.reg); ++ factor *= cv1800_clk_regfield_get(regval, &aclk->m); ++ ++ regval = readl(aclk->common.base + aclk->n.reg); ++ rate *= cv1800_clk_regfield_get(regval, &aclk->n); ++ ++ return DIV64_U64_ROUND_UP(rate, factor); ++} ++ ++static void aclk_determine_mn(unsigned long parent_rate, unsigned long rate, ++ u32 *m, u32 *n) ++{ ++ u32 tm = parent_rate / 2; ++ u32 tn = rate; ++ u32 tcommon = gcd(tm, tn); ++ *m = tm / tcommon; ++ *n = tn / tcommon; ++} ++ ++static int aclk_set_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ struct cv1800_clk_audio *aclk = hw_to_cv1800_clk_audio(hw); ++ unsigned long flags; ++ u32 m, n; ++ ++ aclk_determine_mn(parent_rate, rate, ++ &m, &n); ++ ++ spin_lock_irqsave(aclk->common.lock, flags); ++ ++ writel(m, aclk->common.base + aclk->m.reg); ++ writel(n, aclk->common.base + aclk->n.reg); ++ ++ cv1800_clk_setbit(&aclk->common, &aclk->div_en); ++ cv1800_clk_setbit(&aclk->common, &aclk->div_up); ++ ++ spin_unlock_irqrestore(aclk->common.lock, flags); ++ ++ return 0; ++} ++ ++const struct clk_ops cv1800_clk_audio_ops = { ++ .disable = aclk_disable, ++ .enable = aclk_enable, ++ .is_enabled = aclk_is_enabled, ++ ++ .determine_rate = aclk_determine_rate, ++ .recalc_rate = aclk_recalc_rate, ++ .set_rate = aclk_set_rate, ++}; +diff --git a/drivers/clk/sophgo/clk-cv18xx-ip.h b/drivers/clk/sophgo/clk-cv18xx-ip.h +new file mode 100644 +index 000000000000..b37ba42bfde3 +--- /dev/null ++++ b/drivers/clk/sophgo/clk-cv18xx-ip.h +@@ -0,0 +1,261 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2023 Inochi Amaoto ++ */ ++ ++#ifndef _CLK_SOPHGO_CV1800_IP_H_ ++#define _CLK_SOPHGO_CV1800_IP_H_ ++ ++#include "clk-cv18xx-common.h" ++ ++struct cv1800_clk_gate { ++ struct cv1800_clk_common common; ++ struct cv1800_clk_regbit gate; ++}; ++ ++struct cv1800_clk_div_data { ++ u32 reg; ++ u32 mask; ++ u32 width; ++ u32 init; ++ u32 flags; ++}; ++ ++struct cv1800_clk_div { ++ struct cv1800_clk_common common; ++ struct cv1800_clk_regbit gate; ++ struct cv1800_clk_regfield div; ++}; ++ ++struct cv1800_clk_bypass_div { ++ struct cv1800_clk_div div; ++ struct cv1800_clk_regbit bypass; ++}; ++ ++struct cv1800_clk_mux { ++ struct cv1800_clk_common common; ++ struct cv1800_clk_regbit gate; ++ struct cv1800_clk_regfield div; ++ struct cv1800_clk_regfield mux; ++}; ++ ++struct cv1800_clk_bypass_mux { ++ struct cv1800_clk_mux mux; ++ struct cv1800_clk_regbit bypass; ++}; ++ ++struct cv1800_clk_mmux { ++ struct cv1800_clk_common common; ++ struct cv1800_clk_regbit gate; ++ struct cv1800_clk_regfield div[2]; ++ struct cv1800_clk_regfield mux[2]; ++ struct cv1800_clk_regbit bypass; ++ struct cv1800_clk_regbit clk_sel; ++ const s8 *parent2sel; ++ const u8 *sel2parent[2]; ++}; ++ ++struct cv1800_clk_audio { ++ struct cv1800_clk_common common; ++ struct cv1800_clk_regbit src_en; ++ struct cv1800_clk_regbit output_en; ++ struct cv1800_clk_regbit div_en; ++ struct cv1800_clk_regbit div_up; ++ struct cv1800_clk_regfield m; ++ struct cv1800_clk_regfield n; ++ u32 target_rate; ++}; ++ ++#define CV1800_GATE(_name, _parent, _gate_reg, _gate_shift, _flags) \ ++ struct cv1800_clk_gate _name = { \ ++ .common = CV1800_CLK_COMMON(#_name, _parent, \ ++ &cv1800_clk_gate_ops, \ ++ _flags), \ ++ .gate = CV1800_CLK_BIT(_gate_reg, _gate_shift), \ ++ } ++ ++#define _CV1800_DIV(_name, _parent, _gate_reg, _gate_shift, \ ++ _div_reg, _div_shift, _div_width, _div_init, \ ++ _div_flag, _ops, _flags) \ ++ { \ ++ .common = CV1800_CLK_COMMON(#_name, _parent, \ ++ _ops, _flags), \ ++ .gate = CV1800_CLK_BIT(_gate_reg, \ ++ _gate_shift), \ ++ .div = CV1800_CLK_REG(_div_reg, _div_shift, \ ++ _div_width, _div_init, \ ++ _div_flag), \ ++ } ++ ++#define _CV1800_FIXED_DIV_FLAG \ ++ (CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ROUND_CLOSEST) ++ ++#define _CV1800_FIXED_DIV(_name, _parent, _gate_reg, _gate_shift, \ ++ _fix_div, _ops, _flags) \ ++ { \ ++ .common = CV1800_CLK_COMMON(#_name, _parent, \ ++ _ops, _flags), \ ++ .gate = CV1800_CLK_BIT(_gate_reg, \ ++ _gate_shift), \ ++ .div = CV1800_CLK_REG(0, 0, 0, \ ++ _fix_div, \ ++ _CV1800_FIXED_DIV_FLAG),\ ++ } ++ ++#define CV1800_DIV(_name, _parent, _gate_reg, _gate_shift, \ ++ _div_reg, _div_shift, _div_width, _div_init, \ ++ _div_flag, _flags) \ ++ struct cv1800_clk_div _name = \ ++ _CV1800_DIV(_name, _parent, _gate_reg, _gate_shift, \ ++ _div_reg, _div_shift, _div_width, _div_init,\ ++ _div_flag, &cv1800_clk_div_ops, _flags) ++ ++#define CV1800_BYPASS_DIV(_name, _parent, _gate_reg, _gate_shift, \ ++ _div_reg, _div_shift, _div_width, _div_init, \ ++ _div_flag, _bypass_reg, _bypass_shift, _flags)\ ++ struct cv1800_clk_bypass_div _name = { \ ++ .div = _CV1800_DIV(_name, _parent, \ ++ _gate_reg, _gate_shift, \ ++ _div_reg, _div_shift, \ ++ _div_width, _div_init, _div_flag, \ ++ &cv1800_clk_bypass_div_ops, \ ++ _flags), \ ++ .bypass = CV1800_CLK_BIT(_bypass_reg, _bypass_shift), \ ++ } ++ ++#define CV1800_FIXED_DIV(_name, _parent, _gate_reg, _gate_shift, \ ++ _fix_div, _flags) \ ++ struct cv1800_clk_div _name = \ ++ _CV1800_FIXED_DIV(_name, _parent, \ ++ _gate_reg, _gate_shift, \ ++ _fix_div, \ ++ &cv1800_clk_div_ops, _flags) \ ++ ++#define CV1800_BYPASS_FIXED_DIV(_name, _parent, _gate_reg, _gate_shift, \ ++ _fix_div, _bypass_reg, _bypass_shift, \ ++ _flags) \ ++ struct cv1800_clk_bypass_div _name = { \ ++ .div = _CV1800_FIXED_DIV(_name, _parent, \ ++ _gate_reg, _gate_shift, \ ++ _fix_div, \ ++ &cv1800_clk_bypass_div_ops, \ ++ _flags), \ ++ .bypass = CV1800_CLK_BIT(_bypass_reg, _bypass_shift), \ ++ } ++ ++#define _CV1800_MUX(_name, _parent, _gate_reg, _gate_shift, \ ++ _div_reg, _div_shift, _div_width, _div_init, \ ++ _div_flag, \ ++ _mux_reg, _mux_shift, _mux_width, \ ++ _ops, _flags) \ ++ { \ ++ .common = CV1800_CLK_COMMON(#_name, _parent, \ ++ _ops, _flags), \ ++ .gate = CV1800_CLK_BIT(_gate_reg, \ ++ _gate_shift), \ ++ .div = CV1800_CLK_REG(_div_reg, _div_shift, \ ++ _div_width, _div_init, \ ++ _div_flag), \ ++ .mux = CV1800_CLK_REG(_mux_reg, _mux_shift, \ ++ _mux_width, 0, 0), \ ++ } ++ ++#define CV1800_MUX(_name, _parent, _gate_reg, _gate_shift, \ ++ _div_reg, _div_shift, _div_width, _div_init, \ ++ _div_flag, \ ++ _mux_reg, _mux_shift, _mux_width, _flags) \ ++ struct cv1800_clk_mux _name = \ ++ _CV1800_MUX(_name, _parent, _gate_reg, _gate_shift, \ ++ _div_reg, _div_shift, _div_width, _div_init,\ ++ _div_flag, _mux_reg, _mux_shift, _mux_width,\ ++ &cv1800_clk_mux_ops, _flags) ++ ++#define CV1800_BYPASS_MUX(_name, _parent, _gate_reg, _gate_shift, \ ++ _div_reg, _div_shift, _div_width, _div_init, \ ++ _div_flag, \ ++ _mux_reg, _mux_shift, _mux_width, \ ++ _bypass_reg, _bypass_shift, _flags) \ ++ struct cv1800_clk_bypass_mux _name = { \ ++ .mux = _CV1800_MUX(_name, _parent, \ ++ _gate_reg, _gate_shift, \ ++ _div_reg, _div_shift, _div_width, \ ++ _div_init, _div_flag, \ ++ _mux_reg, _mux_shift, _mux_width, \ ++ &cv1800_clk_bypass_mux_ops, \ ++ _flags), \ ++ .bypass = CV1800_CLK_BIT(_bypass_reg, _bypass_shift), \ ++ } ++ ++#define CV1800_MMUX(_name, _parent, _gate_reg, _gate_shift, \ ++ _div0_reg, _div0_shift, _div0_width, _div0_init, \ ++ _div0_flag, \ ++ _div1_reg, _div1_shift, _div1_width, _div1_init, \ ++ _div1_flag, \ ++ _mux0_reg, _mux0_shift, _mux0_width, \ ++ _mux1_reg, _mux1_shift, _mux1_width, \ ++ _bypass_reg, _bypass_shift, \ ++ _clk_sel_reg, _clk_sel_shift, \ ++ _parent2sel, _sel2parent0, _sel2parent1, _flags) \ ++ struct cv1800_clk_mmux _name = { \ ++ .common = CV1800_CLK_COMMON(#_name, _parent, \ ++ &cv1800_clk_mmux_ops,\ ++ _flags), \ ++ .gate = CV1800_CLK_BIT(_gate_reg, _gate_shift),\ ++ .div = { \ ++ CV1800_CLK_REG(_div0_reg, _div0_shift, \ ++ _div0_width, _div0_init, \ ++ _div0_flag), \ ++ CV1800_CLK_REG(_div1_reg, _div1_shift, \ ++ _div1_width, _div1_init, \ ++ _div1_flag), \ ++ }, \ ++ .mux = { \ ++ CV1800_CLK_REG(_mux0_reg, _mux0_shift, \ ++ _mux0_width, 0, 0), \ ++ CV1800_CLK_REG(_mux1_reg, _mux1_shift, \ ++ _mux1_width, 0, 0), \ ++ }, \ ++ .bypass = CV1800_CLK_BIT(_bypass_reg, \ ++ _bypass_shift), \ ++ .clk_sel = CV1800_CLK_BIT(_clk_sel_reg, \ ++ _clk_sel_shift), \ ++ .parent2sel = _parent2sel, \ ++ .sel2parent = { _sel2parent0, _sel2parent1 }, \ ++ } ++ ++#define CV1800_ACLK(_name, _parent, \ ++ _src_en_reg, _src_en_reg_shift, \ ++ _output_en_reg, _output_en_shift, \ ++ _div_en_reg, _div_en_reg_shift, \ ++ _div_up_reg, _div_up_reg_shift, \ ++ _m_reg, _m_shift, _m_width, _m_flag, \ ++ _n_reg, _n_shift, _n_width, _n_flag, \ ++ _target_rate, _flags) \ ++ struct cv1800_clk_audio _name = { \ ++ .common = CV1800_CLK_COMMON(#_name, _parent, \ ++ &cv1800_clk_audio_ops,\ ++ _flags), \ ++ .src_en = CV1800_CLK_BIT(_src_en_reg, \ ++ _src_en_reg_shift), \ ++ .output_en = CV1800_CLK_BIT(_output_en_reg, \ ++ _output_en_shift), \ ++ .div_en = CV1800_CLK_BIT(_div_en_reg, \ ++ _div_en_reg_shift), \ ++ .div_up = CV1800_CLK_BIT(_div_up_reg, \ ++ _div_up_reg_shift), \ ++ .m = CV1800_CLK_REG(_m_reg, _m_shift, \ ++ _m_width, 0, _m_flag), \ ++ .n = CV1800_CLK_REG(_n_reg, _n_shift, \ ++ _n_width, 0, _n_flag), \ ++ .target_rate = _target_rate, \ ++ } ++ ++extern const struct clk_ops cv1800_clk_gate_ops; ++extern const struct clk_ops cv1800_clk_div_ops; ++extern const struct clk_ops cv1800_clk_bypass_div_ops; ++extern const struct clk_ops cv1800_clk_mux_ops; ++extern const struct clk_ops cv1800_clk_bypass_mux_ops; ++extern const struct clk_ops cv1800_clk_mmux_ops; ++extern const struct clk_ops cv1800_clk_audio_ops; ++ ++#endif // _CLK_SOPHGO_CV1800_IP_H_ +diff --git a/drivers/clk/sophgo/clk-cv18xx-pll.c b/drivers/clk/sophgo/clk-cv18xx-pll.c +new file mode 100644 +index 000000000000..c546dad1791c +--- /dev/null ++++ b/drivers/clk/sophgo/clk-cv18xx-pll.c +@@ -0,0 +1,420 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2023 Inochi Amaoto ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "clk-cv18xx-pll.h" ++ ++static inline struct cv1800_clk_pll *hw_to_cv1800_clk_pll(struct clk_hw *hw) ++{ ++ struct cv1800_clk_common *common = hw_to_cv1800_clk_common(hw); ++ ++ return container_of(common, struct cv1800_clk_pll, common); ++} ++ ++static unsigned long ipll_calc_rate(unsigned long parent_rate, ++ unsigned long pre_div_sel, ++ unsigned long div_sel, ++ unsigned long post_div_sel) ++{ ++ uint64_t rate = parent_rate; ++ ++ rate *= div_sel; ++ do_div(rate, pre_div_sel * post_div_sel); ++ ++ return rate; ++} ++ ++static unsigned long ipll_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct cv1800_clk_pll *pll = hw_to_cv1800_clk_pll(hw); ++ u32 value; ++ ++ value = readl(pll->common.base + pll->pll_reg); ++ ++ return ipll_calc_rate(parent_rate, ++ PLL_GET_PRE_DIV_SEL(value), ++ PLL_GET_DIV_SEL(value), ++ PLL_GET_POST_DIV_SEL(value)); ++} ++ ++static int ipll_find_rate(const struct cv1800_clk_pll_limit *limit, ++ unsigned long prate, unsigned long *rate, ++ u32 *value) ++{ ++ unsigned long best_rate = 0; ++ unsigned long trate = *rate; ++ unsigned long pre_div_sel = 0, div_sel = 0, post_div_sel = 0; ++ unsigned long pre, div, post; ++ u32 detected = *value; ++ unsigned long tmp; ++ ++ for_each_pll_limit_range(pre, &limit->pre_div) { ++ for_each_pll_limit_range(div, &limit->div) { ++ for_each_pll_limit_range(post, &limit->post_div) { ++ tmp = ipll_calc_rate(prate, pre, div, post); ++ ++ if (tmp > trate) ++ continue; ++ ++ if ((trate - tmp) < (trate - best_rate)) { ++ best_rate = tmp; ++ pre_div_sel = pre; ++ div_sel = div; ++ post_div_sel = post; ++ } ++ } ++ } ++ } ++ ++ if (best_rate) { ++ detected = PLL_SET_PRE_DIV_SEL(detected, pre_div_sel); ++ detected = PLL_SET_POST_DIV_SEL(detected, post_div_sel); ++ detected = PLL_SET_DIV_SEL(detected, div_sel); ++ *value = detected; ++ *rate = best_rate; ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++ ++static int ipll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) ++{ ++ u32 val; ++ struct cv1800_clk_pll *pll = hw_to_cv1800_clk_pll(hw); ++ ++ return ipll_find_rate(pll->pll_limit, req->best_parent_rate, ++ &req->rate, &val); ++} ++ ++static void pll_get_mode_ctrl(unsigned long div_sel, ++ bool (*mode_ctrl_check)(unsigned long, ++ unsigned long, ++ unsigned long), ++ const struct cv1800_clk_pll_limit *limit, ++ u32 *value) ++{ ++ unsigned long ictrl = 0, mode = 0; ++ u32 detected = *value; ++ ++ for_each_pll_limit_range(mode, &limit->mode) { ++ for_each_pll_limit_range(ictrl, &limit->ictrl) { ++ if (mode_ctrl_check(div_sel, ictrl, mode)) { ++ detected = PLL_SET_SEL_MODE(detected, mode); ++ detected = PLL_SET_ICTRL(detected, ictrl); ++ *value = detected; ++ return; ++ } ++ } ++ } ++} ++ ++static bool ipll_check_mode_ctrl_restrict(unsigned long div_sel, ++ unsigned long ictrl, ++ unsigned long mode) ++{ ++ unsigned long left_rest = 20 * div_sel; ++ unsigned long right_rest = 35 * div_sel; ++ unsigned long test = 184 * (1 + mode) * (1 + ictrl) / 2; ++ ++ return test > left_rest && test <= right_rest; ++} ++ ++static int ipll_set_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ u32 regval, detected = 0; ++ unsigned long flags; ++ struct cv1800_clk_pll *pll = hw_to_cv1800_clk_pll(hw); ++ ++ ipll_find_rate(pll->pll_limit, parent_rate, &rate, &detected); ++ pll_get_mode_ctrl(PLL_GET_DIV_SEL(detected), ++ ipll_check_mode_ctrl_restrict, ++ pll->pll_limit, &detected); ++ ++ spin_lock_irqsave(pll->common.lock, flags); ++ ++ regval = readl(pll->common.base + pll->pll_reg); ++ regval = PLL_COPY_REG(regval, detected); ++ ++ writel(regval, pll->common.base + pll->pll_reg); ++ ++ spin_unlock_irqrestore(pll->common.lock, flags); ++ ++ cv1800_clk_wait_for_lock(&pll->common, pll->pll_status.reg, ++ BIT(pll->pll_status.shift)); ++ ++ return 0; ++} ++ ++static int pll_enable(struct clk_hw *hw) ++{ ++ struct cv1800_clk_pll *pll = hw_to_cv1800_clk_pll(hw); ++ ++ return cv1800_clk_clearbit(&pll->common, &pll->pll_pwd); ++} ++ ++static void pll_disable(struct clk_hw *hw) ++{ ++ struct cv1800_clk_pll *pll = hw_to_cv1800_clk_pll(hw); ++ ++ cv1800_clk_setbit(&pll->common, &pll->pll_pwd); ++} ++ ++static int pll_is_enable(struct clk_hw *hw) ++{ ++ struct cv1800_clk_pll *pll = hw_to_cv1800_clk_pll(hw); ++ ++ return cv1800_clk_checkbit(&pll->common, &pll->pll_pwd) == 0; ++} ++ ++const struct clk_ops cv1800_clk_ipll_ops = { ++ .disable = pll_disable, ++ .enable = pll_enable, ++ .is_enabled = pll_is_enable, ++ ++ .recalc_rate = ipll_recalc_rate, ++ .determine_rate = ipll_determine_rate, ++ .set_rate = ipll_set_rate, ++}; ++ ++#define PLL_SYN_FACTOR_DOT_POS 26 ++#define PLL_SYN_FACTOR_MINIMUM ((4 << PLL_SYN_FACTOR_DOT_POS) + 1) ++ ++static bool fpll_is_factional_mode(struct cv1800_clk_pll *pll) ++{ ++ return cv1800_clk_checkbit(&pll->common, &pll->pll_syn->en); ++} ++ ++static unsigned long fpll_calc_rate(unsigned long parent_rate, ++ unsigned long pre_div_sel, ++ unsigned long div_sel, ++ unsigned long post_div_sel, ++ unsigned long ssc_syn_set, ++ bool is_full_parent) ++{ ++ u64 dividend = parent_rate * div_sel; ++ u64 factor = ssc_syn_set * pre_div_sel * post_div_sel; ++ unsigned long rate; ++ ++ dividend <<= PLL_SYN_FACTOR_DOT_POS - 1; ++ rate = dividend / factor; ++ dividend %= factor; ++ ++ if (is_full_parent) { ++ dividend <<= 1; ++ rate <<= 1; ++ } ++ ++ rate += DIV64_U64_ROUND_CLOSEST(dividend, factor); ++ ++ return rate; ++} ++ ++static unsigned long fpll_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct cv1800_clk_pll *pll = hw_to_cv1800_clk_pll(hw); ++ u32 value; ++ bool clk_full; ++ u32 syn_set; ++ ++ if (!fpll_is_factional_mode(pll)) ++ return ipll_recalc_rate(hw, parent_rate); ++ ++ syn_set = readl(pll->common.base + pll->pll_syn->set); ++ ++ if (syn_set == 0) ++ return 0; ++ ++ clk_full = cv1800_clk_checkbit(&pll->common, ++ &pll->pll_syn->clk_half); ++ ++ value = readl(pll->common.base + pll->pll_reg); ++ ++ return fpll_calc_rate(parent_rate, ++ PLL_GET_PRE_DIV_SEL(value), ++ PLL_GET_DIV_SEL(value), ++ PLL_GET_POST_DIV_SEL(value), ++ syn_set, clk_full); ++} ++ ++static unsigned long fpll_find_synthesizer(unsigned long parent, ++ unsigned long rate, ++ unsigned long pre_div, ++ unsigned long div, ++ unsigned long post_div, ++ bool is_full_parent, ++ u32 *ssc_syn_set) ++{ ++ u32 test_max = U32_MAX, test_min = PLL_SYN_FACTOR_MINIMUM; ++ unsigned long trate; ++ ++ while (test_min < test_max) { ++ u32 tssc = (test_max + test_min) / 2; ++ ++ trate = fpll_calc_rate(parent, pre_div, div, post_div, ++ tssc, is_full_parent); ++ ++ if (trate == rate) { ++ test_min = tssc; ++ break; ++ } ++ ++ if (trate > rate) ++ test_min = tssc + 1; ++ else ++ test_max = tssc - 1; ++ } ++ ++ if (trate != 0) ++ *ssc_syn_set = test_min; ++ ++ return trate; ++} ++ ++static int fpll_find_rate(struct cv1800_clk_pll *pll, ++ const struct cv1800_clk_pll_limit *limit, ++ unsigned long prate, ++ unsigned long *rate, ++ u32 *value, u32 *ssc_syn_set) ++{ ++ unsigned long best_rate = 0; ++ unsigned long pre_div_sel = 0, div_sel = 0, post_div_sel = 0; ++ unsigned long pre, div, post; ++ unsigned long trate = *rate; ++ u32 detected = *value; ++ unsigned long tmp; ++ bool clk_full = cv1800_clk_checkbit(&pll->common, ++ &pll->pll_syn->clk_half); ++ ++ for_each_pll_limit_range(pre, &limit->pre_div) { ++ for_each_pll_limit_range(post, &limit->post_div) { ++ for_each_pll_limit_range(div, &limit->div) { ++ tmp = fpll_find_synthesizer(prate, trate, ++ pre, div, post, ++ clk_full, ++ ssc_syn_set); ++ ++ if ((trate - tmp) < (trate - best_rate)) { ++ best_rate = tmp; ++ pre_div_sel = pre; ++ div_sel = div; ++ post_div_sel = post; ++ } ++ } ++ } ++ } ++ ++ if (best_rate) { ++ detected = PLL_SET_PRE_DIV_SEL(detected, pre_div_sel); ++ detected = PLL_SET_POST_DIV_SEL(detected, post_div_sel); ++ detected = PLL_SET_DIV_SEL(detected, div_sel); ++ *value = detected; ++ *rate = best_rate; ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++ ++static int fpll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) ++{ ++ struct cv1800_clk_pll *pll = hw_to_cv1800_clk_pll(hw); ++ u32 val, ssc_syn_set; ++ ++ if (!fpll_is_factional_mode(pll)) ++ return ipll_determine_rate(hw, req); ++ ++ fpll_find_rate(pll, &pll->pll_limit[2], req->best_parent_rate, ++ &req->rate, &val, &ssc_syn_set); ++ ++ return 0; ++} ++ ++static bool fpll_check_mode_ctrl_restrict(unsigned long div_sel, ++ unsigned long ictrl, ++ unsigned long mode) ++{ ++ unsigned long left_rest = 10 * div_sel; ++ unsigned long right_rest = 24 * div_sel; ++ unsigned long test = 184 * (1 + mode) * (1 + ictrl) / 2; ++ ++ return test > left_rest && test <= right_rest; ++} ++ ++static int fpll_set_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ u32 regval; ++ u32 detected = 0, detected_ssc = 0; ++ unsigned long flags; ++ struct cv1800_clk_pll *pll = hw_to_cv1800_clk_pll(hw); ++ ++ if (!fpll_is_factional_mode(pll)) ++ return ipll_set_rate(hw, rate, parent_rate); ++ ++ fpll_find_rate(pll, &pll->pll_limit[2], parent_rate, ++ &rate, &detected, &detected_ssc); ++ pll_get_mode_ctrl(PLL_GET_DIV_SEL(detected), ++ fpll_check_mode_ctrl_restrict, ++ pll->pll_limit, &detected); ++ ++ spin_lock_irqsave(pll->common.lock, flags); ++ ++ writel(detected_ssc, pll->common.base + pll->pll_syn->set); ++ ++ regval = readl(pll->common.base + pll->pll_reg); ++ regval = PLL_COPY_REG(regval, detected); ++ ++ writel(regval, pll->common.base + pll->pll_reg); ++ ++ spin_unlock_irqrestore(pll->common.lock, flags); ++ ++ cv1800_clk_wait_for_lock(&pll->common, pll->pll_status.reg, ++ BIT(pll->pll_status.shift)); ++ ++ return 0; ++} ++ ++static u8 fpll_get_parent(struct clk_hw *hw) ++{ ++ struct cv1800_clk_pll *pll = hw_to_cv1800_clk_pll(hw); ++ ++ if (fpll_is_factional_mode(pll)) ++ return 1; ++ ++ return 0; ++} ++ ++static int fpll_set_parent(struct clk_hw *hw, u8 index) ++{ ++ struct cv1800_clk_pll *pll = hw_to_cv1800_clk_pll(hw); ++ ++ if (index) ++ cv1800_clk_setbit(&pll->common, &pll->pll_syn->en); ++ else ++ cv1800_clk_clearbit(&pll->common, &pll->pll_syn->en); ++ ++ return 0; ++} ++ ++const struct clk_ops cv1800_clk_fpll_ops = { ++ .disable = pll_disable, ++ .enable = pll_enable, ++ .is_enabled = pll_is_enable, ++ ++ .recalc_rate = fpll_recalc_rate, ++ .determine_rate = fpll_determine_rate, ++ .set_rate = fpll_set_rate, ++ ++ .set_parent = fpll_set_parent, ++ .get_parent = fpll_get_parent, ++}; +diff --git a/drivers/clk/sophgo/clk-cv18xx-pll.h b/drivers/clk/sophgo/clk-cv18xx-pll.h +new file mode 100644 +index 000000000000..7a33f3da2d64 +--- /dev/null ++++ b/drivers/clk/sophgo/clk-cv18xx-pll.h +@@ -0,0 +1,118 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (C) 2023 Inochi Amaoto ++ */ ++ ++#ifndef _CLK_SOPHGO_CV1800_PLL_H_ ++#define _CLK_SOPHGO_CV1800_PLL_H_ ++ ++#include "clk-cv18xx-common.h" ++ ++struct cv1800_clk_pll_limit { ++ struct { ++ u8 min; ++ u8 max; ++ } pre_div, div, post_div, ictrl, mode; ++}; ++ ++#define _CV1800_PLL_LIMIT(_min, _max) \ ++ { \ ++ .min = _min, \ ++ .max = _max, \ ++ } \ ++ ++#define for_each_pll_limit_range(_var, _restrict) \ ++ for (_var = (_restrict)->min; _var <= (_restrict)->max; _var++) ++ ++struct cv1800_clk_pll_synthesizer { ++ struct cv1800_clk_regbit en; ++ struct cv1800_clk_regbit clk_half; ++ u32 ctrl; ++ u32 set; ++}; ++ ++#define _PLL_PRE_DIV_SEL_FIELD GENMASK(6, 0) ++#define _PLL_POST_DIV_SEL_FIELD GENMASK(14, 8) ++#define _PLL_SEL_MODE_FIELD GENMASK(16, 15) ++#define _PLL_DIV_SEL_FIELD GENMASK(23, 17) ++#define _PLL_ICTRL_FIELD GENMASK(26, 24) ++ ++#define _PLL_ALL_FIELD_MASK \ ++ (_PLL_PRE_DIV_SEL_FIELD | \ ++ _PLL_POST_DIV_SEL_FIELD | \ ++ _PLL_SEL_MODE_FIELD | \ ++ _PLL_DIV_SEL_FIELD | \ ++ _PLL_ICTRL_FIELD) ++ ++#define PLL_COPY_REG(_dest, _src) \ ++ (((_dest) & (~_PLL_ALL_FIELD_MASK)) | ((_src) & _PLL_ALL_FIELD_MASK)) ++ ++#define PLL_GET_PRE_DIV_SEL(_reg) \ ++ FIELD_GET(_PLL_PRE_DIV_SEL_FIELD, (_reg)) ++#define PLL_GET_POST_DIV_SEL(_reg) \ ++ FIELD_GET(_PLL_POST_DIV_SEL_FIELD, (_reg)) ++#define PLL_GET_SEL_MODE(_reg) \ ++ FIELD_GET(_PLL_SEL_MODE_FIELD, (_reg)) ++#define PLL_GET_DIV_SEL(_reg) \ ++ FIELD_GET(_PLL_DIV_SEL_FIELD, (_reg)) ++#define PLL_GET_ICTRL(_reg) \ ++ FIELD_GET(_PLL_ICTRL_FIELD, (_reg)) ++ ++#define PLL_SET_PRE_DIV_SEL(_reg, _val) \ ++ _CV1800_SET_FIELD((_reg), (_val), _PLL_PRE_DIV_SEL_FIELD) ++#define PLL_SET_POST_DIV_SEL(_reg, _val) \ ++ _CV1800_SET_FIELD((_reg), (_val), _PLL_POST_DIV_SEL_FIELD) ++#define PLL_SET_SEL_MODE(_reg, _val) \ ++ _CV1800_SET_FIELD((_reg), (_val), _PLL_SEL_MODE_FIELD) ++#define PLL_SET_DIV_SEL(_reg, _val) \ ++ _CV1800_SET_FIELD((_reg), (_val), _PLL_DIV_SEL_FIELD) ++#define PLL_SET_ICTRL(_reg, _val) \ ++ _CV1800_SET_FIELD((_reg), (_val), _PLL_ICTRL_FIELD) ++ ++struct cv1800_clk_pll { ++ struct cv1800_clk_common common; ++ u32 pll_reg; ++ struct cv1800_clk_regbit pll_pwd; ++ struct cv1800_clk_regbit pll_status; ++ const struct cv1800_clk_pll_limit *pll_limit; ++ struct cv1800_clk_pll_synthesizer *pll_syn; ++}; ++ ++#define CV1800_INTEGRAL_PLL(_name, _parent, _pll_reg, \ ++ _pll_pwd_reg, _pll_pwd_shift, \ ++ _pll_status_reg, _pll_status_shift, \ ++ _pll_limit, _flags) \ ++ struct cv1800_clk_pll _name = { \ ++ .common = CV1800_CLK_COMMON(#_name, _parent, \ ++ &cv1800_clk_ipll_ops,\ ++ _flags), \ ++ .pll_reg = _pll_reg, \ ++ .pll_pwd = CV1800_CLK_BIT(_pll_pwd_reg, \ ++ _pll_pwd_shift), \ ++ .pll_status = CV1800_CLK_BIT(_pll_status_reg, \ ++ _pll_status_shift), \ ++ .pll_limit = _pll_limit, \ ++ .pll_syn = NULL, \ ++ } ++ ++#define CV1800_FACTIONAL_PLL(_name, _parent, _pll_reg, \ ++ _pll_pwd_reg, _pll_pwd_shift, \ ++ _pll_status_reg, _pll_status_shift, \ ++ _pll_limit, _pll_syn, _flags) \ ++ struct cv1800_clk_pll _name = { \ ++ .common = CV1800_CLK_COMMON(#_name, _parent, \ ++ &cv1800_clk_fpll_ops,\ ++ _flags), \ ++ .pll_reg = _pll_reg, \ ++ .pll_pwd = CV1800_CLK_BIT(_pll_pwd_reg, \ ++ _pll_pwd_shift), \ ++ .pll_status = CV1800_CLK_BIT(_pll_status_reg, \ ++ _pll_status_shift), \ ++ .pll_limit = _pll_limit, \ ++ .pll_syn = _pll_syn, \ ++ } ++ ++extern const struct clk_ops cv1800_clk_ipll_ops; ++extern const struct clk_ops cv1800_clk_fpll_ops; ++ ++#endif // _CLK_SOPHGO_CV1800_PLL_H_ +-- +2.20.1 + diff --git a/target/linux/cv18x0/patches-6.6/0013-riscv-dts-sophgo-add-sdcard-support-for-milkv-duo.patch b/target/linux/cv18x0/patches-6.6/0013-riscv-dts-sophgo-add-sdcard-support-for-milkv-duo.patch new file mode 100644 index 0000000000..ed63c4bacd --- /dev/null +++ b/target/linux/cv18x0/patches-6.6/0013-riscv-dts-sophgo-add-sdcard-support-for-milkv-duo.patch @@ -0,0 +1,80 @@ +From 5ae34f760404f060bf2b3e6593f50e0b1d0a4d6b Mon Sep 17 00:00:00 2001 +From: Jisheng Zhang +Date: Sat, 17 Feb 2024 22:48:26 +0800 +Subject: [PATCH 13/18] riscv: dts: sophgo: add sdcard support for milkv duo + +Add sdhci dt node in SoC dtsi and enable it in milkv duo dts. + +Signed-off-by: Jisheng Zhang + +Upstream-Status: Submitted [https://lore.kernel.org/linux-riscv/20240217144826.3944-1-jszhang@kernel.org/] +--- + .../riscv/boot/dts/sophgo/cv1800b-milkv-duo.dts | 9 +++++++++ + arch/riscv/boot/dts/sophgo/cv18xx.dtsi | 17 +++++++++++++++++ + 2 files changed, 26 insertions(+) + +diff --git a/arch/riscv/boot/dts/sophgo/cv1800b-milkv-duo.dts b/arch/riscv/boot/dts/sophgo/cv1800b-milkv-duo.dts +index 3af9e34b3bc7..6944f3c1c6c6 100644 +--- a/arch/riscv/boot/dts/sophgo/cv1800b-milkv-duo.dts ++++ b/arch/riscv/boot/dts/sophgo/cv1800b-milkv-duo.dts +@@ -33,6 +33,15 @@ + clock-frequency = <25000000>; + }; + ++&sdhci0 { ++ status = "okay"; ++ bus-width = <4>; ++ disable-wp; ++ no-1-8-v; ++ no-mmc; ++ no-sdio; ++}; ++ + &uart0 { + status = "okay"; + }; +diff --git a/arch/riscv/boot/dts/sophgo/cv18xx.dtsi b/arch/riscv/boot/dts/sophgo/cv18xx.dtsi +index e375e9d9516e..c0a0ca437fec 100644 +--- a/arch/riscv/boot/dts/sophgo/cv18xx.dtsi ++++ b/arch/riscv/boot/dts/sophgo/cv18xx.dtsi +@@ -4,6 +4,7 @@ + * Copyright (C) 2023 Inochi Amaoto + */ + ++#include + #include + #include + +@@ -47,6 +48,13 @@ + #clock-cells = <0>; + }; + ++ sdhci_clk: sdhci-clock { ++ compatible = "fixed-clock"; ++ clock-frequency = <375000000>; ++ clock-output-names = "sdhci_clk"; ++ #clock-cells = <0>; ++ }; ++ + soc { + compatible = "simple-bus"; + interrupt-parent = <&plic>; +@@ -188,6 +196,15 @@ + status = "disabled"; + }; + ++ sdhci0: mmc@4310000 { ++ compatible = "sophgo,cv1800b-dwcmshc"; ++ reg = <0x4310000 0x1000>; ++ interrupts = <36 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&sdhci_clk>; ++ clock-names = "core"; ++ status = "disabled"; ++ }; ++ + plic: interrupt-controller@70000000 { + reg = <0x70000000 0x4000000>; + interrupts-extended = <&cpu0_intc 11>, <&cpu0_intc 9>; +-- +2.20.1 + diff --git a/target/linux/cv18x0/patches-6.6/0014-sophgo-add-reboot-shutdown-driver.patch b/target/linux/cv18x0/patches-6.6/0014-sophgo-add-reboot-shutdown-driver.patch new file mode 100644 index 0000000000..de4fe89b2c --- /dev/null +++ b/target/linux/cv18x0/patches-6.6/0014-sophgo-add-reboot-shutdown-driver.patch @@ -0,0 +1,174 @@ +From 3759b7030c46bcb98ed0a114e3d5790eeb95d96a Mon Sep 17 00:00:00 2001 +From: GP Orcullo +Date: Sat, 4 Nov 2023 13:09:27 +0000 +Subject: [PATCH 14/18] sophgo: add reboot/shutdown driver + +extracted from OEM supplied sources + +Upstream-Status: Pending +--- + arch/riscv/boot/dts/sophgo/cv18xx.dtsi | 5 ++ + drivers/power/reset/Kconfig | 6 ++ + drivers/power/reset/Makefile | 1 + + drivers/power/reset/sophgo-reboot.c | 108 +++++++++++++++++++++++++ + 4 files changed, 120 insertions(+) + create mode 100644 drivers/power/reset/sophgo-reboot.c + +diff --git a/arch/riscv/boot/dts/sophgo/cv18xx.dtsi b/arch/riscv/boot/dts/sophgo/cv18xx.dtsi +index c0a0ca437fec..efd8bbdbf1ca 100644 +--- a/arch/riscv/boot/dts/sophgo/cv18xx.dtsi ++++ b/arch/riscv/boot/dts/sophgo/cv18xx.dtsi +@@ -218,5 +218,10 @@ + reg = <0x74000000 0x10000>; + interrupts-extended = <&cpu0_intc 3>, <&cpu0_intc 7>; + }; ++ ++ restart: restart-controller@5025000 { ++ compatible = "sophgo,restart"; ++ reg = <0x05025000 0x2000>; ++ }; + }; + }; +diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig +index 411e00b255d6..f4ae605da7c7 100644 +--- a/drivers/power/reset/Kconfig ++++ b/drivers/power/reset/Kconfig +@@ -199,6 +199,12 @@ config POWER_RESET_RESTART + Instead they restart, and u-boot holds the SoC until the + user presses a key. u-boot then boots into Linux. + ++config POWER_RESET_SOPHGO ++ bool "SOPHGO power-off driver" ++ depends on ARCH_SOPHGO ++ help ++ Power off and restart support for SOPHGO boards. ++ + config POWER_RESET_ST + bool "ST restart driver" + depends on ARCH_STI +diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile +index a95d1bd275d1..a65266f2e3f6 100644 +--- a/drivers/power/reset/Makefile ++++ b/drivers/power/reset/Makefile +@@ -36,3 +36,4 @@ obj-$(CONFIG_SYSCON_REBOOT_MODE) += syscon-reboot-mode.o + obj-$(CONFIG_POWER_RESET_SC27XX) += sc27xx-poweroff.o + obj-$(CONFIG_NVMEM_REBOOT_MODE) += nvmem-reboot-mode.o + obj-$(CONFIG_POWER_MLXBF) += pwr-mlxbf.o ++obj-$(CONFIG_POWER_RESET_SOPHGO) += sophgo-reboot.o +diff --git a/drivers/power/reset/sophgo-reboot.c b/drivers/power/reset/sophgo-reboot.c +new file mode 100644 +index 000000000000..17b828a15272 +--- /dev/null ++++ b/drivers/power/reset/sophgo-reboot.c +@@ -0,0 +1,108 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define RTC_CTRL0_UNLOCKKEY 0x4 ++#define RTC_CTRL0 0x8 ++#define RTC_EN_SHDN_REQ 0xC0 ++#define RTC_EN_WARM_RST_REQ 0xCC ++#define RTC_EN_SUSPEND_REQ 0xE4 ++#define RSM_STATE 0xD4 ++#define ST_ON 0x3 ++ ++static void __iomem *base; ++ ++static int sophgo_restart_handler(struct notifier_block *this, ++ unsigned long mode, void *cmd) ++{ ++ void __iomem *REG_RTC_CTRL_BASE = base; ++ void __iomem *REG_RTC_BASE = base + 0x1000; ++ ++ /* Enable power suspend wakeup source mask */ ++ writel(0x1, REG_RTC_BASE + 0x3C); // 1 = select prdata from 32K domain ++ ++ writel(0xAB18, REG_RTC_CTRL_BASE + RTC_CTRL0_UNLOCKKEY); ++ ++ writel(0x1, REG_RTC_BASE + RTC_EN_WARM_RST_REQ); ++ ++ while (readl(REG_RTC_BASE + RTC_EN_WARM_RST_REQ) != 0x01) ++ ; ++ ++ while (readl(REG_RTC_BASE + RSM_STATE) != ST_ON) ++ ; ++ ++ writel(0xFFFF0800 | (0x1 << 4), REG_RTC_CTRL_BASE + RTC_CTRL0); ++ ++ return NOTIFY_DONE; ++} ++ ++static void sophgo_do_pwroff(void) ++{ ++ void __iomem *REG_RTC_CTRL_BASE = base; ++ void __iomem *REG_RTC_BASE = base + 0x1000; ++ ++ /* Enable power suspend wakeup source mask */ ++ writel(0x1, REG_RTC_BASE + 0x3C); // 1 = select prdata from 32K domain ++ ++ writel(0xAB18, REG_RTC_CTRL_BASE + RTC_CTRL0_UNLOCKKEY); ++ ++ writel(0x1, REG_RTC_BASE + RTC_EN_SHDN_REQ); ++ ++ while (readl(REG_RTC_BASE + RTC_EN_SHDN_REQ) != 0x01) ++ ; ++ ++ writel(0xFFFF0800 | (0x1 << 0), REG_RTC_CTRL_BASE + RTC_CTRL0); ++ ++ /* Wait some time until system down, otherwise, notice with a warn */ ++ mdelay(1000); ++ ++ WARN_ONCE(1, "Unable to power off system\n"); ++} ++ ++static struct notifier_block sophgo_restart_nb = { ++ .notifier_call = sophgo_restart_handler, ++ .priority = 128, ++}; ++ ++static int sophgo_reboot_probe(struct platform_device *pdev) ++{ ++ struct device_node *np = pdev->dev.of_node; ++ int err; ++ ++ base = of_iomap(np, 0); ++ if (!base) { ++ WARN(1, "failed to map base address"); ++ return -ENODEV; ++ } ++ ++ err = register_restart_handler(&sophgo_restart_nb); ++ if (err) { ++ dev_err(&pdev->dev, "cannot register restart handler (err=%d)\n", ++ err); ++ iounmap(base); ++ } ++ ++ pm_power_off = &sophgo_do_pwroff; ++ ++ return err; ++} ++ ++static const struct of_device_id sophgo_reboot_of_match[] = { ++ { .compatible = "sophgo,restart" }, ++ {} ++}; ++ ++static struct platform_driver sophgo_reboot_driver = { ++ .probe = sophgo_reboot_probe, ++ .driver = { ++ .name = "sophgo-reboot", ++ .of_match_table = sophgo_reboot_of_match, ++ }, ++}; ++module_platform_driver(sophgo_reboot_driver); +-- +2.20.1 + diff --git a/target/linux/cv18x0/patches-6.6/0015-dt-bindings-reset-Add-binding-for-Sophgo-CV1800B-res.patch b/target/linux/cv18x0/patches-6.6/0015-dt-bindings-reset-Add-binding-for-Sophgo-CV1800B-res.patch new file mode 100644 index 0000000000..ddc24dff0d --- /dev/null +++ b/target/linux/cv18x0/patches-6.6/0015-dt-bindings-reset-Add-binding-for-Sophgo-CV1800B-res.patch @@ -0,0 +1,166 @@ +From 05bd968ce9f19c79ade3be9bc81991c3c40c70df Mon Sep 17 00:00:00 2001 +From: Jisheng Zhang +Date: Mon, 13 Nov 2023 08:55:00 +0800 +Subject: [PATCH 15/18] dt-bindings: reset: Add binding for Sophgo CV1800B + reset controller + +Add devicetree binding for Sophgo CV1800B SoC reset controller. + +Signed-off-by: Jisheng Zhang +Reviewed-by: Conor Dooley +--- + .../bindings/reset/sophgo,cv1800b-reset.yaml | 38 ++++++++ + .../dt-bindings/reset/sophgo,cv1800b-reset.h | 96 +++++++++++++++++++ + 2 files changed, 134 insertions(+) + create mode 100644 Documentation/devicetree/bindings/reset/sophgo,cv1800b-reset.yaml + create mode 100644 include/dt-bindings/reset/sophgo,cv1800b-reset.h + +diff --git a/Documentation/devicetree/bindings/reset/sophgo,cv1800b-reset.yaml b/Documentation/devicetree/bindings/reset/sophgo,cv1800b-reset.yaml +new file mode 100644 +index 000000000000..20a525147490 +--- /dev/null ++++ b/Documentation/devicetree/bindings/reset/sophgo,cv1800b-reset.yaml +@@ -0,0 +1,38 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/reset/sophgo,cv1800b-reset.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Sophgo CV1800B SoC Reset Controller ++ ++maintainers: ++ - Jisheng Zhang ++ ++properties: ++ compatible: ++ enum: ++ - sophgo,cv1800b-reset ++ ++ reg: ++ maxItems: 1 ++ ++ "#reset-cells": ++ const: 1 ++ ++required: ++ - compatible ++ - reg ++ - "#reset-cells" ++ ++additionalProperties: false ++ ++examples: ++ - | ++ reset-controller@3003000 { ++ compatible = "sophgo,cv1800b-reset"; ++ reg = <0x03003000 0x1000>; ++ #reset-cells = <1>; ++ }; ++ ++... +diff --git a/include/dt-bindings/reset/sophgo,cv1800b-reset.h b/include/dt-bindings/reset/sophgo,cv1800b-reset.h +new file mode 100644 +index 000000000000..4ab9ede74ba3 +--- /dev/null ++++ b/include/dt-bindings/reset/sophgo,cv1800b-reset.h +@@ -0,0 +1,96 @@ ++/* SPDX-License-Identifier: GPL-2.0 OR MIT */ ++/* ++ * Copyright (C) 2023 Sophgo Technology Inc. All rights reserved. ++ * Copyright (C) 2023 Jisheng Zhang ++ */ ++ ++#ifndef _DT_BINDINGS_CV1800B_RESET_H ++#define _DT_BINDINGS_CV1800B_RESET_H ++ ++/* 0-1 */ ++#define RST_DDR 2 ++#define RST_H264C 3 ++#define RST_JPEG 4 ++#define RST_H265C 5 ++#define RST_VIPSYS 6 ++#define RST_TDMA 7 ++#define RST_TPU 8 ++#define RST_TPUSYS 9 ++/* 10 */ ++#define RST_USB 11 ++#define RST_ETH0 12 ++/* 13 */ ++#define RST_NAND 14 ++/* 15 */ ++#define RST_SD0 16 ++/* 17 */ ++#define RST_SDMA 18 ++#define RST_I2S0 19 ++#define RST_I2S1 20 ++#define RST_I2S2 21 ++#define RST_I2S3 22 ++#define RST_UART0 23 ++#define RST_UART1 24 ++#define RST_UART2 25 ++#define RST_UART3 26 ++#define RST_I2C0 27 ++#define RST_I2C1 28 ++#define RST_I2C2 29 ++#define RST_I2C3 30 ++#define RST_I2C4 31 ++#define RST_PWM0 32 ++#define RST_PWM1 33 ++#define RST_PWM2 34 ++#define RST_PWM3 35 ++/* 36-39 */ ++#define RST_SPI0 40 ++#define RST_SPI1 41 ++#define RST_SPI2 42 ++#define RST_SPI3 43 ++#define RST_GPIO0 44 ++#define RST_GPIO1 45 ++#define RST_GPIO2 46 ++#define RST_EFUSE 47 ++#define RST_WDT 48 ++#define RST_AHBRST_ROM 49 ++#define RST_SPIC 50 ++#define RST_TEMPSEN 51 ++#define RST_SARADC 52 ++/* 53-57 */ ++#define RST_COMBORST_PHY0 58 ++/* 59-60 */ ++#define RST_SPIRST_NAND 61 ++#define RST_SE 62 ++/* 63-73 */ ++#define RST_UART4 74 ++#define RST_GPIO3 75 ++#define RST_SYSTEM 76 ++#define RST_TIMER 77 ++#define RST_TIMER0 78 ++#define RST_TIMER1 79 ++#define RST_TIMER2 80 ++#define RST_TIMER3 81 ++#define RST_TIMER4 82 ++#define RST_TIMER5 83 ++#define RST_TIMER6 84 ++#define RST_TIMER7 85 ++#define RST_WGN0 86 ++#define RST_WGN1 87 ++#define RST_WGN2 88 ++#define RST_KEYSCAN 89 ++/* 90 */ ++#define RST_AUDDAC 91 ++#define RST_AUDDACRST_APB 92 ++#define RST_AUDADC 93 ++/* 94 */ ++#define RST_VCSYS 95 ++#define RST_ETHPHY 96 ++#define RST_ETHPHYRST_APB 97 ++#define RST_AUDSRC 98 ++#define RST_VIP_CAM0 99 ++#define RST_WDT1 100 ++#define RST_WDT2 101 ++/* 102-292 */ ++#define RST_CPUSYS1 293 ++#define RST_CPUSYS2 294 ++#endif +-- +2.20.1 + diff --git a/target/linux/cv18x0/patches-6.6/0016-reset-Add-reset-controller-support-for-Sophgo-CV1800.patch b/target/linux/cv18x0/patches-6.6/0016-reset-Add-reset-controller-support-for-Sophgo-CV1800.patch new file mode 100644 index 0000000000..bc7cdfaabd --- /dev/null +++ b/target/linux/cv18x0/patches-6.6/0016-reset-Add-reset-controller-support-for-Sophgo-CV1800.patch @@ -0,0 +1,117 @@ +From c251dd18b0a101c7ea551b9a1634b41f22796bb2 Mon Sep 17 00:00:00 2001 +From: Jisheng Zhang +Date: Mon, 13 Nov 2023 08:55:01 +0800 +Subject: [PATCH 16/18] reset: Add reset controller support for Sophgo CV1800B + SoC + +Add reset controller support for Sophgo CV1800B SoC reusing the +reset-simple driver. + +Signed-off-by: Jisheng Zhang +--- + arch/riscv/boot/dts/sophgo/cv18xx.dtsi | 12 ++++++++++++ + drivers/reset/Kconfig | 3 ++- + drivers/reset/reset-simple.c | 2 ++ + 3 files changed, 16 insertions(+), 1 deletion(-) + +diff --git a/arch/riscv/boot/dts/sophgo/cv18xx.dtsi b/arch/riscv/boot/dts/sophgo/cv18xx.dtsi +index efd8bbdbf1ca..37c71808b048 100644 +--- a/arch/riscv/boot/dts/sophgo/cv18xx.dtsi ++++ b/arch/riscv/boot/dts/sophgo/cv18xx.dtsi +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + + / { + #address-cells = <1>; +@@ -141,12 +142,19 @@ + }; + }; + ++ rst: reset-controller@3003000 { ++ compatible = "sophgo,cv1800b-reset"; ++ reg = <0x03003000 0x1000>; ++ #reset-cells = <1>; ++ }; ++ + uart0: serial@4140000 { + compatible = "snps,dw-apb-uart"; + reg = <0x04140000 0x100>; + interrupts = <44 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk CLK_UART0>, <&clk CLK_APB_UART0>; + clock-names = "baudclk", "apb_pclk"; ++ resets = <&rst RST_UART0>; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; +@@ -158,6 +166,7 @@ + interrupts = <45 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk CLK_UART1>, <&clk CLK_APB_UART1>; + clock-names = "baudclk", "apb_pclk"; ++ resets = <&rst RST_UART1>; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; +@@ -169,6 +178,7 @@ + interrupts = <46 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk CLK_UART2>, <&clk CLK_APB_UART2>; + clock-names = "baudclk", "apb_pclk"; ++ resets = <&rst RST_UART2>; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; +@@ -180,6 +190,7 @@ + interrupts = <47 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk CLK_UART3>, <&clk CLK_APB_UART3>; + clock-names = "baudclk", "apb_pclk"; ++ resets = <&rst RST_UART3>; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; +@@ -191,6 +202,7 @@ + interrupts = <48 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk CLK_UART4>, <&clk CLK_APB_UART4>; + clock-names = "baudclk", "apb_pclk"; ++ resets = <&rst RST_UART4>; + reg-shift = <2>; + reg-io-width = <4>; + status = "disabled"; +diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig +index ccd59ddd7610..2034f69d5953 100644 +--- a/drivers/reset/Kconfig ++++ b/drivers/reset/Kconfig +@@ -213,7 +213,7 @@ config RESET_SCMI + + config RESET_SIMPLE + bool "Simple Reset Controller Driver" if COMPILE_TEST || EXPERT +- default ARCH_ASPEED || ARCH_BCMBCA || ARCH_BITMAIN || ARCH_REALTEK || ARCH_STM32 || (ARCH_INTEL_SOCFPGA && ARM64) || ARCH_SUNXI || ARC ++ default ARCH_ASPEED || ARCH_BCMBCA || ARCH_BITMAIN || ARCH_REALTEK || ARCH_SOPHGO || ARCH_STM32 || (ARCH_INTEL_SOCFPGA && ARM64) || ARCH_SUNXI || ARC + depends on HAS_IOMEM + help + This enables a simple reset controller driver for reset lines that +@@ -228,6 +228,7 @@ config RESET_SIMPLE + - RCC reset controller in STM32 MCUs + - Allwinner SoCs + - SiFive FU740 SoCs ++ - Sophgo SoCs + + config RESET_SOCFPGA + bool "SoCFPGA Reset Driver" if COMPILE_TEST && (!ARM || !ARCH_INTEL_SOCFPGA) +diff --git a/drivers/reset/reset-simple.c b/drivers/reset/reset-simple.c +index 7ea5adbf2097..573753ae3e08 100644 +--- a/drivers/reset/reset-simple.c ++++ b/drivers/reset/reset-simple.c +@@ -151,6 +151,8 @@ static const struct of_device_id reset_simple_dt_ids[] = { + { .compatible = "snps,dw-high-reset" }, + { .compatible = "snps,dw-low-reset", + .data = &reset_simple_active_low }, ++ { .compatible = "sophgo,cv1800b-reset", ++ .data = &reset_simple_active_low }, + { /* sentinel */ }, + }; + +-- +2.20.1 + diff --git a/target/linux/cv18x0/patches-6.6/0017-riscv-dts-sophgo-add-watchdog-dt-node-for-CV1800.patch b/target/linux/cv18x0/patches-6.6/0017-riscv-dts-sophgo-add-watchdog-dt-node-for-CV1800.patch new file mode 100644 index 0000000000..e7ace82f57 --- /dev/null +++ b/target/linux/cv18x0/patches-6.6/0017-riscv-dts-sophgo-add-watchdog-dt-node-for-CV1800.patch @@ -0,0 +1,58 @@ +From 945c22abfac4989df3e7d46f773a75518a61cdef Mon Sep 17 00:00:00 2001 +From: AnnanLiu +Date: Thu, 28 Dec 2023 21:08:17 +0800 +Subject: [PATCH 17/18] riscv: dts: sophgo: add watchdog dt node for CV1800 + +Add the watchdog device tree node to cv1800 SoC. +This patch depends on the clk driver and reset driver. +Clk driver link: +https://lore.kernel.org/all/IA1PR20MB49539CDAD9A268CBF6CA184BBB9FA@IA1PR20MB4953.namprd20.prod.outlook.com/ +Reset driver link: +https://lore.kernel.org/all/20231113005503.2423-1-jszhang@kernel.org/ + +Signed-off-by: AnnanLiu +--- + arch/riscv/boot/dts/sophgo/cv1800b-milkv-duo.dts | 4 ++++ + arch/riscv/boot/dts/sophgo/cv18xx.dtsi | 14 ++++++++++++++ + 2 files changed, 18 insertions(+) + +diff --git a/arch/riscv/boot/dts/sophgo/cv1800b-milkv-duo.dts b/arch/riscv/boot/dts/sophgo/cv1800b-milkv-duo.dts +index 6944f3c1c6c6..22c3b5be0739 100644 +--- a/arch/riscv/boot/dts/sophgo/cv1800b-milkv-duo.dts ++++ b/arch/riscv/boot/dts/sophgo/cv1800b-milkv-duo.dts +@@ -45,3 +45,7 @@ + &uart0 { + status = "okay"; + }; ++ ++&watchdog0 { ++ status = "okay"; ++}; +diff --git a/arch/riscv/boot/dts/sophgo/cv18xx.dtsi b/arch/riscv/boot/dts/sophgo/cv18xx.dtsi +index 37c71808b048..82e828721df7 100644 +--- a/arch/riscv/boot/dts/sophgo/cv18xx.dtsi ++++ b/arch/riscv/boot/dts/sophgo/cv18xx.dtsi +@@ -226,6 +226,20 @@ + riscv,ndev = <101>; + }; + ++ watchdog0: watchdog@3010000{ ++ compatible = "snps,dw-wdt"; ++ reg = <0x3010000 0x100>; ++ interrupts = <58 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&pclk>; ++ resets = <&rst RST_WDT>; ++ }; ++ ++ pclk: pclk { ++ #clock-cells = <0>; ++ compatible = "fixed-clock"; ++ clock-frequency = <25000000>; ++ }; ++ + clint: timer@74000000 { + reg = <0x74000000 0x10000>; + interrupts-extended = <&cpu0_intc 3>, <&cpu0_intc 7>; +-- +2.20.1 + diff --git a/target/linux/cv18x0/patches-6.6/0018-riscv-dts-sophgo-add-timer-dt-node-for-CV1800.patch b/target/linux/cv18x0/patches-6.6/0018-riscv-dts-sophgo-add-timer-dt-node-for-CV1800.patch new file mode 100644 index 0000000000..d3ebeed14d --- /dev/null +++ b/target/linux/cv18x0/patches-6.6/0018-riscv-dts-sophgo-add-timer-dt-node-for-CV1800.patch @@ -0,0 +1,103 @@ +From 6f1f2e3823dc0e4a9960c76792eea1d0a43c3f66 Mon Sep 17 00:00:00 2001 +From: AnnanLiu +Date: Thu, 28 Dec 2023 21:06:54 +0800 +Subject: [PATCH 18/18] riscv: dts: sophgo: add timer dt node for CV1800 + +Add the timer device tree node to CV1800 SoC. +This patch depends on the clk driver and reset driver. +Clk driver link: +https://lore.kernel.org/all/IA1PR20MB49539CDAD9A268CBF6CA184BBB9FA@IA1PR20MB4953.namprd20.prod.outlook.com/ +Reset driver link: +https://lore.kernel.org/all/20231113005503.2423-1-jszhang@kernel.org/ + +Signed-off-by: AnnanLiu +--- + arch/riscv/boot/dts/sophgo/cv18xx.dtsi | 72 ++++++++++++++++++++++++++ + 1 file changed, 72 insertions(+) + +diff --git a/arch/riscv/boot/dts/sophgo/cv18xx.dtsi b/arch/riscv/boot/dts/sophgo/cv18xx.dtsi +index 82e828721df7..e87df337ec68 100644 +--- a/arch/riscv/boot/dts/sophgo/cv18xx.dtsi ++++ b/arch/riscv/boot/dts/sophgo/cv18xx.dtsi +@@ -240,6 +240,78 @@ + clock-frequency = <25000000>; + }; + ++ timer0: timer@030a0000 { ++ compatible = "snps,dw-apb-timer"; ++ reg = <0x030a0000 0x14>; ++ interrupts = <79 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&osc>; ++ resets = <&rst RST_TIMER0>; ++ status = "okay"; ++ }; ++ ++ timer1: timer@030a0014 { ++ compatible = "snps,dw-apb-timer"; ++ reg = <0x030a0014 0x14>; ++ interrupts = <80 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&osc>; ++ resets = <&rst RST_TIMER1>; ++ status = "okay"; ++ }; ++ ++ timer2: timer@030a0028 { ++ compatible = "snps,dw-apb-timer"; ++ reg = <0x030a0028 0x14>; ++ interrupts = <81 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&osc>; ++ resets = <&rst RST_TIMER2>; ++ status = "okay"; ++ }; ++ ++ timer3: timer@030a003c { ++ compatible = "snps,dw-apb-timer"; ++ reg = <0x030a003c 0x14>; ++ interrupts = <82 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&osc>; ++ resets = <&rst RST_TIMER3>; ++ status = "okay"; ++ }; ++ ++ timer4: timer@030a0050 { ++ compatible = "snps,dw-apb-timer"; ++ reg = <0x030a0050 0x14>; ++ interrupts = <83 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&osc>; ++ resets = <&rst RST_TIMER4>; ++ status = "okay"; ++ }; ++ ++ timer5: timer@30a0064 { ++ compatible = "snps,dw-apb-timer"; ++ reg = <0x030a0064 0x14>; ++ interrupts = <84 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&osc>; ++ resets = <&rst RST_TIMER5>; ++ status = "okay"; ++ }; ++ ++ timer6: timer@030a0078 { ++ compatible = "snps,dw-apb-timer"; ++ reg = <0x030a0078 0x14>; ++ interrupts = <85 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&osc>; ++ resets = <&rst RST_TIMER6>; ++ status = "okay"; ++ }; ++ ++ timer7: timer@030a008c { ++ compatible = "snps,dw-apb-timer"; ++ reg = <0x030a008c 0x14>; ++ interrupts = <86 IRQ_TYPE_LEVEL_HIGH>; ++ clocks = <&osc>; ++ resets = <&rst RST_TIMER7>; ++ status = "okay"; ++ }; ++ + clint: timer@74000000 { + reg = <0x74000000 0x10000>; + interrupts-extended = <&cpu0_intc 3>, <&cpu0_intc 7>; +-- +2.20.1 + diff --git a/target/linux/cv18x0/patches-6.6/0019-mmc-sdhci-of-dwcmshc-Add-tuning-support-for-Sophgo-C.patch b/target/linux/cv18x0/patches-6.6/0019-mmc-sdhci-of-dwcmshc-Add-tuning-support-for-Sophgo-C.patch new file mode 100644 index 0000000000..1fbb725c2c --- /dev/null +++ b/target/linux/cv18x0/patches-6.6/0019-mmc-sdhci-of-dwcmshc-Add-tuning-support-for-Sophgo-C.patch @@ -0,0 +1,158 @@ +From 295e4c305fb59d994970c94f11d7d8d524557693 Mon Sep 17 00:00:00 2001 +From: Jisheng Zhang +Date: Sat, 20 Apr 2024 10:14:29 +0800 +Subject: [PATCH 19/19] mmc: sdhci-of-dwcmshc: Add tuning support for Sophgo + CV1800B and SG200X + +Implement the .platform_execute_tuning for Sophgo CV1800B and SG200X. +Some code is borrowed from sdhci-esdhc-imx.c. The tuning result is +similar as the one of SoC vendor's SDK. + +Signed-off-by: Jisheng Zhang +Acked-by: Adrian Hunter +Link: https://lore.kernel.org/r/20240420021429.454-1-jszhang@kernel.org +Signed-off-by: Ulf Hansson +--- + drivers/mmc/host/sdhci-of-dwcmshc.c | 112 ++++++++++++++++++++++++++++ + 1 file changed, 112 insertions(+) + +diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c +index e473af22e585..54ebb59c3fab 100644 +--- a/drivers/mmc/host/sdhci-of-dwcmshc.c ++++ b/drivers/mmc/host/sdhci-of-dwcmshc.c +@@ -51,6 +51,10 @@ + #define CV18XX_SDHCI_PHY_CONFIG 0x4c + #define CV18XX_PHY_TX_BPS BIT(0) + ++#define CV18XX_TUNE_MAX 128 ++#define CV18XX_TUNE_STEP 1 ++#define CV18XX_RETRY_TUNING_MAX 50 ++ + /* Rockchip specific Registers */ + #define DWCMSHC_EMMC_DLL_CTRL 0x800 + #define DWCMSHC_EMMC_DLL_RXCLK 0x804 +@@ -382,6 +386,113 @@ static void cv18xx_sdhci_reset(struct sdhci_host *host, u8 mask) + sdhci_writel(host, val, priv->vendor_specific_area1 + CV18XX_SDHCI_PHY_TX_RX_DLY); + } + ++static void cv18xx_sdhci_set_tap(struct sdhci_host *host, int tap) ++{ ++ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); ++ struct dwcmshc_priv *priv = sdhci_pltfm_priv(pltfm_host); ++ u16 clk; ++ u32 val; ++ ++ clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); ++ clk &= ~SDHCI_CLOCK_CARD_EN; ++ sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); ++ ++ val = sdhci_readl(host, priv->vendor_specific_area1 + CV18XX_SDHCI_MSHC_CTRL); ++ val &= ~CV18XX_LATANCY_1T; ++ sdhci_writel(host, val, priv->vendor_specific_area1 + CV18XX_SDHCI_MSHC_CTRL); ++ ++ val = (FIELD_PREP(CV18XX_PHY_TX_DLY_MSK, 0) | ++ FIELD_PREP(CV18XX_PHY_TX_SRC_MSK, CV18XX_PHY_TX_SRC_INVERT_CLK_TX) | ++ FIELD_PREP(CV18XX_PHY_RX_DLY_MSK, tap)); ++ sdhci_writel(host, val, priv->vendor_specific_area1 + CV18XX_SDHCI_PHY_TX_RX_DLY); ++ ++ sdhci_writel(host, 0, priv->vendor_specific_area1 + CV18XX_SDHCI_PHY_CONFIG); ++ ++ clk |= SDHCI_CLOCK_CARD_EN; ++ sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); ++ usleep_range(1000, 2000); ++} ++ ++static int cv18xx_retry_tuning(struct mmc_host *mmc, u32 opcode, int *cmd_error) ++{ ++ int ret, retry = 0; ++ ++ while (retry < CV18XX_RETRY_TUNING_MAX) { ++ ret = mmc_send_tuning(mmc, opcode, NULL); ++ if (ret) ++ return ret; ++ retry++; ++ } ++ ++ return 0; ++} ++ ++static void cv18xx_sdhci_post_tuning(struct sdhci_host *host) ++{ ++ u32 val; ++ ++ val = sdhci_readl(host, SDHCI_INT_STATUS); ++ val |= SDHCI_INT_DATA_AVAIL; ++ sdhci_writel(host, val, SDHCI_INT_STATUS); ++ ++ sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); ++} ++ ++static int cv18xx_sdhci_execute_tuning(struct sdhci_host *host, u32 opcode) ++{ ++ int min, max, avg, ret; ++ int win_length, target_min, target_max, target_win_length; ++ ++ min = max = 0; ++ target_win_length = 0; ++ ++ sdhci_reset_tuning(host); ++ ++ while (max < CV18XX_TUNE_MAX) { ++ /* find the mininum delay first which can pass tuning */ ++ while (min < CV18XX_TUNE_MAX) { ++ cv18xx_sdhci_set_tap(host, min); ++ if (!cv18xx_retry_tuning(host->mmc, opcode, NULL)) ++ break; ++ min += CV18XX_TUNE_STEP; ++ } ++ ++ /* find the maxinum delay which can not pass tuning */ ++ max = min + CV18XX_TUNE_STEP; ++ while (max < CV18XX_TUNE_MAX) { ++ cv18xx_sdhci_set_tap(host, max); ++ if (cv18xx_retry_tuning(host->mmc, opcode, NULL)) { ++ max -= CV18XX_TUNE_STEP; ++ break; ++ } ++ max += CV18XX_TUNE_STEP; ++ } ++ ++ win_length = max - min + 1; ++ /* get the largest pass window */ ++ if (win_length > target_win_length) { ++ target_win_length = win_length; ++ target_min = min; ++ target_max = max; ++ } ++ ++ /* continue to find the next pass window */ ++ min = max + CV18XX_TUNE_STEP; ++ } ++ ++ cv18xx_sdhci_post_tuning(host); ++ ++ /* use average delay to get the best timing */ ++ avg = (target_min + target_max) / 2; ++ cv18xx_sdhci_set_tap(host, avg); ++ ret = mmc_send_tuning(host->mmc, opcode, NULL); ++ ++ dev_dbg(mmc_dev(host->mmc), "tuning %s at 0x%x ret %d\n", ++ ret ? "failed" : "passed", avg, ret); ++ ++ return ret; ++} ++ + static const struct sdhci_ops sdhci_dwcmshc_ops = { + .set_clock = sdhci_set_clock, + .set_bus_width = sdhci_set_bus_width, +@@ -407,6 +518,7 @@ static const struct sdhci_ops sdhci_dwcmshc_cv18xx_ops = { + .get_max_clock = dwcmshc_get_max_clock, + .reset = cv18xx_sdhci_reset, + .adma_write_desc = dwcmshc_adma_write_desc, ++ .platform_execute_tuning = cv18xx_sdhci_execute_tuning, + }; + + static const struct sdhci_pltfm_data sdhci_dwcmshc_pdata = { +-- +2.20.1 + diff --git a/target/linux/cv18x0/patches-6.6/0020-riscv-dts-sophgo-use-real-clock-for-sdhci.patch b/target/linux/cv18x0/patches-6.6/0020-riscv-dts-sophgo-use-real-clock-for-sdhci.patch new file mode 100644 index 0000000000..6f59e9621e --- /dev/null +++ b/target/linux/cv18x0/patches-6.6/0020-riscv-dts-sophgo-use-real-clock-for-sdhci.patch @@ -0,0 +1,48 @@ +From 72218d886b6719110e2b07be648ca702e696d1d6 Mon Sep 17 00:00:00 2001 +From: Inochi Amaoto +Date: Thu, 11 Apr 2024 20:21:35 +0800 +Subject: [PATCH 20/20] riscv: dts: sophgo: use real clock for sdhci + +As the clk patch is merged, Use real clocks for sdhci0. + +Reviewed-by: Chen Wang +Link: https://lore.kernel.org/r/IA1PR20MB4953CA5D46EA8913B130D502BB052@IA1PR20MB4953.namprd20.prod.outlook.com +Signed-off-by: Inochi Amaoto +Signed-off-by: Chen Wang +--- + arch/riscv/boot/dts/sophgo/cv18xx.dtsi | 12 +++--------- + 1 file changed, 3 insertions(+), 9 deletions(-) + +diff --git a/arch/riscv/boot/dts/sophgo/cv18xx.dtsi b/arch/riscv/boot/dts/sophgo/cv18xx.dtsi +index e87df337ec68..786a31617eca 100644 +--- a/arch/riscv/boot/dts/sophgo/cv18xx.dtsi ++++ b/arch/riscv/boot/dts/sophgo/cv18xx.dtsi +@@ -49,13 +49,6 @@ + #clock-cells = <0>; + }; + +- sdhci_clk: sdhci-clock { +- compatible = "fixed-clock"; +- clock-frequency = <375000000>; +- clock-output-names = "sdhci_clk"; +- #clock-cells = <0>; +- }; +- + soc { + compatible = "simple-bus"; + interrupt-parent = <&plic>; +@@ -212,8 +205,9 @@ + compatible = "sophgo,cv1800b-dwcmshc"; + reg = <0x4310000 0x1000>; + interrupts = <36 IRQ_TYPE_LEVEL_HIGH>; +- clocks = <&sdhci_clk>; +- clock-names = "core"; ++ clocks = <&clk CLK_AXI4_SD0>, ++ <&clk CLK_SD0>; ++ clock-names = "core", "bus"; + status = "disabled"; + }; + +-- +2.20.1 + -- 2.30.2