From: Jorge Ramirez-Ortiz Date: Wed, 10 Jan 2018 10:33:49 +0000 (+0100) Subject: arm: mach-snapdragon: refactor clock driver X-Git-Url: http://git.ipfire.org/?p=people%2Fms%2Fu-boot.git;a=commitdiff_plain;h=7c75f7f1b29eb53912b75472f4d8135c465f87f5 arm: mach-snapdragon: refactor clock driver In preparation to add support for the Dragonboard820c (APQ8096), refactor the current Snapdragon clock driver. No new functionality has been added. Signed-off-by: Jorge Ramirez-Ortiz --- diff --git a/arch/arm/mach-snapdragon/Makefile b/arch/arm/mach-snapdragon/Makefile index d82a04dda6..d798b82f07 100644 --- a/arch/arm/mach-snapdragon/Makefile +++ b/arch/arm/mach-snapdragon/Makefile @@ -4,5 +4,6 @@ # SPDX-License-Identifier: GPL-2.0+ # -obj-y += clock-apq8016.o -obj-y += sysmap-apq8016.o +obj-$(CONFIG_TARGET_DRAGONBOARD410C) += clock-apq8016.o +obj-$(CONFIG_TARGET_DRAGONBOARD410C) += sysmap-apq8016.o +obj-y += clock-snapdragon.o diff --git a/arch/arm/mach-snapdragon/clock-apq8016.c b/arch/arm/mach-snapdragon/clock-apq8016.c index da05015c32..a2424178c6 100644 --- a/arch/arm/mach-snapdragon/clock-apq8016.c +++ b/arch/arm/mach-snapdragon/clock-apq8016.c @@ -14,146 +14,12 @@ #include #include #include +#include "clock-snapdragon.h" /* GPLL0 clock control registers */ -#define GPLL0_STATUS 0x2101C #define GPLL0_STATUS_ACTIVE BIT(17) - -#define APCS_GPLL_ENA_VOTE 0x45000 #define APCS_GPLL_ENA_VOTE_GPLL0 BIT(0) -/* vote reg for blsp1 clock */ -#define APCS_CLOCK_BRANCH_ENA_VOTE 0x45004 -#define APCS_CLOCK_BRANCH_ENA_VOTE_BLSP1 BIT(10) - -/* SDC(n) clock control registers; n=1,2 */ - -/* block control register */ -#define SDCC_BCR(n) ((n * 0x1000) + 0x41000) -/* cmd */ -#define SDCC_CMD_RCGR(n) ((n * 0x1000) + 0x41004) -/* cfg */ -#define SDCC_CFG_RCGR(n) ((n * 0x1000) + 0x41008) -/* m */ -#define SDCC_M(n) ((n * 0x1000) + 0x4100C) -/* n */ -#define SDCC_N(n) ((n * 0x1000) + 0x41010) -/* d */ -#define SDCC_D(n) ((n * 0x1000) + 0x41014) -/* branch control */ -#define SDCC_APPS_CBCR(n) ((n * 0x1000) + 0x41018) -#define SDCC_AHB_CBCR(n) ((n * 0x1000) + 0x4101C) - -/* BLSP1 AHB clock (root clock for BLSP) */ -#define BLSP1_AHB_CBCR 0x1008 - -/* Uart clock control registers */ -#define BLSP1_UART2_BCR 0x3028 -#define BLSP1_UART2_APPS_CBCR 0x302C -#define BLSP1_UART2_APPS_CMD_RCGR 0x3034 -#define BLSP1_UART2_APPS_CFG_RCGR 0x3038 -#define BLSP1_UART2_APPS_M 0x303C -#define BLSP1_UART2_APPS_N 0x3040 -#define BLSP1_UART2_APPS_D 0x3044 - -/* CBCR register fields */ -#define CBCR_BRANCH_ENABLE_BIT BIT(0) -#define CBCR_BRANCH_OFF_BIT BIT(31) - -struct msm_clk_priv { - phys_addr_t base; -}; - -/* Enable clock controlled by CBC soft macro */ -static void clk_enable_cbc(phys_addr_t cbcr) -{ - setbits_le32(cbcr, CBCR_BRANCH_ENABLE_BIT); - - while (readl(cbcr) & CBCR_BRANCH_OFF_BIT) - ; -} - -/* clock has 800MHz */ -static void clk_enable_gpll0(phys_addr_t base) -{ - if (readl(base + GPLL0_STATUS) & GPLL0_STATUS_ACTIVE) - return; /* clock already enabled */ - - setbits_le32(base + APCS_GPLL_ENA_VOTE, APCS_GPLL_ENA_VOTE_GPLL0); - - while ((readl(base + GPLL0_STATUS) & GPLL0_STATUS_ACTIVE) == 0) - ; -} - -#define APPS_CMD_RGCR_UPDATE BIT(0) - -/* Update clock command via CMD_RGCR */ -static void clk_bcr_update(phys_addr_t apps_cmd_rgcr) -{ - setbits_le32(apps_cmd_rgcr, APPS_CMD_RGCR_UPDATE); - - /* Wait for frequency to be updated. */ - while (readl(apps_cmd_rgcr) & APPS_CMD_RGCR_UPDATE) - ; -} - -struct bcr_regs { - uintptr_t cfg_rcgr; - uintptr_t cmd_rcgr; - uintptr_t M; - uintptr_t N; - uintptr_t D; -}; - -/* RCGR_CFG register fields */ -#define CFG_MODE_DUAL_EDGE (0x2 << 12) /* Counter mode */ - -/* sources */ -#define CFG_CLK_SRC_CXO (0 << 8) -#define CFG_CLK_SRC_GPLL0 (1 << 8) -#define CFG_CLK_SRC_MASK (7 << 8) - -/* Mask for supported fields */ -#define CFG_MASK 0x3FFF - -#define CFG_DIVIDER_MASK 0x1F - -/* root set rate for clocks with half integer and MND divider */ -static void clk_rcg_set_rate_mnd(phys_addr_t base, const struct bcr_regs *regs, - int div, int m, int n, int source) -{ - uint32_t cfg; - /* M value for MND divider. */ - uint32_t m_val = m; - /* NOT(N-M) value for MND divider. */ - uint32_t n_val = ~((n)-(m)) * !!(n); - /* NOT 2D value for MND divider. */ - uint32_t 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); -} - static const struct bcr_regs sdc_regs[] = { { .cfg_rcgr = SDCC_CFG_RCGR(1), @@ -171,7 +37,14 @@ static const struct bcr_regs sdc_regs[] = { } }; -/* Init clock for SDHCI controller */ +static struct gpll0_ctrl gpll0_ctrl = { + .status = GPLL0_STATUS, + .status_bit = GPLL0_STATUS_ACTIVE, + .ena_vote = APCS_GPLL_ENA_VOTE, + .vote_bit = APCS_GPLL_ENA_VOTE_GPLL0, +}; + +/* SDHCI */ static int clk_init_sdc(struct msm_clk_priv *priv, int slot, uint rate) { int div = 8; /* 100MHz default */ @@ -183,7 +56,7 @@ static int clk_init_sdc(struct msm_clk_priv *priv, int slot, uint rate) /* 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); + clk_enable_gpll0(priv->base, &gpll0_ctrl); clk_enable_cbc(priv->base + SDCC_APPS_CBCR(slot)); return rate; @@ -197,7 +70,7 @@ static const struct bcr_regs uart2_regs = { .D = BLSP1_UART2_APPS_D, }; -/* Init UART clock, 115200 */ +/* UART: 115200 */ static int clk_init_uart(struct msm_clk_priv *priv) { /* Enable iface clk */ @@ -205,7 +78,7 @@ static int clk_init_uart(struct msm_clk_priv *priv) /* 7372800 uart block clock @ GPLL0 */ clk_rcg_set_rate_mnd(priv->base, &uart2_regs, 1, 144, 15625, CFG_CLK_SRC_GPLL0); - clk_enable_gpll0(priv->base); + clk_enable_gpll0(priv->base, &gpll0_ctrl); /* Enable core clk */ clk_enable_cbc(priv->base + BLSP1_UART2_APPS_CBCR); @@ -230,33 +103,3 @@ ulong msm_set_rate(struct clk *clk, ulong rate) return 0; } } - -static int msm_clk_probe(struct udevice *dev) -{ - struct msm_clk_priv *priv = dev_get_priv(dev); - - priv->base = devfdt_get_addr(dev); - if (priv->base == FDT_ADDR_T_NONE) - return -EINVAL; - - return 0; -} - -static struct clk_ops msm_clk_ops = { - .set_rate = msm_set_rate, -}; - -static const struct udevice_id msm_clk_ids[] = { - { .compatible = "qcom,gcc-msm8916" }, - { .compatible = "qcom,gcc-apq8016" }, - { } -}; - -U_BOOT_DRIVER(clk_msm) = { - .name = "clk_msm", - .id = UCLASS_CLK, - .of_match = msm_clk_ids, - .ops = &msm_clk_ops, - .priv_auto_alloc_size = sizeof(struct msm_clk_priv), - .probe = msm_clk_probe, -}; diff --git a/arch/arm/mach-snapdragon/clock-snapdragon.c b/arch/arm/mach-snapdragon/clock-snapdragon.c new file mode 100644 index 0000000000..899b5ba6ce --- /dev/null +++ b/arch/arm/mach-snapdragon/clock-snapdragon.c @@ -0,0 +1,134 @@ +/* + * Clock drivers for Qualcomm APQ8016, APQ8096 + * + * (C) Copyright 2015 Mateusz Kulikowski + * + * Based on Little Kernel driver, simplified + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#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); + +/* 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 gpll0_ctrl *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 APPS_CMD_RGCR_UPDATE BIT(0) + +/* Update clock command via CMD_RGCR */ +void clk_bcr_update(phys_addr_t apps_cmd_rgcr) +{ + setbits_le32(apps_cmd_rgcr, APPS_CMD_RGCR_UPDATE); + + /* Wait for frequency to be updated. */ + while (readl(apps_cmd_rgcr) & APPS_CMD_RGCR_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); +} + +static int msm_clk_probe(struct udevice *dev) +{ + struct msm_clk_priv *priv = dev_get_priv(dev); + + priv->base = devfdt_get_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 struct clk_ops msm_clk_ops = { + .set_rate = msm_clk_set_rate, +}; + +static const struct udevice_id msm_clk_ids[] = { + { .compatible = "qcom,gcc-msm8916" }, + { .compatible = "qcom,gcc-apq8016" }, + { .compatible = "qcom,gcc-msm8996" }, + { .compatible = "qcom,gcc-apq8096" }, + { } +}; + +U_BOOT_DRIVER(clk_msm) = { + .name = "clk_msm", + .id = UCLASS_CLK, + .of_match = msm_clk_ids, + .ops = &msm_clk_ops, + .priv_auto_alloc_size = 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 new file mode 100644 index 0000000000..d7026aa867 --- /dev/null +++ b/arch/arm/mach-snapdragon/clock-snapdragon.h @@ -0,0 +1,40 @@ +/* + * Qualcomm APQ8016, APQ8096 + * + * (C) Copyright 2017 Jorge Ramirez-Ortiz + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#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_MASK (7 << 8) + +struct gpll0_ctrl { + uintptr_t status; + int status_bit; + 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 gpll0_ctrl *pll0); +void clk_bcr_update(phys_addr_t apps_cmd_rgcr); +void clk_enable_cbc(phys_addr_t cbcr); +void clk_rcg_set_rate_mnd(phys_addr_t base, const struct bcr_regs *regs, + int div, int m, int n, int source); + +#endif diff --git a/arch/arm/mach-snapdragon/include/mach/sysmap-apq8016.h b/arch/arm/mach-snapdragon/include/mach/sysmap-apq8016.h index cdbfad0def..1094b14a80 100644 --- a/arch/arm/mach-snapdragon/include/mach/sysmap-apq8016.h +++ b/arch/arm/mach-snapdragon/include/mach/sysmap-apq8016.h @@ -8,7 +8,32 @@ #ifndef _MACH_SYSMAP_APQ8016_H #define _MACH_SYSMAP_APQ8016_H -#define GICD_BASE 0x0b000000 -#define GICC_BASE 0x0a20c000 +#define GICD_BASE (0x0b000000) +#define GICC_BASE (0x0a20c000) + +/* Clocks: (from CLK_CTL_BASE) */ +#define GPLL0_STATUS (0x2101C) +#define APCS_GPLL_ENA_VOTE (0x45000) + +#define SDCC_BCR(n) ((n * 0x1000) + 0x41000) +#define SDCC_CMD_RCGR(n) ((n * 0x1000) + 0x41004) +#define SDCC_CFG_RCGR(n) ((n * 0x1000) + 0x41008) +#define SDCC_M(n) ((n * 0x1000) + 0x4100C) +#define SDCC_N(n) ((n * 0x1000) + 0x41010) +#define SDCC_D(n) ((n * 0x1000) + 0x41014) +#define SDCC_APPS_CBCR(n) ((n * 0x1000) + 0x41018) +#define SDCC_AHB_CBCR(n) ((n * 0x1000) + 0x4101C) + +/* BLSP1 AHB clock (root clock for BLSP) */ +#define BLSP1_AHB_CBCR 0x1008 + +/* Uart clock control registers */ +#define BLSP1_UART2_BCR (0x3028) +#define BLSP1_UART2_APPS_CBCR (0x302C) +#define BLSP1_UART2_APPS_CMD_RCGR (0x3034) +#define BLSP1_UART2_APPS_CFG_RCGR (0x3038) +#define BLSP1_UART2_APPS_M (0x303C) +#define BLSP1_UART2_APPS_N (0x3040) +#define BLSP1_UART2_APPS_D (0x3044) #endif