* [PATCH v2 2/5] dt: qcom: 8996: thermal: Move to DT initialisation
From: Amit Kucheria @ 2018-06-12 10:54 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1528799892.git.amit.kucheria@linaro.org>
We also split up the regmap address space into two, one for the TM
registers, the other for the SROT registers. This was required to deal with
different address offsets for the TM and SROT registers across different
SoC families.
Since tsens-common.c/init_common() currently only registers one address space, the order is important (TM before SROT).This is OK since the code doesn't really use the SROT functionality yet.
Signed-off-by: Amit Kucheria <amit.kucheria@linaro.org>
---
arch/arm64/boot/dts/qcom/msm8996.dtsi | 12 +++++++++++-
drivers/thermal/qcom/tsens-8996.c | 1 -
2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/boot/dts/qcom/msm8996.dtsi b/arch/arm64/boot/dts/qcom/msm8996.dtsi
index 410ae78..b4aab18 100644
--- a/arch/arm64/boot/dts/qcom/msm8996.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8996.dtsi
@@ -451,7 +451,17 @@
tsens0: thermal-sensor at 4a8000 {
compatible = "qcom,msm8996-tsens";
- reg = <0x4a8000 0x2000>;
+ reg = <0x4a9000 0x1000>, /* TM */
+ <0x4a8000 0x1000>; /* SROT */
+ #qcom,sensors = <13>;
+ #thermal-sensor-cells = <1>;
+ };
+
+ tsens1: thermal-sensor at 4ac000 {
+ compatible = "qcom,msm8996-tsens";
+ reg = <0x4ad000 0x1000>, /* TM */
+ <0x4ac000 0x1000>; /* SROT */
+ #qcom,sensors = <8>;
#thermal-sensor-cells = <1>;
};
diff --git a/drivers/thermal/qcom/tsens-8996.c b/drivers/thermal/qcom/tsens-8996.c
index e1f7781..6e59078 100644
--- a/drivers/thermal/qcom/tsens-8996.c
+++ b/drivers/thermal/qcom/tsens-8996.c
@@ -79,6 +79,5 @@ static const struct tsens_ops ops_8996 = {
};
const struct tsens_data data_8996 = {
- .num_sensors = 13,
.ops = &ops_8996,
};
--
2.7.4
^ permalink raw reply related
* [GIT PULL 2/4] ARM: Device-tree updates
From: Kalle Valo @ 2018-06-12 10:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180612000142.28883-3-olof@lixom.net>
Olof Johansson <olof@lixom.net> writes:
> - Qualcomm:
> + SDM845, a.k.a Snapdragon 845, an 4+4-core Kryo 385/845
> (Cortex-A75/A55 derivative) SoC that's one of the current high-end
> mobile SoCs.
>
> It's great to see mainline support for it. So far, you
> can't do much with it, since a lot of peripherals are not yet in the
> DTs but driver support for USB, GPU and other pieces are starting to
> trickle in. This might end up being a well-supported SoC upstream if
> the momentum keeps up.
The wifi chip is called wcn3990 and we are working on supporting that in
ath10k. I'm hoping to get it ready for v4.19.
--
Kalle Valo
^ permalink raw reply
* [PATCH v2] arm64: dma-mapping: clear buffers allocated with FORCE_CONTIGUOUS flag
From: Marek Szyprowski @ 2018-06-12 11:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CGME20180612110857eucas1p1f5e3b6d984d4fd7e3b3ce31418df546e@eucas1p1.samsung.com>
dma_alloc_*() buffers might be exposed to userspace via mmap() call, so
they should be cleared on allocation. In case of IOMMU-based dma-mapping
implementation such buffer clearing was missing in the code path for
DMA_ATTR_FORCE_CONTIGUOUS flag handling, because dma_alloc_from_contiguous()
doesn't honor __GFP_ZERO flag. This patch fixes this issue. For more
information on clearing buffers allocated by dma_alloc_* functions,
see commit 6829e274a623 ("arm64: dma-mapping: always clear allocated
buffers").
Fixes: 44176bb38fa4 ("arm64: Add support for DMA_ATTR_FORCE_CONTIGUOUS to IOMMU")
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
v2:
- fixed incorrect commit id in commit body (thanks to Geert)
- extended description with information that dma_alloc_from_contiguous()
lacks __GFP_ZERO support
---
arch/arm64/mm/dma-mapping.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index 632d32109755..aa0037a3185f 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -629,13 +629,14 @@ static void *__iommu_alloc_attrs(struct device *dev, size_t size,
size >> PAGE_SHIFT);
return NULL;
}
- if (!coherent)
- __dma_flush_area(page_to_virt(page), iosize);
-
addr = dma_common_contiguous_remap(page, size, VM_USERMAP,
prot,
__builtin_return_address(0));
- if (!addr) {
+ if (addr) {
+ memset(addr, 0, size);
+ if (!coherent)
+ __dma_flush_area(page_to_virt(page), iosize);
+ } else {
iommu_dma_unmap_page(dev, *handle, iosize, 0, attrs);
dma_release_from_contiguous(dev, page,
size >> PAGE_SHIFT);
--
2.17.1
^ permalink raw reply related
* [PATCH v2] ARM: DTS: imx53: Add support for imx53 HSC/DDC boards from K+P
From: Lukasz Majewski @ 2018-06-12 11:28 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180611051357.GA16091@dragon>
Hi Shawn,
Thanks for you review.
> On Sat, May 19, 2018 at 02:15:06PM +0200, Lukasz Majewski wrote:
> > This commit provides support for HSC and DDC boards from
> > Kieback&Peter GmbH vendor.
> >
> > Signed-off-by: Lukasz Majewski <lukma@denx.de>
> > ---
> > Changes for v2:
> >
> > - Remove not needed #address-cells and #size-cells in
> > the gpio_buttons node to pass make W=1
> > - Rename button@{12} to button_{kalt|pwr} nodes to pass make W=1
> > - Include #include <dt-bindings/input/input.h> to use KEY_F6|F7
> > directly
> >
> > ---
> > arch/arm/boot/dts/Makefile | 2 +
> > arch/arm/boot/dts/imx53-kp-ddc.dts | 146
> > ++++++++++++++++++++++++++++ arch/arm/boot/dts/imx53-kp-hsc.dts |
> > 51 ++++++++++ arch/arm/boot/dts/imx53-kp.dtsi | 190
> > +++++++++++++++++++++++++++++++++++++ 4 files changed, 389
> > insertions(+) create mode 100644 arch/arm/boot/dts/imx53-kp-ddc.dts
> > create mode 100644 arch/arm/boot/dts/imx53-kp-hsc.dts
> > create mode 100644 arch/arm/boot/dts/imx53-kp.dtsi
> >
> > diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
> > index fbc04b0db781..00854a5b6ac4 100644
> > --- a/arch/arm/boot/dts/Makefile
> > +++ b/arch/arm/boot/dts/Makefile
> > @@ -360,6 +360,8 @@ dtb-$(CONFIG_SOC_IMX51) += \
> > dtb-$(CONFIG_SOC_IMX53) += \
> > imx53-ard.dtb \
> > imx53-cx9020.dtb \
> > + imx53-kp-ddc.dtb \
> > + imx53-kp-hsc.dtb \
> > imx53-m53evk.dtb \
> > imx53-mba53.dtb \
> > imx53-ppd.dtb \
> > diff --git a/arch/arm/boot/dts/imx53-kp-ddc.dts
> > b/arch/arm/boot/dts/imx53-kp-ddc.dts new file mode 100644
> > index 000000000000..acaf477a52c5
> > --- /dev/null
> > +++ b/arch/arm/boot/dts/imx53-kp-ddc.dts
> > @@ -0,0 +1,146 @@
> > +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> > +/*
> > + * Copyright 2018
> > + * Lukasz Majewski, DENX Software Engineering, lukma at denx.de
> > + */
> > +
> > +/dts-v1/;
> > +#include "imx53-kp.dtsi"
> > +
> > +/ {
> > + model = "K+P imx53 DDC";
> > + compatible = "kiebackpeter,imx53-ddc", "fsl,imx53";
> > +
> > + backlight_lcd: backlight {
> > + compatible = "pwm-backlight";
> > + pwms = <&pwm2 0 50000>;
> > + power-supply = <®_backlight>;
> > + brightness-levels = <0 24 28 32 36
> > + 40 44 48 52 56
> > + 60 64 68 72 76
> > + 80 84 88 92 96 100>;
> > + default-brightness-level = <20>;
> > + };
> > +
> > + lcd_display: disp1 {
>
> display for node node.
I assume that I shall change disp1 -> display ?
>
> > + compatible = "fsl,imx-parallel-display";
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > + interface-pix-fmt = "rgb24";
> > + pinctrl-names = "default";
> > + pinctrl-0 = <&pinctrl_disp>;
> > +
> > + port at 0 {
> > + reg = <0>;
> > +
> > + display1_in: endpoint {
> > + remote-endpoint = <&ipu_di1_disp1>;
> > + };
> > + };
> > +
> > + port at 1 {
> > + reg = <1>;
> > +
> > + lcd_display_out: endpoint {
> > + remote-endpoint = <&lcd_panel_in>;
> > + };
> > + };
> > + };
> > +
> > + lcd_panel: lcd-panel {
> > + compatible = "koe,tx14d24vm1bpa";
>
> Undefined compatible?
The display's in question "koe,tx14d24vm1bpa" compatible has been
ack'ed by Rob Herring and Thierry promised to apply it to his tree:
https://patchwork.kernel.org/patch/10391589/
The v2 of this patch:
https://patchwork.kernel.org/patch/10436007/
>
> > + backlight = <&backlight_lcd>;
> > + power-supply = <®_3v3>;
> > +
> > + port {
> > + lcd_panel_in: endpoint {
> > + remote-endpoint =
> > <&lcd_display_out>;
> > + };
> > + };
> > + };
> > +
> > + reg_backlight: regulator-backlight {
> > + compatible = "regulator-fixed";
> > + regulator-name = "backlight-supply";
> > + regulator-min-microvolt = <15000000>;
> > + regulator-max-microvolt = <15000000>;
> > + regulator-always-on;
> > + };
> > +};
> > +
> > +&i2c3 {
> > + adc at 48 {
> > + compatible = "ti,ads1015";
> > + reg = <0x48>;
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > +
> > + channel at 4 {
> > + reg = <4>;
> > + ti,gain = <2>;
> > + ti,datarate = <4>;
> > + };
> > +
> > + channel at 6 {
> > + reg = <6>;
> > + ti,gain = <2>;
> > + ti,datarate = <4>;
> > + };
> > + };
> > +
> > + gpio_expander2 at 21 {
>
> Use hyphen instead of underscore in node name.
Ok. I will change this globally. And send v3.
>
> > + compatible = "nxp,pcf8574";
> > + reg = <0x21>;
> > + interrupts = <109>;
> > + #gpio-cells = <2>;
> > + gpio-controller;
> > + };
> > +};
> > +
> > +&iomuxc {
> > + imx53-kp-ddc {
> > + pinctrl_disp: dispgrp {
> > + fsl,pins = <
> > +
> > MX53_PAD_EIM_A16__IPU_DI1_DISP_CLK 0x4
> > +
> > MX53_PAD_EIM_DA10__IPU_DI1_PIN15 0x4
> > +
> > MX53_PAD_EIM_DA9__IPU_DISP1_DAT_0 0x4
> > +
> > MX53_PAD_EIM_DA8__IPU_DISP1_DAT_1 0x4
> > +
> > MX53_PAD_EIM_DA7__IPU_DISP1_DAT_2 0x4
> > +
> > MX53_PAD_EIM_DA6__IPU_DISP1_DAT_3 0x4
> > +
> > MX53_PAD_EIM_DA5__IPU_DISP1_DAT_4 0x4
> > +
> > MX53_PAD_EIM_DA4__IPU_DISP1_DAT_5 0x4
> > +
> > MX53_PAD_EIM_DA3__IPU_DISP1_DAT_6 0x4
> > +
> > MX53_PAD_EIM_DA2__IPU_DISP1_DAT_7 0x4
> > +
> > MX53_PAD_EIM_DA1__IPU_DISP1_DAT_8 0x4
> > +
> > MX53_PAD_EIM_DA0__IPU_DISP1_DAT_9 0x4
> > +
> > MX53_PAD_EIM_EB1__IPU_DISP1_DAT_10 0x4
> > +
> > MX53_PAD_EIM_EB0__IPU_DISP1_DAT_11 0x4
> > +
> > MX53_PAD_EIM_A17__IPU_DISP1_DAT_12 0x4
> > +
> > MX53_PAD_EIM_A18__IPU_DISP1_DAT_13 0x4
> > +
> > MX53_PAD_EIM_A19__IPU_DISP1_DAT_14 0x4
> > +
> > MX53_PAD_EIM_A20__IPU_DISP1_DAT_15 0x4
> > +
> > MX53_PAD_EIM_A21__IPU_DISP1_DAT_16 0x4
> > +
> > MX53_PAD_EIM_A22__IPU_DISP1_DAT_17 0x4
> > +
> > MX53_PAD_EIM_A23__IPU_DISP1_DAT_18 0x4
> > +
> > MX53_PAD_EIM_A24__IPU_DISP1_DAT_19 0x4
> > +
> > MX53_PAD_EIM_D31__IPU_DISP1_DAT_20 0x4
> > +
> > MX53_PAD_EIM_D30__IPU_DISP1_DAT_21 0x4
> > +
> > MX53_PAD_EIM_D26__IPU_DISP1_DAT_22 0x4
> > +
> > MX53_PAD_EIM_D27__IPU_DISP1_DAT_23 0x4
> > + MX53_PAD_GPIO_1__PWM2_PWMO 0x4
> > + >;
> > + };
> > + };
> > +};
> > +
> > +&ipu_di1_disp1 {
> > + remote-endpoint = <&display1_in>;
> > +};
> > +
> > +&fec {
> > + status = "okay";
> > +};
>
> Sort the labeled nodes alphabetically in label name.
>
> > +
> > +&pmic {
> > + fsl,mc13xxx-uses-touch;
> > +};
> > diff --git a/arch/arm/boot/dts/imx53-kp-hsc.dts
> > b/arch/arm/boot/dts/imx53-kp-hsc.dts new file mode 100644
> > index 000000000000..d68cdd5da819
> > --- /dev/null
> > +++ b/arch/arm/boot/dts/imx53-kp-hsc.dts
> > @@ -0,0 +1,51 @@
> > +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> > +/*
> > + * Copyright 2018
> > + * Lukasz Majewski, DENX Software Engineering, lukma at denx.de
> > + */
> > +
> > +/dts-v1/;
> > +#include "imx53-kp.dtsi"
> > +
> > +/ {
> > + model = "K+P imx53 HSC";
> > + compatible = "kiebackpeter,imx53-hsc", "fsl,imx53";
> > +};
> > +
> > +&fec {
> > + status = "okay";
>
> Have a newline between property list and child node.
>
> > + fixed-link { /* RMII fixed link to LAN9303 */
> > + speed = <100>;
> > + full-duplex;
> > + };
> > +};
> > +
> > +&i2c3 {
> > + switch: switch at a {
> > + compatible = "smsc,lan9303-i2c";
> > + reg = <0xa>;
> > + reset-gpios = <&gpio7 6 GPIO_ACTIVE_LOW>;
> > + reset-duration = <400>;
> > +
> > + ports {
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > +
> > + port at 0 { /* RMII fixed link to master */
> > + reg = <0>;
> > + label = "cpu";
> > + ethernet = <&fec>;
> > + };
> > +
> > + port at 1 { /* external port 1 */
> > + reg = <1>;
> > + label = "lan1";
> > + };
> > +
> > + port at 2 { /* external port 2 */
> > + reg = <2>;
> > + label = "lan2";
> > + };
> > + };
> > + };
> > +};
> > diff --git a/arch/arm/boot/dts/imx53-kp.dtsi
> > b/arch/arm/boot/dts/imx53-kp.dtsi new file mode 100644
> > index 000000000000..f87266843842
> > --- /dev/null
> > +++ b/arch/arm/boot/dts/imx53-kp.dtsi
> > @@ -0,0 +1,190 @@
> > +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> > +/*
> > + * Copyright 2018
> > + * Lukasz Majewski, DENX Software Engineering, lukma at denx.de
> > + */
> > +
> > +/dts-v1/;
> > +#include "imx53-tqma53.dtsi"
> > +#include <dt-bindings/input/input.h>
> > +
> > +/ {
> > + buzzer {
> > + compatible = "pwm-beeper";
> > + pinctrl-names = "default";
> > + pinctrl-0 = <&pinctrl_buzzer>;
> > +
>
> Drop this newline.
>
> > + pwms = <&pwm1 0 500000>;
> > + };
> > +
> > + gpio_buttons {
>
> Use hyphen.
>
> > + compatible = "gpio-keys";
> > + pinctrl-names = "default";
> > + pinctrl-0 = <&pinctrl_gpiobuttons>;
> > +
> > + button_kalt {
>
> Ditto
>
> > + label = "Kaltstart";
> > + linux,code = <KEY_F6>;
> > + gpios = <&gpio2 26 GPIO_ACTIVE_HIGH>;
> > + };
> > +
> > + button_pwr {
>
> Ditto
>
> > + label = "PowerFailInterrupt";
> > + linux,code = <KEY_F7>;
> > + gpios = <&gpio3 22 GPIO_ACTIVE_HIGH>;
> > + };
> > + };
> > +
> > + leds {
> > + compatible = "gpio-leds";
> > + pinctrl-names = "default";
> > + pinctrl-0 = <&pinctrl_leds>;
> > +
> > + led_bus {
>
> Ditto
>
> > + label = "bus";
> > + gpios = <&gpio2 30 GPIO_ACTIVE_HIGH>;
> > + linux,default-trigger = "gpio";
> > + default-state = "off";
> > + };
> > +
> > + led_error {
>
> Ditto
>
> > + label = "error";
> > + gpios = <&gpio3 28 GPIO_ACTIVE_HIGH>;
> > + linux,default-trigger = "gpio";
> > + default-state = "off";
> > + };
> > +
> > + led_flash {
>
> Ditto
>
> > + label = "flash";
> > + gpios = <&gpio5 0 GPIO_ACTIVE_HIGH>;
> > + linux,default-trigger = "heartbeat";
> > + };
> > + };
> > +
> > + reg_3v3: regulator-3v3 {
> > + compatible = "regulator-fixed";
> > + regulator-name = "3V3";
> > + regulator-min-microvolt = <3300000>;
> > + regulator-max-microvolt = <3300000>;
> > + regulator-always-on;
> > + };
> > +};
> > +
> > +&can1 {
> > + status = "okay";
> > +};
> > +
> > +&can2 {
> > + status = "okay";
> > +};
> > +
> > +&i2c3 {
> > + status = "okay";
> > +
> > + gpio_expander1 at 22 {
>
> Ditto
>
> Shawn
>
> > + compatible = "nxp,pcf8574";
> > + reg = <0x22>;
> > + interrupts = <109>;
> > + #gpio-cells = <2>;
> > + gpio-controller;
> > + };
> > +
> > + rtc at 51 {
> > + compatible = "nxp,pcf8563";
> > + reg = <0x51>;
> > + };
> > +};
> > +
> > +&iomuxc {
> > + pinctrl-names = "default";
> > + pinctrl-0 = <&pinctrl_kp_common>;
> > +
> > + imx53-kp-common {
> > + pinctrl_buzzer: buzzergrp {
> > + fsl,pins = <
> > + MX53_PAD_SD1_DATA3__PWM1_PWMO 0x1e4
> > + >;
> > + };
> > +
> > + pinctrl_gpiobuttons: gpiobuttonsgrp {
> > + fsl,pins = <
> > + MX53_PAD_EIM_RW__GPIO2_26 0x1e4
> > + MX53_PAD_EIM_D22__GPIO3_22 0x1e4
> > + >;
> > + };
> > +
> > + pinctrl_kp_common: kpcommongrp {
> > + fsl,pins = <
> > + MX53_PAD_EIM_CS0__GPIO2_23 0x1e4
> > + MX53_PAD_GPIO_19__GPIO4_5 0x1e4
> > + MX53_PAD_PATA_DATA6__GPIO2_6 0x1e4
> > + MX53_PAD_PATA_DATA7__GPIO2_7 0xe0
> > + MX53_PAD_CSI0_DAT14__GPIO6_0 0x1e4
> > + MX53_PAD_CSI0_DAT16__GPIO6_2 0x1e4
> > + MX53_PAD_CSI0_DAT18__GPIO6_4 0x1e4
> > + MX53_PAD_EIM_D17__GPIO3_17 0x1e4
> > + MX53_PAD_EIM_D18__GPIO3_18 0x1e4
> > + MX53_PAD_EIM_D21__GPIO3_21 0x1e4
> > + MX53_PAD_EIM_D29__GPIO3_29 0x1e4
> > + MX53_PAD_EIM_DA11__GPIO3_11 0x1e4
> > + MX53_PAD_EIM_DA13__GPIO3_13 0x1e4
> > + MX53_PAD_EIM_DA14__GPIO3_14 0x1e4
> > + MX53_PAD_SD1_DATA0__GPIO1_16 0x1e4
> > + MX53_PAD_SD1_CMD__GPIO1_18 0x1e4
> > + MX53_PAD_SD1_CLK__GPIO1_20 0x1e4
> > + >;
> > + };
> > +
> > + pinctrl_leds: ledgrp {
> > + fsl,pins = <
> > + MX53_PAD_EIM_EB2__GPIO2_30 0x1d4
> > + MX53_PAD_EIM_D28__GPIO3_28 0x1d4
> > + MX53_PAD_EIM_WAIT__GPIO5_0 0x1d4
> > + >;
> > + };
> > +
> > + pinctrl_uart4: uart4grp {
> > + fsl,pins = <
> > + MX53_PAD_CSI0_DAT12__UART4_TXD_MUX
> > 0x1e4
> > + MX53_PAD_CSI0_DAT13__UART4_RXD_MUX
> > 0x1e4
> > + >;
> > + };
> > + };
> > +};
> > +
> > +&pinctrl_uart1 {
> > + fsl,pins = <
> > + MX53_PAD_EIM_D23__GPIO3_23 0x1e4
> > + MX53_PAD_EIM_EB3__GPIO2_31 0x1e4
> > + MX53_PAD_EIM_D24__GPIO3_24 0x1e4
> > + MX53_PAD_EIM_D25__GPIO3_25 0x1e4
> > + MX53_PAD_EIM_D19__GPIO3_19 0x1e4
> > + MX53_PAD_EIM_D20__GPIO3_20 0x1e4
> > + >;
> > +};
> > +
> > +&uart1 {
> > + status = "okay";
> > +};
> > +
> > +&uart2 {
> > + status = "okay";
> > +};
> > +
> > +&uart3 {
> > + status = "okay";
> > +};
> > +
> > +&uart4 {
> > + pinctrl-names = "default";
> > + pinctrl-0 = <&pinctrl_uart4>;
> > + status = "okay";
> > +};
> > +
> > +&usbh1 {
> > + status = "okay";
> > +};
> > +
> > +&usbphy0 {
> > + status = "disabled";
> > +};
> > --
> > 2.11.0
> >
Best regards,
Lukasz Majewski
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 488 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180612/dbdb4b81/attachment-0001.sig>
^ permalink raw reply
* handling voice calls in ALSA soc (on Droid 4)
From: Pavel Machek @ 2018-06-12 12:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180611121548.GB11580@sirena.org.uk>
Hi!
Sebastian, would you have pointer to original Motorola sources you
used for inspiration?
> > With setup like that, how does userland tell kernel that the baseband
> > <-> microphone/speaker connection should be activated?
>
> Audio routing should be done as normal, and ideally the driver for the
> modem will be able to figure out if there's an active call or not. If
> userspace has to enable the input and output manually then you can set
> up SOC_DAPM_PIN_SWITCH()es as normal.
Modem talks AT commands, so the driver is in userspace for now.
I tried SOC_DAPM_PIN_SWITCH(), but it results in alsamixer oopsing, I
guess I'm doing something wrong.
Message from syslogd at devuan at Jun 12 13:51:31 ...
kernel:[ 743.678588] BUG: spinlock bad magic on CPU#1,
alsamixer/2217
Message from syslogd at devuan at Jun 12 13:51:31 ...
kernel:[ 743.684417] lock: 0xede423a0, .magic: eee2a6a4, .owner:
<none>/-1, .owner_cpu: -287136604
I'm trying to understand how it is supposed to work, but
https://www.alsa-project.org/main/index.php/DAPM has TODO's at
critical places. If there's better source of information, let me know.
Best regards,
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 181 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180612/2a174be2/attachment.sig>
^ permalink raw reply
* [PATCH v7 3/6] kernel/reboot.c: export pm_power_off_prepare
From: Oleksij Rempel @ 2018-06-12 12:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180517055014.6607-4-o.rempel@pengutronix.de>
Hi Rafael,
Last version of this patch was send at 17.05.2018. No other comment was
provided and this patch is a blocker for other patches in this serie.
Can you please give some feedback on it.
On 17.05.2018 07:50, Oleksij Rempel wrote:
> Export pm_power_off_prepare. It is needed to implement power off on
> Freescale/NXP iMX6 based boards with external power management
> integrated circuit (PMIC).
>
> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> ---
> kernel/reboot.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/kernel/reboot.c b/kernel/reboot.c
> index e4ced883d8de..83810d726f3e 100644
> --- a/kernel/reboot.c
> +++ b/kernel/reboot.c
> @@ -49,6 +49,7 @@ int reboot_force;
> */
>
> void (*pm_power_off_prepare)(void);
> +EXPORT_SYMBOL_GPL(pm_power_off_prepare);
>
> /**
> * emergency_restart - reboot the system
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180612/cf8a0197/attachment.sig>
^ permalink raw reply
* [PATCH RESEND v4 2/2] arm/arm64: KVM: Add KVM_GET/SET_VCPU_EVENTS
From: gengdongjiu @ 2018-06-12 12:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180609111745.GJ5097@C02W217FHV2R.local>
Christoffer,
Thanks for the review.
On 2018/6/9 19:17, Christoffer Dall wrote:
> On Sat, Jun 09, 2018 at 03:48:40AM +0800, Dongjiu Geng wrote:
>> For the migrating VMs, user space may need to know the exception
>> state. For example, in the machine A, KVM make an SError pending,
>> when migrate to B, KVM also needs to pend an SError.
>>
>> This new IOCTL exports user-invisible states related to SError.
>> Together with appropriate user space changes, user space can get/set
>> the SError exception state to do migrate/snapshot/suspend.
>>
>> Signed-off-by: Dongjiu Geng <gengdongjiu@huawei.com>
>> ---
>> change since v3:
>> 1. Fix the memset() issue in the kvm_arm_vcpu_get_events()
>>
>> change since v2:
>> 1. Add kvm_vcpu_events structure definition for arm platform to avoid the build errors.
>>
>> change since v1:
>> Address Marc's comments, thanks Marc's review
>> 1. serror_has_esr always true when ARM64_HAS_RAS_EXTN is set
>> 2. remove Spurious blank line in kvm_arm_vcpu_set_events()
>> 3. rename pend_guest_serror() to kvm_set_sei_esr()
>> 4. Make kvm_arm_vcpu_get_events() did all the work rather than having this split responsibility.
>> 5. using sizeof(events) instead of sizeof(struct kvm_vcpu_events)
>>
>> this series patch is separated from https://www.spinics.net/lists/kvm/msg168917.html
>> The user space patch is here: https://lists.gnu.org/archive/html/qemu-devel/2018-05/msg06965.html
>>
>> change since V12:
>> 1. change (vcpu->arch.hcr_el2 & HCR_VSE) to !!(vcpu->arch.hcr_el2 & HCR_VSE) in kvm_arm_vcpu_get_events()
>>
>> Change since V11:
>> Address James's comments, thanks James
>> 1. Align the struct of kvm_vcpu_events to 64 bytes
>> 2. Avoid exposing the stale ESR value in the kvm_arm_vcpu_get_events()
>> 3. Change variables 'injected' name to 'serror_pending' in the kvm_arm_vcpu_set_events()
>> 4. Change to sizeof(events) from sizeof(struct kvm_vcpu_events) in kvm_arch_vcpu_ioctl()
>>
>> Change since V10:
>> Address James's comments, thanks James
>> 1. Merge the helper function with the user.
>> 2. Move the ISS_MASK into pend_guest_serror() to clear top bits
>> 3. Make kvm_vcpu_events struct align to 4 bytes
>> 4. Add something check in the kvm_arm_vcpu_set_events()
>> 5. Check kvm_arm_vcpu_get/set_events()'s return value.
>> 6. Initialise kvm_vcpu_events to 0 so that padding transferred to user-space doesn't
>> contain kernel stack.
>> ---
>> Documentation/virtual/kvm/api.txt | 31 ++++++++++++++++++++++++++++---
>> arch/arm/include/asm/kvm_host.h | 6 ++++++
>> arch/arm/include/uapi/asm/kvm.h | 12 ++++++++++++
>> arch/arm/kvm/guest.c | 12 ++++++++++++
>> arch/arm64/include/asm/kvm_emulate.h | 5 +++++
>> arch/arm64/include/asm/kvm_host.h | 7 +++++++
>> arch/arm64/include/uapi/asm/kvm.h | 13 +++++++++++++
>> arch/arm64/kvm/guest.c | 36 ++++++++++++++++++++++++++++++++++++
>> arch/arm64/kvm/inject_fault.c | 6 +++---
>> arch/arm64/kvm/reset.c | 1 +
>> virt/kvm/arm/arm.c | 19 +++++++++++++++++++
>> 11 files changed, 142 insertions(+), 6 deletions(-)
>>
>> diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
>> index fdac969..8896737 100644
>> --- a/Documentation/virtual/kvm/api.txt
>> +++ b/Documentation/virtual/kvm/api.txt
>> @@ -835,11 +835,13 @@ struct kvm_clock_data {
>>
>> Capability: KVM_CAP_VCPU_EVENTS
>> Extended by: KVM_CAP_INTR_SHADOW
>> -Architectures: x86
>> +Architectures: x86, arm, arm64
>> Type: vm ioctl
>> Parameters: struct kvm_vcpu_event (out)
>> Returns: 0 on success, -1 on error
>>
>> +X86:
>> +
>> Gets currently pending exceptions, interrupts, and NMIs as well as related
>> states of the vcpu.
>>
>> @@ -881,15 +883,32 @@ Only two fields are defined in the flags field:
>> - KVM_VCPUEVENT_VALID_SMM may be set in the flags field to signal that
>> smi contains a valid state.
>>
>> +ARM, ARM64:
>> +
>> +Gets currently pending SError exceptions as well as related states of the vcpu.
>> +
>> +struct kvm_vcpu_events {
>> + struct {
>> + __u8 serror_pending;
>> + __u8 serror_has_esr;
>> + /* Align it to 8 bytes */
>> + __u8 pad[6];
>> + __u64 serror_esr;
>> + } exception;
>> + __u32 reserved[12];
>> +};
>> +
>> 4.32 KVM_SET_VCPU_EVENTS
>>
>> -Capability: KVM_CAP_VCPU_EVENTS
>> +Capebility: KVM_CAP_VCPU_EVENTS
>
> nit: unintended change?
>
>> Extended by: KVM_CAP_INTR_SHADOW
>> -Architectures: x86
>> +Architectures: x86, arm, arm64
>> Type: vm ioctl
>> Parameters: struct kvm_vcpu_event (in)
>> Returns: 0 on success, -1 on error
>>
>> +X86:
>> +
>> Set pending exceptions, interrupts, and NMIs as well as related states of the
>> vcpu.
>>
>> @@ -910,6 +929,12 @@ shall be written into the VCPU.
>>
>> KVM_VCPUEVENT_VALID_SMM can only be set if KVM_CAP_X86_SMM is available.
>>
>> +ARM, ARM64:
>> +
>> +Set pending SError exceptions as well as related states of the vcpu.
>> +
>> +See KVM_GET_VCPU_EVENTS for the data structure.
>> +
>>
>> 4.33 KVM_GET_DEBUGREGS
>>
>> diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
>> index c7c28c8..39f9901 100644
>> --- a/arch/arm/include/asm/kvm_host.h
>> +++ b/arch/arm/include/asm/kvm_host.h
>> @@ -213,6 +213,12 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu);
>> int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);
>> int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
>> int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
>> +int kvm_arm_vcpu_get_events(struct kvm_vcpu *vcpu,
>> + struct kvm_vcpu_events *events);
>> +
>> +int kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu,
>> + struct kvm_vcpu_events *events);
>> +
>> unsigned long kvm_call_hyp(void *hypfn, ...);
>> void force_vm_exit(const cpumask_t *mask);
>>
>> diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
>> index caae484..c3e6975 100644
>> --- a/arch/arm/include/uapi/asm/kvm.h
>> +++ b/arch/arm/include/uapi/asm/kvm.h
>> @@ -124,6 +124,18 @@ struct kvm_sync_regs {
>> struct kvm_arch_memory_slot {
>> };
>>
>> +/* for KVM_GET/SET_VCPU_EVENTS */
>> +struct kvm_vcpu_events {
>> + struct {
>> + __u8 serror_pending;
>> + __u8 serror_has_esr;
>> + /* Align it to 8 bytes */
>> + __u8 pad[6];
>> + __u64 serror_esr;
>> + } exception;
>> + __u32 reserved[12];
>> +};
>> +
>> /* If you need to interpret the index values, here is the key: */
>> #define KVM_REG_ARM_COPROC_MASK 0x000000000FFF0000
>> #define KVM_REG_ARM_COPROC_SHIFT 16
>> diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c
>> index a18f33e..c685f0e 100644
>> --- a/arch/arm/kvm/guest.c
>> +++ b/arch/arm/kvm/guest.c
>> @@ -261,6 +261,18 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
>> return -EINVAL;
>> }
>>
>> +int kvm_arm_vcpu_get_events(struct kvm_vcpu *vcpu,
>> + struct kvm_vcpu_events *events)
>> +{
>> + return -EINVAL;
>> +}
>> +
>> +int kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu,
>> + struct kvm_vcpu_events *events)
>> +{
>> + return -EINVAL;
>> +}
>> +
>> int __attribute_const__ kvm_target_cpu(void)
>> {
>> switch (read_cpuid_part()) {
>> diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
>> index 1dab3a9..18f61ff 100644
>> --- a/arch/arm64/include/asm/kvm_emulate.h
>> +++ b/arch/arm64/include/asm/kvm_emulate.h
>> @@ -81,6 +81,11 @@ static inline unsigned long *vcpu_hcr(struct kvm_vcpu *vcpu)
>> return (unsigned long *)&vcpu->arch.hcr_el2;
>> }
>>
>> +static inline unsigned long vcpu_get_vsesr(struct kvm_vcpu *vcpu)
>> +{
>> + return vcpu->arch.vsesr_el2;
>> +}
>> +
>> static inline void vcpu_set_vsesr(struct kvm_vcpu *vcpu, u64 vsesr)
>> {
>> vcpu->arch.vsesr_el2 = vsesr;
>> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
>> index 469de8a..357304a 100644
>> --- a/arch/arm64/include/asm/kvm_host.h
>> +++ b/arch/arm64/include/asm/kvm_host.h
>> @@ -335,6 +335,11 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu);
>> int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);
>> int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
>> int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
>> +int kvm_arm_vcpu_get_events(struct kvm_vcpu *vcpu,
>> + struct kvm_vcpu_events *events);
>> +
>> +int kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu,
>> + struct kvm_vcpu_events *events);
>>
>> #define KVM_ARCH_WANT_MMU_NOTIFIER
>> int kvm_unmap_hva(struct kvm *kvm, unsigned long hva);
>> @@ -363,6 +368,8 @@ void handle_exit_early(struct kvm_vcpu *vcpu, struct kvm_run *run,
>> int kvm_perf_init(void);
>> int kvm_perf_teardown(void);
>>
>> +void kvm_set_sei_esr(struct kvm_vcpu *vcpu, u64 syndrome);
>> +
>> struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr);
>>
>> void __kvm_set_tpidr_el2(u64 tpidr_el2);
>> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
>> index 04b3256..df4faee 100644
>> --- a/arch/arm64/include/uapi/asm/kvm.h
>> +++ b/arch/arm64/include/uapi/asm/kvm.h
>> @@ -39,6 +39,7 @@
>> #define __KVM_HAVE_GUEST_DEBUG
>> #define __KVM_HAVE_IRQ_LINE
>> #define __KVM_HAVE_READONLY_MEM
>> +#define __KVM_HAVE_VCPU_EVENTS
>>
>> #define KVM_COALESCED_MMIO_PAGE_OFFSET 1
>>
>> @@ -153,6 +154,18 @@ struct kvm_sync_regs {
>> struct kvm_arch_memory_slot {
>> };
>>
>> +/* for KVM_GET/SET_VCPU_EVENTS */
>> +struct kvm_vcpu_events {
>> + struct {
>> + __u8 serror_pending;
>> + __u8 serror_has_esr;
>> + /* Align it to 8 bytes */
>> + __u8 pad[6];
>> + __u64 serror_esr;
>> + } exception;
>> + __u32 reserved[12];
>> +};
>> +
>> /* If you need to interpret the index values, here is the key: */
>> #define KVM_REG_ARM_COPROC_MASK 0x000000000FFF0000
>> #define KVM_REG_ARM_COPROC_SHIFT 16
>> diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
>> index 56a0260..4426915 100644
>> --- a/arch/arm64/kvm/guest.c
>> +++ b/arch/arm64/kvm/guest.c
>> @@ -289,6 +289,42 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
>> return -EINVAL;
>> }
>>
>> +int kvm_arm_vcpu_get_events(struct kvm_vcpu *vcpu,
>> + struct kvm_vcpu_events *events)
>> +{
>> + memset(events, 0, sizeof(*events));
>> +
>> + events->exception.serror_pending = !!(vcpu->arch.hcr_el2 & HCR_VSE);
>> + events->exception.serror_has_esr =
>> + cpus_have_const_cap(ARM64_HAS_RAS_EXTN);
>
> nit: no need to wrap this line so strangely, just keep it on a single
> line (regardless of going slightly over the 80 chars limit).
Ok, will fix it.
>
>> +
>> + if (events->exception.serror_pending &&
>> + events->exception.serror_has_esr)
>
> same here
OK, will fix it.
>
>> + events->exception.serror_esr = vcpu_get_vsesr(vcpu);
>> + else
>> + events->exception.serror_esr = 0;
>> +
>> + return 0;
>> +}
>> +
>> +int kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu,
>> + struct kvm_vcpu_events *events)
>> +{
>> + bool serror_pending = events->exception.serror_pending;
>> + bool has_esr = events->exception.serror_has_esr;
>> +
>> + if (serror_pending && has_esr) {
>> + if (!cpus_have_const_cap(ARM64_HAS_RAS_EXTN))
>> + return -EINVAL;
>> +
>> + kvm_set_sei_esr(vcpu, events->exception.serror_esr);
>> + } else if (serror_pending) {
>> + kvm_inject_vabt(vcpu);
>> + }
>> +
>> + return 0;
>> +}
>> +
>> int __attribute_const__ kvm_target_cpu(void)
>> {
>> unsigned long implementor = read_cpuid_implementor();
>> diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
>> index d8e7165..a55e91d 100644
>> --- a/arch/arm64/kvm/inject_fault.c
>> +++ b/arch/arm64/kvm/inject_fault.c
>> @@ -164,9 +164,9 @@ void kvm_inject_undefined(struct kvm_vcpu *vcpu)
>> inject_undef64(vcpu);
>> }
>>
>> -static void pend_guest_serror(struct kvm_vcpu *vcpu, u64 esr)
>> +void kvm_set_sei_esr(struct kvm_vcpu *vcpu, u64 esr)
>> {
>> - vcpu_set_vsesr(vcpu, esr);
>> + vcpu_set_vsesr(vcpu, esr & ESR_ELx_ISS_MASK);
>> *vcpu_hcr(vcpu) |= HCR_VSE;
>> }
>>
>> @@ -184,5 +184,5 @@ static void pend_guest_serror(struct kvm_vcpu *vcpu, u64 esr)
>> */
>> void kvm_inject_vabt(struct kvm_vcpu *vcpu)
>> {
>> - pend_guest_serror(vcpu, ESR_ELx_ISV);
>> + kvm_set_sei_esr(vcpu, ESR_ELx_ISV);
>> }
>> diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
>> index 38c8a64..20e919a 100644
>> --- a/arch/arm64/kvm/reset.c
>> +++ b/arch/arm64/kvm/reset.c
>> @@ -82,6 +82,7 @@ int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, long ext)
>> break;
>> case KVM_CAP_SET_GUEST_DEBUG:
>> case KVM_CAP_VCPU_ATTRIBUTES:
>> + case KVM_CAP_VCPU_EVENTS:
>> r = 1;
>> break;
>> default:
>> diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
>> index a4c1b76..79ecba9 100644
>> --- a/virt/kvm/arm/arm.c
>> +++ b/virt/kvm/arm/arm.c
>> @@ -1107,6 +1107,25 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
>> r = kvm_arm_vcpu_has_attr(vcpu, &attr);
>> break;
>> }
>> + case KVM_GET_VCPU_EVENTS: {
>> + struct kvm_vcpu_events events;
>> +
>> + if (kvm_arm_vcpu_get_events(vcpu, &events))
>> + return -EINVAL;
>> +
>> + if (copy_to_user(argp, &events, sizeof(events)))
>> + return -EFAULT;
>> +
>> + return 0;
>> + }
>> + case KVM_SET_VCPU_EVENTS: {
>> + struct kvm_vcpu_events events;
>> +
>> + if (copy_from_user(&events, argp, sizeof(events)))
>> + return -EFAULT;
>> +
>> + return kvm_arm_vcpu_set_events(vcpu, &events);
>> + }
>> default:
>> r = -EINVAL;
>> }
>> --
>> 2.7.4
>>
>
> I'll leave it to James to comment on the specifics of the RAS
> interaction, but I think the two patches should be re-ordered, so that
> the capability patch comes last, after the functionality has been
> introduced.
ok, I will reorder them in the next version.
>
> Otherwise this looks reasonable enough.
>
> Thanks,
> -Christoffer
>
> .
>
^ permalink raw reply
* [PATCH v2 1/6] arm64: KVM: Add support for Stage-2 control of memory types and cacheability
From: Marc Zyngier @ 2018-06-12 12:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <6675e8b0-7c34-ce1f-99e2-1f63566b3426@arm.com>
On 31/05/18 13:38, Marc Zyngier wrote:
> On 31/05/18 12:49, Mark Rutland wrote:
>> On Wed, May 30, 2018 at 01:47:01PM +0100, Marc Zyngier wrote:
>>> Up to ARMv8.3, the combinaison of Stage-1 and Stage-2 attributes
>>> results in the strongest attribute of the two stages. This means
>>> that the hypervisor has to perform quite a lot of cache maintenance
>>> just in case the guest has some non-cacheable mappings around.
>>>
>>> ARMv8.4 solves this problem by offering a different mode (FWB) where
>>> Stage-2 has total control over the memory attribute (this is limited
>>> to systems where both I/O and instruction caches are coherent with
>>
>> s/caches/fetches/ -- the I-caches themselves aren't coherent with the
>> D-caches (or we could omit I-cache maintenance).
>>
>> i.e. this implies IDC, but not DIC.
>
> It may imply IDC behaviour, but not quite IDC itself. I agree, this
> looks dodgy. I've asked for clarification on the spec.
I've now received confirmation that FWB implies the IDC behaviour. It
doesn't guarantee that CTR_EL0.IDC will be set though, only that
CLIDR_EL1.LOU{U,IS} are both 0.
>
>>
>>> the dcache). This is achieved by having a different set of memory
>>> attributes in the page tables, and a new bit set in HCR_EL2.
>>>
>>> On such a system, we can then safely sidestep any form of dcache
>>> management.
>>>
>>> Acked-by: Catalin Marinas <catalin.marinas@arm.com>
>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>>> ---
>>
>>> static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu)
>>> {
>>> @@ -268,7 +269,10 @@ static inline void __clean_dcache_guest_page(kvm_pfn_t pfn, unsigned long size)
>>> {
>>> void *va = page_address(pfn_to_page(pfn));
>>>
>>> - kvm_flush_dcache_to_poc(va, size);
>>> + if (!cpus_have_const_cap(ARM64_HAS_STAGE2_FWB))
>>> + kvm_flush_dcache_to_poc(va, size);
>>> + else
>>> + kvm_flush_dcache_to_pou(va, size);
>>> }
>>
>> Te commit message said instruction fetches were coherent, and that no
>> D-cache maintenance was necessary, so why do we need maintenance to the
>> PoU?
>
> That maintenance will be elided if we actually have IDC set. I'm happy
> to drop it once I have confirmation that we have an identical behaviour.
Given the above, I'll drop the clean to PoU.
>
>>
>>> +static void cpu_has_fwb(const struct arm64_cpu_capabilities *__unused)
>>> +{
>>> + u64 val = read_sysreg_s(SYS_CLIDR_EL1);
>>> +
>>> + /* Check that CLIDR_EL1.LOU{U,IS} are both 0 */
>>> + WARN_ON(val & (7 << 27 | 7 << 21));
>>> +}
>>
>> What about CTR_EL0.IDC?
>
> Again, that depends on whether FWB implies IDC or not.
The spec doesn't seem to guarantee IDC, but does mandate that
CLIDR_EL1.LOU{U,IS} are set 0.
Thanks,
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply
* [GIT PULL 2/4] ARM: Device-tree updates
From: Heiko Stuebner @ 2018-06-12 13:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CA+55aFy2sOHqcO-6LaKOZ5omyAow15gq+=Z7aOTZisrDihoecw@mail.gmail.com>
Am Dienstag, 12. Juni 2018, 03:04:34 CEST schrieb Linus Torvalds:
> On Mon, Jun 11, 2018 at 5:02 PM Olof Johansson <olof@lixom.net> wrote:
> >
> > - Qualcomm:
> > + SDM845, a.k.a Snapdragon 845, an 4+4-core Kryo 385/845
> > (Cortex-A75/A55 derivative) SoC that's one of the current high-end
> > mobile SoCs.
> >
> > It's great to see mainline support for it. So far, you
> > can't do much with it, since a lot of peripherals are not yet in the
> > DTs but driver support for USB, GPU and other pieces are starting to
> > trickle in. This might end up being a well-supported SoC upstream if
> > the momentum keeps up.
>
> Isn't the Qualcomm 845 also the SoC in some of the new WARM laptops?
>
> I asked one person that had an older one (ASUS NovaGo - Qualcomm 835),
> and apparently you can actually disable secure boot on that thing and
> boot from USB.
>
> In other words, it might _actually_ act like a normal laptop.
>
> I'd love to have something that is actually a real honest-to-goodness
> ARM laptop finally. Are we getting at all close to that?
I guess the Samsung Chromebook Plus (Rockchip RK3399-based [branded
OP1 though]) also is somewhat close to that target - even with a nice
high-res display and everything except the 32kb BootRom being replaceable.
Of course Qualcomm-based devices have the Adreno/Freedreno bonus,
but even in that area we're seeing some progress for Mali (Midgard)
this year [0].
[0] https://rosenzweig.io/blog/a-moving-mesa-midgard-cube.html
^ permalink raw reply
* [PATCH RESEND v4 2/2] arm/arm64: KVM: Add KVM_GET/SET_VCPU_EVENTS
From: gengdongjiu @ 2018-06-12 13:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <86zi04875t.wl-marc.zyngier@arm.com>
Hi Marc
thanks for the review.
On 2018/6/9 20:40, Marc Zyngier wrote:
> On Fri, 08 Jun 2018 20:48:40 +0100,
> Dongjiu Geng wrote:
>>
>> For the migrating VMs, user space may need to know the exception
>> state. For example, in the machine A, KVM make an SError pending,
>> when migrate to B, KVM also needs to pend an SError.
>>
>> This new IOCTL exports user-invisible states related to SError.
>> Together with appropriate user space changes, user space can get/set
>> the SError exception state to do migrate/snapshot/suspend.
>>
>> Signed-off-by: Dongjiu Geng <gengdongjiu@huawei.com>
>> ---
>> change since v3:
>> 1. Fix the memset() issue in the kvm_arm_vcpu_get_events()
>>
>> change since v2:
>> 1. Add kvm_vcpu_events structure definition for arm platform to avoid the build errors.
>>
>> change since v1:
>> Address Marc's comments, thanks Marc's review
>> 1. serror_has_esr always true when ARM64_HAS_RAS_EXTN is set
>> 2. remove Spurious blank line in kvm_arm_vcpu_set_events()
>> 3. rename pend_guest_serror() to kvm_set_sei_esr()
>> 4. Make kvm_arm_vcpu_get_events() did all the work rather than having this split responsibility.
>> 5. using sizeof(events) instead of sizeof(struct kvm_vcpu_events)
>>
>> this series patch is separated from https://www.spinics.net/lists/kvm/msg168917.html
>> The user space patch is here: https://lists.gnu.org/archive/html/qemu-devel/2018-05/msg06965.html
>>
>> change since V12:
>> 1. change (vcpu->arch.hcr_el2 & HCR_VSE) to !!(vcpu->arch.hcr_el2 & HCR_VSE) in kvm_arm_vcpu_get_events()
>>
>> Change since V11:
>> Address James's comments, thanks James
>> 1. Align the struct of kvm_vcpu_events to 64 bytes
>> 2. Avoid exposing the stale ESR value in the kvm_arm_vcpu_get_events()
>> 3. Change variables 'injected' name to 'serror_pending' in the kvm_arm_vcpu_set_events()
>> 4. Change to sizeof(events) from sizeof(struct kvm_vcpu_events) in kvm_arch_vcpu_ioctl()
>>
>> Change since V10:
>> Address James's comments, thanks James
>> 1. Merge the helper function with the user.
>> 2. Move the ISS_MASK into pend_guest_serror() to clear top bits
>> 3. Make kvm_vcpu_events struct align to 4 bytes
>> 4. Add something check in the kvm_arm_vcpu_set_events()
>> 5. Check kvm_arm_vcpu_get/set_events()'s return value.
>> 6. Initialise kvm_vcpu_events to 0 so that padding transferred to user-space doesn't
>> contain kernel stack.
>> ---
>> Documentation/virtual/kvm/api.txt | 31 ++++++++++++++++++++++++++++---
>> arch/arm/include/asm/kvm_host.h | 6 ++++++
>> arch/arm/include/uapi/asm/kvm.h | 12 ++++++++++++
>> arch/arm/kvm/guest.c | 12 ++++++++++++
>> arch/arm64/include/asm/kvm_emulate.h | 5 +++++
>> arch/arm64/include/asm/kvm_host.h | 7 +++++++
>> arch/arm64/include/uapi/asm/kvm.h | 13 +++++++++++++
>> arch/arm64/kvm/guest.c | 36 ++++++++++++++++++++++++++++++++++++
>> arch/arm64/kvm/inject_fault.c | 6 +++---
>> arch/arm64/kvm/reset.c | 1 +
>> virt/kvm/arm/arm.c | 19 +++++++++++++++++++
>> 11 files changed, 142 insertions(+), 6 deletions(-)
>>
>> diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
>> index fdac969..8896737 100644
>> --- a/Documentation/virtual/kvm/api.txt
>> +++ b/Documentation/virtual/kvm/api.txt
>> @@ -835,11 +835,13 @@ struct kvm_clock_data {
>>
>> Capability: KVM_CAP_VCPU_EVENTS
>> Extended by: KVM_CAP_INTR_SHADOW
>> -Architectures: x86
>> +Architectures: x86, arm, arm64
>> Type: vm ioctl
>> Parameters: struct kvm_vcpu_event (out)
>> Returns: 0 on success, -1 on error
>>
>> +X86:
>> +
>> Gets currently pending exceptions, interrupts, and NMIs as well as related
>> states of the vcpu.
>>
>> @@ -881,15 +883,32 @@ Only two fields are defined in the flags field:
>> - KVM_VCPUEVENT_VALID_SMM may be set in the flags field to signal that
>> smi contains a valid state.
>>
>> +ARM, ARM64:
>> +
>> +Gets currently pending SError exceptions as well as related states of the vcpu.
>> +
>> +struct kvm_vcpu_events {
>> + struct {
>> + __u8 serror_pending;
>> + __u8 serror_has_esr;
>> + /* Align it to 8 bytes */
>> + __u8 pad[6];
>> + __u64 serror_esr;
>> + } exception;
>> + __u32 reserved[12];
>> +};
>> +
>> 4.32 KVM_SET_VCPU_EVENTS
>>
>> -Capability: KVM_CAP_VCPU_EVENTS
>> +Capebility: KVM_CAP_VCPU_EVENTS
>> Extended by: KVM_CAP_INTR_SHADOW
>> -Architectures: x86
>> +Architectures: x86, arm, arm64
>> Type: vm ioctl
>> Parameters: struct kvm_vcpu_event (in)
>> Returns: 0 on success, -1 on error
>>
>> +X86:
>> +
>> Set pending exceptions, interrupts, and NMIs as well as related states of the
>> vcpu.
>>
>> @@ -910,6 +929,12 @@ shall be written into the VCPU.
>>
>> KVM_VCPUEVENT_VALID_SMM can only be set if KVM_CAP_X86_SMM is available.
>>
>> +ARM, ARM64:
>> +
>> +Set pending SError exceptions as well as related states of the vcpu.
>> +
>> +See KVM_GET_VCPU_EVENTS for the data structure.
>> +
>>
>> 4.33 KVM_GET_DEBUGREGS
>>
>> diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
>> index c7c28c8..39f9901 100644
>> --- a/arch/arm/include/asm/kvm_host.h
>> +++ b/arch/arm/include/asm/kvm_host.h
>> @@ -213,6 +213,12 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu);
>> int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);
>> int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
>> int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
>> +int kvm_arm_vcpu_get_events(struct kvm_vcpu *vcpu,
>> + struct kvm_vcpu_events *events);
>> +
>> +int kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu,
>> + struct kvm_vcpu_events *events);
>> +
>> unsigned long kvm_call_hyp(void *hypfn, ...);
>> void force_vm_exit(const cpumask_t *mask);
>>
>> diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
>> index caae484..c3e6975 100644
>> --- a/arch/arm/include/uapi/asm/kvm.h
>> +++ b/arch/arm/include/uapi/asm/kvm.h
>> @@ -124,6 +124,18 @@ struct kvm_sync_regs {
>> struct kvm_arch_memory_slot {
>> };
>>
>> +/* for KVM_GET/SET_VCPU_EVENTS */
>> +struct kvm_vcpu_events {
>> + struct {
>> + __u8 serror_pending;
>> + __u8 serror_has_esr;
>> + /* Align it to 8 bytes */
>> + __u8 pad[6];
>> + __u64 serror_esr;
>> + } exception;
>> + __u32 reserved[12];
>> +};
>> +
>> /* If you need to interpret the index values, here is the key: */
>> #define KVM_REG_ARM_COPROC_MASK 0x000000000FFF0000
>> #define KVM_REG_ARM_COPROC_SHIFT 16
>> diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c
>> index a18f33e..c685f0e 100644
>> --- a/arch/arm/kvm/guest.c
>> +++ b/arch/arm/kvm/guest.c
>> @@ -261,6 +261,18 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
>> return -EINVAL;
>> }
>>
>> +int kvm_arm_vcpu_get_events(struct kvm_vcpu *vcpu,
>> + struct kvm_vcpu_events *events)
>> +{
>> + return -EINVAL;
>> +}
>> +
>> +int kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu,
>> + struct kvm_vcpu_events *events)
>> +{
>> + return -EINVAL;
>> +}
>> +
>> int __attribute_const__ kvm_target_cpu(void)
>> {
>> switch (read_cpuid_part()) {
>> diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
>> index 1dab3a9..18f61ff 100644
>> --- a/arch/arm64/include/asm/kvm_emulate.h
>> +++ b/arch/arm64/include/asm/kvm_emulate.h
>> @@ -81,6 +81,11 @@ static inline unsigned long *vcpu_hcr(struct kvm_vcpu *vcpu)
>> return (unsigned long *)&vcpu->arch.hcr_el2;
>> }
>>
>> +static inline unsigned long vcpu_get_vsesr(struct kvm_vcpu *vcpu)
>> +{
>> + return vcpu->arch.vsesr_el2;
>> +}
>> +
>> static inline void vcpu_set_vsesr(struct kvm_vcpu *vcpu, u64 vsesr)
>> {
>> vcpu->arch.vsesr_el2 = vsesr;
>> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
>> index 469de8a..357304a 100644
>> --- a/arch/arm64/include/asm/kvm_host.h
>> +++ b/arch/arm64/include/asm/kvm_host.h
>> @@ -335,6 +335,11 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu);
>> int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);
>> int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
>> int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
>> +int kvm_arm_vcpu_get_events(struct kvm_vcpu *vcpu,
>> + struct kvm_vcpu_events *events);
>> +
>> +int kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu,
>> + struct kvm_vcpu_events *events);
>>
>> #define KVM_ARCH_WANT_MMU_NOTIFIER
>> int kvm_unmap_hva(struct kvm *kvm, unsigned long hva);
>> @@ -363,6 +368,8 @@ void handle_exit_early(struct kvm_vcpu *vcpu, struct kvm_run *run,
>> int kvm_perf_init(void);
>> int kvm_perf_teardown(void);
>>
>> +void kvm_set_sei_esr(struct kvm_vcpu *vcpu, u64 syndrome);
>> +
>> struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr);
>>
>> void __kvm_set_tpidr_el2(u64 tpidr_el2);
>> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
>> index 04b3256..df4faee 100644
>> --- a/arch/arm64/include/uapi/asm/kvm.h
>> +++ b/arch/arm64/include/uapi/asm/kvm.h
>> @@ -39,6 +39,7 @@
>> #define __KVM_HAVE_GUEST_DEBUG
>> #define __KVM_HAVE_IRQ_LINE
>> #define __KVM_HAVE_READONLY_MEM
>> +#define __KVM_HAVE_VCPU_EVENTS
>>
>> #define KVM_COALESCED_MMIO_PAGE_OFFSET 1
>>
>> @@ -153,6 +154,18 @@ struct kvm_sync_regs {
>> struct kvm_arch_memory_slot {
>> };
>>
>> +/* for KVM_GET/SET_VCPU_EVENTS */
>> +struct kvm_vcpu_events {
>> + struct {
>> + __u8 serror_pending;
>> + __u8 serror_has_esr;
>> + /* Align it to 8 bytes */
>> + __u8 pad[6];
>> + __u64 serror_esr;
>> + } exception;
>> + __u32 reserved[12];
>> +};
>> +
>> /* If you need to interpret the index values, here is the key: */
>> #define KVM_REG_ARM_COPROC_MASK 0x000000000FFF0000
>> #define KVM_REG_ARM_COPROC_SHIFT 16
>> diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
>> index 56a0260..4426915 100644
>> --- a/arch/arm64/kvm/guest.c
>> +++ b/arch/arm64/kvm/guest.c
>> @@ -289,6 +289,42 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
>> return -EINVAL;
>> }
>>
>> +int kvm_arm_vcpu_get_events(struct kvm_vcpu *vcpu,
>> + struct kvm_vcpu_events *events)
>> +{
>> + memset(events, 0, sizeof(*events));
>> +
>> + events->exception.serror_pending = !!(vcpu->arch.hcr_el2 & HCR_VSE);
>> + events->exception.serror_has_esr =
>> + cpus_have_const_cap(ARM64_HAS_RAS_EXTN);
>> +
>> + if (events->exception.serror_pending &&
>> + events->exception.serror_has_esr)
>> + events->exception.serror_esr = vcpu_get_vsesr(vcpu);
>> + else
>> + events->exception.serror_esr = 0;
>
> Other than the alignment issues that Christoffer already commented on,
> you can perfectly remove the "else" clause altogether (we've just
> zeroed the whole structure).
yes, you are right. it should be moved, thanks for the pointing out.
>
>> +
>> + return 0;
>> +}
>> +
>> +int kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu,
>> + struct kvm_vcpu_events *events)
>> +{
>> + bool serror_pending = events->exception.serror_pending;
>> + bool has_esr = events->exception.serror_has_esr;
>> +
>> + if (serror_pending && has_esr) {
>> + if (!cpus_have_const_cap(ARM64_HAS_RAS_EXTN))
>> + return -EINVAL;
>> +
>> + kvm_set_sei_esr(vcpu, events->exception.serror_esr);
>> + } else if (serror_pending) {
>> + kvm_inject_vabt(vcpu);
>> + }
>> +
>> + return 0;
>
> There was an earlier request to check that all the padding is set to
> zero. I still think this makes sense.
previously I think it may be not needed to check that all the padding is set to
zero. so not added it. but now I consider it again, it should be make sense to check that.
so I will added them. thanks for the mention again.
>
> Thanks,
>
> M.
>
^ permalink raw reply
* [PATCH 00/19] mmc: mmci: add stm32 sdmmc variant
From: Ludovic Barre @ 2018-06-12 13:14 UTC (permalink / raw)
To: linux-arm-kernel
From: Ludovic Barre <ludovic.barre@st.com>
This patch series adapts mmci driver to add support for stm32
sdmmc variant. stm32h7 SoC integrates the first revision of
stm32 sdmmc.
This series is composed of 3 parts:
-Prepare mmci driver to manage dma interfaces by adding property.
New mmci dma API is defined according to the legacy needs.
-Adapt mmci driver to dedicated constraints of stm32 sdmmc variant,
defined under some specific properties.
-Add stm32 sdmmc variant. As Internal DMA way satisfies data
transfer, the mmci driver hasn't been modified for pio_read/write.
Specific adds-ons to stm32 sdmmc:
+ registers
+ clk/power functions
+ idma interface
Ludovic Barre (19):
mmc: mmci: regroup and define dma operations
mmc: mmci: merge qcom dml feature into mmci dma
mmc: mmci: add datactrl block size variant property
mmc: mmci: expand startbiterr to irqmask and error check
mmc: mmci: allow to overwrite clock/power procedure to specific
variant
mmc: mmci: add variant properties to define cpsm & cmdresp bits
mmc: mmci: add variant property to define dpsm bit
mmc: mmci: add variant property to define irq pio mask
mmc: mmci: add variant property to write datactrl before command
mmc: mmci: add variant property to allow remain data
mmc: mmci: add variant property to check specific data constraint
mmc: mmci: add variant property to request a reset
mmc: mmci: send stop cmd if a data command fail
mmc: mmci: add clock divider for stm32 sdmmc
mmc: mmci: add stm32 sdmmc registers
mmc: mmci: add DT bindings for STM32 sdmmc
mmc: mmci: add stm32 sdmmc idma support
mmc: mmci: add specific clk/pwr procedure for stm32 sdmmc
mmc: mmci: add stm32 sdmmc variant
Documentation/devicetree/bindings/mmc/mmci.txt | 11 +
drivers/mmc/host/Makefile | 3 +-
drivers/mmc/host/mmci.c | 846 +++++++++++--------------
drivers/mmc/host/mmci.h | 237 ++++++-
drivers/mmc/host/mmci_dma.c | 780 +++++++++++++++++++++++
drivers/mmc/host/mmci_dma.h | 33 +
drivers/mmc/host/mmci_qcom_dml.c | 177 ------
drivers/mmc/host/mmci_qcom_dml.h | 31 -
8 files changed, 1410 insertions(+), 708 deletions(-)
create mode 100644 drivers/mmc/host/mmci_dma.c
create mode 100644 drivers/mmc/host/mmci_dma.h
delete mode 100644 drivers/mmc/host/mmci_qcom_dml.c
delete mode 100644 drivers/mmc/host/mmci_qcom_dml.h
--
2.7.4
^ permalink raw reply
* [PATCH 01/19] mmc: mmci: regroup and define dma operations
From: Ludovic Barre @ 2018-06-12 13:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1528809280-31116-1-git-send-email-ludovic.Barre@st.com>
From: Ludovic Barre <ludovic.barre@st.com>
Prepare mmci driver to manage dma interface by new property.
This patch defines and regroups dma operations for mmci drivers.
mmci_dma_XX prototypes are added to call member of mmci_dma_ops
if not null. Based on legacy need, a mmci dma interface has been
defined with:
-mmci_dma_setup
-mmci_dma_release
-mmci_dma_pre_req
-mmci_dma_start
-mmci_dma_finalize
-mmci_dma_post_req
-mmci_dma_error
-mmci_dma_get_next_data
A dma_priv is added to host structure to contain private dma needs.
Legacy dmaengine functions have been moved with just some adaptation on:
-dma_in_progress moves to dmaengine_priv structure, called in
dmaengine_error and dmaengine_finalize.
-centralized dma_unmap_sg into dmaengine_unmap, called by
dmaengine_error and dmaengine_finalize.
Signed-off-by: Ludovic Barre <ludovic.barre@st.com>
---
drivers/mmc/host/Makefile | 2 +-
drivers/mmc/host/mmci.c | 437 ++----------------------------------------
drivers/mmc/host/mmci.h | 95 ++++++++--
drivers/mmc/host/mmci_dma.c | 450 ++++++++++++++++++++++++++++++++++++++++++++
drivers/mmc/host/mmci_dma.h | 31 +++
5 files changed, 579 insertions(+), 436 deletions(-)
create mode 100644 drivers/mmc/host/mmci_dma.c
create mode 100644 drivers/mmc/host/mmci_dma.h
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 85dc132..daecaa98 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -4,7 +4,7 @@
#
obj-$(CONFIG_MMC_ARMMMCI) += armmmci.o
-armmmci-y := mmci.o
+armmmci-y := mmci.o mmci_dma.o
armmmci-$(CONFIG_MMC_QCOM_DML) += mmci_qcom_dml.o
obj-$(CONFIG_MMC_PXA) += pxamci.o
obj-$(CONFIG_MMC_MXC) += mxcmmc.o
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index f184977..8868be0 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -42,84 +42,13 @@
#include <asm/io.h>
#include "mmci.h"
+#include "mmci_dma.h"
#include "mmci_qcom_dml.h"
#define DRIVER_NAME "mmci-pl18x"
static unsigned int fmax = 515633;
-/**
- * struct variant_data - MMCI variant-specific quirks
- * @clkreg: default value for MCICLOCK register
- * @clkreg_enable: enable value for MMCICLOCK register
- * @clkreg_8bit_bus_enable: enable value for 8 bit bus
- * @clkreg_neg_edge_enable: enable value for inverted data/cmd output
- * @datalength_bits: number of bits in the MMCIDATALENGTH register
- * @fifosize: number of bytes that can be written when MMCI_TXFIFOEMPTY
- * is asserted (likewise for RX)
- * @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY
- * is asserted (likewise for RX)
- * @data_cmd_enable: enable value for data commands.
- * @st_sdio: enable ST specific SDIO logic
- * @st_clkdiv: true if using a ST-specific clock divider algorithm
- * @datactrl_mask_ddrmode: ddr mode mask in datactrl register.
- * @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register
- * @blksz_datactrl4: true if Block size is at b4..b16 position in datactrl
- * register
- * @datactrl_mask_sdio: SDIO enable mask in datactrl register
- * @pwrreg_powerup: power up value for MMCIPOWER register
- * @f_max: maximum clk frequency supported by the controller.
- * @signal_direction: input/out direction of bus signals can be indicated
- * @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock
- * @busy_detect: true if the variant supports busy detection on DAT0.
- * @busy_dpsm_flag: bitmask enabling busy detection in the DPSM
- * @busy_detect_flag: bitmask identifying the bit in the MMCISTATUS register
- * indicating that the card is busy
- * @busy_detect_mask: bitmask identifying the bit in the MMCIMASK0 to mask for
- * getting busy end detection interrupts
- * @pwrreg_nopower: bits in MMCIPOWER don't controls ext. power supply
- * @explicit_mclk_control: enable explicit mclk control in driver.
- * @qcom_fifo: enables qcom specific fifo pio read logic.
- * @qcom_dml: enables qcom specific dma glue for dma transfers.
- * @reversed_irq_handling: handle data irq before cmd irq.
- * @mmcimask1: true if variant have a MMCIMASK1 register.
- * @start_err: bitmask identifying the STARTBITERR bit inside MMCISTATUS
- * register.
- * @opendrain: bitmask identifying the OPENDRAIN bit inside MMCIPOWER register
- */
-struct variant_data {
- unsigned int clkreg;
- unsigned int clkreg_enable;
- unsigned int clkreg_8bit_bus_enable;
- unsigned int clkreg_neg_edge_enable;
- unsigned int datalength_bits;
- unsigned int fifosize;
- unsigned int fifohalfsize;
- unsigned int data_cmd_enable;
- unsigned int datactrl_mask_ddrmode;
- unsigned int datactrl_mask_sdio;
- bool st_sdio;
- bool st_clkdiv;
- bool blksz_datactrl16;
- bool blksz_datactrl4;
- u32 pwrreg_powerup;
- u32 f_max;
- bool signal_direction;
- bool pwrreg_clkgate;
- bool busy_detect;
- u32 busy_dpsm_flag;
- u32 busy_detect_flag;
- u32 busy_detect_mask;
- bool pwrreg_nopower;
- bool explicit_mclk_control;
- bool qcom_fifo;
- bool qcom_dml;
- bool reversed_irq_handling;
- bool mmcimask1;
- u32 start_err;
- u32 opendrain;
-};
-
static struct variant_data variant_arm = {
.fifosize = 16 * 4,
.fifohalfsize = 8 * 4,
@@ -130,6 +59,7 @@ static struct variant_data variant_arm = {
.mmcimask1 = true,
.start_err = MCI_STARTBITERR,
.opendrain = MCI_ROD,
+ .mmci_dma = &dmaengine,
};
static struct variant_data variant_arm_extended_fifo = {
@@ -141,6 +71,7 @@ static struct variant_data variant_arm_extended_fifo = {
.mmcimask1 = true,
.start_err = MCI_STARTBITERR,
.opendrain = MCI_ROD,
+ .mmci_dma = &dmaengine,
};
static struct variant_data variant_arm_extended_fifo_hwfc = {
@@ -153,6 +84,7 @@ static struct variant_data variant_arm_extended_fifo_hwfc = {
.mmcimask1 = true,
.start_err = MCI_STARTBITERR,
.opendrain = MCI_ROD,
+ .mmci_dma = &dmaengine,
};
static struct variant_data variant_u300 = {
@@ -171,6 +103,7 @@ static struct variant_data variant_u300 = {
.mmcimask1 = true,
.start_err = MCI_STARTBITERR,
.opendrain = MCI_OD,
+ .mmci_dma = &dmaengine,
};
static struct variant_data variant_nomadik = {
@@ -190,6 +123,7 @@ static struct variant_data variant_nomadik = {
.mmcimask1 = true,
.start_err = MCI_STARTBITERR,
.opendrain = MCI_OD,
+ .mmci_dma = &dmaengine,
};
static struct variant_data variant_ux500 = {
@@ -215,6 +149,7 @@ static struct variant_data variant_ux500 = {
.mmcimask1 = true,
.start_err = MCI_STARTBITERR,
.opendrain = MCI_OD,
+ .mmci_dma = &dmaengine,
};
static struct variant_data variant_ux500v2 = {
@@ -242,6 +177,7 @@ static struct variant_data variant_ux500v2 = {
.mmcimask1 = true,
.start_err = MCI_STARTBITERR,
.opendrain = MCI_OD,
+ .mmci_dma = &dmaengine,
};
static struct variant_data variant_stm32 = {
@@ -259,6 +195,7 @@ static struct variant_data variant_stm32 = {
.f_max = 48000000,
.pwrreg_clkgate = true,
.pwrreg_nopower = true,
+ .mmci_dma = &dmaengine,
};
static struct variant_data variant_qcom = {
@@ -280,6 +217,7 @@ static struct variant_data variant_qcom = {
.mmcimask1 = true,
.start_err = MCI_STARTBITERR,
.opendrain = MCI_ROD,
+ .mmci_dma = &dmaengine,
};
/* Busy detection for the ST Micro variant */
@@ -355,7 +293,7 @@ static void mmci_write_pwrreg(struct mmci_host *host, u32 pwr)
/*
* This must be called with host->lock held
*/
-static void mmci_write_datactrlreg(struct mmci_host *host, u32 datactrl)
+void mmci_write_datactrlreg(struct mmci_host *host, u32 datactrl)
{
/* Keep busy mode in DPSM if enabled */
datactrl |= host->datactrl_reg & host->variant->busy_dpsm_flag;
@@ -480,281 +418,10 @@ static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data)
sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
}
-/*
- * All the DMA operation mode stuff goes inside this ifdef.
- * This assumes that you have a generic DMA device interface,
- * no custom DMA interfaces are supported.
- */
-#ifdef CONFIG_DMA_ENGINE
-static void mmci_dma_setup(struct mmci_host *host)
-{
- const char *rxname, *txname;
- struct variant_data *variant = host->variant;
-
- host->dma_rx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "rx");
- host->dma_tx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "tx");
-
- /* initialize pre request cookie */
- host->next_data.cookie = 1;
-
- /*
- * If only an RX channel is specified, the driver will
- * attempt to use it bidirectionally, however if it is
- * is specified but cannot be located, DMA will be disabled.
- */
- if (host->dma_rx_channel && !host->dma_tx_channel)
- host->dma_tx_channel = host->dma_rx_channel;
-
- if (host->dma_rx_channel)
- rxname = dma_chan_name(host->dma_rx_channel);
- else
- rxname = "none";
-
- if (host->dma_tx_channel)
- txname = dma_chan_name(host->dma_tx_channel);
- else
- txname = "none";
-
- dev_info(mmc_dev(host->mmc), "DMA channels RX %s, TX %s\n",
- rxname, txname);
-
- /*
- * Limit the maximum segment size in any SG entry according to
- * the parameters of the DMA engine device.
- */
- if (host->dma_tx_channel) {
- struct device *dev = host->dma_tx_channel->device->dev;
- unsigned int max_seg_size = dma_get_max_seg_size(dev);
-
- if (max_seg_size < host->mmc->max_seg_size)
- host->mmc->max_seg_size = max_seg_size;
- }
- if (host->dma_rx_channel) {
- struct device *dev = host->dma_rx_channel->device->dev;
- unsigned int max_seg_size = dma_get_max_seg_size(dev);
-
- if (max_seg_size < host->mmc->max_seg_size)
- host->mmc->max_seg_size = max_seg_size;
- }
-
- if (variant->qcom_dml && host->dma_rx_channel && host->dma_tx_channel)
- if (dml_hw_init(host, host->mmc->parent->of_node))
- variant->qcom_dml = false;
-}
-
-/*
- * This is used in or so inline it
- * so it can be discarded.
- */
-static inline void mmci_dma_release(struct mmci_host *host)
-{
- if (host->dma_rx_channel)
- dma_release_channel(host->dma_rx_channel);
- if (host->dma_tx_channel)
- dma_release_channel(host->dma_tx_channel);
- host->dma_rx_channel = host->dma_tx_channel = NULL;
-}
-
-static void mmci_dma_data_error(struct mmci_host *host)
-{
- dev_err(mmc_dev(host->mmc), "error during DMA transfer!\n");
- dmaengine_terminate_all(host->dma_current);
- host->dma_in_progress = false;
- host->dma_current = NULL;
- host->dma_desc_current = NULL;
- host->data->host_cookie = 0;
-}
-
-static void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data)
-{
- struct dma_chan *chan;
-
- if (data->flags & MMC_DATA_READ)
- chan = host->dma_rx_channel;
- else
- chan = host->dma_tx_channel;
-
- dma_unmap_sg(chan->device->dev, data->sg, data->sg_len,
- mmc_get_dma_dir(data));
-}
-
-static void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data)
-{
- u32 status;
- int i;
-
- /* Wait up to 1ms for the DMA to complete */
- for (i = 0; ; i++) {
- status = readl(host->base + MMCISTATUS);
- if (!(status & MCI_RXDATAAVLBLMASK) || i >= 100)
- break;
- udelay(10);
- }
-
- /*
- * Check to see whether we still have some data left in the FIFO -
- * this catches DMA controllers which are unable to monitor the
- * DMALBREQ and DMALSREQ signals while allowing us to DMA to non-
- * contiguous buffers. On TX, we'll get a FIFO underrun error.
- */
- if (status & MCI_RXDATAAVLBLMASK) {
- mmci_dma_data_error(host);
- if (!data->error)
- data->error = -EIO;
- }
-
- if (!data->host_cookie)
- mmci_dma_unmap(host, data);
-
- /*
- * Use of DMA with scatter-gather is impossible.
- * Give up with DMA and switch back to PIO mode.
- */
- if (status & MCI_RXDATAAVLBLMASK) {
- dev_err(mmc_dev(host->mmc), "buggy DMA detected. Taking evasive action.\n");
- mmci_dma_release(host);
- }
-
- host->dma_in_progress = false;
- host->dma_current = NULL;
- host->dma_desc_current = NULL;
-}
-
-/* prepares DMA channel and DMA descriptor, returns non-zero on failure */
-static int __mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data,
- struct dma_chan **dma_chan,
- struct dma_async_tx_descriptor **dma_desc)
-{
- struct variant_data *variant = host->variant;
- struct dma_slave_config conf = {
- .src_addr = host->phybase + MMCIFIFO,
- .dst_addr = host->phybase + MMCIFIFO,
- .src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
- .dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
- .src_maxburst = variant->fifohalfsize >> 2, /* # of words */
- .dst_maxburst = variant->fifohalfsize >> 2, /* # of words */
- .device_fc = false,
- };
- struct dma_chan *chan;
- struct dma_device *device;
- struct dma_async_tx_descriptor *desc;
- int nr_sg;
- unsigned long flags = DMA_CTRL_ACK;
-
- if (data->flags & MMC_DATA_READ) {
- conf.direction = DMA_DEV_TO_MEM;
- chan = host->dma_rx_channel;
- } else {
- conf.direction = DMA_MEM_TO_DEV;
- chan = host->dma_tx_channel;
- }
-
- /* If there's no DMA channel, fall back to PIO */
- if (!chan)
- return -EINVAL;
-
- /* If less than or equal to the fifo size, don't bother with DMA */
- if (data->blksz * data->blocks <= variant->fifosize)
- return -EINVAL;
-
- device = chan->device;
- nr_sg = dma_map_sg(device->dev, data->sg, data->sg_len,
- mmc_get_dma_dir(data));
- if (nr_sg == 0)
- return -EINVAL;
-
- if (host->variant->qcom_dml)
- flags |= DMA_PREP_INTERRUPT;
-
- dmaengine_slave_config(chan, &conf);
- desc = dmaengine_prep_slave_sg(chan, data->sg, nr_sg,
- conf.direction, flags);
- if (!desc)
- goto unmap_exit;
-
- *dma_chan = chan;
- *dma_desc = desc;
-
- return 0;
-
- unmap_exit:
- dma_unmap_sg(device->dev, data->sg, data->sg_len,
- mmc_get_dma_dir(data));
- return -ENOMEM;
-}
-
-static inline int mmci_dma_prep_data(struct mmci_host *host,
- struct mmc_data *data)
-{
- /* Check if next job is already prepared. */
- if (host->dma_current && host->dma_desc_current)
- return 0;
-
- /* No job were prepared thus do it now. */
- return __mmci_dma_prep_data(host, data, &host->dma_current,
- &host->dma_desc_current);
-}
-
-static inline int mmci_dma_prep_next(struct mmci_host *host,
- struct mmc_data *data)
-{
- struct mmci_host_next *nd = &host->next_data;
- return __mmci_dma_prep_data(host, data, &nd->dma_chan, &nd->dma_desc);
-}
-
-static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl)
-{
- int ret;
- struct mmc_data *data = host->data;
-
- ret = mmci_dma_prep_data(host, host->data);
- if (ret)
- return ret;
-
- /* Okay, go for it. */
- dev_vdbg(mmc_dev(host->mmc),
- "Submit MMCI DMA job, sglen %d blksz %04x blks %04x flags %08x\n",
- data->sg_len, data->blksz, data->blocks, data->flags);
- host->dma_in_progress = true;
- dmaengine_submit(host->dma_desc_current);
- dma_async_issue_pending(host->dma_current);
-
- if (host->variant->qcom_dml)
- dml_start_xfer(host, data);
-
- datactrl |= MCI_DPSM_DMAENABLE;
-
- /* Trigger the DMA transfer */
- mmci_write_datactrlreg(host, datactrl);
-
- /*
- * Let the MMCI say when the data is ended and it's time
- * to fire next DMA request. When that happens, MMCI will
- * call mmci_data_end()
- */
- writel(readl(host->base + MMCIMASK0) | MCI_DATAENDMASK,
- host->base + MMCIMASK0);
- return 0;
-}
-
-static void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data)
-{
- struct mmci_host_next *next = &host->next_data;
-
- WARN_ON(data->host_cookie && data->host_cookie != next->cookie);
- WARN_ON(!data->host_cookie && (next->dma_desc || next->dma_chan));
-
- host->dma_desc_current = next->dma_desc;
- host->dma_current = next->dma_chan;
- next->dma_desc = NULL;
- next->dma_chan = NULL;
-}
-
static void mmci_pre_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct mmci_host *host = mmc_priv(mmc);
struct mmc_data *data = mrq->data;
- struct mmci_host_next *nd = &host->next_data;
if (!data)
return;
@@ -764,8 +431,7 @@ static void mmci_pre_request(struct mmc_host *mmc, struct mmc_request *mrq)
if (mmci_validate_data(host, data))
return;
- if (!mmci_dma_prep_next(host, data))
- data->host_cookie = ++nd->cookie < 0 ? 1 : nd->cookie;
+ mmci_dma_pre_req(host, data);
}
static void mmci_post_request(struct mmc_host *mmc, struct mmc_request *mrq,
@@ -777,67 +443,9 @@ static void mmci_post_request(struct mmc_host *mmc, struct mmc_request *mrq,
if (!data || !data->host_cookie)
return;
- mmci_dma_unmap(host, data);
-
- if (err) {
- struct mmci_host_next *next = &host->next_data;
- struct dma_chan *chan;
- if (data->flags & MMC_DATA_READ)
- chan = host->dma_rx_channel;
- else
- chan = host->dma_tx_channel;
- dmaengine_terminate_all(chan);
-
- if (host->dma_desc_current == next->dma_desc)
- host->dma_desc_current = NULL;
-
- if (host->dma_current == next->dma_chan) {
- host->dma_in_progress = false;
- host->dma_current = NULL;
- }
-
- next->dma_desc = NULL;
- next->dma_chan = NULL;
- data->host_cookie = 0;
- }
-}
-
-#else
-/* Blank functions if the DMA engine is not available */
-static void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data)
-{
-}
-static inline void mmci_dma_setup(struct mmci_host *host)
-{
-}
-
-static inline void mmci_dma_release(struct mmci_host *host)
-{
-}
-
-static inline void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data)
-{
-}
-
-static inline void mmci_dma_finalize(struct mmci_host *host,
- struct mmc_data *data)
-{
-}
-
-static inline void mmci_dma_data_error(struct mmci_host *host)
-{
-}
-
-static inline int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl)
-{
- return -ENOSYS;
+ mmci_dma_post_req(host, data, err);
}
-#define mmci_pre_request NULL
-#define mmci_post_request NULL
-
-#endif
-
static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
{
struct variant_data *variant = host->variant;
@@ -904,7 +512,7 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
* Attempt to use DMA operation mode, if this
* should fail, fall back to PIO mode
*/
- if (!mmci_dma_start_data(host, datactrl))
+ if (!mmci_dma_start(host, datactrl))
return;
/* IRQ mode, map the SG list for CPU reading/writing */
@@ -979,10 +587,7 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
u32 remain, success;
/* Terminate the DMA transfer */
- if (dma_inprogress(host)) {
- mmci_dma_data_error(host);
- mmci_dma_unmap(host, data);
- }
+ mmci_dma_error(host);
/*
* Calculate how far we are into the transfer. Note that
@@ -1020,8 +625,8 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
dev_err(mmc_dev(host->mmc), "stray MCI_DATABLOCKEND interrupt\n");
if (status & MCI_DATAEND || data->error) {
- if (dma_inprogress(host))
- mmci_dma_finalize(host, data);
+ mmci_dma_finalize(host, data);
+
mmci_stop_data(host);
if (!data->error)
@@ -1128,10 +733,8 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
if ((!sbc && !cmd->data) || cmd->error) {
if (host->data) {
/* Terminate the DMA transfer */
- if (dma_inprogress(host)) {
- mmci_dma_data_error(host);
- mmci_dma_unmap(host, host->data);
- }
+ mmci_dma_error(host);
+
mmci_stop_data(host);
}
mmci_request_end(host, host->mrq);
@@ -1399,7 +1002,7 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
host->mrq = mrq;
if (mrq->data)
- mmci_get_next_data(host, mrq->data);
+ mmci_dma_get_next_data(host, mrq->data);
if (mrq->data && mrq->data->flags & MMC_DATA_READ)
mmci_start_data(host, mrq->data);
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index f91cdf7..a73bb98 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -195,13 +195,81 @@
#define MMCI_PINCTRL_STATE_OPENDRAIN "opendrain"
struct clk;
-struct variant_data;
struct dma_chan;
-struct mmci_host_next {
- struct dma_async_tx_descriptor *dma_desc;
- struct dma_chan *dma_chan;
- s32 cookie;
+/**
+ * struct variant_data - MMCI variant-specific quirks
+ * @clkreg: default value for MCICLOCK register
+ * @clkreg_enable: enable value for MMCICLOCK register
+ * @clkreg_8bit_bus_enable: enable value for 8 bit bus
+ * @clkreg_neg_edge_enable: enable value for inverted data/cmd output
+ * @datalength_bits: number of bits in the MMCIDATALENGTH register
+ * @fifosize: number of bytes that can be written when MMCI_TXFIFOEMPTY
+ * is asserted (likewise for RX)
+ * @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY
+ * is asserted (likewise for RX)
+ * @data_cmd_enable: enable value for data commands.
+ * @st_sdio: enable ST specific SDIO logic
+ * @st_clkdiv: true if using a ST-specific clock divider algorithm
+ * @datactrl_mask_ddrmode: ddr mode mask in datactrl register.
+ * @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl
+ * register
+ * @blksz_datactrl4: true if Block size is at b4..b16 position in datactrl
+ * register
+ * @datactrl_mask_sdio: SDIO enable mask in datactrl register
+ * @pwrreg_powerup: power up value for MMCIPOWER register
+ * @f_max: maximum clk frequency supported by the controller.
+ * @signal_direction: input/out direction of bus signals can be indicated
+ * @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock
+ * @busy_detect: true if the variant supports busy detection on DAT0.
+ * @busy_dpsm_flag: bitmask enabling busy detection in the DPSM
+ * @busy_detect_flag: bitmask identifying the bit in the MMCISTATUS register
+ * indicating that the card is busy
+ * @busy_detect_mask: bitmask identifying the bit in the MMCIMASK0 to mask for
+ * getting busy end detection interrupts
+ * @pwrreg_nopower: bits in MMCIPOWER don't controls ext. power supply
+ * @explicit_mclk_control: enable explicit mclk control in driver.
+ * @qcom_fifo: enables qcom specific fifo pio read logic.
+ * @qcom_dml: enables qcom specific dma glue for dma transfers.
+ * @reversed_irq_handling: handle data irq before cmd irq.
+ * @mmcimask1: true if variant have a MMCIMASK1 register.
+ * @start_err: bitmask identifying the STARTBITERR bit inside MMCISTATUS
+ * register.
+ * @opendrain: bitmask identifying the OPENDRAIN bit inside MMCIPOWER register
+ * @mmci_dma: Pointer to platform-specific DMA callbacks.
+ */
+struct variant_data {
+ unsigned int clkreg;
+ unsigned int clkreg_enable;
+ unsigned int clkreg_8bit_bus_enable;
+ unsigned int clkreg_neg_edge_enable;
+ unsigned int datalength_bits;
+ unsigned int fifosize;
+ unsigned int fifohalfsize;
+ unsigned int data_cmd_enable;
+ unsigned int datactrl_mask_ddrmode;
+ unsigned int datactrl_mask_sdio;
+ bool st_sdio;
+ bool st_clkdiv;
+ bool blksz_datactrl16;
+ bool blksz_datactrl4;
+ u32 pwrreg_powerup;
+ u32 f_max;
+ bool signal_direction;
+ bool pwrreg_clkgate;
+ bool busy_detect;
+ u32 busy_dpsm_flag;
+ u32 busy_detect_flag;
+ u32 busy_detect_mask;
+ bool pwrreg_nopower;
+ bool explicit_mclk_control;
+ bool qcom_fifo;
+ bool qcom_dml;
+ bool reversed_irq_handling;
+ bool mmcimask1;
+ u32 start_err;
+ u32 opendrain;
+ struct mmci_dma_ops *mmci_dma;
};
struct mmci_host {
@@ -244,18 +312,9 @@ struct mmci_host {
unsigned int size;
int (*get_rx_fifocnt)(struct mmci_host *h, u32 status, int remain);
-#ifdef CONFIG_DMA_ENGINE
- /* DMA stuff */
- struct dma_chan *dma_current;
- struct dma_chan *dma_rx_channel;
- struct dma_chan *dma_tx_channel;
- struct dma_async_tx_descriptor *dma_desc_current;
- struct mmci_host_next next_data;
- bool dma_in_progress;
-
-#define dma_inprogress(host) ((host)->dma_in_progress)
-#else
-#define dma_inprogress(host) (0)
-#endif
+ void *dma_priv;
};
+extern struct mmci_dma_ops dmaengine;
+
+void mmci_write_datactrlreg(struct mmci_host *host, u32 datactrl);
diff --git a/drivers/mmc/host/mmci_dma.c b/drivers/mmc/host/mmci_dma.c
new file mode 100644
index 0000000..98a542d
--- /dev/null
+++ b/drivers/mmc/host/mmci_dma.c
@@ -0,0 +1,450 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Author: Ludovic.barre at st.com for STMicroelectronics.
+ */
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/scatterlist.h>
+
+#include "mmci.h"
+#include "mmci_dma.h"
+#include "mmci_qcom_dml.h"
+
+int mmci_dma_setup(struct mmci_host *host)
+{
+ struct mmci_dma_ops *mmci_dma = host->variant->mmci_dma;
+
+ if (mmci_dma && mmci_dma->setup)
+ return mmci_dma->setup(host);
+
+ return 0;
+}
+
+void mmci_dma_release(struct mmci_host *host)
+{
+ struct mmci_dma_ops *mmci_dma = host->variant->mmci_dma;
+
+ if (mmci_dma && mmci_dma->release)
+ mmci_dma->release(host);
+}
+
+void mmci_dma_pre_req(struct mmci_host *host, struct mmc_data *data)
+{
+ struct mmci_dma_ops *mmci_dma = host->variant->mmci_dma;
+
+ if (mmci_dma && mmci_dma->pre_req)
+ mmci_dma->pre_req(host, data);
+}
+
+int mmci_dma_start(struct mmci_host *host, unsigned int datactrl)
+{
+ struct mmci_dma_ops *mmci_dma = host->variant->mmci_dma;
+
+ if (mmci_dma && mmci_dma->start)
+ return mmci_dma->start(host, datactrl);
+
+ return -EINVAL;
+}
+
+void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data)
+{
+ struct mmci_dma_ops *mmci_dma = host->variant->mmci_dma;
+
+ if (mmci_dma && mmci_dma->finalize)
+ mmci_dma->finalize(host, data);
+}
+
+void mmci_dma_post_req(struct mmci_host *host,
+ struct mmc_data *data, int err)
+{
+ struct mmci_dma_ops *mmci_dma = host->variant->mmci_dma;
+
+ if (mmci_dma && mmci_dma->post_req)
+ mmci_dma->post_req(host, data, err);
+}
+
+void mmci_dma_error(struct mmci_host *host)
+{
+ struct mmci_dma_ops *mmci_dma = host->variant->mmci_dma;
+
+ if (mmci_dma && mmci_dma->error)
+ mmci_dma->error(host);
+}
+
+void mmci_dma_get_next_data(struct mmci_host *host, struct mmc_data *data)
+{
+ struct mmci_dma_ops *mmci_dma = host->variant->mmci_dma;
+
+ if (mmci_dma && mmci_dma->get_next_data)
+ mmci_dma->get_next_data(host, data);
+}
+
+#ifdef CONFIG_DMA_ENGINE
+struct dmaengine_next {
+ struct dma_async_tx_descriptor *dma_desc;
+ struct dma_chan *dma_chan;
+ s32 cookie;
+};
+
+struct dmaengine_priv {
+ struct dma_chan *dma_current;
+ struct dma_chan *dma_rx_channel;
+ struct dma_chan *dma_tx_channel;
+ struct dma_async_tx_descriptor *dma_desc_current;
+ struct dmaengine_next next_data;
+ bool dma_in_progress;
+};
+
+#define dma_inprogress(dmae) ((dmae)->dma_in_progress)
+
+static int dmaengine_setup(struct mmci_host *host)
+{
+ const char *rxname, *txname;
+ struct variant_data *variant = host->variant;
+ struct dmaengine_priv *dmae;
+
+ dmae = devm_kzalloc(mmc_dev(host->mmc), sizeof(*dmae), GFP_KERNEL);
+ if (!dmae)
+ return -ENOMEM;
+
+ host->dma_priv = dmae;
+
+ dmae->dma_rx_channel = dma_request_slave_channel(mmc_dev(host->mmc),
+ "rx");
+ dmae->dma_tx_channel = dma_request_slave_channel(mmc_dev(host->mmc),
+ "tx");
+
+ /* initialize pre request cookie */
+ dmae->next_data.cookie = 1;
+
+ /*
+ * If only an RX channel is specified, the driver will
+ * attempt to use it bidirectionally, however if it is
+ * is specified but cannot be located, DMA will be disabled.
+ */
+ if (dmae->dma_rx_channel && !dmae->dma_tx_channel)
+ dmae->dma_tx_channel = dmae->dma_rx_channel;
+
+ if (dmae->dma_rx_channel)
+ rxname = dma_chan_name(dmae->dma_rx_channel);
+ else
+ rxname = "none";
+
+ if (dmae->dma_tx_channel)
+ txname = dma_chan_name(dmae->dma_tx_channel);
+ else
+ txname = "none";
+
+ dev_info(mmc_dev(host->mmc), "DMA channels RX %s, TX %s\n",
+ rxname, txname);
+
+ /*
+ * Limit the maximum segment size in any SG entry according to
+ * the parameters of the DMA engine device.
+ */
+ if (dmae->dma_tx_channel) {
+ struct device *dev = dmae->dma_tx_channel->device->dev;
+ unsigned int max_seg_size = dma_get_max_seg_size(dev);
+
+ if (max_seg_size < host->mmc->max_seg_size)
+ host->mmc->max_seg_size = max_seg_size;
+ }
+ if (dmae->dma_rx_channel) {
+ struct device *dev = dmae->dma_rx_channel->device->dev;
+ unsigned int max_seg_size = dma_get_max_seg_size(dev);
+
+ if (max_seg_size < host->mmc->max_seg_size)
+ host->mmc->max_seg_size = max_seg_size;
+ }
+
+ if (variant->qcom_dml && dmae->dma_rx_channel && dmae->dma_tx_channel)
+ if (dml_hw_init(host, host->mmc->parent->of_node))
+ variant->qcom_dml = false;
+
+ return 0;
+}
+
+static inline void dmaengine_release(struct mmci_host *host)
+{
+ struct dmaengine_priv *dmae = host->dma_priv;
+
+ if (dmae->dma_rx_channel)
+ dma_release_channel(dmae->dma_rx_channel);
+ if (dmae->dma_tx_channel)
+ dma_release_channel(dmae->dma_tx_channel);
+
+ dmae->dma_rx_channel = dmae->dma_tx_channel = NULL;
+}
+
+static void dmaengine_unmap(struct mmci_host *host, struct mmc_data *data)
+{
+ struct dmaengine_priv *dmae = host->dma_priv;
+ struct dma_chan *chan;
+
+ if (data->flags & MMC_DATA_READ)
+ chan = dmae->dma_rx_channel;
+ else
+ chan = dmae->dma_tx_channel;
+
+ dma_unmap_sg(chan->device->dev, data->sg, data->sg_len,
+ mmc_get_dma_dir(data));
+}
+
+static void dmaengine_error(struct mmci_host *host)
+{
+ struct dmaengine_priv *dmae = host->dma_priv;
+
+ if (!dma_inprogress(dmae))
+ return;
+
+ dev_err(mmc_dev(host->mmc), "error during DMA transfer!\n");
+ dmaengine_terminate_all(dmae->dma_current);
+ dmae->dma_in_progress = false;
+ dmae->dma_current = NULL;
+ dmae->dma_desc_current = NULL;
+ host->data->host_cookie = 0;
+
+ dmaengine_unmap(host, host->data);
+}
+
+static void dmaengine_finalize(struct mmci_host *host, struct mmc_data *data)
+{
+ struct dmaengine_priv *dmae = host->dma_priv;
+ u32 status;
+ int i;
+
+ if (!dma_inprogress(dmae))
+ return;
+
+ /* Wait up to 1ms for the DMA to complete */
+ for (i = 0; ; i++) {
+ status = readl(host->base + MMCISTATUS);
+ if (!(status & MCI_RXDATAAVLBLMASK) || i >= 100)
+ break;
+ udelay(10);
+ }
+
+ /*
+ * Check to see whether we still have some data left in the FIFO -
+ * this catches DMA controllers which are unable to monitor the
+ * DMALBREQ and DMALSREQ signals while allowing us to DMA to non-
+ * contiguous buffers. On TX, we'll get a FIFO underrun error.
+ */
+ if (status & MCI_RXDATAAVLBLMASK) {
+ dmaengine_error(host);
+ if (!data->error)
+ data->error = -EIO;
+ }
+
+ if (!data->host_cookie)
+ dmaengine_unmap(host, data);
+
+ /*
+ * Use of DMA with scatter-gather is impossible.
+ * Give up with DMA and switch back to PIO mode.
+ */
+ if (status & MCI_RXDATAAVLBLMASK) {
+ dev_err(mmc_dev(host->mmc),
+ "buggy DMA detected. Taking evasive action.\n");
+ dmaengine_release(host);
+ }
+
+ dmae->dma_in_progress = false;
+ dmae->dma_current = NULL;
+ dmae->dma_desc_current = NULL;
+}
+
+/* prepares DMA channel and DMA descriptor, returns non-zero on failure */
+static int __dmaengine_prep_data(struct mmci_host *host, struct mmc_data *data,
+ struct dma_chan **dma_chan,
+ struct dma_async_tx_descriptor **dma_desc)
+{
+ struct dmaengine_priv *dmae = host->dma_priv;
+ struct variant_data *variant = host->variant;
+ struct dma_slave_config conf = {
+ .src_addr = host->phybase + MMCIFIFO,
+ .dst_addr = host->phybase + MMCIFIFO,
+ .src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
+ .dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
+ .src_maxburst = variant->fifohalfsize >> 2, /* # of words */
+ .dst_maxburst = variant->fifohalfsize >> 2, /* # of words */
+ .device_fc = false,
+ };
+ struct dma_chan *chan;
+ struct dma_device *device;
+ struct dma_async_tx_descriptor *desc;
+ int nr_sg;
+ unsigned long flags = DMA_CTRL_ACK;
+
+ if (data->flags & MMC_DATA_READ) {
+ conf.direction = DMA_DEV_TO_MEM;
+ chan = dmae->dma_rx_channel;
+ } else {
+ conf.direction = DMA_MEM_TO_DEV;
+ chan = dmae->dma_tx_channel;
+ }
+
+ /* If there's no DMA channel, fall back to PIO */
+ if (!chan)
+ return -EINVAL;
+
+ /* If less than or equal to the fifo size, don't bother with DMA */
+ if (data->blksz * data->blocks <= variant->fifosize)
+ return -EINVAL;
+
+ device = chan->device;
+ nr_sg = dma_map_sg(device->dev, data->sg, data->sg_len,
+ mmc_get_dma_dir(data));
+ if (nr_sg == 0)
+ return -EINVAL;
+
+ if (host->variant->qcom_dml)
+ flags |= DMA_PREP_INTERRUPT;
+
+ dmaengine_slave_config(chan, &conf);
+ desc = dmaengine_prep_slave_sg(chan, data->sg, nr_sg,
+ conf.direction, flags);
+ if (!desc)
+ goto unmap_exit;
+
+ *dma_chan = chan;
+ *dma_desc = desc;
+
+ return 0;
+
+ unmap_exit:
+ dmaengine_unmap(host, data);
+ return -ENOMEM;
+}
+
+static inline int dmaengine_prep_data(struct mmci_host *host,
+ struct mmc_data *data)
+{
+ struct dmaengine_priv *dmae = host->dma_priv;
+
+ /* Check if next job is already prepared. */
+ if (dmae->dma_current && dmae->dma_desc_current)
+ return 0;
+
+ /* No job were prepared thus do it now. */
+ return __dmaengine_prep_data(host, data, &dmae->dma_current,
+ &dmae->dma_desc_current);
+}
+
+static inline int dmaengine_prep_next(struct mmci_host *host,
+ struct mmc_data *data)
+{
+ struct dmaengine_priv *dmae = host->dma_priv;
+ struct dmaengine_next *nd = &dmae->next_data;
+
+ return __dmaengine_prep_data(host, data, &nd->dma_chan, &nd->dma_desc);
+}
+
+static int dmaengine_start(struct mmci_host *host, unsigned int datactrl)
+{
+ struct dmaengine_priv *dmae = host->dma_priv;
+ struct mmc_data *data = host->data;
+ int ret;
+
+ ret = dmaengine_prep_data(host, host->data);
+ if (ret)
+ return ret;
+
+ /* Okay, go for it. */
+ dev_vdbg(mmc_dev(host->mmc),
+ "Submit MMCI DMA job, sglen %d blksz %04x blks %04x flags %08x\n",
+ data->sg_len, data->blksz, data->blocks, data->flags);
+ dmae->dma_in_progress = true;
+ dmaengine_submit(dmae->dma_desc_current);
+ dma_async_issue_pending(dmae->dma_current);
+
+ if (host->variant->qcom_dml)
+ dml_start_xfer(host, data);
+
+ datactrl |= MCI_DPSM_DMAENABLE;
+
+ /* Trigger the DMA transfer */
+ mmci_write_datactrlreg(host, datactrl);
+
+ /*
+ * Let the MMCI say when the data is ended and it's time
+ * to fire next DMA request. When that happens, MMCI will
+ * call mmci_data_end()
+ */
+ writel(readl(host->base + MMCIMASK0) | MCI_DATAENDMASK,
+ host->base + MMCIMASK0);
+ return 0;
+}
+
+static void dmaengine_get_next_data(struct mmci_host *host,
+ struct mmc_data *data)
+{
+ struct dmaengine_priv *dmae = host->dma_priv;
+ struct dmaengine_next *next = &dmae->next_data;
+
+ WARN_ON(data->host_cookie && data->host_cookie != next->cookie);
+ WARN_ON(!data->host_cookie && (next->dma_desc || next->dma_chan));
+
+ dmae->dma_desc_current = next->dma_desc;
+ dmae->dma_current = next->dma_chan;
+ next->dma_desc = NULL;
+ next->dma_chan = NULL;
+}
+
+static void dmaengine_pre_req(struct mmci_host *host, struct mmc_data *data)
+{
+ struct dmaengine_priv *dmae = host->dma_priv;
+ struct dmaengine_next *nd = &dmae->next_data;
+
+ if (!dmaengine_prep_next(host, data))
+ data->host_cookie = ++nd->cookie < 0 ? 1 : nd->cookie;
+}
+
+static void dmaengine_post_req(struct mmci_host *host,
+ struct mmc_data *data, int err)
+{
+ struct dmaengine_priv *dmae = host->dma_priv;
+
+ dmaengine_unmap(host, data);
+
+ if (err) {
+ struct dmaengine_next *next = &dmae->next_data;
+ struct dma_chan *chan;
+
+ if (data->flags & MMC_DATA_READ)
+ chan = dmae->dma_rx_channel;
+ else
+ chan = dmae->dma_tx_channel;
+ dmaengine_terminate_all(chan);
+
+ if (dmae->dma_desc_current == next->dma_desc)
+ dmae->dma_desc_current = NULL;
+
+ if (dmae->dma_current == next->dma_chan) {
+ dmae->dma_in_progress = false;
+ dmae->dma_current = NULL;
+ }
+
+ next->dma_desc = NULL;
+ next->dma_chan = NULL;
+ data->host_cookie = 0;
+ }
+}
+
+struct mmci_dma_ops dmaengine = {
+ .setup = dmaengine_setup,
+ .release = dmaengine_release,
+ .pre_req = dmaengine_pre_req,
+ .start = dmaengine_start,
+ .finalize = dmaengine_finalize,
+ .post_req = dmaengine_post_req,
+ .error = dmaengine_error,
+ .get_next_data = dmaengine_get_next_data,
+};
+#else
+struct mmci_dma_ops dmaengine = {};
+#endif
diff --git a/drivers/mmc/host/mmci_dma.h b/drivers/mmc/host/mmci_dma.h
new file mode 100644
index 0000000..33e4e8a
--- /dev/null
+++ b/drivers/mmc/host/mmci_dma.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Author: Ludovic.barre at st.com for STMicroelectronics.
+ */
+#ifndef __MMC_DMA_H__
+#define __MMC_DMA_H__
+
+struct mmci_dma_ops {
+ int (*setup)(struct mmci_host *host);
+ void (*release)(struct mmci_host *host);
+ void (*pre_req)(struct mmci_host *host, struct mmc_data *data);
+ int (*start)(struct mmci_host *host, unsigned int datactrl);
+ void (*finalize)(struct mmci_host *host, struct mmc_data *data);
+ void (*post_req)(struct mmci_host *host,
+ struct mmc_data *data, int err);
+ void (*error)(struct mmci_host *host);
+ void (*get_next_data)(struct mmci_host *host, struct mmc_data *data);
+};
+
+int mmci_dma_setup(struct mmci_host *host);
+int mmci_dma_start(struct mmci_host *host, unsigned int datactrl);
+void mmci_dma_release(struct mmci_host *host);
+void mmci_dma_pre_req(struct mmci_host *host, struct mmc_data *data);
+void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data);
+void mmci_dma_post_req(struct mmci_host *host,
+ struct mmc_data *data, int err);
+void mmci_dma_error(struct mmci_host *host);
+void mmci_dma_get_next_data(struct mmci_host *host, struct mmc_data *data);
+
+#endif /* __MMC_DMA_H__ */
--
2.7.4
^ permalink raw reply related
* [PATCH 02/19] mmc: mmci: merge qcom dml feature into mmci dma
From: Ludovic Barre @ 2018-06-12 13:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1528809280-31116-1-git-send-email-ludovic.Barre@st.com>
From: Ludovic Barre <ludovic.barre@st.com>
This patch integrates qcom dml feature into mmci_dma file.
Qualcomm Data Mover lite/local is already a variant of mmci dmaengine.
Signed-off-by: Ludovic Barre <ludovic.barre@st.com>
---
drivers/mmc/host/Makefile | 1 -
drivers/mmc/host/mmci.c | 1 -
drivers/mmc/host/mmci.h | 35 ++++++++
drivers/mmc/host/mmci_dma.c | 135 ++++++++++++++++++++++++++++-
drivers/mmc/host/mmci_qcom_dml.c | 177 ---------------------------------------
drivers/mmc/host/mmci_qcom_dml.h | 31 -------
6 files changed, 169 insertions(+), 211 deletions(-)
delete mode 100644 drivers/mmc/host/mmci_qcom_dml.c
delete mode 100644 drivers/mmc/host/mmci_qcom_dml.h
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index daecaa98..608a020 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -5,7 +5,6 @@
obj-$(CONFIG_MMC_ARMMMCI) += armmmci.o
armmmci-y := mmci.o mmci_dma.o
-armmmci-$(CONFIG_MMC_QCOM_DML) += mmci_qcom_dml.o
obj-$(CONFIG_MMC_PXA) += pxamci.o
obj-$(CONFIG_MMC_MXC) += mxcmmc.o
obj-$(CONFIG_MMC_MXS) += mxs-mmc.o
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 8868be0..7a15afd 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -43,7 +43,6 @@
#include "mmci.h"
#include "mmci_dma.h"
-#include "mmci_qcom_dml.h"
#define DRIVER_NAME "mmci-pl18x"
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index a73bb98..f7cba35 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -194,6 +194,41 @@
#define MMCI_PINCTRL_STATE_OPENDRAIN "opendrain"
+/* QCOM DML Registers */
+#define DML_CONFIG 0x00
+#define PRODUCER_CRCI_MSK GENMASK(1, 0)
+#define PRODUCER_CRCI_DISABLE 0
+#define PRODUCER_CRCI_X_SEL BIT(0)
+#define PRODUCER_CRCI_Y_SEL BIT(1)
+#define CONSUMER_CRCI_MSK GENMASK(3, 2)
+#define CONSUMER_CRCI_DISABLE 0
+#define CONSUMER_CRCI_X_SEL BIT(2)
+#define CONSUMER_CRCI_Y_SEL BIT(3)
+#define PRODUCER_TRANS_END_EN BIT(4)
+#define BYPASS BIT(16)
+#define DIRECT_MODE BIT(17)
+#define INFINITE_CONS_TRANS BIT(18)
+
+#define DML_SW_RESET 0x08
+#define DML_PRODUCER_START 0x0c
+#define DML_CONSUMER_START 0x10
+#define DML_PRODUCER_PIPE_LOGICAL_SIZE 0x14
+#define DML_CONSUMER_PIPE_LOGICAL_SIZE 0x18
+#define DML_PIPE_ID 0x1c
+#define PRODUCER_PIPE_ID_SHFT 0
+#define PRODUCER_PIPE_ID_MSK GENMASK(4, 0)
+#define CONSUMER_PIPE_ID_SHFT 16
+#define CONSUMER_PIPE_ID_MSK GENMASK(20, 16)
+
+#define DML_PRODUCER_BAM_BLOCK_SIZE 0x24
+#define DML_PRODUCER_BAM_TRANS_SIZE 0x28
+
+/* other definitions */
+#define PRODUCER_PIPE_LOGICAL_SIZE 4096
+#define CONSUMER_PIPE_LOGICAL_SIZE 4096
+
+#define DML_OFFSET 0x800
+
struct clk;
struct dma_chan;
diff --git a/drivers/mmc/host/mmci_dma.c b/drivers/mmc/host/mmci_dma.c
index 98a542d..dd7dae5 100644
--- a/drivers/mmc/host/mmci_dma.c
+++ b/drivers/mmc/host/mmci_dma.c
@@ -8,11 +8,11 @@
#include <linux/dmaengine.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
+#include <linux/of.h>
#include <linux/scatterlist.h>
#include "mmci.h"
#include "mmci_dma.h"
-#include "mmci_qcom_dml.h"
int mmci_dma_setup(struct mmci_host *host)
{
@@ -101,6 +101,139 @@ struct dmaengine_priv {
#define dma_inprogress(dmae) ((dmae)->dma_in_progress)
+#ifdef CONFIG_MMC_QCOM_DML
+void dml_start_xfer(struct mmci_host *host, struct mmc_data *data)
+{
+ u32 config;
+ void __iomem *base = host->base + DML_OFFSET;
+
+ if (data->flags & MMC_DATA_READ) {
+ /* Read operation: configure DML for producer operation */
+ /* Set producer CRCI-x and disable consumer CRCI */
+ config = readl_relaxed(base + DML_CONFIG);
+ config = (config & ~PRODUCER_CRCI_MSK) | PRODUCER_CRCI_X_SEL;
+ config = (config & ~CONSUMER_CRCI_MSK) | CONSUMER_CRCI_DISABLE;
+ writel_relaxed(config, base + DML_CONFIG);
+
+ /* Set the Producer BAM block size */
+ writel_relaxed(data->blksz, base + DML_PRODUCER_BAM_BLOCK_SIZE);
+
+ /* Set Producer BAM Transaction size */
+ writel_relaxed(data->blocks * data->blksz,
+ base + DML_PRODUCER_BAM_TRANS_SIZE);
+ /* Set Producer Transaction End bit */
+ config = readl_relaxed(base + DML_CONFIG);
+ config |= PRODUCER_TRANS_END_EN;
+ writel_relaxed(config, base + DML_CONFIG);
+ /* Trigger producer */
+ writel_relaxed(1, base + DML_PRODUCER_START);
+ } else {
+ /* Write operation: configure DML for consumer operation */
+ /* Set consumer CRCI-x and disable producer CRCI*/
+ config = readl_relaxed(base + DML_CONFIG);
+ config = (config & ~CONSUMER_CRCI_MSK) | CONSUMER_CRCI_X_SEL;
+ config = (config & ~PRODUCER_CRCI_MSK) | PRODUCER_CRCI_DISABLE;
+ writel_relaxed(config, base + DML_CONFIG);
+ /* Clear Producer Transaction End bit */
+ config = readl_relaxed(base + DML_CONFIG);
+ config &= ~PRODUCER_TRANS_END_EN;
+ writel_relaxed(config, base + DML_CONFIG);
+ /* Trigger consumer */
+ writel_relaxed(1, base + DML_CONSUMER_START);
+ }
+
+ /* make sure the dml is configured before dma is triggered */
+ wmb();
+}
+
+static int of_get_dml_pipe_index(struct device_node *np, const char *name)
+{
+ int index;
+ struct of_phandle_args dma_spec;
+
+ index = of_property_match_string(np, "dma-names", name);
+
+ if (index < 0)
+ return -ENODEV;
+
+ if (of_parse_phandle_with_args(np, "dmas", "#dma-cells", index,
+ &dma_spec))
+ return -ENODEV;
+
+ if (dma_spec.args_count)
+ return dma_spec.args[0];
+
+ return -ENODEV;
+}
+
+/* Initialize the dml hardware connected to SD Card controller */
+int dml_hw_init(struct mmci_host *host, struct device_node *np)
+{
+ u32 config;
+ void __iomem *base;
+ int consumer_id, producer_id;
+
+ consumer_id = of_get_dml_pipe_index(np, "tx");
+ producer_id = of_get_dml_pipe_index(np, "rx");
+
+ if (producer_id < 0 || consumer_id < 0)
+ return -ENODEV;
+
+ base = host->base + DML_OFFSET;
+
+ /* Reset the DML block */
+ writel_relaxed(1, base + DML_SW_RESET);
+
+ /* Disable the producer and consumer CRCI */
+ config = (PRODUCER_CRCI_DISABLE | CONSUMER_CRCI_DISABLE);
+ /*
+ * Disable the bypass mode. Bypass mode will only be used
+ * if data transfer is to happen in PIO mode and don't
+ * want the BAM interface to connect with SDCC-DML.
+ */
+ config &= ~BYPASS;
+ /*
+ * Disable direct mode as we don't DML to MASTER the AHB bus.
+ * BAM connected with DML should MASTER the AHB bus.
+ */
+ config &= ~DIRECT_MODE;
+ /*
+ * Disable infinite mode transfer as we won't be doing any
+ * infinite size data transfers. All data transfer will be
+ * of finite data size.
+ */
+ config &= ~INFINITE_CONS_TRANS;
+ writel_relaxed(config, base + DML_CONFIG);
+
+ /*
+ * Initialize the logical BAM pipe size for producer
+ * and consumer.
+ */
+ writel_relaxed(PRODUCER_PIPE_LOGICAL_SIZE,
+ base + DML_PRODUCER_PIPE_LOGICAL_SIZE);
+ writel_relaxed(CONSUMER_PIPE_LOGICAL_SIZE,
+ base + DML_CONSUMER_PIPE_LOGICAL_SIZE);
+
+ /* Initialize Producer/consumer pipe id */
+ writel_relaxed(producer_id | (consumer_id << CONSUMER_PIPE_ID_SHFT),
+ base + DML_PIPE_ID);
+
+ /* Make sure dml initialization is finished */
+ mb();
+
+ return 0;
+}
+#else
+static inline int dml_hw_init(struct mmci_host *host, struct device_node *np)
+{
+ return -EINVAL;
+}
+
+static inline void dml_start_xfer(struct mmci_host *host, struct mmc_data *data)
+{
+}
+#endif /* CONFIG_MMC_QCOM_DML */
+
static int dmaengine_setup(struct mmci_host *host)
{
const char *rxname, *txname;
diff --git a/drivers/mmc/host/mmci_qcom_dml.c b/drivers/mmc/host/mmci_qcom_dml.c
deleted file mode 100644
index 00750c9..0000000
--- a/drivers/mmc/host/mmci_qcom_dml.c
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- *
- * Copyright (c) 2011, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-#include <linux/of.h>
-#include <linux/of_dma.h>
-#include <linux/bitops.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/card.h>
-#include "mmci.h"
-
-/* Registers */
-#define DML_CONFIG 0x00
-#define PRODUCER_CRCI_MSK GENMASK(1, 0)
-#define PRODUCER_CRCI_DISABLE 0
-#define PRODUCER_CRCI_X_SEL BIT(0)
-#define PRODUCER_CRCI_Y_SEL BIT(1)
-#define CONSUMER_CRCI_MSK GENMASK(3, 2)
-#define CONSUMER_CRCI_DISABLE 0
-#define CONSUMER_CRCI_X_SEL BIT(2)
-#define CONSUMER_CRCI_Y_SEL BIT(3)
-#define PRODUCER_TRANS_END_EN BIT(4)
-#define BYPASS BIT(16)
-#define DIRECT_MODE BIT(17)
-#define INFINITE_CONS_TRANS BIT(18)
-
-#define DML_SW_RESET 0x08
-#define DML_PRODUCER_START 0x0c
-#define DML_CONSUMER_START 0x10
-#define DML_PRODUCER_PIPE_LOGICAL_SIZE 0x14
-#define DML_CONSUMER_PIPE_LOGICAL_SIZE 0x18
-#define DML_PIPE_ID 0x1c
-#define PRODUCER_PIPE_ID_SHFT 0
-#define PRODUCER_PIPE_ID_MSK GENMASK(4, 0)
-#define CONSUMER_PIPE_ID_SHFT 16
-#define CONSUMER_PIPE_ID_MSK GENMASK(20, 16)
-
-#define DML_PRODUCER_BAM_BLOCK_SIZE 0x24
-#define DML_PRODUCER_BAM_TRANS_SIZE 0x28
-
-/* other definitions */
-#define PRODUCER_PIPE_LOGICAL_SIZE 4096
-#define CONSUMER_PIPE_LOGICAL_SIZE 4096
-
-#define DML_OFFSET 0x800
-
-void dml_start_xfer(struct mmci_host *host, struct mmc_data *data)
-{
- u32 config;
- void __iomem *base = host->base + DML_OFFSET;
-
- if (data->flags & MMC_DATA_READ) {
- /* Read operation: configure DML for producer operation */
- /* Set producer CRCI-x and disable consumer CRCI */
- config = readl_relaxed(base + DML_CONFIG);
- config = (config & ~PRODUCER_CRCI_MSK) | PRODUCER_CRCI_X_SEL;
- config = (config & ~CONSUMER_CRCI_MSK) | CONSUMER_CRCI_DISABLE;
- writel_relaxed(config, base + DML_CONFIG);
-
- /* Set the Producer BAM block size */
- writel_relaxed(data->blksz, base + DML_PRODUCER_BAM_BLOCK_SIZE);
-
- /* Set Producer BAM Transaction size */
- writel_relaxed(data->blocks * data->blksz,
- base + DML_PRODUCER_BAM_TRANS_SIZE);
- /* Set Producer Transaction End bit */
- config = readl_relaxed(base + DML_CONFIG);
- config |= PRODUCER_TRANS_END_EN;
- writel_relaxed(config, base + DML_CONFIG);
- /* Trigger producer */
- writel_relaxed(1, base + DML_PRODUCER_START);
- } else {
- /* Write operation: configure DML for consumer operation */
- /* Set consumer CRCI-x and disable producer CRCI*/
- config = readl_relaxed(base + DML_CONFIG);
- config = (config & ~CONSUMER_CRCI_MSK) | CONSUMER_CRCI_X_SEL;
- config = (config & ~PRODUCER_CRCI_MSK) | PRODUCER_CRCI_DISABLE;
- writel_relaxed(config, base + DML_CONFIG);
- /* Clear Producer Transaction End bit */
- config = readl_relaxed(base + DML_CONFIG);
- config &= ~PRODUCER_TRANS_END_EN;
- writel_relaxed(config, base + DML_CONFIG);
- /* Trigger consumer */
- writel_relaxed(1, base + DML_CONSUMER_START);
- }
-
- /* make sure the dml is configured before dma is triggered */
- wmb();
-}
-
-static int of_get_dml_pipe_index(struct device_node *np, const char *name)
-{
- int index;
- struct of_phandle_args dma_spec;
-
- index = of_property_match_string(np, "dma-names", name);
-
- if (index < 0)
- return -ENODEV;
-
- if (of_parse_phandle_with_args(np, "dmas", "#dma-cells", index,
- &dma_spec))
- return -ENODEV;
-
- if (dma_spec.args_count)
- return dma_spec.args[0];
-
- return -ENODEV;
-}
-
-/* Initialize the dml hardware connected to SD Card controller */
-int dml_hw_init(struct mmci_host *host, struct device_node *np)
-{
- u32 config;
- void __iomem *base;
- int consumer_id, producer_id;
-
- consumer_id = of_get_dml_pipe_index(np, "tx");
- producer_id = of_get_dml_pipe_index(np, "rx");
-
- if (producer_id < 0 || consumer_id < 0)
- return -ENODEV;
-
- base = host->base + DML_OFFSET;
-
- /* Reset the DML block */
- writel_relaxed(1, base + DML_SW_RESET);
-
- /* Disable the producer and consumer CRCI */
- config = (PRODUCER_CRCI_DISABLE | CONSUMER_CRCI_DISABLE);
- /*
- * Disable the bypass mode. Bypass mode will only be used
- * if data transfer is to happen in PIO mode and don't
- * want the BAM interface to connect with SDCC-DML.
- */
- config &= ~BYPASS;
- /*
- * Disable direct mode as we don't DML to MASTER the AHB bus.
- * BAM connected with DML should MASTER the AHB bus.
- */
- config &= ~DIRECT_MODE;
- /*
- * Disable infinite mode transfer as we won't be doing any
- * infinite size data transfers. All data transfer will be
- * of finite data size.
- */
- config &= ~INFINITE_CONS_TRANS;
- writel_relaxed(config, base + DML_CONFIG);
-
- /*
- * Initialize the logical BAM pipe size for producer
- * and consumer.
- */
- writel_relaxed(PRODUCER_PIPE_LOGICAL_SIZE,
- base + DML_PRODUCER_PIPE_LOGICAL_SIZE);
- writel_relaxed(CONSUMER_PIPE_LOGICAL_SIZE,
- base + DML_CONSUMER_PIPE_LOGICAL_SIZE);
-
- /* Initialize Producer/consumer pipe id */
- writel_relaxed(producer_id | (consumer_id << CONSUMER_PIPE_ID_SHFT),
- base + DML_PIPE_ID);
-
- /* Make sure dml initialization is finished */
- mb();
-
- return 0;
-}
diff --git a/drivers/mmc/host/mmci_qcom_dml.h b/drivers/mmc/host/mmci_qcom_dml.h
deleted file mode 100644
index 6e405d0..0000000
--- a/drivers/mmc/host/mmci_qcom_dml.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- *
- * Copyright (c) 2011, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-#ifndef __MMC_QCOM_DML_H__
-#define __MMC_QCOM_DML_H__
-
-#ifdef CONFIG_MMC_QCOM_DML
-int dml_hw_init(struct mmci_host *host, struct device_node *np);
-void dml_start_xfer(struct mmci_host *host, struct mmc_data *data);
-#else
-static inline int dml_hw_init(struct mmci_host *host, struct device_node *np)
-{
- return -ENOSYS;
-}
-static inline void dml_start_xfer(struct mmci_host *host, struct mmc_data *data)
-{
-}
-#endif /* CONFIG_MMC_QCOM_DML */
-
-#endif /* __MMC_QCOM_DML_H__ */
--
2.7.4
^ permalink raw reply related
* [PATCH 03/19] mmc: mmci: add datactrl block size variant property
From: Ludovic Barre @ 2018-06-12 13:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1528809280-31116-1-git-send-email-ludovic.Barre@st.com>
From: Ludovic Barre <ludovic.barre@st.com>
This patch allows to define a datactrl block size
by variant, requested by STM32 sdmmc variant.
Signed-off-by: Ludovic Barre <ludovic.barre@st.com>
---
drivers/mmc/host/mmci.c | 13 +++++++++++--
drivers/mmc/host/mmci.h | 2 ++
2 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 7a15afd..9b25714 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -52,6 +52,7 @@ static struct variant_data variant_arm = {
.fifosize = 16 * 4,
.fifohalfsize = 8 * 4,
.datalength_bits = 16,
+ .datactrl_blocksz = 11,
.pwrreg_powerup = MCI_PWR_UP,
.f_max = 100000000,
.reversed_irq_handling = true,
@@ -65,6 +66,7 @@ static struct variant_data variant_arm_extended_fifo = {
.fifosize = 128 * 4,
.fifohalfsize = 64 * 4,
.datalength_bits = 16,
+ .datactrl_blocksz = 11,
.pwrreg_powerup = MCI_PWR_UP,
.f_max = 100000000,
.mmcimask1 = true,
@@ -78,6 +80,7 @@ static struct variant_data variant_arm_extended_fifo_hwfc = {
.fifohalfsize = 64 * 4,
.clkreg_enable = MCI_ARM_HWFCEN,
.datalength_bits = 16,
+ .datactrl_blocksz = 11,
.pwrreg_powerup = MCI_PWR_UP,
.f_max = 100000000,
.mmcimask1 = true,
@@ -92,6 +95,7 @@ static struct variant_data variant_u300 = {
.clkreg_enable = MCI_ST_U300_HWFCEN,
.clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
.datalength_bits = 16,
+ .datactrl_blocksz = 11,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
.st_sdio = true,
.pwrreg_powerup = MCI_PWR_ON,
@@ -111,6 +115,7 @@ static struct variant_data variant_nomadik = {
.clkreg = MCI_CLK_ENABLE,
.clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
.datalength_bits = 24,
+ .datactrl_blocksz = 11,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
.st_sdio = true,
.st_clkdiv = true,
@@ -133,6 +138,7 @@ static struct variant_data variant_ux500 = {
.clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
.clkreg_neg_edge_enable = MCI_ST_UX500_NEG_EDGE,
.datalength_bits = 24,
+ .datactrl_blocksz = 11,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
.st_sdio = true,
.st_clkdiv = true,
@@ -160,6 +166,7 @@ static struct variant_data variant_ux500v2 = {
.clkreg_neg_edge_enable = MCI_ST_UX500_NEG_EDGE,
.datactrl_mask_ddrmode = MCI_DPSM_ST_DDRMODE,
.datalength_bits = 24,
+ .datactrl_blocksz = 11,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
.st_sdio = true,
.st_clkdiv = true,
@@ -187,6 +194,7 @@ static struct variant_data variant_stm32 = {
.clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
.clkreg_neg_edge_enable = MCI_ST_UX500_NEG_EDGE,
.datalength_bits = 24,
+ .datactrl_blocksz = 11,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
.st_sdio = true,
.st_clkdiv = true,
@@ -208,6 +216,7 @@ static struct variant_data variant_qcom = {
.data_cmd_enable = MCI_CPSM_QCOM_DATCMD,
.blksz_datactrl4 = true,
.datalength_bits = 24,
+ .datactrl_blocksz = 11,
.pwrreg_powerup = MCI_PWR_UP,
.f_max = 208000000,
.explicit_mclk_control = true,
@@ -1399,13 +1408,13 @@ static int mmci_probe(struct amba_device *dev,
/*
* Block size can be up to 2048 bytes, but must be a power of two.
*/
- mmc->max_blk_size = 1 << 11;
+ mmc->max_blk_size = 1 << variant->datactrl_blocksz;
/*
* Limit the number of blocks transferred so that we don't overflow
* the maximum request size.
*/
- mmc->max_blk_count = mmc->max_req_size >> 11;
+ mmc->max_blk_count = mmc->max_req_size >> variant->datactrl_blocksz;
spin_lock_init(&host->lock);
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index f7cba35..27a2236 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -252,6 +252,7 @@ struct dma_chan;
* @blksz_datactrl4: true if Block size is at b4..b16 position in datactrl
* register
* @datactrl_mask_sdio: SDIO enable mask in datactrl register
+ * @datactrl_blksz: block size in power of two
* @pwrreg_powerup: power up value for MMCIPOWER register
* @f_max: maximum clk frequency supported by the controller.
* @signal_direction: input/out direction of bus signals can be indicated
@@ -284,6 +285,7 @@ struct variant_data {
unsigned int data_cmd_enable;
unsigned int datactrl_mask_ddrmode;
unsigned int datactrl_mask_sdio;
+ unsigned int datactrl_blocksz;
bool st_sdio;
bool st_clkdiv;
bool blksz_datactrl16;
--
2.7.4
^ permalink raw reply related
* [PATCH 04/19] mmc: mmci: expand startbiterr to irqmask and error check
From: Ludovic Barre @ 2018-06-12 13:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1528809280-31116-1-git-send-email-ludovic.Barre@st.com>
From: Ludovic Barre <ludovic.barre@st.com>
All variants don't pretend to have a startbiterr.
-While data error check, if status register return an error
(like MCI_DATACRCFAIL) we must avoid to check MCI_STARTBITERR
(if not desired).
-expand start_err to MCI_IRQENABLE to avoid to set this bit by default.
Signed-off-by: Ludovic Barre <ludovic.barre@st.com>
---
drivers/mmc/host/mmci.c | 27 ++++++++++++++++-----------
drivers/mmc/host/mmci.h | 6 +++---
2 files changed, 19 insertions(+), 14 deletions(-)
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 9b25714..ede95b7 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -584,14 +584,18 @@ static void
mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
unsigned int status)
{
+ unsigned int status_err;
+
/* Make sure we have data to handle */
if (!data)
return;
/* First check for errors */
- if (status & (MCI_DATACRCFAIL | MCI_DATATIMEOUT |
- host->variant->start_err |
- MCI_TXUNDERRUN | MCI_RXOVERRUN)) {
+ status_err = status & (host->variant->start_err |
+ MCI_DATACRCFAIL | MCI_DATATIMEOUT |
+ MCI_TXUNDERRUN | MCI_RXOVERRUN);
+
+ if (status_err) {
u32 remain, success;
/* Terminate the DMA transfer */
@@ -608,18 +612,18 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
success = data->blksz * data->blocks - remain;
dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ, status 0x%08x at 0x%08x\n",
- status, success);
- if (status & MCI_DATACRCFAIL) {
+ status_err, success);
+ if (status_err & MCI_DATACRCFAIL) {
/* Last block was not successful */
success -= 1;
data->error = -EILSEQ;
- } else if (status & MCI_DATATIMEOUT) {
+ } else if (status_err & MCI_DATATIMEOUT) {
data->error = -ETIMEDOUT;
- } else if (status & MCI_STARTBITERR) {
+ } else if (status_err & MCI_STARTBITERR) {
data->error = -ECOMM;
- } else if (status & MCI_TXUNDERRUN) {
+ } else if (status_err & MCI_TXUNDERRUN) {
data->error = -EIO;
- } else if (status & MCI_RXOVERRUN) {
+ } else if (status_err & MCI_RXOVERRUN) {
if (success > host->variant->fifosize)
success -= host->variant->fifosize;
else
@@ -1470,7 +1474,7 @@ static int mmci_probe(struct amba_device *dev,
goto clk_disable;
}
- writel(MCI_IRQENABLE, host->base + MMCIMASK0);
+ writel(MCI_IRQENABLE | variant->start_err, host->base + MMCIMASK0);
amba_set_drvdata(dev, mmc);
@@ -1557,7 +1561,8 @@ static void mmci_restore(struct mmci_host *host)
writel(host->datactrl_reg, host->base + MMCIDATACTRL);
writel(host->pwr_reg, host->base + MMCIPOWER);
}
- writel(MCI_IRQENABLE, host->base + MMCIMASK0);
+ writel(MCI_IRQENABLE | host->variant->start_err,
+ host->base + MMCIMASK0);
mmci_reg_delay(host);
spin_unlock_irqrestore(&host->lock, flags);
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index 27a2236..2ba9640 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -181,9 +181,9 @@
#define MMCIFIFO 0x080 /* to 0x0bc */
#define MCI_IRQENABLE \
- (MCI_CMDCRCFAILMASK|MCI_DATACRCFAILMASK|MCI_CMDTIMEOUTMASK| \
- MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK| \
- MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_STARTBITERRMASK)
+ (MCI_CMDCRCFAILMASK | MCI_DATACRCFAILMASK | MCI_CMDTIMEOUTMASK | \
+ MCI_DATATIMEOUTMASK | MCI_TXUNDERRUNMASK | MCI_RXOVERRUNMASK | \
+ MCI_CMDRESPENDMASK | MCI_CMDSENTMASK)
/* These interrupts are directed to IRQ1 when two IRQ lines are available */
#define MCI_IRQ1MASK \
--
2.7.4
^ permalink raw reply related
* [PATCH 05/19] mmc: mmci: allow to overwrite clock/power procedure to specific variant
From: Ludovic Barre @ 2018-06-12 13:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1528809280-31116-1-git-send-email-ludovic.Barre@st.com>
From: Ludovic Barre <ludovic.barre@st.com>
A specific variant could have different power or clock procedures.
This patch allows to overwrite the default mmci_set_clkreg and
mmci_set_pwrreg for a specific variant.
Signed-off-by: Ludovic Barre <ludovic.barre@st.com>
---
drivers/mmc/host/mmci.c | 96 +++++++++++++++++++++++++++++--------------------
drivers/mmc/host/mmci.h | 7 ++++
2 files changed, 64 insertions(+), 39 deletions(-)
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index ede95b7..801c86b 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -374,6 +374,52 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
mmci_write_clkreg(host, clk);
}
+static void mmci_set_pwrreg(struct mmci_host *host, unsigned char power_mode,
+ unsigned int pwr)
+{
+ struct variant_data *variant = host->variant;
+ struct mmc_host *mmc = host->mmc;
+
+ switch (power_mode) {
+ case MMC_POWER_OFF:
+ if (!IS_ERR(mmc->supply.vmmc))
+ mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
+
+ if (!IS_ERR(mmc->supply.vqmmc) && host->vqmmc_enabled) {
+ regulator_disable(mmc->supply.vqmmc);
+ host->vqmmc_enabled = false;
+ }
+
+ break;
+ case MMC_POWER_UP:
+ if (!IS_ERR(mmc->supply.vmmc))
+ mmc_regulator_set_ocr(mmc, mmc->supply.vmmc,
+ mmc->ios.vdd);
+
+ /*
+ * The ST Micro variant doesn't have the PL180s MCI_PWR_UP
+ * and instead uses MCI_PWR_ON so apply whatever value is
+ * configured in the variant data.
+ */
+ pwr |= variant->pwrreg_powerup;
+
+ break;
+ case MMC_POWER_ON:
+ if (!IS_ERR(mmc->supply.vqmmc) && !host->vqmmc_enabled) {
+ if (regulator_enable(mmc->supply.vqmmc) < 0)
+ dev_err(mmc_dev(mmc),
+ "failed to enable vqmmc regulator\n");
+ else
+ host->vqmmc_enabled = true;
+ }
+
+ pwr |= MCI_PWR_ON;
+ break;
+ }
+
+ mmci_write_pwrreg(host, pwr);
+}
+
static void
mmci_request_end(struct mmci_host *host, struct mmc_request *mrq)
{
@@ -1031,7 +1077,7 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct mmci_host *host = mmc_priv(mmc);
struct variant_data *variant = host->variant;
- u32 pwr = 0;
+ unsigned int pwr = 0;
unsigned long flags;
int ret;
@@ -1039,42 +1085,6 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
host->plat->ios_handler(mmc_dev(mmc), ios))
dev_err(mmc_dev(mmc), "platform ios_handler failed\n");
- switch (ios->power_mode) {
- case MMC_POWER_OFF:
- if (!IS_ERR(mmc->supply.vmmc))
- mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
-
- if (!IS_ERR(mmc->supply.vqmmc) && host->vqmmc_enabled) {
- regulator_disable(mmc->supply.vqmmc);
- host->vqmmc_enabled = false;
- }
-
- break;
- case MMC_POWER_UP:
- if (!IS_ERR(mmc->supply.vmmc))
- mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd);
-
- /*
- * The ST Micro variant doesn't have the PL180s MCI_PWR_UP
- * and instead uses MCI_PWR_ON so apply whatever value is
- * configured in the variant data.
- */
- pwr |= variant->pwrreg_powerup;
-
- break;
- case MMC_POWER_ON:
- if (!IS_ERR(mmc->supply.vqmmc) && !host->vqmmc_enabled) {
- ret = regulator_enable(mmc->supply.vqmmc);
- if (ret < 0)
- dev_err(mmc_dev(mmc),
- "failed to enable vqmmc regulator\n");
- else
- host->vqmmc_enabled = true;
- }
-
- pwr |= MCI_PWR_ON;
- break;
- }
if (variant->signal_direction && ios->power_mode != MMC_POWER_OFF) {
/*
@@ -1126,8 +1136,16 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
spin_lock_irqsave(&host->lock, flags);
- mmci_set_clkreg(host, ios->clock);
- mmci_write_pwrreg(host, pwr);
+ if (variant->set_clkreg)
+ variant->set_clkreg(host, ios->clock);
+ else
+ mmci_set_clkreg(host, ios->clock);
+
+ if (variant->set_pwrreg)
+ variant->set_pwrreg(host, ios->power_mode, pwr);
+ else
+ mmci_set_pwrreg(host, ios->power_mode, pwr);
+
mmci_reg_delay(host);
spin_unlock_irqrestore(&host->lock, flags);
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index 2ba9640..7265ca6 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -231,6 +231,7 @@
struct clk;
struct dma_chan;
+struct mmci_host;
/**
* struct variant_data - MMCI variant-specific quirks
@@ -273,6 +274,8 @@ struct dma_chan;
* register.
* @opendrain: bitmask identifying the OPENDRAIN bit inside MMCIPOWER register
* @mmci_dma: Pointer to platform-specific DMA callbacks.
+ * @set_clk_ios: if clock procedure of variant is specific
+ * @set_pwr_ios: if power procedure of variant is specific
*/
struct variant_data {
unsigned int clkreg;
@@ -307,6 +310,9 @@ struct variant_data {
u32 start_err;
u32 opendrain;
struct mmci_dma_ops *mmci_dma;
+ void (*set_clkreg)(struct mmci_host *host, unsigned int desired);
+ void (*set_pwrreg)(struct mmci_host *host, unsigned char power_mode,
+ unsigned int pwr);
};
struct mmci_host {
@@ -328,6 +334,7 @@ struct mmci_host {
u32 pwr_reg;
u32 pwr_reg_add;
u32 clk_reg;
+ u32 clk_reg_add;
u32 datactrl_reg;
u32 busy_status;
u32 mask1_reg;
--
2.7.4
^ permalink raw reply related
* [PATCH 06/19] mmc: mmci: add variant properties to define cpsm & cmdresp bits
From: Ludovic Barre @ 2018-06-12 13:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1528809280-31116-1-git-send-email-ludovic.Barre@st.com>
From: Ludovic Barre <ludovic.barre@st.com>
This patch adds command variant properties to define
cpsm enable bit and responses.
Needed to support the STM32 variant (shift of cpsm bit,
specific definition of commands response).
Signed-off-by: Ludovic Barre <ludovic.barre@st.com>
---
drivers/mmc/host/mmci.c | 47 +++++++++++++++++++++++++++++++++++++++++++----
drivers/mmc/host/mmci.h | 8 ++++++++
2 files changed, 51 insertions(+), 4 deletions(-)
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 801c86b..52562fc 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -51,6 +51,10 @@ static unsigned int fmax = 515633;
static struct variant_data variant_arm = {
.fifosize = 16 * 4,
.fifohalfsize = 8 * 4,
+ .cmdreg_cpsm_enable = MCI_CPSM_ENABLE,
+ .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP,
+ .cmdreg_srsp_crc = MCI_CPSM_RESPONSE,
+ .cmdreg_srsp = MCI_CPSM_RESPONSE,
.datalength_bits = 16,
.datactrl_blocksz = 11,
.pwrreg_powerup = MCI_PWR_UP,
@@ -65,6 +69,10 @@ static struct variant_data variant_arm = {
static struct variant_data variant_arm_extended_fifo = {
.fifosize = 128 * 4,
.fifohalfsize = 64 * 4,
+ .cmdreg_cpsm_enable = MCI_CPSM_ENABLE,
+ .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP,
+ .cmdreg_srsp_crc = MCI_CPSM_RESPONSE,
+ .cmdreg_srsp = MCI_CPSM_RESPONSE,
.datalength_bits = 16,
.datactrl_blocksz = 11,
.pwrreg_powerup = MCI_PWR_UP,
@@ -79,6 +87,10 @@ static struct variant_data variant_arm_extended_fifo_hwfc = {
.fifosize = 128 * 4,
.fifohalfsize = 64 * 4,
.clkreg_enable = MCI_ARM_HWFCEN,
+ .cmdreg_cpsm_enable = MCI_CPSM_ENABLE,
+ .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP,
+ .cmdreg_srsp_crc = MCI_CPSM_RESPONSE,
+ .cmdreg_srsp = MCI_CPSM_RESPONSE,
.datalength_bits = 16,
.datactrl_blocksz = 11,
.pwrreg_powerup = MCI_PWR_UP,
@@ -94,6 +106,10 @@ static struct variant_data variant_u300 = {
.fifohalfsize = 8 * 4,
.clkreg_enable = MCI_ST_U300_HWFCEN,
.clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
+ .cmdreg_cpsm_enable = MCI_CPSM_ENABLE,
+ .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP,
+ .cmdreg_srsp_crc = MCI_CPSM_RESPONSE,
+ .cmdreg_srsp = MCI_CPSM_RESPONSE,
.datalength_bits = 16,
.datactrl_blocksz = 11,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
@@ -114,6 +130,10 @@ static struct variant_data variant_nomadik = {
.fifohalfsize = 8 * 4,
.clkreg = MCI_CLK_ENABLE,
.clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
+ .cmdreg_cpsm_enable = MCI_CPSM_ENABLE,
+ .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP,
+ .cmdreg_srsp_crc = MCI_CPSM_RESPONSE,
+ .cmdreg_srsp = MCI_CPSM_RESPONSE,
.datalength_bits = 24,
.datactrl_blocksz = 11,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
@@ -137,6 +157,10 @@ static struct variant_data variant_ux500 = {
.clkreg_enable = MCI_ST_UX500_HWFCEN,
.clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
.clkreg_neg_edge_enable = MCI_ST_UX500_NEG_EDGE,
+ .cmdreg_cpsm_enable = MCI_CPSM_ENABLE,
+ .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP,
+ .cmdreg_srsp_crc = MCI_CPSM_RESPONSE,
+ .cmdreg_srsp = MCI_CPSM_RESPONSE,
.datalength_bits = 24,
.datactrl_blocksz = 11,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
@@ -164,6 +188,10 @@ static struct variant_data variant_ux500v2 = {
.clkreg_enable = MCI_ST_UX500_HWFCEN,
.clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
.clkreg_neg_edge_enable = MCI_ST_UX500_NEG_EDGE,
+ .cmdreg_cpsm_enable = MCI_CPSM_ENABLE,
+ .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP,
+ .cmdreg_srsp_crc = MCI_CPSM_RESPONSE,
+ .cmdreg_srsp = MCI_CPSM_RESPONSE,
.datactrl_mask_ddrmode = MCI_DPSM_ST_DDRMODE,
.datalength_bits = 24,
.datactrl_blocksz = 11,
@@ -193,6 +221,10 @@ static struct variant_data variant_stm32 = {
.clkreg_enable = MCI_ST_UX500_HWFCEN,
.clkreg_8bit_bus_enable = MCI_ST_8BIT_BUS,
.clkreg_neg_edge_enable = MCI_ST_UX500_NEG_EDGE,
+ .cmdreg_cpsm_enable = MCI_CPSM_ENABLE,
+ .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP,
+ .cmdreg_srsp_crc = MCI_CPSM_RESPONSE,
+ .cmdreg_srsp = MCI_CPSM_RESPONSE,
.datalength_bits = 24,
.datactrl_blocksz = 11,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
@@ -213,6 +245,10 @@ static struct variant_data variant_qcom = {
MCI_QCOM_CLK_SELECT_IN_FBCLK,
.clkreg_8bit_bus_enable = MCI_QCOM_CLK_WIDEBUS_8,
.datactrl_mask_ddrmode = MCI_QCOM_CLK_SELECT_IN_DDR_MODE,
+ .cmdreg_cpsm_enable = MCI_CPSM_ENABLE,
+ .cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP,
+ .cmdreg_srsp_crc = MCI_CPSM_RESPONSE,
+ .cmdreg_srsp = MCI_CPSM_RESPONSE,
.data_cmd_enable = MCI_CPSM_QCOM_DATCMD,
.blksz_datactrl4 = true,
.datalength_bits = 24,
@@ -603,16 +639,19 @@ mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c)
dev_dbg(mmc_dev(host->mmc), "op %02x arg %08x flags %08x\n",
cmd->opcode, cmd->arg, cmd->flags);
- if (readl(base + MMCICOMMAND) & MCI_CPSM_ENABLE) {
+ if (readl(base + MMCICOMMAND) & host->variant->cmdreg_cpsm_enable) {
writel(0, base + MMCICOMMAND);
mmci_reg_delay(host);
}
- c |= cmd->opcode | MCI_CPSM_ENABLE;
+ c |= cmd->opcode | host->variant->cmdreg_cpsm_enable;
if (cmd->flags & MMC_RSP_PRESENT) {
if (cmd->flags & MMC_RSP_136)
- c |= MCI_CPSM_LONGRSP;
- c |= MCI_CPSM_RESPONSE;
+ c |= host->variant->cmdreg_lrsp_crc;
+ else if (cmd->flags & MMC_RSP_CRC)
+ c |= host->variant->cmdreg_srsp_crc;
+ else
+ c |= host->variant->cmdreg_srsp;
}
if (/*interrupt*/0)
c |= MCI_CPSM_INTERRUPT;
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index 7265ca6..e173305 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -239,6 +239,10 @@ struct mmci_host;
* @clkreg_enable: enable value for MMCICLOCK register
* @clkreg_8bit_bus_enable: enable value for 8 bit bus
* @clkreg_neg_edge_enable: enable value for inverted data/cmd output
+ * @cmdreg_cpsm_enable: enable value for CPSM
+ * @cmdreg_lrsp_crc: enable value for long response with crc
+ * @cmdreg_srsp_crc: enable value for short response with crc
+ * @cmdreg_srsp: enable value for short response without crc
* @datalength_bits: number of bits in the MMCIDATALENGTH register
* @fifosize: number of bytes that can be written when MMCI_TXFIFOEMPTY
* is asserted (likewise for RX)
@@ -282,6 +286,10 @@ struct variant_data {
unsigned int clkreg_enable;
unsigned int clkreg_8bit_bus_enable;
unsigned int clkreg_neg_edge_enable;
+ unsigned int cmdreg_cpsm_enable;
+ unsigned int cmdreg_lrsp_crc;
+ unsigned int cmdreg_srsp_crc;
+ unsigned int cmdreg_srsp;
unsigned int datalength_bits;
unsigned int fifosize;
unsigned int fifohalfsize;
--
2.7.4
^ permalink raw reply related
* [PATCH 07/19] mmc: mmci: add variant property to define dpsm bit
From: Ludovic Barre @ 2018-06-12 13:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1528809280-31116-1-git-send-email-ludovic.Barre@st.com>
From: Ludovic Barre <ludovic.barre@st.com>
This patch adds datactrl variant property to define
dpsm enable bit. Needed to support the STM32 variant
(STM32 has no dpsm enable bit).
Signed-off-by: Ludovic Barre <ludovic.barre@st.com>
---
drivers/mmc/host/mmci.c | 15 ++++++++++++---
drivers/mmc/host/mmci.h | 2 ++
2 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 52562fc..1f44c61 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -57,6 +57,7 @@ static struct variant_data variant_arm = {
.cmdreg_srsp = MCI_CPSM_RESPONSE,
.datalength_bits = 16,
.datactrl_blocksz = 11,
+ .datactrl_dpsm_enable = MCI_DPSM_ENABLE,
.pwrreg_powerup = MCI_PWR_UP,
.f_max = 100000000,
.reversed_irq_handling = true,
@@ -75,6 +76,7 @@ static struct variant_data variant_arm_extended_fifo = {
.cmdreg_srsp = MCI_CPSM_RESPONSE,
.datalength_bits = 16,
.datactrl_blocksz = 11,
+ .datactrl_dpsm_enable = MCI_DPSM_ENABLE,
.pwrreg_powerup = MCI_PWR_UP,
.f_max = 100000000,
.mmcimask1 = true,
@@ -93,6 +95,7 @@ static struct variant_data variant_arm_extended_fifo_hwfc = {
.cmdreg_srsp = MCI_CPSM_RESPONSE,
.datalength_bits = 16,
.datactrl_blocksz = 11,
+ .datactrl_dpsm_enable = MCI_DPSM_ENABLE,
.pwrreg_powerup = MCI_PWR_UP,
.f_max = 100000000,
.mmcimask1 = true,
@@ -112,6 +115,7 @@ static struct variant_data variant_u300 = {
.cmdreg_srsp = MCI_CPSM_RESPONSE,
.datalength_bits = 16,
.datactrl_blocksz = 11,
+ .datactrl_dpsm_enable = MCI_DPSM_ENABLE,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
.st_sdio = true,
.pwrreg_powerup = MCI_PWR_ON,
@@ -136,6 +140,7 @@ static struct variant_data variant_nomadik = {
.cmdreg_srsp = MCI_CPSM_RESPONSE,
.datalength_bits = 24,
.datactrl_blocksz = 11,
+ .datactrl_dpsm_enable = MCI_DPSM_ENABLE,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
.st_sdio = true,
.st_clkdiv = true,
@@ -163,6 +168,7 @@ static struct variant_data variant_ux500 = {
.cmdreg_srsp = MCI_CPSM_RESPONSE,
.datalength_bits = 24,
.datactrl_blocksz = 11,
+ .datactrl_dpsm_enable = MCI_DPSM_ENABLE,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
.st_sdio = true,
.st_clkdiv = true,
@@ -195,6 +201,7 @@ static struct variant_data variant_ux500v2 = {
.datactrl_mask_ddrmode = MCI_DPSM_ST_DDRMODE,
.datalength_bits = 24,
.datactrl_blocksz = 11,
+ .datactrl_dpsm_enable = MCI_DPSM_ENABLE,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
.st_sdio = true,
.st_clkdiv = true,
@@ -227,6 +234,7 @@ static struct variant_data variant_stm32 = {
.cmdreg_srsp = MCI_CPSM_RESPONSE,
.datalength_bits = 24,
.datactrl_blocksz = 11,
+ .datactrl_dpsm_enable = MCI_DPSM_ENABLE,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
.st_sdio = true,
.st_clkdiv = true,
@@ -253,6 +261,7 @@ static struct variant_data variant_qcom = {
.blksz_datactrl4 = true,
.datalength_bits = 24,
.datactrl_blocksz = 11,
+ .datactrl_dpsm_enable = MCI_DPSM_ENABLE,
.pwrreg_powerup = MCI_PWR_UP,
.f_max = 208000000,
.explicit_mclk_control = true,
@@ -564,11 +573,11 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
BUG_ON(1 << blksz_bits != data->blksz);
if (variant->blksz_datactrl16)
- datactrl = MCI_DPSM_ENABLE | (data->blksz << 16);
+ datactrl = variant->datactrl_dpsm_enable | (data->blksz << 16);
else if (variant->blksz_datactrl4)
- datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
+ datactrl = variant->datactrl_dpsm_enable | (data->blksz << 4);
else
- datactrl = MCI_DPSM_ENABLE | blksz_bits << 4;
+ datactrl = variant->datactrl_dpsm_enable | blksz_bits << 4;
if (data->flags & MMC_DATA_READ)
datactrl |= MCI_DPSM_DIRECTION;
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index e173305..a2bf8bc 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -258,6 +258,7 @@ struct mmci_host;
* register
* @datactrl_mask_sdio: SDIO enable mask in datactrl register
* @datactrl_blksz: block size in power of two
+ * @datactrl_dpsm_enable: enable value for DPSM
* @pwrreg_powerup: power up value for MMCIPOWER register
* @f_max: maximum clk frequency supported by the controller.
* @signal_direction: input/out direction of bus signals can be indicated
@@ -297,6 +298,7 @@ struct variant_data {
unsigned int datactrl_mask_ddrmode;
unsigned int datactrl_mask_sdio;
unsigned int datactrl_blocksz;
+ unsigned int datactrl_dpsm_enable;
bool st_sdio;
bool st_clkdiv;
bool blksz_datactrl16;
--
2.7.4
^ permalink raw reply related
* [PATCH 08/19] mmc: mmci: add variant property to define irq pio mask
From: Ludovic Barre @ 2018-06-12 13:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1528809280-31116-1-git-send-email-ludovic.Barre@st.com>
From: Ludovic Barre <ludovic.barre@st.com>
This patch allows to define specific pio mask for variants.
Needed to support the STM32 sdmmc variant which has some bits
with different meaning (bits: 21,20,13,12,9)
Signed-off-by: Ludovic Barre <ludovic.barre@st.com>
---
drivers/mmc/host/mmci.c | 13 +++++++++++--
drivers/mmc/host/mmci.h | 5 ++++-
2 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 1f44c61..5fd3ffb6 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -62,6 +62,7 @@ static struct variant_data variant_arm = {
.f_max = 100000000,
.reversed_irq_handling = true,
.mmcimask1 = true,
+ .irq_pio_mask = MCI_IRQ_PIO_MASK,
.start_err = MCI_STARTBITERR,
.opendrain = MCI_ROD,
.mmci_dma = &dmaengine,
@@ -80,6 +81,7 @@ static struct variant_data variant_arm_extended_fifo = {
.pwrreg_powerup = MCI_PWR_UP,
.f_max = 100000000,
.mmcimask1 = true,
+ .irq_pio_mask = MCI_IRQ_PIO_MASK,
.start_err = MCI_STARTBITERR,
.opendrain = MCI_ROD,
.mmci_dma = &dmaengine,
@@ -99,6 +101,7 @@ static struct variant_data variant_arm_extended_fifo_hwfc = {
.pwrreg_powerup = MCI_PWR_UP,
.f_max = 100000000,
.mmcimask1 = true,
+ .irq_pio_mask = MCI_IRQ_PIO_MASK,
.start_err = MCI_STARTBITERR,
.opendrain = MCI_ROD,
.mmci_dma = &dmaengine,
@@ -124,6 +127,7 @@ static struct variant_data variant_u300 = {
.pwrreg_clkgate = true,
.pwrreg_nopower = true,
.mmcimask1 = true,
+ .irq_pio_mask = MCI_IRQ_PIO_MASK,
.start_err = MCI_STARTBITERR,
.opendrain = MCI_OD,
.mmci_dma = &dmaengine,
@@ -150,6 +154,7 @@ static struct variant_data variant_nomadik = {
.pwrreg_clkgate = true,
.pwrreg_nopower = true,
.mmcimask1 = true,
+ .irq_pio_mask = MCI_IRQ_PIO_MASK,
.start_err = MCI_STARTBITERR,
.opendrain = MCI_OD,
.mmci_dma = &dmaengine,
@@ -182,6 +187,7 @@ static struct variant_data variant_ux500 = {
.busy_detect_mask = MCI_ST_BUSYENDMASK,
.pwrreg_nopower = true,
.mmcimask1 = true,
+ .irq_pio_mask = MCI_IRQ_PIO_MASK,
.start_err = MCI_STARTBITERR,
.opendrain = MCI_OD,
.mmci_dma = &dmaengine,
@@ -216,6 +222,7 @@ static struct variant_data variant_ux500v2 = {
.busy_detect_mask = MCI_ST_BUSYENDMASK,
.pwrreg_nopower = true,
.mmcimask1 = true,
+ .irq_pio_mask = MCI_IRQ_PIO_MASK,
.start_err = MCI_STARTBITERR,
.opendrain = MCI_OD,
.mmci_dma = &dmaengine,
@@ -232,6 +239,7 @@ static struct variant_data variant_stm32 = {
.cmdreg_lrsp_crc = MCI_CPSM_RESPONSE | MCI_CPSM_LONGRSP,
.cmdreg_srsp_crc = MCI_CPSM_RESPONSE,
.cmdreg_srsp = MCI_CPSM_RESPONSE,
+ .irq_pio_mask = MCI_IRQ_PIO_MASK,
.datalength_bits = 24,
.datactrl_blocksz = 11,
.datactrl_dpsm_enable = MCI_DPSM_ENABLE,
@@ -268,6 +276,7 @@ static struct variant_data variant_qcom = {
.qcom_fifo = true,
.qcom_dml = true,
.mmcimask1 = true,
+ .irq_pio_mask = MCI_IRQ_PIO_MASK,
.start_err = MCI_STARTBITERR,
.opendrain = MCI_ROD,
.mmci_dma = &dmaengine,
@@ -486,7 +495,7 @@ static void mmci_set_mask1(struct mmci_host *host, unsigned int mask)
if (host->singleirq) {
unsigned int mask0 = readl(base + MMCIMASK0);
- mask0 &= ~MCI_IRQ1MASK;
+ mask0 &= ~variant->irq_pio_mask;
mask0 |= mask;
writel(mask0, base + MMCIMASK0);
@@ -1046,7 +1055,7 @@ static irqreturn_t mmci_irq(int irq, void *dev_id)
if (status & host->mask1_reg)
mmci_pio_irq(irq, dev_id);
- status &= ~MCI_IRQ1MASK;
+ status &= ~host->variant->irq_pio_mask;
}
/*
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index a2bf8bc..b91b130 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -186,7 +186,7 @@
MCI_CMDRESPENDMASK | MCI_CMDSENTMASK)
/* These interrupts are directed to IRQ1 when two IRQ lines are available */
-#define MCI_IRQ1MASK \
+#define MCI_IRQ_PIO_MASK \
(MCI_RXFIFOHALFFULLMASK | MCI_RXDATAAVLBLMASK | \
MCI_TXFIFOHALFEMPTYMASK)
@@ -275,6 +275,8 @@ struct mmci_host;
* @qcom_dml: enables qcom specific dma glue for dma transfers.
* @reversed_irq_handling: handle data irq before cmd irq.
* @mmcimask1: true if variant have a MMCIMASK1 register.
+ * @irq_pio_mask: bitmask used to manage interrupt pio transfert in mmcimask
+ * register
* @start_err: bitmask identifying the STARTBITERR bit inside MMCISTATUS
* register.
* @opendrain: bitmask identifying the OPENDRAIN bit inside MMCIPOWER register
@@ -317,6 +319,7 @@ struct variant_data {
bool qcom_dml;
bool reversed_irq_handling;
bool mmcimask1;
+ unsigned int irq_pio_mask;
u32 start_err;
u32 opendrain;
struct mmci_dma_ops *mmci_dma;
--
2.7.4
^ permalink raw reply related
* [PATCH 09/19] mmc: mmci: add variant property to write datactrl before command
From: Ludovic Barre @ 2018-06-12 13:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1528809280-31116-1-git-send-email-ludovic.Barre@st.com>
From: Ludovic Barre <ludovic.barre@st.com>
This patch adds a boolean property to allow to write datactrl
before to send command, whatever the command type (read or write).
Needed to support the STM32 sdmmc variant.
Signed-off-by: Ludovic Barre <ludovic.barre@st.com>
---
drivers/mmc/host/mmci.c | 6 ++++--
drivers/mmc/host/mmci.h | 2 ++
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 5fd3ffb6..83c3572 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -855,7 +855,8 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
mmci_request_end(host, host->mrq);
} else if (sbc) {
mmci_start_command(host, host->mrq->cmd, 0);
- } else if (!(cmd->data->flags & MMC_DATA_READ)) {
+ } else if (!host->variant->datactrl_first &&
+ !(cmd->data->flags & MMC_DATA_READ)) {
mmci_start_data(host, cmd->data);
}
}
@@ -1119,7 +1120,8 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
if (mrq->data)
mmci_dma_get_next_data(host, mrq->data);
- if (mrq->data && mrq->data->flags & MMC_DATA_READ)
+ if (mrq->data &&
+ (host->variant->datactrl_first || mrq->data->flags & MMC_DATA_READ))
mmci_start_data(host, mrq->data);
if (mrq->sbc)
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index b91b130..5091025 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -259,6 +259,7 @@ struct mmci_host;
* @datactrl_mask_sdio: SDIO enable mask in datactrl register
* @datactrl_blksz: block size in power of two
* @datactrl_dpsm_enable: enable value for DPSM
+ * @datactrl_first: true if data must be setup before send command
* @pwrreg_powerup: power up value for MMCIPOWER register
* @f_max: maximum clk frequency supported by the controller.
* @signal_direction: input/out direction of bus signals can be indicated
@@ -301,6 +302,7 @@ struct variant_data {
unsigned int datactrl_mask_sdio;
unsigned int datactrl_blocksz;
unsigned int datactrl_dpsm_enable;
+ bool datactrl_first;
bool st_sdio;
bool st_clkdiv;
bool blksz_datactrl16;
--
2.7.4
^ permalink raw reply related
* [PATCH 10/19] mmc: mmci: add variant property to allow remain data
From: Ludovic Barre @ 2018-06-12 13:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1528809280-31116-1-git-send-email-ludovic.Barre@st.com>
From: Ludovic Barre <ludovic.barre@st.com>
This patch adds a boolean property to read remaining data.
Needed to support the STM32 sdmmc variant. MMCIDATACNT
register should be read only after the data transfer is complete.
When reading after an error event the read data count value may be
different from the real number of data bytes transferred.
Signed-off-by: Ludovic Barre <ludovic.barre@st.com>
---
drivers/mmc/host/mmci.c | 17 +++++++++++++++--
drivers/mmc/host/mmci.h | 3 +++
2 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 83c3572..abddad7 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -58,6 +58,7 @@ static struct variant_data variant_arm = {
.datalength_bits = 16,
.datactrl_blocksz = 11,
.datactrl_dpsm_enable = MCI_DPSM_ENABLE,
+ .datacnt_remain = true,
.pwrreg_powerup = MCI_PWR_UP,
.f_max = 100000000,
.reversed_irq_handling = true,
@@ -78,6 +79,7 @@ static struct variant_data variant_arm_extended_fifo = {
.datalength_bits = 16,
.datactrl_blocksz = 11,
.datactrl_dpsm_enable = MCI_DPSM_ENABLE,
+ .datacnt_remain = true,
.pwrreg_powerup = MCI_PWR_UP,
.f_max = 100000000,
.mmcimask1 = true,
@@ -98,6 +100,7 @@ static struct variant_data variant_arm_extended_fifo_hwfc = {
.datalength_bits = 16,
.datactrl_blocksz = 11,
.datactrl_dpsm_enable = MCI_DPSM_ENABLE,
+ .datacnt_remain = true,
.pwrreg_powerup = MCI_PWR_UP,
.f_max = 100000000,
.mmcimask1 = true,
@@ -120,6 +123,7 @@ static struct variant_data variant_u300 = {
.datactrl_blocksz = 11,
.datactrl_dpsm_enable = MCI_DPSM_ENABLE,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
+ .datacnt_remain = true,
.st_sdio = true,
.pwrreg_powerup = MCI_PWR_ON,
.f_max = 100000000,
@@ -146,6 +150,7 @@ static struct variant_data variant_nomadik = {
.datactrl_blocksz = 11,
.datactrl_dpsm_enable = MCI_DPSM_ENABLE,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
+ .datacnt_remain = true,
.st_sdio = true,
.st_clkdiv = true,
.pwrreg_powerup = MCI_PWR_ON,
@@ -175,6 +180,7 @@ static struct variant_data variant_ux500 = {
.datactrl_blocksz = 11,
.datactrl_dpsm_enable = MCI_DPSM_ENABLE,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
+ .datacnt_remain = true,
.st_sdio = true,
.st_clkdiv = true,
.pwrreg_powerup = MCI_PWR_ON,
@@ -209,6 +215,7 @@ static struct variant_data variant_ux500v2 = {
.datactrl_blocksz = 11,
.datactrl_dpsm_enable = MCI_DPSM_ENABLE,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
+ .datacnt_remain = true,
.st_sdio = true,
.st_clkdiv = true,
.blksz_datactrl16 = true,
@@ -244,6 +251,7 @@ static struct variant_data variant_stm32 = {
.datactrl_blocksz = 11,
.datactrl_dpsm_enable = MCI_DPSM_ENABLE,
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
+ .datacnt_remain = true,
.st_sdio = true,
.st_clkdiv = true,
.pwrreg_powerup = MCI_PWR_ON,
@@ -270,6 +278,7 @@ static struct variant_data variant_qcom = {
.datalength_bits = 24,
.datactrl_blocksz = 11,
.datactrl_dpsm_enable = MCI_DPSM_ENABLE,
+ .datacnt_remain = true,
.pwrreg_powerup = MCI_PWR_UP,
.f_max = 208000000,
.explicit_mclk_control = true,
@@ -711,8 +720,12 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
* can be as much as a FIFO-worth of data ahead. This
* matters for FIFO overruns only.
*/
- remain = readl(host->base + MMCIDATACNT);
- success = data->blksz * data->blocks - remain;
+ if (host->variant->datacnt_remain) {
+ remain = readl(host->base + MMCIDATACNT);
+ success = data->blksz * data->blocks - remain;
+ } else {
+ success = 0;
+ }
dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ, status 0x%08x at 0x%08x\n",
status_err, success);
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index 5091025..12ee2e6 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -260,6 +260,8 @@ struct mmci_host;
* @datactrl_blksz: block size in power of two
* @datactrl_dpsm_enable: enable value for DPSM
* @datactrl_first: true if data must be setup before send command
+ * @datacnt_remain: true if you could read datacnt register
+ * to define remain data
* @pwrreg_powerup: power up value for MMCIPOWER register
* @f_max: maximum clk frequency supported by the controller.
* @signal_direction: input/out direction of bus signals can be indicated
@@ -303,6 +305,7 @@ struct variant_data {
unsigned int datactrl_blocksz;
unsigned int datactrl_dpsm_enable;
bool datactrl_first;
+ bool datacnt_remain;
bool st_sdio;
bool st_clkdiv;
bool blksz_datactrl16;
--
2.7.4
^ permalink raw reply related
* [PATCH 11/19] mmc: mmci: add variant property to check specific data constraint
From: Ludovic Barre @ 2018-06-12 13:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1528809280-31116-1-git-send-email-ludovic.Barre@st.com>
From: Ludovic Barre <ludovic.barre@st.com>
This patch adds a function pointer to check specific data constraint
follow hardware variant. Needed to support the STM32 sdmmc variant
which has alignment constraint.
Signed-off-by: Ludovic Barre <ludovic.barre@st.com>
---
drivers/mmc/host/mmci.c | 5 +++++
drivers/mmc/host/mmci.h | 2 ++
2 files changed, 7 insertions(+)
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index abddad7..9c00804 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -312,6 +312,8 @@ static int mmci_card_busy(struct mmc_host *mmc)
static int mmci_validate_data(struct mmci_host *host,
struct mmc_data *data)
{
+ struct variant_data *variant = host->variant;
+
if (!data)
return 0;
@@ -321,6 +323,9 @@ static int mmci_validate_data(struct mmci_host *host,
return -EINVAL;
}
+ if (variant->validate_data)
+ return variant->validate_data(host, data);
+
return 0;
}
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index 12ee2e6..30d3f53 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -284,6 +284,7 @@ struct mmci_host;
* register.
* @opendrain: bitmask identifying the OPENDRAIN bit inside MMCIPOWER register
* @mmci_dma: Pointer to platform-specific DMA callbacks.
+ * @validate_data: if hardware block has specific constraint on validate data
* @set_clk_ios: if clock procedure of variant is specific
* @set_pwr_ios: if power procedure of variant is specific
*/
@@ -328,6 +329,7 @@ struct variant_data {
u32 start_err;
u32 opendrain;
struct mmci_dma_ops *mmci_dma;
+ int (*validate_data)(struct mmci_host *host, struct mmc_data *data);
void (*set_clkreg)(struct mmci_host *host, unsigned int desired);
void (*set_pwrreg)(struct mmci_host *host, unsigned char power_mode,
unsigned int pwr);
--
2.7.4
^ permalink raw reply related
* [PATCH 12/19] mmc: mmci: add variant property to request a reset
From: Ludovic Barre @ 2018-06-12 13:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1528809280-31116-1-git-send-email-ludovic.Barre@st.com>
From: Ludovic Barre <ludovic.barre@st.com>
Some variants could require a reset.
STM32 sdmmc variant needs to reset hardware block
during the power cycle procedure (for re-initialization)
Signed-off-by: Ludovic Barre <ludovic.barre@st.com>
---
Documentation/devicetree/bindings/mmc/mmci.txt | 2 ++
drivers/mmc/host/mmci.c | 9 +++++++++
drivers/mmc/host/mmci.h | 4 ++++
3 files changed, 15 insertions(+)
diff --git a/Documentation/devicetree/bindings/mmc/mmci.txt b/Documentation/devicetree/bindings/mmc/mmci.txt
index 03796cf..e952707 100644
--- a/Documentation/devicetree/bindings/mmc/mmci.txt
+++ b/Documentation/devicetree/bindings/mmc/mmci.txt
@@ -11,6 +11,8 @@ Required properties:
- compatible : contains "arm,pl18x", "arm,primecell".
- vmmc-supply : phandle to the regulator device tree node, mentioned
as the VCC/VDD supply in the eMMC/SD specs.
+depend of variant:
+- resets : phandle to internal reset line.
Optional properties:
- arm,primecell-periphid : contains the PrimeCell Peripheral ID, it overrides
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 9c00804..87724e1 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -37,6 +37,7 @@
#include <linux/pm_runtime.h>
#include <linux/types.h>
#include <linux/pinctrl/consumer.h>
+#include <linux/reset.h>
#include <asm/div64.h>
#include <asm/io.h>
@@ -1445,6 +1446,14 @@ static int mmci_probe(struct amba_device *dev,
dev_dbg(mmc_dev(mmc), "clocking block at %u Hz\n", mmc->f_max);
+ if (variant->reset) {
+ host->rst = devm_reset_control_get_exclusive(&dev->dev, NULL);
+ if (IS_ERR(host->rst)) {
+ ret = PTR_ERR(host->rst);
+ goto clk_disable;
+ }
+ }
+
/* Get regulators and the supported OCR mask */
ret = mmc_regulator_get_supply(mmc);
if (ret)
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index 30d3f53..2d7e901 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -284,6 +284,7 @@ struct mmci_host;
* register.
* @opendrain: bitmask identifying the OPENDRAIN bit inside MMCIPOWER register
* @mmci_dma: Pointer to platform-specific DMA callbacks.
+ * @reset: true if variant has need reset signal.
* @validate_data: if hardware block has specific constraint on validate data
* @set_clk_ios: if clock procedure of variant is specific
* @set_pwr_ios: if power procedure of variant is specific
@@ -329,6 +330,7 @@ struct variant_data {
u32 start_err;
u32 opendrain;
struct mmci_dma_ops *mmci_dma;
+ bool reset;
int (*validate_data)(struct mmci_host *host, struct mmc_data *data);
void (*set_clkreg)(struct mmci_host *host, unsigned int desired);
void (*set_pwrreg)(struct mmci_host *host, unsigned char power_mode,
@@ -345,6 +347,8 @@ struct mmci_host {
struct clk *clk;
bool singleirq;
+ struct reset_control *rst;
+
spinlock_t lock;
unsigned int mclk;
--
2.7.4
^ permalink raw reply related
* [PATCH 13/19] mmc: mmci: send stop cmd if a data command fail
From: Ludovic Barre @ 2018-06-12 13:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1528809280-31116-1-git-send-email-ludovic.Barre@st.com>
From: Ludovic Barre <ludovic.barre@st.com>
The mmc framework follows the requirement of SD_Specification:
the STOP_TRANSMISSION is sent on multiple write/read commands
and the stop command (alone), not needed on other ADTC commands.
But, some variants require a stop command "STOP_TRANSMISION" to clear
the DPSM "Data Path State Machine" if an error happens on command or data
step. If it's not done the next data command will freeze hardware block.
Needed to support the STM32 sdmmc variant.
Signed-off-by: Ludovic Barre <ludovic.barre@st.com>
---
drivers/mmc/host/mmci.c | 36 +++++++++++++++++++++++++++++++-----
drivers/mmc/host/mmci.h | 3 +++
2 files changed, 34 insertions(+), 5 deletions(-)
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 87724e1..9af7db8 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -24,6 +24,7 @@
#include <linux/mmc/pm.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/amba/bus.h>
#include <linux/clk.h>
@@ -522,11 +523,28 @@ static void mmci_set_mask1(struct mmci_host *host, unsigned int mask)
host->mask1_reg = mask;
}
-static void mmci_stop_data(struct mmci_host *host)
+static int mmci_stop_data(struct mmci_host *host)
{
+ struct mmc_command *stop = &host->stop_abort;
+ struct mmc_data *data = host->data;
+ unsigned int cmd = 0;
+
mmci_write_datactrlreg(host, 0);
mmci_set_mask1(host, 0);
host->data = NULL;
+
+ if (host->variant->cmdreg_stop) {
+ cmd |= host->variant->cmdreg_stop;
+ if (!data->stop) {
+ memset(stop, 0, sizeof(struct mmc_command));
+ stop->opcode = MMC_STOP_TRANSMISSION;
+ stop->arg = 0;
+ stop->flags = MMC_RSP_R1B | MMC_CMD_AC;
+ data->stop = stop;
+ }
+ }
+
+ return cmd;
}
static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data)
@@ -703,6 +721,7 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
unsigned int status)
{
unsigned int status_err;
+ unsigned int cmd_reg = 0;
/* Make sure we have data to handle */
if (!data)
@@ -761,7 +780,7 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
if (status & MCI_DATAEND || data->error) {
mmci_dma_finalize(host, data);
- mmci_stop_data(host);
+ cmd_reg = mmci_stop_data(host);
if (!data->error)
/* The error clause is handled above, success! */
@@ -770,7 +789,7 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
if (!data->stop || host->mrq->sbc) {
mmci_request_end(host, data->mrq);
} else {
- mmci_start_command(host, data->stop, 0);
+ mmci_start_command(host, data->stop, cmd_reg);
}
}
}
@@ -780,6 +799,8 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
unsigned int status)
{
void __iomem *base = host->base;
+ struct mmc_data *data = host->data;
+ unsigned int cmd_reg = 0;
bool sbc;
if (!cmd)
@@ -865,11 +886,16 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
}
if ((!sbc && !cmd->data) || cmd->error) {
- if (host->data) {
+ if (data) {
/* Terminate the DMA transfer */
mmci_dma_error(host);
- mmci_stop_data(host);
+ cmd_reg = mmci_stop_data(host);
+
+ if (data->stop) {
+ mmci_start_command(host, data->stop, cmd_reg);
+ return;
+ }
}
mmci_request_end(host, host->mrq);
} else if (sbc) {
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index 2d7e901..4b4cd1d 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -243,6 +243,7 @@ struct mmci_host;
* @cmdreg_lrsp_crc: enable value for long response with crc
* @cmdreg_srsp_crc: enable value for short response with crc
* @cmdreg_srsp: enable value for short response without crc
+ * @cmdreg_stop: enable value for stop and abort transmission
* @datalength_bits: number of bits in the MMCIDATALENGTH register
* @fifosize: number of bytes that can be written when MMCI_TXFIFOEMPTY
* is asserted (likewise for RX)
@@ -298,6 +299,7 @@ struct variant_data {
unsigned int cmdreg_lrsp_crc;
unsigned int cmdreg_srsp_crc;
unsigned int cmdreg_srsp;
+ unsigned int cmdreg_stop;
unsigned int datalength_bits;
unsigned int fifosize;
unsigned int fifohalfsize;
@@ -343,6 +345,7 @@ struct mmci_host {
struct mmc_request *mrq;
struct mmc_command *cmd;
struct mmc_data *data;
+ struct mmc_command stop_abort;
struct mmc_host *mmc;
struct clk *clk;
bool singleirq;
--
2.7.4
^ permalink raw reply related
* [PATCH 14/19] mmc: mmci: add clock divider for stm32 sdmmc
From: Ludovic Barre @ 2018-06-12 13:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1528809280-31116-1-git-send-email-ludovic.Barre@st.com>
From: Ludovic Barre <ludovic.barre@st.com>
The STM32 sdmmc variant has a different clock divider.
Signed-off-by: Ludovic Barre <ludovic.barre@st.com>
---
drivers/mmc/host/mmci.c | 2 ++
drivers/mmc/host/mmci.h | 2 ++
2 files changed, 4 insertions(+)
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 9af7db8..e24fd1e 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -1451,6 +1451,8 @@ static int mmci_probe(struct amba_device *dev,
*/
if (variant->st_clkdiv)
mmc->f_min = DIV_ROUND_UP(host->mclk, 257);
+ else if (variant->stm32_clkdiv)
+ mmc->f_min = DIV_ROUND_UP(host->mclk, 2046);
else if (variant->explicit_mclk_control)
mmc->f_min = clk_round_rate(host->clk, 100000);
else
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index 4b4cd1d..227927e 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -252,6 +252,7 @@ struct mmci_host;
* @data_cmd_enable: enable value for data commands.
* @st_sdio: enable ST specific SDIO logic
* @st_clkdiv: true if using a ST-specific clock divider algorithm
+ * @stm32_clkdiv: true if using a STM32-specific clock divider algorithm
* @datactrl_mask_ddrmode: ddr mode mask in datactrl register.
* @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl
* register
@@ -312,6 +313,7 @@ struct variant_data {
bool datacnt_remain;
bool st_sdio;
bool st_clkdiv;
+ bool stm32_clkdiv;
bool blksz_datactrl16;
bool blksz_datactrl4;
u32 pwrreg_powerup;
--
2.7.4
^ permalink raw reply related
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