From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.3 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,NICE_REPLY_A,SPF_HELO_NONE,SPF_PASS,USER_AGENT_SANE_1 autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 362A1C433ED for ; Fri, 21 May 2021 13:34:22 +0000 (UTC) Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 59C8A610CB for ; Fri, 21 May 2021 13:34:20 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 59C8A610CB Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=rock-chips.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 8780482D68; Fri, 21 May 2021 15:34:18 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=rock-chips.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by phobos.denx.de (Postfix, from userid 109) id A0B7C82E1E; Fri, 21 May 2021 15:34:17 +0200 (CEST) Received: from regular1.263xmail.com (regular1.263xmail.com [211.150.70.196]) (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 1E0D881658 for ; Fri, 21 May 2021 15:34:04 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=none (p=none dis=none) header.from=rock-chips.com Authentication-Results: phobos.denx.de; spf=fail smtp.mailfrom=kever.yang@rock-chips.com Received: from localhost (unknown [192.168.167.225]) by regular1.263xmail.com (Postfix) with ESMTP id 9CC961E45 for ; Fri, 21 May 2021 21:33:58 +0800 (CST) X-MAIL-GRAY: 0 X-MAIL-DELIVERY: 1 X-ADDR-CHECKED4: 1 X-ANTISPAM-LEVEL: 2 X-SKE-CHECKED: 1 X-ABS-CHECKED: 1 Received: from [172.16.12.120] (unknown [58.22.7.114]) by smtp.263.net (postfix) whith ESMTP id P23340T140511734134528S1621604037036614_; Fri, 21 May 2021 21:33:58 +0800 (CST) X-IP-DOMAINF: 1 X-UNIQUE-TAG: X-RL-SENDER: kever.yang@rock-chips.com X-SENDER: yk@rock-chips.com X-LOGIN-NAME: kever.yang@rock-chips.com X-FST-TO: zhangqing@rock-chips.com X-RCPT-COUNT: 5 X-SENDER-IP: 58.22.7.114 X-ATTACHMENT-NUM: 0 X-System-Flag: 0 Subject: Re: [PATCH v1 2/2] rockchip: rk3568: add clock driver To: Elaine Zhang , sjg@chromium.org, lukma@denx.de Cc: u-boot@lists.denx.de, chenjh@rock-chips.com, Elaine Zhang References: <20210519084919.11475-1-zhangqing@rock-chips.com> <20210519084919.11475-3-zhangqing@rock-chips.com> From: Kever Yang Message-ID: Date: Fri, 21 May 2021 21:33:57 +0800 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.10.0 MIME-Version: 1.0 In-Reply-To: <20210519084919.11475-3-zhangqing@rock-chips.com> Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 8bit Content-Language: en-US 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 Hi Elaine,     Thanks for your patch, pls update the copyright info and remove unused clock set/get. On 2021/5/19 下午4:49, Elaine Zhang wrote: > From: Elaine Zhang > > Add rk3568 clock driver and cru structure definition. > > Signed-off-by: Elaine Zhang > --- > .../include/asm/arch-rockchip/cru_rk3568.h | 504 +++ > drivers/clk/rockchip/Makefile | 1 + > drivers/clk/rockchip/clk_rk3568.c | 2908 +++++++++++++++++ > 3 files changed, 3413 insertions(+) > create mode 100644 arch/arm/include/asm/arch-rockchip/cru_rk3568.h > create mode 100644 drivers/clk/rockchip/clk_rk3568.c > > diff --git a/arch/arm/include/asm/arch-rockchip/cru_rk3568.h b/arch/arm/include/asm/arch-rockchip/cru_rk3568.h > new file mode 100644 > index 000000000000..6c59033f03a6 > --- /dev/null > +++ b/arch/arm/include/asm/arch-rockchip/cru_rk3568.h > @@ -0,0 +1,504 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Copyright (c) 2021 Rockchip Electronics Co. Ltd. > + * Author: Elaine Zhang > + */ > + > +#ifndef _ASM_ARCH_CRU_RK3568_H > +#define _ASM_ARCH_CRU_RK3568_H > + > +#define MHz 1000000 > +#define KHz 1000 > +#define OSC_HZ (24 * MHz) > + > +#define APLL_HZ (816 * MHz) > +#define GPLL_HZ (1188 * MHz) > +#define CPLL_HZ (1000 * MHz) > +#define PPLL_HZ (100 * MHz) > + > +/* RK3568 pll id */ > +enum rk3568_pll_id { > + APLL, > + DPLL, > + CPLL, > + GPLL, > + NPLL, > + VPLL, > + PPLL, > + HPLL, > + PLL_COUNT, > +}; > + > +struct rk3568_clk_info { > + unsigned long id; > + char *name; > + bool is_cru; > +}; > + > +/* Private data for the clock driver - used by rockchip_get_cru() */ > +struct rk3568_pmuclk_priv { > + struct rk3568_pmucru *pmucru; > + ulong ppll_hz; > + ulong hpll_hz; > +}; > + > +struct rk3568_clk_priv { > + struct rk3568_cru *cru; > + struct rk3568_grf *grf; > + ulong ppll_hz; > + ulong hpll_hz; > + ulong gpll_hz; > + ulong cpll_hz; > + ulong npll_hz; > + ulong vpll_hz; > + ulong armclk_hz; > + ulong armclk_enter_hz; > + ulong armclk_init_hz; > + bool sync_kernel; > + bool set_armclk_rate; > +}; > + > +struct rk3568_pll { > + unsigned int con0; > + unsigned int con1; > + unsigned int con2; > + unsigned int con3; > + unsigned int con4; > + unsigned int reserved0[3]; > +}; > + > +struct rk3568_pmucru { > + struct rk3568_pll pll[2];/* Address Offset: 0x0000 */ > + unsigned int reserved0[16];/* Address Offset: 0x0040 */ > + unsigned int mode_con00;/* Address Offset: 0x0080 */ > + unsigned int reserved1[31];/* Address Offset: 0x0084 */ > + unsigned int pmu_clksel_con[10];/* Address Offset: 0x0100 */ > + unsigned int reserved2[22];/* Address Offset: 0x0128 */ > + unsigned int pmu_clkgate_con[3];/* Address Offset: 0x0180 */ > + unsigned int reserved3[29];/* Address Offset: 0x018C */ > + unsigned int pmu_softrst_con[1];/* Address Offset: 0x0200 */ > +}; > + > +check_member(rk3568_pmucru, mode_con00, 0x80); > +check_member(rk3568_pmucru, pmu_softrst_con[0], 0x200); > + > +struct rk3568_cru { > + struct rk3568_pll pll[6]; > + unsigned int mode_con00;/* Address Offset: 0x00C0 */ > + unsigned int misc_con[3];/* Address Offset: 0x00C4 */ > + unsigned int glb_cnt_th;/* Address Offset: 0x00D0 */ > + unsigned int glb_srst_fst;/* Address Offset: 0x00D4 */ > + unsigned int glb_srsr_snd; /* Address Offset: 0x00D8 */ > + unsigned int glb_rst_con;/* Address Offset: 0x00DC */ > + unsigned int glb_rst_st;/* Address Offset: 0x00E0 */ > + unsigned int reserved0[7];/* Address Offset: 0x00E4 */ > + unsigned int clksel_con[85]; /* Address Offset: 0x0100 */ > + unsigned int reserved1[43];/* Address Offset: 0x0254 */ > + unsigned int clkgate_con[36];/* Address Offset: 0x0300 */ > + unsigned int reserved2[28]; /* Address Offset: 0x0390 */ > + unsigned int softrst_con[30];/* Address Offset: 0x0400 */ > + unsigned int reserved3[2];/* Address Offset: 0x0478 */ > + unsigned int ssgtbl[32];/* Address Offset: 0x0480 */ > + unsigned int reserved4[32];/* Address Offset: 0x0500 */ > + unsigned int sdmmc0_con[2];/* Address Offset: 0x0580 */ > + unsigned int sdmmc1_con[2];/* Address Offset: 0x058C */ > + unsigned int sdmmc2_con[2];/* Address Offset: 0x0590 */ > + unsigned int emmc_con[2];/* Address Offset: 0x0598 */ > +}; > + > +check_member(rk3568_cru, mode_con00, 0xc0); > +check_member(rk3568_cru, softrst_con[0], 0x400); > + > +struct pll_rate_table { > + unsigned long rate; > + unsigned int fbdiv; > + unsigned int postdiv1; > + unsigned int refdiv; > + unsigned int postdiv2; > + unsigned int dsmpd; > + unsigned int frac; > +}; > + > +#define RK3568_PMU_MODE 0x80 > +#define RK3568_PMU_PLL_CON(x) ((x) * 0x4) > +#define RK3568_PLL_CON(x) ((x) * 0x4) > +#define RK3568_MODE_CON 0xc0 > + > +enum { > + /* CRU_PMU_CLK_SEL0_CON */ > + RTC32K_SEL_SHIFT = 6, > + RTC32K_SEL_MASK = 0x3 << RTC32K_SEL_SHIFT, > + RTC32K_SEL_PMUPVTM = 0, > + RTC32K_SEL_OSC1_32K, > + RTC32K_SEL_OSC0_DIV32K, > + > + /* CRU_PMU_CLK_SEL1_CON */ > + RTC32K_FRAC_NUMERATOR_SHIFT = 16, > + RTC32K_FRAC_NUMERATOR_MASK = 0xffff << 16, > + RTC32K_FRAC_DENOMINATOR_SHIFT = 0, > + RTC32K_FRAC_DENOMINATOR_MASK = 0xffff, > + > + /* CRU_PMU_CLK_SEL2_CON */ > + PCLK_PDPMU_SEL_SHIFT = 15, > + PCLK_PDPMU_SEL_MASK = 1 << PCLK_PDPMU_SEL_SHIFT, > + PCLK_PDPMU_SEL_PPLL = 0, > + PCLK_PDPMU_SEL_GPLL, > + PCLK_PDPMU_DIV_SHIFT = 0, > + PCLK_PDPMU_DIV_MASK = 0x1f, > + > + /* CRU_PMU_CLK_SEL3_CON */ > + CLK_I2C0_DIV_SHIFT = 0, > + CLK_I2C0_DIV_MASK = 0x7f, > + > + /* CRU_PMU_CLK_SEL6_CON */ > + CLK_PWM0_SEL_SHIFT = 7, > + CLK_PWM0_SEL_MASK = 1 << CLK_PWM0_SEL_SHIFT, > + CLK_PWM0_SEL_XIN24M = 0, > + CLK_PWM0_SEL_PPLL, > + CLK_PWM0_DIV_SHIFT = 0, > + CLK_PWM0_DIV_MASK = 0x7f, > + > + /* CRU_CLK_SEL0_CON */ > + CLK_CORE_PRE_SEL_SHIFT = 7, > + CLK_CORE_PRE_SEL_MASK = 1 << CLK_CORE_PRE_SEL_SHIFT, > + CLK_CORE_PRE_SEL_SRC = 0, > + CLK_CORE_PRE_SEL_APLL, > + > + /* CRU_CLK_SEL2_CON */ > + SCLK_CORE_PRE_SEL_SHIFT = 15, > + SCLK_CORE_PRE_SEL_MASK = 1 << SCLK_CORE_PRE_SEL_SHIFT, > + SCLK_CORE_PRE_SEL_SRC = 0, > + SCLK_CORE_PRE_SEL_NPLL, > + SCLK_CORE_SRC_SEL_SHIFT = 8, > + SCLK_CORE_SRC_SEL_MASK = 3 << SCLK_CORE_SRC_SEL_SHIFT, > + SCLK_CORE_SRC_SEL_APLL = 0, > + SCLK_CORE_SRC_SEL_GPLL, > + SCLK_CORE_SRC_SEL_NPLL, > + SCLK_CORE_SRC_DIV_SHIFT = 0, > + SCLK_CORE_SRC_DIV_MASK = 0x1f << SCLK_CORE_SRC_DIV_SHIFT, > + > + /* CRU_CLK_SEL3_CON */ > + GICCLK_CORE_DIV_SHIFT = 8, > + GICCLK_CORE_DIV_MASK = 0x1f << GICCLK_CORE_DIV_SHIFT, > + ATCLK_CORE_DIV_SHIFT = 0, > + ATCLK_CORE_DIV_MASK = 0x1f << ATCLK_CORE_DIV_SHIFT, > + > + /* CRU_CLK_SEL4_CON */ > + PERIPHCLK_CORE_PRE_DIV_SHIFT = 8, > + PERIPHCLK_CORE_PRE_DIV_MASK = 0x1f << PERIPHCLK_CORE_PRE_DIV_SHIFT, > + PCLK_CORE_PRE_DIV_SHIFT = 0, > + PCLK_CORE_PRE_DIV_MASK = 0x1f << PCLK_CORE_PRE_DIV_SHIFT, > + > + /* CRU_CLK_SEL5_CON */ > + ACLK_CORE_NIU2BUS_SEL_SHIFT = 14, > + ACLK_CORE_NIU2BUS_SEL_MASK = 0x3 << ACLK_CORE_NIU2BUS_SEL_SHIFT, > + ACLK_CORE_NDFT_DIV_SHIFT = 8, > + ACLK_CORE_NDFT_DIV_MASK = 0x1f << ACLK_CORE_NDFT_DIV_SHIFT, > + > + /* CRU_CLK_SEL10_CON */ > + HCLK_PERIMID_SEL_SHIFT = 6, > + HCLK_PERIMID_SEL_MASK = 3 << HCLK_PERIMID_SEL_SHIFT, > + HCLK_PERIMID_SEL_150M = 0, > + HCLK_PERIMID_SEL_100M, > + HCLK_PERIMID_SEL_75M, > + HCLK_PERIMID_SEL_24M, > + ACLK_PERIMID_SEL_SHIFT = 4, > + ACLK_PERIMID_SEL_MASK = 3 << ACLK_PERIMID_SEL_SHIFT, > + ACLK_PERIMID_SEL_300M = 0, > + ACLK_PERIMID_SEL_200M, > + ACLK_PERIMID_SEL_100M, > + ACLK_PERIMID_SEL_24M, > + > + /* CRU_CLK_SEL27_CON */ > + CLK_CRYPTO_PKA_SEL_SHIFT = 6, > + CLK_CRYPTO_PKA_SEL_MASK = 3 << CLK_CRYPTO_PKA_SEL_SHIFT, > + CLK_CRYPTO_PKA_SEL_300M = 0, > + CLK_CRYPTO_PKA_SEL_200M, > + CLK_CRYPTO_PKA_SEL_100M, > + CLK_CRYPTO_CORE_SEL_SHIFT = 4, > + CLK_CRYPTO_CORE_SEL_MASK = 3 << CLK_CRYPTO_CORE_SEL_SHIFT, > + CLK_CRYPTO_CORE_SEL_200M = 0, > + CLK_CRYPTO_CORE_SEL_150M, > + CLK_CRYPTO_CORE_SEL_100M, > + HCLK_SECURE_FLASH_SEL_SHIFT = 2, > + HCLK_SECURE_FLASH_SEL_MASK = 3 << HCLK_SECURE_FLASH_SEL_SHIFT, > + HCLK_SECURE_FLASH_SEL_150M = 0, > + HCLK_SECURE_FLASH_SEL_100M, > + HCLK_SECURE_FLASH_SEL_75M, > + HCLK_SECURE_FLASH_SEL_24M, > + ACLK_SECURE_FLASH_SEL_SHIFT = 0, > + ACLK_SECURE_FLASH_SEL_MASK = 3 << ACLK_SECURE_FLASH_SEL_SHIFT, > + ACLK_SECURE_FLASH_SEL_200M = 0, > + ACLK_SECURE_FLASH_SEL_150M, > + ACLK_SECURE_FLASH_SEL_100M, > + ACLK_SECURE_FLASH_SEL_24M, > + > + /* CRU_CLK_SEL28_CON */ > + CCLK_EMMC_SEL_SHIFT = 12, > + CCLK_EMMC_SEL_MASK = 7 << CCLK_EMMC_SEL_SHIFT, > + CCLK_EMMC_SEL_24M = 0, > + CCLK_EMMC_SEL_200M, > + CCLK_EMMC_SEL_150M, > + CCLK_EMMC_SEL_100M, > + CCLK_EMMC_SEL_50M, > + CCLK_EMMC_SEL_375K, > + BCLK_EMMC_SEL_SHIFT = 8, > + BCLK_EMMC_SEL_MASK = 3 << BCLK_EMMC_SEL_SHIFT, > + BCLK_EMMC_SEL_200M = 0, > + BCLK_EMMC_SEL_150M, > + BCLK_EMMC_SEL_125M, > + SCLK_SFC_SEL_SHIFT = 4, > + SCLK_SFC_SEL_MASK = 7 << SCLK_SFC_SEL_SHIFT, > + SCLK_SFC_SEL_24M = 0, > + SCLK_SFC_SEL_50M, > + SCLK_SFC_SEL_75M, > + SCLK_SFC_SEL_100M, > + SCLK_SFC_SEL_125M, > + SCLK_SFC_SEL_150M, > + NCLK_NANDC_SEL_SHIFT = 0, > + NCLK_NANDC_SEL_MASK = 3 << NCLK_NANDC_SEL_SHIFT, > + NCLK_NANDC_SEL_200M = 0, > + NCLK_NANDC_SEL_150M, > + NCLK_NANDC_SEL_100M, > + NCLK_NANDC_SEL_24M, > + > + /* CRU_CLK_SEL30_CON */ > + CLK_SDMMC1_SEL_SHIFT = 12, > + CLK_SDMMC1_SEL_MASK = 7 << CLK_SDMMC1_SEL_SHIFT, > + CLK_SDMMC0_SEL_SHIFT = 8, > + CLK_SDMMC0_SEL_MASK = 7 << CLK_SDMMC0_SEL_SHIFT, > + CLK_SDMMC_SEL_24M = 0, > + CLK_SDMMC_SEL_400M, > + CLK_SDMMC_SEL_300M, > + CLK_SDMMC_SEL_100M, > + CLK_SDMMC_SEL_50M, > + CLK_SDMMC_SEL_750K, > + > + /* CRU_CLK_SEL31_CON */ > + CLK_MAC0_OUT_SEL_SHIFT = 14, > + CLK_MAC0_OUT_SEL_MASK = 3 << CLK_MAC0_OUT_SEL_SHIFT, > + CLK_MAC0_OUT_SEL_125M = 0, > + CLK_MAC0_OUT_SEL_50M, > + CLK_MAC0_OUT_SEL_25M, > + CLK_MAC0_OUT_SEL_24M, > + CLK_GMAC0_PTP_REF_SEL_SHIFT = 12, > + CLK_GMAC0_PTP_REF_SEL_MASK = 3 << CLK_GMAC0_PTP_REF_SEL_SHIFT, > + CLK_GMAC0_PTP_REF_SEL_62_5M = 0, > + CLK_GMAC0_PTP_REF_SEL_100M, > + CLK_GMAC0_PTP_REF_SEL_50M, > + CLK_GMAC0_PTP_REF_SEL_24M, > + CLK_MAC0_2TOP_SEL_SHIFT = 8, > + CLK_MAC0_2TOP_SEL_MASK = 3 << CLK_MAC0_2TOP_SEL_SHIFT, > + CLK_MAC0_2TOP_SEL_125M = 0, > + CLK_MAC0_2TOP_SEL_50M, > + CLK_MAC0_2TOP_SEL_25M, > + CLK_MAC0_2TOP_SEL_PPLL, > + RGMII0_CLK_SEL_SHIFT = 4, > + RGMII0_CLK_SEL_MASK = 3 << RGMII0_CLK_SEL_SHIFT, > + RGMII0_CLK_SEL_125M = 0, > + RGMII0_CLK_SEL_125M_1, > + RGMII0_CLK_SEL_2_5M, > + RGMII0_CLK_SEL_25M, > + RMII0_CLK_SEL_SHIFT = 3, > + RMII0_CLK_SEL_MASK = 1 << RMII0_CLK_SEL_SHIFT, > + RMII0_CLK_SEL_2_5M = 0, > + RMII0_CLK_SEL_25M, > + RMII0_EXTCLK_SEL_SHIFT = 2, > + RMII0_EXTCLK_SEL_MASK = 1 << RMII0_EXTCLK_SEL_SHIFT, > + RMII0_EXTCLK_SEL_MAC0_TOP = 0, > + RMII0_EXTCLK_SEL_IO, > + RMII0_MODE_SHIFT = 0, > + RMII0_MODE_MASK = 3 << RMII0_MODE_SHIFT, > + RMII0_MODE_SEL_RGMII = 0, > + RMII0_MODE_SEL_RMII, > + RMII0_MODE_SEL_GMII, > + > + /* CRU_CLK_SEL32_CON */ > + CLK_SDMMC2_SEL_SHIFT = 8, > + CLK_SDMMC2_SEL_MASK = 7 << CLK_SDMMC2_SEL_SHIFT, > + > + /* CRU_CLK_SEL38_CON */ > + ACLK_VOP_PRE_SEL_SHIFT = 6, > + ACLK_VOP_PRE_SEL_MASK = 3 << ACLK_VOP_PRE_SEL_SHIFT, > + ACLK_VOP_PRE_SEL_CPLL = 0, > + ACLK_VOP_PRE_SEL_GPLL, > + ACLK_VOP_PRE_SEL_HPLL, > + ACLK_VOP_PRE_SEL_VPLL, > + ACLK_VOP_PRE_DIV_SHIFT = 0, > + ACLK_VOP_PRE_DIV_MASK = 0x1f << ACLK_VOP_PRE_DIV_SHIFT, > + > + /* CRU_CLK_SEL39_CON */ > + DCLK0_VOP_SEL_SHIFT = 10, > + DCLK0_VOP_SEL_MASK = 3 << DCLK0_VOP_SEL_SHIFT, > + DCLK_VOP_SEL_HPLL = 0, > + DCLK_VOP_SEL_VPLL, > + DCLK_VOP_SEL_GPLL, > + DCLK_VOP_SEL_CPLL, > + DCLK0_VOP_DIV_SHIFT = 0, > + DCLK0_VOP_DIV_MASK = 0xff << DCLK0_VOP_DIV_SHIFT, > + > + /* CRU_CLK_SEL40_CON */ > + DCLK1_VOP_SEL_SHIFT = 10, > + DCLK1_VOP_SEL_MASK = 3 << DCLK1_VOP_SEL_SHIFT, > + DCLK1_VOP_DIV_SHIFT = 0, > + DCLK1_VOP_DIV_MASK = 0xff << DCLK1_VOP_DIV_SHIFT, > + > + /* CRU_CLK_SEL41_CON */ > + DCLK2_VOP_SEL_SHIFT = 10, > + DCLK2_VOP_SEL_MASK = 3 << DCLK2_VOP_SEL_SHIFT, > + DCLK2_VOP_DIV_SHIFT = 0, > + DCLK2_VOP_DIV_MASK = 0xff << DCLK2_VOP_DIV_SHIFT, > + > + /* CRU_CLK_SEL43_CON */ > + DCLK_EBC_SEL_SHIFT = 6, > + DCLK_EBC_SEL_MASK = 3 << DCLK_EBC_SEL_SHIFT, > + DCLK_EBC_SEL_GPLL_400M = 0, > + DCLK_EBC_SEL_CPLL_333M, > + DCLK_EBC_SEL_GPLL_200M, > + > + /* CRU_CLK_SEL47_CON */ > + ACLK_RKVDEC_SEL_SHIFT = 7, > + ACLK_RKVDEC_SEL_MASK = 1 << ACLK_RKVDEC_SEL_SHIFT, > + ACLK_RKVDEC_SEL_GPLL = 0, > + ACLK_RKVDEC_SEL_CPLL, > + ACLK_RKVDEC_DIV_SHIFT = 0, > + ACLK_RKVDEC_DIV_MASK = 0x1f << ACLK_RKVDEC_DIV_SHIFT, > + > + /* CRU_CLK_SEL49_CON */ > + CLK_RKVDEC_CORE_SEL_SHIFT = 14, > + CLK_RKVDEC_CORE_SEL_MASK = 0x3 << CLK_RKVDEC_CORE_SEL_SHIFT, > + CLK_RKVDEC_CORE_SEL_GPLL = 0, > + CLK_RKVDEC_CORE_SEL_CPLL, > + CLK_RKVDEC_CORE_SEL_NPLL, > + CLK_RKVDEC_CORE_SEL_VPLL, > + CLK_RKVDEC_CORE_DIV_SHIFT = 8, > + CLK_RKVDEC_CORE_DIV_MASK = 0x1f << CLK_RKVDEC_CORE_DIV_SHIFT, > + > + /* CRU_CLK_SEL50_CON */ > + PCLK_BUS_SEL_SHIFT = 4, > + PCLK_BUS_SEL_MASK = 3 << PCLK_BUS_SEL_SHIFT, > + PCLK_BUS_SEL_100M = 0, > + PCLK_BUS_SEL_75M, > + PCLK_BUS_SEL_50M, > + PCLK_BUS_SEL_24M, > + ACLK_BUS_SEL_SHIFT = 0, > + ACLK_BUS_SEL_MASK = 3 << ACLK_BUS_SEL_SHIFT, > + ACLK_BUS_SEL_200M = 0, > + ACLK_BUS_SEL_150M, > + ACLK_BUS_SEL_100M, > + ACLK_BUS_SEL_24M, > + > + /* CRU_CLK_SEL51_CON */ > + CLK_TSADC_DIV_SHIFT = 8, > + CLK_TSADC_DIV_MASK = 0x7f << CLK_TSADC_DIV_SHIFT, > + CLK_TSADC_TSEN_SEL_SHIFT = 4, > + CLK_TSADC_TSEN_SEL_MASK = 0x3 << CLK_TSADC_TSEN_SEL_SHIFT, > + CLK_TSADC_TSEN_SEL_24M = 0, > + CLK_TSADC_TSEN_SEL_100M, > + CLK_TSADC_TSEN_SEL_CPLL_100M, > + CLK_TSADC_TSEN_DIV_SHIFT = 0, > + CLK_TSADC_TSEN_DIV_MASK = 0x7 << CLK_TSADC_TSEN_DIV_SHIFT, > + > + /* CRU_CLK_SEL52_CON */ > + CLK_UART_SEL_SHIFT = 12, > + CLK_UART_SEL_MASK = 0x3 << CLK_UART_SEL_SHIFT, > + CLK_UART_SEL_SRC = 0, > + CLK_UART_SEL_FRAC, > + CLK_UART_SEL_XIN24M, > + CLK_UART_SRC_SEL_SHIFT = 8, > + CLK_UART_SRC_SEL_MASK = 0x3 << CLK_UART_SRC_SEL_SHIFT, > + CLK_UART_SRC_SEL_GPLL = 0, > + CLK_UART_SRC_SEL_CPLL, > + CLK_UART_SRC_SEL_480M, > + CLK_UART_SRC_DIV_SHIFT = 0, > + CLK_UART_SRC_DIV_MASK = 0x3f << CLK_UART_SRC_DIV_SHIFT, > + > + /* CRU_CLK_SEL53_CON */ > + CLK_UART_FRAC_NUMERATOR_SHIFT = 16, > + CLK_UART_FRAC_NUMERATOR_MASK = 0xffff << 16, > + CLK_UART_FRAC_DENOMINATOR_SHIFT = 0, > + CLK_UART_FRAC_DENOMINATOR_MASK = 0xffff, > + > + /* CRU_CLK_SEL71_CON */ > + CLK_I2C_SEL_SHIFT = 8, > + CLK_I2C_SEL_MASK = 3 << CLK_I2C_SEL_SHIFT, > + CLK_I2C_SEL_200M = 0, > + CLK_I2C_SEL_100M, > + CLK_I2C_SEL_24M, > + CLK_I2C_SEL_CPLL_100M, > + > + /* CRU_CLK_SEL72_CON */ > + CLK_PWM3_SEL_SHIFT = 12, > + CLK_PWM3_SEL_MASK = 3 << CLK_PWM3_SEL_SHIFT, > + CLK_PWM2_SEL_SHIFT = 10, > + CLK_PWM2_SEL_MASK = 3 << CLK_PWM2_SEL_SHIFT, > + CLK_PWM1_SEL_SHIFT = 8, > + CLK_PWM1_SEL_MASK = 3 << CLK_PWM1_SEL_SHIFT, > + CLK_PWM_SEL_100M = 0, > + CLK_PWM_SEL_24M, > + CLK_PWM_SEL_CPLL_100M, > + CLK_SPI3_SEL_SHIFT = 6, > + CLK_SPI3_SEL_MASK = 3 << CLK_SPI3_SEL_SHIFT, > + CLK_SPI2_SEL_SHIFT = 4, > + CLK_SPI2_SEL_MASK = 3 << CLK_SPI2_SEL_SHIFT, > + CLK_SPI1_SEL_SHIFT = 2, > + CLK_SPI1_SEL_MASK = 3 << CLK_SPI1_SEL_SHIFT, > + CLK_SPI0_SEL_SHIFT = 0, > + CLK_SPI0_SEL_MASK = 3 << CLK_SPI0_SEL_SHIFT, > + CLK_SPI_SEL_200M = 0, > + CLK_SPI_SEL_24M, > + CLK_SPI_SEL_CPLL_100M, > + > + /* CRU_CLK_SEL73_CON */ > + PCLK_TOP_SEL_SHIFT = 12, > + PCLK_TOP_SEL_MASK = 3 << PCLK_TOP_SEL_SHIFT, > + PCLK_TOP_SEL_100M = 0, > + PCLK_TOP_SEL_75M, > + PCLK_TOP_SEL_50M, > + PCLK_TOP_SEL_24M, > + HCLK_TOP_SEL_SHIFT = 8, > + HCLK_TOP_SEL_MASK = 3 << HCLK_TOP_SEL_SHIFT, > + HCLK_TOP_SEL_150M = 0, > + HCLK_TOP_SEL_100M, > + HCLK_TOP_SEL_75M, > + HCLK_TOP_SEL_24M, > + ACLK_TOP_LOW_SEL_SHIFT = 4, > + ACLK_TOP_LOW_SEL_MASK = 3 << ACLK_TOP_LOW_SEL_SHIFT, > + ACLK_TOP_LOW_SEL_400M = 0, > + ACLK_TOP_LOW_SEL_300M, > + ACLK_TOP_LOW_SEL_200M, > + ACLK_TOP_LOW_SEL_24M, > + ACLK_TOP_HIGH_SEL_SHIFT = 0, > + ACLK_TOP_HIGH_SEL_MASK = 3 << ACLK_TOP_HIGH_SEL_SHIFT, > + ACLK_TOP_HIGH_SEL_500M = 0, > + ACLK_TOP_HIGH_SEL_400M, > + ACLK_TOP_HIGH_SEL_300M, > + ACLK_TOP_HIGH_SEL_24M, > + > + /* CRU_CLK_SEL78_CON */ > + CPLL_500M_DIV_SHIFT = 8, > + CPLL_500M_DIV_MASK = 0x1f << CPLL_500M_DIV_SHIFT, > + > + /* CRU_CLK_SEL79_CON */ > + CPLL_250M_DIV_SHIFT = 8, > + CPLL_250M_DIV_MASK = 0x1f << CPLL_250M_DIV_SHIFT, > + CPLL_333M_DIV_SHIFT = 0, > + CPLL_333M_DIV_MASK = 0x1f << CPLL_333M_DIV_SHIFT, > + > + /* CRU_CLK_SEL80_CON */ > + CPLL_62P5M_DIV_SHIFT = 8, > + CPLL_62P5M_DIV_MASK = 0x1f << CPLL_62P5M_DIV_SHIFT, > + CPLL_125M_DIV_SHIFT = 0, > + CPLL_125M_DIV_MASK = 0x1f << CPLL_125M_DIV_SHIFT, > + > + /* CRU_CLK_SEL81_CON */ > + CPLL_25M_DIV_SHIFT = 8, > + CPLL_25M_DIV_MASK = 0x1f << CPLL_25M_DIV_SHIFT, > + CPLL_50M_DIV_SHIFT = 0, > + CPLL_50M_DIV_MASK = 0x1f << CPLL_50M_DIV_SHIFT, > + > + /* CRU_CLK_SEL82_CON */ > + CPLL_100M_DIV_SHIFT = 0, > + CPLL_100M_DIV_MASK = 0x1f << CPLL_100M_DIV_SHIFT, > +}; > +#endif > diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile > index 4cfcf8330929..913f611a0ff8 100644 > --- a/drivers/clk/rockchip/Makefile > +++ b/drivers/clk/rockchip/Makefile > @@ -14,4 +14,5 @@ obj-$(CONFIG_ROCKCHIP_RK3308) += clk_rk3308.o > obj-$(CONFIG_ROCKCHIP_RK3328) += clk_rk3328.o > obj-$(CONFIG_ROCKCHIP_RK3368) += clk_rk3368.o > obj-$(CONFIG_ROCKCHIP_RK3399) += clk_rk3399.o > +obj-$(CONFIG_ROCKCHIP_RK3568) += clk_rk3568.o > obj-$(CONFIG_ROCKCHIP_RV1108) += clk_rv1108.o > diff --git a/drivers/clk/rockchip/clk_rk3568.c b/drivers/clk/rockchip/clk_rk3568.c > new file mode 100644 > index 000000000000..359aca358e0d > --- /dev/null > +++ b/drivers/clk/rockchip/clk_rk3568.c > @@ -0,0 +1,2908 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright (c) 2021 Fuzhou Rockchip Electronics Co., Ltd Please remove "Fuzhou". > + * Author: Elaine Zhang > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +DECLARE_GLOBAL_DATA_PTR; > + > +#if CONFIG_IS_ENABLED(OF_PLATDATA) > +struct rk3568_clk_plat { > + struct dtd_rockchip_rk3568_cru dtd; > +}; > + > +struct rk3568_pmuclk_plat { > + struct dtd_rockchip_rk3568_pmucru dtd; > +}; > +#endif > + > +#define RK3568_CPUCLK_RATE(_rate, _aclk_div, _pclk_div) \ > +{ \ > + .rate = _rate##U, \ > + .aclk_div = _aclk_div, \ > + .pclk_div = _pclk_div, \ > +} > + > +#define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1)) > + > +static struct rockchip_cpu_rate_table rk3568_cpu_rates[] = { > + RK3568_CPUCLK_RATE(1416000000, 1, 5), > + RK3568_CPUCLK_RATE(1296000000, 1, 5), > + RK3568_CPUCLK_RATE(1200000000, 1, 3), > + RK3568_CPUCLK_RATE(1104000000, 1, 3), > + RK3568_CPUCLK_RATE(1008000000, 1, 3), > + RK3568_CPUCLK_RATE(912000000, 1, 3), > + RK3568_CPUCLK_RATE(816000000, 1, 3), > + RK3568_CPUCLK_RATE(600000000, 1, 1), > + RK3568_CPUCLK_RATE(408000000, 1, 1), > + { /* sentinel */ }, > +}; > + > +static struct rockchip_pll_rate_table rk3568_pll_rates[] = { > + /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */ > + RK3036_PLL_RATE(1608000000, 1, 67, 1, 1, 1, 0), > + RK3036_PLL_RATE(1416000000, 1, 118, 2, 1, 1, 0), > + RK3036_PLL_RATE(1296000000, 1, 108, 2, 1, 1, 0), > + RK3036_PLL_RATE(1200000000, 1, 100, 2, 1, 1, 0), > + RK3036_PLL_RATE(1188000000, 1, 99, 2, 1, 1, 0), > + RK3036_PLL_RATE(1104000000, 1, 92, 2, 1, 1, 0), > + RK3036_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0), > + RK3036_PLL_RATE(1000000000, 3, 250, 2, 1, 1, 0), > + RK3036_PLL_RATE(912000000, 1, 76, 2, 1, 1, 0), > + RK3036_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0), > + RK3036_PLL_RATE(600000000, 1, 100, 4, 1, 1, 0), > + RK3036_PLL_RATE(594000000, 1, 99, 4, 1, 1, 0), > + RK3036_PLL_RATE(500000000, 1, 125, 6, 1, 1, 0), > + RK3036_PLL_RATE(408000000, 1, 68, 2, 2, 1, 0), > + RK3036_PLL_RATE(400000000, 1, 100, 6, 1, 1, 0), > + RK3036_PLL_RATE(200000000, 1, 100, 6, 2, 1, 0), > + RK3036_PLL_RATE(100000000, 1, 150, 6, 6, 1, 0), > + { /* sentinel */ }, > +}; > + > +static struct rockchip_pll_clock rk3568_pll_clks[] = { > + [APLL] = PLL(pll_rk3328, PLL_APLL, RK3568_PLL_CON(0), > + RK3568_MODE_CON, 0, 10, 0, rk3568_pll_rates), > + [DPLL] = PLL(pll_rk3328, PLL_DPLL, RK3568_PLL_CON(8), > + RK3568_MODE_CON, 2, 10, 0, NULL), > + [CPLL] = PLL(pll_rk3328, PLL_CPLL, RK3568_PLL_CON(24), > + RK3568_MODE_CON, 4, 10, 0, rk3568_pll_rates), > + [GPLL] = PLL(pll_rk3328, PLL_HPLL, RK3568_PLL_CON(16), > + RK3568_MODE_CON, 6, 10, 0, rk3568_pll_rates), > + [NPLL] = PLL(pll_rk3328, PLL_NPLL, RK3568_PLL_CON(32), > + RK3568_MODE_CON, 10, 10, 0, rk3568_pll_rates), > + [VPLL] = PLL(pll_rk3328, PLL_VPLL, RK3568_PLL_CON(40), > + RK3568_MODE_CON, 12, 10, 0, rk3568_pll_rates), > + [PPLL] = PLL(pll_rk3328, PLL_PPLL, RK3568_PMU_PLL_CON(0), > + RK3568_PMU_MODE, 0, 10, 0, rk3568_pll_rates), > + [HPLL] = PLL(pll_rk3328, PLL_HPLL, RK3568_PMU_PLL_CON(16), > + RK3568_PMU_MODE, 2, 10, 0, rk3568_pll_rates), > +}; > + > +static ulong __maybe_unused > +rk3568_pmu_pll_set_rate(struct rk3568_clk_priv *priv, > + ulong pll_id, ulong rate) > +{ > + struct udevice *pmucru_dev; > + struct rk3568_pmuclk_priv *pmu_priv; > + int ret; > + > + ret = uclass_get_device_by_driver(UCLASS_CLK, > + DM_DRIVER_GET(rockchip_rk3568_pmucru), > + &pmucru_dev); > + if (ret) { > + printf("%s: could not find pmucru device\n", __func__); > + return ret; > + } > + pmu_priv = dev_get_priv(pmucru_dev); > + > + rockchip_pll_set_rate(&rk3568_pll_clks[pll_id], > + pmu_priv->pmucru, pll_id, rate); > + > + return 0; > +} > + > +static ulong rk3568_pmu_pll_get_rate(struct rk3568_clk_priv *priv, > + ulong pll_id) > +{ > + struct udevice *pmucru_dev; > + struct rk3568_pmuclk_priv *pmu_priv; > + int ret; > + > + ret = uclass_get_device_by_driver(UCLASS_CLK, > + DM_DRIVER_GET(rockchip_rk3568_pmucru), > + &pmucru_dev); > + if (ret) { > + printf("%s: could not find pmucru device\n", __func__); > + return ret; > + } > + pmu_priv = dev_get_priv(pmucru_dev); > + > + return rockchip_pll_get_rate(&rk3568_pll_clks[pll_id], > + pmu_priv->pmucru, pll_id); > +} > + > +/* > + * > + * rational_best_approximation(31415, 10000, > + * (1 << 8) - 1, (1 << 5) - 1, &n, &d); > + * > + * you may look at given_numerator as a fixed point number, > + * with the fractional part size described in given_denominator. > + * > + * for theoretical background, see: > + * http://en.wikipedia.org/wiki/Continued_fraction > + */ > +static void rational_best_approximation(unsigned long given_numerator, > + unsigned long given_denominator, > + unsigned long max_numerator, > + unsigned long max_denominator, > + unsigned long *best_numerator, > + unsigned long *best_denominator) > +{ > + unsigned long n, d, n0, d0, n1, d1; > + > + n = given_numerator; > + d = given_denominator; > + n0 = 0; > + d1 = 0; > + n1 = 1; > + d0 = 1; > + for (;;) { > + unsigned long t, a; > + > + if (n1 > max_numerator || d1 > max_denominator) { > + n1 = n0; > + d1 = d0; > + break; > + } > + if (d == 0) > + break; > + t = d; > + a = n / d; > + d = n % d; > + n = t; > + t = n0 + a * n1; > + n0 = n1; > + n1 = t; > + t = d0 + a * d1; > + d0 = d1; > + d1 = t; > + } > + *best_numerator = n1; > + *best_denominator = d1; > +} > + > +static ulong rk3568_rtc32k_get_pmuclk(struct rk3568_pmuclk_priv *priv) > +{ > + struct rk3568_pmucru *pmucru = priv->pmucru; > + unsigned long m, n; > + u32 fracdiv; > + > + fracdiv = readl(&pmucru->pmu_clksel_con[1]); > + m = fracdiv & RTC32K_FRAC_NUMERATOR_MASK; > + m >>= RTC32K_FRAC_NUMERATOR_SHIFT; > + n = fracdiv & RTC32K_FRAC_DENOMINATOR_MASK; > + n >>= RTC32K_FRAC_DENOMINATOR_SHIFT; > + > + return OSC_HZ * m / n; > +} > + > +static ulong rk3568_rtc32k_set_pmuclk(struct rk3568_pmuclk_priv *priv, > + ulong rate) > +{ > + struct rk3568_pmucru *pmucru = priv->pmucru; > + unsigned long m, n, val; > + > + rk_clrsetreg(&pmucru->pmu_clksel_con[0], RTC32K_SEL_MASK, > + RTC32K_SEL_OSC0_DIV32K << RTC32K_SEL_SHIFT); > + > + rational_best_approximation(rate, OSC_HZ, > + GENMASK(16 - 1, 0), > + GENMASK(16 - 1, 0), > + &m, &n); > + val = m << RTC32K_FRAC_NUMERATOR_SHIFT | n; > + writel(val, &pmucru->pmu_clksel_con[1]); > + > + return rk3568_rtc32k_get_pmuclk(priv); > +} > + > +static ulong rk3568_i2c_get_pmuclk(struct rk3568_pmuclk_priv *priv, > + ulong clk_id) > +{ > + struct rk3568_pmucru *pmucru = priv->pmucru; > + u32 div, con; > + > + switch (clk_id) { > + case CLK_I2C0: > + con = readl(&pmucru->pmu_clksel_con[3]); > + div = (con & CLK_I2C0_DIV_MASK) >> CLK_I2C0_DIV_SHIFT; > + break; > + default: > + return -ENOENT; > + } > + > + return DIV_TO_RATE(priv->ppll_hz, div); > +} > + > +static ulong rk3568_i2c_set_pmuclk(struct rk3568_pmuclk_priv *priv, > + ulong clk_id, ulong rate) > +{ > + struct rk3568_pmucru *pmucru = priv->pmucru; > + int src_clk_div; > + > + src_clk_div = DIV_ROUND_UP(priv->ppll_hz, rate); > + assert(src_clk_div - 1 <= 127); > + > + switch (clk_id) { > + case CLK_I2C0: > + rk_clrsetreg(&pmucru->pmu_clksel_con[3], CLK_I2C0_DIV_MASK, > + (src_clk_div - 1) << CLK_I2C0_DIV_SHIFT); > + break; > + default: > + return -ENOENT; > + } > + > + return rk3568_i2c_get_pmuclk(priv, clk_id); > +} > + > +static ulong rk3568_pwm_get_pmuclk(struct rk3568_pmuclk_priv *priv, > + ulong clk_id) > +{ > + struct rk3568_pmucru *pmucru = priv->pmucru; > + u32 div, sel, con, parent; > + > + switch (clk_id) { > + case CLK_PWM0: > + con = readl(&pmucru->pmu_clksel_con[6]); > + sel = (con & CLK_PWM0_SEL_MASK) >> CLK_PWM0_SEL_SHIFT; > + div = (con & CLK_PWM0_DIV_MASK) >> CLK_PWM0_DIV_SHIFT; > + if (sel == CLK_PWM0_SEL_XIN24M) > + parent = OSC_HZ; > + else > + parent = priv->ppll_hz; > + break; > + default: > + return -ENOENT; > + } > + > + return DIV_TO_RATE(parent, div); > +} > + > +static ulong rk3568_pwm_set_pmuclk(struct rk3568_pmuclk_priv *priv, > + ulong clk_id, ulong rate) > +{ > + struct rk3568_pmucru *pmucru = priv->pmucru; > + int src_clk_div; > + > + switch (clk_id) { > + case CLK_PWM0: > + if (rate == OSC_HZ) { > + rk_clrsetreg(&pmucru->pmu_clksel_con[6], > + CLK_PWM0_SEL_MASK | CLK_PWM0_DIV_MASK, > + (CLK_PWM0_SEL_XIN24M << > + CLK_PWM0_SEL_SHIFT) | > + 0 << CLK_PWM0_SEL_SHIFT); > + } else { > + src_clk_div = DIV_ROUND_UP(priv->ppll_hz, rate); > + assert(src_clk_div - 1 <= 127); > + rk_clrsetreg(&pmucru->pmu_clksel_con[6], > + CLK_PWM0_DIV_MASK | CLK_PWM0_DIV_MASK, > + (CLK_PWM0_SEL_PPLL << CLK_PWM0_SEL_SHIFT) | > + (src_clk_div - 1) << CLK_PWM0_DIV_SHIFT); > + } > + break; > + default: > + return -ENOENT; > + } > + > + return rk3568_pwm_get_pmuclk(priv, clk_id); > +} > + > +static ulong rk3568_pmu_get_pmuclk(struct rk3568_pmuclk_priv *priv) > +{ > + struct rk3568_pmucru *pmucru = priv->pmucru; > + u32 div, con, sel, parent; > + > + con = readl(&pmucru->pmu_clksel_con[2]); > + sel = (con & PCLK_PDPMU_SEL_MASK) >> PCLK_PDPMU_SEL_SHIFT; > + div = (con & PCLK_PDPMU_DIV_MASK) >> PCLK_PDPMU_DIV_SHIFT; > + if (sel) > + parent = GPLL_HZ; > + else > + parent = priv->ppll_hz; > + > + return DIV_TO_RATE(parent, div); > +} > + > +static ulong rk3568_pmu_set_pmuclk(struct rk3568_pmuclk_priv *priv, > + ulong rate) > +{ > + struct rk3568_pmucru *pmucru = priv->pmucru; > + int src_clk_div; > + > + src_clk_div = DIV_ROUND_UP(priv->ppll_hz, rate); > + assert(src_clk_div - 1 <= 31); > + > + rk_clrsetreg(&pmucru->pmu_clksel_con[2], > + PCLK_PDPMU_DIV_MASK | PCLK_PDPMU_SEL_MASK, > + (PCLK_PDPMU_SEL_PPLL << PCLK_PDPMU_SEL_SHIFT) | > + ((src_clk_div - 1) << PCLK_PDPMU_DIV_SHIFT)); > + > + return rk3568_pmu_get_pmuclk(priv); > +} > + > +static ulong rk3568_pmuclk_get_rate(struct clk *clk) > +{ > + struct rk3568_pmuclk_priv *priv = dev_get_priv(clk->dev); > + ulong rate = 0; > + > + if (!priv->ppll_hz) { > + printf("%s ppll=%lu\n", __func__, priv->ppll_hz); > + return -ENOENT; > + } > + > + debug("%s %ld\n", __func__, clk->id); > + switch (clk->id) { > + case PLL_PPLL: > + rate = rockchip_pll_get_rate(&rk3568_pll_clks[PPLL], > + priv->pmucru, PPLL); > + break; > + case PLL_HPLL: > + rate = rockchip_pll_get_rate(&rk3568_pll_clks[HPLL], > + priv->pmucru, HPLL); > + break; > + case CLK_RTC_32K: > + case CLK_RTC32K_FRAC: > + rate = rk3568_rtc32k_get_pmuclk(priv); > + break; > + case CLK_I2C0: > + rate = rk3568_i2c_get_pmuclk(priv, clk->id); > + break; > + case CLK_PWM0: > + rate = rk3568_pwm_get_pmuclk(priv, clk->id); > + break; > + case PCLK_PMU: > + rate = rk3568_pmu_get_pmuclk(priv); > + break; > + default: > + return -ENOENT; > + } > + > + return rate; > +} > + > +static ulong rk3568_pmuclk_set_rate(struct clk *clk, ulong rate) > +{ > + struct rk3568_pmuclk_priv *priv = dev_get_priv(clk->dev); > + ulong ret = 0; > + > + if (!priv->ppll_hz) { > + printf("%s ppll=%lu\n", __func__, priv->ppll_hz); > + return -ENOENT; > + } > + > + debug("%s %ld %ld\n", __func__, clk->id, rate); > + switch (clk->id) { > + case PLL_PPLL: > + ret = rockchip_pll_set_rate(&rk3568_pll_clks[PPLL], > + priv->pmucru, PPLL, rate); > + priv->ppll_hz = rockchip_pll_get_rate(&rk3568_pll_clks[PPLL], > + priv->pmucru, PPLL); > + break; > + case PLL_HPLL: > + ret = rockchip_pll_set_rate(&rk3568_pll_clks[HPLL], > + priv->pmucru, HPLL, rate); > + priv->hpll_hz = rockchip_pll_get_rate(&rk3568_pll_clks[HPLL], > + priv->pmucru, HPLL); > + break; > + case CLK_RTC_32K: > + case CLK_RTC32K_FRAC: > + ret = rk3568_rtc32k_set_pmuclk(priv, rate); > + break; > + case CLK_I2C0: > + ret = rk3568_i2c_set_pmuclk(priv, clk->id, rate); > + break; > + case CLK_PWM0: > + ret = rk3568_pwm_set_pmuclk(priv, clk->id, rate); > + break; > + case PCLK_PMU: > + ret = rk3568_pmu_set_pmuclk(priv, rate); > + break; > + default: > + return -ENOENT; > + } > + > + return ret; > +} > + > +static int rk3568_rtc32k_set_parent(struct clk *clk, struct clk *parent) > +{ > + struct rk3568_pmuclk_priv *priv = dev_get_priv(clk->dev); > + struct rk3568_pmucru *pmucru = priv->pmucru; > + > + if (parent->id == CLK_RTC32K_FRAC) > + rk_clrsetreg(&pmucru->pmu_clksel_con[0], RTC32K_SEL_MASK, > + RTC32K_SEL_OSC0_DIV32K << RTC32K_SEL_SHIFT); > + else > + rk_clrsetreg(&pmucru->pmu_clksel_con[0], RTC32K_SEL_MASK, > + RTC32K_SEL_OSC1_32K << RTC32K_SEL_SHIFT); > + > + return 0; > +} > + > +static int rk3568_pmuclk_set_parent(struct clk *clk, struct clk *parent) > +{ > + switch (clk->id) { > + case CLK_RTC_32K: > + return rk3568_rtc32k_set_parent(clk, parent); > + default: > + return -ENOENT; > + } > +} > + > +static struct clk_ops rk3568_pmuclk_ops = { > + .get_rate = rk3568_pmuclk_get_rate, > + .set_rate = rk3568_pmuclk_set_rate, > + .set_parent = rk3568_pmuclk_set_parent, > +}; > + > +static int rk3568_pmuclk_probe(struct udevice *dev) > +{ > + struct rk3568_pmuclk_priv *priv = dev_get_priv(dev); > + int ret = 0; > + > + if (priv->ppll_hz != PPLL_HZ) { > + ret = rockchip_pll_set_rate(&rk3568_pll_clks[PPLL], > + priv->pmucru, > + PPLL, PPLL_HZ); > + if (!ret) > + priv->ppll_hz = PPLL_HZ; > + } > + > + /* Ungate PCIe30phy refclk_m and refclk_n */ > + rk_clrsetreg(&priv->pmucru->pmu_clkgate_con[2], 0x3 << 13, 0 << 13); > + return 0; > +} > + > +static int rk3568_pmuclk_ofdata_to_platdata(struct udevice *dev) > +{ > + struct rk3568_pmuclk_priv *priv = dev_get_priv(dev); > + > + priv->pmucru = dev_read_addr_ptr(dev); > + > + return 0; > +} > + > +static int rk3568_pmuclk_bind(struct udevice *dev) > +{ > +#if CONFIG_IS_ENABLED(RESET_ROCKCHIP) > + int ret = 0; > + > + ret = offsetof(struct rk3568_pmucru, pmu_softrst_con[0]); > + ret = rockchip_reset_bind(dev, ret, 1); > + if (ret) > + debug("Warning: pmucru software reset driver bind faile\n"); > +#endif > + > + return 0; > +} > + > +static const struct udevice_id rk3568_pmuclk_ids[] = { > + { .compatible = "rockchip,rk3568-pmucru" }, > + { } > +}; > + > +U_BOOT_DRIVER(rockchip_rk3568_pmucru) = { > + .name = "rockchip_rk3568_pmucru", > + .id = UCLASS_CLK, > + .of_match = rk3568_pmuclk_ids, > + .priv_auto = sizeof(struct rk3568_pmuclk_priv), > + .of_to_plat = rk3568_pmuclk_ofdata_to_platdata, > + .ops = &rk3568_pmuclk_ops, > + .bind = rk3568_pmuclk_bind, > + .probe = rk3568_pmuclk_probe, > +#if CONFIG_IS_ENABLED(OF_PLATDATA) > + .plat_auto = sizeof(struct rk3568_pmuclk_plat), > +#endif > + > +}; > + > +static int rk3568_armclk_set_clk(struct rk3568_clk_priv *priv, ulong hz) > +{ > + struct rk3568_cru *cru = priv->cru; > + const struct rockchip_cpu_rate_table *rate; > + ulong old_rate; > + > + rate = rockchip_get_cpu_settings(rk3568_cpu_rates, hz); > + if (!rate) { > + printf("%s unsupported rate\n", __func__); > + return -EINVAL; > + } > + > + rk_clrsetreg(&cru->clksel_con[0], > + CLK_CORE_PRE_SEL_MASK, > + (CLK_CORE_PRE_SEL_SRC << CLK_CORE_PRE_SEL_SHIFT)); > + rk_clrsetreg(&cru->clksel_con[2], > + SCLK_CORE_PRE_SEL_MASK | > + SCLK_CORE_SRC_SEL_MASK | > + SCLK_CORE_SRC_DIV_MASK, > + (SCLK_CORE_PRE_SEL_SRC << > + SCLK_CORE_PRE_SEL_SHIFT) | > + (SCLK_CORE_SRC_SEL_APLL << > + SCLK_CORE_SRC_SEL_SHIFT) | > + (1 << SCLK_CORE_SRC_DIV_SHIFT)); > + > + /* > + * set up dependent divisors for DBG and ACLK clocks. > + */ > + old_rate = rockchip_pll_get_rate(&rk3568_pll_clks[APLL], > + priv->cru, APLL); > + if (old_rate > hz) { > + if (rockchip_pll_set_rate(&rk3568_pll_clks[APLL], > + priv->cru, APLL, hz)) > + return -EINVAL; > + rk_clrsetreg(&cru->clksel_con[3], > + GICCLK_CORE_DIV_MASK | ATCLK_CORE_DIV_MASK, > + rate->pclk_div << GICCLK_CORE_DIV_SHIFT | > + rate->pclk_div << ATCLK_CORE_DIV_SHIFT); > + rk_clrsetreg(&cru->clksel_con[4], > + PERIPHCLK_CORE_PRE_DIV_MASK | > + PCLK_CORE_PRE_DIV_MASK, > + rate->pclk_div << PCLK_CORE_PRE_DIV_SHIFT | > + rate->pclk_div << PERIPHCLK_CORE_PRE_DIV_SHIFT); > + rk_clrsetreg(&cru->clksel_con[5], > + ACLK_CORE_NDFT_DIV_MASK, > + rate->aclk_div << ACLK_CORE_NDFT_DIV_SHIFT); > + } else if (old_rate < hz) { > + rk_clrsetreg(&cru->clksel_con[3], > + GICCLK_CORE_DIV_MASK | ATCLK_CORE_DIV_MASK, > + rate->pclk_div << GICCLK_CORE_DIV_SHIFT | > + rate->pclk_div << ATCLK_CORE_DIV_SHIFT); > + rk_clrsetreg(&cru->clksel_con[4], > + PERIPHCLK_CORE_PRE_DIV_MASK | > + PCLK_CORE_PRE_DIV_MASK, > + rate->pclk_div << PCLK_CORE_PRE_DIV_SHIFT | > + rate->pclk_div << PERIPHCLK_CORE_PRE_DIV_SHIFT); > + rk_clrsetreg(&cru->clksel_con[5], > + ACLK_CORE_NDFT_DIV_MASK, > + rate->aclk_div << ACLK_CORE_NDFT_DIV_SHIFT); > + if (rockchip_pll_set_rate(&rk3568_pll_clks[APLL], > + priv->cru, APLL, hz)) > + return -EINVAL; > + } > + > + return 0; > +} > + > +static ulong rk3568_cpll_div_get_rate(struct rk3568_clk_priv *priv, > + ulong clk_id) > +{ > + struct rk3568_cru *cru = priv->cru; > + int div, mask, shift, con; > + > + switch (clk_id) { > + case CPLL_500M: > + con = 78; > + mask = CPLL_500M_DIV_MASK; > + shift = CPLL_500M_DIV_SHIFT; > + break; > + case CPLL_333M: > + con = 79; > + mask = CPLL_333M_DIV_MASK; > + shift = CPLL_333M_DIV_SHIFT; > + break; > + case CPLL_250M: > + con = 79; > + mask = CPLL_250M_DIV_MASK; > + shift = CPLL_250M_DIV_SHIFT; > + break; > + case CPLL_125M: > + con = 80; > + mask = CPLL_125M_DIV_MASK; > + shift = CPLL_125M_DIV_SHIFT; > + break; > + case CPLL_100M: > + con = 82; > + mask = CPLL_100M_DIV_MASK; > + shift = CPLL_100M_DIV_SHIFT; > + break; > + case CPLL_62P5M: > + con = 80; > + mask = CPLL_62P5M_DIV_MASK; > + shift = CPLL_62P5M_DIV_SHIFT; > + break; > + case CPLL_50M: > + con = 81; > + mask = CPLL_50M_DIV_MASK; > + shift = CPLL_50M_DIV_SHIFT; > + break; > + case CPLL_25M: > + con = 81; > + mask = CPLL_25M_DIV_MASK; > + shift = CPLL_25M_DIV_SHIFT; > + break; > + default: > + return -ENOENT; > + } > + > + div = (readl(&cru->clksel_con[con]) & mask) >> shift; > + return DIV_TO_RATE(priv->cpll_hz, div); > +} > + > +static ulong rk3568_cpll_div_set_rate(struct rk3568_clk_priv *priv, > + ulong clk_id, ulong rate) > +{ > + struct rk3568_cru *cru = priv->cru; > + int div, mask, shift, con; > + > + switch (clk_id) { > + case CPLL_500M: > + con = 78; > + mask = CPLL_500M_DIV_MASK; > + shift = CPLL_500M_DIV_SHIFT; > + break; > + case CPLL_333M: > + con = 79; > + mask = CPLL_333M_DIV_MASK; > + shift = CPLL_333M_DIV_SHIFT; > + break; > + case CPLL_250M: > + con = 79; > + mask = CPLL_250M_DIV_MASK; > + shift = CPLL_250M_DIV_SHIFT; > + break; > + case CPLL_125M: > + con = 80; > + mask = CPLL_125M_DIV_MASK; > + shift = CPLL_125M_DIV_SHIFT; > + break; > + case CPLL_100M: > + con = 82; > + mask = CPLL_100M_DIV_MASK; > + shift = CPLL_100M_DIV_SHIFT; > + break; > + case CPLL_62P5M: > + con = 80; > + mask = CPLL_62P5M_DIV_MASK; > + shift = CPLL_62P5M_DIV_SHIFT; > + break; > + case CPLL_50M: > + con = 81; > + mask = CPLL_50M_DIV_MASK; > + shift = CPLL_50M_DIV_SHIFT; > + break; > + case CPLL_25M: > + con = 81; > + mask = CPLL_25M_DIV_MASK; > + shift = CPLL_25M_DIV_SHIFT; > + break; > + default: > + return -ENOENT; > + } > + > + div = DIV_ROUND_UP(priv->cpll_hz, rate); > + assert(div - 1 <= 31); > + rk_clrsetreg(&cru->clksel_con[con], > + mask, (div - 1) << shift); > + return rk3568_cpll_div_get_rate(priv, clk_id); > +} > + > +static ulong rk3568_bus_get_clk(struct rk3568_clk_priv *priv, ulong clk_id) > +{ > + struct rk3568_cru *cru = priv->cru; > + u32 con, sel, rate; > + > + switch (clk_id) { > + case ACLK_BUS: > + con = readl(&cru->clksel_con[50]); > + sel = (con & ACLK_BUS_SEL_MASK) >> ACLK_BUS_SEL_SHIFT; > + if (sel == ACLK_BUS_SEL_200M) > + rate = 200 * MHz; > + else if (sel == ACLK_BUS_SEL_150M) > + rate = 150 * MHz; > + else if (sel == ACLK_BUS_SEL_100M) > + rate = 100 * MHz; > + else > + rate = OSC_HZ; > + break; > + case PCLK_BUS: > + case PCLK_WDT_NS: > + con = readl(&cru->clksel_con[50]); > + sel = (con & PCLK_BUS_SEL_MASK) >> PCLK_BUS_SEL_SHIFT; > + if (sel == PCLK_BUS_SEL_100M) > + rate = 100 * MHz; > + else if (sel == PCLK_BUS_SEL_75M) > + rate = 75 * MHz; > + else if (sel == PCLK_BUS_SEL_50M) > + rate = 50 * MHz; > + else > + rate = OSC_HZ; > + break; > + default: > + return -ENOENT; > + } > + > + return rate; > +} > + > +static ulong rk3568_bus_set_clk(struct rk3568_clk_priv *priv, > + ulong clk_id, ulong rate) > +{ > + struct rk3568_cru *cru = priv->cru; > + int src_clk; > + > + switch (clk_id) { > + case ACLK_BUS: > + if (rate == 200 * MHz) > + src_clk = ACLK_BUS_SEL_200M; > + else if (rate == 150 * MHz) > + src_clk = ACLK_BUS_SEL_150M; > + else if (rate == 100 * MHz) > + src_clk = ACLK_BUS_SEL_100M; > + else > + src_clk = ACLK_BUS_SEL_24M; > + rk_clrsetreg(&cru->clksel_con[50], > + ACLK_BUS_SEL_MASK, > + src_clk << ACLK_BUS_SEL_SHIFT); > + break; > + case PCLK_BUS: > + case PCLK_WDT_NS: > + if (rate == 100 * MHz) > + src_clk = PCLK_BUS_SEL_100M; > + else if (rate == 75 * MHz) > + src_clk = PCLK_BUS_SEL_75M; > + else if (rate == 50 * MHz) > + src_clk = PCLK_BUS_SEL_50M; > + else > + src_clk = PCLK_BUS_SEL_24M; > + rk_clrsetreg(&cru->clksel_con[50], > + PCLK_BUS_SEL_MASK, > + src_clk << PCLK_BUS_SEL_SHIFT); > + break; > + > + default: > + printf("do not support this bus freq\n"); > + return -EINVAL; > + } > + > + return rk3568_bus_get_clk(priv, clk_id); > +} > + > +static ulong rk3568_perimid_get_clk(struct rk3568_clk_priv *priv, ulong clk_id) > +{ > + struct rk3568_cru *cru = priv->cru; > + u32 con, sel, rate; > + > + switch (clk_id) { > + case ACLK_PERIMID: > + con = readl(&cru->clksel_con[10]); > + sel = (con & ACLK_PERIMID_SEL_MASK) >> ACLK_PERIMID_SEL_SHIFT; > + if (sel == ACLK_PERIMID_SEL_300M) > + rate = 300 * MHz; > + else if (sel == ACLK_PERIMID_SEL_200M) > + rate = 200 * MHz; > + else if (sel == ACLK_PERIMID_SEL_100M) > + rate = 100 * MHz; > + else > + rate = OSC_HZ; > + break; > + case HCLK_PERIMID: > + con = readl(&cru->clksel_con[10]); > + sel = (con & HCLK_PERIMID_SEL_MASK) >> HCLK_PERIMID_SEL_SHIFT; > + if (sel == HCLK_PERIMID_SEL_150M) > + rate = 150 * MHz; > + else if (sel == HCLK_PERIMID_SEL_100M) > + rate = 100 * MHz; > + else if (sel == HCLK_PERIMID_SEL_75M) > + rate = 75 * MHz; > + else > + rate = OSC_HZ; > + break; > + default: > + return -ENOENT; > + } > + > + return rate; > +} > + > +static ulong rk3568_perimid_set_clk(struct rk3568_clk_priv *priv, > + ulong clk_id, ulong rate) > +{ > + struct rk3568_cru *cru = priv->cru; > + int src_clk; > + > + switch (clk_id) { > + case ACLK_PERIMID: > + if (rate == 300 * MHz) > + src_clk = ACLK_PERIMID_SEL_300M; > + else if (rate == 200 * MHz) > + src_clk = ACLK_PERIMID_SEL_200M; > + else if (rate == 100 * MHz) > + src_clk = ACLK_PERIMID_SEL_100M; > + else > + src_clk = ACLK_PERIMID_SEL_24M; > + rk_clrsetreg(&cru->clksel_con[10], > + ACLK_PERIMID_SEL_MASK, > + src_clk << ACLK_PERIMID_SEL_SHIFT); > + break; > + case HCLK_PERIMID: > + if (rate == 150 * MHz) > + src_clk = HCLK_PERIMID_SEL_150M; > + else if (rate == 100 * MHz) > + src_clk = HCLK_PERIMID_SEL_100M; > + else if (rate == 75 * MHz) > + src_clk = HCLK_PERIMID_SEL_75M; > + else > + src_clk = HCLK_PERIMID_SEL_24M; > + rk_clrsetreg(&cru->clksel_con[10], > + HCLK_PERIMID_SEL_MASK, > + src_clk << HCLK_PERIMID_SEL_SHIFT); > + break; > + > + default: > + printf("do not support this permid freq\n"); > + return -EINVAL; > + } > + > + return rk3568_perimid_get_clk(priv, clk_id); > +} > + > +static ulong rk3568_top_get_clk(struct rk3568_clk_priv *priv, ulong clk_id) > +{ > + struct rk3568_cru *cru = priv->cru; > + u32 con, sel, rate; > + > + switch (clk_id) { > + case ACLK_TOP_HIGH: > + con = readl(&cru->clksel_con[73]); > + sel = (con & ACLK_TOP_HIGH_SEL_MASK) >> ACLK_TOP_HIGH_SEL_SHIFT; > + if (sel == ACLK_TOP_HIGH_SEL_500M) > + rate = 500 * MHz; > + else if (sel == ACLK_TOP_HIGH_SEL_400M) > + rate = 400 * MHz; > + else if (sel == ACLK_TOP_HIGH_SEL_300M) > + rate = 300 * MHz; > + else > + rate = OSC_HZ; > + break; > + case ACLK_TOP_LOW: > + con = readl(&cru->clksel_con[73]); > + sel = (con & ACLK_TOP_LOW_SEL_MASK) >> ACLK_TOP_LOW_SEL_SHIFT; > + if (sel == ACLK_TOP_LOW_SEL_400M) > + rate = 400 * MHz; > + else if (sel == ACLK_TOP_LOW_SEL_300M) > + rate = 300 * MHz; > + else if (sel == ACLK_TOP_LOW_SEL_200M) > + rate = 200 * MHz; > + else > + rate = OSC_HZ; > + break; > + case HCLK_TOP: > + con = readl(&cru->clksel_con[73]); > + sel = (con & HCLK_TOP_SEL_MASK) >> HCLK_TOP_SEL_SHIFT; > + if (sel == HCLK_TOP_SEL_150M) > + rate = 150 * MHz; > + else if (sel == HCLK_TOP_SEL_100M) > + rate = 100 * MHz; > + else if (sel == HCLK_TOP_SEL_75M) > + rate = 75 * MHz; > + else > + rate = OSC_HZ; > + break; > + case PCLK_TOP: > + con = readl(&cru->clksel_con[73]); > + sel = (con & PCLK_TOP_SEL_MASK) >> PCLK_TOP_SEL_SHIFT; > + if (sel == PCLK_TOP_SEL_100M) > + rate = 100 * MHz; > + else if (sel == PCLK_TOP_SEL_75M) > + rate = 75 * MHz; > + else if (sel == PCLK_TOP_SEL_50M) > + rate = 50 * MHz; > + else > + rate = OSC_HZ; > + break; > + default: > + return -ENOENT; > + } > + > + return rate; > +} > + > +static ulong rk3568_top_set_clk(struct rk3568_clk_priv *priv, > + ulong clk_id, ulong rate) > +{ > + struct rk3568_cru *cru = priv->cru; > + int src_clk; > + > + switch (clk_id) { > + case ACLK_TOP_HIGH: > + if (rate == 500 * MHz) > + src_clk = ACLK_TOP_HIGH_SEL_500M; > + else if (rate == 400 * MHz) > + src_clk = ACLK_TOP_HIGH_SEL_400M; > + else if (rate == 300 * MHz) > + src_clk = ACLK_TOP_HIGH_SEL_300M; > + else > + src_clk = ACLK_TOP_HIGH_SEL_24M; > + rk_clrsetreg(&cru->clksel_con[73], > + ACLK_TOP_HIGH_SEL_MASK, > + src_clk << ACLK_TOP_HIGH_SEL_SHIFT); > + break; > + case ACLK_TOP_LOW: > + if (rate == 400 * MHz) > + src_clk = ACLK_TOP_LOW_SEL_400M; > + else if (rate == 300 * MHz) > + src_clk = ACLK_TOP_LOW_SEL_300M; > + else if (rate == 200 * MHz) > + src_clk = ACLK_TOP_LOW_SEL_200M; > + else > + src_clk = ACLK_TOP_LOW_SEL_24M; > + rk_clrsetreg(&cru->clksel_con[73], > + ACLK_TOP_LOW_SEL_MASK, > + src_clk << ACLK_TOP_LOW_SEL_SHIFT); > + break; > + case HCLK_TOP: > + if (rate == 150 * MHz) > + src_clk = HCLK_TOP_SEL_150M; > + else if (rate == 100 * MHz) > + src_clk = HCLK_TOP_SEL_100M; > + else if (rate == 75 * MHz) > + src_clk = HCLK_TOP_SEL_75M; > + else > + src_clk = HCLK_TOP_SEL_24M; > + rk_clrsetreg(&cru->clksel_con[73], > + HCLK_TOP_SEL_MASK, > + src_clk << HCLK_TOP_SEL_SHIFT); > + break; > + case PCLK_TOP: > + if (rate == 100 * MHz) > + src_clk = PCLK_TOP_SEL_100M; > + else if (rate == 75 * MHz) > + src_clk = PCLK_TOP_SEL_75M; > + else if (rate == 50 * MHz) > + src_clk = PCLK_TOP_SEL_50M; > + else > + src_clk = PCLK_TOP_SEL_24M; > + rk_clrsetreg(&cru->clksel_con[73], > + PCLK_TOP_SEL_MASK, > + src_clk << PCLK_TOP_SEL_SHIFT); > + break; > + > + default: > + printf("do not support this permid freq\n"); > + return -EINVAL; > + } > + > + return rk3568_top_get_clk(priv, clk_id); > +} > + > +static ulong rk3568_i2c_get_clk(struct rk3568_clk_priv *priv, ulong clk_id) > +{ > + struct rk3568_cru *cru = priv->cru; > + u32 sel, con; > + ulong rate; > + > + switch (clk_id) { > + case CLK_I2C1: > + case CLK_I2C2: > + case CLK_I2C3: > + case CLK_I2C4: > + case CLK_I2C5: > + con = readl(&cru->clksel_con[71]); > + sel = (con & CLK_I2C_SEL_MASK) >> CLK_I2C_SEL_SHIFT; > + if (sel == CLK_I2C_SEL_200M) > + rate = 200 * MHz; > + else if (sel == CLK_I2C_SEL_100M) > + rate = 100 * MHz; > + else if (sel == CLK_I2C_SEL_CPLL_100M) > + rate = 100 * MHz; > + else > + rate = OSC_HZ; > + break; > + default: > + return -ENOENT; > + } > + > + return rate; > +} > + > +static ulong rk3568_i2c_set_clk(struct rk3568_clk_priv *priv, ulong clk_id, > + ulong rate) > +{ > + struct rk3568_cru *cru = priv->cru; > + int src_clk; > + > + if (rate == 200 * MHz) > + src_clk = CLK_I2C_SEL_200M; > + else if (rate == 100 * MHz) > + src_clk = CLK_I2C_SEL_100M; > + else > + src_clk = CLK_I2C_SEL_24M; > + > + switch (clk_id) { > + case CLK_I2C1: > + case CLK_I2C2: > + case CLK_I2C3: > + case CLK_I2C4: > + case CLK_I2C5: > + rk_clrsetreg(&cru->clksel_con[71], CLK_I2C_SEL_MASK, > + src_clk << CLK_I2C_SEL_SHIFT); > + break; > + default: > + return -ENOENT; > + } > + > + return rk3568_i2c_get_clk(priv, clk_id); > +} > + > +static ulong rk3568_spi_get_clk(struct rk3568_clk_priv *priv, ulong clk_id) > +{ > + struct rk3568_cru *cru = priv->cru; > + u32 sel, con; > + > + con = readl(&cru->clksel_con[72]); > + > + switch (clk_id) { > + case CLK_SPI0: > + sel = (con & CLK_SPI0_SEL_MASK) >> CLK_SPI0_SEL_SHIFT; > + break; > + case CLK_SPI1: > + sel = (con & CLK_SPI1_SEL_MASK) >> CLK_SPI1_SEL_SHIFT; > + break; > + case CLK_SPI2: > + sel = (con & CLK_SPI2_SEL_MASK) >> CLK_SPI2_SEL_SHIFT; > + break; > + case CLK_SPI3: > + sel = (con & CLK_SPI3_SEL_MASK) >> CLK_SPI3_SEL_SHIFT; > + break; > + default: > + return -ENOENT; > + } > + > + switch (sel) { > + case CLK_SPI_SEL_200M: > + return 200 * MHz; > + case CLK_SPI_SEL_24M: > + return OSC_HZ; > + case CLK_SPI_SEL_CPLL_100M: > + return 100 * MHz; > + default: > + return -ENOENT; > + } > +} > + > +static ulong rk3568_spi_set_clk(struct rk3568_clk_priv *priv, > + ulong clk_id, ulong rate) > +{ > + struct rk3568_cru *cru = priv->cru; > + int src_clk; > + > + if (rate == 200 * MHz) > + src_clk = CLK_SPI_SEL_200M; > + else if (rate == 100 * MHz) > + src_clk = CLK_SPI_SEL_CPLL_100M; > + else > + src_clk = CLK_SPI_SEL_24M; > + > + switch (clk_id) { > + case CLK_SPI0: > + rk_clrsetreg(&cru->clksel_con[72], > + CLK_SPI0_SEL_MASK, > + src_clk << CLK_SPI0_SEL_SHIFT); > + break; > + case CLK_SPI1: > + rk_clrsetreg(&cru->clksel_con[72], > + CLK_SPI1_SEL_MASK, > + src_clk << CLK_SPI1_SEL_SHIFT); > + break; > + case CLK_SPI2: > + rk_clrsetreg(&cru->clksel_con[72], > + CLK_SPI2_SEL_MASK, > + src_clk << CLK_SPI2_SEL_SHIFT); > + break; > + case CLK_SPI3: > + rk_clrsetreg(&cru->clksel_con[72], > + CLK_SPI3_SEL_MASK, > + src_clk << CLK_SPI3_SEL_SHIFT); > + break; > + default: > + return -ENOENT; > + } > + > + return rk3568_spi_get_clk(priv, clk_id); > +} > + > +static ulong rk3568_pwm_get_clk(struct rk3568_clk_priv *priv, ulong clk_id) > +{ > + struct rk3568_cru *cru = priv->cru; > + u32 sel, con; > + > + con = readl(&cru->clksel_con[72]); > + > + switch (clk_id) { > + case CLK_PWM1: > + sel = (con & CLK_PWM1_SEL_MASK) >> CLK_PWM3_SEL_SHIFT; > + break; > + case CLK_PWM2: > + sel = (con & CLK_PWM2_SEL_MASK) >> CLK_PWM2_SEL_SHIFT; > + break; > + case CLK_PWM3: > + sel = (con & CLK_PWM3_SEL_MASK) >> CLK_PWM3_SEL_SHIFT; > + break; > + default: > + return -ENOENT; > + } > + > + switch (sel) { > + case CLK_PWM_SEL_100M: > + return 100 * MHz; > + case CLK_PWM_SEL_24M: > + return OSC_HZ; > + case CLK_PWM_SEL_CPLL_100M: > + return 100 * MHz; > + default: > + return -ENOENT; > + } > +} > + > +static ulong rk3568_pwm_set_clk(struct rk3568_clk_priv *priv, > + ulong clk_id, ulong rate) > +{ > + struct rk3568_cru *cru = priv->cru; > + int src_clk; > + > + if (rate == 100 * MHz) > + src_clk = CLK_PWM_SEL_100M; > + else > + src_clk = CLK_PWM_SEL_24M; > + > + switch (clk_id) { > + case CLK_PWM1: > + rk_clrsetreg(&cru->clksel_con[72], > + CLK_PWM1_SEL_MASK, > + src_clk << CLK_PWM1_SEL_SHIFT); > + break; > + case CLK_PWM2: > + rk_clrsetreg(&cru->clksel_con[72], > + CLK_PWM2_SEL_MASK, > + src_clk << CLK_PWM2_SEL_SHIFT); > + break; > + case CLK_PWM3: > + rk_clrsetreg(&cru->clksel_con[72], > + CLK_PWM3_SEL_MASK, > + src_clk << CLK_PWM3_SEL_SHIFT); > + break; > + default: > + return -ENOENT; > + } > + > + return rk3568_pwm_get_clk(priv, clk_id); > +} > + > +static ulong rk3568_adc_get_clk(struct rk3568_clk_priv *priv, ulong clk_id) > +{ > + struct rk3568_cru *cru = priv->cru; > + u32 div, sel, con, prate; > + > + switch (clk_id) { > + case CLK_SARADC: > + return OSC_HZ; > + case CLK_TSADC_TSEN: > + con = readl(&cru->clksel_con[51]); > + div = (con & CLK_TSADC_TSEN_DIV_MASK) >> > + CLK_TSADC_TSEN_DIV_SHIFT; > + sel = (con & CLK_TSADC_TSEN_SEL_MASK) >> > + CLK_TSADC_TSEN_SEL_SHIFT; > + if (sel == CLK_TSADC_TSEN_SEL_24M) > + prate = OSC_HZ; > + else > + prate = 100 * MHz; > + return DIV_TO_RATE(prate, div); > + case CLK_TSADC: > + con = readl(&cru->clksel_con[51]); > + div = (con & CLK_TSADC_DIV_MASK) >> CLK_TSADC_DIV_SHIFT; > + prate = rk3568_adc_get_clk(priv, CLK_TSADC_TSEN); > + return DIV_TO_RATE(prate, div); > + default: > + return -ENOENT; > + } > +} > + > +static ulong rk3568_adc_set_clk(struct rk3568_clk_priv *priv, > + ulong clk_id, ulong rate) > +{ > + struct rk3568_cru *cru = priv->cru; > + int src_clk_div; > + ulong prate = 0; > + > + switch (clk_id) { > + case CLK_SARADC: > + return OSC_HZ; > + case CLK_TSADC_TSEN: > + if (!(OSC_HZ % rate)) { > + src_clk_div = DIV_ROUND_UP(OSC_HZ, rate); > + assert(src_clk_div - 1 <= 7); > + rk_clrsetreg(&cru->clksel_con[51], > + CLK_TSADC_TSEN_SEL_MASK | > + CLK_TSADC_TSEN_DIV_MASK, > + (CLK_TSADC_TSEN_SEL_24M << > + CLK_TSADC_TSEN_SEL_SHIFT) | > + (src_clk_div - 1) << > + CLK_TSADC_TSEN_DIV_SHIFT); > + } else { > + src_clk_div = DIV_ROUND_UP(100 * MHz, rate); > + assert(src_clk_div - 1 <= 7); > + rk_clrsetreg(&cru->clksel_con[51], > + CLK_TSADC_TSEN_SEL_MASK | > + CLK_TSADC_TSEN_DIV_MASK, > + (CLK_TSADC_TSEN_SEL_100M << > + CLK_TSADC_TSEN_SEL_SHIFT) | > + (src_clk_div - 1) << > + CLK_TSADC_TSEN_DIV_SHIFT); > + } > + break; > + case CLK_TSADC: > + prate = rk3568_adc_get_clk(priv, CLK_TSADC_TSEN); > + src_clk_div = DIV_ROUND_UP(prate, rate); > + assert(src_clk_div - 1 <= 128); > + rk_clrsetreg(&cru->clksel_con[51], > + CLK_TSADC_DIV_MASK, > + (src_clk_div - 1) << CLK_TSADC_DIV_SHIFT); > + break; > + default: > + return -ENOENT; > + } > + return rk3568_adc_get_clk(priv, clk_id); > +} > + > +static ulong rk3568_crypto_get_rate(struct rk3568_clk_priv *priv, ulong clk_id) > +{ > + struct rk3568_cru *cru = priv->cru; > + u32 sel, con; > + > + switch (clk_id) { > + case ACLK_SECURE_FLASH: > + case ACLK_CRYPTO_NS: > + con = readl(&cru->clksel_con[27]); > + sel = (con & ACLK_SECURE_FLASH_SEL_MASK) >> > + ACLK_SECURE_FLASH_SEL_SHIFT; > + if (sel == ACLK_SECURE_FLASH_SEL_200M) > + return 200 * MHz; > + else if (sel == ACLK_SECURE_FLASH_SEL_150M) > + return 150 * MHz; > + else if (sel == ACLK_SECURE_FLASH_SEL_100M) > + return 100 * MHz; > + else > + return 24 * MHz; > + case HCLK_SECURE_FLASH: > + case HCLK_CRYPTO_NS: > + case CLK_CRYPTO_NS_RNG: > + con = readl(&cru->clksel_con[27]); > + sel = (con & HCLK_SECURE_FLASH_SEL_MASK) >> > + HCLK_SECURE_FLASH_SEL_SHIFT; > + if (sel == HCLK_SECURE_FLASH_SEL_150M) > + return 150 * MHz; > + else if (sel == HCLK_SECURE_FLASH_SEL_100M) > + return 100 * MHz; > + else if (sel == HCLK_SECURE_FLASH_SEL_75M) > + return 75 * MHz; > + else > + return 24 * MHz; > + case CLK_CRYPTO_NS_CORE: > + con = readl(&cru->clksel_con[27]); > + sel = (con & CLK_CRYPTO_CORE_SEL_MASK) >> > + CLK_CRYPTO_CORE_SEL_SHIFT; > + if (sel == CLK_CRYPTO_CORE_SEL_200M) > + return 200 * MHz; > + else if (sel == CLK_CRYPTO_CORE_SEL_150M) > + return 150 * MHz; > + else > + return 100 * MHz; > + case CLK_CRYPTO_NS_PKA: > + con = readl(&cru->clksel_con[27]); > + sel = (con & CLK_CRYPTO_PKA_SEL_MASK) >> > + CLK_CRYPTO_PKA_SEL_SHIFT; > + if (sel == CLK_CRYPTO_PKA_SEL_300M) > + return 300 * MHz; > + else if (sel == CLK_CRYPTO_PKA_SEL_200M) > + return 200 * MHz; > + else > + return 100 * MHz; > + default: > + return -ENOENT; > + } > +} > + > +static ulong rk3568_crypto_set_rate(struct rk3568_clk_priv *priv, > + ulong clk_id, ulong rate) > +{ > + struct rk3568_cru *cru = priv->cru; > + u32 src_clk, mask, shift; > + > + switch (clk_id) { > + case ACLK_SECURE_FLASH: > + case ACLK_CRYPTO_NS: > + mask = ACLK_SECURE_FLASH_SEL_MASK; > + shift = ACLK_SECURE_FLASH_SEL_SHIFT; > + if (rate == 200 * MHz) > + src_clk = ACLK_SECURE_FLASH_SEL_200M; > + else if (rate == 150 * MHz) > + src_clk = ACLK_SECURE_FLASH_SEL_150M; > + else if (rate == 100 * MHz) > + src_clk = ACLK_SECURE_FLASH_SEL_100M; > + else > + src_clk = ACLK_SECURE_FLASH_SEL_24M; > + break; > + case HCLK_SECURE_FLASH: > + case HCLK_CRYPTO_NS: > + case CLK_CRYPTO_NS_RNG: > + mask = HCLK_SECURE_FLASH_SEL_MASK; > + shift = HCLK_SECURE_FLASH_SEL_SHIFT; > + if (rate == 150 * MHz) > + src_clk = HCLK_SECURE_FLASH_SEL_150M; > + else if (rate == 100 * MHz) > + src_clk = HCLK_SECURE_FLASH_SEL_100M; > + else if (rate == 75 * MHz) > + src_clk = HCLK_SECURE_FLASH_SEL_75M; > + else > + src_clk = HCLK_SECURE_FLASH_SEL_24M; > + break; > + case CLK_CRYPTO_NS_CORE: > + mask = CLK_CRYPTO_CORE_SEL_MASK; > + shift = CLK_CRYPTO_CORE_SEL_SHIFT; > + if (rate == 200 * MHz) > + src_clk = CLK_CRYPTO_CORE_SEL_200M; > + else if (rate == 150 * MHz) > + src_clk = CLK_CRYPTO_CORE_SEL_150M; > + else > + src_clk = CLK_CRYPTO_CORE_SEL_100M; > + break; > + case CLK_CRYPTO_NS_PKA: > + mask = CLK_CRYPTO_PKA_SEL_MASK; > + shift = CLK_CRYPTO_PKA_SEL_SHIFT; > + if (rate == 300 * MHz) > + src_clk = CLK_CRYPTO_PKA_SEL_300M; > + else if (rate == 200 * MHz) > + src_clk = CLK_CRYPTO_PKA_SEL_200M; > + else > + src_clk = CLK_CRYPTO_PKA_SEL_100M; > + break; > + default: > + return -ENOENT; > + } > + > + rk_clrsetreg(&cru->clksel_con[27], mask, src_clk << shift); > + > + return rk3568_crypto_get_rate(priv, clk_id); > +} > + > +static ulong rk3568_sdmmc_get_clk(struct rk3568_clk_priv *priv, ulong clk_id) > +{ > + struct rk3568_cru *cru = priv->cru; > + u32 sel, con; > + > + switch (clk_id) { > + case HCLK_SDMMC0: > + case CLK_SDMMC0: > + con = readl(&cru->clksel_con[30]); > + sel = (con & CLK_SDMMC0_SEL_MASK) >> CLK_SDMMC0_SEL_SHIFT; > + break; > + case CLK_SDMMC1: > + con = readl(&cru->clksel_con[30]); > + sel = (con & CLK_SDMMC1_SEL_MASK) >> CLK_SDMMC1_SEL_SHIFT; > + break; > + case CLK_SDMMC2: > + con = readl(&cru->clksel_con[32]); > + sel = (con & CLK_SDMMC2_SEL_MASK) >> CLK_SDMMC2_SEL_SHIFT; > + break; > + default: > + return -ENOENT; > + } > + > + switch (sel) { > + case CLK_SDMMC_SEL_24M: > + return OSC_HZ; > + case CLK_SDMMC_SEL_400M: > + return 400 * MHz; > + case CLK_SDMMC_SEL_300M: > + return 300 * MHz; > + case CLK_SDMMC_SEL_100M: > + return 100 * MHz; > + case CLK_SDMMC_SEL_50M: > + return 50 * MHz; > + case CLK_SDMMC_SEL_750K: > + return 750 * KHz; > + default: > + return -ENOENT; > + } > +} > + > +static ulong rk3568_sdmmc_set_clk(struct rk3568_clk_priv *priv, > + ulong clk_id, ulong rate) > +{ > + struct rk3568_cru *cru = priv->cru; > + int src_clk; > + > + switch (rate) { > + case OSC_HZ: > + src_clk = CLK_SDMMC_SEL_24M; > + break; > + case 400 * MHz: > + src_clk = CLK_SDMMC_SEL_400M; > + break; > + case 300 * MHz: > + src_clk = CLK_SDMMC_SEL_300M; > + break; > + case 100 * MHz: > + src_clk = CLK_SDMMC_SEL_100M; > + break; > + case 52 * MHz: > + case 50 * MHz: > + src_clk = CLK_SDMMC_SEL_50M; > + break; > + case 750 * KHz: > + case 400 * KHz: > + src_clk = CLK_SDMMC_SEL_750K; > + break; > + default: > + return -ENOENT; > + } > + > + switch (clk_id) { > + case HCLK_SDMMC0: > + case CLK_SDMMC0: > + rk_clrsetreg(&cru->clksel_con[30], > + CLK_SDMMC0_SEL_MASK, > + src_clk << CLK_SDMMC0_SEL_SHIFT); > + break; > + case CLK_SDMMC1: > + rk_clrsetreg(&cru->clksel_con[30], > + CLK_SDMMC1_SEL_MASK, > + src_clk << CLK_SDMMC1_SEL_SHIFT); > + break; > + case CLK_SDMMC2: > + rk_clrsetreg(&cru->clksel_con[32], > + CLK_SDMMC2_SEL_MASK, > + src_clk << CLK_SDMMC2_SEL_SHIFT); > + break; > + default: > + return -ENOENT; > + } > + > + return rk3568_sdmmc_get_clk(priv, clk_id); > +} > + > +static ulong rk3568_sfc_get_clk(struct rk3568_clk_priv *priv) > +{ > + struct rk3568_cru *cru = priv->cru; > + u32 sel, con; > + > + con = readl(&cru->clksel_con[28]); > + sel = (con & SCLK_SFC_SEL_MASK) >> SCLK_SFC_SEL_SHIFT; > + switch (sel) { > + case SCLK_SFC_SEL_24M: > + return OSC_HZ; > + case SCLK_SFC_SEL_50M: > + return 50 * MHz; > + case SCLK_SFC_SEL_75M: > + return 75 * MHz; > + case SCLK_SFC_SEL_100M: > + return 100 * MHz; > + case SCLK_SFC_SEL_125M: > + return 125 * MHz; > + case SCLK_SFC_SEL_150M: > + return 150 * KHz; > + default: > + return -ENOENT; > + } > +} > + > +static ulong rk3568_sfc_set_clk(struct rk3568_clk_priv *priv, ulong rate) > +{ > + struct rk3568_cru *cru = priv->cru; > + int src_clk; > + > + switch (rate) { > + case OSC_HZ: > + src_clk = SCLK_SFC_SEL_24M; > + break; > + case 50 * MHz: > + src_clk = SCLK_SFC_SEL_50M; > + break; > + case 75 * MHz: > + src_clk = SCLK_SFC_SEL_75M; > + break; > + case 100 * MHz: > + src_clk = SCLK_SFC_SEL_100M; > + break; > + case 125 * MHz: > + src_clk = SCLK_SFC_SEL_125M; > + break; > + case 150 * KHz: > + src_clk = SCLK_SFC_SEL_150M; > + break; > + default: > + return -ENOENT; > + } > + > + rk_clrsetreg(&cru->clksel_con[28], > + SCLK_SFC_SEL_MASK, > + src_clk << SCLK_SFC_SEL_SHIFT); > + > + return rk3568_sfc_get_clk(priv); > +} > + > +static ulong rk3568_nand_get_clk(struct rk3568_clk_priv *priv) > +{ > + struct rk3568_cru *cru = priv->cru; > + u32 sel, con; > + > + con = readl(&cru->clksel_con[28]); > + sel = (con & NCLK_NANDC_SEL_MASK) >> NCLK_NANDC_SEL_SHIFT; > + switch (sel) { > + case NCLK_NANDC_SEL_200M: > + return 200 * MHz; > + case NCLK_NANDC_SEL_150M: > + return 150 * MHz; > + case NCLK_NANDC_SEL_100M: > + return 100 * MHz; > + case NCLK_NANDC_SEL_24M: > + return OSC_HZ; > + default: > + return -ENOENT; > + } > +} > + > +static ulong rk3568_nand_set_clk(struct rk3568_clk_priv *priv, ulong rate) > +{ > + struct rk3568_cru *cru = priv->cru; > + int src_clk; > + > + switch (rate) { > + case OSC_HZ: > + src_clk = NCLK_NANDC_SEL_24M; > + break; > + case 100 * MHz: > + src_clk = NCLK_NANDC_SEL_100M; > + break; > + case 150 * MHz: > + src_clk = NCLK_NANDC_SEL_150M; > + break; > + case 200 * MHz: > + src_clk = NCLK_NANDC_SEL_200M; > + break; > + default: > + return -ENOENT; > + } > + > + rk_clrsetreg(&cru->clksel_con[28], > + NCLK_NANDC_SEL_MASK, > + src_clk << NCLK_NANDC_SEL_SHIFT); > + > + return rk3568_nand_get_clk(priv); > +} > + > +static ulong rk3568_emmc_get_clk(struct rk3568_clk_priv *priv) > +{ > + struct rk3568_cru *cru = priv->cru; > + u32 sel, con; > + > + con = readl(&cru->clksel_con[28]); > + sel = (con & CCLK_EMMC_SEL_MASK) >> CCLK_EMMC_SEL_SHIFT; > + switch (sel) { > + case CCLK_EMMC_SEL_200M: > + return 200 * MHz; > + case CCLK_EMMC_SEL_150M: > + return 150 * MHz; > + case CCLK_EMMC_SEL_100M: > + return 100 * MHz; > + case CCLK_EMMC_SEL_50M: > + return 50 * MHz; > + case CCLK_EMMC_SEL_375K: > + return 375 * KHz; > + case CCLK_EMMC_SEL_24M: > + return OSC_HZ; > + default: > + return -ENOENT; > + } > +} > + > +static ulong rk3568_emmc_set_clk(struct rk3568_clk_priv *priv, ulong rate) > +{ > + struct rk3568_cru *cru = priv->cru; > + int src_clk; > + > + switch (rate) { > + case OSC_HZ: > + src_clk = CCLK_EMMC_SEL_24M; > + break; > + case 52 * MHz: > + case 50 * MHz: > + src_clk = CCLK_EMMC_SEL_50M; > + break; > + case 100 * MHz: > + src_clk = CCLK_EMMC_SEL_100M; > + break; > + case 150 * MHz: > + src_clk = CCLK_EMMC_SEL_150M; > + break; > + case 200 * MHz: > + src_clk = CCLK_EMMC_SEL_200M; > + break; > + case 400 * KHz: > + case 375 * KHz: > + src_clk = CCLK_EMMC_SEL_375K; > + break; > + default: > + return -ENOENT; > + } > + > + rk_clrsetreg(&cru->clksel_con[28], > + CCLK_EMMC_SEL_MASK, > + src_clk << CCLK_EMMC_SEL_SHIFT); > + > + return rk3568_emmc_get_clk(priv); > +} > + > +#ifndef CONFIG_SPL_BUILD > +static ulong rk3568_aclk_vop_get_clk(struct rk3568_clk_priv *priv) > +{ > + struct rk3568_cru *cru = priv->cru; > + u32 div, sel, con, parent; > + > + con = readl(&cru->clksel_con[38]); > + div = (con & ACLK_VOP_PRE_DIV_MASK) >> ACLK_VOP_PRE_DIV_SHIFT; > + sel = (con & ACLK_VOP_PRE_SEL_MASK) >> ACLK_VOP_PRE_SEL_SHIFT; > + if (sel == ACLK_VOP_PRE_SEL_GPLL) > + parent = priv->gpll_hz; > + else if (sel == ACLK_VOP_PRE_SEL_CPLL) > + parent = priv->cpll_hz; > + else if (sel == ACLK_VOP_PRE_SEL_VPLL) > + parent = priv->vpll_hz; > + else > + parent = priv->hpll_hz; > + > + return DIV_TO_RATE(parent, div); > +} > + > +static ulong rk3568_aclk_vop_set_clk(struct rk3568_clk_priv *priv, ulong rate) > +{ > + struct rk3568_cru *cru = priv->cru; > + int src_clk_div, src_clk_mux; > + > + if ((priv->cpll_hz % rate) == 0) { > + src_clk_div = DIV_ROUND_UP(priv->cpll_hz, rate); > + src_clk_mux = ACLK_VOP_PRE_SEL_CPLL; > + } else { > + src_clk_div = DIV_ROUND_UP(priv->gpll_hz, rate); > + src_clk_mux = ACLK_VOP_PRE_SEL_GPLL; > + } > + assert(src_clk_div - 1 <= 31); > + rk_clrsetreg(&cru->clksel_con[38], > + ACLK_VOP_PRE_SEL_MASK | ACLK_VOP_PRE_DIV_MASK, > + src_clk_mux << ACLK_VOP_PRE_SEL_SHIFT | > + (src_clk_div - 1) << ACLK_VOP_PRE_DIV_SHIFT); > + > + return rk3568_aclk_vop_get_clk(priv); > +} > + > +static ulong rk3568_dclk_vop_get_clk(struct rk3568_clk_priv *priv, ulong clk_id) > +{ > + struct rk3568_cru *cru = priv->cru; > + u32 conid, div, sel, con, parent; > + > + switch (clk_id) { > + case DCLK_VOP0: > + conid = 39; > + break; > + case DCLK_VOP1: > + conid = 40; > + break; > + case DCLK_VOP2: > + conid = 41; > + break; > + default: > + return -ENOENT; > + } > + > + con = readl(&cru->clksel_con[conid]); > + div = (con & DCLK0_VOP_DIV_MASK) >> DCLK0_VOP_DIV_SHIFT; > + sel = (con & DCLK0_VOP_SEL_MASK) >> DCLK0_VOP_SEL_SHIFT; > + if (sel == DCLK_VOP_SEL_HPLL) > + parent = rk3568_pmu_pll_get_rate(priv, HPLL); > + else if (sel == DCLK_VOP_SEL_VPLL) > + parent = rockchip_pll_get_rate(&rk3568_pll_clks[VPLL], > + priv->cru, VPLL); > + else if (sel == DCLK_VOP_SEL_GPLL) > + parent = priv->gpll_hz; > + else if (sel == DCLK_VOP_SEL_CPLL) > + parent = priv->cpll_hz; > + else > + return -ENOENT; > + > + return DIV_TO_RATE(parent, div); > +} > + > +#define RK3568_VOP_PLL_LIMIT_FREQ 600000000 > + > +static ulong rk3568_dclk_vop_set_clk(struct rk3568_clk_priv *priv, > + ulong clk_id, ulong rate) > +{ > + struct rk3568_cru *cru = priv->cru; > + ulong pll_rate, now, best_rate = 0; > + u32 i, conid, con, sel, div, best_div = 0, best_sel = 0; > + > + switch (clk_id) { > + case DCLK_VOP0: > + conid = 39; > + break; > + case DCLK_VOP1: > + conid = 40; > + break; > + case DCLK_VOP2: > + conid = 41; > + break; > + default: > + return -ENOENT; > + } > + > + con = readl(&cru->clksel_con[conid]); > + sel = (con & DCLK0_VOP_SEL_MASK) >> DCLK0_VOP_SEL_SHIFT; > + > + if (sel == DCLK_VOP_SEL_HPLL) { > + div = 1; > + rk_clrsetreg(&cru->clksel_con[conid], > + DCLK0_VOP_DIV_MASK | DCLK0_VOP_SEL_MASK, > + (DCLK_VOP_SEL_HPLL << DCLK0_VOP_SEL_SHIFT) | > + ((div - 1) << DCLK0_VOP_DIV_SHIFT)); > + rk3568_pmu_pll_set_rate(priv, HPLL, div * rate); > + } else if (sel == DCLK_VOP_SEL_VPLL) { > + div = DIV_ROUND_UP(RK3568_VOP_PLL_LIMIT_FREQ, rate); > + rk_clrsetreg(&cru->clksel_con[conid], > + DCLK0_VOP_DIV_MASK | DCLK0_VOP_SEL_MASK, > + (DCLK_VOP_SEL_VPLL << DCLK0_VOP_SEL_SHIFT) | > + ((div - 1) << DCLK0_VOP_DIV_SHIFT)); > + rockchip_pll_set_rate(&rk3568_pll_clks[VPLL], > + priv->cru, VPLL, div * rate); > + } else { > + for (i = 0; i <= DCLK_VOP_SEL_CPLL; i++) { > + switch (i) { > + case DCLK_VOP_SEL_GPLL: > + pll_rate = priv->gpll_hz; > + break; > + case DCLK_VOP_SEL_CPLL: > + pll_rate = priv->cpll_hz; > + break; > + default: > + printf("do not support this vop pll sel\n"); > + return -EINVAL; > + } > + > + div = DIV_ROUND_UP(pll_rate, rate); > + if (div > 255) > + continue; > + now = pll_rate / div; > + if (abs(rate - now) < abs(rate - best_rate)) { > + best_rate = now; > + best_div = div; > + best_sel = i; > + } > + debug("p_rate=%lu, best_rate=%lu, div=%u, sel=%u\n", > + pll_rate, best_rate, best_div, best_sel); > + } > + > + if (best_rate) { > + rk_clrsetreg(&cru->clksel_con[conid], > + DCLK0_VOP_DIV_MASK | DCLK0_VOP_SEL_MASK, > + best_sel << DCLK0_VOP_SEL_SHIFT | > + (best_div - 1) << DCLK0_VOP_DIV_SHIFT); > + } else { > + printf("do not support this vop freq %lu\n", rate); > + return -EINVAL; > + } > + } > + return rk3568_dclk_vop_get_clk(priv, clk_id); > +} > + > +static ulong rk3568_gmac_src_get_clk(struct rk3568_clk_priv *priv, > + ulong mac_id) > +{ > + struct rk3568_cru *cru = priv->cru; > + u32 sel, con; > + > + con = readl(&cru->clksel_con[31 + mac_id * 2]); > + sel = (con & CLK_MAC0_2TOP_SEL_MASK) >> CLK_MAC0_2TOP_SEL_SHIFT; > + > + switch (sel) { > + case CLK_MAC0_2TOP_SEL_125M: > + return 125 * MHz; > + case CLK_MAC0_2TOP_SEL_50M: > + return 50 * MHz; > + case CLK_MAC0_2TOP_SEL_25M: > + return 25 * MHz; > + case CLK_MAC0_2TOP_SEL_PPLL: > + return rk3568_pmu_pll_get_rate(priv, HPLL); > + default: > + return -ENOENT; > + } > +} > + > +static ulong rk3568_gmac_src_set_clk(struct rk3568_clk_priv *priv, > + ulong mac_id, ulong rate) > +{ > + struct rk3568_cru *cru = priv->cru; > + int src_clk; > + > + switch (rate) { > + case 125 * MHz: > + src_clk = CLK_MAC0_2TOP_SEL_125M; > + break; > + case 50 * MHz: > + src_clk = CLK_MAC0_2TOP_SEL_50M; > + break; > + case 25 * MHz: > + src_clk = CLK_MAC0_2TOP_SEL_25M; > + break; > + default: > + return -ENOENT; > + } > + > + rk_clrsetreg(&cru->clksel_con[31 + mac_id * 2], > + CLK_MAC0_2TOP_SEL_MASK, > + src_clk << CLK_MAC0_2TOP_SEL_SHIFT); > + > + return rk3568_gmac_src_get_clk(priv, mac_id); > +} > + > +static ulong rk3568_gmac_out_get_clk(struct rk3568_clk_priv *priv, > + ulong mac_id) > +{ > + struct rk3568_cru *cru = priv->cru; > + u32 sel, con; > + > + con = readl(&cru->clksel_con[31 + mac_id * 2]); > + sel = (con & CLK_MAC0_OUT_SEL_MASK) >> CLK_MAC0_OUT_SEL_SHIFT; > + > + switch (sel) { > + case CLK_MAC0_OUT_SEL_125M: > + return 125 * MHz; > + case CLK_MAC0_OUT_SEL_50M: > + return 50 * MHz; > + case CLK_MAC0_OUT_SEL_25M: > + return 25 * MHz; > + case CLK_MAC0_OUT_SEL_24M: > + return OSC_HZ; > + default: > + return -ENOENT; > + } > +} > + > +static ulong rk3568_gmac_out_set_clk(struct rk3568_clk_priv *priv, > + ulong mac_id, ulong rate) > +{ > + struct rk3568_cru *cru = priv->cru; > + int src_clk; > + > + switch (rate) { > + case 125 * MHz: > + src_clk = CLK_MAC0_OUT_SEL_125M; > + break; > + case 50 * MHz: > + src_clk = CLK_MAC0_OUT_SEL_50M; > + break; > + case 25 * MHz: > + src_clk = CLK_MAC0_OUT_SEL_25M; > + break; > + case 24 * MHz: > + src_clk = CLK_MAC0_OUT_SEL_24M; > + break; > + default: > + return -ENOENT; > + } > + > + rk_clrsetreg(&cru->clksel_con[31 + mac_id * 2], > + CLK_MAC0_OUT_SEL_MASK, > + src_clk << CLK_MAC0_OUT_SEL_SHIFT); > + > + return rk3568_gmac_out_get_clk(priv, mac_id); > +} > + > +static ulong rk3568_gmac_ptp_ref_get_clk(struct rk3568_clk_priv *priv, > + ulong mac_id) > +{ > + struct rk3568_cru *cru = priv->cru; > + u32 sel, con; > + > + con = readl(&cru->clksel_con[31 + mac_id * 2]); > + sel = (con & CLK_GMAC0_PTP_REF_SEL_MASK) >> CLK_GMAC0_PTP_REF_SEL_SHIFT; > + > + switch (sel) { > + case CLK_GMAC0_PTP_REF_SEL_62_5M: > + return 62500 * KHz; > + case CLK_GMAC0_PTP_REF_SEL_100M: > + return 100 * MHz; > + case CLK_GMAC0_PTP_REF_SEL_50M: > + return 50 * MHz; > + case CLK_GMAC0_PTP_REF_SEL_24M: > + return OSC_HZ; > + default: > + return -ENOENT; > + } > +} > + > +static ulong rk3568_gmac_ptp_ref_set_clk(struct rk3568_clk_priv *priv, > + ulong mac_id, ulong rate) > +{ > + struct rk3568_cru *cru = priv->cru; > + int src_clk; > + > + switch (rate) { > + case 62500 * KHz: > + src_clk = CLK_GMAC0_PTP_REF_SEL_62_5M; > + break; > + case 100 * MHz: > + src_clk = CLK_GMAC0_PTP_REF_SEL_100M; > + break; > + case 50 * MHz: > + src_clk = CLK_GMAC0_PTP_REF_SEL_50M; > + break; > + case 24 * MHz: > + src_clk = CLK_GMAC0_PTP_REF_SEL_24M; > + break; > + default: > + return -ENOENT; > + } > + > + rk_clrsetreg(&cru->clksel_con[31 + mac_id * 2], > + CLK_GMAC0_PTP_REF_SEL_MASK, > + src_clk << CLK_GMAC0_PTP_REF_SEL_SHIFT); > + > + return rk3568_gmac_ptp_ref_get_clk(priv, mac_id); > +} > + > +static ulong rk3568_gmac_tx_rx_set_clk(struct rk3568_clk_priv *priv, > + ulong mac_id, ulong rate) > +{ > + struct rk3568_cru *cru = priv->cru; > + u32 con, sel, div_sel; > + > + con = readl(&cru->clksel_con[31 + mac_id * 2]); > + sel = (con & RMII0_MODE_MASK) >> RMII0_MODE_SHIFT; > + > + if (sel == RMII0_MODE_SEL_RGMII) { > + if (rate == 2500000) > + div_sel = RGMII0_CLK_SEL_2_5M; > + else if (rate == 25000000) > + div_sel = RGMII0_CLK_SEL_25M; > + else > + div_sel = RGMII0_CLK_SEL_125M; > + rk_clrsetreg(&cru->clksel_con[31 + mac_id * 2], > + RGMII0_CLK_SEL_MASK, > + div_sel << RGMII0_CLK_SEL_SHIFT); > + } else if (sel == RMII0_MODE_SEL_RMII) { > + if (rate == 2500000) > + div_sel = RMII0_CLK_SEL_2_5M; > + else > + div_sel = RMII0_CLK_SEL_25M; > + rk_clrsetreg(&cru->clksel_con[31 + mac_id * 2], > + RMII0_CLK_SEL_MASK, > + div_sel << RMII0_CLK_SEL_SHIFT); > + } > + > + return 0; > +} > + > +static ulong rk3568_ebc_get_clk(struct rk3568_clk_priv *priv) > +{ > + struct rk3568_cru *cru = priv->cru; > + u32 con, div, p_rate; > + > + con = readl(&cru->clksel_con[79]); > + div = (con & CPLL_333M_DIV_MASK) >> CPLL_333M_DIV_SHIFT; > + p_rate = DIV_TO_RATE(priv->cpll_hz, div); > + > + con = readl(&cru->clksel_con[43]); > + div = (con & DCLK_EBC_SEL_MASK) >> DCLK_EBC_SEL_SHIFT; > + switch (div) { > + case DCLK_EBC_SEL_GPLL_400M: > + return 400 * MHz; > + case DCLK_EBC_SEL_CPLL_333M: > + return p_rate; > + case DCLK_EBC_SEL_GPLL_200M: > + return 200 * MHz; > + default: > + return -ENOENT; > + } > +} > + > +static ulong rk3568_ebc_set_clk(struct rk3568_clk_priv *priv, ulong rate) > +{ > + struct rk3568_cru *cru = priv->cru; > + int src_clk_div; > + > + src_clk_div = DIV_ROUND_UP(priv->cpll_hz, rate); > + assert(src_clk_div - 1 <= 31); > + rk_clrsetreg(&cru->clksel_con[79], > + CPLL_333M_DIV_MASK, > + (src_clk_div - 1) << CPLL_333M_DIV_SHIFT); > + rk_clrsetreg(&cru->clksel_con[43], > + DCLK_EBC_SEL_MASK, > + DCLK_EBC_SEL_CPLL_333M << DCLK_EBC_SEL_SHIFT); > + > + return rk3568_ebc_get_clk(priv); > +} > + > +static ulong rk3568_rkvdec_get_clk(struct rk3568_clk_priv *priv, ulong clk_id) > +{ > + struct rk3568_cru *cru = priv->cru; > + u32 con, div, src, p_rate; > + > + switch (clk_id) { > + case ACLK_RKVDEC_PRE: > + case ACLK_RKVDEC: > + con = readl(&cru->clksel_con[47]); > + src = (con & ACLK_RKVDEC_SEL_MASK) >> ACLK_RKVDEC_SEL_SHIFT; > + div = (con & ACLK_RKVDEC_DIV_MASK) >> ACLK_RKVDEC_DIV_SHIFT; > + if (src == ACLK_RKVDEC_SEL_CPLL) > + p_rate = priv->cpll_hz; > + else > + p_rate = priv->gpll_hz; > + return DIV_TO_RATE(p_rate, div); > + case CLK_RKVDEC_CORE: > + con = readl(&cru->clksel_con[49]); > + src = (con & CLK_RKVDEC_CORE_SEL_MASK) > + >> CLK_RKVDEC_CORE_SEL_SHIFT; > + div = (con & CLK_RKVDEC_CORE_DIV_MASK) > + >> CLK_RKVDEC_CORE_DIV_SHIFT; > + if (src == CLK_RKVDEC_CORE_SEL_CPLL) > + p_rate = priv->cpll_hz; > + else if (src == CLK_RKVDEC_CORE_SEL_NPLL) > + p_rate = priv->npll_hz; > + else if (src == CLK_RKVDEC_CORE_SEL_VPLL) > + p_rate = priv->vpll_hz; > + else > + p_rate = priv->gpll_hz; > + return DIV_TO_RATE(p_rate, div); > + default: > + return -ENOENT; > + } > +} > + > +static ulong rk3568_rkvdec_set_clk(struct rk3568_clk_priv *priv, > + ulong clk_id, ulong rate) > +{ > + struct rk3568_cru *cru = priv->cru; > + int src_clk_div, src, p_rate; > + > + switch (clk_id) { > + case ACLK_RKVDEC_PRE: > + case ACLK_RKVDEC: > + src = (readl(&cru->clksel_con[47]) & ACLK_RKVDEC_SEL_MASK) > + >> ACLK_RKVDEC_SEL_SHIFT; > + if (src == ACLK_RKVDEC_SEL_CPLL) > + p_rate = priv->cpll_hz; > + else > + p_rate = priv->gpll_hz; > + src_clk_div = DIV_ROUND_UP(p_rate, rate); > + assert(src_clk_div - 1 <= 31); > + rk_clrsetreg(&cru->clksel_con[47], > + ACLK_RKVDEC_SEL_MASK | > + ACLK_RKVDEC_DIV_MASK, > + (src << ACLK_RKVDEC_SEL_SHIFT) | > + (src_clk_div - 1) << ACLK_RKVDEC_DIV_SHIFT); > + break; > + case CLK_RKVDEC_CORE: > + src = (readl(&cru->clksel_con[49]) & CLK_RKVDEC_CORE_SEL_MASK) > + >> CLK_RKVDEC_CORE_SEL_SHIFT; > + if (src == CLK_RKVDEC_CORE_SEL_CPLL) > + p_rate = priv->cpll_hz; > + else if (src == CLK_RKVDEC_CORE_SEL_NPLL) > + p_rate = priv->npll_hz; > + else if (src == CLK_RKVDEC_CORE_SEL_VPLL) > + p_rate = priv->vpll_hz; > + else > + p_rate = priv->gpll_hz; > + src_clk_div = DIV_ROUND_UP(p_rate, rate); > + assert(src_clk_div - 1 <= 31); > + rk_clrsetreg(&cru->clksel_con[49], > + CLK_RKVDEC_CORE_SEL_MASK | > + CLK_RKVDEC_CORE_DIV_MASK, > + (src << CLK_RKVDEC_CORE_SEL_SHIFT) | > + (src_clk_div - 1) << CLK_RKVDEC_CORE_DIV_SHIFT); > + break; > + default: > + return -ENOENT; > + } > + > + return rk3568_rkvdec_get_clk(priv, clk_id); > +} > + > +static ulong rk3568_uart_get_rate(struct rk3568_clk_priv *priv, ulong clk_id) > +{ > + struct rk3568_cru *cru = priv->cru; > + u32 reg, con, fracdiv, div, src, p_src, p_rate; > + unsigned long m, n; > + > + switch (clk_id) { > + case SCLK_UART1: > + reg = 52; > + break; > + case SCLK_UART2: > + reg = 54; > + break; > + case SCLK_UART3: > + reg = 56; > + break; > + case SCLK_UART4: > + reg = 58; > + break; > + case SCLK_UART5: > + reg = 60; > + break; > + case SCLK_UART6: > + reg = 62; > + break; > + case SCLK_UART7: > + reg = 64; > + break; > + case SCLK_UART8: > + reg = 66; > + break; > + case SCLK_UART9: > + reg = 68; > + break; > + default: > + return -ENOENT; > + } > + con = readl(&cru->clksel_con[reg]); > + src = (con & CLK_UART_SEL_MASK) >> CLK_UART_SEL_SHIFT; > + div = (con & CLK_UART_SRC_DIV_MASK) >> CLK_UART_SRC_DIV_SHIFT; > + p_src = (con & CLK_UART_SRC_SEL_MASK) >> CLK_UART_SRC_SEL_SHIFT; > + if (p_src == CLK_UART_SRC_SEL_GPLL) > + p_rate = priv->gpll_hz; > + else if (p_src == CLK_UART_SRC_SEL_CPLL) > + p_rate = priv->cpll_hz; > + else > + p_rate = 480000000; > + if (src == CLK_UART_SEL_SRC) { > + return DIV_TO_RATE(p_rate, div); > + } else if (src == CLK_UART_SEL_FRAC) { > + fracdiv = readl(&cru->clksel_con[reg + 1]); > + n = fracdiv & CLK_UART_FRAC_NUMERATOR_MASK; > + n >>= CLK_UART_FRAC_NUMERATOR_SHIFT; > + m = fracdiv & CLK_UART_FRAC_DENOMINATOR_MASK; > + m >>= CLK_UART_FRAC_DENOMINATOR_SHIFT; > + return DIV_TO_RATE(p_rate, div) * n / m; > + } else { > + return OSC_HZ; > + } > +} > + > +static ulong rk3568_uart_set_rate(struct rk3568_clk_priv *priv, > + ulong clk_id, ulong rate) > +{ > + struct rk3568_cru *cru = priv->cru; > + u32 reg, clk_src, uart_src, div; > + unsigned long m = 0, n = 0, val; > + > + if (priv->gpll_hz % rate == 0) { > + clk_src = CLK_UART_SRC_SEL_GPLL; > + uart_src = CLK_UART_SEL_SRC; > + div = DIV_ROUND_UP(priv->gpll_hz, rate); > + } else if (priv->cpll_hz % rate == 0) { > + clk_src = CLK_UART_SRC_SEL_CPLL; > + uart_src = CLK_UART_SEL_SRC; > + div = DIV_ROUND_UP(priv->gpll_hz, rate); > + } else if (rate == OSC_HZ) { > + clk_src = CLK_UART_SRC_SEL_GPLL; > + uart_src = CLK_UART_SEL_XIN24M; > + div = 2; > + } else { > + clk_src = CLK_UART_SRC_SEL_GPLL; > + uart_src = CLK_UART_SEL_FRAC; > + div = 2; > + rational_best_approximation(rate, priv->gpll_hz / div, > + GENMASK(16 - 1, 0), > + GENMASK(16 - 1, 0), > + &m, &n); > + } > + > + switch (clk_id) { > + case SCLK_UART1: > + reg = 52; > + break; > + case SCLK_UART2: > + reg = 54; > + break; > + case SCLK_UART3: > + reg = 56; > + break; > + case SCLK_UART4: > + reg = 58; > + break; > + case SCLK_UART5: > + reg = 60; > + break; > + case SCLK_UART6: > + reg = 62; > + break; > + case SCLK_UART7: > + reg = 64; > + break; > + case SCLK_UART8: > + reg = 66; > + break; > + case SCLK_UART9: > + reg = 68; > + break; > + default: > + return -ENOENT; > + } > + rk_clrsetreg(&cru->clksel_con[reg], > + CLK_UART_SEL_MASK | CLK_UART_SRC_SEL_MASK | > + CLK_UART_SRC_DIV_MASK, > + (clk_src << CLK_UART_SRC_SEL_SHIFT) | > + (uart_src << CLK_UART_SEL_SHIFT) | > + ((div - 1) << CLK_UART_SRC_DIV_SHIFT)); > + if (m && n) { > + val = m << CLK_UART_FRAC_NUMERATOR_SHIFT | n; > + writel(val, &cru->clksel_con[reg + 1]); > + } > + > + return rk3568_uart_get_rate(priv, clk_id); > +} > +#endif > + > +static ulong rk3568_clk_get_rate(struct clk *clk) > +{ > + struct rk3568_clk_priv *priv = dev_get_priv(clk->dev); > + ulong rate = 0; > + > + if (!priv->gpll_hz) { > + printf("%s gpll=%lu\n", __func__, priv->gpll_hz); > + return -ENOENT; > + } > + > + switch (clk->id) { > + case PLL_APLL: > + case ARMCLK: > + rate = rockchip_pll_get_rate(&rk3568_pll_clks[APLL], priv->cru, > + APLL); > + break; > + case PLL_CPLL: > + rate = rockchip_pll_get_rate(&rk3568_pll_clks[CPLL], priv->cru, > + CPLL); > + break; > + case PLL_GPLL: > + rate = rockchip_pll_get_rate(&rk3568_pll_clks[GPLL], priv->cru, > + GPLL); > + break; > + case PLL_NPLL: > + rate = rockchip_pll_get_rate(&rk3568_pll_clks[NPLL], priv->cru, > + NPLL); > + break; > + case PLL_VPLL: > + rate = rockchip_pll_get_rate(&rk3568_pll_clks[VPLL], priv->cru, > + VPLL); > + break; > + case PLL_DPLL: > + rate = rockchip_pll_get_rate(&rk3568_pll_clks[DPLL], priv->cru, > + DPLL); > + break; > + case ACLK_BUS: > + case PCLK_BUS: > + case PCLK_WDT_NS: > + rate = rk3568_bus_get_clk(priv, clk->id); > + break; > + case ACLK_PERIMID: > + case HCLK_PERIMID: > + rate = rk3568_perimid_get_clk(priv, clk->id); > + break; > + case ACLK_TOP_HIGH: > + case ACLK_TOP_LOW: > + case HCLK_TOP: > + case PCLK_TOP: > + rate = rk3568_top_get_clk(priv, clk->id); > + break; > + case CLK_I2C1: > + case CLK_I2C2: > + case CLK_I2C3: > + case CLK_I2C4: > + case CLK_I2C5: > + rate = rk3568_i2c_get_clk(priv, clk->id); > + break; > + case CLK_SPI0: > + case CLK_SPI1: > + case CLK_SPI2: > + case CLK_SPI3: > + rate = rk3568_spi_get_clk(priv, clk->id); > + break; > + case CLK_PWM1: > + case CLK_PWM2: > + case CLK_PWM3: > + rate = rk3568_pwm_get_clk(priv, clk->id); > + break; > + case CLK_SARADC: > + case CLK_TSADC_TSEN: > + case CLK_TSADC: > + rate = rk3568_adc_get_clk(priv, clk->id); > + break; > + case HCLK_SDMMC0: > + case CLK_SDMMC0: > + case CLK_SDMMC1: > + case CLK_SDMMC2: > + rate = rk3568_sdmmc_get_clk(priv, clk->id); > + break; > + case SCLK_SFC: > + rate = rk3568_sfc_get_clk(priv); > + break; > + case NCLK_NANDC: > + rate = rk3568_nand_get_clk(priv); > + break; > + case CCLK_EMMC: > + rate = rk3568_emmc_get_clk(priv); > + break; > +#ifndef CONFIG_SPL_BUILD > + case ACLK_VOP: > + rate = rk3568_aclk_vop_get_clk(priv); > + break; > + case DCLK_VOP0: > + case DCLK_VOP1: > + case DCLK_VOP2: > + rate = rk3568_dclk_vop_get_clk(priv, clk->id); > + break; > + case SCLK_GMAC0: > + case CLK_MAC0_2TOP: > + case CLK_MAC0_REFOUT: > + rate = rk3568_gmac_src_get_clk(priv, 0); > + break; > + case CLK_MAC0_OUT: > + rate = rk3568_gmac_out_get_clk(priv, 0); > + break; > + case CLK_GMAC0_PTP_REF: > + rate = rk3568_gmac_ptp_ref_get_clk(priv, 0); > + break; > + case SCLK_GMAC1: > + case CLK_MAC1_2TOP: > + case CLK_MAC1_REFOUT: > + rate = rk3568_gmac_src_get_clk(priv, 1); > + break; > + case CLK_MAC1_OUT: > + rate = rk3568_gmac_out_get_clk(priv, 1); > + break; > + case CLK_GMAC1_PTP_REF: > + rate = rk3568_gmac_ptp_ref_get_clk(priv, 1); > + break; > + case DCLK_EBC: > + rate = rk3568_ebc_get_clk(priv); > + break; > + case ACLK_RKVDEC_PRE: > + case ACLK_RKVDEC: > + case CLK_RKVDEC_CORE: > + rate = rk3568_rkvdec_get_clk(priv, clk->id); > + break; > + case TCLK_WDT_NS: > + rate = OSC_HZ; > + break; > + case SCLK_UART1: > + case SCLK_UART2: > + case SCLK_UART3: > + case SCLK_UART4: > + case SCLK_UART5: > + case SCLK_UART6: > + case SCLK_UART7: > + case SCLK_UART8: > + case SCLK_UART9: > + rate = rk3568_uart_get_rate(priv, clk->id); > + break; > +#endif > + case ACLK_SECURE_FLASH: > + case ACLK_CRYPTO_NS: > + case HCLK_SECURE_FLASH: > + case HCLK_CRYPTO_NS: > + case CLK_CRYPTO_NS_RNG: > + case CLK_CRYPTO_NS_CORE: > + case CLK_CRYPTO_NS_PKA: > + rate = rk3568_crypto_get_rate(priv, clk->id); > + break; > + case CPLL_500M: > + case CPLL_333M: > + case CPLL_250M: > + case CPLL_125M: > + case CPLL_100M: > + case CPLL_62P5M: > + case CPLL_50M: > + case CPLL_25M: > + rate = rk3568_cpll_div_get_rate(priv, clk->id); > + break; > + default: > + return -ENOENT; > + } > + > + return rate; > +}; > + > +static ulong rk3568_clk_set_rate(struct clk *clk, ulong rate) > +{ > + struct rk3568_clk_priv *priv = dev_get_priv(clk->dev); > + ulong ret = 0; > + > + if (!priv->gpll_hz) { > + printf("%s gpll=%lu\n", __func__, priv->gpll_hz); > + return -ENOENT; > + } > + > + switch (clk->id) { > + case PLL_APLL: > + case ARMCLK: > + if (priv->armclk_hz) > + rk3568_armclk_set_clk(priv, rate); > + priv->armclk_hz = rate; > + break; > + case PLL_CPLL: > + ret = rockchip_pll_set_rate(&rk3568_pll_clks[CPLL], priv->cru, > + CPLL, rate); > + priv->cpll_hz = rockchip_pll_get_rate(&rk3568_pll_clks[CPLL], > + priv->cru, CPLL); > + break; > + case PLL_GPLL: > + ret = rockchip_pll_set_rate(&rk3568_pll_clks[GPLL], priv->cru, > + GPLL, rate); > + priv->gpll_hz = rockchip_pll_get_rate(&rk3568_pll_clks[GPLL], > + priv->cru, GPLL); > + break; > + case PLL_NPLL: > + ret = rockchip_pll_set_rate(&rk3568_pll_clks[NPLL], priv->cru, > + NPLL, rate); > + break; > + case PLL_VPLL: > + ret = rockchip_pll_set_rate(&rk3568_pll_clks[VPLL], priv->cru, > + VPLL, rate); > + priv->vpll_hz = rockchip_pll_get_rate(&rk3568_pll_clks[VPLL], > + priv->cru, > + VPLL); > + break; > + case ACLK_BUS: > + case PCLK_BUS: > + case PCLK_WDT_NS: > + ret = rk3568_bus_set_clk(priv, clk->id, rate); > + break; > + case ACLK_PERIMID: > + case HCLK_PERIMID: > + ret = rk3568_perimid_set_clk(priv, clk->id, rate); > + break; > + case ACLK_TOP_HIGH: > + case ACLK_TOP_LOW: > + case HCLK_TOP: > + case PCLK_TOP: > + ret = rk3568_top_set_clk(priv, clk->id, rate); > + break; > + case CLK_I2C1: > + case CLK_I2C2: > + case CLK_I2C3: > + case CLK_I2C4: > + case CLK_I2C5: > + ret = rk3568_i2c_set_clk(priv, clk->id, rate); > + break; > + case CLK_SPI0: > + case CLK_SPI1: > + case CLK_SPI2: > + case CLK_SPI3: > + ret = rk3568_spi_set_clk(priv, clk->id, rate); > + break; > + case CLK_PWM1: > + case CLK_PWM2: > + case CLK_PWM3: > + ret = rk3568_pwm_set_clk(priv, clk->id, rate); > + break; > + case CLK_SARADC: > + case CLK_TSADC_TSEN: > + case CLK_TSADC: > + ret = rk3568_adc_set_clk(priv, clk->id, rate); > + break; > + case HCLK_SDMMC0: > + case CLK_SDMMC0: > + case CLK_SDMMC1: > + case CLK_SDMMC2: > + ret = rk3568_sdmmc_set_clk(priv, clk->id, rate); > + break; > + case SCLK_SFC: > + ret = rk3568_sfc_set_clk(priv, rate); > + break; > + case NCLK_NANDC: > + ret = rk3568_nand_set_clk(priv, rate); > + break; > + case CCLK_EMMC: > + ret = rk3568_emmc_set_clk(priv, rate); > + break; > +#ifndef CONFIG_SPL_BUILD > + case ACLK_VOP: > + ret = rk3568_aclk_vop_set_clk(priv, rate); > + break; > + case DCLK_VOP0: > + case DCLK_VOP1: > + case DCLK_VOP2: > + ret = rk3568_dclk_vop_set_clk(priv, clk->id, rate); > + break; > + case SCLK_GMAC0: > + case CLK_MAC0_2TOP: > + case CLK_MAC0_REFOUT: > + ret = rk3568_gmac_src_set_clk(priv, 0, rate); > + break; > + case CLK_MAC0_OUT: > + ret = rk3568_gmac_out_set_clk(priv, 0, rate); > + break; > + case SCLK_GMAC0_RX_TX: > + ret = rk3568_gmac_tx_rx_set_clk(priv, 0, rate); > + break; > + case CLK_GMAC0_PTP_REF: > + ret = rk3568_gmac_ptp_ref_set_clk(priv, 0, rate); > + break; > + case SCLK_GMAC1: > + case CLK_MAC1_2TOP: > + case CLK_MAC1_REFOUT: > + ret = rk3568_gmac_src_set_clk(priv, 1, rate); > + break; > + case CLK_MAC1_OUT: > + ret = rk3568_gmac_out_set_clk(priv, 1, rate); > + break; > + case SCLK_GMAC1_RX_TX: > + ret = rk3568_gmac_tx_rx_set_clk(priv, 1, rate); > + break; > + case CLK_GMAC1_PTP_REF: > + ret = rk3568_gmac_ptp_ref_set_clk(priv, 1, rate); > + break; > + case DCLK_EBC: > + ret = rk3568_ebc_set_clk(priv, rate); > + break; > + case ACLK_RKVDEC_PRE: > + case ACLK_RKVDEC: > + case CLK_RKVDEC_CORE: > + ret = rk3568_rkvdec_set_clk(priv, clk->id, rate); I don't thing we need to set rkvdec clock in the U-Boot, pls remove it. Thanks, - Kever > + break; > + case TCLK_WDT_NS: > + ret = OSC_HZ; > + break; > + case SCLK_UART1: > + case SCLK_UART2: > + case SCLK_UART3: > + case SCLK_UART4: > + case SCLK_UART5: > + case SCLK_UART6: > + case SCLK_UART7: > + case SCLK_UART8: > + case SCLK_UART9: > + ret = rk3568_uart_set_rate(priv, clk->id, rate); > + break; > +#endif > + case ACLK_SECURE_FLASH: > + case ACLK_CRYPTO_NS: > + case HCLK_SECURE_FLASH: > + case HCLK_CRYPTO_NS: > + case CLK_CRYPTO_NS_RNG: > + case CLK_CRYPTO_NS_CORE: > + case CLK_CRYPTO_NS_PKA: > + ret = rk3568_crypto_set_rate(priv, clk->id, rate); > + break; > + case CPLL_500M: > + case CPLL_333M: > + case CPLL_250M: > + case CPLL_125M: > + case CPLL_100M: > + case CPLL_62P5M: > + case CPLL_50M: > + case CPLL_25M: > + ret = rk3568_cpll_div_set_rate(priv, clk->id, rate); > + break; > + default: > + return -ENOENT; > + } > + > + return ret; > +}; > + > +#if (IS_ENABLED(OF_CONTROL)) || (!IS_ENABLED(OF_PLATDATA)) > +static int rk3568_gmac0_src_set_parent(struct clk *clk, struct clk *parent) > +{ > + struct rk3568_clk_priv *priv = dev_get_priv(clk->dev); > + struct rk3568_cru *cru = priv->cru; > + > + if (parent->id == CLK_MAC0_2TOP) > + rk_clrsetreg(&cru->clksel_con[31], > + RMII0_EXTCLK_SEL_MASK, > + RMII0_EXTCLK_SEL_MAC0_TOP << > + RMII0_EXTCLK_SEL_SHIFT); > + else > + rk_clrsetreg(&cru->clksel_con[31], > + RMII0_EXTCLK_SEL_MASK, > + RMII0_EXTCLK_SEL_IO << RMII0_EXTCLK_SEL_SHIFT); > + return 0; > +} > + > +static int rk3568_gmac1_src_set_parent(struct clk *clk, struct clk *parent) > +{ > + struct rk3568_clk_priv *priv = dev_get_priv(clk->dev); > + struct rk3568_cru *cru = priv->cru; > + > + if (parent->id == CLK_MAC1_2TOP) > + rk_clrsetreg(&cru->clksel_con[33], > + RMII0_EXTCLK_SEL_MASK, > + RMII0_EXTCLK_SEL_MAC0_TOP << > + RMII0_EXTCLK_SEL_SHIFT); > + else > + rk_clrsetreg(&cru->clksel_con[33], > + RMII0_EXTCLK_SEL_MASK, > + RMII0_EXTCLK_SEL_IO << RMII0_EXTCLK_SEL_SHIFT); > + return 0; > +} > + > +static int rk3568_gmac0_tx_rx_set_parent(struct clk *clk, struct clk *parent) > +{ > + struct rk3568_clk_priv *priv = dev_get_priv(clk->dev); > + struct rk3568_cru *cru = priv->cru; > + > + if (parent->id == SCLK_GMAC0_RGMII_SPEED) > + rk_clrsetreg(&cru->clksel_con[31], > + RMII0_MODE_MASK, > + RMII0_MODE_SEL_RGMII << RMII0_MODE_SHIFT); > + else if (parent->id == SCLK_GMAC0_RMII_SPEED) > + rk_clrsetreg(&cru->clksel_con[31], > + RMII0_MODE_MASK, > + RMII0_MODE_SEL_RMII << RMII0_MODE_SHIFT); > + else > + rk_clrsetreg(&cru->clksel_con[31], > + RMII0_MODE_MASK, > + RMII0_MODE_SEL_GMII << RMII0_MODE_SHIFT); > + > + return 0; > +} > + > +static int rk3568_gmac1_tx_rx_set_parent(struct clk *clk, struct clk *parent) > +{ > + struct rk3568_clk_priv *priv = dev_get_priv(clk->dev); > + struct rk3568_cru *cru = priv->cru; > + > + if (parent->id == SCLK_GMAC1_RGMII_SPEED) > + rk_clrsetreg(&cru->clksel_con[33], > + RMII0_MODE_MASK, > + RMII0_MODE_SEL_RGMII << RMII0_MODE_SHIFT); > + else if (parent->id == SCLK_GMAC1_RMII_SPEED) > + rk_clrsetreg(&cru->clksel_con[33], > + RMII0_MODE_MASK, > + RMII0_MODE_SEL_RMII << RMII0_MODE_SHIFT); > + else > + rk_clrsetreg(&cru->clksel_con[33], > + RMII0_MODE_MASK, > + RMII0_MODE_SEL_GMII << RMII0_MODE_SHIFT); > + > + return 0; > +} > + > +static int __maybe_unused rk3568_dclk_vop_set_parent(struct clk *clk, > + struct clk *parent) > +{ > + struct rk3568_clk_priv *priv = dev_get_priv(clk->dev); > + struct rk3568_cru *cru = priv->cru; > + u32 con_id; > + > + switch (clk->id) { > + case DCLK_VOP0: > + con_id = 39; > + break; > + case DCLK_VOP1: > + con_id = 40; > + break; > + case DCLK_VOP2: > + con_id = 41; > + break; > + default: > + return -EINVAL; > + } > + if (parent->id == PLL_VPLL) { > + rk_clrsetreg(&cru->clksel_con[con_id], DCLK0_VOP_SEL_MASK, > + DCLK_VOP_SEL_VPLL << DCLK0_VOP_SEL_SHIFT); > + } else { > + rk_clrsetreg(&cru->clksel_con[con_id], DCLK0_VOP_SEL_MASK, > + DCLK_VOP_SEL_HPLL << DCLK0_VOP_SEL_SHIFT); > + } > + > + return 0; > +} > + > +static int __maybe_unused rk3568_rkvdec_set_parent(struct clk *clk, > + struct clk *parent) > +{ > + struct rk3568_clk_priv *priv = dev_get_priv(clk->dev); > + struct rk3568_cru *cru = priv->cru; > + u32 con_id, mask, shift; > + > + switch (clk->id) { > + case ACLK_RKVDEC_PRE: > + con_id = 47; > + mask = ACLK_RKVDEC_SEL_MASK; > + shift = ACLK_RKVDEC_SEL_SHIFT; > + break; > + case CLK_RKVDEC_CORE: > + con_id = 49; > + mask = CLK_RKVDEC_CORE_SEL_MASK; > + shift = CLK_RKVDEC_CORE_SEL_SHIFT; > + break; > + default: > + return -EINVAL; > + } > + if (parent->id == PLL_CPLL) { > + rk_clrsetreg(&cru->clksel_con[con_id], mask, > + ACLK_RKVDEC_SEL_CPLL << shift); > + } else { > + rk_clrsetreg(&cru->clksel_con[con_id], mask, > + ACLK_RKVDEC_SEL_GPLL << shift); > + } > + > + return 0; > +} > + > +static int rk3568_clk_set_parent(struct clk *clk, struct clk *parent) > +{ > + switch (clk->id) { > + case SCLK_GMAC0: > + return rk3568_gmac0_src_set_parent(clk, parent); > + case SCLK_GMAC1: > + return rk3568_gmac1_src_set_parent(clk, parent); > + case SCLK_GMAC0_RX_TX: > + return rk3568_gmac0_tx_rx_set_parent(clk, parent); > + case SCLK_GMAC1_RX_TX: > + return rk3568_gmac1_tx_rx_set_parent(clk, parent); > + case DCLK_VOP0: > + case DCLK_VOP1: > + case DCLK_VOP2: > + return rk3568_dclk_vop_set_parent(clk, parent); > + case ACLK_RKVDEC_PRE: > + case CLK_RKVDEC_CORE: > + return rk3568_rkvdec_set_parent(clk, parent); > + default: > + return -ENOENT; > + } > + > + return 0; > +} > +#endif > + > +static struct clk_ops rk3568_clk_ops = { > + .get_rate = rk3568_clk_get_rate, > + .set_rate = rk3568_clk_set_rate, > +#if (IS_ENABLED(OF_CONTROL)) || (!IS_ENABLED(OF_PLATDATA)) > + .set_parent = rk3568_clk_set_parent, > +#endif > +}; > + > +static void rk3568_clk_init(struct rk3568_clk_priv *priv) > +{ > + int ret; > + > + priv->sync_kernel = false; > + if (!priv->armclk_enter_hz) { > + priv->armclk_enter_hz = > + rockchip_pll_get_rate(&rk3568_pll_clks[APLL], > + priv->cru, APLL); > + priv->armclk_init_hz = priv->armclk_enter_hz; > + } > + > + if (priv->armclk_init_hz != APLL_HZ) { > + ret = rk3568_armclk_set_clk(priv, APLL_HZ); > + if (!ret) > + priv->armclk_init_hz = APLL_HZ; > + } > + if (priv->cpll_hz != CPLL_HZ) { > + ret = rockchip_pll_set_rate(&rk3568_pll_clks[CPLL], priv->cru, > + CPLL, CPLL_HZ); > + if (!ret) > + priv->cpll_hz = CPLL_HZ; > + } > + if (priv->gpll_hz != GPLL_HZ) { > + ret = rockchip_pll_set_rate(&rk3568_pll_clks[GPLL], priv->cru, > + GPLL, GPLL_HZ); > + if (!ret) > + priv->gpll_hz = GPLL_HZ; > + } > + > +#ifdef CONFIG_SPL_BUILD > + ret = rk3568_bus_set_clk(priv, ACLK_BUS, 150000000); > + if (ret < 0) > + printf("Fail to set the ACLK_BUS clock.\n"); > +#endif > + > + priv->ppll_hz = rk3568_pmu_pll_get_rate(priv, PPLL); > + priv->hpll_hz = rk3568_pmu_pll_get_rate(priv, HPLL); > +} > + > +static int rk3568_clk_probe(struct udevice *dev) > +{ > + struct rk3568_clk_priv *priv = dev_get_priv(dev); > + int ret; > + > + priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); > + if (IS_ERR(priv->grf)) > + return PTR_ERR(priv->grf); > + > + rk3568_clk_init(priv); > + > + /* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */ > + ret = clk_set_defaults(dev, 1); > + if (ret) > + debug("%s clk_set_defaults failed %d\n", __func__, ret); > + else > + priv->sync_kernel = true; > + > + return 0; > +} > + > +static int rk3568_clk_ofdata_to_platdata(struct udevice *dev) > +{ > + struct rk3568_clk_priv *priv = dev_get_priv(dev); > + > + priv->cru = dev_read_addr_ptr(dev); > + > + return 0; > +} > + > +static int rk3568_clk_bind(struct udevice *dev) > +{ > + int ret; > + struct udevice *sys_child; > + struct sysreset_reg *priv; > + > + /* The reset driver does not have a device node, so bind it here */ > + ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset", > + &sys_child); > + if (ret) { > + debug("Warning: No sysreset driver: ret=%d\n", ret); > + } else { > + priv = malloc(sizeof(struct sysreset_reg)); > + priv->glb_srst_fst_value = offsetof(struct rk3568_cru, > + glb_srst_fst); > + priv->glb_srst_snd_value = offsetof(struct rk3568_cru, > + glb_srsr_snd); > + } > + > +#if CONFIG_IS_ENABLED(RESET_ROCKCHIP) > + ret = offsetof(struct rk3568_cru, softrst_con[0]); > + ret = rockchip_reset_bind(dev, ret, 30); > + if (ret) > + debug("Warning: software reset driver bind faile\n"); > +#endif > + > + return 0; > +} > + > +static const struct udevice_id rk3568_clk_ids[] = { > + { .compatible = "rockchip,rk3568-cru" }, > + { } > +}; > + > +U_BOOT_DRIVER(rockchip_rk3568_cru) = { > + .name = "rockchip_rk3568_cru", > + .id = UCLASS_CLK, > + .of_match = rk3568_clk_ids, > + .priv_auto = sizeof(struct rk3568_clk_priv), > + .of_to_plat = rk3568_clk_ofdata_to_platdata, > + .ops = &rk3568_clk_ops, > + .bind = rk3568_clk_bind, > + .probe = rk3568_clk_probe, > +#if CONFIG_IS_ENABLED(OF_PLATDATA) > + .plat_auto = sizeof(struct rk3568_clk_plat), > +#endif > +};