summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/sysfs-bus-fsi16
-rw-r--r--Documentation/admin-guide/kernel-parameters.txt3
-rw-r--r--Documentation/devicetree/bindings/bmc/npcm7xx-lpc-bpc.txt26
-rw-r--r--Documentation/devicetree/bindings/bmc/npcm7xx-pci-mbox.txt19
-rw-r--r--Documentation/devicetree/bindings/edac/npcm7xx-sdram-edac.txt17
-rw-r--r--Documentation/devicetree/bindings/fsi/fsi-master-aspeed.txt24
-rw-r--r--Documentation/devicetree/bindings/fsi/ibm,fsi2spi.yaml36
-rw-r--r--Documentation/devicetree/bindings/fsi/ibm,p9-occ.txt12
-rw-r--r--Documentation/devicetree/bindings/hwmon/pmbus/max31785.txt158
-rw-r--r--Documentation/devicetree/bindings/hwmon/pmbus/ti,ucd90320.yaml45
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-npcm7xx.txt29
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/aspeed,ast2xxx-scu-ic.txt23
-rw-r--r--Documentation/devicetree/bindings/mfd/intel,peci-client.yaml67
-rw-r--r--Documentation/devicetree/bindings/net/nuvoton,npcm7xx-emc.txt36
-rw-r--r--Documentation/devicetree/bindings/peci/peci-aspeed.yaml124
-rw-r--r--Documentation/devicetree/bindings/peci/peci-bus.yaml129
-rw-r--r--Documentation/devicetree/bindings/peci/peci-client.yaml54
-rw-r--r--Documentation/devicetree/bindings/peci/peci-npcm.yaml102
-rw-r--r--Documentation/devicetree/bindings/security/tpm/tpm-tis-i2c.yaml47
-rw-r--r--Documentation/devicetree/bindings/soc/aspeed/xdma.yaml103
-rw-r--r--Documentation/driver-api/ipmb.rst4
-rw-r--r--Documentation/hwmon/index.rst2
-rw-r--r--Documentation/hwmon/peci-cputemp.rst95
-rw-r--r--Documentation/hwmon/peci-dimmtemp.rst60
-rw-r--r--Documentation/hwmon/ucd9000.rst12
-rw-r--r--Documentation/ioctl/ioctl-number.rst2
-rw-r--r--MAINTAINERS29
-rw-r--r--arch/arm/boot/dts/Makefile6
-rw-r--r--arch/arm/boot/dts/aspeed-ast2500-evb.dts2
-rw-r--r--arch/arm/boot/dts/aspeed-ast2600-evb.dts161
-rw-r--r--arch/arm/boot/dts/aspeed-bmc-arm-stardragon4800-rep2.dts3
-rw-r--r--arch/arm/boot/dts/aspeed-bmc-facebook-cmm.dts66
-rw-r--r--arch/arm/boot/dts/aspeed-bmc-facebook-minipack.dts59
-rw-r--r--arch/arm/boot/dts/aspeed-bmc-facebook-tiogapass.dts3
-rw-r--r--arch/arm/boot/dts/aspeed-bmc-facebook-yamp.dts65
-rw-r--r--arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts729
-rw-r--r--arch/arm/boot/dts/aspeed-bmc-inspur-fp5280g2.dts58
-rw-r--r--arch/arm/boot/dts/aspeed-bmc-inspur-on5263m5.dts3
-rw-r--r--arch/arm/boot/dts/aspeed-bmc-intel-s2600wf.dts3
-rw-r--r--arch/arm/boot/dts/aspeed-bmc-lenovo-hr630.dts3
-rw-r--r--arch/arm/boot/dts/aspeed-bmc-lenovo-hr855xg2.dts3
-rw-r--r--arch/arm/boot/dts/aspeed-bmc-opp-lanyang.dts3
-rw-r--r--arch/arm/boot/dts/aspeed-bmc-opp-mihawk.dts469
-rw-r--r--arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts2
-rw-r--r--arch/arm/boot/dts/aspeed-bmc-opp-romulus.dts40
-rw-r--r--arch/arm/boot/dts/aspeed-bmc-opp-swift.dts3
-rw-r--r--arch/arm/boot/dts/aspeed-bmc-opp-tacoma.dts868
-rw-r--r--arch/arm/boot/dts/aspeed-bmc-opp-vesnin.dts4
-rw-r--r--arch/arm/boot/dts/aspeed-bmc-opp-witherspoon-128.dts59
-rw-r--r--arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts112
-rw-r--r--arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts42
-rw-r--r--arch/arm/boot/dts/aspeed-bmc-portwell-neptune.dts6
-rw-r--r--arch/arm/boot/dts/aspeed-g4.dtsi116
-rw-r--r--arch/arm/boot/dts/aspeed-g5.dtsi212
-rw-r--r--arch/arm/boot/dts/aspeed-g6-pinctrl.dtsi34
-rw-r--r--arch/arm/boot/dts/aspeed-g6.dtsi694
-rw-r--r--arch/arm/boot/dts/ast2500-facebook-netbmc-common.dtsi96
-rw-r--r--arch/arm/boot/dts/nuvoton-common-npcm7xx.dtsi1113
-rw-r--r--arch/arm/boot/dts/nuvoton-npcm730-gsj-gpio.dtsi477
-rw-r--r--arch/arm/boot/dts/nuvoton-npcm730-gsj.dts553
-rw-r--r--arch/arm/boot/dts/nuvoton-npcm730.dtsi57
-rw-r--r--arch/arm/boot/dts/nuvoton-npcm750-evb.dts598
-rw-r--r--arch/arm/boot/dts/nuvoton-npcm750-gpio.dtsi2021
-rw-r--r--arch/arm/boot/dts/nuvoton-npcm750-runbmc-olympus-pincfg.dtsi517
-rw-r--r--arch/arm/boot/dts/nuvoton-npcm750-runbmc-olympus.dts1197
-rw-r--r--arch/arm/boot/dts/nuvoton-npcm750.dtsi140
-rw-r--r--arch/arm/boot/dts/openbmc-flash-layout-128.dtsi32
-rw-r--r--arch/arm/configs/aspeed_g4_defconfig26
-rw-r--r--arch/arm/configs/aspeed_g5_defconfig45
-rw-r--r--arch/arm/configs/npcm7xx_defconfig127
-rw-r--r--arch/arm/mach-aspeed/Kconfig1
-rw-r--r--crypto/asymmetric_keys/asym_tpm.c12
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/char/Kconfig9
-rw-r--r--drivers/char/ipmi/bt-bmc.c1
-rw-r--r--drivers/char/ipmi/ipmb_dev_int.c60
-rw-r--r--drivers/char/ipmi/kcs_bmc_aspeed.c1
-rw-r--r--drivers/char/mem.c11
-rw-r--r--drivers/char/tpm/Kconfig12
-rw-r--r--drivers/char/tpm/Makefile1
-rw-r--r--drivers/char/tpm/tpm.h214
-rw-r--r--drivers/char/tpm/tpm2-cmd.c4
-rw-r--r--drivers/char/tpm/tpm_tis_core.c175
-rw-r--r--drivers/char/tpm/tpm_tis_core.h41
-rw-r--r--drivers/char/tpm/tpm_tis_i2c.c292
-rw-r--r--drivers/char/tpm/tpm_tis_spi.c41
-rw-r--r--drivers/clk/clk-aspeed.c27
-rw-r--r--drivers/clk/clk-ast2600.c51
-rw-r--r--drivers/clocksource/timer-fttmr010.c68
-rw-r--r--drivers/edac/Kconfig7
-rw-r--r--drivers/edac/Makefile1
-rw-r--r--drivers/edac/npcm7xx_edac.c424
-rw-r--r--drivers/fsi/Kconfig8
-rw-r--r--drivers/fsi/Makefile1
-rw-r--r--drivers/fsi/fsi-core.c36
-rw-r--r--drivers/fsi/fsi-master-aspeed.c607
-rw-r--r--drivers/fsi/fsi-master-hub.c46
-rw-r--r--drivers/fsi/fsi-master.h71
-rw-r--r--drivers/fsi/fsi-occ.c126
-rw-r--r--drivers/gpio/Kconfig8
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/gpio-aspeed-sgpio.c (renamed from drivers/gpio/sgpio-aspeed.c)0
-rw-r--r--drivers/hwmon/Kconfig28
-rw-r--r--drivers/hwmon/Makefile2
-rw-r--r--drivers/hwmon/occ/common.c65
-rw-r--r--drivers/hwmon/peci-cputemp.c472
-rw-r--r--drivers/hwmon/peci-dimmtemp.c425
-rw-r--r--drivers/hwmon/peci-hwmon.h48
-rw-r--r--drivers/hwmon/pmbus/Kconfig6
-rw-r--r--drivers/hwmon/pmbus/ibm-cffps.c138
-rw-r--r--drivers/hwmon/pmbus/max31785.c497
-rw-r--r--drivers/hwmon/pmbus/pmbus_core.c20
-rw-r--r--drivers/hwmon/pmbus/ucd9000.c39
-rw-r--r--drivers/i2c/busses/Kconfig11
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-aspeed.c4
-rw-r--r--drivers/i2c/busses/i2c-fsi.c7
-rw-r--r--drivers/i2c/busses/i2c-npcm7xx.c2485
-rw-r--r--drivers/irqchip/Makefile2
-rw-r--r--drivers/irqchip/irq-aspeed-scu-ic.c239
-rw-r--r--drivers/media/platform/aspeed-video.c43
-rw-r--r--drivers/mfd/Kconfig17
-rw-r--r--drivers/mfd/Makefile1
-rw-r--r--drivers/mfd/intel-peci-client.c148
-rw-r--r--drivers/misc/Kconfig22
-rw-r--r--drivers/misc/Makefile3
-rw-r--r--drivers/misc/mctp-lpc.c443
-rw-r--r--drivers/misc/npcm7xx-lpc-bpc.c394
-rw-r--r--drivers/misc/npcm7xx-pci-mbox.c288
-rw-r--r--drivers/mtd/spi-nor/aspeed-smc.c586
-rw-r--r--drivers/mtd/spi-nor/spi-nor.c4
-rw-r--r--drivers/net/ethernet/Kconfig1
-rw-r--r--drivers/net/ethernet/Makefile1
-rw-r--r--drivers/net/ethernet/faraday/ftgmac100.c35
-rw-r--r--drivers/net/ethernet/nuvoton/Kconfig30
-rw-r--r--drivers/net/ethernet/nuvoton/Makefile6
-rw-r--r--drivers/net/ethernet/nuvoton/npcm7xx_emc.c2091
-rw-r--r--drivers/peci/Kconfig37
-rw-r--r--drivers/peci/Makefile11
-rw-r--r--drivers/peci/busses/Kconfig34
-rw-r--r--drivers/peci/busses/Makefile7
-rw-r--r--drivers/peci/busses/peci-aspeed.c484
-rw-r--r--drivers/peci/busses/peci-npcm.c406
-rw-r--r--drivers/peci/peci-core.c2089
-rw-r--r--drivers/peci/peci-dev.c348
-rw-r--r--drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c170
-rw-r--r--drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c212
-rw-r--r--drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c394
-rw-r--r--drivers/pinctrl/aspeed/pinctrl-aspeed.c75
-rw-r--r--drivers/pinctrl/aspeed/pinctrl-aspeed.h38
-rw-r--r--drivers/pinctrl/aspeed/pinmux-aspeed.h1
-rw-r--r--drivers/reset/reset-simple.c1
-rw-r--r--drivers/soc/aspeed/Kconfig16
-rw-r--r--drivers/soc/aspeed/Makefile2
-rw-r--r--drivers/soc/aspeed/aspeed-bmc-misc.c190
-rw-r--r--drivers/soc/aspeed/aspeed-lpc-ctrl.c31
-rw-r--r--drivers/soc/aspeed/aspeed-lpc-snoop.c2
-rw-r--r--drivers/soc/aspeed/aspeed-xdma.c1221
-rw-r--r--drivers/spi/Kconfig7
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/spi-fsi.c558
-rw-r--r--drivers/usb/gadget/composite.c6
-rw-r--r--drivers/usb/gadget/udc/aspeed-vhub/Kconfig4
-rw-r--r--drivers/usb/gadget/udc/aspeed-vhub/core.c109
-rw-r--r--drivers/usb/gadget/udc/aspeed-vhub/dev.c30
-rw-r--r--drivers/usb/gadget/udc/aspeed-vhub/epn.c4
-rw-r--r--drivers/usb/gadget/udc/aspeed-vhub/hub.c26
-rw-r--r--drivers/usb/gadget/udc/aspeed-vhub/vhub.h23
-rw-r--r--include/dt-bindings/clock/aspeed-clock.h2
-rw-r--r--include/dt-bindings/clock/ast2600-clock.h4
-rw-r--r--include/dt-bindings/interrupt-controller/aspeed-scu-ic.h23
-rw-r--r--include/keys/trusted.h12
-rw-r--r--include/linux/mfd/intel-peci-client.h119
-rw-r--r--include/linux/peci.h150
-rw-r--r--include/linux/tpm.h213
-rw-r--r--include/trace/events/fsi.h6
-rw-r--r--include/trace/events/fsi_master_aspeed.h77
-rw-r--r--include/uapi/linux/aspeed-xdma.h42
-rw-r--r--include/uapi/linux/peci-ioctl.h661
-rw-r--r--security/keys/trusted.c12
181 files changed, 29709 insertions, 1212 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-fsi b/Documentation/ABI/testing/sysfs-bus-fsi
index 57c806350d6c..320697bdf41d 100644
--- a/Documentation/ABI/testing/sysfs-bus-fsi
+++ b/Documentation/ABI/testing/sysfs-bus-fsi
@@ -1,25 +1,25 @@
-What: /sys/bus/platform/devices/fsi-master/rescan
+What: /sys/bus/platform/devices/../fsi-master/fsi0/rescan
Date: May 2017
KernelVersion: 4.12
-Contact: cbostic@linux.vnet.ibm.com
+Contact: linux-fsi@lists.ozlabs.org
Description:
Initiates a FSI master scan for all connected slave devices
on its links.
-What: /sys/bus/platform/devices/fsi-master/break
+What: /sys/bus/platform/devices/../fsi-master/fsi0/break
Date: May 2017
KernelVersion: 4.12
-Contact: cbostic@linux.vnet.ibm.com
+Contact: linux-fsi@lists.ozlabs.org
Description:
Sends an FSI BREAK command on a master's communication
link to any connnected slaves. A BREAK resets connected
device's logic and preps it to receive further commands
from the master.
-What: /sys/bus/platform/devices/fsi-master/slave@00:00/term
+What: /sys/bus/platform/devices/../fsi-master/fsi0/slave@00:00/term
Date: May 2017
KernelVersion: 4.12
-Contact: cbostic@linux.vnet.ibm.com
+Contact: linux-fsi@lists.ozlabs.org
Description:
Sends an FSI terminate command from the master to its
connected slave. A terminate resets the slave's state machines
@@ -29,10 +29,10 @@ Description:
ongoing operation in case of an expired 'Master Time Out'
timer.
-What: /sys/bus/platform/devices/fsi-master/slave@00:00/raw
+What: /sys/bus/platform/devices/../fsi-master/fsi0/slave@00:00/raw
Date: May 2017
KernelVersion: 4.12
-Contact: cbostic@linux.vnet.ibm.com
+Contact: linux-fsi@lists.ozlabs.org
Description:
Provides a means of reading/writing a 32 bit value from/to a
specified FSI bus address.
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 13984b6cc322..33dc11ec660a 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -2607,6 +2607,9 @@
deep - Suspend-To-RAM or equivalent (if supported)
See Documentation/admin-guide/pm/sleep-states.rst.
+ mem.devmem= Activate the /dev/mem device
+ Format: <bool> (1/Y/y=enable, 0/N/n=disable)
+
meye.*= [HW] Set MotionEye Camera parameters
See Documentation/media/v4l-drivers/meye.rst.
diff --git a/Documentation/devicetree/bindings/bmc/npcm7xx-lpc-bpc.txt b/Documentation/devicetree/bindings/bmc/npcm7xx-lpc-bpc.txt
new file mode 100644
index 000000000000..0832c9cbea32
--- /dev/null
+++ b/Documentation/devicetree/bindings/bmc/npcm7xx-lpc-bpc.txt
@@ -0,0 +1,26 @@
+Nuvoton NPCM7xx LPC BPC interface
+
+Nuvoton BMC NPCM7xx BIOS Post Code (BPC) monitoring two
+configurable I/O addresses written by the host on the
+Low Pin Count (LPC) bus, the capure data stored in 128-word FIFO.
+
+NPCM7xx BPC supports capture double words, when using capture
+double word only I/O address 1 is monitored.
+
+Required properties for lpc_bpc node
+- compatible : "nuvoton,npcm750-lpc-bpc" for Poleg NPCM7XX.
+- reg : specifies physical base address and size of the registers.
+- interrupts : contain the LPC BPC with flags for falling edge.
+- monitor-ports : contain monitor I/O addresses, at least one monitor I/O
+ address required
+
+Optional property for lpc_bpc node
+- bpc-en-dwcapture : enable capture double words support.
+
+Example:
+ lpc_bpc: lpc-bpc@f0007040 {
+ compatible = "nuvoton,npcm7xx-lpc-bpc";
+ reg = <0xf0007040 0x14>;
+ monitor-ports = <0x80>;
+ interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+ };
diff --git a/Documentation/devicetree/bindings/bmc/npcm7xx-pci-mbox.txt b/Documentation/devicetree/bindings/bmc/npcm7xx-pci-mbox.txt
new file mode 100644
index 000000000000..e5585f38041b
--- /dev/null
+++ b/Documentation/devicetree/bindings/bmc/npcm7xx-pci-mbox.txt
@@ -0,0 +1,19 @@
+Nuvoton NPCM7xx PCI mail box interface
+
+Nuvoton BMC NPCM7xx PCI mail box, The mailbox is a high-bandwidth
+communication module between the BMC CPU and host CPU.
+
+Required properties for lpc_bpc node
+- compatible : "nuvoton,npcm750-pci-mbox" for Poleg NPCM7XX.
+- reg : specifies two address space
+ 1. physical base address and size of the registers.
+ 2. physical base address and size of the dual-ported RAM.
+- interrupts : contain the PCI mail box interrupt with flags for falling edge.
+
+Example:
+ pcimbox: pcimbox@f0848000 {
+ compatible = "nuvoton,npcm750-pci-mbox", "simple-mfd", "syscon";
+ reg = <0xf084C000 0x8
+ 0xf0848000 0x3F00>;
+ interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+ };
diff --git a/Documentation/devicetree/bindings/edac/npcm7xx-sdram-edac.txt b/Documentation/devicetree/bindings/edac/npcm7xx-sdram-edac.txt
new file mode 100644
index 000000000000..dd4dac59a5bd
--- /dev/null
+++ b/Documentation/devicetree/bindings/edac/npcm7xx-sdram-edac.txt
@@ -0,0 +1,17 @@
+Nuvoton NPCM7xx SoC EDAC device driver
+
+The Nuvoton NPCM7xx SoC supports DDR4 memory with/without ECC and the driver
+uses the EDAC framework to implement the ECC detection and corrtection.
+
+Required properties:
+- compatible: should be "nuvoton,npcm7xx-sdram-edac"
+- reg: Memory controller register set should be <0xf0824000 0x1000>
+- interrupts: should be MC interrupt #25
+
+Example:
+
+ mc: memory-controller@f0824000 {
+ compatible = "nuvoton,npcm7xx-sdram-edac";
+ reg = <0xf0824000 0x1000>;
+ interrupts = <0 25 4>;
+ };
diff --git a/Documentation/devicetree/bindings/fsi/fsi-master-aspeed.txt b/Documentation/devicetree/bindings/fsi/fsi-master-aspeed.txt
new file mode 100644
index 000000000000..b758f91914f7
--- /dev/null
+++ b/Documentation/devicetree/bindings/fsi/fsi-master-aspeed.txt
@@ -0,0 +1,24 @@
+Device-tree bindings for AST2600 FSI master
+-------------------------------------------
+
+The AST2600 contains two identical FSI masters. They share a clock and have a
+separate interrupt line and output pins.
+
+Required properties:
+ - compatible: "aspeed,ast2600-fsi-master"
+ - reg: base address and length
+ - clocks: phandle and clock number
+ - interrupts: platform dependent interrupt description
+ - pinctrl-0: phandle to pinctrl node
+ - pinctrl-names: pinctrl state
+
+Examples:
+
+ fsi-master {
+ compatible = "aspeed,ast2600-fsi-master", "fsi-master";
+ reg = <0x1e79b000 0x94>;
+ interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_fsi1_default>;
+ clocks = <&syscon ASPEED_CLK_GATE_FSICLK>;
+ };
diff --git a/Documentation/devicetree/bindings/fsi/ibm,fsi2spi.yaml b/Documentation/devicetree/bindings/fsi/ibm,fsi2spi.yaml
new file mode 100644
index 000000000000..893d81e54caa
--- /dev/null
+++ b/Documentation/devicetree/bindings/fsi/ibm,fsi2spi.yaml
@@ -0,0 +1,36 @@
+# SPDX-License-Identifier: (GPL-2.0-or-later)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/fsi/ibm,fsi2spi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: IBM FSI-attached SPI controllers
+
+maintainers:
+ - Eddie James <eajames@linux.ibm.com>
+
+description: |
+ This binding describes an FSI CFAM engine called the FSI2SPI. Therefore this
+ node will always be a child of an FSI CFAM node; see fsi.txt for details on
+ FSI slave and CFAM nodes. This FSI2SPI engine provides access to a number of
+ SPI controllers.
+
+properties:
+ compatible:
+ enum:
+ - ibm,fsi2spi
+
+ reg:
+ items:
+ - description: FSI slave address
+
+required:
+ - compatible
+ - reg
+
+examples:
+ - |
+ fsi2spi@1c00 {
+ compatible = "ibm,fsi2spi";
+ reg = <0x1c00 0x400>;
+ };
diff --git a/Documentation/devicetree/bindings/fsi/ibm,p9-occ.txt b/Documentation/devicetree/bindings/fsi/ibm,p9-occ.txt
index 99ca9862a586..e73358075a90 100644
--- a/Documentation/devicetree/bindings/fsi/ibm,p9-occ.txt
+++ b/Documentation/devicetree/bindings/fsi/ibm,p9-occ.txt
@@ -1,13 +1,13 @@
-Device-tree bindings for FSI-attached POWER9 On-Chip Controller (OCC)
----------------------------------------------------------------------
+Device-tree bindings for FSI-attached POWER9/POWER10 On-Chip Controller (OCC)
+-----------------------------------------------------------------------------
-This is the binding for the P9 On-Chip Controller accessed over FSI from a
-service processor. See fsi.txt for details on bindings for FSI slave and CFAM
+This is the binding for the P9 or P10 On-Chip Controller accessed over FSI from
+a service processor. See fsi.txt for details on bindings for FSI slave and CFAM
nodes. The OCC is not an FSI slave device itself, rather it is accessed
-through the SBE fifo.
+through the SBE FIFO.
Required properties:
- - compatible = "ibm,p9-occ"
+ - compatible = "ibm,p9-occ" or "ibm,p10-occ"
Examples:
diff --git a/Documentation/devicetree/bindings/hwmon/pmbus/max31785.txt b/Documentation/devicetree/bindings/hwmon/pmbus/max31785.txt
new file mode 100644
index 000000000000..af9578e7742c
--- /dev/null
+++ b/Documentation/devicetree/bindings/hwmon/pmbus/max31785.txt
@@ -0,0 +1,158 @@
+Bindings for the Maxim MAX31785 Intelligent Fan Controller
+==========================================================
+
+Reference:
+
+https://datasheets.maximintegrated.com/en/ds/MAX31785.pdf
+
+Required properties:
+- compatible : One of "maxim,max31785" or "maxim,max31785a"
+- reg : I2C address, one of 0x52, 0x53, 0x54, 0x55.
+- #address-cells : Must be 1
+- #size-cells : Must be 0
+- #thermal-sensor-cells : Should be 1. The device supports:
+ - One internal sensor
+ - Four external I2C digital sensors
+ - Six external thermal diodes
+
+Optional properties:
+- use-stored-presence : Do not treat the devicetree description as canon for
+ fan presence (the 'installed' bit of FAN_CONFIG_*).
+ Instead, rely on the on the default value store of
+ the device to populate it.
+
+Capabilities are configured through subnodes of the controller's node.
+
+Fans
+----
+
+Only fans with subnodes present will be considered as installed. If
+use-stored-presence is present in the parent node, then only fans that are both
+defined in the devicetree and have their installed bit set are considered
+installed.
+
+Required subnode properties:
+- compatible : Must be "pmbus-fan"
+- reg : The PMBus page the properties apply to.
+- #cooling-cells : Should be 2. See the thermal bindings at [1].
+- maxim,fan-rotor-input : The type of rotor measurement provided to the
+ controller. Must be either "tach" for tachometer
+ pulses or "lock" for a locked-rotor signal.
+- maxim,fan-lock-polarity: Required iff maxim,fan-rotor-input is "lock". Valid
+ values are "low" for active low, "high" for active
+ high.
+
+Optional subnode properties:
+- fan-mode : "rpm" or "pwm". Default value is "pwm".
+- tach-pulses : Tachometer pulses per revolution. Valid values are
+ 1, 2, 3 or 4. The default is 1.
+- cooling-min-level : Smallest cooling state accepted. See [1].
+- cooling-max-level : Largest cooling state accepted. See [1].
+- maxim,fan-no-fault-ramp: Do not ramp the fan to 100% PWM duty on detecting a
+ fan fault
+- maxim,fan-startup : The number of rotations required before taking
+ emergency action for an unresponsive fan and driving
+ it with 100% or 0% PWM duty, depending on the state
+ of maxim,fan-no-fault-ramp. Valid values are 0
+ (automatic spin-up disabled), 2, 4, or 8. Default
+ value is 0.
+- maxim,fan-health : Enable automated fan health check
+- maxim,fan-ramp : Configures how fast the device ramps the PWM duty
+ cycle from one value to another. Valid values are 0
+ to 7 inclusive, with values 0 - 2 configuring a
+ 1000ms update rate and 1 - 3% duty respective duty
+ increase, and 3 - 7 a 200ms update rate with a 1 -
+ 5% respective duty increase. Default value is 0.
+- maxim,fan-no-watchdog : Do not ramp fan to 100% PWM duty on failure to
+ update desired fan rate inside 10s. This implies
+ maxim,tmp-no-fault-ramp
+- maxim,tmp-no-fault-ramp: Do not ramp fan to 100% PWM duty on temperature
+ sensor fault detection. This implies
+ maxim,fan-no-watchdog
+- maxim,tmp-hysteresis : The temperature hysteresis used to determine
+ transitions to lower fan speed bands in the
+ temperature/fan rate lookup table. Valid values are
+ 2, 4, 6 or 8 (degrees celcius). Default value is 2.
+- maxim,fan-dual-tach : Enable dual tachometer functionality
+- maxim,fan-pwm-freq : The PWM frequency. Valid values are 30, 50, 100, 150
+ and 25000 (Hz). Default value is 30Hz.
+- maxim,fan-lookup-table : A 16-element cell array of alternating temperature
+ and rate values representing the look up table. The
+ rate units are set through the fan-mode property.
+- maxim,fan-fault-pin-mon: Ramp fans to 100% PWM duty when the FAULT pin is
+ asserted
+
+Temperature
+-----------
+
+Required subnode properties:
+- compatible : Must be "pmbus-temperature"
+- reg : The PMBus page the properties apply to.
+
+Optional subnode properties:
+- maxim,tmp-offset : Valid values are 0 - 30 (degrees celcius) inclusive.
+ Default value is 0.
+- maxim,tmp-fans : An array of phandles to fans controlled by the
+ current temperature sensor.
+
+[1] Documentation/devicetree/bindings/thermal/thermal.txt
+
+Example:
+ fan-max31785: max31785@52 {
+ reg = <0x52>;
+ compatible = "maxim,max31785";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #thermal-sensor-cells = <1>;
+
+ fan@0 {
+ compatible = "pmbus-fan";
+ reg = <0>;
+ mode = "rpm";
+ tach-pulses = <1>;
+
+ #cooling-cells = <2>;
+ cooling-min-level = <0>;
+ cooling-max-level = <9>;
+
+ maxim,fan-rotor-input = "tach";
+ maxim,fan-dual-tach;
+ };
+
+ /*
+ * Hardware controlled fan: Fan speed is controlled by a
+ * temperature sensor feeding values into the lookup table. The
+ * fan association is done in the temperature sensor node. One
+ * sensor can drive multiple fans.
+ */
+ cpu_fan: fan@1 {
+ compatible = "pmbus-fan";
+ reg = <1>;
+ mode = "rpm";
+ tach-pulses = <1>;
+
+ #cooling-cells = <2>;
+
+ maxim,fan-rotor-input = "tach";
+ maxim,tmp-hysteresis = <2>;
+ maxim,fan-lookup-table = <
+ /* Temperature RPM */
+ 0 1000
+ 10 2000
+ 20 3000
+ 30 4000
+ 40 5000
+ 50 6000
+ 60 7000
+ 70 8000
+ >;
+ };
+
+ cpu_temp: sensor@6 {
+ compatible = "pmbus-temperature";
+ reg = <6>;
+
+ maxim,tmp-offset = <0>;
+ maxim,tmp-fans = <&cpu_fan>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/hwmon/pmbus/ti,ucd90320.yaml b/Documentation/devicetree/bindings/hwmon/pmbus/ti,ucd90320.yaml
new file mode 100644
index 000000000000..5d42e1304202
--- /dev/null
+++ b/Documentation/devicetree/bindings/hwmon/pmbus/ti,ucd90320.yaml
@@ -0,0 +1,45 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+
+$id: http://devicetree.org/schemas/hwmon/pmbus/ti,ucd90320.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: UCD90320 power sequencer
+
+maintainers:
+ - Jim Wright <wrightj@linux.vnet.ibm.com>
+
+description: |
+ The UCD90320 is a 32-rail PMBus/I2C addressable power-supply sequencer and
+ monitor. The 24 integrated ADC channels (AMONx) monitor the power supply
+ voltage, current, and temperature. Of the 84 GPIO pins, 8 can be used as
+ digital monitors (DMONx), 32 to enable the power supply (ENx), 24 for
+ margining (MARx), 16 for logical GPO, and 32 GPIs for cascading, and system
+ function.
+
+ http://focus.ti.com/lit/ds/symlink/ucd90320.pdf
+
+properties:
+ compatible:
+ enum:
+ - ti,ucd90320
+
+ reg:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+
+examples:
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ucd90320@11 {
+ compatible = "ti,ucd90320";
+ reg = <0x11>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/i2c/i2c-npcm7xx.txt b/Documentation/devicetree/bindings/i2c/i2c-npcm7xx.txt
new file mode 100644
index 000000000000..d36cc20742fd
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/i2c-npcm7xx.txt
@@ -0,0 +1,29 @@
+Nuvoton NPCM7XX I2C bus
+
+The NPCM750x includes sixteen I2C bus controllers. All Controllers support
+both master and slave mode. Each controller has two 16 byte HW FIFO for TX and
+RX.
+
+Required properties:
+- compatible : must be "nuvoton,npcm750-i2c"
+- reg : Offset and length of the register set for the device.
+- interrupts : Contain the I2C interrupt with flags for falling edge.
+- clocks : phandle of I2C reference clock.
+
+Optional:
+- bus-frequency : Contain the I2C bus frequency,
+ the default I2C bus frequency is 100000.
+- pinctrl-0 : for example <&smbX_pins>, X is module number
+ (on NPCM7XX it's 0 to 15)
+- pinctrl-names : should be set to "default"
+Example:
+
+ i2c0: i2c@80000 {
+ compatible = "nuvoton,npcm750-i2c";
+ reg = <0x80000 0x1000>;
+ clocks = <&clk NPCM7XX_CLK_APB2>;
+ bus-frequency = <100000>;
+ interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&smb0_pins>;
+ };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/aspeed,ast2xxx-scu-ic.txt b/Documentation/devicetree/bindings/interrupt-controller/aspeed,ast2xxx-scu-ic.txt
new file mode 100644
index 000000000000..251ed44171db
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/aspeed,ast2xxx-scu-ic.txt
@@ -0,0 +1,23 @@
+Aspeed AST25XX and AST26XX SCU Interrupt Controller
+
+Required Properties:
+ - #interrupt-cells : must be 1
+ - compatible : must be "aspeed,ast2500-scu-ic",
+ "aspeed,ast2600-scu-ic0" or
+ "aspeed,ast2600-scu-ic1"
+ - interrupts : interrupt from the parent controller
+ - interrupt-controller : indicates that the controller receives and
+ fires new interrupts for child busses
+
+Example:
+
+ syscon@1e6e2000 {
+ ranges = <0 0x1e6e2000 0x1a8>;
+
+ scu_ic: interrupt-controller@18 {
+ #interrupt-cells = <1>;
+ compatible = "aspeed,ast2500-scu-ic";
+ interrupts = <21>;
+ interrupt-controller;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/mfd/intel,peci-client.yaml b/Documentation/devicetree/bindings/mfd/intel,peci-client.yaml
new file mode 100644
index 000000000000..7baddce0a92c
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/intel,peci-client.yaml
@@ -0,0 +1,67 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/mfd/intel,peci-client.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Intel PECI Client Device Tree Bindings
+
+maintainers:
+ - Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
+
+description: |
+ PECI (Platform Environment Control Interface) is a one-wire bus interface
+ that provides a communication channel from PECI clients in Intel processors
+ and chipset components to external monitoring or control devices. PECI is
+ designed to support the following sideband functions:
+ - Processor and DRAM thermal management
+ - Platform Manageability
+ - Processor Interface Tuning and Diagnostics
+ - Failure Analysis
+
+properties:
+ compatible:
+ const: intel,peci-client
+
+ reg:
+ description: |
+ Address of a client CPU. According to the PECI specification, client
+ addresses start from 0x30.
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/clock/ast2600-clock.h>
+ peci: bus@1e78b000 {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0x1e78b000 0x60>;
+
+ peci0: peci-bus@0 {
+ compatible = "aspeed,ast2600-peci";
+ reg = <0x0 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&syscon ASPEED_CLK_GATE_REF0CLK>;
+ resets = <&syscon ASPEED_RESET_PECI>;
+ clock-frequency = <24000000>;
+
+ peci-client@30 {
+ compatible = "intel,peci-client";
+ reg = <0x30>;
+ };
+
+ peci-client@31 {
+ compatible = "intel,peci-client";
+ reg = <0x31>;
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/net/nuvoton,npcm7xx-emc.txt b/Documentation/devicetree/bindings/net/nuvoton,npcm7xx-emc.txt
new file mode 100644
index 000000000000..4227597401f5
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/nuvoton,npcm7xx-emc.txt
@@ -0,0 +1,36 @@
+Nuvoton NPCM7XX 10/100 Ethernet MAC Controller (EMC)
+
+The NPCM750x provides two identical Ethernet MAC Controllers
+for WAN/LAN applications
+
+Required properties:
+- device_type : Should be "network"
+- compatible : "nuvoton,npcm750-emc" for Poleg NPCM750.
+- reg : Offset and length of the register set for the device.
+- interrupts : Contain the emc interrupts with flags for falling edge.
+ first interrupt dedicated to Txirq
+ second interrupt dedicated to Rxirq
+- phy-mode : Should be "rmii" (see ethernet.txt in the same directory)
+- clocks : phandle of emc reference clock.
+- use-ncsi : Use the NC-SI stack instead of an MDIO PHY
+
+Example:
+
+emc0: eth@f0825000 {
+ device_type = "network";
+ compatible = "nuvoton,npcm750-emc";
+ reg = <0xf0825000 0x1000>;
+ interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
+ phy-mode = "rmii";
+ clocks = <&clk NPCM7XX_CLK_AHB>;
+
+ #use-ncsi; /* add this to support ncsi */
+
+ clock-names = "clk_emc";
+ pinctrl-names = "default";
+ pinctrl-0 = <&r1_pins
+ &r1err_pins
+ &r1md_pins>;
+ status = "okay";
+}; \ No newline at end of file
diff --git a/Documentation/devicetree/bindings/peci/peci-aspeed.yaml b/Documentation/devicetree/bindings/peci/peci-aspeed.yaml
new file mode 100644
index 000000000000..0f5c2993fe9b
--- /dev/null
+++ b/Documentation/devicetree/bindings/peci/peci-aspeed.yaml
@@ -0,0 +1,124 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/peci/peci-aspeed.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Aspeed PECI Bus Device Tree Bindings
+
+maintainers:
+ - Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
+
+properties:
+ compatible:
+ enum:
+ - aspeed,ast2400-peci
+ - aspeed,ast2500-peci
+ - aspeed,ast2600-peci
+
+ reg:
+ maxItems: 1
+
+ "#address-cells":
+ # Required to define a client address.
+ const: 1
+
+ "#size-cells":
+ # Required to define a client address.
+ const: 0
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ description: |
+ Clock source for PECI controller. Should reference the external
+ oscillator clock.
+ maxItems: 1
+
+ resets:
+ maxItems: 1
+
+ clock-frequency:
+ # Operation frequency of PECI controller in units of Hz.
+ minimum: 187500
+ maximum: 24000000
+
+ msg-timing:
+ description: |
+ Message timing negotiation period. This value will determine the period
+ of message timing negotiation to be issued by PECI controller. The unit
+ of the programmed value is four times of PECI clock period.
+ allOf:
+ - $ref: /schemas/types.yaml#/definitions/uint32
+ - minimum: 0
+ maximum: 255
+ default: 1
+
+ addr-timing:
+ description: |
+ Address timing negotiation period. This value will determine the period
+ of address timing negotiation to be issued by PECI controller. The unit
+ of the programmed value is four times of PECI clock period.
+ allOf:
+ - $ref: /schemas/types.yaml#/definitions/uint32
+ - minimum: 0
+ maximum: 255
+ default: 1
+
+ rd-sampling-point:
+ description: |
+ Read sampling point selection. The whole period of a bit time will be
+ divided into 16 time frames. This value will determine the time frame
+ in which the controller will sample PECI signal for data read back.
+ Usually in the middle of a bit time is the best.
+ allOf:
+ - $ref: /schemas/types.yaml#/definitions/uint32
+ - minimum: 0
+ maximum: 15
+ default: 8
+
+ cmd-timeout-ms:
+ # Command timeout in units of ms.
+ allOf:
+ - $ref: /schemas/types.yaml#/definitions/uint32
+ - minimum: 1
+ maximum: 60000
+ default: 1000
+
+required:
+ - compatible
+ - reg
+ - "#address-cells"
+ - "#size-cells"
+ - interrupts
+ - clocks
+ - resets
+ - clock-frequency
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/clock/ast2600-clock.h>
+ peci: bus@1e78b000 {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0x1e78b000 0x60>;
+
+ peci0: peci-bus@0 {
+ compatible = "aspeed,ast2600-peci";
+ reg = <0x0 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&syscon ASPEED_CLK_GATE_REF0CLK>;
+ resets = <&syscon ASPEED_RESET_PECI>;
+ clock-frequency = <24000000>;
+ msg-timing = <1>;
+ addr-timing = <1>;
+ rd-sampling-point = <8>;
+ cmd-timeout-ms = <1000>;
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/peci/peci-bus.yaml b/Documentation/devicetree/bindings/peci/peci-bus.yaml
new file mode 100644
index 000000000000..b085e67089cf
--- /dev/null
+++ b/Documentation/devicetree/bindings/peci/peci-bus.yaml
@@ -0,0 +1,129 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/peci/peci-bus.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Generic Device Tree Bindings for PECI bus
+
+maintainers:
+ - Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
+
+description: |
+ PECI (Platform Environment Control Interface) is a one-wire bus interface that
+ provides a communication channel from Intel processors and chipset components
+ to external monitoring or control devices. PECI is designed to support the
+ following sideband functions:
+
+ * Processor and DRAM thermal management
+ - Processor fan speed control is managed by comparing Digital Thermal
+ Sensor (DTS) thermal readings acquired via PECI against the
+ processor-specific fan speed control reference point, or TCONTROL. Both
+ TCONTROL and DTS thermal readings are accessible via the processor PECI
+ client. These variables are referenced to a common temperature, the TCC
+ activation point, and are both defined as negative offsets from that
+ reference.
+ - PECI based access to the processor package configuration space provides
+ a means for Baseboard Management Controllers (BMC) or other platform
+ management devices to actively manage the processor and memory power
+ and thermal features.
+
+ * Platform Manageability
+ - Platform manageability functions including thermal, power, and error
+ monitoring. Note that platform 'power' management includes monitoring
+ and control for both the processor and DRAM subsystem to assist with
+ data center power limiting.
+ - PECI allows read access to certain error registers in the processor MSR
+ space and status monitoring registers in the PCI configuration space
+ within the processor and downstream devices.
+ - PECI permits writes to certain registers in the processor PCI
+ configuration space.
+
+ * Processor Interface Tuning and Diagnostics
+ - Processor interface tuning and diagnostics capabilities
+ (Intel Interconnect BIST). The processors Intel Interconnect Built In
+ Self Test (Intel IBIST) allows for infield diagnostic capabilities in
+ the Intel UPI and memory controller interfaces. PECI provides a port to
+ execute these diagnostics via its PCI Configuration read and write
+ capabilities.
+
+ * Failure Analysis
+ - Output the state of the processor after a failure for analysis via
+ Crashdump.
+
+ PECI uses a single wire for self-clocking and data transfer. The bus
+ requires no additional control lines. The physical layer is a self-clocked
+ one-wire bus that begins each bit with a driven, rising edge from an idle
+ level near zero volts. The duration of the signal driven high depends on
+ whether the bit value is a logic '0' or logic '1'. PECI also includes
+ variable data transfer rate established with every message. In this way, it
+ is highly flexible even though underlying logic is simple.
+
+ The interface design was optimized for interfacing between an Intel
+ processor and chipset components in both single processor and multiple
+ processor environments. The single wire interface provides low board
+ routing overhead for the multiple load connections in the congested routing
+ area near the processor and chipset components. Bus speed, error checking,
+ and low protocol overhead provides adequate link bandwidth and reliability
+ to transfer critical device operating conditions and configuration
+ information.
+
+ PECI subsystem provides single or multiple bus nodes support so each bus can
+ have one adapter node and multiple device specific client nodes that can be
+ attached to the PECI bus so each processor client's features can be supported
+ by the client node through an adapter connection in the bus.
+
+properties:
+ compatible:
+ const: simple-bus
+
+ "#address-cells":
+ # Required to define bus device control resource address.
+ const: 1
+
+ "#size-cells":
+ # Required to define bus device control resource address.
+ const: 1
+
+ ranges: true
+
+required:
+ - compatible
+ - "#address-cells"
+ - "#size-cells"
+ - ranges
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/clock/ast2600-clock.h>
+ peci: bus@1e78b000 {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0x1e78b000 0x200>;
+
+ peci0: peci-bus@0 {
+ compatible = "aspeed,ast2600-peci";
+ reg = <0x0 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&syscon ASPEED_CLK_GATE_REF0CLK>;
+ resets = <&syscon ASPEED_RESET_PECI>;
+ clock-frequency = <24000000>;
+ };
+
+ // Just an example. ast2600 doesn't have a second PECI module actually.
+ peci1: peci-bus@100 {
+ compatible = "aspeed,ast2600-peci";
+ reg = <0x100 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&syscon ASPEED_CLK_GATE_REF0CLK>;
+ resets = <&syscon ASPEED_RESET_PECI>;
+ clock-frequency = <24000000>;
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/peci/peci-client.yaml b/Documentation/devicetree/bindings/peci/peci-client.yaml
new file mode 100644
index 000000000000..fc7c4110e929
--- /dev/null
+++ b/Documentation/devicetree/bindings/peci/peci-client.yaml
@@ -0,0 +1,54 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/peci/peci-client.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Generic Device Tree Bindings for PECI clients
+
+maintainers:
+ - Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
+
+properties:
+ compatible:
+ enum:
+ - intel,peci-client
+
+ reg:
+ description: |
+ Address of a client CPU. According to the PECI specification, client
+ addresses start from 0x30.
+ maxItems: 1
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/clock/ast2600-clock.h>
+ peci: bus@1e78b000 {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0x1e78b000 0x60>;
+
+ peci0: peci-bus@0 {
+ compatible = "aspeed,ast2600-peci";
+ reg = <0x0 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&syscon ASPEED_CLK_GATE_REF0CLK>;
+ resets = <&syscon ASPEED_RESET_PECI>;
+ clock-frequency = <24000000>;
+
+ peci-client@30 {
+ compatible = "intel,peci-client";
+ reg = <0x30>;
+ };
+
+ peci-client@31 {
+ compatible = "intel,peci-client";
+ reg = <0x31>;
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/peci/peci-npcm.yaml b/Documentation/devicetree/bindings/peci/peci-npcm.yaml
new file mode 100644
index 000000000000..bcd5626e68e7
--- /dev/null
+++ b/Documentation/devicetree/bindings/peci/peci-npcm.yaml
@@ -0,0 +1,102 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/peci/peci-npcm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Nuvoton NPCM PECI Bus Device Tree Bindings
+
+maintainers:
+ - Tomer Maimon <tmaimon77@gmail.com>
+
+properties:
+ compatible:
+ const: nuvoton,npcm750-peci # for the NPCM7XX BMC.
+
+ reg:
+ maxItems: 1
+
+ "#address-cells":
+ # Required to define a client address.
+ const: 1
+
+ "#size-cells":
+ # Required to define a client address.
+ const: 0
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ # PECI reference clock.
+ maxItems: 1
+
+ cmd-timeout-ms:
+ # Command timeout in units of ms.
+ allOf:
+ - $ref: /schemas/types.yaml#/definitions/uint32
+ - minimum: 1
+ maximum: 60000
+ default: 1000
+
+ pull-down:
+ description: |
+ Defines the PECI I/O internal pull down operation.
+ 0: pull down always enable
+ 1: pull down only during transactions.
+ 2: pull down always disable.
+ allOf:
+ - $ref: /schemas/types.yaml#/definitions/uint32
+ - minimum: 0
+ maximum: 2
+ default: 0
+
+ host-neg-bit-rate:
+ description: |
+ Define host negotiation bit rate divider.
+ the host negotiation bit rate calculate with formula:
+ clock frequency[Hz] / [4 x {host-neg-bit-rate + 1}]
+ allOf:
+ - $ref: /schemas/types.yaml#/definitions/uint32
+ - minimum: 7
+ maximum: 31
+ default: 15
+
+ high-volt-range:
+ description: |
+ Adapts PECI I/O interface to voltage range.
+ 0: PECI I/O interface voltage range of 0.8-1.06V (default)
+ 1: PECI I/O interface voltage range of 0.95-1.26V
+ type: boolean
+
+required:
+ - compatible
+ - reg
+ - "#address-cells"
+ - "#size-cells"
+ - interrupts
+ - clocks
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/clock/nuvoton,npcm7xx-clock.h>
+ peci: bus@100000 {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0x100000 0x200>;
+
+ peci0: peci-bus@0 {
+ compatible = "nuvoton,npcm750-peci";
+ reg = <0x0 0x200>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clk NPCM7XX_CLK_APB3>;
+ cmd-timeout-ms = <1000>;
+ pull-down = <0>;
+ host-neg-bit-rate = <15>;
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/security/tpm/tpm-tis-i2c.yaml b/Documentation/devicetree/bindings/security/tpm/tpm-tis-i2c.yaml
new file mode 100644
index 000000000000..13d7c2c81c11
--- /dev/null
+++ b/Documentation/devicetree/bindings/security/tpm/tpm-tis-i2c.yaml
@@ -0,0 +1,47 @@
+# SPDX-License-Identifier: GPL-2.0
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/security/tpm/tpm-tis-i2c.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: I2C PTP based TPM Device Tree Bindings
+
+maintainers:
+ - Amir Mizinski <amirmizi6@gmail.com>
+
+description:
+ Device Tree Bindings for I2C based Trusted Platform Module(TPM).
+
+properties:
+ compatible:
+ contains:
+ const: tcg,tpm-tis-i2c
+
+ reg:
+ maxItems: 1
+
+ interrupt:
+ maxItems: 1
+
+ crc-checksum:
+ $ref: /schemas/types.yaml#/definitions/flag
+ description:
+ CRC checksum enable.
+
+required:
+ - compatible
+ - reg
+
+examples:
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ tpm-tis-i2c@2e {
+ compatible = "tcg,tpm-tis-i2c";
+ reg = <0x2e>;
+ crc-checksum;
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/soc/aspeed/xdma.yaml b/Documentation/devicetree/bindings/soc/aspeed/xdma.yaml
new file mode 100644
index 000000000000..495743581e2d
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/aspeed/xdma.yaml
@@ -0,0 +1,103 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/soc/aspeed/xdma.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Aspeed AST25XX and AST26XX XDMA Engine
+
+maintainers:
+ - Eddie James <eajames@linux.ibm.com>
+
+description: |
+ This binding describes the XDMA Engine embedded in the AST2500 and AST2600
+ SOCs. The XDMA engine can perform automatic DMA operations over PCI between
+ the SOC (acting as a BMC) and a host processor.
+
+properties:
+ compatible:
+ enum:
+ - aspeed,ast2500-xdma
+ - aspeed,ast2600-xdma
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ resets:
+ minItems: 1
+ maxItems: 2
+
+ reset-names:
+ maxItems: 2
+ items:
+ - const: device
+ - const: root-complex
+
+ interrupts:
+ maxItems: 2
+ items:
+ - description: global interrupt for the XDMA engine
+ - description: PCI-E reset or PERST interrupt
+
+ aspeed,scu:
+ description: a reference to the System Control Unit node of the Aspeed SOC.
+ allOf:
+ - $ref: /schemas/types.yaml#/definitions/phandle
+
+ aspeed,pcie-device:
+ description: describes which PCI-E device the XDMA engine should use
+ allOf:
+ - $ref: /schemas/types.yaml#/definitions/string
+ - enum: [ bmc, vga ]
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - resets
+ - interrupts-extended
+ - aspeed,scu
+ - memory-region
+
+if:
+ properties:
+ compatible:
+ contains:
+ const: aspeed,ast2600-xdma
+then:
+ required:
+ - reset-names
+
+examples:
+ - |
+ #include <dt-bindings/clock/ast2600-clock.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/interrupt-controller/aspeed-scu-ic.h>
+ syscon: syscon@1e6e2000 {
+ reg = <0x1e6e2000 0x1000>;
+ ranges = <0 0x1e6e2000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ scu_ic0: interrupt-controller@560 {
+ reg = <0x560 0x4>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+ };
+ xdma@1e6e7000 {
+ compatible = "aspeed,ast2600-xdma";
+ reg = <0x1e6e7000 0x100>;
+ clocks = <&syscon ASPEED_CLK_GATE_BCLK>;
+ resets = <&syscon ASPEED_RESET_DEV_XDMA>, <&syscon ASPEED_RESET_RC_XDMA>;
+ reset-names = "device", "root-complex";
+ interrupts-extended = <&gic GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>,
+ <&scu_ic0 ASPEED_AST2600_SCU_IC0_PCIE_PERST_LO_TO_HI>;
+ aspeed,scu = <&syscon>;
+ aspeed,pcie-device = "bmc";
+ memory-region = <&vga_memory>;
+ };
diff --git a/Documentation/driver-api/ipmb.rst b/Documentation/driver-api/ipmb.rst
index 3ec3baed84c4..209c49e05116 100644
--- a/Documentation/driver-api/ipmb.rst
+++ b/Documentation/driver-api/ipmb.rst
@@ -71,9 +71,13 @@ b) Example for device tree::
ipmb@10 {
compatible = "ipmb-dev";
reg = <0x10>;
+ i2c-protocol;
};
};
+If xmit of data to be done using raw i2c block vs smbus
+then "i2c-protocol" needs to be defined as above.
+
2) Manually from Linux::
modprobe ipmb-dev-int
diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst
index 230ad59b462b..7d894c9e07ed 100644
--- a/Documentation/hwmon/index.rst
+++ b/Documentation/hwmon/index.rst
@@ -128,6 +128,8 @@ Hardware Monitoring Kernel Drivers
pc87360
pc87427
pcf8591
+ peci-cputemp
+ peci-dimmtemp
pmbus
powr1220
pxe1610
diff --git a/Documentation/hwmon/peci-cputemp.rst b/Documentation/hwmon/peci-cputemp.rst
new file mode 100644
index 000000000000..bf08e16dd989
--- /dev/null
+++ b/Documentation/hwmon/peci-cputemp.rst
@@ -0,0 +1,95 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+Kernel driver peci-cputemp
+==========================
+
+:Copyright: |copy| 2018-2019 Intel Corporation
+
+Supported chips:
+ One of Intel server CPUs listed below which is connected to a PECI bus.
+ * Intel Xeon E5/E7 v3 server processors
+ Intel Xeon E5-14xx v3 family
+ Intel Xeon E5-24xx v3 family
+ Intel Xeon E5-16xx v3 family
+ Intel Xeon E5-26xx v3 family
+ Intel Xeon E5-46xx v3 family
+ Intel Xeon E7-48xx v3 family
+ Intel Xeon E7-88xx v3 family
+ * Intel Xeon E5/E7 v4 server processors
+ Intel Xeon E5-16xx v4 family
+ Intel Xeon E5-26xx v4 family
+ Intel Xeon E5-46xx v4 family
+ Intel Xeon E7-48xx v4 family
+ Intel Xeon E7-88xx v4 family
+ * Intel Xeon Scalable server processors
+ Intel Xeon D family
+ Intel Xeon Bronze family
+ Intel Xeon Silver family
+ Intel Xeon Gold family
+ Intel Xeon Platinum family
+
+ Addresses scanned: PECI client address 0x30 - 0x37
+ Datasheet: Available from http://www.intel.com/design/literature.htm
+
+Author:
+ Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
+
+Description
+-----------
+
+This driver implements a generic PECI hwmon feature which provides Digital
+Thermal Sensor (DTS) thermal readings of the CPU package and CPU cores that are
+accessible using the PECI Client Command Suite via the processor PECI client.
+
+All temperature values are given in millidegree Celsius and will be measurable
+only when the target CPU is powered on.
+
+``sysfs`` interface
+-------------------
+======================= =======================================================
+temp1_label "Die"
+temp1_input Provides current die temperature of the CPU package.
+temp1_max Provides thermal control temperature of the CPU package
+ which is also known as Tcontrol.
+temp1_crit Provides shutdown temperature of the CPU package which
+ is also known as the maximum processor junction
+ temperature, Tjmax or Tprochot.
+temp1_crit_hyst Provides the hysteresis value from Tcontrol to Tjmax of
+ the CPU package.
+
+temp2_label "DTS"
+temp2_input Provides current DTS temperature of the CPU package.
+temp2_max Provides thermal control temperature of the CPU package
+ which is also known as Tcontrol.
+temp2_crit Provides shutdown temperature of the CPU package which
+ is also known as the maximum processor junction
+ temperature, Tjmax or Tprochot.
+temp2_crit_hyst Provides the hysteresis value from Tcontrol to Tjmax of
+ the CPU package.
+
+temp3_label "Tcontrol"
+temp3_input Provides current Tcontrol temperature of the CPU
+ package which is also known as Fan Temperature target.
+ Indicates the relative value from thermal monitor trip
+ temperature at which fans should be engaged.
+temp3_crit Provides Tcontrol critical value of the CPU package
+ which is same to Tjmax.
+
+temp4_label "Tthrottle"
+temp4_input Provides current Tthrottle temperature of the CPU
+ package. Used for throttling temperature. If this value
+ is allowed and lower than Tjmax - the throttle will
+ occur and reported at lower than Tjmax.
+
+temp5_label "Tjmax"
+temp5_input Provides the maximum junction temperature, Tjmax of the
+ CPU package.
+
+temp[6-N]_label Provides string "Core X", where X is resolved core
+ number.
+temp[6-N]_input Provides current temperature of each core.
+temp[6-N]_max Provides thermal control temperature of the core.
+temp[6-N]_crit Provides shutdown temperature of the core.
+temp[6-N]_crit_hyst Provides the hysteresis value from Tcontrol to Tjmax of
+ the core.
+======================= ======================================================= \ No newline at end of file
diff --git a/Documentation/hwmon/peci-dimmtemp.rst b/Documentation/hwmon/peci-dimmtemp.rst
new file mode 100644
index 000000000000..e3581811de2d
--- /dev/null
+++ b/Documentation/hwmon/peci-dimmtemp.rst
@@ -0,0 +1,60 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+Kernel driver peci-dimmtemp
+===========================
+
+:Copyright: |copy| 2018-2019 Intel Corporation
+
+Supported chips:
+ One of Intel server CPUs listed below which is connected to a PECI bus.
+ * Intel Xeon E5/E7 v3 server processors
+ Intel Xeon E5-14xx v3 family
+ Intel Xeon E5-24xx v3 family
+ Intel Xeon E5-16xx v3 family
+ Intel Xeon E5-26xx v3 family
+ Intel Xeon E5-46xx v3 family
+ Intel Xeon E7-48xx v3 family
+ Intel Xeon E7-88xx v3 family
+ * Intel Xeon E5/E7 v4 server processors
+ Intel Xeon E5-16xx v4 family
+ Intel Xeon E5-26xx v4 family
+ Intel Xeon E5-46xx v4 family
+ Intel Xeon E7-48xx v4 family
+ Intel Xeon E7-88xx v4 family
+ * Intel Xeon Scalable server processors
+ Intel Xeon D family
+ Intel Xeon Bronze family
+ Intel Xeon Silver family
+ Intel Xeon Gold family
+ Intel Xeon Platinum family
+
+ Addresses scanned: PECI client address 0x30 - 0x37
+ Datasheet: Available from http://www.intel.com/design/literature.htm
+
+Author:
+ Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
+
+Description
+-----------
+
+This driver implements a generic PECI hwmon feature which provides Digital
+Thermal Sensor (DTS) thermal readings of DIMM components that are accessible
+using the PECI Client Command Suite via the processor PECI client.
+
+All temperature values are given in millidegree Celsius and will be measurable
+only when the target CPU is powered on.
+
+``sysfs`` interface
+-------------------
+======================= =======================================================
+
+temp[N]_label Provides string "DIMM CI", where C is DIMM channel and
+ I is DIMM index of the populated DIMM.
+temp[N]_input Provides current temperature of the populated DIMM.
+temp[N]_max Provides thermal control temperature of the DIMM.
+temp[N]_crit Provides shutdown temperature of the DIMM.
+======================= =======================================================
+
+Note:
+ DIMM temperature attributes will appear when the client CPU's BIOS
+ completes memory training and testing.
diff --git a/Documentation/hwmon/ucd9000.rst b/Documentation/hwmon/ucd9000.rst
index 746f21fcb48c..704f0cbd95d3 100644
--- a/Documentation/hwmon/ucd9000.rst
+++ b/Documentation/hwmon/ucd9000.rst
@@ -3,9 +3,10 @@ Kernel driver ucd9000
Supported chips:
- * TI UCD90120, UCD90124, UCD90160, UCD9090, and UCD90910
+ * TI UCD90120, UCD90124, UCD90160, UCD90320, UCD9090, and UCD90910
- Prefixes: 'ucd90120', 'ucd90124', 'ucd90160', 'ucd9090', 'ucd90910'
+ Prefixes: 'ucd90120', 'ucd90124', 'ucd90160', 'ucd90320', 'ucd9090',
+ 'ucd90910'
Addresses scanned: -
@@ -14,6 +15,7 @@ Supported chips:
- http://focus.ti.com/lit/ds/symlink/ucd90120.pdf
- http://focus.ti.com/lit/ds/symlink/ucd90124.pdf
- http://focus.ti.com/lit/ds/symlink/ucd90160.pdf
+ - http://focus.ti.com/lit/ds/symlink/ucd90320.pdf
- http://focus.ti.com/lit/ds/symlink/ucd9090.pdf
- http://focus.ti.com/lit/ds/symlink/ucd90910.pdf
@@ -45,6 +47,12 @@ power-on reset signals, external interrupts, cascading, or other system
functions. Twelve of these pins offer PWM functionality. Using these pins, the
UCD90160 offers support for margining, and general-purpose PWM functions.
+The UCD90320 is a 32-rail PMBus/I2C addressable power-supply sequencer and
+monitor. The 24 integrated ADC channels (AMONx) monitor the power supply
+voltage, current, and temperature. Of the 84 GPIO pins, 8 can be used as
+digital monitors (DMONx), 32 to enable the power supply (ENx), 24 for margining
+(MARx), 16 for logical GPO, and 32 GPIs for cascading, and system function.
+
The UCD9090 is a 10-rail PMBus/I2C addressable power-supply sequencer and
monitor. The device integrates a 12-bit ADC for monitoring up to 10 power-supply
voltage inputs. Twenty-three GPIO pins can be used for power supply enables,
diff --git a/Documentation/ioctl/ioctl-number.rst b/Documentation/ioctl/ioctl-number.rst
index bef79cd4c6b4..de23fc0f0fce 100644
--- a/Documentation/ioctl/ioctl-number.rst
+++ b/Documentation/ioctl/ioctl-number.rst
@@ -337,6 +337,8 @@ Code Seq# Include File Comments
0xB4 00-0F linux/gpio.h <mailto:linux-gpio@vger.kernel.org>
0xB5 00-0F uapi/linux/rpmsg.h <mailto:linux-remoteproc@vger.kernel.org>
0xB6 all linux/fpga-dfl.h
+0xB7 all uapi/linux/peci-ioctl.h PECI subsystem
+ <mailto:jae.hyun.yoo@linux.intel.com>
0xC0 00-0F linux/usb/iowarrior.h
0xCA 00-0F uapi/misc/cxl.h
0xCA 10-2F uapi/misc/ocxl.h
diff --git a/MAINTAINERS b/MAINTAINERS
index fe6fa5d3a63e..b992f34dc4b1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2649,6 +2649,14 @@ S: Maintained
F: drivers/pinctrl/aspeed/
F: Documentation/devicetree/bindings/pinctrl/aspeed,*
+ASPEED SCU INTERRUPT CONTROLLER DRIVER
+M: Eddie James <eajames@linux.ibm.com>
+L: linux-aspeed@lists.ozlabs.org (moderated for non-subscribers)
+S: Maintained
+F: Documentation/devicetree/bindings/interrupt-controller/aspeed,ast2xxx-scu-ic.txt
+F: drivers/irqchip/irq-aspeed-scu-ic.c
+F: include/dt-bindings/interrupt-controller/aspeed-scu-ic.h
+
ASPEED VIDEO ENGINE DRIVER
M: Eddie James <eajames@linux.ibm.com>
L: linux-media@vger.kernel.org
@@ -2657,6 +2665,14 @@ S: Maintained
F: drivers/media/platform/aspeed-video.c
F: Documentation/devicetree/bindings/media/aspeed-video.txt
+ASPEED XDMA ENGINE DRIVER
+M: Eddie James <eajames@linux.ibm.com>
+L: linux-aspeed@lists.ozlabs.org (moderated for non-subscribers)
+S: Maintained
+F: Documentation/devicetree/bindings/soc/aspeed/xdma.txt
+F: drivers/soc/aspeed/aspeed-xdma.c
+F: include/uapi/linux/aspeed-xdma.h
+
ASUS NOTEBOOKS AND EEEPC ACPI/WMI EXTRAS DRIVERS
M: Corentin Chary <corentin.chary@gmail.com>
L: acpi4asus-user@lists.sourceforge.net
@@ -5941,6 +5957,12 @@ L: linux-edac@vger.kernel.org
S: Maintained
F: drivers/edac/mpc85xx_edac.[ch]
+EDAC-NPCM7XX
+M: George Hung <george.hung@quantatw.com>
+S: Maintained
+F: drivers/edac/npcm7xx_edac.c
+F: Documentation/devicetree/bindings/edac/npcm7xx-sdram-edac.txt
+
EDAC-PASEMI
M: Egor Martovetsky <egor@pasemi.com>
L: linux-edac@vger.kernel.org
@@ -6709,6 +6731,13 @@ S: Maintained
F: drivers/i2c/busses/i2c-fsi.c
F: Documentation/devicetree/bindings/i2c/i2c-fsi.txt
+FSI-ATTACHED SPI DRIVER
+M: Eddie James <eajames@linux.ibm.com>
+L: linux-spi@vger.kernel.org
+S: Maintained
+F: drivers/spi/spi-fsi.c
+F: Documentation/devicetree/bindings/fsi/ibm,fsi2spi.yaml
+
FSNOTIFY: FILESYSTEM NOTIFICATION INFRASTRUCTURE
M: Jan Kara <jack@suse.cz>
R: Amir Goldstein <amir73il@gmail.com>
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index b21b3a64641a..d6dfdf73e66b 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -324,7 +324,8 @@ dtb-$(CONFIG_ARCH_LPC32XX) += \
lpc3250-ea3250.dtb \
lpc3250-phy3250.dtb
dtb-$(CONFIG_ARCH_NPCM7XX) += \
- nuvoton-npcm750-evb.dtb
+ nuvoton-npcm750-evb.dtb \
+ nuvoton-npcm730-gsj.dtb
dtb-$(CONFIG_MACH_MESON6) += \
meson6-atv1200.dtb
dtb-$(CONFIG_MACH_MESON8) += \
@@ -1288,6 +1289,7 @@ dtb-$(CONFIG_ARCH_ASPEED) += \
aspeed-bmc-facebook-wedge40.dtb \
aspeed-bmc-facebook-wedge100.dtb \
aspeed-bmc-facebook-yamp.dtb \
+ aspeed-bmc-ibm-rainier.dtb \
aspeed-bmc-intel-s2600wf.dtb \
aspeed-bmc-inspur-fp5280g2.dtb \
aspeed-bmc-lenovo-hr630.dtb \
@@ -1298,8 +1300,10 @@ dtb-$(CONFIG_ARCH_ASPEED) += \
aspeed-bmc-opp-palmetto.dtb \
aspeed-bmc-opp-romulus.dtb \
aspeed-bmc-opp-swift.dtb \
+ aspeed-bmc-opp-tacoma.dtb \
aspeed-bmc-opp-vesnin.dtb \
aspeed-bmc-opp-witherspoon.dtb \
+ aspeed-bmc-opp-witherspoon-128.dtb \
aspeed-bmc-opp-zaius.dtb \
aspeed-bmc-portwell-neptune.dtb \
aspeed-bmc-quanta-q71l.dtb
diff --git a/arch/arm/boot/dts/aspeed-ast2500-evb.dts b/arch/arm/boot/dts/aspeed-ast2500-evb.dts
index c9d88c90135e..8bec21ed0de5 100644
--- a/arch/arm/boot/dts/aspeed-ast2500-evb.dts
+++ b/arch/arm/boot/dts/aspeed-ast2500-evb.dts
@@ -40,6 +40,7 @@
status = "okay";
m25p,fast-read;
label = "bmc";
+ spi-max-frequency = <50000000>;
#include "openbmc-flash-layout.dtsi"
};
};
@@ -50,6 +51,7 @@
status = "okay";
m25p,fast-read;
label = "pnor";
+ spi-max-frequency = <100000000>;
};
};
diff --git a/arch/arm/boot/dts/aspeed-ast2600-evb.dts b/arch/arm/boot/dts/aspeed-ast2600-evb.dts
index 9870553919b7..89be13197780 100644
--- a/arch/arm/boot/dts/aspeed-ast2600-evb.dts
+++ b/arch/arm/boot/dts/aspeed-ast2600-evb.dts
@@ -23,6 +23,15 @@
};
};
+&mdio0 {
+ status = "okay";
+
+ ethphy0: ethernet-phy@0 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <0>;
+ };
+};
+
&mdio1 {
status = "okay";
@@ -50,11 +59,25 @@
};
};
+&mac0 {
+ status = "okay";
+
+ phy-mode = "rgmii";
+ phy-handle = <&ethphy0>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_rgmii1_default>;
+};
+
+
&mac1 {
status = "okay";
phy-mode = "rgmii";
phy-handle = <&ethphy1>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_rgmii2_default>;
};
&mac2 {
@@ -62,6 +85,9 @@
phy-mode = "rgmii";
phy-handle = <&ethphy2>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_rgmii3_default>;
};
&mac3 {
@@ -69,12 +95,145 @@
phy-mode = "rgmii";
phy-handle = <&ethphy3>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_rgmii4_default>;
};
-&emmc {
+&emmc_controller {
status = "okay";
};
+&emmc {
+ non-removable;
+ bus-width = <4>;
+ max-frequency = <52000000>;
+};
+
&rtc {
status = "okay";
};
+
+&fmc {
+ status = "okay";
+ flash@0 {
+ status = "okay";
+ m25p,fast-read;
+ label = "bmc";
+ spi-max-frequency = <50000000>;
+
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ u-boot@0 {
+ reg = <0x0 0xe0000>; // 896KB
+ label = "u-boot";
+ };
+
+ u-boot-env@e0000 {
+ reg = <0xe0000 0x20000>; // 128KB
+ label = "u-boot-env";
+ };
+
+ kernel@100000 {
+ reg = <0x100000 0x900000>; // 9MB
+ label = "kernel";
+ };
+
+ rofs@a00000 {
+ reg = <0xa00000 0x2000000>; // 32MB
+ label = "rofs";
+ };
+
+ rwfs@6000000 {
+ reg = <0x2a00000 0x1600000>; // 22MB
+ label = "rwfs";
+ };
+ };
+ };
+};
+
+&spi1 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_spi1_default>;
+
+ flash@0 {
+ status = "okay";
+ m25p,fast-read;
+ label = "pnor";
+ spi-max-frequency = <100000000>;
+ };
+};
+
+&uart5 {
+ // Workaround for A0
+ compatible = "snps,dw-apb-uart";
+};
+
+&i2c0 {
+ status = "okay";
+
+ temp@2e {
+ compatible = "adi,adt7490";
+ reg = <0x2e>;
+ };
+};
+
+&i2c1 {
+ status = "okay";
+};
+
+&i2c2 {
+ status = "okay";
+};
+
+&i2c3 {
+ status = "okay";
+};
+
+&i2c4 {
+ status = "okay";
+};
+
+&i2c5 {
+ status = "okay";
+};
+
+&i2c6 {
+ status = "okay";
+};
+
+&i2c7 {
+ status = "okay";
+};
+
+&i2c8 {
+ status = "okay";
+};
+
+&i2c9 {
+ status = "okay";
+};
+
+&i2c12 {
+ status = "okay";
+};
+
+&i2c13 {
+ status = "okay";
+};
+
+&i2c14 {
+ status = "okay";
+};
+
+&i2c15 {
+ status = "okay";
+};
+
+&fsim0 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/aspeed-bmc-arm-stardragon4800-rep2.dts b/arch/arm/boot/dts/aspeed-bmc-arm-stardragon4800-rep2.dts
index 521afbea2c5b..2c29ac037d32 100644
--- a/arch/arm/boot/dts/aspeed-bmc-arm-stardragon4800-rep2.dts
+++ b/arch/arm/boot/dts/aspeed-bmc-arm-stardragon4800-rep2.dts
@@ -92,6 +92,9 @@
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_rmii2_default>;
+ clocks = <&syscon ASPEED_CLK_GATE_MAC2CLK>,
+ <&syscon ASPEED_CLK_MAC2RCLK>;
+ clock-names = "MACCLK", "RCLK";
use-ncsi;
};
diff --git a/arch/arm/boot/dts/aspeed-bmc-facebook-cmm.dts b/arch/arm/boot/dts/aspeed-bmc-facebook-cmm.dts
index d519d307aa2a..016bbcb99bb6 100644
--- a/arch/arm/boot/dts/aspeed-bmc-facebook-cmm.dts
+++ b/arch/arm/boot/dts/aspeed-bmc-facebook-cmm.dts
@@ -2,7 +2,7 @@
// Copyright (c) 2018 Facebook Inc.
/dts-v1/;
-#include "aspeed-g5.dtsi"
+#include "ast2500-facebook-netbmc-common.dtsi"
/ {
model = "Facebook Backpack CMM BMC";
@@ -53,10 +53,6 @@
bootargs = "console=ttyS1,9600n8 root=/dev/ram rw earlyprintk";
};
- memory@80000000 {
- reg = <0x80000000 0x20000000>;
- };
-
ast-adc-hwmon {
compatible = "iio-hwmon";
io-channels = <&adc 0>, <&adc 1>, <&adc 2>, <&adc 3>,
@@ -64,39 +60,7 @@
};
};
-&pinctrl {
- aspeed,external-nodes = <&gfx &lhc>;
-};
-
-/*
- * Update reset type to "system" (full chip) to fix warm reboot hang issue
- * when reset type is set to default ("soc", gated by reset mask registers).
- */
-&wdt1 {
- status = "okay";
- aspeed,reset-type = "system";
-};
-
-/*
- * wdt2 is not used by Backpack CMM.
- */
-&wdt2 {
- status = "disabled";
-};
-
-&fmc {
- status = "okay";
- flash@0 {
- status = "okay";
- m25p,fast-read;
- label = "bmc";
-#include "facebook-bmc-flash-layout.dtsi"
- };
-};
-
&uart1 {
- status = "okay";
- pinctrl-names = "default";
pinctrl-0 = <&pinctrl_txd1_default
&pinctrl_rxd1_default
&pinctrl_ncts1_default
@@ -107,8 +71,6 @@
};
&uart3 {
- status = "okay";
- pinctrl-names = "default";
pinctrl-0 = <&pinctrl_txd3_default
&pinctrl_rxd3_default
&pinctrl_ncts3_default
@@ -123,17 +85,6 @@
&pinctrl_rxd4_default>;
};
-&uart5 {
- status = "okay";
-};
-
-&mac1 {
- status = "okay";
- no-hw-checksum;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_rgmii2_default &pinctrl_mdio2_default>;
-};
-
/*
* I2C bus reserved for communication with COM-E.
*/
@@ -380,3 +331,18 @@
&ehci1 {
status = "okay";
};
+
+&vhub {
+ status = "disabled";
+};
+
+&sdhci0 {
+ status = "okay";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_sd1_default>;
+};
+
+&sdhci1 {
+ status = "disabled";
+};
diff --git a/arch/arm/boot/dts/aspeed-bmc-facebook-minipack.dts b/arch/arm/boot/dts/aspeed-bmc-facebook-minipack.dts
index c05478296446..88ce4ff9f47e 100644
--- a/arch/arm/boot/dts/aspeed-bmc-facebook-minipack.dts
+++ b/arch/arm/boot/dts/aspeed-bmc-facebook-minipack.dts
@@ -2,7 +2,7 @@
// Copyright (c) 2018 Facebook Inc.
/dts-v1/;
-#include "aspeed-g5.dtsi"
+#include "ast2500-facebook-netbmc-common.dtsi"
/ {
model = "Facebook Minipack 100 BMC";
@@ -76,35 +76,36 @@
stdout-path = &uart1;
bootargs = "debug console=ttyS1,9600n8 root=/dev/ram rw";
};
-
- memory@80000000 {
- reg = <0x80000000 0x20000000>;
- };
};
-&wdt1 {
+&wdt2 {
status = "okay";
aspeed,reset-type = "system";
};
-&wdt2 {
- status = "okay";
- aspeed,reset-type = "system";
+/*
+ * Both firmware flashes are 64MB on Minipack BMC.
+ */
+&fmc_flash0 {
+ partitions {
+ data0@1c00000 {
+ reg = <0x1c00000 0x2400000>;
+ };
+ flash0@0 {
+ reg = <0x0 0x4000000>;
+ };
+ };
};
-&fmc {
- status = "okay";
- flash@0 {
- status = "okay";
- m25p,fast-read;
- label = "bmc";
-#include "facebook-bmc-flash-layout.dtsi"
+&fmc_flash1 {
+ partitions {
+ flash1@0 {
+ reg = <0x0 0x4000000>;
+ };
};
};
&uart1 {
- status = "okay";
- pinctrl-names = "default";
pinctrl-0 = <&pinctrl_txd1_default
&pinctrl_rxd1_default
&pinctrl_ncts1_default
@@ -120,13 +121,6 @@
&pinctrl_rxd2_default>;
};
-&uart3 {
- status = "okay";
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_txd3_default
- &pinctrl_rxd3_default>;
-};
-
&uart4 {
status = "okay";
pinctrl-names = "default";
@@ -134,17 +128,6 @@
&pinctrl_rxd4_default>;
};
-&uart5 {
- status = "okay";
-};
-
-&mac1 {
- status = "okay";
- no-hw-checksum;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_rgmii2_default &pinctrl_mdio2_default>;
-};
-
&i2c0 {
status = "okay";
bus-frequency = <400000>;
@@ -423,7 +406,3 @@
&i2c13 {
status = "okay";
};
-
-&vhub {
- status = "okay";
-};
diff --git a/arch/arm/boot/dts/aspeed-bmc-facebook-tiogapass.dts b/arch/arm/boot/dts/aspeed-bmc-facebook-tiogapass.dts
index 682f729ea25e..5d7cbd9164d4 100644
--- a/arch/arm/boot/dts/aspeed-bmc-facebook-tiogapass.dts
+++ b/arch/arm/boot/dts/aspeed-bmc-facebook-tiogapass.dts
@@ -126,6 +126,9 @@
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_rmii1_default>;
+ clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>,
+ <&syscon ASPEED_CLK_MAC1RCLK>;
+ clock-names = "MACCLK", "RCLK";
use-ncsi;
};
diff --git a/arch/arm/boot/dts/aspeed-bmc-facebook-yamp.dts b/arch/arm/boot/dts/aspeed-bmc-facebook-yamp.dts
index 4e09a9cf32b7..52933598aac6 100644
--- a/arch/arm/boot/dts/aspeed-bmc-facebook-yamp.dts
+++ b/arch/arm/boot/dts/aspeed-bmc-facebook-yamp.dts
@@ -2,7 +2,7 @@
// Copyright (c) 2018 Facebook Inc.
/dts-v1/;
-#include "aspeed-g5.dtsi"
+#include "ast2500-facebook-netbmc-common.dtsi"
/ {
model = "Facebook YAMP 100 BMC";
@@ -23,47 +23,6 @@
stdout-path = &uart5;
bootargs = "console=ttyS0,9600n8 root=/dev/ram rw";
};
-
- memory@80000000 {
- reg = <0x80000000 0x20000000>;
- };
-};
-
-&pinctrl {
- aspeed,external-nodes = <&gfx &lhc>;
-};
-
-/*
- * Update reset type to "system" (full chip) to fix warm reboot hang issue
- * when reset type is set to default ("soc", gated by reset mask registers).
- */
-&wdt1 {
- status = "okay";
- aspeed,reset-type = "system";
-};
-
-/*
- * wdt2 is not used by Yamp.
- */
-&wdt2 {
- status = "disabled";
-};
-
-&fmc {
- status = "okay";
- flash@0 {
- status = "okay";
- m25p,fast-read;
- label = "bmc";
-#include "facebook-bmc-flash-layout.dtsi"
- };
-};
-
-&uart1 {
- status = "okay";
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_txd1_default
- &pinctrl_rxd1_default>;
};
&uart2 {
@@ -73,23 +32,19 @@
&pinctrl_rxd2_default>;
};
-&uart3 {
- status = "okay";
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_txd3_default
- &pinctrl_rxd3_default>;
-};
-
-&uart5 {
- status = "okay";
-};
-
&mac0 {
status = "okay";
use-ncsi;
no-hw-checksum;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_rmii1_default>;
+ clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>,
+ <&syscon ASPEED_CLK_MAC1RCLK>;
+ clock-names = "MACCLK", "RCLK";
+};
+
+&mac1 {
+ status = "disabled";
};
&i2c0 {
@@ -154,7 +109,3 @@
&i2c13 {
status = "okay";
};
-
-&vhub {
- status = "okay";
-};
diff --git a/arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts b/arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts
new file mode 100644
index 000000000000..0b5c6cc1c66a
--- /dev/null
+++ b/arch/arm/boot/dts/aspeed-bmc-ibm-rainier.dts
@@ -0,0 +1,729 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// Copyright 2019 IBM Corp.
+/dts-v1/;
+
+#include "aspeed-g6.dtsi"
+#include <dt-bindings/gpio/aspeed-gpio.h>
+#include <dt-bindings/leds/leds-pca955x.h>
+
+/ {
+ model = "Rainier";
+ compatible = "ibm,rainier-bmc", "aspeed,ast2600";
+
+ aliases {
+ serial4 = &uart5;
+ };
+
+ chosen {
+ stdout-path = &uart5;
+ bootargs = "console=ttyS4,115200n8";
+ };
+
+ memory@80000000 {
+ device_type = "memory";
+ reg = <0x80000000 0x40000000>;
+ };
+
+ reserved-memory {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ flash_memory: region@B8000000 {
+ no-map;
+ reg = <0xB8000000 0x04000000>; /* 64M */
+ };
+
+ vga_memory: region@bf000000 {
+ no-map;
+ compatible = "shared-dma-pool";
+ reg = <0xbf000000 0x01000000>; /* 16M */
+ };
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+
+ ps0-presence {
+ label = "ps0-presence";
+ gpios = <&gpio0 ASPEED_GPIO(S, 0) GPIO_ACTIVE_LOW>;
+ linux,code = <ASPEED_GPIO(S, 0)>;
+ };
+
+ ps1-presence {
+ label = "ps1-presence";
+ gpios = <&gpio0 ASPEED_GPIO(S, 1) GPIO_ACTIVE_LOW>;
+ linux,code = <ASPEED_GPIO(S, 1)>;
+ };
+
+ ps2-presence {
+ label = "ps2-presence";
+ gpios = <&gpio0 ASPEED_GPIO(S, 2) GPIO_ACTIVE_LOW>;
+ linux,code = <ASPEED_GPIO(S, 2)>;
+ };
+
+ ps3-presence {
+ label = "ps3-presence";
+ gpios = <&gpio0 ASPEED_GPIO(S, 3) GPIO_ACTIVE_LOW>;
+ linux,code = <ASPEED_GPIO(S, 3)>;
+ };
+ };
+
+};
+
+&gpio0 {
+ gpio-line-names =
+ /*A0-A7*/ "","","","","","","","",
+ /*B0-B7*/ "","","","","","","checkstop","",
+ /*C0-C7*/ "","","","","","","","",
+ /*D0-D7*/ "","","","","","","","",
+ /*E0-E7*/ "","","","","","","","",
+ /*F0-F7*/ "","","","","","","","",
+ /*G0-G7*/ "","","","","","","","",
+ /*H0-H7*/ "","","","","","","","",
+ /*I0-I7*/ "","","","","","","","",
+ /*J0-J7*/ "","","","","","","","",
+ /*K0-K7*/ "","","","","","","","",
+ /*L0-L7*/ "","","","","","","","",
+ /*M0-M7*/ "","","","","","","","",
+ /*N0-N7*/ "","","","","","","","",
+ /*O0-O7*/ "","","","","","","","",
+ /*P0-P7*/ "","","","","","","","",
+ /*Q0-Q7*/ "cfam-reset","","","","","","","",
+ /*R0-R7*/ "","","","","","","","",
+ /*S0-S7*/ "presence-ps0","presence-ps1","presence-ps2","presence-ps3",
+ "","","","",
+ /*T0-T7*/ "","","","","","","","",
+ /*U0-U7*/ "","","","","","","","",
+ /*V0-V7*/ "","","","","","","","",
+ /*W0-W7*/ "","","","","","","","",
+ /*X0-X7*/ "","","","","","","","",
+ /*Y0-Y7*/ "","","","","","","","",
+ /*Z0-Z7*/ "","","","","","","","",
+ /*AA0-AA7*/ "","","","","","","","",
+ /*AB0-AB7*/ "","","","","","","","",
+ /*AC0-AC7*/ "","","","","","","","";
+
+ pin_mclr_vpp {
+ gpio-hog;
+ gpios = <ASPEED_GPIO(P, 7) GPIO_OPEN_DRAIN>;
+ output-high;
+ line-name = "mclr_vpp";
+ };
+};
+
+&emmc_controller {
+ status = "okay";
+};
+
+&emmc {
+ status = "okay";
+};
+
+&fsim0 {
+ status = "okay";
+
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ cfam@0,0 {
+ reg = <0 0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ chip-id = <0>;
+
+ scom@1000 {
+ compatible = "ibm,fsi2pib";
+ reg = <0x1000 0x400>;
+ };
+
+ sbefifo@2400 {
+ compatible = "ibm,p9-sbefifo";
+ reg = <0x2400 0x400>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ fsi_occ0: occ {
+ compatible = "ibm,p9-occ";
+ };
+ };
+
+ fsi_hub0: hub@3400 {
+ compatible = "fsi-master-hub";
+ reg = <0x3400 0x400>;
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ no-scan-on-init;
+ };
+ };
+};
+
+&fsi_hub0 {
+ cfam@1,0 {
+ reg = <1 0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ chip-id = <1>;
+
+ scom@1000 {
+ compatible = "ibm,fsi2pib";
+ reg = <0x1000 0x400>;
+ };
+
+ sbefifo@2400 {
+ compatible = "ibm,p9-sbefifo";
+ reg = <0x2400 0x400>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ fsi_occ1: occ {
+ compatible = "ibm,p9-occ";
+ };
+ };
+
+ fsi_hub1: hub@3400 {
+ compatible = "fsi-master-hub";
+ reg = <0x3400 0x400>;
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ no-scan-on-init;
+ };
+ };
+
+ cfam@2,0 {
+ reg = <2 0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ chip-id = <2>;
+
+ scom@1000 {
+ compatible = "ibm,fsi2pib";
+ reg = <0x1000 0x400>;
+ };
+
+ sbefifo@2400 {
+ compatible = "ibm,p9-sbefifo";
+ reg = <0x2400 0x400>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ fsi_occ2: occ {
+ compatible = "ibm,p9-occ";
+ };
+ };
+
+ fsi_hub2: hub@3400 {
+ compatible = "fsi-master-hub";
+ reg = <0x3400 0x400>;
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ no-scan-on-init;
+ };
+ };
+};
+
+/* Legacy OCC numbering (to get rid of when userspace is fixed) */
+&fsi_occ0 {
+ reg = <1>;
+};
+
+&fsi_occ1 {
+ reg = <2>;
+};
+
+&fsi_occ2 {
+ reg = <3>;
+};
+
+&ibt {
+ status = "okay";
+};
+
+&i2c0 {
+ status = "okay";
+
+ eeprom@51 {
+ compatible = "atmel,24c64";
+ reg = <0x51>;
+ };
+};
+
+&i2c1 {
+ status = "okay";
+};
+
+&i2c2 {
+ status = "okay";
+};
+
+&i2c3 {
+ status = "okay";
+
+ power-supply@68 {
+ compatible = "ibm,cffps";
+ reg = <0x68>;
+ };
+
+ power-supply@69 {
+ compatible = "ibm,cffps";
+ reg = <0x69>;
+ };
+
+ power-supply@6a {
+ compatible = "ibm,cffps";
+ reg = <0x6a>;
+ };
+
+ power-supply@6b {
+ compatible = "ibm,cffps";
+ reg = <0x6b>;
+ };
+};
+
+&i2c4 {
+ status = "okay";
+
+ tmp275@48 {
+ compatible = "ti,tmp275";
+ reg = <0x48>;
+ };
+
+ tmp275@49 {
+ compatible = "ti,tmp275";
+ reg = <0x49>;
+ };
+
+ tmp275@4a {
+ compatible = "ti,tmp275";
+ reg = <0x4a>;
+ };
+
+ eeprom@50 {
+ compatible = "atmel,24c64";
+ reg = <0x50>;
+ };
+
+ eeprom@51 {
+ compatible = "atmel,24c64";
+ reg = <0x51>;
+ };
+
+ eeprom@52 {
+ compatible = "atmel,24c64";
+ reg = <0x52>;
+ };
+};
+
+&i2c5 {
+ status = "okay";
+
+ tmp275@48 {
+ compatible = "ti,tmp275";
+ reg = <0x48>;
+ };
+
+ tmp275@49 {
+ compatible = "ti,tmp275";
+ reg = <0x49>;
+ };
+
+ eeprom@50 {
+ compatible = "atmel,24c64";
+ reg = <0x50>;
+ };
+
+ eeprom@51 {
+ compatible = "atmel,24c64";
+ reg = <0x51>;
+ };
+};
+
+&i2c6 {
+ status = "okay";
+
+ tmp275@48 {
+ compatible = "ti,tmp275";
+ reg = <0x48>;
+ };
+
+ tmp275@4a {
+ compatible = "ti,tmp275";
+ reg = <0x4a>;
+ };
+
+ tmp275@4b {
+ compatible = "ti,tmp275";
+ reg = <0x4b>;
+ };
+
+ eeprom@50 {
+ compatible = "atmel,24c64";
+ reg = <0x50>;
+ };
+
+ eeprom@51 {
+ compatible = "atmel,24c64";
+ reg = <0x51>;
+ };
+
+ eeprom@52 {
+ compatible = "atmel,24c64";
+ reg = <0x52>;
+ };
+
+ eeprom@53 {
+ compatible = "atmel,24c64";
+ reg = <0x53>;
+ };
+};
+
+&i2c7 {
+ status = "okay";
+
+ si7021-a20@20 {
+ compatible = "silabs,si7020";
+ reg = <0x20>;
+ };
+
+ tmp275@48 {
+ compatible = "ti,tmp275";
+ reg = <0x48>;
+ };
+
+ max31785@52 {
+ compatible = "maxim,max31785a";
+ reg = <0x52>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ fan@0 {
+ compatible = "pmbus-fan";
+ reg = <0>;
+ tach-pulses = <2>;
+ };
+
+ fan@1 {
+ compatible = "pmbus-fan";
+ reg = <1>;
+ tach-pulses = <2>;
+ };
+
+ fan@2 {
+ compatible = "pmbus-fan";
+ reg = <2>;
+ tach-pulses = <2>;
+ };
+
+ fan@3 {
+ compatible = "pmbus-fan";
+ reg = <3>;
+ tach-pulses = <2>;
+ };
+ };
+
+ pca0: pca9552@61 {
+ compatible = "nxp,pca9552";
+ reg = <0x61>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ gpio@0 {
+ reg = <0>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@1 {
+ reg = <1>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@2 {
+ reg = <2>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@3 {
+ reg = <3>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@4 {
+ reg = <4>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@5 {
+ reg = <5>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@6 {
+ reg = <6>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@7 {
+ reg = <7>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@8 {
+ reg = <8>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@9 {
+ reg = <9>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@10 {
+ reg = <10>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@11 {
+ reg = <11>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@12 {
+ reg = <12>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@13 {
+ reg = <13>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@14 {
+ reg = <14>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@15 {
+ reg = <15>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+ };
+
+ dps: dps310@76 {
+ compatible = "infineon,dps310";
+ reg = <0x76>;
+ #io-channel-cells = <0>;
+ };
+
+ eeprom@50 {
+ compatible = "atmel,24c64";
+ reg = <0x50>;
+ };
+
+ eeprom@51 {
+ compatible = "atmel,24c64";
+ reg = <0x51>;
+ };
+};
+
+&i2c8 {
+ status = "okay";
+
+ ucd90320@11 {
+ compatible = "ti,ucd90320";
+ reg = <0x11>;
+ };
+
+ rtc@32 {
+ compatible = "epson,rx8900";
+ reg = <0x32>;
+ };
+
+ tmp275@48 {
+ compatible = "ti,tmp275";
+ reg = <0x48>;
+ };
+
+ tmp275@4a {
+ compatible = "ti,tmp275";
+ reg = <0x4a>;
+ };
+
+ eeprom@50 {
+ compatible = "atmel,24c64";
+ reg = <0x50>;
+ };
+
+ eeprom@51 {
+ compatible = "atmel,24c64";
+ reg = <0x51>;
+ };
+};
+
+&i2c9 {
+ status = "okay";
+
+ tmp423a@4c {
+ compatible = "ti,tmp423";
+ reg = <0x4c>;
+ };
+
+ tmp423b@4d {
+ compatible = "ti,tmp423";
+ reg = <0x4d>;
+ };
+
+ eeprom@50 {
+ compatible = "atmel,24c128";
+ reg = <0x50>;
+ };
+};
+
+&i2c10 {
+ status = "okay";
+
+ tmp423a@4c {
+ compatible = "ti,tmp423";
+ reg = <0x4c>;
+ };
+
+ tmp423b@4d {
+ compatible = "ti,tmp423";
+ reg = <0x4d>;
+ };
+
+ eeprom@50 {
+ compatible = "atmel,24c128";
+ reg = <0x50>;
+ };
+};
+
+&i2c11 {
+ status = "okay";
+
+ tmp275@48 {
+ compatible = "ti,tmp275";
+ reg = <0x48>;
+ };
+
+ tmp275@49 {
+ compatible = "ti,tmp275";
+ reg = <0x49>;
+ };
+
+ eeprom@50 {
+ compatible = "atmel,24c64";
+ reg = <0x50>;
+ };
+
+ eeprom@51 {
+ compatible = "atmel,24c64";
+ reg = <0x51>;
+ };
+};
+
+&i2c12 {
+ status = "okay";
+};
+
+&i2c13 {
+ status = "okay";
+
+ eeprom@50 {
+ compatible = "atmel,24c64";
+ reg = <0x50>;
+ };
+};
+
+&i2c14 {
+ status = "okay";
+
+ eeprom@50 {
+ compatible = "atmel,24c64";
+ reg = <0x50>;
+ };
+};
+
+&i2c15 {
+ status = "okay";
+
+ eeprom@50 {
+ compatible = "atmel,24c64";
+ reg = <0x50>;
+ };
+};
+
+&vuart1 {
+ status = "okay";
+};
+
+&vuart2 {
+ status = "okay";
+};
+
+&lpc_ctrl {
+ status = "okay";
+ memory-region = <&flash_memory>;
+};
+
+&lpc_host {
+ kcs4: kcs4@0 {
+ compatible = "openbmc,mctp-lpc";
+ interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
+ status = "okay";
+ };
+};
+
+&mac2 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_rmii3_default>;
+ clocks = <&syscon ASPEED_CLK_GATE_MAC3CLK>,
+ <&syscon ASPEED_CLK_MAC3RCLK>;
+ clock-names = "MACCLK", "RCLK";
+ use-ncsi;
+};
+
+&mac3 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_rmii4_default>;
+ clocks = <&syscon ASPEED_CLK_GATE_MAC4CLK>,
+ <&syscon ASPEED_CLK_MAC4RCLK>;
+ clock-names = "MACCLK", "RCLK";
+ use-ncsi;
+};
+
+&fmc {
+ status = "okay";
+ flash@0 {
+ status = "okay";
+ m25p,fast-read;
+ label = "bmc";
+ spi-max-frequency = <50000000>;
+#include "openbmc-flash-layout-128.dtsi"
+ };
+};
+
+&spi1 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_spi1_default>;
+
+ flash@0 {
+ status = "okay";
+ m25p,fast-read;
+ label = "pnor";
+ spi-max-frequency = <100000000>;
+ };
+};
+
+&xdma {
+ status = "okay";
+ memory-region = <&vga_memory>;
+};
diff --git a/arch/arm/boot/dts/aspeed-bmc-inspur-fp5280g2.dts b/arch/arm/boot/dts/aspeed-bmc-inspur-fp5280g2.dts
index e9d714a46a60..c17bb7fce7ff 100644
--- a/arch/arm/boot/dts/aspeed-bmc-inspur-fp5280g2.dts
+++ b/arch/arm/boot/dts/aspeed-bmc-inspur-fp5280g2.dts
@@ -148,14 +148,48 @@
};
leds {
- compatible = "gpio-leds";
+ compatible = "gpio-leds";
- power {
- label = "power";
- /* TODO: dummy gpio */
- gpios = <&gpio ASPEED_GPIO(R, 1) GPIO_ACTIVE_LOW>;
- };
+ power {
+ label = "power";
+ /* TODO: dummy gpio */
+ gpios = <&gpio ASPEED_GPIO(R, 1) GPIO_ACTIVE_LOW>;
+ };
+
+ init-ok {
+ label = "init-ok";
+ gpios = <&gpio ASPEED_GPIO(B, 7) GPIO_ACTIVE_LOW>;
+ };
+
+ front-memory {
+ label = "front-memory";
+ gpios = <&gpio ASPEED_GPIO(F, 4) GPIO_ACTIVE_LOW>;
+ };
+
+ front-syshot {
+ label = "front-syshot";
+ gpios = <&gpio ASPEED_GPIO(I, 1) GPIO_ACTIVE_LOW>;
+ };
+
+ front-syshealth {
+ label = "front-syshealth";
+ gpios = <&gpio ASPEED_GPIO(I, 0) GPIO_ACTIVE_LOW>;
+ };
+ front-fan {
+ label = "front-fan";
+ gpios = <&gpio ASPEED_GPIO(H, 4) GPIO_ACTIVE_LOW>;
+ };
+
+ front-psu {
+ label = "front-psu";
+ gpios = <&gpio ASPEED_GPIO(B, 2) GPIO_ACTIVE_LOW>;
+ };
+
+ identify {
+ label = "identify";
+ gpios = <&gpio ASPEED_GPIO(Z, 7) GPIO_ACTIVE_LOW>;
+ };
};
iio-hwmon-battery {
@@ -239,6 +273,9 @@
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_rmii1_default>;
+ clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>,
+ <&syscon ASPEED_CLK_MAC1RCLK>;
+ clock-names = "MACCLK", "RCLK";
use-ncsi;
};
@@ -749,15 +786,6 @@
aspeed,external-nodes = <&gfx &lhc>;
};
-&gpio {
- pin_gpio_b7 {
- gpio-hog;
- gpios = <ASPEED_GPIO(B,7) GPIO_ACTIVE_LOW>;
- output-high;
- line-name = "BMC_INIT_OK";
- };
-};
-
&wdt1 {
aspeed,reset-type = "none";
aspeed,external-signal;
diff --git a/arch/arm/boot/dts/aspeed-bmc-inspur-on5263m5.dts b/arch/arm/boot/dts/aspeed-bmc-inspur-on5263m5.dts
index 2337ee23f5c4..80c92e065a10 100644
--- a/arch/arm/boot/dts/aspeed-bmc-inspur-on5263m5.dts
+++ b/arch/arm/boot/dts/aspeed-bmc-inspur-on5263m5.dts
@@ -77,6 +77,9 @@
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_rmii1_default>;
+ clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>,
+ <&syscon ASPEED_CLK_MAC1RCLK>;
+ clock-names = "MACCLK", "RCLK";
use-ncsi;
};
diff --git a/arch/arm/boot/dts/aspeed-bmc-intel-s2600wf.dts b/arch/arm/boot/dts/aspeed-bmc-intel-s2600wf.dts
index 22dade6393d0..1deb30ec912c 100644
--- a/arch/arm/boot/dts/aspeed-bmc-intel-s2600wf.dts
+++ b/arch/arm/boot/dts/aspeed-bmc-intel-s2600wf.dts
@@ -69,6 +69,9 @@
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_rmii1_default>;
+ clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>,
+ <&syscon ASPEED_CLK_MAC1RCLK>;
+ clock-names = "MACCLK", "RCLK";
use-ncsi;
};
diff --git a/arch/arm/boot/dts/aspeed-bmc-lenovo-hr630.dts b/arch/arm/boot/dts/aspeed-bmc-lenovo-hr630.dts
index d3695a32e8e0..c29e5f4d86ad 100644
--- a/arch/arm/boot/dts/aspeed-bmc-lenovo-hr630.dts
+++ b/arch/arm/boot/dts/aspeed-bmc-lenovo-hr630.dts
@@ -133,6 +133,9 @@
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_rmii1_default>;
+ clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>,
+ <&syscon ASPEED_CLK_MAC1RCLK>;
+ clock-names = "MACCLK", "RCLK";
use-ncsi;
};
diff --git a/arch/arm/boot/dts/aspeed-bmc-lenovo-hr855xg2.dts b/arch/arm/boot/dts/aspeed-bmc-lenovo-hr855xg2.dts
index 118eb8bbbf1b..084c455ad4cb 100644
--- a/arch/arm/boot/dts/aspeed-bmc-lenovo-hr855xg2.dts
+++ b/arch/arm/boot/dts/aspeed-bmc-lenovo-hr855xg2.dts
@@ -139,6 +139,9 @@
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_rmii1_default>;
+ clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>,
+ <&syscon ASPEED_CLK_MAC1RCLK>;
+ clock-names = "MACCLK", "RCLK";
use-ncsi;
};
diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-lanyang.dts b/arch/arm/boot/dts/aspeed-bmc-opp-lanyang.dts
index de95112e2a04..42b37a204241 100644
--- a/arch/arm/boot/dts/aspeed-bmc-opp-lanyang.dts
+++ b/arch/arm/boot/dts/aspeed-bmc-opp-lanyang.dts
@@ -178,6 +178,9 @@
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_rmii1_default>;
+ clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>,
+ <&syscon ASPEED_CLK_MAC1RCLK>;
+ clock-names = "MACCLK", "RCLK";
use-ncsi;
};
diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-mihawk.dts b/arch/arm/boot/dts/aspeed-bmc-opp-mihawk.dts
index e55cc454b17f..091e77f77b1e 100644
--- a/arch/arm/boot/dts/aspeed-bmc-opp-mihawk.dts
+++ b/arch/arm/boot/dts/aspeed-bmc-opp-mihawk.dts
@@ -7,7 +7,52 @@
/ {
model = "Mihawk BMC";
compatible = "ibm,mihawk-bmc", "aspeed,ast2500";
-
+ aliases {
+ i2c215 = &bus6_mux215;
+ i2c216 = &bus6_mux216;
+ i2c217 = &bus6_mux217;
+ i2c218 = &bus6_mux218;
+ i2c219 = &bus6_mux219;
+ i2c220 = &bus6_mux220;
+ i2c221 = &bus6_mux221;
+ i2c222 = &bus6_mux222;
+ i2c223 = &bus7_mux223;
+ i2c224 = &bus7_mux224;
+ i2c225 = &bus7_mux225;
+ i2c226 = &bus7_mux226;
+ i2c227 = &bus7_mux227;
+ i2c228 = &bus7_mux228;
+ i2c229 = &bus7_mux229;
+ i2c230 = &bus7_mux230;
+ i2c231 = &bus9_mux231;
+ i2c232 = &bus9_mux232;
+ i2c233 = &bus9_mux233;
+ i2c234 = &bus9_mux234;
+ i2c235 = &bus9_mux235;
+ i2c236 = &bus9_mux236;
+ i2c237 = &bus9_mux237;
+ i2c238 = &bus9_mux238;
+ i2c239 = &bus10_mux239;
+ i2c240 = &bus10_mux240;
+ i2c241 = &bus10_mux241;
+ i2c242 = &bus10_mux242;
+ i2c243 = &bus10_mux243;
+ i2c244 = &bus10_mux244;
+ i2c245 = &bus10_mux245;
+ i2c246 = &bus10_mux246;
+ i2c247 = &bus12_mux247;
+ i2c248 = &bus12_mux248;
+ i2c249 = &bus12_mux249;
+ i2c250 = &bus12_mux250;
+ i2c251 = &bus13_mux251;
+ i2c252 = &bus13_mux252;
+ i2c253 = &bus13_mux253;
+ i2c254 = &bus13_mux254;
+ i2c255 = &bus13_mux255;
+ i2c256 = &bus13_mux256;
+ i2c257 = &bus13_mux257;
+ i2c258 = &bus13_mux258;
+ };
chosen {
stdout-path = &uart5;
@@ -120,35 +165,24 @@
leds {
compatible = "gpio-leds";
- fault {
+ front-fault {
retain-state-shutdown;
default-state = "keep";
gpios = <&gpio ASPEED_GPIO(AA, 0) GPIO_ACTIVE_LOW>;
};
- power {
+ power-button {
retain-state-shutdown;
default-state = "keep";
gpios = <&gpio ASPEED_GPIO(AA, 1) GPIO_ACTIVE_LOW>;
};
- rear-id {
+ front-id {
retain-state-shutdown;
default-state = "keep";
gpios = <&gpio ASPEED_GPIO(AA, 2) GPIO_ACTIVE_LOW>;
};
- rear-g {
- retain-state-shutdown;
- default-state = "keep";
- gpios = <&gpio ASPEED_GPIO(AA, 4) GPIO_ACTIVE_LOW>;
- };
-
- rear-ok {
- retain-state-shutdown;
- default-state = "keep";
- gpios = <&gpio ASPEED_GPIO(Y, 0) GPIO_ACTIVE_LOW>;
- };
fan0 {
retain-state-shutdown;
@@ -449,6 +483,9 @@
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_rmii1_default>;
+ clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>,
+ <&syscon ASPEED_CLK_MAC1RCLK>;
+ clock-names = "MACCLK", "RCLK";
use-ncsi;
};
@@ -627,6 +664,55 @@
#address-cells = <1>;
#size-cells = <0>;
reg = <0x70>;
+
+ bus7_mux223: i2c@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+ };
+
+ bus7_mux224: i2c@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+ };
+
+ bus7_mux225: i2c@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+ };
+
+ bus7_mux226: i2c@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+ };
+
+ bus7_mux227: i2c@4 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <4>;
+ };
+
+ bus7_mux228: i2c@5 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <5>;
+ };
+
+ bus7_mux229: i2c@6 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <6>;
+ };
+
+ bus7_mux230: i2c@7 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <7>;
+ };
+
};
};
@@ -641,6 +727,55 @@
#address-cells = <1>;
#size-cells = <0>;
reg = <0x70>;
+
+ bus6_mux215: i2c@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+ };
+
+ bus6_mux216: i2c@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+ };
+
+ bus6_mux217: i2c@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+ };
+
+ bus6_mux218: i2c@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+ };
+
+ bus6_mux219: i2c@4 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <4>;
+ };
+
+ bus6_mux220: i2c@5 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <5>;
+ };
+
+ bus6_mux221: i2c@6 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <6>;
+ };
+
+ bus6_mux222: i2c@7 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <7>;
+ };
+
};
};
@@ -681,6 +816,68 @@
i2c-mux-idle-disconnect;
interrupt-controller;
#interrupt-cells = <2>;
+
+ bus9_mux231: i2c@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ tca9554@39 {
+ compatible = "ti,tca9554";
+ reg = <0x39>;
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ smbus0 {
+ gpio-hog;
+ gpios = <4 GPIO_ACTIVE_HIGH>;
+ output-high;
+ line-name = "smbus0";
+ };
+ };
+
+ tmp431@4c {
+ compatible = "ti,tmp401";
+ reg = <0x4c>;
+ };
+ };
+
+ bus9_mux232: i2c@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ tca9554@39 {
+ compatible = "ti,tca9554";
+ reg = <0x39>;
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ smbus1 {
+ gpio-hog;
+ gpios = <4 GPIO_ACTIVE_HIGH>;
+ output-high;
+ line-name = "smbus1";
+ };
+ };
+
+ tmp431@4c {
+ compatible = "ti,tmp401";
+ reg = <0x4c>;
+ };
+ };
+
+ bus9_mux233: i2c@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+ };
+
+ bus9_mux234: i2c@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+ };
};
pca9545@71 {
@@ -692,6 +889,68 @@
i2c-mux-idle-disconnect;
interrupt-controller;
#interrupt-cells = <2>;
+
+ bus9_mux235: i2c@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ tca9554@39 {
+ compatible = "ti,tca9554";
+ reg = <0x39>;
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ smbus2 {
+ gpio-hog;
+ gpios = <4 GPIO_ACTIVE_HIGH>;
+ output-high;
+ line-name = "smbus2";
+ };
+ };
+
+ tmp431@4c {
+ compatible = "ti,tmp401";
+ reg = <0x4c>;
+ };
+ };
+
+ bus9_mux236: i2c@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ tca9554@39 {
+ compatible = "ti,tca9554";
+ reg = <0x39>;
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ smbus3 {
+ gpio-hog;
+ gpios = <4 GPIO_ACTIVE_HIGH>;
+ output-high;
+ line-name = "smbus3";
+ };
+ };
+
+ tmp431@4c {
+ compatible = "ti,tmp401";
+ reg = <0x4c>;
+ };
+ };
+
+ bus9_mux237: i2c@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+ };
+
+ bus9_mux238: i2c@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+ };
};
};
@@ -722,6 +981,68 @@
i2c-mux-idle-disconnect;
interrupt-controller;
#interrupt-cells = <2>;
+
+ bus10_mux239: i2c@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ tca9554@39 {
+ compatible = "ti,tca9554";
+ reg = <0x39>;
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ smbus4 {
+ gpio-hog;
+ gpios = <4 GPIO_ACTIVE_HIGH>;
+ output-high;
+ line-name = "smbus4";
+ };
+ };
+
+ tmp431@4c {
+ compatible = "ti,tmp401";
+ reg = <0x4c>;
+ };
+ };
+
+ bus10_mux240: i2c@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ tca9554@39 {
+ compatible = "ti,tca9554";
+ reg = <0x39>;
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ smbus5 {
+ gpio-hog;
+ gpios = <4 GPIO_ACTIVE_HIGH>;
+ output-high;
+ line-name = "smbus5";
+ };
+ };
+
+ tmp431@4c {
+ compatible = "ti,tmp401";
+ reg = <0x4c>;
+ };
+ };
+
+ bus10_mux241: i2c@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+ };
+
+ bus10_mux242: i2c@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+ };
};
pca9545@71 {
@@ -733,6 +1054,68 @@
i2c-mux-idle-disconnect;
interrupt-controller;
#interrupt-cells = <2>;
+
+ bus10_mux243: i2c@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ tca9554@39 {
+ compatible = "ti,tca9554";
+ reg = <0x39>;
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ smbus6 {
+ gpio-hog;
+ gpios = <4 GPIO_ACTIVE_HIGH>;
+ output-high;
+ line-name = "smbus6";
+ };
+ };
+
+ tmp431@4c {
+ compatible = "ti,tmp401";
+ reg = <0x4c>;
+ };
+ };
+
+ bus10_mux244: i2c@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ tca9554@39 {
+ compatible = "ti,tca9554";
+ reg = <0x39>;
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ smbus7 {
+ gpio-hog;
+ gpios = <4 GPIO_ACTIVE_HIGH>;
+ output-high;
+ line-name = "smbus7";
+ };
+ };
+
+ tmp431@4c {
+ compatible = "ti,tmp401";
+ reg = <0x4c>;
+ };
+ };
+
+ bus10_mux245: i2c@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+ };
+
+ bus10_mux246: i2c@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+ };
};
};
@@ -793,7 +1176,7 @@
interrupt-controller;
#interrupt-cells = <2>;
- i2c@0 {
+ bus12_mux247: i2c@0 {
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;
@@ -804,7 +1187,7 @@
};
};
- i2c@1 {
+ bus12_mux248: i2c@1 {
#address-cells = <1>;
#size-cells = <0>;
reg = <1>;
@@ -815,7 +1198,7 @@
};
};
- i2c@2 {
+ bus12_mux249: i2c@2 {
#address-cells = <1>;
#size-cells = <0>;
reg = <2>;
@@ -826,7 +1209,7 @@
};
};
- i2c@3 {
+ bus12_mux250: i2c@3 {
#address-cells = <1>;
#size-cells = <0>;
reg = <3>;
@@ -854,6 +1237,54 @@
#address-cells = <1>;
#size-cells = <0>;
reg = <0x70>;
+
+ bus13_mux251: i2c@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+ };
+
+ bus13_mux252: i2c@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+ };
+
+ bus13_mux253: i2c@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+ };
+
+ bus13_mux254: i2c@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+ };
+
+ bus13_mux255: i2c@4 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <4>;
+ };
+
+ bus13_mux256: i2c@5 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <5>;
+ };
+
+ bus13_mux257: i2c@6 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <6>;
+ };
+
+ bus13_mux258: i2c@7 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <7>;
+ };
};
};
diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts b/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts
index b0cb34ccb135..eb4e93a57ff4 100644
--- a/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts
+++ b/arch/arm/boot/dts/aspeed-bmc-opp-palmetto.dts
@@ -87,6 +87,7 @@
status = "okay";
m25p,fast-read;
label = "bmc";
+ spi-max-frequency = <50000000>;
#include "openbmc-flash-layout.dtsi"
};
};
@@ -99,6 +100,7 @@
flash@0 {
status = "okay";
m25p,fast-read;
+ spi-max-frequency = <50000000>;
label = "pnor";
};
};
diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-romulus.dts b/arch/arm/boot/dts/aspeed-bmc-opp-romulus.dts
index 9628ecb879cf..fd2e014dae75 100644
--- a/arch/arm/boot/dts/aspeed-bmc-opp-romulus.dts
+++ b/arch/arm/boot/dts/aspeed-bmc-opp-romulus.dts
@@ -112,6 +112,7 @@
status = "okay";
m25p,fast-read;
label = "bmc";
+ spi-max-frequency = <50000000>;
#include "openbmc-flash-layout.dtsi"
};
};
@@ -125,6 +126,7 @@
status = "okay";
m25p,fast-read;
label = "pnor";
+ spi-max-frequency = <100000000>;
};
};
@@ -160,6 +162,9 @@
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_rmii1_default>;
+ clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>,
+ <&syscon ASPEED_CLK_MAC1RCLK>;
+ clock-names = "MACCLK", "RCLK";
};
&i2c1 {
@@ -226,23 +231,52 @@
};
&gpio {
+ gpio-line-names =
+ /*A0-A7*/ "","cfam-reset","","","","","fsi-mux","",
+ /*B0-B7*/ "","","","","","","","",
+ /*C0-C7*/ "","","","","","","","",
+ /*D0-D7*/ "fsi-enable","","","nic_func_mode0","nic_func_mode1","","","",
+ /*E0-E7*/ "","","","","","","","",
+ /*F0-F7*/ "","","","","","","","",
+ /*G0-G7*/ "","","","","","","","",
+ /*H0-H7*/ "","","","","","","","",
+ /*I0-I7*/ "","","","power-button","","","","",
+ /*J0-J7*/ "","","checkstop","","","","","",
+ /*K0-K7*/ "","","","","","","","",
+ /*L0-L7*/ "","","","","","","","",
+ /*M0-M7*/ "","","","","","","","",
+ /*N0-N7*/ "","","led-fault","",
+ "led-identify","","","",
+ /*O0-O7*/ "","","","","","","","",
+ /*P0-P7*/ "","","","","","","","",
+ /*Q0-Q7*/ "","","","","","","","id-button",
+ /*R0-R7*/ "","","fsi-trans","","","led-power","","",
+ /*S0-S7*/ "","","","","","","","seq_cont",
+ /*T0-T7*/ "","","","","","","","",
+ /*U0-U7*/ "","","","","","","","",
+ /*V0-V7*/ "","","","","","","","",
+ /*W0-W7*/ "","","","","","","","",
+ /*X0-X7*/ "","","","","","","","",
+ /*Y0-Y7*/ "","","","","","","","",
+ /*Z0-Z7*/ "","","","","","","","",
+ /*AA0-AA7*/ "fsi-clock","","fsi-data","","","","","",
+ /*AB0-AB7*/ "","","","","","","","",
+ /*AC0-AC7*/ "","","","","","","","";
+
nic_func_mode0 {
gpio-hog;
gpios = <ASPEED_GPIO(D, 3) GPIO_ACTIVE_HIGH>;
output-low;
- line-name = "nic_func_mode0";
};
nic_func_mode1 {
gpio-hog;
gpios = <ASPEED_GPIO(D, 4) GPIO_ACTIVE_HIGH>;
output-low;
- line-name = "nic_func_mode1";
};
seq_cont {
gpio-hog;
gpios = <ASPEED_GPIO(S, 7) GPIO_ACTIVE_HIGH>;
output-low;
- line-name = "seq_cont";
};
};
diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-swift.dts b/arch/arm/boot/dts/aspeed-bmc-opp-swift.dts
index f67fef1ac5e1..b8fdd2a8a2c9 100644
--- a/arch/arm/boot/dts/aspeed-bmc-opp-swift.dts
+++ b/arch/arm/boot/dts/aspeed-bmc-opp-swift.dts
@@ -322,6 +322,9 @@
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_rmii1_default>;
use-ncsi;
+ clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>,
+ <&syscon ASPEED_CLK_MAC1RCLK>;
+ clock-names = "MACCLK", "RCLK";
};
&i2c2 {
diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-tacoma.dts b/arch/arm/boot/dts/aspeed-bmc-opp-tacoma.dts
new file mode 100644
index 000000000000..96a45014b7e5
--- /dev/null
+++ b/arch/arm/boot/dts/aspeed-bmc-opp-tacoma.dts
@@ -0,0 +1,868 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// Copyright 2019 IBM Corp.
+/dts-v1/;
+
+#include "aspeed-g6.dtsi"
+#include <dt-bindings/gpio/aspeed-gpio.h>
+#include <dt-bindings/leds/leds-pca955x.h>
+
+/ {
+ model = "Tacoma";
+ compatible = "ibm,tacoma-bmc", "aspeed,ast2600";
+
+ chosen {
+ stdout-path = &uart5;
+ bootargs = "console=ttyS4,115200n8";
+ };
+
+ memory@80000000 {
+ device_type = "memory";
+ reg = <0x80000000 0x40000000>;
+ };
+
+ reserved-memory {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ flash_memory: region@ba000000 {
+ no-map;
+ reg = <0xb8000000 0x4000000>; /* 64M */
+ };
+
+ vga_memory: region@bf000000 {
+ no-map;
+ compatible = "shared-dma-pool";
+ reg = <0xbf000000 0x01000000>; /* 16M */
+ };
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+
+ ps0-presence {
+ label = "ps0-presence";
+ gpios = <&gpio0 ASPEED_GPIO(H, 3) GPIO_ACTIVE_LOW>;
+ linux,code = <ASPEED_GPIO(H, 3)>;
+ };
+
+ ps1-presence {
+ label = "ps1-presence";
+ gpios = <&gpio0 ASPEED_GPIO(E, 5) GPIO_ACTIVE_LOW>;
+ linux,code = <ASPEED_GPIO(E, 5)>;
+ };
+ };
+
+ gpio-keys-polled {
+ compatible = "gpio-keys-polled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ poll-interval = <1000>;
+
+ fan0-presence {
+ label = "fan0-presence";
+ gpios = <&pca0 4 GPIO_ACTIVE_LOW>;
+ linux,code = <4>;
+ };
+
+ fan1-presence {
+ label = "fan1-presence";
+ gpios = <&pca0 5 GPIO_ACTIVE_LOW>;
+ linux,code = <5>;
+ };
+
+ fan2-presence {
+ label = "fan2-presence";
+ gpios = <&pca0 6 GPIO_ACTIVE_LOW>;
+ linux,code = <6>;
+ };
+
+ fan3-presence {
+ label = "fan3-presence";
+ gpios = <&pca0 7 GPIO_ACTIVE_LOW>;
+ linux,code = <7>;
+ };
+ };
+
+ iio-hwmon-dps310 {
+ compatible = "iio-hwmon";
+ io-channels = <&dps 0>;
+ };
+
+ iio-hwmon-bmp280 {
+ compatible = "iio-hwmon";
+ io-channels = <&bmp 1>;
+ };
+};
+
+&gpio0 {
+ gpio-line-names =
+ /*A0-A7*/ "","","","","","","","",
+ /*B0-B7*/ "fsi-mux","","","","","","","",
+ /*C0-C7*/ "","","","","","","","",
+ /*D0-D7*/ "","","","","","","","",
+ /*E0-E7*/ "power-button","","","checkstop","","presence-ps1","","led-rear-fault",
+ /*F0-F7*/ "","","","","","","","",
+ /*G0-G7*/ "","","","","","","","",
+ /*H0-H7*/ "","","","presence-ps0","","","","",
+ /*I0-I7*/ "","","","","","","","",
+ /*J0-J7*/ "","","","","","","","",
+ /*K0-K7*/ "","","","","","","","",
+ /*L0-L7*/ "","","","","","","","",
+ /*M0-M7*/ "","","","","","","","",
+ /*N0-N7*/ "","","","","","","","",
+ /*O0-O7*/ "led-rear-power","led-rear-id","","","","","","",
+ /*P0-P7*/ "","","","","","","","",
+ /*Q0-Q7*/ "cfam-reset","","","","","","","fsi-routing",
+ /*R0-R7*/ "","","","","","","","",
+ /*S0-S7*/ "","","","","","","","",
+ /*T0-T7*/ "","","","","","","","",
+ /*U0-U7*/ "","","","","","","","",
+ /*V0-V7*/ "","","","","","","","",
+ /*W0-W7*/ "","","","","","","","",
+ /*X0-X7*/ "","","","","","","","",
+ /*Y0-Y7*/ "","","","","","","","",
+ /*Z0-Z7*/ "","","","","","","","",
+ /*AA0-AA7*/ "","","","","","","","",
+ /*AB0-AB7*/ "","","","","","","","",
+ /*AC0-AC7*/ "","","","","","","","";
+};
+
+&fmc {
+ status = "okay";
+ flash@0 {
+ status = "okay";
+ m25p,fast-read;
+ label = "bmc";
+ spi-max-frequency = <50000000>;
+#include "openbmc-flash-layout-128.dtsi"
+ };
+
+ flash@1 {
+ status = "okay";
+ m25p,fast-read;
+ label = "alt-bmc";
+ spi-max-frequency = <50000000>;
+ };
+};
+
+&spi1 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_spi1_default>;
+
+ flash@0 {
+ status = "okay";
+ m25p,fast-read;
+ label = "pnor";
+ spi-max-frequency = <100000000>;
+ };
+};
+
+&mac2 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_rmii3_default>;
+ clocks = <&syscon ASPEED_CLK_GATE_MAC3CLK>,
+ <&syscon ASPEED_CLK_MAC3RCLK>;
+ clock-names = "MACCLK", "RCLK";
+ use-ncsi;
+};
+
+&emmc_controller {
+ status = "okay";
+};
+
+&emmc {
+ status = "okay";
+};
+
+&fsim0 {
+ status = "okay";
+
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ fsi-routing-gpios = <&gpio0 ASPEED_GPIO(Q, 7) GPIO_ACTIVE_HIGH>;
+ fsi-mux-gpios = <&gpio0 ASPEED_GPIO(B, 0) GPIO_ACTIVE_HIGH>;
+
+ cfam@0,0 {
+ reg = <0 0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ chip-id = <0>;
+
+ scom@1000 {
+ compatible = "ibm,fsi2pib";
+ reg = <0x1000 0x400>;
+ };
+
+ i2c@1800 {
+ compatible = "ibm,fsi-i2c-master";
+ reg = <0x1800 0x400>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cfam0_i2c0: i2c-bus@0 {
+ reg = <0>;
+ };
+
+ cfam0_i2c1: i2c-bus@1 {
+ reg = <1>;
+ };
+
+ cfam0_i2c2: i2c-bus@2 {
+ reg = <2>;
+ };
+
+ cfam0_i2c3: i2c-bus@3 {
+ reg = <3>;
+ };
+
+ cfam0_i2c4: i2c-bus@4 {
+ reg = <4>;
+ };
+
+ cfam0_i2c5: i2c-bus@5 {
+ reg = <5>;
+ };
+
+ cfam0_i2c6: i2c-bus@6 {
+ reg = <6>;
+ };
+
+ cfam0_i2c7: i2c-bus@7 {
+ reg = <7>;
+ };
+
+ cfam0_i2c8: i2c-bus@8 {
+ reg = <8>;
+ };
+
+ cfam0_i2c9: i2c-bus@9 {
+ reg = <9>;
+ };
+
+ cfam0_i2c10: i2c-bus@a {
+ reg = <10>;
+ };
+
+ cfam0_i2c11: i2c-bus@b {
+ reg = <11>;
+ };
+
+ cfam0_i2c12: i2c-bus@c {
+ reg = <12>;
+ };
+
+ cfam0_i2c13: i2c-bus@d {
+ reg = <13>;
+ };
+
+ cfam0_i2c14: i2c-bus@e {
+ reg = <14>;
+ };
+ };
+
+ sbefifo@2400 {
+ compatible = "ibm,p9-sbefifo";
+ reg = <0x2400 0x400>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ fsi_occ0: occ {
+ compatible = "ibm,p9-occ";
+ };
+ };
+
+ fsi_hub0: hub@3400 {
+ compatible = "fsi-master-hub";
+ reg = <0x3400 0x400>;
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ no-scan-on-init;
+ };
+ };
+};
+
+&fsi_hub0 {
+ cfam@1,0 {
+ reg = <1 0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ chip-id = <1>;
+
+ scom@1000 {
+ compatible = "ibm,fsi2pib";
+ reg = <0x1000 0x400>;
+ };
+
+ i2c@1800 {
+ compatible = "ibm,fsi-i2c-master";
+ reg = <0x1800 0x400>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cfam1_i2c0: i2c-bus@0 {
+ reg = <0>;
+ };
+
+ cfam1_i2c1: i2c-bus@1 {
+ reg = <1>;
+ };
+
+ cfam1_i2c2: i2c-bus@2 {
+ reg = <2>;
+ };
+
+ cfam1_i2c3: i2c-bus@3 {
+ reg = <3>;
+ };
+
+ cfam1_i2c4: i2c-bus@4 {
+ reg = <4>;
+ };
+
+ cfam1_i2c5: i2c-bus@5 {
+ reg = <5>;
+ };
+
+ cfam1_i2c6: i2c-bus@6 {
+ reg = <6>;
+ };
+
+ cfam1_i2c7: i2c-bus@7 {
+ reg = <7>;
+ };
+
+ cfam1_i2c8: i2c-bus@8 {
+ reg = <8>;
+ };
+
+ cfam1_i2c9: i2c-bus@9 {
+ reg = <9>;
+ };
+
+ cfam1_i2c10: i2c-bus@a {
+ reg = <10>;
+ };
+
+ cfam1_i2c11: i2c-bus@b {
+ reg = <11>;
+ };
+
+ cfam1_i2c12: i2c-bus@c {
+ reg = <12>;
+ };
+
+ cfam1_i2c13: i2c-bus@d {
+ reg = <13>;
+ };
+
+ cfam1_i2c14: i2c-bus@e {
+ reg = <14>;
+ };
+ };
+
+ sbefifo@2400 {
+ compatible = "ibm,p9-sbefifo";
+ reg = <0x2400 0x400>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ fsi_occ1: occ {
+ compatible = "ibm,p9-occ";
+ };
+ };
+
+ fsi_hub1: hub@3400 {
+ compatible = "fsi-master-hub";
+ reg = <0x3400 0x400>;
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ no-scan-on-init;
+ };
+ };
+};
+
+/* Legacy OCC numbering (to get rid of when userspace is fixed) */
+&fsi_occ0 {
+ reg = <1>;
+};
+
+&fsi_occ1 {
+ reg = <2>;
+};
+
+/ {
+ aliases {
+ i2c100 = &cfam0_i2c0;
+ i2c101 = &cfam0_i2c1;
+ i2c102 = &cfam0_i2c2;
+ i2c103 = &cfam0_i2c3;
+ i2c104 = &cfam0_i2c4;
+ i2c105 = &cfam0_i2c5;
+ i2c106 = &cfam0_i2c6;
+ i2c107 = &cfam0_i2c7;
+ i2c108 = &cfam0_i2c8;
+ i2c109 = &cfam0_i2c9;
+ i2c110 = &cfam0_i2c10;
+ i2c111 = &cfam0_i2c11;
+ i2c112 = &cfam0_i2c12;
+ i2c113 = &cfam0_i2c13;
+ i2c114 = &cfam0_i2c14;
+ i2c200 = &cfam1_i2c0;
+ i2c201 = &cfam1_i2c1;
+ i2c202 = &cfam1_i2c2;
+ i2c203 = &cfam1_i2c3;
+ i2c204 = &cfam1_i2c4;
+ i2c205 = &cfam1_i2c5;
+ i2c206 = &cfam1_i2c6;
+ i2c207 = &cfam1_i2c7;
+ i2c208 = &cfam1_i2c8;
+ i2c209 = &cfam1_i2c9;
+ i2c210 = &cfam1_i2c10;
+ i2c211 = &cfam1_i2c11;
+ i2c212 = &cfam1_i2c12;
+ i2c213 = &cfam1_i2c13;
+ i2c214 = &cfam1_i2c14;
+ };
+
+};
+
+&i2c0 {
+ status = "okay";
+};
+
+&i2c1 {
+ status = "okay";
+
+ tpm: tpm@2e {
+ compatible = "tcg,tpm-tis-i2c";
+ reg = <0x2e>;
+ };
+};
+
+&i2c2 {
+ status = "okay";
+};
+
+&i2c3 {
+ status = "okay";
+
+ bmp: bmp280@77 {
+ compatible = "bosch,bmp280";
+ reg = <0x77>;
+ #io-channel-cells = <1>;
+ };
+
+ max31785@52 {
+ compatible = "maxim,max31785a";
+ reg = <0x52>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ fan@0 {
+ compatible = "pmbus-fan";
+ reg = <0>;
+ tach-pulses = <2>;
+ maxim,fan-rotor-input = "tach";
+ maxim,fan-pwm-freq = <25000>;
+ maxim,fan-dual-tach;
+ maxim,fan-no-watchdog;
+ maxim,fan-no-fault-ramp;
+ maxim,fan-ramp = <2>;
+ maxim,fan-fault-pin-mon;
+ };
+
+ fan@1 {
+ compatible = "pmbus-fan";
+ reg = <1>;
+ tach-pulses = <2>;
+ maxim,fan-rotor-input = "tach";
+ maxim,fan-pwm-freq = <25000>;
+ maxim,fan-dual-tach;
+ maxim,fan-no-watchdog;
+ maxim,fan-no-fault-ramp;
+ maxim,fan-ramp = <2>;
+ maxim,fan-fault-pin-mon;
+ };
+
+ fan@2 {
+ compatible = "pmbus-fan";
+ reg = <2>;
+ tach-pulses = <2>;
+ maxim,fan-rotor-input = "tach";
+ maxim,fan-pwm-freq = <25000>;
+ maxim,fan-dual-tach;
+ maxim,fan-no-watchdog;
+ maxim,fan-no-fault-ramp;
+ maxim,fan-ramp = <2>;
+ maxim,fan-fault-pin-mon;
+ };
+
+ fan@3 {
+ compatible = "pmbus-fan";
+ reg = <3>;
+ tach-pulses = <2>;
+ maxim,fan-rotor-input = "tach";
+ maxim,fan-pwm-freq = <25000>;
+ maxim,fan-dual-tach;
+ maxim,fan-no-watchdog;
+ maxim,fan-no-fault-ramp;
+ maxim,fan-ramp = <2>;
+ maxim,fan-fault-pin-mon;
+ };
+ };
+
+ dps: dps310@76 {
+ compatible = "infineon,dps310";
+ reg = <0x76>;
+ #io-channel-cells = <0>;
+ };
+
+ pca0: pca9552@60 {
+ compatible = "nxp,pca9552";
+ reg = <0x60>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ gpio@0 {
+ reg = <0>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@1 {
+ reg = <1>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@2 {
+ reg = <2>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@3 {
+ reg = <3>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@4 {
+ reg = <4>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@5 {
+ reg = <5>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@6 {
+ reg = <6>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@7 {
+ reg = <7>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@8 {
+ reg = <8>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@9 {
+ reg = <9>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@10 {
+ reg = <10>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@11 {
+ reg = <11>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@12 {
+ reg = <12>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@13 {
+ reg = <13>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@14 {
+ reg = <14>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@15 {
+ reg = <15>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+ };
+
+ power-supply@68 {
+ compatible = "ibm,cffps1";
+ reg = <0x68>;
+ };
+
+ power-supply@69 {
+ compatible = "ibm,cffps1";
+ reg = <0x69>;
+ };
+};
+
+&i2c4 {
+ status = "okay";
+
+ tmp423a@4c {
+ compatible = "ti,tmp423";
+ reg = <0x4c>;
+ };
+
+ ir35221@70 {
+ compatible = "infineon,ir35221";
+ reg = <0x70>;
+ };
+
+ ir35221@71 {
+ compatible = "infineon,ir35221";
+ reg = <0x71>;
+ };
+};
+
+&i2c5 {
+ status = "okay";
+
+ tmp423a@4c {
+ compatible = "ti,tmp423";
+ reg = <0x4c>;
+ };
+
+ ir35221@70 {
+ compatible = "infineon,ir35221";
+ reg = <0x70>;
+ };
+
+ ir35221@71 {
+ compatible = "infineon,ir35221";
+ reg = <0x71>;
+ };
+};
+
+&i2c7 {
+ status = "okay";
+};
+
+&i2c9 {
+ status = "okay";
+
+ tmp275@4a {
+ compatible = "ti,tmp275";
+ reg = <0x4a>;
+ };
+};
+
+&i2c10 {
+ status = "okay";
+};
+
+&i2c11 {
+ status = "okay";
+
+ pca9552: pca9552@60 {
+ compatible = "nxp,pca9552";
+ reg = <0x60>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ gpio-line-names = "PS_SMBUS_RESET_N", "APSS_RESET_N",
+ "GPU0_TH_OVERT_N_BUFF", "GPU1_TH_OVERT_N_BUFF",
+ "GPU2_TH_OVERT_N_BUFF", "GPU3_TH_OVERT_N_BUFF",
+ "GPU4_TH_OVERT_N_BUFF", "GPU5_TH_OVERT_N_BUFF",
+ "GPU0_PWR_GOOD_BUFF", "GPU1_PWR_GOOD_BUFF",
+ "GPU2_PWR_GOOD_BUFF", "GPU3_PWR_GOOD_BUFF",
+ "GPU4_PWR_GOOD_BUFF", "GPU5_PWR_GOOD_BUFF",
+ "12V_BREAKER_FLT_N", "THROTTLE_UNLATCHED_N";
+
+ gpio@0 {
+ reg = <0>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@1 {
+ reg = <1>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@2 {
+ reg = <2>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@3 {
+ reg = <3>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@4 {
+ reg = <4>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@5 {
+ reg = <5>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@6 {
+ reg = <6>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@7 {
+ reg = <7>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@8 {
+ reg = <8>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@9 {
+ reg = <9>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@10 {
+ reg = <10>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@11 {
+ reg = <11>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@12 {
+ reg = <12>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@13 {
+ reg = <13>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@14 {
+ reg = <14>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+
+ gpio@15 {
+ reg = <15>;
+ type = <PCA955X_TYPE_GPIO>;
+ };
+ };
+
+ rtc@32 {
+ compatible = "epson,rx8900";
+ reg = <0x32>;
+ };
+
+ eeprom@51 {
+ compatible = "atmel,24c64";
+ reg = <0x51>;
+ };
+
+ ucd90160@64 {
+ compatible = "ti,ucd90160";
+ reg = <0x64>;
+ };
+};
+
+&i2c12 {
+ status = "okay";
+};
+
+&i2c13 {
+ status = "okay";
+};
+
+&ibt {
+ status = "okay";
+};
+
+&uart1 {
+ status = "okay";
+ // Workaround for A0
+ compatible = "snps,dw-apb-uart";
+};
+
+&uart5 {
+ // Workaround for A0
+ compatible = "snps,dw-apb-uart";
+};
+
+&vuart1 {
+ status = "okay";
+};
+
+&vuart2 {
+ status = "okay";
+};
+
+&lpc_ctrl {
+ status = "okay";
+ memory-region = <&flash_memory>;
+ flash = <&spi1>;
+};
+
+&wdt1 {
+ aspeed,reset-type = "none";
+ aspeed,external-signal;
+ aspeed,ext-push-pull;
+ aspeed,ext-active-high;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_wdtrst1_default>;
+};
+
+&wdt2 {
+ status = "okay";
+};
+
+&pinctrl {
+ /* Hog these as no driver is probed for the entire LPC block */
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_lpc_default>,
+ <&pinctrl_lsirq_default>;
+};
+
+&xdma {
+ status = "okay";
+ memory-region = <&vga_memory>;
+};
+
+&lpc_host {
+ kcs4: kcs4@0 {
+ compatible = "openbmc,mctp-lpc";
+ interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
+ status = "okay";
+ };
+};
diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-vesnin.dts b/arch/arm/boot/dts/aspeed-bmc-opp-vesnin.dts
index a27c88d23056..affd2c8743b1 100644
--- a/arch/arm/boot/dts/aspeed-bmc-opp-vesnin.dts
+++ b/arch/arm/boot/dts/aspeed-bmc-opp-vesnin.dts
@@ -43,6 +43,10 @@
gpios = <&gpio ASPEED_GPIO(N, 1) GPIO_ACTIVE_LOW>;
};
+ power_green {
+ gpios = <&gpio ASPEED_GPIO(F, 1) GPIO_ACTIVE_LOW>;
+ };
+
id_blue {
gpios = <&gpio ASPEED_GPIO(O, 0) GPIO_ACTIVE_LOW>;
};
diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-witherspoon-128.dts b/arch/arm/boot/dts/aspeed-bmc-opp-witherspoon-128.dts
new file mode 100644
index 000000000000..1ba673a49334
--- /dev/null
+++ b/arch/arm/boot/dts/aspeed-bmc-opp-witherspoon-128.dts
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// Copyright 2019 IBM Corp.
+/dts-v1/;
+
+#include "aspeed-bmc-opp-witherspoon.dts"
+
+&fmc {
+ status = "okay";
+
+ flash@0 {
+ status = "okay";
+ label = "bmc";
+ m25p,fast-read;
+ spi-max-frequency = <100000000>;
+
+ partitions {
+ #address-cells = < 1 >;
+ #size-cells = < 1 >;
+ compatible = "fixed-partitions";
+ u-boot@0 {
+ reg = < 0 0x60000 >;
+ label = "u-boot";
+ };
+ u-boot-env@60000 {
+ reg = < 0x60000 0x20000 >;
+ label = "u-boot-env";
+ };
+ obmc-ubi@80000 {
+ reg = < 0x80000 0x7F80000>;
+ label = "obmc-ubi";
+ };
+ };
+ };
+
+ flash@1 {
+ status = "okay";
+ label = "alt-bmc";
+ m25p,fast-read;
+ spi-max-frequency = <100000000>;
+
+ partitions {
+ #address-cells = < 1 >;
+ #size-cells = < 1 >;
+ compatible = "fixed-partitions";
+ u-boot@0 {
+ reg = < 0 0x60000 >;
+ label = "alt-u-boot";
+ };
+ u-boot-env@60000 {
+ reg = < 0x60000 0x20000 >;
+ label = "alt-u-boot-env";
+ };
+ obmc-ubi@80000 {
+ reg = < 0x80000 0x7F80000>;
+ label = "alt-obmc-ubi";
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts b/arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts
index 31ea34e14c79..bd7aff0b84d7 100644
--- a/arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts
+++ b/arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts
@@ -27,6 +27,12 @@
reg = <0x98000000 0x04000000>; /* 64M */
};
+ vga_memory: region@9f000000 {
+ no-map;
+ compatible = "shared-dma-pool";
+ reg = <0x9f000000 0x01000000>; /* 16M */
+ };
+
gfx_memory: framebuffer {
size = <0x01000000>;
alignment = <0x01000000>;
@@ -193,6 +199,40 @@
};
+&gpio {
+ gpio-line-names =
+ /*A0-A7*/ "","cfam-reset","","","","","fsi-mux","",
+ /*B0-B7*/ "","","","","","air-water","","",
+ /*C0-C7*/ "","","","","","","","",
+ /*D0-D7*/ "fsi-enable","","","","","","","",
+ /*E0-E7*/ "fsi-data","","","","","","","",
+ /*F0-F7*/ "","","","","","","","",
+ /*G0-G7*/ "","","","","","","","",
+ /*H0-H7*/ "","","","","","","","",
+ /*I0-I7*/ "","","","","","","","",
+ /*J0-J7*/ "","","checkstop","","","","","",
+ /*K0-K7*/ "","","","","","","","",
+ /*L0-L7*/ "","","","","","","","",
+ /*M0-M7*/ "","","","","","","","",
+ /*N0-N7*/ "presence-ps1","","led-rear-fault","led-rear-power",
+ "led-rear-id","","","",
+ /*O0-O7*/ "","","","","","","","",
+ /*P0-P7*/ "","","","","","","","presence-ps0",
+ /*Q0-Q7*/ "","","","","","","","",
+ /*R0-R7*/ "","","fsi-trans","","","power-button","","",
+ /*S0-S7*/ "","","","","","","","",
+ /*T0-T7*/ "","","","","","","","",
+ /*U0-U7*/ "","","","","","","","",
+ /*V0-V7*/ "","","","","","","","",
+ /*W0-W7*/ "","","","","","","","",
+ /*X0-X7*/ "","","","","","","","",
+ /*Y0-Y7*/ "","","","","","","","",
+ /*Z0-Z7*/ "","","","","","","","",
+ /*AA0-AA7*/ "fsi-clock","","","","","","","",
+ /*AB0-AB7*/ "","","","","","","","",
+ /*AC0-AC7*/ "","","","","","","","";
+};
+
&fmc {
status = "okay";
@@ -200,6 +240,7 @@
status = "okay";
label = "bmc";
m25p,fast-read;
+ spi-max-frequency = <50000000>;
partitions {
#address-cells = < 1 >;
@@ -224,6 +265,7 @@
status = "okay";
label = "alt-bmc";
m25p,fast-read;
+ spi-max-frequency = <50000000>;
partitions {
#address-cells = < 1 >;
@@ -242,7 +284,6 @@
label = "alt-obmc-ubi";
};
};
-
};
};
@@ -255,6 +296,7 @@
status = "okay";
label = "pnor";
m25p,fast-read;
+ spi-max-frequency = <100000000>;
};
};
@@ -289,10 +331,21 @@
flash = <&spi1>;
};
+&lpc_host {
+ kcs4: kcs4@0 {
+ compatible = "openbmc,mctp-lpc";
+ interrupts = <8>;
+ status = "okay";
+ };
+};
+
&mac0 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_rmii1_default>;
+ clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>,
+ <&syscon ASPEED_CLK_MAC1RCLK>;
+ clock-names = "MACCLK", "RCLK";
use-ncsi;
};
@@ -319,6 +372,58 @@
reg = <0x52>;
#address-cells = <1>;
#size-cells = <0>;
+
+ fan@0 {
+ compatible = "pmbus-fan";
+ reg = <0>;
+ tach-pulses = <2>;
+ maxim,fan-rotor-input = "tach";
+ maxim,fan-pwm-freq = <25000>;
+ maxim,fan-dual-tach;
+ maxim,fan-no-watchdog;
+ maxim,fan-no-fault-ramp;
+ maxim,fan-ramp = <2>;
+ maxim,fan-fault-pin-mon;
+ };
+
+ fan@1 {
+ compatible = "pmbus-fan";
+ reg = <1>;
+ tach-pulses = <2>;
+ maxim,fan-rotor-input = "tach";
+ maxim,fan-pwm-freq = <25000>;
+ maxim,fan-dual-tach;
+ maxim,fan-no-watchdog;
+ maxim,fan-no-fault-ramp;
+ maxim,fan-ramp = <2>;
+ maxim,fan-fault-pin-mon;
+ };
+
+ fan@2 {
+ compatible = "pmbus-fan";
+ reg = <2>;
+ tach-pulses = <2>;
+ maxim,fan-rotor-input = "tach";
+ maxim,fan-pwm-freq = <25000>;
+ maxim,fan-dual-tach;
+ maxim,fan-no-watchdog;
+ maxim,fan-no-fault-ramp;
+ maxim,fan-ramp = <2>;
+ maxim,fan-fault-pin-mon;
+ };
+
+ fan@3 {
+ compatible = "pmbus-fan";
+ reg = <3>;
+ tach-pulses = <2>;
+ maxim,fan-rotor-input = "tach";
+ maxim,fan-pwm-freq = <25000>;
+ maxim,fan-dual-tach;
+ maxim,fan-no-watchdog;
+ maxim,fan-no-fault-ramp;
+ maxim,fan-ramp = <2>;
+ maxim,fan-fault-pin-mon;
+ };
};
dps: dps310@76 {
@@ -653,4 +758,9 @@
memory-region = <&video_engine_memory>;
};
+&xdma {
+ status = "okay";
+ memory-region = <&vga_memory>;
+};
+
#include "ibm-power9-dual.dtsi"
diff --git a/arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts b/arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts
index 30624378316d..4bcc82046362 100644
--- a/arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts
+++ b/arch/arm/boot/dts/aspeed-bmc-opp-zaius.dts
@@ -130,6 +130,7 @@
status = "okay";
label = "bmc";
m25p,fast-read;
+ spi-max-frequency = <50000000>;
#include "openbmc-flash-layout.dtsi"
};
};
@@ -143,6 +144,7 @@
status = "okay";
label = "pnor";
m25p,fast-read;
+ spi-max-frequency = <100000000>;
};
};
@@ -187,6 +189,9 @@
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_rmii1_default>;
+ clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>,
+ <&syscon ASPEED_CLK_MAC1RCLK>;
+ clock-names = "MACCLK", "RCLK";
use-ncsi;
};
@@ -473,32 +478,61 @@
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_gpioh_unbiased>;
+ gpio-line-names =
+ /*A0-A7*/ "","cfam-reset","","","","","","",
+ /*B0-B7*/ "","","","","","","","",
+ /*C0-C7*/ "","","","","","","","",
+ /*D0-D7*/ "fsi-enable","","","","","led-sys-boot-status","led-attention",
+ "led-fault",
+ /*E0-E7*/ "","","","","","","","presence-pcie-e2b",
+ /*F0-F7*/ "","","","","","","","checkstop",
+ /*G0-G7*/ "fsi-clock","fsi-data","","","","","","",
+ /*H0-H7*/ "onewire0","onewire1","onewire2","onewire3","","","","",
+ /*I0-I7*/ "","","","power-button","","","","",
+ /*J0-J7*/ "","","","","","","","",
+ /*K0-K7*/ "","","","","","","","",
+ /*L0-L7*/ "","","","","","","","",
+ /*M0-M7*/ "","","","","","","","",
+ /*N0-N7*/ "","","","","","","","",
+ /*O0-O7*/ "","","","","iso_u164_en","","fsi-trans","",
+ /*P0-P7*/ "ncsi_mux_en_n","bmc_i2c2_sw_rst_n","","bmc_i2c5_sw_rst_n","",
+ "","fsi-mux","",
+ /*Q0-Q7*/ "","","","","","","","",
+ /*R0-R7*/ "","","","","","","","",
+ /*S0-S7*/ "","","","","","","","",
+ /*T0-T7*/ "","","","","","","","",
+ /*U0-U7*/ "","","","","","","","",
+ /*V0-V7*/ "","","","","","","","",
+ /*W0-W7*/ "","","","","","","","",
+ /*X0-X7*/ "","","","","","","","",
+ /*Y0-Y7*/ "","","","","","","","",
+ /*Z0-Z7*/ "","","","","","","","",
+ /*AA0-AA7*/ "","","led-hdd-fault","","","","","",
+ /*AB0-AB7*/ "","","","","","","","",
+ /*AC0-AC7*/ "","","","","","","","";
+
line_iso_u146_en {
gpio-hog;
gpios = <ASPEED_GPIO(O, 4) GPIO_ACTIVE_HIGH>;
output-high;
- line-name = "iso_u164_en";
};
ncsi_mux_en_n {
gpio-hog;
gpios = <ASPEED_GPIO(P, 0) GPIO_ACTIVE_HIGH>;
output-low;
- line-name = "ncsi_mux_en_n";
};
line_bmc_i2c2_sw_rst_n {
gpio-hog;
gpios = <ASPEED_GPIO(P, 1) GPIO_ACTIVE_HIGH>;
output-high;
- line-name = "bmc_i2c2_sw_rst_n";
};
line_bmc_i2c5_sw_rst_n {
gpio-hog;
gpios = <ASPEED_GPIO(P, 3) GPIO_ACTIVE_HIGH>;
output-high;
- line-name = "bmc_i2c5_sw_rst_n";
};
};
diff --git a/arch/arm/boot/dts/aspeed-bmc-portwell-neptune.dts b/arch/arm/boot/dts/aspeed-bmc-portwell-neptune.dts
index 33d704541de6..4a1ca8f5b6a7 100644
--- a/arch/arm/boot/dts/aspeed-bmc-portwell-neptune.dts
+++ b/arch/arm/boot/dts/aspeed-bmc-portwell-neptune.dts
@@ -80,12 +80,18 @@
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_rmii1_default
&pinctrl_mdio1_default>;
+ clocks = <&syscon ASPEED_CLK_GATE_MAC1CLK>,
+ <&syscon ASPEED_CLK_MAC1RCLK>;
+ clock-names = "MACCLK", "RCLK";
};
&mac1 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_rmii2_default>;
+ clocks = <&syscon ASPEED_CLK_GATE_MAC2CLK>,
+ <&syscon ASPEED_CLK_MAC2RCLK>;
+ clock-names = "MACCLK", "RCLK";
use-ncsi;
};
diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi
index dffb595d30e4..b875c0785833 100644
--- a/arch/arm/boot/dts/aspeed-g4.dtsi
+++ b/arch/arm/boot/dts/aspeed-g4.dtsi
@@ -65,6 +65,7 @@
flash@0 {
reg = < 0 >;
compatible = "jedec,spi-nor";
+ spi-max-frequency = <50000000>;
status = "disabled";
};
flash@1 {
@@ -100,6 +101,7 @@
flash@0 {
reg = < 0 >;
compatible = "jedec,spi-nor";
+ spi-max-frequency = <50000000>;
status = "disabled";
};
};
@@ -182,7 +184,7 @@
#reset-cells = <1>;
pinctrl: pinctrl {
- compatible = "aspeed,g4-pinctrl";
+ compatible = "aspeed,ast2400-pinctrl";
};
p2a: p2a-control {
@@ -373,9 +375,20 @@
interrupts = <8>;
status = "disabled";
};
+
+ sio_regs: regs {
+ compatible = "aspeed,bmc-misc";
+ };
};
};
+ peci: bus@1e78b000 {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0x1e78b000 0x60>;
+ };
+
uart2: serial@1e78d000 {
compatible = "ns16550a";
reg = <0x1e78d000 0x20>;
@@ -419,6 +432,24 @@
};
};
+&peci {
+ peci0: peci-bus@0 {
+ compatible = "aspeed,ast2400-peci";
+ reg = <0x0 0x60>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <15>;
+ clocks = <&syscon ASPEED_CLK_GATE_REFCLK>;
+ resets = <&syscon ASPEED_RESET_PECI>;
+ clock-frequency = <24000000>;
+ msg-timing = <1>;
+ addr-timing = <1>;
+ rd-sampling-point = <8>;
+ cmd-timeout-ms = <1000>;
+ status = "disabled";
+ };
+};
+
&i2c {
i2c_ic: interrupt-controller@0 {
#interrupt-cells = <1>;
@@ -1416,3 +1447,86 @@
groups = "WDTRST2";
};
};
+
+&sio_regs {
+ sio_2b {
+ offset = <0xf0>;
+ bit-mask = <0xff>;
+ bit-shift = <24>;
+ };
+ sio_2a {
+ offset = <0xf0>;
+ bit-mask = <0xff>;
+ bit-shift = <16>;
+ };
+ sio_29 {
+ offset = <0xf0>;
+ bit-mask = <0xff>;
+ bit-shift = <8>;
+ };
+ sio_28 {
+ offset = <0xf0>;
+ bit-mask = <0xff>;
+ bit-shift = <0>;
+ };
+ sio_2f {
+ offset = <0xf4>;
+ bit-mask = <0xff>;
+ bit-shift = <24>;
+ };
+ sio_2e {
+ offset = <0xf4>;
+ bit-mask = <0xff>;
+ bit-shift = <16>;
+ };
+ sio_2d {
+ offset = <0xf4>;
+ bit-mask = <0xff>;
+ bit-shift = <8>;
+ };
+ sio_2c {
+ offset = <0xf4>;
+ bit-mask = <0xff>;
+ bit-shift = <0>;
+ };
+ sio_23 {
+ offset = <0xf8>;
+ bit-mask = <0xff>;
+ bit-shift = <24>;
+ };
+ sio_22 {
+ offset = <0xf8>;
+ bit-mask = <0xff>;
+ bit-shift = <16>;
+ };
+ sio_21 {
+ offset = <0xf8>;
+ bit-mask = <0xff>;
+ bit-shift = <8>;
+ };
+ sio_20 {
+ offset = <0xf8>;
+ bit-mask = <0xff>;
+ bit-shift = <0>;
+ };
+ sio_27 {
+ offset = <0xfc>;
+ bit-mask = <0xff>;
+ bit-shift = <24>;
+ };
+ sio_26 {
+ offset = <0xfc>;
+ bit-mask = <0xff>;
+ bit-shift = <16>;
+ };
+ sio_25 {
+ offset = <0xfc>;
+ bit-mask = <0xff>;
+ bit-shift = <8>;
+ };
+ sio_24 {
+ offset = <0xfc>;
+ bit-mask = <0xff>;
+ bit-shift = <0>;
+ };
+};
diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
index e8feb8b66a2f..377bce274030 100644
--- a/arch/arm/boot/dts/aspeed-g5.dtsi
+++ b/arch/arm/boot/dts/aspeed-g5.dtsi
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
#include <dt-bindings/clock/aspeed-clock.h>
+#include <dt-bindings/interrupt-controller/aspeed-scu-ic.h>
/ {
model = "Aspeed BMC";
@@ -48,7 +49,7 @@
};
edac: sdram@1e6e0000 {
- compatible = "aspeed,ast2500-sdram-edac";
+ compatible = "aspeed,ast2500-sdram-edac", "syscon";
reg = <0x1e6e0000 0x174>;
interrupts = <0>;
status = "disabled";
@@ -72,16 +73,19 @@
flash@0 {
reg = < 0 >;
compatible = "jedec,spi-nor";
+ spi-max-frequency = <50000000>;
status = "disabled";
};
flash@1 {
reg = < 1 >;
compatible = "jedec,spi-nor";
+ spi-max-frequency = <50000000>;
status = "disabled";
};
flash@2 {
reg = < 2 >;
compatible = "jedec,spi-nor";
+ spi-max-frequency = <50000000>;
status = "disabled";
};
};
@@ -97,11 +101,13 @@
flash@0 {
reg = < 0 >;
compatible = "jedec,spi-nor";
+ spi-max-frequency = <50000000>;
status = "disabled";
};
flash@1 {
reg = < 1 >;
compatible = "jedec,spi-nor";
+ spi-max-frequency = <50000000>;
status = "disabled";
};
};
@@ -117,11 +123,13 @@
flash@0 {
reg = < 0 >;
compatible = "jedec,spi-nor";
+ spi-max-frequency = <50000000>;
status = "disabled";
};
flash@1 {
reg = < 1 >;
compatible = "jedec,spi-nor";
+ spi-max-frequency = <50000000>;
status = "disabled";
};
};
@@ -214,8 +222,15 @@
#clock-cells = <1>;
#reset-cells = <1>;
+ scu_ic: interrupt-controller@18 {
+ #interrupt-cells = <1>;
+ compatible = "aspeed,ast2500-scu-ic";
+ interrupts = <21>;
+ interrupt-controller;
+ };
+
pinctrl: pinctrl {
- compatible = "aspeed,g5-pinctrl";
+ compatible = "aspeed,ast2500-pinctrl";
aspeed,external-nodes = <&gfx &lhc>;
};
@@ -224,6 +239,10 @@
compatible = "aspeed,ast2500-p2a-ctrl";
status = "disabled";
};
+
+ vga_scratch: scratch {
+ compatible = "aspeed,bmc-misc";
+ };
};
rng: hwrng@1e6e2078 {
@@ -243,6 +262,18 @@
interrupts = <0x19>;
};
+ xdma: xdma@1e6e7000 {
+ compatible = "aspeed,ast2500-xdma";
+ reg = <0x1e6e7000 0x100>;
+ clocks = <&syscon ASPEED_CLK_GATE_BCLK>;
+ resets = <&syscon ASPEED_RESET_XDMA>;
+ interrupts-extended = <&vic 6>, <&scu_ic ASPEED_AST2500_SCU_IC_PCIE_RESET_LO_TO_HI>;
+ aspeed,pcie-device = "bmc";
+ aspeed,scu = <&syscon>;
+ sdmc = <&edac>;
+ status = "disabled";
+ };
+
adc: adc@1e6e9000 {
compatible = "aspeed,ast2500-adc";
reg = <0x1e6e9000 0xb0>;
@@ -299,7 +330,7 @@
#gpio-cells = <2>;
gpio-controller;
compatible = "aspeed,ast2500-gpio";
- reg = <0x1e780000 0x1000>;
+ reg = <0x1e780000 0x200>;
interrupts = <20>;
gpio-ranges = <&pinctrl 0 0 232>;
clocks = <&syscon ASPEED_CLK_APB>;
@@ -307,6 +338,21 @@
#interrupt-cells = <2>;
};
+ sgpio: sgpio@1e780200 {
+ #gpio-cells = <2>;
+ compatible = "aspeed,ast2500-sgpio";
+ gpio-controller;
+ interrupts = <40>;
+ reg = <0x1e780200 0x0100>;
+ clocks = <&syscon ASPEED_CLK_APB>;
+ interrupt-controller;
+ ngpios = <8>;
+ bus-frequency = <12000000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_sgpm_default>;
+ status = "disabled";
+ };
+
rtc: rtc@1e781000 {
compatible = "aspeed,ast2500-rtc";
reg = <0x1e781000 0x18>;
@@ -466,9 +512,20 @@
interrupts = <8>;
status = "disabled";
};
+
+ sio_regs: regs {
+ compatible = "aspeed,bmc-misc";
+ };
};
};
+ peci: bus@1e78b000 {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0x1e78b000 0x60>;
+ };
+
uart2: serial@1e78d000 {
compatible = "ns16550a";
reg = <0x1e78d000 0x20>;
@@ -512,6 +569,24 @@
};
};
+&peci {
+ peci0: peci-bus@0 {
+ compatible = "aspeed,ast2500-peci";
+ reg = <0x0 0x60>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <15>;
+ clocks = <&syscon ASPEED_CLK_GATE_REFCLK>;
+ resets = <&syscon ASPEED_RESET_PECI>;
+ clock-frequency = <24000000>;
+ msg-timing = <1>;
+ addr-timing = <1>;
+ rd-sampling-point = <8>;
+ cmd-timeout-ms = <1000>;
+ status = "disabled";
+ };
+};
+
&i2c {
i2c_ic: interrupt-controller@0 {
#interrupt-cells = <1>;
@@ -1589,3 +1664,134 @@
groups = "WDTRST2";
};
};
+
+&vga_scratch {
+ dac_mux {
+ offset = <0x2c>;
+ bit-mask = <0x3>;
+ bit-shift = <16>;
+ };
+ vga0 {
+ offset = <0x50>;
+ bit-mask = <0xffffffff>;
+ bit-shift = <0>;
+ };
+ vga1 {
+ offset = <0x54>;
+ bit-mask = <0xffffffff>;
+ bit-shift = <0>;
+ };
+ vga2 {
+ offset = <0x58>;
+ bit-mask = <0xffffffff>;
+ bit-shift = <0>;
+ };
+ vga3 {
+ offset = <0x5c>;
+ bit-mask = <0xffffffff>;
+ bit-shift = <0>;
+ };
+ vga4 {
+ offset = <0x60>;
+ bit-mask = <0xffffffff>;
+ bit-shift = <0>;
+ };
+ vga5 {
+ offset = <0x64>;
+ bit-mask = <0xffffffff>;
+ bit-shift = <0>;
+ };
+ vga6 {
+ offset = <0x68>;
+ bit-mask = <0xffffffff>;
+ bit-shift = <0>;
+ };
+ vga7 {
+ offset = <0x6c>;
+ bit-mask = <0xffffffff>;
+ bit-shift = <0>;
+ };
+};
+
+&sio_regs {
+ sio_2b {
+ offset = <0xf0>;
+ bit-mask = <0xff>;
+ bit-shift = <24>;
+ };
+ sio_2a {
+ offset = <0xf0>;
+ bit-mask = <0xff>;
+ bit-shift = <16>;
+ };
+ sio_29 {
+ offset = <0xf0>;
+ bit-mask = <0xff>;
+ bit-shift = <8>;
+ };
+ sio_28 {
+ offset = <0xf0>;
+ bit-mask = <0xff>;
+ bit-shift = <0>;
+ };
+ sio_2f {
+ offset = <0xf4>;
+ bit-mask = <0xff>;
+ bit-shift = <24>;
+ };
+ sio_2e {
+ offset = <0xf4>;
+ bit-mask = <0xff>;
+ bit-shift = <16>;
+ };
+ sio_2d {
+ offset = <0xf4>;
+ bit-mask = <0xff>;
+ bit-shift = <8>;
+ };
+ sio_2c {
+ offset = <0xf4>;
+ bit-mask = <0xff>;
+ bit-shift = <0>;
+ };
+ sio_23 {
+ offset = <0xf8>;
+ bit-mask = <0xff>;
+ bit-shift = <24>;
+ };
+ sio_22 {
+ offset = <0xf8>;
+ bit-mask = <0xff>;
+ bit-shift = <16>;
+ };
+ sio_21 {
+ offset = <0xf8>;
+ bit-mask = <0xff>;
+ bit-shift = <8>;
+ };
+ sio_20 {
+ offset = <0xf8>;
+ bit-mask = <0xff>;
+ bit-shift = <0>;
+ };
+ sio_27 {
+ offset = <0xfc>;
+ bit-mask = <0xff>;
+ bit-shift = <24>;
+ };
+ sio_26 {
+ offset = <0xfc>;
+ bit-mask = <0xff>;
+ bit-shift = <16>;
+ };
+ sio_25 {
+ offset = <0xfc>;
+ bit-mask = <0xff>;
+ bit-shift = <8>;
+ };
+ sio_24 {
+ offset = <0xfc>;
+ bit-mask = <0xff>;
+ bit-shift = <0>;
+ };
+};
diff --git a/arch/arm/boot/dts/aspeed-g6-pinctrl.dtsi b/arch/arm/boot/dts/aspeed-g6-pinctrl.dtsi
index 5b8bf58e89cb..7028e21bdd98 100644
--- a/arch/arm/boot/dts/aspeed-g6-pinctrl.dtsi
+++ b/arch/arm/boot/dts/aspeed-g6-pinctrl.dtsi
@@ -852,14 +852,9 @@
groups = "SD2";
};
- pinctrl_sd3_default: sd3_default {
- function = "SD3";
- groups = "SD3";
- };
-
pinctrl_emmc_default: emmc_default {
- function = "SD3";
- groups = "EMMC";
+ function = "EMMC";
+ groups = "EMMCG4";
};
pinctrl_sgpm1_default: sgpm1_default {
@@ -1117,6 +1112,31 @@
groups = "UART9";
};
+ pinctrl_usb2ah_default: usb2ah_default {
+ function = "USB2AH";
+ groups = "USBA";
+ };
+
+ pinctrl_usb2ad_default: usb2ad_default {
+ function = "USB2AD";
+ groups = "USBA";
+ };
+
+ pinctrl_usb2bh_default: usb2bh_default {
+ function = "USB2BH";
+ groups = "USBB";
+ };
+
+ pinctrl_usb2bd_default: usb2bd_default {
+ function = "USB2BD";
+ groups = "USBB";
+ };
+
+ pinctrl_usb11bhid_default: usb11bhid_default {
+ function = "USB11BHID";
+ groups = "USBB";
+ };
+
pinctrl_vb_default: vb_default {
function = "VB";
groups = "VB";
diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi
index 3a1422f7c49c..d0916af4f293 100644
--- a/arch/arm/boot/dts/aspeed-g6.dtsi
+++ b/arch/arm/boot/dts/aspeed-g6.dtsi
@@ -3,6 +3,7 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/ast2600-clock.h>
+#include <dt-bindings/interrupt-controller/aspeed-scu-ic.h>
/ {
model = "Aspeed BMC";
@@ -12,7 +13,29 @@
interrupt-parent = <&gic>;
aliases {
+ i2c0 = &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;
+ serial0 = &uart1;
+ serial1 = &uart2;
+ serial2 = &uart3;
+ serial3 = &uart4;
serial4 = &uart5;
+ serial5 = &vuart1;
+ serial6 = &vuart2;
};
@@ -43,6 +66,7 @@
<GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>;
clocks = <&syscon ASPEED_CLK_HPLL>;
arm,cpu-registers-not-fw-configured;
+ always-on;
};
ahb {
@@ -64,12 +88,93 @@
<0x40466000 0x2000>;
};
+ fmc: spi@1e620000 {
+ reg = < 0x1e620000 0xc4
+ 0x20000000 0x10000000 >;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "aspeed,ast2600-fmc";
+ clocks = <&syscon ASPEED_CLK_AHB>;
+ status = "disabled";
+ interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
+ flash@0 {
+ reg = < 0 >;
+ compatible = "jedec,spi-nor";
+ spi-max-frequency = <50000000>;
+ status = "disabled";
+ };
+ flash@1 {
+ reg = < 1 >;
+ compatible = "jedec,spi-nor";
+ spi-max-frequency = <50000000>;
+ status = "disabled";
+ };
+ flash@2 {
+ reg = < 2 >;
+ compatible = "jedec,spi-nor";
+ spi-max-frequency = <50000000>;
+ status = "disabled";
+ };
+ };
+
+ spi1: spi@1e630000 {
+ reg = < 0x1e630000 0xc4
+ 0x30000000 0x10000000 >;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "aspeed,ast2600-spi";
+ clocks = <&syscon ASPEED_CLK_AHB>;
+ status = "disabled";
+ flash@0 {
+ reg = < 0 >;
+ compatible = "jedec,spi-nor";
+ spi-max-frequency = <50000000>;
+ status = "disabled";
+ };
+ flash@1 {
+ reg = < 1 >;
+ compatible = "jedec,spi-nor";
+ spi-max-frequency = <50000000>;
+ status = "disabled";
+ };
+ };
+
+ spi2: spi@1e631000 {
+ reg = < 0x1e631000 0xc4
+ 0x50000000 0x10000000 >;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "aspeed,ast2600-spi";
+ clocks = <&syscon ASPEED_CLK_AHB>;
+ status = "disabled";
+ flash@0 {
+ reg = < 0 >;
+ compatible = "jedec,spi-nor";
+ spi-max-frequency = <50000000>;
+ status = "disabled";
+ };
+ flash@1 {
+ reg = < 1 >;
+ compatible = "jedec,spi-nor";
+ spi-max-frequency = <50000000>;
+ status = "disabled";
+ };
+ flash@2 {
+ reg = < 2 >;
+ compatible = "jedec,spi-nor";
+ spi-max-frequency = <50000000>;
+ status = "disabled";
+ };
+ };
+
mdio0: mdio@1e650000 {
compatible = "aspeed,ast2600-mdio";
reg = <0x1e650000 0x8>;
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_mdio1_default>;
};
mdio1: mdio@1e650008 {
@@ -78,6 +183,8 @@
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_mdio2_default>;
};
mdio2: mdio@1e650010 {
@@ -86,6 +193,8 @@
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_mdio3_default>;
};
mdio3: mdio@1e650018 {
@@ -94,6 +203,8 @@
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_mdio4_default>;
};
mac0: ftgmac@1e660000 {
@@ -136,6 +247,54 @@
status = "disabled";
};
+ ehci0: usb@1e6a1000 {
+ compatible = "aspeed,ast2600-ehci", "generic-ehci";
+ reg = <0x1e6a1000 0x100>;
+ interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&syscon ASPEED_CLK_GATE_USBPORT1CLK>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usb2ah_default>;
+ status = "disabled";
+ };
+
+ ehci1: usb@1e6a3000 {
+ compatible = "aspeed,ast2600-ehci", "generic-ehci";
+ reg = <0x1e6a3000 0x100>;
+ interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&syscon ASPEED_CLK_GATE_USBPORT2CLK>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usb2bh_default>;
+ status = "disabled";
+ };
+
+ uhci: usb@1e6b0000 {
+ compatible = "aspeed,ast2600-uhci", "generic-uhci";
+ reg = <0x1e6b0000 0x100>;
+ interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
+ #ports = <2>;
+ clocks = <&syscon ASPEED_CLK_GATE_USBUHCICLK>;
+ status = "disabled";
+ /*
+ * No default pinmux, it will follow EHCI, use an
+ * explicit pinmux override if EHCI is not enabled.
+ */
+ };
+
+ vhub: usb-vhub@1e6a0000 {
+ compatible = "aspeed,ast2600-usb-vhub";
+ reg = <0x1e6a0000 0x350>;
+ interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&syscon ASPEED_CLK_GATE_USBPORT1CLK>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usb2ad_default>;
+ status = "disabled";
+ };
+
+ sdmc: sdram@1e6e0000 {
+ compatible = "syscon";
+ reg = <0x1e6e0000 0xb8>;
+ };
+
apb {
compatible = "simple-bus";
#address-cells = <1>;
@@ -159,6 +318,20 @@
compatible = "aspeed,ast2600-smpmem";
reg = <0x180 0x40>;
};
+
+ scu_ic0: interrupt-controller@0 {
+ #interrupt-cells = <1>;
+ compatible = "aspeed,ast2600-scu-ic0";
+ interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-controller;
+ };
+
+ scu_ic1: interrupt-controller@1 {
+ #interrupt-cells = <1>;
+ compatible = "aspeed,ast2600-scu-ic1";
+ interrupts = <GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-controller;
+ };
};
rng: hwrng@1e6e2524 {
@@ -168,6 +341,46 @@
quality = <100>;
};
+ xdma: xdma@1e6e7000 {
+ compatible = "aspeed,ast2600-xdma";
+ reg = <0x1e6e7000 0x100>;
+ clocks = <&syscon ASPEED_CLK_GATE_BCLK>;
+ resets = <&syscon ASPEED_RESET_DEV_XDMA>, <&syscon ASPEED_RESET_RC_XDMA>;
+ reset-names = "device", "root-complex";
+ interrupts-extended = <&gic GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>,
+ <&scu_ic0 ASPEED_AST2600_SCU_IC0_PCIE_PERST_LO_TO_HI>;
+ aspeed,pcie-device = "bmc";
+ aspeed,scu = <&syscon>;
+ sdmc = <&sdmc>;
+ status = "disabled";
+ };
+
+ gpio0: gpio@1e780000 {
+ #gpio-cells = <2>;
+ gpio-controller;
+ compatible = "aspeed,ast2600-gpio";
+ reg = <0x1e780000 0x800>;
+ interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-ranges = <&pinctrl 0 0 208>;
+ ngpios = <208>;
+ clocks = <&syscon ASPEED_CLK_APB2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpio1: gpio@1e780800 {
+ #gpio-cells = <2>;
+ gpio-controller;
+ compatible = "aspeed,ast2600-gpio";
+ reg = <0x1e780800 0x800>;
+ interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-ranges = <&pinctrl 0 208 36>;
+ ngpios = <36>;
+ clocks = <&syscon ASPEED_CLK_APB1>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
rtc: rtc@1e781000 {
compatible = "aspeed,ast2600-rtc";
reg = <0x1e781000 0x18>;
@@ -175,6 +388,36 @@
status = "disabled";
};
+ timer: timer@1e782000 {
+ compatible = "aspeed,ast2600-timer";
+ reg = <0x1e782000 0x90>;
+ interrupts-extended = <&gic GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
+ <&gic GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>,
+ <&gic GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
+ <&gic GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>,
+ <&gic GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>,
+ <&gic GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>,
+ <&gic GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>,
+ <&gic GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&syscon ASPEED_CLK_APB1>;
+ clock-names = "PCLK";
+ status = "disabled";
+ };
+
+ uart1: serial@1e783000 {
+ compatible = "ns16550a";
+ reg = <0x1e783000 0x20>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&syscon ASPEED_CLK_GATE_UART1CLK>;
+ resets = <&lpc_reset 4>;
+ no-loopback-test;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_txd1_default &pinctrl_rxd1_default>;
+ status = "disabled";
+ };
+
uart5: serial@1e784000 {
compatible = "ns16550a";
reg = <0x1e784000 0x1000>;
@@ -207,6 +450,104 @@
status = "disabled";
};
+ peci: bus@1e78b000 {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0x1e78b000 0x100>;
+ };
+
+ lpc: lpc@1e789000 {
+ compatible = "aspeed,ast2600-lpc", "simple-mfd";
+ reg = <0x1e789000 0x1000>;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0x1e789000 0x1000>;
+
+ lpc_bmc: lpc-bmc@0 {
+ compatible = "aspeed,ast2600-lpc-bmc", "simple-mfd", "syscon";
+ reg = <0x0 0x80>;
+ reg-io-width = <4>;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0x0 0x80>;
+
+ kcs1: kcs1@0 {
+ compatible = "aspeed,ast2600-kcs-bmc";
+ interrupts = <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>;
+ kcs_chan = <1>;
+ status = "disabled";
+ };
+ kcs2: kcs2@0 {
+ compatible = "aspeed,ast2600-kcs-bmc";
+ interrupts = <GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>;
+ kcs_chan = <2>;
+ status = "disabled";
+ };
+ kcs3: kcs3@0 {
+ compatible = "aspeed,ast2600-kcs-bmc";
+ interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
+ kcs_chan = <3>;
+ status = "disabled";
+ };
+ };
+
+ lpc_host: lpc-host@80 {
+ compatible = "aspeed,ast2600-lpc-host", "simple-mfd", "syscon";
+ reg = <0x80 0x1e0>;
+ reg-io-width = <4>;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0x80 0x1e0>;
+
+ kcs4: kcs4@0 {
+ compatible = "aspeed,ast2600-kcs-bmc";
+ interrupts = <GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>;
+ kcs_chan = <4>;
+ status = "disabled";
+ };
+
+ lpc_ctrl: lpc-ctrl@0 {
+ compatible = "aspeed,ast2600-lpc-ctrl";
+ reg = <0x0 0x80>;
+ clocks = <&syscon ASPEED_CLK_GATE_LCLK>;
+ status = "disabled";
+ };
+
+ lpc_snoop: lpc-snoop@0 {
+ compatible = "aspeed,ast2600-lpc-snoop";
+ reg = <0x0 0x80>;
+ interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
+ lhc: lhc@20 {
+ compatible = "aspeed,ast2600-lhc";
+ reg = <0x20 0x24 0x48 0x8>;
+ };
+
+ lpc_reset: reset-controller@18 {
+ compatible = "aspeed,ast2600-lpc-reset";
+ reg = <0x18 0x4>;
+ #reset-cells = <1>;
+ };
+
+ ibt: ibt@c0 {
+ compatible = "aspeed,ast2600-ibt-bmc";
+ reg = <0xc0 0x18>;
+ interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
+ sio_regs: regs {
+ compatible = "aspeed,bmc-misc";
+ };
+ };
+ };
+
sdc: sdc@1e740000 {
compatible = "aspeed,ast2600-sd-controller";
reg = <0x1e740000 0x100>;
@@ -235,7 +576,7 @@
};
};
- emmc: sdc@1e750000 {
+ emmc_controller: sdc@1e750000 {
compatible = "aspeed,ast2600-sd-controller";
reg = <0x1e750000 0x100>;
#address-cells = <1>;
@@ -244,7 +585,7 @@
clocks = <&syscon ASPEED_CLK_GATE_EMMCCLK>;
status = "disabled";
- sdhci@1e750100 {
+ emmc: sdhci@1e750100 {
compatible = "aspeed,ast2600-sdhci";
reg = <0x100 0x100>;
sdhci,auto-cmd12;
@@ -254,8 +595,357 @@
pinctrl-0 = <&pinctrl_emmc_default>;
};
};
+
+ vuart1: serial@1e787000 {
+ compatible = "aspeed,ast2500-vuart";
+ reg = <0x1e787000 0x40>;
+ reg-shift = <2>;
+ interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&syscon ASPEED_CLK_APB1>;
+ no-loopback-test;
+ status = "disabled";
+ };
+
+ vuart2: serial@1e788000 {
+ compatible = "aspeed,ast2500-vuart";
+ reg = <0x1e788000 0x40>;
+ reg-shift = <2>;
+ interrupts = <GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&syscon ASPEED_CLK_APB1>;
+ no-loopback-test;
+ status = "disabled";
+ };
+
+ uart2: serial@1e78d000 {
+ compatible = "ns16550a";
+ reg = <0x1e78d000 0x20>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&syscon ASPEED_CLK_GATE_UART2CLK>;
+ resets = <&lpc_reset 5>;
+ no-loopback-test;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_txd2_default &pinctrl_rxd2_default>;
+ status = "disabled";
+ };
+
+ uart3: serial@1e78e000 {
+ compatible = "ns16550a";
+ reg = <0x1e78e000 0x20>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&syscon ASPEED_CLK_GATE_UART3CLK>;
+ resets = <&lpc_reset 6>;
+ no-loopback-test;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_txd3_default &pinctrl_rxd3_default>;
+ status = "disabled";
+ };
+
+ uart4: serial@1e78f000 {
+ compatible = "ns16550a";
+ reg = <0x1e78f000 0x20>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&syscon ASPEED_CLK_GATE_UART4CLK>;
+ resets = <&lpc_reset 7>;
+ no-loopback-test;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_txd4_default &pinctrl_rxd4_default>;
+ status = "disabled";
+ };
+
+ i2c: bus@1e78a000 {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x1e78a000 0x1000>;
+ };
+
+ fsim0: fsi@1e79b000 {
+ compatible = "aspeed,ast2600-fsi-master", "fsi-master";
+ reg = <0x1e79b000 0x94>;
+ interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_fsi1_default>;
+ clocks = <&syscon ASPEED_CLK_GATE_FSICLK>;
+ status = "disabled";
+ };
+
+ fsim1: fsi@1e79b100 {
+ compatible = "aspeed,ast2600-fsi-master", "fsi-master";
+ reg = <0x1e79b100 0x94>;
+ interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_fsi2_default>;
+ clocks = <&syscon ASPEED_CLK_GATE_FSICLK>;
+ status = "disabled";
+ };
};
};
};
#include "aspeed-g6-pinctrl.dtsi"
+
+&peci {
+ peci0: peci-bus@0 {
+ compatible = "aspeed,ast2600-peci";
+ reg = <0x0 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&syscon ASPEED_CLK_GATE_REF0CLK>;
+ resets = <&syscon ASPEED_RESET_PECI>;
+ clock-frequency = <24000000>;
+ msg-timing = <1>;
+ addr-timing = <1>;
+ rd-sampling-point = <8>;
+ cmd-timeout-ms = <1000>;
+ status = "disabled";
+ };
+};
+
+&i2c {
+ i2c0: i2c-bus@80 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+ reg = <0x80 0x80>;
+ compatible = "aspeed,ast2600-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB2>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+ interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
+ bus-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c1_default>;
+ status = "disabled";
+ };
+
+ i2c1: i2c-bus@100 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+ reg = <0x100 0x80>;
+ compatible = "aspeed,ast2600-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB2>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+ interrupts = <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>;
+ bus-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c2_default>;
+ status = "disabled";
+ };
+
+ i2c2: i2c-bus@180 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+ reg = <0x180 0x80>;
+ compatible = "aspeed,ast2600-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB2>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+ interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
+ bus-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c3_default>;
+ status = "disabled";
+ };
+
+ i2c3: i2c-bus@200 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+ reg = <0x200 0x80>;
+ compatible = "aspeed,ast2600-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB2>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+ interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
+ bus-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c4_default>;
+ status = "disabled";
+ };
+
+ i2c4: i2c-bus@280 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+ reg = <0x280 0x80>;
+ compatible = "aspeed,ast2600-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB2>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+ interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
+ bus-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c5_default>;
+ status = "disabled";
+ };
+
+ i2c5: i2c-bus@300 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+ reg = <0x300 0x80>;
+ compatible = "aspeed,ast2600-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB2>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+ interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>;
+ bus-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c6_default>;
+ status = "disabled";
+ };
+
+ i2c6: i2c-bus@380 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+ reg = <0x380 0x80>;
+ compatible = "aspeed,ast2600-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB2>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+ interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
+ bus-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c7_default>;
+ status = "disabled";
+ };
+
+ i2c7: i2c-bus@400 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+ reg = <0x400 0x80>;
+ compatible = "aspeed,ast2600-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB2>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+ bus-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c8_default>;
+ status = "disabled";
+ };
+
+ i2c8: i2c-bus@480 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+ reg = <0x480 0x80>;
+ compatible = "aspeed,ast2600-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB2>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+ bus-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c9_default>;
+ status = "disabled";
+ };
+
+ i2c9: i2c-bus@500 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+ reg = <0x500 0x80>;
+ compatible = "aspeed,ast2600-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB2>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+ interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
+ bus-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c10_default>;
+ status = "disabled";
+ };
+
+ i2c10: i2c-bus@580 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+ reg = <0x580 0x80>;
+ compatible = "aspeed,ast2600-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB2>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+ interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
+ bus-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c11_default>;
+ status = "disabled";
+ };
+
+ i2c11: i2c-bus@600 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+ reg = <0x600 0x80>;
+ compatible = "aspeed,ast2600-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB2>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+ bus-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c12_default>;
+ status = "disabled";
+ };
+
+ i2c12: i2c-bus@680 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+ reg = <0x680 0x80>;
+ compatible = "aspeed,ast2600-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB2>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+ interrupts = <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>;
+ bus-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c13_default>;
+ status = "disabled";
+ };
+
+ i2c13: i2c-bus@700 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+ reg = <0x700 0x80>;
+ compatible = "aspeed,ast2600-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB2>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+ interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
+ bus-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c14_default>;
+ status = "disabled";
+ };
+
+ i2c14: i2c-bus@780 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+ reg = <0x780 0x80>;
+ compatible = "aspeed,ast2600-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB2>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+ interrupts = <GIC_SPI 124 IRQ_TYPE_LEVEL_HIGH>;
+ bus-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c15_default>;
+ status = "disabled";
+ };
+
+ i2c15: i2c-bus@800 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #interrupt-cells = <1>;
+ reg = <0x800 0x80>;
+ compatible = "aspeed,ast2600-i2c-bus";
+ clocks = <&syscon ASPEED_CLK_APB2>;
+ resets = <&syscon ASPEED_RESET_I2C>;
+ interrupts = <GIC_SPI 125 IRQ_TYPE_LEVEL_HIGH>;
+ bus-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c16_default>;
+ status = "disabled";
+ };
+};
diff --git a/arch/arm/boot/dts/ast2500-facebook-netbmc-common.dtsi b/arch/arm/boot/dts/ast2500-facebook-netbmc-common.dtsi
new file mode 100644
index 000000000000..7a395ba56512
--- /dev/null
+++ b/arch/arm/boot/dts/ast2500-facebook-netbmc-common.dtsi
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Copyright (c) 2019 Facebook Inc.
+
+#include "aspeed-g5.dtsi"
+
+/ {
+ memory@80000000 {
+ reg = <0x80000000 0x40000000>;
+ };
+};
+
+/*
+ * Update reset type to "system" (full chip) to fix warm reboot hang issue
+ * when reset type is set to default ("soc", gated by reset mask registers).
+ */
+&wdt1 {
+ status = "okay";
+ aspeed,reset-type = "system";
+};
+
+&wdt2 {
+ status = "disabled";
+};
+
+&uart1 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_txd1_default
+ &pinctrl_rxd1_default>;
+};
+
+&uart3 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_txd3_default
+ &pinctrl_rxd3_default>;
+};
+
+&uart5 {
+ status = "okay";
+};
+
+&fmc {
+ status = "okay";
+
+ fmc_flash0: flash@0 {
+ status = "okay";
+ m25p,fast-read;
+ label = "spi0.0";
+
+#include "facebook-bmc-flash-layout.dtsi"
+ };
+
+ fmc_flash1: flash@1 {
+ status = "okay";
+ m25p,fast-read;
+ label = "spi0.1";
+
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ flash1@0 {
+ reg = <0x0 0x2000000>;
+ label = "flash1";
+ };
+ };
+ };
+};
+
+&mac1 {
+ status = "okay";
+ no-hw-checksum;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_rgmii2_default &pinctrl_mdio2_default>;
+};
+
+&rtc {
+ status = "okay";
+};
+
+&vhub {
+ status = "okay";
+};
+
+&sdmmc {
+ status = "okay";
+};
+
+&sdhci1 {
+ status = "okay";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_sd2_default>;
+};
diff --git a/arch/arm/boot/dts/nuvoton-common-npcm7xx.dtsi b/arch/arm/boot/dts/nuvoton-common-npcm7xx.dtsi
index d2d0761295a4..72841f54deb4 100644
--- a/arch/arm/boot/dts/nuvoton-common-npcm7xx.dtsi
+++ b/arch/arm/boot/dts/nuvoton-common-npcm7xx.dtsi
@@ -3,14 +3,21 @@
// Copyright 2018 Google, Inc.
#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/clock/nuvoton,npcm7xx-clock.h>
+#include <dt-bindings/gpio/gpio.h>
/ {
#address-cells = <1>;
#size-cells = <1>;
interrupt-parent = <&gic>;
+ memory {
+ device_type = "memory";
+ reg = <0 0>;
+ };
+
/* external reference clock */
- clk_refclk: clk_refclk {
+ clk_refclk: clk-refclk {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <25000000>;
@@ -18,7 +25,7 @@
};
/* external reference clock for cpu. float in normal operation */
- clk_sysbypck: clk_sysbypck {
+ clk_sysbypck: clk-sysbypck {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <800000000>;
@@ -26,7 +33,7 @@
};
/* external reference clock for MC. float in normal operation */
- clk_mcbypck: clk_mcbypck {
+ clk_mcbypck: clk-mcbypck {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <800000000>;
@@ -34,7 +41,7 @@
};
/* external clock signal rg1refck, supplied by the phy */
- clk_rg1refck: clk_rg1refck {
+ clk_rg1refck: clk-rg1refck {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <125000000>;
@@ -42,14 +49,14 @@
};
/* external clock signal rg2refck, supplied by the phy */
- clk_rg2refck: clk_rg2refck {
+ clk_rg2refck: clk-rg2refck {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <125000000>;
clock-output-names = "clk_rg2refck";
};
- clk_xin: clk_xin {
+ clk_xin: clk-xin {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <50000000>;
@@ -69,6 +76,12 @@
reg = <0x800000 0x1000>;
};
+ rst: rst@f0801000 {
+ compatible = "nuvoton,npcm750-rst", "syscon",
+ "simple-mfd";
+ reg = <0x801000 0x6C>;
+ };
+
scu: scu@3fe000 {
compatible = "arm,cortex-a9-scu";
reg = <0x3fe000 0x1000>;
@@ -80,7 +93,7 @@
interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
cache-unified;
cache-level = <2>;
- clocks = <&clk 10>;
+ clocks = <&clk NPCM7XX_CLK_AXI>;
arm,shared-override;
};
@@ -109,6 +122,170 @@
clocks = <&clk_refclk>, <&clk_sysbypck>, <&clk_mcbypck>;
};
+ gmac0: eth@f0802000 {
+ device_type = "network";
+ compatible = "snps,dwmac";
+ reg = <0xf0802000 0x2000>;
+ interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "macirq";
+ ethernet = <0>;
+ clocks = <&clk_rg1refck>, <&clk NPCM7XX_CLK_AHB>;
+ clock-names = "stmmaceth", "clk_gmac";
+ pinctrl-names = "default";
+ pinctrl-0 = <&rg1_pins
+ &rg1mdio_pins>;
+ status = "disabled";
+ };
+
+ emc0: eth@f0825000 {
+ device_type = "network";
+ compatible = "nuvoton,npcm750-emc";
+ reg = <0xf0825000 0x1000>;
+ interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clk NPCM7XX_CLK_AHB>;
+ clock-names = "clk_emc";
+ pinctrl-names = "default";
+ pinctrl-0 = <&r1_pins
+ &r1err_pins
+ &r1md_pins>;
+ status = "disabled";
+ };
+
+ ehci1:usb@f0806000 {
+ compatible = "nuvoton,npcm750-ehci";
+ reg = <0xf0806000 0x1000>;
+ interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
+ ohci1: ohci@f0807000 {
+ compatible = "nuvoton,npcm750-ohci";
+ reg = <0xf0807000 0x1000>;
+ interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
+ sdhci0: sdhci@f0842000 {
+ compatible = "nuvoton,npcm750-sdhci";
+ status = "disabled";
+ reg = <0xf0842000 0x200>;
+ interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clk NPCM7XX_CLK_AHB>; /*, <&clk_xin>;*/
+ clock-names = "clk_mmc"; /* ,"clk_xin"; */
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc8_pins
+ &mmc_pins>;
+ };
+
+ sdhci1: sdhci@f0840000 {
+ compatible = "nuvoton,npcm750-sdhci";
+ status = "disabled";
+ reg = <0xf0840000 0x200>;
+ interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clk NPCM7XX_CLK_AHB>; /*, <&clk_xin>;*/
+ clock-names = "clk_sdhc"; /* ,"clk_xin"; */
+ pinctrl-names = "default";
+ pinctrl-0 = <&sd1_pins>;
+ };
+
+ aes:aes@f0858000 {
+ compatible = "nuvoton,npcm750-aes";
+ reg = <0xf0858000 0x1000>;
+ status = "disabled";
+ clocks = <&clk NPCM7XX_CLK_AHB>;
+ clock-names = "clk_ahb";
+ };
+
+ sha:sha@f085a000 {
+ compatible = "nuvoton,npcm750-sha";
+ reg = <0xf085a000 0x1000>;
+ status = "disabled";
+ clocks = <&clk NPCM7XX_CLK_AHB>;
+ clock-names = "clk_ahb";
+ };
+
+ copr: copr@0 {
+ compatible = "nuvoton,npcm750-copr";
+ interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clk NPCM7XX_CLK_AHB>;
+ clock-names = "clk_ahb";
+ };
+
+ vdma: vdma@e0800000 {
+ compatible = "nuvoton,npcm750-vdm";
+ reg = <0xe0800000 0x1000
+ 0xf0822000 0x1000>;
+ interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ fiu0: fiu@fb000000 {
+ compatible = "nuvoton,npcm750-fiu";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0xfb000000 0x1000>, <0x80000000 0x10000000>;
+ reg-names = "control", "memory";
+ clocks = <&clk NPCM7XX_CLK_AHB>;
+ clock-names = "clk_ahb";
+ status = "disabled";
+ };
+
+ fiu3: fiu@c0000000 {
+ compatible = "nuvoton,npcm750-fiu";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0xc0000000 0x1000>, <0xA0000000 0x20000000>;
+ reg-names = "control", "memory";
+ clocks = <&clk NPCM7XX_CLK_AHB>;
+ clock-names = "clk_ahb";
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi3_pins>;
+ status = "disabled";
+ };
+
+ fiux: fiu@fb001000 {
+ compatible = "nuvoton,npcm750-fiu";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0xfb001000 0x1000>, <0xf8000000 0x2000000>;
+ reg-names = "control", "memory";
+ clocks = <&clk NPCM7XX_CLK_AHB>;
+ clock-names = "clk_ahb";
+ status = "disabled";
+ };
+
+ dvc: dvc@f0808000 {
+ compatible = "nuvoton,npcm750-dvc";
+ reg = <0xf0808000 0x1000>;
+ interrupts = <0 23 4>;
+ };
+
+ vcd: vcd@f0810000 {
+ compatible = "nuvoton,npcm750-vcd";
+ reg = <0xf0810000 0x10000>;
+ mem-addr = <0x3e200000>;
+ mem-size = <0x600000>;
+ interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
+ ece: ece@f0820000 {
+ compatible = "nuvoton,npcm750-ece";
+ reg = <0xf0820000 0x2000>;
+ mem-addr = <0x3e800000>;
+ mem-size = <0x600000>;
+ interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
+ pcimbox: pcimbox@f0848000 {
+ compatible = "nuvoton,npcm750-pci-mbox",
+ "simple-mfd", "syscon";
+ reg = <0xf084C000 0x8
+ 0xf0848000 0x3F00>;
+ interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
apb {
#address-cells = <1>;
#size-cells = <1>;
@@ -116,11 +293,96 @@
interrupt-parent = <&gic>;
ranges = <0x0 0xf0000000 0x00300000>;
+ lpc_kcs: lpc_kcs@7000 {
+ compatible = "nuvoton,npcm750-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,npcm750-kcs-bmc";
+ reg = <0x0 0x40>;
+ interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+ kcs_chan = <1>;
+ status = "disabled";
+ };
+
+ kcs2: kcs2@0 {
+ compatible = "nuvoton,npcm750-kcs-bmc";
+ reg = <0x0 0x40>;
+ interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+ kcs_chan = <2>;
+ status = "disabled";
+ };
+
+ kcs3: kcs3@0 {
+ compatible = "nuvoton,npcm750-kcs-bmc";
+ reg = <0x0 0x40>;
+ interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+ kcs_chan = <3>;
+ status = "disabled";
+ };
+ };
+
+ lpc_host: lpc_host@7000 {
+ compatible = "nuvoton,npcm750-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,npcm750-lpc-bpc";
+ reg = <0x40 0x20>;
+ interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+ };
+
+ peci: bus@100000 {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0x100000 0x200>;
+ };
+
+ spi0: spi@200000 {
+ compatible = "nuvoton,npcm750-pspi";
+ reg = <0x200000 0x1000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pspi1_pins>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clk NPCM7XX_CLK_APB5>;
+ clock-names = "clk_apb5";
+ status = "disabled";
+ };
+
+ spi1: spi@201000 {
+ compatible = "nuvoton,npcm750-pspi";
+ reg = <0x201000 0x1000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pspi2_pins>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clk NPCM7XX_CLK_APB5>;
+ clock-names = "clk_apb5";
+ status = "disabled";
+ };
+
timer0: timer@8000 {
compatible = "nuvoton,npcm750-timer";
interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
- reg = <0x8000 0x50>;
- clocks = <&clk 5>;
+ reg = <0x8000 0x1C>;
+ clocks = <&clk NPCM7XX_CLK_TIMER>;
};
watchdog0: watchdog@801C {
@@ -128,7 +390,7 @@
interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
reg = <0x801C 0x4>;
status = "disabled";
- clocks = <&clk 5>;
+ clocks = <&clk NPCM7XX_CLK_TIMER>;
};
watchdog1: watchdog@901C {
@@ -136,7 +398,7 @@
interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
reg = <0x901C 0x4>;
status = "disabled";
- clocks = <&clk 5>;
+ clocks = <&clk NPCM7XX_CLK_TIMER>;
};
watchdog2: watchdog@a01C {
@@ -144,13 +406,13 @@
interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
reg = <0xa01C 0x4>;
status = "disabled";
- clocks = <&clk 5>;
+ clocks = <&clk NPCM7XX_CLK_TIMER>;
};
serial0: serial@1000 {
compatible = "nuvoton,npcm750-uart";
reg = <0x1000 0x1000>;
- clocks = <&clk 6>;
+ clocks = <&clk NPCM7XX_CLK_UART>;
interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
status = "disabled";
@@ -159,7 +421,7 @@
serial1: serial@2000 {
compatible = "nuvoton,npcm750-uart";
reg = <0x2000 0x1000>;
- clocks = <&clk 6>;
+ clocks = <&clk NPCM7XX_CLK_UART>;
interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
status = "disabled";
@@ -168,7 +430,7 @@
serial2: serial@3000 {
compatible = "nuvoton,npcm750-uart";
reg = <0x3000 0x1000>;
- clocks = <&clk 6>;
+ clocks = <&clk NPCM7XX_CLK_UART>;
interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
status = "disabled";
@@ -177,11 +439,830 @@
serial3: serial@4000 {
compatible = "nuvoton,npcm750-uart";
reg = <0x4000 0x1000>;
- clocks = <&clk 6>;
+ clocks = <&clk NPCM7XX_CLK_UART>;
interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
status = "disabled";
};
+
+ rng: rng@b000 {
+ compatible = "nuvoton,npcm750-rng";
+ reg = <0xb000 0x1000>;
+ clocks = <&clk NPCM7XX_CLK_APB1>;
+ clock-names = "clk_apb1";
+ status = "disabled";
+ };
+
+ adc: adc@c000 {
+ compatible = "nuvoton,npcm750-adc";
+ reg = <0xc000 0x8>;
+ interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clk NPCM7XX_CLK_ADC>;
+ status = "disabled";
+ };
+
+ otp:otp@189000 {
+ compatible = "nuvoton,npcm750-otp";
+ reg = <0x189000 0x1000
+ 0x18a000 0x1000>;
+ status = "disabled";
+ clocks = <&clk NPCM7XX_CLK_APB4>;
+ clock-names = "clk_apb4";
+ };
+
+ pwm_fan:pwm-fan-controller@103000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "nuvoton,npcm750-pwm-fan";
+ reg = <0x103000 0x2000>,
+ <0x180000 0x8000>;
+ reg-names = "pwm", "fan";
+ clocks = <&clk NPCM7XX_CLK_APB3>,
+ <&clk NPCM7XX_CLK_APB4>;
+ clock-names = "pwm","fan";
+ interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm0_pins &pwm1_pins
+ &pwm2_pins &pwm3_pins
+ &pwm4_pins &pwm5_pins
+ &pwm6_pins &pwm7_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";
+ };
+
+ i2c0: i2c@80000 {
+ reg = <0x80000 0x1000>;
+ compatible = "nuvoton,npcm750-i2c";
+ clocks = <&clk NPCM7XX_CLK_APB2>;
+ bus-frequency = <100000>;
+ interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&smb0_pins>;
+ status = "disabled";
+ };
+
+ i2c1: i2c@81000 {
+ reg = <0x81000 0x1000>;
+ compatible = "nuvoton,npcm750-i2c";
+ clocks = <&clk NPCM7XX_CLK_APB2>;
+ bus-frequency = <100000>;
+ interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&smb1_pins>;
+ status = "disabled";
+ };
+
+ i2c2: i2c@82000 {
+ reg = <0x82000 0x1000>;
+ compatible = "nuvoton,npcm750-i2c";
+ clocks = <&clk NPCM7XX_CLK_APB2>;
+ bus-frequency = <100000>;
+ interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&smb2_pins>;
+ status = "disabled";
+ };
+
+ i2c3: i2c@83000 {
+ reg = <0x83000 0x1000>;
+ compatible = "nuvoton,npcm750-i2c";
+ clocks = <&clk NPCM7XX_CLK_APB2>;
+ bus-frequency = <100000>;
+ interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&smb3_pins>;
+ status = "disabled";
+ };
+
+ i2c4: i2c@84000 {
+ reg = <0x84000 0x1000>;
+ compatible = "nuvoton,npcm750-i2c";
+ clocks = <&clk NPCM7XX_CLK_APB2>;
+ bus-frequency = <100000>;
+ interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&smb4_pins>;
+ status = "disabled";
+ };
+
+ i2c5: i2c@85000 {
+ reg = <0x85000 0x1000>;
+ compatible = "nuvoton,npcm750-i2c";
+ clocks = <&clk NPCM7XX_CLK_APB2>;
+ bus-frequency = <100000>;
+ interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&smb5_pins>;
+ status = "disabled";
+ };
+
+ i2c6: i2c@86000 {
+ reg = <0x86000 0x1000>;
+ compatible = "nuvoton,npcm750-i2c";
+ clocks = <&clk NPCM7XX_CLK_APB2>;
+ bus-frequency = <100000>;
+ interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&smb6_pins>;
+ status = "disabled";
+ };
+
+ i2c7: i2c@87000 {
+ reg = <0x87000 0x1000>;
+ compatible = "nuvoton,npcm750-i2c";
+ clocks = <&clk NPCM7XX_CLK_APB2>;
+ bus-frequency = <100000>;
+ interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&smb7_pins>;
+ status = "disabled";
+ };
+
+ i2c8: i2c@88000 {
+ reg = <0x88000 0x1000>;
+ compatible = "nuvoton,npcm750-i2c";
+ clocks = <&clk NPCM7XX_CLK_APB2>;
+ bus-frequency = <100000>;
+ interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&smb8_pins>;
+ status = "disabled";
+ };
+
+ i2c9: i2c@89000 {
+ reg = <0x89000 0x1000>;
+ compatible = "nuvoton,npcm750-i2c";
+ clocks = <&clk NPCM7XX_CLK_APB2>;
+ bus-frequency = <100000>;
+ interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&smb9_pins>;
+ status = "disabled";
+ };
+
+ i2c10: i2c@8a000 {
+ reg = <0x8a000 0x1000>;
+ compatible = "nuvoton,npcm750-i2c";
+ clocks = <&clk NPCM7XX_CLK_APB2>;
+ bus-frequency = <100000>;
+ interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&smb10_pins>;
+ status = "disabled";
+ };
+
+ i2c11: i2c@8b000 {
+ reg = <0x8b000 0x1000>;
+ compatible = "nuvoton,npcm750-i2c";
+ clocks = <&clk NPCM7XX_CLK_APB2>;
+ bus-frequency = <100000>;
+ interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&smb11_pins>;
+ status = "disabled";
+ };
+
+ i2c12: i2c@8c000 {
+ reg = <0x8c000 0x1000>;
+ compatible = "nuvoton,npcm750-i2c";
+ clocks = <&clk NPCM7XX_CLK_APB2>;
+ bus-frequency = <100000>;
+ interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&smb12_pins>;
+ status = "disabled";
+ };
+
+ i2c13: i2c@8d000 {
+ reg = <0x8d000 0x1000>;
+ compatible = "nuvoton,npcm750-i2c";
+ clocks = <&clk NPCM7XX_CLK_APB2>;
+ bus-frequency = <100000>;
+ interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&smb13_pins>;
+ status = "disabled";
+ };
+
+ i2c14: i2c@8e000 {
+ reg = <0x8e000 0x1000>;
+ compatible = "nuvoton,npcm750-i2c";
+ clocks = <&clk NPCM7XX_CLK_APB2>;
+ bus-frequency = <100000>;
+ interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&smb14_pins>;
+ status = "disabled";
+ };
+
+ i2c15: i2c@8f000 {
+ reg = <0x8f000 0x1000>;
+ compatible = "nuvoton,npcm750-i2c";
+ clocks = <&clk NPCM7XX_CLK_APB2>;
+ bus-frequency = <100000>;
+ interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&smb15_pins>;
+ status = "disabled";
+ };
+
+ gfxi: gfxi@f000e000 {
+ compatible = "nuvoton,npcm750-gfxi", "syscon",
+ "simple-mfd";
+ reg = <0xf000e000 0x100>;
+ };
+
+ };
+ };
+
+ pinctrl: pinctrl@f0800000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "nuvoton,npcm750-pinctrl", "syscon", "simple-mfd";
+ ranges = <0 0xf0010000 0x8000>;
+ status = "okay";
+ gpio0: gpio@f0010000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ reg = <0x0 0x80>;
+ interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-ranges = <&pinctrl 0 0 32>;
+ };
+ gpio1: gpio@f0011000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ reg = <0x1000 0x80>;
+ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-ranges = <&pinctrl 0 32 32>;
+ };
+ gpio2: gpio@f0012000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ reg = <0x2000 0x80>;
+ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-ranges = <&pinctrl 0 64 32>;
+ };
+ gpio3: gpio@f0013000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ reg = <0x3000 0x80>;
+ interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-ranges = <&pinctrl 0 96 32>;
+ };
+ gpio4: gpio@f0014000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ reg = <0x4000 0x80>;
+ interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-ranges = <&pinctrl 0 128 32>;
+ };
+ gpio5: gpio@f0015000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ reg = <0x5000 0x80>;
+ interrupts = <GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-ranges = <&pinctrl 0 160 32>;
};
+ gpio6: gpio@f0016000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ reg = <0x6000 0x80>;
+ interrupts = <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-ranges = <&pinctrl 0 192 32>;
+ };
+ gpio7: gpio@f0017000 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ reg = <0x7000 0x80>;
+ interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-ranges = <&pinctrl 0 224 32>;
+ };
+
+ iox1_pins: iox1-pins {
+ groups = "iox1";
+ function = "iox1";
+ };
+ iox2_pins: iox2-pins {
+ groups = "iox2";
+ function = "iox2";
+ };
+ smb1d_pins: smb1d-pins {
+ groups = "smb1d";
+ function = "smb1d";
+ };
+ smb2d_pins: smb2d-pins {
+ groups = "smb2d";
+ function = "smb2d";
+ };
+ lkgpo1_pins: lkgpo1-pins {
+ groups = "lkgpo1";
+ function = "lkgpo1";
+ };
+ lkgpo2_pins: lkgpo2-pins {
+ groups = "lkgpo2";
+ function = "lkgpo2";
+ };
+ ioxh_pins: ioxh-pins {
+ groups = "ioxh";
+ function = "ioxh";
+ };
+ gspi_pins: gspi-pins {
+ groups = "gspi";
+ function = "gspi";
+ };
+ smb5b_pins: smb5b-pins {
+ groups = "smb5b";
+ function = "smb5b";
+ };
+ smb5c_pins: smb5c-pins {
+ groups = "smb5c";
+ function = "smb5c";
+ };
+ lkgpo0_pins: lkgpo0-pins {
+ groups = "lkgpo0";
+ function = "lkgpo0";
+ };
+ pspi2_pins: pspi2-pins {
+ groups = "pspi2";
+ function = "pspi2";
+ };
+ smb4den_pins: smb4den-pins {
+ groups = "smb4den";
+ function = "smb4den";
+ };
+ smb4b_pins: smb4b-pins {
+ groups = "smb4b";
+ function = "smb4b";
+ };
+ smb4c_pins: smb4c-pins {
+ groups = "smb4c";
+ function = "smb4c";
+ };
+ smb15_pins: smb15-pins {
+ groups = "smb15";
+ function = "smb15";
+ };
+ smb4d_pins: smb4d-pins {
+ groups = "smb4d";
+ function = "smb4d";
+ };
+ smb14_pins: smb14-pins {
+ groups = "smb14";
+ function = "smb14";
+ };
+ smb5_pins: smb5-pins {
+ groups = "smb5";
+ function = "smb5";
+ };
+ smb4_pins: smb4-pins {
+ groups = "smb4";
+ function = "smb4";
+ };
+ smb3_pins: smb3-pins {
+ groups = "smb3";
+ function = "smb3";
+ };
+ spi0cs1_pins: spi0cs1-pins {
+ groups = "spi0cs1";
+ function = "spi0cs1";
+ };
+ spi0cs2_pins: spi0cs2-pins {
+ groups = "spi0cs2";
+ function = "spi0cs2";
+ };
+ spi0cs3_pins: spi0cs3-pins {
+ groups = "spi0cs3";
+ function = "spi0cs3";
+ };
+ smb3c_pins: smb3c-pins {
+ groups = "smb3c";
+ function = "smb3c";
+ };
+ smb3b_pins: smb3b-pins {
+ groups = "smb3b";
+ function = "smb3b";
+ };
+ bmcuart0a_pins: bmcuart0a-pins {
+ groups = "bmcuart0a";
+ function = "bmcuart0a";
+ };
+ uart1_pins: uart1-pins {
+ groups = "uart1";
+ function = "uart1";
+ };
+ jtag2_pins: jtag2-pins {
+ groups = "jtag2";
+ function = "jtag2";
+ };
+ bmcuart1_pins: bmcuart1-pins {
+ groups = "bmcuart1";
+ function = "bmcuart1";
+ };
+ uart2_pins: uart2-pins {
+ groups = "uart2";
+ function = "uart2";
+ };
+ bmcuart0b_pins: bmcuart0b-pins {
+ groups = "bmcuart0b";
+ function = "bmcuart0b";
+ };
+ r1err_pins: r1err-pins {
+ groups = "r1err";
+ function = "r1err";
+ };
+ r1md_pins: r1md-pins {
+ groups = "r1md";
+ function = "r1md";
+ };
+ smb3d_pins: smb3d-pins {
+ groups = "smb3d";
+ function = "smb3d";
+ };
+ fanin0_pins: fanin0-pins {
+ groups = "fanin0";
+ function = "fanin0";
+ };
+ fanin1_pins: fanin1-pins {
+ groups = "fanin1";
+ function = "fanin1";
+ };
+ fanin2_pins: fanin2-pins {
+ groups = "fanin2";
+ function = "fanin2";
+ };
+ fanin3_pins: fanin3-pins {
+ groups = "fanin3";
+ function = "fanin3";
+ };
+ fanin4_pins: fanin4-pins {
+ groups = "fanin4";
+ function = "fanin4";
+ };
+ fanin5_pins: fanin5-pins {
+ groups = "fanin5";
+ function = "fanin5";
+ };
+ fanin6_pins: fanin6-pins {
+ groups = "fanin6";
+ function = "fanin6";
+ };
+ fanin7_pins: fanin7-pins {
+ groups = "fanin7";
+ function = "fanin7";
+ };
+ fanin8_pins: fanin8-pins {
+ groups = "fanin8";
+ function = "fanin8";
+ };
+ fanin9_pins: fanin9-pins {
+ groups = "fanin9";
+ function = "fanin9";
+ };
+ fanin10_pins: fanin10-pins {
+ groups = "fanin10";
+ function = "fanin10";
+ };
+ fanin11_pins: fanin11-pins {
+ groups = "fanin11";
+ function = "fanin11";
+ };
+ fanin12_pins: fanin12-pins {
+ groups = "fanin12";
+ function = "fanin12";
+ };
+ fanin13_pins: fanin13-pins {
+ groups = "fanin13";
+ function = "fanin13";
+ };
+ fanin14_pins: fanin14-pins {
+ groups = "fanin14";
+ function = "fanin14";
+ };
+ fanin15_pins: fanin15-pins {
+ groups = "fanin15";
+ function = "fanin15";
+ };
+ pwm0_pins: pwm0-pins {
+ groups = "pwm0";
+ function = "pwm0";
+ };
+ pwm1_pins: pwm1-pins {
+ groups = "pwm1";
+ function = "pwm1";
+ };
+ pwm2_pins: pwm2-pins {
+ groups = "pwm2";
+ function = "pwm2";
+ };
+ pwm3_pins: pwm3-pins {
+ groups = "pwm3";
+ function = "pwm3";
+ };
+ r2_pins: r2-pins {
+ groups = "r2";
+ function = "r2";
+ };
+ r2err_pins: r2err-pins {
+ groups = "r2err";
+ function = "r2err";
+ };
+ r2md_pins: r2md-pins {
+ groups = "r2md";
+ function = "r2md";
+ };
+ ga20kbc_pins: ga20kbc-pins {
+ groups = "ga20kbc";
+ function = "ga20kbc";
+ };
+ smb5d_pins: smb5d-pins {
+ groups = "smb5d";
+ function = "smb5d";
+ };
+ lpc_pins: lpc-pins {
+ groups = "lpc";
+ function = "lpc";
+ };
+ espi_pins: espi-pins {
+ groups = "espi";
+ function = "espi";
+ };
+ rg1_pins: rg1-pins {
+ groups = "rg1";
+ function = "rg1";
+ };
+ rg1mdio_pins: rg1mdio-pins {
+ groups = "rg1mdio";
+ function = "rg1mdio";
+ };
+ rg2_pins: rg2-pins {
+ groups = "rg2";
+ function = "rg2";
+ };
+ ddr_pins: ddr-pins {
+ groups = "ddr";
+ function = "ddr";
+ };
+ smb0_pins: smb0-pins {
+ groups = "smb0";
+ function = "smb0";
+ };
+ smb1_pins: smb1-pins {
+ groups = "smb1";
+ function = "smb1";
+ };
+ smb2_pins: smb2-pins {
+ groups = "smb2";
+ function = "smb2";
+ };
+ smb2c_pins: smb2c-pins {
+ groups = "smb2c";
+ function = "smb2c";
+ };
+ smb2b_pins: smb2b-pins {
+ groups = "smb2b";
+ function = "smb2b";
+ };
+ smb1c_pins: smb1c-pins {
+ groups = "smb1c";
+ function = "smb1c";
+ };
+ smb1b_pins: smb1b-pins {
+ groups = "smb1b";
+ function = "smb1b";
+ };
+ smb8_pins: smb8-pins {
+ groups = "smb8";
+ function = "smb8";
+ };
+ smb9_pins: smb9-pins {
+ groups = "smb9";
+ function = "smb9";
+ };
+ smb10_pins: smb10-pins {
+ groups = "smb10";
+ function = "smb10";
+ };
+ smb11_pins: smb11-pins {
+ groups = "smb11";
+ function = "smb11";
+ };
+ sd1_pins: sd1-pins {
+ groups = "sd1";
+ function = "sd1";
+ };
+ sd1pwr_pins: sd1pwr-pins {
+ groups = "sd1pwr";
+ function = "sd1pwr";
+ };
+ pwm4_pins: pwm4-pins {
+ groups = "pwm4";
+ function = "pwm4";
+ };
+ pwm5_pins: pwm5-pins {
+ groups = "pwm5";
+ function = "pwm5";
+ };
+ pwm6_pins: pwm6-pins {
+ groups = "pwm6";
+ function = "pwm6";
+ };
+ pwm7_pins: pwm7-pins {
+ groups = "pwm7";
+ function = "pwm7";
+ };
+ mmc8_pins: mmc8-pins {
+ groups = "mmc8";
+ function = "mmc8";
+ };
+ mmc_pins: mmc-pins {
+ groups = "mmc";
+ function = "mmc";
+ };
+ mmcwp_pins: mmcwp-pins {
+ groups = "mmcwp";
+ function = "mmcwp";
+ };
+ mmccd_pins: mmccd-pins {
+ groups = "mmccd";
+ function = "mmccd";
+ };
+ mmcrst_pins: mmcrst-pins {
+ groups = "mmcrst";
+ function = "mmcrst";
+ };
+ clkout_pins: clkout-pins {
+ groups = "clkout";
+ function = "clkout";
+ };
+ serirq_pins: serirq-pins {
+ groups = "serirq";
+ function = "serirq";
+ };
+ lpcclk_pins: lpcclk-pins {
+ groups = "lpcclk";
+ function = "lpcclk";
+ };
+ scipme_pins: scipme-pins {
+ groups = "scipme";
+ function = "scipme";
+ };
+ sci_pins: sci-pins {
+ groups = "sci";
+ function = "sci";
+ };
+ smb6_pins: smb6-pins {
+ groups = "smb6";
+ function = "smb6";
+ };
+ smb7_pins: smb7-pins {
+ groups = "smb7";
+ function = "smb7";
+ };
+ pspi1_pins: pspi1-pins {
+ groups = "pspi1";
+ function = "pspi1";
+ };
+ faninx_pins: faninx-pins {
+ groups = "faninx";
+ function = "faninx";
+ };
+ r1_pins: r1-pins {
+ groups = "r1";
+ function = "r1";
+ };
+ spi3_pins: spi3-pins {
+ groups = "spi3";
+ function = "spi3";
+ };
+ spi3cs1_pins: spi3cs1-pins {
+ groups = "spi3cs1";
+ function = "spi3cs1";
+ };
+ spi3quad_pins: spi3quad-pins {
+ groups = "spi3quad";
+ function = "spi3quad";
+ };
+ spi3cs2_pins: spi3cs2-pins {
+ groups = "spi3cs2";
+ function = "spi3cs2";
+ };
+ spi3cs3_pins: spi3cs3-pins {
+ groups = "spi3cs3";
+ function = "spi3cs3";
+ };
+ nprd_smi_pins: nprd-smi-pins {
+ groups = "nprd_smi";
+ function = "nprd_smi";
+ };
+ smb0b_pins: smb0b-pins {
+ groups = "smb0b";
+ function = "smb0b";
+ };
+ smb0c_pins: smb0c-pins {
+ groups = "smb0c";
+ function = "smb0c";
+ };
+ smb0den_pins: smb0den-pins {
+ groups = "smb0den";
+ function = "smb0den";
+ };
+ smb0d_pins: smb0d-pins {
+ groups = "smb0d";
+ function = "smb0d";
+ };
+ ddc_pins: ddc-pins {
+ groups = "ddc";
+ function = "ddc";
+ };
+ rg2mdio_pins: rg2mdio-pins {
+ groups = "rg2mdio";
+ function = "rg2mdio";
+ };
+ wdog1_pins: wdog1-pins {
+ groups = "wdog1";
+ function = "wdog1";
+ };
+ wdog2_pins: wdog2-pins {
+ groups = "wdog2";
+ function = "wdog2";
+ };
+ smb12_pins: smb12-pins {
+ groups = "smb12";
+ function = "smb12";
+ };
+ smb13_pins: smb13-pins {
+ groups = "smb13";
+ function = "smb13";
+ };
+ spix_pins: spix-pins {
+ groups = "spix";
+ function = "spix";
+ };
+ spixcs1_pins: spixcs1-pins {
+ groups = "spixcs1";
+ function = "spixcs1";
+ };
+ clkreq_pins: clkreq-pins {
+ groups = "clkreq";
+ function = "clkreq";
+ };
+ hgpio0_pins: hgpio0-pins {
+ groups = "hgpio0";
+ function = "hgpio0";
+ };
+ hgpio1_pins: hgpio1-pins {
+ groups = "hgpio1";
+ function = "hgpio1";
+ };
+ hgpio2_pins: hgpio2-pins {
+ groups = "hgpio2";
+ function = "hgpio2";
+ };
+ hgpio3_pins: hgpio3-pins {
+ groups = "hgpio3";
+ function = "hgpio3";
+ };
+ hgpio4_pins: hgpio4-pins {
+ groups = "hgpio4";
+ function = "hgpio4";
+ };
+ hgpio5_pins: hgpio5-pins {
+ groups = "hgpio5";
+ function = "hgpio5";
+ };
+ hgpio6_pins: hgpio6-pins {
+ groups = "hgpio6";
+ function = "hgpio6";
+ };
+ hgpio7_pins: hgpio7-pins {
+ groups = "hgpio7";
+ function = "hgpio7";
+ };
+ };
+};
+
+&peci {
+ peci0: peci-bus@0 {
+ compatible = "nuvoton,npcm750-peci";
+ reg = <0x0 0x200>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clk NPCM7XX_CLK_APB3>;
+ status = "disabled";
};
};
diff --git a/arch/arm/boot/dts/nuvoton-npcm730-gsj-gpio.dtsi b/arch/arm/boot/dts/nuvoton-npcm730-gsj-gpio.dtsi
new file mode 100644
index 000000000000..53cfd15fa03f
--- /dev/null
+++ b/arch/arm/boot/dts/nuvoton-npcm730-gsj-gpio.dtsi
@@ -0,0 +1,477 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018 Nuvoton Technology tomer.maimon@nuvoton.com
+
+/ {
+ pinctrl: pinctrl@f0800000 {
+ gpio0pp_pins: gpio0pp-pins {
+ pins = "GPIO0/IOX1DI";
+ bias-disable;
+ drive-push-pull;
+ };
+ gpio1pp_pins: gpio1pp-pins {
+ pins = "GPIO1/IOX1LD";
+ bias-disable;
+ drive-push-pull;
+ };
+ gpio2pp_pins: gpio2pp-pins {
+ pins = "GPIO2/IOX1CK";
+ bias-disable;
+ drive-push-pull;
+ };
+ gpio3pp_pins: gpio3pp-pins {
+ pins = "GPIO3/IOX1D0";
+ bias-disable;
+ drive-push-pull;
+ };
+ gpio4pp_pins: gpio4pp-pins {
+ pins = "GPIO4/IOX2DI/SMB1DSDA";
+ bias-disable;
+ drive-push-pull;
+ };
+ gpio5pp_pins: gpio5pp-pins {
+ pins = "GPIO5/IOX2LD/SMB1DSCL";
+ bias-disable;
+ drive-push-pull;
+ };
+ gpio6pp_pins: gpio6pp-pins {
+ pins = "GPIO6/IOX2CK/SMB2DSDA";
+ bias-disable;
+ drive-push-pull;
+ };
+ gpio7pp_pins: gpio7pp-pins {
+ pins = "GPIO7/IOX2D0/SMB2DSCL";
+ bias-disable;
+ drive-push-pull;
+ };
+ gpio8_pins: gpio8-pins {
+ pins = "GPIO8/LKGPO1";
+ bias-disable;
+ input-enable;
+ };
+ gpio9_pins: gpio9-pins {
+ pins = "GPIO9/LKGPO2";
+ bias-disable;
+ input-enable;
+ };
+ gpio10pp_pins: gpio10pp-pins {
+ pins = "GPIO10/IOXHLD";
+ bias-disable;
+ drive-push-pull;
+ };
+ gpio11pp_pins: gpio11pp-pins {
+ pins = "GPIO11/IOXHCK";
+ bias-disable;
+ drive-push-pull;
+ };
+ gpio12_pins: gpio12-pins {
+ pins = "GPIO12/GSPICK/SMB5BSCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio13_pins: gpio13-pins {
+ pins = "GPIO13/GSPIDO/SMB5BSDA";
+ bias-disable;
+ input-enable;
+ };
+ gpio14_pins: gpio14-pins {
+ pins = "GPIO14/GSPIDI/SMB5CSCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio15od_pins: gpio15od-pins {
+ pins = "GPIO15/GSPICS/SMB5CSDA";
+ bias-disable;
+ drive-open-drain;
+ };
+ gpio17pp_pins: gpio17pp-pins {
+ pins = "GPIO17/PSPI2DI/SMB4DEN";
+ bias-disable;
+ drive-push-pull;
+ };
+ gpio18pp_pins: gpio18pp-pins {
+ pins = "GPIO18/PSPI2D0/SMB4BSDA";
+ bias-disable;
+ drive-push-pull;
+ };
+ gpio19pp_pins: gpio19pp-pins {
+ pins = "GPIO19/PSPI2CK/SMB4BSCL";
+ bias-disable;
+ drive-push-pull;
+ };
+ gpio24pp_pins: gpio24pp-pins {
+ pins = "GPIO24/IOXHDO";
+ bias-disable;
+ drive-push-pull;
+ };
+ gpio25pp_pins: gpio25pp-pins {
+ pins = "GPIO25/IOXHDI";
+ bias-disable;
+ drive-push-pull;
+ };
+ gpio37od_pins: gpio37od-pins {
+ pins = "GPIO37/SMB3CSDA";
+ bias-disable;
+ drive-open-drain;
+ };
+ gpio59pp_pins: gpio59pp-pins {
+ pins = "GPIO59/SMB3DSDA";
+ bias-disable;
+ drive-push-pull;
+ };
+ gpio60_pins: gpio60-pins {
+ pins = "GPIO60/SMB3DSCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio72od_pins: gpio72od-pins {
+ pins = "GPIO72/FANIN8";
+ bias-disable;
+ drive-open-drain;
+ };
+ gpio73od_pins: gpio73od-pins {
+ pins = "GPIO73/FANIN9";
+ bias-disable;
+ drive-open-drain;
+ };
+ gpio74od_pins: gpio74od-pins {
+ pins = "GPIO74/FANIN10";
+ bias-disable;
+ drive-open-drain;
+ };
+ gpio75od_pins: gpio75od-pins {
+ pins = "GPIO75/FANIN11";
+ bias-disable;
+ drive-open-drain;
+ };
+ gpio76od_pins: gpio76od-pins {
+ pins = "GPIO76/FANIN12";
+ bias-disable;
+ drive-open-drain;
+ };
+ gpio77od_pins: gpio77od-pins {
+ pins = "GPIO77/FANIN13";
+ bias-disable;
+ drive-open-drain;
+ };
+ gpio78od_pins: gpio78od-pins {
+ pins = "GPIO78/FANIN14";
+ bias-disable;
+ drive-open-drain;
+ };
+ gpio79od_pins: gpio79od-pins {
+ pins = "GPIO79/FANIN15";
+ bias-disable;
+ drive-open-drain;
+ };
+ gpio83_pins: gpio83-pins {
+ pins = "GPIO83/PWM3";
+ bias-disable;
+ input-enable;
+ };
+ gpio84pp_pins: gpio84pp-pins {
+ pins = "GPIO84/R2TXD0";
+ bias-disable;
+ drive-push-pull;
+ };
+ gpio85pp_pins: gpio85pp-pins {
+ pins = "GPIO85/R2TXD1";
+ bias-disable;
+ drive-push-pull;
+ };
+ gpio86pp_pins: gpio86pp-pins {
+ pins = "GPIO86/R2TXEN";
+ bias-disable;
+ drive-push-pull;
+ };
+ gpio87pp_pins: gpio87pp-pins {
+ pins = "GPIO87/R2RXD0";
+ bias-disable;
+ drive-push-pull;
+ };
+ gpio88pp_pins: gpio88pp-pins {
+ pins = "GPIO88/R2RXD1";
+ bias-disable;
+ drive-push-pull;
+ };
+ gpio89pp_pins: gpio89pp-pins {
+ pins = "GPIO89/R2CRSDV";
+ bias-disable;
+ drive-push-pull;
+ };
+ gpio90pp_pins: gpio90pp-pins {
+ pins = "GPIO90/R2RXERR";
+ bias-disable;
+ drive-push-pull;
+ };
+ gpio91_pins: gpio91-pins {
+ pins = "GPIO91/R2MDC";
+ bias-disable;
+ input-enable;
+ };
+ gpio92_pins: gpio92-pins {
+ pins = "GPIO92/R2MDIO";
+ bias-disable;
+ input-enable;
+ };
+ gpio93pp_pins: gpio93pp-pins {
+ pins = "GPIO93/GA20/SMB5DSCL";
+ bias-disable;
+ drive-push-pull;
+ };
+ gpio94pp_pins: gpio94pp-pins {
+ pins = "GPIO94/nKBRST/SMB5DSDA";
+ bias-disable;
+ drive-push-pull;
+ };
+ gpio95_pins: gpio95-pins {
+ pins = "GPIO95/nLRESET/nESPIRST";
+ bias-disable;
+ input-enable;
+ };
+ gpio125pp_pins: gpio125pp-pins {
+ pins = "GPIO125/SMB1CSCL";
+ bias-disable;
+ drive-push-pull;
+ };
+ gpio126od_pins: gpio126od-pins {
+ pins = "GPIO126/SMB1BSDA";
+ bias-disable;
+ drive-open-drain;
+ };
+ gpio127od_pins: gpio127od-pins {
+ pins = "GPIO127/SMB1BSCL";
+ bias-disable;
+ drive-open-drain;
+ };
+ gpio136_pins: gpio136-pins {
+ pins = "GPIO136/SD1DT0";
+ bias-disable;
+ input-enable;
+ };
+ gpio137_pins: gpio137-pins {
+ pins = "GPIO137/SD1DT1";
+ bias-disable;
+ input-enable;
+ };
+ gpio141_pins: gpio141-pins {
+ pins = "GPIO141/SD1WP";
+ bias-disable;
+ input-enable;
+ };
+ gpio142od_pins: gpio142od-pins {
+ pins = "GPIO142/SD1CMD";
+ bias-disable;
+ drive-open-drain;
+ };
+ gpio143ol_pins: gpio143ol-pins {
+ pins = "GPIO143/SD1CD/SD1PWR";
+ bias-disable;
+ output-low;
+ };
+ gpio144_pins: gpio144-pins {
+ pins = "GPIO144/PWM4";
+ bias-disable;
+ input-enable;
+ };
+ gpio145_pins: gpio145-pins {
+ pins = "GPIO145/PWM5";
+ bias-disable;
+ input-enable;
+ };
+ gpio146_pins: gpio146-pins {
+ pins = "GPIO146/PWM6";
+ bias-disable;
+ input-enable;
+ };
+ gpio147_pins: gpio147-pins {
+ pins = "GPIO147/PWM7";
+ bias-disable;
+ input-enable;
+ };
+ gpio148_pins: gpio148-pins {
+ pins = "GPIO148/MMCDT4";
+ bias-disable;
+ input-enable;
+ };
+ gpio149_pins: gpio149-pins {
+ pins = "GPIO149/MMCDT5";
+ bias-disable;
+ input-enable;
+ };
+ gpio150_pins: gpio150-pins {
+ pins = "GPIO150/MMCDT6";
+ bias-disable;
+ input-enable;
+ };
+ gpio151_pins: gpio151-pins {
+ pins = "GPIO151/MMCDT7";
+ bias-disable;
+ input-enable;
+ };
+ gpio152_pins: gpio152-pins {
+ pins = "GPIO152/MMCCLK";
+ bias-disable;
+ input-enable;
+ };
+ gpio153_pins: gpio153-pins {
+ pins = "GPIO153/MMCWP";
+ bias-disable;
+ input-enable;
+ };
+ gpio154_pins: gpio154-pins {
+ pins = "GPIO154/MMCCMD";
+ bias-disable;
+ input-enable;
+ };
+ gpio155_pins: gpio155-pins {
+ pins = "GPIO155/nMMCCD/nMMCRST";
+ bias-disable;
+ input-enable;
+ };
+ gpio156_pins: gpio156-pins {
+ pins = "GPIO156/MMCDT0";
+ bias-disable;
+ input-enable;
+ };
+ gpio157_pins: gpio157-pins {
+ pins = "GPIO157/MMCDT1";
+ bias-disable;
+ input-enable;
+ };
+ gpio158_pins: gpio158-pins {
+ pins = "GPIO158/MMCDT2";
+ bias-disable;
+ input-enable;
+ };
+ gpio159_pins: gpio159-pins {
+ pins = "GPIO159/MMCDT3";
+ bias-disable;
+ input-enable;
+ };
+ gpio161_pins: gpio161-pins {
+ pins = "GPIO161/nLFRAME/nESPICS";
+ bias-disable;
+ input-enable;
+ };
+ gpio162_pins: gpio162-pins {
+ pins = "GPIO162/SERIRQ";
+ bias-disable;
+ input-enable;
+ };
+ gpio163_pins: gpio163-pins {
+ pins = "GPIO163/LCLK/ESPICLK";
+ bias-disable;
+ input-enable;
+ };
+ gpio164_pins: gpio164-pins {
+ pins = "GPIO164/LAD0/ESPI_IO0";
+ bias-disable;
+ input-enable;
+ };
+ gpio165_pins: gpio165-pins {
+ pins = "GPIO165/LAD1/ESPI_IO1";
+ bias-disable;
+ input-enable;
+ };
+ gpio166_pins: gpio166-pins {
+ pins = "GPIO166/LAD2/ESPI_IO2";
+ bias-disable;
+ input-enable;
+ };
+ gpio167_pins: gpio167-pins {
+ pins = "GPIO167/LAD3/ESPI_IO3";
+ bias-disable;
+ input-enable;
+ };
+ gpio168_pins: gpio168-pins {
+ pins = "GPIO168/nCLKRUN/nESPIALERT";
+ bias-disable;
+ input-enable;
+ };
+ gpio169_pins: gpio169-pins {
+ pins = "GPIO169/nSCIPME";
+ bias-disable;
+ input-enable;
+ };
+ gpio170_pins: gpio170-pins {
+ pins = "GPIO170/nSMI";
+ bias-disable;
+ input-enable;
+ };
+ gpio175od_pins: gpio175od-pins {
+ pins = "GPIO175/PSPI1CK/FANIN19";
+ bias-disable;
+ drive-open-drain;
+ };
+ gpio176od_pins: gpio176od-pins {
+ pins = "GPIO176/PSPI1DO/FANIN18";
+ bias-disable;
+ drive-open-drain;
+ };
+ gpio177_pins: gpio177-pins {
+ pins = "GPIO177/PSPI1DI/FANIN17";
+ bias-disable;
+ input-enable;
+ };
+ gpio190od_pins: gpio190od-pins {
+ pins = "GPIO190/nPRD_SMI";
+ bias-disable;
+ drive-open-drain;
+ };
+ gpio191_pins: gpio191-pins {
+ pins = "GPIO191";
+ bias-disable;
+ input-enable;
+ };
+ gpio192_pins: gpio192-pins {
+ pins = "GPIO192";
+ bias-disable;
+ input-enable;
+ };
+ gpio194pp_pins: gpio194pp-pins {
+ pins = "GPIO194/SMB0BSCL";
+ bias-disable;
+ drive-push-pull;
+ };
+ gpio195od_pins: gpio195od-pins {
+ pins = "GPIO195/SMB0BSDA";
+ bias-disable;
+ drive-open-drain;
+ };
+ gpio196od_pins: gpio196od-pins {
+ pins = "GPIO196/SMB0CSCL";
+ bias-disable;
+ drive-open-drain;
+ };
+ gpio197od_pins: gpio197od-pins {
+ pins = "GPIO197/SMB0DEN";
+ bias-disable;
+ drive-open-drain;
+ };
+ gpio198od_pins: gpio198od-pins {
+ pins = "GPIO198/SMB0DSDA";
+ bias-disable;
+ drive-open-drain;
+ };
+ gpio199od_pins: gpio199od-pins {
+ pins = "GPIO199/SMB0DSCL";
+ bias-disable;
+ drive-open-drain;
+ };
+ gpio200pp_pins: gpio200pp-pins {
+ pins = "GPIO200/R2CK";
+ bias-disable;
+ drive-push-pull;
+ };
+ gpio202od_pins: gpio202od-pins {
+ pins = "GPIO202/SMB0CSDA";
+ bias-disable;
+ drive-open-drain;
+ };
+ gpio203_pins: gpio203-pins {
+ pins = "GPIO203/FANIN16";
+ bias-disable;
+ input-enable;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/nuvoton-npcm730-gsj.dts b/arch/arm/boot/dts/nuvoton-npcm730-gsj.dts
new file mode 100644
index 000000000000..801ed73d962c
--- /dev/null
+++ b/arch/arm/boot/dts/nuvoton-npcm730-gsj.dts
@@ -0,0 +1,553 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2019 Quanta Computer lnc. Fran.Hsu@quantatw.com
+
+/dts-v1/;
+#include "nuvoton-npcm730.dtsi"
+#include "nuvoton-npcm730-gsj-gpio.dtsi"
+/ {
+ model = "Quanta GSJ Board (Device Tree v12)";
+ compatible = "nuvoton,npcm750";
+
+ aliases {
+ ethernet0 = &emc0;
+ ethernet1 = &gmac0;
+ serial3 = &serial3;
+ udc9 = &udc9;
+ i2c1 = &i2c1;
+ i2c2 = &i2c2;
+ i2c3 = &i2c3;
+ i2c4 = &i2c4;
+ i2c8 = &i2c8;
+ i2c9 = &i2c9;
+ i2c10 = &i2c10;
+ i2c11 = &i2c11;
+ i2c12 = &i2c12;
+ i2c15 = &i2c15;
+ fiu0 = &fiu0;
+ };
+
+ chosen {
+ stdout-path = &serial3;
+ };
+
+ memory {
+ reg = <0 0x40000000>;
+ };
+
+ ahb {
+ gmac0: eth@f0802000 {
+ phy-mode = "rgmii-id";
+ status = "okay";
+ };
+
+ mc: memory-controller@f0824000 {
+ compatible = "nuvoton,npcm7xx-sdram-edac";
+ reg = <0xf0824000 0x1000>;
+ interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ emc0: eth@f0825000 {
+ phy-mode = "rmii";
+ use-ncsi;
+ status = "okay";
+ };
+
+ ehci1: usb@f0806000 {
+ status = "okay";
+ };
+
+ ohci1: ohci@f0807000 {
+ status = "okay";
+ };
+
+ udc9:udc@f0839000 {
+ status = "okay";
+ };
+
+ aes:aes@f0858000 {
+ status = "okay";
+ };
+
+ sha:sha@f085a000 {
+ status = "okay";
+ };
+
+ fiu0: fiu@fb000000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi0cs1_pins>;
+ status = "okay";
+ spi-nor@0 {
+ compatible = "jedec,spi-nor";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0>;
+ spi-rx-bus-width = <2>;
+ partitions@80000000 {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ bmc@0{
+ label = "bmc";
+ reg = <0x000000 0x2000000>;
+ };
+ u-boot@0 {
+ label = "u-boot";
+ reg = <0x0000000 0x80000>;
+ read-only;
+ };
+ u-boot-env@100000{
+ label = "u-boot-env";
+ reg = <0x00100000 0x40000>;
+ };
+ kernel@200000 {
+ label = "kernel";
+ reg = <0x0200000 0x600000>;
+ };
+ rofs@800000 {
+ label = "rofs";
+ reg = <0x800000 0x1400000>;
+ };
+ rwfs@1c00000 {
+ label = "rwfs";
+ reg = <0x1c00000 0x300000>;
+ };
+ reserved@1f00000 {
+ label = "reserved";
+ reg = <0x1f00000 0x100000>;
+ };
+ };
+ };
+ };
+
+ pcimbox: pcimbox@f0848000 {
+ status = "okay";
+ };
+
+ apb {
+
+ watchdog1: watchdog@901C {
+ status = "okay";
+ };
+
+ rng: rng@b000 {
+ status = "okay";
+ };
+
+ serial0: serial@1000 {
+ status = "okay";
+ };
+
+ serial1: serial@2000 {
+ status = "okay";
+ };
+
+ serial2: serial@3000 {
+ status = "okay";
+ };
+
+ serial3: serial@4000 {
+ status = "okay";
+ };
+
+ adc: adc@c000 {
+ status = "okay";
+ };
+ otp:otp@189000 {
+ status = "okay";
+ };
+
+ i2c1: i2c@81000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ status = "okay";
+ lm75@5c {
+ compatible = "maxim,max31725";
+ reg = <0x5c>;
+ status = "okay";
+ };
+ };
+
+ i2c2: i2c@82000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ status = "okay";
+ lm75@5c {
+ compatible = "maxim,max31725";
+ reg = <0x5c>;
+ status = "okay";
+ };
+ };
+
+ i2c3: i2c@83000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ status = "okay";
+ lm75@5c {
+ compatible = "maxim,max31725";
+ reg = <0x5c>;
+ status = "okay";
+ };
+ };
+
+ i2c4: i2c@84000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ status = "okay";
+ lm75@5c {
+ compatible = "maxim,max31725";
+ reg = <0x5c>;
+ status = "okay";
+ };
+ };
+
+ i2c8: i2c@88000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ status = "okay";
+ };
+
+ i2c9: i2c@89000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ status = "okay";
+ eeprom@55 {
+ compatible = "atmel,24c64";
+ reg = <0x55>;
+ };
+ };
+
+ i2c10: i2c@8a000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ status = "okay";
+ eeprom@55 {
+ compatible = "atmel,24c64";
+ reg = <0x55>;
+ };
+ };
+
+ i2c11: i2c@8b000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ status = "okay";
+
+ /* P12V Quarter Brick DC/DC Power Module Q54SH12050 @60 */
+ power-brick@36 {
+ compatible = "delta,dps800";
+ reg = <0x36>;
+ };
+
+ hotswap@15 {
+ compatible = "ti,lm5066i";
+ reg = <0x15>;
+ };
+ };
+
+ i2c12: i2c@8c000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ status = "okay";
+ ucd90160@6b {
+ compatible = "ti,ucd90160";
+ reg = <0x6b>;
+ };
+ };
+
+ i2c15: i2c@8f000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ status = "okay";
+
+ i2c-switch@75 {
+ compatible = "nxp,pca9548";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x75>;
+ i2c-mux-idle-disconnect;
+
+ i2c_u20: i2c@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+ };
+
+ i2c_u21: i2c@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+ };
+
+ i2c_u22: i2c@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+ };
+
+ i2c_u23: i2c@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+ };
+
+ i2c_u24: i2c@4 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <4>;
+ };
+
+ i2c_u25: i2c@5 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <5>;
+ };
+
+ i2c_u26: i2c@6 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <6>;
+ };
+
+ i2c_u27: i2c@7 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <7>;
+ };
+ };
+ };
+
+ pwm_fan:pwm-fan-controller@103000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm0_pins &pwm1_pins &pwm2_pins
+ &fanin0_pins &fanin1_pins
+ &fanin2_pins &fanin3_pins
+ &fanin4_pins &fanin5_pins>;
+ status = "okay";
+
+ fan@0 {
+ reg = <0x00>;
+ fan-tach-ch = /bits/ 8 <0x00 0x01>;
+ cooling-levels = <127 255>;
+ };
+
+ fan@1 {
+ reg = <0x01>;
+ fan-tach-ch = /bits/ 8 <0x02 0x03>;
+ cooling-levels = /bits/ 8 <127 255>;
+ };
+
+ fan@2 {
+ reg = <0x02>;
+ fan-tach-ch = /bits/ 8 <0x04 0x05>;
+ cooling-levels = /bits/ 8 <127 255>;
+ };
+ };
+
+ };
+ };
+
+ pinctrl: pinctrl@f0800000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <
+ /* GPI pins*/
+ &gpio8_pins
+ &gpio9_pins
+ &gpio12_pins
+ &gpio13_pins
+ &gpio14_pins
+ &gpio60_pins
+ &gpio83_pins
+ &gpio91_pins
+ &gpio92_pins
+ &gpio95_pins
+ &gpio136_pins
+ &gpio137_pins
+ &gpio141_pins
+ &gpio144_pins
+ &gpio145_pins
+ &gpio146_pins
+ &gpio147_pins
+ &gpio148_pins
+ &gpio149_pins
+ &gpio150_pins
+ &gpio151_pins
+ &gpio152_pins
+ &gpio153_pins
+ &gpio154_pins
+ &gpio155_pins
+ &gpio156_pins
+ &gpio157_pins
+ &gpio158_pins
+ &gpio159_pins
+ &gpio161_pins
+ &gpio162_pins
+ &gpio163_pins
+ &gpio164_pins
+ &gpio165_pins
+ &gpio166_pins
+ &gpio167_pins
+ &gpio168_pins
+ &gpio169_pins
+ &gpio170_pins
+ &gpio177_pins
+ &gpio191_pins
+ &gpio192_pins
+ &gpio203_pins
+ /* GPO pins*/
+ &gpio0pp_pins
+ &gpio1pp_pins
+ &gpio2pp_pins
+ &gpio3pp_pins
+ &gpio4pp_pins
+ &gpio5pp_pins
+ &gpio6pp_pins
+ &gpio7pp_pins
+ &gpio10pp_pins
+ &gpio11pp_pins
+ &gpio15od_pins
+ &gpio17pp_pins
+ &gpio18pp_pins
+ &gpio19pp_pins
+ &gpio24pp_pins
+ &gpio25pp_pins
+ &gpio37od_pins
+ &gpio59pp_pins
+ &gpio72od_pins
+ &gpio73od_pins
+ &gpio74od_pins
+ &gpio75od_pins
+ &gpio76od_pins
+ &gpio77od_pins
+ &gpio78od_pins
+ &gpio79od_pins
+ &gpio84pp_pins
+ &gpio85pp_pins
+ &gpio86pp_pins
+ &gpio87pp_pins
+ &gpio88pp_pins
+ &gpio89pp_pins
+ &gpio90pp_pins
+ &gpio93pp_pins
+ &gpio94pp_pins
+ &gpio125pp_pins
+ &gpio126od_pins
+ &gpio127od_pins
+ &gpio142od_pins
+ &gpio143ol_pins
+ &gpio175od_pins
+ &gpio176od_pins
+ &gpio190od_pins
+ &gpio194pp_pins
+ &gpio195od_pins
+ &gpio196od_pins
+ &gpio197od_pins
+ &gpio198od_pins
+ &gpio199od_pins
+ &gpio200pp_pins
+ &gpio202od_pins
+ >;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ led-bmc-live {
+ gpios = <&gpio4 15 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+
+ LED_U2_0_LOCATE {
+ gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+
+ LED_U2_1_LOCATE {
+ gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+
+ LED_U2_2_LOCATE {
+ gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+
+ LED_U2_3_LOCATE {
+ gpios = <&gpio0 3 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+
+ LED_U2_4_LOCATE {
+ gpios = <&gpio0 10 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+
+ LED_U2_5_LOCATE {
+ gpios = <&gpio0 11 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+
+ LED_BMC_TRAY_PWRGD {
+ gpios = <&gpio0 19 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+
+ LED_U2_7_FAULT {
+ gpios = <&gpio6 8 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+
+ LED_U2_6_LOCATE {
+ gpios = <&gpio0 24 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+
+ LED_U2_7_LOCATE {
+ gpios = <&gpio0 25 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+
+ LED_U2_0_FAULT {
+ gpios = <&gpio2 20 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+
+ LED_U2_1_FAULT {
+ gpios = <&gpio2 21 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+
+ LED_U2_2_FAULT {
+ gpios = <&gpio2 22 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+
+ LED_U2_3_FAULT {
+ gpios = <&gpio2 23 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+
+ LED_U2_4_FAULT {
+ gpios = <&gpio2 24 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+
+ LED_U2_5_FAULT {
+ gpios = <&gpio2 25 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+
+ LED_U2_6_FAULT {
+ gpios = <&gpio2 26 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/nuvoton-npcm730.dtsi b/arch/arm/boot/dts/nuvoton-npcm730.dtsi
new file mode 100644
index 000000000000..20e13489b993
--- /dev/null
+++ b/arch/arm/boot/dts/nuvoton-npcm730.dtsi
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018 Nuvoton Technology tomer.maimon@nuvoton.com
+// Copyright 2018 Google, Inc.
+
+#include "nuvoton-common-npcm7xx.dtsi"
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ interrupt-parent = <&gic>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ enable-method = "nuvoton,npcm750-smp";
+
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ clocks = <&clk NPCM7XX_CLK_CPU>;
+ clock-names = "clk_cpu";
+ reg = <0>;
+ next-level-cache = <&l2>;
+ };
+
+ cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ clocks = <&clk NPCM7XX_CLK_CPU>;
+ clock-names = "clk_cpu";
+ reg = <1>;
+ next-level-cache = <&l2>;
+ };
+ };
+
+ soc {
+ timer@3fe600 {
+ compatible = "arm,cortex-a9-twd-timer";
+ reg = <0x3fe600 0x20>;
+ interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) |
+ IRQ_TYPE_LEVEL_HIGH)>;
+ clocks = <&clk NPCM7XX_CLK_AHB>;
+ };
+ };
+
+ ahb {
+ udc9:udc@f0839000 {
+ compatible = "nuvoton,npcm750-udc";
+ reg = <0xf0839000 0x1000
+ 0xfffd0000 0x800>;
+ interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ clocks = <&clk NPCM7XX_CLK_SU>;
+ clock-names = "clk_usb_bridge";
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/nuvoton-npcm750-evb.dts b/arch/arm/boot/dts/nuvoton-npcm750-evb.dts
index 15f744f1beea..e02c04910ef0 100644
--- a/arch/arm/boot/dts/nuvoton-npcm750-evb.dts
+++ b/arch/arm/boot/dts/nuvoton-npcm750-evb.dts
@@ -9,6 +9,50 @@
model = "Nuvoton npcm750 Development Board (Device Tree)";
compatible = "nuvoton,npcm750";
+ aliases {
+ ethernet0 = &emc0;
+ ethernet1 = &emc1;
+ ethernet2 = &gmac0;
+ ethernet3 = &gmac1;
+ serial0 = &serial0;
+ serial1 = &serial1;
+ serial2 = &serial2;
+ serial3 = &serial3;
+ udc0 = &udc0;
+ udc1 = &udc1;
+ udc2 = &udc2;
+ udc3 = &udc3;
+ udc4 = &udc4;
+ udc5 = &udc5;
+ udc6 = &udc6;
+ udc7 = &udc7;
+ udc8 = &udc8;
+ udc9 = &udc9;
+ emmc0 = &sdhci0;
+ emmc1 = &sdhci1;
+ i2c0 = &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;
+ spi0 = &spi0;
+ spi1 = &spi1;
+ fiu0 = &fiu0;
+ fiu1 = &fiu3;
+ fiu2 = &fiux;
+ };
+
chosen {
stdout-path = &serial3;
};
@@ -16,24 +60,554 @@
memory {
reg = <0 0x40000000>;
};
-};
-&watchdog1 {
- status = "okay";
-};
+ regulators {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <0>;
-&serial0 {
- status = "okay";
-};
+ reg_vref1_2: regulator@0 {
+ compatible = "regulator-fixed";
+ reg = <0>;
+ regulator-name = "vref_1_2v";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
+ reg_vref3_3: regulator@1 {
+ compatible = "regulator-fixed";
+ reg = <0>;
+ regulator-name = "vref_3_3v";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+ };
-&serial1 {
- status = "okay";
+ ahb {
+ gmac0: eth@f0802000 {
+ phy-mode = "rgmii-id";
+ status = "okay";
+ };
+
+ gmac1: eth@f0804000 {
+ phy-mode = "rgmii-id";
+ status = "okay";
+ };
+
+ emc0: eth@f0825000 {
+ phy-mode = "rmii";
+ #use-ncsi; /* add this to support ncsi */
+ status = "okay";
+ };
+
+ emc1: eth@f0826000 {
+ phy-mode = "rmii";
+ #use-ncsi; /* add this to support ncsi */
+ status = "okay";
+ };
+
+ ehci1: usb@f0806000 {
+ status = "okay";
+ };
+
+ ohci1: ohci@f0807000 {
+ status = "okay";
+ };
+
+ udc0:udc@f0830000 {
+ status = "okay";
+ };
+
+ udc1:udc@f0831000 {
+ status = "okay";
+ };
+
+ udc2:udc@f0832000 {
+ status = "okay";
+ };
+
+ udc3:udc@f0833000 {
+ status = "okay";
+ };
+
+ udc4:udc@f0834000 {
+ status = "okay";
+ };
+
+ udc5:udc@f0835000 {
+ status = "okay";
+ };
+
+ udc6:udc@f0836000 {
+ status = "okay";
+ };
+
+ udc7:udc@f0837000 {
+ status = "okay";
+ };
+
+ udc8:udc@f0838000 {
+ status = "okay";
+ };
+
+ udc9:udc@f0839000 {
+ status = "okay";
+ };
+
+ aes:aes@f0858000 {
+ status = "okay";
+ };
+
+ sha:sha@f085a000 {
+ status = "okay";
+ };
+
+ fiu0: fiu@fb000000 {
+ status = "okay";
+ spi-nor@0 {
+ compatible = "jedec,spi-nor";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ spi-rx-bus-width = <2>;
+ reg = <0>;
+ partitions@80000000 {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ bbuboot1@0 {
+ label = "bb-uboot-1";
+ reg = <0x0000000 0x80000>;
+ read-only;
+ };
+ bbuboot2@80000 {
+ label = "bb-uboot-2";
+ reg = <0x0080000 0x80000>;
+ read-only;
+ };
+ envparam@100000 {
+ label = "env-param";
+ reg = <0x0100000 0x40000>;
+ read-only;
+ };
+ spare@140000 {
+ label = "spare";
+ reg = <0x0140000 0xC0000>;
+ };
+ kernel@200000 {
+ label = "kernel";
+ reg = <0x0200000 0x400000>;
+ };
+ rootfs@600000 {
+ label = "rootfs";
+ reg = <0x0600000 0x700000>;
+ };
+ spare1@D00000 {
+ label = "spare1";
+ reg = <0x0D00000 0x200000>;
+ };
+ spare2@0F00000 {
+ label = "spare2";
+ reg = <0x0F00000 0x200000>;
+ };
+ spare3@1100000 {
+ label = "spare3";
+ reg = <0x1100000 0x200000>;
+ };
+ spare4@1300000 {
+ label = "spare4";
+ reg = <0x1300000 0x0>;
+ };
+ };
+ };
+ };
+
+ fiu3: fiu@c0000000 {
+ pinctrl-0 = <&spi3_pins>, <&spi3quad_pins>;
+ status = "okay";
+ spi-nor@0 {
+ compatible = "jedec,spi-nor";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ spi-rx-bus-width = <2>;
+ reg = <0>;
+ partitions@A0000000 {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ system1@0 {
+ label = "spi3-system1";
+ reg = <0x0 0x0>;
+ };
+ };
+ };
+ };
+
+ fiux: fiu@fb001000 {
+ spix-mode;
+ };
+
+ sdhci0: sdhci@f0842000 {
+ status = "okay";
+ };
+
+ sdhci1: sdhci@f0840000 {
+ status = "okay";
+ };
+
+ pcimbox: pcimbox@f0848000 {
+ status = "okay";
+ };
+
+ vcd: vcd@f0810000 {
+ status = "okay";
+ };
+
+ ece: ece@f0820000 {
+ status = "okay";
+ };
+
+ apb {
+
+ watchdog1: watchdog@901C {
+ status = "okay";
+ };
+
+ rng: rng@b000 {
+ status = "okay";
+ };
+
+ serial0: serial@1000 {
+ status = "okay";
+ };
+
+ serial1: serial@2000 {
+ status = "okay";
+ };
+
+ serial2: serial@3000 {
+ status = "okay";
+ };
+
+ serial3: serial@4000 {
+ status = "okay";
+ };
+
+ adc: adc@c000 {
+ /* enable external vref */
+ /*vref-supply = <&reg_vref1_2>;*/
+ status = "okay";
+ };
+
+ otp:otp@189000 {
+ status = "okay";
+ };
+
+ lpc_kcs: lpc_kcs@7000 {
+ kcs1: kcs1@0 {
+ status = "okay";
+ };
+
+ kcs2: kcs2@0 {
+ status = "okay";
+ };
+
+ kcs3: kcs3@0 {
+ status = "okay";
+ };
+ };
+
+ lpc_host: lpc_host@7000 {
+ lpc_bpc: lpc_bpc@40 {
+ monitor-ports = <0x80>;
+ status = "okay";
+ };
+ };
+
+ /* lm75 on SVB */
+ i2c0: i2c@80000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ status = "okay";
+
+ lm75@48 {
+ compatible = "lm75";
+ reg = <0x48>;
+ status = "okay";
+ };
+ };
+
+ /* lm75 on EB */
+ i2c1: i2c@81000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ status = "okay";
+
+ lm75@48 {
+ compatible = "lm75";
+ reg = <0x48>;
+ status = "okay";
+ };
+ };
+
+ /* tmp100 on EB */
+ i2c2: i2c@82000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ status = "okay";
+
+ tmp100@48 {
+ compatible = "tmp100";
+ reg = <0x48>;
+ status = "okay";
+ };
+ };
+
+ /* tmp100 on SVB */
+ i2c6: i2c@86000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ status = "okay";
+
+ tmp100@48 {
+ compatible = "tmp100";
+ reg = <0x48>;
+ status = "okay";
+ };
+ };
+ i2c3: i2c@83000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ status = "okay";
+ };
+
+ i2c4: i2c@84000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ status = "disabled";
+ };
+
+ i2c5: i2c@85000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ status = "okay";
+ };
+
+ i2c7: i2c@87000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ status = "okay";
+ };
+
+ i2c8: i2c@88000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ status = "okay";
+ };
+
+ i2c9: i2c@89000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ status = "okay";
+ };
+
+ i2c10: i2c@8a000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ status = "okay";
+ };
+
+ i2c11: i2c@8b000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ status = "okay";
+ };
+
+ i2c14: i2c@8e000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ status = "okay";
+ };
+
+ i2c15: i2c@8f000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ /* SVB conflict with pspi2 cs gpio20o_pins */
+ status = "disabled";
+ };
+
+ pwm_fan:pwm-fan-controller@103000 {
+ status = "okay";
+ fan@0 {
+ reg = <0x00>;
+ fan-tach-ch = /bits/ 8 <0x00 0x01>;
+ cooling-levels = <127 255>;
+ };
+ fan@1 {
+ reg = <0x01>;
+ fan-tach-ch = /bits/ 8 <0x02 0x03>;
+ cooling-levels = /bits/ 8 <127 255>;
+ };
+ fan@2 {
+ reg = <0x02>;
+ fan-tach-ch = /bits/ 8 <0x04 0x05>;
+ cooling-levels = /bits/ 8 <127 255>;
+ };
+ fan@3 {
+ reg = <0x03>;
+ fan-tach-ch = /bits/ 8 <0x06 0x07>;
+ cooling-levels = /bits/ 8 <127 255>;
+ };
+ fan@4 {
+ reg = <0x04>;
+ fan-tach-ch = /bits/ 8 <0x08 0x09>;
+ cooling-levels = /bits/ 8 <127 255>;
+ };
+ fan@5 {
+ reg = <0x05>;
+ fan-tach-ch = /bits/ 8 <0x0A 0x0B>;
+ cooling-levels = /bits/ 8 <127 255>;
+ };
+ fan@6 {
+ reg = <0x06>;
+ fan-tach-ch = /bits/ 8 <0x0C 0x0D>;
+ cooling-levels = /bits/ 8 <127 255>;
+ };
+ fan@7 {
+ reg = <0x07>;
+ fan-tach-ch = /bits/ 8 <0x0E 0x0F>;
+ cooling-levels = /bits/ 8 <127 255>;
+ };
+ };
+
+ spi0: spi@200000 {
+ cs-gpios = <&gpio6 11 GPIO_ACTIVE_LOW>;
+ status = "okay";
+ Flash@0 {
+ compatible = "winbond,w25q128",
+ "jedec,spi-nor";
+ reg = <0x0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ spi-max-frequency = <5000000>;
+ partition@0 {
+ label = "spi0_spare1";
+ reg = <0x0000000 0x800000>;
+ };
+ partition@1 {
+ label = "spi0_spare2";
+ reg = <0x800000 0x0>;
+ };
+ };
+ };
+
+ spi1: spi@201000 {
+ cs-gpios = <&gpio0 20 GPIO_ACTIVE_LOW>;
+ status = "okay";
+ Flash@0 {
+ compatible = "winbond,w25q128fw",
+ "jedec,spi-nor";
+ reg = <0x0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ spi-max-frequency = <5000000>;
+ partition@0 {
+ label = "spi1_spare1";
+ reg = <0x0000000 0x800000>;
+ };
+ partition@1 {
+ label = "spi1_spare2";
+ reg = <0x800000 0x0>;
+ };
+ };
+ };
+ };
+ };
+
+ pinctrl: pinctrl@f0800000 {
+ pinctrl-names = "default";
+ pinctrl-0 = < &iox1_pins
+ &gpio8_pins
+ &gpio9o_pins
+ &gpio10_pins
+ &gpio11o_pins
+ &gpio16_pins
+ &gpio24o_pins
+ &gpio25ol_pins
+ &gpio32o_pins
+ &jtag2_pins
+ &gpio61o_pins
+ &gpio62o_pins
+ &gpio63o_pins
+ &gpio64o_pins /* SVB pspi1 enable */
+ &gpio80_pins
+ &gpio81_pins
+ &gpio82_pins
+ &gpio83_pins
+ &lpc_pins
+ &gpio132_pins
+ &gpio133_pins
+ &gpio134_pins
+ &gpio135_pins
+ &gpio144_pins
+ &gpio145_pins
+ &gpio146_pins
+ &gpio147_pins
+ &gpio160_pins
+ &gpio162_pins
+ &gpio168_pins
+ &gpio169_pins
+ &gpio170_pins
+ &gpio187o_pins
+ &gpio190_pins
+ &gpio191o_pins
+ &gpio192o_pins
+ &gpio197ol_pins
+ &ddc_pins
+ &gpio218_pins
+ &gpio219ol_pins
+ &gpio220ol_pins
+ &gpio221o_pins
+ &gpio222_pins
+ &gpio223ol_pins
+ &spix_pins
+ &gpio228ol_pins
+ &gpio231o_pins
+ &gpio255_pins>;
+ };
};
-&serial2 {
- status = "okay";
+&gcr {
+ serial_port_mux: mux-controller {
+ compatible = "mmio-mux";
+ #mux-control-cells = <1>;
+
+ mux-reg-masks = <0x38 0x07>;
+ idle-states = <2>; /* Serial port mode 3 (takeover) */
+ };
};
-&serial3 {
+&peci0 {
+ cmd-timeout-ms = <1000>;
+ pull-down = <0>;
+ host-neg-bit-rate = <15>;
status = "okay";
+
+ intel-peci-dimmtemp@30 {
+ compatible = "intel,peci-client";
+ reg = <0x30>;
+ status = "okay";
+ };
};
diff --git a/arch/arm/boot/dts/nuvoton-npcm750-gpio.dtsi b/arch/arm/boot/dts/nuvoton-npcm750-gpio.dtsi
new file mode 100644
index 000000000000..a912910bc7ec
--- /dev/null
+++ b/arch/arm/boot/dts/nuvoton-npcm750-gpio.dtsi
@@ -0,0 +1,2021 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018 Nuvoton Technology tomer.maimon@nuvoton.com
+
+/ {
+ pinctrl: pinctrl@f0800000 {
+ gpio0o_pins: gpio0o-pins {
+ pins = "GPIO0/IOX1DI";
+ bias-disable;
+ output-high;
+ };
+ gpio1_pins: gpio1-pins {
+ pins = "GPIO1/IOX1LD";
+ bias-disable;
+ input-enable;
+ };
+ gpio2_pins: gpio2-pins {
+ pins = "GPIO2/IOX1CK";
+ bias-disable;
+ input-enable;
+ };
+ gpio2o_pins: gpio2o-pins {
+ pins = "GPIO2/IOX1CK";
+ bias-disable;
+ output_high;
+ };
+ gpio3_pins: gpio3-pins {
+ pins = "GPIO3/IOX1D0";
+ bias-disable;
+ input-enable;
+ };
+ gpio3o_pins: gpio3o-pins {
+ pins = "GPIO3/IOX1D0";
+ bias-disable;
+ output-high;
+ };
+ gpio4_pins: gpio4-pins {
+ pins = "GPIO4/IOX2DI/SMB1DSDA";
+ bias-disable;
+ input-enable;
+ };
+ gpio5_pins: gpio5-pins {
+ pins = "GPIO5/IOX2LD/SMB1DSCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio6_pins: gpio6-pins {
+ pins = "GPIO6/IOX2CK/SMB2DSDA";
+ bias-disable;
+ input-enable;
+ };
+ gpio6o_pins: gpio6o-pins {
+ pins = "GPIO6/IOX2CK/SMB2DSDA";
+ bias-disable;
+ output-high;
+ };
+ gpio6ol_pins: gpio6ol-pins {
+ pins = "GPIO6/IOX2CK/SMB2DSDA";
+ bias-disable;
+ output-low;
+ };
+ gpio7_pins: gpio7-pins {
+ pins = "GPIO7/IOX2D0/SMB2DSCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio7o_pins: gpio7o-pins {
+ pins = "GPIO7/IOX2D0/SMB2DSCL";
+ bias-disable;
+ output-high;
+ };
+ gpio7ol_pins: gpio7ol-pins {
+ pins = "GPIO7/IOX2D0/SMB2DSCL";
+ bias-disable;
+ output-low;
+ };
+ gpio8_pins: gpio8-pins {
+ pins = "GPIO8/LKGPO1";
+ bias-disable;
+ input-enable;
+ };
+ gpio8ol_pins: gpio8ol-pins {
+ pins = "GPIO8/LKGPO1";
+ bias-disable;
+ output-low;
+ };
+ gpio9_pins: gpio9-pins {
+ pins = "GPIO9/LKGPO2";
+ bias-disable;
+ input-enable;
+ };
+ gpio9o_pins: gpio9o-pins {
+ pins = "GPIO9/LKGPO2";
+ bias-disable;
+ output-high;
+ };
+ gpio9ol_pins: gpio9ol-pins {
+ pins = "GPIO9/LKGPO2";
+ bias-disable;
+ output-low;
+ };
+ gpio10_pins: gpio10-pins {
+ pins = "GPIO10/IOXHLD";
+ bias-disable;
+ input-enable;
+ };
+ gpio10ol_pins: gpio10ol-pins {
+ pins = "GPIO10/IOXHLD";
+ bias-disable;
+ output-low;
+ };
+ gpio11_pins: gpio11-pins {
+ pins = "GPIO11/IOXHCK";
+ bias-disable;
+ input-enable;
+ };
+ gpio11o_pins: gpio11o-pins {
+ pins = "GPIO11/IOXHCK";
+ bias-disable;
+ output-high;
+ };
+ gpio11ol_pins: gpio11ol-pins {
+ pins = "GPIO11/IOXHCK";
+ bias-disable;
+ output-low;
+ };
+ gpio12_pins: gpio12-pins {
+ pins = "GPIO12/GSPICK/SMB5BSCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio12o_pins: gpio12o-pins {
+ pins = "GPIO12/GSPICK/SMB5BSCL";
+ bias-disable;
+ output-high;
+ };
+ gpio12ol_pins: gpio12ol-pins {
+ pins = "GPIO12/GSPICK/SMB5BSCL";
+ bias-disable;
+ output-low;
+ };
+ gpio13_pins: gpio13-pins {
+ pins = "GPIO13/GSPIDO/SMB5BSDA";
+ bias-disable;
+ input-enable;
+ };
+ gpio13ol_pins: gpio13ol-pins {
+ pins = "GPIO13/GSPIDO/SMB5BSDA";
+ bias-disable;
+ output-low;
+ };
+ gpio14_pins: gpio14-pins {
+ pins = "GPIO14/GSPIDI/SMB5CSCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio14ol_pins: gpio14ol-pins {
+ pins = "GPIO14/GSPIDI/SMB5CSCL";
+ bias-disable;
+ output-low;
+ };
+ gpio15_pins: gpio15-pins {
+ pins = "GPIO15/GSPICS/SMB5CSDA";
+ bias-disable;
+ input-enable;
+ };
+ gpio15o_pins: gpio15o-pins {
+ pins = "GPIO15/GSPICS/SMB5CSDA";
+ bias-disable;
+ output-high;
+ };
+ gpio16_pins: gpio16-pins {
+ pins = "GPIO16/LKGPO0";
+ bias-disable;
+ input-enable;
+ };
+ gpio16o_pins: gpio16o-pins {
+ pins = "GPIO16/LKGPO0";
+ bias-disable;
+ output-high;
+ };
+ gpio16ol_pins: gpio16ol-pins {
+ pins = "GPIO16/LKGPO0";
+ bias-disable;
+ output-low;
+ };
+ gpio17_pins: gpio17-pins {
+ pins = "GPIO17/PSPI2DI/SMB4DEN";
+ bias-disable;
+ input-enable;
+ };
+ gpio17o_pins: gpio17o-pins {
+ pins = "GPIO17/PSPI2DI/SMB4DEN";
+ bias-disable;
+ output-high;
+ };
+ gpio17ol_pins: gpio17ol-pins {
+ pins = "GPIO17/PSPI2DI/SMB4DEN";
+ bias-disable;
+ output-low;
+ };
+ gpio18_pins: gpio18-pins {
+ pins = "GPIO18/PSPI2D0/SMB4BSDA";
+ bias-disable;
+ input-enable;
+ };
+ gpio18ol_pins: gpio18ol-pins {
+ pins = "GPIO18/PSPI2D0/SMB4BSDA";
+ bias-disable;
+ output-low;
+ };
+ gpio19_pins: gpio19-pins {
+ pins = "GPIO19/PSPI2CK/SMB4BSCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio19ol_pins: gpio19ol-pins {
+ pins = "GPIO19/PSPI2CK/SMB4BSCL";
+ bias-disable;
+ output-low;
+ };
+ gpio20_pins: gpio20-pins {
+ pins = "GPIO20/SMB4CSDA/SMB15SDA";
+ bias-disable;
+ input-enable;
+ };
+ gpio20o_pins: gpio20o-pins {
+ pins = "GPIO20/SMB4CSDA/SMB15SDA";
+ bias-disable;
+ output-high;
+ };
+ gpio20ol_pins: gpio20ol-pins {
+ pins = "GPIO20/SMB4CSDA/SMB15SDA";
+ bias-disable;
+ output-low;
+ };
+ gpio21_pins: gpio21-pins {
+ pins = "GPIO21/SMB4CSCL/SMB15SCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio21ol_pins: gpio21ol-pins {
+ pins = "GPIO21/SMB4CSCL/SMB15SCL";
+ bias-disable;
+ output-low;
+ };
+ gpio22_pins: gpio22-pins {
+ pins = "GPIO22/SMB4DSDA/SMB14SDA";
+ bias-disable;
+ input-enable;
+ };
+ gpio22ol_pins: gpio22ol-pins {
+ pins = "GPIO22/SMB4DSDA/SMB14SDA";
+ bias-disable;
+ output-low;
+ };
+ gpio23_pins: gpio23-pins {
+ pins = "GPIO23/SMB4DSCL/SMB14SCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio23ol_pins: gpio23ol-pins {
+ pins = "GPIO23/SMB4DSCL/SMB14SCL";
+ bias-disable;
+ output-low;
+ };
+ gpio24_pins: gpio24-pins {
+ pins = "GPIO24/IOXHDO";
+ bias-disable;
+ input-enable;
+ };
+ gpio24o_pins: gpio24o-pins {
+ pins = "GPIO24/IOXHDO";
+ bias-disable;
+ output-high;
+ };
+ gpio24ol_pins: gpio24ol-pins {
+ pins = "GPIO24/IOXHDO";
+ bias-disable;
+ output-low;
+ };
+ gpio25_pins: gpio25-pins {
+ pins = "GPIO25/IOXHDI";
+ bias-disable;
+ input-enable;
+ };
+ gpio25o_pins: gpio25o-pins {
+ pins = "GPIO25/IOXHDI";
+ bias-disable;
+ output-high;
+ };
+ gpio25ol_pins: gpio25ol-pins {
+ pins = "GPIO25/IOXHDI";
+ bias-disable;
+ output-low;
+ };
+ gpio26_pins: gpio26-pins {
+ pins = "GPIO26/SMB5SDA";
+ bias-disable;
+ input-enable;
+ };
+ gpio27_pins: gpio27-pins {
+ pins = "GPIO27/SMB5SCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio32_pins: gpio32-pins {
+ pins = "GPIO32/nSPI0CS1";
+ bias-disable;
+ input-enable;
+ };
+ gpio32o_pins: gpio32o-pins {
+ pins = "GPIO32/nSPI0CS1";
+ bias-disable;
+ output-high;
+ };
+ gpio32ol_pins: gpio32ol-pins {
+ pins = "GPIO32/nSPI0CS1";
+ bias-disable;
+ output-low;
+ };
+ gpio37_pins: gpio37-pins {
+ pins = "GPIO37/SMB3CSDA";
+ bias-disable;
+ input-enable;
+ };
+ gpio37o_pins: gpio37o-pins {
+ pins = "GPIO37/SMB3CSDA";
+ bias-disable;
+ output-high;
+ };
+ gpio37ol_pins: gpio37ol-pins {
+ pins = "GPIO37/SMB3CSDA";
+ bias-disable;
+ output-low;
+ };
+ gpio38_pins: gpio38-pins {
+ pins = "GPIO38/SMB3CSCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio38o_pins: gpio38o-pins {
+ pins = "GPIO38/SMB3CSCL";
+ bias-disable;
+ output-high;
+ };
+ gpio38ol_pins: gpio38ol-pins {
+ pins = "GPIO38/SMB3CSCL";
+ bias-disable;
+ output-low;
+ };
+ gpio39_pins: gpio39-pins {
+ pins = "GPIO39/SMB3BSDA";
+ bias-disable;
+ input-enable;
+ };
+ gpio39o_pins: gpio39o-pins {
+ pins = "GPIO39/SMB3BSDA";
+ bias-disable;
+ output-high;
+ };
+ gpio39ol_pins: gpio39ol-pins {
+ pins = "GPIO39/SMB3BSDA";
+ bias-disable;
+ output-low;
+ };
+ gpio40_pins: gpio40-pins {
+ pins = "GPIO40/SMB3BSCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio40o_pins: gpio40o-pins {
+ pins = "GPIO40/SMB3BSCL";
+ bias-disable;
+ output-high;
+ };
+ gpio40ol_pins: gpio40ol-pins {
+ pins = "GPIO40/SMB3BSCL";
+ bias-disable;
+ output-low;
+ };
+ gpio41_pins: gpio41-pins {
+ pins = "GPIO41/BSPRXD";
+ input-enable;
+ };
+ gpio42_pins: gpio42-pins {
+ pins = "GPO42/BSPTXD/STRAP11";
+ bias-disable;
+ input-enable;
+ };
+ gpio43_pins: gpio43-pins {
+ pins = "GPIO43/RXD1/JTMS2/BU1RXD";
+ bias-disable;
+ input-enable;
+ };
+ gpio44_pins: gpio44-pins {
+ pins = "GPIO44/nCTS1/JTDI2/BU1CTS";
+ bias-disable;
+ input-enable;
+ };
+ gpio45_pins: gpio45-pins {
+ pins = "GPIO45/nDCD1/JTDO2";
+ bias-disable;
+ input-enable;
+ };
+ gpio46_pins: gpio46-pins {
+ pins = "GPIO46/nDSR1/JTCK2";
+ bias-disable;
+ input-enable;
+ };
+ gpio47_pins: gpio47-pins {
+ pins = "GPIO47/nRI1/JCP_RDY2";
+ bias-disable;
+ input-enable;
+ };
+ gpio48_pins: gpio48-pins {
+ pins = "GPIO48/TXD2/BSPTXD";
+ bias-disable;
+ input-enable;
+ };
+ gpio49_pins: gpio49-pins {
+ pins = "GPIO49/RXD2/BSPRXD";
+ bias-disable;
+ input-enable;
+ };
+ gpio50_pins: gpio50-pins {
+ pins = "GPIO50/nCTS2";
+ bias-disable;
+ input-enable;
+ };
+ gpio50ol_pins: gpio50ol-pins {
+ pins = "GPIO50/nCTS2";
+ bias-disable;
+ output-low;
+ };
+ gpio51_pins: gpio51-pins {
+ pins = "GPO51/nRTS2/STRAP2";
+ bias-disable;
+ input-enable;
+ };
+ gpio51o_pins: gpio51o-pins {
+ pins = "GPO51/nRTS2/STRAP2";
+ bias-disable;
+ output-high;
+ };
+ gpio52_pins: gpio52-pins {
+ pins = "GPIO52/nDCD2";
+ bias-disable;
+ input-enable;
+ };
+ gpio52ol_pins: gpio52ol-pins {
+ pins = "GPIO52/nDCD2";
+ bias-disable;
+ output-low;
+ };
+ gpio53_pins: gpio53-pins {
+ pins = "GPO53/nDTR2_BOUT2/STRAP1";
+ bias-disable;
+ input-enable;
+ };
+ gpio53o_pins: gpio53o-pins {
+ pins = "GPO53/nDTR2_BOUT2/STRAP1";
+ bias-disable;
+ output-high;
+ };
+ gpio54_pins: gpio54-pins {
+ pins = "GPIO54/nDSR2";
+ bias-disable;
+ input-enable;
+ };
+ gpio54ol_pins: gpio54ol-pins {
+ pins = "GPIO54/nDSR2";
+ bias-disable;
+ output-low;
+ };
+ gpio55_pins: gpio55-pins {
+ pins = "GPIO55/nRI2";
+ bias-disable;
+ input-enable;
+ };
+ gpio55ol_pins: gpio55ol-pins {
+ pins = "GPIO55/nRI2";
+ bias-disable;
+ output-low;
+ };
+ gpio56_pins: gpio56-pins {
+ pins = "GPIO56/R1RXERR";
+ bias-disable;
+ input-enable;
+ };
+ gpio57_pins: gpio57-pins {
+ pins = "GPIO57/R1MDC";
+ bias-disable;
+ input-enable;
+ };
+ gpio57ol_pins: gpio57ol-pins {
+ pins = "GPIO57/R1MDC";
+ bias-disable;
+ output-low;
+ };
+ gpio58_pins: gpio58-pins {
+ pins = "GPIO58/R1MDIO";
+ bias-disable;
+ input-enable;
+ };
+ gpio58ol_pins: gpio58ol-pins {
+ pins = "GPIO58/R1MDIO";
+ bias-disable;
+ output-low;
+ };
+ gpio59_pins: gpio59-pins {
+ pins = "GPIO59/SMB3DSDA";
+ bias-disable;
+ input-enable;
+ };
+ gpio59o_pins: gpio59o-pins {
+ pins = "GPIO59/SMB3DSDA";
+ bias-disable;
+ output-high;
+ };
+ gpio59ol_pins: gpio59ol-pins {
+ pins = "GPIO59/SMB3DSDA";
+ bias-disable;
+ output-low;
+ };
+ gpio60_pins: gpio60-pins {
+ pins = "GPIO60/SMB3DSCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio60o_pins: gpio60o-pins {
+ pins = "GPIO60/SMB3DSCL";
+ bias-disable;
+ output-high;
+ };
+ gpio60ol_pins: gpio60ol-pins {
+ pins = "GPIO60/SMB3DSCL";
+ bias-disable;
+ output-low;
+ };
+ gpio61_pins: gpio61-pins {
+ pins = "GPO61/nDTR1_BOUT1/STRAP6";
+ bias-disable;
+ input-enable;
+ };
+ gpio61o_pins: gpio61o-pins {
+ pins = "GPO61/nDTR1_BOUT1/STRAP6";
+ bias-disable;
+ output-high;
+ };
+ gpio62_pins: gpio62-pins {
+ pins = "GPO62/nRTST1/STRAP5";
+ bias-disable;
+ input-enable;
+ };
+ gpio62o_pins: gpio62o-pins {
+ pins = "GPO62/nRTST1/STRAP5";
+ bias-disable;
+ output-high;
+ };
+ gpio63_pins: gpio63-pins {
+ pins = "GPO63/TXD1/STRAP4";
+ bias-disable;
+ input-enable;
+ };
+ gpio63o_pins: gpio63o-pins {
+ pins = "GPO63/TXD1/STRAP4";
+ bias-disable;
+ output-high;
+ };
+ gpio64_pins: gpio64-pins {
+ pins = "GPIO64/FANIN0";
+ bias-disable;
+ input-enable;
+ };
+ gpio64o_pins: gpio64o-pins {
+ pins = "GPIO64/FANIN0";
+ bias-disable;
+ output-high;
+ };
+ gpio65_pins: gpio65-pins {
+ pins = "GPIO65/FANIN1";
+ bias-disable;
+ input-enable;
+ };
+ gpio66_pins: gpio66-pins {
+ pins = "GPIO66/FANIN2";
+ bias-disable;
+ input-enable;
+ };
+ gpio67_pins: gpio67-pins {
+ pins = "GPIO67/FANIN3";
+ bias-disable;
+ input-enable;
+ };
+ gpio68_pins: gpio68-pins {
+ pins = "GPIO68/FANIN4";
+ bias-disable;
+ input-enable;
+ };
+ gpio69_pins: gpio69-pins {
+ pins = "GPIO69/FANIN5";
+ bias-disable;
+ input-enable;
+ };
+ gpio69ol_pins: gpio69ol-pins {
+ pins = "GPIO69/FANIN5";
+ bias-disable;
+ output-low;
+ };
+ gpio70_pins: gpio70-pins {
+ pins = "GPIO70/FANIN6";
+ bias-disable;
+ input-enable;
+ };
+ gpio71_pins: gpio71-pins {
+ pins = "GPIO71/FANIN7";
+ bias-disable;
+ input-enable;
+ };
+ gpio72_pins: gpio72-pins {
+ pins = "GPIO72/FANIN8";
+ bias-disable;
+ input-enable;
+ };
+ gpio72ol_pins: gpio72ol-pins {
+ pins = "GPIO72/FANIN8";
+ bias-disable;
+ output-low;
+ };
+ gpio73_pins: gpio73-pins {
+ pins = "GPIO73/FANIN9";
+ bias-disable;
+ input-enable;
+ };
+ gpio73ol_pins: gpio73ol-pins {
+ pins = "GPIO73/FANIN9";
+ bias-disable;
+ output-low;
+ };
+ gpio74_pins: gpio74-pins {
+ pins = "GPIO74/FANIN10";
+ bias-disable;
+ input-enable;
+ };
+ gpio74ol_pins: gpio74ol-pins {
+ pins = "GPIO74/FANIN10";
+ bias-disable;
+ output-low;
+ };
+ gpio75_pins: gpio75-pins {
+ pins = "GPIO75/FANIN11";
+ bias-disable;
+ input-enable;
+ };
+ gpio75ol_pins: gpio75ol-pins {
+ pins = "GPIO75/FANIN11";
+ bias-disable;
+ output-low;
+ };
+ gpio76_pins: gpio76-pins {
+ pins = "GPIO76/FANIN12";
+ bias-disable;
+ input-enable;
+ };
+ gpio76ol_pins: gpio76ol-pins {
+ pins = "GPIO76/FANIN12";
+ bias-disable;
+ output-low;
+ };
+ gpio77_pins: gpio77-pins {
+ pins = "GPIO77/FANIN13";
+ bias-disable;
+ input-enable;
+ };
+ gpio77ol_pins: gpio77ol-pins {
+ pins = "GPIO77/FANIN13";
+ bias-disable;
+ output-low;
+ };
+ gpio78_pins: gpio78-pins {
+ pins = "GPIO78/FANIN14";
+ bias-disable;
+ input-enable;
+ };
+ gpio78ol_pins: gpio78ol-pins {
+ pins = "GPIO78/FANIN14";
+ bias-disable;
+ output-low;
+ };
+ gpio79_pins: gpio79-pins {
+ pins = "GPIO79/FANIN15";
+ bias-disable;
+ input-enable;
+ };
+ gpio79ol_pins: gpio79ol-pins {
+ pins = "GPIO79/FANIN15";
+ bias-disable;
+ output-low;
+ };
+ gpio80_pins: gpio80-pins {
+ pins = "GPIO80/PWM0";
+ bias-disable;
+ input-enable;
+ };
+ gpio81_pins: gpio81-pins {
+ pins = "GPIO81/PWM1";
+ bias-disable;
+ input-enable;
+ };
+ gpio82_pins: gpio82-pins {
+ pins = "GPIO82/PWM2";
+ bias-disable;
+ input-enable;
+ };
+ gpio83_pins: gpio83-pins {
+ pins = "GPIO83/PWM3";
+ bias-disable;
+ input-enable;
+ };
+ gpio84_pins: gpio84-pins {
+ pins = "GPIO84/R2TXD0";
+ bias-disable;
+ input-enable;
+ };
+ gpio84o_pins: gpio84ol-pins {
+ pins = "GPIO84/R2TXD0";
+ bias-disable;
+ output-high;
+ };
+ gpio85_pins: gpio85-pins {
+ pins = "GPIO85/R2TXD1";
+ bias-disable;
+ input-enable;
+ };
+ gpio85o_pins: gpio85o-pins {
+ pins = "GPIO85/R2TXD1";
+ bias-disable;
+ output-high;
+ };
+ gpio86_pins: gpio86-pins {
+ pins = "GPIO86/R2TXEN";
+ bias-disable;
+ input-enable;
+ };
+ gpio86o_pins: gpio86o-pins {
+ pins = "GPIO86/R2TXEN";
+ bias-disable;
+ output-high;
+ };
+ gpio87_pins: gpio87-pins {
+ pins = "GPIO87/R2RXD0";
+ bias-disable;
+ input-enable;
+ };
+ gpio87o_pins: gpio87o-pins {
+ pins = "GPIO87/R2RXD0";
+ bias-disable;
+ output-high;
+ };
+ gpio88_pins: gpio88-pins {
+ pins = "GPIO88/R2RXD1";
+ bias-disable;
+ input-enable;
+ };
+ gpio88ol_pins: gpio88ol-pins {
+ pins = "GPIO88/R2RXD1";
+ bias-disable;
+ output-low;
+ };
+ gpio89_pins: gpio89-pins {
+ pins = "GPIO89/R2CRSDV";
+ bias-disable;
+ input-enable;
+ };
+ gpio89ol_pins: gpio89ol-pins {
+ pins = "GPIO89/R2CRSDV";
+ bias-disable;
+ output-low;
+ };
+ gpio90_pins: gpio90-pins {
+ pins = "GPIO90/R2RXERR";
+ bias-disable;
+ input-enable;
+ };
+ gpio90o_pins: gpio90o0-pins {
+ pins = "GPIO90/R2RXERR";
+ bias-disable;
+ output-high;
+ };
+ gpio90ol_pins: gpio90ol-pins {
+ pins = "GPIO90/R2RXERR";
+ bias-disable;
+ output-low;
+ };
+ gpio91_pins: gpio91-pins {
+ pins = "GPIO91/R2MDC";
+ bias-disable;
+ input-enable;
+ };
+ gpio91o_pins: gpio91o-pins {
+ pins = "GPIO91/R2MDC";
+ bias-disable;
+ output-high;
+ };
+ gpio91ol_pins: gpio91ol-pins {
+ pins = "GPIO91/R2MDC";
+ bias-disable;
+ output-low;
+ };
+ gpio92_pins: gpio92-pins {
+ pins = "GPIO92/R2MDIO";
+ bias-disable;
+ input-enable;
+ };
+ gpio92o_pins: gpio92o-pins {
+ pins = "GPIO92/R2MDIO";
+ bias-disable;
+ output-high;
+ };
+ gpio92ol_pins: gpio92ol-pins {
+ pins = "GPIO92/R2MDIO";
+ bias-disable;
+ output-low;
+ };
+ gpio93_pins: gpio93-pins {
+ pins = "GPIO93/GA20/SMB5DSCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio93ol_pins: gpio93ol-pins {
+ pins = "GPIO93/GA20/SMB5DSCL";
+ bias-disable;
+ output-low;
+ };
+ gpio94_pins: gpio94-pins {
+ pins = "GPIO94/nKBRST/SMB5DSDA";
+ bias-disable;
+ input-enable;
+ };
+ gpio94o_pins: gpio94o-pins {
+ pins = "GPIO94/nKBRST/SMB5DSDA";
+ bias-disable;
+ output-high;
+ };
+ gpio95_pins: gpio95-pins {
+ pins = "GPIO95/nLRESET/nESPIRST";
+ bias-disable;
+ input-enable;
+ };
+ gpio96_pins: gpio96-pins {
+ pins = "GPIO96/RG1TXD0";
+ bias-disable;
+ input-enable;
+ };
+ gpio96ol_pins: gpio96ol-pins {
+ pins = "GPIO96/RG1TXD0";
+ bias-disable;
+ output-low;
+ };
+ gpio97_pins: gpio97-pins {
+ pins = "GPIO97/RG1TXD1";
+ bias-disable;
+ input-enable;
+ };
+ gpio97ol_pins: gpio97ol-pins {
+ pins = "GPIO97/RG1TXD1";
+ bias-disable;
+ output-low;
+ };
+ gpio98_pins: gpio98-pins {
+ pins = "GPIO98/RG1TXD2";
+ bias-disable;
+ input-enable;
+ };
+ gpio98ol_pins: gpio98ol-pins {
+ pins = "GPIO98/RG1TXD2";
+ bias-disable;
+ output-low;
+ };
+ gpio99_pins: gpio99-pins {
+ pins = "GPIO99/RG1TXD3";
+ bias-disable;
+ input-enable;
+ };
+ gpio99ol_pins: gpio99ol-pins {
+ pins = "GPIO99/RG1TXD3";
+ bias-disable;
+ output-low;
+ };
+ gpio100_pins: gpio100-pins {
+ pins = "GPIO100/RG1TXC";
+ bias-disable;
+ input-enable;
+ };
+ gpio100ol_pins: gpio100ol-pins {
+ pins = "GPIO100/RG1TXC";
+ bias-disable;
+ output-low;
+ };
+ gpio101_pins: gpio101-pins {
+ pins = "GPIO101/RG1TXCTL";
+ bias-disable;
+ input-enable;
+ };
+ gpio101ol_pins: gpio101ol-pins {
+ pins = "GPIO101/RG1TXCTL";
+ bias-disable;
+ output-low;
+ };
+ gpio102_pins: gpio102-pins {
+ pins = "GPIO102/RG1RXD0";
+ bias-disable;
+ input-enable;
+ };
+ gpio102ol_pins: gpio102ol-pins {
+ pins = "GPIO102/RG1RXD0";
+ bias-disable;
+ output-low;
+ };
+ gpio103_pins: gpio103-pins {
+ pins = "GPIO103/RG1RXD1";
+ bias-disable;
+ input-enable;
+ };
+ gpio103ol_pins: gpio103ol-pins {
+ pins = "GPIO103/RG1RXD1";
+ bias-disable;
+ output-low;
+ };
+ gpio104_pins: gpio104-pins {
+ pins = "GPIO104/RG1RXD2";
+ bias-disable;
+ input-enable;
+ };
+ gpio104ol_pins: gpio104ol-pins {
+ pins = "GPIO104/RG1RXD2";
+ bias-disable;
+ output-low;
+ };
+ gpio105_pins: gpio105-pins {
+ pins = "GPIO105/RG1RXD3";
+ bias-disable;
+ input-enable;
+ };
+ gpio105ol_pins: gpio105ol-pins {
+ pins = "GPIO105/RG1RXD3";
+ bias-disable;
+ output-low;
+ };
+ gpio106_pins: gpio106-pins {
+ pins = "GPIO106/RG1RXC";
+ bias-disable;
+ input-enable;
+ };
+ gpio106ol_pins: gpio106ol-pins {
+ pins = "GPIO106/RG1RXC";
+ bias-disable;
+ output-low;
+ };
+ gpio107_pins: gpio107-pins {
+ pins = "GPIO107/RG1RXCTL";
+ bias-disable;
+ input-enable;
+ };
+ gpio107ol_pins: gpio107ol-pins {
+ pins = "GPIO107/RG1RXCTL";
+ bias-disable;
+ output-low;
+ };
+ gpio108_pins: gpio108-pins {
+ pins = "GPIO108/RG1MDC";
+ bias-disable;
+ input-enable;
+ };
+ gpio108ol_pins: gpio108ol-pins {
+ pins = "GPIO108/RG1MDC";
+ bias-disable;
+ output-low;
+ };
+ gpio109_pins: gpio109-pins {
+ pins = "GPIO109/RG1MDIO";
+ bias-disable;
+ input-enable;
+ };
+ gpio109ol_pins: gpio109ol-pins {
+ pins = "GPIO109/RG1MDIO";
+ bias-disable;
+ output-low;
+ };
+ gpio110_pins: gpio110-pins {
+ pins = "GPIO110/RG2TXD0/DDRV0";
+ bias-disable;
+ input-enable;
+ };
+ gpio110ol_pins: gpio110ol-pins {
+ pins = "GPIO110/RG2TXD0/DDRV0";
+ bias-disable;
+ output-low;
+ };
+ gpio111_pins: gpio111-pins {
+ pins = "GPIO111/RG2TXD1/DDRV1";
+ bias-disable;
+ input-enable;
+ };
+ gpio111ol_pins: gpio111ol-pins {
+ pins = "GPIO111/RG2TXD1/DDRV1";
+ bias-disable;
+ output-low;
+ };
+ gpio112_pins: gpio112-pins {
+ pins = "GPIO112/RG2TXD2/DDRV2";
+ bias-disable;
+ input-enable;
+ };
+ gpio112ol_pins: gpio112ol-pins {
+ pins = "GPIO112/RG2TXD2/DDRV2";
+ bias-disable;
+ output-low;
+ };
+ gpio113_pins: gpio113-pins {
+ pins = "GPIO113/RG2TXD3/DDRV3";
+ bias-disable;
+ input-enable;
+ };
+ gpio113ol_pins: gpio113ol-pins {
+ pins = "GPIO113/RG2TXD3/DDRV3";
+ bias-disable;
+ output-low;
+ };
+ gpio118_pins: gpio118-pins {
+ pins = "GPIO118/SMB2SCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio119_pins: gpio119-pins {
+ pins = "GPIO119/SMB2SDA";
+ bias-disable;
+ input-enable;
+ };
+ gpio120_pins: gpio120-pins {
+ pins = "GPIO120/SMB2CSDA";
+ bias-disable;
+ input-enable;
+ };
+ gpio121_pins: gpio121-pins {
+ pins = "GPIO121/SMB2CSCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio122_pins: gpio122-pins {
+ pins = "GPIO122/SMB2BSDA";
+ bias-disable;
+ input-enable;
+ };
+ gpio123_pins: gpio123-pins {
+ pins = "GPIO123/SMB2BSCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio123_pins: gpio123-pins {
+ pins = "GPIO123/SMB2BSCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio124_pins: gpio124-pins {
+ pins = "GPIO124/SMB1CSDA";
+ bias-disable;
+ input-enable;
+ };
+ gpio125_pins: gpio125-pins {
+ pins = "GPIO125/SMB1CSCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio126_pins: gpio126-pins {
+ pins = "GPIO126/SMB1BSDA";
+ bias-disable;
+ input-enable;
+ };
+ gpio127_pins: gpio127-pins {
+ pins = "GPIO127/SMB1BSCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio128o_pins: gpio128o-pins {
+ pins = "GPIO128/SMB8SCL";
+ bias-disable;
+ output-high;
+ };
+ gpio130_pins: gpio130-pins {
+ pins = "GPIO130/SMB9SCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio131_pins: gpio131-pins {
+ pins = "GPIO131/SMB9SDA";
+ bias-disable;
+ input-enable;
+ };
+ gpio132_pins: gpio132-pins {
+ pins = "GPIO132/SMB10SCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio133_pins: gpio133-pins {
+ pins = "GPIO133/SMB10SDA";
+ bias-disable;
+ input-enable;
+ };
+ gpio134_pins: gpio134-pins {
+ pins = "GPIO134/SMB11SCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio135_pins: gpio135-pins {
+ pins = "GPIO135/SMB11SDA";
+ bias-disable;
+ input-enable;
+ };
+ gpio136_pins: gpio136-pins {
+ pins = "GPIO136/SD1DT0";
+ bias-disable;
+ input-enable;
+ };
+ gpio136o_pins: gpio136o-pins {
+ pins = "GPIO136/SD1DT0";
+ bias-disable;
+ output-high;
+ };
+ gpio137_pins: gpio137-pins {
+ pins = "GPIO137/SD1DT1";
+ bias-disable;
+ input-enable;
+ };
+ gpio137o_pins: gpio137o-pins {
+ pins = "GPIO137/SD1DT1";
+ bias-disable;
+ output-high;
+ };
+ gpio138_pins: gpio138-pins {
+ pins = "GPIO138/SD1DT2";
+ bias-disable;
+ input-enable;
+ };
+ gpio138o_pins: gpio138o-pins {
+ pins = "GPIO138/SD1DT2";
+ bias-disable;
+ output-high;
+ };
+ gpio139_pins: gpio139-pins {
+ pins = "GPIO139/SD1DT3";
+ bias-disable;
+ input-enable;
+ };
+ gpio139o_pins: gpio139o-pins {
+ pins = "GPIO139/SD1DT3";
+ bias-disable;
+ output-high;
+ };
+ gpio140_pins: gpio140-pins {
+ pins = "GPIO140/SD1CLK";
+ bias-disable;
+ input-enable;
+ };
+ gpio140o_pins: gpio140o-pins {
+ pins = "GPIO140/SD1CLK";
+ bias-disable;
+ output-high;
+ };
+ gpio141_pins: gpio141-pins {
+ pins = "GPIO141/SD1WP";
+ bias-disable;
+ input-enable;
+ };
+ gpio141o_pins: gpio141o-pins {
+ pins = "GPIO141/SD1WP";
+ bias-disable;
+ output-high;
+ };
+ gpio142_pins: gpio142-pins {
+ pins = "GPIO142/SD1CMD";
+ bias-disable;
+ input-enable;
+ };
+ gpio142o_pins: gpio142o-pins {
+ pins = "GPIO142/SD1CMD";
+ bias-disable;
+ output-high;
+ };
+ gpio143_pins: gpio143-pins {
+ pins = "GPIO143/SD1CD/SD1PWR";
+ bias-disable;
+ input-enable;
+ };
+ gpio143o_pins: gpio143o-pins {
+ pins = "GPIO143/SD1CD/SD1PWR";
+ bias-disable;
+ output-high;
+ };
+ gpio143ol_pins: gpio143ol-pins {
+ pins = "GPIO143/SD1CD/SD1PWR";
+ bias-disable;
+ output-low;
+ };
+ gpio144_pins: gpio144-pins {
+ pins = "GPIO144/PWM4";
+ bias-disable;
+ input-enable;
+ };
+ gpio145_pins: gpio145-pins {
+ pins = "GPIO145/PWM5";
+ bias-disable;
+ input-enable;
+ };
+ gpio146_pins: gpio146-pins {
+ pins = "GPIO146/PWM6";
+ bias-disable;
+ input-enable;
+ };
+ gpio147_pins: gpio147-pins {
+ pins = "GPIO147/PWM7";
+ bias-disable;
+ input-enable;
+ };
+ gpio148_pins: gpio148-pins {
+ pins = "GPIO148/MMCDT4";
+ bias-disable;
+ input-enable;
+ };
+ gpio148o_pins: gpio148o-pins {
+ pins = "GPIO148/MMCDT4";
+ bias-disable;
+ output-high;
+ };
+ gpio148ol_pins: gpio148ol_pins {
+ pins = "GPIO148/MMCDT4";
+ bias-disable;
+ output-low;
+ };
+ gpio149_pins: gpio149-pins {
+ pins = "GPIO149/MMCDT5";
+ bias-disable;
+ input-enable;
+ };
+ gpio149o_pins: gpio149o-pins {
+ pins = "GPIO149/MMCDT5";
+ bias-disable;
+ output-high;
+ };
+ gpio149ol_pins: gpio149ol-pins {
+ pins = "GPIO149/MMCDT5";
+ bias-disable;
+ output-low;
+ };
+ gpio150_pins: gpio150-pins {
+ pins = "GPIO150/MMCDT6";
+ bias-disable;
+ input-enable;
+ };
+ gpio150o_pins: gpio150o-pins {
+ pins = "GPIO150/MMCDT6";
+ bias-disable;
+ output-high;
+ };
+ gpio150ol_pins: gpio150ol-pins {
+ pins = "GPIO150/MMCDT6";
+ bias-disable;
+ output-low;
+ };
+ gpio151_pins: gpio151-pins {
+ pins = "GPIO151/MMCDT7";
+ bias-disable;
+ input-enable;
+ };
+ gpio151o_pins: gpio151o-pins {
+ pins = "GPIO151/MMCDT7";
+ bias-disable;
+ output-high;
+ };
+ gpio151ol_pins: gpio151ol-pins {
+ pins = "GPIO151/MMCDT7";
+ bias-disable;
+ output-low;
+ };
+ gpio152_pins: gpio152-pins {
+ pins = "GPIO152/MMCCLK";
+ bias-disable;
+ input-enable;
+ };
+ gpio152o_pins: gpio152o-pins {
+ pins = "GPIO152/MMCCLK";
+ bias-disable;
+ output-high;
+ };
+ gpio152ol_pins: gpio152ol-pins {
+ pins = "GPIO152/MMCCLK";
+ bias-disable;
+ output-low;
+ };
+ gpio153_pins: gpio153-pins {
+ pins = "GPIO153/MMCWP";
+ bias-disable;
+ input-enable;
+ };
+ gpio153ol_pins: gpio153ol-pins {
+ pins = "GPIO153/MMCWP";
+ bias-disable;
+ output-low;
+ };
+ gpio154_pins: gpio154-pins {
+ pins = "GPIO154/MMCCMD";
+ bias-disable;
+ input-enable;
+ };
+ gpio154ol_pins: gpio154ol-pins {
+ pins = "GPIO154/MMCCMD";
+ bias-disable;
+ output-low;
+ };
+ gpio155_pins: gpio155-pins {
+ pins = "GPIO155/nMMCCD/nMMCRST";
+ bias-disable;
+ input-enable;
+ };
+ gpio155ol_pins: gpio155ol-pins {
+ pins = "GPIO155/nMMCCD/nMMCRST";
+ bias-disable;
+ output-low;
+ };
+ gpio156_pins: gpio156-pins {
+ pins = "GPIO156/MMCDT0";
+ bias-disable;
+ input-enable;
+ };
+ gpio156ol_pins: gpio156ol-pins {
+ pins = "GPIO156/MMCDT0";
+ bias-disable;
+ output-low;
+ };
+ gpio157_pins: gpio157-pins {
+ pins = "GPIO157/MMCDT1";
+ bias-disable;
+ input-enable;
+ };
+ gpio157o_pins: gpio157o-pins {
+ pins = "GPIO157/MMCDT1";
+ bias-disable;
+ output-high;
+ };
+ gpio157ol_pins: gpio157ol-pins {
+ pins = "GPIO157/MMCDT1";
+ bias-disable;
+ output-low;
+ };
+ gpio158_pins: gpio158-pins {
+ pins = "GPIO158/MMCDT2";
+ bias-disable;
+ input-enable;
+ };
+ gpio158o_pins: gpio158o-pins {
+ pins = "GPIO158/MMCDT2";
+ bias-disable;
+ output-high;
+ };
+ gpio158ol_pins: gpio158ol-pins {
+ pins = "GPIO158/MMCDT2";
+ bias-disable;
+ output-low;
+ };
+ gpio159_pins: gpio159-pins {
+ pins = "GPIO159/MMCDT3";
+ bias-disable;
+ input-enable;
+ };
+ gpio159o_pins: gpio159o-pins {
+ pins = "GPIO159/MMCDT3";
+ bias-disable;
+ output-high;
+ };
+ gpio159ol_pins: gpio159ol-pins {
+ pins = "GPIO159/MMCDT3";
+ bias-disable;
+ output-low;
+ };
+ gpio160_pins: gpio160-pins {
+ pins = "GPIO160/CLKOUT/RNGOSCOUT";
+ bias-disable;
+ input-enable;
+ };
+ gpio160o_pins: gpio160o-pins {
+ pins = "GPIO160/CLKOUT/RNGOSCOUT";
+ bias-disable;
+ output-high;
+ };
+ gpio160ol_pins: gpio160ol-pins {
+ pins = "GPIO160/CLKOUT/RNGOSCOUT";
+ bias-disable;
+ output-low;
+ };
+ gpio161_pins: gpio161-pins {
+ pins = "GPIO161/nLFRAME/nESPICS";
+ bias-disable;
+ input-enable;
+ };
+ gpio162_pins: gpio162-pins {
+ pins = "GPIO162/SERIRQ";
+ bias-disable;
+ input-enable;
+ };
+ gpio163_pins: gpio163-pins {
+ pins = "GPIO163/LCLK/ESPICLK";
+ bias-disable;
+ input-enable;
+ };
+ gpio164_pins: gpio164-pins {
+ pins = "GPIO164/LAD0/ESPI_IO0";
+ bias-disable;
+ input-enable;
+ };
+ gpio165_pins: gpio165-pins {
+ pins = "GPIO165/LAD1/ESPI_IO1";
+ bias-disable;
+ input-enable;
+ };
+ gpio166_pins: gpio166-pins {
+ pins = "GPIO166/LAD2/ESPI_IO2";
+ bias-disable;
+ input-enable;
+ };
+ gpio167_pins: gpio167-pins {
+ pins = "GPIO167/LAD3/ESPI_IO3";
+ bias-disable;
+ input-enable;
+ };
+ gpio168_pins: gpio168-pins {
+ pins = "GPIO168/nCLKRUN/nESPIALERT";
+ bias-disable;
+ input-enable;
+ };
+ gpio168ol_pins: gpio168ol-pins {
+ pins = "GPIO168/nCLKRUN/nESPIALERT";
+ bias-disable;
+ output-low;
+ };
+ gpio169_pins: gpio169-pins {
+ pins = "GPIO169/nSCIPME";
+ bias-disable;
+ input-enable;
+ };
+ gpio169o_pins: gpio169o-pins {
+ pins = "GPIO169/nSCIPME";
+ bias-disable;
+ output-high;
+ };
+ gpio169ol_pins: gpio169ol-pins {
+ pins = "GPIO169/nSCIPME";
+ bias-disable;
+ output-low;
+ };
+ gpio170_pins: gpio170-pins {
+ pins = "GPIO170/nSMI";
+ bias-disable;
+ input-enable;
+ };
+ gpio170ol_pins: gpio170ol-pins {
+ pins = "GPIO170/nSMI";
+ bias-disable;
+ output-low;
+ };
+ gpio173o_pins: gpio173o-pins {
+ pins = "GPIO173/SMB7SCL";
+ bias-disable;
+ output-high;
+ };
+ gpio173ol_pins: gpio173ol-pins {
+ pins = "GPIO173/SMB7SCL";
+ bias-disable;
+ output-low;
+ };
+ gpio174_pins: gpio174-pins {
+ pins = "GPIO174/SMB7SDA";
+ bias-disable;
+ input-enable;
+ };
+ gpio175_pins: gpio175-pins {
+ pins = "GPIO175/PSPI1CK/FANIN19";
+ bias-disable;
+ input-enable;
+ };
+ gpio175o_pins: gpio175o-pins {
+ pins = "GPIO175/PSPI1CK/FANIN19";
+ bias-disable;
+ output-high;
+ };
+ gpio175ol_pins: gpio175ol-pins {
+ pins = "GPIO175/PSPI1CK/FANIN19";
+ bias-disable;
+ output-low;
+ };
+ gpio176_pins: gpio176-pins {
+ pins = "GPIO176/PSPI1DO/FANIN18";
+ bias-disable;
+ input-enable;
+ };
+ gpio176o_pins: gpio176o-pins {
+ pins = "GPIO176/PSPI1DO/FANIN18";
+ bias-disable;
+ output-high;
+ };
+ gpio176ol_pins: gpio176ol-pins {
+ pins = "GPIO176/PSPI1DO/FANIN18";
+ bias-disable;
+ output-low;
+ };
+ gpio177_pins: gpio177-pins {
+ pins = "GPIO177/PSPI1DI/FANIN17";
+ bias-disable;
+ input-enable;
+ };
+ gpio177o_pins: gpio177o-pins {
+ pins = "GPIO177/PSPI1DI/FANIN17";
+ bias-disable;
+ output-high;
+ };
+ gpio177ol_pins: gpio177ol-pins {
+ pins = "GPIO177/PSPI1DI/FANIN17";
+ bias-disable;
+ output-low;
+ };
+ gpio187_pins: gpio187-pins {
+ pins = "GPIO187/nSPI3CS1";
+ bias-disable;
+ input-enable;
+ };
+ gpio187o_pins: gpio187o-pins {
+ pins = "GPIO187/nSPI3CS1";
+ bias-disable;
+ output-high;
+ };
+ gpio187ol_pins: gpio187ol-pins {
+ pins = "GPIO187/nSPI3CS1";
+ bias-disable;
+ output-low;
+ };
+ gpio188_pins: gpio188-pins {
+ pins = "GPIO188/SPI3D2/nSPI3CS2";
+ bias-disable;
+ input-enable;
+ };
+ gpio188o_pins: gpio188o-pins {
+ pins = "GPIO188/SPI3D2/nSPI3CS2";
+ bias-disable;
+ output-high;
+ };
+ gpio189o_pins: gpio189o-pins {
+ pins = "GPIO189/SPI3D3/nSPI3CS3";
+ bias-disable;
+ output-high;
+ };
+ gpio190_pins: gpio190-pins {
+ pins = "GPIO190/nPRD_SMI";
+ bias-disable;
+ input-enable;
+ };
+ gpio190o_pins: gpio190o-pins {
+ pins = "GPIO190/nPRD_SMI";
+ bias-disable;
+ output-high;
+ };
+ gpio190ol_pins: gpio190ol-pins {
+ pins = "GPIO190/nPRD_SMI";
+ bias-disable;
+ output-low;
+ };
+ gpio191o_pins: gpio191o-pins {
+ pins = "GPIO191";
+ bias-disable;
+ output-high;
+ };
+ gpio191ol_pins: gpio191ol-pins {
+ pins = "GPIO191";
+ bias-disable;
+ output-low;
+ };
+ gpio192_pins: gpio192-pins {
+ pins = "GPIO192";
+ bias-disable;
+ input-enable;
+ };
+ gpio192o_pins: gpio192o-pins {
+ pins = "GPIO192";
+ bias-disable;
+ output-high;
+ };
+ gpio192ol_pins: gpio192ol-pins {
+ pins = "GPIO192";
+ bias-disable;
+ output-low;
+ };
+ gpio194_pins: gpio194-pins {
+ pins = "GPIO194/SMB0BSCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio194o_pins: gpio194o-pins {
+ pins = "GPIO194/SMB0BSCL";
+ bias-disable;
+ output-high;
+ };
+ gpio195_pins: gpio195-pins {
+ pins = "GPIO195/SMB0BSDA";
+ bias-disable;
+ input-enable;
+ };
+ gpio196_pins: gpio196-pins {
+ pins = "GPIO196/SMB0CSCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio197_pins: gpio197-pins {
+ pins = "GPIO197/SMB0DEN";
+ bias-disable;
+ input-enable;
+ };
+ gpio197o_pins: gpio197o-pins {
+ pins = "GPIO197/SMB0DEN";
+ bias-disable;
+ output-high;
+ };
+ gpio197ol_pins: gpio197ol-pins {
+ pins = "GPIO197/SMB0DEN";
+ bias-disable;
+ output-low;
+ };
+ gpio198o_pins: gpio198o-pins {
+ pins = "GPIO198/SMB0DSDA";
+ bias-disable;
+ output-high;
+ };
+ gpio198ol_pins: gpio198ol-pins {
+ pins = "GPIO198/SMB0DSDA";
+ bias-disable;
+ output-low;
+ };
+ gpio199_pins: gpio199-pins {
+ pins = "GPIO199/SMB0DSCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio200_pins: gpio200-pins {
+ pins = "GPIO200/R2CK";
+ input-enable;
+ bias-disable;
+ };
+ gpio200ol_pins: gpio200ol-pins {
+ pins = "GPIO200/R2CK";
+ bias-disable;
+ output-low;
+ };
+ gpio201ol_pins: gpio201ol-pins {
+ pins = "GPIO200/R2CK";
+ bias-disable;
+ output-low;
+ };
+ gpio202_pins: gpio202-pins {
+ pins = "GPIO202/SMB0CSDA";
+ bias-disable;
+ input-enable;
+ };
+ gpio203_pins: gpio203-pins {
+ pins = "GPIO203/FANIN16";
+ bias-disable;
+ input-enable;
+ };
+ gpio203o_pins: gpio203o-pins {
+ pins = "GPIO203/FANIN16";
+ bias-disable;
+ output-high;
+ };
+ gpio203ol_pins: gpio203ol-pins {
+ pins = "GPIO203/FANIN16";
+ bias-disable;
+ output-low;
+ };
+ gpio204_pins: gpio204-pins {
+ pins = "GPIO204/DDC2SCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio204o_pins: gpio204o-pins {
+ pins = "GPIO204/DDC2SCL";
+ bias-disable;
+ output-high;
+ };
+ gpio204ol_pins: gpio204ol-pins {
+ pins = "GPIO204/DDC2SCL";
+ bias-disable;
+ output-low;
+ };
+ gpio205_pins: gpio205-pins {
+ pins = "GPIO205/DDC2SDA";
+ bias-disable;
+ input-enable;
+ };
+ gpio205o_pins: gpio205o-pins {
+ pins = "GPIO205/DDC2SDA";
+ bias-disable;
+ output-high;
+ };
+ gpio205ol_pins: gpio205ol-pins {
+ pins = "GPIO205/DDC2SDA";
+ bias-disable;
+ output-low;
+ };
+ gpio206_pins: gpio206-pins {
+ pins = "GPIO206/HSYNC2";
+ bias-disable;
+ input-enable;
+ };
+ gpio206o_pins: gpio206o-pins {
+ pins = "GPIO206/HSYNC2";
+ bias-disable;
+ output-high;
+ };
+ gpio206ol_pins: gpio206ol-pins {
+ pins = "GPIO206/HSYNC2";
+ bias-disable;
+ output-low;
+ };
+ gpio207_pins: gpio207-pins {
+ pins = "GPIO207/VSYNC2";
+ bias-disable;
+ input-enable;
+ };
+ gpio207o_pins: gpio207o-pins {
+ pins = "GPIO207/VSYNC2";
+ bias-disable;
+ output-high;
+ };
+ gpio207ol_pins: gpio207ol-pins {
+ pins = "GPIO207/VSYNC2";
+ bias-disable;
+ output-low;
+ };
+ gpio208_pins: gpio208-pins {
+ pins = "GPIO208/RG2TXC/DVCK";
+ bias-disable;
+ input-enable;
+ };
+ gpio208o_pins: gpio208o-pins {
+ pins = "GPIO208/RG2TXC/DVCK";
+ bias-disable;
+ output-high;
+ };
+ gpio208ol_pins: gpio208ol-pins {
+ pins = "GPIO208/RG2TXC/DVCK";
+ bias-disable;
+ output-low;
+ };
+ gpio209_pins: gpio209-pins {
+ pins = "GPIO209/RG2TXCTL/DDRV4";
+ bias-disable;
+ input-enable;
+ };
+ gpio209ol_pins: gpio209ol-pins {
+ pins = "GPIO209/RG2TXCTL/DDRV4";
+ bias-disable;
+ output-low;
+ };
+ gpio210_pins: gpio210-pins {
+ pins = "GPIO210/RG2RXD0/DDRV5";
+ bias-disable;
+ input-enable;
+ };
+ gpio210o_pins: gpio210o-pins {
+ pins = "GPIO210/RG2RXD0/DDRV5";
+ bias-disable;
+ output-high;
+ };
+ gpio210ol_pins: gpio210ol-pins {
+ pins = "GPIO210/RG2RXD0/DDRV5";
+ bias-disable;
+ output-low;
+ };
+ gpio211_pins: gpio211-pins {
+ pins = "GPIO211/RG2RXD1/DDRV6";
+ bias-disable;
+ input-enable;
+ };
+ gpio211o_pins: gpio211o-pins {
+ pins = "GPIO211/RG2RXD1/DDRV6";
+ bias-disable;
+ output-high;
+ };
+ gpio211ol_pins: gpio211ol-pins {
+ pins = "GPIO211/RG2RXD1/DDRV6";
+ bias-disable;
+ output-low;
+ };
+ gpio212_pins: gpio212-pins {
+ pins = "GPIO212/RG2RXD2/DDRV7";
+ bias-disable;
+ input-enable;
+ };
+ gpio212o_pins: gpio212o-pins {
+ pins = "GPIO212/RG2RXD2/DDRV7";
+ bias-disable;
+ output-high;
+ };
+ gpio212ol_pins: gpio212ol-pins {
+ pins = "GPIO212/RG2RXD2/DDRV7";
+ bias-disable;
+ output-low;
+ };
+ gpio213_pins: gpio213-pins {
+ pins = "GPIO213/RG2RXD3/DDRV8";
+ bias-disable;
+ input-enable;
+ };
+ gpio213o_pins: gpio213o-pins {
+ pins = "GPIO213/RG2RXD3/DDRV8";
+ bias-disable;
+ output-high;
+ };
+ gpio213ol_pins: gpio213ol-pins {
+ pins = "GPIO213/RG2RXD3/DDRV8";
+ bias-disable;
+ output-low;
+ };
+ gpio214_pins: gpio214-pins {
+ pins = "GPIO214/RG2RXC/DDRV9";
+ bias-disable;
+ input-enable;
+ };
+ gpio214ol_pins: gpio214ol-pins {
+ pins = "GPIO214/RG2RXC/DDRV9";
+ bias-disable;
+ output-low;
+ };
+ gpio215_pins: gpio215-pins {
+ pins = "GPIO215/RG2RXCTL/DDRV10";
+ bias-disable;
+ input-enable;
+ };
+ gpio215ol_pins: gpio215ol-pins {
+ pins = "GPIO215/RG2RXCTL/DDRV10";
+ bias-disable;
+ output-low;
+ };
+ gpio216_pins: gpio216-pins {
+ pins = "GPIO216/RG2MDC/DDRV11";
+ bias-disable;
+ input-enable;
+ };
+ gpio216ol_pins: gpio216ol-pins {
+ pins = "GPIO216/RG2MDC/DDRV11";
+ bias-disable;
+ output-low;
+ };
+ gpio217_pins: gpio217-pins {
+ pins = "GPIO217/RG2MDIO/DVHSYNC";
+ bias-disable;
+ input-enable;
+ };
+ gpio217ol_pins: gpio217ol-pins {
+ pins = "GPIO217/RG2MDIO/DVHSYNC";
+ bias-disable;
+ output-low;
+ };
+ gpio218_pins: gpio218-pins {
+ pins = "GPIO218/nWDO1";
+ bias-disable;
+ input-enable;
+ };
+ gpio218ol_pins: gpio218ol-pins {
+ pins = "GPIO218/nWDO1";
+ bias-disable;
+ output-low;
+ };
+ gpio219_pins: gpio219-pins {
+ pins = "GPIO219/nWDO2";
+ bias-disable;
+ input-enable;
+ };
+ gpio219ol_pins: gpio219ol-pins {
+ pins = "GPIO219/nWDO2";
+ bias-disable;
+ output-low;
+ };
+ gpio220ol_pins: gpio220ol-pins {
+ pins = "GPIO220/SMB12SCL";
+ bias-disable;
+ output-low;
+ };
+ gpio221o_pins: gpio221o-pins {
+ pins = "GPIO221/SMB12SDA";
+ bias-disable;
+ output-high;
+ };
+ gpio222_pins: gpio222-pins {
+ pins = "GPIO222/SMB13SCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio222o_pins: gpio222o-pins {
+ pins = "GPIO222/SMB13SCL";
+ bias-disable;
+ output-high;
+ };
+ gpio223_pins: gpio223-pins {
+ pins = "GPIO223/SMB13SDA";
+ bias-disable;
+ input-enable;
+ };
+ gpio223ol_pins: gpio223ol-pins {
+ pins = "GPIO223/SMB13SDA";
+ bias-disable;
+ output-low;
+ };
+ gpio224_pins: gpio224-pins {
+ pins = "GPIO224/SPIXCK";
+ bias-disable;
+ input-enable;
+ };
+ gpio224o_pins: gpio224o-pins {
+ pins = "GPIO224/SPIXCK";
+ bias-disable;
+ output-high;
+ };
+ gpio224ol_pins: gpio224ol-pins {
+ pins = "GPIO224/SPIXCK";
+ bias-disable;
+ output-low;
+ };
+ gpio225_pins: gpio225-pins {
+ pins = "GPO225/SPIXD0/STRAP12";
+ bias-disable;
+ input-enable;
+ };
+ gpio225o_pins: gpio225o-pins {
+ pins = "GPO225/SPIXD0/STRAP12";
+ bias-disable;
+ output-high;
+ };
+ gpio226_pins: gpio226-pins {
+ pins = "GPO226/SPIXD1/STRAP13";
+ bias-disable;
+ input-enable;
+ };
+ gpio226o_pins: gpio226o-pins {
+ pins = "GPO226/SPIXD1/STRAP13";
+ bias-disable;
+ output-high;
+ };
+ gpio227_pins: gpio227-pins {
+ pins = "GPIO227/nSPIXCS0";
+ bias-disable;
+ input-enable;
+ };
+ gpio227o_pins: gpio227o-pins {
+ pins = "GPIO227/nSPIXCS0";
+ bias-disable;
+ output-high;
+ };
+ gpio227ol_pins: gpio227ol-pins {
+ pins = "GPIO227/nSPIXCS0";
+ bias-disable;
+ output-low;
+ };
+ gpio228_pins: gpio228-pins {
+ pins = "GPIO228/nSPIXCS1";
+ bias-disable;
+ input-enable;
+ };
+ gpio228ol_pins: gpio228ol-pins {
+ pins = "GPIO228/nSPIXCS1";
+ bias-disable;
+ output-low;
+ };
+ gpio229_pins: gpio229-pins {
+ pins = "GPO229/SPIXD2/STRAP3";
+ bias-disable;
+ input-enable;
+ };
+ gpio229o_pins: gpio229o-pins {
+ pins = "GPO229/SPIXD2/STRAP3";
+ bias-disable;
+ output-high;
+ };
+ gpio230_pins: gpio230-pins {
+ pins = "GPIO230/SPIXD3";
+ bias-disable;
+ input-enable;
+ };
+ gpio230o_pins: gpio230o-pins {
+ pins = "GPIO230/SPIXD3";
+ bias-disable;
+ output-high;
+ };
+ gpio230ol_pins: gpio230ol-pins {
+ pins = "GPIO230/SPIXD3";
+ bias-disable;
+ output-low;
+ };
+ gpio231_pins: gpio231-pins {
+ pins = "GPIO231/nCLKREQ";
+ bias-disable;
+ input-enable;
+ };
+ gpio231o_pins: gpio231o-pins {
+ pins = "GPIO231/nCLKREQ";
+ bias-disable;
+ output-high;
+ };
+ gpio255_pins: gpio255-pins {
+ pins = "GPI255/DACOSEL";
+ bias-disable;
+ input-enable;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/nuvoton-npcm750-runbmc-olympus-pincfg.dtsi b/arch/arm/boot/dts/nuvoton-npcm750-runbmc-olympus-pincfg.dtsi
new file mode 100644
index 000000000000..230cb344b2e1
--- /dev/null
+++ b/arch/arm/boot/dts/nuvoton-npcm750-runbmc-olympus-pincfg.dtsi
@@ -0,0 +1,517 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2019 Quanta Computer Inc. Samuel.Jiang@quantatw.com
+
+/ {
+ pinctrl: pinctrl@f0800000 {
+ gpio0ol_pins: gpio0ol-pins {
+ pins = "GPIO0/IOX1DI";
+ bias-disable;
+ output-low;
+ };
+ gpio1ol_pins: gpio1ol-pins {
+ pins = "GPIO1/IOX1LD";
+ bias-disable;
+ output-low;
+ };
+ gpio2ol_pins: gpio2ol-pins {
+ pins = "GPIO2/IOX1CK";
+ bias-disable;
+ output-low;
+ };
+ gpio3ol_pins: gpio3ol-pins {
+ pins = "GPIO3/IOX1D0";
+ bias-disable;
+ output-low;
+ };
+ gpio5_pins: gpio5-pins {
+ pins = "GPIO5/IOX2LD/SMB1DSCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio6_pins: gpio6-pins {
+ pins = "GPIO6/IOX2CK/SMB2DSDA";
+ bias-disable;
+ input-enable;
+ };
+ gpio7_pins: gpio7-pins {
+ pins = "GPIO7/IOX2D0/SMB2DSCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio8o_pins: gpio8o-pins {
+ pins = "GPIO8/LKGPO1";
+ bias-disable;
+ output-high;
+ };
+ gpio9ol_pins: gpio9ol-pins {
+ pins = "GPIO9/LKGPO2";
+ bias-disable;
+ output-low;
+ };
+ gpio10_pins: gpio10-pins {
+ pins = "GPIO10/IOXHLD";
+ bias-disable;
+ input-enable;
+ };
+ gpio11_pins: gpio11-pins {
+ pins = "GPIO11/IOXHCK";
+ bias-disable;
+ input-enable;
+ };
+ gpio12ol_pins: gpio12ol-pins {
+ pins = "GPIO12/GSPICK/SMB5BSCL";
+ bias-disable;
+ output-low;
+ };
+ gpio13ol_pins: gpio13ol-pins {
+ pins = "GPIO13/GSPIDO/SMB5BSDA";
+ bias-disable;
+ output-low;
+ };
+ gpio14ol_pins: gpio14ol-pins {
+ pins = "GPIO14/GSPIDI/SMB5CSCL";
+ bias-disable;
+ output-low;
+ };
+ gpio15ol_pins: gpio15ol-pins {
+ pins = "GPIO15/GSPICS/SMB5CSDA";
+ bias-disable;
+ output-low;
+ };
+ gpio20_pins: gpio20-pins {
+ pins = "GPIO20/SMB4CSDA/SMB15SDA";
+ bias-disable;
+ input-enable;
+ };
+ gpio21_pins: gpio21-pins {
+ pins = "GPIO21/SMB4CSCL/SMB15SCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio22o_pins: gpio22o-pins {
+ pins = "GPIO22/SMB4DSDA/SMB14SDA";
+ bias-disable;
+ output-high;
+ };
+ gpio23_pins: gpio23-pins {
+ pins = "GPIO23/SMB4DSCL/SMB14SCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio24_pins: gpio24-pins {
+ pins = "GPIO24/IOXHDO";
+ bias-disable;
+ input-enable;
+ };
+ gpio25_pins: gpio25-pins {
+ pins = "GPIO25/IOXHDI";
+ bias-disable;
+ input-enable;
+ };
+ gpio30_pins: gpio30-pins {
+ pins = "GPIO30/SMB3SDA";
+ bias-disable;
+ input-enable;
+ };
+ gpio31_pins: gpio31-pins {
+ pins = "GPIO31/SMB3SCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio37o_pins: gpio37o-pins {
+ pins = "GPIO37/SMB3CSDA";
+ bias-disable;
+ output-high;
+ };
+ gpio38_pins: gpio38-pins {
+ pins = "GPIO38/SMB3CSCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio39_pins: gpio39-pins {
+ pins = "GPIO39/SMB3BSDA";
+ bias-disable;
+ input-enable;
+ };
+ gpio40o_pins: gpio40o-pins {
+ pins = "GPIO40/SMB3BSCL";
+ bias-disable;
+ output-high;
+ };
+ gpio59_pins: gpio59-pins {
+ pins = "GPIO59/SMB3DSDA";
+ bias-disable;
+ input-enable;
+ };
+ gpio76_pins: gpio76-pins {
+ pins = "GPIO76/FANIN12";
+ bias-disable;
+ input-enable;
+ };
+ gpio77_pins: gpio77-pins {
+ pins = "GPIO77/FANIN13";
+ bias-disable;
+ input-enable;
+ };
+ gpio78o_pins: gpio78o-pins {
+ pins = "GPIO78/FANIN14";
+ bias-disable;
+ output-high;
+ };
+ gpio79_pins: gpio79-pins {
+ pins = "GPIO79/FANIN15";
+ bias-disable;
+ input-enable;
+ };
+ gpio82_pins: gpio82-pins {
+ pins = "GPIO82/PWM2";
+ bias-disable;
+ input-enable;
+ };
+ gpio83_pins: gpio83-pins {
+ pins = "GPIO83/PWM3";
+ bias-disable;
+ input-enable;
+ };
+ gpio84_pins: gpio84-pins {
+ pins = "GPIO84/R2TXD0";
+ bias-disable;
+ input-enable;
+ };
+ gpio85o_pins: gpio85o-pins {
+ pins = "GPIO85/R2TXD1";
+ bias-disable;
+ output-high;
+ };
+ gpio86ol_pins: gpio86ol-pins {
+ pins = "GPIO86/R2TXEN";
+ bias-disable;
+ output-low;
+ };
+ gpio87_pins: gpio87-pins {
+ pins = "GPIO87/R2RXD0";
+ bias-disable;
+ input-enable;
+ };
+ gpio88_pins: gpio88-pins {
+ pins = "GPIO88/R2RXD1";
+ bias-disable;
+ input-enable;
+ };
+ gpio89_pins: gpio89-pins {
+ pins = "GPIO89/R2CRSDV";
+ bias-disable;
+ input-enable;
+ };
+ gpio90_pins: gpio90-pins {
+ pins = "GPIO90/R2RXERR";
+ bias-disable;
+ input-enable;
+ };
+ gpio93_pins: gpio93-pins {
+ pins = "GPIO93/GA20/SMB5DSCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio94ol_pins: gpio94ol-pins {
+ pins = "GPIO94/nKBRST/SMB5DSDA";
+ bias-disable;
+ output-low;
+ };
+ gpio108ol_pins: gpio108ol-pins {
+ pins = "GPIO108/RG1MDC";
+ bias-disable;
+ output-low;
+ };
+ gpio109ol_pins: gpio109ol-pins {
+ pins = "GPIO109/RG1MDIO";
+ bias-disable;
+ output-low;
+ };
+ gpio110ol_pins: gpio110ol-pins {
+ pins = "GPIO110/RG2TXD0/DDRV0";
+ bias-disable;
+ output-low;
+ };
+ gpio111ol_pins: gpio111ol-pins {
+ pins = "GPIO111/RG2TXD1/DDRV1";
+ bias-disable;
+ output-low;
+ };
+ gpio112ol_pins: gpio112ol-pins {
+ pins = "GPIO112/RG2TXD2/DDRV2";
+ bias-disable;
+ output-low;
+ };
+ gpio113ol_pins: gpio113ol-pins {
+ pins = "GPIO113/RG2TXD3/DDRV3";
+ bias-disable;
+ output-low;
+ };
+ gpio114o_pins: gpio114o-pins {
+ pins = "GPIO114/SMB0SCL";
+ bias-disable;
+ output-high;
+ };
+ gpio115_pins: gpio115-pins {
+ pins = "GPIO115/SMB0SDA";
+ bias-disable;
+ input-enable;
+ };
+ gpio120_pins: gpio120-pins {
+ pins = "GPIO120/SMB2CSDA";
+ bias-disable;
+ input-enable;
+ };
+ gpio121_pins: gpio121-pins {
+ pins = "GPIO121/SMB2CSCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio122_pins: gpio122-pins {
+ pins = "GPIO122/SMB2BSDA";
+ bias-disable;
+ input-enable;
+ };
+ gpio123_pins: gpio123-pins {
+ pins = "GPIO123/SMB2BSCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio124_pins: gpio124-pins {
+ pins = "GPIO124/SMB1CSDA";
+ bias-disable;
+ input-enable;
+ };
+ gpio125_pins: gpio125-pins {
+ pins = "GPIO125/SMB1CSCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio126_pins: gpio126-pins {
+ pins = "GPIO126/SMB1BSDA";
+ bias-disable;
+ input-enable;
+ };
+ gpio127o_pins: gpio127o-pins {
+ pins = "GPIO127/SMB1BSCL";
+ bias-disable;
+ output-high;
+ };
+ gpio136_pins: gpio136-pins {
+ pins = "GPIO136/SD1DT0";
+ bias-disable;
+ input-enable;
+ };
+ gpio137_pins: gpio137-pins {
+ pins = "GPIO137/SD1DT1";
+ bias-disable;
+ input-enable;
+ };
+ gpio138_pins: gpio138-pins {
+ pins = "GPIO138/SD1DT2";
+ bias-disable;
+ input-enable;
+ };
+ gpio139_pins: gpio139-pins {
+ pins = "GPIO139/SD1DT3";
+ bias-disable;
+ input-enable;
+ };
+ gpio140_pins: gpio140-pins {
+ pins = "GPIO140/SD1CLK";
+ bias-disable;
+ input-enable;
+ };
+ gpio141_pins: gpio141-pins {
+ pins = "GPIO141/SD1WP";
+ bias-disable;
+ input-enable;
+ };
+ gpio142_pins: gpio142-pins {
+ pins = "GPIO142/SD1CMD";
+ bias-disable;
+ input-enable;
+ };
+ gpio143_pins: gpio143-pins {
+ pins = "GPIO143/SD1CD/SD1PWR";
+ bias-disable;
+ input-enable;
+ };
+ gpio144_pins: gpio144-pins {
+ pins = "GPIO144/PWM4";
+ bias-disable;
+ input-enable;
+ };
+ gpio145_pins: gpio145-pins {
+ pins = "GPIO145/PWM5";
+ bias-disable;
+ input-enable;
+ };
+ gpio146_pins: gpio146-pins {
+ pins = "GPIO146/PWM6";
+ bias-disable;
+ input-enable;
+ };
+ gpio147_pins: gpio147-pins {
+ pins = "GPIO147/PWM7";
+ bias-disable;
+ input-enable;
+ };
+ gpio153o_pins: gpio153o-pins {
+ pins = "GPIO153/MMCWP";
+ bias-disable;
+ output-high;
+ };
+ gpio155_pins: gpio155-pins {
+ pins = "GPIO155/nMMCCD/nMMCRST";
+ bias-disable;
+ input-enable;
+ };
+ gpio160o_pins: gpio160o-pins {
+ pins = "GPIO160/CLKOUT/RNGOSCOUT";
+ bias-disable;
+ output-high;
+ };
+ gpio169o_pins: gpio169o-pins {
+ pins = "GPIO169/nSCIPME";
+ bias-disable;
+ output-high;
+ };
+ gpio188o_pins: gpio188o-pins {
+ pins = "GPIO188/SPI3D2/nSPI3CS2";
+ bias-disable;
+ output-high;
+ };
+ gpio189_pins: gpio189-pins {
+ pins = "GPIO189/SPI3D3/nSPI3CS3";
+ bias-disable;
+ input-enable;
+ };
+ gpio196_pins: gpio196-pins {
+ pins = "GPIO196/SMB0CSCL";
+ bias-disable;
+ input-enable;
+ };
+ gpio197_pins: gpio197-pins {
+ pins = "GPIO197/SMB0DEN";
+ bias-disable;
+ input-enable;
+ };
+ gpio198o_pins: gpio198o-pins {
+ pins = "GPIO198/SMB0DSDA";
+ bias-disable;
+ output-high;
+ };
+ gpio199o_pins: gpio199o-pins {
+ pins = "GPIO199/SMB0DSCL";
+ bias-disable;
+ output-high;
+ };
+ gpio200_pins: gpio200-pins {
+ pins = "GPIO200/R2CK";
+ input-enable;
+ bias-disable;
+ };
+ gpio202_pins: gpio202-pins {
+ pins = "GPIO202/SMB0CSDA";
+ bias-disable;
+ input-enable;
+ };
+ gpio203o_pins: gpio203o-pins {
+ pins = "GPIO203/FANIN16";
+ bias-disable;
+ output-high;
+ };
+ gpio208_pins: gpio208-pins {
+ pins = "GPIO208/RG2TXC/DVCK";
+ bias-disable;
+ input-enable;
+ };
+ gpio209ol_pins: gpio209ol-pins {
+ pins = "GPIO209/RG2TXCTL/DDRV4";
+ bias-disable;
+ output-low;
+ };
+ gpio210ol_pins: gpio210ol-pins {
+ pins = "GPIO210/RG2RXD0/DDRV5";
+ bias-disable;
+ output-low;
+ };
+ gpio211ol_pins: gpio211ol-pins {
+ pins = "GPIO211/RG2RXD1/DDRV6";
+ bias-disable;
+ output-low;
+ };
+ gpio212ol_pins: gpio212ol-pins {
+ pins = "GPIO212/RG2RXD2/DDRV7";
+ bias-disable;
+ output-low;
+ };
+ gpio213ol_pins: gpio213ol-pins {
+ pins = "GPIO213/RG2RXD3/DDRV8";
+ bias-disable;
+ output-low;
+ };
+ gpio214ol_pins: gpio214ol-pins {
+ pins = "GPIO214/RG2RXC/DDRV9";
+ bias-disable;
+ output-low;
+ };
+ gpio215ol_pins: gpio215ol-pins {
+ pins = "GPIO215/RG2RXCTL/DDRV10";
+ bias-disable;
+ output-low;
+ };
+ gpio216ol_pins: gpio216ol-pins {
+ pins = "GPIO216/RG2MDC/DDRV11";
+ bias-disable;
+ output-low;
+ };
+ gpio217ol_pins: gpio217ol-pins {
+ pins = "GPIO217/RG2MDIO/DVHSYNC";
+ bias-disable;
+ output-low;
+ };
+ gpio224_pins: gpio224-pins {
+ pins = "GPIO224/SPIXCK";
+ bias-disable;
+ input-enable;
+ };
+ gpio225ol_pins: gpio225ol-pins {
+ pins = "GPO225/SPIXD0/STRAP12";
+ bias-disable;
+ output-low;
+ };
+ gpio226ol_pins: gpio226ol-pins {
+ pins = "GPO226/SPIXD1/STRAP13";
+ bias-disable;
+ output-low;
+ };
+ gpio227ol_pins: gpio227ol-pins {
+ pins = "GPIO227/nSPIXCS0";
+ bias-disable;
+ output-low;
+ };
+ gpio228o_pins: gpio228ol-pins {
+ pins = "GPIO228/nSPIXCS1";
+ bias-disable;
+ output-high;
+ };
+ gpio229o_pins: gpio229o-pins {
+ pins = "GPO229/SPIXD2/STRAP3";
+ bias-disable;
+ output-high;
+ };
+ gpio230_pins: gpio230-pins {
+ pins = "GPIO230/SPIXD3";
+ bias-disable;
+ input-enable;
+ };
+ gpio231o_pins: gpio231o-pins {
+ pins = "GPIO231/nCLKREQ";
+ bias-disable;
+ output-high;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/nuvoton-npcm750-runbmc-olympus.dts b/arch/arm/boot/dts/nuvoton-npcm750-runbmc-olympus.dts
new file mode 100644
index 000000000000..71b384676301
--- /dev/null
+++ b/arch/arm/boot/dts/nuvoton-npcm750-runbmc-olympus.dts
@@ -0,0 +1,1197 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2019 Nuvoton Technology kwliu@nuvoton.com
+// Copyright (c) 2019 Quanta Computer Inc. Samuel.Jiang@quantatw.com
+
+/dts-v1/;
+#include "nuvoton-npcm750.dtsi"
+#include "nuvoton-npcm750-runbmc-olympus-pincfg.dtsi"
+
+/ {
+ model = "Nuvoton npcm750 RunBMC Olympus";
+ compatible = "nuvoton,npcm750";
+
+ aliases {
+ ethernet0 = &emc0;
+ ethernet1 = &gmac0;
+ serial0 = &serial0;
+ serial1 = &serial1;
+ serial2 = &serial2;
+ serial3 = &serial3;
+ udc0 = &udc0;
+ udc1 = &udc1;
+ udc2 = &udc2;
+ udc3 = &udc3;
+ udc4 = &udc4;
+ udc5 = &udc5;
+ udc6 = &udc6;
+ udc7 = &udc7;
+ udc8 = &udc8;
+ udc9 = &udc9;
+ emmc0 = &sdhci0;
+ i2c0 = &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;
+ spi0 = &spi0;
+ spi1 = &spi1;
+ fiu0 = &fiu0;
+ fiu1 = &fiu3;
+ };
+
+ chosen {
+ stdout-path = &serial3;
+ };
+
+ memory {
+ reg = <0 0x40000000>;
+ };
+
+ iio-hwmon {
+ compatible = "iio-hwmon";
+ io-channels = <&adc 0>, <&adc 1>, <&adc 2>, <&adc 3>,
+ <&adc 4>, <&adc 5>, <&adc 6>, <&adc 7>;
+ };
+
+ ahb {
+ gmac0: eth@f0802000 {
+ phy-mode = "rgmii-id";
+ snps,eee-force-disable;
+ status = "okay";
+ };
+
+ emc0: eth@f0825000 {
+ phy-mode = "rmii";
+ use-ncsi;
+ status = "okay";
+ };
+
+ ehci1: usb@f0806000 {
+ status = "okay";
+ };
+
+ ohci1: ohci@f0807000 {
+ status = "okay";
+ };
+
+ udc0:udc@f0830000 {
+ status = "okay";
+ };
+
+ udc1:udc@f0831000 {
+ status = "okay";
+ };
+
+ udc2:udc@f0832000 {
+ status = "okay";
+ };
+
+ udc3:udc@f0833000 {
+ status = "okay";
+ };
+
+ udc4:udc@f0834000 {
+ status = "okay";
+ };
+
+ udc5:udc@f0835000 {
+ status = "okay";
+ };
+
+ udc6:udc@f0836000 {
+ status = "okay";
+ };
+
+ udc7:udc@f0837000 {
+ status = "okay";
+ };
+
+ udc8:udc@f0838000 {
+ status = "okay";
+ };
+
+ udc9:udc@f0839000 {
+ status = "okay";
+ };
+
+ aes:aes@f0858000 {
+ status = "okay";
+ };
+
+ sha:sha@f085a000 {
+ status = "okay";
+ };
+
+ fiu0: fiu@fb000000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi0cs1_pins>;
+ status = "okay";
+ spi-nor@0 {
+ compatible = "jedec,spi-nor";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0>;
+ spi-rx-bus-width = <2>;
+ partitions@80000000 {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ bmc@0{
+ label = "bmc";
+ reg = <0x000000 0x2000000>;
+ };
+ u-boot@0 {
+ label = "u-boot";
+ reg = <0x0000000 0x80000>;
+ read-only;
+ };
+ u-boot-env@100000{
+ label = "u-boot-env";
+ reg = <0x00100000 0x40000>;
+ };
+ kernel@200000 {
+ label = "kernel";
+ reg = <0x0200000 0x600000>;
+ };
+ rofs@800000 {
+ label = "rofs";
+ reg = <0x800000 0x1500000>;
+ };
+ rwfs@1d00000 {
+ label = "rwfs";
+ reg = <0x1d00000 0x300000>;
+ };
+ };
+ };
+ spi-nor@1 {
+ compatible = "jedec,spi-nor";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <1>;
+ npcm,fiu-rx-bus-width = <2>;
+ partitions@88000000 {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ spare1@0 {
+ label = "spi0-cs1-spare1";
+ reg = <0x0 0x800000>;
+ };
+ spare2@800000 {
+ label = "spi0-cs1-spare2";
+ reg = <0x800000 0x0>;
+ };
+ };
+ };
+ };
+
+ fiu3: fiu@c0000000 {
+ pinctrl-0 = <&spi3_pins>;
+ status = "okay";
+ spi-nor@0 {
+ compatible = "jedec,spi-nor";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0>;
+ spi-rx-bus-width = <2>;
+ partitions@A0000000 {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ system1@0 {
+ label = "spi3-system1";
+ reg = <0x0 0x800000>;
+ };
+ system2@800000 {
+ label = "spi3-system2";
+ reg = <0x800000 0x0>;
+ };
+ };
+ };
+ };
+
+ sdhci0: sdhci@f0842000 {
+ status = "okay";
+ };
+
+ pcimbox: pcimbox@f0848000 {
+ status = "okay";
+ };
+
+ vcd: vcd@f0810000 {
+ status = "okay";
+ };
+
+ ece: ece@f0820000 {
+ status = "okay";
+ };
+
+ apb {
+
+ watchdog1: watchdog@901C {
+ status = "okay";
+ };
+
+ rng: rng@b000 {
+ status = "okay";
+ };
+
+ serial0: serial@1000 {
+ status = "okay";
+ };
+
+ serial1: serial@2000 {
+ status = "okay";
+ };
+
+ serial2: serial@3000 {
+ status = "okay";
+ };
+
+ serial3: serial@4000 {
+ status = "okay";
+ };
+
+ adc: adc@c000 {
+ #io-channel-cells = <1>;
+ status = "okay";
+ };
+
+ otp:otp@189000 {
+ status = "okay";
+ };
+
+ lpc_kcs: lpc_kcs@7000 {
+ kcs1: kcs1@0 {
+ status = "okay";
+ };
+
+ kcs2: kcs2@0 {
+ status = "okay";
+ };
+
+ kcs3: kcs3@0 {
+ status = "okay";
+ };
+ };
+
+ lpc_host: lpc_host@7000 {
+ lpc_bpc: lpc_bpc@40 {
+ monitor-ports = <0x80>;
+ status = "okay";
+ };
+ };
+
+ i2c0: i2c@80000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ status = "disabled";
+ };
+
+ i2c1: i2c@81000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ status = "okay";
+ i2c-switch@70 {
+ compatible = "nxp,pca9548";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x70>;
+ i2c-mux-idle-disconnect;
+
+ i2c_slot1a: i2c-bus@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+ };
+
+ i2c_slot1b: i2c-bus@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+ };
+
+ i2c_slot2a: i2c-bus@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+ };
+
+ i2c_slot2b: i2c-bus@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+ };
+
+ i2c_slot3: i2c-bus@4 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <4>;
+ };
+
+ i2c_slot4: i2c-bus@5 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <5>;
+ };
+
+ i2c_slot5: i2c-bus@6 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <6>;
+ };
+ };
+
+ i2c-switch@71 {
+ compatible = "nxp,pca9546";
+ reg = <0x71>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ i2c-mux-idle-disconnect;
+
+ i2c_m2_s1: i2c-bus@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+ };
+
+ i2c_m2_s2: i2c-bus@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+ };
+ i2c_m2_s3: i2c-bus@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+ };
+
+ i2c_m2_s4: i2c-bus@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+ };
+ };
+ };
+
+ i2c2: i2c@82000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ status = "okay";
+ tmp421@4c {
+ compatible = "ti,tmp421";
+ reg = <0x4c>;
+ };
+ power-supply@58 {
+ compatible = "delta,dps800";
+ reg = <0x58>;
+ };
+ };
+
+ i2c3: i2c@83000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ status = "okay";
+ };
+
+ i2c4: i2c@84000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ status = "okay";
+ eeprom@54 {
+ compatible = "atmel,24c64";
+ reg = <0x54>;
+ };
+ };
+
+ i2c5: i2c@85000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ status = "okay";
+ slave_mqueue: i2c-slave-mqueue@40000010 {
+ compatible = "i2c-slave-mqueue";
+ reg = <0x40000010>;
+ status = "okay";
+ };
+ };
+
+ i2c6: i2c@86000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ status = "okay";
+ ina219@40 {
+ compatible = "ti,ina219";
+ reg = <0x40>;
+ };
+ ina219@41 {
+ compatible = "ti,ina219";
+ reg = <0x41>;
+ };
+ ina219@44 {
+ compatible = "ti,ina219";
+ reg = <0x44>;
+ };
+ ina219@45 {
+ compatible = "ti,ina219";
+ reg = <0x45>;
+ };
+ tps53679@60 {
+ compatible = "ti,tps53679";
+ reg = <0x60>;
+ };
+ tps53659@62 {
+ compatible = "ti,tps53659";
+ reg = <0x62>;
+ };
+ tps53659@64 {
+ compatible = "ti,tps53659";
+ reg = <0x64>;
+ };
+ tps53622@67 {
+ compatible = "ti,tps53622";
+ reg = <0x67>;
+ };
+ tps53622@69 {
+ compatible = "ti,tps53622";
+ reg = <0x69>;
+ };
+ tps53679@70 {
+ compatible = "ti,tps53679";
+ reg = <0x70>;
+ };
+ tps53659@72 {
+ compatible = "ti,tps53659";
+ reg = <0x72>;
+ };
+ tps53659@74 {
+ compatible = "ti,tps53659";
+ reg = <0x74>;
+ };
+ tps53622@77 {
+ compatible = "ti,tps53622";
+ reg = <0x77>;
+ };
+ };
+
+ i2c7: i2c@87000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ status = "okay";
+ tmp421@4c {
+ compatible = "ti,tmp421";
+ reg = <0x4c>;
+ };
+ };
+
+ i2c8: i2c@88000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ status = "okay";
+ adm1278@11 {
+ compatible = "adm1278";
+ reg = <0x11>;
+ Rsense = <500>;
+ };
+ };
+
+ i2c9: i2c@89000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ status = "okay";
+ };
+
+ i2c10: i2c@8a000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ status = "okay";
+ gpio: pca9555@27 {
+ compatible = "nxp,pca9555";
+ reg = <0x27>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+ };
+
+ i2c11: i2c@8b000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ status = "okay";
+ pca9539_g1a: pca9539-g1a@74 {
+ compatible = "nxp,pca9539";
+ reg = <0x74>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ reset-gpios = <&gpio7 4 GPIO_ACTIVE_LOW>;
+ G1A_P0_0 {
+ gpio-hog;
+ gpios = <0 0>;
+ output-high;
+ line-name = "TPM_BMC_ALERT_N";
+ };
+ G1A_P0_1 {
+ gpio-hog;
+ gpios = <1 0>;
+ input;
+ line-name = "FM_BIOS_TOP_SWAP";
+ };
+ G1A_P0_2 {
+ gpio-hog;
+ gpios = <2 0>;
+ input;
+ line-name = "FM_BIOS_PREFRB2_GOOD";
+ };
+ G1A_P0_3 {
+ gpio-hog;
+ gpios = <3 0>;
+ input;
+ line-name = "BMC_SATAXPCIE_0TO3_SEL";
+ };
+ G1A_P0_4 {
+ gpio-hog;
+ gpios = <4 0>;
+ input;
+ line-name = "BMC_SATAXPCIE_4TO7_SEL";
+ };
+ G1A_P0_5 {
+ gpio-hog;
+ gpios = <5 0>;
+ output-low;
+ line-name = "FM_UV_ADR_TRIGGER_EN_N";
+ };
+ G1A_P0_6 {
+ gpio-hog;
+ gpios = <6 0>;
+ input;
+ line-name = "RM_THROTTLE_EN_N";
+ };
+ G1A_P1_0 {
+ gpio-hog;
+ gpios = <8 0>;
+ input;
+ line-name = "FM_BMC_TPM_PRES_N";
+ };
+ G1A_P1_1 {
+ gpio-hog;
+ gpios = <9 0>;
+ input;
+ line-name = "FM_CPU0_SKTOCC_LVT3_N";
+ };
+ G1A_P1_2 {
+ gpio-hog;
+ gpios = <10 0>;
+ input;
+ line-name = "FM_CPU1_SKTOCC_LVT3_N";
+ };
+ G1A_P1_3 {
+ gpio-hog;
+ gpios = <11 0>;
+ input;
+ line-name = "PSU1_ALERT_N";
+ };
+ G1A_P1_4 {
+ gpio-hog;
+ gpios = <12 0>;
+ input;
+ line-name = "PSU2_ALERT_N";
+ };
+ G1A_P1_5 {
+ gpio-hog;
+ gpios = <13 0>;
+ input;
+ line-name = "H_CPU0_FAST_WAKE_LVT3_N";
+ };
+ G1A_P1_6 {
+ gpio-hog;
+ gpios = <14 0>;
+ output-high;
+ line-name = "I2C_MUX1_RESET_N";
+ };
+ G1A_P1_7 {
+ gpio-hog;
+ gpios = <15 0>;
+ input;
+ line-name = "FM_CPU_CATERR_LVT3_N";
+ };
+ };
+ pca9539_g1b: pca9539-g1b@75 {
+ compatible = "nxp,pca9539";
+ reg = <0x75>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ G1B_P0_0 {
+ gpio-hog;
+ gpios = <0 0>;
+ input;
+ line-name = "PVDDQ_ABC_PINALERT_N";
+ };
+ G1B_P0_1 {
+ gpio-hog;
+ gpios = <1 0>;
+ input;
+ line-name = "PVDDQ_DEF_PINALERT_N";
+ };
+ G1B_P0_2 {
+ gpio-hog;
+ gpios = <2 0>;
+ input;
+ line-name = "PVDDQ_GHJ_PINALERT_N";
+ };
+ G1B_P0_3 {
+ gpio-hog;
+ gpios = <3 0>;
+ input;
+ line-name = "PVDDQ_KLM_PINALERT_N";
+ };
+ G1B_P0_5 {
+ gpio-hog;
+ gpios = <5 0>;
+ input;
+ line-name = "FM_BOARD_REV_ID0";
+ };
+ G1B_P0_6 {
+ gpio-hog;
+ gpios = <6 0>;
+ input;
+ line-name = "FM_BOARD_REV_ID1";
+ };
+ G1B_P0_7 {
+ gpio-hog;
+ gpios = <7 0>;
+ input;
+ line-name = "FM_BOARD_REV_ID2";
+ };
+ G1B_P1_0 {
+ gpio-hog;
+ gpios = <8 0>;
+ input;
+ line-name = "FM_OC_DETECT_EN_N";
+ };
+ G1B_P1_1 {
+ gpio-hog;
+ gpios = <9 0>;
+ input;
+ line-name = "FM_FLASH_DESC_OVERRIDE";
+ };
+ G1B_P1_2 {
+ gpio-hog;
+ gpios = <10 0>;
+ output-low;
+ line-name = "FP_PWR_ID_LED_N";
+ };
+ G1B_P1_3 {
+ gpio-hog;
+ gpios = <11 0>;
+ output-low;
+ line-name = "BMC_LED_PWR_GRN";
+ };
+ G1B_P1_4 {
+ gpio-hog;
+ gpios = <12 0>;
+ output-low;
+ line-name = "BMC_LED_PWR_AMBER";
+ };
+ G1B_P1_5 {
+ gpio-hog;
+ gpios = <13 0>;
+ output-high;
+ line-name = "FM_BMC_FAULT_LED_N";
+ };
+ G1B_P1_6 {
+ gpio-hog;
+ gpios = <14 0>;
+ output-high;
+ line-name = "FM_CPLD_BMC_PWRDN_N";
+ };
+ G1B_P1_7 {
+ gpio-hog;
+ gpios = <15 0>;
+ output-high;
+ line-name = "BMC_LED_CATERR_N";
+ };
+ };
+ };
+
+ i2c12: i2c@8c000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ status = "okay";
+ pca9539_g2a: pca9539-g2a@74 {
+ compatible = "nxp,pca9539";
+ reg = <0x74>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ reset-gpios = <&gpio5 28 GPIO_ACTIVE_LOW>;
+ G2A_P0_0 {
+ gpio-hog;
+ gpios = <0 0>;
+ output-high;
+ line-name = "BMC_PON_RST_REQ_N";
+ };
+ G2A_P0_1 {
+ gpio-hog;
+ gpios = <1 0>;
+ output-high;
+ line-name = "BMC_RST_IND_REQ_N";
+ };
+ G2A_P0_2 {
+ gpio-hog;
+ gpios = <2 0>;
+ input;
+ line-name = "RST_BMC_RTCRST";
+ };
+ G2A_P0_3 {
+ gpio-hog;
+ gpios = <3 0>;
+ output-high;
+ line-name = "FM_BMC_PWRBTN_OUT_N";
+ };
+ G2A_P0_4 {
+ gpio-hog;
+ gpios = <4 0>;
+ output-high;
+ line-name = "RST_BMC_SYSRST_BTN_OUT_N";
+ };
+ G2A_P0_5 {
+ gpio-hog;
+ gpios = <5 0>;
+ output-high;
+ line-name = "FM_BATTERY_SENSE_EN_N";
+ };
+ G2A_P0_6 {
+ gpio-hog;
+ gpios = <6 0>;
+ output-high;
+ line-name = "FM_BMC_READY_N";
+ };
+ G2A_P0_7 {
+ gpio-hog;
+ gpios = <7 0>;
+ input;
+ line-name = "IRQ_BMC_PCH_SMI_LPC_N";
+ };
+ G2A_P1_0 {
+ gpio-hog;
+ gpios = <8 0>;
+ input;
+ line-name = "FM_SLOT4_CFG0";
+ };
+ G2A_P1_1 {
+ gpio-hog;
+ gpios = <9 0>;
+ input;
+ line-name = "FM_SLOT4_CFG1";
+ };
+ G2A_P1_2 {
+ gpio-hog;
+ gpios = <10 0>;
+ input;
+ line-name = "FM_NVDIMM_EVENT_N";
+ };
+ G2A_P1_3 {
+ gpio-hog;
+ gpios = <11 0>;
+ input;
+ line-name = "PSU1_BLADE_EN_N";
+ };
+ G2A_P1_4 {
+ gpio-hog;
+ gpios = <12 0>;
+ input;
+ line-name = "BMC_PCH_FNM";
+ };
+ G2A_P1_5 {
+ gpio-hog;
+ gpios = <13 0>;
+ input;
+ line-name = "FM_SOL_UART_CH_SEL";
+ };
+ G2A_P1_6 {
+ gpio-hog;
+ gpios = <14 0>;
+ input;
+ line-name = "FM_BIOS_POST_CMPLT_N";
+ };
+ };
+
+ pca9539_g2b: pca9539-g2b@75 {
+ compatible = "nxp,pca9539";
+ reg = <0x75>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ G2B_P0_0 {
+ gpio-hog;
+ gpios = <0 0>;
+ input;
+ line-name = "FM_CPU_MSMI_LVT3_N";
+ };
+ G2B_P0_1 {
+ gpio-hog;
+ gpios = <1 0>;
+ input;
+ line-name = "FM_BIOS_MRC_DEBUG_MSG_DIS";
+ };
+ G2B_P0_2 {
+ gpio-hog;
+ gpios = <2 0>;
+ input;
+ line-name = "FM_CPU1_DISABLE_BMC_N";
+ };
+ G2B_P0_3 {
+ gpio-hog;
+ gpios = <3 0>;
+ output-low;
+ line-name = "BMC_JTAG_SELECT";
+ };
+ G2B_P0_4 {
+ gpio-hog;
+ gpios = <4 0>;
+ output-high;
+ line-name = "PECI_MUX_SELECT";
+ };
+ G2B_P0_5 {
+ gpio-hog;
+ gpios = <5 0>;
+ output-high;
+ line-name = "I2C_MUX2_RESET_N";
+ };
+ G2B_P0_6 {
+ gpio-hog;
+ gpios = <6 0>;
+ input;
+ line-name = "FM_BMC_CPLD_PSU2_ON";
+ };
+ G2B_P0_7 {
+ gpio-hog;
+ gpios = <7 0>;
+ output-high;
+ line-name = "PSU2_ALERT_EN_N";
+ };
+ G2B_P1_0 {
+ gpio-hog;
+ gpios = <8 0>;
+ output-high;
+ line-name = "FM_CPU_BMC_INIT";
+ };
+ G2B_P1_1 {
+ gpio-hog;
+ gpios = <9 0>;
+ output-high;
+ line-name = "IRQ_BMC_PCH_SCI_LPC_N";
+ };
+ G2B_P1_2 {
+ gpio-hog;
+ gpios = <10 0>;
+ output-low;
+ line-name = "PMB_ALERT_EN_N";
+ };
+ G2B_P1_3 {
+ gpio-hog;
+ gpios = <11 0>;
+ output-high;
+ line-name = "FM_FAST_PROCHOT_EN_N";
+ };
+ G2B_P1_4 {
+ gpio-hog;
+ gpios = <12 0>;
+ output-high;
+ line-name = "BMC_NVDIMM_PRSNT_N";
+ };
+ G2B_P1_5 {
+ gpio-hog;
+ gpios = <13 0>;
+ output-low;
+ line-name = "FM_BACKUP_BIOS_SEL_H_BMC";
+ };
+ G2B_P1_6 {
+ gpio-hog;
+ gpios = <14 0>;
+ output-high;
+ line-name = "FM_PWRBRK_N";
+ };
+ };
+ };
+
+ i2c13: i2c@8d000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ bus-frequency = <100000>;
+ status = "okay";
+ tmp75@4a {
+ compatible = "ti,tmp75";
+ reg = <0x4a>;
+ status = "okay";
+ };
+ m24128_fru@51 {
+ compatible = "atmel,24c128";
+ reg = <0x51>;
+ pagesize = <64>;
+ status = "okay";
+ };
+ };
+
+ pwm_fan:pwm-fan-controller@103000 {
+ pinctrl-names = "default";
+ pinctrl-0 = < &pwm0_pins &pwm1_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>;
+ status = "okay";
+ fan@0 {
+ reg = <0x00>;
+ fan-tach-ch = /bits/ 8 <0x00 0x01>;
+ cooling-levels = <127 255>;
+ };
+ fan@1 {
+ reg = <0x01>;
+ fan-tach-ch = /bits/ 8 <0x02 0x03>;
+ cooling-levels = /bits/ 8 <127 255>;
+ };
+ fan@2 {
+ reg = <0x02>;
+ fan-tach-ch = /bits/ 8 <0x04 0x05>;
+ cooling-levels = /bits/ 8 <127 255>;
+ };
+ fan@3 {
+ reg = <0x03>;
+ fan-tach-ch = /bits/ 8 <0x06 0x07>;
+ cooling-levels = /bits/ 8 <127 255>;
+ };
+ fan@4 {
+ reg = <0x04>;
+ fan-tach-ch = /bits/ 8 <0x08 0x09>;
+ cooling-levels = /bits/ 8 <127 255>;
+ };
+ fan@5 {
+ reg = <0x05>;
+ fan-tach-ch = /bits/ 8 <0x0A 0x0B>;
+ cooling-levels = /bits/ 8 <127 255>;
+ };
+ fan@6 {
+ reg = <0x06>;
+ fan-tach-ch = /bits/ 8 <0x0C 0x0D>;
+ cooling-levels = /bits/ 8 <127 255>;
+ };
+ fan@7 {
+ reg = <0x07>;
+ fan-tach-ch = /bits/ 8 <0x0E 0x0F>;
+ cooling-levels = /bits/ 8 <127 255>;
+ };
+ };
+
+ peci: peci-bus@100000 {
+ cmd-timeout-ms = <1000>;
+ pull-down = <0>;
+ host-neg-bit-rate = <15>;
+ status = "okay";
+ intel-peci-dimmtemp@30 {
+ compatible = "intel,peci-client";
+ reg = <0x30>;
+ status = "okay";
+ };
+ intel-peci-dimmtemp@31 {
+ compatible = "intel,peci-client";
+ reg = <0x31>;
+ status = "okay";
+ };
+ };
+
+ spi0: spi@200000 {
+ cs-gpios = <&gpio6 11 GPIO_ACTIVE_LOW>;
+ status = "okay";
+ };
+
+ spi1: spi@201000 {
+ status = "okay";
+ };
+ };
+ };
+
+ pinctrl: pinctrl@f0800000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <
+ /******* RunBMC inside Module pins *******/
+ &gpio0ol_pins
+ &gpio1ol_pins
+ &gpio2ol_pins
+ &gpio3ol_pins
+ &gpio8o_pins
+ &gpio9ol_pins
+ &gpio12ol_pins
+ &gpio13ol_pins
+ &gpio14ol_pins
+ &gpio15ol_pins
+ &gpio37o_pins
+ &gpio38_pins
+ &gpio39_pins
+ &gpio94ol_pins
+ &gpio108ol_pins
+ &gpio109ol_pins
+ &gpio111ol_pins
+ &gpio112ol_pins
+ &gpio113ol_pins
+ &gpio208_pins
+ &gpio209ol_pins
+ &gpio210ol_pins
+ &gpio211ol_pins
+ &gpio212ol_pins
+ &gpio213ol_pins
+ &gpio214ol_pins
+ &gpio215ol_pins
+ &gpio216ol_pins
+ &gpio217ol_pins
+ /******* RunBMC outside Connector pins *******/
+ &gpio5_pins
+ &gpio6_pins
+ &gpio7_pins
+ &gpio10_pins
+ &gpio11_pins
+ &gpio20_pins
+ &gpio21_pins
+ &gpio22o_pins
+ &gpio23_pins
+ &gpio24_pins
+ &gpio25_pins
+ &gpio30_pins
+ &gpio31_pins
+ &gpio40o_pins
+ &gpio59_pins
+ &gpio76_pins
+ &gpio77_pins
+ &gpio78o_pins
+ &gpio79_pins
+ &gpio82_pins
+ &gpio83_pins
+ &gpio84_pins
+ &gpio85o_pins
+ &gpio86ol_pins
+ &gpio87_pins
+ &gpio88_pins
+ &gpio89_pins
+ &gpio90_pins
+ &gpio93_pins
+ &gpio114o_pins
+ &gpio115_pins
+ &gpio120_pins
+ &gpio121_pins
+ &gpio122_pins
+ &gpio123_pins
+ &gpio124_pins
+ &gpio125_pins
+ &gpio126_pins
+ &gpio127o_pins
+ &gpio136_pins
+ &gpio137_pins
+ &gpio138_pins
+ &gpio139_pins
+ &gpio140_pins
+ &gpio141_pins
+ &gpio142_pins
+ &gpio143_pins
+ &gpio144_pins
+ &gpio146_pins
+ &gpio145_pins
+ &gpio147_pins
+ &gpio153o_pins
+ &gpio155_pins
+ &gpio160o_pins
+ &gpio169o_pins
+ &gpio188o_pins
+ &gpio189_pins
+ &gpio196_pins
+ &gpio197_pins
+ &gpio198o_pins
+ &gpio199o_pins
+ &gpio200_pins
+ &gpio202_pins
+ &gpio203o_pins
+ &gpio224_pins
+ &gpio225ol_pins
+ &gpio226ol_pins
+ &gpio227ol_pins
+ &gpio228o_pins
+ &gpio229o_pins
+ &gpio230_pins
+ &gpio231o_pins
+ &ddc_pins
+ &wdog1_pins
+ &wdog2_pins
+ >;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ heartbeat {
+ label = "heartbeat";
+ gpios = <&gpio3 14 1>;
+ };
+
+ identify {
+ label = "identify";
+ gpios = <&gpio3 15 1>;
+ };
+ };
+
+ jtag {
+ compatible = "nuvoton,npcm750-jtag";
+ enable_pspi_jtag = <1>;
+ pspi-index = <2>;
+ tck {
+ label = "tck";
+ gpios = <&gpio0 19 0>; /* gpio19 */
+ regbase = <0xf0010000 0x1000>;
+ };
+
+ tdi {
+ label = "tdi";
+ gpios = <&gpio0 18 0>; /* gpio18 */
+ regbase = <0xf0010000 0x1000>;
+ };
+
+ tdo {
+ label = "tdo";
+ gpios = <&gpio0 17 0>; /* gpio17 */
+ regbase = <0xf0010000 0x1000>;
+ };
+ tms {
+ label = "tms";
+ gpios = <&gpio0 16 0>; /* gpio16 */
+ regbase = <0xf0010000 0x1000>;
+ };
+ };
+};
+
+&gcr {
+ serial_port_mux: mux-controller {
+ compatible = "mmio-mux";
+ #mux-control-cells = <1>;
+
+ mux-reg-masks = <0x38 0x07>;
+ idle-states = <6>;
+ };
+};
diff --git a/arch/arm/boot/dts/nuvoton-npcm750.dtsi b/arch/arm/boot/dts/nuvoton-npcm750.dtsi
index 6ac340533587..14b3d5b1206f 100644
--- a/arch/arm/boot/dts/nuvoton-npcm750.dtsi
+++ b/arch/arm/boot/dts/nuvoton-npcm750.dtsi
@@ -3,6 +3,7 @@
// Copyright 2018 Google, Inc.
#include "nuvoton-common-npcm7xx.dtsi"
+#include "nuvoton-npcm750-gpio.dtsi"
/ {
#address-cells = <1>;
@@ -17,7 +18,7 @@
cpu@0 {
device_type = "cpu";
compatible = "arm,cortex-a9";
- clocks = <&clk 0>;
+ clocks = <&clk NPCM7XX_CLK_CPU>;
clock-names = "clk_cpu";
reg = <0>;
next-level-cache = <&l2>;
@@ -26,19 +27,152 @@
cpu@1 {
device_type = "cpu";
compatible = "arm,cortex-a9";
- clocks = <&clk 0>;
+ clocks = <&clk NPCM7XX_CLK_CPU>;
clock-names = "clk_cpu";
reg = <1>;
next-level-cache = <&l2>;
};
};
+
soc {
timer@3fe600 {
compatible = "arm,cortex-a9-twd-timer";
reg = <0x3fe600 0x20>;
interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) |
IRQ_TYPE_LEVEL_HIGH)>;
- clocks = <&clk 5>;
+ clocks = <&clk NPCM7XX_CLK_AHB>;
+ };
+ };
+
+ ahb {
+ gmac1: eth@f0804000 {
+ device_type = "network";
+ compatible = "snps,dwmac";
+ reg = <0xf0804000 0x2000>;
+ interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "macirq";
+ ethernet = <1>;
+ clocks = <&clk_rg2refck>, <&clk NPCM7XX_CLK_AHB>;
+ clock-names = "stmmaceth", "clk_gmac";
+ pinctrl-names = "default";
+ pinctrl-0 = <&rg2_pins
+ &rg2mdio_pins>;
+ status = "disabled";
+ };
+
+ emc1: eth@f0826000 {
+ device_type = "network";
+ compatible = "nuvoton,npcm750-emc";
+ reg = <0xf0826000 0x1000>;
+ interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clk NPCM7XX_CLK_AHB>;
+ clock-names = "clk_emc";
+ pinctrl-names = "default";
+ pinctrl-0 = <&r2_pins
+ &r2err_pins
+ &r2md_pins>;
+ status = "disabled";
+ };
+
+ udc0:udc@f0830000 {
+ compatible = "nuvoton,npcm750-udc";
+ reg = <0xf0830000 0x1000
+ 0xfffd0000 0x800>;
+ interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ clocks = <&clk NPCM7XX_CLK_SU>;
+ clock-names = "clk_usb_bridge";
+ };
+
+ udc1:udc@f0831000 {
+ compatible = "nuvoton,npcm750-udc";
+ reg = <0xf0831000 0x1000
+ 0xfffd0800 0x800>;
+ interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ clocks = <&clk NPCM7XX_CLK_SU>;
+ clock-names = "clk_usb_bridge";
+ };
+
+ udc2:udc@f0832000 {
+ compatible = "nuvoton,npcm750-udc";
+ reg = <0xf0832000 0x1000
+ 0xfffd1000 0x800>;
+ interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ clocks = <&clk NPCM7XX_CLK_SU>;
+ clock-names = "clk_usb_bridge";
+ };
+
+ udc3:udc@f0833000 {
+ compatible = "nuvoton,npcm750-udc";
+ reg = <0xf0833000 0x1000
+ 0xfffd1800 0x800>;
+ interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ clocks = <&clk NPCM7XX_CLK_SU>;
+ clock-names = "clk_usb_bridge";
+ };
+
+ udc4:udc@f0834000 {
+ compatible = "nuvoton,npcm750-udc";
+ reg = <0xf0834000 0x1000
+ 0xfffd2000 0x800>;
+ interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ clocks = <&clk NPCM7XX_CLK_SU>;
+ clock-names = "clk_usb_bridge";
+ };
+
+ udc5:udc@f0835000 {
+ compatible = "nuvoton,npcm750-udc";
+ reg = <0xf0835000 0x1000
+ 0xfffd2800 0x800>;
+ interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ clocks = <&clk NPCM7XX_CLK_SU>;
+ clock-names = "clk_usb_bridge";
+ };
+
+ udc6:udc@f0836000 {
+ compatible = "nuvoton,npcm750-udc";
+ reg = <0xf0836000 0x1000
+ 0xfffd3000 0x800>;
+ interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ clocks = <&clk NPCM7XX_CLK_SU>;
+ clock-names = "clk_usb_bridge";
+ };
+
+ udc7:udc@f0837000 {
+ compatible = "nuvoton,npcm750-udc";
+ reg = <0xf0837000 0x1000
+ 0xfffd3800 0x800>;
+ interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ clocks = <&clk NPCM7XX_CLK_SU>;
+ clock-names = "clk_usb_bridge";
+ };
+
+ udc8:udc@f0838000 {
+ compatible = "nuvoton,npcm750-udc";
+ reg = <0xf0838000 0x1000
+ 0xfffd4000 0x800>;
+ interrupts = <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ clocks = <&clk NPCM7XX_CLK_SU>;
+ clock-names = "clk_usb_bridge";
+ };
+
+ udc9:udc@f0839000 {
+ compatible = "nuvoton,npcm750-udc";
+ reg = <0xf0839000 0x1000
+ 0xfffd4800 0x800>;
+ interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ clocks = <&clk NPCM7XX_CLK_SU>;
+ clock-names = "clk_usb_bridge";
};
};
};
diff --git a/arch/arm/boot/dts/openbmc-flash-layout-128.dtsi b/arch/arm/boot/dts/openbmc-flash-layout-128.dtsi
new file mode 100644
index 000000000000..05101a38c5bd
--- /dev/null
+++ b/arch/arm/boot/dts/openbmc-flash-layout-128.dtsi
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ u-boot@0 {
+ reg = <0x0 0xe0000>; // 896KB
+ label = "u-boot";
+ };
+
+ u-boot-env@e0000 {
+ reg = <0xe0000 0x20000>; // 128KB
+ label = "u-boot-env";
+ };
+
+ kernel@100000 {
+ reg = <0x100000 0x900000>; // 9MB
+ label = "kernel";
+ };
+
+ rofs@a00000 {
+ reg = <0xa00000 0x5600000>; // 86MB
+ label = "rofs";
+ };
+
+ rwfs@6000000 {
+ reg = <0x6000000 0x2000000>; // 32MB
+ label = "rwfs";
+ };
+};
diff --git a/arch/arm/configs/aspeed_g4_defconfig b/arch/arm/configs/aspeed_g4_defconfig
index 1857df992484..ffd45cc8f1b6 100644
--- a/arch/arm/configs/aspeed_g4_defconfig
+++ b/arch/arm/configs/aspeed_g4_defconfig
@@ -3,6 +3,8 @@ CONFIG_KERNEL_XZ=y
CONFIG_SYSVIPC=y
CONFIG_NO_HZ_IDLE=y
CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PSI=y
+CONFIG_PSI_DEFAULT_DISABLED=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=16
@@ -30,8 +32,6 @@ CONFIG_SECCOMP=y
# CONFIG_ATAGS is not set
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_ARM_APPENDED_DTB=y
-CONFIG_ARM_ATAG_DTB_COMPAT=y
CONFIG_KEXEC=y
CONFIG_FIRMWARE_MEMMAP=y
CONFIG_JUMP_LABEL=y
@@ -49,8 +49,16 @@ CONFIG_UNIX=y
CONFIG_UNIX_DIAG=y
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
CONFIG_SYN_COOKIES=y
# CONFIG_INET_DIAG is not set
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
CONFIG_NETFILTER=y
# CONFIG_NETFILTER_ADVANCED is not set
CONFIG_VLAN_8021Q=y
@@ -69,6 +77,7 @@ CONFIG_MTD_UBI=y
CONFIG_MTD_UBI_FASTMAP=y
CONFIG_MTD_UBI_BLOCK=y
CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_NBD=y
CONFIG_EEPROM_AT24=y
CONFIG_NETDEVICES=y
CONFIG_NETCONSOLE=y
@@ -90,6 +99,7 @@ CONFIG_FTGMAC100=y
# CONFIG_NET_VENDOR_MARVELL is not set
# CONFIG_NET_VENDOR_MELLANOX is not set
# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MICROCHIP is not set
# CONFIG_NET_VENDOR_MICROSEMI is not set
# CONFIG_NET_VENDOR_NATSEMI is not set
# CONFIG_NET_VENDOR_NETRONOME is not set
@@ -132,10 +142,12 @@ CONFIG_ASPEED_BT_IPMI_BMC=y
CONFIG_HW_RANDOM_TIMERIOMEM=y
# CONFIG_I2C_COMPAT is not set
CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_MUX=y
CONFIG_I2C_MUX_PCA9541=y
CONFIG_I2C_MUX_PCA954x=y
CONFIG_I2C_ASPEED=y
CONFIG_I2C_FSI=y
+CONFIG_SPI=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_ASPEED=y
@@ -146,6 +158,7 @@ CONFIG_SENSORS_ASPEED=y
CONFIG_SENSORS_IIO_HWMON=y
CONFIG_SENSORS_LM75=y
CONFIG_SENSORS_NCT7904=y
+CONFIG_SENSORS_OCC_P8_I2C=y
CONFIG_PMBUS=y
CONFIG_SENSORS_ADM1275=y
CONFIG_SENSORS_IBM_CFFPS=y
@@ -162,6 +175,7 @@ CONFIG_MEDIA_CAMERA_SUPPORT=y
CONFIG_V4L_PLATFORM_DRIVERS=y
CONFIG_VIDEO_ASPEED=y
CONFIG_DRM=y
+CONFIG_DRM_ASPEED_GFX=y
CONFIG_USB=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_DYNAMIC_MINORS=y
@@ -185,6 +199,12 @@ CONFIG_USB_CONFIGFS_F_LB_SS=y
CONFIG_USB_CONFIGFS_F_FS=y
CONFIG_USB_CONFIGFS_F_HID=y
CONFIG_USB_CONFIGFS_F_PRINTER=y
+CONFIG_MMC=y
+# CONFIG_PWRSEQ_EMMC is not set
+# CONFIG_PWRSEQ_SIMPLE is not set
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_OF_ASPEED=y
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
CONFIG_LEDS_CLASS_FLASH=y
@@ -216,7 +236,6 @@ CONFIG_FSI_MASTER_GPIO=y
CONFIG_FSI_MASTER_HUB=y
CONFIG_FSI_MASTER_AST_CF=y
CONFIG_FSI_SCOM=y
-CONFIG_FSI_SBEFIFO=y
CONFIG_FANOTIFY=y
CONFIG_OVERLAY_FS=y
CONFIG_TMPFS=y
@@ -231,7 +250,6 @@ CONFIG_SQUASHFS_ZSTD=y
# CONFIG_NETWORK_FILESYSTEMS is not set
CONFIG_HARDENED_USERCOPY=y
CONFIG_FORTIFY_SOURCE=y
-# CONFIG_CRYPTO_ECHAINIV is not set
CONFIG_CRYPTO_HMAC=y
CONFIG_CRYPTO_SHA256=y
CONFIG_CRYPTO_USER_API_HASH=y
diff --git a/arch/arm/configs/aspeed_g5_defconfig b/arch/arm/configs/aspeed_g5_defconfig
index b87508c7056c..ac70286e84ad 100644
--- a/arch/arm/configs/aspeed_g5_defconfig
+++ b/arch/arm/configs/aspeed_g5_defconfig
@@ -3,10 +3,15 @@ CONFIG_KERNEL_XZ=y
CONFIG_SYSVIPC=y
CONFIG_NO_HZ_IDLE=y
CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PSI=y
+CONFIG_PSI_DEFAULT_DISABLED=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=16
CONFIG_CGROUPS=y
+CONFIG_CGROUP_BPF=y
+CONFIG_NAMESPACES=y
+CONFIG_USER_NS=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_RD_BZIP2 is not set
# CONFIG_RD_LZO is not set
@@ -82,7 +87,13 @@ CONFIG_MTD_UBI=y
CONFIG_MTD_UBI_FASTMAP=y
CONFIG_MTD_UBI_BLOCK=y
CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_NBD=y
+CONFIG_MCTP_LPC=y
CONFIG_EEPROM_AT24=y
+CONFIG_EEPROM_AT25=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_VERITY=y
CONFIG_NETDEVICES=y
CONFIG_NETCONSOLE=y
# CONFIG_NET_VENDOR_ALACRITECH is not set
@@ -103,6 +114,7 @@ CONFIG_FTGMAC100=y
# CONFIG_NET_VENDOR_MARVELL is not set
# CONFIG_NET_VENDOR_MELLANOX is not set
# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MICROCHIP is not set
# CONFIG_NET_VENDOR_MICROSEMI is not set
# CONFIG_NET_VENDOR_NATSEMI is not set
# CONFIG_NET_VENDOR_NETRONOME is not set
@@ -152,20 +164,31 @@ CONFIG_I2C_MUX_PCA954x=y
CONFIG_I2C_ASPEED=y
CONFIG_I2C_FSI=y
CONFIG_SPI=y
+CONFIG_SPI_FSI=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_ASPEED=y
+CONFIG_GPIO_ASPEED_SGPIO=y
+CONFIG_GPIO_PCA953X=y
+CONFIG_GPIO_PCA953X_IRQ=y
CONFIG_W1=y
CONFIG_W1_MASTER_GPIO=y
CONFIG_W1_SLAVE_THERM=y
+CONFIG_SENSORS_ADT7475=y
CONFIG_SENSORS_ASPEED=y
CONFIG_SENSORS_IIO_HWMON=y
CONFIG_SENSORS_LM75=y
CONFIG_SENSORS_NCT7904=y
+CONFIG_SENSORS_OCC_P8_I2C=y
+CONFIG_SENSORS_OCC_P9_SBE=y
+CONFIG_SENSORS_PECI_CPUTEMP=y
+CONFIG_SENSORS_PECI_DIMMTEMP=y
CONFIG_PMBUS=y
CONFIG_SENSORS_ADM1275=y
CONFIG_SENSORS_IBM_CFFPS=y
CONFIG_SENSORS_IR35221=y
+CONFIG_SENSORS_IR38064=y
+CONFIG_SENSORS_ISL68137=y
CONFIG_SENSORS_LM25066=y
CONFIG_SENSORS_MAX31785=y
CONFIG_SENSORS_UCD9000=y
@@ -186,22 +209,10 @@ CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_ROOT_HUB_TT=y
CONFIG_USB_EHCI_HCD_PLATFORM=y
CONFIG_USB_GADGET=y
-CONFIG_U_SERIAL_CONSOLE=y
CONFIG_USB_ASPEED_VHUB=y
CONFIG_USB_CONFIGFS=y
-CONFIG_USB_CONFIGFS_SERIAL=y
-CONFIG_USB_CONFIGFS_ACM=y
-CONFIG_USB_CONFIGFS_OBEX=y
-CONFIG_USB_CONFIGFS_NCM=y
-CONFIG_USB_CONFIGFS_ECM=y
-CONFIG_USB_CONFIGFS_ECM_SUBSET=y
-CONFIG_USB_CONFIGFS_RNDIS=y
-CONFIG_USB_CONFIGFS_EEM=y
CONFIG_USB_CONFIGFS_MASS_STORAGE=y
-CONFIG_USB_CONFIGFS_F_LB_SS=y
-CONFIG_USB_CONFIGFS_F_FS=y
CONFIG_USB_CONFIGFS_F_HID=y
-CONFIG_USB_CONFIGFS_F_PRINTER=y
CONFIG_MMC=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
@@ -217,6 +228,7 @@ CONFIG_LEDS_TRIGGER_TIMER=y
CONFIG_LEDS_TRIGGER_HEARTBEAT=y
CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
CONFIG_EDAC=y
+# CONFIG_EDAC_LEGACY_SYSFS is not set
CONFIG_EDAC_ASPEED=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_DS1307=y
@@ -228,17 +240,22 @@ CONFIG_RTC_DRV_ASPEED=y
CONFIG_ASPEED_LPC_CTRL=y
CONFIG_ASPEED_LPC_SNOOP=y
CONFIG_ASPEED_P2A_CTRL=y
+CONFIG_ASPEED_XDMA=y
CONFIG_IIO=y
CONFIG_ASPEED_ADC=y
CONFIG_MAX1363=y
CONFIG_BMP280=y
+CONFIG_DPS310=y
CONFIG_RAS=y
CONFIG_FSI=y
CONFIG_FSI_MASTER_GPIO=y
CONFIG_FSI_MASTER_HUB=y
CONFIG_FSI_MASTER_AST_CF=y
+CONFIG_FSI_MASTER_ASPEED=y
CONFIG_FSI_SCOM=y
CONFIG_FSI_SBEFIFO=y
+CONFIG_FSI_OCC=y
+CONFIG_EXT4_FS=y
CONFIG_FANOTIFY=y
CONFIG_OVERLAY_FS=y
CONFIG_TMPFS=y
@@ -269,12 +286,14 @@ CONFIG_DEBUG_INFO_DWARF4=y
CONFIG_GDB_SCRIPTS=y
CONFIG_STRIP_ASM_SYMS=y
CONFIG_SOFTLOCKUP_DETECTOR=y
-# CONFIG_DETECT_HUNG_TASK is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC=y
CONFIG_WQ_WATCHDOG=y
CONFIG_PANIC_ON_OOPS=y
CONFIG_PANIC_TIMEOUT=-1
# CONFIG_SCHED_DEBUG is not set
CONFIG_SCHED_STACK_END_CHECK=y
+CONFIG_DEBUG_LIST=y
CONFIG_FUNCTION_TRACER=y
# CONFIG_RUNTIME_TESTING_MENU is not set
CONFIG_DEBUG_WX=y
diff --git a/arch/arm/configs/npcm7xx_defconfig b/arch/arm/configs/npcm7xx_defconfig
new file mode 100644
index 000000000000..62aaffdba4dd
--- /dev/null
+++ b/arch/arm/configs/npcm7xx_defconfig
@@ -0,0 +1,127 @@
+CONFIG_KERNEL_XZ=y
+CONFIG_SYSVIPC=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_LOG_BUF_SHIFT=21
+CONFIG_CGROUPS=y
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_EMBEDDED=y
+CONFIG_SLAB=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_DEFAULT_DEADLINE=y
+CONFIG_ARCH_NPCM=y
+CONFIG_ARCH_NPCM7XX=y
+CONFIG_SMP=y
+CONFIG_VMSPLIT_3G_OPT=y
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_BINFMT_MISC=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_MTD=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_RAM=y
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_M25P80=y
+CONFIG_MTD_SPI_NOR=y
+CONFIG_SPI_NPCM_FIU=y
+CONFIG_OF_OVERLAY=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_NBD=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=1
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_NPCM7XX_LPC_BPC=y
+CONFIG_NPCM7XX_PCI_MBOX=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_NETDEVICES=y
+CONFIG_NPCM7XX_EMC_ETH=y
+CONFIG_STMMAC_ETH=y
+CONFIG_BROADCOM_PHY=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_NPCM750_OTP=y
+CONFIG_NPCM750_OTP_WRITE_ENABLE=y
+CONFIG_NPCM7XX_KCS_IPMI_BMC=y
+CONFIG_HW_RANDOM=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_NPCM7XX=y
+CONFIG_I2C_SLAVE_EEPROM=y
+CONFIG_SPI=y
+CONFIG_SPI_NPCM_PSPI=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_GENERIC_PLATFORM=y
+CONFIG_SENSORS_LM75=y
+CONFIG_SENSORS_NPCM7XX=y
+CONFIG_SENSORS_TMP102=y
+CONFIG_WATCHDOG=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_NPCM750_VCD=y
+CONFIG_NPCM750_ECE=y
+CONFIG_USB_HIDDEV=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_CHIPIDEA=y
+CONFIG_USB_CHIPIDEA_UDC=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_NPCMX50_USB2=y
+CONFIG_USB_CONFIGFS=y
+CONFIG_USB_CONFIGFS_F_HID=y
+CONFIG_USB_MASS_STORAGE=m
+CONFIG_USB_EDM_KBD_MOUSE=m
+CONFIG_MMC=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_NPCM750=y
+CONFIG_IIO=y
+CONFIG_NPCM_ADC=y
+CONFIG_IIO_MUX=y
+CONFIG_MUX_MMIO=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_ROMFS_FS=y
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
+CONFIG_CIFS=y
+CONFIG_CIFS_XATTR=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_REDUCED=y
+CONFIG_READABLE_ASM=y
+CONFIG_DEBUG_SECTION_MISMATCH=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_FUNCTION_TRACER=y
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_CRC32C=y
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_LZO=y
+CONFIG_CRYPTO_USER_API_SKCIPHER=y
+CONFIG_CRYPTO_DEV_NPCMX50=y
+CONFIG_ARM_CRYPTO=y
+CONFIG_PECI=y
+CONFIG_PECI_NPCM=y
+CONFIG_MFD_INTEL_PECI_CLIENT=y
+CONFIG_SENSORS_PECI_CPUTEMP=y
+CONFIG_SENSORS_PECI_DIMMTEMP=y
diff --git a/arch/arm/mach-aspeed/Kconfig b/arch/arm/mach-aspeed/Kconfig
index e8d6e9957d65..693cbddae3d8 100644
--- a/arch/arm/mach-aspeed/Kconfig
+++ b/arch/arm/mach-aspeed/Kconfig
@@ -25,6 +25,7 @@ config MACH_ASPEED_G4
config MACH_ASPEED_G5
bool "Aspeed SoC 5th Generation"
+ # This implies ARMv6K which covers the ARM1176
depends on ARCH_MULTI_V6
select PINCTRL_ASPEED_G5
select FTTMR010_TIMER
diff --git a/crypto/asymmetric_keys/asym_tpm.c b/crypto/asymmetric_keys/asym_tpm.c
index 5154e280ada2..659e6f81b10a 100644
--- a/crypto/asymmetric_keys/asym_tpm.c
+++ b/crypto/asymmetric_keys/asym_tpm.c
@@ -31,7 +31,7 @@
/*
* Load a TPM key from the blob provided by userspace
*/
-static int tpm_loadkey2(struct tpm_buf *tb,
+static int tpm_loadkey2(struct tpm1_buf *tb,
uint32_t keyhandle, unsigned char *keyauth,
const unsigned char *keyblob, int keybloblen,
uint32_t *newhandle)
@@ -99,7 +99,7 @@ static int tpm_loadkey2(struct tpm_buf *tb,
/*
* Execute the FlushSpecific TPM command
*/
-static int tpm_flushspecific(struct tpm_buf *tb, uint32_t handle)
+static int tpm_flushspecific(struct tpm1_buf *tb, uint32_t handle)
{
INIT_BUF(tb);
store16(tb, TPM_TAG_RQU_COMMAND);
@@ -115,7 +115,7 @@ static int tpm_flushspecific(struct tpm_buf *tb, uint32_t handle)
* Decrypt a blob provided by userspace using a specific key handle.
* The handle is a well known handle or previously loaded by e.g. LoadKey2
*/
-static int tpm_unbind(struct tpm_buf *tb,
+static int tpm_unbind(struct tpm1_buf *tb,
uint32_t keyhandle, unsigned char *keyauth,
const unsigned char *blob, uint32_t bloblen,
void *out, uint32_t outlen)
@@ -201,7 +201,7 @@ static int tpm_unbind(struct tpm_buf *tb,
* up to key_length_in_bytes - 11 and not be limited to size 20 like the
* TPM_SS_RSASSAPKCS1v15_SHA1 signature scheme.
*/
-static int tpm_sign(struct tpm_buf *tb,
+static int tpm_sign(struct tpm1_buf *tb,
uint32_t keyhandle, unsigned char *keyauth,
const unsigned char *blob, uint32_t bloblen,
void *out, uint32_t outlen)
@@ -520,7 +520,7 @@ static int tpm_key_decrypt(struct tpm_key *tk,
struct kernel_pkey_params *params,
const void *in, void *out)
{
- struct tpm_buf *tb;
+ struct tpm1_buf *tb;
uint32_t keyhandle;
uint8_t srkauth[SHA1_DIGEST_SIZE];
uint8_t keyauth[SHA1_DIGEST_SIZE];
@@ -644,7 +644,7 @@ static int tpm_key_sign(struct tpm_key *tk,
struct kernel_pkey_params *params,
const void *in, void *out)
{
- struct tpm_buf *tb;
+ struct tpm1_buf *tb;
uint32_t keyhandle;
uint8_t srkauth[SHA1_DIGEST_SIZE];
uint8_t keyauth[SHA1_DIGEST_SIZE];
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 8befa53f43be..4322efa37732 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -228,4 +228,6 @@ source "drivers/interconnect/Kconfig"
source "drivers/counter/Kconfig"
+source "drivers/peci/Kconfig"
+
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index aaef17cc6512..82f78cfedf69 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -186,3 +186,4 @@ obj-$(CONFIG_SIOX) += siox/
obj-$(CONFIG_GNSS) += gnss/
obj-$(CONFIG_INTERCONNECT) += interconnect/
obj-$(CONFIG_COUNTER) += counter/
+obj-$(CONFIG_PECI) += peci/
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index df0fc997dc3e..49c4db8c8813 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -16,6 +16,15 @@ config DEVMEM
memory.
When in doubt, say "Y".
+config DEVMEM_BOOTPARAM
+ bool "mem.devmem boot parameter"
+ depends on DEVMEM
+ default n
+ help
+ This option adds a 'mem.devmem' kernel parameter which activates
+ the /dev/mem device when enabled.
+ When in doubt, say "N".
+
config DEVKMEM
bool "/dev/kmem virtual device support"
# On arm64, VMALLOC_START < PAGE_OFFSET, which confuses kmem read/write
diff --git a/drivers/char/ipmi/bt-bmc.c b/drivers/char/ipmi/bt-bmc.c
index 40b9927c072c..0e600449931b 100644
--- a/drivers/char/ipmi/bt-bmc.c
+++ b/drivers/char/ipmi/bt-bmc.c
@@ -513,6 +513,7 @@ static int bt_bmc_remove(struct platform_device *pdev)
static const struct of_device_id bt_bmc_match[] = {
{ .compatible = "aspeed,ast2400-ibt-bmc" },
{ .compatible = "aspeed,ast2500-ibt-bmc" },
+ { .compatible = "aspeed,ast2600-ibt-bmc" },
{ },
};
diff --git a/drivers/char/ipmi/ipmb_dev_int.c b/drivers/char/ipmi/ipmb_dev_int.c
index 09e3e25562a8..11efb09659ba 100644
--- a/drivers/char/ipmi/ipmb_dev_int.c
+++ b/drivers/char/ipmi/ipmb_dev_int.c
@@ -19,7 +19,7 @@
#include <linux/spinlock.h>
#include <linux/wait.h>
-#define MAX_MSG_LEN 128
+#define MAX_MSG_LEN 240
#define IPMB_REQUEST_LEN_MIN 7
#define NETFN_RSP_BIT_MASK 0x4
#define REQUEST_QUEUE_MAX_LEN 256
@@ -63,6 +63,7 @@ struct ipmb_dev {
spinlock_t lock;
wait_queue_head_t wait_queue;
struct mutex file_mutex;
+ bool is_i2c_protocol;
};
static inline struct ipmb_dev *to_ipmb_dev(struct file *file)
@@ -112,6 +113,25 @@ static ssize_t ipmb_read(struct file *file, char __user *buf, size_t count,
return ret < 0 ? ret : count;
}
+static int ipmb_i2c_write(struct i2c_client *client, u8 *msg, u8 addr)
+{
+ struct i2c_msg i2c_msg;
+
+ /*
+ * subtract 1 byte (rq_sa) from the length of the msg passed to
+ * raw i2c_transfer
+ */
+ i2c_msg.len = msg[IPMB_MSG_LEN_IDX] - 1;
+
+ /* Assign message to buffer except first 2 bytes (length and address) */
+ i2c_msg.buf = msg + 2;
+
+ i2c_msg.addr = addr;
+ i2c_msg.flags = client->flags & I2C_CLIENT_PEC;
+
+ return i2c_transfer(client->adapter, &i2c_msg, 1);
+}
+
static ssize_t ipmb_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
@@ -133,8 +153,11 @@ static ssize_t ipmb_write(struct file *file, const char __user *buf,
rq_sa = GET_7BIT_ADDR(msg[RQ_SA_8BIT_IDX]);
netf_rq_lun = msg[NETFN_LUN_IDX];
- if (!(netf_rq_lun & NETFN_RSP_BIT_MASK))
- return -EINVAL;
+ /* Check i2c block transfer vs smbus */
+ if (ipmb_dev->is_i2c_protocol) {
+ ret = ipmb_i2c_write(ipmb_dev->client, msg, rq_sa);
+ return (ret == 1) ? count : ret;
+ }
/*
* subtract rq_sa and netf_rq_lun from the length of the msg passed to
@@ -203,25 +226,16 @@ static u8 ipmb_verify_checksum1(struct ipmb_dev *ipmb_dev, u8 rs_sa)
ipmb_dev->request.checksum1);
}
-static bool is_ipmb_request(struct ipmb_dev *ipmb_dev, u8 rs_sa)
+/*
+ * Verify if message has proper ipmb header with minimum length
+ * and correct checksum byte.
+ */
+static bool is_ipmb_msg(struct ipmb_dev *ipmb_dev, u8 rs_sa)
{
- if (ipmb_dev->msg_idx >= IPMB_REQUEST_LEN_MIN) {
- if (ipmb_verify_checksum1(ipmb_dev, rs_sa))
- return false;
+ if ((ipmb_dev->msg_idx >= IPMB_REQUEST_LEN_MIN) &&
+ (!ipmb_verify_checksum1(ipmb_dev, rs_sa)))
+ return true;
- /*
- * Check whether this is an IPMB request or
- * response.
- * The 6 MSB of netfn_rs_lun are dedicated to the netfn
- * while the remaining bits are dedicated to the lun.
- * If the LSB of the netfn is cleared, it is associated
- * with an IPMB request.
- * If the LSB of the netfn is set, it is associated with
- * an IPMB response.
- */
- if (!(ipmb_dev->request.netfn_rs_lun & NETFN_RSP_BIT_MASK))
- return true;
- }
return false;
}
@@ -273,8 +287,7 @@ static int ipmb_slave_cb(struct i2c_client *client,
case I2C_SLAVE_STOP:
ipmb_dev->request.len = ipmb_dev->msg_idx;
-
- if (is_ipmb_request(ipmb_dev, GET_8BIT_ADDR(client->addr)))
+ if (is_ipmb_msg(ipmb_dev, GET_8BIT_ADDR(client->addr)))
ipmb_handle_request(ipmb_dev);
break;
@@ -315,6 +328,9 @@ static int ipmb_probe(struct i2c_client *client,
if (ret)
return ret;
+ ipmb_dev->is_i2c_protocol
+ = device_property_read_bool(&client->dev, "i2c-protocol");
+
ipmb_dev->client = client;
i2c_set_clientdata(client, ipmb_dev);
ret = i2c_slave_register(client, ipmb_slave_cb);
diff --git a/drivers/char/ipmi/kcs_bmc_aspeed.c b/drivers/char/ipmi/kcs_bmc_aspeed.c
index 3c955946e647..a0a8bb89c9b3 100644
--- a/drivers/char/ipmi/kcs_bmc_aspeed.c
+++ b/drivers/char/ipmi/kcs_bmc_aspeed.c
@@ -301,6 +301,7 @@ static int aspeed_kcs_remove(struct platform_device *pdev)
static const struct of_device_id ast_kcs_bmc_match[] = {
{ .compatible = "aspeed,ast2400-kcs-bmc" },
{ .compatible = "aspeed,ast2500-kcs-bmc" },
+ { .compatible = "aspeed,ast2600-kcs-bmc" },
{ }
};
MODULE_DEVICE_TABLE(of, ast_kcs_bmc_match);
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 6b56bff9b68c..06611d177d4d 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -10,6 +10,7 @@
*/
#include <linux/mm.h>
+#include <linux/moduleparam.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
@@ -994,6 +995,12 @@ static char *mem_devnode(struct device *dev, umode_t *mode)
return NULL;
}
+#ifdef CONFIG_DEVMEM_BOOTPARAM
+static bool devmem;
+module_param(devmem, bool, 0444);
+MODULE_PARM_DESC(devmem, "kernel parameter to activate /dev/mem");
+#endif
+
static struct class *mem_class;
static int devmem_fs_init_fs_context(struct fs_context *fc)
@@ -1054,6 +1061,10 @@ static int __init chr_dev_init(void)
if (!devlist[minor].name)
continue;
+#ifdef CONFIG_DEVMEM_BOOTPARAM
+ if (minor == DEVMEM_MINOR && !devmem)
+ continue;
+#endif
/*
* Create /dev/port?
*/
diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
index 9c37047f4b56..eccc38fccd58 100644
--- a/drivers/char/tpm/Kconfig
+++ b/drivers/char/tpm/Kconfig
@@ -67,6 +67,18 @@ config TCG_TIS_SPI
within Linux. To compile this driver as a module, choose M here;
the module will be called tpm_tis_spi.
+config TCG_TIS_I2C
+ tristate "TPM I2C Interface Specification"
+ depends on I2C
+ depends on CRC_CCITT
+ select TCG_TIS_CORE
+ ---help---
+ If you have a TPM security chip which is connected to a regular
+ I2C master (i.e. most embedded platforms) that is compliant with the
+ TCG TPM I2C Interface Specification say Yes and it will be accessible from
+ within Linux. To compile this driver as a module, choose M here;
+ the module will be called tpm_tis_i2c.
+
config TCG_TIS_I2C_ATMEL
tristate "TPM Interface Specification 1.2 Interface (I2C - Atmel)"
depends on I2C
diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
index c354cdff9c62..c969e4250a1d 100644
--- a/drivers/char/tpm/Makefile
+++ b/drivers/char/tpm/Makefile
@@ -22,6 +22,7 @@ tpm-$(CONFIG_OF) += eventlog/of.o
obj-$(CONFIG_TCG_TIS_CORE) += tpm_tis_core.o
obj-$(CONFIG_TCG_TIS) += tpm_tis.o
obj-$(CONFIG_TCG_TIS_SPI) += tpm_tis_spi.o
+obj-$(CONFIG_TCG_TIS_I2C) += tpm_tis_i2c.o
obj-$(CONFIG_TCG_TIS_I2C_ATMEL) += tpm_i2c_atmel.o
obj-$(CONFIG_TCG_TIS_I2C_INFINEON) += tpm_i2c_infineon.o
obj-$(CONFIG_TCG_TIS_I2C_NUVOTON) += tpm_i2c_nuvoton.o
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 218cb496222a..a9f5f2cd7056 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -25,7 +25,6 @@
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/tpm.h>
-#include <linux/highmem.h>
#include <linux/tpm_eventlog.h>
#ifdef CONFIG_X86
@@ -58,123 +57,6 @@ enum tpm_addr {
#define TPM_ERR_DISABLED 0x7
#define TPM_ERR_INVALID_POSTINIT 38
-#define TPM_HEADER_SIZE 10
-
-enum tpm2_const {
- TPM2_PLATFORM_PCR = 24,
- TPM2_PCR_SELECT_MIN = ((TPM2_PLATFORM_PCR + 7) / 8),
-};
-
-enum tpm2_timeouts {
- TPM2_TIMEOUT_A = 750,
- TPM2_TIMEOUT_B = 2000,
- TPM2_TIMEOUT_C = 200,
- TPM2_TIMEOUT_D = 30,
- TPM2_DURATION_SHORT = 20,
- TPM2_DURATION_MEDIUM = 750,
- TPM2_DURATION_LONG = 2000,
- TPM2_DURATION_LONG_LONG = 300000,
- TPM2_DURATION_DEFAULT = 120000,
-};
-
-enum tpm2_structures {
- TPM2_ST_NO_SESSIONS = 0x8001,
- TPM2_ST_SESSIONS = 0x8002,
-};
-
-/* Indicates from what layer of the software stack the error comes from */
-#define TSS2_RC_LAYER_SHIFT 16
-#define TSS2_RESMGR_TPM_RC_LAYER (11 << TSS2_RC_LAYER_SHIFT)
-
-enum tpm2_return_codes {
- TPM2_RC_SUCCESS = 0x0000,
- TPM2_RC_HASH = 0x0083, /* RC_FMT1 */
- TPM2_RC_HANDLE = 0x008B,
- TPM2_RC_INITIALIZE = 0x0100, /* RC_VER1 */
- TPM2_RC_FAILURE = 0x0101,
- TPM2_RC_DISABLED = 0x0120,
- TPM2_RC_COMMAND_CODE = 0x0143,
- TPM2_RC_TESTING = 0x090A, /* RC_WARN */
- TPM2_RC_REFERENCE_H0 = 0x0910,
- TPM2_RC_RETRY = 0x0922,
-};
-
-enum tpm2_command_codes {
- TPM2_CC_FIRST = 0x011F,
- TPM2_CC_HIERARCHY_CONTROL = 0x0121,
- TPM2_CC_HIERARCHY_CHANGE_AUTH = 0x0129,
- TPM2_CC_CREATE_PRIMARY = 0x0131,
- TPM2_CC_SEQUENCE_COMPLETE = 0x013E,
- TPM2_CC_SELF_TEST = 0x0143,
- TPM2_CC_STARTUP = 0x0144,
- TPM2_CC_SHUTDOWN = 0x0145,
- TPM2_CC_NV_READ = 0x014E,
- TPM2_CC_CREATE = 0x0153,
- TPM2_CC_LOAD = 0x0157,
- TPM2_CC_SEQUENCE_UPDATE = 0x015C,
- TPM2_CC_UNSEAL = 0x015E,
- TPM2_CC_CONTEXT_LOAD = 0x0161,
- TPM2_CC_CONTEXT_SAVE = 0x0162,
- TPM2_CC_FLUSH_CONTEXT = 0x0165,
- TPM2_CC_VERIFY_SIGNATURE = 0x0177,
- TPM2_CC_GET_CAPABILITY = 0x017A,
- TPM2_CC_GET_RANDOM = 0x017B,
- TPM2_CC_PCR_READ = 0x017E,
- TPM2_CC_PCR_EXTEND = 0x0182,
- TPM2_CC_EVENT_SEQUENCE_COMPLETE = 0x0185,
- TPM2_CC_HASH_SEQUENCE_START = 0x0186,
- TPM2_CC_CREATE_LOADED = 0x0191,
- TPM2_CC_LAST = 0x0193, /* Spec 1.36 */
-};
-
-enum tpm2_permanent_handles {
- TPM2_RS_PW = 0x40000009,
-};
-
-enum tpm2_capabilities {
- TPM2_CAP_HANDLES = 1,
- TPM2_CAP_COMMANDS = 2,
- TPM2_CAP_PCRS = 5,
- TPM2_CAP_TPM_PROPERTIES = 6,
-};
-
-enum tpm2_properties {
- TPM_PT_TOTAL_COMMANDS = 0x0129,
-};
-
-enum tpm2_startup_types {
- TPM2_SU_CLEAR = 0x0000,
- TPM2_SU_STATE = 0x0001,
-};
-
-enum tpm2_cc_attrs {
- TPM2_CC_ATTR_CHANDLES = 25,
- TPM2_CC_ATTR_RHANDLE = 28,
-};
-
-#define TPM_VID_INTEL 0x8086
-#define TPM_VID_WINBOND 0x1050
-#define TPM_VID_STM 0x104A
-
-enum tpm_chip_flags {
- TPM_CHIP_FLAG_TPM2 = BIT(1),
- TPM_CHIP_FLAG_IRQ = BIT(2),
- TPM_CHIP_FLAG_VIRTUAL = BIT(3),
- TPM_CHIP_FLAG_HAVE_TIMEOUTS = BIT(4),
- TPM_CHIP_FLAG_ALWAYS_POWERED = BIT(5),
-};
-
-#define to_tpm_chip(d) container_of(d, struct tpm_chip, dev)
-
-struct tpm_header {
- __be16 tag;
- __be32 length;
- union {
- __be32 ordinal;
- __be32 return_code;
- };
-} __packed;
-
#define TPM_TAG_RQU_COMMAND 193
struct stclear_flags_t {
@@ -274,102 +156,6 @@ enum tpm_sub_capabilities {
* compiler warnings about stack frame size. */
#define TPM_MAX_RNG_DATA 128
-/* A string buffer type for constructing TPM commands. This is based on the
- * ideas of string buffer code in security/keys/trusted.h but is heap based
- * in order to keep the stack usage minimal.
- */
-
-enum tpm_buf_flags {
- TPM_BUF_OVERFLOW = BIT(0),
-};
-
-struct tpm_buf {
- struct page *data_page;
- unsigned int flags;
- u8 *data;
-};
-
-static inline void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal)
-{
- struct tpm_header *head = (struct tpm_header *)buf->data;
-
- head->tag = cpu_to_be16(tag);
- head->length = cpu_to_be32(sizeof(*head));
- head->ordinal = cpu_to_be32(ordinal);
-}
-
-static inline int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal)
-{
- buf->data_page = alloc_page(GFP_HIGHUSER);
- if (!buf->data_page)
- return -ENOMEM;
-
- buf->flags = 0;
- buf->data = kmap(buf->data_page);
- tpm_buf_reset(buf, tag, ordinal);
- return 0;
-}
-
-static inline void tpm_buf_destroy(struct tpm_buf *buf)
-{
- kunmap(buf->data_page);
- __free_page(buf->data_page);
-}
-
-static inline u32 tpm_buf_length(struct tpm_buf *buf)
-{
- struct tpm_header *head = (struct tpm_header *)buf->data;
-
- return be32_to_cpu(head->length);
-}
-
-static inline u16 tpm_buf_tag(struct tpm_buf *buf)
-{
- struct tpm_header *head = (struct tpm_header *)buf->data;
-
- return be16_to_cpu(head->tag);
-}
-
-static inline void tpm_buf_append(struct tpm_buf *buf,
- const unsigned char *new_data,
- unsigned int new_len)
-{
- struct tpm_header *head = (struct tpm_header *)buf->data;
- u32 len = tpm_buf_length(buf);
-
- /* Return silently if overflow has already happened. */
- if (buf->flags & TPM_BUF_OVERFLOW)
- return;
-
- if ((len + new_len) > PAGE_SIZE) {
- WARN(1, "tpm_buf: overflow\n");
- buf->flags |= TPM_BUF_OVERFLOW;
- return;
- }
-
- memcpy(&buf->data[len], new_data, new_len);
- head->length = cpu_to_be32(len + new_len);
-}
-
-static inline void tpm_buf_append_u8(struct tpm_buf *buf, const u8 value)
-{
- tpm_buf_append(buf, &value, 1);
-}
-
-static inline void tpm_buf_append_u16(struct tpm_buf *buf, const u16 value)
-{
- __be16 value2 = cpu_to_be16(value);
-
- tpm_buf_append(buf, (u8 *) &value2, 2);
-}
-
-static inline void tpm_buf_append_u32(struct tpm_buf *buf, const u32 value)
-{
- __be32 value2 = cpu_to_be32(value);
-
- tpm_buf_append(buf, (u8 *) &value2, 4);
-}
-
extern struct class *tpm_class;
extern struct class *tpmrm_class;
extern dev_t tpm_devt;
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
index 2f8026b71933..185d1711c953 100644
--- a/drivers/char/tpm/tpm2-cmd.c
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -1033,6 +1033,10 @@ int tpm2_auto_startup(struct tpm_chip *chip)
goto out;
rc = tpm2_do_selftest(chip);
+
+ if ((rc == TPM2_RC_UPGRADE) || (rc == TPM2_RC_COMMAND_CODE))
+ return 0;
+
if (rc && rc != TPM2_RC_INITIALIZE)
goto out;
diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c
index 63f6bed78d89..a568ae4cef1f 100644
--- a/drivers/char/tpm/tpm_tis_core.c
+++ b/drivers/char/tpm/tpm_tis_core.c
@@ -44,9 +44,10 @@ static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask,
return false;
}
-static int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask,
- unsigned long timeout, wait_queue_head_t *queue,
- bool check_cancel)
+static int wait_for_tpm_stat_result(struct tpm_chip *chip, u8 mask,
+ u8 mask_result, unsigned long timeout,
+ wait_queue_head_t *queue,
+ bool check_cancel)
{
unsigned long stop;
long rc;
@@ -55,7 +56,7 @@ static int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask,
/* check current status */
status = chip->ops->status(chip);
- if ((status & mask) == mask)
+ if ((status & mask) == mask_result)
return 0;
stop = jiffies + timeout;
@@ -83,7 +84,7 @@ again:
usleep_range(TPM_TIMEOUT_USECS_MIN,
TPM_TIMEOUT_USECS_MAX);
status = chip->ops->status(chip);
- if ((status & mask) == mask)
+ if ((status & mask) == mask_result)
return 0;
} while (time_before(jiffies, stop));
}
@@ -242,6 +243,15 @@ static u8 tpm_tis_status(struct tpm_chip *chip)
return status;
}
+static bool tpm_tis_check_data(struct tpm_chip *chip, const u8 *buf, size_t len)
+{
+ struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
+
+ if (priv->phy_ops->check_data)
+ return priv->phy_ops->check_data(priv, buf, len);
+ return true;
+}
+
static void tpm_tis_ready(struct tpm_chip *chip)
{
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
@@ -281,10 +291,11 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
int size = 0, burstcnt, rc;
while (size < count) {
- rc = wait_for_tpm_stat(chip,
- TPM_STS_DATA_AVAIL | TPM_STS_VALID,
- chip->timeout_c,
- &priv->read_queue, true);
+ rc = wait_for_tpm_stat_result(chip,
+ TPM_STS_DATA_AVAIL | TPM_STS_VALID,
+ TPM_STS_DATA_AVAIL | TPM_STS_VALID,
+ chip->timeout_c,
+ &priv->read_queue, true);
if (rc < 0)
return rc;
burstcnt = get_burstcount(chip);
@@ -308,47 +319,60 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
{
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
int size = 0;
- int status;
+ int status, i;
u32 expected;
+ bool check_data = false;
- if (count < TPM_HEADER_SIZE) {
- size = -EIO;
- goto out;
- }
+ for (i = 0; i < TPM_RETRY; i++) {
+ if (count < TPM_HEADER_SIZE) {
+ size = -EIO;
+ goto out;
+ }
- size = recv_data(chip, buf, TPM_HEADER_SIZE);
- /* read first 10 bytes, including tag, paramsize, and result */
- if (size < TPM_HEADER_SIZE) {
- dev_err(&chip->dev, "Unable to read header\n");
- goto out;
- }
+ size = recv_data(chip, buf, TPM_HEADER_SIZE);
+ /* read first 10 bytes, including tag, paramsize, and result */
+ if (size < TPM_HEADER_SIZE) {
+ dev_err(&chip->dev, "Unable to read header\n");
+ goto out;
+ }
- expected = be32_to_cpu(*(__be32 *) (buf + 2));
- if (expected > count || expected < TPM_HEADER_SIZE) {
- size = -EIO;
- goto out;
- }
+ expected = be32_to_cpu(*(__be32 *) (buf + 2));
+ if (expected > count || expected < TPM_HEADER_SIZE) {
+ size = -EIO;
+ goto out;
+ }
- size += recv_data(chip, &buf[TPM_HEADER_SIZE],
- expected - TPM_HEADER_SIZE);
- if (size < expected) {
- dev_err(&chip->dev, "Unable to read remainder of result\n");
- size = -ETIME;
- goto out;
- }
+ size += recv_data(chip, &buf[TPM_HEADER_SIZE],
+ expected - TPM_HEADER_SIZE);
+ if (size < expected) {
+ dev_err(&chip->dev, "Unable to read remainder of result\n");
+ size = -ETIME;
+ goto out;
+ }
- if (wait_for_tpm_stat(chip, TPM_STS_VALID, chip->timeout_c,
- &priv->int_queue, false) < 0) {
- size = -ETIME;
- goto out;
+ if (wait_for_tpm_stat_result(chip, TPM_STS_VALID,
+ TPM_STS_VALID, chip->timeout_c,
+ &priv->int_queue, false) < 0) {
+ size = -ETIME;
+ goto out;
+ }
+
+ status = tpm_tis_status(chip);
+ if (status & TPM_STS_DATA_AVAIL) { /* retry? */
+ dev_err(&chip->dev, "Error left over data\n");
+ size = -EIO;
+ goto out;
+ }
+
+ check_data = tpm_tis_check_data(chip, buf, size);
+ if (!check_data)
+ tpm_tis_write8(priv, TPM_STS(priv->locality),
+ TPM_STS_RESPONSE_RETRY);
+ else
+ break;
}
- status = tpm_tis_status(chip);
- if (status & TPM_STS_DATA_AVAIL) { /* retry? */
- dev_err(&chip->dev, "Error left over data\n");
+ if (!check_data)
size = -EIO;
- goto out;
- }
-
out:
tpm_tis_ready(chip);
return size;
@@ -364,61 +388,40 @@ static int tpm_tis_send_data(struct tpm_chip *chip, const u8 *buf, size_t len)
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
int rc, status, burstcnt;
size_t count = 0;
- bool itpm = priv->flags & TPM_TIS_ITPM_WORKAROUND;
status = tpm_tis_status(chip);
if ((status & TPM_STS_COMMAND_READY) == 0) {
tpm_tis_ready(chip);
- if (wait_for_tpm_stat
- (chip, TPM_STS_COMMAND_READY, chip->timeout_b,
- &priv->int_queue, false) < 0) {
+ if (wait_for_tpm_stat_result(chip, TPM_STS_COMMAND_READY,
+ TPM_STS_COMMAND_READY,
+ chip->timeout_b,
+ &priv->int_queue, false) < 0) {
rc = -ETIME;
goto out_err;
}
}
- while (count < len - 1) {
+ while (count < len) {
burstcnt = get_burstcount(chip);
if (burstcnt < 0) {
dev_err(&chip->dev, "Unable to read burstcount\n");
rc = burstcnt;
goto out_err;
}
- burstcnt = min_t(int, burstcnt, len - count - 1);
+ burstcnt = min_t(int, burstcnt, len - count);
rc = tpm_tis_write_bytes(priv, TPM_DATA_FIFO(priv->locality),
burstcnt, buf + count);
if (rc < 0)
goto out_err;
count += burstcnt;
-
- if (wait_for_tpm_stat(chip, TPM_STS_VALID, chip->timeout_c,
- &priv->int_queue, false) < 0) {
- rc = -ETIME;
- goto out_err;
- }
- status = tpm_tis_status(chip);
- if (!itpm && (status & TPM_STS_DATA_EXPECT) == 0) {
- rc = -EIO;
- goto out_err;
- }
}
-
- /* write last byte */
- rc = tpm_tis_write8(priv, TPM_DATA_FIFO(priv->locality), buf[count]);
- if (rc < 0)
- goto out_err;
-
- if (wait_for_tpm_stat(chip, TPM_STS_VALID, chip->timeout_c,
- &priv->int_queue, false) < 0) {
+ if (wait_for_tpm_stat_result(chip, TPM_STS_VALID | TPM_STS_DATA_EXPECT,
+ TPM_STS_VALID, chip->timeout_a,
+ &priv->int_queue, false) < 0) {
rc = -ETIME;
goto out_err;
}
- status = tpm_tis_status(chip);
- if (!itpm && (status & TPM_STS_DATA_EXPECT) != 0) {
- rc = -EIO;
- goto out_err;
- }
return 0;
@@ -456,14 +459,19 @@ static void disable_interrupts(struct tpm_chip *chip)
static int tpm_tis_send_main(struct tpm_chip *chip, const u8 *buf, size_t len)
{
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
- int rc;
+ int rc, i;
u32 ordinal;
unsigned long dur;
+ bool data_valid = false;
- rc = tpm_tis_send_data(chip, buf, len);
- if (rc < 0)
- return rc;
-
+ for (i = 0; i < TPM_RETRY && !data_valid; i++) {
+ rc = tpm_tis_send_data(chip, buf, len);
+ if (rc < 0)
+ return rc;
+ data_valid = tpm_tis_check_data(chip, buf, len);
+ }
+ if (!data_valid)
+ return -EIO;
/* go and do it */
rc = tpm_tis_write8(priv, TPM_STS(priv->locality), TPM_STS_GO);
if (rc < 0)
@@ -473,9 +481,11 @@ static int tpm_tis_send_main(struct tpm_chip *chip, const u8 *buf, size_t len)
ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
dur = tpm_calc_ordinal_duration(chip, ordinal);
- if (wait_for_tpm_stat
- (chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID, dur,
- &priv->read_queue, false) < 0) {
+ if (wait_for_tpm_stat_result(chip,
+ TPM_STS_DATA_AVAIL | TPM_STS_VALID,
+ TPM_STS_DATA_AVAIL | TPM_STS_VALID,
+ dur,
+ &priv->read_queue, false) < 0) {
rc = -ETIME;
goto out_err;
}
@@ -612,13 +622,10 @@ static bool tpm_tis_req_canceled(struct tpm_chip *chip, u8 status)
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
switch (priv->manufacturer_id) {
- case TPM_VID_WINBOND:
- return ((status == TPM_STS_VALID) ||
- (status == (TPM_STS_VALID | TPM_STS_COMMAND_READY)));
case TPM_VID_STM:
return (status == (TPM_STS_VALID | TPM_STS_COMMAND_READY));
default:
- return (status == TPM_STS_COMMAND_READY);
+ return ((status & TPM_STS_COMMAND_READY) == TPM_STS_COMMAND_READY);
}
}
diff --git a/drivers/char/tpm/tpm_tis_core.h b/drivers/char/tpm/tpm_tis_core.h
index 7337819f5d7b..486c2e9d7138 100644
--- a/drivers/char/tpm/tpm_tis_core.h
+++ b/drivers/char/tpm/tpm_tis_core.h
@@ -34,6 +34,7 @@ enum tis_status {
TPM_STS_GO = 0x20,
TPM_STS_DATA_AVAIL = 0x10,
TPM_STS_DATA_EXPECT = 0x08,
+ TPM_STS_RESPONSE_RETRY = 0x02,
};
enum tis_int_flags {
@@ -106,6 +107,8 @@ struct tpm_tis_phy_ops {
int (*read16)(struct tpm_tis_data *data, u32 addr, u16 *result);
int (*read32)(struct tpm_tis_data *data, u32 addr, u32 *result);
int (*write32)(struct tpm_tis_data *data, u32 addr, u32 src);
+ bool (*check_data)(struct tpm_tis_data *data, const u8 *buf,
+ size_t len);
};
static inline int tpm_tis_read_bytes(struct tpm_tis_data *data, u32 addr,
@@ -122,13 +125,35 @@ static inline int tpm_tis_read8(struct tpm_tis_data *data, u32 addr, u8 *result)
static inline int tpm_tis_read16(struct tpm_tis_data *data, u32 addr,
u16 *result)
{
- return data->phy_ops->read16(data, addr, result);
+ __le16 result_le;
+ int rc;
+
+ if (data->phy_ops->read16)
+ return data->phy_ops->read16(data, addr, result);
+
+ rc = data->phy_ops->read_bytes(data, addr, sizeof(u16),
+ (u8 *)&result_le);
+ if (!rc)
+ *result = le16_to_cpu(result_le);
+
+ return rc;
}
static inline int tpm_tis_read32(struct tpm_tis_data *data, u32 addr,
u32 *result)
{
- return data->phy_ops->read32(data, addr, result);
+ __le32 result_le;
+ int rc;
+
+ if (data->phy_ops->read32)
+ return data->phy_ops->read32(data, addr, result);
+
+ rc = data->phy_ops->read_bytes(data, addr, sizeof(u32),
+ (u8 *)&result_le);
+ if (!rc)
+ *result = le32_to_cpu(result_le);
+
+ return rc;
}
static inline int tpm_tis_write_bytes(struct tpm_tis_data *data, u32 addr,
@@ -145,7 +170,17 @@ static inline int tpm_tis_write8(struct tpm_tis_data *data, u32 addr, u8 value)
static inline int tpm_tis_write32(struct tpm_tis_data *data, u32 addr,
u32 value)
{
- return data->phy_ops->write32(data, addr, value);
+ __le32 value_le;
+ int rc;
+
+ if (data->phy_ops->write32)
+ return data->phy_ops->write32(data, addr, value);
+
+ value_le = cpu_to_le32(value);
+ rc = data->phy_ops->write_bytes(data, addr, sizeof(u32),
+ (u8 *)&value_le);
+
+ return rc;
}
static inline bool is_bsw(void)
diff --git a/drivers/char/tpm/tpm_tis_i2c.c b/drivers/char/tpm/tpm_tis_i2c.c
new file mode 100644
index 000000000000..83c0b3ae5039
--- /dev/null
+++ b/drivers/char/tpm/tpm_tis_i2c.c
@@ -0,0 +1,292 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2014-2019 Nuvoton Technology corporation
+ *
+ * TPM TIS I2C
+ *
+ * TPM TIS I2C Device Driver Interface for devices that implement the TPM I2C
+ * Interface defined by TCG PC Client Platform TPM Profile (PTP) Specification
+ * Revision 01.03 v22 at www.trustedcomputinggroup.org
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/acpi.h>
+#include <linux/freezer.h>
+#include <linux/crc-ccitt.h>
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/of_irq.h>
+#include <linux/of_gpio.h>
+#include <linux/tpm.h>
+#include "tpm.h"
+#include "tpm_tis_core.h"
+
+#define TPM_LOC_SEL 0x04
+#define TPM_I2C_INTERFACE_CAPABILITY 0x30
+#define TPM_I2C_DEVICE_ADDRESS 0x38
+#define TPM_DATA_CSUM_ENABLE 0x40
+#define TPM_DATA_CSUM 0x44
+#define TPM_I2C_DID_VID 0x48
+#define TPM_I2C_RID 0x4C
+
+//#define I2C_IS_TPM2 1
+
+struct tpm_tis_i2c_phy {
+ struct tpm_tis_data priv;
+ struct i2c_client *i2c_client;
+ bool data_csum;
+ u8 *iobuf;
+};
+
+static inline struct tpm_tis_i2c_phy *to_tpm_tis_i2c_phy(struct tpm_tis_data *data)
+{
+ return container_of(data, struct tpm_tis_i2c_phy, priv);
+}
+
+static u8 address_to_register(u32 addr)
+{
+ addr &= 0xFFF;
+
+ switch (addr) {
+ // adapt register addresses that have changed compared to
+ // older TIS versions
+ case TPM_ACCESS(0):
+ return 0x04;
+ case TPM_LOC_SEL:
+ return 0x00;
+ case TPM_DID_VID(0):
+ return 0x48;
+ case TPM_RID(0):
+ return 0x4C;
+ default:
+ return addr;
+ }
+}
+
+static int tpm_tis_i2c_read_bytes(struct tpm_tis_data *data, u32 addr,
+ u16 len, u8 *result)
+{
+ struct tpm_tis_i2c_phy *phy = to_tpm_tis_i2c_phy(data);
+ int ret = 0;
+ int i = 0;
+ u8 reg = address_to_register(addr);
+ struct i2c_msg msgs[] = {
+ {
+ .addr = phy->i2c_client->addr,
+ .len = sizeof(reg),
+ .buf = &reg,
+ },
+ {
+ .addr = phy->i2c_client->addr,
+ .len = len,
+ .buf = result,
+ .flags = I2C_M_RD,
+ },
+ };
+
+ do {
+ ret = i2c_transfer(phy->i2c_client->adapter, msgs,
+ ARRAY_SIZE(msgs));
+ usleep_range(250, 300); // wait default GUARD_TIME of 250µs
+
+ } while (ret < 0 && i++ < TPM_RETRY);
+
+ if (ret < 0)
+ return ret;
+
+
+ return 0;
+}
+
+static int tpm_tis_i2c_write_bytes(struct tpm_tis_data *data, u32 addr,
+ u16 len, const u8 *value)
+{
+ struct tpm_tis_i2c_phy *phy = to_tpm_tis_i2c_phy(data);
+ int ret = 0;
+ int i = 0;
+
+ if (phy->iobuf) {
+ if (len > TPM_BUFSIZE - 1)
+ return -EIO;
+
+ phy->iobuf[0] = address_to_register(addr);
+ memcpy(phy->iobuf + 1, value, len);
+
+ {
+ struct i2c_msg msgs[] = {
+ {
+ .addr = phy->i2c_client->addr,
+ .len = len + 1,
+ .buf = phy->iobuf,
+ },
+ };
+
+ do {
+ ret = i2c_transfer(phy->i2c_client->adapter,
+ msgs, ARRAY_SIZE(msgs));
+ // wait default GUARD_TIME of 250µs
+ usleep_range(250, 300);
+ } while (ret < 0 && i++ < TPM_RETRY);
+ }
+ } else {
+ u8 reg = address_to_register(addr);
+
+ struct i2c_msg msgs[] = {
+ {
+ .addr = phy->i2c_client->addr,
+ .len = sizeof(reg),
+ .buf = &reg,
+ },
+ {
+ .addr = phy->i2c_client->addr,
+ .len = len,
+ .buf = (u8 *)value,
+ .flags = I2C_M_NOSTART,
+ },
+ };
+ do {
+ ret = i2c_transfer(phy->i2c_client->adapter, msgs,
+ ARRAY_SIZE(msgs));
+ // wait default GUARD_TIME of 250µs
+ usleep_range(250, 300);
+ } while (ret < 0 && i++ < TPM_RETRY);
+ }
+
+ if (ret < 0)
+ return ret;
+
+
+ return 0;
+}
+
+static bool tpm_tis_i2c_check_data(struct tpm_tis_data *data,
+ const u8 *buf, size_t len)
+{
+ struct tpm_tis_i2c_phy *phy = to_tpm_tis_i2c_phy(data);
+ u16 crc, crc_tpm;
+ int rc;
+
+ if (phy->data_csum) {
+ crc = crc_ccitt(0x0000, buf, len);
+ rc = tpm_tis_read16(data, TPM_DATA_CSUM, &crc_tpm);
+ if (rc < 0)
+ return false;
+
+ crc_tpm = be16_to_cpu(crc_tpm);
+ return crc == crc_tpm;
+ }
+
+ return true;
+}
+
+static SIMPLE_DEV_PM_OPS(tpm_tis_pm, tpm_pm_suspend, tpm_tis_resume);
+
+static int csum_state_store(struct tpm_tis_data *data, u8 new_state)
+{
+ struct tpm_tis_i2c_phy *phy = to_tpm_tis_i2c_phy(data);
+ u8 cur_state;
+ int rc;
+
+ rc = tpm_tis_i2c_write_bytes(&phy->priv, TPM_DATA_CSUM_ENABLE,
+ 1, &new_state);
+ if (rc < 0)
+ return rc;
+
+ rc = tpm_tis_i2c_read_bytes(&phy->priv, TPM_DATA_CSUM_ENABLE,
+ 1, &cur_state);
+ if (rc < 0)
+ return rc;
+
+ if (new_state == cur_state)
+ phy->data_csum = (bool)new_state;
+
+ return rc;
+}
+
+static const struct tpm_tis_phy_ops tpm_i2c_phy_ops = {
+ .read_bytes = tpm_tis_i2c_read_bytes,
+ .write_bytes = tpm_tis_i2c_write_bytes,
+ .check_data = tpm_tis_i2c_check_data,
+};
+
+static int tpm_tis_i2c_probe(struct i2c_client *dev,
+ const struct i2c_device_id *id)
+{
+ struct tpm_tis_i2c_phy *phy;
+ int rc;
+ int CRC_Checksum = 0;
+ const u8 loc_init = 0;
+ struct device_node *np;
+
+ phy = devm_kzalloc(&dev->dev, sizeof(struct tpm_tis_i2c_phy),
+ GFP_KERNEL);
+ if (!phy)
+ return -ENOMEM;
+
+ phy->i2c_client = dev;
+
+ if (!i2c_check_functionality(dev->adapter, I2C_FUNC_NOSTART)) {
+ phy->iobuf = devm_kmalloc(&dev->dev, TPM_BUFSIZE, GFP_KERNEL);
+ if (!phy->iobuf)
+ return -ENOMEM;
+ }
+
+ // select locality 0 (the driver will access only via locality 0)
+ rc = tpm_tis_i2c_write_bytes(&phy->priv, TPM_LOC_SEL, 1, &loc_init);
+ if (rc < 0)
+ return rc;
+
+ // set CRC checksum calculation enable
+ np = dev->dev.of_node;
+ if (of_property_read_bool(np, "crc-checksum"))
+ CRC_Checksum = 1;
+
+ rc = csum_state_store(&phy->priv, CRC_Checksum);
+ if (rc < 0)
+ return rc;
+
+ return tpm_tis_core_init(&dev->dev, &phy->priv, -1, &tpm_i2c_phy_ops,
+ NULL);
+}
+
+static const struct i2c_device_id tpm_tis_i2c_id[] = {
+ {"tpm_tis_i2c", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, tpm_tis_i2c_id);
+
+static const struct of_device_id of_tis_i2c_match[] = {
+ { .compatible = "tcg,tpm-tis-i2c", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, of_tis_i2c_match);
+
+static const struct acpi_device_id acpi_tis_i2c_match[] = {
+ {"SMO0768", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(acpi, acpi_tis_i2c_match);
+
+static struct i2c_driver tpm_tis_i2c_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "tpm_tis_i2c",
+ .pm = &tpm_tis_pm,
+ .of_match_table = of_match_ptr(of_tis_i2c_match),
+ .acpi_match_table = ACPI_PTR(acpi_tis_i2c_match),
+ },
+ .probe = tpm_tis_i2c_probe,
+ .id_table = tpm_tis_i2c_id,
+};
+
+module_i2c_driver(tpm_tis_i2c_driver);
+
+MODULE_DESCRIPTION("TPM Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/tpm/tpm_tis_spi.c b/drivers/char/tpm/tpm_tis_spi.c
index 19513e622053..da82924b08fe 100644
--- a/drivers/char/tpm/tpm_tis_spi.c
+++ b/drivers/char/tpm/tpm_tis_spi.c
@@ -146,50 +146,9 @@ static int tpm_tis_spi_write_bytes(struct tpm_tis_data *data, u32 addr,
return tpm_tis_spi_transfer(data, addr, len, NULL, value);
}
-static int tpm_tis_spi_read16(struct tpm_tis_data *data, u32 addr, u16 *result)
-{
- __le16 result_le;
- int rc;
-
- rc = data->phy_ops->read_bytes(data, addr, sizeof(u16),
- (u8 *)&result_le);
- if (!rc)
- *result = le16_to_cpu(result_le);
-
- return rc;
-}
-
-static int tpm_tis_spi_read32(struct tpm_tis_data *data, u32 addr, u32 *result)
-{
- __le32 result_le;
- int rc;
-
- rc = data->phy_ops->read_bytes(data, addr, sizeof(u32),
- (u8 *)&result_le);
- if (!rc)
- *result = le32_to_cpu(result_le);
-
- return rc;
-}
-
-static int tpm_tis_spi_write32(struct tpm_tis_data *data, u32 addr, u32 value)
-{
- __le32 value_le;
- int rc;
-
- value_le = cpu_to_le32(value);
- rc = data->phy_ops->write_bytes(data, addr, sizeof(u32),
- (u8 *)&value_le);
-
- return rc;
-}
-
static const struct tpm_tis_phy_ops tpm_spi_phy_ops = {
.read_bytes = tpm_tis_spi_read_bytes,
.write_bytes = tpm_tis_spi_write_bytes,
- .read16 = tpm_tis_spi_read16,
- .read32 = tpm_tis_spi_read32,
- .write32 = tpm_tis_spi_write32,
};
static int tpm_tis_spi_probe(struct spi_device *dev)
diff --git a/drivers/clk/clk-aspeed.c b/drivers/clk/clk-aspeed.c
index abf06fb6453e..411ff5fb2c07 100644
--- a/drivers/clk/clk-aspeed.c
+++ b/drivers/clk/clk-aspeed.c
@@ -14,7 +14,7 @@
#include "clk-aspeed.h"
-#define ASPEED_NUM_CLKS 36
+#define ASPEED_NUM_CLKS 38
#define ASPEED_RESET2_OFFSET 32
@@ -28,6 +28,7 @@
#define AST2400_HPLL_BYPASS_EN BIT(17)
#define ASPEED_MISC_CTRL 0x2c
#define UART_DIV13_EN BIT(12)
+#define ASPEED_MAC_CLK_DLY 0x48
#define ASPEED_STRAP 0x70
#define CLKIN_25MHZ_EN BIT(23)
#define AST2400_CLK_SOURCE_SEL BIT(18)
@@ -462,6 +463,30 @@ static int aspeed_clk_probe(struct platform_device *pdev)
return PTR_ERR(hw);
aspeed_clk_data->hws[ASPEED_CLK_MAC] = hw;
+ if (of_device_is_compatible(pdev->dev.of_node, "aspeed,ast2500-scu")) {
+ /* RMII 50MHz RCLK */
+ hw = clk_hw_register_fixed_rate(dev, "mac12rclk", "hpll", 0,
+ 50000000);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+
+ /* RMII1 50MHz (RCLK) output enable */
+ hw = clk_hw_register_gate(dev, "mac1rclk", "mac12rclk", 0,
+ scu_base + ASPEED_MAC_CLK_DLY, 29, 0,
+ &aspeed_clk_lock);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+ aspeed_clk_data->hws[ASPEED_CLK_MAC1RCLK] = hw;
+
+ /* RMII2 50MHz (RCLK) output enable */
+ hw = clk_hw_register_gate(dev, "mac2rclk", "mac12rclk", 0,
+ scu_base + ASPEED_MAC_CLK_DLY, 30, 0,
+ &aspeed_clk_lock);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+ aspeed_clk_data->hws[ASPEED_CLK_MAC2RCLK] = hw;
+ }
+
/* LPC Host (LHCLK) clock divider */
hw = clk_hw_register_divider_table(dev, "lhclk", "hpll", 0,
scu_base + ASPEED_CLK_SELECTION, 20, 3, 0,
diff --git a/drivers/clk/clk-ast2600.c b/drivers/clk/clk-ast2600.c
index 7015974f24b4..bbacaccad554 100644
--- a/drivers/clk/clk-ast2600.c
+++ b/drivers/clk/clk-ast2600.c
@@ -15,7 +15,7 @@
#include "clk-aspeed.h"
-#define ASPEED_G6_NUM_CLKS 67
+#define ASPEED_G6_NUM_CLKS 71
#define ASPEED_G6_SILICON_REV 0x004
@@ -40,6 +40,9 @@
#define ASPEED_G6_STRAP1 0x500
+#define ASPEED_MAC12_CLK_DLY 0x340
+#define ASPEED_MAC34_CLK_DLY 0x350
+
/* Globally visible clocks */
static DEFINE_SPINLOCK(aspeed_g6_clk_lock);
@@ -61,7 +64,7 @@ static const struct aspeed_gate_data aspeed_g6_gates[] = {
[ASPEED_CLK_GATE_GCLK] = { 2, 7, "gclk-gate", NULL, 0 }, /* 2D engine */
/* vclk parent - dclk/d1clk/hclk/mclk */
[ASPEED_CLK_GATE_VCLK] = { 3, 6, "vclk-gate", NULL, 0 }, /* Video Capture */
- [ASPEED_CLK_GATE_BCLK] = { 4, 8, "bclk-gate", "bclk", 0 }, /* PCIe/PCI */
+ [ASPEED_CLK_GATE_BCLK] = { 4, 8, "bclk-gate", "bclk", CLK_IS_CRITICAL }, /* PCIe/PCI */
/* From dpll */
[ASPEED_CLK_GATE_DCLK] = { 5, -1, "dclk-gate", NULL, CLK_IS_CRITICAL }, /* DAC */
[ASPEED_CLK_GATE_REF0CLK] = { 6, -1, "ref0clk-gate", "clkin", CLK_IS_CRITICAL },
@@ -116,8 +119,6 @@ static const struct aspeed_gate_data aspeed_g6_gates[] = {
[ASPEED_CLK_GATE_FSICLK] = { 62, 59, "fsiclk-gate", NULL, 0 }, /* FSI */
};
-static const char * const eclk_parent_names[] = { "mpll", "hpll", "dpll" };
-
static const struct clk_div_table ast2600_eclk_div_table[] = {
{ 0x0, 2 },
{ 0x1, 2 },
@@ -519,6 +520,11 @@ static int aspeed_g6_clk_probe(struct platform_device *pdev)
return PTR_ERR(hw);
aspeed_g6_clk_data->hws[ASPEED_CLK_SDIO] = hw;
+ /* MAC1/2 RMII 50MHz RCLK */
+ hw = clk_hw_register_fixed_rate(dev, "mac12rclk", "hpll", 0, 50000000);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+
/* MAC1/2 AHB bus clock divider */
hw = clk_hw_register_divider_table(dev, "mac12", "hpll", 0,
scu_g6_base + ASPEED_G6_CLK_SELECTION1, 16, 3, 0,
@@ -528,6 +534,27 @@ static int aspeed_g6_clk_probe(struct platform_device *pdev)
return PTR_ERR(hw);
aspeed_g6_clk_data->hws[ASPEED_CLK_MAC12] = hw;
+ /* RMII1 50MHz (RCLK) output enable */
+ hw = clk_hw_register_gate(dev, "mac1rclk", "mac12rclk", 0,
+ scu_g6_base + ASPEED_MAC12_CLK_DLY, 29, 0,
+ &aspeed_g6_clk_lock);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+ aspeed_g6_clk_data->hws[ASPEED_CLK_MAC1RCLK] = hw;
+
+ /* RMII2 50MHz (RCLK) output enable */
+ hw = clk_hw_register_gate(dev, "mac2rclk", "mac12rclk", 0,
+ scu_g6_base + ASPEED_MAC12_CLK_DLY, 30, 0,
+ &aspeed_g6_clk_lock);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+ aspeed_g6_clk_data->hws[ASPEED_CLK_MAC2RCLK] = hw;
+
+ /* MAC1/2 RMII 50MHz RCLK */
+ hw = clk_hw_register_fixed_rate(dev, "mac34rclk", "hclk", 0, 50000000);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+
/* MAC3/4 AHB bus clock divider */
hw = clk_hw_register_divider_table(dev, "mac34", "hpll", 0,
scu_g6_base + 0x310, 24, 3, 0,
@@ -537,6 +564,22 @@ static int aspeed_g6_clk_probe(struct platform_device *pdev)
return PTR_ERR(hw);
aspeed_g6_clk_data->hws[ASPEED_CLK_MAC34] = hw;
+ /* RMII3 50MHz (RCLK) output enable */
+ hw = clk_hw_register_gate(dev, "mac3rclk", "mac34rclk", 0,
+ scu_g6_base + ASPEED_MAC34_CLK_DLY, 29, 0,
+ &aspeed_g6_clk_lock);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+ aspeed_g6_clk_data->hws[ASPEED_CLK_MAC3RCLK] = hw;
+
+ /* RMII4 50MHz (RCLK) output enable */
+ hw = clk_hw_register_gate(dev, "mac4rclk", "mac34rclk", 0,
+ scu_g6_base + ASPEED_MAC34_CLK_DLY, 30, 0,
+ &aspeed_g6_clk_lock);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+ aspeed_g6_clk_data->hws[ASPEED_CLK_MAC4RCLK] = hw;
+
/* LPC Host (LHCLK) clock divider */
hw = clk_hw_register_divider_table(dev, "lhclk", "hpll", 0,
scu_g6_base + ASPEED_G6_CLK_SELECTION1, 20, 3, 0,
diff --git a/drivers/clocksource/timer-fttmr010.c b/drivers/clocksource/timer-fttmr010.c
index fadff7915dd9..688d540ebddd 100644
--- a/drivers/clocksource/timer-fttmr010.c
+++ b/drivers/clocksource/timer-fttmr010.c
@@ -38,6 +38,11 @@
#define TIMER_CR (0x30)
/*
+ Control register set to clear for ast2600 only.
+ */
+#define TIMER_CR_CLR (0x3c)
+
+/*
* Control register (TMC30) bit fields for fttmr010/gemini/moxart timers.
*/
#define TIMER_1_CR_ENABLE BIT(0)
@@ -97,6 +102,7 @@ struct fttmr010 {
bool is_aspeed;
u32 t1_enable_val;
struct clock_event_device clkevt;
+ int (*timer_shutdown)(struct clock_event_device *evt);
#ifdef CONFIG_ARM
struct delay_timer delay_timer;
#endif
@@ -140,9 +146,7 @@ static int fttmr010_timer_set_next_event(unsigned long cycles,
u32 cr;
/* Stop */
- cr = readl(fttmr010->base + TIMER_CR);
- cr &= ~fttmr010->t1_enable_val;
- writel(cr, fttmr010->base + TIMER_CR);
+ fttmr010->timer_shutdown(evt);
if (fttmr010->is_aspeed) {
/*
@@ -164,6 +168,16 @@ static int fttmr010_timer_set_next_event(unsigned long cycles,
return 0;
}
+static int ast2600_timer_shutdown(struct clock_event_device *evt)
+{
+ struct fttmr010 *fttmr010 = to_fttmr010(evt);
+
+ /* Stop */
+ writel(fttmr010->t1_enable_val, fttmr010->base + TIMER_CR_CLR);
+
+ return 0;
+}
+
static int fttmr010_timer_shutdown(struct clock_event_device *evt)
{
struct fttmr010 *fttmr010 = to_fttmr010(evt);
@@ -183,9 +197,7 @@ static int fttmr010_timer_set_oneshot(struct clock_event_device *evt)
u32 cr;
/* Stop */
- cr = readl(fttmr010->base + TIMER_CR);
- cr &= ~fttmr010->t1_enable_val;
- writel(cr, fttmr010->base + TIMER_CR);
+ fttmr010->timer_shutdown(evt);
/* Setup counter start from 0 or ~0 */
writel(0, fttmr010->base + TIMER1_COUNT);
@@ -211,9 +223,7 @@ static int fttmr010_timer_set_periodic(struct clock_event_device *evt)
u32 cr;
/* Stop */
- cr = readl(fttmr010->base + TIMER_CR);
- cr &= ~fttmr010->t1_enable_val;
- writel(cr, fttmr010->base + TIMER_CR);
+ fttmr010->timer_shutdown(evt);
/* Setup timer to fire at 1/HZ intervals. */
if (fttmr010->is_aspeed) {
@@ -249,7 +259,21 @@ static irqreturn_t fttmr010_timer_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int __init fttmr010_common_init(struct device_node *np, bool is_aspeed)
+static irqreturn_t ast2600_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = dev_id;
+ struct fttmr010 *fttmr010 = to_fttmr010(evt);
+
+ writel(0x1, fttmr010->base + TIMER_INTR_STATE);
+
+ evt->event_handler(evt);
+ return IRQ_HANDLED;
+}
+
+static int __init fttmr010_common_init(struct device_node *np,
+ bool is_aspeed,
+ int (*timer_shutdown)(struct clock_event_device *),
+ irq_handler_t handler)
{
struct fttmr010 *fttmr010;
int irq;
@@ -350,6 +374,8 @@ static int __init fttmr010_common_init(struct device_node *np, bool is_aspeed)
fttmr010->tick_rate);
}
+ fttmr010->timer_shutdown = timer_shutdown;
+
/*
* Setup clockevent timer (interrupt-driven) on timer 1.
*/
@@ -357,7 +383,7 @@ static int __init fttmr010_common_init(struct device_node *np, bool is_aspeed)
writel(0, fttmr010->base + TIMER1_LOAD);
writel(0, fttmr010->base + TIMER1_MATCH1);
writel(0, fttmr010->base + TIMER1_MATCH2);
- ret = request_irq(irq, fttmr010_timer_interrupt, IRQF_TIMER,
+ ret = request_irq(irq, handler, IRQF_TIMER,
"FTTMR010-TIMER1", &fttmr010->clkevt);
if (ret) {
pr_err("FTTMR010-TIMER1 no IRQ\n");
@@ -370,10 +396,10 @@ static int __init fttmr010_common_init(struct device_node *np, bool is_aspeed)
fttmr010->clkevt.features = CLOCK_EVT_FEAT_PERIODIC |
CLOCK_EVT_FEAT_ONESHOT;
fttmr010->clkevt.set_next_event = fttmr010_timer_set_next_event;
- fttmr010->clkevt.set_state_shutdown = fttmr010_timer_shutdown;
+ fttmr010->clkevt.set_state_shutdown = fttmr010->timer_shutdown;
fttmr010->clkevt.set_state_periodic = fttmr010_timer_set_periodic;
fttmr010->clkevt.set_state_oneshot = fttmr010_timer_set_oneshot;
- fttmr010->clkevt.tick_resume = fttmr010_timer_shutdown;
+ fttmr010->clkevt.tick_resume = fttmr010->timer_shutdown;
fttmr010->clkevt.cpumask = cpumask_of(0);
fttmr010->clkevt.irq = irq;
clockevents_config_and_register(&fttmr010->clkevt,
@@ -404,14 +430,25 @@ out_disable_clock:
return ret;
}
+static __init int ast2600_timer_init(struct device_node *np)
+{
+ return fttmr010_common_init(np, true,
+ ast2600_timer_shutdown,
+ ast2600_timer_interrupt);
+}
+
static __init int aspeed_timer_init(struct device_node *np)
{
- return fttmr010_common_init(np, true);
+ return fttmr010_common_init(np, true,
+ fttmr010_timer_shutdown,
+ fttmr010_timer_interrupt);
}
static __init int fttmr010_timer_init(struct device_node *np)
{
- return fttmr010_common_init(np, false);
+ return fttmr010_common_init(np, false,
+ fttmr010_timer_shutdown,
+ fttmr010_timer_interrupt);
}
TIMER_OF_DECLARE(fttmr010, "faraday,fttmr010", fttmr010_timer_init);
@@ -419,3 +456,4 @@ TIMER_OF_DECLARE(gemini, "cortina,gemini-timer", fttmr010_timer_init);
TIMER_OF_DECLARE(moxart, "moxa,moxart-timer", fttmr010_timer_init);
TIMER_OF_DECLARE(ast2400, "aspeed,ast2400-timer", aspeed_timer_init);
TIMER_OF_DECLARE(ast2500, "aspeed,ast2500-timer", aspeed_timer_init);
+TIMER_OF_DECLARE(ast2600, "aspeed,ast2600-timer", ast2600_timer_init);
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 417dad635526..4adec4af9805 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -524,4 +524,11 @@ config EDAC_BLUEFIELD
Support for error detection and correction on the
Mellanox BlueField SoCs.
+config EDAC_NPCM7XX
+ tristate "Nuvoton NPCM7xx DDR Memory Controller"
+ depends on ARCH_NPCM7XX
+ help
+ Support for error detection and correction on the
+ Nuvoton NPCM7xx DDR memory controller.
+
endif # EDAC
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
index d77200c9680b..1730bc054885 100644
--- a/drivers/edac/Makefile
+++ b/drivers/edac/Makefile
@@ -87,3 +87,4 @@ obj-$(CONFIG_EDAC_TI) += ti_edac.o
obj-$(CONFIG_EDAC_QCOM) += qcom_edac.o
obj-$(CONFIG_EDAC_ASPEED) += aspeed_edac.o
obj-$(CONFIG_EDAC_BLUEFIELD) += bluefield_edac.o
+obj-$(CONFIG_EDAC_NPCM7XX) += npcm7xx_edac.o
diff --git a/drivers/edac/npcm7xx_edac.c b/drivers/edac/npcm7xx_edac.c
new file mode 100644
index 000000000000..2d2deb81e49c
--- /dev/null
+++ b/drivers/edac/npcm7xx_edac.c
@@ -0,0 +1,424 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Quanta Computer lnc.
+ */
+
+#include <linux/edac.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+
+#include "edac_module.h"
+
+#define ECC_ENABLE BIT(24)
+#define ECC_EN_INT_MASK 0x7fffff87
+
+#define INT_STATUS_ADDR 116
+#define INT_ACK_ADDR 117
+#define INT_MASK_ADDR 118
+
+#define ECC_EN_ADDR 93
+#define ECC_C_ADDR_ADDR 98
+#define ECC_C_DATA_ADDR 100
+#define ECC_C_ID_ADDR 101
+#define ECC_C_SYND_ADDR 99
+#define ECC_U_ADDR_ADDR 95
+#define ECC_U_DATA_ADDR 97
+#define ECC_U_ID_ADDR 101
+#define ECC_U_SYND_ADDR 96
+
+#define ECC_ERROR -1
+#define EDAC_MSG_SIZE 256
+#define EDAC_MOD_NAME "npcm7xx-edac"
+
+struct ecc_error_signature_info {
+ u32 ecc_addr;
+ u32 ecc_data;
+ u32 ecc_id;
+ u32 ecc_synd;
+};
+
+struct npcm7xx_ecc_int_status {
+ u32 int_mask;
+ u32 int_status;
+ u32 int_ack;
+ u32 ce_cnt;
+ u32 ue_cnt;
+ struct ecc_error_signature_info ceinfo;
+ struct ecc_error_signature_info ueinfo;
+};
+
+struct npcm7xx_edac_priv {
+ void __iomem *baseaddr;
+ char message[EDAC_MSG_SIZE];
+ struct npcm7xx_ecc_int_status stat;
+};
+
+/**
+ * npcm7xx_edac_get_ecc_syndrom - Get the current ecc error info
+ * @base: Pointer to the base address of the ddr memory controller
+ * @p: Pointer to the Nuvoton ecc status structure
+ *
+ * Determines there is any ecc error or not
+ *
+ * Return: ECC detection status
+ */
+static int npcm7xx_edac_get_ecc_syndrom(void __iomem *base,
+ struct npcm7xx_ecc_int_status *p)
+{
+ int status = 0;
+ u32 int_status = 0;
+
+ int_status = readl(base + 4*INT_STATUS_ADDR);
+ writel(int_status, base + 4*INT_ACK_ADDR);
+ edac_dbg(3, "int_status: %#08x\n", int_status);
+
+ if ((int_status & (1 << 6)) == (1 << 6)) {
+ edac_dbg(3, "6-Mult uncorrectable detected.\n");
+ p->ue_cnt++;
+ status = ECC_ERROR;
+ }
+
+ if ((int_status & (1 << 5)) == (1 << 5)) {
+ edac_dbg(3, "5-An uncorrectable detected\n");
+ p->ue_cnt++;
+ status = ECC_ERROR;
+ }
+
+ if ((int_status & (1 << 4)) == (1 << 4)) {
+ edac_dbg(3, "4-mult correctable detected.\n");
+ p->ce_cnt++;
+ status = ECC_ERROR;
+ }
+
+ if ((int_status & (1 << 3)) == (1 << 3)) {
+ edac_dbg(3, "3-A correctable detected.\n");
+ p->ce_cnt++;
+ status = ECC_ERROR;
+ }
+
+ if (status == ECC_ERROR) {
+ u32 ecc_id;
+
+ p->ceinfo.ecc_addr = readl(base + 4*ECC_C_ADDR_ADDR);
+ p->ceinfo.ecc_data = readl(base + 4*ECC_C_DATA_ADDR);
+ p->ceinfo.ecc_synd = readl(base + 4*ECC_C_SYND_ADDR);
+
+ p->ueinfo.ecc_addr = readl(base + 4*ECC_U_ADDR_ADDR);
+ p->ueinfo.ecc_data = readl(base + 4*ECC_U_DATA_ADDR);
+ p->ueinfo.ecc_synd = readl(base + 4*ECC_U_SYND_ADDR);
+
+ /* ECC_C_ID_ADDR has same value as ECC_U_ID_ADDR */
+ ecc_id = readl(base + 4*ECC_C_ID_ADDR);
+ p->ueinfo.ecc_id = ecc_id & 0xffff;
+ p->ceinfo.ecc_id = ecc_id >> 16;
+ }
+
+ return status;
+}
+
+/**
+ * npcm7xx_edac_handle_error - Handle controller error types CE and UE
+ * @mci: Pointer to the edac memory controller instance
+ * @p: Pointer to the Nuvoton ecc status structure
+ *
+ * Handles the controller ECC correctable and un correctable error.
+ */
+static void npcm7xx_edac_handle_error(struct mem_ctl_info *mci,
+ struct npcm7xx_ecc_int_status *p)
+{
+ struct npcm7xx_edac_priv *priv = mci->pvt_info;
+ u32 page, offset;
+
+ if (p->ce_cnt) {
+ snprintf(priv->message, EDAC_MSG_SIZE,
+ "DDR ECC: synd=%#08x addr=%#08x data=%#08x source_id=%#08x ",
+ p->ceinfo.ecc_synd, p->ceinfo.ecc_addr,
+ p->ceinfo.ecc_data, p->ceinfo.ecc_id);
+
+ page = p->ceinfo.ecc_addr >> PAGE_SHIFT;
+ offset = p->ceinfo.ecc_addr & ~PAGE_MASK;
+ edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+ p->ce_cnt, page, offset,
+ p->ceinfo.ecc_synd,
+ 0, 0, -1,
+ priv->message, "");
+ }
+
+ if (p->ue_cnt) {
+ snprintf(priv->message, EDAC_MSG_SIZE,
+ "DDR ECC: synd=%#08x addr=%#08x data=%#08x source_id=%#08x ",
+ p->ueinfo.ecc_synd, p->ueinfo.ecc_addr,
+ p->ueinfo.ecc_data, p->ueinfo.ecc_id);
+
+ page = p->ueinfo.ecc_addr >> PAGE_SHIFT;
+ offset = p->ueinfo.ecc_addr & ~PAGE_MASK;
+ edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+ p->ue_cnt, page, offset,
+ p->ueinfo.ecc_synd,
+ 0, 0, -1,
+ priv->message, "");
+ }
+
+ memset(p, 0, sizeof(*p));
+}
+
+/**
+ * npcm7xx_edac_check - Check controller for ECC errors
+ * @mci: Pointer to the edac memory controller instance
+ *
+ * This routine is used to check and post ECC errors and is called by
+ * this driver's CE and UE interrupt handler.
+ */
+static void npcm7xx_edac_check(struct mem_ctl_info *mci)
+{
+ struct npcm7xx_edac_priv *priv = mci->pvt_info;
+ int status = 0;
+
+ status = npcm7xx_edac_get_ecc_syndrom(priv->baseaddr, &priv->stat);
+ if (status != ECC_ERROR)
+ return;
+
+ npcm7xx_edac_handle_error(mci, &priv->stat);
+}
+
+/**
+ * npcm7xx_edac_isr - CE/UE interrupt service routine
+ * @irq: The virtual interrupt number being serviced.
+ * @dev_id: A pointer to the EDAC memory controller instance
+ * associated with the interrupt being handled.
+ *
+ * This routine implements the interrupt handler for both correctable
+ * (CE) and uncorrectable (UE) ECC errors for the Nuvoton Cadence DDR
+ * controller. It simply calls through to the routine used to check,
+ * report and clear the ECC status.
+ *
+ * Unconditionally returns IRQ_HANDLED.
+ */
+static irqreturn_t npcm7xx_edac_isr(int irq, void *dev_id)
+{
+ struct mem_ctl_info *mci = dev_id;
+ int npcm_edac_report = 0;
+
+ npcm_edac_report = edac_get_report_status();
+ if (npcm_edac_report != EDAC_REPORTING_DISABLED)
+ npcm7xx_edac_check(mci);
+
+ return IRQ_HANDLED;
+}
+
+static int npcm7xx_edac_register_irq(struct mem_ctl_info *mci,
+ struct platform_device *pdev)
+{
+ int status = 0;
+ int mc_irq;
+ struct npcm7xx_edac_priv *priv = mci->pvt_info;
+
+ /* Only enable MC interrupts with ECC - clear int_mask[6:3] */
+ writel(ECC_EN_INT_MASK, priv->baseaddr + 4*INT_MASK_ADDR);
+
+ mc_irq = platform_get_irq(pdev, 0);
+
+ if (!mc_irq) {
+ edac_printk(KERN_ERR, EDAC_MC, "Unable to map interrupts.\n");
+ status = -ENODEV;
+ goto fail;
+ }
+
+ status = devm_request_irq(&pdev->dev, mc_irq, npcm7xx_edac_isr, 0,
+ "npcm-memory-controller", mci);
+
+ if (status < 0) {
+ edac_printk(KERN_ERR, EDAC_MC,
+ "Unable to request irq %d for ECC",
+ mc_irq);
+ status = -ENODEV;
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ return status;
+}
+
+static const struct of_device_id npcm7xx_edac_of_match[] = {
+ { .compatible = "nuvoton,npcm7xx-sdram-edac"},
+ { /* end of table */ }
+};
+
+MODULE_DEVICE_TABLE(of, npcm7xx_edac_of_match);
+
+/**
+ * npcm7xx_edac_mc_init - Initialize driver instance
+ * @mci: Pointer to the edac memory controller instance
+ * @pdev: Pointer to the platform_device struct
+ *
+ * Performs initialization of the EDAC memory controller instance and
+ * related driver-private data associated with the memory controller the
+ * instance is bound to.
+ *
+ * Returns 0 if OK; otherwise, < 0 on error.
+ */
+static int npcm7xx_edac_mc_init(struct mem_ctl_info *mci,
+ struct platform_device *pdev)
+{
+ const struct of_device_id *id;
+
+ id = of_match_device(npcm7xx_edac_of_match, &pdev->dev);
+ if (!id)
+ return -ENODEV;
+
+ /* Initialize controller capabilities and configuration */
+ mci->mtype_cap = MEM_FLAG_DDR4;
+ mci->edac_ctl_cap = EDAC_FLAG_SECDED;
+ mci->edac_cap = EDAC_FLAG_SECDED;
+ mci->scrub_cap = SCRUB_FLAG_HW_SRC;
+ mci->scrub_mode = SCRUB_HW_SRC;
+ mci->ctl_name = id->compatible;
+ mci->dev_name = dev_name(&pdev->dev);
+ mci->mod_name = EDAC_MOD_NAME;
+
+ edac_op_state = EDAC_OPSTATE_INT;
+
+ return 0;
+}
+
+/**
+ * npcm7xx_edac_get_eccstate - Return the controller ecc enable/disable status
+ * @base: Pointer to the ddr memory controller base address
+ *
+ * Get the ECC enable/disable status for the controller
+ *
+ * Return: a ecc status boolean i.e true/false - enabled/disabled.
+ */
+static bool npcm7xx_edac_get_eccstate(void __iomem *base)
+{
+ u32 ecc_en;
+ bool state = false;
+
+ ecc_en = readl(base + 4*ECC_EN_ADDR);
+ if (ecc_en & ECC_ENABLE) {
+ edac_printk(KERN_INFO, EDAC_MC, "ECC reporting and correcting on. ");
+ state = true;
+ }
+
+ return state;
+}
+
+/**
+ * npcm7xx_edac_mc_probe - Check controller and bind driver
+ * @pdev: Pointer to the platform_device struct
+ *
+ * Probes a specific controller instance for binding with the driver.
+ *
+ * Return: 0 if the controller instance was successfully bound to the
+ * driver; otherwise, < 0 on error.
+ */
+static int npcm7xx_edac_mc_probe(struct platform_device *pdev)
+{
+ struct mem_ctl_info *mci;
+ struct edac_mc_layer layers[1];
+ struct npcm7xx_edac_priv *priv;
+ struct resource *res;
+ void __iomem *baseaddr;
+ int rc;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ baseaddr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(baseaddr)) {
+ edac_printk(KERN_ERR, EDAC_MOD_NAME,
+ "DDR controller regs not defined\n");
+ return PTR_ERR(baseaddr);
+ }
+
+ /*
+ * Check if ECC is enabled.
+ * If not, there is no useful monitoring that can be done
+ * for this controller.
+ */
+ if (!npcm7xx_edac_get_eccstate(baseaddr)) {
+ edac_printk(KERN_INFO, EDAC_MC, "ECC disabled\n");
+ return -ENXIO;
+ }
+
+ /*
+ * Allocate an EDA controller instance and perform the appropriate
+ * initialization.
+ */
+ layers[0].type = EDAC_MC_LAYER_ALL_MEM;
+ layers[0].size = 1;
+
+ mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers,
+ sizeof(struct npcm7xx_edac_priv));
+ if (!mci) {
+ edac_printk(KERN_ERR, EDAC_MC,
+ "Failed memory allocation for mc instance\n");
+ return -ENOMEM;
+ }
+
+ mci->pdev = &pdev->dev;
+ priv = mci->pvt_info;
+ priv->baseaddr = baseaddr;
+ platform_set_drvdata(pdev, mci);
+
+ rc = npcm7xx_edac_mc_init(mci, pdev);
+ if (rc) {
+ edac_printk(KERN_ERR, EDAC_MC,
+ "Failed to initialize instance\n");
+ goto free_edac_mc;
+ }
+
+ /* Attempt to register it with the EDAC subsystem */
+ rc = edac_mc_add_mc(mci);
+ if (rc) {
+ edac_printk(KERN_ERR, EDAC_MC,
+ "Failed to register with EDAC core\n");
+ goto free_edac_mc;
+ }
+
+ /* Register interrupts */
+ rc = npcm7xx_edac_register_irq(mci, pdev);
+ if (rc)
+ goto free_edac_mc;
+
+ return 0;
+
+free_edac_mc:
+ edac_mc_free(mci);
+
+ return rc;
+}
+
+/**
+ * npcm7xx_edac_mc_remove - Unbind driver from controller
+ * @pdev: Pointer to the platform_device struct
+ *
+ * Return: Unconditionally 0
+ */
+static int npcm7xx_edac_mc_remove(struct platform_device *pdev)
+{
+ struct mem_ctl_info *mci = platform_get_drvdata(pdev);
+
+ edac_mc_del_mc(&pdev->dev);
+ edac_mc_free(mci);
+
+ return 0;
+}
+
+static struct platform_driver npcm7xx_edac_driver = {
+ .probe = npcm7xx_edac_mc_probe,
+ .remove = npcm7xx_edac_mc_remove,
+ .driver = {
+ .name = EDAC_MOD_NAME,
+ .of_match_table = npcm7xx_edac_of_match,
+ },
+};
+
+module_platform_driver(npcm7xx_edac_driver);
+
+MODULE_AUTHOR("Quanta Computer Inc.");
+MODULE_DESCRIPTION("Nuvoton NPCM7xx EDAC Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/fsi/Kconfig b/drivers/fsi/Kconfig
index c612db7a914a..92ce6d85802c 100644
--- a/drivers/fsi/Kconfig
+++ b/drivers/fsi/Kconfig
@@ -53,6 +53,14 @@ config FSI_MASTER_AST_CF
lines driven by the internal ColdFire coprocessor. This requires
the corresponding machine specific ColdFire firmware to be available.
+config FSI_MASTER_ASPEED
+ tristate "FSI ASPEED master"
+ help
+ This option enables a FSI master that is present behind an OPB bridge
+ in the AST2600.
+
+ Enable it for your BMC kernel in an OpenPower or IBM Power system.
+
config FSI_SCOM
tristate "SCOM FSI client device driver"
---help---
diff --git a/drivers/fsi/Makefile b/drivers/fsi/Makefile
index e4a2ff043c32..da218a1ad8e1 100644
--- a/drivers/fsi/Makefile
+++ b/drivers/fsi/Makefile
@@ -2,6 +2,7 @@
obj-$(CONFIG_FSI) += fsi-core.o
obj-$(CONFIG_FSI_MASTER_HUB) += fsi-master-hub.o
+obj-$(CONFIG_FSI_MASTER_ASPEED) += fsi-master-aspeed.o
obj-$(CONFIG_FSI_MASTER_GPIO) += fsi-master-gpio.o
obj-$(CONFIG_FSI_MASTER_AST_CF) += fsi-master-ast-cf.o
obj-$(CONFIG_FSI_SCOM) += fsi-scom.o
diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
index 9282239b4d95..8244da8a7241 100644
--- a/drivers/fsi/fsi-core.c
+++ b/drivers/fsi/fsi-core.c
@@ -1264,6 +1264,19 @@ static ssize_t master_break_store(struct device *dev,
static DEVICE_ATTR(break, 0200, NULL, master_break_store);
+static struct attribute *master_attrs[] = {
+ &dev_attr_break.attr,
+ &dev_attr_rescan.attr,
+ NULL
+};
+
+ATTRIBUTE_GROUPS(master);
+
+static struct class fsi_master_class = {
+ .name = "fsi-master",
+ .dev_groups = master_groups,
+};
+
int fsi_master_register(struct fsi_master *master)
{
int rc;
@@ -1272,6 +1285,7 @@ int fsi_master_register(struct fsi_master *master)
mutex_init(&master->scan_lock);
master->idx = ida_simple_get(&master_ida, 0, INT_MAX, GFP_KERNEL);
dev_set_name(&master->dev, "fsi%d", master->idx);
+ master->dev.class = &fsi_master_class;
rc = device_register(&master->dev);
if (rc) {
@@ -1279,20 +1293,6 @@ int fsi_master_register(struct fsi_master *master)
return rc;
}
- rc = device_create_file(&master->dev, &dev_attr_rescan);
- if (rc) {
- device_del(&master->dev);
- ida_simple_remove(&master_ida, master->idx);
- return rc;
- }
-
- rc = device_create_file(&master->dev, &dev_attr_break);
- if (rc) {
- device_del(&master->dev);
- ida_simple_remove(&master_ida, master->idx);
- return rc;
- }
-
np = dev_of_node(&master->dev);
if (!of_property_read_bool(np, "no-scan-on-init")) {
mutex_lock(&master->scan_lock);
@@ -1373,8 +1373,15 @@ static int __init fsi_init(void)
rc = bus_register(&fsi_bus_type);
if (rc)
goto fail_bus;
+
+ rc = class_register(&fsi_master_class);
+ if (rc)
+ goto fail_class;
+
return 0;
+ fail_class:
+ bus_unregister(&fsi_bus_type);
fail_bus:
unregister_chrdev_region(fsi_base_dev, FSI_CHAR_MAX_DEVICES);
return rc;
@@ -1383,6 +1390,7 @@ postcore_initcall(fsi_init);
static void fsi_exit(void)
{
+ class_unregister(&fsi_master_class);
bus_unregister(&fsi_bus_type);
unregister_chrdev_region(fsi_base_dev, FSI_CHAR_MAX_DEVICES);
ida_destroy(&fsi_minor_ida);
diff --git a/drivers/fsi/fsi-master-aspeed.c b/drivers/fsi/fsi-master-aspeed.c
new file mode 100644
index 000000000000..b44f71f1f0a8
--- /dev/null
+++ b/drivers/fsi/fsi-master-aspeed.c
@@ -0,0 +1,607 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// Copyright (C) IBM Corporation 2018
+// FSI master driver for AST2600
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/fsi.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/iopoll.h>
+#include <linux/gpio/consumer.h>
+
+#include "fsi-master.h"
+
+struct fsi_master_aspeed {
+ struct fsi_master master;
+ struct device *dev;
+ void __iomem *base;
+ struct clk *clk;
+};
+
+#define to_fsi_master_aspeed(m) \
+ container_of(m, struct fsi_master_aspeed, master)
+
+/* Control register (size 0x400) */
+static const u32 ctrl_base = 0x80000000;
+
+static const u32 fsi_base = 0xa0000000;
+
+#define OPB_FSI_VER 0x00
+#define OPB_TRIGGER 0x04
+#define OPB_CTRL_BASE 0x08
+#define OPB_FSI_BASE 0x0c
+#define OPB_CLK_SYNC 0x3c
+#define OPB_IRQ_CLEAR 0x40
+#define OPB_IRQ_MASK 0x44
+#define OPB_IRQ_STATUS 0x48
+
+#define OPB0_SELECT 0x10
+#define OPB0_RW 0x14
+#define OPB0_XFER_SIZE 0x18
+#define OPB0_FSI_ADDR 0x1c
+#define OPB0_FSI_DATA_W 0x20
+#define OPB0_STATUS 0x80
+#define OPB0_FSI_DATA_R 0x84
+
+#define OPB0_WRITE_ORDER1 0x4c
+#define OPB0_WRITE_ORDER2 0x50
+#define OPB1_WRITE_ORDER1 0x54
+#define OPB1_WRITE_ORDER2 0x58
+#define OPB0_READ_ORDER1 0x5c
+#define OPB1_READ_ORDER2 0x60
+
+#define OPB_RETRY_COUNTER 0x64
+
+/* OPBn_STATUS */
+#define STATUS_HALFWORD_ACK BIT(0)
+#define STATUS_FULLWORD_ACK BIT(1)
+#define STATUS_ERR_ACK BIT(2)
+#define STATUS_RETRY BIT(3)
+#define STATUS_TIMEOUT BIT(4)
+
+/* OPB_IRQ_MASK */
+#define OPB1_XFER_ACK_EN BIT(17)
+#define OPB0_XFER_ACK_EN BIT(16)
+
+/* OPB_RW */
+#define CMD_READ BIT(0)
+#define CMD_WRITE 0
+
+/* OPBx_XFER_SIZE */
+#define XFER_FULLWORD (BIT(1) | BIT(0))
+#define XFER_HALFWORD (BIT(0))
+#define XFER_BYTE (0)
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/fsi_master_aspeed.h>
+
+#define FSI_LINK_ENABLE_SETUP_TIME 10 /* in mS */
+
+/* Run the bus at maximum speed by default */
+#define FSI_DIVISOR_DEFAULT 1
+#define FSI_DIVISOR_CABLED 2
+static u16 aspeed_fsi_divisor = FSI_DIVISOR_DEFAULT;
+module_param_named(bus_div,aspeed_fsi_divisor, ushort, 0);
+
+#define OPB_POLL_TIMEOUT 10000
+
+static int __opb_write(struct fsi_master_aspeed *aspeed, u32 addr,
+ u32 val, u32 transfer_size)
+{
+ void __iomem *base = aspeed->base;
+ u32 reg, status;
+ int ret;
+
+ writel(CMD_WRITE, base + OPB0_RW);
+ writel(transfer_size, base + OPB0_XFER_SIZE);
+ writel(addr, base + OPB0_FSI_ADDR);
+ writel(val, base + OPB0_FSI_DATA_W);
+ writel(0x1, base + OPB_IRQ_CLEAR);
+ writel(0x1, base + OPB_TRIGGER);
+
+ ret = readl_poll_timeout(base + OPB_IRQ_STATUS, reg,
+ (reg & OPB0_XFER_ACK_EN) != 0,
+ 0, OPB_POLL_TIMEOUT);
+
+ status = readl(base + OPB0_STATUS);
+
+ trace_fsi_master_aspeed_opb_write(addr, val, transfer_size, status, reg);
+
+ /* Return error when poll timed out */
+ if (ret)
+ return ret;
+
+ /* Command failed, master will reset */
+ if (status & STATUS_ERR_ACK)
+ return -EIO;
+
+ return 0;
+}
+
+static int opb_writeb(struct fsi_master_aspeed *aspeed, u32 addr, u8 val)
+{
+ return __opb_write(aspeed, addr, val, XFER_BYTE);
+}
+
+static int opb_writew(struct fsi_master_aspeed *aspeed, u32 addr, __be16 val)
+{
+ return __opb_write(aspeed, addr, (__force u16)val, XFER_HALFWORD);
+}
+
+static int opb_writel(struct fsi_master_aspeed *aspeed, u32 addr, __be32 val)
+{
+ return __opb_write(aspeed, addr, (__force u32)val, XFER_FULLWORD);
+}
+
+static int __opb_read(struct fsi_master_aspeed *aspeed, uint32_t addr,
+ u32 transfer_size, void *out)
+{
+ void __iomem *base = aspeed->base;
+ u32 result, reg;
+ int status, ret;
+
+ writel(CMD_READ, base + OPB0_RW);
+ writel(transfer_size, base + OPB0_XFER_SIZE);
+ writel(addr, base + OPB0_FSI_ADDR);
+ writel(0x1, base + OPB_IRQ_CLEAR);
+ writel(0x1, base + OPB_TRIGGER);
+
+ ret = readl_poll_timeout(base + OPB_IRQ_STATUS, reg,
+ (reg & OPB0_XFER_ACK_EN) != 0,
+ 0, OPB_POLL_TIMEOUT);
+
+ status = readl(base + OPB0_STATUS);
+
+ result = readl(base + OPB0_FSI_DATA_R);
+
+ trace_fsi_master_aspeed_opb_read(addr, transfer_size, result,
+ readl(base + OPB0_STATUS),
+ reg);
+
+ /* Return error when poll timed out */
+ if (ret)
+ return ret;
+
+ /* Command failed, master will reset */
+ if (status & STATUS_ERR_ACK)
+ return -EIO;
+
+ if (out) {
+ switch (transfer_size) {
+ case XFER_BYTE:
+ *(u8 *)out = result;
+ break;
+ case XFER_HALFWORD:
+ *(u16 *)out = result;
+ break;
+ case XFER_FULLWORD:
+ *(u32 *)out = result;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ }
+
+ return 0;
+}
+
+static int opb_readl(struct fsi_master_aspeed *aspeed, uint32_t addr, __be32 *out)
+{
+ return __opb_read(aspeed, addr, XFER_FULLWORD, out);
+}
+
+static int opb_readw(struct fsi_master_aspeed *aspeed, uint32_t addr, __be16 *out)
+{
+ return __opb_read(aspeed, addr, XFER_HALFWORD, (void *)out);
+}
+
+static int opb_readb(struct fsi_master_aspeed *aspeed, uint32_t addr, u8 *out)
+{
+ return __opb_read(aspeed, addr, XFER_BYTE, (void *)out);
+}
+
+static int check_errors(struct fsi_master_aspeed *aspeed, int err)
+{
+ int ret;
+
+ if (trace_fsi_master_aspeed_opb_error_enabled()) {
+ __be32 mresp0, mstap0, mesrb0;
+
+ opb_readl(aspeed, ctrl_base + FSI_MRESP0, &mresp0);
+ opb_readl(aspeed, ctrl_base + FSI_MSTAP0, &mstap0);
+ opb_readl(aspeed, ctrl_base + FSI_MESRB0, &mesrb0);
+
+ trace_fsi_master_aspeed_opb_error(
+ be32_to_cpu(mresp0),
+ be32_to_cpu(mstap0),
+ be32_to_cpu(mesrb0));
+ }
+
+ if (err == -EIO) {
+ /* Check MAEB (0x70) ? */
+
+ /* Then clear errors in master */
+ ret = opb_writel(aspeed, ctrl_base + FSI_MRESP0,
+ cpu_to_be32(FSI_MRESP_RST_ALL_MASTER));
+ if (ret) {
+ /* TODO: log? return different code? */
+ return ret;
+ }
+ /* TODO: confirm that 0x70 was okay */
+ }
+
+ /* This will pass through timeout errors */
+ return err;
+}
+
+static int aspeed_master_read(struct fsi_master *master, int link,
+ uint8_t id, uint32_t addr, void *val, size_t size)
+{
+ struct fsi_master_aspeed *aspeed = to_fsi_master_aspeed(master);
+ int ret;
+
+ if (id > 0x3)
+ return -EINVAL;
+
+ addr |= id << 21;
+ addr += link * FSI_HUB_LINK_SIZE;
+
+ switch (size) {
+ case 1:
+ ret = opb_readb(aspeed, fsi_base + addr, val);
+ break;
+ case 2:
+ ret = opb_readw(aspeed, fsi_base + addr, val);
+ break;
+ case 4:
+ ret = opb_readl(aspeed, fsi_base + addr, val);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = check_errors(aspeed, ret);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int aspeed_master_write(struct fsi_master *master, int link,
+ uint8_t id, uint32_t addr, const void *val, size_t size)
+{
+ struct fsi_master_aspeed *aspeed = to_fsi_master_aspeed(master);
+ int ret;
+
+ if (id > 0x3)
+ return -EINVAL;
+
+ addr |= id << 21;
+ addr += link * FSI_HUB_LINK_SIZE;
+
+ switch (size) {
+ case 1:
+ ret = opb_writeb(aspeed, fsi_base + addr, *(u8 *)val);
+ break;
+ case 2:
+ ret = opb_writew(aspeed, fsi_base + addr, *(__be16 *)val);
+ break;
+ case 4:
+ ret = opb_writel(aspeed, fsi_base + addr, *(__be32 *)val);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = check_errors(aspeed, ret);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int aspeed_master_link_enable(struct fsi_master *master, int link)
+{
+ struct fsi_master_aspeed *aspeed = to_fsi_master_aspeed(master);
+ int idx, bit, ret;
+ __be32 reg, result;
+
+ idx = link / 32;
+ bit = link % 32;
+
+ reg = cpu_to_be32(0x80000000 >> bit);
+
+ ret = opb_writel(aspeed, ctrl_base + FSI_MSENP0 + (4 * idx), reg);
+ if (ret)
+ return ret;
+
+ mdelay(FSI_LINK_ENABLE_SETUP_TIME);
+
+ ret = opb_readl(aspeed, ctrl_base + FSI_MENP0 + (4 * idx), &result);
+ if (ret)
+ return ret;
+
+ if (result != reg) {
+ dev_err(aspeed->dev, "%s failed: %08x\n", __func__, result);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int aspeed_master_term(struct fsi_master *master, int link, uint8_t id)
+{
+ uint32_t addr;
+ __be32 cmd;
+
+ addr = 0x4;
+ cmd = cpu_to_be32(0xecc00000);
+
+ return aspeed_master_write(master, link, id, addr, &cmd, 4);
+}
+
+static int aspeed_master_break(struct fsi_master *master, int link)
+{
+ uint32_t addr;
+ __be32 cmd;
+
+ addr = 0x0;
+ cmd = cpu_to_be32(0xc0de0000);
+
+ return aspeed_master_write(master, link, 0, addr, &cmd, 4);
+}
+
+static void aspeed_master_release(struct device *dev)
+{
+ struct fsi_master_aspeed *aspeed =
+ to_fsi_master_aspeed(dev_to_fsi_master(dev));
+
+ kfree(aspeed);
+}
+
+/* mmode encoders */
+static inline u32 fsi_mmode_crs0(u32 x)
+{
+ return (x & FSI_MMODE_CRS0MASK) << FSI_MMODE_CRS0SHFT;
+}
+
+static inline u32 fsi_mmode_crs1(u32 x)
+{
+ return (x & FSI_MMODE_CRS1MASK) << FSI_MMODE_CRS1SHFT;
+}
+
+static int aspeed_master_init(struct fsi_master_aspeed *aspeed)
+{
+ __be32 reg;
+
+ reg = cpu_to_be32(FSI_MRESP_RST_ALL_MASTER | FSI_MRESP_RST_ALL_LINK
+ | FSI_MRESP_RST_MCR | FSI_MRESP_RST_PYE);
+ opb_writel(aspeed, ctrl_base + FSI_MRESP0, reg);
+
+ /* Initialize the MFSI (hub master) engine */
+ reg = cpu_to_be32(FSI_MRESP_RST_ALL_MASTER | FSI_MRESP_RST_ALL_LINK
+ | FSI_MRESP_RST_MCR | FSI_MRESP_RST_PYE);
+ opb_writel(aspeed, ctrl_base + FSI_MRESP0, reg);
+
+ reg = cpu_to_be32(FSI_MECTRL_EOAE | FSI_MECTRL_P8_AUTO_TERM);
+ opb_writel(aspeed, ctrl_base + FSI_MECTRL, reg);
+
+ reg = cpu_to_be32(FSI_MMODE_ECRC | FSI_MMODE_EPC | FSI_MMODE_RELA
+ | fsi_mmode_crs0(aspeed_fsi_divisor)
+ | fsi_mmode_crs1(aspeed_fsi_divisor)
+ | FSI_MMODE_P8_TO_LSB);
+ dev_info(aspeed->dev, "mmode set to %08x (divisor %d)\n",
+ be32_to_cpu(reg), aspeed_fsi_divisor);
+ opb_writel(aspeed, ctrl_base + FSI_MMODE, reg);
+
+ reg = cpu_to_be32(0xffff0000);
+ opb_writel(aspeed, ctrl_base + FSI_MDLYR, reg);
+
+ reg = cpu_to_be32(~0);
+ opb_writel(aspeed, ctrl_base + FSI_MSENP0, reg);
+
+ /* Leave enabled long enough for master logic to set up */
+ mdelay(FSI_LINK_ENABLE_SETUP_TIME);
+
+ opb_writel(aspeed, ctrl_base + FSI_MCENP0, reg);
+
+ opb_readl(aspeed, ctrl_base + FSI_MAEB, NULL);
+
+ reg = cpu_to_be32(FSI_MRESP_RST_ALL_MASTER | FSI_MRESP_RST_ALL_LINK);
+ opb_writel(aspeed, ctrl_base + FSI_MRESP0, reg);
+
+ opb_readl(aspeed, ctrl_base + FSI_MLEVP0, NULL);
+
+ /* Reset the master bridge */
+ reg = cpu_to_be32(FSI_MRESB_RST_GEN);
+ opb_writel(aspeed, ctrl_base + FSI_MRESB0, reg);
+
+ reg = cpu_to_be32(FSI_MRESB_RST_ERR);
+ opb_writel(aspeed, ctrl_base + FSI_MRESB0, reg);
+
+ return 0;
+}
+
+static int tacoma_cabled_fsi_fixup(struct device *dev)
+{
+ struct gpio_desc *routing_gpio, *mux_gpio;
+ int gpio;
+
+ /*
+ * The routing GPIO is a jumper indicating we should mux for the
+ * externally connected FSI cable.
+ */
+ routing_gpio = devm_gpiod_get_optional(dev, "fsi-routing",
+ GPIOD_IN | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
+ if (IS_ERR(routing_gpio))
+ return PTR_ERR(routing_gpio);
+ if (!routing_gpio)
+ return 0;
+
+ mux_gpio = devm_gpiod_get_optional(dev, "fsi-mux", GPIOD_ASIS);
+ if (IS_ERR(mux_gpio))
+ return PTR_ERR(mux_gpio);
+ if (!mux_gpio)
+ return 0;
+
+ gpio = gpiod_get_value(routing_gpio);
+ if (gpio < 0)
+ return gpio;
+
+ /* If the routing GPIO is high we should set the mux to low. */
+ if (gpio) {
+ /*
+ * Cable signal integrity means we should run the bus
+ * slightly slower. Do not override if a kernel param
+ * has already overridden.
+ */
+ if (aspeed_fsi_divisor == FSI_DIVISOR_DEFAULT)
+ aspeed_fsi_divisor = FSI_DIVISOR_CABLED;
+
+ gpiod_direction_output(mux_gpio, 0);
+ dev_info(dev, "FSI configured for external cable\n");
+ } else {
+ gpiod_direction_output(mux_gpio, 1);
+ }
+
+ devm_gpiod_put(dev, routing_gpio);
+
+ return 0;
+}
+
+static int fsi_master_aspeed_probe(struct platform_device *pdev)
+{
+ struct fsi_master_aspeed *aspeed;
+ struct resource *res;
+ int rc, links, reg;
+ __be32 raw;
+
+ rc = tacoma_cabled_fsi_fixup(&pdev->dev);
+ if (rc) {
+ dev_err(&pdev->dev, "Tacoma FSI cable fixup failed\n");
+ return rc;
+ }
+
+ aspeed = devm_kzalloc(&pdev->dev, sizeof(*aspeed), GFP_KERNEL);
+ if (!aspeed)
+ return -ENOMEM;
+
+ aspeed->dev = &pdev->dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ aspeed->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(aspeed->base))
+ return PTR_ERR(aspeed->base);
+
+ aspeed->clk = devm_clk_get(aspeed->dev, NULL);
+ if (IS_ERR(aspeed->clk)) {
+ dev_err(aspeed->dev, "couldn't get clock\n");
+ return PTR_ERR(aspeed->clk);
+ }
+ rc = clk_prepare_enable(aspeed->clk);
+ if (rc) {
+ dev_err(aspeed->dev, "couldn't enable clock\n");
+ return rc;
+ }
+
+ writel(0x1, aspeed->base + OPB_CLK_SYNC);
+ writel(OPB1_XFER_ACK_EN | OPB0_XFER_ACK_EN,
+ aspeed->base + OPB_IRQ_MASK);
+
+ /* TODO: determine an appropriate value */
+ writel(0x10, aspeed->base + OPB_RETRY_COUNTER);
+
+ writel(ctrl_base, aspeed->base + OPB_CTRL_BASE);
+ writel(fsi_base, aspeed->base + OPB_FSI_BASE);
+
+ /* Set read data order */
+ writel(0x00030b1b, aspeed->base + OPB0_READ_ORDER1);
+
+ /* Set write data order */
+ writel(0x0011101b, aspeed->base + OPB0_WRITE_ORDER1);
+ writel(0x0c330f3f, aspeed->base + OPB0_WRITE_ORDER2);
+
+ /*
+ * Select OPB0 for all operations.
+ * Will need to be reworked when enabling DMA or anything that uses
+ * OPB1.
+ */
+ writel(0x1, aspeed->base + OPB0_SELECT);
+
+ rc = opb_readl(aspeed, ctrl_base + FSI_MVER, &raw);
+ if (rc) {
+ dev_err(&pdev->dev, "failed to read hub version\n");
+ return rc;
+ }
+
+ reg = be32_to_cpu(raw);
+ links = (reg >> 8) & 0xff;
+ dev_info(&pdev->dev, "hub version %08x (%d links)\n", reg, links);
+
+ aspeed->master.dev.parent = &pdev->dev;
+ aspeed->master.dev.release = aspeed_master_release;
+ aspeed->master.dev.of_node = of_node_get(dev_of_node(&pdev->dev));
+
+ aspeed->master.n_links = links;
+ aspeed->master.read = aspeed_master_read;
+ aspeed->master.write = aspeed_master_write;
+ aspeed->master.send_break = aspeed_master_break;
+ aspeed->master.term = aspeed_master_term;
+ aspeed->master.link_enable = aspeed_master_link_enable;
+
+ dev_set_drvdata(&pdev->dev, aspeed);
+
+ aspeed_master_init(aspeed);
+
+ rc = fsi_master_register(&aspeed->master);
+ if (rc)
+ goto err_release;
+
+ /* At this point, fsi_master_register performs the device_initialize(),
+ * and holds the sole reference on master.dev. This means the device
+ * will be freed (via ->release) during any subsequent call to
+ * fsi_master_unregister. We add our own reference to it here, so we
+ * can perform cleanup (in _remove()) without it being freed before
+ * we're ready.
+ */
+ get_device(&aspeed->master.dev);
+ return 0;
+
+err_release:
+ clk_disable_unprepare(aspeed->clk);
+ return rc;
+}
+
+static int fsi_master_aspeed_remove(struct platform_device *pdev)
+{
+ struct fsi_master_aspeed *aspeed = platform_get_drvdata(pdev);
+
+ fsi_master_unregister(&aspeed->master);
+ clk_disable_unprepare(aspeed->clk);
+
+ return 0;
+}
+
+static const struct of_device_id fsi_master_aspeed_match[] = {
+ { .compatible = "aspeed,ast2600-fsi-master" },
+ { },
+};
+
+static struct platform_driver fsi_master_aspeed_driver = {
+ .driver = {
+ .name = "fsi-master-aspeed",
+ .of_match_table = fsi_master_aspeed_match,
+ },
+ .probe = fsi_master_aspeed_probe,
+ .remove = fsi_master_aspeed_remove,
+};
+
+module_platform_driver(fsi_master_aspeed_driver);
+MODULE_LICENSE("GPL");
diff --git a/drivers/fsi/fsi-master-hub.c b/drivers/fsi/fsi-master-hub.c
index f158b1a88286..def35cf92571 100644
--- a/drivers/fsi/fsi-master-hub.c
+++ b/drivers/fsi/fsi-master-hub.c
@@ -13,53 +13,7 @@
#include "fsi-master.h"
-/* Control Registers */
-#define FSI_MMODE 0x0 /* R/W: mode */
-#define FSI_MDLYR 0x4 /* R/W: delay */
-#define FSI_MCRSP 0x8 /* R/W: clock rate */
-#define FSI_MENP0 0x10 /* R/W: enable */
-#define FSI_MLEVP0 0x18 /* R: plug detect */
-#define FSI_MSENP0 0x18 /* S: Set enable */
-#define FSI_MCENP0 0x20 /* C: Clear enable */
-#define FSI_MAEB 0x70 /* R: Error address */
-#define FSI_MVER 0x74 /* R: master version/type */
-#define FSI_MRESP0 0xd0 /* W: Port reset */
-#define FSI_MESRB0 0x1d0 /* R: Master error status */
-#define FSI_MRESB0 0x1d0 /* W: Reset bridge */
-#define FSI_MECTRL 0x2e0 /* W: Error control */
-
-/* MMODE: Mode control */
-#define FSI_MMODE_EIP 0x80000000 /* Enable interrupt polling */
-#define FSI_MMODE_ECRC 0x40000000 /* Enable error recovery */
-#define FSI_MMODE_EPC 0x10000000 /* Enable parity checking */
-#define FSI_MMODE_P8_TO_LSB 0x00000010 /* Timeout value LSB */
- /* MSB=1, LSB=0 is 0.8 ms */
- /* MSB=0, LSB=1 is 0.9 ms */
-#define FSI_MMODE_CRS0SHFT 18 /* Clk rate selection 0 shift */
-#define FSI_MMODE_CRS0MASK 0x3ff /* Clk rate selection 0 mask */
-#define FSI_MMODE_CRS1SHFT 8 /* Clk rate selection 1 shift */
-#define FSI_MMODE_CRS1MASK 0x3ff /* Clk rate selection 1 mask */
-
-/* MRESB: Reset brindge */
-#define FSI_MRESB_RST_GEN 0x80000000 /* General reset */
-#define FSI_MRESB_RST_ERR 0x40000000 /* Error Reset */
-
-/* MRESB: Reset port */
-#define FSI_MRESP_RST_ALL_MASTER 0x20000000 /* Reset all FSI masters */
-#define FSI_MRESP_RST_ALL_LINK 0x10000000 /* Reset all FSI port contr. */
-#define FSI_MRESP_RST_MCR 0x08000000 /* Reset FSI master reg. */
-#define FSI_MRESP_RST_PYE 0x04000000 /* Reset FSI parity error */
-#define FSI_MRESP_RST_ALL 0xfc000000 /* Reset any error */
-
-/* MECTRL: Error control */
-#define FSI_MECTRL_EOAE 0x8000 /* Enable machine check when */
- /* master 0 in error */
-#define FSI_MECTRL_P8_AUTO_TERM 0x4000 /* Auto terminate */
-
#define FSI_ENGID_HUB_MASTER 0x1c
-#define FSI_HUB_LINK_OFFSET 0x80000
-#define FSI_HUB_LINK_SIZE 0x80000
-#define FSI_HUB_MASTER_MAX_LINKS 8
#define FSI_LINK_ENABLE_SETUP_TIME 10 /* in mS */
diff --git a/drivers/fsi/fsi-master.h b/drivers/fsi/fsi-master.h
index c7174237e864..6e8d4d4d5149 100644
--- a/drivers/fsi/fsi-master.h
+++ b/drivers/fsi/fsi-master.h
@@ -12,6 +12,71 @@
#include <linux/device.h>
#include <linux/mutex.h>
+/*
+ * Master registers
+ *
+ * These are used by hardware masters, such as the one in the FSP2, AST2600 and
+ * the hub master in POWER processors.
+ */
+
+/* Control Registers */
+#define FSI_MMODE 0x0 /* R/W: mode */
+#define FSI_MDLYR 0x4 /* R/W: delay */
+#define FSI_MCRSP 0x8 /* R/W: clock rate */
+#define FSI_MENP0 0x10 /* R/W: enable */
+#define FSI_MLEVP0 0x18 /* R: plug detect */
+#define FSI_MSENP0 0x18 /* S: Set enable */
+#define FSI_MCENP0 0x20 /* C: Clear enable */
+#define FSI_MAEB 0x70 /* R: Error address */
+#define FSI_MVER 0x74 /* R: master version/type */
+#define FSI_MSTAP0 0xd0 /* R: Port status */
+#define FSI_MRESP0 0xd0 /* W: Port reset */
+#define FSI_MESRB0 0x1d0 /* R: Master error status */
+#define FSI_MRESB0 0x1d0 /* W: Reset bridge */
+#define FSI_MSCSB0 0x1d4 /* R: Master sub command stack */
+#define FSI_MATRB0 0x1d8 /* R: Master address trace */
+#define FSI_MDTRB0 0x1dc /* R: Master data trace */
+#define FSI_MECTRL 0x2e0 /* W: Error control */
+
+/* MMODE: Mode control */
+#define FSI_MMODE_EIP 0x80000000 /* Enable interrupt polling */
+#define FSI_MMODE_ECRC 0x40000000 /* Enable error recovery */
+#define FSI_MMODE_RELA 0x20000000 /* Enable relative address commands */
+#define FSI_MMODE_EPC 0x10000000 /* Enable parity checking */
+#define FSI_MMODE_P8_TO_LSB 0x00000010 /* Timeout value LSB */
+ /* MSB=1, LSB=0 is 0.8 ms */
+ /* MSB=0, LSB=1 is 0.9 ms */
+#define FSI_MMODE_CRS0SHFT 18 /* Clk rate selection 0 shift */
+#define FSI_MMODE_CRS0MASK 0x3ff /* Clk rate selection 0 mask */
+#define FSI_MMODE_CRS1SHFT 8 /* Clk rate selection 1 shift */
+#define FSI_MMODE_CRS1MASK 0x3ff /* Clk rate selection 1 mask */
+
+/* MRESB: Reset brindge */
+#define FSI_MRESB_RST_GEN 0x80000000 /* General reset */
+#define FSI_MRESB_RST_ERR 0x40000000 /* Error Reset */
+
+/* MRESP: Reset port */
+#define FSI_MRESP_RST_ALL_MASTER 0x20000000 /* Reset all FSI masters */
+#define FSI_MRESP_RST_ALL_LINK 0x10000000 /* Reset all FSI port contr. */
+#define FSI_MRESP_RST_MCR 0x08000000 /* Reset FSI master reg. */
+#define FSI_MRESP_RST_PYE 0x04000000 /* Reset FSI parity error */
+#define FSI_MRESP_RST_ALL 0xfc000000 /* Reset any error */
+
+/* MECTRL: Error control */
+#define FSI_MECTRL_EOAE 0x8000 /* Enable machine check when */
+ /* master 0 in error */
+#define FSI_MECTRL_P8_AUTO_TERM 0x4000 /* Auto terminate */
+
+#define FSI_HUB_LINK_OFFSET 0x80000
+#define FSI_HUB_LINK_SIZE 0x80000
+#define FSI_HUB_MASTER_MAX_LINKS 8
+
+/*
+ * Protocol definitions
+ *
+ * These are used by low level masters that bit-bang out the protocol
+ */
+
/* Various protocol delays */
#define FSI_ECHO_DELAY_CLOCKS 16 /* Number clocks for echo delay */
#define FSI_SEND_DELAY_CLOCKS 16 /* Number clocks for send delay */
@@ -47,6 +112,12 @@
/* fsi-master definition and flags */
#define FSI_MASTER_FLAG_SWCLOCK 0x1
+/*
+ * Structures and function prototypes
+ *
+ * These are common to all masters
+ */
+
struct fsi_master {
struct device dev;
int idx;
diff --git a/drivers/fsi/fsi-occ.c b/drivers/fsi/fsi-occ.c
index 7da9c81759ac..942eff4032b0 100644
--- a/drivers/fsi/fsi-occ.c
+++ b/drivers/fsi/fsi-occ.c
@@ -14,6 +14,7 @@
#include <linux/mutex.h>
#include <linux/fsi-occ.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
#include <linux/slab.h>
@@ -24,8 +25,13 @@
#define OCC_CMD_DATA_BYTES 4090
#define OCC_RESP_DATA_BYTES 4089
-#define OCC_SRAM_CMD_ADDR 0xFFFBE000
-#define OCC_SRAM_RSP_ADDR 0xFFFBF000
+#define OCC_P9_SRAM_CMD_ADDR 0xFFFBE000
+#define OCC_P9_SRAM_RSP_ADDR 0xFFFBF000
+
+#define OCC_P10_SRAM_CMD_ADDR 0xFFFFD000
+#define OCC_P10_SRAM_RSP_ADDR 0xFFFFE000
+
+#define OCC_P10_SRAM_MODE 0x58 /* Normal mode, OCB channel 2 */
/*
* Assume we don't have much FFDC, if we do we'll overflow and
@@ -37,11 +43,14 @@
#define OCC_TIMEOUT_MS 1000
#define OCC_CMD_IN_PRG_WAIT_MS 50
+enum versions { occ_p9, occ_p10 };
+
struct occ {
struct device *dev;
struct device *sbefifo;
char name[32];
int idx;
+ enum versions version;
struct miscdevice mdev;
struct mutex occ_lock;
};
@@ -235,29 +244,43 @@ static int occ_verify_checksum(struct occ_response *resp, u16 data_length)
return 0;
}
-static int occ_getsram(struct occ *occ, u32 address, void *data, ssize_t len)
+static int occ_getsram(struct occ *occ, u32 offset, void *data, ssize_t len)
{
u32 data_len = ((len + 7) / 8) * 8; /* must be multiples of 8 B */
- size_t resp_len, resp_data_len;
- __be32 *resp, cmd[5];
- int rc;
+ size_t cmd_len, resp_len, resp_data_len;
+ __be32 *resp, cmd[6];
+ int idx = 0, rc;
/*
* Magic sequence to do SBE getsram command. SBE will fetch data from
* specified SRAM address.
*/
- cmd[0] = cpu_to_be32(0x5);
+ switch (occ->version) {
+ default:
+ case occ_p9:
+ cmd_len = 5;
+ cmd[2] = cpu_to_be32(1); /* Normal mode */
+ cmd[3] = cpu_to_be32(OCC_P9_SRAM_RSP_ADDR + offset);
+ break;
+ case occ_p10:
+ idx = 1;
+ cmd_len = 6;
+ cmd[2] = cpu_to_be32(OCC_P10_SRAM_MODE);
+ cmd[3] = 0;
+ cmd[4] = cpu_to_be32(OCC_P10_SRAM_RSP_ADDR + offset);
+ break;
+ }
+
+ cmd[0] = cpu_to_be32(cmd_len);
cmd[1] = cpu_to_be32(SBEFIFO_CMD_GET_OCC_SRAM);
- cmd[2] = cpu_to_be32(1);
- cmd[3] = cpu_to_be32(address);
- cmd[4] = cpu_to_be32(data_len);
+ cmd[4 + idx] = cpu_to_be32(data_len);
resp_len = (data_len >> 2) + OCC_SBE_STATUS_WORDS;
resp = kzalloc(resp_len << 2, GFP_KERNEL);
if (!resp)
return -ENOMEM;
- rc = sbefifo_submit(occ->sbefifo, cmd, 5, resp, &resp_len);
+ rc = sbefifo_submit(occ->sbefifo, cmd, cmd_len, resp, &resp_len);
if (rc)
goto free;
@@ -287,20 +310,21 @@ free:
return rc;
}
-static int occ_putsram(struct occ *occ, u32 address, const void *data,
- ssize_t len)
+static int occ_putsram(struct occ *occ, const void *data, ssize_t len)
{
size_t cmd_len, buf_len, resp_len, resp_data_len;
u32 data_len = ((len + 7) / 8) * 8; /* must be multiples of 8 B */
__be32 *buf;
- int rc;
+ int idx = 0, rc;
+
+ cmd_len = (occ->version == occ_p10) ? 6 : 5;
/*
* We use the same buffer for command and response, make
* sure it's big enough
*/
resp_len = OCC_SBE_STATUS_WORDS;
- cmd_len = (data_len >> 2) + 5;
+ cmd_len += data_len >> 2;
buf_len = max(cmd_len, resp_len);
buf = kzalloc(buf_len << 2, GFP_KERNEL);
if (!buf)
@@ -312,11 +336,23 @@ static int occ_putsram(struct occ *occ, u32 address, const void *data,
*/
buf[0] = cpu_to_be32(cmd_len);
buf[1] = cpu_to_be32(SBEFIFO_CMD_PUT_OCC_SRAM);
- buf[2] = cpu_to_be32(1);
- buf[3] = cpu_to_be32(address);
- buf[4] = cpu_to_be32(data_len);
- memcpy(&buf[5], data, len);
+ switch (occ->version) {
+ default:
+ case occ_p9:
+ buf[2] = cpu_to_be32(1); /* Normal mode */
+ buf[3] = cpu_to_be32(OCC_P9_SRAM_CMD_ADDR);
+ break;
+ case occ_p10:
+ idx = 1;
+ buf[2] = cpu_to_be32(OCC_P10_SRAM_MODE);
+ buf[3] = 0;
+ buf[4] = cpu_to_be32(OCC_P10_SRAM_CMD_ADDR);
+ break;
+ }
+
+ buf[4 + idx] = cpu_to_be32(data_len);
+ memcpy(&buf[5 + idx], data, len);
rc = sbefifo_submit(occ->sbefifo, buf, cmd_len, buf, &resp_len);
if (rc)
@@ -356,21 +392,35 @@ free:
static int occ_trigger_attn(struct occ *occ)
{
__be32 buf[OCC_SBE_STATUS_WORDS];
- size_t resp_len, resp_data_len;
- int rc;
+ size_t cmd_len, resp_len, resp_data_len;
+ int idx = 0, rc;
- BUILD_BUG_ON(OCC_SBE_STATUS_WORDS < 7);
+ BUILD_BUG_ON(OCC_SBE_STATUS_WORDS < 8);
resp_len = OCC_SBE_STATUS_WORDS;
- buf[0] = cpu_to_be32(0x5 + 0x2); /* Chip-op length in words */
+ switch (occ->version) {
+ default:
+ case occ_p9:
+ cmd_len = 7;
+ buf[2] = cpu_to_be32(3); /* Circular mode */
+ buf[3] = 0;
+ break;
+ case occ_p10:
+ idx = 1;
+ cmd_len = 8;
+ buf[2] = cpu_to_be32(0xd0); /* Circular mode, OCB Channel 1 */
+ buf[3] = 0;
+ buf[4] = 0;
+ break;
+ }
+
+ buf[0] = cpu_to_be32(cmd_len); /* Chip-op length in words */
buf[1] = cpu_to_be32(SBEFIFO_CMD_PUT_OCC_SRAM);
- buf[2] = cpu_to_be32(0x3); /* Mode: Circular */
- buf[3] = cpu_to_be32(0x0); /* Address: ignore in mode 3 */
- buf[4] = cpu_to_be32(0x8); /* Data length in bytes */
- buf[5] = cpu_to_be32(0x20010000); /* Trigger OCC attention */
- buf[6] = 0;
+ buf[4 + idx] = cpu_to_be32(8); /* Data length in bytes */
+ buf[5 + idx] = cpu_to_be32(0x20010000); /* Trigger OCC attention */
+ buf[6 + idx] = 0;
- rc = sbefifo_submit(occ->sbefifo, buf, 7, buf, &resp_len);
+ rc = sbefifo_submit(occ->sbefifo, buf, cmd_len, buf, &resp_len);
if (rc)
goto error;
@@ -429,7 +479,7 @@ int fsi_occ_submit(struct device *dev, const void *request, size_t req_len,
/* Extract the seq_no from the command (first byte) */
seq_no = *(const u8 *)request;
- rc = occ_putsram(occ, OCC_SRAM_CMD_ADDR, request, req_len);
+ rc = occ_putsram(occ, request, req_len);
if (rc)
goto done;
@@ -440,7 +490,7 @@ int fsi_occ_submit(struct device *dev, const void *request, size_t req_len,
/* Read occ response header */
start = jiffies;
do {
- rc = occ_getsram(occ, OCC_SRAM_RSP_ADDR, resp, 8);
+ rc = occ_getsram(occ, 0, resp, 8);
if (rc)
goto done;
@@ -476,8 +526,7 @@ int fsi_occ_submit(struct device *dev, const void *request, size_t req_len,
/* Grab the rest */
if (resp_data_length > 1) {
/* already got 3 bytes resp, also need 2 bytes checksum */
- rc = occ_getsram(occ, OCC_SRAM_RSP_ADDR + 8,
- &resp->data[3], resp_data_length - 1);
+ rc = occ_getsram(occ, 8, &resp->data[3], resp_data_length - 1);
if (rc)
goto done;
}
@@ -508,6 +557,7 @@ static int occ_probe(struct platform_device *pdev)
struct occ *occ;
struct platform_device *hwmon_dev;
struct device *dev = &pdev->dev;
+ const void *md = of_device_get_match_data(dev);
struct platform_device_info hwmon_dev_info = {
.parent = dev,
.name = "occ-hwmon",
@@ -517,6 +567,7 @@ static int occ_probe(struct platform_device *pdev)
if (!occ)
return -ENOMEM;
+ occ->version = (enum versions)md;
occ->dev = dev;
occ->sbefifo = dev->parent;
mutex_init(&occ->occ_lock);
@@ -575,7 +626,14 @@ static int occ_remove(struct platform_device *pdev)
}
static const struct of_device_id occ_match[] = {
- { .compatible = "ibm,p9-occ" },
+ {
+ .compatible = "ibm,p9-occ",
+ .data = (void *)occ_p9
+ },
+ {
+ .compatible = "ibm,p10-occ",
+ .data = (void *)occ_p10
+ },
{ },
};
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index f9263426af03..5665ecc139e9 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -120,6 +120,14 @@ config GPIO_ASPEED
help
Say Y here to support Aspeed AST2400 and AST2500 GPIO controllers.
+config GPIO_ASPEED_SGPIO
+ bool "Aspeed SGPIO support"
+ depends on (ARCH_ASPEED || COMPILE_TEST) && OF_GPIO
+ select GPIO_GENERIC
+ select GPIOLIB_IRQCHIP
+ help
+ Say Y here to support Aspeed AST2500 SGPIO functionality.
+
config GPIO_ATH79
tristate "Atheros AR71XX/AR724X/AR913X GPIO support"
default y if ATH79
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index d2fd19c15bae..e4599f90f702 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_GPIO_AMD_FCH) += gpio-amd-fch.o
obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o
obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o
obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.o
+obj-$(CONFIG_GPIO_ASPEED_SGPIO) += gpio-aspeed-sgpio.o
obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o
obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
obj-$(CONFIG_GPIO_BD70528) += gpio-bd70528.o
diff --git a/drivers/gpio/sgpio-aspeed.c b/drivers/gpio/gpio-aspeed-sgpio.c
index 8319812593e3..8319812593e3 100644
--- a/drivers/gpio/sgpio-aspeed.c
+++ b/drivers/gpio/gpio-aspeed-sgpio.c
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 13a6b4afb4b3..e244a7901392 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1322,6 +1322,34 @@ config SENSORS_PCF8591
These devices are hard to detect and rarely found on mainstream
hardware. If unsure, say N.
+config SENSORS_PECI_CPUTEMP
+ tristate "PECI CPU temperature monitoring client"
+ depends on PECI
+ select MFD_INTEL_PECI_CLIENT
+ help
+ If you say yes here you get support for the generic Intel PECI
+ cputemp driver which provides Digital Thermal Sensor (DTS) thermal
+ readings of the CPU package and CPU cores that are accessible using
+ the PECI Client Command Suite via the processor PECI client.
+ Check <file:Documentation/hwmon/peci-cputemp.rst> for details.
+
+ This driver can also be built as a module. If so, the module
+ will be called peci-cputemp.
+
+config SENSORS_PECI_DIMMTEMP
+ tristate "PECI DIMM temperature monitoring client"
+ depends on PECI
+ select MFD_INTEL_PECI_CLIENT
+ help
+ If you say yes here you get support for the generic Intel PECI hwmon
+ driver which provides Digital Thermal Sensor (DTS) thermal readings of
+ DIMM components that are accessible using the PECI Client Command
+ Suite via the processor PECI client.
+ Check <file:Documentation/hwmon/peci-dimmtemp.rst> for details.
+
+ This driver can also be built as a module. If so, the module
+ will be called peci-dimmtemp.
+
source "drivers/hwmon/pmbus/Kconfig"
config SENSORS_PWM_FAN
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 40c036ea45e6..1c7ab361adc7 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -141,6 +141,8 @@ obj-$(CONFIG_SENSORS_NTC_THERMISTOR) += ntc_thermistor.o
obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
+obj-$(CONFIG_SENSORS_PECI_CPUTEMP) += peci-cputemp.o
+obj-$(CONFIG_SENSORS_PECI_DIMMTEMP) += peci-dimmtemp.o
obj-$(CONFIG_SENSORS_POWR1220) += powr1220.o
obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o
obj-$(CONFIG_SENSORS_RASPBERRYPI_HWMON) += raspberrypi-hwmon.o
diff --git a/drivers/hwmon/occ/common.c b/drivers/hwmon/occ/common.c
index 30e18eb60da7..3e580a83ae61 100644
--- a/drivers/hwmon/occ/common.c
+++ b/drivers/hwmon/occ/common.c
@@ -41,6 +41,14 @@ struct temp_sensor_2 {
u8 value;
} __packed;
+struct temp_sensor_10 {
+ u32 sensor_id;
+ u8 fru_type;
+ u8 value;
+ u8 throttle;
+ u8 reserved;
+} __packed;
+
struct freq_sensor_1 {
u16 sensor_id;
u16 value;
@@ -307,6 +315,60 @@ static ssize_t occ_show_temp_2(struct device *dev,
return snprintf(buf, PAGE_SIZE - 1, "%u\n", val);
}
+static ssize_t occ_show_temp_10(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int rc;
+ u32 val = 0;
+ struct temp_sensor_10 *temp;
+ struct occ *occ = dev_get_drvdata(dev);
+ struct occ_sensors *sensors = &occ->sensors;
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+
+ rc = occ_update_response(occ);
+ if (rc)
+ return rc;
+
+ temp = ((struct temp_sensor_10 *)sensors->temp.data) + sattr->index;
+
+ switch (sattr->nr) {
+ case 0:
+ val = get_unaligned_be32(&temp->sensor_id);
+ break;
+ case 1:
+ val = temp->value;
+ if (val == OCC_TEMP_SENSOR_FAULT)
+ return -EREMOTEIO;
+
+ /*
+ * VRM doesn't return temperature, only alarm bit. This
+ * attribute maps to tempX_alarm instead of tempX_input for
+ * VRM
+ */
+ if (temp->fru_type != OCC_FRU_TYPE_VRM) {
+ /* sensor not ready */
+ if (val == 0)
+ return -EAGAIN;
+
+ val *= 1000;
+ }
+ break;
+ case 2:
+ val = temp->fru_type;
+ break;
+ case 3:
+ val = temp->value == OCC_TEMP_SENSOR_FAULT;
+ break;
+ case 4:
+ val = temp->throttle * 1000;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return snprintf(buf, PAGE_SIZE - 1, "%u\n", val);
+}
+
static ssize_t occ_show_freq_1(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -745,6 +807,9 @@ static int occ_setup_sensor_attrs(struct occ *occ)
num_attrs += (sensors->temp.num_sensors * 4);
show_temp = occ_show_temp_2;
break;
+ case 0x10:
+ show_temp = occ_show_temp_10;
+ break;
default:
sensors->temp.num_sensors = 0;
}
diff --git a/drivers/hwmon/peci-cputemp.c b/drivers/hwmon/peci-cputemp.c
new file mode 100644
index 000000000000..b9fe91281d58
--- /dev/null
+++ b/drivers/hwmon/peci-cputemp.c
@@ -0,0 +1,472 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018-2019 Intel Corporation
+
+#include <linux/hwmon.h>
+#include <linux/jiffies.h>
+#include <linux/mfd/intel-peci-client.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include "peci-hwmon.h"
+
+#define DEFAULT_CHANNEL_NUMS 5
+#define CORETEMP_CHANNEL_NUMS CORE_NUMS_MAX
+#define CPUTEMP_CHANNEL_NUMS (DEFAULT_CHANNEL_NUMS + CORETEMP_CHANNEL_NUMS)
+
+struct temp_group {
+ struct peci_sensor_data die;
+ struct peci_sensor_data dts;
+ struct peci_sensor_data tcontrol;
+ struct peci_sensor_data tthrottle;
+ struct peci_sensor_data tjmax;
+ struct peci_sensor_data core[CORETEMP_CHANNEL_NUMS];
+};
+
+struct peci_cputemp {
+ struct peci_client_manager *mgr;
+ struct device *dev;
+ char name[PECI_NAME_SIZE];
+ const struct cpu_gen_info *gen_info;
+ struct temp_group temp;
+ u64 core_mask;
+ u32 temp_config[CPUTEMP_CHANNEL_NUMS + 1];
+ uint config_idx;
+ struct hwmon_channel_info temp_info;
+ const struct hwmon_channel_info *info[2];
+ struct hwmon_chip_info chip;
+ char **coretemp_label;
+};
+
+enum cputemp_channels {
+ channel_die,
+ channel_dts,
+ channel_tcontrol,
+ channel_tthrottle,
+ channel_tjmax,
+ channel_core,
+};
+
+static const u32 config_table[DEFAULT_CHANNEL_NUMS + 1] = {
+ /* Die temperature */
+ HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_CRIT_HYST,
+
+ /* DTS margin */
+ HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_CRIT_HYST,
+
+ /* Tcontrol temperature */
+ HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_CRIT,
+
+ /* Tthrottle temperature */
+ HWMON_T_LABEL | HWMON_T_INPUT,
+
+ /* Tjmax temperature */
+ HWMON_T_LABEL | HWMON_T_INPUT,
+
+ /* Core temperature - for all core channels */
+ HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
+ HWMON_T_CRIT_HYST,
+};
+
+static const char *cputemp_label[DEFAULT_CHANNEL_NUMS] = {
+ "Die",
+ "DTS",
+ "Tcontrol",
+ "Tthrottle",
+ "Tjmax"
+};
+
+static s32 ten_dot_six_to_millidegree(s32 val)
+{
+ return ((val ^ 0x8000) - 0x8000) * 1000 / 64;
+}
+
+static int get_temp_targets(struct peci_cputemp *priv)
+{
+ s32 tthrottle_offset;
+ s32 tcontrol_margin;
+ u8 pkg_cfg[4];
+ int ret;
+
+ /*
+ * Just use only the tcontrol marker to determine if target values need
+ * update.
+ */
+ if (!peci_sensor_need_update(&priv->temp.tcontrol))
+ return 0;
+
+ ret = peci_client_read_package_config(priv->mgr,
+ PECI_MBX_INDEX_TEMP_TARGET, 0,
+ pkg_cfg);
+ if (ret)
+ return ret;
+
+ priv->temp.tjmax.value = pkg_cfg[2] * 1000;
+
+ tcontrol_margin = pkg_cfg[1];
+ tcontrol_margin = ((tcontrol_margin ^ 0x80) - 0x80) * 1000;
+ priv->temp.tcontrol.value = priv->temp.tjmax.value - tcontrol_margin;
+
+ tthrottle_offset = (pkg_cfg[3] & 0x2f) * 1000;
+ priv->temp.tthrottle.value = priv->temp.tjmax.value - tthrottle_offset;
+
+ peci_sensor_mark_updated(&priv->temp.tcontrol);
+
+ return 0;
+}
+
+static int get_die_temp(struct peci_cputemp *priv)
+{
+ struct peci_get_temp_msg msg;
+ int ret;
+
+ if (!peci_sensor_need_update(&priv->temp.die))
+ return 0;
+
+ msg.addr = priv->mgr->client->addr;
+
+ ret = peci_command(priv->mgr->client->adapter, PECI_CMD_GET_TEMP, &msg);
+ if (ret)
+ return ret;
+
+ /* Note that the tjmax should be available before calling it */
+ priv->temp.die.value = priv->temp.tjmax.value +
+ (msg.temp_raw * 1000 / 64);
+
+ peci_sensor_mark_updated(&priv->temp.die);
+
+ return 0;
+}
+
+static int get_dts(struct peci_cputemp *priv)
+{
+ s32 dts_margin;
+ u8 pkg_cfg[4];
+ int ret;
+
+ if (!peci_sensor_need_update(&priv->temp.dts))
+ return 0;
+
+ ret = peci_client_read_package_config(priv->mgr,
+ PECI_MBX_INDEX_DTS_MARGIN, 0,
+ pkg_cfg);
+
+ if (ret)
+ return ret;
+
+ dts_margin = le16_to_cpup((__le16 *)pkg_cfg);
+
+ /**
+ * Processors return a value of DTS reading in 10.6 format
+ * (10 bits signed decimal, 6 bits fractional).
+ * Error codes:
+ * 0x8000: General sensor error
+ * 0x8001: Reserved
+ * 0x8002: Underflow on reading value
+ * 0x8003-0x81ff: Reserved
+ */
+ if (dts_margin >= 0x8000 && dts_margin <= 0x81ff)
+ return -EIO;
+
+ dts_margin = ten_dot_six_to_millidegree(dts_margin);
+
+ /* Note that the tcontrol should be available before calling it */
+ priv->temp.dts.value = priv->temp.tcontrol.value - dts_margin;
+
+ peci_sensor_mark_updated(&priv->temp.dts);
+
+ return 0;
+}
+
+static int get_core_temp(struct peci_cputemp *priv, int core_index)
+{
+ s32 core_dts_margin;
+ u8 pkg_cfg[4];
+ int ret;
+
+ if (!peci_sensor_need_update(&priv->temp.core[core_index]))
+ return 0;
+
+ ret = peci_client_read_package_config(priv->mgr,
+ PECI_MBX_INDEX_PER_CORE_DTS_TEMP,
+ core_index, pkg_cfg);
+ if (ret)
+ return ret;
+
+ core_dts_margin = le16_to_cpup((__le16 *)pkg_cfg);
+
+ /*
+ * Processors return a value of the core DTS reading in 10.6 format
+ * (10 bits signed decimal, 6 bits fractional).
+ * Error codes:
+ * 0x8000: General sensor error
+ * 0x8001: Reserved
+ * 0x8002: Underflow on reading value
+ * 0x8003-0x81ff: Reserved
+ */
+ if (core_dts_margin >= 0x8000 && core_dts_margin <= 0x81ff)
+ return -EIO;
+
+ core_dts_margin = ten_dot_six_to_millidegree(core_dts_margin);
+
+ /* Note that the tjmax should be available before calling it */
+ priv->temp.core[core_index].value = priv->temp.tjmax.value +
+ core_dts_margin;
+
+ peci_sensor_mark_updated(&priv->temp.core[core_index]);
+
+ return 0;
+}
+
+static int cputemp_read_string(struct device *dev,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel, const char **str)
+{
+ struct peci_cputemp *priv = dev_get_drvdata(dev);
+
+ if (attr != hwmon_temp_label)
+ return -EOPNOTSUPP;
+
+ *str = (channel < DEFAULT_CHANNEL_NUMS) ?
+ cputemp_label[channel] :
+ (const char *)priv->coretemp_label[channel -
+ DEFAULT_CHANNEL_NUMS];
+
+ return 0;
+}
+
+static int cputemp_read(struct device *dev,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ struct peci_cputemp *priv = dev_get_drvdata(dev);
+ int ret, core_index;
+
+ if (channel >= CPUTEMP_CHANNEL_NUMS ||
+ !(priv->temp_config[channel] & BIT(attr)))
+ return -EOPNOTSUPP;
+
+ ret = get_temp_targets(priv);
+ if (ret)
+ return ret;
+
+ switch (attr) {
+ case hwmon_temp_input:
+ switch (channel) {
+ case channel_die:
+ ret = get_die_temp(priv);
+ if (ret)
+ break;
+
+ *val = priv->temp.die.value;
+ break;
+ case channel_dts:
+ ret = get_dts(priv);
+ if (ret)
+ break;
+
+ *val = priv->temp.dts.value;
+ break;
+ case channel_tcontrol:
+ *val = priv->temp.tcontrol.value;
+ break;
+ case channel_tthrottle:
+ *val = priv->temp.tthrottle.value;
+ break;
+ case channel_tjmax:
+ *val = priv->temp.tjmax.value;
+ break;
+ default:
+ core_index = channel - DEFAULT_CHANNEL_NUMS;
+ ret = get_core_temp(priv, core_index);
+ if (ret)
+ break;
+
+ *val = priv->temp.core[core_index].value;
+ break;
+ }
+ break;
+ case hwmon_temp_max:
+ *val = priv->temp.tcontrol.value;
+ break;
+ case hwmon_temp_crit:
+ *val = priv->temp.tjmax.value;
+ break;
+ case hwmon_temp_crit_hyst:
+ *val = priv->temp.tjmax.value - priv->temp.tcontrol.value;
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ return ret;
+}
+
+static umode_t cputemp_is_visible(const void *data,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ const struct peci_cputemp *priv = data;
+
+ if (channel < ARRAY_SIZE(priv->temp_config) &&
+ (priv->temp_config[channel] & BIT(attr)) &&
+ (channel < DEFAULT_CHANNEL_NUMS ||
+ (channel >= DEFAULT_CHANNEL_NUMS &&
+ (priv->core_mask & BIT(channel - DEFAULT_CHANNEL_NUMS)))))
+ return 0444;
+
+ return 0;
+}
+
+static const struct hwmon_ops cputemp_ops = {
+ .is_visible = cputemp_is_visible,
+ .read_string = cputemp_read_string,
+ .read = cputemp_read,
+};
+
+static int check_resolved_cores(struct peci_cputemp *priv)
+{
+ struct peci_rd_pci_cfg_local_msg msg;
+ int ret;
+
+ /* Get the RESOLVED_CORES register value */
+ msg.addr = priv->mgr->client->addr;
+ msg.device = 30;
+ msg.function = 3;
+ msg.rx_len = 4;
+ msg.bus = 1;
+ msg.reg = 0xb4;
+
+ ret = peci_command(priv->mgr->client->adapter,
+ PECI_CMD_RD_PCI_CFG_LOCAL, &msg);
+ if (msg.cc != PECI_DEV_CC_SUCCESS)
+ ret = -EAGAIN;
+ if (ret)
+ return ret;
+
+ priv->core_mask = le32_to_cpup((__le32 *)msg.pci_config);
+ if (!priv->core_mask)
+ return -EAGAIN;
+
+ dev_dbg(priv->dev, "Scanned resolved cores: 0x%llx\n", priv->core_mask);
+
+ return 0;
+}
+
+static int create_core_temp_label(struct peci_cputemp *priv, int idx)
+{
+ priv->coretemp_label[idx] = devm_kzalloc(priv->dev,
+ PECI_HWMON_LABEL_STR_LEN,
+ GFP_KERNEL);
+ if (!priv->coretemp_label[idx])
+ return -ENOMEM;
+
+ sprintf(priv->coretemp_label[idx], "Core %d", idx + 1);
+
+ return 0;
+}
+
+static int create_core_temp_info(struct peci_cputemp *priv)
+{
+ int ret, i;
+
+ ret = check_resolved_cores(priv);
+ if (ret)
+ return ret;
+
+ priv->coretemp_label = devm_kzalloc(priv->dev,
+ priv->gen_info->core_max *
+ sizeof(char *),
+ GFP_KERNEL);
+ if (!priv->coretemp_label)
+ return -ENOMEM;
+
+ for (i = 0; i < priv->gen_info->core_max; i++)
+ if (priv->core_mask & BIT(i)) {
+ while (priv->config_idx <= i + DEFAULT_CHANNEL_NUMS)
+ priv->temp_config[priv->config_idx++] =
+ config_table[channel_core];
+
+ ret = create_core_temp_label(priv, i);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int peci_cputemp_probe(struct platform_device *pdev)
+{
+ struct peci_client_manager *mgr = dev_get_drvdata(pdev->dev.parent);
+ struct device *dev = &pdev->dev;
+ struct peci_cputemp *priv;
+ struct device *hwmon_dev;
+ int ret;
+
+ if ((mgr->client->adapter->cmd_mask &
+ (BIT(PECI_CMD_GET_TEMP) | BIT(PECI_CMD_RD_PKG_CFG))) !=
+ (BIT(PECI_CMD_GET_TEMP) | BIT(PECI_CMD_RD_PKG_CFG)))
+ return -ENODEV;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, priv);
+ priv->mgr = mgr;
+ priv->dev = dev;
+ priv->gen_info = mgr->gen_info;
+
+ snprintf(priv->name, PECI_NAME_SIZE, "peci_cputemp.cpu%d",
+ mgr->client->addr - PECI_BASE_ADDR);
+
+ priv->temp_config[priv->config_idx++] = config_table[channel_die];
+ priv->temp_config[priv->config_idx++] = config_table[channel_dts];
+ priv->temp_config[priv->config_idx++] = config_table[channel_tcontrol];
+ priv->temp_config[priv->config_idx++] = config_table[channel_tthrottle];
+ priv->temp_config[priv->config_idx++] = config_table[channel_tjmax];
+
+ ret = create_core_temp_info(priv);
+ if (ret)
+ dev_dbg(dev, "Skipped creating core temp info\n");
+
+ priv->chip.ops = &cputemp_ops;
+ priv->chip.info = priv->info;
+
+ priv->info[0] = &priv->temp_info;
+
+ priv->temp_info.type = hwmon_temp;
+ priv->temp_info.config = priv->temp_config;
+
+ hwmon_dev = devm_hwmon_device_register_with_info(priv->dev,
+ priv->name,
+ priv,
+ &priv->chip,
+ NULL);
+
+ if (IS_ERR(hwmon_dev))
+ return PTR_ERR(hwmon_dev);
+
+ dev_dbg(dev, "%s: sensor '%s'\n", dev_name(hwmon_dev), priv->name);
+
+ return 0;
+}
+
+static const struct platform_device_id peci_cputemp_ids[] = {
+ { .name = "peci-cputemp", .driver_data = 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, peci_cputemp_ids);
+
+static struct platform_driver peci_cputemp_driver = {
+ .probe = peci_cputemp_probe,
+ .id_table = peci_cputemp_ids,
+ .driver = { .name = KBUILD_MODNAME, },
+};
+module_platform_driver(peci_cputemp_driver);
+
+MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
+MODULE_DESCRIPTION("PECI cputemp driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hwmon/peci-dimmtemp.c b/drivers/hwmon/peci-dimmtemp.c
new file mode 100644
index 000000000000..45eabd2ec5c8
--- /dev/null
+++ b/drivers/hwmon/peci-dimmtemp.c
@@ -0,0 +1,425 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018-2019 Intel Corporation
+
+#include <linux/hwmon.h>
+#include <linux/jiffies.h>
+#include <linux/mfd/intel-peci-client.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+#include "peci-hwmon.h"
+
+#define DIMM_MASK_CHECK_DELAY_JIFFIES msecs_to_jiffies(5000)
+#define DIMM_MASK_CHECK_RETRY_MAX 60 /* 60 x 5 secs = 5 minutes */
+
+struct peci_dimmtemp {
+ struct peci_client_manager *mgr;
+ struct device *dev;
+ char name[PECI_NAME_SIZE];
+ const struct cpu_gen_info *gen_info;
+ struct workqueue_struct *work_queue;
+ struct delayed_work work_handler;
+ struct peci_sensor_data temp[DIMM_NUMS_MAX];
+ long temp_max[DIMM_NUMS_MAX];
+ long temp_crit[DIMM_NUMS_MAX];
+ u32 dimm_mask;
+ int retry_count;
+ u32 temp_config[DIMM_NUMS_MAX + 1];
+ struct hwmon_channel_info temp_info;
+ const struct hwmon_channel_info *info[2];
+ struct hwmon_chip_info chip;
+ char **dimmtemp_label;
+};
+
+static const u8 support_model[] = {
+ INTEL_FAM6_HASWELL_X,
+ INTEL_FAM6_BROADWELL_X,
+ INTEL_FAM6_SKYLAKE_X,
+ INTEL_FAM6_SKYLAKE_XD,
+};
+
+static inline int read_ddr_dimm_temp_config(struct peci_dimmtemp *priv,
+ int chan_rank,
+ u8 *cfg_data)
+{
+ return peci_client_read_package_config(priv->mgr,
+ PECI_MBX_INDEX_DDR_DIMM_TEMP,
+ chan_rank, cfg_data);
+}
+
+static int get_dimm_temp(struct peci_dimmtemp *priv, int dimm_no)
+{
+ int dimm_order = dimm_no % priv->gen_info->dimm_idx_max;
+ int chan_rank = dimm_no / priv->gen_info->dimm_idx_max;
+ struct peci_rd_pci_cfg_local_msg rp_msg;
+ u8 cfg_data[4];
+ int ret;
+
+ if (!peci_sensor_need_update(&priv->temp[dimm_no]))
+ return 0;
+
+ ret = read_ddr_dimm_temp_config(priv, chan_rank, cfg_data);
+ if (ret)
+ return ret;
+
+ priv->temp[dimm_no].value = cfg_data[dimm_order] * 1000;
+
+ switch (priv->gen_info->model) {
+ case INTEL_FAM6_SKYLAKE_X:
+ rp_msg.addr = priv->mgr->client->addr;
+ rp_msg.bus = 2;
+ /*
+ * Device 10, Function 2: IMC 0 channel 0 -> rank 0
+ * Device 10, Function 6: IMC 0 channel 1 -> rank 1
+ * Device 11, Function 2: IMC 0 channel 2 -> rank 2
+ * Device 12, Function 2: IMC 1 channel 0 -> rank 3
+ * Device 12, Function 6: IMC 1 channel 1 -> rank 4
+ * Device 13, Function 2: IMC 1 channel 2 -> rank 5
+ */
+ rp_msg.device = 10 + chan_rank / 3 * 2 +
+ (chan_rank % 3 == 2 ? 1 : 0);
+ rp_msg.function = chan_rank % 3 == 1 ? 6 : 2;
+ rp_msg.reg = 0x120 + dimm_order * 4;
+ rp_msg.rx_len = 4;
+
+ ret = peci_command(priv->mgr->client->adapter,
+ PECI_CMD_RD_PCI_CFG_LOCAL, &rp_msg);
+ if (rp_msg.cc != PECI_DEV_CC_SUCCESS)
+ ret = -EAGAIN;
+ if (ret)
+ return ret;
+
+ priv->temp_max[dimm_no] = rp_msg.pci_config[1] * 1000;
+ priv->temp_crit[dimm_no] = rp_msg.pci_config[2] * 1000;
+ break;
+ case INTEL_FAM6_SKYLAKE_XD:
+ rp_msg.addr = priv->mgr->client->addr;
+ rp_msg.bus = 2;
+ /*
+ * Device 10, Function 2: IMC 0 channel 0 -> rank 0
+ * Device 10, Function 6: IMC 0 channel 1 -> rank 1
+ * Device 12, Function 2: IMC 1 channel 0 -> rank 2
+ * Device 12, Function 6: IMC 1 channel 1 -> rank 3
+ */
+ rp_msg.device = 10 + chan_rank / 2 * 2;
+ rp_msg.function = (chan_rank % 2) ? 6 : 2;
+ rp_msg.reg = 0x120 + dimm_order * 4;
+ rp_msg.rx_len = 4;
+
+ ret = peci_command(priv->mgr->client->adapter,
+ PECI_CMD_RD_PCI_CFG_LOCAL, &rp_msg);
+ if (rp_msg.cc != PECI_DEV_CC_SUCCESS)
+ ret = -EAGAIN;
+ if (ret)
+ return ret;
+
+ priv->temp_max[dimm_no] = rp_msg.pci_config[1] * 1000;
+ priv->temp_crit[dimm_no] = rp_msg.pci_config[2] * 1000;
+ break;
+ case INTEL_FAM6_HASWELL_X:
+ case INTEL_FAM6_BROADWELL_X:
+ rp_msg.addr = priv->mgr->client->addr;
+ rp_msg.bus = 1;
+ /*
+ * Device 20, Function 0: IMC 0 channel 0 -> rank 0
+ * Device 20, Function 1: IMC 0 channel 1 -> rank 1
+ * Device 21, Function 0: IMC 0 channel 2 -> rank 2
+ * Device 21, Function 1: IMC 0 channel 3 -> rank 3
+ * Device 23, Function 0: IMC 1 channel 0 -> rank 4
+ * Device 23, Function 1: IMC 1 channel 1 -> rank 5
+ * Device 24, Function 0: IMC 1 channel 2 -> rank 6
+ * Device 24, Function 1: IMC 1 channel 3 -> rank 7
+ */
+ rp_msg.device = 20 + chan_rank / 2 + chan_rank / 4;
+ rp_msg.function = chan_rank % 2;
+ rp_msg.reg = 0x120 + dimm_order * 4;
+ rp_msg.rx_len = 4;
+
+ ret = peci_command(priv->mgr->client->adapter,
+ PECI_CMD_RD_PCI_CFG_LOCAL, &rp_msg);
+ if (rp_msg.cc != PECI_DEV_CC_SUCCESS)
+ ret = -EAGAIN;
+ if (ret)
+ return ret;
+
+ priv->temp_max[dimm_no] = rp_msg.pci_config[1] * 1000;
+ priv->temp_crit[dimm_no] = rp_msg.pci_config[2] * 1000;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ peci_sensor_mark_updated(&priv->temp[dimm_no]);
+
+ return 0;
+}
+
+static int dimmtemp_read_string(struct device *dev,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel, const char **str)
+{
+ struct peci_dimmtemp *priv = dev_get_drvdata(dev);
+
+ if (attr != hwmon_temp_label)
+ return -EOPNOTSUPP;
+
+ *str = (const char *)priv->dimmtemp_label[channel];
+
+ return 0;
+}
+
+static int dimmtemp_read(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ struct peci_dimmtemp *priv = dev_get_drvdata(dev);
+ int ret;
+
+ ret = get_dimm_temp(priv, channel);
+ if (ret)
+ return ret;
+
+ switch (attr) {
+ case hwmon_temp_input:
+ *val = priv->temp[channel].value;
+ break;
+ case hwmon_temp_max:
+ *val = priv->temp_max[channel];
+ break;
+ case hwmon_temp_crit:
+ *val = priv->temp_crit[channel];
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ return ret;
+}
+
+static umode_t dimmtemp_is_visible(const void *data,
+ enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ const struct peci_dimmtemp *priv = data;
+
+ if (priv->temp_config[channel] & BIT(attr) &&
+ priv->dimm_mask & BIT(channel))
+ return 0444;
+
+ return 0;
+}
+
+static const struct hwmon_ops dimmtemp_ops = {
+ .is_visible = dimmtemp_is_visible,
+ .read_string = dimmtemp_read_string,
+ .read = dimmtemp_read,
+};
+
+static int check_populated_dimms(struct peci_dimmtemp *priv)
+{
+ u32 chan_rank_max = priv->gen_info->chan_rank_max;
+ u32 dimm_idx_max = priv->gen_info->dimm_idx_max;
+ int chan_rank, dimm_idx;
+ u8 cfg_data[4];
+
+ for (chan_rank = 0; chan_rank < chan_rank_max; chan_rank++) {
+ int ret;
+
+ ret = read_ddr_dimm_temp_config(priv, chan_rank, cfg_data);
+ if (ret) {
+ priv->dimm_mask = 0;
+ return ret;
+ }
+
+ for (dimm_idx = 0; dimm_idx < dimm_idx_max; dimm_idx++)
+ if (cfg_data[dimm_idx])
+ priv->dimm_mask |= BIT(chan_rank *
+ dimm_idx_max +
+ dimm_idx);
+ }
+
+ if (!priv->dimm_mask)
+ return -EAGAIN;
+
+ dev_dbg(priv->dev, "Scanned populated DIMMs: 0x%x\n", priv->dimm_mask);
+
+ return 0;
+}
+
+static int create_dimm_temp_label(struct peci_dimmtemp *priv, int chan)
+{
+ int rank, idx;
+
+ priv->dimmtemp_label[chan] = devm_kzalloc(priv->dev,
+ PECI_HWMON_LABEL_STR_LEN,
+ GFP_KERNEL);
+ if (!priv->dimmtemp_label[chan])
+ return -ENOMEM;
+
+ rank = chan / priv->gen_info->dimm_idx_max;
+ idx = chan % priv->gen_info->dimm_idx_max;
+
+ sprintf(priv->dimmtemp_label[chan], "DIMM %c%d", 'A' + rank, idx + 1);
+
+ return 0;
+}
+
+static int create_dimm_temp_info(struct peci_dimmtemp *priv)
+{
+ int ret, i, config_idx, channels;
+ struct device *dev;
+
+ ret = check_populated_dimms(priv);
+ if (ret) {
+ if (ret == -EAGAIN) {
+ if (priv->retry_count < DIMM_MASK_CHECK_RETRY_MAX) {
+ queue_delayed_work(priv->work_queue,
+ &priv->work_handler,
+ DIMM_MASK_CHECK_DELAY_JIFFIES);
+ priv->retry_count++;
+ dev_dbg(priv->dev,
+ "Deferred DIMM temp info creation\n");
+ } else {
+ dev_err(priv->dev,
+ "Timeout DIMM temp info creation\n");
+ ret = -ETIMEDOUT;
+ }
+ }
+
+ return ret;
+ }
+
+ channels = priv->gen_info->chan_rank_max *
+ priv->gen_info->dimm_idx_max;
+
+ priv->dimmtemp_label = devm_kzalloc(priv->dev,
+ channels * sizeof(char *),
+ GFP_KERNEL);
+ if (!priv->dimmtemp_label)
+ return -ENOMEM;
+
+ for (i = 0, config_idx = 0; i < channels; i++)
+ if (priv->dimm_mask & BIT(i)) {
+ while (i >= config_idx)
+ priv->temp_config[config_idx++] =
+ HWMON_T_LABEL | HWMON_T_INPUT |
+ HWMON_T_MAX | HWMON_T_CRIT;
+
+ ret = create_dimm_temp_label(priv, i);
+ if (ret)
+ return ret;
+ }
+
+ priv->chip.ops = &dimmtemp_ops;
+ priv->chip.info = priv->info;
+
+ priv->info[0] = &priv->temp_info;
+
+ priv->temp_info.type = hwmon_temp;
+ priv->temp_info.config = priv->temp_config;
+
+ dev = devm_hwmon_device_register_with_info(priv->dev,
+ priv->name,
+ priv,
+ &priv->chip,
+ NULL);
+ if (IS_ERR(dev)) {
+ dev_err(priv->dev, "Failed to register hwmon device\n");
+ return PTR_ERR(dev);
+ }
+
+ dev_dbg(priv->dev, "%s: sensor '%s'\n", dev_name(dev), priv->name);
+
+ return 0;
+}
+
+static void create_dimm_temp_info_delayed(struct work_struct *work)
+{
+ struct delayed_work *dwork = to_delayed_work(work);
+ struct peci_dimmtemp *priv = container_of(dwork, struct peci_dimmtemp,
+ work_handler);
+ int ret;
+
+ ret = create_dimm_temp_info(priv);
+ if (ret && ret != -EAGAIN)
+ dev_dbg(priv->dev, "Failed to create DIMM temp info\n");
+}
+
+static int peci_dimmtemp_probe(struct platform_device *pdev)
+{
+ struct peci_client_manager *mgr = dev_get_drvdata(pdev->dev.parent);
+ struct device *dev = &pdev->dev;
+ struct peci_dimmtemp *priv;
+ int ret, i;
+
+ if ((mgr->client->adapter->cmd_mask &
+ (BIT(PECI_CMD_GET_TEMP) | BIT(PECI_CMD_RD_PKG_CFG))) !=
+ (BIT(PECI_CMD_GET_TEMP) | BIT(PECI_CMD_RD_PKG_CFG)))
+ return -ENODEV;
+
+ for (i = 0; i < ARRAY_SIZE(support_model); i++) {
+ if (mgr->gen_info->model == support_model[i])
+ break;
+ }
+ if (i == ARRAY_SIZE(support_model))
+ return -ENODEV;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, priv);
+ priv->mgr = mgr;
+ priv->dev = dev;
+ priv->gen_info = mgr->gen_info;
+
+ snprintf(priv->name, PECI_NAME_SIZE, "peci_dimmtemp.cpu%d",
+ priv->mgr->client->addr - PECI_BASE_ADDR);
+
+ priv->work_queue = alloc_ordered_workqueue(priv->name, 0);
+ if (!priv->work_queue)
+ return -ENOMEM;
+
+ INIT_DELAYED_WORK(&priv->work_handler, create_dimm_temp_info_delayed);
+
+ ret = create_dimm_temp_info(priv);
+ if (ret && ret != -EAGAIN) {
+ dev_dbg(dev, "Failed to create DIMM temp info\n");
+ goto err_free_wq;
+ }
+
+ return 0;
+
+err_free_wq:
+ destroy_workqueue(priv->work_queue);
+ return ret;
+}
+
+static int peci_dimmtemp_remove(struct platform_device *pdev)
+{
+ struct peci_dimmtemp *priv = dev_get_drvdata(&pdev->dev);
+
+ cancel_delayed_work_sync(&priv->work_handler);
+ destroy_workqueue(priv->work_queue);
+
+ return 0;
+}
+
+static const struct platform_device_id peci_dimmtemp_ids[] = {
+ { .name = "peci-dimmtemp", .driver_data = 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, peci_dimmtemp_ids);
+
+static struct platform_driver peci_dimmtemp_driver = {
+ .probe = peci_dimmtemp_probe,
+ .remove = peci_dimmtemp_remove,
+ .id_table = peci_dimmtemp_ids,
+ .driver = { .name = KBUILD_MODNAME, },
+};
+module_platform_driver(peci_dimmtemp_driver);
+
+MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
+MODULE_DESCRIPTION("PECI dimmtemp driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hwmon/peci-hwmon.h b/drivers/hwmon/peci-hwmon.h
new file mode 100644
index 000000000000..4d78c528c4c8
--- /dev/null
+++ b/drivers/hwmon/peci-hwmon.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2018-2019 Intel Corporation */
+
+#ifndef __PECI_HWMON_H
+#define __PECI_HWMON_H
+
+#include <linux/peci.h>
+
+#define TEMP_TYPE_PECI 6 /* Sensor type 6: Intel PECI */
+#define UPDATE_INTERVAL HZ
+
+#define PECI_HWMON_LABEL_STR_LEN 10
+
+/**
+ * struct peci_sensor_data - PECI sensor information
+ * @valid: flag to indicate the sensor value is valid
+ * @value: sensor value in millidegree Celsius
+ * @last_updated: time of the last update in jiffies
+ */
+struct peci_sensor_data {
+ uint valid;
+ s32 value;
+ ulong last_updated;
+};
+
+/**
+ * peci_sensor_need_update - check whether sensor update is needed or not
+ * @sensor: pointer to sensor data struct
+ *
+ * Return: true if update is needed, false if not.
+ */
+static inline bool peci_sensor_need_update(struct peci_sensor_data *sensor)
+{
+ return !sensor->valid ||
+ time_after(jiffies, sensor->last_updated + UPDATE_INTERVAL);
+}
+
+/**
+ * peci_sensor_mark_updated - mark the sensor is updated
+ * @sensor: pointer to sensor data struct
+ */
+static inline void peci_sensor_mark_updated(struct peci_sensor_data *sensor)
+{
+ sensor->valid = 1;
+ sensor->last_updated = jiffies;
+}
+
+#endif /* __PECI_HWMON_H */
diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig
index d62d69bb7e49..61062632b22b 100644
--- a/drivers/hwmon/pmbus/Kconfig
+++ b/drivers/hwmon/pmbus/Kconfig
@@ -200,11 +200,11 @@ config SENSORS_TPS53679
be called tps53679.
config SENSORS_UCD9000
- tristate "TI UCD90120, UCD90124, UCD90160, UCD9090, UCD90910"
+ tristate "TI UCD90120, UCD90124, UCD90160, UCD90320, UCD9090, UCD90910"
help
If you say yes here you get hardware monitoring support for TI
- UCD90120, UCD90124, UCD90160, UCD9090, UCD90910, Sequencer and System
- Health Controllers.
+ UCD90120, UCD90124, UCD90160, UCD90320, UCD9090, UCD90910, Sequencer
+ and System Health Controllers.
This driver can also be built as a module. If so, the module will
be called ucd9000.
diff --git a/drivers/hwmon/pmbus/ibm-cffps.c b/drivers/hwmon/pmbus/ibm-cffps.c
index 929c909ac27a..7cf4cc5824ab 100644
--- a/drivers/hwmon/pmbus/ibm-cffps.c
+++ b/drivers/hwmon/pmbus/ibm-cffps.c
@@ -3,6 +3,7 @@
* Copyright 2017 IBM Corp.
*/
+#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/debugfs.h>
#include <linux/device.h>
@@ -19,16 +20,26 @@
#define CFFPS_FRU_CMD 0x9A
#define CFFPS_PN_CMD 0x9B
+#define CFFPS_HEADER_CMD 0x9C
#define CFFPS_SN_CMD 0x9E
+#define CFFPS_MAX_POWER_OUT_CMD 0xA7
#define CFFPS_CCIN_CMD 0xBD
#define CFFPS_FW_CMD 0xFA
#define CFFPS1_FW_NUM_BYTES 4
#define CFFPS2_FW_NUM_WORDS 3
#define CFFPS_SYS_CONFIG_CMD 0xDA
+#define CFFPS_12VCS_VOUT_CMD 0xDE
#define CFFPS_INPUT_HISTORY_CMD 0xD6
#define CFFPS_INPUT_HISTORY_SIZE 100
+#define CFFPS_CCIN_REVISION GENMASK(7, 0)
+#define CFFPS_CCIN_REVISION_LEGACY 0xde
+#define CFFPS_CCIN_VERSION GENMASK(15, 8)
+#define CFFPS_CCIN_VERSION_1 0x2b
+#define CFFPS_CCIN_VERSION_2 0x2e
+#define CFFPS_CCIN_VERSION_3 0x51
+
/* STATUS_MFR_SPECIFIC bits */
#define CFFPS_MFR_FAN_FAULT BIT(0)
#define CFFPS_MFR_THERMAL_FAULT BIT(1)
@@ -39,26 +50,25 @@
#define CFFPS_MFR_VAUX_FAULT BIT(6)
#define CFFPS_MFR_CURRENT_SHARE_WARNING BIT(7)
-/*
- * LED off state actually relinquishes LED control to PSU firmware, so it can
- * turn on the LED for faults.
- */
-#define CFFPS_LED_OFF 0
#define CFFPS_LED_BLINK BIT(0)
#define CFFPS_LED_ON BIT(1)
+#define CFFPS_LED_OFF BIT(2)
#define CFFPS_BLINK_RATE_MS 250
enum {
CFFPS_DEBUGFS_INPUT_HISTORY = 0,
CFFPS_DEBUGFS_FRU,
CFFPS_DEBUGFS_PN,
+ CFFPS_DEBUGFS_HEADER,
CFFPS_DEBUGFS_SN,
+ CFFPS_DEBUGFS_MAX_POWER_OUT,
CFFPS_DEBUGFS_CCIN,
CFFPS_DEBUGFS_FW,
+ CFFPS_DEBUGFS_ON_OFF_CONFIG,
CFFPS_DEBUGFS_NUM_ENTRIES
};
-enum versions { cffps1, cffps2 };
+enum versions { cffps1, cffps2, cffps_unknown };
struct ibm_cffps_input_history {
struct mutex update_lock;
@@ -131,15 +141,15 @@ static ssize_t ibm_cffps_read_input_history(struct ibm_cffps *psu,
psu->input_history.byte_count);
}
-static ssize_t ibm_cffps_debugfs_op(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
+static ssize_t ibm_cffps_debugfs_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
{
u8 cmd;
int i, rc;
int *idxp = file->private_data;
int idx = *idxp;
struct ibm_cffps *psu = to_psu(idxp, idx);
- char data[I2C_SMBUS_BLOCK_MAX] = { 0 };
+ char data[I2C_SMBUS_BLOCK_MAX + 2] = { 0 };
pmbus_set_page(psu->client, 0);
@@ -152,9 +162,20 @@ static ssize_t ibm_cffps_debugfs_op(struct file *file, char __user *buf,
case CFFPS_DEBUGFS_PN:
cmd = CFFPS_PN_CMD;
break;
+ case CFFPS_DEBUGFS_HEADER:
+ cmd = CFFPS_HEADER_CMD;
+ break;
case CFFPS_DEBUGFS_SN:
cmd = CFFPS_SN_CMD;
break;
+ case CFFPS_DEBUGFS_MAX_POWER_OUT:
+ rc = i2c_smbus_read_word_swapped(psu->client,
+ CFFPS_MAX_POWER_OUT_CMD);
+ if (rc < 0)
+ return rc;
+
+ rc = snprintf(data, I2C_SMBUS_BLOCK_MAX, "%d", rc);
+ goto done;
case CFFPS_DEBUGFS_CCIN:
rc = i2c_smbus_read_word_swapped(psu->client, CFFPS_CCIN_CMD);
if (rc < 0)
@@ -194,6 +215,14 @@ static ssize_t ibm_cffps_debugfs_op(struct file *file, char __user *buf,
return -EOPNOTSUPP;
}
goto done;
+ case CFFPS_DEBUGFS_ON_OFF_CONFIG:
+ rc = i2c_smbus_read_byte_data(psu->client,
+ PMBUS_ON_OFF_CONFIG);
+ if (rc < 0)
+ return rc;
+
+ rc = snprintf(data, 3, "%02x", rc);
+ goto done;
default:
return -EINVAL;
}
@@ -209,9 +238,42 @@ done:
return simple_read_from_buffer(buf, count, ppos, data, rc);
}
+static ssize_t ibm_cffps_debugfs_write(struct file *file,
+ const char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ u8 data;
+ ssize_t rc;
+ int *idxp = file->private_data;
+ int idx = *idxp;
+ struct ibm_cffps *psu = to_psu(idxp, idx);
+
+ switch (idx) {
+ case CFFPS_DEBUGFS_ON_OFF_CONFIG:
+ pmbus_set_page(psu->client, 0);
+
+ rc = simple_write_to_buffer(&data, 1, ppos, buf, count);
+ if (rc < 0)
+ return rc;
+
+ rc = i2c_smbus_write_byte_data(psu->client,
+ PMBUS_ON_OFF_CONFIG, data);
+ if (rc)
+ return rc;
+
+ rc = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return rc;
+}
+
static const struct file_operations ibm_cffps_fops = {
.llseek = noop_llseek,
- .read = ibm_cffps_debugfs_op,
+ .read = ibm_cffps_debugfs_read,
+ .write = ibm_cffps_debugfs_write,
.open = simple_open,
};
@@ -288,6 +350,9 @@ static int ibm_cffps_read_word_data(struct i2c_client *client, int page,
if (mfr & CFFPS_MFR_PS_KILL)
rc |= PB_STATUS_OFF;
break;
+ case PMBUS_VIRT_READ_VMON:
+ rc = pmbus_read_word_data(client, page, CFFPS_12VCS_VOUT_CMD);
+ break;
default:
rc = -ENODATA;
break;
@@ -370,6 +435,9 @@ static void ibm_cffps_create_led_class(struct ibm_cffps *psu)
rc = devm_led_classdev_register(dev, &psu->led);
if (rc)
dev_warn(dev, "failed to register led class: %d\n", rc);
+ else
+ i2c_smbus_write_byte_data(client, CFFPS_SYS_CONFIG_CMD,
+ CFFPS_LED_OFF);
}
static struct pmbus_driver_info ibm_cffps_info[] = {
@@ -391,7 +459,7 @@ static struct pmbus_driver_info ibm_cffps_info[] = {
PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 |
PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT |
PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP |
- PMBUS_HAVE_STATUS_FAN12,
+ PMBUS_HAVE_STATUS_FAN12 | PMBUS_HAVE_VMON,
.func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT |
PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_TEMP3 |
PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT,
@@ -408,7 +476,7 @@ static int ibm_cffps_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int i, rc;
- enum versions vs;
+ enum versions vs = cffps_unknown;
struct dentry *debugfs;
struct dentry *ibm_cffps_dir;
struct ibm_cffps *psu;
@@ -418,8 +486,36 @@ static int ibm_cffps_probe(struct i2c_client *client,
vs = (enum versions)md;
else if (id)
vs = (enum versions)id->driver_data;
- else
- vs = cffps1;
+
+ if (vs == cffps_unknown) {
+ u16 ccin_revision = 0;
+ u16 ccin_version = CFFPS_CCIN_VERSION_1;
+ int ccin = i2c_smbus_read_word_swapped(client, CFFPS_CCIN_CMD);
+
+ if (ccin > 0) {
+ ccin_revision = FIELD_GET(CFFPS_CCIN_REVISION, ccin);
+ ccin_version = FIELD_GET(CFFPS_CCIN_VERSION, ccin);
+ }
+
+ switch (ccin_version) {
+ default:
+ case CFFPS_CCIN_VERSION_1:
+ vs = cffps1;
+ break;
+ case CFFPS_CCIN_VERSION_2:
+ vs = cffps2;
+ break;
+ case CFFPS_CCIN_VERSION_3:
+ if (ccin_revision == CFFPS_CCIN_REVISION_LEGACY)
+ vs = cffps1;
+ else
+ vs = cffps2;
+ break;
+ }
+
+ /* Set the client name to include the version number. */
+ snprintf(client->name, I2C_NAME_SIZE, "cffps%d", vs + 1);
+ }
client->dev.platform_data = &ibm_cffps_pdata;
rc = pmbus_do_probe(client, id, &ibm_cffps_info[vs]);
@@ -462,15 +558,24 @@ static int ibm_cffps_probe(struct i2c_client *client,
debugfs_create_file("part_number", 0444, ibm_cffps_dir,
&psu->debugfs_entries[CFFPS_DEBUGFS_PN],
&ibm_cffps_fops);
+ debugfs_create_file("header", 0444, ibm_cffps_dir,
+ &psu->debugfs_entries[CFFPS_DEBUGFS_HEADER],
+ &ibm_cffps_fops);
debugfs_create_file("serial_number", 0444, ibm_cffps_dir,
&psu->debugfs_entries[CFFPS_DEBUGFS_SN],
&ibm_cffps_fops);
+ debugfs_create_file("max_power_out", 0444, ibm_cffps_dir,
+ &psu->debugfs_entries[CFFPS_DEBUGFS_MAX_POWER_OUT],
+ &ibm_cffps_fops);
debugfs_create_file("ccin", 0444, ibm_cffps_dir,
&psu->debugfs_entries[CFFPS_DEBUGFS_CCIN],
&ibm_cffps_fops);
debugfs_create_file("fw_version", 0444, ibm_cffps_dir,
&psu->debugfs_entries[CFFPS_DEBUGFS_FW],
&ibm_cffps_fops);
+ debugfs_create_file("on_off_config", 0644, ibm_cffps_dir,
+ &psu->debugfs_entries[CFFPS_DEBUGFS_ON_OFF_CONFIG],
+ &ibm_cffps_fops);
return 0;
}
@@ -478,6 +583,7 @@ static int ibm_cffps_probe(struct i2c_client *client,
static const struct i2c_device_id ibm_cffps_id[] = {
{ "ibm_cffps1", cffps1 },
{ "ibm_cffps2", cffps2 },
+ { "ibm_cffps", cffps_unknown },
{}
};
MODULE_DEVICE_TABLE(i2c, ibm_cffps_id);
@@ -491,6 +597,10 @@ static const struct of_device_id ibm_cffps_of_match[] = {
.compatible = "ibm,cffps2",
.data = (void *)cffps2
},
+ {
+ .compatible = "ibm,cffps",
+ .data = (void *)cffps_unknown
+ },
{}
};
MODULE_DEVICE_TABLE(of, ibm_cffps_of_match);
diff --git a/drivers/hwmon/pmbus/max31785.c b/drivers/hwmon/pmbus/max31785.c
index 254b0f98c755..0d4ad47171de 100644
--- a/drivers/hwmon/pmbus/max31785.c
+++ b/drivers/hwmon/pmbus/max31785.c
@@ -12,40 +12,126 @@
enum max31785_regs {
MFR_REVISION = 0x9b,
+ MFR_FAULT_RESPONSE = 0xd9,
+ MFR_TEMP_SENSOR_CONFIG = 0xf0,
MFR_FAN_CONFIG = 0xf1,
+ MFR_FAN_FAULT_LIMIT = 0xf5,
};
#define MAX31785 0x3030
#define MAX31785A 0x3040
#define MFR_FAN_CONFIG_DUAL_TACH BIT(12)
+#define MFR_FAN_CONFIG_TSFO BIT(9)
+#define MFR_FAN_CONFIG_TACHO BIT(8)
+#define MFR_FAN_CONFIG_HEALTH BIT(4)
+#define MFR_FAN_CONFIG_ROTOR_HI_LO BIT(3)
+#define MFR_FAN_CONFIG_ROTOR BIT(2)
+
+#define MFR_FAULT_RESPONSE_MONITOR BIT(0)
#define MAX31785_NR_PAGES 23
#define MAX31785_NR_FAN_PAGES 6
+/*
+ * MAX31785 dragons ahead
+ *
+ * We see weird issues where some transfers fail. There doesn't appear to be
+ * any pattern to the problem, so below we wrap all the read/write calls with a
+ * retry. The device provides no indication of this besides NACK'ing master
+ * Txs; no bits are set in STATUS_BYTE to suggest anything has gone wrong.
+ */
+
+#define max31785_retry(_func, ...) ({ \
+ /* All relevant functions return int, sue me */ \
+ int _ret = _func(__VA_ARGS__); \
+ if (_ret == -EIO) \
+ _ret = _func(__VA_ARGS__); \
+ _ret; \
+})
+
+static int max31785_i2c_smbus_read_byte_data(struct i2c_client *client,
+ int command)
+{
+ return max31785_retry(i2c_smbus_read_byte_data, client, command);
+}
+
+
+static int max31785_i2c_smbus_write_byte_data(struct i2c_client *client,
+ int command, u16 data)
+{
+ return max31785_retry(i2c_smbus_write_byte_data, client, command, data);
+}
+
+static int max31785_i2c_smbus_read_word_data(struct i2c_client *client,
+ int command)
+{
+ return max31785_retry(i2c_smbus_read_word_data, client, command);
+}
+
+static int max31785_i2c_smbus_write_word_data(struct i2c_client *client,
+ int command, u16 data)
+{
+ return max31785_retry(i2c_smbus_write_word_data, client, command, data);
+}
+
+static int max31785_pmbus_write_byte(struct i2c_client *client, int page,
+ u8 value)
+{
+ return max31785_retry(pmbus_write_byte, client, page, value);
+}
+
+static int max31785_pmbus_read_byte_data(struct i2c_client *client, int page,
+ int command)
+{
+ return max31785_retry(pmbus_read_byte_data, client, page, command);
+}
+
+static int max31785_pmbus_write_byte_data(struct i2c_client *client, int page,
+ int command, u16 data)
+{
+ return max31785_retry(pmbus_write_byte_data, client, page, command,
+ data);
+}
+
+static int max31785_pmbus_read_word_data(struct i2c_client *client, int page,
+ int command)
+{
+ return max31785_retry(pmbus_read_word_data, client, page, command);
+}
+
+static int max31785_pmbus_write_word_data(struct i2c_client *client, int page,
+ int command, u16 data)
+{
+ return max31785_retry(pmbus_write_word_data, client, page, command,
+ data);
+}
+
static int max31785_read_byte_data(struct i2c_client *client, int page,
int reg)
{
- if (page < MAX31785_NR_PAGES)
- return -ENODATA;
-
switch (reg) {
case PMBUS_VOUT_MODE:
- return -ENOTSUPP;
+ if (page >= MAX31785_NR_PAGES)
+ return -ENOTSUPP;
+ break;
case PMBUS_FAN_CONFIG_12:
- return pmbus_read_byte_data(client, page - MAX31785_NR_PAGES,
- reg);
+ if (page >= MAX31785_NR_PAGES)
+ return max31785_pmbus_read_byte_data(client,
+ page - MAX31785_NR_PAGES,
+ reg);
+ break;
}
- return -ENODATA;
+ return max31785_pmbus_read_byte_data(client, page, reg);
}
static int max31785_write_byte(struct i2c_client *client, int page, u8 value)
{
- if (page < MAX31785_NR_PAGES)
- return -ENODATA;
+ if (page >= MAX31785_NR_PAGES)
+ return -ENOTSUPP;
- return -ENOTSUPP;
+ return max31785_pmbus_write_byte(client, page, value);
}
static int max31785_read_long_data(struct i2c_client *client, int page,
@@ -106,11 +192,13 @@ static int max31785_get_pwm_mode(struct i2c_client *client, int page)
int config;
int command;
- config = pmbus_read_byte_data(client, page, PMBUS_FAN_CONFIG_12);
+ config = max31785_pmbus_read_byte_data(client, page,
+ PMBUS_FAN_CONFIG_12);
if (config < 0)
return config;
- command = pmbus_read_word_data(client, page, PMBUS_FAN_COMMAND_1);
+ command = max31785_pmbus_read_word_data(client, page,
+ PMBUS_FAN_COMMAND_1);
if (command < 0)
return command;
@@ -134,15 +222,14 @@ static int max31785_read_word_data(struct i2c_client *client, int page,
switch (reg) {
case PMBUS_READ_FAN_SPEED_1:
if (page < MAX31785_NR_PAGES)
- return -ENODATA;
+ return max31785_pmbus_read_word_data(client, page, reg);
rv = max31785_read_long_data(client, page - MAX31785_NR_PAGES,
reg, &val);
if (rv < 0)
return rv;
- rv = (val >> 16) & 0xffff;
- break;
+ return (val >> 16) & 0xffff;
case PMBUS_FAN_COMMAND_1:
/*
* PMBUS_FAN_COMMAND_x is probed to judge whether or not to
@@ -150,20 +237,28 @@ static int max31785_read_word_data(struct i2c_client *client, int page,
*
* Don't expose fan_target attribute for virtual pages.
*/
- rv = (page >= MAX31785_NR_PAGES) ? -ENOTSUPP : -ENODATA;
+ if (page >= MAX31785_NR_PAGES)
+ return -ENOTSUPP;
break;
+ case PMBUS_VIRT_FAN_TARGET_1:
+ if (page >= MAX31785_NR_PAGES)
+ return -ENOTSUPP;
+
+ return -ENODATA;
case PMBUS_VIRT_PWM_1:
- rv = max31785_get_pwm(client, page);
- break;
+ return max31785_get_pwm(client, page);
case PMBUS_VIRT_PWM_ENABLE_1:
- rv = max31785_get_pwm_mode(client, page);
- break;
+ return max31785_get_pwm_mode(client, page);
default:
- rv = -ENODATA;
+ if (page >= MAX31785_NR_PAGES)
+ return -ENXIO;
break;
}
- return rv;
+ if (reg >= PMBUS_VIRT_BASE)
+ return -ENXIO;
+
+ return max31785_pmbus_read_word_data(client, page, reg);
}
static inline u32 max31785_scale_pwm(u32 sensor_val)
@@ -187,6 +282,31 @@ static inline u32 max31785_scale_pwm(u32 sensor_val)
return (sensor_val * 100) / 255;
}
+static int max31785_update_fan(struct i2c_client *client, int page,
+ u8 config, u8 mask, u16 command)
+{
+ int from, rv;
+ u8 to;
+
+ from = max31785_pmbus_read_byte_data(client, page, PMBUS_FAN_CONFIG_12);
+ if (from < 0)
+ return from;
+
+ to = (from & ~mask) | (config & mask);
+
+ if (to != from) {
+ rv = max31785_pmbus_write_byte_data(client, page,
+ PMBUS_FAN_CONFIG_12, to);
+ if (rv < 0)
+ return rv;
+ }
+
+ rv = max31785_pmbus_write_word_data(client, page, PMBUS_FAN_COMMAND_1,
+ command);
+
+ return rv;
+}
+
static int max31785_pwm_enable(struct i2c_client *client, int page,
u16 word)
{
@@ -216,15 +336,18 @@ static int max31785_pwm_enable(struct i2c_client *client, int page,
return -EINVAL;
}
- return pmbus_update_fan(client, page, 0, config, PB_FAN_1_RPM, rate);
+ return max31785_update_fan(client, page, config, PB_FAN_1_RPM, rate);
}
static int max31785_write_word_data(struct i2c_client *client, int page,
int reg, u16 word)
{
switch (reg) {
+ case PMBUS_VIRT_FAN_TARGET_1:
+ return max31785_update_fan(client, page, PB_FAN_1_RPM,
+ PB_FAN_1_RPM, word);
case PMBUS_VIRT_PWM_1:
- return pmbus_update_fan(client, page, 0, 0, PB_FAN_1_RPM,
+ return max31785_update_fan(client, page, 0, PB_FAN_1_RPM,
max31785_scale_pwm(word));
case PMBUS_VIRT_PWM_ENABLE_1:
return max31785_pwm_enable(client, page, word);
@@ -232,7 +355,279 @@ static int max31785_write_word_data(struct i2c_client *client, int page,
break;
}
- return -ENODATA;
+ if (reg < PMBUS_VIRT_BASE)
+ return max31785_pmbus_write_word_data(client, page, reg, word);
+
+ return -ENXIO;
+}
+
+/*
+ * Returns negative error codes if an unrecoverable problem is detected, 0 if a
+ * recoverable problem is detected, or a positive value on success.
+ */
+static int max31785_of_fan_config(struct i2c_client *client,
+ struct pmbus_driver_info *info,
+ struct device_node *child)
+{
+ int mfr_cfg = 0, mfr_fault_resp = 0, pb_cfg;
+ struct device *dev = &client->dev;
+ char *lock_polarity = NULL;
+ const char *sval;
+ u32 page;
+ u32 uval;
+ int ret;
+
+ if (!of_device_is_compatible(child, "pmbus-fan"))
+ return 0;
+
+ ret = of_property_read_u32(child, "reg", &page);
+ if (ret < 0) {
+ dev_err(&client->dev, "Missing valid reg property\n");
+ return ret;
+ }
+
+ if (!(info->func[page] & PMBUS_HAVE_FAN12)) {
+ dev_err(dev, "Page %d does not have fan capabilities\n", page);
+ return -ENXIO;
+ }
+
+ ret = max31785_i2c_smbus_write_byte_data(client, PMBUS_PAGE, page);
+ if (ret < 0)
+ return ret;
+
+ pb_cfg = max31785_i2c_smbus_read_byte_data(client, PMBUS_FAN_CONFIG_12);
+ if (pb_cfg < 0)
+ return pb_cfg;
+
+ if (of_property_read_bool(child->parent, "use-stored-presence")) {
+ if (!(pb_cfg & PB_FAN_1_INSTALLED))
+ dev_info(dev, "Fan %d is configured but not installed\n",
+ page);
+ } else {
+ pb_cfg |= PB_FAN_1_INSTALLED;
+ }
+
+ ret = of_property_read_string(child, "maxim,fan-rotor-input", &sval);
+ if (ret < 0) {
+ dev_err(dev, "Missing valid maxim,fan-rotor-input property for fan %d\n",
+ page);
+ return ret;
+ }
+
+ if (strcmp("tach", sval) && strcmp("lock", sval)) {
+ dev_err(dev, "maxim,fan-rotor-input has invalid value for fan %d: %s\n",
+ page, sval);
+ return -EINVAL;
+ } else if (!strcmp("lock", sval)) {
+ mfr_cfg |= MFR_FAN_CONFIG_ROTOR;
+
+ ret = max31785_i2c_smbus_write_word_data(client,
+ MFR_FAN_FAULT_LIMIT,
+ 1);
+ if (ret < 0)
+ return ret;
+
+ ret = of_property_read_string(child, "maxim,fan-lock-polarity",
+ &sval);
+ if (ret < 0) {
+ dev_err(dev, "Missing valid maxim,fan-lock-polarity property for fan %d\n",
+ page);
+ return ret;
+ }
+
+ if (strcmp("low", sval) && strcmp("high", sval)) {
+ dev_err(dev, "maxim,fan-lock-polarity has invalid value for fan %d: %s\n",
+ page, lock_polarity);
+ return -EINVAL;
+ } else if (!strcmp("high", sval))
+ mfr_cfg |= MFR_FAN_CONFIG_ROTOR_HI_LO;
+ }
+
+ if (!of_property_read_string(child, "fan-mode", &sval)) {
+ if (!strcmp("rpm", sval))
+ pb_cfg |= PB_FAN_1_RPM;
+ else if (!strcmp("pwm", sval))
+ pb_cfg &= ~PB_FAN_1_RPM;
+ else {
+ dev_err(dev, "fan-mode has invalid value for fan %d: %s\n",
+ page, sval);
+ return -EINVAL;
+ }
+ }
+
+ ret = of_property_read_u32(child, "tach-pulses", &uval);
+ if (ret < 0) {
+ pb_cfg &= ~PB_FAN_1_PULSE_MASK;
+ } else if (uval && (uval - 1) < 4) {
+ pb_cfg = ((pb_cfg & ~PB_FAN_1_PULSE_MASK) | ((uval - 1) << 4));
+ } else {
+ dev_err(dev, "tach-pulses has invalid value for fan %d: %u\n",
+ page, uval);
+ return -EINVAL;
+ }
+
+ if (of_property_read_bool(child, "maxim,fan-health"))
+ mfr_cfg |= MFR_FAN_CONFIG_HEALTH;
+
+ if (of_property_read_bool(child, "maxim,fan-no-watchdog") ||
+ of_property_read_bool(child, "maxim,tmp-no-fault-ramp"))
+ mfr_cfg |= MFR_FAN_CONFIG_TSFO;
+
+ if (of_property_read_bool(child, "maxim,fan-dual-tach"))
+ mfr_cfg |= MFR_FAN_CONFIG_DUAL_TACH;
+
+ if (of_property_read_bool(child, "maxim,fan-no-fault-ramp"))
+ mfr_cfg |= MFR_FAN_CONFIG_TACHO;
+
+ if (!of_property_read_u32(child, "maxim,fan-startup", &uval)) {
+ uval /= 2;
+ if (uval < 5) {
+ mfr_cfg |= uval;
+ } else {
+ dev_err(dev, "maxim,fan-startup has invalid value for fan %d: %u\n",
+ page, uval);
+ return -EINVAL;
+ }
+ }
+
+ if (!of_property_read_u32(child, "maxim,fan-ramp", &uval)) {
+ if (uval < 8) {
+ mfr_cfg |= uval << 5;
+ } else {
+ dev_err(dev, "maxim,fan-ramp has invalid value for fan %d: %u\n",
+ page, uval);
+ return -EINVAL;
+ }
+ }
+
+ if (!of_property_read_u32(child, "maxim,tmp-hysteresis", &uval)) {
+ uval /= 2;
+ uval -= 1;
+ if (uval < 4) {
+ mfr_cfg |= uval << 10;
+ } else {
+ dev_err(dev, "maxim,tmp-hysteresis has invalid value for fan %d, %u\n",
+ page, uval);
+ return -EINVAL;
+ }
+ }
+
+ if (!of_property_read_u32(child, "maxim,fan-pwm-freq", &uval)) {
+ u16 val;
+
+ if (uval == 30) {
+ val = 0;
+ } else if (uval == 50) {
+ val = 1;
+ } else if (uval == 100) {
+ val = 2;
+ } else if (uval == 150) {
+ val = 3;
+ } else if (uval == 25000) {
+ val = 7;
+ } else {
+ dev_err(dev, "maxim,fan-pwm-freq has invalid value for fan %d: %u\n",
+ page, uval);
+ return -EINVAL;
+ }
+
+ mfr_cfg |= val << 13;
+ }
+
+ if (of_property_read_bool(child, "maxim,fan-fault-pin-mon"))
+ mfr_fault_resp |= MFR_FAULT_RESPONSE_MONITOR;
+
+ ret = max31785_i2c_smbus_write_byte_data(client, PMBUS_FAN_CONFIG_12,
+ pb_cfg & ~PB_FAN_1_INSTALLED);
+ if (ret < 0)
+ return ret;
+
+ ret = max31785_i2c_smbus_write_word_data(client, MFR_FAN_CONFIG,
+ mfr_cfg);
+ if (ret < 0)
+ return ret;
+
+ ret = max31785_i2c_smbus_write_byte_data(client, MFR_FAULT_RESPONSE,
+ mfr_fault_resp);
+ if (ret < 0)
+ return ret;
+
+ ret = max31785_i2c_smbus_write_byte_data(client, PMBUS_FAN_CONFIG_12,
+ pb_cfg);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Fans are on pages 0 - 5. If the page property of a fan node is
+ * greater than 5 we will have errored in checks above out above.
+ * Therefore we don't need to cope with values up to 31, and the int
+ * return type is enough.
+ *
+ * The bit mask return value is used to populate a bitfield of fans
+ * who are both configured in the devicetree _and_ reported as
+ * installed by the hardware. Any fans that are not configured in the
+ * devicetree but are reported as installed by the hardware will have
+ * their hardware configuration updated to unset the installed bit.
+ */
+ return BIT(page);
+}
+
+static int max31785_of_tmp_config(struct i2c_client *client,
+ struct pmbus_driver_info *info,
+ struct device_node *child)
+{
+ struct device *dev = &client->dev;
+ struct device_node *np;
+ u16 mfr_tmp_cfg = 0;
+ u32 page;
+ u32 uval;
+ int ret;
+ int i;
+
+ if (!of_device_is_compatible(child, "pmbus-temperature"))
+ return 0;
+
+ ret = of_property_read_u32(child, "reg", &page);
+ if (ret < 0) {
+ dev_err(&client->dev, "Missing valid reg property\n");
+ return ret;
+ }
+
+ if (!(info->func[page] & PMBUS_HAVE_TEMP)) {
+ dev_err(dev, "Page %d does not have temp capabilities\n", page);
+ return -ENXIO;
+ }
+
+ ret = max31785_i2c_smbus_write_byte_data(client, PMBUS_PAGE, page);
+ if (ret < 0)
+ return ret;
+
+ if (!of_property_read_u32(child, "maxim,tmp-offset", &uval)) {
+ if (uval < 32)
+ mfr_tmp_cfg |= uval << 10;
+ }
+
+ i = 0;
+ while ((np = of_parse_phandle(child, "maxim,tmp-fans", i))) {
+ if (of_property_read_u32(np, "reg", &uval)) {
+ dev_err(&client->dev, "Failed to read fan reg property for phandle index %d\n",
+ i);
+ } else {
+ if (uval < 6)
+ mfr_tmp_cfg |= BIT(uval);
+ else
+ dev_warn(&client->dev, "Invalid fan page: %d\n",
+ uval);
+ }
+ i++;
+ }
+
+ ret = max31785_i2c_smbus_write_word_data(client, MFR_TEMP_SENSOR_CONFIG,
+ mfr_tmp_cfg);
+ if (ret < 0)
+ return ret;
+
+ return 0;
}
#define MAX31785_FAN_FUNCS \
@@ -304,11 +699,11 @@ static int max31785_configure_dual_tach(struct i2c_client *client,
int i;
for (i = 0; i < MAX31785_NR_FAN_PAGES; i++) {
- ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, i);
+ ret = max31785_i2c_smbus_write_byte_data(client, PMBUS_PAGE, i);
if (ret < 0)
return ret;
- ret = i2c_smbus_read_word_data(client, MFR_FAN_CONFIG);
+ ret = max31785_i2c_smbus_read_word_data(client, MFR_FAN_CONFIG);
if (ret < 0)
return ret;
@@ -328,9 +723,12 @@ static int max31785_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
+ struct device_node *child;
struct pmbus_driver_info *info;
bool dual_tach = false;
+ u32 fans;
s64 ret;
+ int i;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA |
@@ -343,7 +741,7 @@ static int max31785_probe(struct i2c_client *client,
*info = max31785_info;
- ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 255);
+ ret = max31785_i2c_smbus_write_byte_data(client, PMBUS_PAGE, 255);
if (ret < 0)
return ret;
@@ -360,6 +758,49 @@ static int max31785_probe(struct i2c_client *client,
return -ENODEV;
}
+ fans = 0;
+ for_each_child_of_node(dev->of_node, child) {
+ ret = max31785_of_fan_config(client, info, child);
+ if (ret < 0) {
+ of_node_put(child);
+ return ret;
+ }
+
+ if (ret)
+ fans |= ret;
+
+ ret = max31785_of_tmp_config(client, info, child);
+ if (ret < 0) {
+ of_node_put(child);
+ return ret;
+ }
+ }
+
+ for (i = 0; i < MAX31785_NR_PAGES; i++) {
+ bool have_fan = !!(info->func[i] & PMBUS_HAVE_FAN12);
+ bool fan_configured = !!(fans & BIT(i));
+
+ if (!have_fan || fan_configured)
+ continue;
+
+ ret = max31785_i2c_smbus_write_byte_data(client, PMBUS_PAGE,
+ i);
+ if (ret < 0)
+ return ret;
+
+ ret = max31785_i2c_smbus_read_byte_data(client,
+ PMBUS_FAN_CONFIG_12);
+ if (ret < 0)
+ return ret;
+
+ ret &= ~PB_FAN_1_INSTALLED;
+ ret = max31785_i2c_smbus_write_word_data(client,
+ PMBUS_FAN_CONFIG_12,
+ ret);
+ if (ret < 0)
+ return ret;
+ }
+
if (dual_tach) {
ret = max31785_configure_dual_tach(client, info);
if (ret < 0)
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
index 8470097907bc..898d7378f4f8 100644
--- a/drivers/hwmon/pmbus/pmbus_core.c
+++ b/drivers/hwmon/pmbus/pmbus_core.c
@@ -155,9 +155,17 @@ int pmbus_set_page(struct i2c_client *client, int page)
return 0;
if (!(data->info->func[page] & PMBUS_PAGE_VIRTUAL)) {
+ dev_dbg(&client->dev, "Want page %u, %u cached\n", page,
+ data->currpage);
+
rv = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page);
- if (rv < 0)
- return rv;
+ if (rv) {
+ rv = i2c_smbus_write_byte_data(client, PMBUS_PAGE,
+ page);
+ dev_dbg(&client->dev,
+ "Failed to set page %u, performed one-shot retry %s: %d\n",
+ page, rv ? "and failed" : "with success", rv);
+ }
rv = i2c_smbus_read_byte_data(client, PMBUS_PAGE);
if (rv < 0)
@@ -433,15 +441,15 @@ static int pmbus_get_fan_rate(struct i2c_client *client, int page, int id,
return s->data;
}
- config = pmbus_read_byte_data(client, page,
- pmbus_fan_config_registers[id]);
+ config = _pmbus_read_byte_data(client, page,
+ pmbus_fan_config_registers[id]);
if (config < 0)
return config;
have_rpm = !!(config & pmbus_fan_rpm_mask[id]);
if (want_rpm == have_rpm)
- return pmbus_read_word_data(client, page,
- pmbus_fan_command_registers[id]);
+ return _pmbus_read_word_data(client, page,
+ pmbus_fan_command_registers[id]);
/* Can't sensibly map between RPM and PWM, just return zero */
return 0;
diff --git a/drivers/hwmon/pmbus/ucd9000.c b/drivers/hwmon/pmbus/ucd9000.c
index a9229c6b0e84..23ea3415f166 100644
--- a/drivers/hwmon/pmbus/ucd9000.c
+++ b/drivers/hwmon/pmbus/ucd9000.c
@@ -18,7 +18,8 @@
#include <linux/gpio/driver.h>
#include "pmbus.h"
-enum chips { ucd9000, ucd90120, ucd90124, ucd90160, ucd9090, ucd90910 };
+enum chips { ucd9000, ucd90120, ucd90124, ucd90160, ucd90320, ucd9090,
+ ucd90910 };
#define UCD9000_MONITOR_CONFIG 0xd5
#define UCD9000_NUM_PAGES 0xd6
@@ -38,7 +39,7 @@ enum chips { ucd9000, ucd90120, ucd90124, ucd90160, ucd9090, ucd90910 };
#define UCD9000_GPIO_OUTPUT 1
#define UCD9000_MON_TYPE(x) (((x) >> 5) & 0x07)
-#define UCD9000_MON_PAGE(x) ((x) & 0x0f)
+#define UCD9000_MON_PAGE(x) ((x) & 0x1f)
#define UCD9000_MON_VOLTAGE 1
#define UCD9000_MON_TEMPERATURE 2
@@ -50,10 +51,12 @@ enum chips { ucd9000, ucd90120, ucd90124, ucd90160, ucd9090, ucd90910 };
#define UCD9000_GPIO_NAME_LEN 16
#define UCD9090_NUM_GPIOS 23
#define UCD901XX_NUM_GPIOS 26
+#define UCD90320_NUM_GPIOS 84
#define UCD90910_NUM_GPIOS 26
#define UCD9000_DEBUGFS_NAME_LEN 24
#define UCD9000_GPI_COUNT 8
+#define UCD90320_GPI_COUNT 32
struct ucd9000_data {
u8 fan_data[UCD9000_NUM_FAN][I2C_SMBUS_BLOCK_MAX];
@@ -131,6 +134,7 @@ static const struct i2c_device_id ucd9000_id[] = {
{"ucd90120", ucd90120},
{"ucd90124", ucd90124},
{"ucd90160", ucd90160},
+ {"ucd90320", ucd90320},
{"ucd9090", ucd9090},
{"ucd90910", ucd90910},
{}
@@ -155,6 +159,10 @@ static const struct of_device_id __maybe_unused ucd9000_of_match[] = {
.data = (void *)ucd90160
},
{
+ .compatible = "ti,ucd90320",
+ .data = (void *)ucd90320
+ },
+ {
.compatible = "ti,ucd9090",
.data = (void *)ucd9090
},
@@ -322,6 +330,9 @@ static void ucd9000_probe_gpio(struct i2c_client *client,
case ucd90160:
data->gpio.ngpio = UCD901XX_NUM_GPIOS;
break;
+ case ucd90320:
+ data->gpio.ngpio = UCD90320_NUM_GPIOS;
+ break;
case ucd90910:
data->gpio.ngpio = UCD90910_NUM_GPIOS;
break;
@@ -372,17 +383,18 @@ static int ucd9000_debugfs_show_mfr_status_bit(void *data, u64 *val)
struct ucd9000_debugfs_entry *entry = data;
struct i2c_client *client = entry->client;
u8 buffer[I2C_SMBUS_BLOCK_MAX];
- int ret;
+ int ret, i;
ret = ucd9000_get_mfr_status(client, buffer);
if (ret < 0)
return ret;
/*
- * Attribute only created for devices with gpi fault bits at bits
- * 16-23, which is the second byte of the response.
+ * GPI fault bits are in sets of 8, two bytes from end of response.
*/
- *val = !!(buffer[1] & BIT(entry->index));
+ i = ret - 3 - entry->index / 8;
+ if (i >= 0)
+ *val = !!(buffer[i] & BIT(entry->index % 8));
return 0;
}
@@ -422,7 +434,7 @@ static int ucd9000_init_debugfs(struct i2c_client *client,
{
struct dentry *debugfs;
struct ucd9000_debugfs_entry *entries;
- int i;
+ int i, gpi_count;
char name[UCD9000_DEBUGFS_NAME_LEN];
debugfs = pmbus_get_debugfs_dir(client);
@@ -435,18 +447,21 @@ static int ucd9000_init_debugfs(struct i2c_client *client,
/*
* Of the chips this driver supports, only the UCD9090, UCD90160,
- * and UCD90910 report GPI faults in their MFR_STATUS register, so only
- * create the GPI fault debugfs attributes for those chips.
+ * UCD90320, and UCD90910 report GPI faults in their MFR_STATUS
+ * register, so only create the GPI fault debugfs attributes for those
+ * chips.
*/
if (mid->driver_data == ucd9090 || mid->driver_data == ucd90160 ||
- mid->driver_data == ucd90910) {
+ mid->driver_data == ucd90320 || mid->driver_data == ucd90910) {
+ gpi_count = mid->driver_data == ucd90320 ? UCD90320_GPI_COUNT
+ : UCD9000_GPI_COUNT;
entries = devm_kcalloc(&client->dev,
- UCD9000_GPI_COUNT, sizeof(*entries),
+ gpi_count, sizeof(*entries),
GFP_KERNEL);
if (!entries)
return -ENOMEM;
- for (i = 0; i < UCD9000_GPI_COUNT; i++) {
+ for (i = 0; i < gpi_count; i++) {
entries[i].client = client;
entries[i].index = i;
scnprintf(name, UCD9000_DEBUGFS_NAME_LEN,
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 146ce40d8e0a..9091b93aaf90 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -786,6 +786,17 @@ config I2C_NOMADIK
I2C interface from ST-Ericsson's Nomadik and Ux500 architectures,
as well as the STA2X11 PCIe I/O HUB.
+config I2C_NPCM7XX
+ tristate "Nuvoton I2C Controller"
+ depends on ARCH_NPCM7XX
+ select I2C_SLAVE
+ help
+ If you say yes to this option, support will be included for the
+ Nuvoton I2C controller.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-npcm7xx.
+
config I2C_OCORES
tristate "OpenCores I2C Controller"
help
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 3ab8aebc39c9..4af59a806f3c 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -81,6 +81,7 @@ obj-$(CONFIG_I2C_MT7621) += i2c-mt7621.o
obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o
obj-$(CONFIG_I2C_MXS) += i2c-mxs.o
obj-$(CONFIG_I2C_NOMADIK) += i2c-nomadik.o
+obj-$(CONFIG_I2C_NPCM7XX) += i2c-npcm7xx.o
obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o
obj-$(CONFIG_I2C_OMAP) += i2c-omap.o
obj-$(CONFIG_I2C_OWL) += i2c-owl.o
diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c
index dad6e432de89..538dfc4110f8 100644
--- a/drivers/i2c/busses/i2c-aspeed.c
+++ b/drivers/i2c/busses/i2c-aspeed.c
@@ -955,6 +955,10 @@ static const struct of_device_id aspeed_i2c_bus_of_table[] = {
.compatible = "aspeed,ast2500-i2c-bus",
.data = aspeed_i2c_25xx_get_clk_reg_val,
},
+ {
+ .compatible = "aspeed,ast2600-i2c-bus",
+ .data = aspeed_i2c_25xx_get_clk_reg_val,
+ },
{ },
};
MODULE_DEVICE_TABLE(of, aspeed_i2c_bus_of_table);
diff --git a/drivers/i2c/busses/i2c-fsi.c b/drivers/i2c/busses/i2c-fsi.c
index 977d6f524649..95b6b6bc1d78 100644
--- a/drivers/i2c/busses/i2c-fsi.c
+++ b/drivers/i2c/busses/i2c-fsi.c
@@ -703,7 +703,12 @@ static int fsi_i2c_probe(struct device *dev)
for (port_no = 0; port_no < ports; port_no++) {
np = fsi_i2c_find_port_of_node(dev->of_node, port_no);
- if (np && !of_device_is_available(np))
+ /* Do not add port if it is not described in the device tree */
+ if (!np)
+ continue;
+
+ /* Do not add port if it is described as disabled */
+ if (!of_device_is_available(np))
continue;
port = kzalloc(sizeof(*port), GFP_KERNEL);
diff --git a/drivers/i2c/busses/i2c-npcm7xx.c b/drivers/i2c/busses/i2c-npcm7xx.c
new file mode 100644
index 000000000000..33b15dc517db
--- /dev/null
+++ b/drivers/i2c/busses/i2c-npcm7xx.c
@@ -0,0 +1,2485 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Nuvoton NPCM7xx SMB Controller driver
+ *
+ * Copyright (C) 2018 Nuvoton Technologies tali.perry@nuvoton.com
+ */
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/jiffies.h>
+
+#define I2C_VERSION "0.1.0"
+
+enum smb_mode {
+ SMB_SLAVE = 1,
+ SMB_MASTER
+};
+
+/*
+ * External SMB Interface driver xfer indication values, which indicate status
+ * of the bus.
+ */
+enum smb_state_ind {
+ SMB_NO_STATUS_IND = 0,
+ SMB_SLAVE_RCV_IND = 1,
+ SMB_SLAVE_XMIT_IND = 2,
+ SMB_SLAVE_XMIT_MISSING_DATA_IND = 3,
+ SMB_SLAVE_RESTART_IND = 4,
+ SMB_SLAVE_DONE_IND = 5,
+ SMB_MASTER_DONE_IND = 6,
+ SMB_NACK_IND = 8,
+ SMB_BUS_ERR_IND = 9,
+ SMB_WAKE_UP_IND = 10,
+ SMB_BLOCK_BYTES_ERR_IND = 12,
+ SMB_SLAVE_RCV_MISSING_DATA_IND = 14,
+};
+
+// SMBus Operation type values
+enum smb_oper {
+ SMB_NO_OPER = 0,
+ SMB_WRITE_OPER = 1,
+ SMB_READ_OPER = 2
+};
+
+// SMBus Bank (FIFO mode)
+enum smb_bank {
+ SMB_BANK_0 = 0,
+ SMB_BANK_1 = 1
+};
+
+// Internal SMB states values (for the SMB module state machine).
+enum smb_state {
+ SMB_DISABLE = 0,
+ SMB_IDLE,
+ SMB_MASTER_START,
+ SMB_SLAVE_MATCH,
+ SMB_OPER_STARTED,
+ SMB_STOP_PENDING
+};
+
+// Module supports setting multiple own slave addresses
+enum smb_addr {
+ SMB_SLAVE_ADDR1 = 0,
+ SMB_SLAVE_ADDR2,
+ SMB_SLAVE_ADDR3,
+ SMB_SLAVE_ADDR4,
+ SMB_SLAVE_ADDR5,
+ SMB_SLAVE_ADDR6,
+ SMB_SLAVE_ADDR7,
+ SMB_SLAVE_ADDR8,
+ SMB_SLAVE_ADDR9,
+ SMB_SLAVE_ADDR10,
+ SMB_GC_ADDR,
+ SMB_ARP_ADDR
+};
+
+// global regs
+static struct regmap *gcr_regmap;
+static struct regmap *clk_regmap;
+
+#define NPCM_I2CSEGCTL 0xE4
+#define I2CSEGCTL_VAL 0x0333F000
+
+// Common regs
+#define NPCM_SMBSDA 0x000
+#define NPCM_SMBST 0x002
+#define NPCM_SMBCST 0x004
+#define NPCM_SMBCTL1 0x006
+#define NPCM_SMBADDR1 0x008
+#define NPCM_SMBCTL2 0x00A
+#define NPCM_SMBADDR2 0x00C
+#define NPCM_SMBCTL3 0x00E
+#define NPCM_SMBCST2 0x018
+#define NPCM_SMBCST3 0x019
+#define SMB_VER 0x01F
+
+// BANK 0 regs
+#define NPCM_SMBADDR3 0x010
+#define NPCM_SMBADDR7 0x011
+#define NPCM_SMBADDR4 0x012
+#define NPCM_SMBADDR8 0x013
+#define NPCM_SMBADDR5 0x014
+#define NPCM_SMBADDR9 0x015
+#define NPCM_SMBADDR6 0x016
+#define NPCM_SMBADDR10 0x017
+
+// SMBADDR array: because the addr regs are sprinkled all over the address space
+const int NPCM_SMBADDR[10] = {NPCM_SMBADDR1, NPCM_SMBADDR2, NPCM_SMBADDR3,
+ NPCM_SMBADDR4, NPCM_SMBADDR5, NPCM_SMBADDR6,
+ NPCM_SMBADDR7, NPCM_SMBADDR8, NPCM_SMBADDR9,
+ NPCM_SMBADDR10};
+
+#define NPCM_SMBCTL4 0x01A
+#define NPCM_SMBCTL5 0x01B
+#define NPCM_SMBSCLLT 0x01C // SCL Low Time
+#define NPCM_SMBFIF_CTL 0x01D // FIFO Control
+#define NPCM_SMBSCLHT 0x01E // SCL High Time
+
+// BANK 1 regs
+#define NPCM_SMBFIF_CTS 0x010 // Both FIFOs Control and status
+#define NPCM_SMBTXF_CTL 0x012 // Tx-FIFO Control
+#define NPCM_SMBT_OUT 0x014 // Bus T.O.
+#define NPCM_SMBPEC 0x016 // PEC Data
+#define NPCM_SMBTXF_STS 0x01A // Tx-FIFO Status
+#define NPCM_SMBRXF_STS 0x01C // Rx-FIFO Status
+#define NPCM_SMBRXF_CTL 0x01E // Rx-FIFO Control
+
+// NPCM_SMBST reg fields
+#define NPCM_SMBST_XMIT BIT(0)
+#define NPCM_SMBST_MASTER BIT(1)
+#define NPCM_SMBST_NMATCH BIT(2)
+#define NPCM_SMBST_STASTR BIT(3)
+#define NPCM_SMBST_NEGACK BIT(4)
+#define NPCM_SMBST_BER BIT(5)
+#define NPCM_SMBST_SDAST BIT(6)
+#define NPCM_SMBST_SLVSTP BIT(7)
+
+// NPCM_SMBCST reg fields
+#define NPCM_SMBCST_BUSY BIT(0)
+#define NPCM_SMBCST_BB BIT(1)
+#define NPCM_SMBCST_MATCH BIT(2)
+#define NPCM_SMBCST_GCMATCH BIT(3)
+#define NPCM_SMBCST_TSDA BIT(4)
+#define NPCM_SMBCST_TGSCL BIT(5)
+#define NPCM_SMBCST_MATCHAF BIT(6)
+#define NPCM_SMBCST_ARPMATCH BIT(7)
+
+// NPCM_SMBCTL1 reg fields
+#define NPCM_SMBCTL1_START BIT(0)
+#define NPCM_SMBCTL1_STOP BIT(1)
+#define NPCM_SMBCTL1_INTEN BIT(2)
+#define NPCM_SMBCTL1_EOBINTE BIT(3)
+#define NPCM_SMBCTL1_ACK BIT(4)
+#define NPCM_SMBCTL1_GCMEN BIT(5)
+#define NPCM_SMBCTL1_NMINTE BIT(6)
+#define NPCM_SMBCTL1_STASTRE BIT(7)
+
+// RW1S fields (inside a RW reg):
+#define NPCM_SMBCTL1_RWS_FIELDS (NPCM_SMBCTL1_START | NPCM_SMBCTL1_STOP | \
+ NPCM_SMBCTL1_ACK)
+// NPCM_SMBADDR reg fields
+#define NPCM_SMBADDR_A GENMASK(6, 0)
+#define NPCM_SMBADDR_SAEN BIT(7)
+
+// NPCM_SMBCTL2 reg fields
+#define SMBCTL2_ENABLE BIT(0)
+#define SMBCTL2_SCLFRQ6_0 GENMASK(7, 1)
+
+// NPCM_SMBCTL3 reg fields
+#define SMBCTL3_SCLFRQ8_7 GENMASK(1, 0)
+#define SMBCTL3_ARPMEN BIT(2)
+#define SMBCTL3_IDL_START BIT(3)
+#define SMBCTL3_400K_MODE BIT(4)
+#define SMBCTL3_BNK_SEL BIT(5)
+#define SMBCTL3_SDA_LVL BIT(6)
+#define SMBCTL3_SCL_LVL BIT(7)
+
+// NPCM_SMBCST2 reg fields
+#define NPCM_SMBCST2_MATCHA1F BIT(0)
+#define NPCM_SMBCST2_MATCHA2F BIT(1)
+#define NPCM_SMBCST2_MATCHA3F BIT(2)
+#define NPCM_SMBCST2_MATCHA4F BIT(3)
+#define NPCM_SMBCST2_MATCHA5F BIT(4)
+#define NPCM_SMBCST2_MATCHA6F BIT(5)
+#define NPCM_SMBCST2_MATCHA7F BIT(5)
+#define NPCM_SMBCST2_INTSTS BIT(7)
+
+// NPCM_SMBCST3 reg fields
+#define NPCM_SMBCST3_MATCHA8F BIT(0)
+#define NPCM_SMBCST3_MATCHA9F BIT(1)
+#define NPCM_SMBCST3_MATCHA10F BIT(2)
+#define NPCM_SMBCST3_EO_BUSY BIT(7)
+
+// NPCM_SMBCTL4 reg fields
+#define SMBCTL4_HLDT GENMASK(5, 0)
+#define SMBCTL4_LVL_WE BIT(7)
+
+// NPCM_SMBCTL5 reg fields
+#define SMBCTL5_DBNCT GENMASK(3, 0)
+
+// NPCM_SMBFIF_CTS reg fields
+#define NPCM_SMBFIF_CTS_RXF_TXE BIT(1)
+#define NPCM_SMBFIF_CTS_RFTE_IE BIT(3)
+#define NPCM_SMBFIF_CTS_CLR_FIFO BIT(6)
+#define NPCM_SMBFIF_CTS_SLVRSTR BIT(7)
+
+// NPCM_SMBTXF_CTL reg fields
+#define NPCM_SMBTXF_CTL_TX_THR GENMASK(4, 0)
+#define NPCM_SMBTXF_CTL_THR_TXIE BIT(6)
+
+// NPCM_SMBT_OUT reg fields
+#define NPCM_SMBT_OUT_TO_CKDIV GENMASK(5, 0)
+#define NPCM_SMBT_OUT_T_OUTIE BIT(6)
+#define NPCM_SMBT_OUT_T_OUTST BIT(7)
+
+// NPCM_SMBTXF_STS reg fields
+#define NPCM_SMBTXF_STS_TX_BYTES GENMASK(4, 0)
+#define NPCM_SMBTXF_STS_TX_THST BIT(6)
+
+// NPCM_SMBRXF_STS reg fields
+#define NPCM_SMBRXF_STS_RX_BYTES GENMASK(4, 0)
+#define NPCM_SMBRXF_STS_RX_THST BIT(6)
+
+// NPCM_SMBFIF_CTL reg fields
+#define NPCM_SMBFIF_CTL_FIFO_EN BIT(4)
+
+// NPCM_SMBRXF_CTL reg fields
+#define NPCM_SMBRXF_CTL_RX_THR GENMASK(4, 0)
+#define NPCM_SMBRXF_CTL_LAST_PEC BIT(5)
+#define NPCM_SMBRXF_CTL_THR_RXIE BIT(6)
+
+#define SMBUS_FIFO_SIZE 16
+
+// SMB_VER reg fields
+#define SMB_VER_VERSION GENMASK(6, 0)
+#define SMB_VER_FIFO_EN BIT(7)
+
+// stall/stuck timeout
+const unsigned int DEFAULT_STALL_COUNT = 25;
+
+// retries in a loop for master abort
+const unsigned int RETRIES_NUM = 10000;
+
+// SMBus spec. values in KHZ
+const unsigned int SMBUS_FREQ_MIN = 10;
+const unsigned int SMBUS_FREQ_MAX = 1000;
+const unsigned int SMBUS_FREQ_100KHZ = 100;
+const unsigned int SMBUS_FREQ_400KHZ = 400;
+const unsigned int SMBUS_FREQ_1MHZ = 1000;
+
+// SCLFRQ min/max field values
+const unsigned int SCLFRQ_MIN = 10;
+const unsigned int SCLFRQ_MAX = 511;
+
+// SCLFRQ field position
+#define SCLFRQ_0_TO_6 GENMASK(6, 0)
+#define SCLFRQ_7_TO_8 GENMASK(8, 7)
+
+const unsigned int SMB_NUM_OF_ADDR = 10;
+
+#define NPCM_I2C_EVENT_START BIT(0)
+#define NPCM_I2C_EVENT_STOP BIT(1)
+#define NPCM_I2C_EVENT_ABORT BIT(2)
+#define NPCM_I2C_EVENT_WRITE BIT(3)
+
+#define NPCM_I2C_EVENT_READ BIT(4)
+#define NPCM_I2C_EVENT_BER BIT(5)
+#define NPCM_I2C_EVENT_NACK BIT(6)
+#define NPCM_I2C_EVENT_TO BIT(7)
+
+#define NPCM_I2C_EVENT_EOB BIT(8)
+#define NPCM_I2C_EVENT_STALL BIT(9)
+#define NPCM_I2C_EVENT_CB BIT(10)
+#define NPCM_I2C_EVENT_DONE BIT(11)
+
+#define NPCM_I2C_EVENT_READ1 BIT(12)
+#define NPCM_I2C_EVENT_READ2 BIT(13)
+#define NPCM_I2C_EVENT_READ3 BIT(14)
+#define NPCM_I2C_EVENT_READ4 BIT(15)
+
+#define NPCM_I2C_EVENT_NMATCH_SLV BIT(16)
+#define NPCM_I2C_EVENT_NMATCH_MSTR BIT(17)
+#define NPCM_I2C_EVENT_BER_SLV BIT(18)
+
+#define NPCM_I2C_EVENT_LOG(event) (bus->event_log |= event)
+
+// Status of one SMBus module
+struct npcm_i2c {
+ struct i2c_adapter adap;
+ struct device *dev;
+ unsigned char __iomem *reg;
+ spinlock_t lock; /* IRQ synchronization */
+ struct completion cmd_complete;
+ int irq;
+ int cmd_err;
+ struct i2c_msg *msgs;
+ int msgs_num;
+ int num;
+ u32 apb_clk;
+ struct i2c_bus_recovery_info rinfo;
+ enum smb_state state;
+ enum smb_oper operation;
+ enum smb_mode master_or_slave;
+ enum smb_state_ind stop_ind;
+ u8 dest_addr;
+ u8 *rd_buf;
+ u16 rd_size;
+ u16 rd_ind;
+ u8 *wr_buf;
+ u16 wr_size;
+ u16 wr_ind;
+ bool fifo_use;
+
+ // PEC bit mask per slave address.
+ // 1: use PEC for this address,
+ // 0: do not use PEC for this address
+ u16 PEC_mask;
+ bool PEC_use;
+ bool read_block_use;
+ u8 int_cnt;
+ u32 event_log;
+ u32 event_log_prev;
+ u32 clk_period_us;
+ unsigned long int_time_stamp;
+ unsigned long bus_freq; // in kHz
+ u32 xmits;
+
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+ u8 own_slave_addr;
+ struct i2c_client *slave;
+
+ // currently I2C slave IF only supports single byte operations.
+ // in order to utilyze the npcm HW FIFO, the driver will ask for 16bytes
+ // at a time, pack them in buffer, and then transmit them all together
+ // to the FIFO and onward to the bus .
+ // NACK on read will be once reached to bus->adap->quirks->max_read_len
+ // sending a NACK whever the backend requests for it is not supported.
+
+ // This module can be master and slave at the same time. separate ptrs
+ // and counters:
+ int slv_rd_size;
+ int slv_rd_ind;
+ int slv_wr_size;
+ int slv_wr_ind;
+ u8 slv_rd_buf[SMBUS_FIFO_SIZE];
+ u8 slv_wr_buf[SMBUS_FIFO_SIZE];
+#endif
+};
+
+static inline void npcm_smb_select_bank(struct npcm_i2c *bus,
+ enum smb_bank bank)
+{
+ if (bank == SMB_BANK_0)
+ iowrite8(ioread8(bus->reg + NPCM_SMBCTL3) & ~SMBCTL3_BNK_SEL,
+ bus->reg + NPCM_SMBCTL3);
+ else
+ iowrite8(ioread8(bus->reg + NPCM_SMBCTL3) | SMBCTL3_BNK_SEL,
+ bus->reg + NPCM_SMBCTL3);
+}
+
+static void npcm_smb_init_params(struct npcm_i2c *bus)
+{
+ bus->stop_ind = SMB_NO_STATUS_IND;
+ bus->rd_size = 0;
+ bus->wr_size = 0;
+ bus->rd_ind = 0;
+ bus->wr_ind = 0;
+ bus->int_cnt = 0;
+ bus->event_log_prev = bus->event_log;
+ bus->event_log = 0;
+ bus->read_block_use = false;
+ bus->int_time_stamp = 0;
+ bus->PEC_use = false;
+ bus->PEC_mask = 0;
+ if (bus->slave)
+ bus->master_or_slave = SMB_SLAVE;
+}
+
+static inline void npcm_smb_wr_byte(struct npcm_i2c *bus, u8 data)
+{
+ iowrite8(data, bus->reg + NPCM_SMBSDA);
+}
+
+static inline void npcm_smb_rd_byte(struct npcm_i2c *bus, u8 *data)
+{
+ *data = ioread8(bus->reg + NPCM_SMBSDA);
+}
+
+static inline u16 npcm_smb_get_index(struct npcm_i2c *bus)
+{
+ u16 index = 0;
+
+ if (bus->operation == SMB_READ_OPER)
+ index = bus->rd_ind;
+ else if (bus->operation == SMB_WRITE_OPER)
+ index = bus->wr_ind;
+
+ return index;
+}
+
+// quick protocol (just address):
+static inline bool npcm_smb_is_quick(struct npcm_i2c *bus)
+{
+ if (bus->wr_size == 0 && bus->rd_size == 0)
+ return true;
+ return false;
+}
+
+static void npcm_smb_disable(struct npcm_i2c *bus)
+{
+ int i;
+
+ // select bank 0 for SMB addresses
+ npcm_smb_select_bank(bus, SMB_BANK_0);
+
+ // Slave addresses removal
+ for (i = SMB_SLAVE_ADDR1; i < SMB_NUM_OF_ADDR; i++)
+ iowrite8(0, bus->reg + NPCM_SMBADDR[i]);
+
+ npcm_smb_select_bank(bus, SMB_BANK_1);
+
+ // Disable module.
+ iowrite8(ioread8(bus->reg + NPCM_SMBCTL2) & ~SMBCTL2_ENABLE,
+ bus->reg + NPCM_SMBCTL2);
+
+ bus->state = SMB_DISABLE;
+}
+
+static void npcm_smb_enable(struct npcm_i2c *bus)
+{
+ iowrite8((ioread8(bus->reg + NPCM_SMBCTL2) | SMBCTL2_ENABLE),
+ bus->reg + NPCM_SMBCTL2);
+
+ bus->state = SMB_IDLE;
+}
+
+static bool npcm_smb_wait_for_bus_free(struct npcm_i2c *bus, bool may_sleep)
+{
+ int cnt = 0;
+ int max_count = 2; /* wait for 2 ms */
+
+ if (may_sleep)
+ might_sleep();
+ else
+ max_count = max_count * 100; /* since each delay is 10 us */
+
+ while (ioread8(bus->reg + NPCM_SMBCST) & NPCM_SMBCST_BUSY) {
+ if (cnt < max_count) {
+ if (may_sleep)
+ msleep_interruptible(1);
+ else
+ udelay(10);
+ cnt++;
+
+ } else {
+ bus->cmd_err = -EAGAIN;
+ return false;
+ }
+ }
+ return true;
+}
+
+// enable\disable end of busy (EOB) interrupt
+static inline void npcm_smb_eob_int(struct npcm_i2c *bus, bool enable)
+{
+ // Clear EO_BUSY pending bit:
+ iowrite8(ioread8(bus->reg + NPCM_SMBCST3) | NPCM_SMBCST3_EO_BUSY,
+ bus->reg + NPCM_SMBCST3);
+
+ if (enable) {
+ iowrite8((ioread8(bus->reg + NPCM_SMBCTL1) |
+ NPCM_SMBCTL1_EOBINTE) & ~NPCM_SMBCTL1_RWS_FIELDS,
+ bus->reg + NPCM_SMBCTL1);
+ } else {
+ iowrite8(ioread8(bus->reg + NPCM_SMBCTL1) &
+ ~NPCM_SMBCTL1_EOBINTE & ~NPCM_SMBCTL1_RWS_FIELDS,
+ bus->reg + NPCM_SMBCTL1);
+ }
+}
+
+static inline bool npcm_smb_tx_fifo_empty(struct npcm_i2c *bus)
+{
+ u8 tx_fifo_sts = ioread8(bus->reg + NPCM_SMBTXF_STS);
+
+ // check if TX FIFO is not empty
+ if ((tx_fifo_sts & NPCM_SMBTXF_STS_TX_BYTES) == 0)
+ return false;
+
+ // check if TX FIFO status bit is set:
+ return (bool)FIELD_GET(NPCM_SMBTXF_STS_TX_THST, tx_fifo_sts);
+}
+
+static inline bool npcm_smb_rx_fifo_full(struct npcm_i2c *bus)
+{
+ u8 rx_fifo_sts = ioread8(bus->reg + NPCM_SMBRXF_STS);
+
+ // check if RX FIFO is not empty:
+ if ((rx_fifo_sts & NPCM_SMBRXF_STS_RX_BYTES) == 0)
+ return false;
+
+ // check if rx fifo full status is set:
+ return (bool)FIELD_GET(NPCM_SMBRXF_STS_RX_THST, rx_fifo_sts);
+}
+
+static inline void npcm_smb_clear_fifo_int(struct npcm_i2c *bus)
+{
+ iowrite8((ioread8(bus->reg + NPCM_SMBFIF_CTS) &
+ NPCM_SMBFIF_CTS_SLVRSTR) |
+ NPCM_SMBFIF_CTS_RXF_TXE,
+ bus->reg + NPCM_SMBFIF_CTS);
+}
+
+static inline void npcm_smb_clear_tx_fifo(struct npcm_i2c *bus)
+{
+ iowrite8(ioread8(bus->reg + NPCM_SMBTXF_STS) | NPCM_SMBTXF_STS_TX_THST,
+ bus->reg + NPCM_SMBTXF_STS);
+}
+
+static inline void npcm_smb_clear_rx_fifo(struct npcm_i2c *bus)
+{
+ iowrite8(ioread8(bus->reg + NPCM_SMBRXF_STS) | NPCM_SMBRXF_STS_RX_THST,
+ bus->reg + NPCM_SMBRXF_STS);
+}
+
+static void npcm_smb_int_enable(struct npcm_i2c *bus, bool enable)
+{
+ if (enable)
+ iowrite8((ioread8(bus->reg + NPCM_SMBCTL1) |
+ NPCM_SMBCTL1_INTEN) & ~NPCM_SMBCTL1_RWS_FIELDS,
+ bus->reg + NPCM_SMBCTL1);
+ else
+ iowrite8((ioread8(bus->reg + NPCM_SMBCTL1) &
+ ~NPCM_SMBCTL1_INTEN) & ~NPCM_SMBCTL1_RWS_FIELDS,
+ bus->reg + NPCM_SMBCTL1);
+}
+
+static inline void npcm_smb_master_start(struct npcm_i2c *bus)
+{
+ NPCM_I2C_EVENT_LOG(NPCM_I2C_EVENT_START);
+
+ iowrite8((ioread8(bus->reg + NPCM_SMBCTL1) | NPCM_SMBCTL1_START) &
+ ~(NPCM_SMBCTL1_STOP | NPCM_SMBCTL1_ACK),
+ bus->reg + NPCM_SMBCTL1);
+}
+
+static inline void npcm_smb_master_stop(struct npcm_i2c *bus)
+{
+ NPCM_I2C_EVENT_LOG(NPCM_I2C_EVENT_STOP);
+
+ // override HW issue: SMBus may fail to supply stop condition in Master
+ // Write operation.
+ // Need to delay at least 5 us from the last int, before issueing a stop
+ udelay(10);
+
+ iowrite8((ioread8(bus->reg + NPCM_SMBCTL1) | NPCM_SMBCTL1_STOP) &
+ ~(NPCM_SMBCTL1_START | NPCM_SMBCTL1_ACK),
+ bus->reg + NPCM_SMBCTL1);
+
+ if (bus->fifo_use) {
+ npcm_smb_select_bank(bus, SMB_BANK_1);
+
+ if (bus->operation == SMB_READ_OPER)
+ npcm_smb_clear_rx_fifo(bus);
+ else
+ npcm_smb_clear_tx_fifo(bus);
+
+ npcm_smb_clear_fifo_int(bus);
+
+ iowrite8(0, bus->reg + NPCM_SMBTXF_CTL);
+ }
+}
+
+static inline void npcm_smb_stall_after_start(struct npcm_i2c *bus, bool stall)
+{
+ if (stall)
+ iowrite8((ioread8(bus->reg + NPCM_SMBCTL1) |
+ NPCM_SMBCTL1_STASTRE) & ~NPCM_SMBCTL1_RWS_FIELDS,
+ bus->reg + NPCM_SMBCTL1);
+ else
+ iowrite8((ioread8(bus->reg + NPCM_SMBCTL1) &
+ ~NPCM_SMBCTL1_STASTRE) & ~NPCM_SMBCTL1_RWS_FIELDS,
+ bus->reg + NPCM_SMBCTL1);
+}
+
+static inline void npcm_smb_nack(struct npcm_i2c *bus)
+{
+ iowrite8((ioread8(bus->reg + NPCM_SMBCTL1) | NPCM_SMBCTL1_ACK) &
+ ~(NPCM_SMBCTL1_STOP | NPCM_SMBCTL1_START),
+ bus->reg + NPCM_SMBCTL1);
+}
+
+static int npcm_smb_slave_enable_l(struct npcm_i2c *bus,
+ enum smb_addr addr_type, u8 addr,
+ bool enable);
+
+static void npcm_smb_reset(struct npcm_i2c *bus)
+{
+ // Save NPCM_SMBCTL1 relevant bits. It is being cleared when the
+ // module is disabled
+ u8 smbctl1;
+
+ smbctl1 = ioread8(bus->reg + NPCM_SMBCTL1);
+
+ // Disable the SMB module
+ iowrite8((ioread8(bus->reg + NPCM_SMBCTL2) & ~SMBCTL2_ENABLE),
+ bus->reg + NPCM_SMBCTL2);
+
+ // Enable the SMB module
+ npcm_smb_enable(bus);
+
+ // Restore NPCM_SMBCTL1 status
+ iowrite8(smbctl1 & ~NPCM_SMBCTL1_RWS_FIELDS, bus->reg + NPCM_SMBCTL1);
+
+ // Clear BB (BUS BUSY) bit
+ iowrite8(NPCM_SMBCST_BB, bus->reg + NPCM_SMBCST);
+
+ iowrite8(0xFF, bus->reg + NPCM_SMBST);
+
+ // Clear EOB bit
+ iowrite8(NPCM_SMBCST3_EO_BUSY, bus->reg + NPCM_SMBCST3);
+
+ // Clear all fifo bits:
+ iowrite8(NPCM_SMBFIF_CTS_CLR_FIFO, bus->reg + NPCM_SMBFIF_CTS);
+
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+ if (bus->slave) {
+ npcm_smb_slave_enable_l(bus, SMB_SLAVE_ADDR1, bus->slave->addr,
+ true);
+ }
+#endif
+
+ bus->state = SMB_IDLE;
+}
+
+static inline bool npcm_smb_is_master(struct npcm_i2c *bus)
+{
+ return (bool)FIELD_GET(NPCM_SMBST_MASTER,
+ ioread8(bus->reg + NPCM_SMBST));
+}
+
+static void npcm_smb_callback(struct npcm_i2c *bus,
+ enum smb_state_ind op_status, u16 info)
+{
+ struct i2c_msg *msgs = bus->msgs;
+ int msgs_num = bus->msgs_num;
+
+ NPCM_I2C_EVENT_LOG(NPCM_I2C_EVENT_CB);
+
+ if (!msgs)
+ return;
+
+ if (completion_done(&bus->cmd_complete) == true)
+ return;
+
+ switch (op_status) {
+ case SMB_MASTER_DONE_IND:
+ bus->cmd_err = bus->msgs_num;
+ fallthrough;
+ case SMB_BLOCK_BYTES_ERR_IND:
+ // Master transaction finished and all transmit bytes were sent
+ if (bus->msgs) {
+ if (msgs[0].flags & I2C_M_RD)
+ msgs[0].len = info;
+ else if (msgs_num == 2 &&
+ msgs[1].flags & I2C_M_RD)
+ msgs[1].len = info;
+ }
+
+ NPCM_I2C_EVENT_LOG(NPCM_I2C_EVENT_DONE);
+
+ if (completion_done(&bus->cmd_complete) == false)
+ complete(&bus->cmd_complete);
+ break;
+
+ case SMB_NACK_IND:
+ // MASTER transmit got a NACK before tx all bytes
+ // info: number of transmitted bytes
+ bus->cmd_err = -ENXIO;
+ if (bus->master_or_slave == SMB_MASTER)
+ complete(&bus->cmd_complete);
+
+ break;
+ case SMB_BUS_ERR_IND:
+ // Bus error
+ bus->cmd_err = -EAGAIN;
+ if (bus->master_or_slave == SMB_MASTER)
+ complete(&bus->cmd_complete);
+
+ break;
+ case SMB_WAKE_UP_IND:
+ // SMBus wake up
+ break;
+ default:
+ break;
+ }
+
+ bus->operation = SMB_NO_OPER;
+ if (bus->slave)
+ bus->master_or_slave = SMB_SLAVE;
+}
+
+static u32 npcm_smb_get_fifo_fullness(struct npcm_i2c *bus)
+{
+ if (bus->operation == SMB_WRITE_OPER)
+ return FIELD_GET(NPCM_SMBTXF_STS_TX_BYTES,
+ ioread8(bus->reg + NPCM_SMBTXF_STS));
+ else if (bus->operation == SMB_READ_OPER)
+ return FIELD_GET(NPCM_SMBRXF_STS_RX_BYTES,
+ ioread8(bus->reg + NPCM_SMBRXF_STS));
+ return 0;
+}
+
+static void npcm_smb_write_to_fifo_master(struct npcm_i2c *bus,
+ u16 max_bytes_to_send)
+{
+ // Fill the FIFO, while the FIFO is not full and there are more bytes to
+ // write
+ if (max_bytes_to_send == 0)
+ return;
+ while ((max_bytes_to_send--) && (SMBUS_FIFO_SIZE -
+ npcm_smb_get_fifo_fullness(bus))) {
+ if (bus->wr_ind < bus->wr_size)
+ npcm_smb_wr_byte(bus, bus->wr_buf[bus->wr_ind++]);
+ else
+ npcm_smb_wr_byte(bus, 0xFF);
+ }
+}
+
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+static void npcm_smb_write_to_fifo_slave(struct npcm_i2c *bus,
+ u16 max_bytes_to_send)
+{
+ // Fill the FIFO, while the FIFO is not full and there are more bytes to
+ // write
+ npcm_smb_clear_fifo_int(bus);
+ npcm_smb_clear_tx_fifo(bus);
+ iowrite8(0, bus->reg + NPCM_SMBTXF_CTL);
+
+ if (max_bytes_to_send == 0)
+ return;
+
+ while ((max_bytes_to_send--) && (SMBUS_FIFO_SIZE -
+ npcm_smb_get_fifo_fullness(bus))) {
+ if (bus->slv_wr_size > 0) {
+ npcm_smb_wr_byte(bus,
+ bus->slv_wr_buf[bus->slv_wr_ind %
+ SMBUS_FIFO_SIZE]);
+ bus->slv_wr_ind = (bus->slv_wr_ind + 1) %
+ SMBUS_FIFO_SIZE;
+ bus->slv_wr_size--; // size indicates the # of bytes in
+ // the SW FIFO, not HW.
+ } else {
+ break;
+ }
+ }
+}
+#endif
+
+// configure the FIFO before using it. If nread is -1 RX FIFO will not be
+// configured. same for nwrite
+static void npcm_smb_set_fifo(struct npcm_i2c *bus, int nread, int nwrite)
+{
+ u8 rxf_ctl = 0;
+
+ if (!bus->fifo_use)
+ return;
+ npcm_smb_select_bank(bus, SMB_BANK_1);
+ npcm_smb_clear_tx_fifo(bus);
+ npcm_smb_clear_rx_fifo(bus);
+
+ // configure RX FIFO
+ if (nread > 0) {
+ rxf_ctl = min_t(u16, (u16)nread, (u16)SMBUS_FIFO_SIZE);
+
+ // set LAST bit. if LAST is set enxt FIFO packet is nacked
+ // regular read of less then buffer size:
+ if (nread <= SMBUS_FIFO_SIZE)
+ rxf_ctl |= NPCM_SMBRXF_CTL_LAST_PEC;
+ // if we are about to read the first byte in blk rd mode,
+ // don't NACK it. BTW, if slave return zero size HW can't NACK
+ // it immidiattly, it will read extra byte and then NACK.
+ if (bus->rd_ind == 0 && bus->read_block_use) {
+ // set fifo to read one byte, no last:
+ rxf_ctl = 1;
+ }
+
+ // set fifo size:
+ iowrite8(rxf_ctl, bus->reg + NPCM_SMBRXF_CTL);
+ }
+
+ // configure TX FIFO
+ if (nwrite > 0) {
+ if (nwrite > SMBUS_FIFO_SIZE)
+ // data to send is more then FIFO size.
+ // Configure the FIFO int to be after of FIFO is cleared
+ iowrite8(SMBUS_FIFO_SIZE, bus->reg + NPCM_SMBTXF_CTL);
+ else
+ iowrite8(nwrite, bus->reg + NPCM_SMBTXF_CTL);
+
+ npcm_smb_clear_tx_fifo(bus);
+ }
+}
+
+static void npcm_smb_read_from_fifo(struct npcm_i2c *bus, u8 bytes_in_fifo)
+{
+ u8 data;
+
+ while (bytes_in_fifo--) {
+ npcm_smb_rd_byte(bus, &data);
+
+ if (bus->master_or_slave == SMB_MASTER) {
+ if (bus->rd_ind < bus->rd_size)
+ bus->rd_buf[bus->rd_ind++] = data;
+ } else { // SMB_SLAVE:
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+ if (bus->slave) {
+ bus->slv_rd_buf[bus->slv_rd_ind %
+ SMBUS_FIFO_SIZE] = data;
+ bus->slv_rd_ind++;
+ if (bus->slv_rd_ind == 1 && bus->read_block_use)
+ // 1st byte is length in block protocol
+ bus->slv_rd_size = data +
+ (u8)bus->PEC_use +
+ (u8)bus->read_block_use;
+ }
+#endif
+ }
+ }
+}
+
+static int npcm_smb_master_abort(struct npcm_i2c *bus)
+{
+ int ret = 0;
+
+ NPCM_I2C_EVENT_LOG(NPCM_I2C_EVENT_ABORT);
+
+ // Only current master is allowed to issue Stop Condition
+ if (npcm_smb_is_master(bus)) {
+ npcm_smb_eob_int(bus, true);
+ npcm_smb_master_stop(bus);
+
+ // Clear NEGACK, STASTR and BER bits
+ iowrite8(NPCM_SMBST_BER | NPCM_SMBST_NEGACK | NPCM_SMBST_STASTR,
+ bus->reg + NPCM_SMBST);
+ }
+
+ return ret;
+}
+
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+static irqreturn_t npcm_i2c_bus_irq(int irq, void *dev_id);
+
+static int npcm_smb_slave_enable_l(struct npcm_i2c *bus,
+ enum smb_addr addr_type, u8 addr,
+ bool enable)
+{
+ u8 slave_addr_reg = FIELD_PREP(NPCM_SMBADDR_A, addr) |
+ FIELD_PREP(NPCM_SMBADDR_SAEN, enable);
+
+ if (addr_type == SMB_GC_ADDR) {
+ iowrite8((ioread8(bus->reg + NPCM_SMBCTL1) &
+ ~NPCM_SMBCTL1_GCMEN) |
+ FIELD_PREP(NPCM_SMBCTL1_GCMEN, enable),
+ bus->reg + NPCM_SMBCTL1);
+ return 0;
+ }
+ if (addr_type == SMB_ARP_ADDR) {
+ iowrite8((ioread8(bus->reg + NPCM_SMBCTL3) &
+ ~SMBCTL3_ARPMEN) |
+ FIELD_PREP(SMBCTL3_ARPMEN, enable),
+ bus->reg + NPCM_SMBCTL3);
+ return 0;
+ }
+ if (addr_type >= SMB_ARP_ADDR)
+ return -EFAULT;
+
+ // select bank 0 for address 3 to 10
+ if (addr_type > SMB_SLAVE_ADDR2)
+ npcm_smb_select_bank(bus, SMB_BANK_0);
+
+ // Set and enable the address
+ iowrite8(slave_addr_reg, bus->reg + NPCM_SMBADDR[(int)addr_type]);
+
+ // enable interrupt on slave match:
+ iowrite8((ioread8(bus->reg + NPCM_SMBCTL1) | NPCM_SMBCTL1_NMINTE) &
+ ~NPCM_SMBCTL1_RWS_FIELDS, bus->reg + NPCM_SMBCTL1);
+
+ if (addr_type > SMB_SLAVE_ADDR2)
+ npcm_smb_select_bank(bus, SMB_BANK_1);
+ return 0;
+}
+
+static u8 npcm_smb_get_slave_addr(struct npcm_i2c *bus,
+ enum smb_addr addr_type)
+{
+ u8 slave_add;
+
+ // select bank 0 for address 3 to 10
+ if (addr_type > SMB_SLAVE_ADDR2)
+ npcm_smb_select_bank(bus, SMB_BANK_0);
+
+ slave_add = ioread8(bus->reg + NPCM_SMBADDR[(int)addr_type]);
+
+ if (addr_type > SMB_SLAVE_ADDR2)
+ npcm_smb_select_bank(bus, SMB_BANK_1);
+
+ return slave_add;
+}
+
+static int npcm_smb_remove_slave_addr(struct npcm_i2c *bus, u8 slave_add)
+{
+ int i;
+
+ slave_add |= 0x80; //Set the enable bit
+
+ npcm_smb_select_bank(bus, SMB_BANK_0);
+
+ for (i = SMB_SLAVE_ADDR1; i < SMB_NUM_OF_ADDR; i++) {
+ if (ioread8(bus->reg + NPCM_SMBADDR[i]) == slave_add)
+ iowrite8(0, bus->reg + NPCM_SMBADDR[i]);
+ }
+
+ npcm_smb_select_bank(bus, SMB_BANK_1);
+
+ return 0;
+}
+
+static int npcm_i2c_slave_get_wr_buf(struct npcm_i2c *bus)
+{
+ u8 value = 0;
+ int ret = bus->slv_wr_ind;
+ int i;
+
+ // fill a cyclic buffer
+ for (i = 0; i < SMBUS_FIFO_SIZE; i++) {
+ if (bus->slv_wr_size >= SMBUS_FIFO_SIZE)
+ break;
+ i2c_slave_event(bus->slave, I2C_SLAVE_READ_REQUESTED, &value);
+ bus->slv_wr_buf[(bus->slv_wr_ind + bus->slv_wr_size) %
+ SMBUS_FIFO_SIZE] = value;
+ bus->slv_wr_size++;
+ i2c_slave_event(bus->slave, I2C_SLAVE_READ_PROCESSED, &value);
+ }
+ return SMBUS_FIFO_SIZE - ret;
+}
+
+static void npcm_i2c_slave_send_rd_buf(struct npcm_i2c *bus)
+{
+ int i;
+
+ for (i = 0; i < bus->slv_rd_ind; i++)
+ i2c_slave_event(bus->slave, I2C_SLAVE_WRITE_RECEIVED,
+ &bus->slv_rd_buf[i]);
+
+ // once we send bytes up, need to reset the counter of the wr buf
+ // got data from master (new offset in device), ignore wr fifo:
+ if (bus->slv_rd_ind) {
+ bus->slv_wr_size = 0;
+ bus->slv_wr_ind = 0;
+ }
+
+ bus->slv_rd_ind = 0;
+ bus->slv_rd_size = bus->adap.quirks->max_read_len;
+
+ npcm_smb_clear_fifo_int(bus);
+ npcm_smb_clear_rx_fifo(bus);
+}
+
+static bool npcm_smb_slave_receive(struct npcm_i2c *bus, u16 nread,
+ u8 *read_data)
+{
+ bus->state = SMB_OPER_STARTED;
+ bus->operation = SMB_READ_OPER;
+ bus->slv_rd_size = nread;
+ bus->slv_rd_ind = 0;
+
+ iowrite8(0, bus->reg + NPCM_SMBTXF_CTL);
+ iowrite8(SMBUS_FIFO_SIZE, bus->reg + NPCM_SMBRXF_CTL);
+
+ npcm_smb_clear_tx_fifo(bus);
+ npcm_smb_clear_rx_fifo(bus);
+
+ return true;
+}
+
+static bool npcm_smb_slave_xmit(struct npcm_i2c *bus, u16 nwrite,
+ u8 *write_data)
+{
+ if (nwrite == 0)
+ return false;
+
+ bus->state = SMB_OPER_STARTED;
+ bus->operation = SMB_WRITE_OPER;
+
+ // get the next buffer
+ npcm_i2c_slave_get_wr_buf(bus);
+
+ if (nwrite > 0)
+ npcm_smb_write_to_fifo_slave(bus, nwrite);
+
+ return true;
+}
+
+// currently slave IF only supports single byte operations.
+// in order to utilyze the npcm HW FIFO, the driver will ask for 16 bytes
+// at a time, pack them in buffer, and then transmit them all together
+// to the FIFO and onward to the bus.
+// NACK on read will be once reached to bus->adap->quirks->max_read_len.
+// sending a NACK wherever the backend requests for it is not supported.
+// the next two functions allow reading to local buffer before writing it all
+// to the HW FIFO.
+// ret val: number of bytes read form the IF:
+
+static int npcm_i2c_slave_wr_buf_sync(struct npcm_i2c *bus)
+{
+ int left_in_fifo = FIELD_GET(NPCM_SMBTXF_STS_TX_BYTES,
+ ioread8(bus->reg + NPCM_SMBTXF_STS));
+
+ if (left_in_fifo >= SMBUS_FIFO_SIZE)
+ return left_in_fifo;
+
+ if (bus->slv_wr_size >= SMBUS_FIFO_SIZE)
+ return left_in_fifo; // fifo already full
+
+ // update the wr fifo ind, back to the untransmitted bytes:
+ bus->slv_wr_ind = bus->slv_wr_ind - left_in_fifo;
+ bus->slv_wr_size = bus->slv_wr_size + left_in_fifo;
+
+ if (bus->slv_wr_ind < 0)
+ bus->slv_wr_ind += SMBUS_FIFO_SIZE;
+
+ return left_in_fifo;
+}
+
+static void npcm_i2c_slave_rd_wr(struct npcm_i2c *bus)
+{
+ if (FIELD_GET(NPCM_SMBST_XMIT, ioread8(bus->reg + NPCM_SMBST))) {
+ // Slave got an address match with direction bit 1 so
+ // it should transmit data
+ // Write till the master will NACK
+ bus->operation = SMB_WRITE_OPER;
+ npcm_smb_slave_xmit(bus,
+ bus->adap.quirks->max_write_len,
+ bus->slv_wr_buf);
+ } else {
+ // Slave got an address match with direction bit 0
+ // so it should receive data.
+ // this module does not support saying no to bytes.
+ // it will always ACK.
+ bus->operation = SMB_READ_OPER;
+ npcm_smb_read_from_fifo(bus, npcm_smb_get_fifo_fullness(bus));
+ bus->stop_ind = SMB_SLAVE_RCV_IND;
+ npcm_i2c_slave_send_rd_buf(bus);
+ npcm_smb_slave_receive(bus,
+ bus->adap.quirks->max_read_len,
+ bus->slv_rd_buf);
+ }
+}
+
+static irqreturn_t npcm_smb_int_slave_handler(struct npcm_i2c *bus)
+{
+ irqreturn_t ret = IRQ_NONE;
+ u8 smbst = ioread8(bus->reg + NPCM_SMBST);
+ // Slave: A NACK has occurred
+ if (FIELD_GET(NPCM_SMBST_NEGACK, smbst)) {
+ NPCM_I2C_EVENT_LOG(NPCM_I2C_EVENT_NACK);
+ bus->stop_ind = SMB_NACK_IND;
+ npcm_i2c_slave_wr_buf_sync(bus);
+ if (bus->fifo_use)
+ // clear the FIFO
+ iowrite8(NPCM_SMBFIF_CTS_CLR_FIFO,
+ bus->reg + NPCM_SMBFIF_CTS);
+
+ // In slave write, NACK is OK, otherwise it is a problem
+ bus->stop_ind = SMB_NO_STATUS_IND;
+ bus->operation = SMB_NO_OPER;
+ bus->own_slave_addr = 0xFF;
+
+ // Slave has to wait for SMB_STOP to decide this is the end
+ // of the transaction.
+ // Therefore transaction is not yet considered as done
+ iowrite8(NPCM_SMBST_NEGACK, bus->reg + NPCM_SMBST);
+
+ ret = IRQ_HANDLED;
+ }
+
+ // Slave mode: a Bus Error (BER) has been identified
+ if (FIELD_GET(NPCM_SMBST_BER, smbst)) {
+ // Check whether bus arbitration or Start or Stop during data
+ // xfer bus arbitration problem should not result in recovery
+ NPCM_I2C_EVENT_LOG(NPCM_I2C_EVENT_BER_SLV);
+ bus->stop_ind = SMB_BUS_ERR_IND;
+
+ // wait for bus busy before clear fifo
+ iowrite8(NPCM_SMBFIF_CTS_CLR_FIFO, bus->reg + NPCM_SMBFIF_CTS);
+
+ bus->state = SMB_IDLE;
+
+ // in BER case we might get 2 interrupts: one for slave one for
+ // master ( for a channel which is master\slave switching)
+ if (completion_done(&bus->cmd_complete) == false) {
+ bus->cmd_err = -EIO;
+ complete(&bus->cmd_complete);
+ }
+ bus->own_slave_addr = 0xFF;
+ iowrite8(NPCM_SMBST_BER, bus->reg + NPCM_SMBST);
+ ret = IRQ_HANDLED;
+ }
+
+ // A Slave Stop Condition has been identified
+ if (FIELD_GET(NPCM_SMBST_SLVSTP, smbst)) {
+ int bytes_in_fifo = npcm_smb_get_fifo_fullness(bus);
+
+ bus->stop_ind = SMB_SLAVE_DONE_IND;
+
+ if (bus->operation == SMB_READ_OPER) {
+ npcm_smb_read_from_fifo(bus, bytes_in_fifo);
+
+ // Slave done transmitting or receiving
+ // if the buffer is empty nothing will be sent
+ }
+
+ // Slave done transmitting or receiving
+ // if the buffer is empty nothing will be sent
+ npcm_i2c_slave_send_rd_buf(bus);
+
+ bus->stop_ind = SMB_NO_STATUS_IND;
+
+ // Note, just because we got here, it doesn't mean we through
+ // away the wr buffer.
+ // we keep it until the next received offset.
+ bus->operation = SMB_NO_OPER;
+ bus->int_cnt = 0;
+ bus->event_log_prev = bus->event_log;
+ bus->event_log = 0;
+ bus->own_slave_addr = 0xFF;
+
+ i2c_slave_event(bus->slave, I2C_SLAVE_STOP, 0);
+
+ iowrite8(NPCM_SMBST_SLVSTP, bus->reg + NPCM_SMBST);
+
+ if (bus->fifo_use) {
+ npcm_smb_clear_fifo_int(bus);
+ npcm_smb_clear_rx_fifo(bus);
+ npcm_smb_clear_tx_fifo(bus);
+
+ iowrite8(NPCM_SMBFIF_CTS_CLR_FIFO,
+ bus->reg + NPCM_SMBFIF_CTS);
+ }
+
+ bus->state = SMB_IDLE;
+ ret = IRQ_HANDLED;
+ }
+
+ // restart condition occurred and Rx-FIFO was not empty
+ if (bus->fifo_use && FIELD_GET(NPCM_SMBFIF_CTS_SLVRSTR,
+ ioread8(bus->reg + NPCM_SMBFIF_CTS))) {
+ bus->stop_ind = SMB_SLAVE_RESTART_IND;
+
+ bus->master_or_slave = SMB_SLAVE;
+
+ if (bus->operation == SMB_READ_OPER)
+ npcm_smb_read_from_fifo(bus,
+ npcm_smb_get_fifo_fullness(bus)
+ );
+
+ bus->operation = SMB_WRITE_OPER;
+
+ iowrite8(0, bus->reg + NPCM_SMBRXF_CTL);
+
+ iowrite8(NPCM_SMBFIF_CTS_CLR_FIFO | NPCM_SMBFIF_CTS_SLVRSTR |
+ NPCM_SMBFIF_CTS_RXF_TXE, bus->reg + NPCM_SMBFIF_CTS);
+
+ npcm_i2c_slave_rd_wr(bus);
+
+ ret = IRQ_HANDLED;
+ }
+
+ // A Slave Address Match has been identified
+ if (FIELD_GET(NPCM_SMBST_NMATCH, smbst)) {
+ u8 info = 0;
+
+ NPCM_I2C_EVENT_LOG(NPCM_I2C_EVENT_NMATCH_SLV);
+ // Address match automatically implies slave mode
+ bus->master_or_slave = SMB_SLAVE;
+
+ npcm_smb_clear_fifo_int(bus);
+ npcm_smb_clear_rx_fifo(bus);
+ npcm_smb_clear_tx_fifo(bus);
+ iowrite8(0, bus->reg + NPCM_SMBTXF_CTL);
+ iowrite8(SMBUS_FIFO_SIZE, bus->reg + NPCM_SMBRXF_CTL);
+
+ if (FIELD_GET(NPCM_SMBST_XMIT, smbst)) {
+ bus->operation = SMB_WRITE_OPER;
+ } else {
+ i2c_slave_event(bus->slave, I2C_SLAVE_WRITE_REQUESTED,
+ &info);
+ bus->operation = SMB_READ_OPER;
+ }
+
+ if (bus->own_slave_addr == 0xFF) { // unknown address
+ // Check which type of address match
+ if (FIELD_GET(NPCM_SMBCST_MATCH,
+ ioread8(bus->reg + NPCM_SMBCST))) {
+ u16 addr;
+ enum smb_addr eaddr;
+
+ addr = ((ioread8(bus->reg + NPCM_SMBCST3) &
+ 0x7) << 7) |
+ (ioread8(bus->reg + NPCM_SMBCST2) &
+ 0x7F);
+
+ info = ffs(addr);
+ eaddr = (enum smb_addr)info;
+
+ addr = FIELD_GET(NPCM_SMBADDR_A,
+ npcm_smb_get_slave_addr(bus,
+ eaddr)
+ );
+ bus->own_slave_addr = addr;
+
+ if (bus->PEC_mask & BIT(info))
+ bus->PEC_use = true;
+ else
+ bus->PEC_use = false;
+ } else {
+ if (FIELD_GET(NPCM_SMBCST_GCMATCH,
+ ioread8(bus->reg + NPCM_SMBCST)))
+ bus->own_slave_addr = 0;
+ if (FIELD_GET(NPCM_SMBCST_ARPMATCH,
+ ioread8(bus->reg + NPCM_SMBCST)))
+ bus->own_slave_addr = 0x61;
+ }
+ } else {
+ // Slave match can happen in two options:
+ // 1. Start, SA, read (slave read without further ado)
+ // 2. Start, SA, read, data, restart, SA, read, ...
+ // (slave read in fragmented mode)
+ // 3. Start, SA, write, data, restart, SA, read, ..
+ // (regular write-read mode)
+ if ((bus->state == SMB_OPER_STARTED &&
+ bus->operation == SMB_READ_OPER &&
+ bus->stop_ind == SMB_SLAVE_XMIT_IND) ||
+ bus->stop_ind == SMB_SLAVE_RCV_IND) {
+ // slave transmit after slave receive w/o Slave
+ // Stop implies repeated start
+ bus->stop_ind = SMB_SLAVE_RESTART_IND;
+ }
+ }
+
+ if (FIELD_GET(NPCM_SMBST_XMIT, smbst))
+ bus->stop_ind = SMB_SLAVE_XMIT_IND;
+ else
+ bus->stop_ind = SMB_SLAVE_RCV_IND;
+
+ bus->state = SMB_SLAVE_MATCH;
+
+ npcm_i2c_slave_rd_wr(bus);
+
+ iowrite8(NPCM_SMBST_NMATCH, bus->reg + NPCM_SMBST);
+ ret = IRQ_HANDLED;
+ }
+
+ // Slave SDA status is set - transmit or receive, slave
+ if (FIELD_GET(NPCM_SMBST_SDAST, smbst) ||
+ (bus->fifo_use &&
+ (npcm_smb_tx_fifo_empty(bus) || npcm_smb_rx_fifo_full(bus)))) {
+ npcm_i2c_slave_rd_wr(bus);
+
+ iowrite8(NPCM_SMBST_SDAST, bus->reg + NPCM_SMBST);
+
+ ret = IRQ_HANDLED;
+ } //SDAST
+
+ return ret;
+}
+
+static int npcm_i2c_reg_slave(struct i2c_client *client)
+{
+ unsigned long lock_flags;
+ struct npcm_i2c *bus = i2c_get_adapdata(client->adapter);
+
+ bus->slave = client;
+
+ if (!bus->slave)
+ return -EINVAL;
+
+ if (client->flags & I2C_CLIENT_TEN)
+ return -EAFNOSUPPORT;
+
+ spin_lock_irqsave(&bus->lock, lock_flags);
+
+ npcm_smb_init_params(bus);
+ bus->slv_rd_size = 0;
+ bus->slv_wr_size = 0;
+ bus->slv_rd_ind = 0;
+ bus->slv_wr_ind = 0;
+ if (client->flags & I2C_CLIENT_PEC)
+ bus->PEC_use = true;
+
+ dev_info(bus->dev, "I2C%d register slave SA=0x%x, PEC=%d\n", bus->num,
+ client->addr, bus->PEC_use);
+
+ npcm_smb_slave_enable_l(bus, SMB_SLAVE_ADDR1, client->addr, true);
+
+ npcm_smb_clear_fifo_int(bus);
+ npcm_smb_clear_rx_fifo(bus);
+ npcm_smb_clear_tx_fifo(bus);
+
+ spin_unlock_irqrestore(&bus->lock, lock_flags);
+
+ return 0;
+}
+
+static int npcm_i2c_unreg_slave(struct i2c_client *client)
+{
+ struct npcm_i2c *bus = client->adapter->algo_data;
+ unsigned long lock_flags;
+
+ spin_lock_irqsave(&bus->lock, lock_flags);
+ if (!bus->slave) {
+ spin_unlock_irqrestore(&bus->lock, lock_flags);
+ return -EINVAL;
+ }
+
+ npcm_smb_remove_slave_addr(bus, client->addr);
+
+ bus->slave = NULL;
+ spin_unlock_irqrestore(&bus->lock, lock_flags);
+
+ return 0;
+}
+#endif // CONFIG_I2C_SLAVE
+
+static void npcm_smb_master_fifo_read(struct npcm_i2c *bus)
+{
+ int rcount;
+ int fifo_bytes;
+ enum smb_state_ind ind = SMB_MASTER_DONE_IND;
+
+ fifo_bytes = npcm_smb_get_fifo_fullness(bus);
+
+ rcount = bus->rd_size - bus->rd_ind;
+
+ // In order not to change the RX_TRH during transaction (we found that
+ // this might be problematic if it takes too much time to read the FIFO)
+ // we read the data in the following way. If the number of bytes to
+ // read == FIFO Size + C (where C < FIFO Size)then first read C bytes
+ // and in the next int we read rest of the data.
+ if (rcount < (2 * SMBUS_FIFO_SIZE) && rcount > SMBUS_FIFO_SIZE)
+ fifo_bytes = (u8)(rcount - SMBUS_FIFO_SIZE);
+
+ if ((rcount - fifo_bytes) <= 0) {
+ // last bytes are about to be read - end of transaction.
+ // Stop should be set before reading last byte.
+ NPCM_I2C_EVENT_LOG(NPCM_I2C_EVENT_READ4);
+
+ bus->state = SMB_STOP_PENDING;
+ bus->stop_ind = ind;
+
+ npcm_smb_eob_int(bus, true);
+ npcm_smb_master_stop(bus);
+ npcm_smb_read_from_fifo(bus, fifo_bytes);
+ } else {
+ NPCM_I2C_EVENT_LOG(NPCM_I2C_EVENT_READ3);
+ npcm_smb_read_from_fifo(bus, fifo_bytes);
+ rcount = bus->rd_size - bus->rd_ind;
+ npcm_smb_set_fifo(bus, rcount, -1);
+ }
+}
+
+static void npcm_smb_int_master_handler_write(struct npcm_i2c *bus)
+{
+ u16 wcount;
+
+ NPCM_I2C_EVENT_LOG(NPCM_I2C_EVENT_WRITE);
+ if (bus->fifo_use)
+ npcm_smb_clear_tx_fifo(bus); // clear the TX fifo status bit
+
+ // Master write operation - last byte handling
+ if (bus->wr_ind == bus->wr_size) {
+ if (bus->fifo_use && npcm_smb_get_fifo_fullness(bus) > 0)
+ // No more bytes to send (to add to the FIFO),
+ // however the FIFO is not empty yet. It is
+ // still in the middle of tx. Currently there's nothing
+ // to do except for waiting to the end of the tx.
+ // We will get an int when the FIFO will get empty.
+ return;
+
+ if (bus->rd_size == 0) {
+ // all bytes have been written, in a pure wr operation
+ npcm_smb_eob_int(bus, true);
+
+ bus->state = SMB_STOP_PENDING;
+ bus->stop_ind = SMB_MASTER_DONE_IND;
+
+ npcm_smb_master_stop(bus);
+ // Clear SDA Status bit (by writing dummy byte)
+ npcm_smb_wr_byte(bus, 0xFF);
+
+ } else {
+ // last write-byte written on previous int - need to
+ // restart & send slave address
+ npcm_smb_set_fifo(bus, bus->rd_size, -1);
+
+ // Generate repeated start upon next write to SDA
+ npcm_smb_master_start(bus);
+
+ if (bus->rd_size == 1)
+ // Receiving one byte only - stall after
+ // successful completion of send
+ // address byte. If we NACK here,
+ // and slave doesn't ACK the address, we
+ // might unintentionally NACK the next
+ // multi-byte read
+ npcm_smb_stall_after_start(bus, true);
+
+ // Next int will occur on read
+ bus->operation = SMB_READ_OPER;
+
+ // send the slave address in read direction
+ npcm_smb_wr_byte(bus, bus->dest_addr | 0x1);
+ }
+ } else {
+ // write next byte not last byte and not slave address
+ if (!bus->fifo_use || bus->wr_size == 1) {
+ npcm_smb_wr_byte(bus, bus->wr_buf[bus->wr_ind++]);
+ } else {
+ wcount = bus->wr_size - bus->wr_ind;
+ npcm_smb_set_fifo(bus, -1, wcount);
+ npcm_smb_write_to_fifo_master(bus, wcount);
+ }
+ }
+}
+
+static void npcm_smb_int_master_handler_read(struct npcm_i2c *bus)
+{
+ u16 block_extra_bytes_size;
+ u8 data;
+
+ // Master read operation (pure read or following a write operation).
+ NPCM_I2C_EVENT_LOG(NPCM_I2C_EVENT_READ);
+
+ // added bytes to the packet:
+ block_extra_bytes_size = (u8)bus->read_block_use + (u8)bus->PEC_use;
+
+ // Perform master read, distinguishing between last byte and the rest of
+ // the bytes. The last byte should be read when the clock is stopped
+ if (bus->rd_ind == 0) { //first byte handling:
+ // in block protocol first byte is the size
+ NPCM_I2C_EVENT_LOG(NPCM_I2C_EVENT_READ1);
+ if (bus->read_block_use) {
+ // first byte in block protocol is the size:
+ npcm_smb_rd_byte(bus, &data);
+
+ // if slave returned illegal size. read up to 32 bytes.
+ if (data >= I2C_SMBUS_BLOCK_MAX)
+ data = I2C_SMBUS_BLOCK_MAX;
+
+ // is data is 0 -> not supported. read at least one byte
+ if (data == 0)
+ data = 1;
+
+ bus->rd_size = data + block_extra_bytes_size;
+
+ bus->rd_buf[bus->rd_ind++] = data;
+
+ // clear RX FIFO interrupt status:
+ if (bus->fifo_use) {
+ iowrite8(NPCM_SMBFIF_CTS_RXF_TXE |
+ ioread8(bus->reg + NPCM_SMBFIF_CTS),
+ bus->reg + NPCM_SMBFIF_CTS);
+ }
+
+ npcm_smb_set_fifo(bus, (bus->rd_size - 1), -1);
+ npcm_smb_stall_after_start(bus, false);
+ } else {
+ npcm_smb_clear_tx_fifo(bus);
+ npcm_smb_master_fifo_read(bus);
+ }
+ } else {
+ if (bus->rd_size == block_extra_bytes_size &&
+ bus->read_block_use) {
+ bus->state = SMB_STOP_PENDING;
+ bus->stop_ind = SMB_BLOCK_BYTES_ERR_IND;
+ bus->cmd_err = -EIO;
+ npcm_smb_eob_int(bus, true);
+ npcm_smb_master_stop(bus);
+ npcm_smb_read_from_fifo(bus,
+ npcm_smb_get_fifo_fullness(bus)
+ );
+ } else {
+ NPCM_I2C_EVENT_LOG(NPCM_I2C_EVENT_READ2);
+ npcm_smb_master_fifo_read(bus);
+ }
+ }
+}
+
+static irqreturn_t npcm_smb_int_master_handler(struct npcm_i2c *bus)
+{
+ irqreturn_t ret = IRQ_NONE;
+ u8 fif_cts;
+
+ if (FIELD_GET(NPCM_SMBST_NMATCH, ioread8(bus->reg + NPCM_SMBST))) {
+ NPCM_I2C_EVENT_LOG(NPCM_I2C_EVENT_NMATCH_MSTR);
+ iowrite8(NPCM_SMBST_NMATCH, bus->reg + NPCM_SMBST);
+ npcm_smb_nack(bus);
+ bus->stop_ind = SMB_BUS_ERR_IND;
+ npcm_smb_callback(bus, bus->stop_ind, npcm_smb_get_index(bus));
+
+ return IRQ_HANDLED;
+ }
+ // A NACK has occurred
+ if (FIELD_GET(NPCM_SMBST_NEGACK, ioread8(bus->reg + NPCM_SMBST))) {
+ NPCM_I2C_EVENT_LOG(NPCM_I2C_EVENT_NACK);
+ if (bus->fifo_use) {
+ // if there are still untransmitted bytes in TX FIFO
+ // reduce them from wr_ind
+ if (bus->operation == SMB_WRITE_OPER)
+ bus->wr_ind -= npcm_smb_get_fifo_fullness(bus);
+
+ // clear the FIFO
+ iowrite8(NPCM_SMBFIF_CTS_CLR_FIFO,
+ bus->reg + NPCM_SMBFIF_CTS);
+ }
+
+ // In master write operation, NACK is a problem
+ // number of bytes sent to master less than required
+ bus->stop_ind = SMB_NACK_IND;
+ // Only current master is allowed to issue Stop Condition
+ if (npcm_smb_is_master(bus)) {
+ // stopping in the middle, not waiting for ints anymore
+ npcm_smb_eob_int(bus, false);
+
+ npcm_smb_master_stop(bus);
+
+ // Clear NEGACK, STASTR and BER bits
+ // In Master mode, NEGACK should be cleared only after
+ // generating STOP.
+ // In such case, the bus is released from stall only
+ // after the software clears NEGACK bit.
+ // Then a Stop condition is sent.
+ iowrite8(NPCM_SMBST_BER | NPCM_SMBST_NEGACK |
+ NPCM_SMBST_STASTR, bus->reg + NPCM_SMBST);
+
+ npcm_smb_wait_for_bus_free(bus, false);
+ }
+ bus->state = SMB_IDLE;
+
+ // In Master mode, NACK should be cleared only after
+ // generating STOP.
+ // In such case, the bus is released from stall only after the
+ // software clears NACK bit.
+ // Then a Stop condition is sent.
+ npcm_smb_callback(bus, bus->stop_ind, bus->wr_ind);
+ return IRQ_HANDLED;
+ }
+
+ // Master mode: a Bus Error has been identified
+ if (FIELD_GET(NPCM_SMBST_BER, ioread8(bus->reg + NPCM_SMBST))) {
+ // Check whether bus arbitration or Start or Stop during data
+ // xfer bus arbitration problem should not result in recovery
+ NPCM_I2C_EVENT_LOG(NPCM_I2C_EVENT_BER);
+ bus->stop_ind = SMB_BUS_ERR_IND;
+ if (npcm_smb_is_master(bus)) {
+ npcm_smb_master_abort(bus);
+ } else {
+ // Clear NEGACK, STASTR and BER bits
+ iowrite8(NPCM_SMBST_BER | NPCM_SMBST_NEGACK |
+ NPCM_SMBST_STASTR, bus->reg + NPCM_SMBST);
+
+ // Clear BB (BUS BUSY) bit
+ iowrite8(NPCM_SMBCST_BB, bus->reg + NPCM_SMBCST);
+
+ bus->cmd_err = -EAGAIN;
+ npcm_smb_callback(bus, bus->stop_ind,
+ npcm_smb_get_index(bus));
+ }
+ bus->state = SMB_IDLE;
+ ret = IRQ_HANDLED;
+ return ret;
+ }
+
+ // A Master End of Busy (meaning Stop Condition happened)
+ // End of Busy int is on and End of Busy is set
+ if ((FIELD_GET(NPCM_SMBCTL1_EOBINTE,
+ ioread8(bus->reg + NPCM_SMBCTL1)) == 1) &&
+ (FIELD_GET(NPCM_SMBCST3_EO_BUSY,
+ ioread8(bus->reg + NPCM_SMBCST3)))) {
+ NPCM_I2C_EVENT_LOG(NPCM_I2C_EVENT_EOB);
+ npcm_smb_eob_int(bus, false);
+ bus->state = SMB_IDLE;
+ npcm_smb_callback(bus, bus->stop_ind, bus->rd_ind);
+ return IRQ_HANDLED;
+ }
+
+ // Address sent and requested stall occurred (Master mode)
+ if (FIELD_GET(NPCM_SMBST_STASTR, ioread8(bus->reg + NPCM_SMBST))) {
+ NPCM_I2C_EVENT_LOG(NPCM_I2C_EVENT_STALL);
+
+ if (npcm_smb_is_quick(bus)) {
+ bus->state = SMB_STOP_PENDING;
+ bus->stop_ind = SMB_MASTER_DONE_IND;
+ npcm_smb_eob_int(bus, true);
+ npcm_smb_master_stop(bus);
+
+ } else if ((bus->rd_size == 1) && !bus->read_block_use) {
+ // Receiving one byte only - set NACK after ensuring
+ // slave ACKed the address byte
+ npcm_smb_nack(bus);
+ }
+
+ // Reset stall-after-address-byte
+ npcm_smb_stall_after_start(bus, false);
+
+ // Clear stall only after setting STOP
+ iowrite8(NPCM_SMBST_STASTR, bus->reg + NPCM_SMBST);
+
+ ret = IRQ_HANDLED;
+ }
+
+ // SDA status is set - TX or RX, master
+ if (FIELD_GET(NPCM_SMBST_SDAST, ioread8(bus->reg + NPCM_SMBST)) ||
+ (bus->fifo_use &&
+ (npcm_smb_tx_fifo_empty(bus) || npcm_smb_rx_fifo_full(bus)))) {
+ // Status Bit is cleared by writing to or reading from SDA
+ // (depending on current direction)
+
+ // Send address:
+ if (bus->state == SMB_IDLE) {
+ if (npcm_smb_is_master(bus)) {
+ bus->stop_ind = SMB_WAKE_UP_IND;
+
+ // test stall on start
+ if (npcm_smb_is_quick(bus) ||
+ bus->read_block_use)
+ // Need to stall after successful
+ // completion of sending address byte
+ npcm_smb_stall_after_start(bus, true);
+ else
+ npcm_smb_stall_after_start(bus, false);
+
+ // Receiving one byte only - stall after
+ // successful completion of sending address byte
+ // If we NACK here, and slave doesn't ACK the
+ // address, we might unintentionally NACK
+ // the next multi-byte read
+ if (bus->wr_size == 0 && bus->rd_size == 1)
+ npcm_smb_stall_after_start(bus, true);
+
+ // Initiate SMBus master transaction
+ // Generate a Start condition on the SMBus
+
+ // select bank 1 for FIFO regs
+ npcm_smb_select_bank(bus, SMB_BANK_1);
+
+ fif_cts = ioread8(bus->reg + NPCM_SMBFIF_CTS);
+
+ // clear FIFO and relevant status bits.
+ iowrite8((fif_cts & ~NPCM_SMBFIF_CTS_SLVRSTR)
+ | NPCM_SMBFIF_CTS_CLR_FIFO,
+ bus->reg + NPCM_SMBFIF_CTS);
+
+ // and enable it
+ iowrite8((fif_cts & ~NPCM_SMBFIF_CTS_SLVRSTR)
+ | NPCM_SMBFIF_CTS_RXF_TXE,
+ bus->reg + NPCM_SMBFIF_CTS);
+
+ // Configure the FIFO threshold
+ // according to the needed # of bytes to read.
+ // Note: due to HW limitation can't config the
+ // rx fifo before
+ // got and ACK on the restart. LAST bit will not
+ // be reset unless RX completed.
+ // It will stay set on the next tx.
+ if (bus->wr_size)
+ npcm_smb_set_fifo(bus, -1,
+ bus->wr_size);
+ else
+ npcm_smb_set_fifo(bus, bus->rd_size,
+ -1);
+
+ bus->state = SMB_OPER_STARTED;
+
+ if (npcm_smb_is_quick(bus) || bus->wr_size)
+ npcm_smb_wr_byte(bus, bus->dest_addr);
+ else
+ npcm_smb_wr_byte(bus, bus->dest_addr |
+ 0x01);
+ }
+
+ return IRQ_HANDLED;
+ // SDA status is set - transmit or receive: Handle master mode
+ } else {
+ if ((NPCM_SMBST_XMIT &
+ ioread8(bus->reg + NPCM_SMBST)) == 0) {
+ bus->operation = SMB_READ_OPER;
+ npcm_smb_int_master_handler_read(bus);
+ } else {
+ bus->operation = SMB_WRITE_OPER;
+ npcm_smb_int_master_handler_write(bus);
+ }
+ }
+ ret = IRQ_HANDLED;
+ }
+
+ return ret;
+}
+
+static int npcm_smb_get_SCL(struct i2c_adapter *_adap)
+{
+ unsigned int ret = 0;
+ struct npcm_i2c *bus = container_of(_adap, struct npcm_i2c, adap);
+ u32 offset = 0;
+
+ offset = 0;
+ ret = FIELD_GET(SMBCTL3_SCL_LVL, ioread32(bus->reg + NPCM_SMBCTL3));
+
+ pr_debug("i2c%d get SCL 0x%08X\n", bus->num, ret);
+
+ return (ret >> (offset)) & 0x01;
+}
+
+static int npcm_smb_get_SDA(struct i2c_adapter *_adap)
+{
+ unsigned int ret = 0;
+ struct npcm_i2c *bus = container_of(_adap, struct npcm_i2c, adap);
+ u32 offset = 0;
+
+ offset = 0;
+ ret = FIELD_GET(SMBCTL3_SDA_LVL, ioread32(bus->reg + NPCM_SMBCTL3));
+
+ pr_debug("i2c%d get SDA 0x%08X\n", bus->num, ret);
+
+ return (ret >> (offset)) & 0x01;
+}
+
+// recovery using TGCLK functionality of the module
+static int npcm_smb_recovery_tgclk(struct i2c_adapter *_adap)
+{
+ int iter = 27; // Allow 3 bytes to be sent by the Slave
+ int retries = 0;
+ bool done = false;
+ int status = -(ENOTRECOVERABLE);
+ u8 fif_cts;
+ struct npcm_i2c *bus = container_of(_adap, struct npcm_i2c, adap);
+
+ dev_dbg(bus->dev, "TGCLK recovery bus%d\n", bus->num);
+
+ if ((npcm_smb_get_SDA(_adap) == 1) && (npcm_smb_get_SCL(_adap) == 1)) {
+ dev_dbg(bus->dev, "TGCLK recovery bus%d: skipped bus not stuck",
+ bus->num);
+ npcm_smb_reset(bus);
+ return status;
+ }
+
+ // Disable int
+ npcm_smb_int_enable(bus, false);
+
+ npcm_smb_disable(bus);
+ npcm_smb_enable(bus);
+ iowrite8(NPCM_SMBCST_BB, bus->reg + NPCM_SMBCST);
+ npcm_smb_clear_tx_fifo(bus);
+ npcm_smb_clear_rx_fifo(bus);
+ iowrite8(0, bus->reg + NPCM_SMBRXF_CTL);
+ iowrite8(0, bus->reg + NPCM_SMBTXF_CTL);
+ npcm_smb_stall_after_start(bus, false);
+
+ // select bank 1 for FIFO regs
+ npcm_smb_select_bank(bus, SMB_BANK_1);
+
+ fif_cts = ioread8(bus->reg + NPCM_SMBFIF_CTS);
+
+ // clear FIFO and relevant status bits.
+ iowrite8((fif_cts & ~NPCM_SMBFIF_CTS_SLVRSTR) |
+ NPCM_SMBFIF_CTS_CLR_FIFO,
+ bus->reg + NPCM_SMBFIF_CTS);
+
+ npcm_smb_set_fifo(bus, -1, 0);
+
+ // Check If the SDA line is active (low)
+ if (npcm_smb_get_SDA(_adap) == 0) {
+ // Repeat the following sequence until SDA is released
+ do {
+ // Issue a single SCL cycle
+ iowrite8(NPCM_SMBCST_TGSCL, bus->reg + NPCM_SMBCST);
+ retries = 10;
+ while (retries != 0 &&
+ FIELD_GET(NPCM_SMBCST_TGSCL,
+ ioread8(bus->reg + NPCM_SMBCST))) {
+ udelay(20);
+ retries--;
+ }
+
+ // tgclk failed to toggle
+ if (retries == 0)
+ dev_dbg(bus->dev, "\t toggle timeout\n");
+ // If SDA line is inactive (high), stop
+ if (npcm_smb_get_SDA(_adap))
+ done = true;
+ } while ((!done) && (--iter != 0));
+
+ // If SDA line is released: send start-addr-stop, to re-sync.
+ if (done) {
+ npcm_smb_master_start(bus);
+
+ // Wait until START condition is sent, or RETRIES_NUM
+ retries = RETRIES_NUM;
+ while (retries && !npcm_smb_is_master(bus)) {
+ udelay(20);
+ retries--;
+ }
+
+ // If START condition was sent
+ if (retries > 0) {
+ // Send an address byte in write direction:
+ npcm_smb_wr_byte(bus, bus->dest_addr);
+ udelay(200);
+ npcm_smb_master_stop(bus);
+ udelay(200);
+ status = 0;
+ }
+ }
+ }
+
+ // if bus is still stuck: total reset: set SCL low for 35ms:
+ if (unlikely(npcm_smb_get_SDA(_adap) == 0)) {
+ // Generate a START, to synchronize Master and Slave
+ npcm_smb_master_start(bus);
+
+ // Wait until START condition is sent, or RETRIES_NUM
+ retries = RETRIES_NUM;
+ while (retries && !npcm_smb_is_master(bus))
+ retries--;
+
+ // set SCL low for a long time (note: this is unlikely)
+ usleep_range(25000, 35000);
+ npcm_smb_master_stop(bus);
+ udelay(200);
+ status = 0;
+ }
+
+ dev_dbg(bus->dev, "TGCLK done, iter = %d, done = %d, retries = %d\n",
+ 27 - iter, done, retries);
+ // Enable SMB int and New Address Match int source
+ iowrite8((ioread8(bus->reg + NPCM_SMBCTL1) | NPCM_SMBCTL1_NMINTE) &
+ ~NPCM_SMBCTL1_RWS_FIELDS,
+ bus->reg + NPCM_SMBCTL1);
+ npcm_smb_reset(bus);
+ npcm_smb_int_enable(bus, true);
+ return status;
+}
+
+// recovery using bit banging functionality of the module
+static int npcm_smb_recovery_init(struct i2c_adapter *_adap)
+{
+ struct npcm_i2c *bus = container_of(_adap, struct npcm_i2c, adap);
+ struct i2c_bus_recovery_info *rinfo = &bus->rinfo;
+
+ rinfo->recover_bus = npcm_smb_recovery_tgclk;
+ rinfo->prepare_recovery = NULL;
+ rinfo->unprepare_recovery = NULL;
+ rinfo->set_scl = NULL;
+ rinfo->set_sda = NULL;
+
+ dev_dbg(bus->dev, "i2c gpio recovery using TGCLK\n");
+
+ rinfo->get_scl = npcm_smb_get_SCL;
+ rinfo->get_sda = npcm_smb_get_SDA;
+
+ _adap->bus_recovery_info = rinfo;
+
+ return 0;
+}
+
+static bool npcm_smb_init_clk(struct npcm_i2c *bus, u32 bus_freq)
+{
+ u32 k1 = 0;
+ u32 k2 = 0;
+ u8 dbnct = 0;
+ u32 sclfrq = 0;
+ u8 hldt = 7;
+ bool fast_mode = false;
+ u32 src_clk_freq; // in KHz
+
+ src_clk_freq = bus->apb_clk / 1000;
+ bus->bus_freq = bus_freq;
+
+ if (bus_freq <= SMBUS_FREQ_100KHZ) {
+ sclfrq = src_clk_freq / (bus_freq * 4);
+
+ if (sclfrq < SCLFRQ_MIN || sclfrq > SCLFRQ_MAX)
+ return false;
+
+ if (src_clk_freq >= 40000)
+ hldt = 17;
+ else if (src_clk_freq >= 12500)
+ hldt = 15;
+ else
+ hldt = 7;
+ }
+
+ else if (bus_freq == SMBUS_FREQ_400KHZ) {
+ sclfrq = 0;
+ fast_mode = true;
+
+ if (src_clk_freq < 7500)
+ // 400KHZ cannot be supported for core clock < 7.5 MHZ
+ return false;
+
+ else if (src_clk_freq >= 50000) {
+ k1 = 80;
+ k2 = 48;
+ hldt = 12;
+ dbnct = 7;
+ }
+
+ // Master or Slave with frequency > 25 MHZ
+ else if (src_clk_freq > 25000) {
+ hldt = (u8)__KERNEL_DIV_ROUND_UP(src_clk_freq * 300,
+ 1000000) + 7;
+
+ k1 = __KERNEL_DIV_ROUND_UP(src_clk_freq * 1600,
+ 1000000);
+ k2 = __KERNEL_DIV_ROUND_UP(src_clk_freq * 900,
+ 1000000);
+ 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 false;
+ }
+ }
+
+ else if (bus_freq == SMBUS_FREQ_1MHZ) {
+ sclfrq = 0;
+ fast_mode = true;
+
+ if (src_clk_freq < 24000)
+ // 1MHZ cannot be supported for master core clock < 15 MHZ
+ // or slave core clock < 24 MHZ
+ return false;
+
+ k1 = round_up((__KERNEL_DIV_ROUND_UP(src_clk_freq * 620,
+ 1000000)), 2);
+ k2 = round_up((__KERNEL_DIV_ROUND_UP(src_clk_freq * 380,
+ 1000000) + 1), 2);
+ if (k1 < SCLFRQ_MIN || k1 > SCLFRQ_MAX ||
+ k2 < SCLFRQ_MIN || k2 > SCLFRQ_MAX)
+ return false;
+
+ // Master or Slave with frequency > 40 MHZ
+ if (src_clk_freq > 40000) {
+ // Set HLDT:
+ // SDA hold time: (HLDT-7) * T(CLK) >= 120
+ // HLDT = 120/T(CLK) + 7 = 120 * FREQ(CLK) + 7
+ hldt = (u8)__KERNEL_DIV_ROUND_UP(src_clk_freq * 120,
+ 1000000) + 7;
+ } else {
+ hldt = 7;
+ dbnct = 2;
+ }
+ }
+
+ // Frequency larger than 1 MHZ
+ else
+ return false;
+
+ // After clock parameters calculation update reg (ENABLE should be 0):
+ iowrite8(FIELD_PREP(SMBCTL2_SCLFRQ6_0, sclfrq & 0x7F),
+ bus->reg + NPCM_SMBCTL2);
+
+ // force to bank 0, set SCL and fast mode
+ iowrite8(FIELD_PREP(SMBCTL3_400K_MODE, fast_mode) |
+ FIELD_PREP(SMBCTL3_SCLFRQ8_7, (sclfrq >> 7) & 0x3),
+ bus->reg + NPCM_SMBCTL3);
+
+ // Select Bank 0 to access NPCM_SMBCTL4/NPCM_SMBCTL5
+ npcm_smb_select_bank(bus, SMB_BANK_0);
+
+ if (bus_freq >= SMBUS_FREQ_400KHZ) {
+ // Set SCL Low/High Time:
+ // k1 = 2 * SCLLT7-0 -> Low Time = k1 / 2
+ // k2 = 2 * SCLLT7-0 -> High Time = k2 / 2
+ iowrite8((u8)k1 / 2, bus->reg + NPCM_SMBSCLLT);
+ iowrite8((u8)k2 / 2, bus->reg + NPCM_SMBSCLHT);
+
+ iowrite8(dbnct, bus->reg + NPCM_SMBCTL5);
+ }
+
+ iowrite8(hldt, bus->reg + NPCM_SMBCTL4);
+
+ // Return to Bank 1, and stay there by default:
+ npcm_smb_select_bank(bus, SMB_BANK_1);
+
+ return true;
+}
+
+static bool npcm_smb_init_module(struct npcm_i2c *bus, enum smb_mode mode,
+ u32 bus_freq)
+{
+ // Check whether module already enabled or frequency is out of bounds
+ if ((bus->state != SMB_DISABLE && bus->state != SMB_IDLE) ||
+ bus_freq < SMBUS_FREQ_MIN || bus_freq > SMBUS_FREQ_MAX)
+ return false;
+
+ npcm_smb_disable(bus);
+
+ // Configure FIFO mode :
+ if (FIELD_GET(SMB_VER_FIFO_EN, ioread8(bus->reg + SMB_VER))) {
+ bus->fifo_use = true;
+ npcm_smb_select_bank(bus, SMB_BANK_0);
+ iowrite8(ioread8(bus->reg + NPCM_SMBFIF_CTL) |
+ NPCM_SMBFIF_CTL_FIFO_EN, bus->reg + NPCM_SMBFIF_CTL);
+ npcm_smb_select_bank(bus, SMB_BANK_1);
+ } else {
+ bus->fifo_use = false;
+ }
+
+ // Configure SMB module clock frequency
+ if (!npcm_smb_init_clk(bus, bus_freq)) {
+ dev_err(bus->dev, "npcm_smb_init_clk failed\n");
+ return false;
+ }
+
+ // Enable module (before configuring CTL1)
+ npcm_smb_enable(bus);
+ bus->state = SMB_IDLE;
+
+ // Enable SMB int and New Address Match int source
+ iowrite8((ioread8(bus->reg + NPCM_SMBCTL1) | NPCM_SMBCTL1_NMINTE) &
+ ~NPCM_SMBCTL1_RWS_FIELDS,
+ bus->reg + NPCM_SMBCTL1);
+
+ npcm_smb_int_enable(bus, true);
+
+ npcm_smb_reset(bus);
+
+ return true;
+}
+
+static int __npcm_i2c_init(struct npcm_i2c *bus, struct platform_device *pdev)
+{
+ u32 clk_freq;
+ int ret;
+
+ // Initialize the internal data structures
+ bus->state = SMB_DISABLE;
+ bus->master_or_slave = SMB_SLAVE;
+ bus->int_time_stamp = 0;
+ bus->slave = NULL;
+ bus->xmits = 0;
+
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "bus-frequency", &clk_freq);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Could not read bus-frequency property\n");
+ clk_freq = 100000;
+ }
+
+ ret = npcm_smb_init_module(bus, SMB_MASTER, clk_freq / 1000);
+ if (!ret) {
+ dev_err(&pdev->dev,
+ "npcm_smb_init_module() failed\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static irqreturn_t npcm_i2c_bus_irq(int irq, void *dev_id)
+{
+ irqreturn_t ret;
+ struct npcm_i2c *bus = dev_id;
+
+ bus->int_cnt++;
+
+ if (npcm_smb_is_master(bus))
+ bus->master_or_slave = SMB_MASTER;
+
+ if (bus->master_or_slave == SMB_MASTER) {
+ bus->int_time_stamp = jiffies;
+ ret = npcm_smb_int_master_handler(bus);
+ if (ret == IRQ_HANDLED)
+ return ret;
+ }
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+ if (bus->slave) {
+ bus->master_or_slave = SMB_SLAVE;
+ ret = npcm_smb_int_slave_handler(bus);
+ if (ret == IRQ_HANDLED)
+ return ret;
+ }
+#endif
+ return IRQ_HANDLED;
+}
+
+static bool npcm_smb_master_start_xmit(struct npcm_i2c *bus,
+ u8 slave_addr, u16 nwrite, u16 nread,
+ u8 *write_data, u8 *read_data,
+ bool use_PEC, bool use_read_block)
+{
+ if (bus->state != SMB_IDLE) {
+ bus->cmd_err = -(EBUSY);
+ return false;
+ }
+
+ bus->xmits++;
+
+ bus->dest_addr = (u8)(slave_addr << 1);// Translate 7bit to 8bit format
+ bus->wr_buf = write_data;
+ bus->wr_size = nwrite;
+ bus->wr_ind = 0;
+ bus->rd_buf = read_data;
+ bus->rd_size = nread;
+ bus->rd_ind = 0;
+ bus->PEC_use = 0;
+
+ // for write, PEC is appended to buffer from i2c IF. PEC flag is ignored
+ if (nread)
+ bus->PEC_use = use_PEC;
+ bus->read_block_use = use_read_block;
+ if (nread && !nwrite)
+ bus->operation = SMB_READ_OPER;
+ else
+ bus->operation = SMB_WRITE_OPER;
+
+ bus->int_cnt = 0;
+ bus->event_log = 0;
+
+ if (bus->fifo_use) {
+ u8 smbfif_cts;
+ // select bank 1 for FIFO regs
+ npcm_smb_select_bank(bus, SMB_BANK_1);
+
+ smbfif_cts = ioread8(bus->reg + NPCM_SMBFIF_CTS);
+
+ // clear FIFO and relevant status bits.
+ iowrite8((smbfif_cts & (~NPCM_SMBFIF_CTS_SLVRSTR)) |
+ NPCM_SMBFIF_CTS_CLR_FIFO,
+ bus->reg + NPCM_SMBFIF_CTS);
+ }
+
+ bus->state = SMB_IDLE;
+
+ npcm_smb_stall_after_start(bus, true);
+ npcm_smb_master_start(bus);
+
+ return true;
+}
+
+static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ int num)
+{
+ struct npcm_i2c *bus = container_of(adap, struct npcm_i2c, adap);
+ struct i2c_msg *msg0, *msg1;
+ unsigned long time_left, flags;
+ u16 nwrite, nread;
+ u8 *write_data, *read_data;
+ u8 slave_addr;
+ int timeout;
+ int ret = 0;
+ bool read_block = false;
+ bool read_PEC = false;
+ u8 bus_busy;
+ unsigned long timeout_usec;
+
+ if (unlikely(bus->state == SMB_DISABLE)) {
+ dev_err(bus->dev, "I2C%d module is disabled", bus->num);
+ return -EINVAL;
+ }
+
+ if (num > 2 || num < 1) {
+ dev_err(bus->dev, "I2C cmd not supported num of msgs=%d", num);
+ return -EINVAL;
+ }
+
+ msg0 = &msgs[0];
+ slave_addr = msg0->addr;
+ if (msg0->flags & I2C_M_RD) { // read
+ if (num == 2) {
+ dev_err(bus->dev, "num=2 but 1st msg rd instead of wr");
+ return -EINVAL;
+ }
+ nwrite = 0;
+ write_data = NULL;
+ read_data = msg0->buf;
+ if (msg0->flags & I2C_M_RECV_LEN) {
+ nread = 1;
+ read_block = true;
+ if (msg0->flags & I2C_CLIENT_PEC)
+ read_PEC = true;
+ } else {
+ nread = msg0->len;
+ }
+ } else { // write
+ nwrite = msg0->len;
+ write_data = msg0->buf;
+ nread = 0;
+ read_data = NULL;
+ if (num == 2) {
+ msg1 = &msgs[1];
+ read_data = msg1->buf;
+ if (slave_addr != msg1->addr) {
+ dev_err(bus->dev,
+ "SA==%02x but msg1->addr==%02x\n",
+ slave_addr, msg1->addr);
+ return -EINVAL;
+ }
+ if ((msg1->flags & I2C_M_RD) == 0) {
+ dev_err(bus->dev,
+ "num = 2 but both msg are write.\n");
+ return -EINVAL;
+ }
+ if (msg1->flags & I2C_M_RECV_LEN) {
+ nread = 1;
+ read_block = true;
+ if (msg1->flags & I2C_CLIENT_PEC)
+ read_PEC = true;
+ } else {
+ nread = msg1->len;
+ read_block = false;
+ }
+ }
+ }
+
+ /* Adaptive TimeOut: astimated time in usec + 100% margin */
+ timeout_usec = (2 * 10000 / bus->bus_freq) * (2 + nread + nwrite);
+ timeout = max(msecs_to_jiffies(35), 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 +
+ msecs_to_jiffies(DEFAULT_STALL_COUNT) + 1;
+ do {
+ /* we must clear slave address immediately when the bus is not
+ * busy, so we spinlock it, but we don't keep the lock for the
+ * entire while since it is too long.
+ */
+ spin_lock_irqsave(&bus->lock, flags);
+ bus_busy = ioread8(bus->reg + NPCM_SMBCST) & NPCM_SMBCST_BB;
+ if (!bus_busy && bus->slave)
+ iowrite8((bus->slave->addr & 0x7F),
+ bus->reg + NPCM_SMBADDR1);
+ spin_unlock_irqrestore(&bus->lock, flags);
+
+ if (!bus_busy)
+ break;
+ } while (time_is_after_jiffies(time_left));
+
+ if (bus_busy) {
+ iowrite8(NPCM_SMBCST_BB, bus->reg + NPCM_SMBCST);
+ npcm_smb_reset(bus);
+ i2c_recover_bus(adap);
+ return -EAGAIN;
+ }
+
+ npcm_smb_init_params(bus);
+ bus->dest_addr = slave_addr;
+ bus->msgs = msgs;
+ bus->msgs_num = num;
+ bus->read_block_use = read_block;
+
+ reinit_completion(&bus->cmd_complete);
+
+ if (!npcm_smb_master_start_xmit(bus, slave_addr, nwrite, nread,
+ write_data, read_data, read_PEC,
+ read_block))
+ ret = -(EBUSY);
+
+ if (ret != -(EBUSY)) {
+ time_left = wait_for_completion_timeout(&bus->cmd_complete,
+ timeout);
+
+ if (time_left == 0) {
+ NPCM_I2C_EVENT_LOG(NPCM_I2C_EVENT_TO);
+ if (bus->master_or_slave == SMB_MASTER) {
+ dev_dbg(bus->dev,
+ "i2c%d TO = %d\n", bus->num, timeout);
+ i2c_recover_bus(adap);
+ bus->cmd_err = -EIO;
+ bus->state = SMB_IDLE;
+ }
+ }
+ }
+ ret = bus->cmd_err;
+
+ // if there was BER, check if need to recover the bus:
+ if (bus->cmd_err == -EAGAIN)
+ i2c_recover_bus(adap);
+
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+ // reenable slave if it was enabled
+ if (bus->slave)
+ iowrite8((bus->slave->addr & 0x7F) | NPCM_SMBADDR_SAEN,
+ bus->reg + NPCM_SMBADDR1);
+#endif
+
+ // If nothing went wrong, return number of messages x-ferred.
+ if (ret >= 0)
+ return num;
+
+ // print errors apart from NACK
+ if (bus->cmd_err == -ENXIO)
+ dev_dbg(bus->dev, "cmd failed cmd_err = %d\n", ret);
+ return ret;
+}
+
+static u32 npcm_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_BLOCK_DATA |
+ I2C_FUNC_SLAVE | I2C_FUNC_SMBUS_PEC;
+}
+
+static const struct i2c_adapter_quirks npcm_i2c_quirks = {
+ .max_read_len = 32768,
+ .max_write_len = 32768,
+ .max_num_msgs = 2,
+ .flags = I2C_AQ_COMB_WRITE_THEN_READ
+};
+
+static const struct i2c_algorithm npcm_i2c_algo = {
+ .master_xfer = npcm_i2c_master_xfer,
+ .functionality = npcm_i2c_functionality,
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+ .reg_slave = npcm_i2c_reg_slave,
+ .unreg_slave = npcm_i2c_unreg_slave,
+#endif
+};
+
+static int npcm_i2c_probe_bus(struct platform_device *pdev)
+{
+ struct npcm_i2c *bus;
+ struct i2c_adapter *adap;
+ struct resource *res;
+ struct clk *i2c_clk;
+ int ret;
+ int num;
+
+ bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL);
+ if (!bus)
+ return -ENOMEM;
+
+#ifdef CONFIG_OF
+ num = of_alias_get_id(pdev->dev.of_node, "i2c");
+ bus->num = num;
+ i2c_clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(i2c_clk)) {
+ dev_err(bus->dev, " I2C probe failed: can't read clk\n");
+ return -EPROBE_DEFER;
+ }
+ bus->apb_clk = clk_get_rate(i2c_clk);
+ dev_dbg(bus->dev, "I2C APB clock is %d\n", bus->apb_clk);
+#endif // CONFIG_OF
+
+ gcr_regmap = syscon_regmap_lookup_by_compatible("nuvoton,npcm750-gcr");
+ if (IS_ERR(gcr_regmap)) {
+ dev_err(bus->dev, "%s: failed to find nuvoton,npcm750-gcr\n",
+ __func__);
+ return IS_ERR(gcr_regmap);
+ }
+ regmap_write(gcr_regmap, NPCM_I2CSEGCTL, I2CSEGCTL_VAL);
+ dev_dbg(bus->dev, "I2C%d: gcr mapped\n", bus->num);
+
+ clk_regmap = syscon_regmap_lookup_by_compatible("nuvoton,npcm750-clk");
+ if (IS_ERR(clk_regmap)) {
+ dev_err(bus->dev, "%s: failed to find nuvoton,npcm750-clk\n",
+ __func__);
+ return IS_ERR(clk_regmap);
+ }
+ dev_dbg(bus->dev, "I2C%d: clk mapped\n", bus->num);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ dev_dbg(bus->dev, "resource: %pR\n", res);
+ bus->reg = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR((bus)->reg))
+ return PTR_ERR((bus)->reg);
+ dev_dbg(bus->dev, "base = %p\n", bus->reg);
+
+ // Initialize the I2C adapter
+ spin_lock_init(&bus->lock);
+ init_completion(&bus->cmd_complete);
+
+ adap = &bus->adap;
+ adap->owner = THIS_MODULE;
+ adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD | I2C_CLIENT_SLAVE;
+ adap->retries = 3;
+ adap->timeout = HZ;
+ adap->algo = &npcm_i2c_algo;
+ adap->quirks = &npcm_i2c_quirks;
+ adap->algo_data = bus;
+ adap->dev.parent = &pdev->dev;
+ adap->dev.of_node = pdev->dev.of_node;
+ adap->nr = pdev->id;
+
+ bus->dev = &pdev->dev;
+ bus->slave = NULL;
+
+ bus->irq = platform_get_irq(pdev, 0);
+ if (bus->irq < 0) {
+ dev_err(bus->dev, "I2C platform_get_irq error\n");
+ return -ENODEV;
+ }
+ dev_dbg(bus->dev, "irq = %d\n", bus->irq);
+
+ ret = devm_request_irq(&pdev->dev, bus->irq, npcm_i2c_bus_irq, 0,
+ dev_name(&pdev->dev), (void *)bus);
+
+ if (ret) {
+ dev_err(&pdev->dev, "I2C%d: request_irq fail\n", bus->num);
+ return ret;
+ }
+
+ ret = __npcm_i2c_init(bus, pdev);
+ if (ret < 0)
+ return ret;
+
+ ret = npcm_smb_recovery_init(adap);
+ if (ret)
+ return ret;
+
+ i2c_set_adapdata(adap, bus);
+
+ snprintf(bus->adap.name, sizeof(bus->adap.name), "Nuvoton i2c");
+
+ ret = i2c_add_numbered_adapter(&bus->adap);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "I2C%d: i2c_add_numbered_adapter fail\n",
+ bus->num);
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, bus);
+
+ pr_info("npcm7xx I2C bus is %d registered\n", bus->adap.nr);
+
+ return 0;
+}
+
+static int npcm_i2c_remove_bus(struct platform_device *pdev)
+{
+ unsigned long lock_flags;
+ struct npcm_i2c *bus = platform_get_drvdata(pdev);
+
+ spin_lock_irqsave(&bus->lock, lock_flags);
+ npcm_smb_disable(bus);
+ spin_unlock_irqrestore(&bus->lock, lock_flags);
+ i2c_del_adapter(&bus->adap);
+
+ return 0;
+}
+
+static const struct of_device_id npcm_i2c_bus_of_table[] = {
+ { .compatible = "nuvoton,npcm750-i2c", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, npcm_i2c_bus_of_table);
+
+static struct platform_driver npcm_i2c_bus_driver = {
+ .probe = npcm_i2c_probe_bus,
+ .remove = npcm_i2c_remove_bus,
+ .driver = {
+ .name = "nuvoton-i2c",
+ .of_match_table = npcm_i2c_bus_of_table,
+ }
+};
+module_platform_driver(npcm_i2c_bus_driver);
+
+MODULE_AUTHOR("Avi Fishman <avi.fishman@gmail.com>");
+MODULE_AUTHOR("Tali Perry <tali.perry@nuvoton.com>");
+MODULE_AUTHOR("Tyrone Ting <kfting@nuvoton.com>");
+MODULE_DESCRIPTION("Nuvoton I2C Bus Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(I2C_VERSION);
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index cc7c43932f16..fce6b1d59f5d 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -86,7 +86,7 @@ obj-$(CONFIG_MVEBU_PIC) += irq-mvebu-pic.o
obj-$(CONFIG_MVEBU_SEI) += irq-mvebu-sei.o
obj-$(CONFIG_LS_SCFG_MSI) += irq-ls-scfg-msi.o
obj-$(CONFIG_EZNPS_GIC) += irq-eznps.o
-obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o irq-aspeed-i2c-ic.o
+obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o irq-aspeed-i2c-ic.o irq-aspeed-scu-ic.o
obj-$(CONFIG_STM32_EXTI) += irq-stm32-exti.o
obj-$(CONFIG_QCOM_IRQ_COMBINER) += qcom-irq-combiner.o
obj-$(CONFIG_IRQ_UNIPHIER_AIDET) += irq-uniphier-aidet.o
diff --git a/drivers/irqchip/irq-aspeed-scu-ic.c b/drivers/irqchip/irq-aspeed-scu-ic.c
new file mode 100644
index 000000000000..c90a3346b985
--- /dev/null
+++ b/drivers/irqchip/irq-aspeed-scu-ic.c
@@ -0,0 +1,239 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Aspeed AST24XX, AST25XX, and AST26XX SCU Interrupt Controller
+ * Copyright 2019 IBM Corporation
+ *
+ * Eddie James <eajames@linux.ibm.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_irq.h>
+#include <linux/regmap.h>
+
+#define ASPEED_SCU_IC_REG 0x018
+#define ASPEED_SCU_IC_SHIFT 0
+#define ASPEED_SCU_IC_ENABLE GENMASK(6, ASPEED_SCU_IC_SHIFT)
+#define ASPEED_SCU_IC_NUM_IRQS 7
+#define ASPEED_SCU_IC_STATUS_SHIFT 16
+
+#define ASPEED_AST2600_SCU_IC0_REG 0x560
+#define ASPEED_AST2600_SCU_IC0_SHIFT 0
+#define ASPEED_AST2600_SCU_IC0_ENABLE \
+ GENMASK(5, ASPEED_AST2600_SCU_IC0_SHIFT)
+#define ASPEED_AST2600_SCU_IC0_NUM_IRQS 6
+
+#define ASPEED_AST2600_SCU_IC1_REG 0x570
+#define ASPEED_AST2600_SCU_IC1_SHIFT 4
+#define ASPEED_AST2600_SCU_IC1_ENABLE \
+ GENMASK(5, ASPEED_AST2600_SCU_IC1_SHIFT)
+#define ASPEED_AST2600_SCU_IC1_NUM_IRQS 2
+
+struct aspeed_scu_ic {
+ unsigned long irq_enable;
+ unsigned long irq_shift;
+ unsigned int num_irqs;
+ unsigned int reg;
+ struct regmap *scu;
+ struct irq_domain *irq_domain;
+};
+
+static void aspeed_scu_ic_irq_handler(struct irq_desc *desc)
+{
+ unsigned int irq;
+ unsigned int sts;
+ unsigned long bit;
+ unsigned long enabled;
+ unsigned long max;
+ unsigned long status;
+ struct aspeed_scu_ic *scu_ic = irq_desc_get_handler_data(desc);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ unsigned int mask = scu_ic->irq_enable << ASPEED_SCU_IC_STATUS_SHIFT;
+
+ chained_irq_enter(chip, desc);
+
+ /*
+ * The SCU IC has just one register to control its operation and read
+ * status. The interrupt enable bits occupy the lower 16 bits of the
+ * register, while the interrupt status bits occupy the upper 16 bits.
+ * The status bit for a given interrupt is always 16 bits shifted from
+ * the enable bit for the same interrupt.
+ * Therefore, perform the IRQ operations in the enable bit space by
+ * shifting the status down to get the mapping and then back up to
+ * clear the bit.
+ */
+ regmap_read(scu_ic->scu, scu_ic->reg, &sts);
+ enabled = sts & scu_ic->irq_enable;
+ status = (sts >> ASPEED_SCU_IC_STATUS_SHIFT) & enabled;
+
+ bit = scu_ic->irq_shift;
+ max = scu_ic->num_irqs + bit;
+
+ for_each_set_bit_from(bit, &status, max) {
+ irq = irq_find_mapping(scu_ic->irq_domain,
+ bit - scu_ic->irq_shift);
+ generic_handle_irq(irq);
+
+ regmap_update_bits(scu_ic->scu, scu_ic->reg, mask,
+ BIT(bit + ASPEED_SCU_IC_STATUS_SHIFT));
+ }
+
+ chained_irq_exit(chip, desc);
+}
+
+static void aspeed_scu_ic_irq_mask(struct irq_data *data)
+{
+ struct aspeed_scu_ic *scu_ic = irq_data_get_irq_chip_data(data);
+ unsigned int mask = BIT(data->hwirq + scu_ic->irq_shift) |
+ (scu_ic->irq_enable << ASPEED_SCU_IC_STATUS_SHIFT);
+
+ /*
+ * Status bits are cleared by writing 1. In order to prevent the mask
+ * operation from clearing the status bits, they should be under the
+ * mask and written with 0.
+ */
+ regmap_update_bits(scu_ic->scu, scu_ic->reg, mask, 0);
+}
+
+static void aspeed_scu_ic_irq_unmask(struct irq_data *data)
+{
+ struct aspeed_scu_ic *scu_ic = irq_data_get_irq_chip_data(data);
+ unsigned int bit = BIT(data->hwirq + scu_ic->irq_shift);
+ unsigned int mask = bit |
+ (scu_ic->irq_enable << ASPEED_SCU_IC_STATUS_SHIFT);
+
+ /*
+ * Status bits are cleared by writing 1. In order to prevent the unmask
+ * operation from clearing the status bits, they should be under the
+ * mask and written with 0.
+ */
+ regmap_update_bits(scu_ic->scu, scu_ic->reg, mask, bit);
+}
+
+static int aspeed_scu_ic_irq_set_affinity(struct irq_data *data,
+ const struct cpumask *dest,
+ bool force)
+{
+ return -EINVAL;
+}
+
+static struct irq_chip aspeed_scu_ic_chip = {
+ .name = "aspeed-scu-ic",
+ .irq_mask = aspeed_scu_ic_irq_mask,
+ .irq_unmask = aspeed_scu_ic_irq_unmask,
+ .irq_set_affinity = aspeed_scu_ic_irq_set_affinity,
+};
+
+static int aspeed_scu_ic_map(struct irq_domain *domain, unsigned int irq,
+ irq_hw_number_t hwirq)
+{
+ irq_set_chip_and_handler(irq, &aspeed_scu_ic_chip, handle_level_irq);
+ irq_set_chip_data(irq, domain->host_data);
+
+ return 0;
+}
+
+static const struct irq_domain_ops aspeed_scu_ic_domain_ops = {
+ .map = aspeed_scu_ic_map,
+};
+
+static int aspeed_scu_ic_of_init_common(struct aspeed_scu_ic *scu_ic,
+ struct device_node *node)
+{
+ int irq;
+ int rc = 0;
+
+ if (!node->parent) {
+ rc = -ENODEV;
+ goto err;
+ }
+
+ scu_ic->scu = syscon_node_to_regmap(node->parent);
+ if (IS_ERR(scu_ic->scu)) {
+ rc = PTR_ERR(scu_ic->scu);
+ goto err;
+ }
+
+ irq = irq_of_parse_and_map(node, 0);
+ if (irq < 0) {
+ rc = irq;
+ goto err;
+ }
+
+ scu_ic->irq_domain = irq_domain_add_linear(node, scu_ic->num_irqs,
+ &aspeed_scu_ic_domain_ops,
+ scu_ic);
+ if (!scu_ic->irq_domain) {
+ rc = -ENOMEM;
+ goto err;
+ }
+
+ irq_set_chained_handler_and_data(irq, aspeed_scu_ic_irq_handler,
+ scu_ic);
+
+ return 0;
+
+err:
+ kfree(scu_ic);
+
+ return rc;
+}
+
+static int __init aspeed_scu_ic_of_init(struct device_node *node,
+ struct device_node *parent)
+{
+ struct aspeed_scu_ic *scu_ic = kzalloc(sizeof(*scu_ic), GFP_KERNEL);
+
+ if (!scu_ic)
+ return -ENOMEM;
+
+ scu_ic->irq_enable = ASPEED_SCU_IC_ENABLE;
+ scu_ic->irq_shift = ASPEED_SCU_IC_SHIFT;
+ scu_ic->num_irqs = ASPEED_SCU_IC_NUM_IRQS;
+ scu_ic->reg = ASPEED_SCU_IC_REG;
+
+ return aspeed_scu_ic_of_init_common(scu_ic, node);
+}
+
+static int __init aspeed_ast2600_scu_ic0_of_init(struct device_node *node,
+ struct device_node *parent)
+{
+ struct aspeed_scu_ic *scu_ic = kzalloc(sizeof(*scu_ic), GFP_KERNEL);
+
+ if (!scu_ic)
+ return -ENOMEM;
+
+ scu_ic->irq_enable = ASPEED_AST2600_SCU_IC0_ENABLE;
+ scu_ic->irq_shift = ASPEED_AST2600_SCU_IC0_SHIFT;
+ scu_ic->num_irqs = ASPEED_AST2600_SCU_IC0_NUM_IRQS;
+ scu_ic->reg = ASPEED_AST2600_SCU_IC0_REG;
+
+ return aspeed_scu_ic_of_init_common(scu_ic, node);
+}
+
+static int __init aspeed_ast2600_scu_ic1_of_init(struct device_node *node,
+ struct device_node *parent)
+{
+ struct aspeed_scu_ic *scu_ic = kzalloc(sizeof(*scu_ic), GFP_KERNEL);
+
+ if (!scu_ic)
+ return -ENOMEM;
+
+ scu_ic->irq_enable = ASPEED_AST2600_SCU_IC1_ENABLE;
+ scu_ic->irq_shift = ASPEED_AST2600_SCU_IC1_SHIFT;
+ scu_ic->num_irqs = ASPEED_AST2600_SCU_IC1_NUM_IRQS;
+ scu_ic->reg = ASPEED_AST2600_SCU_IC1_REG;
+
+ return aspeed_scu_ic_of_init_common(scu_ic, node);
+}
+
+IRQCHIP_DECLARE(ast2400_scu_ic, "aspeed,ast2400-scu-ic", aspeed_scu_ic_of_init);
+IRQCHIP_DECLARE(ast2500_scu_ic, "aspeed,ast2500-scu-ic", aspeed_scu_ic_of_init);
+IRQCHIP_DECLARE(ast2600_scu_ic0, "aspeed,ast2600-scu-ic0",
+ aspeed_ast2600_scu_ic0_of_init);
+IRQCHIP_DECLARE(ast2600_scu_ic1, "aspeed,ast2600-scu-ic1",
+ aspeed_ast2600_scu_ic1_of_init);
diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c
index 4eaaf39b9223..d8593cb2ae84 100644
--- a/drivers/media/platform/aspeed-video.c
+++ b/drivers/media/platform/aspeed-video.c
@@ -624,7 +624,7 @@ static void aspeed_video_check_and_set_polarity(struct aspeed_video *video)
int i;
int hsync_counter = 0;
int vsync_counter = 0;
- u32 sts;
+ u32 sts, ctrl;
for (i = 0; i < NUM_POLARITY_CHECKS; ++i) {
sts = aspeed_video_read(video, VE_MODE_DETECT_STATUS);
@@ -639,30 +639,29 @@ static void aspeed_video_check_and_set_polarity(struct aspeed_video *video)
hsync_counter++;
}
- if (hsync_counter < 0 || vsync_counter < 0) {
- u32 ctrl = 0;
+ ctrl = aspeed_video_read(video, VE_CTRL);
- if (hsync_counter < 0) {
- ctrl = VE_CTRL_HSYNC_POL;
- video->detected_timings.polarities &=
- ~V4L2_DV_HSYNC_POS_POL;
- } else {
- video->detected_timings.polarities |=
- V4L2_DV_HSYNC_POS_POL;
- }
-
- if (vsync_counter < 0) {
- ctrl = VE_CTRL_VSYNC_POL;
- video->detected_timings.polarities &=
- ~V4L2_DV_VSYNC_POS_POL;
- } else {
- video->detected_timings.polarities |=
- V4L2_DV_VSYNC_POS_POL;
- }
+ if (hsync_counter < 0) {
+ ctrl |= VE_CTRL_HSYNC_POL;
+ video->detected_timings.polarities &=
+ ~V4L2_DV_HSYNC_POS_POL;
+ } else {
+ ctrl &= ~VE_CTRL_HSYNC_POL;
+ video->detected_timings.polarities |=
+ V4L2_DV_HSYNC_POS_POL;
+ }
- if (ctrl)
- aspeed_video_update(video, VE_CTRL, 0, ctrl);
+ if (vsync_counter < 0) {
+ ctrl |= VE_CTRL_VSYNC_POL;
+ video->detected_timings.polarities &=
+ ~V4L2_DV_VSYNC_POS_POL;
+ } else {
+ ctrl &= ~VE_CTRL_VSYNC_POL;
+ video->detected_timings.polarities |=
+ V4L2_DV_VSYNC_POS_POL;
}
+
+ aspeed_video_write(video, VE_CTRL, ctrl);
}
static bool aspeed_video_alloc_buf(struct aspeed_video *video,
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 43169f25da1f..38ec55b4a678 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -632,6 +632,23 @@ config MFD_INTEL_MSIC
Passage) chip. This chip embeds audio, battery, GPIO, etc.
devices used in Intel Medfield platforms.
+config MFD_INTEL_PECI_CLIENT
+ tristate "Intel PECI client"
+ depends on (PECI || COMPILE_TEST)
+ select MFD_CORE
+ help
+ If you say yes to this option, support will be included for the
+ Intel PECI (Platform Environment Control Interface) client. PECI is a
+ one-wire bus interface that provides a communication channel from PECI
+ clients in Intel processors and chipset components to external
+ monitoring or control devices.
+
+ Additional drivers must be enabled in order to use the functionality
+ of the device.
+
+ This driver can also be built as a module. If so, the module
+ will be called intel-peci-client.
+
config MFD_IPAQ_MICRO
bool "Atmel Micro ASIC (iPAQ h3100/h3600/h3700) Support"
depends on SA1100_H3100 || SA1100_H3600
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index c1067ea46204..07722f3d80b6 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -212,6 +212,7 @@ obj-$(CONFIG_MFD_INTEL_LPSS) += intel-lpss.o
obj-$(CONFIG_MFD_INTEL_LPSS_PCI) += intel-lpss-pci.o
obj-$(CONFIG_MFD_INTEL_LPSS_ACPI) += intel-lpss-acpi.o
obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o
+obj-$(CONFIG_MFD_INTEL_PECI_CLIENT) += intel-peci-client.o
obj-$(CONFIG_MFD_PALMAS) += palmas.o
obj-$(CONFIG_MFD_VIPERBOARD) += viperboard.o
obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o
diff --git a/drivers/mfd/intel-peci-client.c b/drivers/mfd/intel-peci-client.c
new file mode 100644
index 000000000000..24f15438634c
--- /dev/null
+++ b/drivers/mfd/intel-peci-client.c
@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018-2019 Intel Corporation
+
+#include <linux/bitfield.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/intel-peci-client.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/peci.h>
+
+#define CPU_ID_MODEL_MASK GENMASK(7, 4)
+#define CPU_ID_FAMILY_MASK GENMASK(11, 8)
+#define CPU_ID_EXT_MODEL_MASK GENMASK(19, 16)
+#define CPU_ID_EXT_FAMILY_MASK GENMASK(27, 20)
+
+#define LOWER_NIBBLE_MASK GENMASK(3, 0)
+#define UPPER_NIBBLE_MASK GENMASK(7, 4)
+#define LOWER_BYTE_MASK GENMASK(7, 0)
+#define UPPER_BYTE_MASK GENMASK(16, 8)
+
+static struct mfd_cell peci_functions[] = {
+ { .name = "peci-cputemp", },
+ { .name = "peci-dimmtemp", },
+};
+
+static const struct cpu_gen_info cpu_gen_info_table[] = {
+ { /* Haswell Xeon */
+ .family = INTEL_FAM6,
+ .model = INTEL_FAM6_HASWELL_X,
+ .core_max = CORE_MAX_ON_HSX,
+ .chan_rank_max = CHAN_RANK_MAX_ON_HSX,
+ .dimm_idx_max = DIMM_IDX_MAX_ON_HSX },
+ { /* Broadwell Xeon */
+ .family = INTEL_FAM6,
+ .model = INTEL_FAM6_BROADWELL_X,
+ .core_max = CORE_MAX_ON_BDX,
+ .chan_rank_max = CHAN_RANK_MAX_ON_BDX,
+ .dimm_idx_max = DIMM_IDX_MAX_ON_BDX },
+ { /* Skylake Xeon */
+ .family = INTEL_FAM6,
+ .model = INTEL_FAM6_SKYLAKE_X,
+ .core_max = CORE_MAX_ON_SKX,
+ .chan_rank_max = CHAN_RANK_MAX_ON_SKX,
+ .dimm_idx_max = DIMM_IDX_MAX_ON_SKX },
+ { /* Skylake Xeon D */
+ .family = INTEL_FAM6,
+ .model = INTEL_FAM6_SKYLAKE_XD,
+ .core_max = CORE_MAX_ON_SKXD,
+ .chan_rank_max = CHAN_RANK_MAX_ON_SKXD,
+ .dimm_idx_max = DIMM_IDX_MAX_ON_SKXD },
+};
+
+static int peci_client_get_cpu_gen_info(struct peci_client_manager *priv)
+{
+ struct device *dev = &priv->client->dev;
+ u32 cpu_id;
+ u16 family;
+ u8 model;
+ int ret;
+ int i;
+
+ ret = peci_get_cpu_id(priv->client->adapter, priv->client->addr,
+ &cpu_id);
+ if (ret)
+ return ret;
+
+ family = FIELD_PREP(LOWER_BYTE_MASK,
+ FIELD_GET(CPU_ID_FAMILY_MASK, cpu_id)) |
+ FIELD_PREP(UPPER_BYTE_MASK,
+ FIELD_GET(CPU_ID_EXT_FAMILY_MASK, cpu_id));
+ model = FIELD_PREP(LOWER_NIBBLE_MASK,
+ FIELD_GET(CPU_ID_MODEL_MASK, cpu_id)) |
+ FIELD_PREP(UPPER_NIBBLE_MASK,
+ FIELD_GET(CPU_ID_EXT_MODEL_MASK, cpu_id));
+
+ for (i = 0; i < ARRAY_SIZE(cpu_gen_info_table); i++) {
+ const struct cpu_gen_info *cpu_info = &cpu_gen_info_table[i];
+
+ if (family == cpu_info->family && model == cpu_info->model) {
+ priv->gen_info = cpu_info;
+ break;
+ }
+ }
+
+ if (!priv->gen_info) {
+ dev_err(dev, "Can't support this CPU: 0x%x\n", cpu_id);
+ ret = -ENODEV;
+ }
+
+ return ret;
+}
+
+static int peci_client_probe(struct peci_client *client)
+{
+ struct device *dev = &client->dev;
+ struct peci_client_manager *priv;
+ uint cpu_no;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, priv);
+ priv->client = client;
+ cpu_no = client->addr - PECI_BASE_ADDR;
+
+ ret = peci_client_get_cpu_gen_info(priv);
+ if (ret)
+ return ret;
+
+ ret = devm_mfd_add_devices(dev, cpu_no, peci_functions,
+ ARRAY_SIZE(peci_functions), NULL, 0, NULL);
+ if (ret < 0) {
+ dev_err(dev, "Failed to register child devices: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id peci_client_of_table[] = {
+ { .compatible = "intel,peci-client" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, peci_client_of_table);
+#endif
+
+static const struct peci_device_id peci_client_ids[] = {
+ { .name = "peci-client" },
+ { }
+};
+MODULE_DEVICE_TABLE(peci, peci_client_ids);
+
+static struct peci_driver peci_client_driver = {
+ .probe = peci_client_probe,
+ .id_table = peci_client_ids,
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .of_match_table = of_match_ptr(peci_client_of_table),
+ },
+};
+module_peci_driver(peci_client_driver);
+
+MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
+MODULE_DESCRIPTION("PECI client driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index c55b63750757..c90a9cacc19f 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -454,6 +454,13 @@ config XILINX_SDFEC
If unsure, say N.
+config MCTP_LPC
+ tristate "MCTP LPC binding implementation for ASPEED BMCs"
+ depends on REGMAP
+ help
+ Implements the MCTP LPC binding via KCS LPC IO cycles for control and
+ LPC FWH cycles for data
+
config MISC_RTSX
tristate
default MISC_RTSX_PCI || MISC_RTSX_USB
@@ -466,6 +473,21 @@ config PVPANIC
a paravirtualized device provided by QEMU; it lets a virtual machine
(guest) communicate panic events to the host.
+config NPCM7XX_LPC_BPC
+ tristate "NPCM7xx LPC BIOS Post Code support"
+ depends on (ARCH_NPCM7XX || COMPILE_TEST)
+ help
+ Provides a NPCM7xx driver to control the LPC BIOS Post Code
+ interface which allows the BMC to monitoring and save
+ the data written by the host to an arbitrary LPC I/O port.
+
+config NPCM7XX_PCI_MBOX
+ tristate "NPCM7xx PCI Mailbox Controller"
+ depends on (ARCH_NPCM7XX || COMPILE_TEST) && REGMAP && MFD_SYSCON
+ help
+ Expose the NPCM750/730/715/705 PCI MBOX registers found on
+ Nuvoton SOCs to userspace.
+
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index c1860d35dc7e..9ef78d42be9d 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -57,3 +57,6 @@ obj-y += cardreader/
obj-$(CONFIG_PVPANIC) += pvpanic.o
obj-$(CONFIG_HABANA_AI) += habanalabs/
obj-$(CONFIG_XILINX_SDFEC) += xilinx_sdfec.o
+obj-$(CONFIG_NPCM7XX_LPC_BPC) += npcm7xx-lpc-bpc.o
+obj-$(CONFIG_NPCM7XX_PCI_MBOX) += npcm7xx-pci-mbox.o
+obj-$(CONFIG_MCTP_LPC) += mctp-lpc.o
diff --git a/drivers/misc/mctp-lpc.c b/drivers/misc/mctp-lpc.c
new file mode 100644
index 000000000000..71fc4ae69de7
--- /dev/null
+++ b/drivers/misc/mctp-lpc.c
@@ -0,0 +1,443 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2019, IBM Corp.
+ */
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/poll.h>
+#include <linux/regmap.h>
+#include <linux/sched/signal.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+
+#define LPC_HICRB 0x080
+#define LPC_HICRB_IBFIF4 BIT(1)
+#define LPC_HICRB_LPC4E BIT(0)
+#define LPC_HICRC 0x084
+#define LPC_KCS4_IRQSEL_MASK GENMASK(7, 4)
+#define LPC_KCS4_IRQSEL_SHIFT 4
+#define LPC_KCS4_IRQTYPE_MASK GENMASK(3, 2)
+#define LPC_KCS4_IRQTYPE_SHIFT 2
+#define LPC_KCS4_IRQTYPE_LOW 0b00
+#define LPC_KCS4_IRQTYPE_HIGH 0b01
+#define LPC_KCS4_IRQTYPE_RSVD 0b10
+#define LPC_KCS4_IRQTYPE_RISING 0b11
+#define LPC_KCS4_OBF4_AUTO_CLR BIT(1)
+#define LPC_KCS4_IRQ_HOST BIT(0)
+#define LPC_LADR4 0x090
+#define LPC_IDR4 0x094
+#define LPC_ODR4 0x098
+#define LPC_STR4 0x09C
+#define STR4_IBF (1 << 1)
+#define STR4_OBF (1 << 0)
+
+#define HOST_ODR 0xca2
+#define HOST_STR 0xca3
+#define HOST_SERIRQ_ID 11
+#define HOST_SERIRQ_TYPE LPC_KCS4_IRQTYPE_LOW
+
+#define RX_BUF_SIZE 1024
+
+struct mctp_lpc {
+ struct miscdevice miscdev;
+ struct regmap *map;
+
+ wait_queue_head_t rx;
+ bool pending;
+ u8 idr;
+};
+
+static irqreturn_t mctp_lpc_irq(int irq, void *data)
+{
+ struct mctp_lpc *priv = data;
+ unsigned long flags;
+ unsigned int hicrb;
+ struct device *dev;
+ unsigned int str;
+ irqreturn_t ret;
+
+ dev = priv->miscdev.this_device;
+
+ spin_lock_irqsave(&priv->rx.lock, flags);
+
+ regmap_read(priv->map, LPC_STR4, &str);
+ regmap_read(priv->map, LPC_HICRB, &hicrb);
+
+ if ((str & STR4_IBF) && (hicrb & LPC_HICRB_IBFIF4)) {
+ unsigned int val;
+
+ if (priv->pending)
+ dev_err(dev, "Storm brewing!");
+
+ /* Mask the IRQ / Enter polling mode */
+ dev_dbg(dev, "Received IRQ %d, disabling to provide back-pressure\n",
+ irq);
+ regmap_update_bits(priv->map, LPC_HICRB, LPC_HICRB_IBFIF4, 0);
+
+ /*
+ * Extract the IDR4 value to ack the IRQ. Reading IDR clears
+ * IBF and allows the host to write another value, however as
+ * we have disabled IRQs the back-pressure is still applied
+ * until userspace starts servicing the interface.
+ */
+ regmap_read(priv->map, LPC_IDR4, &val);
+ priv->idr = val & 0xff;
+ priv->pending = true;
+
+ dev_dbg(dev, "Set pending, waking waiters\n");
+ wake_up_locked(&priv->rx);
+ ret = IRQ_HANDLED;
+ } else {
+ dev_dbg(dev, "LPC IRQ triggered, but not for us (str=0x%x, hicrb=0x%x)\n",
+ str, hicrb);
+ ret = IRQ_NONE;
+ }
+
+ spin_unlock_irqrestore(&priv->rx.lock, flags);
+
+ return ret;
+}
+
+static inline struct mctp_lpc *to_mctp_lpc(struct file *filp)
+{
+ return container_of(filp->private_data, struct mctp_lpc, miscdev);
+}
+
+static ssize_t mctp_lpc_read(struct file *filp, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct mctp_lpc *priv;
+ struct device *dev;
+ size_t remaining;
+ ssize_t rc;
+
+ priv = to_mctp_lpc(filp);
+ dev = priv->miscdev.this_device;
+
+ if (!count)
+ return 0;
+
+ if (count > 2 || *ppos > 1)
+ return -EINVAL;
+
+ remaining = count;
+
+ spin_lock_irq(&priv->rx.lock);
+ if (*ppos == 0) {
+ unsigned int val;
+ u8 str;
+
+ /* YOLO blocking, non-block not supported */
+ dev_dbg(dev, "Waiting for IBF\n");
+ regmap_read(priv->map, LPC_STR4, &val);
+ str = val & 0xff;
+ rc = wait_event_interruptible_locked(priv->rx, (priv->pending || str & STR4_IBF));
+ if (rc < 0)
+ goto out;
+
+ if (signal_pending(current)) {
+ dev_dbg(dev, "Interrupted waiting for IBF\n");
+ rc = -EINTR;
+ goto out;
+ }
+
+ /*
+ * Re-enable IRQs prior to possible read of IDR (which clears
+ * IBF) to ensure we receive interrupts for subsequent writes
+ * to IDR. Writes to IDR by the host should not occur while IBF
+ * is set.
+ */
+ dev_dbg(dev, "Woken by IBF, enabling IRQ\n");
+ regmap_update_bits(priv->map, LPC_HICRB, LPC_HICRB_IBFIF4,
+ LPC_HICRB_IBFIF4);
+
+ /* Read data out of IDR into internal storage if necessary */
+ if (!priv->pending) {
+ WARN(!(str & STR4_IBF), "Unknown reason for wakeup!");
+
+ /* Extract the IDR4 value to ack the IRQ */
+ regmap_read(priv->map, LPC_IDR4, &val);
+ priv->idr = val & 0xff;
+ }
+
+ /* Copy data from internal storage to userspace */
+ if (copy_to_user(buf, &priv->idr, sizeof(priv->idr))) {
+ rc = -EFAULT;
+ goto out;
+ }
+
+ /* We're done consuming the internally stored value */
+ priv->pending = false;
+
+ remaining--;
+ buf++;
+ }
+
+ if (remaining) {
+ /* Either:
+ *
+ * 1. (count == 1 && *ppos == 1)
+ * 2. (count == 2 && *ppos == 0)
+ */
+ unsigned int val;
+ u8 str;
+
+ regmap_read(priv->map, LPC_STR4, &val);
+ str = val & 0xff;
+ if (*ppos == 0 || priv->pending)
+ /*
+ * If we got this far with `*ppos == 0` then we've read
+ * data out of IDR, so set IBF when reporting back to
+ * userspace so userspace knows the IDR value is valid.
+ */
+ str |= STR4_IBF;
+
+ dev_dbg(dev, "Read status 0x%x\n", str);
+ if (copy_to_user(buf, &str, sizeof(str))) {
+ rc = -EFAULT;
+ goto out;
+ }
+
+ remaining--;
+ }
+
+ WARN_ON(remaining);
+
+ rc = count;
+
+out:
+ spin_unlock_irq(&priv->rx.lock);
+
+ return rc;
+}
+
+static ssize_t mctp_lpc_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ uint8_t _data[2], *data = &_data[0];
+ struct mctp_lpc *priv;
+ struct device *dev;
+ size_t remaining;
+ unsigned int str;
+
+ priv = to_mctp_lpc(filp);
+ dev = priv->miscdev.this_device;
+
+ if (!count)
+ return count;
+
+ if (count > 2)
+ return -EINVAL;
+
+ if (*ppos >= 2)
+ return -EINVAL;
+
+ if (*ppos + count > 2)
+ return -EINVAL;
+
+ if (copy_from_user(data, buf, count))
+ return -EFAULT;
+
+ remaining = count;
+
+ if (*ppos == 0) {
+ /* Wait until OBF is clear - we don't get an IRQ */
+ dev_dbg(dev, "Waiting for OBF to clear\n");
+ for (;;) {
+ if (signal_pending(current))
+ return -EINTR;
+
+ regmap_read(priv->map, LPC_STR4, &str);
+ if (!(str & STR4_OBF))
+ break;
+
+ msleep(1);
+ }
+
+ dev_dbg(dev, "Writing 0x%x to ODR\n", *data);
+ regmap_write(priv->map, LPC_ODR4, *data);
+ remaining--;
+ data++;
+ }
+
+ if (remaining) {
+ if (!(*data & STR4_OBF))
+ dev_err(dev, "Clearing OBF with status write: 0x%x\n",
+ *data);
+ dev_dbg(dev, "Writing status 0x%x\n", *data);
+ regmap_write(priv->map, LPC_STR4, *data);
+ remaining--;
+ }
+
+ WARN_ON(remaining);
+
+ regmap_read(priv->map, LPC_STR4, &str);
+ dev_dbg(dev, "Triggering SerIRQ (current str=0x%x)\n", str);
+
+ /*
+ * Trigger Host IRQ on ODR write. Do this after any STR write in case
+ * we need to write ODR to indicate an STR update (which we do).
+ */
+ if (*ppos == 0)
+ regmap_update_bits(priv->map, LPC_HICRC, LPC_KCS4_IRQ_HOST,
+ LPC_KCS4_IRQ_HOST);
+
+ return count;
+}
+
+static __poll_t mctp_lpc_poll(struct file *filp, poll_table *wait)
+{
+ struct mctp_lpc *priv;
+ struct device *dev;
+ unsigned int val;
+ bool ibf;
+
+ priv = to_mctp_lpc(filp);
+ dev = priv->miscdev.this_device;
+
+ regmap_read(priv->map, LPC_STR4, &val);
+
+ spin_lock_irq(&priv->rx.lock);
+
+ ibf = priv->pending || val & STR4_IBF;
+
+ if (!ibf) {
+ dev_dbg(dev, "Polling on IBF\n");
+
+ spin_unlock_irq(&priv->rx.lock);
+
+ poll_wait(filp, &priv->rx, wait);
+ if (signal_pending(current)) {
+ dev_dbg(dev, "Polling IBF was interrupted\n");
+ goto out;
+ }
+
+ spin_lock_irq(&priv->rx.lock);
+
+ regmap_read(priv->map, LPC_STR4, &val);
+
+ ibf = priv->pending || val & STR4_IBF;
+ }
+
+ spin_unlock_irq(&priv->rx.lock);
+
+out:
+ dev_dbg(dev, "Polled IBF state: %s\n", ibf ? "set" : "clear");
+
+ return ibf ? EPOLLIN : 0;
+}
+
+static const struct file_operations mctp_lpc_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_seek_end_llseek,
+ .read = mctp_lpc_read,
+ .write = mctp_lpc_write,
+ .poll = mctp_lpc_poll,
+};
+
+static int mctp_lpc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ unsigned int mask, val;
+ struct mctp_lpc *priv;
+ int irq;
+ int rc;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->map = syscon_node_to_regmap(dev->parent->of_node);
+ if (IS_ERR(priv->map)) {
+ dev_err(dev, "Couldn't get regmap\n");
+ return -ENODEV;
+ }
+
+ /*
+ * Set the LPC address. Simultaneously, test our MMIO regmap works. All
+ * subsequent accesses are assumed to work
+ */
+ rc = regmap_write(priv->map, LPC_LADR4, ((HOST_STR) << 16) | HOST_ODR);
+ if (rc < 0)
+ return rc;
+
+ /* Set up the SerIRQ */
+ mask = LPC_KCS4_IRQSEL_MASK
+ | LPC_KCS4_IRQTYPE_MASK
+ | LPC_KCS4_OBF4_AUTO_CLR;
+ val = (HOST_SERIRQ_ID << LPC_KCS4_IRQSEL_SHIFT)
+ | (HOST_SERIRQ_TYPE << LPC_KCS4_IRQTYPE_SHIFT);
+ val &= ~LPC_KCS4_OBF4_AUTO_CLR; /* Unnecessary, just documentation */
+ regmap_update_bits(priv->map, LPC_HICRC, mask, val);
+
+ /* Trigger waiters from IRQ */
+ init_waitqueue_head(&priv->rx);
+
+ dev_set_drvdata(dev, priv);
+
+ /* Set up the miscdevice */
+ priv->miscdev.minor = MISC_DYNAMIC_MINOR;
+ priv->miscdev.name = "mctp0";
+ priv->miscdev.fops = &mctp_lpc_fops;
+
+ /* Configure the IRQ handler */
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ rc = devm_request_irq(dev, irq, mctp_lpc_irq, IRQF_SHARED,
+ dev_name(dev), priv);
+ if (rc < 0)
+ return rc;
+
+ /* Register the device */
+ rc = misc_register(&priv->miscdev);
+ if (rc) {
+ dev_err(dev, "Unable to register device\n");
+ return rc;
+ }
+
+ /* Enable the channel */
+ regmap_update_bits(priv->map, LPC_HICRB,
+ LPC_HICRB_IBFIF4 | LPC_HICRB_LPC4E,
+ LPC_HICRB_IBFIF4 | LPC_HICRB_LPC4E);
+
+ return 0;
+}
+
+static int mctp_lpc_remove(struct platform_device *pdev)
+{
+ struct mctp_lpc *ctx = dev_get_drvdata(&pdev->dev);
+
+ misc_deregister(&ctx->miscdev);
+
+ return 0;
+}
+
+static const struct of_device_id mctp_lpc_match[] = {
+ { .compatible = "openbmc,mctp-lpc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, mctp_lpc_match);
+
+static struct platform_driver mctp_lpc = {
+ .driver = {
+ .name = "mctp-lpc",
+ .of_match_table = mctp_lpc_match,
+ },
+ .probe = mctp_lpc_probe,
+ .remove = mctp_lpc_remove,
+};
+module_platform_driver(mctp_lpc);
+
+MODULE_LICENSE("GPL v2+");
+MODULE_AUTHOR("Andrew Jeffery <andrew@aj.id.au>");
+MODULE_DESCRIPTION("OpenBMC MCTP LPC binding on ASPEED KCS");
diff --git a/drivers/misc/npcm7xx-lpc-bpc.c b/drivers/misc/npcm7xx-lpc-bpc.c
new file mode 100644
index 000000000000..e014e07cd4a4
--- /dev/null
+++ b/drivers/misc/npcm7xx-lpc-bpc.c
@@ -0,0 +1,394 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2014-2018 Nuvoton Technology corporation.
+
+#include <linux/fs.h>
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/kfifo.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/miscdevice.h>
+#include <linux/poll.h>
+
+#define DEVICE_NAME "npcm7xx-lpc-bpc"
+
+#define NUM_BPC_CHANNELS 2
+#define DW_PAD_SIZE 3
+
+/* BIOS POST Code FIFO Registers */
+#define NPCM7XX_BPCFA2L_REG 0x2 //BIOS POST Code FIFO Address 2 LSB
+#define NPCM7XX_BPCFA2M_REG 0x4 //BIOS POST Code FIFO Address 2 MSB
+#define NPCM7XX_BPCFEN_REG 0x6 //BIOS POST Code FIFO Enable
+#define NPCM7XX_BPCFSTAT_REG 0x8 //BIOS POST Code FIFO Status
+#define NPCM7XX_BPCFDATA_REG 0xA //BIOS POST Code FIFO Data
+#define NPCM7XX_BPCFMSTAT_REG 0xC //BIOS POST Code FIFO Miscellaneous Status
+#define NPCM7XX_BPCFA1L_REG 0x10 //BIOS POST Code FIFO Address 1 LSB
+#define NPCM7XX_BPCFA1M_REG 0x12 //BIOS POST Code FIFO Address 1 MSB
+
+/*BIOS regiser data*/
+#define FIFO_IOADDR1_ENABLE 0x80
+#define FIFO_IOADDR2_ENABLE 0x40
+
+/* BPC interface package and structure definition */
+#define BPC_KFIFO_SIZE 0x400
+
+/*BPC regiser data*/
+#define FIFO_DATA_VALID 0x80
+#define FIFO_OVERFLOW 0x20
+#define FIFO_READY_INT_ENABLE 0x8
+#define FIFO_DWCAPTURE 0x4
+#define FIFO_ADDR_DECODE 0x1
+
+/*Host Reset*/
+#define HOST_RESET_INT_ENABLE 0x10
+#define HOST_RESET_CHANGED 0x40
+
+struct npcm7xx_bpc_channel {
+ struct npcm7xx_bpc *data;
+ struct kfifo fifo;
+ wait_queue_head_t wq;
+ bool host_reset;
+ struct miscdevice miscdev;
+};
+
+struct npcm7xx_bpc {
+ void __iomem *base;
+ int irq;
+ bool en_dwcap;
+ struct npcm7xx_bpc_channel ch[NUM_BPC_CHANNELS];
+};
+
+static struct npcm7xx_bpc_channel *npcm7xx_file_to_ch(struct file *file)
+{
+ return container_of(file->private_data, struct npcm7xx_bpc_channel,
+ miscdev);
+}
+
+static ssize_t npcm7xx_bpc_read(struct file *file, char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ struct npcm7xx_bpc_channel *chan = npcm7xx_file_to_ch(file);
+ struct npcm7xx_bpc *lpc_bpc = chan->data;
+ unsigned int copied;
+ int ret = 0;
+ int cond_size = 1;
+
+ if (lpc_bpc->en_dwcap)
+ cond_size = 3;
+
+ if (kfifo_len(&chan->fifo) < cond_size) {
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ ret = wait_event_interruptible
+ (chan->wq, kfifo_len(&chan->fifo) > cond_size);
+ if (ret == -ERESTARTSYS)
+ return -EINTR;
+ }
+
+ ret = kfifo_to_user(&chan->fifo, buffer, count, &copied);
+
+ return ret ? ret : copied;
+}
+
+static __poll_t npcm7xx_bpc_poll(struct file *file,
+ struct poll_table_struct *pt)
+{
+ struct npcm7xx_bpc_channel *chan = npcm7xx_file_to_ch(file);
+ __poll_t mask = 0;
+
+ poll_wait(file, &chan->wq, pt);
+ if (!kfifo_is_empty(&chan->fifo))
+ mask |= POLLIN;
+
+ if (chan->host_reset) {
+ mask |= POLLHUP;
+ chan->host_reset = false;
+ }
+
+ return mask;
+}
+
+static const struct file_operations npcm7xx_bpc_fops = {
+ .owner = THIS_MODULE,
+ .read = npcm7xx_bpc_read,
+ .poll = npcm7xx_bpc_poll,
+ .llseek = noop_llseek,
+};
+
+static irqreturn_t npcm7xx_bpc_irq(int irq, void *arg)
+{
+ struct npcm7xx_bpc *lpc_bpc = arg;
+ u8 fifo_st;
+ u8 host_st;
+ u8 addr_index = 0;
+ u8 Data;
+ u8 padzero[3] = {0};
+ u8 last_addr_bit = 0;
+ bool isr_flag = false;
+
+ fifo_st = ioread8(lpc_bpc->base + NPCM7XX_BPCFSTAT_REG);
+ while (FIFO_DATA_VALID & fifo_st) {
+ /* If dwcapture enabled only channel 0 (FIFO 0) used */
+ if (!lpc_bpc->en_dwcap)
+ addr_index = fifo_st & FIFO_ADDR_DECODE;
+ else
+ last_addr_bit = fifo_st & FIFO_ADDR_DECODE;
+
+ /*Read data from FIFO to clear interrupt*/
+ Data = ioread8(lpc_bpc->base + NPCM7XX_BPCFDATA_REG);
+ if (kfifo_is_full(&lpc_bpc->ch[addr_index].fifo))
+ kfifo_skip(&lpc_bpc->ch[addr_index].fifo);
+ kfifo_put(&lpc_bpc->ch[addr_index].fifo, Data);
+ if (fifo_st & FIFO_OVERFLOW)
+ pr_info("BIOS Post Codes FIFO Overflow!!!\n");
+
+ fifo_st = ioread8(lpc_bpc->base + NPCM7XX_BPCFSTAT_REG);
+ if (lpc_bpc->en_dwcap && last_addr_bit) {
+ if ((fifo_st & FIFO_ADDR_DECODE) ||
+ ((FIFO_DATA_VALID & fifo_st) == 0)) {
+ while (kfifo_avail(&lpc_bpc->ch[addr_index].fifo) < DW_PAD_SIZE)
+ kfifo_skip(&lpc_bpc->ch[addr_index].fifo);
+ kfifo_in(&lpc_bpc->ch[addr_index].fifo,
+ padzero, DW_PAD_SIZE);
+ }
+ }
+ isr_flag = true;
+ }
+
+ host_st = ioread8(lpc_bpc->base + NPCM7XX_BPCFMSTAT_REG);
+ if (host_st & HOST_RESET_CHANGED) {
+ iowrite8(HOST_RESET_CHANGED,
+ lpc_bpc->base + NPCM7XX_BPCFMSTAT_REG);
+ lpc_bpc->ch[addr_index].host_reset = true;
+ isr_flag = true;
+ }
+
+ if (isr_flag) {
+ wake_up_interruptible(&lpc_bpc->ch[addr_index].wq);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static int npcm7xx_bpc_config_irq(struct npcm7xx_bpc *lpc_bpc,
+ struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ int rc;
+
+ lpc_bpc->irq = platform_get_irq(pdev, 0);
+ if (lpc_bpc->irq < 0) {
+ dev_err(dev, "get IRQ failed\n");
+ return lpc_bpc->irq;
+ }
+
+ rc = devm_request_irq(dev, lpc_bpc->irq,
+ npcm7xx_bpc_irq, IRQF_SHARED,
+ DEVICE_NAME, lpc_bpc);
+ if (rc < 0) {
+ dev_warn(dev, "Unable to request IRQ %d\n", lpc_bpc->irq);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int npcm7xx_enable_bpc(struct npcm7xx_bpc *lpc_bpc, struct device *dev,
+ int channel, u16 lpc_port)
+{
+ int rc;
+ u8 addr_en, reg_en;
+
+ init_waitqueue_head(&lpc_bpc->ch[channel].wq);
+
+ rc = kfifo_alloc(&lpc_bpc->ch[channel].fifo,
+ BPC_KFIFO_SIZE, GFP_KERNEL);
+ if (rc)
+ return rc;
+
+ lpc_bpc->ch[channel].miscdev.minor = MISC_DYNAMIC_MINOR;
+ lpc_bpc->ch[channel].miscdev.name =
+ devm_kasprintf(dev, GFP_KERNEL, "%s%d", DEVICE_NAME, channel);
+ lpc_bpc->ch[channel].miscdev.fops = &npcm7xx_bpc_fops;
+ lpc_bpc->ch[channel].miscdev.parent = dev;
+ rc = misc_register(&lpc_bpc->ch[channel].miscdev);
+ if (rc)
+ return rc;
+
+ lpc_bpc->ch[channel].data = lpc_bpc;
+ lpc_bpc->ch[channel].host_reset = false;
+
+ /* Enable LPC snoop channel at requested port */
+ switch (channel) {
+ case 0:
+ addr_en = FIFO_IOADDR1_ENABLE;
+ iowrite8((u8)lpc_port & 0xFF,
+ lpc_bpc->base + NPCM7XX_BPCFA1L_REG);
+ iowrite8((u8)(lpc_port >> 8),
+ lpc_bpc->base + NPCM7XX_BPCFA1M_REG);
+ break;
+ case 1:
+ addr_en = FIFO_IOADDR2_ENABLE;
+ iowrite8((u8)lpc_port & 0xFF,
+ lpc_bpc->base + NPCM7XX_BPCFA2L_REG);
+ iowrite8((u8)(lpc_port >> 8),
+ lpc_bpc->base + NPCM7XX_BPCFA2M_REG);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (lpc_bpc->en_dwcap)
+ addr_en = FIFO_DWCAPTURE;
+
+ /*
+ * Enable FIFO Ready Interrupt, FIFO Capture of I/O addr,
+ * and Host Reset
+ */
+ reg_en = ioread8(lpc_bpc->base + NPCM7XX_BPCFEN_REG);
+ iowrite8(reg_en | addr_en | FIFO_READY_INT_ENABLE |
+ HOST_RESET_INT_ENABLE, lpc_bpc->base + NPCM7XX_BPCFEN_REG);
+
+ return 0;
+}
+
+static void npcm7xx_disable_bpc(struct npcm7xx_bpc *lpc_bpc, int channel)
+{
+ u8 reg_en;
+
+ switch (channel) {
+ case 0:
+ reg_en = ioread8(lpc_bpc->base + NPCM7XX_BPCFEN_REG);
+ if (lpc_bpc->en_dwcap)
+ iowrite8(reg_en & ~FIFO_DWCAPTURE,
+ lpc_bpc->base + NPCM7XX_BPCFEN_REG);
+ else
+ iowrite8(reg_en & ~FIFO_IOADDR1_ENABLE,
+ lpc_bpc->base + NPCM7XX_BPCFEN_REG);
+ break;
+ case 1:
+ reg_en = ioread8(lpc_bpc->base + NPCM7XX_BPCFEN_REG);
+ iowrite8(reg_en & ~FIFO_IOADDR2_ENABLE,
+ lpc_bpc->base + NPCM7XX_BPCFEN_REG);
+ break;
+ default:
+ return;
+ }
+
+ if (!(reg_en & (FIFO_IOADDR1_ENABLE | FIFO_IOADDR2_ENABLE)))
+ iowrite8(reg_en &
+ ~(FIFO_READY_INT_ENABLE | HOST_RESET_INT_ENABLE),
+ lpc_bpc->base + NPCM7XX_BPCFEN_REG);
+
+ kfifo_free(&lpc_bpc->ch[channel].fifo);
+ misc_deregister(&lpc_bpc->ch[channel].miscdev);
+}
+
+static int npcm7xx_bpc_probe(struct platform_device *pdev)
+{
+ struct npcm7xx_bpc *lpc_bpc;
+ struct resource *res;
+ struct device *dev;
+ u32 port;
+ int rc;
+
+ dev = &pdev->dev;
+
+ lpc_bpc = devm_kzalloc(dev, sizeof(*lpc_bpc), GFP_KERNEL);
+ if (!lpc_bpc)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev, "BIOS post code reg resource not found\n");
+ return -ENODEV;
+ }
+
+ dev_dbg(dev, "BIOS post code base resource is %pR\n", res);
+ lpc_bpc->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(lpc_bpc->base))
+ return PTR_ERR(lpc_bpc->base);
+
+ dev_set_drvdata(&pdev->dev, lpc_bpc);
+
+ rc = of_property_read_u32_index(dev->of_node, "monitor-ports", 0,
+ &port);
+ if (rc) {
+ dev_err(dev, "no monitor ports configured\n");
+ return -ENODEV;
+ }
+
+ lpc_bpc->en_dwcap =
+ of_property_read_bool(dev->of_node, "bpc-en-dwcapture");
+
+ rc = npcm7xx_bpc_config_irq(lpc_bpc, pdev);
+ if (rc)
+ return rc;
+
+ rc = npcm7xx_enable_bpc(lpc_bpc, dev, 0, port);
+ if (rc) {
+ dev_err(dev, "Enable BIOS post code I/O port 0 failed\n");
+ return rc;
+ }
+
+ /*
+ * Configuration of second BPC channel port is optional
+ * Double-Word Capture ignoring address 2
+ */
+ if (!lpc_bpc->en_dwcap) {
+ if (of_property_read_u32_index(dev->of_node, "monitor-ports",
+ 1, &port) == 0) {
+ rc = npcm7xx_enable_bpc(lpc_bpc, dev, 1, port);
+ if (rc) {
+ dev_err(dev, "Enable BIOS post code I/O port 1 failed, disable I/O port 0\n");
+ npcm7xx_disable_bpc(lpc_bpc, 0);
+ return rc;
+ }
+ }
+ }
+
+ pr_info("npcm7xx BIOS post code probe\n");
+
+ return rc;
+}
+
+static int npcm7xx_bpc_remove(struct platform_device *pdev)
+{
+ struct npcm7xx_bpc *lpc_bpc = dev_get_drvdata(&pdev->dev);
+ u8 reg_en;
+
+ reg_en = ioread8(lpc_bpc->base + NPCM7XX_BPCFEN_REG);
+
+ if (reg_en & FIFO_IOADDR1_ENABLE)
+ npcm7xx_disable_bpc(lpc_bpc, 0);
+ if (reg_en & FIFO_IOADDR2_ENABLE)
+ npcm7xx_disable_bpc(lpc_bpc, 1);
+
+ return 0;
+}
+
+static const struct of_device_id npcm7xx_bpc_match[] = {
+ { .compatible = "nuvoton,npcm750-lpc-bpc" },
+ { },
+};
+
+static struct platform_driver npcm7xx_bpc_driver = {
+ .driver = {
+ .name = DEVICE_NAME,
+ .of_match_table = npcm7xx_bpc_match,
+ },
+ .probe = npcm7xx_bpc_probe,
+ .remove = npcm7xx_bpc_remove,
+};
+
+module_platform_driver(npcm7xx_bpc_driver);
+
+MODULE_DEVICE_TABLE(of, npcm7xx_bpc_match);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tomer Maimon <tomer.maimon@nuvoton.com>");
+MODULE_DESCRIPTION("Linux driver to control NPCM7XX LPC BIOS post code monitoring");
diff --git a/drivers/misc/npcm7xx-pci-mbox.c b/drivers/misc/npcm7xx-pci-mbox.c
new file mode 100644
index 000000000000..1a80661a4296
--- /dev/null
+++ b/drivers/misc/npcm7xx-pci-mbox.c
@@ -0,0 +1,288 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2014-2018 Nuvoton Technology corporation.
+
+#include <linux/interrupt.h>
+#include <linux/mfd/syscon.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/poll.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#define DEVICE_NAME "npcm7xx-pci-mbox"
+
+#define NPCM7XX_MBOX_BMBXSTAT 0x0
+#define NPCM7XX_MBOX_BMBXCTL 0x4
+#define NPCM7XX_MBOX_BMBXCMD 0x8
+
+#define NPCM7XX_MBOX_CIF_0 BIT(0)
+#define NPCM7XX_MBOX_CIE_0 BIT(0)
+#define NPCM7XX_MBOX_HIF_0 BIT(0)
+
+#define NPCM7XX_MBOX_ALL_CIF GENMASK(7, 0)
+#define NPCM7XX_MBOX_ALL_CIE GENMASK(7, 0)
+#define NPCM7XX_MBOX_ALL_HIF GENMASK(7, 0)
+
+struct npcm7xx_mbox {
+ struct miscdevice miscdev;
+ struct regmap *regmap;
+ void __iomem *memory;
+ wait_queue_head_t queue;
+ spinlock_t lock; /* mbox access mutex */
+ bool cif0;
+ u32 max_buf_size;
+};
+
+static atomic_t npcm7xx_mbox_open_count = ATOMIC_INIT(0);
+
+static struct npcm7xx_mbox *file_mbox(struct file *file)
+{
+ return container_of(file->private_data, struct npcm7xx_mbox, miscdev);
+}
+
+static int npcm7xx_mbox_open(struct inode *inode, struct file *file)
+{
+ struct npcm7xx_mbox *mbox = file_mbox(file);
+
+ if (atomic_inc_return(&npcm7xx_mbox_open_count) == 1) {
+ /* enable mailbox interrupt */
+ regmap_update_bits(mbox->regmap, NPCM7XX_MBOX_BMBXCTL,
+ NPCM7XX_MBOX_ALL_CIE, NPCM7XX_MBOX_CIE_0);
+ return 0;
+ }
+
+ atomic_dec(&npcm7xx_mbox_open_count);
+ return -EBUSY;
+}
+
+static ssize_t npcm7xx_mbox_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct npcm7xx_mbox *mbox = file_mbox(file);
+ unsigned long flags;
+
+ if (!access_ok(buf, count))
+ return -EFAULT;
+
+ if ((*ppos + count) > mbox->max_buf_size)
+ return -EINVAL;
+
+ if (file->f_flags & O_NONBLOCK) {
+ if (!mbox->cif0)
+ return -EAGAIN;
+ } else if (wait_event_interruptible(mbox->queue, mbox->cif0)) {
+ return -ERESTARTSYS;
+ }
+
+ spin_lock_irqsave(&mbox->lock, flags);
+
+ if (copy_to_user((void __user *)buf,
+ (const void *)(mbox->memory + *ppos), count)) {
+ spin_unlock_irqrestore(&mbox->lock, flags);
+ return -EFAULT;
+ }
+
+ mbox->cif0 = false;
+ spin_unlock_irqrestore(&mbox->lock, flags);
+ return count;
+}
+
+static ssize_t npcm7xx_mbox_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct npcm7xx_mbox *mbox = file_mbox(file);
+ unsigned long flags;
+
+ if (!access_ok(buf, count))
+ return -EFAULT;
+
+ if ((*ppos + count) > mbox->max_buf_size)
+ return -EINVAL;
+
+ spin_lock_irqsave(&mbox->lock, flags);
+
+ if (copy_from_user((void *)(mbox->memory + *ppos),
+ (void __user *)buf, count)) {
+ spin_unlock_irqrestore(&mbox->lock, flags);
+ return -EFAULT;
+ }
+
+ regmap_update_bits(mbox->regmap, NPCM7XX_MBOX_BMBXCMD,
+ NPCM7XX_MBOX_ALL_HIF, NPCM7XX_MBOX_HIF_0);
+
+ spin_unlock_irqrestore(&mbox->lock, flags);
+ return count;
+}
+
+static unsigned int npcm7xx_mbox_poll(struct file *file, poll_table *wait)
+{
+ struct npcm7xx_mbox *mbox = file_mbox(file);
+ unsigned int mask = 0;
+
+ poll_wait(file, &mbox->queue, wait);
+ if (mbox->cif0)
+ mask |= POLLIN;
+
+ return mask;
+}
+
+static int npcm7xx_mbox_release(struct inode *inode, struct file *file)
+{
+ atomic_dec(&npcm7xx_mbox_open_count);
+ return 0;
+}
+
+static const struct file_operations npcm7xx_mbox_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_seek_end_llseek,
+ .read = npcm7xx_mbox_read,
+ .write = npcm7xx_mbox_write,
+ .open = npcm7xx_mbox_open,
+ .release = npcm7xx_mbox_release,
+ .poll = npcm7xx_mbox_poll,
+};
+
+static irqreturn_t npcm7xx_mbox_irq(int irq, void *arg)
+{
+ struct npcm7xx_mbox *mbox = arg;
+ u32 val;
+
+ regmap_read(mbox->regmap, NPCM7XX_MBOX_BMBXSTAT, &val);
+ if ((val & NPCM7XX_MBOX_CIF_0) != NPCM7XX_MBOX_CIF_0)
+ return IRQ_NONE;
+
+ /*
+ * Leave the status bit set so that we know the data is for us,
+ * clear it once it has been read.
+ */
+ mbox->cif0 = true;
+
+ /* Mask it off, we'll clear it when we the data gets read */
+ regmap_write_bits(mbox->regmap, NPCM7XX_MBOX_BMBXSTAT,
+ NPCM7XX_MBOX_ALL_CIF, NPCM7XX_MBOX_CIF_0);
+
+ wake_up(&mbox->queue);
+
+ return IRQ_HANDLED;
+}
+
+static int npcm7xx_mbox_config_irq(struct npcm7xx_mbox *mbox,
+ struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ int rc, irq;
+ u32 val;
+
+ /* Disable all register based interrupts */
+ regmap_update_bits(mbox->regmap, NPCM7XX_MBOX_BMBXCTL,
+ NPCM7XX_MBOX_ALL_CIE, 0);
+/*
+ * These registers are write one to clear. Clear them.
+ * Per spec, cleared bits should not be re-cleared.
+ * Need to read and clear needed bits only, instead of blindly clearing all.
+ */
+ regmap_read(mbox->regmap, NPCM7XX_MBOX_BMBXSTAT, &val);
+ val &= NPCM7XX_MBOX_ALL_CIF;
+
+ /* If any bit is set, write back to clear */
+ if (val)
+ regmap_write_bits(mbox->regmap, NPCM7XX_MBOX_BMBXSTAT,
+ NPCM7XX_MBOX_ALL_CIF, val);
+
+ irq = irq_of_parse_and_map(dev->of_node, 0);
+ if (!irq)
+ return -ENODEV;
+
+ rc = devm_request_irq(dev, irq, npcm7xx_mbox_irq, 0, DEVICE_NAME, mbox);
+ if (rc < 0) {
+ dev_err(dev, "Unable to request IRQ %d\n", irq);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int npcm7xx_mbox_probe(struct platform_device *pdev)
+{
+ struct npcm7xx_mbox *mbox;
+ struct device *dev;
+ struct resource *res;
+ int rc;
+
+ dev = &pdev->dev;
+
+ mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL);
+ if (!mbox)
+ return -ENOMEM;
+
+ dev_set_drvdata(&pdev->dev, mbox);
+
+ mbox->regmap = syscon_node_to_regmap(dev->of_node);
+ if (IS_ERR(mbox->regmap)) {
+ dev_err(dev, "Couldn't get regmap\n");
+ return -ENODEV;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ mbox->memory = devm_ioremap_resource(dev, res);
+ if (IS_ERR(mbox->memory))
+ return PTR_ERR(mbox->memory);
+ mbox->max_buf_size = resource_size(res);
+
+ spin_lock_init(&mbox->lock);
+ init_waitqueue_head(&mbox->queue);
+
+ mbox->miscdev.minor = MISC_DYNAMIC_MINOR;
+ mbox->miscdev.name = DEVICE_NAME;
+ mbox->miscdev.fops = &npcm7xx_mbox_fops;
+ mbox->miscdev.parent = dev;
+ mbox->cif0 = false;
+ rc = misc_register(&mbox->miscdev);
+ if (rc) {
+ dev_err(dev, "Unable to register device\n");
+ return rc;
+ }
+
+ rc = npcm7xx_mbox_config_irq(mbox, pdev);
+ if (rc) {
+ dev_err(dev, "Failed to configure IRQ\n");
+ misc_deregister(&mbox->miscdev);
+ return rc;
+ }
+
+ pr_info("NPCM7xx PCI Mailbox probed\n");
+
+ return 0;
+}
+
+static int npcm7xx_mbox_remove(struct platform_device *pdev)
+{
+ struct npcm7xx_mbox *mbox = dev_get_drvdata(&pdev->dev);
+
+ misc_deregister(&mbox->miscdev);
+
+ return 0;
+}
+
+static const struct of_device_id npcm7xx_mbox_match[] = {
+ { .compatible = "nuvoton,npcm750-pci-mbox" },
+ { },
+};
+
+static struct platform_driver npcm7xx_mbox_driver = {
+ .driver = {
+ .name = DEVICE_NAME,
+ .of_match_table = npcm7xx_mbox_match,
+ },
+ .probe = npcm7xx_mbox_probe,
+ .remove = npcm7xx_mbox_remove,
+};
+
+module_platform_driver(npcm7xx_mbox_driver);
+
+MODULE_DEVICE_TABLE(of, npcm7xx_mbox_match);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tomer Maimon <tomer.maimon@nuvoton.com>");
+MODULE_DESCRIPTION("NPCM7XX mailbox device driver");
diff --git a/drivers/mtd/spi-nor/aspeed-smc.c b/drivers/mtd/spi-nor/aspeed-smc.c
index 009c1da8574c..0805dcab8cb1 100644
--- a/drivers/mtd/spi-nor/aspeed-smc.c
+++ b/drivers/mtd/spi-nor/aspeed-smc.c
@@ -6,6 +6,7 @@
*/
#include <linux/bug.h>
+#include <linux/clk.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/module.h>
@@ -16,6 +17,7 @@
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/sizes.h>
+#include <linux/slab.h>
#include <linux/sysfs.h>
#define DEVICE_NAME "aspeed-smc"
@@ -30,6 +32,7 @@ enum aspeed_smc_flash_type {
};
struct aspeed_smc_chip;
+struct aspeed_smc_controller;
struct aspeed_smc_info {
u32 maxsize; /* maximum size of chip window */
@@ -37,12 +40,34 @@ struct aspeed_smc_info {
bool hastype; /* flash type field exists in config reg */
u8 we0; /* shift for write enable bit for CE0 */
u8 ctl0; /* offset in regs of ctl for CE0 */
+ u8 timing; /* offset in regs of timing */
+ u32 hclk_mask; /* clock frequency mask in CEx Control reg */
+ u32 hdiv_max; /* Max HCLK divisor on read timing reg */
void (*set_4b)(struct aspeed_smc_chip *chip);
+ int (*optimize_read)(struct aspeed_smc_chip *chip, u32 max_freq);
+ int (*calibrate)(struct aspeed_smc_chip *chip, u32 hdiv,
+ const u8 *golden_buf, u8 *test_buf);
+
+ u32 (*segment_start)(struct aspeed_smc_controller *controller, u32 reg);
+ u32 (*segment_end)(struct aspeed_smc_controller *controller, u32 reg);
+ u32 (*segment_reg)(struct aspeed_smc_controller *controller,
+ u32 start, u32 end);
};
static void aspeed_smc_chip_set_4b_spi_2400(struct aspeed_smc_chip *chip);
static void aspeed_smc_chip_set_4b(struct aspeed_smc_chip *chip);
+static int aspeed_smc_optimize_read(struct aspeed_smc_chip *chip,
+ u32 max_freq);
+static int aspeed_smc_calibrate_reads(struct aspeed_smc_chip *chip, u32 hdiv,
+ const u8 *golden_buf, u8 *test_buf);
+
+static u32 aspeed_smc_segment_start(
+ struct aspeed_smc_controller *controller, u32 reg);
+static u32 aspeed_smc_segment_end(
+ struct aspeed_smc_controller *controller, u32 reg);
+static u32 aspeed_smc_segment_reg(
+ struct aspeed_smc_controller *controller, u32 start, u32 end);
static const struct aspeed_smc_info fmc_2400_info = {
.maxsize = 64 * 1024 * 1024,
@@ -50,7 +75,15 @@ static const struct aspeed_smc_info fmc_2400_info = {
.hastype = true,
.we0 = 16,
.ctl0 = 0x10,
+ .timing = 0x94,
+ .hclk_mask = 0xfffff0ff,
+ .hdiv_max = 1,
.set_4b = aspeed_smc_chip_set_4b,
+ .optimize_read = aspeed_smc_optimize_read,
+ .calibrate = aspeed_smc_calibrate_reads,
+ .segment_start = aspeed_smc_segment_start,
+ .segment_end = aspeed_smc_segment_end,
+ .segment_reg = aspeed_smc_segment_reg,
};
static const struct aspeed_smc_info spi_2400_info = {
@@ -59,7 +92,13 @@ static const struct aspeed_smc_info spi_2400_info = {
.hastype = false,
.we0 = 0,
.ctl0 = 0x04,
+ .timing = 0x14,
+ .hclk_mask = 0xfffff0ff,
+ .hdiv_max = 1,
.set_4b = aspeed_smc_chip_set_4b_spi_2400,
+ .optimize_read = aspeed_smc_optimize_read,
+ .calibrate = aspeed_smc_calibrate_reads,
+ /* No segment registers */
};
static const struct aspeed_smc_info fmc_2500_info = {
@@ -68,7 +107,15 @@ static const struct aspeed_smc_info fmc_2500_info = {
.hastype = true,
.we0 = 16,
.ctl0 = 0x10,
+ .timing = 0x94,
+ .hclk_mask = 0xfffff0ff,
+ .hdiv_max = 1,
.set_4b = aspeed_smc_chip_set_4b,
+ .optimize_read = aspeed_smc_optimize_read,
+ .calibrate = aspeed_smc_calibrate_reads,
+ .segment_start = aspeed_smc_segment_start,
+ .segment_end = aspeed_smc_segment_end,
+ .segment_reg = aspeed_smc_segment_reg,
};
static const struct aspeed_smc_info spi_2500_info = {
@@ -77,7 +124,59 @@ static const struct aspeed_smc_info spi_2500_info = {
.hastype = false,
.we0 = 16,
.ctl0 = 0x10,
+ .timing = 0x94,
+ .hclk_mask = 0xfffff0ff,
+ .hdiv_max = 1,
+ .set_4b = aspeed_smc_chip_set_4b,
+ .optimize_read = aspeed_smc_optimize_read,
+ .calibrate = aspeed_smc_calibrate_reads,
+ .segment_start = aspeed_smc_segment_start,
+ .segment_end = aspeed_smc_segment_end,
+ .segment_reg = aspeed_smc_segment_reg,
+};
+
+static u32 aspeed_smc_segment_start_ast2600(
+ struct aspeed_smc_controller *controller, u32 reg);
+static u32 aspeed_smc_segment_end_ast2600(
+ struct aspeed_smc_controller *controller, u32 reg);
+static u32 aspeed_smc_segment_reg_ast2600(
+ struct aspeed_smc_controller *controller, u32 start, u32 end);
+
+static int aspeed_smc_calibrate_reads_ast2600(struct aspeed_smc_chip *chip,
+ u32 hdiv, const u8 *golden_buf, u8 *test_buf);
+
+static const struct aspeed_smc_info fmc_2600_info = {
+ .maxsize = 256 * 1024 * 1024,
+ .nce = 3,
+ .hastype = false, /* SPI Only */
+ .we0 = 16,
+ .ctl0 = 0x10,
+ .timing = 0x94,
+ .hclk_mask = 0xf0fff0ff,
+ .hdiv_max = 2,
+ .set_4b = aspeed_smc_chip_set_4b,
+ .optimize_read = aspeed_smc_optimize_read,
+ .calibrate = aspeed_smc_calibrate_reads_ast2600,
+ .segment_start = aspeed_smc_segment_start_ast2600,
+ .segment_end = aspeed_smc_segment_end_ast2600,
+ .segment_reg = aspeed_smc_segment_reg_ast2600,
+};
+
+static const struct aspeed_smc_info spi_2600_info = {
+ .maxsize = 256 * 1024 * 1024,
+ .nce = 2,
+ .hastype = false,
+ .we0 = 16,
+ .ctl0 = 0x10,
+ .timing = 0x94,
+ .hclk_mask = 0xf0fff0ff,
+ .hdiv_max = 2,
.set_4b = aspeed_smc_chip_set_4b,
+ .optimize_read = aspeed_smc_optimize_read,
+ .calibrate = aspeed_smc_calibrate_reads_ast2600,
+ .segment_start = aspeed_smc_segment_start_ast2600,
+ .segment_end = aspeed_smc_segment_end_ast2600,
+ .segment_reg = aspeed_smc_segment_reg_ast2600,
};
enum aspeed_smc_ctl_reg_value {
@@ -98,6 +197,7 @@ struct aspeed_smc_chip {
u32 ctl_val[smc_max]; /* control settings */
enum aspeed_smc_flash_type type; /* what type of flash */
struct spi_nor nor;
+ u32 clk_rate;
};
struct aspeed_smc_controller {
@@ -106,12 +206,17 @@ struct aspeed_smc_controller {
struct mutex mutex; /* controller access mutex */
const struct aspeed_smc_info *info; /* type info of controller */
void __iomem *regs; /* controller registers */
- void __iomem *ahb_base; /* per-chip windows resource */
+ void __iomem *ahb_base; /* per-chip window resource */
+ u32 ahb_base_phy; /* phys addr of AHB window */
u32 ahb_window_size; /* full mapping window size */
+ unsigned long clk_frequency;
+
struct aspeed_smc_chip *chips[0]; /* pointers to attached chips */
};
+#define ASPEED_SPI_DEFAULT_FREQ 50000000
+
/*
* SPI Flash Configuration Register (AST2500 SPI)
* or
@@ -181,23 +286,82 @@ struct aspeed_smc_controller {
(CONTROL_AAF_MODE | CONTROL_CE_INACTIVE_MASK | CONTROL_CLK_DIV4 | \
CONTROL_CLOCK_FREQ_SEL_MASK | CONTROL_LSB_FIRST | CONTROL_CLOCK_MODE_3)
-/*
- * The Segment Register uses a 8MB unit to encode the start address
- * and the end address of the mapping window of a flash SPI slave :
- *
- * | byte 1 | byte 2 | byte 3 | byte 4 |
- * +--------+--------+--------+--------+
- * | end | start | 0 | 0 |
- */
#define SEGMENT_ADDR_REG0 0x30
-#define SEGMENT_ADDR_START(_r) ((((_r) >> 16) & 0xFF) << 23)
-#define SEGMENT_ADDR_END(_r) ((((_r) >> 24) & 0xFF) << 23)
-#define SEGMENT_ADDR_VALUE(start, end) \
- (((((start) >> 23) & 0xFF) << 16) | ((((end) >> 23) & 0xFF) << 24))
#define SEGMENT_ADDR_REG(controller, cs) \
((controller)->regs + SEGMENT_ADDR_REG0 + (cs) * 4)
/*
+ * The Segment Registers of the AST2400 and AST2500 have a 8MB
+ * unit. The address range of a flash SPI slave is encoded with
+ * absolute addresses which should be part of the overall controller
+ * window.
+ */
+static u32 aspeed_smc_segment_start(
+ struct aspeed_smc_controller *controller, u32 reg)
+{
+ return ((reg >> 16) & 0xFF) << 23;
+}
+
+static u32 aspeed_smc_segment_end(
+ struct aspeed_smc_controller *controller, u32 reg)
+{
+ return ((reg >> 24) & 0xFF) << 23;
+}
+
+static u32 aspeed_smc_segment_reg(
+ struct aspeed_smc_controller *controller, u32 start, u32 end)
+{
+ return (((start >> 23) & 0xFF) << 16) | (((end >> 23) & 0xFF) << 24);
+}
+
+/*
+ * The Segment Registers of the AST2600 have a 1MB unit. The address
+ * range of a flash SPI slave is encoded with offsets in the overall
+ * controller window. The previous SoC AST2400 and AST2500 used
+ * absolute addresses. Only bits [27:20] are relevant and the end
+ * address is an upper bound limit.
+ */
+
+#define AST2600_SEG_ADDR_MASK 0x0ff00000
+
+static u32 aspeed_smc_segment_start_ast2600(
+ struct aspeed_smc_controller *controller, u32 reg)
+{
+ uint32_t start_offset = (reg << 16) & AST2600_SEG_ADDR_MASK;
+
+ return controller->ahb_base_phy + start_offset;
+}
+
+static u32 aspeed_smc_segment_end_ast2600(
+ struct aspeed_smc_controller *controller, u32 reg)
+{
+ uint32_t end_offset = reg & AST2600_SEG_ADDR_MASK;
+
+ /* segment is disabled */
+ if (!end_offset)
+ return controller->ahb_base_phy;
+
+ return controller->ahb_base_phy + end_offset + 0x100000;
+}
+
+static u32 aspeed_smc_segment_reg_ast2600(
+ struct aspeed_smc_controller *controller, u32 start, u32 end)
+{
+ /* disable zero size segments */
+ if (start == end)
+ return 0;
+
+ return ((start & AST2600_SEG_ADDR_MASK) >> 16) |
+ ((end - 1) & AST2600_SEG_ADDR_MASK);
+}
+
+/*
+ * Switch to turn off read optimisation if needed
+ */
+static bool optimize_read = true;
+module_param(optimize_read, bool, 0644);
+
+/*
* In user mode all data bytes read or written to the chip decode address
* range are transferred to or from the SPI bus. The range is treated as a
* fifo of arbitratry 1, 2, or 4 byte width but each write has to be aligned
@@ -369,18 +533,49 @@ static void aspeed_smc_send_cmd_addr(struct spi_nor *nor, u8 cmd, u32 addr)
}
}
+static int aspeed_smc_get_io_mode(struct aspeed_smc_chip *chip)
+{
+ switch (chip->nor.read_proto) {
+ case SNOR_PROTO_1_1_1:
+ return 0;
+ case SNOR_PROTO_1_1_2:
+ return CONTROL_IO_DUAL_DATA;
+ case SNOR_PROTO_1_2_2:
+ return CONTROL_IO_DUAL_ADDR_DATA;
+ default:
+ dev_err(chip->nor.dev, "unsupported SPI read mode\n");
+ return -EINVAL;
+ }
+}
+
+static void aspeed_smc_set_io_mode(struct aspeed_smc_chip *chip, u32 io_mode)
+{
+ u32 ctl;
+
+ if (io_mode > 0) {
+ ctl = readl(chip->ctl) & ~CONTROL_IO_MODE_MASK;
+ ctl |= io_mode;
+ writel(ctl, chip->ctl);
+ }
+}
+
static ssize_t aspeed_smc_read_user(struct spi_nor *nor, loff_t from,
size_t len, u_char *read_buf)
{
struct aspeed_smc_chip *chip = nor->priv;
int i;
u8 dummy = 0xFF;
+ int io_mode = aspeed_smc_get_io_mode(chip);
aspeed_smc_start_user(nor);
aspeed_smc_send_cmd_addr(nor, nor->read_opcode, from);
for (i = 0; i < chip->nor.read_dummy / 8; i++)
aspeed_smc_write_to_ahb(chip->ahb_base, &dummy, sizeof(dummy));
+ /* Set IO mode only for data */
+ if (io_mode == CONTROL_IO_DUAL_DATA)
+ aspeed_smc_set_io_mode(chip, io_mode);
+
aspeed_smc_read_from_ahb(read_buf, chip->ahb_base, len);
aspeed_smc_stop_user(nor);
return len;
@@ -398,6 +593,31 @@ static ssize_t aspeed_smc_write_user(struct spi_nor *nor, loff_t to,
return len;
}
+static ssize_t aspeed_smc_read(struct spi_nor *nor, loff_t from, size_t len,
+ u_char *read_buf)
+{
+ struct aspeed_smc_chip *chip = nor->priv;
+
+ /*
+ * The AHB window configured for the chip is too small for the
+ * read offset. Use the "User mode" of the controller to
+ * perform the read.
+ */
+ if (from >= chip->ahb_window_size) {
+ aspeed_smc_read_user(nor, from, len, read_buf);
+ goto out;
+ }
+
+ /*
+ * Use the "Command mode" to do a direct read from the AHB
+ * window configured for the chip. This should be the default.
+ */
+ memcpy_fromio(read_buf, chip->ahb_base + from, len);
+
+out:
+ return len;
+}
+
static int aspeed_smc_unregister(struct aspeed_smc_controller *controller)
{
struct aspeed_smc_chip *chip;
@@ -422,6 +642,8 @@ static const struct of_device_id aspeed_smc_matches[] = {
{ .compatible = "aspeed,ast2400-spi", .data = &spi_2400_info },
{ .compatible = "aspeed,ast2500-fmc", .data = &fmc_2500_info },
{ .compatible = "aspeed,ast2500-spi", .data = &spi_2500_info },
+ { .compatible = "aspeed,ast2600-fmc", .data = &fmc_2600_info },
+ { .compatible = "aspeed,ast2600-spi", .data = &spi_2600_info },
{ }
};
MODULE_DEVICE_TABLE(of, aspeed_smc_matches);
@@ -437,36 +659,32 @@ static void __iomem *aspeed_smc_chip_base(struct aspeed_smc_chip *chip,
struct resource *res)
{
struct aspeed_smc_controller *controller = chip->controller;
+ const struct aspeed_smc_info *info = controller->info;
u32 offset = 0;
u32 reg;
- if (controller->info->nce > 1) {
+ if (info->nce > 1) {
reg = readl(SEGMENT_ADDR_REG(controller, chip->cs));
- if (SEGMENT_ADDR_START(reg) >= SEGMENT_ADDR_END(reg))
+ if (info->segment_start(controller, reg) >=
+ info->segment_end(controller, reg)) {
return NULL;
+ }
- offset = SEGMENT_ADDR_START(reg) - res->start;
+ offset = info->segment_start(controller, reg) - res->start;
}
return controller->ahb_base + offset;
}
-static u32 aspeed_smc_ahb_base_phy(struct aspeed_smc_controller *controller)
-{
- u32 seg0_val = readl(SEGMENT_ADDR_REG(controller, 0));
-
- return SEGMENT_ADDR_START(seg0_val);
-}
-
static u32 chip_set_segment(struct aspeed_smc_chip *chip, u32 cs, u32 start,
u32 size)
{
struct aspeed_smc_controller *controller = chip->controller;
+ const struct aspeed_smc_info *info = controller->info;
void __iomem *seg_reg;
- u32 seg_oldval, seg_newval, ahb_base_phy, end;
-
- ahb_base_phy = aspeed_smc_ahb_base_phy(controller);
+ u32 seg_oldval, seg_newval, end;
+ u32 ahb_base_phy = controller->ahb_base_phy;
seg_reg = SEGMENT_ADDR_REG(controller, cs);
seg_oldval = readl(seg_reg);
@@ -476,8 +694,15 @@ static u32 chip_set_segment(struct aspeed_smc_chip *chip, u32 cs, u32 start,
* size, but take into account the possible overlap with the
* previous segment
*/
- if (!size)
- size = SEGMENT_ADDR_END(seg_oldval) - start;
+ if (!size) {
+ end = info->segment_end(controller, seg_oldval);
+
+ /*
+ * Check for disabled segment (AST2600).
+ */
+ if (end != ahb_base_phy)
+ size = end - start;
+ }
/*
* The segment cannot exceed the maximum window size of the
@@ -490,7 +715,7 @@ static u32 chip_set_segment(struct aspeed_smc_chip *chip, u32 cs, u32 start,
}
end = start + size;
- seg_newval = SEGMENT_ADDR_VALUE(start, end);
+ seg_newval = info->segment_reg(controller, start, end);
writel(seg_newval, seg_reg);
/*
@@ -501,13 +726,13 @@ static u32 chip_set_segment(struct aspeed_smc_chip *chip, u32 cs, u32 start,
if (seg_newval != readl(seg_reg)) {
dev_err(chip->nor.dev, "CE%d window invalid", cs);
writel(seg_oldval, seg_reg);
- start = SEGMENT_ADDR_START(seg_oldval);
- end = SEGMENT_ADDR_END(seg_oldval);
+ start = info->segment_start(controller, seg_oldval);
+ end = info->segment_end(controller, seg_oldval);
size = end - start;
}
- dev_info(chip->nor.dev, "CE%d window [ 0x%.8x - 0x%.8x ] %dMB",
- cs, start, end, size >> 20);
+ dev_info(chip->nor.dev, "CE%d window [ 0x%.8x - 0x%.8x ] %dMB%s",
+ cs, start, end, size >> 20, size ? "" : " (disabled)");
return size;
}
@@ -555,7 +780,7 @@ static u32 aspeed_smc_chip_set_segment(struct aspeed_smc_chip *chip)
chip->cs, size >> 20);
}
- ahb_base_phy = aspeed_smc_ahb_base_phy(controller);
+ ahb_base_phy = controller->ahb_base_phy;
/*
* As a start address for the current segment, use the default
@@ -565,7 +790,7 @@ static u32 aspeed_smc_chip_set_segment(struct aspeed_smc_chip *chip)
if (chip->cs) {
u32 prev = readl(SEGMENT_ADDR_REG(controller, chip->cs - 1));
- start = SEGMENT_ADDR_END(prev);
+ start = controller->info->segment_end(controller, prev);
} else {
start = ahb_base_phy;
}
@@ -702,10 +927,258 @@ static int aspeed_smc_chip_setup_init(struct aspeed_smc_chip *chip,
return 0;
}
+
+#define CALIBRATE_BUF_SIZE 16384
+
+static bool aspeed_smc_check_reads(struct aspeed_smc_chip *chip,
+ const u8 *golden_buf, u8 *test_buf)
+{
+ int i;
+
+ for (i = 0; i < 10; i++) {
+ memcpy_fromio(test_buf, chip->ahb_base, CALIBRATE_BUF_SIZE);
+ if (memcmp(test_buf, golden_buf, CALIBRATE_BUF_SIZE) != 0)
+ return false;
+ }
+ return true;
+}
+
+static int aspeed_smc_calibrate_reads(struct aspeed_smc_chip *chip, u32 hdiv,
+ const u8 *golden_buf, u8 *test_buf)
+{
+ struct aspeed_smc_controller *controller = chip->controller;
+ const struct aspeed_smc_info *info = controller->info;
+ int i;
+ int good_pass = -1, pass_count = 0;
+ u32 shift = (hdiv - 1) << 2;
+ u32 mask = ~(0xfu << shift);
+ u32 fread_timing_val = 0;
+
+#define FREAD_TPASS(i) (((i) / 2) | (((i) & 1) ? 0 : 8))
+
+ /* Try HCLK delay 0..5, each one with/without delay and look for a
+ * good pair.
+ */
+ for (i = 0; i < 12; i++) {
+ bool pass;
+
+ fread_timing_val &= mask;
+ fread_timing_val |= FREAD_TPASS(i) << shift;
+
+ writel(fread_timing_val, controller->regs + info->timing);
+ pass = aspeed_smc_check_reads(chip, golden_buf, test_buf);
+ dev_dbg(chip->nor.dev,
+ " * [%08x] %d HCLK delay, %dns DI delay : %s",
+ fread_timing_val, i/2, (i & 1) ? 0 : 4,
+ pass ? "PASS" : "FAIL");
+ if (pass) {
+ pass_count++;
+ if (pass_count == 3) {
+ good_pass = i - 1;
+ break;
+ }
+ } else
+ pass_count = 0;
+ }
+
+ /* No good setting for this frequency */
+ if (good_pass < 0)
+ return -1;
+
+ /* We have at least one pass of margin, let's use first pass */
+ fread_timing_val &= mask;
+ fread_timing_val |= FREAD_TPASS(good_pass) << shift;
+ writel(fread_timing_val, controller->regs + info->timing);
+ dev_dbg(chip->nor.dev, " * -> good is pass %d [0x%08x]",
+ good_pass, fread_timing_val);
+ return 0;
+}
+
+static bool aspeed_smc_check_calib_data(const u8 *test_buf, u32 size)
+{
+ const u32 *tb32 = (const u32 *) test_buf;
+ u32 i, cnt = 0;
+
+ /* We check if we have enough words that are neither all 0
+ * nor all 1's so the calibration can be considered valid.
+ *
+ * I use an arbitrary threshold for now of 64
+ */
+ size >>= 2;
+ for (i = 0; i < size; i++) {
+ if (tb32[i] != 0 && tb32[i] != 0xffffffff)
+ cnt++;
+ }
+ return cnt >= 64;
+}
+
+static const uint32_t aspeed_smc_hclk_divs[] = {
+ 0xf, /* HCLK */
+ 0x7, /* HCLK/2 */
+ 0xe, /* HCLK/3 */
+ 0x6, /* HCLK/4 */
+ 0xd, /* HCLK/5 */
+};
+#define ASPEED_SMC_HCLK_DIV(i) \
+ (aspeed_smc_hclk_divs[(i) - 1] << CONTROL_CLOCK_FREQ_SEL_SHIFT)
+
+static u32 aspeed_smc_default_read(struct aspeed_smc_chip *chip)
+{
+ /*
+ * Keep the 4Byte address mode on the AST2400 SPI controller.
+ * Other controllers set the 4Byte mode in the CE Control
+ * Register
+ */
+ u32 ctl_mask = chip->controller->info == &spi_2400_info ?
+ CONTROL_IO_ADDRESS_4B : 0;
+ u8 cmd = chip->nor.flags & SNOR_F_4B_OPCODES ? SPINOR_OP_READ_4B :
+ SPINOR_OP_READ;
+
+ /*
+ * Use the "read command" mode to customize the opcode. In
+ * normal command mode, the value is necessarily READ (0x3) on
+ * the AST2400/2500 SoCs.
+ */
+ return (chip->ctl_val[smc_read] & ctl_mask) |
+ (0x00 << 28) | /* Single bit */
+ (0x00 << 24) | /* CE# max */
+ (cmd << 16) | /* use read mode to support 4B opcode */
+ (0x00 << 8) | /* HCLK/16 */
+ (0x00 << 6) | /* no dummy cycle */
+ (0x01); /* read mode */
+}
+
+static int aspeed_smc_optimize_read(struct aspeed_smc_chip *chip,
+ u32 max_freq)
+{
+ struct aspeed_smc_controller *controller = chip->controller;
+ const struct aspeed_smc_info *info = controller->info;
+ u8 *golden_buf, *test_buf;
+ int i, rc, best_div = -1;
+ u32 save_read_val = chip->ctl_val[smc_read];
+ u32 ahb_freq = chip->controller->clk_frequency;
+
+ dev_dbg(chip->nor.dev, "AHB frequency: %d MHz", ahb_freq / 1000000);
+
+ test_buf = kmalloc(CALIBRATE_BUF_SIZE * 2, GFP_KERNEL);
+ golden_buf = test_buf + CALIBRATE_BUF_SIZE;
+
+ /* We start with the dumbest setting (keep 4Byte bit) and read
+ * some data
+ */
+ chip->ctl_val[smc_read] = aspeed_smc_default_read(chip);
+
+ writel(chip->ctl_val[smc_read], chip->ctl);
+
+ memcpy_fromio(golden_buf, chip->ahb_base, CALIBRATE_BUF_SIZE);
+
+ /* Establish our read mode with freq field set to 0 (HCLK/16) */
+ chip->ctl_val[smc_read] = save_read_val & info->hclk_mask;
+
+ /* Check if calibration data is suitable */
+ if (!aspeed_smc_check_calib_data(golden_buf, CALIBRATE_BUF_SIZE)) {
+ dev_info(chip->nor.dev,
+ "Calibration area too uniform, using low speed");
+ writel(chip->ctl_val[smc_read], chip->ctl);
+ kfree(test_buf);
+ return 0;
+ }
+
+ /* Now we iterate the HCLK dividers until we find our breaking point */
+ for (i = ARRAY_SIZE(aspeed_smc_hclk_divs); i > info->hdiv_max - 1; i--) {
+ u32 tv, freq;
+
+ /* Compare timing to max */
+ freq = ahb_freq / i;
+ if (freq > max_freq)
+ continue;
+
+ /* Set the timing */
+ tv = chip->ctl_val[smc_read] | ASPEED_SMC_HCLK_DIV(i);
+ writel(tv, chip->ctl);
+ dev_dbg(chip->nor.dev, "Trying HCLK/%d [%08x] ...", i, tv);
+ rc = info->calibrate(chip, i, golden_buf, test_buf);
+ if (rc == 0)
+ best_div = i;
+ }
+ kfree(test_buf);
+
+ /* Nothing found ? */
+ if (best_div < 0)
+ dev_warn(chip->nor.dev, "No good frequency, using dumb slow");
+ else {
+ dev_dbg(chip->nor.dev, "Found good read timings at HCLK/%d",
+ best_div);
+ chip->ctl_val[smc_read] |= ASPEED_SMC_HCLK_DIV(best_div);
+ }
+
+ writel(chip->ctl_val[smc_read], chip->ctl);
+ return 0;
+}
+
+#define TIMING_DELAY_DI BIT(3)
+#define TIMING_DELAY_HCYCLE_MAX 5
+#define TIMING_REG_AST2600(chip) \
+ ((chip)->controller->regs + (chip)->controller->info->timing + \
+ (chip)->cs * 4)
+
+static int aspeed_smc_calibrate_reads_ast2600(struct aspeed_smc_chip *chip, u32 hdiv,
+ const u8 *golden_buf, u8 *test_buf)
+{
+ int hcycle;
+ u32 shift = (hdiv - 2) << 3;
+ u32 mask = ~(0xfu << shift);
+ u32 fread_timing_val = 0;
+
+ for (hcycle = 0; hcycle <= TIMING_DELAY_HCYCLE_MAX; hcycle++) {
+ int delay_ns;
+ bool pass = false;
+
+ fread_timing_val &= mask;
+ fread_timing_val |= hcycle << shift;
+
+ /* no DI input delay first */
+ writel(fread_timing_val, TIMING_REG_AST2600(chip));
+ pass = aspeed_smc_check_reads(chip, golden_buf, test_buf);
+ dev_dbg(chip->nor.dev,
+ " * [%08x] %d HCLK delay, DI delay none : %s",
+ fread_timing_val, hcycle, pass ? "PASS" : "FAIL");
+ if (pass)
+ return 0;
+
+ /* Add DI input delays */
+ fread_timing_val &= mask;
+ fread_timing_val |= (TIMING_DELAY_DI | hcycle) << shift;
+
+ for (delay_ns = 0; delay_ns < 0x10; delay_ns++) {
+ fread_timing_val &= ~(0xf << (4 + shift));
+ fread_timing_val |= delay_ns << (4 + shift);
+
+ writel(fread_timing_val, TIMING_REG_AST2600(chip));
+ pass = aspeed_smc_check_reads(chip, golden_buf, test_buf);
+ dev_dbg(chip->nor.dev,
+ " * [%08x] %d HCLK delay, DI delay %d.%dns : %s",
+ fread_timing_val, hcycle, (delay_ns + 1)/2,
+ (delay_ns + 1) & 1 ? 5 : 5, pass ? "PASS" : "FAIL");
+ /*
+ * TODO: This is optimistic. We should look
+ * for a working interval and save the middle
+ * value in the read timing register.
+ */
+ if (pass)
+ return 0;
+ }
+ }
+
+ /* No good setting for this frequency */
+ return -1;
+}
+
static int aspeed_smc_chip_setup_finish(struct aspeed_smc_chip *chip)
{
struct aspeed_smc_controller *controller = chip->controller;
const struct aspeed_smc_info *info = controller->info;
+ int io_mode;
u32 cmd;
if (chip->nor.addr_width == 4 && info->set_4b)
@@ -728,21 +1201,24 @@ static int aspeed_smc_chip_setup_finish(struct aspeed_smc_chip *chip)
* TODO: Adjust clocks if fast read is supported and interpret
* SPI-NOR flags to adjust controller settings.
*/
- if (chip->nor.read_proto == SNOR_PROTO_1_1_1) {
- if (chip->nor.read_dummy == 0)
- cmd = CONTROL_COMMAND_MODE_NORMAL;
- else
- cmd = CONTROL_COMMAND_MODE_FREAD;
- } else {
- dev_err(chip->nor.dev, "unsupported SPI read mode\n");
- return -EINVAL;
- }
+ io_mode = aspeed_smc_get_io_mode(chip);
+ if (io_mode < 0)
+ return io_mode;
+
+ if (chip->nor.read_dummy == 0)
+ cmd = CONTROL_COMMAND_MODE_NORMAL;
+ else
+ cmd = CONTROL_COMMAND_MODE_FREAD;
- chip->ctl_val[smc_read] |= cmd |
+ chip->ctl_val[smc_read] |= cmd | io_mode |
+ chip->nor.read_opcode << CONTROL_COMMAND_SHIFT |
CONTROL_IO_DUMMY_SET(chip->nor.read_dummy / 8);
- dev_dbg(controller->dev, "base control register: %08x\n",
+ dev_info(controller->dev, "read control register: %08x\n",
chip->ctl_val[smc_read]);
+
+ if (optimize_read && info->optimize_read)
+ info->optimize_read(chip, chip->clk_rate);
return 0;
}
@@ -752,6 +1228,7 @@ static int aspeed_smc_setup_flash(struct aspeed_smc_controller *controller,
const struct spi_nor_hwcaps hwcaps = {
.mask = SNOR_HWCAPS_READ |
SNOR_HWCAPS_READ_FAST |
+ SNOR_HWCAPS_READ_1_1_2 |
SNOR_HWCAPS_PP,
};
const struct aspeed_smc_info *info = controller->info;
@@ -795,6 +1272,13 @@ static int aspeed_smc_setup_flash(struct aspeed_smc_controller *controller,
break;
}
+ if (of_property_read_u32(child, "spi-max-frequency",
+ &chip->clk_rate)) {
+ chip->clk_rate = ASPEED_SPI_DEFAULT_FREQ;
+ }
+ dev_info(dev, "Using %d MHz SPI frequency\n",
+ chip->clk_rate / 1000000);
+
chip->controller = controller;
chip->ctl = controller->regs + info->ctl0 + cs * 4;
chip->cs = cs;
@@ -805,7 +1289,7 @@ static int aspeed_smc_setup_flash(struct aspeed_smc_controller *controller,
nor->dev = dev;
nor->priv = chip;
spi_nor_set_flash_node(nor, child);
- nor->read = aspeed_smc_read_user;
+ nor->read = aspeed_smc_read;
nor->write = aspeed_smc_write_user;
nor->read_reg = aspeed_smc_read_reg;
nor->write_reg = aspeed_smc_write_reg;
@@ -851,6 +1335,7 @@ static int aspeed_smc_probe(struct platform_device *pdev)
struct aspeed_smc_controller *controller;
const struct of_device_id *match;
const struct aspeed_smc_info *info;
+ struct clk *clk;
struct resource *res;
int ret;
@@ -876,12 +1361,19 @@ static int aspeed_smc_probe(struct platform_device *pdev)
return PTR_ERR(controller->regs);
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ controller->ahb_base_phy = res->start;
controller->ahb_base = devm_ioremap_resource(dev, res);
if (IS_ERR(controller->ahb_base))
return PTR_ERR(controller->ahb_base);
controller->ahb_window_size = resource_size(res);
+ clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+ controller->clk_frequency = clk_get_rate(clk);
+ devm_clk_put(&pdev->dev, clk);
+
ret = aspeed_smc_setup_flash(controller, np, res);
if (ret)
dev_err(dev, "Aspeed SMC probe failed %d\n", ret);
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index f417fb680cd8..3668a862d37d 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -2294,7 +2294,7 @@ static const struct flash_info spi_nor_ids[] = {
{ "mx25v8035f", INFO(0xc22314, 0, 64 * 1024, 16,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
- { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
+ { "mx66l51235f", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "mx66u51235f", INFO(0xc2253a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
{ "mx66l1g45g", INFO(0xc2201b, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "mx66l1g55g", INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) },
@@ -2483,6 +2483,8 @@ static const struct flash_info spi_nor_ids[] = {
{ "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "w25q256jvm", INFO(0xef7019, 0, 64 * 1024, 512,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ { "w25q512jv", INFO(0xef4020, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+ SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) },
{ "w25m512jv", INFO(0xef7119, 0, 64 * 1024, 1024,
SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_DUAL_READ) },
diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index e8e9c166185d..751896c8c5f9 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -140,6 +140,7 @@ source "drivers/net/ethernet/neterion/Kconfig"
source "drivers/net/ethernet/netronome/Kconfig"
source "drivers/net/ethernet/ni/Kconfig"
source "drivers/net/ethernet/8390/Kconfig"
+source "drivers/net/ethernet/nuvoton/Kconfig"
source "drivers/net/ethernet/nvidia/Kconfig"
source "drivers/net/ethernet/nxp/Kconfig"
source "drivers/net/ethernet/oki-semi/Kconfig"
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
index 05abebc17804..62c59123f0ba 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -64,6 +64,7 @@ obj-$(CONFIG_NET_VENDOR_NATSEMI) += natsemi/
obj-$(CONFIG_NET_VENDOR_NETERION) += neterion/
obj-$(CONFIG_NET_VENDOR_NETRONOME) += netronome/
obj-$(CONFIG_NET_VENDOR_NI) += ni/
+obj-$(CONFIG_NET_VENDOR_NUVOTON) += nuvoton/
obj-$(CONFIG_NET_VENDOR_NVIDIA) += nvidia/
obj-$(CONFIG_LPC_ENET) += nxp/
obj-$(CONFIG_NET_VENDOR_OKI) += oki-semi/
diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c
index 96e9565f1e08..2e5fba354412 100644
--- a/drivers/net/ethernet/faraday/ftgmac100.c
+++ b/drivers/net/ethernet/faraday/ftgmac100.c
@@ -90,6 +90,9 @@ struct ftgmac100 {
struct mii_bus *mii_bus;
struct clk *clk;
+ /* 2600 RMII clock gate */
+ struct clk *rclk;
+
/* Link management */
int cur_speed;
int cur_duplex;
@@ -1717,12 +1720,14 @@ static void ftgmac100_ncsi_handler(struct ncsi_dev *nd)
nd->link_up ? "up" : "down");
}
-static void ftgmac100_setup_clk(struct ftgmac100 *priv)
+static int ftgmac100_setup_clk(struct ftgmac100 *priv)
{
- priv->clk = devm_clk_get(priv->dev, NULL);
- if (IS_ERR(priv->clk))
- return;
+ struct clk *clk;
+ clk = devm_clk_get(priv->dev, NULL /* MACCLK */);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+ priv->clk = clk;
clk_prepare_enable(priv->clk);
/* Aspeed specifies a 100MHz clock is required for up to
@@ -1731,6 +1736,14 @@ static void ftgmac100_setup_clk(struct ftgmac100 *priv)
*/
clk_set_rate(priv->clk, priv->use_ncsi ? FTGMAC_25MHZ :
FTGMAC_100MHZ);
+
+ /* RCLK is for RMII, typically used for NCSI. Optional because its not
+ * necessary if it's the 2400 MAC or the MAC is configured for RGMII
+ */
+ priv->rclk = devm_clk_get_optional(priv->dev, "RCLK");
+ clk_prepare_enable(priv->rclk);
+
+ return 0;
}
static int ftgmac100_probe(struct platform_device *pdev)
@@ -1852,8 +1865,11 @@ static int ftgmac100_probe(struct platform_device *pdev)
goto err_setup_mdio;
}
- if (priv->is_aspeed)
- ftgmac100_setup_clk(priv);
+ if (priv->is_aspeed) {
+ err = ftgmac100_setup_clk(priv);
+ if (err)
+ goto err_ncsi_dev;
+ }
/* Default ring sizes */
priv->rx_q_entries = priv->new_rx_q_entries = DEF_RX_QUEUE_ENTRIES;
@@ -1885,8 +1901,11 @@ static int ftgmac100_probe(struct platform_device *pdev)
return 0;
-err_ncsi_dev:
err_register_netdev:
+ if (priv->rclk)
+ clk_disable_unprepare(priv->rclk);
+ clk_disable_unprepare(priv->clk);
+err_ncsi_dev:
ftgmac100_destroy_mdio(netdev);
err_setup_mdio:
iounmap(priv->base);
@@ -1908,6 +1927,8 @@ static int ftgmac100_remove(struct platform_device *pdev)
unregister_netdev(netdev);
+ if (priv->rclk)
+ clk_disable_unprepare(priv->rclk);
clk_disable_unprepare(priv->clk);
/* There's a small chance the reset task will have been re-queued,
diff --git a/drivers/net/ethernet/nuvoton/Kconfig b/drivers/net/ethernet/nuvoton/Kconfig
new file mode 100644
index 000000000000..e79af5f0ba3c
--- /dev/null
+++ b/drivers/net/ethernet/nuvoton/Kconfig
@@ -0,0 +1,30 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Nuvoton network device configuration
+#
+
+config NET_VENDOR_NUVOTON
+ bool "Nuvoton devices"
+ default y
+ depends on ARM && (ARCH_W90X900 || ARCH_NPCM7XX)
+ help
+ If you have a network (Ethernet) card belonging to this class, say Y.
+
+if NET_VENDOR_NUVOTON
+
+config NPCM7XX_EMC_ETH
+ bool "Nuvoton NPCM7XX Ethernet EMC"
+ depends on ARM && ARCH_NPCM7XX
+ select PHYLIB
+ select MII
+ help
+ Say Y here if you want to use built-in Ethernet MAC
+ on NPCM750 MCU.
+
+config NPCM7XX_EMC_ETH_DEBUG
+ bool "Nuvoton NPCM7XX Ethernet EMC debug"
+ depends on NPCM7XX_EMC_ETH
+ help
+ Say Y here if you want debug info via /proc/driver/npcm7xx_emc.x
+
+endif # NET_VENDOR_NUVOTON
diff --git a/drivers/net/ethernet/nuvoton/Makefile b/drivers/net/ethernet/nuvoton/Makefile
new file mode 100644
index 000000000000..3811daa84be8
--- /dev/null
+++ b/drivers/net/ethernet/nuvoton/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Makefile for the Nuvoton network device drivers.
+#
+
+obj-$(CONFIG_NPCM7XX_EMC_ETH) += npcm7xx_emc.o
diff --git a/drivers/net/ethernet/nuvoton/npcm7xx_emc.c b/drivers/net/ethernet/nuvoton/npcm7xx_emc.c
new file mode 100644
index 000000000000..efb441d511c5
--- /dev/null
+++ b/drivers/net/ethernet/nuvoton/npcm7xx_emc.c
@@ -0,0 +1,2091 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2014-2019 Nuvoton Technology corporation.
+
+#ifdef CONFIG_NPCM7XX_EMC_ETH_DEBUG
+#define DEBUG
+#endif
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/ethtool.h>
+#include <linux/platform_device.h>
+#include <linux/gfp.h>
+#include <linux/kthread.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/ctype.h>
+#include <linux/debugfs.h>
+
+#include <linux/clk.h>
+
+#include <linux/of.h>
+#include <linux/of_net.h>
+#include <linux/of_device.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+#include <linux/if_ether.h>
+
+#include <net/ip.h>
+#include <net/ncsi.h>
+
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *npcm7xx_fs_dir;
+#endif
+
+#define MFSEL1_OFFSET 0x00C
+#define MFSEL3_OFFSET 0x064
+#define INTCR_OFFSET 0x03C
+
+#define IPSRST1_OFFSET 0x020
+
+#define DRV_MODULE_NAME "npcm7xx-emc"
+#define DRV_MODULE_VERSION "3.90"
+
+/* Ethernet MAC Registers */
+#define REG_CAMCMR 0x00
+#define REG_CAMEN 0x04
+#define REG_CAMM_BASE 0x08
+#define REG_CAML_BASE 0x0c
+#define REG_TXDLSA 0x88
+#define REG_RXDLSA 0x8C
+#define REG_MCMDR 0x90
+#define REG_MIID 0x94
+#define REG_MIIDA 0x98
+#define REG_FFTCR 0x9C
+#define REG_TSDR 0xa0
+#define REG_RSDR 0xa4
+#define REG_DMARFC 0xa8
+#define REG_MIEN 0xac
+#define REG_MISTA 0xb0
+#define REG_MGSTA 0xb4
+#define REG_MPCNT 0xb8
+#define REG_MRPC 0xbc
+#define REG_MRPCC 0xc0
+#define REG_MREPC 0xc4
+#define REG_DMARFS 0xc8
+#define REG_CTXDSA 0xcc
+#define REG_CTXBSA 0xd0
+#define REG_CRXDSA 0xd4
+#define REG_CRXBSA 0xd8
+
+/* EMC Diagnostic Registers */
+#define REG_RXFSM 0x200
+#define REG_TXFSM 0x204
+#define REG_FSM0 0x208
+#define REG_FSM1 0x20c
+#define REG_DCR 0x210
+#define REG_DMMIR 0x214
+#define REG_BISTR 0x300
+
+/* mac controller bit */
+#define MCMDR_RXON BIT(0)
+#define MCMDR_ALP BIT(1)
+#define MCMDR_ACP BIT(3)
+#define MCMDR_SPCRC BIT(5)
+#define MCMDR_TXON BIT(8)
+#define MCMDR_NDEF BIT(9)
+#define MCMDR_FDUP BIT(18)
+#define MCMDR_ENMDC BIT(19)
+#define MCMDR_OPMOD BIT(20)
+#define SWR BIT(24)
+
+/* cam command regiser */
+#define CAMCMR_AUP BIT(0)
+#define CAMCMR_AMP BIT(1)
+#define CAMCMR_ABP BIT(2)
+#define CAMCMR_CCAM BIT(3)
+#define CAMCMR_ECMP BIT(4)
+
+/* cam enable regiser */
+#define CAM0EN BIT(0)
+
+/* mac mii controller bit */
+#define PHYAD BIT(8)
+#define PHYWR BIT(16)
+#define PHYBUSY BIT(17)
+#define PHYPRESP BIT(18)
+#define MDCON BIT(19)
+#define CAM_ENTRY_SIZE 0x08
+
+/* rx and tx status */
+#define TXDS_TXCP BIT(19)
+#define RXDS_CRCE BIT(17)
+#define RXDS_PTLE BIT(19)
+#define RXDS_RXGD BIT(20)
+#define RXDS_ALIE BIT(21)
+#define RXDS_RP BIT(22)
+
+/* mac interrupt status*/
+#define MISTA_RXINTR BIT(0)
+#define MISTA_CRCE BIT(1)
+#define MISTA_RXOV BIT(2)
+#define MISTA_PTLE BIT(3)
+#define MISTA_RXGD BIT(4)
+#define MISTA_ALIE BIT(5)
+#define MISTA_RP BIT(6)
+#define MISTA_MMP BIT(7)
+#define MISTA_DFOI BIT(8)
+#define MISTA_DENI BIT(9)
+#define MISTA_RDU BIT(10)
+#define MISTA_RXBERR BIT(11)
+#define MISTA_CFR BIT(14)
+#define MISTA_TXINTR BIT(16)
+#define MISTA_TXEMP BIT(17)
+#define MISTA_TXCP BIT(18)
+#define MISTA_EXDEF BIT(19)
+#define MISTA_NCS BIT(20)
+#define MISTA_TXABT BIT(21)
+#define MISTA_LC BIT(22)
+#define MISTA_TDU BIT(23)
+#define MISTA_TXBERR BIT(24)
+
+/* Transmit/Receive Start Demand Register */
+#define ENSTART BIT(0)
+
+#define ENRXINTR BIT(0)
+#define ENCRCE BIT(1)
+#define EMRXOV BIT(2)
+#define ENPTLE BIT(3)
+#define ENRXGD BIT(4)
+#define ENALIE BIT(5)
+#define ENRP BIT(6)
+#define ENMMP BIT(7)
+#define ENDFO BIT(8)
+#define ENDENI BIT(9)
+#define ENRDU BIT(10)
+#define ENRXBERR BIT(11)
+#define ENCFR BIT(14)
+#define ENTXINTR BIT(16)
+#define ENTXEMP BIT(17)
+#define ENTXCP BIT(18)
+#define ENTXDEF BIT(19)
+#define ENNCS BIT(20)
+#define ENTXABT BIT(21)
+#define ENLC BIT(22)
+#define ENTDU BIT(23)
+#define ENTXBERR BIT(24)
+
+/* rx and tx owner bit */
+#define RX_OWN_DMA BIT(31)
+#define TX_OWN_DMA BIT(31)
+
+/* tx frame desc controller bit */
+#define MACTXINTEN BIT(2)
+#define CRCMODE BIT(1)
+#define PADDINGMODE BIT(0)
+
+/* fftcr controller bit */
+#define RXTHD (0x03 << 0)
+#define TXTHD (0x02 << 8)
+#define BLENGTH (0x02 << 20)
+
+/* global setting for driver */
+#define RX_QUEUE_LEN 128
+#define TX_QUEUE_LEN 64
+#define MAX_RBUFF_SZ 0x600
+#define MAX_TBUFF_SZ 0x600
+#define TX_TIMEOUT 50
+#define DELAY 1000
+#define CAM0 0x0
+#define RX_POLL_SIZE 16
+
+#ifdef CONFIG_VLAN_8021Q
+#define IS_VLAN 1
+#else
+#define IS_VLAN 0
+#endif
+
+#define MAX_PACKET_SIZE (1514 + (IS_VLAN * 4))
+#define MAX_PACKET_SIZE_W_CRC (MAX_PACKET_SIZE + 4) /* 1518 */
+
+#define MHZ (1000 * 1000)
+#define MII_TIMEOUT 100
+
+struct plat_npcm7xx_emc_data {
+ char *phy_bus_name;
+ int phy_addr;
+ unsigned char mac_addr[ETH_ALEN];
+};
+
+struct npcm7xx_rxbd {
+ __le32 sl;
+ __le32 buffer;
+ __le32 reserved;
+ __le32 next;
+};
+
+struct npcm7xx_txbd {
+ __le32 mode; /* Ownership bit and some other bits */
+ __le32 buffer; /* Transmit Buffer Starting Address */
+ __le32 sl; /* Transmit Byte Count and status bits */
+ __le32 next; /* Next Tx Descriptor Starting Address */
+};
+
+struct npcm7xx_ether {
+ struct sk_buff *rx_skb[RX_QUEUE_LEN];
+ struct sk_buff *tx_skb[TX_QUEUE_LEN];
+ spinlock_t lock; /* lock sk */
+ struct npcm7xx_rxbd *rdesc;
+ struct npcm7xx_txbd *tdesc;
+ dma_addr_t rdesc_phys;
+ dma_addr_t tdesc_phys;
+ struct net_device_stats stats;
+ struct platform_device *pdev;
+ struct net_device *ndev;
+ struct resource *res;
+ unsigned int msg_enable;
+ struct mii_bus *mii_bus;
+ struct phy_device *phy_dev;
+ struct napi_struct napi;
+ struct ncsi_dev *ncsidev;
+ bool use_ncsi;
+ void __iomem *reg;
+ int rxirq;
+ int txirq;
+ unsigned int cur_tx;
+ unsigned int cur_rx;
+ unsigned int finish_tx;
+ unsigned int pending_tx;
+ __le32 start_tx_ptr;
+ __le32 start_rx_ptr;
+ unsigned int rx_berr;
+ unsigned int rx_err;
+ unsigned int rdu;
+ unsigned int rxov;
+ __le32 camcmr;
+ unsigned int rx_stuck;
+ int link;
+ int speed;
+ int duplex;
+ int need_reset;
+ char *dump_buf;
+ struct regmap *rst_regmap;
+
+ /* debug counters */
+ unsigned int max_waiting_rx;
+ unsigned int rx_count_pool;
+ unsigned int count_xmit;
+ unsigned int rx_int_count;
+ unsigned int rx_err_count;
+ unsigned int tx_int_count;
+ unsigned int tx_tdu;
+ unsigned int tx_tdu_i;
+ unsigned int tx_cp_i;
+ unsigned int count_finish;
+
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *dbgfs_dir;
+ struct dentry *dbgfs_status;
+ struct dentry *dbgfs_dma_cap;
+#endif
+};
+
+#if defined CONFIG_NPCM7XX_EMC_ETH_DEBUG || defined CONFIG_DEBUG_FS
+#define REG_PRINT(reg_name) {t = scnprintf(next, size, "%-10s = %08X\n", \
+ #reg_name, readl(ether->reg + reg_name)); size -= t; next += t; }
+#define DUMP_PRINT(f, x...) {t = scnprintf(next, size, f, ## x); size -= t; \
+ next += t; }
+
+static int npcm7xx_info_dump(char *buf, int count, struct net_device *dev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(dev);
+ struct npcm7xx_txbd *txbd;
+ struct npcm7xx_rxbd *rxbd;
+ unsigned long flags;
+ unsigned int i, cur, txd_offset, rxd_offset;
+ char *next = buf;
+ unsigned int size = count;
+ int t;
+ int is_locked = spin_is_locked(&ether->lock);
+
+ if (!is_locked)
+ spin_lock_irqsave(&ether->lock, flags);
+
+ /* ------basic driver information ---- */
+ DUMP_PRINT("NPCM7XX EMC %s driver version: %s\n", dev->name,
+ DRV_MODULE_VERSION);
+
+ REG_PRINT(REG_CAMCMR);
+ REG_PRINT(REG_CAMEN);
+ REG_PRINT(REG_CAMM_BASE);
+ REG_PRINT(REG_CAML_BASE);
+ REG_PRINT(REG_TXDLSA);
+ REG_PRINT(REG_RXDLSA);
+ REG_PRINT(REG_MCMDR);
+ REG_PRINT(REG_MIID);
+ REG_PRINT(REG_MIIDA);
+ REG_PRINT(REG_FFTCR);
+ REG_PRINT(REG_TSDR);
+ REG_PRINT(REG_RSDR);
+ REG_PRINT(REG_DMARFC);
+ REG_PRINT(REG_MIEN);
+ REG_PRINT(REG_MISTA);
+ REG_PRINT(REG_MGSTA);
+ REG_PRINT(REG_MPCNT);
+ writel(0x7FFF, (ether->reg + REG_MPCNT));
+ REG_PRINT(REG_MRPC);
+ REG_PRINT(REG_MRPCC);
+ REG_PRINT(REG_MREPC);
+ REG_PRINT(REG_DMARFS);
+ REG_PRINT(REG_CTXDSA);
+ REG_PRINT(REG_CTXBSA);
+ REG_PRINT(REG_CRXDSA);
+ REG_PRINT(REG_CRXBSA);
+ REG_PRINT(REG_RXFSM);
+ REG_PRINT(REG_TXFSM);
+ REG_PRINT(REG_FSM0);
+ REG_PRINT(REG_FSM1);
+ REG_PRINT(REG_DCR);
+ REG_PRINT(REG_DMMIR);
+ REG_PRINT(REG_BISTR);
+ DUMP_PRINT("\n");
+
+ DUMP_PRINT("netif_queue %s\n\n", netif_queue_stopped(dev) ?
+ "Stopped" : "Running");
+ if (ether->rdesc)
+ DUMP_PRINT("napi is %s\n\n", test_bit(NAPI_STATE_SCHED,
+ &ether->napi.state) ?
+ "scheduled" :
+ "not scheduled");
+
+ txd_offset = (readl((ether->reg + REG_CTXDSA)) -
+ readl((ether->reg + REG_TXDLSA))) /
+ sizeof(struct npcm7xx_txbd);
+ DUMP_PRINT("TXD offset %6d\n", txd_offset);
+ DUMP_PRINT("cur_tx %6d\n", ether->cur_tx);
+ DUMP_PRINT("finish_tx %6d\n", ether->finish_tx);
+ DUMP_PRINT("pending_tx %6d\n", ether->pending_tx);
+ /* debug counters */
+ DUMP_PRINT("tx_tdu %6d\n", ether->tx_tdu);
+ ether->tx_tdu = 0;
+ DUMP_PRINT("tx_tdu_i %6d\n", ether->tx_tdu_i);
+ ether->tx_tdu_i = 0;
+ DUMP_PRINT("tx_cp_i %6d\n", ether->tx_cp_i);
+ ether->tx_cp_i = 0;
+ DUMP_PRINT("tx_int_count %6d\n", ether->tx_int_count);
+ ether->tx_int_count = 0;
+ DUMP_PRINT("count_xmit tx %6d\n", ether->count_xmit);
+ ether->count_xmit = 0;
+ DUMP_PRINT("count_finish %6d\n", ether->count_finish);
+ ether->count_finish = 0;
+ DUMP_PRINT("\n");
+
+ rxd_offset = (readl((ether->reg + REG_CRXDSA)) -
+ readl((ether->reg + REG_RXDLSA)))
+ / sizeof(struct npcm7xx_txbd);
+ DUMP_PRINT("RXD offset %6d\n", rxd_offset);
+ DUMP_PRINT("cur_rx %6d\n", ether->cur_rx);
+ DUMP_PRINT("rx_err %6d\n", ether->rx_err);
+ ether->rx_err = 0;
+ DUMP_PRINT("rx_berr %6d\n", ether->rx_berr);
+ ether->rx_berr = 0;
+ DUMP_PRINT("rx_stuck %6d\n", ether->rx_stuck);
+ ether->rx_stuck = 0;
+ DUMP_PRINT("rdu %6d\n", ether->rdu);
+ ether->rdu = 0;
+ DUMP_PRINT("rxov rx %6d\n", ether->rxov);
+ ether->rxov = 0;
+ /* debug counters */
+ DUMP_PRINT("rx_int_count %6d\n", ether->rx_int_count);
+ ether->rx_int_count = 0;
+ DUMP_PRINT("rx_err_count %6d\n", ether->rx_err_count);
+ ether->rx_err_count = 0;
+ DUMP_PRINT("rx_count_pool %6d\n", ether->rx_count_pool);
+ ether->rx_count_pool = 0;
+ DUMP_PRINT("max_waiting_rx %5d\n", ether->max_waiting_rx);
+ ether->max_waiting_rx = 0;
+ DUMP_PRINT("\n");
+ DUMP_PRINT("need_reset %5d\n", ether->need_reset);
+
+ if (ether->tdesc && ether->rdesc) {
+ cur = ether->finish_tx - 2;
+ for (i = 0; i < 3; i++) {
+ cur = (cur + 1) % TX_QUEUE_LEN;
+ txbd = (ether->tdesc + cur);
+ DUMP_PRINT("finish %3d txbd mode %08X buffer %08X sl %08X next %08X tx_skb %p\n",
+ cur, txbd->mode, txbd->buffer,
+ txbd->sl, txbd->next, ether->tx_skb[cur]);
+ }
+ DUMP_PRINT("\n");
+
+ cur = txd_offset - 2;
+ for (i = 0; i < 3; i++) {
+ cur = (cur + 1) % TX_QUEUE_LEN;
+ txbd = (ether->tdesc + cur);
+ DUMP_PRINT("txd_of %3d txbd mode %08X buffer %08X sl %08X next %08X\n",
+ cur, txbd->mode, txbd->buffer,
+ txbd->sl, txbd->next);
+ }
+ DUMP_PRINT("\n");
+
+ cur = ether->cur_tx - 63;
+ for (i = 0; i < 64; i++) {
+ cur = (cur + 1) % TX_QUEUE_LEN;
+ txbd = (ether->tdesc + cur);
+ DUMP_PRINT("cur_tx %3d txbd mode %08X buffer %08X sl %08X next %08X\n",
+ cur, txbd->mode, txbd->buffer,
+ txbd->sl, txbd->next);
+ }
+ DUMP_PRINT("\n");
+
+ cur = ether->cur_rx - 63;
+ for (i = 0; i < 64; i++) {
+ cur = (cur + 1) % RX_QUEUE_LEN;
+ rxbd = (ether->rdesc + cur);
+ DUMP_PRINT("cur_rx %3d rxbd sl %08X buffer %08X sl %08X next %08X\n",
+ cur, rxbd->sl, rxbd->buffer,
+ rxbd->reserved, rxbd->next);
+ }
+ DUMP_PRINT("\n");
+
+ cur = rxd_offset - 2;
+ for (i = 0; i < 3; i++) {
+ cur = (cur + 1) % RX_QUEUE_LEN;
+ rxbd = (ether->rdesc + cur);
+ DUMP_PRINT("rxd_of %3d rxbd sl %08X buffer %08X sl %08X next %08X\n",
+ cur, rxbd->sl, rxbd->buffer,
+ rxbd->reserved, rxbd->next);
+ }
+ DUMP_PRINT("\n");
+ }
+
+ if (!is_locked)
+ spin_unlock_irqrestore(&ether->lock, flags);
+
+ return count - size;
+}
+#endif
+
+#ifdef CONFIG_NPCM7XX_EMC_ETH_DEBUG
+static void npcm7xx_info_print(struct net_device *dev)
+{
+ char *emc_dump_buf;
+ int count;
+ struct npcm7xx_ether *ether;
+ struct platform_device *pdev;
+ const size_t print_size = 5 * PAGE_SIZE;
+
+ ether = netdev_priv(dev);
+ pdev = ether->pdev;
+
+ emc_dump_buf = kmalloc(print_size, GFP_KERNEL);
+ if (!emc_dump_buf) {
+ dev_err(&pdev->dev, "kmalloc failed\n");
+ } else {
+ char c;
+ char *tmp_buf = emc_dump_buf;
+
+ count = npcm7xx_info_dump(emc_dump_buf, print_size, dev);
+ while (count > 512) {
+ c = tmp_buf[512];
+ tmp_buf[512] = 0;
+ dev_info(&pdev->dev, "%s", tmp_buf);
+ tmp_buf += 512;
+ tmp_buf[0] = c;
+ count -= 512;
+ }
+ dev_info(&pdev->dev, "%s", tmp_buf);
+ kfree(emc_dump_buf);
+ }
+}
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/seq_file.h>
+
+static int npcm7xx_debug_show(struct seq_file *sf, void *v)
+{
+ struct net_device *dev = (struct net_device *)sf->private;
+ struct npcm7xx_ether *ether = netdev_priv(dev);
+ const size_t print_size = 5 * PAGE_SIZE;
+
+ if (!ether->dump_buf) {
+ ether->dump_buf = kmalloc(print_size, GFP_KERNEL);
+ if (!ether->dump_buf)
+ return -1;
+ npcm7xx_info_dump(ether->dump_buf, print_size, dev);
+ }
+
+ seq_printf(sf, "%s", ether->dump_buf);
+ if (sf->count < sf->size) {
+ kfree(ether->dump_buf);
+ ether->dump_buf = NULL;
+ }
+
+ return 0;
+}
+
+static int npcm7xx_debug_show_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, npcm7xx_debug_show, inode->i_private);
+}
+
+static const struct file_operations npcm7xx_debug_show_fops = {
+ .open = npcm7xx_debug_show_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int npcm7xx_debug_reset(struct seq_file *sf, void *v)
+{
+ struct net_device *dev = (struct net_device *)sf->private;
+ struct npcm7xx_ether *ether = netdev_priv(dev);
+ unsigned long flags;
+
+ seq_puts(sf, "Ask to reset the module\n");
+ spin_lock_irqsave(&ether->lock, flags);
+ writel(0, (ether->reg + REG_MIEN));
+ spin_unlock_irqrestore(&ether->lock, flags);
+ ether->need_reset = 1;
+ napi_schedule(&ether->napi);
+
+ return 0;
+}
+
+static int npcm7xx_debug_reset_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, npcm7xx_debug_reset, inode->i_private);
+}
+
+static const struct file_operations npcm7xx_debug_reset_fops = {
+ .owner = THIS_MODULE,
+ .open = npcm7xx_debug_reset_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int npcm7xx_debug_fs(struct npcm7xx_ether *ether)
+{
+ /* Create debugfs main directory if it doesn't exist yet */
+ if (!npcm7xx_fs_dir) {
+ npcm7xx_fs_dir = debugfs_create_dir(DRV_MODULE_NAME, NULL);
+
+ if (!npcm7xx_fs_dir || IS_ERR(npcm7xx_fs_dir)) {
+ dev_err(&ether->pdev->dev, "ERROR %s, debugfs create directory failed\n",
+ DRV_MODULE_NAME);
+ return -ENOMEM;
+ }
+ }
+
+ /* Create per netdev entries */
+ ether->dbgfs_dir = debugfs_create_dir(ether->ndev->name,
+ npcm7xx_fs_dir);
+ if (!ether->dbgfs_dir || IS_ERR(ether->dbgfs_dir)) {
+ dev_err(&ether->pdev->dev, "ERROR failed to create %s directory\n", ether->ndev->name);
+ return -ENOMEM;
+ }
+
+ /* Entry to report DMA RX/TX rings */
+ ether->dbgfs_status =
+ debugfs_create_file("status", 0444,
+ ether->dbgfs_dir, ether->ndev,
+ &npcm7xx_debug_show_fops);
+
+ if (!ether->dbgfs_status || IS_ERR(ether->dbgfs_status)) {
+ dev_err(&ether->pdev->dev, "ERROR creating \'status\' debugfs file\n");
+ debugfs_remove_recursive(ether->dbgfs_dir);
+
+ return -ENOMEM;
+ }
+
+ /* Entry to report the DMA HW features */
+ ether->dbgfs_dma_cap = debugfs_create_file("do_reset", 0444,
+ ether->dbgfs_dir,
+ ether->ndev,
+ &npcm7xx_debug_reset_fops);
+
+ if (!ether->dbgfs_dma_cap || IS_ERR(ether->dbgfs_dma_cap)) {
+ dev_err(&ether->pdev->dev, "ERROR creating stmmac \'do_reset\' debugfs file\n");
+ debugfs_remove_recursive(ether->dbgfs_dir);
+
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+#endif
+
+static void npcm7xx_opmode(struct net_device *dev, int speed, int duplex)
+{
+ __le32 val;
+ struct npcm7xx_ether *ether = netdev_priv(dev);
+
+ val = readl((ether->reg + REG_MCMDR));
+ if (speed == 100)
+ val |= MCMDR_OPMOD;
+ else
+ val &= ~MCMDR_OPMOD;
+
+ if (duplex == DUPLEX_FULL)
+ val |= MCMDR_FDUP;
+ else
+ val &= ~MCMDR_FDUP;
+
+ writel(val, (ether->reg + REG_MCMDR));
+}
+
+static void adjust_link(struct net_device *dev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(dev);
+ struct phy_device *phydev = ether->phy_dev;
+ bool status_change = false;
+ unsigned long flags;
+
+ /* clear GPIO interrupt status whihc indicates PHY statu change? */
+ spin_lock_irqsave(&ether->lock, flags);
+
+ if (phydev->link) {
+ if (ether->speed != phydev->speed ||
+ ether->duplex != phydev->duplex) {
+ ether->speed = phydev->speed;
+ ether->duplex = phydev->duplex;
+ status_change = true;
+ }
+ } else {
+ ether->speed = 0;
+ ether->duplex = -1;
+ }
+
+ if (phydev->link != ether->link) {
+ ether->link = phydev->link;
+ status_change = true;
+ }
+
+ spin_unlock_irqrestore(&ether->lock, flags);
+
+ if (status_change)
+ npcm7xx_opmode(dev, ether->speed, ether->duplex);
+}
+
+static void npcm7xx_write_cam(struct net_device *dev,
+ unsigned int x, unsigned char *pval)
+{
+ struct npcm7xx_ether *ether = netdev_priv(dev);
+ __le32 msw, lsw;
+
+ msw = (pval[0] << 24) | (pval[1] << 16) | (pval[2] << 8) | pval[3];
+
+ lsw = (pval[4] << 24) | (pval[5] << 16);
+
+ writel(lsw, (ether->reg + REG_CAML_BASE) + x * CAM_ENTRY_SIZE);
+ writel(msw, (ether->reg + REG_CAMM_BASE) + x * CAM_ENTRY_SIZE);
+ dev_dbg(&ether->pdev->dev, "REG_CAML_BASE = 0x%08X REG_CAMM_BASE = 0x%08X", lsw, msw);
+}
+
+static struct sk_buff *get_new_skb(struct net_device *dev, u32 i)
+{
+ struct npcm7xx_ether *ether = netdev_priv(dev);
+ struct sk_buff *skb = dev_alloc_skb(roundup(MAX_PACKET_SIZE_W_CRC, 4));
+
+ if (!skb)
+ return NULL;
+
+ /* Do not unmark the following skb_reserve() Receive Buffer Starting
+ * Address must be aligned to 4 bytes and the following line
+ * if unmarked will make it align to 2 and this likely will
+ * hult the RX and crash the linux skb_reserve(skb, NET_IP_ALIGN);
+ */
+ skb->dev = dev;
+ (ether->rdesc + i)->buffer =
+ dma_map_single(&dev->dev, skb->data,
+ roundup(MAX_PACKET_SIZE_W_CRC, 4),
+ DMA_FROM_DEVICE);
+ ether->rx_skb[i] = skb;
+
+ return skb;
+}
+
+static int npcm7xx_init_desc(struct net_device *dev)
+{
+ struct npcm7xx_ether *ether;
+ struct npcm7xx_txbd *tdesc;
+ struct npcm7xx_rxbd *rdesc;
+ struct platform_device *pdev;
+ unsigned int i;
+
+ ether = netdev_priv(dev);
+ pdev = ether->pdev;
+
+ if (!ether->tdesc) {
+ ether->tdesc = (struct npcm7xx_txbd *)
+ dma_alloc_coherent(&pdev->dev,
+ sizeof(struct npcm7xx_txbd) *
+ TX_QUEUE_LEN,
+ &ether->tdesc_phys,
+ GFP_KERNEL);
+
+ if (!ether->tdesc) {
+ dev_err(&pdev->dev, "Failed to allocate memory for tx desc\n");
+ return -ENOMEM;
+ }
+ }
+
+ if (!ether->rdesc) {
+ ether->rdesc = (struct npcm7xx_rxbd *)
+ dma_alloc_coherent(&pdev->dev,
+ sizeof(struct npcm7xx_rxbd) *
+ RX_QUEUE_LEN,
+ &ether->rdesc_phys,
+ GFP_KERNEL);
+
+ if (!ether->rdesc) {
+ dev_err(&pdev->dev, "Failed to allocate memory for rx desc\n");
+ dma_free_coherent(&pdev->dev,
+ sizeof(struct npcm7xx_txbd) *
+ TX_QUEUE_LEN, ether->tdesc,
+ ether->tdesc_phys);
+ ether->tdesc = NULL;
+ return -ENOMEM;
+ }
+ }
+
+ for (i = 0; i < TX_QUEUE_LEN; i++) {
+ unsigned int offset;
+
+ tdesc = (ether->tdesc + i);
+
+ if (i == TX_QUEUE_LEN - 1)
+ offset = 0;
+ else
+ offset = sizeof(struct npcm7xx_txbd) * (i + 1);
+
+ tdesc->next = ether->tdesc_phys + offset;
+ tdesc->buffer = (__le32)NULL;
+ tdesc->sl = 0;
+ tdesc->mode = 0;
+ }
+
+ ether->start_tx_ptr = ether->tdesc_phys;
+
+ for (i = 0; i < RX_QUEUE_LEN; i++) {
+ unsigned int offset;
+
+ rdesc = (ether->rdesc + i);
+
+ if (i == RX_QUEUE_LEN - 1)
+ offset = 0;
+ else
+ offset = sizeof(struct npcm7xx_rxbd) * (i + 1);
+
+ rdesc->next = ether->rdesc_phys + offset;
+ rdesc->sl = RX_OWN_DMA;
+
+ if (!get_new_skb(dev, i)) {
+ dev_err(&pdev->dev, "get_new_skb() failed\n");
+
+ for (; i != 0; i--) {
+ dma_unmap_single(&dev->dev, (dma_addr_t)
+ ((ether->rdesc + i)->buffer),
+ roundup(MAX_PACKET_SIZE_W_CRC,
+ 4), DMA_FROM_DEVICE);
+ dev_kfree_skb_any(ether->rx_skb[i]);
+ ether->rx_skb[i] = NULL;
+ }
+
+ dma_free_coherent(&pdev->dev,
+ sizeof(struct npcm7xx_txbd) *
+ TX_QUEUE_LEN,
+ ether->tdesc, ether->tdesc_phys);
+ dma_free_coherent(&pdev->dev,
+ sizeof(struct npcm7xx_rxbd) *
+ RX_QUEUE_LEN,
+ ether->rdesc, ether->rdesc_phys);
+
+ return -ENOMEM;
+ }
+ }
+
+ ether->start_rx_ptr = ether->rdesc_phys;
+ wmb();
+ for (i = 0; i < TX_QUEUE_LEN; i++)
+ ether->tx_skb[i] = NULL;
+
+ return 0;
+}
+
+/* This API must call with Tx/Rx stopped */
+static void npcm7xx_free_desc(struct net_device *dev,
+ bool free_also_descriptors)
+{
+ struct sk_buff *skb;
+ u32 i;
+ struct npcm7xx_ether *ether = netdev_priv(dev);
+ struct platform_device *pdev = ether->pdev;
+
+ for (i = 0; i < TX_QUEUE_LEN; i++) {
+ skb = ether->tx_skb[i];
+ if (skb) {
+ dma_unmap_single(&dev->dev, (dma_addr_t)((ether->tdesc +
+ i)->buffer),
+ skb->len, DMA_TO_DEVICE);
+ dev_kfree_skb_any(skb);
+ ether->tx_skb[i] = NULL;
+ }
+ }
+
+ for (i = 0; i < RX_QUEUE_LEN; i++) {
+ skb = ether->rx_skb[i];
+ if (skb) {
+ dma_unmap_single(&dev->dev, (dma_addr_t)((ether->rdesc +
+ i)->buffer),
+ roundup(MAX_PACKET_SIZE_W_CRC, 4),
+ DMA_FROM_DEVICE);
+ dev_kfree_skb_any(skb);
+ ether->rx_skb[i] = NULL;
+ }
+ }
+
+ if (free_also_descriptors) {
+ if (ether->tdesc)
+ dma_free_coherent(&pdev->dev,
+ sizeof(struct npcm7xx_txbd) *
+ TX_QUEUE_LEN,
+ ether->tdesc, ether->tdesc_phys);
+ ether->tdesc = NULL;
+
+ if (ether->rdesc)
+ dma_free_coherent(&pdev->dev,
+ sizeof(struct npcm7xx_rxbd) *
+ RX_QUEUE_LEN,
+ ether->rdesc, ether->rdesc_phys);
+ ether->rdesc = NULL;
+ }
+}
+
+static void npcm7xx_set_fifo_threshold(struct net_device *dev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(dev);
+ __le32 val;
+
+ val = RXTHD | TXTHD | BLENGTH;
+ writel(val, (ether->reg + REG_FFTCR));
+}
+
+static void npcm7xx_return_default_idle(struct net_device *dev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(dev);
+ __le32 val;
+ __le32 saved_bits;
+
+ val = readl((ether->reg + REG_MCMDR));
+ saved_bits = val & (MCMDR_FDUP | MCMDR_OPMOD);
+ val |= SWR;
+ writel(val, (ether->reg + REG_MCMDR));
+
+ /* During the EMC reset the AHB will read 0 from all registers,
+ * so in order to see if the reset finished we can't count on
+ * (ether->reg + REG_MCMDR).SWR to become 0, instead we read another
+ * register that its reset value is not 0,
+ * we choose (ether->reg + REG_FFTCR).
+ */
+ do {
+ val = readl((ether->reg + REG_FFTCR));
+ } while (val == 0);
+
+ /*
+ * Now we can verify if (ether->reg + REG_MCMDR).SWR became
+ * 0 (probably it will be 0 on the first read).
+ */
+ do {
+ val = readl((ether->reg + REG_MCMDR));
+ } while (val & SWR);
+
+ /* restore values */
+ writel(saved_bits, (ether->reg + REG_MCMDR));
+}
+
+static void npcm7xx_enable_mac_interrupt(struct net_device *dev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(dev);
+ __le32 val;
+
+ val = ENRXINTR | /* Start of RX interrupts */
+ ENCRCE |
+ EMRXOV |
+ (ENPTLE * (!IS_VLAN)) | /* If we don't support VLAN we want interrupt on long packets */
+ ENRXGD |
+ ENALIE |
+ ENRP |
+ ENMMP |
+ ENDFO |
+ /* ENDENI | */ /* We don't need interrupt on DMA Early Notification */
+ ENRDU | /* We don't need interrupt on Receive Descriptor Unavailable Interrupt */
+ ENRXBERR |
+ /* ENCFR | */
+ ENTXINTR | /* Start of TX interrupts */
+ ENTXEMP |
+ ENTXCP |
+ ENTXDEF |
+ ENNCS |
+ ENTXABT |
+ ENLC |
+ /* ENTDU | */ /* We don't need interrupt on Transmit Descriptor Unavailable at start of operation */
+ ENTXBERR;
+ writel(val, (ether->reg + REG_MIEN));
+}
+
+static void npcm7xx_get_and_clear_int(struct net_device *dev,
+ __le32 *val, __le32 mask)
+{
+ struct npcm7xx_ether *ether = netdev_priv(dev);
+
+ *val = readl((ether->reg + REG_MISTA)) & mask;
+ writel(*val, (ether->reg + REG_MISTA));
+}
+
+static void npcm7xx_set_global_maccmd(struct net_device *dev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(dev);
+ __le32 val;
+
+ val = readl((ether->reg + REG_MCMDR));
+
+ val |= MCMDR_SPCRC | MCMDR_ENMDC | MCMDR_ACP | MCMDR_NDEF;
+ if (IS_VLAN) {
+ /*
+ * we set ALP accept long packets since VLAN packets
+ * are 4 bytes longer than 1518
+ */
+ val |= MCMDR_ALP;
+ /* limit receive length to 1522 bytes due to VLAN */
+ writel(MAX_PACKET_SIZE_W_CRC, (ether->reg + REG_DMARFC));
+ }
+ writel(val, (ether->reg + REG_MCMDR));
+}
+
+static void npcm7xx_enable_cam(struct net_device *dev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(dev);
+ __le32 val;
+
+ npcm7xx_write_cam(dev, CAM0, dev->dev_addr);
+
+ val = readl((ether->reg + REG_CAMEN));
+ val |= CAM0EN;
+ writel(val, (ether->reg + REG_CAMEN));
+}
+
+static void npcm7xx_set_curdest(struct net_device *dev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(dev);
+
+ writel(ether->start_rx_ptr, (ether->reg + REG_RXDLSA));
+ writel(ether->start_tx_ptr, (ether->reg + REG_TXDLSA));
+}
+
+static void npcm7xx_ether_set_rx_mode(struct net_device *dev)
+{
+ struct npcm7xx_ether *ether;
+ __le32 rx_mode;
+
+ ether = netdev_priv(dev);
+
+ dev_dbg(&ether->pdev->dev, "%s CAMCMR_AUP\n",
+ (dev->flags & IFF_PROMISC) ? "Set" : "Clear");
+ if (dev->flags & IFF_PROMISC)
+ rx_mode = CAMCMR_AUP | CAMCMR_AMP | CAMCMR_ABP | CAMCMR_ECMP;
+ else if ((dev->flags & IFF_ALLMULTI) || !netdev_mc_empty(dev))
+ rx_mode = CAMCMR_AMP | CAMCMR_ABP | CAMCMR_ECMP;
+ else
+ rx_mode = CAMCMR_ECMP | CAMCMR_ABP;
+ writel(rx_mode, (ether->reg + REG_CAMCMR));
+ ether->camcmr = rx_mode;
+}
+
+static void npcm7xx_reset_mac(struct net_device *dev, int need_free)
+{
+ struct npcm7xx_ether *ether = netdev_priv(dev);
+
+ netif_tx_lock(dev);
+
+ /* disable RX and TX */
+ writel(readl((ether->reg + REG_MCMDR)) & ~(MCMDR_TXON | MCMDR_RXON),
+ (ether->reg + REG_MCMDR));
+
+ npcm7xx_return_default_idle(dev);
+ npcm7xx_set_fifo_threshold(dev);
+
+ if (need_free)
+ npcm7xx_free_desc(dev, false);
+
+ npcm7xx_init_desc(dev);
+
+ ether->cur_tx = 0x0;
+ ether->finish_tx = 0x0;
+ ether->pending_tx = 0x0;
+ ether->cur_rx = 0x0;
+ ether->tx_tdu = 0;
+ ether->tx_tdu_i = 0;
+ ether->tx_cp_i = 0;
+
+ npcm7xx_set_curdest(dev);
+ npcm7xx_enable_cam(dev);
+ npcm7xx_ether_set_rx_mode(dev);
+ npcm7xx_enable_mac_interrupt(dev);
+ npcm7xx_set_global_maccmd(dev);
+
+ /* enable RX and TX */
+ writel(readl((ether->reg + REG_MCMDR)) | MCMDR_TXON | MCMDR_RXON,
+ (ether->reg + REG_MCMDR));
+
+ /* trigger RX */
+ writel(ENSTART, (ether->reg + REG_RSDR));
+
+ ether->need_reset = 0;
+
+ netif_wake_queue(dev);
+ netif_tx_unlock(dev);
+}
+
+static int npcm7xx_mdio_write(struct mii_bus *bus, int phy_id, int regnum,
+ u16 value)
+{
+ struct npcm7xx_ether *ether = bus->priv;
+ unsigned long timeout = jiffies + msecs_to_jiffies(MII_TIMEOUT * 100);
+
+ writel(value, (ether->reg + REG_MIID));
+ writel((phy_id << 0x08) | regnum | PHYBUSY | PHYWR,
+ (ether->reg + REG_MIIDA));
+
+ /* Wait for completion */
+ while (readl((ether->reg + REG_MIIDA)) & PHYBUSY) {
+ if (time_after(jiffies, timeout)) {
+ dev_dbg(&ether->pdev->dev, "mdio read timed out\n ether->reg = 0x%x phy_id=0x%x REG_MIIDA=0x%x\n",
+ (unsigned int)ether->reg, phy_id
+ , readl((ether->reg + REG_MIIDA)));
+ return -ETIMEDOUT;
+ }
+ cpu_relax();
+ }
+
+ return 0;
+}
+
+static int npcm7xx_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
+{
+ struct npcm7xx_ether *ether = bus->priv;
+ unsigned long timeout = jiffies + msecs_to_jiffies(MII_TIMEOUT * 100);
+
+ writel((phy_id << 0x08) | regnum | PHYBUSY, (ether->reg + REG_MIIDA));
+
+ /* Wait for completion */
+ while (readl((ether->reg + REG_MIIDA)) & PHYBUSY) {
+ if (time_after(jiffies, timeout)) {
+ dev_dbg(&ether->pdev->dev, "mdio read timed out\n ether->reg = 0x%x phy_id=0x%x REG_MIIDA=0x%x\n",
+ (unsigned int)ether->reg, phy_id
+ , readl((ether->reg + REG_MIIDA)));
+ return -ETIMEDOUT;
+ }
+ cpu_relax();
+ }
+
+ return readl((ether->reg + REG_MIID));
+}
+
+static int npcm7xx_mdio_reset(struct mii_bus *bus)
+{
+ /* reset EMAC engine?? */
+ return 0;
+}
+
+static int npcm7xx_set_mac_address(struct net_device *dev, void *addr)
+{
+ struct sockaddr *address = addr;
+
+ if (!is_valid_ether_addr((u8 *)address->sa_data))
+ return -EADDRNOTAVAIL;
+
+ memcpy(dev->dev_addr, address->sa_data, dev->addr_len);
+ npcm7xx_write_cam(dev, CAM0, dev->dev_addr);
+
+ return 0;
+}
+
+static int npcm7xx_ether_close(struct net_device *dev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(dev);
+
+ npcm7xx_return_default_idle(dev);
+
+ if (ether->phy_dev)
+ phy_stop(ether->phy_dev);
+ else if (ether->use_ncsi)
+ ncsi_stop_dev(ether->ncsidev);
+
+ msleep(20);
+
+ free_irq(ether->txirq, dev);
+ free_irq(ether->rxirq, dev);
+
+ netif_stop_queue(dev);
+ napi_disable(&ether->napi);
+
+ npcm7xx_free_desc(dev, true);
+
+ kfree(ether->dump_buf);
+ ether->dump_buf = NULL;
+
+ return 0;
+}
+
+static struct net_device_stats *npcm7xx_ether_stats(struct net_device *dev)
+{
+ struct npcm7xx_ether *ether;
+
+ ether = netdev_priv(dev);
+ return &ether->stats;
+}
+
+static int npcm7xx_clean_tx(struct net_device *dev, bool from_xmit)
+{
+ struct npcm7xx_ether *ether = netdev_priv(dev);
+ struct npcm7xx_txbd *txbd;
+ struct sk_buff *s;
+ dma_addr_t cur_entry, entry;
+ __le32 sl;
+
+ if (ether->pending_tx == 0)
+ return (0);
+
+ cur_entry = readl((ether->reg + REG_CTXDSA));
+
+ /* Release old used buffers */
+ entry = ether->tdesc_phys + sizeof(struct npcm7xx_txbd) *
+ (ether->finish_tx);
+
+ while (entry != cur_entry) {
+ txbd = (ether->tdesc + ether->finish_tx);
+ s = ether->tx_skb[ether->finish_tx];
+ if (!s)
+ break;
+
+ ether->count_finish++;
+
+ dma_unmap_single(&dev->dev, txbd->buffer, s->len,
+ DMA_TO_DEVICE);
+ consume_skb(s);
+ ether->tx_skb[ether->finish_tx] = NULL;
+
+ if (++ether->finish_tx >= TX_QUEUE_LEN)
+ ether->finish_tx = 0;
+ ether->pending_tx--;
+
+ sl = txbd->sl;
+ if (sl & TXDS_TXCP) {
+ ether->stats.tx_packets++;
+ ether->stats.tx_bytes += (sl & 0xFFFF);
+ } else {
+ ether->stats.tx_errors++;
+ }
+
+ entry = ether->tdesc_phys + sizeof(struct npcm7xx_txbd) *
+ (ether->finish_tx);
+ }
+
+ if (!from_xmit && unlikely(netif_queue_stopped(dev) &&
+ (TX_QUEUE_LEN - ether->pending_tx) > 1)) {
+ netif_tx_lock(dev);
+ if (netif_queue_stopped(dev) &&
+ (TX_QUEUE_LEN - ether->pending_tx) > 1) {
+ netif_wake_queue(dev);
+ }
+ netif_tx_unlock(dev);
+ }
+
+ return(0);
+}
+
+static int npcm7xx_ether_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(dev);
+ struct npcm7xx_txbd *txbd;
+ unsigned long flags;
+
+ ether->count_xmit++;
+
+ /* Insert new buffer */
+ txbd = (ether->tdesc + ether->cur_tx);
+ txbd->buffer = dma_map_single(&dev->dev, skb->data, skb->len,
+ DMA_TO_DEVICE);
+ ether->tx_skb[ether->cur_tx] = skb;
+ if (skb->len > MAX_PACKET_SIZE)
+ dev_err(&ether->pdev->dev, "skb->len (= %d) > MAX_PACKET_SIZE (= %d)\n",
+ skb->len, MAX_PACKET_SIZE);
+
+ txbd->sl = skb->len > MAX_PACKET_SIZE ? MAX_PACKET_SIZE : skb->len;
+ dma_wmb();
+
+ txbd->mode = TX_OWN_DMA | PADDINGMODE | CRCMODE;
+ wmb();
+
+ /* trigger TX */
+ writel(ENSTART, (ether->reg + REG_TSDR));
+
+ if (++ether->cur_tx >= TX_QUEUE_LEN)
+ ether->cur_tx = 0;
+
+ spin_lock_irqsave(&ether->lock, flags);
+ ether->pending_tx++;
+
+ npcm7xx_clean_tx(dev, true);
+
+ if (ether->pending_tx >= TX_QUEUE_LEN - 1) {
+ __le32 reg_mien;
+ unsigned int index_to_wake = ether->cur_tx +
+ ((TX_QUEUE_LEN * 3) / 4);
+
+ if (index_to_wake >= TX_QUEUE_LEN)
+ index_to_wake -= TX_QUEUE_LEN;
+
+ txbd = (ether->tdesc + index_to_wake);
+ txbd->mode = TX_OWN_DMA | PADDINGMODE | CRCMODE | MACTXINTEN;
+ wmb();
+
+ writel(MISTA_TDU, (ether->reg + REG_MISTA));
+ /* Clear TDU interrupt */
+ reg_mien = readl((ether->reg + REG_MIEN));
+
+ if (reg_mien != 0)
+ /* Enable TDU interrupt */
+ writel(reg_mien | ENTDU, (ether->reg + REG_MIEN));
+
+ ether->tx_tdu++;
+ netif_stop_queue(dev);
+ }
+
+ spin_unlock_irqrestore(&ether->lock, flags);
+
+ return 0;
+}
+
+static irqreturn_t npcm7xx_tx_interrupt(int irq, void *dev_id)
+{
+ struct npcm7xx_ether *ether;
+ struct platform_device *pdev;
+ struct net_device *dev;
+ __le32 status;
+ unsigned long flags;
+
+ dev = dev_id;
+ ether = netdev_priv(dev);
+ pdev = ether->pdev;
+
+ npcm7xx_get_and_clear_int(dev, &status, 0xFFFF0000);
+
+ ether->tx_int_count++;
+
+ if (status & MISTA_EXDEF)
+ dev_err(&pdev->dev, "emc defer exceed interrupt status=0x%08X\n"
+ , status);
+ else if (status & MISTA_TXBERR) {
+ dev_err(&pdev->dev, "emc bus error interrupt status=0x%08X\n",
+ status);
+#ifdef CONFIG_NPCM7XX_EMC_ETH_DEBUG
+ npcm7xx_info_print(dev);
+#endif
+ spin_lock_irqsave(&ether->lock, flags);
+ writel(0, (ether->reg + REG_MIEN)); /* disable any interrupt */
+ spin_unlock_irqrestore(&ether->lock, flags);
+ ether->need_reset = 1;
+ } else if (status & ~(MISTA_TXINTR | MISTA_TXCP | MISTA_TDU))
+ dev_err(&pdev->dev, "emc other error interrupt status=0x%08X\n",
+ status);
+
+ /* if we got MISTA_TXCP | MISTA_TDU remove those interrupt and call napi */
+ if (status & (MISTA_TXCP | MISTA_TDU) &
+ readl((ether->reg + REG_MIEN))) {
+ __le32 reg_mien;
+
+ spin_lock_irqsave(&ether->lock, flags);
+ reg_mien = readl((ether->reg + REG_MIEN));
+ if (reg_mien & ENTDU)
+ /* Disable TDU interrupt */
+ writel(reg_mien & (~ENTDU), (ether->reg + REG_MIEN));
+
+ spin_unlock_irqrestore(&ether->lock, flags);
+
+ if (status & MISTA_TXCP)
+ ether->tx_cp_i++;
+ if (status & MISTA_TDU)
+ ether->tx_tdu_i++;
+ } else {
+ dev_dbg(&pdev->dev, "status=0x%08X\n", status);
+ }
+
+ napi_schedule(&ether->napi);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t npcm7xx_rx_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = (struct net_device *)dev_id;
+ struct npcm7xx_ether *ether = netdev_priv(dev);
+ struct platform_device *pdev = ether->pdev;
+ __le32 status;
+ unsigned long flags;
+ unsigned int any_err = 0;
+ __le32 rxfsm;
+
+ npcm7xx_get_and_clear_int(dev, &status, 0xFFFF);
+ ether->rx_int_count++;
+
+ if (unlikely(status & MISTA_RXBERR)) {
+ ether->rx_berr++;
+ dev_err(&pdev->dev, "emc rx bus error status=0x%08X\n", status);
+#ifdef CONFIG_NPCM7XX_EMC_ETH_DEBUG
+ npcm7xx_info_print(dev);
+#endif
+ spin_lock_irqsave(&ether->lock, flags);
+ writel(0, (ether->reg + REG_MIEN)); /* disable any interrupt */
+ spin_unlock_irqrestore(&ether->lock, flags);
+ ether->need_reset = 1;
+ napi_schedule(&ether->napi);
+ return IRQ_HANDLED;
+ }
+
+ if (unlikely(status & (MISTA_RXOV | MISTA_RDU))) {
+ /*
+ * filter out all received packets until we have
+ * enough available buffer descriptors
+ */
+ writel(0, (ether->reg + REG_CAMCMR));
+ any_err = 1;
+ if (status & (MISTA_RXOV))
+ ether->rxov++;
+ if (status & (MISTA_RDU))
+ ether->rdu++;
+
+ /*
+ * workaround Errata 1.36: EMC Hangs on receiving 253-256
+ * byte packet
+ */
+ rxfsm = readl((ether->reg + REG_RXFSM));
+
+ if ((rxfsm & 0xFFFFF000) == 0x08044000) {
+ int i;
+
+ for (i = 0; i < 32; i++) {
+ rxfsm = readl((ether->reg + REG_RXFSM));
+ if ((rxfsm & 0xFFFFF000) != 0x08044000)
+ break;
+ }
+ if (i == 32) {
+ ether->rx_stuck++;
+ spin_lock_irqsave(&ether->lock, flags);
+#ifdef CONFIG_NPCM7XX_EMC_ETH_DEBUG
+ npcm7xx_info_print(dev);
+#endif
+ writel(0, (ether->reg + REG_MIEN));
+ spin_unlock_irqrestore(&ether->lock, flags);
+ ether->need_reset = 1;
+ napi_schedule(&ether->napi);
+ dev_err(&pdev->dev, "stuck on REG_RXFSM = 0x%08X status=%08X doing reset!\n", rxfsm, status);
+ return IRQ_HANDLED;
+ }
+ }
+ }
+
+ /* echo MISTA status on unexpected flags although we don't do anithing with them */
+ if (unlikely(status &
+ (/* MISTA_RXINTR | */ /* Receive - all RX interrupt set this */
+ MISTA_CRCE | /* CRC Error */
+ /* MISTA_RXOV | */ /* Receive FIFO Overflow - we alread handled it */
+ (MISTA_PTLE * !IS_VLAN) | /* Packet Too Long is needed if VLAN is not supported */
+ /* MISTA_RXGD | */ /* Receive Good - this is the common good case */
+ MISTA_ALIE | /* Alignment Error */
+ MISTA_RP | /* Runt Packet */
+ MISTA_MMP | /* More Missed Packet */
+ MISTA_DFOI | /* Maximum Frame Length */
+ /* MISTA_DENI | */ /* DMA Early Notification - every packet get this */
+ /* MISTA_RDU | */ /* Receive Descriptor Unavailable */
+ /* MISTA_RXBERR | */ /* Receive Bus Error Interrupt - we alread handled it */
+ /* MISTA_CFR | */ /* Control Frame Receive - not an error */
+ 0))) {
+ dev_dbg(&pdev->dev, "emc rx MISTA status=0x%08X\n", status);
+ any_err = 1;
+ ether->rx_err++;
+ }
+
+ if (!any_err && ((status & MISTA_RXGD) == 0))
+ dev_err(&pdev->dev, "emc rx MISTA status=0x%08X\n", status);
+
+ spin_lock_irqsave(&ether->lock, flags);
+ writel(readl((ether->reg + REG_MIEN)) & ~ENRXGD,
+ (ether->reg + REG_MIEN));
+ spin_unlock_irqrestore(&ether->lock, flags);
+ napi_schedule(&ether->napi);
+
+ return IRQ_HANDLED;
+}
+
+static int npcm7xx_poll(struct napi_struct *napi, int budget)
+{
+ struct npcm7xx_ether *ether =
+ container_of(napi, struct npcm7xx_ether, napi);
+ struct npcm7xx_rxbd *rxbd;
+ struct net_device *dev = ether->ndev;
+ struct platform_device *pdev = ether->pdev;
+ struct sk_buff *skb, *s;
+ unsigned int length;
+ __le32 status;
+ unsigned long flags;
+ int rx_cnt = 0;
+ int complete = 0;
+ unsigned int rx_offset = (readl((ether->reg + REG_CRXDSA)) -
+ ether->start_rx_ptr) /
+ sizeof(struct npcm7xx_txbd);
+ unsigned int local_count = (rx_offset >= ether->cur_rx) ?
+ rx_offset - ether->cur_rx : rx_offset +
+ RX_QUEUE_LEN - ether->cur_rx;
+
+ if (local_count > ether->max_waiting_rx)
+ ether->max_waiting_rx = local_count;
+
+ if (local_count > (4 * RX_POLL_SIZE))
+ /*
+ * we are porbably in a storm of short packets and we don't
+ * want to get into RDU since short packets in RDU cause
+ * many RXOV which may cause EMC halt, so we filter out all
+ * coming packets
+ */
+ writel(0, (ether->reg + REG_CAMCMR));
+
+ if (local_count <= budget)
+ /* we can restore accepting of packets */
+ writel(ether->camcmr, (ether->reg + REG_CAMCMR));
+
+ spin_lock_irqsave(&ether->lock, flags);
+ npcm7xx_clean_tx(dev, false);
+ spin_unlock_irqrestore(&ether->lock, flags);
+
+ rxbd = (ether->rdesc + ether->cur_rx);
+
+ while (rx_cnt < budget) {
+ status = rxbd->sl;
+ if ((status & RX_OWN_DMA) == RX_OWN_DMA) {
+ complete = 1;
+ break;
+ }
+ /* for debug puposes we save the previous value */
+ rxbd->reserved = status;
+ s = ether->rx_skb[ether->cur_rx];
+ length = status & 0xFFFF;
+
+ /*
+ * If VLAN is not supporte RXDS_PTLE (packet too long) is also
+ * an error
+ */
+ if (likely((status & (RXDS_RXGD | RXDS_CRCE | RXDS_ALIE |
+ RXDS_RP | (IS_VLAN ? 0 : RXDS_PTLE))) ==
+ RXDS_RXGD) && likely(length <= MAX_PACKET_SIZE)) {
+ dma_unmap_single(&dev->dev, (dma_addr_t)rxbd->buffer,
+ roundup(MAX_PACKET_SIZE_W_CRC, 4),
+ DMA_FROM_DEVICE);
+
+ skb_put(s, length);
+ s->protocol = eth_type_trans(s, dev);
+ netif_receive_skb(s);
+ ether->stats.rx_packets++;
+ ether->stats.rx_bytes += length;
+ rx_cnt++;
+ ether->rx_count_pool++;
+
+ /* now we allocate new skb instead if the used one. */
+ skb = dev_alloc_skb(roundup(MAX_PACKET_SIZE_W_CRC, 4));
+ if (!skb) {
+ dev_err(&pdev->dev, "get skb buffer error\n");
+ ether->stats.rx_dropped++;
+ goto rx_out;
+ }
+
+ /* Do not unmark the following skb_reserve() Receive
+ * Buffer Starting Address must be aligned
+ * to 4 bytes and the following line if unmarked
+ * will make it align to 2 and this likely
+ * will hult the RX and crash the linux
+ * skb_reserve(skb, NET_IP_ALIGN);
+ */
+ skb->dev = dev;
+
+ rxbd->buffer = dma_map_single(&dev->dev, skb->data,
+ roundup(MAX_PACKET_SIZE_W_CRC, 4),
+ DMA_FROM_DEVICE);
+ ether->rx_skb[ether->cur_rx] = skb;
+ } else {
+ ether->rx_err_count++;
+ ether->stats.rx_errors++;
+ dev_dbg(&pdev->dev, "rx_errors = %lu status = 0x%08X\n",
+ ether->stats.rx_errors, status);
+
+ if (status & RXDS_RP) {
+ ether->stats.rx_length_errors++;
+ dev_dbg(&pdev->dev, "rx_length_errors = %lu\n",
+ ether->stats.rx_length_errors);
+ } else if (status & RXDS_CRCE) {
+ ether->stats.rx_crc_errors++;
+ dev_dbg(&pdev->dev, "rx_crc_errors = %lu\n",
+ ether->stats.rx_crc_errors);
+ } else if (status & RXDS_ALIE) {
+ ether->stats.rx_frame_errors++;
+ dev_dbg(&pdev->dev, "rx_frame_errors = %lu\n",
+ ether->stats.rx_frame_errors);
+ } else if (((!IS_VLAN) && (status & RXDS_PTLE)) ||
+ length > MAX_PACKET_SIZE) {
+ ether->stats.rx_length_errors++;
+ dev_dbg(&pdev->dev, "rx_length_errors = %lu\n",
+ ether->stats.rx_length_errors);
+ }
+ }
+
+ wmb();
+ rxbd->sl = RX_OWN_DMA;
+ wmb();
+
+ if (++ether->cur_rx >= RX_QUEUE_LEN)
+ ether->cur_rx = 0;
+
+ rxbd = (ether->rdesc + ether->cur_rx);
+ }
+
+ if (complete) {
+ napi_complete(napi);
+
+ if (ether->need_reset) {
+ dev_dbg(&pdev->dev, "Reset\n");
+ npcm7xx_reset_mac(dev, 1);
+ }
+
+ spin_lock_irqsave(&ether->lock, flags);
+ writel(readl((ether->reg + REG_MIEN)) | ENRXGD, (ether->reg +
+ REG_MIEN));
+ spin_unlock_irqrestore(&ether->lock, flags);
+ } else {
+ rx_offset = (readl((ether->reg + REG_CRXDSA)) -
+ ether->start_rx_ptr) / sizeof(struct npcm7xx_txbd);
+ local_count = (rx_offset >= ether->cur_rx) ? rx_offset -
+ ether->cur_rx : rx_offset + RX_QUEUE_LEN -
+ ether->cur_rx;
+
+ if (local_count > ether->max_waiting_rx)
+ ether->max_waiting_rx = local_count;
+
+ if (local_count > (3 * RX_POLL_SIZE))
+ /*
+ * we are porbably in a storm of short packets and
+ * we don't want to get into RDU since short packets in
+ * RDU cause many RXOV which may cause
+ * EMC halt, so we filter out all coming packets
+ */
+ writel(0, (ether->reg + REG_CAMCMR));
+ if (local_count <= RX_POLL_SIZE)
+ /* we can restore accepting of packets */
+ writel(ether->camcmr, (ether->reg + REG_CAMCMR));
+ }
+rx_out:
+
+ /* trigger RX */
+ writel(ENSTART, (ether->reg + REG_RSDR));
+ return rx_cnt;
+}
+
+static int npcm7xx_ether_open(struct net_device *dev)
+{
+ struct npcm7xx_ether *ether;
+ struct platform_device *pdev;
+
+ ether = netdev_priv(dev);
+ pdev = ether->pdev;
+
+ if (ether->use_ncsi) {
+ ether->speed = 100;
+ ether->duplex = DUPLEX_FULL;
+ npcm7xx_opmode(dev, 100, DUPLEX_FULL);
+ }
+ npcm7xx_reset_mac(dev, 0);
+
+ if (request_irq(ether->txirq, npcm7xx_tx_interrupt, 0x0, pdev->name,
+ dev)) {
+ dev_err(&pdev->dev, "register irq tx failed\n");
+ npcm7xx_ether_close(dev);
+ return -EAGAIN;
+ }
+
+ if (request_irq(ether->rxirq, npcm7xx_rx_interrupt, 0x0, pdev->name,
+ dev)) {
+ dev_err(&pdev->dev, "register irq rx failed\n");
+ npcm7xx_ether_close(dev);
+ return -EAGAIN;
+ }
+
+ if (ether->phy_dev)
+ phy_start(ether->phy_dev);
+ else if (ether->use_ncsi)
+ netif_carrier_on(dev);
+
+ netif_start_queue(dev);
+ napi_enable(&ether->napi);
+
+ /* trigger RX */
+ writel(ENSTART, (ether->reg + REG_RSDR));
+
+ /* Start the NCSI device */
+ if (ether->use_ncsi) {
+ int err = ncsi_start_dev(ether->ncsidev);
+
+ if (err) {
+ npcm7xx_ether_close(dev);
+ return err;
+ }
+ }
+
+ dev_info(&pdev->dev, "%s is OPENED\n", dev->name);
+
+ return 0;
+}
+
+static int npcm7xx_ether_ioctl(struct net_device *dev,
+ struct ifreq *ifr, int cmd)
+{
+ struct npcm7xx_ether *ether = netdev_priv(dev);
+ struct phy_device *phydev = ether->phy_dev;
+
+ if (!netif_running(dev))
+ return -EINVAL;
+
+ if (!phydev)
+ return -ENODEV;
+
+ return phy_mii_ioctl(phydev, ifr, cmd);
+}
+
+static void npcm7xx_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
+ strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
+ strlcpy(info->fw_version, "N/A", sizeof(info->fw_version));
+ strlcpy(info->bus_info, "N/A", sizeof(info->bus_info));
+}
+
+static int npcm7xx_get_settings(struct net_device *dev,
+ struct ethtool_link_ksettings *cmd)
+{
+ struct npcm7xx_ether *ether = netdev_priv(dev);
+ struct phy_device *phydev = ether->phy_dev;
+
+ if (!phydev)
+ return -ENODEV;
+
+ dev_info(&ether->pdev->dev, "\n\nnpcm7xx_get_settings\n");
+ phy_ethtool_ksettings_get(phydev, cmd);
+
+ return 0;
+}
+
+static int npcm7xx_set_settings(struct net_device *dev,
+ const struct ethtool_link_ksettings *cmd)
+{
+ struct npcm7xx_ether *ether = netdev_priv(dev);
+ struct phy_device *phydev = ether->phy_dev;
+ int ret;
+
+ if (!phydev)
+ return -ENODEV;
+
+ dev_info(&ether->pdev->dev, "\n\nnpcm7xx_set_settings\n");
+ ret = phy_ethtool_ksettings_set(phydev, cmd);
+
+ return ret;
+}
+
+static u32 npcm7xx_get_msglevel(struct net_device *dev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(dev);
+
+ return ether->msg_enable;
+}
+
+static void npcm7xx_set_msglevel(struct net_device *dev, u32 level)
+{
+ struct npcm7xx_ether *ether = netdev_priv(dev);
+
+ ether->msg_enable = level;
+}
+
+static const struct ethtool_ops npcm7xx_ether_ethtool_ops = {
+ .get_link_ksettings = npcm7xx_get_settings,
+ .set_link_ksettings = npcm7xx_set_settings,
+ .get_drvinfo = npcm7xx_get_drvinfo,
+ .get_msglevel = npcm7xx_get_msglevel,
+ .set_msglevel = npcm7xx_set_msglevel,
+ .get_link = ethtool_op_get_link,
+};
+
+static const struct net_device_ops npcm7xx_ether_netdev_ops = {
+ .ndo_open = npcm7xx_ether_open,
+ .ndo_stop = npcm7xx_ether_close,
+ .ndo_start_xmit = npcm7xx_ether_start_xmit,
+ .ndo_get_stats = npcm7xx_ether_stats,
+ .ndo_set_rx_mode = npcm7xx_ether_set_rx_mode,
+ .ndo_set_mac_address = npcm7xx_set_mac_address,
+ .ndo_do_ioctl = npcm7xx_ether_ioctl,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_change_mtu = eth_change_mtu,
+};
+
+static void get_mac_address(struct net_device *dev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(dev);
+ struct platform_device *pdev = ether->pdev;
+ struct device_node *np = ether->pdev->dev.of_node;
+ const u8 *mac_address = NULL;
+
+ mac_address = of_get_mac_address(np);
+
+ if (mac_address != 0)
+ ether_addr_copy(dev->dev_addr, mac_address);
+
+ if (is_valid_ether_addr(dev->dev_addr)) {
+ dev_info(&pdev->dev, "%s: device MAC address : %pM\n",
+ pdev->name, dev->dev_addr);
+ } else {
+ eth_hw_addr_random(dev);
+ dev_info(&pdev->dev, "%s: device MAC address (random generator) %pM\n",
+ dev->name, dev->dev_addr);
+ }
+}
+
+static int npcm7xx_mii_setup(struct net_device *dev)
+{
+ struct npcm7xx_ether *ether = netdev_priv(dev);
+ struct platform_device *pdev;
+ struct phy_device *phydev = NULL;
+ int i, err = 0;
+
+ pdev = ether->pdev;
+
+ ether->mii_bus = mdiobus_alloc();
+ if (!ether->mii_bus) {
+ err = -ENOMEM;
+ dev_err(&pdev->dev, "mdiobus_alloc() failed\n");
+ goto out0;
+ }
+
+ ether->mii_bus->name = "npcm7xx_rmii";
+ ether->mii_bus->read = &npcm7xx_mdio_read;
+ ether->mii_bus->write = &npcm7xx_mdio_write;
+ ether->mii_bus->reset = &npcm7xx_mdio_reset;
+ snprintf(ether->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
+ ether->pdev->name, ether->pdev->id);
+ dev_dbg(&pdev->dev, "%s ether->mii_bus->id=%s\n", __func__,
+ ether->mii_bus->id);
+ ether->mii_bus->priv = ether;
+ ether->mii_bus->parent = &ether->pdev->dev;
+
+ for (i = 0; i < PHY_MAX_ADDR; i++)
+ ether->mii_bus->irq[i] = PHY_POLL;
+
+ platform_set_drvdata(ether->pdev, ether->mii_bus);
+
+ /* Enable MDIO Clock */
+ writel(readl((ether->reg + REG_MCMDR)) | MCMDR_ENMDC,
+ (ether->reg + REG_MCMDR));
+
+ if (mdiobus_register(ether->mii_bus)) {
+ dev_err(&pdev->dev, "mdiobus_register() failed\n");
+ goto out2;
+ }
+
+ phydev = phy_find_first(ether->mii_bus);
+ if (!phydev) {
+ dev_err(&pdev->dev, "phy_find_first() failed\n");
+ goto out3;
+ }
+
+ dev_info(&pdev->dev, " name = %s ETH-Phy-Id = 0x%x\n",
+ phydev_name(phydev), phydev->phy_id);
+
+ phydev = phy_connect(dev, phydev_name(phydev),
+ &adjust_link,
+ PHY_INTERFACE_MODE_RMII);
+
+ dev_info(&pdev->dev, " ETH-Phy-Id = 0x%x name = %s\n",
+ phydev->phy_id, phydev->drv->name);
+
+ if (IS_ERR(phydev)) {
+ err = PTR_ERR(phydev);
+ dev_err(&pdev->dev, "phy_connect() failed - %d\n", err);
+ goto out3;
+ }
+
+ linkmode_and(phydev->supported, phydev->supported, PHY_BASIC_FEATURES);
+ linkmode_copy(phydev->advertising, phydev->supported);
+ ether->phy_dev = phydev;
+
+ return 0;
+
+out3:
+ mdiobus_unregister(ether->mii_bus);
+out2:
+ kfree(ether->mii_bus->irq);
+ mdiobus_free(ether->mii_bus);
+out0:
+
+ return err;
+}
+
+static const struct of_device_id emc_dt_id[] = {
+ { .compatible = "nuvoton,npcm750-emc", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, emc_dt_id);
+
+static void npcm7xx_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 int npcm7xx_ether_probe(struct platform_device *pdev)
+{
+ struct npcm7xx_ether *ether;
+ struct net_device *dev;
+ int error;
+
+ struct clk *emc_clk = NULL;
+ struct device_node *np = pdev->dev.of_node;
+
+ pdev->id = of_alias_get_id(np, "ethernet");
+ if (pdev->id < 0)
+ pdev->id = 0;
+
+ emc_clk = devm_clk_get(&pdev->dev, NULL);
+
+ if (IS_ERR(emc_clk))
+ return PTR_ERR(emc_clk);
+
+ /* Enable Clock */
+ clk_prepare_enable(emc_clk);
+
+ error = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+ if (error)
+ return -ENODEV;
+
+ dev = alloc_etherdev(sizeof(struct npcm7xx_ether));
+ if (!dev)
+ return -ENOMEM;
+
+ ether = netdev_priv(dev);
+
+ ether->rst_regmap =
+ syscon_regmap_lookup_by_compatible("nuvoton,npcm750-rst");
+ if (IS_ERR(ether->rst_regmap)) {
+ dev_err(&pdev->dev, "%s: failed to find nuvoton,npcm750-rst\n", __func__);
+ return IS_ERR(ether->rst_regmap);
+ }
+
+ /* Reset EMC module */
+ if (pdev->id == 0) {
+ regmap_update_bits(ether->rst_regmap, IPSRST1_OFFSET,
+ (0x1 << 6), (0x1 << 6));
+ regmap_update_bits(ether->rst_regmap, IPSRST1_OFFSET,
+ (0x1 << 6), 0);
+ }
+ if (pdev->id == 1) {
+ regmap_update_bits(ether->rst_regmap, IPSRST1_OFFSET,
+ (0x1 << 21), (0x1 << 21));
+ regmap_update_bits(ether->rst_regmap, IPSRST1_OFFSET,
+ (0x1 << 21), 0);
+ }
+
+ ether->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!ether->res) {
+ dev_err(&pdev->dev, "failed to get I/O memory\n");
+ error = -ENXIO;
+ goto failed_free;
+ }
+
+ if (!request_mem_region(ether->res->start,
+ resource_size(ether->res), pdev->name)) {
+ dev_err(&pdev->dev, "failed to request I/O memory\n");
+ error = -EBUSY;
+ goto failed_free;
+ }
+
+ ether->reg = ioremap(ether->res->start, resource_size(ether->res));
+ dev_dbg(&pdev->dev, "%s ether->reg = 0x%x\n", __func__,
+ (unsigned int)ether->reg);
+
+ if (!ether->reg) {
+ dev_err(&pdev->dev, "failed to remap I/O memory\n");
+ error = -ENXIO;
+ goto failed_free_mem;
+ }
+
+ ether->txirq = platform_get_irq(pdev, 0);
+ if (ether->txirq < 0) {
+ dev_err(&pdev->dev, "failed to get ether tx irq\n");
+ error = -ENXIO;
+ goto failed_free_io;
+ }
+
+ ether->rxirq = platform_get_irq(pdev, 1);
+ if (ether->rxirq < 0) {
+ dev_err(&pdev->dev, "failed to get ether rx irq\n");
+ error = -ENXIO;
+ goto failed_free_io;
+ }
+
+ SET_NETDEV_DEV(dev, &pdev->dev);
+ platform_set_drvdata(pdev, dev);
+ ether->ndev = dev;
+
+ ether->pdev = pdev;
+ ether->msg_enable = NETIF_MSG_LINK;
+
+ dev->netdev_ops = &npcm7xx_ether_netdev_ops;
+ dev->ethtool_ops = &npcm7xx_ether_ethtool_ops;
+
+ dev->tx_queue_len = TX_QUEUE_LEN;
+ dev->dma = 0x0;
+ dev->watchdog_timeo = TX_TIMEOUT;
+
+ get_mac_address(dev);
+
+ ether->cur_tx = 0x0;
+ ether->cur_rx = 0x0;
+ ether->finish_tx = 0x0;
+ ether->pending_tx = 0x0;
+ ether->link = 0;
+ ether->speed = 100;
+ ether->duplex = DUPLEX_FULL;
+ ether->need_reset = 0;
+ ether->dump_buf = NULL;
+ ether->rx_berr = 0;
+ ether->rx_err = 0;
+ ether->rdu = 0;
+ ether->rxov = 0;
+ ether->rx_stuck = 0;
+ /* debug counters */
+ ether->max_waiting_rx = 0;
+ ether->rx_count_pool = 0;
+ ether->count_xmit = 0;
+ ether->rx_int_count = 0;
+ ether->rx_err_count = 0;
+ ether->tx_int_count = 0;
+ ether->count_finish = 0;
+ ether->tx_tdu = 0;
+ ether->tx_tdu_i = 0;
+ ether->tx_cp_i = 0;
+
+ spin_lock_init(&ether->lock);
+
+ netif_napi_add(dev, &ether->napi, npcm7xx_poll, RX_POLL_SIZE);
+
+ if (pdev->dev.of_node &&
+ of_get_property(pdev->dev.of_node, "use-ncsi", NULL)) {
+ if (!IS_ENABLED(CONFIG_NET_NCSI)) {
+ dev_err(&pdev->dev, "CONFIG_NET_NCSI not enabled\n");
+ error = -ENODEV;
+ goto failed_free_napi;
+ }
+ dev_info(&pdev->dev, "Using NCSI interface\n");
+ ether->use_ncsi = true;
+ ether->ncsidev = ncsi_register_dev(dev, npcm7xx_ncsi_handler);
+ if (!ether->ncsidev) {
+ error = -ENODEV;
+ goto failed_free_napi;
+ }
+ } else {
+ ether->use_ncsi = false;
+ error = npcm7xx_mii_setup(dev);
+ if (error < 0) {
+ dev_err(&pdev->dev, "npcm7xx_mii_setup err\n");
+ goto failed_free_napi;
+ }
+ }
+
+ error = register_netdev(dev);
+ if (error != 0) {
+ dev_err(&pdev->dev, "register_netdev() failed\n");
+ error = -ENODEV;
+ goto failed_free_napi;
+ }
+
+#ifdef CONFIG_DEBUG_FS
+ npcm7xx_debug_fs(ether);
+#endif
+
+ return 0;
+
+failed_free_napi:
+ netif_napi_del(&ether->napi);
+ platform_set_drvdata(pdev, NULL);
+failed_free_io:
+ iounmap(ether->reg);
+failed_free_mem:
+ release_mem_region(ether->res->start, resource_size(ether->res));
+failed_free:
+ free_netdev(dev);
+
+ return error;
+}
+
+static int npcm7xx_ether_remove(struct platform_device *pdev)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+ struct npcm7xx_ether *ether = netdev_priv(dev);
+
+#ifdef CONFIG_DEBUG_FS
+ debugfs_remove_recursive(ether->dbgfs_dir);
+#endif
+
+ unregister_netdev(dev);
+
+ free_irq(ether->txirq, dev);
+ free_irq(ether->rxirq, dev);
+
+ if (ether->phy_dev)
+ phy_disconnect(ether->phy_dev);
+
+ mdiobus_unregister(ether->mii_bus);
+ kfree(ether->mii_bus->irq);
+ mdiobus_free(ether->mii_bus);
+
+ platform_set_drvdata(pdev, NULL);
+
+ free_netdev(dev);
+ return 0;
+}
+
+static struct platform_driver npcm7xx_ether_driver = {
+ .probe = npcm7xx_ether_probe,
+ .remove = npcm7xx_ether_remove,
+ .driver = {
+ .name = DRV_MODULE_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(emc_dt_id),
+ },
+};
+
+module_platform_driver(npcm7xx_ether_driver);
+
+MODULE_AUTHOR("Nuvoton Technology Corp.");
+MODULE_DESCRIPTION("NPCM750 EMC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:npcm750-emc");
+MODULE_VERSION(DRV_MODULE_VERSION);
diff --git a/drivers/peci/Kconfig b/drivers/peci/Kconfig
new file mode 100644
index 000000000000..a64fed7bb367
--- /dev/null
+++ b/drivers/peci/Kconfig
@@ -0,0 +1,37 @@
+#
+# Platform Environment Control Interface (PECI) subsystem configuration
+#
+
+menu "PECI support"
+
+config PECI
+ tristate "PECI support"
+ select CRC8
+ help
+ The Platform Environment Control Interface (PECI) is a one-wire bus
+ interface that provides a communication channel from Intel processors
+ and chipset components to external monitoring or control devices.
+
+ If you want PECI support, you should say Y here and also to the
+ specific driver for your bus adapter(s) below.
+
+ This support is also available as a module. If so, the module
+ will be called peci-core.
+
+if PECI
+
+config PECI_CHARDEV
+ tristate "PECI device interface"
+ help
+ Say Y here to use peci-* device files, usually found in the /dev
+ directory on your system. They make it possible to have user-space
+ programs use the PECI bus.
+
+ This support is also available as a module. If so, the module
+ will be called peci-dev.
+
+source "drivers/peci/busses/Kconfig"
+
+endif # PECI
+
+endmenu
diff --git a/drivers/peci/Makefile b/drivers/peci/Makefile
new file mode 100644
index 000000000000..da8b0a33fa42
--- /dev/null
+++ b/drivers/peci/Makefile
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the PECI core drivers.
+#
+
+# Core functionality
+obj-$(CONFIG_PECI) += peci-core.o
+obj-$(CONFIG_PECI_CHARDEV) += peci-dev.o
+
+# Hardware specific bus drivers
+obj-y += busses/
diff --git a/drivers/peci/busses/Kconfig b/drivers/peci/busses/Kconfig
new file mode 100644
index 000000000000..4316234db67c
--- /dev/null
+++ b/drivers/peci/busses/Kconfig
@@ -0,0 +1,34 @@
+#
+# PECI hardware bus configuration
+#
+
+menu "PECI Hardware Bus support"
+
+config PECI_ASPEED
+ tristate "ASPEED PECI support"
+ depends on ARCH_ASPEED || COMPILE_TEST
+ depends on OF
+ depends on HAS_IOMEM
+ depends on PECI
+ help
+ Say Y here if you want support for the Platform Environment Control
+ Interface (PECI) bus adapter driver on the ASPEED SoCs.
+
+ This support is also available as a module. If so, the module
+ will be called peci-aspeed.
+
+config PECI_NPCM
+ tristate "Nuvoton NPCM PECI support"
+ select REGMAP_MMIO
+ depends on OF
+ depends on HAS_IOMEM
+ depends on ARCH_NPCM || COMPILE_TEST
+ depends on PECI
+ help
+ Say Y here if you want support for the Platform Environment Control
+ Interface (PECI) bus adapter driver on the Nuvoton NPCM SoCs.
+
+ This support is also available as a module. If so, the module
+ will be called peci-npcm.
+
+endmenu
diff --git a/drivers/peci/busses/Makefile b/drivers/peci/busses/Makefile
new file mode 100644
index 000000000000..aa8ce3ae5947
--- /dev/null
+++ b/drivers/peci/busses/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the PECI hardware bus drivers.
+#
+
+obj-$(CONFIG_PECI_ASPEED) += peci-aspeed.o
+obj-$(CONFIG_PECI_NPCM) += peci-npcm.o
diff --git a/drivers/peci/busses/peci-aspeed.c b/drivers/peci/busses/peci-aspeed.c
new file mode 100644
index 000000000000..2673d4c4dcf9
--- /dev/null
+++ b/drivers/peci/busses/peci-aspeed.c
@@ -0,0 +1,484 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2012-2017 ASPEED Technology Inc.
+// Copyright (c) 2018-2019 Intel Corporation
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/peci.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+
+/* ASPEED PECI Registers */
+/* Control Register */
+#define ASPEED_PECI_CTRL 0x00
+#define ASPEED_PECI_CTRL_SAMPLING_MASK GENMASK(19, 16)
+#define ASPEED_PECI_CTRL_READ_MODE_MASK GENMASK(13, 12)
+#define ASPEED_PECI_CTRL_READ_MODE_COUNT BIT(12)
+#define ASPEED_PECI_CTRL_READ_MODE_DBG BIT(13)
+#define ASPEED_PECI_CTRL_CLK_SOURCE_MASK BIT(11)
+#define ASPEED_PECI_CTRL_CLK_DIV_MASK GENMASK(10, 8)
+#define ASPEED_PECI_CTRL_INVERT_OUT BIT(7)
+#define ASPEED_PECI_CTRL_INVERT_IN BIT(6)
+#define ASPEED_PECI_CTRL_BUS_CONTENT_EN BIT(5)
+#define ASPEED_PECI_CTRL_PECI_EN BIT(4)
+#define ASPEED_PECI_CTRL_PECI_CLK_EN BIT(0)
+
+/* Timing Negotiation Register */
+#define ASPEED_PECI_TIMING_NEGOTIATION 0x04
+#define ASPEED_PECI_TIMING_MESSAGE_MASK GENMASK(15, 8)
+#define ASPEED_PECI_TIMING_ADDRESS_MASK GENMASK(7, 0)
+
+/* Command Register */
+#define ASPEED_PECI_CMD 0x08
+#define ASPEED_PECI_CMD_PIN_MON BIT(31)
+#define ASPEED_PECI_CMD_STS_MASK GENMASK(27, 24)
+#define ASPEED_PECI_CMD_IDLE_MASK \
+ (ASPEED_PECI_CMD_STS_MASK | ASPEED_PECI_CMD_PIN_MON)
+#define ASPEED_PECI_CMD_FIRE BIT(0)
+
+/* Read/Write Length Register */
+#define ASPEED_PECI_RW_LENGTH 0x0c
+#define ASPEED_PECI_AW_FCS_EN BIT(31)
+#define ASPEED_PECI_READ_LEN_MASK GENMASK(23, 16)
+#define ASPEED_PECI_WRITE_LEN_MASK GENMASK(15, 8)
+#define ASPEED_PECI_TAGET_ADDR_MASK GENMASK(7, 0)
+
+/* Expected FCS Data Register */
+#define ASPEED_PECI_EXP_FCS 0x10
+#define ASPEED_PECI_EXP_READ_FCS_MASK GENMASK(23, 16)
+#define ASPEED_PECI_EXP_AW_FCS_AUTO_MASK GENMASK(15, 8)
+#define ASPEED_PECI_EXP_WRITE_FCS_MASK GENMASK(7, 0)
+
+/* Captured FCS Data Register */
+#define ASPEED_PECI_CAP_FCS 0x14
+#define ASPEED_PECI_CAP_READ_FCS_MASK GENMASK(23, 16)
+#define ASPEED_PECI_CAP_WRITE_FCS_MASK GENMASK(7, 0)
+
+/* Interrupt Register */
+#define ASPEED_PECI_INT_CTRL 0x18
+#define ASPEED_PECI_TIMING_NEGO_SEL_MASK GENMASK(31, 30)
+#define ASPEED_PECI_1ST_BIT_OF_ADDR_NEGO 0
+#define ASPEED_PECI_2ND_BIT_OF_ADDR_NEGO 1
+#define ASPEED_PECI_MESSAGE_NEGO 2
+#define ASPEED_PECI_INT_MASK GENMASK(4, 0)
+#define ASPEED_PECI_INT_BUS_TIMEOUT BIT(4)
+#define ASPEED_PECI_INT_BUS_CONNECT BIT(3)
+#define ASPEED_PECI_INT_W_FCS_BAD BIT(2)
+#define ASPEED_PECI_INT_W_FCS_ABORT BIT(1)
+#define ASPEED_PECI_INT_CMD_DONE BIT(0)
+
+/* Interrupt Status Register */
+#define ASPEED_PECI_INT_STS 0x1c
+#define ASPEED_PECI_INT_TIMING_RESULT_MASK GENMASK(29, 16)
+ /* bits[4..0]: Same bit fields in the 'Interrupt Register' */
+
+/* Rx/Tx Data Buffer Registers */
+#define ASPEED_PECI_W_DATA0 0x20
+#define ASPEED_PECI_W_DATA1 0x24
+#define ASPEED_PECI_W_DATA2 0x28
+#define ASPEED_PECI_W_DATA3 0x2c
+#define ASPEED_PECI_R_DATA0 0x30
+#define ASPEED_PECI_R_DATA1 0x34
+#define ASPEED_PECI_R_DATA2 0x38
+#define ASPEED_PECI_R_DATA3 0x3c
+#define ASPEED_PECI_W_DATA4 0x40
+#define ASPEED_PECI_W_DATA5 0x44
+#define ASPEED_PECI_W_DATA6 0x48
+#define ASPEED_PECI_W_DATA7 0x4c
+#define ASPEED_PECI_R_DATA4 0x50
+#define ASPEED_PECI_R_DATA5 0x54
+#define ASPEED_PECI_R_DATA6 0x58
+#define ASPEED_PECI_R_DATA7 0x5c
+#define ASPEED_PECI_DATA_BUF_SIZE_MAX 32
+
+/* Timing Negotiation */
+#define ASPEED_PECI_RD_SAMPLING_POINT_DEFAULT 8
+#define ASPEED_PECI_RD_SAMPLING_POINT_MAX 15
+#define ASPEED_PECI_CLK_DIV_DEFAULT 0
+#define ASPEED_PECI_CLK_DIV_MAX 7
+#define ASPEED_PECI_MSG_TIMING_DEFAULT 1
+#define ASPEED_PECI_MSG_TIMING_MAX 255
+#define ASPEED_PECI_ADDR_TIMING_DEFAULT 1
+#define ASPEED_PECI_ADDR_TIMING_MAX 255
+
+/* Timeout */
+#define ASPEED_PECI_IDLE_CHECK_TIMEOUT_USEC 50000
+#define ASPEED_PECI_IDLE_CHECK_INTERVAL_USEC 10000
+#define ASPEED_PECI_CMD_TIMEOUT_MS_DEFAULT 1000
+#define ASPEED_PECI_CMD_TIMEOUT_MS_MAX 60000
+
+struct aspeed_peci {
+ struct peci_adapter *adapter;
+ struct device *dev;
+ void __iomem *base;
+ struct clk *clk;
+ struct reset_control *rst;
+ int irq;
+ spinlock_t lock; /* to sync completion status handling */
+ struct completion xfer_complete;
+ u32 status;
+ u32 cmd_timeout_ms;
+};
+
+static inline int aspeed_peci_check_idle(struct aspeed_peci *priv)
+{
+ u32 cmd_sts;
+
+ return readl_poll_timeout(priv->base + ASPEED_PECI_CMD,
+ cmd_sts,
+ !(cmd_sts & ASPEED_PECI_CMD_IDLE_MASK),
+ ASPEED_PECI_IDLE_CHECK_INTERVAL_USEC,
+ ASPEED_PECI_IDLE_CHECK_TIMEOUT_USEC);
+}
+
+static int aspeed_peci_xfer(struct peci_adapter *adapter,
+ struct peci_xfer_msg *msg)
+{
+ struct aspeed_peci *priv = peci_get_adapdata(adapter);
+ long err, timeout = msecs_to_jiffies(priv->cmd_timeout_ms);
+ u32 peci_head, peci_state, rx_data = 0;
+ ulong flags;
+ int i, ret;
+ uint reg;
+
+ if (msg->tx_len > ASPEED_PECI_DATA_BUF_SIZE_MAX ||
+ msg->rx_len > ASPEED_PECI_DATA_BUF_SIZE_MAX)
+ return -EINVAL;
+
+ /* Check command sts and bus idle state */
+ ret = aspeed_peci_check_idle(priv);
+ if (ret)
+ return ret; /* -ETIMEDOUT */
+
+ spin_lock_irqsave(&priv->lock, flags);
+ reinit_completion(&priv->xfer_complete);
+
+ peci_head = FIELD_PREP(ASPEED_PECI_TAGET_ADDR_MASK, msg->addr) |
+ FIELD_PREP(ASPEED_PECI_WRITE_LEN_MASK, msg->tx_len) |
+ FIELD_PREP(ASPEED_PECI_READ_LEN_MASK, msg->rx_len);
+
+ writel(peci_head, priv->base + ASPEED_PECI_RW_LENGTH);
+
+ for (i = 0; i < msg->tx_len; i += 4) {
+ reg = i < 16 ? ASPEED_PECI_W_DATA0 + i % 16 :
+ ASPEED_PECI_W_DATA4 + i % 16;
+ writel(le32_to_cpup((__le32 *)&msg->tx_buf[i]),
+ priv->base + reg);
+ }
+
+ dev_dbg(priv->dev, "HEAD : 0x%08x\n", peci_head);
+ print_hex_dump_debug("TX : ", DUMP_PREFIX_NONE, 16, 1,
+ msg->tx_buf, msg->tx_len, true);
+
+ priv->status = 0;
+ writel(ASPEED_PECI_CMD_FIRE, priv->base + ASPEED_PECI_CMD);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ err = wait_for_completion_interruptible_timeout(&priv->xfer_complete,
+ timeout);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ dev_dbg(priv->dev, "INT_STS : 0x%08x\n", priv->status);
+ peci_state = readl(priv->base + ASPEED_PECI_CMD);
+ dev_dbg(priv->dev, "PECI_STATE : 0x%lx\n",
+ FIELD_GET(ASPEED_PECI_CMD_STS_MASK, peci_state));
+
+ writel(0, priv->base + ASPEED_PECI_CMD);
+
+ if (err <= 0 || priv->status != ASPEED_PECI_INT_CMD_DONE) {
+ if (err < 0) { /* -ERESTARTSYS */
+ ret = (int)err;
+ goto err_irqrestore;
+ } else if (err == 0) {
+ dev_dbg(priv->dev, "Timeout waiting for a response!\n");
+ ret = -ETIMEDOUT;
+ goto err_irqrestore;
+ }
+
+ dev_dbg(priv->dev, "No valid response!\n");
+ ret = -EIO;
+ goto err_irqrestore;
+ }
+
+ /*
+ * Note that rx_len and rx_buf size can be an odd number.
+ * Byte handling is more efficient.
+ */
+ for (i = 0; i < msg->rx_len; i++) {
+ u8 byte_offset = i % 4;
+
+ if (byte_offset == 0) {
+ reg = i < 16 ? ASPEED_PECI_R_DATA0 + i % 16 :
+ ASPEED_PECI_R_DATA4 + i % 16;
+ rx_data = readl(priv->base + reg);
+ }
+
+ msg->rx_buf[i] = (u8)(rx_data >> (byte_offset << 3));
+ }
+
+ print_hex_dump_debug("RX : ", DUMP_PREFIX_NONE, 16, 1,
+ msg->rx_buf, msg->rx_len, true);
+
+ peci_state = readl(priv->base + ASPEED_PECI_CMD);
+ dev_dbg(priv->dev, "PECI_STATE : 0x%lx\n",
+ FIELD_GET(ASPEED_PECI_CMD_STS_MASK, peci_state));
+ dev_dbg(priv->dev, "------------------------\n");
+
+err_irqrestore:
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return ret;
+}
+
+static irqreturn_t aspeed_peci_irq_handler(int irq, void *arg)
+{
+ struct aspeed_peci *priv = arg;
+ u32 status;
+
+ spin_lock(&priv->lock);
+ status = readl(priv->base + ASPEED_PECI_INT_STS);
+ writel(status, priv->base + ASPEED_PECI_INT_STS);
+ priv->status |= (status & ASPEED_PECI_INT_MASK);
+
+ /*
+ * In most cases, interrupt bits will be set one by one but also note
+ * that multiple interrupt bits could be set at the same time.
+ */
+ if (status & ASPEED_PECI_INT_BUS_TIMEOUT)
+ dev_dbg(priv->dev, "ASPEED_PECI_INT_BUS_TIMEOUT\n");
+
+ if (status & ASPEED_PECI_INT_BUS_CONNECT)
+ dev_dbg(priv->dev, "ASPEED_PECI_INT_BUS_CONNECT\n");
+
+ if (status & ASPEED_PECI_INT_W_FCS_BAD)
+ dev_dbg(priv->dev, "ASPEED_PECI_INT_W_FCS_BAD\n");
+
+ if (status & ASPEED_PECI_INT_W_FCS_ABORT)
+ dev_dbg(priv->dev, "ASPEED_PECI_INT_W_FCS_ABORT\n");
+
+ /*
+ * All commands should be ended up with a ASPEED_PECI_INT_CMD_DONE bit
+ * set even in an error case.
+ */
+ if (status & ASPEED_PECI_INT_CMD_DONE) {
+ dev_dbg(priv->dev, "ASPEED_PECI_INT_CMD_DONE\n");
+ complete(&priv->xfer_complete);
+ }
+
+ spin_unlock(&priv->lock);
+
+ return IRQ_HANDLED;
+}
+
+static int aspeed_peci_init_ctrl(struct aspeed_peci *priv)
+{
+ u32 msg_timing, addr_timing, rd_sampling_point;
+ u32 clk_freq, clk_divisor, clk_div_val = 0;
+ int ret;
+
+ priv->clk = devm_clk_get(priv->dev, NULL);
+ if (IS_ERR(priv->clk)) {
+ dev_err(priv->dev, "Failed to get clk source.\n");
+ return PTR_ERR(priv->clk);
+ }
+
+ ret = clk_prepare_enable(priv->clk);
+ if (ret) {
+ dev_err(priv->dev, "Failed to enable clock.\n");
+ return ret;
+ }
+
+ ret = device_property_read_u32(priv->dev, "clock-frequency", &clk_freq);
+ if (ret) {
+ dev_err(priv->dev,
+ "Could not read clock-frequency property.\n");
+ clk_disable_unprepare(priv->clk);
+ return ret;
+ }
+
+ clk_divisor = clk_get_rate(priv->clk) / clk_freq;
+
+ while ((clk_divisor >> 1) && (clk_div_val < ASPEED_PECI_CLK_DIV_MAX))
+ clk_div_val++;
+
+ ret = device_property_read_u32(priv->dev, "msg-timing", &msg_timing);
+ if (ret || msg_timing > ASPEED_PECI_MSG_TIMING_MAX) {
+ if (!ret)
+ dev_warn(priv->dev,
+ "Invalid msg-timing : %u, Use default : %u\n",
+ msg_timing, ASPEED_PECI_MSG_TIMING_DEFAULT);
+ msg_timing = ASPEED_PECI_MSG_TIMING_DEFAULT;
+ }
+
+ ret = device_property_read_u32(priv->dev, "addr-timing", &addr_timing);
+ if (ret || addr_timing > ASPEED_PECI_ADDR_TIMING_MAX) {
+ if (!ret)
+ dev_warn(priv->dev,
+ "Invalid addr-timing : %u, Use default : %u\n",
+ addr_timing, ASPEED_PECI_ADDR_TIMING_DEFAULT);
+ addr_timing = ASPEED_PECI_ADDR_TIMING_DEFAULT;
+ }
+
+ ret = device_property_read_u32(priv->dev, "rd-sampling-point",
+ &rd_sampling_point);
+ if (ret || rd_sampling_point > ASPEED_PECI_RD_SAMPLING_POINT_MAX) {
+ if (!ret)
+ dev_warn(priv->dev,
+ "Invalid rd-sampling-point : %u. Use default : %u\n",
+ rd_sampling_point,
+ ASPEED_PECI_RD_SAMPLING_POINT_DEFAULT);
+ rd_sampling_point = ASPEED_PECI_RD_SAMPLING_POINT_DEFAULT;
+ }
+
+ ret = device_property_read_u32(priv->dev, "cmd-timeout-ms",
+ &priv->cmd_timeout_ms);
+ if (ret || priv->cmd_timeout_ms > ASPEED_PECI_CMD_TIMEOUT_MS_MAX ||
+ priv->cmd_timeout_ms == 0) {
+ if (!ret)
+ dev_warn(priv->dev,
+ "Invalid cmd-timeout-ms : %u. Use default : %u\n",
+ priv->cmd_timeout_ms,
+ ASPEED_PECI_CMD_TIMEOUT_MS_DEFAULT);
+ priv->cmd_timeout_ms = ASPEED_PECI_CMD_TIMEOUT_MS_DEFAULT;
+ }
+
+ writel(FIELD_PREP(ASPEED_PECI_CTRL_CLK_DIV_MASK,
+ ASPEED_PECI_CLK_DIV_DEFAULT) |
+ ASPEED_PECI_CTRL_PECI_CLK_EN, priv->base + ASPEED_PECI_CTRL);
+
+ /*
+ * Timing negotiation period setting.
+ * The unit of the programmed value is 4 times of PECI clock period.
+ */
+ writel(FIELD_PREP(ASPEED_PECI_TIMING_MESSAGE_MASK, msg_timing) |
+ FIELD_PREP(ASPEED_PECI_TIMING_ADDRESS_MASK, addr_timing),
+ priv->base + ASPEED_PECI_TIMING_NEGOTIATION);
+
+ /* Clear interrupts */
+ writel(readl(priv->base + ASPEED_PECI_INT_STS) | ASPEED_PECI_INT_MASK,
+ priv->base + ASPEED_PECI_INT_STS);
+
+ /* Set timing negotiation mode and enable interrupts */
+ writel(FIELD_PREP(ASPEED_PECI_TIMING_NEGO_SEL_MASK,
+ ASPEED_PECI_1ST_BIT_OF_ADDR_NEGO) |
+ ASPEED_PECI_INT_MASK, priv->base + ASPEED_PECI_INT_CTRL);
+
+ /* Read sampling point and clock speed setting */
+ writel(FIELD_PREP(ASPEED_PECI_CTRL_SAMPLING_MASK, rd_sampling_point) |
+ FIELD_PREP(ASPEED_PECI_CTRL_CLK_DIV_MASK, clk_div_val) |
+ ASPEED_PECI_CTRL_PECI_EN | ASPEED_PECI_CTRL_PECI_CLK_EN,
+ priv->base + ASPEED_PECI_CTRL);
+
+ return 0;
+}
+
+static int aspeed_peci_probe(struct platform_device *pdev)
+{
+ struct peci_adapter *adapter;
+ struct aspeed_peci *priv;
+ int ret;
+
+ adapter = peci_alloc_adapter(&pdev->dev, sizeof(*priv));
+ if (!adapter)
+ return -ENOMEM;
+
+ priv = peci_get_adapdata(adapter);
+ priv->adapter = adapter;
+ priv->dev = &pdev->dev;
+ dev_set_drvdata(&pdev->dev, priv);
+
+ priv->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->base)) {
+ ret = PTR_ERR(priv->base);
+ goto err_put_adapter_dev;
+ }
+
+ priv->irq = platform_get_irq(pdev, 0);
+ if (!priv->irq) {
+ ret = -ENODEV;
+ goto err_put_adapter_dev;
+ }
+
+ ret = devm_request_irq(&pdev->dev, priv->irq, aspeed_peci_irq_handler,
+ 0, "peci-aspeed-irq", priv);
+ if (ret)
+ goto err_put_adapter_dev;
+
+ init_completion(&priv->xfer_complete);
+ spin_lock_init(&priv->lock);
+
+ priv->adapter->owner = THIS_MODULE;
+ priv->adapter->dev.of_node = of_node_get(dev_of_node(priv->dev));
+ strlcpy(priv->adapter->name, pdev->name, sizeof(priv->adapter->name));
+ priv->adapter->xfer = aspeed_peci_xfer;
+ priv->adapter->use_dma = false;
+
+ priv->rst = devm_reset_control_get(&pdev->dev, NULL);
+ if (IS_ERR(priv->rst)) {
+ dev_err(&pdev->dev,
+ "missing or invalid reset controller entry\n");
+ ret = PTR_ERR(priv->rst);
+ goto err_put_adapter_dev;
+ }
+ reset_control_deassert(priv->rst);
+
+ ret = aspeed_peci_init_ctrl(priv);
+ if (ret)
+ goto err_put_adapter_dev;
+
+ ret = peci_add_adapter(priv->adapter);
+ if (ret)
+ goto err_put_adapter_dev;
+
+ dev_info(&pdev->dev, "peci bus %d registered, irq %d\n",
+ priv->adapter->nr, priv->irq);
+
+ return 0;
+
+err_put_adapter_dev:
+ put_device(&adapter->dev);
+
+ return ret;
+}
+
+static int aspeed_peci_remove(struct platform_device *pdev)
+{
+ struct aspeed_peci *priv = dev_get_drvdata(&pdev->dev);
+
+ clk_disable_unprepare(priv->clk);
+ reset_control_assert(priv->rst);
+ peci_del_adapter(priv->adapter);
+ of_node_put(priv->adapter->dev.of_node);
+
+ return 0;
+}
+
+static const struct of_device_id aspeed_peci_of_table[] = {
+ { .compatible = "aspeed,ast2400-peci", },
+ { .compatible = "aspeed,ast2500-peci", },
+ { .compatible = "aspeed,ast2600-peci", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, aspeed_peci_of_table);
+
+static struct platform_driver aspeed_peci_driver = {
+ .probe = aspeed_peci_probe,
+ .remove = aspeed_peci_remove,
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .of_match_table = of_match_ptr(aspeed_peci_of_table),
+ },
+};
+module_platform_driver(aspeed_peci_driver);
+
+MODULE_AUTHOR("Ryan Chen <ryan_chen@aspeedtech.com>");
+MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
+MODULE_DESCRIPTION("ASPEED PECI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/peci/busses/peci-npcm.c b/drivers/peci/busses/peci-npcm.c
new file mode 100644
index 000000000000..bdebbf1ec7f1
--- /dev/null
+++ b/drivers/peci/busses/peci-npcm.c
@@ -0,0 +1,406 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2019 Nuvoton Technology corporation.
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/peci.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <linux/reset.h>
+
+/* NPCM7xx GCR module */
+#define NPCM7XX_INTCR3_OFFSET 0x9C
+#define NPCM7XX_INTCR3_PECIVSEL BIT(19)
+
+/* NPCM PECI Registers */
+#define NPCM_PECI_CTL_STS 0x00
+#define NPCM_PECI_RD_LENGTH 0x04
+#define NPCM_PECI_ADDR 0x08
+#define NPCM_PECI_CMD 0x0C
+#define NPCM_PECI_CTL2 0x10
+#define NPCM_PECI_WR_LENGTH 0x1C
+#define NPCM_PECI_PDDR 0x2C
+#define NPCM_PECI_DAT_INOUT(n) (0x100 + ((n) * 4))
+
+#define NPCM_PECI_MAX_REG 0x200
+
+/* NPCM_PECI_CTL_STS - 0x00 : Control Register */
+#define NPCM_PECI_CTRL_DONE_INT_EN BIT(6)
+#define NPCM_PECI_CTRL_ABRT_ERR BIT(4)
+#define NPCM_PECI_CTRL_CRC_ERR BIT(3)
+#define NPCM_PECI_CTRL_DONE BIT(1)
+#define NPCM_PECI_CTRL_START_BUSY BIT(0)
+
+/* NPCM_PECI_RD_LENGTH - 0x04 : Command Register */
+#define NPCM_PECI_RD_LEN_MASK GENMASK(6, 0)
+
+/* NPCM_PECI_CMD - 0x10 : Command Register */
+#define NPCM_PECI_CTL2_MASK GENMASK(7, 6)
+
+/* NPCM_PECI_WR_LENGTH - 0x1C : Command Register */
+#define NPCM_PECI_WR_LEN_MASK GENMASK(6, 0)
+
+/* NPCM_PECI_PDDR - 0x2C : Command Register */
+#define NPCM_PECI_PDDR_MASK GENMASK(4, 0)
+
+#define NPCM_PECI_INT_MASK \
+ (NPCM_PECI_CTRL_ABRT_ERR | NPCM_PECI_CTRL_CRC_ERR | NPCM_PECI_CTRL_DONE)
+
+#define NPCM_PECI_IDLE_CHECK_TIMEOUT_USEC 50000
+#define NPCM_PECI_IDLE_CHECK_INTERVAL_USEC 10000
+#define NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT 1000
+#define NPCM_PECI_CMD_TIMEOUT_MS_MAX 60000
+#define NPCM_PECI_HOST_NEG_BIT_RATE_MAX 31
+#define NPCM_PECI_HOST_NEG_BIT_RATE_MIN 7
+#define NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT 15
+#define NPCM_PECI_PULL_DOWN_DEFAULT 0
+#define NPCM_PECI_PULL_DOWN_MAX 2
+
+struct npcm_peci {
+ u32 cmd_timeout_ms;
+ u32 host_bit_rate;
+ struct completion xfer_complete;
+ struct regmap *gcr_regmap;
+ struct peci_adapter *adapter;
+ struct regmap *regmap;
+ u32 status;
+ spinlock_t lock; /* to sync completion status handling */
+ struct device *dev;
+ struct clk *clk;
+ int irq;
+};
+
+static int npcm_peci_xfer_native(struct npcm_peci *priv,
+ struct peci_xfer_msg *msg)
+{
+ long err, timeout = msecs_to_jiffies(priv->cmd_timeout_ms);
+ unsigned long flags;
+ unsigned int msg_rd;
+ u32 cmd_sts;
+ int i, rc;
+
+ /* Check command sts and bus idle state */
+ rc = regmap_read_poll_timeout(priv->regmap, NPCM_PECI_CTL_STS, cmd_sts,
+ !(cmd_sts & NPCM_PECI_CTRL_START_BUSY),
+ NPCM_PECI_IDLE_CHECK_INTERVAL_USEC,
+ NPCM_PECI_IDLE_CHECK_TIMEOUT_USEC);
+ if (rc)
+ return rc; /* -ETIMEDOUT */
+
+ spin_lock_irqsave(&priv->lock, flags);
+ reinit_completion(&priv->xfer_complete);
+
+ regmap_write(priv->regmap, NPCM_PECI_ADDR, msg->addr);
+ regmap_write(priv->regmap, NPCM_PECI_RD_LENGTH,
+ NPCM_PECI_WR_LEN_MASK & msg->rx_len);
+ regmap_write(priv->regmap, NPCM_PECI_WR_LENGTH,
+ NPCM_PECI_WR_LEN_MASK & msg->tx_len);
+
+ if (msg->tx_len) {
+ regmap_write(priv->regmap, NPCM_PECI_CMD, msg->tx_buf[0]);
+
+ for (i = 0; i < (msg->tx_len - 1); i++)
+ regmap_write(priv->regmap, NPCM_PECI_DAT_INOUT(i),
+ msg->tx_buf[i + 1]);
+ }
+
+ priv->status = 0;
+ regmap_update_bits(priv->regmap, NPCM_PECI_CTL_STS,
+ NPCM_PECI_CTRL_START_BUSY,
+ NPCM_PECI_CTRL_START_BUSY);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ err = wait_for_completion_interruptible_timeout(&priv->xfer_complete,
+ timeout);
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ regmap_write(priv->regmap, NPCM_PECI_CMD, 0);
+
+ if (err <= 0 || priv->status != NPCM_PECI_CTRL_DONE) {
+ if (err < 0) { /* -ERESTARTSYS */
+ rc = (int)err;
+ goto err_irqrestore;
+ } else if (err == 0) {
+ dev_dbg(priv->dev, "Timeout waiting for a response!\n");
+ rc = -ETIMEDOUT;
+ goto err_irqrestore;
+ }
+
+ dev_dbg(priv->dev, "No valid response!\n");
+ rc = -EIO;
+ goto err_irqrestore;
+ }
+
+ for (i = 0; i < msg->rx_len; i++) {
+ regmap_read(priv->regmap, NPCM_PECI_DAT_INOUT(i), &msg_rd);
+ msg->rx_buf[i] = (u8)msg_rd;
+ }
+
+err_irqrestore:
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return rc;
+}
+
+static irqreturn_t npcm_peci_irq_handler(int irq, void *arg)
+{
+ struct npcm_peci *priv = arg;
+ u32 status_ack = 0;
+ u32 status;
+
+ spin_lock(&priv->lock);
+ regmap_read(priv->regmap, NPCM_PECI_CTL_STS, &status);
+ priv->status |= (status & NPCM_PECI_INT_MASK);
+
+ if (status & NPCM_PECI_CTRL_CRC_ERR) {
+ dev_dbg(priv->dev, "PECI_INT_W_FCS_BAD\n");
+ status_ack |= NPCM_PECI_CTRL_CRC_ERR;
+ }
+
+ if (status & NPCM_PECI_CTRL_ABRT_ERR) {
+ dev_dbg(priv->dev, "NPCM_PECI_CTRL_ABRT_ERR\n");
+ status_ack |= NPCM_PECI_CTRL_ABRT_ERR;
+ }
+
+ /*
+ * All commands should be ended up with a NPCM_PECI_CTRL_DONE
+ * bit set even in an error case.
+ */
+ if (status & NPCM_PECI_CTRL_DONE) {
+ dev_dbg(priv->dev, "NPCM_PECI_CTRL_DONE\n");
+ status_ack |= NPCM_PECI_CTRL_DONE;
+ complete(&priv->xfer_complete);
+ }
+
+ regmap_write_bits(priv->regmap, NPCM_PECI_CTL_STS,
+ NPCM_PECI_INT_MASK, status_ack);
+
+ spin_unlock(&priv->lock);
+ return IRQ_HANDLED;
+}
+
+static int npcm_peci_init_ctrl(struct npcm_peci *priv)
+{
+ u32 cmd_sts, host_neg_bit_rate = 0, pull_down = 0;
+ int ret;
+
+ priv->clk = devm_clk_get(priv->dev, NULL);
+ if (IS_ERR(priv->clk)) {
+ dev_err(priv->dev, "Failed to get clk source.\n");
+ return PTR_ERR(priv->clk);
+ }
+
+ ret = clk_prepare_enable(priv->clk);
+ if (ret) {
+ dev_err(priv->dev, "Failed to enable clock.\n");
+ return ret;
+ }
+
+ ret = of_property_read_u32(priv->dev->of_node, "cmd-timeout-ms",
+ &priv->cmd_timeout_ms);
+ if (ret || priv->cmd_timeout_ms > NPCM_PECI_CMD_TIMEOUT_MS_MAX ||
+ priv->cmd_timeout_ms == 0) {
+ if (ret)
+ dev_warn(priv->dev,
+ "cmd-timeout-ms not found, use default : %u\n",
+ NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT);
+ else
+ dev_warn(priv->dev,
+ "Invalid cmd-timeout-ms : %u. Use default : %u\n",
+ priv->cmd_timeout_ms,
+ NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT);
+
+ priv->cmd_timeout_ms = NPCM_PECI_CMD_TIMEOUT_MS_DEFAULT;
+ }
+
+ if (of_device_is_compatible(priv->dev->of_node,
+ "nuvoton,npcm750-peci")) {
+ priv->gcr_regmap = syscon_regmap_lookup_by_compatible
+ ("nuvoton,npcm750-gcr");
+ if (!IS_ERR(priv->gcr_regmap)) {
+ bool volt = of_property_read_bool(priv->dev->of_node,
+ "high-volt-range");
+ if (volt)
+ regmap_update_bits(priv->gcr_regmap,
+ NPCM7XX_INTCR3_OFFSET,
+ NPCM7XX_INTCR3_PECIVSEL,
+ NPCM7XX_INTCR3_PECIVSEL);
+ else
+ regmap_update_bits(priv->gcr_regmap,
+ NPCM7XX_INTCR3_OFFSET,
+ NPCM7XX_INTCR3_PECIVSEL, 0);
+ }
+ }
+
+ ret = of_property_read_u32(priv->dev->of_node, "pull-down",
+ &pull_down);
+ if (ret || pull_down > NPCM_PECI_PULL_DOWN_MAX) {
+ if (ret)
+ dev_warn(priv->dev,
+ "pull-down not found, use default : %u\n",
+ NPCM_PECI_PULL_DOWN_DEFAULT);
+ else
+ dev_warn(priv->dev,
+ "Invalid pull-down : %u. Use default : %u\n",
+ pull_down,
+ NPCM_PECI_PULL_DOWN_DEFAULT);
+ pull_down = NPCM_PECI_PULL_DOWN_DEFAULT;
+ }
+
+ regmap_update_bits(priv->regmap, NPCM_PECI_CTL2, NPCM_PECI_CTL2_MASK,
+ pull_down << 6);
+
+ ret = of_property_read_u32(priv->dev->of_node, "host-neg-bit-rate",
+ &host_neg_bit_rate);
+ if (ret || host_neg_bit_rate > NPCM_PECI_HOST_NEG_BIT_RATE_MAX ||
+ host_neg_bit_rate < NPCM_PECI_HOST_NEG_BIT_RATE_MIN) {
+ if (ret)
+ dev_warn(priv->dev,
+ "host-neg-bit-rate not found, use default : %u\n",
+ NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT);
+ else
+ dev_warn(priv->dev,
+ "Invalid host-neg-bit-rate : %u. Use default : %u\n",
+ host_neg_bit_rate,
+ NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT);
+ host_neg_bit_rate = NPCM_PECI_HOST_NEG_BIT_RATE_DEFAULT;
+ }
+
+ regmap_update_bits(priv->regmap, NPCM_PECI_PDDR, NPCM_PECI_PDDR_MASK,
+ host_neg_bit_rate);
+
+ priv->host_bit_rate = clk_get_rate(priv->clk) /
+ (4 * (host_neg_bit_rate + 1));
+
+ ret = regmap_read_poll_timeout(priv->regmap, NPCM_PECI_CTL_STS, cmd_sts,
+ !(cmd_sts & NPCM_PECI_CTRL_START_BUSY),
+ NPCM_PECI_IDLE_CHECK_INTERVAL_USEC,
+ NPCM_PECI_IDLE_CHECK_TIMEOUT_USEC);
+ if (ret)
+ return ret; /* -ETIMEDOUT */
+
+ /* PECI interrupt enable */
+ regmap_update_bits(priv->regmap, NPCM_PECI_CTL_STS,
+ NPCM_PECI_CTRL_DONE_INT_EN,
+ NPCM_PECI_CTRL_DONE_INT_EN);
+
+ return 0;
+}
+
+static const struct regmap_config npcm_peci_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = NPCM_PECI_MAX_REG,
+ .fast_io = true,
+};
+
+static int npcm_peci_xfer(struct peci_adapter *adapter,
+ struct peci_xfer_msg *msg)
+{
+ struct npcm_peci *priv = peci_get_adapdata(adapter);
+
+ return npcm_peci_xfer_native(priv, msg);
+}
+
+static int npcm_peci_probe(struct platform_device *pdev)
+{
+ struct peci_adapter *adapter;
+ struct npcm_peci *priv;
+ void __iomem *base;
+ int ret;
+
+ adapter = peci_alloc_adapter(&pdev->dev, sizeof(*priv));
+ if (!adapter)
+ return -ENOMEM;
+
+ priv = peci_get_adapdata(adapter);
+ priv->adapter = adapter;
+ priv->dev = &pdev->dev;
+ dev_set_drvdata(&pdev->dev, priv);
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base)) {
+ ret = PTR_ERR(base);
+ goto err_put_adapter_dev;
+ }
+
+ priv->regmap = devm_regmap_init_mmio(&pdev->dev, base,
+ &npcm_peci_regmap_config);
+ if (IS_ERR(priv->regmap)) {
+ ret = PTR_ERR(priv->regmap);
+ goto err_put_adapter_dev;
+ }
+
+ priv->irq = platform_get_irq(pdev, 0);
+ if (!priv->irq) {
+ ret = -ENODEV;
+ goto err_put_adapter_dev;
+ }
+
+ ret = devm_request_irq(&pdev->dev, priv->irq, npcm_peci_irq_handler,
+ 0, "peci-npcm-irq", priv);
+ if (ret)
+ goto err_put_adapter_dev;
+
+ init_completion(&priv->xfer_complete);
+ spin_lock_init(&priv->lock);
+
+ priv->adapter->owner = THIS_MODULE;
+ priv->adapter->dev.of_node = of_node_get(dev_of_node(priv->dev));
+ strlcpy(priv->adapter->name, pdev->name, sizeof(priv->adapter->name));
+ priv->adapter->xfer = npcm_peci_xfer;
+
+ ret = npcm_peci_init_ctrl(priv);
+ if (ret)
+ goto err_put_adapter_dev;
+
+ ret = peci_add_adapter(priv->adapter);
+ if (ret)
+ goto err_put_adapter_dev;
+
+ dev_info(&pdev->dev, "peci bus %d registered, host negotiation bit rate %dHz",
+ priv->adapter->nr, priv->host_bit_rate);
+
+ return 0;
+
+err_put_adapter_dev:
+ put_device(&adapter->dev);
+ return ret;
+}
+
+static int npcm_peci_remove(struct platform_device *pdev)
+{
+ struct npcm_peci *priv = dev_get_drvdata(&pdev->dev);
+
+ clk_disable_unprepare(priv->clk);
+ peci_del_adapter(priv->adapter);
+ of_node_put(priv->adapter->dev.of_node);
+
+ return 0;
+}
+
+static const struct of_device_id npcm_peci_of_table[] = {
+ { .compatible = "nuvoton,npcm750-peci", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, npcm_peci_of_table);
+
+static struct platform_driver npcm_peci_driver = {
+ .probe = npcm_peci_probe,
+ .remove = npcm_peci_remove,
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .of_match_table = of_match_ptr(npcm_peci_of_table),
+ },
+};
+module_platform_driver(npcm_peci_driver);
+
+MODULE_AUTHOR("Tomer Maimon <tomer.maimon@nuvoton.com>");
+MODULE_DESCRIPTION("NPCM Platform Environment Control Interface (PECI) driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/peci/peci-core.c b/drivers/peci/peci-core.c
new file mode 100644
index 000000000000..9aedb74710e6
--- /dev/null
+++ b/drivers/peci/peci-core.c
@@ -0,0 +1,2089 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018-2019 Intel Corporation
+
+#include <linux/bitfield.h>
+#include <linux/crc8.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/peci.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
+#include <linux/sched/task_stack.h>
+#include <linux/slab.h>
+
+/* Mask for getting minor revision number from DIB */
+#define REVISION_NUM_MASK GENMASK(15, 8)
+
+/* CRC8 table for Assured Write Frame Check */
+#define PECI_CRC8_POLYNOMIAL 0x07
+DECLARE_CRC8_TABLE(peci_crc8_table);
+
+static bool is_registered;
+
+static DEFINE_MUTEX(core_lock);
+static DEFINE_IDR(peci_adapter_idr);
+
+struct peci_adapter *peci_get_adapter(int nr)
+{
+ struct peci_adapter *adapter;
+
+ mutex_lock(&core_lock);
+ adapter = idr_find(&peci_adapter_idr, nr);
+ if (!adapter)
+ goto out_unlock;
+
+ if (try_module_get(adapter->owner))
+ get_device(&adapter->dev);
+ else
+ adapter = NULL;
+
+out_unlock:
+ mutex_unlock(&core_lock);
+
+ return adapter;
+}
+EXPORT_SYMBOL_GPL(peci_get_adapter);
+
+void peci_put_adapter(struct peci_adapter *adapter)
+{
+ if (!adapter)
+ return;
+
+ put_device(&adapter->dev);
+ module_put(adapter->owner);
+}
+EXPORT_SYMBOL_GPL(peci_put_adapter);
+
+static ssize_t name_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%s\n", dev->type == &peci_client_type ?
+ to_peci_client(dev)->name : to_peci_adapter(dev)->name);
+}
+static DEVICE_ATTR_RO(name);
+
+static void peci_client_dev_release(struct device *dev)
+{
+ struct peci_client *client = to_peci_client(dev);
+
+ dev_dbg(dev, "%s: %s\n", __func__, client->name);
+ peci_put_adapter(client->adapter);
+ kfree(client);
+}
+
+static struct attribute *peci_device_attrs[] = {
+ &dev_attr_name.attr,
+ NULL
+};
+ATTRIBUTE_GROUPS(peci_device);
+
+struct device_type peci_client_type = {
+ .groups = peci_device_groups,
+ .release = peci_client_dev_release,
+};
+EXPORT_SYMBOL_GPL(peci_client_type);
+
+/**
+ * peci_verify_client - return parameter as peci_client, or NULL
+ * @dev: device, probably from some driver model iterator
+ *
+ * Return: pointer to peci_client on success, else NULL.
+ */
+struct peci_client *peci_verify_client(struct device *dev)
+{
+ return (dev->type == &peci_client_type)
+ ? to_peci_client(dev)
+ : NULL;
+}
+EXPORT_SYMBOL_GPL(peci_verify_client);
+
+/**
+ * peci_get_xfer_msg() - get a DMA safe peci_xfer_msg for the given tx and rx
+ * length
+ * @tx_len: the length of tx_buf. May be 0 if tx_buf isn't needed.
+ * @rx_len: the length of rx_buf. May be 0 if rx_buf isn't needed.
+ *
+ * Return: NULL if a DMA safe buffer was not obtained.
+ * Or a valid pointer to be used with DMA. After use, release it by
+ * calling peci_put_xfer_msg().
+ *
+ * This function must only be called from process context!
+ */
+struct peci_xfer_msg *peci_get_xfer_msg(u8 tx_len, u8 rx_len)
+{
+ struct peci_xfer_msg *msg;
+ u8 *tx_buf, *rx_buf;
+
+ if (tx_len) {
+ tx_buf = kzalloc(tx_len, GFP_KERNEL);
+ if (!tx_buf)
+ return NULL;
+ } else {
+ tx_buf = NULL;
+ }
+
+ if (rx_len) {
+ rx_buf = kzalloc(rx_len, GFP_KERNEL);
+ if (!rx_buf)
+ goto err_free_tx_buf;
+ } else {
+ rx_buf = NULL;
+ }
+
+ msg = kzalloc(sizeof(*msg), GFP_KERNEL);
+ if (!msg)
+ goto err_free_tx_rx_buf;
+
+ msg->tx_len = tx_len;
+ msg->tx_buf = tx_buf;
+ msg->rx_len = rx_len;
+ msg->rx_buf = rx_buf;
+
+ return msg;
+
+err_free_tx_rx_buf:
+ kfree(rx_buf);
+err_free_tx_buf:
+ kfree(tx_buf);
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(peci_get_xfer_msg);
+
+/**
+ * peci_put_xfer_msg - release a DMA safe peci_xfer_msg
+ * @msg: the message obtained from peci_get_xfer_msg(). May be NULL.
+ */
+void peci_put_xfer_msg(struct peci_xfer_msg *msg)
+{
+ if (!msg)
+ return;
+
+ kfree(msg->rx_buf);
+ kfree(msg->tx_buf);
+ kfree(msg);
+}
+EXPORT_SYMBOL_GPL(peci_put_xfer_msg);
+
+/* Calculate an Assured Write Frame Check Sequence byte */
+static int peci_aw_fcs(struct peci_xfer_msg *msg, int len, u8 *aw_fcs)
+{
+ u8 *tmp_buf;
+
+ /* Allocate a temporary buffer to use a contiguous byte array */
+ tmp_buf = kmalloc(len, GFP_KERNEL);
+ if (!tmp_buf)
+ return -ENOMEM;
+
+ tmp_buf[0] = msg->addr;
+ tmp_buf[1] = msg->tx_len;
+ tmp_buf[2] = msg->rx_len;
+ memcpy(&tmp_buf[3], msg->tx_buf, len - 3);
+
+ *aw_fcs = crc8(peci_crc8_table, tmp_buf, (size_t)len, 0);
+
+ kfree(tmp_buf);
+
+ return 0;
+}
+
+static int __peci_xfer(struct peci_adapter *adapter, struct peci_xfer_msg *msg,
+ bool do_retry, bool has_aw_fcs)
+{
+ uint interval_ms = PECI_DEV_RETRY_INTERVAL_MIN_MSEC;
+ ulong timeout = jiffies;
+ u8 aw_fcs;
+ int ret;
+
+ /*
+ * In case if adapter uses DMA, check at here whether tx and rx buffers
+ * are DMA capable or not.
+ */
+ if (IS_ENABLED(CONFIG_HAS_DMA) && adapter->use_dma) {
+ if (is_vmalloc_addr(msg->tx_buf) ||
+ is_vmalloc_addr(msg->rx_buf)) {
+ WARN_ONCE(1, "xfer msg is not dma capable\n");
+ return -EAGAIN;
+ } else if (object_is_on_stack(msg->tx_buf) ||
+ object_is_on_stack(msg->rx_buf)) {
+ WARN_ONCE(1, "xfer msg is on stack\n");
+ return -EAGAIN;
+ }
+ }
+
+ /*
+ * For some commands, the PECI originator may need to retry a command if
+ * the processor PECI client responds with a 0x8x completion code. In
+ * each instance, the processor PECI client may have started the
+ * operation but not completed it yet. When the 'retry' bit is set, the
+ * PECI client will ignore a new request if it exactly matches a
+ * previous valid request. For better performance and for reducing
+ * retry traffic, the interval time will be increased exponentially.
+ */
+
+ if (do_retry)
+ timeout += PECI_DEV_RETRY_TIMEOUT;
+
+ for (;;) {
+ ret = adapter->xfer(adapter, msg);
+
+ if (!do_retry || ret || !msg->rx_buf)
+ break;
+
+ /* Retry is needed when completion code is 0x8x */
+ if ((msg->rx_buf[0] & PECI_DEV_CC_RETRY_CHECK_MASK) !=
+ PECI_DEV_CC_NEED_RETRY)
+ break;
+
+ /* Set the retry bit to indicate a retry attempt */
+ msg->tx_buf[1] |= PECI_DEV_RETRY_BIT;
+
+ /* Recalculate the AW FCS if it has one */
+ if (has_aw_fcs) {
+ ret = peci_aw_fcs(msg, 2 + msg->tx_len, &aw_fcs);
+ if (ret)
+ break;
+
+ msg->tx_buf[msg->tx_len - 1] = 0x80 ^ aw_fcs;
+ }
+
+ /* Retry it for 'timeout' before returning an error. */
+ if (time_after(jiffies, timeout)) {
+ dev_dbg(&adapter->dev, "Timeout retrying xfer!\n");
+ ret = -ETIMEDOUT;
+ break;
+ }
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (schedule_timeout(msecs_to_jiffies(interval_ms))) {
+ ret = -EINTR;
+ break;
+ }
+
+ interval_ms *= 2;
+ if (interval_ms > PECI_DEV_RETRY_INTERVAL_MAX_MSEC)
+ interval_ms = PECI_DEV_RETRY_INTERVAL_MAX_MSEC;
+ }
+
+ if (ret)
+ dev_dbg(&adapter->dev, "xfer error: %d\n", ret);
+
+ return ret;
+}
+
+static int peci_xfer(struct peci_adapter *adapter, struct peci_xfer_msg *msg)
+{
+ return __peci_xfer(adapter, msg, false, false);
+}
+
+static int peci_xfer_with_retries(struct peci_adapter *adapter,
+ struct peci_xfer_msg *msg,
+ bool has_aw_fcs)
+{
+ return __peci_xfer(adapter, msg, true, has_aw_fcs);
+}
+
+static int peci_scan_cmd_mask(struct peci_adapter *adapter)
+{
+ struct peci_xfer_msg *msg;
+ u8 revision;
+ int ret;
+ u64 dib;
+
+ /* Update command mask just once */
+ if (adapter->cmd_mask & BIT(PECI_CMD_XFER))
+ return 0;
+
+ msg = peci_get_xfer_msg(PECI_GET_DIB_WR_LEN, PECI_GET_DIB_RD_LEN);
+ if (!msg)
+ return -ENOMEM;
+
+ msg->addr = PECI_BASE_ADDR;
+ msg->tx_buf[0] = PECI_GET_DIB_CMD;
+
+ ret = peci_xfer(adapter, msg);
+ if (ret)
+ return ret;
+
+ dib = le64_to_cpup((__le64 *)msg->rx_buf);
+
+ /* Check special case for Get DIB command */
+ if (dib == 0) {
+ dev_dbg(&adapter->dev, "DIB read as 0\n");
+ ret = -EIO;
+ goto out;
+ }
+
+ /*
+ * Setting up the supporting commands based on revision number.
+ * See PECI Spec Table 3-1.
+ */
+ revision = FIELD_GET(REVISION_NUM_MASK, dib);
+ if (revision >= 0x40) { /* Rev. 4.0 */
+ adapter->cmd_mask |= BIT(PECI_CMD_RD_IA_MSREX);
+ adapter->cmd_mask |= BIT(PECI_CMD_RD_END_PT_CFG);
+ adapter->cmd_mask |= BIT(PECI_CMD_WR_END_PT_CFG);
+ adapter->cmd_mask |= BIT(PECI_CMD_CRASHDUMP_DISC);
+ adapter->cmd_mask |= BIT(PECI_CMD_CRASHDUMP_GET_FRAME);
+ }
+ if (revision >= 0x36) /* Rev. 3.6 */
+ adapter->cmd_mask |= BIT(PECI_CMD_WR_IA_MSR);
+ if (revision >= 0x35) /* Rev. 3.5 */
+ adapter->cmd_mask |= BIT(PECI_CMD_WR_PCI_CFG);
+ if (revision >= 0x34) /* Rev. 3.4 */
+ adapter->cmd_mask |= BIT(PECI_CMD_RD_PCI_CFG);
+ if (revision >= 0x33) { /* Rev. 3.3 */
+ adapter->cmd_mask |= BIT(PECI_CMD_RD_PCI_CFG_LOCAL);
+ adapter->cmd_mask |= BIT(PECI_CMD_WR_PCI_CFG_LOCAL);
+ }
+ if (revision >= 0x32) /* Rev. 3.2 */
+ adapter->cmd_mask |= BIT(PECI_CMD_RD_IA_MSR);
+ if (revision >= 0x31) { /* Rev. 3.1 */
+ adapter->cmd_mask |= BIT(PECI_CMD_RD_PKG_CFG);
+ adapter->cmd_mask |= BIT(PECI_CMD_WR_PKG_CFG);
+ }
+
+ adapter->cmd_mask |= BIT(PECI_CMD_XFER);
+ adapter->cmd_mask |= BIT(PECI_CMD_GET_TEMP);
+ adapter->cmd_mask |= BIT(PECI_CMD_GET_DIB);
+ adapter->cmd_mask |= BIT(PECI_CMD_PING);
+
+out:
+ peci_put_xfer_msg(msg);
+
+ return ret;
+}
+
+static int peci_check_cmd_support(struct peci_adapter *adapter,
+ enum peci_cmd cmd)
+{
+ if (!(adapter->cmd_mask & BIT(PECI_CMD_PING)) &&
+ peci_scan_cmd_mask(adapter) < 0) {
+ dev_dbg(&adapter->dev, "Failed to scan command mask\n");
+ return -EIO;
+ }
+
+ if (!(adapter->cmd_mask & BIT(cmd))) {
+ dev_dbg(&adapter->dev, "Command %d is not supported\n", cmd);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int peci_cmd_xfer(struct peci_adapter *adapter, void *vmsg)
+{
+ struct peci_xfer_msg *msg = vmsg;
+ u8 aw_fcs;
+ int ret;
+
+ if (!msg->tx_len) {
+ ret = peci_xfer(adapter, msg);
+ } else {
+ switch (msg->tx_buf[0]) {
+ case PECI_RDPKGCFG_CMD:
+ case PECI_RDIAMSR_CMD:
+ case PECI_RDIAMSREX_CMD:
+ case PECI_RDPCICFG_CMD:
+ case PECI_RDPCICFGLOCAL_CMD:
+ case PECI_RDENDPTCFG_CMD:
+ case PECI_CRASHDUMP_CMD:
+ ret = peci_xfer_with_retries(adapter, msg, false);
+ break;
+ case PECI_WRPKGCFG_CMD:
+ case PECI_WRIAMSR_CMD:
+ case PECI_WRPCICFG_CMD:
+ case PECI_WRPCICFGLOCAL_CMD:
+ case PECI_WRENDPTCFG_CMD:
+ /* Check if the AW FCS byte is already provided */
+ ret = peci_aw_fcs(msg, 2 + msg->tx_len, &aw_fcs);
+ if (ret)
+ break;
+
+ if (msg->tx_buf[msg->tx_len - 1] != (0x80 ^ aw_fcs)) {
+ /*
+ * Add an Assured Write Frame Check Sequence
+ * byte and increment the tx_len to include
+ * the new byte.
+ */
+ msg->tx_len++;
+ ret = peci_aw_fcs(msg, 2 + msg->tx_len,
+ &aw_fcs);
+ if (ret)
+ break;
+
+ msg->tx_buf[msg->tx_len - 1] = 0x80 ^ aw_fcs;
+ }
+
+ ret = peci_xfer_with_retries(adapter, msg, true);
+ break;
+ case PECI_GET_DIB_CMD:
+ case PECI_GET_TEMP_CMD:
+ default:
+ ret = peci_xfer(adapter, msg);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int peci_cmd_ping(struct peci_adapter *adapter, void *vmsg)
+{
+ struct peci_ping_msg *umsg = vmsg;
+ struct peci_xfer_msg *msg;
+ int ret;
+
+ msg = peci_get_xfer_msg(0, 0);
+ if (!msg)
+ return -ENOMEM;
+
+ msg->addr = umsg->addr;
+
+ ret = peci_xfer(adapter, msg);
+
+ peci_put_xfer_msg(msg);
+
+ return ret;
+}
+
+static int peci_cmd_get_dib(struct peci_adapter *adapter, void *vmsg)
+{
+ struct peci_get_dib_msg *umsg = vmsg;
+ struct peci_xfer_msg *msg;
+ int ret;
+
+ msg = peci_get_xfer_msg(PECI_GET_DIB_WR_LEN, PECI_GET_DIB_RD_LEN);
+ if (!msg)
+ return -ENOMEM;
+
+ msg->addr = umsg->addr;
+ msg->tx_buf[0] = PECI_GET_DIB_CMD;
+
+ ret = peci_xfer(adapter, msg);
+ if (ret)
+ goto out;
+
+ umsg->dib = le64_to_cpup((__le64 *)msg->rx_buf);
+
+out:
+ peci_put_xfer_msg(msg);
+
+ return ret;
+}
+
+static int peci_cmd_get_temp(struct peci_adapter *adapter, void *vmsg)
+{
+ struct peci_get_temp_msg *umsg = vmsg;
+ struct peci_xfer_msg *msg;
+ int ret;
+
+ msg = peci_get_xfer_msg(PECI_GET_TEMP_WR_LEN, PECI_GET_TEMP_RD_LEN);
+ if (!msg)
+ return -ENOMEM;
+
+ msg->addr = umsg->addr;
+ msg->tx_buf[0] = PECI_GET_TEMP_CMD;
+
+ ret = peci_xfer(adapter, msg);
+ if (ret)
+ goto out;
+
+ umsg->temp_raw = le16_to_cpup((__le16 *)msg->rx_buf);
+
+out:
+ peci_put_xfer_msg(msg);
+
+ return ret;
+}
+
+static int peci_cmd_rd_pkg_cfg(struct peci_adapter *adapter, void *vmsg)
+{
+ struct peci_rd_pkg_cfg_msg *umsg = vmsg;
+ struct peci_xfer_msg *msg;
+ int ret;
+
+ /* Per the PECI spec, the read length must be a byte, word, or dword */
+ if (umsg->rx_len != 1 && umsg->rx_len != 2 && umsg->rx_len != 4) {
+ dev_dbg(&adapter->dev, "Invalid read length, rx_len: %d\n",
+ umsg->rx_len);
+ return -EINVAL;
+ }
+
+ msg = peci_get_xfer_msg(PECI_RDPKGCFG_WRITE_LEN,
+ PECI_RDPKGCFG_READ_LEN_BASE + umsg->rx_len);
+ if (!msg)
+ return -ENOMEM;
+
+ msg->addr = umsg->addr;
+ msg->tx_buf[0] = PECI_RDPKGCFG_CMD;
+ msg->tx_buf[1] = 0; /* request byte for Host ID | Retry bit */
+ /* Host ID is 0 for PECI 3.0 */
+ msg->tx_buf[2] = umsg->index; /* RdPkgConfig index */
+ msg->tx_buf[3] = (u8)umsg->param; /* LSB - Config parameter */
+ msg->tx_buf[4] = (u8)(umsg->param >> 8); /* MSB - Config parameter */
+
+ ret = peci_xfer_with_retries(adapter, msg, false);
+ if (!ret)
+ memcpy(umsg->pkg_config, &msg->rx_buf[1], umsg->rx_len);
+
+ umsg->cc = msg->rx_buf[0];
+ peci_put_xfer_msg(msg);
+
+ return ret;
+}
+
+static int peci_cmd_wr_pkg_cfg(struct peci_adapter *adapter, void *vmsg)
+{
+ struct peci_wr_pkg_cfg_msg *umsg = vmsg;
+ struct peci_xfer_msg *msg;
+ int ret, i;
+ u8 aw_fcs;
+
+ /* Per the PECI spec, the write length must be a dword */
+ if (umsg->tx_len != 4) {
+ dev_dbg(&adapter->dev, "Invalid write length, tx_len: %d\n",
+ umsg->tx_len);
+ return -EINVAL;
+ }
+
+ msg = peci_get_xfer_msg(PECI_WRPKGCFG_WRITE_LEN_BASE + umsg->tx_len,
+ PECI_WRPKGCFG_READ_LEN);
+ if (!msg)
+ return -ENOMEM;
+
+ msg->addr = umsg->addr;
+ msg->tx_buf[0] = PECI_WRPKGCFG_CMD;
+ msg->tx_buf[1] = 0; /* request byte for Host ID | Retry bit */
+ /* Host ID is 0 for PECI 3.0 */
+ msg->tx_buf[2] = umsg->index; /* RdPkgConfig index */
+ msg->tx_buf[3] = (u8)umsg->param; /* LSB - Config parameter */
+ msg->tx_buf[4] = (u8)(umsg->param >> 8); /* MSB - Config parameter */
+ for (i = 0; i < umsg->tx_len; i++)
+ msg->tx_buf[5 + i] = (u8)(umsg->value >> (i << 3));
+
+ /* Add an Assured Write Frame Check Sequence byte */
+ ret = peci_aw_fcs(msg, 8 + umsg->tx_len, &aw_fcs);
+ if (ret)
+ goto out;
+
+ msg->tx_buf[5 + i] = 0x80 ^ aw_fcs;
+
+ ret = peci_xfer_with_retries(adapter, msg, true);
+
+out:
+ umsg->cc = msg->rx_buf[0];
+ peci_put_xfer_msg(msg);
+
+ return ret;
+}
+
+static int peci_cmd_rd_ia_msr(struct peci_adapter *adapter, void *vmsg)
+{
+ struct peci_rd_ia_msr_msg *umsg = vmsg;
+ struct peci_xfer_msg *msg;
+ int ret;
+
+ msg = peci_get_xfer_msg(PECI_RDIAMSR_WRITE_LEN, PECI_RDIAMSR_READ_LEN);
+ if (!msg)
+ return -ENOMEM;
+
+ msg->addr = umsg->addr;
+ msg->tx_buf[0] = PECI_RDIAMSR_CMD;
+ msg->tx_buf[1] = 0;
+ msg->tx_buf[2] = umsg->thread_id;
+ msg->tx_buf[3] = (u8)umsg->address;
+ msg->tx_buf[4] = (u8)(umsg->address >> 8);
+
+ ret = peci_xfer_with_retries(adapter, msg, false);
+ if (!ret)
+ memcpy(&umsg->value, &msg->rx_buf[1], sizeof(uint64_t));
+
+ umsg->cc = msg->rx_buf[0];
+ peci_put_xfer_msg(msg);
+
+ return ret;
+}
+
+static int peci_cmd_rd_ia_msrex(struct peci_adapter *adapter, void *vmsg)
+{
+ struct peci_rd_ia_msrex_msg *umsg = vmsg;
+ struct peci_xfer_msg *msg;
+ int ret;
+
+ msg = peci_get_xfer_msg(PECI_RDIAMSREX_WRITE_LEN,
+ PECI_RDIAMSREX_READ_LEN);
+ if (!msg)
+ return -ENOMEM;
+
+ msg->addr = umsg->addr;
+ msg->tx_buf[0] = PECI_RDIAMSREX_CMD;
+ msg->tx_buf[1] = 0;
+ msg->tx_buf[2] = (u8)umsg->thread_id;
+ msg->tx_buf[3] = (u8)(umsg->thread_id >> 8);
+ msg->tx_buf[4] = (u8)umsg->address;
+ msg->tx_buf[5] = (u8)(umsg->address >> 8);
+
+ ret = peci_xfer_with_retries(adapter, msg, false);
+ if (!ret)
+ memcpy(&umsg->value, &msg->rx_buf[1], sizeof(uint64_t));
+
+ umsg->cc = msg->rx_buf[0];
+ peci_put_xfer_msg(msg);
+
+ return ret;
+}
+
+static int peci_cmd_wr_ia_msr(struct peci_adapter *adapter, void *vmsg)
+{
+ return -ENOSYS; /* Not implemented yet */
+}
+
+static int peci_cmd_rd_pci_cfg(struct peci_adapter *adapter, void *vmsg)
+{
+ struct peci_rd_pci_cfg_msg *umsg = vmsg;
+ struct peci_xfer_msg *msg;
+ u32 address;
+ int ret;
+
+ msg = peci_get_xfer_msg(PECI_RDPCICFG_WRITE_LEN,
+ PECI_RDPCICFG_READ_LEN);
+ if (!msg)
+ return -ENOMEM;
+
+ address = umsg->reg; /* [11:0] - Register */
+ address |= (u32)umsg->function << 12; /* [14:12] - Function */
+ address |= (u32)umsg->device << 15; /* [19:15] - Device */
+ address |= (u32)umsg->bus << 20; /* [27:20] - Bus */
+ /* [31:28] - Reserved */
+ msg->addr = umsg->addr;
+ msg->tx_buf[0] = PECI_RDPCICFG_CMD;
+ msg->tx_buf[1] = 0; /* request byte for Host ID | Retry bit */
+ /* Host ID is 0 for PECI 3.0 */
+ msg->tx_buf[2] = (u8)address; /* LSB - PCI Config Address */
+ msg->tx_buf[3] = (u8)(address >> 8); /* PCI Config Address */
+ msg->tx_buf[4] = (u8)(address >> 16); /* PCI Config Address */
+ msg->tx_buf[5] = (u8)(address >> 24); /* MSB - PCI Config Address */
+
+ ret = peci_xfer_with_retries(adapter, msg, false);
+ if (!ret)
+ memcpy(umsg->pci_config, &msg->rx_buf[1], 4);
+
+ umsg->cc = msg->rx_buf[0];
+ peci_put_xfer_msg(msg);
+
+ return ret;
+}
+
+static int peci_cmd_wr_pci_cfg(struct peci_adapter *adapter, void *vmsg)
+{
+ return -ENOSYS; /* Not implemented yet */
+}
+
+static int peci_cmd_rd_pci_cfg_local(struct peci_adapter *adapter, void *vmsg)
+{
+ struct peci_rd_pci_cfg_local_msg *umsg = vmsg;
+ struct peci_xfer_msg *msg;
+ u32 address;
+ int ret;
+
+ /* Per the PECI spec, the read length must be a byte, word, or dword */
+ if (umsg->rx_len != 1 && umsg->rx_len != 2 && umsg->rx_len != 4) {
+ dev_dbg(&adapter->dev, "Invalid read length, rx_len: %d\n",
+ umsg->rx_len);
+ return -EINVAL;
+ }
+
+ msg = peci_get_xfer_msg(PECI_RDPCICFGLOCAL_WRITE_LEN,
+ PECI_RDPCICFGLOCAL_READ_LEN_BASE +
+ umsg->rx_len);
+ if (!msg)
+ return -ENOMEM;
+
+ address = umsg->reg; /* [11:0] - Register */
+ address |= (u32)umsg->function << 12; /* [14:12] - Function */
+ address |= (u32)umsg->device << 15; /* [19:15] - Device */
+ address |= (u32)umsg->bus << 20; /* [23:20] - Bus */
+
+ msg->addr = umsg->addr;
+ msg->tx_buf[0] = PECI_RDPCICFGLOCAL_CMD;
+ msg->tx_buf[1] = 0; /* request byte for Host ID | Retry bit */
+ /* Host ID is 0 for PECI 3.0 */
+ msg->tx_buf[2] = (u8)address; /* LSB - PCI Configuration Address */
+ msg->tx_buf[3] = (u8)(address >> 8); /* PCI Configuration Address */
+ msg->tx_buf[4] = (u8)(address >> 16); /* PCI Configuration Address */
+
+ ret = peci_xfer_with_retries(adapter, msg, false);
+ if (!ret)
+ memcpy(umsg->pci_config, &msg->rx_buf[1], umsg->rx_len);
+
+ umsg->cc = msg->rx_buf[0];
+ peci_put_xfer_msg(msg);
+
+ return ret;
+}
+
+static int peci_cmd_wr_pci_cfg_local(struct peci_adapter *adapter, void *vmsg)
+{
+ struct peci_wr_pci_cfg_local_msg *umsg = vmsg;
+ struct peci_xfer_msg *msg;
+ u32 address;
+ int ret, i;
+ u8 aw_fcs;
+
+ /* Per the PECI spec, the write length must be a byte, word, or dword */
+ if (umsg->tx_len != 1 && umsg->tx_len != 2 && umsg->tx_len != 4) {
+ dev_dbg(&adapter->dev, "Invalid write length, tx_len: %d\n",
+ umsg->tx_len);
+ return -EINVAL;
+ }
+
+ msg = peci_get_xfer_msg(PECI_WRPCICFGLOCAL_WRITE_LEN_BASE +
+ umsg->tx_len, PECI_WRPCICFGLOCAL_READ_LEN);
+ if (!msg)
+ return -ENOMEM;
+
+ address = umsg->reg; /* [11:0] - Register */
+ address |= (u32)umsg->function << 12; /* [14:12] - Function */
+ address |= (u32)umsg->device << 15; /* [19:15] - Device */
+ address |= (u32)umsg->bus << 20; /* [23:20] - Bus */
+
+ msg->addr = umsg->addr;
+ msg->tx_buf[0] = PECI_WRPCICFGLOCAL_CMD;
+ msg->tx_buf[1] = 0; /* request byte for Host ID | Retry bit */
+ /* Host ID is 0 for PECI 3.0 */
+ msg->tx_buf[2] = (u8)address; /* LSB - PCI Configuration Address */
+ msg->tx_buf[3] = (u8)(address >> 8); /* PCI Configuration Address */
+ msg->tx_buf[4] = (u8)(address >> 16); /* PCI Configuration Address */
+ for (i = 0; i < umsg->tx_len; i++)
+ msg->tx_buf[5 + i] = (u8)(umsg->value >> (i << 3));
+
+ /* Add an Assured Write Frame Check Sequence byte */
+ ret = peci_aw_fcs(msg, 8 + umsg->tx_len, &aw_fcs);
+ if (ret)
+ goto out;
+
+ msg->tx_buf[5 + i] = 0x80 ^ aw_fcs;
+
+ ret = peci_xfer_with_retries(adapter, msg, true);
+
+out:
+ umsg->cc = msg->rx_buf[0];
+ peci_put_xfer_msg(msg);
+
+ return ret;
+}
+
+static int peci_cmd_rd_end_pt_cfg(struct peci_adapter *adapter, void *vmsg)
+{
+ struct peci_rd_end_pt_cfg_msg *umsg = vmsg;
+ struct peci_xfer_msg *msg = NULL;
+ u32 address;
+ u8 tx_size;
+ int ret;
+
+ switch (umsg->msg_type) {
+ case PECI_ENDPTCFG_TYPE_LOCAL_PCI:
+ case PECI_ENDPTCFG_TYPE_PCI:
+ /*
+ * Per the PECI spec, the read length must be a byte, word,
+ * or dword
+ */
+ if (umsg->rx_len != 1 && umsg->rx_len != 2 &&
+ umsg->rx_len != 4) {
+ dev_dbg(&adapter->dev,
+ "Invalid read length, rx_len: %d\n",
+ umsg->rx_len);
+ return -EINVAL;
+ }
+
+ msg = peci_get_xfer_msg(PECI_RDENDPTCFG_PCI_WRITE_LEN,
+ PECI_RDENDPTCFG_READ_LEN_BASE +
+ umsg->rx_len);
+ if (!msg)
+ return -ENOMEM;
+
+ address = umsg->params.pci_cfg.reg; /* [11:0] - Register */
+ address |= (u32)umsg->params.pci_cfg.function
+ << 12; /* [14:12] - Function */
+ address |= (u32)umsg->params.pci_cfg.device
+ << 15; /* [19:15] - Device */
+ address |= (u32)umsg->params.pci_cfg.bus
+ << 20; /* [27:20] - Bus */
+ /* [31:28] - Reserved */
+ msg->addr = umsg->addr;
+ msg->tx_buf[0] = PECI_RDENDPTCFG_CMD;
+ msg->tx_buf[1] = 0x00; /* request byte for Host ID|Retry bit */
+ msg->tx_buf[2] = umsg->msg_type; /* Message Type */
+ msg->tx_buf[3] = 0x00; /* Endpoint ID */
+ msg->tx_buf[4] = 0x00; /* Reserved */
+ msg->tx_buf[5] = 0x00; /* Reserved */
+ msg->tx_buf[6] = PECI_ENDPTCFG_ADDR_TYPE_PCI; /* Addr Type */
+ msg->tx_buf[7] = umsg->params.pci_cfg.seg; /* PCI Segment */
+ msg->tx_buf[8] = (u8)address; /* LSB - PCI Config Address */
+ msg->tx_buf[9] = (u8)(address >> 8); /* PCI Config Address */
+ msg->tx_buf[10] = (u8)(address >> 16); /* PCI Config Address */
+ msg->tx_buf[11] =
+ (u8)(address >> 24); /* MSB - PCI Config Address */
+ break;
+
+ case PECI_ENDPTCFG_TYPE_MMIO:
+ /*
+ * Per the PECI spec, the read length must be a byte, word,
+ * dword, or qword
+ */
+ if (umsg->rx_len != 1 && umsg->rx_len != 2 &&
+ umsg->rx_len != 4 && umsg->rx_len != 8) {
+ dev_dbg(&adapter->dev,
+ "Invalid read length, rx_len: %d\n",
+ umsg->rx_len);
+ return -EINVAL;
+ }
+ /*
+ * Per the PECI spec, the address type must specify either DWORD
+ * or QWORD
+ */
+ if (umsg->params.mmio.addr_type !=
+ PECI_ENDPTCFG_ADDR_TYPE_MMIO_D &&
+ umsg->params.mmio.addr_type !=
+ PECI_ENDPTCFG_ADDR_TYPE_MMIO_Q) {
+ dev_dbg(&adapter->dev,
+ "Invalid address type, addr_type: %d\n",
+ umsg->params.mmio.addr_type);
+ return -EINVAL;
+ }
+
+ if (umsg->params.mmio.addr_type ==
+ PECI_ENDPTCFG_ADDR_TYPE_MMIO_D)
+ tx_size = PECI_RDENDPTCFG_MMIO_D_WRITE_LEN;
+ else
+ tx_size = PECI_RDENDPTCFG_MMIO_Q_WRITE_LEN;
+ msg = peci_get_xfer_msg(tx_size,
+ PECI_RDENDPTCFG_READ_LEN_BASE +
+ umsg->rx_len);
+ if (!msg)
+ return -ENOMEM;
+
+ address = umsg->params.mmio.function; /* [2:0] - Function */
+ address |= (u32)umsg->params.mmio.device
+ << 3; /* [7:3] - Device */
+
+ msg->addr = umsg->addr;
+ msg->tx_buf[0] = PECI_RDENDPTCFG_CMD;
+ msg->tx_buf[1] = 0x00; /* request byte for Host ID|Retry bit */
+ msg->tx_buf[2] = umsg->msg_type; /* Message Type */
+ msg->tx_buf[3] = 0x00; /* Endpoint ID */
+ msg->tx_buf[4] = 0x00; /* Reserved */
+ msg->tx_buf[5] = umsg->params.mmio.bar; /* BAR # */
+ msg->tx_buf[6] = umsg->params.mmio.addr_type; /* Address Type */
+ msg->tx_buf[7] = umsg->params.mmio.seg; /* PCI Segment */
+ msg->tx_buf[8] = (u8)address; /* Function/Device */
+ msg->tx_buf[9] = umsg->params.mmio.bus; /* PCI Bus */
+ msg->tx_buf[10] = (u8)umsg->params.mmio
+ .offset; /* LSB - Register Offset */
+ msg->tx_buf[11] = (u8)(umsg->params.mmio.offset
+ >> 8); /* Register Offset */
+ msg->tx_buf[12] = (u8)(umsg->params.mmio.offset
+ >> 16); /* Register Offset */
+ msg->tx_buf[13] = (u8)(umsg->params.mmio.offset
+ >> 24); /* MSB - DWORD Register Offset */
+ if (umsg->params.mmio.addr_type ==
+ PECI_ENDPTCFG_ADDR_TYPE_MMIO_Q) {
+ msg->tx_buf[14] = (u8)(umsg->params.mmio.offset
+ >> 32); /* Register Offset */
+ msg->tx_buf[15] = (u8)(umsg->params.mmio.offset
+ >> 40); /* Register Offset */
+ msg->tx_buf[16] = (u8)(umsg->params.mmio.offset
+ >> 48); /* Register Offset */
+ msg->tx_buf[17] =
+ (u8)(umsg->params.mmio.offset
+ >> 56); /* MSB - QWORD Register Offset */
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ ret = peci_xfer_with_retries(adapter, msg, false);
+ if (!ret)
+ memcpy(umsg->data, &msg->rx_buf[1], umsg->rx_len);
+
+ umsg->cc = msg->rx_buf[0];
+ peci_put_xfer_msg(msg);
+
+ return ret;
+}
+
+static int peci_cmd_wr_end_pt_cfg(struct peci_adapter *adapter, void *vmsg)
+{
+ struct peci_wr_end_pt_cfg_msg *umsg = vmsg;
+ struct peci_xfer_msg *msg = NULL;
+ u8 tx_size, aw_fcs;
+ int ret, i, idx;
+ u32 address;
+
+ switch (umsg->msg_type) {
+ case PECI_ENDPTCFG_TYPE_LOCAL_PCI:
+ case PECI_ENDPTCFG_TYPE_PCI:
+ /*
+ * Per the PECI spec, the write length must be a byte, word,
+ * or dword
+ */
+ if (umsg->tx_len != 1 && umsg->tx_len != 2 &&
+ umsg->tx_len != 4) {
+ dev_dbg(&adapter->dev,
+ "Invalid write length, tx_len: %d\n",
+ umsg->tx_len);
+ return -EINVAL;
+ }
+
+ msg = peci_get_xfer_msg(PECI_WRENDPTCFG_PCI_WRITE_LEN_BASE +
+ umsg->tx_len, PECI_WRENDPTCFG_READ_LEN);
+ if (!msg)
+ return -ENOMEM;
+
+ address = umsg->params.pci_cfg.reg; /* [11:0] - Register */
+ address |= (u32)umsg->params.pci_cfg.function
+ << 12; /* [14:12] - Function */
+ address |= (u32)umsg->params.pci_cfg.device
+ << 15; /* [19:15] - Device */
+ address |= (u32)umsg->params.pci_cfg.bus
+ << 20; /* [27:20] - Bus */
+ /* [31:28] - Reserved */
+ msg->addr = umsg->addr;
+ msg->tx_buf[0] = PECI_WRENDPTCFG_CMD;
+ msg->tx_buf[1] = 0x00; /* request byte for Host ID|Retry bit */
+ msg->tx_buf[2] = umsg->msg_type; /* Message Type */
+ msg->tx_buf[3] = 0x00; /* Endpoint ID */
+ msg->tx_buf[4] = 0x00; /* Reserved */
+ msg->tx_buf[5] = 0x00; /* Reserved */
+ msg->tx_buf[6] = PECI_ENDPTCFG_ADDR_TYPE_PCI; /* Addr Type */
+ msg->tx_buf[7] = umsg->params.pci_cfg.seg; /* PCI Segment */
+ msg->tx_buf[8] = (u8)address; /* LSB - PCI Config Address */
+ msg->tx_buf[9] = (u8)(address >> 8); /* PCI Config Address */
+ msg->tx_buf[10] = (u8)(address >> 16); /* PCI Config Address */
+ msg->tx_buf[11] =
+ (u8)(address >> 24); /* MSB - PCI Config Address */
+ for (i = 0; i < umsg->tx_len; i++)
+ msg->tx_buf[12 + i] = (u8)(umsg->value >> (i << 3));
+
+ /* Add an Assured Write Frame Check Sequence byte */
+ ret = peci_aw_fcs(msg, 15 + umsg->tx_len, &aw_fcs);
+ if (ret)
+ goto out;
+
+ msg->tx_buf[12 + i] = 0x80 ^ aw_fcs;
+ break;
+
+ case PECI_ENDPTCFG_TYPE_MMIO:
+ /*
+ * Per the PECI spec, the write length must be a byte, word,
+ * dword, or qword
+ */
+ if (umsg->tx_len != 1 && umsg->tx_len != 2 &&
+ umsg->tx_len != 4 && umsg->tx_len != 8) {
+ dev_dbg(&adapter->dev,
+ "Invalid write length, tx_len: %d\n",
+ umsg->tx_len);
+ return -EINVAL;
+ }
+ /*
+ * Per the PECI spec, the address type must specify either DWORD
+ * or QWORD
+ */
+ if (umsg->params.mmio.addr_type !=
+ PECI_ENDPTCFG_ADDR_TYPE_MMIO_D &&
+ umsg->params.mmio.addr_type !=
+ PECI_ENDPTCFG_ADDR_TYPE_MMIO_Q) {
+ dev_dbg(&adapter->dev,
+ "Invalid address type, addr_type: %d\n",
+ umsg->params.mmio.addr_type);
+ return -EINVAL;
+ }
+
+ if (umsg->params.mmio.addr_type ==
+ PECI_ENDPTCFG_ADDR_TYPE_MMIO_D)
+ tx_size = PECI_WRENDPTCFG_MMIO_D_WRITE_LEN_BASE +
+ umsg->tx_len;
+ else
+ tx_size = PECI_WRENDPTCFG_MMIO_Q_WRITE_LEN_BASE +
+ umsg->tx_len;
+ msg = peci_get_xfer_msg(tx_size, PECI_WRENDPTCFG_READ_LEN);
+ if (!msg)
+ return -ENOMEM;
+
+ address = umsg->params.mmio.function; /* [2:0] - Function */
+ address |= (u32)umsg->params.mmio.device
+ << 3; /* [7:3] - Device */
+
+ msg->addr = umsg->addr;
+ msg->tx_buf[0] = PECI_WRENDPTCFG_CMD;
+ msg->tx_buf[1] = 0x00; /* request byte for Host ID|Retry bit */
+ msg->tx_buf[2] = umsg->msg_type; /* Message Type */
+ msg->tx_buf[3] = 0x00; /* Endpoint ID */
+ msg->tx_buf[4] = 0x00; /* Reserved */
+ msg->tx_buf[5] = umsg->params.mmio.bar; /* BAR # */
+ msg->tx_buf[6] = umsg->params.mmio.addr_type; /* Address Type */
+ msg->tx_buf[7] = umsg->params.mmio.seg; /* PCI Segment */
+ msg->tx_buf[8] = (u8)address; /* Function/Device */
+ msg->tx_buf[9] = umsg->params.mmio.bus; /* PCI Bus */
+ msg->tx_buf[10] = (u8)umsg->params.mmio
+ .offset; /* LSB - Register Offset */
+ msg->tx_buf[11] = (u8)(umsg->params.mmio.offset
+ >> 8); /* Register Offset */
+ msg->tx_buf[12] = (u8)(umsg->params.mmio.offset
+ >> 16); /* Register Offset */
+ msg->tx_buf[13] = (u8)(umsg->params.mmio.offset
+ >> 24); /* MSB - DWORD Register Offset */
+ if (umsg->params.mmio.addr_type ==
+ PECI_ENDPTCFG_ADDR_TYPE_MMIO_Q) {
+ msg->tx_len = PECI_WRENDPTCFG_MMIO_Q_WRITE_LEN_BASE;
+ msg->tx_buf[14] = (u8)(umsg->params.mmio.offset
+ >> 32); /* Register Offset */
+ msg->tx_buf[15] = (u8)(umsg->params.mmio.offset
+ >> 40); /* Register Offset */
+ msg->tx_buf[16] = (u8)(umsg->params.mmio.offset
+ >> 48); /* Register Offset */
+ msg->tx_buf[17] =
+ (u8)(umsg->params.mmio.offset
+ >> 56); /* MSB - QWORD Register Offset */
+ idx = 18;
+ } else {
+ idx = 14;
+ }
+ for (i = 0; i < umsg->tx_len; i++)
+ msg->tx_buf[idx + i] = (u8)(umsg->value >> (i << 3));
+
+ /* Add an Assured Write Frame Check Sequence byte */
+ ret = peci_aw_fcs(msg, idx + 3 + umsg->tx_len, &aw_fcs);
+ if (ret)
+ goto out;
+
+ msg->tx_buf[idx + i] = 0x80 ^ aw_fcs;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ ret = peci_xfer_with_retries(adapter, msg, false);
+
+out:
+ umsg->cc = msg->rx_buf[0];
+ peci_put_xfer_msg(msg);
+
+ return ret;
+}
+
+static int peci_cmd_crashdump_disc(struct peci_adapter *adapter, void *vmsg)
+{
+ struct peci_crashdump_disc_msg *umsg = vmsg;
+ struct peci_xfer_msg *msg;
+ int ret;
+
+ /* Per the EDS, the read length must be a byte, word, or qword */
+ if (umsg->rx_len != 1 && umsg->rx_len != 2 && umsg->rx_len != 8) {
+ dev_dbg(&adapter->dev, "Invalid read length, rx_len: %d\n",
+ umsg->rx_len);
+ return -EINVAL;
+ }
+
+ msg = peci_get_xfer_msg(PECI_CRASHDUMP_DISC_WRITE_LEN,
+ PECI_CRASHDUMP_DISC_READ_LEN_BASE +
+ umsg->rx_len);
+ if (!msg)
+ return -ENOMEM;
+
+ msg->addr = umsg->addr;
+ msg->tx_buf[0] = PECI_CRASHDUMP_CMD;
+ msg->tx_buf[1] = 0x00; /* request byte for Host ID | Retry bit */
+ /* Host ID is 0 for PECI 3.0 */
+ msg->tx_buf[2] = PECI_CRASHDUMP_DISC_VERSION;
+ msg->tx_buf[3] = PECI_CRASHDUMP_DISC_OPCODE;
+ msg->tx_buf[4] = umsg->subopcode;
+ msg->tx_buf[5] = umsg->param0;
+ msg->tx_buf[6] = (u8)umsg->param1;
+ msg->tx_buf[7] = (u8)(umsg->param1 >> 8);
+ msg->tx_buf[8] = umsg->param2;
+
+ ret = peci_xfer_with_retries(adapter, msg, false);
+ if (!ret)
+ memcpy(umsg->data, &msg->rx_buf[1], umsg->rx_len);
+
+ umsg->cc = msg->rx_buf[0];
+ peci_put_xfer_msg(msg);
+
+ return ret;
+}
+
+static int peci_cmd_crashdump_get_frame(struct peci_adapter *adapter,
+ void *vmsg)
+{
+ struct peci_crashdump_get_frame_msg *umsg = vmsg;
+ struct peci_xfer_msg *msg;
+ int ret;
+
+ /* Per the EDS, the read length must be a qword or dqword */
+ if (umsg->rx_len != 8 && umsg->rx_len != 16) {
+ dev_dbg(&adapter->dev, "Invalid read length, rx_len: %d\n",
+ umsg->rx_len);
+ return -EINVAL;
+ }
+
+ msg = peci_get_xfer_msg(PECI_CRASHDUMP_GET_FRAME_WRITE_LEN,
+ PECI_CRASHDUMP_GET_FRAME_READ_LEN_BASE +
+ umsg->rx_len);
+ if (!msg)
+ return -ENOMEM;
+
+ msg->addr = umsg->addr;
+ msg->tx_buf[0] = PECI_CRASHDUMP_CMD;
+ msg->tx_buf[1] = 0x00; /* request byte for Host ID | Retry bit */
+ /* Host ID is 0 for PECI 3.0 */
+ msg->tx_buf[2] = PECI_CRASHDUMP_GET_FRAME_VERSION;
+ msg->tx_buf[3] = PECI_CRASHDUMP_GET_FRAME_OPCODE;
+ msg->tx_buf[4] = (u8)umsg->param0;
+ msg->tx_buf[5] = (u8)(umsg->param0 >> 8);
+ msg->tx_buf[6] = (u8)umsg->param1;
+ msg->tx_buf[7] = (u8)(umsg->param1 >> 8);
+ msg->tx_buf[8] = (u8)umsg->param2;
+ msg->tx_buf[9] = (u8)(umsg->param2 >> 8);
+
+ ret = peci_xfer_with_retries(adapter, msg, false);
+ if (!ret)
+ memcpy(umsg->data, &msg->rx_buf[1], umsg->rx_len);
+
+ umsg->cc = msg->rx_buf[0];
+ peci_put_xfer_msg(msg);
+
+ return ret;
+}
+
+typedef int (*peci_cmd_fn_type)(struct peci_adapter *, void *);
+
+static const peci_cmd_fn_type peci_cmd_fn[PECI_CMD_MAX] = {
+ peci_cmd_xfer,
+ peci_cmd_ping,
+ peci_cmd_get_dib,
+ peci_cmd_get_temp,
+ peci_cmd_rd_pkg_cfg,
+ peci_cmd_wr_pkg_cfg,
+ peci_cmd_rd_ia_msr,
+ peci_cmd_wr_ia_msr,
+ peci_cmd_rd_ia_msrex,
+ peci_cmd_rd_pci_cfg,
+ peci_cmd_wr_pci_cfg,
+ peci_cmd_rd_pci_cfg_local,
+ peci_cmd_wr_pci_cfg_local,
+ peci_cmd_rd_end_pt_cfg,
+ peci_cmd_wr_end_pt_cfg,
+ peci_cmd_crashdump_disc,
+ peci_cmd_crashdump_get_frame,
+};
+
+/**
+ * peci_command - transfer function of a PECI command
+ * @adapter: pointer to peci_adapter
+ * @vmsg: pointer to PECI messages
+ * Context: can sleep
+ *
+ * This performs a transfer of a PECI command using PECI messages parameter
+ * which has various formats on each command.
+ *
+ * Return: zero on success, else a negative error code.
+ */
+int peci_command(struct peci_adapter *adapter, enum peci_cmd cmd, void *vmsg)
+{
+ int ret;
+
+ if (cmd >= PECI_CMD_MAX || cmd < PECI_CMD_XFER)
+ return -ENOTTY;
+
+ dev_dbg(&adapter->dev, "%s, cmd=0x%02x\n", __func__, cmd);
+
+ if (!peci_cmd_fn[cmd])
+ return -EINVAL;
+
+ mutex_lock(&adapter->bus_lock);
+
+ ret = peci_check_cmd_support(adapter, cmd);
+ if (!ret)
+ ret = peci_cmd_fn[cmd](adapter, vmsg);
+
+ mutex_unlock(&adapter->bus_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(peci_command);
+
+static int peci_detect(struct peci_adapter *adapter, u8 addr)
+{
+ struct peci_ping_msg msg;
+
+ msg.addr = addr;
+
+ return peci_command(adapter, PECI_CMD_PING, &msg);
+}
+
+static const struct of_device_id *
+peci_of_match_device(const struct of_device_id *matches,
+ struct peci_client *client)
+{
+#if IS_ENABLED(CONFIG_OF)
+ if (!(client && matches))
+ return NULL;
+
+ return of_match_device(matches, &client->dev);
+#else /* CONFIG_OF */
+ return NULL;
+#endif /* CONFIG_OF */
+}
+
+static const struct peci_device_id *
+peci_match_id(const struct peci_device_id *id, struct peci_client *client)
+{
+ if (!(id && client))
+ return NULL;
+
+ while (id->name[0]) {
+ if (!strncmp(client->name, id->name, PECI_NAME_SIZE))
+ return id;
+ id++;
+ }
+
+ return NULL;
+}
+
+static int peci_device_match(struct device *dev, struct device_driver *drv)
+{
+ struct peci_client *client = peci_verify_client(dev);
+ struct peci_driver *driver;
+
+ /* Attempt an OF style match */
+ if (peci_of_match_device(drv->of_match_table, client))
+ return 1;
+
+ driver = to_peci_driver(drv);
+
+ /* Finally an ID match */
+ if (peci_match_id(driver->id_table, client))
+ return 1;
+
+ return 0;
+}
+
+static int peci_device_probe(struct device *dev)
+{
+ struct peci_client *client = peci_verify_client(dev);
+ struct peci_driver *driver;
+ int status = -EINVAL;
+
+ if (!client)
+ return 0;
+
+ driver = to_peci_driver(dev->driver);
+
+ if (!driver->id_table &&
+ !peci_of_match_device(dev->driver->of_match_table, client))
+ return -ENODEV;
+
+ dev_dbg(dev, "%s: name:%s\n", __func__, client->name);
+
+ status = dev_pm_domain_attach(&client->dev, true);
+ if (status == -EPROBE_DEFER)
+ return status;
+
+ if (driver->probe)
+ status = driver->probe(client);
+ else
+ status = -EINVAL;
+
+ if (status)
+ goto err_detach_pm_domain;
+
+ return 0;
+
+err_detach_pm_domain:
+ dev_pm_domain_detach(&client->dev, true);
+
+ return status;
+}
+
+static int peci_device_remove(struct device *dev)
+{
+ struct peci_client *client = peci_verify_client(dev);
+ struct peci_driver *driver;
+ int status = 0;
+
+ if (!client || !dev->driver)
+ return 0;
+
+ driver = to_peci_driver(dev->driver);
+ if (driver->remove) {
+ dev_dbg(dev, "%s: name:%s\n", __func__, client->name);
+ status = driver->remove(client);
+ }
+
+ dev_pm_domain_detach(&client->dev, true);
+
+ return status;
+}
+
+static void peci_device_shutdown(struct device *dev)
+{
+ struct peci_client *client = peci_verify_client(dev);
+ struct peci_driver *driver;
+
+ if (!client || !dev->driver)
+ return;
+
+ dev_dbg(dev, "%s: name:%s\n", __func__, client->name);
+
+ driver = to_peci_driver(dev->driver);
+ if (driver->shutdown)
+ driver->shutdown(client);
+}
+
+struct bus_type peci_bus_type = {
+ .name = "peci",
+ .match = peci_device_match,
+ .probe = peci_device_probe,
+ .remove = peci_device_remove,
+ .shutdown = peci_device_shutdown,
+};
+EXPORT_SYMBOL_GPL(peci_bus_type);
+
+static int peci_check_addr_validity(u8 addr)
+{
+ if (addr < PECI_BASE_ADDR && addr > PECI_BASE_ADDR + PECI_OFFSET_MAX)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int peci_check_client_busy(struct device *dev, void *client_new_p)
+{
+ struct peci_client *client = peci_verify_client(dev);
+ struct peci_client *client_new = client_new_p;
+
+ if (client && client->addr == client_new->addr)
+ return -EBUSY;
+
+ return 0;
+}
+
+/**
+ * peci_get_cpu_id - read CPU ID from the Package Configuration Space of CPU
+ * @adapter: pointer to peci_adapter
+ * @addr: address of the PECI client CPU
+ * @cpu_id: where the CPU ID will be stored
+ * Context: can sleep
+ *
+ * Return: zero on success, else a negative error code.
+ */
+int peci_get_cpu_id(struct peci_adapter *adapter, u8 addr, u32 *cpu_id)
+{
+ struct peci_rd_pkg_cfg_msg msg;
+ int ret;
+
+ msg.addr = addr;
+ msg.index = PECI_MBX_INDEX_CPU_ID;
+ msg.param = PECI_PKG_ID_CPU_ID;
+ msg.rx_len = 4;
+
+ ret = peci_command(adapter, PECI_CMD_RD_PKG_CFG, &msg);
+ if (msg.cc != PECI_DEV_CC_SUCCESS)
+ ret = -EAGAIN;
+ if (ret)
+ return ret;
+
+ *cpu_id = le32_to_cpup((__le32 *)msg.pkg_config);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(peci_get_cpu_id);
+
+static struct peci_client *peci_new_device(struct peci_adapter *adapter,
+ struct peci_board_info const *info)
+{
+ struct peci_client *client;
+ int ret;
+
+ /* Increase reference count for the adapter assigned */
+ if (!peci_get_adapter(adapter->nr))
+ return NULL;
+
+ client = kzalloc(sizeof(*client), GFP_KERNEL);
+ if (!client)
+ goto err_put_adapter;
+
+ client->adapter = adapter;
+ client->addr = info->addr;
+ strlcpy(client->name, info->type, sizeof(client->name));
+
+ ret = peci_check_addr_validity(client->addr);
+ if (ret) {
+ dev_err(&adapter->dev, "Invalid PECI CPU address 0x%02hx\n",
+ client->addr);
+ goto err_free_client_silent;
+ }
+
+ /* Check online status of client */
+ ret = peci_detect(adapter, client->addr);
+ if (ret)
+ goto err_free_client;
+
+ ret = device_for_each_child(&adapter->dev, client,
+ peci_check_client_busy);
+ if (ret)
+ goto err_free_client;
+
+ client->dev.parent = &client->adapter->dev;
+ client->dev.bus = &peci_bus_type;
+ client->dev.type = &peci_client_type;
+ client->dev.of_node = of_node_get(info->of_node);
+ dev_set_name(&client->dev, "%d-%02x", adapter->nr, client->addr);
+
+ ret = device_register(&client->dev);
+ if (ret)
+ goto err_put_of_node;
+
+ dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n",
+ client->name, dev_name(&client->dev));
+
+ return client;
+
+err_put_of_node:
+ of_node_put(info->of_node);
+err_free_client:
+ dev_err(&adapter->dev,
+ "Failed to register peci client %s at 0x%02x (%d)\n",
+ client->name, client->addr, ret);
+err_free_client_silent:
+ kfree(client);
+err_put_adapter:
+ peci_put_adapter(adapter);
+
+ return NULL;
+}
+
+static void peci_unregister_device(struct peci_client *client)
+{
+ if (!client)
+ return;
+
+ if (client->dev.of_node) {
+ of_node_clear_flag(client->dev.of_node, OF_POPULATED);
+ of_node_put(client->dev.of_node);
+ }
+
+ device_unregister(&client->dev);
+}
+
+static int peci_unregister_client(struct device *dev, void *dummy)
+{
+ struct peci_client *client = peci_verify_client(dev);
+
+ peci_unregister_device(client);
+
+ return 0;
+}
+
+static void peci_adapter_dev_release(struct device *dev)
+{
+ struct peci_adapter *adapter = to_peci_adapter(dev);
+
+ dev_dbg(dev, "%s: %s\n", __func__, adapter->name);
+ mutex_destroy(&adapter->userspace_clients_lock);
+ mutex_destroy(&adapter->bus_lock);
+ kfree(adapter);
+}
+
+static ssize_t peci_sysfs_new_device(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct peci_adapter *adapter = to_peci_adapter(dev);
+ struct peci_board_info info = {};
+ struct peci_client *client;
+ char *blank, end;
+ short addr;
+ int ret;
+
+ /* Parse device type */
+ blank = strchr(buf, ' ');
+ if (!blank) {
+ dev_err(dev, "%s: Missing parameters\n", "new_device");
+ return -EINVAL;
+ }
+ if (blank - buf > PECI_NAME_SIZE - 1) {
+ dev_err(dev, "%s: Invalid device type\n", "new_device");
+ return -EINVAL;
+ }
+ memcpy(info.type, buf, blank - buf);
+
+ /* Parse remaining parameters, reject extra parameters */
+ ret = sscanf(++blank, "%hi%c", &addr, &end);
+ if (ret < 1) {
+ dev_err(dev, "%s: Can't parse client address\n", "new_device");
+ return -EINVAL;
+ }
+ if (ret > 1 && end != '\n') {
+ dev_err(dev, "%s: Extra parameters\n", "new_device");
+ return -EINVAL;
+ }
+
+ info.addr = (u8)addr;
+ client = peci_new_device(adapter, &info);
+ if (!client)
+ return -EINVAL;
+
+ /* Keep track of the added device */
+ mutex_lock(&adapter->userspace_clients_lock);
+ list_add_tail(&client->detected, &adapter->userspace_clients);
+ mutex_unlock(&adapter->userspace_clients_lock);
+ dev_dbg(dev, "%s: Instantiated device %s at 0x%02hx\n", "new_device",
+ info.type, info.addr);
+
+ return count;
+}
+static DEVICE_ATTR(new_device, 0200, NULL, peci_sysfs_new_device);
+
+static ssize_t peci_sysfs_delete_device(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct peci_adapter *adapter = to_peci_adapter(dev);
+ struct peci_client *client, *next;
+ struct peci_board_info info = {};
+ char *blank, end;
+ short addr;
+ int ret;
+
+ /* Parse device type */
+ blank = strchr(buf, ' ');
+ if (!blank) {
+ dev_err(dev, "%s: Missing parameters\n", "delete_device");
+ return -EINVAL;
+ }
+ if (blank - buf > PECI_NAME_SIZE - 1) {
+ dev_err(dev, "%s: Invalid device type\n", "delete_device");
+ return -EINVAL;
+ }
+ memcpy(info.type, buf, blank - buf);
+
+ /* Parse remaining parameters, reject extra parameters */
+ ret = sscanf(++blank, "%hi%c", &addr, &end);
+ if (ret < 1) {
+ dev_err(dev, "%s: Can't parse client address\n",
+ "delete_device");
+ return -EINVAL;
+ }
+ if (ret > 1 && end != '\n') {
+ dev_err(dev, "%s: Extra parameters\n", "delete_device");
+ return -EINVAL;
+ }
+
+ info.addr = (u8)addr;
+
+ /* Make sure the device was added through sysfs */
+ ret = -ENOENT;
+ mutex_lock(&adapter->userspace_clients_lock);
+ list_for_each_entry_safe(client, next, &adapter->userspace_clients,
+ detected) {
+ if (client->addr == info.addr &&
+ !strncmp(client->name, info.type, PECI_NAME_SIZE)) {
+ dev_dbg(dev, "%s: Deleting device %s at 0x%02hx\n",
+ "delete_device", client->name, client->addr);
+ list_del(&client->detected);
+ peci_unregister_device(client);
+ ret = count;
+ break;
+ }
+ }
+ mutex_unlock(&adapter->userspace_clients_lock);
+
+ if (ret < 0)
+ dev_dbg(dev, "%s: Can't find device in list\n",
+ "delete_device");
+
+ return ret;
+}
+static DEVICE_ATTR_IGNORE_LOCKDEP(delete_device, 0200, NULL,
+ peci_sysfs_delete_device);
+
+static struct attribute *peci_adapter_attrs[] = {
+ &dev_attr_name.attr,
+ &dev_attr_new_device.attr,
+ &dev_attr_delete_device.attr,
+ NULL
+};
+ATTRIBUTE_GROUPS(peci_adapter);
+
+struct device_type peci_adapter_type = {
+ .groups = peci_adapter_groups,
+ .release = peci_adapter_dev_release,
+};
+EXPORT_SYMBOL_GPL(peci_adapter_type);
+
+/**
+ * peci_verify_adapter - return parameter as peci_adapter, or NULL
+ * @dev: device, probably from some driver model iterator
+ *
+ * Return: pointer to peci_adapter on success, else NULL.
+ */
+struct peci_adapter *peci_verify_adapter(struct device *dev)
+{
+ return (dev->type == &peci_adapter_type)
+ ? to_peci_adapter(dev)
+ : NULL;
+}
+EXPORT_SYMBOL_GPL(peci_verify_adapter);
+
+#if IS_ENABLED(CONFIG_OF)
+static struct peci_client *peci_of_register_device(struct peci_adapter *adapter,
+ struct device_node *node)
+{
+ struct peci_board_info info = {};
+ struct peci_client *client;
+ u32 addr;
+ int ret;
+
+ dev_dbg(&adapter->dev, "register %pOF\n", node);
+
+ ret = of_property_read_u32(node, "reg", &addr);
+ if (ret) {
+ dev_err(&adapter->dev, "invalid reg on %pOF\n", node);
+ return ERR_PTR(ret);
+ }
+
+ info.addr = addr;
+ info.of_node = node;
+
+ client = peci_new_device(adapter, &info);
+ if (!client)
+ client = ERR_PTR(-EINVAL);
+
+ return client;
+}
+
+static void peci_of_register_devices(struct peci_adapter *adapter)
+{
+ struct device_node *bus, *node;
+ struct peci_client *client;
+
+ /* Only register child devices if the adapter has a node pointer set */
+ if (!adapter->dev.of_node)
+ return;
+
+ bus = of_get_child_by_name(adapter->dev.of_node, "peci-bus");
+ if (!bus)
+ bus = of_node_get(adapter->dev.of_node);
+
+ for_each_available_child_of_node(bus, node) {
+ if (of_node_test_and_set_flag(node, OF_POPULATED))
+ continue;
+
+ client = peci_of_register_device(adapter, node);
+ if (IS_ERR(client)) {
+ dev_warn(&adapter->dev,
+ "Failed to create PECI device for %pOF\n",
+ node);
+ of_node_clear_flag(node, OF_POPULATED);
+ }
+ }
+
+ of_node_put(bus);
+}
+#else /* CONFIG_OF */
+static void peci_of_register_devices(struct peci_adapter *adapter) { }
+#endif /* CONFIG_OF */
+
+#if IS_ENABLED(CONFIG_OF_DYNAMIC)
+static int peci_of_match_node(struct device *dev, const void *data)
+{
+ return dev->of_node == data;
+}
+
+/* must call put_device() when done with returned peci_client device */
+static struct peci_client *peci_of_find_device(struct device_node *node)
+{
+ struct peci_client *client;
+ struct device *dev;
+
+ dev = bus_find_device(&peci_bus_type, NULL, node, peci_of_match_node);
+ if (!dev)
+ return NULL;
+
+ client = peci_verify_client(dev);
+ if (!client)
+ put_device(dev);
+
+ return client;
+}
+
+/* must call put_device() when done with returned peci_adapter device */
+static struct peci_adapter *peci_of_find_adapter(struct device_node *node)
+{
+ struct peci_adapter *adapter;
+ struct device *dev;
+
+ dev = bus_find_device(&peci_bus_type, NULL, node, peci_of_match_node);
+ if (!dev)
+ return NULL;
+
+ adapter = peci_verify_adapter(dev);
+ if (!adapter)
+ put_device(dev);
+
+ return adapter;
+}
+
+static int peci_of_notify(struct notifier_block *nb, ulong action, void *arg)
+{
+ struct of_reconfig_data *rd = arg;
+ struct peci_adapter *adapter;
+ struct peci_client *client;
+
+ switch (of_reconfig_get_state_change(action, rd)) {
+ case OF_RECONFIG_CHANGE_ADD:
+ adapter = peci_of_find_adapter(rd->dn->parent);
+ if (!adapter)
+ return NOTIFY_OK; /* not for us */
+
+ if (of_node_test_and_set_flag(rd->dn, OF_POPULATED)) {
+ put_device(&adapter->dev);
+ return NOTIFY_OK;
+ }
+
+ client = peci_of_register_device(adapter, rd->dn);
+ put_device(&adapter->dev);
+
+ if (IS_ERR(client)) {
+ dev_err(&adapter->dev,
+ "failed to create client for '%pOF'\n", rd->dn);
+ of_node_clear_flag(rd->dn, OF_POPULATED);
+ return notifier_from_errno(PTR_ERR(client));
+ }
+ break;
+ case OF_RECONFIG_CHANGE_REMOVE:
+ /* already depopulated? */
+ if (!of_node_check_flag(rd->dn, OF_POPULATED))
+ return NOTIFY_OK;
+
+ /* find our device by node */
+ client = peci_of_find_device(rd->dn);
+ if (!client)
+ return NOTIFY_OK; /* no? not meant for us */
+
+ /* unregister takes one ref away */
+ peci_unregister_device(client);
+
+ /* and put the reference of the find */
+ put_device(&client->dev);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block peci_of_notifier = {
+ .notifier_call = peci_of_notify,
+};
+#else /* CONFIG_OF_DYNAMIC */
+extern struct notifier_block peci_of_notifier;
+#endif /* CONFIG_OF_DYNAMIC */
+
+/**
+ * peci_alloc_adapter - allocate a PECI adapter
+ * @dev: the adapter, possibly using the platform_bus
+ * @size: how much zeroed driver-private data to allocate; the pointer to this
+ * memory is in the driver_data field of the returned device,
+ * accessible with peci_get_adapdata().
+ * Context: can sleep
+ *
+ * This call is used only by PECI adapter drivers, which are the only ones
+ * directly touching chip registers. It's how they allocate a peci_adapter
+ * structure, prior to calling peci_add_adapter().
+ *
+ * This must be called from context that can sleep.
+ *
+ * The caller is responsible for initializing the adapter's methods before
+ * calling peci_add_adapter(); and (after errors while adding the device)
+ * calling put_device() to prevent a memory leak.
+ *
+ * Return: the peci_adapter structure on success, else NULL.
+ */
+struct peci_adapter *peci_alloc_adapter(struct device *dev, uint size)
+{
+ struct peci_adapter *adapter;
+
+ if (!dev)
+ return NULL;
+
+ adapter = kzalloc(size + sizeof(*adapter), GFP_KERNEL);
+ if (!adapter)
+ return NULL;
+
+ device_initialize(&adapter->dev);
+ adapter->dev.parent = dev;
+ adapter->dev.bus = &peci_bus_type;
+ adapter->dev.type = &peci_adapter_type;
+ peci_set_adapdata(adapter, &adapter[1]);
+
+ return adapter;
+}
+EXPORT_SYMBOL_GPL(peci_alloc_adapter);
+
+static int peci_register_adapter(struct peci_adapter *adapter)
+{
+ int ret = -EINVAL;
+
+ /* Can't register until after driver model init */
+ if (WARN_ON(!is_registered))
+ goto err_free_idr;
+
+ if (WARN(!adapter->name[0], "peci adapter has no name"))
+ goto err_free_idr;
+
+ if (WARN(!adapter->xfer, "peci adapter has no xfer function\n"))
+ goto err_free_idr;
+
+ mutex_init(&adapter->bus_lock);
+ mutex_init(&adapter->userspace_clients_lock);
+ INIT_LIST_HEAD(&adapter->userspace_clients);
+
+ dev_set_name(&adapter->dev, "peci-%d", adapter->nr);
+
+ ret = device_add(&adapter->dev);
+ if (ret) {
+ pr_err("adapter '%s': can't add device (%d)\n",
+ adapter->name, ret);
+ goto err_free_idr;
+ }
+
+ dev_dbg(&adapter->dev, "adapter [%s] registered\n", adapter->name);
+
+ pm_runtime_no_callbacks(&adapter->dev);
+ pm_suspend_ignore_children(&adapter->dev, true);
+ pm_runtime_enable(&adapter->dev);
+
+ /* create pre-declared device nodes */
+ peci_of_register_devices(adapter);
+
+ return 0;
+
+err_free_idr:
+ mutex_lock(&core_lock);
+ idr_remove(&peci_adapter_idr, adapter->nr);
+ mutex_unlock(&core_lock);
+ return ret;
+}
+
+static int peci_add_numbered_adapter(struct peci_adapter *adapter)
+{
+ int id;
+
+ mutex_lock(&core_lock);
+ id = idr_alloc(&peci_adapter_idr, adapter,
+ adapter->nr, adapter->nr + 1, GFP_KERNEL);
+ mutex_unlock(&core_lock);
+ if (WARN(id < 0, "couldn't get idr"))
+ return id == -ENOSPC ? -EBUSY : id;
+
+ return peci_register_adapter(adapter);
+}
+
+/**
+ * peci_add_adapter - add a PECI adapter
+ * @adapter: initialized adapter, originally from peci_alloc_adapter()
+ * Context: can sleep
+ *
+ * PECI adapters connect to their drivers using some non-PECI bus,
+ * such as the platform bus. The final stage of probe() in that code
+ * includes calling peci_add_adapter() to hook up to this PECI bus glue.
+ *
+ * This must be called from context that can sleep.
+ *
+ * It returns zero on success, else a negative error code (dropping the
+ * adapter's refcount). After a successful return, the caller is responsible
+ * for calling peci_del_adapter().
+ *
+ * Return: zero on success, else a negative error code.
+ */
+int peci_add_adapter(struct peci_adapter *adapter)
+{
+ struct device *dev = &adapter->dev;
+ int id;
+
+ id = of_alias_get_id(dev->of_node, "peci");
+ if (id >= 0) {
+ adapter->nr = id;
+ return peci_add_numbered_adapter(adapter);
+ }
+
+ mutex_lock(&core_lock);
+ id = idr_alloc(&peci_adapter_idr, adapter, 0, 0, GFP_KERNEL);
+ mutex_unlock(&core_lock);
+ if (WARN(id < 0, "couldn't get idr"))
+ return id;
+
+ adapter->nr = id;
+
+ return peci_register_adapter(adapter);
+}
+EXPORT_SYMBOL_GPL(peci_add_adapter);
+
+/**
+ * peci_del_adapter - delete a PECI adapter
+ * @adapter: the adpater being deleted
+ * Context: can sleep
+ *
+ * This call is used only by PECI adpater drivers, which are the only ones
+ * directly touching chip registers.
+ *
+ * This must be called from context that can sleep.
+ *
+ * Note that this function also drops a reference to the adapter.
+ */
+void peci_del_adapter(struct peci_adapter *adapter)
+{
+ struct peci_client *client, *next;
+ struct peci_adapter *found;
+ int nr;
+
+ /* First make sure that this adapter was ever added */
+ mutex_lock(&core_lock);
+ found = idr_find(&peci_adapter_idr, adapter->nr);
+ mutex_unlock(&core_lock);
+
+ if (found != adapter)
+ return;
+
+ /* Remove devices instantiated from sysfs */
+ mutex_lock(&adapter->userspace_clients_lock);
+ list_for_each_entry_safe(client, next, &adapter->userspace_clients,
+ detected) {
+ dev_dbg(&adapter->dev, "Removing %s at 0x%x\n", client->name,
+ client->addr);
+ list_del(&client->detected);
+ peci_unregister_device(client);
+ }
+ mutex_unlock(&adapter->userspace_clients_lock);
+
+ /*
+ * Detach any active clients. This can't fail, thus we do not
+ * check the returned value.
+ */
+ device_for_each_child(&adapter->dev, NULL, peci_unregister_client);
+
+ /* device name is gone after device_unregister */
+ dev_dbg(&adapter->dev, "adapter [%s] unregistered\n", adapter->name);
+
+ pm_runtime_disable(&adapter->dev);
+ nr = adapter->nr;
+ device_unregister(&adapter->dev);
+
+ /* free bus id */
+ mutex_lock(&core_lock);
+ idr_remove(&peci_adapter_idr, nr);
+ mutex_unlock(&core_lock);
+}
+EXPORT_SYMBOL_GPL(peci_del_adapter);
+
+int peci_for_each_dev(void *data, int (*fn)(struct device *, void *))
+{
+ int ret;
+
+ mutex_lock(&core_lock);
+ ret = bus_for_each_dev(&peci_bus_type, NULL, data, fn);
+ mutex_unlock(&core_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(peci_for_each_dev);
+
+/**
+ * peci_register_driver - register a PECI driver
+ * @owner: owner module of the driver being registered
+ * @driver: the driver being registered
+ * Context: can sleep
+ *
+ * Return: zero on success, else a negative error code.
+ */
+int peci_register_driver(struct module *owner, struct peci_driver *driver)
+{
+ int ret;
+
+ /* Can't register until after driver model init */
+ if (WARN_ON(!is_registered))
+ return -EAGAIN;
+
+ /* add the driver to the list of peci drivers in the driver core */
+ driver->driver.owner = owner;
+ driver->driver.bus = &peci_bus_type;
+
+ /*
+ * When registration returns, the driver core
+ * will have called probe() for all matching-but-unbound devices.
+ */
+ ret = driver_register(&driver->driver);
+ if (ret)
+ return ret;
+
+ pr_debug("driver [%s] registered\n", driver->driver.name);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(peci_register_driver);
+
+/**
+ * peci_del_driver - unregister a PECI driver
+ * @driver: the driver being unregistered
+ * Context: can sleep
+ */
+void peci_del_driver(struct peci_driver *driver)
+{
+ driver_unregister(&driver->driver);
+ pr_debug("driver [%s] unregistered\n", driver->driver.name);
+}
+EXPORT_SYMBOL_GPL(peci_del_driver);
+
+static int __init peci_init(void)
+{
+ int ret;
+
+ ret = bus_register(&peci_bus_type);
+ if (ret < 0) {
+ pr_err("peci: Failed to register PECI bus type!\n");
+ return ret;
+ }
+
+ crc8_populate_msb(peci_crc8_table, PECI_CRC8_POLYNOMIAL);
+
+ if (IS_ENABLED(CONFIG_OF_DYNAMIC))
+ WARN_ON(of_reconfig_notifier_register(&peci_of_notifier));
+
+ is_registered = true;
+
+ return 0;
+}
+
+static void __exit peci_exit(void)
+{
+ if (IS_ENABLED(CONFIG_OF_DYNAMIC))
+ WARN_ON(of_reconfig_notifier_unregister(&peci_of_notifier));
+
+ bus_unregister(&peci_bus_type);
+}
+
+subsys_initcall(peci_init);
+module_exit(peci_exit);
+
+MODULE_AUTHOR("Jason M Biils <jason.m.bills@linux.intel.com>");
+MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
+MODULE_DESCRIPTION("PECI bus core module");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/peci/peci-dev.c b/drivers/peci/peci-dev.c
new file mode 100644
index 000000000000..e0fe09467a80
--- /dev/null
+++ b/drivers/peci/peci-dev.c
@@ -0,0 +1,348 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018-2019 Intel Corporation
+
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/peci.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+
+/*
+ * A peci_dev represents an peci_adapter ... an PECI or SMBus master, not a
+ * slave (peci_client) with which messages will be exchanged. It's coupled
+ * with a character special file which is accessed by user mode drivers.
+ *
+ * The list of peci_dev structures is parallel to the peci_adapter lists
+ * maintained by the driver model, and is updated using bus notifications.
+ */
+struct peci_dev {
+ struct list_head list;
+ struct peci_adapter *adapter;
+ struct device *dev;
+ struct cdev cdev;
+};
+
+#define PECI_MINORS MINORMASK
+
+static dev_t peci_devt;
+static LIST_HEAD(peci_dev_list);
+static DEFINE_SPINLOCK(peci_dev_list_lock);
+
+static struct peci_dev *peci_dev_get_by_minor(uint index)
+{
+ struct peci_dev *peci_dev;
+
+ spin_lock(&peci_dev_list_lock);
+ list_for_each_entry(peci_dev, &peci_dev_list, list) {
+ if (peci_dev->adapter->nr == index)
+ goto found;
+ }
+ peci_dev = NULL;
+found:
+ spin_unlock(&peci_dev_list_lock);
+
+ return peci_dev;
+}
+
+static struct peci_dev *peci_dev_alloc(struct peci_adapter *adapter)
+{
+ struct peci_dev *peci_dev;
+
+ if (adapter->nr >= PECI_MINORS) {
+ dev_err(&adapter->dev, "Out of device minors (%d)\n",
+ adapter->nr);
+ return ERR_PTR(-ENODEV);
+ }
+
+ peci_dev = kzalloc(sizeof(*peci_dev), GFP_KERNEL);
+ if (!peci_dev)
+ return ERR_PTR(-ENOMEM);
+ peci_dev->adapter = adapter;
+
+ spin_lock(&peci_dev_list_lock);
+ list_add_tail(&peci_dev->list, &peci_dev_list);
+ spin_unlock(&peci_dev_list_lock);
+
+ return peci_dev;
+}
+
+static void peci_dev_put(struct peci_dev *peci_dev)
+{
+ spin_lock(&peci_dev_list_lock);
+ list_del(&peci_dev->list);
+ spin_unlock(&peci_dev_list_lock);
+ kfree(peci_dev);
+}
+
+static ssize_t name_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct peci_dev *peci_dev = peci_dev_get_by_minor(MINOR(dev->devt));
+
+ if (!peci_dev)
+ return -ENODEV;
+
+ return sprintf(buf, "%s\n", peci_dev->adapter->name);
+}
+static DEVICE_ATTR_RO(name);
+
+static struct attribute *peci_dev_attrs[] = {
+ &dev_attr_name.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(peci_dev);
+
+static long peci_dev_ioctl(struct file *file, uint iocmd, ulong arg)
+{
+ struct peci_dev *peci_dev = file->private_data;
+ void __user *umsg = (void __user *)arg;
+ struct peci_xfer_msg *xmsg = NULL;
+ struct peci_xfer_msg uxmsg;
+ enum peci_cmd cmd;
+ u8 *msg = NULL;
+ uint msg_len;
+ int ret;
+
+ cmd = _IOC_NR(iocmd);
+ msg_len = _IOC_SIZE(iocmd);
+
+ switch (cmd) {
+ case PECI_CMD_XFER:
+ if (msg_len != sizeof(struct peci_xfer_msg)) {
+ ret = -EFAULT;
+ break;
+ }
+
+ if (copy_from_user(&uxmsg, umsg, msg_len)) {
+ ret = -EFAULT;
+ break;
+ }
+
+ xmsg = peci_get_xfer_msg(uxmsg.tx_len, uxmsg.rx_len);
+ if (IS_ERR(xmsg)) {
+ ret = PTR_ERR(xmsg);
+ break;
+ }
+
+ if (uxmsg.tx_len &&
+ copy_from_user(xmsg->tx_buf, (__u8 __user *)uxmsg.tx_buf,
+ uxmsg.tx_len)) {
+ ret = -EFAULT;
+ break;
+ }
+
+ xmsg->addr = uxmsg.addr;
+ xmsg->tx_len = uxmsg.tx_len;
+ xmsg->rx_len = uxmsg.rx_len;
+
+ ret = peci_command(peci_dev->adapter, cmd, xmsg);
+ if (!ret && xmsg->rx_len &&
+ copy_to_user((__u8 __user *)uxmsg.rx_buf, xmsg->rx_buf,
+ xmsg->rx_len))
+ ret = -EFAULT;
+
+ break;
+
+ default:
+ msg = memdup_user(umsg, msg_len);
+ if (IS_ERR(msg)) {
+ ret = PTR_ERR(msg);
+ break;
+ }
+
+ ret = peci_command(peci_dev->adapter, cmd, msg);
+ if ((!ret || ret == -ETIMEDOUT) &&
+ copy_to_user(umsg, msg, msg_len))
+ ret = -EFAULT;
+
+ break;
+ }
+
+ peci_put_xfer_msg(xmsg);
+ kfree(msg);
+
+ return (long)ret;
+}
+
+static int peci_dev_open(struct inode *inode, struct file *file)
+{
+ struct peci_adapter *adapter;
+ struct peci_dev *peci_dev;
+
+ peci_dev = peci_dev_get_by_minor(iminor(inode));
+ if (!peci_dev)
+ return -ENODEV;
+
+ adapter = peci_get_adapter(peci_dev->adapter->nr);
+ if (!adapter)
+ return -ENODEV;
+
+ file->private_data = peci_dev;
+
+ return 0;
+}
+
+static int peci_dev_release(struct inode *inode, struct file *file)
+{
+ struct peci_dev *peci_dev = file->private_data;
+
+ peci_put_adapter(peci_dev->adapter);
+ file->private_data = NULL;
+
+ return 0;
+}
+
+static const struct file_operations peci_dev_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = peci_dev_ioctl,
+ .open = peci_dev_open,
+ .release = peci_dev_release,
+ .llseek = no_llseek,
+};
+
+static struct class *peci_dev_class;
+
+static int peci_dev_attach_adapter(struct device *dev, void *dummy)
+{
+ struct peci_adapter *adapter;
+ struct peci_dev *peci_dev;
+ dev_t devt;
+ int ret;
+
+ if (dev->type != &peci_adapter_type)
+ return 0;
+
+ adapter = to_peci_adapter(dev);
+ peci_dev = peci_dev_alloc(adapter);
+ if (IS_ERR(peci_dev))
+ return PTR_ERR(peci_dev);
+
+ cdev_init(&peci_dev->cdev, &peci_dev_fops);
+ peci_dev->cdev.owner = THIS_MODULE;
+ devt = MKDEV(MAJOR(peci_devt), adapter->nr);
+
+ ret = cdev_add(&peci_dev->cdev, devt, 1);
+ if (ret)
+ goto err_put_dev;
+
+ /* register this peci device with the driver core */
+ peci_dev->dev = device_create(peci_dev_class, &adapter->dev, devt, NULL,
+ "peci-%d", adapter->nr);
+ if (IS_ERR(peci_dev->dev)) {
+ ret = PTR_ERR(peci_dev->dev);
+ goto err_del_cdev;
+ }
+
+ dev_info(dev, "cdev of adapter [%s] registered as minor %d\n",
+ adapter->name, adapter->nr);
+
+ return 0;
+
+err_del_cdev:
+ cdev_del(&peci_dev->cdev);
+err_put_dev:
+ peci_dev_put(peci_dev);
+
+ return ret;
+}
+
+static int peci_dev_detach_adapter(struct device *dev, void *dummy)
+{
+ struct peci_adapter *adapter;
+ struct peci_dev *peci_dev;
+ dev_t devt;
+
+ if (dev->type != &peci_adapter_type)
+ return 0;
+
+ adapter = to_peci_adapter(dev);
+ peci_dev = peci_dev_get_by_minor(adapter->nr);
+ if (!peci_dev)
+ return 0;
+
+ cdev_del(&peci_dev->cdev);
+ devt = peci_dev->dev->devt;
+ peci_dev_put(peci_dev);
+ device_destroy(peci_dev_class, devt);
+
+ dev_info(dev, "cdev of adapter [%s] unregistered\n", adapter->name);
+
+ return 0;
+}
+
+static int peci_dev_notifier_call(struct notifier_block *nb, ulong action,
+ void *data)
+{
+ struct device *dev = data;
+
+ switch (action) {
+ case BUS_NOTIFY_ADD_DEVICE:
+ return peci_dev_attach_adapter(dev, NULL);
+ case BUS_NOTIFY_DEL_DEVICE:
+ return peci_dev_detach_adapter(dev, NULL);
+ }
+
+ return 0;
+}
+
+static struct notifier_block peci_dev_notifier = {
+ .notifier_call = peci_dev_notifier_call,
+};
+
+static int __init peci_dev_init(void)
+{
+ int ret;
+
+ pr_debug("peci /dev entries driver\n");
+
+ ret = alloc_chrdev_region(&peci_devt, 0, PECI_MINORS, "peci");
+ if (ret < 0) {
+ pr_err("peci: Failed to allocate chr dev region!\n");
+ bus_unregister(&peci_bus_type);
+ goto err;
+ }
+
+ peci_dev_class = class_create(THIS_MODULE, KBUILD_MODNAME);
+ if (IS_ERR(peci_dev_class)) {
+ ret = PTR_ERR(peci_dev_class);
+ goto err_unreg_chrdev;
+ }
+ peci_dev_class->dev_groups = peci_dev_groups;
+
+ /* Keep track of adapters which will be added or removed later */
+ ret = bus_register_notifier(&peci_bus_type, &peci_dev_notifier);
+ if (ret)
+ goto err_destroy_class;
+
+ /* Bind to already existing adapters right away */
+ peci_for_each_dev(NULL, peci_dev_attach_adapter);
+
+ return 0;
+
+err_destroy_class:
+ class_destroy(peci_dev_class);
+err_unreg_chrdev:
+ unregister_chrdev_region(peci_devt, PECI_MINORS);
+err:
+ pr_err("%s: Driver Initialization failed\n", __FILE__);
+
+ return ret;
+}
+
+static void __exit peci_dev_exit(void)
+{
+ bus_unregister_notifier(&peci_bus_type, &peci_dev_notifier);
+ peci_for_each_dev(NULL, peci_dev_detach_adapter);
+ class_destroy(peci_dev_class);
+ unregister_chrdev_region(peci_devt, PECI_MINORS);
+}
+
+module_init(peci_dev_init);
+module_exit(peci_dev_exit);
+
+MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
+MODULE_DESCRIPTION("PECI /dev entries driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c
index 95ea593fa29d..bfed0e274643 100644
--- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c
+++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c
@@ -2439,88 +2439,88 @@ static const struct aspeed_pin_function aspeed_g4_functions[] = {
static const struct aspeed_pin_config aspeed_g4_configs[] = {
/* GPIO banks ranges [A, B], [D, J], [M, R] */
- { PIN_CONFIG_BIAS_PULL_DOWN, { D6, D5 }, SCU8C, 16 },
- { PIN_CONFIG_BIAS_DISABLE, { D6, D5 }, SCU8C, 16 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { J21, E18 }, SCU8C, 17 },
- { PIN_CONFIG_BIAS_DISABLE, { J21, E18 }, SCU8C, 17 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { A18, E15 }, SCU8C, 19 },
- { PIN_CONFIG_BIAS_DISABLE, { A18, E15 }, SCU8C, 19 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { D15, B14 }, SCU8C, 20 },
- { PIN_CONFIG_BIAS_DISABLE, { D15, B14 }, SCU8C, 20 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { D18, C17 }, SCU8C, 21 },
- { PIN_CONFIG_BIAS_DISABLE, { D18, C17 }, SCU8C, 21 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { A14, U18 }, SCU8C, 22 },
- { PIN_CONFIG_BIAS_DISABLE, { A14, U18 }, SCU8C, 22 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { A8, E7 }, SCU8C, 23 },
- { PIN_CONFIG_BIAS_DISABLE, { A8, E7 }, SCU8C, 23 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { C22, E20 }, SCU8C, 24 },
- { PIN_CONFIG_BIAS_DISABLE, { C22, E20 }, SCU8C, 24 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { J5, T1 }, SCU8C, 25 },
- { PIN_CONFIG_BIAS_DISABLE, { J5, T1 }, SCU8C, 25 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { U1, U5 }, SCU8C, 26 },
- { PIN_CONFIG_BIAS_DISABLE, { U1, U5 }, SCU8C, 26 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { V3, V5 }, SCU8C, 27 },
- { PIN_CONFIG_BIAS_DISABLE, { V3, V5 }, SCU8C, 27 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { W4, AB2 }, SCU8C, 28 },
- { PIN_CONFIG_BIAS_DISABLE, { W4, AB2 }, SCU8C, 28 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { V6, V7 }, SCU8C, 29 },
- { PIN_CONFIG_BIAS_DISABLE, { V6, V7 }, SCU8C, 29 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { Y6, AB7 }, SCU8C, 30 },
- { PIN_CONFIG_BIAS_DISABLE, { Y6, AB7 }, SCU8C, 30 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { V20, A5 }, SCU8C, 31 },
- { PIN_CONFIG_BIAS_DISABLE, { V20, A5 }, SCU8C, 31 },
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, D6, D5, SCU8C, 16),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, D6, D5, SCU8C, 16),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, J21, E18, SCU8C, 17),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, J21, E18, SCU8C, 17),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, A18, E15, SCU8C, 19),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, A18, E15, SCU8C, 19),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, D15, B14, SCU8C, 20),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, D15, B14, SCU8C, 20),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, D18, C17, SCU8C, 21),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, D18, C17, SCU8C, 21),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, A14, U18, SCU8C, 22),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, A14, U18, SCU8C, 22),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, A8, E7, SCU8C, 23),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, A8, E7, SCU8C, 23),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, C22, E20, SCU8C, 24),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, C22, E20, SCU8C, 24),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, J5, T1, SCU8C, 25),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, J5, T1, SCU8C, 25),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, U1, U5, SCU8C, 26),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, U1, U5, SCU8C, 26),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, V3, V5, SCU8C, 27),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, V3, V5, SCU8C, 27),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, W4, AB2, SCU8C, 28),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, W4, AB2, SCU8C, 28),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, V6, V7, SCU8C, 29),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, V6, V7, SCU8C, 29),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, Y6, AB7, SCU8C, 30),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, Y6, AB7, SCU8C, 30),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, V20, A5, SCU8C, 31),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, V20, A5, SCU8C, 31),
/* GPIOs T[0-5] (RGMII1 Tx pins) */
- { PIN_CONFIG_DRIVE_STRENGTH, { A12, A13 }, SCU90, 9 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { A12, A13 }, SCU90, 12 },
- { PIN_CONFIG_BIAS_DISABLE, { A12, A13 }, SCU90, 12 },
+ ASPEED_SB_PINCONF(PIN_CONFIG_DRIVE_STRENGTH, A12, A13, SCU90, 9),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, A12, A13, SCU90, 12),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, A12, A13, SCU90, 12),
/* GPIOs T[6-7], U[0-3] (RGMII2 TX pins) */
- { PIN_CONFIG_DRIVE_STRENGTH, { D9, D10 }, SCU90, 11 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { D9, D10 }, SCU90, 14 },
- { PIN_CONFIG_BIAS_DISABLE, { D9, D10 }, SCU90, 14 },
+ ASPEED_SB_PINCONF(PIN_CONFIG_DRIVE_STRENGTH, D9, D10, SCU90, 11),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, D9, D10, SCU90, 14),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, D9, D10, SCU90, 14),
/* GPIOs U[4-7], V[0-1] (RGMII1 Rx pins) */
- { PIN_CONFIG_BIAS_PULL_DOWN, { E11, E10 }, SCU90, 13 },
- { PIN_CONFIG_BIAS_DISABLE, { E11, E10 }, SCU90, 13 },
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, E11, E10, SCU90, 13),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, E11, E10, SCU90, 13),
/* GPIOs V[2-7] (RGMII2 Rx pins) */
- { PIN_CONFIG_BIAS_PULL_DOWN, { C9, C8 }, SCU90, 15 },
- { PIN_CONFIG_BIAS_DISABLE, { C9, C8 }, SCU90, 15 },
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, C9, C8, SCU90, 15),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, C9, C8, SCU90, 15),
/* ADC pull-downs (SCUA8[19:4]) */
- { PIN_CONFIG_BIAS_PULL_DOWN, { L5, L5 }, SCUA8, 4 },
- { PIN_CONFIG_BIAS_DISABLE, { L5, L5 }, SCUA8, 4 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { L4, L4 }, SCUA8, 5 },
- { PIN_CONFIG_BIAS_DISABLE, { L4, L4 }, SCUA8, 5 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { L3, L3 }, SCUA8, 6 },
- { PIN_CONFIG_BIAS_DISABLE, { L3, L3 }, SCUA8, 6 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { L2, L2 }, SCUA8, 7 },
- { PIN_CONFIG_BIAS_DISABLE, { L2, L2 }, SCUA8, 7 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { L1, L1 }, SCUA8, 8 },
- { PIN_CONFIG_BIAS_DISABLE, { L1, L1 }, SCUA8, 8 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { M5, M5 }, SCUA8, 9 },
- { PIN_CONFIG_BIAS_DISABLE, { M5, M5 }, SCUA8, 9 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { M4, M4 }, SCUA8, 10 },
- { PIN_CONFIG_BIAS_DISABLE, { M4, M4 }, SCUA8, 10 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { M3, M3 }, SCUA8, 11 },
- { PIN_CONFIG_BIAS_DISABLE, { M3, M3 }, SCUA8, 11 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { M2, M2 }, SCUA8, 12 },
- { PIN_CONFIG_BIAS_DISABLE, { M2, M2 }, SCUA8, 12 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { M1, M1 }, SCUA8, 13 },
- { PIN_CONFIG_BIAS_DISABLE, { M1, M1 }, SCUA8, 13 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { N5, N5 }, SCUA8, 14 },
- { PIN_CONFIG_BIAS_DISABLE, { N5, N5 }, SCUA8, 14 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { N4, N4 }, SCUA8, 15 },
- { PIN_CONFIG_BIAS_DISABLE, { N4, N4 }, SCUA8, 15 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { N3, N3 }, SCUA8, 16 },
- { PIN_CONFIG_BIAS_DISABLE, { N3, N3 }, SCUA8, 16 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { N2, N2 }, SCUA8, 17 },
- { PIN_CONFIG_BIAS_DISABLE, { N2, N2 }, SCUA8, 17 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { N1, N1 }, SCUA8, 18 },
- { PIN_CONFIG_BIAS_DISABLE, { N1, N1 }, SCUA8, 18 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { P5, P5 }, SCUA8, 19 },
- { PIN_CONFIG_BIAS_DISABLE, { P5, P5 }, SCUA8, 19 },
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, L5, L5, SCUA8, 4),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, L5, L5, SCUA8, 4),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, L4, L4, SCUA8, 5),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, L4, L4, SCUA8, 5),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, L3, L3, SCUA8, 6),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, L3, L3, SCUA8, 6),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, L2, L2, SCUA8, 7),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, L2, L2, SCUA8, 7),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, L1, L1, SCUA8, 8),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, L1, L1, SCUA8, 8),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, M5, M5, SCUA8, 9),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, M5, M5, SCUA8, 9),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, M4, M4, SCUA8, 10),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, M4, M4, SCUA8, 10),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, M3, M3, SCUA8, 11),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, M3, M3, SCUA8, 11),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, M2, M2, SCUA8, 12),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, M2, M2, SCUA8, 12),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, M1, M1, SCUA8, 13),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, M1, M1, SCUA8, 13),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, N5, N5, SCUA8, 14),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, N5, N5, SCUA8, 14),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, N4, N4, SCUA8, 15),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, N4, N4, SCUA8, 15),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, N3, N3, SCUA8, 16),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, N3, N3, SCUA8, 16),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, N2, N2, SCUA8, 17),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, N2, N2, SCUA8, 17),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, N1, N1, SCUA8, 18),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, N1, N1, SCUA8, 18),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, P5, P5, SCUA8, 19),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, P5, P5, SCUA8, 19),
/*
* Debounce settings for GPIOs D and E passthrough mode are in
@@ -2531,14 +2531,14 @@ static const struct aspeed_pin_config aspeed_g4_configs[] = {
* controller. Due to this tangle between GPIO and pinctrl we don't yet
* fully support pass-through debounce.
*/
- { PIN_CONFIG_INPUT_DEBOUNCE, { A18, D16 }, SCUA8, 20 },
- { PIN_CONFIG_INPUT_DEBOUNCE, { B17, A17 }, SCUA8, 21 },
- { PIN_CONFIG_INPUT_DEBOUNCE, { C16, B16 }, SCUA8, 22 },
- { PIN_CONFIG_INPUT_DEBOUNCE, { A16, E15 }, SCUA8, 23 },
- { PIN_CONFIG_INPUT_DEBOUNCE, { D15, C15 }, SCUA8, 24 },
- { PIN_CONFIG_INPUT_DEBOUNCE, { B15, A15 }, SCUA8, 25 },
- { PIN_CONFIG_INPUT_DEBOUNCE, { E14, D14 }, SCUA8, 26 },
- { PIN_CONFIG_INPUT_DEBOUNCE, { C14, B14 }, SCUA8, 27 },
+ ASPEED_SB_PINCONF(PIN_CONFIG_INPUT_DEBOUNCE, A18, D16, SCUA8, 20),
+ ASPEED_SB_PINCONF(PIN_CONFIG_INPUT_DEBOUNCE, B17, A17, SCUA8, 21),
+ ASPEED_SB_PINCONF(PIN_CONFIG_INPUT_DEBOUNCE, C16, B16, SCUA8, 22),
+ ASPEED_SB_PINCONF(PIN_CONFIG_INPUT_DEBOUNCE, A16, E15, SCUA8, 23),
+ ASPEED_SB_PINCONF(PIN_CONFIG_INPUT_DEBOUNCE, D15, C15, SCUA8, 24),
+ ASPEED_SB_PINCONF(PIN_CONFIG_INPUT_DEBOUNCE, B15, A15, SCUA8, 25),
+ ASPEED_SB_PINCONF(PIN_CONFIG_INPUT_DEBOUNCE, E14, D14, SCUA8, 26),
+ ASPEED_SB_PINCONF(PIN_CONFIG_INPUT_DEBOUNCE, C14, B14, SCUA8, 27),
};
static int aspeed_g4_sig_expr_set(struct aspeed_pinmux_data *ctx,
@@ -2594,6 +2594,14 @@ static int aspeed_g4_sig_expr_set(struct aspeed_pinmux_data *ctx,
return 0;
}
+static const struct aspeed_pin_config_map aspeed_g4_pin_config_map[] = {
+ { PIN_CONFIG_BIAS_PULL_DOWN, 0, 1, BIT_MASK(0)},
+ { PIN_CONFIG_BIAS_PULL_DOWN, -1, 0, BIT_MASK(0)},
+ { PIN_CONFIG_BIAS_DISABLE, -1, 1, BIT_MASK(0)},
+ { PIN_CONFIG_DRIVE_STRENGTH, 8, 0, BIT_MASK(0)},
+ { PIN_CONFIG_DRIVE_STRENGTH, 16, 1, BIT_MASK(0)},
+};
+
static const struct aspeed_pinmux_ops aspeed_g4_ops = {
.set = aspeed_g4_sig_expr_set,
};
@@ -2610,6 +2618,8 @@ static struct aspeed_pinctrl_data aspeed_g4_pinctrl_data = {
},
.configs = aspeed_g4_configs,
.nconfigs = ARRAY_SIZE(aspeed_g4_configs),
+ .confmaps = aspeed_g4_pin_config_map,
+ .nconfmaps = ARRAY_SIZE(aspeed_g4_pin_config_map),
};
static const struct pinmux_ops aspeed_g4_pinmux_ops = {
diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c
index d8a804b9f958..0cab4c2576e2 100644
--- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c
+++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c
@@ -2476,124 +2476,124 @@ static const struct aspeed_pin_function aspeed_g5_functions[] = {
static struct aspeed_pin_config aspeed_g5_configs[] = {
/* GPIOA, GPIOQ */
- { PIN_CONFIG_BIAS_PULL_DOWN, { B14, B13 }, SCU8C, 16 },
- { PIN_CONFIG_BIAS_DISABLE, { B14, B13 }, SCU8C, 16 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { A11, N20 }, SCU8C, 16 },
- { PIN_CONFIG_BIAS_DISABLE, { A11, N20 }, SCU8C, 16 },
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, B14, B13, SCU8C, 16),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, B14, B13, SCU8C, 16),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, A11, N20, SCU8C, 16),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, A11, N20, SCU8C, 16),
/* GPIOB, GPIOR */
- { PIN_CONFIG_BIAS_PULL_DOWN, { K19, H20 }, SCU8C, 17 },
- { PIN_CONFIG_BIAS_DISABLE, { K19, H20 }, SCU8C, 17 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { AA19, E10 }, SCU8C, 17 },
- { PIN_CONFIG_BIAS_DISABLE, { AA19, E10 }, SCU8C, 17 },
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, K19, H20, SCU8C, 17),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, K19, H20, SCU8C, 17),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, AA19, E10, SCU8C, 17),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, AA19, E10, SCU8C, 17),
/* GPIOC, GPIOS*/
- { PIN_CONFIG_BIAS_PULL_DOWN, { C12, B11 }, SCU8C, 18 },
- { PIN_CONFIG_BIAS_DISABLE, { C12, B11 }, SCU8C, 18 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { V20, AA20 }, SCU8C, 18 },
- { PIN_CONFIG_BIAS_DISABLE, { V20, AA20 }, SCU8C, 18 },
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, C12, B11, SCU8C, 18),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, C12, B11, SCU8C, 18),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, V20, AA20, SCU8C, 18),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, V20, AA20, SCU8C, 18),
/* GPIOD, GPIOY */
- { PIN_CONFIG_BIAS_PULL_DOWN, { F19, C21 }, SCU8C, 19 },
- { PIN_CONFIG_BIAS_DISABLE, { F19, C21 }, SCU8C, 19 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { R22, P20 }, SCU8C, 19 },
- { PIN_CONFIG_BIAS_DISABLE, { R22, P20 }, SCU8C, 19 },
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, F19, C21, SCU8C, 19),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, F19, C21, SCU8C, 19),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, R22, P20, SCU8C, 19),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, R22, P20, SCU8C, 19),
/* GPIOE, GPIOZ */
- { PIN_CONFIG_BIAS_PULL_DOWN, { B20, B19 }, SCU8C, 20 },
- { PIN_CONFIG_BIAS_DISABLE, { B20, B19 }, SCU8C, 20 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { Y20, W21 }, SCU8C, 20 },
- { PIN_CONFIG_BIAS_DISABLE, { Y20, W21 }, SCU8C, 20 },
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, B20, B19, SCU8C, 20),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, B20, B19, SCU8C, 20),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, Y20, W21, SCU8C, 20),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, Y20, W21, SCU8C, 20),
/* GPIOF, GPIOAA */
- { PIN_CONFIG_BIAS_PULL_DOWN, { J19, H18 }, SCU8C, 21 },
- { PIN_CONFIG_BIAS_DISABLE, { J19, H18 }, SCU8C, 21 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { Y21, P19 }, SCU8C, 21 },
- { PIN_CONFIG_BIAS_DISABLE, { Y21, P19 }, SCU8C, 21 },
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, J19, H18, SCU8C, 21),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, J19, H18, SCU8C, 21),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, Y21, P19, SCU8C, 21),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, Y21, P19, SCU8C, 21),
- /* GPIOG, GPIOAB */
- { PIN_CONFIG_BIAS_PULL_DOWN, { A19, E14 }, SCU8C, 22 },
- { PIN_CONFIG_BIAS_DISABLE, { A19, E14 }, SCU8C, 22 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { N19, R20 }, SCU8C, 22 },
- { PIN_CONFIG_BIAS_DISABLE, { N19, R20 }, SCU8C, 22 },
+ /* GPIOG, GPIOAB */
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, A19, E14, SCU8C, 22),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, A19, E14, SCU8C, 22),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, N19, R20, SCU8C, 22),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, N19, R20, SCU8C, 22),
/* GPIOH, GPIOAC */
- { PIN_CONFIG_BIAS_PULL_DOWN, { A18, D18 }, SCU8C, 23 },
- { PIN_CONFIG_BIAS_DISABLE, { A18, D18 }, SCU8C, 23 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { G21, G22 }, SCU8C, 23 },
- { PIN_CONFIG_BIAS_DISABLE, { G21, G22 }, SCU8C, 23 },
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, A18, D18, SCU8C, 23),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, A18, D18, SCU8C, 23),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, G21, G22, SCU8C, 23),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, G21, G22, SCU8C, 23),
/* GPIOs [I, P] */
- { PIN_CONFIG_BIAS_PULL_DOWN, { C18, A15 }, SCU8C, 24 },
- { PIN_CONFIG_BIAS_DISABLE, { C18, A15 }, SCU8C, 24 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { R2, T3 }, SCU8C, 25 },
- { PIN_CONFIG_BIAS_DISABLE, { R2, T3 }, SCU8C, 25 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { L3, R1 }, SCU8C, 26 },
- { PIN_CONFIG_BIAS_DISABLE, { L3, R1 }, SCU8C, 26 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { T2, W1 }, SCU8C, 27 },
- { PIN_CONFIG_BIAS_DISABLE, { T2, W1 }, SCU8C, 27 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { Y1, T5 }, SCU8C, 28 },
- { PIN_CONFIG_BIAS_DISABLE, { Y1, T5 }, SCU8C, 28 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { V2, T4 }, SCU8C, 29 },
- { PIN_CONFIG_BIAS_DISABLE, { V2, T4 }, SCU8C, 29 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { U5, W4 }, SCU8C, 30 },
- { PIN_CONFIG_BIAS_DISABLE, { U5, W4 }, SCU8C, 30 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { V4, V6 }, SCU8C, 31 },
- { PIN_CONFIG_BIAS_DISABLE, { V4, V6 }, SCU8C, 31 },
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, C18, A15, SCU8C, 24),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, C18, A15, SCU8C, 24),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, R2, T3, SCU8C, 25),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, R2, T3, SCU8C, 25),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, L3, R1, SCU8C, 26),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, L3, R1, SCU8C, 26),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, T2, W1, SCU8C, 27),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, T2, W1, SCU8C, 27),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, Y1, T5, SCU8C, 28),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, Y1, T5, SCU8C, 28),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, V2, T4, SCU8C, 29),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, V2, T4, SCU8C, 29),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, U5, W4, SCU8C, 30),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, U5, W4, SCU8C, 30),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, V4, V6, SCU8C, 31),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, V4, V6, SCU8C, 31),
/* GPIOs T[0-5] (RGMII1 Tx pins) */
- { PIN_CONFIG_DRIVE_STRENGTH, { B5, B5 }, SCU90, 8 },
- { PIN_CONFIG_DRIVE_STRENGTH, { E9, A5 }, SCU90, 9 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { B5, D7 }, SCU90, 12 },
- { PIN_CONFIG_BIAS_DISABLE, { B5, D7 }, SCU90, 12 },
+ ASPEED_SB_PINCONF(PIN_CONFIG_DRIVE_STRENGTH, B5, B5, SCU90, 8),
+ ASPEED_SB_PINCONF(PIN_CONFIG_DRIVE_STRENGTH, E9, A5, SCU90, 9),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, B5, D7, SCU90, 12),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, B5, D7, SCU90, 12),
/* GPIOs T[6-7], U[0-3] (RGMII2 TX pins) */
- { PIN_CONFIG_DRIVE_STRENGTH, { B2, B2 }, SCU90, 10 },
- { PIN_CONFIG_DRIVE_STRENGTH, { B1, B3 }, SCU90, 11 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { B2, D4 }, SCU90, 14 },
- { PIN_CONFIG_BIAS_DISABLE, { B2, D4 }, SCU90, 14 },
+ ASPEED_SB_PINCONF(PIN_CONFIG_DRIVE_STRENGTH, B2, B2, SCU90, 10),
+ ASPEED_SB_PINCONF(PIN_CONFIG_DRIVE_STRENGTH, B1, B3, SCU90, 11),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, B2, D4, SCU90, 14),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, B2, D4, SCU90, 14),
/* GPIOs U[4-7], V[0-1] (RGMII1 Rx pins) */
- { PIN_CONFIG_BIAS_PULL_DOWN, { B4, C4 }, SCU90, 13 },
- { PIN_CONFIG_BIAS_DISABLE, { B4, C4 }, SCU90, 13 },
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, B4, C4, SCU90, 13),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, B4, C4, SCU90, 13),
/* GPIOs V[2-7] (RGMII2 Rx pins) */
- { PIN_CONFIG_BIAS_PULL_DOWN, { C2, E6 }, SCU90, 15 },
- { PIN_CONFIG_BIAS_DISABLE, { C2, E6 }, SCU90, 15 },
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, C2, E6, SCU90, 15),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, C2, E6, SCU90, 15),
/* ADC pull-downs (SCUA8[19:4]) */
- { PIN_CONFIG_BIAS_PULL_DOWN, { F4, F4 }, SCUA8, 4 },
- { PIN_CONFIG_BIAS_DISABLE, { F4, F4 }, SCUA8, 4 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { F5, F5 }, SCUA8, 5 },
- { PIN_CONFIG_BIAS_DISABLE, { F5, F5 }, SCUA8, 5 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { E2, E2 }, SCUA8, 6 },
- { PIN_CONFIG_BIAS_DISABLE, { E2, E2 }, SCUA8, 6 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { E1, E1 }, SCUA8, 7 },
- { PIN_CONFIG_BIAS_DISABLE, { E1, E1 }, SCUA8, 7 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { F3, F3 }, SCUA8, 8 },
- { PIN_CONFIG_BIAS_DISABLE, { F3, F3 }, SCUA8, 8 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { E3, E3 }, SCUA8, 9 },
- { PIN_CONFIG_BIAS_DISABLE, { E3, E3 }, SCUA8, 9 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { G5, G5 }, SCUA8, 10 },
- { PIN_CONFIG_BIAS_DISABLE, { G5, G5 }, SCUA8, 10 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { G4, G4 }, SCUA8, 11 },
- { PIN_CONFIG_BIAS_DISABLE, { G4, G4 }, SCUA8, 11 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { F2, F2 }, SCUA8, 12 },
- { PIN_CONFIG_BIAS_DISABLE, { F2, F2 }, SCUA8, 12 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { G3, G3 }, SCUA8, 13 },
- { PIN_CONFIG_BIAS_DISABLE, { G3, G3 }, SCUA8, 13 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { G2, G2 }, SCUA8, 14 },
- { PIN_CONFIG_BIAS_DISABLE, { G2, G2 }, SCUA8, 14 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { F1, F1 }, SCUA8, 15 },
- { PIN_CONFIG_BIAS_DISABLE, { F1, F1 }, SCUA8, 15 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { H5, H5 }, SCUA8, 16 },
- { PIN_CONFIG_BIAS_DISABLE, { H5, H5 }, SCUA8, 16 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { G1, G1 }, SCUA8, 17 },
- { PIN_CONFIG_BIAS_DISABLE, { G1, G1 }, SCUA8, 17 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { H3, H3 }, SCUA8, 18 },
- { PIN_CONFIG_BIAS_DISABLE, { H3, H3 }, SCUA8, 18 },
- { PIN_CONFIG_BIAS_PULL_DOWN, { H4, H4 }, SCUA8, 19 },
- { PIN_CONFIG_BIAS_DISABLE, { H4, H4 }, SCUA8, 19 },
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, F4, F4, SCUA8, 4),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, F4, F4, SCUA8, 4),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, F5, F5, SCUA8, 5),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, F5, F5, SCUA8, 5),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, E2, E2, SCUA8, 6),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, E2, E2, SCUA8, 6),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, E1, E1, SCUA8, 7),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, E1, E1, SCUA8, 7),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, F3, F3, SCUA8, 8),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, F3, F3, SCUA8, 8),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, E3, E3, SCUA8, 9),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, E3, E3, SCUA8, 9),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, G5, G5, SCUA8, 10),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, G5, G5, SCUA8, 10),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, G4, G4, SCUA8, 11),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, G4, G4, SCUA8, 11),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, F2, F2, SCUA8, 12),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, F2, F2, SCUA8, 12),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, G3, G3, SCUA8, 13),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, G3, G3, SCUA8, 13),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, G2, G2, SCUA8, 14),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, G2, G2, SCUA8, 14),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, F1, F1, SCUA8, 15),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, F1, F1, SCUA8, 15),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, H5, H5, SCUA8, 16),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, H5, H5, SCUA8, 16),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, G1, G1, SCUA8, 17),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, G1, G1, SCUA8, 17),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, H3, H3, SCUA8, 18),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, H3, H3, SCUA8, 18),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, H4, H4, SCUA8, 19),
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, H4, H4, SCUA8, 19),
/*
* Debounce settings for GPIOs D and E passthrough mode are in
@@ -2604,14 +2604,14 @@ static struct aspeed_pin_config aspeed_g5_configs[] = {
* controller. Due to this tangle between GPIO and pinctrl we don't yet
* fully support pass-through debounce.
*/
- { PIN_CONFIG_INPUT_DEBOUNCE, { F19, E21 }, SCUA8, 20 },
- { PIN_CONFIG_INPUT_DEBOUNCE, { F20, D20 }, SCUA8, 21 },
- { PIN_CONFIG_INPUT_DEBOUNCE, { D21, E20 }, SCUA8, 22 },
- { PIN_CONFIG_INPUT_DEBOUNCE, { G18, C21 }, SCUA8, 23 },
- { PIN_CONFIG_INPUT_DEBOUNCE, { B20, C20 }, SCUA8, 24 },
- { PIN_CONFIG_INPUT_DEBOUNCE, { F18, F17 }, SCUA8, 25 },
- { PIN_CONFIG_INPUT_DEBOUNCE, { E18, D19 }, SCUA8, 26 },
- { PIN_CONFIG_INPUT_DEBOUNCE, { A20, B19 }, SCUA8, 27 },
+ ASPEED_SB_PINCONF(PIN_CONFIG_INPUT_DEBOUNCE, F19, E21, SCUA8, 20),
+ ASPEED_SB_PINCONF(PIN_CONFIG_INPUT_DEBOUNCE, F20, D20, SCUA8, 21),
+ ASPEED_SB_PINCONF(PIN_CONFIG_INPUT_DEBOUNCE, D21, E20, SCUA8, 22),
+ ASPEED_SB_PINCONF(PIN_CONFIG_INPUT_DEBOUNCE, G18, C21, SCUA8, 23),
+ ASPEED_SB_PINCONF(PIN_CONFIG_INPUT_DEBOUNCE, B20, C20, SCUA8, 24),
+ ASPEED_SB_PINCONF(PIN_CONFIG_INPUT_DEBOUNCE, F18, F17, SCUA8, 25),
+ ASPEED_SB_PINCONF(PIN_CONFIG_INPUT_DEBOUNCE, E18, D19, SCUA8, 26),
+ ASPEED_SB_PINCONF(PIN_CONFIG_INPUT_DEBOUNCE, A20, B19, SCUA8, 27),
};
static struct regmap *aspeed_g5_acquire_regmap(struct aspeed_pinmux_data *ctx,
@@ -2780,6 +2780,14 @@ static int aspeed_g5_sig_expr_set(struct aspeed_pinmux_data *ctx,
return 0;
}
+static const struct aspeed_pin_config_map aspeed_g5_pin_config_map[] = {
+ { PIN_CONFIG_BIAS_PULL_DOWN, 0, 1, BIT_MASK(0)},
+ { PIN_CONFIG_BIAS_PULL_DOWN, -1, 0, BIT_MASK(0)},
+ { PIN_CONFIG_BIAS_DISABLE, -1, 1, BIT_MASK(0)},
+ { PIN_CONFIG_DRIVE_STRENGTH, 8, 0, BIT_MASK(0)},
+ { PIN_CONFIG_DRIVE_STRENGTH, 16, 1, BIT_MASK(0)},
+};
+
static const struct aspeed_pinmux_ops aspeed_g5_ops = {
.eval = aspeed_g5_sig_expr_eval,
.set = aspeed_g5_sig_expr_set,
@@ -2797,6 +2805,8 @@ static struct aspeed_pinctrl_data aspeed_g5_pinctrl_data = {
},
.configs = aspeed_g5_configs,
.nconfigs = ARRAY_SIZE(aspeed_g5_configs),
+ .confmaps = aspeed_g5_pin_config_map,
+ .nconfmaps = ARRAY_SIZE(aspeed_g5_pin_config_map),
};
static const struct pinmux_ops aspeed_g5_pinmux_ops = {
diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c
index bb07024d22ed..7efe6dbe4398 100644
--- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c
+++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c
@@ -26,7 +26,10 @@
#define SCU430 0x430 /* Multi-function Pin Control #8 */
#define SCU434 0x434 /* Multi-function Pin Control #9 */
#define SCU438 0x438 /* Multi-function Pin Control #10 */
+#define SCU440 0x440 /* USB Multi-function Pin Control #12 */
#define SCU450 0x450 /* Multi-function Pin Control #14 */
+#define SCU454 0x454 /* Multi-function Pin Control #15 */
+#define SCU458 0x458 /* Multi-function Pin Control #16 */
#define SCU4B0 0x4B0 /* Multi-function Pin Control #17 */
#define SCU4B4 0x4B4 /* Multi-function Pin Control #18 */
#define SCU4B8 0x4B8 /* Multi-function Pin Control #19 */
@@ -35,9 +38,18 @@
#define SCU4D8 0x4D8 /* Multi-function Pin Control #23 */
#define SCU500 0x500 /* Hardware Strap 1 */
#define SCU510 0x510 /* Hardware Strap 2 */
+#define SCU610 0x610 /* Disable GPIO Internal Pull-Down #0 */
+#define SCU614 0x614 /* Disable GPIO Internal Pull-Down #1 */
+#define SCU618 0x618 /* Disable GPIO Internal Pull-Down #2 */
+#define SCU61C 0x61c /* Disable GPIO Internal Pull-Down #3 */
+#define SCU620 0x620 /* Disable GPIO Internal Pull-Down #4 */
+#define SCU634 0x634 /* Disable GPIO Internal Pull-Down #5 */
+#define SCU638 0x638 /* Disable GPIO Internal Pull-Down #6 */
#define SCU694 0x694 /* Multi-function Pin Control #25 */
+#define SCU69C 0x69C /* Multi-function Pin Control #27 */
+#define SCUC20 0xC20 /* PCIE configuration Setting Control */
-#define ASPEED_G6_NR_PINS 248
+#define ASPEED_G6_NR_PINS 256
#define M24 0
SIG_EXPR_LIST_DECL_SESG(M24, MDC3, MDIO3, SIG_DESC_SET(SCU410, 0));
@@ -808,11 +820,13 @@ FUNC_DECL_2(PWM14, PWM14G0, PWM14G1);
#define Y23 127
SIG_EXPR_LIST_DECL_SEMG(Y23, PWM15, PWM15G1, PWM15, SIG_DESC_SET(SCU41C, 31));
SIG_EXPR_LIST_DECL_SESG(Y23, THRUOUT3, THRU3, SIG_DESC_SET(SCU4BC, 31));
-PIN_DECL_2(Y23, GPIOP7, PWM15, THRUOUT3);
+SIG_EXPR_LIST_DECL_SESG(Y23, HEARTBEAT, HEARTBEAT, SIG_DESC_SET(SCU69C, 31));
+PIN_DECL_3(Y23, GPIOP7, PWM15, THRUOUT3, HEARTBEAT);
GROUP_DECL(PWM15G1, Y23);
FUNC_DECL_2(PWM15, PWM15G0, PWM15G1);
FUNC_GROUP_DECL(THRU3, AB24, Y23);
+FUNC_GROUP_DECL(HEARTBEAT, Y23);
#define AA25 128
SSSF_PIN_DECL(AA25, GPIOQ0, TACH0, SIG_DESC_SET(SCU430, 0));
@@ -1534,6 +1548,78 @@ GROUP_DECL(I3C4, AE25, AF24);
FUNC_DECL_2(I3C4, HVI3C4, I3C4);
FUNC_GROUP_DECL(FSI2, AE25, AF24);
+#define AF23 248
+SIG_EXPR_LIST_DECL_SESG(AF23, I3C1SCL, I3C1, SIG_DESC_SET(SCU438, 16));
+PIN_DECL_(AF23, SIG_EXPR_LIST_PTR(AF23, I3C1SCL));
+
+#define AE24 249
+SIG_EXPR_LIST_DECL_SESG(AE24, I3C1SDA, I3C1, SIG_DESC_SET(SCU438, 17));
+PIN_DECL_(AE24, SIG_EXPR_LIST_PTR(AE24, I3C1SDA));
+
+FUNC_GROUP_DECL(I3C1, AF23, AE24);
+
+#define AF22 250
+SIG_EXPR_LIST_DECL_SESG(AF22, I3C2SCL, I3C2, SIG_DESC_SET(SCU438, 18));
+PIN_DECL_(AF22, SIG_EXPR_LIST_PTR(AF22, I3C2SCL));
+
+#define AE22 251
+SIG_EXPR_LIST_DECL_SESG(AE22, I3C2SDA, I3C2, SIG_DESC_SET(SCU438, 19));
+PIN_DECL_(AE22, SIG_EXPR_LIST_PTR(AE22, I3C2SDA));
+
+FUNC_GROUP_DECL(I3C2, AF22, AE22);
+
+#define USB2ADP_DESC { ASPEED_IP_SCU, SCU440, GENMASK(25, 24), 0, 0 }
+#define USB2AD_DESC { ASPEED_IP_SCU, SCU440, GENMASK(25, 24), 1, 0 }
+#define USB2AH_DESC { ASPEED_IP_SCU, SCU440, GENMASK(25, 24), 2, 0 }
+#define USB2AHP_DESC { ASPEED_IP_SCU, SCU440, GENMASK(25, 24), 3, 0 }
+#define USB11BHID_DESC { ASPEED_IP_SCU, SCU440, GENMASK(29, 28), 0, 0 }
+#define USB2BD_DESC { ASPEED_IP_SCU, SCU440, GENMASK(29, 28), 1, 0 }
+#define USB2BH_DESC { ASPEED_IP_SCU, SCU440, GENMASK(29, 28), 2, 0 }
+
+#define A4 252
+SIG_EXPR_LIST_DECL_SEMG(A4, USB2ADPDP, USBA, USB2ADP, USB2ADP_DESC,
+ SIG_DESC_SET(SCUC20, 16));
+SIG_EXPR_LIST_DECL_SEMG(A4, USB2ADDP, USBA, USB2AD, USB2AD_DESC);
+SIG_EXPR_LIST_DECL_SEMG(A4, USB2AHDP, USBA, USB2AH, USB2AH_DESC);
+SIG_EXPR_LIST_DECL_SEMG(A4, USB2AHPDP, USBA, USB2AHP, USB2AHP_DESC);
+PIN_DECL_(A4, SIG_EXPR_LIST_PTR(A4, USB2ADPDP), SIG_EXPR_LIST_PTR(A4, USB2ADDP),
+ SIG_EXPR_LIST_PTR(A4, USB2AHDP));
+
+#define B4 253
+SIG_EXPR_LIST_DECL_SEMG(B4, USB2ADPDN, USBA, USB2ADP, USB2ADP_DESC);
+SIG_EXPR_LIST_DECL_SEMG(B4, USB2ADDN, USBA, USB2AD, USB2AD_DESC);
+SIG_EXPR_LIST_DECL_SEMG(B4, USB2AHDN, USBA, USB2AH, USB2AH_DESC);
+SIG_EXPR_LIST_DECL_SEMG(B4, USB2AHPDN, USBA, USB2AHP, USB2AHP_DESC);
+PIN_DECL_(B4, SIG_EXPR_LIST_PTR(B4, USB2ADPDN), SIG_EXPR_LIST_PTR(B4, USB2ADDN),
+ SIG_EXPR_LIST_PTR(B4, USB2AHDN));
+
+GROUP_DECL(USBA, A4, B4);
+
+FUNC_DECL_1(USB2ADP, USBA);
+FUNC_DECL_1(USB2AD, USBA);
+FUNC_DECL_1(USB2AH, USBA);
+FUNC_DECL_1(USB2AHP, USBA);
+
+#define A6 254
+SIG_EXPR_LIST_DECL_SEMG(A6, USB11BDP, USBB, USB11BHID, USB11BHID_DESC);
+SIG_EXPR_LIST_DECL_SEMG(A6, USB2BDDP, USBB, USB2BD, USB2BD_DESC);
+SIG_EXPR_LIST_DECL_SEMG(A6, USB2BHDP, USBB, USB2BH, USB2BH_DESC);
+PIN_DECL_(A6, SIG_EXPR_LIST_PTR(A6, USB11BDP), SIG_EXPR_LIST_PTR(A6, USB2BDDP),
+ SIG_EXPR_LIST_PTR(A6, USB2BHDP));
+
+#define B6 255
+SIG_EXPR_LIST_DECL_SEMG(B6, USB11BDN, USBB, USB11BHID, USB11BHID_DESC);
+SIG_EXPR_LIST_DECL_SEMG(B6, USB2BDDN, USBB, USB2BD, USB2BD_DESC);
+SIG_EXPR_LIST_DECL_SEMG(B6, USB2BHDN, USBB, USB2BH, USB2BH_DESC);
+PIN_DECL_(B6, SIG_EXPR_LIST_PTR(B6, USB11BDN), SIG_EXPR_LIST_PTR(B6, USB2BDDN),
+ SIG_EXPR_LIST_PTR(B6, USB2BHDN));
+
+GROUP_DECL(USBB, A6, B6);
+
+FUNC_DECL_1(USB11BHID, USBB);
+FUNC_DECL_1(USB2BD, USBB);
+FUNC_DECL_1(USB2BH, USBB);
+
/* Pins, groups and functions are sort(1):ed alphabetically for sanity */
static struct pinctrl_pin_desc aspeed_g6_pins[ASPEED_G6_NR_PINS] = {
@@ -1554,6 +1640,8 @@ static struct pinctrl_pin_desc aspeed_g6_pins[ASPEED_G6_NR_PINS] = {
ASPEED_PINCTRL_PIN(A24),
ASPEED_PINCTRL_PIN(A25),
ASPEED_PINCTRL_PIN(A3),
+ ASPEED_PINCTRL_PIN(A4),
+ ASPEED_PINCTRL_PIN(A6),
ASPEED_PINCTRL_PIN(AA11),
ASPEED_PINCTRL_PIN(AA12),
ASPEED_PINCTRL_PIN(AA16),
@@ -1625,6 +1713,8 @@ static struct pinctrl_pin_desc aspeed_g6_pins[ASPEED_G6_NR_PINS] = {
ASPEED_PINCTRL_PIN(AE16),
ASPEED_PINCTRL_PIN(AE18),
ASPEED_PINCTRL_PIN(AE19),
+ ASPEED_PINCTRL_PIN(AE22),
+ ASPEED_PINCTRL_PIN(AE24),
ASPEED_PINCTRL_PIN(AE25),
ASPEED_PINCTRL_PIN(AE26),
ASPEED_PINCTRL_PIN(AE7),
@@ -1634,6 +1724,8 @@ static struct pinctrl_pin_desc aspeed_g6_pins[ASPEED_G6_NR_PINS] = {
ASPEED_PINCTRL_PIN(AF12),
ASPEED_PINCTRL_PIN(AF14),
ASPEED_PINCTRL_PIN(AF15),
+ ASPEED_PINCTRL_PIN(AF22),
+ ASPEED_PINCTRL_PIN(AF23),
ASPEED_PINCTRL_PIN(AF24),
ASPEED_PINCTRL_PIN(AF25),
ASPEED_PINCTRL_PIN(AF7),
@@ -1654,6 +1746,8 @@ static struct pinctrl_pin_desc aspeed_g6_pins[ASPEED_G6_NR_PINS] = {
ASPEED_PINCTRL_PIN(B25),
ASPEED_PINCTRL_PIN(B26),
ASPEED_PINCTRL_PIN(B3),
+ ASPEED_PINCTRL_PIN(B4),
+ ASPEED_PINCTRL_PIN(B6),
ASPEED_PINCTRL_PIN(C1),
ASPEED_PINCTRL_PIN(C11),
ASPEED_PINCTRL_PIN(C12),
@@ -1829,6 +1923,7 @@ static const struct aspeed_pin_group aspeed_g6_groups[] = {
ASPEED_PINCTRL_GROUP(GPIU5),
ASPEED_PINCTRL_GROUP(GPIU6),
ASPEED_PINCTRL_GROUP(GPIU7),
+ ASPEED_PINCTRL_GROUP(HEARTBEAT),
ASPEED_PINCTRL_GROUP(HVI3C3),
ASPEED_PINCTRL_GROUP(HVI3C4),
ASPEED_PINCTRL_GROUP(I2C1),
@@ -1847,6 +1942,8 @@ static const struct aspeed_pin_group aspeed_g6_groups[] = {
ASPEED_PINCTRL_GROUP(I2C7),
ASPEED_PINCTRL_GROUP(I2C8),
ASPEED_PINCTRL_GROUP(I2C9),
+ ASPEED_PINCTRL_GROUP(I3C1),
+ ASPEED_PINCTRL_GROUP(I3C2),
ASPEED_PINCTRL_GROUP(I3C3),
ASPEED_PINCTRL_GROUP(I3C4),
ASPEED_PINCTRL_GROUP(I3C5),
@@ -2012,6 +2109,8 @@ static const struct aspeed_pin_group aspeed_g6_groups[] = {
ASPEED_PINCTRL_GROUP(UART7),
ASPEED_PINCTRL_GROUP(UART8),
ASPEED_PINCTRL_GROUP(UART9),
+ ASPEED_PINCTRL_GROUP(USBA),
+ ASPEED_PINCTRL_GROUP(USBB),
ASPEED_PINCTRL_GROUP(VB),
ASPEED_PINCTRL_GROUP(VGAHS),
ASPEED_PINCTRL_GROUP(VGAVS),
@@ -2063,6 +2162,7 @@ static const struct aspeed_pin_function aspeed_g6_functions[] = {
ASPEED_PINCTRL_FUNC(GPIU5),
ASPEED_PINCTRL_FUNC(GPIU6),
ASPEED_PINCTRL_FUNC(GPIU7),
+ ASPEED_PINCTRL_FUNC(HEARTBEAT),
ASPEED_PINCTRL_FUNC(I2C1),
ASPEED_PINCTRL_FUNC(I2C10),
ASPEED_PINCTRL_FUNC(I2C11),
@@ -2079,6 +2179,8 @@ static const struct aspeed_pin_function aspeed_g6_functions[] = {
ASPEED_PINCTRL_FUNC(I2C7),
ASPEED_PINCTRL_FUNC(I2C8),
ASPEED_PINCTRL_FUNC(I2C9),
+ ASPEED_PINCTRL_FUNC(I3C1),
+ ASPEED_PINCTRL_FUNC(I3C2),
ASPEED_PINCTRL_FUNC(I3C3),
ASPEED_PINCTRL_FUNC(I3C4),
ASPEED_PINCTRL_FUNC(I3C5),
@@ -2221,6 +2323,13 @@ static const struct aspeed_pin_function aspeed_g6_functions[] = {
ASPEED_PINCTRL_FUNC(UART7),
ASPEED_PINCTRL_FUNC(UART8),
ASPEED_PINCTRL_FUNC(UART9),
+ ASPEED_PINCTRL_FUNC(USB11BHID),
+ ASPEED_PINCTRL_FUNC(USB2AD),
+ ASPEED_PINCTRL_FUNC(USB2ADP),
+ ASPEED_PINCTRL_FUNC(USB2AH),
+ ASPEED_PINCTRL_FUNC(USB2AHP),
+ ASPEED_PINCTRL_FUNC(USB2BD),
+ ASPEED_PINCTRL_FUNC(USB2BH),
ASPEED_PINCTRL_FUNC(VB),
ASPEED_PINCTRL_FUNC(VGAHS),
ASPEED_PINCTRL_FUNC(VGAVS),
@@ -2230,6 +2339,260 @@ static const struct aspeed_pin_function aspeed_g6_functions[] = {
ASPEED_PINCTRL_FUNC(WDTRST4),
};
+static struct aspeed_pin_config aspeed_g6_configs[] = {
+ /* GPIOB7 */
+ ASPEED_PULL_DOWN_PINCONF(J24, SCU610, 15),
+ /* GPIOB6 */
+ ASPEED_PULL_DOWN_PINCONF(H25, SCU610, 14),
+ /* GPIOB5 */
+ ASPEED_PULL_DOWN_PINCONF(G26, SCU610, 13),
+ /* GPIOB4 */
+ ASPEED_PULL_DOWN_PINCONF(J23, SCU610, 12),
+ /* GPIOB3 */
+ ASPEED_PULL_DOWN_PINCONF(J25, SCU610, 11),
+ /* GPIOB2 */
+ ASPEED_PULL_DOWN_PINCONF(H26, SCU610, 10),
+ /* GPIOB1 */
+ ASPEED_PULL_DOWN_PINCONF(K23, SCU610, 9),
+ /* GPIOB0 */
+ ASPEED_PULL_DOWN_PINCONF(J26, SCU610, 8),
+
+ /* GPIOH3 */
+ ASPEED_PULL_DOWN_PINCONF(A17, SCU614, 27),
+ /* GPIOH2 */
+ ASPEED_PULL_DOWN_PINCONF(C18, SCU614, 26),
+ /* GPIOH1 */
+ ASPEED_PULL_DOWN_PINCONF(B18, SCU614, 25),
+ /* GPIOH0 */
+ ASPEED_PULL_DOWN_PINCONF(A18, SCU614, 24),
+
+ /* GPIOL7 */
+ ASPEED_PULL_DOWN_PINCONF(C14, SCU618, 31),
+ /* GPIOL6 */
+ ASPEED_PULL_DOWN_PINCONF(B14, SCU618, 30),
+ /* GPIOL5 */
+ ASPEED_PULL_DOWN_PINCONF(F15, SCU618, 29),
+ /* GPIOL4 */
+ ASPEED_PULL_DOWN_PINCONF(C15, SCU618, 28),
+
+ /* GPIOJ7 */
+ ASPEED_PULL_UP_PINCONF(D19, SCU618, 15),
+ /* GPIOJ6 */
+ ASPEED_PULL_UP_PINCONF(C20, SCU618, 14),
+ /* GPIOJ5 */
+ ASPEED_PULL_UP_PINCONF(A19, SCU618, 13),
+ /* GPIOJ4 */
+ ASPEED_PULL_UP_PINCONF(C19, SCU618, 12),
+ /* GPIOJ3 */
+ ASPEED_PULL_UP_PINCONF(D20, SCU618, 11),
+ /* GPIOJ2 */
+ ASPEED_PULL_UP_PINCONF(E19, SCU618, 10),
+ /* GPIOJ1 */
+ ASPEED_PULL_UP_PINCONF(A20, SCU618, 9),
+ /* GPIOJ0 */
+ ASPEED_PULL_UP_PINCONF(B20, SCU618, 8),
+
+ /* GPIOI7 */
+ ASPEED_PULL_DOWN_PINCONF(A15, SCU618, 7),
+ /* GPIOI6 */
+ ASPEED_PULL_DOWN_PINCONF(B16, SCU618, 6),
+ /* GPIOI5 */
+ ASPEED_PULL_DOWN_PINCONF(E16, SCU618, 5),
+ /* GPIOI4 */
+ ASPEED_PULL_DOWN_PINCONF(C16, SCU618, 4),
+ /* GPIOI3 */
+ ASPEED_PULL_DOWN_PINCONF(D16, SCU618, 3),
+ /* GPIOI2 */
+ ASPEED_PULL_DOWN_PINCONF(E17, SCU618, 2),
+ /* GPIOI1 */
+ ASPEED_PULL_DOWN_PINCONF(A16, SCU618, 1),
+ /* GPIOI0 */
+ ASPEED_PULL_DOWN_PINCONF(D17, SCU618, 0),
+
+ /* GPIOP7 */
+ ASPEED_PULL_DOWN_PINCONF(Y23, SCU61C, 31),
+ /* GPIOP6 */
+ ASPEED_PULL_DOWN_PINCONF(AB24, SCU61C, 30),
+ /* GPIOP5 */
+ ASPEED_PULL_DOWN_PINCONF(AB23, SCU61C, 29),
+ /* GPIOP4 */
+ ASPEED_PULL_DOWN_PINCONF(W23, SCU61C, 28),
+ /* GPIOP3 */
+ ASPEED_PULL_DOWN_PINCONF(AA24, SCU61C, 27),
+ /* GPIOP2 */
+ ASPEED_PULL_DOWN_PINCONF(AA23, SCU61C, 26),
+ /* GPIOP1 */
+ ASPEED_PULL_DOWN_PINCONF(W24, SCU61C, 25),
+ /* GPIOP0 */
+ ASPEED_PULL_DOWN_PINCONF(AB22, SCU61C, 24),
+
+ /* GPIOO7 */
+ ASPEED_PULL_DOWN_PINCONF(AC23, SCU61C, 23),
+ /* GPIOO6 */
+ ASPEED_PULL_DOWN_PINCONF(AC24, SCU61C, 22),
+ /* GPIOO5 */
+ ASPEED_PULL_DOWN_PINCONF(AC22, SCU61C, 21),
+ /* GPIOO4 */
+ ASPEED_PULL_DOWN_PINCONF(AD25, SCU61C, 20),
+ /* GPIOO3 */
+ ASPEED_PULL_DOWN_PINCONF(AD24, SCU61C, 19),
+ /* GPIOO2 */
+ ASPEED_PULL_DOWN_PINCONF(AD23, SCU61C, 18),
+ /* GPIOO1 */
+ ASPEED_PULL_DOWN_PINCONF(AD22, SCU61C, 17),
+ /* GPIOO0 */
+ ASPEED_PULL_DOWN_PINCONF(AD26, SCU61C, 16),
+
+ /* GPION7 */
+ ASPEED_PULL_DOWN_PINCONF(M26, SCU61C, 15),
+ /* GPION6 */
+ ASPEED_PULL_DOWN_PINCONF(N26, SCU61C, 14),
+ /* GPION5 */
+ ASPEED_PULL_DOWN_PINCONF(M23, SCU61C, 13),
+ /* GPION4 */
+ ASPEED_PULL_DOWN_PINCONF(P26, SCU61C, 12),
+ /* GPION3 */
+ ASPEED_PULL_DOWN_PINCONF(N24, SCU61C, 11),
+ /* GPION2 */
+ ASPEED_PULL_DOWN_PINCONF(N25, SCU61C, 10),
+ /* GPION1 */
+ ASPEED_PULL_DOWN_PINCONF(N23, SCU61C, 9),
+ /* GPION0 */
+ ASPEED_PULL_DOWN_PINCONF(P25, SCU61C, 8),
+
+ /* GPIOM7 */
+ ASPEED_PULL_DOWN_PINCONF(D13, SCU61C, 7),
+ /* GPIOM6 */
+ ASPEED_PULL_DOWN_PINCONF(C13, SCU61C, 6),
+ /* GPIOM5 */
+ ASPEED_PULL_DOWN_PINCONF(C12, SCU61C, 5),
+ /* GPIOM4 */
+ ASPEED_PULL_DOWN_PINCONF(B12, SCU61C, 4),
+ /* GPIOM3 */
+ ASPEED_PULL_DOWN_PINCONF(E14, SCU61C, 3),
+ /* GPIOM2 */
+ ASPEED_PULL_DOWN_PINCONF(A12, SCU61C, 2),
+ /* GPIOM1 */
+ ASPEED_PULL_DOWN_PINCONF(B13, SCU61C, 1),
+ /* GPIOM0 */
+ ASPEED_PULL_DOWN_PINCONF(D14, SCU61C, 0),
+
+ /* GPIOS7 */
+ ASPEED_PULL_DOWN_PINCONF(T24, SCU620, 23),
+ /* GPIOS6 */
+ ASPEED_PULL_DOWN_PINCONF(P23, SCU620, 22),
+ /* GPIOS5 */
+ ASPEED_PULL_DOWN_PINCONF(P24, SCU620, 21),
+ /* GPIOS4 */
+ ASPEED_PULL_DOWN_PINCONF(R26, SCU620, 20),
+ /* GPIOS3*/
+ ASPEED_PULL_DOWN_PINCONF(R24, SCU620, 19),
+ /* GPIOS2 */
+ ASPEED_PULL_DOWN_PINCONF(T26, SCU620, 18),
+ /* GPIOS1 */
+ ASPEED_PULL_DOWN_PINCONF(T25, SCU620, 17),
+ /* GPIOS0 */
+ ASPEED_PULL_DOWN_PINCONF(R23, SCU620, 16),
+
+ /* GPIOR7 */
+ ASPEED_PULL_DOWN_PINCONF(U26, SCU620, 15),
+ /* GPIOR6 */
+ ASPEED_PULL_DOWN_PINCONF(W26, SCU620, 14),
+ /* GPIOR5 */
+ ASPEED_PULL_DOWN_PINCONF(T23, SCU620, 13),
+ /* GPIOR4 */
+ ASPEED_PULL_DOWN_PINCONF(U25, SCU620, 12),
+ /* GPIOR3*/
+ ASPEED_PULL_DOWN_PINCONF(V26, SCU620, 11),
+ /* GPIOR2 */
+ ASPEED_PULL_DOWN_PINCONF(V24, SCU620, 10),
+ /* GPIOR1 */
+ ASPEED_PULL_DOWN_PINCONF(U24, SCU620, 9),
+ /* GPIOR0 */
+ ASPEED_PULL_DOWN_PINCONF(V25, SCU620, 8),
+
+ /* GPIOX7 */
+ ASPEED_PULL_DOWN_PINCONF(AB10, SCU634, 31),
+ /* GPIOX6 */
+ ASPEED_PULL_DOWN_PINCONF(AF9, SCU634, 30),
+ /* GPIOX5 */
+ ASPEED_PULL_DOWN_PINCONF(AD9, SCU634, 29),
+ /* GPIOX4 */
+ ASPEED_PULL_DOWN_PINCONF(AB9, SCU634, 28),
+ /* GPIOX3*/
+ ASPEED_PULL_DOWN_PINCONF(AF8, SCU634, 27),
+ /* GPIOX2 */
+ ASPEED_PULL_DOWN_PINCONF(AC9, SCU634, 26),
+ /* GPIOX1 */
+ ASPEED_PULL_DOWN_PINCONF(AA9, SCU634, 25),
+ /* GPIOX0 */
+ ASPEED_PULL_DOWN_PINCONF(AE8, SCU634, 24),
+
+ /* GPIOV7 */
+ ASPEED_PULL_DOWN_PINCONF(AF15, SCU634, 15),
+ /* GPIOV6 */
+ ASPEED_PULL_DOWN_PINCONF(AD15, SCU634, 14),
+ /* GPIOV5 */
+ ASPEED_PULL_DOWN_PINCONF(AE14, SCU634, 13),
+ /* GPIOV4 */
+ ASPEED_PULL_DOWN_PINCONF(AE15, SCU634, 12),
+ /* GPIOV3*/
+ ASPEED_PULL_DOWN_PINCONF(AC15, SCU634, 11),
+ /* GPIOV2 */
+ ASPEED_PULL_DOWN_PINCONF(AD14, SCU634, 10),
+ /* GPIOV1 */
+ ASPEED_PULL_DOWN_PINCONF(AF14, SCU634, 9),
+ /* GPIOV0 */
+ ASPEED_PULL_DOWN_PINCONF(AB15, SCU634, 8),
+
+ /* GPIOZ7 */
+ ASPEED_PULL_DOWN_PINCONF(AF10, SCU638, 15),
+ /* GPIOZ6 */
+ ASPEED_PULL_DOWN_PINCONF(AD11, SCU638, 14),
+ /* GPIOZ5 */
+ ASPEED_PULL_DOWN_PINCONF(AA11, SCU638, 13),
+ /* GPIOZ4 */
+ ASPEED_PULL_DOWN_PINCONF(AC11, SCU638, 12),
+ /* GPIOZ3*/
+ ASPEED_PULL_DOWN_PINCONF(AB11, SCU638, 11),
+
+ /* GPIOZ1 */
+ ASPEED_PULL_DOWN_PINCONF(AD10, SCU638, 9),
+ /* GPIOZ0 */
+ ASPEED_PULL_DOWN_PINCONF(AC10, SCU638, 8),
+
+ /* GPIOY6 */
+ ASPEED_PULL_DOWN_PINCONF(AC12, SCU638, 6),
+ /* GPIOY5 */
+ ASPEED_PULL_DOWN_PINCONF(AF12, SCU638, 5),
+ /* GPIOY4 */
+ ASPEED_PULL_DOWN_PINCONF(AE12, SCU638, 4),
+ /* GPIOY3 */
+ ASPEED_PULL_DOWN_PINCONF(AA12, SCU638, 3),
+ /* GPIOY2 */
+ ASPEED_PULL_DOWN_PINCONF(AE11, SCU638, 2),
+ /* GPIOY1 */
+ ASPEED_PULL_DOWN_PINCONF(AD12, SCU638, 1),
+ /* GPIOY0 */
+ ASPEED_PULL_DOWN_PINCONF(AF11, SCU638, 0),
+
+ /* LAD3 */
+ { PIN_CONFIG_DRIVE_STRENGTH, { AC7, AC7 }, SCU454, GENMASK(31, 30)},
+ /* LAD2 */
+ { PIN_CONFIG_DRIVE_STRENGTH, { AC8, AC8 }, SCU454, GENMASK(29, 28)},
+ /* LAD1 */
+ { PIN_CONFIG_DRIVE_STRENGTH, { AB8, AB8 }, SCU454, GENMASK(27, 26)},
+ /* LAD0 */
+ { PIN_CONFIG_DRIVE_STRENGTH, { AB7, AB7 }, SCU454, GENMASK(25, 24)},
+
+ /* MAC3 */
+ { PIN_CONFIG_POWER_SOURCE, { H24, E26 }, SCU458, BIT_MASK(4)},
+ { PIN_CONFIG_DRIVE_STRENGTH, { H24, E26 }, SCU458, GENMASK(1, 0)},
+ /* MAC4 */
+ { PIN_CONFIG_POWER_SOURCE, { F24, B24 }, SCU458, BIT_MASK(5)},
+ { PIN_CONFIG_DRIVE_STRENGTH, { F24, B24 }, SCU458, GENMASK(3, 2)},
+};
+
/**
* Configure a pin's signal by applying an expression's descriptor state for
* all descriptors in the expression.
@@ -2297,6 +2660,20 @@ static int aspeed_g6_sig_expr_set(struct aspeed_pinmux_data *ctx,
return 0;
}
+static const struct aspeed_pin_config_map aspeed_g6_pin_config_map[] = {
+ { PIN_CONFIG_BIAS_PULL_DOWN, 0, 1, BIT_MASK(0)},
+ { PIN_CONFIG_BIAS_PULL_DOWN, -1, 0, BIT_MASK(0)},
+ { PIN_CONFIG_BIAS_PULL_UP, 0, 1, BIT_MASK(0)},
+ { PIN_CONFIG_BIAS_PULL_UP, -1, 0, BIT_MASK(0)},
+ { PIN_CONFIG_BIAS_DISABLE, -1, 1, BIT_MASK(0)},
+ { PIN_CONFIG_DRIVE_STRENGTH, 4, 0, GENMASK(1, 0)},
+ { PIN_CONFIG_DRIVE_STRENGTH, 8, 1, GENMASK(1, 0)},
+ { PIN_CONFIG_DRIVE_STRENGTH, 12, 2, GENMASK(1, 0)},
+ { PIN_CONFIG_DRIVE_STRENGTH, 16, 3, GENMASK(1, 0)},
+ { PIN_CONFIG_POWER_SOURCE, 3300, 0, BIT_MASK(0)},
+ { PIN_CONFIG_POWER_SOURCE, 1800, 1, BIT_MASK(0)},
+};
+
static const struct aspeed_pinmux_ops aspeed_g5_ops = {
.set = aspeed_g6_sig_expr_set,
};
@@ -2311,6 +2688,10 @@ static struct aspeed_pinctrl_data aspeed_g6_pinctrl_data = {
.functions = aspeed_g6_functions,
.nfunctions = ARRAY_SIZE(aspeed_g6_functions),
},
+ .configs = aspeed_g6_configs,
+ .nconfigs = ARRAY_SIZE(aspeed_g6_configs),
+ .confmaps = aspeed_g6_pin_config_map,
+ .nconfmaps = ARRAY_SIZE(aspeed_g6_pin_config_map),
};
static const struct pinmux_ops aspeed_g6_pinmux_ops = {
@@ -2331,12 +2712,21 @@ static const struct pinctrl_ops aspeed_g6_pinctrl_ops = {
.dt_free_map = pinctrl_utils_free_map,
};
+static const struct pinconf_ops aspeed_g6_conf_ops = {
+ .is_generic = true,
+ .pin_config_get = aspeed_pin_config_get,
+ .pin_config_set = aspeed_pin_config_set,
+ .pin_config_group_get = aspeed_pin_config_group_get,
+ .pin_config_group_set = aspeed_pin_config_group_set,
+};
+
static struct pinctrl_desc aspeed_g6_pinctrl_desc = {
.name = "aspeed-g6-pinctrl",
.pins = aspeed_g6_pins,
.npins = ARRAY_SIZE(aspeed_g6_pins),
.pctlops = &aspeed_g6_pinctrl_ops,
.pmxops = &aspeed_g6_pinmux_ops,
+ .confops = &aspeed_g6_conf_ops,
};
static int aspeed_g6_pinctrl_probe(struct platform_device *pdev)
diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed.c b/drivers/pinctrl/aspeed/pinctrl-aspeed.c
index 54933665b5f8..53f3f8aec695 100644
--- a/drivers/pinctrl/aspeed/pinctrl-aspeed.c
+++ b/drivers/pinctrl/aspeed/pinctrl-aspeed.c
@@ -76,6 +76,9 @@ static int aspeed_sig_expr_enable(struct aspeed_pinmux_data *ctx,
{
int ret;
+ pr_debug("Enabling signal %s for %s\n", expr->signal,
+ expr->function);
+
ret = aspeed_sig_expr_eval(ctx, expr, true);
if (ret < 0)
return ret;
@@ -91,6 +94,9 @@ static int aspeed_sig_expr_disable(struct aspeed_pinmux_data *ctx,
{
int ret;
+ pr_debug("Disabling signal %s for %s\n", expr->signal,
+ expr->function);
+
ret = aspeed_sig_expr_eval(ctx, expr, true);
if (ret < 0)
return ret;
@@ -229,7 +235,7 @@ int aspeed_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function,
const struct aspeed_sig_expr **funcs;
const struct aspeed_sig_expr ***prios;
- pr_debug("Muxing pin %d for %s\n", pin, pfunc->name);
+ pr_debug("Muxing pin %s for %s\n", pdesc->name, pfunc->name);
if (!pdesc)
return -EINVAL;
@@ -269,6 +275,9 @@ int aspeed_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function,
ret = aspeed_sig_expr_enable(&pdata->pinmux, expr);
if (ret)
return ret;
+
+ pr_debug("Muxed pin %s as %s for %s\n", pdesc->name, expr->signal,
+ expr->function);
}
return 0;
@@ -317,6 +326,8 @@ int aspeed_gpio_request_enable(struct pinctrl_dev *pctldev,
if (!prios)
return -ENXIO;
+ pr_debug("Muxing pin %s for GPIO\n", pdesc->name);
+
/* Disable any functions of higher priority than GPIO */
while ((funcs = *prios)) {
if (aspeed_gpio_in_exprs(funcs))
@@ -346,14 +357,22 @@ int aspeed_gpio_request_enable(struct pinctrl_dev *pctldev,
* lowest-priority signal type. As such it has no associated
* expression.
*/
- if (!expr)
+ if (!expr) {
+ pr_debug("Muxed pin %s as GPIO\n", pdesc->name);
return 0;
+ }
/*
* If GPIO is not the lowest priority signal type, assume there is only
* one expression defined to enable the GPIO function
*/
- return aspeed_sig_expr_enable(&pdata->pinmux, expr);
+ ret = aspeed_sig_expr_enable(&pdata->pinmux, expr);
+ if (ret)
+ return ret;
+
+ pr_debug("Muxed pin %s as %s\n", pdesc->name, expr->signal);
+
+ return 0;
}
int aspeed_pinctrl_probe(struct platform_device *pdev,
@@ -411,49 +430,21 @@ static inline const struct aspeed_pin_config *find_pinconf_config(
return NULL;
}
-/*
- * Aspeed pin configuration description.
- *
- * @param: pinconf configuration parameter
- * @arg: The supported argument for @param, or -1 if any value is supported
- * @val: The register value to write to configure @arg for @param
- *
- * The map is to be used in conjunction with the configuration array supplied
- * by the driver implementation.
- */
-struct aspeed_pin_config_map {
- enum pin_config_param param;
- s32 arg;
- u32 val;
-};
-
enum aspeed_pin_config_map_type { MAP_TYPE_ARG, MAP_TYPE_VAL };
-/* Aspeed consistently both:
- *
- * 1. Defines "disable bits" for internal pull-downs
- * 2. Uses 8mA or 16mA drive strengths
- */
-static const struct aspeed_pin_config_map pin_config_map[] = {
- { PIN_CONFIG_BIAS_PULL_DOWN, 0, 1 },
- { PIN_CONFIG_BIAS_PULL_DOWN, -1, 0 },
- { PIN_CONFIG_BIAS_DISABLE, -1, 1 },
- { PIN_CONFIG_DRIVE_STRENGTH, 8, 0 },
- { PIN_CONFIG_DRIVE_STRENGTH, 16, 1 },
-};
-
static const struct aspeed_pin_config_map *find_pinconf_map(
+ const struct aspeed_pinctrl_data *pdata,
enum pin_config_param param,
enum aspeed_pin_config_map_type type,
s64 value)
{
int i;
- for (i = 0; i < ARRAY_SIZE(pin_config_map); i++) {
+ for (i = 0; i < pdata->nconfmaps; i++) {
const struct aspeed_pin_config_map *elem;
bool match;
- elem = &pin_config_map[i];
+ elem = &pdata->confmaps[i];
switch (type) {
case MAP_TYPE_ARG:
@@ -491,8 +482,8 @@ int aspeed_pin_config_get(struct pinctrl_dev *pctldev, unsigned int offset,
if (rc < 0)
return rc;
- pmap = find_pinconf_map(param, MAP_TYPE_VAL,
- (val & BIT(pconf->bit)) >> pconf->bit);
+ pmap = find_pinconf_map(pdata, param, MAP_TYPE_VAL,
+ (val & pconf->mask) >> __ffs(pconf->mask));
if (!pmap)
return -EINVAL;
@@ -535,22 +526,22 @@ int aspeed_pin_config_set(struct pinctrl_dev *pctldev, unsigned int offset,
if (!pconf)
return -ENOTSUPP;
- pmap = find_pinconf_map(param, MAP_TYPE_ARG, arg);
+ pmap = find_pinconf_map(pdata, param, MAP_TYPE_ARG, arg);
if (WARN_ON(!pmap))
return -EINVAL;
- val = pmap->val << pconf->bit;
+ val = pmap->val << __ffs(pconf->mask);
rc = regmap_update_bits(pdata->scu, pconf->reg,
- BIT(pconf->bit), val);
+ pmap->mask, val);
if (rc < 0)
return rc;
- pr_debug("%s: Set SCU%02X[%d]=%d for param %d(=%d) on pin %d\n",
- __func__, pconf->reg, pconf->bit, pmap->val,
- param, arg, offset);
+ pr_debug("%s: Set SCU%02X[%lu]=%d for param %d(=%d) on pin %d\n",
+ __func__, pconf->reg, __ffs(pconf->mask),
+ pmap->val, param, arg, offset);
}
return 0;
diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed.h b/drivers/pinctrl/aspeed/pinctrl-aspeed.h
index a5d83986f32e..4dcde3bc29c8 100644
--- a/drivers/pinctrl/aspeed/pinctrl-aspeed.h
+++ b/drivers/pinctrl/aspeed/pinctrl-aspeed.h
@@ -24,8 +24,7 @@ struct aspeed_pin_config {
enum pin_config_param param;
unsigned int pins[2];
unsigned int reg;
- u8 bit;
- u8 value;
+ u32 mask;
};
#define ASPEED_PINCTRL_PIN(name_) \
@@ -35,6 +34,38 @@ struct aspeed_pin_config {
.drv_data = (void *) &(PIN_SYM(name_)) \
}
+#define ASPEED_SB_PINCONF(param_, pin0_, pin1_, reg_, bit_) { \
+ .param = param_, \
+ .pins = {pin0_, pin1_}, \
+ .reg = reg_, \
+ .mask = BIT_MASK(bit_) \
+}
+
+#define ASPEED_PULL_DOWN_PINCONF(pin_, reg_, bit_) \
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_DOWN, pin_, pin_, reg_, bit_), \
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, pin_, pin_, reg_, bit_)
+
+#define ASPEED_PULL_UP_PINCONF(pin_, reg_, bit_) \
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_PULL_UP, pin_, pin_, reg_, bit_), \
+ ASPEED_SB_PINCONF(PIN_CONFIG_BIAS_DISABLE, pin_, pin_, reg_, bit_)
+/*
+ * Aspeed pin configuration description.
+ *
+ * @param: pinconf configuration parameter
+ * @arg: The supported argument for @param, or -1 if any value is supported
+ * @val: The register value to write to configure @arg for @param
+ * @mask: The bitfield mask for @val
+ *
+ * The map is to be used in conjunction with the configuration array supplied
+ * by the driver implementation.
+ */
+struct aspeed_pin_config_map {
+ enum pin_config_param param;
+ s32 arg;
+ u32 val;
+ u32 mask;
+};
+
struct aspeed_pinctrl_data {
struct regmap *scu;
@@ -45,6 +76,9 @@ struct aspeed_pinctrl_data {
const unsigned int nconfigs;
struct aspeed_pinmux_data pinmux;
+
+ const struct aspeed_pin_config_map *confmaps;
+ const unsigned int nconfmaps;
};
/* Aspeed pinctrl helpers */
diff --git a/drivers/pinctrl/aspeed/pinmux-aspeed.h b/drivers/pinctrl/aspeed/pinmux-aspeed.h
index 140c5ce9fbc1..f86739e800c3 100644
--- a/drivers/pinctrl/aspeed/pinmux-aspeed.h
+++ b/drivers/pinctrl/aspeed/pinmux-aspeed.h
@@ -737,6 +737,7 @@ struct aspeed_pin_desc {
#define FUNC_DECL_(func, ...) \
static const char *FUNC_SYM(func)[] = { __VA_ARGS__ }
+#define FUNC_DECL_1(func, group) FUNC_DECL_(func, #group)
#define FUNC_DECL_2(func, one, two) FUNC_DECL_(func, #one, #two)
#define FUNC_DECL_3(func, one, two, three) FUNC_DECL_(func, #one, #two, #three)
diff --git a/drivers/reset/reset-simple.c b/drivers/reset/reset-simple.c
index 067e7e7b34f1..795c9063fe7b 100644
--- a/drivers/reset/reset-simple.c
+++ b/drivers/reset/reset-simple.c
@@ -125,6 +125,7 @@ static const struct of_device_id reset_simple_dt_ids[] = {
.data = &reset_simple_active_low },
{ .compatible = "aspeed,ast2400-lpc-reset" },
{ .compatible = "aspeed,ast2500-lpc-reset" },
+ { .compatible = "aspeed,ast2600-lpc-reset" },
{ .compatible = "bitmain,bm1880-reset",
.data = &reset_simple_active_low },
{ .compatible = "snps,dw-high-reset" },
diff --git a/drivers/soc/aspeed/Kconfig b/drivers/soc/aspeed/Kconfig
index 323e177aa74d..a4b3cac87ce2 100644
--- a/drivers/soc/aspeed/Kconfig
+++ b/drivers/soc/aspeed/Kconfig
@@ -5,6 +5,14 @@ config SOC_ASPEED
def_bool y
depends on ARCH_ASPEED || COMPILE_TEST
+config ASPEED_BMC_MISC
+ bool "Miscellaneous ASPEED BMC interfaces"
+ depends on ARCH_ASPEED || COMPILE_TEST
+ default ARCH_ASPEED
+ help
+ Say yes to expose VGA and LPC scratch registers, and other
+ miscellaneous control interfaces specific to the ASPEED BMC SoCs
+
config ASPEED_LPC_CTRL
depends on SOC_ASPEED && REGMAP && MFD_SYSCON
tristate "Aspeed ast2400/2500 HOST LPC to BMC bridge control"
@@ -29,4 +37,12 @@ config ASPEED_P2A_CTRL
ioctl()s, the driver also provides an interface for userspace mappings to
a pre-defined region.
+config ASPEED_XDMA
+ tristate "Aspeed XDMA Engine Driver"
+ depends on SOC_ASPEED && REGMAP && MFD_SYSCON && HAS_DMA
+ help
+ Enable support for the Aspeed XDMA Engine found on the Aspeed AST2XXX
+ SOCs. The XDMA engine can perform automatic PCI DMA operations
+ between the AST2XXX (acting as a BMC) and a host processor.
+
endmenu
diff --git a/drivers/soc/aspeed/Makefile b/drivers/soc/aspeed/Makefile
index b64be47f2b1f..217d876fec25 100644
--- a/drivers/soc/aspeed/Makefile
+++ b/drivers/soc/aspeed/Makefile
@@ -1,4 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_ASPEED_BMC_MISC) += aspeed-bmc-misc.o
obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o
obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o
obj-$(CONFIG_ASPEED_P2A_CTRL) += aspeed-p2a-ctrl.o
+obj-$(CONFIG_ASPEED_XDMA) += aspeed-xdma.o
diff --git a/drivers/soc/aspeed/aspeed-bmc-misc.c b/drivers/soc/aspeed/aspeed-bmc-misc.c
new file mode 100644
index 000000000000..314007bad74f
--- /dev/null
+++ b/drivers/soc/aspeed/aspeed-bmc-misc.c
@@ -0,0 +1,190 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Copyright 2018 IBM Corp.
+
+#include <linux/kobject.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+#define DEVICE_NAME "aspeed-bmc-misc"
+
+struct aspeed_bmc_ctrl {
+ const char *name;
+ u32 offset;
+ u32 mask;
+ u32 shift;
+ struct regmap *map;
+ struct kobj_attribute attr;
+};
+
+struct aspeed_bmc_misc {
+ struct device *dev;
+ struct regmap *map;
+ struct aspeed_bmc_ctrl *ctrls;
+ int nr_ctrls;
+};
+
+static int aspeed_bmc_misc_parse_dt_child(struct device_node *child,
+ struct aspeed_bmc_ctrl *ctrl)
+{
+ int rc;
+
+ /* Example child:
+ *
+ * ilpc2ahb {
+ * offset = <0x80>;
+ * bit-mask = <0x1>;
+ * bit-shift = <6>;
+ * label = "foo";
+ * }
+ */
+ if (of_property_read_string(child, "label", &ctrl->name))
+ ctrl->name = child->name;
+
+ rc = of_property_read_u32(child, "offset", &ctrl->offset);
+ if (rc < 0)
+ return rc;
+
+ rc = of_property_read_u32(child, "bit-mask", &ctrl->mask);
+ if (rc < 0)
+ return rc;
+
+ rc = of_property_read_u32(child, "bit-shift", &ctrl->shift);
+ if (rc < 0)
+ return rc;
+
+ ctrl->mask <<= ctrl->shift;
+
+ return 0;
+}
+
+static int aspeed_bmc_misc_parse_dt(struct aspeed_bmc_misc *bmc,
+ struct device_node *parent)
+{
+ struct aspeed_bmc_ctrl *ctrl;
+ struct device_node *child;
+ int rc;
+
+ bmc->nr_ctrls = of_get_child_count(parent);
+ bmc->ctrls = devm_kcalloc(bmc->dev, bmc->nr_ctrls, sizeof(*bmc->ctrls),
+ GFP_KERNEL);
+ if (!bmc->ctrls)
+ return -ENOMEM;
+
+ ctrl = bmc->ctrls;
+ for_each_child_of_node(parent, child) {
+ rc = aspeed_bmc_misc_parse_dt_child(child, ctrl++);
+ if (rc < 0) {
+ of_node_put(child);
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+static ssize_t aspeed_bmc_misc_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct aspeed_bmc_ctrl *ctrl;
+ unsigned int val;
+ int rc;
+
+ ctrl = container_of(attr, struct aspeed_bmc_ctrl, attr);
+ rc = regmap_read(ctrl->map, ctrl->offset, &val);
+ if (rc)
+ return rc;
+
+ val &= ctrl->mask;
+ val >>= ctrl->shift;
+
+ return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t aspeed_bmc_misc_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct aspeed_bmc_ctrl *ctrl;
+ long val;
+ int rc;
+
+ rc = kstrtol(buf, 0, &val);
+ if (rc)
+ return rc;
+
+ ctrl = container_of(attr, struct aspeed_bmc_ctrl, attr);
+ val <<= ctrl->shift;
+ rc = regmap_update_bits(ctrl->map, ctrl->offset, ctrl->mask, val);
+
+ return rc < 0 ? rc : count;
+}
+
+static int aspeed_bmc_misc_add_sysfs_attr(struct aspeed_bmc_misc *bmc,
+ struct aspeed_bmc_ctrl *ctrl)
+{
+ ctrl->map = bmc->map;
+
+ sysfs_attr_init(&ctrl->attr.attr);
+ ctrl->attr.attr.name = ctrl->name;
+ ctrl->attr.attr.mode = 0664;
+ ctrl->attr.show = aspeed_bmc_misc_show;
+ ctrl->attr.store = aspeed_bmc_misc_store;
+
+ return sysfs_create_file(&bmc->dev->kobj, &ctrl->attr.attr);
+}
+
+static int aspeed_bmc_misc_populate_sysfs(struct aspeed_bmc_misc *bmc)
+{
+ int rc;
+ int i;
+
+ for (i = 0; i < bmc->nr_ctrls; i++) {
+ rc = aspeed_bmc_misc_add_sysfs_attr(bmc, &bmc->ctrls[i]);
+ if (rc < 0)
+ return rc;
+ }
+
+ return 0;
+}
+
+static int aspeed_bmc_misc_probe(struct platform_device *pdev)
+{
+ struct aspeed_bmc_misc *bmc;
+ int rc;
+
+ bmc = devm_kzalloc(&pdev->dev, sizeof(*bmc), GFP_KERNEL);
+ if (!bmc)
+ return -ENOMEM;
+
+ bmc->dev = &pdev->dev;
+ bmc->map = syscon_node_to_regmap(pdev->dev.parent->of_node);
+ if (IS_ERR(bmc->map))
+ return PTR_ERR(bmc->map);
+
+ rc = aspeed_bmc_misc_parse_dt(bmc, pdev->dev.of_node);
+ if (rc < 0)
+ return rc;
+
+ return aspeed_bmc_misc_populate_sysfs(bmc);
+}
+
+static const struct of_device_id aspeed_bmc_misc_match[] = {
+ { .compatible = "aspeed,bmc-misc" },
+ { },
+};
+
+static struct platform_driver aspeed_bmc_misc = {
+ .driver = {
+ .name = DEVICE_NAME,
+ .of_match_table = aspeed_bmc_misc_match,
+ },
+ .probe = aspeed_bmc_misc_probe,
+};
+
+module_platform_driver(aspeed_bmc_misc);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Andrew Jeffery <andrew@aj.id.au>");
diff --git a/drivers/soc/aspeed/aspeed-lpc-ctrl.c b/drivers/soc/aspeed/aspeed-lpc-ctrl.c
index 01ed21e8bfee..142cb4cc85e7 100644
--- a/drivers/soc/aspeed/aspeed-lpc-ctrl.c
+++ b/drivers/soc/aspeed/aspeed-lpc-ctrl.c
@@ -4,6 +4,7 @@
*/
#include <linux/clk.h>
+#include <linux/log2.h>
#include <linux/mfd/syscon.h>
#include <linux/miscdevice.h>
#include <linux/mm.h>
@@ -21,6 +22,9 @@
#define HICR5_ENL2H BIT(8)
#define HICR5_ENFWH BIT(10)
+#define HICR6 0x4
+#define SW_FWH2AHB BIT(17)
+
#define HICR7 0x8
#define HICR8 0xc
@@ -32,6 +36,7 @@ struct aspeed_lpc_ctrl {
resource_size_t mem_size;
u32 pnor_size;
u32 pnor_base;
+ bool fwh2ahb;
};
static struct aspeed_lpc_ctrl *file_aspeed_lpc_ctrl(struct file *file)
@@ -177,6 +182,16 @@ static long aspeed_lpc_ctrl_ioctl(struct file *file, unsigned int cmd,
return rc;
/*
+ * Switch to FWH2AHB mode, AST2600 only.
+ *
+ * The other bits in this register are interrupt status bits
+ * that are cleared by writing 1. As we don't want to clear
+ * them, set only the bit of interest.
+ */
+ if (lpc_ctrl->fwh2ahb)
+ regmap_write(lpc_ctrl->regmap, HICR6, SW_FWH2AHB);
+
+ /*
* Enable LPC FHW cycles. This is required for the host to
* access the regions specified.
*/
@@ -241,6 +256,18 @@ static int aspeed_lpc_ctrl_probe(struct platform_device *pdev)
lpc_ctrl->mem_size = resource_size(&resm);
lpc_ctrl->mem_base = resm.start;
+
+ if (!is_power_of_2(lpc_ctrl->mem_size)) {
+ dev_err(dev, "Reserved memory size must be a power of 2, got %zu\n",
+ lpc_ctrl->mem_size);
+ return -EINVAL;
+ }
+
+ if (!IS_ALIGNED(lpc_ctrl->mem_base, lpc_ctrl->mem_size)) {
+ dev_err(dev, "Reserved memory must be naturally aligned for size %zu\n",
+ lpc_ctrl->mem_size);
+ return -EINVAL;
+ }
}
lpc_ctrl->regmap = syscon_node_to_regmap(
@@ -261,6 +288,9 @@ static int aspeed_lpc_ctrl_probe(struct platform_device *pdev)
return rc;
}
+ if (of_device_is_compatible(dev->of_node, "aspeed,ast2600-lpc-ctrl"))
+ lpc_ctrl->fwh2ahb = true;
+
lpc_ctrl->miscdev.minor = MISC_DYNAMIC_MINOR;
lpc_ctrl->miscdev.name = DEVICE_NAME;
lpc_ctrl->miscdev.fops = &aspeed_lpc_ctrl_fops;
@@ -291,6 +321,7 @@ static int aspeed_lpc_ctrl_remove(struct platform_device *pdev)
static const struct of_device_id aspeed_lpc_ctrl_match[] = {
{ .compatible = "aspeed,ast2400-lpc-ctrl" },
{ .compatible = "aspeed,ast2500-lpc-ctrl" },
+ { .compatible = "aspeed,ast2600-lpc-ctrl" },
{ },
};
diff --git a/drivers/soc/aspeed/aspeed-lpc-snoop.c b/drivers/soc/aspeed/aspeed-lpc-snoop.c
index f3d8d53ab84d..682ba0eb4eba 100644
--- a/drivers/soc/aspeed/aspeed-lpc-snoop.c
+++ b/drivers/soc/aspeed/aspeed-lpc-snoop.c
@@ -325,6 +325,8 @@ static const struct of_device_id aspeed_lpc_snoop_match[] = {
.data = &ast2400_model_data },
{ .compatible = "aspeed,ast2500-lpc-snoop",
.data = &ast2500_model_data },
+ { .compatible = "aspeed,ast2600-lpc-snoop",
+ .data = &ast2500_model_data },
{ },
};
diff --git a/drivers/soc/aspeed/aspeed-xdma.c b/drivers/soc/aspeed/aspeed-xdma.c
new file mode 100644
index 000000000000..fa2d968abd13
--- /dev/null
+++ b/drivers/soc/aspeed/aspeed-xdma.c
@@ -0,0 +1,1221 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// Copyright IBM Corp 2019
+
+#include <linux/aspeed-xdma.h>
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/fs.h>
+#include <linux/genalloc.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/mfd/syscon.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of_device.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/platform_device.h>
+#include <linux/poll.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+
+#define DEVICE_NAME "aspeed-xdma"
+
+#define SCU_AST2600_MISC_CTRL 0x0c0
+#define SCU_AST2600_MISC_CTRL_XDMA_BMC BIT(8)
+
+#define SCU_AST2500_PCIE_CONF 0x180
+#define SCU_AST2600_PCIE_CONF 0xc20
+#define SCU_PCIE_CONF_VGA_EN BIT(0)
+#define SCU_PCIE_CONF_VGA_EN_MMIO BIT(1)
+#define SCU_PCIE_CONF_VGA_EN_LPC BIT(2)
+#define SCU_PCIE_CONF_VGA_EN_MSI BIT(3)
+#define SCU_PCIE_CONF_VGA_EN_MCTP BIT(4)
+#define SCU_PCIE_CONF_VGA_EN_IRQ BIT(5)
+#define SCU_PCIE_CONF_VGA_EN_DMA BIT(6)
+#define SCU_PCIE_CONF_BMC_EN BIT(8)
+#define SCU_PCIE_CONF_BMC_EN_MMIO BIT(9)
+#define SCU_PCIE_CONF_BMC_EN_MSI BIT(11)
+#define SCU_PCIE_CONF_BMC_EN_MCTP BIT(12)
+#define SCU_PCIE_CONF_BMC_EN_IRQ BIT(13)
+#define SCU_PCIE_CONF_BMC_EN_DMA BIT(14)
+
+#define SCU_AST2500_BMC_CLASS_REV 0x19c
+#define SCU_AST2600_BMC_CLASS_REV 0xc68
+#define SCU_BMC_CLASS_REV_XDMA 0xff000001
+
+#define SDMC_REMAP 0x008
+#define SDMC_AST2500_REMAP_PCIE BIT(16)
+#define SDMC_AST2500_REMAP_XDMA BIT(17)
+#define SDMC_AST2600_REMAP_XDMA BIT(18)
+
+#define XDMA_CMDQ_SIZE PAGE_SIZE
+#define XDMA_NUM_CMDS \
+ (XDMA_CMDQ_SIZE / sizeof(struct aspeed_xdma_cmd))
+
+/* Aspeed specification requires 100us after disabling the reset */
+#define XDMA_ENGINE_SETUP_TIME_MAX_US 1000
+#define XDMA_ENGINE_SETUP_TIME_MIN_US 100
+
+#define XDMA_CMD_AST2500_PITCH_SHIFT 3
+#define XDMA_CMD_AST2500_PITCH_BMC GENMASK_ULL(62, 51)
+#define XDMA_CMD_AST2500_PITCH_HOST GENMASK_ULL(46, 35)
+#define XDMA_CMD_AST2500_PITCH_UPSTREAM BIT_ULL(31)
+#define XDMA_CMD_AST2500_PITCH_ADDR GENMASK_ULL(29, 4)
+#define XDMA_CMD_AST2500_PITCH_ID BIT_ULL(0)
+#define XDMA_CMD_AST2500_CMD_IRQ_EN BIT_ULL(31)
+#define XDMA_CMD_AST2500_CMD_LINE_NO GENMASK_ULL(27, 16)
+#define XDMA_CMD_AST2500_CMD_IRQ_BMC BIT_ULL(15)
+#define XDMA_CMD_AST2500_CMD_LINE_SIZE_SHIFT 4
+#define XDMA_CMD_AST2500_CMD_LINE_SIZE \
+ GENMASK_ULL(14, XDMA_CMD_AST2500_CMD_LINE_SIZE_SHIFT)
+#define XDMA_CMD_AST2500_CMD_ID BIT_ULL(1)
+
+#define XDMA_CMD_AST2600_PITCH_BMC GENMASK_ULL(62, 48)
+#define XDMA_CMD_AST2600_PITCH_HOST GENMASK_ULL(46, 32)
+#define XDMA_CMD_AST2600_PITCH_ADDR GENMASK_ULL(30, 0)
+#define XDMA_CMD_AST2600_CMD_64_EN BIT_ULL(40)
+#define XDMA_CMD_AST2600_CMD_IRQ_BMC BIT_ULL(37)
+#define XDMA_CMD_AST2600_CMD_IRQ_HOST BIT_ULL(36)
+#define XDMA_CMD_AST2600_CMD_UPSTREAM BIT_ULL(32)
+#define XDMA_CMD_AST2600_CMD_LINE_NO GENMASK_ULL(27, 16)
+#define XDMA_CMD_AST2600_CMD_LINE_SIZE GENMASK_ULL(14, 0)
+#define XDMA_CMD_AST2600_CMD_MULTILINE_SIZE GENMASK_ULL(14, 12)
+
+#define XDMA_AST2500_QUEUE_ENTRY_SIZE 4
+#define XDMA_AST2500_HOST_CMDQ_ADDR0 0x00
+#define XDMA_AST2500_HOST_CMDQ_ENDP 0x04
+#define XDMA_AST2500_HOST_CMDQ_WRITEP 0x08
+#define XDMA_AST2500_HOST_CMDQ_READP 0x0c
+#define XDMA_AST2500_BMC_CMDQ_ADDR 0x10
+#define XDMA_AST2500_BMC_CMDQ_ENDP 0x14
+#define XDMA_AST2500_BMC_CMDQ_WRITEP 0x18
+#define XDMA_AST2500_BMC_CMDQ_READP 0x1c
+#define XDMA_BMC_CMDQ_READP_RESET 0xee882266
+#define XDMA_AST2500_CTRL 0x20
+#define XDMA_AST2500_CTRL_US_COMP BIT(4)
+#define XDMA_AST2500_CTRL_DS_COMP BIT(5)
+#define XDMA_AST2500_CTRL_DS_DIRTY BIT(6)
+#define XDMA_AST2500_CTRL_DS_SIZE_256 BIT(17)
+#define XDMA_AST2500_CTRL_DS_TIMEOUT BIT(28)
+#define XDMA_AST2500_CTRL_DS_CHECK_ID BIT(29)
+#define XDMA_AST2500_STATUS 0x24
+#define XDMA_AST2500_STATUS_US_COMP BIT(4)
+#define XDMA_AST2500_STATUS_DS_COMP BIT(5)
+#define XDMA_AST2500_STATUS_DS_DIRTY BIT(6)
+#define XDMA_AST2500_INPRG_DS_CMD1 0x38
+#define XDMA_AST2500_INPRG_DS_CMD2 0x3c
+#define XDMA_AST2500_INPRG_US_CMD00 0x40
+#define XDMA_AST2500_INPRG_US_CMD01 0x44
+#define XDMA_AST2500_INPRG_US_CMD10 0x48
+#define XDMA_AST2500_INPRG_US_CMD11 0x4c
+#define XDMA_AST2500_INPRG_US_CMD20 0x50
+#define XDMA_AST2500_INPRG_US_CMD21 0x54
+#define XDMA_AST2500_HOST_CMDQ_ADDR1 0x60
+#define XDMA_AST2500_VGA_CMDQ_ADDR0 0x64
+#define XDMA_AST2500_VGA_CMDQ_ENDP 0x68
+#define XDMA_AST2500_VGA_CMDQ_WRITEP 0x6c
+#define XDMA_AST2500_VGA_CMDQ_READP 0x70
+#define XDMA_AST2500_VGA_CMD_STATUS 0x74
+#define XDMA_AST2500_VGA_CMDQ_ADDR1 0x78
+
+#define XDMA_AST2600_QUEUE_ENTRY_SIZE 2
+#define XDMA_AST2600_HOST_CMDQ_ADDR0 0x00
+#define XDMA_AST2600_HOST_CMDQ_ADDR1 0x04
+#define XDMA_AST2600_HOST_CMDQ_ENDP 0x08
+#define XDMA_AST2600_HOST_CMDQ_WRITEP 0x0c
+#define XDMA_AST2600_HOST_CMDQ_READP 0x10
+#define XDMA_AST2600_BMC_CMDQ_ADDR 0x14
+#define XDMA_AST2600_BMC_CMDQ_ENDP 0x18
+#define XDMA_AST2600_BMC_CMDQ_WRITEP 0x1c
+#define XDMA_AST2600_BMC_CMDQ_READP 0x20
+#define XDMA_AST2600_VGA_CMDQ_ADDR0 0x24
+#define XDMA_AST2600_VGA_CMDQ_ADDR1 0x28
+#define XDMA_AST2600_VGA_CMDQ_ENDP 0x2c
+#define XDMA_AST2600_VGA_CMDQ_WRITEP 0x30
+#define XDMA_AST2600_VGA_CMDQ_READP 0x34
+#define XDMA_AST2600_CTRL 0x38
+#define XDMA_AST2600_CTRL_US_COMP BIT(16)
+#define XDMA_AST2600_CTRL_DS_COMP BIT(17)
+#define XDMA_AST2600_CTRL_DS_DIRTY BIT(18)
+#define XDMA_AST2600_CTRL_DS_SIZE_256 BIT(20)
+#define XDMA_AST2600_STATUS 0x3c
+#define XDMA_AST2600_STATUS_US_COMP BIT(16)
+#define XDMA_AST2600_STATUS_DS_COMP BIT(17)
+#define XDMA_AST2600_STATUS_DS_DIRTY BIT(18)
+#define XDMA_AST2600_INPRG_DS_CMD00 0x40
+#define XDMA_AST2600_INPRG_DS_CMD01 0x44
+#define XDMA_AST2600_INPRG_DS_CMD10 0x48
+#define XDMA_AST2600_INPRG_DS_CMD11 0x4c
+#define XDMA_AST2600_INPRG_DS_CMD20 0x50
+#define XDMA_AST2600_INPRG_DS_CMD21 0x54
+#define XDMA_AST2600_INPRG_US_CMD00 0x60
+#define XDMA_AST2600_INPRG_US_CMD01 0x64
+#define XDMA_AST2600_INPRG_US_CMD10 0x68
+#define XDMA_AST2600_INPRG_US_CMD11 0x6c
+#define XDMA_AST2600_INPRG_US_CMD20 0x70
+#define XDMA_AST2600_INPRG_US_CMD21 0x74
+
+struct aspeed_xdma_cmd {
+ u64 host_addr;
+ u64 pitch;
+ u64 cmd;
+ u64 reserved;
+};
+
+struct aspeed_xdma_regs {
+ u8 bmc_cmdq_addr;
+ u8 bmc_cmdq_endp;
+ u8 bmc_cmdq_writep;
+ u8 bmc_cmdq_readp;
+ u8 control;
+ u8 status;
+};
+
+struct aspeed_xdma_status_bits {
+ u32 us_comp;
+ u32 ds_comp;
+ u32 ds_dirty;
+};
+
+struct aspeed_xdma;
+
+struct aspeed_xdma_chip {
+ u32 control;
+ u32 scu_bmc_class;
+ u32 scu_misc_ctrl;
+ u32 scu_pcie_conf;
+ u32 sdmc_remap;
+ unsigned int queue_entry_size;
+ struct aspeed_xdma_regs regs;
+ struct aspeed_xdma_status_bits status_bits;
+ unsigned int (*set_cmd)(struct aspeed_xdma *ctx,
+ struct aspeed_xdma_cmd cmds[2],
+ struct aspeed_xdma_op *op, u32 bmc_addr);
+};
+
+struct aspeed_xdma_client;
+
+struct aspeed_xdma {
+ struct kobject kobj;
+ const struct aspeed_xdma_chip *chip;
+
+ int irq;
+ int pcie_irq;
+ struct clk *clock;
+ struct device *dev;
+ void __iomem *base;
+ resource_size_t res_size;
+ resource_size_t res_start;
+ struct reset_control *reset;
+ struct reset_control *reset_rc;
+
+ /* Protects current_client */
+ spinlock_t client_lock;
+ struct aspeed_xdma_client *current_client;
+
+ /* Protects engine configuration */
+ spinlock_t engine_lock;
+ struct aspeed_xdma_cmd *cmdq;
+ unsigned int cmd_idx;
+ bool in_reset;
+ bool upstream;
+
+ /* Queue waiters for idle engine */
+ wait_queue_head_t wait;
+
+ struct work_struct reset_work;
+
+ u32 mem_phys;
+ u32 mem_size;
+ void *mem_virt;
+ dma_addr_t mem_coherent;
+ dma_addr_t cmdq_phys;
+ struct gen_pool *pool;
+
+ struct miscdevice misc;
+};
+
+struct aspeed_xdma_client {
+ struct aspeed_xdma *ctx;
+
+ bool error;
+ bool in_progress;
+ void *virt;
+ dma_addr_t phys;
+ u32 size;
+};
+
+static u32 aspeed_xdma_readl(struct aspeed_xdma *ctx, u8 reg)
+{
+ u32 v = readl(ctx->base + reg);
+
+ dev_dbg(ctx->dev, "read %02x[%08x]\n", reg, v);
+ return v;
+}
+
+static void aspeed_xdma_writel(struct aspeed_xdma *ctx, u8 reg, u32 val)
+{
+ writel(val, ctx->base + reg);
+ dev_dbg(ctx->dev, "write %02x[%08x]\n", reg, val);
+}
+
+static void aspeed_xdma_init_eng(struct aspeed_xdma *ctx)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctx->engine_lock, flags);
+ aspeed_xdma_writel(ctx, ctx->chip->regs.bmc_cmdq_endp,
+ ctx->chip->queue_entry_size * XDMA_NUM_CMDS);
+ aspeed_xdma_writel(ctx, ctx->chip->regs.bmc_cmdq_readp,
+ XDMA_BMC_CMDQ_READP_RESET);
+ aspeed_xdma_writel(ctx, ctx->chip->regs.bmc_cmdq_writep, 0);
+ aspeed_xdma_writel(ctx, ctx->chip->regs.control, ctx->chip->control);
+ aspeed_xdma_writel(ctx, ctx->chip->regs.bmc_cmdq_addr, ctx->cmdq_phys);
+
+ ctx->cmd_idx = 0;
+ spin_unlock_irqrestore(&ctx->engine_lock, flags);
+}
+
+static unsigned int aspeed_xdma_ast2500_set_cmd(struct aspeed_xdma *ctx,
+ struct aspeed_xdma_cmd cmds[2],
+ struct aspeed_xdma_op *op,
+ u32 bmc_addr)
+{
+ unsigned int rc = 1;
+ unsigned int pitch = 1;
+ unsigned int line_no = 1;
+ unsigned int line_size = op->len >>
+ XDMA_CMD_AST2500_CMD_LINE_SIZE_SHIFT;
+ u64 cmd = XDMA_CMD_AST2500_CMD_IRQ_EN | XDMA_CMD_AST2500_CMD_IRQ_BMC |
+ XDMA_CMD_AST2500_CMD_ID;
+ u64 cmd_pitch = (op->direction ? XDMA_CMD_AST2500_PITCH_UPSTREAM : 0) |
+ XDMA_CMD_AST2500_PITCH_ID;
+
+ dev_dbg(ctx->dev, "xdma %s ast2500: bmc[%08x] len[%08x] host[%08x]\n",
+ op->direction ? "upstream" : "downstream", bmc_addr, op->len,
+ (u32)op->host_addr);
+
+ if (op->len > XDMA_CMD_AST2500_CMD_LINE_SIZE) {
+ unsigned int rem;
+ unsigned int total;
+
+ line_no = op->len / XDMA_CMD_AST2500_CMD_LINE_SIZE;
+ total = XDMA_CMD_AST2500_CMD_LINE_SIZE * line_no;
+ rem = (op->len - total) >>
+ XDMA_CMD_AST2500_CMD_LINE_SIZE_SHIFT;
+ line_size = XDMA_CMD_AST2500_CMD_LINE_SIZE;
+ pitch = line_size >> XDMA_CMD_AST2500_PITCH_SHIFT;
+ line_size >>= XDMA_CMD_AST2500_CMD_LINE_SIZE_SHIFT;
+
+ if (rem) {
+ u32 rbmc = bmc_addr + total;
+
+ cmds[1].host_addr = op->host_addr + (u64)total;
+ cmds[1].pitch = cmd_pitch |
+ ((u64)rbmc & XDMA_CMD_AST2500_PITCH_ADDR) |
+ FIELD_PREP(XDMA_CMD_AST2500_PITCH_HOST, 1) |
+ FIELD_PREP(XDMA_CMD_AST2500_PITCH_BMC, 1);
+ cmds[1].cmd = cmd |
+ FIELD_PREP(XDMA_CMD_AST2500_CMD_LINE_NO, 1) |
+ FIELD_PREP(XDMA_CMD_AST2500_CMD_LINE_SIZE,
+ rem);
+ cmds[1].reserved = 0ULL;
+
+ print_hex_dump_debug("xdma rem ", DUMP_PREFIX_OFFSET,
+ 16, 1, &cmds[1], sizeof(*cmds),
+ true);
+
+ cmd &= ~(XDMA_CMD_AST2500_CMD_IRQ_EN |
+ XDMA_CMD_AST2500_CMD_IRQ_BMC);
+
+ rc++;
+ }
+ }
+
+ cmds[0].host_addr = op->host_addr;
+ cmds[0].pitch = cmd_pitch |
+ ((u64)bmc_addr & XDMA_CMD_AST2500_PITCH_ADDR) |
+ FIELD_PREP(XDMA_CMD_AST2500_PITCH_HOST, pitch) |
+ FIELD_PREP(XDMA_CMD_AST2500_PITCH_BMC, pitch);
+ cmds[0].cmd = cmd | FIELD_PREP(XDMA_CMD_AST2500_CMD_LINE_NO, line_no) |
+ FIELD_PREP(XDMA_CMD_AST2500_CMD_LINE_SIZE, line_size);
+ cmds[0].reserved = 0ULL;
+
+ print_hex_dump_debug("xdma cmd ", DUMP_PREFIX_OFFSET, 16, 1, cmds,
+ sizeof(*cmds), true);
+
+ return rc;
+}
+
+static unsigned int aspeed_xdma_ast2600_set_cmd(struct aspeed_xdma *ctx,
+ struct aspeed_xdma_cmd cmds[2],
+ struct aspeed_xdma_op *op,
+ u32 bmc_addr)
+{
+ unsigned int rc = 1;
+ unsigned int pitch = 1;
+ unsigned int line_no = 1;
+ unsigned int line_size = op->len;
+ u64 cmd = XDMA_CMD_AST2600_CMD_IRQ_BMC |
+ (op->direction ? XDMA_CMD_AST2600_CMD_UPSTREAM : 0);
+
+ if (op->host_addr & 0xffffffff00000000ULL ||
+ (op->host_addr + (u64)op->len) & 0xffffffff00000000ULL)
+ cmd |= XDMA_CMD_AST2600_CMD_64_EN;
+
+ dev_dbg(ctx->dev, "xdma %s ast2600: bmc[%08x] len[%08x] "
+ "host[%016llx]\n", op->direction ? "upstream" : "downstream",
+ bmc_addr, op->len, op->host_addr);
+
+ if (op->len > XDMA_CMD_AST2600_CMD_LINE_SIZE) {
+ unsigned int rem;
+ unsigned int total;
+
+ line_no = op->len / XDMA_CMD_AST2600_CMD_MULTILINE_SIZE;
+ total = XDMA_CMD_AST2600_CMD_MULTILINE_SIZE * line_no;
+ rem = op->len - total;
+ line_size = XDMA_CMD_AST2600_CMD_MULTILINE_SIZE;
+ pitch = line_size;
+
+ if (rem) {
+ u32 rbmc = bmc_addr + total;
+
+ cmds[1].host_addr = op->host_addr + (u64)total;
+ cmds[1].pitch =
+ ((u64)rbmc & XDMA_CMD_AST2600_PITCH_ADDR) |
+ FIELD_PREP(XDMA_CMD_AST2600_PITCH_HOST, 1) |
+ FIELD_PREP(XDMA_CMD_AST2600_PITCH_BMC, 1);
+ cmds[1].cmd = cmd |
+ FIELD_PREP(XDMA_CMD_AST2600_CMD_LINE_NO, 1) |
+ FIELD_PREP(XDMA_CMD_AST2600_CMD_LINE_SIZE,
+ rem);
+ cmds[1].reserved = 0ULL;
+
+ print_hex_dump_debug("xdma rem ", DUMP_PREFIX_OFFSET,
+ 16, 1, &cmds[1], sizeof(*cmds),
+ true);
+
+ cmd &= ~XDMA_CMD_AST2600_CMD_IRQ_BMC;
+
+ rc++;
+ }
+ }
+
+ cmds[0].host_addr = op->host_addr;
+ cmds[0].pitch = ((u64)bmc_addr & XDMA_CMD_AST2600_PITCH_ADDR) |
+ FIELD_PREP(XDMA_CMD_AST2600_PITCH_HOST, pitch) |
+ FIELD_PREP(XDMA_CMD_AST2600_PITCH_BMC, pitch);
+ cmds[0].cmd = cmd | FIELD_PREP(XDMA_CMD_AST2600_CMD_LINE_NO, line_no) |
+ FIELD_PREP(XDMA_CMD_AST2600_CMD_LINE_SIZE, line_size);
+ cmds[0].reserved = 0ULL;
+
+ print_hex_dump_debug("xdma cmd ", DUMP_PREFIX_OFFSET, 16, 1, cmds,
+ sizeof(*cmds), true);
+
+ return rc;
+}
+
+static int aspeed_xdma_start(struct aspeed_xdma *ctx, unsigned int num_cmds,
+ struct aspeed_xdma_cmd cmds[2], bool upstream,
+ struct aspeed_xdma_client *client)
+{
+ unsigned int i;
+ int rc = -EBUSY;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctx->engine_lock, flags);
+ if (ctx->in_reset)
+ goto unlock;
+
+ spin_lock(&ctx->client_lock);
+ if (ctx->current_client) {
+ spin_unlock(&ctx->client_lock);
+ goto unlock;
+ }
+
+ client->error = false;
+ client->in_progress = true;
+ ctx->current_client = client;
+ spin_unlock(&ctx->client_lock);
+
+ ctx->upstream = upstream;
+ for (i = 0; i < num_cmds; ++i) {
+ /*
+ * Use memcpy_toio here to get some barriers before starting
+ * the operation. The command(s) need to be in physical memory
+ * before the XDMA engine starts.
+ */
+ memcpy_toio(&ctx->cmdq[ctx->cmd_idx], &cmds[i],
+ sizeof(struct aspeed_xdma_cmd));
+ ctx->cmd_idx = (ctx->cmd_idx + 1) % XDMA_NUM_CMDS;
+ }
+
+ aspeed_xdma_writel(ctx, ctx->chip->regs.bmc_cmdq_writep,
+ ctx->cmd_idx * ctx->chip->queue_entry_size);
+ rc = 0;
+
+unlock:
+ spin_unlock_irqrestore(&ctx->engine_lock, flags);
+ return rc;
+}
+
+static void aspeed_xdma_done(struct aspeed_xdma *ctx, bool error)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctx->client_lock, flags);
+ if (ctx->current_client) {
+ ctx->current_client->error = error;
+ ctx->current_client->in_progress = false;
+ ctx->current_client = NULL;
+ }
+ spin_unlock_irqrestore(&ctx->client_lock, flags);
+
+ wake_up_interruptible_all(&ctx->wait);
+}
+
+static irqreturn_t aspeed_xdma_irq(int irq, void *arg)
+{
+ struct aspeed_xdma *ctx = arg;
+ u32 status;
+
+ spin_lock(&ctx->engine_lock);
+ status = aspeed_xdma_readl(ctx, ctx->chip->regs.status);
+
+ if (status & ctx->chip->status_bits.ds_dirty) {
+ aspeed_xdma_done(ctx, true);
+ } else {
+ if (status & ctx->chip->status_bits.us_comp) {
+ if (ctx->upstream)
+ aspeed_xdma_done(ctx, false);
+ }
+
+ if (status & ctx->chip->status_bits.ds_comp) {
+ if (!ctx->upstream)
+ aspeed_xdma_done(ctx, false);
+ }
+ }
+
+ aspeed_xdma_writel(ctx, ctx->chip->regs.status, status);
+ spin_unlock(&ctx->engine_lock);
+
+ return IRQ_HANDLED;
+}
+
+static void aspeed_xdma_reset(struct aspeed_xdma *ctx)
+{
+ unsigned long flags;
+
+ reset_control_assert(ctx->reset);
+ usleep_range(XDMA_ENGINE_SETUP_TIME_MIN_US,
+ XDMA_ENGINE_SETUP_TIME_MAX_US);
+ reset_control_deassert(ctx->reset);
+ usleep_range(XDMA_ENGINE_SETUP_TIME_MIN_US,
+ XDMA_ENGINE_SETUP_TIME_MAX_US);
+
+ aspeed_xdma_init_eng(ctx);
+
+ aspeed_xdma_done(ctx, true);
+
+ spin_lock_irqsave(&ctx->engine_lock, flags);
+ ctx->in_reset = false;
+ spin_unlock_irqrestore(&ctx->engine_lock, flags);
+
+ wake_up_interruptible(&ctx->wait);
+}
+
+static void aspeed_xdma_reset_work(struct work_struct *work)
+{
+ struct aspeed_xdma *ctx = container_of(work, struct aspeed_xdma,
+ reset_work);
+
+ aspeed_xdma_reset(ctx);
+}
+
+static irqreturn_t aspeed_xdma_pcie_irq(int irq, void *arg)
+{
+ struct aspeed_xdma *ctx = arg;
+
+ dev_dbg(ctx->dev, "PCI-E reset requested.\n");
+
+ spin_lock(&ctx->engine_lock);
+ if (ctx->in_reset) {
+ spin_unlock(&ctx->engine_lock);
+ return IRQ_HANDLED;
+ }
+
+ ctx->in_reset = true;
+ spin_unlock(&ctx->engine_lock);
+
+ schedule_work(&ctx->reset_work);
+ return IRQ_HANDLED;
+}
+
+static ssize_t aspeed_xdma_write(struct file *file, const char __user *buf,
+ size_t len, loff_t *offset)
+{
+ int rc;
+ unsigned int num_cmds;
+ struct aspeed_xdma_op op;
+ struct aspeed_xdma_cmd cmds[2];
+ struct aspeed_xdma_client *client = file->private_data;
+ struct aspeed_xdma *ctx = client->ctx;
+
+ if (len != sizeof(op))
+ return -EINVAL;
+
+ rc = copy_from_user(&op, buf, len);
+ if (rc)
+ return rc;
+
+ if (!op.len || op.len > client->size ||
+ op.direction > ASPEED_XDMA_DIRECTION_UPSTREAM)
+ return -EINVAL;
+
+ num_cmds = ctx->chip->set_cmd(ctx, cmds, &op, client->phys);
+ do {
+ rc = aspeed_xdma_start(ctx, num_cmds, cmds, !!op.direction,
+ client);
+ if (!rc)
+ break;
+
+ if ((file->f_flags & O_NONBLOCK) || rc != -EBUSY)
+ return rc;
+
+ rc = wait_event_interruptible(ctx->wait,
+ !(ctx->current_client ||
+ ctx->in_reset));
+ } while (!rc);
+
+ if (rc)
+ return -EINTR;
+
+ if (!(file->f_flags & O_NONBLOCK)) {
+ rc = wait_event_interruptible(ctx->wait, !client->in_progress);
+ if (rc)
+ return -EINTR;
+
+ if (client->error)
+ return -EIO;
+ }
+
+ return len;
+}
+
+static __poll_t aspeed_xdma_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ __poll_t mask = 0;
+ __poll_t req = poll_requested_events(wait);
+ struct aspeed_xdma_client *client = file->private_data;
+ struct aspeed_xdma *ctx = client->ctx;
+
+ if (req & (EPOLLIN | EPOLLRDNORM)) {
+ if (READ_ONCE(client->in_progress))
+ poll_wait(file, &ctx->wait, wait);
+
+ if (!READ_ONCE(client->in_progress)) {
+ if (READ_ONCE(client->error))
+ mask |= EPOLLERR;
+ else
+ mask |= EPOLLIN | EPOLLRDNORM;
+ }
+ }
+
+ if (req & (EPOLLOUT | EPOLLWRNORM)) {
+ if (READ_ONCE(ctx->current_client))
+ poll_wait(file, &ctx->wait, wait);
+
+ if (!READ_ONCE(ctx->current_client))
+ mask |= EPOLLOUT | EPOLLWRNORM;
+ }
+
+ return mask;
+}
+
+static long aspeed_xdma_ioctl(struct file *file, unsigned int cmd,
+ unsigned long param)
+{
+ unsigned long flags;
+ struct aspeed_xdma_client *client = file->private_data;
+ struct aspeed_xdma *ctx = client->ctx;
+
+ switch (cmd) {
+ case ASPEED_XDMA_IOCTL_RESET:
+ spin_lock_irqsave(&ctx->engine_lock, flags);
+ if (ctx->in_reset) {
+ spin_unlock_irqrestore(&ctx->engine_lock, flags);
+ return 0;
+ }
+
+ ctx->in_reset = true;
+ spin_unlock_irqrestore(&ctx->engine_lock, flags);
+
+ if (READ_ONCE(ctx->current_client))
+ dev_warn(ctx->dev,
+ "User reset with transfer in progress.\n");
+
+ aspeed_xdma_reset(ctx);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void aspeed_xdma_vma_close(struct vm_area_struct *vma)
+{
+ int rc;
+ struct aspeed_xdma_client *client = vma->vm_private_data;
+
+ rc = wait_event_interruptible(client->ctx->wait, !client->in_progress);
+ if (rc)
+ return;
+
+ gen_pool_free(client->ctx->pool, (unsigned long)client->virt,
+ client->size);
+
+ client->virt = NULL;
+ client->phys = 0;
+ client->size = 0;
+}
+
+static const struct vm_operations_struct aspeed_xdma_vm_ops = {
+ .close = aspeed_xdma_vma_close,
+};
+
+static int aspeed_xdma_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ int rc;
+ struct aspeed_xdma_client *client = file->private_data;
+ struct aspeed_xdma *ctx = client->ctx;
+
+ /* restrict file to one mapping */
+ if (client->size)
+ return -EBUSY;
+
+ client->size = vma->vm_end - vma->vm_start;
+ client->virt = gen_pool_dma_alloc(ctx->pool, client->size,
+ &client->phys);
+ if (!client->virt) {
+ client->phys = 0;
+ client->size = 0;
+ return -ENOMEM;
+ }
+
+ vma->vm_pgoff = (client->phys - ctx->mem_phys) >> PAGE_SHIFT;
+ vma->vm_ops = &aspeed_xdma_vm_ops;
+ vma->vm_private_data = client;
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ rc = io_remap_pfn_range(vma, vma->vm_start, client->phys >> PAGE_SHIFT,
+ client->size, vma->vm_page_prot);
+ if (rc) {
+ dev_warn(ctx->dev, "mmap err: v[%08lx] to p[%08x], s[%08x]\n",
+ vma->vm_start, (u32)client->phys, client->size);
+
+ gen_pool_free(ctx->pool, (unsigned long)client->virt,
+ client->size);
+
+ client->virt = NULL;
+ client->phys = 0;
+ client->size = 0;
+ return rc;
+ }
+
+ dev_dbg(ctx->dev, "mmap: v[%08lx] to p[%08x], s[%08x]\n",
+ vma->vm_start, (u32)client->phys, client->size);
+
+ return 0;
+}
+
+static int aspeed_xdma_open(struct inode *inode, struct file *file)
+{
+ struct miscdevice *misc = file->private_data;
+ struct aspeed_xdma *ctx = container_of(misc, struct aspeed_xdma, misc);
+ struct aspeed_xdma_client *client = kzalloc(sizeof(*client),
+ GFP_KERNEL);
+
+ if (!client)
+ return -ENOMEM;
+
+ kobject_get(&ctx->kobj);
+ client->ctx = ctx;
+ file->private_data = client;
+ return 0;
+}
+
+static int aspeed_xdma_release(struct inode *inode, struct file *file)
+{
+ bool reset = false;
+ unsigned long flags;
+ struct aspeed_xdma_client *client = file->private_data;
+ struct aspeed_xdma *ctx = client->ctx;
+
+ spin_lock_irqsave(&ctx->client_lock, flags);
+ if (client == ctx->current_client) {
+ spin_lock(&ctx->engine_lock);
+ if (ctx->in_reset) {
+ ctx->current_client = NULL;
+ } else {
+ ctx->in_reset = true;
+ reset = true;
+ }
+ spin_unlock(&ctx->engine_lock);
+ }
+ spin_unlock_irqrestore(&ctx->client_lock, flags);
+
+ if (reset)
+ aspeed_xdma_reset(ctx);
+
+ if (client->virt)
+ gen_pool_free(ctx->pool, (unsigned long)client->virt,
+ client->size);
+
+ kfree(client);
+ kobject_put(&ctx->kobj);
+ return 0;
+}
+
+static const struct file_operations aspeed_xdma_fops = {
+ .owner = THIS_MODULE,
+ .write = aspeed_xdma_write,
+ .poll = aspeed_xdma_poll,
+ .unlocked_ioctl = aspeed_xdma_ioctl,
+ .mmap = aspeed_xdma_mmap,
+ .open = aspeed_xdma_open,
+ .release = aspeed_xdma_release,
+};
+
+static int aspeed_xdma_init_scu(struct aspeed_xdma *ctx, struct device *dev)
+{
+ struct regmap *scu = syscon_regmap_lookup_by_phandle(dev->of_node,
+ "aspeed,scu");
+
+ if (!IS_ERR(scu)) {
+ u32 selection;
+ bool pcie_device_bmc = true;
+ const u32 bmc = SCU_PCIE_CONF_BMC_EN |
+ SCU_PCIE_CONF_BMC_EN_MSI | SCU_PCIE_CONF_BMC_EN_IRQ |
+ SCU_PCIE_CONF_BMC_EN_DMA;
+ const u32 vga = SCU_PCIE_CONF_VGA_EN |
+ SCU_PCIE_CONF_VGA_EN_MSI | SCU_PCIE_CONF_VGA_EN_IRQ |
+ SCU_PCIE_CONF_VGA_EN_DMA;
+ const char *pcie = NULL;
+
+ if (!of_property_read_string(dev->of_node,
+ "aspeed,pcie-device", &pcie)) {
+ if (!strcmp(pcie, "vga")) {
+ pcie_device_bmc = false;
+ } else if (strcmp(pcie, "bmc")) {
+ dev_err(dev,
+ "Invalid pcie-device property %s.\n",
+ pcie);
+ return -EINVAL;
+ }
+ }
+
+ if (pcie_device_bmc) {
+ selection = bmc;
+ regmap_write(scu, ctx->chip->scu_bmc_class,
+ SCU_BMC_CLASS_REV_XDMA);
+ } else {
+ selection = vga;
+ }
+
+ regmap_update_bits(scu, ctx->chip->scu_pcie_conf, bmc | vga,
+ selection);
+
+ if (ctx->chip->scu_misc_ctrl)
+ regmap_update_bits(scu, ctx->chip->scu_misc_ctrl,
+ SCU_AST2600_MISC_CTRL_XDMA_BMC,
+ SCU_AST2600_MISC_CTRL_XDMA_BMC);
+ } else {
+ dev_warn(dev, "Unable to configure PCIe: %ld; continuing.\n",
+ PTR_ERR(scu));
+ }
+
+ return 0;
+}
+
+static void aspeed_xdma_kobject_release(struct kobject *kobj)
+{
+ struct aspeed_xdma *ctx = container_of(kobj, struct aspeed_xdma, kobj);
+
+ if (ctx->pcie_irq >= 0)
+ free_irq(ctx->pcie_irq, ctx);
+
+ gen_pool_free(ctx->pool, (unsigned long)ctx->cmdq, XDMA_CMDQ_SIZE);
+
+ gen_pool_destroy(ctx->pool);
+
+ dma_free_coherent(ctx->dev, ctx->mem_size, ctx->mem_virt,
+ ctx->mem_coherent);
+
+ if (ctx->reset_rc)
+ reset_control_put(ctx->reset_rc);
+ reset_control_put(ctx->reset);
+
+ clk_put(ctx->clock);
+
+ free_irq(ctx->irq, ctx);
+
+ iounmap(ctx->base);
+ release_mem_region(ctx->res_start, ctx->res_size);
+
+ kfree(ctx);
+}
+
+static struct kobj_type aspeed_xdma_kobject_type = {
+ .release = aspeed_xdma_kobject_release,
+};
+
+static int aspeed_xdma_iomap(struct aspeed_xdma *ctx,
+ struct platform_device *pdev)
+{
+ resource_size_t size;
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ if (!res)
+ return -ENOMEM;
+
+ size = resource_size(res);
+ if (!request_mem_region(res->start, size, dev_name(ctx->dev)))
+ return -ENOMEM;
+
+ ctx->base = ioremap(res->start, size);
+ if (!ctx->base) {
+ release_mem_region(res->start, size);
+ return -ENOMEM;
+ }
+
+ ctx->res_start = res->start;
+ ctx->res_size = size;
+
+ return 0;
+}
+
+static int aspeed_xdma_probe(struct platform_device *pdev)
+{
+ int rc;
+ struct regmap *sdmc;
+ struct aspeed_xdma *ctx;
+ struct reserved_mem *mem;
+ struct device *dev = &pdev->dev;
+ struct device_node *memory_region;
+ const void *md = of_device_get_match_data(dev);
+
+ if (!md)
+ return -ENODEV;
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->chip = md;
+ ctx->dev = dev;
+ platform_set_drvdata(pdev, ctx);
+ spin_lock_init(&ctx->client_lock);
+ spin_lock_init(&ctx->engine_lock);
+ INIT_WORK(&ctx->reset_work, aspeed_xdma_reset_work);
+ init_waitqueue_head(&ctx->wait);
+
+ rc = aspeed_xdma_iomap(ctx, pdev);
+ if (rc) {
+ dev_err(dev, "Failed to map registers.\n");
+ goto err_nomap;
+ }
+
+ ctx->irq = platform_get_irq(pdev, 0);
+ if (ctx->irq < 0) {
+ dev_err(dev, "Failed to find IRQ.\n");
+ rc = ctx->irq;
+ goto err_noirq;
+ }
+
+ rc = request_irq(ctx->irq, aspeed_xdma_irq, 0, DEVICE_NAME, ctx);
+ if (rc < 0) {
+ dev_err(dev, "Failed to request IRQ %d.\n", ctx->irq);
+ goto err_noirq;
+ }
+
+ ctx->clock = clk_get(dev, NULL);
+ if (IS_ERR(ctx->clock)) {
+ dev_err(dev, "Failed to request clock.\n");
+ rc = PTR_ERR(ctx->clock);
+ goto err_noclk;
+ }
+
+ ctx->reset = reset_control_get_exclusive(dev, NULL);
+ if (IS_ERR(ctx->reset)) {
+ dev_err(dev, "Failed to request reset control.\n");
+ rc = PTR_ERR(ctx->reset);
+ goto err_noreset;
+ }
+
+ ctx->reset_rc = reset_control_get_exclusive(dev, "root-complex");
+ if (IS_ERR(ctx->reset_rc)) {
+ dev_dbg(dev, "Failed to request reset RC control.\n");
+ ctx->reset_rc = NULL;
+ }
+
+ memory_region = of_parse_phandle(dev->of_node, "memory-region", 0);
+ if (!memory_region) {
+ dev_err(dev, "Failed to find memory-region.\n");
+ rc = -ENOMEM;
+ goto err_nomem;
+ }
+
+ mem = of_reserved_mem_lookup(memory_region);
+ of_node_put(memory_region);
+ if (!mem) {
+ dev_err(dev, "Failed to find reserved memory.\n");
+ rc = -ENOMEM;
+ goto err_nomem;
+ }
+
+ ctx->mem_phys = mem->base;
+ ctx->mem_size = mem->size;
+
+ rc = of_reserved_mem_device_init(dev);
+ if (rc) {
+ dev_err(dev, "Failed to init reserved memory.\n");
+ goto err_nomem;
+ }
+
+ rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
+ if (rc) {
+ dev_err(dev, "Failed to mask DMA.\n");
+ goto err_nomem;
+ }
+
+ ctx->mem_virt = dma_alloc_coherent(dev, ctx->mem_size,
+ &ctx->mem_coherent, 0);
+ if (!ctx->mem_virt) {
+ dev_err(dev, "Failed to allocate reserved memory.\n");
+ rc = -ENOMEM;
+ goto err_nomem;
+ }
+
+ ctx->pool = gen_pool_create(ilog2(PAGE_SIZE), -1);
+ if (!ctx->pool) {
+ dev_err(dev, "Failed to setup genalloc pool.\n");
+ rc = -ENOMEM;
+ goto err_nopool;
+ }
+
+ rc = gen_pool_add_virt(ctx->pool, (unsigned long)ctx->mem_virt,
+ ctx->mem_phys, ctx->mem_size, -1);
+ if (rc) {
+ dev_err(ctx->dev, "Failed to add memory to genalloc pool.\n");
+ goto err_pool_scu_clk;
+ }
+
+ sdmc = syscon_regmap_lookup_by_phandle(dev->of_node, "sdmc");
+ if (!IS_ERR(sdmc))
+ regmap_update_bits(sdmc, SDMC_REMAP, ctx->chip->sdmc_remap,
+ ctx->chip->sdmc_remap);
+ else
+ dev_err(dev, "Unable to configure memory controller.\n");
+
+ rc = aspeed_xdma_init_scu(ctx, dev);
+ if (rc)
+ goto err_pool_scu_clk;
+
+ rc = clk_prepare_enable(ctx->clock);
+ if (rc) {
+ dev_err(dev, "Failed to enable the clock.\n");
+ goto err_pool_scu_clk;
+ }
+
+ if (ctx->reset_rc) {
+ rc = reset_control_deassert(ctx->reset_rc);
+ if (rc) {
+ dev_err(dev, "Failed to clear the RC reset.\n");
+ goto err_reset_rc;
+ }
+ usleep_range(XDMA_ENGINE_SETUP_TIME_MIN_US,
+ XDMA_ENGINE_SETUP_TIME_MAX_US);
+ }
+
+ rc = reset_control_deassert(ctx->reset);
+ if (rc) {
+ dev_err(dev, "Failed to clear the reset.\n");
+ goto err_reset;
+ }
+ usleep_range(XDMA_ENGINE_SETUP_TIME_MIN_US,
+ XDMA_ENGINE_SETUP_TIME_MAX_US);
+
+ ctx->cmdq = gen_pool_dma_alloc(ctx->pool, XDMA_CMDQ_SIZE,
+ &ctx->cmdq_phys);
+ if (!ctx->cmdq) {
+ dev_err(ctx->dev, "Failed to genalloc cmdq.\n");
+ rc = -ENOMEM;
+ goto err_pool;
+ }
+
+ aspeed_xdma_init_eng(ctx);
+
+ ctx->misc.minor = MISC_DYNAMIC_MINOR;
+ ctx->misc.fops = &aspeed_xdma_fops;
+ ctx->misc.name = "aspeed-xdma";
+ ctx->misc.parent = dev;
+ rc = misc_register(&ctx->misc);
+ if (rc) {
+ dev_err(dev, "Failed to register xdma miscdevice.\n");
+ goto err_misc;
+ }
+
+ /*
+ * This interrupt could fire immediately so only request it once the
+ * engine and driver are initialized.
+ */
+ ctx->pcie_irq = platform_get_irq(pdev, 1);
+ if (ctx->pcie_irq < 0) {
+ dev_warn(dev, "Failed to find PCI-E IRQ.\n");
+ } else {
+ rc = request_irq(ctx->pcie_irq, aspeed_xdma_pcie_irq,
+ IRQF_SHARED, DEVICE_NAME, ctx);
+ if (rc < 0) {
+ dev_warn(dev, "Failed to request PCI-E IRQ %d.\n", rc);
+ ctx->pcie_irq = -1;
+ }
+ }
+
+ kobject_init(&ctx->kobj, &aspeed_xdma_kobject_type);
+ return 0;
+
+err_misc:
+ gen_pool_free(ctx->pool, (unsigned long)ctx->cmdq, XDMA_CMDQ_SIZE);
+err_pool:
+ reset_control_assert(ctx->reset);
+err_reset:
+ if (ctx->reset_rc)
+ reset_control_assert(ctx->reset_rc);
+err_reset_rc:
+ clk_disable_unprepare(ctx->clock);
+err_pool_scu_clk:
+ gen_pool_destroy(ctx->pool);
+err_nopool:
+ dma_free_coherent(ctx->dev, ctx->mem_size, ctx->mem_virt,
+ ctx->mem_coherent);
+err_nomem:
+ if (ctx->reset_rc)
+ reset_control_put(ctx->reset_rc);
+ reset_control_put(ctx->reset);
+err_noreset:
+ clk_put(ctx->clock);
+err_noclk:
+ free_irq(ctx->irq, ctx);
+err_noirq:
+ iounmap(ctx->base);
+ release_mem_region(ctx->res_start, ctx->res_size);
+err_nomap:
+ kfree(ctx);
+ return rc;
+}
+
+static int aspeed_xdma_remove(struct platform_device *pdev)
+{
+ struct aspeed_xdma *ctx = platform_get_drvdata(pdev);
+
+ reset_control_assert(ctx->reset);
+ if (ctx->reset_rc)
+ reset_control_assert(ctx->reset_rc);
+ clk_disable_unprepare(ctx->clock);
+
+ aspeed_xdma_done(ctx, true);
+
+ misc_deregister(&ctx->misc);
+ kobject_put(&ctx->kobj);
+
+ return 0;
+}
+
+static const struct aspeed_xdma_chip aspeed_ast2500_xdma_chip = {
+ .control = XDMA_AST2500_CTRL_US_COMP | XDMA_AST2500_CTRL_DS_COMP |
+ XDMA_AST2500_CTRL_DS_DIRTY | XDMA_AST2500_CTRL_DS_SIZE_256 |
+ XDMA_AST2500_CTRL_DS_TIMEOUT | XDMA_AST2500_CTRL_DS_CHECK_ID,
+ .scu_bmc_class = SCU_AST2500_BMC_CLASS_REV,
+ .scu_misc_ctrl = 0,
+ .scu_pcie_conf = SCU_AST2500_PCIE_CONF,
+ .sdmc_remap = SDMC_AST2500_REMAP_PCIE | SDMC_AST2500_REMAP_XDMA,
+ .queue_entry_size = XDMA_AST2500_QUEUE_ENTRY_SIZE,
+ .regs = {
+ .bmc_cmdq_addr = XDMA_AST2500_BMC_CMDQ_ADDR,
+ .bmc_cmdq_endp = XDMA_AST2500_BMC_CMDQ_ENDP,
+ .bmc_cmdq_writep = XDMA_AST2500_BMC_CMDQ_WRITEP,
+ .bmc_cmdq_readp = XDMA_AST2500_BMC_CMDQ_READP,
+ .control = XDMA_AST2500_CTRL,
+ .status = XDMA_AST2500_STATUS,
+ },
+ .status_bits = {
+ .us_comp = XDMA_AST2500_STATUS_US_COMP,
+ .ds_comp = XDMA_AST2500_STATUS_DS_COMP,
+ .ds_dirty = XDMA_AST2500_STATUS_DS_DIRTY,
+ },
+ .set_cmd = aspeed_xdma_ast2500_set_cmd,
+};
+
+static const struct aspeed_xdma_chip aspeed_ast2600_xdma_chip = {
+ .control = XDMA_AST2600_CTRL_US_COMP | XDMA_AST2600_CTRL_DS_COMP |
+ XDMA_AST2600_CTRL_DS_DIRTY | XDMA_AST2600_CTRL_DS_SIZE_256,
+ .scu_bmc_class = SCU_AST2600_BMC_CLASS_REV,
+ .scu_misc_ctrl = SCU_AST2600_MISC_CTRL,
+ .scu_pcie_conf = SCU_AST2600_PCIE_CONF,
+ .sdmc_remap = SDMC_AST2600_REMAP_XDMA,
+ .queue_entry_size = XDMA_AST2600_QUEUE_ENTRY_SIZE,
+ .regs = {
+ .bmc_cmdq_addr = XDMA_AST2600_BMC_CMDQ_ADDR,
+ .bmc_cmdq_endp = XDMA_AST2600_BMC_CMDQ_ENDP,
+ .bmc_cmdq_writep = XDMA_AST2600_BMC_CMDQ_WRITEP,
+ .bmc_cmdq_readp = XDMA_AST2600_BMC_CMDQ_READP,
+ .control = XDMA_AST2600_CTRL,
+ .status = XDMA_AST2600_STATUS,
+ },
+ .status_bits = {
+ .us_comp = XDMA_AST2600_STATUS_US_COMP,
+ .ds_comp = XDMA_AST2600_STATUS_DS_COMP,
+ .ds_dirty = XDMA_AST2600_STATUS_DS_DIRTY,
+ },
+ .set_cmd = aspeed_xdma_ast2600_set_cmd,
+};
+
+static const struct of_device_id aspeed_xdma_match[] = {
+ {
+ .compatible = "aspeed,ast2500-xdma",
+ .data = &aspeed_ast2500_xdma_chip,
+ },
+ {
+ .compatible = "aspeed,ast2600-xdma",
+ .data = &aspeed_ast2600_xdma_chip,
+ },
+ { },
+};
+
+static struct platform_driver aspeed_xdma_driver = {
+ .probe = aspeed_xdma_probe,
+ .remove = aspeed_xdma_remove,
+ .driver = {
+ .name = DEVICE_NAME,
+ .of_match_table = aspeed_xdma_match,
+ },
+};
+
+module_platform_driver(aspeed_xdma_driver);
+
+MODULE_AUTHOR("Eddie James");
+MODULE_DESCRIPTION("Aspeed XDMA Engine Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 6f7fdcbb9151..ee8634d8417e 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -263,6 +263,13 @@ config SPI_FALCON
has only been tested with m25p80 type chips. The hardware has no
support for other types of SPI peripherals.
+config SPI_FSI
+ tristate "FSI SPI driver"
+ depends on FSI
+ help
+ This enables support for the driver for FSI bus attached SPI
+ controllers.
+
config SPI_FSL_LPSPI
tristate "Freescale i.MX LPSPI controller"
depends on ARCH_MXC || COMPILE_TEST
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index bb49c9e6d0a0..5cb476315ad6 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -40,6 +40,7 @@ spi-dw-midpci-objs := spi-dw-pci.o spi-dw-mid.o
obj-$(CONFIG_SPI_EFM32) += spi-efm32.o
obj-$(CONFIG_SPI_EP93XX) += spi-ep93xx.o
obj-$(CONFIG_SPI_FALCON) += spi-falcon.o
+obj-$(CONFIG_SPI_FSI) += spi-fsi.o
obj-$(CONFIG_SPI_FSL_CPM) += spi-fsl-cpm.o
obj-$(CONFIG_SPI_FSL_DSPI) += spi-fsl-dspi.o
obj-$(CONFIG_SPI_FSL_LIB) += spi-fsl-lib.o
diff --git a/drivers/spi/spi-fsi.c b/drivers/spi/spi-fsi.c
new file mode 100644
index 000000000000..37a3e0f8e752
--- /dev/null
+++ b/drivers/spi/spi-fsi.c
@@ -0,0 +1,558 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// Copyright (C) IBM Corporation 2020
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/fsi.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/spi/spi.h>
+
+#define FSI_ENGID_SPI 0x23
+#define FSI_MBOX_ROOT_CTRL_8 0x2860
+
+#define FSI2SPI_DATA0 0x00
+#define FSI2SPI_DATA1 0x04
+#define FSI2SPI_CMD 0x08
+#define FSI2SPI_CMD_WRITE BIT(31)
+#define FSI2SPI_RESET 0x18
+#define FSI2SPI_STATUS 0x1c
+#define FSI2SPI_STATUS_ANY_ERROR BIT(31)
+#define FSI2SPI_IRQ 0x20
+
+#define SPI_FSI_BASE 0x70000
+#define SPI_FSI_INIT_TIMEOUT_MS 1000
+#define SPI_FSI_MAX_TRANSFER_SIZE 2048
+
+#define SPI_FSI_ERROR 0x0
+#define SPI_FSI_COUNTER_CFG 0x1
+#define SPI_FSI_COUNTER_CFG_LOOPS(x) (((u64)(x) & 0xffULL) << 32)
+#define SPI_FSI_CFG1 0x2
+#define SPI_FSI_CLOCK_CFG 0x3
+#define SPI_FSI_CLOCK_CFG_MM_ENABLE BIT_ULL(32)
+#define SPI_FSI_CLOCK_CFG_ECC_DISABLE (BIT_ULL(35) | BIT_ULL(33))
+#define SPI_FSI_CLOCK_CFG_RESET1 (BIT_ULL(36) | BIT_ULL(38))
+#define SPI_FSI_CLOCK_CFG_RESET2 (BIT_ULL(37) | BIT_ULL(39))
+#define SPI_FSI_CLOCK_CFG_MODE (BIT_ULL(41) | BIT_ULL(42))
+#define SPI_FSI_CLOCK_CFG_SCK_RECV_DEL GENMASK_ULL(51, 44)
+#define SPI_FSI_CLOCK_CFG_SCK_NO_DEL BIT_ULL(51)
+#define SPI_FSI_CLOCK_CFG_SCK_DIV GENMASK_ULL(63, 52)
+#define SPI_FSI_MMAP 0x4
+#define SPI_FSI_DATA_TX 0x5
+#define SPI_FSI_DATA_RX 0x6
+#define SPI_FSI_SEQUENCE 0x7
+#define SPI_FSI_SEQUENCE_STOP 0x00
+#define SPI_FSI_SEQUENCE_SEL_SLAVE(x) (0x10 | ((x) & 0xf))
+#define SPI_FSI_SEQUENCE_SHIFT_OUT(x) (0x30 | ((x) & 0xf))
+#define SPI_FSI_SEQUENCE_SHIFT_IN(x) (0x40 | ((x) & 0xf))
+#define SPI_FSI_SEQUENCE_COPY_DATA_TX 0xc0
+#define SPI_FSI_SEQUENCE_BRANCH(x) (0xe0 | ((x) & 0xf))
+#define SPI_FSI_STATUS 0x8
+#define SPI_FSI_STATUS_ERROR \
+ (GENMASK_ULL(31, 21) | GENMASK_ULL(15, 12))
+#define SPI_FSI_STATUS_SEQ_STATE GENMASK_ULL(55, 48)
+#define SPI_FSI_STATUS_SEQ_STATE_IDLE BIT_ULL(48)
+#define SPI_FSI_STATUS_TDR_UNDERRUN BIT_ULL(57)
+#define SPI_FSI_STATUS_TDR_OVERRUN BIT_ULL(58)
+#define SPI_FSI_STATUS_TDR_FULL BIT_ULL(59)
+#define SPI_FSI_STATUS_RDR_UNDERRUN BIT_ULL(61)
+#define SPI_FSI_STATUS_RDR_OVERRUN BIT_ULL(62)
+#define SPI_FSI_STATUS_RDR_FULL BIT_ULL(63)
+#define SPI_FSI_STATUS_ANY_ERROR \
+ (SPI_FSI_STATUS_ERROR | SPI_FSI_STATUS_TDR_UNDERRUN | \
+ SPI_FSI_STATUS_TDR_OVERRUN | SPI_FSI_STATUS_RDR_UNDERRUN | \
+ SPI_FSI_STATUS_RDR_OVERRUN)
+#define SPI_FSI_PORT_CTRL 0x9
+
+struct fsi_spi {
+ struct device *dev; /* SPI controller device */
+ struct fsi_device *fsi; /* FSI2SPI CFAM engine device */
+ u32 base;
+};
+
+struct fsi_spi_sequence {
+ int bit;
+ u64 data;
+};
+
+static int fsi_spi_check_status(struct fsi_spi *ctx)
+{
+ int rc;
+ u32 sts;
+ __be32 sts_be;
+
+ rc = fsi_device_read(ctx->fsi, FSI2SPI_STATUS, &sts_be,
+ sizeof(sts_be));
+ if (rc)
+ return rc;
+
+ sts = be32_to_cpu(sts_be);
+ if (sts & FSI2SPI_STATUS_ANY_ERROR) {
+ dev_err(ctx->dev, "Error with FSI2SPI interface: %08x.\n", sts);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int fsi_spi_read_reg(struct fsi_spi *ctx, u32 offset, u64 *value)
+{
+ int rc;
+ __be32 cmd_be;
+ __be32 data_be;
+ u32 cmd = offset + ctx->base;
+
+ *value = 0ULL;
+
+ if (cmd & FSI2SPI_CMD_WRITE)
+ return -EINVAL;
+
+ cmd_be = cpu_to_be32(cmd);
+ rc = fsi_device_write(ctx->fsi, FSI2SPI_CMD, &cmd_be, sizeof(cmd_be));
+ if (rc)
+ return rc;
+
+ rc = fsi_spi_check_status(ctx);
+ if (rc)
+ return rc;
+
+ rc = fsi_device_read(ctx->fsi, FSI2SPI_DATA0, &data_be,
+ sizeof(data_be));
+ if (rc)
+ return rc;
+
+ *value |= (u64)be32_to_cpu(data_be) << 32;
+
+ rc = fsi_device_read(ctx->fsi, FSI2SPI_DATA1, &data_be,
+ sizeof(data_be));
+ if (rc)
+ return rc;
+
+ *value |= (u64)be32_to_cpu(data_be);
+ dev_dbg(ctx->dev, "Read %02x[%016llx].\n", offset, *value);
+
+ return 0;
+}
+
+static int fsi_spi_write_reg(struct fsi_spi *ctx, u32 offset, u64 value)
+{
+ int rc;
+ __be32 cmd_be;
+ __be32 data_be;
+ u32 cmd = offset + ctx->base;
+
+ if (cmd & FSI2SPI_CMD_WRITE)
+ return -EINVAL;
+
+ dev_dbg(ctx->dev, "Write %02x[%016llx].\n", offset, value);
+
+ data_be = cpu_to_be32(upper_32_bits(value));
+ rc = fsi_device_write(ctx->fsi, FSI2SPI_DATA0, &data_be,
+ sizeof(data_be));
+ if (rc)
+ return rc;
+
+ data_be = cpu_to_be32(lower_32_bits(value));
+ rc = fsi_device_write(ctx->fsi, FSI2SPI_DATA1, &data_be,
+ sizeof(data_be));
+ if (rc)
+ return rc;
+
+ cmd_be = cpu_to_be32(cmd | FSI2SPI_CMD_WRITE);
+ rc = fsi_device_write(ctx->fsi, FSI2SPI_CMD, &cmd_be, sizeof(cmd_be));
+ if (rc)
+ return rc;
+
+ return fsi_spi_check_status(ctx);
+}
+
+static int fsi_spi_data_in(u64 in, u8 *rx, int len)
+{
+ int i;
+ int num_bytes = min(len, 8);
+
+ for (i = 0; i < num_bytes; ++i)
+ rx[i] = (u8)(in >> (8 * ((num_bytes - 1) - i)));
+
+ return num_bytes;
+}
+
+static int fsi_spi_data_out(u64 *out, const u8 *tx, int len)
+{
+ int i;
+ int num_bytes = min(len, 8);
+ u8 *out_bytes = (u8 *)out;
+
+ /* Unused bytes of the tx data should be 0. */
+ *out = 0ULL;
+
+ for (i = 0; i < num_bytes; ++i)
+ out_bytes[8 - (i + 1)] = tx[i];
+
+ return num_bytes;
+}
+
+static int fsi_spi_reset(struct fsi_spi *ctx)
+{
+ int rc;
+
+ dev_dbg(ctx->dev, "Resetting SPI controller.\n");
+
+ rc = fsi_spi_write_reg(ctx, SPI_FSI_CLOCK_CFG,
+ SPI_FSI_CLOCK_CFG_RESET1);
+ if (rc)
+ return rc;
+
+ return fsi_spi_write_reg(ctx, SPI_FSI_CLOCK_CFG,
+ SPI_FSI_CLOCK_CFG_RESET2);
+}
+
+static int fsi_spi_sequence_add(struct fsi_spi_sequence *seq, u8 val)
+{
+ /*
+ * Add the next byte of instruction to the 8-byte sequence register.
+ * Then decrement the counter so that the next instruction will go in
+ * the right place. Return the number of "slots" left in the sequence
+ * register.
+ */
+ seq->data |= (u64)val << seq->bit;
+ seq->bit -= 8;
+
+ return ((64 - seq->bit) / 8) - 2;
+}
+
+static void fsi_spi_sequence_init(struct fsi_spi_sequence *seq)
+{
+ seq->bit = 56;
+ seq->data = 0ULL;
+}
+
+static int fsi_spi_sequence_transfer(struct fsi_spi *ctx,
+ struct fsi_spi_sequence *seq,
+ struct spi_transfer *transfer)
+{
+ int loops;
+ int idx;
+ int rc;
+ u8 len = min(transfer->len, 8U);
+ u8 rem = transfer->len % len;
+
+ loops = transfer->len / len;
+
+ if (transfer->tx_buf) {
+ idx = fsi_spi_sequence_add(seq,
+ SPI_FSI_SEQUENCE_SHIFT_OUT(len));
+ if (rem)
+ rem = SPI_FSI_SEQUENCE_SHIFT_OUT(rem);
+ } else if (transfer->rx_buf) {
+ idx = fsi_spi_sequence_add(seq,
+ SPI_FSI_SEQUENCE_SHIFT_IN(len));
+ if (rem)
+ rem = SPI_FSI_SEQUENCE_SHIFT_IN(rem);
+ } else {
+ return -EINVAL;
+ }
+
+ if (loops > 1) {
+ fsi_spi_sequence_add(seq, SPI_FSI_SEQUENCE_BRANCH(idx));
+
+ if (rem)
+ fsi_spi_sequence_add(seq, rem);
+
+ rc = fsi_spi_write_reg(ctx, SPI_FSI_COUNTER_CFG,
+ SPI_FSI_COUNTER_CFG_LOOPS(loops - 1));
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
+static int fsi_spi_transfer_data(struct fsi_spi *ctx,
+ struct spi_transfer *transfer)
+{
+ int rc = 0;
+ u64 status = 0ULL;
+
+ if (transfer->tx_buf) {
+ int nb;
+ int sent = 0;
+ u64 out = 0ULL;
+ const u8 *tx = transfer->tx_buf;
+
+ while (transfer->len > sent) {
+ nb = fsi_spi_data_out(&out, &tx[sent],
+ (int)transfer->len - sent);
+
+ rc = fsi_spi_write_reg(ctx, SPI_FSI_DATA_TX, out);
+ if (rc)
+ return rc;
+
+ do {
+ rc = fsi_spi_read_reg(ctx, SPI_FSI_STATUS,
+ &status);
+ if (rc)
+ return rc;
+
+ if (status & SPI_FSI_STATUS_ANY_ERROR) {
+ rc = fsi_spi_reset(ctx);
+ if (rc)
+ return rc;
+
+ return -EREMOTEIO;
+ }
+ } while (status & SPI_FSI_STATUS_TDR_FULL);
+
+ sent += nb;
+ }
+ } else if (transfer->rx_buf) {
+ int recv = 0;
+ u64 in = 0ULL;
+ u8 *rx = transfer->rx_buf;
+
+ while (transfer->len > recv) {
+ do {
+ rc = fsi_spi_read_reg(ctx, SPI_FSI_STATUS,
+ &status);
+ if (rc)
+ return rc;
+
+ if (status & SPI_FSI_STATUS_ANY_ERROR) {
+ rc = fsi_spi_reset(ctx);
+ if (rc)
+ return rc;
+
+ return -EREMOTEIO;
+ }
+ } while (!(status & SPI_FSI_STATUS_RDR_FULL));
+
+ rc = fsi_spi_read_reg(ctx, SPI_FSI_DATA_RX, &in);
+ if (rc)
+ return rc;
+
+ recv += fsi_spi_data_in(in, &rx[recv],
+ (int)transfer->len - recv);
+ }
+ }
+
+ return 0;
+}
+
+static int fsi_spi_transfer_init(struct fsi_spi *ctx)
+{
+ int rc;
+ bool reset = false;
+ unsigned long end;
+ u64 seq_state;
+ u64 clock_cfg = 0ULL;
+ u64 status = 0ULL;
+ u64 wanted_clock_cfg = SPI_FSI_CLOCK_CFG_ECC_DISABLE |
+ SPI_FSI_CLOCK_CFG_SCK_NO_DEL |
+ FIELD_PREP(SPI_FSI_CLOCK_CFG_SCK_DIV, 4);
+
+ end = jiffies + msecs_to_jiffies(SPI_FSI_INIT_TIMEOUT_MS);
+ do {
+ if (time_after(jiffies, end))
+ return -ETIMEDOUT;
+
+ rc = fsi_spi_read_reg(ctx, SPI_FSI_STATUS, &status);
+ if (rc)
+ return rc;
+
+ seq_state = status & SPI_FSI_STATUS_SEQ_STATE;
+
+ if (status & (SPI_FSI_STATUS_ANY_ERROR |
+ SPI_FSI_STATUS_TDR_FULL |
+ SPI_FSI_STATUS_RDR_FULL)) {
+ if (reset)
+ return -EIO;
+
+ rc = fsi_spi_reset(ctx);
+ if (rc)
+ return rc;
+
+ reset = true;
+ continue;
+ }
+ } while (seq_state && (seq_state != SPI_FSI_STATUS_SEQ_STATE_IDLE));
+
+ rc = fsi_spi_read_reg(ctx, SPI_FSI_CLOCK_CFG, &clock_cfg);
+ if (rc)
+ return rc;
+
+ if ((clock_cfg & (SPI_FSI_CLOCK_CFG_MM_ENABLE |
+ SPI_FSI_CLOCK_CFG_ECC_DISABLE |
+ SPI_FSI_CLOCK_CFG_MODE |
+ SPI_FSI_CLOCK_CFG_SCK_RECV_DEL |
+ SPI_FSI_CLOCK_CFG_SCK_DIV)) != wanted_clock_cfg)
+ rc = fsi_spi_write_reg(ctx, SPI_FSI_CLOCK_CFG,
+ wanted_clock_cfg);
+
+ return rc;
+}
+
+static int fsi_spi_transfer_one_message(struct spi_controller *ctlr,
+ struct spi_message *mesg)
+{
+ int rc = 0;
+ u8 seq_slave = SPI_FSI_SEQUENCE_SEL_SLAVE(mesg->spi->chip_select + 1);
+ struct spi_transfer *transfer;
+ struct fsi_spi *ctx = spi_controller_get_devdata(ctlr);
+
+ list_for_each_entry(transfer, &mesg->transfers, transfer_list) {
+ struct fsi_spi_sequence seq;
+ struct spi_transfer *next = NULL;
+
+ /* Sequencer must do shift out (tx) first. */
+ if (!transfer->tx_buf ||
+ transfer->len > SPI_FSI_MAX_TRANSFER_SIZE) {
+ rc = -EINVAL;
+ goto error;
+ }
+
+ dev_dbg(ctx->dev, "Start tx of %d bytes.\n", transfer->len);
+
+ rc = fsi_spi_transfer_init(ctx);
+ if (rc < 0)
+ goto error;
+
+ fsi_spi_sequence_init(&seq);
+ fsi_spi_sequence_add(&seq, seq_slave);
+
+ rc = fsi_spi_sequence_transfer(ctx, &seq, transfer);
+ if (rc)
+ goto error;
+
+ if (!list_is_last(&transfer->transfer_list,
+ &mesg->transfers)) {
+ next = list_next_entry(transfer, transfer_list);
+
+ /* Sequencer can only do shift in (rx) after tx. */
+ if (next->rx_buf) {
+ if (next->len > SPI_FSI_MAX_TRANSFER_SIZE) {
+ rc = -EINVAL;
+ goto error;
+ }
+
+ dev_dbg(ctx->dev, "Sequence rx of %d bytes.\n",
+ next->len);
+
+ rc = fsi_spi_sequence_transfer(ctx, &seq,
+ next);
+ if (rc)
+ goto error;
+ } else {
+ next = NULL;
+ }
+ }
+
+ fsi_spi_sequence_add(&seq, SPI_FSI_SEQUENCE_SEL_SLAVE(0));
+
+ rc = fsi_spi_write_reg(ctx, SPI_FSI_SEQUENCE, seq.data);
+ if (rc)
+ goto error;
+
+ rc = fsi_spi_transfer_data(ctx, transfer);
+ if (rc)
+ goto error;
+
+ if (next) {
+ rc = fsi_spi_transfer_data(ctx, next);
+ if (rc)
+ goto error;
+
+ transfer = next;
+ }
+ }
+
+error:
+ mesg->status = rc;
+ spi_finalize_current_message(ctlr);
+
+ return rc;
+}
+
+static size_t fsi_spi_max_transfer_size(struct spi_device *spi)
+{
+ return SPI_FSI_MAX_TRANSFER_SIZE;
+}
+
+static int fsi_spi_probe(struct device *dev)
+{
+ int rc;
+ u32 root_ctrl_8;
+ struct device_node *np;
+ int num_controllers_registered = 0;
+ struct fsi_device *fsi = to_fsi_dev(dev);
+
+ /*
+ * Check the SPI mux before attempting to probe. If the mux isn't set
+ * then the SPI controllers can't access their slave devices.
+ */
+ rc = fsi_slave_read(fsi->slave, FSI_MBOX_ROOT_CTRL_8, &root_ctrl_8,
+ sizeof(root_ctrl_8));
+ if (rc)
+ return rc;
+
+ if (!root_ctrl_8) {
+ dev_dbg(dev, "SPI mux not set, aborting probe.\n");
+ return -ENODEV;
+ }
+
+ for_each_available_child_of_node(dev->of_node, np) {
+ u32 base;
+ struct fsi_spi *ctx;
+ struct spi_controller *ctlr;
+
+ if (of_property_read_u32(np, "reg", &base))
+ continue;
+
+ ctlr = spi_alloc_master(dev, sizeof(*ctx));
+ if (!ctlr)
+ break;
+
+ ctlr->dev.of_node = np;
+ ctlr->num_chipselect = of_get_available_child_count(np) ?: 1;
+ ctlr->flags = SPI_CONTROLLER_HALF_DUPLEX;
+ ctlr->max_transfer_size = fsi_spi_max_transfer_size;
+ ctlr->transfer_one_message = fsi_spi_transfer_one_message;
+
+ ctx = spi_controller_get_devdata(ctlr);
+ ctx->dev = &ctlr->dev;
+ ctx->fsi = fsi;
+ ctx->base = base + SPI_FSI_BASE;
+
+ rc = devm_spi_register_controller(dev, ctlr);
+ if (rc)
+ spi_controller_put(ctlr);
+ else
+ num_controllers_registered++;
+ }
+
+ if (!num_controllers_registered)
+ return -ENODEV;
+
+ return 0;
+}
+
+static const struct fsi_device_id fsi_spi_ids[] = {
+ { FSI_ENGID_SPI, FSI_VERSION_ANY },
+ { }
+};
+MODULE_DEVICE_TABLE(fsi, fsi_spi_ids);
+
+static struct fsi_driver fsi_spi_driver = {
+ .id_table = fsi_spi_ids,
+ .drv = {
+ .name = "spi-fsi",
+ .bus = &fsi_bus_type,
+ .probe = fsi_spi_probe,
+ },
+};
+module_fsi_driver(fsi_spi_driver);
+
+MODULE_AUTHOR("Eddie James <eajames@linux.ibm.com>");
+MODULE_DESCRIPTION("FSI attached SPI controller");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index f75ff1a75dc4..5c1eb96a5c57 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -840,9 +840,9 @@ static int set_config(struct usb_composite_dev *cdev,
result = 0;
}
- INFO(cdev, "%s config #%d: %s\n",
- usb_speed_string(gadget->speed),
- number, c ? c->label : "unconfigured");
+ DBG(cdev, "%s config #%d: %s\n",
+ usb_speed_string(gadget->speed),
+ number, c ? c->label : "unconfigured");
if (!c)
goto done;
diff --git a/drivers/usb/gadget/udc/aspeed-vhub/Kconfig b/drivers/usb/gadget/udc/aspeed-vhub/Kconfig
index 83ba8a2eb6af..605500b19cf3 100644
--- a/drivers/usb/gadget/udc/aspeed-vhub/Kconfig
+++ b/drivers/usb/gadget/udc/aspeed-vhub/Kconfig
@@ -4,5 +4,5 @@ config USB_ASPEED_VHUB
depends on ARCH_ASPEED || COMPILE_TEST
depends on USB_LIBCOMPOSITE
help
- USB peripheral controller for the Aspeed AST2500 family
- SoCs supporting the "vHub" functionality and USB2.0
+ USB peripheral controller for the Aspeed AST2400, AST2500 and
+ AST2600 family SoCs supporting the "vHub" functionality and USB2.0
diff --git a/drivers/usb/gadget/udc/aspeed-vhub/core.c b/drivers/usb/gadget/udc/aspeed-vhub/core.c
index 90b134d5dca9..c827bf420278 100644
--- a/drivers/usb/gadget/udc/aspeed-vhub/core.c
+++ b/drivers/usb/gadget/udc/aspeed-vhub/core.c
@@ -32,6 +32,38 @@
#include "vhub.h"
+struct ast_vhub_config {
+ u32 max_ports; /* max number of downstream ports */
+ u32 max_epns; /* max number of generic endpoints */
+};
+
+static const struct ast_vhub_config ast2400_config = {
+ .max_ports = 5,
+ .max_epns = 15,
+};
+
+static const struct ast_vhub_config ast2600_config = {
+ .max_ports = 7,
+ .max_epns = 21,
+};
+
+static const struct of_device_id ast_vhub_dt_ids[] = {
+ {
+ .compatible = "aspeed,ast2400-usb-vhub",
+ .data = &ast2400_config,
+ },
+ {
+ .compatible = "aspeed,ast2500-usb-vhub",
+ .data = &ast2400_config,
+ },
+ {
+ .compatible = "aspeed,ast2600-usb-vhub",
+ .data = &ast2600_config,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ast_vhub_dt_ids);
+
void ast_vhub_done(struct ast_vhub_ep *ep, struct ast_vhub_req *req,
int status)
{
@@ -99,7 +131,7 @@ static irqreturn_t ast_vhub_irq(int irq, void *data)
{
struct ast_vhub *vhub = data;
irqreturn_t iret = IRQ_NONE;
- u32 istat;
+ u32 i, istat;
/* Stale interrupt while tearing down */
if (!vhub->ep0_bufs)
@@ -121,10 +153,10 @@ static irqreturn_t ast_vhub_irq(int irq, void *data)
/* Handle generic EPs first */
if (istat & VHUB_IRQ_EP_POOL_ACK_STALL) {
- u32 i, ep_acks = readl(vhub->regs + AST_VHUB_EP_ACK_ISR);
+ u32 ep_acks = readl(vhub->regs + AST_VHUB_EP_ACK_ISR);
writel(ep_acks, vhub->regs + AST_VHUB_EP_ACK_ISR);
- for (i = 0; ep_acks && i < AST_VHUB_NUM_GEN_EPs; i++) {
+ for (i = 0; ep_acks && i < vhub->max_epns; i++) {
u32 mask = VHUB_EP_IRQ(i);
if (ep_acks & mask) {
ast_vhub_epn_ack_irq(&vhub->epns[i]);
@@ -134,21 +166,11 @@ static irqreturn_t ast_vhub_irq(int irq, void *data)
}
/* Handle device interrupts */
- if (istat & (VHUB_IRQ_DEVICE1 |
- VHUB_IRQ_DEVICE2 |
- VHUB_IRQ_DEVICE3 |
- VHUB_IRQ_DEVICE4 |
- VHUB_IRQ_DEVICE5)) {
- if (istat & VHUB_IRQ_DEVICE1)
- ast_vhub_dev_irq(&vhub->ports[0].dev);
- if (istat & VHUB_IRQ_DEVICE2)
- ast_vhub_dev_irq(&vhub->ports[1].dev);
- if (istat & VHUB_IRQ_DEVICE3)
- ast_vhub_dev_irq(&vhub->ports[2].dev);
- if (istat & VHUB_IRQ_DEVICE4)
- ast_vhub_dev_irq(&vhub->ports[3].dev);
- if (istat & VHUB_IRQ_DEVICE5)
- ast_vhub_dev_irq(&vhub->ports[4].dev);
+ for (i = 0; i < vhub->max_ports; i++) {
+ u32 dev_mask = VHUB_IRQ_DEVICE1 << i;
+
+ if (istat & dev_mask)
+ ast_vhub_dev_irq(&vhub->ports[i].dev);
}
/* Handle top-level vHub EP0 interrupts */
@@ -182,7 +204,7 @@ static irqreturn_t ast_vhub_irq(int irq, void *data)
void ast_vhub_init_hw(struct ast_vhub *vhub)
{
- u32 ctrl;
+ u32 ctrl, port_mask, epn_mask;
UDCDBG(vhub,"(Re)Starting HW ...\n");
@@ -222,15 +244,20 @@ void ast_vhub_init_hw(struct ast_vhub *vhub)
}
/* Reset all devices */
- writel(VHUB_SW_RESET_ALL, vhub->regs + AST_VHUB_SW_RESET);
+ port_mask = GENMASK(vhub->max_ports, 1);
+ writel(VHUB_SW_RESET_ROOT_HUB |
+ VHUB_SW_RESET_DMA_CONTROLLER |
+ VHUB_SW_RESET_EP_POOL |
+ port_mask, vhub->regs + AST_VHUB_SW_RESET);
udelay(1);
writel(0, vhub->regs + AST_VHUB_SW_RESET);
/* Disable and cleanup EP ACK/NACK interrupts */
+ epn_mask = GENMASK(vhub->max_epns - 1, 0);
writel(0, vhub->regs + AST_VHUB_EP_ACK_IER);
writel(0, vhub->regs + AST_VHUB_EP_NACK_IER);
- writel(VHUB_EP_IRQ_ALL, vhub->regs + AST_VHUB_EP_ACK_ISR);
- writel(VHUB_EP_IRQ_ALL, vhub->regs + AST_VHUB_EP_NACK_ISR);
+ writel(epn_mask, vhub->regs + AST_VHUB_EP_ACK_ISR);
+ writel(epn_mask, vhub->regs + AST_VHUB_EP_NACK_ISR);
/* Default settings for EP0, enable HW hub EP1 */
writel(0, vhub->regs + AST_VHUB_EP0_CTRL);
@@ -273,7 +300,7 @@ static int ast_vhub_remove(struct platform_device *pdev)
return 0;
/* Remove devices */
- for (i = 0; i < AST_VHUB_NUM_PORTS; i++)
+ for (i = 0; i < vhub->max_ports; i++)
ast_vhub_del_dev(&vhub->ports[i].dev);
spin_lock_irqsave(&vhub->lock, flags);
@@ -295,7 +322,7 @@ static int ast_vhub_remove(struct platform_device *pdev)
if (vhub->ep0_bufs)
dma_free_coherent(&pdev->dev,
AST_VHUB_EP0_MAX_PACKET *
- (AST_VHUB_NUM_PORTS + 1),
+ (vhub->max_ports + 1),
vhub->ep0_bufs,
vhub->ep0_bufs_dma);
vhub->ep0_bufs = NULL;
@@ -309,11 +336,30 @@ static int ast_vhub_probe(struct platform_device *pdev)
struct ast_vhub *vhub;
struct resource *res;
int i, rc = 0;
+ const struct of_device_id *ofdid;
+ const struct ast_vhub_config *config;
vhub = devm_kzalloc(&pdev->dev, sizeof(*vhub), GFP_KERNEL);
if (!vhub)
return -ENOMEM;
+ ofdid = of_match_node(ast_vhub_dt_ids, pdev->dev.of_node);
+ if (!ofdid)
+ return -EINVAL;
+ config = ofdid->data;
+
+ vhub->max_ports = config->max_ports;
+ vhub->ports = devm_kcalloc(&pdev->dev, vhub->max_ports,
+ sizeof(*vhub->ports), GFP_KERNEL);
+ if (!vhub->ports)
+ return -ENOMEM;
+
+ vhub->max_epns = config->max_epns;
+ vhub->epns = devm_kcalloc(&pdev->dev, vhub->max_epns,
+ sizeof(*vhub->epns), GFP_KERNEL);
+ if (!vhub->epns)
+ return -ENOMEM;
+
spin_lock_init(&vhub->lock);
vhub->pdev = pdev;
@@ -366,7 +412,7 @@ static int ast_vhub_probe(struct platform_device *pdev)
*/
vhub->ep0_bufs = dma_alloc_coherent(&pdev->dev,
AST_VHUB_EP0_MAX_PACKET *
- (AST_VHUB_NUM_PORTS + 1),
+ (vhub->max_ports + 1),
&vhub->ep0_bufs_dma, GFP_KERNEL);
if (!vhub->ep0_bufs) {
dev_err(&pdev->dev, "Failed to allocate EP0 DMA buffers\n");
@@ -380,7 +426,7 @@ static int ast_vhub_probe(struct platform_device *pdev)
ast_vhub_init_ep0(vhub, &vhub->ep0, NULL);
/* Init devices */
- for (i = 0; i < AST_VHUB_NUM_PORTS && rc == 0; i++)
+ for (i = 0; i < vhub->max_ports && rc == 0; i++)
rc = ast_vhub_init_dev(vhub, i);
if (rc)
goto err;
@@ -400,17 +446,6 @@ static int ast_vhub_probe(struct platform_device *pdev)
return rc;
}
-static const struct of_device_id ast_vhub_dt_ids[] = {
- {
- .compatible = "aspeed,ast2400-usb-vhub",
- },
- {
- .compatible = "aspeed,ast2500-usb-vhub",
- },
- { }
-};
-MODULE_DEVICE_TABLE(of, ast_vhub_dt_ids);
-
static struct platform_driver ast_vhub_driver = {
.probe = ast_vhub_probe,
.remove = ast_vhub_remove,
diff --git a/drivers/usb/gadget/udc/aspeed-vhub/dev.c b/drivers/usb/gadget/udc/aspeed-vhub/dev.c
index 4008e7a51188..d268306a7bfe 100644
--- a/drivers/usb/gadget/udc/aspeed-vhub/dev.c
+++ b/drivers/usb/gadget/udc/aspeed-vhub/dev.c
@@ -77,7 +77,7 @@ static void ast_vhub_dev_enable(struct ast_vhub_dev *d)
writel(d->ep0.buf_dma, d->regs + AST_VHUB_DEV_EP0_DATA);
/* Clear stall on all EPs */
- for (i = 0; i < AST_VHUB_NUM_GEN_EPs; i++) {
+ for (i = 0; i < d->max_epns; i++) {
struct ast_vhub_ep *ep = d->epns[i];
if (ep && (ep->epn.stalled || ep->epn.wedged)) {
@@ -137,7 +137,7 @@ static int ast_vhub_ep_feature(struct ast_vhub_dev *d,
is_set ? "SET" : "CLEAR", ep_num, wValue);
if (ep_num == 0)
return std_req_complete;
- if (ep_num >= AST_VHUB_NUM_GEN_EPs || !d->epns[ep_num - 1])
+ if (ep_num >= d->max_epns || !d->epns[ep_num - 1])
return std_req_stall;
if (wValue != USB_ENDPOINT_HALT)
return std_req_driver;
@@ -181,7 +181,7 @@ static int ast_vhub_ep_status(struct ast_vhub_dev *d,
DDBG(d, "GET_STATUS(ep%d)\n", ep_num);
- if (ep_num >= AST_VHUB_NUM_GEN_EPs)
+ if (ep_num >= d->max_epns)
return std_req_stall;
if (ep_num != 0) {
ep = d->epns[ep_num - 1];
@@ -299,7 +299,7 @@ static void ast_vhub_dev_nuke(struct ast_vhub_dev *d)
{
unsigned int i;
- for (i = 0; i < AST_VHUB_NUM_GEN_EPs; i++) {
+ for (i = 0; i < d->max_epns; i++) {
if (!d->epns[i])
continue;
ast_vhub_nuke(d->epns[i], -ESHUTDOWN);
@@ -416,10 +416,10 @@ static struct usb_ep *ast_vhub_udc_match_ep(struct usb_gadget *gadget,
* that will allow the generic code to use our
* assigned address.
*/
- for (i = 0; i < AST_VHUB_NUM_GEN_EPs; i++)
+ for (i = 0; i < d->max_epns; i++)
if (d->epns[i] == NULL)
break;
- if (i >= AST_VHUB_NUM_GEN_EPs)
+ if (i >= d->max_epns)
return NULL;
addr = i + 1;
@@ -526,6 +526,7 @@ void ast_vhub_del_dev(struct ast_vhub_dev *d)
usb_del_gadget_udc(&d->gadget);
device_unregister(d->port_dev);
+ kfree(d->epns);
}
static void ast_vhub_dev_release(struct device *dev)
@@ -547,13 +548,24 @@ int ast_vhub_init_dev(struct ast_vhub *vhub, unsigned int idx)
ast_vhub_init_ep0(vhub, &d->ep0, d);
/*
+ * A USB device can have up to 30 endpoints besides control
+ * endpoint 0.
+ */
+ d->max_epns = min_t(u32, vhub->max_epns, 30);
+ d->epns = kcalloc(d->max_epns, sizeof(*d->epns), GFP_KERNEL);
+ if (!d->epns)
+ return -ENOMEM;
+
+ /*
* The UDC core really needs us to have separate and uniquely
* named "parent" devices for each port so we create a sub device
* here for that purpose
*/
d->port_dev = kzalloc(sizeof(struct device), GFP_KERNEL);
- if (!d->port_dev)
- return -ENOMEM;
+ if (!d->port_dev) {
+ rc = -ENOMEM;
+ goto fail_alloc;
+ }
device_initialize(d->port_dev);
d->port_dev->release = ast_vhub_dev_release;
d->port_dev->parent = parent;
@@ -584,6 +596,8 @@ int ast_vhub_init_dev(struct ast_vhub *vhub, unsigned int idx)
device_del(d->port_dev);
fail_add:
put_device(d->port_dev);
+ fail_alloc:
+ kfree(d->epns);
return rc;
}
diff --git a/drivers/usb/gadget/udc/aspeed-vhub/epn.c b/drivers/usb/gadget/udc/aspeed-vhub/epn.c
index 7475c74aa5c5..0bd6b20435b8 100644
--- a/drivers/usb/gadget/udc/aspeed-vhub/epn.c
+++ b/drivers/usb/gadget/udc/aspeed-vhub/epn.c
@@ -800,10 +800,10 @@ struct ast_vhub_ep *ast_vhub_alloc_epn(struct ast_vhub_dev *d, u8 addr)
/* Find a free one (no device) */
spin_lock_irqsave(&vhub->lock, flags);
- for (i = 0; i < AST_VHUB_NUM_GEN_EPs; i++)
+ for (i = 0; i < vhub->max_epns; i++)
if (vhub->epns[i].dev == NULL)
break;
- if (i >= AST_VHUB_NUM_GEN_EPs) {
+ if (i >= vhub->max_epns) {
spin_unlock_irqrestore(&vhub->lock, flags);
return NULL;
}
diff --git a/drivers/usb/gadget/udc/aspeed-vhub/hub.c b/drivers/usb/gadget/udc/aspeed-vhub/hub.c
index 19b3517e04c0..9c7e57fbd8ef 100644
--- a/drivers/usb/gadget/udc/aspeed-vhub/hub.c
+++ b/drivers/usb/gadget/udc/aspeed-vhub/hub.c
@@ -133,10 +133,13 @@ static const struct ast_vhub_full_cdesc {
#define AST_VHUB_HUB_DESC_SIZE (USB_DT_HUB_NONVAR_SIZE + 2)
-static const struct usb_hub_descriptor ast_vhub_hub_desc = {
+/*
+ * "bNbrPorts" field is updated in "ast_vhub_init_hub" function based on
+ * "max_ports" of the vhub.
+ */
+static struct usb_hub_descriptor ast_vhub_hub_desc = {
.bDescLength = AST_VHUB_HUB_DESC_SIZE,
.bDescriptorType = USB_DT_HUB,
- .bNbrPorts = AST_VHUB_NUM_PORTS,
.wHubCharacteristics = cpu_to_le16(HUB_CHAR_NO_LPSM),
.bPwrOn2PwrGood = 10,
.bHubContrCurrent = 0,
@@ -504,7 +507,7 @@ static void ast_vhub_wake_work(struct work_struct *work)
* we let the normal host wake path deal with it later.
*/
spin_lock_irqsave(&vhub->lock, flags);
- for (i = 0; i < AST_VHUB_NUM_PORTS; i++) {
+ for (i = 0; i < vhub->max_ports; i++) {
struct ast_vhub_port *p = &vhub->ports[i];
if (!(p->status & USB_PORT_STAT_SUSPEND))
@@ -587,7 +590,7 @@ static enum std_req_rc ast_vhub_set_port_feature(struct ast_vhub_ep *ep,
struct ast_vhub *vhub = ep->vhub;
struct ast_vhub_port *p;
- if (port == 0 || port > AST_VHUB_NUM_PORTS)
+ if (port == 0 || port > vhub->max_ports)
return std_req_stall;
port--;
p = &vhub->ports[port];
@@ -630,7 +633,7 @@ static enum std_req_rc ast_vhub_clr_port_feature(struct ast_vhub_ep *ep,
struct ast_vhub *vhub = ep->vhub;
struct ast_vhub_port *p;
- if (port == 0 || port > AST_VHUB_NUM_PORTS)
+ if (port == 0 || port > vhub->max_ports)
return std_req_stall;
port--;
p = &vhub->ports[port];
@@ -676,7 +679,7 @@ static enum std_req_rc ast_vhub_get_port_stat(struct ast_vhub_ep *ep,
struct ast_vhub *vhub = ep->vhub;
u16 stat, chg;
- if (port == 0 || port > AST_VHUB_NUM_PORTS)
+ if (port == 0 || port > vhub->max_ports)
return std_req_stall;
port--;
@@ -757,7 +760,7 @@ void ast_vhub_hub_suspend(struct ast_vhub *vhub)
* Forward to unsuspended ports without changing
* their connection status.
*/
- for (i = 0; i < AST_VHUB_NUM_PORTS; i++) {
+ for (i = 0; i < vhub->max_ports; i++) {
struct ast_vhub_port *p = &vhub->ports[i];
if (!(p->status & USB_PORT_STAT_SUSPEND))
@@ -780,7 +783,7 @@ void ast_vhub_hub_resume(struct ast_vhub *vhub)
* Forward to unsuspended ports without changing
* their connection status.
*/
- for (i = 0; i < AST_VHUB_NUM_PORTS; i++) {
+ for (i = 0; i < vhub->max_ports; i++) {
struct ast_vhub_port *p = &vhub->ports[i];
if (!(p->status & USB_PORT_STAT_SUSPEND))
@@ -814,7 +817,7 @@ void ast_vhub_hub_reset(struct ast_vhub *vhub)
* Clear all port status, disable gadgets and "suspend"
* them. They will be woken up by a port reset.
*/
- for (i = 0; i < AST_VHUB_NUM_PORTS; i++) {
+ for (i = 0; i < vhub->max_ports; i++) {
struct ast_vhub_port *p = &vhub->ports[i];
/* Only keep the connected flag */
@@ -838,5 +841,10 @@ void ast_vhub_init_hub(struct ast_vhub *vhub)
{
vhub->speed = USB_SPEED_UNKNOWN;
INIT_WORK(&vhub->wake_work, ast_vhub_wake_work);
+
+ /*
+ * Fixup number of ports in hub descriptor.
+ */
+ ast_vhub_hub_desc.bNbrPorts = vhub->max_ports;
}
diff --git a/drivers/usb/gadget/udc/aspeed-vhub/vhub.h b/drivers/usb/gadget/udc/aspeed-vhub/vhub.h
index 761919e220d3..e46980fe66f2 100644
--- a/drivers/usb/gadget/udc/aspeed-vhub/vhub.h
+++ b/drivers/usb/gadget/udc/aspeed-vhub/vhub.h
@@ -76,17 +76,9 @@
#define VHUB_SW_RESET_DEVICE2 (1 << 2)
#define VHUB_SW_RESET_DEVICE1 (1 << 1)
#define VHUB_SW_RESET_ROOT_HUB (1 << 0)
-#define VHUB_SW_RESET_ALL (VHUB_SW_RESET_EP_POOL | \
- VHUB_SW_RESET_DMA_CONTROLLER | \
- VHUB_SW_RESET_DEVICE5 | \
- VHUB_SW_RESET_DEVICE4 | \
- VHUB_SW_RESET_DEVICE3 | \
- VHUB_SW_RESET_DEVICE2 | \
- VHUB_SW_RESET_DEVICE1 | \
- VHUB_SW_RESET_ROOT_HUB)
+
/* EP ACK/NACK IRQ masks */
#define VHUB_EP_IRQ(n) (1 << (n))
-#define VHUB_EP_IRQ_ALL 0x7fff /* 15 EPs */
/* USB status reg */
#define VHUB_USBSTS_HISPEED (1 << 27)
@@ -210,8 +202,6 @@
* *
****************************************/
-#define AST_VHUB_NUM_GEN_EPs 15 /* Generic non-0 EPs */
-#define AST_VHUB_NUM_PORTS 5 /* vHub ports */
#define AST_VHUB_EP0_MAX_PACKET 64 /* EP0's max packet size */
#define AST_VHUB_EPn_MAX_PACKET 1024 /* Generic EPs max packet size */
#define AST_VHUB_DESCS_COUNT 256 /* Use 256 descriptor mode (valid
@@ -342,7 +332,7 @@ struct ast_vhub_dev {
struct ast_vhub *vhub;
void __iomem *regs;
- /* Device index (0...4) and name string */
+ /* Device index (zero-based) and name string */
unsigned int index;
const char *name;
@@ -358,7 +348,8 @@ struct ast_vhub_dev {
/* Endpoint structures */
struct ast_vhub_ep ep0;
- struct ast_vhub_ep *epns[AST_VHUB_NUM_GEN_EPs];
+ struct ast_vhub_ep **epns;
+ u32 max_epns;
};
#define to_ast_dev(__g) container_of(__g, struct ast_vhub_dev, gadget)
@@ -393,10 +384,12 @@ struct ast_vhub {
bool ep1_stalled : 1;
/* Per-port info */
- struct ast_vhub_port ports[AST_VHUB_NUM_PORTS];
+ struct ast_vhub_port *ports;
+ u32 max_ports;
/* Generic EP data structures */
- struct ast_vhub_ep epns[AST_VHUB_NUM_GEN_EPs];
+ struct ast_vhub_ep *epns;
+ u32 max_epns;
/* Upstream bus is suspended ? */
bool suspended : 1;
diff --git a/include/dt-bindings/clock/aspeed-clock.h b/include/dt-bindings/clock/aspeed-clock.h
index f43738607d77..9ff4f6e4558c 100644
--- a/include/dt-bindings/clock/aspeed-clock.h
+++ b/include/dt-bindings/clock/aspeed-clock.h
@@ -39,6 +39,8 @@
#define ASPEED_CLK_BCLK 33
#define ASPEED_CLK_MPLL 34
#define ASPEED_CLK_24M 35
+#define ASPEED_CLK_MAC1RCLK 36
+#define ASPEED_CLK_MAC2RCLK 37
#define ASPEED_RESET_XDMA 0
#define ASPEED_RESET_MCTP 1
diff --git a/include/dt-bindings/clock/ast2600-clock.h b/include/dt-bindings/clock/ast2600-clock.h
index 38074a5f7296..62b9520a00fd 100644
--- a/include/dt-bindings/clock/ast2600-clock.h
+++ b/include/dt-bindings/clock/ast2600-clock.h
@@ -83,6 +83,10 @@
#define ASPEED_CLK_MAC12 64
#define ASPEED_CLK_MAC34 65
#define ASPEED_CLK_USBPHY_40M 66
+#define ASPEED_CLK_MAC1RCLK 67
+#define ASPEED_CLK_MAC2RCLK 68
+#define ASPEED_CLK_MAC3RCLK 69
+#define ASPEED_CLK_MAC4RCLK 70
/* Only list resets here that are not part of a gate */
#define ASPEED_RESET_ADC 55
diff --git a/include/dt-bindings/interrupt-controller/aspeed-scu-ic.h b/include/dt-bindings/interrupt-controller/aspeed-scu-ic.h
new file mode 100644
index 000000000000..f315d5a7f5ee
--- /dev/null
+++ b/include/dt-bindings/interrupt-controller/aspeed-scu-ic.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#ifndef _DT_BINDINGS_INTERRUPT_CONTROLLER_ASPEED_SCU_IC_H_
+#define _DT_BINDINGS_INTERRUPT_CONTROLLER_ASPEED_SCU_IC_H_
+
+#define ASPEED_SCU_IC_VGA_CURSOR_CHANGE 0
+#define ASPEED_SCU_IC_VGA_SCRATCH_REG_CHANGE 1
+
+#define ASPEED_AST2500_SCU_IC_PCIE_RESET_LO_TO_HI 2
+#define ASPEED_AST2500_SCU_IC_PCIE_RESET_HI_TO_LO 3
+#define ASPEED_AST2500_SCU_IC_LPC_RESET_LO_TO_HI 4
+#define ASPEED_AST2500_SCU_IC_LPC_RESET_HI_TO_LO 5
+#define ASPEED_AST2500_SCU_IC_ISSUE_MSI 6
+
+#define ASPEED_AST2600_SCU_IC0_PCIE_PERST_LO_TO_HI 2
+#define ASPEED_AST2600_SCU_IC0_PCIE_PERST_HI_TO_LO 3
+#define ASPEED_AST2600_SCU_IC0_PCIE_RCRST_LO_TO_HI 4
+#define ASPEED_AST2600_SCU_IC0_PCIE_RCRST_HI_TO_LO 5
+
+#define ASPEED_AST2600_SCU_IC1_LPC_RESET_LO_TO_HI 0
+#define ASPEED_AST2600_SCU_IC1_LPC_RESET_HI_TO_LO 1
+
+#endif /* _DT_BINDINGS_INTERRUPT_CONTROLLER_ASPEED_SCU_IC_H_ */
diff --git a/include/keys/trusted.h b/include/keys/trusted.h
index 0071298b9b28..841ae111c976 100644
--- a/include/keys/trusted.h
+++ b/include/keys/trusted.h
@@ -17,7 +17,7 @@
#define LOAD32N(buffer, offset) (*(uint32_t *)&buffer[offset])
#define LOAD16(buffer, offset) (ntohs(*(uint16_t *)&buffer[offset]))
-struct tpm_buf {
+struct tpm1_buf {
int len;
unsigned char data[MAX_BUF_SIZE];
};
@@ -46,7 +46,7 @@ int TSS_checkhmac1(unsigned char *buffer,
unsigned int keylen, ...);
int trusted_tpm_send(unsigned char *cmd, size_t buflen);
-int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce);
+int oiap(struct tpm1_buf *tb, uint32_t *handle, unsigned char *nonce);
#define TPM_DEBUG 0
@@ -110,24 +110,24 @@ static inline void dump_tpm_buf(unsigned char *buf)
}
#endif
-static inline void store8(struct tpm_buf *buf, const unsigned char value)
+static inline void store8(struct tpm1_buf *buf, const unsigned char value)
{
buf->data[buf->len++] = value;
}
-static inline void store16(struct tpm_buf *buf, const uint16_t value)
+static inline void store16(struct tpm1_buf *buf, const uint16_t value)
{
*(uint16_t *) & buf->data[buf->len] = htons(value);
buf->len += sizeof value;
}
-static inline void store32(struct tpm_buf *buf, const uint32_t value)
+static inline void store32(struct tpm1_buf *buf, const uint32_t value)
{
*(uint32_t *) & buf->data[buf->len] = htonl(value);
buf->len += sizeof value;
}
-static inline void storebytes(struct tpm_buf *buf, const unsigned char *in,
+static inline void storebytes(struct tpm1_buf *buf, const unsigned char *in,
const int len)
{
memcpy(buf->data + buf->len, in, len);
diff --git a/include/linux/mfd/intel-peci-client.h b/include/linux/mfd/intel-peci-client.h
new file mode 100644
index 000000000000..7668d0cfa843
--- /dev/null
+++ b/include/linux/mfd/intel-peci-client.h
@@ -0,0 +1,119 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2018-2019 Intel Corporation */
+
+#ifndef __LINUX_MFD_INTEL_PECI_CLIENT_H
+#define __LINUX_MFD_INTEL_PECI_CLIENT_H
+
+#include <linux/peci.h>
+
+#if IS_ENABLED(CONFIG_X86)
+#include <asm/intel-family.h>
+#else
+/*
+ * Architectures other than x86 cannot include the header file so define these
+ * at here. These are needed for detecting type of client x86 CPUs behind a PECI
+ * connection.
+ */
+#define INTEL_FAM6_HASWELL_X 0x3F
+#define INTEL_FAM6_BROADWELL_X 0x4F
+#define INTEL_FAM6_SKYLAKE_X 0x55
+#define INTEL_FAM6_SKYLAKE_XD 0x56
+#endif
+
+#define INTEL_FAM6 6 /* P6 (Pentium Pro and later) */
+
+#define CORE_MAX_ON_HSX 18 /* Max number of cores on Haswell */
+#define CHAN_RANK_MAX_ON_HSX 8 /* Max number of channel ranks on Haswell */
+#define DIMM_IDX_MAX_ON_HSX 3 /* Max DIMM index per channel on Haswell */
+
+#define CORE_MAX_ON_BDX 24 /* Max number of cores on Broadwell */
+#define CHAN_RANK_MAX_ON_BDX 4 /* Max number of channel ranks on Broadwell */
+#define DIMM_IDX_MAX_ON_BDX 3 /* Max DIMM index per channel on Broadwell */
+
+#define CORE_MAX_ON_SKX 28 /* Max number of cores on Skylake */
+#define CHAN_RANK_MAX_ON_SKX 6 /* Max number of channel ranks on Skylake */
+#define DIMM_IDX_MAX_ON_SKX 2 /* Max DIMM index per channel on Skylake */
+
+#define CORE_MAX_ON_SKXD 16 /* Max number of cores on Skylake D */
+#define CHAN_RANK_MAX_ON_SKXD 2 /* Max number of channel ranks on Skylake D */
+#define DIMM_IDX_MAX_ON_SKXD 2 /* Max DIMM index per channel on Skylake D */
+
+#define CORE_NUMS_MAX CORE_MAX_ON_SKX
+#define CHAN_RANK_MAX CHAN_RANK_MAX_ON_HSX
+#define DIMM_IDX_MAX DIMM_IDX_MAX_ON_HSX
+#define DIMM_NUMS_MAX (CHAN_RANK_MAX * DIMM_IDX_MAX)
+
+/**
+ * struct cpu_gen_info - CPU generation specific information
+ * @family: CPU family ID
+ * @model: CPU model
+ * @core_max: max number of cores
+ * @chan_rank_max: max number of channel ranks
+ * @dimm_idx_max: max number of DIMM indices
+ *
+ * CPU generation specific information to identify maximum number of cores and
+ * DIMM slots.
+ */
+struct cpu_gen_info {
+ u16 family;
+ u8 model;
+ uint core_max;
+ uint chan_rank_max;
+ uint dimm_idx_max;
+};
+
+/**
+ * struct peci_client_manager - PECI client manager information
+ * @client; pointer to the PECI client
+ * @name: PECI client manager name
+ * @gen_info: CPU generation info of the detected CPU
+ *
+ * PECI client manager information for managing PECI sideband functions on a CPU
+ * client.
+ */
+struct peci_client_manager {
+ struct peci_client *client;
+ char name[PECI_NAME_SIZE];
+ const struct cpu_gen_info *gen_info;
+};
+
+/**
+ * peci_client_read_package_config - read from the Package Configuration Space
+ * @priv: driver private data structure
+ * @index: encoding index for the requested service
+ * @param: parameter to specify the exact data being requested
+ * @data: data buffer to store the result
+ * Context: can sleep
+ *
+ * A generic PECI command that provides read access to the
+ * "Package Configuration Space" that is maintained by the PCU, including
+ * various power and thermal management functions. Typical PCS read services
+ * supported by the processor may include access to temperature data, energy
+ * status, run time information, DIMM temperatures and so on.
+ *
+ * Return: zero on success, else a negative error code.
+ */
+static inline int
+peci_client_read_package_config(struct peci_client_manager *priv,
+ u8 index, u16 param, u8 *data)
+{
+ struct peci_rd_pkg_cfg_msg msg;
+ int ret;
+
+ msg.addr = priv->client->addr;
+ msg.index = index;
+ msg.param = param;
+ msg.rx_len = 4;
+
+ ret = peci_command(priv->client->adapter, PECI_CMD_RD_PKG_CFG, &msg);
+ if (msg.cc != PECI_DEV_CC_SUCCESS)
+ ret = -EAGAIN;
+ if (ret)
+ return ret;
+
+ memcpy(data, msg.pkg_config, 4);
+
+ return 0;
+}
+
+#endif /* __LINUX_MFD_INTEL_PECI_CLIENT_H */
diff --git a/include/linux/peci.h b/include/linux/peci.h
new file mode 100644
index 000000000000..4bc4595c797d
--- /dev/null
+++ b/include/linux/peci.h
@@ -0,0 +1,150 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2018-2019 Intel Corporation */
+
+#ifndef __LINUX_PECI_H
+#define __LINUX_PECI_H
+
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/peci-ioctl.h>
+
+#define PECI_NAME_SIZE 32
+
+struct peci_board_info {
+ char type[PECI_NAME_SIZE];
+ u8 addr; /* CPU client address */
+ struct device_node *of_node;
+};
+
+/**
+ * struct peci_adapter - represent a PECI adapter
+ * @owner: owner module of the PECI adpater
+ * @bus_lock: mutex for exclusion of multiple callers
+ * @dev: device interface to this driver
+ * @nr: the bus number to map
+ * @name: name of the adapter
+ * @userspace_clients_lock: mutex for exclusion of clients handling
+ * @userspace_clients: list of registered clients
+ * @xfer: low-level transfer function pointer of the adapter
+ * @cmd_mask: mask for supportable PECI commands
+ * @use_dma: flag for indicating that adapter uses DMA
+ *
+ * Each PECI adapter can communicate with one or more PECI client children.
+ * These make a small bus, sharing a single wired PECI connection.
+ */
+struct peci_adapter {
+ struct module *owner;
+ struct mutex bus_lock; /* mutex for bus locking */
+ struct device dev;
+ int nr;
+ char name[PECI_NAME_SIZE];
+ struct mutex userspace_clients_lock; /* clients list mutex */
+ struct list_head userspace_clients;
+ int (*xfer)(struct peci_adapter *adapter,
+ struct peci_xfer_msg *msg);
+ u32 cmd_mask;
+ bool use_dma;
+};
+
+static inline struct peci_adapter *to_peci_adapter(void *d)
+{
+ return container_of(d, struct peci_adapter, dev);
+}
+
+static inline void *peci_get_adapdata(const struct peci_adapter *adapter)
+{
+ return dev_get_drvdata(&adapter->dev);
+}
+
+static inline void peci_set_adapdata(struct peci_adapter *adapter, void *data)
+{
+ dev_set_drvdata(&adapter->dev, data);
+}
+
+/**
+ * struct peci_client - represent a PECI client device
+ * @dev: driver model device node for the client
+ * @adapter: manages the bus segment hosting this PECI device
+ * @addr: address used on the PECI bus connected to the parent adapter
+ * @name: indicates the type of the device
+ * @detected: detected PECI clients list
+ *
+ * A peci_client identifies a single device (i.e. CPU) connected to a peci bus.
+ * The behaviour exposed to Linux is defined by the driver managing the device.
+ */
+struct peci_client {
+ struct device dev;
+ struct peci_adapter *adapter;
+ u8 addr;
+ char name[PECI_NAME_SIZE];
+ struct list_head detected;
+};
+
+static inline struct peci_client *to_peci_client(void *d)
+{
+ return container_of(d, struct peci_client, dev);
+}
+
+struct peci_device_id {
+ char name[PECI_NAME_SIZE];
+ ulong driver_data; /* Data private to the driver */
+};
+
+/**
+ * struct peci_driver - represent a PECI device driver
+ * @probe: callback for device binding
+ * @remove: callback for device unbinding
+ * @shutdown: callback for device shutdown
+ * @driver: device driver model driver
+ * @id_table: list of PECI devices supported by this driver
+ *
+ * The driver.owner field should be set to the module owner of this driver.
+ * The driver.name field should be set to the name of this driver.
+ */
+struct peci_driver {
+ int (*probe)(struct peci_client *client);
+ int (*remove)(struct peci_client *client);
+ void (*shutdown)(struct peci_client *client);
+ struct device_driver driver;
+ const struct peci_device_id *id_table;
+};
+
+static inline struct peci_driver *to_peci_driver(void *d)
+{
+ return container_of(d, struct peci_driver, driver);
+}
+
+/**
+ * module_peci_driver - Helper macro for registering a modular PECI driver
+ * @__peci_driver: peci_driver struct
+ *
+ * Helper macro for PECI drivers which do not do anything special in module
+ * init/exit. This eliminates a lot of boilerplate. Each module may only
+ * use this macro once, and calling it replaces module_init() and module_exit()
+ */
+#define module_peci_driver(__peci_driver) \
+ module_driver(__peci_driver, peci_add_driver, peci_del_driver)
+
+/* use a define to avoid include chaining to get THIS_MODULE */
+#define peci_add_driver(driver) peci_register_driver(THIS_MODULE, driver)
+
+extern struct bus_type peci_bus_type;
+extern struct device_type peci_adapter_type;
+extern struct device_type peci_client_type;
+
+int peci_register_driver(struct module *owner, struct peci_driver *drv);
+void peci_del_driver(struct peci_driver *driver);
+struct peci_client *peci_verify_client(struct device *dev);
+struct peci_adapter *peci_alloc_adapter(struct device *dev, uint size);
+struct peci_adapter *peci_get_adapter(int nr);
+void peci_put_adapter(struct peci_adapter *adapter);
+int peci_add_adapter(struct peci_adapter *adapter);
+void peci_del_adapter(struct peci_adapter *adapter);
+struct peci_adapter *peci_verify_adapter(struct device *dev);
+int peci_for_each_dev(void *data, int (*fn)(struct device *, void *));
+struct peci_xfer_msg *peci_get_xfer_msg(u8 tx_len, u8 rx_len);
+void peci_put_xfer_msg(struct peci_xfer_msg *msg);
+int peci_command(struct peci_adapter *adpater, enum peci_cmd cmd, void *vmsg);
+int peci_get_cpu_id(struct peci_adapter *adapter, u8 addr, u32 *cpu_id);
+
+#endif /* __LINUX_PECI_H */
diff --git a/include/linux/tpm.h b/include/linux/tpm.h
index 53c0ea9ec9df..1ce90b121fa5 100644
--- a/include/linux/tpm.h
+++ b/include/linux/tpm.h
@@ -21,6 +21,7 @@
#include <linux/acpi.h>
#include <linux/cdev.h>
#include <linux/fs.h>
+#include <linux/highmem.h>
#include <crypto/hash_info.h>
#define TPM_DIGEST_SIZE 20 /* Max TPM v1.2 PCR size */
@@ -161,6 +162,218 @@ struct tpm_chip {
int locality;
};
+#define TPM_HEADER_SIZE 10
+
+enum tpm2_const {
+ TPM2_PLATFORM_PCR = 24,
+ TPM2_PCR_SELECT_MIN = ((TPM2_PLATFORM_PCR + 7) / 8),
+};
+
+enum tpm2_timeouts {
+ TPM2_TIMEOUT_A = 750,
+ TPM2_TIMEOUT_B = 2000,
+ TPM2_TIMEOUT_C = 200,
+ TPM2_TIMEOUT_D = 30,
+ TPM2_DURATION_SHORT = 20,
+ TPM2_DURATION_MEDIUM = 750,
+ TPM2_DURATION_LONG = 2000,
+ TPM2_DURATION_LONG_LONG = 300000,
+ TPM2_DURATION_DEFAULT = 120000,
+};
+
+enum tpm2_structures {
+ TPM2_ST_NO_SESSIONS = 0x8001,
+ TPM2_ST_SESSIONS = 0x8002,
+};
+
+/* Indicates from what layer of the software stack the error comes from */
+#define TSS2_RC_LAYER_SHIFT 16
+#define TSS2_RESMGR_TPM_RC_LAYER (11 << TSS2_RC_LAYER_SHIFT)
+
+enum tpm2_return_codes {
+ TPM2_RC_SUCCESS = 0x0000,
+ TPM2_RC_HASH = 0x0083, /* RC_FMT1 */
+ TPM2_RC_HANDLE = 0x008B,
+ TPM2_RC_INITIALIZE = 0x0100, /* RC_VER1 */
+ TPM2_RC_FAILURE = 0x0101,
+ TPM2_RC_DISABLED = 0x0120,
+ TPM2_RC_UPGRADE = 0x012D,
+ TPM2_RC_COMMAND_CODE = 0x0143,
+ TPM2_RC_TESTING = 0x090A, /* RC_WARN */
+ TPM2_RC_REFERENCE_H0 = 0x0910,
+ TPM2_RC_RETRY = 0x0922,
+};
+
+enum tpm2_command_codes {
+ TPM2_CC_FIRST = 0x011F,
+ TPM2_CC_HIERARCHY_CONTROL = 0x0121,
+ TPM2_CC_HIERARCHY_CHANGE_AUTH = 0x0129,
+ TPM2_CC_CREATE_PRIMARY = 0x0131,
+ TPM2_CC_SEQUENCE_COMPLETE = 0x013E,
+ TPM2_CC_SELF_TEST = 0x0143,
+ TPM2_CC_STARTUP = 0x0144,
+ TPM2_CC_SHUTDOWN = 0x0145,
+ TPM2_CC_NV_READ = 0x014E,
+ TPM2_CC_CREATE = 0x0153,
+ TPM2_CC_LOAD = 0x0157,
+ TPM2_CC_SEQUENCE_UPDATE = 0x015C,
+ TPM2_CC_UNSEAL = 0x015E,
+ TPM2_CC_CONTEXT_LOAD = 0x0161,
+ TPM2_CC_CONTEXT_SAVE = 0x0162,
+ TPM2_CC_FLUSH_CONTEXT = 0x0165,
+ TPM2_CC_VERIFY_SIGNATURE = 0x0177,
+ TPM2_CC_GET_CAPABILITY = 0x017A,
+ TPM2_CC_GET_RANDOM = 0x017B,
+ TPM2_CC_PCR_READ = 0x017E,
+ TPM2_CC_PCR_EXTEND = 0x0182,
+ TPM2_CC_EVENT_SEQUENCE_COMPLETE = 0x0185,
+ TPM2_CC_HASH_SEQUENCE_START = 0x0186,
+ TPM2_CC_CREATE_LOADED = 0x0191,
+ TPM2_CC_LAST = 0x0193, /* Spec 1.36 */
+};
+
+enum tpm2_permanent_handles {
+ TPM2_RS_PW = 0x40000009,
+};
+
+enum tpm2_capabilities {
+ TPM2_CAP_HANDLES = 1,
+ TPM2_CAP_COMMANDS = 2,
+ TPM2_CAP_PCRS = 5,
+ TPM2_CAP_TPM_PROPERTIES = 6,
+};
+
+enum tpm2_properties {
+ TPM_PT_TOTAL_COMMANDS = 0x0129,
+};
+
+enum tpm2_startup_types {
+ TPM2_SU_CLEAR = 0x0000,
+ TPM2_SU_STATE = 0x0001,
+};
+
+enum tpm2_cc_attrs {
+ TPM2_CC_ATTR_CHANDLES = 25,
+ TPM2_CC_ATTR_RHANDLE = 28,
+};
+
+#define TPM_VID_INTEL 0x8086
+#define TPM_VID_WINBOND 0x1050
+#define TPM_VID_STM 0x104A
+
+enum tpm_chip_flags {
+ TPM_CHIP_FLAG_TPM2 = BIT(1),
+ TPM_CHIP_FLAG_IRQ = BIT(2),
+ TPM_CHIP_FLAG_VIRTUAL = BIT(3),
+ TPM_CHIP_FLAG_HAVE_TIMEOUTS = BIT(4),
+ TPM_CHIP_FLAG_ALWAYS_POWERED = BIT(5),
+ TPM_CHIP_FLAG_FIRMWARE_POWER_MANAGED = BIT(6),
+};
+
+#define to_tpm_chip(d) container_of(d, struct tpm_chip, dev)
+
+struct tpm_header {
+ __be16 tag;
+ __be32 length;
+ union {
+ __be32 ordinal;
+ __be32 return_code;
+ };
+} __packed;
+
+/* A string buffer type for constructing TPM commands. This is based on the
+ * ideas of string buffer code in security/keys/trusted.h but is heap based
+ * in order to keep the stack usage minimal.
+ */
+
+enum tpm_buf_flags {
+ TPM_BUF_OVERFLOW = BIT(0),
+};
+
+struct tpm_buf {
+ unsigned int flags;
+ u8 *data;
+};
+
+static inline void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal)
+{
+ struct tpm_header *head = (struct tpm_header *)buf->data;
+
+ head->tag = cpu_to_be16(tag);
+ head->length = cpu_to_be32(sizeof(*head));
+ head->ordinal = cpu_to_be32(ordinal);
+}
+
+static inline int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal)
+{
+ buf->data = (u8 *)__get_free_page(GFP_KERNEL);
+ if (!buf->data)
+ return -ENOMEM;
+
+ buf->flags = 0;
+ tpm_buf_reset(buf, tag, ordinal);
+ return 0;
+}
+
+static inline void tpm_buf_destroy(struct tpm_buf *buf)
+{
+ free_page((unsigned long)buf->data);
+}
+
+static inline u32 tpm_buf_length(struct tpm_buf *buf)
+{
+ struct tpm_header *head = (struct tpm_header *)buf->data;
+
+ return be32_to_cpu(head->length);
+}
+
+static inline u16 tpm_buf_tag(struct tpm_buf *buf)
+{
+ struct tpm_header *head = (struct tpm_header *)buf->data;
+
+ return be16_to_cpu(head->tag);
+}
+
+static inline void tpm_buf_append(struct tpm_buf *buf,
+ const unsigned char *new_data,
+ unsigned int new_len)
+{
+ struct tpm_header *head = (struct tpm_header *)buf->data;
+ u32 len = tpm_buf_length(buf);
+
+ /* Return silently if overflow has already happened. */
+ if (buf->flags & TPM_BUF_OVERFLOW)
+ return;
+
+ if ((len + new_len) > PAGE_SIZE) {
+ WARN(1, "tpm_buf: overflow\n");
+ buf->flags |= TPM_BUF_OVERFLOW;
+ return;
+ }
+
+ memcpy(&buf->data[len], new_data, new_len);
+ head->length = cpu_to_be32(len + new_len);
+}
+
+static inline void tpm_buf_append_u8(struct tpm_buf *buf, const u8 value)
+{
+ tpm_buf_append(buf, &value, 1);
+}
+
+static inline void tpm_buf_append_u16(struct tpm_buf *buf, const u16 value)
+{
+ __be16 value2 = cpu_to_be16(value);
+
+ tpm_buf_append(buf, (u8 *) &value2, 2);
+}
+
+static inline void tpm_buf_append_u32(struct tpm_buf *buf, const u32 value)
+{
+ __be32 value2 = cpu_to_be32(value);
+
+ tpm_buf_append(buf, (u8 *) &value2, 4);
+}
+
#if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE)
extern int tpm_is_tpm2(struct tpm_chip *chip);
diff --git a/include/trace/events/fsi.h b/include/trace/events/fsi.h
index 92e5e89e52ed..9832cb8e0eb0 100644
--- a/include/trace/events/fsi.h
+++ b/include/trace/events/fsi.h
@@ -26,7 +26,7 @@ TRACE_EVENT(fsi_master_read,
__entry->addr = addr;
__entry->size = size;
),
- TP_printk("fsi%d:%02d:%02d %08x[%zd]",
+ TP_printk("fsi%d:%02d:%02d %08x[%zu]",
__entry->master_idx,
__entry->link,
__entry->id,
@@ -56,7 +56,7 @@ TRACE_EVENT(fsi_master_write,
__entry->data = 0;
memcpy(&__entry->data, data, size);
),
- TP_printk("fsi%d:%02d:%02d %08x[%zd] <= {%*ph}",
+ TP_printk("fsi%d:%02d:%02d %08x[%zu] <= {%*ph}",
__entry->master_idx,
__entry->link,
__entry->id,
@@ -93,7 +93,7 @@ TRACE_EVENT(fsi_master_rw_result,
if (__entry->write || !__entry->ret)
memcpy(&__entry->data, data, size);
),
- TP_printk("fsi%d:%02d:%02d %08x[%zd] %s {%*ph} ret %d",
+ TP_printk("fsi%d:%02d:%02d %08x[%zu] %s {%*ph} ret %d",
__entry->master_idx,
__entry->link,
__entry->id,
diff --git a/include/trace/events/fsi_master_aspeed.h b/include/trace/events/fsi_master_aspeed.h
new file mode 100644
index 000000000000..a355ceacc33f
--- /dev/null
+++ b/include/trace/events/fsi_master_aspeed.h
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM fsi_master_aspeed
+
+#if !defined(_TRACE_FSI_MASTER_ASPEED_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_FSI_MASTER_ASPEED_H
+
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(fsi_master_aspeed_opb_read,
+ TP_PROTO(uint32_t addr, size_t size, uint32_t result, uint32_t status, uint32_t irq_status),
+ TP_ARGS(addr, size, result, status, irq_status),
+ TP_STRUCT__entry(
+ __field(uint32_t, addr)
+ __field(size_t, size)
+ __field(uint32_t, result)
+ __field(uint32_t, status)
+ __field(uint32_t, irq_status)
+ ),
+ TP_fast_assign(
+ __entry->addr = addr;
+ __entry->size = size;
+ __entry->result = result;
+ __entry->status = status;
+ __entry->irq_status = irq_status;
+ ),
+ TP_printk("addr %08x size %zu: result %08x sts: %08x irq_sts: %08x",
+ __entry->addr, __entry->size, __entry->result,
+ __entry->status, __entry->irq_status
+ )
+);
+
+TRACE_EVENT(fsi_master_aspeed_opb_write,
+ TP_PROTO(uint32_t addr, uint32_t val, size_t size, uint32_t status, uint32_t irq_status),
+ TP_ARGS(addr, val, size, status, irq_status),
+ TP_STRUCT__entry(
+ __field(uint32_t, addr)
+ __field(uint32_t, val)
+ __field(size_t, size)
+ __field(uint32_t, status)
+ __field(uint32_t, irq_status)
+ ),
+ TP_fast_assign(
+ __entry->addr = addr;
+ __entry->val = val;
+ __entry->size = size;
+ __entry->status = status;
+ __entry->irq_status = irq_status;
+ ),
+ TP_printk("addr %08x val %08x size %zu status: %08x irq_sts: %08x",
+ __entry->addr, __entry->val, __entry->size,
+ __entry->status, __entry->irq_status
+ )
+ );
+
+TRACE_EVENT(fsi_master_aspeed_opb_error,
+ TP_PROTO(uint32_t mresp0, uint32_t mstap0, uint32_t mesrb0),
+ TP_ARGS(mresp0, mstap0, mesrb0),
+ TP_STRUCT__entry(
+ __field(uint32_t, mresp0)
+ __field(uint32_t, mstap0)
+ __field(uint32_t, mesrb0)
+ ),
+ TP_fast_assign(
+ __entry->mresp0 = mresp0;
+ __entry->mstap0 = mstap0;
+ __entry->mesrb0 = mesrb0;
+ ),
+ TP_printk("mresp0 %08x mstap0 %08x mesrb0 %08x",
+ __entry->mresp0, __entry->mstap0, __entry->mesrb0
+ )
+ );
+
+#endif
+
+#include <trace/define_trace.h>
diff --git a/include/uapi/linux/aspeed-xdma.h b/include/uapi/linux/aspeed-xdma.h
new file mode 100644
index 000000000000..3a3646fd1e9e
--- /dev/null
+++ b/include/uapi/linux/aspeed-xdma.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/* Copyright IBM Corp 2019 */
+
+#ifndef _UAPI_LINUX_ASPEED_XDMA_H_
+#define _UAPI_LINUX_ASPEED_XDMA_H_
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+#define __ASPEED_XDMA_IOCTL_MAGIC 0xb7
+#define ASPEED_XDMA_IOCTL_RESET _IO(__ASPEED_XDMA_IOCTL_MAGIC, 0)
+
+/*
+ * aspeed_xdma_direction
+ *
+ * ASPEED_XDMA_DIRECTION_DOWNSTREAM: transfers data from the host to the BMC
+ *
+ * ASPEED_XDMA_DIRECTION_UPSTREAM: transfers data from the BMC to the host
+ */
+enum aspeed_xdma_direction {
+ ASPEED_XDMA_DIRECTION_DOWNSTREAM = 0,
+ ASPEED_XDMA_DIRECTION_UPSTREAM,
+};
+
+/*
+ * aspeed_xdma_op
+ *
+ * host_addr: the DMA address on the host side, typically configured by PCI
+ * subsystem
+ *
+ * len: the size of the transfer in bytes
+ *
+ * direction: an enumerator indicating the direction of the DMA operation; see
+ * enum aspeed_xdma_direction
+ */
+struct aspeed_xdma_op {
+ __u64 host_addr;
+ __u32 len;
+ __u32 direction;
+};
+
+#endif /* _UAPI_LINUX_ASPEED_XDMA_H_ */
diff --git a/include/uapi/linux/peci-ioctl.h b/include/uapi/linux/peci-ioctl.h
new file mode 100644
index 000000000000..c74b3cde52e8
--- /dev/null
+++ b/include/uapi/linux/peci-ioctl.h
@@ -0,0 +1,661 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/* Copyright (c) 2018-2020 Intel Corporation */
+
+#ifndef __PECI_IOCTL_H
+#define __PECI_IOCTL_H
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+/* The PECI client's default address of 0x30 */
+#define PECI_BASE_ADDR 0x30
+
+/* Max number of CPU clients */
+#define PECI_OFFSET_MAX 8
+
+/* PECI read/write data buffer size max */
+#define PECI_BUFFER_SIZE 255
+
+/* Device Specific Completion Code (CC) Definition */
+#define PECI_DEV_CC_SUCCESS 0x40
+#define PECI_DEV_CC_NEED_RETRY 0x80
+#define PECI_DEV_CC_OUT_OF_RESOURCE 0x81
+#define PECI_DEV_CC_UNAVAIL_RESOURCE 0x82
+#define PECI_DEV_CC_INVALID_REQ 0x90
+#define PECI_DEV_CC_MCA_ERROR 0x91
+#define PECI_DEV_CC_CATASTROPHIC_MCA_ERROR 0x93
+#define PECI_DEV_CC_FATAL_MCA_DETECTED 0x94
+#define PECI_DEV_CC_PARITY_ERROR_ON_GPSB_OR_PMSB 0x98
+#define PECI_DEV_CC_PARITY_ERROR_ON_GPSB_OR_PMSB_IERR 0x9B
+#define PECI_DEV_CC_PARITY_ERROR_ON_GPSB_OR_PMSB_MCA 0x9C
+
+/* Completion Code mask to check retry needs */
+#define PECI_DEV_CC_RETRY_CHECK_MASK 0xf0
+
+#define PECI_DEV_RETRY_TIMEOUT msecs_to_jiffies(700)
+#define PECI_DEV_RETRY_INTERVAL_MIN_MSEC 1
+#define PECI_DEV_RETRY_INTERVAL_MAX_MSEC 128
+#define PECI_DEV_RETRY_BIT 0x01
+
+/**
+ * enum peci_cmd - PECI client commands
+ * @PECI_CMD_XFER: raw PECI transfer
+ * @PECI_CMD_PING: ping, a required message for all PECI devices
+ * @PECI_CMD_GET_DIB: get DIB (Device Info Byte)
+ * @PECI_CMD_GET_TEMP: get maximum die temperature
+ * @PECI_CMD_RD_PKG_CFG: read access to the PCS (Package Configuration Space)
+ * @PECI_CMD_WR_PKG_CFG: write access to the PCS (Package Configuration Space)
+ * @PECI_CMD_RD_IA_MSR: read access to MSRs (Model Specific Registers)
+ * @PECI_CMD_WR_IA_MSR: write access to MSRs (Model Specific Registers)
+ * @PECI_CMD_RD_IA_MSREX: read access to MSRs (Model Specific Registers)
+ * @PECI_CMD_RD_PCI_CFG: sideband read access to the PCI configuration space
+ * maintained in downstream devices external to the processor
+ * @PECI_CMD_WR_PCI_CFG: sideband write access to the PCI configuration space
+ * maintained in downstream devices external to the processor
+ * @PECI_CMD_RD_PCI_CFG_LOCAL: sideband read access to the PCI configuration
+ * space that resides within the processor
+ * @PECI_CMD_WR_PCI_CFG_LOCAL: sideband write access to the PCI configuration
+ * space that resides within the processor
+ *
+ * Available commands depend on client's PECI revision.
+ */
+enum peci_cmd {
+ PECI_CMD_XFER = 0,
+ PECI_CMD_PING,
+ PECI_CMD_GET_DIB,
+ PECI_CMD_GET_TEMP,
+ PECI_CMD_RD_PKG_CFG,
+ PECI_CMD_WR_PKG_CFG,
+ PECI_CMD_RD_IA_MSR,
+ PECI_CMD_WR_IA_MSR,
+ PECI_CMD_RD_IA_MSREX,
+ PECI_CMD_RD_PCI_CFG,
+ PECI_CMD_WR_PCI_CFG,
+ PECI_CMD_RD_PCI_CFG_LOCAL,
+ PECI_CMD_WR_PCI_CFG_LOCAL,
+ PECI_CMD_RD_END_PT_CFG,
+ PECI_CMD_WR_END_PT_CFG,
+ PECI_CMD_CRASHDUMP_DISC,
+ PECI_CMD_CRASHDUMP_GET_FRAME,
+ PECI_CMD_MAX
+};
+
+/**
+ * struct peci_xfer_msg - raw PECI transfer command
+ * @addr; address of the client
+ * @tx_len: number of data to be written in bytes
+ * @rx_len: number of data to be read in bytes
+ * @tx_buf: data to be written, or NULL
+ * @rx_buf: data to be read, or NULL
+ *
+ * raw PECI transfer
+ */
+struct peci_xfer_msg {
+ __u8 addr;
+ __u8 tx_len;
+ __u8 rx_len;
+ __u8 padding;
+ __u8 *tx_buf;
+ __u8 *rx_buf;
+} __attribute__((__packed__));
+
+/**
+ * struct peci_ping_msg - ping command
+ * @addr: address of the client
+ *
+ * Ping() is a required message for all PECI devices. This message is used to
+ * enumerate devices or determine if a device has been removed, been
+ * powered-off, etc.
+ */
+struct peci_ping_msg {
+ __u8 addr;
+ __u8 padding[3];
+} __attribute__((__packed__));
+
+/**
+ * struct peci_get_dib_msg - GetDIB command
+ * @addr: address of the client
+ * @dib: DIB data to be read
+ *
+ * The processor PECI client implementation of GetDIB() includes an 8-byte
+ * response and provides information regarding client revision number and the
+ * number of supported domains. All processor PECI clients support the GetDIB()
+ * command.
+ */
+struct peci_get_dib_msg {
+#define PECI_GET_DIB_WR_LEN 1
+#define PECI_GET_DIB_RD_LEN 8
+#define PECI_GET_DIB_CMD 0xf7
+
+ __u8 addr;
+ __u8 padding[3];
+ __u64 dib;
+} __attribute__((__packed__));
+
+/**
+ * struct peci_get_temp_msg - GetTemp command
+ * @addr: address of the client
+ * @temp_raw: raw temperature data to be read
+ *
+ * The GetTemp() command is used to retrieve the maximum die temperature from a
+ * target PECI address. The temperature is used by the external thermal
+ * management system to regulate the temperature on the die. The data is
+ * returned as a negative value representing the number of degrees centigrade
+ * below the maximum processor junction temperature.
+ */
+struct peci_get_temp_msg {
+#define PECI_GET_TEMP_WR_LEN 1
+#define PECI_GET_TEMP_RD_LEN 2
+#define PECI_GET_TEMP_CMD 0x01
+
+ __u8 addr;
+ __u8 padding;
+ __s16 temp_raw;
+} __attribute__((__packed__));
+
+/**
+ * struct peci_rd_pkg_cfg_msg - RdPkgConfig command
+ * @addr: address of the client
+ * @index: encoding index for the requested service
+ * @param: specific data being requested
+ * @rx_len: number of data to be read in bytes
+ * @cc: completion code
+ * @pkg_config: package config data to be read
+ *
+ * The RdPkgConfig() command provides read access to the Package Configuration
+ * Space (PCS) within the processor, including various power and thermal
+ * management functions. Typical PCS read services supported by the processor
+ * may include access to temperature data, energy status, run time information,
+ * DIMM temperatures and so on.
+ */
+struct peci_rd_pkg_cfg_msg {
+#define PECI_RDPKGCFG_WRITE_LEN 5
+#define PECI_RDPKGCFG_READ_LEN_BASE 1
+#define PECI_RDPKGCFG_CMD 0xa1
+
+ __u8 addr;
+ __u8 index;
+#define PECI_MBX_INDEX_CPU_ID 0 /* Package Identifier Read */
+#define PECI_MBX_INDEX_VR_DEBUG 1 /* VR Debug */
+#define PECI_MBX_INDEX_PKG_TEMP_READ 2 /* Package Temperature Read */
+#define PECI_MBX_INDEX_ENERGY_COUNTER 3 /* Energy counter */
+#define PECI_MBX_INDEX_ENERGY_STATUS 4 /* DDR Energy Status */
+#define PECI_MBX_INDEX_WAKE_MODE_BIT 5 /* "Wake on PECI" Mode bit */
+#define PECI_MBX_INDEX_EPI 6 /* Efficient Performance Indication */
+#define PECI_MBX_INDEX_PKG_RAPL_PERF 8 /* Pkg RAPL Performance Status Read */
+#define PECI_MBX_INDEX_PER_CORE_DTS_TEMP 9 /* Per Core DTS Temperature Read */
+#define PECI_MBX_INDEX_DTS_MARGIN 10 /* DTS thermal margin */
+#define PECI_MBX_INDEX_SKT_PWR_THRTL_DUR 11 /* Socket Power Throttled Duration */
+#define PECI_MBX_INDEX_CFG_TDP_CONTROL 12 /* TDP Config Control */
+#define PECI_MBX_INDEX_CFG_TDP_LEVELS 13 /* TDP Config Levels */
+#define PECI_MBX_INDEX_DDR_DIMM_TEMP 14 /* DDR DIMM Temperature */
+#define PECI_MBX_INDEX_CFG_ICCMAX 15 /* Configurable ICCMAX */
+#define PECI_MBX_INDEX_TEMP_TARGET 16 /* Temperature Target Read */
+#define PECI_MBX_INDEX_CURR_CFG_LIMIT 17 /* Current Config Limit */
+#define PECI_MBX_INDEX_DIMM_TEMP_READ 20 /* Package Thermal Status Read */
+#define PECI_MBX_INDEX_DRAM_IMC_TMP_READ 22 /* DRAM IMC Temperature Read */
+#define PECI_MBX_INDEX_DDR_CH_THERM_STAT 23 /* DDR Channel Thermal Status */
+#define PECI_MBX_INDEX_PKG_POWER_LIMIT1 26 /* Package Power Limit1 */
+#define PECI_MBX_INDEX_PKG_POWER_LIMIT2 27 /* Package Power Limit2 */
+#define PECI_MBX_INDEX_TDP 28 /* Thermal design power minimum */
+#define PECI_MBX_INDEX_TDP_HIGH 29 /* Thermal design power maximum */
+#define PECI_MBX_INDEX_TDP_UNITS 30 /* Units for power/energy registers */
+#define PECI_MBX_INDEX_RUN_TIME 31 /* Accumulated Run Time */
+#define PECI_MBX_INDEX_CONSTRAINED_TIME 32 /* Thermally Constrained Time Read */
+#define PECI_MBX_INDEX_TURBO_RATIO 33 /* Turbo Activation Ratio */
+#define PECI_MBX_INDEX_DDR_RAPL_PL1 34 /* DDR RAPL PL1 */
+#define PECI_MBX_INDEX_DDR_PWR_INFO_HIGH 35 /* DRAM Power Info Read (high) */
+#define PECI_MBX_INDEX_DDR_PWR_INFO_LOW 36 /* DRAM Power Info Read (low) */
+#define PECI_MBX_INDEX_DDR_RAPL_PL2 37 /* DDR RAPL PL2 */
+#define PECI_MBX_INDEX_DDR_RAPL_STATUS 38 /* DDR RAPL Performance Status */
+#define PECI_MBX_INDEX_DDR_HOT_ABSOLUTE 43 /* DDR Hottest Dimm Absolute Temp */
+#define PECI_MBX_INDEX_DDR_HOT_RELATIVE 44 /* DDR Hottest Dimm Relative Temp */
+#define PECI_MBX_INDEX_DDR_THROTTLE_TIME 45 /* DDR Throttle Time */
+#define PECI_MBX_INDEX_DDR_THERM_STATUS 46 /* DDR Thermal Status */
+#define PECI_MBX_INDEX_TIME_AVG_TEMP 47 /* Package time-averaged temperature */
+#define PECI_MBX_INDEX_TURBO_RATIO_LIMIT 49 /* Turbo Ratio Limit Read */
+#define PECI_MBX_INDEX_HWP_AUTO_OOB 53 /* HWP Autonomous Out-of-band */
+#define PECI_MBX_INDEX_DDR_WARM_BUDGET 55 /* DDR Warm Power Budget */
+#define PECI_MBX_INDEX_DDR_HOT_BUDGET 56 /* DDR Hot Power Budget */
+#define PECI_MBX_INDEX_PKG_PSYS_PWR_LIM3 57 /* Package/Psys Power Limit3 */
+#define PECI_MBX_INDEX_PKG_PSYS_PWR_LIM1 58 /* Package/Psys Power Limit1 */
+#define PECI_MBX_INDEX_PKG_PSYS_PWR_LIM2 59 /* Package/Psys Power Limit2 */
+#define PECI_MBX_INDEX_PKG_PSYS_PWR_LIM4 60 /* Package/Psys Power Limit4 */
+#define PECI_MBX_INDEX_PERF_LIMIT_REASON 65 /* Performance Limit Reasons */
+
+ __u16 param;
+/* When index is PECI_MBX_INDEX_CPU_ID */
+#define PECI_PKG_ID_CPU_ID 0x0000 /* CPUID Info */
+#define PECI_PKG_ID_PLATFORM_ID 0x0001 /* Platform ID */
+#define PECI_PKG_ID_UNCORE_ID 0x0002 /* Uncore Device ID */
+#define PECI_PKG_ID_MAX_THREAD_ID 0x0003 /* Max Thread ID */
+#define PECI_PKG_ID_MICROCODE_REV 0x0004 /* CPU Microcode Update Revision */
+#define PECI_PKG_ID_MACHINE_CHECK_STATUS 0x0005 /* Machine Check Status */
+
+ __u8 rx_len;
+ __u8 cc;
+ __u8 padding[2];
+ __u8 pkg_config[4];
+} __attribute__((__packed__));
+
+/**
+ * struct peci_wr_pkg_cfg_msg - WrPkgConfig command
+ * @addr: address of the client
+ * @index: encoding index for the requested service
+ * @param: specific data being requested
+ * @tx_len: number of data to be written in bytes
+ * @cc: completion code
+ * @value: package config data to be written
+ *
+ * The WrPkgConfig() command provides write access to the Package Configuration
+ * Space (PCS) within the processor, including various power and thermal
+ * management functions. Typical PCS write services supported by the processor
+ * may include power limiting, thermal averaging constant programming and so
+ * on.
+ */
+struct peci_wr_pkg_cfg_msg {
+#define PECI_WRPKGCFG_WRITE_LEN_BASE 6
+#define PECI_WRPKGCFG_READ_LEN 1
+#define PECI_WRPKGCFG_CMD 0xa5
+
+ __u8 addr;
+ __u8 index;
+#define PECI_MBX_INDEX_DIMM_AMBIENT 19
+#define PECI_MBX_INDEX_DIMM_TEMP 24
+
+ __u16 param;
+ __u8 tx_len;
+ __u8 cc;
+ __u8 padding[2];
+ __u32 value;
+} __attribute__((__packed__));
+
+/**
+ * struct peci_rd_ia_msr_msg - RdIAMSR command
+ * @addr: address of the client
+ * @thread_id: ID of the specific logical processor
+ * @address: address of MSR to read from
+ * @cc: completion code
+ * @value: data to be read
+ *
+ * The RdIAMSR() PECI command provides read access to Model Specific Registers
+ * (MSRs) defined in the processor's Intel Architecture (IA).
+ */
+struct peci_rd_ia_msr_msg {
+#define PECI_RDIAMSR_WRITE_LEN 5
+#define PECI_RDIAMSR_READ_LEN 9
+#define PECI_RDIAMSR_CMD 0xb1
+
+ __u8 addr;
+ __u8 thread_id;
+ __u16 address;
+ __u8 cc;
+ __u8 padding[3];
+ __u64 value;
+} __attribute__((__packed__));
+
+/**
+ * struct peci_wr_ia_msr_msg - WrIAMSR command
+ * @addr: address of the client
+ * @thread_id: ID of the specific logical processor
+ * @address: address of MSR to write to
+ * @tx_len: number of data to be written in bytes
+ * @cc: completion code
+ * @value: data to be written
+ *
+ * The WrIAMSR() PECI command provides write access to Model Specific Registers
+ * (MSRs) defined in the processor's Intel Architecture (IA).
+ */
+struct peci_wr_ia_msr_msg {
+#define PECI_WRIAMSR_CMD 0xb5
+
+ __u8 addr;
+ __u8 thread_id;
+ __u16 address;
+ __u8 tx_len;
+ __u8 cc;
+ __u8 padding[2];
+ __u64 value;
+} __attribute__((__packed__));
+
+/**
+ * struct peci_rd_ia_msrex_msg - RdIAMSREX command
+ * @addr: address of the client
+ * @thread_id: ID of the specific logical processor
+ * @address: address of MSR to read from
+ * @cc: completion code
+ * @value: data to be read
+ *
+ * The RdIAMSREX() PECI command provides read access to Model Specific
+ * Registers (MSRs) defined in the processor's Intel Architecture (IA).
+ * The differences between RdIAMSREX() and RdIAMSR() are that:
+ * (1)RdIAMSR() can only read MC registers, RdIAMSREX() can read all MSRs
+ * (2)thread_id of RdIAMSR() is u8, thread_id of RdIAMSREX() is u16
+ */
+struct peci_rd_ia_msrex_msg {
+#define PECI_RDIAMSREX_WRITE_LEN 6
+#define PECI_RDIAMSREX_READ_LEN 9
+#define PECI_RDIAMSREX_CMD 0xd1
+
+ __u8 addr;
+ __u8 padding0;
+ __u16 thread_id;
+ __u16 address;
+ __u8 cc;
+ __u8 padding1;
+ __u64 value;
+} __attribute__((__packed__));
+
+/**
+ * struct peci_rd_pci_cfg_msg - RdPCIConfig command
+ * @addr: address of the client
+ * @bus: PCI bus number
+ * @device: PCI device number
+ * @function: specific function to read from
+ * @reg: specific register to read from
+ * @cc: completion code
+ * @pci_config: config data to be read
+ *
+ * The RdPCIConfig() command provides sideband read access to the PCI
+ * configuration space maintained in downstream devices external to the
+ * processor.
+ */
+struct peci_rd_pci_cfg_msg {
+#define PECI_RDPCICFG_WRITE_LEN 6
+#define PECI_RDPCICFG_READ_LEN 5
+#define PECI_RDPCICFG_READ_LEN_MAX 24
+#define PECI_RDPCICFG_CMD 0x61
+
+ __u8 addr;
+ __u8 bus;
+#define PECI_PCI_BUS0_CPU0 0x00
+#define PECI_PCI_BUS0_CPU1 0x80
+#define PECI_PCI_CPUBUSNO_BUS 0x00
+#define PECI_PCI_CPUBUSNO_DEV 0x08
+#define PECI_PCI_CPUBUSNO_FUNC 0x02
+#define PECI_PCI_CPUBUSNO 0xcc
+#define PECI_PCI_CPUBUSNO_1 0xd0
+#define PECI_PCI_CPUBUSNO_VALID 0xd4
+
+ __u8 device;
+ __u8 function;
+ __u16 reg;
+ __u8 cc;
+ __u8 padding[1];
+ __u8 pci_config[4];
+} __attribute__((__packed__));
+
+/**
+ * struct peci_wr_pci_cfg_msg - WrPCIConfig command
+ * @addr: address of the client
+ * @bus: PCI bus number
+ * @device: PCI device number
+ * @function: specific function to write to
+ * @reg: specific register to write to
+ * @tx_len: number of data to be written in bytes
+ * @cc: completion code
+ * @pci_config: config data to be written
+ *
+ * The RdPCIConfig() command provides sideband write access to the PCI
+ * configuration space maintained in downstream devices external to the
+ * processor.
+ */
+struct peci_wr_pci_cfg_msg {
+#define PECI_WRPCICFG_CMD 0x65
+
+ __u8 addr;
+ __u8 bus;
+ __u8 device;
+ __u8 function;
+ __u16 reg;
+ __u8 tx_len;
+ __u8 cc;
+ __u8 pci_config[4];
+} __attribute__((__packed__));
+
+/**
+ * struct peci_rd_pci_cfg_local_msg - RdPCIConfigLocal command
+ * @addr: address of the client
+ * @bus: PCI bus number
+ * @device: PCI device number
+ * @function: specific function to read from
+ * @reg: specific register to read from
+ * @rx_len: number of data to be read in bytes
+ * @cc: completion code
+ * @pci_config: config data to be read
+ *
+ * The RdPCIConfigLocal() command provides sideband read access to the PCI
+ * configuration space that resides within the processor. This includes all
+ * processor IIO and uncore registers within the PCI configuration space.
+ */
+struct peci_rd_pci_cfg_local_msg {
+#define PECI_RDPCICFGLOCAL_WRITE_LEN 5
+#define PECI_RDPCICFGLOCAL_READ_LEN_BASE 1
+#define PECI_RDPCICFGLOCAL_CMD 0xe1
+
+ __u8 addr;
+ __u8 bus;
+ __u8 device;
+ __u8 function;
+ __u16 reg;
+ __u8 rx_len;
+ __u8 cc;
+ __u8 pci_config[4];
+} __attribute__((__packed__));
+
+/**
+ * struct peci_wr_pci_cfg_local_msg - WrPCIConfigLocal command
+ * @addr: address of the client
+ * @bus: PCI bus number
+ * @device: PCI device number
+ * @function: specific function to read from
+ * @reg: specific register to read from
+ * @tx_len: number of data to be written in bytes
+ * @cc: completion code
+ * @value: config data to be written
+ *
+ * The WrPCIConfigLocal() command provides sideband write access to the PCI
+ * configuration space that resides within the processor. PECI originators can
+ * access this space even before BIOS enumeration of the system buses.
+ */
+struct peci_wr_pci_cfg_local_msg {
+#define PECI_WRPCICFGLOCAL_WRITE_LEN_BASE 6
+#define PECI_WRPCICFGLOCAL_READ_LEN 1
+#define PECI_WRPCICFGLOCAL_CMD 0xe5
+
+ __u8 addr;
+ __u8 bus;
+ __u8 device;
+ __u8 function;
+ __u16 reg;
+ __u8 tx_len;
+ __u8 cc;
+ __u32 value;
+} __attribute__((__packed__));
+
+struct peci_rd_end_pt_cfg_msg {
+#define PECI_RDENDPTCFG_PCI_WRITE_LEN 12
+#define PECI_RDENDPTCFG_MMIO_D_WRITE_LEN 14
+#define PECI_RDENDPTCFG_MMIO_Q_WRITE_LEN 18
+#define PECI_RDENDPTCFG_READ_LEN_BASE 1
+#define PECI_RDENDPTCFG_CMD 0xc1
+
+ __u8 addr;
+ __u8 msg_type;
+#define PECI_ENDPTCFG_TYPE_LOCAL_PCI 0x03
+#define PECI_ENDPTCFG_TYPE_PCI 0x04
+#define PECI_ENDPTCFG_TYPE_MMIO 0x05
+
+ union {
+ struct {
+ __u8 seg;
+ __u8 bus;
+ __u8 device;
+ __u8 function;
+ __u16 reg;
+ } pci_cfg;
+ struct {
+ __u8 seg;
+ __u8 bus;
+ __u8 device;
+ __u8 function;
+ __u8 bar;
+ __u8 addr_type;
+#define PECI_ENDPTCFG_ADDR_TYPE_PCI 0x04
+#define PECI_ENDPTCFG_ADDR_TYPE_MMIO_D 0x05
+#define PECI_ENDPTCFG_ADDR_TYPE_MMIO_Q 0x06
+
+ __u64 offset;
+ } mmio;
+ } params;
+ __u8 rx_len;
+ __u8 cc;
+ __u8 padding[2];
+ __u8 data[8];
+} __attribute__((__packed__));
+
+struct peci_wr_end_pt_cfg_msg {
+#define PECI_WRENDPTCFG_PCI_WRITE_LEN_BASE 13
+#define PECI_WRENDPTCFG_MMIO_D_WRITE_LEN_BASE 15
+#define PECI_WRENDPTCFG_MMIO_Q_WRITE_LEN_BASE 19
+#define PECI_WRENDPTCFG_READ_LEN 1
+#define PECI_WRENDPTCFG_CMD 0xc5
+
+ __u8 addr;
+ __u8 msg_type;
+ /* See msg_type in struct peci_rd_end_pt_cfg_msg */
+
+ union {
+ struct {
+ __u8 seg;
+ __u8 bus;
+ __u8 device;
+ __u8 function;
+ __u16 reg;
+ } pci_cfg;
+ struct {
+ __u8 seg;
+ __u8 bus;
+ __u8 device;
+ __u8 function;
+ __u8 bar;
+ __u8 addr_type;
+ /* See addr_type in struct peci_rd_end_pt_cfg_msg */
+
+ __u64 offset;
+ } mmio;
+ } params;
+ __u8 tx_len;
+ __u8 cc;
+ __u8 padding[2];
+ __u64 value;
+} __attribute__((__packed__));
+
+/* Crashdump Agent */
+#define PECI_CRASHDUMP_CORE 0x00
+#define PECI_CRASHDUMP_TOR 0x01
+
+/* Crashdump Agent Param */
+#define PECI_CRASHDUMP_PAYLOAD_SIZE 0x00
+
+/* Crashdump Agent Data Param */
+#define PECI_CRASHDUMP_AGENT_ID 0x00
+#define PECI_CRASHDUMP_AGENT_PARAM 0x01
+
+struct peci_crashdump_disc_msg {
+ __u8 addr;
+ __u8 subopcode;
+#define PECI_CRASHDUMP_ENABLED 0x00
+#define PECI_CRASHDUMP_NUM_AGENTS 0x01
+#define PECI_CRASHDUMP_AGENT_DATA 0x02
+
+ __u8 cc;
+ __u8 param0;
+ __u16 param1;
+ __u8 param2;
+ __u8 rx_len;
+ __u8 data[8];
+} __attribute__((__packed__));
+
+struct peci_crashdump_get_frame_msg {
+#define PECI_CRASHDUMP_DISC_WRITE_LEN 9
+#define PECI_CRASHDUMP_DISC_READ_LEN_BASE 1
+#define PECI_CRASHDUMP_DISC_VERSION 0
+#define PECI_CRASHDUMP_DISC_OPCODE 1
+#define PECI_CRASHDUMP_GET_FRAME_WRITE_LEN 10
+#define PECI_CRASHDUMP_GET_FRAME_READ_LEN_BASE 1
+#define PECI_CRASHDUMP_GET_FRAME_VERSION 0
+#define PECI_CRASHDUMP_GET_FRAME_OPCODE 3
+#define PECI_CRASHDUMP_CMD 0x71
+
+ __u8 addr;
+ __u8 padding0;
+ __u16 param0;
+ __u16 param1;
+ __u16 param2;
+ __u8 rx_len;
+ __u8 cc;
+ __u8 padding1[2];
+ __u8 data[16];
+} __attribute__((__packed__));
+
+#define PECI_IOC_BASE 0xb7
+
+#define PECI_IOC_XFER \
+ _IOWR(PECI_IOC_BASE, PECI_CMD_XFER, struct peci_xfer_msg)
+
+#define PECI_IOC_PING \
+ _IOWR(PECI_IOC_BASE, PECI_CMD_PING, struct peci_ping_msg)
+
+#define PECI_IOC_GET_DIB \
+ _IOWR(PECI_IOC_BASE, PECI_CMD_GET_DIB, struct peci_get_dib_msg)
+
+#define PECI_IOC_GET_TEMP \
+ _IOWR(PECI_IOC_BASE, PECI_CMD_GET_TEMP, struct peci_get_temp_msg)
+
+#define PECI_IOC_RD_PKG_CFG \
+ _IOWR(PECI_IOC_BASE, PECI_CMD_RD_PKG_CFG, struct peci_rd_pkg_cfg_msg)
+
+#define PECI_IOC_WR_PKG_CFG \
+ _IOWR(PECI_IOC_BASE, PECI_CMD_WR_PKG_CFG, struct peci_wr_pkg_cfg_msg)
+
+#define PECI_IOC_RD_IA_MSR \
+ _IOWR(PECI_IOC_BASE, PECI_CMD_RD_IA_MSR, struct peci_rd_ia_msr_msg)
+
+#define PECI_IOC_WR_IA_MSR \
+ _IOWR(PECI_IOC_BASE, PECI_CMD_WR_IA_MSR, struct peci_wr_ia_msr_msg)
+
+#define PECI_IOC_RD_IA_MSREX \
+ _IOWR(PECI_IOC_BASE, PECI_CMD_RD_IA_MSREX, struct peci_rd_ia_msrex_msg)
+
+#define PECI_IOC_RD_PCI_CFG \
+ _IOWR(PECI_IOC_BASE, PECI_CMD_RD_PCI_CFG, struct peci_rd_pci_cfg_msg)
+
+#define PECI_IOC_WR_PCI_CFG \
+ _IOWR(PECI_IOC_BASE, PECI_CMD_WR_PCI_CFG, struct peci_wr_pci_cfg_msg)
+
+#define PECI_IOC_RD_PCI_CFG_LOCAL \
+ _IOWR(PECI_IOC_BASE, PECI_CMD_RD_PCI_CFG_LOCAL, \
+ struct peci_rd_pci_cfg_local_msg)
+
+#define PECI_IOC_WR_PCI_CFG_LOCAL \
+ _IOWR(PECI_IOC_BASE, PECI_CMD_WR_PCI_CFG_LOCAL, \
+ struct peci_wr_pci_cfg_local_msg)
+
+#define PECI_IOC_RD_END_PT_CFG \
+ _IOWR(PECI_IOC_BASE, PECI_CMD_RD_END_PT_CFG, \
+ struct peci_rd_end_pt_cfg_msg)
+
+#define PECI_IOC_WR_END_PT_CFG \
+ _IOWR(PECI_IOC_BASE, PECI_CMD_WR_END_PT_CFG, \
+ struct peci_wr_end_pt_cfg_msg)
+
+#define PECI_IOC_CRASHDUMP_DISC \
+ _IOWR(PECI_IOC_BASE, PECI_CMD_CRASHDUMP_DISC, \
+ struct peci_crashdump_disc_msg)
+
+#define PECI_IOC_CRASHDUMP_GET_FRAME \
+ _IOWR(PECI_IOC_BASE, PECI_CMD_CRASHDUMP_GET_FRAME, \
+ struct peci_crashdump_get_frame_msg)
+
+#endif /* __PECI_IOCTL_H */
diff --git a/security/keys/trusted.c b/security/keys/trusted.c
index 36afc29aecc3..8bb0fb571810 100644
--- a/security/keys/trusted.c
+++ b/security/keys/trusted.c
@@ -395,7 +395,7 @@ static int pcrlock(const int pcrnum)
/*
* Create an object specific authorisation protocol (OSAP) session
*/
-static int osap(struct tpm_buf *tb, struct osapsess *s,
+static int osap(struct tpm1_buf *tb, struct osapsess *s,
const unsigned char *key, uint16_t type, uint32_t handle)
{
unsigned char enonce[TPM_NONCE_SIZE];
@@ -430,7 +430,7 @@ static int osap(struct tpm_buf *tb, struct osapsess *s,
/*
* Create an object independent authorisation protocol (oiap) session
*/
-int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce)
+int oiap(struct tpm1_buf *tb, uint32_t *handle, unsigned char *nonce)
{
int ret;
@@ -464,7 +464,7 @@ struct tpm_digests {
* Have the TPM seal(encrypt) the trusted key, possibly based on
* Platform Configuration Registers (PCRs). AUTH1 for sealing key.
*/
-static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,
+static int tpm_seal(struct tpm1_buf *tb, uint16_t keytype,
uint32_t keyhandle, const unsigned char *keyauth,
const unsigned char *data, uint32_t datalen,
unsigned char *blob, uint32_t *bloblen,
@@ -579,7 +579,7 @@ out:
/*
* use the AUTH2_COMMAND form of unseal, to authorize both key and blob
*/
-static int tpm_unseal(struct tpm_buf *tb,
+static int tpm_unseal(struct tpm1_buf *tb,
uint32_t keyhandle, const unsigned char *keyauth,
const unsigned char *blob, int bloblen,
const unsigned char *blobauth,
@@ -670,7 +670,7 @@ static int tpm_unseal(struct tpm_buf *tb,
static int key_seal(struct trusted_key_payload *p,
struct trusted_key_options *o)
{
- struct tpm_buf *tb;
+ struct tpm1_buf *tb;
int ret;
tb = kzalloc(sizeof *tb, GFP_KERNEL);
@@ -696,7 +696,7 @@ static int key_seal(struct trusted_key_payload *p,
static int key_unseal(struct trusted_key_payload *p,
struct trusted_key_options *o)
{
- struct tpm_buf *tb;
+ struct tpm1_buf *tb;
int ret;
tb = kzalloc(sizeof *tb, GFP_KERNEL);