Received: by 2002:ad5:474a:0:0:0:0:0 with SMTP id i10csp1136194imu; Mon, 5 Nov 2018 14:38:32 -0800 (PST) X-Google-Smtp-Source: AJdET5c15etlZ3w0iTOeriAch778eSBH4CJXAhsO6BVdOtPX4kY0boCaWR0QCG2wIa+RIxTDCJ4c X-Received: by 2002:a63:1258:: with SMTP id 24mr10870870pgs.114.1541457512225; Mon, 05 Nov 2018 14:38:32 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1541457512; cv=none; d=google.com; s=arc-20160816; b=K2oNQUm0QAfw1L1vRrsqC9eT6ZlEMjFHVhTABgF4nnKi2JBZ82goqtM9evS6on19js qCOkdf7otZylkFpfufoYexgA9tz6M3HvnXpdTMQgy/mVOxRBwMlInJcGtvDpPr4OTBv9 EGn4iPXBV8BcJjOMD82eXeAQoayIJGaSbpzXtf34yrn0RHuycpiQVlF9sYDS7JXD7NaH zlKOvEp9Yn3tzOzEL+mWnNjsmVv+qpx//OzxTj3qatyKzRlibaSedx+TwXVJQCkVQlaC bOAOGbupMT7JGjefYrJOkwCl5qpVhXKfEfcNWmpLKpAD5vQnuGHhPGg3BqAqyWeOsRp+ X7Vw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:spamdiagnosticmetadata :spamdiagnosticoutput:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:dkim-signature; bh=llFKy7iaTmJSnEkqa4RIMJVwwaUku3oM6h06J5ZCcks=; b=0JLcKSgVf5WfNBCvUrezNQ8hSoRkUEd2YMVRNJGDZs3aitonKlYmtJmzc4Hkb3r79I xevZMi1iEByFF9RcJxeIwhTHpPD/seM7g5OLGGpV3pC1cPpaBKZ72soUCVmHR4dNFGx4 gO1UI37xyY98JbpILc4+1dYEUpmp77B26z5y76ow73hfrCcvIDgIDywAejJ4acemcM/h 7X2Bfr/OKE3jtVxHfMSvd3UBhGun07PyFBE2s5fdOpnGSnPBpi7+BCZxB4WmU6j47zkG fDR9D2t8vaf6X6AzpnzI3hxe9J9Dg2GXIoUpozcOpWlNb8ie0AhXQw6ofDrEh7K/Y/Er I/3A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@xilinx.onmicrosoft.com header.s=selector1-xilinx-com header.b="ru/oI5id"; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 133si23037144pge.246.2018.11.05.14.38.16; Mon, 05 Nov 2018 14:38:32 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@xilinx.onmicrosoft.com header.s=selector1-xilinx-com header.b="ru/oI5id"; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388279AbeKFH7a (ORCPT + 99 others); Tue, 6 Nov 2018 02:59:30 -0500 Received: from mail-cys01nam02on0060.outbound.protection.outlook.com ([104.47.37.60]:29102 "EHLO NAM02-CY1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S2387983AbeKFH7a (ORCPT ); Tue, 6 Nov 2018 02:59:30 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=xilinx.onmicrosoft.com; s=selector1-xilinx-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=llFKy7iaTmJSnEkqa4RIMJVwwaUku3oM6h06J5ZCcks=; b=ru/oI5idFiTySlegYaBa3OV9Aj+ruShmZsDloqXaKz8G0luD+UnFqLgfhstlEnyHGc/+Jk7GxgmmHl7bEKapZJgQPLt7zOoD+ix0OUCiqUzpLD9ptoaJhglus4FT+WWTwIIXExuio0jN+7DAFWAixGe+i5Kmap6ezNn8DdB+qBk= Received: from DM6PR02CA0024.namprd02.prod.outlook.com (2603:10b6:5:1c::37) by BYAPR02MB4456.namprd02.prod.outlook.com (2603:10b6:a03:57::29) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.1294.21; Mon, 5 Nov 2018 22:37:20 +0000 Received: from BL2NAM02FT016.eop-nam02.prod.protection.outlook.com (2a01:111:f400:7e46::209) by DM6PR02CA0024.outlook.office365.com (2603:10b6:5:1c::37) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) id 15.20.1294.21 via Frontend Transport; Mon, 5 Nov 2018 22:37:20 +0000 Authentication-Results: spf=pass (sender IP is 149.199.60.83) smtp.mailfrom=xilinx.com; vger.kernel.org; dkim=none (message not signed) header.d=none;vger.kernel.org; dmarc=bestguesspass action=none header.from=xilinx.com; Received-SPF: Pass (protection.outlook.com: domain of xilinx.com designates 149.199.60.83 as permitted sender) receiver=protection.outlook.com; client-ip=149.199.60.83; helo=xsj-pvapsmtpgw01; Received: from xsj-pvapsmtpgw01 (149.199.60.83) by BL2NAM02FT016.mail.protection.outlook.com (10.152.77.171) with Microsoft SMTP Server (version=TLS1_0, cipher=TLS_RSA_WITH_AES_256_CBC_SHA) id 15.20.1294.14 via Frontend Transport; Mon, 5 Nov 2018 22:37:20 +0000 Received: from unknown-38-66.xilinx.com ([149.199.38.66] helo=xsj-pvapsmtp01) by xsj-pvapsmtpgw01 with esmtp (Exim 4.63) (envelope-from ) id 1gJnUl-0006ve-KM; Mon, 05 Nov 2018 14:37:19 -0800 Received: from [127.0.0.1] (helo=localhost) by xsj-pvapsmtp01 with smtp (Exim 4.63) (envelope-from ) id 1gJnUg-0001yB-G5; Mon, 05 Nov 2018 14:37:14 -0800 Received: from xsj-pvapsmtp01 (mailhost.xilinx.com [149.199.38.66]) by xsj-smtp-dlp1.xlnx.xilinx.com (8.13.8/8.13.1) with ESMTP id wA5Mb4pI016201; Mon, 5 Nov 2018 14:37:04 -0800 Received: from [172.19.2.167] (helo=xsjjliang50.xilinx.com) by xsj-pvapsmtp01 with esmtp (Exim 4.63) (envelope-from ) id 1gJnUV-0001wf-Rh; Mon, 05 Nov 2018 14:37:03 -0800 From: Wendy Liang To: , , , CC: , , , Wendy Liang Subject: [PATCH v5 1/2] mailbox: ZynqMP IPI mailbox controller Date: Mon, 5 Nov 2018 14:37:00 -0800 Message-ID: <1541457421-14820-2-git-send-email-wendy.liang@xilinx.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1541457421-14820-1-git-send-email-wendy.liang@xilinx.com> References: <1541457421-14820-1-git-send-email-wendy.liang@xilinx.com> X-RCIS-Action: ALLOW X-TM-AS-Product-Ver: IMSS-7.1.0.1224-8.2.0.1013-23620.005 X-TM-AS-User-Approved-Sender: Yes;Yes X-EOPAttributedMessage: 0 X-MS-Office365-Filtering-HT: Tenant X-Forefront-Antispam-Report: CIP:149.199.60.83;IPV:NLI;CTRY:US;EFV:NLI;SFV:NSPM;SFS:(10009020)(136003)(396003)(346002)(39860400002)(376002)(2980300002)(438002)(199004)(189003)(446003)(2616005)(44832011)(305945005)(9786002)(8936002)(81166006)(77096007)(4326008)(476003)(126002)(186003)(47776003)(11346002)(39060400002)(106466001)(426003)(336012)(50226002)(81156014)(486006)(5660300001)(8676002)(356004)(478600001)(2906002)(63266004)(36386004)(14444005)(76176011)(51416003)(36756003)(4744004)(575784001)(26005)(107886003)(48376002)(7696005)(16586007)(50466002)(110136005)(54906003)(15650500001)(316002)(106002)(107986001);DIR:OUT;SFP:1101;SCL:1;SRVR:BYAPR02MB4456;H:xsj-pvapsmtpgw01;FPR:;SPF:Pass;LANG:en;PTR:unknown-60-83.xilinx.com;A:1;MX:1; X-Microsoft-Exchange-Diagnostics: 1;BL2NAM02FT016;1:4c7sAQr/Fp54B1OmWC5QyK/RBxyeXojyZzh+CwTD02SYlDuxWJ98aXE1bwKT+fI7DWb+aXpF6qEJvfewRRKs/BvmizZ0jLJgJEf8OesLqC/wH9KZGDEZUdDrFvFpJ750 MIME-Version: 1.0 Content-Type: text/plain X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 56820858-eb29-45f5-db4b-08d6436f3f85 X-Microsoft-Antispam: BCL:0;PCL:0;RULEID:(7020095)(4652040)(8989299)(4534185)(4627221)(201703031133081)(201702281549075)(8990200)(5600074)(711020)(4608076)(2017052603328)(7153060);SRVR:BYAPR02MB4456; X-Microsoft-Exchange-Diagnostics: 1;BYAPR02MB4456;3:o5z/TTx/tTdfSW4JjYBpTdhlinfF6G2t+AWc8vxq1AqWEmm5+2MD2G7jdBr7An47J6dioPNm+ikz3bqkzLo4wmzkejo4DtxzzMZnb4LN+5nKT1q8xGftQkDu0ozm3trM47G7DovcQjN97U1XuV67b4y54R+A2SnYDrQJSQeFZwk3IJT83NRxbZG3SOlF3X7XDtdajpAbzvn7ZPnITK54D4ZlwQoEj6qaUvjneLHXrcIziHpvoj/GOLDQdbHWevy5ZACPudKRdduBxXm9ruuAnXLgZjpyclBMAtTEYvYF4w+GceqNn+44FsRYMlFlAk5WEjVkiajyBbIDQl+lUXk3HyaHjM4l+VYp6sZlAWSc5q4=;25:G+v1ftT/STIuP0Bv8s0rXx7zV6CHHrm+1zDEA84bw163Vzpt5C3S5oOPcf05WsnFjoJJj1BqON7XLT9INL1peMWjg1/E5ZoDlM/psfIww1+PW0FUoUg+puuptousPFnupglW9g5vvVSfufsxutLgQ6XymI3NQB7xNEyXXdmnRn4kmxO1+qYbilZaSQJMeZalHGwD3vjQSNkx9QGoO15ILJeSCzwDw2DiI1UTABp6mCfybrgLizSTyODu7bdGScOl4LNNj+gmDAv7ZjneYEK/yuQu/1pKsW6eB6iLkAl1xc4N4sa4XqUy1Lac1op2xXm9uDGkM2UprrgHHCG4vnMO5w== X-MS-TrafficTypeDiagnostic: BYAPR02MB4456: X-Microsoft-Exchange-Diagnostics: 1;BYAPR02MB4456;31:fa7xyDmG2H/rRwCbpV94sTSFmXOIriy/PeuyNUE2nZfhDKiagSQVyKDc514s8FpPv728KrRXXcHJhtdmBaqME5+qIbDe9zvD2ufQSgb0frl3Y7DDfu+DVgn6u7DAKnF7urG+T6rntipVX3u+wmpsMjVdEnKWJbbdXJdTaf5udzmASFme8mlob/1FK2H+V9iKOvkFY4gRYWnHYPtETuDOgDRdDEoMjKP7MobYFQSm0Ms=;20:KqFcoKqQmu6HZJwBcygNtgiVZTtyCgNPO5HkxLp+A6flxdgDtyjRDXZ/tbCNku0/Qzc2CGgXePhatsDer8XXSy5kDZ1dEoM61iIN3YDaLh+VW7spGzHw60IF38Ytu4LRHFyQtYBRazBVBWo5/B6uL+U6gcWQVoGi4El5HWklEpbGT1KdT/I217emXK8zoqUihARtnDQmEXvz2V6GcRlFYCP9C1XSJG0FS0BM67Ml66QKHi/j18feb0oZyx0Dc+pXGcrMNUqmn8uh3GMLhh3HLHIbdgsp565RHNrDR7D/XSGcWl6aid1qDCRgjJjmkgamICLGci270fYYxixCPemS/EP++TU3r/hUdxueub/arQyhaWKy+kPi2rXh/l2tev2IV13JgFqOGxsuIo5nuj5lJCGm+wOGeJ3OiwHzbvjeEhlol/Y+I0C47CIhpbvflhng7CdTvcS54cS+AGpRa7plgHOlu5zv/E0IKgqair2NqnPFiAjcEEJXXWIah+RL/giX X-Auto-Response-Suppress: DR, RN, NRN, OOF, AutoReply X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(192813158149592); X-MS-Exchange-SenderADCheck: 1 X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:(8211001083)(6040522)(2401047)(5005006)(8121501046)(3231382)(944501410)(52105095)(3002001)(10201501046)(93006095)(93004095)(6055026)(148016)(149066)(150057)(6041310)(201703131423095)(201702281528075)(20161123555045)(201703061421075)(201703061406153)(20161123560045)(20161123558120)(20161123562045)(20161123564045)(201708071742011)(7699051)(76991095);SRVR:BYAPR02MB4456;BCL:0;PCL:0;RULEID:;SRVR:BYAPR02MB4456; X-Microsoft-Exchange-Diagnostics: 1;BYAPR02MB4456;4:9KPZicPvFlCblDdGObFjq4zVOBAmfMJuxcCv+us7/iECjFw6KD6ruqvNqQCOfP0p+B3ZlUb+dcg3Ln90wtN9I4B6crBVW0GrI5jwvcF1XEPe3WothHkY7eNw9KZG3fU3d7h4m1ByIQhG3VhHovP2AUhlPrVDu+QlD3tAx8XUKA/k2/zpIGX+gEt8XW7XOg92XaH2VQyIiBbSG4r5yRekQ7k4F+oo9sXnQe3/Q4nRXfocXNtIyzZY7h8EVoBHsFw66AzzlRirol5+oasIEmWdhXn93brMFYGS4ytObzgMRBwdwp3AA/W2nNH/efuCxN8z X-Forefront-PRVS: 08476BC6EF X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1;BYAPR02MB4456;23:0odP/9H53yxOJvhEy9xzhJpfETpdpZaUVNj/TDdk2?= =?us-ascii?Q?71ztSl7sK3+g1LeWERKQXzvqPku81WTxM8OoSqUigRNlGMrIOGXKd/dvxjR2?= =?us-ascii?Q?SI9LFZDei8yMASN7otlvywzkqeRJgvV6FJpX43wFR2kzUBEC15/RkUGUGHCj?= =?us-ascii?Q?zg3s22ActLdBLUkqzpiN8D7KE+3HHXlWebL74SZooGOt57OM6z5peJ5WaHbs?= =?us-ascii?Q?dkk74xpkqtpbPOn9y7w2a2HxeICXwhpaiTymSZYkVPMYdbhu3Gys0Sn53prb?= =?us-ascii?Q?AwNGwPsQbxqs6BKE3ZFMrmHy/HztN96Tt4EidAInmLMzKmx62pFHV2wZF1Pf?= =?us-ascii?Q?IiHgKUKcDHCeSMPUk3MHSXt6O2D3Hpu+sjmGtTLcSx7Pw5n5O8yoR/eMJEkG?= =?us-ascii?Q?ZXFZdPmW+mnqfa8zOy7V0Afle/NVwh85TzZfgFin37DMZ03TJySLGuTAE8YX?= =?us-ascii?Q?jjuiSVp+dU2jXg9/Bi8xxpKofFKB8x8pBaXRYmi3DLkSiSW7WSa2w98r6qMc?= =?us-ascii?Q?Xy8n0uBeSRA6xqucthDSfs3rcIRxIPZ3S9utjOLMPxYAYOMebmIeJ8hTHUg2?= =?us-ascii?Q?Ato264NJlv8wxF/cOvt5hiN6UYRYIT9vZEtrUDMsGDYP6Au8ZmMN4qgwNz0r?= =?us-ascii?Q?lezYC3Kkz8uoLB1Xre4Q6loVBppfQgCzJGgzTJBR+W5HSKugYOUV8qBj+vw/?= =?us-ascii?Q?laJUWboIREqFh0REg4bHDDZkRszjvvSCIUYy/yO5NgPtKibPgA2IJvycv7lj?= =?us-ascii?Q?HObJ+BSPZu5lvDyEvl85yA94VmAJAwym2HplF7lifcyke0g9hQ+iAXPbaNQo?= =?us-ascii?Q?vj7J1yt39NOKqbyaf+i1bZOmOYk0IyNQHebS9Sk2SwGUSAP7zMHvvxebYIva?= =?us-ascii?Q?0KvULPuwfI9N2VBWAqpItz/7ZpbIqLTO3O+/sLpgqGUuB+HE9djWL17GhT6X?= =?us-ascii?Q?GOwqw/WMWe49y4fw56BC8NxFoG1XhU3iyUt0B2Ojk/ldpRnRgWKHWEH00ZLO?= =?us-ascii?Q?5ameRyLWRYGkrg1gty0jCI7wF3F3SNGgFcL/o4YqdhMuwnWqnKrid+J/WvGD?= =?us-ascii?Q?DYaKmQqAe06wQ0fcIvv5Mze2x7RQcDx7y47R5knhtw4rjNpdlMdZ3wZVsX18?= =?us-ascii?Q?GFKzpJTSXS4Zl81vgeHA7M1w9G6jS4I/fscMIGvDXhsCdG3asmNnniJYbLwF?= =?us-ascii?Q?bV2GcHKAjdXcmKvLkxC6zb8FKgdqiteGYXZfYpnpLF3NN6Esv6Nt5R0QQ=3D?= =?us-ascii?Q?=3D?= X-Microsoft-Antispam-Message-Info: ZOfSOy5pST0xsQCq+/orNSY95jcbJK67rpggYsyv6txOaZF95oY0xfRAllfzEk/rA1xlo1FdANQrOLdfpN6OXH0vsv8uE2x3Jpzlyub6SrwMEdBpEAyFHmfajtcUmxQRjg3/z5bqzpdorQ587g+8O5Vb74AUnAJ+7XEajSVfzpNdbWvPqyjuMBM1wt39bk9An4Sb/872ydBI8C23rU/dJdMN3cFAGjuGIlLRrXXTvTFxUvS/Y93r2dGpKc8g2lm09TbQOO4RjlPgCfAeREgOkYfATx9B40uUYnnKnZmHT2nRSI+4ocV5YG70njnYPuozyXzBDEagB0dg+nIonTWuoESEZsXPdxg8Bq+SGWxABE4= X-Microsoft-Exchange-Diagnostics: 1;BYAPR02MB4456;6:mzWulptYAUPy6ad3lohXHimlNT3uiNGl9DpjzmunAO2yKuUwflvLMb5aTFLWrWGBet4IVvJ5J40iuB4NzM6QDFJcrvHooTw8Tx+VTbqlGUgj/+eRn18BYsnEf9JkEYzy0i2cm4ziQcEwq8Kz89tOOMNUx+7cn18G24VzthAWgJ4IxxGoeOEOI55Ocj9MjksV1nCyhpdvev+TBhNuEfEnWfupsI+juuxhYHWBmUfkFadVGkfiFdvUdg+mtJn2vriM3JNzq8QqSbvCyHRaBB5gyON7ZNEDtu4ewn20XRd4d0V/pcf+4A8YXR0UC1u1I62glNXaEsTl1LTiY9gVH9c84TMkB2R9jsDojY1bP9IcK7uL8HWAehtXzAR66rDZOBgA/G9qN6Tg1oSlCM9dhd1Z7OgIKwKnnj/nrc/XnNhJelvlMm7yxFfhIZPDHLkX5vbuVge59DdzQL29zPwLjCkXTg==;5:Pyxu06qzvx8JYGdFi0NfdLL0uFclVBddbQ9SIqtkr8z7/af4b3knaGkYiu2X8JGnp6Mv62EnxXw/yLD9cw9cK0JNqqBCzIhrGinBgkzMeLBOFW/Va6Q4qowvhwozTSDRH7VJHP/Tu3OCEkidlabDl75V+5i3s+XrhDDfGnL2Rjc=;7:GMUvSjGWVjDapTjJIB/JBbkGZkJzCkrwFwUUi0+rJssKSwFn+Tw9WU4o5N5w+Yd1JoBgZnf/2M0G3Eyk42tG/SdEaQWqxuufsRJOdTXePQoaNq9kb/5YQ+5l2rtUA6PoDYunt+axDbVnb/uaNNajSQ== SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: xilinx.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 05 Nov 2018 22:37:20.1765 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 56820858-eb29-45f5-db4b-08d6436f3f85 X-MS-Exchange-CrossTenant-Id: 657af505-d5df-48d0-8300-c31994686c5c X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=657af505-d5df-48d0-8300-c31994686c5c;Ip=[149.199.60.83];Helo=[xsj-pvapsmtpgw01] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: BYAPR02MB4456 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch is to introduce ZynqMP IPI mailbox controller driver to use the ZynqMP IPI block as mailboxes. Signed-off-by: Wendy Liang --- drivers/mailbox/Kconfig | 9 + drivers/mailbox/Makefile | 2 + drivers/mailbox/zynqmp-ipi-mailbox.c | 762 +++++++++++++++++++++++++++++ include/linux/mailbox/zynqmp-ipi-message.h | 24 + 4 files changed, 797 insertions(+) create mode 100644 drivers/mailbox/zynqmp-ipi-mailbox.c create mode 100644 include/linux/mailbox/zynqmp-ipi-message.h diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index 3eeb12e9..10bfe3f 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -205,4 +205,13 @@ config MTK_CMDQ_MBOX mailbox driver. The CMDQ is used to help read/write registers with critical time limitation, such as updating display configuration during the vblank. + +config ZYNQMP_IPI_MBOX + tristate "Xilinx ZynqMP IPI Mailbox" + depends on ARCH_ZYNQMP && OF + help + Mailbox implementation for Xilinx ZynqMP IPI controller. It is used + to send notification or short message between processors on Xilinx + UltraScale+ MPSoC platforms. Say Y here if you want to have this + support. endif diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index c818b5d..bb3d604 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile @@ -44,3 +44,5 @@ obj-$(CONFIG_TEGRA_HSP_MBOX) += tegra-hsp.o obj-$(CONFIG_STM32_IPCC) += stm32-ipcc.o obj-$(CONFIG_MTK_CMDQ_MBOX) += mtk-cmdq-mailbox.o + +obj-$(CONFIG_ZYNQMP_IPI_MBOX) += zynqmp-ipi-mailbox.o diff --git a/drivers/mailbox/zynqmp-ipi-mailbox.c b/drivers/mailbox/zynqmp-ipi-mailbox.c new file mode 100644 index 0000000..6a2e0fc --- /dev/null +++ b/drivers/mailbox/zynqmp-ipi-mailbox.c @@ -0,0 +1,762 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Xilinx Inter Processor Interrupt(IPI) Mailbox Driver + * + * Copyright (C) 2018 Xilinx Inc. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* IPI agent ID any */ +#define IPI_ID_ANY 0xFFUL + +/* indicate if ZynqMP IPI mailbox driver uses SMC calls or HVC calls */ +#define USE_SMC 0 +#define USE_HVC 1 + +/* Default IPI SMC function IDs */ +#define SMC_IPI_MAILBOX_OPEN 0x82001000U +#define SMC_IPI_MAILBOX_RELEASE 0x82001001U +#define SMC_IPI_MAILBOX_STATUS_ENQUIRY 0x82001002U +#define SMC_IPI_MAILBOX_NOTIFY 0x82001003U +#define SMC_IPI_MAILBOX_ACK 0x82001004U +#define SMC_IPI_MAILBOX_ENABLE_IRQ 0x82001005U +#define SMC_IPI_MAILBOX_DISABLE_IRQ 0x82001006U + +/* IPI SMC Macros */ +#define IPI_SMC_OPEN_IRQ_MASK 0x00000001UL /* IRQ enable bit in IPI + * open SMC call + */ +#define IPI_SMC_NOTIFY_BLOCK_MASK 0x00000001UL /* Flag to indicate if + * IPI notification needs + * to be blocking. + */ +#define IPI_SMC_ENQUIRY_DIRQ_MASK 0x00000001UL /* Flag to indicate if + * notification interrupt + * to be disabled. + */ +#define IPI_SMC_ACK_EIRQ_MASK 0x00000001UL /* Flag to indicate if + * notification interrupt + * to be enabled. + */ + +/* IPI mailbox status */ +#define IPI_MB_STATUS_IDLE 0 +#define IPI_MB_STATUS_SEND_PENDING 1 +#define IPI_MB_STATUS_RECV_PENDING 2 + +#define IPI_MB_CHNL_TX 0 /* IPI mailbox TX channel */ +#define IPI_MB_CHNL_RX 1 /* IPI mailbox RX channel */ + +/** + * struct zynqmp_ipi_mchan - Description of a Xilinx ZynqMP IPI mailbox channel + * @is_opened: indicate if the IPI channel is opened + * @req_buf: local to remote request buffer start address + * @resp_buf: local to remote response buffer start address + * @req_buf_size: request buffer size + * @resp_buf_size: response buffer size + * @rx_buf: receive buffer to pass received message to client + * @chan_type: channel type + */ +struct zynqmp_ipi_mchan { + int is_opened; + void __iomem *req_buf; + void __iomem *resp_buf; + void *rx_buf; + size_t req_buf_size; + size_t resp_buf_size; + unsigned int chan_type; +}; + +/** + * struct zynqmp_ipi_mbox - Description of a ZynqMP IPI mailbox + * platform data. + * @pdata: pointer to the IPI private data + * @dev: device pointer corresponding to the Xilinx ZynqMP + * IPI mailbox + * @remote_id: remote IPI agent ID + * @mbox: mailbox Controller + * @mchans: array for channels, tx channel and rx channel. + * @irq: IPI agent interrupt ID + */ +struct zynqmp_ipi_mbox { + struct zynqmp_ipi_pdata *pdata; + struct device dev; + u32 remote_id; + struct mbox_controller mbox; + struct zynqmp_ipi_mchan mchans[2]; +}; + +/** + * struct zynqmp_ipi_pdata - Description of z ZynqMP IPI agent platform data. + * + * @dev: device pointer corresponding to the Xilinx ZynqMP + * IPI agent + * @irq: IPI agent interrupt ID + * @method: IPI SMC or HVC is going to be used + * @local_id: local IPI agent ID + * @ipi_mboxes: IPI mailboxes of this IPI agent + */ +struct zynqmp_ipi_pdata { + struct device *dev; + int irq; + unsigned int method; + u32 local_id; + int num_mboxes; + struct zynqmp_ipi_mbox *ipi_mboxes; +}; + +static struct device_driver zynqmp_ipi_mbox_driver = { + .owner = THIS_MODULE, + .name = "zynqmp-ipi-mbox", +}; + +static void zynqmp_ipi_fw_call(struct zynqmp_ipi_mbox *ipi_mbox, + unsigned long a0, unsigned long a3, + unsigned long a4, unsigned long a5, + unsigned long a6, unsigned long a7, + struct arm_smccc_res *res) +{ + struct zynqmp_ipi_pdata *pdata = ipi_mbox->pdata; + unsigned long a1, a2; + + a1 = pdata->local_id; + a2 = ipi_mbox->remote_id; + if (pdata->method == USE_SMC) + arm_smccc_smc(a0, a1, a2, a3, a4, a5, a6, a7, res); + else + arm_smccc_hvc(a0, a1, a2, a3, a4, a5, a6, a7, res); +} + +/** + * zynqmp_ipi_interrupt - Interrupt handler for IPI notification + * + * @irq: Interrupt number + * @data: ZynqMP IPI mailbox platform data. + * + * Return: -EINVAL if there is no instance + * IRQ_NONE if the interrupt is not ours. + * IRQ_HANDLED if the rx interrupt was successfully handled. + */ +static irqreturn_t zynqmp_ipi_interrupt(int irq, void *data) +{ + struct zynqmp_ipi_pdata *pdata = data; + struct mbox_chan *chan; + struct zynqmp_ipi_mbox *ipi_mbox; + struct zynqmp_ipi_mchan *mchan; + struct zynqmp_ipi_message *msg; + u64 arg0, arg3; + struct arm_smccc_res res; + int ret, i; + + arg0 = SMC_IPI_MAILBOX_STATUS_ENQUIRY; + arg3 = IPI_SMC_ENQUIRY_DIRQ_MASK; + for (i = 0; i < pdata->num_mboxes; i++) { + ipi_mbox = &pdata->ipi_mboxes[i]; + mchan = &ipi_mbox->mchans[IPI_MB_CHNL_RX]; + chan = &ipi_mbox->mbox.chans[IPI_MB_CHNL_RX]; + zynqmp_ipi_fw_call(ipi_mbox, arg0, arg3, 0, 0, 0, 0, &res); + ret = (int)(res.a0 & 0xFFFFFFFF); + if (ret > 0 && ret & IPI_MB_STATUS_RECV_PENDING) { + if (mchan->is_opened) { + msg = mchan->rx_buf; + msg->len = mchan->req_buf_size; + memcpy_fromio(msg->data, mchan->req_buf, + msg->len); + mbox_chan_received_data(chan, (void *)msg); + return IRQ_HANDLED; + } + } + } + return IRQ_NONE; +} + +/** + * zynqmp_ipi_peek_data - Peek to see if there are any rx messages. + * + * @chan: Channel Pointer + * + * Return: 'true' if there is pending rx data, 'false' if there is none. + */ +static bool zynqmp_ipi_peek_data(struct mbox_chan *chan) +{ + struct device *dev = chan->mbox->dev; + struct zynqmp_ipi_mbox *ipi_mbox = dev_get_drvdata(dev); + struct zynqmp_ipi_mchan *mchan = chan->con_priv; + int ret; + u64 arg0; + struct arm_smccc_res res; + + if (WARN_ON(!ipi_mbox)) { + dev_err(dev, "no platform drv data??\n"); + return false; + } + + arg0 = SMC_IPI_MAILBOX_STATUS_ENQUIRY; + zynqmp_ipi_fw_call(ipi_mbox, arg0, 0, 0, 0, 0, 0, &res); + ret = (int)(res.a0 & 0xFFFFFFFF); + + if (mchan->chan_type == IPI_MB_CHNL_TX) { + /* TX channel, check if the message has been acked + * by the remote, if yes, response is available. + */ + if (ret < 0 || ret & IPI_MB_STATUS_SEND_PENDING) + return false; + else + return true; + } else if (ret > 0 && ret & IPI_MB_STATUS_RECV_PENDING) { + /* RX channel, check if there is message arrived. */ + return true; + } + return false; +} + +/** + * zynqmp_ipi_last_tx_done - See if the last tx message is sent + * + * @chan: Channel pointer + * + * Return: 'true' is no pending tx data, 'false' if there are any. + */ +static bool zynqmp_ipi_last_tx_done(struct mbox_chan *chan) +{ + struct device *dev = chan->mbox->dev; + struct zynqmp_ipi_mbox *ipi_mbox = dev_get_drvdata(dev); + struct zynqmp_ipi_mchan *mchan = chan->con_priv; + int ret; + u64 arg0; + struct arm_smccc_res res; + struct zynqmp_ipi_message *msg; + + if (WARN_ON(!ipi_mbox)) { + dev_err(dev, "no platform drv data??\n"); + return false; + } + + if (mchan->chan_type == IPI_MB_CHNL_TX) { + /* We only need to check if the message been taken + * by the remote in the TX channel + */ + arg0 = SMC_IPI_MAILBOX_STATUS_ENQUIRY; + zynqmp_ipi_fw_call(ipi_mbox, arg0, 0, 0, 0, 0, 0, &res); + /* Check the SMC call status, a0 of the result */ + ret = (int)(res.a0 & 0xFFFFFFFF); + if (ret < 0 || ret & IPI_MB_STATUS_SEND_PENDING) + return false; + + msg = mchan->rx_buf; + msg->len = mchan->resp_buf_size; + memcpy_fromio(msg->data, mchan->resp_buf, msg->len); + mbox_chan_received_data(chan, (void *)msg); + return true; + } + /* Always true for the response message in RX channel */ + return true; +} + +/** + * zynqmp_ipi_send_data - Send data + * + * @chan: Channel Pointer + * @data: Message Pointer + * + * Return: 0 if all goes good, else appropriate error messages. + */ +static int zynqmp_ipi_send_data(struct mbox_chan *chan, void *data) +{ + struct device *dev = chan->mbox->dev; + struct zynqmp_ipi_mbox *ipi_mbox = dev_get_drvdata(dev); + struct zynqmp_ipi_mchan *mchan = chan->con_priv; + struct zynqmp_ipi_message *msg = data; + u64 arg0; + struct arm_smccc_res res; + u32 timeout; + int ret; + + if (WARN_ON(!ipi_mbox)) { + dev_err(dev, "no platform drv data??\n"); + return -EINVAL; + } + + if (mchan->chan_type == IPI_MB_CHNL_TX) { + /* Send request message */ + if (msg && msg->len > mchan->req_buf_size) { + dev_err(dev, "channel %d message length %u > max %lu\n", + mchan->chan_type, (unsigned int)msg->len, + mchan->req_buf_size); + return -EINVAL; + } + /* Enquire if the mailbox is free to send message */ + arg0 = SMC_IPI_MAILBOX_STATUS_ENQUIRY; + timeout = 10; + if (msg && msg->len) { + timeout = 10; + do { + zynqmp_ipi_fw_call(ipi_mbox, arg0, + 0, 0, 0, 0, 0, &res); + ret = res.a0 & 0xFFFFFFFF; + if (ret >= 0 && + !(ret & IPI_MB_STATUS_SEND_PENDING)) + break; + usleep_range(1, 2); + timeout--; + } while (timeout); + if (!timeout) { + dev_warn(dev, "chan %d sending msg timeout.\n", + ipi_mbox->remote_id); + return -ETIME; + } + memcpy_toio(mchan->req_buf, msg->data, msg->len); + } + /* Kick IPI mailbox to send message */ + arg0 = SMC_IPI_MAILBOX_NOTIFY; + zynqmp_ipi_fw_call(ipi_mbox, arg0, 0, 0, 0, 0, 0, &res); + } else { + /* Send response message */ + if (msg && msg->len > mchan->resp_buf_size) { + dev_err(dev, "channel %d message length %u > max %lu\n", + mchan->chan_type, (unsigned int)msg->len, + mchan->resp_buf_size); + return -EINVAL; + } + if (msg && msg->len) + memcpy(mchan->resp_buf, msg->data, msg->len); + arg0 = SMC_IPI_MAILBOX_NOTIFY; + arg0 = SMC_IPI_MAILBOX_ACK; + zynqmp_ipi_fw_call(ipi_mbox, arg0, IPI_SMC_ACK_EIRQ_MASK, + 0, 0, 0, 0, &res); + } + return 0; +} + +/** + * zynqmp_ipi_startup - Startup the IPI channel + * + * @chan: Channel pointer + * + * Return: 0 if all goes good, else return corresponding error message + */ +static int zynqmp_ipi_startup(struct mbox_chan *chan) +{ + struct device *dev = chan->mbox->dev; + struct zynqmp_ipi_mbox *ipi_mbox = dev_get_drvdata(dev); + struct zynqmp_ipi_mchan *mchan = chan->con_priv; + u64 arg0; + struct arm_smccc_res res; + int ret = 0; + unsigned int nchan_type; + + if (mchan->is_opened) + return 0; + + /* If no channel has been opened, open the IPI mailbox */ + nchan_type = (mchan->chan_type + 1) % 2; + if (!ipi_mbox->mchans[nchan_type].is_opened) { + arg0 = SMC_IPI_MAILBOX_OPEN; + zynqmp_ipi_fw_call(ipi_mbox, arg0, 0, 0, 0, 0, 0, &res); + /* Check the SMC call status, a0 of the result */ + ret = (int)(res.a0 | 0xFFFFFFFF); + if (res.a0 < 0) { + dev_err(dev, "SMC to open the IPI channel failed.\n"); + ret = res.a0; + return ret; + } + ret = 0; + } + + /* If it is RX channel, enable the IPI notification interrupt */ + if (mchan->chan_type == IPI_MB_CHNL_RX) { + arg0 = SMC_IPI_MAILBOX_ENABLE_IRQ; + zynqmp_ipi_fw_call(ipi_mbox, arg0, 0, 0, 0, 0, 0, &res); + } + mchan->is_opened = 1; + + return ret; +} + +/** + * zynqmp_ipi_shutdown - Shutdown the IPI channel + * + * @chan: Channel pointer + */ +static void zynqmp_ipi_shutdown(struct mbox_chan *chan) +{ + struct device *dev = chan->mbox->dev; + struct zynqmp_ipi_mbox *ipi_mbox = dev_get_drvdata(dev); + struct zynqmp_ipi_mchan *mchan = chan->con_priv; + u64 arg0; + struct arm_smccc_res res; + unsigned int chan_type; + + if (!mchan->is_opened) + return; + + /* If it is RX channel, disable notification interrupt */ + chan_type = mchan->chan_type; + if (chan_type == IPI_MB_CHNL_RX) { + arg0 = SMC_IPI_MAILBOX_DISABLE_IRQ; + zynqmp_ipi_fw_call(ipi_mbox, arg0, 0, 0, 0, 0, 0, &res); + } + /* Release IPI mailbox if no other channel is opened */ + chan_type = (chan_type + 1) % 2; + if (!ipi_mbox->mchans[chan_type].is_opened) { + arg0 = SMC_IPI_MAILBOX_RELEASE; + zynqmp_ipi_fw_call(ipi_mbox, arg0, 0, 0, 0, 0, 0, &res); + } + + mchan->is_opened = 0; +} + +/* ZynqMP IPI mailbox operations */ +static const struct mbox_chan_ops zynqmp_ipi_chan_ops = { + .startup = zynqmp_ipi_startup, + .shutdown = zynqmp_ipi_shutdown, + .peek_data = zynqmp_ipi_peek_data, + .last_tx_done = zynqmp_ipi_last_tx_done, + .send_data = zynqmp_ipi_send_data, +}; + +/** + * zynqmp_ipi_of_xlate - Translate of phandle to IPI mailbox channel + * + * @mbox: mailbox controller pointer + * @p: phandle pointer + * + * Return: Mailbox channel, else return error pointer. + */ +static struct mbox_chan *zynqmp_ipi_of_xlate(struct mbox_controller *mbox, + const struct of_phandle_args *p) +{ + struct mbox_chan *chan; + struct device *dev = mbox->dev; + unsigned int chan_type; + + /* Only supports TX and RX channels */ + chan_type = p->args[0]; + if (chan_type != IPI_MB_CHNL_TX && chan_type != IPI_MB_CHNL_RX) { + dev_err(dev, "req chnl failure: invalid chnl type %u.\n", + chan_type); + return ERR_PTR(-EINVAL); + } + chan = &mbox->chans[chan_type]; + return chan; +} + +static const struct of_device_id zynqmp_ipi_of_match[] = { + {.compatible = "xlnx,zynqmp-ipi-mailbox"}, +}; +MODULE_DEVICE_TABLE(of, zynqmp_ipi_of_match); + +/** + * zynqmp_ipi_mbox_get_buf_res - Get buffer resource from the IPI dev node + * + * @node: IPI mbox device child node + * @name: name of the IPI buffer + * @res: pointer to where the resource information will be stored. + * + * Return: 0 for success, negative value for failure + */ +static int zynqmp_ipi_mbox_get_buf_res(struct device_node *node, + const char *name, + struct resource *res) +{ + int ret, index; + + index = of_property_match_string(node, "reg-names", name); + if (index >= 0) { + ret = of_address_to_resource(node, index, res); + if (ret < 0) + return -EINVAL; + return 0; + } + return -ENODEV; +} + +/** + * zynqmp_ipi_mbox_dev_release() - release the existence of a ipi mbox dev + * + * This is to avoid the no device release() function kernel warning. + * + * @dev: the ipi mailbox device + */ +static void zynqmp_ipi_mbox_dev_release(struct device *dev) +{ + (void)dev; +} + +/** + * zynqmp_ipi_mbox_probe - probe IPI mailbox resource from device node + * + * @ipi_mbox: pointer to IPI mailbox private data structure + * @node: IPI mailbox device node + * + * Return: 0 for success, negative value for failure + */ +static int zynqmp_ipi_mbox_probe(struct zynqmp_ipi_mbox *ipi_mbox, + struct device_node *node) +{ + struct zynqmp_ipi_mchan *mchan; + struct mbox_chan *chans; + struct mbox_controller *mbox; + struct resource res; + struct device *dev, *mdev; + const char *name; + int ret; + + dev = ipi_mbox->pdata->dev; + /* Initialize dev for IPI mailbox */ + ipi_mbox->dev.parent = dev; + ipi_mbox->dev.release = NULL; + ipi_mbox->dev.of_node = node; + dev_set_name(&ipi_mbox->dev, "%s", of_node_full_name(node)); + dev_set_drvdata(&ipi_mbox->dev, ipi_mbox); + ipi_mbox->dev.release = zynqmp_ipi_mbox_dev_release; + ipi_mbox->dev.driver = &zynqmp_ipi_mbox_driver; + ret = device_register(&ipi_mbox->dev); + if (ret) { + dev_err(dev, "Failed to register ipi mbox dev.\n"); + return ret; + } + mdev = &ipi_mbox->dev; + + mchan = &ipi_mbox->mchans[IPI_MB_CHNL_TX]; + name = "local_request_region"; + ret = zynqmp_ipi_mbox_get_buf_res(node, name, &res); + if (!ret) { + mchan->req_buf_size = resource_size(&res); + mchan->req_buf = devm_ioremap(mdev, res.start, + mchan->req_buf_size); + if (IS_ERR(mchan->req_buf)) { + dev_err(dev, "Unable to map IPI buffer I/O memory\n"); + ret = PTR_ERR(mchan->req_buf); + return ret; + } + } else if (ret != -ENODEV) { + dev_err(mdev, "Unmatched resource %s, %d.\n", name, ret); + return ret; + } + + name = "remote_response_region"; + ret = zynqmp_ipi_mbox_get_buf_res(node, name, &res); + if (!ret) { + mchan->resp_buf_size = resource_size(&res); + mchan->resp_buf = devm_ioremap(mdev, res.start, + mchan->resp_buf_size); + if (IS_ERR(mchan->resp_buf)) { + dev_err(mdev, "Unable to map IPI buffer I/O memory\n"); + ret = PTR_ERR(mchan->resp_buf); + return ret; + } + } else if (ret != -ENODEV) { + dev_err(mdev, "Unmatched resource %s.\n", name); + return ret; + } + mchan->rx_buf = devm_kzalloc(mdev, + mchan->resp_buf_size + + sizeof(struct zynqmp_ipi_message), + GFP_KERNEL); + if (!mchan->rx_buf) + return -ENOMEM; + + mchan = &ipi_mbox->mchans[IPI_MB_CHNL_RX]; + name = "remote_request_region"; + ret = zynqmp_ipi_mbox_get_buf_res(node, name, &res); + if (!ret) { + mchan->req_buf_size = resource_size(&res); + mchan->req_buf = devm_ioremap(mdev, res.start, + mchan->req_buf_size); + if (IS_ERR(mchan->req_buf)) { + dev_err(mdev, "Unable to map IPI buffer I/O memory\n"); + ret = PTR_ERR(mchan->req_buf); + return ret; + } + } else if (ret != -ENODEV) { + dev_err(mdev, "Unmatched resource %s.\n", name); + return ret; + } + + name = "local_response_region"; + ret = zynqmp_ipi_mbox_get_buf_res(node, name, &res); + if (!ret) { + mchan->resp_buf_size = resource_size(&res); + mchan->resp_buf = devm_ioremap(mdev, res.start, + mchan->resp_buf_size); + if (IS_ERR(mchan->resp_buf)) { + dev_err(mdev, "Unable to map IPI buffer I/O memory\n"); + ret = PTR_ERR(mchan->resp_buf); + return ret; + } + } else if (ret != -ENODEV) { + dev_err(mdev, "Unmatched resource %s.\n", name); + return ret; + } + mchan->rx_buf = devm_kzalloc(mdev, + mchan->resp_buf_size + + sizeof(struct zynqmp_ipi_message), + GFP_KERNEL); + if (!mchan->rx_buf) + return -ENOMEM; + + /* Get the IPI remote agent ID */ + ret = of_property_read_u32(node, "xlnx,ipi-id", &ipi_mbox->remote_id); + if (ret < 0) { + dev_err(dev, "No IPI remote ID is specified.\n"); + return ret; + } + + mbox = &ipi_mbox->mbox; + mbox->dev = mdev; + mbox->ops = &zynqmp_ipi_chan_ops; + mbox->num_chans = 2; + mbox->txdone_irq = false; + mbox->txdone_poll = true; + mbox->txpoll_period = 5; + mbox->of_xlate = zynqmp_ipi_of_xlate; + chans = devm_kzalloc(mdev, 2 * sizeof(*chans), GFP_KERNEL); + if (!chans) + return -ENOMEM; + mbox->chans = chans; + chans[IPI_MB_CHNL_TX].con_priv = &ipi_mbox->mchans[IPI_MB_CHNL_TX]; + chans[IPI_MB_CHNL_RX].con_priv = &ipi_mbox->mchans[IPI_MB_CHNL_RX]; + ipi_mbox->mchans[IPI_MB_CHNL_TX].chan_type = IPI_MB_CHNL_TX; + ipi_mbox->mchans[IPI_MB_CHNL_RX].chan_type = IPI_MB_CHNL_RX; + ret = mbox_controller_register(mbox); + if (ret) + dev_err(mdev, + "Failed to register mbox_controller(%d)\n", ret); + else + dev_info(mdev, "Probed ZynqMP IPI Mailbox driver.\n"); + return ret; +} + +/** + * zynqmp_ipi_free_mboxes - Free IPI mailboxes devices + * + * @pdata: IPI private data + */ +static void zynqmp_ipi_free_mboxes(struct zynqmp_ipi_pdata *pdata) +{ + struct zynqmp_ipi_mbox *ipi_mbox; + int i; + + i = pdata->num_mboxes; + for (; i >= 0; i--) { + ipi_mbox = &pdata->ipi_mboxes[i]; + if (ipi_mbox->dev.parent) { + mbox_controller_unregister(&ipi_mbox->mbox); + device_unregister(&ipi_mbox->dev); + } + } +} + +static int zynqmp_ipi_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *nc, *np = pdev->dev.of_node; + struct zynqmp_ipi_pdata *pdata; + struct zynqmp_ipi_mbox *mbox; + int i, ret = -EINVAL; + + i = 0; + for_each_available_child_of_node(np, nc) + i++; + pdata = devm_kzalloc(dev, sizeof(*pdata) + (i * sizeof(*mbox)), + GFP_KERNEL); + if (!pdata) + return -ENOMEM; + pdata->dev = dev; + + /* Get the IPI local agents ID */ + ret = of_property_read_u32(np, "xlnx,ipi-id", &pdata->local_id); + if (ret < 0) { + dev_err(dev, "No IPI local ID is specified.\n"); + return ret; + } + + pdata->num_mboxes = i; + pdata->ipi_mboxes = (struct zynqmp_ipi_mbox *) + ((char *)pdata + sizeof(*pdata)); + + mbox = pdata->ipi_mboxes; + for_each_available_child_of_node(np, nc) { + mbox->pdata = pdata; + ret = zynqmp_ipi_mbox_probe(mbox, nc); + if (ret) { + dev_err(dev, "failed to probe subdev.\n"); + ret = -EINVAL; + goto free_mbox_dev; + } + mbox++; + } + + /* IPI IRQ */ + ret = platform_get_irq(pdev, 0); + if (ret < 0) { + dev_err(dev, "unable to find IPI IRQ.\n"); + goto free_mbox_dev; + } + pdata->irq = ret; + ret = devm_request_irq(dev, pdata->irq, zynqmp_ipi_interrupt, + IRQF_SHARED, dev_name(dev), pdata); + if (ret) { + dev_err(dev, "IRQ %d is not requested successfully.\n", + pdata->irq); + goto free_mbox_dev; + } + + platform_set_drvdata(pdev, pdata); + return ret; + +free_mbox_dev: + zynqmp_ipi_free_mboxes(pdata); + return ret; +} + +static int zynqmp_ipi_remove(struct platform_device *pdev) +{ + struct zynqmp_ipi_pdata *pdata; + + pdata = platform_get_drvdata(pdev); + zynqmp_ipi_free_mboxes(pdata); + + return 0; +} + +static struct platform_driver zynqmp_ipi_driver = { + .probe = zynqmp_ipi_probe, + .remove = zynqmp_ipi_remove, + .driver = { + .name = "zynqmp-ipi", + .of_match_table = of_match_ptr(zynqmp_ipi_of_match), + }, +}; + +static int __init zynqmp_ipi_init(void) +{ + return platform_driver_register(&zynqmp_ipi_driver); +} +subsys_initcall(zynqmp_ipi_init); + +static void __exit zynqmp_ipi_exit(void) +{ + platform_driver_unregister(&zynqmp_ipi_driver); +} +module_exit(zynqmp_ipi_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Xilinx ZynqMP IPI Mailbox driver"); +MODULE_AUTHOR("Xilinx Inc."); diff --git a/include/linux/mailbox/zynqmp-ipi-message.h b/include/linux/mailbox/zynqmp-ipi-message.h new file mode 100644 index 0000000..72a9d9d --- /dev/null +++ b/include/linux/mailbox/zynqmp-ipi-message.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2017 Xilinx Inc. + * + */ + +#ifndef _LINUX_ZYNQMP_IPI_MESSAGE_H_ +#define _LINUX_ZYNQMP_IPI_MESSAGE_H_ + +/** + * struct zynqmp_ipi_message - ZynqMP IPI message structure + * @len: Length of the request message + * @data: Request message + * + * This is the structure for data used in mbox_send_message + * the maximum length of data buffer is fixed to 12 bytes. + * Client is supposed to be aware of this. + */ +struct zynqmp_ipi_message { + size_t len; + u8 data[0]; +}; + +#endif /* _LINUX_ZYNQMP_IPI_MESSAGE_H_ */ -- 2.7.4