diff options
author | Amit Daniel Kachhap <amit.kachhap@arm.com> | 2018-07-30 14:06:10 +0530 |
---|---|---|
committer | Amit Daniel Kachhap <amit.kachhap@arm.com> | 2018-07-30 14:06:10 +0530 |
commit | c37be6a93733b0b8e32c4a747153c06448758261 (patch) | |
tree | dd72504fb921dac3f0864cd70c78d217db5b7332 | |
parent | fd271cdb4e4d81f1b8548c129cf6fd5025ef3269 (diff) | |
parent | 8a60d0a554b7c854a00ee61c2a899e8351b6509b (diff) |
Merge branch 'latest-armlt-scmi' into latest-armlt
-rw-r--r-- | Documentation/devicetree/bindings/mailbox/arm-mhu.txt | 39 | ||||
-rw-r--r-- | arch/arm/mach-vexpress/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm64/boot/dts/arm/juno-base.dtsi | 129 | ||||
-rw-r--r-- | arch/arm64/boot/dts/arm/juno-cs-r1r2.dtsi | 6 | ||||
-rw-r--r-- | arch/arm64/boot/dts/arm/juno-r1.dts | 12 | ||||
-rw-r--r-- | arch/arm64/boot/dts/arm/juno-r2.dts | 12 | ||||
-rw-r--r-- | arch/arm64/boot/dts/arm/juno.dts | 12 | ||||
-rw-r--r-- | arch/arm64/configs/defconfig | 14 | ||||
-rw-r--r-- | drivers/mailbox/arm_mhu.c | 388 | ||||
-rw-r--r-- | drivers/mailbox/mailbox.c | 11 | ||||
-rw-r--r-- | include/linux/mailbox_controller.h | 11 | ||||
-rw-r--r-- | linaro/configs/vexpress64.conf | 17 |
12 files changed, 509 insertions, 143 deletions
diff --git a/Documentation/devicetree/bindings/mailbox/arm-mhu.txt b/Documentation/devicetree/bindings/mailbox/arm-mhu.txt index 4971f03f0b33..ba659bcc7109 100644 --- a/Documentation/devicetree/bindings/mailbox/arm-mhu.txt +++ b/Documentation/devicetree/bindings/mailbox/arm-mhu.txt @@ -10,6 +10,15 @@ STAT register and the remote clears it after having read the data. The last channel is specified to be a 'Secure' resource, hence can't be used by Linux running NS. +The MHU drives the interrupt signal using a 32-bit register, with all +32-bits logically ORed together. It provides a set of registers to +enable software to set, clear and check the status of each of the bits +of this register independently. The use of 32 bits per interrupt line +enables software to provide more information about the source of the +interrupt. For example, each bit of the register can be associated with +a type of event that can contribute to raising the interrupt. Each of +the 32-bits can be used as "doorbell" to alert the remote processor. + Mailbox Device Node: ==================== @@ -18,13 +27,21 @@ Required properties: - compatible: Shall be "arm,mhu" & "arm,primecell" - reg: Contains the mailbox register address range (base address and length) -- #mbox-cells Shall be 1 - the index of the channel needed. +- #mbox-cells Shall be 1 - the index of the channel needed when + not used as set of doorbell bits. + Shall be 2 - the index of the channel needed, and + the index of the doorbell bit within the channel + when used in doorbell mode. - interrupts: Contains the interrupt information corresponding to - each of the 3 links of MHU. + each of the 3 physical channels of MHU namely low + priority non-secure, high priority non-secure and + secure channels. Example: -------- +1. Controller which doesn't support doorbells + mhu: mailbox@2b1f0000 { #mbox-cells = <1>; compatible = "arm,mhu", "arm,primecell"; @@ -41,3 +58,21 @@ Example: reg = <0 0x2e000000 0x4000>; mboxes = <&mhu 1>; /* HP-NonSecure */ }; + +2. Controller which supports doorbells + + mhu: mailbox@2b1f0000 { + #mbox-cells = <2>; + compatible = "arm,mhu", "arm,primecell"; + reg = <0 0x2b1f0000 0x1000>; + interrupts = <0 36 4>, /* LP-NonSecure */ + <0 35 4>; /* HP-NonSecure */ + clocks = <&clock 0 2 1>; + clock-names = "apb_pclk"; + }; + + mhu_client: scb@2e000000 { + compatible = "arm,scpi"; + reg = <0 0x2e000000 0x200>; + mboxes = <&mhu 1 4>; /* HP-NonSecure 5th doorbell bit */ + }; diff --git a/arch/arm/mach-vexpress/Kconfig b/arch/arm/mach-vexpress/Kconfig index 34fb191bb6e3..f848d0e11b02 100644 --- a/arch/arm/mach-vexpress/Kconfig +++ b/arch/arm/mach-vexpress/Kconfig @@ -24,6 +24,7 @@ menuconfig ARCH_VEXPRESS select VEXPRESS_CONFIG select VEXPRESS_SYSCFG select MFD_VEXPRESS_SYSREG + select PM_GENERIC_DOMAINS help This option enables support for systems using Cortex processor based ARM core and logic (FPGA) tiles on the Versatile Express motherboard, diff --git a/arch/arm64/boot/dts/arm/juno-base.dtsi b/arch/arm64/boot/dts/arm/juno-base.dtsi index 4b898164ab74..000b681a1001 100644 --- a/arch/arm64/boot/dts/arm/juno-base.dtsi +++ b/arch/arm64/boot/dts/arm/juno-base.dtsi @@ -23,13 +23,14 @@ }; mailbox: mhu@2b1f0000 { - compatible = "arm,mhu", "arm,primecell"; + compatible = "arm,mhu-doorbell", "arm,primecell"; reg = <0x0 0x2b1f0000 0x0 0x1000>; interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "mhu_lpri_rx", "mhu_hpri_rx"; - #mbox-cells = <1>; + #mbox-cells = <2>; + mbox-name = "ARM-MHU"; clocks = <&soc_refclk100mhz>; clock-names = "apb_pclk"; }; @@ -53,7 +54,7 @@ #iommu-cells = <1>; #global-interrupts = <1>; dma-coherent; - power-domains = <&scpi_devpd 0>; + power-domains = <&scmi_devpd 8>; }; gic: interrupt-controller@2c010000 { @@ -113,7 +114,7 @@ clocks = <&soc_smc50mhz>; clock-names = "apb_pclk"; - power-domains = <&scpi_devpd 0>; + power-domains = <&scmi_devpd 8>; ports { #address-cells = <1>; #size-cells = <0>; @@ -142,7 +143,7 @@ clocks = <&soc_smc50mhz>; clock-names = "apb_pclk"; - power-domains = <&scpi_devpd 0>; + power-domains = <&scmi_devpd 8>; port { tpiu_in_port: endpoint { slave-mode; @@ -158,7 +159,7 @@ clocks = <&soc_smc50mhz>; clock-names = "apb_pclk"; - power-domains = <&scpi_devpd 0>; + power-domains = <&scmi_devpd 8>; ports { #address-cells = <1>; #size-cells = <0>; @@ -197,7 +198,7 @@ clocks = <&soc_smc50mhz>; clock-names = "apb_pclk"; - power-domains = <&scpi_devpd 0>; + power-domains = <&scmi_devpd 8>; port { etr_in_port: endpoint { slave-mode; @@ -214,7 +215,7 @@ clocks = <&soc_smc50mhz>; clock-names = "apb_pclk"; - power-domains = <&scpi_devpd 0>; + power-domains = <&scmi_devpd 8>; port { stm_out_port: endpoint { }; @@ -227,7 +228,7 @@ clocks = <&soc_smc50mhz>; clock-names = "apb_pclk"; - power-domains = <&scpi_devpd 0>; + power-domains = <&scmi_devpd 8>; }; etm0: etm@22040000 { @@ -236,7 +237,7 @@ clocks = <&soc_smc50mhz>; clock-names = "apb_pclk"; - power-domains = <&scpi_devpd 0>; + power-domains = <&scmi_devpd 8>; port { cluster0_etm0_out_port: endpoint { remote-endpoint = <&cluster0_funnel_in_port0>; @@ -250,7 +251,7 @@ clocks = <&soc_smc50mhz>; clock-names = "apb_pclk"; - power-domains = <&scpi_devpd 0>; + power-domains = <&scmi_devpd 8>; ports { #address-cells = <1>; #size-cells = <0>; @@ -286,7 +287,7 @@ clocks = <&soc_smc50mhz>; clock-names = "apb_pclk"; - power-domains = <&scpi_devpd 0>; + power-domains = <&scmi_devpd 8>; }; etm1: etm@22140000 { @@ -295,7 +296,7 @@ clocks = <&soc_smc50mhz>; clock-names = "apb_pclk"; - power-domains = <&scpi_devpd 0>; + power-domains = <&scmi_devpd 8>; port { cluster0_etm1_out_port: endpoint { remote-endpoint = <&cluster0_funnel_in_port1>; @@ -309,7 +310,7 @@ clocks = <&soc_smc50mhz>; clock-names = "apb_pclk"; - power-domains = <&scpi_devpd 0>; + power-domains = <&scmi_devpd 8>; }; etm2: etm@23040000 { @@ -318,7 +319,7 @@ clocks = <&soc_smc50mhz>; clock-names = "apb_pclk"; - power-domains = <&scpi_devpd 0>; + power-domains = <&scmi_devpd 8>; port { cluster1_etm0_out_port: endpoint { remote-endpoint = <&cluster1_funnel_in_port0>; @@ -332,7 +333,7 @@ clocks = <&soc_smc50mhz>; clock-names = "apb_pclk"; - power-domains = <&scpi_devpd 0>; + power-domains = <&scmi_devpd 8>; ports { #address-cells = <1>; #size-cells = <0>; @@ -382,7 +383,7 @@ clocks = <&soc_smc50mhz>; clock-names = "apb_pclk"; - power-domains = <&scpi_devpd 0>; + power-domains = <&scmi_devpd 8>; }; etm3: etm@23140000 { @@ -391,7 +392,7 @@ clocks = <&soc_smc50mhz>; clock-names = "apb_pclk"; - power-domains = <&scpi_devpd 0>; + power-domains = <&scmi_devpd 8>; port { cluster1_etm1_out_port: endpoint { remote-endpoint = <&cluster1_funnel_in_port1>; @@ -405,7 +406,7 @@ clocks = <&soc_smc50mhz>; clock-names = "apb_pclk"; - power-domains = <&scpi_devpd 0>; + power-domains = <&scmi_devpd 8>; }; etm4: etm@23240000 { @@ -414,7 +415,7 @@ clocks = <&soc_smc50mhz>; clock-names = "apb_pclk"; - power-domains = <&scpi_devpd 0>; + power-domains = <&scmi_devpd 8>; port { cluster1_etm2_out_port: endpoint { remote-endpoint = <&cluster1_funnel_in_port2>; @@ -428,7 +429,7 @@ clocks = <&soc_smc50mhz>; clock-names = "apb_pclk"; - power-domains = <&scpi_devpd 0>; + power-domains = <&scmi_devpd 8>; }; etm5: etm@23340000 { @@ -437,7 +438,7 @@ clocks = <&soc_smc50mhz>; clock-names = "apb_pclk"; - power-domains = <&scpi_devpd 0>; + power-domains = <&scmi_devpd 8>; port { cluster1_etm3_out_port: endpoint { remote-endpoint = <&cluster1_funnel_in_port3>; @@ -451,7 +452,7 @@ clocks = <&soc_smc50mhz>; clock-names = "apb_pclk"; - power-domains = <&scpi_devpd 0>; + power-domains = <&scmi_devpd 8>; ports { #address-cells = <1>; @@ -490,14 +491,24 @@ #size-cells = <1>; ranges = <0 0x0 0x2e000000 0x8000>; - cpu_scp_lpri: scp-shmem@0 { + cpu_scp_lpri0: scp-shmem@0 { compatible = "arm,juno-scp-shmem"; - reg = <0x0 0x200>; + reg = <0x0 0x80>; }; - cpu_scp_hpri: scp-shmem@200 { + cpu_scp_lpri1: scp-shmem@80 { compatible = "arm,juno-scp-shmem"; - reg = <0x200 0x200>; + reg = <0x80 0x80>; + }; + + cpu_scp_hpri0: scp-shmem@100 { + compatible = "arm,juno-scp-shmem"; + reg = <0x100 0x80>; + }; + + cpu_scp_hpri1: scp-shmem@180 { + compatible = "arm,juno-scp-shmem"; + reg = <0x180 0x80>; }; }; @@ -525,37 +536,37 @@ iommu-map = <0x0 &smmu_pcie 0x0 0x1>; }; - scpi { - compatible = "arm,scpi"; - mboxes = <&mailbox 1>; - shmem = <&cpu_scp_hpri>; + firmware { + scmi { + compatible = "arm,scmi"; + mbox-names = "tx", "rx"; + mboxes = <&mailbox 0 0 &mailbox 0 1>; + shmem = <&cpu_scp_lpri0 &cpu_scp_lpri1>; + #address-cells = <1>; + #size-cells = <0>; - clocks { - compatible = "arm,scpi-clocks"; + scmi_devpd: protocol@11 { + reg = <0x11>; + #power-domain-cells = <1>; + }; - scpi_dvfs: scpi-dvfs { - compatible = "arm,scpi-dvfs-clocks"; + scmi_dvfs: protocol@13 { + reg = <0x13>; #clock-cells = <1>; - clock-indices = <0>, <1>, <2>; - clock-output-names = "atlclk", "aplclk","clk_mali"; + mbox-names = "tx", "rx"; + mboxes = <&mailbox 1 0 &mailbox 1 1>; + shmem = <&cpu_scp_hpri0 &cpu_scp_hpri1>; }; - scpi_clk: scpi-clk { - compatible = "arm,scpi-variable-clocks"; + + scmi_clk: protocol@14 { + reg = <0x14>; #clock-cells = <1>; - clock-indices = <3>; - clock-output-names = "pxlclk"; }; - }; - scpi_devpd: scpi-power-domains { - compatible = "arm,scpi-power-domains"; - num-domains = <2>; - #power-domain-cells = <1>; - }; - - scpi_sensors0: sensors { - compatible = "arm,scpi-sensors"; - #thermal-sensor-cells = <1>; + scmi_sensors0: protocol@15 { + reg = <0x15>; + #thermal-sensor-cells = <1>; + }; }; }; @@ -563,40 +574,40 @@ pmic { polling-delay = <1000>; polling-delay-passive = <100>; - thermal-sensors = <&scpi_sensors0 0>; + thermal-sensors = <&scmi_sensors0 0>; }; soc { polling-delay = <1000>; polling-delay-passive = <100>; - thermal-sensors = <&scpi_sensors0 3>; + thermal-sensors = <&scmi_sensors0 3>; }; big_cluster_thermal_zone: big_cluster { polling-delay = <1000>; polling-delay-passive = <100>; - thermal-sensors = <&scpi_sensors0 21>; + thermal-sensors = <&scmi_sensors0 21>; status = "disabled"; }; little_cluster_thermal_zone: little_cluster { polling-delay = <1000>; polling-delay-passive = <100>; - thermal-sensors = <&scpi_sensors0 22>; + thermal-sensors = <&scmi_sensors0 22>; status = "disabled"; }; gpu0_thermal_zone: gpu0 { polling-delay = <1000>; polling-delay-passive = <100>; - thermal-sensors = <&scpi_sensors0 23>; + thermal-sensors = <&scmi_sensors0 23>; status = "disabled"; }; gpu1_thermal_zone: gpu1 { polling-delay = <1000>; polling-delay-passive = <100>; - thermal-sensors = <&scpi_sensors0 24>; + thermal-sensors = <&scmi_sensors0 24>; status = "disabled"; }; }; @@ -673,7 +684,7 @@ reg = <0 0x7ff50000 0 0x1000>; interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>; iommus = <&smmu_hdlcd1 0>; - clocks = <&scpi_clk 3>; + clocks = <&scmi_clk 3>; clock-names = "pxlclk"; port { @@ -688,7 +699,7 @@ reg = <0 0x7ff60000 0 0x1000>; interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>; iommus = <&smmu_hdlcd0 0>; - clocks = <&scpi_clk 3>; + clocks = <&scmi_clk 3>; clock-names = "pxlclk"; port { diff --git a/arch/arm64/boot/dts/arm/juno-cs-r1r2.dtsi b/arch/arm64/boot/dts/arm/juno-cs-r1r2.dtsi index 0c43fb3525eb..21287f2d75d3 100644 --- a/arch/arm64/boot/dts/arm/juno-cs-r1r2.dtsi +++ b/arch/arm64/boot/dts/arm/juno-cs-r1r2.dtsi @@ -6,7 +6,7 @@ clocks = <&soc_smc50mhz>; clock-names = "apb_pclk"; - power-domains = <&scpi_devpd 0>; + power-domains = <&scmi_devpd 8>; ports { #address-cells = <1>; #size-cells = <0>; @@ -36,7 +36,7 @@ clocks = <&soc_smc50mhz>; clock-names = "apb_pclk"; - power-domains = <&scpi_devpd 0>; + power-domains = <&scmi_devpd 8>; ports { #address-cells = <1>; #size-cells = <0>; @@ -66,7 +66,7 @@ clocks = <&soc_smc50mhz>; clock-names = "apb_pclk"; - power-domains = <&scpi_devpd 0>; + power-domains = <&scmi_devpd 8>; ports { #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm64/boot/dts/arm/juno-r1.dts b/arch/arm64/boot/dts/arm/juno-r1.dts index ffd94be44f1b..8b2501e73cbe 100644 --- a/arch/arm64/boot/dts/arm/juno-r1.dts +++ b/arch/arm64/boot/dts/arm/juno-r1.dts @@ -96,7 +96,7 @@ d-cache-line-size = <64>; d-cache-sets = <256>; next-level-cache = <&A57_L2>; - clocks = <&scpi_dvfs 0>; + clocks = <&scmi_dvfs 0>; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; capacity-dmips-mhz = <1024>; }; @@ -113,7 +113,7 @@ d-cache-line-size = <64>; d-cache-sets = <256>; next-level-cache = <&A57_L2>; - clocks = <&scpi_dvfs 0>; + clocks = <&scmi_dvfs 0>; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; capacity-dmips-mhz = <1024>; }; @@ -130,7 +130,7 @@ d-cache-line-size = <64>; d-cache-sets = <128>; next-level-cache = <&A53_L2>; - clocks = <&scpi_dvfs 1>; + clocks = <&scmi_dvfs 1>; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; capacity-dmips-mhz = <578>; }; @@ -147,7 +147,7 @@ d-cache-line-size = <64>; d-cache-sets = <128>; next-level-cache = <&A53_L2>; - clocks = <&scpi_dvfs 1>; + clocks = <&scmi_dvfs 1>; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; capacity-dmips-mhz = <578>; }; @@ -164,7 +164,7 @@ d-cache-line-size = <64>; d-cache-sets = <128>; next-level-cache = <&A53_L2>; - clocks = <&scpi_dvfs 1>; + clocks = <&scmi_dvfs 1>; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; capacity-dmips-mhz = <578>; }; @@ -181,7 +181,7 @@ d-cache-line-size = <64>; d-cache-sets = <128>; next-level-cache = <&A53_L2>; - clocks = <&scpi_dvfs 1>; + clocks = <&scmi_dvfs 1>; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; capacity-dmips-mhz = <578>; }; diff --git a/arch/arm64/boot/dts/arm/juno-r2.dts b/arch/arm64/boot/dts/arm/juno-r2.dts index 64fe406c9aac..dab2e49befef 100644 --- a/arch/arm64/boot/dts/arm/juno-r2.dts +++ b/arch/arm64/boot/dts/arm/juno-r2.dts @@ -96,7 +96,7 @@ d-cache-line-size = <64>; d-cache-sets = <256>; next-level-cache = <&A72_L2>; - clocks = <&scpi_dvfs 0>; + clocks = <&scmi_dvfs 0>; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; capacity-dmips-mhz = <1024>; }; @@ -113,7 +113,7 @@ d-cache-line-size = <64>; d-cache-sets = <256>; next-level-cache = <&A72_L2>; - clocks = <&scpi_dvfs 0>; + clocks = <&scmi_dvfs 0>; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; capacity-dmips-mhz = <1024>; }; @@ -130,7 +130,7 @@ d-cache-line-size = <64>; d-cache-sets = <128>; next-level-cache = <&A53_L2>; - clocks = <&scpi_dvfs 1>; + clocks = <&scmi_dvfs 1>; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; capacity-dmips-mhz = <485>; }; @@ -147,7 +147,7 @@ d-cache-line-size = <64>; d-cache-sets = <128>; next-level-cache = <&A53_L2>; - clocks = <&scpi_dvfs 1>; + clocks = <&scmi_dvfs 1>; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; capacity-dmips-mhz = <485>; }; @@ -164,7 +164,7 @@ d-cache-line-size = <64>; d-cache-sets = <128>; next-level-cache = <&A53_L2>; - clocks = <&scpi_dvfs 1>; + clocks = <&scmi_dvfs 1>; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; capacity-dmips-mhz = <485>; }; @@ -181,7 +181,7 @@ d-cache-line-size = <64>; d-cache-sets = <128>; next-level-cache = <&A53_L2>; - clocks = <&scpi_dvfs 1>; + clocks = <&scmi_dvfs 1>; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; capacity-dmips-mhz = <485>; }; diff --git a/arch/arm64/boot/dts/arm/juno.dts b/arch/arm64/boot/dts/arm/juno.dts index 1eec71d8eaf4..1d05029687ff 100644 --- a/arch/arm64/boot/dts/arm/juno.dts +++ b/arch/arm64/boot/dts/arm/juno.dts @@ -95,7 +95,7 @@ d-cache-line-size = <64>; d-cache-sets = <256>; next-level-cache = <&A57_L2>; - clocks = <&scpi_dvfs 0>; + clocks = <&scmi_dvfs 0>; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; capacity-dmips-mhz = <1024>; }; @@ -112,7 +112,7 @@ d-cache-line-size = <64>; d-cache-sets = <256>; next-level-cache = <&A57_L2>; - clocks = <&scpi_dvfs 0>; + clocks = <&scmi_dvfs 0>; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; capacity-dmips-mhz = <1024>; }; @@ -129,7 +129,7 @@ d-cache-line-size = <64>; d-cache-sets = <128>; next-level-cache = <&A53_L2>; - clocks = <&scpi_dvfs 1>; + clocks = <&scmi_dvfs 1>; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; capacity-dmips-mhz = <578>; }; @@ -146,7 +146,7 @@ d-cache-line-size = <64>; d-cache-sets = <128>; next-level-cache = <&A53_L2>; - clocks = <&scpi_dvfs 1>; + clocks = <&scmi_dvfs 1>; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; capacity-dmips-mhz = <578>; }; @@ -163,7 +163,7 @@ d-cache-line-size = <64>; d-cache-sets = <128>; next-level-cache = <&A53_L2>; - clocks = <&scpi_dvfs 1>; + clocks = <&scmi_dvfs 1>; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; capacity-dmips-mhz = <578>; }; @@ -180,7 +180,7 @@ d-cache-line-size = <64>; d-cache-sets = <128>; next-level-cache = <&A53_L2>; - clocks = <&scpi_dvfs 1>; + clocks = <&scmi_dvfs 1>; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; capacity-dmips-mhz = <578>; }; diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index ecf613761e78..c259a2186307 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -104,15 +104,16 @@ CONFIG_CPU_FREQ=y CONFIG_CPU_FREQ_GOV_ATTR_SET=y CONFIG_CPU_FREQ_GOV_COMMON=y CONFIG_CPU_FREQ_STAT=y -CONFIG_CPU_FREQ_GOV_POWERSAVE=m +CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_CPU_FREQ_GOV_ONDEMAND=y -CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y CONFIG_CPUFREQ_DT=y CONFIG_ARM_ARMADA_37XX_CPUFREQ=y CONFIG_ARM_BIG_LITTLE_CPUFREQ=y CONFIG_ARM_SCPI_CPUFREQ=y +CONFIG_ARM_SCMI_CPUFREQ=y CONFIG_ARM_TEGRA186_CPUFREQ=y CONFIG_ACPI_CPPC_CPUFREQ=m CONFIG_NET=y @@ -337,6 +338,7 @@ CONFIG_POWER_RESET_XGENE=y CONFIG_POWER_RESET_SYSCON=y CONFIG_SYSCON_REBOOT_MODE=y CONFIG_BATTERY_BQ27XXX=y +CONFIG_SENSORS_ARM_SCMI=y CONFIG_SENSORS_ARM_SCPI=y CONFIG_SENSORS_LM90=m CONFIG_SENSORS_INA2XX=m @@ -533,6 +535,7 @@ CONFIG_VIRTIO_MMIO=y CONFIG_XEN_GNTDEV=y CONFIG_XEN_GRANT_DEV_ALLOC=y CONFIG_COMMON_CLK_RK808=y +CONFIG_COMMON_CLK_SCMI=y CONFIG_COMMON_CLK_SCPI=y CONFIG_COMMON_CLK_CS2000_CP=y CONFIG_COMMON_CLK_S2MPS11=y @@ -599,6 +602,7 @@ CONFIG_QCOM_QFPROM=y CONFIG_UNIPHIER_EFUSE=y CONFIG_TEE=y CONFIG_OPTEE=y +CONFIG_ARM_SCMI_PROTOCOL=y CONFIG_ARM_SCPI_PROTOCOL=y CONFIG_RASPBERRYPI_FIRMWARE=y CONFIG_EFI_CAPSULE_LOADER=y @@ -637,10 +641,16 @@ CONFIG_VIRTUALIZATION=y CONFIG_KVM=y CONFIG_PRINTK_TIME=y CONFIG_DEBUG_INFO=y +CONFIG_DYNAMIC_DEBUG=y CONFIG_DEBUG_FS=y CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_KERNEL=y CONFIG_LOCKUP_DETECTOR=y +CONFIG_SOFTLOCKUP_DETECTOR=y +CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y +CONFIG_BOOTPARAM_HUNG_TASK_PANIC=y +CONFIG_WQ_WATCHDOG=y +CONFIG_PANIC_ON_OOPS=y # CONFIG_SCHED_DEBUG is not set # CONFIG_DEBUG_PREEMPT is not set # CONFIG_FTRACE is not set diff --git a/drivers/mailbox/arm_mhu.c b/drivers/mailbox/arm_mhu.c index 99befa76e37c..4ed389d8f3dd 100644 --- a/drivers/mailbox/arm_mhu.c +++ b/drivers/mailbox/arm_mhu.c @@ -13,16 +13,16 @@ * GNU General Public License for more details. */ -#include <linux/interrupt.h> -#include <linux/spinlock.h> -#include <linux/mutex.h> -#include <linux/delay.h> -#include <linux/slab.h> +#include <linux/amba/bus.h> +#include <linux/device.h> #include <linux/err.h> +#include <linux/interrupt.h> #include <linux/io.h> -#include <linux/module.h> -#include <linux/amba/bus.h> +#include <linux/kernel.h> #include <linux/mailbox_controller.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> #define INTR_STAT_OFS 0x0 #define INTR_SET_OFS 0x8 @@ -33,7 +33,8 @@ #define MHU_SEC_OFFSET 0x200 #define TX_REG_OFFSET 0x100 -#define MHU_CHANS 3 +#define MHU_NUM_PCHANS 3 /* Secure, Non-Secure High and Low Priority */ +#define MHU_CHAN_MAX 20 /* Max channels to save on unused RAM */ struct mhu_link { unsigned irq; @@ -43,88 +44,341 @@ struct mhu_link { struct arm_mhu { void __iomem *base; - struct mhu_link mlink[MHU_CHANS]; - struct mbox_chan chan[MHU_CHANS]; + struct mhu_link mlink[MHU_NUM_PCHANS]; struct mbox_controller mbox; + struct device *dev; + const char *name; +}; + +/** + * ARM MHU Mailbox platform specific configuration + * + * @num_pchans: Maximum number of physical channels + * @num_doorbells: Maximum number of doorbells per physical channel + */ +struct mhu_mbox_pdata { + unsigned int num_pchans; + unsigned int num_doorbells; + bool support_doorbells; +}; + +/** + * ARM MHU Mailbox allocated channel information + * + * @mhu: Pointer to parent mailbox device + * @pchan: Physical channel within which this doorbell resides in + * @doorbell: doorbell number pertaining to this channel + */ +struct mhu_channel { + struct arm_mhu *mhu; + unsigned int pchan; + unsigned int doorbell; }; +static inline struct mbox_chan * +mhu_mbox_to_channel(struct mbox_controller *mbox, + unsigned int pchan, unsigned int doorbell) +{ + int i; + struct mhu_channel *chan_info; + + for (i = 0; i < mbox->num_chans; i++) { + chan_info = mbox->chans[i].con_priv; + if (chan_info && chan_info->pchan == pchan && + chan_info->doorbell == doorbell) + return &mbox->chans[i]; + } + + dev_err(mbox->dev, + "Channel not registered: physical channel: %d doorbell: %d\n", + pchan, doorbell); + + return NULL; +} + +static void mhu_mbox_clear_irq(struct mbox_chan *chan) +{ + struct mhu_channel *chan_info = chan->con_priv; + void __iomem *base = chan_info->mhu->mlink[chan_info->pchan].rx_reg; + + writel_relaxed(BIT(chan_info->doorbell), base + INTR_CLR_OFS); +} + +static unsigned int mhu_mbox_irq_to_pchan_num(struct arm_mhu *mhu, int irq) +{ + unsigned int pchan; + struct mhu_mbox_pdata *pdata = dev_get_platdata(mhu->dev); + + for (pchan = 0; pchan < pdata->num_pchans; pchan++) + if (mhu->mlink[pchan].irq == irq) + break; + return pchan; +} + +static struct mbox_chan *mhu_mbox_irq_to_channel(struct arm_mhu *mhu, + unsigned int pchan) +{ + unsigned long bits; + unsigned int doorbell; + struct mbox_chan *chan = NULL; + struct mbox_controller *mbox = &mhu->mbox; + void __iomem *base = mhu->mlink[pchan].rx_reg; + + bits = readl_relaxed(base + INTR_STAT_OFS); + if (!bits) + /* No IRQs fired in specified physical channel */ + return NULL; + + /* An IRQ has fired, find the associated channel */ + for (doorbell = 0; bits; doorbell++) { + if (!test_and_clear_bit(doorbell, &bits)) + continue; + + chan = mhu_mbox_to_channel(mbox, pchan, doorbell); + if (chan) + break; + } + + return chan; +} + +static irqreturn_t mhu_mbox_thread_handler(int irq, void *data) +{ + struct mbox_chan *chan; + struct arm_mhu *mhu = data; + unsigned int pchan = mhu_mbox_irq_to_pchan_num(mhu, irq); + + while (NULL != (chan = mhu_mbox_irq_to_channel(mhu, pchan))) { + mbox_chan_received_data(chan, NULL); + mhu_mbox_clear_irq(chan); + } + + return IRQ_HANDLED; +} + +static bool mhu_doorbell_last_tx_done(struct mbox_chan *chan) +{ + struct mhu_channel *chan_info = chan->con_priv; + void __iomem *base = chan_info->mhu->mlink[chan_info->pchan].tx_reg; + + if (readl_relaxed(base + INTR_STAT_OFS) & BIT(chan_info->doorbell)) + return false; + + return true; +} + +static int mhu_doorbell_send_data(struct mbox_chan *chan, void *data) +{ + struct mhu_channel *chan_info = chan->con_priv; + void __iomem *base = chan_info->mhu->mlink[chan_info->pchan].tx_reg; + + /* Send event to co-processor */ + writel_relaxed(BIT(chan_info->doorbell), base + INTR_SET_OFS); + + return 0; +} + +static int mhu_doorbell_startup(struct mbox_chan *chan) +{ + mhu_mbox_clear_irq(chan); + return 0; +} + +static void mhu_doorbell_shutdown(struct mbox_chan *chan) +{ + struct mhu_channel *chan_info = chan->con_priv; + struct mbox_controller *mbox = &chan_info->mhu->mbox; + int i; + + for (i = 0; i < mbox->num_chans; i++) + if (chan == &mbox->chans[i]) + break; + + if (mbox->num_chans == i) { + dev_warn(mbox->dev, "Request to free non-existent channel\n"); + return; + } + + /* Reset channel */ + mhu_mbox_clear_irq(chan); + chan->con_priv = NULL; +} + +static struct mbox_chan *mhu_mbox_xlate(struct mbox_controller *mbox, + const struct of_phandle_args *spec) +{ + struct arm_mhu *mhu = dev_get_drvdata(mbox->dev); + struct mhu_mbox_pdata *pdata = dev_get_platdata(mhu->dev); + struct mhu_channel *chan_info; + struct mbox_chan *chan = NULL; + unsigned int pchan = spec->args[0]; + unsigned int doorbell = pdata->support_doorbells ? spec->args[1] : 0; + int i; + + /* Bounds checking */ + if (pchan >= pdata->num_pchans || doorbell >= pdata->num_doorbells) { + dev_err(mbox->dev, + "Invalid channel requested pchan: %d doorbell: %d\n", + pchan, doorbell); + return ERR_PTR(-EINVAL); + } + + for (i = 0; i < mbox->num_chans; i++) { + chan_info = mbox->chans[i].con_priv; + + /* Is requested channel free? */ + if (chan_info && + mbox->dev == chan_info->mhu->dev && + pchan == chan_info->pchan && + doorbell == chan_info->doorbell) { + dev_err(mbox->dev, "Channel in use\n"); + return ERR_PTR(-EBUSY); + } + + /* + * Find the first free slot, then continue checking + * to see if requested channel is in use + */ + if (!chan && !chan_info) + chan = &mbox->chans[i]; + } + + if (!chan) { + dev_err(mbox->dev, "No free channels left\n"); + return ERR_PTR(-EBUSY); + } + + chan_info = devm_kzalloc(mbox->dev, sizeof(*chan_info), GFP_KERNEL); + if (!chan_info) + return ERR_PTR(-ENOMEM); + + chan_info->mhu = mhu; + chan_info->pchan = pchan; + chan_info->doorbell = doorbell; + + chan->con_priv = chan_info; + + dev_dbg(mbox->dev, "mbox: %s, created channel phys: %d doorbell: %d\n", + mhu->name, pchan, doorbell); + + return chan; +} + static irqreturn_t mhu_rx_interrupt(int irq, void *p) { - struct mbox_chan *chan = p; - struct mhu_link *mlink = chan->con_priv; + struct arm_mhu *mhu = p; + unsigned int pchan = mhu_mbox_irq_to_pchan_num(mhu, irq); + struct mbox_chan *chan = mhu_mbox_to_channel(&mhu->mbox, pchan, 0); + void __iomem *base = mhu->mlink[pchan].rx_reg; u32 val; - val = readl_relaxed(mlink->rx_reg + INTR_STAT_OFS); + val = readl_relaxed(base + INTR_STAT_OFS); if (!val) return IRQ_NONE; mbox_chan_received_data(chan, (void *)&val); - writel_relaxed(val, mlink->rx_reg + INTR_CLR_OFS); + writel_relaxed(val, base + INTR_CLR_OFS); return IRQ_HANDLED; } static bool mhu_last_tx_done(struct mbox_chan *chan) { - struct mhu_link *mlink = chan->con_priv; - u32 val = readl_relaxed(mlink->tx_reg + INTR_STAT_OFS); + struct mhu_channel *chan_info = chan->con_priv; + void __iomem *base = chan_info->mhu->mlink[chan_info->pchan].tx_reg; + u32 val = readl_relaxed(base + INTR_STAT_OFS); return (val == 0); } static int mhu_send_data(struct mbox_chan *chan, void *data) { - struct mhu_link *mlink = chan->con_priv; + struct mhu_channel *chan_info = chan->con_priv; + void __iomem *base = chan_info->mhu->mlink[chan_info->pchan].tx_reg; u32 *arg = data; - writel_relaxed(*arg, mlink->tx_reg + INTR_SET_OFS); + writel_relaxed(*arg, base + INTR_SET_OFS); return 0; } static int mhu_startup(struct mbox_chan *chan) { - struct mhu_link *mlink = chan->con_priv; + struct mhu_channel *chan_info = chan->con_priv; + void __iomem *base = chan_info->mhu->mlink[chan_info->pchan].tx_reg; u32 val; - int ret; - - val = readl_relaxed(mlink->tx_reg + INTR_STAT_OFS); - writel_relaxed(val, mlink->tx_reg + INTR_CLR_OFS); - ret = request_irq(mlink->irq, mhu_rx_interrupt, - IRQF_SHARED, "mhu_link", chan); - if (ret) { - dev_err(chan->mbox->dev, - "Unable to acquire IRQ %d\n", mlink->irq); - return ret; - } + val = readl_relaxed(base + INTR_STAT_OFS); + writel_relaxed(val, base + INTR_CLR_OFS); return 0; } -static void mhu_shutdown(struct mbox_chan *chan) -{ - struct mhu_link *mlink = chan->con_priv; - - free_irq(mlink->irq, chan); -} - static const struct mbox_chan_ops mhu_ops = { .send_data = mhu_send_data, .startup = mhu_startup, - .shutdown = mhu_shutdown, .last_tx_done = mhu_last_tx_done, }; +static const struct mbox_chan_ops mhu_doorbell_ops = { + .send_data = mhu_doorbell_send_data, + .startup = mhu_doorbell_startup, + .shutdown = mhu_doorbell_shutdown, + .last_tx_done = mhu_doorbell_last_tx_done, +}; + +static const struct mhu_mbox_pdata arm_mhu_pdata = { + .num_pchans = 3, + .num_doorbells = 1, + .support_doorbells = false, +}; + +static const struct mhu_mbox_pdata arm_mhu_doorbell_pdata = { + .num_pchans = 2, /* Secure can't be used */ + .num_doorbells = 32, + .support_doorbells = true, +}; + static int mhu_probe(struct amba_device *adev, const struct amba_id *id) { - int i, err; + u32 cell_count; + int i, err, max_chans; + irq_handler_t handler; struct arm_mhu *mhu; + struct mbox_chan *chans; + struct mhu_mbox_pdata *pdata; struct device *dev = &adev->dev; - int mhu_reg[MHU_CHANS] = {MHU_LP_OFFSET, MHU_HP_OFFSET, MHU_SEC_OFFSET}; + struct device_node *np = dev->of_node; + int mhu_reg[MHU_NUM_PCHANS] = { + MHU_LP_OFFSET, MHU_HP_OFFSET, MHU_SEC_OFFSET, + }; + + err = of_property_read_u32(np, "#mbox-cells", &cell_count); + if (err) { + dev_err(dev, "failed to read #mbox-cells in %s\n", + np->full_name); + return err; + } + + if (cell_count == 1) { + max_chans = MHU_NUM_PCHANS; + pdata = (struct mhu_mbox_pdata *)&arm_mhu_pdata; + } else if (cell_count == 2) { + max_chans = MHU_CHAN_MAX; + pdata = (struct mhu_mbox_pdata *)&arm_mhu_doorbell_pdata; + } else { + dev_err(dev, "incorrect value of #mbox-cells in %s\n", + np->full_name); + return -EINVAL; + } + + if (pdata->num_pchans > MHU_NUM_PCHANS) { + dev_err(dev, "Number of physical channel can't exceed %d\n", + MHU_NUM_PCHANS); + return -EINVAL; + } - /* Allocate memory for device */ mhu = devm_kzalloc(dev, sizeof(*mhu), GFP_KERNEL); if (!mhu) return -ENOMEM; @@ -135,30 +389,62 @@ static int mhu_probe(struct amba_device *adev, const struct amba_id *id) return PTR_ERR(mhu->base); } - for (i = 0; i < MHU_CHANS; i++) { - mhu->chan[i].con_priv = &mhu->mlink[i]; - mhu->mlink[i].irq = adev->irq[i]; - mhu->mlink[i].rx_reg = mhu->base + mhu_reg[i]; - mhu->mlink[i].tx_reg = mhu->mlink[i].rx_reg + TX_REG_OFFSET; - } + err = of_property_read_string(np, "mbox-name", &mhu->name); + if (err) + mhu->name = np->full_name; + + chans = devm_kcalloc(dev, max_chans, sizeof(*chans), GFP_KERNEL); + if (!chans) + return -ENOMEM; + + dev->platform_data = pdata; + mhu->dev = dev; mhu->mbox.dev = dev; - mhu->mbox.chans = &mhu->chan[0]; - mhu->mbox.num_chans = MHU_CHANS; - mhu->mbox.ops = &mhu_ops; + mhu->mbox.chans = chans; + mhu->mbox.num_chans = max_chans; mhu->mbox.txdone_irq = false; mhu->mbox.txdone_poll = true; mhu->mbox.txpoll_period = 1; + mhu->mbox.of_xlate = mhu_mbox_xlate; amba_set_drvdata(adev, mhu); + if (pdata->support_doorbells) { + mhu->mbox.ops = &mhu_doorbell_ops; + handler = mhu_mbox_thread_handler; + } else { + mhu->mbox.ops = &mhu_ops; + handler = mhu_rx_interrupt; + } + err = mbox_controller_register(&mhu->mbox); if (err) { dev_err(dev, "Failed to register mailboxes %d\n", err); return err; } - dev_info(dev, "ARM MHU Mailbox registered\n"); + for (i = 0; i < pdata->num_pchans; i++) { + int irq = mhu->mlink[i].irq = adev->irq[i]; + + if (irq <= 0) { + dev_dbg(dev, "No IRQ found for Channel %d\n", i); + continue; + } + + mhu->mlink[i].rx_reg = mhu->base + mhu_reg[i]; + mhu->mlink[i].tx_reg = mhu->mlink[i].rx_reg + TX_REG_OFFSET; + + err = devm_request_threaded_irq(dev, irq, NULL, handler, + IRQF_ONESHOT, "mhu_link", mhu); + if (err) { + dev_err(dev, "Can't claim IRQ %d\n", irq); + mbox_controller_unregister(&mhu->mbox); + return err; + } + } + + dev_info(dev, "%s mailbox registered\n", mhu->name); return 0; } diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c index 674b35f402f5..495b4574b954 100644 --- a/drivers/mailbox/mailbox.c +++ b/drivers/mailbox/mailbox.c @@ -77,7 +77,10 @@ static void msg_submit(struct mbox_chan *chan) if (chan->cl->tx_prepare) chan->cl->tx_prepare(chan->cl, data); /* Try to submit a message to the MBOX controller */ - err = chan->mbox->ops->send_data(chan, data); + if (chan->mbox->ops->send_data) + err = chan->mbox->ops->send_data(chan, data); + else + err = chan->mbox->ops->send_signal(chan); if (!err) { chan->active_req = data; chan->msg_count--; @@ -451,6 +454,12 @@ int mbox_controller_register(struct mbox_controller *mbox) /* Sanity check */ if (!mbox || !mbox->dev || !mbox->ops || !mbox->num_chans) return -EINVAL; + /* + * A controller can support either doorbell mode or normal message + * transmission mode but not both + */ + if (mbox->ops->send_data && mbox->ops->send_signal) + return -EINVAL; if (mbox->txdone_irq) txdone = TXDONE_BY_IRQ; diff --git a/include/linux/mailbox_controller.h b/include/linux/mailbox_controller.h index 74deadb42d76..bdbc5b74097e 100644 --- a/include/linux/mailbox_controller.h +++ b/include/linux/mailbox_controller.h @@ -24,6 +24,16 @@ struct mbox_chan; * transmission of data is reported by the controller via * mbox_chan_txdone (if it has some TX ACK irq). It must not * sleep. + * @send_signal: The API asks the MBOX controller driver, in atomic + * context try to transmit a signal on the bus. Returns 0 if + * data is accepted for transmission, -EBUSY while rejecting + * if the remote hasn't yet absorbed the last signal sent. Actual + * transmission of data must be handled by the client and is + * reported by the controller via mbox_chan_txdone (if it has + * some TX ACK irq). It must not sleep. Unlike send_data, + * send_signal doesn't handle any messages/data. It just sends + * notification signal(doorbell) and client needs to prepare all + * the data. * @startup: Called when a client requests the chan. The controller * could ask clients for additional parameters of communication * to be provided via client's chan_data. This call may @@ -46,6 +56,7 @@ struct mbox_chan; */ struct mbox_chan_ops { int (*send_data)(struct mbox_chan *chan, void *data); + int (*send_signal)(struct mbox_chan *chan); int (*startup)(struct mbox_chan *chan); void (*shutdown)(struct mbox_chan *chan); bool (*last_tx_done)(struct mbox_chan *chan); diff --git a/linaro/configs/vexpress64.conf b/linaro/configs/vexpress64.conf index 4d766c762acc..53362364d369 100644 --- a/linaro/configs/vexpress64.conf +++ b/linaro/configs/vexpress64.conf @@ -48,19 +48,22 @@ CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_HCD_PLATFORM=y CONFIG_NOP_USB_XCEIV=y CONFIG_USB_OHCI_HCD=y +CONFIG_PM_OPP=y CONFIG_MAILBOX=y CONFIG_ARM_MHU=y -CONFIG_ARM_SCPI_PROTOCOL=y -CONFIG_SENSORS_ARM_SCPI=y -CONFIG_COMMON_CLK_SCPI=y -CONFIG_ARM_SCPI_CPUFREQ=y +CONFIG_PLATFORM_MHU=y +CONFIG_ARM_SCMI_PROTOCOL=y +CONFIG_SENSORS_ARM_SCMI=y +CONFIG_COMMON_CLK_SCMI=y +CONFIG_ARM_SCMI_CPUFREQ=y CONFIG_ARM_BIG_LITTLE_CPUFREQ=y -CONFIG_ARM_DT_BL_CPUFREQ=y +CONFIG_CPU_FREQ_STAT=y CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_CPU_FREQ_GOV_ONDEMAND=y -CONFIG_CPU_FREQ_GOV_INTERACTIVE=y -CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y CONFIG_PCI=y CONFIG_PCI_MSI=y CONFIG_PCI_REALLOC_ENABLE_AUTO=y |