From patchwork Mon Feb 24 09:18:25 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mykyta Poturai X-Patchwork-Id: 13987648 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 6986FC021B3 for ; Mon, 24 Feb 2025 09:18:56 +0000 (UTC) Received: from list by lists.xenproject.org with outflank-mailman.894980.1303619 (Exim 4.92) (envelope-from ) id 1tmUbg-0004lU-QY; Mon, 24 Feb 2025 09:18:32 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 894980.1303619; Mon, 24 Feb 2025 09:18:32 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1tmUbg-0004lN-M1; Mon, 24 Feb 2025 09:18:32 +0000 Received: by outflank-mailman (input) for mailman id 894980; Mon, 24 Feb 2025 09:18:31 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1tmUbf-0003pb-09 for xen-devel@lists.xenproject.org; Mon, 24 Feb 2025 09:18:31 +0000 Received: from EUR03-DBA-obe.outbound.protection.outlook.com (mail-dbaeur03on20603.outbound.protection.outlook.com [2a01:111:f403:260d::603]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id 4f984d22-f290-11ef-9aae-95dc52dad729; Mon, 24 Feb 2025 10:18:29 +0100 (CET) Received: from PAVPR03MB10102.eurprd03.prod.outlook.com (2603:10a6:102:30d::12) by AS8PR03MB8859.eurprd03.prod.outlook.com (2603:10a6:20b:56f::15) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.8466.18; Mon, 24 Feb 2025 09:18:25 +0000 Received: from PAVPR03MB10102.eurprd03.prod.outlook.com ([fe80::35ac:8893:c31c:b971]) by PAVPR03MB10102.eurprd03.prod.outlook.com ([fe80::35ac:8893:c31c:b971%3]) with mapi id 15.20.8466.016; Mon, 24 Feb 2025 09:18:25 +0000 X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: 4f984d22-f290-11ef-9aae-95dc52dad729 ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=D7fMnZzFVK7HilAfS10fEgD8N4cV/jNKZu1DR63ODdGqNvhszOYYOlCWaz2SZulBWT5qvl6FAiHmF6r+LslZdzp0zYMPq6Y/+hTzjNtNqO7PbbiTXtjnfFbCa+ujFG49Bdpzx25X7bNH/Con9cLJTFlEADZksvYt97/ZicYMKoSI9mdDuoiVAnrl8jw8wcltytDrjPrvUtgSR5ZZcKGKaVVW47nxJS5K5FHVC83GXAzyAqRJcSZ6LqKKlq6oj1sPSplL3+dqcSbgpl2hGU08UBxFkMTxiSp+tWG3CgrPLUrBfBvSdLtNYieNjIJA8AA/2jjdNbzqCYvp103SuLHoXQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=CFD8EL417kBsRTr2esgxWJnqnirmd77/F9gJ5bh9ez4=; b=cj4SNoFwM3EXkIl06gbl9O9leIR7fk7HwHvQEWarKv6nsPoNIbRQA2+YHUUBvc+gI4aBYvnVTshJTnitacQZMZUOmYTcIyoYMZxSCzsc7KxD00dswPwuxccl34N0kmcOgEMjb9coO1XrGUsBbt3wHZY3AulrZ3Groi5t5QxVWQjE8tqeuFIgcPaqw1exjD/QJmeJ5yoKa6etsbtnurhzciew7uyRSICv2vTfLyUvsTjJh4tk5eY+JUh5N0CgI/8XlfJKYmZVulcFwNbidKMpkhwhZfL3CQPFiG7rGgs7bz/u0ySj/4iJkkQh5m5I+FiXkTv46ZE7u5EfV7BijK+EpQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=epam.com; dmarc=pass action=none header.from=epam.com; dkim=pass header.d=epam.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=epam.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=CFD8EL417kBsRTr2esgxWJnqnirmd77/F9gJ5bh9ez4=; b=huqgC6BA4VZtYy3eJGZLD9a2yHEAGdLcUWKUgjB78Fk2mAKdb4rJJUmMvl56xQRw8oNs82kDq0r9rb7kbQtA+AThZGdAOoR56Ur/8EFcBUFrSwFJdPk1UrWvFBn2HP7SGNOP9XdHhwNDI8WggL023wEJ0PlY9Ay5AEmKL7aE54wGgs2/wa0FD6gfJuCJqCvt/G8ZyT192fJgKVggONV/5rDYvtOCVch3hZGbgNN5kBUV6pbmP05+yKzIsd6PWZuNDjf9iEb5UHNRdF/V5KOuOI6L/OH6Gvc2xKp1/weJBO+ZFnq9RlRqfof+EtXJWv7D4XrniVv0QkM4yYuOotYu5Q== From: Mykyta Poturai To: "xen-devel@lists.xenproject.org" CC: Oleksandr Andrushchenko , Stefano Stabellini , Julien Grall , Bertrand Marquis , Michal Orzel , Volodymyr Babchuk , Mykyta Poturai Subject: [PATCH 4/7] xen/arm: add support for R-Car Gen4 PCI host controller Thread-Topic: [PATCH 4/7] xen/arm: add support for R-Car Gen4 PCI host controller Thread-Index: AQHbhp0OJEwwd7KbIUWidoI1k6AKJw== Date: Mon, 24 Feb 2025 09:18:25 +0000 Message-ID: <8e567e7db48ba6d268c5e3a3481d53d891524d68.1740382735.git.mykyta_poturai@epam.com> References: In-Reply-To: Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: authentication-results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=epam.com; x-ms-publictraffictype: Email x-ms-traffictypediagnostic: PAVPR03MB10102:EE_|AS8PR03MB8859:EE_ x-ms-office365-filtering-correlation-id: d9814b2f-3d43-4f68-9c33-08dd54b43155 x-ms-exchange-senderadcheck: 1 x-ms-exchange-antispam-relay: 0 x-microsoft-antispam: BCL:0;ARA:13230040|376014|366016|1800799024|38070700018; x-microsoft-antispam-message-info: =?iso-8859-1?q?lk7ri5yYUStex+Gw5e6B8Za03t?= =?iso-8859-1?q?HRIS5ZkaeOTTxxkwtB4MPfVo1vTnsHKxHN33q+5/aQKbN4GdgyoFxNAklLLO?= =?iso-8859-1?q?tBmJZQyOxJ+TqvyvIvzrHtBezJDd/EmgQIJMMmgtrboAV8+A1TN0UzGti/9c?= =?iso-8859-1?q?n3RfCcr9ah7UK3leYvSD4nEXvG/H/vt2zDdzjT/DweEZABdVIqfn48cpiU80?= =?iso-8859-1?q?vp4kewjnHjKsmMJIH6tVJpP82up9+98dxibIpPkWmEINJl2ocmXhaVmYeaN2?= =?iso-8859-1?q?GbEN3wjB/0ePTO5TVc0pKk0zqLWtijnMq9PBQhowJP2RhLTKPzqthuSWo+H4?= =?iso-8859-1?q?Z95FsY+l4hk9oClJ0RytF+1KxX/zbsy9PfzwvS0waLJxSZg/EgdhGBKjMxmX?= =?iso-8859-1?q?yAzssPMgqX+6pBUaonGAeOKsxsNYiAJYOANe6Ahd68dMIT2+zX4EDbm+GH2a?= =?iso-8859-1?q?qgI2W1xbn8A13FWGV/5LMUYMygAheZZSaJq/TgfR9H4Lwpbv8CbNADn3DN0K?= =?iso-8859-1?q?YKmbmVTS6RlaYEix6u01fiiss0U+73goKgJ1jGVCWShf995CEO00t6nMrXUl?= =?iso-8859-1?q?frCzTLgY/xdWCPpc9dwXSnqcoBc44D74Pmf8ulUxJA2xk1u3xb9N/cH8Tq+q?= =?iso-8859-1?q?Wz623TQjC/R6N9BymhNm/Ij/YBuYoLJ7oR4TPE78KRWT1Uh8Ht5E1AVkF4cj?= =?iso-8859-1?q?a4pUpLK94BiNebZkE/aJDFmM81+nH0R1HIOSvxb4s83Wwm6YUOF9LbvEiaXL?= =?iso-8859-1?q?8964/yBFQWH+tj22YARtvi8Z/b3ikVXvvJBH9YswwLT7WvCqTIDlZ9TTy8ru?= =?iso-8859-1?q?v9CIT60q5WxbBNoUtc03Z/hxib2LjujMD09hA3dHIysbGMmrdGq0E9DLylV0?= =?iso-8859-1?q?eBpLP80JOQO9lk3eG5s55LF0CCgVAw3T5OquyYeS5D9XH+M4igbW4lnNCTbW?= =?iso-8859-1?q?r6Z5qSWJxfldtNHvGpSyPaGrn2/HmBVGyRYNE3E46g2tc5e3JYCLhGJSyOfy?= =?iso-8859-1?q?swewOl0uFJlMWf8SZY+tFSlmxHV33RyXqEeeMlMuIqSEJCi5Zcv0Gql5Yq7G?= =?iso-8859-1?q?Cccs8AFL3wMI6Psh/UpD2x4xC3CiJ3V3TD85wfVF3MSEXWYLOjIXwVh9Q2vj?= =?iso-8859-1?q?DbK6ogNKTwCXJYp+8rej20Xtwv3GeGVo64x8xoJZ+/1WVDL3Ns5uBPGw9yFM?= =?iso-8859-1?q?QKwnF3qPKOw8w0zo/MZotUcjYpu8aTfseqh0dq2q3Nj0O294ccsnANxZx20b?= =?iso-8859-1?q?RGdwwIcOlMXtBfJTVHAuXddd5VslhcrjiHDq09LxGsq01Vt/BSR3ib5FrvhS?= =?iso-8859-1?q?Hz/ldMX1ilJYfbVFzl364LyiSXh3SSmrHZHyS+Ny9MIfv3hCAEg699O4GImH?= =?iso-8859-1?q?vSSahF9sFrmkkqy7fZzmLC4VssypliDWuaObKNsRpXIYIjd+F06JTw8D1MeM?= =?iso-8859-1?q?8PZyTdxK2OL7UbOBO0WFAfLg=3D=3D?= x-forefront-antispam-report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:PAVPR03MB10102.eurprd03.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(376014)(366016)(1800799024)(38070700018);DIR:OUT;SFP:1101; x-ms-exchange-antispam-messagedata-chunkcount: 1 x-ms-exchange-antispam-messagedata-0: =?iso-8859-1?q?Bs9JMOVlvrCR1BwUlim0XbQ?= =?iso-8859-1?q?of7StXdZZrj/33PVZtoW1ZQg/cGqLok62JYP7seCxh8+xJs3XJgythZ6xU8H?= =?iso-8859-1?q?FK3yHgMT01KCU2Kp42FbnkZtnv77mQbLQpTo/mbrWjVytU0Mg8+PAngZ0ms9?= =?iso-8859-1?q?xxAIe9iXpCjOQZslKv1on0iOVNZq+e7BCoEuUH/Zjh6f2oTIQ4kTB2Ng1eEW?= =?iso-8859-1?q?eK+nWjhMew6osTUpinigX9kcy6aXkqNvXimxn5bOQrOn7a4D/wqQmnXqhUg7?= =?iso-8859-1?q?w7zsIqrDAKUY1d5gBrcg/UOeBtuGdNYdJWljG7y1HGYZ8l8e1kxHdz0BI03I?= =?iso-8859-1?q?HZnGWgT12KOV4Vx+aKTrP9NsEjg9MvAdP4O0x0v1bocMLaLCo9CU9TEwXeyG?= =?iso-8859-1?q?9hr688sAv2jjFTFETQywMijOEoi7ABlG8AxQyU9bbG5W4t7b0L4TTZMVC/Js?= =?iso-8859-1?q?S2nM8RJWX85WI2PuvU84ZiVwf/kT1AyapTyluSSPAgYisfFkY8Poh/Hb+ZLr?= =?iso-8859-1?q?fs8nHoKYoGYyfkqV0L4aH3U+OikP7949Z8M0vKgj5FJc5OaiV2MK+P6RCFT8?= =?iso-8859-1?q?5BBuQBJpQ83sv0vkqOsG6uI57Zi+UZwCFXSnFIvY9HO7795cFiGewu+ay/e9?= =?iso-8859-1?q?GMUfQ1oC28cV8miVvQra+3rUvsrOHABPs8V3ntjIZZsIqaqCPWSeTFHAivjo?= =?iso-8859-1?q?xf1zf7J1wev5EefgP2/yIGvc6fwIdak8v6tQB1nRCoFyM9DNqDgvF+4/nbL5?= =?iso-8859-1?q?fEj8FJzsHOMz5o+a4d6FJZuab4O63wpmGtFT1HsQBCPVTkQE4W2VhE51/f1g?= =?iso-8859-1?q?cUTYapg4SgsmZBLvfbi5kPKA33WO04t1jDf7mAOgUJtgFSyHBl3JLyNrGYnn?= =?iso-8859-1?q?RR4GqDSUyuAek6/zyP+HgXsVjoMq2OpcMDmbLqeR/i2xANK9xKO2jYZ8uDE0?= =?iso-8859-1?q?SGgbsVre++Q+5FfAPOpo6O+O3bPFQsh6u/Abh+yeXdxZ4Ic4wsC6ROXcUaEK?= =?iso-8859-1?q?EJb6CeeZPhozxaJ75rZAIBqCvtJsxMWj3/JBqHUBLCFCHfSeAA8BdwG2X3n6?= =?iso-8859-1?q?RQ93X7CdJKsLxddmGog2D8Cw17u+qh/ABehPZWiUjFBuCcO7xeXGWoclAewR?= =?iso-8859-1?q?BpsVrPIpJysGroV48qeiVLid01ThG8682cUE/ykkib7B/ALipflqsjdTYwH6?= =?iso-8859-1?q?Iz3euZit7w7CBAdSmzIvyQ12AqufBU0/DCJBxbomfk7ooCg2UvGI+tDt6Xa3?= =?iso-8859-1?q?YYp1yxhYi7WMN1Pumu/PjIpNeoZRv+FLk9gOVGYPDK71eMBeewffOYKJKnqI?= =?iso-8859-1?q?D2frPyo7Jiu5kyD4P/FKpIs01hIut3Foh0Ftdzp+7hfODG79JwqQrAbJDWqu?= =?iso-8859-1?q?up+W9rnfLddFSX4jgKqbqF5M7EPIQDqcnwNmMx/hPu0nEbT1ysbIw+WdMLcJ?= =?iso-8859-1?q?5LXzv5RxVx2eCOrocOgCzQSaEr0OOtcP5bRd10vzWUWDaJcHmIPndtJmfYcO?= =?iso-8859-1?q?geUwiZTIJi1/uaY/gOnqCCjdWR4TkiUzmpkOJIfg+c+oCU/6UAeWlKjCEEay?= =?iso-8859-1?q?xqpQhQhNfMmQhC56gtN/W+c8GlUkJvQZK2qM1nSEA1etBRRMS2awJnxsbeR1?= =?iso-8859-1?q?Z2FYHoykX6rPhgS3AcejO6JRbTvYiNecnyOGDGQ=3D=3D?= MIME-Version: 1.0 X-OriginatorOrg: epam.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-AuthSource: PAVPR03MB10102.eurprd03.prod.outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: d9814b2f-3d43-4f68-9c33-08dd54b43155 X-MS-Exchange-CrossTenant-originalarrivaltime: 24 Feb 2025 09:18:25.4453 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: b41b72d0-4e9f-4c26-8a69-f949f367c91d X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: mTxDsPNcwEfGaNasMdXIq+7JdCFEGjj3yLLnroRNEFoQ8DN8QNsb9hHgfS9DeY9APTdi+fX4YRpGJyfQ6MjenA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: AS8PR03MB8859 From: Oleksandr Andrushchenko Add support for Renesas R-Car Gen4 PCI host controller. S4 and V4H SoCs are supported. Implement config read/write operations for both root and child buses. For accessing the child bus, iATU is used for address translation. Signed-off-by: Oleksandr Andrushchenko Signed-off-by: Mykyta Poturai --- xen/arch/arm/pci/Makefile | 1 + xen/arch/arm/pci/pci-host-rcar4.c | 529 ++++++++++++++++++++++++++++++ 2 files changed, 530 insertions(+) create mode 100644 xen/arch/arm/pci/pci-host-rcar4.c diff --git a/xen/arch/arm/pci/Makefile b/xen/arch/arm/pci/Makefile index 1d045ade01..63ea86d9fa 100644 --- a/xen/arch/arm/pci/Makefile +++ b/xen/arch/arm/pci/Makefile @@ -4,3 +4,4 @@ obj-y += pci-host-generic.o obj-y += pci-host-common.o obj-y += ecam.o obj-y += pci-host-zynqmp.o +obj-y += pci-host-rcar4.o diff --git a/xen/arch/arm/pci/pci-host-rcar4.c b/xen/arch/arm/pci/pci-host-rcar4.c new file mode 100644 index 0000000000..df337e3159 --- /dev/null +++ b/xen/arch/arm/pci/pci-host-rcar4.c @@ -0,0 +1,529 @@ +/* + * Based on Linux drivers/pci/controller/pci-host-common.c + * Based on Linux drivers/pci/controller/pci-host-generic.c + * Based on xen/arch/arm/pci/pci-host-generic.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include +#include +#include + +#define RCAR4_DWC_VERSION 0x520A + +struct rcar4_priv +{ + uint32_t num_viewport; + bool iatu_unroll_initilized; + bool iatu_unroll_enabled; + void __iomem *atu_base; + unsigned int version; +}; + +/* + * PCI host bridges often have different ways to access the root and child + * bus config spaces: + * "dbi" : the aperture where root port's own configuration registers + * are available. + * "config": child's configuration space + * "atu" : iATU registers for DWC version 4.80 or later + */ +static int __init rcar4_cfg_reg_index(struct dt_device_node *np) +{ + return dt_property_match_string(np, "reg-names", "dbi"); +} + +static int __init rcar4_child_cfg_reg_index(struct dt_device_node *np) +{ + return dt_property_match_string(np, "reg-names", "config"); +} + +/* ECAM ops */ +const struct pci_ecam_ops rcar4_pcie_ops = { + .bus_shift = 20, + .cfg_reg_index = rcar4_cfg_reg_index, + .pci_ops = { + .map_bus = pci_ecam_map_bus, + .read = pci_generic_config_read, + .write = pci_generic_config_write, + .need_p2m_hwdom_mapping = pci_ecam_need_p2m_hwdom_mapping, + } +}; + +#define PCIBIOS_SUCCESSFUL 0x00 +#define PCIBIOS_BAD_REGISTER_NUMBER 0x87 + +#define FIELD_PREP(_mask, _val) \ + (((typeof(_mask))(_val) << (ffs64(_mask) - 1)) & (_mask)) + +/** + * upper_32_bits - return bits 32-63 of a number + * @n: the number we're accessing + * + * A basic shift-right of a 64- or 32-bit quantity. Use this to suppress + * the "right shift count >= width of type" warning when that quantity is + * 32-bits. + */ +#define upper_32_bits(n) ((uint32_t)(((n) >> 16) >> 16)) + +/** + * lower_32_bits - return bits 0-31 of a number + * @n: the number we're accessing + */ +#define lower_32_bits(n) ((uint32_t)((n) & 0xffffffff)) + +#define PCIE_ATU_VIEWPORT 0x900 +#define PCIE_ATU_REGION_OUTBOUND 0 +#define PCIE_ATU_CR1 0x904 +#define PCIE_ATU_INCREASE_REGION_SIZE BIT(13, UL) +#define PCIE_ATU_CR2 0x908 +#define PCIE_ATU_ENABLE BIT(31, UL) +#define PCIE_ATU_LOWER_BASE 0x90C +#define PCIE_ATU_UPPER_BASE 0x910 +#define PCIE_ATU_LIMIT 0x914 +#define PCIE_ATU_LOWER_TARGET 0x918 +#define PCIE_ATU_UPPER_TARGET 0x91C +#define PCIE_ATU_UPPER_LIMIT 0x924 + +#define PCIE_ATU_REGION_INDEX1 0x1 +#define PCIE_ATU_TYPE_IO 0x2 +#define PCIE_ATU_TYPE_CFG0 0x4 + +#define PCIE_ATU_BUS(x) FIELD_PREP(GENMASK(31, 24), x) +#define PCIE_ATU_DEV(x) FIELD_PREP(GENMASK(23, 19), x) +#define PCIE_ATU_FUNC(x) FIELD_PREP(GENMASK(18, 16), x) + +/* Register address builder */ +#define PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(region) \ + ((region) << 9) + +/* + * iATU Unroll-specific register definitions + * From 4.80 core version the address translation will be made by unroll + */ +#define PCIE_ATU_UNR_REGION_CTRL1 0x00 +#define PCIE_ATU_UNR_REGION_CTRL2 0x04 +#define PCIE_ATU_UNR_LOWER_BASE 0x08 +#define PCIE_ATU_UNR_UPPER_BASE 0x0C +#define PCIE_ATU_UNR_LOWER_LIMIT 0x10 +#define PCIE_ATU_UNR_LOWER_TARGET 0x14 +#define PCIE_ATU_UNR_UPPER_TARGET 0x18 +#define PCIE_ATU_UNR_UPPER_LIMIT 0x20 + +#define PCIE_ATU_FUNC_NUM(pf) ((pf) << 20) + +/* Parameters for the waiting for iATU enabled routine */ +#define LINK_WAIT_MAX_IATU_RETRIES 5 +#define LINK_WAIT_IATU 9 + +static int dw_pcie_read(void __iomem *addr, int size, uint32_t *val) +{ + if ( !IS_ALIGNED((uintptr_t)addr, size) ) + { + *val = 0; + return PCIBIOS_BAD_REGISTER_NUMBER; + } + + if (size == 4) + *val = readl(addr); + else if (size == 2) + *val = readw(addr); + else if (size == 1) + *val = readb(addr); + else + { + *val = 0; + return PCIBIOS_BAD_REGISTER_NUMBER; + } + + return PCIBIOS_SUCCESSFUL; +} + +static int dw_pcie_write(void __iomem *addr, int size, uint32_t val) +{ + if ( !IS_ALIGNED((uintptr_t)addr, size) ) + return PCIBIOS_BAD_REGISTER_NUMBER; + + if (size == 4) + writel(val, addr); + else if (size == 2) + writew(val, addr); + else if (size == 1) + writeb(val, addr); + else + return PCIBIOS_BAD_REGISTER_NUMBER; + + return PCIBIOS_SUCCESSFUL; +} + +static uint32_t rcar4_read_dbi(struct pci_host_bridge *bridge, + uint32_t reg, size_t size) +{ + void __iomem *addr = bridge->cfg->win + reg; + uint32_t val; + + dw_pcie_read(addr, size, &val); + return val; +} + +static void rcar4_write_dbi(struct pci_host_bridge *bridge, + uint32_t reg, size_t size, uint32_t val) +{ + void __iomem *addr = bridge->cfg->win + reg; + + dw_pcie_write(addr, size, val); +} + +static uint32_t rcar4_readl_dbi(struct pci_host_bridge *bridge, uint32_t reg) +{ + return rcar4_read_dbi(bridge, reg, sizeof(uint32_t)); +} + +static void dw_pcie_writel_dbi(struct pci_host_bridge *pci, uint32_t reg, + uint32_t val) +{ + rcar4_write_dbi(pci, reg, sizeof(uint32_t), val); +} + +static void rcar4_read_iatu_unroll_enabled(struct pci_host_bridge *bridge) +{ + struct rcar4_priv *priv = bridge->priv; + uint32_t val; + + val = rcar4_readl_dbi(bridge, PCIE_ATU_VIEWPORT); + if (val == 0xffffffff) + priv->iatu_unroll_enabled = true; + + printk(XENLOG_DEBUG "%s iATU unroll: %sabled\n", + dt_node_full_name(bridge->dt_node), + priv->iatu_unroll_enabled ? "en" : "dis"); +} + +static uint32_t dw_pcie_readl_atu(struct pci_host_bridge *pci, uint32_t reg) +{ + struct rcar4_priv *priv = pci->priv; + int ret; + uint32_t val; + + ret = dw_pcie_read(priv->atu_base + reg, 4, &val); + if ( ret ) + printk(XENLOG_ERR "Read ATU address failed\n"); + + return val; +} + +static void dw_pcie_writel_atu(struct pci_host_bridge *pci, uint32_t reg, + uint32_t val) +{ + struct rcar4_priv *priv = pci->priv; + int ret; + + ret = dw_pcie_write(priv->atu_base + reg, 4, val); + if (ret) + printk(XENLOG_ERR "Write ATU address failed\n"); +} + +static uint32_t dw_pcie_readl_ob_unroll(struct pci_host_bridge *pci, + uint32_t index, uint32_t reg) +{ + uint32_t offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index); + + return dw_pcie_readl_atu(pci, offset + reg); +} + +static void dw_pcie_writel_ob_unroll(struct pci_host_bridge *pci, + uint32_t index, uint32_t reg, uint32_t val) +{ + uint32_t offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index); + + dw_pcie_writel_atu(pci, offset + reg, val); +} + +static uint32_t dw_pcie_enable_ecrc(uint32_t val) +{ + ASSERT_UNREACHABLE(); + return 0; +} + +static void dw_pcie_prog_outbound_atu_unroll(struct pci_host_bridge *pci, + uint8_t func_no, int index, + int type, uint64_t cpu_addr, + uint64_t pci_addr, uint64_t size) +{ + struct rcar4_priv *priv = pci->priv; + uint32_t retries, val; + uint64_t limit_addr = cpu_addr + size - 1; + + dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_BASE, + lower_32_bits(cpu_addr)); + dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_BASE, + upper_32_bits(cpu_addr)); + dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_LIMIT, + lower_32_bits(limit_addr)); + dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_LIMIT, + upper_32_bits(limit_addr)); + dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET, + lower_32_bits(pci_addr)); + dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET, + upper_32_bits(pci_addr)); + val = type | PCIE_ATU_FUNC_NUM(func_no); + val = upper_32_bits(size - 1) ? val | PCIE_ATU_INCREASE_REGION_SIZE : val; + if (priv->version == 0x490A) + val = dw_pcie_enable_ecrc(val); + dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, val); + dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2, + PCIE_ATU_ENABLE); + + /* + * Make sure ATU enable takes effect before any subsequent config + * and I/O accesses. + */ + for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) + { + val = dw_pcie_readl_ob_unroll(pci, index, + PCIE_ATU_UNR_REGION_CTRL2); + if (val & PCIE_ATU_ENABLE) + return; + + mdelay(LINK_WAIT_IATU); + } + printk(XENLOG_ERR "Outbound iATU is not being enabled\n"); +} + +static void __dw_pcie_prog_outbound_atu(struct pci_host_bridge *pci, + uint8_t func_no, int index, int type, + uint64_t cpu_addr, uint64_t pci_addr, + uint64_t size) +{ + struct rcar4_priv *priv = pci->priv; + uint32_t retries, val; + + if (priv->iatu_unroll_enabled) + { + dw_pcie_prog_outbound_atu_unroll(pci, func_no, index, type, + cpu_addr, pci_addr, size); + return; + } + + dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, + PCIE_ATU_REGION_OUTBOUND | index); + dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_BASE, + lower_32_bits(cpu_addr)); + dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_BASE, + upper_32_bits(cpu_addr)); + dw_pcie_writel_dbi(pci, PCIE_ATU_LIMIT, + lower_32_bits(cpu_addr + size - 1)); + if (priv->version >= 0x460A) + dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_LIMIT, + upper_32_bits(cpu_addr + size - 1)); + dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, + lower_32_bits(pci_addr)); + dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET, + upper_32_bits(pci_addr)); + val = type | PCIE_ATU_FUNC_NUM(func_no); + val = ((upper_32_bits(size - 1)) && (priv->version >= 0x460A)) ? + val | PCIE_ATU_INCREASE_REGION_SIZE : val; + if (priv->version == 0x490A) + val = dw_pcie_enable_ecrc(val); + dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, val); + dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE); + + /* + * Make sure ATU enable takes effect before any subsequent config + * and I/O accesses. + */ + for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) + { + val = rcar4_readl_dbi(pci, PCIE_ATU_CR2); + if (val & PCIE_ATU_ENABLE) + return; + + mdelay(LINK_WAIT_IATU); + } + printk(XENLOG_ERR "Outbound iATU is not being enabled\n"); +} + +static void dw_pcie_prog_outbound_atu(struct pci_host_bridge *pci, int index, + int type, uint64_t cpu_addr, + uint64_t pci_addr, uint64_t size) +{ + __dw_pcie_prog_outbound_atu(pci, 0, index, type, + cpu_addr, pci_addr, size); +} + +static void __iomem *rcar4_child_map_bus(struct pci_host_bridge *bridge, + pci_sbdf_t sbdf, uint32_t where) +{ + uint32_t busdev; + + busdev = PCIE_ATU_BUS(sbdf.bus) | PCIE_ATU_DEV(PCI_SLOT(sbdf.devfn)) | + PCIE_ATU_FUNC(PCI_FUNC(sbdf.devfn)); + + /* FIXME: Parent is the root bus, so use PCIE_ATU_TYPE_CFG0. */ + dw_pcie_prog_outbound_atu(bridge, PCIE_ATU_REGION_INDEX1, + PCIE_ATU_TYPE_CFG0, + bridge->child_cfg->phys_addr, + busdev, bridge->child_cfg->size); + + return bridge->child_cfg->win + where; +} + +static int rcar4_child_config_read(struct pci_host_bridge *bridge, + pci_sbdf_t sbdf, uint32_t reg, + uint32_t len, uint32_t *value) +{ + struct rcar4_priv *priv = bridge->priv; + int ret; + + /* + * FIXME: we cannot read iATU settings at the early initialization + * (probe) as the host's HW is not yet initialized at that phase. + * This read operation is the very first thing Domain-0 will do + * during its initialization, so take this opportunity and read + * iATU setting now. + */ + if ( unlikely(!priv->iatu_unroll_initilized) ) + { + rcar4_read_iatu_unroll_enabled(bridge); + priv->iatu_unroll_initilized = true; + } + + ret = pci_generic_config_read(bridge, sbdf, reg, len, value); + if ( !ret && (priv->num_viewport <= 2) ) + dw_pcie_prog_outbound_atu(bridge, PCIE_ATU_REGION_INDEX1, + PCIE_ATU_TYPE_IO, + bridge->child_cfg->phys_addr, + 0, bridge->child_cfg->size); + + return ret; +} + +static int rcar4_child_config_write(struct pci_host_bridge *bridge, + pci_sbdf_t sbdf, uint32_t reg, + uint32_t len, uint32_t value) +{ + struct rcar4_priv *priv = bridge->priv; + int ret; + + ret = pci_generic_config_write(bridge, sbdf, reg, len, value); + if ( !ret && (priv->num_viewport <= 2) ) + dw_pcie_prog_outbound_atu(bridge, PCIE_ATU_REGION_INDEX1, + PCIE_ATU_TYPE_IO, + bridge->child_cfg->phys_addr, + 0, bridge->child_cfg->size); + return ret; +} + +bool __init rcar4_child_need_p2m_hwdom_mapping(struct domain *d, + struct pci_host_bridge *bridge, + uint64_t addr) +{ + struct pci_config_window *cfg = bridge->child_cfg; + + /* + * We do not want ECAM address space to be mapped in Domain-0's p2m, + * so we can trap access to it. + */ + return cfg->phys_addr != addr; +} + +const struct pci_ecam_ops rcar4_pcie_child_ops = { + .bus_shift = 20, + .cfg_reg_index = rcar4_child_cfg_reg_index, + .pci_ops = { + .map_bus = rcar4_child_map_bus, + .read = rcar4_child_config_read, + .write = rcar4_child_config_write, + .need_p2m_hwdom_mapping = rcar4_child_need_p2m_hwdom_mapping, + } +}; + +static const struct dt_device_match __initconstrel rcar4_pcie_dt_match[] = +{ + { .compatible = "renesas,r8a779f0-pcie" }, + { .compatible = "renesas,r8a779g0-pcie" }, + { }, +}; + +static int __init pci_host_generic_probe(struct dt_device_node *dev, + const void *data) +{ + struct pci_host_bridge *bridge; + struct rcar4_priv *priv; + paddr_t atu_phys_addr; + paddr_t atu_size; + int atu_idx, ret; + + bridge = pci_host_common_probe(dev, &rcar4_pcie_ops, &rcar4_pcie_child_ops, + sizeof(*priv)); + if ( IS_ERR(bridge) ) + return PTR_ERR(bridge); + + priv = bridge->priv; + + atu_idx = dt_property_match_string(dev, "reg-names", "atu"); + if ( atu_idx < 0 ) + { + printk(XENLOG_ERR "Cannot find \"atu\" range index in device tree\n"); + return atu_idx; + } + ret = dt_device_get_address(dev, atu_idx, &atu_phys_addr, &atu_size); + if ( ret ) + { + printk(XENLOG_ERR "Cannot find \"atu\" range in device tree\n"); + return ret; + } + printk("iATU at [mem 0x%" PRIpaddr "-0x%" PRIpaddr "]\n", + atu_phys_addr, atu_phys_addr + atu_size - 1); + priv->atu_base = ioremap_nocache(atu_phys_addr, atu_size); + if ( !priv->atu_base ) + { + printk(XENLOG_ERR "iATU ioremap failed\n"); + return ENXIO; + } + + if ( !dt_property_read_u32(dev, "num-viewport", &priv->num_viewport) ) + priv->num_viewport = 2; + + /* + * FIXME: we cannot read iATU unroll enable now as the host bridge's + * HW is not yet initialized by Domain-0: leave it for later. + */ + + printk(XENLOG_INFO "%s number of view ports: %d\n", dt_node_full_name(dev), + priv->num_viewport); + + priv->version = RCAR4_DWC_VERSION; + + return 0; +} + +DT_DEVICE_START(pci_gen, "PCI HOST R-CAR GEN4", DEVICE_PCI_HOSTBRIDGE) +.dt_match = rcar4_pcie_dt_match, +.init = pci_host_generic_probe, +DT_DEVICE_END + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */