From patchwork Thu Mar 31 21:12:32 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mateusz Kulikowski X-Patchwork-Id: 604517 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 3qbclN5yfLz9sBf for ; Fri, 1 Apr 2016 08:16:48 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b=p6WPqf7r; dkim-atps=neutral Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id CFF7FA75E5; Thu, 31 Mar 2016 23:15:39 +0200 (CEST) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id M5zFwjjOh-jG; Thu, 31 Mar 2016 23:15:39 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 6B8A4A75F3; Thu, 31 Mar 2016 23:14:39 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id DB84FA7608 for ; Thu, 31 Mar 2016 23:14:15 +0200 (CEST) Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id jIE50gn7PI9i for ; Thu, 31 Mar 2016 23:14:15 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-lb0-f175.google.com (mail-lb0-f175.google.com [209.85.217.175]) by theia.denx.de (Postfix) with ESMTPS id 489D1A7609 for ; Thu, 31 Mar 2016 23:13:57 +0200 (CEST) Received: by mail-lb0-f175.google.com with SMTP id qe11so60088483lbc.3 for ; Thu, 31 Mar 2016 14:13:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=Kfd89F8q9JbPlUV0vvC8EY2OIbkJZWWI1Aq3YBygDqA=; b=p6WPqf7rH101eodKQ+zr08WG7t4QviK+vWuCveyued2/SpTLlg5efpde7zWWmCeXd7 BgiGJpYOq1A6OXeoEOXG6+9RXC4LcFjY2dgl+uRPXzE4AvjJGGQNaYlAVBMO1EFI0v8o 2qdtxdl/NIa92dVuvBKK6D3NT/w6p0omTi2kqMtOYQzo1o0fuXinBliz2iEa0r4XdMDk bH4JPoRW9LCv445BvXSKH5tJR1Ir01smaxIyDGCXpvp+Bz8pOwIoXCEp20W80ooFlo3s iNHcyuaG3b2Yj9fNYufOhzFJNqW5AzJVfYA8TwLWBmZekjju1kKNgjeAvi2SXjyIia5i dXxg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=Kfd89F8q9JbPlUV0vvC8EY2OIbkJZWWI1Aq3YBygDqA=; b=gSz/JtULKlTWep/BLKN40gDo6LyrOClbeLLfwEkYIe5/YoFNFov/tIX/qW8uZ7Sgi3 kWGnoqXgxkfu9d8WBS0yOI7fCL2UgeP8kd+6Z0B+42o+sM8sAyQFUg9swz3HH1WR+duF +lrwSonrGahxBUxzw4wSOZlyYDYSBiIAySk5iVLy6tMb6LXlplgq4nBErhb6qZx/9F2d 8UAOpb3xTUstGop11di5pms6//rIRkEWzK+QloLmR+xZyqHQ+UWYLjwq8omtwXS+96vf 0hv/KjnwlG/iVDALqZTncHx3y2lUAy7+410Jm/QArgZQqF4FRq5bMyIluxwVTyGdWQeg HBBw== X-Gm-Message-State: AD7BkJKP5F2CWhMp39d0yxtMF4UiuQ8clNUOKFeownWHY0jaHGqX7gyYK1VuVqKYFDnhtA== X-Received: by 10.112.54.132 with SMTP id j4mr2252633lbp.3.1459458836928; Thu, 31 Mar 2016 14:13:56 -0700 (PDT) Received: from localhost.localdomain (095160097038.warszawa.vectranet.pl. [95.160.97.38]) by smtp.gmail.com with ESMTPSA id w6sm1630673lbo.31.2016.03.31.14.13.55 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 31 Mar 2016 14:13:56 -0700 (PDT) From: Mateusz Kulikowski To: u-boot@lists.denx.de, Przemyslaw Marczak , Simon Glass , sk.syed2@gmail.com, Tom Rini , sjoerd.simons@collabora.co.uk Date: Thu, 31 Mar 2016 23:12:32 +0200 Message-Id: <1459458754-29559-20-git-send-email-mateusz.kulikowski@gmail.com> X-Mailer: git-send-email 2.5.0 In-Reply-To: <1459458754-29559-1-git-send-email-mateusz.kulikowski@gmail.com> References: <1459458754-29559-1-git-send-email-mateusz.kulikowski@gmail.com> Cc: Marek Vasut , Pantelis Antoniou , dg@emlix.com, jteki@openedev.com Subject: [U-Boot] [PATCH v4 19/21] arm: Add support for Qualcomm Snapdragon family X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.15 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" 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 Reviewed-by: Simon Glass Tested-by: Simon Glass --- Changes in v4: - Add sysmap for apq8016 (required to enable MMU) 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 | 9 + 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 ++++ arch/arm/mach-snapdragon/sysmap-apq8016.c | 30 +++ 9 files changed, 383 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 create mode 100644 arch/arm/mach-snapdragon/sysmap-apq8016.c diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 9851065..fc0c03f 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -511,6 +511,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 @@ -774,6 +784,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 6defdfb..bb2666c 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..4735844 --- /dev/null +++ b/arch/arm/mach-snapdragon/Makefile @@ -0,0 +1,9 @@ +# +# (C) Copyright 2015 Mateusz Kulikowski +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y += clock-apq8016.o +obj-y += sysmap-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 + * + * Based on Little Kernel driver, simplified + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include + +/* 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 + * + * 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 + * + * 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 + * + * 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(msm_reset) = { + .name = "msm_reset", + .id = UCLASS_RESET, + .of_match = msm_reset_ids, + .ops = &msm_reset_ops, +}; diff --git a/arch/arm/mach-snapdragon/sysmap-apq8016.c b/arch/arm/mach-snapdragon/sysmap-apq8016.c new file mode 100644 index 0000000..ef0db2a --- /dev/null +++ b/arch/arm/mach-snapdragon/sysmap-apq8016.c @@ -0,0 +1,30 @@ +/* + * Qualcomm APQ8016 memory map + * + * (C) Copyright 2016 Mateusz Kulikowski + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include + +static struct mm_region apq8016_mem_map[] = { + { + .base = 0x0UL, /* Peripheral block */ + .size = 0x8000000UL, + .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | + PTE_BLOCK_NON_SHARE | + PTE_BLOCK_PXN | PTE_BLOCK_UXN + }, { + .base = 0x80000000UL, /* DDR */ + .size = 0x80000000UL, + .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | + PTE_BLOCK_INNER_SHARE + }, { + /* List terminator */ + 0, + } +}; + +struct mm_region *mem_map = apq8016_mem_map;