From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=104.47.38.127; helo=nam02-bl2-obe.outbound.protection.outlook.com; envelope-from=christopher.co@microsoft.com; receiver=edk2-devel@lists.01.org Received: from NAM02-BL2-obe.outbound.protection.outlook.com (mail-bl2nam02on0127.outbound.protection.outlook.com [104.47.38.127]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id D431C21154128 for ; Fri, 21 Sep 2018 01:26:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=X+KjjlhRmKNEAeB9upIAj540yiMlkto0pm9HlE7VYe0=; b=Yi31dVrra76q3x9bqiXEAAO3oLtL2Mh9IJH9ZwYm1z9yUs3dXssIhdRqF1BGJbKwG86FyPCb8c7WptLYOeWxrNDfa0hZoZzIDslDWYGFiaEH2+QmdtTrSvFAM3kUwMqJiUyFG/XNqsDNH01OdYBW6JJ7zyWKXN9STu69eRWp+eY= Received: from DM5PR2101MB1128.namprd21.prod.outlook.com (52.132.133.20) by DM5PR2101MB0727.namprd21.prod.outlook.com (10.167.110.39) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.1185.6; Fri, 21 Sep 2018 08:26:11 +0000 Received: from DM5PR2101MB1128.namprd21.prod.outlook.com ([fe80::81f8:300e:d90:d49]) by DM5PR2101MB1128.namprd21.prod.outlook.com ([fe80::81f8:300e:d90:d49%3]) with mapi id 15.20.1164.008; Fri, 21 Sep 2018 08:26:11 +0000 From: Chris Co To: "edk2-devel@lists.01.org" CC: Ard Biesheuvel , Leif Lindholm , Michael D Kinney Thread-Topic: [PATCH edk2-platforms 18/27] Silicon/NXP: Add i.MX6 Clock Library Thread-Index: AQHUUYTA0acqaZLu0EiEUPizJh488A== Date: Fri, 21 Sep 2018 08:26:11 +0000 Message-ID: <20180921082542.35768-19-christopher.co@microsoft.com> References: <20180921082542.35768-1-christopher.co@microsoft.com> In-Reply-To: <20180921082542.35768-1-christopher.co@microsoft.com> Accept-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-clientproxiedby: MWHPR17CA0054.namprd17.prod.outlook.com (2603:10b6:300:93::16) To DM5PR2101MB1128.namprd21.prod.outlook.com (2603:10b6:4:a8::20) x-ms-exchange-messagesentrepresentingtype: 1 x-originating-ip: [2001:4898:80e8:8:388a:edc9:7085:c18] x-ms-publictraffictype: Email x-microsoft-exchange-diagnostics: 1; DM5PR2101MB0727; 6:eBY2KXOHzjlLr2CMWX6JSPtvTdOnFxc13jA0/pu5S10o4yOX2DIQfUAFvyWbHWKyZHkDs4OXaiwDj+38NyyHQ30/a8+mDdUDUXmwqfO/qBfp5xrQeEioJRWEqk3g8B1mg6RZP274p3Hmdz9HBk0VIUIpwrkq22ayreqYkB/BmikwvMYTBNN2ltAM3xtJuhYLMsq1mhs2T/riuSHXWH2IQ2ZoI+BOT8No1c9A7NiHBJYfxQmUa0F9JFkEOXv0Ws+2x+pSTXfSxtIKbUOYwpONowCcrvl0Ps4iU8kivaHCMX2kkqZbwOPPt5NUGTu2xmjN1R39vsxYH6VPbaK0cGUjJruH0JAzwM2rRd4i0xP3u2Zuxyd1kDaIwxmd++Eg65y6EYl1+AqgN4V9pG+BU4FKGjWT/Q7o5FSZiFwkCHocixcjvGhBGWXoxMOrdK0Z1Z3MqHZ1qvY2VUpcxv7h8h4jfw==; 5:Wf/HPKoHZrZ1q9fmaaRyDk81FpiRHQnko87T16GKAq5sjl1YeQWaYLekDQDdReEofry1r5U4cuT24v3X8OyMOiYPrDPrY126miGSaTSM6xpZBsGXdyOM33fJZi/zKN4MAP2hfJl5RZ/iTz6Nz8ZOPyHl48X13yeUCXlJ3Vmb0v4=; 7:dzeYVMX5qRsKnkLF0/wCN3qgj3coNtdDxDv7xzOarYjgi9vA+/YBG1ryWOb0KvY//UvNeaof1C1RX9wghiGEN153IIj3Mi0tpFoWEPQr6bcirnb0/BNq2xtBpH6DjT8tRnpsBHrtn9lJO2SCH3+IXa2sMQbQf8YNflpJBJE8XmrXAOeq0qG2tmJchSWSo5TOAMuxlg5sSqhFEB2YSOliLQ7WHKeMm7VDtCPzW6K2VdQA2tbmdS05fPLm9ncgNu6e x-ms-office365-filtering-correlation-id: e4d376e0-b2de-447c-b8e3-08d61f9be268 x-ms-office365-filtering-ht: Tenant x-microsoft-antispam: BCL:0; PCL:0; RULEID:(7020095)(4652040)(8989299)(4534165)(4627221)(201703031133081)(201702281549075)(8990200)(5600074)(711020)(4618075)(2017052603328)(7193020); SRVR:DM5PR2101MB0727; x-ms-traffictypediagnostic: DM5PR2101MB0727: x-microsoft-antispam-prvs: x-exchange-antispam-report-test: UriScan:(28532068793085)(89211679590171)(12401385986421)(228905959029699); x-ms-exchange-senderadcheck: 1 x-exchange-antispam-report-cfa-test: BCL:0; PCL:0; RULEID:(8211001083)(6040522)(2401047)(8121501046)(5005006)(3231355)(2280164)(944501410)(52105095)(2018427008)(93006095)(93001095)(3002001)(10201501046)(6055026)(149027)(150027)(6041310)(201703131423095)(201702281528075)(20161123555045)(201703061421075)(201703061406153)(20161123562045)(20161123560045)(20161123564045)(20161123558120)(201708071742011)(7699051)(76991041); SRVR:DM5PR2101MB0727; BCL:0; PCL:0; RULEID:; SRVR:DM5PR2101MB0727; x-forefront-prvs: 0802ADD973 x-forefront-antispam-report: SFV:NSPM; SFS:(10019020)(1496009)(39860400002)(396003)(136003)(376002)(366004)(346002)(199004)(189003)(8676002)(81156014)(25786009)(446003)(2900100001)(102836004)(46003)(52116002)(6346003)(81166006)(11346002)(105586002)(2351001)(8936002)(386003)(4326008)(76176011)(6506007)(10090500001)(5250100002)(7736002)(2616005)(486006)(305945005)(53376002)(6116002)(186003)(16799955002)(1076002)(2501003)(476003)(6916009)(99286004)(22452003)(97736004)(45954006)(71200400001)(71190400001)(72206003)(478600001)(966005)(6306002)(10290500003)(5640700003)(14454004)(36756003)(86362001)(19627235002)(575784001)(6436002)(16200700003)(15188155005)(2906002)(53946003)(86612001)(106356001)(54906003)(316002)(6486002)(256004)(6512007)(14444005)(68736007)(5660300001)(53936002)(60540400001)(579004)(569006); DIR:OUT; SFP:1102; SCL:1; SRVR:DM5PR2101MB0727; H:DM5PR2101MB1128.namprd21.prod.outlook.com; FPR:; SPF:None; LANG:en; PTR:InfoNoRecords; A:1; MX:1; received-spf: None (protection.outlook.com: microsoft.com does not designate permitted sender hosts) authentication-results: spf=none (sender IP is ) smtp.mailfrom=Christopher.Co@microsoft.com; x-microsoft-antispam-message-info: z5PJEwnFthaQib0Y3GU3+BXQCECa800+hu5AUOoXHSs/6cBYXCJrIG1CFXG0AkxQjlVH7P2Du47GW/JaY2Jjo69k9WLzZIpA6JQC516HzNL9lhiAH/x18o8u7M7VHycdMfgoIynqHzb+//if+BqmoIkAmKfbwYzOFhHaY/ytc38xyfwm08QY6+wgFn+qAu0yRwW+YXrQc89/SACKINW/s3QZvqsB9Zx6+0DQ+hxwuskwTWlnhxN89WPXvTO+iWVkzYmnRMbmoc7RWe7RssMs1NFtvKvMn+KnqKBIdotSPDagIJUm6YT4OjYWBkuY4kICYEmSLXlwNvqvJv/mu0l/ZOP2TZNJ/LPOK2CFXMJIDipYoO24RbWwvh4PVOK0bfGA0DXENQoqR8m4ZPDfxWG6udaKg65D9nwX/CCAfL1VWJNbbBrN40caOkKsvZLjrUnzRk6hQGPQWA2OCZZfR7eU0wUoRQZB6P8uHn3mW6biYate3pnltn2hL6hgNVQ8yEDnFxO1lQkO/XL485N6aKdmmNE8CUtCmlYECsMYObN2ing29DNRWeYSagjLxzHKsnk0 spamdiagnosticoutput: 1:99 spamdiagnosticmetadata: NSPM MIME-Version: 1.0 X-OriginatorOrg: microsoft.com X-MS-Exchange-CrossTenant-Network-Message-Id: e4d376e0-b2de-447c-b8e3-08d61f9be268 X-MS-Exchange-CrossTenant-originalarrivaltime: 21 Sep 2018 08:26:11.1847 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 72f988bf-86f1-41af-91ab-2d7cd011db47 X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM5PR2101MB0727 Subject: [PATCH edk2-platforms 18/27] Silicon/NXP: Add i.MX6 Clock Library X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 21 Sep 2018 08:26:14 -0000 Content-Language: en-US Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable This adds support for managing clocks on NXP i.MX6 SoC. It will manipulate the Clock Gating registers (CCGR). Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Christopher Co Cc: Ard Biesheuvel Cc: Leif Lindholm Cc: Michael D Kinney --- Silicon/NXP/iMX6Pkg/Library/iMX6ClkPwrLib/iMX6ClkPwr.c | 1876 ++++= ++++++++++++++++ Silicon/NXP/iMX6Pkg/Library/iMX6ClkPwrLib/iMX6ClkPwrLib.inf | 46 + Silicon/NXP/iMX6Pkg/Library/iMX6ClkPwrLib/iMX6ClkPwr_private.h | 221 +++ 3 files changed, 2143 insertions(+) diff --git a/Silicon/NXP/iMX6Pkg/Library/iMX6ClkPwrLib/iMX6ClkPwr.c b/Silic= on/NXP/iMX6Pkg/Library/iMX6ClkPwrLib/iMX6ClkPwr.c new file mode 100644 index 000000000000..07958b1e392d --- /dev/null +++ b/Silicon/NXP/iMX6Pkg/Library/iMX6ClkPwrLib/iMX6ClkPwr.c @@ -0,0 +1,1876 @@ +/** @file +* +* Copyright (c) 2018 Microsoft Corporation. All rights reserved. +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the B= SD License +* which accompanies this distribution. The full text of the license may = be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IM= PLIED. +* +**/ + +#include + +#include +#include +#include +#include + +#include +#include +#include "iMX6ClkPwr_private.h" + +static IMX_CLOCK_TREE_CACHE mImxpClockPwrCache; // Cached clock value + +STATIC CONST IMX_CCGR_INDEX ImxpCcgrIndexMap[] =3D { + {0, 0}, // MX6_AIPS_TZ1_CLK_ENABLE + {0, 1}, // MX6_AIPS_TZ2_CLK_ENABLE + {0, 2}, // MX6_APBHDMA_HCLK_ENABLE + {0, 3}, // MX6_ASRC_CLK_ENABLE + {0, 4}, // MX6_CAAM_SECURE_MEM_CLK_ENABLE + {0, 5}, // MX6_CAAM_WRAPPER_ACLK_ENABLE + {0, 6}, // MX6_CAAM_WRAPPER_IPG_ENABLE + {0, 7}, // MX6_CAN1_CLK_ENABLE + {0, 8}, // MX6_CAN1_SERIAL_CLK_ENABLE + {0, 9}, // MX6_CAN2_CLK_ENABLE + {0, 10}, // MX6_CAN2_SERIAL_CLK_ENABLE + {0, 11}, // MX6_ARM_DBG_CLK_ENABLE + {0, 12}, // MX6_DCIC1_CLK_ENABLE + {0, 13}, // MX6_DCIC2_CLK_ENABLE + {0, 14}, // MX6_DTCP_CLK_ENABLE + {1, 0}, // MX6_ECSPI1_CLK_ENABLE + {1, 1}, // MX6_ECSPI2_CLK_ENABLE + {1, 2}, // MX6_ECSPI3_CLK_ENABLE + {1, 3}, // MX6_ECSPI4_CLK_ENABLE + {1, 4}, // MX6_ECSPI5_CLK_ENABLE + {1, 5}, // MX6_ENET_CLK_ENABLE + {1, 6}, // MX6_EPIT1_CLK_ENABLE + {1, 7}, // MX6_EPIT2_CLK_ENABLE + {1, 8}, // MX6_ESAI_CLK_ENABLE + {1, 10}, // MX6_GPT_CLK_ENABLE + {1, 11}, // MX6_GPT_SERIAL_CLK_ENABLE + {1, 12}, // MX6_GPU2D_CLK_ENABLE + {1, 13}, // MX6_GPU3D_CLK_ENABLE + {2, 0}, // MX6_HDMI_TX_ENABLE + {2, 2}, // MX6_HDMI_TX_ISFRCLK_ENABLE + {2, 3}, // MX6_I2C1_SERIAL_CLK_ENABLE + {2, 4}, // MX6_I2C2_SERIAL_CLK_ENABLE + {2, 5}, // MX6_I2C3_SERIAL_CLK_ENABLE + {2, 6}, // MX6_IIM_CLK_ENABLE + {2, 7}, // MX6_IOMUX_IPT_CLK_IO_ENABLE + {2, 8}, // MX6_IPMUX1_CLK_ENABLE + {2, 9}, // MX6_IPMUX2_CLK_ENABLE + {2, 10}, // MX6_IPMUX3_CLK_ENABLE + {2, 11}, // MX6_IPSYNC_IP2APB_TZASC1_IPG_MASTER_CLK_ENABLE + {2, 12}, // MX6_IPSYNC_IP2APB_TZASC2_IPG_MASTER_CLK_ENABLE + {2, 13}, // MX6_IPSYNC_VDOA_IPG_MASTER_CLK_ENABLE + {3, 0}, // MX6_IPU1_IPU_CLK_ENABLE + {3, 1}, // MX6_IPU1_IPU_DI0_CLK_ENABLE + {3, 2}, // MX6_IPU1_IPU_DI1_CLK_ENABLE + {3, 3}, // MX6_IPU2_IPU_CLK_ENABLE + {3, 4}, // MX6_IPU2_IPU_DI0_CLK_ENABLE + {3, 5}, // MX6_IPU2_IPU_DI1_CLK_ENABLE + {3, 6}, // MX6_LDB_DI0_CLK_ENABLE + {3, 7}, // MX6_LDB_DI1_CLK_ENABLE + {3, 8}, // MX6_MIPI_CORE_CFG_CLK_ENABLE + {3, 9}, // MX6_MLB_CLK_ENABLE + {3, 10}, // MX6_MMDC_CORE_ACLK_FAST_CORE_P0_ENABLE + {3, 12}, // MX6_MMDC_CORE_IPG_CLK_P0_ENABLE + {3, 14}, // MX6_OCRAM_CLK_ENABLE + {3, 15}, // MX6_OPENVGAXICLK_CLK_ROOT_ENABLE + {4, 0}, // MX6_PCIE_ROOT_ENABLE + {4, 4}, // MX6_PL301_MX6QFAST1_S133CLK_ENABLE + {4, 6}, // MX6_PL301_MX6QPER1_BCHCLK_ENABLE + {4, 7}, // MX6_PL301_MX6QPER2_MAINCLK_ENABLE + {4, 8}, // MX6_PWM1_CLK_ENABLE + {4, 9}, // MX6_PWM2_CLK_ENABLE + {4, 10}, // MX6_PWM3_CLK_ENABLE + {4, 11}, // MX6_PWM4_CLK_ENABLE + {4, 12}, // MX6_RAWNAND_U_BCH_INPUT_APB_CLK_ENABLE + {4, 13}, // MX6_RAWNAND_U_GPMI_BCH_INPUT_BCH_CLK_ENABLE + {4, 14}, // MX6_RAWNAND_U_GPMI_BCH_INPUT_GPMI_IO_CLK_ENABLE + {4, 15}, // MX6_RAWNAND_U_GPMI_INPUT_APB_CLK_ENABLE + {5, 0}, // MX6_ROM_CLK_ENABLE + {5, 2}, // MX6_SATA_CLK_ENABLE + {5, 3}, // MX6_SDMA_CLK_ENABLE + {5, 6}, // MX6_SPBA_CLK_ENABLE + {5, 7}, // MX6_SPDIF_CLK_ENABLE + {5, 9}, // MX6_SSI1_CLK_ENABLE + {5, 10}, // MX6_SSI2_CLK_ENABLE + {5, 11}, // MX6_SSI3_CLK_ENABLE + {5, 12}, // MX6_UART_CLK_ENABLE + {5, 13}, // MX6_UART_SERIAL_CLK_ENABLE + {6, 0}, // MX6_USBOH3_CLK_ENABLE + {6, 1}, // MX6_USDHC1_CLK_ENABLE + {6, 2}, // MX6_USDHC2_CLK_ENABLE + {6, 3}, // MX6_USDHC3_CLK_ENABLE + {6, 4}, // MX6_USDHC4_CLK_ENABLE + {6, 5}, // MX6_EIM_SLOW_CLK_ENABLE + {6, 6}, // MX6_VDOAXICLK_CLK_ENABLE + {6, 7}, // MX6_VPU_CLK_ENABLE +}; + +#if defined(CPU_IMX6DQ) || defined(CPU_IMX6DQP) +STATIC IMX_CLOCK_CONTEXT ExpectedClocks[] =3D { + {IMX_OSC_CLK, {24000000, IMX_CLK_NONE}}, + {IMX_PLL1_MAIN_CLK, {792000000, IMX_OSC_CLK}}, + {IMX_PLL2_MAIN_CLK, {528000000, IMX_OSC_CLK}}, + {IMX_PLL2_PFD0, {352000000, IMX_PLL2_MAIN_CLK}}, + {IMX_PLL2_PFD1, {594000000, IMX_PLL2_MAIN_CLK}}, + {IMX_PLL2_PFD2, {396000000, IMX_PLL2_MAIN_CLK}}, + {IMX_PLL3_MAIN_CLK, {480000000, IMX_OSC_CLK}}, + {IMX_PLL3_PFD0, {720000000, IMX_PLL3_MAIN_CLK}}, + {IMX_PLL3_PFD1, {540000000, IMX_PLL3_MAIN_CLK}}, + {IMX_PLL3_PFD2, {508235294, IMX_PLL3_MAIN_CLK}}, + {IMX_PLL3_PFD3, {454736842, IMX_PLL3_MAIN_CLK}}, + {IMX_AXI_CLK_ROOT, {264000000, IMX_PERIPH_CLK}}, + {IMX_MMDC_CH0_CLK_ROOT, {528000000, IMX_PERIPH_CLK}}, +}; +#elif defined(CPU_IMX6SDL) +STATIC IMX_CLOCK_CONTEXT ExpectedClocks[] =3D { + {IMX_OSC_CLK, {24000000, IMX_CLK_NONE}}, + {IMX_PLL1_MAIN_CLK, {792000000, IMX_OSC_CLK}}, + {IMX_PLL2_MAIN_CLK, {528000000, IMX_OSC_CLK}}, + {IMX_PLL2_PFD0, {306580645, IMX_PLL2_MAIN_CLK}}, + {IMX_PLL2_PFD1, {528000000, IMX_PLL2_MAIN_CLK}}, + {IMX_PLL2_PFD2, {396000000, IMX_PLL2_MAIN_CLK}}, + {IMX_PLL3_MAIN_CLK, {480000000, IMX_OSC_CLK}}, + {IMX_PLL3_PFD0, {720000000, IMX_PLL3_MAIN_CLK}}, + {IMX_PLL3_PFD1, {540000000, IMX_PLL3_MAIN_CLK}}, + {IMX_PLL3_PFD2, {508235294, IMX_PLL3_MAIN_CLK}}, + {IMX_PLL3_PFD3, {454736842, IMX_PLL3_MAIN_CLK}}, + {IMX_AXI_CLK_ROOT, {198000000, IMX_PERIPH_CLK}}, + {IMX_MMDC_CH0_CLK_ROOT, {396000000, IMX_PERIPH_CLK}}, +}; +#endif + +/** + Get the CCGR register index and gate number for a clock gate. + + @param[in] ClockGate Specific clock gate to get CCGR index +**/ +IMX_CCGR_INDEX +ImxpCcgrIndexFromClkGate ( + IN IMX_CLK_GATE ClockGate + ) +{ + return ImxpCcgrIndexMap[ClockGate]; +} + +CONST CHAR16* +StringFromImxClk ( + IN IMX_CLK Value + ) +{ + switch (Value) { + case IMX_CLK_NONE: + return L"(none)"; + case IMX_OSC_CLK: + return L"OSC_CLK"; + case IMX_PLL1_MAIN_CLK: + return L"PLL1_MAIN_CLK"; + case IMX_PLL2_MAIN_CLK: + return L"PLL2_MAIN_CLK"; + case IMX_PLL2_PFD0: + return L"PLL2_PFD0"; + case IMX_PLL2_PFD1: + return L"PLL2_PFD1"; + case IMX_PLL2_PFD2: + return L"PLL2_PFD2"; + case IMX_PLL3_MAIN_CLK: + return L"PLL3_MAIN_CLK"; + case IMX_PLL3_PFD0: + return L"PLL3_PFD0"; + case IMX_PLL3_PFD1: + return L"PLL3_PFD1"; + case IMX_PLL3_PFD2: + return L"PLL3_PFD2"; + case IMX_PLL3_PFD3: + return L"PLL3_PFD3"; + case IMX_PLL4_MAIN_CLK: + return L"PLL4_MAIN_CLK"; + case IMX_PLL5_MAIN_CLK: + return L"PLL5_MAIN_CLK"; + case IMX_CLK1: + return L"CLK1"; + case IMX_CLK2: + return L"CLK2"; + case IMX_PLL1_SW_CLK: + return L"PLL1_SW_CLK"; + case IMX_STEP_CLK: + return L"STEP_CLK"; + case IMX_PLL3_SW_CLK: + return L"PLL3_SW_CLK"; + case IMX_AXI_ALT: + return L"AXI_ALT"; + case IMX_AXI_CLK_ROOT: + return L"AXI_CLK_ROOT"; + case IMX_PERIPH_CLK2: + return L"PERIPH_CLK2"; + case IMX_PERIPH_CLK: + return L"PERIPH_CLK"; + case IMX_PRE_PERIPH_CLK: + return L"PRE_PERIPH_CLK"; + case IMX_PRE_PERIPH2_CLK: + return L"PRE_PERIPH2_CLK"; + case IMX_PERIPH2_CLK: + return L"PERIPH2_CLK"; + case IMX_ARM_CLK_ROOT: + return L"ARM_CLK_ROOT"; + case IMX_MMDC_CH0_CLK_ROOT: + return L"MMDC_CH0_CLK_ROOT"; + case IMX_MMDC_CH1_CLK_ROOT: + return L"MMDC_CH1_CLK_ROOT"; + case IMX_AHB_CLK_ROOT: + return L"AHB_CLK_ROOT"; + case IMX_IPG_CLK_ROOT: + return L"IPG_CLK_ROOT"; + case IMX_PERCLK_CLK_ROOT: + return L"PERCLK_CLK_ROOT"; + case IMX_USDHC1_CLK_ROOT: + return L"USDHC1_CLK_ROOT"; + case IMX_USDHC2_CLK_ROOT: + return L"USDHC2_CLK_ROOT"; + case IMX_USDHC3_CLK_ROOT: + return L"USDHC3_CLK_ROOT"; + case IMX_USDHC4_CLK_ROOT: + return L"USDHC4_CLK_ROOT"; + case IMX_SSI1_CLK_ROOT: + return L"SSI1_CLK_ROOT"; + case IMX_SSI2_CLK_ROOT: + return L"SSI2_CLK_ROOT"; + case IMX_SSI3_CLK_ROOT: + return L"SSI3_CLK_ROOT"; + case IMX_GPU2D_AXI_CLK_ROOT: + return L"GPU2D_AXI_CLK_ROOT"; + case IMX_GPU3D_AXI_CLK_ROOT: + return L"GPU3D_AXI_CLK_ROOT"; + case IMX_PCIE_AXI_CLK_ROOT: + return L"PCIE_AXI_CLK_ROOT"; + case IMX_VDO_AXI_CLK_ROOT: + return L"VDO_AXI_CLK_ROOT"; + case IMX_IPU1_HSP_CLK_ROOT: + return L"IPU1_HSP_CLK_ROOT"; + case IMX_GPU2D_CORE_CLK_ROOT: + return L"GPU2D_CORE_CLK_ROOT"; + case IMX_ACLK_EIM_SLOW_CLK_ROOT: + return L"ACLK_EIM_SLOW_CLK_ROOT"; + case IMX_ACLK_CLK_ROOT: + return L"ACLK_CLK_ROOT"; + case IMX_ENFC_CLK_ROOT: + return L"ENFC_CLK_ROOT"; + case IMX_GPU3D_CORE_CLK_ROOT: + return L"GPU3D_CORE_CLK_ROOT"; + case IMX_GPU3D_SHADER_CLK_ROOT: + return L"GPU3D_SHADER_CLK_ROOT"; + case IMX_VPU_AXI_CLK_ROOT: + return L"VPU_AXI_CLK_ROOT"; + case IMX_IPU1_DI0_CLK_ROOT: + return L"IPU1_DI0_CLK_ROOT"; + case IMX_IPU1_DI1_CLK_ROOT: + return L"IPU1_DI1_CLK_ROOT"; + case IMX_LDB_DI0_SERIAL_CLK_ROOT: + return L"LDB_DI0_SERIAL_CLK_ROOT"; + case IMX_LDB_DI0_IPU: + return L"LDB_DI0_IPU"; + case IMX_LDB_DI1_SERIAL_CLK_ROOT: + return L"LDB_DI1_SERIAL_CLK_ROOT"; + case IMX_LDB_DI1_IPU: + return L"LDB_DI1_IPU"; + case IMX_SPDIF0_CLK_ROOT: + return L"SPDIF0_CLK_ROOT"; + case IMX_SPDIF1_CLK_ROOT: + return L"SPDIF1_CLK_ROOT"; + case IMX_ESAI_CLK_ROOT: + return L"ESAI_CLK_ROOT"; + case IMX_HSI_TX_CLK_ROOT: + return L"HSI_TX_CLK_ROOT"; + case IMX_CAN_CLK_ROOT: + return L"CAN_CLK_ROOT"; + case IMX_ECSPI_CLK_ROOT: + return L"ECSPI_CLK_ROOT"; + case IMX_UART_CLK_ROOT: + return L"UART_CLK_ROOT"; + case IMX_VIDEO_27M_CLK_ROOT: + return L"VIDEO_27M_CLK_ROOT"; +#if defined(CPU_IMX6DQ) || defined(CPU_IMX6DQP) + case IMX_IPU2_HSP_CLK_ROOT: + return L"IPU2_HSP_CLK_ROOT"; + case IMX_IPU2_DI0_CLK_ROOT: + return L"IPU2_DI0_CLK_ROOT"; + case IMX_IPU2_DI1_CLK_ROOT: + return L"IPU2_DI1_CLK_ROOT"; +#endif + default: + ASSERT (FALSE); + return L"[Invalid IMX_CLK value]"; + } +} + +IMX_CLK +ImxpClkFromBypassClkSource ( + IN IMX_PLL_BYPASS_CLK_SRC BypassClockSource + ) +{ + switch (BypassClockSource) { + case IMX_PLL_BYPASS_CLK_SRC_REF_CLK_24M: + return IMX_OSC_CLK; + case IMX_PLL_BYPASS_CLK_SRC_CLK1: + return IMX_CLK1; + case IMX_PLL_BYPASS_CLK_SRC_CLK2: + return IMX_CLK2; + case IMX_PLL_BYPASS_CLK_SRC_XOR: + default: + ASSERT (FALSE); + return IMX_CLK_NONE; + } +} + +/** + Configure the GPU clock tree so that GPU2D and GPU3D are clocked from + the AXI clock root and are within the allowed frequency range. + + The GPU must be powered down, and GPU clocks must be gated when this + function is called. +**/ +VOID +ImxCcmConfigureGpuClockTree ( + VOID + ) +{ + volatile IMX_CCM_REGISTERS *pCcmRegisters; + IMX_CCM_CBCMR_REG CbcmrReg; + + pCcmRegisters =3D (IMX_CCM_REGISTERS *) IMX_CCM_BASE; + CbcmrReg.AsUint32 =3D MmioRead32 ((UINTN) &pCcmRegisters->CBCMR); + + CbcmrReg.gpu2d_axi_clk_sel =3D IMX_CCM_GPU2D_AXI_CLK_SEL_AXI; + CbcmrReg.gpu3d_axi_clk_sel =3D IMX_CCM_GPU3D_AXI_CLK_SEL_AXI; + CbcmrReg.gpu2d_core_clk_sel =3D IMX_CCM_GPU2D_CORE_CLK_SEL_PLL2_PFD0; + CbcmrReg.gpu3d_core_clk_sel =3D IMX_CCM_GPU3D_CORE_CLK_SEL_MMDC_CH0_AXI; + CbcmrReg.gpu3d_shader_clk_sel =3D IMX_CCM_GPU3D_SHADER_CLK_SEL_MMDC_CH0_= AXI; + CbcmrReg.gpu2d_core_clk_podf =3D 0; + CbcmrReg.gpu3d_core_podf =3D 0; + CbcmrReg.gpu3d_shader_podf =3D 0; + + ImxpClkPwrCacheReset (); + MmioWrite32 ((UINTN) &pCcmRegisters->CBCMR, CbcmrReg.AsUint32); +} + +/** + Configure all of DIx clock tree for both IPU1 and IPU2. For flexibility + purpose use PLL5 (PLL Video) as main reference clock. PLL 5 has flexible + divider making it easily configurable. Muxing and clock programming need= s + when to be updated when supporting multiple display. +**/ +VOID +ImxCcmConfigureIPUDIxClockTree ( + VOID + ) +{ + volatile IMX_CCM_REGISTERS *pCcmRegisters; + IMX_CCM_CHSCCDR_REG ChscddrReg; + + pCcmRegisters =3D (IMX_CCM_REGISTERS *) IMX_CCM_BASE; + ChscddrReg.AsUint32 =3D MmioRead32 ((UINTN)&pCcmRegisters->CHSCCDR); + + // Setup muxing to pre-mux + if (FeaturePcdGet (PcdLvdsEnable)) { + ChscddrReg.ipu1_di0_clk_sel =3D IMX_CHSCCDR_IPU1_DI0_CLK_SEL_LDB_DI0_C= LK; + ChscddrReg.ipu1_di1_clk_sel =3D IMX_CHSCCDR_IPU1_DI0_CLK_SEL_LDB_DI0_C= LK; + } else { + ChscddrReg.ipu1_di0_clk_sel =3D IMX_CHSCCDR_IPU1_DI0_CLK_SEL_PREMUX; + ChscddrReg.ipu1_di1_clk_sel =3D IMX_CHSCCDR_IPU1_DI1_CLK_SEL_PREMUX; + } + ChscddrReg.ipu1_di0_podf =3D IMX_CHSCCDR_IPU1_DI0_PODF_DIV_1; + ChscddrReg.ipu1_di1_podf =3D IMX_CHSCCDR_IPU1_DI1_PODF_DIV_1; + ChscddrReg.ipu1_di0_pre_clk_sel =3D IMX_CHSCCDR_IPU1_DI0_PRE_CLK_SEL_PLL= 5; + ChscddrReg.ipu1_di1_pre_clk_sel =3D IMX_CHSCCDR_IPU1_DI1_PRE_CLK_SEL_PLL= 5; + + MmioWrite32 ((UINTN)&pCcmRegisters->CHSCCDR, ChscddrReg.AsUint32); +} + +#if defined(CPU_IMX6DQ) || defined(CPU_IMX6DQP) +/** + Configure both LDB0/1 to use PLL5 clock +**/ +VOID +ImxCcmConfigureIPULDBxClockTree ( + VOID + ) +{ + volatile IMX_CCM_REGISTERS *pCcmRegisters; + IMX_CCM_CS2CDR_REG Cs2cdrReg; + + pCcmRegisters =3D (IMX_CCM_REGISTERS *) IMX_CCM_BASE; + Cs2cdrReg.AsUint32 =3D MmioRead32 ((UINTN)&pCcmRegisters->CS2CDR); + + Cs2cdrReg.ldb_di0_clk_sel =3D 0x0; + Cs2cdrReg.ldb_di1_clk_sel =3D 0x0; + + MmioWrite32 ((UINTN)&pCcmRegisters->CS2CDR, Cs2cdrReg.AsUint32); +} +#endif + +/** + Configure PLL 5 clock rate to the desired clock rate +**/ +VOID +ImxSetClockRatePLL5 ( + IN UINT32 ClockRate, + IN IMX_CCM_PLL_VIDEO_CTRL_POST_DIV_SELECT PostDivSelect + ) +{ + volatile IMX_CCM_ANALOG_REGISTERS *pCcmAnalogRegisters; + UINT32 Counter; + UINT32 Denom; + UINT32 DivSelect; + UINT32 Numerator; + IMX_CCM_PLL_VIDEO_CTRL_REG PllVideoCtrlClearReg; + IMX_CCM_PLL_VIDEO_CTRL_REG PllVideoCtrlReg; + IMX_CCM_PLL_VIDEO_CTRL_REG PllVideoCtrlSetReg; + + // Use clock rate as Denom for simple fractional calculation + Denom =3D IMX_REF_CLK_24M_FREQ; + DivSelect =3D ClockRate / IMX_REF_CLK_24M_FREQ; + Numerator =3D ClockRate % IMX_REF_CLK_24M_FREQ; + pCcmAnalogRegisters =3D (IMX_CCM_ANALOG_REGISTERS *)IMX_CCM_ANALOG_BASE; + PllVideoCtrlReg.AsUint32 =3D MmioRead32 ((UINTN)&pCcmAnalogRegisters->PL= L_VIDEO); + + ASSERT (Numerator < Denom); + ASSERT ((DivSelect >=3D 27) && (DivSelect <=3D 54)); + + // PLL output frequency =3D Fref * (DIV_SELECT + NUM / DENOM) + PllVideoCtrlReg.DIV_SELECT =3D DivSelect; + PllVideoCtrlReg.POST_DIV_SELECT =3D PostDivSelect; + + MmioWrite32 ( + (UINTN)&pCcmAnalogRegisters->PLL_VIDEO, PllVideoCtrlReg.AsUint32); + MmioWrite32 ( + (UINTN)&pCcmAnalogRegisters->PLL_VIDEO_NUM, Numerator); + MmioWrite32 ( + (UINTN)&pCcmAnalogRegisters->PLL_VIDEO_DENOM, Denom); + + PllVideoCtrlReg.AsUint32 =3D MmioRead32 ( + (UINTN)&pCcmAnalogRegisters->PLL_VIDEO); + + // Check to see if pll is locked, if not attempt to enable it + if (PllVideoCtrlReg.LOCK =3D=3D 0) { + PllVideoCtrlClearReg.AsUint32 =3D 0; + PllVideoCtrlClearReg.POWERDOWN =3D 1; + MmioWrite32 ( + (UINTN)&pCcmAnalogRegisters->PLL_VIDEO_CLR, + PllVideoCtrlClearReg.AsUint32); + PllVideoCtrlReg.AsUint32 =3D MmioRead32 ((UINTN)&pCcmAnalogRegisters->= PLL_VIDEO); + + PllVideoCtrlSetReg.AsUint32 =3D 0; + PllVideoCtrlSetReg.ENABLE =3D 1; + MmioWrite32 ( + (UINTN)&pCcmAnalogRegisters->PLL_VIDEO_SET, + PllVideoCtrlSetReg.AsUint32); + PllVideoCtrlReg.AsUint32 =3D MmioRead32 ((UINTN)&pCcmAnalogRegisters->= PLL_VIDEO); + + PllVideoCtrlClearReg.AsUint32 =3D 0; + PllVideoCtrlClearReg.BYPASS =3D 1; + MmioWrite32 ( + (UINTN)&pCcmAnalogRegisters->PLL_VIDEO_CLR, + PllVideoCtrlClearReg.AsUint32); + PllVideoCtrlReg.AsUint32 =3D MmioRead32 ((UINTN)&pCcmAnalogRegisters->= PLL_VIDEO); + + for (Counter =3D 0; Counter < 10000; Counter++) { + PllVideoCtrlReg.AsUint32 =3D MmioRead32 ((UINTN)&pCcmAnalogRegisters= ->PLL_VIDEO); + if (PllVideoCtrlReg.LOCK =3D=3D 1) { + DEBUG ((DEBUG_VERBOSE, "%a: PLL5 Video locked.\n", __FUNCTION__)); + break; + } + } + if (PllVideoCtrlReg.LOCK =3D=3D 0) { + DEBUG ((DEBUG_ERROR, "%a: PLL5 Video not locked.\n", __FUNCTION__)); + } + } +} + +EFI_STATUS +ImxpGetPll2PfdClkInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + IN IMX_PLL_PFD PfdIndex, + OUT IMX_CLOCK_INFO *ClockInfo + ) +{ + volatile IMX_CCM_ANALOG_REGISTERS *pCcmAnalogRegisters; + IMX_CLOCK_INFO ParentInfo; + IMX_CCM_PFD_528_REG Pfd528Reg; + UINT32 PfdFrac; + EFI_STATUS Status; + + pCcmAnalogRegisters =3D (IMX_CCM_ANALOG_REGISTERS *) IMX_CCM_ANALOG_BASE= ; + Pfd528Reg.AsUint32 =3D MmioRead32 ((UINTN) &pCcmAnalogRegisters->PFD_528= ); + switch (PfdIndex) { + case IMX_PLL_PFD0: + PfdFrac =3D Pfd528Reg.PFD0_FRAC; + break; + case IMX_PLL_PFD1: + PfdFrac =3D Pfd528Reg.PFD1_FRAC; + break; + case IMX_PLL_PFD2: + PfdFrac =3D Pfd528Reg.PFD2_FRAC; + break; + default: + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + Status =3D ImxpGetClockInfo (Cache, IMX_PLL2_MAIN_CLK, &ParentInfo); + if (EFI_ERROR (Status)) { + return Status; + } + + // The resulting frequency shall be 528*18/PFDn_FRAC + // where PFD0_FRAC is in the range 12-35. + ASSERT ((PfdFrac >=3D 12) && (PfdFrac <=3D 35)); + ClockInfo->Frequency =3D (UINT32) ((UINT64) ParentInfo.Frequency * 18 / = PfdFrac); + ClockInfo->Parent =3D IMX_PLL2_MAIN_CLK; + + return EFI_SUCCESS; +} + +EFI_STATUS +ImxpGetAxiClkRootInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + OUT IMX_CLOCK_INFO *ClockInfo + ) +{ + volatile IMX_CCM_REGISTERS *pCcmRegisters; + IMX_CCM_CBCDR_REG CbcdrReg; + IMX_CLK Parent; + IMX_CLOCK_INFO ParentInfo; + EFI_STATUS Status; + + pCcmRegisters =3D (IMX_CCM_REGISTERS *) IMX_CCM_BASE; + CbcdrReg.AsUint32 =3D MmioRead32 ((UINTN) &pCcmRegisters->CBCDR); + + if (CbcdrReg.axi_sel =3D=3D IMX_CCM_AXI_SEL_PERIPH_CLK) { + Parent =3D IMX_PERIPH_CLK; + } else { + ASSERT (CbcdrReg.axi_sel =3D=3D IMX_CCM_AXI_SEL_AXI_ALT); + Parent =3D IMX_AXI_ALT; + } + + Status =3D ImxpGetClockInfo (Cache, Parent, &ParentInfo); + if (EFI_ERROR (Status)) { + return Status; + } + + ClockInfo->Frequency =3D ParentInfo.Frequency / (1 + CbcdrReg.axi_podf); + ClockInfo->Parent =3D Parent; + return EFI_SUCCESS; +} + +EFI_STATUS +ImxpGetGpu2dCoreClkInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + OUT IMX_CLOCK_INFO *ClockInfo + ) +{ + volatile IMX_CCM_REGISTERS *pCcmRegisters; + IMX_CCM_CBCMR_REG CbcmrReg; + IMX_CLK Parent; + IMX_CLOCK_INFO ParentInfo; + EFI_STATUS Status; + + pCcmRegisters =3D (IMX_CCM_REGISTERS *) IMX_CCM_BASE; + CbcmrReg.AsUint32 =3D MmioRead32 ((UINTN) &pCcmRegisters->CBCMR); + switch (CbcmrReg.gpu2d_core_clk_sel) { + case IMX_CCM_GPU2D_CORE_CLK_SEL_AXI: + Parent =3D IMX_AXI_CLK_ROOT; + break; + case IMX_CCM_GPU2D_CORE_CLK_SEL_PLL3_SW: + Parent =3D IMX_PLL3_SW_CLK; + break; + case IMX_CCM_GPU2D_CORE_CLK_SEL_PLL2_PFD0: + Parent =3D IMX_PLL2_PFD0; + break; + case IMX_CCM_GPU2D_CORE_CLK_SEL_PLL2_PFD2: + Parent =3D IMX_PLL2_PFD2; + break; + default: + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + Status =3D ImxpGetClockInfo (Cache, Parent, &ParentInfo); + if (EFI_ERROR (Status)) { + return Status; + } + + ClockInfo->Frequency =3D ParentInfo.Frequency / (1 + CbcmrReg.gpu2d_core= _clk_podf); + ClockInfo->Parent =3D Parent; + if (ClockInfo->Frequency > IMX_GPU2D_CORE_CLK_MAX) { + DEBUG (( + DEBUG_WARN, + "%a: GPU2D_CORE_CLK exceeds maximum. (Value =3D %d, Max =3D %d= )\n", + __FUNCTION__, + ClockInfo->Frequency, + IMX_GPU2D_CORE_CLK_MAX)); + } + return EFI_SUCCESS; +} + +EFI_STATUS +ImxpGetGpu3dCoreClkInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + OUT IMX_CLOCK_INFO *ClockInfo + ) +{ + volatile IMX_CCM_REGISTERS *pCcmRegisters; + IMX_CCM_CBCMR_REG CbcmrReg; + IMX_CLK Parent; + IMX_CLOCK_INFO ParentInfo; + EFI_STATUS Status; + + pCcmRegisters =3D (IMX_CCM_REGISTERS *) IMX_CCM_BASE; + CbcmrReg.AsUint32 =3D MmioRead32 ((UINTN) &pCcmRegisters->CBCMR); + switch (CbcmrReg.gpu3d_core_clk_sel) { + case IMX_CCM_GPU3D_CORE_CLK_SEL_MMDC_CH0_AXI: + Parent =3D IMX_MMDC_CH0_CLK_ROOT; + break; + case IMX_CCM_GPU3D_CORE_CLK_SEL_PLL3_SW: + Parent =3D IMX_PLL3_SW_CLK; + break; + case IMX_CCM_GPU3D_CORE_CLK_SEL_PLL2_PFD1: + Parent =3D IMX_PLL2_PFD1; + break; + case IMX_CCM_GPU3D_CORE_CLK_SEL_PLL2_PFD2: + Parent =3D IMX_PLL2_PFD2; + break; + default: + ASSERT (FALSE); + return EFI_UNSUPPORTED; + } + + Status =3D ImxpGetClockInfo (Cache, Parent, &ParentInfo); + if (EFI_ERROR (Status)) { + return Status; + } + + ClockInfo->Frequency =3D ParentInfo.Frequency / (1 + CbcmrReg.gpu3d_core= _podf); + ClockInfo->Parent =3D Parent; + if (ClockInfo->Frequency > IMX_GPU3D_CORE_CLK_MAX) { + DEBUG (( + DEBUG_WARN, + "%a: GPU3D_CORE_CLK exceeds maximum. (Value =3D %d, Max =3D %d= )\n", + __FUNCTION__, + ClockInfo->Frequency, + IMX_GPU3D_CORE_CLK_MAX)); + } + return EFI_SUCCESS; +} + +EFI_STATUS +ImxpGetGpu3dShaderClkInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + OUT IMX_CLOCK_INFO *ClockInfo + ) +{ + volatile IMX_CCM_REGISTERS *pCcmRegisters; + IMX_CCM_CBCMR_REG CbcmrReg; + IMX_CLK Parent; + IMX_CLOCK_INFO ParentInfo; + EFI_STATUS Status; + + pCcmRegisters =3D (IMX_CCM_REGISTERS *) IMX_CCM_BASE; + CbcmrReg.AsUint32 =3D MmioRead32 ((UINTN) &pCcmRegisters->CBCMR); + switch (CbcmrReg.gpu3d_shader_clk_sel) { + case IMX_CCM_GPU3D_SHADER_CLK_SEL_MMDC_CH0_AXI: + Parent =3D IMX_MMDC_CH0_CLK_ROOT; + break; + case IMX_CCM_GPU3D_SHADER_CLK_SEL_PLL3_SW: + Parent =3D IMX_PLL3_SW_CLK; + break; + case IMX_CCM_GPU3D_SHADER_CLK_SEL_PLL2_PFD1: + Parent =3D IMX_PLL2_PFD1; + break; + case IMX_CCM_GPU3D_SHADER_CLK_SEL_PLL3_PFD0: + Parent =3D IMX_PLL3_PFD0; + break; + default: + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + Status =3D ImxpGetClockInfo (Cache, Parent, &ParentInfo); + if (EFI_ERROR (Status)) { + return Status; + } + + ClockInfo->Frequency =3D ParentInfo.Frequency / (1 + CbcmrReg.gpu3d_shad= er_podf); + ClockInfo->Parent =3D Parent; + +#if defined(CPU_IMX6DQ) || defined(CPU_IMX6DQP) + if (ClockInfo->Frequency > IMX_GPU3D_SHADER_CLK_MAX) { + DEBUG (( + DEBUG_WARN, + "%a: GPU3D_SHADER_CLK exceeds maximum. (Value =3D %d, Max =3D = %d)", + __FUNCTION__, + ClockInfo->Frequency, + IMX_GPU3D_SHADER_CLK_MAX)); + } +#endif + + return EFI_SUCCESS; +} + +EFI_STATUS +ImxpGetPeriphClk2Info ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + OUT IMX_CLOCK_INFO *ClockInfo + ) +{ + volatile IMX_CCM_REGISTERS *pCcmRegisters; + IMX_CCM_CBCDR_REG CbcdrReg; + IMX_CCM_CBCMR_REG CbcmrReg; + IMX_CLK Parent; + IMX_CLOCK_INFO ParentInfo; + EFI_STATUS Status; + + pCcmRegisters =3D (IMX_CCM_REGISTERS *) IMX_CCM_BASE; + CbcmrReg.AsUint32 =3D MmioRead32 ((UINTN) &pCcmRegisters->CBCMR); + switch (CbcmrReg.periph_clk2_sel) { + case IMX_CCM_PERIPH_CLK2_SEL_PLL3_SW_CLK: + Parent =3D IMX_PLL3_SW_CLK; + break; + case IMX_CCM_PERIPH_CLK2_SEL_OSC_CLK: + Parent =3D IMX_OSC_CLK; + break; + case IMX_CCM_PERIPH_CLK2_SEL_PLL2: + Parent =3D IMX_PLL2_MAIN_CLK; + break; + default: + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + CbcdrReg.AsUint32 =3D MmioRead32 ((UINTN) &pCcmRegisters->CBCDR); + Status =3D ImxpGetClockInfo (Cache, Parent, &ParentInfo); + if (EFI_ERROR (Status)) { + return Status; + } + + ClockInfo->Frequency =3D ParentInfo.Frequency / (1 + CbcdrReg.periph_clk= 2_podf); + ClockInfo->Parent =3D Parent; + return EFI_SUCCESS; +} + +EFI_STATUS +ImxpGetPeriphClkInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + OUT IMX_CLOCK_INFO *ClockInfo + ) +{ + volatile IMX_CCM_REGISTERS *pCcmRegisters; + IMX_CCM_CBCDR_REG CbcdrReg; + IMX_CLK Parent; + IMX_CLOCK_INFO ParentInfo; + EFI_STATUS Status; + + pCcmRegisters =3D (IMX_CCM_REGISTERS *) IMX_CCM_BASE; + CbcdrReg.AsUint32 =3D MmioRead32 ((UINTN) &pCcmRegisters->CBCDR); + + // NOTE: periph_clk_sel is OR'd with PLL_bypass_en2 (from jtag) to + // produce the input value to the MUX. We assume PLL_bypass_en2 is= 0. + if (CbcdrReg.periph_clk_sel =3D=3D 0) { + Parent =3D IMX_PRE_PERIPH_CLK; + } else { + ASSERT (CbcdrReg.periph_clk_sel =3D=3D 1); + Parent =3D IMX_PERIPH_CLK2; + } + + Status =3D ImxpGetClockInfo (Cache, Parent, &ParentInfo); + if (EFI_ERROR (Status)) { + return Status; + } + + ClockInfo->Frequency =3D ParentInfo.Frequency / (1 + CbcdrReg.mmdc_ch0_a= xi_podf); + ClockInfo->Parent =3D Parent; + return EFI_SUCCESS; +} + +EFI_STATUS +ImxpGetMmdcCh0ClkRootInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + OUT IMX_CLOCK_INFO *ClockInfo + ) +{ + volatile IMX_CCM_REGISTERS *pCcmRegisters; + IMX_CCM_CBCDR_REG CbcdrReg; + IMX_CLOCK_INFO ParentInfo; + EFI_STATUS Status; + + pCcmRegisters =3D (IMX_CCM_REGISTERS *) IMX_CCM_BASE; + Status =3D ImxpGetClockInfo (Cache, IMX_PERIPH_CLK, &ParentInfo); + if (EFI_ERROR (Status)) { + return Status; + } + + CbcdrReg.AsUint32 =3D MmioRead32 ((UINTN) &pCcmRegisters->CBCDR); + ClockInfo->Frequency =3D ParentInfo.Frequency / (1 + CbcdrReg.mmdc_ch0_a= xi_podf); + ClockInfo->Parent =3D IMX_PERIPH_CLK; + return EFI_SUCCESS; +} + +EFI_STATUS +ImxpGetGpu2dAxiClkRootInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + OUT IMX_CLOCK_INFO *ClockInfo + ) +{ + volatile IMX_CCM_REGISTERS *pCcmRegisters; + IMX_CCM_CBCMR_REG CbcmrReg; + IMX_CLK Parent; + IMX_CLOCK_INFO ParentInfo; + EFI_STATUS Status; + + pCcmRegisters =3D (IMX_CCM_REGISTERS *) IMX_CCM_BASE; + CbcmrReg.AsUint32 =3D MmioRead32 ((UINTN) &pCcmRegisters->CBCMR); + if (CbcmrReg.gpu2d_axi_clk_sel =3D=3D IMX_CCM_GPU2D_AXI_CLK_SEL_AXI) { + Parent =3D IMX_AXI_CLK_ROOT; + } else { + ASSERT (CbcmrReg.gpu2d_axi_clk_sel =3D=3D IMX_CCM_GPU2D_AXI_CLK_SEL_AH= B); + Parent =3D IMX_AHB_CLK_ROOT; + } + + Status =3D ImxpGetClockInfo (Cache, Parent, &ParentInfo); + if (EFI_ERROR (Status)) { + return Status; + } + + ClockInfo->Frequency =3D ParentInfo.Frequency; + ClockInfo->Parent =3D Parent; + return EFI_SUCCESS; +} + +EFI_STATUS +ImxpGetGpu3dAxiClkRootInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + OUT IMX_CLOCK_INFO *ClockInfo + ) +{ + volatile IMX_CCM_REGISTERS *pCcmRegisters; + IMX_CCM_CBCMR_REG CbcmrReg; + IMX_CLK Parent; + IMX_CLOCK_INFO ParentInfo; + EFI_STATUS Status; + + pCcmRegisters =3D (IMX_CCM_REGISTERS *) IMX_CCM_BASE; + CbcmrReg.AsUint32 =3D MmioRead32 ((UINTN) &pCcmRegisters->CBCMR); + if (CbcmrReg.gpu3d_axi_clk_sel =3D=3D IMX_CCM_GPU3D_AXI_CLK_SEL_AXI) { + Parent =3D IMX_AXI_CLK_ROOT; + } else { + ASSERT (CbcmrReg.gpu3d_axi_clk_sel =3D=3D IMX_CCM_GPU3D_AXI_CLK_SEL_AH= B); + Parent =3D IMX_AHB_CLK_ROOT; + } + + Status =3D ImxpGetClockInfo (Cache, Parent, &ParentInfo); + if (EFI_ERROR (Status)) { + return Status; + } + + ClockInfo->Frequency =3D ParentInfo.Frequency; + ClockInfo->Parent =3D Parent; + return EFI_SUCCESS; +} + +VOID +ImxEnableGpuVpuPowerDomain ( + VOID + ) +{ + volatile IMX_CCM_ANALOG_REGISTERS *pAnalogRegisters; + volatile IMX_GPC_REGISTERS *pGpcRegisters; + volatile IMX_GPC_PGC_REGISTERS *pGpuPgcRegisters; + IMX_GPC_CNTR_REG GpcCntrReg; + IMX_PMU_REG_CORE_REG PmuCoreReg; + IMX_GPC_PGC_PUPSCR_REG PupscrReg; + + pAnalogRegisters =3D (IMX_CCM_ANALOG_REGISTERS *) IMX_CCM_ANALOG_BASE; + pGpcRegisters =3D (IMX_GPC_REGISTERS *) IMX_GPC_BASE; + pGpuPgcRegisters =3D &pGpcRegisters->PGC_GPU; + + // Configure GPC/PGC PUPSCR Register SW2ISO bits + PupscrReg.AsUint32 =3D MmioRead32 ((UINTN) &pGpuPgcRegisters->PUPSCR); + PupscrReg.SW =3D IMX_GPC_PGC_PUPSCR_SW_DEFAULT; + PupscrReg.SW2ISO =3D IMX_GPC_PGC_PUPSCR_SW2ISO_DEFAULT; + MmioWrite32 ((UINTN) &pGpuPgcRegisters->PUPSCR, PupscrReg.AsUint32); + + // Turn on LDO_PU to 1.250V + PmuCoreReg.AsUint32 =3D 0; + PmuCoreReg.REG1_TARG =3D 0x1f; + MmioWrite32 ((UINTN) &pAnalogRegisters->PMU_REG_CORE_CLR, PmuCoreReg.AsU= int32); + PmuCoreReg.REG1_TARG =3D 22; + MmioWrite32 ((UINTN) &pAnalogRegisters->PMU_REG_CORE_SET, PmuCoreReg.AsU= int32); + MicroSecondDelay (100); + + // Assert power up request + GpcCntrReg.AsUint32 =3D MmioRead32 ((UINTN) &pGpcRegisters->CNTR); + GpcCntrReg.gpu_vpu_pdn_req =3D 0; + GpcCntrReg.gpu_vpu_pup_req =3D 1; + MmioWrite32 ((UINTN) &pGpcRegisters->CNTR, GpcCntrReg.AsUint32); + + // Wait for power up request to complete + do { + GpcCntrReg.AsUint32 =3D MmioRead32 ((UINTN) &pGpcRegisters->CNTR); + } while (GpcCntrReg.gpu_vpu_pup_req !=3D 0); +} + +VOID +ImxDisableGpuVpuPowerDomain ( + VOID + ) +{ + volatile IMX_GPC_REGISTERS *pGpcRegisters; + volatile IMX_GPC_PGC_REGISTERS *pGpuPgcRegisters; + IMX_GPC_PGC_PGCR_REG CtrlReg; + IMX_GPC_CNTR_REG GpcCntrReg; + IMX_GPC_PGC_PDNSCR_REG PdnscrReg; + + pGpcRegisters =3D (IMX_GPC_REGISTERS *) IMX_GPC_BASE; + pGpuPgcRegisters =3D &pGpcRegisters->PGC_GPU; + + // Configure GPC/PGC PDNSCR Register ISO bits + PdnscrReg.AsUint32 =3D MmioRead32 ((UINTN) &pGpuPgcRegisters->PDNSCR); + PdnscrReg.ISO =3D IMX_GPC_PGC_PDNSCR_ISO_DEFAULT; + PdnscrReg.ISO2SW =3D IMX_GPC_PGC_PDNSCR_ISO2SW_DEFAULT; + MmioWrite32 ((UINTN) &pGpuPgcRegisters->PDNSCR, PdnscrReg.AsUint32); + + // Configure GPC/PGC CTRL[PCR] bit to allow power down of the blocks + CtrlReg.AsUint32 =3D MmioRead32 ((UINTN) &pGpuPgcRegisters->CTRL); + CtrlReg.PCR =3D 1; // Enable powering down of the blocks + MmioWrite32 ((UINTN) &pGpuPgcRegisters->CTRL, CtrlReg.AsUint32); + + // Assert power down request + GpcCntrReg.AsUint32 =3D MmioRead32 ((UINTN) &pGpcRegisters->CNTR); + GpcCntrReg.gpu_vpu_pdn_req =3D 1; + GpcCntrReg.gpu_vpu_pup_req =3D 0; + MmioWrite32 ((UINTN) &pGpcRegisters->CNTR, GpcCntrReg.AsUint32); + + // Wait for power down request to complete + do { + GpcCntrReg.AsUint32 =3D MmioRead32 ((UINTN) &pGpcRegisters->CNTR); + } while (GpcCntrReg.gpu_vpu_pdn_req !=3D 0); +} + +EFI_STATUS +ImxpGetClockInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + IN IMX_CLK ClockId, + OUT IMX_CLOCK_INFO *ClockInfo + ) +{ + UINTN CacheValidBits; + EFI_STATUS Status; + + ASSERT (ClockId < ARRAYSIZE (Cache->Table)); + + // First try to satisfy from cache + CacheValidBits =3D Cache->Valid[ClockId / _BITS_PER_UINTN]; + if (CacheValidBits & (1 << (ClockId % _BITS_PER_UINTN))) { + *ClockInfo =3D Cache->Table[ClockId]; + return EFI_SUCCESS; + } + + switch (ClockId) { + case IMX_OSC_CLK: + ImxpGetOsc24ClkInfo (ClockInfo); + Status =3D EFI_SUCCESS; + break; + case IMX_PLL1_MAIN_CLK: + Status =3D ImxpGetPll1MainClkInfo (Cache, ClockInfo); + break; + case IMX_PLL2_MAIN_CLK: + Status =3D ImxpGetPll2MainClkInfo (Cache, ClockInfo); + break; + case IMX_PLL2_PFD0: + Status =3D ImxpGetPll2PfdClkInfo (Cache, IMX_PLL_PFD0, ClockInfo); + break; + case IMX_PLL2_PFD1: + Status =3D ImxpGetPll2PfdClkInfo (Cache, IMX_PLL_PFD1, ClockInfo); + break; + case IMX_PLL2_PFD2: + Status =3D ImxpGetPll2PfdClkInfo (Cache, IMX_PLL_PFD2, ClockInfo); + break; + case IMX_PLL3_MAIN_CLK: + Status =3D ImxpGetPll3MainClkInfo (Cache, ClockInfo); + break; + case IMX_PLL3_PFD0: + Status =3D ImxpGetPll3PfdClkInfo (Cache, IMX_PLL_PFD0, ClockInfo); + break; + case IMX_PLL3_PFD1: + Status =3D ImxpGetPll3PfdClkInfo (Cache, IMX_PLL_PFD1, ClockInfo); + break; + case IMX_PLL3_PFD2: + Status =3D ImxpGetPll3PfdClkInfo (Cache, IMX_PLL_PFD2, ClockInfo); + break; + case IMX_PLL3_PFD3: + Status =3D ImxpGetPll3PfdClkInfo (Cache, IMX_PLL_PFD3, ClockInfo); + break; + case IMX_PLL3_SW_CLK: + Status =3D ImxpGetPll3SwClkInfo (Cache, ClockInfo); + break; + case IMX_AXI_CLK_ROOT: + Status =3D ImxpGetAxiClkRootInfo (Cache, ClockInfo); + break; + case IMX_PERIPH_CLK2: + Status =3D ImxpGetPeriphClk2Info (Cache, ClockInfo); + break; + case IMX_PERIPH_CLK: + Status =3D ImxpGetPeriphClkInfo (Cache, ClockInfo); + break; + case IMX_PRE_PERIPH_CLK: + Status =3D ImxpGetPrePeriphClkInfo (Cache, ClockInfo); + break; + case IMX_ARM_CLK_ROOT: + Status =3D ImxpGetArmClkRootInfo (Cache, ClockInfo); + break; + case IMX_MMDC_CH0_CLK_ROOT: + Status =3D ImxpGetMmdcCh0ClkRootInfo (Cache, ClockInfo); + break; + case IMX_AHB_CLK_ROOT: + Status =3D ImxpGetAhbClkRootInfo (Cache, ClockInfo); + break; + case IMX_IPG_CLK_ROOT: + Status =3D ImxpGetIpgClkRootInfo (Cache, ClockInfo); + break; + case IMX_GPU2D_AXI_CLK_ROOT: + Status =3D ImxpGetGpu2dAxiClkRootInfo (Cache, ClockInfo); + break; + case IMX_GPU3D_AXI_CLK_ROOT: + Status =3D ImxpGetGpu3dAxiClkRootInfo (Cache, ClockInfo); + break; + case IMX_GPU2D_CORE_CLK_ROOT: + Status =3D ImxpGetGpu2dCoreClkInfo (Cache, ClockInfo); + break; + case IMX_GPU3D_CORE_CLK_ROOT: + Status =3D ImxpGetGpu3dCoreClkInfo (Cache, ClockInfo); + break; + case IMX_GPU3D_SHADER_CLK_ROOT: + Status =3D ImxpGetGpu3dShaderClkInfo (Cache, ClockInfo); + break; + default: + return EFI_UNSUPPORTED; + } + + if (EFI_ERROR (Status)) { + return Status; + } + + // Update the cache + Cache->Table[ClockId] =3D *ClockInfo; + Cache->Valid[ClockId / _BITS_PER_UINTN] |=3D (1 << (ClockId % _BITS_PER_= UINTN)); + return EFI_SUCCESS; +} + +/** + Power on and clock the GPU2D/GPU3D blocks. + + Follow the datasheet recommended sequence for clocking and powering: + Gate clocks -> unpower module -> + configure muxes/dividers -> power module -> Ungate clocks +**/ +EFI_STATUS +ImxClkPwrGpuEnable ( + VOID + ) +{ +#if !defined(MDEPKG_NDEBUG) + // Precondition: clock and power should be disabled + ASSERT (ImxClkPwrGetClockGate (IMX_GPU3D_CLK_ENABLE) =3D=3D IMX_CLOCK_GA= TE_STATE_OFF); + ASSERT (ImxClkPwrGetClockGate (IMX_GPU2D_CLK_ENABLE) =3D=3D IMX_CLOCK_GA= TE_STATE_OFF); + ASSERT (ImxClkPwrGetClockGate (IMX_OPENVGAXICLK_CLK_ROOT_ENABLE) =3D=3D = IMX_CLOCK_GATE_STATE_OFF); +#endif + + // Ensure clocks are gated + ImxClkPwrSetClockGate (IMX_GPU3D_CLK_ENABLE, IMX_CLOCK_GATE_STATE_OFF); + ImxClkPwrSetClockGate (IMX_GPU2D_CLK_ENABLE, IMX_CLOCK_GATE_STATE_OFF); + ImxClkPwrSetClockGate (IMX_OPENVGAXICLK_CLK_ROOT_ENABLE, + IMX_CLOCK_GATE_STATE_OFF); + + // Ensure GPU powered down (GPU should be powered down anyway) + ImxDisableGpuVpuPowerDomain (); + + // Configure clock muxes and dividers for GPU3D, GPU2D, and OpenVG + ImxCcmConfigureGpuClockTree (); + + // Power on the GPU + ImxEnableGpuVpuPowerDomain (); + + // Ungate the GPU clocks + ImxClkPwrSetClockGate (IMX_GPU3D_CLK_ENABLE, IMX_CLOCK_GATE_STATE_ON); + ImxClkPwrSetClockGate (IMX_GPU2D_CLK_ENABLE, IMX_CLOCK_GATE_STATE_ON); + ImxClkPwrSetClockGate (IMX_OPENVGAXICLK_CLK_ROOT_ENABLE, + IMX_CLOCK_GATE_STATE_ON); + + return EFI_SUCCESS; +} + +EFI_STATUS +ImxClkPwrIpuDIxEnable ( + VOID + ) +{ + ImxClkPwrSetClockGate (IMX_IPU1_DI0_CLK_ENABLE, IMX_CCM_CCGR_OFF); + ImxClkPwrSetClockGate (IMX_IPU1_DI1_CLK_ENABLE, IMX_CCM_CCGR_OFF); +#if defined(CPU_IMX6DQ) || defined(CPU_IMX6DQP) + ImxClkPwrSetClockGate (IMX_IPU2_DI0_CLK_ENABLE, IMX_CCM_CCGR_OFF); + ImxClkPwrSetClockGate (IMX_IPU2_DI1_CLK_ENABLE, IMX_CCM_CCGR_OFF); +#endif + ImxCcmConfigureIPUDIxClockTree(); + ImxClkPwrSetClockGate (IMX_IPU1_DI0_CLK_ENABLE, IMX_CCM_CCGR_ON); + + // Setup PLL to 65MHz as expected from UBOOT although transition + // might be so fast that UBOOT screen would not be displayed + ImxSetPll5ReferenceRate (65000000); + return EFI_SUCCESS; +} + +#if defined(CPU_IMX6DQ) || defined(CPU_IMX6DQP) +/** + Setup the clock tree for LDB0/1 +**/ +EFI_STATUS +ImxClkPwrIpuLDBxEnable ( + VOID + ) +{ + ImxClkPwrSetClockGate (IMX_LDB_DI0_CLK_ENABLE, IMX_CCM_CCGR_OFF); + ImxClkPwrSetClockGate (IMX_LDB_DI1_CLK_ENABLE, IMX_CCM_CCGR_OFF); + ImxCcmConfigureIPULDBxClockTree(); + ImxClkPwrSetClockGate (IMX_LDB_DI0_CLK_ENABLE, IMX_CCM_CCGR_ON); + ImxClkPwrSetClockGate (IMX_LDB_DI1_CLK_ENABLE, IMX_CCM_CCGR_ON); + + return EFI_SUCCESS; +} +#endif + +/** + Configure PLL5 to the desired clock rate for all Display Interface (DI= ). + Currently only support one display to IPU1 DI0. +**/ +EFI_STATUS +ImxSetPll5ReferenceRate ( + IN UINT32 ClockRate + ) +{ + volatile IMX_CCM_REGISTERS *pCcmRegisters; + IMX_CCM_CHSCCDR_REG ChscddrReg; + UINT32 DxPodfDivider; + BOOLEAN FoundConfig; + IMX_CCM_PLL_VIDEO_CTRL_POST_DIV_SELECT postDivSelect[3]; + UINT32 PostDivSelectCount; + UINT32 PostDivSelectValue[3]; + UINT32 TargetFreq; + + FoundConfig =3D FALSE; + PostDivSelectValue[0] =3D 1; + PostDivSelectValue[1] =3D 2; + PostDivSelectValue[2] =3D 4; + postDivSelect[0] =3D IMX_POST_DIV_SELECT_DIVIDE_1; + postDivSelect[1] =3D IMX_POST_DIV_SELECT_DIVIDE_2; + postDivSelect[2] =3D IMX_POST_DIV_SELECT_DIVIDE_4; + + for (PostDivSelectCount =3D 0; + PostDivSelectCount < ARRAYSIZE (PostDivSelectValue); + ++PostDivSelectCount) { + for (DxPodfDivider =3D 1; DxPodfDivider < 9; ++DxPodfDivider) { + TargetFreq =3D DxPodfDivider * ClockRate * PostDivSelectValue[PostDi= vSelectCount]; + // The valid range for PPL loop divider is 27-54 so target freq need= s + // to fit within the valid range. + if ((TargetFreq >=3D PLL5_MIN_FREQ) && + (TargetFreq <=3D PLL5_MAX_FREQ)) { + FoundConfig =3D TRUE; + break; + } + } + + if (FoundConfig =3D=3D TRUE) { + break; + } + } + + if (FoundConfig =3D=3D FALSE) { + DEBUG ((DEBUG_ERROR, "%a: ClockRate %d\n", __FUNCTION__, ClockRate)); + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + DEBUG (( + DEBUG_INFO, + "%a: PLL 5 setting (%d) Target Freq %d Divider %d PostDiv %d\n", + __FUNCTION__, + ClockRate, + TargetFreq, + DxPodfDivider, + PostDivSelectValue[PostDivSelectCount] + )); + + pCcmRegisters =3D (IMX_CCM_REGISTERS *) IMX_CCM_BASE; + ChscddrReg.AsUint32 =3D MmioRead32 ((UINTN)&pCcmRegisters->CHSCCDR); + ImxClkPwrSetClockGate (IMX_IPU1_DI0_CLK_ENABLE, IMX_CCM_CCGR_OFF); + ImxClkPwrSetClockGate (IMX_IPU1_DI1_CLK_ENABLE, IMX_CCM_CCGR_OFF); +#if defined(CPU_IMX6DQ) || defined(CPU_IMX6DQP) + ImxClkPwrSetClockGate (IMX_IPU2_DI0_CLK_ENABLE, IMX_CCM_CCGR_OFF); + ImxClkPwrSetClockGate (IMX_IPU2_DI1_CLK_ENABLE, IMX_CCM_CCGR_OFF); +#endif + ChscddrReg.ipu1_di0_podf =3D DxPodfDivider - 1; + ChscddrReg.ipu1_di1_podf =3D DxPodfDivider - 1; + MmioWrite32 ((UINTN)&pCcmRegisters->CHSCCDR, ChscddrReg.AsUint32); + + ImxClkPwrSetClockGate (IMX_IPU1_DI0_CLK_ENABLE, IMX_CCM_CCGR_ON); + ImxSetClockRatePLL5 (TargetFreq, postDivSelect[PostDivSelectCount]); + return EFI_SUCCESS; +} + +EFI_STATUS +ImxClkPwrClkOut1Enable ( + IN IMX_CLK Clock, + IN UINT32 Divider + ) +{ + volatile IMX_CCM_REGISTERS *pCcmRegisters; + IMX_CCM_CCOSR_REG CcosrReg; + + pCcmRegisters =3D (IMX_CCM_REGISTERS *) IMX_CCM_BASE; + if ((Divider < 1) || (Divider > 8)) { + return EFI_INVALID_PARAMETER; + } + + CcosrReg.AsUint32 =3D MmioRead32 ((UINTN) &pCcmRegisters->CCOSR); + switch (Clock) { + case IMX_OSC_CLK: + CcosrReg.CLKO2_SEL =3D IMX_CCM_CLKO2_SEL_OSC_CLK; + CcosrReg.CLKO2_DIV =3D Divider - 1; + CcosrReg.CLKO2_EN =3D 1; + CcosrReg.CLK_OUT_SEL =3D IMX_CCM_CLK_OUT_SEL_CCM_CLKO2; + break; + + case IMX_PLL2_MAIN_CLK: + CcosrReg.CLKO1_SEL =3D IMX_CCM_CLKO1_SEL_PLL2_MAIN_CLK_2; + CcosrReg.CLKO1_DIV =3D Divider - 1; + CcosrReg.CLKO1_EN =3D 1; + CcosrReg.CLK_OUT_SEL =3D IMX_CCM_CLK_OUT_SEL_CCM_CLKO1; + break; + + case IMX_AXI_CLK_ROOT: + CcosrReg.CLKO1_SEL =3D IMX_CCM_CLKO1_SEL_AXI_CLK_ROOT; + CcosrReg.CLKO1_DIV =3D Divider - 1; + CcosrReg.CLKO1_EN =3D 1; + CcosrReg.CLK_OUT_SEL =3D IMX_CCM_CLK_OUT_SEL_CCM_CLKO1; + break; + + case IMX_IPG_CLK_ROOT: + CcosrReg.CLKO1_SEL =3D IMX_CCM_CLKO1_SEL_IPG_CLK_ROOT; + CcosrReg.CLKO1_DIV =3D Divider - 1; + CcosrReg.CLKO1_EN =3D 1; + CcosrReg.CLK_OUT_SEL =3D IMX_CCM_CLK_OUT_SEL_CCM_CLKO1; + break; + + case IMX_GPU2D_AXI_CLK_ROOT: + CcosrReg.CLKO2_SEL =3D IMX_CCM_CLKO2_SEL_GPU2D_AXI_CLK_ROOT; + CcosrReg.CLKO2_DIV =3D Divider - 1; + CcosrReg.CLKO2_EN =3D 1; + CcosrReg.CLK_OUT_SEL =3D IMX_CCM_CLK_OUT_SEL_CCM_CLKO2; + break; + + case IMX_GPU3D_AXI_CLK_ROOT: + CcosrReg.CLKO2_SEL =3D IMX_CCM_CLKO2_SEL_GPU3D_AXI_CLK_ROOT; + CcosrReg.CLKO2_DIV =3D Divider - 1; + CcosrReg.CLKO2_EN =3D 1; + CcosrReg.CLK_OUT_SEL =3D IMX_CCM_CLK_OUT_SEL_CCM_CLKO2; + break; + + case IMX_GPU2D_CORE_CLK_ROOT: + CcosrReg.CLKO2_SEL =3D IMX_CCM_CLKO2_SEL_GPU2D_CORE_CLK_ROOT; + CcosrReg.CLKO2_DIV =3D Divider - 1; + CcosrReg.CLKO2_EN =3D 1; + CcosrReg.CLK_OUT_SEL =3D IMX_CCM_CLK_OUT_SEL_CCM_CLKO2; + break; + + case IMX_GPU3D_CORE_CLK_ROOT: + CcosrReg.CLKO2_SEL =3D IMX_CCM_CLKO2_SEL_GPU3D_CORE_CLK_ROOT; + CcosrReg.CLKO2_DIV =3D Divider - 1; + CcosrReg.CLKO2_EN =3D 1; + CcosrReg.CLK_OUT_SEL =3D IMX_CCM_CLK_OUT_SEL_CCM_CLKO2; + break; + + case IMX_GPU3D_SHADER_CLK_ROOT: + CcosrReg.CLKO2_SEL =3D IMX_CCM_CLKO2_SEL_GPU3D_SHADER_CLK_ROOT; + CcosrReg.CLKO2_DIV =3D Divider - 1; + CcosrReg.CLKO2_EN =3D 1; + CcosrReg.CLK_OUT_SEL =3D IMX_CCM_CLK_OUT_SEL_CCM_CLKO2; + break; + + case IMX_UART_CLK_ROOT: + CcosrReg.CLKO2_SEL =3D IMX_CCM_CLKO2_SEL_UART_CLK_ROOT; + CcosrReg.CLKO2_DIV =3D Divider - 1; + CcosrReg.CLKO2_EN =3D 1; + CcosrReg.CLK_OUT_SEL =3D IMX_CCM_CLK_OUT_SEL_CCM_CLKO2; + break; + + default: + return EFI_UNSUPPORTED; + } + + MmioWrite32 ((UINTN) &pCcmRegisters->CCOSR, CcosrReg.AsUint32); + return EFI_SUCCESS; +} + +VOID +ImxClkPwrClkOut1Disable ( + VOID + ) +{ + volatile IMX_CCM_REGISTERS *pCcmRegisters; + IMX_CCM_CCOSR_REG CcosrReg; + + pCcmRegisters =3D (IMX_CCM_REGISTERS *) IMX_CCM_BASE; + CcosrReg.AsUint32 =3D MmioRead32 ((UINTN) &pCcmRegisters->CCOSR); + CcosrReg.CLKO1_EN =3D 0; + CcosrReg.CLKO2_EN =3D 0; + MmioWrite32 ((UINTN) &pCcmRegisters->CCOSR, CcosrReg.AsUint32); +} + +EFI_STATUS +ImxClkPwrValidateClocks ( + VOID + ) +{ + IMX_CLOCK_INFO ActualInfo; + UINT32 i; + BOOLEAN Invalid; + EFI_STATUS Status; + + Invalid =3D FALSE; + for (i =3D 0; i < ARRAYSIZE (ExpectedClocks); ++i) { + DEBUG (( + DEBUG_INFO, + "%a: Validating clock %s. Expecting: Frequency =3D %d (%d Mhz)= , Parent =3D %s\n", + __FUNCTION__, + StringFromImxClk (ExpectedClocks[i].Clock), + ExpectedClocks[i].Info.Frequency, + ExpectedClocks[i].Info.Frequency / 1000000, + StringFromImxClk (ExpectedClocks[i].Info.Parent) + )); + Status =3D ImxClkPwrGetClockInfo (ExpectedClocks[i].Clock, &ActualInfo= ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a: Failed to get clock info. (Clock =3D %s, Status =3D 0x%= x)\n", + __FUNCTION__, + StringFromImxClk (ExpectedClocks[i].Clock), + Status + )); + return Status; + } + if ((ActualInfo.Frequency !=3D ExpectedClocks[i].Info.Frequency) || + (ActualInfo.Parent !=3D ExpectedClocks[i].Info.Parent)) { + DEBUG (( + DEBUG_ERROR, + "%a: Clock settings do not match expected! Clock =3D %s (Exp= ected, Actual) " + "Frequency: %d, %d. Parent: %s, %s\n", + __FUNCTION__, + StringFromImxClk (ExpectedClocks[i].Clock), + ExpectedClocks[i].Info.Frequency, + ActualInfo.Frequency, + StringFromImxClk (ExpectedClocks[i].Info.Parent), + StringFromImxClk (ActualInfo.Parent) + )); + Invalid =3D TRUE; + } + } + + return Invalid ? EFI_DEVICE_ERROR : EFI_SUCCESS; +} + +/** + Reset/invalidate the clock tree cache. + + The clock tree cache must be invalidated whenever the clock tree is modi= fied, + e.g. when changing PLL configuration, clock mux, or divider. + +**/ +VOID +ImxpClkPwrCacheReset ( + VOID + ) +{ + SetMem (&mImxpClockPwrCache.Valid, sizeof (mImxpClockPwrCache.Valid), 0)= ; +} + +/** + Configure clock gating for the specified clock signal. + + @param[in] ClockGate Specific clock signal to configure. + @param[in] State State to set the clock signal to. +**/ +VOID +ImxClkPwrSetClockGate ( + IN IMX_CLK_GATE ClockGate, + IN IMX_CLOCK_GATE_STATE State + ) +{ + volatile IMX_CCM_REGISTERS *pCcmRegisters; + UINTN EndBit; + IMX_CCGR_INDEX Index; + UINTN StartBit; + + pCcmRegisters =3D (IMX_CCM_REGISTERS *) IMX_CCM_BASE; + + // Extract register index + Index =3D ImxpCcgrIndexFromClkGate (ClockGate); + StartBit =3D Index.GateNumber * 2; + EndBit =3D StartBit + 1; + + MmioBitFieldWrite32 ( + (UINTN) &pCcmRegisters->CCGR[Index.RegisterIndex], + StartBit, + EndBit, + State); +} + +/** + Determine if gating TZASC1_IPG_MASTER_CLK should be skipped. + **/ +BOOLEAN +ImxClkPwrShouldSkipTZASC1 ( + VOID + ) +{ +#if defined(CPU_IMX6DQ) || defined(CPU_IMX6DQP) + IMX_IOMUXC_GPR_REGISTERS *IoMuxMmioBasePtr; + UINTN IomuxGPR9; +#endif + BOOLEAN Skip; + + Skip =3D FALSE; +#if defined(CPU_IMX6DQ) || defined(CPU_IMX6DQP) + IoMuxMmioBasePtr =3D (IMX_IOMUXC_GPR_REGISTERS *)IOMUXC_GPR_BASE_ADDRESS= ; + + IomuxGPR9 =3D MmioRead32 ((UINTN) &IoMuxMmioBasePtr->GPR9); + if (IomuxGPR9 & IMX_IOMUXC_TZASC1_BYP) { + // TZASC-1 is active. + Skip =3D TRUE; + } +#endif + + return Skip; +} + +/** + Determine if a clock gate should be skipped + + @param[in] ClockGate Specific clock signal to configure. + **/ +BOOLEAN +ImxClkPwrShouldSkipGate ( + IN IMX_CLK_GATE ClockGate + ) +{ + switch (ClockGate) { + case IMX_IPSYNC_IP2APB_TZASC1_IPG_MASTER_CLK_ENABLE: + return ImxClkPwrShouldSkipTZASC1 (); + + default: + return FALSE; + } +} + +/** + Set multiple clock signals to a given state. + + @param[in] ClockGateList Pointer to list of possible clock signals. + @param[in] ClockGateCount Number of clock signals to gate. + @param[in] State State to set the clock signal to. +**/ +VOID +ImxClkPwrSetClockGates ( + CONST IMX_CLK_GATE *ClockGateList, + UINTN ClockGateCount, + IMX_CLOCK_GATE_STATE State + ) +{ + volatile IMX_CCM_REGISTERS *pCcmRegisters; + UINTN i; + IMX_CCGR_INDEX Index; + + pCcmRegisters =3D (IMX_CCM_REGISTERS *) IMX_CCM_BASE; + + // Read all CCGR registers to local copy + UINT32 ccgrRegisters[ARRAYSIZE (pCcmRegisters->CCGR)]; + for (i =3D 0; i < ARRAYSIZE (ccgrRegisters); ++i) { + ccgrRegisters[i] =3D MmioRead32 ((UINTN) &pCcmRegisters->CCGR[i]); + } + + // Compute new CCGR register values + for (i =3D 0; i < ClockGateCount; ++i) { + if (ImxClkPwrShouldSkipGate (ClockGateList[i])) { + continue; + } + + Index =3D ImxpCcgrIndexFromClkGate (ClockGateList[i]); + ccgrRegisters[Index.RegisterIndex] =3D + (ccgrRegisters[Index.RegisterIndex] & ~(0x3 << (2 * Index.GateNumber= ))) | + (State << (2 * Index.GateNumber)); + } + + // Write back to registers + for (i =3D 0; i < ARRAYSIZE (ccgrRegisters); ++i) { + MmioWrite32 ((UINTN) &pCcmRegisters->CCGR[i], ccgrRegisters[i]); + } +} + +/** + Get the current clock gating setting for the specified clock gate. + + @param[in] ClockGate Specific clock signal to fetch clock gate info= from. +**/ +IMX_CLOCK_GATE_STATE +ImxClkPwrGetClockGate ( + IN IMX_CLK_GATE ClockGate + ) +{ + volatile IMX_CCM_REGISTERS *pCcmRegisters; + UINTN EndBit; + IMX_CCGR_INDEX Index; + UINTN StartBit; + UINT32 Value; + + pCcmRegisters =3D (IMX_CCM_REGISTERS *) IMX_CCM_BASE; + Index =3D ImxpCcgrIndexFromClkGate (ClockGate); + StartBit =3D Index.GateNumber * 2; + EndBit =3D StartBit + 1; + + Value =3D MmioBitFieldRead32 ( + (UINTN) &pCcmRegisters->CCGR[Index.RegisterIndex], + StartBit, + EndBit); + + if ((Value !=3D IMX_CCM_CCGR_OFF) && + (Value !=3D IMX_CCM_CCGR_ON_RUN) && + (Value !=3D IMX_CCM_CCGR_ON)) { + ASSERT (FALSE); + } + + return (IMX_CLOCK_GATE_STATE) Value; +} + +EFI_STATUS +ImxpGetPll3MainClkInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + OUT IMX_CLOCK_INFO *ClockInfo + ) +{ + volatile IMX_CCM_ANALOG_REGISTERS *pCcmAnalogRegisters; + IMX_CLK Parent; + IMX_CLOCK_INFO ParentInfo; + IMX_CCM_ANALOG_PLL_USB1_REG PllUsb1Reg; + EFI_STATUS Status; + + pCcmAnalogRegisters =3D (IMX_CCM_ANALOG_REGISTERS *) IMX_CCM_ANALOG_BASE= ; + PllUsb1Reg.AsUint32 =3D MmioRead32 ((UINTN)&pCcmAnalogRegisters->PLL_USB= 1); + Parent =3D ImxpClkFromBypassClkSource (PllUsb1Reg.BYPASS_CLK_SRC); + Status =3D ImxpGetClockInfo (Cache, Parent, &ParentInfo); + if (EFI_ERROR (Status)) { + return Status; + } + + if (PllUsb1Reg.DIV_SELECT =3D=3D 0) { + ClockInfo->Frequency =3D ParentInfo.Frequency * 20; + } else { + ClockInfo->Frequency =3D ParentInfo.Frequency * 22; + } + + ClockInfo->Parent =3D Parent; + return EFI_SUCCESS; +} + +EFI_STATUS +ImxpGetPll3PfdClkInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + IN IMX_PLL_PFD PfdIndex, + OUT IMX_CLOCK_INFO *ClockInfo + ) +{ + volatile IMX_CCM_ANALOG_REGISTERS *pCcmAnalogRegisters; + IMX_CLOCK_INFO ParentInfo; + IMX_CCM_PFD_480_REG Pfd480Reg; + UINT32 PfdFrac; + EFI_STATUS Status; + + pCcmAnalogRegisters =3D (IMX_CCM_ANALOG_REGISTERS *) IMX_CCM_ANALOG_BASE= ; + Pfd480Reg.AsUint32 =3D MmioRead32 ((UINTN) &pCcmAnalogRegisters->PFD_480= ); + switch (PfdIndex) { + case IMX_PLL_PFD0: + PfdFrac =3D Pfd480Reg.PFD0_FRAC; + break; + case IMX_PLL_PFD1: + PfdFrac =3D Pfd480Reg.PFD1_FRAC; + break; + case IMX_PLL_PFD2: + PfdFrac =3D Pfd480Reg.PFD2_FRAC; + break; + case IMX_PLL_PFD3: + PfdFrac =3D Pfd480Reg.PFD3_FRAC; + break; + default: + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + Status =3D ImxpGetClockInfo (Cache, IMX_PLL3_MAIN_CLK, &ParentInfo); + if (EFI_ERROR (Status)) { + return Status; + } + + // The resulting frequency shall be 480*18/PFDn_FRAC + // where PFD0_FRAC is in the range 12-35. + ASSERT ((PfdFrac >=3D 12) && (PfdFrac <=3D 35)); + ClockInfo->Frequency =3D (UINT32) ((UINT64) ParentInfo.Frequency * 18 / = PfdFrac); + ClockInfo->Parent =3D IMX_PLL3_MAIN_CLK; + return EFI_SUCCESS; +} + +EFI_STATUS +ImxpGetPll3SwClkInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + OUT IMX_CLOCK_INFO *ClockInfo + ) +{ + volatile IMX_CCM_REGISTERS *pCcmRegisters; + IMX_CCM_CCSR_REG CcsrReg; + IMX_CLK Parent; + IMX_CLOCK_INFO ParentInfo; + EFI_STATUS Status; + + pCcmRegisters =3D (IMX_CCM_REGISTERS *) IMX_CCM_BASE; + CcsrReg.AsUint32 =3D MmioRead32 ((UINTN) &pCcmRegisters->CCSR); + if (CcsrReg.pll3_sw_clk_sel =3D=3D IMX_CCM_PLL3_SW_CLK_SEL_PLL3_MAIN_CLK= ) { + Parent =3D IMX_PLL3_MAIN_CLK; + } else { + ASSERT (CcsrReg.pll3_sw_clk_sel =3D=3D IMX_CCM_PLL3_SW_CLK_SEL_PLL3_BY= PASS_CLK); + ASSERT (!"Not implemented"); + return EFI_UNSUPPORTED; + } + + Status =3D ImxpGetClockInfo (Cache, Parent, &ParentInfo); + if (EFI_ERROR (Status)) { + return Status; + } + + ClockInfo->Frequency =3D ParentInfo.Frequency; + ClockInfo->Parent =3D Parent; + return EFI_SUCCESS; +} + +EFI_STATUS +ImxpGetPll1MainClkInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + OUT IMX_CLOCK_INFO *ClockInfo + ) +{ + volatile IMX_CCM_ANALOG_REGISTERS *pCcmAnalogRegisters; + IMX_CLK Parent; + IMX_CLOCK_INFO ParentInfo; + IMX_CCM_ANALOG_PLL_ARM_REG PllArmReg; + EFI_STATUS Status; + + pCcmAnalogRegisters =3D (IMX_CCM_ANALOG_REGISTERS *) IMX_CCM_ANALOG_BASE= ; + PllArmReg.AsUint32 =3D MmioRead32 ((UINTN) &pCcmAnalogRegisters->PLL_ARM= ); + Parent =3D ImxpClkFromBypassClkSource (PllArmReg.BYPASS_CLK_SRC); + Status =3D ImxpGetClockInfo (Cache, Parent, &ParentInfo); + if (EFI_ERROR (Status)) { + return Status; + } + + if (PllArmReg.BYPASS !=3D 0) { + ClockInfo->Frequency =3D ParentInfo.Frequency; + ClockInfo->Parent =3D Parent; + return EFI_SUCCESS; + } + + ClockInfo->Frequency =3D (UINT32) ((UINT64) ParentInfo.Frequency * PllAr= mReg.DIV_SELECT / 2); + ClockInfo->Parent =3D Parent; + return EFI_SUCCESS; +} + +EFI_STATUS +ImxpGetPll2MainClkInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + OUT IMX_CLOCK_INFO *ClockInfo + ) +{ + volatile IMX_CCM_ANALOG_REGISTERS *pCcmAnalogRegisters; + IMX_CLK Parent; + IMX_CLOCK_INFO ParentInfo; + IMX_CCM_ANALOG_PLL_SYS_REG PllSysReg; + EFI_STATUS Status; + + pCcmAnalogRegisters =3D (IMX_CCM_ANALOG_REGISTERS *) IMX_CCM_ANALOG_BASE= ; + PllSysReg.AsUint32 =3D MmioRead32 ((UINTN) &pCcmAnalogRegisters->PLL_SYS= ); + // Determine the reference clock source + Parent =3D ImxpClkFromBypassClkSource (PllSysReg.BYPASS_CLK_SRC); + Status =3D ImxpGetClockInfo (Cache, Parent, &ParentInfo); + if (EFI_ERROR (Status)) { + return Status; + } + + if (PllSysReg.BYPASS !=3D 0) { + ClockInfo->Frequency =3D ParentInfo.Frequency; + ClockInfo->Parent =3D Parent; + return EFI_SUCCESS; + } + + if (PllSysReg.DIV_SELECT =3D=3D 0) { + ClockInfo->Frequency =3D ParentInfo.Frequency * 20; + } else { + ASSERT (PllSysReg.DIV_SELECT =3D=3D 1); + ClockInfo->Frequency =3D ParentInfo.Frequency * 22; + } + + ClockInfo->Parent =3D Parent; + return EFI_SUCCESS; +} + +EFI_STATUS +ImxpGetArmClkRootInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + OUT IMX_CLOCK_INFO *ClockInfo + ) +{ + volatile IMX_CCM_REGISTERS *pCcmRegisters; + IMX_CCM_CACRR_REG CacrrReg; + IMX_CLOCK_INFO Pll1Info; + EFI_STATUS Status; + + pCcmRegisters =3D (IMX_CCM_REGISTERS *) IMX_CCM_BASE; + Status =3D ImxpGetClockInfo (Cache, IMX_PLL1_MAIN_CLK, &Pll1Info); + if (EFI_ERROR (Status)) { + return Status; + } + + CacrrReg.AsUint32 =3D MmioRead32 ((UINTN) &pCcmRegisters->CACRR); + ClockInfo->Frequency =3D Pll1Info.Frequency / (1 + CacrrReg.arm_podf); + ClockInfo->Parent =3D IMX_PLL1_MAIN_CLK; + return EFI_SUCCESS; +} + +EFI_STATUS +ImxpGetPrePeriphClkInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + OUT IMX_CLOCK_INFO *ClockInfo + ) +{ + volatile IMX_CCM_REGISTERS *pCcmRegisters; + IMX_CCM_CBCMR_REG CbcmrReg; + IMX_CLK Parent; + IMX_CLOCK_INFO ParentInfo; + EFI_STATUS Status; + + pCcmRegisters =3D (IMX_CCM_REGISTERS *) IMX_CCM_BASE; + CbcmrReg.AsUint32 =3D MmioRead32 ((UINTN) &pCcmRegisters->CBCMR); + switch (CbcmrReg.pre_periph_clk_sel) { + case IMX_CCM_PRE_PERIPH_CLK_SEL_PLL2: + Parent =3D IMX_PLL2_MAIN_CLK; + break; + case IMX_CCM_PRE_PERIPH_CLK_SEL_PLL2_PFD2: + Parent =3D IMX_PLL2_PFD2; + break; + case IMX_CCM_PRE_PERIPH_CLK_SEL_PLL2_PFD0: + Parent =3D IMX_PLL2_PFD0; + break; + case IMX_CCM_PRE_PERIPH_CLK_SEL_PLL2_PFD2_DIV2: + Parent =3D IMX_PLL2_PFD2; + break; + default: + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + Status =3D ImxpGetClockInfo (Cache, Parent, &ParentInfo); + if (EFI_ERROR (Status)) { + return Status; + } + + if (CbcmrReg.pre_periph_clk_sel =3D=3D IMX_CCM_PRE_PERIPH_CLK_SEL_PLL2_P= FD2_DIV2) { + ClockInfo->Frequency =3D ParentInfo.Frequency / 2; + } else { + ClockInfo->Frequency =3D ParentInfo.Frequency; + } + + ClockInfo->Parent =3D Parent; + return EFI_SUCCESS; +} + +VOID +ImxpGetOsc24ClkInfo ( + OUT IMX_CLOCK_INFO *ClockInfo + ) +{ + ClockInfo->Frequency =3D IMX_REF_CLK_24M_FREQ; + ClockInfo->Parent =3D IMX_CLK_NONE; +} + +EFI_STATUS +ImxpGetAhbClkRootInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + OUT IMX_CLOCK_INFO *ClockInfo + ) +{ + volatile IMX_CCM_REGISTERS *pCcmRegisters; + IMX_CCM_CBCDR_REG CbcdrReg; + IMX_CLOCK_INFO ParentInfo; + EFI_STATUS Status; + + pCcmRegisters =3D (IMX_CCM_REGISTERS *) IMX_CCM_BASE; + Status =3D ImxpGetClockInfo (Cache, IMX_PERIPH_CLK, &ParentInfo); + if (EFI_ERROR (Status)) { + return Status; + } + + CbcdrReg.AsUint32 =3D MmioRead32 ((UINTN) &pCcmRegisters->CBCDR); + ClockInfo->Frequency =3D ParentInfo.Frequency / (1 + CbcdrReg.ahb_podf); + ClockInfo->Parent =3D IMX_PERIPH_CLK; + return EFI_SUCCESS; +} + +EFI_STATUS +ImxpGetIpgClkRootInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + OUT IMX_CLOCK_INFO *ClockInfo + ) +{ + volatile IMX_CCM_REGISTERS *pCcmRegisters; + IMX_CCM_CBCDR_REG CbcdrReg; + IMX_CLOCK_INFO ParentInfo; + EFI_STATUS Status; + + pCcmRegisters =3D (IMX_CCM_REGISTERS *) IMX_CCM_BASE; + Status =3D ImxpGetClockInfo (Cache, IMX_AHB_CLK_ROOT, &ParentInfo); + if (EFI_ERROR (Status)) { + return Status; + } + + CbcdrReg.AsUint32 =3D MmioRead32 ((UINTN) &pCcmRegisters->CBCDR); + ClockInfo->Frequency =3D ParentInfo.Frequency / (1 + CbcdrReg.ipg_podf); + ClockInfo->Parent =3D IMX_AHB_CLK_ROOT; + return EFI_SUCCESS; +} + +EFI_STATUS +ImxClkPwrGetClockInfo ( + IN IMX_CLK ClockId, + OUT IMX_CLOCK_INFO *ClockInfo + ) +{ + return ImxpGetClockInfo (&mImxpClockPwrCache, ClockId, ClockInfo); +} diff --git a/Silicon/NXP/iMX6Pkg/Library/iMX6ClkPwrLib/iMX6ClkPwrLib.inf b/= Silicon/NXP/iMX6Pkg/Library/iMX6ClkPwrLib/iMX6ClkPwrLib.inf new file mode 100644 index 000000000000..5e4603131471 --- /dev/null +++ b/Silicon/NXP/iMX6Pkg/Library/iMX6ClkPwrLib/iMX6ClkPwrLib.inf @@ -0,0 +1,46 @@ +## @file +# +# Copyright (c) 2018 Microsoft Corporation. All rights reserved. +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the B= SD License +# which accompanies this distribution. The full text of the license may = be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IM= PLIED. +# +## + +[Defines] + INF_VERSION =3D 0x0001001A + BASE_NAME =3D iMX6ClkPwrLib + FILE_GUID =3D 8DB4B460-9201-435A-B86A-24B58CED9A9E + MODULE_TYPE =3D BASE + VERSION_STRING =3D 1.0 + LIBRARY_CLASS =3D iMX6ClkPwrLib + +[Packages] + ArmPkg/ArmPkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + Silicon/NXP/iMX6Pkg/iMX6Pkg.dec + Silicon/NXP/iMXPlatformPkg/iMXPlatformPkg.dec + +[LibraryClasses] + BaseMemoryLib + DebugLib + iMXIoMuxLib + IoLib + TimerLib + +[Sources.common] + iMX6ClkPwr.c + +[FeaturePcd] + giMX6TokenSpaceGuid.PcdLvdsEnable + +[FixedPcd] + giMXPlatformTokenSpaceGuid.PcdGpioBankMemoryRange diff --git a/Silicon/NXP/iMX6Pkg/Library/iMX6ClkPwrLib/iMX6ClkPwr_private.h= b/Silicon/NXP/iMX6Pkg/Library/iMX6ClkPwrLib/iMX6ClkPwr_private.h new file mode 100644 index 000000000000..2de1f62c7740 --- /dev/null +++ b/Silicon/NXP/iMX6Pkg/Library/iMX6ClkPwrLib/iMX6ClkPwr_private.h @@ -0,0 +1,221 @@ +/** @file +* +* Copyright (c) 2018 Microsoft Corporation. All rights reserved. +* Copyright 2018 NXP +* +* This program and the accompanying materials +* are licensed and made available under the terms and conditions of the B= SD License +* which accompanies this distribution. The full text of the license may = be found at +* http://opensource.org/licenses/bsd-license.php +* +* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IM= PLIED. +* +**/ + +#ifndef _IMX6_CLK_PWR_PRIVATE_H_ +#define _IMX6_CLK_PWR_PRIVATE_H_ + +#ifndef ARRAYSIZE +#define ARRAYSIZE(a) (sizeof(a) / sizeof(a[0])) +#endif // ARRAYSIZE + +#define _BITS_PER_UINTN (8 * sizeof(UINTN)) + +typedef enum { + IMX_PLL_PFD0, + IMX_PLL_PFD1, + IMX_PLL_PFD2, + IMX_PLL_PFD3, +} IMX_PLL_PFD; + +typedef struct { + IMX_CLK Clock; + IMX_CLOCK_INFO Info; +} IMX_CLOCK_CONTEXT; + +typedef struct { + UINT16 RegisterIndex; // Register index (0-6) + UINT16 GateNumber; // Gate number within register (0-15) +} IMX_CCGR_INDEX; + +typedef struct { + UINTN Valid[(IMX_CLK_MAX + _BITS_PER_UINTN) / _BITS_PER_UINTN]; + IMX_CLOCK_INFO Table[IMX_CLK_MAX]; +} IMX_CLOCK_TREE_CACHE; + +IMX_CCGR_INDEX +ImxpCcgrIndexFromClkGate ( + IN IMX_CLK_GATE ClockGate + ); + +VOID +ImxpClkPwrCacheReset ( + VOID + ); + +IMX_CLK +ImxpClkFromBypassClkSource ( + IN IMX_PLL_BYPASS_CLK_SRC BypassClockSource + ); + +VOID +ImxCcmConfigureGpuClockTree ( + VOID + ); + +VOID +ImxCcmConfigureIPUDIxClockTree ( + VOID + ); + +VOID +ImxCcmConfigureIPULDBxClockTree ( + VOID + ); + +VOID +ImxSetClockRatePLL5 ( + IN UINT32 ClockRate, + IN IMX_CCM_PLL_VIDEO_CTRL_POST_DIV_SELECT PostDivSelect + ); + +EFI_STATUS +ImxpGetClockInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + IN IMX_CLK ClockId, + OUT IMX_CLOCK_INFO *ClockInfo + ); + +VOID +ImxpGetOsc24ClkInfo ( + OUT IMX_CLOCK_INFO *ClockInfo + ); + +EFI_STATUS +ImxpGetPll1MainClkInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + OUT IMX_CLOCK_INFO *ClockInfo + ); + +EFI_STATUS +ImxpGetPll2MainClkInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + OUT IMX_CLOCK_INFO *ClockInfo + ); + +EFI_STATUS +ImxpGetPll2PfdClkInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + IN IMX_PLL_PFD PfdIndex, + OUT IMX_CLOCK_INFO *ClockInfo + ); + +EFI_STATUS +ImxpGetPll3MainClkInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + OUT IMX_CLOCK_INFO *ClockInfo + ); + +EFI_STATUS +ImxpGetPll3PfdClkInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + IN IMX_PLL_PFD PfdIndex, + OUT IMX_CLOCK_INFO *ClockInfo + ); + +EFI_STATUS +ImxpGetPll3SwClkInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + OUT IMX_CLOCK_INFO *ClockInfo + ); + +EFI_STATUS +ImxpGetAxiClkRootInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + OUT IMX_CLOCK_INFO *ClockInfo + ); + +EFI_STATUS +ImxpGetPeriphClkInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + OUT IMX_CLOCK_INFO *ClockInfo + ); + +EFI_STATUS +ImxpGetPrePeriphClkInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + OUT IMX_CLOCK_INFO *ClockInfo + ); + +EFI_STATUS +ImxpGetPeriphClk2Info ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + OUT IMX_CLOCK_INFO *ClockInfo + ); + +EFI_STATUS +ImxpGetArmClkRootInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + OUT IMX_CLOCK_INFO *ClockInfo + ); + +EFI_STATUS +ImxpGetMmdcCh0ClkRootInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + OUT IMX_CLOCK_INFO *ClockInfo + ); + +EFI_STATUS +ImxpGetAhbClkRootInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + OUT IMX_CLOCK_INFO *ClockInfo + ); + +EFI_STATUS +ImxpGetIpgClkRootInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + OUT IMX_CLOCK_INFO *ClockInfo + ); + +EFI_STATUS +ImxpGetGpu2dAxiClkRootInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + OUT IMX_CLOCK_INFO *ClockInfo + ); + +EFI_STATUS +ImxpGetGpu3dAxiClkRootInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + OUT IMX_CLOCK_INFO *ClockInfo + ); + +EFI_STATUS +ImxpGetGpu2dCoreClkInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + OUT IMX_CLOCK_INFO *ClockInfo + ); + +EFI_STATUS +ImxpGetGpu3dCoreClkInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + OUT IMX_CLOCK_INFO *ClockInfo + ); + +EFI_STATUS +ImxpGetGpu3dShaderClkInfo ( + IN OUT IMX_CLOCK_TREE_CACHE *Cache, + OUT IMX_CLOCK_INFO *ClockInfo + ); + +VOID +ImxEnableGpuVpuPowerDomain ( + VOID + ); + +VOID +ImxDisableGpuVpuPowerDomain ( + VOID + ); + +#endif // _IMX6_CLK_PWR_PRIVATE_H_ --=20 2.16.2.gvfs.1.33.gf5370f1