[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