2013-01-18 13:42:20 +04:00
/*
* Copyright ( C ) 2004 , 2007 - 2010 , 2011 - 2012 Synopsys , Inc . ( www . synopsys . com )
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
# include <linux/seq_file.h>
# include <linux/fs.h>
# include <linux/delay.h>
# include <linux/root_dev.h>
2017-03-03 14:30:02 +03:00
# include <linux/clk.h>
2016-10-31 23:26:25 +03:00
# include <linux/clk-provider.h>
# include <linux/clocksource.h>
2013-01-18 13:42:20 +04:00
# include <linux/console.h>
# include <linux/module.h>
# include <linux/cpu.h>
2013-01-22 15:30:52 +04:00
# include <linux/of_fdt.h>
2016-07-13 23:21:20 +03:00
# include <linux/of.h>
2013-03-06 15:23:44 +04:00
# include <linux/cache.h>
2018-11-02 02:07:23 +03:00
# include <uapi/linux/mount.h>
2013-01-22 15:30:52 +04:00
# include <asm/sections.h>
2013-01-18 13:42:20 +04:00
# include <asm/arcregs.h>
# include <asm/tlb.h>
# include <asm/setup.h>
# include <asm/page.h>
# include <asm/irq.h>
2013-01-22 15:33:19 +04:00
# include <asm/unwind.h>
2013-01-18 13:42:26 +04:00
# include <asm/mach_desc.h>
2014-09-04 09:27:33 +04:00
# include <asm/smp.h>
2013-01-18 13:42:20 +04:00
# define FIX_PTR(x) __asm__ __volatile__(";" : "+r"(x))
2014-09-22 15:21:47 +04:00
unsigned int intr_to_DE_cnt ;
2014-01-16 13:31:24 +04:00
/* Part of U-boot ABI: see head.S */
int __initdata uboot_tag ;
char __initdata * uboot_arg ;
2013-08-28 06:43:12 +04:00
const struct machine_desc * machine_desc ;
2013-01-18 13:42:20 +04:00
struct task_struct * _current_task [ NR_CPUS ] ; /* For stack switching */
struct cpuinfo_arc cpuinfo_arc700 [ NR_CPUS ] ;
2016-10-28 00:33:19 +03:00
static const struct id_to_str arc_cpu_rel [ ] = {
2016-10-21 03:49:15 +03:00
# ifdef CONFIG_ISA_ARCOMPACT
2016-10-28 00:33:19 +03:00
{ 0x34 , " R4.10 " } ,
{ 0x35 , " R4.11 " } ,
2016-10-21 03:49:15 +03:00
# else
2016-10-28 00:33:19 +03:00
{ 0x51 , " R2.0 " } ,
{ 0x52 , " R2.1 " } ,
{ 0x53 , " R3.0 " } ,
2018-02-22 02:10:02 +03:00
{ 0x54 , " R3.10a " } ,
2016-10-21 03:49:15 +03:00
# endif
2016-10-28 00:33:19 +03:00
{ 0x00 , NULL }
} ;
static const struct id_to_str arc_cpu_nm [ ] = {
# ifdef CONFIG_ISA_ARCOMPACT
{ 0x20 , " ARC 600 " } ,
{ 0x30 , " ARC 770 " } , /* 750 identified seperately */
# else
{ 0x40 , " ARC EM " } ,
{ 0x50 , " ARC HS38 " } ,
2017-09-22 04:02:44 +03:00
{ 0x54 , " ARC HS48 " } ,
2016-10-28 00:33:19 +03:00
# endif
{ 0x00 , " Unknown " }
2016-10-21 03:49:15 +03:00
} ;
2016-02-16 10:06:18 +03:00
static void read_decode_ccm_bcr ( struct cpuinfo_arc * cpu )
{
if ( is_isa_arcompact ( ) ) {
struct bcr_iccm_arcompact iccm ;
struct bcr_dccm_arcompact dccm ;
READ_BCR ( ARC_REG_ICCM_BUILD , iccm ) ;
if ( iccm . ver ) {
cpu - > iccm . sz = 4096 < < iccm . sz ; /* 8K to 512K */
cpu - > iccm . base_addr = iccm . base < < 16 ;
}
READ_BCR ( ARC_REG_DCCM_BUILD , dccm ) ;
if ( dccm . ver ) {
unsigned long base ;
cpu - > dccm . sz = 2048 < < dccm . sz ; /* 2K to 256K */
base = read_aux_reg ( ARC_REG_DCCM_BASE_BUILD ) ;
cpu - > dccm . base_addr = base & ~ 0xF ;
}
} else {
struct bcr_iccm_arcv2 iccm ;
struct bcr_dccm_arcv2 dccm ;
unsigned long region ;
READ_BCR ( ARC_REG_ICCM_BUILD , iccm ) ;
if ( iccm . ver ) {
cpu - > iccm . sz = 256 < < iccm . sz00 ; /* 512B to 16M */
if ( iccm . sz00 = = 0xF & & iccm . sz01 > 0 )
cpu - > iccm . sz < < = iccm . sz01 ;
region = read_aux_reg ( ARC_REG_AUX_ICCM ) ;
cpu - > iccm . base_addr = region & 0xF0000000 ;
}
READ_BCR ( ARC_REG_DCCM_BUILD , dccm ) ;
if ( dccm . ver ) {
cpu - > dccm . sz = 256 < < dccm . sz0 ;
if ( dccm . sz0 = = 0xF & & dccm . sz1 > 0 )
cpu - > dccm . sz < < = dccm . sz1 ;
region = read_aux_reg ( ARC_REG_AUX_DCCM ) ;
cpu - > dccm . base_addr = region & 0xF0000000 ;
}
}
}
2013-09-04 14:43:35 +04:00
static void read_arc_build_cfg_regs ( void )
2013-01-18 13:42:20 +04:00
{
2016-01-22 12:50:18 +03:00
struct bcr_timer timer ;
2014-09-25 15:24:43 +04:00
struct bcr_generic bcr ;
2013-01-18 13:42:24 +04:00
struct cpuinfo_arc * cpu = & cpuinfo_arc700 [ smp_processor_id ( ) ] ;
2016-10-28 00:33:19 +03:00
const struct id_to_str * tbl ;
2017-09-22 03:46:38 +03:00
struct bcr_isa_arcv2 isa ;
2019-01-09 20:36:00 +03:00
struct bcr_actionpoint ap ;
2016-10-21 03:49:15 +03:00
2013-01-18 13:42:24 +04:00
FIX_PTR ( cpu ) ;
READ_BCR ( AUX_IDENTITY , cpu - > core ) ;
2016-10-28 00:33:19 +03:00
for ( tbl = & arc_cpu_rel [ 0 ] ; tbl - > id ! = 0 ; tbl + + ) {
if ( cpu - > core . family = = tbl - > id ) {
cpu - > details = tbl - > str ;
2016-10-21 03:49:15 +03:00
break ;
}
}
2016-10-28 00:33:19 +03:00
for ( tbl = & arc_cpu_nm [ 0 ] ; tbl - > id ! = 0 ; tbl + + ) {
2017-09-22 04:02:44 +03:00
if ( ( cpu - > core . family & 0xF4 ) = = tbl - > id )
2016-10-28 00:33:19 +03:00
break ;
}
cpu - > name = tbl - > str ;
2016-10-21 03:49:15 +03:00
2016-01-22 12:50:18 +03:00
READ_BCR ( ARC_REG_TIMERS_BCR , timer ) ;
cpu - > extn . timer0 = timer . t0 ;
cpu - > extn . timer1 = timer . t1 ;
cpu - > extn . rtc = timer . rtc ;
2013-01-18 13:42:24 +04:00
cpu - > vec_base = read_aux_reg ( AUX_INTR_VEC_BASE ) ;
2014-09-25 15:24:43 +04:00
READ_BCR ( ARC_REG_MUL_BCR , cpu - > extn_mpy ) ;
2013-01-18 13:42:24 +04:00
2014-09-25 15:24:43 +04:00
cpu - > extn . norm = read_aux_reg ( ARC_REG_NORM_BCR ) > 1 ? 1 : 0 ; /* 2,3 */
cpu - > extn . barrel = read_aux_reg ( ARC_REG_BARREL_BCR ) > 1 ? 1 : 0 ; /* 2,3 */
cpu - > extn . swap = read_aux_reg ( ARC_REG_SWAP_BCR ) ? 1 : 0 ; /* 1,3 */
cpu - > extn . crc = read_aux_reg ( ARC_REG_CRC_BCR ) ? 1 : 0 ;
cpu - > extn . minmax = read_aux_reg ( ARC_REG_MIXMAX_BCR ) > 1 ? 1 : 0 ; /* 2 */
2016-10-21 04:08:10 +03:00
cpu - > extn . swape = ( cpu - > core . family > = 0x34 ) ? 1 :
IS_ENABLED ( CONFIG_ARC_HAS_SWAPE ) ;
2013-01-18 13:42:24 +04:00
READ_BCR ( ARC_REG_XY_MEM_BCR , cpu - > extn_xymem ) ;
2016-02-16 10:06:18 +03:00
/* Read CCM BCRs for boot reporting even if not enabled in Kconfig */
read_decode_ccm_bcr ( cpu ) ;
2013-01-18 13:42:20 +04:00
read_decode_mmu_bcr ( ) ;
read_decode_cache_bcr ( ) ;
2013-01-18 13:42:24 +04:00
ARCv2: Support for ARCv2 ISA and HS38x cores
The notable features are:
- SMP configurations of upto 4 cores with coherency
- Optional L2 Cache and IO-Coherency
- Revised Interrupt Architecture (multiple priorites, reg banks,
auto stack switch, auto regfile save/restore)
- MMUv4 (PIPT dcache, Huge Pages)
- Instructions for
* 64bit load/store: LDD, STD
* Hardware assisted divide/remainder: DIV, REM
* Function prologue/epilogue: ENTER_S, LEAVE_S
* IRQ enable/disable: CLRI, SETI
* pop count: FFS, FLS
* SETcc, BMSKN, XBFU...
Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
2013-05-13 17:00:41 +04:00
if ( is_isa_arcompact ( ) ) {
2014-09-25 15:24:43 +04:00
struct bcr_fp_arcompact sp , dp ;
struct bcr_bpu_arcompact bpu ;
READ_BCR ( ARC_REG_FP_BCR , sp ) ;
READ_BCR ( ARC_REG_DPFP_BCR , dp ) ;
cpu - > extn . fpu_sp = sp . ver ? 1 : 0 ;
cpu - > extn . fpu_dp = dp . ver ? 1 : 0 ;
READ_BCR ( ARC_REG_BPU_BCR , bpu ) ;
cpu - > bpu . ver = bpu . ver ;
cpu - > bpu . full = bpu . fam ? 1 : 0 ;
if ( bpu . ent ) {
cpu - > bpu . num_cache = 256 < < ( bpu . ent - 1 ) ;
cpu - > bpu . num_pred = 256 < < ( bpu . ent - 1 ) ;
}
ARCv2: Support for ARCv2 ISA and HS38x cores
The notable features are:
- SMP configurations of upto 4 cores with coherency
- Optional L2 Cache and IO-Coherency
- Revised Interrupt Architecture (multiple priorites, reg banks,
auto stack switch, auto regfile save/restore)
- MMUv4 (PIPT dcache, Huge Pages)
- Instructions for
* 64bit load/store: LDD, STD
* Hardware assisted divide/remainder: DIV, REM
* Function prologue/epilogue: ENTER_S, LEAVE_S
* IRQ enable/disable: CLRI, SETI
* pop count: FFS, FLS
* SETcc, BMSKN, XBFU...
Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
2013-05-13 17:00:41 +04:00
} else {
struct bcr_fp_arcv2 spdp ;
struct bcr_bpu_arcv2 bpu ;
READ_BCR ( ARC_REG_FP_V2_BCR , spdp ) ;
cpu - > extn . fpu_sp = spdp . sp ? 1 : 0 ;
cpu - > extn . fpu_dp = spdp . dp ? 1 : 0 ;
READ_BCR ( ARC_REG_BPU_BCR , bpu ) ;
cpu - > bpu . ver = bpu . ver ;
cpu - > bpu . full = bpu . ft ;
cpu - > bpu . num_cache = 256 < < bpu . bce ;
cpu - > bpu . num_pred = 2048 < < bpu . pte ;
2018-12-06 11:17:50 +03:00
cpu - > bpu . ret_stk = 4 < < bpu . rse ;
2017-09-22 04:02:44 +03:00
if ( cpu - > core . family > = 0x54 ) {
unsigned int exec_ctrl ;
READ_BCR ( AUX_EXEC_CTRL , exec_ctrl ) ;
2017-11-23 13:21:55 +03:00
cpu - > extn . dual_enb = ! ( exec_ctrl & 1 ) ;
2017-11-10 23:40:00 +03:00
/* dual issue always present for this core */
cpu - > extn . dual = 1 ;
2017-09-22 04:02:44 +03:00
}
2014-09-25 15:24:43 +04:00
}
2019-01-09 20:36:00 +03:00
READ_BCR ( ARC_REG_AP_BCR , ap ) ;
if ( ap . ver ) {
cpu - > extn . ap_num = 2 < < ap . num ;
cpu - > extn . ap_full = ! ! ap . min ;
}
2014-09-25 15:24:43 +04:00
READ_BCR ( ARC_REG_SMART_BCR , bcr ) ;
cpu - > extn . smart = bcr . ver ? 1 : 0 ;
2015-03-08 11:48:21 +03:00
READ_BCR ( ARC_REG_RTT_BCR , bcr ) ;
cpu - > extn . rtt = bcr . ver ? 1 : 0 ;
2017-09-22 03:46:38 +03:00
READ_BCR ( ARC_REG_ISA_CFG_BCR , isa ) ;
2016-10-21 03:49:15 +03:00
/* some hacks for lack of feature BCR info in old ARC700 cores */
if ( is_isa_arcompact ( ) ) {
2017-09-22 03:46:38 +03:00
if ( ! isa . ver ) /* ISA BCR absent, use Kconfig info */
2016-10-21 03:49:15 +03:00
cpu - > isa . atomic = IS_ENABLED ( CONFIG_ARC_HAS_LLSC ) ;
2017-09-22 03:46:38 +03:00
else {
/* ARC700_BUILD only has 2 bits of isa info */
struct bcr_generic bcr = * ( struct bcr_generic * ) & isa ;
cpu - > isa . atomic = bcr . info & 1 ;
}
2013-01-18 13:42:24 +04:00
2016-10-21 03:49:15 +03:00
cpu - > isa . be = IS_ENABLED ( CONFIG_CPU_BIG_ENDIAN ) ;
2016-10-28 00:33:19 +03:00
/* there's no direct way to distinguish 750 vs. 770 */
if ( unlikely ( cpu - > core . family < 0x34 | | cpu - > mmu . ver < 3 ) )
cpu - > name = " ARC750 " ;
2017-09-22 03:46:38 +03:00
} else {
cpu - > isa = isa ;
2016-10-21 03:49:15 +03:00
}
}
2014-09-25 15:24:43 +04:00
2013-09-04 14:43:35 +04:00
static char * arc_cpu_mumbojumbo ( int cpu_id , char * buf , int len )
2013-01-18 13:42:24 +04:00
{
struct cpuinfo_arc * cpu = & cpuinfo_arc700 [ cpu_id ] ;
struct bcr_identity * core = & cpu - > core ;
2018-10-29 19:44:18 +03:00
int i , n = 0 , ua = 0 ;
2014-09-25 15:24:43 +04:00
2013-01-18 13:42:24 +04:00
FIX_PTR ( cpu ) ;
n + = scnprintf ( buf + n , len - n ,
2014-09-25 15:24:43 +04:00
" \n IDENTITY \t : ARCVER [%#02x] ARCNUM [%#02x] CHIPID [%#4x] \n " ,
core - > family , core - > cpu_id , core - > chip_id ) ;
2013-01-18 13:42:24 +04:00
2017-09-22 04:02:44 +03:00
n + = scnprintf ( buf + n , len - n , " processor [%d] \t : %s %s (%s ISA) %s%s%s \n " ,
2016-10-28 00:33:19 +03:00
cpu_id , cpu - > name , cpu - > details ,
2016-10-21 03:49:15 +03:00
is_isa_arcompact ( ) ? " ARCompact " : " ARCv2 " ,
2017-09-22 04:02:44 +03:00
IS_AVAIL1 ( cpu - > isa . be , " [Big-Endian] " ) ,
2017-11-10 23:40:00 +03:00
IS_AVAIL3 ( cpu - > extn . dual , cpu - > extn . dual_enb , " Dual-Issue " ) ) ;
2013-01-18 13:42:24 +04:00
2016-11-01 00:26:41 +03:00
n + = scnprintf ( buf + n , len - n , " Timers \t \t : %s%s%s%s%s%s \n ISA Extn \t : " ,
2016-01-22 12:50:18 +03:00
IS_AVAIL1 ( cpu - > extn . timer0 , " Timer0 " ) ,
IS_AVAIL1 ( cpu - > extn . timer1 , " Timer1 " ) ,
2016-11-01 00:26:41 +03:00
IS_AVAIL2 ( cpu - > extn . rtc , " RTC [UP 64-bit] " , CONFIG_ARC_TIMERS_64BIT ) ,
IS_AVAIL2 ( cpu - > extn . gfrc , " GFRC [SMP 64-bit] " , CONFIG_ARC_TIMERS_64BIT ) ) ;
2013-01-18 13:42:24 +04:00
2018-10-29 19:44:18 +03:00
# ifdef __ARC_UNALIGNED__
ua = 1 ;
# endif
n + = i = scnprintf ( buf + n , len - n , " %s%s%s%s%s%s " ,
2016-10-21 03:49:15 +03:00
IS_AVAIL2 ( cpu - > isa . atomic , " atomic " , CONFIG_ARC_HAS_LLSC ) ,
ARCv2: Support for ARCv2 ISA and HS38x cores
The notable features are:
- SMP configurations of upto 4 cores with coherency
- Optional L2 Cache and IO-Coherency
- Revised Interrupt Architecture (multiple priorites, reg banks,
auto stack switch, auto regfile save/restore)
- MMUv4 (PIPT dcache, Huge Pages)
- Instructions for
* 64bit load/store: LDD, STD
* Hardware assisted divide/remainder: DIV, REM
* Function prologue/epilogue: ENTER_S, LEAVE_S
* IRQ enable/disable: CLRI, SETI
* pop count: FFS, FLS
* SETcc, BMSKN, XBFU...
Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
2013-05-13 17:00:41 +04:00
IS_AVAIL2 ( cpu - > isa . ldd , " ll64 " , CONFIG_ARC_HAS_LL64 ) ,
2018-10-29 19:44:18 +03:00
IS_AVAIL1 ( cpu - > isa . unalign , " unalign " ) , IS_USED_RUN ( ua ) ) ;
2013-01-18 13:42:24 +04:00
2014-09-25 15:24:43 +04:00
if ( i )
n + = scnprintf ( buf + n , len - n , " \n \t \t : " ) ;
2013-01-18 13:42:24 +04:00
ARCv2: Support for ARCv2 ISA and HS38x cores
The notable features are:
- SMP configurations of upto 4 cores with coherency
- Optional L2 Cache and IO-Coherency
- Revised Interrupt Architecture (multiple priorites, reg banks,
auto stack switch, auto regfile save/restore)
- MMUv4 (PIPT dcache, Huge Pages)
- Instructions for
* 64bit load/store: LDD, STD
* Hardware assisted divide/remainder: DIV, REM
* Function prologue/epilogue: ENTER_S, LEAVE_S
* IRQ enable/disable: CLRI, SETI
* pop count: FFS, FLS
* SETcc, BMSKN, XBFU...
Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
2013-05-13 17:00:41 +04:00
if ( cpu - > extn_mpy . ver ) {
if ( cpu - > extn_mpy . ver < = 0x2 ) { /* ARCompact */
n + = scnprintf ( buf + n , len - n , " mpy " ) ;
} else {
int opt = 2 ; /* stock MPY/MPYH */
if ( cpu - > extn_mpy . dsp ) /* OPT 7-9 */
opt = cpu - > extn_mpy . dsp + 6 ;
n + = scnprintf ( buf + n , len - n , " mpy[opt %d] " , opt ) ;
}
}
2014-09-25 15:24:43 +04:00
n + = scnprintf ( buf + n , len - n , " %s%s%s%s%s%s%s%s \n " ,
ARCv2: Support for ARCv2 ISA and HS38x cores
The notable features are:
- SMP configurations of upto 4 cores with coherency
- Optional L2 Cache and IO-Coherency
- Revised Interrupt Architecture (multiple priorites, reg banks,
auto stack switch, auto regfile save/restore)
- MMUv4 (PIPT dcache, Huge Pages)
- Instructions for
* 64bit load/store: LDD, STD
* Hardware assisted divide/remainder: DIV, REM
* Function prologue/epilogue: ENTER_S, LEAVE_S
* IRQ enable/disable: CLRI, SETI
* pop count: FFS, FLS
* SETcc, BMSKN, XBFU...
Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
2013-05-13 17:00:41 +04:00
IS_AVAIL1 ( cpu - > isa . div_rem , " div_rem " ) ,
2014-09-25 15:24:43 +04:00
IS_AVAIL1 ( cpu - > extn . norm , " norm " ) ,
IS_AVAIL1 ( cpu - > extn . barrel , " barrel-shift " ) ,
IS_AVAIL1 ( cpu - > extn . swap , " swap " ) ,
IS_AVAIL1 ( cpu - > extn . minmax , " minmax " ) ,
IS_AVAIL1 ( cpu - > extn . crc , " crc " ) ,
2016-10-21 04:08:10 +03:00
IS_AVAIL2 ( cpu - > extn . swape , " swape " , CONFIG_ARC_HAS_SWAPE ) ) ;
2013-01-18 13:42:24 +04:00
2014-09-25 15:24:43 +04:00
if ( cpu - > bpu . ver )
n + = scnprintf ( buf + n , len - n ,
2018-12-06 11:17:50 +03:00
" BPU \t \t : %s%s match, cache:%d, Predict Table:%d Return stk: %d " ,
2014-09-25 15:24:43 +04:00
IS_AVAIL1 ( cpu - > bpu . full , " full " ) ,
IS_AVAIL1 ( ! cpu - > bpu . full , " partial " ) ,
2018-12-06 11:17:50 +03:00
cpu - > bpu . num_cache , cpu - > bpu . num_pred , cpu - > bpu . ret_stk ) ;
2013-01-18 13:42:24 +04:00
2017-11-10 23:40:00 +03:00
if ( is_isa_arcv2 ( ) ) {
struct bcr_lpb lpb ;
READ_BCR ( ARC_REG_LPB_BUILD , lpb ) ;
if ( lpb . ver ) {
unsigned int ctl ;
ctl = read_aux_reg ( ARC_REG_LPB_CTRL ) ;
n + = scnprintf ( buf + n , len - n , " Loop Buffer:%d %s " ,
lpb . entries ,
IS_DISABLED_RUN ( ! ctl ) ) ;
}
}
n + = scnprintf ( buf + n , len - n , " \n " ) ;
2014-09-25 15:24:43 +04:00
return buf ;
}
2013-01-18 13:42:24 +04:00
2013-09-04 14:43:35 +04:00
static char * arc_extn_mumbojumbo ( int cpu_id , char * buf , int len )
2013-01-18 13:42:24 +04:00
{
int n = 0 ;
struct cpuinfo_arc * cpu = & cpuinfo_arc700 [ cpu_id ] ;
FIX_PTR ( cpu ) ;
2016-10-14 01:53:02 +03:00
n + = scnprintf ( buf + n , len - n , " Vector Table \t : %#x \n " , cpu - > vec_base ) ;
2014-09-25 15:24:43 +04:00
if ( cpu - > extn . fpu_sp | | cpu - > extn . fpu_dp )
n + = scnprintf ( buf + n , len - n , " FPU \t \t : %s%s \n " ,
IS_AVAIL1 ( cpu - > extn . fpu_sp , " SP " ) ,
IS_AVAIL1 ( cpu - > extn . fpu_dp , " DP " ) ) ;
2019-01-09 20:36:00 +03:00
if ( cpu - > extn . ap_num | cpu - > extn . smart | cpu - > extn . rtt ) {
n + = scnprintf ( buf + n , len - n , " DEBUG \t \t : %s%s " ,
2014-09-25 15:24:43 +04:00
IS_AVAIL1 ( cpu - > extn . smart , " smaRT " ) ,
IS_AVAIL1 ( cpu - > extn . rtt , " RTT " ) ) ;
2019-01-09 20:36:00 +03:00
if ( cpu - > extn . ap_num ) {
n + = scnprintf ( buf + n , len - n , " ActionPoint %d/%s " ,
cpu - > extn . ap_num ,
cpu - > extn . ap_full ? " full " : " min " ) ;
}
n + = scnprintf ( buf + n , len - n , " \n " ) ;
}
2014-09-25 15:24:43 +04:00
if ( cpu - > dccm . sz | | cpu - > iccm . sz )
n + = scnprintf ( buf + n , len - n , " Extn [CCM] \t : DCCM @ %x, %d KB / ICCM: @ %x, %d KB \n " ,
cpu - > dccm . base_addr , TO_KB ( cpu - > dccm . sz ) ,
2013-01-18 13:42:24 +04:00
cpu - > iccm . base_addr , TO_KB ( cpu - > iccm . sz ) ) ;
2017-11-10 23:40:00 +03:00
if ( is_isa_arcv2 ( ) ) {
/* Error Protection: ECC/Parity */
struct bcr_erp erp ;
READ_BCR ( ARC_REG_ERP_BUILD , erp ) ;
if ( erp . ver ) {
struct ctl_erp ctl ;
READ_BCR ( ARC_REG_ERP_CTRL , ctl ) ;
/* inverted bits: 0 means enabled */
n + = scnprintf ( buf + n , len - n , " Extn [ECC] \t : %s%s%s%s%s%s \n " ,
IS_AVAIL3 ( erp . ic , ! ctl . dpi , " IC " ) ,
IS_AVAIL3 ( erp . dc , ! ctl . dpd , " DC " ) ,
IS_AVAIL3 ( erp . mmu , ! ctl . mpd , " MMU " ) ) ;
}
}
2016-08-11 00:10:57 +03:00
n + = scnprintf ( buf + n , len - n , " OS ABI [v%d] \t : %s \n " ,
EF_ARC_OSABI_CURRENT > > 8 ,
EF_ARC_OSABI_CURRENT = = EF_ARC_OSABI_V3 ?
" no-legacy-syscalls " : " 64-bit data any register aligned " ) ;
2013-01-18 13:42:24 +04:00
return buf ;
}
2014-09-25 14:37:44 +04:00
static void arc_chk_core_config ( void )
2013-01-18 13:42:25 +04:00
{
struct cpuinfo_arc * cpu = & cpuinfo_arc700 [ smp_processor_id ( ) ] ;
2017-04-21 01:36:51 +03:00
int saved = 0 , present = 0 ;
2018-01-23 18:16:09 +03:00
char * opt_nm = NULL ;
2013-01-18 13:42:25 +04:00
2016-01-22 12:50:18 +03:00
if ( ! cpu - > extn . timer0 )
2014-09-25 15:24:43 +04:00
panic ( " Timer0 is not present! \n " ) ;
2016-01-22 12:50:18 +03:00
if ( ! cpu - > extn . timer1 )
2014-09-25 15:24:43 +04:00
panic ( " Timer1 is not present! \n " ) ;
2013-01-18 13:42:25 +04:00
# ifdef CONFIG_ARC_HAS_DCCM
/*
* DCCM can be arbit placed in hardware .
* Make sure it ' s placement / sz matches what Linux is built with
*/
if ( ( unsigned int ) __arc_dccm_base ! = cpu - > dccm . base_addr )
panic ( " Linux built with incorrect DCCM Base address \n " ) ;
if ( CONFIG_ARC_DCCM_SZ ! = cpu - > dccm . sz )
panic ( " Linux built with incorrect DCCM Size \n " ) ;
# endif
# ifdef CONFIG_ARC_HAS_ICCM
if ( CONFIG_ARC_ICCM_SZ ! = cpu - > iccm . sz )
panic ( " Linux built with incorrect ICCM Size \n " ) ;
# endif
2014-09-25 14:37:44 +04:00
/*
* FP hardware / software config sanity
2017-04-21 01:36:51 +03:00
* - If hardware present , kernel needs to save / restore FPU state
2014-09-25 14:37:44 +04:00
* - If not , it will crash trying to save / restore the non - existant regs
*/
2013-01-18 13:42:24 +04:00
2017-04-21 01:36:51 +03:00
if ( is_isa_arcompact ( ) ) {
opt_nm = " CONFIG_ARC_FPU_SAVE_RESTORE " ;
saved = IS_ENABLED ( CONFIG_ARC_FPU_SAVE_RESTORE ) ;
/* only DPDP checked since SP has no arch visible regs */
present = cpu - > extn . fpu_dp ;
} else {
opt_nm = " CONFIG_ARC_HAS_ACCL_REGS " ;
saved = IS_ENABLED ( CONFIG_ARC_HAS_ACCL_REGS ) ;
/* Accumulator Low:High pair (r58:59) present if DSP MPY or FPU */
present = cpu - > extn_mpy . dsp | cpu - > extn . fpu_sp | cpu - > extn . fpu_dp ;
}
if ( present & & ! saved )
pr_warn ( " Enable %s for working apps \n " , opt_nm ) ;
else if ( ! present & & saved )
panic ( " Disable %s, hardware NOT present \n " , opt_nm ) ;
2013-01-18 13:42:20 +04:00
}
/*
* Initialize and setup the processor core
* This is called by all the CPUs thus should not do special case stuff
* such as only for boot CPU etc
*/
2013-06-24 23:30:15 +04:00
void setup_processor ( void )
2013-01-18 13:42:20 +04:00
{
2013-01-18 13:42:24 +04:00
char str [ 512 ] ;
int cpu_id = smp_processor_id ( ) ;
2013-01-18 13:42:20 +04:00
read_arc_build_cfg_regs ( ) ;
arc_init_IRQ ( ) ;
2013-01-18 13:42:24 +04:00
2017-06-15 11:43:51 +03:00
pr_info ( " %s " , arc_cpu_mumbojumbo ( cpu_id , str , sizeof ( str ) ) ) ;
2013-01-18 13:42:24 +04:00
2013-01-18 13:42:20 +04:00
arc_mmu_init ( ) ;
arc_cache_init ( ) ;
2013-01-18 13:42:24 +04:00
2017-06-15 11:43:51 +03:00
pr_info ( " %s " , arc_extn_mumbojumbo ( cpu_id , str , sizeof ( str ) ) ) ;
pr_info ( " %s " , arc_platform_smp_cpuinfo ( ) ) ;
2013-01-18 13:42:24 +04:00
2014-09-25 14:37:44 +04:00
arc_chk_core_config ( ) ;
2013-01-18 13:42:20 +04:00
}
2014-01-16 13:31:24 +04:00
static inline int is_kernel ( unsigned long addr )
{
if ( addr > = ( unsigned long ) _stext & & addr < = ( unsigned long ) _end )
return 1 ;
return 0 ;
}
2013-01-18 13:42:20 +04:00
void __init setup_arch ( char * * cmdline_p )
{
2015-03-09 17:10:09 +03:00
# ifdef CONFIG_ARC_UBOOT_SUPPORT
2014-01-16 13:34:24 +04:00
/* make sure that uboot passed pointer to cmdline/dtb is valid */
if ( uboot_tag & & is_kernel ( ( unsigned long ) uboot_arg ) )
panic ( " Invalid uboot arg \n " ) ;
/* See if u-boot passed an external Device Tree blob */
machine_desc = setup_machine_fdt ( uboot_arg ) ; /* uboot_tag == 2 */
2015-03-09 17:10:09 +03:00
if ( ! machine_desc )
# endif
{
2014-01-16 13:34:24 +04:00
/* No, so try the embedded one */
2014-01-16 13:31:24 +04:00
machine_desc = setup_machine_fdt ( __dtb_start ) ;
if ( ! machine_desc )
panic ( " Embedded DT invalid \n " ) ;
/*
2014-01-16 13:34:24 +04:00
* If we are here , it is established that @ uboot_arg didn ' t
* point to DT blob . Instead if u - boot says it is cmdline ,
2016-05-21 14:45:35 +03:00
* append to embedded DT cmdline .
2014-01-16 13:31:24 +04:00
* setup_machine_fdt ( ) would have populated @ boot_command_line
*/
if ( uboot_tag = = 1 ) {
/* Ensure a whitespace between the 2 cmdlines */
strlcat ( boot_command_line , " " , COMMAND_LINE_SIZE ) ;
strlcat ( boot_command_line , uboot_arg ,
COMMAND_LINE_SIZE ) ;
}
2014-01-16 13:34:24 +04:00
}
2013-01-18 13:42:20 +04:00
/* Save unparsed command line copy for /proc/cmdline */
2013-04-09 14:48:04 +04:00
* cmdline_p = boot_command_line ;
2013-01-22 15:30:52 +04:00
2013-01-18 13:42:20 +04:00
/* To force early parsing of things like mem=xxx */
parse_early_param ( ) ;
/* Platform/board specific: e.g. early console registration */
2013-01-18 13:42:26 +04:00
if ( machine_desc - > init_early )
machine_desc - > init_early ( ) ;
2013-01-18 13:42:20 +04:00
2013-01-18 13:42:23 +04:00
smp_init_cpus ( ) ;
2015-10-12 13:58:55 +03:00
setup_processor ( ) ;
2013-01-18 13:42:20 +04:00
setup_arch_memory ( ) ;
2013-02-21 16:07:06 +04:00
/* copy flat DT out of .init and then unflatten it */
2013-08-26 20:23:27 +04:00
unflatten_and_copy_device_tree ( ) ;
2013-01-22 15:30:52 +04:00
2013-01-18 13:42:20 +04:00
/* Can be issue if someone passes cmd line arg "ro"
* But that is unlikely so keeping it as it is
*/
root_mountflags & = ~ MS_RDONLY ;
# if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE)
conswitchp = & dummy_con ;
# endif
2013-01-22 15:33:19 +04:00
arc_unwind_init ( ) ;
2013-01-18 13:42:20 +04:00
}
2016-10-31 23:26:25 +03:00
/*
* Called from start_kernel ( ) - boot CPU only
*/
void __init time_init ( void )
{
of_clk_init ( NULL ) ;
2017-05-26 18:40:46 +03:00
timer_probe ( ) ;
2016-10-31 23:26:25 +03:00
}
2013-01-18 13:42:26 +04:00
static int __init customize_machine ( void )
{
if ( machine_desc - > init_machine )
machine_desc - > init_machine ( ) ;
return 0 ;
}
arch_initcall ( customize_machine ) ;
static int __init init_late_machine ( void )
{
if ( machine_desc - > init_late )
machine_desc - > init_late ( ) ;
return 0 ;
}
late_initcall ( init_late_machine ) ;
2013-01-18 13:42:20 +04:00
/*
* Get CPU information for use by the procfs .
*/
# define cpu_to_ptr(c) ((void *)(0xFFFF0000 | (unsigned int)(c)))
# define ptr_to_cpu(p) (~0xFFFF0000UL & (unsigned int)(p))
static int show_cpuinfo ( struct seq_file * m , void * v )
{
char * str ;
int cpu_id = ptr_to_cpu ( v ) ;
2017-03-03 14:30:02 +03:00
struct device * cpu_dev = get_cpu_device ( cpu_id ) ;
struct clk * cpu_clk ;
unsigned long freq = 0 ;
2013-01-18 13:42:20 +04:00
2014-12-12 07:35:03 +03:00
if ( ! cpu_online ( cpu_id ) ) {
seq_printf ( m , " processor [%d] \t : Offline \n " , cpu_id ) ;
goto done ;
}
2017-09-14 02:28:29 +03:00
str = ( char * ) __get_free_page ( GFP_KERNEL ) ;
2013-01-18 13:42:20 +04:00
if ( ! str )
goto done ;
2013-01-18 13:42:24 +04:00
seq_printf ( m , arc_cpu_mumbojumbo ( cpu_id , str , PAGE_SIZE ) ) ;
2013-01-18 13:42:20 +04:00
2017-03-03 14:30:02 +03:00
cpu_clk = clk_get ( cpu_dev , NULL ) ;
if ( IS_ERR ( cpu_clk ) ) {
seq_printf ( m , " CPU speed \t : Cannot get clock for processor [%d] \n " ,
cpu_id ) ;
} else {
freq = clk_get_rate ( cpu_clk ) ;
}
2016-02-01 17:30:17 +03:00
if ( freq )
2017-03-03 14:30:02 +03:00
seq_printf ( m , " CPU speed \t : %lu.%02lu Mhz \n " ,
2016-02-01 17:30:17 +03:00
freq / 1000000 , ( freq / 10000 ) % 100 ) ;
2014-09-25 15:24:43 +04:00
seq_printf ( m , " Bogo MIPS \t : %lu.%02lu \n " ,
2013-01-18 13:42:20 +04:00
loops_per_jiffy / ( 500000 / HZ ) ,
( loops_per_jiffy / ( 5000 / HZ ) ) % 100 ) ;
2013-01-18 13:42:24 +04:00
seq_printf ( m , arc_mmu_mumbojumbo ( cpu_id , str , PAGE_SIZE ) ) ;
seq_printf ( m , arc_cache_mumbojumbo ( cpu_id , str , PAGE_SIZE ) ) ;
seq_printf ( m , arc_extn_mumbojumbo ( cpu_id , str , PAGE_SIZE ) ) ;
seq_printf ( m , arc_platform_smp_cpuinfo ( ) ) ;
2013-01-18 13:42:20 +04:00
free_page ( ( unsigned long ) str ) ;
done :
2014-12-12 07:35:03 +03:00
seq_printf ( m , " \n " ) ;
2013-01-18 13:42:20 +04:00
return 0 ;
}
static void * c_start ( struct seq_file * m , loff_t * pos )
{
/*
* Callback returns cpu - id to iterator for show routine , NULL to stop .
* However since NULL is also a valid cpu - id ( 0 ) , we use a round - about
* way to pass it w / o having to kmalloc / free a 2 byte string .
* Encode cpu - id as 0xFFcccc , which is decoded by show routine .
*/
2016-10-19 14:25:03 +03:00
return * pos < nr_cpu_ids ? cpu_to_ptr ( * pos ) : NULL ;
2013-01-18 13:42:20 +04:00
}
static void * c_next ( struct seq_file * m , void * v , loff_t * pos )
{
+ + * pos ;
return c_start ( m , pos ) ;
}
static void c_stop ( struct seq_file * m , void * v )
{
}
const struct seq_operations cpuinfo_op = {
. start = c_start ,
. next = c_next ,
. stop = c_stop ,
. show = show_cpuinfo
} ;
static DEFINE_PER_CPU ( struct cpu , cpu_topology ) ;
static int __init topology_init ( void )
{
int cpu ;
for_each_present_cpu ( cpu )
register_cpu ( & per_cpu ( cpu_topology , cpu ) , cpu ) ;
return 0 ;
}
subsys_initcall ( topology_init ) ;