From nobody Mon Dec 15 22:46:29 2025 Received: from mx0b-0024c301.pphosted.com (mx0b-0024c301.pphosted.com [148.163.153.153]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B6526224AE0 for ; Fri, 12 Dec 2025 16:49:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=148.163.153.153 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1765558180; cv=fail; b=pfsBib88j58IbkAxqwbDen+Kbv44dmxoTg6hkmwDO9FGV4ZnNbAX61xsDS5ToUBeGQGzIJXxJtSEfUZsSnMmjyjg+StA2skIGwRMfdJ1QvJq+yWnWlIHxKaCZq+irNjexaAMOKh1Z4QlmmY0T6Y0VrglD1ondpnr20P7Fb+2y4s= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1765558180; c=relaxed/simple; bh=HBeWldmPbvCnedKxFTw59us13CMMykCrmUlAQ8VY5CI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: Content-Type:MIME-Version; b=Yu6ia2NmTIJaETvj2t4kzQeGy3sNdPOVQdz4xRCLnNWcZQ3/dGBhqFjm+ir8qi64siXhykIVIDnfQ41aIrMKAfAseJ5Nz1PCtW/Acd5+7Xxgt0jV1HfDMBPHByZ3MoY45qFoRsdVMj4HCSOTJc336V+SSc2UfApV2xEb1V7W9Ms= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=silabs.com; spf=pass smtp.mailfrom=silabs.com; dkim=pass (2048-bit key) header.d=silabs.com header.i=@silabs.com header.b=EUAYmSsd; dkim=pass (1024-bit key) header.d=silabs.com header.i=@silabs.com header.b=CdeFtDzU; arc=fail smtp.client-ip=148.163.153.153 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=silabs.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=silabs.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=silabs.com header.i=@silabs.com header.b="EUAYmSsd"; dkim=pass (1024-bit key) header.d=silabs.com header.i=@silabs.com header.b="CdeFtDzU" Received: from pps.filterd (m0101742.ppops.net [127.0.0.1]) by mx0a-0024c301.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 5BCBo1De3523286; Fri, 12 Dec 2025 10:13:34 -0600 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=silabs.com; h=cc :content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=pps12202023; bh=4srF8DjHjXqya7FKJIhvTqDtNsPwI5GjJklr2vlKn+I=; b=EUAYmSsdlccz sYK94OgC/9nOlIk71T0V7YAIhIo8nxn1cmHWKRuOES0mUjJhDuV8nbAIAzT7Ea+5 LnzDNz4fTgyB0kreQBbcD7RkVIiA9OzJUFG/gUF4RyXW5/mDKCTXYlirNJpzCEhE qRJP7llhRfU26Q8Sug7KtJ4zSmZymhulv1g7wKxZn0tdC/6UI9UlU9WsrcZProEP UiiFBVfVeLZIqVc1P7N4+duAryXEScqTenrA+qsPsl5DvujkHh49ZTeu+Evs+B7k t+JAT/xXwUeBf+9TKgggWhMTO17CekkOpupaXNqwZtTHWXqZZRA/cMN9/aRYf7AV 2r2JzWK+3g== Received: from bl2pr02cu003.outbound.protection.outlook.com (mail-eastusazon11021107.outbound.protection.outlook.com [52.101.52.107]) by mx0a-0024c301.pphosted.com (PPS) with ESMTPS id 4aykqe47hx-1 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Fri, 12 Dec 2025 10:13:34 -0600 (CST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=dJWHYC8Pd48SDfNQD334d2Lnm3g3L3/+hKe/45pJ0NA+W10TGZlrjAp8vXmshBlEg8yerfRD075PqTNPMF6gTKwHXJWe44TCPuH8/0n6AglI5oEgeWkiC8edWbrPx0w2JvPQeP0Oj/6XwrHMnZqYPh7HoPLXmA2w6Ee0sipQ7F2xDnrDJon91LVFtxAhBuveRSoIN48tvgIJiWA9gFChvkBOY0Uz4qw5Pya3rkzanYSxS4Y1Zok7TTgfI9bwIt7KtmZr+Ih//9FW2NBLfnS8lnsU9qaz4wGYBgg2yQB5GfwoiQB2X1eWyhrUU+wcEQhQQud3CrzIdaOf0YBUpmawjA== 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=4srF8DjHjXqya7FKJIhvTqDtNsPwI5GjJklr2vlKn+I=; b=zHsFDTtQngiRDFQcjLhEhROVB1bbW3Ro6kLMw2J6r5+SqQ8Y/7ChZyYvJTXwkcwhz4tUT4VUvJhDjhwDBEtK09cwnuC34TUGH7ZLLvzdAYywg5N8yY6MYyFtEhqv/cA2+CWHWvs6n7SPUT0XOwh8QQWwqQ+ocb297X5/i+vawdn3Va5Dxw3KOjWYzd+imF3GSpZVrdy0M2lQhb5S9y+sKQxRpMxVva9C0nYeRxZ+VJoMLghAfdUiI0gbbi9e/ETGkdMdEQ/G8lwfGHT3u+8y2GRMeB1BusHkw4vF0LdxbO9wrFXl+cPHAfkiWo68O4PWw9sdIr9kcp1+Lx1rXE3bJg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=silabs.com; dmarc=pass action=none header.from=silabs.com; dkim=pass header.d=silabs.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=silabs.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=4srF8DjHjXqya7FKJIhvTqDtNsPwI5GjJklr2vlKn+I=; b=CdeFtDzUu9BE5Vfg0mxzyW5AHSgwqeDYZIOB87U1TBgN+YBs94dR4caQdlTnHYVT+SVWidsEVn8j7kJe/avcT1h8d6+pdjdtf7w3aIWP+akpjGurXn1y1l2+MOMqbcjvzZ+9j4G1aOcbUrzVADO0In+QB7fWdX1Wl23iHF82x2A= Received: from DS0PR11MB8205.namprd11.prod.outlook.com (2603:10b6:8:162::17) by MN0PR11MB6111.namprd11.prod.outlook.com (2603:10b6:208:3cd::11) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9412.9; Fri, 12 Dec 2025 16:13:32 +0000 Received: from DS0PR11MB8205.namprd11.prod.outlook.com ([fe80::2de6:bc88:2af7:3583]) by DS0PR11MB8205.namprd11.prod.outlook.com ([fe80::2de6:bc88:2af7:3583%3]) with mapi id 15.20.9412.005; Fri, 12 Dec 2025 16:13:32 +0000 From: =?UTF-8?q?Damien=20Ri=C3=A9gel?= To: greybus-dev@lists.linaro.org Cc: linux-kernel@vger.kernel.org, Johan Hovold , Alex Elder , Greg Kroah-Hartman , Silicon Labs Kernel Team , Gabriel Beaulieu , =?UTF-8?q?Damien=20Ri=C3=A9gel?= Subject: [PATCH 14/14] greybus: cpc: add CPC SDIO host driver Date: Fri, 12 Dec 2025 11:13:08 -0500 Message-ID: <20251212161308.25678-15-damien.riegel@silabs.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20251212161308.25678-1-damien.riegel@silabs.com> References: <20251212161308.25678-1-damien.riegel@silabs.com> Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: YQZPR01CA0176.CANPRD01.PROD.OUTLOOK.COM (2603:10b6:c01:8b::25) To DS0PR11MB8205.namprd11.prod.outlook.com (2603:10b6:8:162::17) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DS0PR11MB8205:EE_|MN0PR11MB6111:EE_ X-MS-Office365-Filtering-Correlation-Id: 8cf5b5b7-975f-4d36-2d2b-08de3999653c X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|52116014|366016|376014|38350700014; X-Microsoft-Antispam-Message-Info: =?utf-8?B?bk0vZTA3VVRIUGE0NTJCaFJ0NzZQY0N2Vmxqa1VQTFFRNjV2Z3A2QVFiZ3Fo?= =?utf-8?B?QkdFbEpZL3RoaDlicm15MjdEUGM3aFI2TSt6cTE1ZmZVYlpxR0crTHZRcTBS?= =?utf-8?B?NlptVHNETkJPVy9lZ2ZzOCs5Z1lGcTVaVXVPU3RjWng4dGg3SGltK3ozWTMz?= =?utf-8?B?UzgwY3orTU0zbUM0VVozSDhkby9GVlJBQTRsMjBZS3FLb3h5bGVuZkhFU1la?= =?utf-8?B?Nm9qaG1DTm1EanRBbHVIdXBIN0lSOVQ1ODg1YWFqeElnMWhpT3Z5OVFLWVpD?= =?utf-8?B?Z3FCZEVyZ0ZYTGd6UVI2Q2U5bUhETE9mY3l1TWQxTUorSFBjZStSSWRkRkFU?= =?utf-8?B?Z1BsU0hxa2tnYm80STVqZWhlNzBIdktBalFpNC95Y2Jycy9RdHhZSExwTzdm?= =?utf-8?B?MlFRY1RNb21wRDEyb1N4RGQyd1ptME5TUjliM1pKYVpVNHRpbU5wek1mdFdw?= =?utf-8?B?K09ndXZvUGY1ZG81MDNXcjUwSTJVSytjMW1ucXkwUUZMWW50VFIvelJ4ZTRs?= =?utf-8?B?UTZ1WExSQ1U3Z1RsbkdSNDdTOHI5clBHQnN1WlJBcmFPNlA1dnJ6OVNZSDk5?= =?utf-8?B?T1kxWGRyT202Q3c0Z243MC9MUHYxTzQ3ME9tdjZTaVBPTm5CWEdrb205M0t3?= =?utf-8?B?T25WT0YraWNrNExNOWhRZGR4aHpEWnZxZ04vd3NGbEVaUzBlSXRoVGE0T1oy?= =?utf-8?B?MWZha1VhditJRUhWVXZReVNJKzUxdEMyTnA2KzdpdkhDVDlzOWlJTGxOMXI0?= =?utf-8?B?d1RnRE8xSXBIcVJlVTJtQWt6MW9pNm5CRnBIdEVmRHAwaXNFdEx3Rk8xckFu?= =?utf-8?B?cjc5ZnhXdDFMcytkQ2dIVW9YaG0vSU5XK28yZittUnR2c3pGVUR2SjVwcWJt?= =?utf-8?B?VmNyVHpEdUhVUnhEUyswTUxjK2JhRDJYYmhxZmNzZEl1VXpRNjZXbW1INjhU?= =?utf-8?B?b01GN24wTE1uczZkaVE0dnlMdkpLK0cyOWRoc0JiRUZ0QlRCTmhRMm5LNWY0?= =?utf-8?B?QW5VcGFtd2Z3U0Jzd1k0RUpEZ214enhIZGdkWXlFcmh1bklHdE8zL2FqODkv?= =?utf-8?B?bnVoaldPaFlDczI4VnQ4QjJuNytmajFxMkZ1clN3cm5WYlZ0dUd2dzRmdnls?= =?utf-8?B?RGJaRXQ5TC9IOG1nTjVaRXEzKzhxNVVCbi9vQ1lQbXZtQzhLaU5YV0drbVNH?= =?utf-8?B?V0s2T1hiUjU3VERac0NMV0xmTm9KMnppS0hzd3MwdStZdElJRDkwcXpJaXNq?= =?utf-8?B?OTVOS1BMMlByTEtvK2FuSFRhRWpUd2hWNHFGM0J6UGFWRC9WU3Y0TWI2WUZl?= =?utf-8?B?YzJ3SGFnLzRLVEZKL29jOEZjSzN6L1k4TjF0VUVoem5vNFZ1R1EzYVRZeDU3?= =?utf-8?B?clZMMFlHbnYwUGtHblhsMkYzdEwyTTBaMW1Vb0tSMXV3VmxIbjZub21PWUVC?= =?utf-8?B?UjNqSVdWZCtKa3FjVmo4UUZWbHlxRFB2SXQwbEo3QWpJc29USDRybXRiT216?= =?utf-8?B?TkNiWU8rZzNrR0IvTDh3WU1yWWJBZW9mc3F6M3BmRGIzTWdJUW9LN0VPMDZX?= =?utf-8?B?UGU0NXZJdXZRbnpCZHVYdnVCaS9HUHF6bk4vdmFvQko1MEhKaFlFNk5vZnFO?= =?utf-8?B?S09Cb05TS0RVUzJrTzRDSTVwOHlmejRCcW1rdzNGbUZFVVpuQW1aS1JpU0p3?= =?utf-8?B?bllkNEZZamFEcnFYeEViTjdwUGhkTVYyRWtlMzJZT1ZueWNNU3lSdXdvZjZL?= =?utf-8?B?YWNDbk9aaGlDTVk3amtXK1BHdUdpL04ycERsQUx0N2NkZFR5dnRhR3BIMUNB?= =?utf-8?B?UzByUmQyeFBrcnpER0tES3o3bnF4WlUzRXNGVVlNQ3V5ZnFzRW5ZMXFkZDla?= =?utf-8?B?OWlHelFxMXFaNEZSSVcrNEFiMXNjdUI5TUFnME16WmNvbTZGYVV1WS9FSnJM?= =?utf-8?B?anlTWWFpZEtCQWNOVUFGdk43QURMQ2M2MFQ1dFk4TFhCbHRLOC9BeGdFRVNL?= =?utf-8?B?ZjdSKzVlRUt3a3ErdlIrQjJnbnh6ZExLV3ZYOFEzV24wdVVVUG1LenFoZWN2?= =?utf-8?Q?DOZ8t1?= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:DS0PR11MB8205.namprd11.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(1800799024)(52116014)(366016)(376014)(38350700014);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?ekR4UUw3MHBXd1ZOZkhwaFgzbmZzckIzQUJUcWIyLzh1YzFmUWRxMzQ0Zjl5?= =?utf-8?B?UmFYWG1DWlpBb1VsOWhBeTUrYktIdGhRWlhJWGpqR2hmSUh2QTh4ZkJqWStC?= =?utf-8?B?NTdyZkpNV1RiMWNYVktZd0NuYkwxUDkyQzNuUU5zVE9OQWFOQkRFdFBTcElm?= =?utf-8?B?NC9tWGVhaWxRS0J6aFR5VnYyTUxRSlRnbnJwWHVCS0Z6b3pTRzhJVzgvckUr?= =?utf-8?B?MmlYTnBqK1ljeVNMTjRrMWxIdWVXWU9DbWJQdnhRRldkMjRWNE1OWHJXRFpF?= =?utf-8?B?cFFsOXA1OGJKazBoQytMdjNocGswVzNWUWIzdW50ZXU5QStRRVpBNkhqbll5?= =?utf-8?B?azYxZ1JrYTB0YUlTMXFUNGZDVGZtRWRtODJQdld4amZ1a1ZhL3JnNEJuZ1hr?= =?utf-8?B?RlZ1K0R2R0dNUFhPNWJJeTlZcDMyNnY4SUhHdFVtQW9kNE1iNlkvMnlUYVhp?= =?utf-8?B?V3E1WVBjVzQwb2h5enAxODEyeGxPU3Q4Tk9QSHkyazVlS3V0M2xxRW0rdDJW?= =?utf-8?B?TzZQVnZCSXFMZnA1WURqZmhpOWtMUDh3MnZJY25ZYVA1MWgrS3pjS3VBMVd2?= =?utf-8?B?d1FZbHZOaWpKTXhJdXJjeUtQMDRCeVVFaXJNVGZoeURiQWR1WU1GU0hic2RP?= =?utf-8?B?NVI3SXk4WGh4VTcyWVZXWEdZdko3UkQ3dEVRaE9CSTZYQ0tPaG5jaHptNlhU?= =?utf-8?B?d0xFY1VQRENLWUlobGlmMjRPdXNxcXppdmRvVkIxM29YQnlKVmtSRW9hQzhW?= =?utf-8?B?eDFYT3VKUW5VcWFaWVFMY3IyUVdCYnhMOTkrQ3NjV0dtSFpqZkkzRTBvSlpL?= =?utf-8?B?RlNuOEhOaXFSbGxWYjM4Uzc2bmNVN2sram40VldzOEdGamVicmo1VDhSUkVS?= =?utf-8?B?L2dkcC9iMk45anJFbU9rMytOei9uOFJ6OHpiSVNWVGxvL2RoZXlYbW16WGVL?= =?utf-8?B?S2RrancwZmwvU0hadlFDZTBIQWZTY1lmdkJSUmNzTXVVeFRjUzZJQ0d1TGJI?= =?utf-8?B?cWFHSUxTNnZOdnM3U1Y2MXRMRlRHNXVjbDNVdDR6YzkwWFM2Y3hBbnVrcXR1?= =?utf-8?B?TGF2dVowMEUrSytvTVZIYVRBSzhjN3duTy9FenAzcGRKejJrWWdnalZGN2xi?= =?utf-8?B?ZFFRdklrUHhGSjYwN2tmd0xVNjhRMGFlcjNyWk9pQ1JPeVRXTGxVWlZEVFJs?= =?utf-8?B?Vm02VTZnMUs2QzltY044L0preExHcVZEN1Q5cTV4cDkzZXByNVlXcEs2Vnox?= =?utf-8?B?VGVIQVlLdkxQbVpNL0hxOTBwQkRMMUl5VURoZkpIdW9nbGRhYkpMdjNpSTZB?= =?utf-8?B?SEZLenlkK1hoemIrWnpDYmNEMHJrK3MvdU9ob0YvZmljUnJJdzhxSDRSZmlo?= =?utf-8?B?UWtCMFZ2ZFV5U3dsUHlYbWdGbE4vcnBveC9SZkRQbnprZ05UQU1rc2c5WVNK?= =?utf-8?B?TTR4SnRWOWd0M3NudjV1b0FXL3pkVW1iUmFsTmlRK05mZ3VuQmVlSjkyRHhO?= =?utf-8?B?eHpoYk15OWFrd1lVL3RveTZwVlhUOElxdzhvS0ljS2puZWFObGoxUHJ4dGZt?= =?utf-8?B?SnhobEY4Rm8rMW1UaUhjTTZNeXN5YlhlRVQzUjVEYXdGVXpwb2ZuSkFNUEM5?= =?utf-8?B?ZEM3enNySGRJMzkyb2daeDZXZ0UwK1BWcUxOalN3SkRKSDJEVjRNdzdOZGhN?= =?utf-8?B?eE1PcmtLYUZiSmxVeW54a0pyOGxEck1oYkpBYko4VEFaSGY2SzlmVzJQaEVr?= =?utf-8?B?SHc1T1FIL3VsU0VqS2FFOXgwSXZQWW1JSWYrZ2grREx6RHdURE5rR0YxNi9K?= =?utf-8?B?US9nbHNncTFFbUtYYlJCSkQ1RDlmdVpPRHRRSTBxS2NwekVoYkc4YU9yb285?= =?utf-8?B?UDZmVy9Ka1VCUEhJalVvb0FDNVZOUEg1YkZRNDh6VDB3RFVOY3FhenB3RWJm?= =?utf-8?B?OUpxVXRkTUUwZSs2S3J6ZzRJb1FaTDd3QmRDREZId2tQOE1GY0hwVi9BM3ln?= =?utf-8?B?d0JTLzVXa1hia0hNMjlnOTd1anlzd1BWN0NIRnI3WEY4aWdTUDBYL1ZlL2FS?= =?utf-8?B?dzJMVElNK2RZeXNyQytadEZOelBJSk12MXVwV1UyajBpZUN1TVZ6L29qTllW?= =?utf-8?Q?SGe4ARHRzlSXF04Og1CYSW5/k?= X-OriginatorOrg: silabs.com X-MS-Exchange-CrossTenant-Network-Message-Id: 8cf5b5b7-975f-4d36-2d2b-08de3999653c X-MS-Exchange-CrossTenant-AuthSource: DS0PR11MB8205.namprd11.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 12 Dec 2025 16:13:32.6240 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 54dbd822-5231-4b20-944d-6f4abcd541fb X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: hLyXaqp4rIFn9LzPskw4OIwkenClxtwg3NMeeLN6F9O66eG/BCua4j0Iheru+pBBHvYcLJ9nuAP50Q9kP5rAOA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: MN0PR11MB6111 X-Proofpoint-ORIG-GUID: 1D3df6QMKB667YfJDE_rIm6kdoelGoix X-Authority-Analysis: v=2.4 cv=brxBxUai c=1 sm=1 tr=0 ts=693c3f2e cx=c_pps a=xX5bFixAAzgdQQ8ihQiE1w==:117 a=6eWqkTHjU83fiwn7nKZWdM+Sl24=:19 a=z/mQ4Ysz8XfWz/Q5cLBRGdckG28=:19 a=lCpzRmAYbLLaTzLvsPZ7Mbvzbb8=:19 a=xqWC_Br6kY4A:10 a=IkcTkHD0fZMA:10 a=wP3pNCr1ah4A:10 a=M51BFTxLslgA:10 a=i1IsUcr2s-wA:10 a=VkNPw1HP01LnGYTKEx00:22 a=2AEO0YjSAAAA:8 a=ijG-J2Scc44MUVjsrbIA:9 a=3ZKOabzyN94A:10 a=QEXdDO2ut3YA:10 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjUxMjEyMDEyOCBTYWx0ZWRfX/fcukzEsC93A FOUo1HHfc3dUV/ZnALunnjgKmGJrin5zJnkB0P6FcFZpUQAcnq8qK1AFmlqp5f/ZPaL6814yvoj tF6qB+jTPTsKlVcuRU3R0OxaS2DADegWxG5JRX3sHDpMIVLf7PXxki54yFMAtrLdi95VIyQhLDp DNfsHX9IYwIvu07ZsYSfO2k7hMkDSwRULB0DBga0+KKyh+LTI//awEJin7nXYzgoW+lv3vaqmQj 0f6SQ+hol2Cbd6HhJf+wvX1ypxLziByfCx/hbNElJAG9bgyIHZDlFN1yEQ87XLySkdhETrwQgmz 3EQz+xrtUmNuz7msOJg/vX2+K3Z9PHtuJCZsc4v7fYeyy5/E8aWxhDybPuB7uVYZyTxul6W2RVz 3haxP0npdY004BMH0pTzI4k+ixVOGw== X-Proofpoint-GUID: 1D3df6QMKB667YfJDE_rIm6kdoelGoix X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1121,Hydra:6.1.9,FMLib:17.12.100.49 definitions=2025-12-12_04,2025-12-11_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 suspectscore=0 lowpriorityscore=0 priorityscore=1501 malwarescore=0 adultscore=0 phishscore=0 spamscore=0 bulkscore=0 clxscore=1015 impostorscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2510240001 definitions=main-2512120128 From: Gabriel Beaulieu This introduces a new module gb-cpc-sdio, in order to communicate with a Greybus CPC device over SDIO. Most of the complexity stems from aggregation: packets are aggregated to minimize the number of CMD53s. In the first block, the first le32 is the number of packets in this transfer. Immediately after that are all the packet headers (CPC + Greybus). This lets the device process all the headers in a single interrupt, and prepare the ADMA descriptors for all the payloads in one go. Payloads start at the beginning of the second block and are concatained. Their lengths must be 32-bit aligned, so the driver takes care of adding and removing padding if necessary. Signed-off-by: Gabriel Beaulieu Signed-off-by: Damien Ri=C3=A9gel --- drivers/greybus/cpc/Kconfig | 12 + drivers/greybus/cpc/Makefile | 3 + drivers/greybus/cpc/sdio.c | 554 +++++++++++++++++++++++++++++++++++ 3 files changed, 569 insertions(+) create mode 100644 drivers/greybus/cpc/sdio.c diff --git a/drivers/greybus/cpc/Kconfig b/drivers/greybus/cpc/Kconfig index ab96fedd0de..8223f56795f 100644 --- a/drivers/greybus/cpc/Kconfig +++ b/drivers/greybus/cpc/Kconfig @@ -8,3 +8,15 @@ config GREYBUS_CPC =20 To compile this code as a module, chose M here: the module will be called gb-cpc.ko + +config GREYBUS_CPC_SDIO + tristate "Greybus CPC over SDIO" + depends on GREYBUS_CPC && MMC + help + This driver provides Greybus CPC host support for devices + connected via SDIO interface. + + To compile this driver as a module, choose M here: the module + will be called gb-cpc-sdio. + + If unsure, say N. diff --git a/drivers/greybus/cpc/Makefile b/drivers/greybus/cpc/Makefile index c4b530d27a3..3296536e86d 100644 --- a/drivers/greybus/cpc/Makefile +++ b/drivers/greybus/cpc/Makefile @@ -4,3 +4,6 @@ gb-cpc-y :=3D cport.o header.o host.o protocol.o =20 # CPC core obj-$(CONFIG_GREYBUS_CPC) +=3D gb-cpc.o + +gb-cpc-sdio-y :=3D sdio.o +obj-$(CONFIG_GREYBUS_CPC_SDIO) +=3D gb-cpc-sdio.o diff --git a/drivers/greybus/cpc/sdio.c b/drivers/greybus/cpc/sdio.c new file mode 100644 index 00000000000..5c467b83ad9 --- /dev/null +++ b/drivers/greybus/cpc/sdio.c @@ -0,0 +1,554 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2025, Silicon Laboratories, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cpc.h" +#include "header.h" +#include "host.h" + +#define GB_CPC_SDIO_MSG_SIZE_MAX 4096 +#define GB_CPC_SDIO_BLOCK_SIZE 256U +#define GB_CPC_SDIO_FIFO_ADDR 0 +#define GB_CPC_SDIO_ALIGNMENT 4 +#define GB_CPC_SDIO_DEFAULT_AGGREGATION 1 +#define CPC_FRAME_HEADER_SIZE (CPC_HEADER_SIZE + GREYBUS_HEADER_SIZE) +#define GB_CPC_SDIO_MAX_AGGREGATION ((GB_CPC_SDIO_BLOCK_SIZE - sizeof(u32)= ) / CPC_FRAME_HEADER_SIZE) + +enum cpc_sdio_flags { + CPC_SDIO_FLAG_IRQ_RUNNING, + CPC_SDIO_FLAG_TX_WORK_DELAYED, + CPC_SDIO_FLAG_SHUTDOWN, +}; + +struct cpc_sdio { + struct cpc_host_device *cpc_hd; + struct device *dev; + struct sdio_func *func; + + struct work_struct tx_work; + unsigned long flags; + + wait_queue_head_t event_queue; + u8 max_aggregation; +}; + +struct frame_header { + struct cpc_header cpc; + struct gb_operation_msg_hdr gb; +} __packed; + +static inline struct cpc_sdio *cpc_hd_to_cpc_sdio(struct cpc_host_device *= cpc_hd) +{ + return (struct cpc_sdio *)cpc_hd->priv; +} + +static int gb_cpc_sdio_wake_tx(struct cpc_host_device *cpc_hd) +{ + struct cpc_sdio *ctx =3D cpc_hd_to_cpc_sdio(cpc_hd); + + if (test_bit(CPC_SDIO_FLAG_SHUTDOWN, &ctx->flags)) + return 0; + + /* Use system workqueue for TX processing */ + schedule_work(&ctx->tx_work); + + return 0; +} + +/** + * Return the memory requirement in bytes for the aggregated frame aligned= to the block size + */ +static size_t cpc_sdio_get_aligned_size(struct cpc_sdio *ctx, struct sk_bu= ff_head *frame_list) +{ + size_t size =3D 0; + struct sk_buff *frame; + + /* Calculate total payload size */ + skb_queue_walk(frame_list, frame) { + size_t payload_len =3D frame->len - CPC_FRAME_HEADER_SIZE; + + /* payload is aligned and padded to 4 bytes */ + size +=3D ALIGN(payload_len, GB_CPC_SDIO_ALIGNMENT); + } + + /* Make sure the total payload size is a round number of blocks */ + size =3D ALIGN(size, GB_CPC_SDIO_BLOCK_SIZE); + + /* Add an additional block for headers */ + size +=3D GB_CPC_SDIO_BLOCK_SIZE; + + return size; +} + +static unsigned char *cpc_sdio_build_aggregated_frame(struct cpc_sdio *ctx, + struct sk_buff_head *frame_list, + size_t *xfer_len) +{ + unsigned char *tx_buff; + struct sk_buff *frame; + __le32 *frame_count; + size_t xfer_size; + unsigned int i =3D 0; + + xfer_size =3D cpc_sdio_get_aligned_size(ctx, frame_list); + + /* Allocate aggregated frame */ + tx_buff =3D kmalloc(xfer_size, GFP_KERNEL); + if (!tx_buff) + return NULL; + + frame_count =3D (__le32 *)tx_buff; + *frame_count =3D cpu_to_le32(skb_queue_len(frame_list)); + i +=3D 4; + + /* Copy frame headers to aggregate buffer */ + skb_queue_walk(frame_list, frame) { + memcpy(&tx_buff[i], frame->data, CPC_FRAME_HEADER_SIZE); + i +=3D CPC_FRAME_HEADER_SIZE; + } + + /* Zero-pad remainder of header block to fill complete SDIO block */ + if (i < GB_CPC_SDIO_BLOCK_SIZE) + memset(&tx_buff[i], 0, GB_CPC_SDIO_BLOCK_SIZE - i); + + /* Start injecting payload at beginning of second block */ + i =3D GB_CPC_SDIO_BLOCK_SIZE; + + /* Build payload blocks if required */ + if (xfer_size > GB_CPC_SDIO_BLOCK_SIZE) { + skb_queue_walk(frame_list, frame) { + size_t payload_len, padding_len; + + if (frame->len <=3D CPC_FRAME_HEADER_SIZE) + continue; + + payload_len =3D frame->len - CPC_FRAME_HEADER_SIZE; + memcpy(&tx_buff[i], &frame->data[CPC_FRAME_HEADER_SIZE], payload_len); + i +=3D payload_len; + + padding_len =3D ALIGN(payload_len, GB_CPC_SDIO_ALIGNMENT) - payload_len; + if (padding_len) { + memset(&tx_buff[i], 0, padding_len); + i +=3D padding_len; + } + } + } + + *xfer_len =3D xfer_size; + + return tx_buff; +} + +static bool cpc_sdio_get_payload_size(struct cpc_sdio *ctx, const struct f= rame_header *header, + size_t *payload_size) +{ + size_t gb_size; + + gb_size =3D le16_to_cpu(header->gb.size); + + /* Validate that the size is at least as large as the Greybus header */ + if (gb_size < GREYBUS_HEADER_SIZE) { + dev_dbg(ctx->dev, "Invalid Greybus header size: %lu\n", gb_size); + return false; + } + + /* Validate maximum size */ + if (gb_size > (GB_CPC_SDIO_MSG_SIZE_MAX + GREYBUS_HEADER_SIZE)) { + dev_dbg(ctx->dev, "Payload size exceeds maximum: %lu\n", gb_size); + return false; + } + + /* Size includes the Greybus header, so subtract it to get payload size */ + *payload_size =3D gb_size - GREYBUS_HEADER_SIZE; + + return true; +} + +/** + * Process aggregated frame + * Reconstructed frame layout: + * +-----+-----+-----+------+------+------+------+-------+---------+ + * | CPC Header (4B) | Size | OpID | Type | Stat | CPort | Payload | + * +-----+-----+-----+------+------+------+------+-------+---------+ + */ +static int cpc_sdio_process_aggregated_frame(struct cpc_sdio *ctx, unsigne= d char *aggregated_frame, + unsigned int frame_len) +{ + const struct frame_header *header; + size_t aligned_payload_size; + struct sk_buff *rx_skb; + const unsigned char *payload_start; + size_t payload_size; + size_t frame_size; + u32 frame_count; + unsigned int payload_offset; + + /* Get frame count from aggregated frame (4-byte u32) */ + frame_count =3D le32_to_cpu(*((__le32 *)aggregated_frame)); + if (frame_count =3D=3D 0) { + dev_dbg(ctx->dev, "Process aggregated frame: invalid frame count: %u\n", + frame_count); + return -EINVAL; + } + + /* Ensure frame count doesn't exceed our negotiated maximum */ + if (frame_count > ctx->max_aggregation) { + dev_warn(ctx->dev, + "Process aggregated frame: frame count %u exceeds negotiated maximum %= u\n", + frame_count, ctx->max_aggregation); + //frame_count =3D ctx->effective_max_aggregation; + } + + /* Header starts at block 0 after frame count */ + header =3D (struct frame_header *)&aggregated_frame[sizeof(__le32)]; + + /* Payloads start at block 1 (after complete block 0) */ + payload_offset =3D GB_CPC_SDIO_BLOCK_SIZE; + + for (unsigned int i =3D 0; i < frame_count; i++) { + payload_start =3D &aggregated_frame[payload_offset]; + + /* Get payload size for this frame */ + if (!cpc_sdio_get_payload_size(ctx, header, &payload_size)) { + dev_err(ctx->dev, + "Process aggregated frame: failed to get payload size, aborting.\n"); + return -ERANGE; + } + + aligned_payload_size =3D ALIGN(payload_size, GB_CPC_SDIO_ALIGNMENT); + + /* Validate the payload is within the buffer boundary */ + if (payload_offset + aligned_payload_size > frame_len) { + dev_err(ctx->dev, + "Process aggregated frame: payload is out of buffer boundary, aborting= at frame %u\n", + i); + return -ENOSPC; + } + + /* Calculate total frame size: CPC header + Greybus header + payload */ + frame_size =3D CPC_FRAME_HEADER_SIZE + payload_size; + + /* Allocate sk_buff for reconstructed frame */ + rx_skb =3D alloc_skb(frame_size, GFP_KERNEL); + if (rx_skb) { + /* Copy header */ + memcpy(skb_put(rx_skb, CPC_FRAME_HEADER_SIZE), header, + CPC_FRAME_HEADER_SIZE); + + /* Copy payload */ + if (payload_size > 0) + memcpy(skb_put(rx_skb, payload_size), payload_start, payload_size); + + /* Send reconstructed frame to CPC core */ + cpc_hd_rcvd(ctx->cpc_hd, rx_skb); + } + /* else: allocation failed, skip this frame but continue processing */ + + /* Move to next header and payload start address */ + header++; + payload_offset +=3D aligned_payload_size; + } + + return 0; +} + +static u32 cpc_sdio_get_rx_num_bytes(struct sdio_func *func, int *err) +{ + unsigned int rx_num_block_addr =3D 0x0C; + + return sdio_readl(func, rx_num_block_addr, err); +} + +static void gb_cpc_sdio_rx(struct cpc_sdio *ctx) +{ + unsigned char *rx_buff; + size_t data_len; + int err; + + sdio_claim_host(ctx->func); + data_len =3D cpc_sdio_get_rx_num_bytes(ctx->func, &err); + + if (err) { + dev_err(ctx->dev, "failed to obtain byte count (%d)\n", err); + goto release_host; + } + + /* Validate minimum RX data length */ + if (data_len < sizeof(u32) + CPC_FRAME_HEADER_SIZE) { + dev_err(ctx->dev, "failed to obtain enough bytes for a header (%zu)\n", = data_len); + goto release_host; + } + + /* Allocate sk_buff for RX data */ + rx_buff =3D kmalloc(data_len, GFP_KERNEL); + if (!rx_buff) + goto release_host; + + err =3D sdio_readsb(ctx->func, rx_buff, GB_CPC_SDIO_FIFO_ADDR, data_len); + sdio_release_host(ctx->func); + + if (err) { + dev_err(ctx->dev, "failed to sdio_readsb (%d)\n", err); + goto free_rx_skb; + } + + if (data_len < GB_CPC_SDIO_BLOCK_SIZE) { + dev_err(ctx->dev, "received %zd bytes, expected at least %u bytes\n", da= ta_len, + GB_CPC_SDIO_BLOCK_SIZE); + goto free_rx_skb; + } + + /* de-aggregate incoming skb into individual frames and send to CPC core = */ + cpc_sdio_process_aggregated_frame(ctx, rx_buff, data_len); + +free_rx_skb: + kfree(rx_buff); + + return; + +release_host: + sdio_release_host(ctx->func); +} + +static void gb_cpc_sdio_tx(struct cpc_sdio *ctx) +{ + struct sk_buff_head frame_list; + unsigned char *tx_buff; + size_t tx_len; + int err; + + skb_queue_head_init(&frame_list); + + /* Dequeue the negotiated maximum aggregated frames from the host device = */ + cpc_hd_dequeue_many(ctx->cpc_hd, &frame_list, ctx->max_aggregation); + + /* Check if any frames were dequeued */ + if (skb_queue_empty(&frame_list)) + return; + + tx_buff =3D cpc_sdio_build_aggregated_frame(ctx, &frame_list, &tx_len); + if (!tx_buff) { + dev_err(ctx->dev, "failed to build aggregated frame\n"); + goto cleanup_frames; + } + + sdio_claim_host(ctx->func); + err =3D sdio_writesb(ctx->func, GB_CPC_SDIO_FIFO_ADDR, tx_buff, tx_len); + sdio_release_host(ctx->func); + + if (err) + dev_err(ctx->dev, "failed to sdio_writesb (%d)\n", err); + + kfree(tx_buff); + +cleanup_frames: + /* Clean up any remaining frames in the list */ + skb_queue_purge(&frame_list); +} + +static void gb_cpc_sdio_rx_tx(struct cpc_sdio *ctx) +{ + gb_cpc_sdio_rx(ctx); + + set_bit(CPC_SDIO_FLAG_IRQ_RUNNING, &ctx->flags); + gb_cpc_sdio_tx(ctx); + clear_bit(CPC_SDIO_FLAG_IRQ_RUNNING, &ctx->flags); +} + +static void gb_cpc_sdio_tx_work(struct work_struct *work) +{ + struct cpc_sdio *ctx =3D container_of(work, struct cpc_sdio, tx_work); + + /* Do not execute concurrently to the interrupt */ + if (test_bit(CPC_SDIO_FLAG_IRQ_RUNNING, &ctx->flags)) { + set_bit(CPC_SDIO_FLAG_TX_WORK_DELAYED, &ctx->flags); + return; + } + + gb_cpc_sdio_tx(ctx); +} + +static struct cpc_hd_driver cpc_sdio_driver =3D { + .wake_tx =3D gb_cpc_sdio_wake_tx, +}; + +static int cpc_sdio_init(struct sdio_func *func) +{ + unsigned char rx_data_ready_irq_en_bit =3D BIT(0); + unsigned int irq_enable_addr =3D 0x09; + int err; + + /* Enable the read data ready interrupt. */ + sdio_writeb(func, rx_data_ready_irq_en_bit, irq_enable_addr, &err); + if (err) + dev_err(&func->dev, "failed to set data ready interrupt (%d)\n", err); + + return err; +} + +static void cpc_sdio_irq_handler(struct sdio_func *func) +{ + struct cpc_sdio *ctx =3D sdio_get_drvdata(func); + struct device *dev =3D &func->dev; + unsigned int rx_data_pending_irq_bit =3D 0; + unsigned int irq_status_addr =3D 0x08; + unsigned long int_status; + int err; + + int_status =3D sdio_readb(func, irq_status_addr, &err); + if (err) { + dev_err(dev, "failed to read interrupt status registers (%d)\n", err); + return; + } + + if (__test_and_clear_bit(rx_data_pending_irq_bit, &int_status)) { + /* Clear the IRQ on the device side. */ + sdio_writeb(func, BIT(rx_data_pending_irq_bit), irq_status_addr, &err); + if (err) { + dev_err(dev, "failed to clear read interrupt (%d), interrupt will repea= t\n", + err); + return; + } + + cancel_work_sync(&ctx->tx_work); + gb_cpc_sdio_rx_tx(ctx); + + if (test_and_clear_bit(CPC_SDIO_FLAG_TX_WORK_DELAYED, &ctx->flags)) + schedule_work(&ctx->tx_work); + } + + if (int_status) + dev_err_once(dev, "unhandled interrupt from the device (%ld)\n", int_sta= tus); +} + +static int cpc_sdio_probe(struct sdio_func *func, const struct sdio_device= _id *id) +{ + struct cpc_host_device *cpc_hd; + struct cpc_sdio *ctx; + int err; + + /* Allocate our private context */ + ctx =3D kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + /* Create CPC host device with our context as private data */ + cpc_hd =3D cpc_hd_create(&cpc_sdio_driver, &func->dev, ctx); + if (IS_ERR(cpc_hd)) { + kfree(ctx); + return PTR_ERR(cpc_hd); + } + + /* Initialize context */ + ctx->cpc_hd =3D cpc_hd; + ctx->dev =3D cpc_hd_dev(cpc_hd); + ctx->func =3D func; + ctx->max_aggregation =3D GB_CPC_SDIO_DEFAULT_AGGREGATION; + + INIT_WORK(&ctx->tx_work, gb_cpc_sdio_tx_work); + + /* Make ctx available to IRQ handler before enabling/claiming IRQ */ + sdio_set_drvdata(func, ctx); + + sdio_claim_host(func); + + err =3D sdio_enable_func(func); + if (err) + goto release_host; + + err =3D sdio_set_block_size(func, GB_CPC_SDIO_BLOCK_SIZE); + if (err) + goto disable_func; + + err =3D cpc_sdio_init(func); + if (err) + goto disable_func; + + err =3D sdio_claim_irq(func, cpc_sdio_irq_handler); + if (err) + goto disable_func; + + err =3D cpc_hd_add(cpc_hd); + if (err) + goto release_irq; + + sdio_release_host(func); + + return 0; + +release_irq: + sdio_release_irq(func); + +disable_func: + sdio_disable_func(func); + +release_host: + sdio_release_host(func); + cpc_hd_put(cpc_hd); + kfree(ctx); + + return err; +} + +static void cpc_sdio_remove(struct sdio_func *func) +{ + struct cpc_sdio *ctx =3D sdio_get_drvdata(func); + struct cpc_host_device *cpc_hd =3D ctx->cpc_hd; + + /* Prevent new TX wakeups and wake the thread */ + set_bit(CPC_SDIO_FLAG_SHUTDOWN, &ctx->flags); + + /* Cancel and flush any pending TX work */ + cancel_work_sync(&ctx->tx_work); + + sdio_claim_host(func); + sdio_release_irq(func); + sdio_disable_func(func); + sdio_release_host(func); + + cpc_hd_del(cpc_hd); + cpc_hd_put(cpc_hd); + + kfree(ctx); +} + +/* NOTE: Development/RFC purposes only. */ +static const struct sdio_device_id sdio_ids[] =3D { + { + SDIO_DEVICE(0x0296, 0x5347), + }, + {}, +}; +MODULE_DEVICE_TABLE(sdio, sdio_ids); + +static struct sdio_driver gb_cpc_sdio_driver =3D { + .name =3D KBUILD_MODNAME, + .id_table =3D sdio_ids, + .probe =3D cpc_sdio_probe, + .remove =3D cpc_sdio_remove, + .drv =3D { + .owner =3D THIS_MODULE, + .name =3D KBUILD_MODNAME, + }, +}; + +module_sdio_driver(gb_cpc_sdio_driver); + +MODULE_DESCRIPTION("Greybus Host Driver for Silicon Labs devices using SDI= O"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Damien Ri=C3=A9gel "); --=20 2.49.0