2013-09-12 04:32:49 +04:00
/*
* R - Car Generation 2 support
*
* Copyright ( C ) 2013 Renesas Solutions Corp .
* Copyright ( C ) 2013 Magnus Damm
2014-09-12 12:52:05 +04:00
* Copyright ( C ) 2014 Ulrich Hecht
2013-09-12 04:32:49 +04:00
*
* 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 .
*/
2013-12-11 18:13:51 +04:00
# include <linux/clk/shmobile.h>
2013-09-12 04:32:49 +04:00
# include <linux/clocksource.h>
2014-06-09 16:38:45 +04:00
# include <linux/device.h>
# include <linux/dma-contiguous.h>
2013-09-12 04:32:49 +04:00
# include <linux/io.h>
# include <linux/kernel.h>
2015-01-21 08:01:37 +03:00
# include <linux/memblock.h>
2014-09-12 12:52:05 +04:00
# include <linux/of.h>
2014-06-09 16:38:45 +04:00
# include <linux/of_fdt.h>
2013-09-12 04:32:49 +04:00
# include <asm/mach/arch.h>
2014-06-17 11:47:37 +04:00
# include "common.h"
2014-06-17 11:48:01 +04:00
# include "rcar-gen2.h"
2013-09-12 04:32:49 +04:00
# define MODEMR 0xe6160060
2014-02-17 10:35:10 +04:00
u32 rcar_gen2_read_mode_pins ( void )
2013-09-12 04:32:49 +04:00
{
2014-03-12 22:44:49 +04:00
static u32 mode ;
static bool mode_valid ;
2013-09-12 04:32:49 +04:00
2014-03-12 22:44:49 +04:00
if ( ! mode_valid ) {
void __iomem * modemr = ioremap_nocache ( MODEMR , 4 ) ;
BUG_ON ( ! modemr ) ;
mode = ioread32 ( modemr ) ;
iounmap ( modemr ) ;
mode_valid = true ;
}
2013-09-12 04:32:49 +04:00
return mode ;
}
# define CNTCR 0
# define CNTFID0 0x20
void __init rcar_gen2_timer_init ( void )
{
u32 mode = rcar_gen2_read_mode_pins ( ) ;
2013-12-11 18:13:51 +04:00
# ifdef CONFIG_ARM_ARCH_TIMER
2013-09-12 04:32:49 +04:00
void __iomem * base ;
int extal_mhz = 0 ;
u32 freq ;
2014-12-03 14:48:04 +03:00
if ( of_machine_is_compatible ( " renesas,r8a7794 " ) ) {
2014-09-12 12:52:05 +04:00
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 .
*/
2013-09-12 04:32:49 +04:00
2014-09-12 12:52:05 +04:00
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 ;
}
2013-09-12 04:32:49 +04:00
2014-09-12 12:52:05 +04:00
/* The arch timer frequency equals EXTAL / 2 */
freq = extal_mhz * ( 1000000 / 2 ) ;
}
2013-09-12 04:32:49 +04:00
/* Remap "armgcnt address map" space */
base = ioremap ( 0xe6080000 , PAGE_SIZE ) ;
2013-12-11 14:07:42 +04:00
/*
* 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 ) ;
}
2013-09-12 04:32:49 +04:00
iounmap ( base ) ;
# endif /* CONFIG_ARM_ARCH_TIMER */
2013-12-11 18:13:51 +04:00
rcar_gen2_clocks_init ( mode ) ;
2015-09-28 17:49:18 +03:00
clocksource_probe ( ) ;
2013-09-12 04:32:49 +04:00
}
2014-06-12 12:42:22 +04:00
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 ;
2014-06-12 12:42:23 +04:00
u64 lpae_start = 1ULL < < 32 ;
2014-06-12 12:42:22 +04:00
/* We are scanning "memory" nodes only */
2014-06-12 12:42:24 +04:00
if ( type = = NULL | | strcmp ( type , " memory " ) )
2014-06-12 12:42:22 +04:00
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 , & reg ) ;
size = dt_mem_next_cell ( dt_root_size_cells , & reg ) ;
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
2015-01-21 08:01:37 +03:00
if ( mrc . size & & memblock_is_region_memory ( mrc . base , mrc . size ) )
2014-06-12 12:42:22 +04:00
dma_contiguous_reserve_area ( mrc . size , mrc . base , 0 ,
2014-06-19 13:31:10 +04:00
& rcar_gen2_dma_contiguous , true ) ;
2014-06-12 12:42:22 +04:00
# endif
}