ARC: [plat-eznps] Add eznps platform

This platform include boards:
	Hardware Emulator (HE)
	Simulator based upon nSIM.

Signed-off-by: Noam Camus <noamc@ezchip.com>
This commit is contained in:
Noam Camus 2012-08-19 11:54:33 +03:00 committed by Vineet Gupta
parent 845033be00
commit 4a66d3fecf
10 changed files with 794 additions and 0 deletions

View File

@ -4379,6 +4379,12 @@ S: Maintained
F: drivers/video/fbdev/exynos/exynos_mipi*
F: include/video/exynos_mipi*
EZchip NPS platform support
M: Noam Camus <noamc@ezchip.com>
S: Supported
F: arch/arc/plat-eznps
F: arch/arc/boot/dts/eznps.dts
F71805F HARDWARE MONITORING DRIVER
M: Jean Delvare <jdelvare@suse.com>
L: linux-hwmon@vger.kernel.org

View File

@ -0,0 +1,35 @@
#
# 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_NPS
select EZNPS_GIC
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.

View File

@ -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

View File

@ -0,0 +1,70 @@
/*******************************************************************************
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 .init.text, "ax",@progbits
.align 1024 ; HW requierment for restart first PC
ENTRY(res_service)
#ifdef CONFIG_EZNPS_MTM_EXT
; There is no work for HW thread id != 0
lr r3, [CTOP_AUX_THREAD_ID]
cmp r3, 0
jne stext
#endif
#ifdef CONFIG_ARC_HAS_DCACHE
; With no cache coherency mechanism D$ need to be used very carefully.
; 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 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
; 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)

View File

@ -0,0 +1,200 @@
/*
* 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
#ifndef CONFIG_ARC_PLAT_EZNPS
#error "Incorrect ctop.h include"
#endif
#include <soc/nps/common.h>
/* core auxiliary registers */
#ifdef __ASSEMBLY__
#define CTOP_AUX_BASE (-0x800)
#else
#define CTOP_AUX_BASE 0xFFFFF800
#endif
#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 CTOP_AUX_EFLAGS (CTOP_AUX_BASE + 0x080)
#define CTOP_AUX_IACK (CTOP_AUX_BASE + 0x088)
#define CTOP_AUX_GPA1 (CTOP_AUX_BASE + 0x08C)
#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 0x3E6F70C3
#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
/* Do not use D$ for address in 2G-3G */
#define HW_COMPLY_KRN_NOT_D_CACHED _BITUL(28)
#define NPS_MSU_EN_CFG 0x80
#define NPS_CRG_BLKID 0x480
#define NPS_CRG_SYNC_BIT _BITUL(0)
#define NPS_GIM_BLKID 0x5C0
/* GIM registers and fields*/
#define NPS_GIM_UART_LINE _BITUL(7)
#define NPS_GIM_DBG_LAN_EAST_TX_DONE_LINE _BITUL(10)
#define NPS_GIM_DBG_LAN_EAST_RX_RDY_LINE _BITUL(11)
#define NPS_GIM_DBG_LAN_WEST_TX_DONE_LINE _BITUL(25)
#define NPS_GIM_DBG_LAN_WEST_RX_RDY_LINE _BITUL(26)
#ifndef __ASSEMBLY__
/* Functional registers definition */
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_msu_en_cfg {
union {
struct {
u32 __reserved1:11,
rtc_en:1, ipc_en:1, gim_1_en:1,
gim_0_en:1, ipi_en:1, buff_e_rls_bmuw:1,
buff_e_alc_bmuw:1, buff_i_rls_bmuw:1, buff_i_alc_bmuw:1,
buff_e_rls_bmue:1, buff_e_alc_bmue:1, buff_i_rls_bmue:1,
buff_i_alc_bmue:1, __reserved2:1, buff_e_pre_en:1,
buff_i_pre_en:1, pmuw_ja_en:1, pmue_ja_en:1,
pmuw_nj_en:1, pmue_nj_en:1, msu_en:1;
};
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;
};
};
/* AUX registers definition */
struct nps_host_reg_aux_udmc {
union {
struct {
u32 dcp:1, cme:1, __reserved:19, 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,
st_cnt:8, __reserved:8,
hs_cnt:8, __reserved1: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;
};
};
/* 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)
#define REG_GIM_P_INT_DST_25 nps_host_reg_non_cl(NPS_GIM_BLKID, 0x149)
#define REG_GIM_P_INT_DST_26 nps_host_reg_non_cl(NPS_GIM_BLKID, 0x14A)
#endif /* __ASSEMBLY__ */
#endif /* _PLAT_EZNPS_CTOP_H */

View File

@ -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 */

View File

@ -0,0 +1,26 @@
/*
* 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 void res_service(void);
#endif /* CONFIG_SMP */
#endif

133
arch/arc/plat-eznps/mtm.c Normal file
View File

@ -0,0 +1,133 @@
/*
* 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 <linux/log2.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));
log_nat = ilog2(nat);
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();
}

View File

@ -0,0 +1,102 @@
/*
* 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 <linux/io.h>
#include <asm/mach_desc.h>
#include <plat/mtm.h>
static void __init eznps_configure_msu(void)
{
int cpu;
struct nps_host_reg_msu_en_cfg msu_en_cfg = {.value = 0};
msu_en_cfg.msu_en = 1;
msu_en_cfg.ipi_en = 1;
msu_en_cfg.gim_0_en = 1;
msu_en_cfg.gim_1_en = 1;
/* enable IPI and GIM messages on all clusters */
for (cpu = 0 ; cpu < eznps_max_cpus; cpu += eznps_cpus_per_cluster)
iowrite32be(msu_en_cfg.value,
nps_host_reg(cpu, NPS_MSU_BLKID, NPS_MSU_EN_CFG));
}
static void __init eznps_configure_gim(void)
{
u32 reg_value;
u32 gim_int_lines;
struct nps_host_reg_gim_p_int_dst gim_p_int_dst = {.value = 0};
gim_int_lines = NPS_GIM_UART_LINE;
gim_int_lines |= NPS_GIM_DBG_LAN_EAST_TX_DONE_LINE;
gim_int_lines |= NPS_GIM_DBG_LAN_EAST_RX_RDY_LINE;
gim_int_lines |= NPS_GIM_DBG_LAN_WEST_TX_DONE_LINE;
gim_int_lines |= NPS_GIM_DBG_LAN_WEST_RX_RDY_LINE;
/*
* IRQ polarity
* low or high level
* negative or positive edge
*/
reg_value = ioread32be(REG_GIM_P_INT_POL_0);
reg_value &= ~gim_int_lines;
iowrite32be(reg_value, REG_GIM_P_INT_POL_0);
/* IRQ type level or edge */
reg_value = ioread32be(REG_GIM_P_INT_SENS_0);
reg_value |= NPS_GIM_DBG_LAN_EAST_TX_DONE_LINE;
reg_value |= NPS_GIM_DBG_LAN_WEST_TX_DONE_LINE;
iowrite32be(reg_value, REG_GIM_P_INT_SENS_0);
/*
* GIM interrupt select type for
* dbg_lan TX and RX interrupts
* should be type 1
* type 0 = IRQ line 6
* type 1 = IRQ line 7
*/
gim_p_int_dst.is = 1;
iowrite32be(gim_p_int_dst.value, REG_GIM_P_INT_DST_10);
iowrite32be(gim_p_int_dst.value, REG_GIM_P_INT_DST_11);
iowrite32be(gim_p_int_dst.value, REG_GIM_P_INT_DST_25);
iowrite32be(gim_p_int_dst.value, REG_GIM_P_INT_DST_26);
/*
* CTOP IRQ lines should be defined
* as blocking in GIM
*/
iowrite32be(gim_int_lines, REG_GIM_P_INT_BLK_0);
/* enable CTOP IRQ lines in GIM */
iowrite32be(gim_int_lines, REG_GIM_P_INT_EN_0);
}
static void __init eznps_early_init(void)
{
eznps_configure_msu();
eznps_configure_gim();
}
static const char *eznps_compat[] __initconst = {
"ezchip,arc-nps",
NULL,
};
MACHINE_START(NPS, "nps")
.dt_compat = eznps_compat,
.init_early = eznps_early_init,
MACHINE_END

155
arch/arc/plat-eznps/smp.c Normal file
View File

@ -0,0 +1,155 @@
/*
* 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 <linux/irqdomain.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
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);
}
}
/*
* Master kick starting another CPU
*/
static void __init 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 = (u32)res_service;
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 = NPS_IPI_IRQ;
__asm__ __volatile__(
" mov r3, %0\n"
" .word %1\n"
:
: "r"(ipi.value), "i"(CTOP_INST_ASRI_0_R3)
: "r3");
}
static void eznps_init_per_cpu(int cpu)
{
smp_ipi_irq_setup(cpu, NPS_IPI_IRQ);
eznps_init_core(cpu);
mtm_enable_core(cpu);
}
static void eznps_ipi_clear(int irq)
{
write_aux_reg(CTOP_AUX_IACK, 1 << irq);
}
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,
.init_per_cpu = eznps_init_per_cpu,
.ipi_clear = eznps_ipi_clear,
};