From patchwork Fri Jan 27 21:53:43 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Masahiro Yamada X-Patchwork-Id: 92736 Delivered-To: patch@linaro.org Received: by 10.140.20.99 with SMTP id 90csp445697qgi; Fri, 27 Jan 2017 13:57:22 -0800 (PST) X-Received: by 10.223.162.205 with SMTP id t13mr10379015wra.155.1485554241985; Fri, 27 Jan 2017 13:57:21 -0800 (PST) Return-Path: Received: from theia.denx.de (theia.denx.de. [85.214.87.163]) by mx.google.com with ESMTP id y52si7347965wry.199.2017.01.27.13.57.21; Fri, 27 Jan 2017 13:57:21 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 85.214.87.163 as permitted sender) client-ip=85.214.87.163; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 85.214.87.163 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 105EAB38C1; Fri, 27 Jan 2017 22:56:01 +0100 (CET) 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 YvfhE60FYq4w; Fri, 27 Jan 2017 22:56:00 +0100 (CET) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id AAD6BB38E3; Fri, 27 Jan 2017 22:55:45 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id B406CB387F for ; Fri, 27 Jan 2017 22:54:39 +0100 (CET) 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 XfMiy9KNuPyb for ; Fri, 27 Jan 2017 22:54:39 +0100 (CET) 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 conuserg-11.nifty.com (conuserg-11.nifty.com [210.131.2.78]) by theia.denx.de (Postfix) with ESMTPS id 59E44A761A for ; Fri, 27 Jan 2017 22:54:26 +0100 (CET) Received: from grover.sesame (FL1-111-169-71-157.osk.mesh.ad.jp [111.169.71.157]) (authenticated) by conuserg-11.nifty.com with ESMTP id v0RLs2X1015159; Sat, 28 Jan 2017 06:54:07 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conuserg-11.nifty.com v0RLs2X1015159 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1485554047; bh=kM2T8rGG+gvGZnkz3QOBuUQq1yjkGWH2Ua3lupeKg3g=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=rzNcIRkrsSD302fX5hLl8RQBAwnWa3sfi6pLra4wjC/yKyauFliBbNnGGjCK/6eKx NrscRKH5aAnSNWfb3xs9kMsY8yhKbQ8S3Y2+F3GZOA8VLR+7hAUasxTodJhLO+h1g9 vAqa4yj9F5ndCjHHqLF5rqSOrF9iDyhBtifrU0i1J/tTnAB71D8ZQ3/lFng7Dl6lDb J978IG9ujy6Lp9F3yIGeXEpiYJyYdJr8PUp38K4pIvaO/6R2PvIqrco+0uumNwmDWM +xFyj/844FV70Cn4tOyv3nWYjTzDuZTw+1i690qoe43DJOhK1AwmEtMXtUkrWv/lEq 6yhb8/9BdRlyg== X-Nifty-SrcIP: [111.169.71.157] From: Masahiro Yamada To: u-boot@lists.denx.de Date: Sat, 28 Jan 2017 06:53:43 +0900 Message-Id: <1485554036-29320-4-git-send-email-yamada.masahiro@socionext.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1485554036-29320-1-git-send-email-yamada.masahiro@socionext.com> References: <1485554036-29320-1-git-send-email-yamada.masahiro@socionext.com> Cc: Albert Aribaud Subject: [U-Boot] [PATCH 03/16] ARM: uniphier: detect RAM size by decoding HW register instead of DT 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" U-Boot needs to set up available memory area(s) in dram_init() and dram_init_banksize(). It is platform-dependent how to detect the memory banks. Currently, UniPhier adopts the memory banks _alleged_ by DT. This is based on the assumption that users bind a correct DT in their build process. Come to think of it, the DRAM controller has already been set up before U-Boot is entered (because U-Boot runs on DRAM). So, the DRAM controller setup register seems a more reliable source of any information about DRAM stuff. The DRAM banks are initialized by preliminary firmware (SPL, ARM Trusted Firmware BL2, or whatever), so this means the source of the reliability is shifted from Device Tree to such early-stage firmware. However, if the DRAM controller is wrongly configured, the system will crash. If your system is running, the DRAM setup register is very likely to provide the correct DRAM mapping. Decode the SG_MEMCONF register to get the available DRAM banks. The dram_init() and dram_init_banksize() need similar decoding. It would be nice if dram_init_banksize() could reuse the outcome of dram_init(), but global variables are unavailable at this stage because the .bss section is available only after the relocation. As a result, SG_MEMCONF must be checked twice, but a new helper uniphier_memconf_decode() will help to avoid code duplication. Signed-off-by: Masahiro Yamada --- arch/arm/mach-uniphier/dram_init.c | 250 ++++++++++++++++++++++++++++++------- arch/arm/mach-uniphier/init.h | 1 + include/configs/uniphier.h | 2 +- 3 files changed, 204 insertions(+), 49 deletions(-) -- 2.7.4 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot diff --git a/arch/arm/mach-uniphier/dram_init.c b/arch/arm/mach-uniphier/dram_init.c index 2cf5f36..43fe6a5 100644 --- a/arch/arm/mach-uniphier/dram_init.c +++ b/arch/arm/mach-uniphier/dram_init.c @@ -5,83 +5,237 @@ */ #include -#include #include #include +#include #include "init.h" +#include "sg-regs.h" #include "soc-info.h" DECLARE_GLOBAL_DATA_PTR; -static const void *get_memory_reg_prop(const void *fdt, int *lenp) +struct uniphier_memif_data { + unsigned int soc_id; + unsigned long sparse_ch1_base; + int have_ch2; +}; + +static const struct uniphier_memif_data uniphier_memif_data[] = { + { + .soc_id = UNIPHIER_SLD3_ID, + .sparse_ch1_base = 0xc0000000, + /* + * In fact, SLD3 has DRAM ch2, but the memory regions for ch1 + * and ch2 overlap, and host cannot get access to them at the + * same time. Hide the ch2 from U-Boot. + */ + }, + { + .soc_id = UNIPHIER_LD4_ID, + .sparse_ch1_base = 0xc0000000, + }, + { + .soc_id = UNIPHIER_PRO4_ID, + .sparse_ch1_base = 0xa0000000, + }, + { + .soc_id = UNIPHIER_SLD8_ID, + .sparse_ch1_base = 0xc0000000, + }, + { + .soc_id = UNIPHIER_PRO5_ID, + .sparse_ch1_base = 0xc0000000, + }, + { + .soc_id = UNIPHIER_PXS2_ID, + .sparse_ch1_base = 0xc0000000, + .have_ch2 = 1, + }, + { + .soc_id = UNIPHIER_LD6B_ID, + .sparse_ch1_base = 0xc0000000, + .have_ch2 = 1, + }, + { + .soc_id = UNIPHIER_LD11_ID, + .sparse_ch1_base = 0xc0000000, + }, + { + .soc_id = UNIPHIER_LD20_ID, + .sparse_ch1_base = 0xc0000000, + .have_ch2 = 1, + }, + { + .soc_id = UNIPHIER_PXS3_ID, + .sparse_ch1_base = 0xc0000000, + .have_ch2 = 1, + }, +}; +UNIPHIER_DEFINE_SOCDATA_FUNC(uniphier_get_memif_data, uniphier_memif_data) + +static int uniphier_memconf_decode(struct uniphier_dram_ch *dram_ch) { - int offset; + const struct uniphier_memif_data *data; + unsigned long size; + u32 val; - offset = fdt_path_offset(fdt, "/memory"); - if (offset < 0) - return NULL; + data = uniphier_get_memif_data(); + if (!data) { + pr_err("unsupported SoC\n"); + return -EINVAL; + } - return fdt_getprop(fdt, offset, "reg", lenp); -} + val = readl(SG_MEMCONF); -int dram_init(void) -{ - const void *fdt = gd->fdt_blob; - const fdt32_t *val; - int ac, sc, len; - - ac = fdt_address_cells(fdt, 0); - sc = fdt_size_cells(fdt, 0); - if (ac < 0 || sc < 1 || sc > 2) { - printf("invalid address/size cells\n"); + /* set up ch0 */ + dram_ch[0].base = CONFIG_SYS_SDRAM_BASE; + + switch (val & SG_MEMCONF_CH0_SZ_MASK) { + case SG_MEMCONF_CH0_SZ_64M: + size = SZ_64M; + break; + case SG_MEMCONF_CH0_SZ_128M: + size = SZ_128M; + break; + case SG_MEMCONF_CH0_SZ_256M: + size = SZ_256M; + break; + case SG_MEMCONF_CH0_SZ_512M: + size = SZ_512M; + break; + case SG_MEMCONF_CH0_SZ_1G: + size = SZ_1G; + break; + default: + pr_err("error: invald value is set to MEMCONF ch0 size\n"); return -EINVAL; } - val = get_memory_reg_prop(fdt, &len); - if (len / sizeof(*val) < ac + sc) + if ((val & SG_MEMCONF_CH0_NUM_MASK) == SG_MEMCONF_CH0_NUM_2) + size *= 2; + + dram_ch[0].size = size; + + /* set up ch1 */ + dram_ch[1].base = dram_ch[0].base + size; + + if (val & SG_MEMCONF_SPARSEMEM) { + if (dram_ch[1].base > data->sparse_ch1_base) { + pr_warn("Sparse mem is enabled, but ch0 and ch1 overlap\n"); + pr_warn("Only ch0 is available\n"); + dram_ch[1].base = 0; + return 0; + } + + dram_ch[1].base = data->sparse_ch1_base; + } + + switch (val & SG_MEMCONF_CH1_SZ_MASK) { + case SG_MEMCONF_CH1_SZ_64M: + size = SZ_64M; + break; + case SG_MEMCONF_CH1_SZ_128M: + size = SZ_128M; + break; + case SG_MEMCONF_CH1_SZ_256M: + size = SZ_256M; + break; + case SG_MEMCONF_CH1_SZ_512M: + size = SZ_512M; + break; + case SG_MEMCONF_CH1_SZ_1G: + size = SZ_1G; + break; + default: + pr_err("error: invald value is set to MEMCONF ch1 size\n"); return -EINVAL; + } + + if ((val & SG_MEMCONF_CH1_NUM_MASK) == SG_MEMCONF_CH1_NUM_2) + size *= 2; - val += ac; + dram_ch[1].size = size; - gd->ram_size = fdtdec_get_number(val, sc); + if (!data->have_ch2) + return 0; - debug("DRAM size = %08lx\n", (unsigned long)gd->ram_size); + /* set up ch2 */ + dram_ch[2].base = dram_ch[1].base + size; + + switch (val & SG_MEMCONF_CH2_SZ_MASK) { + case SG_MEMCONF_CH2_SZ_64M: + size = SZ_64M; + break; + case SG_MEMCONF_CH2_SZ_128M: + size = SZ_128M; + break; + case SG_MEMCONF_CH2_SZ_256M: + size = SZ_256M; + break; + case SG_MEMCONF_CH2_SZ_512M: + size = SZ_512M; + break; + case SG_MEMCONF_CH2_SZ_1G: + size = SZ_1G; + break; + default: + pr_err("error: invald value is set to MEMCONF ch2 size\n"); + return -EINVAL; + } + + if ((val & SG_MEMCONF_CH2_NUM_MASK) == SG_MEMCONF_CH2_NUM_2) + size *= 2; + + dram_ch[2].size = size; return 0; } -void dram_init_banksize(void) +int dram_init(void) { - const void *fdt = gd->fdt_blob; - const fdt32_t *val; - int ac, sc, cells, len, i; - - val = get_memory_reg_prop(fdt, &len); - if (len < 0) - return; - - ac = fdt_address_cells(fdt, 0); - sc = fdt_size_cells(fdt, 0); - if (ac < 1 || sc > 2 || sc < 1 || sc > 2) { - printf("invalid address/size cells\n"); - return; + struct uniphier_dram_ch dram_ch[UNIPHIER_MAX_NR_DRAM_CH] = {}; + int ret, i; + + gd->ram_size = 0; + + ret = uniphier_memconf_decode(dram_ch); + if (ret) + return ret; + + for (i = 0; i < ARRAY_SIZE(dram_ch); i++) { + + if (!dram_ch[i].size) + break; + + /* + * U-Boot relocates itself to the tail of the memory region, + * but it does not expect sparse memory. We use the first + * contiguous chunk here. + */ + if (i > 0 && + dram_ch[i - 1].base + dram_ch[i - 1].size < dram_ch[i].base) + break; + + gd->ram_size += dram_ch[i].size; } - cells = ac + sc; + return 0; +} + +void dram_init_banksize(void) +{ + struct uniphier_dram_ch dram_ch[UNIPHIER_MAX_NR_DRAM_CH] = {}; + int i; - len /= sizeof(*val); + uniphier_memconf_decode(dram_ch); - for (i = 0; i < CONFIG_NR_DRAM_BANKS && len >= cells; - i++, len -= cells) { - gd->bd->bi_dram[i].start = fdtdec_get_number(val, ac); - val += ac; - gd->bd->bi_dram[i].size = fdtdec_get_number(val, sc); - val += sc; + for (i = 0; i < ARRAY_SIZE(dram_ch); i++) { + if (i >= ARRAY_SIZE(gd->bd->bi_dram)) + break; - debug("DRAM bank %d: start = %08lx, size = %08lx\n", - i, (unsigned long)gd->bd->bi_dram[i].start, - (unsigned long)gd->bd->bi_dram[i].size); + gd->bd->bi_dram[i].start = dram_ch[i].base; + gd->bd->bi_dram[i].size = dram_ch[i].size; } } diff --git a/arch/arm/mach-uniphier/init.h b/arch/arm/mach-uniphier/init.h index 3aeb5b1..453e68a 100644 --- a/arch/arm/mach-uniphier/init.h +++ b/arch/arm/mach-uniphier/init.h @@ -124,6 +124,7 @@ int uniphier_pin_init(const char *pinconfig_name); void uniphier_smp_kick_all_cpus(void); void cci500_init(int nr_slaves); +#define pr_warn(fmt, args...) printf(fmt, ##args) #define pr_err(fmt, args...) printf(fmt, ##args) #endif /* __MACH_INIT_H */ diff --git a/include/configs/uniphier.h b/include/configs/uniphier.h index 487d3de..ef5b019 100644 --- a/include/configs/uniphier.h +++ b/include/configs/uniphier.h @@ -237,7 +237,7 @@ #define CONFIG_SYS_BOOTMAPSZ 0x20000000 #define CONFIG_SYS_SDRAM_BASE 0x80000000 -#define CONFIG_NR_DRAM_BANKS 2 +#define CONFIG_NR_DRAM_BANKS 3 /* for LD20; the last 64 byte is used for dynamic DDR PHY training */ #define CONFIG_SYS_MEM_TOP_HIDE 64