From a623c14f43d065a24e9ff7a1dfcbe38e5f9fed7e Mon Sep 17 00:00:00 2001 From: Caleb Connolly Date: Tue, 7 Nov 2023 12:40:59 +0000 Subject: clk/qcom: move from mach-snapdragon Clock drivers don't belong here, move them to the right place and declutter mach-snapdragon a bit. To de-couple these drivers from specific "target" platforms, add additional config options to enable each clock driver gated behind a common CLK_QCOM option and enable them by default for the respective targets. This will make future work easier as we move towards a generic Qualcomm target. Reviewed-by: Sumit Garg Signed-off-by: Caleb Connolly --- MAINTAINERS | 1 + arch/arm/mach-snapdragon/Kconfig | 4 + arch/arm/mach-snapdragon/Makefile | 5 - arch/arm/mach-snapdragon/clock-apq8016.c | 118 -------------- arch/arm/mach-snapdragon/clock-apq8096.c | 100 ------------ arch/arm/mach-snapdragon/clock-qcs404.c | 237 ---------------------------- arch/arm/mach-snapdragon/clock-sdm845.c | 98 ------------ arch/arm/mach-snapdragon/clock-snapdragon.c | 181 --------------------- arch/arm/mach-snapdragon/clock-snapdragon.h | 48 ------ drivers/clk/Kconfig | 1 + drivers/clk/Makefile | 1 + drivers/clk/qcom/Kconfig | 44 ++++++ drivers/clk/qcom/Makefile | 9 ++ drivers/clk/qcom/clock-apq8016.c | 118 ++++++++++++++ drivers/clk/qcom/clock-apq8096.c | 101 ++++++++++++ drivers/clk/qcom/clock-qcom.c | 181 +++++++++++++++++++++ drivers/clk/qcom/clock-qcom.h | 48 ++++++ drivers/clk/qcom/clock-qcs404.c | 237 ++++++++++++++++++++++++++++ drivers/clk/qcom/clock-sdm845.c | 98 ++++++++++++ 19 files changed, 843 insertions(+), 787 deletions(-) delete mode 100644 arch/arm/mach-snapdragon/clock-apq8016.c delete mode 100644 arch/arm/mach-snapdragon/clock-apq8096.c delete mode 100644 arch/arm/mach-snapdragon/clock-qcs404.c delete mode 100644 arch/arm/mach-snapdragon/clock-sdm845.c delete mode 100644 arch/arm/mach-snapdragon/clock-snapdragon.c delete mode 100644 arch/arm/mach-snapdragon/clock-snapdragon.h create mode 100644 drivers/clk/qcom/Kconfig create mode 100644 drivers/clk/qcom/Makefile create mode 100644 drivers/clk/qcom/clock-apq8016.c create mode 100644 drivers/clk/qcom/clock-apq8096.c create mode 100644 drivers/clk/qcom/clock-qcom.c create mode 100644 drivers/clk/qcom/clock-qcom.h create mode 100644 drivers/clk/qcom/clock-qcs404.c create mode 100644 drivers/clk/qcom/clock-sdm845.c diff --git a/MAINTAINERS b/MAINTAINERS index 4fec063a242..185f5ebbb17 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -575,6 +575,7 @@ M: Neil Armstrong R: Sumit Garg S: Maintained F: arch/arm/mach-snapdragon/ +F: drivers/clk/qcom/ F: drivers/gpio/msm_gpio.c F: drivers/mmc/msm_sdhci.c F: drivers/phy/msm8916-usbh-phy.c diff --git a/arch/arm/mach-snapdragon/Kconfig b/arch/arm/mach-snapdragon/Kconfig index 2fc1521e2d3..dde37eccc55 100644 --- a/arch/arm/mach-snapdragon/Kconfig +++ b/arch/arm/mach-snapdragon/Kconfig @@ -15,6 +15,7 @@ config SPL_SYS_MALLOC_F_LEN config SDM845 bool "Qualcomm Snapdragon 845 SoC" select LINUX_KERNEL_IMAGE_HEADER + imply CLK_QCOM_SDM845 config LNX_KRNL_IMG_TEXT_OFFSET_BASE default 0x80000000 @@ -26,6 +27,7 @@ config TARGET_DRAGONBOARD410C bool "96Boards Dragonboard 410C" select BOARD_LATE_INIT select ENABLE_ARM_SOC_BOOT0_HOOK + imply CLK_QCOM_APQ8016 help Support for 96Boards Dragonboard 410C. This board complies with 96Board Open Platform Specifications. Features: @@ -39,6 +41,7 @@ config TARGET_DRAGONBOARD410C config TARGET_DRAGONBOARD820C bool "96Boards Dragonboard 820C" + imply CLK_QCOM_APQ8096 help Support for 96Boards Dragonboard 820C. This board complies with 96Board Open Platform Specifications. Features: @@ -72,6 +75,7 @@ config TARGET_STARQLTECHN config TARGET_QCS404EVB bool "Qualcomm Technologies, Inc. QCS404 EVB" select LINUX_KERNEL_IMAGE_HEADER + imply CLK_QCOM_QCS404 help Support for Qualcomm Technologies, Inc. QCS404 evaluation board. Features: diff --git a/arch/arm/mach-snapdragon/Makefile b/arch/arm/mach-snapdragon/Makefile index cbaaf23f6b5..497ee35cf7d 100644 --- a/arch/arm/mach-snapdragon/Makefile +++ b/arch/arm/mach-snapdragon/Makefile @@ -2,20 +2,15 @@ # # (C) Copyright 2015 Mateusz Kulikowski -obj-$(CONFIG_SDM845) += clock-sdm845.o obj-$(CONFIG_SDM845) += sysmap-sdm845.o obj-$(CONFIG_SDM845) += init_sdm845.o -obj-$(CONFIG_TARGET_DRAGONBOARD820C) += clock-apq8096.o obj-$(CONFIG_TARGET_DRAGONBOARD820C) += sysmap-apq8096.o -obj-$(CONFIG_TARGET_DRAGONBOARD410C) += clock-apq8016.o obj-$(CONFIG_TARGET_DRAGONBOARD410C) += sysmap-apq8016.o obj-y += misc.o -obj-y += clock-snapdragon.o obj-y += dram.o obj-y += pinctrl-snapdragon.o obj-y += pinctrl-apq8016.o obj-y += pinctrl-apq8096.o obj-y += pinctrl-qcs404.o obj-y += pinctrl-sdm845.o -obj-$(CONFIG_TARGET_QCS404EVB) += clock-qcs404.o obj-$(CONFIG_TARGET_QCS404EVB) += sysmap-qcs404.o diff --git a/arch/arm/mach-snapdragon/clock-apq8016.c b/arch/arm/mach-snapdragon/clock-apq8016.c deleted file mode 100644 index 23a37a1714d..00000000000 --- a/arch/arm/mach-snapdragon/clock-apq8016.c +++ /dev/null @@ -1,118 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -/* - * Clock drivers for Qualcomm APQ8016 - * - * (C) Copyright 2015 Mateusz Kulikowski - * - * Based on Little Kernel driver, simplified - */ - -#include -#include -#include -#include -#include -#include -#include "clock-snapdragon.h" - -/* GPLL0 clock control registers */ -#define GPLL0_STATUS_ACTIVE BIT(17) - -static const struct bcr_regs sdc_regs[] = { - { - .cfg_rcgr = SDCC_CFG_RCGR(1), - .cmd_rcgr = SDCC_CMD_RCGR(1), - .M = SDCC_M(1), - .N = SDCC_N(1), - .D = SDCC_D(1), - }, - { - .cfg_rcgr = SDCC_CFG_RCGR(2), - .cmd_rcgr = SDCC_CMD_RCGR(2), - .M = SDCC_M(2), - .N = SDCC_N(2), - .D = SDCC_D(2), - } -}; - -static struct pll_vote_clk gpll0_vote_clk = { - .status = GPLL0_STATUS, - .status_bit = GPLL0_STATUS_ACTIVE, - .ena_vote = APCS_GPLL_ENA_VOTE, - .vote_bit = BIT(0), -}; - -static struct vote_clk gcc_blsp1_ahb_clk = { - .cbcr_reg = BLSP1_AHB_CBCR, - .ena_vote = APCS_CLOCK_BRANCH_ENA_VOTE, - .vote_bit = BIT(10), -}; - -/* SDHCI */ -static int clk_init_sdc(struct msm_clk_priv *priv, int slot, uint rate) -{ - int div = 8; /* 100MHz default */ - - if (rate == 200000000) - div = 4; - - clk_enable_cbc(priv->base + SDCC_AHB_CBCR(slot)); - /* 800Mhz/div, gpll0 */ - clk_rcg_set_rate_mnd(priv->base, &sdc_regs[slot], div, 0, 0, - CFG_CLK_SRC_GPLL0); - clk_enable_gpll0(priv->base, &gpll0_vote_clk); - clk_enable_cbc(priv->base + SDCC_APPS_CBCR(slot)); - - return rate; -} - -static const struct bcr_regs uart2_regs = { - .cfg_rcgr = BLSP1_UART2_APPS_CFG_RCGR, - .cmd_rcgr = BLSP1_UART2_APPS_CMD_RCGR, - .M = BLSP1_UART2_APPS_M, - .N = BLSP1_UART2_APPS_N, - .D = BLSP1_UART2_APPS_D, -}; - -/* UART: 115200 */ -static int clk_init_uart(struct msm_clk_priv *priv) -{ - /* Enable AHB clock */ - clk_enable_vote_clk(priv->base, &gcc_blsp1_ahb_clk); - - /* 7372800 uart block clock @ GPLL0 */ - clk_rcg_set_rate_mnd(priv->base, &uart2_regs, 1, 144, 15625, - CFG_CLK_SRC_GPLL0); - - /* Vote for gpll0 clock */ - clk_enable_gpll0(priv->base, &gpll0_vote_clk); - - /* Enable core clk */ - clk_enable_cbc(priv->base + BLSP1_UART2_APPS_CBCR); - - return 0; -} - -ulong msm_set_rate(struct clk *clk, ulong rate) -{ - struct msm_clk_priv *priv = dev_get_priv(clk->dev); - - switch (clk->id) { - case 0: /* SDC1 */ - return clk_init_sdc(priv, 0, rate); - break; - case 1: /* SDC2 */ - return clk_init_sdc(priv, 1, rate); - break; - case 4: /* UART2 */ - return clk_init_uart(priv); - break; - default: - return 0; - } -} - -int msm_enable(struct clk *clk) -{ - return 0; -} diff --git a/arch/arm/mach-snapdragon/clock-apq8096.c b/arch/arm/mach-snapdragon/clock-apq8096.c deleted file mode 100644 index 66184596d56..00000000000 --- a/arch/arm/mach-snapdragon/clock-apq8096.c +++ /dev/null @@ -1,100 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -/* - * Clock drivers for Qualcomm APQ8096 - * - * (C) Copyright 2017 Jorge Ramirez Ortiz - * - * Based on Little Kernel driver, simplified - */ - -#include -#include -#include -#include -#include -#include -#include "clock-snapdragon.h" - -/* GPLL0 clock control registers */ -#define GPLL0_STATUS_ACTIVE BIT(30) -#define APCS_GPLL_ENA_VOTE_GPLL0 BIT(0) - -static const struct bcr_regs sdc_regs = { - .cfg_rcgr = SDCC2_CFG_RCGR, - .cmd_rcgr = SDCC2_CMD_RCGR, - .M = SDCC2_M, - .N = SDCC2_N, - .D = SDCC2_D, -}; - -static const struct pll_vote_clk gpll0_vote_clk = { - .status = GPLL0_STATUS, - .status_bit = GPLL0_STATUS_ACTIVE, - .ena_vote = APCS_GPLL_ENA_VOTE, - .vote_bit = APCS_GPLL_ENA_VOTE_GPLL0, -}; - -static struct vote_clk gcc_blsp2_ahb_clk = { - .cbcr_reg = BLSP2_AHB_CBCR, - .ena_vote = APCS_CLOCK_BRANCH_ENA_VOTE, - .vote_bit = BIT(15), -}; - -static int clk_init_sdc(struct msm_clk_priv *priv, uint rate) -{ - int div = 3; - - clk_enable_cbc(priv->base + SDCC2_AHB_CBCR); - clk_rcg_set_rate_mnd(priv->base, &sdc_regs, div, 0, 0, - CFG_CLK_SRC_GPLL0); - clk_enable_gpll0(priv->base, &gpll0_vote_clk); - clk_enable_cbc(priv->base + SDCC2_APPS_CBCR); - - return rate; -} - -static const struct bcr_regs uart2_regs = { - .cfg_rcgr = BLSP2_UART2_APPS_CFG_RCGR, - .cmd_rcgr = BLSP2_UART2_APPS_CMD_RCGR, - .M = BLSP2_UART2_APPS_M, - .N = BLSP2_UART2_APPS_N, - .D = BLSP2_UART2_APPS_D, -}; - -static int clk_init_uart(struct msm_clk_priv *priv) -{ - /* Enable AHB clock */ - clk_enable_vote_clk(priv->base, &gcc_blsp2_ahb_clk); - - /* 7372800 uart block clock @ GPLL0 */ - clk_rcg_set_rate_mnd(priv->base, &uart2_regs, 1, 192, 15625, - CFG_CLK_SRC_GPLL0); - - /* Vote for gpll0 clock */ - clk_enable_gpll0(priv->base, &gpll0_vote_clk); - - /* Enable core clk */ - clk_enable_cbc(priv->base + BLSP2_UART2_APPS_CBCR); - - return 0; -} - -ulong msm_set_rate(struct clk *clk, ulong rate) -{ - struct msm_clk_priv *priv = dev_get_priv(clk->dev); - - switch (clk->id) { - case 0: /* SDC1 */ - return clk_init_sdc(priv, rate); - break; - case 4: /*UART2*/ - return clk_init_uart(priv); - default: - return 0; - } -} - -int msm_enable(struct clk *clk) -{ - return 0; -} diff --git a/arch/arm/mach-snapdragon/clock-qcs404.c b/arch/arm/mach-snapdragon/clock-qcs404.c deleted file mode 100644 index 3357b54c30c..00000000000 --- a/arch/arm/mach-snapdragon/clock-qcs404.c +++ /dev/null @@ -1,237 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -/* - * Clock drivers for Qualcomm QCS404 - * - * (C) Copyright 2022 Sumit Garg - */ - -#include -#include -#include -#include -#include -#include -#include "clock-snapdragon.h" - -#include - -/* GPLL0 clock control registers */ -#define GPLL0_STATUS_ACTIVE BIT(31) - -#define CFG_CLK_SRC_GPLL1 BIT(8) -#define GPLL1_STATUS_ACTIVE BIT(31) - -static struct vote_clk gcc_blsp1_ahb_clk = { - .cbcr_reg = BLSP1_AHB_CBCR, - .ena_vote = APCS_CLOCK_BRANCH_ENA_VOTE, - .vote_bit = BIT(10) | BIT(5) | BIT(4), -}; - -static const struct bcr_regs uart2_regs = { - .cfg_rcgr = BLSP1_UART2_APPS_CFG_RCGR, - .cmd_rcgr = BLSP1_UART2_APPS_CMD_RCGR, - .M = BLSP1_UART2_APPS_M, - .N = BLSP1_UART2_APPS_N, - .D = BLSP1_UART2_APPS_D, -}; - -static const struct bcr_regs sdc_regs = { - .cfg_rcgr = SDCC_CFG_RCGR(1), - .cmd_rcgr = SDCC_CMD_RCGR(1), - .M = SDCC_M(1), - .N = SDCC_N(1), - .D = SDCC_D(1), -}; - -static struct pll_vote_clk gpll0_vote_clk = { - .status = GPLL0_STATUS, - .status_bit = GPLL0_STATUS_ACTIVE, - .ena_vote = APCS_GPLL_ENA_VOTE, - .vote_bit = BIT(0), -}; - -static struct pll_vote_clk gpll1_vote_clk = { - .status = GPLL1_STATUS, - .status_bit = GPLL1_STATUS_ACTIVE, - .ena_vote = APCS_GPLL_ENA_VOTE, - .vote_bit = BIT(1), -}; - -static const struct bcr_regs usb30_master_regs = { - .cfg_rcgr = USB30_MASTER_CFG_RCGR, - .cmd_rcgr = USB30_MASTER_CMD_RCGR, - .M = USB30_MASTER_M, - .N = USB30_MASTER_N, - .D = USB30_MASTER_D, -}; - -static const struct bcr_regs emac_regs = { - .cfg_rcgr = EMAC_CFG_RCGR, - .cmd_rcgr = EMAC_CMD_RCGR, - .M = EMAC_M, - .N = EMAC_N, - .D = EMAC_D, -}; - -static const struct bcr_regs emac_ptp_regs = { - .cfg_rcgr = EMAC_PTP_CFG_RCGR, - .cmd_rcgr = EMAC_PTP_CMD_RCGR, - .M = EMAC_M, - .N = EMAC_N, - .D = EMAC_D, -}; - -static const struct bcr_regs blsp1_qup0_i2c_apps_regs = { - .cmd_rcgr = BLSP1_QUP0_I2C_APPS_CMD_RCGR, - .cfg_rcgr = BLSP1_QUP0_I2C_APPS_CFG_RCGR, - /* mnd_width = 0 */ -}; - -static const struct bcr_regs blsp1_qup1_i2c_apps_regs = { - .cmd_rcgr = BLSP1_QUP1_I2C_APPS_CMD_RCGR, - .cfg_rcgr = BLSP1_QUP1_I2C_APPS_CFG_RCGR, - /* mnd_width = 0 */ -}; - -static const struct bcr_regs blsp1_qup2_i2c_apps_regs = { - .cmd_rcgr = BLSP1_QUP2_I2C_APPS_CMD_RCGR, - .cfg_rcgr = BLSP1_QUP2_I2C_APPS_CFG_RCGR, - /* mnd_width = 0 */ -}; - -static const struct bcr_regs blsp1_qup3_i2c_apps_regs = { - .cmd_rcgr = BLSP1_QUP3_I2C_APPS_CMD_RCGR, - .cfg_rcgr = BLSP1_QUP3_I2C_APPS_CFG_RCGR, - /* mnd_width = 0 */ -}; - -static const struct bcr_regs blsp1_qup4_i2c_apps_regs = { - .cmd_rcgr = BLSP1_QUP4_I2C_APPS_CMD_RCGR, - .cfg_rcgr = BLSP1_QUP4_I2C_APPS_CFG_RCGR, - /* mnd_width = 0 */ -}; - -ulong msm_set_rate(struct clk *clk, ulong rate) -{ - struct msm_clk_priv *priv = dev_get_priv(clk->dev); - - switch (clk->id) { - case GCC_BLSP1_UART2_APPS_CLK: - /* UART: 115200 */ - clk_rcg_set_rate_mnd(priv->base, &uart2_regs, 0, 12, 125, - CFG_CLK_SRC_CXO); - clk_enable_cbc(priv->base + BLSP1_UART2_APPS_CBCR); - break; - case GCC_BLSP1_AHB_CLK: - clk_enable_vote_clk(priv->base, &gcc_blsp1_ahb_clk); - break; - case GCC_SDCC1_APPS_CLK: - /* SDCC1: 200MHz */ - clk_rcg_set_rate_mnd(priv->base, &sdc_regs, 4, 0, 0, - CFG_CLK_SRC_GPLL0); - clk_enable_gpll0(priv->base, &gpll0_vote_clk); - clk_enable_cbc(priv->base + SDCC_APPS_CBCR(1)); - break; - case GCC_SDCC1_AHB_CLK: - clk_enable_cbc(priv->base + SDCC_AHB_CBCR(1)); - break; - case GCC_ETH_RGMII_CLK: - if (rate == 250000000) - clk_rcg_set_rate_mnd(priv->base, &emac_regs, 2, 0, 0, - CFG_CLK_SRC_GPLL1); - else if (rate == 125000000) - clk_rcg_set_rate_mnd(priv->base, &emac_regs, 4, 0, 0, - CFG_CLK_SRC_GPLL1); - else if (rate == 50000000) - clk_rcg_set_rate_mnd(priv->base, &emac_regs, 10, 0, 0, - CFG_CLK_SRC_GPLL1); - else if (rate == 5000000) - clk_rcg_set_rate_mnd(priv->base, &emac_regs, 2, 1, 50, - CFG_CLK_SRC_GPLL1); - break; - default: - return 0; - } - - return 0; -} - -int msm_enable(struct clk *clk) -{ - struct msm_clk_priv *priv = dev_get_priv(clk->dev); - - switch (clk->id) { - case GCC_USB30_MASTER_CLK: - clk_enable_cbc(priv->base + USB30_MASTER_CBCR); - clk_rcg_set_rate_mnd(priv->base, &usb30_master_regs, 4, 0, 0, - CFG_CLK_SRC_GPLL0); - break; - case GCC_SYS_NOC_USB3_CLK: - clk_enable_cbc(priv->base + SYS_NOC_USB3_CBCR); - break; - case GCC_USB30_SLEEP_CLK: - clk_enable_cbc(priv->base + USB30_SLEEP_CBCR); - break; - case GCC_USB30_MOCK_UTMI_CLK: - clk_enable_cbc(priv->base + USB30_MOCK_UTMI_CBCR); - break; - case GCC_USB_HS_PHY_CFG_AHB_CLK: - clk_enable_cbc(priv->base + USB_HS_PHY_CFG_AHB_CBCR); - break; - case GCC_USB2A_PHY_SLEEP_CLK: - clk_enable_cbc(priv->base + USB_HS_PHY_CFG_AHB_CBCR); - break; - case GCC_ETH_PTP_CLK: - /* SPEED_1000: freq -> 250MHz */ - clk_enable_cbc(priv->base + ETH_PTP_CBCR); - clk_enable_gpll0(priv->base, &gpll1_vote_clk); - clk_rcg_set_rate_mnd(priv->base, &emac_ptp_regs, 2, 0, 0, - CFG_CLK_SRC_GPLL1); - break; - case GCC_ETH_RGMII_CLK: - /* SPEED_1000: freq -> 250MHz */ - clk_enable_cbc(priv->base + ETH_RGMII_CBCR); - clk_enable_gpll0(priv->base, &gpll1_vote_clk); - clk_rcg_set_rate_mnd(priv->base, &emac_regs, 2, 0, 0, - CFG_CLK_SRC_GPLL1); - break; - case GCC_ETH_SLAVE_AHB_CLK: - clk_enable_cbc(priv->base + ETH_SLAVE_AHB_CBCR); - break; - case GCC_ETH_AXI_CLK: - clk_enable_cbc(priv->base + ETH_AXI_CBCR); - break; - case GCC_BLSP1_AHB_CLK: - clk_enable_vote_clk(priv->base, &gcc_blsp1_ahb_clk); - break; - case GCC_BLSP1_QUP0_I2C_APPS_CLK: - clk_enable_cbc(priv->base + BLSP1_QUP0_I2C_APPS_CBCR); - clk_rcg_set_rate(priv->base, &blsp1_qup0_i2c_apps_regs, 0, - CFG_CLK_SRC_CXO); - break; - case GCC_BLSP1_QUP1_I2C_APPS_CLK: - clk_enable_cbc(priv->base + BLSP1_QUP1_I2C_APPS_CBCR); - clk_rcg_set_rate(priv->base, &blsp1_qup1_i2c_apps_regs, 0, - CFG_CLK_SRC_CXO); - break; - case GCC_BLSP1_QUP2_I2C_APPS_CLK: - clk_enable_cbc(priv->base + BLSP1_QUP2_I2C_APPS_CBCR); - clk_rcg_set_rate(priv->base, &blsp1_qup2_i2c_apps_regs, 0, - CFG_CLK_SRC_CXO); - break; - case GCC_BLSP1_QUP3_I2C_APPS_CLK: - clk_enable_cbc(priv->base + BLSP1_QUP3_I2C_APPS_CBCR); - clk_rcg_set_rate(priv->base, &blsp1_qup3_i2c_apps_regs, 0, - CFG_CLK_SRC_CXO); - break; - case GCC_BLSP1_QUP4_I2C_APPS_CLK: - clk_enable_cbc(priv->base + BLSP1_QUP4_I2C_APPS_CBCR); - clk_rcg_set_rate(priv->base, &blsp1_qup4_i2c_apps_regs, 0, - CFG_CLK_SRC_CXO); - break; - default: - return 0; - } - - return 0; -} diff --git a/arch/arm/mach-snapdragon/clock-sdm845.c b/arch/arm/mach-snapdragon/clock-sdm845.c deleted file mode 100644 index d6df0365afc..00000000000 --- a/arch/arm/mach-snapdragon/clock-sdm845.c +++ /dev/null @@ -1,98 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -/* - * Clock drivers for Qualcomm SDM845 - * - * (C) Copyright 2017 Jorge Ramirez Ortiz - * (C) Copyright 2021 Dzmitry Sankouski - * - * Based on Little Kernel driver, simplified - */ - -#include -#include -#include -#include -#include -#include -#include -#include "clock-snapdragon.h" - -#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } - -struct freq_tbl { - uint freq; - uint src; - u8 pre_div; - u16 m; - u16 n; -}; - -static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = { - F(7372800, CFG_CLK_SRC_GPLL0_EVEN, 1, 384, 15625), - F(14745600, CFG_CLK_SRC_GPLL0_EVEN, 1, 768, 15625), - F(19200000, CFG_CLK_SRC_CXO, 1, 0, 0), - F(29491200, CFG_CLK_SRC_GPLL0_EVEN, 1, 1536, 15625), - F(32000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 8, 75), - F(48000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 4, 25), - F(64000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 16, 75), - F(80000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 4, 15), - F(96000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 8, 25), - F(100000000, CFG_CLK_SRC_GPLL0_EVEN, 3, 0, 0), - F(102400000, CFG_CLK_SRC_GPLL0_EVEN, 1, 128, 375), - F(112000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 28, 75), - F(117964800, CFG_CLK_SRC_GPLL0_EVEN, 1, 6144, 15625), - F(120000000, CFG_CLK_SRC_GPLL0_EVEN, 2.5, 0, 0), - F(128000000, CFG_CLK_SRC_GPLL0, 1, 16, 75), - { } -}; - -static const struct bcr_regs uart2_regs = { - .cfg_rcgr = SE9_UART_APPS_CFG_RCGR, - .cmd_rcgr = SE9_UART_APPS_CMD_RCGR, - .M = SE9_UART_APPS_M, - .N = SE9_UART_APPS_N, - .D = SE9_UART_APPS_D, -}; - -const struct freq_tbl *qcom_find_freq(const struct freq_tbl *f, uint rate) -{ - if (!f) - return NULL; - - if (!f->freq) - return f; - - for (; f->freq; f++) - if (rate <= f->freq) - return f; - - /* Default to our fastest rate */ - return f - 1; -} - -static int clk_init_uart(struct msm_clk_priv *priv, uint rate) -{ - const struct freq_tbl *freq = qcom_find_freq(ftbl_gcc_qupv3_wrap0_s0_clk_src, rate); - - clk_rcg_set_rate_mnd(priv->base, &uart2_regs, - freq->pre_div, freq->m, freq->n, freq->src); - - return 0; -} - -ulong msm_set_rate(struct clk *clk, ulong rate) -{ - struct msm_clk_priv *priv = dev_get_priv(clk->dev); - - switch (clk->id) { - case GCC_QUPV3_WRAP1_S1_CLK: /*UART2*/ - return clk_init_uart(priv, rate); - default: - return 0; - } -} - -int msm_enable(struct clk *clk) -{ - return 0; -} diff --git a/arch/arm/mach-snapdragon/clock-snapdragon.c b/arch/arm/mach-snapdragon/clock-snapdragon.c deleted file mode 100644 index 0ac45dce9a9..00000000000 --- a/arch/arm/mach-snapdragon/clock-snapdragon.c +++ /dev/null @@ -1,181 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -/* - * Clock drivers for Qualcomm APQ8016, APQ8096 - * - * (C) Copyright 2015 Mateusz Kulikowski - * - * Based on Little Kernel driver, simplified - */ - -#include -#include -#include -#include -#include -#include -#include "clock-snapdragon.h" - -/* CBCR register fields */ -#define CBCR_BRANCH_ENABLE_BIT BIT(0) -#define CBCR_BRANCH_OFF_BIT BIT(31) - -extern ulong msm_set_rate(struct clk *clk, ulong rate); -extern int msm_enable(struct clk *clk); - -/* Enable clock controlled by CBC soft macro */ -void clk_enable_cbc(phys_addr_t cbcr) -{ - setbits_le32(cbcr, CBCR_BRANCH_ENABLE_BIT); - - while (readl(cbcr) & CBCR_BRANCH_OFF_BIT) - ; -} - -void clk_enable_gpll0(phys_addr_t base, const struct pll_vote_clk *gpll0) -{ - if (readl(base + gpll0->status) & gpll0->status_bit) - return; /* clock already enabled */ - - setbits_le32(base + gpll0->ena_vote, gpll0->vote_bit); - - while ((readl(base + gpll0->status) & gpll0->status_bit) == 0) - ; -} - -#define BRANCH_ON_VAL (0) -#define BRANCH_NOC_FSM_ON_VAL BIT(29) -#define BRANCH_CHECK_MASK GENMASK(31, 28) - -void clk_enable_vote_clk(phys_addr_t base, const struct vote_clk *vclk) -{ - u32 val; - - setbits_le32(base + vclk->ena_vote, vclk->vote_bit); - do { - val = readl(base + vclk->cbcr_reg); - val &= BRANCH_CHECK_MASK; - } while ((val != BRANCH_ON_VAL) && (val != BRANCH_NOC_FSM_ON_VAL)); -} - -#define APPS_CMD_RCGR_UPDATE BIT(0) - -/* Update clock command via CMD_RCGR */ -void clk_bcr_update(phys_addr_t apps_cmd_rcgr) -{ - setbits_le32(apps_cmd_rcgr, APPS_CMD_RCGR_UPDATE); - - /* Wait for frequency to be updated. */ - while (readl(apps_cmd_rcgr) & APPS_CMD_RCGR_UPDATE) - ; -} - -#define CFG_MODE_DUAL_EDGE (0x2 << 12) /* Counter mode */ - -#define CFG_MASK 0x3FFF - -#define CFG_DIVIDER_MASK 0x1F - -/* root set rate for clocks with half integer and MND divider */ -void clk_rcg_set_rate_mnd(phys_addr_t base, const struct bcr_regs *regs, - int div, int m, int n, int source) -{ - u32 cfg; - /* M value for MND divider. */ - u32 m_val = m; - /* NOT(N-M) value for MND divider. */ - u32 n_val = ~((n) - (m)) * !!(n); - /* NOT 2D value for MND divider. */ - u32 d_val = ~(n); - - /* Program MND values */ - writel(m_val, base + regs->M); - writel(n_val, base + regs->N); - writel(d_val, base + regs->D); - - /* setup src select and divider */ - cfg = readl(base + regs->cfg_rcgr); - cfg &= ~CFG_MASK; - cfg |= source & CFG_CLK_SRC_MASK; /* Select clock source */ - - /* Set the divider; HW permits fraction dividers (+0.5), but - for simplicity, we will support integers only */ - if (div) - cfg |= (2 * div - 1) & CFG_DIVIDER_MASK; - - if (n_val) - cfg |= CFG_MODE_DUAL_EDGE; - - writel(cfg, base + regs->cfg_rcgr); /* Write new clock configuration */ - - /* Inform h/w to start using the new config. */ - clk_bcr_update(base + regs->cmd_rcgr); -} - -/* root set rate for clocks with half integer and mnd_width=0 */ -void clk_rcg_set_rate(phys_addr_t base, const struct bcr_regs *regs, int div, - int source) -{ - u32 cfg; - - /* setup src select and divider */ - cfg = readl(base + regs->cfg_rcgr); - cfg &= ~CFG_MASK; - cfg |= source & CFG_CLK_SRC_MASK; /* Select clock source */ - - /* - * Set the divider; HW permits fraction dividers (+0.5), but - * for simplicity, we will support integers only - */ - if (div) - cfg |= (2 * div - 1) & CFG_DIVIDER_MASK; - - writel(cfg, base + regs->cfg_rcgr); /* Write new clock configuration */ - - /* Inform h/w to start using the new config. */ - clk_bcr_update(base + regs->cmd_rcgr); -} - -static int msm_clk_probe(struct udevice *dev) -{ - struct msm_clk_priv *priv = dev_get_priv(dev); - - priv->base = dev_read_addr(dev); - if (priv->base == FDT_ADDR_T_NONE) - return -EINVAL; - - return 0; -} - -static ulong msm_clk_set_rate(struct clk *clk, ulong rate) -{ - return msm_set_rate(clk, rate); -} - -static int msm_clk_enable(struct clk *clk) -{ - return msm_enable(clk); -} - -static struct clk_ops msm_clk_ops = { - .set_rate = msm_clk_set_rate, - .enable = msm_clk_enable, -}; - -static const struct udevice_id msm_clk_ids[] = { - { .compatible = "qcom,gcc-msm8916" }, - { .compatible = "qcom,gcc-apq8016" }, - { .compatible = "qcom,gcc-msm8996" }, - { .compatible = "qcom,gcc-apq8096" }, - { .compatible = "qcom,gcc-sdm845" }, - { .compatible = "qcom,gcc-qcs404" }, - { } -}; - -U_BOOT_DRIVER(clk_msm) = { - .name = "clk_msm", - .id = UCLASS_CLK, - .of_match = msm_clk_ids, - .ops = &msm_clk_ops, - .priv_auto = sizeof(struct msm_clk_priv), - .probe = msm_clk_probe, -}; diff --git a/arch/arm/mach-snapdragon/clock-snapdragon.h b/arch/arm/mach-snapdragon/clock-snapdragon.h deleted file mode 100644 index c90bbefa588..00000000000 --- a/arch/arm/mach-snapdragon/clock-snapdragon.h +++ /dev/null @@ -1,48 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Qualcomm APQ8016, APQ8096, SDM845 - * - * (C) Copyright 2017 Jorge Ramirez-Ortiz - */ -#ifndef _CLOCK_SNAPDRAGON_H -#define _CLOCK_SNAPDRAGON_H - -#define CFG_CLK_SRC_CXO (0 << 8) -#define CFG_CLK_SRC_GPLL0 (1 << 8) -#define CFG_CLK_SRC_GPLL0_EVEN (6 << 8) -#define CFG_CLK_SRC_MASK (7 << 8) - -struct pll_vote_clk { - uintptr_t status; - int status_bit; - uintptr_t ena_vote; - int vote_bit; -}; - -struct vote_clk { - uintptr_t cbcr_reg; - uintptr_t ena_vote; - int vote_bit; -}; -struct bcr_regs { - uintptr_t cfg_rcgr; - uintptr_t cmd_rcgr; - uintptr_t M; - uintptr_t N; - uintptr_t D; -}; - -struct msm_clk_priv { - phys_addr_t base; -}; - -void clk_enable_gpll0(phys_addr_t base, const struct pll_vote_clk *gpll0); -void clk_bcr_update(phys_addr_t apps_cmd_rgcr); -void clk_enable_cbc(phys_addr_t cbcr); -void clk_enable_vote_clk(phys_addr_t base, const struct vote_clk *vclk); -void clk_rcg_set_rate_mnd(phys_addr_t base, const struct bcr_regs *regs, - int div, int m, int n, int source); -void clk_rcg_set_rate(phys_addr_t base, const struct bcr_regs *regs, int div, - int source); - -#endif diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index bfd23a99046..017dd260a54 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -254,6 +254,7 @@ source "drivers/clk/meson/Kconfig" source "drivers/clk/microchip/Kconfig" source "drivers/clk/mvebu/Kconfig" source "drivers/clk/owl/Kconfig" +source "drivers/clk/qcom/Kconfig" source "drivers/clk/renesas/Kconfig" source "drivers/clk/sunxi/Kconfig" source "drivers/clk/sifive/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index af27ceb27da..638ad04baeb 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_CLK_MPFS) += microchip/ obj-$(CONFIG_CLK_MVEBU) += mvebu/ obj-$(CONFIG_CLK_OCTEON) += clk_octeon.o obj-$(CONFIG_CLK_OWL) += owl/ +obj-$(CONFIG_CLK_QCOM) += qcom/ obj-$(CONFIG_CLK_RENESAS) += renesas/ obj-$(CONFIG_$(SPL_TPL_)CLK_SCMI) += clk_scmi.o obj-$(CONFIG_CLK_SIFIVE) += sifive/ diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig new file mode 100644 index 00000000000..a884f077d9b --- /dev/null +++ b/drivers/clk/qcom/Kconfig @@ -0,0 +1,44 @@ +if ARCH_SNAPDRAGON || ARCH_IPQ40XX + +config CLK_QCOM + bool + depends on CLK && DM_RESET + def_bool n + +menu "Qualcomm clock drivers" + +config CLK_QCOM_APQ8016 + bool "Qualcomm APQ8016 GCC" + select CLK_QCOM + help + Say Y here to enable support for the Global Clock Controller + on the Snapdragon APQ8016 SoC. This driver supports the clocks + and resets exposed by the GCC hardware block. + +config CLK_QCOM_APQ8096 + bool "Qualcomm APQ8096 GCC" + select CLK_QCOM + help + Say Y here to enable support for the Global Clock Controller + on the Snapdragon APQ8096 SoC. This driver supports the clocks + and resets exposed by the GCC hardware block. + +config CLK_QCOM_QCS404 + bool "Qualcomm QCS404 GCC" + select CLK_QCOM + help + Say Y here to enable support for the Global Clock Controller + on the Snapdragon QCS404 SoC. This driver supports the clocks + and resets exposed by the GCC hardware block. + +config CLK_QCOM_SDM845 + bool "Qualcomm SDM845 GCC" + select CLK_QCOM + help + Say Y here to enable support for the Global Clock Controller + on the Snapdragon 845 SoC. This driver supports the clocks + and resets exposed by the GCC hardware block. + +endmenu + +endif diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile new file mode 100644 index 00000000000..44d55583596 --- /dev/null +++ b/drivers/clk/qcom/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# (C) Copyright 2023 Linaro + +obj-y += clock-qcom.o +obj-$(CONFIG_CLK_QCOM_SDM845) += clock-sdm845.o +obj-$(CONFIG_CLK_QCOM_APQ8016) += clock-apq8016.o +obj-$(CONFIG_CLK_QCOM_APQ8096) += clock-apq8096.o +obj-$(CONFIG_CLK_QCOM_QCS404) += clock-qcs404.o diff --git a/drivers/clk/qcom/clock-apq8016.c b/drivers/clk/qcom/clock-apq8016.c new file mode 100644 index 00000000000..90f2a93d9ed --- /dev/null +++ b/drivers/clk/qcom/clock-apq8016.c @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Clock drivers for Qualcomm APQ8016 + * + * (C) Copyright 2015 Mateusz Kulikowski + * + * Based on Little Kernel driver, simplified + */ + +#include +#include +#include +#include +#include +#include +#include "clock-qcom.h" + +/* GPLL0 clock control registers */ +#define GPLL0_STATUS_ACTIVE BIT(17) + +static const struct bcr_regs sdc_regs[] = { + { + .cfg_rcgr = SDCC_CFG_RCGR(1), + .cmd_rcgr = SDCC_CMD_RCGR(1), + .M = SDCC_M(1), + .N = SDCC_N(1), + .D = SDCC_D(1), + }, + { + .cfg_rcgr = SDCC_CFG_RCGR(2), + .cmd_rcgr = SDCC_CMD_RCGR(2), + .M = SDCC_M(2), + .N = SDCC_N(2), + .D = SDCC_D(2), + } +}; + +static struct pll_vote_clk gpll0_vote_clk = { + .status = GPLL0_STATUS, + .status_bit = GPLL0_STATUS_ACTIVE, + .ena_vote = APCS_GPLL_ENA_VOTE, + .vote_bit = BIT(0), +}; + +static struct vote_clk gcc_blsp1_ahb_clk = { + .cbcr_reg = BLSP1_AHB_CBCR, + .ena_vote = APCS_CLOCK_BRANCH_ENA_VOTE, + .vote_bit = BIT(10), +}; + +/* SDHCI */ +static int clk_init_sdc(struct msm_clk_priv *priv, int slot, uint rate) +{ + int div = 8; /* 100MHz default */ + + if (rate == 200000000) + div = 4; + + clk_enable_cbc(priv->base + SDCC_AHB_CBCR(slot)); + /* 800Mhz/div, gpll0 */ + clk_rcg_set_rate_mnd(priv->base, &sdc_regs[slot], div, 0, 0, + CFG_CLK_SRC_GPLL0); + clk_enable_gpll0(priv->base, &gpll0_vote_clk); + clk_enable_cbc(priv->base + SDCC_APPS_CBCR(slot)); + + return rate; +} + +static const struct bcr_regs uart2_regs = { + .cfg_rcgr = BLSP1_UART2_APPS_CFG_RCGR, + .cmd_rcgr = BLSP1_UART2_APPS_CMD_RCGR, + .M = BLSP1_UART2_APPS_M, + .N = BLSP1_UART2_APPS_N, + .D = BLSP1_UART2_APPS_D, +}; + +/* UART: 115200 */ +static int clk_init_uart(struct msm_clk_priv *priv) +{ + /* Enable AHB clock */ + clk_enable_vote_clk(priv->base, &gcc_blsp1_ahb_clk); + + /* 7372800 uart block clock @ GPLL0 */ + clk_rcg_set_rate_mnd(priv->base, &uart2_regs, 1, 144, 15625, + CFG_CLK_SRC_GPLL0); + + /* Vote for gpll0 clock */ + clk_enable_gpll0(priv->base, &gpll0_vote_clk); + + /* Enable core clk */ + clk_enable_cbc(priv->base + BLSP1_UART2_APPS_CBCR); + + return 0; +} + +ulong msm_set_rate(struct clk *clk, ulong rate) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + + switch (clk->id) { + case 0: /* SDC1 */ + return clk_init_sdc(priv, 0, rate); + break; + case 1: /* SDC2 */ + return clk_init_sdc(priv, 1, rate); + break; + case 4: /* UART2 */ + return clk_init_uart(priv); + break; + default: + return 0; + } +} + +int msm_enable(struct clk *clk) +{ + return 0; +} diff --git a/drivers/clk/qcom/clock-apq8096.c b/drivers/clk/qcom/clock-apq8096.c new file mode 100644 index 00000000000..d5388c69aef --- /dev/null +++ b/drivers/clk/qcom/clock-apq8096.c @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Clock drivers for Qualcomm APQ8096 + * + * (C) Copyright 2017 Jorge Ramirez Ortiz + * + * Based on Little Kernel driver, simplified + */ + +#include +#include +#include +#include +#include +#include + +#include "clock-qcom.h" + +/* GPLL0 clock control registers */ +#define GPLL0_STATUS_ACTIVE BIT(30) +#define APCS_GPLL_ENA_VOTE_GPLL0 BIT(0) + +static const struct bcr_regs sdc_regs = { + .cfg_rcgr = SDCC2_CFG_RCGR, + .cmd_rcgr = SDCC2_CMD_RCGR, + .M = SDCC2_M, + .N = SDCC2_N, + .D = SDCC2_D, +}; + +static const struct pll_vote_clk gpll0_vote_clk = { + .status = GPLL0_STATUS, + .status_bit = GPLL0_STATUS_ACTIVE, + .ena_vote = APCS_GPLL_ENA_VOTE, + .vote_bit = APCS_GPLL_ENA_VOTE_GPLL0, +}; + +static struct vote_clk gcc_blsp2_ahb_clk = { + .cbcr_reg = BLSP2_AHB_CBCR, + .ena_vote = APCS_CLOCK_BRANCH_ENA_VOTE, + .vote_bit = BIT(15), +}; + +static int clk_init_sdc(struct msm_clk_priv *priv, uint rate) +{ + int div = 3; + + clk_enable_cbc(priv->base + SDCC2_AHB_CBCR); + clk_rcg_set_rate_mnd(priv->base, &sdc_regs, div, 0, 0, + CFG_CLK_SRC_GPLL0); + clk_enable_gpll0(priv->base, &gpll0_vote_clk); + clk_enable_cbc(priv->base + SDCC2_APPS_CBCR); + + return rate; +} + +static const struct bcr_regs uart2_regs = { + .cfg_rcgr = BLSP2_UART2_APPS_CFG_RCGR, + .cmd_rcgr = BLSP2_UART2_APPS_CMD_RCGR, + .M = BLSP2_UART2_APPS_M, + .N = BLSP2_UART2_APPS_N, + .D = BLSP2_UART2_APPS_D, +}; + +static int clk_init_uart(struct msm_clk_priv *priv) +{ + /* Enable AHB clock */ + clk_enable_vote_clk(priv->base, &gcc_blsp2_ahb_clk); + + /* 7372800 uart block clock @ GPLL0 */ + clk_rcg_set_rate_mnd(priv->base, &uart2_regs, 1, 192, 15625, + CFG_CLK_SRC_GPLL0); + + /* Vote for gpll0 clock */ + clk_enable_gpll0(priv->base, &gpll0_vote_clk); + + /* Enable core clk */ + clk_enable_cbc(priv->base + BLSP2_UART2_APPS_CBCR); + + return 0; +} + +ulong msm_set_rate(struct clk *clk, ulong rate) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + + switch (clk->id) { + case 0: /* SDC1 */ + return clk_init_sdc(priv, rate); + break; + case 4: /*UART2*/ + return clk_init_uart(priv); + default: + return 0; + } +} + +int msm_enable(struct clk *clk) +{ + return 0; +} diff --git a/drivers/clk/qcom/clock-qcom.c b/drivers/clk/qcom/clock-qcom.c new file mode 100644 index 00000000000..5667abeb89a --- /dev/null +++ b/drivers/clk/qcom/clock-qcom.c @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Clock drivers for Qualcomm APQ8016, APQ8096 + * + * (C) Copyright 2015 Mateusz Kulikowski + * + * Based on Little Kernel driver, simplified + */ + +#include +#include +#include +#include +#include +#include +#include "clock-qcom.h" + +/* CBCR register fields */ +#define CBCR_BRANCH_ENABLE_BIT BIT(0) +#define CBCR_BRANCH_OFF_BIT BIT(31) + +extern ulong msm_set_rate(struct clk *clk, ulong rate); +extern int msm_enable(struct clk *clk); + +/* Enable clock controlled by CBC soft macro */ +void clk_enable_cbc(phys_addr_t cbcr) +{ + setbits_le32(cbcr, CBCR_BRANCH_ENABLE_BIT); + + while (readl(cbcr) & CBCR_BRANCH_OFF_BIT) + ; +} + +void clk_enable_gpll0(phys_addr_t base, const struct pll_vote_clk *gpll0) +{ + if (readl(base + gpll0->status) & gpll0->status_bit) + return; /* clock already enabled */ + + setbits_le32(base + gpll0->ena_vote, gpll0->vote_bit); + + while ((readl(base + gpll0->status) & gpll0->status_bit) == 0) + ; +} + +#define BRANCH_ON_VAL (0) +#define BRANCH_NOC_FSM_ON_VAL BIT(29) +#define BRANCH_CHECK_MASK GENMASK(31, 28) + +void clk_enable_vote_clk(phys_addr_t base, const struct vote_clk *vclk) +{ + u32 val; + + setbits_le32(base + vclk->ena_vote, vclk->vote_bit); + do { + val = readl(base + vclk->cbcr_reg); + val &= BRANCH_CHECK_MASK; + } while ((val != BRANCH_ON_VAL) && (val != BRANCH_NOC_FSM_ON_VAL)); +} + +#define APPS_CMD_RCGR_UPDATE BIT(0) + +/* Update clock command via CMD_RCGR */ +void clk_bcr_update(phys_addr_t apps_cmd_rcgr) +{ + setbits_le32(apps_cmd_rcgr, APPS_CMD_RCGR_UPDATE); + + /* Wait for frequency to be updated. */ + while (readl(apps_cmd_rcgr) & APPS_CMD_RCGR_UPDATE) + ; +} + +#define CFG_MODE_DUAL_EDGE (0x2 << 12) /* Counter mode */ + +#define CFG_MASK 0x3FFF + +#define CFG_DIVIDER_MASK 0x1F + +/* root set rate for clocks with half integer and MND divider */ +void clk_rcg_set_rate_mnd(phys_addr_t base, const struct bcr_regs *regs, + int div, int m, int n, int source) +{ + u32 cfg; + /* M value for MND divider. */ + u32 m_val = m; + /* NOT(N-M) value for MND divider. */ + u32 n_val = ~((n) - (m)) * !!(n); + /* NOT 2D value for MND divider. */ + u32 d_val = ~(n); + + /* Program MND values */ + writel(m_val, base + regs->M); + writel(n_val, base + regs->N); + writel(d_val, base + regs->D); + + /* setup src select and divider */ + cfg = readl(base + regs->cfg_rcgr); + cfg &= ~CFG_MASK; + cfg |= source & CFG_CLK_SRC_MASK; /* Select clock source */ + + /* Set the divider; HW permits fraction dividers (+0.5), but + for simplicity, we will support integers only */ + if (div) + cfg |= (2 * div - 1) & CFG_DIVIDER_MASK; + + if (n_val) + cfg |= CFG_MODE_DUAL_EDGE; + + writel(cfg, base + regs->cfg_rcgr); /* Write new clock configuration */ + + /* Inform h/w to start using the new config. */ + clk_bcr_update(base + regs->cmd_rcgr); +} + +/* root set rate for clocks with half integer and mnd_width=0 */ +void clk_rcg_set_rate(phys_addr_t base, const struct bcr_regs *regs, int div, + int source) +{ + u32 cfg; + + /* setup src select and divider */ + cfg = readl(base + regs->cfg_rcgr); + cfg &= ~CFG_MASK; + cfg |= source & CFG_CLK_SRC_MASK; /* Select clock source */ + + /* + * Set the divider; HW permits fraction dividers (+0.5), but + * for simplicity, we will support integers only + */ + if (div) + cfg |= (2 * div - 1) & CFG_DIVIDER_MASK; + + writel(cfg, base + regs->cfg_rcgr); /* Write new clock configuration */ + + /* Inform h/w to start using the new config. */ + clk_bcr_update(base + regs->cmd_rcgr); +} + +static int msm_clk_probe(struct udevice *dev) +{ + struct msm_clk_priv *priv = dev_get_priv(dev); + + priv->base = dev_read_addr(dev); + if (priv->base == FDT_ADDR_T_NONE) + return -EINVAL; + + return 0; +} + +static ulong msm_clk_set_rate(struct clk *clk, ulong rate) +{ + return msm_set_rate(clk, rate); +} + +static int msm_clk_enable(struct clk *clk) +{ + return msm_enable(clk); +} + +static struct clk_ops msm_clk_ops = { + .set_rate = msm_clk_set_rate, + .enable = msm_clk_enable, +}; + +static const struct udevice_id msm_clk_ids[] = { + { .compatible = "qcom,gcc-msm8916" }, + { .compatible = "qcom,gcc-apq8016" }, + { .compatible = "qcom,gcc-msm8996" }, + { .compatible = "qcom,gcc-apq8096" }, + { .compatible = "qcom,gcc-sdm845" }, + { .compatible = "qcom,gcc-qcs404" }, + { } +}; + +U_BOOT_DRIVER(clk_msm) = { + .name = "clk_msm", + .id = UCLASS_CLK, + .of_match = msm_clk_ids, + .ops = &msm_clk_ops, + .priv_auto = sizeof(struct msm_clk_priv), + .probe = msm_clk_probe, +}; diff --git a/drivers/clk/qcom/clock-qcom.h b/drivers/clk/qcom/clock-qcom.h new file mode 100644 index 00000000000..c90bbefa588 --- /dev/null +++ b/drivers/clk/qcom/clock-qcom.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Qualcomm APQ8016, APQ8096, SDM845 + * + * (C) Copyright 2017 Jorge Ramirez-Ortiz + */ +#ifndef _CLOCK_SNAPDRAGON_H +#define _CLOCK_SNAPDRAGON_H + +#define CFG_CLK_SRC_CXO (0 << 8) +#define CFG_CLK_SRC_GPLL0 (1 << 8) +#define CFG_CLK_SRC_GPLL0_EVEN (6 << 8) +#define CFG_CLK_SRC_MASK (7 << 8) + +struct pll_vote_clk { + uintptr_t status; + int status_bit; + uintptr_t ena_vote; + int vote_bit; +}; + +struct vote_clk { + uintptr_t cbcr_reg; + uintptr_t ena_vote; + int vote_bit; +}; +struct bcr_regs { + uintptr_t cfg_rcgr; + uintptr_t cmd_rcgr; + uintptr_t M; + uintptr_t N; + uintptr_t D; +}; + +struct msm_clk_priv { + phys_addr_t base; +}; + +void clk_enable_gpll0(phys_addr_t base, const struct pll_vote_clk *gpll0); +void clk_bcr_update(phys_addr_t apps_cmd_rgcr); +void clk_enable_cbc(phys_addr_t cbcr); +void clk_enable_vote_clk(phys_addr_t base, const struct vote_clk *vclk); +void clk_rcg_set_rate_mnd(phys_addr_t base, const struct bcr_regs *regs, + int div, int m, int n, int source); +void clk_rcg_set_rate(phys_addr_t base, const struct bcr_regs *regs, int div, + int source); + +#endif diff --git a/drivers/clk/qcom/clock-qcs404.c b/drivers/clk/qcom/clock-qcs404.c new file mode 100644 index 00000000000..80218af73ef --- /dev/null +++ b/drivers/clk/qcom/clock-qcs404.c @@ -0,0 +1,237 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Clock drivers for Qualcomm QCS404 + * + * (C) Copyright 2022 Sumit Garg + */ + +#include +#include +#include +#include +#include +#include +#include "clock-qcom.h" + +#include + +/* GPLL0 clock control registers */ +#define GPLL0_STATUS_ACTIVE BIT(31) + +#define CFG_CLK_SRC_GPLL1 BIT(8) +#define GPLL1_STATUS_ACTIVE BIT(31) + +static struct vote_clk gcc_blsp1_ahb_clk = { + .cbcr_reg = BLSP1_AHB_CBCR, + .ena_vote = APCS_CLOCK_BRANCH_ENA_VOTE, + .vote_bit = BIT(10) | BIT(5) | BIT(4), +}; + +static const struct bcr_regs uart2_regs = { + .cfg_rcgr = BLSP1_UART2_APPS_CFG_RCGR, + .cmd_rcgr = BLSP1_UART2_APPS_CMD_RCGR, + .M = BLSP1_UART2_APPS_M, + .N = BLSP1_UART2_APPS_N, + .D = BLSP1_UART2_APPS_D, +}; + +static const struct bcr_regs sdc_regs = { + .cfg_rcgr = SDCC_CFG_RCGR(1), + .cmd_rcgr = SDCC_CMD_RCGR(1), + .M = SDCC_M(1), + .N = SDCC_N(1), + .D = SDCC_D(1), +}; + +static struct pll_vote_clk gpll0_vote_clk = { + .status = GPLL0_STATUS, + .status_bit = GPLL0_STATUS_ACTIVE, + .ena_vote = APCS_GPLL_ENA_VOTE, + .vote_bit = BIT(0), +}; + +static struct pll_vote_clk gpll1_vote_clk = { + .status = GPLL1_STATUS, + .status_bit = GPLL1_STATUS_ACTIVE, + .ena_vote = APCS_GPLL_ENA_VOTE, + .vote_bit = BIT(1), +}; + +static const struct bcr_regs usb30_master_regs = { + .cfg_rcgr = USB30_MASTER_CFG_RCGR, + .cmd_rcgr = USB30_MASTER_CMD_RCGR, + .M = USB30_MASTER_M, + .N = USB30_MASTER_N, + .D = USB30_MASTER_D, +}; + +static const struct bcr_regs emac_regs = { + .cfg_rcgr = EMAC_CFG_RCGR, + .cmd_rcgr = EMAC_CMD_RCGR, + .M = EMAC_M, + .N = EMAC_N, + .D = EMAC_D, +}; + +static const struct bcr_regs emac_ptp_regs = { + .cfg_rcgr = EMAC_PTP_CFG_RCGR, + .cmd_rcgr = EMAC_PTP_CMD_RCGR, + .M = EMAC_M, + .N = EMAC_N, + .D = EMAC_D, +}; + +static const struct bcr_regs blsp1_qup0_i2c_apps_regs = { + .cmd_rcgr = BLSP1_QUP0_I2C_APPS_CMD_RCGR, + .cfg_rcgr = BLSP1_QUP0_I2C_APPS_CFG_RCGR, + /* mnd_width = 0 */ +}; + +static const struct bcr_regs blsp1_qup1_i2c_apps_regs = { + .cmd_rcgr = BLSP1_QUP1_I2C_APPS_CMD_RCGR, + .cfg_rcgr = BLSP1_QUP1_I2C_APPS_CFG_RCGR, + /* mnd_width = 0 */ +}; + +static const struct bcr_regs blsp1_qup2_i2c_apps_regs = { + .cmd_rcgr = BLSP1_QUP2_I2C_APPS_CMD_RCGR, + .cfg_rcgr = BLSP1_QUP2_I2C_APPS_CFG_RCGR, + /* mnd_width = 0 */ +}; + +static const struct bcr_regs blsp1_qup3_i2c_apps_regs = { + .cmd_rcgr = BLSP1_QUP3_I2C_APPS_CMD_RCGR, + .cfg_rcgr = BLSP1_QUP3_I2C_APPS_CFG_RCGR, + /* mnd_width = 0 */ +}; + +static const struct bcr_regs blsp1_qup4_i2c_apps_regs = { + .cmd_rcgr = BLSP1_QUP4_I2C_APPS_CMD_RCGR, + .cfg_rcgr = BLSP1_QUP4_I2C_APPS_CFG_RCGR, + /* mnd_width = 0 */ +}; + +ulong msm_set_rate(struct clk *clk, ulong rate) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + + switch (clk->id) { + case GCC_BLSP1_UART2_APPS_CLK: + /* UART: 115200 */ + clk_rcg_set_rate_mnd(priv->base, &uart2_regs, 0, 12, 125, + CFG_CLK_SRC_CXO); + clk_enable_cbc(priv->base + BLSP1_UART2_APPS_CBCR); + break; + case GCC_BLSP1_AHB_CLK: + clk_enable_vote_clk(priv->base, &gcc_blsp1_ahb_clk); + break; + case GCC_SDCC1_APPS_CLK: + /* SDCC1: 200MHz */ + clk_rcg_set_rate_mnd(priv->base, &sdc_regs, 4, 0, 0, + CFG_CLK_SRC_GPLL0); + clk_enable_gpll0(priv->base, &gpll0_vote_clk); + clk_enable_cbc(priv->base + SDCC_APPS_CBCR(1)); + break; + case GCC_SDCC1_AHB_CLK: + clk_enable_cbc(priv->base + SDCC_AHB_CBCR(1)); + break; + case GCC_ETH_RGMII_CLK: + if (rate == 250000000) + clk_rcg_set_rate_mnd(priv->base, &emac_regs, 2, 0, 0, + CFG_CLK_SRC_GPLL1); + else if (rate == 125000000) + clk_rcg_set_rate_mnd(priv->base, &emac_regs, 4, 0, 0, + CFG_CLK_SRC_GPLL1); + else if (rate == 50000000) + clk_rcg_set_rate_mnd(priv->base, &emac_regs, 10, 0, 0, + CFG_CLK_SRC_GPLL1); + else if (rate == 5000000) + clk_rcg_set_rate_mnd(priv->base, &emac_regs, 2, 1, 50, + CFG_CLK_SRC_GPLL1); + break; + default: + return 0; + } + + return 0; +} + +int msm_enable(struct clk *clk) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + + switch (clk->id) { + case GCC_USB30_MASTER_CLK: + clk_enable_cbc(priv->base + USB30_MASTER_CBCR); + clk_rcg_set_rate_mnd(priv->base, &usb30_master_regs, 4, 0, 0, + CFG_CLK_SRC_GPLL0); + break; + case GCC_SYS_NOC_USB3_CLK: + clk_enable_cbc(priv->base + SYS_NOC_USB3_CBCR); + break; + case GCC_USB30_SLEEP_CLK: + clk_enable_cbc(priv->base + USB30_SLEEP_CBCR); + break; + case GCC_USB30_MOCK_UTMI_CLK: + clk_enable_cbc(priv->base + USB30_MOCK_UTMI_CBCR); + break; + case GCC_USB_HS_PHY_CFG_AHB_CLK: + clk_enable_cbc(priv->base + USB_HS_PHY_CFG_AHB_CBCR); + break; + case GCC_USB2A_PHY_SLEEP_CLK: + clk_enable_cbc(priv->base + USB_HS_PHY_CFG_AHB_CBCR); + break; + case GCC_ETH_PTP_CLK: + /* SPEED_1000: freq -> 250MHz */ + clk_enable_cbc(priv->base + ETH_PTP_CBCR); + clk_enable_gpll0(priv->base, &gpll1_vote_clk); + clk_rcg_set_rate_mnd(priv->base, &emac_ptp_regs, 2, 0, 0, + CFG_CLK_SRC_GPLL1); + break; + case GCC_ETH_RGMII_CLK: + /* SPEED_1000: freq -> 250MHz */ + clk_enable_cbc(priv->base + ETH_RGMII_CBCR); + clk_enable_gpll0(priv->base, &gpll1_vote_clk); + clk_rcg_set_rate_mnd(priv->base, &emac_regs, 2, 0, 0, + CFG_CLK_SRC_GPLL1); + break; + case GCC_ETH_SLAVE_AHB_CLK: + clk_enable_cbc(priv->base + ETH_SLAVE_AHB_CBCR); + break; + case GCC_ETH_AXI_CLK: + clk_enable_cbc(priv->base + ETH_AXI_CBCR); + break; + case GCC_BLSP1_AHB_CLK: + clk_enable_vote_clk(priv->base, &gcc_blsp1_ahb_clk); + break; + case GCC_BLSP1_QUP0_I2C_APPS_CLK: + clk_enable_cbc(priv->base + BLSP1_QUP0_I2C_APPS_CBCR); + clk_rcg_set_rate(priv->base, &blsp1_qup0_i2c_apps_regs, 0, + CFG_CLK_SRC_CXO); + break; + case GCC_BLSP1_QUP1_I2C_APPS_CLK: + clk_enable_cbc(priv->base + BLSP1_QUP1_I2C_APPS_CBCR); + clk_rcg_set_rate(priv->base, &blsp1_qup1_i2c_apps_regs, 0, + CFG_CLK_SRC_CXO); + break; + case GCC_BLSP1_QUP2_I2C_APPS_CLK: + clk_enable_cbc(priv->base + BLSP1_QUP2_I2C_APPS_CBCR); + clk_rcg_set_rate(priv->base, &blsp1_qup2_i2c_apps_regs, 0, + CFG_CLK_SRC_CXO); + break; + case GCC_BLSP1_QUP3_I2C_APPS_CLK: + clk_enable_cbc(priv->base + BLSP1_QUP3_I2C_APPS_CBCR); + clk_rcg_set_rate(priv->base, &blsp1_qup3_i2c_apps_regs, 0, + CFG_CLK_SRC_CXO); + break; + case GCC_BLSP1_QUP4_I2C_APPS_CLK: + clk_enable_cbc(priv->base + BLSP1_QUP4_I2C_APPS_CBCR); + clk_rcg_set_rate(priv->base, &blsp1_qup4_i2c_apps_regs, 0, + CFG_CLK_SRC_CXO); + break; + default: + return 0; + } + + return 0; +} diff --git a/drivers/clk/qcom/clock-sdm845.c b/drivers/clk/qcom/clock-sdm845.c new file mode 100644 index 00000000000..95a057b8298 --- /dev/null +++ b/drivers/clk/qcom/clock-sdm845.c @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Clock drivers for Qualcomm SDM845 + * + * (C) Copyright 2017 Jorge Ramirez Ortiz + * (C) Copyright 2021 Dzmitry Sankouski + * + * Based on Little Kernel driver, simplified + */ + +#include +#include +#include +#include +#include +#include +#include +#include "clock-qcom.h" + +#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } + +struct freq_tbl { + uint freq; + uint src; + u8 pre_div; + u16 m; + u16 n; +}; + +static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = { + F(7372800, CFG_CLK_SRC_GPLL0_EVEN, 1, 384, 15625), + F(14745600, CFG_CLK_SRC_GPLL0_EVEN, 1, 768, 15625), + F(19200000, CFG_CLK_SRC_CXO, 1, 0, 0), + F(29491200, CFG_CLK_SRC_GPLL0_EVEN, 1, 1536, 15625), + F(32000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 8, 75), + F(48000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 4, 25), + F(64000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 16, 75), + F(80000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 4, 15), + F(96000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 8, 25), + F(100000000, CFG_CLK_SRC_GPLL0_EVEN, 3, 0, 0), + F(102400000, CFG_CLK_SRC_GPLL0_EVEN, 1, 128, 375), + F(112000000, CFG_CLK_SRC_GPLL0_EVEN, 1, 28, 75), + F(117964800, CFG_CLK_SRC_GPLL0_EVEN, 1, 6144, 15625), + F(120000000, CFG_CLK_SRC_GPLL0_EVEN, 2.5, 0, 0), + F(128000000, CFG_CLK_SRC_GPLL0, 1, 16, 75), + { } +}; + +static const struct bcr_regs uart2_regs = { + .cfg_rcgr = SE9_UART_APPS_CFG_RCGR, + .cmd_rcgr = SE9_UART_APPS_CMD_RCGR, + .M = SE9_UART_APPS_M, + .N = SE9_UART_APPS_N, + .D = SE9_UART_APPS_D, +}; + +const struct freq_tbl *qcom_find_freq(const struct freq_tbl *f, uint rate) +{ + if (!f) + return NULL; + + if (!f->freq) + return f; + + for (; f->freq; f++) + if (rate <= f->freq) + return f; + + /* Default to our fastest rate */ + return f - 1; +} + +static int clk_init_uart(struct msm_clk_priv *priv, uint rate) +{ + const struct freq_tbl *freq = qcom_find_freq(ftbl_gcc_qupv3_wrap0_s0_clk_src, rate); + + clk_rcg_set_rate_mnd(priv->base, &uart2_regs, + freq->pre_div, freq->m, freq->n, freq->src); + + return 0; +} + +ulong msm_set_rate(struct clk *clk, ulong rate) +{ + struct msm_clk_priv *priv = dev_get_priv(clk->dev); + + switch (clk->id) { + case GCC_QUPV3_WRAP1_S1_CLK: /*UART2*/ + return clk_init_uart(priv, rate); + default: + return 0; + } +} + +int msm_enable(struct clk *clk) +{ + return 0; +} -- cgit v1.3.1