From patchwork Fri Mar 6 13:07:16 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serge Semin X-Patchwork-Id: 11423887 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 3564F921 for ; Fri, 6 Mar 2020 13:13:01 +0000 (UTC) Received: by mail.kernel.org (Postfix) id 2F83421744; Fri, 6 Mar 2020 13:13:01 +0000 (UTC) Delivered-To: soc@kernel.org Received: from mail.baikalelectronics.ru (mail.baikalelectronics.com [87.245.175.226]) by mail.kernel.org (Postfix) with ESMTP id E849221739 for ; Fri, 6 Mar 2020 13:13:00 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org E849221739 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=baikalelectronics.ru Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=Sergey.Semin@baikalelectronics.ru Received: from localhost (unknown [127.0.0.1]) by mail.baikalelectronics.ru (Postfix) with ESMTP id 7E27C8030705; Fri, 6 Mar 2020 13:07:32 +0000 (UTC) X-Virus-Scanned: amavisd-new at baikalelectronics.ru Received: from mail.baikalelectronics.ru ([127.0.0.1]) by localhost (mail.baikalelectronics.ru [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id XUMLQxRvb2VS; Fri, 6 Mar 2020 16:07:31 +0300 (MSK) From: To: Rob Herring , Mark Rutland List-Id: CC: Serge Semin , Serge Semin , Alexey Malahov , Thomas Bogendoerfer , Paul Burton , Ralf Baechle , Arnd Bergmann , Olof Johansson , , , Subject: [PATCH 1/6] dt-bindings: Add Baikal-T1 AXI-bus EHB dts bindings file Date: Fri, 6 Mar 2020 16:07:16 +0300 In-Reply-To: <20200306130721.10347-1-Sergey.Semin@baikalelectronics.ru> References: <20200306130721.10347-1-Sergey.Semin@baikalelectronics.ru> MIME-Version: 1.0 X-ClientProxiedBy: MAIL.baikal.int (192.168.51.25) To mail (192.168.51.25) Message-Id: <20200306130732.7E27C8030705@mail.baikalelectronics.ru> From: Serge Semin This is a specific block embedded into the Baikal-T1 SoC, which is dedicated to detect AXI-bus protocol errors. So the dts node just needs to have the "be,bt1-axi-ehb" compatible string, MMIO registers and interrupts properties declared. Signed-off-by: Serge Semin Signed-off-by: Alexey Malahov Cc: Thomas Bogendoerfer Cc: Paul Burton Cc: Ralf Baechle Cc: Arnd Bergmann Cc: Olof Johansson Cc: soc@kernel.org --- .../soc/baikal-t1/be,bt1-axi-ehb.yaml | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 Documentation/devicetree/bindings/soc/baikal-t1/be,bt1-axi-ehb.yaml diff --git a/Documentation/devicetree/bindings/soc/baikal-t1/be,bt1-axi-ehb.yaml b/Documentation/devicetree/bindings/soc/baikal-t1/be,bt1-axi-ehb.yaml new file mode 100644 index 000000000000..f0deeb8f261c --- /dev/null +++ b/Documentation/devicetree/bindings/soc/baikal-t1/be,bt1-axi-ehb.yaml @@ -0,0 +1,52 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) 2019 - 2020 BAIKAL ELECTRONICS, JSC +# +# Baikal-T1 AXI-bus Errors Handler Block Device Tree Bindings. +# +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/soc/baikal-t1/be,bt1-axi-ehb.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Baikal-T1 AXI-bus Errors Handler Block + +maintainers: + - Serge Semin + +description: | + AXI3-bus is the main communication bus connecting all high-speed peripheral + IP-cores with RAM controller and with MIPS P5600 cores. Traffic arbitration + is done by means of Main Interconnect routing IO request from one block to + another. In case of any protocol error, device not responding an IRQ is + raised and a faulty situation is reported to the AXI EHB described by this + bindings. + +properties: + compatible: + const: be,bt1-axi-ehb + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + +additionalProperties: false + +required: + - compatible + - reg + - interrupts + +examples: + - | + #include + + axi_ehb: ehb@1F04D110 { + compatible = "be,bt1-axi-ehb"; + reg = <0x1F04D110 0x008>; + + interrupts = ; + }; +... From patchwork Fri Mar 6 13:07:17 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serge Semin X-Patchwork-Id: 11423891 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 5FD5618B8 for ; Fri, 6 Mar 2020 13:13:01 +0000 (UTC) Received: by mail.kernel.org (Postfix) id 573B821775; Fri, 6 Mar 2020 13:13:01 +0000 (UTC) Delivered-To: soc@kernel.org Received: from mail.baikalelectronics.ru (mail.baikalelectronics.com [87.245.175.226]) by mail.kernel.org (Postfix) with ESMTP id E625F20866 for ; Fri, 6 Mar 2020 13:13:00 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org E625F20866 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=baikalelectronics.ru Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=Sergey.Semin@baikalelectronics.ru Received: from localhost (unknown [127.0.0.1]) by mail.baikalelectronics.ru (Postfix) with ESMTP id 3FD2C8030706; Fri, 6 Mar 2020 13:07:33 +0000 (UTC) X-Virus-Scanned: amavisd-new at baikalelectronics.ru Received: from mail.baikalelectronics.ru ([127.0.0.1]) by localhost (mail.baikalelectronics.ru [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id zlcMDz8CAUmd; Fri, 6 Mar 2020 16:07:32 +0300 (MSK) From: To: Rob Herring , Mark Rutland List-Id: CC: Serge Semin , Serge Semin , Alexey Malahov , Thomas Bogendoerfer , Paul Burton , Ralf Baechle , Arnd Bergmann , Olof Johansson , , , Subject: [PATCH 2/6] dt-bindings: Add Baikal-T1 APB-bus EHB dts bindings file Date: Fri, 6 Mar 2020 16:07:17 +0300 In-Reply-To: <20200306130721.10347-1-Sergey.Semin@baikalelectronics.ru> References: <20200306130721.10347-1-Sergey.Semin@baikalelectronics.ru> MIME-Version: 1.0 X-ClientProxiedBy: MAIL.baikal.int (192.168.51.25) To mail (192.168.51.25) Message-Id: <20200306130733.3FD2C8030706@mail.baikalelectronics.ru> From: Serge Semin This is a specific block embedded into the Baikal-T1 SoC, which is dedicated to detect APB-bus protocol errors and tune the peripheral access timeout. So the dts bindings implies that corresponding dts node would be equipped with "be,bt1-apb-ehb" compatible string, MMIO region of registers space and of space with no device mapped, interrupts property and with an APB-reference clock handler. Signed-off-by: Serge Semin Signed-off-by: Alexey Malahov Cc: Thomas Bogendoerfer Cc: Paul Burton Cc: Ralf Baechle Cc: Arnd Bergmann Cc: Olof Johansson Cc: soc@kernel.org --- .../soc/baikal-t1/be,bt1-apb-ehb.yaml | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 Documentation/devicetree/bindings/soc/baikal-t1/be,bt1-apb-ehb.yaml diff --git a/Documentation/devicetree/bindings/soc/baikal-t1/be,bt1-apb-ehb.yaml b/Documentation/devicetree/bindings/soc/baikal-t1/be,bt1-apb-ehb.yaml new file mode 100644 index 000000000000..e262aead2fb5 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/baikal-t1/be,bt1-apb-ehb.yaml @@ -0,0 +1,66 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) 2019 - 2020 BAIKAL ELECTRONICS, JSC +# +# Baikal-T1 APB-bus Errors Handler Block Device Tree Bindings. +# +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/soc/baikal-t1/be,bt1-apb-ehb.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Baikal-T1 APB-bus Errors Handler Block + +maintainers: + - Serge Semin + +description: | + Configuration registers of Baikal-T1 SoC peripheral interfaces are accessed + by means of the APB-bus. In case of any APB protocol collisions, slave device + not responding on timeout an IRQ is raised with an erroneous address reported + to the APB terminator (EHB) sub-block described by this bindings file. + +properties: + compatible: + const: be,bt1-apb-ehb + + reg: + items: + - description: APB EHB MMIO registers. + - description: APB MMIO region with no any device mapped. + + interrupts: + maxItems: 1 + + clocks: + description: APB reference clock. + maxItems: 1 + + clock-names: + const: ref + +additionalProperties: false + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + +examples: + - | + #include + #include + + apb_ehb: ehb@1F059000 { + compatible = "be,bt1-apb-ehb"; + reg = <0x1F059000 0x1000>, + <0x1D000000 0x2040000>; + + interrupts = ; + + clocks = <&ccu_sys CCU_SYS_APB_CLK>; + clock-names = "ref"; + }; +... From patchwork Fri Mar 6 13:07:18 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serge Semin X-Patchwork-Id: 11423895 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 78F2D138D for ; Fri, 6 Mar 2020 13:13:02 +0000 (UTC) Received: by mail.kernel.org (Postfix) id 74038208CD; Fri, 6 Mar 2020 13:13:02 +0000 (UTC) Delivered-To: soc@kernel.org Received: from mail.baikalelectronics.ru (mail.baikalelectronics.com [87.245.175.226]) by mail.kernel.org (Postfix) with ESMTP id 109DB222C3 for ; Fri, 6 Mar 2020 13:13:02 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 109DB222C3 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=baikalelectronics.ru Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=Sergey.Semin@baikalelectronics.ru Received: from localhost (unknown [127.0.0.1]) by mail.baikalelectronics.ru (Postfix) with ESMTP id 194288030794; Fri, 6 Mar 2020 13:07:34 +0000 (UTC) X-Virus-Scanned: amavisd-new at baikalelectronics.ru Received: from mail.baikalelectronics.ru ([127.0.0.1]) by localhost (mail.baikalelectronics.ru [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id pPKreXhWPNMw; Fri, 6 Mar 2020 16:07:33 +0300 (MSK) From: To: Rob Herring , Mark Rutland List-Id: CC: Serge Semin , Serge Semin , Alexey Malahov , Thomas Bogendoerfer , Paul Burton , Ralf Baechle , Arnd Bergmann , Olof Johansson , , , Subject: [PATCH 3/6] dt-bindings: Add Baikal-T1 L2-cache Control Block dts bindings file Date: Fri, 6 Mar 2020 16:07:18 +0300 In-Reply-To: <20200306130721.10347-1-Sergey.Semin@baikalelectronics.ru> References: <20200306130721.10347-1-Sergey.Semin@baikalelectronics.ru> MIME-Version: 1.0 X-ClientProxiedBy: MAIL.baikal.int (192.168.51.25) To mail (192.168.51.25) Message-Id: <20200306130734.194288030794@mail.baikalelectronics.ru> From: Serge Semin There is a single register provided by the SoC system controller, which can be used to tune the L2-cache up. It only provides a way to change the L2-RAM access latencies. So aside from the MMIO region with that setting and "be,bt1-l2-ctl" compatible string the device node can be optionally equipped with the properties of Tag/Data/WS latencies. Signed-off-by: Serge Semin Signed-off-by: Alexey Malahov Cc: Thomas Bogendoerfer Cc: Paul Burton Cc: Ralf Baechle Cc: Arnd Bergmann Cc: Olof Johansson Cc: soc@kernel.org --- .../bindings/soc/baikal-t1/be,bt1-l2-ctl.yaml | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 Documentation/devicetree/bindings/soc/baikal-t1/be,bt1-l2-ctl.yaml diff --git a/Documentation/devicetree/bindings/soc/baikal-t1/be,bt1-l2-ctl.yaml b/Documentation/devicetree/bindings/soc/baikal-t1/be,bt1-l2-ctl.yaml new file mode 100644 index 000000000000..8769b3fa517c --- /dev/null +++ b/Documentation/devicetree/bindings/soc/baikal-t1/be,bt1-l2-ctl.yaml @@ -0,0 +1,108 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) 2020 BAIKAL ELECTRONICS, JSC +# +# Baikal-T1 L2-cache Control Block Device Tree Bindings. +# +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/soc/baikal-t1/be,bt1-l2-ctl.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Baikal-T1 L2-cache Control Block + +maintainers: + - Serge Semin + +description: | + Baikal-T1 exposes a few settings to tune the MIPS P5600 CM2 L2-cache + performance up. In particular it's possible to change the Tag, Data and + Way-select RAM access latencies. This bindings file describes the system + controller block, which provides an interface to set the tuning up. + +allOf: + - if: + properties: + compatible: + contains: + const: syscon + then: + $ref: ../../mfd/syscon.yaml# + else: + properties: + reg-io-width: false + + little-endian: false + +properties: + compatible: + oneOf: + - description: P5600 CM2 L2-cache RAM external configuration block. + const: be,bt1-l2-ctl + - description: P5600 CM2 L2-cache RAM system controller block. + items: + - const: be,bt1-l2-ctl + - const: syscon + + reg: + description: MMIO register with MIPS P5600 CM2 L2-cache RAM settings. + maxItems: 1 + + be,l2-ws-latency: + description: Cycles of latency for Way-select RAM accesses. + default: 0 + allOf: + - $ref: /schemas/types.yaml#/definitions/uint32 + - minimum: 0 + maximum: 3 + + be,l2-tag-latency: + description: Cycles of latency for Tag RAM accesses. + default: 0 + allOf: + - $ref: /schemas/types.yaml#/definitions/uint32 + - minimum: 0 + maximum: 3 + + be,l2-data-latency: + description: Cycles of latency for Data RAM accesses. + default: 1 + allOf: + - $ref: /schemas/types.yaml#/definitions/uint32 + - minimum: 0 + maximum: 3 + + reg-io-width: + const: 4 + + little-endian: true + +additionalProperties: false + +required: + - compatible + - reg + +examples: + - | + l2_ctl1: l2@1F04D028 { + compatible = "be,bt1-l2-ctl"; + reg = <0x1F04D028 0x004>; + + be,l2-ws-latency = <0>; + be,l2-tag-latency = <0>; + be,l2-data-latency = <1>; + }; + - | + l2_ctl2: l2@1F04D028 { + compatible = "be,bt1-l2-ctl", "syscon"; + reg = <0x1F04D028 0x004>; + + be,l2-ws-latency = <0>; + be,l2-tag-latency = <0>; + be,l2-data-latency = <1>; + + little-endian; + reg-io-width = <4>; + }; +... From patchwork Fri Mar 6 13:07:19 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serge Semin X-Patchwork-Id: 11423889 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 5CC2E17EF for ; Fri, 6 Mar 2020 13:13:01 +0000 (UTC) Received: by mail.kernel.org (Postfix) id 56F2A21739; Fri, 6 Mar 2020 13:13:01 +0000 (UTC) Delivered-To: soc@kernel.org X-Greylist: delayed 327 seconds by postgrey-1.34 at mail.kernel.org; Fri, 06 Mar 2020 13:13:00 UTC DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org E628C208CD Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=baikalelectronics.ru Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=Sergey.Semin@baikalelectronics.ru Received: from mail.baikalelectronics.ru (mail.baikalelectronics.com [87.245.175.226]) by mail.kernel.org (Postfix) with ESMTP id E628C208CD for ; Fri, 6 Mar 2020 13:13:00 +0000 (UTC) Received: from localhost (unknown [127.0.0.1]) by mail.baikalelectronics.ru (Postfix) with ESMTP id 0EE9D8030700; Fri, 6 Mar 2020 13:07:35 +0000 (UTC) X-Virus-Scanned: amavisd-new at baikalelectronics.ru Received: from mail.baikalelectronics.ru ([127.0.0.1]) by localhost (mail.baikalelectronics.ru [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id WuyWbmOsoFDx; Fri, 6 Mar 2020 16:07:34 +0300 (MSK) From: To: List-Id: CC: Serge Semin , Serge Semin , Alexey Malahov , Thomas Bogendoerfer , Paul Burton , Ralf Baechle , Arnd Bergmann , Olof Johansson , , Subject: [PATCH 4/6] soc: bt1: Add Baikal-T1 AXI-bus EHB driver Date: Fri, 6 Mar 2020 16:07:19 +0300 In-Reply-To: <20200306130721.10347-1-Sergey.Semin@baikalelectronics.ru> References: <20200306130721.10347-1-Sergey.Semin@baikalelectronics.ru> MIME-Version: 1.0 X-ClientProxiedBy: MAIL.baikal.int (192.168.51.25) To mail (192.168.51.25) Message-Id: <20200306130735.0EE9D8030700@mail.baikalelectronics.ru> From: Serge Semin AXI3-bus is the main communication bus connecting all high-speed peripheral IP-cores with RAM controller and MIPS P5600 cores. Baikal-T1 SoC provides a way to detect the bus protocol errors and report a short info about it by means of the AXI-bus Errors Handler Block (AXI EHB). The block rises an interrupt indicating an AXI protocol error at an attempt either to reach a non-existent slave device or to perform an invalid operation with a slave IP-block. This driver provides the interrupt handler, which prints an error message with a faulty address and updates an errors counter, and exposes a sysfs-node to inject the described types of errors. Signed-off-by: Serge Semin Signed-off-by: Alexey Malahov Cc: Thomas Bogendoerfer Cc: Paul Burton Cc: Ralf Baechle Cc: Arnd Bergmann Cc: Olof Johansson Cc: soc@kernel.org --- drivers/soc/Kconfig | 1 + drivers/soc/Makefile | 1 + drivers/soc/baikal-t1/Kconfig | 22 +++ drivers/soc/baikal-t1/Makefile | 2 + drivers/soc/baikal-t1/axi-ehb.c | 250 ++++++++++++++++++++++++++++++++ drivers/soc/baikal-t1/common.h | 37 +++++ 6 files changed, 313 insertions(+) create mode 100644 drivers/soc/baikal-t1/Kconfig create mode 100644 drivers/soc/baikal-t1/Makefile create mode 100644 drivers/soc/baikal-t1/axi-ehb.c create mode 100644 drivers/soc/baikal-t1/common.h diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig index 1778f8c62861..af2c2ca5d643 100644 --- a/drivers/soc/Kconfig +++ b/drivers/soc/Kconfig @@ -5,6 +5,7 @@ source "drivers/soc/actions/Kconfig" source "drivers/soc/amlogic/Kconfig" source "drivers/soc/aspeed/Kconfig" source "drivers/soc/atmel/Kconfig" +source "drivers/soc/baikal-t1/Kconfig" source "drivers/soc/bcm/Kconfig" source "drivers/soc/fsl/Kconfig" source "drivers/soc/imx/Kconfig" diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile index 8b49d782a1ab..0cf4d91f3d09 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_ARCH_ACTIONS) += actions/ obj-$(CONFIG_SOC_ASPEED) += aspeed/ obj-$(CONFIG_ARCH_AT91) += atmel/ +obj-$(CONFIG_SOC_BAIKAL_T1) += baikal-t1/ obj-y += bcm/ obj-$(CONFIG_ARCH_DOVE) += dove/ obj-$(CONFIG_MACH_DOVE) += dove/ diff --git a/drivers/soc/baikal-t1/Kconfig b/drivers/soc/baikal-t1/Kconfig new file mode 100644 index 000000000000..aca155350612 --- /dev/null +++ b/drivers/soc/baikal-t1/Kconfig @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0 +menu "Baikal-T1 SoC drivers" + +config SOC_BAIKAL_T1 + def_bool y + depends on MIPS_BAIKAL_T1 || COMPILE_TEST + +config BT1_AXI_EHB + bool "Baikal-T1 AXI-bus Errors Handler Block" + depends on SOC_BAIKAL_T1 && OF + help + Baikal-T1 CCU registers space as being MFD provides an access to the + AXI-bus Errors Handler Block (AXI EHB). It rises an interrupt + indicating an AXI protocol error at an attempt either to reach a + non-existent slave device or to perform an invalid operation with a + slave IP-block. This driver provides the interrupt handler, which + prints an error message with a faulty address and updates an errors + counter. + + If unsure, say N. + +endmenu diff --git a/drivers/soc/baikal-t1/Makefile b/drivers/soc/baikal-t1/Makefile new file mode 100644 index 000000000000..c069791058b9 --- /dev/null +++ b/drivers/soc/baikal-t1/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_BT1_AXI_EHB) += axi-ehb.o diff --git a/drivers/soc/baikal-t1/axi-ehb.c b/drivers/soc/baikal-t1/axi-ehb.c new file mode 100644 index 000000000000..36929958cb4f --- /dev/null +++ b/drivers/soc/baikal-t1/axi-ehb.c @@ -0,0 +1,250 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2014 - 2020 BAIKAL ELECTRONICS, JSC + * + * Authors: + * Serge Semin + * + * Baikal-T1 AXI-bus Errors Handler Block driver. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "common.h" + +#define AXI_EHB_WERRL 0x00 +#define AXI_EHB_WERRH 0x04 +#define AXI_EHB_WERRH_TYPE BIT(23) +#define AXI_EHB_WERRH_ADDR_FLD 24 +#define AXI_EHB_WERRH_ADDR_MASK GENMASK(31, AXI_EHB_WERRH_ADDR_FLD) + +/* + * struct axi_ehb - Baikal-T1 AXI EHB private data. + * @dev: Pointer to the device structure. + * @regs: Memory mapped block registers. + * @irq: Errors IRQ number. + * @count: Number of errors detected. + */ +struct axi_ehb { + struct device *dev; + + void __iomem *regs; + int irq; + + atomic_t count; +}; + +static irqreturn_t axi_ehb_isr(int irq, void *data) +{ + struct axi_ehb *ehb = data; + u64 addr, val; + + addr = bt1_read(ehb->regs + AXI_EHB_WERRL); + val = bt1_read(ehb->regs + AXI_EHB_WERRH); + + addr |= (u64)(BT1_GET_FLD(AXI_EHB_WERRH_ADDR, val)) << 32; + + dev_crit_ratelimited(ehb->dev, + "AXI-bus fault %d: %s at %08llx\n", + atomic_inc_return(&ehb->count), + val & AXI_EHB_WERRH_TYPE ? "no slave" : "slave protocol error", + addr); + + /* + * Print backtrace on each CPU. This might be pointless if the fault + * has happened on the same CPU as the IRQ handler is executed or + * the other core proceeded further execution despite the error. + * But if it's not, by looking at the trace we would get straight to + * the cause of the problem. + */ + trigger_all_cpu_backtrace(); + + return IRQ_HANDLED; +} + +static void axi_ehb_clear_data(void *data) +{ + struct axi_ehb *ehb = data; + struct platform_device *pdev = to_platform_device(ehb->dev); + + platform_set_drvdata(pdev, NULL); +} + +static struct axi_ehb *axi_ehb_create_data(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct axi_ehb *ehb; + int ret; + + ehb = devm_kzalloc(dev, sizeof(*ehb), GFP_KERNEL); + if (!ehb) + return ERR_PTR(-ENOMEM); + + ret = devm_add_action(dev, axi_ehb_clear_data, ehb); + if (ret) { + dev_err(dev, "Can't add AXI EHB data clear action\n"); + return ERR_PTR(ret); + } + + ehb->dev = dev; + atomic_set(&ehb->count, 0); + platform_set_drvdata(pdev, ehb); + + return ehb; +} + +static int axi_ehb_request_regs(struct axi_ehb *ehb) +{ + struct platform_device *pdev = to_platform_device(ehb->dev); + + ehb->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(ehb->regs)) { + dev_err(ehb->dev, "Couldn't map AXI EHB registers\n"); + return PTR_ERR(ehb->regs); + } + + return 0; +} + +static int axi_ehb_request_irq(struct axi_ehb *ehb) +{ + struct platform_device *pdev = to_platform_device(ehb->dev); + int ret; + + ehb->irq = platform_get_irq(pdev, 0); + if (ehb->irq < 0) { + dev_err(ehb->dev, "Couldn't find AXI EHB IRQ number\n"); + return ehb->irq; + } + + ret = devm_request_irq(ehb->dev, ehb->irq, axi_ehb_isr, IRQF_SHARED, + "axi_ehb", ehb); + if (ret) { + dev_err(ehb->dev, "Couldn't request AXI EHB IRQ\n"); + return ret; + } + + return 0; +} + +static ssize_t count_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct axi_ehb *ehb = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&ehb->count)); +} +static DEVICE_ATTR_RO(count); + +static int inject_error_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "Error injection: bus unaligned\n"); +} + +static int inject_error_store(struct device *dev, + struct device_attribute *attr, + const char *data, size_t count) +{ + struct axi_ehb *ehb = dev_get_drvdata(dev); + + /* + * Performing unaligned read from the memory will cause the CM bus + * error while unaligned writing - the AXI bus write error handled + * by this driver. + */ + if (!strncmp(data, "bus", 3)) + readb(ehb->regs + AXI_EHB_WERRL); + else if (!strncmp(data, "unaligned", 9)) + writeb(0, ehb->regs + AXI_EHB_WERRL); + else + return -EINVAL; + + return count; +} +static DEVICE_ATTR_RW(inject_error); + +static struct attribute *axi_ehb_sysfs_attrs[] = { + &dev_attr_count.attr, + &dev_attr_inject_error.attr, + NULL +}; +ATTRIBUTE_GROUPS(axi_ehb_sysfs); + +static void axi_ehb_remove_sysfs(void *data) +{ + struct axi_ehb *ehb = data; + + device_remove_groups(ehb->dev, axi_ehb_sysfs_groups); +} + +static int axi_ehb_init_sysfs(struct axi_ehb *ehb) +{ + int ret; + + ret = device_add_groups(ehb->dev, axi_ehb_sysfs_groups); + if (ret) { + dev_err(ehb->dev, "Failed to add sysfs files group\n"); + return ret; + } + + ret = devm_add_action_or_reset(ehb->dev, axi_ehb_remove_sysfs, ehb); + if (ret) + dev_err(ehb->dev, "Can't add AXI EHB sysfs remove action\n"); + + return ret; +} + +static int axi_ehb_probe(struct platform_device *pdev) +{ + struct axi_ehb *ehb; + int ret; + + ehb = axi_ehb_create_data(pdev); + if (IS_ERR(ehb)) + return PTR_ERR(ehb); + + ret = axi_ehb_request_regs(ehb); + if (ret) + return ret; + + ret = axi_ehb_request_irq(ehb); + if (ret) + return ret; + + ret = axi_ehb_init_sysfs(ehb); + if (ret) + return ret; + + dev_info(ehb->dev, "AXI-bus errors handler installed\n"); + + return 0; +} + +static const struct of_device_id axi_ehb_of_match[] = { + { .compatible = "be,bt1-axi-ehb" }, + { } +}; +MODULE_DEVICE_TABLE(of, axi_ehb_of_match); + +static struct platform_driver axi_ehb_driver = { + .probe = axi_ehb_probe, + .driver = { + .name = "bt1-axi-ehb", + .of_match_table = of_match_ptr(axi_ehb_of_match) + } +}; +module_platform_driver(axi_ehb_driver); + +MODULE_AUTHOR("Serge Semin "); +MODULE_DESCRIPTION("Baikal-T1 AXI EHB driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/baikal-t1/common.h b/drivers/soc/baikal-t1/common.h new file mode 100644 index 000000000000..d1d7c4e11bd4 --- /dev/null +++ b/drivers/soc/baikal-t1/common.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2019 - 2020 BAIKAL ELECTRONICS, JSC + * + * Baikal-T1 SoC common methods. + */ +#ifndef __SOC_BT1_COMMON_H__ +#define __SOC_BT1_COMMON_H__ + +#include + +#define BT1_GET_FLD(_name, _data) \ + (((u32)(_data) & _name ## _MASK) >> _name ## _FLD) + +#define BT1_SET_FLD(_name, _data, _val) \ + (((u32)(_data) & ~_name ## _MASK) | \ + (((u32)(_val) << _name ## _FLD) & _name ## _MASK)) + +static inline u32 bt1_read(void __iomem *reg) +{ + return readl(reg); +} + +static inline void bt1_write(void __iomem *reg, u32 data) +{ + writel(data, reg); +} + +static inline void bt1_update(void __iomem *reg, u32 mask, u32 data) +{ + u32 old; + + old = readl_relaxed(reg); + writel((old & ~mask) | (data & mask), reg); +} + +#endif /* __SOC_BT1_COMMON_H__ */ From patchwork Fri Mar 6 13:07:20 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serge Semin X-Patchwork-Id: 11423915 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 5E90C921 for ; Fri, 6 Mar 2020 13:18:02 +0000 (UTC) Received: by mail.kernel.org (Postfix) id 5906E2166E; Fri, 6 Mar 2020 13:18:02 +0000 (UTC) Delivered-To: soc@kernel.org Received: from mail.baikalelectronics.ru (mail.baikalelectronics.com [87.245.175.226]) by mail.kernel.org (Postfix) with ESMTP id E77482146E for ; Fri, 6 Mar 2020 13:18:01 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org E77482146E Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=baikalelectronics.ru Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=Sergey.Semin@baikalelectronics.ru Received: from localhost (unknown [127.0.0.1]) by mail.baikalelectronics.ru (Postfix) with ESMTP id 287C48030704; Fri, 6 Mar 2020 13:07:36 +0000 (UTC) X-Virus-Scanned: amavisd-new at baikalelectronics.ru Received: from mail.baikalelectronics.ru ([127.0.0.1]) by localhost (mail.baikalelectronics.ru [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id FtOrceswA8HG; Fri, 6 Mar 2020 16:07:35 +0300 (MSK) From: To: List-Id: CC: Serge Semin , Serge Semin , Alexey Malahov , Thomas Bogendoerfer , Paul Burton , Ralf Baechle , Arnd Bergmann , Olof Johansson , , Subject: [PATCH 5/6] soc: bt1: Add Baikal-T1 APB-bus EHB driver Date: Fri, 6 Mar 2020 16:07:20 +0300 In-Reply-To: <20200306130721.10347-1-Sergey.Semin@baikalelectronics.ru> References: <20200306130721.10347-1-Sergey.Semin@baikalelectronics.ru> MIME-Version: 1.0 X-ClientProxiedBy: MAIL.baikal.int (192.168.51.25) To mail (192.168.51.25) Message-Id: <20200306130736.287C48030704@mail.baikalelectronics.ru> From: Serge Semin APB-bus is the system configuration bus utilized to access the peripheral IP-cores configuration registers space. Baikal-T1 SoC provides a way to detect the bus protocol errors and report a short info about it by means of the APB-bus Errors Handler Block (APB EHB). In case if an attempted APB transaction stays with no response for a pre-defined time an interrupt occurs and the bus gets freed for a next operation. This driver provides the interrupt handler to detect the erroneous address, prints an error message about the faulty address, updates an errors counter. The counter and the APB-bus operations timeout can be accessed via corresponding sysfs nodes. A dedicated sysfs-node can be also used to artificially cause the bus errors described above. Signed-off-by: Serge Semin Signed-off-by: Alexey Malahov Cc: Thomas Bogendoerfer Cc: Paul Burton Cc: Ralf Baechle Cc: Arnd Bergmann Cc: Olof Johansson Cc: soc@kernel.org --- drivers/soc/baikal-t1/Kconfig | 15 ++ drivers/soc/baikal-t1/Makefile | 1 + drivers/soc/baikal-t1/apb-ehb.c | 381 ++++++++++++++++++++++++++++++++ 3 files changed, 397 insertions(+) create mode 100644 drivers/soc/baikal-t1/apb-ehb.c diff --git a/drivers/soc/baikal-t1/Kconfig b/drivers/soc/baikal-t1/Kconfig index aca155350612..a021abea102f 100644 --- a/drivers/soc/baikal-t1/Kconfig +++ b/drivers/soc/baikal-t1/Kconfig @@ -19,4 +19,19 @@ config BT1_AXI_EHB If unsure, say N. +config BT1_APB_EHB + bool "Baikal-T1 APB-bus Errors Handler Block" + depends on SOC_BAIKAL_T1 && OF + help + Baikal-T1 APB-bus is used to access the IP-core blocks CSRs. In case + if an attempted APB transaction stays with no response for a pre- + defined time an interrupt occurs and the bus gets freed for a next + operation. It is done by the APB-bus Errors Handler Block (APB EHB). + This driver provides the interrupt handler to detect the erroneous + address, prints an error message about the address fault, updates an + errors counter. The counter and the APB-bus operations timeout can be + accessed via corresponding sysfs nodes. + + If unsure, say N. + endmenu diff --git a/drivers/soc/baikal-t1/Makefile b/drivers/soc/baikal-t1/Makefile index c069791058b9..ffb035600e01 100644 --- a/drivers/soc/baikal-t1/Makefile +++ b/drivers/soc/baikal-t1/Makefile @@ -1,2 +1,3 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_BT1_AXI_EHB) += axi-ehb.o +obj-$(CONFIG_BT1_APB_EHB) += apb-ehb.o diff --git a/drivers/soc/baikal-t1/apb-ehb.c b/drivers/soc/baikal-t1/apb-ehb.c new file mode 100644 index 000000000000..726cb75d29cb --- /dev/null +++ b/drivers/soc/baikal-t1/apb-ehb.c @@ -0,0 +1,381 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2014 - 2020 BAIKAL ELECTRONICS, JSC + * + * Authors: + * Serge Semin + * + * Baikal-T1 APB-bus Errors Handler Block driver. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +#define APB_EHB_ISR 0x00 +#define APB_EHB_ISR_PENDING BIT(0) +#define APB_EHB_ISR_MASK BIT(1) +#define APB_EHB_ADDR 0x04 +#define APB_EHB_TIMEOUT 0x08 + +#define APB_EHB_TIMEOUT_MIN 0x000003FFU +#define APB_EHB_TIMEOUT_MAX 0xFFFFFFFFU + +#define APB_EHB_N_TO_TOUT_US(_rate, _n) ({ \ + uint64_t _tmp = USEC_PER_SEC * (uint64_t)(_n); \ + do_div(_tmp, _rate); \ + _tmp; \ +}) +#define APB_EHB_TOUT_TO_N_US(_rate, _tout) ({ \ + uint64_t _tmp = (_tout) * (uint64_t)(_rate); \ + do_div(_tmp, USEC_PER_SEC); \ + _tmp; \ +}) + +/* + * struct apb_ehb - Baikal-T1 APB EHB private data. + * @dev: Pointer to the device structure. + * @regs: Memory mapped block registers. + * @reg_isr_lock: Registers memory lock. + * @res: No-device error injection memory region. + * @irq: Errors IRQ number. + * @count: Number of errors detected. + * @ref: APB-reference clock. + */ +struct apb_ehb { + struct device *dev; + + void __iomem *regs; + spinlock_t reg_isr_lock; + void __iomem *res; + int irq; + + atomic_t count; + + struct clk *ref; +}; + +static irqreturn_t apb_ehb_isr(int irq, void *data) +{ + struct apb_ehb *ehb = data; + unsigned long flags; + u32 addr; + + addr = bt1_read(ehb->regs + APB_EHB_ADDR); + + dev_crit_ratelimited(ehb->dev, + "APB-bus fault %d: Slave access timeout at 0x%08x\n", + atomic_inc_return(&ehb->count), + addr); + + /* + * Print backtrace on each CPU. This might be pointless if the fault + * has happened on the same CPU as the IRQ handler is executed or + * the other core proceeded further execution despite the error. + * But if it's not, by looking at the trace we would get straight to + * the cause of the problem. + */ + trigger_all_cpu_backtrace(); + + spin_lock_irqsave(&ehb->reg_isr_lock, flags); + bt1_update(ehb->regs + APB_EHB_ISR, APB_EHB_ISR_PENDING, 0); + spin_unlock_irqrestore(&ehb->reg_isr_lock, flags); + + return IRQ_HANDLED; +} + +static void apb_ehb_clear_data(void *data) +{ + struct apb_ehb *ehb = data; + struct platform_device *pdev = to_platform_device(ehb->dev); + + platform_set_drvdata(pdev, NULL); +} + +static struct apb_ehb *apb_ehb_create_data(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct apb_ehb *ehb; + int ret; + + ehb = devm_kzalloc(dev, sizeof(*ehb), GFP_KERNEL); + if (!ehb) + return ERR_PTR(-ENOMEM); + + ret = devm_add_action(dev, apb_ehb_clear_data, ehb); + if (ret) { + dev_err(dev, "Can't add APB EHB data clear action\n"); + return ERR_PTR(ret); + } + + ehb->dev = dev; + atomic_set(&ehb->count, 0); + platform_set_drvdata(pdev, ehb); + + return ehb; +} + +static int apb_ehb_request_regs(struct apb_ehb *ehb) +{ + struct platform_device *pdev = to_platform_device(ehb->dev); + + ehb->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(ehb->regs)) { + dev_err(ehb->dev, "Couldn't map APB EHB registers\n"); + return PTR_ERR(ehb->regs); + } + + ehb->res = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(ehb->regs)) { + dev_err(ehb->dev, "Couldn't map reserved region\n"); + return PTR_ERR(ehb->res); + } + + return 0; +} + +static void apb_ehb_disable_clk(void *data) +{ + struct apb_ehb *ehb = data; + + clk_disable_unprepare(ehb->ref); +} + +static int apb_ehb_request_clk(struct apb_ehb *ehb) +{ + int ret; + + ehb->ref = devm_clk_get(ehb->dev, "ref"); + if (IS_ERR(ehb->ref)) { + dev_err(ehb->dev, "Couldn't get APB clock descriptor\n"); + return PTR_ERR(ehb->ref); + } + + ret = clk_prepare_enable(ehb->ref); + if (ret) { + dev_err(ehb->dev, "Couldn't enable the APB clock\n"); + return ret; + } + + ret = devm_add_action_or_reset(ehb->dev, apb_ehb_disable_clk, ehb); + if (ret) + dev_err(ehb->dev, "Can't add APB EHB clocks disable action\n"); + + return ret; +} + +static void apb_ehb_clear_irq(void *data) +{ + struct apb_ehb *ehb = data; + unsigned long flags; + + spin_lock_irqsave(&ehb->reg_isr_lock, flags); + bt1_update(ehb->regs + APB_EHB_ISR, APB_EHB_ISR_MASK, 0); + spin_unlock_irqrestore(&ehb->reg_isr_lock, flags); +} + +static int apb_ehb_request_irq(struct apb_ehb *ehb) +{ + struct platform_device *pdev = to_platform_device(ehb->dev); + int ret; + + spin_lock_init(&ehb->reg_isr_lock); + + ehb->irq = platform_get_irq(pdev, 0); + if (ehb->irq < 0) { + dev_err(ehb->dev, "Couldn't find APB EHB IRQ number\n"); + return ehb->irq; + } + + ret = devm_request_irq(ehb->dev, ehb->irq, apb_ehb_isr, IRQF_SHARED, + "apb_ehb", ehb); + if (ret) { + dev_err(ehb->dev, "Couldn't request APB EHB IRQ\n"); + return ret; + } + + ret = devm_add_action(ehb->dev, apb_ehb_clear_irq, ehb); + if (ret) { + dev_err(ehb->dev, "Can't add APB EHB IRQs clear action\n"); + return ret; + } + + /* Unmask IRQ and clear it' pending flag. */ + bt1_update(ehb->regs + APB_EHB_ISR, + APB_EHB_ISR_PENDING | APB_EHB_ISR_MASK, APB_EHB_ISR_MASK); + + return 0; +} + +static ssize_t count_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct apb_ehb *ehb = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&ehb->count)); +} +static DEVICE_ATTR_RO(count); + +static ssize_t timeout_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct apb_ehb *ehb = dev_get_drvdata(dev); + unsigned long timeout, rate; + u32 n; + + rate = clk_get_rate(ehb->ref); + if (!rate) + return -ENODEV; + + n = bt1_read(ehb->regs + APB_EHB_TIMEOUT); + timeout = APB_EHB_N_TO_TOUT_US(rate, n); + + return scnprintf(buf, PAGE_SIZE, "%lu\n", timeout); +} + +static ssize_t timeout_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct apb_ehb *ehb = dev_get_drvdata(dev); + unsigned long timeout, rate; + u32 n; + + if (kstrtoul(buf, 0, &timeout) < 0) + return -EINVAL; + + rate = clk_get_rate(ehb->ref); + if (!rate) + return -ENODEV; + + n = APB_EHB_TOUT_TO_N_US(rate, timeout); + n = clamp(n, APB_EHB_TIMEOUT_MIN, APB_EHB_TIMEOUT_MAX); + + bt1_write(ehb->regs + APB_EHB_TIMEOUT, n); + + return count; +} +static DEVICE_ATTR_RW(timeout); + +static int inject_error_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "Error injection: nodev irq\n"); +} + +static int inject_error_store(struct device *dev, + struct device_attribute *attr, + const char *data, size_t count) +{ + struct apb_ehb *ehb = dev_get_drvdata(dev); + unsigned long flags; + + /* + * Either dummy read from the unmapped address in the APB IO area + * or manually set the IRQ status. + */ + if (!strncmp(data, "nodev", 5)) { + readl(ehb->res); + } else if (!strncmp(data, "irq", 3)) { + spin_lock_irqsave(&ehb->reg_isr_lock, flags); + bt1_write(ehb->regs + APB_EHB_ISR, + APB_EHB_ISR_PENDING | APB_EHB_ISR_MASK); + spin_unlock_irqrestore(&ehb->reg_isr_lock, flags); + } else + return -EINVAL; + + return count; +} +static DEVICE_ATTR_RW(inject_error); + +static struct attribute *apb_ehb_sysfs_attrs[] = { + &dev_attr_count.attr, + &dev_attr_timeout.attr, + &dev_attr_inject_error.attr, + NULL +}; +ATTRIBUTE_GROUPS(apb_ehb_sysfs); + +static void apb_ehb_remove_sysfs(void *data) +{ + struct apb_ehb *ehb = data; + + device_remove_groups(ehb->dev, apb_ehb_sysfs_groups); +} + +static int apb_ehb_init_sysfs(struct apb_ehb *ehb) +{ + int ret; + + ret = device_add_groups(ehb->dev, apb_ehb_sysfs_groups); + if (ret) { + dev_err(ehb->dev, "Failed to create EHB APB sysfs nodes\n"); + return ret; + } + + ret = devm_add_action_or_reset(ehb->dev, apb_ehb_remove_sysfs, ehb); + if (ret) + dev_err(ehb->dev, "Can't add APB EHB sysfs remove action\n"); + + return ret; +} + +static int apb_ehb_probe(struct platform_device *pdev) +{ + struct apb_ehb *ehb; + int ret; + + ehb = apb_ehb_create_data(pdev); + if (IS_ERR(ehb)) + return PTR_ERR(ehb); + + ret = apb_ehb_request_regs(ehb); + if (ret) + return ret; + + ret = apb_ehb_request_clk(ehb); + if (ret) + return ret; + + ret = apb_ehb_request_irq(ehb); + if (ret) + return ret; + + ret = apb_ehb_init_sysfs(ehb); + if (ret) + return ret; + + dev_info(ehb->dev, "APB-bus errors handler installed\n"); + + return 0; +} + +static const struct of_device_id apb_ehb_of_match[] = { + { .compatible = "be,bt1-apb-ehb" }, + { } +}; +MODULE_DEVICE_TABLE(of, apb_ehb_of_match); + +static struct platform_driver apb_ehb_driver = { + .probe = apb_ehb_probe, + .driver = { + .name = "bt1-apb-ehb", + .of_match_table = of_match_ptr(apb_ehb_of_match) + } +}; +module_platform_driver(apb_ehb_driver); + +MODULE_AUTHOR("Serge Semin "); +MODULE_DESCRIPTION("Baikal-T1 APB EHB driver"); +MODULE_LICENSE("GPL v2"); From patchwork Fri Mar 6 13:07:21 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serge Semin X-Patchwork-Id: 11423913 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 5A58D921 for ; Fri, 6 Mar 2020 13:18:01 +0000 (UTC) Received: by mail.kernel.org (Postfix) id 5497221741; Fri, 6 Mar 2020 13:18:01 +0000 (UTC) Delivered-To: soc@kernel.org Received: from mail.baikalelectronics.ru (mail.baikalelectronics.com [87.245.175.226]) by mail.kernel.org (Postfix) with ESMTP id E3042208CD for ; Fri, 6 Mar 2020 13:18:00 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org E3042208CD Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=baikalelectronics.ru Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=Sergey.Semin@baikalelectronics.ru Received: from localhost (unknown [127.0.0.1]) by mail.baikalelectronics.ru (Postfix) with ESMTP id 37A948030707; Fri, 6 Mar 2020 13:07:37 +0000 (UTC) X-Virus-Scanned: amavisd-new at baikalelectronics.ru Received: from mail.baikalelectronics.ru ([127.0.0.1]) by localhost (mail.baikalelectronics.ru [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id qVCK_Moqb4Eg; Fri, 6 Mar 2020 16:07:36 +0300 (MSK) From: To: List-Id: CC: Serge Semin , Serge Semin , Alexey Malahov , Thomas Bogendoerfer , Paul Burton , Ralf Baechle , Arnd Bergmann , Olof Johansson , , Subject: [PATCH 6/6] soc: bt1: Add Baikal-T1 L2-cache Control Block driver Date: Fri, 6 Mar 2020 16:07:21 +0300 In-Reply-To: <20200306130721.10347-1-Sergey.Semin@baikalelectronics.ru> References: <20200306130721.10347-1-Sergey.Semin@baikalelectronics.ru> MIME-Version: 1.0 X-ClientProxiedBy: MAIL.baikal.int (192.168.51.25) To mail (192.168.51.25) Message-Id: <20200306130737.37A948030707@mail.baikalelectronics.ru> From: Serge Semin Baikal-T1 SoC provides a way to tune the MIPS P5600 CM2 L2-cache performance up. It can be done by changing the L2-RAM Data/Tag/WS latencies in a dedicated register exposed by the system controller. The driver added by this commit provides a dts properties-based and sysfs-based interface for it. Signed-off-by: Serge Semin Signed-off-by: Alexey Malahov Cc: Thomas Bogendoerfer Cc: Paul Burton Cc: Ralf Baechle Cc: Arnd Bergmann Cc: Olof Johansson Cc: soc@kernel.org --- drivers/soc/baikal-t1/Kconfig | 12 ++ drivers/soc/baikal-t1/Makefile | 1 + drivers/soc/baikal-t1/l2-ctl.c | 325 +++++++++++++++++++++++++++++++++ 3 files changed, 338 insertions(+) create mode 100644 drivers/soc/baikal-t1/l2-ctl.c diff --git a/drivers/soc/baikal-t1/Kconfig b/drivers/soc/baikal-t1/Kconfig index a021abea102f..b23675d4a097 100644 --- a/drivers/soc/baikal-t1/Kconfig +++ b/drivers/soc/baikal-t1/Kconfig @@ -34,4 +34,16 @@ config BT1_APB_EHB If unsure, say N. +config BT1_L2_CTL + bool "Baikal-T1 CM2 L2 Cache Control Block" + depends on SOC_BAIKAL_T1 && OF + help + Baikal-T1 CPU is based on the MIPS P5600 Warrior IP-core. The CPU + resides Coherency Manager V2 with embedded 1MB L2-cache. It's + possible to tune the L2 cache performance up by setting the data, + tags and way-select latencies. This driver provides a dts + properties-based and sysfs interface for it. + + If unsure, say N. + endmenu diff --git a/drivers/soc/baikal-t1/Makefile b/drivers/soc/baikal-t1/Makefile index ffb035600e01..70918b79e17f 100644 --- a/drivers/soc/baikal-t1/Makefile +++ b/drivers/soc/baikal-t1/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_BT1_AXI_EHB) += axi-ehb.o obj-$(CONFIG_BT1_APB_EHB) += apb-ehb.o +obj-$(CONFIG_BT1_L2_CTL) += l2-ctl.o diff --git a/drivers/soc/baikal-t1/l2-ctl.c b/drivers/soc/baikal-t1/l2-ctl.c new file mode 100644 index 000000000000..2136b9b8bad5 --- /dev/null +++ b/drivers/soc/baikal-t1/l2-ctl.c @@ -0,0 +1,325 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 BAIKAL ELECTRONICS, JSC + * + * Authors: + * Serge Semin + * + * Baikal-T1 CM2 L2-cache Control Block driver. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +#define L2_CTL_REG 0x0 +#define L2_CTL_DATA_STALL_FLD 0 +#define L2_CTL_DATA_STALL_MASK GENMASK(1, L2_CTL_DATA_STALL_FLD) +#define L2_CTL_TAG_STALL_FLD 2 +#define L2_CTL_TAG_STALL_MASK GENMASK(3, L2_CTL_TAG_STALL_FLD) +#define L2_CTL_WS_STALL_FLD 4 +#define L2_CTL_WS_STALL_MASK GENMASK(5, L2_CTL_WS_STALL_FLD) +#define L2_CTL_SET_CLKRATIO BIT(13) +#define L2_CTL_CLKRATIO_LOCK BIT(31) + +#define L2_CTL_STALL_MIN 0 +#define L2_CTL_STALL_MAX 3 +#define L2_CTL_STALL_SET_DELAY_US 1 +#define L2_CTL_STALL_SET_TOUT_US 1000 + +/* + * struct l2_ctl - Baikal-T1 L2 Control block private data. + * @dev: Pointer to the device structure. + * @reg: Regmap of the control register. + */ +struct l2_ctl { + struct device *dev; + + struct regmap *reg; +}; + +/* + * enum l2_ctl_stall - Baikal-T1 L2-cache-RAM stall identifier. + * @L2_WSSTALL: Way-select latency. + * @L2_TAGSTALL: Tag latency. + * @L2_DATASTALL: Data latency. + */ +enum l2_ctl_stall { + L2_WS_STALL, + L2_TAG_STALL, + L2_DATA_STALL +}; + +/* + * struct l2_ctl_device_attribute - Baikal-T1 L2-cache device attribute. + * @dev_attr: Actual sysfs device attribute. + * @id: L2-cache stall field identifier. + */ +struct l2_ctl_device_attribute { + struct device_attribute dev_attr; + enum l2_ctl_stall id; +}; +#define to_l2_ctl_dev_attr(_dev_attr) \ + container_of(_dev_attr, struct l2_ctl_device_attribute, dev_attr) + +#define L2_CTL_ATTR_RW(_name, _prefix, _id) \ + struct l2_ctl_device_attribute l2_ctl_attr_##_name = \ + { __ATTR(_name, 0644, _prefix##_show, _prefix##_store), _id } + +static int l2_ctl_get_latency(struct l2_ctl *l2, enum l2_ctl_stall id, u32 *val) +{ + u32 data = 0; + int ret; + + ret = regmap_read(l2->reg, L2_CTL_REG, &data); + if (ret) + return ret; + + switch (id) { + case L2_WS_STALL: + *val = BT1_GET_FLD(L2_CTL_WS_STALL, data); + break; + case L2_TAG_STALL: + *val = BT1_GET_FLD(L2_CTL_TAG_STALL, data); + break; + case L2_DATA_STALL: + *val = BT1_GET_FLD(L2_CTL_DATA_STALL, data); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int l2_ctl_set_latency(struct l2_ctl *l2, enum l2_ctl_stall id, u32 val) +{ + u32 mask = 0, data = 0; + int ret; + + val = clamp_val(val, L2_CTL_STALL_MIN, L2_CTL_STALL_MAX); + + switch (id) { + case L2_WS_STALL: + data = BT1_SET_FLD(L2_CTL_WS_STALL, 0, val); + mask = L2_CTL_WS_STALL_MASK; + break; + case L2_TAG_STALL: + data = BT1_SET_FLD(L2_CTL_TAG_STALL, 0, val); + mask = L2_CTL_TAG_STALL_MASK; + break; + case L2_DATA_STALL: + data = BT1_SET_FLD(L2_CTL_DATA_STALL, 0, val); + mask = L2_CTL_DATA_STALL_MASK; + break; + default: + return -EINVAL; + } + + data |= L2_CTL_SET_CLKRATIO; + mask |= L2_CTL_SET_CLKRATIO; + + ret = regmap_update_bits(l2->reg, L2_CTL_REG, mask, data); + if (ret) + return ret; + + return regmap_read_poll_timeout(l2->reg, L2_CTL_REG, data, + data & L2_CTL_CLKRATIO_LOCK, + L2_CTL_STALL_SET_DELAY_US, + L2_CTL_STALL_SET_TOUT_US); +} + +static void l2_ctl_clear_data(void *data) +{ + struct l2_ctl *l2 = data; + struct platform_device *pdev = to_platform_device(l2->dev); + + platform_set_drvdata(pdev, NULL); +} + +static struct l2_ctl *l2_ctl_create_data(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct l2_ctl *l2; + int ret; + + l2 = devm_kzalloc(dev, sizeof(*l2), GFP_KERNEL); + if (!l2) + return ERR_PTR(-ENOMEM); + + ret = devm_add_action(dev, l2_ctl_clear_data, l2); + if (ret) { + dev_err(dev, "Can't add L2 CTL data clear action\n"); + return ERR_PTR(ret); + } + + l2->dev = dev; + platform_set_drvdata(pdev, l2); + + return l2; +} + +static int l2_ctl_request_reg(struct l2_ctl *l2) +{ + l2->reg = device_node_to_regmap(l2->dev->of_node); + if (IS_ERR(l2->reg)) { + dev_err(l2->dev, "Couldn't get L2 CTL register map\n"); + return PTR_ERR(l2->reg); + } + + return 0; +} + +static int l2_ctl_of_parse_property(struct l2_ctl *l2, enum l2_ctl_stall id, + const char *propname) +{ + int ret = 0; + u32 data; + + if (of_property_read_u32(l2->dev->of_node, propname, &data)) { + ret = l2_ctl_set_latency(l2, id, data); + if (ret) + dev_err(l2->dev, "Invalid value of '%s'\n", propname); + } + + return ret; +} + +static int l2_ctl_of_parse(struct l2_ctl *l2) +{ + int ret; + + ret = l2_ctl_of_parse_property(l2, L2_WS_STALL, "be,l2-ws-latency"); + if (ret) + return ret; + + ret = l2_ctl_of_parse_property(l2, L2_TAG_STALL, "be,l2-tag-latency"); + if (ret) + return ret; + + return l2_ctl_of_parse_property(l2, L2_DATA_STALL, + "be,l2-data-latency"); +} + +static ssize_t l2_ctl_latency_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct l2_ctl_device_attribute *devattr = to_l2_ctl_dev_attr(attr); + struct l2_ctl *l2 = dev_get_drvdata(dev); + u32 data; + int ret; + + ret = l2_ctl_get_latency(l2, devattr->id, &data); + if (ret) + return ret; + + return scnprintf(buf, PAGE_SIZE, "%u\n", data); +} + +static ssize_t l2_ctl_latency_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct l2_ctl_device_attribute *devattr = to_l2_ctl_dev_attr(attr); + struct l2_ctl *l2 = dev_get_drvdata(dev); + u32 data; + int ret; + + if (kstrtouint(buf, 0, &data) < 0) + return -EINVAL; + + ret = l2_ctl_set_latency(l2, devattr->id, data); + if (ret) + return ret; + + return count; +} +static L2_CTL_ATTR_RW(l2_ws_latency, l2_ctl_latency, L2_WS_STALL); +static L2_CTL_ATTR_RW(l2_tag_latency, l2_ctl_latency, L2_TAG_STALL); +static L2_CTL_ATTR_RW(l2_data_latency, l2_ctl_latency, L2_DATA_STALL); + +static struct attribute *l2_ctl_sysfs_attrs[] = { + &l2_ctl_attr_l2_ws_latency.dev_attr.attr, + &l2_ctl_attr_l2_tag_latency.dev_attr.attr, + &l2_ctl_attr_l2_data_latency.dev_attr.attr, + NULL +}; +ATTRIBUTE_GROUPS(l2_ctl_sysfs); + +static void l2_ctl_remove_sysfs(void *data) +{ + struct l2_ctl *l2 = data; + + device_remove_groups(l2->dev, l2_ctl_sysfs_groups); +} + +static int l2_ctl_init_sysfs(struct l2_ctl *l2) +{ + int ret; + + ret = device_add_groups(l2->dev, l2_ctl_sysfs_groups); + if (ret) { + dev_err(l2->dev, "Failed to create L2 CTL sysfs nodes\n"); + return ret; + } + + ret = devm_add_action_or_reset(l2->dev, l2_ctl_remove_sysfs, l2); + if (ret) + dev_err(l2->dev, "Can't add L2 CTL sysfs remove action\n"); + + return ret; +} + +static int l2_ctl_probe(struct platform_device *pdev) +{ + struct l2_ctl *l2; + int ret; + + l2 = l2_ctl_create_data(pdev); + if (IS_ERR(l2)) + return PTR_ERR(l2); + + ret = l2_ctl_request_reg(l2); + if (ret) + return ret; + + ret = l2_ctl_of_parse(l2); + if (ret) + return ret; + + ret = l2_ctl_init_sysfs(l2); + if (ret) + return ret; + + dev_info(l2->dev, "L2-cache control driver installed\n"); + + return 0; +} + +static const struct of_device_id l2_ctl_of_match[] = { + { .compatible = "be,bt1-l2-ctl" }, + { } +}; +MODULE_DEVICE_TABLE(of, l2_ctl_of_match); + +static struct platform_driver l2_ctl_driver = { + .probe = l2_ctl_probe, + .driver = { + .name = "bt1-l2-ctl", + .of_match_table = of_match_ptr(l2_ctl_of_match) + } +}; +module_platform_driver(l2_ctl_driver); + +MODULE_AUTHOR("Serge Semin "); +MODULE_DESCRIPTION("Baikal-T1 L2-cache driver"); +MODULE_LICENSE("GPL v2");