From patchwork Tue Feb 16 18:27:33 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jae Hyun Yoo X-Patchwork-Id: 383478 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 40761C4332B for ; Tue, 16 Feb 2021 18:17:22 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0C31764E08 for ; Tue, 16 Feb 2021 18:17:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230177AbhBPSRT (ORCPT ); Tue, 16 Feb 2021 13:17:19 -0500 Received: from mga06.intel.com ([134.134.136.31]:16502 "EHLO mga06.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230216AbhBPSRQ (ORCPT ); Tue, 16 Feb 2021 13:17:16 -0500 IronPort-SDR: LuTuOoAOc9wbtdctAQNlsZYEKpVwdI27fXSTeTiB3nSTRChOxDPZwCk/dV5lMvA3ne8k6J+0Jl /SMJv3vhgfZQ== X-IronPort-AV: E=McAfee;i="6000,8403,9897"; a="244445806" X-IronPort-AV: E=Sophos;i="5.81,184,1610438400"; d="scan'208";a="244445806" Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 Feb 2021 10:15:30 -0800 IronPort-SDR: OyQu3WpKO2vLqv7favmSYirZxBTX4XTHykb5okGD9qQly6rU9VC3YJWkP2oKDrLPgbXKaxDRDJ pxny96myG1Yw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,184,1610438400"; d="scan'208";a="493376081" Received: from maru.jf.intel.com ([10.54.51.77]) by fmsmga001.fm.intel.com with ESMTP; 16 Feb 2021 10:15:29 -0800 From: Jae Hyun Yoo To: Brendan Higgins , Wolfram Sang , Benjamin Herrenschmidt , Joel Stanley , Rob Herring , Mark Rutland , Andrew Jeffery , Tao Ren , Cedric Le Goater Cc: linux-i2c@vger.kernel.org, devicetree@vger.kernel.org, linux-aspeed@lists.ozlabs.org, openbmc@lists.ozlabs.org, Jae Hyun Yoo Subject: [PATCH v3 2/4] ARM: dts: aspeed: modify I2C node to support buffer mode Date: Tue, 16 Feb 2021 10:27:33 -0800 Message-Id: <20210216182735.11639-3-jae.hyun.yoo@linux.intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210216182735.11639-1-jae.hyun.yoo@linux.intel.com> References: <20210216182735.11639-1-jae.hyun.yoo@linux.intel.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-i2c@vger.kernel.org This driver uses byte mode that makes lots of interrupt calls so it's not good for performance. Also, it makes the driver very timing sensitive. To improve performance of the driver, this commit modifies I2C node to support buffer mode which uses I2C SRAM buffer instead of using a single byte buffer. AST2400: It has 2 KBytes (256 Bytes x 8 pages) of I2C SRAM buffer pool from 0x1e78a800 to 0x1e78afff that can be used for all busses with buffer pool manipulation. To simplify implementation for supporting both AST2400 and AST2500, it assigns each 128 Bytes per bus without using buffer pool manipulation so total 1792 Bytes of I2C SRAM buffer will be used. AST2500: It has 16 Bytes of individual I2C SRAM buffer per each bus and its range is from 0x1e78a200 to 0x1e78a2df, so it doesn't have 'buffer page selection' bit field in the Function control register, and neither 'base address pointer' bit field in the Pool buffer control register it has. To simplify implementation for supporting both AST2400 and AST2500, it writes zeros on those register bit fields but it's okay because it does nothing in AST2500. AST2600: It has 32 Bytes of individual I2C SRAM buffer per each bus and its range is from 0x1e78ac00 to 0x1e78adff. Works just like AST2500 does. See Documentation/devicetree/bindings/i2c/i2c-aspeed.txt for enabling buffer mode details. Signed-off-by: Jae Hyun Yoo Reviewed-by: Cédric Le Goater Reviewed-by: Brendan Higgins --- Changes since v2: - Added SRAM resources back to default dtsi. Changes since v1: - Updated commit message. - Removed buffer reg settings to keep the default transfer mode as byte mode. arch/arm/boot/dts/aspeed-g4.dtsi | 47 +++++++++++++++++++------------- arch/arm/boot/dts/aspeed-g5.dtsi | 47 +++++++++++++++++++------------- arch/arm/boot/dts/aspeed-g6.dtsi | 32 +++++++++++----------- 3 files changed, 72 insertions(+), 54 deletions(-) diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi index b3dafbc8caca..cfa40dc66a5f 100644 --- a/arch/arm/boot/dts/aspeed-g4.dtsi +++ b/arch/arm/boot/dts/aspeed-g4.dtsi @@ -442,12 +442,21 @@ }; &i2c { - i2c_ic: interrupt-controller@0 { - #interrupt-cells = <1>; - compatible = "aspeed,ast2400-i2c-ic"; + i2c_gr: i2c-global-regs@0 { + compatible = "aspeed,ast2400-i2c-gr", "syscon"; reg = <0x0 0x40>; - interrupts = <12>; - interrupt-controller; + + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x0 0x40>; + + i2c_ic: interrupt-controller@0 { + #interrupt-cells = <1>; + compatible = "aspeed,ast2400-i2c-ic"; + reg = <0x0 0x4>; + interrupts = <12>; + interrupt-controller; + }; }; i2c0: i2c-bus@40 { @@ -455,7 +464,7 @@ #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x40 0x40>; + reg = <0x40 0x40>, <0x800 0x80>; compatible = "aspeed,ast2400-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB>; resets = <&syscon ASPEED_RESET_I2C>; @@ -471,7 +480,7 @@ #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x80 0x40>; + reg = <0x80 0x40>, <0x880 0x80>; compatible = "aspeed,ast2400-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB>; resets = <&syscon ASPEED_RESET_I2C>; @@ -487,7 +496,7 @@ #size-cells = <0>; #interrupt-cells = <1>; - reg = <0xc0 0x40>; + reg = <0xc0 0x40>, <0x900 0x80>; compatible = "aspeed,ast2400-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB>; resets = <&syscon ASPEED_RESET_I2C>; @@ -504,7 +513,7 @@ #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x100 0x40>; + reg = <0x100 0x40>, <0x980 0x80>; compatible = "aspeed,ast2400-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB>; resets = <&syscon ASPEED_RESET_I2C>; @@ -521,7 +530,7 @@ #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x140 0x40>; + reg = <0x140 0x40>, <0xa00 0x80>; compatible = "aspeed,ast2400-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB>; resets = <&syscon ASPEED_RESET_I2C>; @@ -538,7 +547,7 @@ #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x180 0x40>; + reg = <0x180 0x40>, <0xa80 0x80>; compatible = "aspeed,ast2400-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB>; resets = <&syscon ASPEED_RESET_I2C>; @@ -555,7 +564,7 @@ #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x1c0 0x40>; + reg = <0x1c0 0x40>, <0xb00 0x80>; compatible = "aspeed,ast2400-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB>; resets = <&syscon ASPEED_RESET_I2C>; @@ -572,7 +581,7 @@ #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x300 0x40>; + reg = <0x300 0x40>, <0xb80 0x80>; compatible = "aspeed,ast2400-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB>; resets = <&syscon ASPEED_RESET_I2C>; @@ -589,7 +598,7 @@ #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x340 0x40>; + reg = <0x340 0x40>, <0xc00 0x80>; compatible = "aspeed,ast2400-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB>; resets = <&syscon ASPEED_RESET_I2C>; @@ -606,7 +615,7 @@ #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x380 0x40>; + reg = <0x380 0x40>, <0xc80 0x80>; compatible = "aspeed,ast2400-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB>; resets = <&syscon ASPEED_RESET_I2C>; @@ -623,7 +632,7 @@ #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x3c0 0x40>; + reg = <0x3c0 0x40>, <0xd00 0x80>; compatible = "aspeed,ast2400-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB>; resets = <&syscon ASPEED_RESET_I2C>; @@ -640,7 +649,7 @@ #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x400 0x40>; + reg = <0x400 0x40>, <0xd80 0x80>; compatible = "aspeed,ast2400-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB>; resets = <&syscon ASPEED_RESET_I2C>; @@ -657,7 +666,7 @@ #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x440 0x40>; + reg = <0x440 0x40>, <0xe00 0x80>; compatible = "aspeed,ast2400-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB>; resets = <&syscon ASPEED_RESET_I2C>; @@ -674,7 +683,7 @@ #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x480 0x40>; + reg = <0x480 0x40>, <0xe80 0x80>; compatible = "aspeed,ast2400-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB>; resets = <&syscon ASPEED_RESET_I2C>; diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi index 5bc0de0f3365..f2ab94ed6878 100644 --- a/arch/arm/boot/dts/aspeed-g5.dtsi +++ b/arch/arm/boot/dts/aspeed-g5.dtsi @@ -565,12 +565,21 @@ }; &i2c { - i2c_ic: interrupt-controller@0 { - #interrupt-cells = <1>; - compatible = "aspeed,ast2500-i2c-ic"; + i2c_gr: i2c-global-regs@0 { + compatible = "aspeed,ast2500-i2c-gr", "syscon"; reg = <0x0 0x40>; - interrupts = <12>; - interrupt-controller; + + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0x0 0x40>; + + i2c_ic: interrupt-controller@0 { + #interrupt-cells = <1>; + compatible = "aspeed,ast2500-i2c-ic"; + reg = <0x0 0x4>; + interrupts = <12>; + interrupt-controller; + }; }; i2c0: i2c-bus@40 { @@ -578,7 +587,7 @@ #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x40 0x40>; + reg = <0x40 0x40>, <0x200 0x10>; compatible = "aspeed,ast2500-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB>; resets = <&syscon ASPEED_RESET_I2C>; @@ -594,7 +603,7 @@ #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x80 0x40>; + reg = <0x80 0x40>, <0x210 0x10>; compatible = "aspeed,ast2500-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB>; resets = <&syscon ASPEED_RESET_I2C>; @@ -610,7 +619,7 @@ #size-cells = <0>; #interrupt-cells = <1>; - reg = <0xc0 0x40>; + reg = <0xc0 0x40>, <0x220 0x10>; compatible = "aspeed,ast2500-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB>; resets = <&syscon ASPEED_RESET_I2C>; @@ -627,7 +636,7 @@ #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x100 0x40>; + reg = <0x100 0x40>, <0x230 0x10>; compatible = "aspeed,ast2500-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB>; resets = <&syscon ASPEED_RESET_I2C>; @@ -644,7 +653,7 @@ #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x140 0x40>; + reg = <0x140 0x40>, <0x240 0x10>; compatible = "aspeed,ast2500-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB>; resets = <&syscon ASPEED_RESET_I2C>; @@ -661,7 +670,7 @@ #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x180 0x40>; + reg = <0x180 0x40>, <0x250 0x10>; compatible = "aspeed,ast2500-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB>; resets = <&syscon ASPEED_RESET_I2C>; @@ -678,7 +687,7 @@ #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x1c0 0x40>; + reg = <0x1c0 0x40>, <0x260 0x10>; compatible = "aspeed,ast2500-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB>; resets = <&syscon ASPEED_RESET_I2C>; @@ -695,7 +704,7 @@ #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x300 0x40>; + reg = <0x300 0x40>, <0x270 0x10>; compatible = "aspeed,ast2500-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB>; resets = <&syscon ASPEED_RESET_I2C>; @@ -712,7 +721,7 @@ #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x340 0x40>; + reg = <0x340 0x40>, <0x280 0x10>; compatible = "aspeed,ast2500-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB>; resets = <&syscon ASPEED_RESET_I2C>; @@ -729,7 +738,7 @@ #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x380 0x40>; + reg = <0x380 0x40>, <0x290 0x10>; compatible = "aspeed,ast2500-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB>; resets = <&syscon ASPEED_RESET_I2C>; @@ -746,7 +755,7 @@ #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x3c0 0x40>; + reg = <0x3c0 0x40>, <0x2a0 0x10>; compatible = "aspeed,ast2500-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB>; resets = <&syscon ASPEED_RESET_I2C>; @@ -763,7 +772,7 @@ #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x400 0x40>; + reg = <0x400 0x40>, <0x2b0 0x10>; compatible = "aspeed,ast2500-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB>; resets = <&syscon ASPEED_RESET_I2C>; @@ -780,7 +789,7 @@ #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x440 0x40>; + reg = <0x440 0x40>, <0x2c0 0x10>; compatible = "aspeed,ast2500-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB>; resets = <&syscon ASPEED_RESET_I2C>; @@ -797,7 +806,7 @@ #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x480 0x40>; + reg = <0x480 0x40>, <0x2d0 0x10>; compatible = "aspeed,ast2500-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB>; resets = <&syscon ASPEED_RESET_I2C>; diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi index 810b0676ab03..2bec3abc6ac9 100644 --- a/arch/arm/boot/dts/aspeed-g6.dtsi +++ b/arch/arm/boot/dts/aspeed-g6.dtsi @@ -694,7 +694,7 @@ #address-cells = <1>; #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x80 0x80>; + reg = <0x80 0x80>, <0xc00 0x20>; compatible = "aspeed,ast2600-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB2>; resets = <&syscon ASPEED_RESET_I2C>; @@ -709,7 +709,7 @@ #address-cells = <1>; #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x100 0x80>; + reg = <0x100 0x80>, <0xc20 0x20>; compatible = "aspeed,ast2600-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB2>; resets = <&syscon ASPEED_RESET_I2C>; @@ -724,7 +724,7 @@ #address-cells = <1>; #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x180 0x80>; + reg = <0x180 0x80>, <0xc40 0x20>; compatible = "aspeed,ast2600-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB2>; resets = <&syscon ASPEED_RESET_I2C>; @@ -739,7 +739,7 @@ #address-cells = <1>; #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x200 0x80>; + reg = <0x200 0x80>, <0xc60 0x20>; compatible = "aspeed,ast2600-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB2>; resets = <&syscon ASPEED_RESET_I2C>; @@ -754,7 +754,7 @@ #address-cells = <1>; #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x280 0x80>; + reg = <0x280 0x80>, <0xc80 0x20>; compatible = "aspeed,ast2600-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB2>; resets = <&syscon ASPEED_RESET_I2C>; @@ -769,7 +769,7 @@ #address-cells = <1>; #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x300 0x80>; + reg = <0x300 0x80>, <0xca0 0x20>; compatible = "aspeed,ast2600-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB2>; resets = <&syscon ASPEED_RESET_I2C>; @@ -784,7 +784,7 @@ #address-cells = <1>; #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x380 0x80>; + reg = <0x380 0x80>, <0xcc0 0x20>; compatible = "aspeed,ast2600-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB2>; resets = <&syscon ASPEED_RESET_I2C>; @@ -799,7 +799,7 @@ #address-cells = <1>; #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x400 0x80>; + reg = <0x400 0x80>, <0xce0 0x20>; compatible = "aspeed,ast2600-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB2>; resets = <&syscon ASPEED_RESET_I2C>; @@ -814,7 +814,7 @@ #address-cells = <1>; #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x480 0x80>; + reg = <0x480 0x80>, <0xd00 0x20>; compatible = "aspeed,ast2600-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB2>; resets = <&syscon ASPEED_RESET_I2C>; @@ -829,7 +829,7 @@ #address-cells = <1>; #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x500 0x80>; + reg = <0x500 0x80>, <0xd20 0x20>; compatible = "aspeed,ast2600-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB2>; resets = <&syscon ASPEED_RESET_I2C>; @@ -844,7 +844,7 @@ #address-cells = <1>; #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x580 0x80>; + reg = <0x580 0x80>, <0xd40 0x20>; compatible = "aspeed,ast2600-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB2>; resets = <&syscon ASPEED_RESET_I2C>; @@ -859,7 +859,7 @@ #address-cells = <1>; #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x600 0x80>; + reg = <0x600 0x80>, <0xd60 0x20>; compatible = "aspeed,ast2600-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB2>; resets = <&syscon ASPEED_RESET_I2C>; @@ -874,7 +874,7 @@ #address-cells = <1>; #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x680 0x80>; + reg = <0x680 0x80>, <0xd80 0x20>; compatible = "aspeed,ast2600-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB2>; resets = <&syscon ASPEED_RESET_I2C>; @@ -889,7 +889,7 @@ #address-cells = <1>; #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x700 0x80>; + reg = <0x700 0x80>, <0xda0 0x20>; compatible = "aspeed,ast2600-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB2>; resets = <&syscon ASPEED_RESET_I2C>; @@ -904,7 +904,7 @@ #address-cells = <1>; #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x780 0x80>; + reg = <0x780 0x80>, <0xdc0 0x20>; compatible = "aspeed,ast2600-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB2>; resets = <&syscon ASPEED_RESET_I2C>; @@ -919,7 +919,7 @@ #address-cells = <1>; #size-cells = <0>; #interrupt-cells = <1>; - reg = <0x800 0x80>; + reg = <0x800 0x80>, <0xde0 0x20>; compatible = "aspeed,ast2600-i2c-bus"; clocks = <&syscon ASPEED_CLK_APB2>; resets = <&syscon ASPEED_RESET_I2C>; From patchwork Tue Feb 16 18:27:35 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jae Hyun Yoo X-Patchwork-Id: 383477 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1D4B5C433DB for ; Tue, 16 Feb 2021 18:18:36 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id DA08D64E28 for ; Tue, 16 Feb 2021 18:18:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230131AbhBPSSf (ORCPT ); Tue, 16 Feb 2021 13:18:35 -0500 Received: from mga06.intel.com ([134.134.136.31]:16491 "EHLO mga06.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230015AbhBPSSd (ORCPT ); Tue, 16 Feb 2021 13:18:33 -0500 IronPort-SDR: xbyN+s4TDCVoum6dJB3SCots//xd5Qaa9w+KARpc/5t2yKpPrmbH6C/vtm4npjx2IaPk/Nginx JkT88eCpTVXA== X-IronPort-AV: E=McAfee;i="6000,8403,9897"; a="244445825" X-IronPort-AV: E=Sophos;i="5.81,184,1610438400"; d="scan'208";a="244445825" Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 16 Feb 2021 10:15:32 -0800 IronPort-SDR: n1bdBO7d8l5CWqRaNlcAlRpLh9B2mdDSvs4raZx4/lfvdUrC5F3TcBw39KStAaBr7lXzNT0Ogg GRE3lsLGdQGQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,184,1610438400"; d="scan'208";a="493376179" Received: from maru.jf.intel.com ([10.54.51.77]) by fmsmga001.fm.intel.com with ESMTP; 16 Feb 2021 10:15:32 -0800 From: Jae Hyun Yoo To: Brendan Higgins , Wolfram Sang , Benjamin Herrenschmidt , Joel Stanley , Rob Herring , Mark Rutland , Andrew Jeffery , Tao Ren , Cedric Le Goater Cc: linux-i2c@vger.kernel.org, devicetree@vger.kernel.org, linux-aspeed@lists.ozlabs.org, openbmc@lists.ozlabs.org, Jae Hyun Yoo Subject: [PATCH v3 4/4] i2c: aspeed: add DMA mode transfer support Date: Tue, 16 Feb 2021 10:27:35 -0800 Message-Id: <20210216182735.11639-5-jae.hyun.yoo@linux.intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210216182735.11639-1-jae.hyun.yoo@linux.intel.com> References: <20210216182735.11639-1-jae.hyun.yoo@linux.intel.com> Precedence: bulk List-ID: X-Mailing-List: linux-i2c@vger.kernel.org This commit adds DMA mode transfer support. Only AST2500 and later versions support DMA mode. AST2500 has these restrictions: - If one of these controllers is enabled * UHCI host controller * MCTP controller I2C has to use buffer mode or byte mode instead since these controllers run only in DMA mode and I2C is sharing the same DMA H/W with them. - If one of these controllers uses DMA mode, I2C can't use DMA mode * SD/eMMC * Port80 snoop Signed-off-by: Jae Hyun Yoo --- Changes since v2: - Refined SoC family dependent xfer mode configuration functions. Changes since v1: - Updated commit message and comments. - Refined using abstract functions. drivers/i2c/busses/i2c-aspeed.c | 257 ++++++++++++++++++++++++++------ 1 file changed, 212 insertions(+), 45 deletions(-) diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c index 343e621ff133..304d08011ca7 100644 --- a/drivers/i2c/busses/i2c-aspeed.c +++ b/drivers/i2c/busses/i2c-aspeed.c @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include #include #include @@ -47,6 +49,8 @@ #define ASPEED_I2C_DEV_ADDR_REG 0x18 #define ASPEED_I2C_BUF_CTRL_REG 0x1c #define ASPEED_I2C_BYTE_BUF_REG 0x20 +#define ASPEED_I2C_DMA_ADDR_REG 0x24 +#define ASPEED_I2C_DMA_LEN_REG 0x28 /* Device Register Definition */ /* 0x00 : I2CD Function Control Register */ @@ -111,6 +115,8 @@ #define ASPEED_I2CD_BUS_RECOVER_CMD BIT(11) /* Command Bit */ +#define ASPEED_I2CD_RX_DMA_ENABLE BIT(9) +#define ASPEED_I2CD_TX_DMA_ENABLE BIT(8) #define ASPEED_I2CD_RX_BUFF_ENABLE BIT(7) #define ASPEED_I2CD_TX_BUFF_ENABLE BIT(6) #define ASPEED_I2CD_M_STOP_CMD BIT(5) @@ -136,6 +142,14 @@ #define ASPEED_I2CD_BUF_TX_COUNT_MASK GENMASK(15, 8) #define ASPEED_I2CD_BUF_OFFSET_MASK GENMASK(5, 0) +/* 0x24 : I2CD DMA Mode Buffer Address Register */ +#define ASPEED_I2CD_DMA_ADDR_MASK GENMASK(31, 2) +#define ASPEED_I2CD_DMA_ALIGN 4 + +/* 0x28 : I2CD DMA Transfer Length Register */ +#define ASPEED_I2CD_DMA_LEN_SHIFT 0 +#define ASPEED_I2CD_DMA_LEN_MASK GENMASK(11, 0) + enum aspeed_i2c_master_state { ASPEED_I2C_MASTER_INACTIVE, ASPEED_I2C_MASTER_PENDING, @@ -161,6 +175,7 @@ struct aspeed_i2c_config { u32 (*get_clk_reg_val)(struct device *dev, u32 divisor); int (*enable_sram)(void); int (*set_buf_xfer_mode)(struct device *dev); + int (*set_dma_xfer_mode)(struct device *dev); }; struct aspeed_i2c_bus { @@ -190,6 +205,12 @@ struct aspeed_i2c_bus { void __iomem *buf_base; u8 buf_offset; u8 buf_page; + /* DMA mode */ + struct dma_pool *dma_pool; + dma_addr_t dma_handle; + u8 *dma_buf; + size_t dma_len; + /* Buffer/DMA mode */ size_t buf_size; #if IS_ENABLED(CONFIG_I2C_SLAVE) struct i2c_client *slave; @@ -272,9 +293,13 @@ static inline void aspeed_i2c_slave_handle_rx_done(struct aspeed_i2c_bus *bus, u32 irq_status, u8 *value) { - if (bus->buf_base && + if (bus->dma_buf && bus->slave_state == ASPEED_I2C_SLAVE_WRITE_RECEIVED && !(irq_status & ASPEED_I2CD_INTR_NORMAL_STOP)) + *value = bus->dma_buf[0]; + else if (bus->buf_base && + bus->slave_state == ASPEED_I2C_SLAVE_WRITE_RECEIVED && + !(irq_status & ASPEED_I2CD_INTR_NORMAL_STOP)) *value = readb(bus->buf_base); else *value = readl(bus->base + ASPEED_I2C_BYTE_BUF_REG) >> 8; @@ -288,7 +313,18 @@ aspeed_i2c_slave_handle_normal_stop(struct aspeed_i2c_bus *bus, u32 irq_status, if (bus->slave_state == ASPEED_I2C_SLAVE_WRITE_RECEIVED && irq_status & ASPEED_I2CD_INTR_RX_DONE) { - if (bus->buf_base) { + if (bus->dma_buf) { + len = bus->buf_size - + FIELD_GET(ASPEED_I2CD_DMA_LEN_MASK, + readl(bus->base + + ASPEED_I2C_DMA_LEN_REG)); + for (i = 0; i < len; i++) { + *value = bus->dma_buf[i]; + i2c_slave_event(bus->slave, + I2C_SLAVE_WRITE_RECEIVED, + value); + } + } else if (bus->buf_base) { len = FIELD_GET(ASPEED_I2CD_BUF_RX_COUNT_MASK, readl(bus->base + ASPEED_I2C_BUF_CTRL_REG)); @@ -305,7 +341,14 @@ aspeed_i2c_slave_handle_normal_stop(struct aspeed_i2c_bus *bus, u32 irq_status, static inline void aspeed_i2c_slave_handle_write_requested(struct aspeed_i2c_bus *bus, u8 *value) { - if (bus->buf_base) { + if (bus->dma_buf) { + writel(bus->dma_handle & ASPEED_I2CD_DMA_ADDR_MASK, + bus->base + ASPEED_I2C_DMA_ADDR_REG); + writel(FIELD_PREP(ASPEED_I2CD_DMA_LEN_MASK, bus->buf_size), + bus->base + ASPEED_I2C_DMA_LEN_REG); + writel(ASPEED_I2CD_RX_DMA_ENABLE, + bus->base + ASPEED_I2C_CMD_REG); + } else if (bus->buf_base) { writel(FIELD_PREP(ASPEED_I2CD_BUF_RX_SIZE_MASK, bus->buf_size - 1) | FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, @@ -321,7 +364,23 @@ aspeed_i2c_slave_handle_write_received(struct aspeed_i2c_bus *bus, u8 *value) { int i, len; - if (bus->buf_base) { + if (bus->dma_buf) { + len = bus->buf_size - + FIELD_GET(ASPEED_I2CD_DMA_LEN_MASK, + readl(bus->base + + ASPEED_I2C_DMA_LEN_REG)); + for (i = 1; i < len; i++) { + *value = bus->dma_buf[i]; + i2c_slave_event(bus->slave, I2C_SLAVE_WRITE_RECEIVED, + value); + } + writel(bus->dma_handle & ASPEED_I2CD_DMA_ADDR_MASK, + bus->base + ASPEED_I2C_DMA_ADDR_REG); + writel(FIELD_PREP(ASPEED_I2CD_DMA_LEN_MASK, bus->buf_size), + bus->base + ASPEED_I2C_DMA_LEN_REG); + writel(ASPEED_I2CD_RX_DMA_ENABLE, + bus->base + ASPEED_I2C_CMD_REG); + } else if (bus->buf_base) { len = FIELD_GET(ASPEED_I2CD_BUF_RX_COUNT_MASK, readl(bus->base + ASPEED_I2C_BUF_CTRL_REG)); @@ -451,7 +510,15 @@ aspeed_i2c_prepare_rx_buf(struct aspeed_i2c_bus *bus, struct i2c_msg *msg) command |= ASPEED_I2CD_M_S_RX_CMD_LAST; } - if (bus->buf_base) { + if (bus->dma_buf) { + command |= ASPEED_I2CD_RX_DMA_ENABLE; + + writel(bus->dma_handle & ASPEED_I2CD_DMA_ADDR_MASK, + bus->base + ASPEED_I2C_DMA_ADDR_REG); + writel(FIELD_PREP(ASPEED_I2CD_DMA_LEN_MASK, len), + bus->base + ASPEED_I2C_DMA_LEN_REG); + bus->dma_len = len; + } else { command |= ASPEED_I2CD_RX_BUFF_ENABLE; writel(FIELD_PREP(ASPEED_I2CD_BUF_RX_SIZE_MASK, len - 1) | @@ -474,7 +541,18 @@ aspeed_i2c_prepare_tx_buf(struct aspeed_i2c_bus *bus, struct i2c_msg *msg) else len = msg->len + 1; - if (bus->buf_base) { + if (bus->dma_buf) { + command |= ASPEED_I2CD_TX_DMA_ENABLE; + + bus->dma_buf[0] = slave_addr; + memcpy(bus->dma_buf + 1, msg->buf, len); + + writel(bus->dma_handle & ASPEED_I2CD_DMA_ADDR_MASK, + bus->base + ASPEED_I2C_DMA_ADDR_REG); + writel(FIELD_PREP(ASPEED_I2CD_DMA_LEN_MASK, len), + bus->base + ASPEED_I2C_DMA_LEN_REG); + bus->dma_len = len; + } else { u8 wbuf[4]; int i; @@ -527,18 +605,19 @@ static void aspeed_i2c_do_start(struct aspeed_i2c_bus *bus) if (msg->flags & I2C_M_RD) { command |= ASPEED_I2CD_M_RX_CMD; if (!(msg->flags & I2C_M_RECV_LEN)) { - if (msg->len && bus->buf_base) + if (msg->len && (bus->dma_buf || bus->buf_base)) command |= aspeed_i2c_prepare_rx_buf(bus, msg); /* Need to let the hardware know to NACK after RX. */ if (msg->len <= 1) command |= ASPEED_I2CD_M_S_RX_CMD_LAST; } - } else if (msg->len && bus->buf_base) { + } else if (msg->len && (bus->dma_buf || bus->buf_base)) { command |= aspeed_i2c_prepare_tx_buf(bus, msg); } - if (!(command & ASPEED_I2CD_TX_BUFF_ENABLE)) + if (!(command & (ASPEED_I2CD_TX_BUFF_ENABLE | + ASPEED_I2CD_TX_DMA_ENABLE))) writel(i2c_8bit_addr_from_msg(msg), bus->base + ASPEED_I2C_BYTE_BUF_REG); writel(command, bus->base + ASPEED_I2C_CMD_REG); @@ -581,38 +660,51 @@ aspeed_i2c_master_handle_tx_first(struct aspeed_i2c_bus *bus, { u32 command = 0; - if (bus->buf_base) { - u8 wbuf[4]; + if (bus->dma_buf || bus->buf_base) { int len; - int i; if (msg->len - bus->buf_index > bus->buf_size) len = bus->buf_size; else len = msg->len - bus->buf_index; - command |= ASPEED_I2CD_TX_BUFF_ENABLE; + if (bus->dma_buf) { + command |= ASPEED_I2CD_TX_DMA_ENABLE; - if (msg->len - bus->buf_index > bus->buf_size) - len = bus->buf_size; - else - len = msg->len - bus->buf_index; + memcpy(bus->dma_buf, msg->buf + bus->buf_index, len); - for (i = 0; i < len; i++) { - wbuf[i % 4] = msg->buf[bus->buf_index + i]; - if (i % 4 == 3) + writel(bus->dma_handle & ASPEED_I2CD_DMA_ADDR_MASK, + bus->base + ASPEED_I2C_DMA_ADDR_REG); + writel(FIELD_PREP(ASPEED_I2CD_DMA_LEN_MASK, len), + bus->base + ASPEED_I2C_DMA_LEN_REG); + bus->dma_len = len; + } else { + u8 wbuf[4]; + int i; + + command |= ASPEED_I2CD_TX_BUFF_ENABLE; + + if (msg->len - bus->buf_index > bus->buf_size) + len = bus->buf_size; + else + len = msg->len - bus->buf_index; + + for (i = 0; i < len; i++) { + wbuf[i % 4] = msg->buf[bus->buf_index + i]; + if (i % 4 == 3) + writel(*(u32 *)wbuf, + bus->buf_base + i - 3); + } + if (--i % 4 != 3) writel(*(u32 *)wbuf, - bus->buf_base + i - 3); - } - if (--i % 4 != 3) - writel(*(u32 *)wbuf, - bus->buf_base + i - (i % 4)); + bus->buf_base + i - (i % 4)); - writel(FIELD_PREP(ASPEED_I2CD_BUF_TX_COUNT_MASK, - len - 1) | - FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, - bus->buf_offset), - bus->base + ASPEED_I2C_BUF_CTRL_REG); + writel(FIELD_PREP(ASPEED_I2CD_BUF_TX_COUNT_MASK, + len - 1) | + FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, + bus->buf_offset), + bus->base + ASPEED_I2C_BUF_CTRL_REG); + } bus->buf_index += len; } else { @@ -629,7 +721,14 @@ aspeed_i2c_master_handle_rx(struct aspeed_i2c_bus *bus, struct i2c_msg *msg) u8 recv_byte; int len; - if (bus->buf_base) { + if (bus->dma_buf) { + len = bus->dma_len - + FIELD_GET(ASPEED_I2CD_DMA_LEN_MASK, + readl(bus->base + ASPEED_I2C_DMA_LEN_REG)); + + memcpy(msg->buf + bus->buf_index, bus->dma_buf, len); + bus->buf_index += len; + } else if (bus->buf_base) { len = FIELD_GET(ASPEED_I2CD_BUF_RX_COUNT_MASK, readl(bus->base + ASPEED_I2C_BUF_CTRL_REG)); memcpy_fromio(msg->buf + bus->buf_index, bus->buf_base, len); @@ -646,7 +745,7 @@ aspeed_i2c_master_handle_rx_next(struct aspeed_i2c_bus *bus, { u32 command = 0; - if (bus->buf_base) { + if (bus->dma_buf || bus->buf_base) { int len; if (msg->len - bus->buf_index > bus->buf_size) { @@ -656,14 +755,24 @@ aspeed_i2c_master_handle_rx_next(struct aspeed_i2c_bus *bus, command |= ASPEED_I2CD_M_S_RX_CMD_LAST; } - command |= ASPEED_I2CD_RX_BUFF_ENABLE; + if (bus->dma_buf) { + command |= ASPEED_I2CD_RX_DMA_ENABLE; - writel(FIELD_PREP(ASPEED_I2CD_BUF_RX_SIZE_MASK, - len - 1) | - FIELD_PREP(ASPEED_I2CD_BUF_TX_COUNT_MASK, 0) | - FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, - bus->buf_offset), - bus->base + ASPEED_I2C_BUF_CTRL_REG); + writel(bus->dma_handle & ASPEED_I2CD_DMA_ADDR_MASK, + bus->base + ASPEED_I2C_DMA_ADDR_REG); + writel(FIELD_PREP(ASPEED_I2CD_DMA_LEN_MASK, len), + bus->base + ASPEED_I2C_DMA_LEN_REG); + bus->dma_len = len; + } else { + command |= ASPEED_I2CD_RX_BUFF_ENABLE; + + writel(FIELD_PREP(ASPEED_I2CD_BUF_RX_SIZE_MASK, + len - 1) | + FIELD_PREP(ASPEED_I2CD_BUF_TX_COUNT_MASK, 0) | + FIELD_PREP(ASPEED_I2CD_BUF_OFFSET_MASK, + bus->buf_offset), + bus->base + ASPEED_I2C_BUF_CTRL_REG); + } } else { if (bus->buf_index + 1 == msg->len) command |= ASPEED_I2CD_M_S_RX_CMD_LAST; @@ -1283,22 +1392,63 @@ static int aspeed_i2c_25xx_set_buf_xfer_mode(struct device *dev) return bus->buf_size ? 0 : -EINVAL; } +static int aspeed_i2c_24xx_set_dma_xfer_mode(struct device *dev) +{ + /* AST24xx doesn't support DMA mode */ + + return -EBADR; +} + +static int aspeed_i2c_25xx_set_dma_xfer_mode(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct aspeed_i2c_bus *bus = platform_get_drvdata(pdev); + int ret; + + ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); + if (!ret) { + bus->buf_size = ASPEED_I2CD_DMA_LEN_MASK >> + ASPEED_I2CD_DMA_LEN_SHIFT; + bus->dma_pool = dma_pool_create("i2c-aspeed", + &pdev->dev, + bus->buf_size, + ASPEED_I2CD_DMA_ALIGN, + 0); + if (bus->dma_pool) + bus->dma_buf = dma_pool_alloc(bus->dma_pool, + GFP_KERNEL, + &bus->dma_handle); + + if (!bus->dma_buf) { + ret = -ENOMEM; + bus->buf_size = 0; + dev_dbg(&pdev->dev, "Cannot allocate DMA buffer\n"); + dma_pool_destroy(bus->dma_pool); + } + } + + return ret; +} + static const struct aspeed_i2c_config ast24xx_config = { .get_clk_reg_val = aspeed_i2c_24xx_get_clk_reg_val, .enable_sram = aspeed_i2c_24xx_enable_sram, .set_buf_xfer_mode = aspeed_i2c_24xx_set_buf_xfer_mode, + .set_dma_xfer_mode = aspeed_i2c_24xx_set_dma_xfer_mode, }; static const struct aspeed_i2c_config ast25xx_config = { .get_clk_reg_val = aspeed_i2c_25xx_get_clk_reg_val, .enable_sram = aspeed_i2c_25xx_enable_sram, .set_buf_xfer_mode = aspeed_i2c_25xx_set_buf_xfer_mode, + .set_dma_xfer_mode = aspeed_i2c_25xx_set_dma_xfer_mode, }; static const struct aspeed_i2c_config ast26xx_config = { .get_clk_reg_val = aspeed_i2c_25xx_get_clk_reg_val, .enable_sram = aspeed_i2c_24xx_enable_sram, .set_buf_xfer_mode = aspeed_i2c_25xx_set_buf_xfer_mode, + .set_dma_xfer_mode = aspeed_i2c_25xx_set_dma_xfer_mode, }; static const struct of_device_id aspeed_i2c_bus_of_table[] = { @@ -1320,8 +1470,12 @@ static void aspeed_i2c_set_xfer_mode(struct aspeed_i2c_bus *bus) return; ret = bus->config->enable_sram(); - if (!ret && !strncasecmp(mode, "buf", 3)) - ret = bus->config->set_buf_xfer_mode(bus->dev); + if (!ret) { + if (!strncasecmp(mode, "buf", 3)) + ret = bus->config->set_buf_xfer_mode(bus->dev); + else if (!strncasecmp(mode, "dma", 3)) + ret = bus->config->set_dma_xfer_mode(bus->dev); + } if (ret) dev_dbg(&pdev->dev, "Use default (byte) xfer mode\n"); @@ -1396,22 +1550,31 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) */ ret = aspeed_i2c_init(bus, pdev); if (ret < 0) - return ret; + goto out_free_dma_buf; irq = irq_of_parse_and_map(pdev->dev.of_node, 0); ret = devm_request_irq(&pdev->dev, irq, aspeed_i2c_bus_irq, 0, dev_name(&pdev->dev), bus); if (ret < 0) - return ret; + goto out_free_dma_buf; ret = i2c_add_adapter(&bus->adap); if (ret < 0) - return ret; + goto out_free_dma_buf; dev_info(bus->dev, "i2c bus %d registered (%s mode), irq %d\n", - bus->adap.nr, bus->buf_base ? "buf" : "byte", irq); + bus->adap.nr, bus->dma_buf ? "dma" : + bus->buf_base ? "buf" : "byte", + irq); return 0; + +out_free_dma_buf: + if (bus->dma_buf) + dma_pool_free(bus->dma_pool, bus->dma_buf, bus->dma_handle); + dma_pool_destroy(bus->dma_pool); + + return ret; } static int aspeed_i2c_remove_bus(struct platform_device *pdev) @@ -1429,6 +1592,10 @@ static int aspeed_i2c_remove_bus(struct platform_device *pdev) reset_control_assert(bus->rst); + if (bus->dma_buf) + dma_pool_free(bus->dma_pool, bus->dma_buf, bus->dma_handle); + dma_pool_destroy(bus->dma_pool); + i2c_del_adapter(&bus->adap); return 0;