Merge tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 16 Sep 2019 22:52:38 +0000 (15:52 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 16 Sep 2019 22:52:38 +0000 (15:52 -0700)
Pull ARM SoC driver updates from Arnd Bergmann:
 "This contains driver changes that are tightly connected to SoC
  specific code. Aside from smaller cleanups and bug fixes, here is a
  list of the notable changes.

  New device drivers:

   - The Turris Mox router has a new "moxtet" bus driver for its
     on-board pluggable extension bus. The same platform also gains a
     firmware driver.

   - The Samsung Exynos family gains a new Chipid driver exporting using
     the soc device sysfs interface

   - A similar socinfo driver for Qualcomm Snapdragon chips.

   - A firmware driver for the NXP i.MX DSP IPC protocol using shared
     memory and a mailbox

  Other changes:

   - The i.MX reset controller driver now supports the NXP i.MX8MM chip

   - Amlogic SoC specific drivers gain support for the S905X3 and A311D
     chips

   - A rework of the TI Davinci framebuffer driver to allow important
     cleanups in the platform code

   - A couple of device drivers for removed ARM SoC platforms are
     removed. Most of the removals were picked up by other maintainers,
     this contains whatever was left"

* tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (123 commits)
  bus: uniphier-system-bus: use devm_platform_ioremap_resource()
  soc: ti: ti_sci_pm_domains: Add support for exclusive and shared access
  dt-bindings: ti_sci_pm_domains: Add support for exclusive and shared access
  firmware: ti_sci: Allow for device shared and exclusive requests
  bus: imx-weim: remove incorrect __init annotations
  fbdev: remove w90x900/nuc900 platform drivers
  spi: remove w90x900 driver
  net: remove w90p910-ether driver
  net: remove ks8695 driver
  firmware: turris-mox-rwtm: Add sysfs documentation
  firmware: Add Turris Mox rWTM firmware driver
  dt-bindings: firmware: Document cznic,turris-mox-rwtm binding
  bus: moxtet: fix unsigned comparison to less than zero
  bus: moxtet: remove set but not used variable 'dummy'
  ARM: scoop: Use the right include
  dt-bindings: power: add Amlogic Everything-Else power domains bindings
  soc: amlogic: Add support for Everything-Else power domains controller
  fbdev: da8xx: use resource management for dma
  fbdev: da8xx-fb: drop a redundant if
  fbdev: da8xx-fb: use devm_platform_ioremap_resource()
  ...

128 files changed:
Documentation/ABI/testing/debugfs-moxtet [new file with mode: 0644]
Documentation/ABI/testing/sysfs-bus-moxtet-devices [new file with mode: 0644]
Documentation/ABI/testing/sysfs-devices-soc
Documentation/ABI/testing/sysfs-firmware-turris-mox-rwtm [new file with mode: 0644]
Documentation/devicetree/bindings/arm/arm,scmi.txt
Documentation/devicetree/bindings/bus/moxtet.txt [new file with mode: 0644]
Documentation/devicetree/bindings/firmware/cznic,turris-mox-rwtm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/firmware/qcom,scm.txt
Documentation/devicetree/bindings/gpio/gpio-moxtet.txt [new file with mode: 0644]
Documentation/devicetree/bindings/power/amlogic,meson-ee-pwrc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/reset/fsl,imx7-src.txt
Documentation/devicetree/bindings/reset/snps,dw-reset.txt [new file with mode: 0644]
Documentation/devicetree/bindings/soc/amlogic/clk-measure.txt
Documentation/devicetree/bindings/soc/fsl/cpm_qe/qe.txt
Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.txt
Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt
MAINTAINERS
arch/arm/common/scoop.c
arch/arm/mach-davinci/board-da850-evm.c
drivers/base/soc.c
drivers/bus/Kconfig
drivers/bus/Makefile
drivers/bus/fsl-mc/fsl-mc-allocator.c
drivers/bus/fsl-mc/mc-io.c
drivers/bus/imx-weim.c
drivers/bus/moxtet.c [new file with mode: 0644]
drivers/bus/sunxi-rsb.c
drivers/bus/uniphier-system-bus.c
drivers/clk/clk-scmi.c
drivers/firmware/Kconfig
drivers/firmware/Makefile
drivers/firmware/arm_scmi/Makefile
drivers/firmware/arm_scmi/base.c
drivers/firmware/arm_scmi/clock.c
drivers/firmware/arm_scmi/common.h
drivers/firmware/arm_scmi/driver.c
drivers/firmware/arm_scmi/perf.c
drivers/firmware/arm_scmi/power.c
drivers/firmware/arm_scmi/reset.c [new file with mode: 0644]
drivers/firmware/arm_scmi/sensors.c
drivers/firmware/imx/Kconfig
drivers/firmware/imx/Makefile
drivers/firmware/imx/imx-dsp.c [new file with mode: 0644]
drivers/firmware/imx/scu-pd.c
drivers/firmware/qcom_scm.c
drivers/firmware/ti_sci.c
drivers/firmware/turris-mox-rwtm.c [new file with mode: 0644]
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/gpio-moxtet.c [new file with mode: 0644]
drivers/hwmon/scmi-hwmon.c
drivers/net/ethernet/Kconfig
drivers/net/ethernet/Makefile
drivers/net/ethernet/micrel/Kconfig
drivers/net/ethernet/micrel/Makefile
drivers/net/ethernet/micrel/ks8695net.c [deleted file]
drivers/net/ethernet/micrel/ks8695net.h [deleted file]
drivers/net/ethernet/nuvoton/Kconfig [deleted file]
drivers/net/ethernet/nuvoton/Makefile [deleted file]
drivers/net/ethernet/nuvoton/w90p910_ether.c [deleted file]
drivers/reset/Kconfig
drivers/reset/Makefile
drivers/reset/reset-imx7.c
drivers/reset/reset-meson.c
drivers/reset/reset-scmi.c [new file with mode: 0644]
drivers/reset/reset-simple.c
drivers/soc/amlogic/Kconfig
drivers/soc/amlogic/Makefile
drivers/soc/amlogic/meson-clk-measure.c
drivers/soc/amlogic/meson-ee-pwrc.c [new file with mode: 0644]
drivers/soc/amlogic/meson-gx-socinfo.c
drivers/soc/fsl/dpaa2-console.c
drivers/soc/fsl/dpio/dpio-service.c
drivers/soc/fsl/guts.c
drivers/soc/fsl/qbman/bman.c
drivers/soc/fsl/qbman/bman_ccsr.c
drivers/soc/fsl/qbman/bman_portal.c
drivers/soc/fsl/qbman/bman_priv.h
drivers/soc/fsl/qbman/dpaa_sys.c
drivers/soc/fsl/qbman/qman.c
drivers/soc/fsl/qbman/qman_ccsr.c
drivers/soc/fsl/qbman/qman_portal.c
drivers/soc/fsl/qbman/qman_priv.h
drivers/soc/fsl/qe/qe.c
drivers/soc/imx/gpcv2.c
drivers/soc/imx/soc-imx-scu.c
drivers/soc/imx/soc-imx8.c
drivers/soc/mediatek/mtk-cmdq-helper.c
drivers/soc/qcom/Kconfig
drivers/soc/qcom/Makefile
drivers/soc/qcom/qcom_aoss.c
drivers/soc/qcom/smem.c
drivers/soc/qcom/socinfo.c [new file with mode: 0644]
drivers/soc/renesas/Kconfig
drivers/soc/renesas/rcar-sysc.c
drivers/soc/renesas/rmobile-sysc.c
drivers/soc/samsung/Kconfig
drivers/soc/samsung/Makefile
drivers/soc/samsung/exynos-chipid.c [new file with mode: 0644]
drivers/soc/ti/ti_sci_pm_domains.c
drivers/spi/Kconfig
drivers/spi/Makefile
drivers/spi/spi-nuc900.c [deleted file]
drivers/tee/optee/call.c
drivers/video/fbdev/Kconfig
drivers/video/fbdev/Makefile
drivers/video/fbdev/da8xx-fb.c
drivers/video/fbdev/nuc900fb.c [deleted file]
drivers/video/fbdev/nuc900fb.h [deleted file]
include/Kbuild
include/dt-bindings/bus/moxtet.h [new file with mode: 0644]
include/dt-bindings/power/meson-g12a-power.h [new file with mode: 0644]
include/dt-bindings/power/meson-sm1-power.h [new file with mode: 0644]
include/dt-bindings/reset/amlogic,meson-gxbb-reset.h
include/dt-bindings/reset/amlogic,meson8b-reset.h
include/dt-bindings/reset/imx8mq-reset.h
include/dt-bindings/soc/ti,sci_pm_domain.h [new file with mode: 0644]
include/linux/firmware/imx/dsp.h [new file with mode: 0644]
include/linux/moxtet.h [new file with mode: 0644]
include/linux/platform_data/spi-nuc900.h [deleted file]
include/linux/platform_data/video-nuc900fb.h [deleted file]
include/linux/qcom_scm.h
include/linux/scmi_protocol.h
include/linux/soc/mediatek/mtk-cmdq.h
include/linux/soc/samsung/exynos-chipid.h [new file with mode: 0644]
include/linux/soc/ti/ti_sci_protocol.h
include/linux/sys_soc.h
include/video/da8xx-fb.h

diff --git a/Documentation/ABI/testing/debugfs-moxtet b/Documentation/ABI/testing/debugfs-moxtet
new file mode 100644 (file)
index 0000000..67b1717
--- /dev/null
@@ -0,0 +1,23 @@
+What:          /sys/kernel/debug/moxtet/input
+Date:          March 2019
+KernelVersion: 5.3
+Contact:       Marek Behún <marek.behun@nic.cz>
+Description:   (R) Read input from the shift registers, in hexadecimal.
+               Returns N+1 bytes, where N is the number of Moxtet connected
+               modules. The first byte is from the CPU board itself.
+               Example: 101214
+                        10: CPU board with SD card
+                        12: 2 = PCIe module, 1 = IRQ not active
+                        14: 4 = Peridot module, 1 = IRQ not active
+
+What:          /sys/kernel/debug/moxtet/output
+Date:          March 2019
+KernelVersion: 5.3
+Contact:       Marek Behún <marek.behun@nic.cz>
+Description:   (RW) Read last written value to the shift registers, in
+               hexadecimal, or write values to the shift registers, also
+               in hexadecimal.
+               Example: 0102
+                        01: 01 was last written, or is to be written, to the
+                            first module's shift register
+                        02: the same for second module
diff --git a/Documentation/ABI/testing/sysfs-bus-moxtet-devices b/Documentation/ABI/testing/sysfs-bus-moxtet-devices
new file mode 100644 (file)
index 0000000..3559585
--- /dev/null
@@ -0,0 +1,17 @@
+What:          /sys/bus/moxtet/devices/moxtet-<name>.<addr>/module_description
+Date:          March 2019
+KernelVersion: 5.3
+Contact:       Marek Behún <marek.behun@nic.cz>
+Description:   (R) Moxtet module description. Format: string
+
+What:          /sys/bus/moxtet/devices/moxtet-<name>.<addr>/module_id
+Date:          March 2019
+KernelVersion: 5.3
+Contact:       Marek Behún <marek.behun@nic.cz>
+Description:   (R) Moxtet module ID. Format: %x
+
+What:          /sys/bus/moxtet/devices/moxtet-<name>.<addr>/module_name
+Date:          March 2019
+KernelVersion: 5.3
+Contact:       Marek Behún <marek.behun@nic.cz>
+Description:   (R) Moxtet module name. Format: string
index 6d9cc25..ba3a3fa 100644 (file)
@@ -26,6 +26,13 @@ Description:
                Read-only attribute common to all SoCs. Contains SoC family name
                (e.g. DB8500).
 
+What:          /sys/devices/socX/serial_number
+Date:          January 2019
+contact:       Bjorn Andersson <bjorn.andersson@linaro.org>
+Description:
+               Read-only attribute supported by most SoCs. Contains the SoC's
+               serial number, if available.
+
 What:          /sys/devices/socX/soc_id
 Date:          January 2012
 contact:       Lee Jones <lee.jones@linaro.org>
diff --git a/Documentation/ABI/testing/sysfs-firmware-turris-mox-rwtm b/Documentation/ABI/testing/sysfs-firmware-turris-mox-rwtm
new file mode 100644 (file)
index 0000000..15595fa
--- /dev/null
@@ -0,0 +1,37 @@
+What:          /sys/firmware/turris-mox-rwtm/board_version
+Date:          August 2019
+KernelVersion: 5.4
+Contact:       Marek Behún <marek.behun@nic.cz>
+Description:   (R) Board version burned into eFuses of this Turris Mox board.
+               Format: %i
+
+What:          /sys/firmware/turris-mox-rwtm/mac_address*
+Date:          August 2019
+KernelVersion: 5.4
+Contact:       Marek Behún <marek.behun@nic.cz>
+Description:   (R) MAC addresses burned into eFuses of this Turris Mox board.
+               Format: %pM
+
+What:          /sys/firmware/turris-mox-rwtm/pubkey
+Date:          August 2019
+KernelVersion: 5.4
+Contact:       Marek Behún <marek.behun@nic.cz>
+Description:   (R) ECDSA public key (in pubkey hex compressed form) computed
+               as pair to the ECDSA private key burned into eFuses of this
+               Turris Mox Board.
+               Format: string
+
+What:          /sys/firmware/turris-mox-rwtm/ram_size
+Date:          August 2019
+KernelVersion: 5.4
+Contact:       Marek Behún <marek.behun@nic.cz>
+Description:   (R) RAM size in MiB of this Turris Mox board as was detected
+               during manufacturing and burned into eFuses. Can be 512 or 1024.
+               Format: %i
+
+What:          /sys/firmware/turris-mox-rwtm/serial_number
+Date:          August 2019
+KernelVersion: 5.4
+Contact:       Marek Behún <marek.behun@nic.cz>
+Description:   (R) Serial number burned into eFuses of this Turris Mox device.
+               Format: %016X
index 317a2fc..083dbf9 100644 (file)
@@ -73,6 +73,16 @@ Required properties:
                         as used by the firmware. Refer to  platform details
                         for your implementation for the IDs to use.
 
+Reset signal bindings for the reset domains based on SCMI Message Protocol
+------------------------------------------------------------
+
+This binding for the SCMI reset domain providers uses the generic reset
+signal binding[5].
+
+Required properties:
+ - #reset-cells : Should be 1. Contains the reset domain ID value used
+                 by SCMI commands.
+
 SRAM and Shared Memory for SCMI
 -------------------------------
 
@@ -93,6 +103,7 @@ Required sub-node properties:
 [2] Documentation/devicetree/bindings/power/power_domain.txt
 [3] Documentation/devicetree/bindings/thermal/thermal.txt
 [4] Documentation/devicetree/bindings/sram/sram.txt
+[5] Documentation/devicetree/bindings/reset/reset.txt
 
 Example:
 
@@ -152,6 +163,11 @@ firmware {
                        reg = <0x15>;
                        #thermal-sensor-cells = <1>;
                };
+
+               scmi_reset: protocol@16 {
+                       reg = <0x16>;
+                       #reset-cells = <1>;
+               };
        };
 };
 
@@ -166,6 +182,7 @@ hdlcd@7ff60000 {
        reg = <0 0x7ff60000 0 0x1000>;
        clocks = <&scmi_clk 4>;
        power-domains = <&scmi_devpd 1>;
+       resets = <&scmi_reset 10>;
 };
 
 thermal-zones {
diff --git a/Documentation/devicetree/bindings/bus/moxtet.txt b/Documentation/devicetree/bindings/bus/moxtet.txt
new file mode 100644 (file)
index 0000000..fb50fc8
--- /dev/null
@@ -0,0 +1,46 @@
+Turris Mox module status and configuration bus (over SPI)
+
+Required properties:
+ - compatible          : Should be "cznic,moxtet"
+ - #address-cells      : Has to be 1
+ - #size-cells         : Has to be 0
+ - spi-cpol            : Required inverted clock polarity
+ - spi-cpha            : Required shifted clock phase
+ - interrupts          : Must contain reference to the shared interrupt line
+ - interrupt-controller        : Required
+ - #interrupt-cells    : Has to be 1
+
+For other required and optional properties of SPI slave nodes please refer to
+../spi/spi-bus.txt.
+
+Required properties of subnodes:
+ - reg                 : Should be position on the Moxtet bus (how many Moxtet
+                         modules are between this module and CPU module, so
+                         either 0 or a positive integer)
+
+The driver finds the devices connected to the bus by itself, but it may be
+needed to reference some of them from other parts of the device tree. In that
+case the devices can be defined as subnodes of the moxtet node.
+
+Example:
+
+       moxtet@1 {
+               compatible = "cznic,moxtet";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               reg = <1>;
+               spi-max-frequency = <10000000>;
+               spi-cpol;
+               spi-cpha;
+               interrupt-controller;
+               #interrupt-cells = <1>;
+               interrupt-parent = <&gpiosb>;
+               interrupts = <5 IRQ_TYPE_EDGE_FALLING>;
+
+               moxtet_sfp: gpio@0 {
+                       compatible = "cznic,moxtet-gpio";
+                       gpio-controller;
+                       #gpio-cells = <2>;
+                       reg = <0>;
+               }
+       };
diff --git a/Documentation/devicetree/bindings/firmware/cznic,turris-mox-rwtm.txt b/Documentation/devicetree/bindings/firmware/cznic,turris-mox-rwtm.txt
new file mode 100644 (file)
index 0000000..338169d
--- /dev/null
@@ -0,0 +1,19 @@
+Turris Mox rWTM firmware driver
+
+Required properties:
+ - compatible          : Should be "cznic,turris-mox-rwtm"
+ - mboxes              : Must contain a reference to associated mailbox
+
+This device tree node should be used on Turris Mox, or potentially another A3700
+compatible device running the Mox's rWTM firmware in the secure processor (for
+example it is possible to flash this firmware into EspressoBin).
+
+Example:
+
+       firmware {
+               turris-mox-rwtm {
+                       compatible = "cznic,turris-mox-rwtm";
+                       mboxes = <&rwtm 0>;
+                       status = "okay";
+               };
+       };
index 41f133a..3f29ea0 100644 (file)
@@ -9,14 +9,16 @@ Required properties:
 - compatible: must contain one of the following:
  * "qcom,scm-apq8064"
  * "qcom,scm-apq8084"
+ * "qcom,scm-ipq4019"
  * "qcom,scm-msm8660"
  * "qcom,scm-msm8916"
  * "qcom,scm-msm8960"
  * "qcom,scm-msm8974"
  * "qcom,scm-msm8996"
  * "qcom,scm-msm8998"
- * "qcom,scm-ipq4019"
+ * "qcom,scm-sc7180"
  * "qcom,scm-sdm845"
+ * "qcom,scm-sm8150"
  and:
  * "qcom,scm"
 - clocks: Specifies clocks needed by the SCM interface, if any:
diff --git a/Documentation/devicetree/bindings/gpio/gpio-moxtet.txt b/Documentation/devicetree/bindings/gpio/gpio-moxtet.txt
new file mode 100644 (file)
index 0000000..410759d
--- /dev/null
@@ -0,0 +1,18 @@
+Turris Mox Moxtet GPIO expander via Moxtet bus
+
+Required properties:
+ - compatible          : Should be "cznic,moxtet-gpio".
+ - gpio-controller     : Marks the device node as a GPIO controller.
+ - #gpio-cells         : Should be two. For consumer use see gpio.txt.
+
+Other properties are required for a Moxtet bus device, please refer to
+Documentation/devicetree/bindings/bus/moxtet.txt.
+
+Example:
+
+       moxtet_sfp: gpio@0 {
+               compatible = "cznic,moxtet-gpio";
+               gpio-controller;
+               #gpio-cells = <2>;
+               reg = <0>;
+       }
diff --git a/Documentation/devicetree/bindings/power/amlogic,meson-ee-pwrc.yaml b/Documentation/devicetree/bindings/power/amlogic,meson-ee-pwrc.yaml
new file mode 100644 (file)
index 0000000..aab70e8
--- /dev/null
@@ -0,0 +1,93 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright 2019 BayLibre, SAS
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/power/amlogic,meson-ee-pwrc.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Amlogic Meson Everything-Else Power Domains
+
+maintainers:
+  - Neil Armstrong <narmstrong@baylibre.com>
+
+description: |+
+  The Everything-Else Power Domains node should be the child of a syscon
+  node with the required property:
+
+  - compatible: Should be the following:
+                "amlogic,meson-gx-hhi-sysctrl", "simple-mfd", "syscon"
+
+  Refer to the the bindings described in
+  Documentation/devicetree/bindings/mfd/syscon.txt
+
+properties:
+  compatible:
+    enum:
+      - amlogic,meson-g12a-pwrc
+      - amlogic,meson-sm1-pwrc
+
+  clocks:
+    minItems: 2
+
+  clock-names:
+    items:
+      - const: vpu
+      - const: vapb
+
+  resets:
+    minItems: 11
+
+  reset-names:
+    items:
+      - const: viu
+      - const: venc
+      - const: vcbus
+      - const: bt656
+      - const: rdma
+      - const: venci
+      - const: vencp
+      - const: vdac
+      - const: vdi6
+      - const: vencl
+      - const: vid_lock
+
+  "#power-domain-cells":
+    const: 1
+
+  amlogic,ao-sysctrl:
+    description: phandle to the AO sysctrl node
+    allOf:
+      - $ref: /schemas/types.yaml#/definitions/phandle
+
+required:
+  - compatible
+  - clocks
+  - clock-names
+  - resets
+  - reset-names
+  - "#power-domain-cells"
+  - amlogic,ao-sysctrl
+
+examples:
+  - |
+    pwrc: power-controller {
+          compatible = "amlogic,meson-sm1-pwrc";
+          #power-domain-cells = <1>;
+          amlogic,ao-sysctrl = <&rti>;
+          resets = <&reset_viu>,
+                   <&reset_venc>,
+                   <&reset_vcbus>,
+                   <&reset_bt656>,
+                   <&reset_rdma>,
+                   <&reset_venci>,
+                   <&reset_vencp>,
+                   <&reset_vdac>,
+                   <&reset_vdi6>,
+                   <&reset_vencl>,
+                   <&reset_vid_lock>;
+          reset-names = "viu", "venc", "vcbus", "bt656",
+                        "rdma", "venci", "vencp", "vdac",
+                        "vdi6", "vencl", "vid_lock";
+          clocks = <&clk_vpu>, <&clk_vapb>;
+          clock-names = "vpu", "vapb";
+    };
index 13e0951..c2489e4 100644 (file)
@@ -8,6 +8,7 @@ Required properties:
 - compatible:
        - For i.MX7 SoCs should be "fsl,imx7d-src", "syscon"
        - For i.MX8MQ SoCs should be "fsl,imx8mq-src", "syscon"
+       - For i.MX8MM SoCs should be "fsl,imx8mm-src", "fsl,imx8mq-src", "syscon"
 - reg: should be register base and length as documented in the
   datasheet
 - interrupts: Should contain SRC interrupt
@@ -46,5 +47,6 @@ Example:
 
 
 For list of all valid reset indices see
-<dt-bindings/reset/imx7-reset.h> for i.MX7 and
-<dt-bindings/reset/imx8mq-reset.h> for i.MX8MQ
+<dt-bindings/reset/imx7-reset.h> for i.MX7,
+<dt-bindings/reset/imx8mq-reset.h> for i.MX8MQ and
+<dt-bindings/reset/imx8mq-reset.h> for i.MX8MM
diff --git a/Documentation/devicetree/bindings/reset/snps,dw-reset.txt b/Documentation/devicetree/bindings/reset/snps,dw-reset.txt
new file mode 100644 (file)
index 0000000..f94f911
--- /dev/null
@@ -0,0 +1,30 @@
+Synopsys DesignWare Reset controller
+=======================================
+
+Please also refer to reset.txt in this directory for common reset
+controller binding usage.
+
+Required properties:
+
+- compatible: should be one of the following.
+       "snps,dw-high-reset" - for active high configuration
+       "snps,dw-low-reset" - for active low configuration
+
+- reg: physical base address of the controller and length of memory mapped
+       region.
+
+- #reset-cells: must be 1.
+
+example:
+
+       dw_rst_1: reset-controller@0000 {
+               compatible = "snps,dw-high-reset";
+               reg = <0x0000 0x4>;
+               #reset-cells = <1>;
+       };
+
+       dw_rst_2: reset-controller@1000 {i
+               compatible = "snps,dw-low-reset";
+               reg = <0x1000 0x8>;
+               #reset-cells = <1>;
+       };
index 6bf6b43..3dd563c 100644 (file)
@@ -11,6 +11,7 @@ Required properties:
                        "amlogic,meson8b-clk-measure" for Meson8b SoCs
                        "amlogic,meson-axg-clk-measure" for AXG SoCs
                        "amlogic,meson-g12a-clk-measure" for G12a SoCs
+                       "amlogic,meson-sm1-clk-measure" for SM1 SoCs
 - reg: base address and size of the Clock Measurer register space.
 
 Example:
index d7afaff..05ec2a8 100644 (file)
@@ -18,7 +18,8 @@ Required properties:
 - reg : offset and length of the device registers.
 - bus-frequency : the clock frequency for QUICC Engine.
 - fsl,qe-num-riscs: define how many RISC engines the QE has.
-- fsl,qe-num-snums: define how many serial number(SNUM) the QE can use for the
+- fsl,qe-snums: This property has to be specified as '/bits/ 8' value,
+  defining the array of serial number (SNUM) values for the virtual
   threads.
 
 Optional properties:
@@ -34,6 +35,11 @@ Recommended properties
 - brg-frequency : the internal clock source frequency for baud-rate
   generators in Hz.
 
+Deprecated properties
+- fsl,qe-num-snums: define how many serial number(SNUM) the QE can use
+  for the threads. Use fsl,qe-snums instead to not only specify the
+  number of snums, but also their values.
+
 Example:
      qe@e0100000 {
        #address-cells = <1>;
@@ -44,6 +50,11 @@ Example:
        reg = <e0100000 480>;
        brg-frequency = <0>;
        bus-frequency = <179A7B00>;
+       fsl,qe-snums = /bits/ 8 <
+               0x04 0x05 0x0C 0x0D 0x14 0x15 0x1C 0x1D
+               0x24 0x25 0x2C 0x2D 0x34 0x35 0x88 0x89
+               0x98 0x99 0xA8 0xA9 0xB8 0xB9 0xC8 0xC9
+               0xD8 0xD9 0xE8 0xE9>;
      }
 
 * Multi-User RAM (MURAM)
index 954ffee..4fc571e 100644 (file)
@@ -15,7 +15,10 @@ power-domains.
 - compatible:
        Usage: required
        Value type: <string>
-       Definition: must be "qcom,sdm845-aoss-qmp"
+       Definition: must be one of:
+                   "qcom,sc7180-aoss-qmp"
+                   "qcom,sdm845-aoss-qmp"
+                   "qcom,sm8150-aoss-qmp"
 
 - reg:
        Usage: required
index f7b00a7..f541d1f 100644 (file)
@@ -19,8 +19,15 @@ child of the pmmc node.
 Required Properties:
 --------------------
 - compatible: should be "ti,sci-pm-domain"
-- #power-domain-cells: Must be 1 so that an id can be provided in each
-                      device node.
+- #power-domain-cells: Can be one of the following:
+                       1: Containing the device id of each node
+                       2: First entry should be device id
+                          Second entry should be one of the floowing:
+                          TI_SCI_PD_EXCLUSIVE: To allow device to be
+                                               exclusively controlled by
+                                               the requesting hosts.
+                          TI_SCI_PD_SHARED: To allow device to be shared
+                                            by multiple hosts.
 
 Example (K2G):
 -------------
index 1dc4955..5be81cd 100644 (file)
@@ -1617,6 +1617,21 @@ F:       drivers/clocksource/timer-atlas7.c
 N:     [^a-z]sirf
 X:     drivers/gnss
 
+ARM/CZ.NIC TURRIS MOX SUPPORT
+M:     Marek Behun <marek.behun@nic.cz>
+W:     http://mox.turris.cz
+S:     Maintained
+F:     Documentation/ABI/testing/debugfs-moxtet
+F:     Documentation/ABI/testing/sysfs-bus-moxtet-devices
+F:     Documentation/ABI/testing/sysfs-firmware-turris-mox-rwtm
+F:     Documentation/devicetree/bindings/bus/moxtet.txt
+F:     Documentation/devicetree/bindings/firmware/cznic,turris-mox-rwtm.txt
+F:     Documentation/devicetree/bindings/gpio/gpio-moxtet.txt
+F:     include/linux/moxtet.h
+F:     drivers/bus/moxtet.c
+F:     drivers/firmware/turris-mox-rwtm.c
+F:     drivers/gpio/gpio-moxtet.c
+
 ARM/EBSA110 MACHINE SUPPORT
 M:     Russell King <linux@armlinux.org.uk>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -15530,6 +15545,7 @@ F:      drivers/clk/clk-sc[mp]i.c
 F:     drivers/cpufreq/sc[mp]i-cpufreq.c
 F:     drivers/firmware/arm_scpi.c
 F:     drivers/firmware/arm_scmi/
+F:     drivers/reset/reset-scmi.c
 F:     include/linux/sc[mp]i_protocol.h
 
 SYSTEM RESET/SHUTDOWN DRIVERS
@@ -15838,6 +15854,7 @@ F:      drivers/firmware/ti_sci*
 F:     include/linux/soc/ti/ti_sci_protocol.h
 F:     Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt
 F:     drivers/soc/ti/ti_sci_pm_domains.c
+F:     include/dt-bindings/soc/ti,sci_pm_domain.h
 F:     Documentation/devicetree/bindings/reset/ti,sci-reset.txt
 F:     Documentation/devicetree/bindings/clock/ti,sci-clk.txt
 F:     drivers/clk/keystone/sci-clk.c
index 60130bd..6edb961 100644 (file)
@@ -8,7 +8,7 @@
  */
 
 #include <linux/device.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/platform_device.h>
index 0628e7d..5b3549f 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/platform_data/ti-aemif.h>
 #include <linux/platform_data/spi-davinci.h>
 #include <linux/platform_data/uio_pruss.h>
+#include <linux/property.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/tps6507x.h>
 #include <linux/regulator/fixed.h>
@@ -802,37 +803,79 @@ static const short da850_evm_mmcsd0_pins[] __initconst = {
        -1
 };
 
-static void da850_panel_power_ctrl(int val)
-{
-       /* lcd backlight */
-       gpio_set_value(DA850_LCD_BL_PIN, val);
+static struct property_entry da850_lcd_backlight_props[] = {
+       PROPERTY_ENTRY_BOOL("default-on"),
+       { }
+};
 
-       /* lcd power */
-       gpio_set_value(DA850_LCD_PWR_PIN, val);
-}
+static struct gpiod_lookup_table da850_lcd_backlight_gpio_table = {
+       .dev_id         = "gpio-backlight",
+       .table = {
+               GPIO_LOOKUP("davinci_gpio", DA850_LCD_BL_PIN, NULL, 0),
+               { }
+       },
+};
+
+static const struct platform_device_info da850_lcd_backlight_info = {
+       .name           = "gpio-backlight",
+       .id             = PLATFORM_DEVID_NONE,
+       .properties     = da850_lcd_backlight_props,
+};
+
+static struct regulator_consumer_supply da850_lcd_supplies[] = {
+       REGULATOR_SUPPLY("lcd", NULL),
+};
+
+static struct regulator_init_data da850_lcd_supply_data = {
+       .consumer_supplies      = da850_lcd_supplies,
+       .num_consumer_supplies  = ARRAY_SIZE(da850_lcd_supplies),
+       .constraints    = {
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+       },
+};
+
+static struct fixed_voltage_config da850_lcd_supply = {
+       .supply_name            = "lcd",
+       .microvolts             = 33000000,
+       .init_data              = &da850_lcd_supply_data,
+};
+
+static struct platform_device da850_lcd_supply_device = {
+       .name                   = "reg-fixed-voltage",
+       .id                     = 1, /* Dummy fixed regulator is 0 */
+       .dev                    = {
+               .platform_data = &da850_lcd_supply,
+       },
+};
+
+static struct gpiod_lookup_table da850_lcd_supply_gpio_table = {
+       .dev_id                 = "reg-fixed-voltage.1",
+       .table = {
+               GPIO_LOOKUP("davinci_gpio", DA850_LCD_PWR_PIN, NULL, 0),
+               { }
+       },
+};
+
+static struct gpiod_lookup_table *da850_lcd_gpio_lookups[] = {
+       &da850_lcd_backlight_gpio_table,
+       &da850_lcd_supply_gpio_table,
+};
 
 static int da850_lcd_hw_init(void)
 {
+       struct platform_device *backlight;
        int status;
 
-       status = gpio_request(DA850_LCD_BL_PIN, "lcd bl");
-       if (status < 0)
-               return status;
-
-       status = gpio_request(DA850_LCD_PWR_PIN, "lcd pwr");
-       if (status < 0) {
-               gpio_free(DA850_LCD_BL_PIN);
-               return status;
-       }
+       gpiod_add_lookup_tables(da850_lcd_gpio_lookups,
+                               ARRAY_SIZE(da850_lcd_gpio_lookups));
 
-       gpio_direction_output(DA850_LCD_BL_PIN, 0);
-       gpio_direction_output(DA850_LCD_PWR_PIN, 0);
+       backlight = platform_device_register_full(&da850_lcd_backlight_info);
+       if (IS_ERR(backlight))
+               return PTR_ERR(backlight);
 
-       /* Switch off panel power and backlight */
-       da850_panel_power_ctrl(0);
-
-       /* Switch on panel power and backlight */
-       da850_panel_power_ctrl(1);
+       status = platform_device_register(&da850_lcd_supply_device);
+       if (status)
+               return status;
 
        return 0;
 }
@@ -1443,7 +1486,6 @@ static __init void da850_evm_init(void)
        if (ret)
                pr_warn("%s: LCD initialization failed: %d\n", __func__, ret);
 
-       sharp_lk043t1dg01_pdata.panel_power_ctrl = da850_panel_power_ctrl,
        ret = da8xx_register_lcdc(&sharp_lk043t1dg01_pdata);
        if (ret)
                pr_warn("%s: LCDC registration failed: %d\n", __func__, ret);
index 10b280f..7c0c5ca 100644 (file)
@@ -33,6 +33,7 @@ static struct bus_type soc_bus_type = {
 
 static DEVICE_ATTR(machine,  S_IRUGO, soc_info_get,  NULL);
 static DEVICE_ATTR(family,   S_IRUGO, soc_info_get,  NULL);
+static DEVICE_ATTR(serial_number, S_IRUGO, soc_info_get,  NULL);
 static DEVICE_ATTR(soc_id,   S_IRUGO, soc_info_get,  NULL);
 static DEVICE_ATTR(revision, S_IRUGO, soc_info_get,  NULL);
 
@@ -57,6 +58,9 @@ static umode_t soc_attribute_mode(struct kobject *kobj,
        if ((attr == &dev_attr_revision.attr)
            && (soc_dev->attr->revision != NULL))
                return attr->mode;
+       if ((attr == &dev_attr_serial_number.attr)
+           && (soc_dev->attr->serial_number != NULL))
+               return attr->mode;
        if ((attr == &dev_attr_soc_id.attr)
            && (soc_dev->attr->soc_id != NULL))
                return attr->mode;
@@ -77,6 +81,8 @@ static ssize_t soc_info_get(struct device *dev,
                return sprintf(buf, "%s\n", soc_dev->attr->family);
        if (attr == &dev_attr_revision)
                return sprintf(buf, "%s\n", soc_dev->attr->revision);
+       if (attr == &dev_attr_serial_number)
+               return sprintf(buf, "%s\n", soc_dev->attr->serial_number);
        if (attr == &dev_attr_soc_id)
                return sprintf(buf, "%s\n", soc_dev->attr->soc_id);
 
@@ -87,6 +93,7 @@ static ssize_t soc_info_get(struct device *dev,
 static struct attribute *soc_attr[] = {
        &dev_attr_machine.attr,
        &dev_attr_family.attr,
+       &dev_attr_serial_number.attr,
        &dev_attr_soc_id.attr,
        &dev_attr_revision.attr,
        NULL,
@@ -157,6 +164,7 @@ out2:
 out1:
        return ERR_PTR(ret);
 }
+EXPORT_SYMBOL_GPL(soc_device_register);
 
 /* Ensure soc_dev->attr is freed prior to calling soc_device_unregister. */
 void soc_device_unregister(struct soc_device *soc_dev)
@@ -166,6 +174,7 @@ void soc_device_unregister(struct soc_device *soc_dev)
        device_unregister(&soc_dev->dev);
        early_soc_dev_attr = NULL;
 }
+EXPORT_SYMBOL_GPL(soc_device_unregister);
 
 static int __init soc_bus_register(void)
 {
index 1851112..6b33106 100644 (file)
@@ -29,6 +29,16 @@ config BRCMSTB_GISB_ARB
          arbiter. This driver provides timeout and target abort error handling
          and internal bus master decoding.
 
+config MOXTET
+       tristate "CZ.NIC Turris Mox module configuration bus"
+       depends on SPI_MASTER && OF
+       help
+         Say yes here to add support for the module configuration bus found
+         on CZ.NIC's Turris Mox. This is needed for the ability to discover
+         the order in which the modules are connected and to get/set some of
+         their settings. For example the GPIOs on Mox SFP module are
+         configured through this bus.
+
 config HISILICON_LPC
        bool "Support for ISA I/O space on HiSilicon Hip06/7"
        depends on ARM64 && (ARCH_HISI || COMPILE_TEST)
index ca300b1..16b43d3 100644 (file)
@@ -8,6 +8,7 @@ obj-$(CONFIG_ARM_CCI)           += arm-cci.o
 
 obj-$(CONFIG_HISILICON_LPC)    += hisi_lpc.o
 obj-$(CONFIG_BRCMSTB_GISB_ARB) += brcmstb_gisb.o
+obj-$(CONFIG_MOXTET)           += moxtet.o
 
 # DPAA2 fsl-mc bus
 obj-$(CONFIG_FSL_MC_BUS)       += fsl-mc/
index 8ad7724..cc7bb90 100644 (file)
@@ -330,7 +330,6 @@ void fsl_mc_object_free(struct fsl_mc_device *mc_adev)
 
        fsl_mc_resource_free(resource);
 
-       device_link_del(mc_adev->consumer_link);
        mc_adev->consumer_link = NULL;
 }
 EXPORT_SYMBOL_GPL(fsl_mc_object_free);
index 3ae574a..d9629fc 100644 (file)
@@ -255,7 +255,6 @@ void fsl_mc_portal_free(struct fsl_mc_io *mc_io)
        fsl_destroy_mc_io(mc_io);
        fsl_mc_resource_free(resource);
 
-       device_link_del(dpmcp_dev->consumer_link);
        dpmcp_dev->consumer_link = NULL;
 }
 EXPORT_SYMBOL_GPL(fsl_mc_portal_free);
index db74334..28bb65a 100644 (file)
@@ -19,6 +19,8 @@ struct imx_weim_devtype {
        unsigned int    cs_count;
        unsigned int    cs_regs_count;
        unsigned int    cs_stride;
+       unsigned int    wcr_offset;
+       unsigned int    wcr_bcm;
 };
 
 static const struct imx_weim_devtype imx1_weim_devtype = {
@@ -37,6 +39,8 @@ static const struct imx_weim_devtype imx50_weim_devtype = {
        .cs_count       = 4,
        .cs_regs_count  = 6,
        .cs_stride      = 0x18,
+       .wcr_offset     = 0x90,
+       .wcr_bcm        = BIT(0),
 };
 
 static const struct imx_weim_devtype imx51_weim_devtype = {
@@ -72,7 +76,7 @@ static const struct of_device_id weim_id_table[] = {
 };
 MODULE_DEVICE_TABLE(of, weim_id_table);
 
-static int __init imx_weim_gpr_setup(struct platform_device *pdev)
+static int imx_weim_gpr_setup(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
        struct property *prop;
@@ -122,10 +126,10 @@ err:
 }
 
 /* Parse and set the timing for this device. */
-static int __init weim_timing_setup(struct device *dev,
-                                   struct device_node *np, void __iomem *base,
-                                   const struct imx_weim_devtype *devtype,
-                                   struct cs_timing_state *ts)
+static int weim_timing_setup(struct device *dev,
+                            struct device_node *np, void __iomem *base,
+                            const struct imx_weim_devtype *devtype,
+                            struct cs_timing_state *ts)
 {
        u32 cs_idx, value[MAX_CS_REGS_COUNT];
        int i, ret;
@@ -183,8 +187,7 @@ static int __init weim_timing_setup(struct device *dev,
        return 0;
 }
 
-static int __init weim_parse_dt(struct platform_device *pdev,
-                               void __iomem *base)
+static int weim_parse_dt(struct platform_device *pdev, void __iomem *base)
 {
        const struct of_device_id *of_id = of_match_device(weim_id_table,
                                                           &pdev->dev);
@@ -192,6 +195,7 @@ static int __init weim_parse_dt(struct platform_device *pdev,
        struct device_node *child;
        int ret, have_child = 0;
        struct cs_timing_state ts = {};
+       u32 reg;
 
        if (devtype == &imx50_weim_devtype) {
                ret = imx_weim_gpr_setup(pdev);
@@ -199,6 +203,17 @@ static int __init weim_parse_dt(struct platform_device *pdev,
                        return ret;
        }
 
+       if (of_property_read_bool(pdev->dev.of_node, "fsl,burst-clk-enable")) {
+               if (devtype->wcr_bcm) {
+                       reg = readl(base + devtype->wcr_offset);
+                       writel(reg | devtype->wcr_bcm,
+                               base + devtype->wcr_offset);
+               } else {
+                       dev_err(&pdev->dev, "burst clk mode not supported.\n");
+                       return -EINVAL;
+               }
+       }
+
        for_each_available_child_of_node(pdev->dev.of_node, child) {
                ret = weim_timing_setup(&pdev->dev, child, base, devtype, &ts);
                if (ret)
@@ -217,7 +232,7 @@ static int __init weim_parse_dt(struct platform_device *pdev,
        return ret;
 }
 
-static int __init weim_probe(struct platform_device *pdev)
+static int weim_probe(struct platform_device *pdev)
 {
        struct resource *res;
        struct clk *clk;
@@ -254,8 +269,9 @@ static struct platform_driver weim_driver = {
                .name           = "imx-weim",
                .of_match_table = weim_id_table,
        },
+       .probe = weim_probe,
 };
-module_platform_driver_probe(weim_driver, weim_probe);
+module_platform_driver(weim_driver);
 
 MODULE_AUTHOR("Freescale Semiconductor Inc.");
 MODULE_DESCRIPTION("i.MX EIM Controller Driver");
diff --git a/drivers/bus/moxtet.c b/drivers/bus/moxtet.c
new file mode 100644 (file)
index 0000000..36cf13e
--- /dev/null
@@ -0,0 +1,885 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Turris Mox module configuration bus driver
+ *
+ * Copyright (C) 2019 Marek Behun <marek.behun@nic.cz>
+ */
+
+#include <dt-bindings/bus/moxtet.h>
+#include <linux/bitops.h>
+#include <linux/debugfs.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/moxtet.h>
+#include <linux/mutex.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/spi/spi.h>
+
+/*
+ * @name:      module name for sysfs
+ * @hwirq_base:        base index for IRQ for this module (-1 if no IRQs)
+ * @nirqs:     how many interrupts does the shift register provide
+ * @desc:      module description for kernel log
+ */
+static const struct {
+       const char *name;
+       int hwirq_base;
+       int nirqs;
+       const char *desc;
+} mox_module_table[] = {
+       /* do not change order of this array! */
+       { NULL,          0,                     0, NULL },
+       { "sfp",        -1,                     0, "MOX D (SFP cage)" },
+       { "pci",        MOXTET_IRQ_PCI,         1, "MOX B (Mini-PCIe)" },
+       { "topaz",      MOXTET_IRQ_TOPAZ,       1, "MOX C (4 port switch)" },
+       { "peridot",    MOXTET_IRQ_PERIDOT(0),  1, "MOX E (8 port switch)" },
+       { "usb3",       MOXTET_IRQ_USB3,        2, "MOX F (USB 3.0)" },
+       { "pci-bridge", -1,                     0, "MOX G (Mini-PCIe bridge)" },
+};
+
+static inline bool mox_module_known(unsigned int id)
+{
+       return id >= TURRIS_MOX_MODULE_FIRST && id <= TURRIS_MOX_MODULE_LAST;
+}
+
+static inline const char *mox_module_name(unsigned int id)
+{
+       if (mox_module_known(id))
+               return mox_module_table[id].name;
+       else
+               return "unknown";
+}
+
+#define DEF_MODULE_ATTR(name, fmt, ...)                                        \
+static ssize_t                                                         \
+module_##name##_show(struct device *dev, struct device_attribute *a,   \
+                    char *buf)                                         \
+{                                                                      \
+       struct moxtet_device *mdev = to_moxtet_device(dev);             \
+       return sprintf(buf, (fmt), __VA_ARGS__);                        \
+}                                                                      \
+static DEVICE_ATTR_RO(module_##name)
+
+DEF_MODULE_ATTR(id, "0x%x\n", mdev->id);
+DEF_MODULE_ATTR(name, "%s\n", mox_module_name(mdev->id));
+DEF_MODULE_ATTR(description, "%s\n",
+               mox_module_known(mdev->id) ? mox_module_table[mdev->id].desc
+                                          : "");
+
+static struct attribute *moxtet_dev_attrs[] = {
+       &dev_attr_module_id.attr,
+       &dev_attr_module_name.attr,
+       &dev_attr_module_description.attr,
+       NULL,
+};
+
+static const struct attribute_group moxtet_dev_group = {
+       .attrs = moxtet_dev_attrs,
+};
+
+static const struct attribute_group *moxtet_dev_groups[] = {
+       &moxtet_dev_group,
+       NULL,
+};
+
+static int moxtet_match(struct device *dev, struct device_driver *drv)
+{
+       struct moxtet_device *mdev = to_moxtet_device(dev);
+       struct moxtet_driver *tdrv = to_moxtet_driver(drv);
+       const enum turris_mox_module_id *t;
+
+       if (of_driver_match_device(dev, drv))
+               return 1;
+
+       if (!tdrv->id_table)
+               return 0;
+
+       for (t = tdrv->id_table; *t; ++t)
+               if (*t == mdev->id)
+                       return 1;
+
+       return 0;
+}
+
+struct bus_type moxtet_bus_type = {
+       .name           = "moxtet",
+       .dev_groups     = moxtet_dev_groups,
+       .match          = moxtet_match,
+};
+EXPORT_SYMBOL_GPL(moxtet_bus_type);
+
+int __moxtet_register_driver(struct module *owner,
+                            struct moxtet_driver *mdrv)
+{
+       mdrv->driver.owner = owner;
+       mdrv->driver.bus = &moxtet_bus_type;
+       return driver_register(&mdrv->driver);
+}
+EXPORT_SYMBOL_GPL(__moxtet_register_driver);
+
+static int moxtet_dev_check(struct device *dev, void *data)
+{
+       struct moxtet_device *mdev = to_moxtet_device(dev);
+       struct moxtet_device *new_dev = data;
+
+       if (mdev->moxtet == new_dev->moxtet && mdev->id == new_dev->id &&
+           mdev->idx == new_dev->idx)
+               return -EBUSY;
+       return 0;
+}
+
+static void moxtet_dev_release(struct device *dev)
+{
+       struct moxtet_device *mdev = to_moxtet_device(dev);
+
+       put_device(mdev->moxtet->dev);
+       kfree(mdev);
+}
+
+static struct moxtet_device *
+moxtet_alloc_device(struct moxtet *moxtet)
+{
+       struct moxtet_device *dev;
+
+       if (!get_device(moxtet->dev))
+               return NULL;
+
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev) {
+               put_device(moxtet->dev);
+               return NULL;
+       }
+
+       dev->moxtet = moxtet;
+       dev->dev.parent = moxtet->dev;
+       dev->dev.bus = &moxtet_bus_type;
+       dev->dev.release = moxtet_dev_release;
+
+       device_initialize(&dev->dev);
+
+       return dev;
+}
+
+static int moxtet_add_device(struct moxtet_device *dev)
+{
+       static DEFINE_MUTEX(add_mutex);
+       int ret;
+
+       if (dev->idx >= TURRIS_MOX_MAX_MODULES || dev->id > 0xf)
+               return -EINVAL;
+
+       dev_set_name(&dev->dev, "moxtet-%s.%u", mox_module_name(dev->id),
+                    dev->idx);
+
+       mutex_lock(&add_mutex);
+
+       ret = bus_for_each_dev(&moxtet_bus_type, NULL, dev,
+                              moxtet_dev_check);
+       if (ret)
+               goto done;
+
+       ret = device_add(&dev->dev);
+       if (ret < 0)
+               dev_err(dev->moxtet->dev, "can't add %s, status %d\n",
+                       dev_name(dev->moxtet->dev), ret);
+
+done:
+       mutex_unlock(&add_mutex);
+       return ret;
+}
+
+static int __unregister(struct device *dev, void *null)
+{
+       if (dev->of_node) {
+               of_node_clear_flag(dev->of_node, OF_POPULATED);
+               of_node_put(dev->of_node);
+       }
+
+       device_unregister(dev);
+
+       return 0;
+}
+
+static struct moxtet_device *
+of_register_moxtet_device(struct moxtet *moxtet, struct device_node *nc)
+{
+       struct moxtet_device *dev;
+       u32 val;
+       int ret;
+
+       dev = moxtet_alloc_device(moxtet);
+       if (!dev) {
+               dev_err(moxtet->dev,
+                       "Moxtet device alloc error for %pOF\n", nc);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       ret = of_property_read_u32(nc, "reg", &val);
+       if (ret) {
+               dev_err(moxtet->dev, "%pOF has no valid 'reg' property (%d)\n",
+                       nc, ret);
+               goto err_put;
+       }
+
+       dev->idx = val;
+
+       if (dev->idx >= TURRIS_MOX_MAX_MODULES) {
+               dev_err(moxtet->dev, "%pOF Moxtet address 0x%x out of range\n",
+                       nc, dev->idx);
+               ret = -EINVAL;
+               goto err_put;
+       }
+
+       dev->id = moxtet->modules[dev->idx];
+
+       if (!dev->id) {
+               dev_err(moxtet->dev, "%pOF Moxtet address 0x%x is empty\n", nc,
+                       dev->idx);
+               ret = -ENODEV;
+               goto err_put;
+       }
+
+       of_node_get(nc);
+       dev->dev.of_node = nc;
+
+       ret = moxtet_add_device(dev);
+       if (ret) {
+               dev_err(moxtet->dev,
+                       "Moxtet device register error for %pOF\n", nc);
+               of_node_put(nc);
+               goto err_put;
+       }
+
+       return dev;
+
+err_put:
+       put_device(&dev->dev);
+       return ERR_PTR(ret);
+}
+
+static void of_register_moxtet_devices(struct moxtet *moxtet)
+{
+       struct moxtet_device *dev;
+       struct device_node *nc;
+
+       if (!moxtet->dev->of_node)
+               return;
+
+       for_each_available_child_of_node(moxtet->dev->of_node, nc) {
+               if (of_node_test_and_set_flag(nc, OF_POPULATED))
+                       continue;
+               dev = of_register_moxtet_device(moxtet, nc);
+               if (IS_ERR(dev)) {
+                       dev_warn(moxtet->dev,
+                                "Failed to create Moxtet device for %pOF\n",
+                                nc);
+                       of_node_clear_flag(nc, OF_POPULATED);
+               }
+       }
+}
+
+static void
+moxtet_register_devices_from_topology(struct moxtet *moxtet)
+{
+       struct moxtet_device *dev;
+       int i, ret;
+
+       for (i = 0; i < moxtet->count; ++i) {
+               dev = moxtet_alloc_device(moxtet);
+               if (!dev) {
+                       dev_err(moxtet->dev, "Moxtet device %u alloc error\n",
+                               i);
+                       continue;
+               }
+
+               dev->idx = i;
+               dev->id = moxtet->modules[i];
+
+               ret = moxtet_add_device(dev);
+               if (ret && ret != -EBUSY) {
+                       put_device(&dev->dev);
+                       dev_err(moxtet->dev,
+                               "Moxtet device %u register error: %i\n", i,
+                               ret);
+               }
+       }
+}
+
+/*
+ * @nsame:     how many modules with same id are already in moxtet->modules
+ */
+static int moxtet_set_irq(struct moxtet *moxtet, int idx, int id, int nsame)
+{
+       int i, first;
+       struct moxtet_irqpos *pos;
+
+       first = mox_module_table[id].hwirq_base +
+               nsame * mox_module_table[id].nirqs;
+
+       if (first + mox_module_table[id].nirqs > MOXTET_NIRQS)
+               return -EINVAL;
+
+       for (i = 0; i < mox_module_table[id].nirqs; ++i) {
+               pos = &moxtet->irq.position[first + i];
+               pos->idx = idx;
+               pos->bit = i;
+               moxtet->irq.exists |= BIT(first + i);
+       }
+
+       return 0;
+}
+
+static int moxtet_find_topology(struct moxtet *moxtet)
+{
+       u8 buf[TURRIS_MOX_MAX_MODULES];
+       int cnts[TURRIS_MOX_MODULE_LAST];
+       int i, ret;
+
+       memset(cnts, 0, sizeof(cnts));
+
+       ret = spi_read(to_spi_device(moxtet->dev), buf, TURRIS_MOX_MAX_MODULES);
+       if (ret < 0)
+               return ret;
+
+       if (buf[0] == TURRIS_MOX_CPU_ID_EMMC) {
+               dev_info(moxtet->dev, "Found MOX A (eMMC CPU) module\n");
+       } else if (buf[0] == TURRIS_MOX_CPU_ID_SD) {
+               dev_info(moxtet->dev, "Found MOX A (CPU) module\n");
+       } else {
+               dev_err(moxtet->dev, "Invalid Turris MOX A CPU module 0x%02x\n",
+                       buf[0]);
+               return -ENODEV;
+       }
+
+       moxtet->count = 0;
+
+       for (i = 1; i < TURRIS_MOX_MAX_MODULES; ++i) {
+               int id;
+
+               if (buf[i] == 0xff)
+                       break;
+
+               id = buf[i] & 0xf;
+
+               moxtet->modules[i-1] = id;
+               ++moxtet->count;
+
+               if (mox_module_known(id)) {
+                       dev_info(moxtet->dev, "Found %s module\n",
+                                mox_module_table[id].desc);
+
+                       if (moxtet_set_irq(moxtet, i-1, id, cnts[id]++) < 0)
+                               dev_err(moxtet->dev,
+                                       "  Cannot set IRQ for module %s\n",
+                                       mox_module_table[id].desc);
+               } else {
+                       dev_warn(moxtet->dev,
+                                "Unknown Moxtet module found (ID 0x%02x)\n",
+                                id);
+               }
+       }
+
+       return 0;
+}
+
+static int moxtet_spi_read(struct moxtet *moxtet, u8 *buf)
+{
+       struct spi_transfer xfer = {
+               .rx_buf = buf,
+               .tx_buf = moxtet->tx,
+               .len = moxtet->count + 1
+       };
+       int ret;
+
+       mutex_lock(&moxtet->lock);
+
+       ret = spi_sync_transfer(to_spi_device(moxtet->dev), &xfer, 1);
+
+       mutex_unlock(&moxtet->lock);
+
+       return ret;
+}
+
+int moxtet_device_read(struct device *dev)
+{
+       struct moxtet_device *mdev = to_moxtet_device(dev);
+       struct moxtet *moxtet = mdev->moxtet;
+       u8 buf[TURRIS_MOX_MAX_MODULES];
+       int ret;
+
+       if (mdev->idx >= moxtet->count)
+               return -EINVAL;
+
+       ret = moxtet_spi_read(moxtet, buf);
+       if (ret < 0)
+               return ret;
+
+       return buf[mdev->idx + 1] >> 4;
+}
+EXPORT_SYMBOL_GPL(moxtet_device_read);
+
+int moxtet_device_write(struct device *dev, u8 val)
+{
+       struct moxtet_device *mdev = to_moxtet_device(dev);
+       struct moxtet *moxtet = mdev->moxtet;
+       int ret;
+
+       if (mdev->idx >= moxtet->count)
+               return -EINVAL;
+
+       mutex_lock(&moxtet->lock);
+
+       moxtet->tx[moxtet->count - mdev->idx] = val;
+
+       ret = spi_write(to_spi_device(moxtet->dev), moxtet->tx,
+                       moxtet->count + 1);
+
+       mutex_unlock(&moxtet->lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(moxtet_device_write);
+
+int moxtet_device_written(struct device *dev)
+{
+       struct moxtet_device *mdev = to_moxtet_device(dev);
+       struct moxtet *moxtet = mdev->moxtet;
+
+       if (mdev->idx >= moxtet->count)
+               return -EINVAL;
+
+       return moxtet->tx[moxtet->count - mdev->idx];
+}
+EXPORT_SYMBOL_GPL(moxtet_device_written);
+
+#ifdef CONFIG_DEBUG_FS
+static int moxtet_debug_open(struct inode *inode, struct file *file)
+{
+       file->private_data = inode->i_private;
+
+       return nonseekable_open(inode, file);
+}
+
+static ssize_t input_read(struct file *file, char __user *buf, size_t len,
+                         loff_t *ppos)
+{
+       struct moxtet *moxtet = file->private_data;
+       u8 bin[TURRIS_MOX_MAX_MODULES];
+       u8 hex[sizeof(buf) * 2 + 1];
+       int ret, n;
+
+       ret = moxtet_spi_read(moxtet, bin);
+       if (ret < 0)
+               return ret;
+
+       n = moxtet->count + 1;
+       bin2hex(hex, bin, n);
+
+       hex[2*n] = '\n';
+
+       return simple_read_from_buffer(buf, len, ppos, hex, 2*n + 1);
+}
+
+static const struct file_operations input_fops = {
+       .owner  = THIS_MODULE,
+       .open   = moxtet_debug_open,
+       .read   = input_read,
+       .llseek = no_llseek,
+};
+
+static ssize_t output_read(struct file *file, char __user *buf, size_t len,
+                          loff_t *ppos)
+{
+       struct moxtet *moxtet = file->private_data;
+       u8 hex[TURRIS_MOX_MAX_MODULES * 2 + 1];
+       u8 *p = hex;
+       int i;
+
+       mutex_lock(&moxtet->lock);
+
+       for (i = 0; i < moxtet->count; ++i)
+               p = hex_byte_pack(p, moxtet->tx[moxtet->count - i]);
+
+       mutex_unlock(&moxtet->lock);
+
+       *p++ = '\n';
+
+       return simple_read_from_buffer(buf, len, ppos, hex, p - hex);
+}
+
+static ssize_t output_write(struct file *file, const char __user *buf,
+                           size_t len, loff_t *ppos)
+{
+       struct moxtet *moxtet = file->private_data;
+       u8 bin[TURRIS_MOX_MAX_MODULES];
+       u8 hex[sizeof(bin) * 2 + 1];
+       ssize_t res;
+       loff_t dummy = 0;
+       int err, i;
+
+       if (len > 2 * moxtet->count + 1 || len < 2 * moxtet->count)
+               return -EINVAL;
+
+       res = simple_write_to_buffer(hex, sizeof(hex), &dummy, buf, len);
+       if (res < 0)
+               return res;
+
+       if (len % 2 == 1 && hex[len - 1] != '\n')
+               return -EINVAL;
+
+       err = hex2bin(bin, hex, moxtet->count);
+       if (err < 0)
+               return -EINVAL;
+
+       mutex_lock(&moxtet->lock);
+
+       for (i = 0; i < moxtet->count; ++i)
+               moxtet->tx[moxtet->count - i] = bin[i];
+
+       err = spi_write(to_spi_device(moxtet->dev), moxtet->tx,
+                       moxtet->count + 1);
+
+       mutex_unlock(&moxtet->lock);
+
+       return err < 0 ? err : len;
+}
+
+static const struct file_operations output_fops = {
+       .owner  = THIS_MODULE,
+       .open   = moxtet_debug_open,
+       .read   = output_read,
+       .write  = output_write,
+       .llseek = no_llseek,
+};
+
+static int moxtet_register_debugfs(struct moxtet *moxtet)
+{
+       struct dentry *root, *entry;
+
+       root = debugfs_create_dir("moxtet", NULL);
+
+       if (IS_ERR(root))
+               return PTR_ERR(root);
+
+       entry = debugfs_create_file_unsafe("input", 0444, root, moxtet,
+                                          &input_fops);
+       if (IS_ERR(entry))
+               goto err_remove;
+
+       entry = debugfs_create_file_unsafe("output", 0644, root, moxtet,
+                                          &output_fops);
+       if (IS_ERR(entry))
+               goto err_remove;
+
+       moxtet->debugfs_root = root;
+
+       return 0;
+err_remove:
+       debugfs_remove_recursive(root);
+       return PTR_ERR(entry);
+}
+
+static void moxtet_unregister_debugfs(struct moxtet *moxtet)
+{
+       debugfs_remove_recursive(moxtet->debugfs_root);
+}
+#else
+static inline int moxtet_register_debugfs(struct moxtet *moxtet)
+{
+       return 0;
+}
+
+static inline void moxtet_unregister_debugfs(struct moxtet *moxtet)
+{
+}
+#endif
+
+static int moxtet_irq_domain_map(struct irq_domain *d, unsigned int irq,
+                                irq_hw_number_t hw)
+{
+       struct moxtet *moxtet = d->host_data;
+
+       if (hw >= MOXTET_NIRQS || !(moxtet->irq.exists & BIT(hw))) {
+               dev_err(moxtet->dev, "Invalid hw irq number\n");
+               return -EINVAL;
+       }
+
+       irq_set_chip_data(irq, d->host_data);
+       irq_set_chip_and_handler(irq, &moxtet->irq.chip, handle_level_irq);
+
+       return 0;
+}
+
+static int moxtet_irq_domain_xlate(struct irq_domain *d,
+                                  struct device_node *ctrlr,
+                                  const u32 *intspec, unsigned int intsize,
+                                  unsigned long *out_hwirq,
+                                  unsigned int *out_type)
+{
+       struct moxtet *moxtet = d->host_data;
+       int irq;
+
+       if (WARN_ON(intsize < 1))
+               return -EINVAL;
+
+       irq = intspec[0];
+
+       if (irq >= MOXTET_NIRQS || !(moxtet->irq.exists & BIT(irq)))
+               return -EINVAL;
+
+       *out_hwirq = irq;
+       *out_type = IRQ_TYPE_NONE;
+       return 0;
+}
+
+static const struct irq_domain_ops moxtet_irq_domain = {
+       .map = moxtet_irq_domain_map,
+       .xlate = moxtet_irq_domain_xlate,
+};
+
+static void moxtet_irq_mask(struct irq_data *d)
+{
+       struct moxtet *moxtet = irq_data_get_irq_chip_data(d);
+
+       moxtet->irq.masked |= BIT(d->hwirq);
+}
+
+static void moxtet_irq_unmask(struct irq_data *d)
+{
+       struct moxtet *moxtet = irq_data_get_irq_chip_data(d);
+
+       moxtet->irq.masked &= ~BIT(d->hwirq);
+}
+
+static void moxtet_irq_print_chip(struct irq_data *d, struct seq_file *p)
+{
+       struct moxtet *moxtet = irq_data_get_irq_chip_data(d);
+       struct moxtet_irqpos *pos = &moxtet->irq.position[d->hwirq];
+       int id;
+
+       id = moxtet->modules[pos->idx];
+
+       seq_printf(p, " moxtet-%s.%i#%i", mox_module_name(id), pos->idx,
+                  pos->bit);
+}
+
+static const struct irq_chip moxtet_irq_chip = {
+       .name                   = "moxtet",
+       .irq_mask               = moxtet_irq_mask,
+       .irq_unmask             = moxtet_irq_unmask,
+       .irq_print_chip         = moxtet_irq_print_chip,
+};
+
+static int moxtet_irq_read(struct moxtet *moxtet, unsigned long *map)
+{
+       struct moxtet_irqpos *pos = moxtet->irq.position;
+       u8 buf[TURRIS_MOX_MAX_MODULES];
+       int i, ret;
+
+       ret = moxtet_spi_read(moxtet, buf);
+       if (ret < 0)
+               return ret;
+
+       *map = 0;
+
+       for_each_set_bit(i, &moxtet->irq.exists, MOXTET_NIRQS) {
+               if (!(buf[pos[i].idx + 1] & BIT(4 + pos[i].bit)))
+                       set_bit(i, map);
+       }
+
+       return 0;
+}
+
+static irqreturn_t moxtet_irq_thread_fn(int irq, void *data)
+{
+       struct moxtet *moxtet = data;
+       unsigned long set;
+       int nhandled = 0, i, sub_irq, ret;
+
+       ret = moxtet_irq_read(moxtet, &set);
+       if (ret < 0)
+               goto out;
+
+       set &= ~moxtet->irq.masked;
+
+       do {
+               for_each_set_bit(i, &set, MOXTET_NIRQS) {
+                       sub_irq = irq_find_mapping(moxtet->irq.domain, i);
+                       handle_nested_irq(sub_irq);
+                       dev_dbg(moxtet->dev, "%i irq\n", i);
+                       ++nhandled;
+               }
+
+               ret = moxtet_irq_read(moxtet, &set);
+               if (ret < 0)
+                       goto out;
+
+               set &= ~moxtet->irq.masked;
+       } while (set);
+
+out:
+       return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE);
+}
+
+static void moxtet_irq_free(struct moxtet *moxtet)
+{
+       int i, irq;
+
+       for (i = 0; i < MOXTET_NIRQS; ++i) {
+               if (moxtet->irq.exists & BIT(i)) {
+                       irq = irq_find_mapping(moxtet->irq.domain, i);
+                       irq_dispose_mapping(irq);
+               }
+       }
+
+       irq_domain_remove(moxtet->irq.domain);
+}
+
+static int moxtet_irq_setup(struct moxtet *moxtet)
+{
+       int i, ret;
+
+       moxtet->irq.domain = irq_domain_add_simple(moxtet->dev->of_node,
+                                                  MOXTET_NIRQS, 0,
+                                                  &moxtet_irq_domain, moxtet);
+       if (moxtet->irq.domain == NULL) {
+               dev_err(moxtet->dev, "Could not add IRQ domain\n");
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < MOXTET_NIRQS; ++i)
+               if (moxtet->irq.exists & BIT(i))
+                       irq_create_mapping(moxtet->irq.domain, i);
+
+       moxtet->irq.chip = moxtet_irq_chip;
+       moxtet->irq.masked = ~0;
+
+       ret = request_threaded_irq(moxtet->dev_irq, NULL, moxtet_irq_thread_fn,
+                                  IRQF_ONESHOT, "moxtet", moxtet);
+       if (ret < 0)
+               goto err_free;
+
+       return 0;
+
+err_free:
+       moxtet_irq_free(moxtet);
+       return ret;
+}
+
+static int moxtet_probe(struct spi_device *spi)
+{
+       struct moxtet *moxtet;
+       int ret;
+
+       ret = spi_setup(spi);
+       if (ret < 0)
+               return ret;
+
+       moxtet = devm_kzalloc(&spi->dev, sizeof(struct moxtet),
+                             GFP_KERNEL);
+       if (!moxtet)
+               return -ENOMEM;
+
+       moxtet->dev = &spi->dev;
+       spi_set_drvdata(spi, moxtet);
+
+       mutex_init(&moxtet->lock);
+
+       moxtet->dev_irq = of_irq_get(moxtet->dev->of_node, 0);
+       if (moxtet->dev_irq == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+
+       if (moxtet->dev_irq <= 0) {
+               dev_err(moxtet->dev, "No IRQ resource found\n");
+               return -ENXIO;
+       }
+
+       ret = moxtet_find_topology(moxtet);
+       if (ret < 0)
+               return ret;
+
+       if (moxtet->irq.exists) {
+               ret = moxtet_irq_setup(moxtet);
+               if (ret < 0)
+                       return ret;
+       }
+
+       of_register_moxtet_devices(moxtet);
+       moxtet_register_devices_from_topology(moxtet);
+
+       ret = moxtet_register_debugfs(moxtet);
+       if (ret < 0)
+               dev_warn(moxtet->dev, "Failed creating debugfs entries: %i\n",
+                        ret);
+
+       return 0;
+}
+
+static int moxtet_remove(struct spi_device *spi)
+{
+       struct moxtet *moxtet = spi_get_drvdata(spi);
+
+       free_irq(moxtet->dev_irq, moxtet);
+
+       moxtet_irq_free(moxtet);
+
+       moxtet_unregister_debugfs(moxtet);
+
+       device_for_each_child(moxtet->dev, NULL, __unregister);
+
+       mutex_destroy(&moxtet->lock);
+
+       return 0;
+}
+
+static const struct of_device_id moxtet_dt_ids[] = {
+       { .compatible = "cznic,moxtet" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, moxtet_dt_ids);
+
+static struct spi_driver moxtet_spi_driver = {
+       .driver = {
+               .name           = "moxtet",
+               .of_match_table = moxtet_dt_ids,
+       },
+       .probe          = moxtet_probe,
+       .remove         = moxtet_remove,
+};
+
+static int __init moxtet_init(void)
+{
+       int ret;
+
+       ret = bus_register(&moxtet_bus_type);
+       if (ret < 0) {
+               pr_err("moxtet bus registration failed: %d\n", ret);
+               goto error;
+       }
+
+       ret = spi_register_driver(&moxtet_spi_driver);
+       if (ret < 0) {
+               pr_err("moxtet spi driver registration failed: %d\n", ret);
+               goto error_bus;
+       }
+
+       return 0;
+
+error_bus:
+       bus_unregister(&moxtet_bus_type);
+error:
+       return ret;
+}
+postcore_initcall_sync(moxtet_init);
+
+static void __exit moxtet_exit(void)
+{
+       spi_unregister_driver(&moxtet_spi_driver);
+       bus_unregister(&moxtet_bus_type);
+}
+module_exit(moxtet_exit);
+
+MODULE_AUTHOR("Marek Behun <marek.behun@nic.cz>");
+MODULE_DESCRIPTION("CZ.NIC's Turris Mox module configuration bus");
+MODULE_LICENSE("GPL v2");
index 1b76d95..be79d6c 100644 (file)
@@ -651,10 +651,8 @@ static int sunxi_rsb_probe(struct platform_device *pdev)
                return PTR_ERR(rsb->regs);
 
        irq = platform_get_irq(pdev, 0);
-       if (irq < 0) {
-               dev_err(dev, "failed to retrieve irq: %d\n", irq);
+       if (irq < 0)
                return irq;
-       }
 
        rsb->clk = devm_clk_get(dev, NULL);
        if (IS_ERR(rsb->clk)) {
index e845c1a..f70deda 100644 (file)
@@ -176,7 +176,6 @@ static int uniphier_system_bus_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct uniphier_system_bus_priv *priv;
-       struct resource *regs;
        const __be32 *ranges;
        u32 cells, addr, size;
        u64 paddr;
@@ -186,8 +185,7 @@ static int uniphier_system_bus_probe(struct platform_device *pdev)
        if (!priv)
                return -ENOMEM;
 
-       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       priv->membase = devm_ioremap_resource(dev, regs);
+       priv->membase = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(priv->membase))
                return PTR_ERR(priv->membase);
 
index a2287c7..886f7c5 100644 (file)
@@ -69,7 +69,7 @@ static int scmi_clk_set_rate(struct clk_hw *hw, unsigned long rate,
 {
        struct scmi_clk *clk = to_scmi_clk(hw);
 
-       return clk->handle->clk_ops->rate_set(clk->handle, clk->id, 0, rate);
+       return clk->handle->clk_ops->rate_set(clk->handle, clk->id, rate);
 }
 
 static int scmi_clk_enable(struct clk_hw *hw)
index ba8d3d0..c9a827b 100644 (file)
@@ -271,6 +271,20 @@ config TRUSTED_FOUNDATIONS
 
          Choose N if you don't know what this is about.
 
+config TURRIS_MOX_RWTM
+       tristate "Turris Mox rWTM secure firmware driver"
+       depends on ARCH_MVEBU || COMPILE_TEST
+       depends on HAS_DMA && OF
+       depends on MAILBOX
+       select HW_RANDOM
+       select ARMADA_37XX_RWTM_MBOX
+       help
+         This driver communicates with the firmware on the Cortex-M3 secure
+         processor of the Turris Mox router. Enable if you are building for
+         Turris Mox, and you will be able to read the device serial number and
+         other manufacturing data and also utilize the Entropy Bit Generator
+         for hardware random number generation.
+
 config HAVE_ARM_SMCCC
        bool
 
index 3fa0b34..2b6e3a0 100644 (file)
@@ -22,6 +22,7 @@ obj-$(CONFIG_QCOM_SCM_32)     += qcom_scm-32.o
 CFLAGS_qcom_scm-32.o :=$(call as-instr,.arch armv7-a\n.arch_extension sec,-DREQUIRES_SEC=1) -march=armv7-a
 obj-$(CONFIG_TI_SCI_PROTOCOL)  += ti_sci.o
 obj-$(CONFIG_TRUSTED_FOUNDATIONS) += trusted_foundations.o
+obj-$(CONFIG_TURRIS_MOX_RWTM)  += turris-mox-rwtm.o
 
 obj-$(CONFIG_ARM_SCMI_PROTOCOL)        += arm_scmi/
 obj-y                          += psci/
index c47d28d..5f298f0 100644 (file)
@@ -2,5 +2,5 @@
 obj-y  = scmi-bus.o scmi-driver.o scmi-protocols.o
 scmi-bus-y = bus.o
 scmi-driver-y = driver.o
-scmi-protocols-y = base.o clock.o perf.o power.o sensors.o
+scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o
 obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o
index 2043902..f804e8a 100644 (file)
@@ -204,7 +204,7 @@ static int scmi_base_discover_agent_get(const struct scmi_handle *handle,
        if (ret)
                return ret;
 
-       *(__le32 *)t->tx.buf = cpu_to_le32(id);
+       put_unaligned_le32(id, t->tx.buf);
 
        ret = scmi_do_xfer(handle, t);
        if (!ret)
index 0a194af..32526a7 100644 (file)
@@ -56,7 +56,7 @@ struct scmi_msg_resp_clock_describe_rates {
 struct scmi_clock_set_rate {
        __le32 flags;
 #define CLOCK_SET_ASYNC                BIT(0)
-#define CLOCK_SET_DELAYED      BIT(1)
+#define CLOCK_SET_IGNORE_RESP  BIT(1)
 #define CLOCK_SET_ROUND_UP     BIT(2)
 #define CLOCK_SET_ROUND_AUTO   BIT(3)
        __le32 id;
@@ -67,6 +67,7 @@ struct scmi_clock_set_rate {
 struct clock_info {
        int num_clocks;
        int max_async_req;
+       atomic_t cur_async_req;
        struct scmi_clock_info *clk;
 };
 
@@ -106,7 +107,7 @@ static int scmi_clock_attributes_get(const struct scmi_handle *handle,
        if (ret)
                return ret;
 
-       *(__le32 *)t->tx.buf = cpu_to_le32(clk_id);
+       put_unaligned_le32(clk_id, t->tx.buf);
        attr = t->rx.buf;
 
        ret = scmi_do_xfer(handle, t);
@@ -203,39 +204,47 @@ scmi_clock_rate_get(const struct scmi_handle *handle, u32 clk_id, u64 *value)
        if (ret)
                return ret;
 
-       *(__le32 *)t->tx.buf = cpu_to_le32(clk_id);
+       put_unaligned_le32(clk_id, t->tx.buf);
 
        ret = scmi_do_xfer(handle, t);
-       if (!ret) {
-               __le32 *pval = t->rx.buf;
-
-               *value = le32_to_cpu(*pval);
-               *value |= (u64)le32_to_cpu(*(pval + 1)) << 32;
-       }
+       if (!ret)
+               *value = get_unaligned_le64(t->rx.buf);
 
        scmi_xfer_put(handle, t);
        return ret;
 }
 
 static int scmi_clock_rate_set(const struct scmi_handle *handle, u32 clk_id,
-                              u32 config, u64 rate)
+                              u64 rate)
 {
        int ret;
+       u32 flags = 0;
        struct scmi_xfer *t;
        struct scmi_clock_set_rate *cfg;
+       struct clock_info *ci = handle->clk_priv;
 
        ret = scmi_xfer_get_init(handle, CLOCK_RATE_SET, SCMI_PROTOCOL_CLOCK,
                                 sizeof(*cfg), 0, &t);
        if (ret)
                return ret;
 
+       if (ci->max_async_req &&
+           atomic_inc_return(&ci->cur_async_req) < ci->max_async_req)
+               flags |= CLOCK_SET_ASYNC;
+
        cfg = t->tx.buf;
-       cfg->flags = cpu_to_le32(config);
+       cfg->flags = cpu_to_le32(flags);
        cfg->id = cpu_to_le32(clk_id);
        cfg->value_low = cpu_to_le32(rate & 0xffffffff);
        cfg->value_high = cpu_to_le32(rate >> 32);
 
-       ret = scmi_do_xfer(handle, t);
+       if (flags & CLOCK_SET_ASYNC)
+               ret = scmi_do_xfer_with_response(handle, t);
+       else
+               ret = scmi_do_xfer(handle, t);
+
+       if (ci->max_async_req)
+               atomic_dec(&ci->cur_async_req);
 
        scmi_xfer_put(handle, t);
        return ret;
index 44fd4f9..5237c2f 100644 (file)
@@ -15,6 +15,8 @@
 #include <linux/scmi_protocol.h>
 #include <linux/types.h>
 
+#include <asm/unaligned.h>
+
 #define PROTOCOL_REV_MINOR_MASK        GENMASK(15, 0)
 #define PROTOCOL_REV_MAJOR_MASK        GENMASK(31, 16)
 #define PROTOCOL_REV_MAJOR(x)  (u16)(FIELD_GET(PROTOCOL_REV_MAJOR_MASK, (x)))
@@ -48,11 +50,11 @@ struct scmi_msg_resp_prot_version {
 /**
  * struct scmi_msg_hdr - Message(Tx/Rx) header
  *
- * @id: The identifier of the command being sent
- * @protocol_id: The identifier of the protocol used to send @id command
- * @seq: The token to identify the message. when a message/command returns,
- *     the platform returns the whole message header unmodified including
- *     the token
+ * @id: The identifier of the message being sent
+ * @protocol_id: The identifier of the protocol used to send @id message
+ * @seq: The token to identify the message. When a message returns, the
+ *     platform returns the whole message header unmodified including the
+ *     token
  * @status: Status of the transfer once it's complete
  * @poll_completion: Indicate if the transfer needs to be polled for
  *     completion or interrupt mode is used
@@ -84,17 +86,21 @@ struct scmi_msg {
  * @rx: Receive message, the buffer should be pre-allocated to store
  *     message. If request-ACK protocol is used, we can reuse the same
  *     buffer for the rx path as we use for the tx path.
- * @done: completion event
+ * @done: command message transmit completion event
+ * @async: pointer to delayed response message received event completion
  */
 struct scmi_xfer {
        struct scmi_msg_hdr hdr;
        struct scmi_msg tx;
        struct scmi_msg rx;
        struct completion done;
+       struct completion *async_done;
 };
 
 void scmi_xfer_put(const struct scmi_handle *h, struct scmi_xfer *xfer);
 int scmi_do_xfer(const struct scmi_handle *h, struct scmi_xfer *xfer);
+int scmi_do_xfer_with_response(const struct scmi_handle *h,
+                              struct scmi_xfer *xfer);
 int scmi_xfer_get_init(const struct scmi_handle *h, u8 msg_id, u8 prot_id,
                       size_t tx_size, size_t rx_size, struct scmi_xfer **p);
 int scmi_handle_put(const struct scmi_handle *handle);
index b5bc4c7..3eb0382 100644 (file)
 #include "common.h"
 
 #define MSG_ID_MASK            GENMASK(7, 0)
+#define MSG_XTRACT_ID(hdr)     FIELD_GET(MSG_ID_MASK, (hdr))
 #define MSG_TYPE_MASK          GENMASK(9, 8)
+#define MSG_XTRACT_TYPE(hdr)   FIELD_GET(MSG_TYPE_MASK, (hdr))
+#define MSG_TYPE_COMMAND       0
+#define MSG_TYPE_DELAYED_RESP  2
+#define MSG_TYPE_NOTIFICATION  3
 #define MSG_PROTOCOL_ID_MASK   GENMASK(17, 10)
+#define MSG_XTRACT_PROT_ID(hdr)        FIELD_GET(MSG_PROTOCOL_ID_MASK, (hdr))
 #define MSG_TOKEN_ID_MASK      GENMASK(27, 18)
 #define MSG_XTRACT_TOKEN(hdr)  FIELD_GET(MSG_TOKEN_ID_MASK, (hdr))
 #define MSG_TOKEN_MAX          (MSG_XTRACT_TOKEN(MSG_TOKEN_ID_MASK) + 1)
@@ -86,7 +92,7 @@ struct scmi_desc {
 };
 
 /**
- * struct scmi_chan_info - Structure representing a SCMI channel informfation
+ * struct scmi_chan_info - Structure representing a SCMI channel information
  *
  * @cl: Mailbox Client
  * @chan: Transmit/Receive mailbox channel
@@ -111,8 +117,9 @@ struct scmi_chan_info {
  * @handle: Instance of SCMI handle to send to clients
  * @version: SCMI revision information containing protocol version,
  *     implementation version and (sub-)vendor identification.
- * @minfo: Message info
- * @tx_idr: IDR object to map protocol id to channel info pointer
+ * @tx_minfo: Universal Transmit Message management info
+ * @tx_idr: IDR object to map protocol id to Tx channel info pointer
+ * @rx_idr: IDR object to map protocol id to Rx channel info pointer
  * @protocols_imp: List of protocols implemented, currently maximum of
  *     MAX_PROTOCOLS_IMP elements allocated by the base protocol
  * @node: List head
@@ -123,8 +130,9 @@ struct scmi_info {
        const struct scmi_desc *desc;
        struct scmi_revision_info version;
        struct scmi_handle handle;
-       struct scmi_xfers_info minfo;
+       struct scmi_xfers_info tx_minfo;
        struct idr tx_idr;
+       struct idr rx_idr;
        u8 *protocols_imp;
        struct list_head node;
        int users;
@@ -182,7 +190,7 @@ static inline int scmi_to_linux_errno(int errno)
 static inline void scmi_dump_header_dbg(struct device *dev,
                                        struct scmi_msg_hdr *hdr)
 {
-       dev_dbg(dev, "Command ID: %x Sequence ID: %x Protocol: %x\n",
+       dev_dbg(dev, "Message ID: %x Sequence ID: %x Protocol: %x\n",
                hdr->id, hdr->seq, hdr->protocol_id);
 }
 
@@ -190,64 +198,20 @@ static void scmi_fetch_response(struct scmi_xfer *xfer,
                                struct scmi_shared_mem __iomem *mem)
 {
        xfer->hdr.status = ioread32(mem->msg_payload);
-       /* Skip the length of header and statues in payload area i.e 8 bytes*/
+       /* Skip the length of header and status in payload area i.e 8 bytes */
        xfer->rx.len = min_t(size_t, xfer->rx.len, ioread32(&mem->length) - 8);
 
        /* Take a copy to the rx buffer.. */
        memcpy_fromio(xfer->rx.buf, mem->msg_payload + 4, xfer->rx.len);
 }
 
-/**
- * scmi_rx_callback() - mailbox client callback for receive messages
- *
- * @cl: client pointer
- * @m: mailbox message
- *
- * Processes one received message to appropriate transfer information and
- * signals completion of the transfer.
- *
- * NOTE: This function will be invoked in IRQ context, hence should be
- * as optimal as possible.
- */
-static void scmi_rx_callback(struct mbox_client *cl, void *m)
-{
-       u16 xfer_id;
-       struct scmi_xfer *xfer;
-       struct scmi_chan_info *cinfo = client_to_scmi_chan_info(cl);
-       struct device *dev = cinfo->dev;
-       struct scmi_info *info = handle_to_scmi_info(cinfo->handle);
-       struct scmi_xfers_info *minfo = &info->minfo;
-       struct scmi_shared_mem __iomem *mem = cinfo->payload;
-
-       xfer_id = MSG_XTRACT_TOKEN(ioread32(&mem->msg_header));
-
-       /* Are we even expecting this? */
-       if (!test_bit(xfer_id, minfo->xfer_alloc_table)) {
-               dev_err(dev, "message for %d is not expected!\n", xfer_id);
-               return;
-       }
-
-       xfer = &minfo->xfer_block[xfer_id];
-
-       scmi_dump_header_dbg(dev, &xfer->hdr);
-       /* Is the message of valid length? */
-       if (xfer->rx.len > info->desc->max_msg_size) {
-               dev_err(dev, "unable to handle %zu xfer(max %d)\n",
-                       xfer->rx.len, info->desc->max_msg_size);
-               return;
-       }
-
-       scmi_fetch_response(xfer, mem);
-       complete(&xfer->done);
-}
-
 /**
  * pack_scmi_header() - packs and returns 32-bit header
  *
  * @hdr: pointer to header containing all the information on message id,
  *     protocol id and sequence id.
  *
- * Return: 32-bit packed command header to be sent to the platform.
+ * Return: 32-bit packed message header to be sent to the platform.
  */
 static inline u32 pack_scmi_header(struct scmi_msg_hdr *hdr)
 {
@@ -256,6 +220,18 @@ static inline u32 pack_scmi_header(struct scmi_msg_hdr *hdr)
                FIELD_PREP(MSG_PROTOCOL_ID_MASK, hdr->protocol_id);
 }
 
+/**
+ * unpack_scmi_header() - unpacks and records message and protocol id
+ *
+ * @msg_hdr: 32-bit packed message header sent from the platform
+ * @hdr: pointer to header to fetch message and protocol id.
+ */
+static inline void unpack_scmi_header(u32 msg_hdr, struct scmi_msg_hdr *hdr)
+{
+       hdr->id = MSG_XTRACT_ID(msg_hdr);
+       hdr->protocol_id = MSG_XTRACT_PROT_ID(msg_hdr);
+}
+
 /**
  * scmi_tx_prepare() - mailbox client callback to prepare for the transfer
  *
@@ -271,6 +247,14 @@ static void scmi_tx_prepare(struct mbox_client *cl, void *m)
        struct scmi_chan_info *cinfo = client_to_scmi_chan_info(cl);
        struct scmi_shared_mem __iomem *mem = cinfo->payload;
 
+       /*
+        * Ideally channel must be free by now unless OS timeout last
+        * request and platform continued to process the same, wait
+        * until it releases the shared memory, otherwise we may endup
+        * overwriting its response with new message payload or vice-versa
+        */
+       spin_until_cond(ioread32(&mem->channel_status) &
+                       SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE);
        /* Mark channel busy + clear error */
        iowrite32(0x0, &mem->channel_status);
        iowrite32(t->hdr.poll_completion ? 0 : SCMI_SHMEM_FLAG_INTR_ENABLED,
@@ -285,8 +269,9 @@ static void scmi_tx_prepare(struct mbox_client *cl, void *m)
  * scmi_xfer_get() - Allocate one message
  *
  * @handle: Pointer to SCMI entity handle
+ * @minfo: Pointer to Tx/Rx Message management info based on channel type
  *
- * Helper function which is used by various command functions that are
+ * Helper function which is used by various message functions that are
  * exposed to clients of this driver for allocating a message traffic event.
  *
  * This function can sleep depending on pending requests already in the system
@@ -295,13 +280,13 @@ static void scmi_tx_prepare(struct mbox_client *cl, void *m)
  *
  * Return: 0 if all went fine, else corresponding error.
  */
-static struct scmi_xfer *scmi_xfer_get(const struct scmi_handle *handle)
+static struct scmi_xfer *scmi_xfer_get(const struct scmi_handle *handle,
+                                      struct scmi_xfers_info *minfo)
 {
        u16 xfer_id;
        struct scmi_xfer *xfer;
        unsigned long flags, bit_pos;
        struct scmi_info *info = handle_to_scmi_info(handle);
-       struct scmi_xfers_info *minfo = &info->minfo;
 
        /* Keep the locked section as small as possible */
        spin_lock_irqsave(&minfo->xfer_lock, flags);
@@ -324,18 +309,17 @@ static struct scmi_xfer *scmi_xfer_get(const struct scmi_handle *handle)
 }
 
 /**
- * scmi_xfer_put() - Release a message
+ * __scmi_xfer_put() - Release a message
  *
- * @handle: Pointer to SCMI entity handle
+ * @minfo: Pointer to Tx/Rx Message management info based on channel type
  * @xfer: message that was reserved by scmi_xfer_get
  *
  * This holds a spinlock to maintain integrity of internal data structures.
  */
-void scmi_xfer_put(const struct scmi_handle *handle, struct scmi_xfer *xfer)
+static void
+__scmi_xfer_put(struct scmi_xfers_info *minfo, struct scmi_xfer *xfer)
 {
        unsigned long flags;
-       struct scmi_info *info = handle_to_scmi_info(handle);
-       struct scmi_xfers_info *minfo = &info->minfo;
 
        /*
         * Keep the locked section as small as possible
@@ -347,6 +331,68 @@ void scmi_xfer_put(const struct scmi_handle *handle, struct scmi_xfer *xfer)
        spin_unlock_irqrestore(&minfo->xfer_lock, flags);
 }
 
+/**
+ * scmi_rx_callback() - mailbox client callback for receive messages
+ *
+ * @cl: client pointer
+ * @m: mailbox message
+ *
+ * Processes one received message to appropriate transfer information and
+ * signals completion of the transfer.
+ *
+ * NOTE: This function will be invoked in IRQ context, hence should be
+ * as optimal as possible.
+ */
+static void scmi_rx_callback(struct mbox_client *cl, void *m)
+{
+       u8 msg_type;
+       u32 msg_hdr;
+       u16 xfer_id;
+       struct scmi_xfer *xfer;
+       struct scmi_chan_info *cinfo = client_to_scmi_chan_info(cl);
+       struct device *dev = cinfo->dev;
+       struct scmi_info *info = handle_to_scmi_info(cinfo->handle);
+       struct scmi_xfers_info *minfo = &info->tx_minfo;
+       struct scmi_shared_mem __iomem *mem = cinfo->payload;
+
+       msg_hdr = ioread32(&mem->msg_header);
+       msg_type = MSG_XTRACT_TYPE(msg_hdr);
+       xfer_id = MSG_XTRACT_TOKEN(msg_hdr);
+
+       if (msg_type == MSG_TYPE_NOTIFICATION)
+               return; /* Notifications not yet supported */
+
+       /* Are we even expecting this? */
+       if (!test_bit(xfer_id, minfo->xfer_alloc_table)) {
+               dev_err(dev, "message for %d is not expected!\n", xfer_id);
+               return;
+       }
+
+       xfer = &minfo->xfer_block[xfer_id];
+
+       scmi_dump_header_dbg(dev, &xfer->hdr);
+
+       scmi_fetch_response(xfer, mem);
+
+       if (msg_type == MSG_TYPE_DELAYED_RESP)
+               complete(xfer->async_done);
+       else
+               complete(&xfer->done);
+}
+
+/**
+ * scmi_xfer_put() - Release a transmit message
+ *
+ * @handle: Pointer to SCMI entity handle
+ * @xfer: message that was reserved by scmi_xfer_get
+ */
+void scmi_xfer_put(const struct scmi_handle *handle, struct scmi_xfer *xfer)
+{
+       struct scmi_info *info = handle_to_scmi_info(handle);
+
+       __scmi_xfer_put(&info->tx_minfo, xfer);
+}
+
 static bool
 scmi_xfer_poll_done(const struct scmi_chan_info *cinfo, struct scmi_xfer *xfer)
 {
@@ -435,8 +481,36 @@ int scmi_do_xfer(const struct scmi_handle *handle, struct scmi_xfer *xfer)
        return ret;
 }
 
+#define SCMI_MAX_RESPONSE_TIMEOUT      (2 * MSEC_PER_SEC)
+
+/**
+ * scmi_do_xfer_with_response() - Do one transfer and wait until the delayed
+ *     response is received
+ *
+ * @handle: Pointer to SCMI entity handle
+ * @xfer: Transfer to initiate and wait for response
+ *
+ * Return: -ETIMEDOUT in case of no delayed response, if transmit error,
+ *     return corresponding error, else if all goes well, return 0.
+ */
+int scmi_do_xfer_with_response(const struct scmi_handle *handle,
+                              struct scmi_xfer *xfer)
+{
+       int ret, timeout = msecs_to_jiffies(SCMI_MAX_RESPONSE_TIMEOUT);
+       DECLARE_COMPLETION_ONSTACK(async_response);
+
+       xfer->async_done = &async_response;
+
+       ret = scmi_do_xfer(handle, xfer);
+       if (!ret && !wait_for_completion_timeout(xfer->async_done, timeout))
+               ret = -ETIMEDOUT;
+
+       xfer->async_done = NULL;
+       return ret;
+}
+
 /**
- * scmi_xfer_get_init() - Allocate and initialise one message
+ * scmi_xfer_get_init() - Allocate and initialise one message for transmit
  *
  * @handle: Pointer to SCMI entity handle
  * @msg_id: Message identifier
@@ -457,6 +531,7 @@ int scmi_xfer_get_init(const struct scmi_handle *handle, u8 msg_id, u8 prot_id,
        int ret;
        struct scmi_xfer *xfer;
        struct scmi_info *info = handle_to_scmi_info(handle);
+       struct scmi_xfers_info *minfo = &info->tx_minfo;
        struct device *dev = info->dev;
 
        /* Ensure we have sane transfer sizes */
@@ -464,7 +539,7 @@ int scmi_xfer_get_init(const struct scmi_handle *handle, u8 msg_id, u8 prot_id,
            tx_size > info->desc->max_msg_size)
                return -ERANGE;
 
-       xfer = scmi_xfer_get(handle);
+       xfer = scmi_xfer_get(handle, minfo);
        if (IS_ERR(xfer)) {
                ret = PTR_ERR(xfer);
                dev_err(dev, "failed to get free message slot(%d)\n", ret);
@@ -597,27 +672,13 @@ int scmi_handle_put(const struct scmi_handle *handle)
        return 0;
 }
 
-static const struct scmi_desc scmi_generic_desc = {
-       .max_rx_timeout_ms = 30,        /* We may increase this if required */
-       .max_msg = 20,          /* Limited by MBOX_TX_QUEUE_LEN */
-       .max_msg_size = 128,
-};
-
-/* Each compatible listed below must have descriptor associated with it */
-static const struct of_device_id scmi_of_match[] = {
-       { .compatible = "arm,scmi", .data = &scmi_generic_desc },
-       { /* Sentinel */ },
-};
-
-MODULE_DEVICE_TABLE(of, scmi_of_match);
-
 static int scmi_xfer_info_init(struct scmi_info *sinfo)
 {
        int i;
        struct scmi_xfer *xfer;
        struct device *dev = sinfo->dev;
        const struct scmi_desc *desc = sinfo->desc;
-       struct scmi_xfers_info *info = &sinfo->minfo;
+       struct scmi_xfers_info *info = &sinfo->tx_minfo;
 
        /* Pre-allocated messages, no more than what hdr.seq can support */
        if (WARN_ON(desc->max_msg >= MSG_TOKEN_MAX)) {
@@ -652,61 +713,32 @@ static int scmi_xfer_info_init(struct scmi_info *sinfo)
        return 0;
 }
 
-static int scmi_mailbox_check(struct device_node *np)
+static int scmi_mailbox_check(struct device_node *np, int idx)
 {
-       return of_parse_phandle_with_args(np, "mboxes", "#mbox-cells", 0, NULL);
+       return of_parse_phandle_with_args(np, "mboxes", "#mbox-cells",
+                                         idx, NULL);
 }
 
-static int scmi_mbox_free_channel(int id, void *p, void *data)
+static int scmi_mbox_chan_setup(struct scmi_info *info, struct device *dev,
+                               int prot_id, bool tx)
 {
-       struct scmi_chan_info *cinfo = p;
-       struct idr *idr = data;
-
-       if (!IS_ERR_OR_NULL(cinfo->chan)) {
-               mbox_free_channel(cinfo->chan);
-               cinfo->chan = NULL;
-       }
-
-       idr_remove(idr, id);
-
-       return 0;
-}
-
-static int scmi_remove(struct platform_device *pdev)
-{
-       int ret = 0;
-       struct scmi_info *info = platform_get_drvdata(pdev);
-       struct idr *idr = &info->tx_idr;
-
-       mutex_lock(&scmi_list_mutex);
-       if (info->users)
-               ret = -EBUSY;
-       else
-               list_del(&info->node);
-       mutex_unlock(&scmi_list_mutex);
-
-       if (ret)
-               return ret;
-
-       /* Safe to free channels since no more users */
-       ret = idr_for_each(idr, scmi_mbox_free_channel, idr);
-       idr_destroy(&info->tx_idr);
-
-       return ret;
-}
-
-static inline int
-scmi_mbox_chan_setup(struct scmi_info *info, struct device *dev, int prot_id)
-{
-       int ret;
+       int ret, idx;
        struct resource res;
        resource_size_t size;
        struct device_node *shmem, *np = dev->of_node;
        struct scmi_chan_info *cinfo;
        struct mbox_client *cl;
+       struct idr *idr;
+       const char *desc = tx ? "Tx" : "Rx";
 
-       if (scmi_mailbox_check(np)) {
-               cinfo = idr_find(&info->tx_idr, SCMI_PROTOCOL_BASE);
+       /* Transmit channel is first entry i.e. index 0 */
+       idx = tx ? 0 : 1;
+       idr = tx ? &info->tx_idr : &info->rx_idr;
+
+       if (scmi_mailbox_check(np, idx)) {
+               cinfo = idr_find(idr, SCMI_PROTOCOL_BASE);
+               if (unlikely(!cinfo)) /* Possible only if platform has no Rx */
+                       return -EINVAL;
                goto idr_alloc;
        }
 
@@ -719,36 +751,36 @@ scmi_mbox_chan_setup(struct scmi_info *info, struct device *dev, int prot_id)
        cl = &cinfo->cl;
        cl->dev = dev;
        cl->rx_callback = scmi_rx_callback;
-       cl->tx_prepare = scmi_tx_prepare;
+       cl->tx_prepare = tx ? scmi_tx_prepare : NULL;
        cl->tx_block = false;
-       cl->knows_txdone = true;
+       cl->knows_txdone = tx;
 
-       shmem = of_parse_phandle(np, "shmem", 0);
+       shmem = of_parse_phandle(np, "shmem", idx);
        ret = of_address_to_resource(shmem, 0, &res);
        of_node_put(shmem);
        if (ret) {
-               dev_err(dev, "failed to get SCMI Tx payload mem resource\n");
+               dev_err(dev, "failed to get SCMI %s payload memory\n", desc);
                return ret;
        }
 
        size = resource_size(&res);
        cinfo->payload = devm_ioremap(info->dev, res.start, size);
        if (!cinfo->payload) {
-               dev_err(dev, "failed to ioremap SCMI Tx payload\n");
+               dev_err(dev, "failed to ioremap SCMI %s payload\n", desc);
                return -EADDRNOTAVAIL;
        }
 
-       /* Transmit channel is first entry i.e. index 0 */
-       cinfo->chan = mbox_request_channel(cl, 0);
+       cinfo->chan = mbox_request_channel(cl, idx);
        if (IS_ERR(cinfo->chan)) {
                ret = PTR_ERR(cinfo->chan);
                if (ret != -EPROBE_DEFER)
-                       dev_err(dev, "failed to request SCMI Tx mailbox\n");
+                       dev_err(dev, "failed to request SCMI %s mailbox\n",
+                               desc);
                return ret;
        }
 
 idr_alloc:
-       ret = idr_alloc(&info->tx_idr, cinfo, prot_id, prot_id + 1, GFP_KERNEL);
+       ret = idr_alloc(idr, cinfo, prot_id, prot_id + 1, GFP_KERNEL);
        if (ret != prot_id) {
                dev_err(dev, "unable to allocate SCMI idr slot err %d\n", ret);
                return ret;
@@ -758,6 +790,17 @@ idr_alloc:
        return 0;
 }
 
+static inline int
+scmi_mbox_txrx_setup(struct scmi_info *info, struct device *dev, int prot_id)
+{
+       int ret = scmi_mbox_chan_setup(info, dev, prot_id, true);
+
+       if (!ret) /* Rx is optional, hence no error check */
+               scmi_mbox_chan_setup(info, dev, prot_id, false);
+
+       return ret;
+}
+
 static inline void
 scmi_create_protocol_device(struct device_node *np, struct scmi_info *info,
                            int prot_id)
@@ -771,7 +814,7 @@ scmi_create_protocol_device(struct device_node *np, struct scmi_info *info,
                return;
        }
 
-       if (scmi_mbox_chan_setup(info, &sdev->dev, prot_id)) {
+       if (scmi_mbox_txrx_setup(info, &sdev->dev, prot_id)) {
                dev_err(&sdev->dev, "failed to setup transport\n");
                scmi_device_destroy(sdev);
                return;
@@ -791,7 +834,7 @@ static int scmi_probe(struct platform_device *pdev)
        struct device_node *child, *np = dev->of_node;
 
        /* Only mailbox method supported, check for the presence of one */
-       if (scmi_mailbox_check(np)) {
+       if (scmi_mailbox_check(np, 0)) {
                dev_err(dev, "no mailbox found in %pOF\n", np);
                return -EINVAL;
        }
@@ -814,12 +857,13 @@ static int scmi_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, info);
        idr_init(&info->tx_idr);
+       idr_init(&info->rx_idr);
 
        handle = &info->handle;
        handle->dev = info->dev;
        handle->version = &info->version;
 
-       ret = scmi_mbox_chan_setup(info, dev, SCMI_PROTOCOL_BASE);
+       ret = scmi_mbox_txrx_setup(info, dev, SCMI_PROTOCOL_BASE);
        if (ret)
                return ret;
 
@@ -854,6 +898,62 @@ static int scmi_probe(struct platform_device *pdev)
        return 0;
 }
 
+static int scmi_mbox_free_channel(int id, void *p, void *data)
+{
+       struct scmi_chan_info *cinfo = p;
+       struct idr *idr = data;
+
+       if (!IS_ERR_OR_NULL(cinfo->chan)) {
+               mbox_free_channel(cinfo->chan);
+               cinfo->chan = NULL;
+       }
+
+       idr_remove(idr, id);
+
+       return 0;
+}
+
+static int scmi_remove(struct platform_device *pdev)
+{
+       int ret = 0;
+       struct scmi_info *info = platform_get_drvdata(pdev);
+       struct idr *idr = &info->tx_idr;
+
+       mutex_lock(&scmi_list_mutex);
+       if (info->users)
+               ret = -EBUSY;
+       else
+               list_del(&info->node);
+       mutex_unlock(&scmi_list_mutex);
+
+       if (ret)
+               return ret;
+
+       /* Safe to free channels since no more users */
+       ret = idr_for_each(idr, scmi_mbox_free_channel, idr);
+       idr_destroy(&info->tx_idr);
+
+       idr = &info->rx_idr;
+       ret = idr_for_each(idr, scmi_mbox_free_channel, idr);
+       idr_destroy(&info->rx_idr);
+
+       return ret;
+}
+
+static const struct scmi_desc scmi_generic_desc = {
+       .max_rx_timeout_ms = 30,        /* We may increase this if required */
+       .max_msg = 20,          /* Limited by MBOX_TX_QUEUE_LEN */
+       .max_msg_size = 128,
+};
+
+/* Each compatible listed below must have descriptor associated with it */
+static const struct of_device_id scmi_of_match[] = {
+       { .compatible = "arm,scmi", .data = &scmi_generic_desc },
+       { /* Sentinel */ },
+};
+
+MODULE_DEVICE_TABLE(of, scmi_of_match);
+
 static struct platform_driver scmi_driver = {
        .driver = {
                   .name = "arm-scmi",
index 3c8ae7c..4a8012e 100644 (file)
@@ -5,7 +5,10 @@
  * Copyright (C) 2018 ARM Ltd.
  */
 
+#include <linux/bits.h>
 #include <linux/of.h>
+#include <linux/io.h>
+#include <linux/io-64-nonatomic-hi-lo.h>
 #include <linux/platform_device.h>
 #include <linux/pm_opp.h>
 #include <linux/sort.h>
@@ -21,6 +24,7 @@ enum scmi_performance_protocol_cmd {
        PERF_LEVEL_GET = 0x8,
        PERF_NOTIFY_LIMITS = 0x9,
        PERF_NOTIFY_LEVEL = 0xa,
+       PERF_DESCRIBE_FASTCHANNEL = 0xb,
 };
 
 struct scmi_opp {
@@ -44,6 +48,7 @@ struct scmi_msg_resp_perf_domain_attributes {
 #define SUPPORTS_SET_PERF_LVL(x)       ((x) & BIT(30))
 #define SUPPORTS_PERF_LIMIT_NOTIFY(x)  ((x) & BIT(29))
 #define SUPPORTS_PERF_LEVEL_NOTIFY(x)  ((x) & BIT(28))
+#define SUPPORTS_PERF_FASTCHANNELS(x)  ((x) & BIT(27))
        __le32 rate_limit_us;
        __le32 sustained_freq_khz;
        __le32 sustained_perf_level;
@@ -87,17 +92,56 @@ struct scmi_msg_resp_perf_describe_levels {
        } opp[0];
 };
 
+struct scmi_perf_get_fc_info {
+       __le32 domain;
+       __le32 message_id;
+};
+
+struct scmi_msg_resp_perf_desc_fc {
+       __le32 attr;
+#define SUPPORTS_DOORBELL(x)           ((x) & BIT(0))
+#define DOORBELL_REG_WIDTH(x)          FIELD_GET(GENMASK(2, 1), (x))
+       __le32 rate_limit;
+       __le32 chan_addr_low;
+       __le32 chan_addr_high;
+       __le32 chan_size;
+       __le32 db_addr_low;
+       __le32 db_addr_high;
+       __le32 db_set_lmask;
+       __le32 db_set_hmask;
+       __le32 db_preserve_lmask;
+       __le32 db_preserve_hmask;
+};
+
+struct scmi_fc_db_info {
+       int width;
+       u64 set;
+       u64 mask;
+       void __iomem *addr;
+};
+
+struct scmi_fc_info {
+       void __iomem *level_set_addr;
+       void __iomem *limit_set_addr;
+       void __iomem *level_get_addr;
+       void __iomem *limit_get_addr;
+       struct scmi_fc_db_info *level_set_db;
+       struct scmi_fc_db_info *limit_set_db;
+};
+
 struct perf_dom_info {
        bool set_limits;
        bool set_perf;
        bool perf_limit_notify;
        bool perf_level_notify;
+       bool perf_fastchannels;
        u32 opp_count;
        u32 sustained_freq_khz;
        u32 sustained_perf_level;
        u32 mult_factor;
        char name[SCMI_MAX_STR_SIZE];
        struct scmi_opp opp[MAX_OPPS];
+       struct scmi_fc_info *fc_info;
 };
 
 struct scmi_perf_info {
@@ -151,7 +195,7 @@ scmi_perf_domain_attributes_get(const struct scmi_handle *handle, u32 domain,
        if (ret)
                return ret;
 
-       *(__le32 *)t->tx.buf = cpu_to_le32(domain);
+       put_unaligned_le32(domain, t->tx.buf);
        attr = t->rx.buf;
 
        ret = scmi_do_xfer(handle, t);
@@ -162,6 +206,7 @@ scmi_perf_domain_attributes_get(const struct scmi_handle *handle, u32 domain,
                dom_info->set_perf = SUPPORTS_SET_PERF_LVL(flags);
                dom_info->perf_limit_notify = SUPPORTS_PERF_LIMIT_NOTIFY(flags);
                dom_info->perf_level_notify = SUPPORTS_PERF_LEVEL_NOTIFY(flags);
+               dom_info->perf_fastchannels = SUPPORTS_PERF_FASTCHANNELS(flags);
                dom_info->sustained_freq_khz =
                                        le32_to_cpu(attr->sustained_freq_khz);
                dom_info->sustained_perf_level =
@@ -249,8 +294,42 @@ scmi_perf_describe_levels_get(const struct scmi_handle *handle, u32 domain,
        return ret;
 }
 
-static int scmi_perf_limits_set(const struct scmi_handle *handle, u32 domain,
-                               u32 max_perf, u32 min_perf)
+#define SCMI_PERF_FC_RING_DB(w)                                \
+do {                                                   \
+       u##w val = 0;                                   \
+                                                       \
+       if (db->mask)                                   \
+               val = ioread##w(db->addr) & db->mask;   \
+       iowrite##w((u##w)db->set | val, db->addr);      \
+} while (0)
+
+static void scmi_perf_fc_ring_db(struct scmi_fc_db_info *db)
+{
+       if (!db || !db->addr)
+               return;
+
+       if (db->width == 1)
+               SCMI_PERF_FC_RING_DB(8);
+       else if (db->width == 2)
+               SCMI_PERF_FC_RING_DB(16);
+       else if (db->width == 4)
+               SCMI_PERF_FC_RING_DB(32);
+       else /* db->width == 8 */
+#ifdef CONFIG_64BIT
+               SCMI_PERF_FC_RING_DB(64);
+#else
+       {
+               u64 val = 0;
+
+               if (db->mask)
+                       val = ioread64_hi_lo(db->addr) & db->mask;
+               iowrite64_hi_lo(db->set, db->addr);
+       }
+#endif
+}
+
+static int scmi_perf_mb_limits_set(const struct scmi_handle *handle, u32 domain,
+                                  u32 max_perf, u32 min_perf)
 {
        int ret;
        struct scmi_xfer *t;
@@ -272,8 +351,24 @@ static int scmi_perf_limits_set(const struct scmi_handle *handle, u32 domain,
        return ret;
 }
 
-static int scmi_perf_limits_get(const struct scmi_handle *handle, u32 domain,
-                               u32 *max_perf, u32 *min_perf)
+static int scmi_perf_limits_set(const struct scmi_handle *handle, u32 domain,
+                               u32 max_perf, u32 min_perf)
+{
+       struct scmi_perf_info *pi = handle->perf_priv;
+       struct perf_dom_info *dom = pi->dom_info + domain;
+
+       if (dom->fc_info && dom->fc_info->limit_set_addr) {
+               iowrite32(max_perf, dom->fc_info->limit_set_addr);
+               iowrite32(min_perf, dom->fc_info->limit_set_addr + 4);
+               scmi_perf_fc_ring_db(dom->fc_info->limit_set_db);
+               return 0;
+       }
+
+       return scmi_perf_mb_limits_set(handle, domain, max_perf, min_perf);
+}
+
+static int scmi_perf_mb_limits_get(const struct scmi_handle *handle, u32 domain,
+                                  u32 *max_perf, u32 *min_perf)
 {
        int ret;
        struct scmi_xfer *t;
@@ -284,7 +379,7 @@ static int scmi_perf_limits_get(const struct scmi_handle *handle, u32 domain,
        if (ret)
                return ret;
 
-       *(__le32 *)t->tx.buf = cpu_to_le32(domain);
+       put_unaligned_le32(domain, t->tx.buf);
 
        ret = scmi_do_xfer(handle, t);
        if (!ret) {
@@ -298,8 +393,23 @@ static int scmi_perf_limits_get(const struct scmi_handle *handle, u32 domain,
        return ret;
 }
 
-static int scmi_perf_level_set(const struct scmi_handle *handle, u32 domain,
-                              u32 level, bool poll)
+static int scmi_perf_limits_get(const struct scmi_handle *handle, u32 domain,
+                               u32 *max_perf, u32 *min_perf)
+{
+       struct scmi_perf_info *pi = handle->perf_priv;
+       struct perf_dom_info *dom = pi->dom_info + domain;
+
+       if (dom->fc_info && dom->fc_info->limit_get_addr) {
+               *max_perf = ioread32(dom->fc_info->limit_get_addr);
+               *min_perf = ioread32(dom->fc_info->limit_get_addr + 4);
+               return 0;
+       }
+
+       return scmi_perf_mb_limits_get(handle, domain, max_perf, min_perf);
+}
+
+static int scmi_perf_mb_level_set(const struct scmi_handle *handle, u32 domain,
+                                 u32 level, bool poll)
 {
        int ret;
        struct scmi_xfer *t;
@@ -321,8 +431,23 @@ static int scmi_perf_level_set(const struct scmi_handle *handle, u32 domain,
        return ret;
 }
 
-static int scmi_perf_level_get(const struct scmi_handle *handle, u32 domain,
-                              u32 *level, bool poll)
+static int scmi_perf_level_set(const struct scmi_handle *handle, u32 domain,
+                              u32 level, bool poll)
+{
+       struct scmi_perf_info *pi = handle->perf_priv;
+       struct perf_dom_info *dom = pi->dom_info + domain;
+
+       if (dom->fc_info && dom->fc_info->level_set_addr) {
+               iowrite32(level, dom->fc_info->level_set_addr);
+               scmi_perf_fc_ring_db(dom->fc_info->level_set_db);
+               return 0;
+       }
+
+       return scmi_perf_mb_level_set(handle, domain, level, poll);
+}
+
+static int scmi_perf_mb_level_get(const struct scmi_handle *handle, u32 domain,
+                                 u32 *level, bool poll)
 {
        int ret;
        struct scmi_xfer *t;
@@ -333,16 +458,128 @@ static int scmi_perf_level_get(const struct scmi_handle *handle, u32 domain,
                return ret;
 
        t->hdr.poll_completion = poll;
-       *(__le32 *)t->tx.buf = cpu_to_le32(domain);
+       put_unaligned_le32(domain, t->tx.buf);
 
        ret = scmi_do_xfer(handle, t);
        if (!ret)
-               *level = le32_to_cpu(*(__le32 *)t->rx.buf);
+               *level = get_unaligned_le32(t->rx.buf);
 
        scmi_xfer_put(handle, t);
        return ret;
 }
 
+static int scmi_perf_level_get(const struct scmi_handle *handle, u32 domain,
+                              u32 *level, bool poll)
+{
+       struct scmi_perf_info *pi = handle->perf_priv;
+       struct perf_dom_info *dom = pi->dom_info + domain;
+
+       if (dom->fc_info && dom->fc_info->level_get_addr) {
+               *level = ioread32(dom->fc_info->level_get_addr);
+               return 0;
+       }
+
+       return scmi_perf_mb_level_get(handle, domain, level, poll);
+}
+
+static bool scmi_perf_fc_size_is_valid(u32 msg, u32 size)
+{
+       if ((msg == PERF_LEVEL_GET || msg == PERF_LEVEL_SET) && size == 4)
+               return true;
+       if ((msg == PERF_LIMITS_GET || msg == PERF_LIMITS_SET) && size == 8)
+               return true;
+       return false;
+}
+
+static void
+scmi_perf_domain_desc_fc(const struct scmi_handle *handle, u32 domain,
+                        u32 message_id, void __iomem **p_addr,
+                        struct scmi_fc_db_info **p_db)
+{
+       int ret;
+       u32 flags;
+       u64 phys_addr;
+       u8 size;
+       void __iomem *addr;
+       struct scmi_xfer *t;
+       struct scmi_fc_db_info *db;
+       struct scmi_perf_get_fc_info *info;
+       struct scmi_msg_resp_perf_desc_fc *resp;
+
+       if (!p_addr)
+               return;
+
+       ret = scmi_xfer_get_init(handle, PERF_DESCRIBE_FASTCHANNEL,
+                                SCMI_PROTOCOL_PERF,
+                                sizeof(*info), sizeof(*resp), &t);
+       if (ret)
+               return;
+
+       info = t->tx.buf;
+       info->domain = cpu_to_le32(domain);
+       info->message_id = cpu_to_le32(message_id);
+
+       ret = scmi_do_xfer(handle, t);
+       if (ret)
+               goto err_xfer;
+
+       resp = t->rx.buf;
+       flags = le32_to_cpu(resp->attr);
+       size = le32_to_cpu(resp->chan_size);
+       if (!scmi_perf_fc_size_is_valid(message_id, size))
+               goto err_xfer;
+
+       phys_addr = le32_to_cpu(resp->chan_addr_low);
+       phys_addr |= (u64)le32_to_cpu(resp->chan_addr_high) << 32;
+       addr = devm_ioremap(handle->dev, phys_addr, size);
+       if (!addr)
+               goto err_xfer;
+       *p_addr = addr;
+
+       if (p_db && SUPPORTS_DOORBELL(flags)) {
+               db = devm_kzalloc(handle->dev, sizeof(*db), GFP_KERNEL);
+               if (!db)
+                       goto err_xfer;
+
+               size = 1 << DOORBELL_REG_WIDTH(flags);
+               phys_addr = le32_to_cpu(resp->db_addr_low);
+               phys_addr |= (u64)le32_to_cpu(resp->db_addr_high) << 32;
+               addr = devm_ioremap(handle->dev, phys_addr, size);
+               if (!addr)
+                       goto err_xfer;
+
+               db->addr = addr;
+               db->width = size;
+               db->set = le32_to_cpu(resp->db_set_lmask);
+               db->set |= (u64)le32_to_cpu(resp->db_set_hmask) << 32;
+               db->mask = le32_to_cpu(resp->db_preserve_lmask);
+               db->mask |= (u64)le32_to_cpu(resp->db_preserve_hmask) << 32;
+               *p_db = db;
+       }
+err_xfer:
+       scmi_xfer_put(handle, t);
+}
+
+static void scmi_perf_domain_init_fc(const struct scmi_handle *handle,
+                                    u32 domain, struct scmi_fc_info **p_fc)
+{
+       struct scmi_fc_info *fc;
+
+       fc = devm_kzalloc(handle->dev, sizeof(*fc), GFP_KERNEL);
+       if (!fc)
+               return;
+
+       scmi_perf_domain_desc_fc(handle, domain, PERF_LEVEL_SET,
+                                &fc->level_set_addr, &fc->level_set_db);
+       scmi_perf_domain_desc_fc(handle, domain, PERF_LEVEL_GET,
+                                &fc->level_get_addr, NULL);
+       scmi_perf_domain_desc_fc(handle, domain, PERF_LIMITS_SET,
+                                &fc->limit_set_addr, &fc->limit_set_db);
+       scmi_perf_domain_desc_fc(handle, domain, PERF_LIMITS_GET,
+                                &fc->limit_get_addr, NULL);
+       *p_fc = fc;
+}
+
 /* Device specific ops */
 static int scmi_dev_domain_id(struct device *dev)
 {
@@ -494,6 +731,9 @@ static int scmi_perf_protocol_init(struct scmi_handle *handle)
 
                scmi_perf_domain_attributes_get(handle, domain, dom);
                scmi_perf_describe_levels_get(handle, domain, dom);
+
+               if (dom->perf_fastchannels)
+                       scmi_perf_domain_init_fc(handle, domain, &dom->fc_info);
        }
 
        handle->perf_ops = &perf_ops;
index 62f3401..5abef70 100644 (file)
@@ -96,7 +96,7 @@ scmi_power_domain_attributes_get(const struct scmi_handle *handle, u32 domain,
        if (ret)
                return ret;
 
-       *(__le32 *)t->tx.buf = cpu_to_le32(domain);
+       put_unaligned_le32(domain, t->tx.buf);
        attr = t->rx.buf;
 
        ret = scmi_do_xfer(handle, t);
@@ -147,11 +147,11 @@ scmi_power_state_get(const struct scmi_handle *handle, u32 domain, u32 *state)
        if (ret)
                return ret;
 
-       *(__le32 *)t->tx.buf = cpu_to_le32(domain);
+       put_unaligned_le32(domain, t->tx.buf);
 
        ret = scmi_do_xfer(handle, t);
        if (!ret)
-               *state = le32_to_cpu(*(__le32 *)t->rx.buf);
+               *state = get_unaligned_le32(t->rx.buf);
 
        scmi_xfer_put(handle, t);
        return ret;
diff --git a/drivers/firmware/arm_scmi/reset.c b/drivers/firmware/arm_scmi/reset.c
new file mode 100644 (file)
index 0000000..64cc819
--- /dev/null
@@ -0,0 +1,231 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * System Control and Management Interface (SCMI) Reset Protocol
+ *
+ * Copyright (C) 2019 ARM Ltd.
+ */
+
+#include "common.h"
+
+enum scmi_reset_protocol_cmd {
+       RESET_DOMAIN_ATTRIBUTES = 0x3,
+       RESET = 0x4,
+       RESET_NOTIFY = 0x5,
+};
+
+enum scmi_reset_protocol_notify {
+       RESET_ISSUED = 0x0,
+};
+
+#define NUM_RESET_DOMAIN_MASK  0xffff
+#define RESET_NOTIFY_ENABLE    BIT(0)
+
+struct scmi_msg_resp_reset_domain_attributes {
+       __le32 attributes;
+#define SUPPORTS_ASYNC_RESET(x)                ((x) & BIT(31))
+#define SUPPORTS_NOTIFY_RESET(x)       ((x) & BIT(30))
+       __le32 latency;
+           u8 name[SCMI_MAX_STR_SIZE];
+};
+
+struct scmi_msg_reset_domain_reset {
+       __le32 domain_id;
+       __le32 flags;
+#define AUTONOMOUS_RESET       BIT(0)
+#define EXPLICIT_RESET_ASSERT  BIT(1)
+#define ASYNCHRONOUS_RESET     BIT(2)
+       __le32 reset_state;
+#define ARCH_RESET_TYPE                BIT(31)
+#define COLD_RESET_STATE       BIT(0)
+#define ARCH_COLD_RESET                (ARCH_RESET_TYPE | COLD_RESET_STATE)
+};
+
+struct reset_dom_info {
+       bool async_reset;
+       bool reset_notify;
+       u32 latency_us;
+       char name[SCMI_MAX_STR_SIZE];
+};
+
+struct scmi_reset_info {
+       int num_domains;
+       struct reset_dom_info *dom_info;
+};
+
+static int scmi_reset_attributes_get(const struct scmi_handle *handle,
+                                    struct scmi_reset_info *pi)
+{
+       int ret;
+       struct scmi_xfer *t;
+       u32 attr;
+
+       ret = scmi_xfer_get_init(handle, PROTOCOL_ATTRIBUTES,
+                                SCMI_PROTOCOL_RESET, 0, sizeof(attr), &t);
+       if (ret)
+               return ret;
+
+       ret = scmi_do_xfer(handle, t);
+       if (!ret) {
+               attr = get_unaligned_le32(t->rx.buf);
+               pi->num_domains = attr & NUM_RESET_DOMAIN_MASK;
+       }
+
+       scmi_xfer_put(handle, t);
+       return ret;
+}
+
+static int
+scmi_reset_domain_attributes_get(const struct scmi_handle *handle, u32 domain,
+                                struct reset_dom_info *dom_info)
+{
+       int ret;
+       struct scmi_xfer *t;
+       struct scmi_msg_resp_reset_domain_attributes *attr;
+
+       ret = scmi_xfer_get_init(handle, RESET_DOMAIN_ATTRIBUTES,
+                                SCMI_PROTOCOL_RESET, sizeof(domain),
+                                sizeof(*attr), &t);
+       if (ret)
+               return ret;
+
+       put_unaligned_le32(domain, t->tx.buf);
+       attr = t->rx.buf;
+
+       ret = scmi_do_xfer(handle, t);
+       if (!ret) {
+               u32 attributes = le32_to_cpu(attr->attributes);
+
+               dom_info->async_reset = SUPPORTS_ASYNC_RESET(attributes);
+               dom_info->reset_notify = SUPPORTS_NOTIFY_RESET(attributes);
+               dom_info->latency_us = le32_to_cpu(attr->latency);
+               if (dom_info->latency_us == U32_MAX)
+                       dom_info->latency_us = 0;
+               strlcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE);
+       }
+
+       scmi_xfer_put(handle, t);
+       return ret;
+}
+
+static int scmi_reset_num_domains_get(const struct scmi_handle *handle)
+{
+       struct scmi_reset_info *pi = handle->reset_priv;
+
+       return pi->num_domains;
+}
+
+static char *scmi_reset_name_get(const struct scmi_handle *handle, u32 domain)
+{
+       struct scmi_reset_info *pi = handle->reset_priv;
+       struct reset_dom_info *dom = pi->dom_info + domain;
+
+       return dom->name;
+}
+
+static int scmi_reset_latency_get(const struct scmi_handle *handle, u32 domain)
+{
+       struct scmi_reset_info *pi = handle->reset_priv;
+       struct reset_dom_info *dom = pi->dom_info + domain;
+
+       return dom->latency_us;
+}
+
+static int scmi_domain_reset(const struct scmi_handle *handle, u32 domain,
+                            u32 flags, u32 state)
+{
+       int ret;
+       struct scmi_xfer *t;
+       struct scmi_msg_reset_domain_reset *dom;
+       struct scmi_reset_info *pi = handle->reset_priv;
+       struct reset_dom_info *rdom = pi->dom_info + domain;
+
+       if (rdom->async_reset)
+               flags |= ASYNCHRONOUS_RESET;
+
+       ret = scmi_xfer_get_init(handle, RESET, SCMI_PROTOCOL_RESET,
+                                sizeof(*dom), 0, &t);
+       if (ret)
+               return ret;
+
+       dom = t->tx.buf;
+       dom->domain_id = cpu_to_le32(domain);
+       dom->flags = cpu_to_le32(flags);
+       dom->domain_id = cpu_to_le32(state);
+
+       if (rdom->async_reset)
+               ret = scmi_do_xfer_with_response(handle, t);
+       else
+               ret = scmi_do_xfer(handle, t);
+
+       scmi_xfer_put(handle, t);
+       return ret;
+}
+
+static int scmi_reset_domain_reset(const struct scmi_handle *handle, u32 domain)
+{
+       return scmi_domain_reset(handle, domain, AUTONOMOUS_RESET,
+                                ARCH_COLD_RESET);
+}
+
+static int
+scmi_reset_domain_assert(const struct scmi_handle *handle, u32 domain)
+{
+       return scmi_domain_reset(handle, domain, EXPLICIT_RESET_ASSERT,
+                                ARCH_COLD_RESET);
+}
+
+static int
+scmi_reset_domain_deassert(const struct scmi_handle *handle, u32 domain)
+{
+       return scmi_domain_reset(handle, domain, 0, ARCH_COLD_RESET);
+}
+
+static struct scmi_reset_ops reset_ops = {
+       .num_domains_get = scmi_reset_num_domains_get,
+       .name_get = scmi_reset_name_get,
+       .latency_get = scmi_reset_latency_get,
+       .reset = scmi_reset_domain_reset,
+       .assert = scmi_reset_domain_assert,
+       .deassert = scmi_reset_domain_deassert,
+};
+
+static int scmi_reset_protocol_init(struct scmi_handle *handle)
+{
+       int domain;
+       u32 version;
+       struct scmi_reset_info *pinfo;
+
+       scmi_version_get(handle, SCMI_PROTOCOL_RESET, &version);
+
+       dev_dbg(handle->dev, "Reset Version %d.%d\n",
+               PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
+
+       pinfo = devm_kzalloc(handle->dev, sizeof(*pinfo), GFP_KERNEL);
+       if (!pinfo)
+               return -ENOMEM;
+
+       scmi_reset_attributes_get(handle, pinfo);
+
+       pinfo->dom_info = devm_kcalloc(handle->dev, pinfo->num_domains,
+                                      sizeof(*pinfo->dom_info), GFP_KERNEL);
+       if (!pinfo->dom_info)
+               return -ENOMEM;
+
+       for (domain = 0; domain < pinfo->num_domains; domain++) {
+               struct reset_dom_info *dom = pinfo->dom_info + domain;
+
+               scmi_reset_domain_attributes_get(handle, domain, dom);
+       }
+
+       handle->reset_ops = &reset_ops;
+       handle->reset_priv = pinfo;
+
+       return 0;
+}
+
+static int __init scmi_reset_init(void)
+{
+       return scmi_protocol_register(SCMI_PROTOCOL_RESET,
+                                     &scmi_reset_protocol_init);
+}
+subsys_initcall(scmi_reset_init);
index 0e94ab5..a400ea8 100644 (file)
@@ -9,8 +9,8 @@
 
 enum scmi_sensor_protocol_cmd {
        SENSOR_DESCRIPTION_GET = 0x3,
-       SENSOR_CONFIG_SET = 0x4,
-       SENSOR_TRIP_POINT_SET = 0x5,
+       SENSOR_TRIP_POINT_NOTIFY = 0x4,
+       SENSOR_TRIP_POINT_CONFIG = 0x5,
        SENSOR_READING_GET = 0x6,
 };
 
@@ -42,9 +42,10 @@ struct scmi_msg_resp_sensor_description {
        } desc[0];
 };
 
-struct scmi_msg_set_sensor_config {
+struct scmi_msg_sensor_trip_point_notify {
        __le32 id;
        __le32 event_control;
+#define SENSOR_TP_NOTIFY_ALL   BIT(0)
 };
 
 struct scmi_msg_set_sensor_trip_point {
@@ -119,7 +120,7 @@ static int scmi_sensor_description_get(const struct scmi_handle *handle,
 
        do {
                /* Set the number of sensors to be skipped/already read */
-               *(__le32 *)t->tx.buf = cpu_to_le32(desc_index);
+               put_unaligned_le32(desc_index, t->tx.buf);
 
                ret = scmi_do_xfer(handle, t);
                if (ret)
@@ -135,9 +136,10 @@ static int scmi_sensor_description_get(const struct scmi_handle *handle,
                }
 
                for (cnt = 0; cnt < num_returned; cnt++) {
-                       u32 attrh;
+                       u32 attrh, attrl;
                        struct scmi_sensor_info *s;
 
+                       attrl = le32_to_cpu(buf->desc[cnt].attributes_low);
                        attrh = le32_to_cpu(buf->desc[cnt].attributes_high);
                        s = &si->sensors[desc_index + cnt];
                        s->id = le32_to_cpu(buf->desc[cnt].id);
@@ -146,6 +148,8 @@ static int scmi_sensor_description_get(const struct scmi_handle *handle,
                        /* Sign extend to a full s8 */
                        if (s->scale & SENSOR_SCALE_SIGN)
                                s->scale |= SENSOR_SCALE_EXTEND;
+                       s->async = SUPPORTS_ASYNC_READ(attrl);
+                       s->num_trip_points = NUM_TRIP_POINTS(attrl);
                        strlcpy(s->name, buf->desc[cnt].name, SCMI_MAX_STR_SIZE);
                }
 
@@ -160,15 +164,15 @@ static int scmi_sensor_description_get(const struct scmi_handle *handle,
        return ret;
 }
 
-static int
-scmi_sensor_configuration_set(const struct scmi_handle *handle, u32 sensor_id)
+static int scmi_sensor_trip_point_notify(const struct scmi_handle *handle,
+                                        u32 sensor_id, bool enable)
 {
        int ret;
-       u32 evt_cntl = BIT(0);
+       u32 evt_cntl = enable ? SENSOR_TP_NOTIFY_ALL : 0;
        struct scmi_xfer *t;
-       struct scmi_msg_set_sensor_config *cfg;
+       struct scmi_msg_sensor_trip_point_notify *cfg;
 
-       ret = scmi_xfer_get_init(handle, SENSOR_CONFIG_SET,
+       ret = scmi_xfer_get_init(handle, SENSOR_TRIP_POINT_NOTIFY,
                                 SCMI_PROTOCOL_SENSOR, sizeof(*cfg), 0, &t);
        if (ret)
                return ret;
@@ -183,15 +187,16 @@ scmi_sensor_configuration_set(const struct scmi_handle *handle, u32 sensor_id)
        return ret;
 }
 
-static int scmi_sensor_trip_point_set(const struct scmi_handle *handle,
-                                     u32 sensor_id, u8 trip_id, u64 trip_value)
+static int
+scmi_sensor_trip_point_config(const struct scmi_handle *handle, u32 sensor_id,
+                             u8 trip_id, u64 trip_value)
 {
        int ret;
        u32 evt_cntl = SENSOR_TP_BOTH;
        struct scmi_xfer *t;
        struct scmi_msg_set_sensor_trip_point *trip;
 
-       ret = scmi_xfer_get_init(handle, SENSOR_TRIP_POINT_SET,
+       ret = scmi_xfer_get_init(handle, SENSOR_TRIP_POINT_CONFIG,
                                 SCMI_PROTOCOL_SENSOR, sizeof(*trip), 0, &t);
        if (ret)
                return ret;
@@ -209,11 +214,13 @@ static int scmi_sensor_trip_point_set(const struct scmi_handle *handle,
 }
 
 static int scmi_sensor_reading_get(const struct scmi_handle *handle,
-                                  u32 sensor_id, bool async, u64 *value)
+                                  u32 sensor_id, u64 *value)
 {
        int ret;
        struct scmi_xfer *t;
        struct scmi_msg_sensor_reading_get *sensor;
+       struct sensors_info *si = handle->sensor_priv;
+       struct scmi_sensor_info *s = si->sensors + sensor_id;
 
        ret = scmi_xfer_get_init(handle, SENSOR_READING_GET,
                                 SCMI_PROTOCOL_SENSOR, sizeof(*sensor),
@@ -223,14 +230,18 @@ static int scmi_sensor_reading_get(const struct scmi_handle *handle,
 
        sensor = t->tx.buf;
        sensor->id = cpu_to_le32(sensor_id);
-       sensor->flags = cpu_to_le32(async ? SENSOR_READ_ASYNC : 0);
 
-       ret = scmi_do_xfer(handle, t);
-       if (!ret) {
-               __le32 *pval = t->rx.buf;
-
-               *value = le32_to_cpu(*pval);
-               *value |= (u64)le32_to_cpu(*(pval + 1)) << 32;
+       if (s->async) {
+               sensor->flags = cpu_to_le32(SENSOR_READ_ASYNC);
+               ret = scmi_do_xfer_with_response(handle, t);
+               if (!ret)
+                       *value = get_unaligned_le64((void *)
+                                                   ((__le32 *)t->rx.buf + 1));
+       } else {
+               sensor->flags = cpu_to_le32(0);
+               ret = scmi_do_xfer(handle, t);
+               if (!ret)
+                       *value = get_unaligned_le64(t->rx.buf);
        }
 
        scmi_xfer_put(handle, t);
@@ -255,8 +266,8 @@ static int scmi_sensor_count_get(const struct scmi_handle *handle)
 static struct scmi_sensor_ops sensor_ops = {
        .count_get = scmi_sensor_count_get,
        .info_get = scmi_sensor_info_get,
-       .configuration_set = scmi_sensor_configuration_set,
-       .trip_point_set = scmi_sensor_trip_point_set,
+       .trip_point_notify = scmi_sensor_trip_point_notify,
+       .trip_point_config = scmi_sensor_trip_point_config,
        .reading_get = scmi_sensor_reading_get,
 };
 
index 42b566f..0dbee32 100644 (file)
@@ -1,4 +1,15 @@
 # SPDX-License-Identifier: GPL-2.0-only
+config IMX_DSP
+       bool "IMX DSP Protocol driver"
+       depends on IMX_MBOX
+       help
+         This enables DSP IPC protocol between host AP (Linux)
+         and the firmware running on DSP.
+         DSP exists on some i.MX8 processors (e.g i.MX8QM, i.MX8QXP).
+
+         It acts like a doorbell. Client might use shared memory to
+         exchange information with DSP side.
+
 config IMX_SCU
        bool "IMX SCU Protocol driver"
        depends on IMX_MBOX
index 802c4ad..08bc9dd 100644 (file)
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_IMX_DSP)          += imx-dsp.o
 obj-$(CONFIG_IMX_SCU)          += imx-scu.o misc.o imx-scu-irq.o
 obj-$(CONFIG_IMX_SCU_PD)       += scu-pd.o
diff --git a/drivers/firmware/imx/imx-dsp.c b/drivers/firmware/imx/imx-dsp.c
new file mode 100644 (file)
index 0000000..a43d2db
--- /dev/null
@@ -0,0 +1,155 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 NXP
+ *  Author: Daniel Baluta <daniel.baluta@nxp.com>
+ *
+ * Implementation of the DSP IPC interface (host side)
+ */
+
+#include <linux/firmware/imx/dsp.h>
+#include <linux/kernel.h>
+#include <linux/mailbox_client.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+/*
+ * imx_dsp_ring_doorbell - triggers an interrupt on the other side (DSP)
+ *
+ * @dsp: DSP IPC handle
+ * @chan_idx: index of the channel where to trigger the interrupt
+ *
+ * Returns non-negative value for success, negative value for error
+ */
+int imx_dsp_ring_doorbell(struct imx_dsp_ipc *ipc, unsigned int idx)
+{
+       int ret;
+       struct imx_dsp_chan *dsp_chan;
+
+       if (idx >= DSP_MU_CHAN_NUM)
+               return -EINVAL;
+
+       dsp_chan = &ipc->chans[idx];
+       ret = mbox_send_message(dsp_chan->ch, NULL);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+EXPORT_SYMBOL(imx_dsp_ring_doorbell);
+
+/*
+ * imx_dsp_handle_rx - rx callback used by imx mailbox
+ *
+ * @c: mbox client
+ * @msg: message received
+ *
+ * Users of DSP IPC will need to privde handle_reply and handle_request
+ * callbacks.
+ */
+static void imx_dsp_handle_rx(struct mbox_client *c, void *msg)
+{
+       struct imx_dsp_chan *chan = container_of(c, struct imx_dsp_chan, cl);
+
+       if (chan->idx == 0) {
+               chan->ipc->ops->handle_reply(chan->ipc);
+       } else {
+               chan->ipc->ops->handle_request(chan->ipc);
+               imx_dsp_ring_doorbell(chan->ipc, 1);
+       }
+}
+
+static int imx_dsp_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct imx_dsp_ipc *dsp_ipc;
+       struct imx_dsp_chan *dsp_chan;
+       struct mbox_client *cl;
+       char *chan_name;
+       int ret;
+       int i, j;
+
+       device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent);
+
+       dsp_ipc = devm_kzalloc(dev, sizeof(*dsp_ipc), GFP_KERNEL);
+       if (!dsp_ipc)
+               return -ENOMEM;
+
+       for (i = 0; i < DSP_MU_CHAN_NUM; i++) {
+               if (i < 2)
+                       chan_name = kasprintf(GFP_KERNEL, "txdb%d", i);
+               else
+                       chan_name = kasprintf(GFP_KERNEL, "rxdb%d", i - 2);
+
+               if (!chan_name)
+                       return -ENOMEM;
+
+               dsp_chan = &dsp_ipc->chans[i];
+               cl = &dsp_chan->cl;
+               cl->dev = dev;
+               cl->tx_block = false;
+               cl->knows_txdone = true;
+               cl->rx_callback = imx_dsp_handle_rx;
+
+               dsp_chan->ipc = dsp_ipc;
+               dsp_chan->idx = i % 2;
+               dsp_chan->ch = mbox_request_channel_byname(cl, chan_name);
+               if (IS_ERR(dsp_chan->ch)) {
+                       ret = PTR_ERR(dsp_chan->ch);
+                       if (ret != -EPROBE_DEFER)
+                               dev_err(dev, "Failed to request mbox chan %s ret %d\n",
+                                       chan_name, ret);
+                       goto out;
+               }
+
+               dev_dbg(dev, "request mbox chan %s\n", chan_name);
+               /* chan_name is not used anymore by framework */
+               kfree(chan_name);
+       }
+
+       dsp_ipc->dev = dev;
+
+       dev_set_drvdata(dev, dsp_ipc);
+
+       dev_info(dev, "NXP i.MX DSP IPC initialized\n");
+
+       return devm_of_platform_populate(dev);
+out:
+       kfree(chan_name);
+       for (j = 0; j < i; j++) {
+               dsp_chan = &dsp_ipc->chans[j];
+               mbox_free_channel(dsp_chan->ch);
+       }
+
+       return ret;
+}
+
+static int imx_dsp_remove(struct platform_device *pdev)
+{
+       struct imx_dsp_chan *dsp_chan;
+       struct imx_dsp_ipc *dsp_ipc;
+       int i;
+
+       dsp_ipc = dev_get_drvdata(&pdev->dev);
+
+       for (i = 0; i < DSP_MU_CHAN_NUM; i++) {
+               dsp_chan = &dsp_ipc->chans[i];
+               mbox_free_channel(dsp_chan->ch);
+       }
+
+       return 0;
+}
+
+static struct platform_driver imx_dsp_driver = {
+       .driver = {
+               .name = "imx-dsp",
+       },
+       .probe = imx_dsp_probe,
+       .remove = imx_dsp_remove,
+};
+builtin_platform_driver(imx_dsp_driver);
+
+MODULE_AUTHOR("Daniel Baluta <daniel.baluta@nxp.com>");
+MODULE_DESCRIPTION("IMX DSP IPC protocol driver");
+MODULE_LICENSE("GPL v2");
index 480cec6..b556612 100644 (file)
@@ -92,7 +92,8 @@ static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = {
        { "gpt", IMX_SC_R_GPT_0, 5, true, 0 },
        { "kpp", IMX_SC_R_KPP, 1, false, 0 },
        { "fspi", IMX_SC_R_FSPI_0, 2, true, 0 },
-       { "mu", IMX_SC_R_MU_0A, 14, true, 0 },
+       { "mu_a", IMX_SC_R_MU_0A, 14, true, 0 },
+       { "mu_b", IMX_SC_R_MU_13B, 1, true, 13 },
 
        /* CONN SS */
        { "usb", IMX_SC_R_USB_0, 2, true, 0 },
@@ -130,6 +131,7 @@ static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = {
        { "lcd0-pwm", IMX_SC_R_LCD_0_PWM_0, 1, true, 0 },
        { "lpuart", IMX_SC_R_UART_0, 4, true, 0 },
        { "lpspi", IMX_SC_R_SPI_0, 4, true, 0 },
+       { "irqstr_dsp", IMX_SC_R_IRQSTR_DSP, 1, false, 0 },
 
        /* VPU SS */
        { "vpu", IMX_SC_R_VPU, 1, false, 0 },
index 2ddc118..4802ab1 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/init.h>
 #include <linux/cpumask.h>
 #include <linux/export.h>
+#include <linux/dma-direct.h>
 #include <linux/dma-mapping.h>
 #include <linux/module.h>
 #include <linux/types.h>
@@ -425,21 +426,23 @@ EXPORT_SYMBOL(qcom_scm_set_remote_state);
  * @mem_sz:   size of the region.
  * @srcvm:    vmid for current set of owners, each set bit in
  *            flag indicate a unique owner
- * @newvm:    array having new owners and corrsponding permission
+ * @newvm:    array having new owners and corresponding permission
  *            flags
  * @dest_cnt: number of owners in next set.
  *
- * Return negative errno on failure, 0 on success, with @srcvm updated.
+ * Return negative errno on failure or 0 on success with @srcvm updated.
  */
 int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz,
                        unsigned int *srcvm,
-                       struct qcom_scm_vmperm *newvm, int dest_cnt)
+                       const struct qcom_scm_vmperm *newvm,
+                       unsigned int dest_cnt)
 {
        struct qcom_scm_current_perm_info *destvm;
        struct qcom_scm_mem_map_info *mem_to_map;
        phys_addr_t mem_to_map_phys;
        phys_addr_t dest_phys;
        phys_addr_t ptr_phys;
+       dma_addr_t ptr_dma;
        size_t mem_to_map_sz;
        size_t dest_sz;
        size_t src_sz;
@@ -447,52 +450,50 @@ int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz,
        int next_vm;
        __le32 *src;
        void *ptr;
-       int ret;
-       int len;
-       int i;
+       int ret, i, b;
+       unsigned long srcvm_bits = *srcvm;
 
-       src_sz = hweight_long(*srcvm) * sizeof(*src);
+       src_sz = hweight_long(srcvm_bits) * sizeof(*src);
        mem_to_map_sz = sizeof(*mem_to_map);
        dest_sz = dest_cnt * sizeof(*destvm);
        ptr_sz = ALIGN(src_sz, SZ_64) + ALIGN(mem_to_map_sz, SZ_64) +
                        ALIGN(dest_sz, SZ_64);
 
-       ptr = dma_alloc_coherent(__scm->dev, ptr_sz, &ptr_phys, GFP_KERNEL);
+       ptr = dma_alloc_coherent(__scm->dev, ptr_sz, &ptr_dma, GFP_KERNEL);
        if (!ptr)
                return -ENOMEM;
+       ptr_phys = dma_to_phys(__scm->dev, ptr_dma);
 
        /* Fill source vmid detail */
        src = ptr;
-       len = hweight_long(*srcvm);
-       for (i = 0; i < len; i++) {
-               src[i] = cpu_to_le32(ffs(*srcvm) - 1);
-               *srcvm ^= 1 << (ffs(*srcvm) - 1);
-       }
+       i = 0;
+       for_each_set_bit(b, &srcvm_bits, BITS_PER_LONG)
+               src[i++] = cpu_to_le32(b);
 
        /* Fill details of mem buff to map */
        mem_to_map = ptr + ALIGN(src_sz, SZ_64);
        mem_to_map_phys = ptr_phys + ALIGN(src_sz, SZ_64);
-       mem_to_map[0].mem_addr = cpu_to_le64(mem_addr);
-       mem_to_map[0].mem_size = cpu_to_le64(mem_sz);
+       mem_to_map->mem_addr = cpu_to_le64(mem_addr);
+       mem_to_map->mem_size = cpu_to_le64(mem_sz);
 
        next_vm = 0;
        /* Fill details of next vmid detail */
        destvm = ptr + ALIGN(mem_to_map_sz, SZ_64) + ALIGN(src_sz, SZ_64);
        dest_phys = ptr_phys + ALIGN(mem_to_map_sz, SZ_64) + ALIGN(src_sz, SZ_64);
-       for (i = 0; i < dest_cnt; i++) {
-               destvm[i].vmid = cpu_to_le32(newvm[i].vmid);
-               destvm[i].perm = cpu_to_le32(newvm[i].perm);
-               destvm[i].ctx = 0;
-               destvm[i].ctx_size = 0;
-               next_vm |= BIT(newvm[i].vmid);
+       for (i = 0; i < dest_cnt; i++, destvm++, newvm++) {
+               destvm->vmid = cpu_to_le32(newvm->vmid);
+               destvm->perm = cpu_to_le32(newvm->perm);
+               destvm->ctx = 0;
+               destvm->ctx_size = 0;
+               next_vm |= BIT(newvm->vmid);
        }
 
        ret = __qcom_scm_assign_mem(__scm->dev, mem_to_map_phys, mem_to_map_sz,
                                    ptr_phys, src_sz, dest_phys, dest_sz);
-       dma_free_coherent(__scm->dev, ALIGN(ptr_sz, SZ_64), ptr, ptr_phys);
+       dma_free_coherent(__scm->dev, ptr_sz, ptr, ptr_dma);
        if (ret) {
                dev_err(__scm->dev,
-                       "Assign memory protection call failed %d.\n", ret);
+                       "Assign memory protection call failed %d\n", ret);
                return -EINVAL;
        }
 
index cdee0b4..4126be9 100644 (file)
@@ -635,6 +635,7 @@ fail:
 
 /**
  * ti_sci_cmd_get_device() - command to request for device managed by TISCI
+ *                          that can be shared with other hosts.
  * @handle:    Pointer to TISCI handle as retrieved by *ti_sci_get_handle
  * @id:                Device Identifier
  *
@@ -642,11 +643,29 @@ fail:
  * usage count by balancing get_device with put_device. No refcounting is
  * managed by driver for that purpose.
  *
- * NOTE: The request is for exclusive access for the processor.
- *
  * Return: 0 if all went fine, else return appropriate error.
  */
 static int ti_sci_cmd_get_device(const struct ti_sci_handle *handle, u32 id)
+{
+       return ti_sci_set_device_state(handle, id, 0,
+                                      MSG_DEVICE_SW_STATE_ON);
+}
+
+/**
+ * ti_sci_cmd_get_device_exclusive() - command to request for device managed by
+ *                                    TISCI that is exclusively owned by the
+ *                                    requesting host.
+ * @handle:    Pointer to TISCI handle as retrieved by *ti_sci_get_handle
+ * @id:                Device Identifier
+ *
+ * Request for the device - NOTE: the client MUST maintain integrity of
+ * usage count by balancing get_device with put_device. No refcounting is
+ * managed by driver for that purpose.
+ *
+ * Return: 0 if all went fine, else return appropriate error.
+ */
+static int ti_sci_cmd_get_device_exclusive(const struct ti_sci_handle *handle,
+                                          u32 id)
 {
        return ti_sci_set_device_state(handle, id,
                                       MSG_FLAG_DEVICE_EXCLUSIVE,
@@ -665,6 +684,26 @@ static int ti_sci_cmd_get_device(const struct ti_sci_handle *handle, u32 id)
  * Return: 0 if all went fine, else return appropriate error.
  */
 static int ti_sci_cmd_idle_device(const struct ti_sci_handle *handle, u32 id)
+{
+       return ti_sci_set_device_state(handle, id, 0,
+                                      MSG_DEVICE_SW_STATE_RETENTION);
+}
+
+/**
+ * ti_sci_cmd_idle_device_exclusive() - Command to idle a device managed by
+ *                                     TISCI that is exclusively owned by
+ *                                     requesting host.
+ * @handle:    Pointer to TISCI handle as retrieved by *ti_sci_get_handle
+ * @id:                Device Identifier
+ *
+ * Request for the device - NOTE: the client MUST maintain integrity of
+ * usage count by balancing get_device with put_device. No refcounting is
+ * managed by driver for that purpose.
+ *
+ * Return: 0 if all went fine, else return appropriate error.
+ */
+static int ti_sci_cmd_idle_device_exclusive(const struct ti_sci_handle *handle,
+                                           u32 id)
 {
        return ti_sci_set_device_state(handle, id,
                                       MSG_FLAG_DEVICE_EXCLUSIVE,
@@ -2894,7 +2933,9 @@ static void ti_sci_setup_ops(struct ti_sci_info *info)
        core_ops->reboot_device = ti_sci_cmd_core_reboot;
 
        dops->get_device = ti_sci_cmd_get_device;
+       dops->get_device_exclusive = ti_sci_cmd_get_device_exclusive;
        dops->idle_device = ti_sci_cmd_idle_device;
+       dops->idle_device_exclusive = ti_sci_cmd_idle_device_exclusive;
        dops->put_device = ti_sci_cmd_put_device;
 
        dops->is_valid = ti_sci_cmd_dev_is_valid;
diff --git a/drivers/firmware/turris-mox-rwtm.c b/drivers/firmware/turris-mox-rwtm.c
new file mode 100644 (file)
index 0000000..72be589
--- /dev/null
@@ -0,0 +1,384 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Turris Mox rWTM firmware driver
+ *
+ * Copyright (C) 2019 Marek Behun <marek.behun@nic.cz>
+ */
+
+#include <linux/armada-37xx-rwtm-mailbox.h>
+#include <linux/completion.h>
+#include <linux/dma-mapping.h>
+#include <linux/hw_random.h>
+#include <linux/mailbox_client.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define DRIVER_NAME            "turris-mox-rwtm"
+
+/*
+ * The macros and constants below come from Turris Mox's rWTM firmware code.
+ * This firmware is open source and it's sources can be found at
+ * https://gitlab.labs.nic.cz/turris/mox-boot-builder/tree/master/wtmi.
+ */
+
+#define MBOX_STS_SUCCESS       (0 << 30)
+#define MBOX_STS_FAIL          (1 << 30)
+#define MBOX_STS_BADCMD                (2 << 30)
+#define MBOX_STS_ERROR(s)      ((s) & (3 << 30))
+#define MBOX_STS_VALUE(s)      (((s) >> 10) & 0xfffff)
+#define MBOX_STS_CMD(s)                ((s) & 0x3ff)
+
+enum mbox_cmd {
+       MBOX_CMD_GET_RANDOM     = 1,
+       MBOX_CMD_BOARD_INFO     = 2,
+       MBOX_CMD_ECDSA_PUB_KEY  = 3,
+       MBOX_CMD_HASH           = 4,
+       MBOX_CMD_SIGN           = 5,
+       MBOX_CMD_VERIFY         = 6,
+
+       MBOX_CMD_OTP_READ       = 7,
+       MBOX_CMD_OTP_WRITE      = 8,
+};
+
+struct mox_kobject;
+
+struct mox_rwtm {
+       struct device *dev;
+       struct mbox_client mbox_client;
+       struct mbox_chan *mbox;
+       struct mox_kobject *kobj;
+       struct hwrng hwrng;
+
+       struct armada_37xx_rwtm_rx_msg reply;
+
+       void *buf;
+       dma_addr_t buf_phys;
+
+       struct mutex busy;
+       struct completion cmd_done;
+
+       /* board information */
+       int has_board_info;
+       u64 serial_number;
+       int board_version, ram_size;
+       u8 mac_address1[6], mac_address2[6];
+
+       /* public key burned in eFuse */
+       int has_pubkey;
+       u8 pubkey[135];
+};
+
+struct mox_kobject {
+       struct kobject kobj;
+       struct mox_rwtm *rwtm;
+};
+
+static inline struct kobject *rwtm_to_kobj(struct mox_rwtm *rwtm)
+{
+       return &rwtm->kobj->kobj;
+}
+
+static inline struct mox_rwtm *to_rwtm(struct kobject *kobj)
+{
+       return container_of(kobj, struct mox_kobject, kobj)->rwtm;
+}
+
+static void mox_kobj_release(struct kobject *kobj)
+{
+       kfree(to_rwtm(kobj)->kobj);
+}
+
+static struct kobj_type mox_kobj_ktype = {
+       .release        = mox_kobj_release,
+       .sysfs_ops      = &kobj_sysfs_ops,
+};
+
+static int mox_kobj_create(struct mox_rwtm *rwtm)
+{
+       rwtm->kobj = kzalloc(sizeof(*rwtm->kobj), GFP_KERNEL);
+       if (!rwtm->kobj)
+               return -ENOMEM;
+
+       kobject_init(rwtm_to_kobj(rwtm), &mox_kobj_ktype);
+       if (kobject_add(rwtm_to_kobj(rwtm), firmware_kobj, "turris-mox-rwtm")) {
+               kobject_put(rwtm_to_kobj(rwtm));
+               return -ENXIO;
+       }
+
+       rwtm->kobj->rwtm = rwtm;
+
+       return 0;
+}
+
+#define MOX_ATTR_RO(name, format, cat)                         \
+static ssize_t                                                 \
+name##_show(struct kobject *kobj, struct kobj_attribute *a,    \
+           char *buf)                                          \
+{                                                              \
+       struct mox_rwtm *rwtm = to_rwtm(kobj);  \
+       if (!rwtm->has_##cat)                                   \
+               return -ENODATA;                                \
+       return sprintf(buf, format, rwtm->name);                \
+}                                                              \
+static struct kobj_attribute mox_attr_##name = __ATTR_RO(name)
+
+MOX_ATTR_RO(serial_number, "%016llX\n", board_info);
+MOX_ATTR_RO(board_version, "%i\n", board_info);
+MOX_ATTR_RO(ram_size, "%i\n", board_info);
+MOX_ATTR_RO(mac_address1, "%pM\n", board_info);
+MOX_ATTR_RO(mac_address2, "%pM\n", board_info);
+MOX_ATTR_RO(pubkey, "%s\n", pubkey);
+
+static int mox_get_status(enum mbox_cmd cmd, u32 retval)
+{
+       if (MBOX_STS_CMD(retval) != cmd ||
+           MBOX_STS_ERROR(retval) != MBOX_STS_SUCCESS)
+               return -EIO;
+       else if (MBOX_STS_ERROR(retval) == MBOX_STS_FAIL)
+               return -(int)MBOX_STS_VALUE(retval);
+       else
+               return MBOX_STS_VALUE(retval);
+}
+
+static const struct attribute *mox_rwtm_attrs[] = {
+       &mox_attr_serial_number.attr,
+       &mox_attr_board_version.attr,
+       &mox_attr_ram_size.attr,
+       &mox_attr_mac_address1.attr,
+       &mox_attr_mac_address2.attr,
+       &mox_attr_pubkey.attr,
+       NULL
+};
+
+static void mox_rwtm_rx_callback(struct mbox_client *cl, void *data)
+{
+       struct mox_rwtm *rwtm = dev_get_drvdata(cl->dev);
+       struct armada_37xx_rwtm_rx_msg *msg = data;
+
+       rwtm->reply = *msg;
+       complete(&rwtm->cmd_done);
+}
+
+static void reply_to_mac_addr(u8 *mac, u32 t1, u32 t2)
+{
+       mac[0] = t1 >> 8;
+       mac[1] = t1;
+       mac[2] = t2 >> 24;
+       mac[3] = t2 >> 16;
+       mac[4] = t2 >> 8;
+       mac[5] = t2;
+}
+
+static int mox_get_board_info(struct mox_rwtm *rwtm)
+{
+       struct armada_37xx_rwtm_tx_msg msg;
+       struct armada_37xx_rwtm_rx_msg *reply = &rwtm->reply;
+       int ret;
+
+       msg.command = MBOX_CMD_BOARD_INFO;
+       ret = mbox_send_message(rwtm->mbox, &msg);
+       if (ret < 0)
+               return ret;
+
+       ret = wait_for_completion_timeout(&rwtm->cmd_done, HZ / 2);
+       if (ret < 0)
+               return ret;
+
+       ret = mox_get_status(MBOX_CMD_BOARD_INFO, reply->retval);
+       if (ret < 0 && ret != -ENODATA) {
+               return ret;
+       } else if (ret == -ENODATA) {
+               dev_warn(rwtm->dev,
+                        "Board does not have manufacturing information burned!\n");
+       } else {
+               rwtm->serial_number = reply->status[1];
+               rwtm->serial_number <<= 32;
+               rwtm->serial_number |= reply->status[0];
+                       rwtm->board_version = reply->status[2];
+               rwtm->ram_size = reply->status[3];
+               reply_to_mac_addr(rwtm->mac_address1, reply->status[4],
+                                 reply->status[5]);
+               reply_to_mac_addr(rwtm->mac_address2, reply->status[6],
+                                 reply->status[7]);
+               rwtm->has_board_info = 1;
+
+               pr_info("Turris Mox serial number %016llX\n",
+                       rwtm->serial_number);
+               pr_info("           board version %i\n", rwtm->board_version);
+               pr_info("           burned RAM size %i MiB\n", rwtm->ram_size);
+       }
+
+       msg.command = MBOX_CMD_ECDSA_PUB_KEY;
+       ret = mbox_send_message(rwtm->mbox, &msg);
+       if (ret < 0)
+               return ret;
+
+       ret = wait_for_completion_timeout(&rwtm->cmd_done, HZ / 2);
+       if (ret < 0)
+               return ret;
+
+       ret = mox_get_status(MBOX_CMD_ECDSA_PUB_KEY, reply->retval);
+       if (ret < 0 && ret != -ENODATA) {
+               return ret;
+       } else if (ret == -ENODATA) {
+               dev_warn(rwtm->dev, "Board has no public key burned!\n");
+       } else {
+               u32 *s = reply->status;
+
+               rwtm->has_pubkey = 1;
+               sprintf(rwtm->pubkey,
+                       "%06x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x",
+                       ret, s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7],
+                       s[8], s[9], s[10], s[11], s[12], s[13], s[14], s[15]);
+       }
+
+       return 0;
+}
+
+static int mox_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait)
+{
+       struct mox_rwtm *rwtm = (struct mox_rwtm *) rng->priv;
+       struct armada_37xx_rwtm_tx_msg msg;
+       int ret;
+
+       if (max > 4096)
+               max = 4096;
+
+       msg.command = MBOX_CMD_GET_RANDOM;
+       msg.args[0] = 1;
+       msg.args[1] = rwtm->buf_phys;
+       msg.args[2] = (max + 3) & ~3;
+
+       if (!wait) {
+               if (!mutex_trylock(&rwtm->busy))
+                       return -EBUSY;
+       } else {
+               mutex_lock(&rwtm->busy);
+       }
+
+       ret = mbox_send_message(rwtm->mbox, &msg);
+       if (ret < 0)
+               goto unlock_mutex;
+
+       ret = wait_for_completion_interruptible(&rwtm->cmd_done);
+       if (ret < 0)
+               goto unlock_mutex;
+
+       ret = mox_get_status(MBOX_CMD_GET_RANDOM, rwtm->reply.retval);
+       if (ret < 0)
+               goto unlock_mutex;
+
+       memcpy(data, rwtm->buf, max);
+       ret = max;
+
+unlock_mutex:
+       mutex_unlock(&rwtm->busy);
+       return ret;
+}
+
+static int turris_mox_rwtm_probe(struct platform_device *pdev)
+{
+       struct mox_rwtm *rwtm;
+       struct device *dev = &pdev->dev;
+       int ret;
+
+       rwtm = devm_kzalloc(dev, sizeof(*rwtm), GFP_KERNEL);
+       if (!rwtm)
+               return -ENOMEM;
+
+       rwtm->dev = dev;
+       rwtm->buf = dmam_alloc_coherent(dev, PAGE_SIZE, &rwtm->buf_phys,
+                                       GFP_KERNEL);
+       if (!rwtm->buf)
+               return -ENOMEM;
+
+       ret = mox_kobj_create(rwtm);
+       if (ret < 0) {
+               dev_err(dev, "Cannot create turris-mox-rwtm kobject!\n");
+               return ret;
+       }
+
+       ret = sysfs_create_files(rwtm_to_kobj(rwtm), mox_rwtm_attrs);
+       if (ret < 0) {
+               dev_err(dev, "Cannot create sysfs files!\n");
+               goto put_kobj;
+       }
+
+       platform_set_drvdata(pdev, rwtm);
+
+       mutex_init(&rwtm->busy);
+
+       rwtm->mbox_client.dev = dev;
+       rwtm->mbox_client.rx_callback = mox_rwtm_rx_callback;
+
+       rwtm->mbox = mbox_request_channel(&rwtm->mbox_client, 0);
+       if (IS_ERR(rwtm->mbox)) {
+               ret = PTR_ERR(rwtm->mbox);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(dev, "Cannot request mailbox channel: %i\n",
+                               ret);
+               goto remove_files;
+       }
+
+       init_completion(&rwtm->cmd_done);
+
+       ret = mox_get_board_info(rwtm);
+       if (ret < 0)
+               dev_warn(dev, "Cannot read board information: %i\n", ret);
+
+       rwtm->hwrng.name = DRIVER_NAME "_hwrng";
+       rwtm->hwrng.read = mox_hwrng_read;
+       rwtm->hwrng.priv = (unsigned long) rwtm;
+       rwtm->hwrng.quality = 1024;
+
+       ret = devm_hwrng_register(dev, &rwtm->hwrng);
+       if (ret < 0) {
+               dev_err(dev, "Cannot register HWRNG: %i\n", ret);
+               goto free_channel;
+       }
+
+       return 0;
+
+free_channel:
+       mbox_free_channel(rwtm->mbox);
+remove_files:
+       sysfs_remove_files(rwtm_to_kobj(rwtm), mox_rwtm_attrs);
+put_kobj:
+       kobject_put(rwtm_to_kobj(rwtm));
+       return ret;
+}
+
+static int turris_mox_rwtm_remove(struct platform_device *pdev)
+{
+       struct mox_rwtm *rwtm = platform_get_drvdata(pdev);
+
+       sysfs_remove_files(rwtm_to_kobj(rwtm), mox_rwtm_attrs);
+       kobject_put(rwtm_to_kobj(rwtm));
+       mbox_free_channel(rwtm->mbox);
+
+       return 0;
+}
+
+static const struct of_device_id turris_mox_rwtm_match[] = {
+       { .compatible = "cznic,turris-mox-rwtm", },
+       { },
+};
+
+MODULE_DEVICE_TABLE(of, turris_mox_rwtm_match);
+
+static struct platform_driver turris_mox_rwtm_driver = {
+       .probe  = turris_mox_rwtm_probe,
+       .remove = turris_mox_rwtm_remove,
+       .driver = {
+               .name           = DRIVER_NAME,
+               .of_match_table = turris_mox_rwtm_match,
+       },
+};
+module_platform_driver(turris_mox_rwtm_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Turris Mox rWTM firmware driver");
+MODULE_AUTHOR("Marek Behun <marek.behun@nic.cz>");
index 305b47e..38e096e 100644 (file)
@@ -1453,6 +1453,15 @@ config GPIO_XRA1403
        help
          GPIO driver for EXAR XRA1403 16-bit SPI-based GPIO expander.
 
+config GPIO_MOXTET
+       tristate "Turris Mox Moxtet bus GPIO expander"
+       depends on MOXTET
+       help
+         Say yes here if you are building for the Turris Mox router.
+         This is the driver needed for configuring the GPIOs via the Moxtet
+         bus. For example the Mox module with SFP cage needs this driver
+         so that phylink can use corresponding GPIOs.
+
 endmenu
 
 menu "USB GPIO expanders"
index f3e051f..d2fd19c 100644 (file)
@@ -92,6 +92,7 @@ obj-$(CONFIG_GPIO_ML_IOH)             += gpio-ml-ioh.o
 obj-$(CONFIG_GPIO_MLXBF)               += gpio-mlxbf.o
 obj-$(CONFIG_GPIO_MM_LANTIQ)           += gpio-mm-lantiq.o
 obj-$(CONFIG_GPIO_MOCKUP)              += gpio-mockup.o
+obj-$(CONFIG_GPIO_MOXTET)              += gpio-moxtet.o
 obj-$(CONFIG_GPIO_MPC5200)             += gpio-mpc5200.o
 obj-$(CONFIG_GPIO_MPC8XXX)             += gpio-mpc8xxx.o
 obj-$(CONFIG_GPIO_MSIC)                        += gpio-msic.o
diff --git a/drivers/gpio/gpio-moxtet.c b/drivers/gpio/gpio-moxtet.c
new file mode 100644 (file)
index 0000000..3fd7299
--- /dev/null
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *  Turris Mox Moxtet GPIO expander
+ *
+ *  Copyright (C) 2018 Marek Behun <marek.behun@nic.cz>
+ */
+
+#include <linux/bitops.h>
+#include <linux/gpio/driver.h>
+#include <linux/moxtet.h>
+#include <linux/module.h>
+
+#define MOXTET_GPIO_NGPIOS     12
+#define MOXTET_GPIO_INPUTS     4
+
+struct moxtet_gpio_desc {
+       u16 in_mask;
+       u16 out_mask;
+};
+
+static const struct moxtet_gpio_desc descs[] = {
+       [TURRIS_MOX_MODULE_SFP] = {
+               .in_mask = GENMASK(2, 0),
+               .out_mask = GENMASK(5, 4),
+       },
+};
+
+struct moxtet_gpio_chip {
+       struct device                   *dev;
+       struct gpio_chip                gpio_chip;
+       const struct moxtet_gpio_desc   *desc;
+};
+
+static int moxtet_gpio_get_value(struct gpio_chip *gc, unsigned int offset)
+{
+       struct moxtet_gpio_chip *chip = gpiochip_get_data(gc);
+       int ret;
+
+       if (chip->desc->in_mask & BIT(offset)) {
+               ret = moxtet_device_read(chip->dev);
+       } else if (chip->desc->out_mask & BIT(offset)) {
+               ret = moxtet_device_written(chip->dev);
+               if (ret >= 0)
+                       ret <<= MOXTET_GPIO_INPUTS;
+       } else {
+               return -EINVAL;
+       }
+
+       if (ret < 0)
+               return ret;
+
+       return !!(ret & BIT(offset));
+}
+
+static void moxtet_gpio_set_value(struct gpio_chip *gc, unsigned int offset,
+                                 int val)
+{
+       struct moxtet_gpio_chip *chip = gpiochip_get_data(gc);
+       int state;
+
+       state = moxtet_device_written(chip->dev);
+       if (state < 0)
+               return;
+
+       offset -= MOXTET_GPIO_INPUTS;
+
+       if (val)
+               state |= BIT(offset);
+       else
+               state &= ~BIT(offset);
+
+       moxtet_device_write(chip->dev, state);
+}
+
+static int moxtet_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+       struct moxtet_gpio_chip *chip = gpiochip_get_data(gc);
+
+       /* All lines are hard wired to be either input or output, not both. */
+       if (chip->desc->in_mask & BIT(offset))
+               return 1;
+       else if (chip->desc->out_mask & BIT(offset))
+               return 0;
+       else
+               return -EINVAL;
+}
+
+static int moxtet_gpio_direction_input(struct gpio_chip *gc,
+                                      unsigned int offset)
+{
+       struct moxtet_gpio_chip *chip = gpiochip_get_data(gc);
+
+       if (chip->desc->in_mask & BIT(offset))
+               return 0;
+       else if (chip->desc->out_mask & BIT(offset))
+               return -ENOTSUPP;
+       else
+               return -EINVAL;
+}
+
+static int moxtet_gpio_direction_output(struct gpio_chip *gc,
+                                       unsigned int offset, int val)
+{
+       struct moxtet_gpio_chip *chip = gpiochip_get_data(gc);
+
+       if (chip->desc->out_mask & BIT(offset))
+               moxtet_gpio_set_value(gc, offset, val);
+       else if (chip->desc->in_mask & BIT(offset))
+               return -ENOTSUPP;
+       else
+               return -EINVAL;
+
+       return 0;
+}
+
+static int moxtet_gpio_probe(struct device *dev)
+{
+       struct moxtet_gpio_chip *chip;
+       struct device_node *nc = dev->of_node;
+       int id;
+
+       id = to_moxtet_device(dev)->id;
+
+       if (id >= ARRAY_SIZE(descs)) {
+               dev_err(dev, "%pOF Moxtet device id 0x%x is not supported by gpio-moxtet driver\n",
+                       nc, id);
+               return -ENOTSUPP;
+       }
+
+       chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+
+       chip->dev = dev;
+       chip->gpio_chip.parent = dev;
+       chip->desc = &descs[id];
+
+       dev_set_drvdata(dev, chip);
+
+       chip->gpio_chip.label = dev_name(dev);
+       chip->gpio_chip.get_direction = moxtet_gpio_get_direction;
+       chip->gpio_chip.direction_input = moxtet_gpio_direction_input;
+       chip->gpio_chip.direction_output = moxtet_gpio_direction_output;
+       chip->gpio_chip.get = moxtet_gpio_get_value;
+       chip->gpio_chip.set = moxtet_gpio_set_value;
+       chip->gpio_chip.base = -1;
+
+       chip->gpio_chip.ngpio = MOXTET_GPIO_NGPIOS;
+
+       chip->gpio_chip.can_sleep = true;
+       chip->gpio_chip.owner = THIS_MODULE;
+
+       return devm_gpiochip_add_data(dev, &chip->gpio_chip, chip);
+}
+
+static const struct of_device_id moxtet_gpio_dt_ids[] = {
+       { .compatible = "cznic,moxtet-gpio", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, moxtet_gpio_dt_ids);
+
+static const enum turris_mox_module_id moxtet_gpio_module_table[] = {
+       TURRIS_MOX_MODULE_SFP,
+       0,
+};
+
+static struct moxtet_driver moxtet_gpio_driver = {
+       .driver = {
+               .name           = "moxtet-gpio",
+               .of_match_table = moxtet_gpio_dt_ids,
+               .probe          = moxtet_gpio_probe,
+       },
+       .id_table = moxtet_gpio_module_table,
+};
+module_moxtet_driver(moxtet_gpio_driver);
+
+MODULE_AUTHOR("Marek Behun <marek.behun@nic.cz>");
+MODULE_DESCRIPTION("Turris Mox Moxtet GPIO expander");
+MODULE_LICENSE("GPL v2");
index 0c93fc5..8a7732c 100644 (file)
@@ -72,7 +72,7 @@ static int scmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
        const struct scmi_handle *h = scmi_sensors->handle;
 
        sensor = *(scmi_sensors->info[type] + channel);
-       ret = h->sensor_ops->reading_get(h, sensor->id, false, &value);
+       ret = h->sensor_ops->reading_get(h, sensor->id, &value);
        if (ret)
                return ret;
 
index 93a2d4d..dc9dee5 100644 (file)
@@ -151,7 +151,6 @@ config NET_NETX
          To compile this driver as a module, choose M here. The module
          will be called netx-eth.
 
-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"
index fb9155c..4bc3c95 100644 (file)
@@ -65,7 +65,6 @@ obj-$(CONFIG_NET_VENDOR_NETERION) += neterion/
 obj-$(CONFIG_NET_VENDOR_NETRONOME) += netronome/
 obj-$(CONFIG_NET_VENDOR_NI) += ni/
 obj-$(CONFIG_NET_NETX) += netx-eth.o
-obj-$(CONFIG_NET_VENDOR_NUVOTON) += nuvoton/
 obj-$(CONFIG_NET_VENDOR_NVIDIA) += nvidia/
 obj-$(CONFIG_LPC_ENET) += nxp/
 obj-$(CONFIG_NET_VENDOR_OKI) += oki-semi/
index 90a8c6b..b9c4d48 100644 (file)
@@ -6,8 +6,7 @@
 config NET_VENDOR_MICREL
        bool "Micrel devices"
        default y
-       depends on (HAS_IOMEM && DMA_ENGINE) || SPI || PCI || HAS_IOMEM || \
-                  (ARM && ARCH_KS8695)
+       depends on (HAS_IOMEM && DMA_ENGINE) || SPI || PCI || HAS_IOMEM
        ---help---
          If you have a network (Ethernet) card belonging to this class, say Y.
 
@@ -18,14 +17,6 @@ config NET_VENDOR_MICREL
 
 if NET_VENDOR_MICREL
 
-config ARM_KS8695_ETHER
-       tristate "KS8695 Ethernet support"
-       depends on ARM && ARCH_KS8695
-       select MII
-       ---help---
-         If you wish to compile a kernel for the KS8695 and want to
-         use the internal ethernet then you should answer Y to this.
-
 config KS8842
        tristate "Micrel KSZ8841/42 with generic bus interface"
        depends on HAS_IOMEM && DMA_ENGINE
index 848fc1c..6d8ac55 100644 (file)
@@ -3,7 +3,6 @@
 # Makefile for the Micrel network device drivers.
 #
 
-obj-$(CONFIG_ARM_KS8695_ETHER) += ks8695net.o
 obj-$(CONFIG_KS8842) += ks8842.o
 obj-$(CONFIG_KS8851) += ks8851.o
 obj-$(CONFIG_KS8851_MLL) += ks8851_mll.o
diff --git a/drivers/net/ethernet/micrel/ks8695net.c b/drivers/net/ethernet/micrel/ks8695net.c
deleted file mode 100644 (file)
index 1390ef5..0000000
+++ /dev/null
@@ -1,1632 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Micrel KS8695 (Centaur) Ethernet.
- *
- * Copyright 2008 Simtec Electronics
- *               Daniel Silverstone <dsilvers@simtec.co.uk>
- *               Vincent Sanders <vince@simtec.co.uk>
- */
-
-#include <linux/dma-mapping.h>
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/interrupt.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
-#include <linux/crc32.h>
-#include <linux/mii.h>
-#include <linux/ethtool.h>
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-
-#include <asm/irq.h>
-
-#include <mach/regs-switch.h>
-#include <mach/regs-misc.h>
-#include <asm/mach/irq.h>
-#include <mach/regs-irq.h>
-
-#include "ks8695net.h"
-
-#define MODULENAME     "ks8695_ether"
-#define MODULEVERSION  "1.02"
-
-/*
- * Transmit and device reset timeout, default 5 seconds.
- */
-static int watchdog = 5000;
-
-/* Hardware structures */
-
-/**
- *     struct rx_ring_desc - Receive descriptor ring element
- *     @status: The status of the descriptor element (E.g. who owns it)
- *     @length: The number of bytes in the block pointed to by data_ptr
- *     @data_ptr: The physical address of the data block to receive into
- *     @next_desc: The physical address of the next descriptor element.
- */
-struct rx_ring_desc {
-       __le32  status;
-       __le32  length;
-       __le32  data_ptr;
-       __le32  next_desc;
-};
-
-/**
- *     struct tx_ring_desc - Transmit descriptor ring element
- *     @owner: Who owns the descriptor
- *     @status: The number of bytes in the block pointed to by data_ptr
- *     @data_ptr: The physical address of the data block to receive into
- *     @next_desc: The physical address of the next descriptor element.
- */
-struct tx_ring_desc {
-       __le32  owner;
-       __le32  status;
-       __le32  data_ptr;
-       __le32  next_desc;
-};
-
-/**
- *     struct ks8695_skbuff - sk_buff wrapper for rx/tx rings.
- *     @skb: The buffer in the ring
- *     @dma_ptr: The mapped DMA pointer of the buffer
- *     @length: The number of bytes mapped to dma_ptr
- */
-struct ks8695_skbuff {
-       struct sk_buff  *skb;
-       dma_addr_t      dma_ptr;
-       u32             length;
-};
-
-/* Private device structure */
-
-#define MAX_TX_DESC 8
-#define MAX_TX_DESC_MASK 0x7
-#define MAX_RX_DESC 16
-#define MAX_RX_DESC_MASK 0xf
-
-/*napi_weight have better more than rx DMA buffers*/
-#define NAPI_WEIGHT   64
-
-#define MAX_RXBUF_SIZE 0x700
-
-#define TX_RING_DMA_SIZE (sizeof(struct tx_ring_desc) * MAX_TX_DESC)
-#define RX_RING_DMA_SIZE (sizeof(struct rx_ring_desc) * MAX_RX_DESC)
-#define RING_DMA_SIZE (TX_RING_DMA_SIZE + RX_RING_DMA_SIZE)
-
-/**
- *     enum ks8695_dtype - Device type
- *     @KS8695_DTYPE_WAN: This device is a WAN interface
- *     @KS8695_DTYPE_LAN: This device is a LAN interface
- *     @KS8695_DTYPE_HPNA: This device is an HPNA interface
- */
-enum ks8695_dtype {
-       KS8695_DTYPE_WAN,
-       KS8695_DTYPE_LAN,
-       KS8695_DTYPE_HPNA,
-};
-
-/**
- *     struct ks8695_priv - Private data for the KS8695 Ethernet
- *     @in_suspend: Flag to indicate if we're suspending/resuming
- *     @ndev: The net_device for this interface
- *     @dev: The platform device object for this interface
- *     @dtype: The type of this device
- *     @io_regs: The ioremapped registers for this interface
- *      @napi : Add support NAPI for Rx
- *     @rx_irq_name: The textual name of the RX IRQ from the platform data
- *     @tx_irq_name: The textual name of the TX IRQ from the platform data
- *     @link_irq_name: The textual name of the link IRQ from the
- *                     platform data if available
- *     @rx_irq: The IRQ number for the RX IRQ
- *     @tx_irq: The IRQ number for the TX IRQ
- *     @link_irq: The IRQ number for the link IRQ if available
- *     @regs_req: The resource request for the registers region
- *     @phyiface_req: The resource request for the phy/switch region
- *                    if available
- *     @phyiface_regs: The ioremapped registers for the phy/switch if available
- *     @ring_base: The base pointer of the dma coherent memory for the rings
- *     @ring_base_dma: The DMA mapped equivalent of ring_base
- *     @tx_ring: The pointer in ring_base of the TX ring
- *     @tx_ring_used: The number of slots in the TX ring which are occupied
- *     @tx_ring_next_slot: The next slot to fill in the TX ring
- *     @tx_ring_dma: The DMA mapped equivalent of tx_ring
- *     @tx_buffers: The sk_buff mappings for the TX ring
- *     @txq_lock: A lock to protect the tx_buffers tx_ring_used etc variables
- *     @rx_ring: The pointer in ring_base of the RX ring
- *     @rx_ring_dma: The DMA mapped equivalent of rx_ring
- *     @rx_buffers: The sk_buff mappings for the RX ring
- *     @next_rx_desc_read: The next RX descriptor to read from on IRQ
- *      @rx_lock: A lock to protect Rx irq function
- *     @msg_enable: The flags for which messages to emit
- */
-struct ks8695_priv {
-       int in_suspend;
-       struct net_device *ndev;
-       struct device *dev;
-       enum ks8695_dtype dtype;
-       void __iomem *io_regs;
-
-       struct napi_struct      napi;
-
-       const char *rx_irq_name, *tx_irq_name, *link_irq_name;
-       int rx_irq, tx_irq, link_irq;
-
-       struct resource *regs_req, *phyiface_req;
-       void __iomem *phyiface_regs;
-
-       void *ring_base;
-       dma_addr_t ring_base_dma;
-
-       struct tx_ring_desc *tx_ring;
-       int tx_ring_used;
-       int tx_ring_next_slot;
-       dma_addr_t tx_ring_dma;
-       struct ks8695_skbuff tx_buffers[MAX_TX_DESC];
-       spinlock_t txq_lock;
-
-       struct rx_ring_desc *rx_ring;
-       dma_addr_t rx_ring_dma;
-       struct ks8695_skbuff rx_buffers[MAX_RX_DESC];
-       int next_rx_desc_read;
-       spinlock_t rx_lock;
-
-       int msg_enable;
-};
-
-/* Register access */
-
-/**
- *     ks8695_readreg - Read from a KS8695 ethernet register
- *     @ksp: The device to read from
- *     @reg: The register to read
- */
-static inline u32
-ks8695_readreg(struct ks8695_priv *ksp, int reg)
-{
-       return readl(ksp->io_regs + reg);
-}
-
-/**
- *     ks8695_writereg - Write to a KS8695 ethernet register
- *     @ksp: The device to write to
- *     @reg: The register to write
- *     @value: The value to write to the register
- */
-static inline void
-ks8695_writereg(struct ks8695_priv *ksp, int reg, u32 value)
-{
-       writel(value, ksp->io_regs + reg);
-}
-
-/* Utility functions */
-
-/**
- *     ks8695_port_type - Retrieve port-type as user-friendly string
- *     @ksp: The device to return the type for
- *
- *     Returns a string indicating which of the WAN, LAN or HPNA
- *     ports this device is likely to represent.
- */
-static const char *
-ks8695_port_type(struct ks8695_priv *ksp)
-{
-       switch (ksp->dtype) {
-       case KS8695_DTYPE_LAN:
-               return "LAN";
-       case KS8695_DTYPE_WAN:
-               return "WAN";
-       case KS8695_DTYPE_HPNA:
-               return "HPNA";
-       }
-
-       return "UNKNOWN";
-}
-
-/**
- *     ks8695_update_mac - Update the MAC registers in the device
- *     @ksp: The device to update
- *
- *     Updates the MAC registers in the KS8695 device from the address in the
- *     net_device structure associated with this interface.
- */
-static void
-ks8695_update_mac(struct ks8695_priv *ksp)
-{
-       /* Update the HW with the MAC from the net_device */
-       struct net_device *ndev = ksp->ndev;
-       u32 machigh, maclow;
-
-       maclow  = ((ndev->dev_addr[2] << 24) | (ndev->dev_addr[3] << 16) |
-                  (ndev->dev_addr[4] <<  8) | (ndev->dev_addr[5] <<  0));
-       machigh = ((ndev->dev_addr[0] <<  8) | (ndev->dev_addr[1] <<  0));
-
-       ks8695_writereg(ksp, KS8695_MAL, maclow);
-       ks8695_writereg(ksp, KS8695_MAH, machigh);
-
-}
-
-/**
- *     ks8695_refill_rxbuffers - Re-fill the RX buffer ring
- *     @ksp: The device to refill
- *
- *     Iterates the RX ring of the device looking for empty slots.
- *     For each empty slot, we allocate and map a new SKB and give it
- *     to the hardware.
- *     This can be called from interrupt context safely.
- */
-static void
-ks8695_refill_rxbuffers(struct ks8695_priv *ksp)
-{
-       /* Run around the RX ring, filling in any missing sk_buff's */
-       int buff_n;
-
-       for (buff_n = 0; buff_n < MAX_RX_DESC; ++buff_n) {
-               if (!ksp->rx_buffers[buff_n].skb) {
-                       struct sk_buff *skb =
-                               netdev_alloc_skb(ksp->ndev, MAX_RXBUF_SIZE);
-                       dma_addr_t mapping;
-
-                       ksp->rx_buffers[buff_n].skb = skb;
-                       if (skb == NULL) {
-                               /* Failed to allocate one, perhaps
-                                * we'll try again later.
-                                */
-                               break;
-                       }
-
-                       mapping = dma_map_single(ksp->dev, skb->data,
-                                                MAX_RXBUF_SIZE,
-                                                DMA_FROM_DEVICE);
-                       if (unlikely(dma_mapping_error(ksp->dev, mapping))) {
-                               /* Failed to DMA map this SKB, try later */
-                               dev_kfree_skb_irq(skb);
-                               ksp->rx_buffers[buff_n].skb = NULL;
-                               break;
-                       }
-                       ksp->rx_buffers[buff_n].dma_ptr = mapping;
-                       ksp->rx_buffers[buff_n].length = MAX_RXBUF_SIZE;
-
-                       /* Record this into the DMA ring */
-                       ksp->rx_ring[buff_n].data_ptr = cpu_to_le32(mapping);
-                       ksp->rx_ring[buff_n].length =
-                               cpu_to_le32(MAX_RXBUF_SIZE);
-
-                       wmb();
-
-                       /* And give ownership over to the hardware */
-                       ksp->rx_ring[buff_n].status = cpu_to_le32(RDES_OWN);
-               }
-       }
-}
-
-/* Maximum number of multicast addresses which the KS8695 HW supports */
-#define KS8695_NR_ADDRESSES    16
-
-/**
- *     ks8695_init_partial_multicast - Init the mcast addr registers
- *     @ksp: The device to initialise
- *     @addr: The multicast address list to use
- *     @nr_addr: The number of addresses in the list
- *
- *     This routine is a helper for ks8695_set_multicast - it writes
- *     the additional-address registers in the KS8695 ethernet device
- *     and cleans up any others left behind.
- */
-static void
-ks8695_init_partial_multicast(struct ks8695_priv *ksp,
-                             struct net_device *ndev)
-{
-       u32 low, high;
-       int i;
-       struct netdev_hw_addr *ha;
-
-       i = 0;
-       netdev_for_each_mc_addr(ha, ndev) {
-               /* Ran out of space in chip? */
-               BUG_ON(i == KS8695_NR_ADDRESSES);
-
-               low = (ha->addr[2] << 24) | (ha->addr[3] << 16) |
-                     (ha->addr[4] << 8) | (ha->addr[5]);
-               high = (ha->addr[0] << 8) | (ha->addr[1]);
-
-               ks8695_writereg(ksp, KS8695_AAL_(i), low);
-               ks8695_writereg(ksp, KS8695_AAH_(i), AAH_E | high);
-               i++;
-       }
-
-       /* Clear the remaining Additional Station Addresses */
-       for (; i < KS8695_NR_ADDRESSES; i++) {
-               ks8695_writereg(ksp, KS8695_AAL_(i), 0);
-               ks8695_writereg(ksp, KS8695_AAH_(i), 0);
-       }
-}
-
-/* Interrupt handling */
-
-/**
- *     ks8695_tx_irq - Transmit IRQ handler
- *     @irq: The IRQ which went off (ignored)
- *     @dev_id: The net_device for the interrupt
- *
- *     Process the TX ring, clearing out any transmitted slots.
- *     Allows the net_device to pass us new packets once slots are
- *     freed.
- */
-static irqreturn_t
-ks8695_tx_irq(int irq, void *dev_id)
-{
-       struct net_device *ndev = (struct net_device *)dev_id;
-       struct ks8695_priv *ksp = netdev_priv(ndev);
-       int buff_n;
-
-       for (buff_n = 0; buff_n < MAX_TX_DESC; ++buff_n) {
-               if (ksp->tx_buffers[buff_n].skb &&
-                   !(ksp->tx_ring[buff_n].owner & cpu_to_le32(TDES_OWN))) {
-                       rmb();
-                       /* An SKB which is not owned by HW is present */
-                       /* Update the stats for the net_device */
-                       ndev->stats.tx_packets++;
-                       ndev->stats.tx_bytes += ksp->tx_buffers[buff_n].length;
-
-                       /* Free the packet from the ring */
-                       ksp->tx_ring[buff_n].data_ptr = 0;
-
-                       /* Free the sk_buff */
-                       dma_unmap_single(ksp->dev,
-                                        ksp->tx_buffers[buff_n].dma_ptr,
-                                        ksp->tx_buffers[buff_n].length,
-                                        DMA_TO_DEVICE);
-                       dev_consume_skb_irq(ksp->tx_buffers[buff_n].skb);
-                       ksp->tx_buffers[buff_n].skb = NULL;
-                       ksp->tx_ring_used--;
-               }
-       }
-
-       netif_wake_queue(ndev);
-
-       return IRQ_HANDLED;
-}
-
-/**
- *     ks8695_get_rx_enable_bit - Get rx interrupt enable/status bit
- *     @ksp: Private data for the KS8695 Ethernet
- *
- *    For KS8695 document:
- *    Interrupt Enable Register (offset 0xE204)
- *        Bit29 : WAN MAC Receive Interrupt Enable
- *        Bit16 : LAN MAC Receive Interrupt Enable
- *    Interrupt Status Register (Offset 0xF208)
- *        Bit29: WAN MAC Receive Status
- *        Bit16: LAN MAC Receive Status
- *    So, this Rx interrupt enable/status bit number is equal
- *    as Rx IRQ number.
- */
-static inline u32 ks8695_get_rx_enable_bit(struct ks8695_priv *ksp)
-{
-       return ksp->rx_irq;
-}
-
-/**
- *     ks8695_rx_irq - Receive IRQ handler
- *     @irq: The IRQ which went off (ignored)
- *     @dev_id: The net_device for the interrupt
- *
- *     Inform NAPI that packet reception needs to be scheduled
- */
-
-static irqreturn_t
-ks8695_rx_irq(int irq, void *dev_id)
-{
-       struct net_device *ndev = (struct net_device *)dev_id;
-       struct ks8695_priv *ksp = netdev_priv(ndev);
-
-       spin_lock(&ksp->rx_lock);
-
-       if (napi_schedule_prep(&ksp->napi)) {
-               unsigned long status = readl(KS8695_IRQ_VA + KS8695_INTEN);
-               unsigned long mask_bit = 1 << ks8695_get_rx_enable_bit(ksp);
-               /*disable rx interrupt*/
-               status &= ~mask_bit;
-               writel(status , KS8695_IRQ_VA + KS8695_INTEN);
-               __napi_schedule(&ksp->napi);
-       }
-
-       spin_unlock(&ksp->rx_lock);
-       return IRQ_HANDLED;
-}
-
-/**
- *     ks8695_rx - Receive packets called by NAPI poll method
- *     @ksp: Private data for the KS8695 Ethernet
- *     @budget: Number of packets allowed to process
- */
-static int ks8695_rx(struct ks8695_priv *ksp, int budget)
-{
-       struct net_device *ndev = ksp->ndev;
-       struct sk_buff *skb;
-       int buff_n;
-       u32 flags;
-       int pktlen;
-       int received = 0;
-
-       buff_n = ksp->next_rx_desc_read;
-       while (received < budget
-                       && ksp->rx_buffers[buff_n].skb
-                       && (!(ksp->rx_ring[buff_n].status &
-                                       cpu_to_le32(RDES_OWN)))) {
-                       rmb();
-                       flags = le32_to_cpu(ksp->rx_ring[buff_n].status);
-
-                       /* Found an SKB which we own, this means we
-                        * received a packet
-                        */
-                       if ((flags & (RDES_FS | RDES_LS)) !=
-                           (RDES_FS | RDES_LS)) {
-                               /* This packet is not the first and
-                                * the last segment.  Therefore it is
-                                * a "spanning" packet and we can't
-                                * handle it
-                                */
-                               goto rx_failure;
-                       }
-
-                       if (flags & (RDES_ES | RDES_RE)) {
-                               /* It's an error packet */
-                               ndev->stats.rx_errors++;
-                               if (flags & RDES_TL)
-                                       ndev->stats.rx_length_errors++;
-                               if (flags & RDES_RF)
-                                       ndev->stats.rx_length_errors++;
-                               if (flags & RDES_CE)
-                                       ndev->stats.rx_crc_errors++;
-                               if (flags & RDES_RE)
-                                       ndev->stats.rx_missed_errors++;
-
-                               goto rx_failure;
-                       }
-
-                       pktlen = flags & RDES_FLEN;
-                       pktlen -= 4; /* Drop the CRC */
-
-                       /* Retrieve the sk_buff */
-                       skb = ksp->rx_buffers[buff_n].skb;
-
-                       /* Clear it from the ring */
-                       ksp->rx_buffers[buff_n].skb = NULL;
-                       ksp->rx_ring[buff_n].data_ptr = 0;
-
-                       /* Unmap the SKB */
-                       dma_unmap_single(ksp->dev,
-                                        ksp->rx_buffers[buff_n].dma_ptr,
-                                        ksp->rx_buffers[buff_n].length,
-                                        DMA_FROM_DEVICE);
-
-                       /* Relinquish the SKB to the network layer */
-                       skb_put(skb, pktlen);
-                       skb->protocol = eth_type_trans(skb, ndev);
-                       napi_gro_receive(&ksp->napi, skb);
-
-                       /* Record stats */
-                       ndev->stats.rx_packets++;
-                       ndev->stats.rx_bytes += pktlen;
-                       goto rx_finished;
-
-rx_failure:
-                       /* This ring entry is an error, but we can
-                        * re-use the skb
-                        */
-                       /* Give the ring entry back to the hardware */
-                       ksp->rx_ring[buff_n].status = cpu_to_le32(RDES_OWN);
-rx_finished:
-                       received++;
-                       buff_n = (buff_n + 1) & MAX_RX_DESC_MASK;
-       }
-
-       /* And note which RX descriptor we last did */
-       ksp->next_rx_desc_read = buff_n;
-
-       /* And refill the buffers */
-       ks8695_refill_rxbuffers(ksp);
-
-       /* Kick the RX DMA engine, in case it became suspended */
-       ks8695_writereg(ksp, KS8695_DRSC, 0);
-
-       return received;
-}
-
-
-/**
- *     ks8695_poll - Receive packet by NAPI poll method
- *     @ksp: Private data for the KS8695 Ethernet
- *     @budget: The remaining number packets for network subsystem
- *
- *     Invoked by the network core when it requests for new
- *     packets from the driver
- */
-static int ks8695_poll(struct napi_struct *napi, int budget)
-{
-       struct ks8695_priv *ksp = container_of(napi, struct ks8695_priv, napi);
-       unsigned long isr = readl(KS8695_IRQ_VA + KS8695_INTEN);
-       unsigned long mask_bit = 1 << ks8695_get_rx_enable_bit(ksp);
-       int work_done;
-
-       work_done = ks8695_rx(ksp, budget);
-
-       if (work_done < budget && napi_complete_done(napi, work_done)) {
-               unsigned long flags;
-
-               spin_lock_irqsave(&ksp->rx_lock, flags);
-               /* enable rx interrupt */
-               writel(isr | mask_bit, KS8695_IRQ_VA + KS8695_INTEN);
-               spin_unlock_irqrestore(&ksp->rx_lock, flags);
-       }
-       return work_done;
-}
-
-/**
- *     ks8695_link_irq - Link change IRQ handler
- *     @irq: The IRQ which went off (ignored)
- *     @dev_id: The net_device for the interrupt
- *
- *     The WAN interface can generate an IRQ when the link changes,
- *     report this to the net layer and the user.
- */
-static irqreturn_t
-ks8695_link_irq(int irq, void *dev_id)
-{
-       struct net_device *ndev = (struct net_device *)dev_id;
-       struct ks8695_priv *ksp = netdev_priv(ndev);
-       u32 ctrl;
-
-       ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
-       if (ctrl & WMC_WLS) {
-               netif_carrier_on(ndev);
-               if (netif_msg_link(ksp))
-                       dev_info(ksp->dev,
-                                "%s: Link is now up (10%sMbps/%s-duplex)\n",
-                                ndev->name,
-                                (ctrl & WMC_WSS) ? "0" : "",
-                                (ctrl & WMC_WDS) ? "Full" : "Half");
-       } else {
-               netif_carrier_off(ndev);
-               if (netif_msg_link(ksp))
-                       dev_info(ksp->dev, "%s: Link is now down.\n",
-                                ndev->name);
-       }
-
-       return IRQ_HANDLED;
-}
-
-
-/* KS8695 Device functions */
-
-/**
- *     ks8695_reset - Reset a KS8695 ethernet interface
- *     @ksp: The interface to reset
- *
- *     Perform an engine reset of the interface and re-program it
- *     with sensible defaults.
- */
-static void
-ks8695_reset(struct ks8695_priv *ksp)
-{
-       int reset_timeout = watchdog;
-       /* Issue the reset via the TX DMA control register */
-       ks8695_writereg(ksp, KS8695_DTXC, DTXC_TRST);
-       while (reset_timeout--) {
-               if (!(ks8695_readreg(ksp, KS8695_DTXC) & DTXC_TRST))
-                       break;
-               msleep(1);
-       }
-
-       if (reset_timeout < 0) {
-               dev_crit(ksp->dev,
-                        "Timeout waiting for DMA engines to reset\n");
-               /* And blithely carry on */
-       }
-
-       /* Definitely wait long enough before attempting to program
-        * the engines
-        */
-       msleep(10);
-
-       /* RX: unicast and broadcast */
-       ks8695_writereg(ksp, KS8695_DRXC, DRXC_RU | DRXC_RB);
-       /* TX: pad and add CRC */
-       ks8695_writereg(ksp, KS8695_DTXC, DTXC_TEP | DTXC_TAC);
-}
-
-/**
- *     ks8695_shutdown - Shut down a KS8695 ethernet interface
- *     @ksp: The interface to shut down
- *
- *     This disables packet RX/TX, cleans up IRQs, drains the rings,
- *     and basically places the interface into a clean shutdown
- *     state.
- */
-static void
-ks8695_shutdown(struct ks8695_priv *ksp)
-{
-       u32 ctrl;
-       int buff_n;
-
-       /* Disable packet transmission */
-       ctrl = ks8695_readreg(ksp, KS8695_DTXC);
-       ks8695_writereg(ksp, KS8695_DTXC, ctrl & ~DTXC_TE);
-
-       /* Disable packet reception */
-       ctrl = ks8695_readreg(ksp, KS8695_DRXC);
-       ks8695_writereg(ksp, KS8695_DRXC, ctrl & ~DRXC_RE);
-
-       /* Release the IRQs */
-       free_irq(ksp->rx_irq, ksp->ndev);
-       free_irq(ksp->tx_irq, ksp->ndev);
-       if (ksp->link_irq != -1)
-               free_irq(ksp->link_irq, ksp->ndev);
-
-       /* Throw away any pending TX packets */
-       for (buff_n = 0; buff_n < MAX_TX_DESC; ++buff_n) {
-               if (ksp->tx_buffers[buff_n].skb) {
-                       /* Remove this SKB from the TX ring */
-                       ksp->tx_ring[buff_n].owner = 0;
-                       ksp->tx_ring[buff_n].status = 0;
-                       ksp->tx_ring[buff_n].data_ptr = 0;
-
-                       /* Unmap and bin this SKB */
-                       dma_unmap_single(ksp->dev,
-                                        ksp->tx_buffers[buff_n].dma_ptr,
-                                        ksp->tx_buffers[buff_n].length,
-                                        DMA_TO_DEVICE);
-                       dev_kfree_skb_irq(ksp->tx_buffers[buff_n].skb);
-                       ksp->tx_buffers[buff_n].skb = NULL;
-               }
-       }
-
-       /* Purge the RX buffers */
-       for (buff_n = 0; buff_n < MAX_RX_DESC; ++buff_n) {
-               if (ksp->rx_buffers[buff_n].skb) {
-                       /* Remove the SKB from the RX ring */
-                       ksp->rx_ring[buff_n].status = 0;
-                       ksp->rx_ring[buff_n].data_ptr = 0;
-
-                       /* Unmap and bin the SKB */
-                       dma_unmap_single(ksp->dev,
-                                        ksp->rx_buffers[buff_n].dma_ptr,
-                                        ksp->rx_buffers[buff_n].length,
-                                        DMA_FROM_DEVICE);
-                       dev_kfree_skb_irq(ksp->rx_buffers[buff_n].skb);
-                       ksp->rx_buffers[buff_n].skb = NULL;
-               }
-       }
-}
-
-
-/**
- *     ks8695_setup_irq - IRQ setup helper function
- *     @irq: The IRQ number to claim
- *     @irq_name: The name to give the IRQ claimant
- *     @handler: The function to call to handle the IRQ
- *     @ndev: The net_device to pass in as the dev_id argument to the handler
- *
- *     Return 0 on success.
- */
-static int
-ks8695_setup_irq(int irq, const char *irq_name,
-                irq_handler_t handler, struct net_device *ndev)
-{
-       int ret;
-
-       ret = request_irq(irq, handler, IRQF_SHARED, irq_name, ndev);
-
-       if (ret) {
-               dev_err(&ndev->dev, "failure to request IRQ %d\n", irq);
-               return ret;
-       }
-
-       return 0;
-}
-
-/**
- *     ks8695_init_net - Initialise a KS8695 ethernet interface
- *     @ksp: The interface to initialise
- *
- *     This routine fills the RX ring, initialises the DMA engines,
- *     allocates the IRQs and then starts the packet TX and RX
- *     engines.
- */
-static int
-ks8695_init_net(struct ks8695_priv *ksp)
-{
-       int ret;
-       u32 ctrl;
-
-       ks8695_refill_rxbuffers(ksp);
-
-       /* Initialise the DMA engines */
-       ks8695_writereg(ksp, KS8695_RDLB, (u32) ksp->rx_ring_dma);
-       ks8695_writereg(ksp, KS8695_TDLB, (u32) ksp->tx_ring_dma);
-
-       /* Request the IRQs */
-       ret = ks8695_setup_irq(ksp->rx_irq, ksp->rx_irq_name,
-                              ks8695_rx_irq, ksp->ndev);
-       if (ret)
-               return ret;
-       ret = ks8695_setup_irq(ksp->tx_irq, ksp->tx_irq_name,
-                              ks8695_tx_irq, ksp->ndev);
-       if (ret)
-               return ret;
-       if (ksp->link_irq != -1) {
-               ret = ks8695_setup_irq(ksp->link_irq, ksp->link_irq_name,
-                                      ks8695_link_irq, ksp->ndev);
-               if (ret)
-                       return ret;
-       }
-
-       /* Set up the ring indices */
-       ksp->next_rx_desc_read = 0;
-       ksp->tx_ring_next_slot = 0;
-       ksp->tx_ring_used = 0;
-
-       /* Bring up transmission */
-       ctrl = ks8695_readreg(ksp, KS8695_DTXC);
-       /* Enable packet transmission */
-       ks8695_writereg(ksp, KS8695_DTXC, ctrl | DTXC_TE);
-
-       /* Bring up the reception */
-       ctrl = ks8695_readreg(ksp, KS8695_DRXC);
-       /* Enable packet reception */
-       ks8695_writereg(ksp, KS8695_DRXC, ctrl | DRXC_RE);
-       /* And start the DMA engine */
-       ks8695_writereg(ksp, KS8695_DRSC, 0);
-
-       /* All done */
-       return 0;
-}
-
-/**
- *     ks8695_release_device - HW resource release for KS8695 e-net
- *     @ksp: The device to be freed
- *
- *     This unallocates io memory regions, dma-coherent regions etc
- *     which were allocated in ks8695_probe.
- */
-static void
-ks8695_release_device(struct ks8695_priv *ksp)
-{
-       /* Unmap the registers */
-       iounmap(ksp->io_regs);
-       if (ksp->phyiface_regs)
-               iounmap(ksp->phyiface_regs);
-
-       /* And release the request */
-       release_resource(ksp->regs_req);
-       kfree(ksp->regs_req);
-       if (ksp->phyiface_req) {
-               release_resource(ksp->phyiface_req);
-               kfree(ksp->phyiface_req);
-       }
-
-       /* Free the ring buffers */
-       dma_free_coherent(ksp->dev, RING_DMA_SIZE,
-                         ksp->ring_base, ksp->ring_base_dma);
-}
-
-/* Ethtool support */
-
-/**
- *     ks8695_get_msglevel - Get the messages enabled for emission
- *     @ndev: The network device to read from
- */
-static u32
-ks8695_get_msglevel(struct net_device *ndev)
-{
-       struct ks8695_priv *ksp = netdev_priv(ndev);
-
-       return ksp->msg_enable;
-}
-
-/**
- *     ks8695_set_msglevel - Set the messages enabled for emission
- *     @ndev: The network device to configure
- *     @value: The messages to set for emission
- */
-static void
-ks8695_set_msglevel(struct net_device *ndev, u32 value)
-{
-       struct ks8695_priv *ksp = netdev_priv(ndev);
-
-       ksp->msg_enable = value;
-}
-
-/**
- *     ks8695_wan_get_link_ksettings - Get device-specific settings.
- *     @ndev: The network device to read settings from
- *     @cmd: The ethtool structure to read into
- */
-static int
-ks8695_wan_get_link_ksettings(struct net_device *ndev,
-                             struct ethtool_link_ksettings *cmd)
-{
-       struct ks8695_priv *ksp = netdev_priv(ndev);
-       u32 ctrl;
-       u32 supported, advertising;
-
-       /* All ports on the KS8695 support these... */
-       supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
-                         SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
-                         SUPPORTED_TP | SUPPORTED_MII);
-
-       advertising = ADVERTISED_TP | ADVERTISED_MII;
-       cmd->base.port = PORT_MII;
-       supported |= (SUPPORTED_Autoneg | SUPPORTED_Pause);
-       cmd->base.phy_address = 0;
-
-       ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
-       if ((ctrl & WMC_WAND) == 0) {
-               /* auto-negotiation is enabled */
-               advertising |= ADVERTISED_Autoneg;
-               if (ctrl & WMC_WANA100F)
-                       advertising |= ADVERTISED_100baseT_Full;
-               if (ctrl & WMC_WANA100H)
-                       advertising |= ADVERTISED_100baseT_Half;
-               if (ctrl & WMC_WANA10F)
-                       advertising |= ADVERTISED_10baseT_Full;
-               if (ctrl & WMC_WANA10H)
-                       advertising |= ADVERTISED_10baseT_Half;
-               if (ctrl & WMC_WANAP)
-                       advertising |= ADVERTISED_Pause;
-               cmd->base.autoneg = AUTONEG_ENABLE;
-
-               cmd->base.speed = (ctrl & WMC_WSS) ? SPEED_100 : SPEED_10;
-               cmd->base.duplex = (ctrl & WMC_WDS) ?
-                       DUPLEX_FULL : DUPLEX_HALF;
-       } else {
-               /* auto-negotiation is disabled */
-               cmd->base.autoneg = AUTONEG_DISABLE;
-
-               cmd->base.speed = (ctrl & WMC_WANF100) ?
-                                           SPEED_100 : SPEED_10;
-               cmd->base.duplex = (ctrl & WMC_WANFF) ?
-                       DUPLEX_FULL : DUPLEX_HALF;
-       }
-
-       ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
-                                               supported);
-       ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
-                                               advertising);
-
-       return 0;
-}
-
-/**
- *     ks8695_wan_set_link_ksettings - Set device-specific settings.
- *     @ndev: The network device to configure
- *     @cmd: The settings to configure
- */
-static int
-ks8695_wan_set_link_ksettings(struct net_device *ndev,
-                             const struct ethtool_link_ksettings *cmd)
-{
-       struct ks8695_priv *ksp = netdev_priv(ndev);
-       u32 ctrl;
-       u32 advertising;
-
-       ethtool_convert_link_mode_to_legacy_u32(&advertising,
-                                               cmd->link_modes.advertising);
-
-       if ((cmd->base.speed != SPEED_10) && (cmd->base.speed != SPEED_100))
-               return -EINVAL;
-       if ((cmd->base.duplex != DUPLEX_HALF) &&
-           (cmd->base.duplex != DUPLEX_FULL))
-               return -EINVAL;
-       if (cmd->base.port != PORT_MII)
-               return -EINVAL;
-       if ((cmd->base.autoneg != AUTONEG_DISABLE) &&
-           (cmd->base.autoneg != AUTONEG_ENABLE))
-               return -EINVAL;
-
-       if (cmd->base.autoneg == AUTONEG_ENABLE) {
-               if ((advertising & (ADVERTISED_10baseT_Half |
-                               ADVERTISED_10baseT_Full |
-                               ADVERTISED_100baseT_Half |
-                               ADVERTISED_100baseT_Full)) == 0)
-                       return -EINVAL;
-
-               ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
-
-               ctrl &= ~(WMC_WAND | WMC_WANA100F | WMC_WANA100H |
-                         WMC_WANA10F | WMC_WANA10H);
-               if (advertising & ADVERTISED_100baseT_Full)
-                       ctrl |= WMC_WANA100F;
-               if (advertising & ADVERTISED_100baseT_Half)
-                       ctrl |= WMC_WANA100H;
-               if (advertising & ADVERTISED_10baseT_Full)
-                       ctrl |= WMC_WANA10F;
-               if (advertising & ADVERTISED_10baseT_Half)
-                       ctrl |= WMC_WANA10H;
-
-               /* force a re-negotiation */
-               ctrl |= WMC_WANR;
-               writel(ctrl, ksp->phyiface_regs + KS8695_WMC);
-       } else {
-               ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
-
-               /* disable auto-negotiation */
-               ctrl |= WMC_WAND;
-               ctrl &= ~(WMC_WANF100 | WMC_WANFF);
-
-               if (cmd->base.speed == SPEED_100)
-                       ctrl |= WMC_WANF100;
-               if (cmd->base.duplex == DUPLEX_FULL)
-                       ctrl |= WMC_WANFF;
-
-               writel(ctrl, ksp->phyiface_regs + KS8695_WMC);
-       }
-
-       return 0;
-}
-
-/**
- *     ks8695_wan_nwayreset - Restart the autonegotiation on the port.
- *     @ndev: The network device to restart autoneotiation on
- */
-static int
-ks8695_wan_nwayreset(struct net_device *ndev)
-{
-       struct ks8695_priv *ksp = netdev_priv(ndev);
-       u32 ctrl;
-
-       ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
-
-       if ((ctrl & WMC_WAND) == 0)
-               writel(ctrl | WMC_WANR,
-                      ksp->phyiface_regs + KS8695_WMC);
-       else
-               /* auto-negotiation not enabled */
-               return -EINVAL;
-
-       return 0;
-}
-
-/**
- *     ks8695_wan_get_pause - Retrieve network pause/flow-control advertising
- *     @ndev: The device to retrieve settings from
- *     @param: The structure to fill out with the information
- */
-static void
-ks8695_wan_get_pause(struct net_device *ndev, struct ethtool_pauseparam *param)
-{
-       struct ks8695_priv *ksp = netdev_priv(ndev);
-       u32 ctrl;
-
-       ctrl = readl(ksp->phyiface_regs + KS8695_WMC);
-
-       /* advertise Pause */
-       param->autoneg = (ctrl & WMC_WANAP);
-
-       /* current Rx Flow-control */
-       ctrl = ks8695_readreg(ksp, KS8695_DRXC);
-       param->rx_pause = (ctrl & DRXC_RFCE);
-
-       /* current Tx Flow-control */
-       ctrl = ks8695_readreg(ksp, KS8695_DTXC);
-       param->tx_pause = (ctrl & DTXC_TFCE);
-}
-
-/**
- *     ks8695_get_drvinfo - Retrieve driver information
- *     @ndev: The network device to retrieve info about
- *     @info: The info structure to fill out.
- */
-static void
-ks8695_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info)
-{
-       strlcpy(info->driver, MODULENAME, sizeof(info->driver));
-       strlcpy(info->version, MODULEVERSION, sizeof(info->version));
-       strlcpy(info->bus_info, dev_name(ndev->dev.parent),
-               sizeof(info->bus_info));
-}
-
-static const struct ethtool_ops ks8695_ethtool_ops = {
-       .get_msglevel   = ks8695_get_msglevel,
-       .set_msglevel   = ks8695_set_msglevel,
-       .get_drvinfo    = ks8695_get_drvinfo,
-};
-
-static const struct ethtool_ops ks8695_wan_ethtool_ops = {
-       .get_msglevel   = ks8695_get_msglevel,
-       .set_msglevel   = ks8695_set_msglevel,
-       .nway_reset     = ks8695_wan_nwayreset,
-       .get_link       = ethtool_op_get_link,
-       .get_pauseparam = ks8695_wan_get_pause,
-       .get_drvinfo    = ks8695_get_drvinfo,
-       .get_link_ksettings = ks8695_wan_get_link_ksettings,
-       .set_link_ksettings = ks8695_wan_set_link_ksettings,
-};
-
-/* Network device interface functions */
-
-/**
- *     ks8695_set_mac - Update MAC in net dev and HW
- *     @ndev: The network device to update
- *     @addr: The new MAC address to set
- */
-static int
-ks8695_set_mac(struct net_device *ndev, void *addr)
-{
-       struct ks8695_priv *ksp = netdev_priv(ndev);
-       struct sockaddr *address = addr;
-
-       if (!is_valid_ether_addr(address->sa_data))
-               return -EADDRNOTAVAIL;
-
-       memcpy(ndev->dev_addr, address->sa_data, ndev->addr_len);
-
-       ks8695_update_mac(ksp);
-
-       dev_dbg(ksp->dev, "%s: Updated MAC address to %pM\n",
-               ndev->name, ndev->dev_addr);
-
-       return 0;
-}
-
-/**
- *     ks8695_set_multicast - Set up the multicast behaviour of the interface
- *     @ndev: The net_device to configure
- *
- *     This routine, called by the net layer, configures promiscuity
- *     and multicast reception behaviour for the interface.
- */
-static void
-ks8695_set_multicast(struct net_device *ndev)
-{
-       struct ks8695_priv *ksp = netdev_priv(ndev);
-       u32 ctrl;
-
-       ctrl = ks8695_readreg(ksp, KS8695_DRXC);
-
-       if (ndev->flags & IFF_PROMISC) {
-               /* enable promiscuous mode */
-               ctrl |= DRXC_RA;
-       } else if (ndev->flags & ~IFF_PROMISC) {
-               /* disable promiscuous mode */
-               ctrl &= ~DRXC_RA;
-       }
-
-       if (ndev->flags & IFF_ALLMULTI) {
-               /* enable all multicast mode */
-               ctrl |= DRXC_RM;
-       } else if (netdev_mc_count(ndev) > KS8695_NR_ADDRESSES) {
-               /* more specific multicast addresses than can be
-                * handled in hardware
-                */
-               ctrl |= DRXC_RM;
-       } else {
-               /* enable specific multicasts */
-               ctrl &= ~DRXC_RM;
-               ks8695_init_partial_multicast(ksp, ndev);
-       }
-
-       ks8695_writereg(ksp, KS8695_DRXC, ctrl);
-}
-
-/**
- *     ks8695_timeout - Handle a network tx/rx timeout.
- *     @ndev: The net_device which timed out.
- *
- *     A network transaction timed out, reset the device.
- */
-static void
-ks8695_timeout(struct net_device *ndev)
-{
-       struct ks8695_priv *ksp = netdev_priv(ndev);
-
-       netif_stop_queue(ndev);
-       ks8695_shutdown(ksp);
-
-       ks8695_reset(ksp);
-
-       ks8695_update_mac(ksp);
-
-       /* We ignore the return from this since it managed to init
-        * before it probably will be okay to init again.
-        */
-       ks8695_init_net(ksp);
-
-       /* Reconfigure promiscuity etc */
-       ks8695_set_multicast(ndev);
-
-       /* And start the TX queue once more */
-       netif_start_queue(ndev);
-}
-
-/**
- *     ks8695_start_xmit - Start a packet transmission
- *     @skb: The packet to transmit
- *     @ndev: The network device to send the packet on
- *
- *     This routine, called by the net layer, takes ownership of the
- *     sk_buff and adds it to the TX ring. It then kicks the TX DMA
- *     engine to ensure transmission begins.
- */
-static netdev_tx_t
-ks8695_start_xmit(struct sk_buff *skb, struct net_device *ndev)
-{
-       struct ks8695_priv *ksp = netdev_priv(ndev);
-       int buff_n;
-       dma_addr_t dmap;
-
-       spin_lock_irq(&ksp->txq_lock);
-
-       if (ksp->tx_ring_used == MAX_TX_DESC) {
-               /* Somehow we got entered when we have no room */
-               spin_unlock_irq(&ksp->txq_lock);
-               return NETDEV_TX_BUSY;
-       }
-
-       buff_n = ksp->tx_ring_next_slot;
-
-       BUG_ON(ksp->tx_buffers[buff_n].skb);
-
-       dmap = dma_map_single(ksp->dev, skb->data, skb->len, DMA_TO_DEVICE);
-       if (unlikely(dma_mapping_error(ksp->dev, dmap))) {
-               /* Failed to DMA map this SKB, give it back for now */
-               spin_unlock_irq(&ksp->txq_lock);
-               dev_dbg(ksp->dev, "%s: Could not map DMA memory for "\
-                       "transmission, trying later\n", ndev->name);
-               return NETDEV_TX_BUSY;
-       }
-
-       ksp->tx_buffers[buff_n].dma_ptr = dmap;
-       /* Mapped okay, store the buffer pointer and length for later */
-       ksp->tx_buffers[buff_n].skb = skb;
-       ksp->tx_buffers[buff_n].length = skb->len;
-
-       /* Fill out the TX descriptor */
-       ksp->tx_ring[buff_n].data_ptr =
-               cpu_to_le32(ksp->tx_buffers[buff_n].dma_ptr);
-       ksp->tx_ring[buff_n].status =
-               cpu_to_le32(TDES_IC | TDES_FS | TDES_LS |
-                           (skb->len & TDES_TBS));
-
-       wmb();
-
-       /* Hand it over to the hardware */
-       ksp->tx_ring[buff_n].owner = cpu_to_le32(TDES_OWN);
-
-       if (++ksp->tx_ring_used == MAX_TX_DESC)
-               netif_stop_queue(ndev);
-
-       /* Kick the TX DMA in case it decided to go IDLE */
-       ks8695_writereg(ksp, KS8695_DTSC, 0);
-
-       /* And update the next ring slot */
-       ksp->tx_ring_next_slot = (buff_n + 1) & MAX_TX_DESC_MASK;
-
-       spin_unlock_irq(&ksp->txq_lock);
-       return NETDEV_TX_OK;
-}
-
-/**
- *     ks8695_stop - Stop (shutdown) a KS8695 ethernet interface
- *     @ndev: The net_device to stop
- *
- *     This disables the TX queue and cleans up a KS8695 ethernet
- *     device.
- */
-static int
-ks8695_stop(struct net_device *ndev)
-{
-       struct ks8695_priv *ksp = netdev_priv(ndev);
-
-       netif_stop_queue(ndev);
-       napi_disable(&ksp->napi);
-
-       ks8695_shutdown(ksp);
-
-       return 0;
-}
-
-/**
- *     ks8695_open - Open (bring up) a KS8695 ethernet interface
- *     @ndev: The net_device to open
- *
- *     This resets, configures the MAC, initialises the RX ring and
- *     DMA engines and starts the TX queue for a KS8695 ethernet
- *     device.
- */
-static int
-ks8695_open(struct net_device *ndev)
-{
-       struct ks8695_priv *ksp = netdev_priv(ndev);
-       int ret;
-
-       ks8695_reset(ksp);
-
-       ks8695_update_mac(ksp);
-
-       ret = ks8695_init_net(ksp);
-       if (ret) {
-               ks8695_shutdown(ksp);
-               return ret;
-       }
-
-       napi_enable(&ksp->napi);
-       netif_start_queue(ndev);
-
-       return 0;
-}
-
-/* Platform device driver */
-
-/**
- *     ks8695_init_switch - Init LAN switch to known good defaults.
- *     @ksp: The device to initialise
- *
- *     This initialises the LAN switch in the KS8695 to a known-good
- *     set of defaults.
- */
-static void
-ks8695_init_switch(struct ks8695_priv *ksp)
-{
-       u32 ctrl;
-
-       /* Default value for SEC0 according to datasheet */
-       ctrl = 0x40819e00;
-
-       /* LED0 = Speed  LED1 = Link/Activity */
-       ctrl &= ~(SEC0_LLED1S | SEC0_LLED0S);
-       ctrl |= (LLED0S_LINK | LLED1S_LINK_ACTIVITY);
-
-       /* Enable Switch */
-       ctrl |= SEC0_ENABLE;
-
-       writel(ctrl, ksp->phyiface_regs + KS8695_SEC0);
-
-       /* Defaults for SEC1 */
-       writel(0x9400100, ksp->phyiface_regs + KS8695_SEC1);
-}
-
-/**
- *     ks8695_init_wan_phy - Initialise the WAN PHY to sensible defaults
- *     @ksp: The device to initialise
- *
- *     This initialises a KS8695's WAN phy to sensible values for
- *     autonegotiation etc.
- */
-static void
-ks8695_init_wan_phy(struct ks8695_priv *ksp)
-{
-       u32 ctrl;
-
-       /* Support auto-negotiation */
-       ctrl = (WMC_WANAP | WMC_WANA100F | WMC_WANA100H |
-               WMC_WANA10F | WMC_WANA10H);
-
-       /* LED0 = Activity , LED1 = Link */
-       ctrl |= (WLED0S_ACTIVITY | WLED1S_LINK);
-
-       /* Restart Auto-negotiation */
-       ctrl |= WMC_WANR;
-
-       writel(ctrl, ksp->phyiface_regs + KS8695_WMC);
-
-       writel(0, ksp->phyiface_regs + KS8695_WPPM);
-       writel(0, ksp->phyiface_regs + KS8695_PPS);
-}
-
-static const struct net_device_ops ks8695_netdev_ops = {
-       .ndo_open               = ks8695_open,
-       .ndo_stop               = ks8695_stop,
-       .ndo_start_xmit         = ks8695_start_xmit,
-       .ndo_tx_timeout         = ks8695_timeout,
-       .ndo_set_mac_address    = ks8695_set_mac,
-       .ndo_validate_addr      = eth_validate_addr,
-       .ndo_set_rx_mode        = ks8695_set_multicast,
-};
-
-/**
- *     ks8695_probe - Probe and initialise a KS8695 ethernet interface
- *     @pdev: The platform device to probe
- *
- *     Initialise a KS8695 ethernet device from platform data.
- *
- *     This driver requires at least one IORESOURCE_MEM for the
- *     registers and two IORESOURCE_IRQ for the RX and TX IRQs
- *     respectively. It can optionally take an additional
- *     IORESOURCE_MEM for the switch or phy in the case of the lan or
- *     wan ports, and an IORESOURCE_IRQ for the link IRQ for the wan
- *     port.
- */
-static int
-ks8695_probe(struct platform_device *pdev)
-{
-       struct ks8695_priv *ksp;
-       struct net_device *ndev;
-       struct resource *regs_res, *phyiface_res;
-       struct resource *rxirq_res, *txirq_res, *linkirq_res;
-       int ret = 0;
-       int buff_n;
-       bool inv_mac_addr = false;
-       u32 machigh, maclow;
-
-       /* Initialise a net_device */
-       ndev = alloc_etherdev(sizeof(struct ks8695_priv));
-       if (!ndev)
-               return -ENOMEM;
-
-       SET_NETDEV_DEV(ndev, &pdev->dev);
-
-       dev_dbg(&pdev->dev, "ks8695_probe() called\n");
-
-       /* Configure our private structure a little */
-       ksp = netdev_priv(ndev);
-
-       ksp->dev = &pdev->dev;
-       ksp->ndev = ndev;
-       ksp->msg_enable = NETIF_MSG_LINK;
-
-       /* Retrieve resources */
-       regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       phyiface_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-
-       rxirq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       txirq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
-       linkirq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 2);
-
-       if (!(regs_res && rxirq_res && txirq_res)) {
-               dev_err(ksp->dev, "insufficient resources\n");
-               ret = -ENOENT;
-               goto failure;
-       }
-
-       ksp->regs_req = request_mem_region(regs_res->start,
-                                          resource_size(regs_res),
-                                          pdev->name);
-
-       if (!ksp->regs_req) {
-               dev_err(ksp->dev, "cannot claim register space\n");
-               ret = -EIO;
-               goto failure;
-       }
-
-       ksp->io_regs = ioremap(regs_res->start, resource_size(regs_res));
-
-       if (!ksp->io_regs) {
-               dev_err(ksp->dev, "failed to ioremap registers\n");
-               ret = -EINVAL;
-               goto failure;
-       }
-
-       if (phyiface_res) {
-               ksp->phyiface_req =
-                       request_mem_region(phyiface_res->start,
-                                          resource_size(phyiface_res),
-                                          phyiface_res->name);
-
-               if (!ksp->phyiface_req) {
-                       dev_err(ksp->dev,
-                               "cannot claim switch register space\n");
-                       ret = -EIO;
-                       goto failure;
-               }
-
-               ksp->phyiface_regs = ioremap(phyiface_res->start,
-                                            resource_size(phyiface_res));
-
-               if (!ksp->phyiface_regs) {
-                       dev_err(ksp->dev,
-                               "failed to ioremap switch registers\n");
-                       ret = -EINVAL;
-                       goto failure;
-               }
-       }
-
-       ksp->rx_irq = rxirq_res->start;
-       ksp->rx_irq_name = rxirq_res->name ? rxirq_res->name : "Ethernet RX";
-       ksp->tx_irq = txirq_res->start;
-       ksp->tx_irq_name = txirq_res->name ? txirq_res->name : "Ethernet TX";
-       ksp->link_irq = (linkirq_res ? linkirq_res->start : -1);
-       ksp->link_irq_name = (linkirq_res && linkirq_res->name) ?
-               linkirq_res->name : "Ethernet Link";
-
-       /* driver system setup */
-       ndev->netdev_ops = &ks8695_netdev_ops;
-       ndev->watchdog_timeo     = msecs_to_jiffies(watchdog);
-
-       netif_napi_add(ndev, &ksp->napi, ks8695_poll, NAPI_WEIGHT);
-
-       /* Retrieve the default MAC addr from the chip. */
-       /* The bootloader should have left it in there for us. */
-
-       machigh = ks8695_readreg(ksp, KS8695_MAH);
-       maclow = ks8695_readreg(ksp, KS8695_MAL);
-
-       ndev->dev_addr[0] = (machigh >> 8) & 0xFF;
-       ndev->dev_addr[1] = machigh & 0xFF;
-       ndev->dev_addr[2] = (maclow >> 24) & 0xFF;
-       ndev->dev_addr[3] = (maclow >> 16) & 0xFF;
-       ndev->dev_addr[4] = (maclow >> 8) & 0xFF;
-       ndev->dev_addr[5] = maclow & 0xFF;
-
-       if (!is_valid_ether_addr(ndev->dev_addr))
-               inv_mac_addr = true;
-
-       /* In order to be efficient memory-wise, we allocate both
-        * rings in one go.
-        */
-       ksp->ring_base = dma_alloc_coherent(&pdev->dev, RING_DMA_SIZE,
-                                           &ksp->ring_base_dma, GFP_KERNEL);
-       if (!ksp->ring_base) {
-               ret = -ENOMEM;
-               goto failure;
-       }
-
-       /* Specify the TX DMA ring buffer */
-       ksp->tx_ring = ksp->ring_base;
-       ksp->tx_ring_dma = ksp->ring_base_dma;
-
-       /* And initialise the queue's lock */
-       spin_lock_init(&ksp->txq_lock);
-       spin_lock_init(&ksp->rx_lock);
-
-       /* Specify the RX DMA ring buffer */
-       ksp->rx_ring = ksp->ring_base + TX_RING_DMA_SIZE;
-       ksp->rx_ring_dma = ksp->ring_base_dma + TX_RING_DMA_SIZE;
-
-       /* Zero the descriptor rings */
-       memset(ksp->tx_ring, 0, TX_RING_DMA_SIZE);
-       memset(ksp->rx_ring, 0, RX_RING_DMA_SIZE);
-
-       /* Build the rings */
-       for (buff_n = 0; buff_n < MAX_TX_DESC; ++buff_n) {
-               ksp->tx_ring[buff_n].next_desc =
-                       cpu_to_le32(ksp->tx_ring_dma +
-                                   (sizeof(struct tx_ring_desc) *
-                                    ((buff_n + 1) & MAX_TX_DESC_MASK)));
-       }
-
-       for (buff_n = 0; buff_n < MAX_RX_DESC; ++buff_n) {
-               ksp->rx_ring[buff_n].next_desc =
-                       cpu_to_le32(ksp->rx_ring_dma +
-                                   (sizeof(struct rx_ring_desc) *
-                                    ((buff_n + 1) & MAX_RX_DESC_MASK)));
-       }
-
-       /* Initialise the port (physically) */
-       if (ksp->phyiface_regs && ksp->link_irq == -1) {
-               ks8695_init_switch(ksp);
-               ksp->dtype = KS8695_DTYPE_LAN;
-               ndev->ethtool_ops = &ks8695_ethtool_ops;
-       } else if (ksp->phyiface_regs && ksp->link_irq != -1) {
-               ks8695_init_wan_phy(ksp);
-               ksp->dtype = KS8695_DTYPE_WAN;
-               ndev->ethtool_ops = &ks8695_wan_ethtool_ops;
-       } else {
-               /* No initialisation since HPNA does not have a PHY */
-               ksp->dtype = KS8695_DTYPE_HPNA;
-               ndev->ethtool_ops = &ks8695_ethtool_ops;
-       }
-
-       /* And bring up the net_device with the net core */
-       platform_set_drvdata(pdev, ndev);
-       ret = register_netdev(ndev);
-
-       if (ret == 0) {
-               if (inv_mac_addr)
-                       dev_warn(ksp->dev, "%s: Invalid ethernet MAC address. Please set using ip\n",
-                                ndev->name);
-               dev_info(ksp->dev, "ks8695 ethernet (%s) MAC: %pM\n",
-                        ks8695_port_type(ksp), ndev->dev_addr);
-       } else {
-               /* Report the failure to register the net_device */
-               dev_err(ksp->dev, "ks8695net: failed to register netdev.\n");
-               goto failure;
-       }
-
-       /* All is well */
-       return 0;
-
-       /* Error exit path */
-failure:
-       ks8695_release_device(ksp);
-       free_netdev(ndev);
-
-       return ret;
-}
-
-/**
- *     ks8695_drv_suspend - Suspend a KS8695 ethernet platform device.
- *     @pdev: The device to suspend
- *     @state: The suspend state
- *
- *     This routine detaches and shuts down a KS8695 ethernet device.
- */
-static int
-ks8695_drv_suspend(struct platform_device *pdev, pm_message_t state)
-{
-       struct net_device *ndev = platform_get_drvdata(pdev);
-       struct ks8695_priv *ksp = netdev_priv(ndev);
-
-       ksp->in_suspend = 1;
-
-       if (netif_running(ndev)) {
-               netif_device_detach(ndev);
-               ks8695_shutdown(ksp);
-       }
-
-       return 0;
-}
-
-/**
- *     ks8695_drv_resume - Resume a KS8695 ethernet platform device.
- *     @pdev: The device to resume
- *
- *     This routine re-initialises and re-attaches a KS8695 ethernet
- *     device.
- */
-static int
-ks8695_drv_resume(struct platform_device *pdev)
-{
-       struct net_device *ndev = platform_get_drvdata(pdev);
-       struct ks8695_priv *ksp = netdev_priv(ndev);
-
-       if (netif_running(ndev)) {
-               ks8695_reset(ksp);
-               ks8695_init_net(ksp);
-               ks8695_set_multicast(ndev);
-               netif_device_attach(ndev);
-       }
-
-       ksp->in_suspend = 0;
-
-       return 0;
-}
-
-/**
- *     ks8695_drv_remove - Remove a KS8695 net device on driver unload.
- *     @pdev: The platform device to remove
- *
- *     This unregisters and releases a KS8695 ethernet device.
- */
-static int
-ks8695_drv_remove(struct platform_device *pdev)
-{
-       struct net_device *ndev = platform_get_drvdata(pdev);
-       struct ks8695_priv *ksp = netdev_priv(ndev);
-
-       netif_napi_del(&ksp->napi);
-
-       unregister_netdev(ndev);
-       ks8695_release_device(ksp);
-       free_netdev(ndev);
-
-       dev_dbg(&pdev->dev, "released and freed device\n");
-       return 0;
-}
-
-static struct platform_driver ks8695_driver = {
-       .driver = {
-               .name   = MODULENAME,
-       },
-       .probe          = ks8695_probe,
-       .remove         = ks8695_drv_remove,
-       .suspend        = ks8695_drv_suspend,
-       .resume         = ks8695_drv_resume,
-};
-
-module_platform_driver(ks8695_driver);
-
-MODULE_AUTHOR("Simtec Electronics");
-MODULE_DESCRIPTION("Micrel KS8695 (Centaur) Ethernet driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" MODULENAME);
-
-module_param(watchdog, int, 0400);
-MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds");
diff --git a/drivers/net/ethernet/micrel/ks8695net.h b/drivers/net/ethernet/micrel/ks8695net.h
deleted file mode 100644 (file)
index b18fad4..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Micrel KS8695 (Centaur) Ethernet.
- *
- * Copyright 2008 Simtec Electronics
- *               Daniel Silverstone <dsilvers@simtec.co.uk>
- *               Vincent Sanders <vince@simtec.co.uk>
- */
-
-#ifndef KS8695NET_H
-#define KS8695NET_H
-
-/* Receive descriptor flags */
-#define RDES_OWN       (1 << 31)       /* Ownership */
-#define RDES_FS                (1 << 30)       /* First Descriptor */
-#define RDES_LS                (1 << 29)       /* Last Descriptor */
-#define RDES_IPE       (1 << 28)       /* IP Checksum error */
-#define RDES_TCPE      (1 << 27)       /* TCP Checksum error */
-#define RDES_UDPE      (1 << 26)       /* UDP Checksum error */
-#define RDES_ES                (1 << 25)       /* Error summary */
-#define RDES_MF                (1 << 24)       /* Multicast Frame */
-#define RDES_RE                (1 << 19)       /* MII Error reported */
-#define RDES_TL                (1 << 18)       /* Frame too Long */
-#define RDES_RF                (1 << 17)       /* Runt Frame */
-#define RDES_CE                (1 << 16)       /* CRC error */
-#define RDES_FT                (1 << 15)       /* Frame Type */
-#define RDES_FLEN      (0x7ff)         /* Frame Length */
-
-#define RDES_RER       (1 << 25)       /* Receive End of Ring */
-#define RDES_RBS       (0x7ff)         /* Receive Buffer Size */
-
-/* Transmit descriptor flags */
-
-#define TDES_OWN       (1 << 31)       /* Ownership */
-
-#define TDES_IC                (1 << 31)       /* Interrupt on Completion */
-#define TDES_FS                (1 << 30)       /* First Segment */
-#define TDES_LS                (1 << 29)       /* Last Segment */
-#define TDES_IPCKG     (1 << 28)       /* IP Checksum generate */
-#define TDES_TCPCKG    (1 << 27)       /* TCP Checksum generate */
-#define TDES_UDPCKG    (1 << 26)       /* UDP Checksum generate */
-#define TDES_TER       (1 << 25)       /* Transmit End of Ring */
-#define TDES_TBS       (0x7ff)         /* Transmit Buffer Size */
-
-/*
- * Network controller register offsets
- */
-#define KS8695_DTXC            (0x00)          /* DMA Transmit Control */
-#define KS8695_DRXC            (0x04)          /* DMA Receive Control */
-#define KS8695_DTSC            (0x08)          /* DMA Transmit Start Command */
-#define KS8695_DRSC            (0x0c)          /* DMA Receive Start Command */
-#define KS8695_TDLB            (0x10)          /* Transmit Descriptor List
-                                                * Base Address
-                                                */
-#define KS8695_RDLB            (0x14)          /* Receive Descriptor List
-                                                * Base Address
-                                                */
-#define KS8695_MAL             (0x18)          /* MAC Station Address Low */
-#define KS8695_MAH             (0x1c)          /* MAC Station Address High */
-#define KS8695_AAL_(n)         (0x80 + ((n)*8))        /* MAC Additional
-                                                        * Station Address
-                                                        * (0..15) Low
-                                                        */
-#define KS8695_AAH_(n)         (0x84 + ((n)*8))        /* MAC Additional
-                                                        * Station Address
-                                                        * (0..15) High
-                                                        */
-
-
-/* DMA Transmit Control Register */
-#define DTXC_TRST              (1    << 31)    /* Soft Reset */
-#define DTXC_TBS               (0x3f << 24)    /* Transmit Burst Size */
-#define DTXC_TUCG              (1    << 18)    /* Transmit UDP
-                                                * Checksum Generate
-                                                */
-#define DTXC_TTCG              (1    << 17)    /* Transmit TCP
-                                                * Checksum Generate
-                                                */
-#define DTXC_TICG              (1    << 16)    /* Transmit IP
-                                                * Checksum Generate
-                                                */
-#define DTXC_TFCE              (1    <<  9)    /* Transmit Flow
-                                                * Control Enable
-                                                */
-#define DTXC_TLB               (1    <<  8)    /* Loopback mode */
-#define DTXC_TEP               (1    <<  2)    /* Transmit Enable Padding */
-#define DTXC_TAC               (1    <<  1)    /* Transmit Add CRC */
-#define DTXC_TE                        (1    <<  0)    /* TX Enable */
-
-/* DMA Receive Control Register */
-#define DRXC_RBS               (0x3f << 24)    /* Receive Burst Size */
-#define DRXC_RUCC              (1    << 18)    /* Receive UDP Checksum check */
-#define DRXC_RTCG              (1    << 17)    /* Receive TCP Checksum check */
-#define DRXC_RICG              (1    << 16)    /* Receive IP Checksum check */
-#define DRXC_RFCE              (1    <<  9)    /* Receive Flow Control
-                                                * Enable
-                                                */
-#define DRXC_RB                        (1    <<  6)    /* Receive Broadcast */
-#define DRXC_RM                        (1    <<  5)    /* Receive Multicast */
-#define DRXC_RU                        (1    <<  4)    /* Receive Unicast */
-#define DRXC_RERR              (1    <<  3)    /* Receive Error Frame */
-#define DRXC_RA                        (1    <<  2)    /* Receive All */
-#define DRXC_RE                        (1    <<  0)    /* RX Enable */
-
-/* Additional Station Address High */
-#define AAH_E                  (1    << 31)    /* Address Enabled */
-
-#endif /* KS8695NET_H */
diff --git a/drivers/net/ethernet/nuvoton/Kconfig b/drivers/net/ethernet/nuvoton/Kconfig
deleted file mode 100644 (file)
index 325e26c..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-# 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
-       ---help---
-         If you have a network (Ethernet) card belonging to this class, say Y.
-
-         Note that the answer to this question doesn't directly affect the
-         kernel: saying N will just cause the configurator to skip all
-         the questions about Nuvoton cards. If you say Y, you will be asked
-         for your specific card in the following questions.
-
-if NET_VENDOR_NUVOTON
-
-config W90P910_ETH
-       tristate "Nuvoton w90p910 Ethernet support"
-       depends on ARM && ARCH_W90X900
-       select PHYLIB
-       select MII
-       ---help---
-         Say Y here if you want to use built-in Ethernet ports
-         on w90p910 processor.
-
-endif # NET_VENDOR_NUVOTON
diff --git a/drivers/net/ethernet/nuvoton/Makefile b/drivers/net/ethernet/nuvoton/Makefile
deleted file mode 100644 (file)
index 66f6e72..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Makefile for the Nuvoton network device drivers.
-#
-
-obj-$(CONFIG_W90P910_ETH) += w90p910_ether.o
diff --git a/drivers/net/ethernet/nuvoton/w90p910_ether.c b/drivers/net/ethernet/nuvoton/w90p910_ether.c
deleted file mode 100644 (file)
index 3d73970..0000000
+++ /dev/null
@@ -1,1082 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (c) 2008-2009 Nuvoton technology corporation.
- *
- * Wan ZongShun <mcuos.com@gmail.com>
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/mii.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/ethtool.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/gfp.h>
-
-#define DRV_MODULE_NAME                "w90p910-emc"
-#define DRV_MODULE_VERSION     "0.1"
-
-/* 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_CTXDSA             0xcc
-#define REG_CTXBSA             0xd0
-#define REG_CRXDSA             0xd4
-#define REG_CRXBSA             0xd8
-
-/* mac controller bit */
-#define MCMDR_RXON             0x01
-#define MCMDR_ACP              (0x01 << 3)
-#define MCMDR_SPCRC            (0x01 << 5)
-#define MCMDR_TXON             (0x01 << 8)
-#define MCMDR_FDUP             (0x01 << 18)
-#define MCMDR_ENMDC            (0x01 << 19)
-#define MCMDR_OPMOD            (0x01 << 20)
-#define SWR                    (0x01 << 24)
-
-/* cam command regiser */
-#define CAMCMR_AUP             0x01
-#define CAMCMR_AMP             (0x01 << 1)
-#define CAMCMR_ABP             (0x01 << 2)
-#define CAMCMR_CCAM            (0x01 << 3)
-#define CAMCMR_ECMP            (0x01 << 4)
-#define CAM0EN                 0x01
-
-/* mac mii controller bit */
-#define MDCCR                  (0x0a << 20)
-#define PHYAD                  (0x01 << 8)
-#define PHYWR                  (0x01 << 16)
-#define PHYBUSY                        (0x01 << 17)
-#define PHYPRESP               (0x01 << 18)
-#define CAM_ENTRY_SIZE         0x08
-
-/* rx and tx status */
-#define TXDS_TXCP              (0x01 << 19)
-#define RXDS_CRCE              (0x01 << 17)
-#define RXDS_PTLE              (0x01 << 19)
-#define RXDS_RXGD              (0x01 << 20)
-#define RXDS_ALIE              (0x01 << 21)
-#define RXDS_RP                        (0x01 << 22)
-
-/* mac interrupt status*/
-#define MISTA_EXDEF            (0x01 << 19)
-#define MISTA_TXBERR           (0x01 << 24)
-#define MISTA_TDU              (0x01 << 23)
-#define MISTA_RDU              (0x01 << 10)
-#define MISTA_RXBERR           (0x01 << 11)
-
-#define ENSTART                        0x01
-#define ENRXINTR               0x01
-#define ENRXGD                 (0x01 << 4)
-#define ENRXBERR               (0x01 << 11)
-#define ENTXINTR               (0x01 << 16)
-#define ENTXCP                 (0x01 << 18)
-#define ENTXABT                        (0x01 << 21)
-#define ENTXBERR               (0x01 << 24)
-#define ENMDC                  (0x01 << 19)
-#define PHYBUSY                        (0x01 << 17)
-#define MDCCR_VAL              0xa00000
-
-/* rx and tx owner bit */
-#define RX_OWEN_DMA            (0x01 << 31)
-#define RX_OWEN_CPU            (~(0x03 << 30))
-#define TX_OWEN_DMA            (0x01 << 31)
-#define TX_OWEN_CPU            (~(0x01 << 31))
-
-/* tx frame desc controller bit */
-#define MACTXINTEN             0x04
-#define CRCMODE                        0x02
-#define PADDINGMODE            0x01
-
-/* fftcr controller bit */
-#define TXTHD                  (0x03 << 8)
-#define BLENGTH                        (0x01 << 20)
-
-/* global setting for driver */
-#define RX_DESC_SIZE           50
-#define TX_DESC_SIZE           10
-#define MAX_RBUFF_SZ           0x600
-#define MAX_TBUFF_SZ           0x600
-#define TX_TIMEOUT             (HZ/2)
-#define DELAY                  1000
-#define CAM0                   0x0
-
-static int w90p910_mdio_read(struct net_device *dev, int phy_id, int reg);
-
-struct w90p910_rxbd {
-       unsigned int sl;
-       unsigned int buffer;
-       unsigned int reserved;
-       unsigned int next;
-};
-
-struct w90p910_txbd {
-       unsigned int mode;
-       unsigned int buffer;
-       unsigned int sl;
-       unsigned int next;
-};
-
-struct recv_pdesc {
-       struct w90p910_rxbd desclist[RX_DESC_SIZE];
-       char recv_buf[RX_DESC_SIZE][MAX_RBUFF_SZ];
-};
-
-struct tran_pdesc {
-       struct w90p910_txbd desclist[TX_DESC_SIZE];
-       char tran_buf[TX_DESC_SIZE][MAX_TBUFF_SZ];
-};
-
-struct  w90p910_ether {
-       struct recv_pdesc *rdesc;
-       struct tran_pdesc *tdesc;
-       dma_addr_t rdesc_phys;
-       dma_addr_t tdesc_phys;
-       struct platform_device *pdev;
-       struct resource *res;
-       struct sk_buff *skb;
-       struct clk *clk;
-       struct clk *rmiiclk;
-       struct mii_if_info mii;
-       struct timer_list check_timer;
-       void __iomem *reg;
-       int rxirq;
-       int txirq;
-       unsigned int cur_tx;
-       unsigned int cur_rx;
-       unsigned int finish_tx;
-       unsigned int rx_packets;
-       unsigned int rx_bytes;
-       unsigned int start_tx_ptr;
-       unsigned int start_rx_ptr;
-       unsigned int linkflag;
-};
-
-static void update_linkspeed_register(struct net_device *dev,
-                               unsigned int speed, unsigned int duplex)
-{
-       struct w90p910_ether *ether = netdev_priv(dev);
-       unsigned int val;
-
-       val = __raw_readl(ether->reg + REG_MCMDR);
-
-       if (speed == SPEED_100) {
-               /* 100 full/half duplex */
-               if (duplex == DUPLEX_FULL) {
-                       val |= (MCMDR_OPMOD | MCMDR_FDUP);
-               } else {
-                       val |= MCMDR_OPMOD;
-                       val &= ~MCMDR_FDUP;
-               }
-       } else {
-               /* 10 full/half duplex */
-               if (duplex == DUPLEX_FULL) {
-                       val |= MCMDR_FDUP;
-                       val &= ~MCMDR_OPMOD;
-               } else {
-                       val &= ~(MCMDR_FDUP | MCMDR_OPMOD);
-               }
-       }
-
-       __raw_writel(val, ether->reg + REG_MCMDR);
-}
-
-static void update_linkspeed(struct net_device *dev)
-{
-       struct w90p910_ether *ether = netdev_priv(dev);
-       struct platform_device *pdev;
-       unsigned int bmsr, bmcr, lpa, speed, duplex;
-
-       pdev = ether->pdev;
-
-       if (!mii_link_ok(&ether->mii)) {
-               ether->linkflag = 0x0;
-               netif_carrier_off(dev);
-               dev_warn(&pdev->dev, "%s: Link down.\n", dev->name);
-               return;
-       }
-
-       if (ether->linkflag == 1)
-               return;
-
-       bmsr = w90p910_mdio_read(dev, ether->mii.phy_id, MII_BMSR);
-       bmcr = w90p910_mdio_read(dev, ether->mii.phy_id, MII_BMCR);
-
-       if (bmcr & BMCR_ANENABLE) {
-               if (!(bmsr & BMSR_ANEGCOMPLETE))
-                       return;
-
-               lpa = w90p910_mdio_read(dev, ether->mii.phy_id, MII_LPA);
-
-               if ((lpa & LPA_100FULL) || (lpa & LPA_100HALF))
-                       speed = SPEED_100;
-               else
-                       speed = SPEED_10;
-
-               if ((lpa & LPA_100FULL) || (lpa & LPA_10FULL))
-                       duplex = DUPLEX_FULL;
-               else
-                       duplex = DUPLEX_HALF;
-
-       } else {
-               speed = (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10;
-               duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
-       }
-
-       update_linkspeed_register(dev, speed, duplex);
-
-       dev_info(&pdev->dev, "%s: Link now %i-%s\n", dev->name, speed,
-                       (duplex == DUPLEX_FULL) ? "FullDuplex" : "HalfDuplex");
-       ether->linkflag = 0x01;
-
-       netif_carrier_on(dev);
-}
-
-static void w90p910_check_link(struct timer_list *t)
-{
-       struct w90p910_ether *ether = from_timer(ether, t, check_timer);
-       struct net_device *dev = ether->mii.dev;
-
-       update_linkspeed(dev);
-       mod_timer(&ether->check_timer, jiffies + msecs_to_jiffies(1000));
-}
-
-static void w90p910_write_cam(struct net_device *dev,
-                               unsigned int x, unsigned char *pval)
-{
-       struct w90p910_ether *ether = netdev_priv(dev);
-       unsigned int msw, lsw;
-
-       msw = (pval[0] << 24) | (pval[1] << 16) | (pval[2] << 8) | pval[3];
-
-       lsw = (pval[4] << 24) | (pval[5] << 16);
-
-       __raw_writel(lsw, ether->reg + REG_CAML_BASE + x * CAM_ENTRY_SIZE);
-       __raw_writel(msw, ether->reg + REG_CAMM_BASE + x * CAM_ENTRY_SIZE);
-}
-
-static int w90p910_init_desc(struct net_device *dev)
-{
-       struct w90p910_ether *ether;
-       struct w90p910_txbd  *tdesc;
-       struct w90p910_rxbd  *rdesc;
-       struct platform_device *pdev;
-       unsigned int i;
-
-       ether = netdev_priv(dev);
-       pdev = ether->pdev;
-
-       ether->tdesc = dma_alloc_coherent(&pdev->dev, sizeof(struct tran_pdesc),
-                                         &ether->tdesc_phys, GFP_KERNEL);
-       if (!ether->tdesc)
-               return -ENOMEM;
-
-       ether->rdesc = dma_alloc_coherent(&pdev->dev, sizeof(struct recv_pdesc),
-                                         &ether->rdesc_phys, GFP_KERNEL);
-       if (!ether->rdesc) {
-               dma_free_coherent(&pdev->dev, sizeof(struct tran_pdesc),
-                                 ether->tdesc, ether->tdesc_phys);
-               return -ENOMEM;
-       }
-
-       for (i = 0; i < TX_DESC_SIZE; i++) {
-               unsigned int offset;
-
-               tdesc = &(ether->tdesc->desclist[i]);
-
-               if (i == TX_DESC_SIZE - 1)
-                       offset = offsetof(struct tran_pdesc, desclist[0]);
-               else
-                       offset = offsetof(struct tran_pdesc, desclist[i + 1]);
-
-               tdesc->next = ether->tdesc_phys + offset;
-               tdesc->buffer = ether->tdesc_phys +
-                       offsetof(struct tran_pdesc, tran_buf[i]);
-               tdesc->sl = 0;
-               tdesc->mode = 0;
-       }
-
-       ether->start_tx_ptr = ether->tdesc_phys;
-
-       for (i = 0; i < RX_DESC_SIZE; i++) {
-               unsigned int offset;
-
-               rdesc = &(ether->rdesc->desclist[i]);
-
-               if (i == RX_DESC_SIZE - 1)
-                       offset = offsetof(struct recv_pdesc, desclist[0]);
-               else
-                       offset = offsetof(struct recv_pdesc, desclist[i + 1]);
-
-               rdesc->next = ether->rdesc_phys + offset;
-               rdesc->sl = RX_OWEN_DMA;
-               rdesc->buffer = ether->rdesc_phys +
-                       offsetof(struct recv_pdesc, recv_buf[i]);
-         }
-
-       ether->start_rx_ptr = ether->rdesc_phys;
-
-       return 0;
-}
-
-static void w90p910_set_fifo_threshold(struct net_device *dev)
-{
-       struct w90p910_ether *ether = netdev_priv(dev);
-       unsigned int val;
-
-       val = TXTHD | BLENGTH;
-       __raw_writel(val, ether->reg + REG_FFTCR);
-}
-
-static void w90p910_return_default_idle(struct net_device *dev)
-{
-       struct w90p910_ether *ether = netdev_priv(dev);
-       unsigned int val;
-
-       val = __raw_readl(ether->reg + REG_MCMDR);
-       val |= SWR;
-       __raw_writel(val, ether->reg + REG_MCMDR);
-}
-
-static void w90p910_trigger_rx(struct net_device *dev)
-{
-       struct w90p910_ether *ether = netdev_priv(dev);
-
-       __raw_writel(ENSTART, ether->reg + REG_RSDR);
-}
-
-static void w90p910_trigger_tx(struct net_device *dev)
-{
-       struct w90p910_ether *ether = netdev_priv(dev);
-
-       __raw_writel(ENSTART, ether->reg + REG_TSDR);
-}
-
-static void w90p910_enable_mac_interrupt(struct net_device *dev)
-{
-       struct w90p910_ether *ether = netdev_priv(dev);
-       unsigned int val;
-
-       val = ENTXINTR | ENRXINTR | ENRXGD | ENTXCP;
-       val |= ENTXBERR | ENRXBERR | ENTXABT;
-
-       __raw_writel(val, ether->reg + REG_MIEN);
-}
-
-static void w90p910_get_and_clear_int(struct net_device *dev,
-                                                       unsigned int *val)
-{
-       struct w90p910_ether *ether = netdev_priv(dev);
-
-       *val = __raw_readl(ether->reg + REG_MISTA);
-       __raw_writel(*val, ether->reg + REG_MISTA);
-}
-
-static void w90p910_set_global_maccmd(struct net_device *dev)
-{
-       struct w90p910_ether *ether = netdev_priv(dev);
-       unsigned int val;
-
-       val = __raw_readl(ether->reg + REG_MCMDR);
-       val |= MCMDR_SPCRC | MCMDR_ENMDC | MCMDR_ACP | ENMDC;
-       __raw_writel(val, ether->reg + REG_MCMDR);
-}
-
-static void w90p910_enable_cam(struct net_device *dev)
-{
-       struct w90p910_ether *ether = netdev_priv(dev);
-       unsigned int val;
-
-       w90p910_write_cam(dev, CAM0, dev->dev_addr);
-
-       val = __raw_readl(ether->reg + REG_CAMEN);
-       val |= CAM0EN;
-       __raw_writel(val, ether->reg + REG_CAMEN);
-}
-
-static void w90p910_enable_cam_command(struct net_device *dev)
-{
-       struct w90p910_ether *ether = netdev_priv(dev);
-       unsigned int val;
-
-       val = CAMCMR_ECMP | CAMCMR_ABP | CAMCMR_AMP;
-       __raw_writel(val, ether->reg + REG_CAMCMR);
-}
-
-static void w90p910_enable_tx(struct net_device *dev, unsigned int enable)
-{
-       struct w90p910_ether *ether = netdev_priv(dev);
-       unsigned int val;
-
-       val = __raw_readl(ether->reg + REG_MCMDR);
-
-       if (enable)
-               val |= MCMDR_TXON;
-       else
-               val &= ~MCMDR_TXON;
-
-       __raw_writel(val, ether->reg + REG_MCMDR);
-}
-
-static void w90p910_enable_rx(struct net_device *dev, unsigned int enable)
-{
-       struct w90p910_ether *ether = netdev_priv(dev);
-       unsigned int val;
-
-       val = __raw_readl(ether->reg + REG_MCMDR);
-
-       if (enable)
-               val |= MCMDR_RXON;
-       else
-               val &= ~MCMDR_RXON;
-
-       __raw_writel(val, ether->reg + REG_MCMDR);
-}
-
-static void w90p910_set_curdest(struct net_device *dev)
-{
-       struct w90p910_ether *ether = netdev_priv(dev);
-
-       __raw_writel(ether->start_rx_ptr, ether->reg + REG_RXDLSA);
-       __raw_writel(ether->start_tx_ptr, ether->reg + REG_TXDLSA);
-}
-
-static void w90p910_reset_mac(struct net_device *dev)
-{
-       struct w90p910_ether *ether = netdev_priv(dev);
-
-       w90p910_enable_tx(dev, 0);
-       w90p910_enable_rx(dev, 0);
-       w90p910_set_fifo_threshold(dev);
-       w90p910_return_default_idle(dev);
-
-       if (!netif_queue_stopped(dev))
-               netif_stop_queue(dev);
-
-       w90p910_init_desc(dev);
-
-       netif_trans_update(dev); /* prevent tx timeout */
-       ether->cur_tx = 0x0;
-       ether->finish_tx = 0x0;
-       ether->cur_rx = 0x0;
-
-       w90p910_set_curdest(dev);
-       w90p910_enable_cam(dev);
-       w90p910_enable_cam_command(dev);
-       w90p910_enable_mac_interrupt(dev);
-       w90p910_enable_tx(dev, 1);
-       w90p910_enable_rx(dev, 1);
-       w90p910_trigger_tx(dev);
-       w90p910_trigger_rx(dev);
-
-       netif_trans_update(dev); /* prevent tx timeout */
-
-       if (netif_queue_stopped(dev))
-               netif_wake_queue(dev);
-}
-
-static void w90p910_mdio_write(struct net_device *dev,
-                                       int phy_id, int reg, int data)
-{
-       struct w90p910_ether *ether = netdev_priv(dev);
-       struct platform_device *pdev;
-       unsigned int val, i;
-
-       pdev = ether->pdev;
-
-       __raw_writel(data, ether->reg + REG_MIID);
-
-       val = (phy_id << 0x08) | reg;
-       val |= PHYBUSY | PHYWR | MDCCR_VAL;
-       __raw_writel(val, ether->reg + REG_MIIDA);
-
-       for (i = 0; i < DELAY; i++) {
-               if ((__raw_readl(ether->reg + REG_MIIDA) & PHYBUSY) == 0)
-                       break;
-       }
-
-       if (i == DELAY)
-               dev_warn(&pdev->dev, "mdio write timed out\n");
-}
-
-static int w90p910_mdio_read(struct net_device *dev, int phy_id, int reg)
-{
-       struct w90p910_ether *ether = netdev_priv(dev);
-       struct platform_device *pdev;
-       unsigned int val, i, data;
-
-       pdev = ether->pdev;
-
-       val = (phy_id << 0x08) | reg;
-       val |= PHYBUSY | MDCCR_VAL;
-       __raw_writel(val, ether->reg + REG_MIIDA);
-
-       for (i = 0; i < DELAY; i++) {
-               if ((__raw_readl(ether->reg + REG_MIIDA) & PHYBUSY) == 0)
-                       break;
-       }
-
-       if (i == DELAY) {
-               dev_warn(&pdev->dev, "mdio read timed out\n");
-               data = 0xffff;
-       } else {
-               data = __raw_readl(ether->reg + REG_MIID);
-       }
-
-       return data;
-}
-
-static int w90p910_set_mac_address(struct net_device *dev, void *addr)
-{
-       struct sockaddr *address = addr;
-
-       if (!is_valid_ether_addr(address->sa_data))
-               return -EADDRNOTAVAIL;
-
-       memcpy(dev->dev_addr, address->sa_data, dev->addr_len);
-       w90p910_write_cam(dev, CAM0, dev->dev_addr);
-
-       return 0;
-}
-
-static int w90p910_ether_close(struct net_device *dev)
-{
-       struct w90p910_ether *ether = netdev_priv(dev);
-       struct platform_device *pdev;
-
-       pdev = ether->pdev;
-
-       dma_free_coherent(&pdev->dev, sizeof(struct recv_pdesc),
-                                       ether->rdesc, ether->rdesc_phys);
-       dma_free_coherent(&pdev->dev, sizeof(struct tran_pdesc),
-                                       ether->tdesc, ether->tdesc_phys);
-
-       netif_stop_queue(dev);
-
-       del_timer_sync(&ether->check_timer);
-       clk_disable(ether->rmiiclk);
-       clk_disable(ether->clk);
-
-       free_irq(ether->txirq, dev);
-       free_irq(ether->rxirq, dev);
-
-       return 0;
-}
-
-static int w90p910_send_frame(struct net_device *dev,
-                                       unsigned char *data, int length)
-{
-       struct w90p910_ether *ether;
-       struct w90p910_txbd *txbd;
-       struct platform_device *pdev;
-       unsigned char *buffer;
-
-       ether = netdev_priv(dev);
-       pdev = ether->pdev;
-
-       txbd = &ether->tdesc->desclist[ether->cur_tx];
-       buffer = ether->tdesc->tran_buf[ether->cur_tx];
-
-       if (length > 1514) {
-               dev_err(&pdev->dev, "send data %d bytes, check it\n", length);
-               length = 1514;
-       }
-
-       txbd->sl = length & 0xFFFF;
-
-       memcpy(buffer, data, length);
-
-       txbd->mode = TX_OWEN_DMA | PADDINGMODE | CRCMODE | MACTXINTEN;
-
-       w90p910_enable_tx(dev, 1);
-
-       w90p910_trigger_tx(dev);
-
-       if (++ether->cur_tx >= TX_DESC_SIZE)
-               ether->cur_tx = 0;
-
-       txbd = &ether->tdesc->desclist[ether->cur_tx];
-
-       if (txbd->mode & TX_OWEN_DMA)
-               netif_stop_queue(dev);
-
-       return 0;
-}
-
-static int w90p910_ether_start_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-       struct w90p910_ether *ether = netdev_priv(dev);
-
-       if (!(w90p910_send_frame(dev, skb->data, skb->len))) {
-               ether->skb = skb;
-               dev_consume_skb_irq(skb);
-               return 0;
-       }
-       return -EAGAIN;
-}
-
-static irqreturn_t w90p910_tx_interrupt(int irq, void *dev_id)
-{
-       struct w90p910_ether *ether;
-       struct w90p910_txbd  *txbd;
-       struct platform_device *pdev;
-       struct net_device *dev;
-       unsigned int cur_entry, entry, status;
-
-       dev = dev_id;
-       ether = netdev_priv(dev);
-       pdev = ether->pdev;
-
-       w90p910_get_and_clear_int(dev, &status);
-
-       cur_entry = __raw_readl(ether->reg + REG_CTXDSA);
-
-       entry = ether->tdesc_phys +
-               offsetof(struct tran_pdesc, desclist[ether->finish_tx]);
-
-       while (entry != cur_entry) {
-               txbd = &ether->tdesc->desclist[ether->finish_tx];
-
-               if (++ether->finish_tx >= TX_DESC_SIZE)
-                       ether->finish_tx = 0;
-
-               if (txbd->sl & TXDS_TXCP) {
-                       dev->stats.tx_packets++;
-                       dev->stats.tx_bytes += txbd->sl & 0xFFFF;
-               } else {
-                       dev->stats.tx_errors++;
-               }
-
-               txbd->sl = 0x0;
-               txbd->mode = 0x0;
-
-               if (netif_queue_stopped(dev))
-                       netif_wake_queue(dev);
-
-               entry = ether->tdesc_phys +
-                       offsetof(struct tran_pdesc, desclist[ether->finish_tx]);
-       }
-
-       if (status & MISTA_EXDEF) {
-               dev_err(&pdev->dev, "emc defer exceed interrupt\n");
-       } else if (status & MISTA_TXBERR) {
-               dev_err(&pdev->dev, "emc bus error interrupt\n");
-               w90p910_reset_mac(dev);
-       } else if (status & MISTA_TDU) {
-               if (netif_queue_stopped(dev))
-                       netif_wake_queue(dev);
-       }
-
-       return IRQ_HANDLED;
-}
-
-static void netdev_rx(struct net_device *dev)
-{
-       struct w90p910_ether *ether;
-       struct w90p910_rxbd *rxbd;
-       struct platform_device *pdev;
-       struct sk_buff *skb;
-       unsigned char *data;
-       unsigned int length, status, val, entry;
-
-       ether = netdev_priv(dev);
-       pdev = ether->pdev;
-
-       rxbd = &ether->rdesc->desclist[ether->cur_rx];
-
-       do {
-               val = __raw_readl(ether->reg + REG_CRXDSA);
-
-               entry = ether->rdesc_phys +
-                       offsetof(struct recv_pdesc, desclist[ether->cur_rx]);
-
-               if (val == entry)
-                       break;
-
-               status = rxbd->sl;
-               length = status & 0xFFFF;
-
-               if (status & RXDS_RXGD) {
-                       data = ether->rdesc->recv_buf[ether->cur_rx];
-                       skb = netdev_alloc_skb(dev, length + 2);
-                       if (!skb) {
-                               dev->stats.rx_dropped++;
-                               return;
-                       }
-
-                       skb_reserve(skb, 2);
-                       skb_put(skb, length);
-                       skb_copy_to_linear_data(skb, data, length);
-                       skb->protocol = eth_type_trans(skb, dev);
-                       dev->stats.rx_packets++;
-                       dev->stats.rx_bytes += length;
-                       netif_rx(skb);
-               } else {
-                       dev->stats.rx_errors++;
-
-                       if (status & RXDS_RP) {
-                               dev_err(&pdev->dev, "rx runt err\n");
-                               dev->stats.rx_length_errors++;
-                       } else if (status & RXDS_CRCE) {
-                               dev_err(&pdev->dev, "rx crc err\n");
-                               dev->stats.rx_crc_errors++;
-                       } else if (status & RXDS_ALIE) {
-                               dev_err(&pdev->dev, "rx alignment err\n");
-                               dev->stats.rx_frame_errors++;
-                       } else if (status & RXDS_PTLE) {
-                               dev_err(&pdev->dev, "rx longer err\n");
-                               dev->stats.rx_over_errors++;
-                       }
-               }
-
-               rxbd->sl = RX_OWEN_DMA;
-               rxbd->reserved = 0x0;
-
-               if (++ether->cur_rx >= RX_DESC_SIZE)
-                       ether->cur_rx = 0;
-
-               rxbd = &ether->rdesc->desclist[ether->cur_rx];
-
-       } while (1);
-}
-
-static irqreturn_t w90p910_rx_interrupt(int irq, void *dev_id)
-{
-       struct net_device *dev;
-       struct w90p910_ether  *ether;
-       struct platform_device *pdev;
-       unsigned int status;
-
-       dev = dev_id;
-       ether = netdev_priv(dev);
-       pdev = ether->pdev;
-
-       w90p910_get_and_clear_int(dev, &status);
-
-       if (status & MISTA_RDU) {
-               netdev_rx(dev);
-               w90p910_trigger_rx(dev);
-
-               return IRQ_HANDLED;
-       } else if (status & MISTA_RXBERR) {
-               dev_err(&pdev->dev, "emc rx bus error\n");
-               w90p910_reset_mac(dev);
-       }
-
-       netdev_rx(dev);
-       return IRQ_HANDLED;
-}
-
-static int w90p910_ether_open(struct net_device *dev)
-{
-       struct w90p910_ether *ether;
-       struct platform_device *pdev;
-
-       ether = netdev_priv(dev);
-       pdev = ether->pdev;
-
-       w90p910_reset_mac(dev);
-       w90p910_set_fifo_threshold(dev);
-       w90p910_set_curdest(dev);
-       w90p910_enable_cam(dev);
-       w90p910_enable_cam_command(dev);
-       w90p910_enable_mac_interrupt(dev);
-       w90p910_set_global_maccmd(dev);
-       w90p910_enable_rx(dev, 1);
-
-       clk_enable(ether->rmiiclk);
-       clk_enable(ether->clk);
-
-       ether->rx_packets = 0x0;
-       ether->rx_bytes = 0x0;
-
-       if (request_irq(ether->txirq, w90p910_tx_interrupt,
-                                               0x0, pdev->name, dev)) {
-               dev_err(&pdev->dev, "register irq tx failed\n");
-               return -EAGAIN;
-       }
-
-       if (request_irq(ether->rxirq, w90p910_rx_interrupt,
-                                               0x0, pdev->name, dev)) {
-               dev_err(&pdev->dev, "register irq rx failed\n");
-               free_irq(ether->txirq, dev);
-               return -EAGAIN;
-       }
-
-       mod_timer(&ether->check_timer, jiffies + msecs_to_jiffies(1000));
-       netif_start_queue(dev);
-       w90p910_trigger_rx(dev);
-
-       dev_info(&pdev->dev, "%s is OPENED\n", dev->name);
-
-       return 0;
-}
-
-static void w90p910_ether_set_multicast_list(struct net_device *dev)
-{
-       struct w90p910_ether *ether;
-       unsigned int rx_mode;
-
-       ether = netdev_priv(dev);
-
-       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;
-       __raw_writel(rx_mode, ether->reg + REG_CAMCMR);
-}
-
-static int w90p910_ether_ioctl(struct net_device *dev,
-                                               struct ifreq *ifr, int cmd)
-{
-       struct w90p910_ether *ether = netdev_priv(dev);
-       struct mii_ioctl_data *data = if_mii(ifr);
-
-       return generic_mii_ioctl(&ether->mii, data, cmd, NULL);
-}
-
-static void w90p910_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));
-}
-
-static int w90p910_get_link_ksettings(struct net_device *dev,
-                                     struct ethtool_link_ksettings *cmd)
-{
-       struct w90p910_ether *ether = netdev_priv(dev);
-
-       mii_ethtool_get_link_ksettings(&ether->mii, cmd);
-
-       return 0;
-}
-
-static int w90p910_set_link_ksettings(struct net_device *dev,
-                                     const struct ethtool_link_ksettings *cmd)
-{
-       struct w90p910_ether *ether = netdev_priv(dev);
-       return mii_ethtool_set_link_ksettings(&ether->mii, cmd);
-}
-
-static int w90p910_nway_reset(struct net_device *dev)
-{
-       struct w90p910_ether *ether = netdev_priv(dev);
-       return mii_nway_restart(&ether->mii);
-}
-
-static u32 w90p910_get_link(struct net_device *dev)
-{
-       struct w90p910_ether *ether = netdev_priv(dev);
-       return mii_link_ok(&ether->mii);
-}
-
-static const struct ethtool_ops w90p910_ether_ethtool_ops = {
-       .get_drvinfo    = w90p910_get_drvinfo,
-       .nway_reset     = w90p910_nway_reset,
-       .get_link       = w90p910_get_link,
-       .get_link_ksettings = w90p910_get_link_ksettings,
-       .set_link_ksettings = w90p910_set_link_ksettings,
-};
-
-static const struct net_device_ops w90p910_ether_netdev_ops = {
-       .ndo_open               = w90p910_ether_open,
-       .ndo_stop               = w90p910_ether_close,
-       .ndo_start_xmit         = w90p910_ether_start_xmit,
-       .ndo_set_rx_mode        = w90p910_ether_set_multicast_list,
-       .ndo_set_mac_address    = w90p910_set_mac_address,
-       .ndo_do_ioctl           = w90p910_ether_ioctl,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-static void get_mac_address(struct net_device *dev)
-{
-       struct w90p910_ether *ether = netdev_priv(dev);
-       struct platform_device *pdev;
-       char addr[ETH_ALEN];
-
-       pdev = ether->pdev;
-
-       addr[0] = 0x00;
-       addr[1] = 0x02;
-       addr[2] = 0xac;
-       addr[3] = 0x55;
-       addr[4] = 0x88;
-       addr[5] = 0xa8;
-
-       if (is_valid_ether_addr(addr))
-               memcpy(dev->dev_addr, &addr, ETH_ALEN);
-       else
-               dev_err(&pdev->dev, "invalid mac address\n");
-}
-
-static int w90p910_ether_setup(struct net_device *dev)
-{
-       struct w90p910_ether *ether = netdev_priv(dev);
-
-       dev->netdev_ops = &w90p910_ether_netdev_ops;
-       dev->ethtool_ops = &w90p910_ether_ethtool_ops;
-
-       dev->tx_queue_len = 16;
-       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->linkflag = 0x0;
-       ether->mii.phy_id = 0x01;
-       ether->mii.phy_id_mask = 0x1f;
-       ether->mii.reg_num_mask = 0x1f;
-       ether->mii.dev = dev;
-       ether->mii.mdio_read = w90p910_mdio_read;
-       ether->mii.mdio_write = w90p910_mdio_write;
-
-       timer_setup(&ether->check_timer, w90p910_check_link, 0);
-
-       return 0;
-}
-
-static int w90p910_ether_probe(struct platform_device *pdev)
-{
-       struct w90p910_ether *ether;
-       struct net_device *dev;
-       int error;
-
-       dev = alloc_etherdev(sizeof(struct w90p910_ether));
-       if (!dev)
-               return -ENOMEM;
-
-       ether = netdev_priv(dev);
-
-       ether->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (ether->res == NULL) {
-               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));
-       if (ether->reg == NULL) {
-               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;
-       }
-
-       platform_set_drvdata(pdev, dev);
-
-       ether->clk = clk_get(&pdev->dev, NULL);
-       if (IS_ERR(ether->clk)) {
-               dev_err(&pdev->dev, "failed to get ether clock\n");
-               error = PTR_ERR(ether->clk);
-               goto failed_free_io;
-       }
-
-       ether->rmiiclk = clk_get(&pdev->dev, "RMII");
-       if (IS_ERR(ether->rmiiclk)) {
-               dev_err(&pdev->dev, "failed to get ether clock\n");
-               error = PTR_ERR(ether->rmiiclk);
-               goto failed_put_clk;
-       }
-
-       ether->pdev = pdev;
-
-       w90p910_ether_setup(dev);
-
-       error = register_netdev(dev);
-       if (error != 0) {
-               dev_err(&pdev->dev, "Register EMC w90p910 FAILED\n");
-               error = -ENODEV;
-               goto failed_put_rmiiclk;
-       }
-
-       return 0;
-failed_put_rmiiclk:
-       clk_put(ether->rmiiclk);
-failed_put_clk:
-       clk_put(ether->clk);
-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 w90p910_ether_remove(struct platform_device *pdev)
-{
-       struct net_device *dev = platform_get_drvdata(pdev);
-       struct w90p910_ether *ether = netdev_priv(dev);
-
-       unregister_netdev(dev);
-
-       clk_put(ether->rmiiclk);
-       clk_put(ether->clk);
-
-       iounmap(ether->reg);
-       release_mem_region(ether->res->start, resource_size(ether->res));
-
-       del_timer_sync(&ether->check_timer);
-
-       free_netdev(dev);
-       return 0;
-}
-
-static struct platform_driver w90p910_ether_driver = {
-       .probe          = w90p910_ether_probe,
-       .remove         = w90p910_ether_remove,
-       .driver         = {
-               .name   = "nuc900-emc",
-       },
-};
-
-module_platform_driver(w90p910_ether_driver);
-
-MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
-MODULE_DESCRIPTION("w90p910 MAC driver!");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:nuc900-emc");
-
index 21efb7d..7b07281 100644 (file)
@@ -116,9 +116,20 @@ config RESET_QCOM_PDC
          to control reset signals provided by PDC for Modem, Compute,
          Display, GPU, Debug, AOP, Sensors, Audio, SP and APPS.
 
+config RESET_SCMI
+       tristate "Reset driver controlled via ARM SCMI interface"
+       depends on ARM_SCMI_PROTOCOL || COMPILE_TEST
+       default ARM_SCMI_PROTOCOL
+       help
+         This driver provides support for reset signal/domains that are
+         controlled by firmware that implements the SCMI interface.
+
+         This driver uses SCMI Message Protocol to interact with the
+         firmware controlling all the reset signals.
+
 config RESET_SIMPLE
        bool "Simple Reset Controller Driver" if COMPILE_TEST
-       default ARCH_STM32 || ARCH_STRATIX10 || ARCH_SUNXI || ARCH_ZX || ARCH_ASPEED || ARCH_BITMAIN
+       default ARCH_STM32 || ARCH_STRATIX10 || ARCH_SUNXI || ARCH_ZX || ARCH_ASPEED || ARCH_BITMAIN || ARC
        help
          This enables a simple reset controller driver for reset lines that
          that can be asserted and deasserted by toggling bits in a contiguous,
index 61456b8..cf60ce5 100644 (file)
@@ -18,6 +18,7 @@ obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o
 obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o
 obj-$(CONFIG_RESET_QCOM_AOSS) += reset-qcom-aoss.o
 obj-$(CONFIG_RESET_QCOM_PDC) += reset-qcom-pdc.o
+obj-$(CONFIG_RESET_SCMI) += reset-scmi.o
 obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o
 obj-$(CONFIG_RESET_STM32MP157) += reset-stm32mp1.o
 obj-$(CONFIG_RESET_SOCFPGA) += reset-socfpga.o
index 3ecd770..1443a55 100644 (file)
@@ -169,9 +169,9 @@ static const struct imx7_src_signal imx8mq_src_signals[IMX8MQ_RESET_NUM] = {
        [IMX8MQ_RESET_OTG2_PHY_RESET]           = { SRC_USBOPHY2_RCR, BIT(0) },
        [IMX8MQ_RESET_MIPI_DSI_RESET_BYTE_N]    = { SRC_MIPIPHY_RCR, BIT(1) },
        [IMX8MQ_RESET_MIPI_DSI_RESET_N]         = { SRC_MIPIPHY_RCR, BIT(2) },
-       [IMX8MQ_RESET_MIPI_DIS_DPI_RESET_N]     = { SRC_MIPIPHY_RCR, BIT(3) },
-       [IMX8MQ_RESET_MIPI_DIS_ESC_RESET_N]     = { SRC_MIPIPHY_RCR, BIT(4) },
-       [IMX8MQ_RESET_MIPI_DIS_PCLK_RESET_N]    = { SRC_MIPIPHY_RCR, BIT(5) },
+       [IMX8MQ_RESET_MIPI_DSI_DPI_RESET_N]     = { SRC_MIPIPHY_RCR, BIT(3) },
+       [IMX8MQ_RESET_MIPI_DSI_ESC_RESET_N]     = { SRC_MIPIPHY_RCR, BIT(4) },
+       [IMX8MQ_RESET_MIPI_DSI_PCLK_RESET_N]    = { SRC_MIPIPHY_RCR, BIT(5) },
        [IMX8MQ_RESET_PCIEPHY]                  = { SRC_PCIEPHY_RCR,
                                                    BIT(2) | BIT(1) },
        [IMX8MQ_RESET_PCIEPHY_PERST]            = { SRC_PCIEPHY_RCR, BIT(3) },
@@ -220,9 +220,9 @@ static int imx8mq_reset_set(struct reset_controller_dev *rcdev,
 
        case IMX8MQ_RESET_PCIE_CTRL_APPS_EN:
        case IMX8MQ_RESET_PCIE2_CTRL_APPS_EN:   /* fallthrough */
-       case IMX8MQ_RESET_MIPI_DIS_PCLK_RESET_N:        /* fallthrough */
-       case IMX8MQ_RESET_MIPI_DIS_ESC_RESET_N: /* fallthrough */
-       case IMX8MQ_RESET_MIPI_DIS_DPI_RESET_N: /* fallthrough */
+       case IMX8MQ_RESET_MIPI_DSI_PCLK_RESET_N:        /* fallthrough */
+       case IMX8MQ_RESET_MIPI_DSI_ESC_RESET_N: /* fallthrough */
+       case IMX8MQ_RESET_MIPI_DSI_DPI_RESET_N: /* fallthrough */
        case IMX8MQ_RESET_MIPI_DSI_RESET_N:     /* fallthrough */
        case IMX8MQ_RESET_MIPI_DSI_RESET_BYTE_N:        /* fallthrough */
                value = assert ? 0 : bit;
index 5242e06..7d05d76 100644 (file)
@@ -1,58 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 /*
  * Amlogic Meson Reset Controller driver
  *
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright (c) 2016 BayLibre, SAS.
- * Author: Neil Armstrong <narmstrong@baylibre.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- * The full GNU General Public License is included in this distribution
- * in the file called COPYING.
- *
- * BSD LICENSE
- *
  * Copyright (c) 2016 BayLibre, SAS.
  * Author: Neil Armstrong <narmstrong@baylibre.com>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *   * Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- *   * Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in
- *     the documentation and/or other materials provided with the
- *     distribution.
- *   * Neither the name of Intel Corporation nor the names of its
- *     contributors may be used to endorse or promote products derived
- *     from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include <linux/err.h>
 #include <linux/init.h>
diff --git a/drivers/reset/reset-scmi.c b/drivers/reset/reset-scmi.c
new file mode 100644 (file)
index 0000000..c6d3c84
--- /dev/null
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ARM System Control and Management Interface (ARM SCMI) reset driver
+ *
+ * Copyright (C) 2019 ARM Ltd.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/device.h>
+#include <linux/reset-controller.h>
+#include <linux/scmi_protocol.h>
+
+/**
+ * struct scmi_reset_data - reset controller information structure
+ * @rcdev: reset controller entity
+ * @handle: ARM SCMI handle used for communication with system controller
+ */
+struct scmi_reset_data {
+       struct reset_controller_dev rcdev;
+       const struct scmi_handle *handle;
+};
+
+#define to_scmi_reset_data(p)  container_of((p), struct scmi_reset_data, rcdev)
+#define to_scmi_handle(p)      (to_scmi_reset_data(p)->handle)
+
+/**
+ * scmi_reset_assert() - assert device reset
+ * @rcdev: reset controller entity
+ * @id: ID of the reset to be asserted
+ *
+ * This function implements the reset driver op to assert a device's reset
+ * using the ARM SCMI protocol.
+ *
+ * Return: 0 for successful request, else a corresponding error value
+ */
+static int
+scmi_reset_assert(struct reset_controller_dev *rcdev, unsigned long id)
+{
+       const struct scmi_handle *handle = to_scmi_handle(rcdev);
+
+       return handle->reset_ops->assert(handle, id);
+}
+
+/**
+ * scmi_reset_deassert() - deassert device reset
+ * @rcdev: reset controller entity
+ * @id: ID of the reset to be deasserted
+ *
+ * This function implements the reset driver op to deassert a device's reset
+ * using the ARM SCMI protocol.
+ *
+ * Return: 0 for successful request, else a corresponding error value
+ */
+static int
+scmi_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id)
+{
+       const struct scmi_handle *handle = to_scmi_handle(rcdev);
+
+       return handle->reset_ops->deassert(handle, id);
+}
+
+/**
+ * scmi_reset_reset() - reset the device
+ * @rcdev: reset controller entity
+ * @id: ID of the reset signal to be reset(assert + deassert)
+ *
+ * This function implements the reset driver op to trigger a device's
+ * reset signal using the ARM SCMI protocol.
+ *
+ * Return: 0 for successful request, else a corresponding error value
+ */
+static int
+scmi_reset_reset(struct reset_controller_dev *rcdev, unsigned long id)
+{
+       const struct scmi_handle *handle = to_scmi_handle(rcdev);
+
+       return handle->reset_ops->reset(handle, id);
+}
+
+static const struct reset_control_ops scmi_reset_ops = {
+       .assert         = scmi_reset_assert,
+       .deassert       = scmi_reset_deassert,
+       .reset          = scmi_reset_reset,
+};
+
+static int scmi_reset_probe(struct scmi_device *sdev)
+{
+       struct scmi_reset_data *data;
+       struct device *dev = &sdev->dev;
+       struct device_node *np = dev->of_node;
+       const struct scmi_handle *handle = sdev->handle;
+
+       if (!handle || !handle->reset_ops)
+               return -ENODEV;
+
+       data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       data->rcdev.ops = &scmi_reset_ops;
+       data->rcdev.owner = THIS_MODULE;
+       data->rcdev.of_node = np;
+       data->rcdev.nr_resets = handle->reset_ops->num_domains_get(handle);
+
+       return devm_reset_controller_register(dev, &data->rcdev);
+}
+
+static const struct scmi_device_id scmi_id_table[] = {
+       { SCMI_PROTOCOL_RESET },
+       { },
+};
+MODULE_DEVICE_TABLE(scmi, scmi_id_table);
+
+static struct scmi_driver scmi_reset_driver = {
+       .name = "scmi-reset",
+       .probe = scmi_reset_probe,
+       .id_table = scmi_id_table,
+};
+module_scmi_driver(scmi_reset_driver);
+
+MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
+MODULE_DESCRIPTION("ARM SCMI reset controller driver");
+MODULE_LICENSE("GPL v2");
index 1154f7b..067e7e7 100644 (file)
@@ -127,6 +127,9 @@ static const struct of_device_id reset_simple_dt_ids[] = {
        { .compatible = "aspeed,ast2500-lpc-reset" },
        { .compatible = "bitmain,bm1880-reset",
                .data = &reset_simple_active_low },
+       { .compatible = "snps,dw-high-reset" },
+       { .compatible = "snps,dw-low-reset",
+               .data = &reset_simple_active_low },
        { /* sentinel */ },
 };
 
index 23bfb8e..bc2c912 100644 (file)
@@ -37,6 +37,17 @@ config MESON_GX_PM_DOMAINS
          Say yes to expose Amlogic Meson GX Power Domains as
          Generic Power Domains.
 
+config MESON_EE_PM_DOMAINS
+       bool "Amlogic Meson Everything-Else Power Domains driver"
+       depends on ARCH_MESON || COMPILE_TEST
+       depends on PM && OF
+       default ARCH_MESON
+       select PM_GENERIC_DOMAINS
+       select PM_GENERIC_DOMAINS_OF
+       help
+         Say yes to expose Amlogic Meson Everything-Else Power Domains as
+         Generic Power Domains.
+
 config MESON_MX_SOCINFO
        bool "Amlogic Meson MX SoC Information driver"
        depends on ARCH_MESON || COMPILE_TEST
index f2e4ed1..de79d04 100644 (file)
@@ -4,3 +4,4 @@ obj-$(CONFIG_MESON_CLK_MEASURE) += meson-clk-measure.o
 obj-$(CONFIG_MESON_GX_SOCINFO) += meson-gx-socinfo.o
 obj-$(CONFIG_MESON_GX_PM_DOMAINS) += meson-gx-pwrc-vpu.o
 obj-$(CONFIG_MESON_MX_SOCINFO) += meson-mx-socinfo.o
+obj-$(CONFIG_MESON_EE_PM_DOMAINS) += meson-ee-pwrc.o
index 19d4cbc..0fa47d7 100644 (file)
@@ -11,6 +11,8 @@
 #include <linux/debugfs.h>
 #include <linux/regmap.h>
 
+static DEFINE_MUTEX(measure_lock);
+
 #define MSR_CLK_DUTY           0x0
 #define MSR_CLK_REG0           0x4
 #define MSR_CLK_REG1           0x8
@@ -322,6 +324,8 @@ static struct meson_msr_id clk_msr_g12a[CLK_MSR_MAX] = {
        CLK_MSR_ID(84, "co_tx"),
        CLK_MSR_ID(89, "hdmi_todig"),
        CLK_MSR_ID(90, "hdmitx_sys"),
+       CLK_MSR_ID(91, "sys_cpub_div16"),
+       CLK_MSR_ID(92, "sys_pll_cpub_div16"),
        CLK_MSR_ID(94, "eth_phy_rx"),
        CLK_MSR_ID(95, "eth_phy_pll"),
        CLK_MSR_ID(96, "vpu_b"),
@@ -353,6 +357,136 @@ static struct meson_msr_id clk_msr_g12a[CLK_MSR_MAX] = {
        CLK_MSR_ID(122, "audio_pdm_dclk"),
 };
 
+static struct meson_msr_id clk_msr_sm1[CLK_MSR_MAX] = {
+       CLK_MSR_ID(0, "ring_osc_out_ee_0"),
+       CLK_MSR_ID(1, "ring_osc_out_ee_1"),
+       CLK_MSR_ID(2, "ring_osc_out_ee_2"),
+       CLK_MSR_ID(3, "ring_osc_out_ee_3"),
+       CLK_MSR_ID(4, "gp0_pll"),
+       CLK_MSR_ID(5, "gp1_pll"),
+       CLK_MSR_ID(6, "enci"),
+       CLK_MSR_ID(7, "clk81"),
+       CLK_MSR_ID(8, "encp"),
+       CLK_MSR_ID(9, "encl"),
+       CLK_MSR_ID(10, "vdac"),
+       CLK_MSR_ID(11, "eth_tx"),
+       CLK_MSR_ID(12, "hifi_pll"),
+       CLK_MSR_ID(13, "mod_tcon"),
+       CLK_MSR_ID(14, "fec_0"),
+       CLK_MSR_ID(15, "fec_1"),
+       CLK_MSR_ID(16, "fec_2"),
+       CLK_MSR_ID(17, "sys_pll_div16"),
+       CLK_MSR_ID(18, "sys_cpu_div16"),
+       CLK_MSR_ID(19, "lcd_an_ph2"),
+       CLK_MSR_ID(20, "rtc_osc_out"),
+       CLK_MSR_ID(21, "lcd_an_ph3"),
+       CLK_MSR_ID(22, "eth_phy_ref"),
+       CLK_MSR_ID(23, "mpll_50m"),
+       CLK_MSR_ID(24, "eth_125m"),
+       CLK_MSR_ID(25, "eth_rmii"),
+       CLK_MSR_ID(26, "sc_int"),
+       CLK_MSR_ID(27, "in_mac"),
+       CLK_MSR_ID(28, "sar_adc"),
+       CLK_MSR_ID(29, "pcie_inp"),
+       CLK_MSR_ID(30, "pcie_inn"),
+       CLK_MSR_ID(31, "mpll_test_out"),
+       CLK_MSR_ID(32, "vdec"),
+       CLK_MSR_ID(34, "eth_mpll_50m"),
+       CLK_MSR_ID(35, "mali"),
+       CLK_MSR_ID(36, "hdmi_tx_pixel"),
+       CLK_MSR_ID(37, "cdac"),
+       CLK_MSR_ID(38, "vdin_meas"),
+       CLK_MSR_ID(39, "bt656"),
+       CLK_MSR_ID(40, "arm_ring_osc_out_4"),
+       CLK_MSR_ID(41, "eth_rx_or_rmii"),
+       CLK_MSR_ID(42, "mp0_out"),
+       CLK_MSR_ID(43, "fclk_div5"),
+       CLK_MSR_ID(44, "pwm_b"),
+       CLK_MSR_ID(45, "pwm_a"),
+       CLK_MSR_ID(46, "vpu"),
+       CLK_MSR_ID(47, "ddr_dpll_pt"),
+       CLK_MSR_ID(48, "mp1_out"),
+       CLK_MSR_ID(49, "mp2_out"),
+       CLK_MSR_ID(50, "mp3_out"),
+       CLK_MSR_ID(51, "sd_emmc_c"),
+       CLK_MSR_ID(52, "sd_emmc_b"),
+       CLK_MSR_ID(53, "sd_emmc_a"),
+       CLK_MSR_ID(54, "vpu_clkc"),
+       CLK_MSR_ID(55, "vid_pll_div_out"),
+       CLK_MSR_ID(56, "wave420l_a"),
+       CLK_MSR_ID(57, "wave420l_c"),
+       CLK_MSR_ID(58, "wave420l_b"),
+       CLK_MSR_ID(59, "hcodec"),
+       CLK_MSR_ID(60, "arm_ring_osc_out_5"),
+       CLK_MSR_ID(61, "gpio_msr"),
+       CLK_MSR_ID(62, "hevcb"),
+       CLK_MSR_ID(63, "dsi_meas"),
+       CLK_MSR_ID(64, "spicc_1"),
+       CLK_MSR_ID(65, "spicc_0"),
+       CLK_MSR_ID(66, "vid_lock"),
+       CLK_MSR_ID(67, "dsi_phy"),
+       CLK_MSR_ID(68, "hdcp22_esm"),
+       CLK_MSR_ID(69, "hdcp22_skp"),
+       CLK_MSR_ID(70, "pwm_f"),
+       CLK_MSR_ID(71, "pwm_e"),
+       CLK_MSR_ID(72, "pwm_d"),
+       CLK_MSR_ID(73, "pwm_c"),
+       CLK_MSR_ID(74, "arm_ring_osc_out_6"),
+       CLK_MSR_ID(75, "hevcf"),
+       CLK_MSR_ID(76, "arm_ring_osc_out_7"),
+       CLK_MSR_ID(77, "rng_ring_osc_0"),
+       CLK_MSR_ID(78, "rng_ring_osc_1"),
+       CLK_MSR_ID(79, "rng_ring_osc_2"),
+       CLK_MSR_ID(80, "rng_ring_osc_3"),
+       CLK_MSR_ID(81, "vapb"),
+       CLK_MSR_ID(82, "ge2d"),
+       CLK_MSR_ID(83, "co_rx"),
+       CLK_MSR_ID(84, "co_tx"),
+       CLK_MSR_ID(85, "arm_ring_osc_out_8"),
+       CLK_MSR_ID(86, "arm_ring_osc_out_9"),
+       CLK_MSR_ID(87, "mipi_dsi_phy"),
+       CLK_MSR_ID(88, "cis2_adapt"),
+       CLK_MSR_ID(89, "hdmi_todig"),
+       CLK_MSR_ID(90, "hdmitx_sys"),
+       CLK_MSR_ID(91, "nna_core"),
+       CLK_MSR_ID(92, "nna_axi"),
+       CLK_MSR_ID(93, "vad"),
+       CLK_MSR_ID(94, "eth_phy_rx"),
+       CLK_MSR_ID(95, "eth_phy_pll"),
+       CLK_MSR_ID(96, "vpu_b"),
+       CLK_MSR_ID(97, "cpu_b_tmp"),
+       CLK_MSR_ID(98, "ts"),
+       CLK_MSR_ID(99, "arm_ring_osc_out_10"),
+       CLK_MSR_ID(100, "arm_ring_osc_out_11"),
+       CLK_MSR_ID(101, "arm_ring_osc_out_12"),
+       CLK_MSR_ID(102, "arm_ring_osc_out_13"),
+       CLK_MSR_ID(103, "arm_ring_osc_out_14"),
+       CLK_MSR_ID(104, "arm_ring_osc_out_15"),
+       CLK_MSR_ID(105, "arm_ring_osc_out_16"),
+       CLK_MSR_ID(106, "ephy_test"),
+       CLK_MSR_ID(107, "au_dac_g128x"),
+       CLK_MSR_ID(108, "audio_locker_out"),
+       CLK_MSR_ID(109, "audio_locker_in"),
+       CLK_MSR_ID(110, "audio_tdmout_c_sclk"),
+       CLK_MSR_ID(111, "audio_tdmout_b_sclk"),
+       CLK_MSR_ID(112, "audio_tdmout_a_sclk"),
+       CLK_MSR_ID(113, "audio_tdmin_lb_sclk"),
+       CLK_MSR_ID(114, "audio_tdmin_c_sclk"),
+       CLK_MSR_ID(115, "audio_tdmin_b_sclk"),
+       CLK_MSR_ID(116, "audio_tdmin_a_sclk"),
+       CLK_MSR_ID(117, "audio_resample"),
+       CLK_MSR_ID(118, "audio_pdm_sys"),
+       CLK_MSR_ID(119, "audio_spdifout_b"),
+       CLK_MSR_ID(120, "audio_spdifout"),
+       CLK_MSR_ID(121, "audio_spdifin"),
+       CLK_MSR_ID(122, "audio_pdm_dclk"),
+       CLK_MSR_ID(123, "audio_resampled"),
+       CLK_MSR_ID(124, "earcrx_pll"),
+       CLK_MSR_ID(125, "earcrx_pll_test"),
+       CLK_MSR_ID(126, "csi_phy0"),
+       CLK_MSR_ID(127, "csi2_data"),
+};
+
 static int meson_measure_id(struct meson_msr_id *clk_msr_id,
                               unsigned int duration)
 {
@@ -360,6 +494,10 @@ static int meson_measure_id(struct meson_msr_id *clk_msr_id,
        unsigned int val;
        int ret;
 
+       ret = mutex_lock_interruptible(&measure_lock);
+       if (ret)
+               return ret;
+
        regmap_write(priv->regmap, MSR_CLK_REG0, 0);
 
        /* Set measurement duration */
@@ -377,8 +515,10 @@ static int meson_measure_id(struct meson_msr_id *clk_msr_id,
 
        ret = regmap_read_poll_timeout(priv->regmap, MSR_CLK_REG0,
                                       val, !(val & MSR_BUSY), 10, 10000);
-       if (ret)
+       if (ret) {
+               mutex_unlock(&measure_lock);
                return ret;
+       }
 
        /* Disable */
        regmap_update_bits(priv->regmap, MSR_CLK_REG0, MSR_ENABLE, 0);
@@ -386,6 +526,8 @@ static int meson_measure_id(struct meson_msr_id *clk_msr_id,
        /* Get the value in multiple of gate time counts */
        regmap_read(priv->regmap, MSR_CLK_REG2, &val);
 
+       mutex_unlock(&measure_lock);
+
        if (val >= MSR_VAL_MASK)
                return -EINVAL;
 
@@ -533,6 +675,10 @@ static const struct of_device_id meson_msr_match_table[] = {
                .compatible = "amlogic,meson-g12a-clk-measure",
                .data = (void *)clk_msr_g12a,
        },
+       {
+               .compatible = "amlogic,meson-sm1-clk-measure",
+               .data = (void *)clk_msr_sm1,
+       },
        { /* sentinel */ }
 };
 
diff --git a/drivers/soc/amlogic/meson-ee-pwrc.c b/drivers/soc/amlogic/meson-ee-pwrc.c
new file mode 100644 (file)
index 0000000..5823f5b
--- /dev/null
@@ -0,0 +1,492 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2019 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ */
+
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/bitfield.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_device.h>
+#include <linux/reset-controller.h>
+#include <linux/reset.h>
+#include <linux/clk.h>
+#include <dt-bindings/power/meson-g12a-power.h>
+#include <dt-bindings/power/meson-sm1-power.h>
+
+/* AO Offsets */
+
+#define AO_RTI_GEN_PWR_SLEEP0          (0x3a << 2)
+#define AO_RTI_GEN_PWR_ISO0            (0x3b << 2)
+
+/* HHI Offsets */
+
+#define HHI_MEM_PD_REG0                        (0x40 << 2)
+#define HHI_VPU_MEM_PD_REG0            (0x41 << 2)
+#define HHI_VPU_MEM_PD_REG1            (0x42 << 2)
+#define HHI_VPU_MEM_PD_REG3            (0x43 << 2)
+#define HHI_VPU_MEM_PD_REG4            (0x44 << 2)
+#define HHI_AUDIO_MEM_PD_REG0          (0x45 << 2)
+#define HHI_NANOQ_MEM_PD_REG0          (0x46 << 2)
+#define HHI_NANOQ_MEM_PD_REG1          (0x47 << 2)
+#define HHI_VPU_MEM_PD_REG2            (0x4d << 2)
+
+struct meson_ee_pwrc;
+struct meson_ee_pwrc_domain;
+
+struct meson_ee_pwrc_mem_domain {
+       unsigned int reg;
+       unsigned int mask;
+};
+
+struct meson_ee_pwrc_top_domain {
+       unsigned int sleep_reg;
+       unsigned int sleep_mask;
+       unsigned int iso_reg;
+       unsigned int iso_mask;
+};
+
+struct meson_ee_pwrc_domain_desc {
+       char *name;
+       unsigned int reset_names_count;
+       unsigned int clk_names_count;
+       struct meson_ee_pwrc_top_domain *top_pd;
+       unsigned int mem_pd_count;
+       struct meson_ee_pwrc_mem_domain *mem_pd;
+       bool (*get_power)(struct meson_ee_pwrc_domain *pwrc_domain);
+};
+
+struct meson_ee_pwrc_domain_data {
+       unsigned int count;
+       struct meson_ee_pwrc_domain_desc *domains;
+};
+
+/* TOP Power Domains */
+
+static struct meson_ee_pwrc_top_domain g12a_pwrc_vpu = {
+       .sleep_reg = AO_RTI_GEN_PWR_SLEEP0,
+       .sleep_mask = BIT(8),
+       .iso_reg = AO_RTI_GEN_PWR_SLEEP0,
+       .iso_mask = BIT(9),
+};
+
+#define SM1_EE_PD(__bit)                                       \
+       {                                                       \
+               .sleep_reg = AO_RTI_GEN_PWR_SLEEP0,             \
+               .sleep_mask = BIT(__bit),                       \
+               .iso_reg = AO_RTI_GEN_PWR_ISO0,                 \
+               .iso_mask = BIT(__bit),                         \
+       }
+
+static struct meson_ee_pwrc_top_domain sm1_pwrc_vpu = SM1_EE_PD(8);
+static struct meson_ee_pwrc_top_domain sm1_pwrc_nna = SM1_EE_PD(16);
+static struct meson_ee_pwrc_top_domain sm1_pwrc_usb = SM1_EE_PD(17);
+static struct meson_ee_pwrc_top_domain sm1_pwrc_pci = SM1_EE_PD(18);
+static struct meson_ee_pwrc_top_domain sm1_pwrc_ge2d = SM1_EE_PD(19);
+
+/* Memory PD Domains */
+
+#define VPU_MEMPD(__reg)                                       \
+       { __reg, GENMASK(1, 0) },                               \
+       { __reg, GENMASK(3, 2) },                               \
+       { __reg, GENMASK(5, 4) },                               \
+       { __reg, GENMASK(7, 6) },                               \
+       { __reg, GENMASK(9, 8) },                               \
+       { __reg, GENMASK(11, 10) },                             \
+       { __reg, GENMASK(13, 12) },                             \
+       { __reg, GENMASK(15, 14) },                             \
+       { __reg, GENMASK(17, 16) },                             \
+       { __reg, GENMASK(19, 18) },                             \
+       { __reg, GENMASK(21, 20) },                             \
+       { __reg, GENMASK(23, 22) },                             \
+       { __reg, GENMASK(25, 24) },                             \
+       { __reg, GENMASK(27, 26) },                             \
+       { __reg, GENMASK(29, 28) },                             \
+       { __reg, GENMASK(31, 30) }
+
+#define VPU_HHI_MEMPD(__reg)                                   \
+       { __reg, BIT(8) },                                      \
+       { __reg, BIT(9) },                                      \
+       { __reg, BIT(10) },                                     \
+       { __reg, BIT(11) },                                     \
+       { __reg, BIT(12) },                                     \
+       { __reg, BIT(13) },                                     \
+       { __reg, BIT(14) },                                     \
+       { __reg, BIT(15) }
+
+static struct meson_ee_pwrc_mem_domain g12a_pwrc_mem_vpu[] = {
+       VPU_MEMPD(HHI_VPU_MEM_PD_REG0),
+       VPU_MEMPD(HHI_VPU_MEM_PD_REG1),
+       VPU_MEMPD(HHI_VPU_MEM_PD_REG2),
+       VPU_HHI_MEMPD(HHI_MEM_PD_REG0),
+};
+
+static struct meson_ee_pwrc_mem_domain g12a_pwrc_mem_eth[] = {
+       { HHI_MEM_PD_REG0, GENMASK(3, 2) },
+};
+
+static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_vpu[] = {
+       VPU_MEMPD(HHI_VPU_MEM_PD_REG0),
+       VPU_MEMPD(HHI_VPU_MEM_PD_REG1),
+       VPU_MEMPD(HHI_VPU_MEM_PD_REG2),
+       VPU_MEMPD(HHI_VPU_MEM_PD_REG3),
+       { HHI_VPU_MEM_PD_REG4, GENMASK(1, 0) },
+       { HHI_VPU_MEM_PD_REG4, GENMASK(3, 2) },
+       { HHI_VPU_MEM_PD_REG4, GENMASK(5, 4) },
+       { HHI_VPU_MEM_PD_REG4, GENMASK(7, 6) },
+       VPU_HHI_MEMPD(HHI_MEM_PD_REG0),
+};
+
+static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_nna[] = {
+       { HHI_NANOQ_MEM_PD_REG0, 0xff },
+       { HHI_NANOQ_MEM_PD_REG1, 0xff },
+};
+
+static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_usb[] = {
+       { HHI_MEM_PD_REG0, GENMASK(31, 30) },
+};
+
+static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_pcie[] = {
+       { HHI_MEM_PD_REG0, GENMASK(29, 26) },
+};
+
+static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_ge2d[] = {
+       { HHI_MEM_PD_REG0, GENMASK(25, 18) },
+};
+
+static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_audio[] = {
+       { HHI_MEM_PD_REG0, GENMASK(5, 4) },
+       { HHI_AUDIO_MEM_PD_REG0, GENMASK(1, 0) },
+       { HHI_AUDIO_MEM_PD_REG0, GENMASK(3, 2) },
+       { HHI_AUDIO_MEM_PD_REG0, GENMASK(5, 4) },
+       { HHI_AUDIO_MEM_PD_REG0, GENMASK(7, 6) },
+       { HHI_AUDIO_MEM_PD_REG0, GENMASK(13, 12) },
+       { HHI_AUDIO_MEM_PD_REG0, GENMASK(15, 14) },
+       { HHI_AUDIO_MEM_PD_REG0, GENMASK(17, 16) },
+       { HHI_AUDIO_MEM_PD_REG0, GENMASK(19, 18) },
+       { HHI_AUDIO_MEM_PD_REG0, GENMASK(21, 20) },
+       { HHI_AUDIO_MEM_PD_REG0, GENMASK(23, 22) },
+       { HHI_AUDIO_MEM_PD_REG0, GENMASK(25, 24) },
+       { HHI_AUDIO_MEM_PD_REG0, GENMASK(27, 26) },
+};
+
+#define VPU_PD(__name, __top_pd, __mem, __get_power, __resets, __clks) \
+       {                                                               \
+               .name = __name,                                         \
+               .reset_names_count = __resets,                          \
+               .clk_names_count = __clks,                              \
+               .top_pd = __top_pd,                                     \
+               .mem_pd_count = ARRAY_SIZE(__mem),                      \
+               .mem_pd = __mem,                                        \
+               .get_power = __get_power,                               \
+       }
+
+#define TOP_PD(__name, __top_pd, __mem, __get_power)                   \
+       {                                                               \
+               .name = __name,                                         \
+               .top_pd = __top_pd,                                     \
+               .mem_pd_count = ARRAY_SIZE(__mem),                      \
+               .mem_pd = __mem,                                        \
+               .get_power = __get_power,                               \
+       }
+
+#define MEM_PD(__name, __mem)                                          \
+       TOP_PD(__name, NULL, __mem, NULL)
+
+static bool pwrc_ee_get_power(struct meson_ee_pwrc_domain *pwrc_domain);
+
+static struct meson_ee_pwrc_domain_desc g12a_pwrc_domains[] = {
+       [PWRC_G12A_VPU_ID]  = VPU_PD("VPU", &g12a_pwrc_vpu, g12a_pwrc_mem_vpu,
+                                    pwrc_ee_get_power, 11, 2),
+       [PWRC_G12A_ETH_ID] = MEM_PD("ETH", g12a_pwrc_mem_eth),
+};
+
+static struct meson_ee_pwrc_domain_desc sm1_pwrc_domains[] = {
+       [PWRC_SM1_VPU_ID]  = VPU_PD("VPU", &sm1_pwrc_vpu, sm1_pwrc_mem_vpu,
+                                   pwrc_ee_get_power, 11, 2),
+       [PWRC_SM1_NNA_ID]  = TOP_PD("NNA", &sm1_pwrc_nna, sm1_pwrc_mem_nna,
+                                   pwrc_ee_get_power),
+       [PWRC_SM1_USB_ID]  = TOP_PD("USB", &sm1_pwrc_usb, sm1_pwrc_mem_usb,
+                                   pwrc_ee_get_power),
+       [PWRC_SM1_PCIE_ID] = TOP_PD("PCI", &sm1_pwrc_pci, sm1_pwrc_mem_pcie,
+                                   pwrc_ee_get_power),
+       [PWRC_SM1_GE2D_ID] = TOP_PD("GE2D", &sm1_pwrc_ge2d, sm1_pwrc_mem_ge2d,
+                                   pwrc_ee_get_power),
+       [PWRC_SM1_AUDIO_ID] = MEM_PD("AUDIO", sm1_pwrc_mem_audio),
+       [PWRC_SM1_ETH_ID] = MEM_PD("ETH", g12a_pwrc_mem_eth),
+};
+
+struct meson_ee_pwrc_domain {
+       struct generic_pm_domain base;
+       bool enabled;
+       struct meson_ee_pwrc *pwrc;
+       struct meson_ee_pwrc_domain_desc desc;
+       struct clk_bulk_data *clks;
+       int num_clks;
+       struct reset_control *rstc;
+       int num_rstc;
+};
+
+struct meson_ee_pwrc {
+       struct regmap *regmap_ao;
+       struct regmap *regmap_hhi;
+       struct meson_ee_pwrc_domain *domains;
+       struct genpd_onecell_data xlate;
+};
+
+static bool pwrc_ee_get_power(struct meson_ee_pwrc_domain *pwrc_domain)
+{
+       u32 reg;
+
+       regmap_read(pwrc_domain->pwrc->regmap_ao,
+                   pwrc_domain->desc.top_pd->sleep_reg, &reg);
+
+       return (reg & pwrc_domain->desc.top_pd->sleep_mask);
+}
+
+static int meson_ee_pwrc_off(struct generic_pm_domain *domain)
+{
+       struct meson_ee_pwrc_domain *pwrc_domain =
+               container_of(domain, struct meson_ee_pwrc_domain, base);
+       int i;
+
+       if (pwrc_domain->desc.top_pd)
+               regmap_update_bits(pwrc_domain->pwrc->regmap_ao,
+                                  pwrc_domain->desc.top_pd->sleep_reg,
+                                  pwrc_domain->desc.top_pd->sleep_mask,
+                                  pwrc_domain->desc.top_pd->sleep_mask);
+       udelay(20);
+
+       for (i = 0 ; i < pwrc_domain->desc.mem_pd_count ; ++i)
+               regmap_update_bits(pwrc_domain->pwrc->regmap_hhi,
+                                  pwrc_domain->desc.mem_pd[i].reg,
+                                  pwrc_domain->desc.mem_pd[i].mask,
+                                  pwrc_domain->desc.mem_pd[i].mask);
+
+       udelay(20);
+
+       if (pwrc_domain->desc.top_pd)
+               regmap_update_bits(pwrc_domain->pwrc->regmap_ao,
+                                  pwrc_domain->desc.top_pd->iso_reg,
+                                  pwrc_domain->desc.top_pd->iso_mask,
+                                  pwrc_domain->desc.top_pd->iso_mask);
+
+       if (pwrc_domain->num_clks) {
+               msleep(20);
+               clk_bulk_disable_unprepare(pwrc_domain->num_clks,
+                                          pwrc_domain->clks);
+       }
+
+       return 0;
+}
+
+static int meson_ee_pwrc_on(struct generic_pm_domain *domain)
+{
+       struct meson_ee_pwrc_domain *pwrc_domain =
+               container_of(domain, struct meson_ee_pwrc_domain, base);
+       int i, ret;
+
+       if (pwrc_domain->desc.top_pd)
+               regmap_update_bits(pwrc_domain->pwrc->regmap_ao,
+                                  pwrc_domain->desc.top_pd->sleep_reg,
+                                  pwrc_domain->desc.top_pd->sleep_mask, 0);
+       udelay(20);
+
+       for (i = 0 ; i < pwrc_domain->desc.mem_pd_count ; ++i)
+               regmap_update_bits(pwrc_domain->pwrc->regmap_hhi,
+                                  pwrc_domain->desc.mem_pd[i].reg,
+                                  pwrc_domain->desc.mem_pd[i].mask, 0);
+
+       udelay(20);
+
+       ret = reset_control_assert(pwrc_domain->rstc);
+       if (ret)
+               return ret;
+
+       if (pwrc_domain->desc.top_pd)
+               regmap_update_bits(pwrc_domain->pwrc->regmap_ao,
+                                  pwrc_domain->desc.top_pd->iso_reg,
+                                  pwrc_domain->desc.top_pd->iso_mask, 0);
+
+       ret = reset_control_deassert(pwrc_domain->rstc);
+       if (ret)
+               return ret;
+
+       return clk_bulk_prepare_enable(pwrc_domain->num_clks,
+                                      pwrc_domain->clks);
+}
+
+static int meson_ee_pwrc_init_domain(struct platform_device *pdev,
+                                    struct meson_ee_pwrc *pwrc,
+                                    struct meson_ee_pwrc_domain *dom)
+{
+       dom->pwrc = pwrc;
+       dom->num_rstc = dom->desc.reset_names_count;
+       dom->num_clks = dom->desc.clk_names_count;
+
+       if (dom->num_rstc) {
+               int count = reset_control_get_count(&pdev->dev);
+
+               if (count != dom->num_rstc)
+                       dev_warn(&pdev->dev, "Invalid resets count %d for domain %s\n",
+                                count, dom->desc.name);
+
+               dom->rstc = devm_reset_control_array_get(&pdev->dev, false,
+                                                        false);
+               if (IS_ERR(dom->rstc))
+                       return PTR_ERR(dom->rstc);
+       }
+
+       if (dom->num_clks) {
+               int ret = devm_clk_bulk_get_all(&pdev->dev, &dom->clks);
+               if (ret < 0)
+                       return ret;
+
+               if (dom->num_clks != ret) {
+                       dev_warn(&pdev->dev, "Invalid clocks count %d for domain %s\n",
+                                ret, dom->desc.name);
+                       dom->num_clks = ret;
+               }
+       }
+
+       dom->base.name = dom->desc.name;
+       dom->base.power_on = meson_ee_pwrc_on;
+       dom->base.power_off = meson_ee_pwrc_off;
+
+       /*
+         * TOFIX: This is a special case for the VPU power domain, which can
+        * be enabled previously by the bootloader. In this case the VPU
+         * pipeline may be functional but no driver maybe never attach
+         * to this power domain, and if the domain is disabled it could
+         * cause system errors. This is why the pm_domain_always_on_gov
+         * is used here.
+         * For the same reason, the clocks should be enabled in case
+         * we need to power the domain off, otherwise the internal clocks
+         * prepare/enable counters won't be in sync.
+         */
+       if (dom->num_clks && dom->desc.get_power && !dom->desc.get_power(dom)) {
+               int ret = clk_bulk_prepare_enable(dom->num_clks, dom->clks);
+               if (ret)
+                       return ret;
+
+               pm_genpd_init(&dom->base, &pm_domain_always_on_gov, false);
+       } else
+               pm_genpd_init(&dom->base, NULL,
+                             (dom->desc.get_power ?
+                              dom->desc.get_power(dom) : true));
+
+       return 0;
+}
+
+static int meson_ee_pwrc_probe(struct platform_device *pdev)
+{
+       const struct meson_ee_pwrc_domain_data *match;
+       struct regmap *regmap_ao, *regmap_hhi;
+       struct meson_ee_pwrc *pwrc;
+       int i, ret;
+
+       match = of_device_get_match_data(&pdev->dev);
+       if (!match) {
+               dev_err(&pdev->dev, "failed to get match data\n");
+               return -ENODEV;
+       }
+
+       pwrc = devm_kzalloc(&pdev->dev, sizeof(*pwrc), GFP_KERNEL);
+       if (!pwrc)
+               return -ENOMEM;
+
+       pwrc->xlate.domains = devm_kcalloc(&pdev->dev, match->count,
+                                          sizeof(*pwrc->xlate.domains),
+                                          GFP_KERNEL);
+       if (!pwrc->xlate.domains)
+               return -ENOMEM;
+
+       pwrc->domains = devm_kcalloc(&pdev->dev, match->count,
+                                    sizeof(*pwrc->domains), GFP_KERNEL);
+       if (!pwrc->domains)
+               return -ENOMEM;
+
+       pwrc->xlate.num_domains = match->count;
+
+       regmap_hhi = syscon_node_to_regmap(of_get_parent(pdev->dev.of_node));
+       if (IS_ERR(regmap_hhi)) {
+               dev_err(&pdev->dev, "failed to get HHI regmap\n");
+               return PTR_ERR(regmap_hhi);
+       }
+
+       regmap_ao = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+                                                   "amlogic,ao-sysctrl");
+       if (IS_ERR(regmap_ao)) {
+               dev_err(&pdev->dev, "failed to get AO regmap\n");
+               return PTR_ERR(regmap_ao);
+       }
+
+       pwrc->regmap_ao = regmap_ao;
+       pwrc->regmap_hhi = regmap_hhi;
+
+       platform_set_drvdata(pdev, pwrc);
+
+       for (i = 0 ; i < match->count ; ++i) {
+               struct meson_ee_pwrc_domain *dom = &pwrc->domains[i];
+
+               memcpy(&dom->desc, &match->domains[i], sizeof(dom->desc));
+
+               ret = meson_ee_pwrc_init_domain(pdev, pwrc, dom);
+               if (ret)
+                       return ret;
+
+               pwrc->xlate.domains[i] = &dom->base;
+       }
+
+       of_genpd_add_provider_onecell(pdev->dev.of_node, &pwrc->xlate);
+
+       return 0;
+}
+
+static void meson_ee_pwrc_shutdown(struct platform_device *pdev)
+{
+       struct meson_ee_pwrc *pwrc = platform_get_drvdata(pdev);
+       int i;
+
+       for (i = 0 ; i < pwrc->xlate.num_domains ; ++i) {
+               struct meson_ee_pwrc_domain *dom = &pwrc->domains[i];
+
+               if (dom->desc.get_power && !dom->desc.get_power(dom))
+                       meson_ee_pwrc_off(&dom->base);
+       }
+}
+
+static struct meson_ee_pwrc_domain_data meson_ee_g12a_pwrc_data = {
+       .count = ARRAY_SIZE(g12a_pwrc_domains),
+       .domains = g12a_pwrc_domains,
+};
+
+static struct meson_ee_pwrc_domain_data meson_ee_sm1_pwrc_data = {
+       .count = ARRAY_SIZE(sm1_pwrc_domains),
+       .domains = sm1_pwrc_domains,
+};
+
+static const struct of_device_id meson_ee_pwrc_match_table[] = {
+       {
+               .compatible = "amlogic,meson-g12a-pwrc",
+               .data = &meson_ee_g12a_pwrc_data,
+       },
+       {
+               .compatible = "amlogic,meson-sm1-pwrc",
+               .data = &meson_ee_sm1_pwrc_data,
+       },
+       { /* sentinel */ }
+};
+
+static struct platform_driver meson_ee_pwrc_driver = {
+       .probe = meson_ee_pwrc_probe,
+       .shutdown = meson_ee_pwrc_shutdown,
+       .driver = {
+               .name           = "meson_ee_pwrc",
+               .of_match_table = meson_ee_pwrc_match_table,
+       },
+};
+builtin_platform_driver(meson_ee_pwrc_driver);
index bca3495..6d0d04f 100644 (file)
@@ -39,6 +39,7 @@ static const struct meson_gx_soc_id {
        { "TXHD", 0x27 },
        { "G12A", 0x28 },
        { "G12B", 0x29 },
+       { "SM1", 0x2b },
 };
 
 static const struct meson_gx_package_id {
@@ -65,6 +66,8 @@ static const struct meson_gx_package_id {
        { "S905D2", 0x28, 0x10, 0xf0 },
        { "S905X2", 0x28, 0x40, 0xf0 },
        { "S922X", 0x29, 0x40, 0xf0 },
+       { "A311D", 0x29, 0x10, 0xf0 },
+       { "S905X3", 0x2b, 0x5, 0xf },
 };
 
 static inline unsigned int socinfo_to_major(u32 socinfo)
@@ -138,8 +141,10 @@ static int __init meson_gx_socinfo_init(void)
        }
 
        /* check if chip-id is available */
-       if (!of_property_read_bool(np, "amlogic,has-chip-id"))
+       if (!of_property_read_bool(np, "amlogic,has-chip-id")) {
+               of_node_put(np);
                return -ENODEV;
+       }
 
        /* node should be a syscon */
        regmap = syscon_node_to_regmap(np);
index 9168d8d..27243f7 100644 (file)
@@ -73,7 +73,7 @@ static u64 get_mc_fw_base_address(void)
 
        mcfbaregs = ioremap(mc_base_addr.start, resource_size(&mc_base_addr));
        if (!mcfbaregs) {
-               pr_err("could not map MC Firmaware Base registers\n");
+               pr_err("could not map MC Firmware Base registers\n");
                return 0;
        }
 
index b9539ef..518a8e0 100644 (file)
@@ -305,8 +305,6 @@ void dpaa2_io_service_deregister(struct dpaa2_io *service,
        list_del(&ctx->node);
        spin_unlock_irqrestore(&d->lock_notifications, irqflags);
 
-       if (dev)
-               device_link_remove(dev, d->dev);
 }
 EXPORT_SYMBOL_GPL(dpaa2_io_service_deregister);
 
index 1ef8068..34810f9 100644 (file)
@@ -102,6 +102,11 @@ static const struct fsl_soc_die_attr fsl_soc_die[] = {
          .svr          = 0x87360000,
          .mask         = 0xff3f0000,
        },
+       /* Die: LS1028A, SoC: LS1028A */
+       { .die          = "LS1028A",
+         .svr          = 0x870b0000,
+         .mask         = 0xff3f0000,
+       },
        { },
 };
 
@@ -224,6 +229,7 @@ static const struct of_device_id fsl_guts_of_match[] = {
        { .compatible = "fsl,ls1012a-dcfg", },
        { .compatible = "fsl,ls1046a-dcfg", },
        { .compatible = "fsl,lx2160a-dcfg", },
+       { .compatible = "fsl,ls1028a-dcfg", },
        {}
 };
 MODULE_DEVICE_TABLE(of, fsl_guts_of_match);
index f84ab59..f4fb527 100644 (file)
@@ -635,30 +635,31 @@ int bman_p_irqsource_add(struct bman_portal *p, u32 bits)
        return 0;
 }
 
-static int bm_shutdown_pool(u32 bpid)
+int bm_shutdown_pool(u32 bpid)
 {
+       int err = 0;
        struct bm_mc_command *bm_cmd;
        union bm_mc_result *bm_res;
 
+
+       struct bman_portal *p = get_affine_portal();
        while (1) {
-               struct bman_portal *p = get_affine_portal();
                /* Acquire buffers until empty */
                bm_cmd = bm_mc_start(&p->p);
                bm_cmd->bpid = bpid;
                bm_mc_commit(&p->p, BM_MCC_VERB_CMD_ACQUIRE | 1);
                if (!bm_mc_result_timeout(&p->p, &bm_res)) {
-                       put_affine_portal();
                        pr_crit("BMan Acquire Command timedout\n");
-                       return -ETIMEDOUT;
+                       err = -ETIMEDOUT;
+                       goto done;
                }
                if (!(bm_res->verb & BM_MCR_VERB_ACQUIRE_BUFCOUNT)) {
-                       put_affine_portal();
                        /* Pool is empty */
-                       return 0;
+                       goto done;
                }
-               put_affine_portal();
        }
-
+done:
+       put_affine_portal();
        return 0;
 }
 
index 7c3cc96..cb24a08 100644 (file)
@@ -97,17 +97,40 @@ static void bm_get_version(u16 *id, u8 *major, u8 *minor)
 /* signal transactions for FBPRs with higher priority */
 #define FBPR_AR_RPRIO_HI BIT(30)
 
-static void bm_set_memory(u64 ba, u32 size)
+/* Track if probe has occurred and if cleanup is required */
+static int __bman_probed;
+static int __bman_requires_cleanup;
+
+
+static int bm_set_memory(u64 ba, u32 size)
 {
+       u32 bar, bare;
        u32 exp = ilog2(size);
        /* choke if size isn't within range */
        DPAA_ASSERT(size >= 4096 && size <= 1024*1024*1024 &&
                   is_power_of_2(size));
        /* choke if '[e]ba' has lower-alignment than 'size' */
        DPAA_ASSERT(!(ba & (size - 1)));
+
+       /* Check to see if BMan has already been initialized */
+       bar = bm_ccsr_in(REG_FBPR_BAR);
+       if (bar) {
+               /* Maker sure ba == what was programmed) */
+               bare = bm_ccsr_in(REG_FBPR_BARE);
+               if (bare != upper_32_bits(ba) || bar != lower_32_bits(ba)) {
+                       pr_err("Attempted to reinitialize BMan with different BAR, got 0x%llx read BARE=0x%x BAR=0x%x\n",
+                              ba, bare, bar);
+                       return -ENOMEM;
+               }
+               pr_info("BMan BAR already configured\n");
+               __bman_requires_cleanup = 1;
+               return 1;
+       }
+
        bm_ccsr_out(REG_FBPR_BARE, upper_32_bits(ba));
        bm_ccsr_out(REG_FBPR_BAR, lower_32_bits(ba));
        bm_ccsr_out(REG_FBPR_AR, exp - 1);
+       return 0;
 }
 
 /*
@@ -120,7 +143,6 @@ static void bm_set_memory(u64 ba, u32 size)
  */
 static dma_addr_t fbpr_a;
 static size_t fbpr_sz;
-static int __bman_probed;
 
 static int bman_fbpr(struct reserved_mem *rmem)
 {
@@ -173,6 +195,16 @@ int bman_is_probed(void)
 }
 EXPORT_SYMBOL_GPL(bman_is_probed);
 
+int bman_requires_cleanup(void)
+{
+       return __bman_requires_cleanup;
+}
+
+void bman_done_cleanup(void)
+{
+       __bman_requires_cleanup = 0;
+}
+
 static int fsl_bman_probe(struct platform_device *pdev)
 {
        int ret, err_irq;
index cf4f10d..923c440 100644 (file)
@@ -100,7 +100,7 @@ static int bman_portal_probe(struct platform_device *pdev)
        struct device_node *node = dev->of_node;
        struct bm_portal_config *pcfg;
        struct resource *addr_phys[2];
-       int irq, cpu, err;
+       int irq, cpu, err, i;
 
        err = bman_is_probed();
        if (!err)
@@ -135,10 +135,8 @@ static int bman_portal_probe(struct platform_device *pdev)
        pcfg->cpu = -1;
 
        irq = platform_get_irq(pdev, 0);
-       if (irq <= 0) {
-               dev_err(dev, "Can't get %pOF IRQ'\n", node);
+       if (irq <= 0)
                goto err_ioremap1;
-       }
        pcfg->irq = irq;
 
        pcfg->addr_virt_ce = memremap(addr_phys[0]->start,
@@ -178,6 +176,22 @@ static int bman_portal_probe(struct platform_device *pdev)
        if (!cpu_online(cpu))
                bman_offline_cpu(cpu);
 
+       if (__bman_portals_probed == 1 && bman_requires_cleanup()) {
+               /*
+                * BMan wasn't reset prior to boot (Kexec for example)
+                * Empty all the buffer pools so they are in reset state
+                */
+               for (i = 0; i < BM_POOL_MAX; i++) {
+                       err =  bm_shutdown_pool(i);
+                       if (err) {
+                               dev_err(dev, "Failed to shutdown bpool %d\n",
+                                       i);
+                               goto err_portal_init;
+                       }
+               }
+               bman_done_cleanup();
+       }
+
        return 0;
 
 err_portal_init:
index 751ce90..aa3981e 100644 (file)
@@ -76,3 +76,8 @@ int bman_p_irqsource_add(struct bman_portal *p, u32 bits);
 
 const struct bm_portal_config *
 bman_get_bm_portal_config(const struct bman_portal *portal);
+
+int bman_requires_cleanup(void);
+void bman_done_cleanup(void);
+
+int bm_shutdown_pool(u32 bpid);
index e6d48dc..9dd8bb5 100644 (file)
 int qbman_init_private_mem(struct device *dev, int idx, dma_addr_t *addr,
                                size_t *size)
 {
-       int ret;
        struct device_node *mem_node;
-       u64 size64;
+       struct reserved_mem *rmem;
+       struct property *prop;
+       int len, err;
+       __be32 *res_array;
 
-       ret = of_reserved_mem_device_init_by_idx(dev, dev->of_node, idx);
-       if (ret) {
-               dev_err(dev,
-                       "of_reserved_mem_device_init_by_idx(%d) failed 0x%x\n",
-                       idx, ret);
-               return -ENODEV;
-       }
-       mem_node = of_parse_phandle(dev->of_node, "memory-region", 0);
-       if (mem_node) {
-               ret = of_property_read_u64(mem_node, "size", &size64);
-               if (ret) {
-                       dev_err(dev, "of_address_to_resource fails 0x%x\n",
-                               ret);
-                       return -ENODEV;
-               }
-               *size = size64;
-       } else {
+       mem_node = of_parse_phandle(dev->of_node, "memory-region", idx);
+       if (!mem_node) {
                dev_err(dev, "No memory-region found for index %d\n", idx);
                return -ENODEV;
        }
 
-       if (!dma_alloc_coherent(dev, *size, addr, 0)) {
-               dev_err(dev, "DMA Alloc memory failed\n");
+       rmem = of_reserved_mem_lookup(mem_node);
+       if (!rmem) {
+               dev_err(dev, "of_reserved_mem_lookup() returned NULL\n");
                return -ENODEV;
        }
+       *addr = rmem->base;
+       *size = rmem->size;
 
        /*
-        * Disassociate the reserved memory area from the device
-        * because a device can only have one DMA memory area. This
-        * should be fine since the memory is allocated and initialized
-        * and only ever accessed by the QBMan device from now on
+        * Check if the reg property exists - if not insert the node
+        * so upon kexec() the same memory region address will be preserved.
+        * This is needed because QBMan HW does not allow the base address/
+        * size to be modified once set.
         */
-       of_reserved_mem_device_release(dev);
+       prop = of_find_property(mem_node, "reg", &len);
+       if (!prop) {
+               prop = devm_kzalloc(dev, sizeof(*prop), GFP_KERNEL);
+               if (!prop)
+                       return -ENOMEM;
+               prop->value = res_array = devm_kzalloc(dev, sizeof(__be32) * 4,
+                                                      GFP_KERNEL);
+               if (!prop->value)
+                       return -ENOMEM;
+               res_array[0] = cpu_to_be32(upper_32_bits(*addr));
+               res_array[1] = cpu_to_be32(lower_32_bits(*addr));
+               res_array[2] = cpu_to_be32(upper_32_bits(*size));
+               res_array[3] = cpu_to_be32(lower_32_bits(*size));
+               prop->length = sizeof(__be32) * 4;
+               prop->name = devm_kstrdup(dev, "reg", GFP_KERNEL);
+               if (!prop->name)
+                       return -ENOMEM;
+               err = of_add_property(mem_node, prop);
+               if (err)
+                       return err;
+       }
+
        return 0;
 }
index 636f83f..bf68d86 100644 (file)
@@ -1018,6 +1018,20 @@ static inline void put_affine_portal(void)
        put_cpu_var(qman_affine_portal);
 }
 
+
+static inline struct qman_portal *get_portal_for_channel(u16 channel)
+{
+       int i;
+
+       for (i = 0; i < num_possible_cpus(); i++) {
+               if (affine_portals[i] &&
+                   affine_portals[i]->config->channel == channel)
+                       return affine_portals[i];
+       }
+
+       return NULL;
+}
+
 static struct workqueue_struct *qm_portal_wq;
 
 int qman_dqrr_set_ithresh(struct qman_portal *portal, u8 ithresh)
@@ -1070,6 +1084,20 @@ int qman_wq_alloc(void)
        return 0;
 }
 
+
+void qman_enable_irqs(void)
+{
+       int i;
+
+       for (i = 0; i < num_possible_cpus(); i++) {
+               if (affine_portals[i]) {
+                       qm_out(&affine_portals[i]->p, QM_REG_ISR, 0xffffffff);
+                       qm_out(&affine_portals[i]->p, QM_REG_IIR, 0);
+               }
+
+       }
+}
+
 /*
  * This is what everything can wait on, even if it migrates to a different cpu
  * to the one whose affine portal it is waiting on.
@@ -1164,6 +1192,7 @@ static int drain_mr_fqrni(struct qm_portal *p)
 {
        const union qm_mr_entry *msg;
 loop:
+       qm_mr_pvb_update(p);
        msg = qm_mr_current(p);
        if (!msg) {
                /*
@@ -1180,7 +1209,8 @@ loop:
                 * entries well before the ring has been fully consumed, so
                 * we're being *really* paranoid here.
                 */
-               msleep(1);
+               mdelay(1);
+               qm_mr_pvb_update(p);
                msg = qm_mr_current(p);
                if (!msg)
                        return 0;
@@ -1267,8 +1297,8 @@ static int qman_create_portal(struct qman_portal *portal,
        qm_out(p, QM_REG_ISDR, isdr);
        portal->irq_sources = 0;
        qm_out(p, QM_REG_IER, 0);
-       qm_out(p, QM_REG_ISR, 0xffffffff);
        snprintf(portal->irqname, MAX_IRQNAME, IRQNAME, c->cpu);
+       qm_out(p, QM_REG_IIR, 1);
        if (request_irq(c->irq, portal_isr, 0, portal->irqname, portal)) {
                dev_err(c->dev, "request_irq() failed\n");
                goto fail_irq;
@@ -1288,7 +1318,7 @@ static int qman_create_portal(struct qman_portal *portal,
        isdr &= ~(QM_PIRQ_DQRI | QM_PIRQ_MRI);
        qm_out(p, QM_REG_ISDR, isdr);
        if (qm_dqrr_current(p)) {
-               dev_err(c->dev, "DQRR unclean\n");
+               dev_dbg(c->dev, "DQRR unclean\n");
                qm_dqrr_cdc_consume_n(p, 0xffff);
        }
        if (qm_mr_current(p) && drain_mr_fqrni(p)) {
@@ -1301,8 +1331,10 @@ static int qman_create_portal(struct qman_portal *portal,
        }
        /* Success */
        portal->config = c;
+       qm_out(p, QM_REG_ISR, 0xffffffff);
        qm_out(p, QM_REG_ISDR, 0);
-       qm_out(p, QM_REG_IIR, 0);
+       if (!qman_requires_cleanup())
+               qm_out(p, QM_REG_IIR, 0);
        /* Write a sane SDQCR */
        qm_dqrr_sdqcr_set(p, portal->sdqcr);
        return 0;
@@ -2581,9 +2613,9 @@ static int _qm_dqrr_consume_and_match(struct qm_portal *p, u32 fqid, int s,
 #define qm_dqrr_drain_nomatch(p) \
        _qm_dqrr_consume_and_match(p, 0, 0, false)
 
-static int qman_shutdown_fq(u32 fqid)
+int qman_shutdown_fq(u32 fqid)
 {
-       struct qman_portal *p;
+       struct qman_portal *p, *channel_portal;
        struct device *dev;
        union qm_mc_command *mcc;
        union qm_mc_result *mcr;
@@ -2623,17 +2655,28 @@ static int qman_shutdown_fq(u32 fqid)
        channel = qm_fqd_get_chan(&mcr->queryfq.fqd);
        wq = qm_fqd_get_wq(&mcr->queryfq.fqd);
 
+       if (channel < qm_channel_pool1) {
+               channel_portal = get_portal_for_channel(channel);
+               if (channel_portal == NULL) {
+                       dev_err(dev, "Can't find portal for dedicated channel 0x%x\n",
+                               channel);
+                       ret = -EIO;
+                       goto out;
+               }
+       } else
+               channel_portal = p;
+
        switch (state) {
        case QM_MCR_NP_STATE_TEN_SCHED:
        case QM_MCR_NP_STATE_TRU_SCHED:
        case QM_MCR_NP_STATE_ACTIVE:
        case QM_MCR_NP_STATE_PARKED:
                orl_empty = 0;
-               mcc = qm_mc_start(&p->p);
+               mcc = qm_mc_start(&channel_portal->p);
                qm_fqid_set(&mcc->fq, fqid);
-               qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_RETIRE);
-               if (!qm_mc_result_timeout(&p->p, &mcr)) {
-                       dev_err(dev, "QUERYFQ_NP timeout\n");
+               qm_mc_commit(&channel_portal->p, QM_MCC_VERB_ALTER_RETIRE);
+               if (!qm_mc_result_timeout(&channel_portal->p, &mcr)) {
+                       dev_err(dev, "ALTER_RETIRE timeout\n");
                        ret = -ETIMEDOUT;
                        goto out;
                }
@@ -2641,6 +2684,9 @@ static int qman_shutdown_fq(u32 fqid)
                            QM_MCR_VERB_ALTER_RETIRE);
                res = mcr->result; /* Make a copy as we reuse MCR below */
 
+               if (res == QM_MCR_RESULT_OK)
+                       drain_mr_fqrni(&channel_portal->p);
+
                if (res == QM_MCR_RESULT_PENDING) {
                        /*
                         * Need to wait for the FQRN in the message ring, which
@@ -2670,21 +2716,25 @@ static int qman_shutdown_fq(u32 fqid)
                        }
                        /* Set the sdqcr to drain this channel */
                        if (channel < qm_channel_pool1)
-                               qm_dqrr_sdqcr_set(&p->p,
+                               qm_dqrr_sdqcr_set(&channel_portal->p,
                                                  QM_SDQCR_TYPE_ACTIVE |
                                                  QM_SDQCR_CHANNELS_DEDICATED);
                        else
-                               qm_dqrr_sdqcr_set(&p->p,
+                               qm_dqrr_sdqcr_set(&channel_portal->p,
                                                  QM_SDQCR_TYPE_ACTIVE |
                                                  QM_SDQCR_CHANNELS_POOL_CONV
                                                  (channel));
                        do {
                                /* Keep draining DQRR while checking the MR*/
-                               qm_dqrr_drain_nomatch(&p->p);
+                               qm_dqrr_drain_nomatch(&channel_portal->p);
                                /* Process message ring too */
-                               found_fqrn = qm_mr_drain(&p->p, FQRN);
+                               found_fqrn = qm_mr_drain(&channel_portal->p,
+                                                        FQRN);
                                cpu_relax();
                        } while (!found_fqrn);
+                       /* Restore SDQCR */
+                       qm_dqrr_sdqcr_set(&channel_portal->p,
+                                         channel_portal->sdqcr);
 
                }
                if (res != QM_MCR_RESULT_OK &&
@@ -2715,9 +2765,8 @@ static int qman_shutdown_fq(u32 fqid)
                                 * Wait for a dequeue and process the dequeues,
                                 * making sure to empty the ring completely
                                 */
-                       } while (qm_dqrr_drain_wait(&p->p, fqid, FQ_EMPTY));
+                       } while (!qm_dqrr_drain_wait(&p->p, fqid, FQ_EMPTY));
                }
-               qm_dqrr_sdqcr_set(&p->p, 0);
 
                while (!orl_empty) {
                        /* Wait for the ORL to have been completely drained */
@@ -2754,7 +2803,7 @@ static int qman_shutdown_fq(u32 fqid)
 
                DPAA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) ==
                            QM_MCR_VERB_ALTER_OOS);
-               if (mcr->result) {
+               if (mcr->result != QM_MCR_RESULT_OK) {
                        dev_err(dev, "OOS fail: FQ 0x%x (0x%x)\n",
                                fqid, mcr->result);
                        ret = -EIO;
index a6bb430..157659f 100644 (file)
@@ -274,6 +274,7 @@ static u32 __iomem *qm_ccsr_start;
 /* A SDQCR mask comprising all the available/visible pool channels */
 static u32 qm_pools_sdqcr;
 static int __qman_probed;
+static int  __qman_requires_cleanup;
 
 static inline u32 qm_ccsr_in(u32 offset)
 {
@@ -340,19 +341,55 @@ static void qm_get_version(u16 *id, u8 *major, u8 *minor)
 }
 
 #define PFDR_AR_EN             BIT(31)
-static void qm_set_memory(enum qm_memory memory, u64 ba, u32 size)
+static int qm_set_memory(enum qm_memory memory, u64 ba, u32 size)
 {
+       void *ptr;
        u32 offset = (memory == qm_memory_fqd) ? REG_FQD_BARE : REG_PFDR_BARE;
        u32 exp = ilog2(size);
+       u32 bar, bare;
 
        /* choke if size isn't within range */
        DPAA_ASSERT((size >= 4096) && (size <= 1024*1024*1024) &&
                    is_power_of_2(size));
        /* choke if 'ba' has lower-alignment than 'size' */
        DPAA_ASSERT(!(ba & (size - 1)));
+
+       /* Check to see if QMan has already been initialized */
+       bar = qm_ccsr_in(offset + REG_offset_BAR);
+       if (bar) {
+               /* Maker sure ba == what was programmed) */
+               bare = qm_ccsr_in(offset);
+               if (bare != upper_32_bits(ba) || bar != lower_32_bits(ba)) {
+                       pr_err("Attempted to reinitialize QMan with different BAR, got 0x%llx read BARE=0x%x BAR=0x%x\n",
+                              ba, bare, bar);
+                       return -ENOMEM;
+               }
+               __qman_requires_cleanup = 1;
+               /* Return 1 to indicate memory was previously programmed */
+               return 1;
+       }
+       /* Need to temporarily map the area to make sure it is zeroed */
+       ptr = memremap(ba, size, MEMREMAP_WB);
+       if (!ptr) {
+               pr_crit("memremap() of QMan private memory failed\n");
+               return -ENOMEM;
+       }
+       memset(ptr, 0, size);
+
+#ifdef CONFIG_PPC
+       /*
+        * PPC doesn't appear to flush the cache on memunmap() but the
+        * cache must be flushed since QMan does non coherent accesses
+        * to this memory
+        */
+       flush_dcache_range((unsigned long) ptr, (unsigned long) ptr+size);
+#endif
+       memunmap(ptr);
+
        qm_ccsr_out(offset, upper_32_bits(ba));
        qm_ccsr_out(offset + REG_offset_BAR, lower_32_bits(ba));
        qm_ccsr_out(offset + REG_offset_AR, PFDR_AR_EN | (exp - 1));
+       return 0;
 }
 
 static void qm_set_pfdr_threshold(u32 th, u8 k)
@@ -455,7 +492,7 @@ RESERVEDMEM_OF_DECLARE(qman_pfdr, "fsl,qman-pfdr", qman_pfdr);
 
 #endif
 
-static unsigned int qm_get_fqid_maxcnt(void)
+unsigned int qm_get_fqid_maxcnt(void)
 {
        return fqd_sz / 64;
 }
@@ -571,12 +608,19 @@ static int qman_init_ccsr(struct device *dev)
        int i, err;
 
        /* FQD memory */
-       qm_set_memory(qm_memory_fqd, fqd_a, fqd_sz);
+       err = qm_set_memory(qm_memory_fqd, fqd_a, fqd_sz);
+       if (err < 0)
+               return err;
        /* PFDR memory */
-       qm_set_memory(qm_memory_pfdr, pfdr_a, pfdr_sz);
-       err = qm_init_pfdr(dev, 8, pfdr_sz / 64 - 8);
-       if (err)
+       err = qm_set_memory(qm_memory_pfdr, pfdr_a, pfdr_sz);
+       if (err < 0)
                return err;
+       /* Only initialize PFDRs if the QMan was not initialized before */
+       if (err == 0) {
+               err = qm_init_pfdr(dev, 8, pfdr_sz / 64 - 8);
+               if (err)
+                       return err;
+       }
        /* thresholds */
        qm_set_pfdr_threshold(512, 64);
        qm_set_sfdr_threshold(128);
@@ -693,6 +737,18 @@ int qman_is_probed(void)
 }
 EXPORT_SYMBOL_GPL(qman_is_probed);
 
+int qman_requires_cleanup(void)
+{
+       return __qman_requires_cleanup;
+}
+
+void qman_done_cleanup(void)
+{
+       qman_enable_irqs();
+       __qman_requires_cleanup = 0;
+}
+
+
 static int fsl_qman_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
index e2186b6..5685b67 100644 (file)
@@ -233,7 +233,7 @@ static int qman_portal_probe(struct platform_device *pdev)
        struct device_node *node = dev->of_node;
        struct qm_portal_config *pcfg;
        struct resource *addr_phys[2];
-       int irq, cpu, err;
+       int irq, cpu, err, i;
        u32 val;
 
        err = qman_is_probed();
@@ -275,10 +275,8 @@ static int qman_portal_probe(struct platform_device *pdev)
        pcfg->channel = val;
        pcfg->cpu = -1;
        irq = platform_get_irq(pdev, 0);
-       if (irq <= 0) {
-               dev_err(dev, "Can't get %pOF IRQ\n", node);
+       if (irq <= 0)
                goto err_ioremap1;
-       }
        pcfg->irq = irq;
 
        pcfg->addr_virt_ce = memremap(addr_phys[0]->start,
@@ -325,6 +323,22 @@ static int qman_portal_probe(struct platform_device *pdev)
        if (!cpu_online(cpu))
                qman_offline_cpu(cpu);
 
+       if (__qman_portals_probed == 1 && qman_requires_cleanup()) {
+               /*
+                * QMan wasn't reset prior to boot (Kexec for example)
+                * Empty all the frame queues so they are in reset state
+                */
+               for (i = 0; i < qm_get_fqid_maxcnt(); i++) {
+                       err =  qman_shutdown_fq(i);
+                       if (err) {
+                               dev_err(dev, "Failed to shutdown frame queue %d\n",
+                                       i);
+                               goto err_portal_init;
+                       }
+               }
+               qman_done_cleanup();
+       }
+
        return 0;
 
 err_portal_init:
index 0451571..fd1cf54 100644 (file)
@@ -272,3 +272,11 @@ extern struct qman_portal *affine_portals[NR_CPUS];
 extern struct qman_portal *qman_dma_portal;
 const struct qm_portal_config *qman_get_qm_portal_config(
                                                struct qman_portal *portal);
+
+unsigned int qm_get_fqid_maxcnt(void);
+
+int qman_shutdown_fq(u32 fqid);
+
+int qman_requires_cleanup(void);
+void qman_done_cleanup(void);
+void qman_enable_irqs(void);
index c9519e6..417df7e 100644 (file)
@@ -10,6 +10,7 @@
  * General Purpose functions for the global management of the
  * QUICC Engine (QE).
  */
+#include <linux/bitmap.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -39,29 +40,32 @@ static DEFINE_SPINLOCK(qe_lock);
 DEFINE_SPINLOCK(cmxgcr_lock);
 EXPORT_SYMBOL(cmxgcr_lock);
 
-/* QE snum state */
-enum qe_snum_state {
-       QE_SNUM_STATE_USED,
-       QE_SNUM_STATE_FREE
-};
-
-/* QE snum */
-struct qe_snum {
-       u8 num;
-       enum qe_snum_state state;
-};
-
 /* We allocate this here because it is used almost exclusively for
  * the communication processor devices.
  */
 struct qe_immap __iomem *qe_immr;
 EXPORT_SYMBOL(qe_immr);
 
-static struct qe_snum snums[QE_NUM_OF_SNUM];   /* Dynamically allocated SNUMs */
+static u8 snums[QE_NUM_OF_SNUM];       /* Dynamically allocated SNUMs */
+static DECLARE_BITMAP(snum_state, QE_NUM_OF_SNUM);
 static unsigned int qe_num_of_snum;
 
 static phys_addr_t qebase = -1;
 
+static struct device_node *qe_get_device_node(void)
+{
+       struct device_node *qe;
+
+       /*
+        * Newer device trees have an "fsl,qe" compatible property for the QE
+        * node, but we still need to support older device trees.
+        */
+       qe = of_find_compatible_node(NULL, NULL, "fsl,qe");
+       if (qe)
+               return qe;
+       return of_find_node_by_type(NULL, "qe");
+}
+
 static phys_addr_t get_qe_base(void)
 {
        struct device_node *qe;
@@ -71,12 +75,9 @@ static phys_addr_t get_qe_base(void)
        if (qebase != -1)
                return qebase;
 
-       qe = of_find_compatible_node(NULL, NULL, "fsl,qe");
-       if (!qe) {
-               qe = of_find_node_by_type(NULL, "qe");
-               if (!qe)
-                       return qebase;
-       }
+       qe = qe_get_device_node();
+       if (!qe)
+               return qebase;
 
        ret = of_address_to_resource(qe, 0, &res);
        if (!ret)
@@ -170,12 +171,9 @@ unsigned int qe_get_brg_clk(void)
        if (brg_clk)
                return brg_clk;
 
-       qe = of_find_compatible_node(NULL, NULL, "fsl,qe");
-       if (!qe) {
-               qe = of_find_node_by_type(NULL, "qe");
-               if (!qe)
-                       return brg_clk;
-       }
+       qe = qe_get_device_node();
+       if (!qe)
+               return brg_clk;
 
        prop = of_get_property(qe, "brg-frequency", &size);
        if (prop && size == sizeof(*prop))
@@ -281,7 +279,6 @@ EXPORT_SYMBOL(qe_clock_source);
  */
 static void qe_snums_init(void)
 {
-       int i;
        static const u8 snum_init_76[] = {
                0x04, 0x05, 0x0C, 0x0D, 0x14, 0x15, 0x1C, 0x1D,
                0x24, 0x25, 0x2C, 0x2D, 0x34, 0x35, 0x88, 0x89,
@@ -302,19 +299,39 @@ static void qe_snums_init(void)
                0x28, 0x29, 0x38, 0x39, 0x48, 0x49, 0x58, 0x59,
                0x68, 0x69, 0x78, 0x79, 0x80, 0x81,
        };
-       static const u8 *snum_init;
+       struct device_node *qe;
+       const u8 *snum_init;
+       int i;
 
-       qe_num_of_snum = qe_get_num_of_snums();
+       bitmap_zero(snum_state, QE_NUM_OF_SNUM);
+       qe_num_of_snum = 28; /* The default number of snum for threads is 28 */
+       qe = qe_get_device_node();
+       if (qe) {
+               i = of_property_read_variable_u8_array(qe, "fsl,qe-snums",
+                                                      snums, 1, QE_NUM_OF_SNUM);
+               if (i > 0) {
+                       of_node_put(qe);
+                       qe_num_of_snum = i;
+                       return;
+               }
+               /*
+                * Fall back to legacy binding of using the value of
+                * fsl,qe-num-snums to choose one of the static arrays
+                * above.
+                */
+               of_property_read_u32(qe, "fsl,qe-num-snums", &qe_num_of_snum);
+               of_node_put(qe);
+       }
 
-       if (qe_num_of_snum == 76)
+       if (qe_num_of_snum == 76) {
                snum_init = snum_init_76;
-       else
+       } else if (qe_num_of_snum == 28 || qe_num_of_snum == 46) {
                snum_init = snum_init_46;
-
-       for (i = 0; i < qe_num_of_snum; i++) {
-               snums[i].num = snum_init[i];
-               snums[i].state = QE_SNUM_STATE_FREE;
+       } else {
+               pr_err("QE: unsupported value of fsl,qe-num-snums: %u\n", qe_num_of_snum);
+               return;
        }
+       memcpy(snums, snum_init, qe_num_of_snum);
 }
 
 int qe_get_snum(void)
@@ -324,12 +341,10 @@ int qe_get_snum(void)
        int i;
 
        spin_lock_irqsave(&qe_lock, flags);
-       for (i = 0; i < qe_num_of_snum; i++) {
-               if (snums[i].state == QE_SNUM_STATE_FREE) {
-                       snums[i].state = QE_SNUM_STATE_USED;
-                       snum = snums[i].num;
-                       break;
-               }
+       i = find_first_zero_bit(snum_state, qe_num_of_snum);
+       if (i < qe_num_of_snum) {
+               set_bit(i, snum_state);
+               snum = snums[i];
        }
        spin_unlock_irqrestore(&qe_lock, flags);
 
@@ -339,14 +354,10 @@ EXPORT_SYMBOL(qe_get_snum);
 
 void qe_put_snum(u8 snum)
 {
-       int i;
+       const u8 *p = memchr(snums, snum, qe_num_of_snum);
 
-       for (i = 0; i < qe_num_of_snum; i++) {
-               if (snums[i].num == snum) {
-                       snums[i].state = QE_SNUM_STATE_FREE;
-                       break;
-               }
-       }
+       if (p)
+               clear_bit(p - snums, snum_state);
 }
 EXPORT_SYMBOL(qe_put_snum);
 
@@ -572,16 +583,9 @@ struct qe_firmware_info *qe_get_firmware_info(void)
 
        initialized = 1;
 
-       /*
-        * Newer device trees have an "fsl,qe" compatible property for the QE
-        * node, but we still need to support older device trees.
-       */
-       qe = of_find_compatible_node(NULL, NULL, "fsl,qe");
-       if (!qe) {
-               qe = of_find_node_by_type(NULL, "qe");
-               if (!qe)
-                       return NULL;
-       }
+       qe = qe_get_device_node();
+       if (!qe)
+               return NULL;
 
        /* Find the 'firmware' child node */
        fw = of_get_child_by_name(qe, "firmware");
@@ -627,16 +631,9 @@ unsigned int qe_get_num_of_risc(void)
        unsigned int num_of_risc = 0;
        const u32 *prop;
 
-       qe = of_find_compatible_node(NULL, NULL, "fsl,qe");
-       if (!qe) {
-               /* Older devices trees did not have an "fsl,qe"
-                * compatible property, so we need to look for
-                * the QE node by name.
-                */
-               qe = of_find_node_by_type(NULL, "qe");
-               if (!qe)
-                       return num_of_risc;
-       }
+       qe = qe_get_device_node();
+       if (!qe)
+               return num_of_risc;
 
        prop = of_get_property(qe, "fsl,qe-num-riscs", &size);
        if (prop && size == sizeof(*prop))
@@ -650,37 +647,7 @@ EXPORT_SYMBOL(qe_get_num_of_risc);
 
 unsigned int qe_get_num_of_snums(void)
 {
-       struct device_node *qe;
-       int size;
-       unsigned int num_of_snums;
-       const u32 *prop;
-
-       num_of_snums = 28; /* The default number of snum for threads is 28 */
-       qe = of_find_compatible_node(NULL, NULL, "fsl,qe");
-       if (!qe) {
-               /* Older devices trees did not have an "fsl,qe"
-                * compatible property, so we need to look for
-                * the QE node by name.
-                */
-               qe = of_find_node_by_type(NULL, "qe");
-               if (!qe)
-                       return num_of_snums;
-       }
-
-       prop = of_get_property(qe, "fsl,qe-num-snums", &size);
-       if (prop && size == sizeof(*prop)) {
-               num_of_snums = *prop;
-               if ((num_of_snums < 28) || (num_of_snums > QE_NUM_OF_SNUM)) {
-                       /* No QE ever has fewer than 28 SNUMs */
-                       pr_err("QE: number of snum is invalid\n");
-                       of_node_put(qe);
-                       return -EINVAL;
-               }
-       }
-
-       of_node_put(qe);
-
-       return num_of_snums;
+       return qe_num_of_snum;
 }
 EXPORT_SYMBOL(qe_get_num_of_snums);
 
index 31b8d00..b0dffb0 100644 (file)
@@ -198,7 +198,7 @@ static int imx_gpc_pu_pgc_sw_pxx_req(struct generic_pm_domain *genpd,
                err = regulator_disable(domain->regulator);
                if (err)
                        dev_err(domain->dev,
-                               "failed to disable regulator: %d\n", ret);
+                               "failed to disable regulator: %d\n", err);
                /* Preserve earlier error code */
                ret = ret ?: err;
        }
index 676f612..50831eb 100644 (file)
@@ -27,6 +27,40 @@ struct imx_sc_msg_misc_get_soc_id {
        } data;
 } __packed;
 
+struct imx_sc_msg_misc_get_soc_uid {
+       struct imx_sc_rpc_msg hdr;
+       u32 uid_low;
+       u32 uid_high;
+} __packed;
+
+static ssize_t soc_uid_show(struct device *dev,
+                           struct device_attribute *attr, char *buf)
+{
+       struct imx_sc_msg_misc_get_soc_uid msg;
+       struct imx_sc_rpc_msg *hdr = &msg.hdr;
+       u64 soc_uid;
+       int ret;
+
+       hdr->ver = IMX_SC_RPC_VERSION;
+       hdr->svc = IMX_SC_RPC_SVC_MISC;
+       hdr->func = IMX_SC_MISC_FUNC_UNIQUE_ID;
+       hdr->size = 1;
+
+       ret = imx_scu_call_rpc(soc_ipc_handle, &msg, false);
+       if (ret) {
+               pr_err("%s: get soc uid failed, ret %d\n", __func__, ret);
+               return ret;
+       }
+
+       soc_uid = msg.uid_high;
+       soc_uid <<= 32;
+       soc_uid |= msg.uid_low;
+
+       return sprintf(buf, "%016llX\n", soc_uid);
+}
+
+static DEVICE_ATTR_RO(soc_uid);
+
 static int imx_scu_soc_id(void)
 {
        struct imx_sc_msg_misc_get_soc_id msg;
@@ -102,6 +136,11 @@ static int imx_scu_soc_probe(struct platform_device *pdev)
                goto free_revision;
        }
 
+       ret = device_create_file(soc_device_to_device(soc_dev),
+                                &dev_attr_soc_uid);
+       if (ret)
+               goto free_revision;
+
        return 0;
 
 free_revision:
index f924ae8..b983157 100644 (file)
@@ -16,6 +16,9 @@
 #define IMX8MQ_SW_INFO_B1              0x40
 #define IMX8MQ_SW_MAGIC_B1             0xff0055aa
 
+#define OCOTP_UID_LOW                  0x410
+#define OCOTP_UID_HIGH                 0x420
+
 /* Same as ANADIG_DIGPROG_IMX7D */
 #define ANADIG_DIGPROG_IMX8MM  0x800
 
@@ -24,6 +27,16 @@ struct imx8_soc_data {
        u32 (*soc_revision)(void);
 };
 
+static u64 soc_uid;
+
+static ssize_t soc_uid_show(struct device *dev,
+                           struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%016llX\n", soc_uid);
+}
+
+static DEVICE_ATTR_RO(soc_uid);
+
 static u32 __init imx8mq_soc_revision(void)
 {
        struct device_node *np;
@@ -42,6 +55,10 @@ static u32 __init imx8mq_soc_revision(void)
        if (magic == IMX8MQ_SW_MAGIC_B1)
                rev = REV_B1;
 
+       soc_uid = readl_relaxed(ocotp_base + OCOTP_UID_HIGH);
+       soc_uid <<= 32;
+       soc_uid |= readl_relaxed(ocotp_base + OCOTP_UID_LOW);
+
        iounmap(ocotp_base);
 
 out:
@@ -49,6 +66,26 @@ out:
        return rev;
 }
 
+static void __init imx8mm_soc_uid(void)
+{
+       void __iomem *ocotp_base;
+       struct device_node *np;
+
+       np = of_find_compatible_node(NULL, NULL, "fsl,imx8mm-ocotp");
+       if (!np)
+               return;
+
+       ocotp_base = of_iomap(np, 0);
+       WARN_ON(!ocotp_base);
+
+       soc_uid = readl_relaxed(ocotp_base + OCOTP_UID_HIGH);
+       soc_uid <<= 32;
+       soc_uid |= readl_relaxed(ocotp_base + OCOTP_UID_LOW);
+
+       iounmap(ocotp_base);
+       of_node_put(np);
+}
+
 static u32 __init imx8mm_soc_revision(void)
 {
        struct device_node *np;
@@ -66,6 +103,9 @@ static u32 __init imx8mm_soc_revision(void)
 
        iounmap(anatop_base);
        of_node_put(np);
+
+       imx8mm_soc_uid();
+
        return rev;
 }
 
@@ -140,6 +180,11 @@ static int __init imx8_soc_init(void)
                goto free_rev;
        }
 
+       ret = device_create_file(soc_device_to_device(soc_dev),
+                                &dev_attr_soc_uid);
+       if (ret)
+               goto free_rev;
+
        if (IS_ENABLED(CONFIG_ARM_IMX_CPUFREQ_DT))
                platform_device_register_simple("imx-cpufreq-dt", -1, NULL, 0);
 
index ff9fef5..7aa0517 100644 (file)
@@ -136,7 +136,7 @@ static int cmdq_pkt_append_command(struct cmdq_pkt *pkt, enum cmdq_code code,
        return 0;
 }
 
-int cmdq_pkt_write(struct cmdq_pkt *pkt, u32 value, u32 subsys, u32 offset)
+int cmdq_pkt_write(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value)
 {
        u32 arg_a = (offset & CMDQ_ARG_A_WRITE_MASK) |
                    (subsys << CMDQ_SUBSYS_SHIFT);
@@ -145,8 +145,8 @@ int cmdq_pkt_write(struct cmdq_pkt *pkt, u32 value, u32 subsys, u32 offset)
 }
 EXPORT_SYMBOL(cmdq_pkt_write);
 
-int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u32 value,
-                       u32 subsys, u32 offset, u32 mask)
+int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u8 subsys,
+                       u16 offset, u32 value, u32 mask)
 {
        u32 offset_mask = offset;
        int err = 0;
@@ -161,7 +161,7 @@ int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u32 value,
 }
 EXPORT_SYMBOL(cmdq_pkt_write_mask);
 
-int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u32 event)
+int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u16 event)
 {
        u32 arg_b;
 
@@ -181,7 +181,7 @@ int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u32 event)
 }
 EXPORT_SYMBOL(cmdq_pkt_wfe);
 
-int cmdq_pkt_clear_event(struct cmdq_pkt *pkt, u32 event)
+int cmdq_pkt_clear_event(struct cmdq_pkt *pkt, u16 event)
 {
        if (event >= CMDQ_MAX_EVENT)
                return -EINVAL;
index a6d1bfb..661e47a 100644 (file)
@@ -175,6 +175,14 @@ config QCOM_SMSM
          Say yes here to support the Qualcomm Shared Memory State Machine.
          The state machine is represented by bits in shared memory.
 
+config QCOM_SOCINFO
+       tristate "Qualcomm socinfo driver"
+       depends on QCOM_SMEM
+       select SOC_BUS
+       help
+        Say yes here to support the Qualcomm socinfo driver, providing
+        information about the SoC to user space.
+
 config QCOM_WCNSS_CTRL
        tristate "Qualcomm WCNSS control driver"
        depends on ARCH_QCOM || COMPILE_TEST
index eeb088b..1627887 100644 (file)
@@ -18,6 +18,7 @@ obj-$(CONFIG_QCOM_SMEM) +=    smem.o
 obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o
 obj-$(CONFIG_QCOM_SMP2P)       += smp2p.o
 obj-$(CONFIG_QCOM_SMSM)        += smsm.o
+obj-$(CONFIG_QCOM_SOCINFO)     += socinfo.o
 obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o
 obj-$(CONFIG_QCOM_APR) += apr.o
 obj-$(CONFIG_QCOM_LLCC) += llcc-slice.o
index 5f88519..33a27e6 100644 (file)
@@ -10,6 +10,8 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/pm_domain.h>
+#include <linux/thermal.h>
+#include <linux/slab.h>
 
 #define QMP_DESC_MAGIC                 0x0
 #define QMP_DESC_VERSION               0x4
 /* 64 bytes is enough to store the requests and provides padding to 4 bytes */
 #define QMP_MSG_LEN                    64
 
+#define QMP_NUM_COOLING_RESOURCES      2
+
+static bool qmp_cdev_init_state = 1;
+
+struct qmp_cooling_device {
+       struct thermal_cooling_device *cdev;
+       struct qmp *qmp;
+       char *name;
+       bool state;
+};
+
 /**
  * struct qmp - driver state for QMP implementation
  * @msgram: iomem referencing the message RAM used for communication
@@ -69,6 +82,7 @@ struct qmp {
 
        struct clk_hw qdss_clk;
        struct genpd_onecell_data pd_data;
+       struct qmp_cooling_device *cooling_devs;
 };
 
 struct qmp_pd {
@@ -385,6 +399,118 @@ static void qmp_pd_remove(struct qmp *qmp)
                pm_genpd_remove(data->domains[i]);
 }
 
+static int qmp_cdev_get_max_state(struct thermal_cooling_device *cdev,
+                                 unsigned long *state)
+{
+       *state = qmp_cdev_init_state;
+       return 0;
+}
+
+static int qmp_cdev_get_cur_state(struct thermal_cooling_device *cdev,
+                                 unsigned long *state)
+{
+       struct qmp_cooling_device *qmp_cdev = cdev->devdata;
+
+       *state = qmp_cdev->state;
+       return 0;
+}
+
+static int qmp_cdev_set_cur_state(struct thermal_cooling_device *cdev,
+                                 unsigned long state)
+{
+       struct qmp_cooling_device *qmp_cdev = cdev->devdata;
+       char buf[QMP_MSG_LEN] = {};
+       bool cdev_state;
+       int ret;
+
+       /* Normalize state */
+       cdev_state = !!state;
+
+       if (qmp_cdev->state == state)
+               return 0;
+
+       snprintf(buf, sizeof(buf),
+                "{class: volt_flr, event:zero_temp, res:%s, value:%s}",
+                       qmp_cdev->name,
+                       cdev_state ? "off" : "on");
+
+       ret = qmp_send(qmp_cdev->qmp, buf, sizeof(buf));
+
+       if (!ret)
+               qmp_cdev->state = cdev_state;
+
+       return ret;
+}
+
+static struct thermal_cooling_device_ops qmp_cooling_device_ops = {
+       .get_max_state = qmp_cdev_get_max_state,
+       .get_cur_state = qmp_cdev_get_cur_state,
+       .set_cur_state = qmp_cdev_set_cur_state,
+};
+
+static int qmp_cooling_device_add(struct qmp *qmp,
+                                 struct qmp_cooling_device *qmp_cdev,
+                                 struct device_node *node)
+{
+       char *cdev_name = (char *)node->name;
+
+       qmp_cdev->qmp = qmp;
+       qmp_cdev->state = qmp_cdev_init_state;
+       qmp_cdev->name = cdev_name;
+       qmp_cdev->cdev = devm_thermal_of_cooling_device_register
+                               (qmp->dev, node,
+                               cdev_name,
+                               qmp_cdev, &qmp_cooling_device_ops);
+
+       if (IS_ERR(qmp_cdev->cdev))
+               dev_err(qmp->dev, "unable to register %s cooling device\n",
+                       cdev_name);
+
+       return PTR_ERR_OR_ZERO(qmp_cdev->cdev);
+}
+
+static int qmp_cooling_devices_register(struct qmp *qmp)
+{
+       struct device_node *np, *child;
+       int count = QMP_NUM_COOLING_RESOURCES;
+       int ret;
+
+       np = qmp->dev->of_node;
+
+       qmp->cooling_devs = devm_kcalloc(qmp->dev, count,
+                                        sizeof(*qmp->cooling_devs),
+                                        GFP_KERNEL);
+
+       if (!qmp->cooling_devs)
+               return -ENOMEM;
+
+       for_each_available_child_of_node(np, child) {
+               if (!of_find_property(child, "#cooling-cells", NULL))
+                       continue;
+               ret = qmp_cooling_device_add(qmp, &qmp->cooling_devs[count++],
+                                            child);
+               if (ret)
+                       goto unroll;
+       }
+
+       return 0;
+
+unroll:
+       while (--count >= 0)
+               thermal_cooling_device_unregister
+                       (qmp->cooling_devs[count].cdev);
+
+       return ret;
+}
+
+static void qmp_cooling_devices_remove(struct qmp *qmp)
+{
+       int i;
+
+       for (i = 0; i < QMP_NUM_COOLING_RESOURCES; i++)
+               thermal_cooling_device_unregister(qmp->cooling_devs[i].cdev);
+}
+
 static int qmp_probe(struct platform_device *pdev)
 {
        struct resource *res;
@@ -433,6 +559,10 @@ static int qmp_probe(struct platform_device *pdev)
        if (ret)
                goto err_remove_qdss_clk;
 
+       ret = qmp_cooling_devices_register(qmp);
+       if (ret)
+               dev_err(&pdev->dev, "failed to register aoss cooling devices\n");
+
        platform_set_drvdata(pdev, qmp);
 
        return 0;
@@ -453,6 +583,7 @@ static int qmp_remove(struct platform_device *pdev)
 
        qmp_qdss_clk_remove(qmp);
        qmp_pd_remove(qmp);
+       qmp_cooling_devices_remove(qmp);
 
        qmp_close(qmp);
        mbox_free_channel(qmp->mbox_chan);
@@ -461,7 +592,9 @@ static int qmp_remove(struct platform_device *pdev)
 }
 
 static const struct of_device_id qmp_dt_match[] = {
+       { .compatible = "qcom,sc7180-aoss-qmp", },
        { .compatible = "qcom,sdm845-aoss-qmp", },
+       { .compatible = "qcom,sm8150-aoss-qmp", },
        {}
 };
 MODULE_DEVICE_TABLE(of, qmp_dt_match);
index f27c00d..28c19bc 100644 (file)
@@ -84,7 +84,7 @@
 #define SMEM_GLOBAL_HOST       0xfffe
 
 /* Max number of processors/hosts in a system */
-#define SMEM_HOST_COUNT                10
+#define SMEM_HOST_COUNT                11
 
 /**
   * struct smem_proc_comm - proc_comm communication struct (legacy)
@@ -268,6 +268,7 @@ struct qcom_smem {
        struct smem_partition_header *partitions[SMEM_HOST_COUNT];
        size_t cacheline[SMEM_HOST_COUNT];
        u32 item_count;
+       struct platform_device *socinfo;
 
        unsigned num_regions;
        struct smem_region regions[];
@@ -963,11 +964,19 @@ static int qcom_smem_probe(struct platform_device *pdev)
 
        __smem = smem;
 
+       smem->socinfo = platform_device_register_data(&pdev->dev, "qcom-socinfo",
+                                                     PLATFORM_DEVID_NONE, NULL,
+                                                     0);
+       if (IS_ERR(smem->socinfo))
+               dev_dbg(&pdev->dev, "failed to register socinfo device\n");
+
        return 0;
 }
 
 static int qcom_smem_remove(struct platform_device *pdev)
 {
+       platform_device_unregister(__smem->socinfo);
+
        hwspin_lock_free(__smem->hwlock);
        __smem = NULL;
 
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
new file mode 100644 (file)
index 0000000..a39ea50
--- /dev/null
@@ -0,0 +1,476 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2009-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2019, Linaro Ltd.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+#include <linux/soc/qcom/smem.h>
+#include <linux/string.h>
+#include <linux/sys_soc.h>
+#include <linux/types.h>
+
+/*
+ * SoC version type with major number in the upper 16 bits and minor
+ * number in the lower 16 bits.
+ */
+#define SOCINFO_MAJOR(ver) (((ver) >> 16) & 0xffff)
+#define SOCINFO_MINOR(ver) ((ver) & 0xffff)
+#define SOCINFO_VERSION(maj, min)  ((((maj) & 0xffff) << 16)|((min) & 0xffff))
+
+#define SMEM_SOCINFO_BUILD_ID_LENGTH           32
+
+/*
+ * SMEM item id, used to acquire handles to respective
+ * SMEM region.
+ */
+#define SMEM_HW_SW_BUILD_ID            137
+
+#ifdef CONFIG_DEBUG_FS
+#define SMEM_IMAGE_VERSION_BLOCKS_COUNT        32
+#define SMEM_IMAGE_VERSION_SIZE                4096
+#define SMEM_IMAGE_VERSION_NAME_SIZE           75
+#define SMEM_IMAGE_VERSION_VARIANT_SIZE        20
+#define SMEM_IMAGE_VERSION_OEM_SIZE            32
+
+/*
+ * SMEM Image table indices
+ */
+#define SMEM_IMAGE_TABLE_BOOT_INDEX     0
+#define SMEM_IMAGE_TABLE_TZ_INDEX       1
+#define SMEM_IMAGE_TABLE_RPM_INDEX      3
+#define SMEM_IMAGE_TABLE_APPS_INDEX     10
+#define SMEM_IMAGE_TABLE_MPSS_INDEX     11
+#define SMEM_IMAGE_TABLE_ADSP_INDEX     12
+#define SMEM_IMAGE_TABLE_CNSS_INDEX     13
+#define SMEM_IMAGE_TABLE_VIDEO_INDEX    14
+#define SMEM_IMAGE_VERSION_TABLE       469
+
+/*
+ * SMEM Image table names
+ */
+static const char *const socinfo_image_names[] = {
+       [SMEM_IMAGE_TABLE_ADSP_INDEX] = "adsp",
+       [SMEM_IMAGE_TABLE_APPS_INDEX] = "apps",
+       [SMEM_IMAGE_TABLE_BOOT_INDEX] = "boot",
+       [SMEM_IMAGE_TABLE_CNSS_INDEX] = "cnss",
+       [SMEM_IMAGE_TABLE_MPSS_INDEX] = "mpss",
+       [SMEM_IMAGE_TABLE_RPM_INDEX] = "rpm",
+       [SMEM_IMAGE_TABLE_TZ_INDEX] = "tz",
+       [SMEM_IMAGE_TABLE_VIDEO_INDEX] = "video",
+};
+
+static const char *const pmic_models[] = {
+       [0]  = "Unknown PMIC model",
+       [9]  = "PM8994",
+       [11] = "PM8916",
+       [13] = "PM8058",
+       [14] = "PM8028",
+       [15] = "PM8901",
+       [16] = "PM8027",
+       [17] = "ISL9519",
+       [18] = "PM8921",
+       [19] = "PM8018",
+       [20] = "PM8015",
+       [21] = "PM8014",
+       [22] = "PM8821",
+       [23] = "PM8038",
+       [24] = "PM8922",
+       [25] = "PM8917",
+};
+#endif /* CONFIG_DEBUG_FS */
+
+/* Socinfo SMEM item structure */
+struct socinfo {
+       __le32 fmt;
+       __le32 id;
+       __le32 ver;
+       char build_id[SMEM_SOCINFO_BUILD_ID_LENGTH];
+       /* Version 2 */
+       __le32 raw_id;
+       __le32 raw_ver;
+       /* Version 3 */
+       __le32 hw_plat;
+       /* Version 4 */
+       __le32 plat_ver;
+       /* Version 5 */
+       __le32 accessory_chip;
+       /* Version 6 */
+       __le32 hw_plat_subtype;
+       /* Version 7 */
+       __le32 pmic_model;
+       __le32 pmic_die_rev;
+       /* Version 8 */
+       __le32 pmic_model_1;
+       __le32 pmic_die_rev_1;
+       __le32 pmic_model_2;
+       __le32 pmic_die_rev_2;
+       /* Version 9 */
+       __le32 foundry_id;
+       /* Version 10 */
+       __le32 serial_num;
+       /* Version 11 */
+       __le32 num_pmics;
+       __le32 pmic_array_offset;
+       /* Version 12 */
+       __le32 chip_family;
+       __le32 raw_device_family;
+       __le32 raw_device_num;
+};
+
+#ifdef CONFIG_DEBUG_FS
+struct socinfo_params {
+       u32 raw_device_family;
+       u32 hw_plat_subtype;
+       u32 accessory_chip;
+       u32 raw_device_num;
+       u32 chip_family;
+       u32 foundry_id;
+       u32 plat_ver;
+       u32 raw_ver;
+       u32 hw_plat;
+       u32 fmt;
+};
+
+struct smem_image_version {
+       char name[SMEM_IMAGE_VERSION_NAME_SIZE];
+       char variant[SMEM_IMAGE_VERSION_VARIANT_SIZE];
+       char pad;
+       char oem[SMEM_IMAGE_VERSION_OEM_SIZE];
+};
+#endif /* CONFIG_DEBUG_FS */
+
+struct qcom_socinfo {
+       struct soc_device *soc_dev;
+       struct soc_device_attribute attr;
+#ifdef CONFIG_DEBUG_FS
+       struct dentry *dbg_root;
+       struct socinfo_params info;
+#endif /* CONFIG_DEBUG_FS */
+};
+
+struct soc_id {
+       unsigned int id;
+       const char *name;
+};
+
+static const struct soc_id soc_id[] = {
+       { 87, "MSM8960" },
+       { 109, "APQ8064" },
+       { 122, "MSM8660A" },
+       { 123, "MSM8260A" },
+       { 124, "APQ8060A" },
+       { 126, "MSM8974" },
+       { 130, "MPQ8064" },
+       { 138, "MSM8960AB" },
+       { 139, "APQ8060AB" },
+       { 140, "MSM8260AB" },
+       { 141, "MSM8660AB" },
+       { 178, "APQ8084" },
+       { 184, "APQ8074" },
+       { 185, "MSM8274" },
+       { 186, "MSM8674" },
+       { 194, "MSM8974PRO" },
+       { 206, "MSM8916" },
+       { 208, "APQ8074-AA" },
+       { 209, "APQ8074-AB" },
+       { 210, "APQ8074PRO" },
+       { 211, "MSM8274-AA" },
+       { 212, "MSM8274-AB" },
+       { 213, "MSM8274PRO" },
+       { 214, "MSM8674-AA" },
+       { 215, "MSM8674-AB" },
+       { 216, "MSM8674PRO" },
+       { 217, "MSM8974-AA" },
+       { 218, "MSM8974-AB" },
+       { 246, "MSM8996" },
+       { 247, "APQ8016" },
+       { 248, "MSM8216" },
+       { 249, "MSM8116" },
+       { 250, "MSM8616" },
+       { 291, "APQ8096" },
+       { 305, "MSM8996SG" },
+       { 310, "MSM8996AU" },
+       { 311, "APQ8096AU" },
+       { 312, "APQ8096SG" },
+};
+
+static const char *socinfo_machine(struct device *dev, unsigned int id)
+{
+       int idx;
+
+       for (idx = 0; idx < ARRAY_SIZE(soc_id); idx++) {
+               if (soc_id[idx].id == id)
+                       return soc_id[idx].name;
+       }
+
+       return NULL;
+}
+
+#ifdef CONFIG_DEBUG_FS
+
+#define QCOM_OPEN(name, _func)                                         \
+static int qcom_open_##name(struct inode *inode, struct file *file)    \
+{                                                                      \
+       return single_open(file, _func, inode->i_private);              \
+}                                                                      \
+                                                                       \
+static const struct file_operations qcom_ ##name## _ops = {            \
+       .open = qcom_open_##name,                                       \
+       .read = seq_read,                                               \
+       .llseek = seq_lseek,                                            \
+       .release = single_release,                                      \
+}
+
+#define DEBUGFS_ADD(info, name)                                                \
+       debugfs_create_file(__stringify(name), 0400,                    \
+                           qcom_socinfo->dbg_root,                     \
+                           info, &qcom_ ##name## _ops)
+
+
+static int qcom_show_build_id(struct seq_file *seq, void *p)
+{
+       struct socinfo *socinfo = seq->private;
+
+       seq_printf(seq, "%s\n", socinfo->build_id);
+
+       return 0;
+}
+
+static int qcom_show_pmic_model(struct seq_file *seq, void *p)
+{
+       struct socinfo *socinfo = seq->private;
+       int model = SOCINFO_MINOR(le32_to_cpu(socinfo->pmic_model));
+
+       if (model < 0)
+               return -EINVAL;
+
+       seq_printf(seq, "%s\n", pmic_models[model]);
+
+       return 0;
+}
+
+static int qcom_show_pmic_die_revision(struct seq_file *seq, void *p)
+{
+       struct socinfo *socinfo = seq->private;
+
+       seq_printf(seq, "%u.%u\n",
+                  SOCINFO_MAJOR(le32_to_cpu(socinfo->pmic_die_rev)),
+                  SOCINFO_MINOR(le32_to_cpu(socinfo->pmic_die_rev)));
+
+       return 0;
+}
+
+QCOM_OPEN(build_id, qcom_show_build_id);
+QCOM_OPEN(pmic_model, qcom_show_pmic_model);
+QCOM_OPEN(pmic_die_rev, qcom_show_pmic_die_revision);
+
+#define DEFINE_IMAGE_OPS(type)                                 \
+static int show_image_##type(struct seq_file *seq, void *p)              \
+{                                                                \
+       struct smem_image_version *image_version = seq->private;  \
+       seq_puts(seq, image_version->type);                       \
+       seq_puts(seq, "\n");                                      \
+       return 0;                                                 \
+}                                                                \
+static int open_image_##type(struct inode *inode, struct file *file)     \
+{                                                                        \
+       return single_open(file, show_image_##type, inode->i_private); \
+}                                                                        \
+                                                                         \
+static const struct file_operations qcom_image_##type##_ops = {          \
+       .open = open_image_##type,                                        \
+       .read = seq_read,                                                 \
+       .llseek = seq_lseek,                                              \
+       .release = single_release,                                        \
+}
+
+DEFINE_IMAGE_OPS(name);
+DEFINE_IMAGE_OPS(variant);
+DEFINE_IMAGE_OPS(oem);
+
+static void socinfo_debugfs_init(struct qcom_socinfo *qcom_socinfo,
+                                struct socinfo *info)
+{
+       struct smem_image_version *versions;
+       struct dentry *dentry;
+       size_t size;
+       int i;
+
+       qcom_socinfo->dbg_root = debugfs_create_dir("qcom_socinfo", NULL);
+
+       qcom_socinfo->info.fmt = __le32_to_cpu(info->fmt);
+
+       switch (qcom_socinfo->info.fmt) {
+       case SOCINFO_VERSION(0, 12):
+               qcom_socinfo->info.chip_family =
+                       __le32_to_cpu(info->chip_family);
+               qcom_socinfo->info.raw_device_family =
+                       __le32_to_cpu(info->raw_device_family);
+               qcom_socinfo->info.raw_device_num =
+                       __le32_to_cpu(info->raw_device_num);
+
+               debugfs_create_x32("chip_family", 0400, qcom_socinfo->dbg_root,
+                                  &qcom_socinfo->info.chip_family);
+               debugfs_create_x32("raw_device_family", 0400,
+                                  qcom_socinfo->dbg_root,
+                                  &qcom_socinfo->info.raw_device_family);
+               debugfs_create_x32("raw_device_number", 0400,
+                                  qcom_socinfo->dbg_root,
+                                  &qcom_socinfo->info.raw_device_num);
+               /* Fall through */
+       case SOCINFO_VERSION(0, 11):
+       case SOCINFO_VERSION(0, 10):
+       case SOCINFO_VERSION(0, 9):
+               qcom_socinfo->info.foundry_id = __le32_to_cpu(info->foundry_id);
+
+               debugfs_create_u32("foundry_id", 0400, qcom_socinfo->dbg_root,
+                                  &qcom_socinfo->info.foundry_id);
+               /* Fall through */
+       case SOCINFO_VERSION(0, 8):
+       case SOCINFO_VERSION(0, 7):
+               DEBUGFS_ADD(info, pmic_model);
+               DEBUGFS_ADD(info, pmic_die_rev);
+               /* Fall through */
+       case SOCINFO_VERSION(0, 6):
+               qcom_socinfo->info.hw_plat_subtype =
+                       __le32_to_cpu(info->hw_plat_subtype);
+
+               debugfs_create_u32("hardware_platform_subtype", 0400,
+                                  qcom_socinfo->dbg_root,
+                                  &qcom_socinfo->info.hw_plat_subtype);
+               /* Fall through */
+       case SOCINFO_VERSION(0, 5):
+               qcom_socinfo->info.accessory_chip =
+                       __le32_to_cpu(info->accessory_chip);
+
+               debugfs_create_u32("accessory_chip", 0400,
+                                  qcom_socinfo->dbg_root,
+                                  &qcom_socinfo->info.accessory_chip);
+               /* Fall through */
+       case SOCINFO_VERSION(0, 4):
+               qcom_socinfo->info.plat_ver = __le32_to_cpu(info->plat_ver);
+
+               debugfs_create_u32("platform_version", 0400,
+                                  qcom_socinfo->dbg_root,
+                                  &qcom_socinfo->info.plat_ver);
+               /* Fall through */
+       case SOCINFO_VERSION(0, 3):
+               qcom_socinfo->info.hw_plat = __le32_to_cpu(info->hw_plat);
+
+               debugfs_create_u32("hardware_platform", 0400,
+                                  qcom_socinfo->dbg_root,
+                                  &qcom_socinfo->info.hw_plat);
+               /* Fall through */
+       case SOCINFO_VERSION(0, 2):
+               qcom_socinfo->info.raw_ver  = __le32_to_cpu(info->raw_ver);
+
+               debugfs_create_u32("raw_version", 0400, qcom_socinfo->dbg_root,
+                                  &qcom_socinfo->info.raw_ver);
+               /* Fall through */
+       case SOCINFO_VERSION(0, 1):
+               DEBUGFS_ADD(info, build_id);
+               break;
+       }
+
+       versions = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_IMAGE_VERSION_TABLE,
+                                &size);
+
+       for (i = 0; i < ARRAY_SIZE(socinfo_image_names); i++) {
+               if (!socinfo_image_names[i])
+                       continue;
+
+               dentry = debugfs_create_dir(socinfo_image_names[i],
+                                           qcom_socinfo->dbg_root);
+               debugfs_create_file("name", 0400, dentry, &versions[i],
+                                   &qcom_image_name_ops);
+               debugfs_create_file("variant", 0400, dentry, &versions[i],
+                                   &qcom_image_variant_ops);
+               debugfs_create_file("oem", 0400, dentry, &versions[i],
+                                   &qcom_image_oem_ops);
+       }
+}
+
+static void socinfo_debugfs_exit(struct qcom_socinfo *qcom_socinfo)
+{
+       debugfs_remove_recursive(qcom_socinfo->dbg_root);
+}
+#else
+static void socinfo_debugfs_init(struct qcom_socinfo *qcom_socinfo,
+                                struct socinfo *info)
+{
+}
+static void socinfo_debugfs_exit(struct qcom_socinfo *qcom_socinfo) {  }
+#endif /* CONFIG_DEBUG_FS */
+
+static int qcom_socinfo_probe(struct platform_device *pdev)
+{
+       struct qcom_socinfo *qs;
+       struct socinfo *info;
+       size_t item_size;
+
+       info = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_HW_SW_BUILD_ID,
+                             &item_size);
+       if (IS_ERR(info)) {
+               dev_err(&pdev->dev, "Couldn't find socinfo\n");
+               return PTR_ERR(info);
+       }
+
+       qs = devm_kzalloc(&pdev->dev, sizeof(*qs), GFP_KERNEL);
+       if (!qs)
+               return -ENOMEM;
+
+       qs->attr.family = "Snapdragon";
+       qs->attr.machine = socinfo_machine(&pdev->dev,
+                                          le32_to_cpu(info->id));
+       qs->attr.revision = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%u.%u",
+                                          SOCINFO_MAJOR(le32_to_cpu(info->ver)),
+                                          SOCINFO_MINOR(le32_to_cpu(info->ver)));
+       if (offsetof(struct socinfo, serial_num) <= item_size)
+               qs->attr.serial_number = devm_kasprintf(&pdev->dev, GFP_KERNEL,
+                                                       "%u",
+                                                       le32_to_cpu(info->serial_num));
+
+       qs->soc_dev = soc_device_register(&qs->attr);
+       if (IS_ERR(qs->soc_dev))
+               return PTR_ERR(qs->soc_dev);
+
+       socinfo_debugfs_init(qs, info);
+
+       /* Feed the soc specific unique data into entropy pool */
+       add_device_randomness(info, item_size);
+
+       platform_set_drvdata(pdev, qs->soc_dev);
+
+       return 0;
+}
+
+static int qcom_socinfo_remove(struct platform_device *pdev)
+{
+       struct qcom_socinfo *qs = platform_get_drvdata(pdev);
+
+       soc_device_unregister(qs->soc_dev);
+
+       socinfo_debugfs_exit(qs);
+
+       return 0;
+}
+
+static struct platform_driver qcom_socinfo_driver = {
+       .probe = qcom_socinfo_probe,
+       .remove = qcom_socinfo_remove,
+       .driver  = {
+               .name = "qcom-socinfo",
+       },
+};
+
+module_platform_driver(qcom_socinfo_driver);
+
+MODULE_DESCRIPTION("Qualcomm SoCinfo driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:qcom-socinfo");
index 2bbf49e..3c5e017 100644 (file)
@@ -55,6 +55,7 @@ config ARCH_EMEV2
 
 config ARCH_R7S72100
        bool "RZ/A1H (R7S72100)"
+       select ARM_ERRATA_754322
        select PM
        select PM_GENERIC_DOMAINS
        select RENESAS_OSTM
@@ -72,12 +73,14 @@ config ARCH_R8A73A4
        bool "R-Mobile APE6 (R8A73A40)"
        select ARCH_RMOBILE
        select ARM_ERRATA_798181 if SMP
+       select ARM_ERRATA_814220
        select HAVE_ARM_ARCH_TIMER
        select RENESAS_IRQC
 
 config ARCH_R8A7740
        bool "R-Mobile A1 (R8A77400)"
        select ARCH_RMOBILE
+       select ARM_ERRATA_754322
        select RENESAS_INTC_IRQPIN
 
 config ARCH_R8A7743
@@ -95,20 +98,24 @@ config ARCH_R8A7744
 config ARCH_R8A7745
        bool "RZ/G1E (R8A77450)"
        select ARCH_RCAR_GEN2
+       select ARM_ERRATA_814220
        select SYSC_R8A7745
 
 config ARCH_R8A77470
        bool "RZ/G1C (R8A77470)"
        select ARCH_RCAR_GEN2
+       select ARM_ERRATA_814220
        select SYSC_R8A77470
 
 config ARCH_R8A7778
        bool "R-Car M1A (R8A77781)"
        select ARCH_RCAR_GEN1
+       select ARM_ERRATA_754322
 
 config ARCH_R8A7779
        bool "R-Car H1 (R8A77790)"
        select ARCH_RCAR_GEN1
+       select ARM_ERRATA_754322
        select HAVE_ARM_SCU if SMP
        select HAVE_ARM_TWD if SMP
        select SYSC_R8A7779
@@ -117,6 +124,7 @@ config ARCH_R8A7790
        bool "R-Car H2 (R8A77900)"
        select ARCH_RCAR_GEN2
        select ARM_ERRATA_798181 if SMP
+       select ARM_ERRATA_814220
        select I2C
        select SYSC_R8A7790
 
@@ -143,15 +151,18 @@ config ARCH_R8A7793
 config ARCH_R8A7794
        bool "R-Car E2 (R8A77940)"
        select ARCH_RCAR_GEN2
+       select ARM_ERRATA_814220
        select SYSC_R8A7794
 
 config ARCH_R9A06G032
        bool "RZ/N1D (R9A06G032)"
        select ARCH_RZN1
+       select ARM_ERRATA_814220
 
 config ARCH_SH73A0
        bool "SH-Mobile AG5 (R8A73A00)"
        select ARCH_RMOBILE
+       select ARM_ERRATA_754322
        select HAVE_ARM_SCU if SMP
        select HAVE_ARM_TWD if SMP
        select RENESAS_INTC_IRQPIN
index 0c80fab..59b5e6b 100644 (file)
@@ -170,7 +170,7 @@ struct rcar_sysc_pd {
        struct generic_pm_domain genpd;
        struct rcar_sysc_ch ch;
        unsigned int flags;
-       char name[0];
+       char name[];
 };
 
 static inline struct rcar_sysc_pd *to_rcar_pd(struct generic_pm_domain *d)
@@ -200,7 +200,6 @@ static int __init rcar_sysc_pd_setup(struct rcar_sysc_pd *pd)
 {
        struct generic_pm_domain *genpd = &pd->genpd;
        const char *name = pd->genpd.name;
-       struct dev_power_governor *gov = &simple_qos_governor;
        int error;
 
        if (pd->flags & PD_CPU) {
@@ -254,7 +253,7 @@ static int __init rcar_sysc_pd_setup(struct rcar_sysc_pd *pd)
        rcar_sysc_power(&pd->ch, true);
 
 finalize:
-       error = pm_genpd_init(genpd, gov, false);
+       error = pm_genpd_init(genpd, &simple_qos_governor, false);
        if (error)
                pr_err("Failed to init PM domain %s: %d\n", name, error);
 
@@ -346,7 +345,7 @@ static int __init rcar_sysc_pd_init(void)
        if (info->init) {
                error = info->init();
                if (error)
-                       return error;
+                       goto out_put;
        }
 
        has_cpg_mstp = of_find_compatible_node(NULL, NULL,
index 421ae1c..54b616a 100644 (file)
@@ -48,12 +48,8 @@ struct rmobile_pm_domain *to_rmobile_pd(struct generic_pm_domain *d)
 static int rmobile_pd_power_down(struct generic_pm_domain *genpd)
 {
        struct rmobile_pm_domain *rmobile_pd = to_rmobile_pd(genpd);
-       unsigned int mask;
+       unsigned int mask = BIT(rmobile_pd->bit_shift);
 
-       if (rmobile_pd->bit_shift == ~0)
-               return -EBUSY;
-
-       mask = BIT(rmobile_pd->bit_shift);
        if (rmobile_pd->suspend) {
                int ret = rmobile_pd->suspend();
 
@@ -80,14 +76,10 @@ static int rmobile_pd_power_down(struct generic_pm_domain *genpd)
 
 static int __rmobile_pd_power_up(struct rmobile_pm_domain *rmobile_pd)
 {
-       unsigned int mask;
+       unsigned int mask = BIT(rmobile_pd->bit_shift);
        unsigned int retry_count;
        int ret = 0;
 
-       if (rmobile_pd->bit_shift == ~0)
-               return 0;
-
-       mask = BIT(rmobile_pd->bit_shift);
        if (__raw_readl(rmobile_pd->base + PSTR) & mask)
                return ret;
 
@@ -122,11 +114,15 @@ static void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd)
        struct dev_power_governor *gov = rmobile_pd->gov;
 
        genpd->flags |= GENPD_FLAG_PM_CLK | GENPD_FLAG_ACTIVE_WAKEUP;
-       genpd->power_off                = rmobile_pd_power_down;
-       genpd->power_on                 = rmobile_pd_power_up;
-       genpd->attach_dev               = cpg_mstp_attach_dev;
-       genpd->detach_dev               = cpg_mstp_detach_dev;
-       __rmobile_pd_power_up(rmobile_pd);
+       genpd->attach_dev = cpg_mstp_attach_dev;
+       genpd->detach_dev = cpg_mstp_detach_dev;
+
+       if (!(genpd->flags & GENPD_FLAG_ALWAYS_ON)) {
+               genpd->power_off = rmobile_pd_power_down;
+               genpd->power_on = rmobile_pd_power_up;
+               __rmobile_pd_power_up(rmobile_pd);
+       }
+
        pm_genpd_init(genpd, gov ? : &simple_qos_governor, false);
 }
 
@@ -270,6 +266,11 @@ static void __init rmobile_setup_pm_domain(struct device_node *np,
                break;
 
        case PD_NORMAL:
+               if (pd->bit_shift == ~0) {
+                       /* Top-level always-on domain */
+                       pr_debug("PM domain %s is always-on domain\n", name);
+                       pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON;
+               }
                break;
        }
 
index 2186285..33ad0de 100644 (file)
@@ -7,6 +7,12 @@ menuconfig SOC_SAMSUNG
 
 if SOC_SAMSUNG
 
+config EXYNOS_CHIPID
+       bool "Exynos Chipid controller driver" if COMPILE_TEST
+       depends on ARCH_EXYNOS || COMPILE_TEST
+       select MFD_SYSCON
+       select SOC_BUS
+
 config EXYNOS_PMU
        bool "Exynos PMU controller driver" if COMPILE_TEST
        depends on ARCH_EXYNOS || ((ARM || ARM64) && COMPILE_TEST)
index 29f294b..3b6a879 100644 (file)
@@ -1,4 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_EXYNOS_CHIPID)    += exynos-chipid.o
 obj-$(CONFIG_EXYNOS_PMU)       += exynos-pmu.o
 
 obj-$(CONFIG_EXYNOS_PMU_ARM_DRIVERS)   += exynos3250-pmu.o exynos4-pmu.o \
diff --git a/drivers/soc/samsung/exynos-chipid.c b/drivers/soc/samsung/exynos-chipid.c
new file mode 100644 (file)
index 0000000..c55a47c
--- /dev/null
@@ -0,0 +1,105 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *           http://www.samsung.com/
+ *
+ * EXYNOS - CHIP ID support
+ * Author: Pankaj Dubey <pankaj.dubey@samsung.com>
+ * Author: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
+ */
+
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/soc/samsung/exynos-chipid.h>
+#include <linux/sys_soc.h>
+
+static const struct exynos_soc_id {
+       const char *name;
+       unsigned int id;
+} soc_ids[] = {
+       { "EXYNOS3250", 0xE3472000 },
+       { "EXYNOS4210", 0x43200000 },   /* EVT0 revision */
+       { "EXYNOS4210", 0x43210000 },
+       { "EXYNOS4212", 0x43220000 },
+       { "EXYNOS4412", 0xE4412000 },
+       { "EXYNOS5250", 0x43520000 },
+       { "EXYNOS5260", 0xE5260000 },
+       { "EXYNOS5410", 0xE5410000 },
+       { "EXYNOS5420", 0xE5420000 },
+       { "EXYNOS5440", 0xE5440000 },
+       { "EXYNOS5800", 0xE5422000 },
+       { "EXYNOS7420", 0xE7420000 },
+       { "EXYNOS5433", 0xE5433000 },
+};
+
+static const char * __init product_id_to_soc_id(unsigned int product_id)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(soc_ids); i++)
+               if ((product_id & EXYNOS_MASK) == soc_ids[i].id)
+                       return soc_ids[i].name;
+       return NULL;
+}
+
+int __init exynos_chipid_early_init(void)
+{
+       struct soc_device_attribute *soc_dev_attr;
+       struct soc_device *soc_dev;
+       struct device_node *root;
+       struct regmap *regmap;
+       u32 product_id;
+       u32 revision;
+       int ret;
+
+       regmap = syscon_regmap_lookup_by_compatible("samsung,exynos4210-chipid");
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       ret = regmap_read(regmap, EXYNOS_CHIPID_REG_PRO_ID, &product_id);
+       if (ret < 0)
+               return ret;
+
+       revision = product_id & EXYNOS_REV_MASK;
+
+       soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
+       if (!soc_dev_attr)
+               return -ENOMEM;
+
+       soc_dev_attr->family = "Samsung Exynos";
+
+       root = of_find_node_by_path("/");
+       of_property_read_string(root, "model", &soc_dev_attr->machine);
+       of_node_put(root);
+
+       soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%x", revision);
+       soc_dev_attr->soc_id = product_id_to_soc_id(product_id);
+       if (!soc_dev_attr->soc_id) {
+               pr_err("Unknown SoC\n");
+               ret = -ENODEV;
+               goto err;
+       }
+
+       /* please note that the actual registration will be deferred */
+       soc_dev = soc_device_register(soc_dev_attr);
+       if (IS_ERR(soc_dev)) {
+               ret = PTR_ERR(soc_dev);
+               goto err;
+       }
+
+       /* it is too early to use dev_info() here (soc_dev is NULL) */
+       pr_info("soc soc0: Exynos: CPU[%s] PRO_ID[0x%x] REV[0x%x] Detected\n",
+               soc_dev_attr->soc_id, product_id, revision);
+
+       return 0;
+
+err:
+       kfree(soc_dev_attr->revision);
+       kfree(soc_dev_attr);
+       return ret;
+}
+
+early_initcall(exynos_chipid_early_init);
index 97817dd..8c2a2f2 100644 (file)
 #include <linux/pm_domain.h>
 #include <linux/slab.h>
 #include <linux/soc/ti/ti_sci_protocol.h>
+#include <dt-bindings/soc/ti,sci_pm_domain.h>
 
 /**
  * struct ti_sci_genpd_dev_data: holds data needed for every device attached
  *                              to this genpd
  * @idx: index of the device that identifies it with the system
  *      control processor.
+ * @exclusive: Permissions for exclusive request or shared request of the
+ *            device.
  */
 struct ti_sci_genpd_dev_data {
        int idx;
+       u8 exclusive;
 };
 
 /**
@@ -55,6 +59,14 @@ static int ti_sci_dev_id(struct device *dev)
        return sci_dev_data->idx;
 }
 
+static u8 is_ti_sci_dev_exclusive(struct device *dev)
+{
+       struct generic_pm_domain_data *genpd_data = dev_gpd_data(dev);
+       struct ti_sci_genpd_dev_data *sci_dev_data = genpd_data->data;
+
+       return sci_dev_data->exclusive;
+}
+
 /**
  * ti_sci_dev_to_sci_handle(): get pointer to ti_sci_handle
  * @dev: pointer to device associated with this genpd
@@ -79,7 +91,10 @@ static int ti_sci_dev_start(struct device *dev)
        const struct ti_sci_handle *ti_sci = ti_sci_dev_to_sci_handle(dev);
        int idx = ti_sci_dev_id(dev);
 
-       return ti_sci->ops.dev_ops.get_device(ti_sci, idx);
+       if (is_ti_sci_dev_exclusive(dev))
+               return ti_sci->ops.dev_ops.get_device_exclusive(ti_sci, idx);
+       else
+               return ti_sci->ops.dev_ops.get_device(ti_sci, idx);
 }
 
 /**
@@ -110,7 +125,7 @@ static int ti_sci_pd_attach_dev(struct generic_pm_domain *domain,
        if (ret < 0)
                return ret;
 
-       if (pd_args.args_count != 1)
+       if (pd_args.args_count != 1 && pd_args.args_count != 2)
                return -EINVAL;
 
        idx = pd_args.args[0];
@@ -128,6 +143,10 @@ static int ti_sci_pd_attach_dev(struct generic_pm_domain *domain,
                return -ENOMEM;
 
        sci_dev_data->idx = idx;
+       /* Enable the exclusive permissions by default */
+       sci_dev_data->exclusive = TI_SCI_PD_EXCLUSIVE;
+       if (pd_args.args_count == 2)
+               sci_dev_data->exclusive = pd_args.args[1] & 0x1;
 
        genpd_data = dev_gpd_data(dev);
        genpd_data->data = sci_dev_data;
index 6ee514f..0f0fdb5 100644 (file)
@@ -450,13 +450,6 @@ config SPI_NPCM_PSPI
          This driver provides support for Nuvoton NPCM BMC
          Peripheral SPI controller in master mode.
 
-config SPI_NUC900
-       tristate "Nuvoton NUC900 series SPI"
-       depends on ARCH_W90X900
-       select SPI_BITBANG
-       help
-         SPI driver for Nuvoton NUC900 series ARM SoCs
-
 config SPI_LANTIQ_SSC
        tristate "Lantiq SSC SPI controller"
        depends on LANTIQ || COMPILE_TEST
index adbebee..bb49c9e 100644 (file)
@@ -65,7 +65,6 @@ obj-$(CONFIG_SPI_MXIC)                        += spi-mxic.o
 obj-$(CONFIG_SPI_MXS)                  += spi-mxs.o
 obj-$(CONFIG_SPI_NPCM_FIU)             += spi-npcm-fiu.o
 obj-$(CONFIG_SPI_NPCM_PSPI)            += spi-npcm-pspi.o
-obj-$(CONFIG_SPI_NUC900)               += spi-nuc900.o
 obj-$(CONFIG_SPI_NXP_FLEXSPI)          += spi-nxp-fspi.o
 obj-$(CONFIG_SPI_OC_TINY)              += spi-oc-tiny.o
 spi-octeon-objs                                := spi-cavium.o spi-cavium-octeon.o
diff --git a/drivers/spi/spi-nuc900.c b/drivers/spi/spi-nuc900.c
deleted file mode 100644 (file)
index 6140035..0000000
+++ /dev/null
@@ -1,426 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (c) 2009 Nuvoton technology.
- * Wan ZongShun <mcuos.com@gmail.com>
- */
-
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-
-#include <linux/spi/spi.h>
-#include <linux/spi/spi_bitbang.h>
-
-#include <linux/platform_data/spi-nuc900.h>
-
-/* usi registers offset */
-#define USI_CNT                0x00
-#define USI_DIV                0x04
-#define USI_SSR                0x08
-#define USI_RX0                0x10
-#define USI_TX0                0x10
-
-/* usi register bit */
-#define ENINT          (0x01 << 17)
-#define ENFLG          (0x01 << 16)
-#define SLEEP          (0x0f << 12)
-#define TXNUM          (0x03 << 8)
-#define TXBITLEN       (0x1f << 3)
-#define TXNEG          (0x01 << 2)
-#define RXNEG          (0x01 << 1)
-#define LSB            (0x01 << 10)
-#define SELECTLEV      (0x01 << 2)
-#define SELECTPOL      (0x01 << 31)
-#define SELECTSLAVE    0x01
-#define GOBUSY         0x01
-
-struct nuc900_spi {
-       struct spi_bitbang       bitbang;
-       struct completion        done;
-       void __iomem            *regs;
-       int                      irq;
-       int                      len;
-       int                      count;
-       const unsigned char     *tx;
-       unsigned char           *rx;
-       struct clk              *clk;
-       struct spi_master       *master;
-       struct nuc900_spi_info *pdata;
-       spinlock_t              lock;
-};
-
-static inline struct nuc900_spi *to_hw(struct spi_device *sdev)
-{
-       return spi_master_get_devdata(sdev->master);
-}
-
-static void nuc900_slave_select(struct spi_device *spi, unsigned int ssr)
-{
-       struct nuc900_spi *hw = to_hw(spi);
-       unsigned int val;
-       unsigned int cs = spi->mode & SPI_CS_HIGH ? 1 : 0;
-       unsigned int cpol = spi->mode & SPI_CPOL ? 1 : 0;
-       unsigned long flags;
-
-       spin_lock_irqsave(&hw->lock, flags);
-
-       val = __raw_readl(hw->regs + USI_SSR);
-
-       if (!cs)
-               val &= ~SELECTLEV;
-       else
-               val |= SELECTLEV;
-
-       if (!ssr)
-               val &= ~SELECTSLAVE;
-       else
-               val |= SELECTSLAVE;
-
-       __raw_writel(val, hw->regs + USI_SSR);
-
-       val = __raw_readl(hw->regs + USI_CNT);
-
-       if (!cpol)
-               val &= ~SELECTPOL;
-       else
-               val |= SELECTPOL;
-
-       __raw_writel(val, hw->regs + USI_CNT);
-
-       spin_unlock_irqrestore(&hw->lock, flags);
-}
-
-static void nuc900_spi_chipsel(struct spi_device *spi, int value)
-{
-       switch (value) {
-       case BITBANG_CS_INACTIVE:
-               nuc900_slave_select(spi, 0);
-               break;
-
-       case BITBANG_CS_ACTIVE:
-               nuc900_slave_select(spi, 1);
-               break;
-       }
-}
-
-static void nuc900_spi_setup_txnum(struct nuc900_spi *hw, unsigned int txnum)
-{
-       unsigned int val;
-       unsigned long flags;
-
-       spin_lock_irqsave(&hw->lock, flags);
-
-       val = __raw_readl(hw->regs + USI_CNT) & ~TXNUM;
-
-       if (txnum)
-               val |= txnum << 0x08;
-
-       __raw_writel(val, hw->regs + USI_CNT);
-
-       spin_unlock_irqrestore(&hw->lock, flags);
-
-}
-
-static void nuc900_spi_setup_txbitlen(struct nuc900_spi *hw,
-                                                       unsigned int txbitlen)
-{
-       unsigned int val;
-       unsigned long flags;
-
-       spin_lock_irqsave(&hw->lock, flags);
-
-       val = __raw_readl(hw->regs + USI_CNT) & ~TXBITLEN;
-
-       val |= (txbitlen << 0x03);
-
-       __raw_writel(val, hw->regs + USI_CNT);
-
-       spin_unlock_irqrestore(&hw->lock, flags);
-}
-
-static void nuc900_spi_gobusy(struct nuc900_spi *hw)
-{
-       unsigned int val;
-       unsigned long flags;
-
-       spin_lock_irqsave(&hw->lock, flags);
-
-       val = __raw_readl(hw->regs + USI_CNT);
-
-       val |= GOBUSY;
-
-       __raw_writel(val, hw->regs + USI_CNT);
-
-       spin_unlock_irqrestore(&hw->lock, flags);
-}
-
-static inline unsigned int hw_txbyte(struct nuc900_spi *hw, int count)
-{
-       return hw->tx ? hw->tx[count] : 0;
-}
-
-static int nuc900_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
-{
-       struct nuc900_spi *hw = to_hw(spi);
-
-       hw->tx = t->tx_buf;
-       hw->rx = t->rx_buf;
-       hw->len = t->len;
-       hw->count = 0;
-
-       __raw_writel(hw_txbyte(hw, 0x0), hw->regs + USI_TX0);
-
-       nuc900_spi_gobusy(hw);
-
-       wait_for_completion(&hw->done);
-
-       return hw->count;
-}
-
-static irqreturn_t nuc900_spi_irq(int irq, void *dev)
-{
-       struct nuc900_spi *hw = dev;
-       unsigned int status;
-       unsigned int count = hw->count;
-
-       status = __raw_readl(hw->regs + USI_CNT);
-       __raw_writel(status, hw->regs + USI_CNT);
-
-       if (status & ENFLG) {
-               hw->count++;
-
-               if (hw->rx)
-                       hw->rx[count] = __raw_readl(hw->regs + USI_RX0);
-               count++;
-
-               if (count < hw->len) {
-                       __raw_writel(hw_txbyte(hw, count), hw->regs + USI_TX0);
-                       nuc900_spi_gobusy(hw);
-               } else {
-                       complete(&hw->done);
-               }
-
-               return IRQ_HANDLED;
-       }
-
-       complete(&hw->done);
-       return IRQ_HANDLED;
-}
-
-static void nuc900_tx_edge(struct nuc900_spi *hw, unsigned int edge)
-{
-       unsigned int val;
-       unsigned long flags;
-
-       spin_lock_irqsave(&hw->lock, flags);
-
-       val = __raw_readl(hw->regs + USI_CNT);
-
-       if (edge)
-               val |= TXNEG;
-       else
-               val &= ~TXNEG;
-       __raw_writel(val, hw->regs + USI_CNT);
-
-       spin_unlock_irqrestore(&hw->lock, flags);
-}
-
-static void nuc900_rx_edge(struct nuc900_spi *hw, unsigned int edge)
-{
-       unsigned int val;
-       unsigned long flags;
-
-       spin_lock_irqsave(&hw->lock, flags);
-
-       val = __raw_readl(hw->regs + USI_CNT);
-
-       if (edge)
-               val |= RXNEG;
-       else
-               val &= ~RXNEG;
-       __raw_writel(val, hw->regs + USI_CNT);
-
-       spin_unlock_irqrestore(&hw->lock, flags);
-}
-
-static void nuc900_send_first(struct nuc900_spi *hw, unsigned int lsb)
-{
-       unsigned int val;
-       unsigned long flags;
-
-       spin_lock_irqsave(&hw->lock, flags);
-
-       val = __raw_readl(hw->regs + USI_CNT);
-
-       if (lsb)
-               val |= LSB;
-       else
-               val &= ~LSB;
-       __raw_writel(val, hw->regs + USI_CNT);
-
-       spin_unlock_irqrestore(&hw->lock, flags);
-}
-
-static void nuc900_set_sleep(struct nuc900_spi *hw, unsigned int sleep)
-{
-       unsigned int val;
-       unsigned long flags;
-
-       spin_lock_irqsave(&hw->lock, flags);
-
-       val = __raw_readl(hw->regs + USI_CNT) & ~SLEEP;
-
-       if (sleep)
-               val |= (sleep << 12);
-
-       __raw_writel(val, hw->regs + USI_CNT);
-
-       spin_unlock_irqrestore(&hw->lock, flags);
-}
-
-static void nuc900_enable_int(struct nuc900_spi *hw)
-{
-       unsigned int val;
-       unsigned long flags;
-
-       spin_lock_irqsave(&hw->lock, flags);
-
-       val = __raw_readl(hw->regs + USI_CNT);
-
-       val |= ENINT;
-
-       __raw_writel(val, hw->regs + USI_CNT);
-
-       spin_unlock_irqrestore(&hw->lock, flags);
-}
-
-static void nuc900_set_divider(struct nuc900_spi *hw)
-{
-       __raw_writel(hw->pdata->divider, hw->regs + USI_DIV);
-}
-
-static void nuc900_init_spi(struct nuc900_spi *hw)
-{
-       clk_enable(hw->clk);
-       spin_lock_init(&hw->lock);
-
-       nuc900_tx_edge(hw, hw->pdata->txneg);
-       nuc900_rx_edge(hw, hw->pdata->rxneg);
-       nuc900_send_first(hw, hw->pdata->lsb);
-       nuc900_set_sleep(hw, hw->pdata->sleep);
-       nuc900_spi_setup_txbitlen(hw, hw->pdata->txbitlen);
-       nuc900_spi_setup_txnum(hw, hw->pdata->txnum);
-       nuc900_set_divider(hw);
-       nuc900_enable_int(hw);
-}
-
-static int nuc900_spi_probe(struct platform_device *pdev)
-{
-       struct nuc900_spi *hw;
-       struct spi_master *master;
-       int err = 0;
-
-       master = spi_alloc_master(&pdev->dev, sizeof(struct nuc900_spi));
-       if (master == NULL) {
-               dev_err(&pdev->dev, "No memory for spi_master\n");
-               return -ENOMEM;
-       }
-
-       hw = spi_master_get_devdata(master);
-       hw->master = master;
-       hw->pdata  = dev_get_platdata(&pdev->dev);
-
-       if (hw->pdata == NULL) {
-               dev_err(&pdev->dev, "No platform data supplied\n");
-               err = -ENOENT;
-               goto err_pdata;
-       }
-
-       platform_set_drvdata(pdev, hw);
-       init_completion(&hw->done);
-
-       master->mode_bits          = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
-       if (hw->pdata->lsb)
-               master->mode_bits |= SPI_LSB_FIRST;
-       master->num_chipselect     = hw->pdata->num_cs;
-       master->bus_num            = hw->pdata->bus_num;
-       hw->bitbang.master         = hw->master;
-       hw->bitbang.chipselect     = nuc900_spi_chipsel;
-       hw->bitbang.txrx_bufs      = nuc900_spi_txrx;
-
-       hw->regs = devm_platform_ioremap_resource(pdev, 0);
-       if (IS_ERR(hw->regs)) {
-               err = PTR_ERR(hw->regs);
-               goto err_pdata;
-       }
-
-       hw->irq = platform_get_irq(pdev, 0);
-       if (hw->irq < 0) {
-               err = -ENOENT;
-               goto err_pdata;
-       }
-
-       err = devm_request_irq(&pdev->dev, hw->irq, nuc900_spi_irq, 0,
-                               pdev->name, hw);
-       if (err) {
-               dev_err(&pdev->dev, "Cannot claim IRQ\n");
-               goto err_pdata;
-       }
-
-       hw->clk = devm_clk_get(&pdev->dev, "spi");
-       if (IS_ERR(hw->clk)) {
-               dev_err(&pdev->dev, "No clock for device\n");
-               err = PTR_ERR(hw->clk);
-               goto err_pdata;
-       }
-
-       mfp_set_groupg(&pdev->dev, NULL);
-       nuc900_init_spi(hw);
-
-       err = spi_bitbang_start(&hw->bitbang);
-       if (err) {
-               dev_err(&pdev->dev, "Failed to register SPI master\n");
-               goto err_register;
-       }
-
-       return 0;
-
-err_register:
-       clk_disable(hw->clk);
-err_pdata:
-       spi_master_put(hw->master);
-       return err;
-}
-
-static int nuc900_spi_remove(struct platform_device *dev)
-{
-       struct nuc900_spi *hw = platform_get_drvdata(dev);
-
-       spi_bitbang_stop(&hw->bitbang);
-       clk_disable(hw->clk);
-       spi_master_put(hw->master);
-       return 0;
-}
-
-static struct platform_driver nuc900_spi_driver = {
-       .probe          = nuc900_spi_probe,
-       .remove         = nuc900_spi_remove,
-       .driver         = {
-               .name   = "nuc900-spi",
-       },
-};
-module_platform_driver(nuc900_spi_driver);
-
-MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
-MODULE_DESCRIPTION("nuc900 spi driver!");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:nuc900-spi");
index aa94270..13b0269 100644 (file)
@@ -148,6 +148,7 @@ u32 optee_do_call_with_arg(struct tee_context *ctx, phys_addr_t parg)
                         */
                        optee_cq_wait_for_completion(&optee->call_queue, &w);
                } else if (OPTEE_SMC_RETURN_IS_RPC(res.a0)) {
+                       might_sleep();
                        param.a0 = res.a0;
                        param.a1 = res.a1;
                        param.a2 = res.a2;
index 6b2de93..5f83cd7 100644 (file)
@@ -1924,20 +1924,6 @@ config FB_S3C2410_DEBUG
          Turn on debugging messages. Note that you can set/unset at run time
          through sysfs
 
-config FB_NUC900
-       tristate "NUC900 LCD framebuffer support"
-       depends on FB && ARCH_W90X900
-       select FB_CFB_FILLRECT
-       select FB_CFB_COPYAREA
-       select FB_CFB_IMAGEBLIT
-       ---help---
-         Frame buffer driver for the built-in LCD controller in the Nuvoton
-         NUC900 processor
-
-config GPM1040A0_320X240
-       bool "Giantplus Technology GPM1040A0 320x240 Color TFT LCD"
-       depends on FB_NUC900
-
 config FB_SM501
        tristate "Silicon Motion SM501 framebuffer support"
        depends on FB && MFD_SM501
index 7dc4861..aab7155 100644 (file)
@@ -116,7 +116,6 @@ obj-y                             += omap2/
 obj-$(CONFIG_XEN_FBDEV_FRONTEND)  += xen-fbfront.o
 obj-$(CONFIG_FB_CARMINE)          += carminefb.o
 obj-$(CONFIG_FB_MB862XX)         += mb862xx/
-obj-$(CONFIG_FB_NUC900)           += nuc900fb.o
 obj-$(CONFIG_FB_JZ4740)                  += jz4740_fb.o
 obj-$(CONFIG_FB_PUV3_UNIGFX)      += fb-puv3.o
 obj-$(CONFIG_FB_HYPERV)                  += hyperv_fb.o
index b1cf248..2d3dcc5 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/clk.h>
 #include <linux/cpufreq.h>
 #include <linux/console.h>
+#include <linux/regulator/consumer.h>
 #include <linux/spinlock.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
@@ -164,7 +165,7 @@ struct da8xx_fb_par {
        struct notifier_block   freq_transition;
 #endif
        unsigned int            lcdc_clk_rate;
-       void (*panel_power_ctrl)(int);
+       struct regulator        *lcd_supply;
        u32 pseudo_palette[16];
        struct fb_videomode     mode;
        struct lcd_ctrl_config  cfg;
@@ -1066,33 +1067,30 @@ static void lcd_da8xx_cpufreq_deregister(struct da8xx_fb_par *par)
 static int fb_remove(struct platform_device *dev)
 {
        struct fb_info *info = dev_get_drvdata(&dev->dev);
-
-       if (info) {
-               struct da8xx_fb_par *par = info->par;
+       struct da8xx_fb_par *par = info->par;
+       int ret;
 
 #ifdef CONFIG_CPU_FREQ
-               lcd_da8xx_cpufreq_deregister(par);
+       lcd_da8xx_cpufreq_deregister(par);
 #endif
-               if (par->panel_power_ctrl)
-                       par->panel_power_ctrl(0);
+       if (par->lcd_supply) {
+               ret = regulator_disable(par->lcd_supply);
+               if (ret)
+                       return ret;
+       }
 
-               lcd_disable_raster(DA8XX_FRAME_WAIT);
-               lcdc_write(0, LCD_RASTER_CTRL_REG);
+       lcd_disable_raster(DA8XX_FRAME_WAIT);
+       lcdc_write(0, LCD_RASTER_CTRL_REG);
 
-               /* disable DMA  */
-               lcdc_write(0, LCD_DMA_CTRL_REG);
+       /* disable DMA  */
+       lcdc_write(0, LCD_DMA_CTRL_REG);
 
-               unregister_framebuffer(info);
-               fb_dealloc_cmap(&info->cmap);
-               dma_free_coherent(par->dev, PALETTE_SIZE, par->v_palette_base,
-                                 par->p_palette_base);
-               dma_free_coherent(par->dev, par->vram_size, par->vram_virt,
-                                 par->vram_phys);
-               pm_runtime_put_sync(&dev->dev);
-               pm_runtime_disable(&dev->dev);
-               framebuffer_release(info);
+       unregister_framebuffer(info);
+       fb_dealloc_cmap(&info->cmap);
+       pm_runtime_put_sync(&dev->dev);
+       pm_runtime_disable(&dev->dev);
+       framebuffer_release(info);
 
-       }
        return 0;
 }
 
@@ -1179,15 +1177,21 @@ static int cfb_blank(int blank, struct fb_info *info)
        case FB_BLANK_UNBLANK:
                lcd_enable_raster();
 
-               if (par->panel_power_ctrl)
-                       par->panel_power_ctrl(1);
+               if (par->lcd_supply) {
+                       ret = regulator_enable(par->lcd_supply);
+                       if (ret)
+                               return ret;
+               }
                break;
        case FB_BLANK_NORMAL:
        case FB_BLANK_VSYNC_SUSPEND:
        case FB_BLANK_HSYNC_SUSPEND:
        case FB_BLANK_POWERDOWN:
-               if (par->panel_power_ctrl)
-                       par->panel_power_ctrl(0);
+               if (par->lcd_supply) {
+                       ret = regulator_disable(par->lcd_supply);
+                       if (ret)
+                               return ret;
+               }
 
                lcd_disable_raster(DA8XX_FRAME_WAIT);
                break;
@@ -1328,7 +1332,6 @@ static int fb_probe(struct platform_device *device)
 {
        struct da8xx_lcdc_platform_data *fb_pdata =
                                                dev_get_platdata(&device->dev);
-       struct resource *lcdc_regs;
        struct lcd_ctrl_config *lcd_cfg;
        struct fb_videomode *lcdc_info;
        struct fb_info *da8xx_fb_info;
@@ -1346,8 +1349,7 @@ static int fb_probe(struct platform_device *device)
        if (lcdc_info == NULL)
                return -ENODEV;
 
-       lcdc_regs = platform_get_resource(device, IORESOURCE_MEM, 0);
-       da8xx_fb_reg_base = devm_ioremap_resource(&device->dev, lcdc_regs);
+       da8xx_fb_reg_base = devm_platform_ioremap_resource(device, 0);
        if (IS_ERR(da8xx_fb_reg_base))
                return PTR_ERR(da8xx_fb_reg_base);
 
@@ -1395,9 +1397,19 @@ static int fb_probe(struct platform_device *device)
        par->dev = &device->dev;
        par->lcdc_clk = tmp_lcdc_clk;
        par->lcdc_clk_rate = clk_get_rate(par->lcdc_clk);
-       if (fb_pdata->panel_power_ctrl) {
-               par->panel_power_ctrl = fb_pdata->panel_power_ctrl;
-               par->panel_power_ctrl(1);
+
+       par->lcd_supply = devm_regulator_get_optional(&device->dev, "lcd");
+       if (IS_ERR(par->lcd_supply)) {
+               if (PTR_ERR(par->lcd_supply) == -EPROBE_DEFER) {
+                       ret = -EPROBE_DEFER;
+                       goto err_pm_runtime_disable;
+               }
+
+               par->lcd_supply = NULL;
+       } else {
+               ret = regulator_enable(par->lcd_supply);
+               if (ret)
+                       goto err_pm_runtime_disable;
        }
 
        fb_videomode_to_var(&da8xx_fb_var, lcdc_info);
@@ -1411,10 +1423,10 @@ static int fb_probe(struct platform_device *device)
        par->vram_size = roundup(par->vram_size/8, ulcm);
        par->vram_size = par->vram_size * LCD_NUM_BUFFERS;
 
-       par->vram_virt = dma_alloc_coherent(par->dev,
-                                           par->vram_size,
-                                           &par->vram_phys,
-                                           GFP_KERNEL | GFP_DMA);
+       par->vram_virt = dmam_alloc_coherent(par->dev,
+                                            par->vram_size,
+                                            &par->vram_phys,
+                                            GFP_KERNEL | GFP_DMA);
        if (!par->vram_virt) {
                dev_err(&device->dev,
                        "GLCD: kmalloc for frame buffer failed\n");
@@ -1432,20 +1444,20 @@ static int fb_probe(struct platform_device *device)
                da8xx_fb_fix.line_length - 1;
 
        /* allocate palette buffer */
-       par->v_palette_base = dma_alloc_coherent(par->dev, PALETTE_SIZE,
-                                                &par->p_palette_base,
-                                                GFP_KERNEL | GFP_DMA);
+       par->v_palette_base = dmam_alloc_coherent(par->dev, PALETTE_SIZE,
+                                                 &par->p_palette_base,
+                                                 GFP_KERNEL | GFP_DMA);
        if (!par->v_palette_base) {
                dev_err(&device->dev,
                        "GLCD: kmalloc for palette buffer failed\n");
                ret = -EINVAL;
-               goto err_release_fb_mem;
+               goto err_release_fb;
        }
 
        par->irq = platform_get_irq(device, 0);
        if (par->irq < 0) {
                ret = -ENOENT;
-               goto err_release_pl_mem;
+               goto err_release_fb;
        }
 
        da8xx_fb_var.grayscale =
@@ -1463,7 +1475,7 @@ static int fb_probe(struct platform_device *device)
 
        ret = fb_alloc_cmap(&da8xx_fb_info->cmap, PALETTE_SIZE, 0);
        if (ret)
-               goto err_release_pl_mem;
+               goto err_release_fb;
        da8xx_fb_info->cmap.len = par->palette_sz;
 
        /* initialize var_screeninfo */
@@ -1517,14 +1529,6 @@ err_cpu_freq:
 err_dealloc_cmap:
        fb_dealloc_cmap(&da8xx_fb_info->cmap);
 
-err_release_pl_mem:
-       dma_free_coherent(par->dev, PALETTE_SIZE, par->v_palette_base,
-                         par->p_palette_base);
-
-err_release_fb_mem:
-       dma_free_coherent(par->dev, par->vram_size, par->vram_virt,
-                         par->vram_phys);
-
 err_release_fb:
        framebuffer_release(da8xx_fb_info);
 
@@ -1603,10 +1607,14 @@ static int fb_suspend(struct device *dev)
 {
        struct fb_info *info = dev_get_drvdata(dev);
        struct da8xx_fb_par *par = info->par;
+       int ret;
 
        console_lock();
-       if (par->panel_power_ctrl)
-               par->panel_power_ctrl(0);
+       if (par->lcd_supply) {
+               ret = regulator_disable(par->lcd_supply);
+               if (ret)
+                       return ret;
+       }
 
        fb_set_suspend(info, 1);
        lcd_disable_raster(DA8XX_FRAME_WAIT);
@@ -1620,6 +1628,7 @@ static int fb_resume(struct device *dev)
 {
        struct fb_info *info = dev_get_drvdata(dev);
        struct da8xx_fb_par *par = info->par;
+       int ret;
 
        console_lock();
        pm_runtime_get_sync(dev);
@@ -1627,8 +1636,11 @@ static int fb_resume(struct device *dev)
        if (par->blank == FB_BLANK_UNBLANK) {
                lcd_enable_raster();
 
-               if (par->panel_power_ctrl)
-                       par->panel_power_ctrl(1);
+               if (par->lcd_supply) {
+                       ret = regulator_enable(par->lcd_supply);
+                       if (ret)
+                               return ret;
+               }
        }
 
        fb_set_suspend(info, 0);
diff --git a/drivers/video/fbdev/nuc900fb.c b/drivers/video/fbdev/nuc900fb.c
deleted file mode 100644 (file)
index 4fd8515..0000000
+++ /dev/null
@@ -1,760 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * Copyright (c) 2009 Nuvoton technology corporation
- * All rights reserved.
- *
- *  Description:
- *    Nuvoton LCD Controller Driver
- *  Author:
- *    Wang Qiang (rurality.linux@gmail.com) 2009/12/11
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/err.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/fb.h>
-#include <linux/init.h>
-#include <linux/dma-mapping.h>
-#include <linux/interrupt.h>
-#include <linux/workqueue.h>
-#include <linux/wait.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/cpufreq.h>
-#include <linux/io.h>
-#include <linux/pm.h>
-#include <linux/device.h>
-
-#include <mach/map.h>
-#include <mach/regs-clock.h>
-#include <mach/regs-ldm.h>
-#include <linux/platform_data/video-nuc900fb.h>
-
-#include "nuc900fb.h"
-
-
-/*
- *  Initialize the nuc900 video (dual) buffer address
- */
-static void nuc900fb_set_lcdaddr(struct fb_info *info)
-{
-       struct nuc900fb_info *fbi = info->par;
-       void __iomem *regs = fbi->io;
-       unsigned long vbaddr1, vbaddr2;
-
-       vbaddr1  = info->fix.smem_start;
-       vbaddr2  = info->fix.smem_start;
-       vbaddr2 += info->fix.line_length * info->var.yres;
-
-       /* set frambuffer start phy addr*/
-       writel(vbaddr1, regs + REG_LCM_VA_BADDR0);
-       writel(vbaddr2, regs + REG_LCM_VA_BADDR1);
-
-       writel(fbi->regs.lcd_va_fbctrl, regs + REG_LCM_VA_FBCTRL);
-       writel(fbi->regs.lcd_va_scale, regs + REG_LCM_VA_SCALE);
-}
-
-/*
- *     calculate divider for lcd div
- */
-static unsigned int nuc900fb_calc_pixclk(struct nuc900fb_info *fbi,
-                                        unsigned long pixclk)
-{
-       unsigned long clk = fbi->clk_rate;
-       unsigned long long div;
-
-       /* pixclk is in picseconds. our clock is in Hz*/
-       /* div = (clk * pixclk)/10^12 */
-       div = (unsigned long long)clk * pixclk;
-       div >>= 12;
-       do_div(div, 625 * 625UL * 625);
-
-       dev_dbg(fbi->dev, "pixclk %ld, divisor is %lld\n", pixclk, div);
-
-       return div;
-}
-
-/*
- *     Check the video params of 'var'.
- */
-static int nuc900fb_check_var(struct fb_var_screeninfo *var,
-                              struct fb_info *info)
-{
-       struct nuc900fb_info *fbi = info->par;
-       struct nuc900fb_mach_info *mach_info = dev_get_platdata(fbi->dev);
-       struct nuc900fb_display *display = NULL;
-       struct nuc900fb_display *default_display = mach_info->displays +
-                                                  mach_info->default_display;
-       int i;
-
-       dev_dbg(fbi->dev, "check_var(var=%p, info=%p)\n", var, info);
-
-       /* validate x/y resolution */
-       /* choose default mode if possible */
-       if (var->xres == default_display->xres &&
-           var->yres == default_display->yres &&
-           var->bits_per_pixel == default_display->bpp)
-               display = default_display;
-       else
-               for (i = 0; i < mach_info->num_displays; i++)
-                       if (var->xres == mach_info->displays[i].xres &&
-                           var->yres == mach_info->displays[i].yres &&
-                           var->bits_per_pixel == mach_info->displays[i].bpp) {
-                               display = mach_info->displays + i;
-                               break;
-                       }
-
-       if (display == NULL) {
-               printk(KERN_ERR "wrong resolution or depth %dx%d at %d bit per pixel\n",
-                       var->xres, var->yres, var->bits_per_pixel);
-               return -EINVAL;
-       }
-
-       /* it should be the same size as the display */
-       var->xres_virtual       = display->xres;
-       var->yres_virtual       = display->yres;
-       var->height             = display->height;
-       var->width              = display->width;
-
-       /* copy lcd settings */
-       var->pixclock           = display->pixclock;
-       var->left_margin        = display->left_margin;
-       var->right_margin       = display->right_margin;
-       var->upper_margin       = display->upper_margin;
-       var->lower_margin       = display->lower_margin;
-       var->vsync_len          = display->vsync_len;
-       var->hsync_len          = display->hsync_len;
-
-       var->transp.offset      = 0;
-       var->transp.length      = 0;
-
-       fbi->regs.lcd_dccs = display->dccs;
-       fbi->regs.lcd_device_ctrl = display->devctl;
-       fbi->regs.lcd_va_fbctrl = display->fbctrl;
-       fbi->regs.lcd_va_scale = display->scale;
-
-       /* set R/G/B possions */
-       switch (var->bits_per_pixel) {
-       case 1:
-       case 2:
-       case 4:
-       case 8:
-       default:
-               var->red.offset         = 0;
-               var->red.length         = var->bits_per_pixel;
-               var->green              = var->red;
-               var->blue               = var->red;
-               break;
-       case 12:
-               var->red.length         = 4;
-               var->green.length       = 4;
-               var->blue.length        = 4;
-               var->red.offset         = 8;
-               var->green.offset       = 4;
-               var->blue.offset        = 0;
-               break;
-       case 16:
-               var->red.length         = 5;
-               var->green.length       = 6;
-               var->blue.length        = 5;
-               var->red.offset         = 11;
-               var->green.offset       = 5;
-               var->blue.offset        = 0;
-               break;
-       case 18:
-               var->red.length         = 6;
-               var->green.length       = 6;
-               var->blue.length        = 6;
-               var->red.offset         = 12;
-               var->green.offset       = 6;
-               var->blue.offset        = 0;
-               break;
-       case 32:
-               var->red.length         = 8;
-               var->green.length       = 8;
-               var->blue.length        = 8;
-               var->red.offset         = 16;
-               var->green.offset       = 8;
-               var->blue.offset        = 0;
-               break;
-       }
-
-       return 0;
-}
-
-/*
- *     Calculate lcd register values from var setting & save into hw
- */
-static void nuc900fb_calculate_lcd_regs(const struct fb_info *info,
-                                       struct nuc900fb_hw *regs)
-{
-       const struct fb_var_screeninfo *var = &info->var;
-       int vtt = var->height + var->upper_margin + var->lower_margin;
-       int htt = var->width + var->left_margin + var->right_margin;
-       int hsync = var->width + var->right_margin;
-       int vsync = var->height + var->lower_margin;
-
-       regs->lcd_crtc_size = LCM_CRTC_SIZE_VTTVAL(vtt) |
-                             LCM_CRTC_SIZE_HTTVAL(htt);
-       regs->lcd_crtc_dend = LCM_CRTC_DEND_VDENDVAL(var->height) |
-                             LCM_CRTC_DEND_HDENDVAL(var->width);
-       regs->lcd_crtc_hr = LCM_CRTC_HR_EVAL(var->width + 5) |
-                           LCM_CRTC_HR_SVAL(var->width + 1);
-       regs->lcd_crtc_hsync = LCM_CRTC_HSYNC_EVAL(hsync + var->hsync_len) |
-                              LCM_CRTC_HSYNC_SVAL(hsync);
-       regs->lcd_crtc_vr = LCM_CRTC_VR_EVAL(vsync + var->vsync_len) |
-                           LCM_CRTC_VR_SVAL(vsync);
-
-}
-
-/*
- *     Activate (set) the controller from the given framebuffer
- *     information
- */
-static void nuc900fb_activate_var(struct fb_info *info)
-{
-       struct nuc900fb_info *fbi = info->par;
-       void __iomem *regs = fbi->io;
-       struct fb_var_screeninfo *var = &info->var;
-       int clkdiv;
-
-       clkdiv = nuc900fb_calc_pixclk(fbi, var->pixclock) - 1;
-       if (clkdiv < 0)
-               clkdiv = 0;
-
-       nuc900fb_calculate_lcd_regs(info, &fbi->regs);
-
-       /* set the new lcd registers*/
-
-       dev_dbg(fbi->dev, "new lcd register set:\n");
-       dev_dbg(fbi->dev, "dccs       = 0x%08x\n", fbi->regs.lcd_dccs);
-       dev_dbg(fbi->dev, "dev_ctl    = 0x%08x\n", fbi->regs.lcd_device_ctrl);
-       dev_dbg(fbi->dev, "crtc_size  = 0x%08x\n", fbi->regs.lcd_crtc_size);
-       dev_dbg(fbi->dev, "crtc_dend  = 0x%08x\n", fbi->regs.lcd_crtc_dend);
-       dev_dbg(fbi->dev, "crtc_hr    = 0x%08x\n", fbi->regs.lcd_crtc_hr);
-       dev_dbg(fbi->dev, "crtc_hsync = 0x%08x\n", fbi->regs.lcd_crtc_hsync);
-       dev_dbg(fbi->dev, "crtc_vr    = 0x%08x\n", fbi->regs.lcd_crtc_vr);
-
-       writel(fbi->regs.lcd_device_ctrl, regs + REG_LCM_DEV_CTRL);
-       writel(fbi->regs.lcd_crtc_size, regs + REG_LCM_CRTC_SIZE);
-       writel(fbi->regs.lcd_crtc_dend, regs + REG_LCM_CRTC_DEND);
-       writel(fbi->regs.lcd_crtc_hr, regs + REG_LCM_CRTC_HR);
-       writel(fbi->regs.lcd_crtc_hsync, regs + REG_LCM_CRTC_HSYNC);
-       writel(fbi->regs.lcd_crtc_vr, regs + REG_LCM_CRTC_VR);
-
-       /* set lcd address pointers */
-       nuc900fb_set_lcdaddr(info);
-
-       writel(fbi->regs.lcd_dccs, regs + REG_LCM_DCCS);
-}
-
-/*
- *      Alters the hardware state.
- *
- */
-static int nuc900fb_set_par(struct fb_info *info)
-{
-       struct fb_var_screeninfo *var = &info->var;
-
-       switch (var->bits_per_pixel) {
-       case 32:
-       case 24:
-       case 18:
-       case 16:
-       case 12:
-               info->fix.visual = FB_VISUAL_TRUECOLOR;
-               break;
-       case 1:
-               info->fix.visual = FB_VISUAL_MONO01;
-               break;
-       default:
-               info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
-               break;
-       }
-
-       info->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8;
-
-       /* activate this new configuration */
-       nuc900fb_activate_var(info);
-       return 0;
-}
-
-static inline unsigned int chan_to_field(unsigned int chan,
-                                        struct fb_bitfield *bf)
-{
-       chan &= 0xffff;
-       chan >>= 16 - bf->length;
-       return chan << bf->offset;
-}
-
-static int nuc900fb_setcolreg(unsigned regno,
-                              unsigned red, unsigned green, unsigned blue,
-                              unsigned transp, struct fb_info *info)
-{
-       unsigned int val;
-
-       switch (info->fix.visual) {
-       case FB_VISUAL_TRUECOLOR:
-               /* true-colour, use pseuo-palette */
-               if (regno < 16) {
-                       u32 *pal = info->pseudo_palette;
-
-                       val  = chan_to_field(red, &info->var.red);
-                       val |= chan_to_field(green, &info->var.green);
-                       val |= chan_to_field(blue, &info->var.blue);
-                       pal[regno] = val;
-               }
-               break;
-
-       default:
-               return 1;   /* unknown type */
-       }
-       return 0;
-}
-
-/**
- *      nuc900fb_blank
- *
- */
-static int nuc900fb_blank(int blank_mode, struct fb_info *info)
-{
-
-       return 0;
-}
-
-static struct fb_ops nuc900fb_ops = {
-       .owner                  = THIS_MODULE,
-       .fb_check_var           = nuc900fb_check_var,
-       .fb_set_par             = nuc900fb_set_par,
-       .fb_blank               = nuc900fb_blank,
-       .fb_setcolreg           = nuc900fb_setcolreg,
-       .fb_fillrect            = cfb_fillrect,
-       .fb_copyarea            = cfb_copyarea,
-       .fb_imageblit           = cfb_imageblit,
-};
-
-
-static inline void modify_gpio(void __iomem *reg,
-                              unsigned long set, unsigned long mask)
-{
-       unsigned long tmp;
-       tmp = readl(reg) & ~mask;
-       writel(tmp | set, reg);
-}
-
-/*
- * Initialise LCD-related registers
- */
-static int nuc900fb_init_registers(struct fb_info *info)
-{
-       struct nuc900fb_info *fbi = info->par;
-       struct nuc900fb_mach_info *mach_info = dev_get_platdata(fbi->dev);
-       void __iomem *regs = fbi->io;
-
-       /*reset the display engine*/
-       writel(0, regs + REG_LCM_DCCS);
-       writel(readl(regs + REG_LCM_DCCS) | LCM_DCCS_ENG_RST,
-              regs + REG_LCM_DCCS);
-       ndelay(100);
-       writel(readl(regs + REG_LCM_DCCS) & (~LCM_DCCS_ENG_RST),
-              regs + REG_LCM_DCCS);
-       ndelay(100);
-
-       writel(0, regs + REG_LCM_DEV_CTRL);
-
-       /* config gpio output */
-       modify_gpio(W90X900_VA_GPIO + 0x54, mach_info->gpio_dir,
-                   mach_info->gpio_dir_mask);
-       modify_gpio(W90X900_VA_GPIO + 0x58, mach_info->gpio_data,
-                   mach_info->gpio_data_mask);
-
-       return 0;
-}
-
-
-/*
- *    Alloc the SDRAM region of NUC900 for the frame buffer.
- *    The buffer should be a non-cached, non-buffered, memory region
- *    to allow palette and pixel writes without flushing the cache.
- */
-static int nuc900fb_map_video_memory(struct fb_info *info)
-{
-       struct nuc900fb_info *fbi = info->par;
-       dma_addr_t map_dma;
-       unsigned long map_size = PAGE_ALIGN(info->fix.smem_len);
-
-       dev_dbg(fbi->dev, "nuc900fb_map_video_memory(fbi=%p) map_size %lu\n",
-               fbi, map_size);
-
-       info->screen_base = dma_alloc_wc(fbi->dev, map_size, &map_dma,
-                                        GFP_KERNEL);
-
-       if (!info->screen_base)
-               return -ENOMEM;
-
-       memset(info->screen_base, 0x00, map_size);
-       info->fix.smem_start = map_dma;
-
-       return 0;
-}
-
-static inline void nuc900fb_unmap_video_memory(struct fb_info *info)
-{
-       struct nuc900fb_info *fbi = info->par;
-       dma_free_wc(fbi->dev, PAGE_ALIGN(info->fix.smem_len),
-                   info->screen_base, info->fix.smem_start);
-}
-
-static irqreturn_t nuc900fb_irqhandler(int irq, void *dev_id)
-{
-       struct nuc900fb_info *fbi = dev_id;
-       void __iomem *regs = fbi->io;
-       void __iomem *irq_base = fbi->irq_base;
-       unsigned long lcdirq = readl(regs + REG_LCM_INT_CS);
-
-       if (lcdirq & LCM_INT_CS_DISP_F_STATUS) {
-               writel(readl(irq_base) | 1<<30, irq_base);
-
-               /* wait VA_EN low */
-               if ((readl(regs + REG_LCM_DCCS) &
-                   LCM_DCCS_SINGLE) == LCM_DCCS_SINGLE)
-                       while ((readl(regs + REG_LCM_DCCS) &
-                              LCM_DCCS_VA_EN) == LCM_DCCS_VA_EN)
-                               ;
-               /* display_out-enable */
-               writel(readl(regs + REG_LCM_DCCS) | LCM_DCCS_DISP_OUT_EN,
-                       regs + REG_LCM_DCCS);
-               /* va-enable*/
-               writel(readl(regs + REG_LCM_DCCS) | LCM_DCCS_VA_EN,
-                       regs + REG_LCM_DCCS);
-       } else if (lcdirq & LCM_INT_CS_UNDERRUN_INT) {
-               writel(readl(irq_base) | LCM_INT_CS_UNDERRUN_INT, irq_base);
-       } else if (lcdirq & LCM_INT_CS_BUS_ERROR_INT) {
-               writel(readl(irq_base) | LCM_INT_CS_BUS_ERROR_INT, irq_base);
-       }
-
-       return IRQ_HANDLED;
-}
-
-#ifdef CONFIG_CPU_FREQ
-
-static int nuc900fb_cpufreq_transition(struct notifier_block *nb,
-                                      unsigned long val, void *data)
-{
-       struct nuc900fb_info *info;
-       struct fb_info *fbinfo;
-       long delta_f;
-       info = container_of(nb, struct nuc900fb_info, freq_transition);
-       fbinfo = dev_get_drvdata(info->dev);
-
-       delta_f = info->clk_rate - clk_get_rate(info->clk);
-
-       if ((val == CPUFREQ_POSTCHANGE && delta_f > 0) ||
-          (val == CPUFREQ_PRECHANGE && delta_f < 0)) {
-               info->clk_rate = clk_get_rate(info->clk);
-               nuc900fb_activate_var(fbinfo);
-       }
-
-       return 0;
-}
-
-static inline int nuc900fb_cpufreq_register(struct nuc900fb_info *fbi)
-{
-       fbi->freq_transition.notifier_call = nuc900fb_cpufreq_transition;
-       return cpufreq_register_notifier(&fbi->freq_transition,
-                                 CPUFREQ_TRANSITION_NOTIFIER);
-}
-
-static inline void nuc900fb_cpufreq_deregister(struct nuc900fb_info *fbi)
-{
-       cpufreq_unregister_notifier(&fbi->freq_transition,
-                                   CPUFREQ_TRANSITION_NOTIFIER);
-}
-#else
-static inline int nuc900fb_cpufreq_transition(struct notifier_block *nb,
-                                      unsigned long val, void *data)
-{
-       return 0;
-}
-
-static inline int nuc900fb_cpufreq_register(struct nuc900fb_info *fbi)
-{
-       return 0;
-}
-
-static inline void nuc900fb_cpufreq_deregister(struct nuc900fb_info *info)
-{
-}
-#endif
-
-static char driver_name[] = "nuc900fb";
-
-static int nuc900fb_probe(struct platform_device *pdev)
-{
-       struct nuc900fb_info *fbi;
-       struct nuc900fb_display *display;
-       struct fb_info     *fbinfo;
-       struct nuc900fb_mach_info *mach_info;
-       struct resource *res;
-       int ret;
-       int irq;
-       int i;
-       int size;
-
-       dev_dbg(&pdev->dev, "devinit\n");
-       mach_info = dev_get_platdata(&pdev->dev);
-       if (mach_info == NULL) {
-               dev_err(&pdev->dev,
-                       "no platform data for lcd, cannot attach\n");
-               return -EINVAL;
-       }
-
-       if (mach_info->default_display > mach_info->num_displays) {
-               dev_err(&pdev->dev,
-                       "default display No. is %d but only %d displays \n",
-                       mach_info->default_display, mach_info->num_displays);
-               return -EINVAL;
-       }
-
-
-       display = mach_info->displays + mach_info->default_display;
-
-       irq = platform_get_irq(pdev, 0);
-       if (irq < 0) {
-               dev_err(&pdev->dev, "no irq for device\n");
-               return -ENOENT;
-       }
-
-       fbinfo = framebuffer_alloc(sizeof(struct nuc900fb_info), &pdev->dev);
-       if (!fbinfo)
-               return -ENOMEM;
-
-       platform_set_drvdata(pdev, fbinfo);
-
-       fbi = fbinfo->par;
-       fbi->dev = &pdev->dev;
-
-#ifdef CONFIG_CPU_NUC950
-       fbi->drv_type = LCDDRV_NUC950;
-#endif
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
-       size = resource_size(res);
-       fbi->mem = request_mem_region(res->start, size, pdev->name);
-       if (fbi->mem == NULL) {
-               dev_err(&pdev->dev, "failed to alloc memory region\n");
-               ret = -ENOENT;
-               goto free_fb;
-       }
-
-       fbi->io = ioremap(res->start, size);
-       if (fbi->io == NULL) {
-               dev_err(&pdev->dev, "ioremap() of lcd registers failed\n");
-               ret = -ENXIO;
-               goto release_mem_region;
-       }
-
-       fbi->irq_base = fbi->io + REG_LCM_INT_CS;
-
-
-       /* Stop the LCD */
-       writel(0, fbi->io + REG_LCM_DCCS);
-
-       /* fill the fbinfo*/
-       strcpy(fbinfo->fix.id, driver_name);
-       fbinfo->fix.type                = FB_TYPE_PACKED_PIXELS;
-       fbinfo->fix.type_aux            = 0;
-       fbinfo->fix.xpanstep            = 0;
-       fbinfo->fix.ypanstep            = 0;
-       fbinfo->fix.ywrapstep           = 0;
-       fbinfo->fix.accel               = FB_ACCEL_NONE;
-       fbinfo->var.nonstd              = 0;
-       fbinfo->var.activate            = FB_ACTIVATE_NOW;
-       fbinfo->var.accel_flags         = 0;
-       fbinfo->var.vmode               = FB_VMODE_NONINTERLACED;
-       fbinfo->fbops                   = &nuc900fb_ops;
-       fbinfo->flags                   = FBINFO_FLAG_DEFAULT;
-       fbinfo->pseudo_palette          = &fbi->pseudo_pal;
-
-       ret = request_irq(irq, nuc900fb_irqhandler, 0, pdev->name, fbi);
-       if (ret) {
-               dev_err(&pdev->dev, "cannot register irq handler %d -err %d\n",
-                       irq, ret);
-               ret = -EBUSY;
-               goto release_regs;
-       }
-
-       fbi->clk = clk_get(&pdev->dev, NULL);
-       if (IS_ERR(fbi->clk)) {
-               printk(KERN_ERR "nuc900-lcd:failed to get lcd clock source\n");
-               ret = PTR_ERR(fbi->clk);
-               goto release_irq;
-       }
-
-       clk_enable(fbi->clk);
-       dev_dbg(&pdev->dev, "got and enabled clock\n");
-
-       fbi->clk_rate = clk_get_rate(fbi->clk);
-
-       /* calutate the video buffer size */
-       for (i = 0; i < mach_info->num_displays; i++) {
-               unsigned long smem_len = mach_info->displays[i].xres;
-               smem_len *= mach_info->displays[i].yres;
-               smem_len *= mach_info->displays[i].bpp;
-               smem_len >>= 3;
-               if (fbinfo->fix.smem_len < smem_len)
-                       fbinfo->fix.smem_len = smem_len;
-       }
-
-       /* Initialize Video Memory */
-       ret = nuc900fb_map_video_memory(fbinfo);
-       if (ret) {
-               printk(KERN_ERR "Failed to allocate video RAM: %x\n", ret);
-               goto release_clock;
-       }
-
-       dev_dbg(&pdev->dev, "got video memory\n");
-
-       fbinfo->var.xres = display->xres;
-       fbinfo->var.yres = display->yres;
-       fbinfo->var.bits_per_pixel = display->bpp;
-
-       nuc900fb_init_registers(fbinfo);
-
-       nuc900fb_check_var(&fbinfo->var, fbinfo);
-
-       ret = nuc900fb_cpufreq_register(fbi);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "Failed to register cpufreq\n");
-               goto free_video_memory;
-       }
-
-       ret = register_framebuffer(fbinfo);
-       if (ret) {
-               printk(KERN_ERR "failed to register framebuffer device: %d\n",
-                       ret);
-               goto free_cpufreq;
-       }
-
-       fb_info(fbinfo, "%s frame buffer device\n", fbinfo->fix.id);
-
-       return 0;
-
-free_cpufreq:
-       nuc900fb_cpufreq_deregister(fbi);
-free_video_memory:
-       nuc900fb_unmap_video_memory(fbinfo);
-release_clock:
-       clk_disable(fbi->clk);
-       clk_put(fbi->clk);
-release_irq:
-       free_irq(irq, fbi);
-release_regs:
-       iounmap(fbi->io);
-release_mem_region:
-       release_mem_region(res->start, size);
-free_fb:
-       framebuffer_release(fbinfo);
-       return ret;
-}
-
-/*
- * shutdown the lcd controller
- */
-static void nuc900fb_stop_lcd(struct fb_info *info)
-{
-       struct nuc900fb_info *fbi = info->par;
-       void __iomem *regs = fbi->io;
-
-       writel((~LCM_DCCS_DISP_INT_EN) | (~LCM_DCCS_VA_EN) | (~LCM_DCCS_OSD_EN),
-               regs + REG_LCM_DCCS);
-}
-
-/*
- *  Cleanup
- */
-static int nuc900fb_remove(struct platform_device *pdev)
-{
-       struct fb_info *fbinfo = platform_get_drvdata(pdev);
-       struct nuc900fb_info *fbi = fbinfo->par;
-       int irq;
-
-       nuc900fb_stop_lcd(fbinfo);
-       msleep(1);
-
-       unregister_framebuffer(fbinfo);
-       nuc900fb_cpufreq_deregister(fbi);
-       nuc900fb_unmap_video_memory(fbinfo);
-
-       iounmap(fbi->io);
-
-       irq = platform_get_irq(pdev, 0);
-       free_irq(irq, fbi);
-
-       release_resource(fbi->mem);
-       kfree(fbi->mem);
-
-       framebuffer_release(fbinfo);
-
-       return 0;
-}
-
-#ifdef CONFIG_PM
-
-/*
- *     suspend and resume support for the lcd controller
- */
-
-static int nuc900fb_suspend(struct platform_device *dev, pm_message_t state)
-{
-       struct fb_info     *fbinfo = platform_get_drvdata(dev);
-       struct nuc900fb_info *info = fbinfo->par;
-
-       nuc900fb_stop_lcd(fbinfo);
-       msleep(1);
-       clk_disable(info->clk);
-       return 0;
-}
-
-static int nuc900fb_resume(struct platform_device *dev)
-{
-       struct fb_info     *fbinfo = platform_get_drvdata(dev);
-       struct nuc900fb_info *fbi = fbinfo->par;
-
-       printk(KERN_INFO "nuc900fb resume\n");
-
-       clk_enable(fbi->clk);
-       msleep(1);
-
-       nuc900fb_init_registers(fbinfo);
-       nuc900fb_activate_var(fbinfo);
-
-       return 0;
-}
-
-#else
-#define nuc900fb_suspend NULL
-#define nuc900fb_resume  NULL
-#endif
-
-static struct platform_driver nuc900fb_driver = {
-       .probe          = nuc900fb_probe,
-       .remove         = nuc900fb_remove,
-       .suspend        = nuc900fb_suspend,
-       .resume         = nuc900fb_resume,
-       .driver         = {
-               .name   = "nuc900-lcd",
-       },
-};
-
-module_platform_driver(nuc900fb_driver);
-
-MODULE_DESCRIPTION("Framebuffer driver for the NUC900");
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/nuc900fb.h b/drivers/video/fbdev/nuc900fb.h
deleted file mode 100644 (file)
index 055ae92..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- *
- * Copyright (c) 2009 Nuvoton technology corporation
- * All rights reserved.
- *
- *   Author:
- *        Wang Qiang(rurality.linux@gmail.com)  2009/12/16
- */
-
-#ifndef __NUC900FB_H
-#define __NUC900FB_H
-
-#include <mach/map.h>
-#include <linux/platform_data/video-nuc900fb.h>
-
-enum nuc900_lcddrv_type {
-       LCDDRV_NUC910,
-       LCDDRV_NUC930,
-       LCDDRV_NUC932,
-       LCDDRV_NUC950,
-       LCDDRV_NUC960,
-};
-
-
-#define PALETTE_BUFFER_SIZE    256
-#define PALETTE_BUFF_CLEAR     (0x80000000) /* entry is clear/invalid */
-
-struct nuc900fb_info {
-       struct device           *dev;
-       struct clk              *clk;
-
-       struct resource         *mem;
-       void __iomem            *io;
-       void __iomem            *irq_base;
-       int                     drv_type;
-       struct nuc900fb_hw      regs;
-       unsigned long           clk_rate;
-
-#ifdef CONFIG_CPU_FREQ
-       struct notifier_block   freq_transition;
-#endif
-
-       /* keep these registers in case we need to re-write palette */
-       u32                     palette_buffer[PALETTE_BUFFER_SIZE];
-       u32                     pseudo_pal[16];
-};
-
-int nuc900fb_init(void);
-
-#endif /* __NUC900FB_H */
index c38f0d4..4d5a03a 100644 (file)
@@ -550,7 +550,6 @@ header-test-                        += linux/platform_data/sky81452-backlight.h
 header-test-                   += linux/platform_data/spi-davinci.h
 header-test-                   += linux/platform_data/spi-ep93xx.h
 header-test-                   += linux/platform_data/spi-mt65xx.h
-header-test-                   += linux/platform_data/spi-nuc900.h
 header-test-                   += linux/platform_data/st_sensors_pdata.h
 header-test-                   += linux/platform_data/ti-sysc.h
 header-test-                   += linux/platform_data/timer-ixp4xx.h
@@ -569,7 +568,6 @@ header-test-                        += linux/platform_data/usb3503.h
 header-test-                   += linux/platform_data/ux500_wdt.h
 header-test-                   += linux/platform_data/video-clcd-versatile.h
 header-test-                   += linux/platform_data/video-imxfb.h
-header-test-                   += linux/platform_data/video-nuc900fb.h
 header-test-                   += linux/platform_data/video-pxafb.h
 header-test-                   += linux/platform_data/video_s3c.h
 header-test-                   += linux/platform_data/voltage-omap.h
diff --git a/include/dt-bindings/bus/moxtet.h b/include/dt-bindings/bus/moxtet.h
new file mode 100644 (file)
index 0000000..dc93454
--- /dev/null
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Constant for device tree bindings for Turris Mox module configuration bus
+ *
+ * Copyright (C) 2019 Marek Behun <marek.behun@nic.cz>
+ */
+
+#ifndef _DT_BINDINGS_BUS_MOXTET_H
+#define _DT_BINDINGS_BUS_MOXTET_H
+
+#define MOXTET_IRQ_PCI         0
+#define MOXTET_IRQ_USB3                4
+#define MOXTET_IRQ_PERIDOT(n)  (8 + (n))
+#define MOXTET_IRQ_TOPAZ       12
+
+#endif /* _DT_BINDINGS_BUS_MOXTET_H */
diff --git a/include/dt-bindings/power/meson-g12a-power.h b/include/dt-bindings/power/meson-g12a-power.h
new file mode 100644 (file)
index 0000000..bb5e67a
--- /dev/null
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: (GPL-2.0+ or MIT) */
+/*
+ * Copyright (c) 2019 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ */
+
+#ifndef _DT_BINDINGS_MESON_G12A_POWER_H
+#define _DT_BINDINGS_MESON_G12A_POWER_H
+
+#define PWRC_G12A_VPU_ID               0
+#define PWRC_G12A_ETH_ID               1
+
+#endif
diff --git a/include/dt-bindings/power/meson-sm1-power.h b/include/dt-bindings/power/meson-sm1-power.h
new file mode 100644 (file)
index 0000000..a020ab0
--- /dev/null
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: (GPL-2.0+ or MIT) */
+/*
+ * Copyright (c) 2019 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ */
+
+#ifndef _DT_BINDINGS_MESON_SM1_POWER_H
+#define _DT_BINDINGS_MESON_SM1_POWER_H
+
+#define PWRC_SM1_VPU_ID                0
+#define PWRC_SM1_NNA_ID                1
+#define PWRC_SM1_USB_ID                2
+#define PWRC_SM1_PCIE_ID       3
+#define PWRC_SM1_GE2D_ID       4
+#define PWRC_SM1_AUDIO_ID      5
+#define PWRC_SM1_ETH_ID                6
+
+#endif
index 524d607..ea50586 100644 (file)
@@ -1,56 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
 /*
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
  * Copyright (c) 2016 BayLibre, SAS.
  * Author: Neil Armstrong <narmstrong@baylibre.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- * The full GNU General Public License is included in this distribution
- * in the file called COPYING.
- *
- * BSD LICENSE
- *
- * Copyright (c) 2016 BayLibre, SAS.
- * Author: Neil Armstrong <narmstrong@baylibre.com>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *   * Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- *   * Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in
- *     the documentation and/or other materials provided with the
- *     distribution.
- *   * Neither the name of Intel Corporation nor the names of its
- *     contributors may be used to endorse or promote products derived
- *     from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #ifndef _DT_BINDINGS_AMLOGIC_MESON_GXBB_RESET_H
 #define _DT_BINDINGS_AMLOGIC_MESON_GXBB_RESET_H
index 614aff2..c614438 100644 (file)
@@ -1,56 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
 /*
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
  * Copyright (c) 2016 BayLibre, SAS.
  * Author: Neil Armstrong <narmstrong@baylibre.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- * The full GNU General Public License is included in this distribution
- * in the file called COPYING.
- *
- * BSD LICENSE
- *
- * Copyright (c) 2016 BayLibre, SAS.
- * Author: Neil Armstrong <narmstrong@baylibre.com>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *   * Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- *   * Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in
- *     the documentation and/or other materials provided with the
- *     distribution.
- *   * Neither the name of Intel Corporation nor the names of its
- *     contributors may be used to endorse or promote products derived
- *     from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #ifndef _DT_BINDINGS_AMLOGIC_MESON8B_RESET_H
 #define _DT_BINDINGS_AMLOGIC_MESON8B_RESET_H
index 57c5924..9a30108 100644 (file)
 #define IMX8MQ_RESET_OTG2_PHY_RESET            20
 #define IMX8MQ_RESET_MIPI_DSI_RESET_BYTE_N     21
 #define IMX8MQ_RESET_MIPI_DSI_RESET_N          22
-#define IMX8MQ_RESET_MIPI_DIS_DPI_RESET_N      23
-#define IMX8MQ_RESET_MIPI_DIS_ESC_RESET_N      24
-#define IMX8MQ_RESET_MIPI_DIS_PCLK_RESET_N     25
+#define IMX8MQ_RESET_MIPI_DSI_DPI_RESET_N      23
+#define IMX8MQ_RESET_MIPI_DSI_ESC_RESET_N      24
+#define IMX8MQ_RESET_MIPI_DSI_PCLK_RESET_N     25
 #define IMX8MQ_RESET_PCIEPHY                   26
 #define IMX8MQ_RESET_PCIEPHY_PERST             27
 #define IMX8MQ_RESET_PCIE_CTRL_APPS_EN         28
 #define IMX8MQ_RESET_PCIE_CTRL_APPS_TURNOFF    29
-#define IMX8MQ_RESET_HDMI_PHY_APB_RESET                30
+#define IMX8MQ_RESET_HDMI_PHY_APB_RESET                30      /* i.MX8MM does NOT support */
 #define IMX8MQ_RESET_DISP_RESET                        31
 #define IMX8MQ_RESET_GPU_RESET                 32
 #define IMX8MQ_RESET_VPU_RESET                 33
-#define IMX8MQ_RESET_PCIEPHY2                  34
-#define IMX8MQ_RESET_PCIEPHY2_PERST            35
-#define IMX8MQ_RESET_PCIE2_CTRL_APPS_EN                36
-#define IMX8MQ_RESET_PCIE2_CTRL_APPS_TURNOFF   37
-#define IMX8MQ_RESET_MIPI_CSI1_CORE_RESET      38
-#define IMX8MQ_RESET_MIPI_CSI1_PHY_REF_RESET   39
-#define IMX8MQ_RESET_MIPI_CSI1_ESC_RESET       40
-#define IMX8MQ_RESET_MIPI_CSI2_CORE_RESET      41
-#define IMX8MQ_RESET_MIPI_CSI2_PHY_REF_RESET   42
-#define IMX8MQ_RESET_MIPI_CSI2_ESC_RESET       43
+#define IMX8MQ_RESET_PCIEPHY2                  34      /* i.MX8MM does NOT support */
+#define IMX8MQ_RESET_PCIEPHY2_PERST            35      /* i.MX8MM does NOT support */
+#define IMX8MQ_RESET_PCIE2_CTRL_APPS_EN                36      /* i.MX8MM does NOT support */
+#define IMX8MQ_RESET_PCIE2_CTRL_APPS_TURNOFF   37      /* i.MX8MM does NOT support */
+#define IMX8MQ_RESET_MIPI_CSI1_CORE_RESET      38      /* i.MX8MM does NOT support */
+#define IMX8MQ_RESET_MIPI_CSI1_PHY_REF_RESET   39      /* i.MX8MM does NOT support */
+#define IMX8MQ_RESET_MIPI_CSI1_ESC_RESET       40      /* i.MX8MM does NOT support */
+#define IMX8MQ_RESET_MIPI_CSI2_CORE_RESET      41      /* i.MX8MM does NOT support */
+#define IMX8MQ_RESET_MIPI_CSI2_PHY_REF_RESET   42      /* i.MX8MM does NOT support */
+#define IMX8MQ_RESET_MIPI_CSI2_ESC_RESET       43      /* i.MX8MM does NOT support */
 #define IMX8MQ_RESET_DDRC1_PRST                        44
 #define IMX8MQ_RESET_DDRC1_CORE_RESET          45
 #define IMX8MQ_RESET_DDRC1_PHY_RESET           46
-#define IMX8MQ_RESET_DDRC2_PRST                        47
-#define IMX8MQ_RESET_DDRC2_CORE_RESET          48
-#define IMX8MQ_RESET_DDRC2_PHY_RESET           49
+#define IMX8MQ_RESET_DDRC2_PRST                        47      /* i.MX8MM does NOT support */
+#define IMX8MQ_RESET_DDRC2_CORE_RESET          48      /* i.MX8MM does NOT support */
+#define IMX8MQ_RESET_DDRC2_PHY_RESET           49      /* i.MX8MM does NOT support */
 
 #define IMX8MQ_RESET_NUM                       50
 
diff --git a/include/dt-bindings/soc/ti,sci_pm_domain.h b/include/dt-bindings/soc/ti,sci_pm_domain.h
new file mode 100644 (file)
index 0000000..8f2a736
--- /dev/null
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __DT_BINDINGS_TI_SCI_PM_DOMAIN_H
+#define __DT_BINDINGS_TI_SCI_PM_DOMAIN_H
+
+#define TI_SCI_PD_EXCLUSIVE    1
+#define TI_SCI_PD_SHARED       0
+
+#endif /* __DT_BINDINGS_TI_SCI_PM_DOMAIN_H */
diff --git a/include/linux/firmware/imx/dsp.h b/include/linux/firmware/imx/dsp.h
new file mode 100644 (file)
index 0000000..7562099
--- /dev/null
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2019 NXP
+ *
+ * Header file for the DSP IPC implementation
+ */
+
+#ifndef _IMX_DSP_IPC_H
+#define _IMX_DSP_IPC_H
+
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/mailbox_client.h>
+
+#define DSP_MU_CHAN_NUM                4
+
+struct imx_dsp_chan {
+       struct imx_dsp_ipc *ipc;
+       struct mbox_client cl;
+       struct mbox_chan *ch;
+       char *name;
+       int idx;
+};
+
+struct imx_dsp_ops {
+       void (*handle_reply)(struct imx_dsp_ipc *ipc);
+       void (*handle_request)(struct imx_dsp_ipc *ipc);
+};
+
+struct imx_dsp_ipc {
+       /* Host <-> DSP communication uses 2 txdb and 2 rxdb channels */
+       struct imx_dsp_chan chans[DSP_MU_CHAN_NUM];
+       struct device *dev;
+       struct imx_dsp_ops *ops;
+       void *private_data;
+};
+
+static inline void imx_dsp_set_data(struct imx_dsp_ipc *ipc, void *data)
+{
+       if (!ipc)
+               return;
+
+       ipc->private_data = data;
+}
+
+static inline void *imx_dsp_get_data(struct imx_dsp_ipc *ipc)
+{
+       if (!ipc)
+               return NULL;
+
+       return ipc->private_data;
+}
+
+#if IS_ENABLED(CONFIG_IMX_DSP)
+
+int imx_dsp_ring_doorbell(struct imx_dsp_ipc *dsp, unsigned int chan_idx);
+
+#else
+
+static inline int imx_dsp_ring_doorbell(struct imx_dsp_ipc *ipc,
+                                       unsigned int chan_idx)
+{
+       return -ENOTSUPP;
+}
+
+#endif
+#endif /* _IMX_DSP_IPC_H */
diff --git a/include/linux/moxtet.h b/include/linux/moxtet.h
new file mode 100644 (file)
index 0000000..490db68
--- /dev/null
@@ -0,0 +1,109 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Turris Mox module configuration bus driver
+ *
+ * Copyright (C) 2019 Marek Behun <marek.behun@nic.cz>
+ */
+
+#ifndef __LINUX_MOXTET_H
+#define __LINUX_MOXTET_H
+
+#include <linux/device.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/mutex.h>
+
+#define TURRIS_MOX_MAX_MODULES 10
+
+enum turris_mox_cpu_module_id {
+       TURRIS_MOX_CPU_ID_EMMC  = 0x00,
+       TURRIS_MOX_CPU_ID_SD    = 0x10,
+};
+
+enum turris_mox_module_id {
+       TURRIS_MOX_MODULE_FIRST         = 0x01,
+
+       TURRIS_MOX_MODULE_SFP           = 0x01,
+       TURRIS_MOX_MODULE_PCI           = 0x02,
+       TURRIS_MOX_MODULE_TOPAZ         = 0x03,
+       TURRIS_MOX_MODULE_PERIDOT       = 0x04,
+       TURRIS_MOX_MODULE_USB3          = 0x05,
+       TURRIS_MOX_MODULE_PCI_BRIDGE    = 0x06,
+
+       TURRIS_MOX_MODULE_LAST          = 0x06,
+};
+
+#define MOXTET_NIRQS   16
+
+extern struct bus_type moxtet_type;
+
+struct moxtet {
+       struct device                   *dev;
+       struct mutex                    lock;
+       u8                              modules[TURRIS_MOX_MAX_MODULES];
+       int                             count;
+       u8                              tx[TURRIS_MOX_MAX_MODULES];
+       int                             dev_irq;
+       struct {
+               struct irq_domain       *domain;
+               struct irq_chip         chip;
+               unsigned long           masked, exists;
+               struct moxtet_irqpos {
+                                       u8 idx;
+                                       u8 bit;
+               } position[MOXTET_NIRQS];
+       } irq;
+#ifdef CONFIG_DEBUG_FS
+       struct dentry                   *debugfs_root;
+#endif
+};
+
+struct moxtet_driver {
+       const enum turris_mox_module_id *id_table;
+       struct device_driver            driver;
+};
+
+static inline struct moxtet_driver *
+to_moxtet_driver(struct device_driver *drv)
+{
+       if (!drv)
+               return NULL;
+       return container_of(drv, struct moxtet_driver, driver);
+}
+
+extern int __moxtet_register_driver(struct module *owner,
+                                   struct moxtet_driver *mdrv);
+
+static inline void moxtet_unregister_driver(struct moxtet_driver *mdrv)
+{
+       if (mdrv)
+               driver_unregister(&mdrv->driver);
+}
+
+#define moxtet_register_driver(driver) \
+       __moxtet_register_driver(THIS_MODULE, driver)
+
+#define module_moxtet_driver(__moxtet_driver) \
+       module_driver(__moxtet_driver, moxtet_register_driver, \
+                       moxtet_unregister_driver)
+
+struct moxtet_device {
+       struct device                   dev;
+       struct moxtet                   *moxtet;
+       enum turris_mox_module_id       id;
+       unsigned int                    idx;
+};
+
+extern int moxtet_device_read(struct device *dev);
+extern int moxtet_device_write(struct device *dev, u8 val);
+extern int moxtet_device_written(struct device *dev);
+
+static inline struct moxtet_device *
+to_moxtet_device(struct device *dev)
+{
+       if (!dev)
+               return NULL;
+       return container_of(dev, struct moxtet_device, dev);
+}
+
+#endif /* __LINUX_MOXTET_H */
diff --git a/include/linux/platform_data/spi-nuc900.h b/include/linux/platform_data/spi-nuc900.h
deleted file mode 100644 (file)
index ca35108..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (c) 2009 Nuvoton technology corporation.
- *
- * Wan ZongShun <mcuos.com@gmail.com>
- */
-
-#ifndef __SPI_NUC900_H
-#define __SPI_NUC900_H
-
-extern void mfp_set_groupg(struct device *dev, const char *subname);
-
-struct nuc900_spi_info {
-       unsigned int num_cs;
-       unsigned int lsb;
-       unsigned int txneg;
-       unsigned int rxneg;
-       unsigned int divider;
-       unsigned int sleep;
-       unsigned int txnum;
-       unsigned int txbitlen;
-       int bus_num;
-};
-
-struct nuc900_spi_chip {
-       unsigned char bits_per_word;
-};
-
-#endif /* __SPI_NUC900_H */
diff --git a/include/linux/platform_data/video-nuc900fb.h b/include/linux/platform_data/video-nuc900fb.h
deleted file mode 100644 (file)
index 3da5044..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/* linux/include/asm/arch-nuc900/fb.h
- *
- * Copyright (c) 2008 Nuvoton technology corporation
- * All rights reserved.
- *
- * Changelog:
- *
- *   2008/08/26     vincen.zswan modify this file for LCD.
- */
-
-#ifndef __ASM_ARM_FB_H
-#define __ASM_ARM_FB_H
-
-
-
-/* LCD Controller Hardware Desc */
-struct nuc900fb_hw {
-       unsigned int lcd_dccs;
-       unsigned int lcd_device_ctrl;
-       unsigned int lcd_mpulcd_cmd;
-       unsigned int lcd_int_cs;
-       unsigned int lcd_crtc_size;
-       unsigned int lcd_crtc_dend;
-       unsigned int lcd_crtc_hr;
-       unsigned int lcd_crtc_hsync;
-       unsigned int lcd_crtc_vr;
-       unsigned int lcd_va_baddr0;
-       unsigned int lcd_va_baddr1;
-       unsigned int lcd_va_fbctrl;
-       unsigned int lcd_va_scale;
-       unsigned int lcd_va_test;
-       unsigned int lcd_va_win;
-       unsigned int lcd_va_stuff;
-};
-
-/* LCD Display Description */
-struct nuc900fb_display {
-       /* LCD Image type */
-       unsigned type;
-
-       /* LCD Screen Size */
-       unsigned short width;
-       unsigned short height;
-
-       /* LCD Screen Info */
-       unsigned short xres;
-       unsigned short yres;
-       unsigned short bpp;
-
-       unsigned long pixclock;
-       unsigned short left_margin;
-       unsigned short right_margin;
-       unsigned short hsync_len;
-       unsigned short upper_margin;
-       unsigned short lower_margin;
-       unsigned short vsync_len;
-
-       /* hardware special register value */
-       unsigned int dccs;
-       unsigned int devctl;
-       unsigned int fbctrl;
-       unsigned int scale;
-};
-
-struct nuc900fb_mach_info {
-       struct nuc900fb_display *displays;
-       unsigned num_displays;
-       unsigned default_display;
-       /* GPIO Setting  Info */
-       unsigned gpio_dir;
-       unsigned gpio_dir_mask;
-       unsigned gpio_data;
-       unsigned gpio_data_mask;
-};
-
-extern void __init nuc900_fb_set_platdata(struct nuc900fb_mach_info *);
-
-#endif /* __ASM_ARM_FB_H */
index 3f12cc7..2d5eff5 100644 (file)
@@ -49,8 +49,9 @@ extern int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr,
 extern int qcom_scm_pas_auth_and_reset(u32 peripheral);
 extern int qcom_scm_pas_shutdown(u32 peripheral);
 extern int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz,
-                              unsigned int *src, struct qcom_scm_vmperm *newvm,
-                              int dest_cnt);
+                              unsigned int *src,
+                              const struct qcom_scm_vmperm *newvm,
+                              unsigned int dest_cnt);
 extern void qcom_scm_cpu_power_down(u32 flags);
 extern u32 qcom_scm_get_version(void);
 extern int qcom_scm_set_remote_state(u32 state, u32 id);
@@ -87,8 +88,8 @@ qcom_scm_pas_auth_and_reset(u32 peripheral) { return -ENODEV; }
 static inline int qcom_scm_pas_shutdown(u32 peripheral) { return -ENODEV; }
 static inline int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz,
                                      unsigned int *src,
-                                     struct qcom_scm_vmperm *newvm,
-                                     int dest_cnt) { return -ENODEV; }
+                                     const struct qcom_scm_vmperm *newvm,
+                                     unsigned int dest_cnt) { return -ENODEV; }
 static inline void qcom_scm_cpu_power_down(u32 flags) {}
 static inline u32 qcom_scm_get_version(void) { return 0; }
 static inline u32
index 9ff2e93..881fea4 100644 (file)
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * SCMI Message Protocol driver header
  *
@@ -71,7 +71,7 @@ struct scmi_clk_ops {
        int (*rate_get)(const struct scmi_handle *handle, u32 clk_id,
                        u64 *rate);
        int (*rate_set)(const struct scmi_handle *handle, u32 clk_id,
-                       u32 config, u64 rate);
+                       u64 rate);
        int (*enable)(const struct scmi_handle *handle, u32 clk_id);
        int (*disable)(const struct scmi_handle *handle, u32 clk_id);
 };
@@ -145,6 +145,8 @@ struct scmi_sensor_info {
        u32 id;
        u8 type;
        s8 scale;
+       u8 num_trip_points;
+       bool async;
        char name[SCMI_MAX_STR_SIZE];
 };
 
@@ -167,9 +169,9 @@ enum scmi_sensor_class {
  *
  * @count_get: get the count of sensors provided by SCMI
  * @info_get: get the information of the specified sensor
- * @configuration_set: control notifications on cross-over events for
+ * @trip_point_notify: control notifications on cross-over events for
  *     the trip-points
- * @trip_point_set: selects and configures a trip-point of interest
+ * @trip_point_config: selects and configures a trip-point of interest
  * @reading_get: gets the current value of the sensor
  */
 struct scmi_sensor_ops {
@@ -177,12 +179,32 @@ struct scmi_sensor_ops {
 
        const struct scmi_sensor_info *(*info_get)
                (const struct scmi_handle *handle, u32 sensor_id);
-       int (*configuration_set)(const struct scmi_handle *handle,
-                                u32 sensor_id);
-       int (*trip_point_set)(const struct scmi_handle *handle, u32 sensor_id,
-                             u8 trip_id, u64 trip_value);
+       int (*trip_point_notify)(const struct scmi_handle *handle,
+                                u32 sensor_id, bool enable);
+       int (*trip_point_config)(const struct scmi_handle *handle,
+                                u32 sensor_id, u8 trip_id, u64 trip_value);
        int (*reading_get)(const struct scmi_handle *handle, u32 sensor_id,
-                          bool async, u64 *value);
+                          u64 *value);
+};
+
+/**
+ * struct scmi_reset_ops - represents the various operations provided
+ *     by SCMI Reset Protocol
+ *
+ * @num_domains_get: get the count of reset domains provided by SCMI
+ * @name_get: gets the name of a reset domain
+ * @latency_get: gets the reset latency for the specified reset domain
+ * @reset: resets the specified reset domain
+ * @assert: explicitly assert reset signal of the specified reset domain
+ * @deassert: explicitly deassert reset signal of the specified reset domain
+ */
+struct scmi_reset_ops {
+       int (*num_domains_get)(const struct scmi_handle *handle);
+       char *(*name_get)(const struct scmi_handle *handle, u32 domain);
+       int (*latency_get)(const struct scmi_handle *handle, u32 domain);
+       int (*reset)(const struct scmi_handle *handle, u32 domain);
+       int (*assert)(const struct scmi_handle *handle, u32 domain);
+       int (*deassert)(const struct scmi_handle *handle, u32 domain);
 };
 
 /**
@@ -194,6 +216,7 @@ struct scmi_sensor_ops {
  * @perf_ops: pointer to set of performance protocol operations
  * @clk_ops: pointer to set of clock protocol operations
  * @sensor_ops: pointer to set of sensor protocol operations
+ * @reset_ops: pointer to set of reset protocol operations
  * @perf_priv: pointer to private data structure specific to performance
  *     protocol(for internal use only)
  * @clk_priv: pointer to private data structure specific to clock
@@ -202,6 +225,8 @@ struct scmi_sensor_ops {
  *     protocol(for internal use only)
  * @sensor_priv: pointer to private data structure specific to sensors
  *     protocol(for internal use only)
+ * @reset_priv: pointer to private data structure specific to reset
+ *     protocol(for internal use only)
  */
 struct scmi_handle {
        struct device *dev;
@@ -210,11 +235,13 @@ struct scmi_handle {
        struct scmi_clk_ops *clk_ops;
        struct scmi_power_ops *power_ops;
        struct scmi_sensor_ops *sensor_ops;
+       struct scmi_reset_ops *reset_ops;
        /* for protocol internal use */
        void *perf_priv;
        void *clk_priv;
        void *power_priv;
        void *sensor_priv;
+       void *reset_priv;
 };
 
 enum scmi_std_protocol {
@@ -224,6 +251,7 @@ enum scmi_std_protocol {
        SCMI_PROTOCOL_PERF = 0x13,
        SCMI_PROTOCOL_CLOCK = 0x14,
        SCMI_PROTOCOL_SENSOR = 0x15,
+       SCMI_PROTOCOL_RESET = 0x16,
 };
 
 struct scmi_device {
index 54ade13..f3ae45d 100644 (file)
@@ -63,26 +63,26 @@ void cmdq_pkt_destroy(struct cmdq_pkt *pkt);
 /**
  * cmdq_pkt_write() - append write command to the CMDQ packet
  * @pkt:       the CMDQ packet
- * @value:     the specified target register value
  * @subsys:    the CMDQ sub system code
  * @offset:    register offset from CMDQ sub system
+ * @value:     the specified target register value
  *
  * Return: 0 for success; else the error code is returned
  */
-int cmdq_pkt_write(struct cmdq_pkt *pkt, u32 value, u32 subsys, u32 offset);
+int cmdq_pkt_write(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value);
 
 /**
  * cmdq_pkt_write_mask() - append write command with mask to the CMDQ packet
  * @pkt:       the CMDQ packet
- * @value:     the specified target register value
  * @subsys:    the CMDQ sub system code
  * @offset:    register offset from CMDQ sub system
+ * @value:     the specified target register value
  * @mask:      the specified target register mask
  *
  * Return: 0 for success; else the error code is returned
  */
-int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u32 value,
-                       u32 subsys, u32 offset, u32 mask);
+int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u8 subsys,
+                       u16 offset, u32 value, u32 mask);
 
 /**
  * cmdq_pkt_wfe() - append wait for event command to the CMDQ packet
@@ -91,7 +91,7 @@ int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u32 value,
  *
  * Return: 0 for success; else the error code is returned
  */
-int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u32 event);
+int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u16 event);
 
 /**
  * cmdq_pkt_clear_event() - append clear event command to the CMDQ packet
@@ -100,7 +100,7 @@ int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u32 event);
  *
  * Return: 0 for success; else the error code is returned
  */
-int cmdq_pkt_clear_event(struct cmdq_pkt *pkt, u32 event);
+int cmdq_pkt_clear_event(struct cmdq_pkt *pkt, u16 event);
 
 /**
  * cmdq_pkt_flush_async() - trigger CMDQ to asynchronously execute the CMDQ
diff --git a/include/linux/soc/samsung/exynos-chipid.h b/include/linux/soc/samsung/exynos-chipid.h
new file mode 100644 (file)
index 0000000..8bca676
--- /dev/null
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *           http://www.samsung.com/
+ *
+ * Exynos - CHIPID support
+ */
+#ifndef __LINUX_SOC_EXYNOS_CHIPID_H
+#define __LINUX_SOC_EXYNOS_CHIPID_H
+
+#define EXYNOS_CHIPID_REG_PRO_ID       0x00
+#define EXYNOS_SUBREV_MASK             (0xf << 4)
+#define EXYNOS_MAINREV_MASK            (0xf << 0)
+#define EXYNOS_REV_MASK                        (EXYNOS_SUBREV_MASK | \
+                                        EXYNOS_MAINREV_MASK)
+#define EXYNOS_MASK                    0xfffff000
+
+#define EXYNOS_CHIPID_REG_PKG_ID       0x04
+/* Bit field definitions for EXYNOS_CHIPID_REG_PKG_ID register */
+#define EXYNOS5422_IDS_OFFSET          24
+#define EXYNOS5422_IDS_MASK            0xff
+#define EXYNOS5422_USESG_OFFSET        3
+#define EXYNOS5422_USESG_MASK          0x01
+#define EXYNOS5422_SG_OFFSET           0
+#define EXYNOS5422_SG_MASK             0x07
+#define EXYNOS5422_TABLE_OFFSET        8
+#define EXYNOS5422_TABLE_MASK          0x03
+#define EXYNOS5422_SG_A_OFFSET         17
+#define EXYNOS5422_SG_A_MASK           0x0f
+#define EXYNOS5422_SG_B_OFFSET         21
+#define EXYNOS5422_SG_B_MASK           0x03
+#define EXYNOS5422_SG_BSIGN_OFFSET     23
+#define EXYNOS5422_SG_BSIGN_MASK       0x01
+#define EXYNOS5422_BIN2_OFFSET         12
+#define EXYNOS5422_BIN2_MASK           0x01
+
+#define EXYNOS_CHIPID_REG_LOT_ID       0x14
+
+#define EXYNOS_CHIPID_REG_AUX_INFO     0x1c
+/* Bit field definitions for EXYNOS_CHIPID_REG_AUX_INFO register */
+#define EXYNOS5422_TMCB_OFFSET         0
+#define EXYNOS5422_TMCB_MASK           0x7f
+#define EXYNOS5422_ARM_UP_OFFSET       8
+#define EXYNOS5422_ARM_UP_MASK         0x03
+#define EXYNOS5422_ARM_DN_OFFSET       10
+#define EXYNOS5422_ARM_DN_MASK         0x03
+#define EXYNOS5422_KFC_UP_OFFSET       12
+#define EXYNOS5422_KFC_UP_MASK         0x03
+#define EXYNOS5422_KFC_DN_OFFSET       14
+#define EXYNOS5422_KFC_DN_MASK         0x03
+
+#endif /*__LINUX_SOC_EXYNOS_CHIPID_H */
index 6c610e1..9531ec8 100644 (file)
@@ -97,7 +97,10 @@ struct ti_sci_core_ops {
  */
 struct ti_sci_dev_ops {
        int (*get_device)(const struct ti_sci_handle *handle, u32 id);
+       int (*get_device_exclusive)(const struct ti_sci_handle *handle, u32 id);
        int (*idle_device)(const struct ti_sci_handle *handle, u32 id);
+       int (*idle_device_exclusive)(const struct ti_sci_handle *handle,
+                                    u32 id);
        int (*put_device)(const struct ti_sci_handle *handle, u32 id);
        int (*is_valid)(const struct ti_sci_handle *handle, u32 id);
        int (*get_context_loss_count)(const struct ti_sci_handle *handle,
index b7c70c3..48ceea8 100644 (file)
@@ -12,6 +12,7 @@ struct soc_device_attribute {
        const char *machine;
        const char *family;
        const char *revision;
+       const char *serial_number;
        const char *soc_id;
        const void *data;
 };
index efed3c3..1d19ae6 100644 (file)
@@ -32,7 +32,6 @@ struct da8xx_lcdc_platform_data {
        const char manu_name[10];
        void *controller_data;
        const char type[25];
-       void (*panel_power_ctrl)(int);
 };
 
 struct lcd_ctrl_config {