From patchwork Tue Jun 6 11:24:20 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yoshihiro Shimoda X-Patchwork-Id: 9768667 X-Patchwork-Delegate: geert@linux-m68k.org Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 54C126034B for ; Tue, 6 Jun 2017 11:27:17 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 403852818A for ; Tue, 6 Jun 2017 11:27:17 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 345842841E; Tue, 6 Jun 2017 11:27:17 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D00A12818A for ; Tue, 6 Jun 2017 11:27:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751384AbdFFL1P (ORCPT ); Tue, 6 Jun 2017 07:27:15 -0400 Received: from relmlor4.renesas.com ([210.160.252.174]:20208 "EHLO relmlie3.idc.renesas.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1751305AbdFFL1N (ORCPT ); Tue, 6 Jun 2017 07:27:13 -0400 Received: from unknown (HELO relmlir3.idc.renesas.com) ([10.200.68.153]) by relmlie3.idc.renesas.com with ESMTP; 06 Jun 2017 20:27:11 +0900 Received: from relmlii1.idc.renesas.com (relmlii1.idc.renesas.com [10.200.68.65]) by relmlir3.idc.renesas.com (Postfix) with ESMTP id E7CED736DE; Tue, 6 Jun 2017 20:27:10 +0900 (JST) X-IronPort-AV: E=Sophos;i="5.39,306,1493650800"; d="scan'208";a="245567551" Received: from mail-ty1jpn01lp0175.outbound.protection.outlook.com (HELO JPN01-TY1-obe.outbound.protection.outlook.com) ([23.103.139.175]) by relmlii1.idc.renesas.com with ESMTP/TLS/AES256-SHA256; 06 Jun 2017 20:27:10 +0900 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=renesasgroup.onmicrosoft.com; s=selector1-renesas-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version; bh=9SwAhpVifoAdhZDJnPzikzf7pA2Q+aSUCWtR5C2I6CY=; b=ROK9LdQ3DETHC8+9CRk5w0aGdLHqbPz/M0sQTcnUMvrOUogeOOC/1E90ybR3XHVTEsSsxNjAd61jX3TCs1bpnj+TW2rS/HiycVDW5G1XE7y9/kDw+Xt0hFxujq/+qxTFG5EYE+ZYuautTmb1krkfv4X0jlFPGTAWqvgthU3Lpl4= Authentication-Results: kernel.org; dkim=none (message not signed) header.d=none; kernel.org; dmarc=none action=none header.from=renesas.com; Received: from localhost.localdomain (211.11.155.144) by TY1PR06MB0990.apcprd06.prod.outlook.com (10.164.99.24) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1143.10; Tue, 6 Jun 2017 11:27:06 +0000 From: Yoshihiro Shimoda To: CC: , , , Yoshihiro Shimoda Subject: [PATCH v2] usb: gadget: udc: renesas_usb3: add support for dedicated DMAC Date: Tue, 6 Jun 2017 20:24:20 +0900 Message-ID: <1496748260-19664-1-git-send-email-yoshihiro.shimoda.uh@renesas.com> X-Mailer: git-send-email 1.9.1 MIME-Version: 1.0 X-Originating-IP: [211.11.155.144] X-ClientProxiedBy: SG2PR0302CA0007.apcprd03.prod.outlook.com (10.170.129.17) To TY1PR06MB0990.apcprd06.prod.outlook.com (10.164.99.24) X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: TY1PR06MB0990: X-MS-Office365-Filtering-Correlation-Id: feca4151-a83a-4684-5315-08d4accef715 X-MS-Office365-Filtering-HT: Tenant X-Microsoft-Antispam: UriScan:; BCL:0; PCL:0; RULEID:(22001)(48565401081)(201703131423075)(201703031133081); SRVR:TY1PR06MB0990; X-Microsoft-Exchange-Diagnostics: 1; TY1PR06MB0990; 3:yingvr+ren5qeg4Tm7cHlh6YWHdnPS6tfvN5pgRB6C02ecJ4s47mpfRNekil6Rj4L0o39XZr3OrQd1xc/gVWkv/jD+Ebx95MmkN3dxRWgc6pR3oxTlxvUlue061dCzfDpIj/2KYpqOL40YlxCc5nvWZAB7dksCJLqrPpmk3X/tJtnXi0mR1RyGnw3lOQgEwPtJbtnHcPRY7898tYOZglgWWejWWf1HPKoNoeBsqEWaGBNrYICx/nWnAnbu1/TvdXE/6zXEBJNxBXdteav3DQ3AcFpv7Q8m5fsFZxDzTKucWWL3A4cHD7EUdLnQPY+3/oMLqpqKRXk8IpNpFQycM9LWHhCvqOaHZ+eaYAeK8WBCo=; 25:Z2W3mFVVv3hVusmOveiGpfsGEVRY1rPSYpUMlNZ9ogpBaGiZR5aPwZ06LRSRx3VJCJOpTAEAyIoCM2OGV0Iy+yi0E/R/GaI+Xu6SVUyN/WdaxFVhy/G9bawc3TOs2G92rLC+nm9W4zLEnSgwXQuaSYXxbsvw7Sbnb9B4ZO9UtpVrT5L4RgZYN3t0qpRQmQo3NdKRcSEyPa0EBl+W6s0mr7bzpH7xG3UckiJZxSyU19jKXusuxT1NwGda5XMwP+SwLpy9pnuPilGrKgRorgLU9WI3C9ujFD9mw08rnI+s6Kp8gvpjaMUDxYeyVjTFJyKo0QjVpwSuvynVkN0PgKs4K/zhlzJESj3JDAlARvoMDXOcxufpM61eA3Ol+9YsE72GB1og38Kp/UdTbMM15KTnz3mfHROCvIzDx/fmo5BpqanT3eH+1FELG6vBfOjQCIjli9a61qWHUR5/0G++qFWyckM/Zf78mffcwnQehDpXckU= X-Microsoft-Exchange-Diagnostics: 1; TY1PR06MB0990; 31:0+hKEqHbd2h4CGEOiu188I/92A7EKMa5LnloxXHh+91fiXZXNJphHpz7Ny+H4/nVr9tMzZ8mrZU1FhQdH5DuPdYqEk3ugNhti/osZIg9BbjwNkJeMsqBtD4M58yjamuyBfmFDSJ9FNWfM9AsAkb+WbeOmpPreT/CDQe6gcjf0pnSeu9TrFyGJOeRZZ87BFS/DIiktPLWbRaMeXm5kFJRChxT7+4cye73LrTkBtjkB9o=; 20:P5Hkgg4vzfH2qo4YbcTLMbzppKOeibdxrT8XzGP8rq5JnwyNd8/Co4a7ONJjd8JIsf+Yx99HU7emZrz6q7qI3qZ7aF9IL0yhF9NARoE1VviBtIKwCizzJV3KAd1NZaaya1bSyu/dlgbcam/kC8iMKvVx0VUBCyAx1jsiSofp9uODb4nxZJ2qMCu0MCa8pZs70VgYaG8bTtPxpcMjSa8Rj7xdkOvkYU28R1Fj8v/36J015D9OgV6UG0xfiLkhsAklkHVMvngddGVJt9JwtI4hYGcA+eg5yrFETVscMl2mk8J9OGCm2UAD0Wpw7wJ567W6ZesmhSDHVgooSw0JsqxwzCS7UTCuGINPs5xhuGvFNPheSjIr9XwxvH6l+RWdsrUBriFub1QDOtMBnX/b9jTTTnSf1Oj3OvNLeJIKF3ItjczK6DAPPQqMFZoJlOm0jBNdAXIZSkEWKAesHpB3LdCaTyi6iQXpp0HW3qKfC7kaiCEnFpEiowJt5d72nRfxXcen X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(100000700101)(100105000095)(100000701101)(100105300095)(100000702101)(100105100095)(6040450)(601004)(2401047)(8121501046)(5005006)(93006095)(10201501046)(3002001)(100000703101)(100105400095)(6055026)(6041248)(20161123558100)(201703131423075)(201702281528075)(201703061421075)(201703061750153)(20161123560025)(20161123562025)(20161123564025)(20161123555025)(6072148)(100000704101)(100105200095)(100000705101)(100105500095); SRVR:TY1PR06MB0990; BCL:0; PCL:0; RULEID:(100000800101)(100110000095)(100000801101)(100110300095)(100000802101)(100110100095)(100000803101)(100110400095)(100000804101)(100110200095)(100000805101)(100110500095); SRVR:TY1PR06MB0990; X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; TY1PR06MB0990; 4:rm98IUw6Vd9Zh9cTogZiZKps4L7XbgpSM/VQAYk9tg?= =?us-ascii?Q?Th8ZXtAH8aoxyAbxYY71HjuvuqmzvQtzn0iP9LJ41AQ1ZobhJXl68nn9E028?= =?us-ascii?Q?s+zFhBwITz159WB0PhNar7PVyAv6RoQzrsjTM9IKFWPRlc0BXBZhzgiO5l8T?= =?us-ascii?Q?QGK3VMnjxv9HtpQEuMqvqbDrobBLKZltMUbYK/N37T/7+4R/U8iCtnHgQFCv?= =?us-ascii?Q?M969QNOM9TwIPwcSxibsEy/2yeycFrHXtZC5cZy67SPnvc4Jqzazth+ml0Bp?= =?us-ascii?Q?NRWqqN3aCzyPW7EPRc02HwWfSo/W62gmFOXKhFAMN3vxEnfUNT8uYGdyaikK?= =?us-ascii?Q?kIxwgOOHY2o2CXNn0vaWIUQoaeY8+9hL/GU76gcAI+4bSC0eHR7BLVZbaQun?= =?us-ascii?Q?Ds6OGRKDKaCVjqExb7J9BJdHjc1APyJb2Sp6ZaMHDkWHiodqFmnJexzC9lbU?= =?us-ascii?Q?hv/fDuHSJ2JfzewmUM7wW6MWYBxPYy00DFYNu2jCny+sXKoFmQpL4FbXuYKN?= =?us-ascii?Q?GjAnPyoBzXYB3JqWCbENqoS+DxE6/Vse+9CtBGvnRJ0PtD1tFIyzviHtfZ7s?= =?us-ascii?Q?LFvOmY24y0QuSi2XVD3NP7UNDmvraXEoS5+fpbyGtlHp89CV3FL3rDlDp51L?= =?us-ascii?Q?dI9FYVSol6r7vhc/5zegrt5+pOakRcb72oBxRIZWCB++BJpQGug50z2ubE86?= =?us-ascii?Q?6KxJAfQDLGM+3DErmHMuAmcZEHxb+VSqpjT2c5XQYk9KFkasjLZIf/0dSrVY?= =?us-ascii?Q?eO3DuDnMaFjqDD5Nf8v8qsjX64bEPlW2uo1Qv6sdOPksMDhVe+gBr5pgJiX7?= =?us-ascii?Q?sdfZJr3hHxsxBv1ou6bX0R58Dekl8My489KbUZwLh/QtGKKLidplqWTa0Lto?= =?us-ascii?Q?Us4OZfXp2iYBJkCnTs/9fgwkmleZ2Etfj17HFcQu0G+YJm4MYvH7Hyh0FIjp?= =?us-ascii?Q?WvWM/vmL1vwlwfyrt0QqU9WdGQRLCyUzWFMjH4uNG1m10PjXpXUBKZ0Lr7zn?= =?us-ascii?Q?icvKOnvbLRqeECPR4i+0yHY/fvrX0MZtkSDgsZngVFbdJOAx8DwcLty7Zt6q?= =?us-ascii?Q?kb/Tdsy/Yv3oBOcWJxrhyS8bgg7bQN8NcyHAzvL8SIL1JO5RX9xUaVdZ8r94?= =?us-ascii?Q?NRU8HNATsIojqMBwA55oCmh9S+mhQO?= X-Forefront-PRVS: 033054F29A X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10019020)(4630300001)(6069001)(6009001)(39850400002)(39410400002)(39450400003)(39860400002)(39400400002)(39840400002)(51234002)(3846002)(42186005)(2906002)(5003940100001)(4326008)(50986999)(6116002)(78352004)(6916009)(5660300001)(25786009)(50226002)(7736002)(2351001)(36756003)(47776003)(8676002)(66066001)(81166006)(33646002)(6486002)(189998001)(305945005)(6506006)(498600001)(48376002)(53936002)(575784001)(38730400002)(110136004)(107886003)(42882006)(6512007)(6666003)(54906002)(50466002); DIR:OUT; SFP:1102; SCL:1; SRVR:TY1PR06MB0990; H:localhost.localdomain; FPR:; SPF:None; MLV:ovrnspm; PTR:InfoNoRecords; LANG:en; X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; TY1PR06MB0990; 23:8RuO7Agc/TKDhdZ5xP6GUgDMFwTR0OuOHicuhh9wj?= =?us-ascii?Q?AXosLeeHgavOtAEF2quXIEqRZbRFqe7Wz8RlD7Ev5DWcAQZT6ADX99GFqNQ3?= =?us-ascii?Q?zIC37+anm5I/nHDQ7s4ElIpu0WKdhAeNeI6Ft+54XPtNc9dmtufiqYDwHKzU?= =?us-ascii?Q?C6OPSf3CStiTDnHQexTWJPqA1QVH7gRoRTvT7QuH/piWXzUpkuHsqAQPlAaH?= =?us-ascii?Q?VjgkmM75r5Nnmz2d28HSY49boRQBTLtBVjY9YoILNXw+5PYxedtDlQnTHmZj?= =?us-ascii?Q?5bbPNu/SSNigkoi0Imxg7cCpA2M7ZgM7XrSJCJxrT6+EQZUoYrni2Alg6vlB?= =?us-ascii?Q?8boJb6QfGKQWSLo+89lxF//+Hqw/Tt9WEa+hT0rprnr4zVgvNeP5eps1LrpR?= =?us-ascii?Q?pFm0X+77NMuD39veXMwMdPnMWGEhyRCtTMHJnpWFDqbX76/YDNPh3P2HfkSL?= =?us-ascii?Q?Fw9OHbJ0+ND7jniCu+pK8bZF9xJ0SfMBXEdb12zctpkLOQNVXFuUQ0sJ4umG?= =?us-ascii?Q?4C1C93/hj/6Pb1sCjIBfXQ0x7aAiFEB6IWpGbOIf1JMFvG2daLknO5/meQec?= =?us-ascii?Q?uqdPheGkVgvc+LeN36hEeGHZ3muRwFpydKRQXulcW37oRsvKcLQRi2LjaQ5I?= =?us-ascii?Q?q1KGKFftpjxJ9k6LB0mM7j1rh2tqc546TyqqlkdW0gpWr91p5XMsdJJhEspU?= =?us-ascii?Q?AA3e5DMbijdRqjlSV/cY+rFJIeEz7CVW6Vrtvzw/Ns+x8HZ+bjqZ2vHR+QDw?= =?us-ascii?Q?DYArCtSnzv6eFsuzdm1Vgo5Xubq1KSCtlu/wIyNe7D+jI0nqW58XzNHYBee3?= =?us-ascii?Q?KzEA6x0iRJlU0HQ2tcyMo91w3h2KasVqZtagU83moBJz7QaSoMV7KfJKN0xU?= =?us-ascii?Q?+IlFtwzqcKbg6jv80O0zb+m5LrHuz9wYYN9WF+vzeOnKVQXRW0+debG9Qzzf?= =?us-ascii?Q?bFo8F36sDxlw6GmSYFZBwToZrYjATB2o1InV4Aimc0tCAI0kvVzdUUw8uX8b?= =?us-ascii?Q?65SNYi66O1kW+wjNPmV1uOIi6755zZ9GtoC90QqqW8ahnYEK8KpTo7KPGILw?= =?us-ascii?Q?GRYxwhiyJUxdq+q7vu93akjpaTnf6fAlII/wyl64DGJuwfaCTYXQHWbTOdkM?= =?us-ascii?Q?PK4F/F1G4uWbvy/FhtcUes05hPfQb0Dt3Gmj8xVtTBDI/BuTZN3rg=3D=3D?= X-Microsoft-Exchange-Diagnostics: 1; TY1PR06MB0990; 6:z8N+/QsflB44BgyLFG1zzFxyQuxdvxVi79BIIPUkrPXnhoVjHcpC5q9zCNf1JPnml2jIVfCXPFDyVAUleIcGPrUokhy3yJJu57juKQW3hALPL/80IK8qxvMHaTOer05rMR95px3fm7Z/4L47naoBTuDPsvTMSHxNyc0pdg//GNd0IIwfDuVFie+q+LGGBMXN7lHOqEMVd1O7lehs1/jKPufWnOgPPOpzu18FGOrIl1oxCp34LzLkvNMQMvHZi2dIqxuTT0Y7wasIPZ9Y0AW1KJjwcnyPYTNnYXTsQya+XpQTahqfO2wqXXT+6MSUHvYzjMXKXhFGo+H5vmqYTT8LqLPdAsB3Dn+pvme/pxGfmbhREdwwbCXxf1PNlIGfyMYd4hx2Es04g/EHCA0DbL4MMoeuQDxuuizr6oZLlUG2xDySGwQXufSFek1OkEOWHJ4ar0X3BQUYPg3grjBSCqovE8SDDfSfVLzqZFMOhcA2wXG09sGvKhQbrY7k17ew6l2tZn8J+xJhjMiUBm5XDIxP+lT6Npv7WMCqugG4NR26vBylzLvxutw1XxSu/Is8IdynjAJF2IpcjcalzLULfNOzCA== X-Microsoft-Exchange-Diagnostics: 1; TY1PR06MB0990; 5:O13fVH9jB6NlXOXnlNy6f1MCRlVLb1/dSp/LyhcKUIqU+YYZ55whC+tKoGxzjxe/tcyfRnagk9MFYfaenBwEaEZ8COVGGKPbcWKCI16neuZMPRkjgNDrQH+Zlnc0K0BkJFRmgLczbF+VrUJvMzSc9JJktTLV1dbJVWVfIEeNKEcx9DVA4w02uiHyfuP7czdx73neDUKPexti3j0sVYflpp7gDt6+1y6M99mloh2CzyJjQG5GZOQbxt9lI81gjC9rMKWjhYJ9M3m7Y8skATW17O668DquFVxczblmvxWc2RGNV0Avy+UsaO5ahwDY1L+Ms9I4iJK0kfZHB394pMEv4WYqjYmRQeL+e8HguvvsD89exycMRi5O5vKigAOEMf+jWZmhVz3fPTEamKpcdUBBv5iHUDJDlku4eSrq/g/n018I4dYA7uXt0x2IsLpqHp2JG0KcQ+R5KCyYmt6GwzTUA3aXUAP7QDysBsmN9N9lt1cKspRNciyC8CdtZT5MTRZP; 24:HfSl6WSJdy8Zhiv/PVAD2sRqI5wlAuhwShq/wpwVkKzToXZ39qmpuVVUqDOXKLL+8eTworYtlnN+YI1eU/xsFVIldMEsw0cJNHUyvEeBl8c= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1; TY1PR06MB0990; 7:henUCoLtBuAF8teGyzqAgEHlXRl3rbUJsSvuGTMcuHEV9DWR3hnpgusZZJnxPUrO1HAU/XofOdxwstXRCp/oyW030H5MtuURcUndUfzY7585RIT1S5la0KL/fryorwLat8idKsnoLXOURj6J/fhdl71mWIg7LC5h+fi3Iic1E4jaeWGaYCcJFXjXODJFBNNgndtex8CT1+D4j0eT+hM/Ian3fCqc4sNVTkU3E0OseOeAibWDCTKzAOa43CJ3HdtHf9I0JHKtVc9wee2ZhzHwAX9ujtjEMsW0r+oVqEkgqygEXhTcGofnQdm6kpynrBP4SlPkpIpWllkMH0YreUs22A==; 20:JBhRkOsox8BvOjct4AwYt49KiErQaW7AQVtH7kBrIxaAVJfZIbrNmveEh1QzyFafpVyCXGN1a2c4XCz3nCROYyft1pgt7EvJ9mxZOHkl4eGfUxDPc1v/flK6dvvVPHegBC211dlklGB93C0y0SGkoezYfgSQWHMw9hkmftXHjiE= X-OriginatorOrg: renesas.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 06 Jun 2017 11:27:06.3129 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: TY1PR06MB0990 Sender: linux-renesas-soc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-renesas-soc@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The USB3.0 peripheral controller on R-Car SoCs has a dedicated DMAC. The DMAC needs a "PRD table" in system memory and the DMAC can have four PRD tables. This patch adds support for the DMAC. Signed-off-by: Yoshihiro Shimoda --- This patch based on the latest Felipe's usb.git / testing/next branch (the commit id = ad9721fbf4c4dd7e57372662b91adb8ba0c3a9fc). Changes from v1: - Rebase the latest testing/next branch. - Remove adding a blank line. - Remove some patches for fix because they was merged on testing/fix (Thanks!). drivers/usb/gadget/udc/renesas_usb3.c | 392 ++++++++++++++++++++++++++++++++++ 1 file changed, 392 insertions(+) diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c index 5a2d845..078f773 100644 --- a/drivers/usb/gadget/udc/renesas_usb3.c +++ b/drivers/usb/gadget/udc/renesas_usb3.c @@ -9,6 +9,7 @@ */ #include +#include #include #include #include @@ -27,6 +28,8 @@ #define USB3_AXI_INT_ENA 0x00c #define USB3_DMA_INT_STA 0x010 #define USB3_DMA_INT_ENA 0x014 +#define USB3_DMA_CH0_CON(n) (0x030 + ((n) - 1) * 0x10) /* n = 1 to 4 */ +#define USB3_DMA_CH0_PRD_ADR(n) (0x034 + ((n) - 1) * 0x10) /* n = 1 to 4 */ #define USB3_USB_COM_CON 0x200 #define USB3_USB20_CON 0x204 #define USB3_USB30_CON 0x208 @@ -64,6 +67,22 @@ /* AXI_INT_ENA and AXI_INT_STA */ #define AXI_INT_DMAINT BIT(31) #define AXI_INT_EPCINT BIT(30) +/* PRD's n = from 1 to 4 */ +#define AXI_INT_PRDEN_CLR_STA_SHIFT(n) (16 + (n) - 1) +#define AXI_INT_PRDERR_STA_SHIFT(n) (0 + (n) - 1) +#define AXI_INT_PRDEN_CLR_STA(n) (1 << AXI_INT_PRDEN_CLR_STA_SHIFT(n)) +#define AXI_INT_PRDERR_STA(n) (1 << AXI_INT_PRDERR_STA_SHIFT(n)) + +/* DMA_INT_ENA and DMA_INT_STA */ +#define DMA_INT(n) BIT(n) + +/* DMA_CH0_CONn */ +#define DMA_CON_PIPE_DIR BIT(15) /* 1: In Transfer */ +#define DMA_CON_PIPE_NO_SHIFT 8 +#define DMA_CON_PIPE_NO_MASK GENMASK(12, DMA_CON_PIPE_NO_SHIFT) +#define DMA_COM_PIPE_NO(n) (((n) << DMA_CON_PIPE_NO_SHIFT) & \ + DMA_CON_PIPE_NO_MASK) +#define DMA_CON_PRD_EN BIT(0) /* LCLKSEL */ #define LCLKSEL_LSEL BIT(18) @@ -231,8 +250,50 @@ #define USB3_EP0_BUF_SIZE 8 #define USB3_MAX_NUM_PIPES 30 #define USB3_WAIT_US 3 +#define USB3_DMA_NUM_SETTING_AREA 4 +/* + * To avoid double-meaning of "0" (xferred 65536 bytes or received zlp if + * buffer size is 65536), this driver uses the maximum size per a entry is + * 32768 bytes. + */ +#define USB3_DMA_MAX_XFER_SIZE 32768 +#define USB3_DMA_PRD_SIZE 4096 struct renesas_usb3; + +/* Physical Region Descriptor Table */ +struct renesas_usb3_prd { + u32 word1; +#define USB3_PRD1_E BIT(30) /* the end of chain */ +#define USB3_PRD1_U BIT(29) /* completion of transfer */ +#define USB3_PRD1_D BIT(28) /* Error occurred */ +#define USB3_PRD1_INT BIT(27) /* Interrupt occurred */ +#define USB3_PRD1_LST BIT(26) /* Last Packet */ +#define USB3_PRD1_B_INC BIT(24) +#define USB3_PRD1_MPS_8 0 +#define USB3_PRD1_MPS_16 BIT(21) +#define USB3_PRD1_MPS_32 BIT(22) +#define USB3_PRD1_MPS_64 (BIT(22) | BIT(21)) +#define USB3_PRD1_MPS_512 BIT(23) +#define USB3_PRD1_MPS_1024 (BIT(23) | BIT(21)) +#define USB3_PRD1_MPS_RESERVED (BIT(23) | BIT(22) | BIT(21)) +#define USB3_PRD1_SIZE_MASK GENMASK(15, 0) + + u32 bap; +}; +#define USB3_DMA_NUM_PRD_ENTRIES (USB3_DMA_PRD_SIZE / \ + sizeof(struct renesas_usb3_prd)) +#define USB3_DMA_MAX_XFER_SIZE_ALL_PRDS (USB3_DMA_PRD_SIZE / \ + sizeof(struct renesas_usb3_prd) * \ + USB3_DMA_MAX_XFER_SIZE) + +struct renesas_usb3_dma { + struct renesas_usb3_prd *prd; + dma_addr_t prd_dma; + int num; /* Setting area number (from 1 to 4) */ + bool used; +}; + struct renesas_usb3_request { struct usb_request req; struct list_head queue; @@ -242,6 +303,7 @@ struct renesas_usb3_request { struct renesas_usb3_ep { struct usb_ep ep; struct renesas_usb3 *usb3; + struct renesas_usb3_dma *dma; int num; char ep_name[USB3_EP_NAME_SIZE]; struct list_head queue; @@ -270,6 +332,8 @@ struct renesas_usb3 { struct renesas_usb3_ep *usb3_ep; int num_usb3_eps; + struct renesas_usb3_dma dma[USB3_DMA_NUM_SETTING_AREA]; + spinlock_t lock; int disabled_count; @@ -298,8 +362,18 @@ struct renesas_usb3 { (i) < (usb3)->num_usb3_eps; \ (i)++, usb3_ep = usb3_get_ep(usb3, (i))) +#define usb3_get_dma(usb3, i) (&(usb3)->dma[i]) +#define usb3_for_each_dma(usb3, dma, i) \ + for ((i) = 0, dma = usb3_get_dma((usb3), (i)); \ + (i) < USB3_DMA_NUM_SETTING_AREA; \ + (i)++, dma = usb3_get_dma((usb3), (i))) + static const char udc_name[] = "renesas_usb3"; +static bool use_dma = 1; +module_param(use_dma, bool, 0644); +MODULE_PARM_DESC(use_dma, "use dedicated DMAC"); + static void usb3_write(struct renesas_usb3 *usb3, u32 data, u32 offs) { iowrite32(data, usb3->reg + offs); @@ -1060,6 +1134,273 @@ static void usb3_start_pipe0(struct renesas_usb3_ep *usb3_ep, usb3_p0_xfer(usb3_ep, usb3_req); } +static void usb3_enable_dma_pipen(struct renesas_usb3 *usb3) +{ + usb3_set_bit(usb3, PN_CON_DATAIF_EN, USB3_PN_CON); +} + +static void usb3_disable_dma_pipen(struct renesas_usb3 *usb3) +{ + usb3_clear_bit(usb3, PN_CON_DATAIF_EN, USB3_PN_CON); +} + +static void usb3_enable_dma_irq(struct renesas_usb3 *usb3, int num) +{ + usb3_set_bit(usb3, DMA_INT(num), USB3_DMA_INT_ENA); +} + +static void usb3_disable_dma_irq(struct renesas_usb3 *usb3, int num) +{ + usb3_clear_bit(usb3, DMA_INT(num), USB3_DMA_INT_ENA); +} + +static u32 usb3_dma_mps_to_prd_word1(struct renesas_usb3_ep *usb3_ep) +{ + switch (usb3_ep->ep.maxpacket) { + case 8: + return USB3_PRD1_MPS_8; + case 16: + return USB3_PRD1_MPS_16; + case 32: + return USB3_PRD1_MPS_32; + case 64: + return USB3_PRD1_MPS_64; + case 512: + return USB3_PRD1_MPS_512; + case 1024: + return USB3_PRD1_MPS_1024; + default: + return USB3_PRD1_MPS_RESERVED; + } +} + +static bool usb3_dma_get_setting_area(struct renesas_usb3_ep *usb3_ep, + struct renesas_usb3_request *usb3_req) +{ + struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep); + struct renesas_usb3_dma *dma; + int i; + bool ret = false; + + if (usb3_req->req.length > USB3_DMA_MAX_XFER_SIZE_ALL_PRDS) { + dev_dbg(usb3_to_dev(usb3), "%s: the length is too big (%d)\n", + __func__, usb3_req->req.length); + return false; + } + + /* The driver doesn't handle zero-length packet via dmac */ + if (!usb3_req->req.length) + return false; + + if (usb3_dma_mps_to_prd_word1(usb3_ep) == USB3_PRD1_MPS_RESERVED) + return false; + + usb3_for_each_dma(usb3, dma, i) { + if (dma->used) + continue; + + if (usb_gadget_map_request(&usb3->gadget, &usb3_req->req, + usb3_ep->dir_in) < 0) + break; + + dma->used = true; + usb3_ep->dma = dma; + ret = true; + break; + } + + return ret; +} + +static void usb3_dma_put_setting_area(struct renesas_usb3_ep *usb3_ep, + struct renesas_usb3_request *usb3_req) +{ + struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep); + int i; + struct renesas_usb3_dma *dma; + + usb3_for_each_dma(usb3, dma, i) { + if (usb3_ep->dma == dma) { + usb_gadget_unmap_request(&usb3->gadget, &usb3_req->req, + usb3_ep->dir_in); + dma->used = false; + usb3_ep->dma = NULL; + break; + } + } +} + +static void usb3_dma_fill_prd(struct renesas_usb3_ep *usb3_ep, + struct renesas_usb3_request *usb3_req) +{ + struct renesas_usb3_prd *cur_prd = usb3_ep->dma->prd; + u32 remain = usb3_req->req.length; + u32 dma = usb3_req->req.dma; + u32 len; + int i = 0; + + do { + len = min_t(u32, remain, USB3_DMA_MAX_XFER_SIZE) & + USB3_PRD1_SIZE_MASK; + cur_prd->word1 = usb3_dma_mps_to_prd_word1(usb3_ep) | + USB3_PRD1_B_INC | len; + cur_prd->bap = dma; + remain -= len; + dma += len; + if (!remain || (i + 1) < USB3_DMA_NUM_PRD_ENTRIES) + break; + + cur_prd++; + i++; + } while (1); + + cur_prd->word1 |= USB3_PRD1_E | USB3_PRD1_INT; + if (usb3_ep->dir_in) + cur_prd->word1 |= USB3_PRD1_LST; +} + +static void usb3_dma_kick_prd(struct renesas_usb3_ep *usb3_ep) +{ + struct renesas_usb3_dma *dma = usb3_ep->dma; + struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep); + u32 dma_con = DMA_COM_PIPE_NO(usb3_ep->num) | DMA_CON_PRD_EN; + + if (usb3_ep->dir_in) + dma_con |= DMA_CON_PIPE_DIR; + + wmb(); /* prd entries should be in system memory here */ + + usb3_write(usb3, 1 << usb3_ep->num, USB3_DMA_INT_STA); + usb3_write(usb3, AXI_INT_PRDEN_CLR_STA(dma->num) | + AXI_INT_PRDERR_STA(dma->num), USB3_AXI_INT_STA); + + usb3_write(usb3, dma->prd_dma, USB3_DMA_CH0_PRD_ADR(dma->num)); + usb3_write(usb3, dma_con, USB3_DMA_CH0_CON(dma->num)); + usb3_enable_dma_irq(usb3, usb3_ep->num); +} + +static void usb3_dma_stop_prd(struct renesas_usb3_ep *usb3_ep) +{ + struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep); + struct renesas_usb3_dma *dma = usb3_ep->dma; + + usb3_disable_dma_irq(usb3, usb3_ep->num); + usb3_write(usb3, 0, USB3_DMA_CH0_CON(dma->num)); +} + +static int usb3_dma_update_status(struct renesas_usb3_ep *usb3_ep, + struct renesas_usb3_request *usb3_req) +{ + struct renesas_usb3_prd *cur_prd = usb3_ep->dma->prd; + struct usb_request *req = &usb3_req->req; + u32 remain, len; + int i = 0; + int status = 0; + + rmb(); /* The controller updated prd entries */ + + do { + if (cur_prd->word1 & USB3_PRD1_D) + status = -EIO; + if (cur_prd->word1 & USB3_PRD1_E) + len = req->length % USB3_DMA_MAX_XFER_SIZE; + else + len = USB3_DMA_MAX_XFER_SIZE; + remain = cur_prd->word1 & USB3_PRD1_SIZE_MASK; + req->actual += len - remain; + + if (cur_prd->word1 & USB3_PRD1_E || + (i + 1) < USB3_DMA_NUM_PRD_ENTRIES) + break; + + cur_prd++; + i++; + } while (1); + + return status; +} + +static bool usb3_dma_try_start(struct renesas_usb3_ep *usb3_ep, + struct renesas_usb3_request *usb3_req) +{ + struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep); + + if (!use_dma) + return false; + + if (usb3_dma_get_setting_area(usb3_ep, usb3_req)) { + usb3_pn_stop(usb3); + usb3_enable_dma_pipen(usb3); + usb3_dma_fill_prd(usb3_ep, usb3_req); + usb3_dma_kick_prd(usb3_ep); + usb3_pn_start(usb3); + return true; + } + + return false; +} + +static int usb3_dma_try_stop(struct renesas_usb3_ep *usb3_ep, + struct renesas_usb3_request *usb3_req) +{ + struct renesas_usb3 *usb3 = usb3_ep_to_usb3(usb3_ep); + unsigned long flags; + int status = 0; + + spin_lock_irqsave(&usb3->lock, flags); + if (!usb3_ep->dma) + goto out; + + if (!usb3_pn_change(usb3, usb3_ep->num)) + usb3_disable_dma_pipen(usb3); + usb3_dma_stop_prd(usb3_ep); + status = usb3_dma_update_status(usb3_ep, usb3_req); + usb3_dma_put_setting_area(usb3_ep, usb3_req); + +out: + spin_unlock_irqrestore(&usb3->lock, flags); + return status; +} + +static int renesas_usb3_dma_free_prd(struct renesas_usb3 *usb3, + struct device *dev) +{ + int i; + struct renesas_usb3_dma *dma; + + usb3_for_each_dma(usb3, dma, i) { + if (dma->prd) { + dma_free_coherent(dev, USB3_DMA_MAX_XFER_SIZE, + dma->prd, dma->prd_dma); + dma->prd = NULL; + } + } + + return 0; +} + +static int renesas_usb3_dma_alloc_prd(struct renesas_usb3 *usb3, + struct device *dev) +{ + int i; + struct renesas_usb3_dma *dma; + + if (!use_dma) + return 0; + + usb3_for_each_dma(usb3, dma, i) { + dma->prd = dma_alloc_coherent(dev, USB3_DMA_PRD_SIZE, + &dma->prd_dma, GFP_KERNEL); + if (!dma->prd) { + renesas_usb3_dma_free_prd(usb3, dev); + return -ENOMEM; + } + dma->num = i + 1; + } + + return 0; +} + static void usb3_start_pipen(struct renesas_usb3_ep *usb3_ep, struct renesas_usb3_request *usb3_req) { @@ -1079,6 +1420,10 @@ static void usb3_start_pipen(struct renesas_usb3_ep *usb3_ep, goto out; usb3_ep->started = true; + + if (usb3_dma_try_start(usb3_ep, usb3_req)) + goto out; + usb3_pn_start(usb3); if (usb3_ep->dir_in) { @@ -1582,12 +1927,49 @@ static void usb3_irq_epc(struct renesas_usb3 *usb3) } } +static void usb3_irq_dma_int(struct renesas_usb3 *usb3, u32 dma_sta) +{ + struct renesas_usb3_ep *usb3_ep; + struct renesas_usb3_request *usb3_req; + int i, status; + + for (i = 0; i < usb3->num_usb3_eps; i++) { + if (!(dma_sta & DMA_INT(i))) + continue; + + usb3_ep = usb3_get_ep(usb3, i); + if (!(usb3_read(usb3, USB3_AXI_INT_STA) & + AXI_INT_PRDEN_CLR_STA(usb3_ep->dma->num))) + continue; + + usb3_req = usb3_get_request(usb3_ep); + status = usb3_dma_try_stop(usb3_ep, usb3_req); + usb3_request_done_pipen(usb3, usb3_ep, usb3_req, status); + } +} + +static void usb3_irq_dma(struct renesas_usb3 *usb3) +{ + u32 dma_sta = usb3_read(usb3, USB3_DMA_INT_STA); + + dma_sta &= usb3_read(usb3, USB3_DMA_INT_ENA); + if (dma_sta) { + usb3_write(usb3, dma_sta, USB3_DMA_INT_STA); + usb3_irq_dma_int(usb3, dma_sta); + } +} + static irqreturn_t renesas_usb3_irq(int irq, void *_usb3) { struct renesas_usb3 *usb3 = _usb3; irqreturn_t ret = IRQ_NONE; u32 axi_int_sta = usb3_read(usb3, USB3_AXI_INT_STA); + if (axi_int_sta & AXI_INT_DMAINT) { + usb3_irq_dma(usb3); + ret = IRQ_HANDLED; + } + if (axi_int_sta & AXI_INT_EPCINT) { usb3_irq_epc(usb3); ret = IRQ_HANDLED; @@ -1686,6 +2068,7 @@ static int renesas_usb3_ep_disable(struct usb_ep *_ep) usb3_req = usb3_get_request(usb3_ep); if (!usb3_req) break; + usb3_dma_try_stop(usb3_ep, usb3_req); usb3_request_done(usb3_ep, usb3_req, -ESHUTDOWN); } while (1); @@ -1733,6 +2116,7 @@ static int renesas_usb3_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) dev_dbg(usb3_to_dev(usb3), "ep_dequeue: ep%2d, %u\n", usb3_ep->num, _req->length); + usb3_dma_try_stop(usb3_ep, usb3_req); usb3_request_done_pipen(usb3, usb3_ep, usb3_req, -ECONNRESET); return 0; @@ -1895,6 +2279,7 @@ static int renesas_usb3_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); usb_del_gadget_udc(&usb3->gadget); + renesas_usb3_dma_free_prd(usb3, &pdev->dev); __renesas_usb3_ep_free_request(usb3->ep0_req); @@ -2089,6 +2474,10 @@ static int renesas_usb3_probe(struct platform_device *pdev) if (!usb3->ep0_req) return -ENOMEM; + ret = renesas_usb3_dma_alloc_prd(usb3, &pdev->dev); + if (ret < 0) + goto err_alloc_prd; + ret = usb_add_gadget_udc(&pdev->dev, &usb3->gadget); if (ret < 0) goto err_add_udc; @@ -2110,6 +2499,9 @@ static int renesas_usb3_probe(struct platform_device *pdev) usb_del_gadget_udc(&usb3->gadget); err_add_udc: + renesas_usb3_dma_free_prd(usb3, &pdev->dev); + +err_alloc_prd: __renesas_usb3_ep_free_request(usb3->ep0_req); return ret;