* [PATCH v5 4/5] ARM: dts: Add I2C1 support for STM32429 eval board
From: M'boumba Cedric Madianga @ 2016-12-08 8:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <e61ae4d6-a65a-5cfa-6845-27351ac43af6@st.com>
Hi Alex,
2016-12-08 9:39 GMT+01:00 Alexandre Torgue <alexandre.torgue@st.com>:
> Hi Cedric,
>
> On 12/08/2016 09:26 AM, M'boumba Cedric Madianga wrote:
>>
>> Signed-off-by: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
>> ---
>> arch/arm/boot/dts/stm32429i-eval.dts | 6 ++++++
>> 1 file changed, 6 insertions(+)
>>
> Can you change the commit header by: ARM: dts: stm32: Add I2C1 support for
> STM32429 eval board
Ok, I will use this typo in the next version
>
> thx
> Alex
>
>
>> diff --git a/arch/arm/boot/dts/stm32429i-eval.dts
>> b/arch/arm/boot/dts/stm32429i-eval.dts
>> index afb90bc..74e0045 100644
>> --- a/arch/arm/boot/dts/stm32429i-eval.dts
>> +++ b/arch/arm/boot/dts/stm32429i-eval.dts
>> @@ -141,3 +141,9 @@
>> pinctrl-names = "default";
>> status = "okay";
>> };
>> +
>> +&i2c1 {
>> + pinctrl-0 = <&i2c1_pins_b>;
>> + pinctrl-names = "default";
>> + status = "okay";
>> +};
>>
>
^ permalink raw reply
* [PATCH v5 5/5] ARM: configs: Add I2C support for STM32 defconfig
From: M'boumba Cedric Madianga @ 2016-12-08 8:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <daf6b0b4-9bd1-d3eb-a759-ed64eee990f2@st.com>
Hi Alex,
2016-12-08 9:38 GMT+01:00 Alexandre Torgue <alexandre.torgue@st.com>:
> Hi Cedric,
>
> On 12/08/2016 09:26 AM, M'boumba Cedric Madianga wrote:
>>
>> Signed-off-by: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
>> ---
>> arch/arm/configs/stm32_defconfig | 3 +++
>> 1 file changed, 3 insertions(+)
>>
> Can you change the commit header by ARM: configs: stm32: Add I2C support
Ok, I will use this typo in the next version
>
> Thx
> alex
>
>
>
>
>
>> diff --git a/arch/arm/configs/stm32_defconfig
>> b/arch/arm/configs/stm32_defconfig
>> index e7b56d4..9494eaf 100644
>> --- a/arch/arm/configs/stm32_defconfig
>> +++ b/arch/arm/configs/stm32_defconfig
>> @@ -52,6 +52,9 @@ CONFIG_SERIAL_NONSTANDARD=y
>> CONFIG_SERIAL_STM32=y
>> CONFIG_SERIAL_STM32_CONSOLE=y
>> # CONFIG_HW_RANDOM is not set
>> +CONFIG_I2C=y
>> +CONFIG_I2C_CHARDEV=y
>> +CONFIG_I2C_STM32F4=y
>> # CONFIG_HWMON is not set
>> # CONFIG_USB_SUPPORT is not set
>> CONFIG_NEW_LEDS=y
>>
>
^ permalink raw reply
* [PATCH 2/2] ASoC: zte: spdif: correct ZX_SPDIF_CLK_RAT define
From: Shawn Guo @ 2016-12-08 8:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481186655-8213-1-git-send-email-shawnguo@kernel.org>
From: Shawn Guo <shawn.guo@linaro.org>
The macro ZX_SPDIF_CLK_RAT should be 2 instead of 4. With this
fix, we can get correct audio output on HDMI through SPDIF interface.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
sound/soc/zte/zx-spdif.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sound/soc/zte/zx-spdif.c b/sound/soc/zte/zx-spdif.c
index 26265ce4caca..9fa6463ce5d7 100644
--- a/sound/soc/zte/zx-spdif.c
+++ b/sound/soc/zte/zx-spdif.c
@@ -71,7 +71,7 @@
#define ZX_VALID_RIGHT_TRACK (2 << 0)
#define ZX_VALID_TRACK_MASK (3 << 0)
-#define ZX_SPDIF_CLK_RAT (4 * 32)
+#define ZX_SPDIF_CLK_RAT (2 * 32)
struct zx_spdif_info {
struct snd_dmaengine_dai_dma_data dma_data;
--
1.9.1
^ permalink raw reply related
* [PATCH 1/2] ASoC: zte: spdif and i2s drivers are not zx296702 specific
From: Shawn Guo @ 2016-12-08 8:44 UTC (permalink / raw)
To: linux-arm-kernel
From: Shawn Guo <shawn.guo@linaro.org>
ZTE ZX SPDIF and I2S drivers can work on not only ZX296702 but also
other ZTE ZX family SoCs like ZX296718, which is an arm64 platform.
Let's make a few renaming and tweak the Kconfig a bit to get the drivers
available for other ZTE ZX platforms.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
sound/soc/zte/Kconfig | 16 ++++++++--------
sound/soc/zte/Makefile | 4 ++--
sound/soc/zte/{zx296702-i2s.c => zx-i2s.c} | 0
sound/soc/zte/{zx296702-spdif.c => zx-spdif.c} | 0
4 files changed, 10 insertions(+), 10 deletions(-)
rename sound/soc/zte/{zx296702-i2s.c => zx-i2s.c} (100%)
rename sound/soc/zte/{zx296702-spdif.c => zx-spdif.c} (100%)
diff --git a/sound/soc/zte/Kconfig b/sound/soc/zte/Kconfig
index c47eb25e441f..6d8a90d36315 100644
--- a/sound/soc/zte/Kconfig
+++ b/sound/soc/zte/Kconfig
@@ -1,17 +1,17 @@
-config ZX296702_SPDIF
- tristate "ZX296702 spdif"
- depends on SOC_ZX296702 || COMPILE_TEST
+config ZX_SPDIF
+ tristate "ZTE ZX SPDIF Driver Support"
+ depends on ARCH_ZX || COMPILE_TEST
depends on COMMON_CLK
select SND_SOC_GENERIC_DMAENGINE_PCM
help
Say Y or M if you want to add support for codecs attached to the
- zx296702 spdif interface
+ ZTE ZX SPDIF interface
-config ZX296702_I2S
- tristate "ZX296702 i2s"
- depends on SOC_ZX296702 || COMPILE_TEST
+config ZX_I2S
+ tristate "ZTE ZX I2S Driver Support"
+ depends on ARCH_ZX || COMPILE_TEST
depends on COMMON_CLK
select SND_SOC_GENERIC_DMAENGINE_PCM
help
Say Y or M if you want to add support for codecs attached to the
- zx296702 i2s interface
+ ZTE ZX I2S interface
diff --git a/sound/soc/zte/Makefile b/sound/soc/zte/Makefile
index 254ed2c8c1a0..77768f5fd10c 100644
--- a/sound/soc/zte/Makefile
+++ b/sound/soc/zte/Makefile
@@ -1,2 +1,2 @@
-obj-$(CONFIG_ZX296702_SPDIF) += zx296702-spdif.o
-obj-$(CONFIG_ZX296702_I2S) += zx296702-i2s.o
+obj-$(CONFIG_ZX_SPDIF) += zx-spdif.o
+obj-$(CONFIG_ZX_I2S) += zx-i2s.o
diff --git a/sound/soc/zte/zx296702-i2s.c b/sound/soc/zte/zx-i2s.c
similarity index 100%
rename from sound/soc/zte/zx296702-i2s.c
rename to sound/soc/zte/zx-i2s.c
diff --git a/sound/soc/zte/zx296702-spdif.c b/sound/soc/zte/zx-spdif.c
similarity index 100%
rename from sound/soc/zte/zx296702-spdif.c
rename to sound/soc/zte/zx-spdif.c
--
1.9.1
^ permalink raw reply related
* [PATCH v5 4/5] ARM: dts: Add I2C1 support for STM32429 eval board
From: Alexandre Torgue @ 2016-12-08 8:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481185563-8735-5-git-send-email-cedric.madianga@gmail.com>
Hi Cedric,
On 12/08/2016 09:26 AM, M'boumba Cedric Madianga wrote:
> Signed-off-by: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
> ---
> arch/arm/boot/dts/stm32429i-eval.dts | 6 ++++++
> 1 file changed, 6 insertions(+)
>
Can you change the commit header by: ARM: dts: stm32: Add I2C1 support
for STM32429 eval board
thx
Alex
> diff --git a/arch/arm/boot/dts/stm32429i-eval.dts b/arch/arm/boot/dts/stm32429i-eval.dts
> index afb90bc..74e0045 100644
> --- a/arch/arm/boot/dts/stm32429i-eval.dts
> +++ b/arch/arm/boot/dts/stm32429i-eval.dts
> @@ -141,3 +141,9 @@
> pinctrl-names = "default";
> status = "okay";
> };
> +
> +&i2c1 {
> + pinctrl-0 = <&i2c1_pins_b>;
> + pinctrl-names = "default";
> + status = "okay";
> +};
>
^ permalink raw reply
* [PATCH v5 5/5] ARM: configs: Add I2C support for STM32 defconfig
From: Alexandre Torgue @ 2016-12-08 8:38 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481185563-8735-6-git-send-email-cedric.madianga@gmail.com>
Hi Cedric,
On 12/08/2016 09:26 AM, M'boumba Cedric Madianga wrote:
> Signed-off-by: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
> ---
> arch/arm/configs/stm32_defconfig | 3 +++
> 1 file changed, 3 insertions(+)
>
Can you change the commit header by ARM: configs: stm32: Add I2C support
Thx
alex
> diff --git a/arch/arm/configs/stm32_defconfig b/arch/arm/configs/stm32_defconfig
> index e7b56d4..9494eaf 100644
> --- a/arch/arm/configs/stm32_defconfig
> +++ b/arch/arm/configs/stm32_defconfig
> @@ -52,6 +52,9 @@ CONFIG_SERIAL_NONSTANDARD=y
> CONFIG_SERIAL_STM32=y
> CONFIG_SERIAL_STM32_CONSOLE=y
> # CONFIG_HW_RANDOM is not set
> +CONFIG_I2C=y
> +CONFIG_I2C_CHARDEV=y
> +CONFIG_I2C_STM32F4=y
> # CONFIG_HWMON is not set
> # CONFIG_USB_SUPPORT is not set
> CONFIG_NEW_LEDS=y
>
^ permalink raw reply
* [PATCH v5 5/5] ARM: configs: Add I2C support for STM32 defconfig
From: M'boumba Cedric Madianga @ 2016-12-08 8:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481185563-8735-1-git-send-email-cedric.madianga@gmail.com>
Signed-off-by: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
---
arch/arm/configs/stm32_defconfig | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/arm/configs/stm32_defconfig b/arch/arm/configs/stm32_defconfig
index e7b56d4..9494eaf 100644
--- a/arch/arm/configs/stm32_defconfig
+++ b/arch/arm/configs/stm32_defconfig
@@ -52,6 +52,9 @@ CONFIG_SERIAL_NONSTANDARD=y
CONFIG_SERIAL_STM32=y
CONFIG_SERIAL_STM32_CONSOLE=y
# CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_STM32F4=y
# CONFIG_HWMON is not set
# CONFIG_USB_SUPPORT is not set
CONFIG_NEW_LEDS=y
--
1.9.1
^ permalink raw reply related
* [PATCH v5 4/5] ARM: dts: Add I2C1 support for STM32429 eval board
From: M'boumba Cedric Madianga @ 2016-12-08 8:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481185563-8735-1-git-send-email-cedric.madianga@gmail.com>
Signed-off-by: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
---
arch/arm/boot/dts/stm32429i-eval.dts | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/arch/arm/boot/dts/stm32429i-eval.dts b/arch/arm/boot/dts/stm32429i-eval.dts
index afb90bc..74e0045 100644
--- a/arch/arm/boot/dts/stm32429i-eval.dts
+++ b/arch/arm/boot/dts/stm32429i-eval.dts
@@ -141,3 +141,9 @@
pinctrl-names = "default";
status = "okay";
};
+
+&i2c1 {
+ pinctrl-0 = <&i2c1_pins_b>;
+ pinctrl-names = "default";
+ status = "okay";
+};
--
1.9.1
^ permalink raw reply related
* [PATCH v5 3/5] ARM: dts: Add I2C1 support for STM32F429 SoC
From: M'boumba Cedric Madianga @ 2016-12-08 8:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481185563-8735-1-git-send-email-cedric.madianga@gmail.com>
Signed-off-by: Patrice Chotard <patrice.chotard@st.com>
Signed-off-by: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
---
arch/arm/boot/dts/stm32f429.dtsi | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
index 7de52ee..cbdece7 100644
--- a/arch/arm/boot/dts/stm32f429.dtsi
+++ b/arch/arm/boot/dts/stm32f429.dtsi
@@ -48,6 +48,7 @@
#include "skeleton.dtsi"
#include "armv7-m.dtsi"
#include <dt-bindings/pinctrl/stm32f429-pinfunc.h>
+#include <dt-bindings/mfd/stm32f4-rcc.h>
/ {
clocks {
@@ -337,6 +338,16 @@
slew-rate = <2>;
};
};
+
+ i2c1_pins_b: i2c1 at 0 {
+ pins1 {
+ pinmux = <STM32F429_PB9_FUNC_I2C1_SDA>;
+ drive-open-drain;
+ };
+ pins2 {
+ pinmux = <STM32F429_PB6_FUNC_I2C1_SCL>;
+ };
+ };
};
rcc: rcc at 40023810 {
@@ -409,6 +420,18 @@
interrupts = <80>;
clocks = <&rcc 0 38>;
};
+
+ i2c1: i2c at 40005400 {
+ compatible = "st,stm32f4-i2c";
+ reg = <0x40005400 0x400>;
+ interrupts = <31>,
+ <32>;
+ resets = <&rcc STM32F4_APB1_RESET(I2C1)>;
+ clocks = <&rcc 0 STM32F4_APB1_CLOCK(I2C1)>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
};
};
--
1.9.1
^ permalink raw reply related
* [PATCH v5 2/5] i2c: Add STM32F4 I2C driver
From: M'boumba Cedric Madianga @ 2016-12-08 8:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481185563-8735-1-git-send-email-cedric.madianga@gmail.com>
This patch adds support for the STM32F4 I2C controller.
Signed-off-by: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
---
drivers/i2c/busses/Kconfig | 10 +
drivers/i2c/busses/Makefile | 1 +
drivers/i2c/busses/i2c-stm32f4.c | 851 +++++++++++++++++++++++++++++++++++++++
3 files changed, 862 insertions(+)
create mode 100644 drivers/i2c/busses/i2c-stm32f4.c
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 8e43914..584e0d7 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -886,6 +886,16 @@ config I2C_ST
This driver can also be built as module. If so, the module
will be called i2c-st.
+config I2C_STM32F4
+ tristate "STMicroelectronics STM32F4 I2C support"
+ depends on ARCH_STM32 || COMPILE_TEST
+ help
+ Enable this option to add support for STM32 I2C controller embedded
+ in STM32F4 SoCs.
+
+ This driver can also be built as module. If so, the module
+ will be called i2c-stm32f4.
+
config I2C_STU300
tristate "ST Microelectronics DDC I2C interface"
depends on MACH_U300
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 1c1bac8..a2c6ff5 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -85,6 +85,7 @@ obj-$(CONFIG_I2C_SH_MOBILE) += i2c-sh_mobile.o
obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o
obj-$(CONFIG_I2C_SIRF) += i2c-sirf.o
obj-$(CONFIG_I2C_ST) += i2c-st.o
+obj-$(CONFIG_I2C_STM32F4) += i2c-stm32f4.o
obj-$(CONFIG_I2C_STU300) += i2c-stu300.o
obj-$(CONFIG_I2C_SUN6I_P2WI) += i2c-sun6i-p2wi.o
obj-$(CONFIG_I2C_TEGRA) += i2c-tegra.o
diff --git a/drivers/i2c/busses/i2c-stm32f4.c b/drivers/i2c/busses/i2c-stm32f4.c
new file mode 100644
index 0000000..0630354
--- /dev/null
+++ b/drivers/i2c/busses/i2c-stm32f4.c
@@ -0,0 +1,851 @@
+/*
+ * Driver for STMicroelectronics STM32 I2C controller
+ *
+ * Copyright (C) M'boumba Cedric Madianga 2015
+ * Author: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
+ *
+ * This driver is based on i2c-st.c
+ *
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+
+/* STM32F4 I2C offset registers */
+#define STM32F4_I2C_CR1 0x00
+#define STM32F4_I2C_CR2 0x04
+#define STM32F4_I2C_DR 0x10
+#define STM32F4_I2C_SR1 0x14
+#define STM32F4_I2C_SR2 0x18
+#define STM32F4_I2C_CCR 0x1C
+#define STM32F4_I2C_TRISE 0x20
+#define STM32F4_I2C_FLTR 0x24
+
+/* STM32F4 I2C control 1*/
+#define STM32F4_I2C_CR1_SWRST BIT(15)
+#define STM32F4_I2C_CR1_POS BIT(11)
+#define STM32F4_I2C_CR1_ACK BIT(10)
+#define STM32F4_I2C_CR1_STOP BIT(9)
+#define STM32F4_I2C_CR1_START BIT(8)
+#define STM32F4_I2C_CR1_PE BIT(0)
+
+/* STM32F4 I2C control 2 */
+#define STM32F4_I2C_CR2_FREQ_MASK GENMASK(5, 0)
+#define STM32F4_I2C_CR2_FREQ(n) ((n & STM32F4_I2C_CR2_FREQ_MASK))
+#define STM32F4_I2C_CR2_ITBUFEN BIT(10)
+#define STM32F4_I2C_CR2_ITEVTEN BIT(9)
+#define STM32F4_I2C_CR2_ITERREN BIT(8)
+#define STM32F4_I2C_CR2_IRQ_MASK (STM32F4_I2C_CR2_ITBUFEN \
+ | STM32F4_I2C_CR2_ITEVTEN \
+ | STM32F4_I2C_CR2_ITERREN)
+
+/* STM32F4 I2C Status 1 */
+#define STM32F4_I2C_SR1_AF BIT(10)
+#define STM32F4_I2C_SR1_ARLO BIT(9)
+#define STM32F4_I2C_SR1_BERR BIT(8)
+#define STM32F4_I2C_SR1_TXE BIT(7)
+#define STM32F4_I2C_SR1_RXNE BIT(6)
+#define STM32F4_I2C_SR1_BTF BIT(2)
+#define STM32F4_I2C_SR1_ADDR BIT(1)
+#define STM32F4_I2C_SR1_SB BIT(0)
+#define STM32F4_I2C_SR1_ITEVTEN_MASK (STM32F4_I2C_SR1_BTF \
+ | STM32F4_I2C_SR1_ADDR \
+ | STM32F4_I2C_SR1_SB)
+#define STM32F4_I2C_SR1_ITBUFEN_MASK (STM32F4_I2C_SR1_TXE \
+ | STM32F4_I2C_SR1_RXNE)
+#define STM32F4_I2C_SR1_ITERREN_MASK (STM32F4_I2C_SR1_AF \
+ | STM32F4_I2C_SR1_ARLO \
+ | STM32F4_I2C_SR1_BERR)
+
+/* STM32F4 I2C Status 2 */
+#define STM32F4_I2C_SR2_BUSY BIT(1)
+
+/* STM32F4 I2C Control Clock */
+#define STM32F4_I2C_CCR_CCR_MASK GENMASK(11, 0)
+#define STM32F4_I2C_CCR_CCR(n) ((n & STM32F4_I2C_CCR_CCR_MASK))
+#define STM32F4_I2C_CCR_FS BIT(15)
+#define STM32F4_I2C_CCR_DUTY BIT(14)
+
+/* STM32F4 I2C Trise */
+#define STM32F4_I2C_TRISE_VALUE_MASK GENMASK(5, 0)
+#define STM32F4_I2C_TRISE_VALUE(n) ((n & STM32F4_I2C_TRISE_VALUE_MASK))
+
+/* STM32F4 I2C Filter */
+#define STM32F4_I2C_FLTR_DNF_MASK GENMASK(3, 0)
+#define STM32F4_I2C_FLTR_DNF(n) ((n & STM32F4_I2C_FLTR_DNF_MASK))
+#define STM32F4_I2C_FLTR_ANOFF BIT(4)
+
+#define STM32F4_I2C_MIN_FREQ 2
+#define STM32F4_I2C_MAX_FREQ 42
+#define FAST_MODE_MAX_RISE_TIME 1000
+#define STD_MODE_MAX_RISE_TIME 300
+#define MHZ_TO_HZ 1000000
+
+enum stm32f4_i2c_speed {
+ STM32F4_I2C_SPEED_STANDARD, /* 100 kHz */
+ STM32F4_I2C_SPEED_FAST, /* 400 kHz */
+ STM32F4_I2C_SPEED_END,
+};
+
+/**
+ * struct stm32f4_i2c_timings - per-Mode tuning parameters
+ * @duty: Fast mode duty cycle
+ * @mul_ccr: Value to be multiplied to CCR to reach 100Khz/400Khz SCL frequency
+ * @min_ccr: Minimum clock ctrl reg value to reach 100Khz/400Khz SCL frequency
+ */
+struct stm32f4_i2c_timings {
+ u32 rate;
+ u32 duty;
+ u32 mul_ccr;
+ u32 min_ccr;
+};
+
+/**
+ * struct stm32f4_i2c_msg - client specific data
+ * @addr: 8-bit slave addr, including r/w bit
+ * @count: number of bytes to be transferred
+ * @buf: data buffer
+ * @result: result of the transfer
+ * @stop: last I2C msg to be sent, i.e. STOP to be generated
+ */
+struct stm32f4_i2c_msg {
+ u8 addr;
+ u32 count;
+ u8 *buf;
+ int result;
+ bool stop;
+};
+
+/**
+ * struct stm32f4_i2c_dev - private data of the controller
+ * @adap: I2C adapter for this controller
+ * @dev: device for this controller
+ * @base: virtual memory area
+ * @complete: completion of I2C message
+ * @irq_event: interrupt event line for the controller
+ * @irq_error: interrupt error line for the controller
+ * @clk: hw i2c clock
+ * speed: I2C clock frequency of the controller. Standard or Fast only supported
+ * @msg: I2C transfer information
+ */
+struct stm32f4_i2c_dev {
+ struct i2c_adapter adap;
+ struct device *dev;
+ void __iomem *base;
+ struct completion complete;
+ int irq_event;
+ int irq_error;
+ struct clk *clk;
+ int speed;
+ struct stm32f4_i2c_msg msg;
+};
+
+static struct stm32f4_i2c_timings i2c_timings[] = {
+ [STM32F4_I2C_SPEED_STANDARD] = {
+ .mul_ccr = 1,
+ .min_ccr = 4,
+ .duty = 0,
+ },
+ [STM32F4_I2C_SPEED_FAST] = {
+ .mul_ccr = 16,
+ .min_ccr = 1,
+ .duty = 1,
+ },
+};
+
+static inline void stm32f4_i2c_set_bits(void __iomem *reg, u32 mask)
+{
+ writel_relaxed(readl_relaxed(reg) | mask, reg);
+}
+
+static inline void stm32f4_i2c_clr_bits(void __iomem *reg, u32 mask)
+{
+ writel_relaxed(readl_relaxed(reg) & ~mask, reg);
+}
+
+static void stm32f4_i2c_soft_reset(struct stm32f4_i2c_dev *i2c_dev)
+{
+ void __iomem *reg = i2c_dev->base + STM32F4_I2C_CR1;
+
+ stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_SWRST);
+ stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR1_SWRST);
+}
+
+static void stm32f4_i2c_disable_it(struct stm32f4_i2c_dev *i2c_dev)
+{
+ void __iomem *reg = i2c_dev->base + STM32F4_I2C_CR2;
+
+ stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR2_IRQ_MASK);
+}
+
+static void stm32f4_i2c_set_periph_clk_freq(struct stm32f4_i2c_dev *i2c_dev)
+{
+ u32 clk_rate, cr2, freq;
+
+ cr2 = readl_relaxed(i2c_dev->base + STM32F4_I2C_CR2);
+ cr2 &= ~STM32F4_I2C_CR2_FREQ_MASK;
+ clk_rate = clk_get_rate(i2c_dev->clk);
+ freq = clk_rate / MHZ_TO_HZ;
+ freq = clamp(freq, STM32F4_I2C_MIN_FREQ, STM32F4_I2C_MAX_FREQ);
+ cr2 |= STM32F4_I2C_CR2_FREQ(freq);
+ writel_relaxed(cr2, i2c_dev->base + STM32F4_I2C_CR2);
+}
+
+static void stm32f4_i2c_set_rise_time(struct stm32f4_i2c_dev *i2c_dev)
+{
+ u32 trise, freq, cr2, val;
+
+ cr2 = readl_relaxed(i2c_dev->base + STM32F4_I2C_CR2);
+ freq = cr2 & STM32F4_I2C_CR2_FREQ_MASK;
+
+ trise = readl_relaxed(i2c_dev->base + STM32F4_I2C_TRISE);
+ trise &= ~STM32F4_I2C_TRISE_VALUE_MASK;
+
+ /* Maximum rise time computation */
+ if (i2c_dev->speed == STM32F4_I2C_SPEED_STANDARD) {
+ trise |= STM32F4_I2C_TRISE_VALUE((freq + 1));
+ } else {
+ val = freq * FAST_MODE_MAX_RISE_TIME / STD_MODE_MAX_RISE_TIME;
+ trise |= STM32F4_I2C_TRISE_VALUE((val + 1));
+ }
+
+ writel_relaxed(trise, i2c_dev->base + STM32F4_I2C_TRISE);
+}
+
+static void stm32f4_i2c_set_speed_mode(struct stm32f4_i2c_dev *i2c_dev)
+{
+ struct stm32f4_i2c_timings *t = &i2c_timings[i2c_dev->speed];
+ u32 ccr, clk_rate;
+ int val;
+
+ ccr = readl_relaxed(i2c_dev->base + STM32F4_I2C_CCR);
+ ccr &= ~(STM32F4_I2C_CCR_FS | STM32F4_I2C_CCR_DUTY |
+ STM32F4_I2C_CCR_CCR_MASK);
+
+ clk_rate = clk_get_rate(i2c_dev->clk);
+ val = clk_rate / MHZ_TO_HZ * t->mul_ccr;
+ if (val < t->min_ccr)
+ val = t->min_ccr;
+ ccr |= STM32F4_I2C_CCR_CCR(val);
+
+ if (t->duty)
+ ccr |= STM32F4_I2C_CCR_FS | STM32F4_I2C_CCR_DUTY;
+
+ writel_relaxed(ccr, i2c_dev->base + STM32F4_I2C_CCR);
+}
+
+static void stm32f4_i2c_set_filter(struct stm32f4_i2c_dev *i2c_dev)
+{
+ u32 filter;
+
+ /* Enable analog noise filter and disable digital noise filter */
+ filter = readl_relaxed(i2c_dev->base + STM32F4_I2C_FLTR);
+ filter &= ~(STM32F4_I2C_FLTR_ANOFF | STM32F4_I2C_FLTR_DNF_MASK);
+ writel_relaxed(filter, i2c_dev->base + STM32F4_I2C_FLTR);
+}
+
+/**
+ * stm32f4_i2c_hw_config() - Prepare I2C block
+ * @i2c_dev: Controller's private data
+ */
+static void stm32f4_i2c_hw_config(struct stm32f4_i2c_dev *i2c_dev)
+{
+ void __iomem *reg = i2c_dev->base + STM32F4_I2C_CR1;
+
+ /* Disable I2C */
+ stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR1_PE);
+
+ stm32f4_i2c_set_periph_clk_freq(i2c_dev);
+
+ stm32f4_i2c_set_rise_time(i2c_dev);
+
+ stm32f4_i2c_set_speed_mode(i2c_dev);
+
+ stm32f4_i2c_set_filter(i2c_dev);
+
+ /* Enable I2C */
+ stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_PE);
+}
+
+static int stm32f4_i2c_wait_free_bus(struct stm32f4_i2c_dev *i2c_dev)
+{
+ u32 status;
+ int ret;
+
+ ret = readl_relaxed_poll_timeout(i2c_dev->base + STM32F4_I2C_SR2,
+ status,
+ !(status & STM32F4_I2C_SR2_BUSY),
+ 10, 1000);
+ if (ret) {
+ dev_err(i2c_dev->dev, "bus not free\n");
+ ret = -EBUSY;
+ }
+
+ return ret;
+}
+
+/**
+ * stm32f4_i2c_write_ byte() - Write a byte in the data register
+ * @i2c_dev: Controller's private data
+ * @byte: Data to write in the register
+ */
+static void stm32f4_i2c_write_byte(struct stm32f4_i2c_dev *i2c_dev, u8 byte)
+{
+ writel_relaxed(byte, i2c_dev->base + STM32F4_I2C_DR);
+}
+
+/**
+ * stm32f4_i2c_write_msg() - Fill the data register in write mode
+ * @i2c_dev: Controller's private data
+ *
+ * This function fills the data register with I2C transfer buffer
+ */
+static void stm32f4_i2c_write_msg(struct stm32f4_i2c_dev *i2c_dev)
+{
+ struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
+
+ stm32f4_i2c_write_byte(i2c_dev, *msg->buf++);
+ msg->count--;
+}
+
+static void stm32f4_i2c_read_msg(struct stm32f4_i2c_dev *i2c_dev)
+{
+ struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
+ u32 rbuf;
+
+ rbuf = readl_relaxed(i2c_dev->base + STM32F4_I2C_DR);
+ *msg->buf++ = (u8)rbuf & 0xff;
+ msg->count--;
+}
+
+static void stm32f4_i2c_terminate_xfer(struct stm32f4_i2c_dev *i2c_dev)
+{
+ struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
+ void __iomem *reg = i2c_dev->base + STM32F4_I2C_CR2;
+
+ stm32f4_i2c_disable_it(i2c_dev);
+
+ reg = i2c_dev->base + STM32F4_I2C_CR1;
+ if (msg->stop)
+ stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_STOP);
+ else
+ stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_START);
+
+ complete(&i2c_dev->complete);
+}
+
+/**
+ * stm32f4_i2c_handle_write() - Handle FIFO empty interrupt in case of write
+ * @i2c_dev: Controller's private data
+ */
+static void stm32f4_i2c_handle_write(struct stm32f4_i2c_dev *i2c_dev)
+{
+ struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
+ void __iomem *reg = i2c_dev->base + STM32F4_I2C_CR2;
+
+ if (msg->count) {
+ stm32f4_i2c_write_msg(i2c_dev);
+ if (!msg->count) {
+ /* Disable BUF interrupt */
+ stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR2_ITBUFEN);
+ }
+ } else {
+ stm32f4_i2c_terminate_xfer(i2c_dev);
+ }
+}
+
+/**
+ * stm32f4_i2c_handle_read() - Handle FIFO empty interrupt in case of read
+ * @i2c_dev: Controller's private data
+ */
+static void stm32f4_i2c_handle_read(struct stm32f4_i2c_dev *i2c_dev)
+{
+ struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
+ void __iomem *reg = i2c_dev->base + STM32F4_I2C_CR2;
+
+ switch (msg->count) {
+ case 1:
+ stm32f4_i2c_disable_it(i2c_dev);
+ stm32f4_i2c_read_msg(i2c_dev);
+ complete(&i2c_dev->complete);
+ break;
+ case 2:
+ case 3:
+ stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR2_ITBUFEN);
+ break;
+ default:
+ stm32f4_i2c_read_msg(i2c_dev);
+ }
+}
+
+/**
+ * stm32f4_i2c_handle_rx_btf() - Handle byte transfer finished interrupt
+ * in case of read
+ * @i2c_dev: Controller's private data
+ */
+static void stm32f4_i2c_handle_rx_btf(struct stm32f4_i2c_dev *i2c_dev)
+{
+ struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
+ void __iomem *reg;
+ u32 mask;
+ int i;
+
+ switch (msg->count) {
+ case 2:
+ reg = i2c_dev->base + STM32F4_I2C_CR1;
+ /* Generate STOP or REPSTART */
+ if (msg->stop)
+ stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_STOP);
+ else
+ stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_START);
+
+ /* Read two last data bytes */
+ for (i = 2; i > 0; i--)
+ stm32f4_i2c_read_msg(i2c_dev);
+
+ /* Disable EVT and ERR interrupt */
+ reg = i2c_dev->base + STM32F4_I2C_CR2;
+ mask = STM32F4_I2C_CR2_ITEVTEN | STM32F4_I2C_CR2_ITERREN;
+ stm32f4_i2c_clr_bits(reg, mask);
+
+ complete(&i2c_dev->complete);
+ break;
+ case 3:
+ /* Enable ACK and read data */
+ reg = i2c_dev->base + STM32F4_I2C_CR1;
+ stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR1_ACK);
+ stm32f4_i2c_read_msg(i2c_dev);
+ break;
+ default:
+ stm32f4_i2c_read_msg(i2c_dev);
+ }
+}
+
+/**
+ * stm32f4_i2c_handle_rx_addr() - Handle address matched interrupt in case of
+ * master receiver
+ * @i2c_dev: Controller's private data
+ */
+static void stm32f4_i2c_handle_rx_addr(struct stm32f4_i2c_dev *i2c_dev)
+{
+ struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
+ void __iomem *reg;
+ u32 sr2;
+
+ switch (msg->count) {
+ case 0:
+ stm32f4_i2c_terminate_xfer(i2c_dev);
+ /* Clear ADDR flag */
+ sr2 = readl_relaxed(i2c_dev->base + STM32F4_I2C_SR2);
+ break;
+ case 1:
+ /*
+ * Single byte reception:
+ * Enable NACK, clear ADDR flag and generate STOP or RepSTART
+ */
+ reg = i2c_dev->base + STM32F4_I2C_CR1;
+ stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR1_ACK);
+ sr2 = readl_relaxed(i2c_dev->base + STM32F4_I2C_SR2);
+ if (msg->stop)
+ stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_STOP);
+ else
+ stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_START);
+ break;
+ case 2:
+ /*
+ * 2-byte reception:
+ * Enable NACK and PEC Position Ack and clear ADDR flag
+ */
+ reg = i2c_dev->base + STM32F4_I2C_CR1;
+ stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR1_ACK);
+ stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_POS);
+ sr2 = readl_relaxed(i2c_dev->base + STM32F4_I2C_SR2);
+ break;
+
+ default:
+ /* N-byte reception: Enable ACK and clear ADDR flag */
+ reg = i2c_dev->base + STM32F4_I2C_CR1;
+ stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_ACK);
+ sr2 = readl_relaxed(i2c_dev->base + STM32F4_I2C_SR2);
+ break;
+ }
+}
+
+/**
+ * stm32f4_i2c_isr_event() - Interrupt routine for I2C bus event
+ * @irq: interrupt number
+ * @data: Controller's private data
+ */
+static irqreturn_t stm32f4_i2c_isr_event(int irq, void *data)
+{
+ struct stm32f4_i2c_dev *i2c_dev = data;
+ struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
+ void __iomem *reg;
+ u32 real_status, possible_status, ien, sr2;
+ int flag;
+
+ ien = readl_relaxed(i2c_dev->base + STM32F4_I2C_CR2);
+ ien &= STM32F4_I2C_CR2_IRQ_MASK;
+ possible_status = 0;
+
+ /* Check possible status combinations */
+ if (ien & STM32F4_I2C_CR2_ITEVTEN) {
+ possible_status = STM32F4_I2C_SR1_ITEVTEN_MASK;
+ if (ien & STM32F4_I2C_CR2_ITBUFEN)
+ possible_status |= STM32F4_I2C_SR1_ITBUFEN_MASK;
+ }
+
+ real_status = readl_relaxed(i2c_dev->base + STM32F4_I2C_SR1);
+
+ if (!(real_status & possible_status)) {
+ dev_dbg(i2c_dev->dev,
+ "spurious evt it (status=0x%08x, ien=0x%08x)\n",
+ real_status, ien);
+ return IRQ_NONE;
+ }
+
+ /* Use __fls() to check error bits first */
+ flag = __fls(real_status & possible_status);
+
+ switch (1 << flag) {
+ case STM32F4_I2C_SR1_SB:
+ stm32f4_i2c_write_byte(i2c_dev, msg->addr);
+ break;
+
+ case STM32F4_I2C_SR1_ADDR:
+ if (msg->addr & I2C_M_RD)
+ stm32f4_i2c_handle_rx_addr(i2c_dev);
+ else
+ sr2 = readl_relaxed(i2c_dev->base + STM32F4_I2C_SR2);
+
+ /* Enable ITBUF interrupts */
+ reg = i2c_dev->base + STM32F4_I2C_CR2;
+ stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR2_ITBUFEN);
+ break;
+
+ case STM32F4_I2C_SR1_BTF:
+ if (msg->addr & I2C_M_RD)
+ stm32f4_i2c_handle_rx_btf(i2c_dev);
+ else
+ stm32f4_i2c_handle_write(i2c_dev);
+ break;
+
+ case STM32F4_I2C_SR1_TXE:
+ stm32f4_i2c_handle_write(i2c_dev);
+ break;
+
+ case STM32F4_I2C_SR1_RXNE:
+ stm32f4_i2c_handle_read(i2c_dev);
+ break;
+
+ default:
+ dev_err(i2c_dev->dev,
+ "evt it unhandled: status=0x%08x)\n", real_status);
+ return IRQ_NONE;
+ }
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * stm32f4_i2c_isr_error() - Interrupt routine for I2C bus error
+ * @irq: interrupt number
+ * @data: Controller's private data
+ */
+static irqreturn_t stm32f4_i2c_isr_error(int irq, void *data)
+{
+ struct stm32f4_i2c_dev *i2c_dev = data;
+ struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
+ void __iomem *reg;
+ u32 real_status, possible_status, ien;
+ int flag;
+
+ ien = readl_relaxed(i2c_dev->base + STM32F4_I2C_CR2);
+ ien &= STM32F4_I2C_CR2_IRQ_MASK;
+ possible_status = 0;
+
+ /* Check possible status combinations */
+ if (ien & STM32F4_I2C_CR2_ITERREN)
+ possible_status = STM32F4_I2C_SR1_ITERREN_MASK;
+
+ real_status = readl_relaxed(i2c_dev->base + STM32F4_I2C_SR1);
+
+ if (!(real_status & possible_status)) {
+ dev_dbg(i2c_dev->dev,
+ "spurious err it (status=0x%08x, ien=0x%08x)\n",
+ real_status, ien);
+ return IRQ_NONE;
+ }
+
+ /* Use __fls() to check error bits first */
+ flag = __fls(real_status & possible_status);
+
+ switch (1 << flag) {
+ case STM32F4_I2C_SR1_BERR:
+ reg = i2c_dev->base + STM32F4_I2C_SR1;
+ stm32f4_i2c_clr_bits(reg, STM32F4_I2C_SR1_BERR);
+ msg->result = -EIO;
+ break;
+
+ case STM32F4_I2C_SR1_ARLO:
+ reg = i2c_dev->base + STM32F4_I2C_SR1;
+ stm32f4_i2c_clr_bits(reg, STM32F4_I2C_SR1_ARLO);
+ msg->result = -EAGAIN;
+ break;
+
+ case STM32F4_I2C_SR1_AF:
+ reg = i2c_dev->base + STM32F4_I2C_CR1;
+ stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_STOP);
+ msg->result = -EIO;
+ break;
+
+ default:
+ dev_err(i2c_dev->dev,
+ "err it unhandled: status=0x%08x)\n", real_status);
+ return IRQ_NONE;
+ }
+
+ stm32f4_i2c_soft_reset(i2c_dev);
+ stm32f4_i2c_disable_it(i2c_dev);
+ complete(&i2c_dev->complete);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * stm32f4_i2c_xfer_msg() - Transfer a single I2C message
+ * @i2c_dev: Controller's private data
+ * @msg: I2C message to transfer
+ * @is_first: first message of the sequence
+ * @is_last: last message of the sequence
+ */
+static int stm32f4_i2c_xfer_msg(struct stm32f4_i2c_dev *i2c_dev,
+ struct i2c_msg *msg, bool is_first,
+ bool is_last)
+{
+ struct stm32f4_i2c_msg *f4_msg = &i2c_dev->msg;
+ void __iomem *reg = i2c_dev->base + STM32F4_I2C_CR1;
+ unsigned long timeout;
+ u32 mask;
+ int ret;
+
+ f4_msg->addr = i2c_8bit_addr_from_msg(msg);
+ f4_msg->buf = msg->buf;
+ f4_msg->count = msg->len;
+ f4_msg->result = 0;
+ f4_msg->stop = is_last;
+
+ reinit_completion(&i2c_dev->complete);
+
+ /* Enable ITEVT and ITERR interrupts */
+ mask = STM32F4_I2C_CR2_ITEVTEN | STM32F4_I2C_CR2_ITERREN;
+ stm32f4_i2c_set_bits(i2c_dev->base + STM32F4_I2C_CR2, mask);
+
+ if (is_first) {
+ ret = stm32f4_i2c_wait_free_bus(i2c_dev);
+ if (ret)
+ return ret;
+
+ /* START generation */
+ stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_START);
+ }
+
+ timeout = wait_for_completion_timeout(&i2c_dev->complete,
+ i2c_dev->adap.timeout);
+ ret = f4_msg->result;
+
+ /* Disable PEC position Ack */
+ stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR1_POS);
+
+ if (!timeout)
+ ret = -ETIMEDOUT;
+
+ return ret;
+}
+
+/**
+ * stm32f4_i2c_xfer() - Transfer combined I2C message
+ * @i2c_adap: Adapter pointer to the controller
+ * @msgs: Pointer to data to be written.
+ * @num: Number of messages to be executed
+ */
+static int stm32f4_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[],
+ int num)
+{
+ struct stm32f4_i2c_dev *i2c_dev = i2c_get_adapdata(i2c_adap);
+ int ret, i;
+
+ ret = clk_enable(i2c_dev->clk);
+ if (ret) {
+ dev_err(i2c_dev->dev, "Failed to enable clock\n");
+ return ret;
+ }
+
+ stm32f4_i2c_hw_config(i2c_dev);
+
+ for (i = 0; i < num && !ret; i++)
+ ret = stm32f4_i2c_xfer_msg(i2c_dev, &msgs[i], i == 0,
+ i == num - 1);
+
+ clk_disable(i2c_dev->clk);
+
+ return (ret < 0) ? ret : i;
+}
+
+static u32 stm32f4_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm stm32f4_i2c_algo = {
+ .master_xfer = stm32f4_i2c_xfer,
+ .functionality = stm32f4_i2c_func,
+};
+
+static int stm32f4_i2c_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct stm32f4_i2c_dev *i2c_dev;
+ struct resource *res;
+ u32 clk_rate;
+ struct i2c_adapter *adap;
+ struct reset_control *rst;
+ int ret;
+
+ i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
+ if (!i2c_dev)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ i2c_dev->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(i2c_dev->base))
+ return PTR_ERR(i2c_dev->base);
+
+ i2c_dev->irq_event = irq_of_parse_and_map(np, 0);
+ if (!i2c_dev->irq_event) {
+ dev_err(&pdev->dev, "IRQ missing or invalid\n");
+ return -EINVAL;
+ }
+
+ i2c_dev->irq_error = irq_of_parse_and_map(np, 1);
+ if (!i2c_dev->irq_error) {
+ dev_err(&pdev->dev, "IRQ missing or invalid\n");
+ return -EINVAL;
+ }
+
+ i2c_dev->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(i2c_dev->clk)) {
+ dev_err(&pdev->dev, "Error: Missing controller clock\n");
+ return PTR_ERR(i2c_dev->clk);
+ }
+ ret = clk_prepare(i2c_dev->clk);
+ if (ret) {
+ dev_err(i2c_dev->dev, "Failed to prepare clock\n");
+ return ret;
+ }
+
+ rst = devm_reset_control_get(&pdev->dev, NULL);
+ if (IS_ERR(rst)) {
+ dev_err(&pdev->dev, "Error: Missing controller reset\n");
+ ret = PTR_ERR(rst);
+ goto clk_free;
+ }
+ reset_control_assert(rst);
+ udelay(2);
+ reset_control_deassert(rst);
+
+ i2c_dev->speed = STM32F4_I2C_SPEED_STANDARD;
+ ret = of_property_read_u32(np, "clock-frequency", &clk_rate);
+ if ((!ret) && (clk_rate == 400000))
+ i2c_dev->speed = STM32F4_I2C_SPEED_FAST;
+
+ i2c_dev->dev = &pdev->dev;
+
+ ret = devm_request_threaded_irq(&pdev->dev, i2c_dev->irq_event,
+ NULL, stm32f4_i2c_isr_event,
+ IRQF_ONESHOT, pdev->name, i2c_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request irq %i\n",
+ i2c_dev->irq_error);
+ goto clk_free;
+ }
+
+ ret = devm_request_threaded_irq(&pdev->dev, i2c_dev->irq_error,
+ NULL, stm32f4_i2c_isr_error,
+ IRQF_ONESHOT, pdev->name, i2c_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request irq %i\n",
+ i2c_dev->irq_error);
+ goto clk_free;
+ }
+
+ adap = &i2c_dev->adap;
+ i2c_set_adapdata(adap, i2c_dev);
+ snprintf(adap->name, sizeof(adap->name), "STM32 I2C(%pa)", &res->start);
+ adap->owner = THIS_MODULE;
+ adap->timeout = 2 * HZ;
+ adap->retries = 0;
+ adap->algo = &stm32f4_i2c_algo;
+ adap->dev.parent = &pdev->dev;
+ adap->dev.of_node = pdev->dev.of_node;
+
+ init_completion(&i2c_dev->complete);
+
+ ret = i2c_add_adapter(adap);
+ if (ret)
+ goto clk_free;
+
+ platform_set_drvdata(pdev, i2c_dev);
+
+ dev_info(i2c_dev->dev, "STM32F4 I2C driver initialized\n");
+
+ return 0;
+
+clk_free:
+ clk_unprepare(i2c_dev->clk);
+ return ret;
+}
+
+static int stm32f4_i2c_remove(struct platform_device *pdev)
+{
+ struct stm32f4_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&i2c_dev->adap);
+
+ clk_unprepare(i2c_dev->clk);
+
+ return 0;
+}
+
+static const struct of_device_id stm32f4_i2c_match[] = {
+ { .compatible = "st,stm32f4-i2c", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, stm32f4_i2c_match);
+
+static struct platform_driver stm32f4_i2c_driver = {
+ .driver = {
+ .name = "stm32f4-i2c",
+ .of_match_table = stm32f4_i2c_match,
+ },
+ .probe = stm32f4_i2c_probe,
+ .remove = stm32f4_i2c_remove,
+};
+
+module_platform_driver(stm32f4_i2c_driver);
+
+MODULE_AUTHOR("M'boumba Cedric Madianga <cedric.madianga@gmail.com>");
+MODULE_DESCRIPTION("STMicroelectronics STM32F4 I2C driver");
+MODULE_LICENSE("GPL v2");
--
1.9.1
^ permalink raw reply related
* [PATCH v5 1/5] dt-bindings: Document the STM32 I2C bindings
From: M'boumba Cedric Madianga @ 2016-12-08 8:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481185563-8735-1-git-send-email-cedric.madianga@gmail.com>
This patch adds documentation of device tree bindings for the STM32 I2C
controller.
Signed-off-by: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
Acked-by: Rob Herring <robh@kernel.org>
---
.../devicetree/bindings/i2c/i2c-stm32.txt | 33 ++++++++++++++++++++++
1 file changed, 33 insertions(+)
create mode 100644 Documentation/devicetree/bindings/i2c/i2c-stm32.txt
diff --git a/Documentation/devicetree/bindings/i2c/i2c-stm32.txt b/Documentation/devicetree/bindings/i2c/i2c-stm32.txt
new file mode 100644
index 0000000..78eaf7b
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/i2c-stm32.txt
@@ -0,0 +1,33 @@
+* I2C controller embedded in STMicroelectronics STM32 I2C platform
+
+Required properties :
+- compatible : Must be "st,stm32f4-i2c"
+- reg : Offset and length of the register set for the device
+- interrupts : Must contain the interrupt id for I2C event and then the
+ interrupt id for I2C error.
+- resets: Must contain the phandle to the reset controller.
+- clocks: Must contain the input clock of the I2C instance.
+- A pinctrl state named "default" must be defined to set pins in mode of
+ operation for I2C transfer
+- #address-cells = <1>;
+- #size-cells = <0>;
+
+Optional properties :
+- clock-frequency : Desired I2C bus clock frequency in Hz. If not specified,
+ the default 100 kHz frequency will be used. As only Normal and Fast modes
+ are supported, possible values are 100000 and 400000.
+
+Example :
+
+ i2c at 40005400 {
+ compatible = "st,stm32f4-i2c";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x40005400 0x400>;
+ interrupts = <31>,
+ <32>;
+ resets = <&rcc 277>;
+ clocks = <&rcc 0 149>;
+ pinctrl-0 = <&i2c1_sda_pin>, <&i2c1_scl_pin>;
+ pinctrl-names = "default";
+ };
--
1.9.1
^ permalink raw reply related
* [PATCH v5 0/5] Add support for the STM32F4 I2C
From: M'boumba Cedric Madianga @ 2016-12-08 8:25 UTC (permalink / raw)
To: linux-arm-kernel
This patchset adds support for the I2C controller embedded in STM32F4xx SoC.
It enables I2C transfer in interrupt mode with Standard-mode and Fast-mode bus
speed.
Changes since v4:
- Use clamp() function to use a value in a given range as it was missed in V4
M'boumba Cedric Madianga (5):
dt-bindings: Document the STM32 I2C bindings
i2c: Add STM32F4 I2C driver
ARM: dts: Add I2C1 support for STM32F429 SoC
ARM: dts: Add I2C1 support for STM32429 eval board
ARM: configs: Add I2C support for STM32 defconfig
.../devicetree/bindings/i2c/i2c-stm32.txt | 33 +
arch/arm/boot/dts/stm32429i-eval.dts | 6 +
arch/arm/boot/dts/stm32f429.dtsi | 23 +
arch/arm/configs/stm32_defconfig | 3 +
drivers/i2c/busses/Kconfig | 10 +
drivers/i2c/busses/Makefile | 1 +
drivers/i2c/busses/i2c-stm32f4.c | 851 +++++++++++++++++++++
7 files changed, 927 insertions(+)
create mode 100644 Documentation/devicetree/bindings/i2c/i2c-stm32.txt
create mode 100644 drivers/i2c/busses/i2c-stm32f4.c
--
1.9.1
^ permalink raw reply
* [PATCH 5/8] efi: Get the secure boot status [ver #5]
From: David Howells @ 2016-12-08 8:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161208065735.GB8549@wunner.de>
How about the attached?
Thanks,
David
---
commit 6788837a26d517d10d00138aadd338cc73d69237
Author: David Howells <dhowells@redhat.com>
Date: Mon Nov 21 23:55:55 2016 +0000
efi: Get the secure boot status
Get the firmware's secure-boot status in the kernel boot wrapper and stash
it somewhere that the main kernel image can find.
The efi_get_secureboot() function is extracted from the arm stub and (a)
generalised so that it can be called from x86 and (b) made to use
efi_call_runtime() so that it can be run in mixed-mode.
Suggested-by: Lukas Wunner <lukas@wunner.de>
Signed-off-by: David Howells <dhowells@redhat.com>
diff --git a/Documentation/x86/zero-page.txt b/Documentation/x86/zero-page.txt
index 95a4d34af3fd..b8527c6b7646 100644
--- a/Documentation/x86/zero-page.txt
+++ b/Documentation/x86/zero-page.txt
@@ -31,6 +31,8 @@ Offset Proto Name Meaning
1E9/001 ALL eddbuf_entries Number of entries in eddbuf (below)
1EA/001 ALL edd_mbr_sig_buf_entries Number of entries in edd_mbr_sig_buffer
(below)
+1EB/001 ALL kbd_status Numlock is enabled
+1EC/001 ALL secure_boot Secure boot is enabled in the firmware
1EF/001 ALL sentinel Used to detect broken bootloaders
290/040 ALL edd_mbr_sig_buffer EDD MBR signatures
2D0/A00 ALL e820_map E820 memory map table
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index c8c32ebcdfdb..5b151c262ac2 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -1158,6 +1158,8 @@ struct boot_params *efi_main(struct efi_config *c,
else
setup_boot_services32(efi_early);
+ boot_params->secure_boot = efi_get_secureboot(sys_table);
+
setup_graphics(boot_params);
setup_efi_pci(boot_params);
diff --git a/arch/x86/boot/compressed/head_32.S b/arch/x86/boot/compressed/head_32.S
index d85b9625e836..c635f7e32f5c 100644
--- a/arch/x86/boot/compressed/head_32.S
+++ b/arch/x86/boot/compressed/head_32.S
@@ -61,6 +61,7 @@
__HEAD
ENTRY(startup_32)
+ movb $0, BP_secure_boot(%esi)
#ifdef CONFIG_EFI_STUB
jmp preferred_addr
diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
index beab8322f72a..ccd2c7461b7f 100644
--- a/arch/x86/boot/compressed/head_64.S
+++ b/arch/x86/boot/compressed/head_64.S
@@ -244,6 +244,7 @@ ENTRY(startup_64)
* that maps our entire kernel(text+data+bss+brk), zero page
* and command line.
*/
+ movb $0, BP_secure_boot(%rsi)
#ifdef CONFIG_EFI_STUB
/*
* The entry point for the PE/COFF executable is efi_pe_entry, so
diff --git a/arch/x86/include/asm/bootparam_utils.h b/arch/x86/include/asm/bootparam_utils.h
index 4a8cb8d7cbd5..7e16d53ff6a3 100644
--- a/arch/x86/include/asm/bootparam_utils.h
+++ b/arch/x86/include/asm/bootparam_utils.h
@@ -38,9 +38,10 @@ static void sanitize_boot_params(struct boot_params *boot_params)
memset(&boot_params->ext_ramdisk_image, 0,
(char *)&boot_params->efi_info -
(char *)&boot_params->ext_ramdisk_image);
- memset(&boot_params->kbd_status, 0,
+ boot_params->kbd_status = 0;
+ memset(&boot_params->_pad5, 0,
(char *)&boot_params->hdr -
- (char *)&boot_params->kbd_status);
+ (char *)&boot_params->_pad5);
memset(&boot_params->_pad7[0], 0,
(char *)&boot_params->edd_mbr_sig_buffer[0] -
(char *)&boot_params->_pad7[0]);
diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h
index b10bf319ed20..5138dacf8bb8 100644
--- a/arch/x86/include/uapi/asm/bootparam.h
+++ b/arch/x86/include/uapi/asm/bootparam.h
@@ -135,7 +135,8 @@ struct boot_params {
__u8 eddbuf_entries; /* 0x1e9 */
__u8 edd_mbr_sig_buf_entries; /* 0x1ea */
__u8 kbd_status; /* 0x1eb */
- __u8 _pad5[3]; /* 0x1ec */
+ __u8 secure_boot; /* 0x1ec */
+ __u8 _pad5[2]; /* 0x1ed */
/*
* The sentinel is set to a nonzero value (0xff) in header.S.
*
diff --git a/arch/x86/kernel/asm-offsets.c b/arch/x86/kernel/asm-offsets.c
index c62e015b126c..de827d6ac8c2 100644
--- a/arch/x86/kernel/asm-offsets.c
+++ b/arch/x86/kernel/asm-offsets.c
@@ -81,6 +81,7 @@ void common(void) {
BLANK();
OFFSET(BP_scratch, boot_params, scratch);
+ OFFSET(BP_secure_boot, boot_params, secure_boot);
OFFSET(BP_loadflags, boot_params, hdr.loadflags);
OFFSET(BP_hardware_subarch, boot_params, hdr.hardware_subarch);
OFFSET(BP_version, boot_params, hdr.version);
diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
index 6621b13c370f..9af966863612 100644
--- a/drivers/firmware/efi/libstub/Makefile
+++ b/drivers/firmware/efi/libstub/Makefile
@@ -28,7 +28,7 @@ OBJECT_FILES_NON_STANDARD := y
# Prevents link failures: __sanitizer_cov_trace_pc() is not linked in.
KCOV_INSTRUMENT := n
-lib-y := efi-stub-helper.o gop.o
+lib-y := efi-stub-helper.o gop.o secureboot.o
# include the stub's generic dependencies from lib/ when building for ARM/arm64
arm-deps := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c fdt_empty_tree.c fdt_sw.c sort.c
diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c
index b4f7d78f9e8b..9984d0442442 100644
--- a/drivers/firmware/efi/libstub/arm-stub.c
+++ b/drivers/firmware/efi/libstub/arm-stub.c
@@ -20,52 +20,6 @@
bool __nokaslr;
-static int efi_get_secureboot(efi_system_table_t *sys_table_arg)
-{
- static efi_char16_t const sb_var_name[] = {
- 'S', 'e', 'c', 'u', 'r', 'e', 'B', 'o', 'o', 't', 0 };
- static efi_char16_t const sm_var_name[] = {
- 'S', 'e', 't', 'u', 'p', 'M', 'o', 'd', 'e', 0 };
-
- efi_guid_t var_guid = EFI_GLOBAL_VARIABLE_GUID;
- efi_get_variable_t *f_getvar = sys_table_arg->runtime->get_variable;
- u8 val;
- unsigned long size = sizeof(val);
- efi_status_t status;
-
- status = f_getvar((efi_char16_t *)sb_var_name, (efi_guid_t *)&var_guid,
- NULL, &size, &val);
-
- if (status != EFI_SUCCESS)
- goto out_efi_err;
-
- if (val == 0)
- return 0;
-
- status = f_getvar((efi_char16_t *)sm_var_name, (efi_guid_t *)&var_guid,
- NULL, &size, &val);
-
- if (status != EFI_SUCCESS)
- goto out_efi_err;
-
- if (val == 1)
- return 0;
-
- return 1;
-
-out_efi_err:
- switch (status) {
- case EFI_NOT_FOUND:
- return 0;
- case EFI_DEVICE_ERROR:
- return -EIO;
- case EFI_SECURITY_VIOLATION:
- return -EACCES;
- default:
- return -EINVAL;
- }
-}
-
efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg,
void *__image, void **__fh)
{
@@ -226,7 +180,7 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table,
efi_guid_t loaded_image_proto = LOADED_IMAGE_PROTOCOL_GUID;
unsigned long reserve_addr = 0;
unsigned long reserve_size = 0;
- int secure_boot = 0;
+ enum efi_secureboot_mode secure_boot;
struct screen_info *si;
/* Check if we were booted by the EFI firmware */
@@ -296,19 +250,14 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table,
pr_efi_err(sys_table, "Failed to parse EFI cmdline options\n");
secure_boot = efi_get_secureboot(sys_table);
- if (secure_boot > 0)
- pr_efi(sys_table, "UEFI Secure Boot is enabled.\n");
-
- if (secure_boot < 0) {
- pr_efi_err(sys_table,
- "could not determine UEFI Secure Boot status.\n");
- }
/*
- * Unauthenticated device tree data is a security hazard, so
- * ignore 'dtb=' unless UEFI Secure Boot is disabled.
+ * Unauthenticated device tree data is a security hazard, so ignore
+ * 'dtb=' unless UEFI Secure Boot is disabled. We assume that secure
+ * boot is enabled if we can't determine its state.
*/
- if (secure_boot != 0 && strstr(cmdline_ptr, "dtb=")) {
+ if (secure_boot != efi_secureboot_mode_disabled &&
+ strstr(cmdline_ptr, "dtb=")) {
pr_efi(sys_table, "Ignoring DTB from command line.\n");
} else {
status = handle_cmdline_files(sys_table, image, cmdline_ptr,
diff --git a/drivers/firmware/efi/libstub/secureboot.c b/drivers/firmware/efi/libstub/secureboot.c
new file mode 100644
index 000000000000..62d6904da800
--- /dev/null
+++ b/drivers/firmware/efi/libstub/secureboot.c
@@ -0,0 +1,63 @@
+/*
+ * Secure boot handling.
+ *
+ * Copyright (C) 2013,2014 Linaro Limited
+ * Roy Franz <roy.franz at linaro.org
+ * Copyright (C) 2013 Red Hat, Inc.
+ * Mark Salter <msalter@redhat.com>
+ *
+ * This file is part of the Linux kernel, and is made available under the
+ * terms of the GNU General Public License version 2.
+ *
+ */
+
+#include <linux/efi.h>
+#include <asm/efi.h>
+
+/* BIOS variables */
+static const efi_guid_t efi_variable_guid = EFI_GLOBAL_VARIABLE_GUID;
+static const efi_char16_t const efi_SecureBoot_name[] = {
+ 'S', 'e', 'c', 'u', 'r', 'e', 'B', 'o', 'o', 't', 0
+};
+static const efi_char16_t const efi_SetupMode_name[] = {
+ 'S', 'e', 't', 'u', 'p', 'M', 'o', 'd', 'e', 0
+};
+
+#define get_efi_var(name, vendor, ...) \
+ efi_call_runtime(get_variable, \
+ (efi_char16_t *)(name), (efi_guid_t *)(vendor), \
+ __VA_ARGS__);
+
+/*
+ * Determine whether we're in secure boot mode.
+ */
+enum efi_secureboot_mode efi_get_secureboot(efi_system_table_t *sys_table_arg)
+{
+ u8 secboot, setupmode;
+ unsigned long size;
+ efi_status_t status;
+
+ size = sizeof(secboot);
+ status = get_efi_var(efi_SecureBoot_name, &efi_variable_guid,
+ NULL, &size, &secboot);
+ if (status != EFI_SUCCESS)
+ goto out_efi_err;
+
+ size = sizeof(setupmode);
+ status = get_efi_var(efi_SetupMode_name, &efi_variable_guid,
+ NULL, &size, &setupmode);
+ if (status != EFI_SUCCESS)
+ goto out_efi_err;
+
+ if (secboot == 0 || setupmode == 1)
+ return efi_secureboot_mode_disabled;
+
+ pr_efi(sys_table_arg, "UEFI Secure Boot is enabled.\n");
+ return efi_secureboot_mode_enabled;
+
+out_efi_err:
+ pr_efi_err(sys_table_arg, "Could not determine UEFI Secure Boot status.\n");
+ if (status == EFI_NOT_FOUND)
+ return efi_secureboot_mode_disabled;
+ return efi_secureboot_mode_unknown;
+}
diff --git a/include/linux/efi.h b/include/linux/efi.h
index c7904556d7a8..92e23f03045e 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -1477,6 +1477,14 @@ efi_status_t efi_setup_gop(efi_system_table_t *sys_table_arg,
bool efi_runtime_disabled(void);
extern void efi_call_virt_check_flags(unsigned long flags, const char *call);
+enum efi_secureboot_mode {
+ efi_secureboot_mode_unset,
+ efi_secureboot_mode_unknown,
+ efi_secureboot_mode_disabled,
+ efi_secureboot_mode_enabled,
+};
+enum efi_secureboot_mode efi_get_secureboot(efi_system_table_t *sys_table);
+
/*
* Arch code can implement the following three template macros, avoiding
* reptition for the void/non-void return cases of {__,}efi_call_virt():
^ permalink raw reply related
* [RFC v3 09/10] iommu/arm-smmu: Implement reserved region get/put callbacks
From: Auger Eric @ 2016-12-08 7:57 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <5de00158-c82d-6b47-cf64-d4ba0183868d@arm.com>
Hi Robin,
On 07/12/2016 19:24, Robin Murphy wrote:
> On 07/12/16 15:02, Auger Eric wrote:
>> Hi Robin,
>> On 06/12/2016 19:55, Robin Murphy wrote:
>>> On 15/11/16 13:09, Eric Auger wrote:
>>>> The get() populates the list with the PCI host bridge windows
>>>> and the MSI IOVA range.
>>>>
>>>> At the moment an arbitray MSI IOVA window is set at 0x8000000
>>>> of size 1MB. This will allow to report those info in iommu-group
>>>> sysfs?
>>
>>
>> First thank you for reviewing the series. This is definitively helpful!
>>>>
>>>> Signed-off-by: Eric Auger <eric.auger@redhat.com>
>>>>
>>>> ---
>>>>
>>>> RFC v2 -> v3:
>>>> - use existing get/put_resv_regions
>>>>
>>>> RFC v1 -> v2:
>>>> - use defines for MSI IOVA base and length
>>>> ---
>>>> drivers/iommu/arm-smmu.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++
>>>> 1 file changed, 52 insertions(+)
>>>>
>>>> diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
>>>> index 8f72814..81f1a83 100644
>>>> --- a/drivers/iommu/arm-smmu.c
>>>> +++ b/drivers/iommu/arm-smmu.c
>>>> @@ -278,6 +278,9 @@ enum arm_smmu_s2cr_privcfg {
>>>>
>>>> #define FSYNR0_WNR (1 << 4)
>>>>
>>>> +#define MSI_IOVA_BASE 0x8000000
>>>> +#define MSI_IOVA_LENGTH 0x100000
>>>> +
>>>> static int force_stage;
>>>> module_param(force_stage, int, S_IRUGO);
>>>> MODULE_PARM_DESC(force_stage,
>>>> @@ -1545,6 +1548,53 @@ static int arm_smmu_of_xlate(struct device *dev, struct of_phandle_args *args)
>>>> return iommu_fwspec_add_ids(dev, &fwid, 1);
>>>> }
>>>>
>>>> +static void arm_smmu_get_resv_regions(struct device *dev,
>>>> + struct list_head *head)
>>>> +{
>>>> + struct iommu_resv_region *region;
>>>> + struct pci_host_bridge *bridge;
>>>> + struct resource_entry *window;
>>>> +
>>>> + /* MSI region */
>>>> + region = iommu_alloc_resv_region(MSI_IOVA_BASE, MSI_IOVA_LENGTH,
>>>> + IOMMU_RESV_MSI);
>>>> + if (!region)
>>>> + return;
>>>> +
>>>> + list_add_tail(®ion->list, head);
>>>> +
>>>> + if (!dev_is_pci(dev))
>>>> + return;
>>>> +
>>>> + bridge = pci_find_host_bridge(to_pci_dev(dev)->bus);
>>>> +
>>>> + resource_list_for_each_entry(window, &bridge->windows) {
>>>> + phys_addr_t start;
>>>> + size_t length;
>>>> +
>>>> + if (resource_type(window->res) != IORESOURCE_MEM &&
>>>> + resource_type(window->res) != IORESOURCE_IO)
>>>
>>> As Joerg commented elsewhere, considering anything other than memory
>>> resources isn't right (I appreciate you've merely copied my own mistake
>>> here). We need some other way to handle root complexes where the CPU
>>> MMIO views of PCI windows appear in PCI memory space - using the I/O
>>> address of I/O resources only works by chance on Juno, and it still
>>> doesn't account for config space. I suggest we just leave that out for
>>> the time being to make life easier (does it even apply to anything other
>>> than Juno?) and figure it out later.
>> OK so I understand I should remove IORESOURCE_IO check.
>>>
>>>> + continue;
>>>> +
>>>> + start = window->res->start - window->offset;
>>>> + length = window->res->end - window->res->start + 1;
>>>> + region = iommu_alloc_resv_region(start, length,
>>>> + IOMMU_RESV_NOMAP);
>>>> + if (!region)
>>>> + return;
>>>> + list_add_tail(®ion->list, head);
>>>> + }
>>>> +}
>>>
>>> Either way, there's nothing SMMU-specific about PCI windows. The fact
>>> that we'd have to copy-paste all of this into the SMMUv3 driver
>>> unchanged suggests it should go somewhere common (although I would be
>>> inclined to leave the insertion of the fake MSI region to driver-private
>>> wrappers). As I said before, the current iova_reserve_pci_windows()
>>> simply wants splitting into appropriate public callbacks for
>>> get_resv_regions and apply_resv_regions.
>> Do you mean somewhere common in the arm-smmu subsystem (new file) or in
>> another subsystem (pci?)
>>
>> More generally the current implementation does not handle the case where
>> any of those PCIe host bridge window collide with the MSI window. To me
>> this is a flaw.
>> 1) Either we take into account the PCIe windows and prevent any
>> collision when allocating the MSI window.
>> 2) or we do not care about PCIe host bridge windows at kernel level.
>
> Even more generally, the MSI window also needs to avoid any other
> IOMMU-specific reserved regions as well - fortunately I don't think
> there's any current intersection between platforms with RMRR-type
> reservations and platforms which require MSI mapping - so I think we've
> got enough freedom for the moment, but it's certainly an argument in
> favour of ultimately expressing PCI windows through the same mechanism
> to keep everything in the same place. The other big advantage of
> reserved regions is that they will automatically apply to DMA domains as
> well.
>
>> If 1) we are back to the original issue of where do we put the MSI
>> window. Obviously at a place which might not be QEMU friendly anymore.
>> What allocation policy shall we use?
>>
>> Second option - sorry I may look stubborn - which I definitively prefer
>> and which was also advocated by Alex, we handle PCI host bridge windows
>> at user level. MSI window is reported through the iommu group sysfs.
>> PCIe host bridge windows can be enumerated through /proc/iomem. Both x86
>> iommu and arm smmu would report an MSI reserved window. ARM MSI window
>> would become a de facto reserved window for guests.
>
> So from the ABI perspective, the sysfs iommu_group/*/reserved_regions
> represents a minimum set of regions (MSI, RMRR, etc.) which definitely
> *must* be reserved, but offers no guarantee that there aren't also other
> regions not represented there. That seems reasonable to start with, and
> still leaves us free to expand the scope of reserved regions in future
> without breaking anything.
>
>> Thoughts?
>
> I like the second option too - "grep PCI /proc/iomem" already catches
> more than enumerating the resources does (i.e. ECAM space) - and neither
> does it preclude growing the more extensive version on top over time.
>
> For the sake of moving forward, I'd be happy with just dropping the PCI
> stuff from here, and leaving the SMMU drivers exposing the single
> hard-coded MSI region directly (to be fair, it'd hardly be the first
> function which is identical between the two).
OK cool
Thanks
Eric
We can take a look into
> making iommu-dma implement PCI windows as nomap resv_regions properly as
> an orthogonal thing (for the sake of DMA domains), after which we should
> be in a position to drop the hard-coding and start placing the MSI
> window dynamically where appropriate.
>
> Robin.
>
>>>> +static void arm_smmu_put_resv_regions(struct device *dev,
>>>> + struct list_head *head)
>>>> +{
>>>> + struct iommu_resv_region *entry, *next;
>>>> +
>>>> + list_for_each_entry_safe(entry, next, head, list)
>>>> + kfree(entry);
>>>> +}
>>>> +
>>>> static struct iommu_ops arm_smmu_ops = {
>>>> .capable = arm_smmu_capable,
>>>> .domain_alloc = arm_smmu_domain_alloc,
>>>> @@ -1560,6 +1610,8 @@ static int arm_smmu_of_xlate(struct device *dev, struct of_phandle_args *args)
>>>> .domain_get_attr = arm_smmu_domain_get_attr,
>>>> .domain_set_attr = arm_smmu_domain_set_attr,
>>>> .of_xlate = arm_smmu_of_xlate,
>>>> + .get_resv_regions = arm_smmu_get_resv_regions,
>>>> + .put_resv_regions = arm_smmu_put_resv_regions,
>>>> .pgsize_bitmap = -1UL, /* Restricted during device attach */
>>>> };
>>>>
>>>>
>>>
>>>
>>> _______________________________________________
>>> linux-arm-kernel mailing list
>>> linux-arm-kernel at lists.infradead.org
>>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>>>
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
^ permalink raw reply
* [RFC v3 00/10] KVM PCIe/MSI passthrough on ARM/ARM64 and IOVA reserved regions
From: Auger Eric @ 2016-12-08 7:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <165d4f72-ef74-2db8-166a-1f90208315c8@codeaurora.org>
Hi Shanker,
On 07/12/2016 19:52, Shanker Donthineni wrote:
> Hi Eric,
>
> Is there any reason why you are not supporting SMMUv3 driver? Qualcomm
> hardware doesn't not support SMMUv2 hardware, please add support for
> SMMUv3 in next patch set. I've ported ' RFC,v3,09/10] iommu/arm-smmu:
> Implement reserved region get/put callbacks' to SMMUv3 driver and tested
> device-pass-through feature on Qualcomm server platform without any issue.
>
> Tested-by: Shanker Donthineni <shankerd@codeaurora.org>
Thanks!
No reason behind not supporting smmuv3 except I don't have any HW to test.
I will add this support in next version.
Thanks
Eric
^ permalink raw reply
* [PATCH v2] PCI: designware: add host_init error handling
From: Jisheng Zhang @ 2016-12-08 7:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481106769-1404-1-git-send-email-srinivas.kandagatla@linaro.org>
Hi Srinivas,
On Wed, 7 Dec 2016 10:32:49 +0000 Srinivas Kandagatla wrote:
> This patch add support to return value from host_init() callback from drivers,
> so that the designware libary can handle or pass it to proper place. Issue with
> void return type is that errors or error handling within host_init() callback
> are never know to designware code, which could go ahead and access registers
> even in error cases.
>
> Typical case in qcom controller driver is to turn off clks in case of errors,
I have similar idea last year
https://patchwork.kernel.org/patch/7602421/
But finally I dropped the patch. The reason is PCIe supports hotplug. I
noticed that most *errors* are due to the link can't be established, for
example, the exynos, dra7xx in your below patch. I think FAIL_TO_ESTABLISH_LINK
is a normal case if we didn't plug in the PCIe DP, then in this case I think
it can't be considered as *error* and we still need to continue. What about
your opinion?
Thanks,
Jisheng
> if designware code continues to read/write register when clocks are turned off
> the board would reboot/lockup.
>
> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
> ---
> Currently designware code does not have a way return errors generated
> as part of host_init() callback in controller drivers. This is an issue
> with controller drivers like qcom which turns off the clocks in error
> handling path. As the dw core is un aware of this would continue to
> access registers which faults resulting in board reboots/hangs.
>
> There are two ways to solve this issue,
> one is remove error handling in the qcom controller host_init() function
> other is to handle error and pass back to dw core code which would then
> pass back to controller driver as part of dw_pcie_host_init() return value.
>
> Second option seems more sensible and correct way to fix the issue,
> this patch does the same.
>
> As part of this change to host_init() return type I had to patch other
> ihost controller drivers which use dw core. Most of the changes to other drivers
> are to return proper error codes to upper layer.
> Only compile tested drivers.
>
> Changes since RFC:
> - Add error handling to other drivers as suggested by Joao Pinto
>
> drivers/pci/host/pci-dra7xx.c | 10 ++++++++--
> drivers/pci/host/pci-exynos.c | 10 ++++++++--
> drivers/pci/host/pci-imx6.c | 10 ++++++++--
> drivers/pci/host/pci-keystone.c | 10 ++++++++--
> drivers/pci/host/pci-layerscape.c | 22 +++++++++++++---------
> drivers/pci/host/pcie-armada8k.c | 4 +++-
> drivers/pci/host/pcie-designware-plat.c | 10 ++++++++--
> drivers/pci/host/pcie-designware.c | 4 +++-
> drivers/pci/host/pcie-designware.h | 2 +-
> drivers/pci/host/pcie-qcom.c | 5 +++--
> drivers/pci/host/pcie-spear13xx.c | 10 ++++++++--
> 11 files changed, 71 insertions(+), 26 deletions(-)
>
> diff --git a/drivers/pci/host/pci-dra7xx.c b/drivers/pci/host/pci-dra7xx.c
> index 9595fad..811f0f9 100644
> --- a/drivers/pci/host/pci-dra7xx.c
> +++ b/drivers/pci/host/pci-dra7xx.c
> @@ -127,9 +127,10 @@ static void dra7xx_pcie_enable_interrupts(struct dra7xx_pcie *dra7xx)
> LEG_EP_INTERRUPTS);
> }
>
> -static void dra7xx_pcie_host_init(struct pcie_port *pp)
> +static int dra7xx_pcie_host_init(struct pcie_port *pp)
> {
> struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pp);
> + int ret;
>
> pp->io_base &= DRA7XX_CPU_TO_BUS_ADDR;
> pp->mem_base &= DRA7XX_CPU_TO_BUS_ADDR;
> @@ -138,10 +139,15 @@ static void dra7xx_pcie_host_init(struct pcie_port *pp)
>
> dw_pcie_setup_rc(pp);
>
> - dra7xx_pcie_establish_link(dra7xx);
> + ret = dra7xx_pcie_establish_link(dra7xx);
> + if (ret < 0)
> + return ret;
> +
> if (IS_ENABLED(CONFIG_PCI_MSI))
> dw_pcie_msi_init(pp);
> dra7xx_pcie_enable_interrupts(dra7xx);
> +
> + return 0;
> }
>
> static struct pcie_host_ops dra7xx_pcie_host_ops = {
> diff --git a/drivers/pci/host/pci-exynos.c b/drivers/pci/host/pci-exynos.c
> index f1c544b..c116fd9 100644
> --- a/drivers/pci/host/pci-exynos.c
> +++ b/drivers/pci/host/pci-exynos.c
> @@ -458,12 +458,18 @@ static int exynos_pcie_link_up(struct pcie_port *pp)
> return 0;
> }
>
> -static void exynos_pcie_host_init(struct pcie_port *pp)
> +static int exynos_pcie_host_init(struct pcie_port *pp)
> {
> struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp);
> + int ret;
> +
> + ret = exynos_pcie_establish_link(exynos_pcie);
> + if (ret < 0)
> + return ret;
>
> - exynos_pcie_establish_link(exynos_pcie);
> exynos_pcie_enable_interrupts(exynos_pcie);
> +
> + return 0;
> }
>
> static struct pcie_host_ops exynos_pcie_host_ops = {
> diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c
> index c8cefb0..1251e92 100644
> --- a/drivers/pci/host/pci-imx6.c
> +++ b/drivers/pci/host/pci-imx6.c
> @@ -550,18 +550,24 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
> return ret;
> }
>
> -static void imx6_pcie_host_init(struct pcie_port *pp)
> +static int imx6_pcie_host_init(struct pcie_port *pp)
> {
> struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);
> + int ret;
>
> imx6_pcie_assert_core_reset(imx6_pcie);
> imx6_pcie_init_phy(imx6_pcie);
> imx6_pcie_deassert_core_reset(imx6_pcie);
> dw_pcie_setup_rc(pp);
> - imx6_pcie_establish_link(imx6_pcie);
> + ret = imx6_pcie_establish_link(imx6_pcie);
> +
> + if (ret < 0)
> + return ret;
>
> if (IS_ENABLED(CONFIG_PCI_MSI))
> dw_pcie_msi_init(pp);
> +
> + return 0;
> }
>
> static int imx6_pcie_link_up(struct pcie_port *pp)
> diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/host/pci-keystone.c
> index 043c19a..4067a75 100644
> --- a/drivers/pci/host/pci-keystone.c
> +++ b/drivers/pci/host/pci-keystone.c
> @@ -260,12 +260,16 @@ static int keystone_pcie_fault(unsigned long addr, unsigned int fsr,
> return 0;
> }
>
> -static void __init ks_pcie_host_init(struct pcie_port *pp)
> +static int __init ks_pcie_host_init(struct pcie_port *pp)
> {
> struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
> u32 val;
> + int ret;
> +
> + ret = ks_pcie_establish_link(ks_pcie);
> + if (ret < 0)
> + return ret;
>
> - ks_pcie_establish_link(ks_pcie);
> ks_dw_pcie_setup_rc_app_regs(ks_pcie);
> ks_pcie_setup_interrupts(ks_pcie);
> writew(PCI_IO_RANGE_TYPE_32 | (PCI_IO_RANGE_TYPE_32 << 8),
> @@ -287,6 +291,8 @@ static void __init ks_pcie_host_init(struct pcie_port *pp)
> */
> hook_fault_code(17, keystone_pcie_fault, SIGBUS, 0,
> "Asynchronous external abort");
> +
> + return 0;
> }
>
> static struct pcie_host_ops keystone_pcie_host_ops = {
> diff --git a/drivers/pci/host/pci-layerscape.c b/drivers/pci/host/pci-layerscape.c
> index 6537079..60c8b84 100644
> --- a/drivers/pci/host/pci-layerscape.c
> +++ b/drivers/pci/host/pci-layerscape.c
> @@ -103,30 +103,32 @@ static int ls1021_pcie_link_up(struct pcie_port *pp)
> return 1;
> }
>
> -static void ls1021_pcie_host_init(struct pcie_port *pp)
> +static int ls1021_pcie_host_init(struct pcie_port *pp)
> {
> struct device *dev = pp->dev;
> struct ls_pcie *pcie = to_ls_pcie(pp);
> u32 index[2];
> + int ret;
>
> pcie->scfg = syscon_regmap_lookup_by_phandle(dev->of_node,
> "fsl,pcie-scfg");
> if (IS_ERR(pcie->scfg)) {
> dev_err(dev, "No syscfg phandle specified\n");
> - pcie->scfg = NULL;
> - return;
> + return PTR_ERR(pcie->scfg);
> }
>
> - if (of_property_read_u32_array(dev->of_node,
> - "fsl,pcie-scfg", index, 2)) {
> - pcie->scfg = NULL;
> - return;
> - }
> + ret = of_property_read_u32_array(dev->of_node,
> + "fsl,pcie-scfg", index, 2);
> + if (ret < 0)
> + return ret;
> +
> pcie->index = index[1];
>
> dw_pcie_setup_rc(pp);
>
> ls_pcie_drop_msg_tlp(pcie);
> +
> + return 0;
> }
>
> static int ls_pcie_link_up(struct pcie_port *pp)
> @@ -144,7 +146,7 @@ static int ls_pcie_link_up(struct pcie_port *pp)
> return 1;
> }
>
> -static void ls_pcie_host_init(struct pcie_port *pp)
> +static int ls_pcie_host_init(struct pcie_port *pp)
> {
> struct ls_pcie *pcie = to_ls_pcie(pp);
>
> @@ -153,6 +155,8 @@ static void ls_pcie_host_init(struct pcie_port *pp)
> ls_pcie_clear_multifunction(pcie);
> ls_pcie_drop_msg_tlp(pcie);
> iowrite32(0, pcie->pp.dbi_base + PCIE_DBI_RO_WR_EN);
> +
> + return 0;
> }
>
> static int ls_pcie_msi_host_init(struct pcie_port *pp,
> diff --git a/drivers/pci/host/pcie-armada8k.c b/drivers/pci/host/pcie-armada8k.c
> index 0ac0f18..29bdd8b 100644
> --- a/drivers/pci/host/pcie-armada8k.c
> +++ b/drivers/pci/host/pcie-armada8k.c
> @@ -134,12 +134,14 @@ static void armada8k_pcie_establish_link(struct armada8k_pcie *pcie)
> dev_err(pp->dev, "Link not up after reconfiguration\n");
> }
>
> -static void armada8k_pcie_host_init(struct pcie_port *pp)
> +static int armada8k_pcie_host_init(struct pcie_port *pp)
> {
> struct armada8k_pcie *pcie = to_armada8k_pcie(pp);
>
> dw_pcie_setup_rc(pp);
> armada8k_pcie_establish_link(pcie);
> +
> + return 0;
> }
>
> static irqreturn_t armada8k_pcie_irq_handler(int irq, void *arg)
> diff --git a/drivers/pci/host/pcie-designware-plat.c b/drivers/pci/host/pcie-designware-plat.c
> index 1a02038..e01adbb 100644
> --- a/drivers/pci/host/pcie-designware-plat.c
> +++ b/drivers/pci/host/pcie-designware-plat.c
> @@ -35,13 +35,19 @@ static irqreturn_t dw_plat_pcie_msi_irq_handler(int irq, void *arg)
> return dw_handle_msi_irq(pp);
> }
>
> -static void dw_plat_pcie_host_init(struct pcie_port *pp)
> +static int dw_plat_pcie_host_init(struct pcie_port *pp)
> {
> + int ret;
> +
> dw_pcie_setup_rc(pp);
> - dw_pcie_wait_for_link(pp);
> + ret = dw_pcie_wait_for_link(pp);
> + if (ret)
> + return ret;
>
> if (IS_ENABLED(CONFIG_PCI_MSI))
> dw_pcie_msi_init(pp);
> +
> + return 0;
> }
>
> static struct pcie_host_ops dw_plat_pcie_host_ops = {
> diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
> index bed1999..4a81b72 100644
> --- a/drivers/pci/host/pcie-designware.c
> +++ b/drivers/pci/host/pcie-designware.c
> @@ -638,7 +638,9 @@ int dw_pcie_host_init(struct pcie_port *pp)
> }
>
> if (pp->ops->host_init)
> - pp->ops->host_init(pp);
> + ret = pp->ops->host_init(pp);
> + if (ret < 0)
> + goto error;
>
> pp->root_bus_nr = pp->busn->start;
> if (IS_ENABLED(CONFIG_PCI_MSI)) {
> diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
> index a567ea2..eacf18f 100644
> --- a/drivers/pci/host/pcie-designware.h
> +++ b/drivers/pci/host/pcie-designware.h
> @@ -63,7 +63,7 @@ struct pcie_host_ops {
> int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
> unsigned int devfn, int where, int size, u32 val);
> int (*link_up)(struct pcie_port *pp);
> - void (*host_init)(struct pcie_port *pp);
> + int (*host_init)(struct pcie_port *pp);
> void (*msi_set_irq)(struct pcie_port *pp, int irq);
> void (*msi_clear_irq)(struct pcie_port *pp, int irq);
> phys_addr_t (*get_msi_addr)(struct pcie_port *pp);
> diff --git a/drivers/pci/host/pcie-qcom.c b/drivers/pci/host/pcie-qcom.c
> index 3593640..7d5fb38 100644
> --- a/drivers/pci/host/pcie-qcom.c
> +++ b/drivers/pci/host/pcie-qcom.c
> @@ -429,7 +429,7 @@ static int qcom_pcie_link_up(struct pcie_port *pp)
> return !!(val & PCI_EXP_LNKSTA_DLLLA);
> }
>
> -static void qcom_pcie_host_init(struct pcie_port *pp)
> +static int qcom_pcie_host_init(struct pcie_port *pp)
> {
> struct qcom_pcie *pcie = to_qcom_pcie(pp);
> int ret;
> @@ -455,12 +455,13 @@ static void qcom_pcie_host_init(struct pcie_port *pp)
> if (ret)
> goto err;
>
> - return;
> + return ret;
> err:
> qcom_ep_reset_assert(pcie);
> phy_power_off(pcie->phy);
> err_deinit:
> pcie->ops->deinit(pcie);
> + return ret;
> }
>
> static int qcom_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
> diff --git a/drivers/pci/host/pcie-spear13xx.c b/drivers/pci/host/pcie-spear13xx.c
> index 3cf197b..2408f80 100644
> --- a/drivers/pci/host/pcie-spear13xx.c
> +++ b/drivers/pci/host/pcie-spear13xx.c
> @@ -174,12 +174,18 @@ static int spear13xx_pcie_link_up(struct pcie_port *pp)
> return 0;
> }
>
> -static void spear13xx_pcie_host_init(struct pcie_port *pp)
> +static int spear13xx_pcie_host_init(struct pcie_port *pp)
> {
> struct spear13xx_pcie *spear13xx_pcie = to_spear13xx_pcie(pp);
> + int ret;
> +
> + ret = spear13xx_pcie_establish_link(spear13xx_pcie);
> + if (ret < 0)
> + return ret;
>
> - spear13xx_pcie_establish_link(spear13xx_pcie);
> spear13xx_pcie_enable_interrupts(spear13xx_pcie);
> +
> + return 0;
> }
>
> static struct pcie_host_ops spear13xx_pcie_host_ops = {
^ permalink raw reply
* [PATCH 5/8] efi: Get the secure boot status [ver #5]
From: Lukas Wunner @ 2016-12-08 6:57 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <148111671977.23390.12452925207541146423.stgit@warthog.procyon.org.uk>
On Wed, Dec 07, 2016 at 01:18:39PM +0000, David Howells wrote:
> @@ -226,7 +180,7 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table,
> efi_guid_t loaded_image_proto = LOADED_IMAGE_PROTOCOL_GUID;
> unsigned long reserve_addr = 0;
> unsigned long reserve_size = 0;
> - int secure_boot = 0;
> + enum efi_secureboot_mode secure_boot = efi_secureboot_mode_unknown;
You're setting this variable unconditionally further down, so no need
to initialize it.
> +/*
> + * Determine whether we're in secure boot mode. We return:
> + */
We return? Looks like something's missing here.
> +enum efi_secureboot_mode efi_get_secureboot(efi_system_table_t *sys_table_arg)
> +{
> + u8 secboot, setupmode;
> + unsigned long size;
> + efi_status_t status;
> +
> + size = sizeof(secboot);
> + status = get_efi_var(efi_SecureBoot_name, &efi_variable_guid,
> + NULL, &size, &secboot);
> + if (status != EFI_SUCCESS)
> + goto out_efi_err;
> +
> + size = sizeof(setupmode);
> + status = get_efi_var(efi_SetupMode_name, &efi_variable_guid,
> + NULL, &size, &setupmode);
> + if (status != EFI_SUCCESS)
> + goto out_efi_err;
> +
> + if (secboot == 0 || setupmode == 1)
> + goto secure_boot_disabled;
Well, you could just return efi_secureboot_mode_disabled directly here
instead of doing a jump.
> +
> + pr_efi(sys_table_arg, "UEFI Secure Boot is enabled.\n");
> + return efi_secureboot_mode_enabled;
> +
> +secure_boot_disabled:
> + return efi_secureboot_mode_disabled;
> +
> +out_efi_err:
> + pr_efi_err(sys_table_arg, "Could not determine UEFI Secure Boot status.\n");
> + if (status == EFI_NOT_FOUND)
> + goto secure_boot_disabled;
> + return efi_secureboot_mode_unknown;
> +}
Thanks,
Lukas
^ permalink raw reply
* [PATCH] fsl/usb: Add USB node in FSL's ls1012a DTS
From: Changming Huang @ 2016-12-08 6:06 UTC (permalink / raw)
To: linux-arm-kernel
Add USB node in ls1012a device tree
Signed-off-by: Changming Huang <jerry.huang@nxp.com>
---
Dependence on patch "[v3] arm64: Add DTS support for FSL's LS1012A SoC".
https://patchwork.kernel.org/patch/9462399/
arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
index 92e64f3..3e4bda6 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1012a.dtsi
@@ -235,6 +235,23 @@
<&clockgen 4 3>;
};
+ usb0: usb3 at 2f00000 {
+ compatible = "snps,dwc3";
+ reg = <0x0 0x2f00000 0x0 0x10000>;
+ interrupts = <0 60 0x4>;
+ dr_mode = "host";
+ snps,quirk-frame-length-adjustment = <0x20>;
+ snps,dis_rxdet_inp3_quirk;
+ };
+
+ usb1: usb2 at 8600000 {
+ compatible = "fsl-usb2-dr-v2.5", "fsl-usb2-dr";
+ reg = <0x0 0x8600000 0x0 0x1000>;
+ interrupts = <0 139 0x4>;
+ dr_mode = "host";
+ phy_type = "ulpi";
+ };
+
sata: sata at 3200000 {
compatible = "fsl,ls1012a-ahci", "fsl,ls1043a-ahci";
reg = <0x0 0x3200000 0x0 0x10000>;
--
1.7.9.5
^ permalink raw reply related
* [PATCH] arm64: defconfig: Enable NUMA and NUMA_BALANCING
From: Kefeng Wang @ 2016-12-08 5:38 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1480499575-43628-1-git-send-email-wangkefeng.wang@huawei.com>
+ Arnd
On 2016/11/30 17:52, Kefeng Wang wrote:
> Enable NUMA and NUMA_BALANCING to improve the performance on board
> with multiple numa nodes.
>
> Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
> ---
> arch/arm64/configs/defconfig | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
> index dab2cb0..967f6e5 100644
> --- a/arch/arm64/configs/defconfig
> +++ b/arch/arm64/configs/defconfig
> @@ -12,6 +12,7 @@ CONFIG_TASK_IO_ACCOUNTING=y
> CONFIG_IKCONFIG=y
> CONFIG_IKCONFIG_PROC=y
> CONFIG_LOG_BUF_SHIFT=14
> +CONFIG_NUMA_BALANCING=y
> CONFIG_MEMCG=y
> CONFIG_MEMCG_SWAP=y
> CONFIG_BLK_CGROUP=y
> @@ -72,6 +73,7 @@ CONFIG_PCIE_QCOM=y
> CONFIG_PCIE_ARMADA_8K=y
> CONFIG_ARM64_VA_BITS_48=y
> CONFIG_SCHED_MC=y
> +CONFIG_NUMA=y
> CONFIG_PREEMPT=y
> CONFIG_KSM=y
> CONFIG_TRANSPARENT_HUGEPAGE=y
>
^ permalink raw reply
* [PATCH v2 5/5] arm64: dts: exynos5433: Add support of bus frequency using VDD_INT on TM2
From: Chanwoo Choi @ 2016-12-08 4:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481173091-9728-1-git-send-email-cw00.choi@samsung.com>
This patch adds the bus Device-tree nodes for INT (Internal) block
to enable the bus frequency scaling.
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
Reviewed-by: Krzysztof Kozlowski <krzk@kernel.org>
---
arch/arm64/boot/dts/exynos/exynos5433-tm2.dts | 70 +++++++++++++++++++++++++++
1 file changed, 70 insertions(+)
diff --git a/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts b/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts
index c08589970134..451788642b21 100644
--- a/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts
+++ b/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts
@@ -170,6 +170,58 @@
};
};
+&bus_g2d_400 {
+ devfreq-events = <&ppmu_event0_d0_general>, <&ppmu_event0_d1_general>;
+ vdd-supply = <&buck4_reg>;
+ exynos,saturation-ratio = <10>;
+ status = "okay";
+};
+
+&bus_g2d_266 {
+ devfreq = <&bus_g2d_400>;
+ status = "okay";
+};
+
+&bus_gscl {
+ devfreq = <&bus_g2d_400>;
+ status = "okay";
+};
+
+&bus_hevc {
+ devfreq = <&bus_g2d_400>;
+ status = "okay";
+};
+
+&bus_jpeg {
+ devfreq = <&bus_g2d_400>;
+ status = "okay";
+};
+
+&bus_mfc {
+ devfreq = <&bus_g2d_400>;
+ status = "okay";
+};
+
+&bus_mscl {
+ devfreq = <&bus_g2d_400>;
+ status = "okay";
+};
+
+&bus_noc0 {
+ devfreq = <&bus_g2d_400>;
+ status = "okay";
+};
+
+&bus_noc1 {
+ devfreq = <&bus_g2d_400>;
+ status = "okay";
+};
+
+&bus_noc2 {
+ devfreq = <&bus_g2d_400>;
+ status = "okay";
+};
+
&cmu_aud {
assigned-clocks = <&cmu_aud CLK_MOUT_AUD_PLL_USER>;
assigned-clock-parents = <&cmu_top CLK_FOUT_AUD_PLL>;
@@ -794,6 +846,24 @@
bus-width = <4>;
};
+&ppmu_d0_general {
+ status = "okay";
+ events {
+ ppmu_event0_d0_general: ppmu-event0-d0-general {
+ event-name = "ppmu-event0-d0-general";
+ };
+ };
+};
+
+&ppmu_d1_general {
+ status = "okay";
+ events {
+ ppmu_event0_d1_general: ppmu-event0-d1-general {
+ event-name = "ppmu-event0-d1-general";
+ };
+ };
+};
+
&pinctrl_alive {
pinctrl-names = "default";
pinctrl-0 = <&initial_alive>;
--
1.9.1
^ permalink raw reply related
* [PATCH v2 4/5] arm64: dts: exynos5433: Add bus dt node using VDD_INT for Exynos5433
From: Chanwoo Choi @ 2016-12-08 4:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481173091-9728-1-git-send-email-cw00.choi@samsung.com>
This patch adds the bus nodes using VDD_INT for Exynos5433 SoC.
Exynos5433 has the following AMBA AXI buses to translate data
between DRAM and sub-blocks.
Following list specify the detailed correlation between sub-block and clock:
- CLK_ACLK_G2D_{400|266} : Bus clock for G2D (2D graphic engine)
- CLK_ACLK_MSCL_400 : Bus clock for MSCL (Memory to memory Scaler)
- CLK_ACLK_GSCL_333 : Bus clock for GSCL (General Scaler)
- CLK_SCLK_JPEG_MSCL : Bus clock for JPEG
- CLK_ACLK_MFC_400 : Bus clock for MFC (Multi Format Codec)
- CLK_ACLK_HEVC_400 : Bus clock for HEVC (High Efficient Video Codec)
- CLK_ACLK_BUS0_400 : NoC(Network On Chip)'s bus clock for PERIC/PERIS/FSYS/MSCL
- CLK_ACLK_BUS1_400 : NoC's bus clock for MFC/HEVC/G3D
- CLK_ACLK_BUS2_400 : NoC's bus clock for GSCL/DISP/G2D/CAM0/CAM1/ISP
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
---
arch/arm64/boot/dts/exynos/exynos5433-bus.dtsi | 197 +++++++++++++++++++++++++
arch/arm64/boot/dts/exynos/exynos5433.dtsi | 1 +
2 files changed, 198 insertions(+)
create mode 100644 arch/arm64/boot/dts/exynos/exynos5433-bus.dtsi
diff --git a/arch/arm64/boot/dts/exynos/exynos5433-bus.dtsi b/arch/arm64/boot/dts/exynos/exynos5433-bus.dtsi
new file mode 100644
index 000000000000..09dac0124f73
--- /dev/null
+++ b/arch/arm64/boot/dts/exynos/exynos5433-bus.dtsi
@@ -0,0 +1,197 @@
+/*
+ * Samsung's Exynos5433 SoC Memory interface and AMBA bus device tree source
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Chanwoo Choi <cw00.choi@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+&soc {
+ bus_g2d_400: bus0 {
+ compatible = "samsung,exynos-bus";
+ clocks = <&cmu_top CLK_ACLK_G2D_400>;
+ clock-names = "bus";
+ operating-points-v2 = <&bus_g2d_400_opp_table>;
+ status ="disabled";
+ };
+
+ bus_g2d_266: bus1 {
+ compatible = "samsung,exynos-bus";
+ clocks = <&cmu_top CLK_ACLK_G2D_266>;
+ clock-names = "bus";
+ operating-points-v2 = <&bus_g2d_266_opp_table>;
+ status ="disabled";
+ };
+
+ bus_gscl: bus2 {
+ compatible = "samsung,exynos-bus";
+ clocks = <&cmu_top CLK_ACLK_GSCL_333>;
+ clock-names = "bus";
+ operating-points-v2 = <&bus_gscl_opp_table>;
+ status ="disabled";
+ };
+
+ bus_hevc: bus3 {
+ compatible = "samsung,exynos-bus";
+ clocks = <&cmu_top CLK_ACLK_HEVC_400>;
+ clock-names = "bus";
+ operating-points-v2 = <&bus_hevc_opp_table>;
+ status ="disabled";
+ };
+
+ bus_jpeg: bus4 {
+ compatible = "samsung,exynos-bus";
+ clocks = <&cmu_top CLK_SCLK_JPEG_MSCL>;
+ clock-names = "bus";
+ operating-points-v2 = <&bus_g2d_400_opp_table>;
+ status ="disabled";
+ };
+
+ bus_mfc: bus5 {
+ compatible = "samsung,exynos-bus";
+ clocks = <&cmu_top CLK_ACLK_MFC_400>;
+ clock-names = "bus";
+ operating-points-v2 = <&bus_g2d_400_opp_table>;
+ status ="disabled";
+ };
+
+ bus_mscl: bus6 {
+ compatible = "samsung,exynos-bus";
+ clocks = <&cmu_top CLK_ACLK_MSCL_400>;
+ clock-names = "bus";
+ operating-points-v2 = <&bus_g2d_400_opp_table>;
+ status ="disabled";
+ };
+
+ bus_noc0: bus7 {
+ compatible = "samsung,exynos-bus";
+ clocks = <&cmu_top CLK_ACLK_BUS0_400>;
+ clock-names = "bus";
+ operating-points-v2 = <&bus_hevc_opp_table>;
+ status ="disabled";
+ };
+
+ bus_noc1: bus8 {
+ compatible = "samsung,exynos-bus";
+ clocks = <&cmu_top CLK_ACLK_BUS1_400>;
+ clock-names = "bus";
+ operating-points-v2 = <&bus_hevc_opp_table>;
+ status ="disabled";
+ };
+
+ bus_noc2: bus9 {
+ compatible = "samsung,exynos-bus";
+ clocks = <&cmu_mif CLK_ACLK_BUS2_400>;
+ clock-names = "bus";
+ operating-points-v2 = <&bus_noc2_opp_table>;
+ status ="disabled";
+ };
+
+ bus_g2d_400_opp_table: opp_table2 {
+ compatible = "operating-points-v2";
+ opp-shared;
+
+ opp at 400000000 {
+ opp-hz = /bits/ 64 <400000000>;
+ opp-microvolt = <1075000>;
+ };
+ opp at 267000000 {
+ opp-hz = /bits/ 64 <267000000>;
+ opp-microvolt = <1000000>;
+ };
+ opp at 200000000 {
+ opp-hz = /bits/ 64 <200000000>;
+ opp-microvolt = <975000>;
+ };
+ opp at 160000000 {
+ opp-hz = /bits/ 64 <160000000>;
+ opp-microvolt = <962500>;
+ };
+ opp at 134000000 {
+ opp-hz = /bits/ 64 <134000000>;
+ opp-microvolt = <950000>;
+ };
+ opp at 100000000 {
+ opp-hz = /bits/ 64 <100000000>;
+ opp-microvolt = <937500>;
+ };
+ };
+
+ bus_g2d_266_opp_table: opp_table3 {
+ compatible = "operating-points-v2";
+
+ opp at 267000000 {
+ opp-hz = /bits/ 64 <267000000>;
+ };
+ opp at 200000000 {
+ opp-hz = /bits/ 64 <200000000>;
+ };
+ opp at 160000000 {
+ opp-hz = /bits/ 64 <160000000>;
+ };
+ opp at 134000000 {
+ opp-hz = /bits/ 64 <134000000>;
+ };
+ opp at 100000000 {
+ opp-hz = /bits/ 64 <100000000>;
+ };
+ };
+
+ bus_gscl_opp_table: opp_table4 {
+ compatible = "operating-points-v2";
+
+ opp at 333000000 {
+ opp-hz = /bits/ 64 <333000000>;
+ };
+ opp at 222000000 {
+ opp-hz = /bits/ 64 <222000000>;
+ };
+ opp at 166500000 {
+ opp-hz = /bits/ 64 <166500000>;
+ };
+ };
+
+ bus_hevc_opp_table: opp_table5 {
+ compatible = "operating-points-v2";
+ opp-shared;
+
+ opp at 400000000 {
+ opp-hz = /bits/ 64 <400000000>;
+ };
+ opp at 267000000 {
+ opp-hz = /bits/ 64 <267000000>;
+ };
+ opp at 200000000 {
+ opp-hz = /bits/ 64 <200000000>;
+ };
+ opp at 160000000 {
+ opp-hz = /bits/ 64 <160000000>;
+ };
+ opp at 134000000 {
+ opp-hz = /bits/ 64 <134000000>;
+ };
+ opp at 100000000 {
+ opp-hz = /bits/ 64 <100000000>;
+ };
+ };
+
+ bus_noc2_opp_table: opp_table6 {
+ compatible = "operating-points-v2";
+
+ opp at 400000000 {
+ opp-hz = /bits/ 64 <400000000>;
+ };
+ opp at 200000000 {
+ opp-hz = /bits/ 64 <200000000>;
+ };
+ opp at 134000000 {
+ opp-hz = /bits/ 64 <134000000>;
+ };
+ opp at 100000000 {
+ opp-hz = /bits/ 64 <100000000>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/exynos/exynos5433.dtsi b/arch/arm64/boot/dts/exynos/exynos5433.dtsi
index 8c4ee84d5232..68f764e5851c 100644
--- a/arch/arm64/boot/dts/exynos/exynos5433.dtsi
+++ b/arch/arm64/boot/dts/exynos/exynos5433.dtsi
@@ -1482,5 +1482,6 @@
};
};
+#include "exynos5433-bus.dtsi"
#include "exynos5433-pinctrl.dtsi"
#include "exynos5433-tmu.dtsi"
--
1.9.1
^ permalink raw reply related
* [PATCH v2 3/5] arm64: dts: exynos5433: Add PPMU dt node
From: Chanwoo Choi @ 2016-12-08 4:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481173091-9728-1-git-send-email-cw00.choi@samsung.com>
This patch adds PPMU (Platform Performance Monitoring Unit) Device-tree node
to measure the utilization of each IP in Exynos SoC.
- PPMU_D{0|1}_CPU are used to measure the utilization of MIF (Memory Interface)
block with VDD_MIF power source.
- PPMU_D{0|1}_GENERAL are used to measure the utilization of INT(Internal)
block with VDD_INT power source.
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
Reviewed-by: Krzysztof Kozlowski <krzk@kernel.org>
---
arch/arm64/boot/dts/exynos/exynos5433.dtsi | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/arch/arm64/boot/dts/exynos/exynos5433.dtsi b/arch/arm64/boot/dts/exynos/exynos5433.dtsi
index 64226d5ae471..8c4ee84d5232 100644
--- a/arch/arm64/boot/dts/exynos/exynos5433.dtsi
+++ b/arch/arm64/boot/dts/exynos/exynos5433.dtsi
@@ -599,6 +599,30 @@
clock-names = "fin_pll", "mct";
};
+ ppmu_d0_cpu: ppmu at 10480000 {
+ compatible = "samsung,exynos-ppmu-v2";
+ reg = <0x10480000 0x2000>;
+ status = "disabled";
+ };
+
+ ppmu_d0_general: ppmu at 10490000 {
+ compatible = "samsung,exynos-ppmu-v2";
+ reg = <0x10490000 0x2000>;
+ status = "disabled";
+ };
+
+ ppmu_d1_cpu: ppmu at 104b0000 {
+ compatible = "samsung,exynos-ppmu-v2";
+ reg = <0x104b0000 0x2000>;
+ status = "disabled";
+ };
+
+ ppmu_d1_general: ppmu at 104c0000 {
+ compatible = "samsung,exynos-ppmu-v2";
+ reg = <0x104c0000 0x2000>;
+ status = "disabled";
+ };
+
pinctrl_alive: pinctrl at 10580000 {
compatible = "samsung,exynos5433-pinctrl";
reg = <0x10580000 0x1a20>, <0x11090000 0x100>;
--
1.9.1
^ permalink raw reply related
* [PATCH v2 2/5] PM / devfreq: exynos-bus: Add the detailed correlation for Exynos5433
From: Chanwoo Choi @ 2016-12-08 4:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481173091-9728-1-git-send-email-cw00.choi@samsung.com>
This patch adds the detailed corrleation between sub-blocks and VDD_INT power
line for Exynos5433. VDD_INT provided the power source to INT (Internal) block.
Cc: MyungJoo Ham <myungjoo.ham@samsung.com>
Cc: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: devicetree at vger.kernel.org
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
---
Documentation/devicetree/bindings/devfreq/exynos-bus.txt | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/Documentation/devicetree/bindings/devfreq/exynos-bus.txt b/Documentation/devicetree/bindings/devfreq/exynos-bus.txt
index d3ec8e676b6b..d6107770face 100644
--- a/Documentation/devicetree/bindings/devfreq/exynos-bus.txt
+++ b/Documentation/devicetree/bindings/devfreq/exynos-bus.txt
@@ -123,6 +123,21 @@ Detailed correlation between sub-blocks and power line according to Exynos SoC:
|--- FSYS
|--- FSYS2
+- In case of Exynos5433, there is VDD_INT power line as following:
+ VDD_INT |--- G2D_400 (parent device)
+ |--- G2D_266
+ |--- GSCL
+ |--- JPEG
+ |--- HEVC
+ |--- MFC
+ |--- MSCL
+ |--- NoC0
+ |--- NoC1
+ |--- NoC2
+ |--- PERIS (Fixed clock rate)
+ |--- PERIC (Fixed clock rate)
+ |--- FSYS (Fixed clock rate)
+
Example1:
Show the AXI buses of Exynos3250 SoC. Exynos3250 divides the buses to
power line (regulator). The MIF (Memory Interface) AXI bus is used to
--
1.9.1
^ permalink raw reply related
* [PATCH v2 1/5] clk: samsung: exynos5433: Set NoC (Network On Chip) clocks as critical
From: Chanwoo Choi @ 2016-12-08 4:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1481173091-9728-1-git-send-email-cw00.choi@samsung.com>
The ACLK_BUS0/1/2 are used for NoC (Network on Chip). If NoC's clocks are
disabled, the system halt happen. Following clock must be always enabled.
- CLK_ACLK_BUS0_400 : NoC's bus clock for PERIC/PERIS/FSYS/MSCL
- CLK_ACLK_BUS1_400 : NoC's bus clock for MFC/HEVC/G3D
- CLK_ACLK_BUS2_400 : NoC's bus clock for GSCL/DISP/G2D/CAM0/CAM1/ISP
Also, this patch adds the CLK_SET_RATE_PARENT flag to the CLK_SCLK_JPEG_MSCL
because this clock should be used for bus frequency scaling. This clock need to
be changed on the fly with CLK_SET_RATE_PARENT flag.
Cc: Sylwester Nawrocki <s.nawrocki@samsung.com>
Cc: Tomasz Figa <tomasz.figa@gmail.com>
Cc: Chanwoo Choi <cw00.choi@samsung.com>
Cc: Michael Turquette <mturquette@baylibre.com>
Cc: Stephen Boyd <sboyd@codeaurora.org>
Cc:linux-clk at vger.kernel.org
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
---
drivers/clk/samsung/clk-exynos5433.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c
index f096bd7df40c..0db5204c307c 100644
--- a/drivers/clk/samsung/clk-exynos5433.c
+++ b/drivers/clk/samsung/clk-exynos5433.c
@@ -549,10 +549,10 @@
29, CLK_IGNORE_UNUSED, 0),
GATE(CLK_ACLK_BUS0_400, "aclk_bus0_400", "div_aclk_bus0_400",
ENABLE_ACLK_TOP, 26,
- CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0),
+ CLK_IS_CRITICAL | CLK_SET_RATE_PARENT, 0),
GATE(CLK_ACLK_BUS1_400, "aclk_bus1_400", "div_aclk_bus1_400",
ENABLE_ACLK_TOP, 25,
- CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0),
+ CLK_IS_CRITICAL | CLK_SET_RATE_PARENT, 0),
GATE(CLK_ACLK_IMEM_200, "aclk_imem_200", "div_aclk_imem_266",
ENABLE_ACLK_TOP, 24,
CLK_IS_CRITICAL | CLK_SET_RATE_PARENT, 0),
@@ -616,7 +616,7 @@
/* ENABLE_SCLK_TOP_MSCL */
GATE(CLK_SCLK_JPEG_MSCL, "sclk_jpeg_mscl", "div_sclk_jpeg",
- ENABLE_SCLK_TOP_MSCL, 0, 0, 0),
+ ENABLE_SCLK_TOP_MSCL, 0, CLK_SET_RATE_PARENT, 0),
/* ENABLE_SCLK_TOP_CAM1 */
GATE(CLK_SCLK_ISP_SENSOR2, "sclk_isp_sensor2", "div_sclk_isp_sensor2_b",
@@ -1382,7 +1382,7 @@ static void __init exynos5433_cmu_cpif_init(struct device_node *np)
/* ENABLE_ACLK_MIF3 */
GATE(CLK_ACLK_BUS2_400, "aclk_bus2_400", "div_aclk_bus2_400",
ENABLE_ACLK_MIF3, 4,
- CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0),
+ CLK_IS_CRITICAL | CLK_SET_RATE_PARENT, 0),
GATE(CLK_ACLK_DISP_333, "aclk_disp_333", "div_aclk_disp_333",
ENABLE_ACLK_MIF3, 1,
CLK_IS_CRITICAL | CLK_SET_RATE_PARENT, 0),
--
1.9.1
^ permalink raw reply related
* [PATCH v2 0/5] arm64: dts: Enable bus frequency scaling on Exynos5433-based TM2 board
From: Chanwoo Choi @ 2016-12-08 4:58 UTC (permalink / raw)
To: linux-arm-kernel
This patches add the AMBA bus Device-tree node unsing VDD_INT
to enable the bus frequency scaling on Exynos5433-based TM2 board.
There are two kind of bus device with devfreq framework.
- Parent bus device : Change the frequency/voltage according to bus's utilization.
- Passive bus device : Change only frequency according to the new level
of parent bus device.
The VDD_INT regulator provides the power source to INT (Internal) block as
following. The sub-blocks in the INT block share the one power source.
VDD_INT |--- G2D_400 (parent device)
|--- G2D_266
|--- GSCL
|--- JPEG
|--- HEVC
|--- MFC
|--- MSCL
|--- NoC0
|--- NoC1
|--- NoC2
|--- PERIS (Fixed clock rate)
|--- PERIC (Fixed clock rate)
|--- FSYS (Fixed clock rate)
Each sub-block has the bus clock as following:
- CLK_ACLK_G2D_{400|266} : Bus clock for G2D (2D graphic engine)
- CLK_ACLK_MSCL_400 : Bus clock for MSCL (Memory to memory Scaler)
- CLK_ACLK_GSCL_333 : Bus clock for GSCL (General Scaler)
- CLK_SCLK_JPEG_MSCL : Bus clock for JPEG
- CLK_ACLK_MFC_400 : Bus clock for MFC (Multi Format Codec)
- CLK_ACLK_HEVC_400 : Bus clock for HEVC (High Effective Video Codec)
- CLK_ACLK_BUS0_400 : NoC(Network On Chip)'s bus clock for PERIC/PERIS/FSYS/MSCL
- CLK_ACLK_BUS1_400 : NoC's bus clock for MFC/HEVC/G3D
- CLK_ACLK_BUS2_400 : NoC's bus clock for GSCL/DISP/G2D/CAM0/CAM1/ISP
Changes from v1:
- Remove duplicate description of exynos5433-bus.dtsi
- Move the bus device-tree node under the 'soc'
- Modify the node name of bus from 'bus_xxx_xxx' to 'bus[number]'
- Reorder the bus device-tree node alpabetically
- Change the node name from 'bus_busX' to 'bus_nocX'
- Fix minor issue
- Add reviewed-by tag of Krzysztof Kozlowski for patch3/5
Chanwoo Choi (5):
clk: samsung: exynos5433: Set NoC (Network On Chip) clocks as critical
PM / devfreq: exynos-bus: Add the detailed correlation for Exynos5433
arm64: dts: exynos5433: Add PPMU dt node
arm64: dts: exynos5433: Add bus dt node using VDD_INT for Exynos5433
arm64: dts: exynos5433: Add support of bus frequency using VDD_INT on TM2
.../devicetree/bindings/devfreq/exynos-bus.txt | 15 ++
arch/arm64/boot/dts/exynos/exynos5433-bus.dtsi | 197 +++++++++++++++++++++
arch/arm64/boot/dts/exynos/exynos5433-tm2.dts | 70 ++++++++
arch/arm64/boot/dts/exynos/exynos5433.dtsi | 25 +++
drivers/clk/samsung/clk-exynos5433.c | 8 +-
5 files changed, 311 insertions(+), 4 deletions(-)
create mode 100644 arch/arm64/boot/dts/exynos/exynos5433-bus.dtsi
--
1.9.1
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox