mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-26 04:25:27 +08:00
744cadba1a
Allow R-Car Gen2 platforms to boot with CMA enabled and HIGHMEM disabled. This patch adds code to check if the R-Car Gen2 specific memory reservation window is included in the kernel memory range or not. When HIGHMEM is disabled the R-Car Gen2 reservation area is outside the kernel memory range and in such case the memory reservation is simply skipped over. Without this patch the kernel boot hangs when CMA is enabled and HIGHMEM is disabled on the r8a7791 Koelsch hardware platform: WARNING: CPU: 1 PID: 1 at mm/cma.c:113 cma_init_reserved_areas+0x88/0x1d4() ... WARNING: CPU: 1 PID: 1 at mm/cma.c:121 cma_init_reserved_areas+0xf8/0x1d4() ... Unable to handle kernel NULL pointer dereference at virtual address 00000160 pgd = c0003000 [00000160] *pgd=80000040004003, *pmd=00000000 Internal error: Oops: 206 [#1] SMP ARM Modules linked in: CPU: 1 PID: 1 Comm: swapper/0 Tainted: G W 3.19.0-rc4-koelsch-01450-g7f9b6075ce12c3ea-dirty #735 Hardware name: Generic R8A7791 (Flattened Device Tree) task: edc553c0 ti: edc56000 task.ti: edc56000 PC is at set_pfnblock_flags_mask+0x54/0xa0 LR is at 0x440 In the current shmobile_defconfig HIGHMEM is enabled while CMA is disabled, so to trigger this the kernel configuration for both CMA and HIGHMEM needs to be adjusted. Signed-off-by: Magnus Damm <damm+renesas@opensource.se> Tested-by: Geert Uytterhoeven <geert+renesas@glider.be> Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
208 lines
5.1 KiB
C
208 lines
5.1 KiB
C
/*
|
|
* R-Car Generation 2 support
|
|
*
|
|
* Copyright (C) 2013 Renesas Solutions Corp.
|
|
* Copyright (C) 2013 Magnus Damm
|
|
* Copyright (C) 2014 Ulrich Hecht
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; version 2 of the License.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*/
|
|
|
|
#include <linux/clk/shmobile.h>
|
|
#include <linux/clocksource.h>
|
|
#include <linux/device.h>
|
|
#include <linux/dma-contiguous.h>
|
|
#include <linux/io.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/memblock.h>
|
|
#include <linux/of.h>
|
|
#include <linux/of_fdt.h>
|
|
#include <asm/mach/arch.h>
|
|
#include "common.h"
|
|
#include "rcar-gen2.h"
|
|
|
|
#define MODEMR 0xe6160060
|
|
|
|
u32 rcar_gen2_read_mode_pins(void)
|
|
{
|
|
static u32 mode;
|
|
static bool mode_valid;
|
|
|
|
if (!mode_valid) {
|
|
void __iomem *modemr = ioremap_nocache(MODEMR, 4);
|
|
BUG_ON(!modemr);
|
|
mode = ioread32(modemr);
|
|
iounmap(modemr);
|
|
mode_valid = true;
|
|
}
|
|
|
|
return mode;
|
|
}
|
|
|
|
#define CNTCR 0
|
|
#define CNTFID0 0x20
|
|
|
|
void __init rcar_gen2_timer_init(void)
|
|
{
|
|
#if defined(CONFIG_ARM_ARCH_TIMER) || defined(CONFIG_COMMON_CLK)
|
|
u32 mode = rcar_gen2_read_mode_pins();
|
|
#endif
|
|
#ifdef CONFIG_ARM_ARCH_TIMER
|
|
void __iomem *base;
|
|
int extal_mhz = 0;
|
|
u32 freq;
|
|
|
|
if (of_machine_is_compatible("renesas,r8a7794")) {
|
|
freq = 260000000 / 8; /* ZS / 8 */
|
|
/* CNTVOFF has to be initialized either from non-secure
|
|
* Hypervisor mode or secure Monitor mode with SCR.NS==1.
|
|
* If TrustZone is enabled then it should be handled by the
|
|
* secure code.
|
|
*/
|
|
asm volatile(
|
|
" cps 0x16\n"
|
|
" mrc p15, 0, r1, c1, c1, 0\n"
|
|
" orr r0, r1, #1\n"
|
|
" mcr p15, 0, r0, c1, c1, 0\n"
|
|
" isb\n"
|
|
" mov r0, #0\n"
|
|
" mcrr p15, 4, r0, r0, c14\n"
|
|
" isb\n"
|
|
" mcr p15, 0, r1, c1, c1, 0\n"
|
|
" isb\n"
|
|
" cps 0x13\n"
|
|
: : : "r0", "r1");
|
|
} else {
|
|
/* At Linux boot time the r8a7790 arch timer comes up
|
|
* with the counter disabled. Moreover, it may also report
|
|
* a potentially incorrect fixed 13 MHz frequency. To be
|
|
* correct these registers need to be updated to use the
|
|
* frequency EXTAL / 2 which can be determined by the MD pins.
|
|
*/
|
|
|
|
switch (mode & (MD(14) | MD(13))) {
|
|
case 0:
|
|
extal_mhz = 15;
|
|
break;
|
|
case MD(13):
|
|
extal_mhz = 20;
|
|
break;
|
|
case MD(14):
|
|
extal_mhz = 26;
|
|
break;
|
|
case MD(13) | MD(14):
|
|
extal_mhz = 30;
|
|
break;
|
|
}
|
|
|
|
/* The arch timer frequency equals EXTAL / 2 */
|
|
freq = extal_mhz * (1000000 / 2);
|
|
}
|
|
|
|
/* Remap "armgcnt address map" space */
|
|
base = ioremap(0xe6080000, PAGE_SIZE);
|
|
|
|
/*
|
|
* Update the timer if it is either not running, or is not at the
|
|
* right frequency. The timer is only configurable in secure mode
|
|
* so this avoids an abort if the loader started the timer and
|
|
* entered the kernel in non-secure mode.
|
|
*/
|
|
|
|
if ((ioread32(base + CNTCR) & 1) == 0 ||
|
|
ioread32(base + CNTFID0) != freq) {
|
|
/* Update registers with correct frequency */
|
|
iowrite32(freq, base + CNTFID0);
|
|
asm volatile("mcr p15, 0, %0, c14, c0, 0" : : "r" (freq));
|
|
|
|
/* make sure arch timer is started by setting bit 0 of CNTCR */
|
|
iowrite32(1, base + CNTCR);
|
|
}
|
|
|
|
iounmap(base);
|
|
#endif /* CONFIG_ARM_ARCH_TIMER */
|
|
|
|
#ifdef CONFIG_COMMON_CLK
|
|
rcar_gen2_clocks_init(mode);
|
|
#endif
|
|
#ifdef CONFIG_ARCH_SHMOBILE_MULTI
|
|
clocksource_of_init();
|
|
#endif
|
|
}
|
|
|
|
struct memory_reserve_config {
|
|
u64 reserved;
|
|
u64 base, size;
|
|
};
|
|
|
|
static int __init rcar_gen2_scan_mem(unsigned long node, const char *uname,
|
|
int depth, void *data)
|
|
{
|
|
const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
|
|
const __be32 *reg, *endp;
|
|
int l;
|
|
struct memory_reserve_config *mrc = data;
|
|
u64 lpae_start = 1ULL << 32;
|
|
|
|
/* We are scanning "memory" nodes only */
|
|
if (type == NULL || strcmp(type, "memory"))
|
|
return 0;
|
|
|
|
reg = of_get_flat_dt_prop(node, "linux,usable-memory", &l);
|
|
if (reg == NULL)
|
|
reg = of_get_flat_dt_prop(node, "reg", &l);
|
|
if (reg == NULL)
|
|
return 0;
|
|
|
|
endp = reg + (l / sizeof(__be32));
|
|
while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
|
|
u64 base, size;
|
|
|
|
base = dt_mem_next_cell(dt_root_addr_cells, ®);
|
|
size = dt_mem_next_cell(dt_root_size_cells, ®);
|
|
|
|
if (base >= lpae_start)
|
|
continue;
|
|
|
|
if ((base + size) >= lpae_start)
|
|
size = lpae_start - base;
|
|
|
|
if (size < mrc->reserved)
|
|
continue;
|
|
|
|
if (base < mrc->base)
|
|
continue;
|
|
|
|
/* keep the area at top near the 32-bit legacy limit */
|
|
mrc->base = base + size - mrc->reserved;
|
|
mrc->size = mrc->reserved;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct cma *rcar_gen2_dma_contiguous;
|
|
|
|
void __init rcar_gen2_reserve(void)
|
|
{
|
|
struct memory_reserve_config mrc;
|
|
|
|
/* reserve 256 MiB at the top of the physical legacy 32-bit space */
|
|
memset(&mrc, 0, sizeof(mrc));
|
|
mrc.reserved = SZ_256M;
|
|
|
|
of_scan_flat_dt(rcar_gen2_scan_mem, &mrc);
|
|
#ifdef CONFIG_DMA_CMA
|
|
if (mrc.size && memblock_is_region_memory(mrc.base, mrc.size))
|
|
dma_contiguous_reserve_area(mrc.size, mrc.base, 0,
|
|
&rcar_gen2_dma_contiguous, true);
|
|
#endif
|
|
}
|