From e5e57daaaa2b80799246fc8636eb00d8a32802fe Mon Sep 17 00:00:00 2001 From: Liviu Dudau Date: Thu, 30 Apr 2015 16:45:57 +0100 Subject: arm64: Juno: Fix the GIC node address label and the frequency of FAXI clock. During the review of the Juno DT files I've noticed that the GIC node label had two digits swapped leading to a different address being shown in the /sys/devices fs. Sudeep also pointed that public revisions of the Juno documentation list a different frequency for the FAXI system than what the one I've been using when creating the DT file. Verified with the firmware people to be the correct value in the shipped systems. Reported-by: Sudeep Holla Signed-off-by: Liviu Dudau Acked-by: Sudeep Holla Acked-by: Jon Medhurst (cherry picked from commit 18c0b015305edd97c2b31e0ce7211a960d08f62f) Signed-off-by: Jon Medhurst --- arch/arm64/boot/dts/arm/juno-clocks.dtsi | 4 ++-- arch/arm64/boot/dts/arm/juno.dts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/arm/juno-clocks.dtsi b/arch/arm64/boot/dts/arm/juno-clocks.dtsi index c9b89efe0f56..25352ed943e6 100644 --- a/arch/arm64/boot/dts/arm/juno-clocks.dtsi +++ b/arch/arm64/boot/dts/arm/juno-clocks.dtsi @@ -36,9 +36,9 @@ clock-output-names = "apb_pclk"; }; - soc_faxiclk: refclk533mhz { + soc_faxiclk: refclk400mhz { compatible = "fixed-clock"; #clock-cells = <0>; - clock-frequency = <533000000>; + clock-frequency = <400000000>; clock-output-names = "faxi_clk"; }; diff --git a/arch/arm64/boot/dts/arm/juno.dts b/arch/arm64/boot/dts/arm/juno.dts index 5e9110a3353d..7ab071320ff1 100644 --- a/arch/arm64/boot/dts/arm/juno.dts +++ b/arch/arm64/boot/dts/arm/juno.dts @@ -98,7 +98,7 @@ <0x00000008 0x80000000 0x1 0x80000000>; }; - gic: interrupt-controller@2c001000 { + gic: interrupt-controller@2c010000 { compatible = "arm,gic-400", "arm,cortex-a15-gic"; reg = <0x0 0x2c010000 0 0x1000>, <0x0 0x2c02f000 0 0x2000>, -- cgit v1.2.3 From 50681ab1716c5f45c947292f238f831bd4333c9b Mon Sep 17 00:00:00 2001 From: Liviu Dudau Date: Tue, 10 Mar 2015 15:18:18 +0000 Subject: arm64: Juno: Split juno.dts into juno-base.dtsi and juno.dts. Prepare the device tree for adding more boards based on Juno r0. Signed-off-by: Liviu Dudau Acked-by: Jon Medhurst Acked-by: Sudeep Holla (cherry picked from commit e802087437c120b2bf0f213aba5c88c175d7019c) Signed-off-by: Jon Medhurst --- arch/arm64/boot/dts/arm/juno-base.dtsi | 132 +++++++++++++++++++++++++++++++++ arch/arm64/boot/dts/arm/juno.dts | 129 +------------------------------- 2 files changed, 133 insertions(+), 128 deletions(-) create mode 100644 arch/arm64/boot/dts/arm/juno-base.dtsi diff --git a/arch/arm64/boot/dts/arm/juno-base.dtsi b/arch/arm64/boot/dts/arm/juno-base.dtsi new file mode 100644 index 000000000000..5c4c035f8429 --- /dev/null +++ b/arch/arm64/boot/dts/arm/juno-base.dtsi @@ -0,0 +1,132 @@ + /* + * Devices shared by all Juno boards + */ + + gic: interrupt-controller@2c010000 { + compatible = "arm,gic-400", "arm,cortex-a15-gic"; + reg = <0x0 0x2c010000 0 0x1000>, + <0x0 0x2c02f000 0 0x2000>, + <0x0 0x2c04f000 0 0x2000>, + <0x0 0x2c06f000 0 0x2000>; + #address-cells = <0>; + #interrupt-cells = <3>; + interrupt-controller; + interrupts = ; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = , + , + , + ; + }; + + /include/ "juno-clocks.dtsi" + + dma@7ff00000 { + compatible = "arm,pl330", "arm,primecell"; + reg = <0x0 0x7ff00000 0 0x1000>; + #dma-cells = <1>; + #dma-channels = <8>; + #dma-requests = <32>; + interrupts = , + , + , + , + , + , + , + ; + clocks = <&soc_faxiclk>; + clock-names = "apb_pclk"; + }; + + soc_uart0: uart@7ff80000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x0 0x7ff80000 0x0 0x1000>; + interrupts = ; + clocks = <&soc_uartclk>, <&soc_refclk100mhz>; + clock-names = "uartclk", "apb_pclk"; + }; + + i2c@7ffa0000 { + compatible = "snps,designware-i2c"; + reg = <0x0 0x7ffa0000 0x0 0x1000>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = ; + clock-frequency = <400000>; + i2c-sda-hold-time-ns = <500>; + clocks = <&soc_smc50mhz>; + + dvi0: dvi-transmitter@70 { + compatible = "nxp,tda998x"; + reg = <0x70>; + }; + + dvi1: dvi-transmitter@71 { + compatible = "nxp,tda998x"; + reg = <0x71>; + }; + }; + + ohci@7ffb0000 { + compatible = "generic-ohci"; + reg = <0x0 0x7ffb0000 0x0 0x10000>; + interrupts = ; + clocks = <&soc_usb48mhz>; + }; + + ehci@7ffc0000 { + compatible = "generic-ehci"; + reg = <0x0 0x7ffc0000 0x0 0x10000>; + interrupts = ; + clocks = <&soc_usb48mhz>; + }; + + memory-controller@7ffd0000 { + compatible = "arm,pl354", "arm,primecell"; + reg = <0 0x7ffd0000 0 0x1000>; + interrupts = , + ; + clocks = <&soc_smc50mhz>; + clock-names = "apb_pclk"; + }; + + memory@80000000 { + device_type = "memory"; + /* last 16MB of the first memory area is reserved for secure world use by firmware */ + reg = <0x00000000 0x80000000 0x0 0x7f000000>, + <0x00000008 0x80000000 0x1 0x80000000>; + }; + + smb { + compatible = "simple-bus"; + #address-cells = <2>; + #size-cells = <1>; + ranges = <0 0 0 0x08000000 0x04000000>, + <1 0 0 0x14000000 0x04000000>, + <2 0 0 0x18000000 0x04000000>, + <3 0 0 0x1c000000 0x04000000>, + <4 0 0 0x0c000000 0x04000000>, + <5 0 0 0x10000000 0x04000000>; + + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 15>; + interrupt-map = <0 0 0 &gic 0 68 IRQ_TYPE_LEVEL_HIGH>, + <0 0 1 &gic 0 69 IRQ_TYPE_LEVEL_HIGH>, + <0 0 2 &gic 0 70 IRQ_TYPE_LEVEL_HIGH>, + <0 0 3 &gic 0 160 IRQ_TYPE_LEVEL_HIGH>, + <0 0 4 &gic 0 161 IRQ_TYPE_LEVEL_HIGH>, + <0 0 5 &gic 0 162 IRQ_TYPE_LEVEL_HIGH>, + <0 0 6 &gic 0 163 IRQ_TYPE_LEVEL_HIGH>, + <0 0 7 &gic 0 164 IRQ_TYPE_LEVEL_HIGH>, + <0 0 8 &gic 0 165 IRQ_TYPE_LEVEL_HIGH>, + <0 0 9 &gic 0 166 IRQ_TYPE_LEVEL_HIGH>, + <0 0 10 &gic 0 167 IRQ_TYPE_LEVEL_HIGH>, + <0 0 11 &gic 0 168 IRQ_TYPE_LEVEL_HIGH>, + <0 0 12 &gic 0 169 IRQ_TYPE_LEVEL_HIGH>; + + /include/ "juno-motherboard.dtsi" + }; diff --git a/arch/arm64/boot/dts/arm/juno.dts b/arch/arm64/boot/dts/arm/juno.dts index 7ab071320ff1..d7cbdd482a61 100644 --- a/arch/arm64/boot/dts/arm/juno.dts +++ b/arch/arm64/boot/dts/arm/juno.dts @@ -91,33 +91,6 @@ }; }; - memory@80000000 { - device_type = "memory"; - /* last 16MB of the first memory area is reserved for secure world use by firmware */ - reg = <0x00000000 0x80000000 0x0 0x7f000000>, - <0x00000008 0x80000000 0x1 0x80000000>; - }; - - gic: interrupt-controller@2c010000 { - compatible = "arm,gic-400", "arm,cortex-a15-gic"; - reg = <0x0 0x2c010000 0 0x1000>, - <0x0 0x2c02f000 0 0x2000>, - <0x0 0x2c04f000 0 0x2000>, - <0x0 0x2c06f000 0 0x2000>; - #address-cells = <0>; - #interrupt-cells = <3>; - interrupt-controller; - interrupts = ; - }; - - timer { - compatible = "arm,armv8-timer"; - interrupts = , - , - , - ; - }; - pmu { compatible = "arm,armv8-pmuv3"; interrupts = , @@ -134,105 +107,5 @@ <&A53_3>; }; - /include/ "juno-clocks.dtsi" - - dma@7ff00000 { - compatible = "arm,pl330", "arm,primecell"; - reg = <0x0 0x7ff00000 0 0x1000>; - #dma-cells = <1>; - #dma-channels = <8>; - #dma-requests = <32>; - interrupts = , - , - , - , - , - , - , - ; - clocks = <&soc_faxiclk>; - clock-names = "apb_pclk"; - }; - - soc_uart0: uart@7ff80000 { - compatible = "arm,pl011", "arm,primecell"; - reg = <0x0 0x7ff80000 0x0 0x1000>; - interrupts = ; - clocks = <&soc_uartclk>, <&soc_refclk100mhz>; - clock-names = "uartclk", "apb_pclk"; - }; - - i2c@7ffa0000 { - compatible = "snps,designware-i2c"; - reg = <0x0 0x7ffa0000 0x0 0x1000>; - #address-cells = <1>; - #size-cells = <0>; - interrupts = ; - clock-frequency = <400000>; - i2c-sda-hold-time-ns = <500>; - clocks = <&soc_smc50mhz>; - - dvi0: dvi-transmitter@70 { - compatible = "nxp,tda998x"; - reg = <0x70>; - }; - - dvi1: dvi-transmitter@71 { - compatible = "nxp,tda998x"; - reg = <0x71>; - }; - }; - - ohci@7ffb0000 { - compatible = "generic-ohci"; - reg = <0x0 0x7ffb0000 0x0 0x10000>; - interrupts = ; - clocks = <&soc_usb48mhz>; - }; - - ehci@7ffc0000 { - compatible = "generic-ehci"; - reg = <0x0 0x7ffc0000 0x0 0x10000>; - interrupts = ; - clocks = <&soc_usb48mhz>; - }; - - memory-controller@7ffd0000 { - compatible = "arm,pl354", "arm,primecell"; - reg = <0 0x7ffd0000 0 0x1000>; - interrupts = , - ; - clocks = <&soc_smc50mhz>; - clock-names = "apb_pclk"; - }; - - smb { - compatible = "simple-bus"; - #address-cells = <2>; - #size-cells = <1>; - ranges = <0 0 0 0x08000000 0x04000000>, - <1 0 0 0x14000000 0x04000000>, - <2 0 0 0x18000000 0x04000000>, - <3 0 0 0x1c000000 0x04000000>, - <4 0 0 0x0c000000 0x04000000>, - <5 0 0 0x10000000 0x04000000>; - - #interrupt-cells = <1>; - interrupt-map-mask = <0 0 15>; - interrupt-map = <0 0 0 &gic 0 68 IRQ_TYPE_LEVEL_HIGH>, - <0 0 1 &gic 0 69 IRQ_TYPE_LEVEL_HIGH>, - <0 0 2 &gic 0 70 IRQ_TYPE_LEVEL_HIGH>, - <0 0 3 &gic 0 160 IRQ_TYPE_LEVEL_HIGH>, - <0 0 4 &gic 0 161 IRQ_TYPE_LEVEL_HIGH>, - <0 0 5 &gic 0 162 IRQ_TYPE_LEVEL_HIGH>, - <0 0 6 &gic 0 163 IRQ_TYPE_LEVEL_HIGH>, - <0 0 7 &gic 0 164 IRQ_TYPE_LEVEL_HIGH>, - <0 0 8 &gic 0 165 IRQ_TYPE_LEVEL_HIGH>, - <0 0 9 &gic 0 166 IRQ_TYPE_LEVEL_HIGH>, - <0 0 10 &gic 0 167 IRQ_TYPE_LEVEL_HIGH>, - <0 0 11 &gic 0 168 IRQ_TYPE_LEVEL_HIGH>, - <0 0 12 &gic 0 169 IRQ_TYPE_LEVEL_HIGH>; - - /include/ "juno-motherboard.dtsi" - }; + #include "juno-base.dtsi" }; -- cgit v1.2.3 From 1265cd1d0bad2a3df18c61bf3093a15a670bc2be Mon Sep 17 00:00:00 2001 From: Liviu Dudau Date: Tue, 10 Mar 2015 15:21:23 +0000 Subject: arm64: Juno: Add memory mapped timer node Juno based boards have a memory mapped timer @ 0x2a810000. This is disabled on r0 version of the board due to an SoC errata. Signed-off-by: Liviu Dudau Acked-by: Jon Medhurst Acked-by: Sudeep Holla (cherry picked from commit 7950235568dad46683e14aa36678366b43e56fac) Signed-off-by: Jon Medhurst --- arch/arm64/boot/dts/arm/juno-base.dtsi | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/arm64/boot/dts/arm/juno-base.dtsi b/arch/arm64/boot/dts/arm/juno-base.dtsi index 5c4c035f8429..b7e862f1c04c 100644 --- a/arch/arm64/boot/dts/arm/juno-base.dtsi +++ b/arch/arm64/boot/dts/arm/juno-base.dtsi @@ -2,6 +2,21 @@ * Devices shared by all Juno boards */ + memtimer: timer@2a810000 { + compatible = "arm,armv7-timer-mem"; + reg = <0x0 0x2a810000 0x0 0x10000>; + clock-frequency = <50000000>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + status = "disabled"; + frame@2a830000 { + frame-number = <1>; + interrupts = <0 60 4>; + reg = <0x0 0x2a830000 0x0 0x10000>; + }; + }; + gic: interrupt-controller@2c010000 { compatible = "arm,gic-400", "arm,cortex-a15-gic"; reg = <0x0 0x2c010000 0 0x1000>, -- cgit v1.2.3 From 9ff8229d98dc731b3a4d833dedb011320cab14e5 Mon Sep 17 00:00:00 2001 From: Liviu Dudau Date: Thu, 26 Mar 2015 12:16:31 +0000 Subject: arm64: Juno: Add GICv2m support in device tree. Juno contains a GICv2m extension for handling PCIe MSI messages. Add a node declaring the first frame of the extension. Signed-off-by: Liviu Dudau Acked-by: Jon Medhurst Acked-by: Sudeep Holla (cherry picked from commit 9e6f374f99a0c83c6f58cb6f6356645ef8591d1e) Signed-off-by: Jon Medhurst --- arch/arm64/boot/dts/arm/juno-base.dtsi | 35 ++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/arch/arm64/boot/dts/arm/juno-base.dtsi b/arch/arm64/boot/dts/arm/juno-base.dtsi index b7e862f1c04c..e3ee96036eca 100644 --- a/arch/arm64/boot/dts/arm/juno-base.dtsi +++ b/arch/arm64/boot/dts/arm/juno-base.dtsi @@ -23,10 +23,17 @@ <0x0 0x2c02f000 0 0x2000>, <0x0 0x2c04f000 0 0x2000>, <0x0 0x2c06f000 0 0x2000>; - #address-cells = <0>; + #address-cells = <2>; #interrupt-cells = <3>; + #size-cells = <2>; interrupt-controller; interrupts = ; + ranges = <0 0 0 0x2c1c0000 0 0x40000>; + v2m_0: v2m@0 { + compatible = "arm,gic-v2m-frame"; + msi-controller; + reg = <0 0 0 0x1000>; + }; }; timer { @@ -129,19 +136,19 @@ #interrupt-cells = <1>; interrupt-map-mask = <0 0 15>; - interrupt-map = <0 0 0 &gic 0 68 IRQ_TYPE_LEVEL_HIGH>, - <0 0 1 &gic 0 69 IRQ_TYPE_LEVEL_HIGH>, - <0 0 2 &gic 0 70 IRQ_TYPE_LEVEL_HIGH>, - <0 0 3 &gic 0 160 IRQ_TYPE_LEVEL_HIGH>, - <0 0 4 &gic 0 161 IRQ_TYPE_LEVEL_HIGH>, - <0 0 5 &gic 0 162 IRQ_TYPE_LEVEL_HIGH>, - <0 0 6 &gic 0 163 IRQ_TYPE_LEVEL_HIGH>, - <0 0 7 &gic 0 164 IRQ_TYPE_LEVEL_HIGH>, - <0 0 8 &gic 0 165 IRQ_TYPE_LEVEL_HIGH>, - <0 0 9 &gic 0 166 IRQ_TYPE_LEVEL_HIGH>, - <0 0 10 &gic 0 167 IRQ_TYPE_LEVEL_HIGH>, - <0 0 11 &gic 0 168 IRQ_TYPE_LEVEL_HIGH>, - <0 0 12 &gic 0 169 IRQ_TYPE_LEVEL_HIGH>; + interrupt-map = <0 0 0 &gic 0 0 0 68 IRQ_TYPE_LEVEL_HIGH>, + <0 0 1 &gic 0 0 0 69 IRQ_TYPE_LEVEL_HIGH>, + <0 0 2 &gic 0 0 0 70 IRQ_TYPE_LEVEL_HIGH>, + <0 0 3 &gic 0 0 0 160 IRQ_TYPE_LEVEL_HIGH>, + <0 0 4 &gic 0 0 0 161 IRQ_TYPE_LEVEL_HIGH>, + <0 0 5 &gic 0 0 0 162 IRQ_TYPE_LEVEL_HIGH>, + <0 0 6 &gic 0 0 0 163 IRQ_TYPE_LEVEL_HIGH>, + <0 0 7 &gic 0 0 0 164 IRQ_TYPE_LEVEL_HIGH>, + <0 0 8 &gic 0 0 0 165 IRQ_TYPE_LEVEL_HIGH>, + <0 0 9 &gic 0 0 0 166 IRQ_TYPE_LEVEL_HIGH>, + <0 0 10 &gic 0 0 0 167 IRQ_TYPE_LEVEL_HIGH>, + <0 0 11 &gic 0 0 0 168 IRQ_TYPE_LEVEL_HIGH>, + <0 0 12 &gic 0 0 0 169 IRQ_TYPE_LEVEL_HIGH>; /include/ "juno-motherboard.dtsi" }; -- cgit v1.2.3 From 67e9ac2f728859d4ee4dce9c7a60ea21d260842f Mon Sep 17 00:00:00 2001 From: Liviu Dudau Date: Tue, 10 Mar 2015 15:31:37 +0000 Subject: arm64: Add DT support for Juno r1 board. This board is based on Juno r0 with updated Cortex A5x revisions and board errata fixes. It also contains coherent ThinLinks ports on the expansion slot that allow for an AXI master on the daughter card to participate in a coherency domain. Support for SoC PCIe host bridge will be added as a separate series. Signed-off-by: Liviu Dudau Acked-by: Jon Medhurst Acked-by: Sudeep Holla (cherry picked from commit 796c2b35a4105aa02c6a7af6de659086363d47f7) Signed-off-by: Jon Medhurst --- arch/arm64/boot/dts/arm/Makefile | 2 +- arch/arm64/boot/dts/arm/juno-r1.dts | 116 ++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 arch/arm64/boot/dts/arm/juno-r1.dts diff --git a/arch/arm64/boot/dts/arm/Makefile b/arch/arm64/boot/dts/arm/Makefile index 301a0dada1fe..c5c98b91514e 100644 --- a/arch/arm64/boot/dts/arm/Makefile +++ b/arch/arm64/boot/dts/arm/Makefile @@ -1,5 +1,5 @@ dtb-$(CONFIG_ARCH_VEXPRESS) += foundation-v8.dtb -dtb-$(CONFIG_ARCH_VEXPRESS) += juno.dtb +dtb-$(CONFIG_ARCH_VEXPRESS) += juno.dtb juno-r1.dtb dtb-$(CONFIG_ARCH_VEXPRESS) += rtsm_ve-aemv8a.dtb always := $(dtb-y) diff --git a/arch/arm64/boot/dts/arm/juno-r1.dts b/arch/arm64/boot/dts/arm/juno-r1.dts new file mode 100644 index 000000000000..c62751153a4f --- /dev/null +++ b/arch/arm64/boot/dts/arm/juno-r1.dts @@ -0,0 +1,116 @@ +/* + * ARM Ltd. Juno Platform + * + * Copyright (c) 2015 ARM Ltd. + * + * This file is licensed under a dual GPLv2 or BSD license. + */ + +/dts-v1/; + +#include + +/ { + model = "ARM Juno development board (r1)"; + compatible = "arm,juno-r1", "arm,juno", "arm,vexpress"; + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + aliases { + serial0 = &soc_uart0; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + psci { + compatible = "arm,psci-0.2"; + method = "smc"; + }; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + A57_0: cpu@0 { + compatible = "arm,cortex-a57","arm,armv8"; + reg = <0x0 0x0>; + device_type = "cpu"; + enable-method = "psci"; + next-level-cache = <&A57_L2>; + }; + + A57_1: cpu@1 { + compatible = "arm,cortex-a57","arm,armv8"; + reg = <0x0 0x1>; + device_type = "cpu"; + enable-method = "psci"; + next-level-cache = <&A57_L2>; + }; + + A53_0: cpu@100 { + compatible = "arm,cortex-a53","arm,armv8"; + reg = <0x0 0x100>; + device_type = "cpu"; + enable-method = "psci"; + next-level-cache = <&A53_L2>; + }; + + A53_1: cpu@101 { + compatible = "arm,cortex-a53","arm,armv8"; + reg = <0x0 0x101>; + device_type = "cpu"; + enable-method = "psci"; + next-level-cache = <&A53_L2>; + }; + + A53_2: cpu@102 { + compatible = "arm,cortex-a53","arm,armv8"; + reg = <0x0 0x102>; + device_type = "cpu"; + enable-method = "psci"; + next-level-cache = <&A53_L2>; + }; + + A53_3: cpu@103 { + compatible = "arm,cortex-a53","arm,armv8"; + reg = <0x0 0x103>; + device_type = "cpu"; + enable-method = "psci"; + next-level-cache = <&A53_L2>; + }; + + A57_L2: l2-cache0 { + compatible = "cache"; + }; + + A53_L2: l2-cache1 { + compatible = "cache"; + }; + }; + + pmu { + compatible = "arm,armv8-pmuv3"; + interrupts = , + , + , + , + , + ; + interrupt-affinity = <&A57_0>, + <&A57_1>, + <&A53_0>, + <&A53_1>, + <&A53_2>, + <&A53_3>; + }; + + #include "juno-base.dtsi" + +}; + +&memtimer { + status = "okay"; +}; -- cgit v1.2.3 From 2ee7c7c02b2c95e76d8b7fa98b21ae49c0aa4afb Mon Sep 17 00:00:00 2001 From: Liviu Dudau Date: Wed, 20 May 2015 11:42:37 +0100 Subject: Documentation: bindings: Add DT bindings for ARM Juno boards. List the required properties and nodes used to describe the ARM Juno boards. Signed-off-by: Liviu Dudau (cherry picked from commit 41e177b37bd558980d50609116f7810b46fe4ce0) Signed-off-by: Jon Medhurst --- Documentation/devicetree/bindings/arm/arm-boards | 66 ++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/arm-boards b/Documentation/devicetree/bindings/arm/arm-boards index c554ed3d44fb..074d1703d186 100644 --- a/Documentation/devicetree/bindings/arm/arm-boards +++ b/Documentation/devicetree/bindings/arm/arm-boards @@ -92,3 +92,69 @@ Required nodes: - core-module: the root node to the Versatile platforms must have a core-module with regs and the compatible strings "arm,core-module-versatile", "syscon" + +ARM Versatile Express Boards +----------------------------- +For details on the device tree bindings for ARM Versatile Express boards +please consult the vexpress.txt file in the same directory as this file. + +ARM Juno Boards +---------------- +The Juno boards are targeting development for AArch64 systems. The first +iteration, Juno r0, is a vehicle for evaluating big.LITTLE on AArch64, +with the second iteration, Juno r1, mainly aimed at development of PCIe +based systems. Juno r1 also has support for AXI masters placed on the TLX +connectors to join the coherency domain. + +Juno boards are described in a similar way to ARM Versatile Express boards, +with the motherboard part of the hardware being described in a separate file +to highlight the fact that is part of the support infrastructure for the SoC. +Juno device tree bindings also share the Versatile Express bindings as +described under the RS1 memory mapping. + +Required properties (in root node): + compatible = "arm,juno"; /* For Juno r0 board */ + compatible = "arm,juno-r1"; /* For Juno r1 board */ + +Required nodes: +The description for the board must include: + - a "psci" node describing the boot method used for the secondary CPUs. + A detailed description of the bindings used for "psci" nodes is present + in the psci.txt file. + - a "cpus" node describing the available cores and their associated + "enable-method"s. For more details see cpus.txt file. + +Example: + +/dts-v1/; +/ { + model = "ARM Juno development board (r0)"; + compatible = "arm,juno", "arm,vexpress"; + interrupt-parent = <&gic>; + #address-cells = <2>; + #size-cells = <2>; + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + A57_0: cpu@0 { + compatible = "arm,cortex-a57","arm,armv8"; + reg = <0x0 0x0>; + device_type = "cpu"; + enable-method = "psci"; + }; + + ..... + + A53_0: cpu@100 { + compatible = "arm,cortex-a53","arm,armv8"; + reg = <0x0 0x100>; + device_type = "cpu"; + enable-method = "psci"; + }; + + ..... + }; + +}; -- cgit v1.2.3 From 462563072f41d0158c2ee9831745d035be82d416 Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Tue, 30 Jun 2015 13:37:59 +0100 Subject: arm64: dts: Remove FVP related device-tree files In preperation for adding new files more closely matching upstream. Signed-off-by: Jon Medhurst --- arch/arm64/boot/dts/arm/Makefile | 3 - arch/arm64/boot/dts/arm/foundation-v8.dts | 232 ----------------------------- arch/arm64/boot/dts/arm/rtsm_ve-aemv8a.dts | 159 -------------------- 3 files changed, 394 deletions(-) delete mode 100644 arch/arm64/boot/dts/arm/foundation-v8.dts delete mode 100644 arch/arm64/boot/dts/arm/rtsm_ve-aemv8a.dts diff --git a/arch/arm64/boot/dts/arm/Makefile b/arch/arm64/boot/dts/arm/Makefile index 43d1404bb3c1..1b06c28c67eb 100644 --- a/arch/arm64/boot/dts/arm/Makefile +++ b/arch/arm64/boot/dts/arm/Makefile @@ -1,6 +1,3 @@ -dtb-$(CONFIG_ARCH_VEXPRESS) += foundation-v8.dtb -dtb-$(CONFIG_ARCH_VEXPRESS) += rtsm_ve-aemv8a.dtb - always := $(dtb-y) subdir-y := $(dts-dirs) clean-files := *.dtb diff --git a/arch/arm64/boot/dts/arm/foundation-v8.dts b/arch/arm64/boot/dts/arm/foundation-v8.dts deleted file mode 100644 index 4a060906809d..000000000000 --- a/arch/arm64/boot/dts/arm/foundation-v8.dts +++ /dev/null @@ -1,232 +0,0 @@ -/* - * ARM Ltd. - * - * ARMv8 Foundation model DTS - */ - -/dts-v1/; - -/memreserve/ 0x80000000 0x00010000; - -/ { - model = "Foundation-v8A"; - compatible = "arm,foundation-aarch64", "arm,vexpress"; - interrupt-parent = <&gic>; - #address-cells = <2>; - #size-cells = <2>; - - chosen { }; - - aliases { - serial0 = &v2m_serial0; - serial1 = &v2m_serial1; - serial2 = &v2m_serial2; - serial3 = &v2m_serial3; - }; - - cpus { - #address-cells = <2>; - #size-cells = <0>; - - cpu@0 { - device_type = "cpu"; - compatible = "arm,armv8"; - reg = <0x0 0x0>; - enable-method = "spin-table"; - cpu-release-addr = <0x0 0x8000fff8>; - }; - cpu@1 { - device_type = "cpu"; - compatible = "arm,armv8"; - reg = <0x0 0x1>; - enable-method = "spin-table"; - cpu-release-addr = <0x0 0x8000fff8>; - }; - cpu@2 { - device_type = "cpu"; - compatible = "arm,armv8"; - reg = <0x0 0x2>; - enable-method = "spin-table"; - cpu-release-addr = <0x0 0x8000fff8>; - }; - cpu@3 { - device_type = "cpu"; - compatible = "arm,armv8"; - reg = <0x0 0x3>; - enable-method = "spin-table"; - cpu-release-addr = <0x0 0x8000fff8>; - }; - }; - - memory@80000000 { - device_type = "memory"; - reg = <0x00000000 0x80000000 0 0x80000000>, - <0x00000008 0x80000000 0 0x80000000>; - }; - - gic: interrupt-controller@2c001000 { - compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic"; - #interrupt-cells = <3>; - #address-cells = <0>; - interrupt-controller; - reg = <0x0 0x2c001000 0 0x1000>, - <0x0 0x2c002000 0 0x1000>, - <0x0 0x2c004000 0 0x2000>, - <0x0 0x2c006000 0 0x2000>; - interrupts = <1 9 0xf04>; - }; - - timer { - compatible = "arm,armv8-timer"; - interrupts = <1 13 0xff01>, - <1 14 0xff01>, - <1 11 0xff01>, - <1 10 0xff01>; - clock-frequency = <100000000>; - }; - - pmu { - compatible = "arm,armv8-pmuv3"; - interrupts = <0 60 4>, - <0 61 4>, - <0 62 4>, - <0 63 4>; - }; - - smb { - compatible = "arm,vexpress,v2m-p1", "simple-bus"; - arm,v2m-memory-map = "rs1"; - #address-cells = <2>; /* SMB chipselect number and offset */ - #size-cells = <1>; - - ranges = <0 0 0 0x08000000 0x04000000>, - <1 0 0 0x14000000 0x04000000>, - <2 0 0 0x18000000 0x04000000>, - <3 0 0 0x1c000000 0x04000000>, - <4 0 0 0x0c000000 0x04000000>, - <5 0 0 0x10000000 0x04000000>; - - #interrupt-cells = <1>; - interrupt-map-mask = <0 0 63>; - interrupt-map = <0 0 0 &gic 0 0 4>, - <0 0 1 &gic 0 1 4>, - <0 0 2 &gic 0 2 4>, - <0 0 3 &gic 0 3 4>, - <0 0 4 &gic 0 4 4>, - <0 0 5 &gic 0 5 4>, - <0 0 6 &gic 0 6 4>, - <0 0 7 &gic 0 7 4>, - <0 0 8 &gic 0 8 4>, - <0 0 9 &gic 0 9 4>, - <0 0 10 &gic 0 10 4>, - <0 0 11 &gic 0 11 4>, - <0 0 12 &gic 0 12 4>, - <0 0 13 &gic 0 13 4>, - <0 0 14 &gic 0 14 4>, - <0 0 15 &gic 0 15 4>, - <0 0 16 &gic 0 16 4>, - <0 0 17 &gic 0 17 4>, - <0 0 18 &gic 0 18 4>, - <0 0 19 &gic 0 19 4>, - <0 0 20 &gic 0 20 4>, - <0 0 21 &gic 0 21 4>, - <0 0 22 &gic 0 22 4>, - <0 0 23 &gic 0 23 4>, - <0 0 24 &gic 0 24 4>, - <0 0 25 &gic 0 25 4>, - <0 0 26 &gic 0 26 4>, - <0 0 27 &gic 0 27 4>, - <0 0 28 &gic 0 28 4>, - <0 0 29 &gic 0 29 4>, - <0 0 30 &gic 0 30 4>, - <0 0 31 &gic 0 31 4>, - <0 0 32 &gic 0 32 4>, - <0 0 33 &gic 0 33 4>, - <0 0 34 &gic 0 34 4>, - <0 0 35 &gic 0 35 4>, - <0 0 36 &gic 0 36 4>, - <0 0 37 &gic 0 37 4>, - <0 0 38 &gic 0 38 4>, - <0 0 39 &gic 0 39 4>, - <0 0 40 &gic 0 40 4>, - <0 0 41 &gic 0 41 4>, - <0 0 42 &gic 0 42 4>; - - ethernet@2,02000000 { - compatible = "smsc,lan91c111"; - reg = <2 0x02000000 0x10000>; - interrupts = <15>; - }; - - v2m_clk24mhz: clk24mhz { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <24000000>; - clock-output-names = "v2m:clk24mhz"; - }; - - v2m_refclk1mhz: refclk1mhz { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <1000000>; - clock-output-names = "v2m:refclk1mhz"; - }; - - v2m_refclk32khz: refclk32khz { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <32768>; - clock-output-names = "v2m:refclk32khz"; - }; - - iofpga@3,00000000 { - compatible = "arm,amba-bus", "simple-bus"; - #address-cells = <1>; - #size-cells = <1>; - ranges = <0 3 0 0x200000>; - - v2m_sysreg: sysreg@010000 { - compatible = "arm,vexpress-sysreg"; - reg = <0x010000 0x1000>; - }; - - v2m_serial0: uart@090000 { - compatible = "arm,pl011", "arm,primecell"; - reg = <0x090000 0x1000>; - interrupts = <5>; - clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>; - clock-names = "uartclk", "apb_pclk"; - }; - - v2m_serial1: uart@0a0000 { - compatible = "arm,pl011", "arm,primecell"; - reg = <0x0a0000 0x1000>; - interrupts = <6>; - clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>; - clock-names = "uartclk", "apb_pclk"; - }; - - v2m_serial2: uart@0b0000 { - compatible = "arm,pl011", "arm,primecell"; - reg = <0x0b0000 0x1000>; - interrupts = <7>; - clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>; - clock-names = "uartclk", "apb_pclk"; - }; - - v2m_serial3: uart@0c0000 { - compatible = "arm,pl011", "arm,primecell"; - reg = <0x0c0000 0x1000>; - interrupts = <8>; - clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>; - clock-names = "uartclk", "apb_pclk"; - }; - - virtio_block@0130000 { - compatible = "virtio,mmio"; - reg = <0x130000 0x200>; - interrupts = <42>; - }; - }; - }; -}; diff --git a/arch/arm64/boot/dts/arm/rtsm_ve-aemv8a.dts b/arch/arm64/boot/dts/arm/rtsm_ve-aemv8a.dts deleted file mode 100644 index 572005ea2217..000000000000 --- a/arch/arm64/boot/dts/arm/rtsm_ve-aemv8a.dts +++ /dev/null @@ -1,159 +0,0 @@ -/* - * ARM Ltd. Fast Models - * - * Architecture Envelope Model (AEM) ARMv8-A - * ARMAEMv8AMPCT - * - * RTSM_VE_AEMv8A.lisa - */ - -/dts-v1/; - -/memreserve/ 0x80000000 0x00010000; - -/ { - model = "RTSM_VE_AEMv8A"; - compatible = "arm,rtsm_ve,aemv8a", "arm,vexpress"; - interrupt-parent = <&gic>; - #address-cells = <2>; - #size-cells = <2>; - - chosen { }; - - aliases { - serial0 = &v2m_serial0; - serial1 = &v2m_serial1; - serial2 = &v2m_serial2; - serial3 = &v2m_serial3; - }; - - cpus { - #address-cells = <2>; - #size-cells = <0>; - - cpu@0 { - device_type = "cpu"; - compatible = "arm,armv8"; - reg = <0x0 0x0>; - enable-method = "spin-table"; - cpu-release-addr = <0x0 0x8000fff8>; - }; - cpu@1 { - device_type = "cpu"; - compatible = "arm,armv8"; - reg = <0x0 0x1>; - enable-method = "spin-table"; - cpu-release-addr = <0x0 0x8000fff8>; - }; - cpu@2 { - device_type = "cpu"; - compatible = "arm,armv8"; - reg = <0x0 0x2>; - enable-method = "spin-table"; - cpu-release-addr = <0x0 0x8000fff8>; - }; - cpu@3 { - device_type = "cpu"; - compatible = "arm,armv8"; - reg = <0x0 0x3>; - enable-method = "spin-table"; - cpu-release-addr = <0x0 0x8000fff8>; - }; - }; - - memory@80000000 { - device_type = "memory"; - reg = <0x00000000 0x80000000 0 0x80000000>, - <0x00000008 0x80000000 0 0x80000000>; - }; - - gic: interrupt-controller@2c001000 { - compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic"; - #interrupt-cells = <3>; - #address-cells = <0>; - interrupt-controller; - reg = <0x0 0x2c001000 0 0x1000>, - <0x0 0x2c002000 0 0x1000>, - <0x0 0x2c004000 0 0x2000>, - <0x0 0x2c006000 0 0x2000>; - interrupts = <1 9 0xf04>; - }; - - timer { - compatible = "arm,armv8-timer"; - interrupts = <1 13 0xff01>, - <1 14 0xff01>, - <1 11 0xff01>, - <1 10 0xff01>; - clock-frequency = <100000000>; - }; - - pmu { - compatible = "arm,armv8-pmuv3"; - interrupts = <0 60 4>, - <0 61 4>, - <0 62 4>, - <0 63 4>; - }; - - smb { - compatible = "simple-bus"; - - #address-cells = <2>; - #size-cells = <1>; - ranges = <0 0 0 0x08000000 0x04000000>, - <1 0 0 0x14000000 0x04000000>, - <2 0 0 0x18000000 0x04000000>, - <3 0 0 0x1c000000 0x04000000>, - <4 0 0 0x0c000000 0x04000000>, - <5 0 0 0x10000000 0x04000000>; - - #interrupt-cells = <1>; - interrupt-map-mask = <0 0 63>; - interrupt-map = <0 0 0 &gic 0 0 4>, - <0 0 1 &gic 0 1 4>, - <0 0 2 &gic 0 2 4>, - <0 0 3 &gic 0 3 4>, - <0 0 4 &gic 0 4 4>, - <0 0 5 &gic 0 5 4>, - <0 0 6 &gic 0 6 4>, - <0 0 7 &gic 0 7 4>, - <0 0 8 &gic 0 8 4>, - <0 0 9 &gic 0 9 4>, - <0 0 10 &gic 0 10 4>, - <0 0 11 &gic 0 11 4>, - <0 0 12 &gic 0 12 4>, - <0 0 13 &gic 0 13 4>, - <0 0 14 &gic 0 14 4>, - <0 0 15 &gic 0 15 4>, - <0 0 16 &gic 0 16 4>, - <0 0 17 &gic 0 17 4>, - <0 0 18 &gic 0 18 4>, - <0 0 19 &gic 0 19 4>, - <0 0 20 &gic 0 20 4>, - <0 0 21 &gic 0 21 4>, - <0 0 22 &gic 0 22 4>, - <0 0 23 &gic 0 23 4>, - <0 0 24 &gic 0 24 4>, - <0 0 25 &gic 0 25 4>, - <0 0 26 &gic 0 26 4>, - <0 0 27 &gic 0 27 4>, - <0 0 28 &gic 0 28 4>, - <0 0 29 &gic 0 29 4>, - <0 0 30 &gic 0 30 4>, - <0 0 31 &gic 0 31 4>, - <0 0 32 &gic 0 32 4>, - <0 0 33 &gic 0 33 4>, - <0 0 34 &gic 0 34 4>, - <0 0 35 &gic 0 35 4>, - <0 0 36 &gic 0 36 4>, - <0 0 37 &gic 0 37 4>, - <0 0 38 &gic 0 38 4>, - <0 0 39 &gic 0 39 4>, - <0 0 40 &gic 0 40 4>, - <0 0 41 &gic 0 41 4>, - <0 0 42 &gic 0 42 4>; - - /include/ "rtsm_ve-motherboard.dtsi" - }; -}; -- cgit v1.2.3 From 927555871415167c0b6d944ebe64aa3755ade05c Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Thu, 18 Jun 2015 10:20:27 +0100 Subject: arm64: dts: Add Mali GPU to juno.dts Signed-off-by: Jon Medhurst --- arch/arm64/boot/dts/arm/juno-base.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/boot/dts/arm/juno-base.dtsi b/arch/arm64/boot/dts/arm/juno-base.dtsi index e3ee96036eca..b09607237b33 100644 --- a/arch/arm64/boot/dts/arm/juno-base.dtsi +++ b/arch/arm64/boot/dts/arm/juno-base.dtsi @@ -123,6 +123,13 @@ <0x00000008 0x80000000 0x1 0x80000000>; }; + gpu@0x2d000000 { + compatible = "arm,malit6xx", "arm,mali"; + reg = <0x0 0x2d000000 0x0 0x4000>; + interrupts = <0 33 4>, <0 34 4>, <0 32 4>; + interrupt-names = "JOB", "MMU", "GPU"; + }; + smb { compatible = "simple-bus"; #address-cells = <2>; -- cgit v1.2.3 From 5586e0ae7e95298970e231c4ce636f9b2231598b Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Thu, 23 Jul 2015 12:10:27 +0100 Subject: arm64: dts: add CPU topology on Juno This patch adds CPU topology on Juno. It will be useful for ther other IP blocks depending on this topology. Signed-off-by: Sudeep Holla Acked-by: Liviu Dudau Cc: Jon Medhurst (Tixy) Signed-off-by: Jon Medhurst --- arch/arm64/boot/dts/arm/juno-r1.dts | 26 ++++++++++++++++++++++++++ arch/arm64/boot/dts/arm/juno.dts | 26 ++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/arch/arm64/boot/dts/arm/juno-r1.dts b/arch/arm64/boot/dts/arm/juno-r1.dts index c62751153a4f..69130840c6cd 100644 --- a/arch/arm64/boot/dts/arm/juno-r1.dts +++ b/arch/arm64/boot/dts/arm/juno-r1.dts @@ -34,6 +34,32 @@ #address-cells = <2>; #size-cells = <0>; + cpu-map { + cluster0 { + core0 { + cpu = <&A57_0>; + }; + core1 { + cpu = <&A57_1>; + }; + }; + + cluster1 { + core0 { + cpu = <&A53_0>; + }; + core1 { + cpu = <&A53_1>; + }; + core2 { + cpu = <&A53_2>; + }; + core3 { + cpu = <&A53_3>; + }; + }; + }; + A57_0: cpu@0 { compatible = "arm,cortex-a57","arm,armv8"; reg = <0x0 0x0>; diff --git a/arch/arm64/boot/dts/arm/juno.dts b/arch/arm64/boot/dts/arm/juno.dts index d7cbdd482a61..ce1128a54c8d 100644 --- a/arch/arm64/boot/dts/arm/juno.dts +++ b/arch/arm64/boot/dts/arm/juno.dts @@ -34,6 +34,32 @@ #address-cells = <2>; #size-cells = <0>; + cpu-map { + cluster0 { + core0 { + cpu = <&A57_0>; + }; + core1 { + cpu = <&A57_1>; + }; + }; + + cluster1 { + core0 { + cpu = <&A53_0>; + }; + core1 { + cpu = <&A53_1>; + }; + core2 { + cpu = <&A53_2>; + }; + core3 { + cpu = <&A53_3>; + }; + }; + }; + A57_0: cpu@0 { compatible = "arm,cortex-a57","arm,armv8"; reg = <0x0 0x0>; -- cgit v1.2.3 From aa589109dc200b7741b58734ecbeaf9537cd52b5 Mon Sep 17 00:00:00 2001 From: Zeng Tao Date: Tue, 9 Dec 2014 09:19:40 +0800 Subject: staging: ion: ion_cma_heap: remove ion_cma_get_sgtable Remove the temporary code ion_cma_get_sgtable, use dma_common_get_sgtable instead Signed-off-by: Zeng Tao Signed-off-by: Greg Kroah-Hartman (cherry picked from commit e5e76d247f4a40827fef69a72939771943774e87) Signed-off-by: Jon Medhurst --- drivers/staging/android/ion/ion_cma_heap.c | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/drivers/staging/android/ion/ion_cma_heap.c b/drivers/staging/android/ion/ion_cma_heap.c index f8cabcbc39e5..f4211f1be488 100644 --- a/drivers/staging/android/ion/ion_cma_heap.c +++ b/drivers/staging/android/ion/ion_cma_heap.c @@ -39,24 +39,6 @@ struct ion_cma_buffer_info { struct sg_table *table; }; -/* - * Create scatter-list for the already allocated DMA buffer. - * This function could be replaced by dma_common_get_sgtable - * as soon as it will avalaible. - */ -static int ion_cma_get_sgtable(struct device *dev, struct sg_table *sgt, - void *cpu_addr, dma_addr_t handle, size_t size) -{ - struct page *page = virt_to_page(cpu_addr); - int ret; - - ret = sg_alloc_table(sgt, 1, GFP_KERNEL); - if (unlikely(ret)) - return ret; - - sg_set_page(sgt->sgl, page, PAGE_ALIGN(size), 0); - return 0; -} /* ION CMA heap operations functions */ static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer, @@ -91,7 +73,7 @@ static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer, if (!info->table) goto free_mem; - if (ion_cma_get_sgtable + if (dma_common_get_sgtable (dev, info->table, info->cpu_addr, info->handle, len)) goto free_table; /* keep this for memory release */ -- cgit v1.2.3 From 09485995eb80abd545699518ae663ec56882aae7 Mon Sep 17 00:00:00 2001 From: "Jon Medhurst (Tixy)" Date: Fri, 17 Jul 2015 12:01:29 +0100 Subject: staging: ion: ion_cma_heap: Don't directly use dma_common_get_sgtable Use dma_get_sgtable rather than dma_common_get_sgtable so a device's dma_ops aren't bypassed. This is essential in situations where a device uses an IOMMU and the physical memory is not contiguous (as the common function assumes). Signed-off-by: Jon Medhurst --- drivers/staging/android/ion/ion_cma_heap.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/staging/android/ion/ion_cma_heap.c b/drivers/staging/android/ion/ion_cma_heap.c index f4211f1be488..86b91fd53852 100644 --- a/drivers/staging/android/ion/ion_cma_heap.c +++ b/drivers/staging/android/ion/ion_cma_heap.c @@ -73,8 +73,7 @@ static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer, if (!info->table) goto free_mem; - if (dma_common_get_sgtable - (dev, info->table, info->cpu_addr, info->handle, len)) + if (dma_get_sgtable(dev, info->table, info->cpu_addr, info->handle, len)) goto free_table; /* keep this for memory release */ buffer->priv_virt = info; -- cgit v1.2.3 From 08d66ad512fc9fe942e502d19badcf81b6b88f57 Mon Sep 17 00:00:00 2001 From: Liviu Dudau Date: Mon, 30 Jun 2014 18:31:14 +0100 Subject: staging: android: ion: Set the length of the DMA sg entries in buffer. ion_buffer_create() will allocate a buffer and then create a DMA mapping for it, but it forgot to set the length of the page entries. Signed-off-by: Liviu Dudau Signed-off-by: Jon Medhurst --- drivers/staging/android/ion/ion.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 56604f41ec48..5f6f8cf7875e 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -252,8 +252,10 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, allocation via dma_map_sg. The implicit contract here is that memory comming from the heaps is ready for dma, ie if it has a cached mapping that mapping has been invalidated */ - for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents, i) + for_each_sg(buffer->sg_table->sgl, sg, buffer->sg_table->nents, i) { sg_dma_address(sg) = sg_phys(sg); + sg_dma_len(sg) = sg->length; + } mutex_lock(&dev->buffer_lock); ion_buffer_add(dev, buffer); mutex_unlock(&dev->buffer_lock); -- cgit v1.2.3 From 167d63428bfeb0dede6d39eea1faa2c03e209d4c Mon Sep 17 00:00:00 2001 From: Jon Medhurst Date: Thu, 16 Jul 2015 15:15:16 +0100 Subject: common: dma-mapping: Make dma_common_get_sgtable work with more memory regions For buffers outside kernel memory, use the dma handle to find the pages. Signed-off-by: Jon Medhurst --- drivers/base/dma-mapping.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c index 9e8bbdd470ca..e5127e50af59 100644 --- a/drivers/base/dma-mapping.c +++ b/drivers/base/dma-mapping.c @@ -228,9 +228,19 @@ EXPORT_SYMBOL(dmam_release_declared_memory); int dma_common_get_sgtable(struct device *dev, struct sg_table *sgt, void *cpu_addr, dma_addr_t handle, size_t size) { - struct page *page = virt_to_page(cpu_addr); + struct page *page; int ret; + if (virt_addr_valid(cpu_addr)) + page = virt_to_page(cpu_addr); + else { +#ifdef dma_to_phys + page = pfn_to_page(dma_to_phys(dev, handle) >> PAGE_SHIFT); +#else + BUG(); +#endif + } + ret = sg_alloc_table(sgt, 1, GFP_KERNEL); if (unlikely(ret)) return ret; -- cgit v1.2.3 From 320fe4437947b73e2f3a836de100a94173d46064 Mon Sep 17 00:00:00 2001 From: Javi Merino Date: Wed, 5 Aug 2015 15:21:55 +0100 Subject: PM / OPP: add a function to get the voltage for disabled OPPs The OPP library is now used for power models, to calculate the power that a device would consume at a specific OPP. To do that, we use a simple power model which takes frequency and voltage as inputs. We get the voltage and frequency from the OPP library. A devfreq cooling device for the thermal framework controls temperature by disabling OPPs. The power model needs to calculate the power that would be consumed if we reenabled the OPP. dev_pm_opp_get_voltage() doesn't work for disabled OPPs. Add a dev_pm_opp_get_voltage_always() that works both for enabled and disabled OPPs to be used by the power model. The documentation for this function clearly states that you should use dev_pm_opp_get_voltage() instead unless you know what you're doing. Cc: "Rafael J. Wysocki" Cc: Viresh Kumar Signed-off-by: Javi Merino Signed-off-by: Jon Medhurst --- drivers/base/power/opp.c | 35 +++++++++++++++++++++++++++++++++++ include/linux/pm_opp.h | 7 +++++++ 2 files changed, 42 insertions(+) diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index 89ced955fafa..84b16d47cf55 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -163,6 +163,41 @@ unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp) } EXPORT_SYMBOL_GPL(dev_pm_opp_get_voltage); +/** + * dev_pm_opp_get_voltage_always() - Gets the voltage corresponding to an opp + * @opp: opp for which voltage has to be returned for + * + * This function is similar to dev_pm_opp_get_voltage() except that it + * works for disabled opps as well. In most cases, you want to + * operate only on available opps so you should use + * dev_pm_opp_get_voltage() instead. + * + * Return: voltage in micro volt corresponding to the opp, else + * return 0 + * + * Locking: This function must be called under rcu_read_lock(). opp is a rcu + * protected pointer. This means that opp which could have been fetched by + * opp_find_freq_{exact,ceil,floor} functions is valid as long as we are + * under RCU lock. The pointer returned by the opp_find_freq family must be + * used in the same section as the usage of this function with the pointer + * prior to unlocking with rcu_read_unlock() to maintain the integrity of the + * pointer. + */ +unsigned long dev_pm_opp_get_voltage_always(struct dev_pm_opp *opp) +{ + struct dev_pm_opp *tmp_opp; + unsigned long v = 0; + + tmp_opp = rcu_dereference(opp); + if (unlikely(IS_ERR_OR_NULL(tmp_opp))) + pr_err("%s: Invalid parameters\n", __func__); + else + v = tmp_opp->u_volt; + + return v; +} +EXPORT_SYMBOL_GPL(dev_pm_opp_get_voltage_always); + /** * dev_pm_opp_get_freq() - Gets the frequency corresponding to an available opp * @opp: opp for which frequency has to be returned for diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h index 0330217abfad..1c93411b2ac6 100644 --- a/include/linux/pm_opp.h +++ b/include/linux/pm_opp.h @@ -28,6 +28,8 @@ enum dev_pm_opp_event { unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp); +unsigned long dev_pm_opp_get_voltage_always(struct dev_pm_opp *opp); + unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp); int dev_pm_opp_get_opp_count(struct device *dev); @@ -56,6 +58,11 @@ static inline unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp) return 0; } +static inline unsigned long dev_pm_opp_get_voltage_always(struct dev_pm_opp *opp) +{ + return 0; +} + static inline unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp) { return 0; -- cgit v1.2.3 From 4e004d2ea43c2c0a9c094923f3df2d2b5c9b43eb Mon Sep 17 00:00:00 2001 From: Javi Merino Date: Thu, 2 Jul 2015 11:09:24 +0100 Subject: PM / devfreq: cache the last call to get_dev_status() The return value of get_dev_status() can be reused. Cache it so that other parts of the kernel can reuse it instead of having to call the same function again. Cc: MyungJoo Ham Cc: Kyungmin Park Signed-off-by: Javi Merino Signed-off-by: Jon Medhurst --- drivers/devfreq/devfreq.c | 5 +++++ drivers/devfreq/governor_simpleondemand.c | 33 +++++++++++++++++-------------- include/linux/devfreq.h | 8 ++++++++ 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 30b538d8cc90..ebb53bc548ed 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -769,6 +769,11 @@ err_out: } EXPORT_SYMBOL(devfreq_remove_governor); +int devfreq_update_stats(struct devfreq *df) +{ + return df->profile->get_dev_status(df->dev.parent, &df->last_status); +} + static ssize_t governor_show(struct device *dev, struct device_attribute *attr, char *buf) { diff --git a/drivers/devfreq/governor_simpleondemand.c b/drivers/devfreq/governor_simpleondemand.c index 0720ba84ca92..ae72ba5e78df 100644 --- a/drivers/devfreq/governor_simpleondemand.c +++ b/drivers/devfreq/governor_simpleondemand.c @@ -21,17 +21,20 @@ static int devfreq_simple_ondemand_func(struct devfreq *df, unsigned long *freq) { - struct devfreq_dev_status stat; - int err = df->profile->get_dev_status(df->dev.parent, &stat); + int err; + struct devfreq_dev_status *stat; unsigned long long a, b; unsigned int dfso_upthreshold = DFSO_UPTHRESHOLD; unsigned int dfso_downdifferential = DFSO_DOWNDIFFERENCTIAL; struct devfreq_simple_ondemand_data *data = df->data; unsigned long max = (df->max_freq) ? df->max_freq : UINT_MAX; + err = devfreq_update_stats(df); if (err) return err; + stat = &df->last_status; + if (data) { if (data->upthreshold) dfso_upthreshold = data->upthreshold; @@ -43,41 +46,41 @@ static int devfreq_simple_ondemand_func(struct devfreq *df, return -EINVAL; /* Assume MAX if it is going to be divided by zero */ - if (stat.total_time == 0) { + if (stat->total_time == 0) { *freq = max; return 0; } /* Prevent overflow */ - if (stat.busy_time >= (1 << 24) || stat.total_time >= (1 << 24)) { - stat.busy_time >>= 7; - stat.total_time >>= 7; + if (stat->busy_time >= (1 << 24) || stat->total_time >= (1 << 24)) { + stat->busy_time >>= 7; + stat->total_time >>= 7; } /* Set MAX if it's busy enough */ - if (stat.busy_time * 100 > - stat.total_time * dfso_upthreshold) { + if (stat->busy_time * 100 > + stat->total_time * dfso_upthreshold) { *freq = max; return 0; } /* Set MAX if we do not know the initial frequency */ - if (stat.current_frequency == 0) { + if (stat->current_frequency == 0) { *freq = max; return 0; } /* Keep the current frequency */ - if (stat.busy_time * 100 > - stat.total_time * (dfso_upthreshold - dfso_downdifferential)) { - *freq = stat.current_frequency; + if (stat->busy_time * 100 > + stat->total_time * (dfso_upthreshold - dfso_downdifferential)) { + *freq = stat->current_frequency; return 0; } /* Set the desired frequency based on the load */ - a = stat.busy_time; - a *= stat.current_frequency; - b = div_u64(a, stat.total_time); + a = stat->busy_time; + a *= stat->current_frequency; + b = div_u64(a, stat->total_time); b *= 100; b = div_u64(b, (dfso_upthreshold - dfso_downdifferential / 2)); *freq = (unsigned long) b; diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h index f1863dcd83ea..a2f4a834b880 100644 --- a/include/linux/devfreq.h +++ b/include/linux/devfreq.h @@ -161,6 +161,7 @@ struct devfreq { struct delayed_work work; unsigned long previous_freq; + struct devfreq_dev_status last_status; void *data; /* private data for governors */ @@ -204,6 +205,8 @@ extern int devm_devfreq_register_opp_notifier(struct device *dev, extern void devm_devfreq_unregister_opp_notifier(struct device *dev, struct devfreq *devfreq); +int devfreq_update_stats(struct devfreq *df); + #if IS_ENABLED(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND) /** * struct devfreq_simple_ondemand_data - void *data fed to struct devfreq @@ -289,6 +292,11 @@ static inline void devm_devfreq_unregister_opp_notifier(struct device *dev, struct devfreq *devfreq) { } + +static inline int devfreq_update_stats(struct devfreq *df) +{ + return -EINVAL; +} #endif /* CONFIG_PM_DEVFREQ */ #endif /* __LINUX_DEVFREQ_H__ */ -- cgit v1.2.3 From 635cceca04a6f06f98675877c9a6bd198a6f02f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98rjan=20Eide?= Date: Fri, 20 Jun 2014 16:19:53 +0100 Subject: thermal: Add devfreq cooling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a generic thermal cooling device for devfreq, that is similar to cpu_cooling. The device must use devfreq. In order to use the power extension of the cooling device, it must have registered its OPPs using the OPP library. Cc: Zhang Rui Cc: Eduardo Valentin Signed-off-by: Ørjan Eide Signed-off-by: Jon Medhurst --- drivers/thermal/Kconfig | 10 + drivers/thermal/Makefile | 3 + drivers/thermal/devfreq_cooling.c | 471 ++++++++++++++++++++++++++++++++++++++ include/linux/devfreq_cooling.h | 93 ++++++++ 4 files changed, 577 insertions(+) create mode 100644 drivers/thermal/devfreq_cooling.c create mode 100644 include/linux/devfreq_cooling.h diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 8b7d47f2f3aa..11c22e97b9ee 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -148,6 +148,16 @@ config CLOCK_THERMAL device that is configured to use this cooling mechanism will be controlled to reduce clock frequency whenever temperature is high. +config DEVFREQ_THERMAL + bool "Generic device cooling support" + depends on PM_DEVFREQ + help + This implements the generic devfreq cooling mechanism through + frequency reduction for devices using devfreq. + + This will throttle the device by limiting the maximum allowed DVFS + frequency corresponding to the cooling level. + If you want this support, you should say Y here. config THERMAL_EMULATION diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index dae37c089bb4..9390e3cca09a 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -22,6 +22,9 @@ thermal_sys-$(CONFIG_CPU_THERMAL) += cpu_cooling.o # clock cooling thermal_sys-$(CONFIG_CLOCK_THERMAL) += clock_cooling.o +# devfreq cooling +thermal_sys-$(CONFIG_DEVFREQ_THERMAL) += devfreq_cooling.o + # platform thermal drivers obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o obj-$(CONFIG_RCAR_THERMAL) += rcar_thermal.o diff --git a/drivers/thermal/devfreq_cooling.c b/drivers/thermal/devfreq_cooling.c new file mode 100644 index 000000000000..b4368cce95f3 --- /dev/null +++ b/drivers/thermal/devfreq_cooling.c @@ -0,0 +1,471 @@ +/* + * devfreq_cooling: Thermal cooling device implementation for devices using + * devfreq + * + * Copyright (C) 2014-2015 ARM Limited + * + * 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. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include + +static DEFINE_MUTEX(devfreq_lock); +static DEFINE_IDR(devfreq_idr); + +/** + * get_idr - function to get a unique id. + * @idr: struct idr * handle used to create a id. + * @id: int * value generated by this function. + * + * This function will populate @id with an unique + * id, using the idr API. + * + * Return: 0 on success, an error code on failure. + */ +static int get_idr(struct idr *idr, int *id) +{ + int ret; + + mutex_lock(&devfreq_lock); + ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL); + mutex_unlock(&devfreq_lock); + if (unlikely(ret < 0)) + return ret; + *id = ret; + + return 0; +} + +/** + * release_idr - function to free the unique id. + * @idr: struct idr * handle used for creating the id. + * @id: int value representing the unique id. + */ +static void release_idr(struct idr *idr, int id) +{ + mutex_lock(&devfreq_lock); + idr_remove(idr, id); + mutex_unlock(&devfreq_lock); +} + +static int enable_disable_opps(struct devfreq *df, int max_enabled_state) +{ + int i; + struct device *dev = df->dev.parent; + + for (i = 0; i < df->profile->max_state; i++) { + struct dev_pm_opp *opp; + unsigned int freq = df->profile->freq_table[i]; + bool want_enable = i <= max_enabled_state ? true : false; + + rcu_read_lock(); + opp = dev_pm_opp_find_freq_exact(dev, freq, !want_enable); + rcu_read_unlock(); + + if (PTR_ERR(opp) == -ERANGE) + continue; + else if (IS_ERR(opp)) + return PTR_ERR(opp); + + if (want_enable) + dev_pm_opp_enable(dev, freq); + else + dev_pm_opp_disable(dev, freq); + } + + return 0; +} + +static int devfreq_cooling_get_max_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + struct devfreq_cooling_device *dfc = cdev->devdata; + struct devfreq *df = dfc->devfreq; + + *state = df->profile->max_state - 1; + + return 0; +} + +static int devfreq_cooling_get_cur_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + struct devfreq_cooling_device *dfc = cdev->devdata; + + *state = dfc->cooling_state; + + return 0; +} + +static int devfreq_cooling_set_cur_state(struct thermal_cooling_device *cdev, + unsigned long state) +{ + struct devfreq_cooling_device *dfc = cdev->devdata; + struct devfreq *df = dfc->devfreq; + struct device *dev = df->dev.parent; + unsigned long index; + unsigned long max_state = df->profile->max_state; + int ret; + + if (state == dfc->cooling_state) + return 0; + + dev_dbg(dev, "Setting cooling state %lu\n", state); + + if (state >= max_state) + return -EINVAL; + + index = (max_state - 1) - state; + + ret = enable_disable_opps(df, index); + if (ret) + return ret; + + dfc->cooling_state = state; + + return 0; +} + +static unsigned long +freq_get_state(struct devfreq *df, unsigned long freq) +{ + unsigned long state = THERMAL_CSTATE_INVALID; + int i; + + for (i = 0; i < df->profile->max_state; i++) { + if (df->profile->freq_table[i] == freq) + state = (df->profile->max_state - 1) - i; + } + + return state; +} + +static unsigned long +state_get_freq(struct devfreq *df, unsigned long state) +{ + unsigned long index = (df->profile->max_state - 1) - state; + + if (index >= df->profile->max_state) + return 0; + + return df->profile->freq_table[index]; +} + +static unsigned long +get_static_power(struct devfreq_cooling_device *dfc, unsigned long freq) +{ + struct devfreq *df = dfc->devfreq; + struct device *dev = df->dev.parent; + unsigned long voltage; + struct dev_pm_opp *opp; + + rcu_read_lock(); + + opp = dev_pm_opp_find_freq_exact(dev, freq, true); + if (IS_ERR(opp) && (PTR_ERR(opp) == -ERANGE)) + opp = dev_pm_opp_find_freq_exact(dev, freq, false); + + voltage = dev_pm_opp_get_voltage_always(opp) / 1000; /* mV */ + + rcu_read_unlock(); + + if (voltage == 0) { + dev_warn_ratelimited(dev, + "Failed to get voltage for frequency %lu: %ld\n", + freq, IS_ERR(opp) ? PTR_ERR(opp) : 0); + return 0; + } + + return dfc->power_ops->get_static_power(voltage); +} + +static int devfreq_cooling_get_requested_power(struct thermal_cooling_device *cdev, + struct thermal_zone_device *tz, + u32 *power) +{ + struct devfreq_cooling_device *dfc = cdev->devdata; + struct devfreq *df = dfc->devfreq; + struct devfreq_dev_status *status = &df->last_status; + unsigned long state; + unsigned long freq = status->current_frequency; + u32 dyn_power, static_power; + + /* Get dynamic power for state */ + state = freq_get_state(df, freq); + if (state == THERMAL_CSTATE_INVALID) + return -EAGAIN; + + dyn_power = dfc->power_table[state]; + + /* Scale dynamic power for utilization */ + dyn_power = (dyn_power * status->busy_time) / status->total_time; + + /* Get static power */ + static_power = get_static_power(dfc, freq); + + *power = dyn_power + static_power; + + return 0; +} + +static int devfreq_cooling_state2power(struct thermal_cooling_device *cdev, + struct thermal_zone_device *tz, + unsigned long state, + u32 *power) +{ + struct devfreq_cooling_device *dfc = cdev->devdata; + struct devfreq *df = dfc->devfreq; + unsigned long freq; + u32 static_power; + + freq = state_get_freq(df, state); + static_power = get_static_power(dfc, freq); + + *power = dfc->power_table[state] + static_power; + return 0; +} + +static int devfreq_cooling_power2state(struct thermal_cooling_device *cdev, + struct thermal_zone_device *tz, + u32 power, unsigned long *state) +{ + struct devfreq_cooling_device *dfc = cdev->devdata; + struct devfreq *df = dfc->devfreq; + struct devfreq_dev_status *status = &df->last_status; + unsigned long freq = status->current_frequency; + unsigned long busy_time; + s32 dyn_power; + u32 static_power; + int i; + + static_power = get_static_power(dfc, freq); + + dyn_power = power - static_power; + dyn_power = dyn_power > 0 ? dyn_power : 0; + + /* Scale dynamic power for utilization */ + busy_time = status->busy_time ?: 1; + dyn_power = (dyn_power * status->total_time) / busy_time; + + /* + * Find the first cooling state that is within the power + * budget for dynamic power. + */ + for (i = 0; i < df->profile->max_state - 1; i++) + if (dyn_power >= dfc->power_table[i]) + break; + + *state = i; + return 0; +} + +static struct thermal_cooling_device_ops devfreq_cooling_ops = { + .get_max_state = devfreq_cooling_get_max_state, + .get_cur_state = devfreq_cooling_get_cur_state, + .set_cur_state = devfreq_cooling_set_cur_state, +}; + +/** + * devfreq_cooling_gen_power_table(): - Generate power table. + * @dfc: Pointer to devfreq cooling device. + * + * Generate a table with the device's maximum power usage at each cooling + * state (OPP). The static and dynamic powerm using the appropriate voltage and + * frequency for the state, is acquired from the struct devfreq_cooling_ops, and + * summed to make the maximum power draw. + * + * The table is malloced, and a pointer put in dfc->power_table. This must be + * freed when unregistering the devfreq cooling device. + * + * Return: 0 on success, negative error code on failure. + */ +static int devfreq_cooling_gen_power_table(struct devfreq_cooling_device *dfc) +{ + struct devfreq *df = dfc->devfreq; + struct device *dev = df->dev.parent; + int num_opps; + struct devfreq_cooling_ops *callbacks = dfc->power_ops; + unsigned long freq; + u32 *table; + int i; + + if (!IS_ENABLED(CONFIG_PM_OPP)) { + dev_warn(dev, "Can't use power extensions of the devfreq cooling device without CONFIG_PM_OPP\n"); + return -EINVAL; + } + + rcu_read_lock(); + num_opps = dev_pm_opp_get_opp_count(dev); + + if (num_opps != dfc->devfreq->profile->max_state) { + rcu_read_unlock(); + return -ERANGE; + } + + table = devm_kcalloc(dev, num_opps, sizeof(*table), GFP_KERNEL); + if (!table) { + rcu_read_unlock(); + return -ENOMEM; + } + + for (i = 0, freq = ULONG_MAX; i < num_opps; i++, freq--) { + unsigned long power_dyn, voltage; + struct dev_pm_opp *opp; + + opp = dev_pm_opp_find_freq_floor(dev, &freq); + if (IS_ERR(opp)) + break; + + voltage = dev_pm_opp_get_voltage(opp) / 1000; /* mV */ + + power_dyn = callbacks->get_dynamic_power(freq, voltage); + + dev_info(dev, "Dynamic power table: %lu MHz @ %lu mV: %lu = %lu mW\n", + freq / 1000000, voltage, power_dyn, power_dyn); + + table[i] = power_dyn; + } + rcu_read_unlock(); + + if (i != num_opps) { + devm_kfree(dev, table); + return -EFAULT; + } + + dfc->power_table = table; + + return 0; +} + +/** + * of_devfreq_cooling_register_power(): - Register devfreq cooling device, + * with OF and power information. + * @np: Pointer to OF device_node. + * @df: Pointer to devfreq device. + * @ops: Pointer to power ops. + */ +struct devfreq_cooling_device * +of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df, + struct devfreq_cooling_ops *ops) +{ + struct thermal_cooling_device *cdev; + struct devfreq_cooling_device *dfc; + struct device *dev = df->dev.parent; + char dev_name[THERMAL_NAME_LENGTH]; + int err; + + /* freq_table is required to look map state index to frequency. */ + if (!df->profile->max_state || !df->profile->freq_table) + return ERR_PTR(-EINVAL); + + dfc = devm_kzalloc(dev, sizeof(*dfc), GFP_KERNEL); + if (!dfc) + return ERR_PTR(-ENOMEM); + + dfc->devfreq = df; + + if (ops) { + if (!ops->get_static_power || !ops->get_dynamic_power) { + err = -EINVAL; + goto free_dfc; + } + dfc->power_ops = ops; + + err = devfreq_cooling_gen_power_table(dfc); + if (err) + goto free_dfc; + + devfreq_cooling_ops.get_requested_power = + devfreq_cooling_get_requested_power; + devfreq_cooling_ops.state2power = devfreq_cooling_state2power; + devfreq_cooling_ops.power2state = devfreq_cooling_power2state; + } + + err = get_idr(&devfreq_idr, &dfc->id); + if (err) + goto free_power_table; + + snprintf(dev_name, sizeof(dev_name), "devfreq-%d", dfc->id); + + cdev = thermal_of_cooling_device_register(np, dev_name, dfc, + &devfreq_cooling_ops); + if (IS_ERR(cdev)) { + err = PTR_ERR(cdev); + dev_err(df->dev.parent, + "Failed to register devfreq cooling device (%d)\n", + err); + goto release_idr; + } + + dfc->cdev = cdev; + + return dfc; + +release_idr: + release_idr(&devfreq_idr, dfc->id); +free_power_table: + if (dfc->power_table) + devm_kfree(dev, dfc->power_table); +free_dfc: + devm_kfree(dev, dfc); + + return ERR_PTR(err); +} +EXPORT_SYMBOL(of_devfreq_cooling_register_power); + +/** + * of_devfreq_cooling_register(): - Register devfreq cooling device, + * with OF information. + * @np: Pointer to OF device_node. + * @df: Pointer to devfreq device. + */ +struct devfreq_cooling_device * +of_devfreq_cooling_register(struct device_node *np, struct devfreq *df) +{ + return of_devfreq_cooling_register_power(np, df, NULL); +} +EXPORT_SYMBOL(of_devfreq_cooling_register); + +/** + * devfreq_cooling_register(): - Register devfreq cooling device. + * @df: Pointer to devfreq device. + */ +struct devfreq_cooling_device *devfreq_cooling_register(struct devfreq *df) +{ + return of_devfreq_cooling_register(NULL, df); +} +EXPORT_SYMBOL(devfreq_cooling_register); + +/** + * devfreq_cooling_unregister(): - Unregister devfreq cooling device. + * @dfc: Pointer to devfreq cooling device to unregister. + */ +void devfreq_cooling_unregister(struct devfreq_cooling_device *dfc) +{ + struct device *dev; + + if (!dfc) + return; + + dev = dfc->devfreq->dev.parent; + + thermal_cooling_device_unregister(dfc->cdev); + + release_idr(&devfreq_idr, dfc->id); + if (dfc->power_table) + devm_kfree(dev, dfc->power_table); + devm_kfree(dev, dfc); +} +EXPORT_SYMBOL(devfreq_cooling_unregister); diff --git a/include/linux/devfreq_cooling.h b/include/linux/devfreq_cooling.h new file mode 100644 index 000000000000..8e7346ebbeb2 --- /dev/null +++ b/include/linux/devfreq_cooling.h @@ -0,0 +1,93 @@ +/* + * devfreq_cooling: Thermal cooling device implementation for devices using + * devfreq + * + * Copyright (C) 2014 ARM Limited + * + * 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. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __DEVFREQ_COOLING_H__ +#define __DEVFREQ_COOLING_H__ + +#include +#include + +#ifdef CONFIG_DEVFREQ_THERMAL + +/** + * struct devfreq_cooling_ops - Devfreq cooling power ops + * @get_static_power: Take voltage, in mV, and return the static power in mW. + * @get_dynamic_power: Take voltage, in mV, and frequency, in HZ, and return + * the dynamic power draw in mW. + */ +struct devfreq_cooling_ops { + unsigned long (*get_static_power)(unsigned long voltage); + unsigned long (*get_dynamic_power)(unsigned long freq, + unsigned long voltage); +}; + +/** + * struct devfreq_cooling_device - Devfreq cooling device + * @id: unique integer value corresponding to each + * devfreq_cooling_device registered. + * @cdev: Pointer to associated thermal cooling device. + * @devfreq: Pointer to associated devfreq device. + * @cooling_state: Current cooling state. + * @power_table: Pointer to table with maximum power draw for each cooling + * state. State is the index into the table, and the power is + * stated in mW. + * @power_ops: Pointer to power operations, used to generate @power_table. + */ +struct devfreq_cooling_device { + int id; + struct thermal_cooling_device *cdev; + struct devfreq *devfreq; + unsigned long cooling_state; + u32 *power_table; + struct devfreq_cooling_ops *power_ops; +}; + +struct devfreq_cooling_device * +of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df, + struct devfreq_cooling_ops *ops); +struct devfreq_cooling_device * +of_devfreq_cooling_register(struct device_node *np, struct devfreq *df); +struct devfreq_cooling_device *devfreq_cooling_register(struct devfreq *df); +void devfreq_cooling_unregister(struct devfreq_cooling_device *dfc); + +#else /* !CONFIG_DEVFREQ_THERMAL */ + +struct devfreq_cooling_device * +of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df, + struct devfreq_cooling_ops *ops) +{ + return ERR_PTR(-EINVAL); +} + +static inline struct devfreq_cooling_device * +of_devfreq_cooling_register(struct device_node *np, struct devfreq *df) +{ + return ERR_PTR(-EINVAL); +} + +static inline struct devfreq_cooling_device * +devfreq_cooling_register(struct devfreq *df) +{ + return ERR_PTR(-EINVAL); +} + +static inline void +devfreq_cooling_unregister(struct devfreq_cooling_device *dfc) +{ +} + +#endif /* CONFIG_DEVFREQ_THERMAL */ +#endif /* __DEVFREQ_COOLING_H__ */ -- cgit v1.2.3 From facc52709388c6aa850b4f1165e52c4d8b7925b9 Mon Sep 17 00:00:00 2001 From: Javi Merino Date: Mon, 20 Apr 2015 14:30:17 +0100 Subject: devfreq_cooling: add trace information Tracing is useful for debugging and performance tuning. Add similar traces to what's present in the cpu cooling device. Cc: Zhang Rui Cc: Eduardo Valentin Cc: Steven Rostedt Cc: Ingo Molnar Signed-off-by: Javi Merino Signed-off-by: Jon Medhurst --- drivers/thermal/devfreq_cooling.c | 6 +++++ include/trace/events/thermal.h | 53 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/drivers/thermal/devfreq_cooling.c b/drivers/thermal/devfreq_cooling.c index b4368cce95f3..58da2a8d08dc 100644 --- a/drivers/thermal/devfreq_cooling.c +++ b/drivers/thermal/devfreq_cooling.c @@ -21,6 +21,8 @@ #include #include +#include + static DEFINE_MUTEX(devfreq_lock); static DEFINE_IDR(devfreq_idr); @@ -215,6 +217,9 @@ static int devfreq_cooling_get_requested_power(struct thermal_cooling_device *cd /* Get static power */ static_power = get_static_power(dfc, freq); + trace_thermal_power_devfreq_get_power(cdev, status, freq, dyn_power, + static_power); + *power = dyn_power + static_power; return 0; @@ -268,6 +273,7 @@ static int devfreq_cooling_power2state(struct thermal_cooling_device *cdev, break; *state = i; + trace_thermal_power_devfreq_limit(cdev, freq, *state, power); return 0; } diff --git a/include/trace/events/thermal.h b/include/trace/events/thermal.h index 8b1f80682b80..5738bb3e2343 100644 --- a/include/trace/events/thermal.h +++ b/include/trace/events/thermal.h @@ -4,6 +4,7 @@ #if !defined(_TRACE_THERMAL_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_THERMAL_H +#include #include #include @@ -135,6 +136,58 @@ TRACE_EVENT(thermal_power_cpu_limit, __entry->power) ); +TRACE_EVENT(thermal_power_devfreq_get_power, + TP_PROTO(struct thermal_cooling_device *cdev, + struct devfreq_dev_status *status, unsigned long freq, + u32 dynamic_power, u32 static_power), + + TP_ARGS(cdev, status, freq, dynamic_power, static_power), + + TP_STRUCT__entry( + __string(type, cdev->type ) + __field(unsigned long, freq ) + __field(u32, load ) + __field(u32, dynamic_power ) + __field(u32, static_power ) + ), + + TP_fast_assign( + __assign_str(type, cdev->type); + __entry->freq = freq; + __entry->load = (100 * status->busy_time) / status->total_time; + __entry->dynamic_power = dynamic_power; + __entry->static_power = static_power; + ), + + TP_printk("type=%s freq=%lu load=%u dynamic_power=%u static_power=%u", + __get_str(type), __entry->freq, + __entry->load, __entry->dynamic_power, __entry->static_power) +); + +TRACE_EVENT(thermal_power_devfreq_limit, + TP_PROTO(struct thermal_cooling_device *cdev, unsigned long freq, + unsigned long cdev_state, u32 power), + + TP_ARGS(cdev, freq, cdev_state, power), + + TP_STRUCT__entry( + __string(type, cdev->type) + __field(unsigned int, freq ) + __field(unsigned long, cdev_state) + __field(u32, power ) + ), + + TP_fast_assign( + __assign_str(type, cdev->type); + __entry->freq = freq; + __entry->cdev_state = cdev_state; + __entry->power = power; + ), + + TP_printk("type=%s freq=%u cdev_state=%lu power=%u", + __get_str(type), __entry->freq, __entry->cdev_state, + __entry->power) +); #endif /* _TRACE_THERMAL_H */ /* This part must be outside protection */ -- cgit v1.2.3