From nobody Sat Feb 7 09:46:50 2026 Received: from SJ2PR03CU001.outbound.protection.outlook.com (mail-westusazon11022125.outbound.protection.outlook.com [52.101.43.125]) (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 C41FC36683C; Mon, 2 Feb 2026 13:16:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.43.125 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770038218; cv=fail; b=mBxzqUGnCd8lgNRN9bUKC4J6chkPk0+N2TKlpTBDN0sdTU/rbf7iUu0TGODzgZWN6kcQrwITnwTxqv49djdHRZEYc3Y7DZdeYbiEZqgyBDxqos8UKn6fK+7jpRgQgW2TAQ54yxiwrtjWKAQ7/DBu4MOKpTVdrJHfn5IYRYSYOpY= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770038218; c=relaxed/simple; bh=i/vX6FTbEKgepWdxm4LiHJfG0DkQt3iPnVLC3/cNqPw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=UxbHmdkik7k70DDRbd7hVkUnTDS1YBRbmB7cVtZR4lSQfnSOqzoaPUhYfuLT4ebtBdd1uVla31g00KqHiq6FmpvR1nhifIkPcYoRh2CgNxY0uColSP2v/Hsio1OlssRe6Yy8ANIGzQu5iukPCP8HIbZd6ZDQczol6rty0Nc9M6M= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=axiado.com; spf=pass smtp.mailfrom=axiado.com; dkim=pass (2048-bit key) header.d=axiado.com header.i=@axiado.com header.b=rXMfshOX; arc=fail smtp.client-ip=52.101.43.125 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=axiado.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=axiado.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=axiado.com header.i=@axiado.com header.b="rXMfshOX" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=aWVbQG2CZVQ9gBcjRmXLmfn4G36CBiFanlq8jWScgjPglKj4A2h5n2yDnq2JOSVyfpLM5RmKpdDuy0jV98i3cbnOi8ImAu+ZfQZnyl16JNRUwqv5fieASyfLgxiIj7vnUwJHmPASAoI+xKY0sB1n4+6cDSXWK1wXXdnpPCZ4hiaaQFWduIR+QNZ49w4Lo+toVymndsHjmVAuIhBq0sZAK6wG3L85fpFNoXz59fqrOA+Mm+KcQRXQrV6hqYPFP74TbaBhIVpJD00xsdtmDayX8b92JnEU7Fb7dr+hiFZj1n74GiqxUCNIv4dsncMxFELB9opk4Opp1f7j5MNeS9mKBg== 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=doqVh+Zf3G+zZHM8G6ncXFd6FUzWtFUN22Z6fC3EDOU=; b=Y+TkswEvrvEnMoJrezcQNMcktC6SlhyfNzZtk3E8ww3zAyZ5V4o4p4EJc2IyOp3eQCcZVq95aiRxW3Z0HVF52M7ZCdR+7KzzsKB4wSeo/VQDUu/mbDJRoT46mlN46c/+S6zQEA8+xcLDJnNcgpOhd/gW5czSh90nVEPuRJMZzGUIZfZMlu+5va941aR0WxF7IMJal1d44r7q+aTVPyiym9ujtrrH7nAbnir0X2dwQs3nI5FgtFFhsmclVYcYudMkrrUUlWKpX0A/k55vhlnaxAkcL75rXn+aNFBZr7i+Ix3JTyttpgN7KA8TGr5FRHi3cbo6rsCHFYnejUqgBjU/Sw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=fail (sender ip is 4.227.125.105) smtp.rcpttodomain=vger.kernel.org smtp.mailfrom=axiado.com; dmarc=none action=none header.from=axiado.com; dkim=none (message not signed); arc=none (0) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=axiado.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=doqVh+Zf3G+zZHM8G6ncXFd6FUzWtFUN22Z6fC3EDOU=; b=rXMfshOXHyI641a+pJhijMLr4l3d3Mo2BpUH+iHCMOrFwayr9CzvBGJbr/mk06grwLmyNmQmHR++8WbLt0ymvZJ+qI6pmJqZd95XHRSSx0IsS7pRPdhkOycDr0D04nXjauVM38gMRGP+apYBlM3NRINHuRfl2rdsNnwO7/3NK9YMh+khbQfu+2E1cNynGMlLgQ4HcvKXzrUuOb9vQRW2xw+Mp2ma1rfjaamt67OZKsRL7/haoHeRaZfaTy/SvxFg36pDTLQHtwTHgpfVe7OH9RqMgQgAG9ZkhOOqrQuP0Y92O/LJsn+orJCD0PXWNBbvNVWJMliBuXSBP0rIYBff+A== Received: from SJ0PR13CA0215.namprd13.prod.outlook.com (2603:10b6:a03:2c1::10) by CO6PR18MB3857.namprd18.prod.outlook.com (2603:10b6:5:347::13) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9587.12; Mon, 2 Feb 2026 13:16:53 +0000 Received: from SJ5PEPF00000203.namprd05.prod.outlook.com (2603:10b6:a03:2c1:cafe::da) by SJ0PR13CA0215.outlook.office365.com (2603:10b6:a03:2c1::10) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.9587.12 via Frontend Transport; Mon, 2 Feb 2026 13:16:24 +0000 X-MS-Exchange-Authentication-Results: spf=fail (sender IP is 4.227.125.105) smtp.mailfrom=axiado.com; dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=axiado.com; Received-SPF: Fail (protection.outlook.com: domain of axiado.com does not designate 4.227.125.105 as permitted sender) receiver=protection.outlook.com; client-ip=4.227.125.105; helo=[127.0.0.1]; Received: from [127.0.0.1] (4.227.125.105) by SJ5PEPF00000203.mail.protection.outlook.com (10.167.244.36) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.9587.10 via Frontend Transport; Mon, 2 Feb 2026 13:16:52 +0000 From: Vladimir Moravcevic Date: Mon, 02 Feb 2026 05:16:28 -0800 Subject: [PATCH 1/3] dt-bindings: usb: axiado,ax3000-udc: Add Axiado UDC Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260202-axiado-ax3000-usb-device-controller-v1-1-45ce0a8b014f@axiado.com> References: <20260202-axiado-ax3000-usb-device-controller-v1-0-45ce0a8b014f@axiado.com> In-Reply-To: <20260202-axiado-ax3000-usb-device-controller-v1-0-45ce0a8b014f@axiado.com> To: Krutik Shah , Prasad Bolisetty , Greg Kroah-Hartman , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: linux-usb@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, openbmc@lists.ozlabs.org, Vladimir Moravcevic X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1770038210; l=2667; i=vmoravcevic@axiado.com; s=20250904; h=from:subject:message-id; bh=i/vX6FTbEKgepWdxm4LiHJfG0DkQt3iPnVLC3/cNqPw=; b=vF6FfSX8env/lDCGtxNyJBdffahWNmX/u4UX771IYEqokiEsgnDqNOFBZrHg4rLda3nC84lp9 z0Aray+mk5lDl38dRTk62U49oHrC6sxuRg6LGnxIUPMWPxaUyGI98RV X-Developer-Key: i=vmoravcevic@axiado.com; a=ed25519; pk=iiyhWhM1F4HlCbbW3I3qKZhPCE8JsCrDQMgCBRg4YMA= X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: SJ5PEPF00000203:EE_|CO6PR18MB3857:EE_ X-MS-Office365-Filtering-Correlation-Id: d2bf995c-436f-4632-f69b-08de625d54f5 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|376014|36860700013|1800799024|82310400026; X-Microsoft-Antispam-Message-Info: =?utf-8?B?blRlOEJON2l3Y0VxcHN5alNWdFRiSUpPaDhmV0ZrM2ZhSTRJcjVQMVJFd0ZN?= =?utf-8?B?UmNIL1NBMkNKSFA0VDZoMlFJMGZNOHhRZDlDcWE5V3FvWjJZVWg5ZXpJZGJV?= =?utf-8?B?SWdwMGhGRkhmdjQyemZqUWdjRWI3L3k0RXhqcUFoM29aU1FCRm1WaEs2b1JJ?= =?utf-8?B?OXBheXFwY09rRk9yVTZaMjdLUHVVblhMdWJidHU5TDZ4VHE5M0FKMW9OTFgy?= =?utf-8?B?Y1UyeHBxdjlwREtuMVNkbFN1aTM4M1NOaDlsYW1PQTc0RkRxSjM0cHNYaFVJ?= =?utf-8?B?MDZGOHZCdTNuRElwQ0ZGdWFjdTVKM0JCVTNDcWc4ME5ZYjJabXcyODdVR012?= =?utf-8?B?ZU5NN0xZTGt4TjdvdmxtdHhISDBxZjlYL3BoeHd2U3hDaWI1ZXk5YVVJRDNQ?= =?utf-8?B?ODA3VThsVENUbEVGWHNwcllzUkVhK3pLU05YTmNxdWxCZEo3M1pxRzVZQlM1?= =?utf-8?B?WCtyS1RHYnhpa0trMXpHMXpHaytJMlF1UFhIRXpCNURWV3JZeDE3b3AxT3p3?= =?utf-8?B?RTFPakFxcTg3TlNjd1NtODBHQnRQSUtVaTE2OVdML1I1YXhKM2ZoeTJCN0lu?= =?utf-8?B?Mi8vdlZnWFo4OU1ZbFNESWpnaTNZRTA3YzkzUG5ORHp6SXpINnRpeE9SNG1X?= =?utf-8?B?UVFScGhOS2RBUnBJMGx2cnIrL3NKUGpQanRTaDFBNC9EMTM5QjBEK2NOdEN0?= =?utf-8?B?NWM1cWZwU3JZd2hrczd4WGthYzZKeUFrM211cnNhaEExRDNPaXQxYVoyTHBt?= =?utf-8?B?Zzl4ZlpoeW1nQ2N4U1o0QTlmbFgzbVJyLzVNQXU1cDIwTHlJU3prRkE0S0hR?= =?utf-8?B?WlRyc1FsYWpsNEwxNCtCNjk1SWZkbkJHKzdnN3ZxU2xhcVhFbXcxdDErZFFY?= =?utf-8?B?eHdWTC80MDBuSHpqMDR6V3B3TUdOWDJFNEJzQWRaREZhcDBpRlJFaDJGdXo1?= =?utf-8?B?RXRXSWp2M0NSSjRyRkc4MFpLYjB0NFJ4QktIZFZsd1V6WnJTYmNBQmMrUEgw?= =?utf-8?B?bDJ3VTExOHphOHF1ZG51dGlvWW5KVDdwUXRwem1hbWE4MDZEZEt1YndBTEZ4?= =?utf-8?B?RGFRaklXc2tnaEpTN1lwZ3RkS3plclNxTGExdURsSWtFMzBPaEFSRUU5Nnhh?= =?utf-8?B?ZGQ3eFdBUTVUZCtOSWtaSHBXTmxrbERsNVJGQTQwNGZQaVdwOG1oaHlqdW5S?= =?utf-8?B?S2dCTHNoWWdJZ0FrVStxa1IrRngrQkp0UXYxSnF2TjdGc0d2TzVGVGJ4Rzlo?= =?utf-8?B?VEZ0OE9wa2EySXRpQjdGdWJvcFZxWFNySFZ2MXk0d094S2R6N20zTStvMzJz?= =?utf-8?B?NUE3UjV1TE8zQlVSS21yNkRQWEJobldiT3JxNkFUV1lWQWtJVkpBNXkxelVL?= =?utf-8?B?cHhMK1J0dGZVSHova0tFUFRvVGhlSXIvZzhaSXFOejhWd3pxbGZnQTRCWUZT?= =?utf-8?B?MzREWmNUUEtYMkIyalRyNlZyaGJzNzdUcmk0ZEFTeXB1VDlTcWFRN0NuekRW?= =?utf-8?B?NytUaC8rQlU3UmxaYmtUQWlwRVJ6eExaK2h0MDI1MWZTKzhtVlBHVFpMM3dL?= =?utf-8?B?TFFMNDgwSExQdC8yQ0Y4OTlhaVB0cVRsbWl2bHlTNVMzMkkvWlZZeXVicy9P?= =?utf-8?B?dEN2bWZWdGRBR0N0UGZicmhzbHhnb1ZPODlaT01VTlhZRlliSGRHbHF5SnVH?= =?utf-8?B?WXU1WDBJSENEaDkzd1ZPdzk1ZGp1eTVQS0U4bWxtNVVETi93ZmhpWHBXcUxX?= =?utf-8?B?dkwyK0FYRWxxYlpPTk1rdmVCZHpXQ1c4SVp1TmNZVFZJWFdoM2ZEVitwaWh1?= =?utf-8?B?aXVIeUxsV25UOHAvanIxWStHMHo4eVdQb1hyLy9pc0FSejhxVWlXMTVaUlIy?= =?utf-8?B?Q2I0cTFSMDk5anBZNkY2dVI2QjVvaW1ZeVFrbGE1U2dVa3pFanlWcDQ5OWN4?= =?utf-8?B?SkNTZjFjbkFOb0djdnB5WkZhR1RtM0QvZEFGTXVOb0NBWHl3M2dGZUo0cHNV?= =?utf-8?B?M200dHpFaFB0bmR3ZFZaelJMM3g0RFJZcHNNYkowM3pWZVUrSkJTS3I1YThL?= =?utf-8?B?cStNM1dYTEIwem1EdStlM0hDNHlEbk0xc2huVDNZaFpNRWMzR1dySDlsWTdM?= =?utf-8?B?cE1La2YxUm8zdTgxYXZZQ29kNkQybVZmTTIyVE1RSXhnODdSWG5iOVpSRm9F?= =?utf-8?B?NXc9PQ==?= X-Forefront-Antispam-Report: CIP:4.227.125.105;CTRY:US;LANG:en;SCL:1;SRV:;IPV:CAL;SFV:NSPM;H:[127.0.0.1];PTR:InfoDomainNonexistent;CAT:NONE;SFS:(13230040)(376014)(36860700013)(1800799024)(82310400026);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: fEpT+zpnvMM2hMwO7b91NUW29kURSJgF7ax6WQfYQhB+FwKTzCgvCG8D2IAqpcRV8gAsxjQ8Eux26tWN+2b3dfLLC7LZc3BcH/UHcASzT6DOZJ+W8us0D31Op1byyCFgSsIqSTTcuMiL6eaK+3yLJZHPs3WojbQeALZn5v2uJU9bOFOW9sdTn9Ga93/0jlzhk1qEGHybuLUR+6znyE1xr5f722Wx+1ZFdTOAUhUI6pZG0NkPnh1FuJCnUEcZ1qMcg+3H6VKBEdsluhDehMQq+FM4QhHtEfDmPs23Is9Sl5/S2nMUAepjjWLHiPZsDy3fAAjb82lUP3gdu5mjFFVA4ngS1p2DbAQFuMSFLmhGYz8obQTJ50/g6mwu8zQblB5oK8o5oeaOjxP2N0qU5zkxjA99lDtJv0Q5e83V93g9cceYLPYRKk4YOWKu8dCup2m7 X-OriginatorOrg: axiado.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 02 Feb 2026 13:16:52.5025 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: d2bf995c-436f-4632-f69b-08de625d54f5 X-MS-Exchange-CrossTenant-Id: ff2db17c-4338-408e-9036-2dee8e3e17d7 X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=ff2db17c-4338-408e-9036-2dee8e3e17d7;Ip=[4.227.125.105];Helo=[[127.0.0.1]] X-MS-Exchange-CrossTenant-AuthSource: SJ5PEPF00000203.namprd05.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: CO6PR18MB3857 Add Axiado ax3000-udc (for USB v2.0 ports) and ax3000-udc-gen3 (for USB v3.0 ports) compatible string for AX3000 SoC. Co-developed-by: Krutik Shah Signed-off-by: Krutik Shah Co-developed-by: Prasad Bolisetty Signed-off-by: Prasad Bolisetty Signed-off-by: Vladimir Moravcevic --- .../devicetree/bindings/usb/axiado,ax3000-udc.yaml | 59 ++++++++++++++++++= ++++ 1 file changed, 59 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/axiado,ax3000-udc.yaml b= /Documentation/devicetree/bindings/usb/axiado,ax3000-udc.yaml new file mode 100644 index 000000000000..15658b5c924f --- /dev/null +++ b/Documentation/devicetree/bindings/usb/axiado,ax3000-udc.yaml @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/axiado,ax3000-udc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Axiado AX3000 USB Device Controller (Corigine-based) + +maintainers: + - Krutik Shah + - Prasad Bolisetty + - Vladimir Moravcevic + +description: | + Axiado AX3000 USB Device Controller (UDC) is used on + AX3000 SoCs and evaluation boards. This controller is based on a + Corigine USB IP core and provides SuperSpeed (5 Gb/s), High-Speed + (480 Mb/s). It supports control, bulk, interrupt, and isochronous + transfer types across multiple configurable endpoints. The node + describes the memory-mapped register region, interrupt line, and + other required properties for the UDC hardware. + +properties: + compatible: + enum: + - axiado,ax3000-udc # AX3000 UDC (USB 2.0/High-Speed) + - axiado,ax3000-udc-gen3 # AX3000 UDC (USB 3.0/SuperSpeed) + + reg: + maxItems: 1 + description: Base address and size of the UDC register space. + + interrupts: + maxItems: 1 + description: Interrupt line for the UDC. + +required: + - compatible + - reg + - interrupts + +additionalProperties: false + +examples: + - | + #include + #include + + soc { + #address-cells =3D <2>; + #size-cells =3D <2>; + + usb@81200000 { + compatible =3D "axiado,ax3000-udc"; + reg =3D <0x0 0x81200000 0x0 0x00100000>; + interrupt-parent =3D <&gic500>; + interrupts =3D ; + }; + }; --=20 2.34.1 From nobody Sat Feb 7 09:46:50 2026 Received: from DM5PR21CU001.outbound.protection.outlook.com (mail-centralusazon11021072.outbound.protection.outlook.com [52.101.62.72]) (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 8769A366833; Mon, 2 Feb 2026 13:17:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.62.72 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770038231; cv=fail; b=BV7Ct0RrS7dK+ExmgRbgw7dqijRldQ6AZp4vGuYvv8TVpAs9/Qpr+kamqrHQwwJ99ISov/EZb9nUuyggTRN5vpOrqXgb3C11bIysBxVtgSCtq8VsQ2ExnY/lL+HBORG+cuL3trAA0vFyWYYSneM9OI9S5fwJCew8QtKh1ZkhP/M= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770038231; c=relaxed/simple; bh=Rn62i1LVdkePO2CC1IoffQ0LxljlRHTTN/TPPvrk3qc=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=NxWEVXisp+PZAhXC/DLaCFELoxTW36L/Jam9QCepZ4oMQDANnc/bTpc/gox7rDdCBmvhzoC1b81zCqewV3wJXTaFVNwLaY+RVWxr9hcFcdGgLCPb8cXMqk+WuIZiZUvp3X9Sr5NZMFttEOfVRZeUC7oAC1SkKAGhJwYUrrx5pCg= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=axiado.com; spf=pass smtp.mailfrom=axiado.com; dkim=pass (2048-bit key) header.d=axiado.com header.i=@axiado.com header.b=R6l6ksRT; arc=fail smtp.client-ip=52.101.62.72 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=axiado.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=axiado.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=axiado.com header.i=@axiado.com header.b="R6l6ksRT" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=PLBix2v4ThDRsynCTTX/PaXYkqAIpeHRO5VhFFqxSQ8XNsCe/LL+vMT6xQyzfH6GQL6kkT7TfOzRXE6Rpoc7ezvH7juoiA27k4rqcgJbL+d/B/OhcVSN+++T8I4Sg3dmCryan8TDvQKjOhmIYnbZPkpq0+UHf/Jxc8ettChiWgIzEfUyDPMziVRS18IpT06wBSsEq2tVAn/jw8b34ceJ4Y88bQMb0w+CCzymGnVH2URKQ5q0VGPKA488Eif/ztbyTDKQ7tC4AhSUcmjy1zWOS+Yo4iZ8sVZ9LtUNIbVKmN2VbgPylPa15rtXwcXKzMI/VTEfHeSpGHyNYfcuBHTirg== 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=WBbY8UbM9LpzfqUUoBSotA+5lg1MEBQEVtsxgjxCujQ=; b=S4t2llWSYi+B/ishihbSXJuJHVMPzHZw/95tW8Zu6vQzH2ABc2MdinNPTQfXznE58PuPspHPGg8F8IcuAJXyUgkEMouCCnprR7Sv6l9vkoe8fz9s4NYDNTJHw4MQnc2b0jMhKLFp33NK8RgertRS5y2Un8Xzttw9Eq0oTI126l4IV9uP7neoP9HL19qdGmScOcbH1TWGIE2P0XB60PiCZnDO0mGTvltHVWy9ICbvYZlCg3vuFCjWxA8NyK1iNpZ47yGMc5ibPgTxC1xyahUc9tn6XPznfNKqFY400gufI6hd03sIZvAUq0D/xZqHEUDUZjpKWhcKIjJ+VrDoG9pELQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=fail (sender ip is 4.227.125.105) smtp.rcpttodomain=vger.kernel.org smtp.mailfrom=axiado.com; dmarc=none action=none header.from=axiado.com; dkim=none (message not signed); arc=none (0) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=axiado.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=WBbY8UbM9LpzfqUUoBSotA+5lg1MEBQEVtsxgjxCujQ=; b=R6l6ksRTbBKA9JjCdOnhd81i1BIM5Bdy5/SjkJUXf3s0gaRrDi3rveou4rHnyD1GGBFHA8xTMr5+ZZWJS4vdcx45v6S+ltuMFedY9S03RypFhEq58+JDlvFtD8IZuv6M9/uHEmI9pGDCxWYP2Z+5TT/BZ2tsQAaFmLODmwujvtUj6NyEzq4NusZIbQ7ISpJ4Gfzj06MMDZZbnl7RSkDfrIEEbmCdSSOpg/367zC2wYLzkFxlSC5AV6I5Y9j8gidH8OTn5aEzQopZO4iF6/du/6C/fV5lORx7YrYubCr3tEXnjXTrk0smtAJyk+Xfwm4fhwYawrqHlmEI/xKXzuPSwA== Received: from SJ0PR13CA0220.namprd13.prod.outlook.com (2603:10b6:a03:2c1::15) by SA6PR18MB6342.namprd18.prod.outlook.com (2603:10b6:806:41d::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9587.12; Mon, 2 Feb 2026 13:16:54 +0000 Received: from SJ5PEPF00000203.namprd05.prod.outlook.com (2603:10b6:a03:2c1:cafe::1a) by SJ0PR13CA0220.outlook.office365.com (2603:10b6:a03:2c1::15) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.9587.12 via Frontend Transport; Mon, 2 Feb 2026 13:16:31 +0000 X-MS-Exchange-Authentication-Results: spf=fail (sender IP is 4.227.125.105) smtp.mailfrom=axiado.com; dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=axiado.com; Received-SPF: Fail (protection.outlook.com: domain of axiado.com does not designate 4.227.125.105 as permitted sender) receiver=protection.outlook.com; client-ip=4.227.125.105; helo=[127.0.0.1]; Received: from [127.0.0.1] (4.227.125.105) by SJ5PEPF00000203.mail.protection.outlook.com (10.167.244.36) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.9587.10 via Frontend Transport; Mon, 2 Feb 2026 13:16:53 +0000 From: Vladimir Moravcevic Date: Mon, 02 Feb 2026 05:16:29 -0800 Subject: [PATCH 2/3] usb: gadget: udc: Add UDC driver for Axiado Device controller IP Corigine Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260202-axiado-ax3000-usb-device-controller-v1-2-45ce0a8b014f@axiado.com> References: <20260202-axiado-ax3000-usb-device-controller-v1-0-45ce0a8b014f@axiado.com> In-Reply-To: <20260202-axiado-ax3000-usb-device-controller-v1-0-45ce0a8b014f@axiado.com> To: Krutik Shah , Prasad Bolisetty , Greg Kroah-Hartman , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: linux-usb@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, openbmc@lists.ozlabs.org, Vladimir Moravcevic X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1770038210; l=142553; i=vmoravcevic@axiado.com; s=20250904; h=from:subject:message-id; bh=Rn62i1LVdkePO2CC1IoffQ0LxljlRHTTN/TPPvrk3qc=; b=h5qgx/wfA3wQ7hQSTk2kFRdCY+aL/mNjOw26y52uFrVcSjHla2Vga2qqoPEroOoG1KwrDEg1W PrCQYUdtoN1BSB7TDsv/OPHl/0y4KPLGp3dLvI8CIuQuYxzjEHvwp+n X-Developer-Key: i=vmoravcevic@axiado.com; a=ed25519; pk=iiyhWhM1F4HlCbbW3I3qKZhPCE8JsCrDQMgCBRg4YMA= X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: SJ5PEPF00000203:EE_|SA6PR18MB6342:EE_ X-MS-Office365-Filtering-Correlation-Id: ae5b63b4-0e51-461a-5c8f-08de625d55aa X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|376014|1800799024|36860700013|82310400026; X-Microsoft-Antispam-Message-Info: =?utf-8?B?MzJyT2psaVFXaDd6V1k1OHpqa2x4bGFZd0poTDdFVFYzNTFMeEdRaWhLVkhT?= =?utf-8?B?aW4zb0JHbWptQlhoQzVQbGQxbmk1ajlKU28xTUExK2dyNiswWlp2RjJPZ1Ra?= =?utf-8?B?aDhJSzZZVHpaZkhZUU51RGcrM3FRUW40UGVUNzVDNXVIRnIvTTFNY1Y1ZWQy?= =?utf-8?B?TkFBMW50dkdCeFRaaVNqbnFFNzNSWTB2WThXSVdrR0xORWM2bG5ybUhreDVi?= =?utf-8?B?OWQwZ1N6WFd0VDZOdmNQSUxzOTgxb3FaQk9wQzZwcVFTWTViSWwwdzVNbnlE?= =?utf-8?B?OU1LUnFFc1ZiOURsYWNMWDVXaXY1RlAvS2lKMmlycGJYWHJ5d2l6KzdsMDFV?= =?utf-8?B?bHlNLy9DNlFsZlpFWEp1Uks4QkJNQmQ5SEJUYXpwazl4eUNxd2tmRElLT1dS?= =?utf-8?B?dUplY1VzWXZpcnNuOTRzenptQU5NUCtscXMyeDg2MjdpVDQ2NHNxYWRzeCth?= =?utf-8?B?VDBKS2dIT3Y5YUZiSExJRERONTRUSGF4MGVaZjgyVVl5WnY3VkoxSGlFa0dF?= =?utf-8?B?OUJtQ0psbzJidWk3WVVOak9qd1BWa1kxUzZVdUNJaGlSU0ZJNkE5TUxxYVB0?= =?utf-8?B?T1F5Q0EvcmV6dkdUOGVXcjgveHp0NTJrMUw0SGtlaFFVYm5MRkhqVUhLbUVU?= =?utf-8?B?dE9iYktDS0dTbmRaNi9oejZsZDRHQXhGTktwc1o0VjRMZ05HOW1VTkt4UU5r?= =?utf-8?B?MVBaMVp0SVNHVFNxakoyNVpoVkovOUJnc3Qxa0RRT1NPd3FGYkpGOHBodExi?= =?utf-8?B?UnpVeVorRjdHMExxcDRieDVicTdFRGRoNE40ZTlZNFM2Z3FKUENYbk5NWXo5?= =?utf-8?B?a0pKZUhBdnNLaHpBbnZwWk03SWM0WVBKamt1Yy80NXBCb2lBam9BR3JPZ2Jy?= =?utf-8?B?WlBwcEhqRFErMjRMblJYaER0cVRZUHQvcDBtelRSdDdqVHVMank5L1RzTTRn?= =?utf-8?B?bjVCOThFeXh3OGJLQjNyM0ppMVA4TGZZYktzMStQSXFobkZjeGt6aFk4T3ZV?= =?utf-8?B?WS84ZHp4RkJ3N3R4d0pSL3E3RlV6QjFJRjliMExMZ1JNNHRFOXBwblovU25i?= =?utf-8?B?RFloK281cDNBOURKcmkvRWxXZXQ5eE5maVlSK2srcEt4UFRQcFNmZys1Y2FT?= =?utf-8?B?TEpoWWI0bSt6MmU5OUVVZHVRTG1YcmlhSDFZVXBqV2w3bGZROCtIcm1iNWQy?= =?utf-8?B?VTJrdHFJT2Z0bUpuZW90ZTdhQXczSGpBeW5MVStaWTNMVUZKSzhjZFRkaDZj?= =?utf-8?B?L2I2U2xoWU9JOFZRQmpOSHpmSmtWckg2ZDZpVzQ3S2NSTmw0Y1lpam96MStE?= =?utf-8?B?aHZlR1l6ZWhOSHdQNndUR1BjVmtUMmVhMk51amhGd2IrUmtkQzdOcjBKZFQ2?= =?utf-8?B?THRzWDNrcVpQT1EwSTVhQkdEVEtLTnJiOE82ZGlPaTlaM09NVjhJb2RMNzlQ?= =?utf-8?B?cndEbDdXeVo3RG9Ebm5zMGVpbHExVnRyRktKNzNpU09xejRvZTQxVVdLT1lk?= =?utf-8?B?YXZuYndGbWJsOHFRMDFDZGNPbkg5N1I5RkE3eFdlSDlzRkQ5UWZpOFcwK2F3?= =?utf-8?B?RmJTd1p4MEl3QWNNSUx6K2t5K3h5cC94UkN6VUt4L05meW9hbDl6UzVCOG9k?= =?utf-8?B?cjFsTmhBbGNsNlBHbHZ4aWIzV2pwVTlzVG96OC9IRmZJcExFcE40eVYwMy96?= =?utf-8?B?TmdEVkhEOEhMNDdBbUJ5WEREeDVoeEJUd1kvTU1Yb29oVkpjT3lsMFB3UFdy?= =?utf-8?B?dFRNQ0RCcnNiTVM2a0lLOHZUOWZZRmNldWp0ZytscG5YTmdsM3habFNpbC9z?= =?utf-8?B?SHRoYTZ5ak9YNHpnamlMSmVwbEpSUEhjZmwxQ05KeVk1TkpuY0tBeVFCUlZX?= =?utf-8?B?WGRWNm1qR0xLQkxTVTA4c1pmS2lzWDZrd0JXazZqWWNRMlhIWFNVbkxaSyto?= =?utf-8?B?NGo5M3k5K3dXYXoxWHlmTE9oOGFrWkQvN3lmc3lXZE55YWFOZkNoOUJ6YnJC?= =?utf-8?B?WmJFVmhlWndpdksrWXZ4cTViWlNyWDdic3U2dnFGeUl3NzdFb0FmdEVtQ1Q1?= =?utf-8?B?WWhia3dxSjlCam5iVEI2MzBZM2dBTFF0V2hSYnpIeWZjRXhEYXpUejl2d1py?= =?utf-8?B?Zm9kemZhR0VGWWYzSmx6ZDhxOFozNDN1S3BtNW1ualRrcTZQVTluSkZDSlVV?= =?utf-8?B?OENRYlVUdGltU0JWTmx3VGtOZ0V0VHVNUUZYNi8xQ3lkbDRjTWFUWU5BYkJm?= =?utf-8?B?clp3VzQ0bHp4SDRFaGpYSEtYZzZ3PT0=?= X-Forefront-Antispam-Report: CIP:4.227.125.105;CTRY:US;LANG:en;SCL:1;SRV:;IPV:CAL;SFV:NSPM;H:[127.0.0.1];PTR:InfoDomainNonexistent;CAT:NONE;SFS:(13230040)(376014)(1800799024)(36860700013)(82310400026);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: es1jw+fLFt2ox93ScK4+vuFV0B/z9kLQddL0TxCesoOeKp+7LumsyhfBZc55XCy6himzMQxuuBT9lvAbd/mtAtODD6qsIYNMJ+oAFGQSqYaUFQeNBy8VGIPowGUe+Pf4FI4eGIWogH+8pK+fHN1mA/TdXOZqeJLA7H7psfmFfCUTSjgm2VPQrfgL/vJkSOM2fv9FC1dVMLBMDW/Ez8pZ4xJRGqsF6UPcSgp8/pokBaUrjnyNafwYzAM80HYDt7NWpn96Wq6y+59FMRGlLKPPPqSWPbhNx1moUFs56U6v6M/ddx+E/CWX7m0W2ImOWry0M/tJZZ0EO0lgNPCrNN/bPLrqLaBGIIHB4JTfYhjX1zJbaksFGbMScPcoy7C1zJzD2H0BDhWHBKnQExh01keTrG56/yrtzv6q8E8OtkiIODDp8Regu8ot6g2WczpnKFrd X-OriginatorOrg: axiado.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 02 Feb 2026 13:16:53.6471 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: ae5b63b4-0e51-461a-5c8f-08de625d55aa X-MS-Exchange-CrossTenant-Id: ff2db17c-4338-408e-9036-2dee8e3e17d7 X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=ff2db17c-4338-408e-9036-2dee8e3e17d7;Ip=[4.227.125.105];Helo=[[127.0.0.1]] X-MS-Exchange-CrossTenant-AuthSource: SJ5PEPF00000203.namprd05.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: SA6PR18MB6342 Add Corigine USB IP Driver for Axiado AX3000 SoC's USB peripheral (USB 2.0/3.0). The driver is based on the Corigine USB IP core with Axiado-specific enhancements including VBUS detection and USB link stability fixes. The driver supports both USB 2.0 High-Speed and USB 3.0 SuperSpeed modes with control, bulk, interrupt, and isochronous transfer types. Co-developed-by: Krutik Shah Signed-off-by: Krutik Shah Co-developed-by: Prasad Bolisetty Signed-off-by: Prasad Bolisetty Signed-off-by: Vladimir Moravcevic --- drivers/usb/gadget/udc/Kconfig | 15 + drivers/usb/gadget/udc/Makefile | 1 + drivers/usb/gadget/udc/crg_udc.c | 4522 ++++++++++++++++++++++++++++++++++= ++++ drivers/usb/gadget/udc/crg_udc.h | 364 +++ 4 files changed, 4902 insertions(+) diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig index 26460340fbc9..b94d113aad99 100644 --- a/drivers/usb/gadget/udc/Kconfig +++ b/drivers/usb/gadget/udc/Kconfig @@ -417,6 +417,21 @@ config USB_ASPEED_UDC dynamically linked module called "aspeed_udc" and force all gadget drivers to also be dynamically linked. =20 +config USB_CRG_UDC + tristate "AXIADO CORIGINE-based AX3000 Device Controller" + depends on ARCH_AXIADO || COMPILE_TEST + depends on USB_GADGET + help + Enables AX3000 USB device controller driver for Axiado + SoCs and evaluation boards. + + Based on the Corigine USB IP core driver with Axiado specific + enhancements. Supports USB 2.0 (High-Speed) and USB 3.0 + (SuperSpeed), including control, bulk, interrupt, and + isochronous transfers. + + Say "y" to build statically, or "m" to build as a module. + source "drivers/usb/gadget/udc/aspeed-vhub/Kconfig" =20 source "drivers/usb/gadget/udc/cdns2/Kconfig" diff --git a/drivers/usb/gadget/udc/Makefile b/drivers/usb/gadget/udc/Makef= ile index 1b9b1a4f9c57..b17b9c4665a1 100644 --- a/drivers/usb/gadget/udc/Makefile +++ b/drivers/usb/gadget/udc/Makefile @@ -38,3 +38,4 @@ obj-$(CONFIG_USB_ASPEED_UDC) +=3D aspeed_udc.o obj-$(CONFIG_USB_BDC_UDC) +=3D bdc/ obj-$(CONFIG_USB_MAX3420_UDC) +=3D max3420_udc.o obj-$(CONFIG_USB_CDNS2_UDC) +=3D cdns2/ +obj-$(CONFIG_USB_CRG_UDC) +=3D crg_udc.o diff --git a/drivers/usb/gadget/udc/crg_udc.c b/drivers/usb/gadget/udc/crg_= udc.c new file mode 100644 index 000000000000..701123dc35bc --- /dev/null +++ b/drivers/usb/gadget/udc/crg_udc.c @@ -0,0 +1,4522 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +// +// Copyright (c) 2019 Corigine Inc. +// Copyright (c) 2022-2026 Axiado Corporation. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "crg_udc.h" + +#define INIT_ZERO -1 +#define UDC_FALSE false + +#define MAX_PACKET_SIZE 1024 + +#define DMA_ADDR_INVALID (~(dma_addr_t)0) + +#define CRG_ERST_SIZE 1 +#define CRG_EVENT_RING_SIZE 256 +#define CRG_NUM_EP_CX 32 + +#define TRB_MAX_BUFFER_SIZE 65536 +#define CRGUDC_CONTROL_EP_TD_RING_SIZE 16 +#define CRGUDC_BULK_EP_TD_RING_SIZE 1024 +#define CRGUDC_ISOC_EP_TD_RING_SIZE 32 +#define CRGUDC_INT_EP_TD_RING_SIZE 8 +#define CRGUDC_ROLE_DEVICE 0x1 + +#define U1_TIMEOUT_VAL 0x70 +#define U2_TIMEOUT_VAL 0x70 + +#define STATE_USB_LINK_STABLE 4 + +/*********Feature switches********************/ +#define U12_FORBIDDEN 1 +#define U12_INITIATE_FORBIDDEN 1 +#define CRG_UDC_INT_EN +#define REINIT_EP0_ON_BUS_RESET +/*********************************************/ + +enum EP_STATE_E { + EP_STATE_DISABLED =3D 0, + EP_STATE_RUNNING =3D 1, + EP_STATE_HALTED =3D 2, + EP_STATE_STOPPED =3D 3 +}; + +enum EP_TYPE_E { + EP_TYPE_INVALID =3D 0, + EP_TYPE_ISOCH_OUTBOUND, + EP_TYPE_BULK_OUTBOUND, + EP_TYPE_INTR_OUTBOUND, + EP_TYPE_INVALID2, + EP_TYPE_ISOCH_INBOUND, + EP_TYPE_BULK_INBOUND, + EP_TYPE_INTR_INBOUND +}; + +enum TRB_TYPE_E { + TRB_TYPE_RSVD =3D 0, + TRB_TYPE_XFER_NORMAL, + TRB_TYPE_RSVD2, + TRB_TYPE_XFER_DATA_STAGE, + TRB_TYPE_XFER_STATUS_STAGE, + TRB_TYPE_XFER_DATA_ISOCH, /* 5*/ + TRB_TYPE_LINK, + TRB_TYPE_RSVD7, + TRB_TYPE_NO_OP, + + TRB_TYPE_EVT_TRANSFER =3D 32, + TRB_TYPE_EVT_CMD_COMPLETION =3D 33, + TRB_TYPE_EVT_PORT_STATUS_CHANGE =3D 34, + TRB_TYPE_EVT_MFINDEX_WRAP =3D 39, + TRB_TYPE_EVT_SETUP_PKT =3D 40, +}; + +/*Table 127*/ +enum TRB_CMPL_CODES_E { + CMPL_CODE_INVALID =3D 0, + CMPL_CODE_SUCCESS, + CMPL_CODE_DATA_BUFFER_ERR, + CMPL_CODE_BABBLE_DETECTED_ERR, + CMPL_CODE_USB_TRANS_ERR, + CMPL_CODE_TRB_ERR, /*5*/ + CMPL_CODE_TRB_STALL, + CMPL_CODE_INVALID_STREAM_TYPE_ERR =3D 10, + CMPL_CODE_SHORT_PKT =3D 13, + CMPL_CODE_RING_UNDERRUN, + CMPL_CODE_RING_OVERRUN, /*15*/ + CMPL_CODE_EVENT_RING_FULL_ERR =3D 21, + CMPL_CODE_STOPPED =3D 26, + CMPL_CODE_STOPPED_LENGTH_INVALID =3D 27, + CMPL_CODE_ISOCH_BUFFER_OVERRUN =3D 31, + /*192-224 vendor defined error*/ + CMPL_CODE_PROTOCOL_STALL =3D 192, + CMPL_CODE_SETUP_TAG_MISMATCH =3D 193, + CMPL_CODE_HALTED =3D 194, + CMPL_CODE_HALTED_LENGTH_INVALID =3D 195, + CMPL_CODE_DISABLED =3D 196, + CMPL_CODE_DISABLED_LENGTH_INVALID =3D 197, +}; + +static const char driver_name[] =3D "crg_udc"; + +struct buffer_info { + void *vaddr; + dma_addr_t dma; + u32 len; +}; + +struct transfer_trb_s { + __le32 dw0; + __le32 dw1; + +#define TRB_TRANSFER_LEN_MASK 0x0001FFFF +#define TRB_TRANSFER_LEN_SHIFT 0 +#define TRB_TD_SIZE_MASK 0x003E0000 +#define TRB_TD_SIZE_SHIFT 17 +#define TRB_INTR_TARGET_MASK 0xFFC00000 +#define TRB_INTR_TARGET_SHIFT 22 + __le32 dw2; + +#define TRB_CYCLE_BIT_MASK 0x00000001 +#define TRB_CYCLE_BIT_SHIFT 0 +#define TRB_LINK_TOGGLE_CYCLE_MASK 0x00000002 +#define TRB_LINK_TOGGLE_CYCLE_SHIFT 1 +#define TRB_INTR_ON_SHORT_PKT_MASK 0x00000004 +#define TRB_INTR_ON_SHORT_PKT_SHIFT 2 +#define TRB_NO_SNOOP_MASK 0x00000008 +#define TRB_NO_SNOOP_SHIFT 3 +#define TRB_CHAIN_BIT_MASK 0x00000010 +#define TRB_CHAIN_BIT_SHIFT 4 +#define TRB_INTR_ON_COMPLETION_MASK 0x00000020 +#define TRB_INTR_ON_COMPLETION_SHIFT 5 + +#define TRB_APPEND_ZLP_MASK 0x00000080 +#define TRB_APPEND_ZLP_SHIFT 7 + +#define TRB_BLOCK_EVENT_INT_MASK 0x00000200 +#define TRB_BLOCK_EVENT_INT_SHIFT 9 +#define TRB_TYPE_MASK 0x0000FC00 +#define TRB_TYPE_SHIFT 10 +#define DATA_STAGE_TRB_DIR_MASK 0x00010000 +#define DATA_STAGE_TRB_DIR_SHIFT 16 +#define TRB_SETUP_TAG_MASK 0x00060000 +#define TRB_SETUP_TAG_SHIFT 17 +#define STATUS_STAGE_TRB_STALL_MASK 0x00080000 +#define STATUS_STAGE_TRB_STALL_SHIFT 19 +#define STATUS_STAGE_TRB_SET_ADDR_MASK 0x00100000 +#define STATUS_STAGE_TRB_SET_ADDR_SHIFT 20 + +#define ISOC_TRB_FRAME_ID_MASK 0x7FF00000 +#define ISOC_TRB_FRAME_ID_SHIFT 20 +#define ISOC_TRB_SIA_MASK 0x80000000 +#define ISOC_TRB_SIA_SHIFT 31 + __le32 dw3; +}; + +struct event_trb_s { + __le32 dw0; + __le32 dw1; + +#define EVE_TRB_TRAN_LEN_MASK 0x0001FFFF +#define EVE_TRB_TRAN_LEN_SHIFT 0 +#define EVE_TRB_COMPL_CODE_MASK 0xFF000000 +#define EVE_TRB_COMPL_CODE_SHIFT 24 + __le32 dw2; + +#define EVE_TRB_CYCLE_BIT_MASK 0x00000001 +#define EVE_TRB_CYCLE_BIT_SHIFT 0 +#define EVE_TRB_TYPE_MASK 0x0000FC00 +#define EVE_TRB_TYPE_SHIFT 10 +#define EVE_TRB_ENDPOINT_ID_MASK 0x001F0000 +#define EVE_TRB_ENDPOINT_ID_SHIFT 16 +#define EVE_TRB_SETUP_TAG_MASK 0x00600000 +#define EVE_TRB_SETUP_TAG_SHIFT 21 + __le32 dw3; +}; + +struct ep_cx_s { + +#define EP_CX_LOGICAL_EP_NUM_MASK 0x00000078 +#define EP_CX_LOGICAL_EP_NUM_SHIFT 3 + + +#define EP_CX_INTERVAL_MASK 0x00FF0000 +#define EP_CX_INTERVAL_SHIFT 16 + __le32 dw0; + +#define EP_CX_EP_TYPE_MASK 0x00000038 +#define EP_CX_EP_TYPE_SHIFT 3 +#define EP_CX_MAX_BURST_SIZE_MASK 0x0000FF00 +#define EP_CX_MAX_BURST_SIZE_SHIFT 8 +#define EP_CX_MAX_PACKET_SIZE_MASK 0xFFFF0000 +#define EP_CX_MAX_PACKET_SIZE_SHIFT 16 + __le32 dw1; + +#define EP_CX_DEQ_CYC_STATE_MASK 0x00000001 +#define EP_CX_DEQ_CYC_STATE_SHIFT 0 +#define EP_CX_TR_DQPT_LO_MASK 0xFFFFFFF0 +#define EP_CX_TR_DQPT_LO_SHIFT 4 + __le32 dw2; + __le32 dw3; +}; + +struct erst_s { + /* 64-bit event ring segment address */ + __le32 seg_addr_lo; + __le32 seg_addr_hi; + __le32 seg_size; + /* Set to zero */ + __le32 rsvd; +}; + +struct sel_value_s { + u16 u2_pel_value; + u16 u2_sel_value; + u8 u1_pel_value; + u8 u1_sel_value; +}; + +struct crg_udc_request { + struct usb_request usb_req; + struct list_head queue; + bool mapped; + u64 buff_len_left; + u32 trbs_needed; + struct transfer_trb_s *first_trb; + struct transfer_trb_s *last_trb; + bool all_trbs_queued; + bool short_pkt; +}; + +struct crg_udc_ep { + struct usb_ep usb_ep; + + struct buffer_info tran_ring_info; + struct transfer_trb_s *first_trb; + struct transfer_trb_s *last_trb; + + struct transfer_trb_s *enq_pt; + struct transfer_trb_s *deq_pt; + u8 pcs; + + char name[10]; + u8 DCI; + struct list_head queue; + const struct usb_endpoint_descriptor *desc; + const struct usb_ss_ep_comp_descriptor *comp_desc; + bool tran_ring_full; + struct crg_gadget_dev *crg_udc; + + int ep_state; + + unsigned wedge:1; +}; + +#define CRG_RING_NUM 1 + +struct crg_udc_event { + struct buffer_info erst; + struct erst_s *p_erst; + struct buffer_info event_ring; + struct event_trb_s *evt_dq_pt; + u8 CCS; + struct event_trb_s *evt_seg0_last_trb; +}; + +struct crg_setup_packet { + struct usb_ctrlrequest usbctrlreq; + u16 setup_tag; +}; + +struct crg_udc_priv { + bool plat_setup_gen3; +}; + +struct crg_gadget_dev { + void __iomem *mmio_virt_base; + struct resource *udc_res; + resource_size_t udc_res_len; + struct crg_uccr *uccr; + struct crg_uicr *uicr[CRG_RING_NUM]; + + const struct crg_udc_priv *priv; + + /* udc_lock device lock */ + spinlock_t udc_lock; + + struct device *dev; + struct usb_gadget gadget; + struct usb_gadget_driver *gadget_driver; + + int irq; + struct task_struct *vbus_task; + + struct crg_udc_ep udc_ep[32]; + struct buffer_info ep_cx; + struct ep_cx_s *p_epcx; + + struct crg_udc_event udc_event[CRG_RING_NUM]; + + struct crg_udc_request *status_req; + u16 *statusbuf; + struct sel_value_s sel_value; + void (*setup_fn_call_back)(struct crg_gadget_dev *a); + +#define WAIT_FOR_SETUP 0 +#define SETUP_PKT_PROCESS_IN_PROGRESS 1 +#define DATA_STAGE_XFER 2 +#define DATA_STAGE_RECV 3 +#define STATUS_STAGE_XFER 4 +#define STATUS_STAGE_RECV 5 + u8 setup_status; +#define CTRL_REQ_QUEUE_DEPTH 5 + struct crg_setup_packet ctrl_req_queue[CTRL_REQ_QUEUE_DEPTH]; + u8 ctrl_req_enq_idx; + + u8 device_state; + u8 resume_state; + u16 dev_addr; + u8 setup_tag; + u8 set_tm; + + u32 num_enabled_eps; + + int connected; + + unsigned u2_RWE:1; + unsigned feature_u1_enable:1; + unsigned feature_u2_enable:1; + + int setup_tag_mismatch_found; + int portsc_on_reconnecting; +}; + +/*An array should be implemented if we want to support multi + * usb device controller + */ +static DECLARE_WAIT_QUEUE_HEAD(vbus_wait); + +static struct usb_endpoint_descriptor crg_udc_ep0_desc =3D { + .bLength =3D USB_DT_ENDPOINT_SIZE, + .bDescriptorType =3D USB_DT_ENDPOINT, + .bEndpointAddress =3D 0, + .bmAttributes =3D USB_ENDPOINT_XFER_CONTROL, + .wMaxPacketSize =3D cpu_to_le16(64), +}; + +static int get_ep_state(struct crg_gadget_dev *crg_udc, int DCI) +{ + struct crg_udc_ep *udc_ep_ptr; + + if (DCI < 0 || DCI =3D=3D 1) + return -EINVAL; + + udc_ep_ptr =3D &crg_udc->udc_ep[DCI]; + + return udc_ep_ptr->ep_state; +} + +/************command related ops**************************/ +static int crg_issue_command(struct crg_gadget_dev *crg_udc, + enum crg_cmd_type type, u32 param0, u32 param1) +{ + struct crg_uccr *uccr =3D crg_udc->uccr; + u32 status; + bool check_complete =3D false; + u32 tmp; + + tmp =3D readl(&uccr->control); + if (tmp & CRG_U3DC_CTRL_RUN) + check_complete =3D true; + + if (check_complete) { + tmp =3D readl(&uccr->cmd_control); + if (tmp & CRG_U3DC_CMD_CTRL_ACTIVE) { + dev_err(crg_udc->dev, "%s prev command is not complete!\n", __func__); + return -1; + } + } + /* Ensure that everything is written before issuing new command */ + wmb(); + + writel(param0, &uccr->cmd_param0); + writel(param1, &uccr->cmd_param1); + + /*ignore CMD IOC, in uboot no irq is*/ + tmp =3D CRG_U3DC_CMD_CTRL_ACTIVE | + CRG_U3DC_CMD_CTRL_TYPE(type); + writel(tmp, &uccr->cmd_control); + + dev_dbg(crg_udc->dev, "%s start, type=3D%d, par0=3D0x%x, par1=3D0x%x\n", + __func__, type, param0, param1); + + if (check_complete) { + do { + tmp =3D readl(&uccr->cmd_control); + } while (tmp & CRG_U3DC_CMD_CTRL_ACTIVE); + + dev_dbg(crg_udc->dev, "%s successful\n", __func__); + + status =3D CRG_U3DC_CMD_CTRL_STATUS_GET(tmp); + if (status !=3D 0) { + dev_dbg(crg_udc->dev, "%s fail\n", __func__); + return -EIO; + } + } + + return 0; +} + +static void setup_link_trb(struct transfer_trb_s *link_trb, + bool toggle, ulong next_trb) +{ + u32 dw =3D 0; + + link_trb->dw0 =3D cpu_to_le32(lower_32_bits(next_trb)); + link_trb->dw1 =3D cpu_to_le32(upper_32_bits(next_trb)); + link_trb->dw2 =3D 0; + + dw =3D SETF_VAR(TRB_TYPE, dw, TRB_TYPE_LINK); + if (toggle) + dw =3D SETF_VAR(TRB_LINK_TOGGLE_CYCLE, dw, 1); + else + dw =3D SETF_VAR(TRB_LINK_TOGGLE_CYCLE, dw, 0); + + link_trb->dw3 =3D cpu_to_le32(dw); + + /* Ensure that lint trb is updated */ + wmb(); +} + +static dma_addr_t tran_trb_virt_to_dma(struct crg_udc_ep *udc_ep, + struct transfer_trb_s *trb) +{ + unsigned long offset; + int trb_idx; + dma_addr_t dma_addr =3D 0; + + trb_idx =3D trb - udc_ep->first_trb; + if (unlikely(trb_idx < 0)) + return 0; + + offset =3D trb_idx * sizeof(*trb); + if (unlikely(offset > udc_ep->tran_ring_info.len)) + return 0; + dma_addr =3D udc_ep->tran_ring_info.dma + offset; + return dma_addr; +} + +static struct transfer_trb_s *tran_trb_dma_to_virt + (struct crg_udc_ep *udc_ep, dma_addr_t address) +{ + unsigned long offset; + struct transfer_trb_s *trb_virt; + + if (lower_32_bits(address) & 0xf) + return NULL; + + offset =3D address - udc_ep->tran_ring_info.dma; + if (unlikely(offset > udc_ep->tran_ring_info.len)) + return NULL; + offset =3D offset / sizeof(struct transfer_trb_s); + trb_virt =3D udc_ep->first_trb + offset; + return trb_virt; +} + +static dma_addr_t event_trb_virt_to_dma + (struct crg_udc_event *udc_event, struct event_trb_s *event) +{ + dma_addr_t dma_addr =3D 0; + unsigned long seg_offset; + + if (!udc_event || !event) + return 0; + + /* update dequeue pointer */ + seg_offset =3D (void *)event - udc_event->event_ring.vaddr; + dma_addr =3D udc_event->event_ring.dma + seg_offset; + + return dma_addr; +} + +/* Completes request. Calls gadget completion handler + * caller must have acquired spin lock. + */ +static void req_done(struct crg_udc_ep *udc_ep, + struct crg_udc_request *udc_req, int status) +{ + unsigned long flags =3D 0; + struct crg_gadget_dev *crg_udc =3D udc_ep->crg_udc; + + if (likely(udc_req->usb_req.status =3D=3D -EINPROGRESS)) + udc_req->usb_req.status =3D status; + + list_del_init(&udc_req->queue); + + + if (udc_req->usb_req.num_mapped_sgs) { + dma_unmap_sg(crg_udc->dev, udc_req->usb_req.sg, + udc_req->usb_req.num_sgs, + (usb_endpoint_dir_in(udc_ep->desc) + ? DMA_TO_DEVICE : DMA_FROM_DEVICE)); + + udc_req->usb_req.num_mapped_sgs =3D 0; + dev_dbg(crg_udc->dev, "dma_unmap_sg done\n"); + } + + if (udc_req->mapped) { + if (udc_req->usb_req.length) { + dma_unmap_single(crg_udc->dev, udc_req->usb_req.dma, + udc_req->usb_req.length, usb_endpoint_dir_in(udc_ep->desc) + ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + } + udc_req->usb_req.dma =3D DMA_ADDR_INVALID; + udc_req->mapped =3D 0; + } + + if (udc_req->usb_req.complete) { + spin_unlock_irqrestore(&crg_udc->udc_lock, flags); + udc_req->usb_req.complete(&udc_ep->usb_ep, &udc_req->usb_req); + spin_lock_irqsave(&crg_udc->udc_lock, flags); + } +} + +static void nuke(struct crg_udc_ep *udc_ep, int status) +{ + struct crg_udc_request *req =3D NULL; + + while (!list_empty(&udc_ep->queue)) { + req =3D list_entry(udc_ep->queue.next, + struct crg_udc_request, + queue); + + req_done(udc_ep, req, status); + } +} + +static void clear_req_container(struct crg_udc_request *udc_req_ptr) +{ + udc_req_ptr->buff_len_left =3D 0; + udc_req_ptr->trbs_needed =3D 0; + udc_req_ptr->all_trbs_queued =3D 0; + udc_req_ptr->first_trb =3D NULL; + udc_req_ptr->last_trb =3D NULL; + udc_req_ptr->short_pkt =3D 0; +} + +static bool is_pointer_less_than(struct transfer_trb_s *a, + struct transfer_trb_s *b, struct crg_udc_ep *udc_ep) +{ + if (b > a && (udc_ep->enq_pt >=3D b || udc_ep->enq_pt < a)) + return true; + if (b < a && (udc_ep->enq_pt >=3D b && udc_ep->enq_pt < a)) + return true; + return false; +} + +/* num_trbs here is the size of the ring. */ +static u32 room_on_ring(struct crg_gadget_dev *crg_udc, u32 num_trbs, + struct transfer_trb_s *p_ring, struct transfer_trb_s *enq_pt, + struct transfer_trb_s *dq_pt) +{ + u32 i =3D 0; + + if (enq_pt =3D=3D dq_pt) { + /* ring is empty */ + return num_trbs - 1; + } + + while (enq_pt !=3D dq_pt) { + i++; + + enq_pt++; + + if (GETF(TRB_TYPE, enq_pt->dw3) =3D=3D TRB_TYPE_LINK) + enq_pt =3D p_ring; + + if (i > num_trbs) + break; + } + + return i - 1; +} + +static void crg_udc_epcx_setup(struct crg_udc_ep *udc_ep) +{ + struct crg_gadget_dev *crg_udc =3D udc_ep->crg_udc; + const struct usb_endpoint_descriptor *desc =3D udc_ep->desc; + const struct usb_ss_ep_comp_descriptor *comp_desc =3D udc_ep->comp_desc; + u8 DCI =3D udc_ep->DCI; + struct ep_cx_s *epcx =3D (struct ep_cx_s *)(crg_udc->p_epcx + DCI - 2); + enum EP_TYPE_E ep_type; + u16 maxburst =3D 0; + u8 maxstreams =3D 0; + u16 maxsize; + u32 dw; + + dev_dbg(crg_udc->dev, "crgudc->p_epcx %p, epcx %p\n", crg_udc->p_epcx, ep= cx); + dev_dbg(crg_udc->dev, "DCI %d, sizeof ep_cx %ld\n", DCI, sizeof(struct ep= _cx_s)); + dev_dbg(crg_udc->dev, "desc epaddr =3D 0x%x\n", desc->bEndpointAddress); + + /*corigine gadget dir should be opposite to host dir*/ + if (usb_endpoint_dir_out(desc)) + ep_type =3D usb_endpoint_type(desc) + EP_TYPE_INVALID2; + else + ep_type =3D usb_endpoint_type(desc); + + maxsize =3D usb_endpoint_maxp(desc) & 0x07ff; /* D[0:10] */ + + if (crg_udc->gadget.speed >=3D USB_SPEED_SUPER) { + maxburst =3D comp_desc->bMaxBurst; + + if (usb_endpoint_xfer_bulk(udc_ep->desc)) + maxstreams =3D comp_desc->bmAttributes & 0x1f; + + } else if ((crg_udc->gadget.speed =3D=3D USB_SPEED_HIGH || + crg_udc->gadget.speed =3D=3D USB_SPEED_FULL) && + (usb_endpoint_xfer_int(udc_ep->desc) || + usb_endpoint_xfer_isoc(udc_ep->desc))) { + if (crg_udc->gadget.speed =3D=3D USB_SPEED_HIGH) + maxburst =3D (usb_endpoint_maxp(desc) >> 11) & 0x3; + if (maxburst =3D=3D 0x3) { + dev_err(crg_udc->dev, "invalid maxburst\n"); + maxburst =3D 0x2; + } + } + + /* fill ep_dw0 */ + dw =3D 0; + dw =3D SETF_VAR(EP_CX_LOGICAL_EP_NUM, dw, udc_ep->DCI / 2); + dw =3D SETF_VAR(EP_CX_INTERVAL, dw, desc->bInterval); + if (maxstreams) { + dev_err(crg_udc->dev, "%s maxstream=3D%d is not expected\n", + __func__, maxstreams); + } + epcx->dw0 =3D cpu_to_le32(dw); + + /* fill ep_dw1 */ + dw =3D 0; + dw =3D SETF_VAR(EP_CX_EP_TYPE, dw, ep_type); + dw =3D SETF_VAR(EP_CX_MAX_PACKET_SIZE, dw, maxsize); + dw =3D SETF_VAR(EP_CX_MAX_BURST_SIZE, dw, maxburst); + epcx->dw1 =3D cpu_to_le32(dw); + + /* fill ep_dw2 */ + dw =3D lower_32_bits(udc_ep->tran_ring_info.dma) & EP_CX_TR_DQPT_LO_MASK; + dw =3D SETF_VAR(EP_CX_DEQ_CYC_STATE, dw, udc_ep->pcs); + epcx->dw2 =3D cpu_to_le32(dw); + + /* fill ep_dw3 */ + dw =3D upper_32_bits(udc_ep->tran_ring_info.dma); + epcx->dw3 =3D cpu_to_le32(dw); + /* Ensure that epcx is updated */ + wmb(); +} + +static void crg_udc_epcx_update_dqptr(struct crg_udc_ep *udc_ep) +{ + struct crg_gadget_dev *crg_udc =3D udc_ep->crg_udc; + u8 DCI =3D udc_ep->DCI; + struct ep_cx_s *epcx =3D (struct ep_cx_s *)(crg_udc->p_epcx + DCI - 2); + u32 dw; + dma_addr_t dqptaddr; + u32 cmd_param0; + + if (DCI =3D=3D 0) { + dev_err(crg_udc->dev, "%s Cannot update dqptr for ep0\n", __func__); + return; + } + + dqptaddr =3D tran_trb_virt_to_dma(udc_ep, udc_ep->deq_pt); + + /* fill ep_dw2 */ + dw =3D lower_32_bits(dqptaddr) & EP_CX_TR_DQPT_LO_MASK; + dw =3D SETF_VAR(EP_CX_DEQ_CYC_STATE, dw, udc_ep->pcs); + epcx->dw2 =3D cpu_to_le32(dw); + + /* fill ep_dw3 */ + dw =3D upper_32_bits(dqptaddr); + epcx->dw3 =3D cpu_to_le32(dw); + + cmd_param0 =3D (0x1 << udc_ep->DCI); + /* Ensure that dqptr is updated */ + wmb(); + + crg_issue_command(crg_udc, CRG_CMD_SET_TR_DQPTR, cmd_param0, 0); +} + +static void setup_status_trb(struct crg_gadget_dev *crg_udc, + struct transfer_trb_s *p_trb, + struct usb_request *usb_req, u8 pcs, u8 set_addr, u8 stall) +{ + u32 tmp, dir =3D 0; + + /* There are some cases where seutp_status_trb() is called with + * usb_req set to NULL. + */ + + p_trb->dw0 =3D 0; + p_trb->dw1 =3D 0; + + dev_dbg(crg_udc->dev, "data_buf_ptr_lo =3D 0x%x, data_buf_ptr_hi =3D 0x%x= \n", + p_trb->dw0, p_trb->dw1); + + tmp =3D 0; + tmp =3D SETF_VAR(TRB_INTR_TARGET, tmp, 0); + p_trb->dw2 =3D tmp; + + tmp =3D 0; + tmp =3D SETF_VAR(TRB_CYCLE_BIT, tmp, pcs); + tmp =3D SETF_VAR(TRB_INTR_ON_COMPLETION, tmp, 1);/*IOC:1*/ + tmp =3D SETF_VAR(TRB_TYPE, tmp, TRB_TYPE_XFER_STATUS_STAGE); + + dir =3D (crg_udc->setup_status =3D=3D STATUS_STAGE_XFER) ? 0 : 1; + tmp =3D SETF_VAR(DATA_STAGE_TRB_DIR, tmp, dir); + + tmp =3D SETF_VAR(TRB_SETUP_TAG, tmp, crg_udc->setup_tag); + tmp =3D SETF_VAR(STATUS_STAGE_TRB_STALL, tmp, stall); + tmp =3D SETF_VAR(STATUS_STAGE_TRB_SET_ADDR, tmp, set_addr); + + p_trb->dw3 =3D tmp; + dev_dbg(crg_udc->dev, "trb_dword2 =3D 0x%x, trb_dword3 =3D 0x%x\n", + p_trb->dw2, p_trb->dw3); + /* Ensure that status trb is updated */ + wmb(); +} + +static void knock_doorbell(struct crg_gadget_dev *crg_udc, int DCI) +{ + u32 tmp; + struct crg_uccr *uccr; + + uccr =3D crg_udc->uccr; + /* Ensure evreything is written before notifying the HW */ + wmb(); + + tmp =3D CRG_U3DC_DB_TARGET(DCI); + dev_dbg(crg_udc->dev, "DOORBELL =3D 0x%x\n", tmp); + writel(tmp, &uccr->doorbell); +} + +static void setup_datastage_trb(struct crg_gadget_dev *crg_udc, + struct transfer_trb_s *p_trb, struct usb_request *usb_req, + u8 pcs, u32 num_trb, u32 transfer_length, u32 td_size, + u8 IOC, u8 AZP, u8 dir, u8 setup_tag) +{ + u32 tmp; + + dev_dbg(crg_udc->dev, "dma =3D 0x%llx, ", usb_req->dma); + dev_dbg(crg_udc->dev, "buf =3D 0x%lx, ", (unsigned long)usb_req->buf); + + p_trb->dw0 =3D lower_32_bits(usb_req->dma); + p_trb->dw1 =3D upper_32_bits(usb_req->dma); + + dev_dbg(crg_udc->dev, "data_buf_ptr_lo =3D 0x%x, data_buf_ptr_hi =3D 0x%x= \n", + p_trb->dw0, p_trb->dw1); + + + /* TRB_Transfer_Length + *For USB_DIR_OUT, this field is the number of data bytes expected from + *xhc. For USB_DIR_IN, this field is the number of data bytes the device + *will send. + */ + tmp =3D 0; + tmp =3D SETF_VAR(TRB_TRANSFER_LEN, tmp, transfer_length); + tmp =3D SETF_VAR(TRB_TD_SIZE, tmp, td_size); + tmp =3D SETF_VAR(TRB_INTR_TARGET, tmp, 0); + p_trb->dw2 =3D tmp; + + tmp =3D 0; + tmp =3D SETF_VAR(TRB_CYCLE_BIT, tmp, pcs); + tmp =3D SETF_VAR(TRB_INTR_ON_SHORT_PKT, tmp, 1); + tmp =3D SETF_VAR(TRB_INTR_ON_COMPLETION, tmp, IOC); + tmp =3D SETF_VAR(TRB_TYPE, tmp, TRB_TYPE_XFER_DATA_STAGE); + tmp =3D SETF_VAR(TRB_APPEND_ZLP, tmp, AZP); + tmp =3D SETF_VAR(DATA_STAGE_TRB_DIR, tmp, dir); + tmp =3D SETF_VAR(TRB_SETUP_TAG, tmp, setup_tag); + + p_trb->dw3 =3D tmp; + /* Ensure that datastage trb is updated */ + wmb(); + + dev_dbg(crg_udc->dev, "trb_dword0 =3D 0x%x, trb_dword1 =3D 0x%x trb_dword= 2 =3D 0x%x, trb_dword3 =3D 0x%x\n", + p_trb->dw0, p_trb->dw1, p_trb->dw2, p_trb->dw3); +} + +static void setup_trb(struct crg_gadget_dev *crg_udc, + struct transfer_trb_s *p_trb, + struct usb_request *usb_req, u32 xfer_len, + dma_addr_t xfer_buf_addr, u8 td_size, u8 pcs, + u8 trb_type, u8 short_pkt, u8 chain_bit, + u8 intr_on_compl, bool b_setup_stage, u8 usb_dir, + bool b_isoc, u8 tlb_pc, u16 frame_i_d, u8 SIA, u8 AZP) +{ + u32 tmp; + + p_trb->dw0 =3D lower_32_bits(xfer_buf_addr); + p_trb->dw1 =3D upper_32_bits(xfer_buf_addr); + + dev_dbg(crg_udc->dev, "data_buf_ptr_lo =3D 0x%x, data_buf_ptr_hi =3D 0x%x= \n", + p_trb->dw0, p_trb->dw1); + + tmp =3D 0; + tmp =3D SETF_VAR(TRB_TRANSFER_LEN, tmp, xfer_len); + tmp =3D SETF_VAR(TRB_TD_SIZE, tmp, td_size); + tmp =3D SETF_VAR(TRB_INTR_TARGET, tmp, 0); + + p_trb->dw2 =3D tmp; + + tmp =3D 0; + tmp =3D SETF_VAR(TRB_CYCLE_BIT, tmp, pcs); + tmp =3D SETF_VAR(TRB_INTR_ON_SHORT_PKT, tmp, short_pkt); + tmp =3D SETF_VAR(TRB_CHAIN_BIT, tmp, chain_bit); + tmp =3D SETF_VAR(TRB_INTR_ON_COMPLETION, tmp, intr_on_compl); + tmp =3D SETF_VAR(TRB_APPEND_ZLP, tmp, AZP); + tmp =3D SETF_VAR(TRB_TYPE, tmp, trb_type); + + if (b_setup_stage) + tmp =3D SETF_VAR(DATA_STAGE_TRB_DIR, tmp, usb_dir); + + if (b_isoc) { + tmp =3D SETF_VAR(ISOC_TRB_FRAME_ID, tmp, frame_i_d); + tmp =3D SETF_VAR(ISOC_TRB_SIA, tmp, SIA); + } + + p_trb->dw3 =3D tmp; + /* Ensure that trb is updated */ + wmb(); + dev_dbg(crg_udc->dev, "trb_dword2 =3D 0x%.8x, trb_dword3 =3D 0x%.8x\n", + p_trb->dw2, p_trb->dw3); + +} + +static int crg_udc_queue_trbs(struct crg_udc_ep *udc_ep_ptr, + struct crg_udc_request *udc_req_ptr, bool b_isoc, + u32 xfer_ring_size, + u32 num_trbs_needed, u64 buffer_length) +{ + struct crg_gadget_dev *crg_udc =3D udc_ep_ptr->crg_udc; + struct transfer_trb_s *p_xfer_ring =3D udc_ep_ptr->first_trb; + u32 num_trbs_ava =3D 0; + struct usb_request *usb_req =3D &udc_req_ptr->usb_req; + u64 buff_len_temp =3D 0; + u32 i, j =3D 1; + struct transfer_trb_s *enq_pt =3D udc_ep_ptr->enq_pt; + u8 td_size; + u8 chain_bit =3D 1; + u8 short_pkt =3D 0; + u8 intr_on_compl =3D 0; + u32 count; + bool full_td =3D true; + u32 intr_rate; + dma_addr_t trb_buf_addr; + bool need_zlp =3D false; + struct scatterlist *sg =3D NULL; + u32 num_sgs =3D 0; + u64 sg_addr =3D 0; + + dev_dbg(crg_udc->dev, "%s %s\n", __func__, udc_ep_ptr->usb_ep.name); + if (udc_req_ptr->usb_req.num_sgs) { + num_sgs =3D udc_req_ptr->usb_req.num_sgs; + sg =3D udc_req_ptr->usb_req.sg; + sg_addr =3D (u64) sg_dma_address(sg); + buffer_length =3D sg_dma_len(sg); + + dev_dbg(crg_udc->dev, "num_sgs =3D %d, num_mapped_sgs =3D %d\n", + udc_req_ptr->usb_req.num_sgs, + udc_req_ptr->usb_req.num_mapped_sgs); + dev_dbg(crg_udc->dev, + "sg_addr =3D %p, buffer_length =3D %llu, num_trbs =3D %d\n", + (void *)sg_addr, buffer_length, num_trbs_needed); + } + + if (!b_isoc) { + if (udc_req_ptr->usb_req.zero =3D=3D 1 && + udc_req_ptr->usb_req.length !=3D 0 && + ((udc_req_ptr->usb_req.length % + udc_ep_ptr->usb_ep.maxpacket) =3D=3D 0)) { + need_zlp =3D true; + } + } + + td_size =3D num_trbs_needed; + + num_trbs_ava =3D room_on_ring(crg_udc, xfer_ring_size, + p_xfer_ring, udc_ep_ptr->enq_pt, udc_ep_ptr->deq_pt); + + /* trb_buf_addr points to the addr of the buffer that we write in + * each TRB. If this function is called to complete the pending TRB + * transfers of a previous request, point it to the buffer that is + * not transferred, or else point it to the starting address of the + * buffer received in usb_request + */ + if (udc_req_ptr->trbs_needed) { + /* Here udc_req_ptr->trbs_needed is used to indicate if we + * are completing a previous req + */ + trb_buf_addr =3D usb_req->dma + + (usb_req->length - udc_req_ptr->buff_len_left); + } else { + if (sg_addr) + trb_buf_addr =3D sg_addr; + else + trb_buf_addr =3D usb_req->dma; + } + + if (num_trbs_ava >=3D num_trbs_needed) { + count =3D num_trbs_needed; + } else { + if (b_isoc) { + struct crg_udc_request *udc_req_ptr_temp; + u8 temp =3D 0; + + list_for_each_entry(udc_req_ptr_temp, + &udc_ep_ptr->queue, queue) { + temp++; + } + + if (temp >=3D 2) { + dev_err(crg_udc->dev, "%s don't do isoc discard\n", __func__); + /* we already scheduled two mfi in advance. */ + return 0; + } + } + + /* always keep one trb for zlp. */ + count =3D num_trbs_ava; + full_td =3D false; + dev_dbg(crg_udc->dev, "TRB Ring Full. Avail: 0x%x Req: 0x%x\n", + num_trbs_ava, num_trbs_needed); + udc_ep_ptr->tran_ring_full =3D true; + + /*if there is still some trb not queued, + *it means last queued + *trb is not the last trb of TD, so no need zlp + */ + need_zlp =3D false; + } + + for (i =3D 0; i < count; i++) { + if ((udc_req_ptr->usb_req.num_sgs) && (buffer_length =3D=3D 0)) { + sg =3D sg_next(sg); + if (sg) { + trb_buf_addr =3D (u64) sg_dma_address(sg); + buffer_length =3D sg_dma_len(sg); + dev_dbg(crg_udc->dev, + "trb_buf_addr =3D %p, num_trbs =3D %d\n", + (void *)trb_buf_addr, num_trbs_needed); + dev_dbg(crg_udc->dev, "buffer_length =3D %llu\n", + buffer_length); + } else { + dev_err(crg_udc->dev, + "scatterlist ended unexpectedly (i=3D%d, count=3D%d)\n", + i, count); + return -EINVAL; + } + } + + if (buffer_length > TRB_MAX_BUFFER_SIZE) + buff_len_temp =3D TRB_MAX_BUFFER_SIZE; + else + buff_len_temp =3D buffer_length; + + buffer_length -=3D buff_len_temp; + + if (usb_endpoint_dir_out(udc_ep_ptr->desc)) + short_pkt =3D 1; + + if ((buffer_length =3D=3D 0) && (i =3D=3D (count - 1))) { + chain_bit =3D 0; + intr_on_compl =3D 1; + udc_req_ptr->all_trbs_queued =3D 1; + } + + +#define BULK_EP_INTERRUPT_RATE 5 +#define ISOC_EP_INTERRUPT_RATE 1 + if (b_isoc) + intr_rate =3D ISOC_EP_INTERRUPT_RATE; + else + intr_rate =3D BULK_EP_INTERRUPT_RATE; + + if (!full_td && j =3D=3D intr_rate) { + intr_on_compl =3D 1; + j =3D 0; + } + + if (b_isoc) { + setup_trb(crg_udc, enq_pt, usb_req, buff_len_temp, + trb_buf_addr, td_size - 1, udc_ep_ptr->pcs, + TRB_TYPE_XFER_DATA_ISOCH, short_pkt, chain_bit, + intr_on_compl, 0, 0, 1, 0, 0, 1, 0); + } else { + u8 pcs =3D udc_ep_ptr->pcs; + + if (udc_ep_ptr->comp_desc && + (usb_ss_max_streams(udc_ep_ptr->comp_desc))) { + dev_err(crg_udc->dev, "%s don't do bulk stream\n", __func__); + } else { + if (udc_req_ptr->all_trbs_queued) { + /*it is the last trb of TD, + * so consider zlp + */ + u8 AZP =3D 0; + + AZP =3D (need_zlp ? 1 : 0); + + setup_trb(crg_udc, enq_pt, usb_req, + buff_len_temp, trb_buf_addr, + td_size - 1, pcs, + TRB_TYPE_XFER_NORMAL, short_pkt, + chain_bit, intr_on_compl, + 0, 0, 0, 0, 0, 0, AZP); + + } else { + setup_trb(crg_udc, enq_pt, usb_req, + buff_len_temp, trb_buf_addr, + td_size - 1, pcs, + TRB_TYPE_XFER_NORMAL, short_pkt, + chain_bit, intr_on_compl, + 0, 0, 0, 0, 0, 0, 0); + } + } + } + trb_buf_addr +=3D buff_len_temp; + td_size--; + enq_pt++; + j++; + if (GETF(TRB_TYPE, enq_pt->dw3) =3D=3D TRB_TYPE_LINK) { + if (GETF(TRB_LINK_TOGGLE_CYCLE, + enq_pt->dw3)) { + enq_pt->dw3 =3D SETF_VAR(TRB_CYCLE_BIT, + enq_pt->dw3, udc_ep_ptr->pcs); + udc_ep_ptr->pcs ^=3D 0x1; + /* Ensure that trb cycle bit is updated */ + wmb(); + enq_pt =3D udc_ep_ptr->first_trb; + } + } + } + + if (!udc_req_ptr->trbs_needed) + udc_req_ptr->first_trb =3D udc_ep_ptr->enq_pt; + udc_ep_ptr->enq_pt =3D enq_pt; + udc_req_ptr->buff_len_left =3D buffer_length; + udc_req_ptr->trbs_needed =3D td_size; + + if (udc_req_ptr->buff_len_left =3D=3D 0) { + /* It is actually last trb of a request plus 1 */ + if (udc_ep_ptr->enq_pt =3D=3D udc_ep_ptr->first_trb) + udc_req_ptr->last_trb =3D udc_ep_ptr->last_trb - 1; + else + udc_req_ptr->last_trb =3D udc_ep_ptr->enq_pt - 1; + } + + return 0; +} + +static int crg_udc_queue_ctrl(struct crg_udc_ep *udc_ep_ptr, + struct crg_udc_request *udc_req_ptr, u32 num_of_trbs_needed) +{ + struct crg_gadget_dev *crg_udc =3D udc_ep_ptr->crg_udc; + u8 ep_state; + struct transfer_trb_s *enq_pt =3D udc_ep_ptr->enq_pt; + struct transfer_trb_s *dq_pt =3D udc_ep_ptr->deq_pt; + struct usb_request *usb_req =3D &udc_req_ptr->usb_req; + struct transfer_trb_s *p_trb; + u32 transfer_length; + u32 td_size =3D 0; + u8 IOC; + u8 AZP; + u8 dir =3D 0; + u8 setup_tag =3D crg_udc->setup_tag; + + ep_state =3D get_ep_state(crg_udc, 0); + + + /* Need to queue the request even ep is paused or halted */ + if (ep_state !=3D EP_STATE_RUNNING) { + dev_dbg(crg_udc->dev, "EP State =3D 0x%x\n", ep_state); + return -EINVAL; + } + + if (list_empty(&udc_ep_ptr->queue)) { + /* For control endpoint, we can handle one setup request at a + * time. so if there are TD pending in the transfer ring. + * wait for the sequence number error event. Then put the new + * request to transfer ring + */ + if (enq_pt =3D=3D dq_pt) { + u32 tmp =3D 0, i; + bool need_zlp =3D false; + + dev_dbg(crg_udc->dev, "Setup Data Stage TRBs\n"); + /* Transfer ring is empty + * setup data stage TRBs + */ + udc_req_ptr->first_trb =3D udc_ep_ptr->enq_pt; + + if (crg_udc->setup_status =3D=3D DATA_STAGE_XFER) + dir =3D 0; + else if (crg_udc->setup_status =3D=3D DATA_STAGE_RECV) + dir =3D 1; + else + dev_dbg(crg_udc->dev, "unexpected setup_status!%d\n", + crg_udc->setup_status); + + if (udc_req_ptr->usb_req.zero =3D=3D 1 && + udc_req_ptr->usb_req.length !=3D 0 && + ((udc_req_ptr->usb_req.length % + udc_ep_ptr->usb_ep.maxpacket) =3D=3D 0)) + need_zlp =3D true;/*zlp =3D zero length packet*/ + + + for (i =3D 0; i < num_of_trbs_needed; i++) { + p_trb =3D enq_pt; + if (i < (num_of_trbs_needed - 1)) { + transfer_length =3D TRB_MAX_BUFFER_SIZE; + IOC =3D 0; + AZP =3D 0; + } else { + tmp =3D TRB_MAX_BUFFER_SIZE * i; + transfer_length =3D (u32)usb_req->length + - tmp; + + IOC =3D 1; + AZP =3D (need_zlp ? 1 : 0); + } + + dev_dbg(crg_udc->dev, + "tx_len =3D 0x%x, tmp =3D 0x%x\n", + transfer_length, tmp); + + setup_datastage_trb(crg_udc, p_trb, usb_req, + udc_ep_ptr->pcs, i, transfer_length, + td_size, IOC, AZP, dir, setup_tag); + udc_req_ptr->all_trbs_queued =3D 1; + enq_pt++; + + if (GETF(TRB_TYPE, enq_pt->dw3) =3D=3D + TRB_TYPE_LINK) { + if (GETF(TRB_LINK_TOGGLE_CYCLE, + enq_pt->dw3)) { + enq_pt->dw3 =3D SETF_VAR(TRB_CYCLE_BIT, + enq_pt->dw3, + udc_ep_ptr->pcs); + udc_ep_ptr->pcs ^=3D 0x1; + } + /* Ensure that trb cycle bit is updated */ + wmb(); + enq_pt =3D udc_ep_ptr->first_trb; + } + } + + udc_ep_ptr->enq_pt =3D enq_pt; + + tmp =3D 0; + + knock_doorbell(crg_udc, 0); + + if (udc_ep_ptr->enq_pt =3D=3D udc_ep_ptr->first_trb) + udc_req_ptr->last_trb =3D + udc_ep_ptr->last_trb - 1; + else + udc_req_ptr->last_trb =3D udc_ep_ptr->enq_pt - 1; + } else { + /* we process one setup request at a time, so ring + * should already be empty. + */ + dev_err(crg_udc->dev, "Eq =3D 0x%p !=3D Dq =3D 0x%p\n", + enq_pt, dq_pt); + } + } else { + dev_err(crg_udc->dev, "udc_ep_ptr->queue not empty\n"); + /* New setup packet came + * Drop the this req.. + */ + return -EINVAL; + } + + return 0; +} + +static void build_ep0_status(struct crg_udc_ep *udc_ep_ptr, + bool default_value, u32 status, + struct crg_udc_request *udc_req_ptr, u8 set_addr, u8 stall) +{ + struct crg_gadget_dev *crg_udc =3D udc_ep_ptr->crg_udc; + struct transfer_trb_s *enq_pt =3D udc_ep_ptr->enq_pt; + + if (default_value) { + udc_req_ptr =3D crg_udc->status_req; + udc_req_ptr->usb_req.length =3D 0; + udc_req_ptr->usb_req.status =3D status; + udc_req_ptr->usb_req.actual =3D 0; + udc_req_ptr->usb_req.complete =3D NULL; + } else { + udc_req_ptr->usb_req.status =3D status; + udc_req_ptr->usb_req.actual =3D 0; + } + + setup_status_trb(crg_udc, enq_pt, &udc_req_ptr->usb_req, + udc_ep_ptr->pcs, set_addr, stall); + + enq_pt++; + + /* check if we are at end of trb segment. If so, update + * pcs and enq for next segment + */ + if (GETF(TRB_TYPE, enq_pt->dw3) =3D=3D TRB_TYPE_LINK) { + if (GETF(TRB_LINK_TOGGLE_CYCLE, enq_pt->dw3)) { + enq_pt->dw3 =3D SETF_VAR + (TRB_CYCLE_BIT, enq_pt->dw3, udc_ep_ptr->pcs); + udc_ep_ptr->pcs ^=3D 0x1; + } + enq_pt =3D udc_ep_ptr->first_trb; + } + udc_ep_ptr->enq_pt =3D enq_pt; + + knock_doorbell(crg_udc, 0); + + list_add_tail(&udc_req_ptr->queue, &udc_ep_ptr->queue); +} + +static void ep0_req_complete(struct crg_udc_ep *udc_ep_ptr) +{ + struct crg_gadget_dev *crg_udc =3D udc_ep_ptr->crg_udc; + + switch (crg_udc->setup_status) { + case DATA_STAGE_XFER: + crg_udc->setup_status =3D STATUS_STAGE_RECV; + build_ep0_status(udc_ep_ptr, true, -EINPROGRESS, NULL, 0, 0); + break; + case DATA_STAGE_RECV: + crg_udc->setup_status =3D STATUS_STAGE_XFER; + build_ep0_status(udc_ep_ptr, true, -EINPROGRESS, NULL, 0, 0); + break; + default: + if (crg_udc->setup_fn_call_back) + crg_udc->setup_fn_call_back(crg_udc); + + crg_udc->setup_status =3D WAIT_FOR_SETUP; + break; + } +} + +static void handle_cmpl_code_success(struct crg_gadget_dev *crg_udc, + struct event_trb_s *event, struct crg_udc_ep *udc_ep_ptr) +{ + u64 trb_pt; + struct transfer_trb_s *p_trb; + struct crg_udc_request *udc_req_ptr; + u32 trb_transfer_length; + + trb_pt =3D (u64)event->dw0 + ((u64)(event->dw1) << 32); + p_trb =3D tran_trb_dma_to_virt(udc_ep_ptr, trb_pt); + + dev_dbg(crg_udc->dev, "trb_pt =3D 0x%lx, p_trb =3D 0x%p\n", (unsigned lon= g)trb_pt, p_trb); + dev_dbg(crg_udc->dev, "trb dw0 =3D 0x%x\n", p_trb->dw0); + dev_dbg(crg_udc->dev, "trb dw1 =3D 0x%x\n", p_trb->dw1); + dev_dbg(crg_udc->dev, "trb dw2 =3D 0x%x\n", p_trb->dw2); + dev_dbg(crg_udc->dev, "trb dw3 =3D 0x%x\n", p_trb->dw3); + + if (!GETF(TRB_CHAIN_BIT, p_trb->dw3)) { + /* chain bit is not set, which means it + * is the end of a TD + */ + udc_req_ptr =3D list_entry(udc_ep_ptr->queue.next, + struct crg_udc_request, queue); + + dev_dbg(crg_udc->dev, "udc_req_ptr =3D 0x%p\n", udc_req_ptr); + + trb_transfer_length =3D GETF(EVE_TRB_TRAN_LEN, + event->dw2); + udc_req_ptr->usb_req.actual =3D udc_req_ptr->usb_req.length - + trb_transfer_length; + dev_dbg(crg_udc->dev, "Actual data xfer =3D 0x%x, tx_len =3D 0x%x\n", + udc_req_ptr->usb_req.actual, trb_transfer_length); + + dev_dbg(crg_udc->dev, "udc_req_ptr->usb_req.buf =3D 0x%p\n", + udc_req_ptr->usb_req.buf); + /* Ensure that req_ptr is updated */ + wmb(); + req_done(udc_ep_ptr, udc_req_ptr, 0); + if (!udc_ep_ptr->desc) { + dev_dbg(crg_udc->dev, "udc_ep_ptr->desc is NULL\n"); + } else { + if (usb_endpoint_xfer_control(udc_ep_ptr->desc)) + ep0_req_complete(udc_ep_ptr); + } + } +} + +static void update_dequeue_pt(struct event_trb_s *event, + struct crg_udc_ep *udc_ep) +{ + u32 deq_pt_lo =3D event->dw0; + u32 deq_pt_hi =3D event->dw1; + u64 dq_pt_addr =3D (u64)deq_pt_lo + ((u64)deq_pt_hi << 32); + struct transfer_trb_s *deq_pt; + + deq_pt =3D tran_trb_dma_to_virt(udc_ep, dq_pt_addr); + deq_pt++; + + if (GETF(TRB_TYPE, deq_pt->dw3) =3D=3D TRB_TYPE_LINK) + deq_pt =3D udc_ep->first_trb; + + udc_ep->deq_pt =3D deq_pt; +} + +static void advance_dequeue_pt(struct crg_udc_ep *udc_ep) +{ + struct crg_udc_request *udc_req; + + if (!list_empty(&udc_ep->queue)) { + udc_req =3D list_entry(udc_ep->queue.next, + struct crg_udc_request, + queue); + + if (udc_req->first_trb) + udc_ep->deq_pt =3D udc_req->first_trb; + else + udc_ep->deq_pt =3D udc_ep->enq_pt; + } else + udc_ep->deq_pt =3D udc_ep->enq_pt; +} + +static bool is_request_dequeued(struct crg_gadget_dev *crg_udc, + struct crg_udc_ep *udc_ep, struct event_trb_s *event) +{ + struct crg_udc_request *udc_req; + u32 trb_pt_lo =3D event->dw0; + u32 trb_pt_hi =3D event->dw1; + u64 trb_addr =3D (u64)trb_pt_lo + ((u64)trb_pt_hi << 32); + struct transfer_trb_s *trb_pt; + bool status =3D true; + + if (udc_ep->DCI =3D=3D 0) + return false; + + trb_pt =3D tran_trb_dma_to_virt(udc_ep, trb_addr); + list_for_each_entry(udc_req, &udc_ep->queue, queue) { + if (trb_pt =3D=3D udc_req->last_trb || + trb_pt =3D=3D udc_req->first_trb) { + status =3D false; + break; + } + + if (is_pointer_less_than(trb_pt, udc_req->last_trb, udc_ep) && + is_pointer_less_than(udc_req->first_trb, trb_pt, + udc_ep)) { + status =3D false; + break; + } + } + + return status; +} + +static unsigned int count_trbs(u64 addr, u64 len) +{ + unsigned int num_trbs; + + num_trbs =3D DIV_ROUND_UP(len + (addr & (TRB_MAX_BUFFER_SIZE - 1)), + TRB_MAX_BUFFER_SIZE); + if (num_trbs =3D=3D 0) + num_trbs++; + + return num_trbs; +} + +static unsigned int count_sg_trbs_needed(struct usb_request *usb_req) +{ + struct scatterlist *sg; + unsigned int i, len, full_len, num_trbs =3D 0; + + full_len =3D usb_req->length; + + for_each_sg(usb_req->sg, sg, usb_req->num_mapped_sgs, i) { + len =3D sg_dma_len(sg); + num_trbs +=3D count_trbs(sg_dma_address(sg), len); + len =3D min_t(unsigned int, len, full_len); + full_len -=3D len; + if (full_len =3D=3D 0) + break; + } + + return num_trbs; +} + + +static int crg_udc_build_td(struct crg_udc_ep *udc_ep_ptr, + struct crg_udc_request *udc_req_ptr) +{ + int status =3D 0; + struct crg_gadget_dev *crg_udc =3D udc_ep_ptr->crg_udc; + u32 num_trbs_needed; + u64 buffer_length; + u32 tmp; + + dev_dbg(crg_udc->dev, "udc_req buf =3D 0x%p\n", udc_req_ptr->usb_req.buf); + + if (udc_req_ptr->trbs_needed) { + /* If this is called to complete pending TRB transfers + * of previous Request + */ + buffer_length =3D udc_req_ptr->buff_len_left; + num_trbs_needed =3D udc_req_ptr->trbs_needed; + } else { + buffer_length =3D (u64)udc_req_ptr->usb_req.length; + + if (udc_req_ptr->usb_req.num_sgs) + num_trbs_needed =3D count_sg_trbs_needed(&udc_req_ptr->usb_req); + else { + num_trbs_needed =3D (u32)(buffer_length / TRB_MAX_BUFFER_SIZE); + + if (buffer_length =3D=3D 0 || + (buffer_length % TRB_MAX_BUFFER_SIZE)) + num_trbs_needed +=3D 1; + } + } + + dev_dbg(crg_udc->dev, "buf_len =3D %ld, num_trb_needed =3D %d\n", + (unsigned long)buffer_length, num_trbs_needed); + + if (usb_endpoint_xfer_control(udc_ep_ptr->desc)) { + dev_dbg(crg_udc->dev, "crg_udc_queue_ctrl control\n"); + status =3D crg_udc_queue_ctrl(udc_ep_ptr, + udc_req_ptr, num_trbs_needed); + } else if (usb_endpoint_xfer_isoc(udc_ep_ptr->desc)) { + dev_dbg(crg_udc->dev, "crg_udc_queue_trbs isoc\n"); + status =3D crg_udc_queue_trbs(udc_ep_ptr, udc_req_ptr, 1, + CRGUDC_ISOC_EP_TD_RING_SIZE, + num_trbs_needed, buffer_length); + + tmp =3D udc_ep_ptr->DCI; + tmp =3D CRG_U3DC_DB_TARGET(tmp); + dev_dbg(crg_udc->dev, "DOORBELL =3D 0x%x\n", tmp); + + knock_doorbell(crg_udc, udc_ep_ptr->DCI); + } else if (usb_endpoint_xfer_bulk(udc_ep_ptr->desc)) { + dev_dbg(crg_udc->dev, "crg_udc_queue_trbs bulk\n"); + status =3D crg_udc_queue_trbs(udc_ep_ptr, udc_req_ptr, 0, + CRGUDC_BULK_EP_TD_RING_SIZE, + num_trbs_needed, buffer_length); + tmp =3D udc_ep_ptr->DCI; + tmp =3D CRG_U3DC_DB_TARGET(tmp); + if (udc_ep_ptr->comp_desc && + usb_ss_max_streams(udc_ep_ptr->comp_desc)) { + /* hold the doorbell if stream_rejected is set */ + dev_err(crg_udc->dev, "%s, WANT TO have bulk stream\n", __func__); + } + + knock_doorbell(crg_udc, udc_ep_ptr->DCI); + } else { + /* interrupt endpoint */ + status =3D crg_udc_queue_trbs(udc_ep_ptr, udc_req_ptr, 0, + CRGUDC_INT_EP_TD_RING_SIZE, + num_trbs_needed, buffer_length); + tmp =3D udc_ep_ptr->DCI; + tmp =3D CRG_U3DC_DB_TARGET(tmp); + + knock_doorbell(crg_udc, udc_ep_ptr->DCI); + } + + return status; +} + +/* This function will go through the list of the USB requests for the + * given endpoint and schedule any unscheduled trb's to the xfer ring + */ +static void queue_pending_trbs(struct crg_udc_ep *udc_ep_ptr) +{ + struct crg_udc_request *udc_req_ptr; + /* schedule trbs till there arent any pending unscheduled ones + * or the ring is full again + */ + + list_for_each_entry(udc_req_ptr, &udc_ep_ptr->queue, queue) { + if (udc_req_ptr->all_trbs_queued =3D=3D 0) + crg_udc_build_td(udc_ep_ptr, udc_req_ptr); + + if (udc_ep_ptr->tran_ring_full) + break; + } +} + +static void squeeze_xfer_ring(struct crg_udc_ep *udc_ep_ptr, + struct crg_udc_request *udc_req_ptr) +{ + struct transfer_trb_s *temp =3D udc_req_ptr->first_trb; + struct crg_udc_request *next_req; + + /* All the incompleted Requests are recorded in crg_udc_ep.queue by SW*/ + /* 1. Clear all the queued-in-ring trbs from the deleted point */ + /* 2. Re-queue in ring the Requests that are after the deleted Request*/ + while (temp !=3D udc_ep_ptr->enq_pt) { + temp->dw0 =3D 0; + temp->dw1 =3D 0; + temp->dw2 =3D 0; + temp->dw3 =3D 0; + + temp++; + + if (GETF(TRB_TYPE, temp->dw3) =3D=3D TRB_TYPE_LINK) + temp =3D udc_ep_ptr->first_trb; + } + + /* Update the new enq_ptr starting from the deleted req */ + udc_ep_ptr->enq_pt =3D udc_req_ptr->first_trb; + + if (udc_ep_ptr->tran_ring_full) + udc_ep_ptr->tran_ring_full =3D false; + + next_req =3D list_entry(udc_req_ptr->queue.next, + struct crg_udc_request, queue); + + list_for_each_entry_from(next_req, &udc_ep_ptr->queue, queue) { + next_req->usb_req.status =3D -EINPROGRESS; + next_req->usb_req.actual =3D 0; + + /* clear the values of the nv_udc_request container **/ + clear_req_container(next_req); + + if (udc_ep_ptr->tran_ring_full) + break; + + /* push the request to the transfer ring */ + crg_udc_build_td(udc_ep_ptr, next_req); + } +} + +static int set_ep0_halt(struct crg_gadget_dev *crg_udc) +{ + struct crg_udc_ep *udc_ep_ptr =3D &crg_udc->udc_ep[0]; + int ep_state; + + ep_state =3D get_ep_state(crg_udc, udc_ep_ptr->DCI); + if (ep_state =3D=3D EP_STATE_HALTED || + ep_state =3D=3D EP_STATE_DISABLED) { + return 0; + } + + build_ep0_status(udc_ep_ptr, true, -EINVAL, NULL, 0, 1); + + udc_ep_ptr->ep_state =3D EP_STATE_HALTED; + + return 0; +} + +static int set_ep_halt(struct crg_gadget_dev *crg_udc, int DCI) +{ + struct crg_uccr *uccr =3D crg_udc->uccr; + struct crg_udc_ep *udc_ep_ptr =3D &crg_udc->udc_ep[DCI]; + u32 param0; + u32 tmp; + + dev_dbg(crg_udc->dev, "%s DCI=3D%d !!\n", __func__, DCI); + + if (DCI =3D=3D 0) + return 0; + + if (udc_ep_ptr->ep_state =3D=3D EP_STATE_DISABLED || + udc_ep_ptr->ep_state =3D=3D EP_STATE_HALTED) + return 0; + + param0 =3D (0x1 << DCI); + crg_issue_command(crg_udc, CRG_CMD_SET_HALT, param0, 0); + do { + tmp =3D readl(&uccr->ep_running); + } while ((tmp & param0) !=3D 0); + + /* clean up the request queue */ + nuke(udc_ep_ptr, -ECONNRESET); + + udc_ep_ptr->deq_pt =3D udc_ep_ptr->enq_pt; + udc_ep_ptr->tran_ring_full =3D false; + udc_ep_ptr->ep_state =3D EP_STATE_HALTED; + + return 0; +} + +static int ep_halt(struct crg_udc_ep *udc_ep_ptr, + int halt, int ignore_wedge) +{ + struct crg_gadget_dev *crg_udc =3D udc_ep_ptr->crg_udc; + struct crg_uccr *uccr =3D crg_udc->uccr; + int ep_state; + bool reset_seq_only =3D false; + int do_halt; + u32 param0; + u32 tmp; + struct crg_udc_request *udc_req_ptr; + + if (!udc_ep_ptr->desc) { + dev_err(crg_udc->dev, "NULL desc\n"); + return -EINVAL; + } + + if (udc_ep_ptr->desc->bmAttributes =3D=3D USB_ENDPOINT_XFER_ISOC) { + dev_err(crg_udc->dev, "Isoc ep, halt not supported\n"); + return -EOPNOTSUPP; + } + + if (udc_ep_ptr->DCI =3D=3D 0) + return 0; + + ep_state =3D get_ep_state(crg_udc, udc_ep_ptr->DCI); + + if (ep_state =3D=3D EP_STATE_DISABLED) + return 0; + + if (ep_state =3D=3D EP_STATE_HALTED) { + if (halt !=3D 0) + return 0; + + /* want unhalt an halted ep */ + if (udc_ep_ptr->wedge && !ignore_wedge) { + do_halt =3D -1; + reset_seq_only =3D true; + } else { + do_halt =3D 0; + } + + } else { + /* ep state =3D=3D running or stopped */ + if (halt !=3D 0) { + /* want halt a running ep */ + do_halt =3D 1; + } else { + /* reset a running ep */ + do_halt =3D 0; + reset_seq_only =3D true; + } + } + + param0 =3D (0x1 << udc_ep_ptr->DCI); + if (do_halt =3D=3D 1) { + /* setting ep to halt */ + dev_dbg(crg_udc->dev, "HALT EP DCI =3D %d\n", udc_ep_ptr->DCI); + crg_issue_command(crg_udc, CRG_CMD_SET_HALT, param0, 0); + do { + tmp =3D readl(&uccr->ep_running); + } while ((tmp & param0) !=3D 0); + + if (crg_udc->gadget.speed >=3D USB_SPEED_SUPER) { + /* clean up the request queue */ + nuke(udc_ep_ptr, -ECONNRESET); + + udc_ep_ptr->deq_pt =3D udc_ep_ptr->enq_pt; + udc_ep_ptr->tran_ring_full =3D false; + + dev_dbg(crg_udc->dev, "update deq_pt tp enq_pt 0x%p\n", + udc_ep_ptr->deq_pt); + } + /* clean up the request queue */ + udc_ep_ptr->ep_state =3D EP_STATE_HALTED; + } else if (do_halt =3D=3D 0) { + /* clearing ep halt state */ + dev_dbg(crg_udc->dev, "Clear EP HALT DCI =3D %d\n", udc_ep_ptr->DCI); + /* reset sequence number */ + crg_issue_command(crg_udc, CRG_CMD_RESET_SEQNUM, param0, 0); + + if (!reset_seq_only) { + /* Clear halt for a halted EP.*/ + /* NOTE: we must CLEAR_HALT first, then SET_TR_DQPTR*/ + crg_issue_command(crg_udc, + CRG_CMD_CLEAR_HALT, param0, 0); + crg_udc_epcx_update_dqptr(udc_ep_ptr); + + dev_dbg(crg_udc->dev, + "crg_udc_epcx_update_dqptr , PCS =3D %d\n", + udc_ep_ptr->pcs); + } + + udc_ep_ptr->wedge =3D 0; + udc_ep_ptr->ep_state =3D EP_STATE_RUNNING; + /* set endpoint to running state */ + /* clear pause for the endpoint */ + if (!list_empty(&udc_ep_ptr->queue)) { + tmp =3D udc_ep_ptr->DCI; + tmp =3D CRG_U3DC_DB_TARGET(tmp); + + list_for_each_entry(udc_req_ptr, &udc_ep_ptr->queue, + queue) { + struct transfer_trb_s *tmp_ptr =3D + udc_ep_ptr->deq_pt; + + tmp_ptr--; + tmp_ptr =3D udc_ep_ptr->deq_pt + 1; + if (GETF(TRB_TYPE, tmp_ptr->dw3) =3D=3D TRB_TYPE_LINK) { + udc_ep_ptr->pcs ^=3D 0x1; + crg_udc_epcx_update_dqptr(udc_ep_ptr); + udc_ep_ptr->pcs ^=3D 0x1; + } + } + knock_doorbell(crg_udc, udc_ep_ptr->DCI); + } + } else { + /* wedged EP deny CLEAR HALT */ + dev_dbg(crg_udc->dev, "wedged EP deny CLEAR HALT DCI =3D %d\n", udc_ep_p= tr->DCI); + /* reset sequence number */ + if (reset_seq_only) + crg_issue_command(crg_udc, + CRG_CMD_RESET_SEQNUM, param0, 0); + } + + return 0; +} + +/************ep related ops*******************************/ +static int crg_udc_ep_disable(struct usb_ep *ep) +{ + struct crg_udc_ep *udc_ep; + struct crg_gadget_dev *crg_udc; + struct ep_cx_s *p_ep_cx; + int ep_state; + struct crg_uccr *uccr; + unsigned long flags =3D 0; + + if (!ep) + return -EINVAL; + + udc_ep =3D container_of(ep, struct crg_udc_ep, usb_ep); + crg_udc =3D udc_ep->crg_udc; + + if (udc_ep->DCI =3D=3D 0) + return 0; + + spin_lock_irqsave(&crg_udc->udc_lock, flags); + + uccr =3D crg_udc->uccr; + p_ep_cx =3D (struct ep_cx_s *)crg_udc->p_epcx + udc_ep->DCI - 2; + + ep_state =3D get_ep_state(crg_udc, udc_ep->DCI); + if (ep_state =3D=3D EP_STATE_DISABLED) { + /* get here if ep is already disabled */ + spin_unlock_irqrestore(&crg_udc->udc_lock, flags); + return -EINVAL; + } + + dev_dbg(crg_udc->dev, "EPDCI =3D 0x%x\n", udc_ep->DCI); + + /*Maybe we need to halt ep before ep disable*/ + + writel(0x1 << udc_ep->DCI, &uccr->ep_enable); + + /* clean up the request queue */ + nuke(udc_ep, -ESHUTDOWN); + + /* decrement ep counters */ + crg_udc->num_enabled_eps--; + + udc_ep->desc =3D NULL; + + /* clean up the endpoint context */ + memset(p_ep_cx, 0, sizeof(struct ep_cx_s)); + + dev_dbg(crg_udc->dev, "num_enabled_eps =3D %d\n", crg_udc->num_enabled_ep= s); + + /* If device state was changed to default by port + * reset, should not overwrite it again + */ + if (crg_udc->num_enabled_eps =3D=3D 0 && + crg_udc->device_state =3D=3D USB_STATE_CONFIGURED) { + dev_dbg(crg_udc->dev, "Device State USB_STATE_CONFIGURED\n"); + dev_dbg(crg_udc->dev, "Set Device State to addressed\n"); + crg_udc->device_state =3D USB_STATE_ADDRESS; + + } + + udc_ep->ep_state =3D EP_STATE_DISABLED; + + spin_unlock_irqrestore(&crg_udc->udc_lock, flags); + + return 0; +} + +static int crg_udc_ep_enable(struct usb_ep *ep, + const struct usb_endpoint_descriptor *desc) +{ + struct crg_udc_ep *udc_ep; + struct crg_gadget_dev *crg_udc; + u32 param0; + unsigned long flags =3D 0; + struct ep_cx_s *epcx; + struct crg_uccr *uccr; + + if (!ep || !desc || desc->bDescriptorType !=3D USB_DT_ENDPOINT) + return -EINVAL; + + udc_ep =3D container_of(ep, struct crg_udc_ep, usb_ep); + + /*ep0 is always running*/ + if (udc_ep->DCI =3D=3D 0) + return 0; + + crg_udc =3D udc_ep->crg_udc; + uccr =3D crg_udc->uccr; + + if (!crg_udc->gadget_driver) + return -ESHUTDOWN; + + dev_dbg(crg_udc->dev, "%s DCI =3D %d\n", __func__, udc_ep->DCI); + spin_lock_irqsave(&crg_udc->udc_lock, flags); + + /*crg ep context start from ep1*/ + if (get_ep_state(crg_udc, udc_ep->DCI) !=3D EP_STATE_DISABLED) { + dev_dbg(crg_udc->dev, "%s disable first\n", __func__); + spin_unlock_irqrestore(&crg_udc->udc_lock, flags); + crg_udc_ep_disable(ep); + spin_lock_irqsave(&crg_udc->udc_lock, flags); + } + + udc_ep->desc =3D desc; + udc_ep->comp_desc =3D ep->comp_desc; + + /* setup endpoint context for regular endpoint + * the endpoint context for control endpoint has been + * setted up in probe function + */ + if (udc_ep->DCI) { + dev_dbg(crg_udc->dev, "ep_enable udc_ep->DCI =3D %d\n", udc_ep->DCI); + + /* setup transfer ring */ + if (!udc_ep->tran_ring_info.vaddr) { + dma_addr_t dma; + u32 ring_size =3D 0; + void *vaddr; + size_t len; + + if (usb_endpoint_xfer_bulk(desc)) + ring_size =3D CRGUDC_BULK_EP_TD_RING_SIZE; + else if (usb_endpoint_xfer_isoc(desc)) + ring_size =3D CRGUDC_ISOC_EP_TD_RING_SIZE; + else if (usb_endpoint_xfer_int(desc)) + ring_size =3D CRGUDC_INT_EP_TD_RING_SIZE; + len =3D ring_size * sizeof(struct transfer_trb_s); + spin_unlock_irqrestore(&crg_udc->udc_lock, flags); + vaddr =3D dma_alloc_coherent(crg_udc->dev, len, + &dma, GFP_ATOMIC); + if (!vaddr) + return -ENOMEM; + spin_lock_irqsave(&crg_udc->udc_lock, flags); + + udc_ep->tran_ring_info.vaddr =3D vaddr; + udc_ep->tran_ring_info.dma =3D dma; + udc_ep->tran_ring_info.len =3D len; + udc_ep->first_trb =3D vaddr; + udc_ep->last_trb =3D udc_ep->first_trb + ring_size - 1; + } + memset(udc_ep->first_trb, 0, udc_ep->tran_ring_info.len); + /* Ensure that transfer ring is updated */ + wmb(); + setup_link_trb(udc_ep->last_trb, true, + udc_ep->tran_ring_info.dma); + + udc_ep->enq_pt =3D udc_ep->first_trb; + udc_ep->deq_pt =3D udc_ep->first_trb; + udc_ep->pcs =3D 1; + udc_ep->tran_ring_full =3D false; + crg_udc->num_enabled_eps++; + crg_udc_epcx_setup(udc_ep); + } + + dev_dbg(crg_udc->dev, "num_enabled_eps =3D %d\n", crg_udc->num_enabled_ep= s); + + epcx =3D (struct ep_cx_s *)(crg_udc->p_epcx + udc_ep->DCI - 2); + + param0 =3D (0x1 << udc_ep->DCI); + crg_issue_command(crg_udc, CRG_CMD_CONFIG_EP, param0, 0); + + dev_dbg(crg_udc->dev, "config ep and start, DCI=3D%d\n", udc_ep->DCI); + if (crg_udc->device_state =3D=3D USB_STATE_ADDRESS) + crg_udc->device_state =3D USB_STATE_CONFIGURED; + + udc_ep->wedge =3D 0; + udc_ep->ep_state =3D EP_STATE_RUNNING; + + spin_unlock_irqrestore(&crg_udc->udc_lock, flags); + + return 0; +} + +static struct usb_request * +crg_udc_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) +{ + struct crg_udc_request *udc_req_ptr =3D NULL; + + udc_req_ptr =3D kzalloc(sizeof(*udc_req_ptr), gfp_flags); + + + if (!udc_req_ptr) + return NULL; + + udc_req_ptr->usb_req.dma =3D DMA_ADDR_INVALID; + INIT_LIST_HEAD(&udc_req_ptr->queue); + + return &udc_req_ptr->usb_req; +} + +static void crg_udc_free_request(struct usb_ep *_ep, struct usb_request *_= req) +{ + struct crg_udc_request *udc_req_ptr =3D NULL; + + if (!_ep || !_req) + return; + + udc_req_ptr =3D container_of(_req, struct crg_udc_request, usb_req); + kfree(udc_req_ptr); +} + +static int +crg_udc_ep_queue(struct usb_ep *_ep, struct usb_request *_req, + gfp_t gfp_flags) +{ + struct crg_udc_request *udc_req_ptr; + struct crg_udc_ep *udc_ep_ptr; + struct crg_gadget_dev *crg_udc; + int status; + unsigned long flags =3D 0; + int dma_data_dir =3D 0; + + + if (!_req || !_ep) + return -EINVAL; + + udc_req_ptr =3D container_of(_req, struct crg_udc_request, usb_req); + if (!udc_req_ptr) + return -EINVAL; + + udc_ep_ptr =3D container_of(_ep, struct crg_udc_ep, usb_ep); + if (!udc_ep_ptr) + return -EINVAL; + + crg_udc =3D udc_ep_ptr->crg_udc; + if (!crg_udc) + return -EINVAL; + + spin_lock_irqsave(&crg_udc->udc_lock, flags); + + if (!udc_ep_ptr->first_trb || + !udc_req_ptr->usb_req.complete || + (!udc_req_ptr->usb_req.buf && !udc_req_ptr->usb_req.num_sgs) || + !list_empty(&udc_req_ptr->queue)) { + dev_dbg(crg_udc->dev, "%s, invalid usbrequest\n", __func__); + if (!udc_ep_ptr->first_trb) + dev_err(crg_udc->dev, "%s, no first_trb\n", __func__); + + if (!udc_req_ptr->usb_req.complete) + dev_err(crg_udc->dev, "%s, no complete\n", __func__); + + if (!udc_req_ptr->usb_req.buf) + dev_err(crg_udc->dev, "%s, no req buf\n", __func__); + + if (!list_empty(&udc_req_ptr->queue)) + dev_err(crg_udc->dev, "%s, list not empty\n", __func__); + + spin_unlock_irqrestore(&crg_udc->udc_lock, flags); + return -EINVAL; + } + dev_dbg(crg_udc->dev, "enqueue EPDCI =3D 0x%x\n", udc_ep_ptr->DCI); + dev_dbg(crg_udc->dev, "udc_req buf =3D 0x%p\n", udc_req_ptr->usb_req.buf); + + if (!udc_ep_ptr->desc) { + dev_dbg(crg_udc->dev, "udc_ep_ptr->Desc is null\n"); + spin_unlock_irqrestore(&crg_udc->udc_lock, flags); + return -EINVAL; + } + /* Ensure that req_ptr is updated */ + wmb(); + /* Clearing the Values of the UDC_REQUEST container */ + clear_req_container(udc_req_ptr); + udc_req_ptr->mapped =3D 0; + + if (usb_endpoint_xfer_control(udc_ep_ptr->desc) && + _req->length =3D=3D 0) { + crg_udc->setup_status =3D STATUS_STAGE_XFER; + status =3D -EINPROGRESS; + dev_dbg(crg_udc->dev, "udc_req_ptr =3D 0x%p\n", udc_req_ptr); + + build_ep0_status(&crg_udc->udc_ep[0], false, status, + udc_req_ptr, 0, 0); + dev_dbg(crg_udc->dev, "act status request for control endpoint\n"); + spin_unlock_irqrestore(&crg_udc->udc_lock, flags); + return 0; + } + + /* request length is possible to be 0. Like SCSI blank command */ + dev_dbg(crg_udc->dev, "request length=3D%d\n", _req->length); + + if (udc_req_ptr->usb_req.num_sgs) { + int n; + + dev_dbg(crg_udc->dev, "udc_req_ptr->usb_req.num_sgs =3D %d\n", + udc_req_ptr->usb_req.num_sgs); + dev_dbg(crg_udc->dev, "udc_req_ptr->usb_req.sg->length =3D %d\n", + udc_req_ptr->usb_req.sg->length); + dma_data_dir =3D (usb_endpoint_dir_in(udc_ep_ptr->desc) + ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + n =3D dma_map_sg(crg_udc->dev, udc_req_ptr->usb_req.sg, + udc_req_ptr->usb_req.num_sgs, dma_data_dir); + if (n <=3D 0) { + dev_err(crg_udc->dev, "dma_map_sg fail, ret is %d\n", n); + dump_stack(); + spin_unlock_irqrestore(&crg_udc->udc_lock, flags); + return -EINVAL; + } + if (n !=3D udc_req_ptr->usb_req.num_sgs) { + dev_err(crg_udc->dev, "URB_DMA_SG_COMBINED we not support\n"); + spin_unlock_irqrestore(&crg_udc->udc_lock, flags); + return -EAGAIN; + } + udc_req_ptr->usb_req.num_mapped_sgs =3D n; + dev_dbg(crg_udc->dev, "dma_map_sg done , usb_req.num_mapped_sgs =3D %d\n= ", n); + + + } else if (udc_req_ptr->usb_req.sg) { + dev_err(crg_udc->dev, "num_sgs =3D 0, but udc_req_ptr->usb_req.sg is not= NULL\n"); + spin_unlock_irqrestore(&crg_udc->udc_lock, flags); + return -EINVAL; + + } else { + if (udc_req_ptr->usb_req.dma =3D=3D DMA_ADDR_INVALID && _req->length != =3D 0) { + if (usb_endpoint_xfer_control(udc_ep_ptr->desc)) { + if (crg_udc->setup_status =3D=3D DATA_STAGE_XFER || + crg_udc->setup_status =3D=3D STATUS_STAGE_XFER) + dma_data_dir =3D DMA_TO_DEVICE; + + if (crg_udc->setup_status =3D=3D DATA_STAGE_RECV || + crg_udc->setup_status =3D=3D STATUS_STAGE_RECV) + dma_data_dir =3D DMA_FROM_DEVICE; + } else { + dma_data_dir =3D (usb_endpoint_dir_in(udc_ep_ptr->desc) + ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + } + udc_req_ptr->usb_req.dma =3D + dma_map_single(crg_udc->dev, udc_req_ptr->usb_req.buf, + udc_req_ptr->usb_req.length, + dma_data_dir); + + + udc_req_ptr->mapped =3D 1; + + dev_dbg(crg_udc->dev, "dma_map_single and mapped is 1\n"); + } + } + + udc_req_ptr->usb_req.status =3D -EINPROGRESS; + udc_req_ptr->usb_req.actual =3D 0; + + /* If the transfer ring for this particular end point is full, + * then simply queue the request and return + */ + if (udc_ep_ptr->tran_ring_full) { + status =3D 0; + } else { + /* push the request to the transfer ring if possible. */ + status =3D crg_udc_build_td(udc_ep_ptr, udc_req_ptr); + } + if (!status) + list_add_tail(&udc_req_ptr->queue, &udc_ep_ptr->queue); + + spin_unlock_irqrestore(&crg_udc->udc_lock, flags); + + return status; +} + +static int +crg_udc_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) +{ + struct crg_udc_ep *udc_ep_ptr; + struct crg_gadget_dev *crg_udc; + struct crg_uccr *uccr; + u32 tmp =3D 0; + struct crg_udc_request *udc_req; + struct ep_cx_s *p_ep_cx; + int old_ep_state; + struct transfer_trb_s *pause_pt; + u32 deq_pt_lo, deq_pt_hi; + u64 dq_pt_addr; + u8 DCI; + unsigned long flags =3D 0; + + if (!_ep || !_req) + return -EINVAL; + + udc_ep_ptr =3D container_of(_ep, struct crg_udc_ep, usb_ep); + crg_udc =3D udc_ep_ptr->crg_udc; + uccr =3D crg_udc->uccr; + DCI =3D udc_ep_ptr->DCI; + + spin_lock_irqsave(&crg_udc->udc_lock, flags); + + dev_dbg(crg_udc->dev, "%s EPDCI =3D 0x%x\n", __func__, DCI); + old_ep_state =3D get_ep_state(crg_udc, DCI); + if (DCI !=3D 0 && old_ep_state =3D=3D EP_STATE_RUNNING) { + u32 param0; + + dev_dbg(crg_udc->dev, "%s, EP_STATE_RUNNING\n", __func__); + param0 =3D (0x1 << DCI); + /* stop the DMA from HW first */ + crg_issue_command(crg_udc, CRG_CMD_STOP_EP, param0, 0); + do { + tmp =3D readl(&uccr->ep_running); + } while ((tmp & param0) !=3D 0); + udc_ep_ptr->ep_state =3D EP_STATE_STOPPED; + } + + list_for_each_entry(udc_req, &udc_ep_ptr->queue, queue) { + if (&udc_req->usb_req =3D=3D _req) + break; + } + + if (&udc_req->usb_req !=3D _req) { + dev_dbg(crg_udc->dev, "did not find the request in request queue\n"); + spin_unlock_irqrestore(&crg_udc->udc_lock, flags); + return -EINVAL; + } + /* Request hasn't been queued to transfer ring yet + * dequeue it from sw queue only + */ + if (!udc_req->first_trb) { + req_done(udc_ep_ptr, udc_req, -ECONNRESET); + spin_unlock_irqrestore(&crg_udc->udc_lock, flags); + return 0; + } + + /* ep0 cannot be stopped. So if request has already been queued to + * transfer ring, it cannot be dequeued + */ + if (DCI =3D=3D 0) { + spin_unlock_irqrestore(&crg_udc->udc_lock, flags); + return -EINVAL; + } + + p_ep_cx =3D crg_udc->p_epcx + DCI - 2; + deq_pt_lo =3D p_ep_cx->dw2 & EP_CX_TR_DQPT_LO_MASK; + deq_pt_hi =3D p_ep_cx->dw3; + dq_pt_addr =3D (u64)deq_pt_lo + ((u64)deq_pt_hi << 32); + pause_pt =3D tran_trb_dma_to_virt(udc_ep_ptr, dq_pt_addr); + + dev_dbg(crg_udc->dev, "dequeue pause_pt =3D 0x%p, first_trb =3D 0x%p\n", + pause_pt, udc_req->first_trb); + dev_dbg(crg_udc->dev, "dequeue deq_pt =3D 0x%p, enq_pt =3D 0x%p\n", + udc_ep_ptr->deq_pt, udc_ep_ptr->enq_pt); + + if (is_pointer_less_than(pause_pt, udc_req->first_trb, udc_ep_ptr)) { + dev_dbg(crg_udc->dev, "squeeze_xfer_ring\n"); + /* HW hasn't process the request yet */ + squeeze_xfer_ring(udc_ep_ptr, udc_req); + req_done(udc_ep_ptr, udc_req, -ECONNRESET); + } else if (udc_req->last_trb && + is_pointer_less_than(udc_req->last_trb, pause_pt, udc_ep_ptr)) { + /* Request has been completed by HW + * There must be transfer events pending in event ring, and + * it will be processed later once interrupt context gets spin + * lock. + * Gadget driver free the request without checking the return + * value of usb_ep_dequeue, so we have to complete the request + * here and drop the transfer event later. + */ + dev_dbg(crg_udc->dev, " Request has been complete by HW, reject request\= n"); + req_done(udc_ep_ptr, udc_req, -ECONNRESET); + spin_unlock_irqrestore(&crg_udc->udc_lock, flags); + return -EINVAL; + + } else { + /* Request has been partially completed by HW */ + + dev_dbg(crg_udc->dev, " Request has been partially completed by HW\n"); + /*udc_req->usb_req.actual =3D actual_data_xfered(udc_ep, udc_req);*/ + + dev_dbg(crg_udc->dev, "%s, complete requests\n", __func__); + req_done(udc_ep_ptr, udc_req, -ECONNRESET); + + advance_dequeue_pt(udc_ep_ptr); + crg_udc_epcx_update_dqptr(udc_ep_ptr); + + /* For big TD, we generated completion event every 5 TRBS. + * So, we do not need to update sw dequeue pointer here. + * Wait for interrupt context to update it. + * Do not need to queue more trbs also. + */ + } + + dev_dbg(crg_udc->dev, "End dequeue deq_pt =3D 0x%p, enq_pt =3D 0x%p\n", + udc_ep_ptr->deq_pt, udc_ep_ptr->enq_pt); + + /* knock doorbell and resume data transfer */ + if (old_ep_state =3D=3D EP_STATE_RUNNING) { + tmp =3D DCI; + tmp =3D CRG_U3DC_DB_TARGET(tmp); + + knock_doorbell(crg_udc, udc_ep_ptr->DCI); + + udc_ep_ptr->ep_state =3D EP_STATE_RUNNING; + } + + spin_unlock_irqrestore(&crg_udc->udc_lock, flags); + + return 0; +} + +static int crg_udc_ep_set_halt(struct usb_ep *_ep, int value) +{ + struct crg_udc_ep *udc_ep_ptr; + int status; + unsigned long flags =3D 0; + struct crg_gadget_dev *crg_udc; + + if (!_ep) + return -EINVAL; + + udc_ep_ptr =3D container_of(_ep, struct crg_udc_ep, usb_ep); + crg_udc =3D udc_ep_ptr->crg_udc; + + spin_lock_irqsave(&crg_udc->udc_lock, flags); + + if (value && usb_endpoint_dir_in(udc_ep_ptr->desc) && + !list_empty(&udc_ep_ptr->queue)) { + dev_err(crg_udc->dev, "set_halt: list not empty\n"); + spin_unlock_irqrestore(&crg_udc->udc_lock, flags); + return -EAGAIN; + } + + status =3D ep_halt(udc_ep_ptr, value, 1); + + spin_unlock_irqrestore(&crg_udc->udc_lock, flags); + + return status; +} + +static int crg_udc_ep_set_wedge(struct usb_ep *_ep) +{ + struct crg_udc_ep *udc_ep_ptr; + int status; + unsigned long flags =3D 0; + struct crg_gadget_dev *crg_udc; + + if (!_ep) + return -EINVAL; + + udc_ep_ptr =3D container_of(_ep, struct crg_udc_ep, usb_ep); + crg_udc =3D udc_ep_ptr->crg_udc; + + spin_lock_irqsave(&crg_udc->udc_lock, flags); + + udc_ep_ptr->wedge =3D 1; + + status =3D ep_halt(udc_ep_ptr, 1, 1); + + spin_unlock_irqrestore(&crg_udc->udc_lock, flags); + + return status; +} + +static struct usb_ep_ops crg_udc_ep_ops =3D { + .enable =3D crg_udc_ep_enable, + .disable =3D crg_udc_ep_disable, + .alloc_request =3D crg_udc_alloc_request, + .free_request =3D crg_udc_free_request, + .queue =3D crg_udc_ep_queue, + .dequeue =3D crg_udc_ep_dequeue, + .set_halt =3D crg_udc_ep_set_halt, + .set_wedge =3D crg_udc_ep_set_wedge, +}; + +static void crg_ep_struct_setup(struct crg_gadget_dev *crg_udc, + u32 DCI, const char *name) +{ + struct crg_udc_ep *ep =3D &crg_udc->udc_ep[DCI]; + + ep->DCI =3D DCI; + + if (ep->DCI > 1) { + strscpy_pad(ep->name, name, sizeof(ep->name) - 1); + ep->usb_ep.name =3D ep->name; + ep->usb_ep.maxpacket =3D 1024; + ep->usb_ep.max_streams =3D 16; + + ep->usb_ep.caps.type_iso =3D 1; + ep->usb_ep.caps.type_bulk =3D 1; + ep->usb_ep.caps.type_int =3D 1; + ep->usb_ep.caps.dir_in =3D 1; + ep->usb_ep.caps.type_control =3D 1; + + ep->usb_ep.caps.type_iso =3D 1; + ep->usb_ep.caps.type_bulk =3D 1; + ep->usb_ep.caps.type_int =3D 1; + ep->usb_ep.caps.type_control =3D 1; + if (ep->DCI % 2) + ep->usb_ep.caps.dir_out =3D 1; + else + ep->usb_ep.caps.dir_in =3D 1; + usb_ep_set_maxpacket_limit(&ep->usb_ep, MAX_PACKET_SIZE); + } else { + strscpy(ep->name, "ep0", sizeof(ep->name) - 1); + ep->usb_ep.name =3D ep->name; + ep->usb_ep.maxpacket =3D 512; + ep->usb_ep.caps.type_control =3D 1; + ep->usb_ep.caps.dir_in =3D 1; + ep->usb_ep.caps.dir_out =3D 1; + } + + dev_dbg(crg_udc->dev, "ep =3D 0x%p, ep name =3D %s maxpacket =3D %d DCI= =3D%d\n", + ep, ep->name, ep->usb_ep.maxpacket, ep->DCI); + ep->usb_ep.ops =3D &crg_udc_ep_ops; + ep->crg_udc =3D crg_udc; + + INIT_LIST_HEAD(&ep->queue); + if (ep->DCI > 1) + list_add_tail(&ep->usb_ep.ep_list, &crg_udc->gadget.ep_list); +} + + +static void enable_setup_event(struct crg_gadget_dev *crg_udc) +{ + struct crg_uccr *uccr =3D crg_udc->uccr; + u32 val; + + dev_dbg(crg_udc->dev, "before setup en config1[0x%p]=3D0x%x\n", + &uccr->config1, readl(&uccr->config1)); + + val =3D readl(&uccr->config1); + val |=3D CRG_U3DC_CFG1_SETUP_EVENT_EN; + writel(val, &uccr->config1); + dev_dbg(crg_udc->dev, "update config1[0x%p]=3D0x%x\n", + &uccr->config1, readl(&uccr->config1)); +} + +static int is_event_ring_x_empty(struct crg_gadget_dev *crg_udc, int index) +{ + struct event_trb_s *event; + struct crg_udc_event *udc_event; + + udc_event =3D &crg_udc->udc_event[index]; + if (udc_event->evt_dq_pt) { + event =3D (struct event_trb_s *)udc_event->evt_dq_pt; + + if (GETF(EVE_TRB_CYCLE_BIT, event->dw3) !=3D + udc_event->CCS) + return 1; + } + + return 0; +} + +static int is_event_rings_empty(struct crg_gadget_dev *crg_udc) +{ + int i; + + for (i =3D 0; i < CRG_RING_NUM; i++) { + if (!is_event_ring_x_empty(crg_udc, i)) { + dev_err(crg_udc->dev, "%s evt ring not empty\n", __func__); + return 0; + } + } + return 1; +} + +static int enable_setup(struct crg_gadget_dev *crg_udc) +{ + enable_setup_event(crg_udc); + crg_udc->device_state =3D USB_STATE_DEFAULT; + crg_udc->setup_status =3D WAIT_FOR_SETUP; + dev_dbg(crg_udc->dev, "%s ready to receive setup events\n", __func__); + + return 0; +} + +static int prepare_for_setup(struct crg_gadget_dev *crg_udc) +{ + struct crg_udc_ep *udc_ep0_ptr; + +#ifdef REINIT_EP0_ON_BUS_RESET + dma_addr_t dqptaddr; + u32 cmd_param0; + u32 cmd_param1; +#endif + + if (!is_event_rings_empty(crg_udc) || + crg_udc->portsc_on_reconnecting =3D=3D 1) + return -EBUSY; + + udc_ep0_ptr =3D &crg_udc->udc_ep[0]; +/* If we reinit ep0 on bus reset, we just make ep0 dequeue pointer align + * with enqueue pointer, all remaining xfer trbs became dumb ones which + * will not produce xfer event anymore. + * + * If we considering the opposite solution, we should wait all ep0 xfer + * trbs be completed(with some err complete code) + */ +#ifdef REINIT_EP0_ON_BUS_RESET + /* Complete any reqs on EP0 queue */ + nuke(udc_ep0_ptr, -ESHUTDOWN); + + crg_udc->ctrl_req_enq_idx =3D 0; + memset(crg_udc->ctrl_req_queue, 0, + sizeof(struct crg_setup_packet) * CTRL_REQ_QUEUE_DEPTH); + + /*context related ops*/ + dqptaddr =3D tran_trb_virt_to_dma(udc_ep0_ptr, udc_ep0_ptr->enq_pt); + cmd_param0 =3D (lower_32_bits(dqptaddr) & + CRG_CMD0_0_DQPTRLO_MASK) | + CRG_CMD0_0_DCS(udc_ep0_ptr->pcs); + cmd_param1 =3D upper_32_bits(dqptaddr); + crg_issue_command(crg_udc, + CRG_CMD_INIT_EP0, cmd_param0, cmd_param1); + + /* TRY this solution*/ + udc_ep0_ptr->deq_pt =3D udc_ep0_ptr->enq_pt; + udc_ep0_ptr->tran_ring_full =3D false; +#else + if (!list_empty(&udc_ep0_ptr->queue)) { + dev_err(crg_udc->dev, "%s remaining ep0 xfer trbs on reset!\n", __func__= ); + return -EBUSY; + } +#endif + + enable_setup(crg_udc); + + return 0; +} + +static void update_ep0_maxpacketsize(struct crg_gadget_dev *crg_udc) +{ + u16 maxpacketsize =3D 0; + struct crg_udc_ep *udc_ep0 =3D &crg_udc->udc_ep[0]; + u32 param0; + + if (crg_udc->gadget.speed >=3D USB_SPEED_SUPER) + maxpacketsize =3D 512; + else + maxpacketsize =3D 64; + + param0 =3D CRG_CMD1_0_MPS(maxpacketsize); + crg_issue_command(crg_udc, CRG_CMD_UPDATE_EP0_CFG, param0, 0); + + crg_udc_ep0_desc.wMaxPacketSize =3D cpu_to_le16(maxpacketsize); + udc_ep0->usb_ep.maxpacket =3D maxpacketsize; +} + +static int init_event_ring(struct crg_gadget_dev *crg_udc, int index) +{ + struct crg_uicr *uicr =3D crg_udc->uicr[index]; + struct crg_udc_event *udc_event =3D &crg_udc->udc_event[index]; + + int ret; + u32 buff_length; + dma_addr_t mapping; + + buff_length =3D CRG_ERST_SIZE * sizeof(struct erst_s); + if (!udc_event->erst.vaddr) { + udc_event->erst.vaddr =3D + dma_alloc_coherent(crg_udc->dev, buff_length, + &mapping, GFP_KERNEL); + + if (!udc_event->erst.vaddr) { + ret =3D -ENOMEM; + return ret; + } + } else { + mapping =3D udc_event->erst.dma; + } + + udc_event->erst.len =3D buff_length; + udc_event->erst.dma =3D mapping; + udc_event->p_erst =3D udc_event->erst.vaddr; + + buff_length =3D CRG_EVENT_RING_SIZE * sizeof(struct event_trb_s); + if (!udc_event->event_ring.vaddr) { + udc_event->event_ring.vaddr =3D + dma_alloc_coherent(crg_udc->dev, buff_length, + &mapping, GFP_KERNEL); + + if (!udc_event->event_ring.vaddr) { + ret =3D -ENOMEM; + return ret; + } + } else { + mapping =3D udc_event->event_ring.dma; + } + + udc_event->event_ring.len =3D buff_length; + udc_event->event_ring.dma =3D mapping; + udc_event->evt_dq_pt =3D udc_event->event_ring.vaddr; + + udc_event->evt_seg0_last_trb =3D + (struct event_trb_s *)(udc_event->event_ring.vaddr) + + (CRG_EVENT_RING_SIZE - 1); + + udc_event->CCS =3D 1; + + udc_event->p_erst->seg_addr_lo =3D + lower_32_bits(udc_event->event_ring.dma); + udc_event->p_erst->seg_addr_hi =3D + upper_32_bits(udc_event->event_ring.dma); + udc_event->p_erst->seg_size =3D cpu_to_le32(CRG_EVENT_RING_SIZE); + udc_event->p_erst->rsvd =3D 0; + /* Ensure that event ring is updated */ + wmb(); + /*clear the event ring, to avoid hw unexpected ops + *because of dirty data + */ + memset(udc_event->event_ring.vaddr, 0, buff_length); + + /*hw related ops ERSTBA && ERSTSZ && ERDP*/ + /* Ensure that event ring is clear */ + wmb(); + + /**************************/ + writel(CRG_ERST_SIZE, &uicr->erstsz); + writel(lower_32_bits(udc_event->erst.dma), &uicr->erstbalo); + writel(upper_32_bits(udc_event->erst.dma), &uicr->erstbahi); + writel(lower_32_bits(udc_event->event_ring.dma) | CRG_U3DC_ERDPLO_EHB, + &uicr->erdplo); + writel(upper_32_bits(udc_event->event_ring.dma), &uicr->erdphi); + + writel((CRG_U3DC_IMAN_INT_EN | CRG_U3DC_IMAN_INT_PEND), &uicr->iman); + writel((0L << 0) | (4000L << 0), &uicr->imod); + + return 0; +} + +static int init_device_context(struct crg_gadget_dev *crg_udc) +{ + struct crg_uccr *uccr =3D crg_udc->uccr; + int ret; + u32 buff_length; + dma_addr_t mapping; + + /*ep0 is not included in ep contexts in crg udc*/ + buff_length =3D (CRG_NUM_EP_CX - 2) * sizeof(struct ep_cx_s); + + if (!crg_udc->ep_cx.vaddr) { + crg_udc->ep_cx.vaddr =3D + dma_alloc_coherent(crg_udc->dev, buff_length, + &mapping, GFP_KERNEL); + /* Ensure that ep_cx.vaddr is updated */ + wmb(); + if (!crg_udc->ep_cx.vaddr) { + ret =3D -ENOMEM; + return ret; + } + } else { + mapping =3D crg_udc->ep_cx.dma; + } + + crg_udc->p_epcx =3D crg_udc->ep_cx.vaddr; + crg_udc->ep_cx.len =3D buff_length; + crg_udc->ep_cx.dma =3D mapping; + + /*hw ops DCBAPLO DCBAPHI*/ + writel(lower_32_bits(crg_udc->ep_cx.dma), &uccr->dcbaplo); + writel(upper_32_bits(crg_udc->ep_cx.dma), &uccr->dcbaphi); + + dev_dbg(crg_udc->dev, "dcbaplo[0x%p]=3D0x%x\n", &uccr->dcbaplo, readl(&uc= cr->dcbaplo)); + dev_dbg(crg_udc->dev, "dcbaphi[0x%p]=3D0x%x\n", &uccr->dcbaphi, readl(&uc= cr->dcbaphi)); + + return 0; +} + +static int reset_data_struct(struct crg_gadget_dev *crg_udc) +{ + u32 tmp; + int i; + struct crg_uccr *uccr =3D crg_udc->uccr; + u32 val; + + val =3D readl(&uccr->control); + val &=3D (~(CRG_U3DC_CTRL_INT_EN | CRG_U3DC_CTRL_RUN)); + writel(val, &uccr->control); + + dev_dbg(crg_udc->dev, "capability[0x%p]=3D0x%x\n", &uccr->capability, + readl(&uccr->capability)); + + switch (crg_udc->gadget.max_speed) { + case USB_SPEED_FULL: + tmp =3D CRG_U3DC_CFG0_MAXSPEED_FS; + break; + case USB_SPEED_HIGH: + tmp =3D CRG_U3DC_CFG0_MAXSPEED_HS; + break; + case USB_SPEED_SUPER: + tmp =3D CRG_U3DC_CFG0_MAXSPEED_SS; + break; + case USB_SPEED_SUPER_PLUS: + tmp =3D CRG_U3DC_CFG0_MAXSPEED_SSP; + break; + case USB_SPEED_UNKNOWN: + default: + return -EINVAL; + } + writel(tmp, &uccr->config0); + + for (i =3D 0; i < CRG_RING_NUM; i++) + init_event_ring(crg_udc, i); + + init_device_context(crg_udc); + + if (!crg_udc->status_req) { + crg_udc->status_req =3D + container_of(crg_udc_alloc_request(&crg_udc->udc_ep[0].usb_ep, + GFP_ATOMIC), struct crg_udc_request, + usb_req); + } + + /*other hw ops*/ + return 0; +} + +static int init_ep0(struct crg_gadget_dev *crg_udc) +{ + struct crg_udc_ep *udc_ep_ptr =3D &crg_udc->udc_ep[0]; + u32 cmd_param0; + u32 cmd_param1; + + /* setup transfer ring */ + if (!udc_ep_ptr->tran_ring_info.vaddr) { + dma_addr_t dma; + u32 ring_size =3D CRGUDC_CONTROL_EP_TD_RING_SIZE; + void *vaddr; + size_t len; + + len =3D ring_size * sizeof(struct transfer_trb_s); + vaddr =3D dma_alloc_coherent(crg_udc->dev, len, + &dma, GFP_KERNEL); + if (!vaddr) + return -ENOMEM; + + udc_ep_ptr->tran_ring_info.vaddr =3D vaddr; + udc_ep_ptr->tran_ring_info.dma =3D dma; + udc_ep_ptr->tran_ring_info.len =3D len; + udc_ep_ptr->first_trb =3D vaddr; + udc_ep_ptr->last_trb =3D udc_ep_ptr->first_trb + ring_size - 1; + } + + memset(udc_ep_ptr->first_trb, 0, udc_ep_ptr->tran_ring_info.len); + /* Ensure that transfer ring is updated */ + wmb(); + udc_ep_ptr->enq_pt =3D udc_ep_ptr->first_trb; + udc_ep_ptr->deq_pt =3D udc_ep_ptr->first_trb; + udc_ep_ptr->pcs =3D 1; + udc_ep_ptr->tran_ring_full =3D false; + + setup_link_trb(udc_ep_ptr->last_trb, + true, udc_ep_ptr->tran_ring_info.dma); + + /*context related ops*/ + cmd_param0 =3D (lower_32_bits(udc_ep_ptr->tran_ring_info.dma) & + CRG_CMD0_0_DQPTRLO_MASK) | + CRG_CMD0_0_DCS(udc_ep_ptr->pcs); + cmd_param1 =3D upper_32_bits(udc_ep_ptr->tran_ring_info.dma); + + dev_dbg(crg_udc->dev, "ep0 ring dma addr =3D 0x%llx\n", udc_ep_ptr->tran_= ring_info.dma); + + dev_dbg(crg_udc->dev, "ep0 ring vaddr =3D 0x%p\n", udc_ep_ptr->tran_ring_= info.vaddr); + + dev_dbg(crg_udc->dev, "INIT EP0 CMD, par0=3D0x%x, par1=3D0x%x\n", cmd_par= am0, cmd_param1); + + crg_issue_command(crg_udc, CRG_CMD_INIT_EP0, cmd_param0, cmd_param1); + + udc_ep_ptr->ep_state =3D EP_STATE_RUNNING; + + return 0; +} + +static int EP0_Start(struct crg_gadget_dev *crg_udc) +{ + crg_udc->udc_ep[0].desc =3D &crg_udc_ep0_desc; + + return 0; +} + +static void crg_udc_start(struct crg_gadget_dev *crg_udc) +{ + struct crg_uccr *uccr; + u32 val; + + uccr =3D crg_udc->uccr; + + /*****interrupt related*****/ + val =3D readl(&uccr->config1); + val |=3D (CRG_U3DC_CFG1_CSC_EVENT_EN | + CRG_U3DC_CFG1_PEC_EVENT_EN | + CRG_U3DC_CFG1_PPC_EVENT_EN | + CRG_U3DC_CFG1_PRC_EVENT_EN | + CRG_U3DC_CFG1_PLC_EVENT_EN | + CRG_U3DC_CFG1_CEC_EVENT_EN); + writel(val, &uccr->config1); + dev_dbg(crg_udc->dev, "config1[0x%p]=3D0x%x\n", &uccr->config1, readl(&uc= cr->config1)); + dev_dbg(crg_udc->dev, "config0[0x%p]=3D0x%x\n", &uccr->config0, readl(&uc= cr->config0)); + + val =3D readl(&uccr->control); + val |=3D (CRG_U3DC_CTRL_SYSERR_EN | + CRG_U3DC_CTRL_INT_EN); + writel(val, &uccr->control); + /*****interrupt related end*****/ + + val =3D readl(&uccr->control); + val |=3D CRG_U3DC_CTRL_RUN; + writel(val, &uccr->control); + dev_dbg(crg_udc->dev, "%s, control=3D0x%x\n", __func__, readl(&uccr->cont= rol)); +} + +static void crg_udc_clear_portpm(struct crg_gadget_dev *crg_udc) +{ + struct crg_uccr *uccr =3D crg_udc->uccr; + u32 tmp; + + tmp =3D readl(&uccr->u3portpmsc); + + tmp &=3D (~CRG_U3DC_U3PORTPM_U1IEN); + tmp =3D SETF_VAR(CRG_U3DC_U3PORTPM_U1TMOUT, tmp, 0); + tmp &=3D (~CRG_U3DC_U3PORTPM_U2IEN); + tmp =3D SETF_VAR(CRG_U3DC_U3PORTPM_U2TMOUT, tmp, 0); + + writel(tmp, &uccr->u3portpmsc); + + crg_udc->feature_u1_enable =3D 0; + crg_udc->feature_u2_enable =3D 0; +} + +static void crg_udc_reinit(struct crg_gadget_dev *crg_udc) +{ + struct crg_uccr *uccr =3D crg_udc->uccr; + u32 i, tmp; + unsigned long flags =3D 0; + struct crg_udc_ep *udc_ep_ptr; + + crg_udc->setup_status =3D WAIT_FOR_SETUP; + /* Base on Figure 9-1, default USB_STATE is attached */ + crg_udc->device_state =3D USB_STATE_RECONNECTING; + + /* halt all the endpoints */ + + dev_dbg(crg_udc->dev, "ep_enable=3D0x%x\n", readl(&uccr->ep_enable)); + dev_dbg(crg_udc->dev, "ep_running=3D0x%x\n", readl(&uccr->ep_running)); + + /* disable all the endpoints */ + tmp =3D readl(&uccr->ep_enable); + writel(tmp, &uccr->ep_enable); + for (i =3D 0; i < 50; i++) { + tmp =3D readl(&uccr->ep_enable); + if (tmp =3D=3D 0) + break; + } + + dev_dbg(crg_udc->dev, "i=3D%d\n", i); + dev_dbg(crg_udc->dev, "after ep_enable=3D0x%x\n", readl(&uccr->ep_enable)= ); + + for (i =3D 2; i < 32; i++) { + udc_ep_ptr =3D &crg_udc->udc_ep[i]; + udc_ep_ptr->usb_ep.enabled =3D 0; + if (udc_ep_ptr->desc) + nuke(udc_ep_ptr, -ESHUTDOWN); + udc_ep_ptr->tran_ring_full =3D false; + udc_ep_ptr->ep_state =3D EP_STATE_DISABLED; + } + crg_udc->num_enabled_eps =3D 0; + +/* we don't handle ep0 here, we init_ep0 when event ring is empty*/ + + if (crg_udc->dev_addr !=3D 0) { + u32 param0; + + param0 =3D CRG_CMD2_0_DEV_ADDR(0); + crg_issue_command(crg_udc, CRG_CMD_SET_ADDR, param0, 0); + crg_udc->dev_addr =3D 0; + } + + crg_udc_clear_portpm(crg_udc); + + if (crg_udc->gadget_driver) { + dev_dbg(crg_udc->dev, "calling disconnect\n"); + spin_unlock_irqrestore(&crg_udc->udc_lock, flags); + crg_udc->gadget_driver->disconnect(&crg_udc->gadget); + spin_lock_irqsave(&crg_udc->udc_lock, flags); + } +} + +static int crg_udc_reset(struct crg_gadget_dev *crg_udc) +{ + struct crg_uccr *uccr =3D crg_udc->uccr; + u32 i, tmp, count; + struct crg_udc_ep *udc_ep_ptr; + u32 val; + + dev_dbg(crg_udc->dev, "capability =3D %x\n", readl(&uccr->capability)); + + count =3D 0; + val =3D readl(&uccr->control); + val |=3D CRG_U3DC_CTRL_SWRST; + writel(val, &uccr->control); + do { + mdelay(10); + tmp =3D readl(&uccr->control); + count++; + + if (count =3D=3D 50) { + dev_err(crg_udc->dev, "reset error\n"); + return -1; + } + } while ((tmp & CRG_U3DC_CTRL_SWRST) !=3D 0); + + crg_udc_clear_portpm(crg_udc); + + crg_udc->setup_status =3D WAIT_FOR_SETUP; + /* Base on Figure 9-1, default USB_STATE is attached */ + crg_udc->device_state =3D USB_STATE_ATTACHED; + crg_udc->dev_addr =3D 0; + + /* Complete any reqs on EP1-EP15 queue */ + for (i =3D 2; i < 32; i++) { + udc_ep_ptr =3D &crg_udc->udc_ep[i]; + + if (udc_ep_ptr->desc) + nuke(udc_ep_ptr, -ESHUTDOWN); + udc_ep_ptr->tran_ring_full =3D false; + udc_ep_ptr->ep_state =3D EP_STATE_DISABLED; + } + crg_udc->num_enabled_eps =3D 0; + + /* Complete any reqs on EP0 queue */ + udc_ep_ptr =3D &crg_udc->udc_ep[0]; + if (udc_ep_ptr->desc) + nuke(udc_ep_ptr, -ESHUTDOWN); + + crg_udc->ctrl_req_enq_idx =3D 0; + memset(crg_udc->ctrl_req_queue, 0, + sizeof(struct crg_setup_packet) * CTRL_REQ_QUEUE_DEPTH); + + return 0; +} + +/************controller related ops*******************************/ +#define gadget_to_udc(g) (container_of(g, struct crg_gadget_dev, gadget)) +int g_dnl_board_usb_cable_connected(struct crg_gadget_dev *crg_udc); + +static int crg_gadget_pullup(struct usb_gadget *g, int is_on) +{ + struct crg_gadget_dev *crg_udc; + + /* No need to call g_dnl_board_usb_cable_connected upon stop + * controller or pull down D- event. + */ + if (is_on) { + crg_udc =3D gadget_to_udc(g); + g_dnl_board_usb_cable_connected(crg_udc); + } + return 0; +} + +static int crg_vbus_detect_thread(void *data); + +static void crg_vbus_detect(struct crg_gadget_dev *crg_udc, int enable) +{ + if (enable) { + if (crg_udc->vbus_task) { + dev_err(crg_udc->dev, + "vbus task already run, wake up vbus_wait\n"); + wake_up_interruptible(&vbus_wait); + return; + } + /* Enable the VBUS */ + writel((readl(crg_udc->mmio_virt_base + + CRG_UDC_VENDOR_REG) | + CRG_UDC_VBUS_DETECT), + crg_udc->mmio_virt_base + CRG_UDC_VENDOR_REG); + crg_udc->vbus_task =3D kthread_run(crg_vbus_detect_thread, + (void *)crg_udc, + "corigine_vbus_thread"); + if (IS_ERR(crg_udc->vbus_task)) { + dev_err(crg_udc->dev, + "Unable to create corigine_vbus_thread.\n"); + crg_udc->vbus_task =3D NULL; + return; + } + } else { + if (crg_udc->vbus_task) { + /* Disable VBUS to stop controller */ + writel((readl(crg_udc->mmio_virt_base + + CRG_UDC_VENDOR_REG) & + ~(CRG_UDC_VBUS_DETECT)), + crg_udc->mmio_virt_base + CRG_UDC_VENDOR_REG); + wake_up_interruptible(&vbus_wait); + kthread_stop(crg_udc->vbus_task); + crg_udc->vbus_task =3D NULL; + return; + } + } +} + +static int crg_gadget_start(struct usb_gadget *g, + struct usb_gadget_driver *driver) +{ + struct crg_gadget_dev *crg_udc; + + crg_udc =3D gadget_to_udc(g); + crg_udc->gadget_driver =3D driver; + + dev_dbg(crg_udc->dev, "%s %d gadget speed=3D%d, max speed=3D%d\n", + __func__, __LINE__, g->speed, g->max_speed); + dev_dbg(crg_udc->dev, "%s %d driver speed=3D%d\n", + __func__, __LINE__, driver->max_speed); + crg_vbus_detect(crg_udc, 1); + return 0; +} + +static int crg_gadget_stop(struct usb_gadget *g) +{ + struct crg_gadget_dev *crg_udc; + unsigned long flags =3D 0; + + crg_udc =3D gadget_to_udc(g); + + crg_udc->device_state =3D USB_STATE_ATTACHED; + crg_vbus_detect(crg_udc, 0); + + spin_lock_irqsave(&crg_udc->udc_lock, flags); + + crg_udc_reset(crg_udc); + + reset_data_struct(crg_udc); + crg_udc->connected =3D 0; + crg_udc->gadget_driver =3D NULL; + crg_udc->gadget.speed =3D USB_SPEED_UNKNOWN; + + init_ep0(crg_udc); + + spin_unlock_irqrestore(&crg_udc->udc_lock, flags); + + return 0; +} + +static const struct usb_gadget_ops crg_gadget_ops =3D { + .pullup =3D crg_gadget_pullup, + .udc_start =3D crg_gadget_start, + .udc_stop =3D crg_gadget_stop, +}; + +static int init_ep_info(struct crg_gadget_dev *crg_udc) +{ + int i; + + /*udc_ep[0] is reserved, */ + crg_ep_struct_setup(crg_udc, 0, NULL); + + for (i =3D 1; i < CRG_NUM_EP_CX / 2; i++) { + char name[14]; + + sprintf(name, "ep%din", i); + crg_ep_struct_setup(crg_udc, i * 2, name); + sprintf(name, "ep%dout", i); + crg_ep_struct_setup(crg_udc, i * 2 + 1, name); + } + + return 0; +} + +static void queue_setup_pkt(struct crg_gadget_dev *crg_udc, + struct usb_ctrlrequest *setup_pkt, + u16 setup_tag) +{ + if (crg_udc->ctrl_req_enq_idx =3D=3D CTRL_REQ_QUEUE_DEPTH) { + dev_err(crg_udc->dev, "ctrl request queque is full\n"); + return; + } + + memcpy(&crg_udc->ctrl_req_queue[crg_udc->ctrl_req_enq_idx].usbctrlreq, + setup_pkt, sizeof(struct usb_ctrlrequest)); + crg_udc->ctrl_req_queue[crg_udc->ctrl_req_enq_idx].setup_tag =3D + setup_tag; + + crg_udc->ctrl_req_enq_idx++; +} + +static inline u32 index2DCI(u16 index) +{ + if (index =3D=3D 0) + return 0; + + return (index & USB_ENDPOINT_NUMBER_MASK) * 2 + ((index & + USB_DIR_IN) ? 0 : 1); +} + +static void get_status_cmpl(struct usb_ep *ep, struct usb_request *req) +{ + kfree(req->buf); +} + +static void getstatusrequest(struct crg_gadget_dev *crg_udc, + u8 RequestType, u16 value, u16 index, u16 length) +{ + u32 status_val =3D 0; + u32 status =3D -EINPROGRESS; + struct crg_udc_ep *udc_ep_ptr; + struct crg_udc_request *udc_req_ptr =3D crg_udc->status_req; + + if (!udc_req_ptr) + return; + udc_req_ptr->usb_req.buf =3D kzalloc(sizeof(u16), GFP_ATOMIC); + dev_dbg(crg_udc->dev, "udc_req_ptr->usb_req.buf =3D 0x%p\n", udc_req_ptr-= >usb_req.buf); + if (!udc_req_ptr->usb_req.buf) + return; + + if (value || length > 2 || !length) { + status =3D -EINVAL; + goto get_status_error; + } + + dev_dbg(crg_udc->dev, "Get status request RequestType =3D 0x%x Index=3D%x= \n", + RequestType, index); + if ((RequestType & USB_RECIP_MASK) =3D=3D USB_RECIP_DEVICE) { + dev_dbg(crg_udc->dev, "Get status request Device request\n"); + if (index) { + status =3D -EINVAL; + goto get_status_error; + } + + if (crg_udc->gadget.speed =3D=3D USB_SPEED_HIGH || + crg_udc->gadget.speed =3D=3D USB_SPEED_FULL) { + if (crg_udc->u2_RWE) + status_val |=3D BIT(USB_DEVICE_REMOTE_WAKEUP); + } + + if (crg_udc->gadget.speed >=3D USB_SPEED_SUPER) { + if (crg_udc->feature_u1_enable) + status_val |=3D BIT(USB_DEV_STAT_U1_ENABLED); + if (crg_udc->feature_u2_enable) + status_val |=3D BIT(USB_DEV_STAT_U2_ENABLED); + } + + status_val |=3D USB_DEVICE_SELF_POWERED; + dev_dbg(crg_udc->dev, "Status =3D 0x%x\n", status_val); + + } else if ((RequestType & USB_RECIP_MASK) =3D=3D USB_RECIP_INTERFACE) { + dev_dbg(crg_udc->dev, "Get status request Interface request\n"); + status_val =3D 0; + } else if ((RequestType & USB_RECIP_MASK) =3D=3D USB_RECIP_ENDPOINT) { + u32 DCI; + + DCI =3D index2DCI(index); + + dev_dbg(crg_udc->dev, "Get status request endpoint request DCI =3D %d\n"= , DCI); + + if (DCI =3D=3D 1) { + status_val =3D 0; + dev_dbg(crg_udc->dev, "Get status request INVALID! DCI =3D %d\n", DCI); + goto get_status_error; + } + /* if device state is address state, index should be 0 + * if device state is configured state, index should be an + * endpoint configured. + */ + + dev_dbg(crg_udc->dev, "crg_udc->device_state =3D %d\n", crg_udc->device_= state); + if (crg_udc->device_state =3D=3D USB_STATE_ADDRESS && DCI !=3D 0) { + status =3D -EINVAL; + goto get_status_error; + } + + if (crg_udc->device_state =3D=3D USB_STATE_CONFIGURED) { + if (get_ep_state(crg_udc, DCI) =3D=3D EP_STATE_DISABLED) { + status =3D -EINVAL; + goto get_status_error; + } + + if (get_ep_state(crg_udc, DCI) =3D=3D EP_STATE_HALTED) { + status_val =3D BIT(USB_ENDPOINT_HALT); + dev_dbg(crg_udc->dev, "endpoint was halted =3D 0x%lx\n", + (unsigned long)status_val); + } + } + } + +get_status_error: + if (status !=3D -EINPROGRESS) { + udc_req_ptr->usb_req.length =3D 0; + } else { + *(u16 *)udc_req_ptr->usb_req.buf =3D cpu_to_le16(status_val); + dev_dbg(crg_udc->dev, "usb_req.buf =3D 0x%x\n", + *((u16 *)udc_req_ptr->usb_req.buf)); + + dev_dbg(crg_udc->dev, "usb_req.buf addr =3D 0x%p\n", + (udc_req_ptr->usb_req.buf)); + + udc_req_ptr->usb_req.length =3D 2; + } + udc_req_ptr->usb_req.status =3D status; + udc_req_ptr->usb_req.actual =3D 0; + udc_req_ptr->usb_req.complete =3D get_status_cmpl; + + if (udc_req_ptr->usb_req.dma =3D=3D DMA_ADDR_INVALID) { + udc_req_ptr->usb_req.dma =3D + dma_map_single(crg_udc->dev, udc_req_ptr->usb_req.buf, + udc_req_ptr->usb_req.length, + DMA_FROM_DEVICE); + udc_req_ptr->mapped =3D 1; + } + dev_dbg(crg_udc->dev, "status_val =3D 0x%x, cpu_to_le16(status_val) =3D 0= x%x\n", + status_val, cpu_to_le16(status_val)); + dev_dbg(crg_udc->dev, "udc_req_ptr->usb_req.buf =3D 0x%p, value =3D 0x%x\= n", + udc_req_ptr->usb_req.buf, *(u16 *)(udc_req_ptr->usb_req.buf)); + dev_dbg(crg_udc->dev, "udc_req_ptr->usb_req.dma =3D 0x%llx\n", + udc_req_ptr->usb_req.dma); + + udc_ep_ptr =3D &crg_udc->udc_ep[0]; + + crg_udc->setup_status =3D DATA_STAGE_XFER; + status =3D crg_udc_build_td(udc_ep_ptr, udc_req_ptr); + + dev_dbg(crg_udc->dev, "getstatus databuf eqpt =3D 0x%p\n", udc_ep_ptr->en= q_pt); + + if (!status) + list_add_tail(&udc_req_ptr->queue, &udc_ep_ptr->queue); +} + +static void set_address_cmpl(struct crg_gadget_dev *crg_udc) +{ + if (crg_udc->device_state =3D=3D USB_STATE_DEFAULT && + crg_udc->dev_addr !=3D 0) { + crg_udc->device_state =3D USB_STATE_ADDRESS; + dev_dbg(crg_udc->dev, "USB State Addressed\n"); + + } else if (crg_udc->device_state =3D=3D USB_STATE_ADDRESS) { + if (crg_udc->dev_addr =3D=3D 0) + crg_udc->device_state =3D USB_STATE_DEFAULT; + } +} + +static void setaddressrequest(struct crg_gadget_dev *crg_udc, + u16 value, u16 index, u16 length) +{ + int status =3D -EINPROGRESS; + u8 status_set_addr =3D 0; + + if (value > 127 || index !=3D 0 || length !=3D 0) { + status =3D -EINVAL; + goto set_address_error; + } + + if ((crg_udc->device_state =3D=3D USB_STATE_DEFAULT && value !=3D 0) || + crg_udc->device_state =3D=3D USB_STATE_ADDRESS) { + u32 param0; + + crg_udc->dev_addr =3D value; + + param0 =3D CRG_CMD2_0_DEV_ADDR(value); + crg_issue_command(crg_udc, CRG_CMD_SET_ADDR, param0, 0); + status_set_addr =3D 1; + } else { + status =3D -EINVAL; + } + +set_address_error: + dev_dbg(crg_udc->dev, "build_ep0_status for Address Device\n"); + + crg_udc->setup_status =3D STATUS_STAGE_XFER; + crg_udc->setup_fn_call_back =3D &set_address_cmpl; + build_ep0_status(&crg_udc->udc_ep[0], + true, status, NULL, status_set_addr, 0); +} + +static void set_sel_cmpl(struct usb_ep *ep, struct usb_request *req) +{ + struct crg_udc_ep *udc_ep; + struct crg_gadget_dev *crg_udc; + struct sel_value_s *sel_value; + + udc_ep =3D container_of(ep, struct crg_udc_ep, usb_ep); + crg_udc =3D udc_ep->crg_udc; + + if (req->buf) { + sel_value =3D req->buf; + crg_udc->sel_value.u2_pel_value =3D sel_value->u2_pel_value; + crg_udc->sel_value.u2_sel_value =3D sel_value->u2_sel_value; + crg_udc->sel_value.u1_pel_value =3D sel_value->u1_pel_value; + crg_udc->sel_value.u1_sel_value =3D sel_value->u1_sel_value; + + kfree(req->buf); + } + + dev_dbg(crg_udc->dev, "u1_sel_value =3D 0x%x, u2_sel_value =3D 0x%x\n", + crg_udc->sel_value.u1_sel_value, + crg_udc->sel_value.u2_sel_value); +} + +static void setselrequest(struct crg_gadget_dev *crg_udc, + u16 value, u16 index, u16 length, u64 data) +{ + int status =3D -EINPROGRESS; + struct crg_udc_request *udc_req_ptr =3D crg_udc->status_req; + struct crg_udc_ep *udc_ep_ptr =3D &crg_udc->udc_ep[0]; + + if (!udc_req_ptr) + return; + + if (crg_udc->device_state =3D=3D USB_STATE_DEFAULT) + status =3D -EINVAL; + + if (index !=3D 0 || value !=3D 0 || length !=3D 6) + status =3D -EINVAL; + + if (status !=3D -EINPROGRESS) { + } else { + udc_req_ptr->usb_req.length =3D length; + udc_req_ptr->usb_req.buf =3D + kzalloc(sizeof(*udc_req_ptr->usb_req.buf), GFP_ATOMIC); + } + + udc_req_ptr->usb_req.status =3D -EINPROGRESS; + udc_req_ptr->usb_req.actual =3D 0; + udc_req_ptr->usb_req.complete =3D set_sel_cmpl; + + if (udc_req_ptr->usb_req.dma =3D=3D DMA_ADDR_INVALID) { + udc_req_ptr->usb_req.dma =3D + dma_map_single(crg_udc->dev, udc_req_ptr->usb_req.buf, + udc_req_ptr->usb_req.length, + DMA_TO_DEVICE); + udc_req_ptr->mapped =3D 1; + } + + status =3D crg_udc_build_td(udc_ep_ptr, udc_req_ptr); + + if (!status) + list_add_tail(&udc_req_ptr->queue, &udc_ep_ptr->queue); +} + +static void set_test_mode_cmpl(struct crg_gadget_dev *crg_udc) +{ + if (crg_udc->set_tm !=3D 0) { + u32 tmp; + struct crg_uccr *uccr =3D crg_udc->uccr; + + tmp =3D readl(&uccr->u2portpmsc); + tmp =3D SETF_VAR(CRG_U3DC_U2PORTPM_TM, tmp, crg_udc->set_tm); + writel(tmp, &uccr->u2portpmsc); + + crg_udc->set_tm =3D 0; + } +} + +static bool setfeaturesrequest(struct crg_gadget_dev *crg_udc, + u8 RequestType, u8 bRequest, u16 value, u16 index, u16 length) +{ + int status =3D -EINPROGRESS; + u8 DCI; + struct crg_udc_ep *udc_ep_ptr; + u32 tmp; + bool set_feat =3D 0; + struct crg_uccr *uccr =3D crg_udc->uccr; + + if (length !=3D 0) { + status =3D -EINVAL; + goto set_feature_error; + } + + if (crg_udc->device_state =3D=3D USB_STATE_DEFAULT) { + status =3D -EINVAL; + goto set_feature_error; + } + + set_feat =3D (bRequest =3D=3D USB_REQ_SET_FEATURE) ? 1 : 0; + if ((RequestType & (USB_RECIP_MASK | USB_TYPE_MASK)) =3D=3D + (USB_RECIP_ENDPOINT | USB_TYPE_STANDARD)) { + dev_dbg(crg_udc->dev, "Halt/Unhalt EP\n"); + if (crg_udc->device_state =3D=3D USB_STATE_ADDRESS) { + if (index !=3D 0) { + status =3D -EINVAL; + goto set_feature_error; + } + } + + DCI =3D index2DCI(index); + + if (DCI =3D=3D 1) { + dev_dbg(crg_udc->dev, "setfeat INVALID DCI =3D 0x%x !!\n", DCI); + goto set_feature_error; + } + + udc_ep_ptr =3D &crg_udc->udc_ep[DCI]; + dev_dbg(crg_udc->dev, "halt/Unhalt endpoint DCI =3D 0x%x\n", DCI); + + status =3D ep_halt(udc_ep_ptr, + (bRequest =3D=3D USB_REQ_SET_FEATURE) ? 1 : 0, + 0); + + if (status < 0) + goto set_feature_error; + } else if ((RequestType & (USB_RECIP_MASK | USB_TYPE_MASK)) =3D=3D + (USB_RECIP_DEVICE | USB_TYPE_STANDARD)) { + switch (value) { + case USB_DEVICE_REMOTE_WAKEUP: + dev_dbg(crg_udc->dev, "USB_DEVICE_REMOTE_WAKEUP called\n"); + /* REMOTE_WAKEUP selector is not used by USB3.0 */ + if (crg_udc->device_state < USB_STATE_DEFAULT || + crg_udc->gadget.speed >=3D USB_SPEED_SUPER) { + status =3D -EINVAL; + goto set_feature_error; + } + dev_dbg(crg_udc->dev, "%s_Feature RemoteWake\n", + set_feat ? "Set" : "Clear"); + + /*TODO corigine hardware ops needed*/ + crg_udc->u2_RWE =3D set_feat; + + break; + case USB_DEVICE_U1_ENABLE: + case USB_DEVICE_U2_ENABLE: + { + u32 timeout_val; + + dev_dbg(crg_udc->dev, "USB_DEVICE_U12_ENABLE called\n"); + if (crg_udc->device_state !=3D USB_STATE_CONFIGURED) { + dev_err(crg_udc->dev, "%s u12 enable fail, usb state=3D%d\n", + __func__, crg_udc->device_state); + status =3D -EINVAL; + goto set_feature_error; + } + + if (index & 0xff) { + status =3D -EINVAL; + goto set_feature_error; + } + + if (set_feat =3D=3D 1 && U12_FORBIDDEN > 0) { + status =3D -EINVAL; + goto set_feature_error; + } + + tmp =3D readl(&uccr->u3portpmsc); + /*TODO corigine hardware ops needed*/ + if (value =3D=3D USB_DEVICE_U1_ENABLE) { +#if (U12_INITIATE_FORBIDDEN =3D=3D 0) + tmp &=3D (~CRG_U3DC_U3PORTPM_U1IEN); + tmp |=3D (set_feat << + CRG_U3DC_U3PORTPM_U1IEN_SHIFT); +#endif + if (U12_FORBIDDEN =3D=3D 0) + timeout_val =3D set_feat ? + U1_TIMEOUT_VAL : 0; + else + timeout_val =3D 0; + + tmp =3D SETF_VAR(CRG_U3DC_U3PORTPM_U1TMOUT, + tmp, timeout_val); + + crg_udc->feature_u1_enable =3D set_feat; + } + + if (value =3D=3D USB_DEVICE_U2_ENABLE) { +#if (U12_INITIATE_FORBIDDEN =3D=3D 0) + tmp &=3D (~CRG_U3DC_U3PORTPM_U2IEN); + tmp |=3D (set_feat << + CRG_U3DC_U3PORTPM_U2IEN_SHIFT); +#endif + if (U12_FORBIDDEN =3D=3D 0) + timeout_val =3D set_feat ? U1_TIMEOUT_VAL : 0; + else + timeout_val =3D 0; + + tmp =3D SETF_VAR(CRG_U3DC_U3PORTPM_U2TMOUT, + tmp, timeout_val); + + crg_udc->feature_u2_enable =3D set_feat; + } + writel(tmp, &uccr->u3portpmsc); + + break; + } + case USB_DEVICE_TEST_MODE: + { + u32 u_pattern; + + dev_dbg(crg_udc->dev, "USB_DEVICE_TEST_MODE called\n"); + if (crg_udc->gadget.speed > USB_SPEED_HIGH) + goto set_feature_error; + + if (crg_udc->device_state < USB_STATE_DEFAULT) + goto set_feature_error; + + u_pattern =3D index >> 8; + /* TESTMODE is only defined for high speed device */ + if (crg_udc->gadget.speed =3D=3D USB_SPEED_HIGH) { + dev_dbg(crg_udc->dev, "high speed test mode enter\n"); + crg_udc->set_tm =3D u_pattern; + crg_udc->setup_fn_call_back =3D + &set_test_mode_cmpl; + } + break; + } + + default: + goto set_feature_error; + } + + } else if ((RequestType & (USB_RECIP_MASK | USB_TYPE_MASK)) =3D=3D + (USB_RECIP_INTERFACE | USB_TYPE_STANDARD)) { + if (crg_udc->device_state !=3D USB_STATE_CONFIGURED) { + dev_err(crg_udc->dev, "%s interface u12 enable fail, usb state=3D%d\n", + __func__, crg_udc->device_state); + status =3D -EINVAL; + goto set_feature_error; + } + + /* Suspend Option */ + if (value =3D=3D USB_INTRF_FUNC_SUSPEND) { + if (index & USB_INTR_FUNC_SUSPEND_OPT_MASK & + USB_INTRF_FUNC_SUSPEND_LP) { + if (index & USB_INTRF_FUNC_SUSPEND_RW) + dev_dbg(crg_udc->dev, "Interface En Remote Wakeup\n"); + else + dev_dbg(crg_udc->dev, "Interface Dis RemoteWakeup\n"); + + /* Do not need to return status stage here + * Pass to composite gadget driver to process + * the request + */ + return false; + } + } + } + + crg_udc->setup_status =3D STATUS_STAGE_XFER; + build_ep0_status(&crg_udc->udc_ep[0], true, status, NULL, 0, 0); + return true; + +set_feature_error: + set_ep0_halt(crg_udc); + return true; +} + +static bool setconfigurationrequest(struct crg_gadget_dev *crg_udc, u16 va= lue) +{ + if (crg_udc->device_state <=3D USB_STATE_DEFAULT) + goto set_config_error; + + /*return false means need further process by composite gadget driver*/ + return false; + +set_config_error: + set_ep0_halt(crg_udc); + return true; +} + +static void set_isoch_delay(struct crg_gadget_dev *crg_udc, + u16 value, u16 index, u16 length) +{ + int status =3D -EINPROGRESS; + + if (value > 65535 || index !=3D 0 || length !=3D 0) + status =3D -EINVAL; + + /*need further ops for isoch delay*/ + + crg_udc->setup_status =3D STATUS_STAGE_XFER; + build_ep0_status(&crg_udc->udc_ep[0], true, status, NULL, 0, 0); +} + +static void crg_handle_setup_pkt(struct crg_gadget_dev *crg_udc, + struct usb_ctrlrequest *setup_pkt, u8 setup_tag) +{ + u16 wValue =3D setup_pkt->wValue; + u16 wIndex =3D setup_pkt->wIndex; + u16 wLength =3D setup_pkt->wLength; + u64 wData =3D 0; + unsigned long flags =3D 0; + + dev_dbg(crg_udc->dev, "bRequest=3D0x%x, wValue=3D0x%.4x, wIndex=3D0x%x, w= Length=3D%d\n", + setup_pkt->bRequest, wValue, wIndex, wLength); + + /* EP0 come backs to running when new setup packet comes*/ + crg_udc->udc_ep[0].ep_state =3D EP_STATE_RUNNING; + + crg_udc->setup_tag =3D setup_tag; + crg_udc->setup_status =3D SETUP_PKT_PROCESS_IN_PROGRESS; + crg_udc->setup_fn_call_back =3D NULL; + + if ((setup_pkt->bRequestType & USB_TYPE_MASK) =3D=3D USB_TYPE_STANDARD) { + switch (setup_pkt->bRequest) { + case USB_REQ_GET_STATUS: + dev_dbg(crg_udc->dev, "USB_REQ_GET_STATUS\n"); + if ((setup_pkt->bRequestType & (USB_DIR_IN | + USB_TYPE_MASK)) + !=3D (USB_DIR_IN | USB_TYPE_STANDARD)) { + crg_udc->setup_status =3D WAIT_FOR_SETUP; + return; + } + + getstatusrequest(crg_udc, setup_pkt->bRequestType, + wValue, wIndex, wLength); + return; + case USB_REQ_SET_ADDRESS: + dev_dbg(crg_udc->dev, "USB_REQ_SET_ADDRESS\n"); + if (setup_pkt->bRequestType !=3D (USB_DIR_OUT | + USB_RECIP_DEVICE | + USB_TYPE_STANDARD)) { + crg_udc->setup_status =3D WAIT_FOR_SETUP; + return; + } + + setaddressrequest(crg_udc, wValue, wIndex, wLength); + return; + case USB_REQ_SET_SEL: + dev_dbg(crg_udc->dev, "USB_REQ_SET_SEL\n"); + + if (setup_pkt->bRequestType !=3D (USB_DIR_OUT | + USB_RECIP_DEVICE | + USB_TYPE_STANDARD)) { + crg_udc->setup_status =3D WAIT_FOR_SETUP; + return; + } + + crg_udc->setup_status =3D DATA_STAGE_RECV; + setselrequest(crg_udc, wValue, wIndex, wLength, wData); + return; + case USB_REQ_SET_ISOCH_DELAY: + if (setup_pkt->bRequestType !=3D (USB_DIR_OUT | + USB_RECIP_DEVICE | + USB_TYPE_STANDARD)) + break; + + dev_dbg(crg_udc->dev, "USB_REQ_SET_ISOCH_DELAY\n"); + set_isoch_delay(crg_udc, wValue, wIndex, wLength); + return; + + case USB_REQ_CLEAR_FEATURE: + case USB_REQ_SET_FEATURE: + dev_dbg(crg_udc->dev, "USB_REQ_CLEAR/SET_FEATURE\n"); + + /* Need composite gadget driver + * to process the function remote wakeup request + */ + if (setfeaturesrequest(crg_udc, setup_pkt->bRequestType, + setup_pkt->bRequest, + wValue, wIndex, wLength)) { + /* Get here if request has been processed.*/ + return; + } + break; + case USB_REQ_SET_CONFIGURATION: + /*In theory we need to clear RUN bit before + *status stage of deconfig request sent. + *But seeing problem if we do it before all the + *endpoints belonging to the configuration + *disabled. + */ + dev_dbg(crg_udc->dev, "USB_REQ_SET_CONFIGURATION\n"); + dev_dbg(crg_udc->dev, "CONFIGURATION wValue=3D%d\n", wValue); + + if (setconfigurationrequest(crg_udc, wValue)) { + /* Get here if request has been processed. + * Or error happens + */ + return; + } + + if (crg_udc->device_state =3D=3D USB_STATE_ADDRESS) + crg_udc->device_state =3D USB_STATE_CONFIGURED; + dev_dbg(crg_udc->dev, "USB_REQ_SET_CONFIGURATION: device_state is %d\n", + crg_udc->device_state); + break; + default: + dev_dbg(crg_udc->dev, "USB_REQ default bRequest=3D%d, bRequestType=3D%d= \n", + setup_pkt->bRequest, setup_pkt->bRequestType); + } + } + + if (wLength) { + /* data phase from gadget like GET_CONFIGURATION + * call the setup routine of gadget driver. + * remember the request direction. + */ + crg_udc->setup_status =3D + (setup_pkt->bRequestType & USB_DIR_IN) ? + DATA_STAGE_XFER : DATA_STAGE_RECV; + } + spin_unlock_irqrestore(&crg_udc->udc_lock, flags); + if (crg_udc->gadget_driver->setup(&crg_udc->gadget, setup_pkt) < 0) { + spin_lock_irqsave(&crg_udc->udc_lock, flags); + set_ep0_halt(crg_udc); + return; + } + spin_lock_irqsave(&crg_udc->udc_lock, flags); +} + +static int crg_handle_xfer_event(struct crg_gadget_dev *crg_udc, + struct event_trb_s *event) +{ + u8 DCI =3D GETF(EVE_TRB_ENDPOINT_ID, event->dw3); + struct crg_udc_ep *udc_ep_ptr =3D &crg_udc->udc_ep[DCI]; + /*Corigine ep contexts start from ep1*/ + u16 comp_code; + struct crg_udc_request *udc_req_ptr; + bool trbs_dequeued =3D false; + + if (!udc_ep_ptr->first_trb || + get_ep_state(crg_udc, DCI) =3D=3D EP_STATE_DISABLED) + return -ENODEV; + + comp_code =3D GETF(EVE_TRB_COMPL_CODE, event->dw2); + if (comp_code =3D=3D CMPL_CODE_STOPPED || + comp_code =3D=3D CMPL_CODE_STOPPED_LENGTH_INVALID || + comp_code =3D=3D CMPL_CODE_DISABLED || + comp_code =3D=3D CMPL_CODE_DISABLED_LENGTH_INVALID || + comp_code =3D=3D CMPL_CODE_HALTED || + comp_code =3D=3D CMPL_CODE_HALTED_LENGTH_INVALID) { + dev_dbg(crg_udc->dev, "comp_code =3D %d(STOPPED/HALTED/DISABLED)\n", com= p_code); + } else { + update_dequeue_pt(event, udc_ep_ptr); + } + + dev_dbg(crg_udc->dev, "%s ep%d dqpt=3D0x%p, eqpt=3D0x%p\n", __func__, + DCI, udc_ep_ptr->deq_pt, udc_ep_ptr->enq_pt); + dev_dbg(crg_udc->dev, "comp_code =3D %d\n", comp_code); + + if (is_request_dequeued(crg_udc, udc_ep_ptr, event)) { + trbs_dequeued =3D true; + dev_dbg(crg_udc->dev, "WARNING: Drop the transfer event\n"); + goto queue_more_trbs; + } + + comp_code =3D GETF(EVE_TRB_COMPL_CODE, event->dw2); + + switch (comp_code) { + case CMPL_CODE_SUCCESS: + { + dev_dbg(crg_udc->dev, "%s Complete SUCCESS\n", __func__); + handle_cmpl_code_success(crg_udc, event, udc_ep_ptr); + + trbs_dequeued =3D true; + break; + } + case CMPL_CODE_SHORT_PKT: + { + u32 trb_transfer_length; + + dev_dbg(crg_udc->dev, "handle_exfer_event CMPL_CODE_SHORT_PKT\n"); + if (usb_endpoint_dir_out(udc_ep_ptr->desc)) { + + trb_transfer_length =3D GETF(EVE_TRB_TRAN_LEN, + event->dw2); + udc_req_ptr =3D list_entry(udc_ep_ptr->queue.next, + struct crg_udc_request, queue); + + udc_req_ptr->usb_req.actual =3D + udc_req_ptr->usb_req.length - + trb_transfer_length; + /* Ensure that req_ptr is updated */ + wmb(); + if (udc_req_ptr->usb_req.actual !=3D 512 && + udc_req_ptr->usb_req.actual !=3D 31) { + u64 trb_pt; + struct transfer_trb_s *p_trb; + + dev_dbg(crg_udc->dev, "Actual Data transferred =3D %d\n", + udc_req_ptr->usb_req.actual); + + trb_pt =3D (u64)event->dw0 + + ((u64)(event->dw1) << 32); + + p_trb =3D tran_trb_dma_to_virt(udc_ep_ptr, trb_pt); + + dev_dbg(crg_udc->dev, "event dw0 =3D 0x%x\n", event->dw0); + dev_dbg(crg_udc->dev, "event dw1 =3D 0x%x\n", event->dw1); + dev_dbg(crg_udc->dev, "event dw2 =3D 0x%x\n", event->dw2); + dev_dbg(crg_udc->dev, "event dw3 =3D 0x%x\n", event->dw3); + + dev_dbg(crg_udc->dev, "trb_pt =3D 0x%lx, p_trb =3D 0x%p\n", + (unsigned long)trb_pt, p_trb); + + dev_dbg(crg_udc->dev, "trb dw0 =3D 0x%x\n", p_trb->dw0); + dev_dbg(crg_udc->dev, "trb dw1 =3D 0x%x\n", p_trb->dw1); + dev_dbg(crg_udc->dev, "trb dw2 =3D 0x%x\n", p_trb->dw2); + dev_dbg(crg_udc->dev, "trb dw3 =3D 0x%x\n", p_trb->dw3); + } + req_done(udc_ep_ptr, udc_req_ptr, 0); + } else { + dev_dbg(crg_udc->dev, "ep dir in\n"); + } + + trbs_dequeued =3D true; + + /* Advance the dequeue pointer to next TD */ + advance_dequeue_pt(udc_ep_ptr); + + break; + } + + case CMPL_CODE_PROTOCOL_STALL: + { + dev_dbg(crg_udc->dev, "%s CMPL_CODE_PROTOCOL_STALL\n", __func__); + + udc_req_ptr =3D list_entry(udc_ep_ptr->queue.next, + struct crg_udc_request, queue); + req_done(udc_ep_ptr, udc_req_ptr, -EINVAL); + trbs_dequeued =3D true; + crg_udc->setup_status =3D WAIT_FOR_SETUP; + advance_dequeue_pt(udc_ep_ptr); + break; + } + + case CMPL_CODE_SETUP_TAG_MISMATCH: + { + u32 enq_idx =3D crg_udc->ctrl_req_enq_idx; + struct usb_ctrlrequest *setup_pkt; + struct crg_setup_packet *crg_setup_pkt; + u16 setup_tag; + + dev_err(crg_udc->dev, "%s SETUP TAG MISMATCH\n", __func__); + dev_dbg(crg_udc->dev, "NOW setup tag =3D 0x%x\n", crg_udc->setup_tag); + + /* skip seqnum err event until last one arrives. */ + if (udc_ep_ptr->deq_pt =3D=3D udc_ep_ptr->enq_pt) { + udc_req_ptr =3D list_entry(udc_ep_ptr->queue.next, + struct crg_udc_request, + queue); + + if (udc_req_ptr) + req_done(udc_ep_ptr, udc_req_ptr, -EINVAL); + + /* drop all the queued setup packet, only + * process the latest one. + */ + crg_udc->setup_status =3D WAIT_FOR_SETUP; + if (enq_idx) { + crg_setup_pkt =3D + &crg_udc->ctrl_req_queue[enq_idx - 1]; + setup_pkt =3D &crg_setup_pkt->usbctrlreq; + setup_tag =3D crg_setup_pkt->setup_tag; + crg_handle_setup_pkt(crg_udc, setup_pkt, + setup_tag); + /* flash the queue after the latest + * setup pkt got handled.. + */ + memset(crg_udc->ctrl_req_queue, 0, + sizeof(struct crg_setup_packet) + * CTRL_REQ_QUEUE_DEPTH); + crg_udc->ctrl_req_enq_idx =3D 0; + } + } else { + dev_dbg(crg_udc->dev, "setuptag mismatch skp dpt!=3Dept: 0x%p, 0x%p\n", + udc_ep_ptr->deq_pt, udc_ep_ptr->enq_pt); + } + + crg_udc->setup_tag_mismatch_found =3D 1; + dev_dbg(crg_udc->dev, "%s SETUP TAG MISMATCH END\n", __func__); + break; + } + + case CMPL_CODE_BABBLE_DETECTED_ERR: + case CMPL_CODE_INVALID_STREAM_TYPE_ERR: + case CMPL_CODE_RING_UNDERRUN: + case CMPL_CODE_RING_OVERRUN: + case CMPL_CODE_ISOCH_BUFFER_OVERRUN: + case CMPL_CODE_USB_TRANS_ERR: + case CMPL_CODE_TRB_ERR: + { + dev_err(crg_udc->dev, "XFER event err, comp_code =3D 0x%x\n", comp_code); + set_ep_halt(crg_udc, DCI); + break; + } + + case CMPL_CODE_STOPPED: + case CMPL_CODE_STOPPED_LENGTH_INVALID: + /* Any ep stop ops should deal with stopped trbs itselves + * Event handler didn't know whether the stopped trb should + * be discarded or continued. So we do nothing here + */ + dev_err(crg_udc->dev, "STOP, comp_code =3D 0x%x\n", comp_code); + break; + default: + dev_dbg(crg_udc->dev, "CRG UNKNOWN comp_code =3D 0x%x\n", comp_code); + dev_dbg(crg_udc->dev, "EPDCI =3D 0x%x\n", udc_ep_ptr->DCI); + break; + } + + dev_dbg(crg_udc->dev, "%s 2 ep%d dqpt=3D0x%p, eqpt=3D0x%p\n", __func__, + DCI, udc_ep_ptr->deq_pt, udc_ep_ptr->enq_pt); + +queue_more_trbs: + /* If there are some trbs dequeued by HW and the ring + * was full before, then schedule any pending TRB's + */ + if (trbs_dequeued && udc_ep_ptr->tran_ring_full) { + udc_ep_ptr->tran_ring_full =3D false; + queue_pending_trbs(udc_ep_ptr); + } + return 0; +} + +int g_dnl_board_usb_cable_connected(struct crg_gadget_dev *crg_udc) +{ + struct crg_uccr *uccr; + u32 tmp, tmp_cfg0; + static bool pp =3D UDC_FALSE; + static int cnt =3D INIT_ZERO; + + uccr =3D crg_udc->uccr; + crg_udc_start(crg_udc); + + if (cnt < STATE_USB_LINK_STABLE) { + tmp =3D readl(crg_udc->mmio_virt_base + CRG_UDC_VENDOR_REG); + writel(tmp | 1 << 26, + crg_udc->mmio_virt_base + CRG_UDC_VENDOR_REG); + + tmp =3D readl(&uccr->control); + tmp |=3D CRG_U3DC_CTRL_RUN; + dev_dbg(crg_udc->dev, "tmp1 =3D 0x%x\n", tmp); + writel(tmp, &uccr->control); + tmp =3D readl(&uccr->control); + dev_dbg(crg_udc->dev, "control =3D 0x%x\n", tmp); + mdelay(10); + pp =3D (readl(crg_udc->mmio_virt_base + + CRG_UDC_VENDOR_REG) >> 26) & 1; + tmp =3D readl(&uccr->control); + tmp &=3D ~CRG_U3DC_CTRL_RUN; + writel(tmp, &uccr->control); + tmp =3D readl(&uccr->control); + dev_dbg(crg_udc->dev, "control2 =3D 0x%x\n", tmp); + cnt++; + } else { + pp =3D (readl(crg_udc->mmio_virt_base + + CRG_UDC_VENDOR_REG) >> 26) & 1; + dev_dbg(crg_udc->dev, "pp =3D %d\n", pp); + if (pp) { + if (crg_udc->device_state < USB_STATE_POWERED) { + tmp_cfg0 =3D readl(&uccr->config0); + tmp_cfg0 &=3D (~0xf0); + tmp_cfg0 |=3D 0xf0; + writel(tmp_cfg0, &uccr->config0); + + mdelay(3); + crg_udc_start(crg_udc); + crg_udc->device_state =3D USB_STATE_POWERED; + return 1; + } else + return 1; + + } else { + cnt =3D 0; + return 0; + } + } + tmp =3D readl(&uccr->portsc); + if (tmp & CRG_U3DC_PORTSC_PP) { + mdelay(100); + tmp =3D readl(&uccr->portsc); + if (tmp & CRG_U3DC_PORTSC_PP) { + if (crg_udc->device_state < USB_STATE_POWERED) { + u32 tmp_cfg0; + + dev_dbg(crg_udc->dev, "%s powered, portsc[0x%p]=3D0x%x\n", __func__, + &uccr->portsc, tmp); + + /*set usb 3 disable count to 15*/ + tmp_cfg0 =3D readl(&uccr->config0); + tmp_cfg0 &=3D (~0xf0); + tmp_cfg0 |=3D 0xf0; + writel(tmp_cfg0, &uccr->config0); + + mdelay(3); + crg_udc_start(crg_udc); + + dev_dbg(crg_udc->dev, "%s device state powered\n", __func__); + crg_udc->device_state =3D USB_STATE_POWERED; + } + } + return 1; + } + + dev_dbg(crg_udc->dev, "%s no power, portsc[0x%p]=3D0x%x\n", __func__, + &uccr->portsc, tmp); + + return 0; +} + +static int crg_handle_port_status(struct crg_gadget_dev *crg_udc) +{ + struct crg_uccr *uccr =3D crg_udc->uccr; + u32 portsc_val; + u32 tmp; + u32 speed; + unsigned long flags =3D 0; + + /* handle Port Reset */ + portsc_val =3D readl(&uccr->portsc); + writel(portsc_val, &uccr->portsc); + + tmp =3D readl(&uccr->portsc); + dev_dbg(crg_udc->dev, "%s RAW,portsc[0x%p]=3D0x%x\n", __func__, + &uccr->portsc, portsc_val); + + if (portsc_val & CRG_U3DC_PORTSC_PRC) { + mdelay(3); + + tmp =3D readl(&uccr->portsc); + if (tmp & CRG_U3DC_PORTSC_PRC) { + dev_dbg(crg_udc->dev, "PRC is still set\n"); + } else if (tmp & CRG_U3DC_PORTSC_PR) { + /* first port status change event for port reset*/ + dev_dbg(crg_udc->dev, "PRC is not set, but PR is set!!!!!!!!\n"); + } else { + if (CRG_U3DC_PORTSC_PLS_GET(tmp) !=3D 0 || + (!(tmp & CRG_U3DC_PORTSC_PED))) { + dev_dbg(crg_udc->dev, + "portsc[0x%p]=3D0x%x no PED\n", + &uccr->portsc, tmp); + return 0; + } + + switch (CRG_U3DC_PORTSC_SPEED_GET(tmp)) { + case CRG_U3DC_PORTSC_SPEED_SSP: + speed =3D USB_SPEED_SUPER_PLUS; + break; + case CRG_U3DC_PORTSC_SPEED_SS: + speed =3D USB_SPEED_SUPER; + break; + case CRG_U3DC_PORTSC_SPEED_HS: + speed =3D USB_SPEED_HIGH; + break; + + case CRG_U3DC_PORTSC_SPEED_FS: + speed =3D USB_SPEED_FULL; + break; + + case CRG_U3DC_PORTSC_SPEED_LS: + speed =3D USB_SPEED_LOW; + break; + default: + speed =3D USB_SPEED_UNKNOWN; + return 0; + } + + if (crg_udc->device_state >=3D USB_STATE_DEFAULT) + crg_udc_reinit(crg_udc); + + crg_udc->gadget.speed =3D speed; + dev_dbg(crg_udc->dev, "gadget speed =3D 0x%x\n", crg_udc->gadget.speed); + + update_ep0_maxpacketsize(crg_udc); + + crg_udc->connected =3D 1; + + if (crg_udc->device_state < USB_STATE_RECONNECTING) + enable_setup(crg_udc); + + dev_dbg(crg_udc->dev, "PORTSC =3D 0x%x\n", readl(&uccr->portsc)); + } + } + /* handle Port Reset end */ + + /* handle Port Connection Change*/ + tmp =3D readl(&uccr->portsc); + if ((tmp & (CRG_U3DC_PORTSC_CCS | CRG_U3DC_PORTSC_PP)) =3D=3D + (CRG_U3DC_PORTSC_CCS | CRG_U3DC_PORTSC_PP)) { + dev_dbg(crg_udc->dev, "connect int checked\n"); + dev_dbg(crg_udc->dev, "portsc[0x%p]=3D0x%x\n", &uccr->portsc, tmp); + + if (CRG_U3DC_PORTSC_PLS_GET(tmp) !=3D 0 || + (!(tmp & CRG_U3DC_PORTSC_PED))) + return 0; + + switch (CRG_U3DC_PORTSC_SPEED_GET(tmp)) { + case CRG_U3DC_PORTSC_SPEED_SSP: + speed =3D USB_SPEED_SUPER_PLUS; + break; + case CRG_U3DC_PORTSC_SPEED_SS: + speed =3D USB_SPEED_SUPER; + break; + case CRG_U3DC_PORTSC_SPEED_HS: + speed =3D USB_SPEED_HIGH; + break; + + case CRG_U3DC_PORTSC_SPEED_FS: + speed =3D USB_SPEED_FULL; + break; + + case CRG_U3DC_PORTSC_SPEED_LS: + default: + speed =3D USB_SPEED_UNKNOWN; + return 0; + } + crg_udc->gadget.speed =3D speed; + + update_ep0_maxpacketsize(crg_udc); + + crg_udc->connected =3D 1; + + if (crg_udc->device_state < USB_STATE_RECONNECTING) + enable_setup(crg_udc); + + dev_dbg(crg_udc->dev, "connect speed =3D %d\n", speed); + + } else if (!(tmp & CRG_U3DC_PORTSC_CCS)) { + int cable_connected; + + int ccs_drop_ignore =3D 0; + + if ((CRG_U3DC_PORTSC_PLS_GET(tmp) =3D=3D 0x0) && + (CRG_U3DC_PORTSC_SPEED_GET(tmp) < + CRG_U3DC_PORTSC_SPEED_SS)) { + ccs_drop_ignore =3D 1; + dev_err(crg_udc->dev, "ccs glitch detect on HS/FS!\n"); + } + + if (!ccs_drop_ignore) + crg_udc->gadget.speed =3D USB_SPEED_UNKNOWN; + + mdelay(150); + cable_connected =3D + g_dnl_board_usb_cable_connected(crg_udc); + if (cable_connected && !ccs_drop_ignore) { + crg_udc->device_state =3D USB_STATE_POWERED; + dev_dbg(crg_udc->dev, "do warm reset\n"); + crg_udc_reinit(crg_udc); + crg_udc->connected =3D 0; + } else if (!cable_connected) { + dev_dbg(crg_udc->dev, "cable disconnected, rst controller\n"); + + crg_udc_reset(crg_udc); + if (crg_udc->gadget_driver->disconnect) { + spin_unlock_irqrestore(&crg_udc->udc_lock, flags); + crg_udc->gadget_driver->disconnect(&crg_udc->gadget); + spin_lock_irqsave(&crg_udc->udc_lock, flags); + } + + reset_data_struct(crg_udc); + crg_udc->connected =3D 0; + init_ep0(crg_udc); + + crg_udc->device_state =3D USB_STATE_ATTACHED; + + wake_up_interruptible(&vbus_wait); + return -ECONNRESET; + } + } + /* handle Port Connection Change end*/ + + if (portsc_val & CRG_U3DC_PORTSC_PLC) { + tmp =3D readl(&uccr->portsc); + if (CRG_U3DC_PORTSC_PLS_GET(tmp) =3D=3D 0xf) { + tmp =3D SETF_VAR(CRG_U3DC_PORTSC_PLS, tmp, 0x0); + writel(tmp, &uccr->portsc); + dev_dbg(crg_udc->dev, "pls to 0, write portsc 0x%x\n", tmp); + } else if (CRG_U3DC_PORTSC_PLS_GET(tmp) =3D=3D 0x3) { + if (crg_udc->gadget_driver->disconnect) { + spin_unlock_irqrestore(&crg_udc->udc_lock, flags); + crg_udc->gadget_driver->disconnect(&crg_udc->gadget); + spin_lock_irqsave(&crg_udc->udc_lock, flags); + } + } + } + + return 0; +} + +static int crg_udc_handle_event(struct crg_gadget_dev *crg_udc, + struct event_trb_s *event) +{ + int ret; + + switch (GETF(EVE_TRB_TYPE, event->dw3)) { + case TRB_TYPE_EVT_PORT_STATUS_CHANGE: + if (crg_udc->device_state =3D=3D USB_STATE_RECONNECTING) { + crg_udc->portsc_on_reconnecting =3D 1; + break; + } + /* 1.Port Reset 2.Port Connection Change 3.Port Link Change */ + ret =3D crg_handle_port_status(crg_udc); + if (ret) + return ret; + + break; + case TRB_TYPE_EVT_TRANSFER: + if (crg_udc->device_state < USB_STATE_RECONNECTING) { + dev_err(crg_udc->dev, + "Xfer compl event rcved when dev state=3D%d !\n", + crg_udc->device_state); + break; + } + + crg_handle_xfer_event(crg_udc, event); + break; + case TRB_TYPE_EVT_SETUP_PKT: + { + struct usb_ctrlrequest *setup_pkt; + u8 setup_tag; + + dev_dbg(crg_udc->dev, "handle_setup_pkt(%d)\n", + crg_udc->device_state); + + setup_pkt =3D (struct usb_ctrlrequest *)&event->dw0; + + setup_tag =3D GETF(EVE_TRB_SETUP_TAG, event->dw3); + dev_dbg(crg_udc->dev, "setup_pkt =3D 0x%p, setup_tag =3D 0x%x\n", + setup_pkt, setup_tag); + if (crg_udc->setup_status !=3D WAIT_FOR_SETUP) { + /*previous setup packet hasn't + * completed yet. Just ignore the prev setup + */ + dev_err(crg_udc->dev, "consecutive setup\n"); + queue_setup_pkt(crg_udc, setup_pkt, setup_tag); + break; + } + + crg_handle_setup_pkt(crg_udc, setup_pkt, setup_tag); + + break; + } + default: + dev_dbg(crg_udc->dev, "unexpect TRB_TYPE =3D 0x%x", + GETF(EVE_TRB_TYPE, event->dw3)); + break; + } + + return 0; +} + +static int process_event_ring(struct crg_gadget_dev *crg_udc, int index) +{ + struct event_trb_s *event; + struct crg_udc_event *udc_event; + struct crg_uicr *uicr =3D crg_udc->uicr[index]; + dma_addr_t tmp; + u32 val; + dma_addr_t erdp; + int ret; + + if (!uicr) + return IRQ_NONE; + + tmp =3D readl(&uicr->iman); + if ((tmp & (CRG_U3DC_IMAN_INT_EN | CRG_U3DC_IMAN_INT_PEND)) !=3D + (CRG_U3DC_IMAN_INT_EN | CRG_U3DC_IMAN_INT_PEND)) { + } + + val =3D readl(&uicr->iman); + val |=3D CRG_U3DC_IMAN_INT_PEND; + writel(val, &uicr->iman); + + udc_event =3D &crg_udc->udc_event[index]; + while (udc_event->evt_dq_pt) { + /* rmb */ + rmb(); + event =3D (struct event_trb_s *)udc_event->evt_dq_pt; + + if (GETF(EVE_TRB_CYCLE_BIT, event->dw3) !=3D + udc_event->CCS) + break; + + ret =3D crg_udc_handle_event(crg_udc, event); + if (ret =3D=3D -ECONNRESET) + return ret; + + if (event =3D=3D udc_event->evt_seg0_last_trb) { + udc_event->CCS =3D udc_event->CCS ? 0 : 1; + udc_event->evt_dq_pt =3D udc_event->event_ring.vaddr; + } else { + udc_event->evt_dq_pt++; + } + } + + /* update dequeue pointer */ + erdp =3D event_trb_virt_to_dma(udc_event, udc_event->evt_dq_pt); + tmp =3D upper_32_bits(erdp); + writel(upper_32_bits(erdp), &uicr->erdphi); + tmp =3D lower_32_bits(erdp); + tmp |=3D CRG_U3DC_ERDPLO_EHB; + writel(lower_32_bits(erdp | CRG_U3DC_ERDPLO_EHB), &uicr->erdplo); + + return 0; +} + +static int crg_gadget_handle_interrupt(struct crg_gadget_dev *crg_udc) +{ + struct crg_uccr *uccr =3D crg_udc->uccr; + u32 tmp_status; + unsigned long flags =3D 0; + + spin_lock_irqsave(&crg_udc->udc_lock, flags); + + /******************************/ + + tmp_status =3D readl(&uccr->status); + + if (tmp_status & CRG_U3DC_STATUS_SYS_ERR) { + dev_err(crg_udc->dev, "%s System error happens!!!\n", __func__); + /*Handle system error*/ + writel(CRG_U3DC_STATUS_SYS_ERR, &uccr->status); + } + + if (tmp_status & CRG_U3DC_STATUS_EINT) { + int i; + + writel(CRG_U3DC_STATUS_EINT, &uccr->status); + + /*process event rings*/ + for (i =3D 0; i < CRG_RING_NUM; i++) + process_event_ring(crg_udc, i); + } + + if (crg_udc->device_state =3D=3D USB_STATE_RECONNECTING && + crg_udc->portsc_on_reconnecting =3D=3D 1 && + is_event_rings_empty(crg_udc)) { + crg_udc->portsc_on_reconnecting =3D 0; + crg_handle_port_status(crg_udc); + } + + if (crg_udc->device_state =3D=3D USB_STATE_RECONNECTING && + crg_udc->connected =3D=3D 1) { + dev_dbg(crg_udc->dev, "check if ready for setup\n"); + prepare_for_setup(crg_udc); + } + + spin_unlock_irqrestore(&crg_udc->udc_lock, flags); + + return 0; +} + +static irqreturn_t crg_udc_common_irq(int irq, void *dev) +{ + int retval =3D 0; + + retval =3D crg_gadget_handle_interrupt(dev); + + return IRQ_HANDLED; +} + +static int crg_gadget_irq_init(struct platform_device *pdev, struct crg_ga= dget_dev *crg_udc) +{ + int irq =3D 0; + int retval =3D 0; + + irq =3D platform_get_irq(pdev, 0); + if (irq < 0) + return -ENODEV; + + crg_udc->irq =3D irq; + + retval =3D request_irq(irq, crg_udc_common_irq, + IRQF_SHARED, "crg_udc", + crg_udc); + if (retval) { + dev_err(crg_udc->dev, "request of irq%d failed\n", irq); + retval =3D -EBUSY; + } + + return 0; +} + +static int crg_vbus_detect_thread(void *data) +{ + struct crg_gadget_dev *crg_udc =3D (struct crg_gadget_dev *)data; + unsigned long flags =3D 0; + int cable_connected =3D 0; + + while (1) { + if (kthread_should_stop()) + break; + + dev_dbg(crg_udc->dev, "crg_udc->device_state is %d\n", + crg_udc->device_state); + + spin_lock_irqsave(&crg_udc->udc_lock, flags); + + cable_connected =3D g_dnl_board_usb_cable_connected(crg_udc); + + spin_unlock_irqrestore(&crg_udc->udc_lock, flags); + + if (cable_connected) { + wait_event_interruptible + (vbus_wait, crg_udc->device_state < USB_STATE_POWERED); + } else { + dev_dbg(crg_udc->dev, "wait for vbus\n"); + msleep(1000); + } + } + + return 0; +} + + +static const struct crg_udc_priv ax3000_plat_setup_gen2 =3D { + .plat_setup_gen3 =3D false, +}; + +static const struct crg_udc_priv ax3000_plat_setup_gen3 =3D { + .plat_setup_gen3 =3D true, +}; + +/** + * crg_gadget_probe - Initializes gadget driver + * + * + * Returns 0 on success otherwise negative errno. + */ + +static const struct of_device_id of_crg_udc_match[] =3D { + { + .compatible =3D "axiado,ax3000-udc", + .data =3D &ax3000_plat_setup_gen2 + }, + { + .compatible =3D "axiado,ax3000-udc-gen3", + .data =3D &ax3000_plat_setup_gen3 + }, + { }, +}; +MODULE_DEVICE_TABLE(of, of_crg_udc_match); + +static int crg_udc_probe(struct platform_device *pdev) +{ + int ret; + int i; + struct crg_gadget_dev *crg_udc; + static int udc_gcnt =3D INIT_ZERO; + char udc_gname[10] =3D {""}; + const struct crg_udc_priv *priv; + + priv =3D of_device_get_match_data(&pdev->dev); + sprintf(udc_gname, "gadget-%d", udc_gcnt); + crg_udc =3D devm_kzalloc(&pdev->dev, sizeof(*crg_udc), GFP_KERNEL); + if (!crg_udc) + return -ENOMEM; + crg_udc->dev =3D &pdev->dev; + + spin_lock_init(&crg_udc->udc_lock); + platform_set_drvdata(pdev, crg_udc); + + dev_set_name(&crg_udc->gadget.dev, udc_gname); + crg_udc->gadget.ops =3D &crg_gadget_ops; + crg_udc->gadget.ep0 =3D &crg_udc->udc_ep[0].usb_ep; + crg_udc->gadget.dev.parent =3D &pdev->dev; + INIT_LIST_HEAD(&crg_udc->gadget.ep_list); + if (priv->plat_setup_gen3) { + crg_udc->gadget.max_speed =3D USB_SPEED_SUPER; + crg_udc->gadget.speed =3D USB_SPEED_SUPER; + } else { + crg_udc->gadget.max_speed =3D USB_SPEED_HIGH; + crg_udc->gadget.speed =3D USB_SPEED_HIGH; + } + crg_udc->gadget.name =3D udc_gname; + crg_udc->gadget.sg_supported =3D true; + dev_dbg(crg_udc->dev, "%s sg support\n", __func__); + crg_udc->connected =3D 0; + crg_udc->dev_addr =3D 0; + + crg_udc->udc_res =3D platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!crg_udc->udc_res) { + dev_err(&pdev->dev, "missing memory resource\n"); + return -ENODEV; + } + + crg_udc->mmio_virt_base =3D devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(crg_udc->mmio_virt_base)) { + dev_err(&pdev->dev, "mmio ioremap failed\n"); + return PTR_ERR(crg_udc->mmio_virt_base); + } + + /* set controller device role*/ + writel((readl(crg_udc->mmio_virt_base + CRG_UDC_MODE_REG) | + CRGUDC_ROLE_DEVICE), + crg_udc->mmio_virt_base + CRG_UDC_MODE_REG); + for (i =3D 0; i < CRG_RING_NUM; i++) { + crg_udc->uicr[i] =3D crg_udc->mmio_virt_base + + CRG_UICR_OFFSET + i * CRG_UICR_STRIDE; + + dev_dbg(crg_udc->dev, "crg_udc->uicr[%d] =3D %p\n", i, + crg_udc->uicr[i]); + } + crg_udc->uccr =3D crg_udc->mmio_virt_base + CRG_UCCR_OFFSET; + + crg_udc_reset(crg_udc); + + crg_udc_clear_portpm(crg_udc); + + ret =3D reset_data_struct(crg_udc); + if (ret) { + dev_err(crg_udc->dev, "reset_data_struct error\n"); + goto err0; + } + + init_ep_info(crg_udc); + init_ep0(crg_udc); + + EP0_Start(crg_udc); + + crg_gadget_irq_init(pdev, crg_udc); + + ret =3D usb_add_gadget_udc(&pdev->dev, &crg_udc->gadget); + if (ret) + goto err0; + + udc_gcnt++; + + return 0; + +err0: + return -1; +} + +static void crg_udc_remove(struct platform_device *pdev) +{ + struct crg_gadget_dev *crg_udc =3D platform_get_drvdata(pdev); + u32 tmp =3D 0; + + dev_dbg(crg_udc->dev, "%s %d called\n", __func__, __LINE__); + + crg_udc->device_state =3D USB_STATE_ATTACHED; + crg_vbus_detect(crg_udc, 0); + + usb_del_gadget_udc(&crg_udc->gadget); + + /* set controller host role*/ + tmp =3D readl(crg_udc->mmio_virt_base + CRG_UDC_MODE_REG) & ~0x1; + writel(tmp, crg_udc->mmio_virt_base + CRG_UDC_MODE_REG); + + if (crg_udc->irq) + free_irq(crg_udc->irq, crg_udc); + + platform_set_drvdata(pdev, 0); + + dev_dbg(crg_udc->dev, "%s %d gadget remove\n", __func__, __LINE__); + +} + +static void crg_udc_shutdown(struct platform_device *pdev) +{ + struct crg_gadget_dev *crg_udc =3D platform_get_drvdata(pdev); + + dev_dbg(crg_udc->dev, "%s %d called\n", __func__, __LINE__); + + crg_udc->device_state =3D USB_STATE_ATTACHED; + crg_vbus_detect(crg_udc, 0); + usb_del_gadget_udc(&crg_udc->gadget); + + if (crg_udc->irq) + free_irq(crg_udc->irq, crg_udc); + /* + * Clear the drvdata pointer. + */ + platform_set_drvdata(pdev, 0); +} + +#ifdef CONFIG_PM +static int crg_udc_suspend(struct device *dev) +{ + return 0; +} + +static int crg_udc_resume(struct device *dev) +{ + + + return 0; +} +#else +#define crg_udc_suspend NULL +#define crg_udc_resume NULL +#endif + +static const struct dev_pm_ops crg_udc_pm_ops =3D { + .suspend =3D crg_udc_suspend, + .resume =3D crg_udc_resume, +}; + +static struct platform_driver crg_udc_driver =3D { + .probe =3D crg_udc_probe, + .remove =3D crg_udc_remove, + .shutdown =3D crg_udc_shutdown, + .driver =3D { + .name =3D "crg_udc", + .owner =3D THIS_MODULE, + .pm =3D &crg_udc_pm_ops, + .of_match_table =3D of_match_ptr(of_crg_udc_match), + }, +}; + +static void crg_gadget_exit(void) +{ + platform_driver_unregister(&crg_udc_driver); +} + +static int crg_gadget_init(void) +{ + + return platform_driver_register(&crg_udc_driver); +} + +module_init(crg_gadget_init); +module_exit(crg_gadget_exit); + +MODULE_DESCRIPTION("Corigine USB Device Controller"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/udc/crg_udc.h b/drivers/usb/gadget/udc/crg_= udc.h new file mode 100644 index 000000000000..bb0cd724582c --- /dev/null +++ b/drivers/usb/gadget/udc/crg_udc.h @@ -0,0 +1,364 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ +/* + * Copyright (c) 2019 Corigine, Inc. + * Copyright (c) 2022-2026 Axiado Corporation. + */ + +#ifndef __CRG_UDC_H__ +#define __CRG_UDC_H__ + +#define CRG_UCCR_OFFSET (0x2400) +#define CRG_UICR_OFFSET (0x2500) +#define CRG_UICR_STRIDE (0x20) + +/* corigine usb 3.1 device core register macros */ +struct crg_uccr { + u32 capability; /*0x00*/ + u32 resv0[3]; + + u32 config0; /*0x10*/ + u32 config1; + u32 resv1[2]; + + u32 control; /*0x20*/ + u32 status; + u32 dcbaplo; + u32 dcbaphi; + u32 portsc; + u32 u3portpmsc; + u32 u2portpmsc; + u32 u3portli; + + u32 doorbell; /*0x40*/ + u32 mfindex; + u32 speed_select; + u32 resv3[5]; + + u32 ep_enable; /*0x60*/ + u32 ep_running; + u32 resv4[2]; + + u32 cmd_param0; /*0x70*/ + u32 cmd_param1; + u32 cmd_control; + u32 resv5[1]; + + u32 odb_capability; /*0x80*/ + u32 resv6[3]; + u32 odb_config[8]; + + u32 debug0; /*0xB0*/ +}; + +struct crg_uicr { + u32 iman; + u32 imod; + u32 erstsz; + u32 resv0; + + u32 erstbalo; /*0x10*/ + u32 erstbahi; + u32 erdplo; + u32 erdphi; +}; + +#define SETF_VAR(field, var, fieldval) \ + (((var) & ~(field ## _MASK)) | \ + (((fieldval) << field ## _SHIFT) & (field ## _MASK))) + +#define GETF(field, val) \ + (((val) & (field ## _MASK)) >> (field ## _SHIFT)) + +#define MAKEF_VAR(field, fieldval) \ + (((fieldval) << field ## _SHIFT) & (field ## _MASK)) + +/* interrupt registers array */ +#define CRG_U3DC_IRS_BASE (0x100L) +#define CRG_U3DC_IRS_IMAN(x) \ + (CRG_U3DC_IRS_BASE + (x) * 0x20L + 0x00L) +#define CRG_U3DC_IRS_IMOD(x) \ + (CRG_U3DC_IRS_BASE + (x) * 0x20L + 0x04L) +#define CRG_U3DC_IRS_ERSTSZ(x) \ + (CRG_U3DC_IRS_BASE + (x) * 0x20L + 0x08L) +#define CRG_U3DC_IRS_ERSTBALO(x) \ + (CRG_U3DC_IRS_BASE + (x) * 0x20L + 0x10L) +#define CRG_U3DC_IRS_ERSTBAHI(x) \ + (CRG_U3DC_IRS_BASE + (x) * 0x20L + 0x14L) +#define CRG_U3DC_IRS_ERDPLO(x) \ + (CRG_U3DC_IRS_BASE + (x) * 0x20L + 0x18L) +#define CRG_U3DC_IRS_ERDPHI(x) \ + (CRG_U3DC_IRS_BASE + (x) * 0x20L + 0x20L) + +/* reg config 0 & 1*/ +#define CRG_U3DC_CFG0_MAXSPEED_MASK (0xfL << 0) +#define CRG_U3DC_CFG0_MAXSPEED_FS (0x1L << 0) +#define CRG_U3DC_CFG0_MAXSPEED_HS (0x3L << 0) +#define CRG_U3DC_CFG0_MAXSPEED_SS (0x4L << 0) +#define CRG_U3DC_CFG0_MAXSPEED_SSP (0x5L << 0) + +#define CRG_U3DC_CFG1_CSC_EVENT_EN BIT(0) +#define CRG_U3DC_CFG1_PEC_EVENT_EN BIT(1) +#define CRG_U3DC_CFG1_PPC_EVENT_EN BIT(3) +#define CRG_U3DC_CFG1_PRC_EVENT_EN BIT(4) +#define CRG_U3DC_CFG1_PLC_EVENT_EN BIT(5) +#define CRG_U3DC_CFG1_CEC_EVENT_EN BIT(6) + +#define CRG_U3DC_CFG1_U3_ENTRY_EN BIT(8) +#define CRG_U3DC_CFG1_L1_ENTRY_EN BIT(9) +#define CRG_U3DC_CFG1_U3_RESUME_EN BIT(10) +#define CRG_U3DC_CFG1_L1_RESUME_EN BIT(11) +#define CRG_U3DC_CFG1_INACTIVE_PLC_EN BIT(12) +#define CRG_U3DC_CFG1_U3_RESUME_NORESP_PLC_EN BIT(13) +#define CRG_U3DC_CFG1_U2_RESUME_NORESP_PLC_EN BIT(14) + +#define CRG_U3DC_CFG1_SETUP_EVENT_EN BIT(16) + +/* ctrl register*/ +#define CRG_U3DC_CTRL_RUN BIT(0) +#define CRG_U3DC_CTRL_STOP (0) +#define CRG_U3DC_CTRL_SWRST BIT(1) +#define CRG_U3DC_CTRL_INT_EN BIT(2) +#define CRG_U3DC_CTRL_SYSERR_EN BIT(3) +#define CRG_U3DC_CTRL_EWE BIT(10) +#define CRG_U3DC_CTRL_KP_CNCT BIT(11) + +/*status register*/ +#define CRG_U3DC_STATUS_DEV_CTRL_HALT BIT(0) +#define CRG_U3DC_STATUS_SYS_ERR BIT(2) +#define CRG_U3DC_STATUS_EINT BIT(3) + +/*portsc register*/ +#define CRG_U3DC_PORTSC_CCS BIT(0) +#define CRG_U3DC_PORTSC_PED BIT(1) +#define CRG_U3DC_PORTSC_PP BIT(3) +#define CRG_U3DC_PORTSC_PR BIT(4) + +#define CRG_U3DC_PORTSC_PLS_SHIFT (5) +#define CRG_U3DC_PORTSC_PLS_MASK (0xf << CRG_U3DC_PORTSC_PLS_SHIFT) +#define CRG_U3DC_PORTSC_PLS(fv) (MAKEF_VAR(CRG_U3DC_PORTSC_PLS, (fv))) +#define CRG_U3DC_PORTSC_PLS_GET(v) (GETF(CRG_U3DC_PORTSC_PLS, (v))) + +#define CRG_U3DC_PORTSC_SPEED_SHIFT (10) +#define CRG_U3DC_PORTSC_SPEED_MASK \ + (0xf << CRG_U3DC_PORTSC_SPEED_SHIFT) +#define CRG_U3DC_PORTSC_SPEED(fv) \ + (MAKEF_VAR(CRG_U3DC_PORTSC_SPEED, (fv))) +#define CRG_U3DC_PORTSC_SPEED_GET(v) \ + (GETF(CRG_U3DC_PORTSC_SPEED, (v))) +#define CRG_U3DC_PORTSC_SPEED_FS (0x1) +#define CRG_U3DC_PORTSC_SPEED_LS (0x2) +#define CRG_U3DC_PORTSC_SPEED_HS (0x3) +#define CRG_U3DC_PORTSC_SPEED_SS (0x4) +#define CRG_U3DC_PORTSC_SPEED_SSP (0x5) + +#define CRG_U3DC_PORTSC_LWS BIT(16) +#define CRG_U3DC_PORTSC_CSC BIT(17) +#define CRG_U3DC_PORTSC_PEC BIT(18) +#define CRG_U3DC_PORTSC_PPC BIT(20) +#define CRG_U3DC_PORTSC_PRC BIT(21) +#define CRG_U3DC_PORTSC_PLC BIT(22) +#define CRG_U3DC_PORTSC_CEC BIT(23) +#define CRG_U3DC_PORTSC_WCE BIT(25) +#define CRG_U3DC_PORTSC_WDE BIT(26) +#define CRG_U3DC_PORTSC_WPR BIT(31) + +#define PORTSC_W1C_MASK (CRG_U3DC_PORTSC_CSC | \ + CRG_U3DC_PORTSC_PEC | \ + CRG_U3DC_PORTSC_PPC | \ + CRG_U3DC_PORTSC_PRC | \ + CRG_U3DC_PORTSC_PLC | \ + CRG_U3DC_PORTSC_CEC) +#define PORTSC_WRITE_MASK (~PORTSC_W1C_MASK) + +/* u3portpmsc */ +#define CRG_U3DC_U3PORTPM_U1TMOUT_SHIFT (0) +#define CRG_U3DC_U3PORTPM_U1TMOUT_MASK \ + (0xff << CRG_U3DC_U3PORTPM_U1TMOUT_SHIFT) +#define CRG_U3DC_U3PORTPM_U1TMOUT(fv) \ + (MAKEF_VAR(CRG_U3DC_U3PORTPM_U1TMOUT, (fv))) + +#define CRG_U3DC_U3PORTPM_U2TMOUT_SHIFT (8) +#define CRG_U3DC_U3PORTPM_U2TMOUT_MASK \ + (0xff << CRG_U3DC_U3PORTPM_U2TMOUT_SHIFT) +#define CRG_U3DC_U3PORTPM_U2TMOUT(fv) \ + (MAKEF_VAR(CRG_U3DC_U3PORTPM_U2TMOUT, (fv))) + +#define CRG_U3DC_U3PORTPM_FLA BIT(16) + +#define CRG_U3DC_U3PORTPM_U1IEN_SHIFT (20) +#define CRG_U3DC_U3PORTPM_U1IEN \ + (1L << CRG_U3DC_U3PORTPM_U1IEN_SHIFT) + +#define CRG_U3DC_U3PORTPM_U2IEN_SHIFT (21) +#define CRG_U3DC_U3PORTPM_U2IEN \ + (1L << CRG_U3DC_U3PORTPM_U2IEN_SHIFT) + +#define CRG_U3DC_U3PORTPM_U1AEN_SHIFT (22) +#define CRG_U3DC_U3PORTPM_U1AEN \ + (1L << CRG_U3DC_U3PORTPM_U1AEN_SHIFT) + +#define CRG_U3DC_U3PORTPM_U2AEN_SHIFT (23) +#define CRG_U3DC_U3PORTPM_U2AEN \ + (1L << CRG_U3DC_U3PORTPM_U2AEN_SHIFT) + +#define CRG_U3DC_U3PORTPM_U1U2TMOUT_SHIFT (24) +#define CRG_U3DC_U3PORTPM_U1U2TMOUT_MASK \ + (0xff << CRG_U3DC_U3PORTPM_U1U2TMOUT_SHIFT) + +/* u2portpmsc */ +#define CRG_U3DC_U2PORTPM_RJ_TH_SHIFT (0) +#define CRG_U3DC_U2PORTPM_RJ_TH_MASK \ + (0xf << CRG_U3DC_U2PORTPM_RJ_TH_SHIFT) +#define CRG_U3DC_U2PORTPM_RJ_TH(fv) \ + (MAKEF_VAR(CRG_U3DC_U2PORTPM_RJ_TH, (fv))) + +#define CRG_U3DC_U2PORTPM_DS_TH_SHIFT (4) +#define CRG_U3DC_U2PORTPM_DS_TH_MASK \ + (0xf << CRG_U3DC_U2PORTPM_DS_TH_SHIFT) +#define CRG_U3DC_U2PORTPM_DS_TH(fv) \ + (MAKEF_VAR(CRG_U3DC_U2PORTPM_DS_TH, (fv))) + +#define CRG_U3DC_U2PORTPM_LPM_EN BIT(8) +#define CRG_U3DC_U2PORTPM_RJ_TH_EN BIT(9) +#define CRG_U3DC_U2PORTPM_DS_EN BIT(10) +#define CRG_U3DC_U2PORTPM_SLP_EN BIT(11) +#define CRG_U3DC_U2PORTPM_LPM_FACK BIT(12) +#define CRG_U3DC_U2PORTPM_L1_AEX BIT(13) +#define CRG_U3DC_U2PORTPM_H_B_SHIFT (16) +#define CRG_U3DC_U2PORTPM_H_B_MASK \ + (0xf << CRG_U3DC_U2PORTPM_H_B_SHIFT) +#define CRG_U3DC_U2PORTPM_H_B(fv) \ + (MAKEF_VAR(CRG_U3DC_U2PORTPM_H_B, (fv))) + +#define CRG_U3DC_U2PORTPM_RWE BIT(20) + +#define CRG_U3DC_U2PORTPM_TM_SHIFT (28) +#define CRG_U3DC_U2PORTPM_TM_MASK \ + (0xf << CRG_U3DC_U2PORTPM_TM_SHIFT) +#define CRG_U3DC_U2PORTPM_TM(fv) \ + (MAKEF_VAR(CRG_U3DC_U2PORTPM_TM, (fv))) + +/* doorbell register*/ +#define CRG_U3DC_DB_TARGET_SHIFT (0) +#define CRG_U3DC_DB_TARGET_MASK \ + (0x1f << CRG_U3DC_DB_TARGET_SHIFT) +#define CRG_U3DC_DB_TARGET(fv) \ + (MAKEF_VAR(CRG_U3DC_DB_TARGET, (fv))) + +/* odb registers*/ +#define CRG_U3DC_ODBCFG_2N_OFFSET_SHIFT (0) +#define CRG_U3DC_ODBCFG_2N_OFFSET_MASK \ + (0x3ff << CRG_U3DC_ODBCFG_2N_OFFSET_SHIFT) +#define CRG_U3DC_ODBCFG_2N_OFFSET(fv) \ + (MAKEF_VAR(CRG_U3DC_ODBCFG_2N_OFFSET, (fv))) + +#define CRG_U3DC_ODBCFG_2N_SIZE_SHIFT (10) +#define CRG_U3DC_ODBCFG_2N_SIZE_MASK \ + (0x7 << CRG_U3DC_ODBCFG_2N_SIZE_SHIFT) +#define CRG_U3DC_ODBCFG_2N_SIZE(fv) \ + (MAKEF_VAR(CRG_U3DC_ODBCFG_2N_SIZE, (fv))) + +#define CRG_U3DC_ODBCFG_2N1_OFFSET_SHIFT (16) +#define CRG_U3DC_ODBCFG_2N1_OFFSET_MASK \ + (0x3ff << CRG_U3DC_ODBCFG_2N1_OFFSET_SHIFT) +#define CRG_U3DC_ODBCFG_2N1_OFFSET(fv) \ + (MAKEF_VAR(CRG_U3DC_ODBCFG_2N1_OFFSET, (fv))) + +#define CRG_U3DC_ODBCFG_2N1_SIZE_SHIFT (26) +#define CRG_U3DC_ODBCFG_2N1_SIZE_MASK \ + (0x7 << CRG_U3DC_ODBCFG_2N1_SIZE_SHIFT) +#define CRG_U3DC_ODBCFG_2N1_SIZE(fv) \ + (MAKEF_VAR(CRG_U3DC_ODBCFG_2N1_SIZE, (fv))) + +/* command control register*/ +#define CRG_U3DC_CMD_CTRL_ACTIVE_SHIFT (0) +#define CRG_U3DC_CMD_CTRL_ACTIVE \ + (1L << CRG_U3DC_CMD_CTRL_ACTIVE_SHIFT) +#define CRG_U3DC_CMD_CTRL_IOC_SHIFT (1) +#define CRG_U3DC_CMD_CTRL_IOC_EN \ + (1L << CRG_U3DC_CMD_CTRL_IOC_SHIFT) + +#define CRG_U3DC_CMD_CTRL_TYPE_SHIFT (4) +#define CRG_U3DC_CMD_CTRL_TYPE_MASK \ + (0xf << CRG_U3DC_CMD_CTRL_TYPE_SHIFT) +#define CRG_U3DC_CMD_CTRL_TYPE(fv) \ + (MAKEF_VAR(CRG_U3DC_CMD_CTRL_TYPE, (fv))) + +#define CRG_U3DC_CMD_CTRL_STATUS_SHIFT (16) +#define CRG_U3DC_CMD_CTRL_STATUS_MASK \ + (0xf << CRG_U3DC_CMD_CTRL_STATUS_SHIFT) +#define CRG_U3DC_CMD_CTRL_STATUS(fv) \ + (MAKEF_VAR(CRG_U3DC_CMD_CTRL_STATUS, (fv))) +#define CRG_U3DC_CMD_CTRL_STATUS_GET(v) \ + (GETF(CRG_U3DC_CMD_CTRL_STATUS, (v))) + +#define CRG_U3DC_CMD_INIT_EP0 (0L) +#define CRG_U3DC_CMD_UPDATE_EP0 (1L) +#define CRG_U3DC_CMD_SET_ADDRESS (2L) +#define CRG_U3DC_CMD_SEND_DEV_NOTIFY (3L) +#define CRG_U3DC_CMD_CONFIG_EP (4L) +#define CRG_U3DC_CMD_SET_HALT (5L) +#define CRG_U3DC_CMD_CLR_HALT (6L) +#define CRG_U3DC_CMD_RST_SEQNUM (7L) +#define CRG_U3DC_CMD_STOP_EP (8L) +#define CRG_U3DC_CMD_SET_TR_DQPTR (9L) +#define CRG_U3DC_CMD_FORCE_FLOW_CTRL (10L) +#define CRG_U3DC_CMD_REQ_LDM_EXCHAG (11L) + +/* int register*/ +/* iman bits*/ +#define CRG_U3DC_IMAN_INT_PEND BIT(0) +#define CRG_U3DC_IMAN_INT_EN BIT(1) + +/* erdp bits*/ +#define CRG_U3DC_ERDPLO_EHB BIT(3) +#define CRG_U3DC_ERDPLO_ADDRLO(fv) ((fv) & 0xfffffff0) + +/*command params*/ +/*command0 init ep0*/ +#define CRG_CMD0_0_DQPTRLO_SHIFT (4) +#define CRG_CMD0_0_DQPTRLO_MASK \ + (0x0fffffff << CRG_CMD0_0_DQPTRLO_SHIFT) + +#define CRG_CMD0_0_DCS_SHIFT (0) +#define CRG_CMD0_0_DCS_MASK (0x1 << CRG_CMD0_0_DCS_SHIFT) +#define CRG_CMD0_0_DCS(fv) (MAKEF_VAR(CRG_CMD0_0_DCS, (fv))) + +/*command1 update ep0 */ +#define CRG_CMD1_0_MPS_SHIFT (16) +#define CRG_CMD1_0_MPS_MASK (0xffff << CRG_CMD1_0_MPS_SHIFT) +#define CRG_CMD1_0_MPS(fv) (MAKEF_VAR(CRG_CMD1_0_MPS, (fv))) + +/*command2 set addr */ +#define CRG_CMD2_0_DEV_ADDR_SHIFT (0) +#define CRG_CMD2_0_DEV_ADDR_MASK (0xff << CRG_CMD2_0_DEV_ADDR_SHIFT) +#define CRG_CMD2_0_DEV_ADDR(fv) (MAKEF_VAR(CRG_CMD2_0_DEV_ADDR, (fv))) + +#define CRG_UDC_MODE_REG 0x20fc +/* Vendor specific register */ +#define CRG_UDC_VENDOR_REG 0x210c +#define CRG_UDC_VBUS_DETECT BIT(26) +/*command type*/ +enum crg_cmd_type { + CRG_CMD_INIT_EP0 =3D 0, + CRG_CMD_UPDATE_EP0_CFG =3D 1, + CRG_CMD_SET_ADDR =3D 2, + CRG_CMD_SEND_DEV_NOTIFICATION =3D 3, + CRG_CMD_CONFIG_EP =3D 4, + CRG_CMD_SET_HALT =3D 5, + CRG_CMD_CLEAR_HALT =3D 6, + CRG_CMD_RESET_SEQNUM =3D 7, + CRG_CMD_STOP_EP =3D 8, + CRG_CMD_SET_TR_DQPTR =3D 9, + CRG_CMD_FORCE_FLOW_CONTROL =3D 10, + CRG_CMD_REQ_LDM_EXCHANGE =3D 11 +}; + +struct crg_gadget_dev; + +struct crg_udc_platdata { + int num_out_eps; + int num_in_eps; +}; + +#endif /* __CRG_UDC_H__ */ --=20 2.34.1 From nobody Sat Feb 7 09:46:50 2026 Received: from PH7PR06CU001.outbound.protection.outlook.com (mail-westus3azon11020134.outbound.protection.outlook.com [52.101.201.134]) (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 5667B366DAC; Mon, 2 Feb 2026 13:16:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.201.134 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770038220; cv=fail; b=TdL3lFHo8lpJPMnsqlX+Ml4UhrWmzSmuR18D0ZBK4g4E22s6u+iqtCJlO8XIUwQnASYA4DKia2kZoRymZOoOYEVS0E4zv3V478IphIi/N5KHPfvN/z+gxK8byvEmAO50O42DIYWRyZ+mhryLXlfB8+OyZNzXXUrHtVY44NEHuL0= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770038220; c=relaxed/simple; bh=a6qvZkig+pybK/x4cqEI0Br3sS95b4VbSIeqdNAr0wE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=V6t3nA5NU51xlm78aSU1zp7P4Nuig5e951AZeUUmi4f44xuizeMdQr64J1sbK+q9j/E5o58aeTUET6jb/lDxErqQP7/fBZcE21I5023t4jS7z2ZY0/lFNC0ZSZVwz9J1Y737YOuzs3+jDuzZYb+u7kg7JTkUyedLMYxlJuy3CV0= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=axiado.com; spf=pass smtp.mailfrom=axiado.com; dkim=pass (2048-bit key) header.d=axiado.com header.i=@axiado.com header.b=JAp7Nzo5; arc=fail smtp.client-ip=52.101.201.134 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=axiado.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=axiado.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=axiado.com header.i=@axiado.com header.b="JAp7Nzo5" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=LUzow0aNliCr5yP3rdhRrsm18qhc/mXa8lUdzCwhLdc/E+8HoaUmSnoykciFYffzaeVjYNDo1vd2hoC+GIXUwrq8YGOSnFheNaRt5r2udUmbvAc0z6cjjAqgX3fQoBjU2EF3iahmMa/OG814M/tE60mVcb7yPlwWsaGdDq4DmTzj1EZ6CsNPAan5dQ/OWi+yU04N4Mzujxe/AV/8uD1TVw6JR5JG5TtOHWNUahrXLJ2JyfWloGEYHRu8KTTnom3jcAo69qbS3q8r1QXdLa8q79f4CJllBKeExMB5ERpk8xcAlqIcIXz9816emE6ffJXWVI1CqaMlTt6SIeec9LVYIA== 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=XE/gUTpMp05dQTr74GUgf3DlEpZZ4za0PyRVDLu5DXo=; b=W8UKcq/sB6agHMD+jfDAwQJpR+LBRrohMq1HmK8nO65yEzqp2H9gZ17w43pSCqTFa3rwzJFhD7TGvOzYpfCxPGRm3sMDK706hi7ynQss7/90cDdsJHHKPh1Mf2duj8cnFzonB3z29mpdgRXe3fvzCa74NGW6TVVCJQ3KXyT4tablUlkcsOJDkZeWHPN+IUbkzC3Itnt0A7DdbZMBuOngpa3vyabMD3+6F/BExrBAhlX0YvIpDGnIuvS9nldDj0gEVbefANnarYT7dS6i5cpo8n5cH0IE8A4tBDkvmvzDM8A93gLYxCl3vFA5+N6upAaCFoo0BSL03p3aVORbWizExg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=fail (sender ip is 4.227.125.105) smtp.rcpttodomain=vger.kernel.org smtp.mailfrom=axiado.com; dmarc=none action=none header.from=axiado.com; dkim=none (message not signed); arc=none (0) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=axiado.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=XE/gUTpMp05dQTr74GUgf3DlEpZZ4za0PyRVDLu5DXo=; b=JAp7Nzo50x6Av264w2Sfz2TKNca5biynu71I1q4nw6LQqMB3ODvsnp8JBPM0Y26F5wgl682e7wLV+RvU45F2DfoTMPyFp2Cb9B1hh6AHCMUDkgZ/6Fbs4C0VhhYntlR+z57mj8qCk0UTJbYP6E5rn/BqlbP0IMqHn2l1S+GKmuEVoCdcmIFn0YMCL6FRji/c+Q12Etih2qAfFCOFRlegMUeKmkkhRsafb6XzbYmk2EQ3aDDj0SREYGv7I5w3odsNyd5Kb/ec6mvC/xP9tTmpzxwqkdwXzOn5X3w4BPCihFUWNlGKeyG+b/fZpnqwIAMm9RWosSjRTpUYY4K1/b2AWg== Received: from SJ0PR13CA0225.namprd13.prod.outlook.com (2603:10b6:a03:2c1::20) by SA3PR18MB5626.namprd18.prod.outlook.com (2603:10b6:806:396::11) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9587.12; Mon, 2 Feb 2026 13:16:55 +0000 Received: from SJ5PEPF00000203.namprd05.prod.outlook.com (2603:10b6:a03:2c1:cafe::29) by SJ0PR13CA0225.outlook.office365.com (2603:10b6:a03:2c1::20) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.9587.12 via Frontend Transport; Mon, 2 Feb 2026 13:16:48 +0000 X-MS-Exchange-Authentication-Results: spf=fail (sender IP is 4.227.125.105) smtp.mailfrom=axiado.com; dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=axiado.com; Received-SPF: Fail (protection.outlook.com: domain of axiado.com does not designate 4.227.125.105 as permitted sender) receiver=protection.outlook.com; client-ip=4.227.125.105; helo=[127.0.0.1]; Received: from [127.0.0.1] (4.227.125.105) by SJ5PEPF00000203.mail.protection.outlook.com (10.167.244.36) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.9587.10 via Frontend Transport; Mon, 2 Feb 2026 13:16:54 +0000 From: Vladimir Moravcevic Date: Mon, 02 Feb 2026 05:16:30 -0800 Subject: [PATCH 3/3] MAINTAINERS: Add entries for the Axiado USB UDC Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260202-axiado-ax3000-usb-device-controller-v1-3-45ce0a8b014f@axiado.com> References: <20260202-axiado-ax3000-usb-device-controller-v1-0-45ce0a8b014f@axiado.com> In-Reply-To: <20260202-axiado-ax3000-usb-device-controller-v1-0-45ce0a8b014f@axiado.com> To: Krutik Shah , Prasad Bolisetty , Greg Kroah-Hartman , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: linux-usb@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, openbmc@lists.ozlabs.org, Vladimir Moravcevic X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1770038210; l=1165; i=vmoravcevic@axiado.com; s=20250904; h=from:subject:message-id; bh=a6qvZkig+pybK/x4cqEI0Br3sS95b4VbSIeqdNAr0wE=; b=Y+LRgCQrxVPRFnbFVYYY4wCtp2aBj9UntFkjIwHv6moaUP+ddKpQxuksrQ/b0efv5rOhw0YmB QJq0dHRnS05BDUXfWKpCQ/BKCYMmoV/7YJ58H4xYzjq3YWXSUiAnM9s X-Developer-Key: i=vmoravcevic@axiado.com; a=ed25519; pk=iiyhWhM1F4HlCbbW3I3qKZhPCE8JsCrDQMgCBRg4YMA= X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: SJ5PEPF00000203:EE_|SA3PR18MB5626:EE_ X-MS-Office365-Filtering-Correlation-Id: 232cbf40-5070-4d69-978e-08de625d5670 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|82310400026|376014|36860700013|1800799024|7053199007; X-Microsoft-Antispam-Message-Info: =?utf-8?B?NVNzaEhSR0hkYmdNb0VyMG04ZG5zNHBlQXd2Mnc4aEI3NXBFM0t5bnhVOWV1?= =?utf-8?B?TXg5QjFUM210a0picGJXc2wvWk41a3lrZVRVcW1Ra29xYXZzdHBUZURQRnZM?= =?utf-8?B?ZXBxenhvazBFUUx4bHFQSWpac1ZxTDZ2LzViNXg2amJod3NJMW9TeWl1bVda?= =?utf-8?B?RlZkbTFsZWlwWEw0eGQ5SVBOdmU2ZFVvWHlrTk1hVHRzVWZwZ1htM1N5Tzk0?= =?utf-8?B?MXRqOHpWYkVGb1p6dmVraGRMN09kOHd4bVZ1NkdCV3NpQTI5RWpBV05XdmpP?= =?utf-8?B?bTNWcmdSdzRLU0x3bEtPaDE5OUdlU0lPSzZCejFhT004VDBEYlRtNGxrNmNv?= =?utf-8?B?OVJwV3FvVWgvWFZXaVhrc1FkaTdvREdsSi9xcXBIUnpHZS94L2ZvWDl6ODRq?= =?utf-8?B?SHpmZW50dDhKc21XT2hERUVvckJyVm9MVWRzM0JISVExRStpczl5Z0VTSzlS?= =?utf-8?B?OTZUdjJPd0JyWXpTM25vemx5cFFKRk9ubW1JQ2N3S2gzdHBTNGVmWlVxcFNE?= =?utf-8?B?cFN3aTdxanNsaVZ3N1lUTTdTZE14Qm5jWnNFMEZFWFE2VjlIT21ObEo0QTFP?= =?utf-8?B?Q0tUUHhwSmU2VnlmamRFYTJTc1V0T09RMGx4VUFqTEZ4T1B4dWYxcUEwV20v?= =?utf-8?B?dmFZdHZ0RnRZUjJET2txUEtOM0tQMjZKSzRLMmxxSDdmT0ZuRUpHM1BqQjky?= =?utf-8?B?enZaSDdFeW9nRVN0aXFmYml0TTVaQVB4MFlNVG5sQTNNbEtpanhNQ2Y1RmJQ?= =?utf-8?B?L3hobFY5bW8rR1ArZlZZM1ZYVXVubC9LUm9Ebk0vV3VpcHdRQ0t4SFdSbXN5?= =?utf-8?B?blpCbGlQYTBWVG00SlJGVUd5V1hMclhRQkJQZlNYVC9OR0tVZDJJODlCa29T?= =?utf-8?B?akMwQW8xdDhOV1h0aGJLZVIybGdEaEpiNkpvcWw4VW5BTjlKdDBQaE9UbEpG?= =?utf-8?B?aEI5OWNOY0Y5b2VWL3pGZmdVa201SlZia1RtTzBFWmJqZWZYNHF4NkZlOGxh?= =?utf-8?B?YVFwN203cXY4NXJFUVpUcE44ajBOR0ZKcVk0NlNrUmhVa1JvN3dGWGhZSkli?= =?utf-8?B?eXlVWnhYNUlLUmNHOGFxRWR0Q1NSbWVuNjVUT1RPcmJkUk9yQ2dhVFhhSlM1?= =?utf-8?B?ZUdETkVDeHdZVGpuQTI5cFJOUVd3NnpydkkwNVgzczh3TGxJNVZZdlhKdURi?= =?utf-8?B?M3BpVkp4L2t1QkdjMzBnVGJtd040TW15K2FZbEoreXd0anU3b3VPR0ZRaFR6?= =?utf-8?B?ZkVTSG94MXNKZ2doUFgrRXZiRzRwK3FpSU9Lcm82ODh3M08yNmNuTlFmejVp?= =?utf-8?B?S2JIVjUyYStkY3ZmVW9kb3dmc0xjM2pSRnFqWnR1RU0rSExKMGt5YUhuNnVE?= =?utf-8?B?c3h1cHUzN3BzRVVSWGRCaHZsb29FMHZxSGRWRWdXRVNKRjUzOWRYYXFLQU1N?= =?utf-8?B?Vlh4UG4xNzJmaVNRMmQ5MGpmN3E5akZpcjFXcnc0d3VoVkhBKzRudk5KWE1C?= =?utf-8?B?aWNuelRzZ0szNUViU1BzeVJUeWYyZlpIUkJIZndlRm83TTdpdG1QeThxYkpD?= =?utf-8?B?dVZEQmlaR3R5ZEpQcGd0dzhQcVo3Q1lLc1BXV3o5NXI0QjB3M20xaHV0Rk5B?= =?utf-8?B?OEtLSmg3WUhhVTFzTms2NkdJTStCTUJlOWxtVFpFcStJQ3Y2UUJXMU1EVVRj?= =?utf-8?B?OTdwZTJOTTkyM2Z3M0pFd1VBSUtMQWZGSjdIU2ZCYmhBRFBzMm9qMzdVck5X?= =?utf-8?B?by90azhGMXRodFBON0dzYm1Kd3poWjJPZkEzdFpQV0NzWWduRTFndUpPd2xI?= =?utf-8?B?RG9TZlRrdUNiQUQ0akZYeW9aRlN3M2pVTGNSbEJvUk52ZDM4Y1R1NlhjMFNy?= =?utf-8?B?Q003RWdZNTdZUGRpQllpRldBTDhtM1hHNWpza3VXVlFuYWVMVkRQV0dKcXdo?= =?utf-8?B?QTFoM045a0RGTUgzV09lS01XV1RSS3ZmUjBzRHpDMG10Wm5NcGFXYU9Fa3ds?= =?utf-8?B?MnlxaFN1REhwV01IRHNiODlYOFR5YmxIUTRnanNTcGJQS3hBK3ZyUnoyMVM5?= =?utf-8?B?UTJZYW5vMllHMWtHZkpMOEU4U0hTSE1ZNTFGUm1hdEZHMGllR0JMdTdVQllm?= =?utf-8?B?KzhHeEdsR1NUb2ppQ0JhdTY3RW85cy9IVWZ2cUxUcktIdVY4cVZBVmVuTkVs?= =?utf-8?B?K1U4OFlxcXFIVHMzMHpqdzVNVnNtc3dNOTJoUEZHNWVzdTc1Wm1lRmRuam92?= =?utf-8?B?bktLWHhmM1hIY0JtRW91VVJhR2JRPT0=?= X-Forefront-Antispam-Report: CIP:4.227.125.105;CTRY:US;LANG:en;SCL:1;SRV:;IPV:CAL;SFV:NSPM;H:[127.0.0.1];PTR:InfoDomainNonexistent;CAT:NONE;SFS:(13230040)(82310400026)(376014)(36860700013)(1800799024)(7053199007);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: DT7ri9IJSoRszv0ibvFSOGZIvxPRBd8dwenzPthuKVmlDQ/Nysk0bgLK8J/hfyiFDibZxusmXlpNFEdIG9c5uxChY58dAGCFRFCc3rOr8BuRdXo4EUOhgaW/OcKdIkM5lqr/XAGq7/yQqE1o8DupuwdMiTnUzPYn09HC2RiKhL78TkNNKliRHcrfWmEWT4BKqmczKW622YJ6GZvksIqqjqGd15qrhbrajXh4cn3BdWrGlv7hZNS919PR6FVPiUiCyvqFZPaW+4zFx2p5v2y3WStEEzN0K8izcTvsqXOiHnpjFbEwcEYYjtHUQa4Zf3OYkG1CvCER77lD7mI/Q8e6ar428KeDvpbgJh66SERomYCN/QCJkbqV6pUj2IJXT0Oz0+x/c3AvsuuoC8BRvGBfWWXvEV9/8jw9XLSzoALvVaJMYxmc3IQzzllqAoQKy5xt X-OriginatorOrg: axiado.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 02 Feb 2026 13:16:54.9812 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 232cbf40-5070-4d69-978e-08de625d5670 X-MS-Exchange-CrossTenant-Id: ff2db17c-4338-408e-9036-2dee8e3e17d7 X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=ff2db17c-4338-408e-9036-2dee8e3e17d7;Ip=[4.227.125.105];Helo=[[127.0.0.1]] X-MS-Exchange-CrossTenant-AuthSource: SJ5PEPF00000203.namprd05.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: SA3PR18MB5626 Add the MAINTAINERS entries for the Axiado USB Device Controller. Co-developed-by: Krutik Shah Signed-off-by: Krutik Shah Co-developed-by: Prasad Bolisetty Signed-off-by: Prasad Bolisetty Signed-off-by: Vladimir Moravcevic --- MAINTAINERS | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 67db88b04537..e63b6b308a3f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4234,6 +4234,16 @@ S: Maintained F: Documentation/devicetree/bindings/sound/axentia,* F: sound/soc/atmel/tse850-pcm5142.c =20 +AXIADO USB UDC DRIVER +M: Krutik Shah +M: Prasad Bolisetty +M: Vladimir Moravcevic +L: linux-usb@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/usb/axiado,ax3000-udc.yaml +F: drivers/usb/gadget/udc/crg_udc.c +F: drivers/usb/gadget/udc/crg_udc.h + AXIS ARTPEC ARM64 SoC SUPPORT M: Jesper Nilsson M: Lars Persson --=20 2.34.1