diff options
Diffstat (limited to 'kernel/arch/arm/mach-shmobile/setup-rcar-gen2.c')
-rw-r--r-- | kernel/arch/arm/mach-shmobile/setup-rcar-gen2.c | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/kernel/arch/arm/mach-shmobile/setup-rcar-gen2.c b/kernel/arch/arm/mach-shmobile/setup-rcar-gen2.c new file mode 100644 index 000000000..5d13595aa --- /dev/null +++ b/kernel/arch/arm/mach-shmobile/setup-rcar-gen2.c @@ -0,0 +1,203 @@ +/* + * 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) +{ + u32 mode = rcar_gen2_read_mode_pins(); +#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 */ + + rcar_gen2_clocks_init(mode); +#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 +} |