From patchwork Mon Apr 12 12:12:45 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Peng Fan \(OSS\)" X-Patchwork-Id: 419553 Delivered-To: patch@linaro.org Received: by 2002:a02:c4d2:0:0:0:0:0 with SMTP id h18csp1666185jaj; Mon, 12 Apr 2021 04:54:21 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxjVRSeUArc4ZQ3LKKECE55UKLKSlZpjC0wa5BG/iTVMSg+GC5PJEw0C/uhHVyfk/skdmwp X-Received: by 2002:a17:906:2e14:: with SMTP id n20mr26307174eji.16.1618228461271; Mon, 12 Apr 2021 04:54:21 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1618228461; cv=pass; d=google.com; s=arc-20160816; b=P78kyqVwexiUtvwE9B8hu6EAr31hoNGblScO1MnDd9WDw8RvuA2O0Zp0xft/jD6Erk yUk355fZOZS5XTZiXnEAxr/eRInJe5RZx6x4A6DybXBtnUeCtCPVXBaXa+Bwl8CM2hsL lehbSS9V72UAqQW1ZkADkmUCjdeZJXDhPiviIFK4N5yUnxJheyyio85h7Gs1ZyDtklEf dL5ij6aLgL1u2OhSyM+cheGhuVQaXVPWgJIsdCPx2ilk2wUipdfECz+BAihNB2ePOzPQ 5+H4quC3gN+vn8366pCqfui23Q757fERnthyejR6b2B0goFuRtEAUnfhQ9YVC4gh/+CW Bl6g== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:mime-version :content-transfer-encoding:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature; bh=ubhwOHRCAV8ne+O3XK0i6k/l96Al6HaOt02D1D6sK6E=; b=RCzIJmaXbm5irh2XLm1c5NN0OQ2i9yW9sx+PgkJfeyd04+LV27iFLoff1nVhG62RHV Y5rpEelu9H9L9ci4pntABJLW+wVnJUlYF/iK2xGzg8kre2JxWCSDf2x7VAMLkAh0h6ZT EGjTevRQC+S7HvPB7lh9fVGu1k9yDZvutQwgTV9WJk7sioFGZlmV9uWEFBPaMy3RLfRh fja2TNPoh2/x9dGwySURcycm/7eZ6G2ZD10/smtlKSS7tGpnoCO+voxRqNxG+ReDvrnp AzOxVIxd6M/7TzFTD/1r6cOXHYj8xRSmDTLq0GqhOiupDjcVcQLPiP6SJtcxlBgW/UQG kngw== ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@NXP1.onmicrosoft.com header.s=selector2-NXP1-onmicrosoft-com header.b=kjDef0xF; arc=pass (i=1 spf=pass spfdomain=oss.nxp.com dkim=pass dkdomain=oss.nxp.com dmarc=pass fromdomain=oss.nxp.com); spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 2a01:238:438b:c500:173d:9f52:ddab:ee01 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=nxp.com Return-Path: Received: from phobos.denx.de (phobos.denx.de. [2a01:238:438b:c500:173d:9f52:ddab:ee01]) by mx.google.com with ESMTPS id f7si8179834edd.239.2021.04.12.04.54.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 12 Apr 2021 04:54:21 -0700 (PDT) Received-SPF: pass (google.com: domain of u-boot-bounces@lists.denx.de designates 2a01:238:438b:c500:173d:9f52:ddab:ee01 as permitted sender) client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; Authentication-Results: mx.google.com; dkim=pass header.i=@NXP1.onmicrosoft.com header.s=selector2-NXP1-onmicrosoft-com header.b=kjDef0xF; arc=pass (i=1 spf=pass spfdomain=oss.nxp.com dkim=pass dkdomain=oss.nxp.com dmarc=pass fromdomain=oss.nxp.com); spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 2a01:238:438b:c500:173d:9f52:ddab:ee01 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=nxp.com Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id E74AF82064; Mon, 12 Apr 2021 13:53:50 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=oss.nxp.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=NXP1.onmicrosoft.com header.i=@NXP1.onmicrosoft.com header.b="kjDef0xF"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 7EB4582037; Mon, 12 Apr 2021 13:53:34 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=1.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,FORGED_SPF_HELO,MSGID_FROM_MTA_HEADER,SPF_HELO_PASS autolearn=no autolearn_force=no version=3.4.2 Received: from EUR05-VI1-obe.outbound.protection.outlook.com (mail-vi1eur05on2061b.outbound.protection.outlook.com [IPv6:2a01:111:f400:7d00::61b]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id B998F81F71 for ; Mon, 12 Apr 2021 13:42:11 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=oss.nxp.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=peng.fan@oss.nxp.com ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=m4/S11/hI+lK00oVAAA8oULbCOhNUOUWrWcn97Jq5KojwkP94upvUeqSVuyrTym37NkGTBTYx+KxWRm0xZsUo4h/4EXFEGZeuc8pPdAy+6IurLrGh4knd5PpuuLDDiu7MU1yAbzjiO99bUNUHpGb5gmty4uqTZS6T/nWpIwxn1z2jc53XKqnX7m3qoSbn34YaFvtrx34s2rusib5CGsCJExKX3ak2z4u9YSVWknHBYENFXINUkr18yzihjZ5cY41q7Q1i/aAxmvsI+9WzvzRBuPi1apre7FKPGsx5whxLU8zVpsN8KZ0w8AvTWJFQFwk1OOUEEQhQOWMjRNh80YJFA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=ubhwOHRCAV8ne+O3XK0i6k/l96Al6HaOt02D1D6sK6E=; b=dB1pb6KLtHEV7syHjIL6H1AmuLfvJM4+8hXcWbW/gFHqMvoXryBilEB/DUnmSyp618OHybcWttQJzj9i/Ne9T2tiSvTZgD93tTHdsN1DdGzVcVSFMR4QQ6NYTD3SbtsLLY8rjz1ZdR19lUV5yAePFLT6ZcgaL8nXo5ohTx96R/L0mBLkyvLDKRoWMb1JGgj++FJ6G7IB1Le041CMa3zmmbJ8W44kDiDe2V5iAjBjWbfnbLWTo1lygOe+dIcnx0IIbNdlxer6UV6z9MgDX/sLiiaI6soJI4hKQ/3dDcSXY0H3+G8qGrVPPE63MHIW7nsHCkk4TzPVo4wz72rCRKcatg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=oss.nxp.com; dmarc=pass action=none header.from=oss.nxp.com; dkim=pass header.d=oss.nxp.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=NXP1.onmicrosoft.com; s=selector2-NXP1-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=ubhwOHRCAV8ne+O3XK0i6k/l96Al6HaOt02D1D6sK6E=; b=kjDef0xF0Ba3zT0HZCZl60uz/bc11w3YY6VP8yNjOmkLB9eRPcOCvaltN2HgPmC3lE23R8Bf9aZ1Q2E+WWX/qgA0+udHfFz8utrDi0XC8M/tVZGWmNXauGLO2rYadOOM1H0BZ20BU4IpjSlE8rIlmlFzGJymhG9QTMEnutJz0ZI= Authentication-Results: denx.de; dkim=none (message not signed) header.d=none; denx.de; dmarc=none action=none header.from=oss.nxp.com; Received: from DB6PR0402MB2760.eurprd04.prod.outlook.com (2603:10a6:4:a1::14) by DB7PR04MB5244.eurprd04.prod.outlook.com (2603:10a6:10:21::24) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4020.18; Mon, 12 Apr 2021 11:42:08 +0000 Received: from DB6PR0402MB2760.eurprd04.prod.outlook.com ([fe80::c57a:6964:f72c:21cf]) by DB6PR0402MB2760.eurprd04.prod.outlook.com ([fe80::c57a:6964:f72c:21cf%11]) with mapi id 15.20.3999.032; Mon, 12 Apr 2021 11:42:07 +0000 From: "Peng Fan (OSS)" To: sbabic@denx.de, festevam@gmail.com Cc: u-boot@lists.denx.de, uboot-imx@nxp.com, Peng Fan Subject: [PATCH 16/37] arm: imx8ulp: add clock support Date: Mon, 12 Apr 2021 20:12:45 +0800 Message-Id: <20210412121306.11484-17-peng.fan@oss.nxp.com> X-Mailer: git-send-email 2.30.0 In-Reply-To: <20210412121306.11484-1-peng.fan@oss.nxp.com> References: <20210412121306.11484-1-peng.fan@oss.nxp.com> X-Originating-IP: [119.31.174.71] X-ClientProxiedBy: HK2PR0401CA0009.apcprd04.prod.outlook.com (2603:1096:202:2::19) To DB6PR0402MB2760.eurprd04.prod.outlook.com (2603:10a6:4:a1::14) MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 Received: from linux-1xn6.ap.freescale.net (119.31.174.71) by HK2PR0401CA0009.apcprd04.prod.outlook.com (2603:1096:202:2::19) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4020.16 via Frontend Transport; Mon, 12 Apr 2021 11:42:04 +0000 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: f5feea33-53bf-462f-1055-08d8fda7ff97 X-MS-TrafficTypeDiagnostic: DB7PR04MB5244: X-MS-Exchange-SharedMailbox-RoutingAgent-Processed: True X-MS-Exchange-Transport-Forked: True X-Microsoft-Antispam-PRVS: X-MS-Oob-TLC-OOBClassifiers: OLM:4714; X-MS-Exchange-SenderADCheck: 1 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: CwI8ze7OuNHz5DGlgyQ8O/vxv+sCm2WO3Tx4KHXieqPS0R2nLaN4Q83sCPxFLUFL5q1VVTCHIhfUe4juZaV+ZdFmZTEZR35YFG0ZEgjE6n70K7uNLzE3DrSm7CP8J2GTj235QmTh24uYGdenyNNeoXNGGSj3hAy47alnFVf5okNO30M1cIObFTioE6p5/itQsFKQkJhYWmQFhE6E7fYd6c/P/A59yxexfehbvGNetFclosryTRlGJBnUOl/sL0wQcnNY+cvKWiRnoRTTluUc92hmkbxHUsZmT9uZP2cQ7swsAYnQ2hRC5UuXCgJlgsrfXGUvCeHn9FvesuIN714dztIgcfNqK/0tbK5o06GAbY6t/MoHlwuXGDiizhUEBZzNjxV64rPlrSDqePgMmlNAlyTSjwAD2+H6tu7Hx5znB/+/ReGjBwBxd80ju+4/6heGIxn99Q/loKaWnJs8/OjtqCp2kmReYSkuRZEyHvJzI/iY4PlY0Cg2u6deYRKV9b5MiuieQQYAYMLSNucCNzQdFfC6eYU7qzg5YZsVkoieBqltGKrHH3ED8mIwPsr+nXnU6Sc8BV8reo6r5Q92UyRw600NkIv09mnPpFRth6he2xxBRoEFMxU0NRgSLpkpSxsVZDIA/6xG74+JccLTPJe7Mo2sB6Fcv4EQSS6ehJnOpXO4GHEk7A/tj7Drgi92x6qPjiqmCWupguOq0cY14KuYlsxJdcpLhYnIjjyjkuFqAu0SsNFdqlHfS4j/yPH2T/Fs X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:DB6PR0402MB2760.eurprd04.prod.outlook.com; PTR:; CAT:NONE; SFS:(4636009)(376002)(346002)(136003)(366004)(39860400002)(396003)(16526019)(30864003)(26005)(186003)(6506007)(38100700002)(66946007)(66556008)(66476007)(316002)(8936002)(38350700002)(4326008)(956004)(478600001)(6486002)(5660300002)(6666004)(86362001)(6512007)(2616005)(2906002)(8676002)(52116002)(83380400001)(1076003)(32563001)(579004)(414714003)(473944003); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData: I4Z8Gb3QtmXkudjzKoZl7kdU8NEb9eQko1mPqtqSFXEeExuj+gERv/EyL/wkplhpT4hrAXu4mVCKzmGnKI1WUSeOw6s1rNOhT0Sc30hgG34tbHYgmrs2KeaKN5y569kjrFUAaJpwW6XgVTYsDc611etkNAOiaAYiX0hmFxOnPKJujz85vYD4cW4xso8UwHUtjxFEU7bRpITtqsJaqqF41MuptQwyeg2NwM8niFfRiDILTTBm6gS7rLGBhEauQSr3tjIlWt18GjxSodIfM24+cGApBK6XXGdz/hERidX9gkkPbq3hEqmo8WDJ4TRRo1U5nqlhduePKhCqANwIN9VLhWWbO/Ka1NV5R6EBDxu0QuiK6RV81+aW5WwpN8JGGWW4Xgb20TN7ZuNiIMVcgTXBb6EugVy44vXwSvBDbesgYi2qz0v3QaWttrrqEoicui1BZvPdzW/y74s+0tiNRhEci0V3v4yLftTDmGZlfEItV5OdkJGK9ja2T6us4I/qNgFxnngDPLckutzkT5bnoFgdRmTY2c2mwcG3Yz3GgiL2TNjQnSAWzL7j719ab1F9OmgIOJIx4sJ6VMAB4p1Rkmi8xSEvbaJoYmvMMXXQrlUc6d9UGFoHastSBgySAzSAhWyzwlqMFnNWYnTTw+n2pTbRatDQBkPdhChETl5TZZH2n7vin1L+46AOFJO32PZZ7fKRncaqrDyVPE2fHb8MWxebm7kg7zvoh0H/kG7QxYUxnoMMYPHmfnQf15/UrzhJoQvb37MpbZj/LKuM0GtMbqaxpEtfN2TU6GKZJkbwjynzVf5W7u810Zt5tZfus9yeLwvinYBhmr/TaKtFCMXsZhWUVb+9gTzNa26Ena2PXW4qJw64qLWBRJCVL1zgy83ZuLW57UUMhk3K53GbQ050EIJfIgskM5RscfnXp/HE4DoyIHP4neqaZiPEDyiCfBq4P5sMMJ+KTNAGnHi+D038+An91k3cIZlaW2hqe8ue+5utLtipIaL4htHBkNy0vv4NA9D27tw54xbpQBUAObDq5RXzwV6k4ejsvxGVEcUssJIocVkHTLWpZIAVTJNcpAHFaF3wZVIopUe1JUuluO24lADKE2u4v7XnCLLb7UNM5Ft+HmR/H0T5spNpb6VtWuPYUiglVEqkUjs5ilFp3O/AfqB2fUXNRBh53IqG2QE2vQmWxTgFkfquQt+Pn2ga6Ry8MO9UL4rxmtuaGkIcRPpbm53CWlZYeNJvclIHivJRLSSC9Q+xo9ovjGEk8kA9kCe/juL4dBH70J9IriMuOJ4ZoCvygNdgFqL3KePdjOUP1NLUWRWmEhbHO9b/AKrVlflZMYsbS8Bep+8W9bglkTgAlv04GA== X-OriginatorOrg: oss.nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: f5feea33-53bf-462f-1055-08d8fda7ff97 X-MS-Exchange-CrossTenant-AuthSource: DB6PR0402MB2760.eurprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 12 Apr 2021 11:42:07.0317 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: mH486r0ANr9NKwWL5n+STLjNlR9D2Mufb+3Uamkno3/FFK6QZ6awVi4N3MfXuacaRMDxpug3+4ZeI0VA3u6uFA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: DB7PR04MB5244 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.102.4 at phobos.denx.de X-Virus-Status: Clean From: Peng Fan Add i.MX8ULP clock support Signed-off-by: Peng Fan --- arch/arm/include/asm/arch-imx8ulp/cgc.h | 130 ++++++ arch/arm/include/asm/arch-imx8ulp/clock.h | 9 +- arch/arm/include/asm/arch-imx8ulp/imx-regs.h | 1 + arch/arm/include/asm/arch-imx8ulp/pcc.h | 139 ++++++ arch/arm/mach-imx/imx8ulp/Makefile | 2 +- arch/arm/mach-imx/imx8ulp/cgc.c | 459 +++++++++++++++++++ arch/arm/mach-imx/imx8ulp/clock.c | 367 ++++++++++++++- arch/arm/mach-imx/imx8ulp/pcc.c | 449 ++++++++++++++++++ arch/arm/mach-imx/imx8ulp/soc.c | 3 + 9 files changed, 1555 insertions(+), 4 deletions(-) create mode 100644 arch/arm/include/asm/arch-imx8ulp/cgc.h create mode 100644 arch/arm/include/asm/arch-imx8ulp/pcc.h create mode 100644 arch/arm/mach-imx/imx8ulp/cgc.c create mode 100644 arch/arm/mach-imx/imx8ulp/pcc.c -- 2.30.0 diff --git a/arch/arm/include/asm/arch-imx8ulp/cgc.h b/arch/arm/include/asm/arch-imx8ulp/cgc.h new file mode 100644 index 0000000000..34a15fb59c --- /dev/null +++ b/arch/arm/include/asm/arch-imx8ulp/cgc.h @@ -0,0 +1,130 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2021 NXP + */ + +#ifndef _ASM_ARCH_CGC_H +#define _ASM_ARCH_CGC_H + +enum cgc1_clk { + DUMMY0_CLK, + DUMMY1_CLK, + LPOSC, + XBAR_BUSCLK, + SOSC, + SOSC_DIV1, + SOSC_DIV2, + SOSC_DIV3, + FRO, + FRO_DIV1, + FRO_DIV2, + FRO_DIV3, + PLL2, + PLL3, + PLL3_VCODIV, + PLL3_PFD0, + PLL3_PFD1, + PLL3_PFD2, + PLL3_PFD3, + PLL3_PFD0_DIV1, + PLL3_PFD0_DIV2, + PLL3_PFD1_DIV1, + PLL3_PFD1_DIV2, + PLL3_PFD2_DIV1, + PLL3_PFD2_DIV2, + PLL3_PFD3_DIV1, + PLL3_PFD3_DIV2, +}; + +struct cgc1_regs { + u32 verid; + u32 rsvd1[4]; + u32 ca35clk; + u32 rsvd2[2]; + u32 clkoutcfg; + u32 rsvd3[4]; + u32 nicclk; + u32 xbarclk; + u32 rsvd4[21]; + u32 clkdivrst; + u32 rsvd5[29]; + u32 soscdiv; + u32 rsvd6[63]; + u32 frodiv; + u32 rsvd7[189]; + u32 pll2csr; + u32 rsvd8[3]; + u32 pll2cfg; + u32 rsvd9; + u32 pll2denom; + u32 pll2num; + u32 pll2ss; + u32 rsvd10[55]; + u32 pll3csr; + u32 pll3div_vco; + u32 pll3div_pfd0; + u32 pll3div_pfd1; + u32 pll3cfg; + u32 pll3pfdcfg; + u32 pll3denom; + u32 pll3num; + u32 pll3ss; + u32 pll3lock; + u32 rsvd11[54]; + u32 enetstamp; + u32 rsvd12[67]; + u32 pllusbcfg; + u32 rsvd13[59]; + u32 aud_clk1; + u32 sai5_4_clk; + u32 tpm6_7clk; + u32 mqs1clk; + u32 rsvd14[60]; + u32 lvdscfg; +}; + +struct cgc2_regs { + u32 verid; + u32 rsvd1[4]; + u32 hificlk; + u32 rsvd2[2]; + u32 clkoutcfg; + u32 rsvd3[6]; + u32 niclpavclk; + u32 ddrclk; + u32 rsvd4[19]; + u32 clkdivrst; + u32 rsvd5[29]; + u32 soscdiv; + u32 rsvd6[63]; + u32 frodiv; + u32 rsvd7[253]; + u32 pll4csr; + u32 pll4div_vco; + u32 pll4div_pfd0; + u32 pll4div_pfd1; + u32 pll4cfg; + u32 pll4pfdcfg; + u32 pll4denom; + u32 pll4num; + u32 pll4ss; + u32 pll4lock; + u32 rsvd8[128]; + u32 aud_clk2; + u32 sai7_6_clk; + u32 tpm8clk; + u32 rsvd9[1]; + u32 spdifclk; + u32 rsvd10[59]; + u32 lvdscfg; +}; + +u32 cgc1_clk_get_rate(enum cgc1_clk clk); +void cgc1_pll3_init(void); +void cgc1_pll2_init(void); +void cgc1_soscdiv_init(void); +void cgc1_init_core_clk(void); +void cgc2_pll4_init(void); +void cgc2_ddrclk_config(u32 src, u32 div); +u32 cgc1_sosc_div(enum cgc1_clk clk); +#endif diff --git a/arch/arm/include/asm/arch-imx8ulp/clock.h b/arch/arm/include/asm/arch-imx8ulp/clock.h index e145c33f01..58e3356e32 100644 --- a/arch/arm/include/asm/arch-imx8ulp/clock.h +++ b/arch/arm/include/asm/arch-imx8ulp/clock.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* - * Copyright 2020 NXP + * Copyright 2021 NXP */ #ifndef _ASM_ARCH_IMX8ULP_CLOCK_H @@ -17,6 +17,7 @@ enum mxc_clock { MXC_DDR_CLK, MXC_ESDHC_CLK, MXC_ESDHC2_CLK, + MXC_ESDHC3_CLK, MXC_I2C_CLK, }; @@ -26,9 +27,15 @@ u32 get_lpuart_clk(void); int enable_i2c_clk(unsigned char enable, unsigned int i2c_num); u32 imx_get_i2cclk(unsigned int i2c_num); #endif +void enable_usboh3_clk(unsigned char enable); +int enable_usb_pll(ulong usb_phy_base); #ifdef CONFIG_MXC_OCOTP void enable_ocotp_clk(unsigned char enable); #endif void init_clk_usdhc(u32 index); +void init_clk_fspi(int index); +void init_clk_ddr(void); +int set_ddr_clk(u32 phy_freq_mhz); void clock_init(void); +void cgc1_enet_stamp_sel(u32 clk_src); #endif diff --git a/arch/arm/include/asm/arch-imx8ulp/imx-regs.h b/arch/arm/include/asm/arch-imx8ulp/imx-regs.h index 52831d7262..9f76bc85fc 100644 --- a/arch/arm/include/asm/arch-imx8ulp/imx-regs.h +++ b/arch/arm/include/asm/arch-imx8ulp/imx-regs.h @@ -7,6 +7,7 @@ #define _IMX8ULP_REGS_H_ #define ARCH_MXC +#include #include #define PBRIDGE0_BASE 0x28000000 diff --git a/arch/arm/include/asm/arch-imx8ulp/pcc.h b/arch/arm/include/asm/arch-imx8ulp/pcc.h new file mode 100644 index 0000000000..091d0175dd --- /dev/null +++ b/arch/arm/include/asm/arch-imx8ulp/pcc.h @@ -0,0 +1,139 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2021 NXP + */ + +#ifndef _ASM_ARCH_IMX8ULP_PCC_H +#define _ASM_ARCH_IMX8ULP_PCC_H + +#include + +enum pcc3_entry { + DMA1_MP_PCC3_SLOT = 1, + DMA1_CH0_PCC3_SLOT = 2, + DMA1_CH1_PCC3_SLOT = 3, + DMA1_CH2_PCC3_SLOT = 4, + DMA1_CH3_PCC3_SLOT = 5, + DMA1_CH4_PCC3_SLOT = 6, + DMA1_CH5_PCC3_SLOT = 7, + DMA1_CH6_PCC3_SLOT = 8, + DMA1_CH7_PCC3_SLOT = 9, + DMA1_CH8_PCC3_SLOT = 10, + DMA1_CH9_PCC3_SLOT = 11, + DMA1_CH10_PCC3_SLOT = 12, + DMA1_CH11_PCC3_SLOT = 13, + DMA1_CH12_PCC3_SLOT = 14, + DMA1_CH13_PCC3_SLOT = 15, + DMA1_CH14_PCC3_SLOT = 16, + DMA1_CH15_PCC3_SLOT = 17, + DMA1_CH16_PCC3_SLOT = 18, + DMA1_CH17_PCC3_SLOT = 19, + DMA1_CH18_PCC3_SLOT = 20, + DMA1_CH19_PCC3_SLOT = 21, + DMA1_CH20_PCC3_SLOT = 22, + DMA1_CH21_PCC3_SLOT = 23, + DMA1_CH22_PCC3_SLOT = 24, + DMA1_CH23_PCC3_SLOT = 25, + DMA1_CH24_PCC3_SLOT = 26, + DMA1_CH25_PCC3_SLOT = 27, + DMA1_CH26_PCC3_SLOT = 28, + DMA1_CH27_PCC3_SLOT = 29, + DMA1_CH28_PCC3_SLOT = 30, + DMA1_CH29_PCC3_SLOT = 31, + DMA1_CH30_PCC3_SLOT = 32, + DMA1_CH31_PCC3_SLOT = 33, + MU0_B_PCC3_SLOT = 34, + MU3_A_PCC3_SLOT = 35, + LLWU1_PCC3_SLOT = 38, + UPOWER_PCC3_SLOT = 40, + WDOG3_PCC3_SLOT = 42, + WDOG4_PCC3_SLOT = 43, + XRDC_MGR_PCC3_SLOT = 47, + SEMA42_1_PCC3_SLOT = 48, + ROMCP1_PCC3_SLOT = 49, + LPIT1_PCC3_SLOT = 50, + TPM4_PCC3_SLOT = 51, + TPM5_PCC3_SLOT = 52, + FLEXIO1_PCC3_SLOT = 53, + I3C2_PCC3_SLOT = 54, + LPI2C4_PCC3_SLOT = 55, + LPI2C5_PCC3_SLOT = 56, + LPUART4_PCC3_SLOT = 57, + LPUART5_PCC3_SLOT = 58, + LPSPI4_PCC3_SLOT = 59, + LPSPI5_PCC3_SLOT = 60, +}; + +enum pcc4_entry { + FLEXSPI2_PCC4_SLOT = 1, + TPM6_PCC4_SLOT = 2, + TPM7_PCC4_SLOT = 3, + LPI2C6_PCC4_SLOT = 4, + LPI2C7_PCC4_SLOT = 5, + LPUART6_PCC4_SLOT = 6, + LPUART7_PCC4_SLOT = 7, + SAI4_PCC4_SLOT = 8, + SAI5_PCC4_SLOT = 9, + PCTLE_PCC4_SLOT = 10, + PCTLF_PCC4_SLOT = 11, + SDHC0_PCC4_SLOT = 13, + SDHC1_PCC4_SLOT = 14, + SDHC2_PCC4_SLOT = 15, + USB0_PCC4_SLOT = 16, + USBPHY_PCC4_SLOT = 17, + USB1_PCC4_SLOT = 18, + USB1PHY_PCC4_SLOT = 19, + USB_XBAR_PCC4_SLOT = 20, + ENET_PCC4_SLOT = 21, + SFA1_PCC4_SLOT = 22, + RGPIOE_PCC4_SLOT = 30, + RGPIOF_PCC4_SLOT = 31, +}; + +/* PCC registers */ +#define PCC_PR_OFFSET 31 +#define PCC_PR_MASK (0x1 << PCC_PR_OFFSET) +#define PCC_CGC_OFFSET 30 +#define PCC_CGC_MASK (0x1 << PCC_CGC_OFFSET) +#define PCC_INUSE_OFFSET 29 +#define PCC_INUSE_MASK (0x1 << PCC_INUSE_OFFSET) +#define PCC_PCS_OFFSET 24 +#define PCC_PCS_MASK (0x7 << PCC_PCS_OFFSET) +#define PCC_FRAC_OFFSET 3 +#define PCC_FRAC_MASK (0x1 << PCC_FRAC_OFFSET) +#define PCC_PCD_OFFSET 0 +#define PCC_PCD_MASK (0x7 << PCC_PCD_OFFSET) + +enum pcc_clksrc_type { + CLKSRC_PER_PLAT = 0, + CLKSRC_PER_BUS = 1, + CLKSRC_NO_PCS = 2, +}; + +enum pcc_div_type { + PCC_HAS_DIV, + PCC_NO_DIV, +}; + +enum pcc_rst_b { + PCC_HAS_RST_B, + PCC_NO_RST_B, +}; + +/* This structure keeps info for each pcc slot */ +struct pcc_entry { + u32 pcc_base; + u32 pcc_slot; + enum pcc_clksrc_type clksrc; + enum pcc_div_type div; + enum pcc_rst_b rst_b; +}; + +int pcc_clock_enable(int pcc_controller, int pcc_clk_slot, bool enable); +int pcc_clock_sel(int pcc_controller, int pcc_clk_slot, enum cgc1_clk src); +int pcc_clock_div_config(int pcc_controller, int pcc_clk_slot, bool frac, u8 div); +bool pcc_clock_is_enable(int pcc_controller, int pcc_clk_slot); +int pcc_clock_get_clksrc(int pcc_controller, int pcc_clk_slot, enum cgc1_clk *src); +int pcc_reset_peripheral(int pcc_controller, int pcc_clk_slot, bool reset); +u32 pcc_clock_get_rate(int pcc_controller, int pcc_clk_slot); +#endif diff --git a/arch/arm/mach-imx/imx8ulp/Makefile b/arch/arm/mach-imx/imx8ulp/Makefile index e8970dc04f..78c81d78bb 100644 --- a/arch/arm/mach-imx/imx8ulp/Makefile +++ b/arch/arm/mach-imx/imx8ulp/Makefile @@ -4,4 +4,4 @@ # obj-y += lowlevel_init.o -obj-y += soc.o clock.o iomux.o +obj-y += soc.o clock.o iomux.o pcc.o cgc.o diff --git a/arch/arm/mach-imx/imx8ulp/cgc.c b/arch/arm/mach-imx/imx8ulp/cgc.c new file mode 100644 index 0000000000..a636592c7f --- /dev/null +++ b/arch/arm/mach-imx/imx8ulp/cgc.c @@ -0,0 +1,459 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2021 NXP + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +static struct cgc1_regs *cgc1_regs = (struct cgc1_regs *)0x292C0000UL; +static struct cgc2_regs *cgc2_regs = (struct cgc2_regs *)0x2da60000UL; + +void cgc1_soscdiv_init(void) +{ + /* Configure SOSC/FRO DIV1 ~ DIV3 */ + clrbits_le32(&cgc1_regs->soscdiv, BIT(7)); + clrbits_le32(&cgc1_regs->soscdiv, BIT(15)); + clrbits_le32(&cgc1_regs->soscdiv, BIT(23)); + clrbits_le32(&cgc1_regs->soscdiv, BIT(31)); + + clrbits_le32(&cgc1_regs->frodiv, BIT(7)); +} + +void cgc1_pll2_init(void) +{ + u32 reg; + + if (readl(&cgc1_regs->pll2csr) & BIT(23)) + clrbits_le32(&cgc1_regs->pll2csr, BIT(23)); + + /* Disable PLL2 */ + clrbits_le32(&cgc1_regs->pll2csr, BIT(0)); + mdelay(1); + + /* wait valid bit false */ + while ((readl(&cgc1_regs->pll2csr) & BIT(24))) + ; + + /* Select SOSC as source, freq = 42 * 24 =1008mhz */ + reg = 42 << 16; + writel(reg, &cgc1_regs->pll2cfg); + + /* Enable PLL2 */ + setbits_le32(&cgc1_regs->pll2csr, BIT(0)); + + /* Wait for PLL2 clock ready */ + while (!(readl(&cgc1_regs->pll2csr) & BIT(24))) + ; +} + +static void cgc1_set_a35_clk(u32 clk_src, u32 div_core) +{ + u32 reg; + + /* ulock */ + if (readl(&cgc1_regs->ca35clk) & BIT(31)) + clrbits_le32(&cgc1_regs->ca35clk, BIT(31)); + + reg = readl(&cgc1_regs->ca35clk); + reg &= ~GENMASK(29, 21); + reg |= ((clk_src & 0x3) << 28); + reg |= (((div_core - 1) & 0x3f) << 21); + writel(reg, &cgc1_regs->ca35clk); + + while (!(readl(&cgc1_regs->ca35clk) & BIT(27))) + ; +} + +void cgc1_init_core_clk(void) +{ + u32 reg = readl(&cgc1_regs->ca35clk); + + /* if already selected to PLL2, switch to FRO firstly */ + if (((reg >> 28) & 0x3) == 0x1) + cgc1_set_a35_clk(0, 1); + + /* Set pll2 to 1Ghz */ + cgc1_pll2_init(); + + /* Set A35 clock to 1GHz */ + cgc1_set_a35_clk(1, 1); +} + +void cgc1_enet_stamp_sel(u32 clk_src) +{ + writel((clk_src & 0x7) << 24, &cgc1_regs->enetstamp); +} + +void cgc1_pll3_init(void) +{ + /* Gate off VCO */ + setbits_le32(&cgc1_regs->pll3div_vco, BIT(7)); + + /* Disable PLL3 */ + clrbits_le32(&cgc1_regs->pll3csr, BIT(0)); + + /* Gate off PFDxDIV */ + setbits_le32(&cgc1_regs->pll3div_pfd0, BIT(7) | BIT(15) | BIT(23) | BIT(31)); + setbits_le32(&cgc1_regs->pll3div_pfd1, BIT(7) | BIT(15) | BIT(23) | BIT(31)); + + /* Gate off PFDx */ + setbits_le32(&cgc1_regs->pll3pfdcfg, BIT(7)); + setbits_le32(&cgc1_regs->pll3pfdcfg, BIT(15)); + setbits_le32(&cgc1_regs->pll3pfdcfg, BIT(23)); + setbits_le32(&cgc1_regs->pll3pfdcfg, BIT(31)); + + /* Select SOSC as source */ + clrbits_le32(&cgc1_regs->pll3cfg, BIT(0)); + + //setbits_le32(&cgc1_regs->pll3cfg, 22 << 16); + writel(22 << 16, &cgc1_regs->pll3cfg); + + writel(578, &cgc1_regs->pll3num); + writel(1000, &cgc1_regs->pll3denom); + + /* Enable PLL3 */ + setbits_le32(&cgc1_regs->pll3csr, BIT(0)); + + /* Wait for PLL3 clock ready */ + while (!(readl(&cgc1_regs->pll3csr) & BIT(24))) + ; + /* Gate on VCO */ + clrbits_le32(&cgc1_regs->pll3div_vco, BIT(7)); + + /* + * PFD0: 380MHz/396/396/328 + */ + clrbits_le32(&cgc1_regs->pll3pfdcfg, 0x3F); + setbits_le32(&cgc1_regs->pll3pfdcfg, 25 << 0); + clrbits_le32(&cgc1_regs->pll3pfdcfg, BIT(7)); + while (!(readl(&cgc1_regs->pll3pfdcfg) & BIT(6))) + ; + + clrbits_le32(&cgc1_regs->pll3pfdcfg, 0x3F << 8); + setbits_le32(&cgc1_regs->pll3pfdcfg, 24 << 8); + clrbits_le32(&cgc1_regs->pll3pfdcfg, BIT(15)); + while (!(readl(&cgc1_regs->pll3pfdcfg) & BIT(14))) + ; + + clrbits_le32(&cgc1_regs->pll3pfdcfg, 0x3F << 16); + setbits_le32(&cgc1_regs->pll3pfdcfg, 24 << 16); + clrbits_le32(&cgc1_regs->pll3pfdcfg, BIT(23)); + while (!(readl(&cgc1_regs->pll3pfdcfg) & BIT(22))) + ; + + clrbits_le32(&cgc1_regs->pll3pfdcfg, 0x3F << 24); + setbits_le32(&cgc1_regs->pll3pfdcfg, 29 << 24); + clrbits_le32(&cgc1_regs->pll3pfdcfg, BIT(31)); + while (!(readl(&cgc1_regs->pll3pfdcfg) & BIT(30))) + ; + + clrbits_le32(&cgc1_regs->pll3div_pfd0, BIT(7)); + clrbits_le32(&cgc1_regs->pll3div_pfd0, BIT(15)); + clrbits_le32(&cgc1_regs->pll3div_pfd0, BIT(23)); + clrbits_le32(&cgc1_regs->pll3div_pfd0, BIT(31)); + + clrbits_le32(&cgc1_regs->pll3div_pfd1, BIT(7)); + clrbits_le32(&cgc1_regs->pll3div_pfd1, BIT(15)); + clrbits_le32(&cgc1_regs->pll3div_pfd1, BIT(23)); + clrbits_le32(&cgc1_regs->pll3div_pfd1, BIT(31)); +} + +void cgc2_pll4_init(void) +{ + /* Disable PFD DIV and clear DIV */ + writel(0x80808080, &cgc2_regs->pll4div_pfd0); + writel(0x80808080, &cgc2_regs->pll4div_pfd1); + + /* Gate off and clear PFD */ + writel(0x80808080, &cgc2_regs->pll4pfdcfg); + + /* Disable PLL4 */ + writel(0x0, &cgc2_regs->pll4csr); + + /* Configure PLL4 to 528Mhz and clock source from SOSC */ + writel(22 << 16, &cgc2_regs->pll4cfg); + writel(0x1, &cgc2_regs->pll4csr); + + /* wait for PLL4 output valid */ + while (!(readl(&cgc2_regs->pll4csr) & BIT(24))) + ; + + /* Enable all 4 PFDs */ + setbits_le32(&cgc2_regs->pll4pfdcfg, 18 << 0); + setbits_le32(&cgc2_regs->pll4pfdcfg, 18 << 8); + setbits_le32(&cgc2_regs->pll4pfdcfg, 12 << 16); + setbits_le32(&cgc2_regs->pll4pfdcfg, 24 << 24); + + /* on Emulator, the valid bit can't work */ + while ((readl(&cgc2_regs->pll4pfdcfg) & (BIT(30) | BIT(22) | BIT(14) | BIT(6))) + != (BIT(30) | BIT(22) | BIT(14) | BIT(6))) + ; + + clrbits_le32(&cgc2_regs->pll4pfdcfg, BIT(7) | BIT(15) | BIT(23) | BIT(31)); + + /* Have to delay since pfd valid can't work on zebu */ + mdelay(1); + + /* Enable PFD DIV */ + clrbits_le32(&cgc2_regs->pll4div_pfd0, BIT(7) | BIT(15) | BIT(23) | BIT(31)); + clrbits_le32(&cgc2_regs->pll4div_pfd1, BIT(7) | BIT(15) | BIT(23) | BIT(31)); +} + +void cgc2_ddrclk_config(u32 src, u32 div) +{ + writel((src << 28) | (div << 21), &cgc2_regs->ddrclk); + /* wait for DDRCLK switching done */ + while (!(readl(&cgc2_regs->ddrclk) & BIT(27))) + ; +} + +u32 decode_pll(enum cgc1_clk pll) +{ + u32 reg, infreq, mult; + u32 num, denom; + + infreq = 24000000U; + /* + * Alought there are four choices for the bypass src, + * we choose SOSC 24M which is the default set in ROM. + * TODO: check more the comments + */ + switch (pll) { + case PLL2: + reg = readl(&cgc1_regs->pll2csr); + if (!(reg & BIT(24))) + return 0; + + reg = readl(&cgc1_regs->pll2cfg); + mult = (reg >> 16) & 0x7F; + denom = readl(&cgc1_regs->pll2denom) & 0x3FFFFFFF; + num = readl(&cgc1_regs->pll2num) & 0x3FFFFFFF; + + return (u64)infreq * mult + (u64)infreq * num / denom; + case PLL3: + reg = readl(&cgc1_regs->pll3csr); + if (!(reg & BIT(24))) + return 0; + + reg = readl(&cgc1_regs->pll3cfg); + mult = (reg >> 16) & 0x7F; + denom = readl(&cgc1_regs->pll3denom) & 0x3FFFFFFF; + num = readl(&cgc1_regs->pll3num) & 0x3FFFFFFF; + + return (u64)infreq * mult + (u64)infreq * num / denom; + default: + printf("Unsupported pll clocks %d\n", pll); + break; + } + + return 0; +} + +u32 cgc1_pll3_vcodiv_rate(void) +{ + u32 reg, gate, div; + + reg = readl(&cgc1_regs->pll3div_vco); + gate = BIT(7) & reg; + div = reg & 0x3F; + + return gate ? 0 : decode_pll(PLL3) / (div + 1); +} + +u32 cgc1_pll3_pfd_rate(enum cgc1_clk clk) +{ + u32 index, gate, vld, reg; + + switch (clk) { + case PLL3_PFD0: + index = 0; + break; + case PLL3_PFD1: + index = 1; + break; + case PLL3_PFD2: + index = 2; + break; + case PLL3_PFD3: + index = 3; + break; + default: + return 0; + } + + reg = readl(&cgc1_regs->pll3pfdcfg); + gate = reg & (BIT(7) << (index * 8)); + vld = reg & (BIT(6) << (index * 8)); + + if (gate || !vld) + return 0; + + return (u64)decode_pll(PLL3) * 18 / ((reg >> (index * 8)) & 0x3F); +} + +u32 cgc1_pll3_pfd_div(enum cgc1_clk clk) +{ + void __iomem *base; + u32 pfd, index, gate, reg; + + switch (clk) { + case PLL3_PFD0_DIV1: + base = &cgc1_regs->pll3div_pfd0; + pfd = PLL3_PFD0; + index = 0; + break; + case PLL3_PFD0_DIV2: + base = &cgc1_regs->pll3div_pfd0; + pfd = PLL3_PFD0; + index = 1; + break; + case PLL3_PFD1_DIV1: + base = &cgc1_regs->pll3div_pfd0; + pfd = PLL3_PFD1; + index = 2; + break; + case PLL3_PFD1_DIV2: + base = &cgc1_regs->pll3div_pfd0; + pfd = PLL3_PFD1; + index = 3; + break; + case PLL3_PFD2_DIV1: + base = &cgc1_regs->pll3div_pfd1; + pfd = PLL3_PFD2; + index = 0; + break; + case PLL3_PFD2_DIV2: + base = &cgc1_regs->pll3div_pfd1; + pfd = PLL3_PFD2; + index = 1; + break; + case PLL3_PFD3_DIV1: + base = &cgc1_regs->pll3div_pfd1; + pfd = PLL3_PFD3; + index = 2; + break; + case PLL3_PFD3_DIV2: + base = &cgc1_regs->pll3div_pfd1; + pfd = PLL3_PFD3; + index = 3; + break; + default: + return 0; + } + + reg = readl(base); + gate = reg & (BIT(7) << (index * 8)); + + if (gate) + return 0; + + return cgc1_pll3_pfd_rate(pfd) / (((reg >> (index * 8)) & 0x3F) + 1); +} + +u32 cgc1_sosc_div(enum cgc1_clk clk) +{ + u32 reg, gate, index; + + switch (clk) { + case SOSC: + return 24000000; + case SOSC_DIV1: + index = 0; + break; + case SOSC_DIV2: + index = 1; + break; + case SOSC_DIV3: + index = 2; + break; + default: + return 0; + } + + reg = readl(&cgc1_regs->soscdiv); + gate = reg & (BIT(7) << (index * 8)); + + if (gate) + return 0; + + return 24000000 / (((reg >> (index * 8)) & 0x3F) + 1); +} + +u32 cgc1_fro_div(enum cgc1_clk clk) +{ + u32 reg, gate, vld, index; + + switch (clk) { + case FRO: + return 192000000; + case FRO_DIV1: + index = 0; + break; + case FRO_DIV2: + index = 1; + break; + case FRO_DIV3: + index = 2; + break; + default: + return 0; + } + + reg = readl(&cgc1_regs->frodiv); + gate = reg & (BIT(7) << (index * 8)); + vld = reg & (BIT(6) << (index * 8)); + + if (gate || !vld) + return 0; + + return 24000000 / (((reg >> (index * 8)) & 0x3F) + 1); +} + +u32 cgc1_clk_get_rate(enum cgc1_clk clk) +{ + switch (clk) { + case SOSC: + case SOSC_DIV1: + case SOSC_DIV2: + case SOSC_DIV3: + return cgc1_sosc_div(clk); + case FRO: + case FRO_DIV1: + case FRO_DIV2: + case FRO_DIV3: + return cgc1_fro_div(clk); + case PLL2: + return decode_pll(PLL2); + case PLL3: + return decode_pll(PLL3); + case PLL3_VCODIV: + return cgc1_pll3_vcodiv_rate(); + case PLL3_PFD0: + case PLL3_PFD1: + case PLL3_PFD2: + case PLL3_PFD3: + return cgc1_pll3_pfd_rate(clk); + case PLL3_PFD0_DIV1: + case PLL3_PFD0_DIV2: + case PLL3_PFD1_DIV1: + case PLL3_PFD1_DIV2: + case PLL3_PFD2_DIV1: + case PLL3_PFD2_DIV2: + case PLL3_PFD3_DIV1: + case PLL3_PFD3_DIV2: + return cgc1_pll3_pfd_div(clk); + default: + printf("Unsupported cgc1 clock: %d\n", clk); + return 0; + } +} diff --git a/arch/arm/mach-imx/imx8ulp/clock.c b/arch/arm/mach-imx/imx8ulp/clock.c index f866809fc2..d6633f05bf 100644 --- a/arch/arm/mach-imx/imx8ulp/clock.c +++ b/arch/arm/mach-imx/imx8ulp/clock.c @@ -4,24 +4,387 @@ */ #include +#include #include +#include #include #include #include +#include +#include #include +#include +#include DECLARE_GLOBAL_DATA_PTR; +#define PLL_USB_EN_USB_CLKS_MASK (0x01 << 6) +#define PLL_USB_PWR_MASK (0x01 << 12) +#define PLL_USB_ENABLE_MASK (0x01 << 13) +#define PLL_USB_BYPASS_MASK (0x01 << 16) +#define PLL_USB_REG_ENABLE_MASK (0x01 << 21) +#define PLL_USB_DIV_SEL_MASK (0x07 << 22) +#define PLL_USB_LOCK_MASK (0x01 << 31) +#define PCC5_LPDDR4_ADDR 0x2da70108 + +static void lpuart_set_clk(u32 index, enum cgc1_clk clk) +{ + const u32 lpuart_pcc_slots[] = { + LPUART4_PCC3_SLOT, + LPUART5_PCC3_SLOT, + LPUART6_PCC4_SLOT, + LPUART7_PCC4_SLOT, + }; + + const u32 lpuart_pcc[] = { + 3, 3, 4, 4, + }; + + if (index > 3) + return; + + pcc_clock_enable(lpuart_pcc[index], lpuart_pcc_slots[index], false); + pcc_clock_sel(lpuart_pcc[index], lpuart_pcc_slots[index], clk); + pcc_clock_enable(lpuart_pcc[index], lpuart_pcc_slots[index], true); + + pcc_reset_peripheral(lpuart_pcc[index], lpuart_pcc_slots[index], false); +} + +static void init_clk_lpuart(void) +{ + u32 index = 0, i; + + const u32 lpuart_array[] = { + LPUART4_RBASE, + LPUART5_RBASE, + LPUART6_RBASE, + LPUART7_RBASE, + }; + + for (i = 0; i < 4; i++) { + if (lpuart_array[i] == LPUART_BASE) { + index = i; + break; + } + } + + lpuart_set_clk(index, SOSC_DIV2); +} + +void init_clk_fspi(int index) +{ + pcc_clock_enable(4, FLEXSPI2_PCC4_SLOT, false); + pcc_clock_sel(4, FLEXSPI2_PCC4_SLOT, PLL3_PFD2_DIV1); + pcc_clock_div_config(4, FLEXSPI2_PCC4_SLOT, false, 8); + pcc_clock_enable(4, FLEXSPI2_PCC4_SLOT, true); + pcc_reset_peripheral(4, FLEXSPI2_PCC4_SLOT, false); +} + +void setclkout_ddr(void) +{ + writel(0x12800000, 0x2DA60020); + writel(0xa00, 0x298C0000); /* PTD0 */ +} + +void ddrphy_pll_lock(void) +{ + writel(0x00011542, 0x2E065964); + writel(0x00011542, 0x2E06586C); + + writel(0x00000B01, 0x2E062000); + writel(0x00000B01, 0x2E060000); +} + +void init_clk_ddr(void) +{ + /* enable pll4 and ddrclk*/ + cgc2_pll4_init(); + cgc2_ddrclk_config(1, 1); + + /* enable ddr pcc */ + writel(0xd0000000, PCC5_LPDDR4_ADDR); + + /* for debug */ + setclkout_ddr(); +} + +int set_ddr_clk(u32 phy_freq_mhz) +{ + debug("%s %u\n", __func__, phy_freq_mhz); + + if (phy_freq_mhz == 48) { + writel(0x90000000, PCC5_LPDDR4_ADDR); /* disable ddr pcc */ + cgc2_ddrclk_config(2, 0); /* 24Mhz DDR clock */ + writel(0xd0000000, PCC5_LPDDR4_ADDR); /* enable ddr pcc */ + } else if (phy_freq_mhz == 384) { + writel(0x90000000, PCC5_LPDDR4_ADDR); /* disable ddr pcc */ + cgc2_ddrclk_config(0, 0); /* 192Mhz DDR clock */ + writel(0xd0000000, PCC5_LPDDR4_ADDR); /* enable ddr pcc */ + } else if (phy_freq_mhz == 528) { + writel(0x90000000, PCC5_LPDDR4_ADDR); /* disable ddr pcc */ + cgc2_ddrclk_config(1, 1); /* 264Mhz DDR clock */ + writel(0xd0000000, PCC5_LPDDR4_ADDR); /* enable ddr pcc */ + } else if (phy_freq_mhz == 192) { + writel(0x90000000, PCC5_LPDDR4_ADDR); /* disable ddr pcc */ + cgc2_ddrclk_config(0, 1); /* 96Mhz DDR clock */ + writel(0xd0000000, PCC5_LPDDR4_ADDR); /* enable ddr pcc */ + } else if (phy_freq_mhz == 50) { + writel(0x90000000, PCC5_LPDDR4_ADDR); /* disable ddr pcc */ + cgc2_ddrclk_config(1, 9); /* 96Mhz DDR clock */ + writel(0xd0000000, PCC5_LPDDR4_ADDR); /* enable ddr pcc */ + } else { + printf("ddr phy clk %uMhz is not supported\n", phy_freq_mhz); + return -EINVAL; + } + + return 0; +} + void clock_init(void) { + init_clk_lpuart(); + + pcc_clock_enable(4, SDHC0_PCC4_SLOT, false); + pcc_clock_sel(4, SDHC0_PCC4_SLOT, PLL3_PFD1_DIV2); + pcc_clock_enable(4, SDHC0_PCC4_SLOT, true); + pcc_reset_peripheral(4, SDHC0_PCC4_SLOT, false); + + pcc_clock_enable(4, SDHC1_PCC4_SLOT, false); + pcc_clock_sel(4, SDHC1_PCC4_SLOT, PLL3_PFD2_DIV1); + pcc_clock_enable(4, SDHC1_PCC4_SLOT, true); + pcc_reset_peripheral(4, SDHC1_PCC4_SLOT, false); + + pcc_clock_enable(4, SDHC2_PCC4_SLOT, false); + pcc_clock_sel(4, SDHC2_PCC4_SLOT, PLL3_PFD2_DIV1); + pcc_clock_enable(4, SDHC2_PCC4_SLOT, true); + pcc_reset_peripheral(4, SDHC2_PCC4_SLOT, false); + + /* Enable upower mu1 clk */ + pcc_clock_enable(3, UPOWER_PCC3_SLOT, true); + + /* + * Enable clock division + * TODO: may not needed after ROM ready. + */ } -unsigned int mxc_get_clock(enum mxc_clock clk) +#if CONFIG_IS_ENABLED(CONFIG_SYS_I2C_IMX_LPI2C) +int enable_i2c_clk(unsigned char enable, u32 int i2c_num) { + /* Set parent to FIRC DIV2 clock */ + const u32 lpi2c_pcc_clks[] = { + LPI2C4_PCC3_SLOT << 8 | 3, + LPI2C5_PCC3_SLOT << 8 | 3, + LPI2C6_PCC4_SLOT << 8 | 4, + LPI2C7_PCC4_SLOT << 8 | 4, + }; + + if (i2c_num < 4 || i2c_num > 7) + return -EINVAL; + + if (enable) { + pcc_clock_enable(lpi2c_pcc_clks[i2c_num - 4] & 0xff, + lpi2c_pcc_clks[i2c_num - 4] >> 8, false); + pcc_clock_sel(lpi2c_pcc_clks[i2c_num - 4] & 0xff, + lpi2c_pcc_clks[i2c_num - 4] >> 8, SOSC_DIV2); + pcc_clock_enable(lpi2c_pcc_clks[i2c_num - 4] & 0xff, + lpi2c_pcc_clks[i2c_num - 4] >> 8, true); + pcc_reset_peripheral(lpi2c_pcc_clks[i2c_num - 4] & 0xff, + lpi2c_pcc_clks[i2c_num - 4] >> 8, false); + } else { + pcc_clock_enable(lpi2c_pcc_clks[i2c_num - 4] & 0xff, + lpi2c_pcc_clks[i2c_num - 4] >> 8, false); + } return 0; } +u32 imx_get_i2cclk(u32 i2c_num) +{ + const u32 lpi2c_pcc_clks[] = { + LPI2C4_PCC3_SLOT << 8 | 3, + LPI2C5_PCC3_SLOT << 8 | 3, + LPI2C6_PCC4_SLOT << 8 | 4, + LPI2C7_PCC4_SLOT << 8 | 4, + }; + + if (i2c_num < 4 || i2c_num > 7) + return 0; + + return pcc_clock_get_rate(lpi2c_pcc_clks[i2c_num - 4] & 0xff, + lpi2c_pcc_clks[i2c_num - 4] >> 8); +} +#endif + +void enable_usboh3_clk(unsigned char enable) +{ + if (enable) { + pcc_clock_enable(4, USB0_PCC4_SLOT, true); + pcc_clock_enable(4, USBPHY_PCC4_SLOT, true); + pcc_reset_peripheral(4, USB0_PCC4_SLOT, false); + pcc_reset_peripheral(4, USBPHY_PCC4_SLOT, false); + +#ifdef CONFIG_USB_MAX_CONTROLLER_COUNT + if (CONFIG_USB_MAX_CONTROLLER_COUNT > 1) { + pcc_clock_enable(4, USB1_PCC4_SLOT, true); + pcc_clock_enable(4, USB1PHY_PCC4_SLOT, true); + pcc_reset_peripheral(4, USB1_PCC4_SLOT, false); + pcc_reset_peripheral(4, USB1PHY_PCC4_SLOT, false); + } +#endif + + pcc_clock_enable(4, USB_XBAR_PCC4_SLOT, true); + } else { + pcc_clock_enable(4, USB0_PCC4_SLOT, false); + pcc_clock_enable(4, USB1_PCC4_SLOT, false); + pcc_clock_enable(4, USBPHY_PCC4_SLOT, false); + pcc_clock_enable(4, USB1PHY_PCC4_SLOT, false); + pcc_clock_enable(4, USB_XBAR_PCC4_SLOT, false); + } +} + +int enable_usb_pll(ulong usb_phy_base) +{ + u32 sosc_rate; + s32 timeout = 1000000; + + struct usbphy_regs *usbphy = + (struct usbphy_regs *)usb_phy_base; + + sosc_rate = cgc1_sosc_div(SOSC); + if (!sosc_rate) + return -EPERM; + + if (!(readl(&usbphy->usb1_pll_480_ctrl) & PLL_USB_LOCK_MASK)) { + writel(0x1c00000, &usbphy->usb1_pll_480_ctrl_clr); + + switch (sosc_rate) { + case 24000000: + writel(0xc00000, &usbphy->usb1_pll_480_ctrl_set); + break; + + case 30000000: + writel(0x800000, &usbphy->usb1_pll_480_ctrl_set); + break; + + case 19200000: + writel(0x1400000, &usbphy->usb1_pll_480_ctrl_set); + break; + + default: + writel(0xc00000, &usbphy->usb1_pll_480_ctrl_set); + break; + } + + /* Enable the regulator first */ + writel(PLL_USB_REG_ENABLE_MASK, + &usbphy->usb1_pll_480_ctrl_set); + + /* Wait at least 15us */ + udelay(15); + + /* Enable the power */ + writel(PLL_USB_PWR_MASK, &usbphy->usb1_pll_480_ctrl_set); + + /* Wait lock */ + while (timeout--) { + if (readl(&usbphy->usb1_pll_480_ctrl) & + PLL_USB_LOCK_MASK) + break; + } + + if (timeout <= 0) { + /* If timeout, we power down the pll */ + writel(PLL_USB_PWR_MASK, + &usbphy->usb1_pll_480_ctrl_clr); + return -ETIME; + } + } + + /* Clear the bypass */ + writel(PLL_USB_BYPASS_MASK, &usbphy->usb1_pll_480_ctrl_clr); + + /* Enable the PLL clock out to USB */ + writel((PLL_USB_EN_USB_CLKS_MASK | PLL_USB_ENABLE_MASK), + &usbphy->usb1_pll_480_ctrl_set); + + return 0; +} + +u32 mxc_get_clock(enum mxc_clock clk) +{ + switch (clk) { + case MXC_ESDHC_CLK: + return pcc_clock_get_rate(4, SDHC0_PCC4_SLOT); + case MXC_ESDHC2_CLK: + return pcc_clock_get_rate(4, SDHC1_PCC4_SLOT); + case MXC_ESDHC3_CLK: + return pcc_clock_get_rate(4, SDHC2_PCC4_SLOT); + case MXC_ARM_CLK: + return cgc1_clk_get_rate(PLL2); + default: + return 0; + } +} + u32 get_lpuart_clk(void) { - return 24000000; + int index = 0; + + const u32 lpuart_array[] = { + LPUART4_RBASE, + LPUART5_RBASE, + LPUART6_RBASE, + LPUART7_RBASE, + }; + + const u32 lpuart_pcc_slots[] = { + LPUART4_PCC3_SLOT, + LPUART5_PCC3_SLOT, + LPUART6_PCC4_SLOT, + LPUART7_PCC4_SLOT, + }; + + const u32 lpuart_pcc[] = { + 3, 3, 4, 4, + }; + + for (index = 0; index < 4; index++) { + if (lpuart_array[index] == LPUART_BASE) + break; + } + + if (index > 3) + return 0; + + return pcc_clock_get_rate(lpuart_pcc[index], lpuart_pcc_slots[index]); +} + +#ifndef CONFIG_SPL_BUILD +/* + * Dump some core clockes. + */ +int do_mx8ulp_showclocks(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) +{ + printf("SDHC0 %8d MHz\n", pcc_clock_get_rate(4, SDHC0_PCC4_SLOT) / 1000000); + printf("SDHC1 %8d MHz\n", pcc_clock_get_rate(4, SDHC1_PCC4_SLOT) / 1000000); + printf("SDHC2 %8d MHz\n", pcc_clock_get_rate(4, SDHC2_PCC4_SLOT) / 1000000); + + printf("SOSC %8d MHz\n", cgc1_clk_get_rate(SOSC) / 1000000); + printf("FRO %8d MHz\n", cgc1_clk_get_rate(FRO) / 1000000); + printf("PLL2 %8d MHz\n", cgc1_clk_get_rate(PLL2) / 1000000); + printf("PLL3 %8d MHz\n", cgc1_clk_get_rate(PLL3) / 1000000); + printf("PLL3_VCODIV %8d MHz\n", cgc1_clk_get_rate(PLL3_VCODIV) / 1000000); + printf("PLL3_PFD0 %8d MHz\n", cgc1_clk_get_rate(PLL3_PFD0) / 1000000); + printf("PLL3_PFD1 %8d MHz\n", cgc1_clk_get_rate(PLL3_PFD1) / 1000000); + printf("PLL3_PFD2 %8d MHz\n", cgc1_clk_get_rate(PLL3_PFD2) / 1000000); + printf("PLL3_PFD3 %8d MHz\n", cgc1_clk_get_rate(PLL3_PFD3) / 1000000); + + return 0; } + +U_BOOT_CMD( + clocks, CONFIG_SYS_MAXARGS, 1, do_mx8ulp_showclocks, + "display clocks", + "" +); +#endif diff --git a/arch/arm/mach-imx/imx8ulp/pcc.c b/arch/arm/mach-imx/imx8ulp/pcc.c new file mode 100644 index 0000000000..a41056b3b1 --- /dev/null +++ b/arch/arm/mach-imx/imx8ulp/pcc.c @@ -0,0 +1,449 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2021 NXP + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define cgc1_clk_TYPES 2 +#define cgc1_clk_NUM 8 + +static enum cgc1_clk pcc3_clksrc[][8] = { + { + }, + { DUMMY0_CLK, + LPOSC, + SOSC_DIV2, + FRO_DIV2, + XBAR_BUSCLK, + PLL3_PFD1_DIV1, + PLL3_PFD0_DIV2, + PLL3_PFD0_DIV1 + } +}; + +static enum cgc1_clk pcc4_clksrc[][8] = { + { + DUMMY0_CLK, + SOSC_DIV1, + FRO_DIV1, + PLL3_PFD3_DIV2, + PLL3_PFD3_DIV1, + PLL3_PFD2_DIV2, + PLL3_PFD2_DIV1, + PLL3_PFD1_DIV2 + }, + { + DUMMY0_CLK, + DUMMY1_CLK, + LPOSC, + SOSC_DIV2, + FRO_DIV2, + XBAR_BUSCLK, + PLL3_VCODIV, + PLL3_PFD0_DIV1 + } +}; + +static struct pcc_entry pcc3_arrays[] = { + {PCC3_RBASE, DMA1_MP_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, DMA1_CH0_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, DMA1_CH1_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, DMA1_CH2_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, DMA1_CH3_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, DMA1_CH4_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, DMA1_CH5_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, DMA1_CH6_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, DMA1_CH7_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, DMA1_CH8_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, DMA1_CH9_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, DMA1_CH10_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, DMA1_CH11_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, DMA1_CH12_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, DMA1_CH13_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, DMA1_CH14_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, DMA1_CH15_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, DMA1_CH16_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, DMA1_CH17_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, DMA1_CH18_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, DMA1_CH19_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, DMA1_CH20_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, DMA1_CH21_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, DMA1_CH22_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, DMA1_CH23_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, DMA1_CH24_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, DMA1_CH25_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, DMA1_CH26_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, DMA1_CH27_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, DMA1_CH28_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, DMA1_CH29_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, DMA1_CH30_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, DMA1_CH31_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, MU0_B_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, MU3_A_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, LLWU1_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, UPOWER_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, WDOG3_PCC3_SLOT, CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B}, + {PCC3_RBASE, WDOG4_PCC3_SLOT, CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B}, + {PCC3_RBASE, XRDC_MGR_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, SEMA42_1_PCC3_SLOT, CLKSRC_PER_BUS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, ROMCP1_PCC3_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B}, + {PCC3_RBASE, LPIT1_PCC3_SLOT, CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B}, + {PCC3_RBASE, TPM4_PCC3_SLOT, CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B}, + {PCC3_RBASE, TPM5_PCC3_SLOT, CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B}, + {PCC3_RBASE, FLEXIO1_PCC3_SLOT, CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B}, + {PCC3_RBASE, I3C2_PCC3_SLOT, CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B}, + {PCC3_RBASE, LPI2C4_PCC3_SLOT, CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B}, + {PCC3_RBASE, LPI2C5_PCC3_SLOT, CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B}, + {PCC3_RBASE, LPUART4_PCC3_SLOT, CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B}, + {PCC3_RBASE, LPUART5_PCC3_SLOT, CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B}, + {PCC3_RBASE, LPSPI4_PCC3_SLOT, CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B}, + {PCC3_RBASE, LPSPI5_PCC3_SLOT, CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B}, + {} +}; + +static struct pcc_entry pcc4_arrays[] = { + {PCC4_RBASE, FLEXSPI2_PCC4_SLOT, CLKSRC_PER_PLAT, PCC_HAS_DIV, PCC_HAS_RST_B }, + {PCC4_RBASE, TPM6_PCC4_SLOT, CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B }, + {PCC4_RBASE, TPM7_PCC4_SLOT, CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B }, + {PCC4_RBASE, LPI2C6_PCC4_SLOT, CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B }, + {PCC4_RBASE, LPI2C7_PCC4_SLOT, CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B }, + {PCC4_RBASE, LPUART6_PCC4_SLOT, CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B }, + {PCC4_RBASE, LPUART7_PCC4_SLOT, CLKSRC_PER_BUS, PCC_HAS_DIV, PCC_HAS_RST_B }, + {PCC4_RBASE, SAI4_PCC4_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_HAS_RST_B }, + {PCC4_RBASE, SAI5_PCC4_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_HAS_RST_B }, + {PCC4_RBASE, PCTLE_PCC4_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC4_RBASE, PCTLF_PCC4_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC4_RBASE, SDHC0_PCC4_SLOT, CLKSRC_PER_PLAT, PCC_HAS_DIV, PCC_HAS_RST_B }, + {PCC4_RBASE, SDHC1_PCC4_SLOT, CLKSRC_PER_PLAT, PCC_HAS_DIV, PCC_HAS_RST_B }, + {PCC4_RBASE, SDHC2_PCC4_SLOT, CLKSRC_PER_PLAT, PCC_HAS_DIV, PCC_HAS_RST_B }, + {PCC4_RBASE, USB0_PCC4_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_HAS_RST_B }, + {PCC4_RBASE, USBPHY_PCC4_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_HAS_RST_B }, + {PCC4_RBASE, USB1_PCC4_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC4_RBASE, USB1PHY_PCC4_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_HAS_RST_B }, + {PCC4_RBASE, USB_XBAR_PCC4_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC4_RBASE, ENET_PCC4_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_HAS_RST_B }, + {PCC4_RBASE, SFA1_PCC4_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC4_RBASE, RGPIOE_PCC4_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {PCC4_RBASE, RGPIOF_PCC4_SLOT, CLKSRC_NO_PCS, PCC_NO_DIV, PCC_NO_RST_B }, + {} +}; + +static int find_pcc_entry(int pcc_controller, int pcc_clk_slot, struct pcc_entry **out) +{ + struct pcc_entry *pcc_array; + int index = 0; + + switch (pcc_controller) { + case 3: + pcc_array = pcc3_arrays; + *out = &pcc3_arrays[0]; + break; + case 4: + pcc_array = pcc4_arrays; + *out = &pcc4_arrays[0]; + break; + default: + printf("Not supported pcc_controller: %d\n", pcc_controller); + return -EINVAL; + } + + while (pcc_array->pcc_base) { + if (pcc_array->pcc_slot == pcc_clk_slot) + return index; + + pcc_array++; + index++; + } + + return -ENOENT; +} + +int pcc_clock_enable(int pcc_controller, int pcc_clk_slot, bool enable) +{ + u32 val; + void __iomem *reg; + int clk; + struct pcc_entry *pcc_array; + + clk = find_pcc_entry(pcc_controller, pcc_clk_slot, &pcc_array); + if (clk < 0) + return -EINVAL; + + reg = (void __iomem *)(uintptr_t)(pcc_array[clk].pcc_base + pcc_array[clk].pcc_slot * 4); + + val = readl(reg); + + debug("%s: clk %d, reg 0x%p, val 0x%x, enable %d\n", __func__, clk, reg, val, enable); + + if (!(val & PCC_PR_MASK) || (val & PCC_INUSE_MASK)) + return -EPERM; + + if (enable) + val |= PCC_CGC_MASK; + else + val &= ~PCC_CGC_MASK; + + writel(val, reg); + + debug("%s: val 0x%x\n", __func__, val); + + return 0; +} + +/* The clock source select needs clock is disabled */ +int pcc_clock_sel(int pcc_controller, int pcc_clk_slot, enum cgc1_clk src) +{ + u32 val, i, clksrc_type; + void __iomem *reg; + struct pcc_entry *pcc_array; + enum cgc1_clk *cgc1_clk_array; + int clk; + + clk = find_pcc_entry(pcc_controller, pcc_clk_slot, &pcc_array); + if (clk < 0) + return -EINVAL; + + reg = (void __iomem *)(uintptr_t)(pcc_array[clk].pcc_base + pcc_array[clk].pcc_slot * 4); + + clksrc_type = pcc_array[clk].clksrc; + if (clksrc_type >= CLKSRC_NO_PCS) { + printf("No PCS field for the PCC %d, clksrc type %d\n", + clk, clksrc_type); + return -EPERM; + } + + if (pcc_controller == 3) + cgc1_clk_array = pcc3_clksrc[clksrc_type]; + else + cgc1_clk_array = pcc4_clksrc[clksrc_type]; + + for (i = 0; i < cgc1_clk_NUM; i++) { + if (cgc1_clk_array[i] == src) { + /* Find the clock src, then set it to PCS */ + break; + } + } + + if (i == cgc1_clk_NUM) { + printf("No parent in PCS of PCC %d, invalid scg_clk %d\n", clk, src); + return -EINVAL; + } + + val = readl(reg); + + debug("%s: clk %d, reg 0x%p, val 0x%x, clksrc_type %d\n", + __func__, clk, reg, val, clksrc_type); + + if (!(val & PCC_PR_MASK) || (val & PCC_INUSE_MASK) || + (val & PCC_CGC_MASK)) { + printf("Not permit to select clock source val = 0x%x\n", val); + return -EPERM; + } + + val &= ~PCC_PCS_MASK; + val |= i << PCC_PCS_OFFSET; + + writel(val, reg); + + debug("%s: val 0x%x\n", __func__, val); + + return 0; +} + +int pcc_clock_div_config(int pcc_controller, int pcc_clk_slot, bool frac, u8 div) +{ + u32 val; + void __iomem *reg; + struct pcc_entry *pcc_array; + int clk; + + clk = find_pcc_entry(pcc_controller, pcc_clk_slot, &pcc_array); + if (clk < 0) + return -EINVAL; + + reg = (void __iomem *)(uintptr_t)(pcc_array[clk].pcc_base + pcc_array[clk].pcc_slot * 4); + + if (div > 8 || (div == 1 && frac != 0)) + return -EINVAL; + + if (pcc_array[clk].div >= PCC_NO_DIV) { + printf("No DIV/FRAC field for the PCC %d\n", clk); + return -EPERM; + } + + val = readl(reg); + + if (!(val & PCC_PR_MASK) || (val & PCC_INUSE_MASK) || + (val & PCC_CGC_MASK)) { + printf("Not permit to set div/frac val = 0x%x\n", val); + return -EPERM; + } + + if (frac) + val |= PCC_FRAC_MASK; + else + val &= ~PCC_FRAC_MASK; + + val &= ~PCC_PCD_MASK; + val |= (div - 1) & PCC_PCD_MASK; + + writel(val, reg); + + return 0; +} + +bool pcc_clock_is_enable(int pcc_controller, int pcc_clk_slot) +{ + u32 val; + void __iomem *reg; + struct pcc_entry *pcc_array; + int clk; + + clk = find_pcc_entry(pcc_controller, pcc_clk_slot, &pcc_array); + if (clk < 0) + return -EINVAL; + + reg = (void __iomem *)(uintptr_t)(pcc_array[clk].pcc_base + pcc_array[clk].pcc_slot * 4); + val = readl(reg); + + if ((val & PCC_INUSE_MASK) || (val & PCC_CGC_MASK)) + return true; + + return false; +} + +int pcc_clock_get_clksrc(int pcc_controller, int pcc_clk_slot, enum cgc1_clk *src) +{ + u32 val, clksrc_type; + void __iomem *reg; + struct pcc_entry *pcc_array; + int clk; + enum cgc1_clk *cgc1_clk_array; + + clk = find_pcc_entry(pcc_controller, pcc_clk_slot, &pcc_array); + if (clk < 0) + return -EINVAL; + + clksrc_type = pcc_array[clk].clksrc; + if (clksrc_type >= CLKSRC_NO_PCS) { + printf("No PCS field for the PCC %d, clksrc type %d\n", + pcc_clk_slot, clksrc_type); + return -EPERM; + } + + reg = (void __iomem *)(uintptr_t)(pcc_array[clk].pcc_base + pcc_array[clk].pcc_slot * 4); + + val = readl(reg); + + debug("%s: clk %d, reg 0x%p, val 0x%x, type %d\n", + __func__, pcc_clk_slot, reg, val, clksrc_type); + + if (!(val & PCC_PR_MASK)) { + printf("This pcc slot is not present = 0x%x\n", val); + return -EPERM; + } + + val &= PCC_PCS_MASK; + val = (val >> PCC_PCS_OFFSET); + + if (!val) { + printf("Clock source is off\n"); + return -EIO; + } + + if (pcc_controller == 3) + cgc1_clk_array = pcc3_clksrc[clksrc_type]; + else + cgc1_clk_array = pcc4_clksrc[clksrc_type]; + + *src = cgc1_clk_array[val]; + + debug("%s: parent cgc1 clk %d\n", __func__, *src); + + return 0; +} + +int pcc_reset_peripheral(int pcc_controller, int pcc_clk_slot, bool reset) +{ + u32 val; + void __iomem *reg; + struct pcc_entry *pcc_array; + int clk; + + clk = find_pcc_entry(pcc_controller, pcc_clk_slot, &pcc_array); + if (clk < 0) + return -EINVAL; + + if (pcc_array[clk].rst_b == PCC_NO_RST_B) + return 0; + + reg = (void __iomem *)(uintptr_t)(pcc_array[clk].pcc_base + pcc_array[clk].pcc_slot * 4); + + val = readl(reg); + + debug("%s: clk %d, reg 0x%p, val 0x%x\n", __func__, pcc_clk_slot, reg, val); + + if (!(val & PCC_PR_MASK)) { + printf("This pcc slot is not present = 0x%x\n", val); + return -EPERM; + } + + if (reset) + val &= ~BIT(28); + else + val |= BIT(28); + + writel(val, reg); + + debug("%s: clk %d, reg 0x%p, val 0x%x\n", __func__, pcc_clk_slot, reg, val); + + return 0; +} + +u32 pcc_clock_get_rate(int pcc_controller, int pcc_clk_slot) +{ + u32 val, rate, frac, div; + void __iomem *reg; + enum cgc1_clk parent; + int ret; + int clk; + struct pcc_entry *pcc_array; + + clk = find_pcc_entry(pcc_controller, pcc_clk_slot, &pcc_array); + if (clk < 0) + return -EINVAL; + + ret = pcc_clock_get_clksrc(pcc_controller, pcc_clk_slot, &parent); + if (ret) + return 0; + + rate = cgc1_clk_get_rate(parent); + + debug("%s: parent rate %u\n", __func__, rate); + + if (pcc_array[clk].div == PCC_HAS_DIV) { + reg = (void __iomem *)(uintptr_t)(pcc_array[clk].pcc_base + + pcc_array[clk].pcc_slot * 4); + val = readl(reg); + + frac = (val & PCC_FRAC_MASK) >> PCC_FRAC_OFFSET; + div = (val & PCC_PCD_MASK) >> PCC_PCD_OFFSET; + + /* + * Theoretically don't have overflow in the calc, + * the rate won't exceed 2G + */ + rate = rate * (frac + 1) / (div + 1); + } + + debug("%s: rate %u\n", __func__, rate); + return rate; +} diff --git a/arch/arm/mach-imx/imx8ulp/soc.c b/arch/arm/mach-imx/imx8ulp/soc.c index b624e648e8..5d291f6b3a 100644 --- a/arch/arm/mach-imx/imx8ulp/soc.c +++ b/arch/arm/mach-imx/imx8ulp/soc.c @@ -284,5 +284,8 @@ void get_board_serial(struct tag_serialnr *serialnr) int arch_cpu_init(void) { + if (IS_ENABLED(CONFIG_SPL_BUILD)) + clock_init(); + return 0; }