[PATCH v1 11/20] ARC: [plat-eznps] Add eznps platform

Vineet Gupta Vineet.Gupta1 at synopsys.com
Wed Nov 4 21:09:25 PST 2015


On Saturday 31 October 2015 06:45 PM, Noam Camus wrote:
> From: Noam Camus <noamc at ezchip.com>
> 
> This platform include boards:
> 	Hardware Emulator (HE)
> 	Simulator based upon nSIM.
> 
> Signed-off-by: Noam Camus <noamc at ezchip.com>
> ---
>  MAINTAINERS                             |    6 +
>  arch/arc/plat-eznps/Kconfig             |   34 ++++
>  arch/arc/plat-eznps/Makefile            |    7 +
>  arch/arc/plat-eznps/entry.S             |   76 +++++++++
>  arch/arc/plat-eznps/include/plat/ctop.h |  264 +++++++++++++++++++++++++++++++
>  arch/arc/plat-eznps/include/plat/mtm.h  |   60 +++++++
>  arch/arc/plat-eznps/include/plat/smp.h  |   27 +++
>  arch/arc/plat-eznps/mtm.c               |  152 ++++++++++++++++++
>  arch/arc/plat-eznps/platform.c          |   40 +++++
>  arch/arc/plat-eznps/smp.c               |  160 +++++++++++++++++++
>  10 files changed, 826 insertions(+), 0 deletions(-)
>  create mode 100644 arch/arc/plat-eznps/Kconfig
>  create mode 100644 arch/arc/plat-eznps/Makefile
>  create mode 100644 arch/arc/plat-eznps/entry.S
>  create mode 100644 arch/arc/plat-eznps/include/plat/ctop.h
>  create mode 100644 arch/arc/plat-eznps/include/plat/mtm.h
>  create mode 100644 arch/arc/plat-eznps/include/plat/smp.h
>  create mode 100644 arch/arc/plat-eznps/mtm.c
>  create mode 100644 arch/arc/plat-eznps/platform.c
>  create mode 100644 arch/arc/plat-eznps/smp.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 08adb4a..c63ca18 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -4171,6 +4171,12 @@ S:	Maintained
>  F:	drivers/video/fbdev/exynos/exynos_mipi*
>  F:	include/video/exynos_mipi*
>  
> +EZchip NPS platform support
> +M:	Noam Camus <noamc at ezchip.com>
> +S:	Supported
> +F:	arch/arc/plat-eznps
> +F:	arch/arc/boot/dts/eznps.dts
> +
>  F71805F HARDWARE MONITORING DRIVER
>  M:	Jean Delvare <jdelvare at suse.com>
>  L:	lm-sensors at lm-sensors.org
> diff --git a/arch/arc/plat-eznps/Kconfig b/arch/arc/plat-eznps/Kconfig
> new file mode 100644
> index 0000000..510354f
> --- /dev/null
> +++ b/arch/arc/plat-eznps/Kconfig
> @@ -0,0 +1,34 @@
> +#
> +# For a description of the syntax of this configuration file,
> +# see Documentation/kbuild/kconfig-language.txt.
> +#
> +
> +menuconfig ARC_PLAT_EZNPS
> +	bool "\"EZchip\" ARC dev platform"
> +	select ARC_HAS_COH_CACHES if SMP
> +	select CPU_BIG_ENDIAN
> +	select CLKSRC_OF
> +	select EZCHIP_NPS_MANAGEMENT_ENET if ETHERNET
> +	help
> +	  Support for EZchip development platforms,
> +	  based on ARC700 cores.
> +	  We handle few flavours:
> +	    - Hardware Emulator AKA HE which is FPGA based chasis
> +	    - Simulator based on MetaWare nSIM
> +	    - NPS400 chip based on ASIC
> +
> +config EZNPS_MTM_EXT
> +	bool "ARC-EZchip MTM Extensions"
> +	select CPUMASK_OFFSTACK
> +	depends on ARC_PLAT_EZNPS && SMP
> +	default y
> +	help
> +	  Here we add new hierarchy for CPUs topology.
> +	  We got:
> +		Core
> +		Thread
> +	  At the new thread level each CPU represent one HW thread.
> +	  At highest hierarchy each core contain 16 threads,
> +	  any of them seem like CPU from Linux point of view.
> +	  All threads within same core share the execution unit of the
> +	  core and HW scheduler round robin between them.
> diff --git a/arch/arc/plat-eznps/Makefile b/arch/arc/plat-eznps/Makefile
> new file mode 100644
> index 0000000..21091b1
> --- /dev/null
> +++ b/arch/arc/plat-eznps/Makefile
> @@ -0,0 +1,7 @@
> +#
> +# Makefile for the linux kernel.
> +#
> +
> +obj-y := entry.o platform.o
> +obj-$(CONFIG_SMP) += smp.o
> +obj-$(CONFIG_EZNPS_MTM_EXT) += mtm.o
> diff --git a/arch/arc/plat-eznps/entry.S b/arch/arc/plat-eznps/entry.S
> new file mode 100644
> index 0000000..a3dec3e
> --- /dev/null
> +++ b/arch/arc/plat-eznps/entry.S
> @@ -0,0 +1,76 @@
> +/*******************************************************************************
> +
> +  EZNPS CPU startup Code
> +  Copyright(c) 2012 EZchip Technologies.
> +
> +  This program is free software; you can redistribute it and/or modify it
> +  under the terms and conditions of the GNU General Public License,
> +  version 2, as published by the Free Software Foundation.
> +
> +  This program is distributed in the hope 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.
> +
> +  The full GNU General Public License is included in this distribution in
> +  the file called "COPYING".
> +
> +*******************************************************************************/
> +#include <linux/linkage.h>
> +#include <asm/entry.h>
> +#include <asm/cache.h>
> +#include <plat/ctop.h>
> +
> +	.cpu A7
> +
> +	.section .text, "ax", at progbits
> +	.align 1024	; HW requierment for restart first PC
> +
> +ENTRY(res_service)
> +#ifdef CONFIG_EZNPS_MTM_EXT
> +	; For HW thread != 0 there is no work.
> +	lr	r3, [CTOP_AUX_THREAD_ID]
> +	cmp	r3, 0
> +	jne	_stext

Don't use _stext - it new rols is to simply demarcate where kernel code starts and
not guaranteed to be code you want to jump to. Per latest head.S, it is stext

> +#endif
> +
> +#ifdef CONFIG_ARC_HAS_DCACHE
> +	; We do not have cache coherency mechanism,
> +	; so D$ need to be used very carefully.

Can these go in same line

> +	; Address space:
> +	; 0G-2G: We disable CONFIG_ARC_CACHE_PAGES.
> +	; 2G-3G: We disable D$ by setting this bit.
> +	; 3G-4G: D$ is disabled by architecture.
> +	; FMT are the huge pages for user application reside at 0-2G.
> +	; Only FMT left as one who can use D$ where each such page got
> +	; disable/enable bit for cachability.
> +	; Programmer will use FMT pages for private data so cache coherency
> +	; would not be a problem.
> +	; First thing we invalidate D$
> +	sr	1, [ARC_REG_DC_IVDC]
> +	sr	HW_COMPLY_KRN_NOT_D_CACHED, [CTOP_AUX_HW_COMPLY]
> +#endif
> +
> +#ifdef CONFIG_SMP
> +	; check for boot CPU
> +	lr	r3, [CTOP_AUX_GLOBAL_ID]
> +	cmp	r3, 0
> +	jeq	_stext
> +
> +	; We set logical cpuid to be used by GET_CPUID
> +	; We do not use physical cpuid since we want ids to be continious when
> +	; it comes to cpus on the same quad cluster.
> +	; This is useful for applications that used shared resources of a quad
> +	; cluster such SRAMS.
> +	lr 	r3, [CTOP_AUX_CORE_ID]
> +	sr	r3, [CTOP_AUX_LOGIC_CORE_ID]
> +	lr	r3, [CTOP_AUX_CLUSTER_ID]
> +	; Set logical is acheived by swap of 2 middle bits of cluster id (4 bit)
> +	; r3 is used since we use short instruction and we need q-class reg
> +	.short	CTOP_INST_MOV2B_FLIP_R3_B1_B2_INST
> +	.word 	CTOP_INST_MOV2B_FLIP_R3_B1_B2_LIMM
> +	 sr	r3, [CTOP_AUX_LOGIC_CLUSTER_ID]
> +#endif
> +
> +	j	_stext
> +END(res_service)
> diff --git a/arch/arc/plat-eznps/include/plat/ctop.h b/arch/arc/plat-eznps/include/plat/ctop.h
> new file mode 100644
> index 0000000..b708f9f
> --- /dev/null
> +++ b/arch/arc/plat-eznps/include/plat/ctop.h
> @@ -0,0 +1,264 @@
> +/*
> + * Copyright(c) 2015 EZchip Technologies.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope 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.
> + *
> + * The full GNU General Public License is included in this distribution in
> + * the file called "COPYING".
> + */
> +
> +#ifndef _PLAT_EZNPS_CTOP_H
> +#define _PLAT_EZNPS_CTOP_H
> +
> +#define NPS_HOST_REG_BASE		0xF6000000
> +
> +/* core auxiliary registers */
> +#define CTOP_AUX_BASE			0xFFFFF800
> +#define CTOP_AUX_GLOBAL_ID		(CTOP_AUX_BASE + 0x000)
> +#define CTOP_AUX_CLUSTER_ID		(CTOP_AUX_BASE + 0x004)
> +#define CTOP_AUX_CORE_ID		(CTOP_AUX_BASE + 0x008)
> +#define CTOP_AUX_THREAD_ID		(CTOP_AUX_BASE + 0x00C)
> +#define CTOP_AUX_LOGIC_GLOBAL_ID	(CTOP_AUX_BASE + 0x010)
> +#define CTOP_AUX_LOGIC_CLUSTER_ID	(CTOP_AUX_BASE + 0x014)
> +#define CTOP_AUX_LOGIC_CORE_ID		(CTOP_AUX_BASE + 0x018)
> +#define CTOP_AUX_MT_CTRL		(CTOP_AUX_BASE + 0x020)
> +#define CTOP_AUX_HW_COMPLY		(CTOP_AUX_BASE + 0x024)
> +#define CTOP_AUX_LPC			(CTOP_AUX_BASE + 0x030)
> +#define AUX_REG_TSI1			(CTOP_AUX_BASE + 0x050)
> +#define CTOP_AUX_EFLAGS			(CTOP_AUX_BASE + 0x080)
> +#define CTOP_AUX_IACK			(CTOP_AUX_BASE + 0x088)
> +#define CTOP_AUX_UDMC			(CTOP_AUX_BASE + 0x300)
> +
> +/* EZchip core instructions */
> +#define CTOP_INST_HWSCHD_OFF_R3			0x3b6f00bf
> +#define CTOP_INST_HWSCHD_OFF_R4			0x3c6f00bf
> +#define CTOP_INST_HWSCHD_RESTORE_R3		0x3e6f7083
> +#define CTOP_INST_HWSCHD_RESTORE_R4		0x3e6f7103
> +#define CTOP_INST_SCHD_RW			0x3e6f7004
> +#define CTOP_INST_SCHD_RD			0x3e6f7084
> +#define CTOP_INST_ASRI_0_R3			0x3b56003e
> +#define CTOP_INST_XEX_DI_R2_R2_R3		0x4a664c00
> +#define CTOP_INST_EXC_DI_R2_R2_R3		0x4a664c01
> +#define CTOP_INST_AADD_DI_R2_R2_R3		0x4a664c02
> +#define CTOP_INST_AAND_DI_R2_R2_R3		0x4a664c04
> +#define CTOP_INST_AOR_DI_R2_R2_R3		0x4a664c05
> +#define CTOP_INST_AXOR_DI_R2_R2_R3		0x4a664c06
> +#define CTOP_INST_MOV2B_FLIP_R3_B1_B2_INST	0x5b60
> +#define CTOP_INST_MOV2B_FLIP_R3_B1_B2_LIMM	0x00010422
> +#define CTOP_INST_RSPI_GIC_0_R12		0x3c56117e
> +
> +/* Do not use D$ for address in 2G-3G */
> +#define HW_COMPLY_KRN_NOT_D_CACHED	(1 << 28)
> +
> +#ifndef __ASSEMBLY__
> +#define NPS_MSU_BLKID			0x018
> +#define NPS_CRG_BLKID			0x480
> +#define NPS_CRG_SYNC_BIT		BIT(0)
> +
> +#define NPS_GIM_BLKID			0x5C0
> +#define NPS_GIM_UART_LINE		BIT(7)
> +#define NPS_GIM_DBG_LAN_TX_DONE_LINE	BIT(10)
> +#define NPS_GIM_DBG_LAN_RX_RDY_LINE	BIT(11)
> +
> +/* CPU global ID */
> +struct global_id {
> +	union {
> +		struct {
> +#ifdef CONFIG_EZNPS_MTM_EXT
> +			u32 __reserved:20, cluster:4, core:4, thread:4;
> +#else
> +			u32 __reserved:24, cluster:4, core:4;
> +#endif
> +		};
> +		u32 value;
> +	};
> +};
> +
> +/*
> + * Convert logical to physical CPU IDs
> + *
> + * The conversion swap bits 1 and 2 of cluster id (out of 4 bits)
> + * Now quad of logical clusters id's are adjacent physicaly,

physically

> + * like can be seen in following table.
> + * Cluster ids are in format: logical (physical)
> + *
> + * 3 |  5 (3)  |  7 (7)  ||  13 (11) |  15 (15)
> + * 2 |  4 (2)  |  6 (6)  ||  12 (10) |  14 (14)
> + * ============================================
> + * 1 |  1 (1)  |  3 (5)  ||  9  (9)  |  11 (13)
> + * 0 |  0 (0)  |  2 (4)  ||  8  (8)  |  10 (12)
> + * --------------------------------------------
> + *   |   0     |   1     ||    2     |    3

I can't quite understand how to read this table !

> + */
> +static inline int nps_cluster_logic_to_phys(int cluster)
> +{
> +	__asm__ __volatile__(
> +	"       mov r3,%0\n"
> +	"       .short %1\n"
> +	"       .word %2\n"
> +	"       mov %0,r3\n"
> +	: "+r"(cluster)
> +	: "i"(CTOP_INST_MOV2B_FLIP_R3_B1_B2_INST),
> +	  "i"(CTOP_INST_MOV2B_FLIP_R3_B1_B2_LIMM)
> +	: "r3");
> +
> +	return cluster;
> +}
> +
> +#define NPS_CPU_TO_CLUSTER_NUM(cpu) \
> +	({ struct global_id gid; gid.value = cpu; \
> +		nps_cluster_logic_to_phys(gid.cluster); })
> +
> +struct nps_host_reg_address {
> +	union {
> +		struct {
> +			u32     base:8, cl_x:4, cl_y:4,
> +			blkid:6, reg:8, __reserved:2;
> +		};
> +		u32 value;
> +	};
> +};
> +
> +struct nps_host_reg_mtm_cfg {
> +	union {
> +		struct {
> +			u32 gen:1, gdis:1, clk_gate_dis:1, asb:1,
> +			__reserved:9, nat:3, ten:16;
> +		};
> +		u32 value;
> +	};
> +};
> +
> +struct nps_host_reg_mtm_cpu_cfg {
> +	union {
> +		struct {
> +			u32 csa:22, dmsid:6, __reserved:3, cs:1;
> +		};
> +		u32 value;
> +	};
> +};
> +
> +struct nps_host_reg_thr_init {
> +	union {
> +		struct {
> +			u32 str:1, __reserved:27, thr_id:4;
> +		};
> +		u32 value;
> +	};
> +};
> +
> +struct nps_host_reg_thr_init_sts {
> +	union {
> +		struct {
> +			u32 bsy:1, err:1, __reserved:26, thr_id:4;
> +		};
> +		u32 value;
> +	};
> +};
> +
> +struct nps_host_reg_aux_udmc {
> +	union {
> +		struct {
> +			u32 dcp:1, cme:1, __reserved:20, nat:3,
> +			__reserved2:5, dcas:3;
> +		};
> +		u32 value;
> +	};
> +};
> +
> +struct nps_host_reg_aux_mt_ctrl {
> +	union {
> +		struct {
> +			u32 mten:1, hsen:1, scd:1, sten:1,
> +			__reserved:4, st_cnt:4, __reserved2:8,
> +			hs_cnt:8, __reserved3:4;
> +		};
> +		u32 value;
> +	};
> +};
> +
> +struct nps_host_reg_aux_hw_comply {
> +	union {
> +		struct {
> +			u32 me:1, le:1, te:1, knc:1, __reserved:28;
> +		};
> +		u32 value;
> +	};
> +};
> +
> +struct nps_host_reg_aux_lpc {
> +	union {
> +		struct {
> +			u32 mep:1, __reserved:31;
> +		};
> +		u32 value;
> +	};
> +};
> +
> +struct nps_host_reg_address_non_cl {
> +	union {
> +		struct {
> +			u32 base:7, blkid:11, reg:12, __reserved:2;
> +		};
> +		u32 value;
> +	};
> +};
> +
> +struct nps_host_reg_gim_p_int_dst {
> +	union {
> +		struct {
> +			u32 int_out_en:1, __reserved1:4,
> +			is:1, intm:2, __reserved2:4,
> +			nid:4, __reserved3:4, cid:4,
> +			__reserved4:4, tid:4;
> +		};
> +		u32 value;
> +	};
> +};
> +
> +static inline void *nps_host_reg_non_cl(u32 blkid, u32 reg)
> +{
> +	struct nps_host_reg_address_non_cl reg_address;
> +
> +	reg_address.value = NPS_HOST_REG_BASE;
> +	reg_address.blkid = blkid;
> +	reg_address.reg = reg;
> +
> +	return (void *)reg_address.value;
> +}
> +
> +static inline void *nps_host_reg(u32 cpu, u32 blkid, u32 reg)
> +{
> +	struct nps_host_reg_address reg_address;
> +	u32 cl = NPS_CPU_TO_CLUSTER_NUM(cpu);
> +
> +	reg_address.value = NPS_HOST_REG_BASE;
> +	reg_address.cl_x  = (cl >> 2) & 0x3;
> +	reg_address.cl_y  = cl & 0x3;
> +	reg_address.blkid = blkid;
> +	reg_address.reg   = reg;
> +
> +	return (void *)reg_address.value;
> +}
> +
> +/* CRG registers */
> +#define REG_GEN_PURP_0	nps_host_reg_non_cl(NPS_CRG_BLKID, 0x1BF)
> +
> +/* GIM registers */
> +#define REG_GIM_P_INT_EN_0	nps_host_reg_non_cl(NPS_GIM_BLKID, 0x100)
> +#define REG_GIM_P_INT_POL_0	nps_host_reg_non_cl(NPS_GIM_BLKID, 0x110)
> +#define REG_GIM_P_INT_SENS_0	nps_host_reg_non_cl(NPS_GIM_BLKID, 0x114)
> +#define REG_GIM_P_INT_BLK_0	nps_host_reg_non_cl(NPS_GIM_BLKID, 0x118)
> +#define REG_GIM_P_INT_DST_10	nps_host_reg_non_cl(NPS_GIM_BLKID, 0x13A)
> +#define REG_GIM_P_INT_DST_11	nps_host_reg_non_cl(NPS_GIM_BLKID, 0x13B)
> +
> +#endif /* __ASEMBLY__ */
> +
> +#endif /* _PLAT_EZNPS_CTOP_H */
> diff --git a/arch/arc/plat-eznps/include/plat/mtm.h b/arch/arc/plat-eznps/include/plat/mtm.h
> new file mode 100644
> index 0000000..29b91b5
> --- /dev/null
> +++ b/arch/arc/plat-eznps/include/plat/mtm.h
> @@ -0,0 +1,60 @@
> +/*
> + * Copyright(c) 2015 EZchip Technologies.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope 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.
> + *
> + * The full GNU General Public License is included in this distribution in
> + * the file called "COPYING".
> + */
> +
> +#ifndef _PLAT_EZNPS_MTM_H
> +#define _PLAT_EZNPS_MTM_H
> +
> +#include <plat/ctop.h>
> +
> +static inline void *nps_mtm_reg_addr(u32 cpu, u32 reg)
> +{
> +	struct global_id gid;
> +	u32 core, blkid;
> +
> +	gid.value = cpu;
> +	core = gid.core;
> +	blkid = (((core & 0x0C) << 2) | (core & 0x03));
> +
> +	return nps_host_reg(cpu, blkid, reg);
> +}
> +
> +#ifdef CONFIG_EZNPS_MTM_EXT
> +#define NPS_CPU_TO_THREAD_NUM(cpu) \
> +	({ struct global_id gid; gid.value = cpu; gid.thread; })
> +
> +/* MTM registers */
> +#define MTM_CFG(cpu)			nps_mtm_reg_addr(cpu, 0x81)
> +#define MTM_THR_INIT(cpu)		nps_mtm_reg_addr(cpu, 0x92)
> +#define MTM_THR_INIT_STS(cpu)		nps_mtm_reg_addr(cpu, 0x93)
> +
> +#define get_thread(map) map.thread
> +#define eznps_max_cpus 4096
> +#define eznps_cpus_per_cluster	256
> +
> +void mtm_enable_core(unsigned int cpu);
> +int mtm_enable_thread(int cpu);
> +#else /* !CONFIG_EZNPS_MTM_EXT */
> +
> +#define get_thread(map) 0
> +#define eznps_max_cpus 256
> +#define eznps_cpus_per_cluster	16
> +#define mtm_enable_core(cpu)
> +#define mtm_enable_thread(cpu) 1
> +#define NPS_CPU_TO_THREAD_NUM(cpu) 0
> +
> +#endif /* CONFIG_EZNPS_MTM_EXT */
> +
> +#endif /* _PLAT_EZNPS_MTM_H */
> diff --git a/arch/arc/plat-eznps/include/plat/smp.h b/arch/arc/plat-eznps/include/plat/smp.h
> new file mode 100644
> index 0000000..7509443
> --- /dev/null
> +++ b/arch/arc/plat-eznps/include/plat/smp.h
> @@ -0,0 +1,27 @@
> +/*
> + * Copyright(c) 2015 EZchip Technologies.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope 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.
> + *
> + * The full GNU General Public License is included in this distribution in
> + * the file called "COPYING".
> + */
> +
> +#ifndef __PLAT_EZNPS_SMP_H
> +#define __PLAT_EZNPS_SMP_H
> +
> +#ifdef CONFIG_SMP
> +
> +extern struct cpumask _cpu_possible_mask;

Is this needed ?

> +void eznps_smp_init_cpu(unsigned int cpu);

You don't need this either - see below !

> +
> +#endif /* CONFIG_SMP */
> +
> +#endif
> diff --git a/arch/arc/plat-eznps/mtm.c b/arch/arc/plat-eznps/mtm.c
> new file mode 100644
> index 0000000..802c3c8
> --- /dev/null
> +++ b/arch/arc/plat-eznps/mtm.c
> @@ -0,0 +1,152 @@
> +/*
> + * Copyright(c) 2015 EZchip Technologies.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope 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.
> + *
> + * The full GNU General Public License is included in this distribution in
> + * the file called "COPYING".
> + */
> +
> +#include <linux/smp.h>
> +#include <linux/io.h>
> +#include <asm/arcregs.h>
> +#include <plat/mtm.h>
> +#include <plat/smp.h>
> +
> +#define MT_CTRL_HS_CNT		0xFF
> +#define MT_CTRL_ST_CNT		0xF
> +#define NPS_NUM_HW_THREADS	0x10
> +
> +static void mtm_init_nat(int cpu)
> +{
> +	struct nps_host_reg_mtm_cfg mtm_cfg;
> +	struct nps_host_reg_aux_udmc udmc;
> +	int log_nat, nat = 0, i, t;
> +
> +	/* Iterate core threads and update nat */
> +	for (i = 0, t = cpu; i < NPS_NUM_HW_THREADS; i++, t++)
> +		nat += test_bit(t, cpumask_bits(cpu_possible_mask));
> +
> +	switch (nat) {
> +	case 1:
> +		log_nat = 0;
> +		break;
> +	case 2:
> +		log_nat = 1;
> +		break;
> +	case 4:
> +		log_nat = 2;
> +		break;
> +	case 8:
> +		log_nat = 3;
> +		break;
> +	case 16:
> +		log_nat = 4;
> +		break;

Can u use a some ilog function do do this ?

> +	default:
> +		pr_warn("BUG: got non valid NAT %d!\n", nat);
> +		log_nat = 0;
> +		break;
> +	}
> +
> +	udmc.value = read_aux_reg(CTOP_AUX_UDMC);
> +	udmc.nat = log_nat;
> +	write_aux_reg(CTOP_AUX_UDMC, udmc.value);
> +
> +	mtm_cfg.value = ioread32be(MTM_CFG(cpu));
> +	mtm_cfg.nat = log_nat;
> +	iowrite32be(mtm_cfg.value, MTM_CFG(cpu));
> +}
> +
> +static void mtm_init_thread(int cpu)
> +{
> +	int i, tries = 5;
> +	struct nps_host_reg_thr_init thr_init;
> +	struct nps_host_reg_thr_init_sts thr_init_sts;
> +
> +	/* Set thread init register */
> +	thr_init.value = 0;
> +	iowrite32be(thr_init.value, MTM_THR_INIT(cpu));
> +	thr_init.thr_id = NPS_CPU_TO_THREAD_NUM(cpu);
> +	thr_init.str = 1;
> +	iowrite32be(thr_init.value, MTM_THR_INIT(cpu));
> +
> +	/* Poll till thread init is done */
> +	for (i = 0; i < tries; i++) {
> +		thr_init_sts.value = ioread32be(MTM_THR_INIT_STS(cpu));
> +		if (thr_init_sts.thr_id == thr_init.thr_id) {
> +			if (thr_init_sts.bsy)
> +				continue;
> +			else if (thr_init_sts.err)
> +				pr_warn("Failed to thread init cpu %u\n", cpu);
> +			break;
> +		}
> +
> +		pr_warn("Wrong thread id in thread init for cpu %u\n", cpu);
> +		break;
> +	}
> +
> +	if (i == tries)
> +		pr_warn("Got thread init timeout for cpu %u\n", cpu);
> +}
> +
> +int mtm_enable_thread(int cpu)
> +{
> +	struct nps_host_reg_mtm_cfg mtm_cfg;
> +
> +	if (NPS_CPU_TO_THREAD_NUM(cpu) == 0)
> +		return 1;
> +
> +	/* Enable thread in mtm */
> +	mtm_cfg.value = ioread32be(MTM_CFG(cpu));
> +	mtm_cfg.ten |= (1 << (NPS_CPU_TO_THREAD_NUM(cpu)));
> +	iowrite32be(mtm_cfg.value, MTM_CFG(cpu));
> +
> +	return 0;
> +}
> +
> +void mtm_enable_core(unsigned int cpu)
> +{
> +	int i;
> +	struct nps_host_reg_aux_mt_ctrl mt_ctrl;
> +	struct nps_host_reg_mtm_cfg mtm_cfg;
> +
> +	if (NPS_CPU_TO_THREAD_NUM(cpu) != 0)
> +		return;
> +
> +	/* Initialize Number of Active Threads */
> +	mtm_init_nat(cpu);
> +
> +	/* Initialize mtm_cfg */
> +	mtm_cfg.value = ioread32be(MTM_CFG(cpu));
> +	mtm_cfg.ten = 1;
> +	iowrite32be(mtm_cfg.value, MTM_CFG(cpu));
> +
> +	/* Initialize all other threads in core */
> +	for (i = 1; i < NPS_NUM_HW_THREADS; i++)
> +		mtm_init_thread(cpu + i);
> +
> +
> +	/* Enable HW schedule, stall counter, mtm */
> +	mt_ctrl.value = 0;
> +	mt_ctrl.hsen = 1;
> +	mt_ctrl.hs_cnt = MT_CTRL_HS_CNT;
> +	mt_ctrl.sten = 1;
> +	mt_ctrl.st_cnt = MT_CTRL_ST_CNT;
> +	mt_ctrl.mten = 1;
> +	write_aux_reg(CTOP_AUX_MT_CTRL, mt_ctrl.value);
> +
> +	/*
> +	 * HW scheduling mechanism will start working
> +	 * Only after call to instruction "schd.rw".
> +	 * cpu_relax() calls "schd.rw" instruction.
> +	 */
> +	cpu_relax();
> +}
> diff --git a/arch/arc/plat-eznps/platform.c b/arch/arc/plat-eznps/platform.c
> new file mode 100644
> index 0000000..c84dfd9
> --- /dev/null
> +++ b/arch/arc/plat-eznps/platform.c
> @@ -0,0 +1,40 @@
> +/*
> + * Copyright(c) 2015 EZchip Technologies.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope 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.
> + *
> + * The full GNU General Public License is included in this distribution in
> + * the file called "COPYING".
> + */
> +
> +#include <linux/init.h>
> +#include <asm/io.h>
> +#include <asm/mach_desc.h>
> +#include <plat/smp.h>

This will go away

> +
> +/*----------------------- Machine Descriptions ------------------------------
> + *
> + * Machine description is simply a set of platform/board specific callbacks
> + * This is not directly related to DeviceTree based dynamic device creation,
> + * however as part of early device tree scan, we also select the right
> + * callback set, by matching the DT compatible name.
> + */

No Cargo Culting please. Delete this comment !

> +
> +static const char *eznps_compat[] __initconst = {
> +	"ezchip,arc-nps",
> +	NULL,
> +};
> +
> +MACHINE_START(NPS, "nps")
> +	.dt_compat	= eznps_compat,
> +#ifdef CONFIG_SMP
> +	.init_cpu_smp	= eznps_smp_init_cpu,  /* for each CPU */
> +#endif

This is not needed. See below !

> +MACHINE_END
> diff --git a/arch/arc/plat-eznps/smp.c b/arch/arc/plat-eznps/smp.c
> new file mode 100644
> index 0000000..0f8b51a
> --- /dev/null
> +++ b/arch/arc/plat-eznps/smp.c
> @@ -0,0 +1,160 @@
> +/*
> + * Copyright(c) 2015 EZchip Technologies.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope 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.
> + *
> + * The full GNU General Public License is included in this distribution in
> + * the file called "COPYING".
> + */
> +
> +#include <linux/smp.h>
> +#include <linux/of_fdt.h>
> +#include <linux/io.h>
> +#include <asm/irq.h>
> +#include <plat/ctop.h>
> +#include <plat/smp.h>
> +#include <plat/mtm.h>
> +
> +#define NPS_DEFAULT_MSID	0x34
> +#define NPS_MTM_CPU_CFG		0x90
> +
> +struct cpumask _cpu_possible_mask;
> +static char smp_cpuinfo_buf[128] = {"Extn [EZNPS-SMP]\t: On\n"};
> +
> +/* Get cpu map from device tree */
> +static int __init eznps_get_map(const char *name, struct cpumask *cpumask)
> +{
> +	unsigned long dt_root = of_get_flat_dt_root();
> +	const char *buf;
> +
> +	buf = of_get_flat_dt_prop(dt_root, name, NULL);
> +	if (!buf)
> +		return 1;
> +
> +	cpulist_parse(buf, cpumask);
> +
> +	return 0;
> +}
> +
> +/* Update board cpu maps */
> +static void __init eznps_init_cpumasks(void)
> +{
> +	struct cpumask cpumask;
> +
> +	if (eznps_get_map("present-cpus", &cpumask)) {
> +		pr_err("Failed to get present-cpus from dtb");
> +		return;
> +	}
> +	init_cpu_present(&cpumask);
> +
> +	if (eznps_get_map("possible-cpus", &cpumask)) {
> +		pr_err("Failed to get possible-cpus from dtb");
> +		return;
> +	}
> +	init_cpu_possible(&cpumask);
> +}
> +
> +static void eznps_init_core(unsigned int cpu)
> +{
> +	u32 sync_value;
> +	struct nps_host_reg_aux_hw_comply hw_comply;
> +	struct nps_host_reg_aux_lpc lpc;
> +
> +	if (NPS_CPU_TO_THREAD_NUM(cpu) != 0)
> +		return;
> +
> +	hw_comply.value = read_aux_reg(CTOP_AUX_HW_COMPLY);
> +	hw_comply.me  = 1;
> +	hw_comply.le  = 1;
> +	hw_comply.te  = 1;
> +	write_aux_reg(CTOP_AUX_HW_COMPLY, hw_comply.value);
> +
> +	/* Enable MMU clock */
> +	lpc.mep = 1;
> +	write_aux_reg(CTOP_AUX_LPC, lpc.value);
> +
> +	/* Boot CPU only */
> +	if (!cpu) {
> +		/* Write to general purpose register in CRG */
> +		sync_value = ioread32be(REG_GEN_PURP_0);
> +		sync_value |= NPS_CRG_SYNC_BIT;
> +		iowrite32be(sync_value, REG_GEN_PURP_0);
> +	}
> +}
> +
> +/*
> + * Any SMP specific init any CPU does when it comes up.
> + * Here we setup the CPU to enable Inter-Processor-Interrupts
> + * Called for each CPU
> + * -Master      : init_IRQ()
> + * -Other(s)    : start_kernel_secondary()
> + */

This comment is no longer accurate, please get rid of it

> +void eznps_smp_init_cpu(unsigned int cpu)
> +{
> +	unsigned int rc;
> +
> +	rc = smp_ipi_irq_setup(cpu, IPI_IRQ);
> +	if (rc)
> +		panic("IPI IRQ %d reg failed on BOOT cpu\n", IPI_IRQ);

This is not just BOOT cpu ?

> +
> +	eznps_init_core(cpu);
> +	mtm_enable_core(cpu);
> +}
> +
> +/*
> + * Master kick starting another CPU
> + */
> +static void eznps_smp_wakeup_cpu(int cpu, unsigned long pc)
> +{
> +	struct nps_host_reg_mtm_cpu_cfg cpu_cfg;
> +
> +	if (mtm_enable_thread(cpu) == 0)
> +		return;
> +
> +	/* set PC, dmsid, and start CPU */
> +	cpu_cfg.value = pc;
> +	cpu_cfg.dmsid = NPS_DEFAULT_MSID;
> +	cpu_cfg.cs = 1;
> +	iowrite32be(cpu_cfg.value, nps_mtm_reg_addr(cpu, NPS_MTM_CPU_CFG));
> +}
> +
> +static void eznps_ipi_send(int cpu)
> +{
> +	struct global_id gid;
> +	struct {
> +		union {
> +			struct {
> +				u32 num:8, cluster:8, core:8, thread:8;
> +			};
> +			u32 value;
> +		};
> +	} ipi;
> +
> +	gid.value = cpu;
> +	ipi.thread = get_thread(gid);
> +	ipi.core = gid.core;
> +	ipi.cluster = nps_cluster_logic_to_phys(gid.cluster);
> +	ipi.num = IPI_IRQ;
> +
> +	__asm__ __volatile__(
> +	"	mov r3, %0\n"
> +	"	.word %1\n"
> +	:
> +	: "r"(ipi.value), "i"(CTOP_INST_ASRI_0_R3)
> +	: "r3");
> +}
> +
> +struct plat_smp_ops plat_smp_ops = {
> +	.info		= smp_cpuinfo_buf,
> +	.init_early_smp	= eznps_init_cpumasks,
> +	.cpu_kick	= eznps_smp_wakeup_cpu,
> +	.ipi_send	= eznps_ipi_send,

look at mcip.c to add eznps_smp_init_cpu() as smp op callback !

commit 286130ebf196d9643800977d57bdb7cda266b49e
Author: Vineet Gupta <vgupta at synopsys.com>
Date:   Wed Oct 14 14:38:02 2015 +0530

    ARC: smp: Introduce smp hook @init_irq_cpu called for all cores

    Note this is not part of platform owned static machine_desc,
    but more of device owned plat_smp_ops (rather misnamed) which a IPI
    provider or some such typically defines.

    This will help us seperate out the IPI registration from platform
    specific init_cpu_smp() into device specific init_irq_cpu()





More information about the linux-snps-arc mailing list