On 8 February 2016 at 02:27, Mateusz Kulikowski <mateusz.kulikow...@gmail.com> 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 <mateusz.kulikow...@gmail.com> > Reviewed-by: Simon Glass <s...@chromium.org> > Tested-by: Simon Glass <s...@chromium.org> > --- > > Changes in v3: None > Changes in v2: > - Rename DM_SPMI -> SPMI > - Make MND divider comments more compact :) > - p -> priv > - Add reviewed-by > - Reordered Kconfig to keep alphabetical order > - Renamed reset_sandbox -> msm_reset (typo in reset.c) > > Changes in v1: > - Fix include order > - Cleanup defines (added spaces for readibility) > - Base address is integer to avoid casting > - Use setbits_* family where possible > - Drop unneded comments, added newlines where needed > - Check return value of dev_get_addr > - Add binding for apq8016 > - Cleaned up divider calculation > - Drop most of gpio.h (only empty file is needed) > > 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 | 9 + > .../mach-snapdragon/include/mach/sysmap-apq8016.h | 14 ++ > arch/arm/mach-snapdragon/reset.c | 40 ++++ > 8 files changed, 352 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
I think mach-qcom looks readable, I understand snapdragon is an soc name but why can't we place all qcom soc code to mach-qcom (I think Linux also doing the same)? > > diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig > index d2dbb1a..f16d0d9 100644 > --- a/arch/arm/Kconfig > +++ b/arch/arm/Kconfig > @@ -504,6 +504,16 @@ config RMOBILE > bool "Renesas ARM SoCs" > select CPU_V7 > > +config ARCH_SNAPDRAGON > + bool "Qualcomm Snapdragon SoCs" > + select ARM64 > + select DM > + select DM_GPIO > + select DM_SERIAL > + select SPMI > + select OF_CONTROL > + select OF_SEPARATE > + > config ARCH_SOCFPGA > bool "Altera SOCFPGA family" > select CPU_V7 > @@ -760,6 +770,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-stm32/Kconfig" > diff --git a/arch/arm/Makefile b/arch/arm/Makefile > index cd7d880..661de56 100644 > --- a/arch/arm/Makefile > +++ b/arch/arm/Makefile > @@ -54,6 +54,7 @@ machine-$(CONFIG_ARCH_MVEBU) += 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_STM32) += stm32 > 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 <mateusz.kulikow...@gmail.com> > +# > +# 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..d548d75 > --- /dev/null > +++ b/arch/arm/mach-snapdragon/clock-apq8016.c > @@ -0,0 +1,262 @@ > +/* > + * Clock drivers for Qualcomm APQ8016 > + * > + * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikow...@gmail.com> > + * > + * Based on Little Kernel driver, simplified > + * > + * SPDX-License-Identifier: BSD-3-Clause > + */ > + > +#include <common.h> > +#include <clk.h> > +#include <dm.h> > +#include <errno.h> > +#include <asm/io.h> > +#include <linux/bitops.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), > + .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 *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); > + 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, > +}; > + > +/* Init UART clock, 115200 */ > +static int clk_init_uart(struct msm_clk_priv *priv) > +{ > + /* Enable iface clk */ > + clk_enable_cbc(priv->base + BLSP1_AHB_CBCR); > + /* 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); > + /* Enable core clk */ > + clk_enable_cbc(priv->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; > + } > +} > + > +static int msm_clk_probe(struct udevice *dev) > +{ > + struct msm_clk_priv *priv = dev_get_priv(dev); > + > + priv->base = dev_get_addr(dev); > + if (priv->base == FDT_ADDR_T_NONE) > + return -EINVAL; > + > + 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" }, > + { .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/include/mach/gpio.h > b/arch/arm/mach-snapdragon/include/mach/gpio.h > new file mode 100644 > index 0000000..ff949b2 > --- /dev/null > +++ b/arch/arm/mach-snapdragon/include/mach/gpio.h > @@ -0,0 +1,9 @@ > +/* > + * Empty gpio.h > + * > + * This file must stay as arch/arm/include/asm/gpio.h requires it. > + * > + * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikow...@gmail.com> > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > 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..cdbfad0 > --- /dev/null > +++ b/arch/arm/mach-snapdragon/include/mach/sysmap-apq8016.h > @@ -0,0 +1,14 @@ > +/* > + * Qualcomm APQ8916 sysmap > + * > + * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikow...@gmail.com> > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > +#ifndef _MACH_SYSMAP_APQ8016_H > +#define _MACH_SYSMAP_APQ8016_H > + > +#define GICD_BASE 0x0b000000 > +#define GICC_BASE 0x0a20c000 > + > +#endif > diff --git a/arch/arm/mach-snapdragon/reset.c > b/arch/arm/mach-snapdragon/reset.c > new file mode 100644 > index 0000000..2627eec > --- /dev/null > +++ b/arch/arm/mach-snapdragon/reset.c > @@ -0,0 +1,40 @@ > +/* > + * Qualcomm APQ8016 reset controller driver > + * > + * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikow...@gmail.com> > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > + > +#include <common.h> > +#include <dm.h> > +#include <errno.h> > +#include <reset.h> > +#include <asm/io.h> > + > +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(msm_reset) = { > + .name = "msm_reset", > + .id = UCLASS_RESET, > + .of_match = msm_reset_ids, > + .ops = &msm_reset_ops, > +}; > -- > 2.5.0 > > _______________________________________________ > U-Boot mailing list > U-Boot@lists.denx.de > http://lists.denx.de/mailman/listinfo/u-boot -- Jagan. _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot