From 2d96aba3468747270155caed20d025bf3958678c Mon Sep 17 00:00:00 2001 From: Marvin Lin Date: Wed, 18 Sep 2024 16:36:43 +0800 Subject: [PATCH] yosemite4: Initial commit for meta-yosemite4n Summary: - Add the meta-yosemite4n layer for Nuvoton management board. This is a Linux Foundation-based machine and already upstream. - Add an u-boot patch for factory memory testing purpose. - Add kernel driver patches that are still under upstream review. - Add an entity-manager patch for i3c interface. - cpld-fw-handler: enable update-ebr-init. Signed-off-by: Joseph Liu Signed-off-by: Marvin Lin --- .../linux/linux-nuvoton_%.bbappend | 6 + .../meta-yosemite4n/conf/layer.conf | 14 + .../conf/machine/yosemite4n.conf | 0 .../templates/default/bblayers.conf.sample | 25 + .../conf/templates/default/conf-notes.txt | 2 + .../conf/templates/default/local.conf.sample | 5 + ...-result-of-mtest-to-enviroment-varia.patch | 46 + .../u-boot/u-boot-nuvoton_%.bbappend | 4 + .../recipes-core/images/yosemite4n-image.bb | 3 + .../cpld-fw-handler_%.bbappend | 2 + ...k-npcm845-Add-reference-25m-clock-pr.patch | 89 + ...odify-clock-property-in-modules-node.patch | 136 + ...x-move-the-clk-handler-node-to-the-r.patch | 44 + ...xx-add-pin-and-gpio-controller-nodes.patch | 739 +++++ ...dts-nuvoton-npcm8xx-add-modules-node.patch | 1202 ++++++++ ...n-add-initial-yosemitev4-device-tree.patch | 2321 ++++++++++++++++ ...t-stmmac-Add-NCSI-support-for-STMMAC.patch | 409 +++ ...-fiu-add-dual-and-quad-write-support.patch | 67 + ...-fiu-add-delay-before-reboot-to-avoi.patch | 56 + ...pi-npcm-pspi-Add-full-duplex-support.patch | 145 + ...Fix-transfer-bits-per-word-issue-389.patch | 66 + ...idea-udc-enforce-write-to-the-memory.patch | 61 + ...-interrupt-enable-bit-before-devm_re.patch | 98 + ...022-i2c-npcm-use-i2c-frequency-table.patch | 292 ++ ...oftware-flag-to-indicate-a-BER-condi.patch | 68 + ...-Modify-timeout-evaluation-mechanism.patch | 69 + ...Modify-the-client-address-assignment.patch | 36 + ...m7xx.c-Enable-slave-in-eob-interrupt.patch | 40 + ...t-the-read-write-operation-procedure.patch | 41 + ...npcm-Return-EAGAIN-while-bus-is-busy.patch | 38 + ...g-master-Add-NPCM845-JTAG-master-dri.patch | 984 +++++++ ...dd-Nuvoton-npcm845-i3c-master-driver.patch | 2459 +++++++++++++++++ ...dings-i3c-Add-NPCM845-i3c-controller.patch | 144 + ...npcm-add-a-support-to-get-reset-casu.patch | 196 ++ ...pose-interface-for-doing-daa-request.patch | 50 + .../linux/linux-nuvoton_%.bbappend | 56 + .../entity-manager_git.bbappend | 5 + ...4-set-mctp-i3c-information-for-SD-an.patch | 127 + openbmc-init-build-env | 1 + tools/platforms/platform_build_names | 3 +- 40 files changed, 10148 insertions(+), 1 deletion(-) create mode 100644 common/recipes-kernel/linux/linux-nuvoton_%.bbappend create mode 100644 meta-facebook/meta-yosemite4/meta-yosemite4n/conf/layer.conf create mode 100644 meta-facebook/meta-yosemite4/meta-yosemite4n/conf/machine/yosemite4n.conf create mode 100644 meta-facebook/meta-yosemite4/meta-yosemite4n/conf/templates/default/bblayers.conf.sample create mode 100644 meta-facebook/meta-yosemite4/meta-yosemite4n/conf/templates/default/conf-notes.txt create mode 100644 meta-facebook/meta-yosemite4/meta-yosemite4n/conf/templates/default/local.conf.sample create mode 100644 meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-bsp/u-boot/u-boot-nuvoton/0100-cmd-mem-set-test-result-of-mtest-to-enviroment-varia.patch create mode 100644 meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-bsp/u-boot/u-boot-nuvoton_%.bbappend create mode 100644 meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-core/images/yosemite4n-image.bb create mode 100644 meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-facebook/cpld-fw-handler/cpld-fw-handler_%.bbappend create mode 100644 meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1000-dt-bindings-clock-npcm845-Add-reference-25m-clock-pr.patch create mode 100644 meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1001-arm64-dts-modify-clock-property-in-modules-node.patch create mode 100644 meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1002-arm64-dts-npmc8xx-move-the-clk-handler-node-to-the-r.patch create mode 100644 meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1003-arm64-dts-nuvoton-npcm8xx-add-pin-and-gpio-controller-nodes.patch create mode 100644 meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1004-arm64-dts-nuvoton-npcm8xx-add-modules-node.patch create mode 100644 meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1005-arm64-dts-nuvoton-add-initial-yosemitev4-device-tree.patch create mode 100644 meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1015-net-stmmac-Add-NCSI-support-for-STMMAC.patch create mode 100644 meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1016-spi-npcm-fiu-add-dual-and-quad-write-support.patch create mode 100644 meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1017-spi-npcm-fiu-add-delay-before-reboot-to-avoi.patch create mode 100644 meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1018-spi-npcm-pspi-Add-full-duplex-support.patch create mode 100644 meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1019-spi-npcm-pspi-Fix-transfer-bits-per-word-issue-389.patch create mode 100644 meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1020-usb-chipidea-udc-enforce-write-to-the-memory.patch create mode 100644 meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1021-i2c-npcm-disable-interrupt-enable-bit-before-devm_re.patch create mode 100644 meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1022-i2c-npcm-use-i2c-frequency-table.patch create mode 100644 meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1023-i2c-npcm-use-a-software-flag-to-indicate-a-BER-condi.patch create mode 100644 meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1024-i2c-npcm-Modify-timeout-evaluation-mechanism.patch create mode 100644 meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1025-i2c-npcm-Modify-the-client-address-assignment.patch create mode 100644 meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1026-i2c-npcm7xx.c-Enable-slave-in-eob-interrupt.patch create mode 100644 meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1027-i2c-npcm-correct-the-read-write-operation-procedure.patch create mode 100644 meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1028-i2c-npcm-Return-EAGAIN-while-bus-is-busy.patch create mode 100644 meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1030-misc-npcm8xx-jtag-master-Add-NPCM845-JTAG-master-dri.patch create mode 100644 meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1035-i3c-master-Add-Nuvoton-npcm845-i3c-master-driver.patch create mode 100644 meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1036-dt-bindings-i3c-Add-NPCM845-i3c-controller.patch create mode 100644 meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1040-driver-watchdog-npcm-add-a-support-to-get-reset-casu.patch create mode 100644 meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1042-i3c-expose-interface-for-doing-daa-request.patch create mode 100644 meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton_%.bbappend create mode 100644 meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-phosphor/entity-manager/entity-manager_git.bbappend create mode 100644 meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-phosphor/entity-manager/files/0100-configuration-yv4-set-mctp-i3c-information-for-SD-an.patch diff --git a/common/recipes-kernel/linux/linux-nuvoton_%.bbappend b/common/recipes-kernel/linux/linux-nuvoton_%.bbappend new file mode 100644 index 00000000000..ff636a76c6f --- /dev/null +++ b/common/recipes-kernel/linux/linux-nuvoton_%.bbappend @@ -0,0 +1,6 @@ +FILESEXTRAPATHS:prepend := "${THISDIR}/6.6:" + +LINUX_NUVOTON_PATCHES_INC ?= "" +LINUX_NUVOTON_PATCHES_INC:openbmc-fb-lf = "linux-patches-6.6.inc" + +include ${LINUX_NUVOTON_PATCHES_INC} diff --git a/meta-facebook/meta-yosemite4/meta-yosemite4n/conf/layer.conf b/meta-facebook/meta-yosemite4/meta-yosemite4n/conf/layer.conf new file mode 100644 index 00000000000..c72bcaf79d1 --- /dev/null +++ b/meta-facebook/meta-yosemite4/meta-yosemite4n/conf/layer.conf @@ -0,0 +1,14 @@ +# We have a conf and classes directory, add to BBPATH +BBPATH .= ":${LAYERDIR}" + +# We have recipes-* directories, add to BBFILES +BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \ + ${LAYERDIR}/recipes-*/*/*.bbappend" + +# Ignore bbappend related to ASPEED in meta-yosemite4 +BBMASK += ".*aspeed.*\.bbappend" + +BBFILE_COLLECTIONS += "fb-yosemite4n-layer" +BBFILE_PATTERN_fb-yosemite4n-layer := "^${LAYERDIR}/" +LAYERVERSION_fb-yosemite4n-layer = "1" +LAYERSERIES_COMPAT_fb-yosemite4n-layer = "scarthgap nanbield kirkstone" diff --git a/meta-facebook/meta-yosemite4/meta-yosemite4n/conf/machine/yosemite4n.conf b/meta-facebook/meta-yosemite4/meta-yosemite4n/conf/machine/yosemite4n.conf new file mode 100644 index 00000000000..e69de29bb2d diff --git a/meta-facebook/meta-yosemite4/meta-yosemite4n/conf/templates/default/bblayers.conf.sample b/meta-facebook/meta-yosemite4/meta-yosemite4n/conf/templates/default/bblayers.conf.sample new file mode 100644 index 00000000000..290bd3bbda8 --- /dev/null +++ b/meta-facebook/meta-yosemite4/meta-yosemite4n/conf/templates/default/bblayers.conf.sample @@ -0,0 +1,25 @@ +# LAYER_CONF_VERSION is increased each time build/conf/bblayers.conf +# changes incompatibly +LCONF_VERSION = "8" + +BBPATH = "${TOPDIR}" +BBFILES ?= "" + +BBLAYERS ?= " \ + ##OEROOT##/meta \ + ##OEROOT##/meta-openembedded/meta-oe \ + ##OEROOT##/meta-openembedded/meta-networking \ + ##OEROOT##/meta-openembedded/meta-python \ + ##OEROOT##/meta-security/meta-tpm \ + ##OEROOT##/meta-phosphor \ + ##OEROOT##/meta-arm/meta-arm \ + ##OEROOT##/meta-arm/meta-arm-toolchain \ + ##OEROOT##/meta-nuvoton \ + ##OEROOT##/meta-facebook \ + ##OEROOT##/meta-facebook/meta-yosemite4 \ + ##OEROOT##/meta-facebook/meta-yosemite4/meta-yosemite4n \ + ##OEROOT##/../.. \ + ##OEROOT##/../../meta-facebook \ + ##OEROOT##/../../meta-facebook/meta-yosemite4 \ + ##OEROOT##/../../meta-facebook/meta-yosemite4/meta-yosemite4n \ + " diff --git a/meta-facebook/meta-yosemite4/meta-yosemite4n/conf/templates/default/conf-notes.txt b/meta-facebook/meta-yosemite4/meta-yosemite4n/conf/templates/default/conf-notes.txt new file mode 100644 index 00000000000..fc08a9d3328 --- /dev/null +++ b/meta-facebook/meta-yosemite4/meta-yosemite4n/conf/templates/default/conf-notes.txt @@ -0,0 +1,2 @@ +Common targets are: + yosemite4n-image diff --git a/meta-facebook/meta-yosemite4/meta-yosemite4n/conf/templates/default/local.conf.sample b/meta-facebook/meta-yosemite4/meta-yosemite4n/conf/templates/default/local.conf.sample new file mode 100644 index 00000000000..26c036b1582 --- /dev/null +++ b/meta-facebook/meta-yosemite4/meta-yosemite4n/conf/templates/default/local.conf.sample @@ -0,0 +1,5 @@ +# +# Local configuration file for building the OpenBMC image. +# +MACHINE ??= "yosemite4n" +DISTRO ?= "openbmc-fb-lf" diff --git a/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-bsp/u-boot/u-boot-nuvoton/0100-cmd-mem-set-test-result-of-mtest-to-enviroment-varia.patch b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-bsp/u-boot/u-boot-nuvoton/0100-cmd-mem-set-test-result-of-mtest-to-enviroment-varia.patch new file mode 100644 index 00000000000..7a4d01f3b01 --- /dev/null +++ b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-bsp/u-boot/u-boot-nuvoton/0100-cmd-mem-set-test-result-of-mtest-to-enviroment-varia.patch @@ -0,0 +1,46 @@ +From fd6c1631c9075161df703e7928063f4acf498113 Mon Sep 17 00:00:00 2001 +From: RickyWu-wiwynn +Date: Mon, 8 Apr 2024 18:07:34 +0800 +Subject: [PATCH] cmd: mem: set test result of mtest to enviroment variable + +--- + cmd/mem.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/cmd/mem.c b/cmd/mem.c +index 5f4e865462..4dee413fea 100644 +--- a/cmd/mem.c ++++ b/cmd/mem.c +@@ -1204,6 +1204,15 @@ static ulong mem_test_quick(vu_long *buf, ulong start_addr, ulong end_addr, + static int do_mem_mtest(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) + { ++ char *is_done; ++ is_done = env_get("memtest_result"); ++ if (is_done != NULL) { ++ env_set("memtest_result", ""); ++ env_set("preboot", ""); ++ env_save(); ++ return 0; ++ } ++ + ulong start, end; + vu_long scratch_space; + vu_long *buf, *dummy = &scratch_space; +@@ -1273,6 +1282,13 @@ static int do_mem_mtest(struct cmd_tbl *cmdtp, int flag, int argc, + + printf("\nTested %d iteration(s) with %lu errors.\n", iteration, count); + ++ if (errs == 0) { ++ env_set("memtest_result", "pass"); ++ } else { ++ env_set("memtest_result", "fail"); ++ } ++ env_save(); ++ + return errs != 0; + } + #endif /* CONFIG_CMD_MEMTEST */ +-- +2.25.1 + diff --git a/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-bsp/u-boot/u-boot-nuvoton_%.bbappend b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-bsp/u-boot/u-boot-nuvoton_%.bbappend new file mode 100644 index 00000000000..e05b68cedbf --- /dev/null +++ b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-bsp/u-boot/u-boot-nuvoton_%.bbappend @@ -0,0 +1,4 @@ +FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:" + +SRC_URI:append = " file://0100-cmd-mem-set-test-result-of-mtest-to-enviroment-varia.patch" + diff --git a/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-core/images/yosemite4n-image.bb b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-core/images/yosemite4n-image.bb new file mode 100644 index 00000000000..97656f34491 --- /dev/null +++ b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-core/images/yosemite4n-image.bb @@ -0,0 +1,3 @@ +require recipes-core/images/yosemite4-image.bb + +IMAGE_INSTALL:remove = " packagegroup-openbmc-tests2" diff --git a/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-facebook/cpld-fw-handler/cpld-fw-handler_%.bbappend b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-facebook/cpld-fw-handler/cpld-fw-handler_%.bbappend new file mode 100644 index 00000000000..b660ed6e9fc --- /dev/null +++ b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-facebook/cpld-fw-handler/cpld-fw-handler_%.bbappend @@ -0,0 +1,2 @@ +EXTRA_OEMESON:append = " -Dupdate-ebr-init=enabled" + diff --git a/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1000-dt-bindings-clock-npcm845-Add-reference-25m-clock-pr.patch b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1000-dt-bindings-clock-npcm845-Add-reference-25m-clock-pr.patch new file mode 100644 index 00000000000..fc0bd64d929 --- /dev/null +++ b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1000-dt-bindings-clock-npcm845-Add-reference-25m-clock-pr.patch @@ -0,0 +1,89 @@ +From 9f903328f2169a1d058418a2e49cbe164584b9d9 Mon Sep 17 00:00:00 2001 +From: Tomer Maimon +Date: Mon, 1 Jul 2024 10:10:44 +0300 +Subject: [PATCH] dt-bindings: clock: npcm845: Add reference 25m clock property + +The NPCM8XX clock driver uses a 25Mhz external clock, therefore adding +clock property. + +The new required clock property does not break the NPCM8XX clock ABI +since the NPCM8XX clock driver hasn't merged yet to the Linux vanilla. + +This change is also contributing to lf-openbmc upstream for reviewing. +Lore Link: https://lore.kernel.org/all/20240701071048.751863-3-tmaimon77@gmail.com/ + +Signed-off-by: Tomer Maimon +--- + arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi | 9 +++++---- + arch/arm64/boot/dts/nuvoton/nuvoton-npcm845-evb.dts | 7 +++++++ + 2 files changed, 12 insertions(+), 4 deletions(-) + +diff --git a/arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi b/arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi +index ecd171b2feba..41d345448430 100644 +--- a/arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi ++++ b/arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi +@@ -52,6 +52,7 @@ rstc: reset-controller@f0801000 { + reg = <0x0 0xf0801000 0x0 0x78>; + #reset-cells = <2>; + nuvoton,sysgcr = <&gcr>; ++ clocks = <&refclk>; + }; + + clk: clock-controller@f0801000 { +@@ -81,7 +82,7 @@ timer0: timer@8000 { + compatible = "nuvoton,npcm845-timer"; + interrupts = ; + reg = <0x8000 0x1C>; +- clocks = <&clk NPCM8XX_CLK_REFCLK>; ++ clocks = <&refclk>; + clock-names = "refclk"; + }; + +@@ -153,7 +154,7 @@ watchdog0: watchdog@801c { + interrupts = ; + reg = <0x801c 0x4>; + status = "disabled"; +- clocks = <&clk NPCM8XX_CLK_REFCLK>; ++ clocks = <&refclk>; + syscon = <&gcr>; + }; + +@@ -162,7 +163,7 @@ watchdog1: watchdog@901c { + interrupts = ; + reg = <0x901c 0x4>; + status = "disabled"; +- clocks = <&clk NPCM8XX_CLK_REFCLK>; ++ clocks = <&refclk>; + syscon = <&gcr>; + }; + +@@ -171,7 +172,7 @@ watchdog2: watchdog@a01c { + interrupts = ; + reg = <0xa01c 0x4>; + status = "disabled"; +- clocks = <&clk NPCM8XX_CLK_REFCLK>; ++ clocks = <&refclk>; + syscon = <&gcr>; + }; + }; +diff --git a/arch/arm64/boot/dts/nuvoton/nuvoton-npcm845-evb.dts b/arch/arm64/boot/dts/nuvoton/nuvoton-npcm845-evb.dts +index a5ab2bc0f835..83c2f4e138e5 100644 +--- a/arch/arm64/boot/dts/nuvoton/nuvoton-npcm845-evb.dts ++++ b/arch/arm64/boot/dts/nuvoton/nuvoton-npcm845-evb.dts +@@ -19,6 +19,13 @@ chosen { + memory { + reg = <0x0 0x0 0x0 0x40000000>; + }; ++ ++ refclk: refclk-25mhz { ++ compatible = "fixed-clock"; ++ clock-output-names = "ref"; ++ clock-frequency = <25000000>; ++ #clock-cells = <0>; ++ }; + }; + + &serial0 { +-- +2.34.1 + diff --git a/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1001-arm64-dts-modify-clock-property-in-modules-node.patch b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1001-arm64-dts-modify-clock-property-in-modules-node.patch new file mode 100644 index 00000000000..83cf53191f0 --- /dev/null +++ b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1001-arm64-dts-modify-clock-property-in-modules-node.patch @@ -0,0 +1,136 @@ +From 7ada4b7e39819f2cc765b27f3fc1ad38ece3278f Mon Sep 17 00:00:00 2001 +From: Tomer Maimon +Date: Mon, 1 Jul 2024 10:10:46 +0300 +Subject: [PATCH] arm64: dts: modify clock property in modules node + +Modify clock property handler in UART, CPU, PECI modules to reset +controller. + +This change is also contributing to lf-openbmc upstream for reviewing. +Lore Link: https://lore.kernel.org/all/20240701071048.751863-5-tmaimon77@gmail.com/ + +Signed-off-by: Tomer Maimon +--- + .../boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi | 16 ++++++++-------- + arch/arm64/boot/dts/nuvoton/nuvoton-npcm845.dtsi | 8 ++++---- + 2 files changed, 12 insertions(+), 12 deletions(-) + +diff --git a/arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi b/arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi +index 41d345448430..92e3b0fe746f 100644 +--- a/arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi ++++ b/arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi +@@ -73,7 +73,7 @@ peci: peci-controller@100000 { + compatible = "nuvoton,npcm845-peci"; + reg = <0x100000 0x1000>; + interrupts = ; +- clocks = <&clk NPCM8XX_CLK_APB3>; ++ clocks = <&rstc NPCM8XX_CLK_APB3>; + cmd-timeout-ms = <1000>; + status = "disabled"; + }; +@@ -89,7 +89,7 @@ timer0: timer@8000 { + serial0: serial@0 { + compatible = "nuvoton,npcm845-uart", "nuvoton,npcm750-uart"; + reg = <0x0 0x1000>; +- clocks = <&clk NPCM8XX_CLK_UART>; ++ clocks = <&rstc NPCM8XX_CLK_UART>; + interrupts = ; + reg-shift = <2>; + status = "disabled"; +@@ -98,7 +98,7 @@ serial0: serial@0 { + serial1: serial@1000 { + compatible = "nuvoton,npcm845-uart", "nuvoton,npcm750-uart"; + reg = <0x1000 0x1000>; +- clocks = <&clk NPCM8XX_CLK_UART>; ++ clocks = <&rstc NPCM8XX_CLK_UART>; + interrupts = ; + reg-shift = <2>; + status = "disabled"; +@@ -107,7 +107,7 @@ serial1: serial@1000 { + serial2: serial@2000 { + compatible = "nuvoton,npcm845-uart", "nuvoton,npcm750-uart"; + reg = <0x2000 0x1000>; +- clocks = <&clk NPCM8XX_CLK_UART>; ++ clocks = <&rstc NPCM8XX_CLK_UART>; + interrupts = ; + reg-shift = <2>; + status = "disabled"; +@@ -116,7 +116,7 @@ serial2: serial@2000 { + serial3: serial@3000 { + compatible = "nuvoton,npcm845-uart", "nuvoton,npcm750-uart"; + reg = <0x3000 0x1000>; +- clocks = <&clk NPCM8XX_CLK_UART>; ++ clocks = <&rstc NPCM8XX_CLK_UART>; + interrupts = ; + reg-shift = <2>; + status = "disabled"; +@@ -125,7 +125,7 @@ serial3: serial@3000 { + serial4: serial@4000 { + compatible = "nuvoton,npcm845-uart", "nuvoton,npcm750-uart"; + reg = <0x4000 0x1000>; +- clocks = <&clk NPCM8XX_CLK_UART>; ++ clocks = <&rstc NPCM8XX_CLK_UART>; + interrupts = ; + reg-shift = <2>; + status = "disabled"; +@@ -134,7 +134,7 @@ serial4: serial@4000 { + serial5: serial@5000 { + compatible = "nuvoton,npcm845-uart", "nuvoton,npcm750-uart"; + reg = <0x5000 0x1000>; +- clocks = <&clk NPCM8XX_CLK_UART>; ++ clocks = <&rstc NPCM8XX_CLK_UART>; + interrupts = ; + reg-shift = <2>; + status = "disabled"; +@@ -143,7 +143,7 @@ serial5: serial@5000 { + serial6: serial@6000 { + compatible = "nuvoton,npcm845-uart", "nuvoton,npcm750-uart"; + reg = <0x6000 0x1000>; +- clocks = <&clk NPCM8XX_CLK_UART>; ++ clocks = <&rstc NPCM8XX_CLK_UART2>; + interrupts = ; + reg-shift = <2>; + status = "disabled"; +diff --git a/arch/arm64/boot/dts/nuvoton/nuvoton-npcm845.dtsi b/arch/arm64/boot/dts/nuvoton/nuvoton-npcm845.dtsi +index 383938dcd3ce..3cbcea65eba2 100644 +--- a/arch/arm64/boot/dts/nuvoton/nuvoton-npcm845.dtsi ++++ b/arch/arm64/boot/dts/nuvoton/nuvoton-npcm845.dtsi +@@ -14,7 +14,7 @@ cpus { + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a35"; +- clocks = <&clk NPCM8XX_CLK_CPU>; ++ clocks = <&rstc NPCM8XX_CLK_CPU>; + reg = <0x0 0x0>; + next-level-cache = <&l2>; + enable-method = "psci"; +@@ -23,7 +23,7 @@ cpu0: cpu@0 { + cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a35"; +- clocks = <&clk NPCM8XX_CLK_CPU>; ++ clocks = <&rstc NPCM8XX_CLK_CPU>; + reg = <0x0 0x1>; + next-level-cache = <&l2>; + enable-method = "psci"; +@@ -32,7 +32,7 @@ cpu1: cpu@1 { + cpu2: cpu@2 { + device_type = "cpu"; + compatible = "arm,cortex-a35"; +- clocks = <&clk NPCM8XX_CLK_CPU>; ++ clocks = <&rstc NPCM8XX_CLK_CPU>; + reg = <0x0 0x2>; + next-level-cache = <&l2>; + enable-method = "psci"; +@@ -41,7 +41,7 @@ cpu2: cpu@2 { + cpu3: cpu@3 { + device_type = "cpu"; + compatible = "arm,cortex-a35"; +- clocks = <&clk NPCM8XX_CLK_CPU>; ++ clocks = <&rstc NPCM8XX_CLK_CPU>; + reg = <0x0 0x3>; + next-level-cache = <&l2>; + enable-method = "psci"; +-- +2.34.1 + diff --git a/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1002-arm64-dts-npmc8xx-move-the-clk-handler-node-to-the-r.patch b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1002-arm64-dts-npmc8xx-move-the-clk-handler-node-to-the-r.patch new file mode 100644 index 00000000000..f6fee6cb38e --- /dev/null +++ b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1002-arm64-dts-npmc8xx-move-the-clk-handler-node-to-the-r.patch @@ -0,0 +1,44 @@ +From d197b1fdad05c195a1f40c4575d9b9b802e7ced1 Mon Sep 17 00:00:00 2001 +From: Tomer Maimon +Date: Mon, 1 Jul 2024 10:10:45 +0300 +Subject: [PATCH] arm64: dts: npmc8xx: move the clk handler node to the reset + node + +Add clk handler node to the reset node and removing the clock node +driver since the reset driver is register the NPCM8xx clock controller +aux device. + +We will contribute to lf-openbmc upstream for reviewing. + +Signed-off-by: Tomer Maimon +--- + arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi b/arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi +index 92e3b0fe746f..01daf0615ccc 100644 +--- a/arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi ++++ b/arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi +@@ -47,18 +47,13 @@ ahb { + interrupt-parent = <&gic>; + ranges; + +- rstc: reset-controller@f0801000 { ++ clk: rstc: reset-controller@f0801000 { + compatible = "nuvoton,npcm845-reset"; + reg = <0x0 0xf0801000 0x0 0x78>; + #reset-cells = <2>; + nuvoton,sysgcr = <&gcr>; + clocks = <&refclk>; +- }; +- +- clk: clock-controller@f0801000 { +- compatible = "nuvoton,npcm845-clk"; + #clock-cells = <1>; +- reg = <0x0 0xf0801000 0x0 0x1000>; + }; + + apb { +-- +2.34.1 + diff --git a/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1003-arm64-dts-nuvoton-npcm8xx-add-pin-and-gpio-controller-nodes.patch b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1003-arm64-dts-nuvoton-npcm8xx-add-pin-and-gpio-controller-nodes.patch new file mode 100644 index 00000000000..7db717e9758 --- /dev/null +++ b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1003-arm64-dts-nuvoton-npcm8xx-add-pin-and-gpio-controller-nodes.patch @@ -0,0 +1,739 @@ +From 29326d7d47e2de9cddabcaf748a5a7dd10ac8023 Mon Sep 17 00:00:00 2001 +From: Tomer Maimon +Date: Sun, 14 Jul 2024 18:26:16 +0300 +Subject: [PATCH] arm64: dts: nuvoton: npcm8xx: add pin and gpio controller + nodes + +Add BMC Nuvoton NPCM8XX pin and GPIO controller nodes. + +The Pin controller node includes eight GPIO controller nodes, each GPIO +node control 32 GPIO. + +This change is also contributing to lf-openbmc upstream for reviewing. +Lore Link: https://lore.kernel.org/all/20240714152617.3055768-2-tmaimon77@gmail.com/ + +Signed-off-by: Tomer Maimon +--- + .../dts/nuvoton/nuvoton-common-npcm8xx.dtsi | 701 +++++++++++++++++- + 1 file changed, 700 insertions(+), 1 deletion(-) + +diff --git a/arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi b/arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi +index ed9f0edf1888..aa90a22dc78f 100644 +--- a/arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi ++++ b/arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi +@@ -4,6 +4,7 @@ + #include + #include + #include ++#include + + / { + #address-cells = <2>; +@@ -178,4 +179,702 @@ watchdog2: watchdog@a01c { + }; + }; + }; +-}; ++ ++ pinctrl: pinctrl@f0010000 { ++ compatible = "nuvoton,npcm845-pinctrl"; ++ ranges = <0x0 0x0 0xf0010000 0x8000>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ nuvoton,sysgcr = <&gcr>; ++ ++ gpio0: gpio@f0010000 { ++ gpio-controller; ++ #gpio-cells = <2>; ++ reg = <0x0 0xB0>; ++ interrupts = ; ++ gpio-ranges = <&pinctrl 0 0 32>; ++ }; ++ gpio1: gpio@f0011000 { ++ gpio-controller; ++ #gpio-cells = <2>; ++ reg = <0x1000 0xB0>; ++ interrupts = ; ++ gpio-ranges = <&pinctrl 0 32 32>; ++ }; ++ gpio2: gpio@f0012000 { ++ gpio-controller; ++ #gpio-cells = <2>; ++ reg = <0x2000 0xB0>; ++ interrupts = ; ++ gpio-ranges = <&pinctrl 0 64 32>; ++ }; ++ gpio3: gpio@f0013000 { ++ gpio-controller; ++ #gpio-cells = <2>; ++ reg = <0x3000 0xB0>; ++ interrupts = ; ++ gpio-ranges = <&pinctrl 0 96 32>; ++ }; ++ gpio4: gpio@f0014000 { ++ gpio-controller; ++ #gpio-cells = <2>; ++ reg = <0x4000 0xB0>; ++ interrupts = ; ++ gpio-ranges = <&pinctrl 0 128 32>; ++ }; ++ gpio5: gpio@f0015000 { ++ gpio-controller; ++ #gpio-cells = <2>; ++ reg = <0x5000 0xB0>; ++ interrupts = ; ++ gpio-ranges = <&pinctrl 0 160 32>; ++ }; ++ gpio6: gpio@f0016000 { ++ gpio-controller; ++ #gpio-cells = <2>; ++ reg = <0x6000 0xB0>; ++ interrupts = ; ++ gpio-ranges = <&pinctrl 0 192 32>; ++ }; ++ gpio7: gpio@f0017000 { ++ gpio-controller; ++ #gpio-cells = <2>; ++ reg = <0x7000 0xB0>; ++ interrupts = ; ++ gpio-ranges = <&pinctrl 0 224 32>; ++ }; ++ ++ iox1_pins: iox1-mux { ++ groups = "iox1"; ++ function = "iox1"; ++ }; ++ iox2_pins: iox2-mux { ++ groups = "iox2"; ++ function = "iox2"; ++ }; ++ smb1d_pins: smb1d-mux { ++ groups = "smb1d"; ++ function = "smb1d"; ++ }; ++ smb2d_pins: smb2d-mux { ++ groups = "smb2d"; ++ function = "smb2d"; ++ }; ++ lkgpo1_pins: lkgpo1-mux { ++ groups = "lkgpo1"; ++ function = "lkgpo1"; ++ }; ++ lkgpo2_pins: lkgpo2-mux { ++ groups = "lkgpo2"; ++ function = "lkgpo2"; ++ }; ++ ioxh_pins: ioxh-mux { ++ groups = "ioxh"; ++ function = "ioxh"; ++ }; ++ gspi_pins: gspi-mux { ++ groups = "gspi"; ++ function = "gspi"; ++ }; ++ smb5b_pins: smb5b-mux { ++ groups = "smb5b"; ++ function = "smb5b"; ++ }; ++ smb5c_pins: smb5c-mux { ++ groups = "smb5c"; ++ function = "smb5c"; ++ }; ++ lkgpo0_pins: lkgpo0-mux { ++ groups = "lkgpo0"; ++ function = "lkgpo0"; ++ }; ++ pspi_pins: pspi-mux { ++ groups = "pspi"; ++ function = "pspi"; ++ }; ++ jm1_pins: jm1-mux { ++ groups = "jm1"; ++ function = "jm1"; ++ }; ++ jm2_pins: jm2-mux { ++ groups = "jm2"; ++ function = "jm2"; ++ }; ++ smb4b_pins: smb4b-mux { ++ groups = "smb4b"; ++ function = "smb4b"; ++ }; ++ smb4c_pins: smb4c-mux { ++ groups = "smb4c"; ++ function = "smb4c"; ++ }; ++ smb15_pins: smb15-mux { ++ groups = "smb15"; ++ function = "smb15"; ++ }; ++ smb16_pins: smb16-mux { ++ groups = "smb16"; ++ function = "smb16"; ++ }; ++ smb17_pins: smb17-mux { ++ groups = "smb17"; ++ function = "smb17"; ++ }; ++ smb18_pins: smb18-mux { ++ groups = "smb18"; ++ function = "smb18"; ++ }; ++ smb19_pins: smb19-mux { ++ groups = "smb19"; ++ function = "smb19"; ++ }; ++ smb20_pins: smb20-mux { ++ groups = "smb20"; ++ function = "smb20"; ++ }; ++ smb21_pins: smb21-mux { ++ groups = "smb21"; ++ function = "smb21"; ++ }; ++ smb22_pins: smb22-mux { ++ groups = "smb22"; ++ function = "smb22"; ++ }; ++ smb23_pins: smb23-mux { ++ groups = "smb23"; ++ function = "smb23"; ++ }; ++ smb4d_pins: smb4d-mux { ++ groups = "smb4d"; ++ function = "smb4d"; ++ }; ++ smb14_pins: smb14-mux { ++ groups = "smb14"; ++ function = "smb14"; ++ }; ++ smb5_pins: smb5-mux { ++ groups = "smb5"; ++ function = "smb5"; ++ }; ++ smb4_pins: smb4-mux { ++ groups = "smb4"; ++ function = "smb4"; ++ }; ++ smb3_pins: smb3-mux { ++ groups = "smb3"; ++ function = "smb3"; ++ }; ++ spi0cs1_pins: spi0cs1-mux { ++ groups = "spi0cs1"; ++ function = "spi0cs1"; ++ }; ++ spi0cs2_pins: spi0cs2-mux { ++ groups = "spi0cs2"; ++ function = "spi0cs2"; ++ }; ++ spi0cs3_pins: spi0cs3-mux { ++ groups = "spi0cs3"; ++ function = "spi0cs3"; ++ }; ++ smb3c_pins: smb3c-mux { ++ groups = "smb3c"; ++ function = "smb3c"; ++ }; ++ smb3b_pins: smb3b-mux { ++ groups = "smb3b"; ++ function = "smb3b"; ++ }; ++ bmcuart0a_pins: bmcuart0a-mux { ++ groups = "bmcuart0a"; ++ function = "bmcuart0a"; ++ }; ++ uart1_pins: uart1-mux { ++ groups = "uart1"; ++ function = "uart1"; ++ }; ++ jtag2_pins: jtag2-mux { ++ groups = "jtag2"; ++ function = "jtag2"; ++ }; ++ bmcuart1_pins: bmcuart1-mux { ++ groups = "bmcuart1"; ++ function = "bmcuart1"; ++ }; ++ uart2_pins: uart2-mux { ++ groups = "uart2"; ++ function = "uart2"; ++ }; ++ bmcuart0b_pins: bmcuart0b-mux { ++ groups = "bmcuart0b"; ++ function = "bmcuart0b"; ++ }; ++ r1err_pins: r1err-mux { ++ groups = "r1err"; ++ function = "r1err"; ++ }; ++ r1md_pins: r1md-mux { ++ groups = "r1md"; ++ function = "r1md"; ++ }; ++ r1oen_pins: r1oen-mux { ++ groups = "r1oen"; ++ function = "r1oen"; ++ }; ++ r2oen_pins: r2oen-mux { ++ groups = "r2oen"; ++ function = "r2oen"; ++ }; ++ rmii3_pins: rmii3-mux { ++ groups = "rmii3"; ++ function = "rmii3"; ++ }; ++ r3oen_pins: r3oen-mux { ++ groups = "r3oen"; ++ function = "r3oen"; ++ }; ++ smb3d_pins: smb3d-mux { ++ groups = "smb3d"; ++ function = "smb3d"; ++ }; ++ fanin0_pins: fanin0-mux { ++ groups = "fanin0"; ++ function = "fanin0"; ++ }; ++ fanin1_pins: fanin1-mux { ++ groups = "fanin1"; ++ function = "fanin1"; ++ }; ++ fanin2_pins: fanin2-mux { ++ groups = "fanin2"; ++ function = "fanin2"; ++ }; ++ fanin3_pins: fanin3-mux { ++ groups = "fanin3"; ++ function = "fanin3"; ++ }; ++ fanin4_pins: fanin4-mux { ++ groups = "fanin4"; ++ function = "fanin4"; ++ }; ++ fanin5_pins: fanin5-mux { ++ groups = "fanin5"; ++ function = "fanin5"; ++ }; ++ fanin6_pins: fanin6-mux { ++ groups = "fanin6"; ++ function = "fanin6"; ++ }; ++ fanin7_pins: fanin7-mux { ++ groups = "fanin7"; ++ function = "fanin7"; ++ }; ++ fanin8_pins: fanin8-mux { ++ groups = "fanin8"; ++ function = "fanin8"; ++ }; ++ fanin9_pins: fanin9-mux { ++ groups = "fanin9"; ++ function = "fanin9"; ++ }; ++ fanin10_pins: fanin10-mux { ++ groups = "fanin10"; ++ function = "fanin10"; ++ }; ++ fanin11_pins: fanin11-mux { ++ groups = "fanin11"; ++ function = "fanin11"; ++ }; ++ fanin12_pins: fanin12-mux { ++ groups = "fanin12"; ++ function = "fanin12"; ++ }; ++ fanin13_pins: fanin13-mux { ++ groups = "fanin13"; ++ function = "fanin13"; ++ }; ++ fanin14_pins: fanin14-mux { ++ groups = "fanin14"; ++ function = "fanin14"; ++ }; ++ fanin15_pins: fanin15-mux { ++ groups = "fanin15"; ++ function = "fanin15"; ++ }; ++ pwm0_pins: pwm0-mux { ++ groups = "pwm0"; ++ function = "pwm0"; ++ }; ++ pwm1_pins: pwm1-mux { ++ groups = "pwm1"; ++ function = "pwm1"; ++ }; ++ pwm2_pins: pwm2-mux { ++ groups = "pwm2"; ++ function = "pwm2"; ++ }; ++ pwm3_pins: pwm3-mux { ++ groups = "pwm3"; ++ function = "pwm3"; ++ }; ++ r2_pins: r2-mux { ++ groups = "r2"; ++ function = "r2"; ++ }; ++ r2err_pins: r2err-mux { ++ groups = "r2err"; ++ function = "r2err"; ++ }; ++ r2md_pins: r2md-mux { ++ groups = "r2md"; ++ function = "r2md"; ++ }; ++ r3rxer_pins: r3rxer-mux { ++ groups = "r3rxer"; ++ function = "r3rxer"; ++ }; ++ ga20kbc_pins: ga20kbc-mux { ++ groups = "ga20kbc"; ++ function = "ga20kbc"; ++ }; ++ smb5d_pins: smb5d-mux { ++ groups = "smb5d"; ++ function = "smb5d"; ++ }; ++ lpc_pins: lpc-mux { ++ groups = "lpc"; ++ function = "lpc"; ++ }; ++ espi_pins: espi-mux { ++ groups = "espi"; ++ function = "espi"; ++ }; ++ sg1mdio_pins: sg1mdio-mux { ++ groups = "sg1mdio"; ++ function = "sg1mdio"; ++ }; ++ rg2_pins: rg2-mux { ++ groups = "rg2"; ++ function = "rg2"; ++ }; ++ ddr_pins: ddr-mux { ++ groups = "ddr"; ++ function = "ddr"; ++ }; ++ i3c0_pins: i3c0-mux { ++ groups = "i3c0"; ++ function = "i3c0"; ++ }; ++ i3c1_pins: i3c1-mux { ++ groups = "i3c1"; ++ function = "i3c1"; ++ }; ++ i3c2_pins: i3c2-mux { ++ groups = "i3c2"; ++ function = "i3c2"; ++ }; ++ i3c3_pins: i3c3-mux { ++ groups = "i3c3"; ++ function = "i3c3"; ++ }; ++ i3c4_pins: i3c4-mux { ++ groups = "i3c4"; ++ function = "i3c4"; ++ }; ++ i3c5_pins: i3c5-mux { ++ groups = "i3c5"; ++ function = "i3c5"; ++ }; ++ smb0_pins: smb0-mux { ++ groups = "smb0"; ++ function = "smb0"; ++ }; ++ smb1_pins: smb1-mux { ++ groups = "smb1"; ++ function = "smb1"; ++ }; ++ smb2_pins: smb2-mux { ++ groups = "smb2"; ++ function = "smb2"; ++ }; ++ smb2c_pins: smb2c-mux { ++ groups = "smb2c"; ++ function = "smb2c"; ++ }; ++ smb2b_pins: smb2b-mux { ++ groups = "smb2b"; ++ function = "smb2b"; ++ }; ++ smb1c_pins: smb1c-mux { ++ groups = "smb1c"; ++ function = "smb1c"; ++ }; ++ smb1b_pins: smb1b-mux { ++ groups = "smb1b"; ++ function = "smb1b"; ++ }; ++ smb8_pins: smb8-mux { ++ groups = "smb8"; ++ function = "smb8"; ++ }; ++ smb9_pins: smb9-mux { ++ groups = "smb9"; ++ function = "smb9"; ++ }; ++ smb10_pins: smb10-mux { ++ groups = "smb10"; ++ function = "smb10"; ++ }; ++ smb11_pins: smb11-mux { ++ groups = "smb11"; ++ function = "smb11"; ++ }; ++ sd1_pins: sd1-mux { ++ groups = "sd1"; ++ function = "sd1"; ++ }; ++ sd1pwr_pins: sd1pwr-mux { ++ groups = "sd1pwr"; ++ function = "sd1pwr"; ++ }; ++ pwm4_pins: pwm4-mux { ++ groups = "pwm4"; ++ function = "pwm4"; ++ }; ++ pwm5_pins: pwm5-mux { ++ groups = "pwm5"; ++ function = "pwm5"; ++ }; ++ pwm6_pins: pwm6-mux { ++ groups = "pwm6"; ++ function = "pwm6"; ++ }; ++ pwm7_pins: pwm7-mux { ++ groups = "pwm7"; ++ function = "pwm7"; ++ }; ++ pwm8_pins: pwm8-mux { ++ groups = "pwm8"; ++ function = "pwm8"; ++ }; ++ pwm9_pins: pwm9-mux { ++ groups = "pwm9"; ++ function = "pwm9"; ++ }; ++ pwm10_pins: pwm10-mux { ++ groups = "pwm10"; ++ function = "pwm10"; ++ }; ++ pwm11_pins: pwm11-mux { ++ groups = "pwm11"; ++ function = "pwm11"; ++ }; ++ mmc8_pins: mmc8-mux { ++ groups = "mmc8"; ++ function = "mmc8"; ++ }; ++ mmc_pins: mmc-mux { ++ groups = "mmc"; ++ function = "mmc"; ++ }; ++ mmcwp_pins: mmcwp-mux { ++ groups = "mmcwp"; ++ function = "mmcwp"; ++ }; ++ mmccd_pins: mmccd-mux { ++ groups = "mmccd"; ++ function = "mmccd"; ++ }; ++ mmcrst_pins: mmcrst-mux { ++ groups = "mmcrst"; ++ function = "mmcrst"; ++ }; ++ clkout_pins: clkout-mux { ++ groups = "clkout"; ++ function = "clkout"; ++ }; ++ serirq_pins: serirq-mux { ++ groups = "serirq"; ++ function = "serirq"; ++ }; ++ scipme_pins: scipme-mux { ++ groups = "scipme"; ++ function = "scipme"; ++ }; ++ smb6_pins: smb6-mux { ++ groups = "smb6"; ++ function = "smb6"; ++ }; ++ smb6b_pins: smb6b-mux { ++ groups = "smb6b"; ++ function = "smb6b"; ++ }; ++ smb6c_pins: smb6c-mux { ++ groups = "smb6c"; ++ function = "smb6c"; ++ }; ++ smb6d_pins: smb6d-mux { ++ groups = "smb6d"; ++ function = "smb6d"; ++ }; ++ smb7_pins: smb7-mux { ++ groups = "smb7"; ++ function = "smb7"; ++ }; ++ smb7b_pins: smb7b-mux { ++ groups = "smb7b"; ++ function = "smb7b"; ++ }; ++ smb7c_pins: smb7c-mux { ++ groups = "smb7c"; ++ function = "smb7c"; ++ }; ++ smb7d_pins: smb7d-mux { ++ groups = "smb7d"; ++ function = "smb7d"; ++ }; ++ spi1_pins: spi1-mux { ++ groups = "spi1"; ++ function = "spi1"; ++ }; ++ faninx_pins: faninx-mux { ++ groups = "faninx"; ++ function = "faninx"; ++ }; ++ r1_pins: r1-mux { ++ groups = "r1"; ++ function = "r1"; ++ }; ++ spi3_pins: spi3-mux { ++ groups = "spi3"; ++ function = "spi3"; ++ }; ++ spi3cs1_pins: spi3cs1-mux { ++ groups = "spi3cs1"; ++ function = "spi3cs1"; ++ }; ++ spi3quad_pins: spi3quad-mux { ++ groups = "spi3quad"; ++ function = "spi3quad"; ++ }; ++ spi3cs2_pins: spi3cs2-mux { ++ groups = "spi3cs2"; ++ function = "spi3cs2"; ++ }; ++ spi3cs3_pins: spi3cs3-mux { ++ groups = "spi3cs3"; ++ function = "spi3cs3"; ++ }; ++ nprd_smi_pins: nprd-smi-mux { ++ groups = "nprd_smi"; ++ function = "nprd_smi"; ++ }; ++ smb0b_pins: smb0b-mux { ++ groups = "smb0b"; ++ function = "smb0b"; ++ }; ++ smb0c_pins: smb0c-mux { ++ groups = "smb0c"; ++ function = "smb0c"; ++ }; ++ smb0den_pins: smb0den-mux { ++ groups = "smb0den"; ++ function = "smb0den"; ++ }; ++ smb0d_pins: smb0d-mux { ++ groups = "smb0d"; ++ function = "smb0d"; ++ }; ++ ddc_pins: ddc-mux { ++ groups = "ddc"; ++ function = "ddc"; ++ }; ++ rg2mdio_pins: rg2mdio-mux { ++ groups = "rg2mdio"; ++ function = "rg2mdio"; ++ }; ++ wdog1_pins: wdog1-mux { ++ groups = "wdog1"; ++ function = "wdog1"; ++ }; ++ wdog2_pins: wdog2-mux { ++ groups = "wdog2"; ++ function = "wdog2"; ++ }; ++ smb12_pins: smb12-mux { ++ groups = "smb12"; ++ function = "smb12"; ++ }; ++ smb13_pins: smb13-mux { ++ groups = "smb13"; ++ function = "smb13"; ++ }; ++ spix_pins: spix-mux { ++ groups = "spix"; ++ function = "spix"; ++ }; ++ spixcs1_pins: spixcs1-mux { ++ groups = "spixcs1"; ++ function = "spixcs1"; ++ }; ++ clkreq_pins: clkreq-mux { ++ groups = "clkreq"; ++ function = "clkreq"; ++ }; ++ hgpio0_pins: hgpio0-mux { ++ groups = "hgpio0"; ++ function = "hgpio0"; ++ }; ++ hgpio1_pins: hgpio1-mux { ++ groups = "hgpio1"; ++ function = "hgpio1"; ++ }; ++ hgpio2_pins: hgpio2-mux { ++ groups = "hgpio2"; ++ function = "hgpio2"; ++ }; ++ hgpio3_pins: hgpio3-mux { ++ groups = "hgpio3"; ++ function = "hgpio3"; ++ }; ++ hgpio4_pins: hgpio4-mux { ++ groups = "hgpio4"; ++ function = "hgpio4"; ++ }; ++ hgpio5_pins: hgpio5-mux { ++ groups = "hgpio5"; ++ function = "hgpio5"; ++ }; ++ hgpio6_pins: hgpio6-mux { ++ groups = "hgpio6"; ++ function = "hgpio6"; ++ }; ++ hgpio7_pins: hgpio7-mux { ++ groups = "hgpio7"; ++ function = "hgpio7"; ++ }; ++ bu4_pins: bu4-mux { ++ groups = "bu4"; ++ function = "bu4"; ++ }; ++ bu4b_pins: bu4b-mux { ++ groups = "bu4b"; ++ function = "bu4b"; ++ }; ++ bu5_pins: bu5-mux { ++ groups = "bu5"; ++ function = "bu5"; ++ }; ++ bu5b_pins: bu5b-mux { ++ groups = "bu5b"; ++ function = "bu5b"; ++ }; ++ bu6_pins: bu6-mux { ++ groups = "bu6"; ++ function = "bu6"; ++ }; ++ gpo187_pins: gpo187-mux { ++ groups = "gpo187"; ++ function = "gpo187"; ++ }; ++ }; ++}; +\ No newline at end of file +-- +2.34.1 + diff --git a/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1004-arm64-dts-nuvoton-npcm8xx-add-modules-node.patch b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1004-arm64-dts-nuvoton-npcm8xx-add-modules-node.patch new file mode 100644 index 00000000000..8c828382e61 --- /dev/null +++ b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1004-arm64-dts-nuvoton-npcm8xx-add-modules-node.patch @@ -0,0 +1,1202 @@ +From f866bf3aa2514cefadd8fcdf5cb0085b91baaed5 Mon Sep 17 00:00:00 2001 +From: Tomer Maimon +Date: Sun, 14 Jul 2024 18:26:17 +0300 +Subject: [PATCH] arm64: dts: nuvoton: npcm8xx: add modules node + +Add the following modules nodes to Nuvoton NPCM8xx BMC device tree: +- GMAC. +- FIU. +- OHCI and EHCI. +- SDHCI. +- PCIe. +- VCD and ECE. +- KCS. +- BPC. +- eSPI. +- PECI. +- PSPI. +- JTAG master. +- RNG. +- ADC. +- SGPIO. +- PWM and FAN. +- I3C. +- I2C. +- GFXI. +- Thermal zone. +- UDC. +- OPTEE. + +This change is also contributing to lf-openbmc upstream for reviewing. +Lore Link: https://lore.kernel.org/all/20240714152617.3055768-3-tmaimon77@gmail.com/ + +Signed-off-by: Tomer Maimon +Signed-off-by: Joseph Liu +--- + .../dts/nuvoton/nuvoton-common-npcm8xx.dtsi | 911 +++++++++++++++++- + .../boot/dts/nuvoton/nuvoton-npcm845.dtsi | 164 +++- + 2 files changed, 1061 insertions(+), 14 deletions(-) + +diff --git a/arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi b/arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi +index a63e8edea..0d16b5f16 100644 +--- a/arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi ++++ b/arch/arm64/boot/dts/nuvoton/nuvoton-common-npcm8xx.dtsi +@@ -19,10 +19,16 @@ soc { + ranges; + + gcr: system-controller@f0800000 { +- compatible = "nuvoton,npcm845-gcr", "syscon"; ++ compatible = "nuvoton,npcm845-gcr", "syscon", "simple-mfd"; + reg = <0x0 0xf0800000 0x0 0x1000>; + }; + ++ fuse:fuse@f0189000 { ++ compatible = "nuvoton,npcm845-fuse", "syscon", ++ "simple-mfd"; ++ reg = <0x0 0xf0189000 0x0 0x1000>; ++ }; ++ + gic: interrupt-controller@dfff9000 { + compatible = "arm,gic-400"; + reg = <0x0 0xdfff9000 0x0 0x1000>, +@@ -57,20 +63,317 @@ clk: rstc: reset-controller@f0801000 { + #clock-cells = <1>; + }; + ++ gmac0: eth@f0802000 { ++ device_type = "network"; ++ compatible = "nuvoton,npcm-dwmac"; ++ reg = <0x0 0xf0802000 0x0 0x2000>, ++ <0x0 0xf0780000 0x0 0x200>; ++ interrupts = ; ++ interrupt-names = "macirq"; ++ clocks = <&clk NPCM8XX_CLK_AHB>; ++ clock-names = "stmmaceth"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&sg1mdio_pins>; ++ status = "disabled"; ++ }; ++ ++ gmac1: eth@f0804000 { ++ device_type = "network"; ++ compatible = "snps,dwmac"; ++ reg = <0x0 0xf0804000 0x0 0x2000>; ++ interrupts = ; ++ interrupt-names = "macirq"; ++ clocks = <&clk NPCM8XX_CLK_AHB>; ++ clock-names = "stmmaceth"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&rg2_pins ++ &rg2mdio_pins>; ++ status = "disabled"; ++ }; ++ ++ gmac2: eth@f0806000 { ++ device_type = "network"; ++ compatible = "snps,dwmac"; ++ reg = <0x0 0xf0806000 0x0 0x2000>; ++ interrupts = ; ++ interrupt-names = "macirq"; ++ clocks = <&clk NPCM8XX_CLK_AHB>; ++ clock-names = "stmmaceth"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&r1_pins ++ &r1err_pins ++ &r1md_pins>; ++ status = "disabled"; ++ }; ++ ++ gmac3: eth@f0808000 { ++ device_type = "network"; ++ compatible = "snps,dwmac"; ++ reg = <0x0 0xf0808000 0x0 0x2000>; ++ interrupts = ; ++ interrupt-names = "macirq"; ++ clocks = <&clk NPCM8XX_CLK_AHB>; ++ clock-names = "stmmaceth"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&r2_pins ++ &r2err_pins ++ &r2md_pins>; ++ status = "disabled"; ++ }; ++ ++ ehci1: usb@f0828100 { ++ compatible = "nuvoton,npcm750-ehci"; ++ reg = <0x0 0xf0828100 0x0 0x1000>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ ++ ehci2: usb@f082a100 { ++ compatible = "nuvoton,npcm750-ehci"; ++ reg = <0x0 0xf082a100 0x0 0x1000>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ ++ ohci1: usb@f0829000 { ++ compatible = "nuvoton,npcm750-ohci", "generic-ohci"; ++ reg = <0x0 0xf0829000 0x0 0x1000>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ ++ ohci2: usb@f082b000 { ++ compatible = "nuvoton,npcm750-ohci", "generic-ohci"; ++ reg = <0x0 0xf082b000 0x0 0x1000>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ ++ sdhci: mmc@f0842000 { ++ compatible = "nuvoton,npcm845-sdhci"; ++ reg = <0x0 0xf0842000 0x0 0x100>; ++ interrupts = ; ++ clocks = <&clk NPCM8XX_CLK_AHB>; ++ clock-names = "clk_mmc"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&mmc8_pins ++ &mmc_pins>; ++ status = "disabled"; ++ }; ++ ++ pcie: pcie@e1000000 { ++ compatible = "nuvoton,npcm845-pcie"; ++ device_type = "pci"; ++ reg = <0x0 0xE1000000 0x0 0x1000>, ++ <0x0 0xE8000000 0x0 0x1000>; ++ bus-range = <0x0 0xF>; ++ #address-cells = <3>; ++ #size-cells = <2>; ++ #interrupt-cells = <1>; ++ ranges = <0x01000000 0 0xe9000000 0x0 0xe9000000 0 0x01000000 ++ 0x02000000 0 0xea000000 0x0 0xea000000 0 0x04000000>; ++ resets = <&rstc 0x34 15>; ++ interrupts = ; ++ interrupt-map-mask = <0 0 0 7>; ++ interrupt-map = <0 0 0 1 &gic GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>; ++ nuvoton,sysgcr = <&gcr>; ++ }; ++ ++ fiu0: spi@fb000000 { ++ compatible = "nuvoton,npcm845-fiu"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x0 0xfb000000 0x0 0x1000>, ++ <0x0 0x80000000 0x0 0x10000000>; ++ reg-names = "control", "memory"; ++ clocks = <&clk NPCM8XX_CLK_SPI0>; ++ clock-names = "clk_ahb"; ++ status = "disabled"; ++ }; ++ ++ fiu1: spi@fb002000 { ++ compatible = "nuvoton,npcm845-fiu"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x0 0xfb002000 0x0 0x1000>, ++ <0x0 0x90000000 0x0 0x4000000>; ++ reg-names = "control", "memory"; ++ clocks = <&clk NPCM8XX_CLK_SPI1>; ++ clock-names = "clk_spi1"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi1_pins>; ++ status = "disabled"; ++ }; ++ ++ fiu3: spi@c0000000 { ++ compatible = "nuvoton,npcm845-fiu"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x0 0xc0000000 0x0 0x1000>, ++ <0x0 0xA0000000 0x0 0x20000000>; ++ reg-names = "control", "memory"; ++ clocks = <&clk NPCM8XX_CLK_SPI3>; ++ clock-names = "clk_spi3"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi3_pins>; ++ status = "disabled"; ++ }; ++ ++ fiux: spi@fb001000 { ++ compatible = "nuvoton,npcm845-fiu"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x0 0xfb001000 0x0 0x1000>, ++ <0x0 0xf8000000 0x0 0x2000000>; ++ reg-names = "control", "memory"; ++ clocks = <&clk NPCM8XX_CLK_SPIX>; ++ clock-names = "clk_ahb"; ++ status = "disabled"; ++ }; ++ ++ pcimbox: pcimbox@f0848000 { ++ compatible = "nuvoton,npcm845-pci-mbox", "nuvoton,npcm750-pci-mbox", ++ "simple-mfd", "syscon"; ++ reg = <0x0 0xf084C000 0x0 0x8 ++ 0x0 0xf0848000 0x0 0x3F00>; ++ interrupts = ; ++ }; ++ ++ vcd: vcd@f0810000 { ++ compatible = "nuvoton,npcm845-vcd"; ++ reg = <0x0 0xf0810000 0x0 0x10000>; ++ interrupts = ; ++ resets = <&rstc 0x24 14>; ++ nuvoton,sysgcr = <&gcr>; ++ nuvoton,sysgfxi = <&gfxi>; ++ nuvoton,ece = <&ece>; ++ status = "disabled"; ++ }; ++ ++ ece: video-codec@f0820000 { ++ compatible = "nuvoton,npcm845-ece"; ++ reg = <0x0 0xf0820000 0x0 0x2000>; ++ interrupts = ; ++ resets = <&rstc 0x24 13>; ++ status = "disabled"; ++ }; ++ + apb { + #address-cells = <1>; + #size-cells = <1>; + compatible = "simple-bus"; + interrupt-parent = <&gic>; + ranges = <0x0 0x0 0xf0000000 0x00300000>, +- <0xfff00000 0x0 0xfff00000 0x00016000>; ++ <0xfff00000 0x0 0xfff00000 0x00016000>, ++ <0xf0800000 0x0 0xf0800000 0x00060000>; ++ ++ lpc_kcs: lpc_kcs@7000 { ++ compatible = "nuvoton,npcm845-lpc-kcs", ++ "simple-mfd", "syscon"; ++ reg = <0x7000 0x40>; ++ reg-io-width = <1>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <0x0 0x7000 0x40>; ++ kcs1: kcs1@0 { ++ compatible = "nuvoton,npcm845-kcs-bmc", "nuvoton,npcm750-kcs-bmc"; ++ reg = <0x0 0x40>; ++ interrupts = ; ++ kcs_chan = <1>; ++ status = "disabled"; ++ }; ++ kcs2: kcs2@0 { ++ compatible = "nuvoton,npcm845-kcs-bmc", "nuvoton,npcm750-kcs-bmc"; ++ reg = <0x0 0x40>; ++ interrupts = ; ++ kcs_chan = <2>; ++ status = "disabled"; ++ }; ++ kcs3: kcs3@0 { ++ compatible = "nuvoton,npcm845-kcs-bmc", "nuvoton,npcm750-kcs-bmc"; ++ reg = <0x0 0x40>; ++ interrupts = ; ++ kcs_chan = <3>; ++ status = "disabled"; ++ }; ++ }; ++ ++ lpc_host: lpc_host@7000 { ++ compatible = "nuvoton,npcm845-lpc-host", ++ "simple-mfd", "syscon"; ++ reg = <0x7000 0x60>; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ ranges = <0x0 0x7000 0x60>; ++ lpc_bpc: lpc_bpc@40 { ++ compatible = "nuvoton,npcm845-lpc-bpc", "nuvoton,npcm750-lpc-bpc"; ++ reg = <0x40 0x20>; ++ interrupts = ; ++ status = "disabled"; ++ }; ++ }; ++ ++ espi: espi@9f000 { ++ compatible = "nuvoton,npcm845-espi", ++ "simple-mfd", "syscon"; ++ reg = <0x9f000 0x1000>; ++ vw_gpio: vw_gpio { ++ compatible = "nuvoton,npcm845-espi-vwgpio"; ++ interrupts = ; ++ gpio-controller; ++ #gpio-cells = <2>; ++ status = "disabled"; ++ }; ++ }; ++ ++ peci0: peci-controller@100000 { ++ compatible = "nuvoton,npcm845-peci"; ++ reg = <0x100000 0x1000>; ++ interrupts = ; ++ clocks = <&rstc NPCM8XX_CLK_APB3>; ++ cmd-timeout-ms = <1000>; ++ status = "disabled"; ++ }; ++ ++ pspi: spi@201000 { ++ compatible = "nuvoton,npcm845-pspi"; ++ reg = <0x201000 0x1000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pspi_pins>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ interrupts = ; ++ clocks = <&clk NPCM8XX_CLK_APB5>; ++ clock-names = "clk_apb5"; ++ resets = <&rstc 0x24 23>; ++ status = "disabled"; ++ }; ++ ++ jtm1: jtm@208000 { ++ compatible = "nuvoton,npcm845-jtm"; ++ reg = <0x208000 0x1000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&jm1_pins>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ interrupts = ; ++ clocks = <&clk NPCM8XX_CLK_APB5>; ++ clock-names = "clk_apb5"; ++ resets = <&rstc 0x74 29>; ++ status = "disabled"; ++ }; + +- peci: peci-controller@100000 { +- compatible = "nuvoton,npcm845-peci"; +- reg = <0x100000 0x1000>; +- interrupts = ; +- clocks = <&rstc NPCM8XX_CLK_APB3>; +- cmd-timeout-ms = <1000>; ++ jtm2: jtm@209000 { ++ compatible = "nuvoton,npcm845-jtm"; ++ reg = <0x209000 0x1000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&jm2_pins>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ interrupts = ; ++ clocks = <&clk NPCM8XX_CLK_APB5>; ++ clock-names = "clk_apb5"; ++ resets = <&rstc 0x74 30>; + status = "disabled"; + }; + +@@ -121,18 +424,22 @@ serial3: serial@3000 { + serial4: serial@4000 { + compatible = "nuvoton,npcm845-uart", "nuvoton,npcm750-uart"; + reg = <0x4000 0x1000>; +- clocks = <&rstc NPCM8XX_CLK_UART>; ++ clocks = <&rstc NPCM8XX_CLK_UART2>; + interrupts = ; + reg-shift = <2>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&bu4_pins>; + status = "disabled"; + }; + + serial5: serial@5000 { + compatible = "nuvoton,npcm845-uart", "nuvoton,npcm750-uart"; + reg = <0x5000 0x1000>; +- clocks = <&rstc NPCM8XX_CLK_UART>; ++ clocks = <&rstc NPCM8XX_CLK_UART2>; + interrupts = ; + reg-shift = <2>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&bu5_pins>; + status = "disabled"; + }; + +@@ -142,11 +449,30 @@ serial6: serial@6000 { + clocks = <&rstc NPCM8XX_CLK_UART2>; + interrupts = ; + reg-shift = <2>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&bu6_pins>; ++ status = "disabled"; ++ }; ++ ++ rng: rng@b000 { ++ compatible = "nuvoton,npcm845-rng"; ++ reg = <0xb000 0x8>; ++ clocks = <&clk NPCM8XX_CLK_APB1>; ++ status = "disabled"; ++ }; ++ ++ adc: adc@c000 { ++ compatible = "nuvoton,npcm845-adc"; ++ reg = <0xC000 0x8>; ++ interrupts = ; ++ clocks = <&clk NPCM8XX_CLK_ADC>; ++ resets = <&rstc 0x20 27>; ++ syscon = <&fuse>; + status = "disabled"; + }; + + watchdog0: watchdog@801c { +- compatible = "nuvoton,npcm845-wdt", "nuvoton,npcm750-wdt"; ++ compatible = "nuvoton,npcm845-wdt"; + interrupts = ; + reg = <0x801c 0x4>; + status = "disabled"; +@@ -155,7 +481,7 @@ watchdog0: watchdog@801c { + }; + + watchdog1: watchdog@901c { +- compatible = "nuvoton,npcm845-wdt", "nuvoton,npcm750-wdt"; ++ compatible = "nuvoton,npcm845-wdt"; + interrupts = ; + reg = <0x901c 0x4>; + status = "disabled"; +@@ -164,13 +490,572 @@ watchdog1: watchdog@901c { + }; + + watchdog2: watchdog@a01c { +- compatible = "nuvoton,npcm845-wdt", "nuvoton,npcm750-wdt"; ++ compatible = "nuvoton,npcm845-wdt"; + interrupts = ; + reg = <0xa01c 0x4>; + status = "disabled"; + clocks = <&refclk>; + syscon = <&gcr>; + }; ++ ++ tmps: tmps@188000 { ++ compatible = "nuvoton,npcm845-thermal"; ++ interrupts = ; ++ clocks = <&clk NPCM8XX_CLK_APB4>; ++ reg = <0x188000 0x5C>; ++ #thermal-sensor-cells = <1>; ++ }; ++ ++ sgpio1: sgpio@101000 { ++ compatible = "nuvoton,npcm845-sgpio"; ++ reg = <0x101000 0x200>; ++ clocks = <&clk NPCM8XX_CLK_APB3>; ++ interrupts = ; ++ gpio-controller; ++ #gpio-cells = <2>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&iox1_pins>; ++ nuvoton,input-ngpios = <64>; ++ nuvoton,output-ngpios = <64>; ++ status = "disabled"; ++ }; ++ ++ sgpio2: sgpio@102000 { ++ compatible = "nuvoton,npcm845-sgpio"; ++ reg = <0x102000 0x200>; ++ clocks = <&clk NPCM8XX_CLK_APB3>; ++ interrupts = ; ++ gpio-controller; ++ #gpio-cells = <2>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&iox2_pins>; ++ nuvoton,input-ngpios = <64>; ++ nuvoton,output-ngpios = <64>; ++ status = "disabled"; ++ }; ++ ++ pwm_fan:pwm-fan-controller@103000 { ++ compatible = "nuvoton,npcm845-pwm-fan"; ++ reg = <0x103000 0x3000>, ++ <0x180000 0x8000>; ++ reg-names = "pwm", "fan"; ++ clocks = <&clk NPCM8XX_CLK_APB3>, ++ <&clk NPCM8XX_CLK_APB4>; ++ clock-names = "pwm","fan"; ++ interrupts = , ++ , ++ , ++ , ++ , ++ , ++ , ++ ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pwm0_pins &pwm1_pins ++ &pwm2_pins &pwm3_pins ++ &pwm4_pins &pwm5_pins ++ &pwm6_pins &pwm7_pins ++ &pwm8_pins &pwm9_pins ++ &pwm10_pins &pwm11_pins ++ &fanin0_pins &fanin1_pins ++ &fanin2_pins &fanin3_pins ++ &fanin4_pins &fanin5_pins ++ &fanin6_pins &fanin7_pins ++ &fanin8_pins &fanin9_pins ++ &fanin10_pins &fanin11_pins ++ &fanin12_pins &fanin13_pins ++ &fanin14_pins &fanin15_pins>; ++ status = "disabled"; ++ }; ++ ++ i3c0: i3c@fff10000 { ++ compatible = "silvaco,i3c-master"; ++ reg = <0xfff10000 0x1000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i3c0_pins>; ++ clocks = <&clk NPCM8XX_CLK_AHB>, <&clk NPCM8XX_CLK_RCP>; ++ clock-names = "pclk", "fast_clk"; ++ interrupts = ; ++ resets = <&rstc 0x74 8>; ++ #address-cells = <3>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i3c1: i3c@fff11000 { ++ compatible = "silvaco,i3c-master"; ++ reg = <0xfff11000 0x1000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i3c1_pins>; ++ clocks = <&clk NPCM8XX_CLK_AHB>, <&clk NPCM8XX_CLK_RCP>; ++ clock-names = "pclk", "fast_clk"; ++ interrupts = ; ++ resets = <&rstc 0x74 9>; ++ #address-cells = <3>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i3c2: i3c@fff12000 { ++ compatible = "silvaco,i3c-master"; ++ reg = <0xfff12000 0x1000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i3c2_pins>; ++ clocks = <&clk NPCM8XX_CLK_AHB>, <&clk NPCM8XX_CLK_RCP>; ++ clock-names = "pclk", "fast_clk"; ++ interrupts = ; ++ resets = <&rstc 0x74 10>; ++ #address-cells = <3>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i3c3: i3c@fff13000 { ++ compatible = "silvaco,i3c-master"; ++ reg = <0xfff13000 0x1000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i3c3_pins>; ++ clocks = <&clk NPCM8XX_CLK_AHB>, <&clk NPCM8XX_CLK_RCP>; ++ clock-names = "pclk", "fast_clk"; ++ interrupts = ; ++ resets = <&rstc 0x74 11>; ++ #address-cells = <3>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i3c4: i3c@fff14000 { ++ compatible = "silvaco,i3c-master"; ++ reg = <0xfff14000 0x1000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i3c4_pins>; ++ clocks = <&clk NPCM8XX_CLK_AHB>, <&clk NPCM8XX_CLK_RCP>; ++ clock-names = "pclk", "fast_clk"; ++ interrupts = ; ++ resets = <&rstc 0x74 12>; ++ #address-cells = <3>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i3c5: i3c@fff15000 { ++ compatible = "silvaco,i3c-master"; ++ reg = <0xfff15000 0x1000>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i3c5_pins>; ++ clocks = <&clk NPCM8XX_CLK_AHB>, <&clk NPCM8XX_CLK_RCP>; ++ clock-names = "pclk", "fast_clk"; ++ interrupts = ; ++ resets = <&rstc 0x74 13>; ++ #address-cells = <3>; ++ #size-cells = <0>; ++ status = "disabled"; ++ }; ++ ++ i2c0: i2c@80000 { ++ reg = <0x80000 0x1000>; ++ compatible = "nuvoton,npcm845-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clk NPCM8XX_CLK_APB2>; ++ clock-frequency = <100000>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&smb0_pins>; ++ nuvoton,sys-mgr = <&gcr>; ++ status = "disabled"; ++ }; ++ ++ i2c1: i2c@81000 { ++ reg = <0x81000 0x1000>; ++ compatible = "nuvoton,npcm845-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clk NPCM8XX_CLK_APB2>; ++ clock-frequency = <100000>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&smb1_pins>; ++ nuvoton,sys-mgr = <&gcr>; ++ status = "disabled"; ++ }; ++ ++ i2c2: i2c@82000 { ++ reg = <0x82000 0x1000>; ++ compatible = "nuvoton,npcm845-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clk NPCM8XX_CLK_APB2>; ++ clock-frequency = <100000>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&smb2_pins>; ++ nuvoton,sys-mgr = <&gcr>; ++ status = "disabled"; ++ }; ++ ++ i2c3: i2c@83000 { ++ reg = <0x83000 0x1000>; ++ compatible = "nuvoton,npcm845-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clk NPCM8XX_CLK_APB2>; ++ clock-frequency = <100000>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&smb3_pins>; ++ nuvoton,sys-mgr = <&gcr>; ++ status = "disabled"; ++ }; ++ ++ i2c4: i2c@84000 { ++ reg = <0x84000 0x1000>; ++ compatible = "nuvoton,npcm845-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clk NPCM8XX_CLK_APB2>; ++ clock-frequency = <100000>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&smb4_pins>; ++ nuvoton,sys-mgr = <&gcr>; ++ status = "disabled"; ++ }; ++ ++ i2c5: i2c@85000 { ++ reg = <0x85000 0x1000>; ++ compatible = "nuvoton,npcm845-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clk NPCM8XX_CLK_APB2>; ++ clock-frequency = <100000>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&smb5_pins>; ++ nuvoton,sys-mgr = <&gcr>; ++ status = "disabled"; ++ }; ++ ++ i2c6: i2c@86000 { ++ reg = <0x86000 0x1000>; ++ compatible = "nuvoton,npcm845-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clk NPCM8XX_CLK_APB2>; ++ clock-frequency = <100000>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&smb6_pins>; ++ nuvoton,sys-mgr = <&gcr>; ++ status = "disabled"; ++ }; ++ ++ i2c7: i2c@87000 { ++ reg = <0x87000 0x1000>; ++ compatible = "nuvoton,npcm845-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clk NPCM8XX_CLK_APB2>; ++ clock-frequency = <100000>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&smb7_pins>; ++ nuvoton,sys-mgr = <&gcr>; ++ status = "disabled"; ++ }; ++ ++ i2c8: i2c@88000 { ++ reg = <0x88000 0x1000>; ++ compatible = "nuvoton,npcm845-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clk NPCM8XX_CLK_APB2>; ++ clock-frequency = <100000>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&smb8_pins>; ++ nuvoton,sys-mgr = <&gcr>; ++ status = "disabled"; ++ }; ++ ++ i2c9: i2c@89000 { ++ reg = <0x89000 0x1000>; ++ compatible = "nuvoton,npcm845-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clk NPCM8XX_CLK_APB2>; ++ clock-frequency = <100000>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&smb9_pins>; ++ nuvoton,sys-mgr = <&gcr>; ++ status = "disabled"; ++ }; ++ ++ i2c10: i2c@8a000 { ++ reg = <0x8a000 0x1000>; ++ compatible = "nuvoton,npcm845-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clk NPCM8XX_CLK_APB2>; ++ clock-frequency = <100000>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&smb10_pins>; ++ nuvoton,sys-mgr = <&gcr>; ++ status = "disabled"; ++ }; ++ ++ i2c11: i2c@8b000 { ++ reg = <0x8b000 0x1000>; ++ compatible = "nuvoton,npcm845-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clk NPCM8XX_CLK_APB2>; ++ clock-frequency = <100000>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&smb11_pins>; ++ nuvoton,sys-mgr = <&gcr>; ++ status = "disabled"; ++ }; ++ ++ i2c12: i2c@8c000 { ++ reg = <0x8c000 0x1000>; ++ compatible = "nuvoton,npcm845-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clk NPCM8XX_CLK_APB2>; ++ clock-frequency = <100000>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&smb12_pins>; ++ nuvoton,sys-mgr = <&gcr>; ++ status = "disabled"; ++ }; ++ ++ i2c13: i2c@8d000 { ++ reg = <0x8d000 0x1000>; ++ compatible = "nuvoton,npcm845-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clk NPCM8XX_CLK_APB2>; ++ clock-frequency = <100000>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&smb13_pins>; ++ nuvoton,sys-mgr = <&gcr>; ++ status = "disabled"; ++ }; ++ ++ i2c14: i2c@8e000 { ++ reg = <0x8e000 0x1000>; ++ compatible = "nuvoton,npcm845-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clk NPCM8XX_CLK_APB2>; ++ clock-frequency = <100000>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&smb14_pins>; ++ nuvoton,sys-mgr = <&gcr>; ++ status = "disabled"; ++ }; ++ ++ i2c15: i2c@8f000 { ++ reg = <0x8f000 0x1000>; ++ compatible = "nuvoton,npcm845-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clk NPCM8XX_CLK_APB2>; ++ clock-frequency = <100000>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&smb15_pins>; ++ nuvoton,sys-mgr = <&gcr>; ++ status = "disabled"; ++ }; ++ ++ i2c16: i2c@fff00000 { ++ reg = <0xfff00000 0x1000>; ++ compatible = "nuvoton,npcm845-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clk NPCM8XX_CLK_APB2>; ++ clock-frequency = <100000>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&smb16_pins>; ++ nuvoton,sys-mgr = <&gcr>; ++ status = "disabled"; ++ }; ++ ++ i2c17: i2c@fff01000 { ++ reg = <0xfff01000 0x1000>; ++ compatible = "nuvoton,npcm845-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clk NPCM8XX_CLK_APB2>; ++ clock-frequency = <100000>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&smb17_pins>; ++ nuvoton,sys-mgr = <&gcr>; ++ status = "disabled"; ++ }; ++ ++ i2c18: i2c@fff02000 { ++ reg = <0xfff02000 0x1000>; ++ compatible = "nuvoton,npcm845-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clk NPCM8XX_CLK_APB2>; ++ clock-frequency = <100000>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&smb18_pins>; ++ nuvoton,sys-mgr = <&gcr>; ++ status = "disabled"; ++ }; ++ ++ i2c19: i2c@fff03000 { ++ reg = <0xfff03000 0x1000>; ++ compatible = "nuvoton,npcm845-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clk NPCM8XX_CLK_APB2>; ++ clock-frequency = <100000>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&smb19_pins>; ++ nuvoton,sys-mgr = <&gcr>; ++ status = "disabled"; ++ }; ++ ++ i2c20: i2c@fff04000 { ++ reg = <0xfff04000 0x1000>; ++ compatible = "nuvoton,npcm845-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clk NPCM8XX_CLK_APB2>; ++ clock-frequency = <100000>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&smb20_pins>; ++ nuvoton,sys-mgr = <&gcr>; ++ status = "disabled"; ++ }; ++ ++ i2c21: i2c@fff05000 { ++ reg = <0xfff05000 0x1000>; ++ compatible = "nuvoton,npcm845-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clk NPCM8XX_CLK_APB2>; ++ clock-frequency = <100000>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&smb21_pins>; ++ nuvoton,sys-mgr = <&gcr>; ++ status = "disabled"; ++ }; ++ ++ i2c22: i2c@fff06000 { ++ reg = <0xfff06000 0x1000>; ++ compatible = "nuvoton,npcm845-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clk NPCM8XX_CLK_APB2>; ++ clock-frequency = <100000>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&smb22_pins>; ++ nuvoton,sys-mgr = <&gcr>; ++ status = "disabled"; ++ }; ++ ++ i2c23: i2c@fff07000 { ++ reg = <0xfff07000 0x1000>; ++ compatible = "nuvoton,npcm845-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clk NPCM8XX_CLK_APB2>; ++ clock-frequency = <100000>; ++ interrupts = ; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&smb23_pins>; ++ nuvoton,sys-mgr = <&gcr>; ++ status = "disabled"; ++ }; ++ ++ i2c24: i2c@fff08000 { ++ reg = <0xfff08000 0x1000>; ++ compatible = "nuvoton,npcm845-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clk NPCM8XX_CLK_APB2>; ++ clock-frequency = <100000>; ++ interrupts = ; ++ nuvoton,sys-mgr = <&gcr>; ++ status = "disabled"; ++ }; ++ ++ i2c25: i2c@fff09000 { ++ reg = <0xfff09000 0x1000>; ++ compatible = "nuvoton,npcm845-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clk NPCM8XX_CLK_APB2>; ++ clock-frequency = <100000>; ++ interrupts = ; ++ nuvoton,sys-mgr = <&gcr>; ++ status = "disabled"; ++ }; ++ ++ i2c26: i2c@fff0a000 { ++ reg = <0xfff0a000 0x1000>; ++ compatible = "nuvoton,npcm845-i2c"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ clocks = <&clk NPCM8XX_CLK_APB2>; ++ clock-frequency = <100000>; ++ interrupts = ; ++ nuvoton,sys-mgr = <&gcr>; ++ status = "disabled"; ++ }; ++ ++ gfxi: gfxi@e000 { ++ compatible = "nuvoton,npcm845-gfxi", "syscon", ++ "simple-mfd"; ++ reg = <0xe000 0x100>; ++ }; ++ }; ++ }; ++ ++ thermal-zones { ++ cpu0_thermal: cpu0-thermal { ++ polling-delay-passive = <250>; ++ polling-delay = <1000>; ++ thermal-sensors = <&tmps 0>; ++ trips { ++ cpu0_alert0: trip-point0 { ++ temperature = <90000>; ++ hysteresis = <2000>; ++ type = "passive"; ++ }; ++ }; ++ }; ++ cpu1_thermal: cpu1-thermal { ++ polling-delay-passive = <250>; ++ polling-delay = <1000>; ++ thermal-sensors = <&tmps 1>; ++ trips { ++ cpu1_alert0: trip-point0 { ++ temperature = <90000>; ++ hysteresis = <2000>; ++ type = "passive"; ++ }; ++ }; + }; + }; + +diff --git a/arch/arm64/boot/dts/nuvoton/nuvoton-npcm845.dtsi b/arch/arm64/boot/dts/nuvoton/nuvoton-npcm845.dtsi +index 3cbcea65e..5918f9522 100644 +--- a/arch/arm64/boot/dts/nuvoton/nuvoton-npcm845.dtsi ++++ b/arch/arm64/boot/dts/nuvoton/nuvoton-npcm845.dtsi +@@ -75,4 +75,166 @@ timer { + , + ; + }; +-}; ++ ++ firmware { ++ optee { ++ compatible = "linaro,optee-tz"; ++ method = "smc"; ++ }; ++ }; ++ ++ udc0_phy: usb-phy { ++ #phy-cells = <0>; ++ compatible = "usb-nop-xceiv"; ++ }; ++ ++ ahb { ++ mc: memory-controller@f0824000 { ++ compatible = "nuvoton,npcm845-memory-controller"; ++ reg = <0x0 0xf0824000 0x0 0x1000>; ++ interrupts = ; ++ }; ++ ++ udc0:udc@f0830000 { ++ compatible = "nuvoton,npcm845-udc"; ++ reg = <0x0 0xf0830000 0x0 0x1000 ++ 0x0 0xfffeb000 0x0 0x800>; ++ interrupts = ; ++ clocks = <&clk NPCM8XX_CLK_SU>; ++ clock-names = "clk_usb_bridge"; ++ ++ phys = <&udc0_phy>; ++ phy_type = "utmi_wide"; ++ dr_mode = "peripheral"; ++ status = "disabled"; ++ }; ++ ++ udc1:udc@f0831000 { ++ compatible = "nuvoton,npcm845-udc"; ++ reg = <0x0 0xf0831000 0x0 0x1000 ++ 0x0 0xfffeb800 0x0 0x800>; ++ interrupts = ; ++ clocks = <&clk NPCM8XX_CLK_SU>; ++ clock-names = "clk_usb_bridge"; ++ ++ phys = <&udc0_phy>; ++ phy_type = "utmi_wide"; ++ dr_mode = "peripheral"; ++ status = "disabled"; ++ }; ++ ++ udc2:udc@f0832000 { ++ compatible = "nuvoton,npcm845-udc"; ++ reg = <0x0 0xf0832000 0x0 0x1000 ++ 0x0 0xfffec000 0x0 0x800>; ++ interrupts = ; ++ clocks = <&clk NPCM8XX_CLK_SU>; ++ clock-names = "clk_usb_bridge"; ++ ++ phys = <&udc0_phy>; ++ phy_type = "utmi_wide"; ++ dr_mode = "peripheral"; ++ status = "disabled"; ++ }; ++ ++ udc3:udc@f0833000 { ++ compatible = "nuvoton,npcm845-udc"; ++ reg = <0x0 0xf0833000 0x0 0x1000 ++ 0x0 0xfffec800 0x0 0x800>; ++ interrupts = ; ++ clocks = <&clk NPCM8XX_CLK_SU>; ++ clock-names = "clk_usb_bridge"; ++ ++ phys = <&udc0_phy>; ++ phy_type = "utmi_wide"; ++ dr_mode = "peripheral"; ++ status = "disabled"; ++ }; ++ ++ udc4:udc@f0834000 { ++ compatible = "nuvoton,npcm845-udc"; ++ reg = <0x0 0xf0834000 0x0 0x1000 ++ 0x0 0xfffed000 0x0 0x800>; ++ interrupts = ; ++ clocks = <&clk NPCM8XX_CLK_SU>; ++ clock-names = "clk_usb_bridge"; ++ ++ phys = <&udc0_phy>; ++ phy_type = "utmi_wide"; ++ dr_mode = "peripheral"; ++ status = "disabled"; ++ }; ++ ++ udc5:udc@f0835000 { ++ compatible = "nuvoton,npcm845-udc"; ++ reg = <0x0 0xf0835000 0x0 0x1000 ++ 0x0 0xfffed800 0x0 0x800>; ++ interrupts = ; ++ clocks = <&clk NPCM8XX_CLK_SU>; ++ clock-names = "clk_usb_bridge"; ++ ++ phys = <&udc0_phy>; ++ phy_type = "utmi_wide"; ++ dr_mode = "peripheral"; ++ status = "disabled"; ++ }; ++ ++ udc6:udc@f0836000 { ++ compatible = "nuvoton,npcm845-udc"; ++ reg = <0x0 0xf0836000 0x0 0x1000 ++ 0x0 0xfffee000 0x0 0x800>; ++ interrupts = ; ++ clocks = <&clk NPCM8XX_CLK_SU>; ++ clock-names = "clk_usb_bridge"; ++ ++ phys = <&udc0_phy>; ++ phy_type = "utmi_wide"; ++ dr_mode = "peripheral"; ++ status = "disabled"; ++ }; ++ ++ udc7:udc@f0837000 { ++ compatible = "nuvoton,npcm845-udc"; ++ reg = <0x0 0xf0837000 0x0 0x1000 ++ 0x0 0xfffee800 0x0 0x800>; ++ interrupts = ; ++ clocks = <&clk NPCM8XX_CLK_SU>; ++ clock-names = "clk_usb_bridge"; ++ ++ phys = <&udc0_phy>; ++ phy_type = "utmi_wide"; ++ dr_mode = "peripheral"; ++ status = "disabled"; ++ }; ++ ++ udc8:udc@f0838000 { ++ compatible = "nuvoton,npcm845-udc"; ++ reg = <0x0 0xf0838000 0x0 0x1000 ++ 0x0 0xfffef000 0x0 0x800>; ++ interrupts = ; ++ clocks = <&clk NPCM8XX_CLK_SU>; ++ clock-names = "clk_usb_bridge"; ++ ++ nuvoton,sysgcr = <&gcr 0x9C 0xC000 0xC000>; ++ phys = <&udc0_phy>; ++ phy_type = "utmi_wide"; ++ dr_mode = "peripheral"; ++ status = "disabled"; ++ }; ++ ++ udc9:udc@f0839000 { ++ compatible = "nuvoton,npcm845-udc"; ++ reg = <0x0 0xf0839000 0x0 0x1000 ++ 0x0 0xfffef800 0x0 0x800>; ++ interrupts = ; ++ clocks = <&clk NPCM8XX_CLK_SU>; ++ clock-names = "clk_usb_bridge"; ++ ++ nuvoton,sysgcr = <&gcr 0x9C 0x3000 0x3000>; ++ phys = <&udc0_phy>; ++ phy_type = "utmi_wide"; ++ dr_mode = "peripheral"; ++ status = "disabled"; ++ }; ++ }; ++}; +\ No newline at end of file +-- +2.34.1 + diff --git a/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1005-arm64-dts-nuvoton-add-initial-yosemitev4-device-tree.patch b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1005-arm64-dts-nuvoton-add-initial-yosemitev4-device-tree.patch new file mode 100644 index 00000000000..0beff78487c --- /dev/null +++ b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1005-arm64-dts-nuvoton-add-initial-yosemitev4-device-tree.patch @@ -0,0 +1,2321 @@ +From 46e5868c01cbb6f1d63b88061f42f4ea943b17ef Mon Sep 17 00:00:00 2001 +From: Marvin Lin +Date: Wed, 18 Sep 2024 13:34:31 +0800 +Subject: [PATCH] arm64: dts: nuvoton: add initial yosemitev4 device tree + +Add linux device tree entry related to Yosemite 4 specific devices +connected to BMC SoC. We will contribute to lf-openbmc upstream soon. + +Signed-off-by: RickyWu-wiwynn +Signed-off-by: Joseph Liu +Signed-off-by: Marvin Lin +--- + arch/arm64/boot/dts/nuvoton/Makefile | 1 + + .../dts/nuvoton/nuvoton-npcm845-yosemite4.dts | 2285 +++++++++++++++++ + 2 files changed, 2286 insertions(+) + create mode 100644 arch/arm64/boot/dts/nuvoton/nuvoton-npcm845-yosemite4.dts + +diff --git a/arch/arm64/boot/dts/nuvoton/Makefile b/arch/arm64/boot/dts/nuvoton/Makefile +index 3bc9787801a5..426ec5ac8b69 100644 +--- a/arch/arm64/boot/dts/nuvoton/Makefile ++++ b/arch/arm64/boot/dts/nuvoton/Makefile +@@ -2,3 +2,4 @@ + dtb-$(CONFIG_ARCH_MA35) += ma35d1-iot-512m.dtb + dtb-$(CONFIG_ARCH_MA35) += ma35d1-som-256m.dtb + dtb-$(CONFIG_ARCH_NPCM) += nuvoton-npcm845-evb.dtb ++dtb-$(CONFIG_ARCH_NPCM) += nuvoton-npcm845-yosemite4.dtb +\ No newline at end of file +diff --git a/arch/arm64/boot/dts/nuvoton/nuvoton-npcm845-yosemite4.dts b/arch/arm64/boot/dts/nuvoton/nuvoton-npcm845-yosemite4.dts +new file mode 100644 +index 000000000000..625980499d85 +--- /dev/null ++++ b/arch/arm64/boot/dts/nuvoton/nuvoton-npcm845-yosemite4.dts +@@ -0,0 +1,2285 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++// Copyright 2023 Facebook Inc. ++ ++/dts-v1/; ++#include "nuvoton-npcm845.dtsi" ++#include ++ ++/ { ++ model = "Facebook Yosemite 4 BMC"; ++ compatible = "facebook,yosemite4n-bmc", "nuvoton,npcm845"; ++ ++ aliases { ++ serial4 = &serial0; ++ serial0 = &serial1; ++ serial1 = &serial3; ++ serial2 = &serial4; ++ serial3 = &serial5; ++ serial5 = &cpld_serial0; ++ serial6 = &cpld_serial1; ++ serial7 = &cpld_serial2; ++ serial8 = &cpld_serial3; ++ fiu0 = &fiu0; ++ fiu1 = &fiux; ++ i2c0 = &i2c1; ++ i2c1 = &i2c2; ++ i2c2 = &i2c3; ++ i2c3 = &i2c4; ++ i2c4 = &i2c5; ++ i2c5 = &i2c6; ++ i2c6 = &i2c7; ++ i2c7 = &i2c8; ++ i2c8 = &i2c9; ++ i2c9 = &i2c10; ++ i2c10 = &i2c11; ++ i2c11 = &i2c12; ++ i2c12 = &i2c13; ++ i2c13 = &i2c14; ++ i2c14 = &i2c15; ++ i2c15 = &i2c16; ++ i2c16 = &imux16; ++ i2c17 = &imux17; ++ i2c18 = &imux18; ++ i2c19 = &imux19; ++ i2c20 = &imux20; ++ i2c21 = &imux21; ++ i2c22 = &imux22; ++ i2c23 = &imux23; ++ i2c24 = &imux24; ++ i2c25 = &imux25; ++ i2c26 = &imux26; ++ i2c27 = &imux27; ++ i2c28 = &imux28; ++ i2c29 = &imux29; ++ i2c30 = &imux30; ++ i2c31 = &imux31; ++ i2c32 = &imux32; ++ i2c33 = &imux33; ++ i2c34 = &imux34; ++ i2c35 = &imux35; ++ i2c36 = &imux36; ++ i2c37 = &imux37; ++ }; ++ ++ chosen { ++ stdout-path = &serial0; ++ }; ++ ++ memory { ++ device_type = "memory"; ++ reg = <0x0 0x0 0x0 0x40000000>; ++ }; ++ ++ iio-hwmon { ++ compatible = "iio-hwmon"; ++ io-channels = <&adc 0>, <&adc 1>, <&adc 2>, <&adc 3>, ++ <&adc 4>, <&adc 5>, <&adc 6>, <&adc 7>; ++ }; ++ ++ regulators { ++ compatible = "simple-bus"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ reg_vref1_8: regulator@0 { ++ compatible = "regulator-fixed"; ++ reg = <0>; ++ regulator-name = "vref_1_8v"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ }; ++ }; ++ ++ firmware { ++ optee { ++ compatible = "linaro,optee-tz"; ++ method = "smc"; ++ }; ++ }; ++ ++ refclk: refclk-25mhz { ++ compatible = "fixed-clock"; ++ clock-output-names = "ref"; ++ clock-frequency = <25000000>; ++ #clock-cells = <0>; ++ }; ++ ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ bl31_reserved: bl31@0x2000000 { ++ reg = <0x0 0x2000000 0x0 0x4200000>; ++ }; ++ }; ++ ++ led_bmc_hb { ++ compatible = "gpio-leds"; ++ heartbeat { ++ label = "heartbeat"; ++ gpios = <&gpio7 4 GPIO_ACTIVE_LOW>; ++ linux,default-trigger = "timer"; ++ led-pattern = <1000 1000>; ++ default-state = "on"; ++ }; ++ }; ++ ++ leds { ++ compatible = "gpio-leds"; ++ fan0_blue { ++ retain-state-shutdown; ++ default-state = "on"; ++ gpios = <&led_gpio0 4 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ fan0_amber { ++ retain-state-shutdown; ++ default-state = "off"; ++ gpios = <&led_gpio0 5 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ fan1_blue { ++ retain-state-shutdown; ++ default-state = "on"; ++ gpios = <&led_gpio0 10 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ fan1_amber { ++ retain-state-shutdown; ++ default-state = "off"; ++ gpios = <&led_gpio0 11 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ fan2_blue { ++ retain-state-shutdown; ++ default-state = "on"; ++ gpios = <&led_gpio1 4 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ fan2_amber { ++ retain-state-shutdown; ++ default-state = "off"; ++ gpios = <&led_gpio1 5 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ fan3_blue { ++ retain-state-shutdown; ++ default-state = "on"; ++ gpios = <&led_gpio1 10 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ fan3_amber { ++ retain-state-shutdown; ++ default-state = "off"; ++ gpios = <&led_gpio1 11 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ fan4_blue { ++ retain-state-shutdown; ++ default-state = "on"; ++ gpios = <&led_gpio0 2 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ fan4_amber { ++ retain-state-shutdown; ++ default-state = "off"; ++ gpios = <&led_gpio0 3 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ fan5_blue { ++ retain-state-shutdown; ++ default-state = "on"; ++ gpios = <&led_gpio0 8 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ fan5_amber { ++ retain-state-shutdown; ++ default-state = "off"; ++ gpios = <&led_gpio0 9 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ fan6_blue { ++ retain-state-shutdown; ++ default-state = "on"; ++ gpios = <&led_gpio1 2 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ fan6_amber { ++ retain-state-shutdown; ++ default-state = "off"; ++ gpios = <&led_gpio1 3 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ fan7_blue { ++ retain-state-shutdown; ++ default-state = "on"; ++ gpios = <&led_gpio1 8 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ fan7_amber { ++ retain-state-shutdown; ++ default-state = "off"; ++ gpios = <&led_gpio1 9 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ fan8_blue { ++ retain-state-shutdown; ++ default-state = "on"; ++ gpios = <&led_gpio0 0 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ fan8_amber { ++ retain-state-shutdown; ++ default-state = "off"; ++ gpios = <&led_gpio0 1 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ fan9_blue { ++ retain-state-shutdown; ++ default-state = "on"; ++ gpios = <&led_gpio0 6 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ fan9_amber { ++ retain-state-shutdown; ++ default-state = "off"; ++ gpios = <&led_gpio0 7 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ fan10_blue { ++ retain-state-shutdown; ++ default-state = "on"; ++ gpios = <&led_gpio1 0 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ fan10_amber { ++ retain-state-shutdown; ++ default-state = "off"; ++ gpios = <&led_gpio1 1 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ fan11_blue { ++ retain-state-shutdown; ++ default-state = "on"; ++ gpios = <&led_gpio1 6 GPIO_ACTIVE_HIGH>; ++ }; ++ ++ fan11_amber { ++ retain-state-shutdown; ++ default-state = "off"; ++ gpios = <&led_gpio1 7 GPIO_ACTIVE_HIGH>; ++ }; ++ }; ++ ++ cpld_serial0: cpld_uart@f8000800 { ++ device_type = "serial"; ++ compatible = "ns16450"; ++ reg = <0x0 0xf8000800 0x0 0x200>; ++ reg-shift = <0>; ++ clocks = <&clk NPCM8XX_CLK_UART>; ++ interrupt-parent = <&gpio4>; ++ interrupts = <31 IRQ_TYPE_EDGE_FALLING>; ++ }; ++ ++ cpld_serial1: cpld_uart@f8000a00 { ++ device_type = "serial"; ++ compatible = "ns16450"; ++ reg = <0x0 0xf8000a00 0x0 0x200>; ++ reg-shift = <0>; ++ clocks = <&clk NPCM8XX_CLK_UART>; ++ interrupt-parent = <&gpio4>; ++ interrupts = <31 IRQ_TYPE_EDGE_FALLING>; ++ }; ++ ++ cpld_serial2: cpld_uart@f8000c00 { ++ device_type = "serial"; ++ compatible = "ns16450"; ++ reg = <0x0 0xf8000c00 0x0 0x200>; ++ reg-shift = <0>; ++ clocks = <&clk NPCM8XX_CLK_UART>; ++ interrupt-parent = <&gpio4>; ++ interrupts = <31 IRQ_TYPE_EDGE_FALLING>; ++ }; ++ ++ cpld_serial3: cpld_uart@f8000e00 { ++ device_type = "serial"; ++ compatible = "ns16450"; ++ reg = <0x0 0xf8000e00 0x0 0x200>; ++ reg-shift = <0>; ++ clocks = <&clk NPCM8XX_CLK_UART>; ++ interrupt-parent = <&gpio4>; ++ interrupts = <31 IRQ_TYPE_EDGE_FALLING>; ++ }; ++}; ++ ++&gcr { ++ mux-controller { ++ compatible = "mmio-mux"; ++ #mux-control-cells = <1>; ++ ++ mux-reg-masks = <0x38 0x07>; ++ idle-states = <2>; // UART switch mode 3 ++ }; ++}; ++ ++&serial0 { ++ status = "okay"; ++}; ++ ++&serial1 { ++ status = "okay"; ++}; ++ ++&serial3 { ++ status = "okay"; ++}; ++ ++&serial4 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&bu4b_pins>; ++ status = "okay"; ++}; ++ ++&serial5 { ++ pinctrl-names = "default"; ++ pinctrl-0 = <&bu5b_pins>; ++ status = "okay"; ++}; ++ ++&watchdog1 { ++ nuvoton,ext1-reset-type = "wd1"; ++ status = "okay"; ++}; ++ ++&watchdog2 { ++ status = "okay"; ++}; ++ ++&gmac2 { ++ status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&r1_pins ++ &r1oen_pins>; ++ use-ncsi; ++ mellanox,multi-host; ++ ncsi-ctrl,start-redo-probe; ++ ncsi-ctrl,no-channel-monitor; ++}; ++ ++&gmac3 { ++ status = "okay"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&r2_pins ++ &r2oen_pins>; ++ use-ncsi; ++ mellanox,multi-host; ++ ncsi-ctrl,start-redo-probe; ++ ncsi-ctrl,no-channel-monitor; ++}; ++ ++&pcie { ++ status = "disabled"; ++}; ++ ++&fiu0 { ++ reg = <0x0 0xfb000000 0x0 0x1000>; ++ reg-names = "control"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spi0cs1_pins>; ++ status = "okay"; ++ ++ spi-nor@0 { ++ compatible = "jedec,spi-nor"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ spi-rx-bus-width = <2>; ++ spi-tx-bus-width = <2>; ++ reg = <0>; ++ spi-max-frequency = <5000000>; ++ partitions@80000000 { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ bmc@0 { ++ label = "bmc"; ++ reg = <0x00000000 0x08000000>; ++ }; ++ u-boot@0 { ++ label = "u-boot"; ++ reg = <0x00000000 0x002BE000>; ++ }; ++ u-boot-env@2C0000 { ++ label = "u-boot-env"; ++ reg = <0x002C0000 0x00040000>; ++ }; ++ kernel@300000 { ++ label = "kernel"; ++ reg = <0x00300000 0x00600000>; // 6MB ++ }; ++ rofs@900000 { ++ label = "rofs"; ++ reg = <0x00900000 0x02800000>; // 40MB ++ }; ++ rwfs@3100000 { ++ label = "rwfs"; ++ reg = <0x03100000 0x00F00000>; // 15MB ++ }; ++ }; ++ }; ++ ++ spi-nor@1 { ++ compatible = "jedec,spi-nor"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ spi-rx-bus-width = <2>; ++ spi-tx-bus-width = <2>; ++ reg = <1>; ++ spi-max-frequency = <5000000>; ++ partitions@80000000 { ++ compatible = "fixed-partitions"; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ bmc2@0 { ++ label = "bmc2"; ++ reg = <0x00000000 0x08000000>; ++ }; ++ }; ++ }; ++}; ++ ++&fiux { ++ spix-mode; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&spix_pins>; ++ status = "okay"; ++}; ++ ++&ehci1 { ++ status = "okay"; ++}; ++ ++&ehci2 { ++ status = "okay"; ++}; ++ ++&i3c1 { ++ compatible = "nuvoton,npcm845-i3c"; ++ reg = <0xfff11000 0x1000>, ++ <0xf0851000 0x1000>, ++ <0xf0800304 0x4>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i3c1_pins ++ &i3c1_scl_slew ++ &i3c1_sda_slew>; ++ status = "okay"; ++ reg-names = "i3c", "dma", "dma_ctl"; ++ i3c-scl-hz = <8000000>; ++ i2c-scl-hz = <400000>; ++ use-dma; ++ mctp-controller; ++ hub@0x70 { ++ reg = <0x70 0x3c0 0x00700000>; ++ cp0-ldo-en = "enabled"; ++ cp1-ldo-en = "enabled"; ++ cp0-ldo-volt = "1.2V"; ++ cp1-ldo-volt = "1.2V"; ++ tp0145-ldo-en = "enabled"; ++ tp2367-ldo-en = "enabled"; ++ tp0145-ldo-volt = "1.2V"; ++ tp2367-ldo-volt = "1.2V"; ++ tp0145-pullup = "2k"; ++ tp2367-pullup = "2k"; ++ ++ target-port@0 { ++ mode = "i3c"; ++ pullup = "enabled"; ++ }; ++ target-port@1 { ++ mode = "i3c"; ++ pullup = "enabled"; ++ }; ++ target-port@2 { ++ mode = "i3c"; ++ pullup = "enabled"; ++ }; ++ target-port@3 { ++ mode = "i3c"; ++ pullup = "enabled"; ++ }; ++ }; ++}; ++ ++&i3c2 { ++ compatible = "nuvoton,npcm845-i3c"; ++ reg = <0xfff12000 0x1000>, ++ <0xf0852000 0x1000>, ++ <0xf0800308 0x4>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i3c2_pins ++ &i3c2_scl_slew ++ &i3c2_sda_slew>; ++ status = "okay"; ++ reg-names = "i3c", "dma", "dma_ctl"; ++ i3c-scl-hz = <8000000>; ++ i2c-scl-hz = <400000>; ++ use-dma; ++ mctp-controller; ++ hub@0x70 { ++ reg = <0x70 0x3c0 0x00700000>; ++ cp0-ldo-en = "enabled"; ++ cp1-ldo-en = "enabled"; ++ cp0-ldo-volt = "1.2V"; ++ cp1-ldo-volt = "1.2V"; ++ tp0145-ldo-en = "enabled"; ++ tp2367-ldo-en = "enabled"; ++ tp0145-ldo-volt = "1.2V"; ++ tp2367-ldo-volt = "1.2V"; ++ tp0145-pullup = "2k"; ++ tp2367-pullup = "2k"; ++ ++ target-port@0 { ++ mode = "i3c"; ++ pullup = "enabled"; ++ }; ++ target-port@1 { ++ mode = "i3c"; ++ pullup = "enabled"; ++ }; ++ target-port@2 { ++ mode = "i3c"; ++ pullup = "enabled"; ++ }; ++ target-port@3 { ++ mode = "i3c"; ++ pullup = "enabled"; ++ }; ++ }; ++}; ++ ++&i2c1 { ++ status = "okay"; ++ clock-frequency = <400000>; ++ multi-master; ++ ++ gpio@24 { ++ compatible = "nxp,pca9506"; ++ reg = <0x24>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ gpio@21 { ++ compatible = "nxp,pca9506"; ++ reg = <0x21>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ gpio@22 { ++ compatible = "nxp,pca9506"; ++ reg = <0x22>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ gpio@23 { ++ compatible = "nxp,pca9506"; ++ reg = <0x23>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ power-sensor@40 { ++ compatible = "adi,adm1281", "mps,mp5990"; ++ reg = <0x40>; ++ shunt-resistor-micro-ohms = <500>; ++ }; ++}; ++ ++&i2c2 { ++ status = "okay"; ++ clock-frequency = <400000>; ++ multi-master; ++ ++ gpio@24 { ++ compatible = "nxp,pca9506"; ++ reg = <0x24>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ gpio@21 { ++ compatible = "nxp,pca9506"; ++ reg = <0x21>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ gpio@22 { ++ compatible = "nxp,pca9506"; ++ reg = <0x22>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ gpio@23 { ++ compatible = "nxp,pca9506"; ++ reg = <0x23>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ power-sensor@40 { ++ compatible = "adi,adm1281", "mps,mp5990"; ++ reg = <0x40>; ++ shunt-resistor-micro-ohms = <500>; ++ }; ++}; ++ ++&i2c3 { ++ status = "okay"; ++ clock-frequency = <400000>; ++ multi-master; ++ ++ gpio@24 { ++ compatible = "nxp,pca9506"; ++ reg = <0x24>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ gpio@21 { ++ compatible = "nxp,pca9506"; ++ reg = <0x21>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ gpio@22 { ++ compatible = "nxp,pca9506"; ++ reg = <0x22>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ gpio@23 { ++ compatible = "nxp,pca9506"; ++ reg = <0x23>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ power-sensor@40 { ++ compatible = "adi,adm1281", "mps,mp5990"; ++ reg = <0x40>; ++ shunt-resistor-micro-ohms = <500>; ++ }; ++}; ++ ++&i2c4 { ++ status = "okay"; ++ clock-frequency = <400000>; ++ multi-master; ++ ++ gpio@24 { ++ compatible = "nxp,pca9506"; ++ reg = <0x24>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ gpio@21 { ++ compatible = "nxp,pca9506"; ++ reg = <0x21>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ gpio@22 { ++ compatible = "nxp,pca9506"; ++ reg = <0x22>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ gpio@23 { ++ compatible = "nxp,pca9506"; ++ reg = <0x23>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ power-sensor@40 { ++ compatible = "adi,adm1281", "mps,mp5990"; ++ reg = <0x40>; ++ shunt-resistor-micro-ohms = <500>; ++ }; ++}; ++ ++&i2c5 { ++ status = "okay"; ++ clock-frequency = <400000>; ++ multi-master; ++ ++ gpio@24 { ++ compatible = "nxp,pca9506"; ++ reg = <0x24>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ gpio@21 { ++ compatible = "nxp,pca9506"; ++ reg = <0x21>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ gpio@22 { ++ compatible = "nxp,pca9506"; ++ reg = <0x22>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ gpio@23 { ++ compatible = "nxp,pca9506"; ++ reg = <0x23>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ power-sensor@40 { ++ compatible = "adi,adm1281", "mps,mp5990"; ++ reg = <0x40>; ++ shunt-resistor-micro-ohms = <500>; ++ }; ++}; ++ ++&i2c6 { ++ status = "okay"; ++ clock-frequency = <400000>; ++ multi-master; ++ ++ gpio@24 { ++ compatible = "nxp,pca9506"; ++ reg = <0x24>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ gpio@21 { ++ compatible = "nxp,pca9506"; ++ reg = <0x21>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ gpio@22 { ++ compatible = "nxp,pca9506"; ++ reg = <0x22>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ gpio@23 { ++ compatible = "nxp,pca9506"; ++ reg = <0x23>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ power-sensor@40 { ++ compatible = "adi,adm1281", "mps,mp5990"; ++ reg = <0x40>; ++ shunt-resistor-micro-ohms = <500>; ++ }; ++}; ++ ++&i2c7 { ++ status = "okay"; ++ clock-frequency = <400000>; ++ multi-master; ++ ++ gpio@24 { ++ compatible = "nxp,pca9506"; ++ reg = <0x24>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ gpio@21 { ++ compatible = "nxp,pca9506"; ++ reg = <0x21>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ gpio@22 { ++ compatible = "nxp,pca9506"; ++ reg = <0x22>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ gpio@23 { ++ compatible = "nxp,pca9506"; ++ reg = <0x23>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ power-sensor@40 { ++ compatible = "adi,adm1281", "mps,mp5990"; ++ reg = <0x40>; ++ shunt-resistor-micro-ohms = <500>; ++ }; ++}; ++ ++&i2c8 { ++ status = "okay"; ++ clock-frequency = <400000>; ++ multi-master; ++ ++ gpio@24 { ++ compatible = "nxp,pca9506"; ++ reg = <0x24>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ gpio@21 { ++ compatible = "nxp,pca9506"; ++ reg = <0x21>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ gpio@22 { ++ compatible = "nxp,pca9506"; ++ reg = <0x22>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ gpio@23 { ++ compatible = "nxp,pca9506"; ++ reg = <0x23>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ power-sensor@40 { ++ compatible = "adi,adm1281", "mps,mp5990"; ++ reg = <0x40>; ++ shunt-resistor-micro-ohms = <500>; ++ }; ++}; ++ ++&i2c9 { ++ status = "okay"; ++ clock-frequency = <400000>; ++ ++ i2c-mux@70 { ++ compatible = "nxp,pca9544"; ++ i2c-mux-idle-disconnect; ++ reg = <0x70>; ++ ++ imux16: i2c@0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0>; ++ ++ gpio@49 { ++ compatible = "nxp,pca9537"; ++ reg = <0x49>; ++ }; ++ ++ eeprom@50 { ++ compatible = "atmel,24c128"; ++ reg = <0x50>; ++ }; ++ ++ eeprom@51 { ++ compatible = "atmel,24c128"; ++ reg = <0x51>; ++ }; ++ ++ eeprom@54 { ++ compatible = "atmel,24c128"; ++ reg = <0x54>; ++ }; ++ }; ++ ++ imux17: i2c@1 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <1>; ++ gpio@49 { ++ compatible = "nxp,pca9537"; ++ reg = <0x49>; ++ }; ++ ++ eeprom@50 { ++ compatible = "atmel,24c128"; ++ reg = <0x50>; ++ }; ++ ++ eeprom@51 { ++ compatible = "atmel,24c128"; ++ reg = <0x51>; ++ }; ++ ++ eeprom@54 { ++ compatible = "atmel,24c128"; ++ reg = <0x54>; ++ }; ++ }; ++ ++ imux18: i2c@2 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <2>; ++ gpio@49 { ++ compatible = "nxp,pca9537"; ++ reg = <0x49>; ++ }; ++ ++ eeprom@50 { ++ compatible = "atmel,24c128"; ++ reg = <0x50>; ++ }; ++ ++ eeprom@51 { ++ compatible = "atmel,24c128"; ++ reg = <0x51>; ++ }; ++ ++ eeprom@54 { ++ compatible = "atmel,24c128"; ++ reg = <0x54>; ++ }; ++ }; ++ ++ imux19: i2c@3 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <3>; ++ gpio@49 { ++ compatible = "nxp,pca9537"; ++ reg = <0x49>; ++ }; ++ ++ eeprom@50 { ++ compatible = "atmel,24c128"; ++ reg = <0x50>; ++ }; ++ ++ eeprom@51 { ++ compatible = "atmel,24c128"; ++ reg = <0x51>; ++ }; ++ ++ eeprom@54 { ++ compatible = "atmel,24c128"; ++ reg = <0x54>; ++ }; ++ }; ++ }; ++}; ++ ++&i2c10 { ++ status = "okay"; ++ clock-frequency = <400000>; ++ ++ i2c-mux@71 { ++ compatible = "nxp,pca9544"; ++ i2c-mux-idle-disconnect; ++ reg = <0x71>; ++ ++ imux20: i2c@0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0>; ++ gpio@49 { ++ compatible = "nxp,pca9537"; ++ reg = <0x49>; ++ }; ++ ++ eeprom@50 { ++ compatible = "atmel,24c128"; ++ reg = <0x50>; ++ }; ++ ++ eeprom@51 { ++ compatible = "atmel,24c128"; ++ reg = <0x51>; ++ }; ++ ++ eeprom@54 { ++ compatible = "atmel,24c128"; ++ reg = <0x54>; ++ }; ++ }; ++ ++ imux21: i2c@1 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <1>; ++ gpio@49 { ++ compatible = "nxp,pca9537"; ++ reg = <0x49>; ++ }; ++ ++ eeprom@50 { ++ compatible = "atmel,24c128"; ++ reg = <0x50>; ++ }; ++ ++ eeprom@51 { ++ compatible = "atmel,24c128"; ++ reg = <0x51>; ++ }; ++ ++ eeprom@54 { ++ compatible = "atmel,24c128"; ++ reg = <0x54>; ++ }; ++ }; ++ ++ imux22: i2c@2 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <2>; ++ gpio@49 { ++ compatible = "nxp,pca9537"; ++ reg = <0x49>; ++ }; ++ ++ eeprom@50 { ++ compatible = "atmel,24c128"; ++ reg = <0x50>; ++ }; ++ ++ eeprom@51 { ++ compatible = "atmel,24c128"; ++ reg = <0x51>; ++ }; ++ ++ eeprom@54 { ++ compatible = "atmel,24c128"; ++ reg = <0x54>; ++ }; ++ }; ++ ++ imux23: i2c@3 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <3>; ++ ++ gpio@49 { ++ compatible = "nxp,pca9537"; ++ reg = <0x49>; ++ }; ++ ++ eeprom@50 { ++ compatible = "atmel,24c128"; ++ reg = <0x50>; ++ }; ++ ++ eeprom@51 { ++ compatible = "atmel,24c128"; ++ reg = <0x51>; ++ }; ++ ++ eeprom@54 { ++ compatible = "atmel,24c128"; ++ reg = <0x54>; ++ }; ++ }; ++ }; ++}; ++ ++&i2c11 { ++ status = "okay"; ++ clock-frequency = <400000>; ++ ++ i2c-mux@74 { ++ compatible = "nxp,pca9544"; ++ i2c-mux-idle-disconnect; ++ reg = <0x74>; ++ ++ imux28: i2c@0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0>; ++ ++ gpio@20 { ++ compatible = "nxp,pca9506"; ++ reg = <0x20>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ gpio@21 { ++ compatible = "nxp,pca9506"; ++ reg = <0x21>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ gpio@22 { ++ compatible = "nxp,pca9506"; ++ reg = <0x22>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ gpio@23 { ++ compatible = "nxp,pca9506"; ++ reg = <0x23>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ gpio@24 { ++ compatible = "nxp,pca9506"; ++ reg = <0x24>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ gpio-line-names = ++ "","","","", ++ "NIC0_MAIN_PWR_EN","NIC1_MAIN_PWR_EN", ++ "NIC2_MAIN_PWR_EN","NIC3_MAIN_PWR_EN", ++ "","","","","","","","", ++ "","","","","","","","", ++ "","","","","","","",""; ++ }; ++ }; ++ ++ imux29: i2c@1 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <1>; ++ }; ++ }; ++}; ++ ++&i2c12 { ++ status = "okay"; ++ power-sensor@10 { ++ compatible = "adi,adm1272"; ++ reg = <0x10>; ++ }; ++ ++ power-sensor@11 { ++ compatible = "infineon,xdp710"; ++ reg = <0x11>; ++ }; ++ ++ power-sensor@12 { ++ compatible = "adi,adm1272"; ++ reg = <0x12>; ++ }; ++ ++ power-sensor@13 { ++ compatible = "infineon,xdp710"; ++ reg = <0x13>; ++ }; ++ ++ gpio@20 { ++ compatible = "nxp,pca9555"; ++ pinctrl-names = "default"; ++ gpio-controller; ++ #gpio-cells = <2>; ++ reg = <0x20>; ++ interrupt-parent = <&gpio3>; ++ interrupts = <31 IRQ_TYPE_LEVEL_LOW>; ++ gpio-line-names = ++ "P48V_OCP_GPIO1","P48V_OCP_GPIO2", ++ "P48V_OCP_GPIO3","FAN_BOARD_0_REVISION_0_R", ++ "FAN_BOARD_0_REVISION_1_R","FAN_BOARD_1_REVISION_0_R", ++ "FAN_BOARD_1_REVISION_1_R","RST_MUX_R_N", ++ "RST_LED_CONTROL_FAN_BOARD_0_N","RST_LED_CONTROL_FAN_BOARD_1_N", ++ "RST_IOEXP_FAN_BOARD_0_N","RST_IOEXP_FAN_BOARD_1_N", ++ "PWRGD_LOAD_SWITCH_FAN_BOARD_0_R","PWRGD_LOAD_SWITCH_FAN_BOARD_1_R", ++ "",""; ++ }; ++ ++ gpio@21 { ++ compatible = "nxp,pca9555"; ++ pinctrl-names = "default"; ++ gpio-controller; ++ #gpio-cells = <2>; ++ reg = <0x21>; ++ interrupt-parent = <&gpio3>; ++ interrupts = <31 IRQ_TYPE_LEVEL_LOW>; ++ gpio-line-names = ++ "HSC_OCP_SLOT_ODD_GPIO1","HSC_OCP_SLOT_ODD_GPIO2", ++ "HSC_OCP_SLOT_ODD_GPIO3","HSC_OCP_SLOT_EVEN_GPIO1", ++ "HSC_OCP_SLOT_EVEN_GPIO2","HSC_OCP_SLOT_EVEN_GPIO3", ++ "ADC_TYPE_0_R","ADC_TYPE_1_R", ++ "MEDUSA_BOARD_REV_0","MEDUSA_BOARD_REV_1", ++ "MEDUSA_BOARD_REV_2","MEDUSA_BOARD_TYPE", ++ "DELTA_MODULE_TYPE","P12V_HSC_TYPE", ++ "",""; ++ }; ++ ++ gpio@22 { ++ compatible = "nxp,pca9555"; ++ pinctrl-names = "default"; ++ gpio-controller; ++ #gpio-cells = <2>; ++ reg = <0x22>; ++ interrupt-parent = <&gpio3>; ++ interrupts = <31 IRQ_TYPE_LEVEL_LOW>; ++ gpio-line-names = ++ "CARD_TYPE_SLOT1","CARD_TYPE_SLOT2", ++ "CARD_TYPE_SLOT3","CARD_TYPE_SLOT4", ++ "CARD_TYPE_SLOT5","CARD_TYPE_SLOT6", ++ "CARD_TYPE_SLOT7","CARD_TYPE_SLOT8", ++ "OC_P48V_HSC_0_N","FLT_P48V_HSC_0_N", ++ "OC_P48V_HSC_1_N","FLT_P48V_HSC_1_N", ++ "EN_P48V_AUX_0","EN_P48V_AUX_1", ++ "PWRGD_P12V_AUX_0","PWRGD_P12V_AUX_1"; ++ }; ++ ++ gpio@23 { ++ compatible = "nxp,pca9555"; ++ pinctrl-names = "default"; ++ gpio-controller; ++ #gpio-cells = <2>; ++ reg = <0x23>; ++ interrupt-parent = <&gpio3>; ++ interrupts = <31 IRQ_TYPE_LEVEL_LOW>; ++ gpio-line-names = ++ "HSC1_ALERT1_R_N","HSC2_ALERT1_R_N", ++ "HSC3_ALERT1_R_N","HSC4_ALERT1_R_N", ++ "HSC5_ALERT1_R_N","HSC6_ALERT1_R_N", ++ "HSC7_ALERT1_R_N","HSC8_ALERT1_R_N", ++ "HSC1_ALERT2_R_N","HSC2_ALERT2_R_N", ++ "HSC3_ALERT2_R_N","HSC4_ALERT2_R_N", ++ "HSC5_ALERT2_R_N","HSC6_ALERT2_R_N", ++ "HSC7_ALERT2_R_N","HSC8_ALERT2_R_N"; ++ }; ++ ++ power-sensor@40 { ++ compatible = "mps,mp5023"; ++ reg = <0x40>; ++ }; ++ ++ power-sensor@41 { ++ compatible = "ti,ina233", "richtek,rtq6056"; ++ resistor-calibration = /bits/ 16 <0x0400>; ++ current-lsb= /bits/ 16 <0x0001>; ++ reg = <0x41>; ++ }; ++ ++ temperature-sensor@48 { ++ compatible = "ti,tmp75"; ++ reg = <0x48>; ++ }; ++ ++ temperature-sensor@49 { ++ compatible = "ti,tmp75"; ++ reg = <0x49>; ++ }; ++ ++ eeprom@54 { ++ compatible = "atmel,24c128"; ++ reg = <0x54>; ++ }; ++ ++ power-sensor@62 { ++ compatible = "pmbus"; ++ reg = <0x62>; ++ }; ++ ++ power-sensor@64 { ++ compatible = "pmbus"; ++ reg = <0x64>; ++ }; ++ ++ power-sensor@65 { ++ compatible = "pmbus"; ++ reg = <0x65>; ++ }; ++ ++ power-sensor@68 { ++ compatible = "pmbus"; ++ reg = <0x68>; ++ }; ++}; ++ ++&i2c13 { ++ status = "okay"; ++ clock-frequency = <400000>; ++ ++ i2c-mux@70 { ++ compatible = "nxp,pca9544"; ++ i2c-mux-idle-disconnect; ++ reg = <0x70>; ++ ++ imux34: i2c@0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0>; ++ ++ adc@1d { ++ compatible = "ti,adc128d818"; ++ reg = <0x1d>; ++ ti,mode = /bits/ 8 <1>; ++ }; ++ ++ adc@33 { ++ compatible = "maxim,max11615"; ++ reg = <0x33>; ++ }; ++ ++ temperature-sensor@48 { ++ compatible = "ti,tmp75"; ++ reg = <0x48>; ++ }; ++ ++ eeprom@50 { ++ compatible = "atmel,24c128"; ++ reg = <0x50>; ++ }; ++ ++ eeprom@54 { ++ compatible = "atmel,24c64"; ++ reg = <0x54>; ++ }; ++ ++ rtc@6f { ++ compatible = "nuvoton,nct3018y"; ++ reg = <0x6f>; ++ }; ++ ++ gpio@20 { ++ compatible = "nxp,pca9506"; ++ reg = <0x20>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ gpio@21 { ++ compatible = "nxp,pca9506"; ++ reg = <0x21>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ gpio@22 { ++ compatible = "nxp,pca9506"; ++ reg = <0x22>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ gpio@23 { ++ compatible = "nxp,pca9506"; ++ reg = <0x23>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ }; ++ ++ imux35: i2c@1 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <1>; ++ }; ++ ++ imux36: i2c@2 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <2>; ++ }; ++ ++ imux37: i2c@3 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <3>; ++ }; ++ }; ++}; ++ ++&i2c14 { ++ status = "okay"; ++ clock-frequency = <100000>; ++}; ++ ++&i2c15 { ++ status = "okay"; ++ clock-frequency = <400000>; ++ adc@1d { ++ compatible = "ti,adc128d818"; ++ reg = <0x1d>; ++ ti,mode = /bits/ 8 <1>; ++ }; ++ ++ adc@36 { ++ compatible = "ti,adc128d818"; ++ reg = <0x36>; ++ ti,mode = /bits/ 8 <1>; ++ }; ++ ++ adc@37 { ++ compatible = "ti,adc128d818"; ++ reg = <0x37>; ++ ti,mode = /bits/ 8 <1>; ++ }; ++ ++ power-sensor@40 { ++ compatible = "ti,ina233", "richtek,rtq6056"; ++ reg = <0x40>; ++ resistor-calibration = /bits/ 16 <0x0400>; ++ current-lsb= /bits/ 16 <0x0001>; ++ }; ++ ++ power-sensor@41 { ++ compatible = "ti,ina233", "richtek,rtq6056"; ++ reg = <0x41>; ++ resistor-calibration = /bits/ 16 <0x0400>; ++ current-lsb= /bits/ 16 <0x0001>; ++ }; ++ ++ power-sensor@42 { ++ compatible = "ti,ina233", "richtek,rtq6056"; ++ reg = <0x42>; ++ resistor-calibration = /bits/ 16 <0x0400>; ++ current-lsb= /bits/ 16 <0x0001>; ++ }; ++ ++ power-sensor@43 { ++ compatible = "ti,ina233", "richtek,rtq6056"; ++ reg = <0x43>; ++ resistor-calibration = /bits/ 16 <0x0400>; ++ current-lsb= /bits/ 16 <0x0001>; ++ }; ++ ++ power-sensor@44 { ++ compatible = "ti,ina233", "richtek,rtq6056"; ++ reg = <0x44>; ++ resistor-calibration = /bits/ 16 <0x0400>; ++ current-lsb= /bits/ 16 <0x0001>; ++ }; ++ ++ temperature-sensor@4e { ++ compatible = "ti,tmp75"; ++ reg = <0x4e>; ++ }; ++ ++ temperature-sensor@4f { ++ compatible = "ti,tmp75"; ++ reg = <0x4f>; ++ }; ++ ++ eeprom@51 { ++ compatible = "atmel,24c128"; ++ reg = <0x51>; ++ }; ++ ++ i2c-mux@74 { ++ compatible = "nxp,pca9546"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ i2c-mux-idle-disconnect; ++ reg = <0x74>; ++ ++ imux30: i2c@0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0>; ++ ++ adc@1f { ++ compatible = "ti,adc128d818"; ++ reg = <0x1f>; ++ ti,mode = /bits/ 8 <1>; ++ }; ++ ++ pwm@20{ ++ compatible = "maxim,max31790"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x20>; ++ channel@4 { ++ reg = <4>; ++ sensor-type = "TACH"; ++ }; ++ ++ channel@5 { ++ reg = <5>; ++ sensor-type = "TACH"; ++ }; ++ }; ++ ++ hwmon0: hwmon@21 { ++ compatible = "nuvoton,nct7363"; ++ reg = <0x21>; ++ #pwm-cells = <2>; ++ ++ fan-3 { ++ pwms = <&hwmon0 2 20000>; ++ tach-ch = /bits/ 8 <0x00>; ++ }; ++ ++ fan-4 { ++ pwms = <&hwmon0 5 20000>; ++ tach-ch = /bits/ 8 <0x01>; ++ }; ++ ++ fan-5 { ++ pwms = <&hwmon0 5 20000>; ++ tach-ch = /bits/ 8 <0x02>; ++ }; ++ ++ fan-0 { ++ pwms = <&hwmon0 0 20000>; ++ tach-ch = /bits/ 8 <0x09>; ++ }; ++ ++ fan-1 { ++ pwms = <&hwmon0 0 20000>; ++ tach-ch = /bits/ 8 <0x0c>; ++ }; ++ ++ fan-2 { ++ pwms = <&hwmon0 2 20000>; ++ tach-ch = /bits/ 8 <0x0e>; ++ }; ++ }; ++ ++ gpio@22{ ++ compatible = "ti,tca6424"; ++ reg = <0x22>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ hwmon1: hwmon@23 { ++ compatible = "nuvoton,nct7363"; ++ reg = <0x23>; ++ #pwm-cells = <2>; ++ ++ fan-3 { ++ pwms = <&hwmon0 2 20000>; ++ tach-ch = /bits/ 8 <0x00>; ++ }; ++ ++ fan-4 { ++ pwms = <&hwmon0 5 20000>; ++ tach-ch = /bits/ 8 <0x01>; ++ }; ++ ++ fan-5 { ++ pwms = <&hwmon0 5 20000>; ++ tach-ch = /bits/ 8 <0x02>; ++ }; ++ ++ fan-0 { ++ pwms = <&hwmon0 0 20000>; ++ tach-ch = /bits/ 8 <0x09>; ++ }; ++ ++ fan-1 { ++ pwms = <&hwmon0 0 20000>; ++ tach-ch = /bits/ 8 <0x0c>; ++ }; ++ ++ fan-2 { ++ pwms = <&hwmon0 2 20000>; ++ tach-ch = /bits/ 8 <0x0e>; ++ }; ++ }; ++ ++ pwm@2f{ ++ compatible = "maxim,max31790"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x2f>; ++ channel@4 { ++ reg = <4>; ++ sensor-type = "TACH"; ++ }; ++ ++ channel@5 { ++ reg = <5>; ++ sensor-type = "TACH"; ++ }; ++ }; ++ ++ adc@33 { ++ compatible = "maxim,max11615"; ++ reg = <0x33>; ++ }; ++ ++ eeprom@52 { ++ compatible = "atmel,24c128"; ++ reg = <0x52>; ++ }; ++ ++ led_gpio0: gpio@61 { ++ compatible = "nxp,pca9552"; ++ reg = <0x61>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ }; ++ ++ imux31: i2c@1 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <1>; ++ ++ adc@1f { ++ compatible = "ti,adc128d818"; ++ reg = <0x1f>; ++ ti,mode = /bits/ 8 <1>; ++ }; ++ ++ pwm@20{ ++ compatible = "maxim,max31790"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x20>; ++ channel@4 { ++ reg = <4>; ++ sensor-type = "TACH"; ++ }; ++ ++ channel@5 { ++ reg = <5>; ++ sensor-type = "TACH"; ++ }; ++ }; ++ ++ hwmon2: hwmon@21 { ++ compatible = "nuvoton,nct7363"; ++ reg = <0x21>; ++ #pwm-cells = <2>; ++ ++ fan-3 { ++ pwms = <&hwmon2 2 20000>; ++ tach-ch = /bits/ 8 <0x00>; ++ }; ++ ++ fan-4 { ++ pwms = <&hwmon2 5 20000>; ++ tach-ch = /bits/ 8 <0x01>; ++ }; ++ ++ fan-5 { ++ pwms = <&hwmon2 5 20000>; ++ tach-ch = /bits/ 8 <0x02>; ++ }; ++ ++ fan-0 { ++ pwms = <&hwmon2 0 20000>; ++ tach-ch = /bits/ 8 <0x09>; ++ }; ++ ++ fan-1 { ++ pwms = <&hwmon2 0 20000>; ++ tach-ch = /bits/ 8 <0x0c>; ++ }; ++ ++ fan-2 { ++ pwms = <&hwmon2 2 20000>; ++ tach-ch = /bits/ 8 <0x0e>; ++ }; ++ }; ++ ++ gpio@22{ ++ compatible = "ti,tca6424"; ++ reg = <0x22>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ ++ hwmon3: hwmon@23 { ++ compatible = "nuvoton,nct7363"; ++ reg = <0x23>; ++ #pwm-cells = <2>; ++ ++ fan-3 { ++ pwms = <&hwmon3 2 20000>; ++ tach-ch = /bits/ 8 <0x00>; ++ }; ++ ++ fan-4 { ++ pwms = <&hwmon3 5 20000>; ++ tach-ch = /bits/ 8 <0x01>; ++ }; ++ ++ fan-5 { ++ pwms = <&hwmon3 5 20000>; ++ tach-ch = /bits/ 8 <0x02>; ++ }; ++ ++ fan-0 { ++ pwms = <&hwmon3 0 20000>; ++ tach-ch = /bits/ 8 <0x09>; ++ }; ++ ++ fan-1 { ++ pwms = <&hwmon3 0 20000>; ++ tach-ch = /bits/ 8 <0x0c>; ++ }; ++ ++ fan-2 { ++ pwms = <&hwmon3 2 20000>; ++ tach-ch = /bits/ 8 <0x0e>; ++ }; ++ }; ++ ++ pwm@2f{ ++ compatible = "maxim,max31790"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0x2f>; ++ channel@4 { ++ reg = <4>; ++ sensor-type = "TACH"; ++ }; ++ ++ channel@5 { ++ reg = <5>; ++ sensor-type = "TACH"; ++ }; ++ }; ++ ++ adc@33 { ++ compatible = "maxim,max11615"; ++ reg = <0x33>; ++ }; ++ ++ eeprom@52 { ++ compatible = "atmel,24c128"; ++ reg = <0x52>; ++ }; ++ ++ led_gpio1: gpio@61 { ++ compatible = "nxp,pca9552"; ++ reg = <0x61>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ gpio-controller; ++ #gpio-cells = <2>; ++ }; ++ }; ++ }; ++ ++ i2c-mux@73 { ++ compatible = "nxp,pca9544"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ i2c-mux-idle-disconnect; ++ reg = <0x73>; ++ ++ imux32: i2c@0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0>; ++ ++ adc@35 { ++ compatible = "maxim,max11617"; ++ reg = <0x35>; ++ }; ++ }; ++ ++ imux33: i2c@1 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <1>; ++ ++ adc@35 { ++ compatible = "maxim,max11617"; ++ reg = <0x35>; ++ }; ++ }; ++ }; ++}; ++ ++&i2c16 { ++ status = "okay"; ++ mctp-controller; ++ multi-master; ++ clock-frequency = <400000>; ++ ++ mctp@10 { ++ compatible = "mctp-i2c-controller"; ++ reg = <(0x10 | I2C_OWN_SLAVE_ADDRESS)>; ++ }; ++ ++ i2c-mux@72 { ++ compatible = "nxp,pca9544"; ++ reg = <0x72>; ++ ++ imux24: i2c@0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <0>; ++ mctp-controller; ++ temperature-sensor@1f { ++ compatible = "ti,tmp421"; ++ reg = <0x1f>; ++ }; ++ ++ temperature-sensor@3c { ++ compatible = "smsc,emc1403"; ++ reg = <0x3c>; ++ }; ++ ++ eeprom@50 { ++ compatible = "atmel,24c64"; ++ reg = <0x50>; ++ }; ++ }; ++ ++ imux25: i2c@1 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <1>; ++ mctp-controller; ++ temperature-sensor@1f { ++ compatible = "ti,tmp421"; ++ reg = <0x1f>; ++ }; ++ ++ temperature-sensor@3c { ++ compatible = "smsc,emc1403"; ++ reg = <0x3c>; ++ }; ++ ++ eeprom@50 { ++ compatible = "atmel,24c64"; ++ reg = <0x50>; ++ }; ++ }; ++ ++ imux26: i2c@2 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <2>; ++ mctp-controller; ++ temperature-sensor@1f { ++ compatible = "ti,tmp421"; ++ reg = <0x1f>; ++ }; ++ ++ temperature-sensor@3c { ++ compatible = "smsc,emc1403"; ++ reg = <0x3c>; ++ }; ++ ++ eeprom@50 { ++ compatible = "atmel,24c64"; ++ reg = <0x50>; ++ }; ++ }; ++ ++ imux27: i2c@3 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ reg = <3>; ++ mctp-controller; ++ temperature-sensor@1f { ++ compatible = "ti,tmp421"; ++ reg = <0x1f>; ++ }; ++ ++ temperature-sensor@3c { ++ compatible = "smsc,emc1403"; ++ reg = <0x3c>; ++ }; ++ ++ eeprom@50 { ++ compatible = "atmel,24c64"; ++ reg = <0x50>; ++ }; ++ }; ++ }; ++}; ++ ++&jtm1 { ++ status = "okay"; ++}; ++ ++&adc { ++ #io-channel-cells = <1>; ++ status = "okay"; ++ vref-supply = <®_vref1_8>; ++}; ++ ++&tmps { ++ status = "disabled"; ++}; ++ ++&sgpio1 { ++ status = "okay"; ++}; ++ ++&pspi { ++ status = "okay"; ++ cs-gpios = <&gpio6 11 GPIO_ACTIVE_LOW>; // GPIO203 ++ spi-max-frequency = <33000000>; ++ tpmdev@0 { ++ compatible = "tcg,tpm_tis-spi"; ++ reg = <0>; ++ }; ++}; ++ ++&pinctrl { ++ pinctrl-names = "default"; ++ pinctrl-0 = < ++ &bmcuart1_pins ++ &tp_uart_pins ++ &spi0_cs1_slew ++ &pspi_di_slew ++ &pspi_d0_slew ++ &pspi_ck_slew ++ &wdog1_pins ++ &wdog2_pins ++ &pin242_slew ++ &pin243_slew ++ &pin244_slew ++ &pin245_slew ++ &gpio4_pins ++ &gpio5_pins ++ &gpio6_pins ++ &gpio9o_pins ++ &gpio12o_pins ++ &gpio13ol_pins ++ &gpio14ol_pins ++ &gpio24o_pins ++ &gpi35_pins ++ &gpi36_pins ++ &gpio57_pins ++ &gpio93_pins ++ &gpio92_pins ++ &gpio96o_pins ++ &gpio120ol_pins ++ &gpio122o_pins ++ &gpio125ol_pins ++ &gpio126o_pins ++ &gpio127_pins ++ &gpio159_pins ++ &gpio162_pins ++ &gpio183_pins ++ &gpio184_pins ++ &gpio1836_pins ++ &gpio189_pins ++ &gpio1889_pins ++ &gpio190_pins ++ &gpio194ol_pins ++ &gpio196ol_pins ++ &gpio203o_pins ++ &gpio208ol_pins ++ &gpio228o_pins ++ &gpio233_pins ++ &gpio235ol_pins>; ++ ++ gpio0: gpio@f0010000 { ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ gpio-line-names = ++ "","","","","FM_BMC_RTCRST_R","PWRGD_P5V_USB_BMC","FLAG_P5V_USB_BMC_N","RST_USB_HUB_R_N", ++ "IRQ_BRIDGE_BMC_N","FM_BMC_RSTIND_R_N","","","RST_BMC_BRIDGE_R_N","EN_NIC0_POWER_BMC_R","EN_NIC1_POWER_BMC_R","PWRGD_SLOT6_STBY", ++ "","","","","","","","", ++ "RST_SMB_NIC2_R_N","PWRGD_SLOT5_STBY","","","","","",""; ++ }; ++ ++ gpio1: gpio@f0011000 { ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ gpio-line-names = ++ "","","","PRSNT_SB_SLOT2_N","PRSNT_SB_SLOT1_N","ALT_RTC_BMC_N","ALT_TEMP_BMC_N","PRSNT_OCP_DEBUG_BMC_N", ++ "PRSNT_TPM_BMC_N","","","","INT_SMB_BMC_SLOT1_4_BMC_N","PRSNT_SB_SLOT4_N","PWRGD_SLOT2_STBY","", ++ "","","","","","","PWRGD_SLOT3_STBY","PWRGD_SLOT4_STBY", ++ "","RST_PCIE_SLOT7_N","RST_PCIE_SLOT8_N","","","PWRGD_SLOT1_STBY","PRSNT_SB_SLOT3_N",""; ++ }; ++ ++ gpio2: gpio@f0012000 { ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ gpio-line-names = ++ "INT_SMB_BMC_SLOT5_8_BMC_N","AC_ON_OFF_BTN_CPLD_SLOT7_N","AC_ON_OFF_BTN_CPLD_SLOT8_N","FM_RESBTN_SLOT1_BMC_N","FM_RESBTN_SLOT2_BMC_N","FM_RESBTN_SLOT3_BMC_N","FM_RESBTN_SLOT4_BMC_N","FM_RESBTN_SLOT5_BMC_N", ++ "FM_RESBTN_SLOT6_BMC_N","FM_RESBTN_SLOT7_BMC_N","FM_RESBTN_SLOT8_BMC_N","FLT_HSC_SERVER_SLOT4_N","FLT_HSC_SERVER_SLOT5_N","FLT_HSC_SERVER_SLOT6_N","FLT_HSC_SERVER_SLOT7_N","FLT_HSC_SERVER_SLOT8_N", ++ "","","","PRSNT_SB_SLOT5_N","","","","", ++ "","","","RST_SMB_NIC1_R_N","PRSNT_NIC2_N","FM_NIC3_WAKE_N","AC_ON_OFF_BTN_CPLD_SLOT5_N",""; ++ }; ++ ++ gpio3: gpio@f0013000 { ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ gpio-line-names = ++ "RST_SMB_NIC3_R_N","","","","","","","", ++ "","","","","PWRGD_SLOT7_STBY","PWRGD_SLOT8_STBY","AC_ON_OFF_BTN_CPLD_SLOT4_N","AC_ON_OFF_BTN_CPLD_SLOT3_N", ++ "AC_ON_OFF_BTN_CPLD_SLOT2_N","AC_ON_OFF_BTN_CPLD_SLOT1_N","","","","","","", ++ "SEL_BMC_JTAG_MUX_R","","SPI_LOCK_REQ_BMC_N","SPI_WP_DISABLE_STATUS_R_N","ALT_SMB_BMC_CPLD1_N","EN_P5V_USB_CPLD_R","RST_SMB_NIC0_R_N","INT_MEDUSA_IOEXP_TEMP_N"; ++ }; ++ ++ gpio4: gpio@f0014000 { ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ gpio-line-names = ++ "","","","","","","","", ++ "","","","","","","","", ++ "PRSNT_SB_SLOT6_N","PRSNT_SB_SLOT7_N","PRSNT_SB_SLOT8_N","FM_PWRBRK_NIC_BMC_R2","ALT_MEDUSA_ADC_N","ALT_SMB_BMC_CPLD2_N","ALT_MEDUSA_P12V_EFUSE_N","", ++ "RST_PCIE_SLOT2_N","RST_PCIE_SLOT1_N","RST_PCIE_SLOT3_N","RST_PCIE_SLOT6_N","FLT_HSC_SERVER_SLOT1_N","FLT_HSC_SERVER_SLOT2_N","INT_SPIDER_ADC_R_N",""; ++ }; ++ ++ gpio5: gpio@f0015000 { ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ gpio-line-names = ++ "FM_BMC_SLED_CYCLE_R","","RTS_BRIDGE_BMC_SLOT5_N","","","","","", ++ "","RTS_BRIDGE_BMC_SLOT6_N","RTS_BRIDGE_BMC_SLOT7_N","","","","","", ++ "","","","","","","","PRSNT_NIC0_N", ++ "PRSNT_NIC3_N","","","","FM_NIC1_WAKE_N","PRSNT_NIC1_N","RTS_BRIDGE_BMC_SLOT8_N","AC_ON_OFF_BTN_CPLD_SLOT6_N"; ++ }; ++ ++ gpio6: gpio@f0016000 { ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ gpio-line-names = ++ "FM_NIC0_WAKE_N","","EN_NIC3_POWER_BMC_R","","EN_NIC2_POWER_BMC_R","","FLT_HSC_SERVER_SLOT3_N","RST_PCIE_SLOT5_N", ++ "","","","PSPI_BMC_TPM_CS_R_N","","","","", ++ "FM_BMC_READY_R2","ALT_SPIDER_TMP75_R_N","ALT_SPIDER_INA233_R_N","","FAST_PROCHOT_N","RST_PCIE_SLOT4_N","FM_NIC2_WAKE_N","", ++ "INT_FANBOARD1_IOEXP_N","INT_FANBOARD0_IOEXP_N","","","","","",""; ++ }; ++ ++ gpio7: gpio@f0017000 { ++ interrupt-controller; ++ #interrupt-cells = <2>; ++ gpio-line-names = ++ "","","","","LED_BMC_HB_R_N","","","", ++ "","PSPI_BMC_BRIDGE_CS_R_N","BTN_BMC_R2_N","EN_P3V_BAT_SCALED_R","","","","", ++ "","","","","","","","", ++ "","","ALT_P12V_AUX_N","","","","",""; ++ }; ++ ++ tp_uart_pins: tp-uart-pins { ++ groups = "tp_uart"; ++ function = "tp_uart"; ++ }; ++ spi0_cs1_slew: spi0-cs1-slew ++ { ++ pins = "GPIO32/SMB14B_SCL/SPI0_nCS1"; ++ slew-rate = <1>; ++ }; ++ pspi_di_slew: pspi-di-slew { ++ pins = "GPIO17/PSPI_DI/CP1_GPIO5"; ++ slew-rate = <1>; ++ }; ++ pspi_d0_slew: pspi-d0-slew { ++ pins = "GPIO18/PSPI_D0/SMB4B_SDA"; ++ slew-rate = <1>; ++ }; ++ pspi_ck_slew: pspi-ck-slew { ++ pins = "GPIO19/PSPI_CK/SMB4B_SCL"; ++ slew-rate = <1>; ++ }; ++ pin242_slew: pin242-slew { ++ pins = "GPIO242/I3C1_SCL"; ++ slew-rate = <1>; ++ }; ++ pin243_slew: pin243-slew { ++ pins = "GPIO243/I3C1_SDA"; ++ slew-rate = <1>; ++ }; ++ pin244_slew: pin244-slew { ++ pins = "GPIO244/I3C2_SCL"; ++ slew-rate = <1>; ++ }; ++ pin245_slew: pin245-slew { ++ pins = "GPIO245/I3C2_SDA"; ++ slew-rate = <1>; ++ }; ++ gpi35_pins: gpi35-pins { ++ groups = "gpi35"; ++ function = "gpi35"; ++ }; ++ gpi36_pins: gpi36-pins { ++ groups = "gpi36"; ++ function = "gpi36"; ++ }; ++ gpio1836_pins: gpio1836-pins { ++ groups = "gpio1836"; ++ function = "gpio1836"; ++ }; ++ gpio1889_pins: gpio1889-pins { ++ groups = "gpio1889"; ++ function = "gpio1889"; ++ }; ++ gpio4_pins: gpio4-pins { ++ pins = "GPIO4/IOX2_DI/SMB1D_SDA"; ++ bias-disable; ++ output-low; ++ }; ++ gpio5_pins: gpio5-pins { ++ pins = "GPIO5/IOX2_LD/SMB1D_SCL"; ++ bias-disable; ++ input-enable; ++ }; ++ gpio6_pins: gpio6-pins { ++ pins = "GPIO6/IOX2_CK/SMB2D_SDA"; ++ bias-disable; ++ input-enable; ++ }; ++ gpio9o_pins: gpio9o-pins { ++ pins = "GPIO9/LKGPO2/TP_GPIO1"; ++ bias-disable; ++ output-high; ++ }; ++ gpio12o_pins: gpio12o-pins { ++ pins = "GPIO12/GSPI_CK/SMB5B_SCL"; ++ bias-disable; ++ output-high; ++ }; ++ gpio13ol_pins: gpio13ol-pins { ++ pins = "GPIO13/GSPI_DO/SMB5B_SDA"; ++ bias-disable; ++ output-low; ++ }; ++ gpio14ol_pins: gpio14ol-pins { ++ pins = "GPIO14/GSPI_DI/SMB5C_SCL"; ++ bias-disable; ++ output-low; ++ }; ++ gpio24o_pins: gpio24o-pins { ++ pins = "GPIO24/IOXH_DO/H_GPIO4/SMB7C_SCL/TP_SMB2_SCL"; ++ bias-disable; ++ output-high; ++ }; ++ gpio57_pins: gpio57-pins { ++ pins = "GPIO57/R1_MDC/TP_GPIO4"; ++ bias-disable; ++ input-enable; ++ }; ++ gpio92_pins: gpio92-pins { ++ pins = "GPIO92/R2_MDIO/CP1_GPIO7/TP_GPIO1"; ++ bias-disable; ++ input-enable; ++ }; ++ gpio93_pins: gpio93-pins { ++ pins = "GPIO93/GA20/SMB5D_SCL"; ++ bias-disable; ++ input-enable; ++ }; ++ gpio96o_pins: gpio96o-pins { ++ pins = "GPIO96/CP1_GPIO7/BU2_TXD/TP_GPIO7"; ++ bias-disable; ++ output-high; ++ }; ++ gpio120ol_pins: gpio120ol-pins { ++ pins = "GPIO120/SMB2C_SDA"; ++ bias-disable; ++ output-low; ++ }; ++ gpio122o_pins: gpio122o-pins { ++ pins = "GPIO122/SMB2B_SDA"; ++ bias-disable; ++ output-high; ++ }; ++ gpio125ol_pins: gpio125ol-pins { ++ pins = "GPIO125/SMB1C_SCL/CP1_GPIO2"; ++ bias-disable; ++ output-low; ++ }; ++ gpio126o_pins: gpio126o-pins { ++ pins = "GPIO126/SMB1B_SDA/CP1_GPIO1"; ++ bias-disable; ++ output-high; ++ }; ++ gpio127_pins: gpio127-pins { ++ pins = "GPIO127/SMB1B_SCL/CP1_GPIO0"; ++ bias-disable; ++ input-enable; ++ }; ++ gpio159_pins: gpio159-pins { ++ pins = "GPIO159/MMC_DT3"; ++ bias-disable; ++ input-enable; ++ }; ++ gpio162_pins: gpio162-pins { ++ pins = "GPIO162/SERIRQ"; ++ bias-disable; ++ input-enable; ++ }; ++ gpio183_pins: gpio183-pins { ++ pins = "GPIO183/SPI3_SEL"; ++ bias-disable; ++ input-enable; ++ }; ++ gpio184_pins: gpio184-pins { ++ pins = "GPIO184/SPI3_D0/STRAP13"; ++ bias-disable; ++ input-enable; ++ }; ++ gpio189_pins: gpio189-pins { ++ pins = "GPIO189/SPI3_D3/SPI3_nCS3"; ++ bias-disable; ++ input-enable; ++ }; ++ gpio190_pins: gpio190-pins { ++ pins = "GPIO190/nPRD_SMI"; ++ bias-disable; ++ input-enable; ++ }; ++ gpio194ol_pins: gpio194ol-pins { ++ pins = "GPIO194/SMB0B_SCL/FM0_CK"; ++ bias-disable; ++ output-low; ++ }; ++ gpio196ol_pins: gpio196ol-pins { ++ pins = "GPIO196/SMB0C_SCL/FM0_D1"; ++ bias-disable; ++ output-low; ++ }; ++ gpio203o_pins: gpio203o-pins { ++ pins = "GPIO203/SPI1_nCS0/FANIN16/FM1_CSI"; ++ bias-disable; ++ output-high; ++ }; ++ gpio208ol_pins: gpio208ol-pins { ++ pins = "GPIO208/RG2_TXC/DVCK"; ++ bias-disable; ++ output-low; ++ }; ++ gpio228o_pins: gpio228o-pins { ++ pins = "GPIO228/SPIX_nCS1/FM2_CSO"; ++ bias-disable; ++ output-high; ++ }; ++ gpio233_pins: gpio233-pins { ++ pins = "GPIO233/SPI1_nCS1/FM1_CSO"; ++ bias-disable; ++ input-enable; ++ }; ++ gpio235ol_pins: gpio235ol-pins { ++ pins = "GPIO235/PWM11/SMB20_SDA"; ++ bias-disable; ++ output-low; ++ }; ++ i3c1_scl_slew: i3c1scl-slew { ++ pins = "GPIO242/I3C1_SCL"; ++ slew-rate = <1>; ++ }; ++ i3c1_sda_slew: i3c1sda-slew { ++ pins = "GPIO243/I3C1_SDA"; ++ slew-rate = <1>; ++ }; ++ i3c2_scl_slew: i3c2scl-slew { ++ pins = "GPIO244/I3C2_SCL"; ++ slew-rate = <1>; ++ }; ++ i3c2_sda_slew: i3c2sda-slew { ++ pins = "GPIO245/I3C2_SDA"; ++ slew-rate = <1>; ++ }; ++}; +-- +2.34.1 + diff --git a/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1015-net-stmmac-Add-NCSI-support-for-STMMAC.patch b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1015-net-stmmac-Add-NCSI-support-for-STMMAC.patch new file mode 100644 index 00000000000..98e9f986f76 --- /dev/null +++ b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1015-net-stmmac-Add-NCSI-support-for-STMMAC.patch @@ -0,0 +1,409 @@ +From 7518955e5d6cd46e5cede06247eb1155e55d22df Mon Sep 17 00:00:00 2001 +From: Marvin Lin +Date: Thu, 27 Jun 2024 14:27:27 +0800 +Subject: [PATCH] net: stmmac: Add NCSI support for STMMAC + +Add NCSI support for STMMAC. + +This change is also contributing to torvalds upstream for reviewing. +Lore Link: https://lore.kernel.org/all/20240709145039.1910298-1-tmaimon77@gmail.com/ + +Signed-off-by: Marvin Lin +Signed-off-by: Tomer Maimon +--- + drivers/net/ethernet/stmicro/stmmac/stmmac.h | 2 + + .../net/ethernet/stmicro/stmmac/stmmac_main.c | 196 ++++++++++++------ + .../ethernet/stmicro/stmmac/stmmac_platform.c | 27 ++- + include/linux/stmmac.h | 1 + + 4 files changed, 158 insertions(+), 68 deletions(-) + +diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h +index b8c93b881a65..02db099e29b2 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h +@@ -332,6 +332,8 @@ struct stmmac_priv { + /* XDP BPF Program */ + unsigned long *af_xdp_zc_qps; + struct bpf_prog *xdp_prog; ++ ++ struct ncsi_dev *ncsidev; + }; + + enum stmmac_state { +diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +index 19c58ad8df34..d79f1ff40d39 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +@@ -50,6 +50,7 @@ + #include "dwmac1000.h" + #include "dwxgmac2.h" + #include "hwif.h" ++#include + + /* As long as the interface is active, we keep the timestamping counter enabled + * with fine resolution and binary rollover. This avoid non-monotonic behavior +@@ -2937,10 +2938,12 @@ static int stmmac_init_dma_engine(struct stmmac_priv *priv) + if (priv->extend_desc && (priv->mode == STMMAC_RING_MODE)) + atds = 1; + +- ret = stmmac_reset(priv, priv->ioaddr); +- if (ret) { +- dev_err(priv->device, "Failed to reset the dma\n"); +- return ret; ++ if (!priv->plat->use_ncsi) { ++ ret = stmmac_reset(priv, priv->ioaddr); ++ if (ret) { ++ dev_err(priv->device, "Failed to reset the dma\n"); ++ return ret; ++ } + } + + /* DMA Configuration */ +@@ -3454,6 +3457,15 @@ static void stmmac_hw_teardown(struct net_device *dev) + clk_disable_unprepare(priv->plat->clk_ptp_ref); + } + ++static void stmmac_ncsi_handler(struct ncsi_dev *nd) ++{ ++ if (unlikely(nd->state != ncsi_dev_state_functional)) ++ return; ++ ++ netdev_info(nd->dev, "NCSI interface %s\n", ++ nd->link_up ? "up" : "down"); ++} ++ + static void stmmac_free_irq(struct net_device *dev, + enum request_irq_err irq_err, int irq_idx) + { +@@ -3819,17 +3831,19 @@ static int __stmmac_open(struct net_device *dev, + if (ret < 0) + return ret; + +- if (priv->hw->pcs != STMMAC_PCS_TBI && +- priv->hw->pcs != STMMAC_PCS_RTBI && +- (!priv->hw->xpcs || +- xpcs_get_an_mode(priv->hw->xpcs, mode) != DW_AN_C73) && +- !priv->hw->lynx_pcs) { +- ret = stmmac_init_phy(dev); +- if (ret) { +- netdev_err(priv->dev, +- "%s: Cannot attach to PHY (error: %d)\n", +- __func__, ret); +- goto init_phy_error; ++ if (!priv->plat->use_ncsi) { ++ if (priv->hw->pcs != STMMAC_PCS_TBI && ++ priv->hw->pcs != STMMAC_PCS_RTBI && ++ (!priv->hw->xpcs || ++ xpcs_get_an_mode(priv->hw->xpcs, mode) != DW_AN_C73) && ++ !priv->hw->lynx_pcs) { ++ ret = stmmac_init_phy(dev); ++ if (ret) { ++ netdev_err(priv->dev, ++ "%s: Cannot attach to PHY (error: %d)\n", ++ __func__, ret); ++ goto init_phy_error; ++ } + } + } + +@@ -3861,9 +3875,23 @@ static int __stmmac_open(struct net_device *dev, + + stmmac_init_coalesce(priv); + +- phylink_start(priv->phylink); +- /* We may have called phylink_speed_down before */ +- phylink_speed_up(priv->phylink); ++ if (priv->plat->use_ncsi) { ++ u32 ctrl; ++ stmmac_mac_flow_ctrl(priv, DUPLEX_FULL); ++ ctrl = readl(priv->ioaddr + MAC_CTRL_REG); ++ ctrl &= ~priv->hw->link.speed_mask; ++ ctrl |= priv->hw->link.speed100; ++ ctrl |= priv->hw->link.duplex; ++ writel(ctrl, priv->ioaddr + MAC_CTRL_REG); ++ ++ priv->speed = SPEED_100; ++ /* If using NC-SI subsystem, set our carrier on and start the stack */ ++ netif_carrier_on(dev); ++ } else { ++ phylink_start(priv->phylink); ++ /* We may have called phylink_speed_down before */ ++ phylink_speed_up(priv->phylink); ++ } + + ret = stmmac_request_irq(dev); + if (ret) +@@ -3873,17 +3901,29 @@ static int __stmmac_open(struct net_device *dev, + netif_tx_start_all_queues(priv->dev); + stmmac_enable_all_dma_irq(priv); + +- return 0; ++ /* Start the NCSI device */ ++ if (priv->plat->use_ncsi) { ++ ret = ncsi_start_dev(priv->ncsidev); ++ if (ret) { ++ netdev_err(priv->dev, "ERROR: start the ncsi device(%d)\n",ret); ++ goto ncsi_error; ++ } ++ } + ++ return 0; ++ncsi_error: ++ stmmac_disable_all_queues(priv); + irq_error: +- phylink_stop(priv->phylink); ++ if (!priv->plat->use_ncsi) ++ phylink_stop(priv->phylink); + + for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) + hrtimer_cancel(&priv->dma_conf.tx_queue[chan].txtimer); + + stmmac_hw_teardown(dev); + init_error: +- phylink_disconnect_phy(priv->phylink); ++ if (!priv->plat->use_ncsi) ++ phylink_disconnect_phy(priv->phylink); + init_phy_error: + pm_runtime_put(priv->device); + return ret; +@@ -3930,11 +3970,15 @@ static int stmmac_release(struct net_device *dev) + struct stmmac_priv *priv = netdev_priv(dev); + u32 chan; + +- if (device_may_wakeup(priv->device)) +- phylink_speed_down(priv->phylink, false); +- /* Stop and disconnect the PHY */ +- phylink_stop(priv->phylink); +- phylink_disconnect_phy(priv->phylink); ++ if (priv->plat->use_ncsi) { ++ ncsi_stop_dev(priv->ncsidev); ++ } else { ++ if (device_may_wakeup(priv->device)) ++ phylink_speed_down(priv->phylink, false); ++ /* Stop and disconnect the PHY */ ++ phylink_stop(priv->phylink); ++ phylink_disconnect_phy(priv->phylink); ++ } + + stmmac_disable_all_queues(priv); + +@@ -6030,7 +6074,8 @@ static int stmmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) + case SIOCGMIIPHY: + case SIOCGMIIREG: + case SIOCSMIIREG: +- ret = phylink_mii_ioctl(priv->phylink, rq, cmd); ++ if (!priv->plat->use_ncsi) ++ ret = phylink_mii_ioctl(priv->phylink, rq, cmd); + break; + case SIOCSHWTSTAMP: + ret = stmmac_hwtstamp_set(dev, rq); +@@ -6501,6 +6546,9 @@ static int stmmac_vlan_rx_add_vid(struct net_device *ndev, __be16 proto, u16 vid + bool is_double = false; + int ret; + ++ if (priv->plat->use_ncsi) ++ return ncsi_vlan_rx_add_vid(ndev, proto, vid); ++ + ret = pm_runtime_resume_and_get(priv->device); + if (ret < 0) + return ret; +@@ -6532,6 +6580,9 @@ static int stmmac_vlan_rx_kill_vid(struct net_device *ndev, __be16 proto, u16 vi + bool is_double = false; + int ret; + ++ if (priv->plat->use_ncsi) ++ return ncsi_vlan_rx_kill_vid(ndev, proto, vid); ++ + ret = pm_runtime_resume_and_get(priv->device); + if (ret < 0) + return ret; +@@ -7354,7 +7405,9 @@ int stmmac_dvr_probe(struct device *device, + if (!priv->xstats.pcpu_stats) + return -ENOMEM; + +- stmmac_set_ethtool_ops(ndev); ++ if (!plat_dat->use_ncsi) ++ stmmac_set_ethtool_ops(ndev); ++ + priv->pause = pause; + priv->plat = plat_dat; + priv->ioaddr = res->addr; +@@ -7468,6 +7521,9 @@ int stmmac_dvr_probe(struct device *device, + * host DMA width for allocation and the device DMA width for + * register handling. + */ ++ if (priv->plat->use_ncsi) ++ ndev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER; ++ + if (priv->plat->host_dma_width) + priv->dma_cap.host_dma_width = priv->plat->host_dma_width; + else +@@ -7576,31 +7632,45 @@ int stmmac_dvr_probe(struct device *device, + if (!pm_runtime_enabled(device)) + pm_runtime_enable(device); + +- if (priv->hw->pcs != STMMAC_PCS_TBI && +- priv->hw->pcs != STMMAC_PCS_RTBI) { +- /* MDIO bus Registration */ +- ret = stmmac_mdio_register(ndev); +- if (ret < 0) { +- dev_err_probe(priv->device, ret, +- "%s: MDIO bus (id: %d) registration failed\n", +- __func__, priv->plat->bus_id); +- goto error_mdio_register; ++ if (!priv->plat->use_ncsi) { ++ if (priv->hw->pcs != STMMAC_PCS_TBI && ++ priv->hw->pcs != STMMAC_PCS_RTBI) { ++ /* MDIO bus Registration */ ++ ret = stmmac_mdio_register(ndev); ++ if (ret < 0) { ++ dev_err_probe(priv->device, ret, ++ "%s: MDIO bus (id: %d) registration failed\n", ++ __func__, priv->plat->bus_id); ++ goto error_mdio_register; ++ } + } +- } + +- if (priv->plat->speed_mode_2500) +- priv->plat->speed_mode_2500(ndev, priv->plat->bsp_priv); ++ if (priv->plat->speed_mode_2500) ++ priv->plat->speed_mode_2500(ndev, priv->plat->bsp_priv); + +- if (priv->plat->mdio_bus_data && priv->plat->mdio_bus_data->has_xpcs) { +- ret = stmmac_xpcs_setup(priv->mii); +- if (ret) +- goto error_xpcs_setup; +- } ++ if (priv->plat->mdio_bus_data && priv->plat->mdio_bus_data->has_xpcs) { ++ ret = stmmac_xpcs_setup(priv->mii); ++ if (ret) ++ goto error_xpcs_setup; ++ } + +- ret = stmmac_phy_setup(priv); +- if (ret) { +- netdev_err(ndev, "failed to setup phy (%d)\n", ret); +- goto error_phy_setup; ++ ret = stmmac_phy_setup(priv); ++ if (ret) { ++ netdev_err(ndev, "failed to setup phy (%d)\n", ret); ++ goto error_phy_setup; ++ } ++ } else { ++ if (!IS_ENABLED(CONFIG_NET_NCSI)) { ++ netdev_err(priv->dev, "CONFIG_NET_NCSI not enabled\n"); ++ goto error_phy_setup; ++ } ++ dev_info(priv->device, "register NCSI dev\n"); ++ priv->ncsidev = ncsi_register_dev(priv->dev, ++ stmmac_ncsi_handler); ++ if (!priv->ncsidev) ++ goto error_phy_setup; ++ ++ dev_info(priv->device, "Using NCSI interface\n"); + } + + ret = register_netdev(ndev); +@@ -7625,12 +7695,14 @@ int stmmac_dvr_probe(struct device *device, + return ret; + + error_netdev_register: +- phylink_destroy(priv->phylink); ++ if (!priv->plat->use_ncsi) ++ phylink_destroy(priv->phylink); + error_xpcs_setup: + error_phy_setup: +- if (priv->hw->pcs != STMMAC_PCS_TBI && +- priv->hw->pcs != STMMAC_PCS_RTBI) +- stmmac_mdio_unregister(ndev); ++ if (!priv->plat->use_ncsi) ++ if (priv->hw->pcs != STMMAC_PCS_TBI && ++ priv->hw->pcs != STMMAC_PCS_RTBI) ++ stmmac_mdio_unregister(ndev); + error_mdio_register: + stmmac_napi_del(ndev); + error_hw_init: +@@ -7728,15 +7800,17 @@ int stmmac_suspend(struct device *dev) + + mutex_unlock(&priv->lock); + +- rtnl_lock(); +- if (device_may_wakeup(priv->device) && priv->plat->pmt) { +- phylink_suspend(priv->phylink, true); +- } else { +- if (device_may_wakeup(priv->device)) +- phylink_speed_down(priv->phylink, false); +- phylink_suspend(priv->phylink, false); ++ if (!priv->plat->use_ncsi) { ++ rtnl_lock(); ++ if (device_may_wakeup(priv->device) && priv->plat->pmt) { ++ phylink_suspend(priv->phylink, true); ++ } else { ++ if (device_may_wakeup(priv->device)) ++ phylink_speed_down(priv->phylink, false); ++ phylink_suspend(priv->phylink, false); ++ } ++ rtnl_unlock(); + } +- rtnl_unlock(); + + if (priv->dma_cap.fpesel) { + /* Disable FPE */ +diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +index 30d5e635190e..8865a74b6f32 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +@@ -417,17 +417,30 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac) + eth_zero_addr(mac); + } + +- phy_mode = device_get_phy_mode(&pdev->dev); +- if (phy_mode < 0) +- return ERR_PTR(phy_mode); ++ if (of_get_property(pdev->dev.of_node, "use-ncsi", NULL)) { ++ plat->use_ncsi = true; ++ plat->has_xgmac = 0; ++ plat->has_gmac4 = 0; ++ plat->has_gmac = 0; ++ } ++ else ++ plat->use_ncsi = false; + +- plat->phy_interface = phy_mode; ++ if (!plat->use_ncsi) { ++ phy_mode = device_get_phy_mode(&pdev->dev); ++ if (phy_mode < 0) ++ return ERR_PTR(phy_mode); ++ ++ plat->phy_interface = phy_mode; ++ } + rc = stmmac_of_get_mac_mode(np); + plat->mac_interface = rc < 0 ? plat->phy_interface : rc; + +- /* Some wrapper drivers still rely on phy_node. Let's save it while +- * they are not converted to phylink. */ +- plat->phy_node = of_parse_phandle(np, "phy-handle", 0); ++ if (!plat->use_ncsi) { ++ /* Some wrapper drivers still rely on phy_node. Let's save it while ++ * they are not converted to phylink. */ ++ plat->phy_node = of_parse_phandle(np, "phy-handle", 0); ++ } + + /* PHYLINK automatically parses the phy-handle property */ + plat->port_node = of_fwnode_handle(np); +diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h +index 5acb77968902..3e948e685ada 100644 +--- a/include/linux/stmmac.h ++++ b/include/linux/stmmac.h +@@ -285,6 +285,7 @@ struct plat_stmmacenet_data { + void *ctx); + void (*dump_debug_regs)(void *priv); + void *bsp_priv; ++ int use_ncsi; + struct clk *stmmac_clk; + struct clk *pclk; + struct clk *clk_ptp_ref; +-- +2.34.1 + diff --git a/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1016-spi-npcm-fiu-add-dual-and-quad-write-support.patch b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1016-spi-npcm-fiu-add-dual-and-quad-write-support.patch new file mode 100644 index 00000000000..b66a7b1c1b6 --- /dev/null +++ b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1016-spi-npcm-fiu-add-dual-and-quad-write-support.patch @@ -0,0 +1,67 @@ +From 9801cc7080a51985f763ced673a46c00a0132717 Mon Sep 17 00:00:00 2001 +From: Tomer Maimon +Date: Thu, 9 May 2024 12:43:06 +0300 +Subject: [PATCH] spi: npcm-fiu: add dual and quad write support + +Add dual and quad write support by writing the command write in the UMA +register first and then write the data in chunks of 16 bytes. + +This change is also contributing to torvalds upstream for reviewing. +Lore Link: https://lore.kernel.org/all/20240709184813.1946724-1-tmaimon77@gmail.com/ + +Signed-off-by: Stanley Chu +Signed-off-by: Tomer Maimon +--- + drivers/spi/spi-npcm-fiu.c | 15 ++++++++------- + 1 file changed, 8 insertions(+), 7 deletions(-) + +diff --git a/drivers/spi/spi-npcm-fiu.c b/drivers/spi/spi-npcm-fiu.c +index bb9e784d8058..ac4b5fe5a1ac 100644 +--- a/drivers/spi/spi-npcm-fiu.c ++++ b/drivers/spi/spi-npcm-fiu.c +@@ -393,7 +393,7 @@ static int npcm_fiu_uma_write(struct spi_mem *mem, + { + struct npcm_fiu_spi *fiu = + spi_controller_get_devdata(mem->spi->controller); +- u32 uma_cfg = BIT(10); ++ u32 uma_cfg = cmd ? BIT(10) : 0; + u32 data_reg[4] = {0}; + u32 val; + u32 i; +@@ -403,8 +403,11 @@ static int npcm_fiu_uma_write(struct spi_mem *mem, + (spi_get_chipselect(mem->spi, 0) << + NPCM_FIU_UMA_CTS_DEV_NUM_SHIFT)); + +- regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CMD, +- NPCM_FIU_UMA_CMD_CMD, cmd); ++ if (cmd) ++ regmap_update_bits(fiu->regmap, NPCM_FIU_UMA_CMD, ++ NPCM_FIU_UMA_CMD_CMD, cmd); ++ else ++ uma_cfg |= ilog2(op->data.buswidth) << NPCM_FIU_UMA_CFG_WDBPCK_SHIFT; + + if (data_size) { + memcpy(data_reg, data, data_size); +@@ -464,8 +467,7 @@ static int npcm_fiu_manualwrite(struct spi_mem *mem, + + /* Starting the data writing loop in multiples of 8 */ + for (idx = 0; idx < num_data_chunks; ++idx) { +- ret = npcm_fiu_uma_write(mem, op, data[0], false, +- &data[1], CHUNK_SIZE - 1); ++ ret = npcm_fiu_uma_write(mem, op, 0, false, &data[0], CHUNK_SIZE); + if (ret) + return ret; + +@@ -474,8 +476,7 @@ static int npcm_fiu_manualwrite(struct spi_mem *mem, + + /* Handling chunk remains */ + if (remain_data > 0) { +- ret = npcm_fiu_uma_write(mem, op, data[0], false, +- &data[1], remain_data - 1); ++ ret = npcm_fiu_uma_write(mem, op, 0, false, &data[0], remain_data); + if (ret) + return ret; + } +-- +2.34.1 + diff --git a/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1017-spi-npcm-fiu-add-delay-before-reboot-to-avoi.patch b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1017-spi-npcm-fiu-add-delay-before-reboot-to-avoi.patch new file mode 100644 index 00000000000..6dc590454d0 --- /dev/null +++ b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1017-spi-npcm-fiu-add-delay-before-reboot-to-avoi.patch @@ -0,0 +1,56 @@ +From 84e65489a64b3a674093c97a0d4e1dc2f6d5bd22 Mon Sep 17 00:00:00 2001 +From: Marvin Lin +Date: Fri, 24 May 2024 17:10:08 +0800 +Subject: [PATCH] spi: npcm-fiu: add delay before reboot to avoid FIU0 + busy + +--- + drivers/spi/spi-npcm-fiu.c | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/drivers/spi/spi-npcm-fiu.c b/drivers/spi/spi-npcm-fiu.c +index 5853684f3df3..5ba90c8eb361 100644 +--- a/drivers/spi/spi-npcm-fiu.c ++++ b/drivers/spi/spi-npcm-fiu.c +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -694,6 +695,20 @@ static const struct of_device_id npcm_fiu_dt_ids[] = { + { /* sentinel */ } + }; + ++static int fiu_spi_reboot(struct notifier_block *nb, unsigned long action, ++ void *data) ++{ ++ /* give a chance to delay for a while to avoid cpu cannot access ++ * spi flash data if program/erase progress */ ++ mdelay(1000); ++ return NOTIFY_DONE; ++} ++ ++static struct notifier_block fiu_spi_reboot_nb = { ++ .notifier_call = fiu_spi_reboot, ++ .priority = 255, ++}; ++ + static int npcm_fiu_probe(struct platform_device *pdev) + { + const struct fiu_data *fiu_data_match; +@@ -763,6 +778,9 @@ static int npcm_fiu_probe(struct platform_device *pdev) + if (ret) + clk_disable_unprepare(fiu->clk); + ++ if (fiu->info->fiu_id == FIU0) ++ register_restart_handler(&fiu_spi_reboot_nb); ++ + return ret; + } + +-- +2.34.1 + diff --git a/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1018-spi-npcm-pspi-Add-full-duplex-support.patch b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1018-spi-npcm-pspi-Add-full-duplex-support.patch new file mode 100644 index 00000000000..a9de9aae80b --- /dev/null +++ b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1018-spi-npcm-pspi-Add-full-duplex-support.patch @@ -0,0 +1,145 @@ +From 6a9f7cc3a2b6951d97bfc1587b7c7dc120364cb7 Mon Sep 17 00:00:00 2001 +From: Tomer Maimon +Date: Tue, 9 Jul 2024 19:02:41 +0300 +Subject: [PATCH] spi: npcm-pspi: add full duplex support + +The NPCM PSPI handler, on TX-buffer not null, would perform a dummy read +but did not save the rx-data, this was valid only for half duplex. + +This patch adds full duplex support for NPCM PSPI driver by storing all +rx-data when the Rx-buffer is defined also for TX-buffer handling. + +This change is also contributing to torvalds upstream for reviewing. +Lore Link: https://lore.kernel.org/r/20210113200010.71845-11-tmaimon77@gmail.com + +Signed-off-by: Tomer Maimon +--- + drivers/spi/spi-npcm-pspi.c | 75 +++++++++++++++---------------------- + 1 file changed, 30 insertions(+), 45 deletions(-) + +diff --git a/drivers/spi/spi-npcm-pspi.c b/drivers/spi/spi-npcm-pspi.c +index 64585c2a25c5..7961b5442082 100644 +--- a/drivers/spi/spi-npcm-pspi.c ++++ b/drivers/spi/spi-npcm-pspi.c +@@ -195,22 +195,22 @@ static void npcm_pspi_setup_transfer(struct spi_device *spi, + static void npcm_pspi_send(struct npcm_pspi *priv) + { + int wsize; +- u16 val; ++ u16 val = 0; + + wsize = min(bytes_per_word(priv->bits_per_word), priv->tx_bytes); + priv->tx_bytes -= wsize; + +- if (!priv->tx_buf) +- return; +- + switch (wsize) { + case 1: +- val = *priv->tx_buf++; ++ if (priv->tx_buf) ++ val = *priv->tx_buf++; + iowrite8(val, NPCM_PSPI_DATA + priv->base); + break; + case 2: +- val = *priv->tx_buf++; +- val = *priv->tx_buf++ | (val << 8); ++ if (priv->tx_buf) { ++ val = *priv->tx_buf++; ++ val = *priv->tx_buf++ | (val << 8); ++ } + iowrite16(val, NPCM_PSPI_DATA + priv->base); + break; + default: +@@ -222,22 +222,24 @@ static void npcm_pspi_send(struct npcm_pspi *priv) + static void npcm_pspi_recv(struct npcm_pspi *priv) + { + int rsize; +- u16 val; ++ u16 val_16; ++ u8 val_8; + + rsize = min(bytes_per_word(priv->bits_per_word), priv->rx_bytes); + priv->rx_bytes -= rsize; + +- if (!priv->rx_buf) +- return; +- + switch (rsize) { + case 1: +- *priv->rx_buf++ = ioread8(priv->base + NPCM_PSPI_DATA); ++ val_8 = ioread8(priv->base + NPCM_PSPI_DATA); ++ if (priv->rx_buf) ++ *priv->rx_buf++ = val_8; + break; + case 2: +- val = ioread16(priv->base + NPCM_PSPI_DATA); +- *priv->rx_buf++ = (val >> 8); +- *priv->rx_buf++ = val & 0xff; ++ val_16 = ioread16(priv->base + NPCM_PSPI_DATA); ++ if (priv->rx_buf) { ++ *priv->rx_buf++ = (val_16 >> 8); ++ *priv->rx_buf++ = val_16 & 0xff; ++ } + break; + default: + WARN_ON_ONCE(1); +@@ -296,43 +298,26 @@ static irqreturn_t npcm_pspi_handler(int irq, void *dev_id) + struct npcm_pspi *priv = dev_id; + u8 stat; + +- stat = ioread8(priv->base + NPCM_PSPI_STAT); +- + if (!priv->tx_buf && !priv->rx_buf) + return IRQ_NONE; + +- if (priv->tx_buf) { +- if (stat & NPCM_PSPI_STAT_RBF) { +- ioread8(NPCM_PSPI_DATA + priv->base); +- if (priv->tx_bytes == 0) { +- npcm_pspi_disable(priv); +- complete(&priv->xfer_done); +- return IRQ_HANDLED; +- } +- } +- +- if ((stat & NPCM_PSPI_STAT_BSY) == 0) +- if (priv->tx_bytes) +- npcm_pspi_send(priv); ++ if (priv->tx_bytes == 0 && priv->rx_bytes == 0) { ++ npcm_pspi_disable(priv); ++ complete(&priv->xfer_done); ++ return IRQ_HANDLED; + } + +- if (priv->rx_buf) { +- if (stat & NPCM_PSPI_STAT_RBF) { +- if (!priv->rx_bytes) +- return IRQ_NONE; +- +- npcm_pspi_recv(priv); ++ stat = ioread8(priv->base + NPCM_PSPI_STAT); + +- if (!priv->rx_bytes) { +- npcm_pspi_disable(priv); +- complete(&priv->xfer_done); +- return IRQ_HANDLED; +- } +- } ++ /* ++ * first we do the read since if we do the write we previous read might ++ * be lost (indeed low chances) ++ */ ++ if ((stat & NPCM_PSPI_STAT_RBF) && priv->rx_bytes) ++ npcm_pspi_recv(priv); + +- if (((stat & NPCM_PSPI_STAT_BSY) == 0) && !priv->tx_buf) +- iowrite8(0x0, NPCM_PSPI_DATA + priv->base); +- } ++ if (((stat & NPCM_PSPI_STAT_BSY) == 0) && priv->tx_bytes) ++ npcm_pspi_send(priv); + + return IRQ_HANDLED; + } +-- +2.34.1 diff --git a/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1019-spi-npcm-pspi-Fix-transfer-bits-per-word-issue-389.patch b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1019-spi-npcm-pspi-Fix-transfer-bits-per-word-issue-389.patch new file mode 100644 index 00000000000..15f0cca7c98 --- /dev/null +++ b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1019-spi-npcm-pspi-Fix-transfer-bits-per-word-issue-389.patch @@ -0,0 +1,66 @@ +From 5a7bc5fdd1034b6ed07a6c3e43d887e88a8b010a Mon Sep 17 00:00:00 2001 +From: jc849 <122246431+jc849@users.noreply.github.com> +Date: Wed, 20 Mar 2024 20:01:44 +0800 +Subject: [PATCH] spi: npcm-pspi: Fix transfer bits per word issue + +This patch fix transfer bits per word issue by avoid polluting SPI +transfer data, as it may be reused and alter the transfer length and +tx/rx buffer (e.g., tpm-spi). + +By default, use an 8-bit data interface mode. +However, change to a 16-bit mode when the transfer length is even. + +This change is also contributing to torvalds upstream for reviewing. +Lore Link: https://lore.kernel.org/all/20240709160242.1921541-3-tmaimon77@gmail.com/ + +Signed-off-by: cpchiang +Signed-off-by: Tomer Maimon +--- + drivers/spi/spi-npcm-pspi.c | 15 ++++++++------- + 1 file changed, 8 insertions(+), 7 deletions(-) + +diff --git a/drivers/spi/spi-npcm-pspi.c b/drivers/spi/spi-npcm-pspi.c +index 7961b5442082..726e6dc01c7d 100644 +--- a/drivers/spi/spi-npcm-pspi.c ++++ b/drivers/spi/spi-npcm-pspi.c +@@ -160,6 +160,7 @@ static void npcm_pspi_setup_transfer(struct spi_device *spi, + struct spi_transfer *t) + { + struct npcm_pspi *priv = spi_master_get_devdata(spi->master); ++ u8 bits_per_word = 8; + + priv->tx_buf = t->tx_buf; + priv->rx_buf = t->rx_buf; +@@ -172,15 +173,14 @@ static void npcm_pspi_setup_transfer(struct spi_device *spi, + } + + /* +- * If transfer is even length, and 8 bits per word transfer, +- * then implement 16 bits-per-word transfer. ++ * If transfer is even length, change to use 16 bits-per-word transfer. + */ +- if (priv->bits_per_word == 8 && !(t->len & 0x1)) +- t->bits_per_word = 16; ++ if (!(t->len & 0x1)) ++ bits_per_word = 16; + +- if (!priv->is_save_param || priv->bits_per_word != t->bits_per_word) { +- npcm_pspi_set_transfer_size(priv, t->bits_per_word); +- priv->bits_per_word = t->bits_per_word; ++ if (!priv->is_save_param || priv->bits_per_word != bits_per_word) { ++ npcm_pspi_set_transfer_size(priv, bits_per_word); ++ priv->bits_per_word = bits_per_word; + } + + if (!priv->is_save_param || priv->speed_hz != t->speed_hz) { +@@ -339,6 +339,7 @@ static int npcm_pspi_probe(struct platform_device *pdev) + priv = spi_master_get_devdata(master); + priv->master = master; + priv->is_save_param = false; ++ priv->bits_per_word = 8; + + priv->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->base)) { +-- +2.34.1 + diff --git a/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1020-usb-chipidea-udc-enforce-write-to-the-memory.patch b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1020-usb-chipidea-udc-enforce-write-to-the-memory.patch new file mode 100644 index 00000000000..acbbce33912 --- /dev/null +++ b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1020-usb-chipidea-udc-enforce-write-to-the-memory.patch @@ -0,0 +1,61 @@ +From e76ab6b9cea51c5a7cf0242438563f25b7edd772 Mon Sep 17 00:00:00 2001 +From: Tomer Maimon +Date: Tue, 16 Apr 2024 21:12:58 +0300 +Subject: [PATCH] usb: chipidea: udc: enforce write to the memory. + +During prime endpoint function we need to read from qh.ptr->td.token +to make sure the previous write to it indeed got into the memory. + +This change is also contributing to torvalds upstream for reviewing. +Lore Link: https://lore.kernel.org/all/20240710124157.2106609-1-tmaimon77@gmail.com/ + +Signed-off-by: Tomer Maimon +--- + drivers/usb/chipidea/udc.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c +index 0b7bd3c643c3..6e5bba9b0043 100644 +--- a/drivers/usb/chipidea/udc.c ++++ b/drivers/usb/chipidea/udc.c +@@ -190,12 +190,18 @@ static int hw_ep_get_halt(struct ci_hdrc *ci, int num, int dir) + * + * This function returns an error code + */ +-static int hw_ep_prime(struct ci_hdrc *ci, int num, int dir, int is_ctrl) ++static int hw_ep_prime(struct ci_hdrc *ci, struct ci_hw_ep *hwep, int num, int dir, int is_ctrl) + { + int n = hw_ep_bit(num, dir); + + /* Synchronize before ep prime */ + wmb(); ++ ++ /* We add the read from qh.ptr->td.token to make sure the previous ++ write to it indeed got into the mamory so when we prime the DMA ++ will read the updated data */ ++ if (hwep->qh.ptr->td.token & 0x80000000) ++ pr_info("%s(): hwep->qh.ptr->td.token=%08x\n", __func__, hwep->qh.ptr->td.token); + + if (is_ctrl && dir == RX && hw_read(ci, OP_ENDPTSETUPSTAT, BIT(num))) + return -EAGAIN; +@@ -632,7 +638,7 @@ static int _hardware_enqueue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq) + hwep->qh.ptr->cap |= cpu_to_le32(mul << __ffs(QH_MULT)); + } + +- ret = hw_ep_prime(ci, hwep->num, hwep->dir, ++ ret = hw_ep_prime(ci, hwep, hwep->num, hwep->dir, + hwep->type == USB_ENDPOINT_XFER_CONTROL); + done: + return ret; +@@ -658,7 +664,7 @@ static int reprime_dtd(struct ci_hdrc *ci, struct ci_hw_ep *hwep, + hwep->qh.ptr->td.token &= + cpu_to_le32(~(TD_STATUS_HALTED | TD_STATUS_ACTIVE)); + +- return hw_ep_prime(ci, hwep->num, hwep->dir, ++ return hw_ep_prime(ci, hwep, hwep->num, hwep->dir, + hwep->type == USB_ENDPOINT_XFER_CONTROL); + } + +-- +2.34.1 + diff --git a/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1021-i2c-npcm-disable-interrupt-enable-bit-before-devm_re.patch b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1021-i2c-npcm-disable-interrupt-enable-bit-before-devm_re.patch new file mode 100644 index 00000000000..a33f4f3f680 --- /dev/null +++ b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1021-i2c-npcm-disable-interrupt-enable-bit-before-devm_re.patch @@ -0,0 +1,98 @@ +From cc28eef4d1cb8c5bfc77f843ce5bfbde442d16b8 Mon Sep 17 00:00:00 2001 +From: Tyrone Ting +Date: Tue, 25 Jun 2024 18:10:49 +0800 +Subject: [PATCH] i2c: npcm: disable interrupt enable bit before + devm_request_irq + +The customer reports that there is a soft lockup issue related to +the i2c driver. After checking, the i2c module was doing a tx transfer +and the bmc machine reboots in the middle of the i2c transaction, the i2c +module keeps the status without being reset. + +Due to such an i2c module status, the i2c irq handler keeps getting triggered +since the i2c irq handler is registered in the kernel booting process +after the bmc machine is doing a warm rebooting. +The continuous triggering is stopped by the soft lockup watchdog timer. + +Disable the interrupt enable bit in the i2c module before calling +devm_request_irq to fix this issue since the i2c relative status bit +is read-only. + +Here is the soft lockup log. +[ 28.176395] watchdog: BUG: soft lockup - CPU#0 stuck for 26s! [swapper/0:1] +[ 28.183351] Modules linked in: +[ 28.186407] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 5.15.120-yocto-s-dirty-bbebc78 #1 +[ 28.201174] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) +[ 28.208128] pc : __do_softirq+0xb0/0x368 +[ 28.212055] lr : __do_softirq+0x70/0x368 +[ 28.215972] sp : ffffff8035ebca00 +[ 28.219278] x29: ffffff8035ebca00 x28: 0000000000000002 x27: ffffff80071a3780 +[ 28.226412] x26: ffffffc008bdc000 x25: ffffffc008bcc640 x24: ffffffc008be50c0 +[ 28.233546] x23: ffffffc00800200c x22: 0000000000000000 x21: 000000000000001b +[ 28.240679] x20: 0000000000000000 x19: ffffff80001c3200 x18: ffffffffffffffff +[ 28.247812] x17: ffffffc02d2e0000 x16: ffffff8035eb8b40 x15: 00001e8480000000 +[ 28.254945] x14: 02c3647e37dbfcb6 x13: 02c364f2ab14200c x12: 0000000002c364f2 +[ 28.262078] x11: 00000000fa83b2da x10: 000000000000b67e x9 : ffffffc008010250 +[ 28.269211] x8 : 000000009d983d00 x7 : 7fffffffffffffff x6 : 0000036d74732434 +[ 28.276344] x5 : 00ffffffffffffff x4 : 0000000000000015 x3 : 0000000000000198 +[ 28.283476] x2 : ffffffc02d2e0000 x1 : 00000000000000e0 x0 : ffffffc008bdcb40 +[ 28.290611] Call trace: +[ 28.293052] __do_softirq+0xb0/0x368 +[ 28.296625] __irq_exit_rcu+0xe0/0x100 +[ 28.300374] irq_exit+0x14/0x20 +[ 28.303513] handle_domain_irq+0x68/0x90 +[ 28.307440] gic_handle_irq+0x78/0xb0 +[ 28.311098] call_on_irq_stack+0x20/0x38 +[ 28.315019] do_interrupt_handler+0x54/0x5c +[ 28.319199] el1_interrupt+0x2c/0x4c +[ 28.322777] el1h_64_irq_handler+0x14/0x20 +[ 28.326872] el1h_64_irq+0x74/0x78 +[ 28.330269] __setup_irq+0x454/0x780 +[ 28.333841] request_threaded_irq+0xd0/0x1b4 +[ 28.338107] devm_request_threaded_irq+0x84/0x100 +[ 28.342809] npcm_i2c_probe_bus+0x188/0x3d0 +[ 28.346990] platform_probe+0x6c/0xc4 +[ 28.350653] really_probe+0xcc/0x45c +[ 28.354227] __driver_probe_device+0x8c/0x160 +[ 28.358578] driver_probe_device+0x44/0xe0 +[ 28.362670] __driver_attach+0x124/0x1d0 +[ 28.366589] bus_for_each_dev+0x7c/0xe0 +[ 28.370426] driver_attach+0x28/0x30 +[ 28.373997] bus_add_driver+0x124/0x240 +[ 28.377830] driver_register+0x7c/0x124 +[ 28.381662] __platform_driver_register+0x2c/0x34 +[ 28.386362] npcm_i2c_init+0x3c/0x5c +[ 28.389937] do_one_initcall+0x74/0x230 +[ 28.393768] kernel_init_freeable+0x24c/0x2b4 +[ 28.398126] kernel_init+0x28/0x130 +[ 28.401614] ret_from_fork+0x10/0x20 +[ 28.405189] Kernel panic - not syncing: softlockup: hung tasks +[ 28.411011] SMP: stopping secondary CPUs +[ 28.414933] Kernel Offset: disabled +[ 28.418412] CPU features: 0x00000000,00000802 +[ 28.427644] Rebooting in 20 seconds.. + +This change is also contributing to torvalds upstream for reviewing. +Lore Link: https://lore.kernel.org/all/20240709105412.1685181-1-tmaimon77@gmail.com/ + +Signed-off-by: Tyrone Ting +--- + drivers/i2c/busses/i2c-npcm7xx.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/i2c/busses/i2c-npcm7xx.c b/drivers/i2c/busses/i2c-npcm7xx.c +index ae4bae63ad4f..ca73760522f5 100644 +--- a/drivers/i2c/busses/i2c-npcm7xx.c ++++ b/drivers/i2c/busses/i2c-npcm7xx.c +@@ -2333,6 +2333,8 @@ static int npcm_i2c_probe_bus(struct platform_device *pdev) + if (irq < 0) + return irq; + ++ npcm_i2c_int_enable(bus, false); ++ + ret = devm_request_irq(bus->dev, irq, npcm_i2c_bus_irq, 0, + dev_name(bus->dev), bus); + if (ret) +-- +2.34.1 + diff --git a/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1022-i2c-npcm-use-i2c-frequency-table.patch b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1022-i2c-npcm-use-i2c-frequency-table.patch new file mode 100644 index 00000000000..c0bab9b627d --- /dev/null +++ b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1022-i2c-npcm-use-i2c-frequency-table.patch @@ -0,0 +1,292 @@ +From 3359889042d9325f2330ca4b377b1ac68072a5be Mon Sep 17 00:00:00 2001 +From: Tyrone Ting +Date: Tue, 8 Nov 2022 11:18:07 +0800 +Subject: [PATCH 1/6] drivers: i2c: use i2c frequency table + +Modify i2c frequency from table parameters +for NPCM i2c modules. + +Supported frequencies are: + +1. 100KHz +2. 400KHz +3. 1MHz + +Signed-off-by: Tyrone Ting +--- + drivers/i2c/busses/i2c-npcm7xx.c | 226 +++++++++++++++++++------------ + 1 file changed, 143 insertions(+), 83 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-npcm7xx.c b/drivers/i2c/busses/i2c-npcm7xx.c +index ca73760522f5..16bf9e6985a6 100644 +--- a/drivers/i2c/busses/i2c-npcm7xx.c ++++ b/drivers/i2c/busses/i2c-npcm7xx.c +@@ -261,6 +261,121 @@ static const int npcm_i2caddr[I2C_NUM_OWN_ADDR] = { + #define I2C_FREQ_MIN_HZ 10000 + #define I2C_FREQ_MAX_HZ I2C_MAX_FAST_MODE_PLUS_FREQ + ++struct SMB_TIMING_T { ++ u32 core_clk; ++ u8 hldt; ++ u8 dbcnt; ++ u16 sclfrq; ++ u8 scllt; ++ u8 sclht; ++ bool fast_mode; ++}; ++ ++static struct SMB_TIMING_T SMB_TIMING_100KHZ[] = { ++ {.core_clk = 100000000, .hldt = 0x2A, .dbcnt = 0x4, .sclfrq = 0xFB, .scllt = 0x0, ++ .sclht = 0x0, .fast_mode = false }, ++ {.core_clk = 62500000, .hldt = 0x2A, .dbcnt = 0x1, .sclfrq = 0x9D, .scllt = 0x0, ++ .sclht = 0x0, .fast_mode = false }, ++ {.core_clk = 50000000, .hldt = 0x2A, .dbcnt = 0x1, .sclfrq = 0x7E, .scllt = 0x0, ++ .sclht = 0x0, .fast_mode = false }, ++ {.core_clk = 48000000, .hldt = 0x2A, .dbcnt = 0x1, .sclfrq = 0x79, .scllt = 0x0, ++ .sclht = 0x0, .fast_mode = false }, ++ {.core_clk = 40000000, .hldt = 0x2A, .dbcnt = 0x1, .sclfrq = 0x65, .scllt = 0x0, ++ .sclht = 0x0, .fast_mode = false }, ++ {.core_clk = 30000000, .hldt = 0x2A, .dbcnt = 0x1, .sclfrq = 0x4C, .scllt = 0x0, ++ .sclht = 0x0, .fast_mode = false }, ++ {.core_clk = 29000000, .hldt = 0x2A, .dbcnt = 0x1, .sclfrq = 0x49, .scllt = 0x0, ++ .sclht = 0x0, .fast_mode = false }, ++ {.core_clk = 26000000, .hldt = 0x2A, .dbcnt = 0x1, .sclfrq = 0x42, .scllt = 0x0, ++ .sclht = 0x0, .fast_mode = false }, ++ {.core_clk = 25000000, .hldt = 0x2A, .dbcnt = 0x1, .sclfrq = 0x3F, .scllt = 0x0, ++ .sclht = 0x0, .fast_mode = false }, ++ {.core_clk = 24000000, .hldt = 0x2A, .dbcnt = 0x1, .sclfrq = 0x3D, .scllt = 0x0, ++ .sclht = 0x0, .fast_mode = false }, ++ {.core_clk = 20000000, .hldt = 0x2A, .dbcnt = 0x1, .sclfrq = 0x33, .scllt = 0x0, ++ .sclht = 0x0, .fast_mode = false }, ++ {.core_clk = 16180000, .hldt = 0x2A, .dbcnt = 0x1, .sclfrq = 0x29, .scllt = 0x0, ++ .sclht = 0x0, .fast_mode = false }, ++ {.core_clk = 15000000, .hldt = 0x23, .dbcnt = 0x1, .sclfrq = 0x26, .scllt = 0x0, ++ .sclht = 0x0, .fast_mode = false }, ++ {.core_clk = 13000000, .hldt = 0x1D, .dbcnt = 0x1, .sclfrq = 0x21, .scllt = 0x0, ++ .sclht = 0x0, .fast_mode = false }, ++ {.core_clk = 12000000, .hldt = 0x1B, .dbcnt = 0x1, .sclfrq = 0x1F, .scllt = 0x0, ++ .sclht = 0x0, .fast_mode = false }, ++ {.core_clk = 10000000, .hldt = 0x18, .dbcnt = 0x1, .sclfrq = 0x1A, .scllt = 0x0, ++ .sclht = 0x0, .fast_mode = false }, ++ {.core_clk = 9000000, .hldt = 0x16, .dbcnt = 0x1, .sclfrq = 0x17, .scllt = 0x0, ++ .sclht = 0x0, .fast_mode = false }, ++ {.core_clk = 8090000, .hldt = 0x14, .dbcnt = 0x1, .sclfrq = 0x15, .scllt = 0x0, ++ .sclht = 0x0, .fast_mode = false }, ++ {.core_clk = 7500000, .hldt = 0x7, .dbcnt = 0x1, .sclfrq = 0x13, .scllt = 0x0, ++ .sclht = 0x0, .fast_mode = false }, ++ {.core_clk = 6500000, .hldt = 0xE, .dbcnt = 0x1, .sclfrq = 0x11, .scllt = 0x0, ++ .sclht = 0x0, .fast_mode = false }, ++ {.core_clk = 4000000, .hldt = 0x9, .dbcnt = 0x1, .sclfrq = 0xB, .scllt = 0x0, ++ .sclht = 0x0, .fast_mode = false } ++}; ++ ++static struct SMB_TIMING_T SMB_TIMING_400KHZ[] = { ++ {.core_clk = 100000000, .hldt = 0x2A, .dbcnt = 0x3, .sclfrq = 0x0, .scllt = 0x47, ++ .sclht = 0x35, .fast_mode = true }, ++ {.core_clk = 62500000, .hldt = 0x2A, .dbcnt = 0x2, .sclfrq = 0x0, .scllt = 0x2C, ++ .sclht = 0x22, .fast_mode = true }, ++ {.core_clk = 50000000, .hldt = 0x21, .dbcnt = 0x1, .sclfrq = 0x0, .scllt = 0x24, ++ .sclht = 0x1B, .fast_mode = true }, ++ {.core_clk = 48000000, .hldt = 0x1E, .dbcnt = 0x1, .sclfrq = 0x0, .scllt = 0x24, ++ .sclht = 0x19, .fast_mode = true }, ++ {.core_clk = 40000000, .hldt = 0x1B, .dbcnt = 0x1, .sclfrq = 0x0, .scllt = 0x1E, ++ .sclht = 0x14, .fast_mode = true }, ++ {.core_clk = 33000000, .hldt = 0x15, .dbcnt = 0x1, .sclfrq = 0x0, .scllt = 0x19, ++ .sclht = 0x11, .fast_mode = true }, ++ {.core_clk = 30000000, .hldt = 0x15, .dbcnt = 0x1, .sclfrq = 0x0, .scllt = 0x19, ++ .sclht = 0xD, .fast_mode = true }, ++ {.core_clk = 29000000, .hldt = 0x11, .dbcnt = 0x1, .sclfrq = 0x0, .scllt = 0x15, ++ .sclht = 0x10, .fast_mode = true }, ++ {.core_clk = 26000000, .hldt = 0x10, .dbcnt = 0x1, .sclfrq = 0x0, .scllt = 0x13, ++ .sclht = 0xE, .fast_mode = true }, ++ {.core_clk = 25000000, .hldt = 0xF, .dbcnt = 0x1, .sclfrq = 0x0, .scllt = 0x13, ++ .sclht = 0xD, .fast_mode = true }, ++ {.core_clk = 24000000, .hldt = 0xD, .dbcnt = 0x1, .sclfrq = 0x0, .scllt = 0x12, ++ .sclht = 0xD, .fast_mode = true }, ++ {.core_clk = 20000000, .hldt = 0xB, .dbcnt = 0x1, .sclfrq = 0x0, .scllt = 0xF, ++ .sclht = 0xA, .fast_mode = true }, ++ {.core_clk = 16180000, .hldt = 0xA, .dbcnt = 0x1, .sclfrq = 0x0, .scllt = 0xC, ++ .sclht = 0x9, .fast_mode = true }, ++ {.core_clk = 15000000, .hldt = 0x9, .dbcnt = 0x1, .sclfrq = 0x0, .scllt = 0xB, ++ .sclht = 0x8, .fast_mode = true }, ++ {.core_clk = 13000000, .hldt = 0x7, .dbcnt = 0x1, .sclfrq = 0x0, .scllt = 0xA, ++ .sclht = 0x7, .fast_mode = true }, ++ {.core_clk = 12000000, .hldt = 0x7, .dbcnt = 0x1, .sclfrq = 0x0, .scllt = 0xA, ++ .sclht = 0x6, .fast_mode = true }, ++ {.core_clk = 10000000, .hldt = 0x6, .dbcnt = 0x1, .sclfrq = 0x0, .scllt = 0x8, ++ .sclht = 0x5, .fast_mode = true }, ++}; ++ ++static struct SMB_TIMING_T SMB_TIMING_1000KHZ[] = { ++ {.core_clk = 100000000, .hldt = 0x15, .dbcnt = 0x4, .sclfrq = 0x0, .scllt = 0x1C, ++ .sclht = 0x15, .fast_mode = true }, ++ {.core_clk = 62500000, .hldt = 0xF, .dbcnt = 0x3, .sclfrq = 0x0, .scllt = 0x11, ++ .sclht = 0xE, .fast_mode = true }, ++ {.core_clk = 50000000, .hldt = 0xA, .dbcnt = 0x2, .sclfrq = 0x0, .scllt = 0xE, ++ .sclht = 0xB, .fast_mode = true }, ++ {.core_clk = 48000000, .hldt = 0x9, .dbcnt = 0x2, .sclfrq = 0x0, .scllt = 0xD, ++ .sclht = 0xB, .fast_mode = true }, ++ {.core_clk = 41000000, .hldt = 0x9, .dbcnt = 0x2, .sclfrq = 0x0, .scllt = 0xC, ++ .sclht = 0x9, .fast_mode = true }, ++ {.core_clk = 40000000, .hldt = 0x8, .dbcnt = 0x2, .sclfrq = 0x0, .scllt = 0xB, ++ .sclht = 0x9, .fast_mode = true }, ++ {.core_clk = 33000000, .hldt = 0x7, .dbcnt = 0x1, .sclfrq = 0x0, .scllt = 0xA, ++ .sclht = 0x7, .fast_mode = true }, ++ {.core_clk = 25000000, .hldt = 0x4, .dbcnt = 0x1, .sclfrq = 0x0, .scllt = 0x7, ++ .sclht = 0x6, .fast_mode = true }, ++ {.core_clk = 24000000, .hldt = 0x7, .dbcnt = 0x1, .sclfrq = 0x0, .scllt = 0x8, ++ .sclht = 0x5, .fast_mode = true }, ++ {.core_clk = 20000000, .hldt = 0x4, .dbcnt = 0x1, .sclfrq = 0x0, .scllt = 0x6, ++ .sclht = 0x4, .fast_mode = true }, ++}; ++ + struct npcm_i2c_data { + u8 fifo_size; + u32 segctl_init_val; +@@ -1806,11 +1921,9 @@ static void npcm_i2c_recovery_init(struct i2c_adapter *_adap) + */ + static int npcm_i2c_init_clk(struct npcm_i2c *bus, u32 bus_freq_hz) + { +- u32 k1 = 0; +- u32 k2 = 0; +- u8 dbnct = 0; +- u32 sclfrq = 0; +- u8 hldt = 7; ++ struct SMB_TIMING_T *smb_timing; ++ u8 scl_table_cnt = 0, table_size = 0; ++ + u8 fast_mode = 0; + u32 src_clk_khz; + u32 bus_freq_khz; +@@ -1819,89 +1932,36 @@ static int npcm_i2c_init_clk(struct npcm_i2c *bus, u32 bus_freq_hz) + bus_freq_khz = bus_freq_hz / 1000; + bus->bus_freq = bus_freq_hz; + +- /* 100KHz and below: */ +- if (bus_freq_hz <= I2C_MAX_STANDARD_MODE_FREQ) { +- sclfrq = src_clk_khz / (bus_freq_khz * 4); +- +- if (sclfrq < SCLFRQ_MIN || sclfrq > SCLFRQ_MAX) +- return -EDOM; +- +- if (src_clk_khz >= 40000) +- hldt = 17; +- else if (src_clk_khz >= 12500) +- hldt = 15; +- else +- hldt = 7; +- } +- +- /* 400KHz: */ +- else if (bus_freq_hz <= I2C_MAX_FAST_MODE_FREQ) { +- sclfrq = 0; ++ switch (bus_freq_hz) { ++ case I2C_MAX_STANDARD_MODE_FREQ: ++ smb_timing = SMB_TIMING_100KHZ; ++ table_size = ARRAY_SIZE(SMB_TIMING_100KHZ); ++ break; ++ case I2C_MAX_FAST_MODE_FREQ: ++ smb_timing = SMB_TIMING_400KHZ; ++ table_size = ARRAY_SIZE(SMB_TIMING_400KHZ); + fast_mode = I2CCTL3_400K_MODE; +- +- if (src_clk_khz < 7500) +- /* 400KHZ cannot be supported for core clock < 7.5MHz */ +- return -EDOM; +- +- else if (src_clk_khz >= 50000) { +- k1 = 80; +- k2 = 48; +- hldt = 12; +- dbnct = 7; +- } +- +- /* Master or Slave with frequency > 25MHz */ +- else if (src_clk_khz > 25000) { +- hldt = clk_coef(src_clk_khz, 300) + 7; +- k1 = clk_coef(src_clk_khz, 1600); +- k2 = clk_coef(src_clk_khz, 900); +- } +- } +- +- /* 1MHz: */ +- else if (bus_freq_hz <= I2C_MAX_FAST_MODE_PLUS_FREQ) { +- sclfrq = 0; ++ break; ++ case I2C_MAX_FAST_MODE_PLUS_FREQ: ++ smb_timing = SMB_TIMING_1000KHZ; ++ table_size = ARRAY_SIZE(SMB_TIMING_1000KHZ); + fast_mode = I2CCTL3_400K_MODE; +- +- /* 1MHZ cannot be supported for core clock < 24 MHz */ +- if (src_clk_khz < 24000) +- return -EDOM; +- +- k1 = clk_coef(src_clk_khz, 620); +- k2 = clk_coef(src_clk_khz, 380); +- +- /* Core clk > 40 MHz */ +- if (src_clk_khz > 40000) { +- /* +- * Set HLDT: +- * SDA hold time: (HLDT-7) * T(CLK) >= 120 +- * HLDT = 120/T(CLK) + 7 = 120 * FREQ(CLK) + 7 +- */ +- hldt = clk_coef(src_clk_khz, 120) + 7; +- } else { +- hldt = 7; +- dbnct = 2; +- } +- } +- +- /* Frequency larger than 1 MHz is not supported */ +- else ++ break; ++ default: + return -EINVAL; +- +- if (bus_freq_hz >= I2C_MAX_FAST_MODE_FREQ) { +- k1 = round_up(k1, 2); +- k2 = round_up(k2 + 1, 2); +- if (k1 < SCLFRQ_MIN || k1 > SCLFRQ_MAX || +- k2 < SCLFRQ_MIN || k2 > SCLFRQ_MAX) +- return -EDOM; + } + ++ for (scl_table_cnt = 0 ; scl_table_cnt < table_size ; scl_table_cnt++) ++ if (bus->apb_clk >= smb_timing[scl_table_cnt].core_clk) ++ break; ++ + /* write sclfrq value. bits [6:0] are in I2CCTL2 reg */ +- iowrite8(FIELD_PREP(I2CCTL2_SCLFRQ6_0, sclfrq & 0x7F), ++ iowrite8(FIELD_PREP(I2CCTL2_SCLFRQ6_0, smb_timing[scl_table_cnt].sclfrq & 0x7F), + bus->reg + NPCM_I2CCTL2); + + /* bits [8:7] are in I2CCTL3 reg */ +- iowrite8(fast_mode | FIELD_PREP(I2CCTL3_SCLFRQ8_7, (sclfrq >> 7) & 0x3), ++ iowrite8(fast_mode | FIELD_PREP(I2CCTL3_SCLFRQ8_7, (smb_timing[scl_table_cnt].sclfrq >> 7) ++ & 0x3), + bus->reg + NPCM_I2CCTL3); + + /* Select Bank 0 to access NPCM_I2CCTL4/NPCM_I2CCTL5 */ +@@ -1913,13 +1973,13 @@ static int npcm_i2c_init_clk(struct npcm_i2c *bus, u32 bus_freq_hz) + * k1 = 2 * SCLLT7-0 -> Low Time = k1 / 2 + * k2 = 2 * SCLLT7-0 -> High Time = k2 / 2 + */ +- iowrite8(k1 / 2, bus->reg + NPCM_I2CSCLLT); +- iowrite8(k2 / 2, bus->reg + NPCM_I2CSCLHT); ++ iowrite8(smb_timing[scl_table_cnt].scllt, bus->reg + NPCM_I2CSCLLT); ++ iowrite8(smb_timing[scl_table_cnt].sclht, bus->reg + NPCM_I2CSCLHT); + +- iowrite8(dbnct, bus->reg + NPCM_I2CCTL5); ++ iowrite8(smb_timing[scl_table_cnt].dbcnt, bus->reg + NPCM_I2CCTL5); + } + +- iowrite8(hldt, bus->reg + NPCM_I2CCTL4); ++ iowrite8(smb_timing[scl_table_cnt].hldt, bus->reg + NPCM_I2CCTL4); + + /* Return to Bank 1, and stay there by default: */ + npcm_i2c_select_bank(bus, I2C_BANK_1); +-- +2.34.1 + diff --git a/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1023-i2c-npcm-use-a-software-flag-to-indicate-a-BER-condi.patch b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1023-i2c-npcm-use-a-software-flag-to-indicate-a-BER-condi.patch new file mode 100644 index 00000000000..e1da94be081 --- /dev/null +++ b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1023-i2c-npcm-use-a-software-flag-to-indicate-a-BER-condi.patch @@ -0,0 +1,68 @@ +From 3f5e6c104110b85c3d01177890ca4894ea5f1bf5 Mon Sep 17 00:00:00 2001 +From: Tyrone Ting +Date: Tue, 28 Jun 2022 15:41:46 +0800 +Subject: [PATCH 2/6] i2c: npcm: use a software flag to indicate a BER + condition + +If not clearing the BB (bus busy) condition in the BER (bus error) +interrupt, the driver causes a timeout and hence the i2c core +doesn't do the i2c transfer retry but returns the driver's return +value to the upper layer instead. + +Clear the BB condition in the BER interrupt and a software flag is +used. The driver does an i2c recovery without causing the timeout +if the flag is set. + +Signed-off-by: Tyrone Ting +--- + drivers/i2c/busses/i2c-npcm7xx.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/i2c/busses/i2c-npcm7xx.c b/drivers/i2c/busses/i2c-npcm7xx.c +index 16bf9e6985a6..4c3743007cbc 100644 +--- a/drivers/i2c/busses/i2c-npcm7xx.c ++++ b/drivers/i2c/busses/i2c-npcm7xx.c +@@ -448,6 +448,7 @@ struct npcm_i2c { + u64 nack_cnt; + u64 timeout_cnt; + u64 tx_complete_cnt; ++ bool ber_state; + }; + + static inline void npcm_i2c_select_bank(struct npcm_i2c *bus, +@@ -1638,6 +1639,7 @@ static void npcm_i2c_irq_handle_ber(struct npcm_i2c *bus) + if (npcm_i2c_is_master(bus)) { + npcm_i2c_master_abort(bus); + } else { ++ bus->ber_state = true; + npcm_i2c_clear_master_status(bus); + + /* Clear BB (BUS BUSY) bit */ +@@ -1819,6 +1821,7 @@ static int npcm_i2c_recovery_tgclk(struct i2c_adapter *_adap) + dev_dbg(bus->dev, "bus%d-0x%x recovery skipped, bus not stuck", + bus->num, bus->dest_addr); + npcm_i2c_reset(bus); ++ bus->ber_state = false; + return 0; + } + +@@ -1883,6 +1886,7 @@ static int npcm_i2c_recovery_tgclk(struct i2c_adapter *_adap) + if (bus->rec_succ_cnt < ULLONG_MAX) + bus->rec_succ_cnt++; + } ++ bus->ber_state = false; + return status; + } + +@@ -2223,7 +2227,7 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + + } while (time_is_after_jiffies(time_left) && bus_busy); + +- if (bus_busy) { ++ if (bus_busy || bus->ber_state) { + iowrite8(NPCM_I2CCST_BB, bus->reg + NPCM_I2CCST); + npcm_i2c_reset(bus); + i2c_recover_bus(adap); +-- +2.34.1 + diff --git a/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1024-i2c-npcm-Modify-timeout-evaluation-mechanism.patch b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1024-i2c-npcm-Modify-timeout-evaluation-mechanism.patch new file mode 100644 index 00000000000..574f5433016 --- /dev/null +++ b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1024-i2c-npcm-Modify-timeout-evaluation-mechanism.patch @@ -0,0 +1,69 @@ +From 7cb28f9fec461ab14b210a0daea89e59283f7bb7 Mon Sep 17 00:00:00 2001 +From: Tyrone Ting +Date: Wed, 17 Aug 2022 15:52:32 +0800 +Subject: [PATCH 3/6] i2c: npcm: Modify timeout evaluation mechanism + +Increase the timeout and treat it as the total timeout, including retries. +The total timeout is 2 seconds now. + +The i2c core layer will have chances to retry to call the i2c driver +transfer function if the i2c driver reports that the bus is busy and +returns EAGAIN. + +Signed-off-by: Tyrone Ting +--- + drivers/i2c/busses/i2c-npcm7xx.c | 19 ++++++++++--------- + 1 file changed, 10 insertions(+), 9 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-npcm7xx.c b/drivers/i2c/busses/i2c-npcm7xx.c +index 4c3743007cbc..0c239c75bdd9 100644 +--- a/drivers/i2c/busses/i2c-npcm7xx.c ++++ b/drivers/i2c/busses/i2c-npcm7xx.c +@@ -2197,19 +2197,12 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + } + } + +- /* +- * Adaptive TimeOut: estimated time in usec + 100% margin: +- * 2: double the timeout for clock stretching case +- * 9: bits per transaction (including the ack/nack) +- */ +- timeout_usec = (2 * 9 * USEC_PER_SEC / bus->bus_freq) * (2 + nread + nwrite); +- timeout = max_t(unsigned long, bus->adap.timeout, usecs_to_jiffies(timeout_usec)); + if (nwrite >= 32 * 1024 || nread >= 32 * 1024) { + dev_err(bus->dev, "i2c%d buffer too big\n", bus->num); + return -EINVAL; + } + +- time_left = jiffies + timeout + 1; ++ time_left = jiffies + bus->adap.timeout / bus->adap.retries + 1; + do { + /* + * we must clear slave address immediately when the bus is not +@@ -2248,6 +2241,14 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + if (npcm_i2c_master_start_xmit(bus, slave_addr, nwrite, nread, + write_data, read_data, read_PEC, + read_block)) { ++ /* ++ * Adaptive TimeOut: estimated time in usec + 100% margin: ++ * 2: double the timeout for clock stretching case ++ * 9: bits per transaction (including the ack/nack) ++ */ ++ timeout_usec = (2 * 9 * USEC_PER_SEC / bus->bus_freq) * (2 + nread + nwrite); ++ timeout = max_t(unsigned long, bus->adap.timeout / bus->adap.retries, ++ usecs_to_jiffies(timeout_usec)); + time_left = wait_for_completion_timeout(&bus->cmd_complete, + timeout); + +@@ -2385,7 +2386,7 @@ static int npcm_i2c_probe_bus(struct platform_device *pdev) + adap = &bus->adap; + adap->owner = THIS_MODULE; + adap->retries = 3; +- adap->timeout = msecs_to_jiffies(35); ++ adap->timeout = 2 * HZ; + adap->algo = &npcm_i2c_algo; + adap->quirks = &npcm_i2c_quirks; + adap->algo_data = bus; +-- +2.34.1 + diff --git a/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1025-i2c-npcm-Modify-the-client-address-assignment.patch b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1025-i2c-npcm-Modify-the-client-address-assignment.patch new file mode 100644 index 00000000000..a6b20383ee5 --- /dev/null +++ b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1025-i2c-npcm-Modify-the-client-address-assignment.patch @@ -0,0 +1,36 @@ +From 35bbd92f2cf5fa7044b9ee4d06beee24e0ebaa4b Mon Sep 17 00:00:00 2001 +From: Tyrone Ting +Date: Wed, 17 Aug 2022 16:13:36 +0800 +Subject: [PATCH 4/6] i2c: npcm: Modify the client address assignment + +Store the client address earlier since it's used in the i2c_recover_bus +logic flow. + +Signed-off-by: Tyrone Ting +--- + drivers/i2c/busses/i2c-npcm7xx.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/i2c/busses/i2c-npcm7xx.c b/drivers/i2c/busses/i2c-npcm7xx.c +index 0c239c75bdd9..3f7a3a00e28e 100644 +--- a/drivers/i2c/busses/i2c-npcm7xx.c ++++ b/drivers/i2c/busses/i2c-npcm7xx.c +@@ -2220,6 +2220,7 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + + } while (time_is_after_jiffies(time_left) && bus_busy); + ++ bus->dest_addr = slave_addr << 1; + if (bus_busy || bus->ber_state) { + iowrite8(NPCM_I2CCST_BB, bus->reg + NPCM_I2CCST); + npcm_i2c_reset(bus); +@@ -2228,7 +2229,6 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + } + + npcm_i2c_init_params(bus); +- bus->dest_addr = slave_addr; + bus->msgs = msgs; + bus->msgs_num = num; + bus->cmd_err = 0; +-- +2.34.1 + diff --git a/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1026-i2c-npcm7xx.c-Enable-slave-in-eob-interrupt.patch b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1026-i2c-npcm7xx.c-Enable-slave-in-eob-interrupt.patch new file mode 100644 index 00000000000..e3f9ab9d01d --- /dev/null +++ b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1026-i2c-npcm7xx.c-Enable-slave-in-eob-interrupt.patch @@ -0,0 +1,40 @@ +From ca2893f9c93aa26077f9c36b0f0dfa6dccaec17a Mon Sep 17 00:00:00 2001 +From: Charles Boyer +Date: Mon, 21 Nov 2022 09:37:20 -0600 +Subject: [PATCH 5/6] i2c-npcm7xx.c: Enable slave in eob interrupt + +Nuvoton slave enable was in user space API call master_xfer, so it is +subject to delays from the OS scheduler. If the BMC is not enabled for +slave mode in time for master to send response, then it will NAK the +address match. Then the PLDM request timeout occurs. + +If the slave enable is moved to the EOB interrupt service routine, then +the BMC can be ready in slave mode by the time it needs to receive a +response. + +Signed-off-by: Charles Boyer +Signed-off-by: Vivekanand Veeracholan +--- + drivers/i2c/busses/i2c-npcm7xx.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/i2c/busses/i2c-npcm7xx.c b/drivers/i2c/busses/i2c-npcm7xx.c +index 3f7a3a00e28e..c39d1717c132 100644 +--- a/drivers/i2c/busses/i2c-npcm7xx.c ++++ b/drivers/i2c/busses/i2c-npcm7xx.c +@@ -1786,6 +1786,12 @@ static int npcm_i2c_int_master_handler(struct npcm_i2c *bus) + (FIELD_GET(NPCM_I2CCST3_EO_BUSY, + ioread8(bus->reg + NPCM_I2CCST3)))) { + npcm_i2c_irq_handle_eob(bus); ++#if IS_ENABLED(CONFIG_I2C_SLAVE) ++ /* reenable slave if it was enabled */ ++ if (bus->slave) ++ iowrite8((bus->slave->addr & 0x7F) | NPCM_I2CADDR_SAEN, ++ bus->reg + NPCM_I2CADDR1); ++#endif + return 0; + } + +-- +2.34.1 + diff --git a/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1027-i2c-npcm-correct-the-read-write-operation-procedure.patch b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1027-i2c-npcm-correct-the-read-write-operation-procedure.patch new file mode 100644 index 00000000000..42d6487df15 --- /dev/null +++ b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1027-i2c-npcm-correct-the-read-write-operation-procedure.patch @@ -0,0 +1,41 @@ +From 116f523d04855d1fb2c86a6c616e978757d812ed Mon Sep 17 00:00:00 2001 +From: Tyrone Ting +Date: Mon, 9 May 2022 18:06:33 +0800 +Subject: [PATCH 6/6] i2c: npcm: correct the read/write operation procedure + +Originally the driver uses the XMIT bit in SMBnST register to decide +the upcoming i2c transaction. If XMIT bit is 1, then it will be an i2c +write operation. If it's 0, then a read operation will be executed. + +After checking the datasheet, the XMIT bit is valid when the i2c module +is acting in a slave role. Use the software status to control the i2c +transaction flow instead when the i2c module is acting in a master role. + +Signed-off-by: Tyrone Ting +--- + drivers/i2c/busses/i2c-npcm7xx.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/drivers/i2c/busses/i2c-npcm7xx.c b/drivers/i2c/busses/i2c-npcm7xx.c +index c39d1717c132..6e649dc6c99e 100644 +--- a/drivers/i2c/busses/i2c-npcm7xx.c ++++ b/drivers/i2c/busses/i2c-npcm7xx.c +@@ -1747,13 +1747,10 @@ static void npcm_i2c_irq_handle_sda(struct npcm_i2c *bus, u8 i2cst) + npcm_i2c_wr_byte(bus, bus->dest_addr | BIT(0)); + /* SDA interrupt, after start\restart */ + } else { +- if (NPCM_I2CST_XMIT & i2cst) { +- bus->operation = I2C_WRITE_OPER; ++ if (bus->operation == I2C_WRITE_OPER) + npcm_i2c_irq_master_handler_write(bus); +- } else { +- bus->operation = I2C_READ_OPER; ++ else if (bus->operation == I2C_READ_OPER) + npcm_i2c_irq_master_handler_read(bus); +- } + } + } + +-- +2.34.1 + diff --git a/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1028-i2c-npcm-Return-EAGAIN-while-bus-is-busy.patch b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1028-i2c-npcm-Return-EAGAIN-while-bus-is-busy.patch new file mode 100644 index 00000000000..c2e91596941 --- /dev/null +++ b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1028-i2c-npcm-Return-EAGAIN-while-bus-is-busy.patch @@ -0,0 +1,38 @@ +From 241620bf50a713a7d32d99e9da45a98d56d92b40 Mon Sep 17 00:00:00 2001 +From: Marvin Lin +Date: Wed, 4 Sep 2024 16:25:55 +0800 +Subject: [PATCH] i2c: npcm: Return EAGAIN while bus is busy + +Return EAGAIN while bus is busy. + +Signed-off-by: Marvin Lin +--- + drivers/i2c/busses/i2c-npcm7xx.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/i2c/busses/i2c-npcm7xx.c b/drivers/i2c/busses/i2c-npcm7xx.c +index 6e649dc6c99e..fe8c104712d3 100644 +--- a/drivers/i2c/busses/i2c-npcm7xx.c ++++ b/drivers/i2c/busses/i2c-npcm7xx.c +@@ -2268,7 +2268,7 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + + /* if there was BER, check if need to recover the bus: */ + if (bus->cmd_err == -EAGAIN) +- bus->cmd_err = i2c_recover_bus(adap); ++ i2c_recover_bus(adap); + + /* + * After any type of error, check if LAST bit is still set, +@@ -2291,6 +2291,9 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + #else + npcm_i2c_int_enable(bus, false); + #endif ++ if (bus->cmd_err == -EBUSY) ++ bus->cmd_err = -EAGAIN; ++ + return bus->cmd_err; + } + +-- +2.34.1 + diff --git a/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1030-misc-npcm8xx-jtag-master-Add-NPCM845-JTAG-master-dri.patch b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1030-misc-npcm8xx-jtag-master-Add-NPCM845-JTAG-master-dri.patch new file mode 100644 index 00000000000..2951d1f2307 --- /dev/null +++ b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1030-misc-npcm8xx-jtag-master-Add-NPCM845-JTAG-master-dri.patch @@ -0,0 +1,984 @@ +From 2ebd4ab47b312bc5a89f79d766ee7c108f7dd6bc Mon Sep 17 00:00:00 2001 +From: Tomer Maimon +Date: Mon, 13 Feb 2023 09:06:48 +0200 +Subject: [PATCH] misc: npcm8xx-jtag-master: Add NPCM845 JTAG master driver + support + +this patch adds NPCM845 JTAG master controller driver support to NPCM845 +BMC SoC. + +We will contribute this patch to lf-openbmc upstream soon. + +Signed-off-by: Tomer Maimon +--- + drivers/misc/Kconfig | 6 + + drivers/misc/Makefile | 1 + + drivers/misc/npcm8xx-jtag-master.c | 930 +++++++++++++++++++++++++++++ + 3 files changed, 937 insertions(+) + create mode 100644 drivers/misc/npcm8xx-jtag-master.c + +diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig +index 499d5baac..99bd36063 100644 +--- a/drivers/misc/Kconfig ++++ b/drivers/misc/Kconfig +@@ -562,6 +562,12 @@ config TPS6594_PFSM + This driver can also be built as a module. If so, the module + will be called tps6594-pfsm. + ++config NPCM8XX_JTAG_MASTER ++ tristate "NPCM8xx JTAG Master driver" ++ depends on (ARCH_NPCM || COMPILE_TEST) ++ help ++ NPCM8xx JTAG Master Interfaces. ++ + source "drivers/misc/amd-apml/Kconfig" + source "drivers/misc/c2port/Kconfig" + source "drivers/misc/eeprom/Kconfig" +diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile +index 5afe96197..600adb6ac 100644 +--- a/drivers/misc/Makefile ++++ b/drivers/misc/Makefile +@@ -68,3 +68,4 @@ obj-$(CONFIG_TMR_MANAGER) += xilinx_tmr_manager.o + obj-$(CONFIG_TMR_INJECT) += xilinx_tmr_inject.o + obj-$(CONFIG_TPS6594_ESM) += tps6594-esm.o + obj-$(CONFIG_TPS6594_PFSM) += tps6594-pfsm.o ++obj-$(CONFIG_NPCM8XX_JTAG_MASTER) += npcm8xx-jtag-master.o +diff --git a/drivers/misc/npcm8xx-jtag-master.c b/drivers/misc/npcm8xx-jtag-master.c +new file mode 100644 +index 000000000..e1b2e867e +--- /dev/null ++++ b/drivers/misc/npcm8xx-jtag-master.c +@@ -0,0 +1,930 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (c) 2021 Nuvoton Technology corporation. ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* JTM registers */ ++#define JTM_CTL 0x00 ++#define JTM_STAT 0x04 ++#define JTM_CMD 0x08 ++#define JTM_TDO_OUT(n) (0x10 + n * 4) ++#define JTM_TDO_EN(n) (0x20 + n * 4) ++#define JTM_TMS_OUT(n) (0x30 + n * 4) ++#define JTM_TDI_IN(n) (0x40 + n * 4) ++ ++#define JTM_CTL_JTM_EN BIT(0) ++#define JTM_CTL_DONE_IE BIT(4) ++#define JTM_CTL_TRST BIT(8) ++#define JTM_CTL_CKDV GENMASK(23, 16) ++#define JTM_STAT_BUSY BIT(0) ++#define JTM_STAT_DONE BIT(1) ++#define JTM_CMD_ST_OP BIT(0) ++#define JTM_CMD_CK_CNT GENMASK(15, 8) ++ ++#define NPCM_JTM_MAX_RATE (50000000) ++#define NPCM_JTM_DEFAULT_RATE (1000000) ++#define NPCM_JTM_FIFO_SIZE 128 ++#define NPCM_JTM_TIMEOUT_MS 10000 ++#define JTAG_MAX_XFER_DATA_LEN 0xFFFFFFFF ++#define JTAG_TLR_TMS_COUNT 9 ++ ++struct tck_bitbang { ++ __u8 tms; ++ __u8 tdi; ++ __u8 tdo; ++} __attribute__((__packed__)); ++ ++struct bitbang_packet { ++ struct tck_bitbang *data; ++ __u32 length; ++} __attribute__((__packed__)); ++ ++struct jtag_xfer { ++ __u8 type; ++ __u8 direction; ++ __u8 from; ++ __u8 endstate; ++ __u32 padding; ++ __u32 length; ++ __u64 tdio; ++}; ++ ++struct jtag_tap_state { ++ __u8 reset; ++ __u8 from; ++ __u8 endstate; ++ __u8 tck; ++}; ++enum jtagstates { ++ jtagtlr, ++ jtagrti, ++ jtagseldr, ++ jtagcapdr, ++ jtagshfdr, ++ jtagex1dr, ++ jtagpaudr, ++ jtagex2dr, ++ jtagupddr, ++ jtagselir, ++ jtagcapir, ++ jtagshfir, ++ jtagex1ir, ++ jtagpauir, ++ jtagex2ir, ++ jtagupdir, ++ JTAG_STATE_CURRENT ++}; ++ ++enum jtag_reset { ++ JTAG_NO_RESET = 0, ++ JTAG_FORCE_RESET = 1, ++}; ++ ++enum jtag_xfer_type { ++ JTAG_SIR_XFER = 0, ++ JTAG_SDR_XFER = 1, ++}; ++ ++enum jtag_xfer_direction { ++ JTAG_READ_XFER = 1, ++ JTAG_WRITE_XFER = 2, ++ JTAG_READ_WRITE_XFER = 3, ++}; ++ ++#define __JTAG_IOCTL_MAGIC 0xb2 ++#define JTAG_SIOCSTATE _IOW(__JTAG_IOCTL_MAGIC, 0, struct jtag_tap_state) ++#define JTAG_SIOCFREQ _IOW(__JTAG_IOCTL_MAGIC, 1, unsigned int) ++#define JTAG_GIOCFREQ _IOR(__JTAG_IOCTL_MAGIC, 2, unsigned int) ++#define JTAG_IOCXFER _IOWR(__JTAG_IOCTL_MAGIC, 3, struct jtag_xfer) ++#define JTAG_GIOCSTATUS _IOWR(__JTAG_IOCTL_MAGIC, 4, enum jtagstates) ++#define JTAG_SIOCMODE _IOW(__JTAG_IOCTL_MAGIC, 5, unsigned int) ++#define JTAG_IOCBITBANG _IOW(__JTAG_IOCTL_MAGIC, 6, unsigned int) ++ ++static DEFINE_IDA(jtag_ida); ++static DEFINE_SPINLOCK(jtag_file_lock); ++ ++struct npcm_jtm { ++ struct device *dev; ++ struct miscdevice miscdev; ++ struct reset_control *reset; ++ struct completion xfer_done; ++ struct clk *clk; ++ void __iomem *base; ++ spinlock_t lock; ++ char *tx_buf; ++ char *rx_buf; ++ char *tms_buf; ++ u32 tx_len; ++ u32 rx_len; ++ u32 ck_cnt; ++ u8 tapstate; ++ u32 freq; ++ int id; ++ bool is_open; ++ bool end_tms_high; ++}; ++ ++struct tmscycle { ++ unsigned char tmsbits; ++ unsigned char count; ++}; ++ ++/* this is the complete set TMS cycles for going from any TAP state to ++ * any other TAP state, following a “shortest path” rule ++ */ ++const struct tmscycle tmscyclelookup[][16] = { ++/* TLR RTI SelDR CapDR SDR */ ++/* Ex1DR PDR Ex2DR UpdDR SelIR */ ++/* CapIR SIR Ex1IR PIR Ex2IR */ ++/* UpdIR */ ++/* TLR */ ++ { ++ {0x01, 1}, {0x00, 1}, {0x02, 2}, {0x02, 3}, {0x02, 4}, ++ {0x0a, 4}, {0x0a, 5}, {0x2a, 6}, {0x1a, 5}, {0x06, 3}, ++ {0x06, 4}, {0x06, 5}, {0x16, 5}, {0x16, 6}, {0x56, 7}, ++ {0x36, 6} ++ }, ++/* RTI */ ++ { ++ {0x07, 3}, {0x00, 1}, {0x01, 1}, {0x01, 2}, {0x01, 3}, ++ {0x05, 3}, {0x05, 4}, {0x15, 5}, {0x0d, 4}, {0x03, 2}, ++ {0x03, 3}, {0x03, 4}, {0x0b, 4}, {0x0b, 5}, {0x2b, 6}, ++ {0x1b, 5} ++ }, ++/* SelDR */ ++ { ++ {0x03, 2}, {0x03, 3}, {0x00, 0}, {0x00, 1}, {0x00, 2}, ++ {0x02, 2}, {0x02, 3}, {0x0a, 4}, {0x06, 3}, {0x01, 1}, ++ {0x01, 2}, {0x01, 3}, {0x05, 3}, {0x05, 4}, {0x15, 5}, ++ {0x0d, 4} ++ }, ++/* CapDR */ ++ { ++ {0x1f, 5}, {0x03, 3}, {0x07, 3}, {0x00, 0}, {0x00, 1}, ++ {0x01, 1}, {0x01, 2}, {0x05, 3}, {0x03, 2}, {0x0f, 4}, ++ {0x0f, 5}, {0x0f, 6}, {0x2f, 6}, {0x2f, 7}, {0xaf, 8}, ++ {0x6f, 7} ++ }, ++/* SDR */ ++ { ++ {0x1f, 5}, {0x03, 3}, {0x07, 3}, {0x07, 4}, {0x00, 0}, ++ {0x01, 1}, {0x01, 2}, {0x05, 3}, {0x03, 2}, {0x0f, 4}, ++ {0x0f, 5}, {0x0f, 6}, {0x2f, 6}, {0x2f, 7}, {0xaf, 8}, ++ {0x6f, 7} ++ }, ++/* Ex1DR */ ++ { ++ {0x0f, 4}, {0x01, 2}, {0x03, 2}, {0x03, 3}, {0x02, 3}, ++ {0x00, 0}, {0x00, 1}, {0x02, 2}, {0x01, 1}, {0x07, 3}, ++ {0x07, 4}, {0x07, 5}, {0x17, 5}, {0x17, 6}, {0x57, 7}, ++ {0x37, 6} ++ }, ++/* PDR */ ++ { ++ {0x1f, 5}, {0x03, 3}, {0x07, 3}, {0x07, 4}, {0x01, 2}, ++ {0x05, 3}, {0x00, 1}, {0x01, 1}, {0x03, 2}, {0x0f, 4}, ++ {0x0f, 5}, {0x0f, 6}, {0x2f, 6}, {0x2f, 7}, {0xaf, 8}, ++ {0x6f, 7} ++ }, ++/* Ex2DR */ ++ { ++ {0x0f, 4}, {0x01, 2}, {0x03, 2}, {0x03, 3}, {0x00, 1}, ++ {0x02, 2}, {0x02, 3}, {0x00, 0}, {0x01, 1}, {0x07, 3}, ++ {0x07, 4}, {0x07, 5}, {0x17, 5}, {0x17, 6}, {0x57, 7}, ++ {0x37, 6} ++ }, ++/* UpdDR */ ++ { ++ {0x07, 3}, {0x00, 1}, {0x01, 1}, {0x01, 2}, {0x01, 3}, ++ {0x05, 3}, {0x05, 4}, {0x15, 5}, {0x00, 0}, {0x03, 2}, ++ {0x03, 3}, {0x03, 4}, {0x0b, 4}, {0x0b, 5}, {0x2b, 6}, ++ {0x1b, 5} ++ }, ++/* SelIR */ ++ { ++ {0x01, 1}, {0x01, 2}, {0x05, 3}, {0x05, 4}, {0x05, 5}, ++ {0x15, 5}, {0x15, 6}, {0x55, 7}, {0x35, 6}, {0x00, 0}, ++ {0x00, 1}, {0x00, 2}, {0x02, 2}, {0x02, 3}, {0x0a, 4}, ++ {0x06, 3} ++ }, ++/* CapIR */ ++ { ++ {0x1f, 5}, {0x03, 3}, {0x07, 3}, {0x07, 4}, {0x07, 5}, ++ {0x17, 5}, {0x17, 6}, {0x57, 7}, {0x37, 6}, {0x0f, 4}, ++ {0x00, 0}, {0x00, 1}, {0x01, 1}, {0x01, 2}, {0x05, 3}, ++ {0x03, 2} ++ }, ++/* SIR */ ++ { ++ {0x1f, 5}, {0x03, 3}, {0x07, 3}, {0x07, 4}, {0x07, 5}, ++ {0x17, 5}, {0x17, 6}, {0x57, 7}, {0x37, 6}, {0x0f, 4}, ++ {0x0f, 5}, {0x00, 0}, {0x01, 1}, {0x01, 2}, {0x05, 3}, ++ {0x03, 2} ++ }, ++/* Ex1IR */ ++ { ++ {0x0f, 4}, {0x01, 2}, {0x03, 2}, {0x03, 3}, {0x03, 4}, ++ {0x0b, 4}, {0x0b, 5}, {0x2b, 6}, {0x1b, 5}, {0x07, 3}, ++ {0x07, 4}, {0x02, 3}, {0x00, 0}, {0x00, 1}, {0x02, 2}, ++ {0x01, 1} ++ }, ++/* PIR */ ++ { ++ {0x1f, 5}, {0x03, 3}, {0x07, 3}, {0x07, 4}, {0x07, 5}, ++ {0x17, 5}, {0x17, 6}, {0x57, 7}, {0x37, 6}, {0x0f, 4}, ++ {0x0f, 5}, {0x01, 2}, {0x05, 3}, {0x00, 1}, {0x01, 1}, ++ {0x03, 2} ++ }, ++/* Ex2IR */ ++ { ++ {0x0f, 4}, {0x01, 2}, {0x03, 2}, {0x03, 3}, {0x03, 4}, ++ {0x0b, 4}, {0x0b, 5}, {0x2b, 6}, {0x1b, 5}, {0x07, 3}, ++ {0x07, 4}, {0x00, 1}, {0x02, 2}, {0x02, 3}, {0x00, 0}, ++ {0x01, 1} ++ }, ++/* UpdIR */ ++ { ++ {0x07, 3}, {0x00, 1}, {0x01, 1}, {0x01, 2}, {0x01, 3}, ++ {0x05, 3}, {0x05, 4}, {0x15, 5}, {0x0d, 4}, {0x03, 2}, ++ {0x03, 3}, {0x03, 4}, {0x0b, 4}, {0x0b, 5}, {0x2b, 6}, ++ {0x00, 0} ++ }, ++}; ++ ++/* should be called from atomic context */ ++static int npcm_jtm_send(struct npcm_jtm *priv) ++{ ++ u32 *tdo32 = (u32 *)priv->tx_buf; ++ u32 *tms32 = (u32 *)priv->tms_buf; ++ u8 *tdo8, *tms8; ++ u32 cnt; ++ u32 val, tmsval; ++ int n, i; ++ int words, bytes; ++ ++ if (priv->tx_len > NPCM_JTM_FIFO_SIZE) ++ cnt = NPCM_JTM_FIFO_SIZE; ++ else ++ cnt = priv->tx_len; ++ ++ words = cnt / 32; ++ bytes = DIV_ROUND_UP((cnt % 32), 8); ++ ++ for (n = 0; n < words; n++) { ++ if (tdo32) { ++ writel(*tdo32, priv->base + JTM_TDO_OUT(n)); ++ tdo32++; ++ } else ++ writel(0, priv->base + JTM_TDO_OUT(n)); ++ if (priv->tms_buf) { ++ tmsval = *tms32; ++ tms32++; ++ } else ++ tmsval = 0; ++ if (priv->end_tms_high && (cnt == priv->tx_len) ++ && !bytes && (n == words - 1)) ++ tmsval |= (1 << 31); ++ writel(tmsval, priv->base + JTM_TMS_OUT(n)); ++ } ++ ++ if (bytes) { ++ tdo8 = (u8 *)tdo32; ++ tms8 = (u8 *)tms32; ++ val = 0; ++ tmsval = 0; ++ for (i = 0; i < bytes; i++) { ++ if (tdo8) ++ val |= tdo8[i] << (i * 8); ++ if (priv->tms_buf) ++ tmsval |= tms8[i] << (i * 8); ++ } ++ if (priv->end_tms_high && (cnt == priv->tx_len)) ++ tmsval |= 1 << ((cnt % 32) - 1); ++ writel(val, priv->base + JTM_TDO_OUT(n)); ++ writel(tmsval, priv->base + JTM_TMS_OUT(n)); ++ } ++ ++ priv->ck_cnt = cnt; ++ priv->tx_len -= cnt; ++ if (priv->tx_buf) ++ priv->tx_buf += cnt / 8; ++ if (priv->tms_buf) ++ priv->tms_buf += cnt / 8; ++ ++ /* Start */ ++ val = readl(priv->base + JTM_CMD); ++ val &= ~JTM_CMD_CK_CNT; ++ val |= (cnt << 8) | JTM_CMD_ST_OP; ++ writel(val, priv->base + JTM_CMD); ++ ++ return cnt; ++} ++ ++/* should be called from atomic context */ ++static int npcm_jtm_recv(struct npcm_jtm *priv, u32 cnt) ++{ ++ u32 *buf32 = (u32 *)priv->rx_buf; ++ u8 *buf; ++ u32 val; ++ int n, i; ++ int words, bytes; ++ ++ if (priv->rx_len < cnt) ++ return -EINVAL; ++ ++ words = cnt / 32; ++ bytes = DIV_ROUND_UP((cnt % 32), 8); ++ for (n = 0; n < words; n++) { ++ val = readl(priv->base + JTM_TDI_IN(n)); ++ if (buf32) { ++ *buf32 = val; ++ buf32++; ++ } ++ } ++ ++ if (bytes) { ++ buf = (u8 *)buf32; ++ val = readl(priv->base + JTM_TDI_IN(n)); ++ if (buf) ++ for (i = 0; i < bytes; i++) ++ buf[i] = (val >> (i * 8)) & 0xFF; ++ } ++ priv->rx_len -= cnt; ++ if (priv->rx_buf) ++ priv->rx_buf += cnt / 8; ++ ++ return 0; ++} ++ ++static irqreturn_t npcm_jtm_handler(int irq, void *dev_id) ++{ ++ struct npcm_jtm *priv = dev_id; ++ u32 stat; ++ ++ stat = readl(priv->base + JTM_STAT); ++ ++ if (stat & JTM_STAT_DONE) { ++ writel(JTM_STAT_DONE, priv->base + JTM_STAT); ++ if (priv->rx_len && priv->ck_cnt) ++ npcm_jtm_recv(priv, priv->ck_cnt); ++ if (priv->rx_len == 0) ++ complete(&priv->xfer_done); ++ } ++ if (((stat & JTM_STAT_BUSY) == 0)) { ++ if (priv->tx_len) ++ npcm_jtm_send(priv); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++/* jtm_tdo: master to target, jtm_tdi: target to master */ ++static int npcm_jtm_shift(struct npcm_jtm *priv, char *jtm_tdo, ++ char *jtm_tdi, char *tms, unsigned int tcks) ++{ ++ u32 val; ++ u8 stat; ++ unsigned long flags; ++ int ret = 0; ++ ++ if (!tcks) ++ return -EINVAL; ++ ++ priv->tx_len = tcks; ++ priv->tx_buf = jtm_tdo; ++ priv->rx_len = tcks; ++ priv->rx_buf = jtm_tdi; ++ priv->tms_buf = tms; ++ ++ stat = readl(priv->base + JTM_STAT); ++ if ((stat & JTM_STAT_BUSY) != 0) { ++ dev_err(priv->dev, "jtm state busy\n"); ++ return -EBUSY; ++ } ++ ++ reinit_completion(&priv->xfer_done); ++ /* enable module and interrupt */ ++ val = readl(priv->base + JTM_CTL); ++ val |= JTM_CTL_JTM_EN | JTM_CTL_DONE_IE; ++ writel(val, priv->base + JTM_CTL); ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ npcm_jtm_send(priv); ++ spin_unlock_irqrestore(&priv->lock, flags); ++ ++ ret = wait_for_completion_timeout(&priv->xfer_done, ++ msecs_to_jiffies ++ (NPCM_JTM_TIMEOUT_MS)); ++ if (ret == 0) { ++ dev_err(priv->dev, "%s: timeout, remaining tx %u rx %u\n", ++ __func__, priv->tx_len, priv->rx_len); ++ ret = -ETIMEDOUT; ++ } else { ++ ret = 0; ++ } ++ ++ /* disable module and interrupt */ ++ val &= ~(JTM_CTL_JTM_EN | JTM_CTL_DONE_IE); ++ writel(val, priv->base + JTM_CTL); ++ ++ return ret; ++} ++ ++static void npcm_jtm_reset_hw(struct npcm_jtm *priv) ++{ ++ reset_control_assert(priv->reset); ++ udelay(5); ++ reset_control_deassert(priv->reset); ++} ++ ++static u32 npcm_jtm_set_baudrate(struct npcm_jtm *priv, unsigned int speed) ++{ ++ u32 ckdiv; ++ u32 regtemp; ++ u32 freq; ++ ++ freq = clk_get_rate(priv->clk); ++ ckdiv = DIV_ROUND_CLOSEST(freq, (2 * speed)) - 1; ++ ++ regtemp = readl(priv->base + JTM_CTL); ++ regtemp &= ~JTM_CTL_CKDV; ++ writel(regtemp | (ckdiv << 16), priv->base + JTM_CTL); ++ ++ return (freq / ((ckdiv + 1) * 2)); ++} ++ ++static void jtag_reset_tapstate(struct npcm_jtm *jtag) ++{ ++ u8 tms[2]; ++ ++ dev_dbg(jtag->miscdev.parent, "reset tapstate\n"); ++ tms[0] = 0xff; ++ tms[1] = 0x01; ++ npcm_jtm_shift(jtag, NULL, NULL, tms, JTAG_TLR_TMS_COUNT); ++ jtag->tapstate = jtagtlr; ++} ++ ++static int jtag_set_tapstate(struct npcm_jtm *jtag, ++ enum jtagstates from, enum jtagstates to) ++{ ++ u8 tms[2]; ++ u8 count; ++ int ret; ++ ++ jtag->end_tms_high = false; ++ if (to == jtagtlr) { ++ jtag_reset_tapstate(jtag); ++ return 0; ++ } ++ ++ if (from == JTAG_STATE_CURRENT) ++ from = jtag->tapstate; ++ ++ if (from == to || to == JTAG_STATE_CURRENT) ++ return 0; ++ ++ if (from > JTAG_STATE_CURRENT || to > JTAG_STATE_CURRENT) ++ return -1; ++ ++ tms[0] = tmscyclelookup[from][to].tmsbits; ++ count = tmscyclelookup[from][to].count; ++ ++ if (count == 0) ++ return 0; ++ ++ ret = npcm_jtm_shift(jtag, NULL, NULL, tms, count); ++ pr_debug("jtag: change state %d -> %d\n", from, to); ++ jtag->tapstate = to; ++ ++ return ret; ++} ++ ++static int jtag_bitbangs(struct npcm_jtm *jtag, ++ struct bitbang_packet *bitbangs, ++ struct tck_bitbang *bitbang_data) ++{ ++ int ret = 0; ++ int i; ++ u8 *jtm_tdo, *jtm_tdi, *tms; ++ ++ jtag->end_tms_high = false; ++ for (i = 0; i < bitbangs->length; i++) { ++ jtm_tdo = &(bitbang_data[i].tdi); ++ jtm_tdi = &(bitbang_data[i].tdo); ++ tms = &(bitbang_data[i].tms); ++ ret = npcm_jtm_shift(jtag, jtm_tdo, jtm_tdi, tms, 1); ++ if (ret != 0) ++ break; ++ } ++ ++ return ret; ++} ++ ++static int jtag_transfer(struct npcm_jtm *jtag, ++ struct jtag_xfer *xfer, u8 *jtm_tdo, u32 bytes) ++{ ++ u8 *jtm_tdi = NULL; ++ int ret; ++ ++ if (xfer->length == 0) ++ return 0; ++ ++ jtm_tdi = kzalloc(bytes, GFP_KERNEL); ++ if (!jtm_tdi) ++ return -ENOMEM; ++ ++ if (xfer->type == JTAG_SIR_XFER) ++ jtag_set_tapstate(jtag, xfer->from, jtagshfir); ++ else if (xfer->type == JTAG_SDR_XFER) ++ jtag_set_tapstate(jtag, xfer->from, jtagshfdr); ++ ++ /* SIR/SDR: the last bit should be shifted with TMS high */ ++ if ((xfer->type == JTAG_SIR_XFER && xfer->endstate != jtagshfir) || ++ (xfer->type == JTAG_SDR_XFER && xfer->endstate != jtagshfdr)) { ++ jtag->end_tms_high = true; ++ jtag->tapstate = (jtag->tapstate == jtagshfdr) ? ++ jtagex1dr : jtagex1ir; ++ } else ++ jtag->end_tms_high = false; ++ ++ ret = npcm_jtm_shift(jtag, jtm_tdo, jtm_tdi, NULL, xfer->length); ++ jtag_set_tapstate(jtag, JTAG_STATE_CURRENT, xfer->endstate); ++ ++ if (jtm_tdo && !ret) ++ memcpy(jtm_tdo, jtm_tdi, bytes); ++ kfree(jtm_tdi); ++ ++ return ret; ++} ++ ++/* Run in specified state for a specfied number of tcks */ ++static int jtag_run_state(struct npcm_jtm *jtag, enum jtagstates run_state, ++ unsigned int tcks) ++{ ++ int ret; ++ ++ dev_dbg(jtag->miscdev.parent, "run test: tcks %u\n", tcks); ++ jtag_set_tapstate(jtag, JTAG_STATE_CURRENT, run_state); ++ jtag->end_tms_high = false; ++ ret = npcm_jtm_shift(jtag, NULL, NULL, NULL, tcks); ++ ++ return ret; ++} ++ ++static long jtag_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ++{ ++ struct npcm_jtm *priv = file->private_data; ++ struct jtag_tap_state tapstate; ++ struct jtag_xfer xfer; ++ struct bitbang_packet bitbang; ++ struct tck_bitbang *bitbang_data; ++ u8 *xfer_data; ++ u32 data_size, print_size; ++ u32 value; ++ int ret = 0; ++ ++ switch (cmd) { ++ case JTAG_SIOCFREQ: ++ if (get_user(value, (__u32 __user *)arg)) ++ return -EFAULT; ++ if (value <= NPCM_JTM_MAX_RATE) { ++ priv->freq = npcm_jtm_set_baudrate(priv, value); ++ dev_dbg(priv->miscdev.parent, "JTAG_SIOCFREQ: freq %u", ++ priv->freq); ++ } else { ++ dev_err(priv->dev, "invalid jtag freq %u\n", value); ++ ret = -EINVAL; ++ } ++ break; ++ case JTAG_GIOCFREQ: ++ dev_dbg(priv->miscdev.parent, "JTAG_GIOCFREQ: freq %u", ++ priv->freq); ++ if (put_user(priv->freq, (__u32 __user *)arg)) ++ return -EFAULT; ++ break; ++ case JTAG_IOCBITBANG: ++ if (copy_from_user(&bitbang, (const void __user *)arg, ++ sizeof(struct bitbang_packet))) ++ return -EFAULT; ++ ++ if (bitbang.length >= JTAG_MAX_XFER_DATA_LEN) ++ return -EINVAL; ++ ++ data_size = bitbang.length * sizeof(struct tck_bitbang); ++ bitbang_data = memdup_user((void __user *)bitbang.data, ++ data_size); ++ if (IS_ERR(bitbang_data)) ++ return -EFAULT; ++ ++ dev_dbg(priv->miscdev.parent, "JTAG_IOCBITBANG: len %u", ++ bitbang.length); ++ ret = jtag_bitbangs(priv, &bitbang, bitbang_data); ++ if (ret) { ++ kfree(bitbang_data); ++ return -EIO; ++ } ++ ret = copy_to_user((void __user *)bitbang.data, ++ (void *)bitbang_data, data_size); ++ kfree(bitbang_data); ++ if (ret) ++ return -EFAULT; ++ break; ++ case JTAG_SIOCSTATE: ++ if (copy_from_user(&tapstate, (const void __user *)arg, ++ sizeof(struct jtag_tap_state))) ++ return -EFAULT; ++ ++ if (tapstate.from > JTAG_STATE_CURRENT) ++ return -EINVAL; ++ ++ if (tapstate.endstate > JTAG_STATE_CURRENT) ++ return -EINVAL; ++ ++ if (tapstate.reset > JTAG_FORCE_RESET) ++ return -EINVAL; ++ ++ dev_dbg(priv->miscdev.parent, ++ "JTAG_SIOCSTATE(curr %d): from %d to %d reset %d tck %d", ++ priv->tapstate, ++ tapstate.from, tapstate.endstate, ++ tapstate.reset, tapstate.tck); ++ if (tapstate.reset == JTAG_FORCE_RESET) ++ jtag_reset_tapstate(priv); ++ jtag_set_tapstate(priv, tapstate.from, ++ tapstate.endstate); ++ if (tapstate.endstate == JTAG_STATE_CURRENT) ++ tapstate.endstate = priv->tapstate; ++ if (tapstate.tck && (tapstate.endstate == jtagtlr || ++ tapstate.endstate == jtagrti || ++ tapstate.endstate == jtagpaudr || ++ tapstate.endstate == jtagpauir)) ++ jtag_run_state(priv, tapstate.endstate, tapstate.tck); ++ break; ++ case JTAG_GIOCSTATUS: ++ dev_dbg(priv->miscdev.parent, "JTAG_GIOCSTATUS: state %d", ++ priv->tapstate); ++ ret = put_user(priv->tapstate, (__u32 __user *)arg); ++ break; ++ case JTAG_IOCXFER: ++ if (copy_from_user(&xfer, (const void __user *)arg, ++ sizeof(struct jtag_xfer))) ++ return -EFAULT; ++ ++ if (xfer.length >= JTAG_MAX_XFER_DATA_LEN) ++ return -EINVAL; ++ ++ if (xfer.type > JTAG_SDR_XFER) ++ return -EINVAL; ++ ++ if (xfer.direction > JTAG_READ_WRITE_XFER) ++ return -EINVAL; ++ ++ if (xfer.from > JTAG_STATE_CURRENT) ++ return -EINVAL; ++ ++ if (xfer.endstate > JTAG_STATE_CURRENT) ++ return -EINVAL; ++ ++ dev_dbg(priv->miscdev.parent, ++ "JTAG_IOCXFER: type %s, dir %d, state %d to %d, padding %d, len 0x%x\n", ++ xfer.type ? "DR" : "IR", xfer.direction, ++ xfer.from, xfer.endstate, xfer.padding, xfer.length); ++ ++ data_size = DIV_ROUND_UP(xfer.length, BITS_PER_BYTE); ++ xfer_data = memdup_user((void __user *)xfer.tdio, data_size); ++ if (IS_ERR(xfer_data)) ++ return -EFAULT; ++ ++ print_size = data_size > 128 ? 128 : data_size; ++ print_hex_dump_debug("I:", DUMP_PREFIX_NONE, 16, 1, xfer_data, ++ print_size, false); ++ ret = jtag_transfer(priv, &xfer, xfer_data, data_size); ++ if (ret) { ++ kfree(xfer_data); ++ return -EIO; ++ } ++ ++ print_hex_dump_debug("O:", DUMP_PREFIX_NONE, 16, 1, xfer_data, ++ print_size, false); ++ ret = copy_to_user((void __user *)xfer.tdio, ++ (void *)xfer_data, data_size); ++ kfree(xfer_data); ++ if (ret) ++ return -EFAULT; ++ ++ if (copy_to_user((void __user *)arg, (void *)&xfer, ++ sizeof(struct jtag_xfer))) ++ return -EFAULT; ++ break; ++ case JTAG_SIOCMODE: ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return ret; ++} ++ ++static int jtag_open(struct inode *inode, struct file *file) ++{ ++ struct npcm_jtm *jtag; ++ ++ jtag = container_of(file->private_data, struct npcm_jtm, miscdev); ++ ++ spin_lock(&jtag_file_lock); ++ if (jtag->is_open) { ++ spin_unlock(&jtag_file_lock); ++ return -EBUSY; ++ } ++ ++ jtag->is_open = true; ++ file->private_data = jtag; ++ spin_unlock(&jtag_file_lock); ++ ++ return 0; ++} ++ ++static int jtag_release(struct inode *inode, struct file *file) ++{ ++ struct npcm_jtm *jtag = file->private_data; ++ ++ spin_lock(&jtag_file_lock); ++ jtag->is_open = false; ++ spin_unlock(&jtag_file_lock); ++ ++ return 0; ++} ++ ++const struct file_operations npcm_jtag_fops = { ++ .open = jtag_open, ++ .unlocked_ioctl = jtag_ioctl, ++ .release = jtag_release, ++}; ++ ++static int jtag_register_device(struct npcm_jtm *jtag) ++{ ++ struct device *dev = jtag->dev; ++ int err; ++ int id; ++ ++ if (!dev) ++ return -ENODEV; ++ ++ id = ida_simple_get(&jtag_ida, 0, 0, GFP_KERNEL); ++ if (id < 0) ++ return id; ++ ++ jtag->id = id; ++ jtag->miscdev.parent = dev; ++ jtag->miscdev.fops = &npcm_jtag_fops; ++ jtag->miscdev.minor = MISC_DYNAMIC_MINOR; ++ jtag->miscdev.name = kasprintf(GFP_KERNEL, "jtag%d", id); ++ if (!jtag->miscdev.name) { ++ err = -ENOMEM; ++ goto err; ++ } ++ ++ err = misc_register(&jtag->miscdev); ++ if (err) { ++ dev_err(jtag->miscdev.parent, ++ "Unable to register device, err %d\n", err); ++ kfree(jtag->miscdev.name); ++ goto err; ++ } ++ ++ return 0; ++ ++err: ++ ida_simple_remove(&jtag_ida, id); ++ return err; ++} ++ ++static int npcm_jtm_probe(struct platform_device *pdev) ++{ ++ struct npcm_jtm *priv; ++ u32 val; ++ int irq; ++ int ret; ++ ++ dev_info(&pdev->dev, "%s\n", __func__); ++ ++ priv = kzalloc(sizeof(struct npcm_jtm), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ priv->dev = &pdev->dev; ++ ++ priv->base = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(priv->base)) { ++ ret = PTR_ERR(priv->base); ++ goto out_free_mem; ++ } ++ ++ priv->clk = devm_clk_get(&pdev->dev, NULL); ++ if (IS_ERR(priv->clk)) { ++ dev_err(&pdev->dev, "failed to get clock\n"); ++ ret = PTR_ERR(priv->clk); ++ goto out_free_mem; ++ } ++ ++ ret = clk_prepare_enable(priv->clk); ++ if (ret) ++ goto out_free_mem; ++ ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) { ++ ret = irq; ++ goto out_disable_clk; ++ } ++ ++ priv->reset = devm_reset_control_get(&pdev->dev, NULL); ++ if (IS_ERR(priv->reset)) { ++ ret = PTR_ERR(priv->reset); ++ goto out_disable_clk; ++ } ++ ++ /* reset JTM-HW block */ ++ npcm_jtm_reset_hw(priv); ++ ++ ret = devm_request_irq(&pdev->dev, irq, npcm_jtm_handler, 0, ++ "npcm-jtm", priv); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to request IRQ\n"); ++ goto out_disable_clk; ++ } ++ ++ init_completion(&priv->xfer_done); ++ ++ priv->freq = npcm_jtm_set_baudrate(priv, NPCM_JTM_DEFAULT_RATE); ++ ++ /* Deassert TRST for normal operation */ ++ val = readl(priv->base + JTM_CTL); ++ val |= JTM_CTL_TRST; ++ writel(val, priv->base + JTM_CTL); ++ ++ ret = jtag_register_device(priv); ++ if (ret) { ++ dev_err(&pdev->dev, "failed to create device\n"); ++ goto out_disable_clk; ++ } ++ platform_set_drvdata(pdev, priv); ++ ++ return 0; ++ ++out_disable_clk: ++ clk_disable_unprepare(priv->clk); ++ ++out_free_mem: ++ kfree(priv); ++ return ret; ++} ++ ++static int npcm_jtm_remove(struct platform_device *pdev) ++{ ++ struct npcm_jtm *jtag = platform_get_drvdata(pdev); ++ ++ if (!jtag) ++ return 0; ++ ++ misc_deregister(&jtag->miscdev); ++ kfree(jtag->miscdev.name); ++ kfree(jtag); ++ ida_simple_remove(&jtag_ida, jtag->id); ++ ++ return 0; ++} ++ ++static const struct of_device_id npcm_jtm_id[] = { ++ { .compatible = "nuvoton,npcm845-jtm", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, npcm_jtm_id); ++ ++static struct platform_driver npcm8xx_jtm_driver = { ++ .probe = npcm_jtm_probe, ++ .remove = npcm_jtm_remove, ++ .driver = { ++ .name = "jtag-master", ++ .owner = THIS_MODULE, ++ .of_match_table = npcm_jtm_id, ++ }, ++}; ++ ++module_platform_driver(npcm8xx_jtm_driver); ++ ++MODULE_AUTHOR("Stanley Chu "); ++MODULE_DESCRIPTION("NPCM8xx JTAG Master Driver"); ++MODULE_LICENSE("GPL v2"); ++ +-- +2.34.1 + diff --git a/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1035-i3c-master-Add-Nuvoton-npcm845-i3c-master-driver.patch b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1035-i3c-master-Add-Nuvoton-npcm845-i3c-master-driver.patch new file mode 100644 index 00000000000..7249354cabe --- /dev/null +++ b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1035-i3c-master-Add-Nuvoton-npcm845-i3c-master-driver.patch @@ -0,0 +1,2459 @@ +From ac7d9479753a31f4bee21afca0a57f3b2f995583 Mon Sep 17 00:00:00 2001 +From: James Chiang +Date: Fri, 12 Jul 2024 11:01:01 +0800 +Subject: [PATCH] i3c: master: Add Nuvoton npcm845 i3c master driver + +Add support for the Nuvoton npcm845 i3c controller which +implements I3C master functionality as defined in the MIPI +Alliance Specification for I3C, Version 1.0. + +The master role is supported in SDR mode only. IBI and Hot-join +requsts are supported. + +This change is also contributing to torvalds upstream for reviewing. +Lore Link: https://lore.kernel.org/all/20240730062122.3781121-3-yschu@nuvoton.com/ + +Signed-off-by: Stanley Chu +Signed-off-by: James Chiang +--- + MAINTAINERS | 7 + + drivers/i3c/master/Kconfig | 14 + + drivers/i3c/master/Makefile | 1 + + drivers/i3c/master/npcm845-i3c-master.c | 2372 +++++++++++++++++++++++ + 4 files changed, 2394 insertions(+) + create mode 100644 drivers/i3c/master/npcm845-i3c-master.c + +diff --git a/MAINTAINERS b/MAINTAINERS +index e46d0f6ab29c..7c020ea88ffc 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -2510,6 +2510,13 @@ F: Documentation/userspace-api/media/drivers/npcm-video.rst + F: drivers/media/platform/nuvoton/ + F: include/uapi/linux/npcm-video.h + ++ARM/NUVOTON NPCM845 I3C MASTER DRIVER ++M: Stanley Chu ++M: James Chiang ++S: Maintained ++F: Documentation/devicetree/bindings/i3c/nuvoton,i3c-master.yaml ++F: drivers/i3c/master/npcm845-i3c-master.c ++ + ARM/NUVOTON WPCM450 ARCHITECTURE + M: Jonathan Neuschäfer + L: openbmc@lists.ozlabs.org (moderated for non-subscribers) +diff --git a/drivers/i3c/master/Kconfig b/drivers/i3c/master/Kconfig +index 90dee3ec5520..a71d504d4744 100644 +--- a/drivers/i3c/master/Kconfig ++++ b/drivers/i3c/master/Kconfig +@@ -44,6 +44,20 @@ config SVC_I3C_MASTER + help + Support for Silvaco I3C Dual-Role Master Controller. + ++config NPCM845_I3C_MASTER ++ tristate "Nuvoton NPCM845 I3C master driver" ++ depends on I3C ++ depends on HAS_IOMEM ++ depends on ARCH_NPCM || COMPILE_TEST ++ help ++ Support for Nuvoton NPCM845 I3C Master Controller. ++ ++ This hardware is an instance of the SVC I3C controller; this ++ driver adds platform specific support for NPCM845 hardware. ++ ++ This driver can also be built as a module. If so, the module ++ will be called npcm845-i3c-master. ++ + config MIPI_I3C_HCI + tristate "MIPI I3C Host Controller Interface driver (EXPERIMENTAL)" + depends on I3C +diff --git a/drivers/i3c/master/Makefile b/drivers/i3c/master/Makefile +index 3e97960160bc..3ed55113190a 100644 +--- a/drivers/i3c/master/Makefile ++++ b/drivers/i3c/master/Makefile +@@ -3,4 +3,5 @@ obj-$(CONFIG_CDNS_I3C_MASTER) += i3c-master-cdns.o + obj-$(CONFIG_DW_I3C_MASTER) += dw-i3c-master.o + obj-$(CONFIG_AST2600_I3C_MASTER) += ast2600-i3c-master.o + obj-$(CONFIG_SVC_I3C_MASTER) += svc-i3c-master.o ++obj-$(CONFIG_NPCM845_I3C_MASTER) += npcm845-i3c-master.o + obj-$(CONFIG_MIPI_I3C_HCI) += mipi-i3c-hci/ +diff --git a/drivers/i3c/master/npcm845-i3c-master.c b/drivers/i3c/master/npcm845-i3c-master.c +new file mode 100644 +index 000000000000..84478ea7702c +--- /dev/null ++++ b/drivers/i3c/master/npcm845-i3c-master.c +@@ -0,0 +1,2372 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Nuvoton NPCM845 I3C master driver ++ * ++ * Copyright (C) 2024 Nuvoton Technology Corp. ++ * Based on svc i3c master driver and add platform specific support ++ * for NPCM845 hardware. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Master Mode Registers */ ++#define NPCM_I3C_MCONFIG 0x000 ++#define NPCM_I3C_MCONFIG_MASTER_EN BIT(0) ++#define NPCM_I3C_MCONFIG_DISTO(x) FIELD_PREP(BIT(3), (x)) ++#define NPCM_I3C_MCONFIG_HKEEP(x) FIELD_PREP(GENMASK(5, 4), (x)) ++#define NPCM_I3C_MCONFIG_ODSTOP(x) FIELD_PREP(BIT(6), (x)) ++#define NPCM_I3C_MCONFIG_PPBAUD(x) FIELD_PREP(GENMASK(11, 8), (x)) ++#define NPCM_I3C_MCONFIG_PPLOW(x) FIELD_PREP(GENMASK(15, 12), (x)) ++#define NPCM_I3C_MCONFIG_ODBAUD(x) FIELD_PREP(GENMASK(23, 16), (x)) ++#define NPCM_I3C_MCONFIG_ODHPP(x) FIELD_PREP(BIT(24), (x)) ++#define NPCM_I3C_MCONFIG_SKEW(x) FIELD_PREP(GENMASK(27, 25), (x)) ++#define NPCM_I3C_MCONFIG_SKEW_MASK GENMASK(27, 25) ++#define NPCM_I3C_MCONFIG_I2CBAUD(x) FIELD_PREP(GENMASK(31, 28), (x)) ++ ++#define NPCM_I3C_MCTRL 0x084 ++#define NPCM_I3C_MCTRL_REQUEST_MASK GENMASK(2, 0) ++#define NPCM_I3C_MCTRL_REQUEST(x) FIELD_GET(GENMASK(2, 0), (x)) ++#define NPCM_I3C_MCTRL_REQUEST_NONE 0 ++#define NPCM_I3C_MCTRL_REQUEST_START_ADDR 1 ++#define NPCM_I3C_MCTRL_REQUEST_STOP 2 ++#define NPCM_I3C_MCTRL_REQUEST_IBI_ACKNACK 3 ++#define NPCM_I3C_MCTRL_REQUEST_PROC_DAA 4 ++#define NPCM_I3C_MCTRL_REQUEST_FORCE_EXIT 6 ++#define NPCM_I3C_MCTRL_REQUEST_AUTO_IBI 7 ++#define NPCM_I3C_MCTRL_TYPE_I3C 0 ++#define NPCM_I3C_MCTRL_TYPE_I2C BIT(4) ++#define NPCM_I3C_MCTRL_IBIRESP_AUTO 0 ++#define NPCM_I3C_MCTRL_IBIRESP_ACK_WITHOUT_BYTE 0 ++#define NPCM_I3C_MCTRL_IBIRESP_ACK_WITH_BYTE BIT(7) ++#define NPCM_I3C_MCTRL_IBIRESP_NACK BIT(6) ++#define NPCM_I3C_MCTRL_IBIRESP_MANUAL GENMASK(7, 6) ++#define NPCM_I3C_MCTRL_DIR(x) FIELD_PREP(BIT(8), (x)) ++#define NPCM_I3C_MCTRL_DIR_WRITE 0 ++#define NPCM_I3C_MCTRL_DIR_READ 1 ++#define NPCM_I3C_MCTRL_ADDR(x) FIELD_PREP(GENMASK(15, 9), (x)) ++#define NPCM_I3C_MCTRL_RDTERM(x) FIELD_PREP(GENMASK(23, 16), (x)) ++ ++#define NPCM_I3C_MSTATUS 0x088 ++#define NPCM_I3C_MSTATUS_STATE(x) FIELD_GET(GENMASK(2, 0), (x)) ++#define NPCM_I3C_MSTATUS_STATE_DAA(x) (NPCM_I3C_MSTATUS_STATE(x) == 5) ++#define NPCM_I3C_MSTATUS_STATE_IDLE(x) (NPCM_I3C_MSTATUS_STATE(x) == 0) ++#define NPCM_I3C_MSTATUS_STATE_SLVREQ(x) (NPCM_I3C_MSTATUS_STATE(x) == 1) ++#define NPCM_I3C_MSTATUS_STATE_IBIACK(x) (NPCM_I3C_MSTATUS_STATE(x) == 6) ++#define NPCM_I3C_MSTATUS_BETWEEN(x) FIELD_GET(BIT(4), (x)) ++#define NPCM_I3C_MSTATUS_NACKED(x) FIELD_GET(BIT(5), (x)) ++#define NPCM_I3C_MSTATUS_IBITYPE(x) FIELD_GET(GENMASK(7, 6), (x)) ++#define NPCM_I3C_MSTATUS_IBITYPE_IBI 1 ++#define NPCM_I3C_MSTATUS_IBITYPE_MASTER_REQUEST 2 ++#define NPCM_I3C_MSTATUS_IBITYPE_HOT_JOIN 3 ++#define NPCM_I3C_MINT_SLVSTART BIT(8) ++#define NPCM_I3C_MINT_MCTRLDONE BIT(9) ++#define NPCM_I3C_MINT_COMPLETE BIT(10) ++#define NPCM_I3C_MINT_RXPEND BIT(11) ++#define NPCM_I3C_MINT_TXNOTFULL BIT(12) ++#define NPCM_I3C_MINT_IBIWON BIT(13) ++#define NPCM_I3C_MINT_ERRWARN BIT(15) ++#define NPCM_I3C_MSTATUS_SLVSTART(x) FIELD_GET(NPCM_I3C_MINT_SLVSTART, (x)) ++#define NPCM_I3C_MSTATUS_MCTRLDONE(x) FIELD_GET(NPCM_I3C_MINT_MCTRLDONE, (x)) ++#define NPCM_I3C_MSTATUS_COMPLETE(x) FIELD_GET(NPCM_I3C_MINT_COMPLETE, (x)) ++#define NPCM_I3C_MSTATUS_RXPEND(x) FIELD_GET(NPCM_I3C_MINT_RXPEND, (x)) ++#define NPCM_I3C_MSTATUS_TXNOTFULL(x) FIELD_GET(NPCM_I3C_MINT_TXNOTFULL, (x)) ++#define NPCM_I3C_MSTATUS_IBIWON(x) FIELD_GET(NPCM_I3C_MINT_IBIWON, (x)) ++#define NPCM_I3C_MSTATUS_ERRWARN(x) FIELD_GET(NPCM_I3C_MINT_ERRWARN, (x)) ++#define NPCM_I3C_MSTATUS_IBIADDR(x) FIELD_GET(GENMASK(30, 24), (x)) ++ ++#define NPCM_I3C_IBIRULES 0x08C ++#define NPCM_I3C_IBIRULES_ADDR(slot, addr) FIELD_PREP(GENMASK(29, 0), \ ++ ((addr) & 0x3F) << ((slot) * 6)) ++#define NPCM_I3C_IBIRULES_ADDRS 5 ++#define NPCM_I3C_IBIRULES_MSB0 BIT(30) ++#define NPCM_I3C_IBIRULES_NOBYTE BIT(31) ++#define NPCM_I3C_IBIRULES_MANDBYTE 0 ++#define NPCM_I3C_MINTSET 0x090 ++#define NPCM_I3C_MINTCLR 0x094 ++#define NPCM_I3C_MINTMASKED 0x098 ++#define NPCM_I3C_MERRWARN 0x09C ++#define NPCM_I3C_MERRWARN_NACK(x) FIELD_GET(BIT(2), (x)) ++#define NPCM_I3C_MERRWARN_TIMEOUT BIT(20) ++#define NPCM_I3C_MERRWARN_HCRC(x) FIELD_GET(BIT(10), (x)) ++#define NPCM_I3C_MDMACTRL 0x0A0 ++#define NPCM_I3C_MDMACTRL_DMAFB(x) FIELD_PREP(GENMASK(1, 0), (x)) ++#define NPCM_I3C_MDMACTRL_DMATB(x) FIELD_PREP(GENMASK(3, 2), (x)) ++#define NPCM_I3C_MDMACTRL_DMAWIDTH(x) FIELD_PREP(GENMASK(5, 4), (x)) ++#define NPCM_I3C_MDATACTRL 0x0AC ++#define NPCM_I3C_MDATACTRL_FLUSHTB BIT(0) ++#define NPCM_I3C_MDATACTRL_FLUSHRB BIT(1) ++#define NPCM_I3C_MDATACTRL_UNLOCK_TRIG BIT(3) ++#define NPCM_I3C_MDATACTRL_TXTRIG_FIFO_NOT_FULL GENMASK(5, 4) ++#define NPCM_I3C_MDATACTRL_RXTRIG_FIFO_NOT_EMPTY 0 ++#define NPCM_I3C_MDATACTRL_RXCOUNT(x) FIELD_GET(GENMASK(28, 24), (x)) ++#define NPCM_I3C_MDATACTRL_TXCOUNT(x) FIELD_GET(GENMASK(20, 16), (x)) ++#define NPCM_I3C_MDATACTRL_TXFULL BIT(30) ++#define NPCM_I3C_MDATACTRL_RXEMPTY BIT(31) ++ ++#define NPCM_I3C_MWDATAB 0x0B0 ++#define NPCM_I3C_MWDATAB_END BIT(8) ++ ++#define NPCM_I3C_MWDATABE 0x0B4 ++#define NPCM_I3C_MWDATAH 0x0B8 ++#define NPCM_I3C_MWDATAHE 0x0BC ++#define NPCM_I3C_MRDATAB 0x0C0 ++#define NPCM_I3C_MRDATAH 0x0C8 ++#define NPCM_I3C_MWMSG_SDR 0x0D0 ++#define NPCM_I3C_MRMSG_SDR 0x0D4 ++#define NPCM_I3C_MWMSG_DDR 0x0D8 ++#define NPCM_I3C_MRMSG_DDR 0x0DC ++ ++#define NPCM_I3C_MDYNADDR 0x0E4 ++#define NPCM_MDYNADDR_VALID BIT(0) ++#define NPCM_MDYNADDR_ADDR(x) FIELD_PREP(GENMASK(7, 1), (x)) ++ ++#define NPCM_I3C_PARTNO 0x06C ++#define NPCM_I3C_VENDORID 0x074 ++#define NPCM_I3C_VENDORID_VID(x) FIELD_GET(GENMASK(14, 0), (x)) ++ ++#define NPCM_I3C_MAX_DEVS 32 ++#define NPCM_I3C_PM_TIMEOUT_MS 1000 ++ ++/* This parameter depends on the implementation and may be tuned */ ++#define NPCM_I3C_FIFO_SIZE 16 ++#define NPCM_I3C_MAX_IBI_PAYLOAD_SIZE 8 ++#define NPCM_I3C_MAX_RDTERM 255 ++#define NPCM_I3C_MAX_PPBAUD 15 ++#define NPCM_I3C_MAX_PPLOW 15 ++#define NPCM_I3C_MAX_ODBAUD 255 ++#define NPCM_I3C_MAX_I2CBAUD 15 ++#define I3C_SCL_PP_PERIOD_NS_MIN 40 ++#define I3C_SCL_OD_LOW_PERIOD_NS_MIN 200 ++ ++/* DMA definitions */ ++#define MAX_DMA_COUNT 1024 ++#define DMA_CH_TX 0 ++#define DMA_CH_RX 1 ++#define NPCM_GDMA_CTL(n) (n * 0x20 + 0x00) ++#define NPCM_GDMA_CTL_GDMAMS(x) FIELD_PREP(GENMASK(3, 2), (x)) ++#define NPCM_GDMA_CTL_TWS(x) FIELD_PREP(GENMASK(13, 12), (x)) ++#define NPCM_GDMA_CTL_GDMAEN BIT(0) ++#define NPCM_GDMA_CTL_DAFIX BIT(6) ++#define NPCM_GDMA_CTL_SAFIX BIT(7) ++#define NPCM_GDMA_CTL_SIEN BIT(8) ++#define NPCM_GDMA_CTL_DM BIT(15) ++#define NPCM_GDMA_CTL_TC BIT(18) ++#define NPCM_GDMA_SRCB(n) (n * 0x20 + 0x04) ++#define NPCM_GDMA_DSTB(n) (n * 0x20 + 0x08) ++#define NPCM_GDMA_TCNT(n) (n * 0x20 + 0x0C) ++#define NPCM_GDMA_CSRC(n) (n * 0x20 + 0x10) ++#define NPCM_GDMA_CDST(n) (n * 0x20 + 0x14) ++#define NPCM_GDMA_CTCNT(n) (n * 0x20 + 0x18) ++#define NPCM_GDMA_MUX(n) (((n & 0xFFFF) >> 12) * 2 + 6) ++#define GDMA_CH0_EN GENMASK(6, 5) ++#define GDMA_CH1_EN GENMASK(22, 21) ++ ++struct npcm_i3c_cmd { ++ u8 addr; ++ bool rnw; ++ u8 *in; ++ const void *out; ++ unsigned int len; ++ unsigned int read_len; ++ bool continued; ++ bool use_dma; ++}; ++ ++struct npcm_i3c_xfer { ++ struct list_head node; ++ struct completion comp; ++ int ret; ++ unsigned int type; ++ unsigned int ncmds; ++ struct npcm_i3c_cmd cmds[]; ++}; ++ ++struct npcm_i3c_regs_save { ++ u32 mconfig; ++ u32 mdynaddr; ++}; ++ ++struct npcm_dma_xfer_desc { ++ const u8 *out; ++ u8 *in; ++ u32 len; ++ bool rnw; ++ bool end; ++}; ++/** ++ * struct npcm_i3c_master - npcm845 I3C Master structure ++ * @base: I3C master controller ++ * @dev: Corresponding device ++ * @regs: Memory mapping ++ * @saved_regs: Volatile values for PM operations ++ * @free_slots: Bit array of available slots ++ * @addrs: Array containing the dynamic addresses of each attached device ++ * @descs: Array of descriptors, one per attached device ++ * @hj_work: Hot-join work ++ * @irq: Main interrupt ++ * @pclk: System clock ++ * @fclk: Fast clock (bus) ++ * @sclk: Slow clock (other events) ++ * @xferqueue: Transfer queue structure ++ * @xferqueue.list: List member ++ * @xferqueue.cur: Current ongoing transfer ++ * @xferqueue.lock: Queue lock ++ * @ibi: IBI structure ++ * @ibi.num_slots: Number of slots available in @ibi.slots ++ * @ibi.slots: Available IBI slots ++ * @ibi.tbq_slot: To be queued IBI slot ++ * @ibi.lock: IBI lock ++ * @lock: Transfer lock, prevent concurrent daa/priv_xfer/ccc ++ * @req_lock: protect between IBI isr and bus operation request ++ */ ++struct npcm_i3c_master { ++ struct i3c_master_controller base; ++ struct device *dev; ++ void __iomem *regs; ++ struct npcm_i3c_regs_save saved_regs; ++ u32 free_slots; ++ u8 addrs[NPCM_I3C_MAX_DEVS]; ++ struct i3c_dev_desc *descs[NPCM_I3C_MAX_DEVS]; ++ struct work_struct hj_work; ++ int irq; ++ struct clk *pclk; ++ struct clk *fclk; ++ struct { ++ u32 i3c_pp_hi; ++ u32 i3c_pp_lo; ++ u32 i3c_pp_sda_rd_skew; ++ u32 i3c_pp_sda_wr_skew; ++ u32 i3c_od_hi; ++ u32 i3c_od_lo; ++ } scl_timing; ++ struct { ++ struct list_head list; ++ struct npcm_i3c_xfer *cur; ++ } xferqueue; ++ struct { ++ unsigned int num_slots; ++ struct i3c_dev_desc **slots; ++ struct i3c_ibi_slot *tbq_slot; ++ /* Prevent races within IBI handlers */ ++ spinlock_t lock; ++ } ibi; ++ spinlock_t req_lock; ++ struct mutex lock; ++ struct dentry *debugfs; ++ ++ /* For DMA */ ++ void __iomem *dma_regs; ++ void __iomem *dma_ctl_regs; ++ bool use_dma; ++ struct completion xfer_comp; ++ char *dma_tx_buf; ++ char *dma_rx_buf; ++ dma_addr_t dma_tx_addr; ++ dma_addr_t dma_rx_addr; ++ struct npcm_dma_xfer_desc dma_xfer; ++ ++ bool en_hj; ++}; ++ ++/** ++ * struct npcm_i3c_i2c_dev_data - Device specific data ++ * @index: Index in the master tables corresponding to this device ++ * @ibi: IBI slot index in the master structure ++ * @ibi_pool: IBI pool associated to this device ++ */ ++struct npcm_i3c_i2c_dev_data { ++ u8 index; ++ int ibi; ++ struct i3c_generic_ibi_pool *ibi_pool; ++}; ++ ++static DEFINE_MUTEX(npcm_i3c_dma_lock); ++ ++static int npcm_i3c_master_wait_for_complete(struct npcm_i3c_master *master); ++static void npcm_i3c_master_stop_dma(struct npcm_i3c_master *master); ++ ++static void npcm_i3c_master_dma_lock(void) ++{ ++ mutex_lock(&npcm_i3c_dma_lock); ++} ++ ++static void npcm_i3c_master_dma_unlock(void) ++{ ++ mutex_unlock(&npcm_i3c_dma_lock); ++} ++ ++static bool npcm_i3c_master_error(struct npcm_i3c_master *master) ++{ ++ u32 mstatus, merrwarn; ++ ++ mstatus = readl(master->regs + NPCM_I3C_MSTATUS); ++ if (NPCM_I3C_MSTATUS_ERRWARN(mstatus)) { ++ merrwarn = readl(master->regs + NPCM_I3C_MERRWARN); ++ writel(merrwarn, master->regs + NPCM_I3C_MERRWARN); ++ ++ /* Ignore timeout error */ ++ if (merrwarn & NPCM_I3C_MERRWARN_TIMEOUT) { ++ dev_dbg(master->dev, "Warning condition: MSTATUS 0x%08x, MERRWARN 0x%08x\n", ++ mstatus, merrwarn); ++ return false; ++ } ++ ++ dev_err(master->dev, ++ "Error condition: MSTATUS 0x%08x, MERRWARN 0x%08x\n", ++ mstatus, merrwarn); ++ ++ return true; ++ } ++ ++ return false; ++} ++ ++static void npcm_i3c_master_set_sda_skew(struct npcm_i3c_master *master, int skew) ++{ ++ u32 val; ++ ++ val = readl(master->regs + NPCM_I3C_MCONFIG) & ~NPCM_I3C_MCONFIG_SKEW_MASK; ++ val |= NPCM_I3C_MCONFIG_SKEW(skew); ++ writel(val, master->regs + NPCM_I3C_MCONFIG); ++} ++ ++static void npcm_i3c_master_enable_interrupts(struct npcm_i3c_master *master, u32 mask) ++{ ++ writel(mask, master->regs + NPCM_I3C_MINTSET); ++} ++ ++static void npcm_i3c_master_disable_interrupts(struct npcm_i3c_master *master) ++{ ++ u32 mask = readl(master->regs + NPCM_I3C_MINTSET); ++ ++ writel(mask, master->regs + NPCM_I3C_MINTCLR); ++} ++ ++static void npcm_i3c_master_clear_merrwarn(struct npcm_i3c_master *master) ++{ ++ /* Clear pending warnings */ ++ writel(readl(master->regs + NPCM_I3C_MERRWARN), ++ master->regs + NPCM_I3C_MERRWARN); ++} ++ ++static void npcm_i3c_master_flush_fifo(struct npcm_i3c_master *master) ++{ ++ /* Flush FIFOs */ ++ writel(NPCM_I3C_MDATACTRL_FLUSHTB | NPCM_I3C_MDATACTRL_FLUSHRB, ++ master->regs + NPCM_I3C_MDATACTRL); ++} ++ ++static void npcm_i3c_master_flush_rx_fifo(struct npcm_i3c_master *master) ++{ ++ writel(NPCM_I3C_MDATACTRL_FLUSHRB, master->regs + NPCM_I3C_MDATACTRL); ++} ++ ++static void npcm_i3c_master_reset_fifo_trigger(struct npcm_i3c_master *master) ++{ ++ u32 reg; ++ ++ /* Set RX and TX tigger levels, flush FIFOs */ ++ reg = NPCM_I3C_MDATACTRL_FLUSHTB | ++ NPCM_I3C_MDATACTRL_FLUSHRB | ++ NPCM_I3C_MDATACTRL_UNLOCK_TRIG | ++ NPCM_I3C_MDATACTRL_TXTRIG_FIFO_NOT_FULL | ++ NPCM_I3C_MDATACTRL_RXTRIG_FIFO_NOT_EMPTY; ++ writel(reg, master->regs + NPCM_I3C_MDATACTRL); ++} ++ ++static void npcm_i3c_master_reset(struct npcm_i3c_master *master) ++{ ++ npcm_i3c_master_clear_merrwarn(master); ++ npcm_i3c_master_reset_fifo_trigger(master); ++ npcm_i3c_master_disable_interrupts(master); ++} ++ ++static inline struct npcm_i3c_master * ++to_npcm_i3c_master(struct i3c_master_controller *master) ++{ ++ return container_of(master, struct npcm_i3c_master, base); ++} ++ ++static void npcm_i3c_master_hj_work(struct work_struct *work) ++{ ++ struct npcm_i3c_master *master; ++ ++ master = container_of(work, struct npcm_i3c_master, hj_work); ++ ++ i3c_master_do_daa(&master->base); ++} ++ ++static struct i3c_dev_desc * ++npcm_i3c_master_dev_from_addr(struct npcm_i3c_master *master, ++ unsigned int ibiaddr) ++{ ++ int i; ++ ++ for (i = 0; i < NPCM_I3C_MAX_DEVS; i++) ++ if (master->addrs[i] == ibiaddr) ++ break; ++ ++ if (i == NPCM_I3C_MAX_DEVS) ++ return NULL; ++ ++ return master->descs[i]; ++} ++ ++static void npcm_i3c_master_ack_ibi(struct npcm_i3c_master *master, ++ bool mandatory_byte) ++{ ++ unsigned int ibi_ack_nack; ++ u32 reg; ++ ++ ibi_ack_nack = NPCM_I3C_MCTRL_REQUEST_IBI_ACKNACK; ++ if (mandatory_byte) ++ ibi_ack_nack |= NPCM_I3C_MCTRL_IBIRESP_ACK_WITH_BYTE | ++ NPCM_I3C_MCTRL_RDTERM(NPCM_I3C_MAX_IBI_PAYLOAD_SIZE); ++ else ++ ibi_ack_nack |= NPCM_I3C_MCTRL_IBIRESP_ACK_WITHOUT_BYTE; ++ ++ writel(ibi_ack_nack, master->regs + NPCM_I3C_MCTRL); ++ readl_poll_timeout(master->regs + NPCM_I3C_MSTATUS, reg, ++ NPCM_I3C_MSTATUS_MCTRLDONE(reg), 0, 1000); ++} ++ ++static void npcm_i3c_master_nack_ibi(struct npcm_i3c_master *master) ++{ ++ u32 reg; ++ ++ writel(NPCM_I3C_MCTRL_REQUEST_IBI_ACKNACK | ++ NPCM_I3C_MCTRL_IBIRESP_NACK, ++ master->regs + NPCM_I3C_MCTRL); ++ readl_poll_timeout(master->regs + NPCM_I3C_MSTATUS, reg, ++ NPCM_I3C_MSTATUS_MCTRLDONE(reg), 0, 1000); ++} ++ ++static void npcm_i3c_master_emit_stop(struct npcm_i3c_master *master) ++{ ++ u32 reg = readl(master->regs + NPCM_I3C_MSTATUS); ++ ++ /* Do not emit stop in the IDLE or SLVREQ state */ ++ if (NPCM_I3C_MSTATUS_STATE_IDLE(reg) || NPCM_I3C_MSTATUS_STATE_SLVREQ(reg)) ++ return; ++ ++ /* ++ * The spurious IBI event may change controller state to IBIACK, switch state ++ * to NORMACT before emitSTOP request. ++ */ ++ if (NPCM_I3C_MSTATUS_STATE_IBIACK(reg)) { ++ npcm_i3c_master_nack_ibi(master); ++ writel(NPCM_I3C_MINT_IBIWON, master->regs + NPCM_I3C_MSTATUS); ++ } ++ ++ writel(NPCM_I3C_MCTRL_REQUEST_STOP, master->regs + NPCM_I3C_MCTRL); ++ readl_poll_timeout(master->regs + NPCM_I3C_MSTATUS, reg, ++ NPCM_I3C_MSTATUS_MCTRLDONE(reg), 0, 1000); ++ ++ /* ++ * This delay is necessary after the emission of a stop, otherwise eg. ++ * repeating IBIs do not get detected. There is a note in the manual ++ * about it, stating that the stop condition might not be settled ++ * correctly if a start condition follows too rapidly. ++ */ ++ udelay(1); ++} ++ ++static int npcm_i3c_master_handle_ibi(struct npcm_i3c_master *master, ++ struct i3c_dev_desc *dev) ++{ ++ struct npcm_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); ++ struct i3c_ibi_slot *slot; ++ unsigned int count; ++ u32 mdatactrl, val; ++ int ret; ++ u8 *buf; ++ ++ if (!data) { ++ dev_err_ratelimited(master->dev, "No data for addr 0x%x\n", ++ dev->info.dyn_addr); ++ goto no_ibi_pool; ++ } ++ ++ if (!data->ibi_pool) { ++ dev_err_ratelimited(master->dev, "No ibi pool for addr 0x%x\n", ++ master->addrs[data->index]); ++ goto no_ibi_pool; ++ } ++ slot = i3c_generic_ibi_get_free_slot(data->ibi_pool); ++ if (!slot) { ++ dev_err_ratelimited(master->dev, "No free ibi slot\n"); ++ goto no_ibi_pool; ++ } ++ ++ slot->len = 0; ++ buf = slot->data; ++ ++ /* ++ * Sometimes I3C HW returns to IDLE state after IBIRCV completed, ++ * continue when state becomes IDLE. ++ */ ++ ret = readl_relaxed_poll_timeout(master->regs + NPCM_I3C_MSTATUS, val, ++ NPCM_I3C_MSTATUS_COMPLETE(val) | ++ NPCM_I3C_MSTATUS_STATE_IDLE(val), ++ 0, 1000); ++ if (ret) { ++ dev_err(master->dev, "Timeout when polling for COMPLETE\n"); ++ if (NPCM_I3C_MSTATUS_RXPEND(val)) ++ npcm_i3c_master_flush_rx_fifo(master); ++ i3c_generic_ibi_recycle_slot(data->ibi_pool, slot); ++ slot = NULL; ++ goto handle_done; ++ } ++ ++ while (NPCM_I3C_MSTATUS_RXPEND(readl(master->regs + NPCM_I3C_MSTATUS)) && ++ slot->len < NPCM_I3C_MAX_IBI_PAYLOAD_SIZE) { ++ mdatactrl = readl(master->regs + NPCM_I3C_MDATACTRL); ++ count = NPCM_I3C_MDATACTRL_RXCOUNT(mdatactrl); ++ readsb(master->regs + NPCM_I3C_MRDATAB, buf, count); ++ slot->len += count; ++ buf += count; ++ } ++ ++handle_done: ++ master->ibi.tbq_slot = slot; ++ ++ return ret; ++ ++no_ibi_pool: ++ /* No ibi pool, drop the payload if received */ ++ readl_relaxed_poll_timeout(master->regs + NPCM_I3C_MSTATUS, val, ++ NPCM_I3C_MSTATUS_COMPLETE(val) | ++ NPCM_I3C_MSTATUS_STATE_IDLE(val), ++ 0, 1000); ++ npcm_i3c_master_flush_rx_fifo(master); ++ return -ENOSPC; ++} ++ ++static int npcm_i3c_master_handle_ibiwon(struct npcm_i3c_master *master, bool autoibi) ++{ ++ struct npcm_i3c_i2c_dev_data *data; ++ unsigned int ibitype, ibiaddr; ++ struct i3c_dev_desc *dev; ++ u32 status; ++ int ret = 0; ++ ++ status = readl(master->regs + NPCM_I3C_MSTATUS); ++ ibitype = NPCM_I3C_MSTATUS_IBITYPE(status); ++ ibiaddr = NPCM_I3C_MSTATUS_IBIADDR(status); ++ ++ dev_dbg(master->dev, "ibitype=%d ibiaddr=%d\n", ibitype, ibiaddr); ++ dev_dbg(master->dev, "ibiwon: mctrl=0x%x mstatus=0x%x\n", ++ readl(master->regs + NPCM_I3C_MCTRL), status); ++ /* Handle the critical responses to IBI's */ ++ switch (ibitype) { ++ case NPCM_I3C_MSTATUS_IBITYPE_IBI: ++ dev = npcm_i3c_master_dev_from_addr(master, ibiaddr); ++ /* Bypass the invalid ibi with address 0 */ ++ if (!dev || ibiaddr == 0) { ++ if (!autoibi) { ++ npcm_i3c_master_nack_ibi(master); ++ break; ++ } ++ /* ++ * Wait for complete to make sure the subsequent emitSTOP ++ * request will be performed in the correct state(NORMACT). ++ */ ++ readl_relaxed_poll_timeout(master->regs + NPCM_I3C_MSTATUS, status, ++ NPCM_I3C_MSTATUS_COMPLETE(status), ++ 0, 1000); ++ /* Flush the garbage data */ ++ if (NPCM_I3C_MSTATUS_RXPEND(status)) ++ npcm_i3c_master_flush_rx_fifo(master); ++ break; ++ } ++ if (!autoibi) { ++ if (dev->info.bcr & I3C_BCR_IBI_PAYLOAD) ++ npcm_i3c_master_ack_ibi(master, true); ++ else ++ npcm_i3c_master_ack_ibi(master, false); ++ } ++ npcm_i3c_master_handle_ibi(master, dev); ++ break; ++ case NPCM_I3C_MSTATUS_IBITYPE_HOT_JOIN: ++ npcm_i3c_master_ack_ibi(master, false); ++ break; ++ case NPCM_I3C_MSTATUS_IBITYPE_MASTER_REQUEST: ++ npcm_i3c_master_nack_ibi(master); ++ status = readl(master->regs + NPCM_I3C_MSTATUS); ++ /* Invalid event may be reported as MR request ++ * and sometimes produce dummy bytes. Flush the garbage data. ++ */ ++ if (NPCM_I3C_MSTATUS_RXPEND(status)) ++ npcm_i3c_master_flush_rx_fifo(master); ++ break; ++ default: ++ break; ++ } ++ ++ /* ++ * If an error happened, we probably got interrupted and the exchange ++ * timedout. In this case we just drop everything, emit a stop and wait ++ * for the slave to interrupt again. ++ */ ++ if (npcm_i3c_master_error(master)) { ++ if (master->ibi.tbq_slot) { ++ data = i3c_dev_get_master_data(dev); ++ i3c_generic_ibi_recycle_slot(data->ibi_pool, ++ master->ibi.tbq_slot); ++ master->ibi.tbq_slot = NULL; ++ } ++ ++ dev_err(master->dev, "npcm_i3c_master_error in ibiwon\n"); ++ /* ++ * No need to emit stop here because the caller should do it ++ * if return error ++ */ ++ ret = -EIO; ++ goto clear_ibiwon; ++ } ++ ++ /* Handle the non critical tasks */ ++ switch (ibitype) { ++ case NPCM_I3C_MSTATUS_IBITYPE_IBI: ++ /* ++ * Sometimes I3C HW returns to IDLE state after IBIRCV completed, ++ * do not emit STOP in the idle state. ++ */ ++ npcm_i3c_master_emit_stop(master); ++ if (dev && master->ibi.tbq_slot) { ++ i3c_master_queue_ibi(dev, master->ibi.tbq_slot); ++ master->ibi.tbq_slot = NULL; ++ } ++ break; ++ case NPCM_I3C_MSTATUS_IBITYPE_HOT_JOIN: ++ /* Emit stop to avoid the INVREQ error after DAA process */ ++ npcm_i3c_master_emit_stop(master); ++ queue_work(master->base.wq, &master->hj_work); ++ break; ++ case NPCM_I3C_MSTATUS_IBITYPE_MASTER_REQUEST: ++ ret = -EOPNOTSUPP; ++ default: ++ break; ++ } ++ ++clear_ibiwon: ++ /* clear IBIWON status */ ++ writel(NPCM_I3C_MINT_IBIWON, master->regs + NPCM_I3C_MSTATUS); ++ return ret; ++} ++ ++static void npcm_i3c_master_ibi_isr(struct npcm_i3c_master *master) ++{ ++ u32 val, mstatus; ++ int ret; ++ ++ spin_lock(&master->req_lock); ++ ++ /* Check slave ibi handled not yet */ ++ mstatus = readl(master->regs + NPCM_I3C_MSTATUS); ++ if (!NPCM_I3C_MSTATUS_STATE_SLVREQ(mstatus)) ++ goto ibi_out; ++ ++ /* ++ * IBIWON may be set before NPCM_I3C_MCTRL_REQUEST_AUTO_IBI, causing ++ * readl_relaxed_poll_timeout() to return immediately. Consequently, ++ * ibitype will be 0 since it was last updated only after the 8th SCL ++ * cycle, leading to missed client IBI handlers. ++ * ++ * Clear NPCM_I3C_MINT_IBIWON before sending NPCM_I3C_MCTRL_REQUEST_AUTO_IBI. ++ */ ++ writel(NPCM_I3C_MINT_IBIWON, master->regs + NPCM_I3C_MSTATUS); ++ ++ /* Acknowledge the incoming interrupt with the AUTOIBI mechanism */ ++ writel(NPCM_I3C_MCTRL_REQUEST_AUTO_IBI | ++ NPCM_I3C_MCTRL_IBIRESP_AUTO | ++ NPCM_I3C_MCTRL_RDTERM(NPCM_I3C_MAX_IBI_PAYLOAD_SIZE), ++ master->regs + NPCM_I3C_MCTRL); ++ ++ /* Wait for IBIWON, should take approximately 100us */ ++ ret = readl_relaxed_poll_timeout_atomic(master->regs + NPCM_I3C_MSTATUS, val, ++ NPCM_I3C_MSTATUS_IBIWON(val), 0, 1000); ++ if (ret) { ++ /* Cancel AUTOIBI if not started */ ++ val = readl(master->regs + NPCM_I3C_MCTRL); ++ if (NPCM_I3C_MCTRL_REQUEST(val) == NPCM_I3C_MCTRL_REQUEST_AUTO_IBI) ++ writel(0, master->regs + NPCM_I3C_MCTRL); ++ dev_err(master->dev, "Timeout when polling for IBIWON\n"); ++ npcm_i3c_master_clear_merrwarn(master); ++ npcm_i3c_master_emit_stop(master); ++ goto ibi_out; ++ } ++ ++ if (npcm_i3c_master_handle_ibiwon(master, true)) ++ npcm_i3c_master_emit_stop(master); ++ibi_out: ++ spin_unlock(&master->req_lock); ++} ++ ++static irqreturn_t npcm_i3c_master_irq_handler(int irq, void *dev_id) ++{ ++ struct npcm_i3c_master *master = (struct npcm_i3c_master *)dev_id; ++ u32 active = readl(master->regs + NPCM_I3C_MINTMASKED), mstatus; ++ ++ if (NPCM_I3C_MSTATUS_COMPLETE(active)) { ++ /* Clear COMPLETE status before emit STOP */ ++ writel(NPCM_I3C_MINT_COMPLETE, master->regs + NPCM_I3C_MSTATUS); ++ /* Disable COMPLETE interrupt */ ++ writel(NPCM_I3C_MINT_COMPLETE, master->regs + NPCM_I3C_MINTCLR); ++ ++ if (master->dma_xfer.end) { ++ /* Stop DMA to prevent receiving the data of other transaction */ ++ npcm_i3c_master_stop_dma(master); ++ npcm_i3c_master_set_sda_skew(master, 0); ++ npcm_i3c_master_emit_stop(master); ++ } ++ ++ complete(&master->xfer_comp); ++ ++ return IRQ_HANDLED; ++ } ++ ++ if (NPCM_I3C_MSTATUS_SLVSTART(active)) { ++ /* Clear the interrupt status */ ++ writel(NPCM_I3C_MINT_SLVSTART, master->regs + NPCM_I3C_MSTATUS); ++ ++ /* Read I3C state */ ++ mstatus = readl(master->regs + NPCM_I3C_MSTATUS); ++ ++ if (NPCM_I3C_MSTATUS_STATE_SLVREQ(mstatus)) { ++ npcm_i3c_master_ibi_isr(master); ++ } else { ++ /* ++ * Workaround: ++ * SlaveStart event under bad signals condition. SLVSTART bit in ++ * MSTATUS may set even slave device doesn't holding I3C_SDA low, ++ * but actual SlaveStart event may happened concurently in this ++ * bad signals condition handler. Give a chance to check current ++ * work state and intmask to avoid actual SlaveStart cannot be ++ * trigger after we clear SlaveStart interrupt status. ++ */ ++ ++ /* Check if state change after we clear interrupt status */ ++ active = readl(master->regs + NPCM_I3C_MINTMASKED); ++ mstatus = readl(master->regs + NPCM_I3C_MSTATUS); ++ ++ if (NPCM_I3C_MSTATUS_STATE_SLVREQ(mstatus)) { ++ if (!NPCM_I3C_MSTATUS_SLVSTART(active)) ++ npcm_i3c_master_ibi_isr(master); ++ /* else: handle interrupt in next time */ ++ } ++ } ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static int npcm_i3c_master_bus_init(struct i3c_master_controller *m) ++{ ++ struct npcm_i3c_master *master = to_npcm_i3c_master(m); ++ struct i3c_bus *bus = i3c_master_get_bus(m); ++ struct i3c_device_info info = {}; ++ unsigned long fclk_rate, fclk_period_ns; ++ unsigned long i3c_scl_rate, i2c_scl_rate; ++ unsigned int pp_high_period_ns, od_low_period_ns, i2c_period_ns; ++ unsigned int scl_period_ns; ++ u32 ppbaud, pplow, odhpp, odbaud, i2cbaud, reg; ++ int ret; ++ ++ /* Timings derivation */ ++ fclk_rate = clk_get_rate(master->fclk); ++ if (!fclk_rate) ++ return -EINVAL; ++ ++ fclk_period_ns = DIV_ROUND_UP(1000000000, fclk_rate); ++ ++ /* ++ * Configure for Push-Pull mode. ++ */ ++ if (master->scl_timing.i3c_pp_hi >= I3C_SCL_PP_PERIOD_NS_MIN && ++ master->scl_timing.i3c_pp_lo >= master->scl_timing.i3c_pp_hi) { ++ ppbaud = DIV_ROUND_UP(master->scl_timing.i3c_pp_hi, fclk_period_ns) - 1; ++ if (ppbaud > NPCM_I3C_MAX_PPBAUD) ++ ppbaud = NPCM_I3C_MAX_PPBAUD; ++ pplow = DIV_ROUND_UP(master->scl_timing.i3c_pp_lo, fclk_period_ns) ++ - (ppbaud + 1); ++ if (pplow > NPCM_I3C_MAX_PPLOW) ++ pplow = NPCM_I3C_MAX_PPLOW; ++ bus->scl_rate.i3c = 1000000000 / (((ppbaud + 1) * 2 + pplow) * fclk_period_ns); ++ } else { ++ scl_period_ns = DIV_ROUND_UP(1000000000, bus->scl_rate.i3c); ++ if (bus->scl_rate.i3c == 10000000) { ++ /* Workaround for npcm8xx: 40/60 ns */ ++ ppbaud = DIV_ROUND_UP(40, fclk_period_ns) - 1; ++ pplow = DIV_ROUND_UP(20, fclk_period_ns); ++ } else { ++ /* 50% duty-cycle */ ++ ppbaud = DIV_ROUND_UP((scl_period_ns / 2), fclk_period_ns) - 1; ++ pplow = 0; ++ } ++ if (ppbaud > NPCM_I3C_MAX_PPBAUD) ++ ppbaud = NPCM_I3C_MAX_PPBAUD; ++ } ++ pp_high_period_ns = (ppbaud + 1) * fclk_period_ns; ++ ++ /* ++ * Configure for Open-Drain mode. ++ */ ++ if (master->scl_timing.i3c_od_hi >= pp_high_period_ns && ++ master->scl_timing.i3c_od_lo >= I3C_SCL_OD_LOW_PERIOD_NS_MIN) { ++ if (master->scl_timing.i3c_od_hi == pp_high_period_ns) ++ odhpp = 1; ++ else ++ odhpp = 0; ++ odbaud = DIV_ROUND_UP(master->scl_timing.i3c_od_lo, pp_high_period_ns) - 1; ++ } else { ++ /* Set default OD timing: 1MHz/1000ns with 50% duty cycle */ ++ odhpp = 0; ++ odbaud = DIV_ROUND_UP(500, pp_high_period_ns) - 1; ++ } ++ if (odbaud > NPCM_I3C_MAX_ODBAUD) ++ odbaud = NPCM_I3C_MAX_ODBAUD; ++ od_low_period_ns = (odbaud + 1) * pp_high_period_ns; ++ ++ /* Configure for I2C mode */ ++ i2c_period_ns = DIV_ROUND_UP(1000000000, bus->scl_rate.i2c); ++ if (i2c_period_ns < od_low_period_ns * 2) ++ i2c_period_ns = od_low_period_ns * 2; ++ i2cbaud = DIV_ROUND_UP(i2c_period_ns, od_low_period_ns) - 2; ++ if (i2cbaud > NPCM_I3C_MAX_I2CBAUD) ++ i2cbaud = NPCM_I3C_MAX_I2CBAUD; ++ ++ i3c_scl_rate = 1000000000 / (((ppbaud + 1) * 2 + pplow) * fclk_period_ns); ++ i2c_scl_rate = 1000000000 / ((i2cbaud + 2) * od_low_period_ns); ++ ++ reg = NPCM_I3C_MCONFIG_MASTER_EN | ++ NPCM_I3C_MCONFIG_DISTO(0) | ++ NPCM_I3C_MCONFIG_HKEEP(3) | ++ NPCM_I3C_MCONFIG_ODSTOP(1) | ++ NPCM_I3C_MCONFIG_PPBAUD(ppbaud) | ++ NPCM_I3C_MCONFIG_PPLOW(pplow) | ++ NPCM_I3C_MCONFIG_ODBAUD(odbaud) | ++ NPCM_I3C_MCONFIG_ODHPP(odhpp) | ++ NPCM_I3C_MCONFIG_SKEW(0) | ++ NPCM_I3C_MCONFIG_I2CBAUD(i2cbaud); ++ writel(reg, master->regs + NPCM_I3C_MCONFIG); ++ ++ dev_dbg(master->dev, "dts: i3c rate=%lu, i2c rate=%lu\n", ++ bus->scl_rate.i3c, bus->scl_rate.i2c); ++ dev_info(master->dev, "fclk=%lu, period_ns=%lu\n", fclk_rate, fclk_period_ns); ++ dev_info(master->dev, "i3c scl_rate=%lu\n", i3c_scl_rate); ++ dev_info(master->dev, "i2c scl_rate=%lu\n", i2c_scl_rate); ++ dev_info(master->dev, "pp_high=%u, pp_low=%lu\n", pp_high_period_ns, ++ (ppbaud + 1 + pplow) * fclk_period_ns); ++ dev_info(master->dev, "pp_sda_rd_skew=%d, pp_sda_wr_skew=%d\n", ++ master->scl_timing.i3c_pp_sda_rd_skew, ++ master->scl_timing.i3c_pp_sda_wr_skew); ++ dev_info(master->dev, "od_high=%d, od_low=%d\n", ++ odhpp ? pp_high_period_ns : od_low_period_ns, od_low_period_ns); ++ dev_dbg(master->dev, "i2c_high=%u, i2c_low=%u\n", ((i2cbaud >> 1) + 1) * od_low_period_ns, ++ ((i2cbaud >> 1) + 1 + (i2cbaud % 2)) * od_low_period_ns); ++ dev_dbg(master->dev, "ppbaud=%d, pplow=%d, odbaud=%d, i2cbaud=%d\n", ++ ppbaud, pplow, odbaud, i2cbaud); ++ dev_info(master->dev, "mconfig=0x%x\n", readl(master->regs + NPCM_I3C_MCONFIG)); ++ /* Master core's registration */ ++ ret = i3c_master_get_free_addr(m, 0); ++ if (ret < 0) ++ return ret; ++ ++ info.dyn_addr = ret; ++ reg = readl(master->regs + NPCM_I3C_VENDORID); ++ info.pid = (NPCM_I3C_VENDORID_VID(reg) << 33) | readl(master->regs + NPCM_I3C_PARTNO); ++ ++ writel(NPCM_MDYNADDR_VALID | NPCM_MDYNADDR_ADDR(info.dyn_addr), ++ master->regs + NPCM_I3C_MDYNADDR); ++ ++ ret = i3c_master_set_info(&master->base, &info); ++ ++ return ret; ++} ++ ++static void npcm_i3c_master_bus_cleanup(struct i3c_master_controller *m) ++{ ++ struct npcm_i3c_master *master = to_npcm_i3c_master(m); ++ ++ npcm_i3c_master_disable_interrupts(master); ++ ++ /* Disable master */ ++ writel(0, master->regs + NPCM_I3C_MCONFIG); ++} ++ ++static int npcm_i3c_master_reserve_slot(struct npcm_i3c_master *master) ++{ ++ unsigned int slot; ++ ++ if (!(master->free_slots & GENMASK(NPCM_I3C_MAX_DEVS - 1, 0))) ++ return -ENOSPC; ++ ++ slot = ffs(master->free_slots) - 1; ++ ++ master->free_slots &= ~BIT(slot); ++ ++ return slot; ++} ++ ++static void npcm_i3c_master_release_slot(struct npcm_i3c_master *master, ++ unsigned int slot) ++{ ++ master->free_slots |= BIT(slot); ++} ++ ++static int npcm_i3c_master_attach_i3c_dev(struct i3c_dev_desc *dev) ++{ ++ struct i3c_master_controller *m = i3c_dev_get_master(dev); ++ struct npcm_i3c_master *master = to_npcm_i3c_master(m); ++ struct npcm_i3c_i2c_dev_data *data; ++ int slot; ++ ++ slot = npcm_i3c_master_reserve_slot(master); ++ if (slot < 0) ++ return slot; ++ ++ data = kzalloc(sizeof(*data), GFP_KERNEL); ++ if (!data) { ++ npcm_i3c_master_release_slot(master, slot); ++ return -ENOMEM; ++ } ++ ++ data->ibi = -1; ++ data->index = slot; ++ master->addrs[slot] = dev->info.dyn_addr ? dev->info.dyn_addr : ++ dev->info.static_addr; ++ master->descs[slot] = dev; ++ ++ i3c_dev_set_master_data(dev, data); ++ ++ return 0; ++} ++ ++static int npcm_i3c_master_reattach_i3c_dev(struct i3c_dev_desc *dev, ++ u8 old_dyn_addr) ++{ ++ struct i3c_master_controller *m = i3c_dev_get_master(dev); ++ struct npcm_i3c_master *master = to_npcm_i3c_master(m); ++ struct npcm_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); ++ ++ master->addrs[data->index] = dev->info.dyn_addr ? dev->info.dyn_addr : ++ dev->info.static_addr; ++ ++ return 0; ++} ++ ++static void npcm_i3c_master_detach_i3c_dev(struct i3c_dev_desc *dev) ++{ ++ struct npcm_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); ++ struct i3c_master_controller *m = i3c_dev_get_master(dev); ++ struct npcm_i3c_master *master = to_npcm_i3c_master(m); ++ ++ master->addrs[data->index] = 0; ++ npcm_i3c_master_release_slot(master, data->index); ++ ++ kfree(data); ++} ++ ++static int npcm_i3c_master_attach_i2c_dev(struct i2c_dev_desc *dev) ++{ ++ struct i3c_master_controller *m = i2c_dev_get_master(dev); ++ struct npcm_i3c_master *master = to_npcm_i3c_master(m); ++ struct npcm_i3c_i2c_dev_data *data; ++ int slot; ++ ++ slot = npcm_i3c_master_reserve_slot(master); ++ if (slot < 0) ++ return slot; ++ ++ data = kzalloc(sizeof(*data), GFP_KERNEL); ++ if (!data) { ++ npcm_i3c_master_release_slot(master, slot); ++ return -ENOMEM; ++ } ++ ++ data->index = slot; ++ master->addrs[slot] = dev->addr; ++ ++ i2c_dev_set_master_data(dev, data); ++ ++ return 0; ++} ++ ++static void npcm_i3c_master_detach_i2c_dev(struct i2c_dev_desc *dev) ++{ ++ struct npcm_i3c_i2c_dev_data *data = i2c_dev_get_master_data(dev); ++ struct i3c_master_controller *m = i2c_dev_get_master(dev); ++ struct npcm_i3c_master *master = to_npcm_i3c_master(m); ++ ++ npcm_i3c_master_release_slot(master, data->index); ++ ++ kfree(data); ++} ++ ++static int npcm_i3c_master_readb(struct npcm_i3c_master *master, u8 *dst, ++ unsigned int len) ++{ ++ int ret, i; ++ u32 reg; ++ ++ for (i = 0; i < len; i++) { ++ ret = readl_poll_timeout_atomic(master->regs + NPCM_I3C_MSTATUS, ++ reg, ++ NPCM_I3C_MSTATUS_RXPEND(reg), ++ 0, 1000); ++ if (ret) ++ return ret; ++ ++ dst[i] = readl(master->regs + NPCM_I3C_MRDATAB); ++ } ++ ++ return 0; ++} ++ ++static int npcm_i3c_master_do_daa_locked(struct npcm_i3c_master *master, ++ u8 *addrs, unsigned int *count) ++{ ++ u64 prov_id[NPCM_I3C_MAX_DEVS] = {}, nacking_prov_id = 0; ++ unsigned int dev_nb = 0, last_addr = 0; ++ unsigned long start = jiffies; ++ u32 reg; ++ int ret, i; ++ int dyn_addr; ++ ++ npcm_i3c_master_flush_fifo(master); ++ ++ while (true) { ++ /* Enter/proceed with DAA */ ++ writel(NPCM_I3C_MCTRL_REQUEST_PROC_DAA | ++ NPCM_I3C_MCTRL_TYPE_I3C | ++ NPCM_I3C_MCTRL_IBIRESP_MANUAL | ++ NPCM_I3C_MCTRL_DIR(NPCM_I3C_MCTRL_DIR_WRITE), ++ master->regs + NPCM_I3C_MCTRL); ++ ++ /* ++ * Either one slave will send its ID, or the assignment process ++ * is done. ++ */ ++ ret = readl_relaxed_poll_timeout_atomic(master->regs + NPCM_I3C_MSTATUS, ++ reg, ++ NPCM_I3C_MSTATUS_RXPEND(reg) | ++ NPCM_I3C_MSTATUS_MCTRLDONE(reg), ++ 0, 1000); ++ if (ret) ++ return ret; ++ ++ if (time_after(jiffies, start + msecs_to_jiffies(3000))) { ++ npcm_i3c_master_emit_stop(master); ++ dev_info(master->dev, "do_daa expired\n"); ++ break; ++ } ++ /* runtime do_daa may ibiwon by others slave devices */ ++ if (NPCM_I3C_MSTATUS_IBIWON(reg)) { ++ ret = npcm_i3c_master_handle_ibiwon(master, false); ++ if (ret) { ++ dev_err(master->dev, "daa: handle ibi event fail, ret=%d\n", ret); ++ return ret; ++ } ++ writel(NPCM_I3C_MINT_MCTRLDONE, master->regs + NPCM_I3C_MSTATUS); ++ continue; ++ } ++ ++ if (dev_nb == NPCM_I3C_MAX_DEVS) { ++ npcm_i3c_master_emit_stop(master); ++ dev_info(master->dev, "Reach max devs\n"); ++ break; ++ } ++ if (NPCM_I3C_MSTATUS_RXPEND(reg)) { ++ u8 data[6]; ++ ++ /* Give the slave device a suitable dynamic address */ ++ dyn_addr = i3c_master_get_free_addr(&master->base, last_addr + 1); ++ if (dyn_addr < 0) ++ return dyn_addr; ++ writel(dyn_addr, master->regs + NPCM_I3C_MWDATAB); ++ ++ /* ++ * We only care about the 48-bit provisional ID yet to ++ * be sure a device does not nack an address twice. ++ * Otherwise, we would just need to flush the RX FIFO. ++ */ ++ ret = npcm_i3c_master_readb(master, data, 6); ++ if (ret) ++ return ret; ++ ++ for (i = 0; i < 6; i++) ++ prov_id[dev_nb] |= (u64)(data[i]) << (8 * (5 - i)); ++ ++ /* We do not care about the BCR and DCR yet */ ++ ret = npcm_i3c_master_readb(master, data, 2); ++ if (ret) ++ return ret; ++ } else if (NPCM_I3C_MSTATUS_MCTRLDONE(reg)) { ++ if ((NPCM_I3C_MSTATUS_STATE_IDLE(reg) | ++ NPCM_I3C_MSTATUS_STATE_SLVREQ(reg)) && ++ NPCM_I3C_MSTATUS_COMPLETE(reg)) { ++ /* ++ * Sometimes the controller state is SLVREQ after ++ * DAA request completed, treat it as normal end. ++ */ ++ /* ++ * All devices received and acked they dynamic ++ * address, this is the natural end of the DAA ++ * procedure. ++ */ ++ break; ++ } else if (NPCM_I3C_MSTATUS_NACKED(reg)) { ++ /* No I3C devices attached */ ++ if (dev_nb == 0) { ++ npcm_i3c_master_emit_stop(master); ++ break; ++ } ++ ++ /* ++ * A slave device nacked the address, this is ++ * allowed only once, DAA will be stopped and ++ * then resumed. The same device is supposed to ++ * answer again immediately and shall ack the ++ * address this time. ++ */ ++ if (prov_id[dev_nb] == nacking_prov_id) ++ return -EIO; ++ ++ dev_nb--; ++ nacking_prov_id = prov_id[dev_nb]; ++ npcm_i3c_master_emit_stop(master); ++ ++ continue; ++ } else { ++ return -EIO; ++ } ++ } ++ ++ /* Wait for the slave to be ready to receive its address */ ++ ret = readl_poll_timeout_atomic(master->regs + NPCM_I3C_MSTATUS, ++ reg, ++ NPCM_I3C_MSTATUS_MCTRLDONE(reg) && ++ NPCM_I3C_MSTATUS_STATE_DAA(reg) && ++ NPCM_I3C_MSTATUS_BETWEEN(reg), ++ 0, 1000); ++ if (ret) ++ return ret; ++ ++ addrs[dev_nb] = dyn_addr; ++ dev_dbg(master->dev, "DAA: device %d assigned to 0x%02x\n", ++ dev_nb, addrs[dev_nb]); ++ last_addr = addrs[dev_nb++]; ++ } ++ ++ *count = dev_nb; ++ ++ return 0; ++} ++ ++static int npcm_i3c_update_ibirules(struct npcm_i3c_master *master) ++{ ++ struct i3c_dev_desc *dev; ++ u32 reg_mbyte = 0, reg_nobyte = NPCM_I3C_IBIRULES_NOBYTE; ++ unsigned int mbyte_addr_ok = 0, mbyte_addr_ko = 0, nobyte_addr_ok = 0, ++ nobyte_addr_ko = 0; ++ bool list_mbyte = false, list_nobyte = false; ++ ++ /* Create the IBIRULES register for both cases */ ++ i3c_bus_for_each_i3cdev(&master->base.bus, dev) { ++ if (I3C_BCR_DEVICE_ROLE(dev->info.bcr) == I3C_BCR_I3C_MASTER) { ++ if (!(dev->info.bcr & I3C_BCR_IBI_REQ_CAP)) ++ continue; ++ } ++ ++ if (dev->info.bcr & I3C_BCR_IBI_PAYLOAD) { ++ reg_mbyte |= NPCM_I3C_IBIRULES_ADDR(mbyte_addr_ok, ++ dev->info.dyn_addr); ++ ++ /* IBI rules cannot be applied to devices with MSb=1 */ ++ if (dev->info.dyn_addr & BIT(7)) ++ mbyte_addr_ko++; ++ else ++ mbyte_addr_ok++; ++ } else { ++ reg_nobyte |= NPCM_I3C_IBIRULES_ADDR(nobyte_addr_ok, ++ dev->info.dyn_addr); ++ ++ /* IBI rules cannot be applied to devices with MSb=1 */ ++ if (dev->info.dyn_addr & BIT(7)) ++ nobyte_addr_ko++; ++ else ++ nobyte_addr_ok++; ++ } ++ } ++ ++ /* Device list cannot be handled by hardware */ ++ if (!mbyte_addr_ko && mbyte_addr_ok <= NPCM_I3C_IBIRULES_ADDRS) ++ list_mbyte = true; ++ ++ if (!nobyte_addr_ko && nobyte_addr_ok <= NPCM_I3C_IBIRULES_ADDRS) ++ list_nobyte = true; ++ ++ /* No list can be properly handled, return an error */ ++ if (!list_mbyte && !list_nobyte) ++ return -ERANGE; ++ ++ /* Pick the first list that can be handled by hardware, randomly */ ++ if (list_mbyte) ++ writel(reg_mbyte, master->regs + NPCM_I3C_IBIRULES); ++ else ++ writel(reg_nobyte, master->regs + NPCM_I3C_IBIRULES); ++ ++ return 0; ++} ++ ++static int npcm_i3c_master_do_daa(struct i3c_master_controller *m) ++{ ++ struct npcm_i3c_master *master = to_npcm_i3c_master(m); ++ u8 addrs[NPCM_I3C_MAX_DEVS]; ++ unsigned int dev_nb; ++ unsigned long flags; ++ int ret, i; ++ ++ mutex_lock(&master->lock); ++ spin_lock_irqsave(&master->req_lock, flags); ++ /* ++ * Fix SCL/SDA timing issue during DAA. ++ * Set SKEW bit to 1 before initiating a DAA, set SKEW bit to 0 ++ * after DAA is completed. ++ */ ++ npcm_i3c_master_set_sda_skew(master, 1); ++ ret = npcm_i3c_master_do_daa_locked(master, addrs, &dev_nb); ++ npcm_i3c_master_set_sda_skew(master, 0); ++ spin_unlock_irqrestore(&master->req_lock, flags); ++ mutex_unlock(&master->lock); ++ if (ret) { ++ npcm_i3c_master_emit_stop(master); ++ npcm_i3c_master_clear_merrwarn(master); ++ goto daa_out; ++ } ++ ++ /* Register all devices who participated to the core */ ++ for (i = 0; i < dev_nb; i++) { ++ ret = i3c_master_add_i3c_dev_locked(m, addrs[i]); ++ if (ret) ++ dev_err(master->dev, "Unable to add i3c dev@0x%x, err %d\n", ++ addrs[i], ret); ++ } ++ ++ /* Configure IBI auto-rules */ ++ ret = npcm_i3c_update_ibirules(master); ++ if (ret) ++ dev_err(master->dev, "Cannot handle such a list of devices"); ++ ++daa_out: ++ /* No Slave ACK */ ++ if (ret == -EIO) ++ return 0; ++ ++ return ret; ++} ++ ++static int npcm_i3c_master_read(struct npcm_i3c_master *master, ++ u8 *in, unsigned int len) ++{ ++ int offset = 0, i; ++ u32 mdctrl, mstatus; ++ bool completed = false; ++ unsigned int count; ++ unsigned long start = jiffies; ++ ++ while (!completed) { ++ mstatus = readl(master->regs + NPCM_I3C_MSTATUS); ++ if (NPCM_I3C_MSTATUS_COMPLETE(mstatus) != 0) ++ completed = true; ++ ++ if (time_after(jiffies, start + msecs_to_jiffies(1000))) { ++ dev_dbg(master->dev, "I3C read timeout\n"); ++ return -ETIMEDOUT; ++ } ++ ++ mdctrl = readl(master->regs + NPCM_I3C_MDATACTRL); ++ count = NPCM_I3C_MDATACTRL_RXCOUNT(mdctrl); ++ if (offset + count > len) { ++ dev_err(master->dev, "I3C receive length too long!\n"); ++ return -EINVAL; ++ } ++ for (i = 0; i < count; i++) ++ in[offset + i] = readl(master->regs + NPCM_I3C_MRDATAB); ++ ++ offset += count; ++ } ++ ++ return offset; ++} ++ ++static int npcm_i3c_master_write(struct npcm_i3c_master *master, ++ const u8 *out, unsigned int len) ++{ ++ int offset = 0, ret; ++ u32 mdctrl; ++ ++ while (offset < len) { ++ ret = readl_poll_timeout(master->regs + NPCM_I3C_MDATACTRL, ++ mdctrl, ++ !(mdctrl & NPCM_I3C_MDATACTRL_TXFULL), ++ 0, 1000); ++ if (ret) ++ return ret; ++ ++ /* ++ * The last byte to be sent over the bus must either have the ++ * "end" bit set or be written in MWDATABE. ++ */ ++ if (likely(offset < (len - 1))) ++ writel(out[offset++], master->regs + NPCM_I3C_MWDATAB); ++ else ++ writel(out[offset++], master->regs + NPCM_I3C_MWDATABE); ++ } ++ ++ return 0; ++} ++ ++static void npcm_i3c_master_stop_dma(struct npcm_i3c_master *master) ++{ ++ writel(0, master->dma_regs + NPCM_GDMA_CTL(DMA_CH_TX)); ++ writel(0, master->dma_regs + NPCM_GDMA_CTL(DMA_CH_RX)); ++ writel(0, master->regs + NPCM_I3C_MDMACTRL); ++ ++ /* Disable COMPLETE interrupt */ ++ writel(NPCM_I3C_MINT_COMPLETE, master->regs + NPCM_I3C_MINTCLR); ++} ++ ++static void npcm_i3c_master_write_dma_table(const u8 *src, u32 *dst, int len) ++{ ++ int i; ++ ++ if (len > MAX_DMA_COUNT) ++ return; ++ ++ for (i = 0; i < len; i++) ++ dst[i] = (u32)src[i] & 0xFF; ++ ++ /* Set end bit for last byte */ ++ dst[len - 1] |= 0x100; ++} ++ ++static int npcm_i3c_master_start_dma(struct npcm_i3c_master *master) ++{ ++ struct npcm_dma_xfer_desc *xfer = &master->dma_xfer; ++ int ch = xfer->rnw ? DMA_CH_RX : DMA_CH_TX; ++ u32 val; ++ ++ if (!xfer->len) ++ return 0; ++ ++ dev_dbg(master->dev, "start dma for %s, count %d\n", ++ xfer->rnw ? "R" : "W", xfer->len); ++ ++ /* Set DMA transfer count */ ++ writel(xfer->len, master->dma_regs + NPCM_GDMA_TCNT(ch)); ++ ++ /* Write data to DMA TX table */ ++ if (!xfer->rnw) ++ npcm_i3c_master_write_dma_table(xfer->out, ++ (u32 *)master->dma_tx_buf, ++ xfer->len); ++ ++ /* ++ * Setup I3C DMA control ++ * 1 byte DMA width ++ * Enable DMA util disabled ++ */ ++ val = NPCM_I3C_MDMACTRL_DMAWIDTH(1); ++ val |= xfer->rnw ? NPCM_I3C_MDMACTRL_DMAFB(2) : NPCM_I3C_MDMACTRL_DMATB(2); ++ writel(val, master->regs + NPCM_I3C_MDMACTRL); ++ ++ /* ++ * Enable DMA ++ * Source Address Fixed for RX ++ * Destination Address Fixed for TX ++ * Use 32-bit transfer width for TX (queal to MWDATAB register width) ++ */ ++ val = NPCM_GDMA_CTL_GDMAEN; ++ if (xfer->rnw) ++ val |= NPCM_GDMA_CTL_SAFIX | NPCM_GDMA_CTL_GDMAMS(2); ++ else ++ val |= NPCM_GDMA_CTL_DAFIX | NPCM_GDMA_CTL_GDMAMS(1) | NPCM_GDMA_CTL_TWS(2); ++ writel(val, master->dma_regs + NPCM_GDMA_CTL(ch)); ++ ++ return 0; ++} ++ ++static int npcm_i3c_master_wait_for_complete(struct npcm_i3c_master *master) ++{ ++ struct npcm_dma_xfer_desc *xfer = &master->dma_xfer; ++ int ch = xfer->rnw ? DMA_CH_RX : DMA_CH_TX; ++ u32 count; ++ int ret; ++ ++ ret = wait_for_completion_timeout(&master->xfer_comp, msecs_to_jiffies(100)); ++ if (!ret) { ++ dev_err(master->dev, "DMA transfer timeout (%s)\n", xfer->rnw ? "Read" : "write"); ++ dev_err(master->dev, "mstatus = 0x%02x\n", readl(master->regs + NPCM_I3C_MSTATUS)); ++ return -ETIMEDOUT; ++ } ++ ++ /* Get the DMA transfer count */ ++ count = readl(master->dma_regs + NPCM_GDMA_CTCNT(ch)); ++ count = (count > xfer->len) ? 0 : ++ (xfer->len - count); ++ dev_dbg(master->dev, "dma xfer count %u\n", count); ++ if (xfer->rnw) ++ memcpy(xfer->in, master->dma_rx_buf, count); ++ if (count != xfer->len) ++ dev_dbg(master->dev, "short dma xfer(%s), want %d transfer %d\n", ++ xfer->rnw ? "R" : "W", xfer->len, count); ++ ++ npcm_i3c_master_stop_dma(master); ++ ++ return count; ++} ++ ++static int npcm_i3c_send_broadcast(struct npcm_i3c_master *master) ++{ ++ u32 reg; ++ int ret; ++ ++ writel(NPCM_I3C_MCTRL_REQUEST_START_ADDR | ++ NPCM_I3C_MCTRL_TYPE_I3C | ++ NPCM_I3C_MCTRL_IBIRESP_AUTO | ++ NPCM_I3C_MCTRL_DIR(0) | ++ NPCM_I3C_MCTRL_ADDR(I3C_BROADCAST_ADDR) | ++ NPCM_I3C_MCTRL_RDTERM(NPCM_I3C_MAX_IBI_PAYLOAD_SIZE), ++ master->regs + NPCM_I3C_MCTRL); ++ ret = readl_poll_timeout(master->regs + NPCM_I3C_MSTATUS, reg, ++ NPCM_I3C_MSTATUS_MCTRLDONE(reg), 0, 1000); ++ if (ret) ++ return -EIO; ++ ++ if (NPCM_I3C_MSTATUS_IBIWON(reg)) { ++ ret = npcm_i3c_master_handle_ibiwon(master, true); ++ if (ret) { ++ dev_err(master->dev, "xfer read: handle ibi event fail, ret=%d\n", ret); ++ return -EIO; ++ } ++ ++ /* Clear COMPLETE status of this IBI transaction */ ++ writel(NPCM_I3C_MINT_COMPLETE, master->regs + NPCM_I3C_MSTATUS); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static int npcm_i3c_master_xfer(struct npcm_i3c_master *master, ++ bool rnw, unsigned int xfer_type, u8 addr, ++ u8 *in, const u8 *out, unsigned int xfer_len, ++ unsigned int *read_len, bool continued, ++ bool use_dma, bool first) ++{ ++ u32 reg, rdterm = *read_len, mstatus, ibiresp; ++ int ret, i, count, space; ++ unsigned long flags; ++ unsigned long start; ++ bool bus_locked = false; ++ ++ if (rdterm > NPCM_I3C_MAX_RDTERM) ++ rdterm = NPCM_I3C_MAX_RDTERM; ++ ++ /* Prevent fifo operation from delay by interrupt */ ++ if (!use_dma) ++ local_irq_disable(); ++ else ++ npcm_i3c_master_dma_lock(); ++ ++ /* Prevent DMA start while IBI isr is running */ ++ spin_lock_irqsave(&master->req_lock, flags); ++ bus_locked = true; ++ ++ /* ++ * There is a chance that first tx data bit is lost when it ++ * is not ready in FIFO right after address phase. ++ * Prepare data before starting the transfer to fix this problem. ++ */ ++ if (!rnw && xfer_len && !use_dma) { ++ ret = readl_poll_timeout(master->regs + NPCM_I3C_MDATACTRL, ++ reg, ++ !(reg & NPCM_I3C_MDATACTRL_TXFULL), ++ 0, 1000); ++ if (ret) { ++ bus_locked = false; ++ spin_unlock_irqrestore(&master->req_lock, flags); ++ local_irq_enable(); ++ return ret; ++ } ++ ++ reg = readl(master->regs + NPCM_I3C_MDATACTRL); ++ space = NPCM_I3C_FIFO_SIZE - NPCM_I3C_MDATACTRL_TXCOUNT(reg); ++ count = xfer_len > space ? space : xfer_len; ++ for (i = 0; i < count; i++) { ++ if (i == xfer_len - 1) ++ writel(out[0], master->regs + NPCM_I3C_MWDATABE); ++ else ++ writel(out[0], master->regs + NPCM_I3C_MWDATAB); ++ out++; ++ } ++ xfer_len -= count; ++ } ++ ++ if (use_dma) { ++ if (xfer_len > MAX_DMA_COUNT) { ++ dev_err(master->dev, "data is larger than buffer size (%d)\n", ++ MAX_DMA_COUNT); ++ spin_unlock_irqrestore(&master->req_lock, flags); ++ npcm_i3c_master_dma_unlock(); ++ return -EINVAL; ++ } ++ master->dma_xfer.out = out; ++ master->dma_xfer.in = in; ++ master->dma_xfer.len = xfer_len; ++ master->dma_xfer.rnw = rnw; ++ master->dma_xfer.end = !continued; ++ init_completion(&master->xfer_comp); ++ } ++ ++ start = jiffies; ++ ++broadcast_start: ++ if (first && rnw) { ++ /* Send 7E first to avoid collision during master read */ ++ ret = npcm_i3c_send_broadcast(master); ++ if (ret < 0) { ++ dev_info(master->dev, "send 7e error\n"); ++ goto emit_stop; ++ } ++ if (time_after(jiffies, start + msecs_to_jiffies(1000))) { ++ dev_info(master->dev, "abnormal ibiwon events\n"); ++ goto emit_stop; ++ } ++ if (ret > 0) ++ goto broadcast_start; ++ } ++ ++ if (rnw) { ++ ibiresp = NPCM_I3C_MCTRL_IBIRESP_NACK; ++ npcm_i3c_master_set_sda_skew(master, ++ master->scl_timing.i3c_pp_sda_rd_skew); ++ } else { ++ ibiresp = NPCM_I3C_MCTRL_IBIRESP_AUTO; ++ npcm_i3c_master_set_sda_skew(master, ++ master->scl_timing.i3c_pp_sda_wr_skew); ++ } ++ ++ if (use_dma) ++ npcm_i3c_master_start_dma(master); ++ ++retry_start: ++ writel(NPCM_I3C_MCTRL_REQUEST_START_ADDR | ++ xfer_type | ++ ibiresp | ++ NPCM_I3C_MCTRL_DIR(rnw) | ++ NPCM_I3C_MCTRL_ADDR(addr) | ++ NPCM_I3C_MCTRL_RDTERM(rdterm), ++ master->regs + NPCM_I3C_MCTRL); ++ ++ ret = readl_poll_timeout(master->regs + NPCM_I3C_MSTATUS, reg, ++ NPCM_I3C_MSTATUS_MCTRLDONE(reg), 0, 1000); ++ if (ret) { ++ dev_err(master->dev, "xfer (%d) wait ctrl-done timeout, mstatus=0x%02x\n", ++ rnw, reg); ++ goto emit_stop; ++ } ++ ++ mstatus = readl(master->regs + NPCM_I3C_MSTATUS); ++ if (NPCM_I3C_MSTATUS_IBIWON(mstatus)) { ++ if (rnw) { ++ dev_err(master->dev, "xfer read: re-start but ibiwon, mstatus=0x%02x\n", ++ mstatus); ++ ret = -EIO; ++ goto emit_stop; ++ } ++ ++ ret = npcm_i3c_master_handle_ibiwon(master, true); ++ if (ret) { ++ dev_err(master->dev, "xfer read: handle ibi event fail, ret=%d\n", ret); ++ goto emit_stop; ++ } ++ ++ if (time_after(jiffies, start + msecs_to_jiffies(1000))) { ++ dev_info(master->dev, "abnormal ibiwon events\n"); ++ goto emit_stop; ++ } ++ ++ /* Clear COMPLETE status of this IBI transaction */ ++ writel(NPCM_I3C_MINT_COMPLETE, master->regs + NPCM_I3C_MSTATUS); ++ goto retry_start; ++ } ++ ++ /* Use COMPLETE interrupt as notification of transfer completion */ ++ if (use_dma) ++ npcm_i3c_master_enable_interrupts(master, NPCM_I3C_MINT_COMPLETE); ++ ++ bus_locked = false; ++ spin_unlock_irqrestore(&master->req_lock, flags); ++ ++ reg = readl(master->regs + NPCM_I3C_MSTATUS); ++ if (NPCM_I3C_MSTATUS_NACKED(reg)) { ++ dev_dbg(master->dev, "addr 0x%x NACK\n", addr); ++ ret = -EIO; ++ goto emit_stop; ++ } ++ ++ if (use_dma) ++ ret = npcm_i3c_master_wait_for_complete(master); ++ else if (rnw) ++ ret = npcm_i3c_master_read(master, in, xfer_len); ++ else ++ ret = npcm_i3c_master_write(master, out, xfer_len); ++ if (ret < 0) ++ goto emit_stop; ++ ++ if (rnw) ++ *read_len = ret; ++ ++ if (!use_dma) { ++ ret = readl_poll_timeout(master->regs + NPCM_I3C_MSTATUS, reg, ++ NPCM_I3C_MSTATUS_COMPLETE(reg), 0, 1000); ++ if (ret) ++ goto emit_stop; ++ ++ /* If use_dma, COMPLETE bit is cleared in the isr */ ++ writel(NPCM_I3C_MINT_COMPLETE, master->regs + NPCM_I3C_MSTATUS); ++ } ++ ++ ++ if (!continued && !use_dma) { ++ npcm_i3c_master_set_sda_skew(master, 0); ++ npcm_i3c_master_emit_stop(master); ++ } ++ ++ if (!use_dma) ++ local_irq_enable(); ++ else ++ npcm_i3c_master_dma_unlock(); ++ ++ return 0; ++ ++emit_stop: ++ if (use_dma) ++ npcm_i3c_master_stop_dma(master); ++ ++ if (bus_locked) ++ spin_unlock_irqrestore(&master->req_lock, flags); ++ ++ spin_lock_irqsave(&master->req_lock, flags); ++ ++ npcm_i3c_master_set_sda_skew(master, 0); ++ ++ reg = readl(master->regs + NPCM_I3C_MSTATUS); ++ npcm_i3c_master_emit_stop(master); ++ npcm_i3c_master_clear_merrwarn(master); ++ npcm_i3c_master_flush_fifo(master); ++ spin_unlock_irqrestore(&master->req_lock, flags); ++ ++ if (!use_dma) ++ local_irq_enable(); ++ else ++ npcm_i3c_master_dma_unlock(); ++ ++ return ret; ++} ++ ++static struct npcm_i3c_xfer * ++npcm_i3c_master_alloc_xfer(struct npcm_i3c_master *master, unsigned int ncmds) ++{ ++ struct npcm_i3c_xfer *xfer; ++ ++ xfer = kzalloc(struct_size(xfer, cmds, ncmds), GFP_KERNEL); ++ if (!xfer) ++ return NULL; ++ ++ INIT_LIST_HEAD(&xfer->node); ++ xfer->ncmds = ncmds; ++ xfer->ret = -ETIMEDOUT; ++ ++ return xfer; ++} ++ ++static void npcm_i3c_master_free_xfer(struct npcm_i3c_xfer *xfer) ++{ ++ kfree(xfer); ++} ++ ++static void npcm_i3c_master_dequeue_xfer_locked(struct npcm_i3c_master *master, ++ struct npcm_i3c_xfer *xfer) ++{ ++ if (master->xferqueue.cur == xfer) ++ master->xferqueue.cur = NULL; ++ else ++ list_del_init(&xfer->node); ++} ++ ++static void npcm_i3c_master_dequeue_xfer(struct npcm_i3c_master *master, ++ struct npcm_i3c_xfer *xfer) ++{ ++ npcm_i3c_master_dequeue_xfer_locked(master, xfer); ++} ++ ++static void npcm_i3c_master_start_xfer_locked(struct npcm_i3c_master *master) ++{ ++ struct npcm_i3c_xfer *xfer = master->xferqueue.cur; ++ unsigned long flags; ++ int ret, i; ++ ++ if (!xfer) ++ return; ++ ++ /* Prevent fifo flush while IBI isr is running */ ++ spin_lock_irqsave(&master->req_lock, flags); ++ npcm_i3c_master_clear_merrwarn(master); ++ npcm_i3c_master_flush_fifo(master); ++ spin_unlock_irqrestore(&master->req_lock, flags); ++ ++ for (i = 0; i < xfer->ncmds; i++) { ++ struct npcm_i3c_cmd *cmd = &xfer->cmds[i]; ++ ++ ret = npcm_i3c_master_xfer(master, cmd->rnw, xfer->type, ++ cmd->addr, cmd->in, cmd->out, ++ cmd->len, &cmd->read_len, ++ cmd->continued, cmd->use_dma, (i == 0)); ++ if (ret) ++ break; ++ } ++ ++ xfer->ret = ret; ++ complete(&xfer->comp); ++ ++ if (ret < 0) ++ npcm_i3c_master_dequeue_xfer_locked(master, xfer); ++ ++ xfer = list_first_entry_or_null(&master->xferqueue.list, ++ struct npcm_i3c_xfer, ++ node); ++ if (xfer) ++ list_del_init(&xfer->node); ++ ++ master->xferqueue.cur = xfer; ++ npcm_i3c_master_start_xfer_locked(master); ++} ++ ++static void npcm_i3c_master_enqueue_xfer(struct npcm_i3c_master *master, ++ struct npcm_i3c_xfer *xfer) ++{ ++ init_completion(&xfer->comp); ++ if (master->xferqueue.cur) { ++ list_add_tail(&xfer->node, &master->xferqueue.list); ++ } else { ++ master->xferqueue.cur = xfer; ++ npcm_i3c_master_start_xfer_locked(master); ++ } ++} ++ ++static bool ++npcm_i3c_master_supports_ccc_cmd(struct i3c_master_controller *master, ++ const struct i3c_ccc_cmd *cmd) ++{ ++ /* No software support for CCC commands targeting more than one slave */ ++ return (cmd->ndests == 1); ++} ++ ++static int npcm_i3c_master_send_bdcast_ccc_cmd(struct npcm_i3c_master *master, ++ struct i3c_ccc_cmd *ccc) ++{ ++ unsigned int xfer_len = ccc->dests[0].payload.len + 1; ++ struct npcm_i3c_xfer *xfer; ++ struct npcm_i3c_cmd *cmd; ++ u8 *buf; ++ int ret; ++ ++ xfer = npcm_i3c_master_alloc_xfer(master, 1); ++ if (!xfer) ++ return -ENOMEM; ++ ++ buf = kmalloc(xfer_len, GFP_KERNEL); ++ if (!buf) { ++ npcm_i3c_master_free_xfer(xfer); ++ return -ENOMEM; ++ } ++ ++ buf[0] = ccc->id; ++ memcpy(&buf[1], ccc->dests[0].payload.data, ccc->dests[0].payload.len); ++ ++ xfer->type = NPCM_I3C_MCTRL_TYPE_I3C; ++ ++ cmd = &xfer->cmds[0]; ++ cmd->addr = ccc->dests[0].addr; ++ cmd->rnw = ccc->rnw; ++ cmd->in = NULL; ++ cmd->out = buf; ++ cmd->len = xfer_len; ++ cmd->read_len = 0; ++ cmd->continued = false; ++ ++ mutex_lock(&master->lock); ++ npcm_i3c_master_enqueue_xfer(master, xfer); ++ if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000))) ++ npcm_i3c_master_dequeue_xfer(master, xfer); ++ mutex_unlock(&master->lock); ++ ++ ret = xfer->ret; ++ kfree(buf); ++ npcm_i3c_master_free_xfer(xfer); ++ ++ return ret; ++} ++ ++static int npcm_i3c_master_send_direct_ccc_cmd(struct npcm_i3c_master *master, ++ struct i3c_ccc_cmd *ccc) ++{ ++ unsigned int xfer_len = ccc->dests[0].payload.len; ++ unsigned int read_len = ccc->rnw ? xfer_len : 0; ++ struct npcm_i3c_xfer *xfer; ++ struct npcm_i3c_cmd *cmd; ++ int ret; ++ ++ xfer = npcm_i3c_master_alloc_xfer(master, 2); ++ if (!xfer) ++ return -ENOMEM; ++ ++ xfer->type = NPCM_I3C_MCTRL_TYPE_I3C; ++ ++ /* Broadcasted message */ ++ cmd = &xfer->cmds[0]; ++ cmd->addr = I3C_BROADCAST_ADDR; ++ cmd->rnw = 0; ++ cmd->in = NULL; ++ cmd->out = &ccc->id; ++ cmd->len = 1; ++ cmd->read_len = 0; ++ cmd->continued = true; ++ ++ /* Directed message */ ++ cmd = &xfer->cmds[1]; ++ cmd->addr = ccc->dests[0].addr; ++ cmd->rnw = ccc->rnw; ++ cmd->in = ccc->rnw ? ccc->dests[0].payload.data : NULL; ++ cmd->out = ccc->rnw ? NULL : ccc->dests[0].payload.data, ++ cmd->len = xfer_len; ++ cmd->read_len = read_len; ++ cmd->continued = false; ++ ++ mutex_lock(&master->lock); ++ npcm_i3c_master_enqueue_xfer(master, xfer); ++ if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000))) ++ npcm_i3c_master_dequeue_xfer(master, xfer); ++ mutex_unlock(&master->lock); ++ ++ if (cmd->read_len != xfer_len) ++ ccc->dests[0].payload.len = cmd->read_len; ++ ++ ret = xfer->ret; ++ npcm_i3c_master_free_xfer(xfer); ++ ++ return ret; ++} ++ ++static int npcm_i3c_master_send_ccc_cmd(struct i3c_master_controller *m, ++ struct i3c_ccc_cmd *cmd) ++{ ++ struct npcm_i3c_master *master = to_npcm_i3c_master(m); ++ bool broadcast = cmd->id < 0x80; ++ int ret; ++ ++ if (broadcast) ++ ret = npcm_i3c_master_send_bdcast_ccc_cmd(master, cmd); ++ else ++ ret = npcm_i3c_master_send_direct_ccc_cmd(master, cmd); ++ ++ if (ret) { ++ dev_dbg(master->dev, "send ccc 0x%02x %s, ret = %d\n", ++ cmd->id, broadcast ? "(broadcast)" : "", ret); ++ cmd->err = I3C_ERROR_M2; ++ } ++ ++ return ret; ++} ++ ++static int npcm_i3c_master_priv_xfers(struct i3c_dev_desc *dev, ++ struct i3c_priv_xfer *xfers, ++ int nxfers) ++{ ++ struct i3c_master_controller *m = i3c_dev_get_master(dev); ++ struct npcm_i3c_master *master = to_npcm_i3c_master(m); ++ struct npcm_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); ++ struct npcm_i3c_xfer *xfer; ++ int ret, i; ++ ++ xfer = npcm_i3c_master_alloc_xfer(master, nxfers); ++ if (!xfer) ++ return -ENOMEM; ++ ++ xfer->type = NPCM_I3C_MCTRL_TYPE_I3C; ++ ++ for (i = 0; i < nxfers; i++) { ++ struct npcm_i3c_cmd *cmd = &xfer->cmds[i]; ++ ++ cmd->addr = master->addrs[data->index]; ++ cmd->rnw = xfers[i].rnw; ++ cmd->in = xfers[i].rnw ? xfers[i].data.in : NULL; ++ cmd->out = xfers[i].rnw ? NULL : xfers[i].data.out; ++ cmd->len = xfers[i].len; ++ cmd->read_len = xfers[i].rnw ? xfers[i].len : 0; ++ cmd->continued = (i + 1) < nxfers; ++ if (master->use_dma && xfers[i].len > 1) ++ cmd->use_dma = true; ++ } ++ ++ mutex_lock(&master->lock); ++ npcm_i3c_master_enqueue_xfer(master, xfer); ++ if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000))) ++ npcm_i3c_master_dequeue_xfer(master, xfer); ++ mutex_unlock(&master->lock); ++ ++ for (i = 0; i < nxfers; i++) { ++ struct npcm_i3c_cmd *cmd = &xfer->cmds[i]; ++ ++ if (xfers[i].rnw) ++ xfers[i].len = cmd->read_len; ++ } ++ ret = xfer->ret; ++ npcm_i3c_master_free_xfer(xfer); ++ ++ return ret; ++} ++ ++static int npcm_i3c_master_i2c_xfers(struct i2c_dev_desc *dev, ++ const struct i2c_msg *xfers, ++ int nxfers) ++{ ++ struct i3c_master_controller *m = i2c_dev_get_master(dev); ++ struct npcm_i3c_master *master = to_npcm_i3c_master(m); ++ struct npcm_i3c_i2c_dev_data *data = i2c_dev_get_master_data(dev); ++ struct npcm_i3c_xfer *xfer; ++ int ret, i; ++ ++ xfer = npcm_i3c_master_alloc_xfer(master, nxfers); ++ if (!xfer) ++ return -ENOMEM; ++ ++ xfer->type = NPCM_I3C_MCTRL_TYPE_I2C; ++ ++ for (i = 0; i < nxfers; i++) { ++ struct npcm_i3c_cmd *cmd = &xfer->cmds[i]; ++ ++ cmd->addr = master->addrs[data->index]; ++ cmd->rnw = xfers[i].flags & I2C_M_RD; ++ cmd->in = cmd->rnw ? xfers[i].buf : NULL; ++ cmd->out = cmd->rnw ? NULL : xfers[i].buf; ++ cmd->len = xfers[i].len; ++ cmd->read_len = cmd->rnw ? xfers[i].len : 0; ++ cmd->continued = (i + 1 < nxfers); ++ } ++ ++ mutex_lock(&master->lock); ++ npcm_i3c_master_enqueue_xfer(master, xfer); ++ if (!wait_for_completion_timeout(&xfer->comp, msecs_to_jiffies(1000))) ++ npcm_i3c_master_dequeue_xfer(master, xfer); ++ mutex_unlock(&master->lock); ++ ++ ret = xfer->ret; ++ npcm_i3c_master_free_xfer(xfer); ++ ++ return ret; ++} ++ ++static int npcm_i3c_master_request_ibi(struct i3c_dev_desc *dev, ++ const struct i3c_ibi_setup *req) ++{ ++ struct i3c_master_controller *m = i3c_dev_get_master(dev); ++ struct npcm_i3c_master *master = to_npcm_i3c_master(m); ++ struct npcm_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); ++ unsigned long flags; ++ unsigned int i; ++ struct i3c_ibi_setup ibi_req; ++ ++ if (dev->ibi->max_payload_len > NPCM_I3C_MAX_IBI_PAYLOAD_SIZE) { ++ dev_err(master->dev, "IBI max payload %d should be < %d\n", ++ dev->ibi->max_payload_len, NPCM_I3C_MAX_IBI_PAYLOAD_SIZE + 1); ++ return -ERANGE; ++ } ++ ++ memcpy(&ibi_req, req, sizeof(struct i3c_ibi_setup)); ++ ibi_req.max_payload_len = NPCM_I3C_MAX_IBI_PAYLOAD_SIZE; ++ data->ibi_pool = i3c_generic_ibi_alloc_pool(dev, &ibi_req); ++ if (IS_ERR(data->ibi_pool)) ++ return PTR_ERR(data->ibi_pool); ++ ++ spin_lock_irqsave(&master->ibi.lock, flags); ++ for (i = 0; i < master->ibi.num_slots; i++) { ++ if (!master->ibi.slots[i]) { ++ data->ibi = i; ++ master->ibi.slots[i] = dev; ++ break; ++ } ++ } ++ spin_unlock_irqrestore(&master->ibi.lock, flags); ++ ++ if (i < master->ibi.num_slots) ++ return 0; ++ ++ i3c_generic_ibi_free_pool(data->ibi_pool); ++ data->ibi_pool = NULL; ++ ++ return -ENOSPC; ++} ++ ++static void npcm_i3c_master_free_ibi(struct i3c_dev_desc *dev) ++{ ++ struct i3c_master_controller *m = i3c_dev_get_master(dev); ++ struct npcm_i3c_master *master = to_npcm_i3c_master(m); ++ struct npcm_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&master->ibi.lock, flags); ++ master->ibi.slots[data->ibi] = NULL; ++ data->ibi = -1; ++ spin_unlock_irqrestore(&master->ibi.lock, flags); ++ ++ i3c_generic_ibi_free_pool(data->ibi_pool); ++} ++ ++static int npcm_i3c_master_enable_ibi(struct i3c_dev_desc *dev) ++{ ++ struct i3c_master_controller *m = i3c_dev_get_master(dev); ++ struct npcm_i3c_master *master = to_npcm_i3c_master(m); ++ ++ /* Clear the interrupt status */ ++ writel(NPCM_I3C_MINT_SLVSTART, master->regs + NPCM_I3C_MSTATUS); ++ npcm_i3c_master_enable_interrupts(master, NPCM_I3C_MINT_SLVSTART); ++ ++ return i3c_master_enec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR); ++} ++ ++static int npcm_i3c_master_disable_ibi(struct i3c_dev_desc *dev) ++{ ++ struct i3c_master_controller *m = i3c_dev_get_master(dev); ++ struct npcm_i3c_master *master = to_npcm_i3c_master(m); ++ int ret; ++ ++ writel(NPCM_I3C_MINT_SLVSTART, master->regs + NPCM_I3C_MINTCLR); ++ ++ ret = i3c_master_disec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR); ++ ++ return ret; ++} ++ ++static void npcm_i3c_master_recycle_ibi_slot(struct i3c_dev_desc *dev, ++ struct i3c_ibi_slot *slot) ++{ ++ struct npcm_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev); ++ ++ i3c_generic_ibi_recycle_slot(data->ibi_pool, slot); ++} ++ ++static const struct i3c_master_controller_ops npcm_i3c_master_ops = { ++ .bus_init = npcm_i3c_master_bus_init, ++ .bus_cleanup = npcm_i3c_master_bus_cleanup, ++ .attach_i3c_dev = npcm_i3c_master_attach_i3c_dev, ++ .detach_i3c_dev = npcm_i3c_master_detach_i3c_dev, ++ .reattach_i3c_dev = npcm_i3c_master_reattach_i3c_dev, ++ .attach_i2c_dev = npcm_i3c_master_attach_i2c_dev, ++ .detach_i2c_dev = npcm_i3c_master_detach_i2c_dev, ++ .do_daa = npcm_i3c_master_do_daa, ++ .supports_ccc_cmd = npcm_i3c_master_supports_ccc_cmd, ++ .send_ccc_cmd = npcm_i3c_master_send_ccc_cmd, ++ .priv_xfers = npcm_i3c_master_priv_xfers, ++ .i2c_xfers = npcm_i3c_master_i2c_xfers, ++ .request_ibi = npcm_i3c_master_request_ibi, ++ .free_ibi = npcm_i3c_master_free_ibi, ++ .recycle_ibi_slot = npcm_i3c_master_recycle_ibi_slot, ++ .enable_ibi = npcm_i3c_master_enable_ibi, ++ .disable_ibi = npcm_i3c_master_disable_ibi, ++}; ++ ++static int npcm_i3c_master_prepare_clks(struct npcm_i3c_master *master) ++{ ++ int ret = 0; ++ ++ ret = clk_prepare_enable(master->pclk); ++ if (ret) ++ return ret; ++ ++ ret = clk_prepare_enable(master->fclk); ++ if (ret) { ++ clk_disable_unprepare(master->pclk); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void npcm_i3c_master_unprepare_clks(struct npcm_i3c_master *master) ++{ ++ clk_disable_unprepare(master->pclk); ++ clk_disable_unprepare(master->fclk); ++} ++ ++static struct dentry *npcm_i3c_debugfs_dir; ++static int debug_show(struct seq_file *seq, void *v) ++{ ++ struct npcm_i3c_master *master = seq->private; ++ ++ seq_printf(seq, "MSTATUS=0x%x\n", readl(master->regs + NPCM_I3C_MSTATUS)); ++ seq_printf(seq, "MERRWARN=0x%x\n", readl(master->regs + NPCM_I3C_MERRWARN)); ++ seq_printf(seq, "MCTRL=0x%x\n", readl(master->regs + NPCM_I3C_MCTRL)); ++ seq_printf(seq, "MDATACTRL=0x%x\n", readl(master->regs + NPCM_I3C_MDATACTRL)); ++ seq_printf(seq, "MCONFIG=0x%x\n", readl(master->regs + NPCM_I3C_MCONFIG)); ++ ++ return 0; ++} ++ ++DEFINE_SHOW_ATTRIBUTE(debug); ++ ++static void npcm_i3c_init_debugfs(struct platform_device *pdev, ++ struct npcm_i3c_master *master) ++{ ++ if (!npcm_i3c_debugfs_dir) { ++ npcm_i3c_debugfs_dir = debugfs_create_dir("npcm_i3c", NULL); ++ if (!npcm_i3c_debugfs_dir) ++ return; ++ } ++ ++ master->debugfs = debugfs_create_dir(dev_name(&pdev->dev), ++ npcm_i3c_debugfs_dir); ++ if (!master->debugfs) ++ return; ++ ++ debugfs_create_file("debug", 0444, master->debugfs, master, &debug_fops); ++} ++ ++static int npcm_i3c_setup_dma(struct platform_device *pdev, struct npcm_i3c_master *master) ++{ ++ struct device *dev = &pdev->dev; ++ u32 dma_conn, dma_ctl, reg_base; ++ ++ if (!of_property_read_bool(dev->of_node, "use-dma")) ++ return 0; ++ ++ master->dma_regs = devm_platform_ioremap_resource_byname(pdev, "dma"); ++ if (IS_ERR(master->dma_regs)) ++ return 0; ++ ++ master->dma_ctl_regs = devm_platform_ioremap_resource_byname(pdev, "dma_ctl"); ++ if (IS_ERR(master->dma_ctl_regs)) ++ return 0; ++ ++ /* DMA TX transfer width is 32 bits(MWDATAB width) for each byte sent to I3C bus */ ++ master->dma_tx_buf = dma_alloc_coherent(dev, MAX_DMA_COUNT * 4, ++ &master->dma_tx_addr, GFP_KERNEL); ++ if (!master->dma_tx_buf) ++ return -ENOMEM; ++ ++ master->dma_rx_buf = dma_alloc_coherent(dev, MAX_DMA_COUNT, ++ &master->dma_rx_addr, GFP_KERNEL); ++ if (!master->dma_rx_buf) { ++ dma_free_coherent(master->dev, MAX_DMA_COUNT * 4, master->dma_tx_buf, ++ master->dma_tx_addr); ++ return -ENOMEM; ++ } ++ ++ /* ++ * Set DMA channel connectivity ++ * channel 0: I3C TX, channel 1: I3C RX ++ */ ++ of_property_read_u32_index(dev->of_node, "reg", 0, ®_base); ++ dma_conn = NPCM_GDMA_MUX(reg_base); ++ dma_ctl = GDMA_CH0_EN | GDMA_CH1_EN | (dma_conn + 1) << 16 | dma_conn; ++ writel(dma_ctl, master->dma_ctl_regs); ++ master->use_dma = true; ++ dev_info(dev, "Using DMA (req_sel %d)\n", dma_conn); ++ ++ /* ++ * Setup GDMA Channel for TX (Memory to I3C FIFO) ++ */ ++ writel(master->dma_tx_addr, master->dma_regs + NPCM_GDMA_SRCB(DMA_CH_TX)); ++ writel(reg_base + NPCM_I3C_MWDATAB, master->dma_regs + ++ NPCM_GDMA_DSTB(DMA_CH_TX)); ++ /* ++ * Setup GDMA Channel for RX (I3C FIFO to Memory) ++ */ ++ writel(reg_base + NPCM_I3C_MRDATAB, master->dma_regs + ++ NPCM_GDMA_SRCB(DMA_CH_RX)); ++ writel(master->dma_rx_addr, master->dma_regs + NPCM_GDMA_DSTB(DMA_CH_RX)); ++ ++ return 0; ++} ++ ++static int npcm_i3c_master_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct npcm_i3c_master *master; ++ struct reset_control *reset; ++ u32 val; ++ int ret; ++ ++ master = devm_kzalloc(dev, sizeof(*master), GFP_KERNEL); ++ if (!master) ++ return -ENOMEM; ++ ++ master->regs = devm_platform_ioremap_resource(pdev, 0); ++ if (IS_ERR(master->regs)) ++ return PTR_ERR(master->regs); ++ ++ master->pclk = devm_clk_get(dev, "pclk"); ++ if (IS_ERR(master->pclk)) ++ return PTR_ERR(master->pclk); ++ ++ master->fclk = devm_clk_get(dev, "fast_clk"); ++ if (IS_ERR(master->fclk)) ++ return PTR_ERR(master->fclk); ++ ++ master->irq = platform_get_irq(pdev, 0); ++ if (master->irq < 0) ++ return master->irq; ++ ++ master->dev = dev; ++ ++ ret = npcm_i3c_master_prepare_clks(master); ++ if (ret) ++ return ret; ++ ++ reset = devm_reset_control_get(&pdev->dev, NULL); ++ if (!IS_ERR(reset)) { ++ reset_control_assert(reset); ++ udelay(5); ++ reset_control_deassert(reset); ++ } ++ INIT_WORK(&master->hj_work, npcm_i3c_master_hj_work); ++ ret = devm_request_irq(dev, master->irq, npcm_i3c_master_irq_handler, ++ IRQF_NO_SUSPEND, "npcm-i3c-irq", master); ++ if (ret) ++ goto err_disable_clks; ++ ++ master->free_slots = GENMASK(NPCM_I3C_MAX_DEVS - 1, 0); ++ ++ mutex_init(&master->lock); ++ INIT_LIST_HEAD(&master->xferqueue.list); ++ ++ spin_lock_init(&master->req_lock); ++ spin_lock_init(&master->ibi.lock); ++ master->ibi.num_slots = NPCM_I3C_MAX_DEVS; ++ master->ibi.slots = devm_kcalloc(&pdev->dev, master->ibi.num_slots, ++ sizeof(*master->ibi.slots), ++ GFP_KERNEL); ++ if (!master->ibi.slots) { ++ ret = -ENOMEM; ++ goto err_disable_clks; ++ } ++ ++ platform_set_drvdata(pdev, master); ++ ++ npcm_i3c_master_reset(master); ++ ++ if (of_property_read_bool(dev->of_node, "enable-hj")) ++ master->en_hj = true; ++ if (!of_property_read_u32(dev->of_node, "i3c-pp-scl-hi-period-ns", &val)) ++ master->scl_timing.i3c_pp_hi = val; ++ ++ if (!of_property_read_u32(dev->of_node, "i3c-pp-scl-lo-period-ns", &val)) ++ master->scl_timing.i3c_pp_lo = val; ++ ++ if (!of_property_read_u32(dev->of_node, "i3c-pp-sda-rd-skew", &val)) ++ master->scl_timing.i3c_pp_sda_rd_skew = val; ++ ++ if (!of_property_read_u32(dev->of_node, "i3c-pp-sda-wr-skew", &val)) ++ master->scl_timing.i3c_pp_sda_wr_skew = val; ++ ++ if (!of_property_read_u32(dev->of_node, "i3c-od-scl-hi-period-ns", &val)) ++ master->scl_timing.i3c_od_hi = val; ++ ++ if (!of_property_read_u32(dev->of_node, "i3c-od-scl-lo-period-ns", &val)) ++ master->scl_timing.i3c_od_lo = val; ++ ++ npcm_i3c_master_clear_merrwarn(master); ++ npcm_i3c_master_flush_fifo(master); ++ ++ npcm_i3c_setup_dma(pdev, master); ++ npcm_i3c_init_debugfs(pdev, master); ++ ++ /* Register the master */ ++ ret = i3c_master_register(&master->base, &pdev->dev, ++ &npcm_i3c_master_ops, false); ++ if (ret) ++ goto err_disable_clks; ++ ++ if (master->en_hj) { ++ dev_info(master->dev, "enable hot-join\n"); ++ npcm_i3c_master_enable_interrupts(master, NPCM_I3C_MINT_SLVSTART); ++ } ++ return 0; ++ ++ debugfs_remove_recursive(master->debugfs); ++ ++err_disable_clks: ++ npcm_i3c_master_unprepare_clks(master); ++ ++ return ret; ++} ++ ++static int npcm_i3c_master_remove(struct platform_device *pdev) ++{ ++ struct npcm_i3c_master *master = platform_get_drvdata(pdev); ++ ++ /* Avoid ibi events during driver unbinding */ ++ writel(NPCM_I3C_MINT_SLVSTART, master->regs + NPCM_I3C_MINTCLR); ++ ++ debugfs_remove_recursive(master->debugfs); ++ ++ i3c_master_unregister(&master->base); ++ ++ if (master->use_dma) { ++ dma_free_coherent(master->dev, MAX_DMA_COUNT * 4, master->dma_tx_buf, ++ master->dma_tx_addr); ++ dma_free_coherent(master->dev, MAX_DMA_COUNT, master->dma_rx_buf, ++ master->dma_rx_addr); ++ } ++ return 0; ++} ++ ++static const struct of_device_id npcm_i3c_master_of_match_tbl[] = { ++ { .compatible = "nuvoton,npcm845-i3c" }, ++ { /* sentinel */ }, ++}; ++MODULE_DEVICE_TABLE(of, npcm_i3c_master_of_match_tbl); ++ ++static struct platform_driver npcm_i3c_master = { ++ .probe = npcm_i3c_master_probe, ++ .remove = npcm_i3c_master_remove, ++ .driver = { ++ .name = "npcm845-i3c-master", ++ .of_match_table = npcm_i3c_master_of_match_tbl, ++ }, ++}; ++module_platform_driver(npcm_i3c_master); ++ ++MODULE_AUTHOR("Stanley Chu "); ++MODULE_AUTHOR("James Chiang "); ++MODULE_DESCRIPTION("Nuvoton NPCM845 I3C master driver"); ++MODULE_LICENSE("GPL"); +-- +2.34.1 + diff --git a/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1036-dt-bindings-i3c-Add-NPCM845-i3c-controller.patch b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1036-dt-bindings-i3c-Add-NPCM845-i3c-controller.patch new file mode 100644 index 00000000000..6e55c0a55fc --- /dev/null +++ b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1036-dt-bindings-i3c-Add-NPCM845-i3c-controller.patch @@ -0,0 +1,144 @@ +From 35023f72207bcd617b8b7b654d7b9d38e90da25c Mon Sep 17 00:00:00 2001 +From: James Chiang +Date: Fri, 12 Jul 2024 10:59:43 +0800 +Subject: [PATCH 1/2] dt-bindings: i3c: Add NPCM845 i3c controller + +Add a devicetree binding for the npcm845 i3c controller hardware. + +We will contribute this patch to torvalds upstream soon. + +Signed-off-by: Stanley Chu +Signed-off-by: James Chiang +--- + .../bindings/i3c/nuvoton,i3c-master.yaml | 119 ++++++++++++++++++ + 1 file changed, 119 insertions(+) + create mode 100644 Documentation/devicetree/bindings/i3c/nuvoton,i3c-master.yaml + +diff --git a/Documentation/devicetree/bindings/i3c/nuvoton,i3c-master.yaml b/Documentation/devicetree/bindings/i3c/nuvoton,i3c-master.yaml +new file mode 100644 +index 000000000000..f5ddd729e37c +--- /dev/null ++++ b/Documentation/devicetree/bindings/i3c/nuvoton,i3c-master.yaml +@@ -0,0 +1,119 @@ ++# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/i3c/nuvoton,i3c-master.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Nuvoton NPCM845 I3C master ++ ++maintainers: ++ - Stanley Chu ++ - James Chiang ++ ++allOf: ++ - $ref: "i3c.yaml#" ++ ++properties: ++ compatible: ++ const: nuvoton,npcm845-i3c ++ ++ reg: ++ maxItems: 1 ++ ++ interrupts: ++ maxItems: 1 ++ ++ clocks: ++ items: ++ - description: system clock ++ - description: bus clock ++ ++ clock-names: ++ items: ++ - const: pclk ++ - const: fast_clk ++ ++ resets: ++ maxItems: 1 ++ ++ i3c-pp-scl-hi-period-ns: ++ maxItems: 1 ++ minimum: 40 ++ maximum: 160 ++ description: | ++ If need to configure SCL with required duty cycle, specify the clock high/low period directly. ++ i3c-pp-scl-hi-perios-ns specifies the high period ns of the SCL clock cycle in push pull mode ++ When i3c-pp-scl-hi-period-ns and i3c-pp-scl-lo-period-ns are specified, the i3c pp frequency is ++ decided by these two properties. ++ ++ i3c-pp-scl-lo-period-ns: ++ maxItems: 1 ++ minimum: 40 ++ maximum: 310 ++ description: | ++ The low period ns of the SCL clock cycle in push pull mode. i3c-pp-scl-lo-period-ns should not ++ be less than i3c-pp-scl-hi-period-ns and the maximal value is i3c-pp-scl-hi-period-ns + 150. ++ ++ i3c-pp-sda-rd-skew: ++ maxItems: 1 ++ minimum: 1 ++ maximum: 7 ++ description: | ++ The number of MCLK clock periods to delay the SDA transition from the SCL clock edge at push ++ pull operation when transfers i3c private read. ++ ++ i3c-pp-sda-wr-skew: ++ maxItems: 1 ++ minimum: 1 ++ maximum: 7 ++ description: | ++ The number of MCLK clock periods to delay the SDA transition from the SCL clock edge at push ++ pull operation when transfers i3c private write. ++ ++ i3c-od-scl-hi-period-ns: ++ maxItems: 1 ++ description: | ++ The i3c open drain frequency is 1MHz by default. ++ If need to use different frequency, specify the clock high/low period directly. ++ i3c-od-scl-hi-perios-ns specifies the high period ns of the SCL clock cycle in open drain mode. ++ When i3c-od-scl-hi-period-ns and i3c-od-scl-lo-period-ns are specified, the i3c od frequency is ++ decided by these two properties. ++ i3c-od-scl-hi-period-ns should be equal to i3c-pp-scl-hi-period-ns or i3c-od-scl-lo-period-ns. ++ ++ i3c-od-scl-lo-period-ns: ++ maxItems: 1 ++ minimum: 200 ++ description: | ++ The low period ns of the SCL clock cycle in open drain mode. i3c-od-scl-lo-period-ns should be ++ multiple of i3c-pp-scl-hi-period-ns. ++ ++ enable-hj: ++ type: boolean ++ description: | ++ Enable SLVSTART interrupt for receiving hot-join request. ++ ++ use-dma: ++ type: boolean ++ description: | ++ Enable the i3c private transfers using DMA. ++ ++required: ++ - compatible ++ - reg ++ - interrupts ++ - clock-names ++ - clocks ++ ++additionalProperties: true ++ ++examples: ++ - | ++ i3c-master@a0000000 { ++ compatible = "nuvoton,npcm845-i3c"; ++ clocks = <&clk NPCM8XX_CLK_AHB>, <&clk NPCM8XX_CLK_RCP>; ++ clock-names = "pclk", "fast_clk"; ++ interrupts = ; ++ reg = <0xfff10000 0x1000>; ++ #address-cells = <3>; ++ #size-cells = <0>; ++ }; +-- +2.34.1 + diff --git a/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1040-driver-watchdog-npcm-add-a-support-to-get-reset-casu.patch b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1040-driver-watchdog-npcm-add-a-support-to-get-reset-casu.patch new file mode 100644 index 00000000000..5808ea7d4db --- /dev/null +++ b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1040-driver-watchdog-npcm-add-a-support-to-get-reset-casu.patch @@ -0,0 +1,196 @@ +From 63a5ffe3f086b48095be69e16f33b47377bb4adb Mon Sep 17 00:00:00 2001 +From: Joseph Liu +Date: Mon, 19 Aug 2024 11:17:03 +0800 +Subject: [PATCH] driver: watchdog: npcm: add a support to get reset casue + +Signed-off-by: Joseph Liu +--- + drivers/watchdog/npcm_wdt.c | 133 +++++++++++++++++++++++++++++++++++- + 1 file changed, 132 insertions(+), 1 deletion(-) + +diff --git a/drivers/watchdog/npcm_wdt.c b/drivers/watchdog/npcm_wdt.c +index a5dd1c230..587a51541 100644 +--- a/drivers/watchdog/npcm_wdt.c ++++ b/drivers/watchdog/npcm_wdt.c +@@ -12,7 +12,25 @@ + #include + #include + #include +- ++#include ++#include ++ ++/* NPCM7xx GCR module */ ++#define NPCM7XX_RESSR_OFFSET 0x6C ++#define NPCM7XX_INTCR2_OFFSET 0x60 ++ ++#define NPCM7XX_PORST BIT(31) ++#define NPCM7XX_CORST BIT(30) ++#define NPCM7XX_WD0RST BIT(29) ++#define NPCM7XX_WD1RST BIT(24) ++#define NPCM7XX_WD2RST BIT(23) ++#define NPCM7XX_SWR1RST BIT(28) ++#define NPCM7XX_SWR2RST BIT(27) ++#define NPCM7XX_SWR3RST BIT(26) ++#define NPCM7XX_SWR4RST BIT(25) ++#define NPCM8XX_RST (GENMASK(31, 23) | GENMASK(15, 12)) ++ ++ /* WD register */ + #define NPCM_WTCR 0x1C + + #define NPCM_WTCLK (BIT(10) | BIT(11)) /* Clock divider */ +@@ -45,6 +63,9 @@ struct npcm_wdt { + struct watchdog_device wdd; + void __iomem *reg; + struct clk *clk; ++ u32 card_reset; ++ u32 ext1_reset; ++ u32 ext2_reset; + }; + + static inline struct npcm_wdt *to_npcm_wdt(struct watchdog_device *wdd) +@@ -188,10 +209,79 @@ static const struct watchdog_ops npcm_wdt_ops = { + .restart = npcm_wdt_restart, + }; + ++static void npcm_get_reset_status(struct npcm_wdt *wdt, struct device *dev) ++{ ++ struct regmap *gcr_regmap; ++ u32 rstval, ressrval; ++ ++ gcr_regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon"); ++ if (IS_ERR(gcr_regmap)) { ++ dev_warn(dev, "Failed to find gcr syscon, WD reset status not supported\n"); ++ return; ++ } ++ ++ /* In Poleg, the INTCR2 indicate only power reset */ ++ regmap_read(gcr_regmap, NPCM7XX_INTCR2_OFFSET, &rstval); ++ if (of_device_is_compatible(dev->of_node, "nuvoton,npcm750-wdt")) { ++ if ((rstval & NPCM7XX_PORST) == 0) { ++ rstval = NPCM7XX_PORST; ++ /* Clear power reset indication */ ++ regmap_write(gcr_regmap, NPCM7XX_INTCR2_OFFSET, ++ rstval | NPCM7XX_PORST); ++ } else { ++ rstval = 0; ++ } ++ regmap_read(gcr_regmap, NPCM7XX_RESSR_OFFSET, &ressrval); ++ rstval |= ressrval; ++ /* After reading the RESSR Clear reset status */ ++ regmap_write(gcr_regmap, NPCM7XX_RESSR_OFFSET, ressrval); ++ } ++ ++ /* In Arbel, after reading the INTCR2 Clear reset status */ ++ if (of_device_is_compatible(dev->of_node, "nuvoton,npcm845-wdt")) ++ regmap_write(gcr_regmap, NPCM7XX_INTCR2_OFFSET, ++ rstval & ~NPCM8XX_RST); ++ ++ if (rstval & wdt->card_reset) ++ wdt->wdd.bootstatus |= WDIOF_CARDRESET; ++ if (rstval & wdt->ext1_reset) ++ wdt->wdd.bootstatus |= WDIOF_EXTERN1; ++ if (rstval & wdt->ext2_reset) ++ wdt->wdd.bootstatus |= WDIOF_EXTERN2; ++} ++ ++static u32 npcm_wdt_reset_type(const char *reset_type) ++{ ++ if (!strcmp(reset_type, "porst")) ++ return NPCM7XX_PORST; ++ else if (!strcmp(reset_type, "corst")) ++ return NPCM7XX_CORST; ++ else if (!strcmp(reset_type, "wd0")) ++ return NPCM7XX_WD0RST; ++ else if (!strcmp(reset_type, "wd1")) ++ return NPCM7XX_WD1RST; ++ else if (!strcmp(reset_type, "wd2")) ++ return NPCM7XX_WD2RST; ++ else if (!strcmp(reset_type, "sw1")) ++ return NPCM7XX_SWR1RST; ++ else if (!strcmp(reset_type, "sw2")) ++ return NPCM7XX_SWR2RST; ++ else if (!strcmp(reset_type, "sw3")) ++ return NPCM7XX_SWR3RST; ++ else if (!strcmp(reset_type, "sw4")) ++ return NPCM7XX_SWR4RST; ++ ++ return 0; ++} ++ + static int npcm_wdt_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; ++ const char *card_reset_type; ++ const char *ext1_reset_type; ++ const char *ext2_reset_type; + struct npcm_wdt *wdt; ++ u32 priority; + int irq; + int ret; + +@@ -211,6 +301,45 @@ static int npcm_wdt_probe(struct platform_device *pdev) + if (irq < 0) + return irq; + ++ if (of_property_read_u32(pdev->dev.of_node, "nuvoton,restart-priority", ++ &priority)) ++ watchdog_set_restart_priority(&wdt->wdd, 128); ++ else ++ watchdog_set_restart_priority(&wdt->wdd, priority); ++ ++ ret = of_property_read_string(pdev->dev.of_node, ++ "nuvoton,card-reset-type", ++ &card_reset_type); ++ if (ret) { ++ wdt->card_reset = NPCM7XX_PORST; ++ } else { ++ wdt->card_reset = npcm_wdt_reset_type(card_reset_type); ++ if (!wdt->card_reset) ++ wdt->card_reset = NPCM7XX_PORST; ++ } ++ ++ ret = of_property_read_string(pdev->dev.of_node, ++ "nuvoton,ext1-reset-type", ++ &ext1_reset_type); ++ if (ret) { ++ wdt->ext1_reset = NPCM7XX_WD0RST; ++ } else { ++ wdt->ext1_reset = npcm_wdt_reset_type(ext1_reset_type); ++ if (!wdt->ext1_reset) ++ wdt->ext1_reset = NPCM7XX_WD0RST; ++ } ++ ++ ret = of_property_read_string(pdev->dev.of_node, ++ "nuvoton,ext2-reset-type", ++ &ext2_reset_type); ++ if (ret) { ++ wdt->ext2_reset = NPCM7XX_SWR1RST; ++ } else { ++ wdt->ext2_reset = npcm_wdt_reset_type(ext2_reset_type); ++ if (!wdt->ext2_reset) ++ wdt->ext2_reset = NPCM7XX_SWR1RST; ++ } ++ + wdt->wdd.info = &npcm_wdt_info; + wdt->wdd.ops = &npcm_wdt_ops; + wdt->wdd.min_timeout = 1; +@@ -229,6 +358,7 @@ static int npcm_wdt_probe(struct platform_device *pdev) + set_bit(WDOG_HW_RUNNING, &wdt->wdd.status); + } + ++ npcm_get_reset_status(wdt, dev); + ret = devm_request_irq(dev, irq, npcm_wdt_interrupt, 0, "watchdog", + wdt); + if (ret) +@@ -247,6 +377,7 @@ static int npcm_wdt_probe(struct platform_device *pdev) + static const struct of_device_id npcm_wdt_match[] = { + {.compatible = "nuvoton,wpcm450-wdt"}, + {.compatible = "nuvoton,npcm750-wdt"}, ++ {.compatible = "nuvoton,npcm845-wdt"}, + {}, + }; + MODULE_DEVICE_TABLE(of, npcm_wdt_match); +-- +2.34.1 + diff --git a/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1042-i3c-expose-interface-for-doing-daa-request.patch b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1042-i3c-expose-interface-for-doing-daa-request.patch new file mode 100644 index 00000000000..ea144c451de --- /dev/null +++ b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton/1042-i3c-expose-interface-for-doing-daa-request.patch @@ -0,0 +1,50 @@ +From f4965a886c1f1e331093cc85516e38fa2be52f2d Mon Sep 17 00:00:00 2001 +From: Stanley Chu +Date: Tue, 9 Apr 2024 16:17:55 +0800 +Subject: [PATCH] i3c: expose interface for doing daa request + +Allow user space to request for doing daa. + +Example: request i3c0 to do daa. +echo 1 > /sys/bus/i3c/devices/i3c-0/discover + +Signed-off-by: Stanley Chu +--- + drivers/i3c/master.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c +index 046070298a64..9279ea730abb 100644 +--- a/drivers/i3c/master.c ++++ b/drivers/i3c/master.c +@@ -638,6 +638,19 @@ static ssize_t hotjoin_show(struct device *dev, struct device_attribute *da, cha + } + + static DEVICE_ATTR_RW(hotjoin); ++static ssize_t discover_store(struct device *dev, struct device_attribute *da, ++ const char *buf, size_t count) ++{ ++ struct i3c_master_controller *master; ++ ssize_t ret = count; ++ ++ master = dev_to_i3cmaster(dev); ++ dev_dbg(&master->dev, "Request master to do DAA\n"); ++ i3c_master_do_daa(master); ++ ++ return ret; ++} ++static DEVICE_ATTR_WO(discover); + + static struct attribute *i3c_masterdev_attrs[] = { + &dev_attr_mode.attr, +@@ -650,6 +663,7 @@ static struct attribute *i3c_masterdev_attrs[] = { + &dev_attr_dynamic_address.attr, + &dev_attr_hdrcap.attr, + &dev_attr_hotjoin.attr, ++ &dev_attr_discover.attr, + NULL, + }; + ATTRIBUTE_GROUPS(i3c_masterdev); +-- +2.34.1 + diff --git a/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton_%.bbappend b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton_%.bbappend new file mode 100644 index 00000000000..a99afe2cb10 --- /dev/null +++ b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-kernel/linux/linux-nuvoton_%.bbappend @@ -0,0 +1,56 @@ +FILESEXTRAPATHS:prepend := "${THISDIR}/linux-nuvoton:${THISDIR}/../../../recipes-kernel/linux/linux-aspeed:" + +# Common driver +SRC_URI:append = " file://0501-hwmon-ina233-Add-ina233-driver.patch" +SRC_URI:append = " file://0502-Add-adm1281-driver.patch" +SRC_URI:append = " file://0513-hwmon-Driver-for-Nuvoton-NCT7363Y.patch" +SRC_URI:append = " file://0516-i3c-master-add-enable-disable-hot-join-in-sys-entry.patch" +SRC_URI:append = " file://0519-dt-bindings-i3c-hub-Add-Renesas-RG3MxxB12A1-I3C-HUB.patch" +SRC_URI:append = " file://0520-i3c-i3c-hub-Add-Renesas-RG3MxxB12A1-I3C-HUB-driver.patch" +SRC_URI:append = " file://0531-hwmon-new-driver-for-ISL28022-power-monitor.patch" + +# NPCM8XX common dts +SRC_URI:append = " file://1000-dt-bindings-clock-npcm845-Add-reference-25m-clock-pr.patch" +SRC_URI:append = " file://1001-arm64-dts-modify-clock-property-in-modules-node.patch" +SRC_URI:append = " file://1002-arm64-dts-npmc8xx-move-the-clk-handler-node-to-the-r.patch" +SRC_URI:append = " file://1003-arm64-dts-nuvoton-npcm8xx-add-pin-and-gpio-controller-nodes.patch" +SRC_URI:append = " file://1004-arm64-dts-nuvoton-npcm8xx-add-modules-node.patch" + +# NPCM8XX YV4 dts +SRC_URI:append = " file://1005-arm64-dts-nuvoton-add-initial-yosemitev4-device-tree.patch" + +# NPCM8XX NCSI driver +SRC_URI:append = " file://1015-net-stmmac-Add-NCSI-support-for-STMMAC.patch" + +# NPCM8XX FIU driver +SRC_URI:append = " file://1016-spi-npcm-fiu-add-dual-and-quad-write-support.patch" +SRC_URI:append = " file://1017-spi-npcm-fiu-add-delay-before-reboot-to-avoi.patch" + +# NPCM8XX PSPI driver +SRC_URI:append = " file://1018-spi-npcm-pspi-Add-full-duplex-support.patch" +SRC_URI:append = " file://1019-spi-npcm-pspi-Fix-transfer-bits-per-word-issue-389.patch" + +# NPCM8XX UDC driver +SRC_URI:append = " file://1020-usb-chipidea-udc-enforce-write-to-the-memory.patch" + +# NPCM8XX i2c driver +SRC_URI:append = " file://1021-i2c-npcm-disable-interrupt-enable-bit-before-devm_re.patch" +SRC_URI:append = " file://1022-i2c-npcm-use-i2c-frequency-table.patch" +SRC_URI:append = " file://1023-i2c-npcm-use-a-software-flag-to-indicate-a-BER-condi.patch" +SRC_URI:append = " file://1024-i2c-npcm-Modify-timeout-evaluation-mechanism.patch" +SRC_URI:append = " file://1025-i2c-npcm-Modify-the-client-address-assignment.patch" +SRC_URI:append = " file://1026-i2c-npcm7xx.c-Enable-slave-in-eob-interrupt.patch" +SRC_URI:append = " file://1027-i2c-npcm-correct-the-read-write-operation-procedure.patch" +SRC_URI:append = " file://1028-i2c-npcm-Return-EAGAIN-while-bus-is-busy.patch" + +# NPCM8XX Jtag Master driver +SRC_URI:append = " file://1030-misc-npcm8xx-jtag-master-Add-NPCM845-JTAG-master-dri.patch" + +# NPCM8XX i3c driver +SRC_URI:append = " file://1035-i3c-master-Add-Nuvoton-npcm845-i3c-master-driver.patch" +SRC_URI:append = " file://1036-dt-bindings-i3c-Add-NPCM845-i3c-controller.patch" + +# NPCM8XX WDT driver +SRC_URI:append = " file://1040-driver-watchdog-npcm-add-a-support-to-get-reset-casu.patch" + +SRC_URI:append = " file://1042-i3c-expose-interface-for-doing-daa-request.patch" diff --git a/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-phosphor/entity-manager/entity-manager_git.bbappend b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-phosphor/entity-manager/entity-manager_git.bbappend new file mode 100644 index 00000000000..c7ab83c492f --- /dev/null +++ b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-phosphor/entity-manager/entity-manager_git.bbappend @@ -0,0 +1,5 @@ +FILESEXTRAPATHS:prepend := "${THISDIR}/files:" + +SRC_URI += " \ + file://0100-configuration-yv4-set-mctp-i3c-information-for-SD-an.patch \ +" diff --git a/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-phosphor/entity-manager/files/0100-configuration-yv4-set-mctp-i3c-information-for-SD-an.patch b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-phosphor/entity-manager/files/0100-configuration-yv4-set-mctp-i3c-information-for-SD-an.patch new file mode 100644 index 00000000000..d1bbbceb28c --- /dev/null +++ b/meta-facebook/meta-yosemite4/meta-yosemite4n/recipes-phosphor/entity-manager/files/0100-configuration-yv4-set-mctp-i3c-information-for-SD-an.patch @@ -0,0 +1,127 @@ +From 82633035d07ba497bcc85230b6bced7050e762b9 Mon Sep 17 00:00:00 2001 +From: Marvin Lin +Date: Fri, 30 Aug 2024 13:38:52 +0800 +Subject: [PATCH] configuration: yv4: set mctp i3c information for SD and WF + +Set mctp i3c information for SD and WF. + +Signed-off-by: Joseph Liu +Signed-off-by: Marvin Lin +--- + configurations/yosemite4_sentineldome_t1.json | 6 +++--- + .../yosemite4_sentineldome_t1_retimer.json | 6 +++--- + configurations/yosemite4_sentineldome_t2.json | 6 +++--- + .../yosemite4_sentineldome_t2_retimer.json | 6 +++--- + configurations/yosemite4_wailuafalls.json | 18 +++++++++--------- + 5 files changed, 21 insertions(+), 21 deletions(-) + +diff --git a/configurations/yosemite4_sentineldome_t1.json b/configurations/yosemite4_sentineldome_t1.json +index 8ffdc8d..7e8640a 100644 +--- a/configurations/yosemite4_sentineldome_t1.json ++++ b/configurations/yosemite4_sentineldome_t1.json +@@ -330,9 +330,9 @@ + ] + }, + { +- "Address": ["0x20"], +- "Bus": "$bus % 16", +- "Class": "I2C", ++ "Address": ["7", "236", "128", "1", "0", "$bus % 16 * 5"], ++ "Bus": "$bus / 4 - 4", ++ "Class": "I3C", + "EndpointId": "$bus % 15 * 10", + "IANA": "0015A000", + "Name": "BIC", +diff --git a/configurations/yosemite4_sentineldome_t1_retimer.json b/configurations/yosemite4_sentineldome_t1_retimer.json +index 87407cc..846736f 100644 +--- a/configurations/yosemite4_sentineldome_t1_retimer.json ++++ b/configurations/yosemite4_sentineldome_t1_retimer.json +@@ -349,9 +349,9 @@ + ] + }, + { +- "Address": ["0x20"], +- "Bus": "$bus % 16", +- "Class": "I2C", ++ "Address": ["7", "236", "128", "1", "0", "$bus % 16 * 5"], ++ "Bus": "$bus / 4 - 4", ++ "Class": "I3C", + "EndpointId": "$bus % 15 * 10", + "IANA": "0015A000", + "Name": "BIC", +diff --git a/configurations/yosemite4_sentineldome_t2.json b/configurations/yosemite4_sentineldome_t2.json +index ef60152..9ec8cf4 100644 +--- a/configurations/yosemite4_sentineldome_t2.json ++++ b/configurations/yosemite4_sentineldome_t2.json +@@ -389,9 +389,9 @@ + ] + }, + { +- "Address": ["0x20"], +- "Bus": "$bus % 16", +- "Class": "I2C", ++ "Address": ["7", "236", "128", "1", "0", "$bus % 16 * 5"], ++ "Bus": "$bus / 4 - 4", ++ "Class": "I3C", + "EndpointId": "$bus % 15 * 10", + "IANA": "0015A000", + "Name": "BIC", +diff --git a/configurations/yosemite4_sentineldome_t2_retimer.json b/configurations/yosemite4_sentineldome_t2_retimer.json +index 9a2e061..5674fa9 100644 +--- a/configurations/yosemite4_sentineldome_t2_retimer.json ++++ b/configurations/yosemite4_sentineldome_t2_retimer.json +@@ -408,9 +408,9 @@ + ] + }, + { +- "Address": ["0x20"], +- "Bus": "$bus % 16", +- "Class": "I2C", ++ "Address": ["7", "236", "128", "1", "0", "$bus % 16 * 5"], ++ "Bus": "$bus / 4 - 4", ++ "Class": "I3C", + "EndpointId": "$bus % 15 * 10", + "IANA": "0015A000", + "Name": "BIC", +diff --git a/configurations/yosemite4_wailuafalls.json b/configurations/yosemite4_wailuafalls.json +index 3fa9dd4..0510d6f 100644 +--- a/configurations/yosemite4_wailuafalls.json ++++ b/configurations/yosemite4_wailuafalls.json +@@ -209,25 +209,25 @@ + ] + }, + { +- "Address": ["0x20"], +- "Bus": "$bus % 16", +- "Class": "I2C", ++ "Address": ["7", "236", "128", "1", "0", "$bus % 16 * 5"], ++ "Bus": "$bus / 4 - 4", ++ "Class": "I3C", + "EndpointId": "$bus % 15 * 10 + 2", + "Name": "BIC", + "Type": "MCTPEndpoint" + }, + { +- "Address": ["0x20"], +- "Bus": "$bus % 16", +- "Class": "I2C", ++ "Address": ["7", "236", "128", "1", "0", "$bus % 16 * 5"], ++ "Bus": "$bus / 4 - 4", ++ "Class": "I3C", + "EndpointId": "$bus % 15 * 10 + 4", + "Name": "CXL1", + "Type": "MCTPEndpoint" + }, + { +- "Address": ["0x20"], +- "Bus": "$bus % 16", +- "Class": "I2C", ++ "Address": ["7", "236", "128", "1", "0", "$bus % 16 * 5"], ++ "Bus": "$bus / 4 - 4", ++ "Class": "I3C", + "EndpointId": "$bus % 15 * 10 + 5", + "Name": "CXL2", + "Type": "MCTPEndpoint" +-- +2.34.1 + diff --git a/openbmc-init-build-env b/openbmc-init-build-env index 00fe9b0e9bc..f8954ca5ae1 100644 --- a/openbmc-init-build-env +++ b/openbmc-init-build-env @@ -54,6 +54,7 @@ PLAT_DISTRO_OVERRIDES=( meta-tahan:lf-master meta-waimeacanyon:lf-master meta-yosemite4:lf-master + meta-yosemite4n:lf-master # dunfell platforms (pending upgrade) meta-cmm:lf-dunfell meta-fbsp:lf-dunfell diff --git a/tools/platforms/platform_build_names b/tools/platforms/platform_build_names index 138467ce562..592a64815a4 100644 --- a/tools/platforms/platform_build_names +++ b/tools/platforms/platform_build_names @@ -40,5 +40,6 @@ "wedge400", "yamp", "yosemite", - "yosemite4" + "yosemite4", + "yosemite4n" ]