提交 0efacbba 编写于 作者: L Linus Torvalds

Merge tag 'arc-4.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc

Pull ARC updates from Vineet Gupta:
 "We have a relatively big changeset for ARC for 4.7.

  The highlight is support for EZChip (now Mellanox) NPS-400 network
  processor, a 400-Gb throughput C-programmable packet processor based
  on ARC700 cores from Synopsys. See

        http://www.mellanox.com/related-docs/prod_npu/PB_NPS-400.pdf

  Also present are irqchip and clocksource drivers for NPS as agreed
  with respective maintainers to go via ARC tree due to an soc header
  dependency.  I have the needed ACKs from Jason, Marc, Daniel.  You
  might run into a trivial merge conflict in drivers/irqchip/*

  This EZChip platform support required some deep changes in ARC
  architecture code and also opportunity to cleanup past sins (legacy
  irq domains, missing irq domain lookup, hard coded timer irqs...)

  Summary:

   - Support for EZChip (now Mellanox) NPS-400 Network processor based
     on ARC700

   - NPS interrupt controller and clocksource drivers

   - ARC timers probed off DT

   - ARC iqrchips switching to linear domain (upgrade from legacy
     domains)"

* tag 'arc-4.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc: (37 commits)
  arc: axs103_smp: Fix CPU frequency to 100MHz for dual-core
  arc: axs10x: Add DT bindings for I2S PLL Clock
  ARC: pae: STRICT_MM_TYPECHECKS was broken
  ARC: Add eznps platform to Kconfig and Makefile
  ARC: [plat-eznps] Use dedicated COMMAND_LINE_SIZE
  ARC: [plat-eznps] Use dedicated cpu_relax()
  ARC: [plat-eznps] Use dedicated identity auxiliary register.
  ARC: [plat-eznps] Use dedicated SMP barriers
  ARC: [plat-eznps] Use dedicated atomic/bitops/cmpxchg
  ARC: [plat-eznps] Use dedicated user stack top
  ARC: [plat-eznps] Add eznps platform
  ARC: [plat-eznps] Add eznps board defconfig and dts
  ARC: Mark secondary cpu online only after all HW setup is done
  ARC: rwlock: disable interrupts in !LLSC variant
  ARC: Make vmalloc size configurable
  ARC: clean out UAPI byteorder.h clean off Kconfig symbol
  irqchip: add nps Internal and external irqchips
  clocksource: Add NPS400 timers driver
  soc: Support for EZchip SoC
  Documentation: Add EZchip vendor to binding list
  ...
EZchip NPS Network Processor Platforms Device Tree Bindings
---------------------------------------------------------------------------
Appliance main board with NPS400 ASIC.
Required root node properties:
- compatible = "ezchip,arc-nps";
EZchip NPS Interrupt Controller
Required properties:
- compatible : should be "ezchip,nps400-ic"
- interrupt-controller : Identifies the node as an interrupt controller
- #interrupt-cells : Specifies the number of cells needed to encode an
interrupt source. The value shall be 1.
Example:
intc: interrupt-controller {
compatible = "ezchip,nps400-ic";
interrupt-controller;
#interrupt-cells = <1>;
};
NPS Network Processor
Required properties:
- compatible : should be "ezchip,nps400-timer"
Clocks required for compatible = "ezchip,nps400-timer":
- clocks : Must contain a single entry describing the clock input
Example:
timer {
compatible = "ezchip,nps400-timer";
clocks = <&sysclk>;
};
Synopsys ARC Local Timer with Interrupt Capabilities
- Found on all ARC CPUs (ARC700/ARCHS)
- Can be optionally programmed to interrupt on Limit
- Two idential copies TIMER0 and TIMER1 exist in ARC cores and historically
TIMER0 used as clockevent provider (true for all ARC cores)
TIMER1 used for clocksource (mandatory for ARC700, optional for ARC HS)
Required properties:
- compatible : should be "snps,arc-timer"
- interrupts : single Interrupt going into parent intc
(16 for ARCHS cores, 3 for ARC700 cores)
- clocks : phandle to the source clock
Optional properties:
- interrupt-parent : phandle to parent intc
Example:
timer0 {
compatible = "snps,arc-timer";
interrupts = <3>;
interrupt-parent = <&core_intc>;
clocks = <&core_clk>;
};
timer1 {
compatible = "snps,arc-timer";
clocks = <&core_clk>;
};
Synopsys ARC Free Running 64-bit Global Timer for ARC HS CPUs
- clocksource provider for SMP SoC
Required properties:
- compatible : should be "snps,archs-gfrc"
- clocks : phandle to the source clock
Example:
gfrc {
compatible = "snps,archs-gfrc";
clocks = <&core_clk>;
};
Synopsys ARC Free Running 64-bit Local Timer for ARC HS CPUs
- clocksource provider for UP SoC
Required properties:
- compatible : should be "snps,archs-rtc"
- clocks : phandle to the source clock
Example:
rtc {
compatible = "snps,arc-rtc";
clocks = <&core_clk>;
};
......@@ -88,6 +88,7 @@ eukrea Eukréa Electromatique
everest Everest Semiconductor Co. Ltd.
everspin Everspin Technologies, Inc.
excito Excito
ezchip EZchip Semiconductor
fcs Fairchild Semiconductor
firefly Firefly
focaltech FocalTech Systems Co.,Ltd
......
......@@ -4444,6 +4444,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
......
......@@ -10,8 +10,9 @@ config ARC
def_bool y
select ARCH_SUPPORTS_ATOMIC_RMW if ARC_HAS_LLSC
select BUILDTIME_EXTABLE_SORT
select COMMON_CLK
select CLKSRC_OF
select CLONE_BACKWARDS
select COMMON_CLK
select GENERIC_ATOMIC64
select GENERIC_CLOCKEVENTS
select GENERIC_FIND_FIRST_BIT
......@@ -30,6 +31,7 @@ config ARC
select HAVE_MOD_ARCH_SPECIFIC if ARC_DW2_UNWIND
select HAVE_OPROFILE
select HAVE_PERF_EVENTS
select HANDLE_DOMAIN_IRQ
select IRQ_DOMAIN
select MODULES_USE_ELF_RELA
select NO_BOOTMEM
......@@ -95,6 +97,7 @@ source "arch/arc/plat-sim/Kconfig"
source "arch/arc/plat-tb10x/Kconfig"
source "arch/arc/plat-axs10x/Kconfig"
#New platform adds here
source "arch/arc/plat-eznps/Kconfig"
endmenu
......@@ -490,6 +493,17 @@ config ARCH_DMA_ADDR_T_64BIT
config ARC_PLAT_NEEDS_PHYS_TO_DMA
bool
config ARC_KVADDR_SIZE
int "Kernel Virtaul Address Space size (MB)"
range 0 512
default "256"
help
The kernel address space is carved out of 256MB of translated address
space for catering to vmalloc, modules, pkmap, fixmap. This however may
not suffice vmalloc requirements of a 4K CPU EZChip system. So allow
this to be stretched to 512 MB (by extending into the reserved
kernel-user gutter)
config ARC_CURR_IN_REG
bool "Dedicate Register r25 for current_task pointer"
default y
......
......@@ -115,6 +115,11 @@ core-y += arch/arc/boot/dts/
core-$(CONFIG_ARC_PLAT_SIM) += arch/arc/plat-sim/
core-$(CONFIG_ARC_PLAT_TB10X) += arch/arc/plat-tb10x/
core-$(CONFIG_ARC_PLAT_AXS10X) += arch/arc/plat-axs10x/
core-$(CONFIG_ARC_PLAT_EZNPS) += arch/arc/plat-eznps/
ifdef CONFIG_ARC_PLAT_EZNPS
KBUILD_CPPFLAGS += -I$(srctree)/arch/arc/plat-eznps/include
endif
drivers-$(CONFIG_OPROFILE) += arch/arc/oprofile/
......
......@@ -35,6 +35,20 @@
};
};
/* TIMER0 with interrupt for clockevent */
timer0 {
compatible = "snps,arc-timer";
interrupts = <3>;
interrupt-parent = <&intc>;
clocks = <&cpu_clk>;
};
/* TIMER1 for free running clocksource */
timer1 {
compatible = "snps,arc-timer";
clocks = <&cpu_clk>;
};
soc100 {
#address-cells = <1>;
#size-cells = <1>;
......
......@@ -11,6 +11,8 @@
* Note that this file only supports the 770D CPU
*/
/include/ "skeleton.dtsi"
/ {
compatible = "snps,arc";
clock-frequency = <750000000>; /* 750 MHZ */
......@@ -24,7 +26,13 @@
ranges = <0x00000000 0xf0000000 0x10000000>;
cpu_intc: arc700-intc@cpu {
core_clk: core_clk {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <750000000>;
};
core_intc: arc700-intc@cpu {
compatible = "snps,arc700-intc";
interrupt-controller;
#interrupt-cells = <1>;
......@@ -48,7 +56,7 @@
reg = <0>;
interrupt-controller;
#interrupt-cells = <2>;
interrupt-parent = <&cpu_intc>;
interrupt-parent = <&core_intc>;
interrupts = <15>;
};
};
......@@ -86,7 +94,7 @@
compatible = "snps,dw-apb-ictl";
reg = < 0xe0012000 0x200 >;
interrupt-controller;
interrupt-parent = <&cpu_intc>;
interrupt-parent = <&core_intc>;
interrupts = < 7 >;
};
......
......@@ -10,6 +10,8 @@
* Device tree for AXC003 CPU card: HS38x UP configuration
*/
/include/ "skeleton_hs.dtsi"
/ {
compatible = "snps,arc";
clock-frequency = <90000000>;
......@@ -23,7 +25,13 @@
ranges = <0x00000000 0xf0000000 0x10000000>;
cpu_intc: archs-intc@cpu {
core_clk: core_clk {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <90000000>;
};
core_intc: archs-intc@cpu {
compatible = "snps,archs-intc";
interrupt-controller;
#interrupt-cells = <1>;
......@@ -47,7 +55,7 @@
reg = <0>;
interrupt-controller;
#interrupt-cells = <2>;
interrupt-parent = <&cpu_intc>;
interrupt-parent = <&core_intc>;
interrupts = <25>;
};
};
......@@ -66,7 +74,7 @@
arcpct0: pct {
compatible = "snps,archs-pct";
#interrupt-cells = <1>;
interrupt-parent = <&cpu_intc>;
interrupt-parent = <&core_intc>;
interrupts = <20>;
};
};
......@@ -89,7 +97,7 @@
compatible = "snps,dw-apb-ictl";
reg = < 0xe0012000 0x200 >;
interrupt-controller;
interrupt-parent = <&cpu_intc>;
interrupt-parent = <&core_intc>;
interrupts = < 24 >;
};
......
......@@ -10,6 +10,8 @@
* Device tree for AXC003 CPU card: HS38x2 (Dual Core) with IDU intc
*/
/include/ "skeleton_hs_idu.dtsi"
/ {
compatible = "snps,arc";
clock-frequency = <90000000>;
......@@ -23,7 +25,13 @@
ranges = <0x00000000 0xf0000000 0x10000000>;
cpu_intc: archs-intc@cpu {
core_clk: core_clk {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <100000000>;
};
core_intc: archs-intc@cpu {
compatible = "snps,archs-intc";
interrupt-controller;
#interrupt-cells = <1>;
......@@ -32,7 +40,7 @@
idu_intc: idu-interrupt-controller {
compatible = "snps,archs-idu-intc";
interrupt-controller;
interrupt-parent = <&cpu_intc>;
interrupt-parent = <&core_intc>;
/*
* <hwirq distribution>
......@@ -89,7 +97,7 @@
arcpct0: pct {
compatible = "snps,archs-pct";
#interrupt-cells = <1>;
interrupt-parent = <&cpu_intc>;
interrupt-parent = <&core_intc>;
interrupts = <20>;
};
};
......
......@@ -16,7 +16,20 @@
ranges = <0x00000000 0xe0000000 0x10000000>;
interrupt-parent = <&mb_intc>;
i2sclk: i2sclk@100a0 {
compatible = "snps,axs10x-i2s-pll-clock";
reg = <0x100a0 0x10>;
clocks = <&i2spll_clk>;
#clock-cells = <0>;
};
clocks {
i2spll_clk: i2spll_clk {
compatible = "fixed-clock";
clock-frequency = <27000000>;
#clock-cells = <0>;
};
i2cclk: i2cclk {
compatible = "fixed-clock";
clock-frequency = <50000000>;
......
/*
* 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".
*/
/dts-v1/;
/ {
compatible = "ezchip,arc-nps";
clock-frequency = <83333333>; /* 83.333333 MHZ */
#address-cells = <1>;
#size-cells = <1>;
interrupt-parent = <&intc>;
present-cpus = "0-1,16-17";
possible-cpus = "0-4095";
aliases {
ethernet0 = &gmac0;
};
chosen {
bootargs = "earlycon=uart8250,mmio32be,0xf7209000,115200n8 console=ttyS0,115200n8";
};
memory {
device_type = "memory";
reg = <0x80000000 0x20000000>; /* 512M */
};
clocks {
sysclk: sysclk {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <83333333>;
};
};
soc {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
/* child and parent address space 1:1 mapped */
ranges;
intc: interrupt-controller {
compatible = "ezchip,nps400-ic";
interrupt-controller;
#interrupt-cells = <1>;
};
timer0: timer_clkevt {
compatible = "snps,arc-timer";
interrupts = <3>;
clocks = <&sysclk>;
};
timer1: timer_clksrc {
compatible = "ezchip,nps400-timer";
clocks = <&sysclk>;
clock-names="sysclk";
};
uart@f7209000 {
compatible = "snps,dw-apb-uart";
device_type = "serial";
reg = <0xf7209000 0x100>;
interrupts = <6>;
clocks = <&sysclk>;
clock-names="baudclk";
baud = <115200>;
reg-shift = <2>;
reg-io-width = <4>;
native-endian;
};
gmac0: ethernet@f7470000 {
compatible = "ezchip,nps-mgt-enet";
reg = <0xf7470000 0x1940>;
interrupts = <7>;
/* Filled in by U-Boot */
mac-address = [ 00 C0 00 F0 04 03 ];
};
};
};
......@@ -14,7 +14,7 @@
clock-frequency = <80000000>; /* 80 MHZ */
#address-cells = <1>;
#size-cells = <1>;
interrupt-parent = <&intc>;
interrupt-parent = <&core_intc>;
chosen {
bootargs = "earlycon=arc_uart,mmio32,0xc0fc1000,115200n8 console=ttyARC0,115200n8";
......@@ -32,7 +32,13 @@
/* child and parent address space 1:1 mapped */
ranges;
intc: interrupt-controller {
core_clk: core_clk {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <80000000>;
};
core_intc: interrupt-controller {
compatible = "snps,arc700-intc";
interrupt-controller;
#interrupt-cells = <1>;
......
......@@ -7,7 +7,7 @@
*/
/dts-v1/;
/include/ "skeleton.dtsi"
/include/ "skeleton_hs.dtsi"
/ {
compatible = "snps,nsim_hs";
......@@ -39,6 +39,12 @@
bus addr, parent bus addr, size */
ranges = <0x80000000 0x0 0x80000000 0x80000000>;
core_clk: core_clk {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <80000000>;
};
core_intc: core-interrupt-controller {
compatible = "snps,archs-intc";
interrupt-controller;
......
......@@ -7,7 +7,7 @@
*/
/dts-v1/;
/include/ "skeleton.dtsi"
/include/ "skeleton_hs_idu.dtsi"
/ {
compatible = "snps,nsim_hs";
......@@ -29,6 +29,12 @@
/* child and parent address space 1:1 mapped */
ranges;
core_clk: core_clk {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <80000000>;
};
core_intc: core-interrupt-controller {
compatible = "snps,archs-intc";
interrupt-controller;
......
......@@ -14,7 +14,7 @@
clock-frequency = <20000000>; /* 20 MHZ */
#address-cells = <1>;
#size-cells = <1>;
interrupt-parent = <&intc>;
interrupt-parent = <&core_intc>;
chosen {
/* this is for console on PGU */
......@@ -35,7 +35,13 @@
/* child and parent address space 1:1 mapped */
ranges;
intc: interrupt-controller {
core_clk: core_clk {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <20000000>;
};
core_intc: interrupt-controller {
compatible = "snps,arc700-intc";
interrupt-controller;
#interrupt-cells = <1>;
......
......@@ -7,7 +7,7 @@
*/
/dts-v1/;
/include/ "skeleton.dtsi"
/include/ "skeleton_hs.dtsi"
/ {
compatible = "snps,nsimosci_hs";
......@@ -35,6 +35,12 @@
/* child and parent address space 1:1 mapped */
ranges;
core_clk: core_clk {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <20000000>;
};
core_intc: core-interrupt-controller {
compatible = "snps,archs-intc";
interrupt-controller;
......
......@@ -7,7 +7,7 @@
*/
/dts-v1/;
/include/ "skeleton.dtsi"
/include/ "skeleton_hs_idu.dtsi"
/ {
compatible = "snps,nsimosci_hs";
......@@ -33,6 +33,12 @@
/* child and parent address space 1:1 mapped */
ranges;
core_clk: core_clk {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <5000000>;
};
core_intc: core-interrupt-controller {
compatible = "snps,archs-intc";
interrupt-controller;
......
......@@ -30,6 +30,20 @@
};
};
/* TIMER0 with interrupt for clockevent */
timer0 {
compatible = "snps,arc-timer";
interrupts = <3>;
interrupt-parent = <&core_intc>;
clocks = <&core_clk>;
};
/* TIMER1 for free running clocksource */
timer1 {
compatible = "snps,arc-timer";
clocks = <&core_clk>;
};
memory {
device_type = "memory";
reg = <0x80000000 0x10000000>; /* 256M */
......
/*
* Copyright (C) 2016 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.
*/
/ {
compatible = "snps,arc";
clock-frequency = <80000000>; /* 80 MHZ */
#address-cells = <1>;
#size-cells = <1>;
chosen { };
aliases { };
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
device_type = "cpu";
compatible = "snps,archs38";
reg = <0>;
};
};
/* TIMER0 with interrupt for clockevent */
timer0 {
compatible = "snps,arc-timer";
interrupts = <16>;
interrupt-parent = <&core_intc>;
clocks = <&core_clk>;
};
/* 64-bit Local RTC: preferred clocksource for UP */
rtc {
compatible = "snps,archs-timer-rtc";
clocks = <&core_clk>;
};
/* TIMER1 for free running clocksource: Fallback if rtc not found */
timer1 {
compatible = "snps,arc-timer";
clocks = <&core_clk>;
};
memory {
device_type = "memory";
reg = <0x80000000 0x10000000>; /* 256M */
};
};
/*
* Copyright (C) 2016 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.
*/
/ {
compatible = "snps,arc";
clock-frequency = <80000000>; /* 80 MHZ */
#address-cells = <1>;
#size-cells = <1>;
chosen { };
aliases { };
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
device_type = "cpu";
compatible = "snps,archs38xN";
reg = <0>;
};
};
/* TIMER0 with interrupt for clockevent */
timer0 {
compatible = "snps,arc-timer";
interrupts = <16>;
interrupt-parent = <&core_intc>;
clocks = <&core_clk>;
};
/* 64-bit Global Free Running Counter */
gfrc {
compatible = "snps,archs-timer-gfrc";
clocks = <&core_clk>;
};
memory {
device_type = "memory";
reg = <0x80000000 0x10000000>; /* 256M */
};
};
......@@ -10,6 +10,8 @@
* Device tree for AXC003 CPU card: HS38x UP configuration (VDK version)
*/
/include/ "skeleton_hs.dtsi"
/ {
compatible = "snps,arc";
clock-frequency = <50000000>;
......@@ -23,7 +25,13 @@
ranges = <0x00000000 0xf0000000 0x10000000>;
cpu_intc: archs-intc@cpu {
core_clk: core_clk {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <50000000>;
};
core_intc: archs-intc@cpu {
compatible = "snps,archs-intc";
interrupt-controller;
#interrupt-cells = <1>;
......@@ -33,7 +41,7 @@
compatible = "snps,dw-apb-uart";
reg = <0x5000 0x100>;
clock-frequency = <2403200>;
interrupt-parent = <&cpu_intc>;
interrupt-parent = <&core_intc>;
interrupts = <19>;
baud = <115200>;
reg-shift = <2>;
......@@ -47,7 +55,7 @@
compatible = "snps,dw-apb-ictl";
reg = < 0xe0012000 0x200 >;
interrupt-controller;
interrupt-parent = <&cpu_intc>;
interrupt-parent = <&core_intc>;
interrupts = < 18 >;
};
......
......@@ -11,6 +11,8 @@
* HS38x2 (Dual Core) with IDU intc (VDK version)
*/
/include/ "skeleton_hs_idu.dtsi"
/ {
compatible = "snps,arc";
clock-frequency = <50000000>;
......@@ -24,7 +26,13 @@
ranges = <0x00000000 0xf0000000 0x10000000>;
cpu_intc: archs-intc@cpu {
core_clk: core_clk {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <50000000>;
};
core_intc: archs-intc@cpu {
compatible = "snps,archs-intc";
interrupt-controller;
#interrupt-cells = <1>;
......@@ -33,7 +41,7 @@
idu_intc: idu-interrupt-controller {
compatible = "snps,archs-idu-intc";
interrupt-controller;
interrupt-parent = <&cpu_intc>;
interrupt-parent = <&core_intc>;
/*
* <hwirq distribution>
......
# CONFIG_LOCALVERSION_AUTO is not set
# CONFIG_SWAP is not set
CONFIG_SYSVIPC=y
CONFIG_NO_HZ_IDLE=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_SYSCTL_SYSCALL=y
# CONFIG_EPOLL is not set
# CONFIG_SIGNALFD is not set
# CONFIG_TIMERFD is not set
# CONFIG_EVENTFD is not set
# CONFIG_AIO is not set
CONFIG_EMBEDDED=y
CONFIG_PERF_EVENTS=y
# CONFIG_COMPAT_BRK is not set
CONFIG_KPROBES=y
CONFIG_MODULES=y
CONFIG_MODULE_FORCE_LOAD=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_IOSCHED_DEADLINE is not set
# CONFIG_IOSCHED_CFQ is not set
CONFIG_ARC_PLAT_EZNPS=y
CONFIG_SMP=y
CONFIG_NR_CPUS=4096
CONFIG_ARC_CACHE_LINE_SHIFT=5
# CONFIG_ARC_CACHE_PAGES is not set
# CONFIG_ARC_HAS_LLSC is not set
CONFIG_ARC_KVADDR_SIZE=402
CONFIG_ARC_EMUL_UNALIGNED=y
CONFIG_ARC_UBOOT_SUPPORT=y
CONFIG_PREEMPT=y
CONFIG_NET=y
CONFIG_UNIX=y
CONFIG_INET=y
CONFIG_IP_PNP=y
# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
# CONFIG_INET_XFRM_MODE_TUNNEL is not set
# CONFIG_INET_XFRM_MODE_BEET is not set
# CONFIG_INET_LRO is not set
# CONFIG_INET_DIAG is not set
# CONFIG_IPV6 is not set
# CONFIG_WIRELESS is not set
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
# CONFIG_PREVENT_FIRMWARE_BUILD is not set
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=1
CONFIG_BLK_DEV_RAM_SIZE=2048
CONFIG_NETDEVICES=y
CONFIG_NETCONSOLE=y
# CONFIG_NET_VENDOR_BROADCOM is not set
# CONFIG_NET_VENDOR_MICREL is not set
# CONFIG_NET_VENDOR_STMICRO is not set
# CONFIG_WLAN is not set
# CONFIG_INPUT_MOUSEDEV is not set
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_SERIO is not set
# CONFIG_LEGACY_PTYS is not set
# CONFIG_DEVKMEM is not set
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_NR_UARTS=1
CONFIG_SERIAL_8250_RUNTIME_UARTS=1
CONFIG_SERIAL_8250_DW=y
CONFIG_SERIAL_OF_PLATFORM=y
# CONFIG_HW_RANDOM is not set
# CONFIG_HWMON is not set
# CONFIG_USB_SUPPORT is not set
# CONFIG_DNOTIFY is not set
CONFIG_PROC_KCORE=y
CONFIG_TMPFS=y
# CONFIG_MISC_FILESYSTEMS is not set
CONFIG_NFS_FS=y
CONFIG_ROOT_NFS=y
CONFIG_DEBUG_INFO=y
# CONFIG_ENABLE_WARN_DEPRECATED is not set
# CONFIG_ENABLE_MUST_CHECK is not set
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_MEMORY_INIT=y
CONFIG_ENABLE_DEFAULT_TRACERS=y
......@@ -17,6 +17,8 @@
#include <asm/barrier.h>
#include <asm/smp.h>
#ifndef CONFIG_ARC_PLAT_EZNPS
#define atomic_read(v) READ_ONCE((v)->counter)
#ifdef CONFIG_ARC_HAS_LLSC
......@@ -180,13 +182,88 @@ ATOMIC_OP(andnot, &= ~, bic)
ATOMIC_OP(or, |=, or)
ATOMIC_OP(xor, ^=, xor)
#undef ATOMIC_OPS
#undef ATOMIC_OP_RETURN
#undef ATOMIC_OP
#undef SCOND_FAIL_RETRY_VAR_DEF
#undef SCOND_FAIL_RETRY_ASM
#undef SCOND_FAIL_RETRY_VARS
#else /* CONFIG_ARC_PLAT_EZNPS */
static inline int atomic_read(const atomic_t *v)
{
int temp;
__asm__ __volatile__(
" ld.di %0, [%1]"
: "=r"(temp)
: "r"(&v->counter)
: "memory");
return temp;
}
static inline void atomic_set(atomic_t *v, int i)
{
__asm__ __volatile__(
" st.di %0,[%1]"
:
: "r"(i), "r"(&v->counter)
: "memory");
}
#define ATOMIC_OP(op, c_op, asm_op) \
static inline void atomic_##op(int i, atomic_t *v) \
{ \
__asm__ __volatile__( \
" mov r2, %0\n" \
" mov r3, %1\n" \
" .word %2\n" \
: \
: "r"(i), "r"(&v->counter), "i"(asm_op) \
: "r2", "r3", "memory"); \
} \
#define ATOMIC_OP_RETURN(op, c_op, asm_op) \
static inline int atomic_##op##_return(int i, atomic_t *v) \
{ \
unsigned int temp = i; \
\
/* Explicit full memory barrier needed before/after */ \
smp_mb(); \
\
__asm__ __volatile__( \
" mov r2, %0\n" \
" mov r3, %1\n" \
" .word %2\n" \
" mov %0, r2" \
: "+r"(temp) \
: "r"(&v->counter), "i"(asm_op) \
: "r2", "r3", "memory"); \
\
smp_mb(); \
\
temp c_op i; \
\
return temp; \
}
#define ATOMIC_OPS(op, c_op, asm_op) \
ATOMIC_OP(op, c_op, asm_op) \
ATOMIC_OP_RETURN(op, c_op, asm_op)
ATOMIC_OPS(add, +=, CTOP_INST_AADD_DI_R2_R2_R3)
#define atomic_sub(i, v) atomic_add(-(i), (v))
#define atomic_sub_return(i, v) atomic_add_return(-(i), (v))
ATOMIC_OP(and, &=, CTOP_INST_AAND_DI_R2_R2_R3)
#define atomic_andnot(mask, v) atomic_and(~(mask), (v))
ATOMIC_OP(or, |=, CTOP_INST_AOR_DI_R2_R2_R3)
ATOMIC_OP(xor, ^=, CTOP_INST_AXOR_DI_R2_R2_R3)
#endif /* CONFIG_ARC_PLAT_EZNPS */
#undef ATOMIC_OPS
#undef ATOMIC_OP_RETURN
#undef ATOMIC_OP
/**
* __atomic_add_unless - add unless the number is a given value
* @v: pointer of type atomic_t
......
......@@ -30,9 +30,7 @@
#define rmb() asm volatile("dmb 1\n" : : : "memory")
#define wmb() asm volatile("dmb 2\n" : : : "memory")
#endif
#ifdef CONFIG_ISA_ARCOMPACT
#elif !defined(CONFIG_ARC_PLAT_EZNPS) /* CONFIG_ISA_ARCOMPACT */
/*
* ARCompact based cores (ARC700) only have SYNC instruction which is super
......@@ -41,6 +39,14 @@
*/
#define mb() asm volatile("sync\n" : : : "memory")
#else /* CONFIG_ARC_PLAT_EZNPS */
#include <plat/ctop.h>
#define mb() asm volatile (".word %0" : : "i"(CTOP_INST_SCHD_RW) : "memory")
#define rmb() asm volatile (".word %0" : : "i"(CTOP_INST_SCHD_RD) : "memory")
#endif
#include <asm-generic/barrier.h>
......
......@@ -22,7 +22,7 @@
#include <asm/smp.h>
#endif
#if defined(CONFIG_ARC_HAS_LLSC)
#ifdef CONFIG_ARC_HAS_LLSC
/*
* Hardware assisted Atomic-R-M-W
......@@ -88,7 +88,7 @@ static inline int test_and_##op##_bit(unsigned long nr, volatile unsigned long *
return (old & (1 << nr)) != 0; \
}
#else /* !CONFIG_ARC_HAS_LLSC */
#elif !defined(CONFIG_ARC_PLAT_EZNPS)
/*
* Non hardware assisted Atomic-R-M-W
......@@ -139,7 +139,55 @@ static inline int test_and_##op##_bit(unsigned long nr, volatile unsigned long *
return (old & (1UL << (nr & 0x1f))) != 0; \
}
#endif /* CONFIG_ARC_HAS_LLSC */
#else /* CONFIG_ARC_PLAT_EZNPS */
#define BIT_OP(op, c_op, asm_op) \
static inline void op##_bit(unsigned long nr, volatile unsigned long *m)\
{ \
m += nr >> 5; \
\
nr = (1UL << (nr & 0x1f)); \
if (asm_op == CTOP_INST_AAND_DI_R2_R2_R3) \
nr = ~nr; \
\
__asm__ __volatile__( \
" mov r2, %0\n" \
" mov r3, %1\n" \
" .word %2\n" \
: \
: "r"(nr), "r"(m), "i"(asm_op) \
: "r2", "r3", "memory"); \
}
#define TEST_N_BIT_OP(op, c_op, asm_op) \
static inline int test_and_##op##_bit(unsigned long nr, volatile unsigned long *m)\
{ \
unsigned long old; \
\
m += nr >> 5; \
\
nr = old = (1UL << (nr & 0x1f)); \
if (asm_op == CTOP_INST_AAND_DI_R2_R2_R3) \
old = ~old; \
\
/* Explicit full memory barrier needed before/after */ \
smp_mb(); \
\
__asm__ __volatile__( \
" mov r2, %0\n" \
" mov r3, %1\n" \
" .word %2\n" \
" mov %0, r2" \
: "+r"(old) \
: "r"(m), "i"(asm_op) \
: "r2", "r3", "memory"); \
\
smp_mb(); \
\
return (old & nr) != 0; \
}
#endif /* CONFIG_ARC_PLAT_EZNPS */
/***************************************
* Non atomic variants
......@@ -181,9 +229,15 @@ static inline int __test_and_##op##_bit(unsigned long nr, volatile unsigned long
/* __test_and_set_bit(), __test_and_clear_bit(), __test_and_change_bit() */\
__TEST_N_BIT_OP(op, c_op, asm_op)
#ifndef CONFIG_ARC_PLAT_EZNPS
BIT_OPS(set, |, bset)
BIT_OPS(clear, & ~, bclr)
BIT_OPS(change, ^, bxor)
#else
BIT_OPS(set, |, CTOP_INST_AOR_DI_R2_R2_R3)
BIT_OPS(clear, & ~, CTOP_INST_AAND_DI_R2_R2_R3)
BIT_OPS(change, ^, CTOP_INST_AXOR_DI_R2_R2_R3)
#endif
/*
* This routine doesn't need to be atomic.
......
/*
* Copyright (C) 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.
*/
#ifndef _ASM_ARC_CLK_H
#define _ASM_ARC_CLK_H
/* Although we can't really hide core_freq, the accessor is still better way */
extern unsigned long core_freq;
static inline unsigned long arc_get_core_freq(void)
{
return core_freq;
}
extern int arc_set_core_freq(unsigned long);
#endif
......@@ -44,7 +44,7 @@ __cmpxchg(volatile void *ptr, unsigned long expected, unsigned long new)
return prev;
}
#else
#elif !defined(CONFIG_ARC_PLAT_EZNPS)
static inline unsigned long
__cmpxchg(volatile void *ptr, unsigned long expected, unsigned long new)
......@@ -64,23 +64,48 @@ __cmpxchg(volatile void *ptr, unsigned long expected, unsigned long new)
return prev;
}
#else /* CONFIG_ARC_PLAT_EZNPS */
static inline unsigned long
__cmpxchg(volatile void *ptr, unsigned long expected, unsigned long new)
{
/*
* Explicit full memory barrier needed before/after
*/
smp_mb();
write_aux_reg(CTOP_AUX_GPA1, expected);
__asm__ __volatile__(
" mov r2, %0\n"
" mov r3, %1\n"
" .word %2\n"
" mov %0, r2"
: "+r"(new)
: "r"(ptr), "i"(CTOP_INST_EXC_DI_R2_R2_R3)
: "r2", "r3", "memory");
smp_mb();
return new;
}
#endif /* CONFIG_ARC_HAS_LLSC */
#define cmpxchg(ptr, o, n) ((typeof(*(ptr)))__cmpxchg((ptr), \
(unsigned long)(o), (unsigned long)(n)))
/*
* Since not supported natively, ARC cmpxchg() uses atomic_ops_lock (UP/SMP)
* just to gaurantee semantics.
* atomic_cmpxchg() needs to use the same locks as it's other atomic siblings
* which also happens to be atomic_ops_lock.
*
* Thus despite semantically being different, implementation of atomic_cmpxchg()
* is same as cmpxchg().
* atomic_cmpxchg is same as cmpxchg
* LLSC: only different in data-type, semantics are exactly same
* !LLSC: cmpxchg() has to use an external lock atomic_ops_lock to guarantee
* semantics, and this lock also happens to be used by atomic_*()
*/
#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
#ifndef CONFIG_ARC_PLAT_EZNPS
/*
* xchg (reg with memory) based on "Native atomic" EX insn
*/
......@@ -143,6 +168,41 @@ static inline unsigned long __xchg(unsigned long val, volatile void *ptr,
#endif
#else /* CONFIG_ARC_PLAT_EZNPS */
static inline unsigned long __xchg(unsigned long val, volatile void *ptr,
int size)
{
extern unsigned long __xchg_bad_pointer(void);
switch (size) {
case 4:
/*
* Explicit full memory barrier needed before/after
*/
smp_mb();
__asm__ __volatile__(
" mov r2, %0\n"
" mov r3, %1\n"
" .word %2\n"
" mov %0, r2\n"
: "+r"(val)
: "r"(ptr), "i"(CTOP_INST_XEX_DI_R2_R2_R3)
: "r2", "r3", "memory");
smp_mb();
return val;
}
return __xchg_bad_pointer();
}
#define xchg(ptr, with) ((typeof(*(ptr)))__xchg((unsigned long)(with), (ptr), \
sizeof(*(ptr))))
#endif /* CONFIG_ARC_PLAT_EZNPS */
/*
* "atomic" variant of xchg()
* REQ: It needs to follow the same serialization rules as other atomic_xxx()
......
......@@ -36,6 +36,10 @@
#include <asm/irqflags-compact.h>
#include <asm/thread_info.h> /* For THREAD_SIZE */
#ifdef CONFIG_ARC_PLAT_EZNPS
#include <plat/ctop.h>
#endif
/*--------------------------------------------------------------
* Switch to Kernel Mode stack if SP points to User Mode stack
*
......@@ -296,11 +300,13 @@
bic \reg, sp, (THREAD_SIZE - 1)
.endm
#ifndef CONFIG_ARC_PLAT_EZNPS
/* Get CPU-ID of this core */
.macro GET_CPU_ID reg
lr \reg, [identity]
lsr \reg, \reg, 8
bmsk \reg, \reg, 7
.endm
#endif
#endif /* __ASM_ARC_ENTRY_COMPACT_H */
......@@ -13,21 +13,14 @@
#define NR_IRQS 128 /* allow some CPU external IRQ handling */
/* Platform Independent IRQs */
#ifdef CONFIG_ISA_ARCOMPACT
#define TIMER0_IRQ 3
#define TIMER1_IRQ 4
#else
#define TIMER0_IRQ 16
#define TIMER1_IRQ 17
#ifdef CONFIG_ISA_ARCV2
#define IPI_IRQ 19
#define SOFTIRQ_IRQ 21
#endif
#include <linux/interrupt.h>
#include <asm-generic/irq.h>
extern void arc_init_IRQ(void);
void arc_local_timer_setup(void);
void arc_request_percpu_irq(int irq, int cpu,
irqreturn_t (*isr)(int irq, void *dev),
const char *irq_nm, void *percpu_dev);
#endif
......@@ -31,7 +31,11 @@ void clear_user_page(void *to, unsigned long u_vaddr, struct page *page);
* These are used to make use of C type-checking..
*/
typedef struct {
#ifdef CONFIG_ARC_HAS_PAE40
unsigned long long pte;
#else
unsigned long pte;
#endif
} pte_t;
typedef struct {
unsigned long pgd;
......
......@@ -217,7 +217,7 @@
#define BITS_FOR_PTE (PGDIR_SHIFT - PAGE_SHIFT)
#define BITS_FOR_PGD (32 - PGDIR_SHIFT)
#define PGDIR_SIZE (1UL << PGDIR_SHIFT) /* vaddr span, not PDG sz */
#define PGDIR_SIZE _BITUL(PGDIR_SHIFT) /* vaddr span, not PDG sz */
#define PGDIR_MASK (~(PGDIR_SIZE-1))
#define PTRS_PER_PTE _BITUL(BITS_FOR_PTE)
......
......@@ -57,10 +57,20 @@ struct task_struct;
* A lot of busy-wait loops in SMP are based off of non-volatile data otherwise
* get optimised away by gcc
*/
#define cpu_relax() __asm__ __volatile__ ("" : : : "memory")
#ifndef CONFIG_EZNPS_MTM_EXT
#define cpu_relax() barrier()
#define cpu_relax_lowlatency() cpu_relax()
#else
#define cpu_relax() \
__asm__ __volatile__ (".word %0" : : "i"(CTOP_INST_SCHD_RW) : "memory")
#define cpu_relax_lowlatency() barrier()
#endif
#define copy_segments(tsk, mm) do { } while (0)
#define release_segments(mm) do { } while (0)
......@@ -97,7 +107,7 @@ extern unsigned int get_wchan(struct task_struct *p);
#endif /* !__ASSEMBLY__ */
/*
* System Memory Map on ARC
* Default System Memory Map on ARC
*
* ---------------------------- (lower 2G, Translated) -------------------------
* 0x0000_0000 0x5FFF_FFFF (user vaddr: TASK_SIZE)
......@@ -109,20 +119,37 @@ extern unsigned int get_wchan(struct task_struct *p);
* 0xC000_0000 0xFFFF_FFFF (peripheral uncached space)
* -----------------------------------------------------------------------------
*/
#define VMALLOC_START 0x70000000
/*
* 1 PGDIR_SIZE each for fixmap/pkmap, 2 PGDIR_SIZE gutter
* See asm/highmem.h for details
*/
#define VMALLOC_SIZE (PAGE_OFFSET - VMALLOC_START - PGDIR_SIZE * 4)
#define VMALLOC_END (VMALLOC_START + VMALLOC_SIZE)
#define TASK_SIZE 0x60000000
#define USER_KERNEL_GUTTER 0x10000000
#define VMALLOC_START (PAGE_OFFSET - (CONFIG_ARC_KVADDR_SIZE << 20))
#define TASK_SIZE (VMALLOC_START - USER_KERNEL_GUTTER)
/* 1 PGDIR_SIZE each for fixmap/pkmap, 2 PGDIR_SIZE gutter (see asm/highmem.h) */
#define VMALLOC_SIZE ((CONFIG_ARC_KVADDR_SIZE << 20) - PGDIR_SIZE * 4)
#define VMALLOC_END (VMALLOC_START + VMALLOC_SIZE)
#define USER_KERNEL_GUTTER (VMALLOC_START - TASK_SIZE)
#ifdef CONFIG_ARC_PLAT_EZNPS
/* NPS architecture defines special window of 129M in user address space for
* special memory areas, when accessing this window the MMU do not use TLB.
* Instead MMU direct the access to:
* 0x57f00000:0x57ffffff -- 1M of closely coupled memory (aka CMEM)
* 0x58000000:0x5fffffff -- 16 huge pages, 8M each, with fixed map (aka FMTs)
*
* CMEM - is the fastest memory we got and its size is 16K.
* FMT - is used to map either to internal/external memory.
* Internal memory is the second fast memory and its size is 16M
* External memory is the biggest memory (16G) and also the slowest.
*
* STACK_TOP need to be PMD align (21bit) that is why we supply 0x57e00000.
*/
#define STACK_TOP 0x57e00000
#else
#define STACK_TOP TASK_SIZE
#endif
#define STACK_TOP_MAX STACK_TOP
/* This decides where the kernel will search for a free chunk of vm
......
......@@ -12,7 +12,11 @@
#include <linux/types.h>
#include <uapi/asm/setup.h>
#ifdef CONFIG_ARC_PLAT_EZNPS
#define COMMAND_LINE_SIZE 2048
#else
#define COMMAND_LINE_SIZE 256
#endif
/*
* Data structure to map a ID to string
......
......@@ -610,7 +610,9 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
static inline int arch_read_trylock(arch_rwlock_t *rw)
{
int ret = 0;
unsigned long flags;
local_irq_save(flags);
arch_spin_lock(&(rw->lock_mutex));
/*
......@@ -623,6 +625,7 @@ static inline int arch_read_trylock(arch_rwlock_t *rw)
}
arch_spin_unlock(&(rw->lock_mutex));
local_irq_restore(flags);
smp_mb();
return ret;
......@@ -632,7 +635,9 @@ static inline int arch_read_trylock(arch_rwlock_t *rw)
static inline int arch_write_trylock(arch_rwlock_t *rw)
{
int ret = 0;
unsigned long flags;
local_irq_save(flags);
arch_spin_lock(&(rw->lock_mutex));
/*
......@@ -646,6 +651,7 @@ static inline int arch_write_trylock(arch_rwlock_t *rw)
ret = 1;
}
arch_spin_unlock(&(rw->lock_mutex));
local_irq_restore(flags);
return ret;
}
......@@ -664,16 +670,24 @@ static inline void arch_write_lock(arch_rwlock_t *rw)
static inline void arch_read_unlock(arch_rwlock_t *rw)
{
unsigned long flags;
local_irq_save(flags);
arch_spin_lock(&(rw->lock_mutex));
rw->counter++;
arch_spin_unlock(&(rw->lock_mutex));
local_irq_restore(flags);
}
static inline void arch_write_unlock(arch_rwlock_t *rw)
{
unsigned long flags;
local_irq_save(flags);
arch_spin_lock(&(rw->lock_mutex));
rw->counter = __ARCH_RW_LOCK_UNLOCKED__;
arch_spin_unlock(&(rw->lock_mutex));
local_irq_restore(flags);
}
#endif
......
......@@ -9,7 +9,7 @@
#ifndef __ASM_ARC_BYTEORDER_H
#define __ASM_ARC_BYTEORDER_H
#ifdef CONFIG_CPU_BIG_ENDIAN
#ifdef __BIG_ENDIAN__
#include <linux/byteorder/big_endian.h>
#else
#include <linux/byteorder/little_endian.h>
......
......@@ -9,7 +9,7 @@
CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"'
obj-y := arcksyms.o setup.o irq.o time.o reset.o ptrace.o process.o devtree.o
obj-y += signal.o traps.o sys.o troubleshoot.o stacktrace.o disasm.o clk.o
obj-y += signal.o traps.o sys.o troubleshoot.o stacktrace.o disasm.o
obj-$(CONFIG_ISA_ARCOMPACT) += entry-compact.o intc-compact.o
obj-$(CONFIG_ISA_ARCV2) += entry-arcv2.o intc-arcv2.o
obj-$(CONFIG_PCI) += pcibios.o
......
/*
* Copyright (C) 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 <asm/clk.h>
unsigned long core_freq = 80000000;
/*
* As of now we default to device-tree provided clock
* In future we can determine this in early boot
*/
int arc_set_core_freq(unsigned long freq)
{
core_freq = freq;
return 0;
}
......@@ -16,6 +16,9 @@
#include <asm/asm-offsets.h>
#include <linux/sched.h>
#ifdef CONFIG_ARC_PLAT_EZNPS
#include <plat/ctop.h>
#endif
#define KSP_WORD_OFF ((TASK_THREAD + THREAD_KSP) / 4)
......@@ -66,10 +69,17 @@ __switch_to(struct task_struct *prev_task, struct task_struct *next_task)
*/
#ifndef CONFIG_SMP
"st %2, [@_current_task] \n\t"
#else
#ifdef CONFIG_ARC_PLAT_EZNPS
"lr r24, [%4] \n\t"
#ifndef CONFIG_EZNPS_MTM_EXT
"lsr r24, r24, 4 \n\t"
#endif
#else
"lr r24, [identity] \n\t"
"lsr r24, r24, 8 \n\t"
"bmsk r24, r24, 7 \n\t"
#endif
"add2 r24, @_current_task, r24 \n\t"
"st %2, [r24] \n\t"
#endif
......@@ -107,6 +117,9 @@ __switch_to(struct task_struct *prev_task, struct task_struct *next_task)
: "=r"(tmp)
: "n"(KSP_WORD_OFF), "r"(next), "r"(prev)
#ifdef CONFIG_ARC_PLAT_EZNPS
, "i"(CTOP_AUX_LOGIC_GLOBAL_ID)
#endif
: "blink"
);
......
......@@ -14,7 +14,6 @@
#include <linux/memblock.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
#include <asm/clk.h>
#include <asm/mach_desc.h>
#ifdef CONFIG_SERIAL_EARLYCON
......@@ -28,14 +27,12 @@ unsigned int __init arc_early_base_baud(void)
static void __init arc_set_early_base_baud(unsigned long dt_root)
{
unsigned int core_clk = arc_get_core_freq();
if (of_flat_dt_is_compatible(dt_root, "abilis,arc-tb10x"))
arc_base_baud = core_clk/3;
arc_base_baud = 166666666; /* Fixed 166.6MHz clk (TB10x) */
else if (of_flat_dt_is_compatible(dt_root, "snps,arc-sdp"))
arc_base_baud = 33333333; /* Fixed 33MHz clk (AXS10x) */
else
arc_base_baud = core_clk;
arc_base_baud = 50000000; /* Fixed default 50MHz */
}
#else
#define arc_set_early_base_baud(dt_root)
......@@ -65,8 +62,6 @@ const struct machine_desc * __init setup_machine_fdt(void *dt)
{
const struct machine_desc *mdesc;
unsigned long dt_root;
const void *clk;
int len;
if (!early_init_dt_scan(dt))
return NULL;
......@@ -76,10 +71,6 @@ const struct machine_desc * __init setup_machine_fdt(void *dt)
machine_halt();
dt_root = of_get_flat_dt_root();
clk = of_get_flat_dt_prop(dt_root, "clock-frequency", &len);
if (clk)
arc_set_core_freq(of_read_ulong(clk, len/4));
arc_set_early_base_baud(dt_root);
return mdesc;
......
......@@ -137,23 +137,30 @@ static const struct irq_domain_ops arcv2_irq_ops = {
.map = arcv2_irq_map,
};
static struct irq_domain *root_domain;
static int __init
init_onchip_IRQ(struct device_node *intc, struct device_node *parent)
{
struct irq_domain *root_domain;
if (parent)
panic("DeviceTree incore intc not a root irq controller\n");
root_domain = irq_domain_add_legacy(intc, NR_CPU_IRQS, 0, 0,
&arcv2_irq_ops, NULL);
root_domain = irq_domain_add_linear(intc, NR_CPU_IRQS, &arcv2_irq_ops, NULL);
if (!root_domain)
panic("root irq domain not avail\n");
/* with this we don't need to export root_domain */
/*
* Needed for primary domain lookup to succeed
* This is a primary irqchip, and can never have a parent
*/
irq_set_default_host(root_domain);
#ifdef CONFIG_SMP
irq_create_mapping(root_domain, IPI_IRQ);
#endif
irq_create_mapping(root_domain, SOFTIRQ_IRQ);
return 0;
}
......
......@@ -14,6 +14,8 @@
#include <linux/irqchip.h>
#include <asm/irq.h>
#define TIMER0_IRQ 3 /* Fixed by ISA */
/*
* Early Hardware specific Interrupt setup
* -Platform independent, needed for each CPU (not foldable into init_IRQ)
......@@ -79,8 +81,9 @@ static struct irq_chip onchip_intc = {
static int arc_intc_domain_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hw)
{
switch (irq) {
switch (hw) {
case TIMER0_IRQ:
irq_set_percpu_devid(irq);
irq_set_chip_and_handler(irq, &onchip_intc, handle_percpu_irq);
break;
default:
......@@ -94,21 +97,23 @@ static const struct irq_domain_ops arc_intc_domain_ops = {
.map = arc_intc_domain_map,
};
static struct irq_domain *root_domain;
static int __init
init_onchip_IRQ(struct device_node *intc, struct device_node *parent)
{
struct irq_domain *root_domain;
if (parent)
panic("DeviceTree incore intc not a root irq controller\n");
root_domain = irq_domain_add_legacy(intc, NR_CPU_IRQS, 0, 0,
root_domain = irq_domain_add_linear(intc, NR_CPU_IRQS,
&arc_intc_domain_ops, NULL);
if (!root_domain)
panic("root irq domain not avail\n");
/* with this we don't need to export root_domain */
/*
* Needed for primary domain lookup to succeed
* This is a primary irqchip, and can never have a parent
*/
irq_set_default_host(root_domain);
return 0;
......
......@@ -41,53 +41,7 @@ void __init init_IRQ(void)
* "C" Entry point for any ARC ISR, called from low level vector handler
* @irq is the vector number read from ICAUSE reg of on-chip intc
*/
void arch_do_IRQ(unsigned int irq, struct pt_regs *regs)
void arch_do_IRQ(unsigned int hwirq, struct pt_regs *regs)
{
struct pt_regs *old_regs = set_irq_regs(regs);
irq_enter();
generic_handle_irq(irq);
irq_exit();
set_irq_regs(old_regs);
}
/*
* API called for requesting percpu interrupts - called by each CPU
* - For boot CPU, actually request the IRQ with genirq core + enables
* - For subsequent callers only enable called locally
*
* Relies on being called by boot cpu first (i.e. request called ahead) of
* any enable as expected by genirq. Hence Suitable only for TIMER, IPI
* which are guaranteed to be setup on boot core first.
* Late probed peripherals such as perf can't use this as there no guarantee
* of being called on boot CPU first.
*/
void arc_request_percpu_irq(int irq, int cpu,
irqreturn_t (*isr)(int irq, void *dev),
const char *irq_nm,
void *percpu_dev)
{
/* Boot cpu calls request, all call enable */
if (!cpu) {
int rc;
#ifdef CONFIG_ISA_ARCOMPACT
/*
* A subsequent request_percpu_irq() fails if percpu_devid is
* not set. That in turns sets NOAUTOEN, meaning each core needs
* to call enable_percpu_irq()
*
* For ARCv2, this is done in irq map function since we know
* which irqs are strictly per cpu
*/
irq_set_percpu_devid(irq);
#endif
rc = request_percpu_irq(irq, isr, irq_nm, percpu_dev);
if (rc)
panic("Percpu IRQ request failed for %d\n", irq);
}
enable_percpu_irq(irq, 0);
handle_domain_irq(NULL, hwirq, regs);
}
......@@ -15,9 +15,6 @@
#include <asm/mcip.h>
#include <asm/setup.h>
#define IPI_IRQ 19
#define SOFTIRQ_IRQ 21
static char smp_cpuinfo_buf[128];
static int idu_detected;
......@@ -116,15 +113,13 @@ static void mcip_probe_n_setup(void)
IS_AVAIL1(mp.dbg, "DEBUG "),
IS_AVAIL1(mp.gfrc, "GFRC"));
cpuinfo_arc700[0].extn.gfrc = mp.gfrc;
idu_detected = mp.idu;
if (mp.dbg) {
__mcip_cmd_data(CMD_DEBUG_SET_SELECT, 0, 0xf);
__mcip_cmd_data(CMD_DEBUG_SET_MASK, 0xf, 0xf);
}
if (IS_ENABLED(CONFIG_ARC_HAS_GFRC) && !mp.gfrc)
panic("kernel trying to use non-existent GFRC\n");
}
struct plat_smp_ops plat_smp_ops = {
......
......@@ -13,7 +13,6 @@
#include <linux/console.h>
#include <linux/module.h>
#include <linux/cpu.h>
#include <linux/clk-provider.h>
#include <linux/of_fdt.h>
#include <linux/of_platform.h>
#include <linux/cache.h>
......@@ -24,7 +23,6 @@
#include <asm/page.h>
#include <asm/irq.h>
#include <asm/unwind.h>
#include <asm/clk.h>
#include <asm/mach_desc.h>
#include <asm/smp.h>
......@@ -220,10 +218,6 @@ static char *arc_cpu_mumbojumbo(int cpu_id, char *buf, int len)
if (tbl->info.id == 0)
n += scnprintf(buf + n, len - n, "UNKNOWN ARC Processor\n");
n += scnprintf(buf + n, len - n, "CPU speed\t: %u.%02u Mhz\n",
(unsigned int)(arc_get_core_freq() / 1000000),
(unsigned int)(arc_get_core_freq() / 10000) % 100);
n += scnprintf(buf + n, len - n, "Timers\t\t: %s%s%s%s\nISA Extn\t: ",
IS_AVAIL1(cpu->extn.timer0, "Timer0 "),
IS_AVAIL1(cpu->extn.timer1, "Timer1 "),
......@@ -314,9 +308,6 @@ static void arc_chk_core_config(void)
if (!cpu->extn.timer1)
panic("Timer1 is not present!\n");
if (IS_ENABLED(CONFIG_ARC_HAS_RTC) && !cpu->extn.rtc)
panic("RTC is not present\n");
#ifdef CONFIG_ARC_HAS_DCCM
/*
* DCCM can be arbit placed in hardware.
......@@ -444,7 +435,6 @@ void __init setup_arch(char **cmdline_p)
static int __init customize_machine(void)
{
of_clk_init(NULL);
/*
* Traverses flattened DeviceTree - registering platform devices
* (if any) complete with their resources
......@@ -477,6 +467,8 @@ static int show_cpuinfo(struct seq_file *m, void *v)
{
char *str;
int cpu_id = ptr_to_cpu(v);
struct device_node *core_clk = of_find_node_by_name(NULL, "core_clk");
u32 freq = 0;
if (!cpu_online(cpu_id)) {
seq_printf(m, "processor [%d]\t: Offline\n", cpu_id);
......@@ -489,6 +481,11 @@ static int show_cpuinfo(struct seq_file *m, void *v)
seq_printf(m, arc_cpu_mumbojumbo(cpu_id, str, PAGE_SIZE));
of_property_read_u32(core_clk, "clock-frequency", &freq);
if (freq)
seq_printf(m, "CPU speed\t: %u.%02u Mhz\n",
freq / 1000000, (freq / 10000) % 100);
seq_printf(m, "Bogo MIPS\t: %lu.%02lu\n",
loops_per_jiffy / (500000 / HZ),
(loops_per_jiffy / (5000 / HZ)) % 100);
......
......@@ -126,11 +126,6 @@ void start_kernel_secondary(void)
current->active_mm = mm;
cpumask_set_cpu(cpu, mm_cpumask(mm));
notify_cpu_starting(cpu);
set_cpu_online(cpu, true);
pr_info("## CPU%u LIVE ##: Executing Code...\n", cpu);
/* Some SMP H/w setup - for each cpu */
if (plat_smp_ops.init_per_cpu)
plat_smp_ops.init_per_cpu(cpu);
......@@ -138,7 +133,10 @@ void start_kernel_secondary(void)
if (machine_desc->init_per_cpu)
machine_desc->init_per_cpu(cpu);
arc_local_timer_setup();
notify_cpu_starting(cpu);
set_cpu_online(cpu, true);
pr_info("## CPU%u LIVE ##: Executing Code...\n", cpu);
local_irq_enable();
preempt_disable();
......@@ -346,6 +344,10 @@ irqreturn_t do_IPI(int irq, void *dev_id)
/*
* API called by platform code to hookup arch-common ISR to their IPI IRQ
*
* Note: If IPI is provided by platform (vs. say ARC MCIP), their intc setup/map
* function needs to call call irq_set_percpu_devid() for IPI IRQ, otherwise
* request_percpu_irq() below will fail
*/
static DEFINE_PER_CPU(int, ipi_dev);
......@@ -353,7 +355,16 @@ int smp_ipi_irq_setup(int cpu, int irq)
{
int *dev = per_cpu_ptr(&ipi_dev, cpu);
arc_request_percpu_irq(irq, cpu, do_IPI, "IPI Interrupt", dev);
/* Boot cpu calls request, all call enable */
if (!cpu) {
int rc;
rc = request_percpu_irq(irq, do_IPI, "IPI Interrupt", dev);
if (rc)
panic("Percpu IRQ request failed for %d\n", irq);
}
enable_percpu_irq(irq, 0);
return 0;
}
......@@ -29,21 +29,16 @@
* which however is currently broken
*/
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/time.h>
#include <linux/init.h>
#include <linux/timex.h>
#include <linux/profile.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clocksource.h>
#include <linux/clockchips.h>
#include <linux/cpu.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <asm/irq.h>
#include <asm/arcregs.h>
#include <asm/clk.h>
#include <asm/mach_desc.h>
#include <asm/mcip.h>
......@@ -60,16 +55,35 @@
#define ARC_TIMER_MAX 0xFFFFFFFF
/********** Clock Source Device *********/
#ifdef CONFIG_ARC_HAS_GFRC
static unsigned long arc_timer_freq;
static int arc_counter_setup(void)
static int noinline arc_get_timer_clk(struct device_node *node)
{
return 1;
struct clk *clk;
int ret;
clk = of_clk_get(node, 0);
if (IS_ERR(clk)) {
pr_err("timer missing clk");
return PTR_ERR(clk);
}
ret = clk_prepare_enable(clk);
if (ret) {
pr_err("Couldn't enable parent clk\n");
return ret;
}
arc_timer_freq = clk_get_rate(clk);
return 0;
}
static cycle_t arc_counter_read(struct clocksource *cs)
/********** Clock Source Device *********/
#ifdef CONFIG_ARC_HAS_GFRC
static cycle_t arc_read_gfrc(struct clocksource *cs)
{
unsigned long flags;
union {
......@@ -94,15 +108,31 @@ static cycle_t arc_counter_read(struct clocksource *cs)
return stamp.full;
}
static struct clocksource arc_counter = {
static struct clocksource arc_counter_gfrc = {
.name = "ARConnect GFRC",
.rating = 400,
.read = arc_counter_read,
.read = arc_read_gfrc,
.mask = CLOCKSOURCE_MASK(64),
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
#else
static void __init arc_cs_setup_gfrc(struct device_node *node)
{
int exists = cpuinfo_arc700[0].extn.gfrc;
int ret;
if (WARN(!exists, "Global-64-bit-Ctr clocksource not detected"))
return;
ret = arc_get_timer_clk(node);
if (ret)
return;
clocksource_register_hz(&arc_counter_gfrc, arc_timer_freq);
}
CLOCKSOURCE_OF_DECLARE(arc_gfrc, "snps,archs-timer-gfrc", arc_cs_setup_gfrc);
#endif
#ifdef CONFIG_ARC_HAS_RTC
......@@ -110,15 +140,7 @@ static struct clocksource arc_counter = {
#define AUX_RTC_LOW 0x104
#define AUX_RTC_HIGH 0x105
int arc_counter_setup(void)
{
write_aux_reg(AUX_RTC_CTRL, 1);
/* Not usable in SMP */
return !IS_ENABLED(CONFIG_SMP);
}
static cycle_t arc_counter_read(struct clocksource *cs)
static cycle_t arc_read_rtc(struct clocksource *cs)
{
unsigned long status;
union {
......@@ -142,47 +164,78 @@ static cycle_t arc_counter_read(struct clocksource *cs)
return stamp.full;
}
static struct clocksource arc_counter = {
static struct clocksource arc_counter_rtc = {
.name = "ARCv2 RTC",
.rating = 350,
.read = arc_counter_read,
.read = arc_read_rtc,
.mask = CLOCKSOURCE_MASK(64),
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
#else /* !CONFIG_ARC_HAS_RTC */
/*
* set 32bit TIMER1 to keep counting monotonically and wraparound
*/
int arc_counter_setup(void)
static void __init arc_cs_setup_rtc(struct device_node *node)
{
write_aux_reg(ARC_REG_TIMER1_LIMIT, ARC_TIMER_MAX);
write_aux_reg(ARC_REG_TIMER1_CNT, 0);
write_aux_reg(ARC_REG_TIMER1_CTRL, TIMER_CTRL_NH);
int exists = cpuinfo_arc700[smp_processor_id()].extn.rtc;
int ret;
if (WARN(!exists, "Local-64-bit-Ctr clocksource not detected"))
return;
/* Local to CPU hence not usable in SMP */
if (WARN(IS_ENABLED(CONFIG_SMP), "Local-64-bit-Ctr not usable in SMP"))
return;
ret = arc_get_timer_clk(node);
if (ret)
return;
/* Not usable in SMP */
return !IS_ENABLED(CONFIG_SMP);
write_aux_reg(AUX_RTC_CTRL, 1);
clocksource_register_hz(&arc_counter_rtc, arc_timer_freq);
}
CLOCKSOURCE_OF_DECLARE(arc_rtc, "snps,archs-timer-rtc", arc_cs_setup_rtc);
#endif
static cycle_t arc_counter_read(struct clocksource *cs)
/*
* 32bit TIMER1 to keep counting monotonically and wraparound
*/
static cycle_t arc_read_timer1(struct clocksource *cs)
{
return (cycle_t) read_aux_reg(ARC_REG_TIMER1_CNT);
}
static struct clocksource arc_counter = {
static struct clocksource arc_counter_timer1 = {
.name = "ARC Timer1",
.rating = 300,
.read = arc_counter_read,
.read = arc_read_timer1,
.mask = CLOCKSOURCE_MASK(32),
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
#endif
#endif
static void __init arc_cs_setup_timer1(struct device_node *node)
{
int ret;
/* Local to CPU hence not usable in SMP */
if (IS_ENABLED(CONFIG_SMP))
return;
ret = arc_get_timer_clk(node);
if (ret)
return;
write_aux_reg(ARC_REG_TIMER1_LIMIT, ARC_TIMER_MAX);
write_aux_reg(ARC_REG_TIMER1_CNT, 0);
write_aux_reg(ARC_REG_TIMER1_CTRL, TIMER_CTRL_NH);
clocksource_register_hz(&arc_counter_timer1, arc_timer_freq);
}
/********** Clock Event Device *********/
static int arc_timer_irq;
/*
* Arm the timer to interrupt after @cycles
* The distinction for oneshot/periodic is done in arc_event_timer_ack() below
......@@ -209,7 +262,7 @@ static int arc_clkevent_set_periodic(struct clock_event_device *dev)
* At X Hz, 1 sec = 1000ms -> X cycles;
* 10ms -> X / 100 cycles
*/
arc_timer_event_setup(arc_get_core_freq() / HZ);
arc_timer_event_setup(arc_timer_freq / HZ);
return 0;
}
......@@ -218,7 +271,6 @@ static DEFINE_PER_CPU(struct clock_event_device, arc_clockevent_device) = {
.features = CLOCK_EVT_FEAT_ONESHOT |
CLOCK_EVT_FEAT_PERIODIC,
.rating = 300,
.irq = TIMER0_IRQ, /* hardwired, no need for resources */
.set_next_event = arc_clkevent_set_next_event,
.set_state_periodic = arc_clkevent_set_periodic,
};
......@@ -244,45 +296,81 @@ static irqreturn_t timer_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
static int arc_timer_cpu_notify(struct notifier_block *self,
unsigned long action, void *hcpu)
{
struct clock_event_device *evt = this_cpu_ptr(&arc_clockevent_device);
evt->cpumask = cpumask_of(smp_processor_id());
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_STARTING:
clockevents_config_and_register(evt, arc_timer_freq,
0, ULONG_MAX);
enable_percpu_irq(arc_timer_irq, 0);
break;
case CPU_DYING:
disable_percpu_irq(arc_timer_irq);
break;
}
return NOTIFY_OK;
}
static struct notifier_block arc_timer_cpu_nb = {
.notifier_call = arc_timer_cpu_notify,
};
/*
* Setup the local event timer for @cpu
* clockevent setup for boot CPU
*/
void arc_local_timer_setup()
static void __init arc_clockevent_setup(struct device_node *node)
{
struct clock_event_device *evt = this_cpu_ptr(&arc_clockevent_device);
int cpu = smp_processor_id();
int ret;
evt->cpumask = cpumask_of(cpu);
clockevents_config_and_register(evt, arc_get_core_freq(),
register_cpu_notifier(&arc_timer_cpu_nb);
arc_timer_irq = irq_of_parse_and_map(node, 0);
if (arc_timer_irq <= 0)
panic("clockevent: missing irq");
ret = arc_get_timer_clk(node);
if (ret)
panic("clockevent: missing clk");
evt->irq = arc_timer_irq;
evt->cpumask = cpumask_of(smp_processor_id());
clockevents_config_and_register(evt, arc_timer_freq,
0, ARC_TIMER_MAX);
/* setup the per-cpu timer IRQ handler - for all cpus */
arc_request_percpu_irq(TIMER0_IRQ, cpu, timer_irq_handler,
/* Needs apriori irq_set_percpu_devid() done in intc map function */
ret = request_percpu_irq(arc_timer_irq, timer_irq_handler,
"Timer0 (per-cpu-tick)", evt);
if (ret)
panic("clockevent: unable to request irq\n");
enable_percpu_irq(arc_timer_irq, 0);
}
static void __init arc_of_timer_init(struct device_node *np)
{
static int init_count = 0;
if (!init_count) {
init_count = 1;
arc_clockevent_setup(np);
} else {
arc_cs_setup_timer1(np);
}
}
CLOCKSOURCE_OF_DECLARE(arc_clkevt, "snps,arc-timer", arc_of_timer_init);
/*
* Called from start_kernel() - boot CPU only
*
* -Sets up h/w timers as applicable on boot cpu
* -Also sets up any global state needed for timer subsystem:
* - for "counting" timer, registers a clocksource, usable across CPUs
* (provided that underlying counter h/w is synchronized across cores)
* - for "event" timer, sets up TIMER0 IRQ (as that is platform agnostic)
*/
void __init time_init(void)
{
/*
* sets up the timekeeping free-flowing counter which also returns
* whether the counter is usable as clocksource
*/
if (arc_counter_setup())
/*
* CLK upto 4.29 GHz can be safely represented in 32 bits
* because Max 32 bit number is 4,294,967,295
*/
clocksource_register_hz(&arc_counter, arc_get_core_freq());
/* sets up the periodic event timer */
arc_local_timer_setup();
of_clk_init(NULL);
clocksource_probe();
}
......@@ -814,6 +814,17 @@ void arc_mmu_init(void)
printk(arc_mmu_mumbojumbo(0, str, sizeof(str)));
/*
* Can't be done in processor.h due to header include depenedencies
*/
BUILD_BUG_ON(!IS_ALIGNED((CONFIG_ARC_KVADDR_SIZE << 20), PMD_SIZE));
/*
* stack top size sanity check,
* Can't be done in processor.h due to header include depenedencies
*/
BUILD_BUG_ON(!IS_ALIGNED(STACK_TOP, PMD_SIZE));
/* For efficiency sake, kernel is compile time built for a MMU ver
* This must match the hardware it is running on.
* Linux built for MMU V2, if run on MMU V1 will break down because V1
......
......@@ -14,10 +14,11 @@
*
*/
#include <linux/of_fdt.h>
#include <linux/of_platform.h>
#include <linux/libfdt.h>
#include <asm/asm-offsets.h>
#include <asm/clk.h>
#include <asm/io.h>
#include <asm/mach_desc.h>
#include <asm/mcip.h>
......@@ -389,6 +390,13 @@ axs103_set_freq(unsigned int id, unsigned int fd, unsigned int od)
static void __init axs103_early_init(void)
{
int offset = fdt_path_offset(initial_boot_params, "/cpu_card/core_clk");
const struct fdt_property *prop = fdt_get_property(initial_boot_params,
offset,
"clock-frequency",
NULL);
u32 freq = be32_to_cpu(*(u32*)(prop->data)) / 1000000, orig = freq;
/*
* AXS103 configurations for SMP/QUAD configurations share device tree
* which defaults to 90 MHz. However recent failures of Quad config
......@@ -401,12 +409,10 @@ static void __init axs103_early_init(void)
#ifdef CONFIG_ARC_MCIP
unsigned int num_cores = (read_aux_reg(ARC_REG_MCIP_BCR) >> 16) & 0x3F;
if (num_cores > 2)
arc_set_core_freq(50 * 1000000);
else if (num_cores == 2)
arc_set_core_freq(75 * 1000000);
freq = 50;
#endif
switch (arc_get_core_freq()/1000000) {
switch (freq) {
case 33:
axs103_set_freq(1, 1, 1);
break;
......@@ -431,11 +437,18 @@ static void __init axs103_early_init(void)
* DT "clock-frequency" might not match with board value.
* Hence update it to match the board value.
*/
arc_set_core_freq(axs103_get_freq() * 1000000);
freq = axs103_get_freq();
break;
}
pr_info("Freq is %dMHz\n", axs103_get_freq());
pr_info("Freq is %dMHz\n", freq);
/* Patching .dtb in-place with new core clock value */
if (freq != orig ) {
freq = cpu_to_be32(freq * 1000000);
fdt_setprop_inplace(initial_boot_params, offset,
"clock-frequency", &freq, sizeof(freq));
}
/* Memory maps already config in pre-bootloader */
......
#
# 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.
#
# Makefile for the linux kernel.
#
obj-y := entry.o platform.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_EZNPS_MTM_EXT) += mtm.o
/*******************************************************************************
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)
/*
* 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)
#else
.macro GET_CPU_ID reg
lr \reg, [CTOP_AUX_LOGIC_GLOBAL_ID]
#ifndef CONFIG_EZNPS_MTM_EXT
lsr \reg, \reg, 4
#endif
.endm
#endif /* __ASSEMBLY__ */
#endif /* _PLAT_EZNPS_CTOP_H */
/*
* 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 */
/*
* 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
/*
* 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();
}
/*
* 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
/*
* 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,
};
......@@ -181,6 +181,16 @@ config CLKSRC_TI_32K
This option enables support for Texas Instruments 32.768 Hz clocksource
available on many OMAP-like platforms.
config CLKSRC_NPS
bool "NPS400 clocksource driver" if COMPILE_TEST
depends on !PHYS_ADDR_T_64BIT
select CLKSRC_MMIO
select CLKSRC_OF if OF
help
NPS400 clocksource support.
Got 64 bit counter with update rate up to 1000MHz.
This counter is accessed via couple of 32 bit memory mapped registers.
config CLKSRC_STM32
bool "Clocksource for STM32 SoCs" if !ARCH_STM32
depends on OF && ARM && (ARCH_STM32 || COMPILE_TEST)
......
......@@ -47,6 +47,7 @@ obj-$(CONFIG_CLKSRC_QCOM) += qcom-timer.o
obj-$(CONFIG_MTK_TIMER) += mtk_timer.o
obj-$(CONFIG_CLKSRC_PISTACHIO) += time-pistachio.o
obj-$(CONFIG_CLKSRC_TI_32K) += timer-ti-32k.o
obj-$(CONFIG_CLKSRC_NPS) += timer-nps.o
obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o
obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o
......
/*
* Copyright (c) 2016, Mellanox Technologies. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <linux/interrupt.h>
#include <linux/clocksource.h>
#include <linux/clockchips.h>
#include <linux/clk.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/cpu.h>
#include <soc/nps/common.h>
#define NPS_MSU_TICK_LOW 0xC8
#define NPS_CLUSTER_OFFSET 8
#define NPS_CLUSTER_NUM 16
/* This array is per cluster of CPUs (Each NPS400 cluster got 256 CPUs) */
static void *nps_msu_reg_low_addr[NPS_CLUSTER_NUM] __read_mostly;
static unsigned long nps_timer_rate;
static cycle_t nps_clksrc_read(struct clocksource *clksrc)
{
int cluster = raw_smp_processor_id() >> NPS_CLUSTER_OFFSET;
return (cycle_t)ioread32be(nps_msu_reg_low_addr[cluster]);
}
static void __init nps_setup_clocksource(struct device_node *node,
struct clk *clk)
{
int ret, cluster;
for (cluster = 0; cluster < NPS_CLUSTER_NUM; cluster++)
nps_msu_reg_low_addr[cluster] =
nps_host_reg((cluster << NPS_CLUSTER_OFFSET),
NPS_MSU_BLKID, NPS_MSU_TICK_LOW);
ret = clk_prepare_enable(clk);
if (ret) {
pr_err("Couldn't enable parent clock\n");
return;
}
nps_timer_rate = clk_get_rate(clk);
ret = clocksource_mmio_init(nps_msu_reg_low_addr, "EZnps-tick",
nps_timer_rate, 301, 32, nps_clksrc_read);
if (ret) {
pr_err("Couldn't register clock source.\n");
clk_disable_unprepare(clk);
}
}
static void __init nps_timer_init(struct device_node *node)
{
struct clk *clk;
clk = of_clk_get(node, 0);
if (IS_ERR(clk)) {
pr_err("Can't get timer clock.\n");
return;
}
nps_setup_clocksource(node, clk);
}
CLOCKSOURCE_OF_DECLARE(ezchip_nps400_clksrc, "ezchip,nps400-timer",
nps_timer_init);
......@@ -253,3 +253,9 @@ config LS_SCFG_MSI
config PARTITION_PERCPU
bool
config EZNPS_GIC
bool "NPS400 Global Interrupt Manager (GIM)"
select IRQ_DOMAIN
help
Support the EZchip NPS400 global interrupt controller
......@@ -68,3 +68,4 @@ obj-$(CONFIG_IMX_GPCV2) += irq-imx-gpcv2.o
obj-$(CONFIG_PIC32_EVIC) += irq-pic32-evic.o
obj-$(CONFIG_MVEBU_ODMI) += irq-mvebu-odmi.o
obj-$(CONFIG_LS_SCFG_MSI) += irq-ls-scfg-msi.o
obj-$(CONFIG_EZNPS_GIC) += irq-eznps.o
/*
* Copyright (c) 2016, Mellanox Technologies. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/irqchip.h>
#include <soc/nps/common.h>
#define NPS_NR_CPU_IRQS 8 /* number of interrupt lines of NPS400 CPU */
#define NPS_TIMER0_IRQ 3
/*
* NPS400 core includes an Interrupt Controller (IC) support.
* All cores can deactivate level irqs at first level control
* at cores mesh layer called MTM.
* For devices out side chip e.g. uart, network there is another
* level called Global Interrupt Manager (GIM).
* This second level can control level and edge interrupt.
*
* NOTE: AUX_IENABLE and CTOP_AUX_IACK are auxiliary registers
* with private HW copy per CPU.
*/
static void nps400_irq_mask(struct irq_data *irqd)
{
unsigned int ienb;
unsigned int irq = irqd_to_hwirq(irqd);
ienb = read_aux_reg(AUX_IENABLE);
ienb &= ~(1 << irq);
write_aux_reg(AUX_IENABLE, ienb);
}
static void nps400_irq_unmask(struct irq_data *irqd)
{
unsigned int ienb;
unsigned int irq = irqd_to_hwirq(irqd);
ienb = read_aux_reg(AUX_IENABLE);
ienb |= (1 << irq);
write_aux_reg(AUX_IENABLE, ienb);
}
static void nps400_irq_eoi_global(struct irq_data *irqd)
{
unsigned int __maybe_unused irq = irqd_to_hwirq(irqd);
write_aux_reg(CTOP_AUX_IACK, 1 << irq);
/* Don't ack GIC before all device access attempts are done */
mb();
nps_ack_gic();
}
static void nps400_irq_eoi(struct irq_data *irqd)
{
unsigned int __maybe_unused irq = irqd_to_hwirq(irqd);
write_aux_reg(CTOP_AUX_IACK, 1 << irq);
}
static struct irq_chip nps400_irq_chip_fasteoi = {
.name = "NPS400 IC Global",
.irq_mask = nps400_irq_mask,
.irq_unmask = nps400_irq_unmask,
.irq_eoi = nps400_irq_eoi_global,
};
static struct irq_chip nps400_irq_chip_percpu = {
.name = "NPS400 IC",
.irq_mask = nps400_irq_mask,
.irq_unmask = nps400_irq_unmask,
.irq_eoi = nps400_irq_eoi,
};
static int nps400_irq_map(struct irq_domain *d, unsigned int virq,
irq_hw_number_t hw)
{
switch (hw) {
case NPS_TIMER0_IRQ:
#ifdef CONFIG_SMP
case NPS_IPI_IRQ:
#endif
irq_set_percpu_devid(virq);
irq_set_chip_and_handler(virq, &nps400_irq_chip_percpu,
handle_percpu_devid_irq);
break;
default:
irq_set_chip_and_handler(virq, &nps400_irq_chip_fasteoi,
handle_fasteoi_irq);
break;
}
return 0;
}
static const struct irq_domain_ops nps400_irq_ops = {
.xlate = irq_domain_xlate_onecell,
.map = nps400_irq_map,
};
static int __init nps400_of_init(struct device_node *node,
struct device_node *parent)
{
static struct irq_domain *nps400_root_domain;
if (parent) {
pr_err("DeviceTree incore ic not a root irq controller\n");
return -EINVAL;
}
nps400_root_domain = irq_domain_add_linear(node, NPS_NR_CPU_IRQS,
&nps400_irq_ops, NULL);
if (!nps400_root_domain) {
pr_err("nps400 root irq domain not avail\n");
return -ENOMEM;
}
/*
* Needed for primary domain lookup to succeed
* This is a primary irqchip, and can never have a parent
*/
irq_set_default_host(nps400_root_domain);
#ifdef CONFIG_SMP
irq_create_mapping(nps400_root_domain, NPS_IPI_IRQ);
#endif
return 0;
}
IRQCHIP_DECLARE(ezchip_nps400_ic, "ezchip,nps400-ic", nps400_of_init);
/*
* Copyright (c) 2016, Mellanox Technologies. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef SOC_NPS_COMMON_H
#define SOC_NPS_COMMON_H
#ifdef CONFIG_SMP
#define NPS_IPI_IRQ 5
#endif
#define NPS_HOST_REG_BASE 0xF6000000
#define NPS_MSU_BLKID 0x018
#define CTOP_INST_RSPI_GIC_0_R12 0x3C56117E
#define CTOP_INST_MOV2B_FLIP_R3_B1_B2_INST 0x5B60
#define CTOP_INST_MOV2B_FLIP_R3_B1_B2_LIMM 0x00010422
#ifndef __ASSEMBLY__
/* In order to increase compilation test coverage */
#ifdef CONFIG_ARC
static inline void nps_ack_gic(void)
{
__asm__ __volatile__ (
" .word %0\n"
:
: "i"(CTOP_INST_RSPI_GIC_0_R12)
: "memory");
}
#else
static inline void nps_ack_gic(void) { }
#define write_aux_reg(r, v)
#define read_aux_reg(r) 0
#endif
/* 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 physically,
* and not like the id's physically came with each cluster.
* Below table is 4x4 mesh of core clusters as it layout on chip.
* 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
*/
static inline int nps_cluster_logic_to_phys(int cluster)
{
#ifdef __arc__
__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");
#endif
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_address_non_cl {
union {
struct {
u32 base:7, blkid:11, reg:12, __reserved:2;
};
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;
}
#endif /* __ASSEMBLY__ */
#endif /* SOC_NPS_COMMON_H */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册