From mboxrd@z Thu Jan 1 00:00:00 1970 From: Simon Glass Date: Wed, 16 Dec 2015 15:29:33 -0700 Subject: [U-Boot] [RFC PATCH 10/11] arm: Add support for Qualcomm Snapdragon family In-Reply-To: <1449783707-23594-11-git-send-email-mateusz.kulikowski@gmail.com> References: <1449783707-23594-1-git-send-email-mateusz.kulikowski@gmail.com> <1449783707-23594-11-git-send-email-mateusz.kulikowski@gmail.com> Message-ID: List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de Hi Mateusz, On 10 December 2015 at 14:41, Mateusz Kulikowski wrote: > > First supported chip is APQ8016 (that is compatible with MSM8916). > Drivers in SoC code: > - Reset controller (PSHOLD) > - Clock controller (very simple clock configuration for MMC and UART) > > Signed-off-by: Mateusz Kulikowski > --- > > arch/arm/Kconfig | 12 + > arch/arm/Makefile | 1 + > arch/arm/mach-snapdragon/Kconfig | 6 + > arch/arm/mach-snapdragon/Makefile | 8 + > arch/arm/mach-snapdragon/clock-apq8016.c | 262 +++++++++++++++++++++ > arch/arm/mach-snapdragon/include/mach/gpio.h | 25 ++ > .../mach-snapdragon/include/mach/sysmap-apq8016.h | 15 ++ > arch/arm/mach-snapdragon/reset.c | 40 ++++ > 8 files changed, 369 insertions(+) > create mode 100644 arch/arm/mach-snapdragon/Kconfig > create mode 100644 arch/arm/mach-snapdragon/Makefile > create mode 100644 arch/arm/mach-snapdragon/clock-apq8016.c > create mode 100644 arch/arm/mach-snapdragon/include/mach/gpio.h > create mode 100644 arch/arm/mach-snapdragon/include/mach/sysmap-apq8016.h > create mode 100644 arch/arm/mach-snapdragon/reset.c > > diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig > index fb9176b..0241980 100644 > --- a/arch/arm/Kconfig > +++ b/arch/arm/Kconfig > @@ -493,6 +493,16 @@ config OMAP54XX > select CPU_V7 > select SUPPORT_SPL > > +config ARCH_SNAPDRAGON > + bool "Qualcomm Snapdragon SoCs" > + select ARM64 > + select DM > + select DM_GPIO > + select DM_SERIAL > + select DM_SPMI > + select OF_CONTROL > + select OF_SEPARATE > + > config RMOBILE > bool "Renesas ARM SoCs" > select CPU_V7 > @@ -745,6 +755,8 @@ source "arch/arm/mach-rockchip/Kconfig" > > source "arch/arm/mach-s5pc1xx/Kconfig" > > +source "arch/arm/mach-snapdragon/Kconfig" > + > source "arch/arm/mach-socfpga/Kconfig" > > source "arch/arm/mach-tegra/Kconfig" > diff --git a/arch/arm/Makefile b/arch/arm/Makefile > index 18283d1..b977309 100644 > --- a/arch/arm/Makefile > +++ b/arch/arm/Makefile > @@ -54,6 +54,7 @@ machine-$(CONFIG_ARMADA_XP) += mvebu > # TODO: rename CONFIG_ORION5X -> CONFIG_ARCH_ORION5X > machine-$(CONFIG_ORION5X) += orion5x > machine-$(CONFIG_ARCH_S5PC1XX) += s5pc1xx > +machine-$(CONFIG_ARCH_SNAPDRAGON) += snapdragon > machine-$(CONFIG_ARCH_SOCFPGA) += socfpga > machine-$(CONFIG_ARCH_ROCKCHIP) += rockchip > machine-$(CONFIG_TEGRA) += tegra > diff --git a/arch/arm/mach-snapdragon/Kconfig b/arch/arm/mach-snapdragon/Kconfig > new file mode 100644 > index 0000000..156e733 > --- /dev/null > +++ b/arch/arm/mach-snapdragon/Kconfig > @@ -0,0 +1,6 @@ > +if ARCH_SNAPDRAGON > + > +config SYS_SOC > + default "snapdragon" > + > +endif > diff --git a/arch/arm/mach-snapdragon/Makefile b/arch/arm/mach-snapdragon/Makefile > new file mode 100644 > index 0000000..8e84705 > --- /dev/null > +++ b/arch/arm/mach-snapdragon/Makefile > @@ -0,0 +1,8 @@ > +# > +# (C) Copyright 2015 Mateusz Kulikowski > +# > +# SPDX-License-Identifier: GPL-2.0+ > +# > + > +obj-y += clock-apq8016.o > +obj-y += reset.o > diff --git a/arch/arm/mach-snapdragon/clock-apq8016.c b/arch/arm/mach-snapdragon/clock-apq8016.c > new file mode 100644 > index 0000000..c8c15b4 > --- /dev/null > +++ b/arch/arm/mach-snapdragon/clock-apq8016.c Can this go in drivers/clk? > @@ -0,0 +1,262 @@ > +/* > + * Clock drivers for Qualcomm APQ8016 > + * > + * (C) Copyright 2015 Mateusz Kulikowski > + * > + * Based on Little Kernel driver, simplified > + * > + * SPDX-License-Identifier: BSD-3-Clause > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include Ordering - please fix globally. > + > +/* 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 reset*/ /* block reset */ > +#define SDCC_BCR(n) (((n*0x1000)) + 0x41000) Can you put spaces around operators? (n * 0x1000) > +/* 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 { > + void *base; You might consider using a struct to access registers to avoid all the void * but it is up to you - we do both now. > +}; > + > +/* Enable clock controlled by CBC soft macro */ > +static void clk_enable_cbc(void *cbcr) > +{ > + uint32_t val = readl(cbcr); blank line > + val |= CBCR_BRANCH_ENABLE_BIT; > + writel(val, cbcr); > + > + while (readl(cbcr) & CBCR_BRANCH_OFF_BIT) > + ; > +} > + > +/* clock has 800MHz */ > +static void clk_enable_gpll0(void *base) > +{ > + uint32_t ena; > + > + if (readl(base + GPLL0_STATUS) & GPLL0_STATUS_ACTIVE) > + return; /* clock already enabled */ > + > + ena = readl(base + APCS_GPLL_ENA_VOTE); > + ena |= APCS_GPLL_ENA_VOTE_GPLL0; > + writel(ena, base + APCS_GPLL_ENA_VOTE); setbits_le32(base + APCS_GPLL_ENA_VOTE, APCS_GPLL_ENA_VOTE_GPLL0) Similarly below. > + > + 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(void *apps_cmd_rgcr) > +{ > + uint32_t cmd; > + > + cmd = readl(apps_cmd_rgcr); > + cmd |= APPS_CMD_RGCR_UPDATE; > + writel(cmd, apps_cmd_rgcr); > + > + /* 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 BM(msb, lsb) (((((uint32_t)-1) << (31-msb)) >> (31-msb+lsb)) << lsb) > +#define BVAL(msb, lsb, val) (((val) << lsb) & BM(msb, lsb)) Best to avoid these sorts of things if possible, and just use MASK and SHIFT #defines. > + > +/* root set rate for clocks with half integer and MND divider */ > +static void clk_rcg_set_rate_mnd(void *base, const struct bcr_regs *regs, > + int div, int m, int n, int source) > +{ > + uint32_t cfg; > + /* This register houses the M value for MND divider. */ > + uint32_t m_val = m; > + /* This register houses the NOT(N-M) value for MND divider. */ > + uint32_t n_val = ~((n)-(m)) * !!(n); > + /* This register houses the NOT 2D value for MND divider. */ > + uint32_t d_val = ~(n); > + > + /* Program MND values */ > + writel(m_val, base + regs->M); /* M */ > + writel(n_val, base + regs->N); /* N */ > + writel(d_val, base + regs->D); /* D */ Those 3 comments don't seem useful. > + > + /* setup src select and divider */ > + cfg = readl(base + regs->cfg_rcgr); > + cfg &= ~CFG_MASK; > + cfg |= source & CFG_CLK_SRC_MASK; /* Select clock source */ > + cfg |= BVAL(4, 0, (int)(2*(div) - 1)) | BVAL(10, 8, source); > + 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), > + .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), > + } > +}; > + > +/* Init clock for SDHCI controller */ > +static int clk_init_sdc(struct msm_clk_priv *p, int slot, uint rate) > +{ > + int div = 8; /* 100MHz default */ > + > + if (rate == 200000000) > + div = 4; > + > + clk_enable_cbc(p->base + SDCC_AHB_CBCR(slot)); > + /* 800Mhz/div, gpll0 */ > + clk_rcg_set_rate_mnd(p->base, &sdc_regs[slot], div, 0, 0, > + CFG_CLK_SRC_GPLL0); > + clk_enable_gpll0(p->base); > + clk_enable_cbc(p->base + SDCC_APPS_CBCR(slot)); blank line before return > + 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, > +}; > + > +/* Init UART clock, 115200 */ > +static int clk_init_uart(struct msm_clk_priv *p) > +{ > + /* Enable iface clk */ > + clk_enable_cbc(p->base + BLSP1_AHB_CBCR); > + /* 7372800 uart block clock @ GPLL0 */ > + clk_rcg_set_rate_mnd(p->base, &uart2_regs, 1, 144, 15625, > + CFG_CLK_SRC_GPLL0); > + clk_enable_gpll0(p->base); > + /* Enable core clk */ > + clk_enable_cbc(p->base + BLSP1_UART2_APPS_CBCR); > + return 0; > +} > + > +ulong msm_set_periph_rate(struct udevice *dev, int periph, ulong rate) > +{ > + struct msm_clk_priv *priv = dev_get_priv(dev); > + > + switch (periph) { > + 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; > + } > + return 0; > +} > + > +static int msm_clk_probe(struct udevice *dev) > +{ > + struct msm_clk_priv *priv = dev_get_priv(dev); > + priv->base = (void *)dev_get_addr(dev); > + return 0; > +} > + > +static struct clk_ops msm_clk_ops = { > + .set_periph_rate = msm_set_periph_rate, > +}; > + > +static const struct udevice_id msm_clk_ids[] = { > + { .compatible = "qcom,gcc-msm8916" }, > + { } > +}; > + > +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/include/mach/gpio.h b/arch/arm/mach-snapdragon/include/mach/gpio.h > new file mode 100644 > index 0000000..e2ce28b > --- /dev/null > +++ b/arch/arm/mach-snapdragon/include/mach/gpio.h Should this go in a different patch? I thought you had a GPIO driver earlier? > @@ -0,0 +1,25 @@ > +/* > + * Qualcomm GPIO definitions > + * > + * (C) Copyright 2015 Mateusz Kulikowski > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > +#ifndef _MACH_GPIO_H > +#define _MACH_GPIO_H > + > +/* Register offsets */ > +#define GPIO_CONFIG_OFF(no) ((no)*0x1000) > +#define GPIO_IN_OUT_OFF(no) ((no)*0x1000 + 0x4) > + > +/* OE */ > +#define GPIO_OE_DISABLE (0x0 << 9) > +#define GPIO_OE_ENABLE (0x1 << 9) > +#define GPIO_OE_MASK (0x1 << 9) > + > +/* GPIO_IN_OUT register shifts. */ > +#define GPIO_IN 0 > +#define GPIO_OUT 1 > + > +#endif /* _ASM_ARCH_GPIO_H */ > + > diff --git a/arch/arm/mach-snapdragon/include/mach/sysmap-apq8016.h b/arch/arm/mach-snapdragon/include/mach/sysmap-apq8016.h > new file mode 100644 > index 0000000..32bc761 > --- /dev/null > +++ b/arch/arm/mach-snapdragon/include/mach/sysmap-apq8016.h > @@ -0,0 +1,15 @@ > +/* > + * Qualcomm APQ8916 sysmap > + * > + * (C) Copyright 2015 Mateusz Kulikowski > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > +#ifndef _MACH_APQ8016_SYSMAP_H > +#define _MACH_APQ8016_SYSMAP_H > + > +#define GICD_BASE 0x0b000000 > +#define GICC_BASE 0x0a20c000 Do you need these? Perhaps they can go in the device tree? > + > +#endif > + > diff --git a/arch/arm/mach-snapdragon/reset.c b/arch/arm/mach-snapdragon/reset.c > new file mode 100644 > index 0000000..ade3237 > --- /dev/null > +++ b/arch/arm/mach-snapdragon/reset.c > @@ -0,0 +1,40 @@ > +/* > + * Qualcomm APQ8016 reset controller driver > + * > + * (C) Copyright 2015 Mateusz Kulikowski > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > + > +#include > +#include > +#include > +#include > +#include > + > +DECLARE_GLOBAL_DATA_PTR; > + > +static int msm_reset_request(struct udevice *dev, enum reset_t type) > +{ > + phys_addr_t addr = dev_get_addr(dev); > + if (!addr) > + return -EINVAL; > + writel(0, addr); > + return -EINPROGRESS; > +} > + > +static struct reset_ops msm_reset_ops = { > + .request = msm_reset_request, > +}; > + > +static const struct udevice_id msm_reset_ids[] = { > + { .compatible = "qcom,pshold" }, > + { } > +}; > + > +U_BOOT_DRIVER(reset_sandbox) = { > + .name = "msm_reset", > + .id = UCLASS_RESET, > + .of_match = msm_reset_ids, > + .ops = &msm_reset_ops, > +}; > -- > 2.5.0 > Regards, Simon