* [Qemu-devel] [PATCH for-2.10] Revert "block/io: Comment out permission assertions"
From: Max Reitz @ 2017-04-11 15:52 UTC (permalink / raw)
To: qemu-block; +Cc: qemu-devel, Max Reitz, Kevin Wolf, Stefan Hajnoczi, Fam Zheng
This reverts commit e3e0003a8f6570aba1421ef99a0b383a43371a74.
This commit was necessary for the 2.9 release because we were unable to
fix the underlying issue(s) in time. However, we will be for 2.10.
Signed-off-by: Max Reitz <mreitz@redhat.com>
---
block.c | 6 +-----
block/io.c | 12 ++----------
2 files changed, 3 insertions(+), 15 deletions(-)
diff --git a/block.c b/block.c
index 1fbbb8d606..086a12df97 100644
--- a/block.c
+++ b/block.c
@@ -3274,11 +3274,7 @@ int bdrv_truncate(BdrvChild *child, int64_t offset)
BlockDriver *drv = bs->drv;
int ret;
- /* FIXME: Some format block drivers use this function instead of implicitly
- * growing their file by writing beyond its end.
- * See bdrv_aligned_pwritev() for an explanation why we currently
- * cannot assert this permission in that case. */
- // assert(child->perm & BLK_PERM_RESIZE);
+ assert(child->perm & BLK_PERM_RESIZE);
if (!drv)
return -ENOMEDIUM;
diff --git a/block/io.c b/block/io.c
index 8706bfa578..bae6947032 100644
--- a/block/io.c
+++ b/block/io.c
@@ -1345,16 +1345,8 @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
assert(!waited || !req->serialising);
assert(req->overlap_offset <= offset);
assert(offset + bytes <= req->overlap_offset + req->overlap_bytes);
- /* FIXME: Block migration uses the BlockBackend of the guest device at a
- * point when it has not yet taken write permissions. This will be
- * fixed by a future patch, but for now we have to bypass this
- * assertion for block migration to work. */
- // assert(child->perm & BLK_PERM_WRITE);
- /* FIXME: Because of the above, we also cannot guarantee that all format
- * BDS take the BLK_PERM_RESIZE permission on their file BDS, since
- * they are not obligated to do so if they do not have any parent
- * that has taken the permission to write to them. */
- // assert(end_sector <= bs->total_sectors || child->perm & BLK_PERM_RESIZE);
+ assert(child->perm & BLK_PERM_WRITE);
+ assert(end_sector <= bs->total_sectors || child->perm & BLK_PERM_RESIZE);
ret = notifier_with_return_list_notify(&bs->before_write_notifiers, req);
--
2.12.2
^ permalink raw reply related
* [Intel-wired-lan] [PATCH 2/3] ixgbe: Add X552 XFI backplane support
From: Singh, Krishneil K @ 2017-04-11 15:52 UTC (permalink / raw)
To: intel-wired-lan
In-Reply-To: <1483150078-35175-1-git-send-email-donald.c.skidmore@intel.com>
-----Original Message-----
From: Intel-wired-lan [mailto:intel-wired-lan-bounces at lists.osuosl.org] On Behalf Of Donald C Skidmore
Sent: Friday, December 30, 2016 6:08 PM
To: intel-wired-lan@lists.osuosl.org
Subject: [Intel-wired-lan] [PATCH 2/3] ixgbe: Add X552 XFI backplane support
This patch add support for X552 XFI backplane interface. The XFI backplane requires a custom tuned link. HW/FW owns the link config for XF backplane and SW must not interfere with it.
Signed-off-by: Don Skidmore <donald.c.skidmore@intel.com>
---
Tested-by: Krishneil Singh <krishneil.k.singh@intel.com>
^ permalink raw reply
* [PATCH v4 1/2] ASoC: stm32: add bindings for SAI
From: olivier moysan @ 2017-04-11 15:47 UTC (permalink / raw)
To: lgirdwood, broonie, perex, tiwai, mcoquelin.stm32,
alexandre.torgue, alsa-devel, robh, mark.rutland, devicetree,
linux-arm-kernel, kernel, linux-kernel, olivier.moysan
Cc: arnaud.pouliquen, benjamin.gaignard
In-Reply-To: <1491925646-29113-1-git-send-email-olivier.moysan@st.com>
This patch adds documentation of device tree bindings for the
STM32 SAI ASoC driver.
Signed-off-by: olivier moysan <olivier.moysan@st.com>
---
.../devicetree/bindings/sound/st,stm32-sai.txt | 89 ++++++++++++++++++++++
1 file changed, 89 insertions(+)
create mode 100644 Documentation/devicetree/bindings/sound/st,stm32-sai.txt
diff --git a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt
new file mode 100644
index 0000000..c59a3d7
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt
@@ -0,0 +1,89 @@
+STMicroelectronics STM32 Serial Audio Interface (SAI).
+
+The SAI interface (Serial Audio Interface) offers a wide set of audio protocols
+as I2S standards, LSB or MSB-justified, PCM/DSP, TDM, and AC'97.
+The SAI contains two independent audio sub-blocks. Each sub-block has
+its own clock generator and I/O lines controller.
+
+Required properties:
+ - compatible: Should be "st,stm32f4-sai"
+ - reg: Base address and size of SAI common register set.
+ - clocks: Must contain phandle and clock specifier pairs for each entry
+ in clock-names.
+ - clock-names: Must contain "x8k" and "x11k"
+ "x8k": SAI parent clock for sampling rates multiple of 8kHz.
+ "x11k": SAI parent clock for sampling rates multiple of 11.025kHz.
+ - interrupts: cpu DAI interrupt line shared by SAI sub-blocks
+
+Optional properties:
+ - resets: Reference to a reset controller asserting the SAI
+
+SAI subnodes:
+Two subnodes corresponding to SAI sub-block instances A et B can be defined.
+Subnode can be omitted for unsused sub-block.
+
+SAI subnodes required properties:
+ - compatible: Should be "st,stm32-sai-sub-a" or "st,stm32-sai-sub-b"
+ for SAI sub-block A or B respectively.
+ - reg: Base address and size of SAI sub-block register set.
+ - clocks: Must contain one phandle and clock specifier pair
+ for sai_ck which feeds the internal clock generator.
+ - clock-names: Must contain "sai_ck".
+ - dmas: see Documentation/devicetree/bindings/dma/stm32-dma.txt
+ - dma-names: identifier string for each DMA request line
+ "tx": if sai sub-block is configured as playback DAI
+ "rx": if sai sub-block is configured as capture DAI
+ - pinctrl-names: should contain only value "default"
+ - pinctrl-0: see Documentation/devicetree/bindings/pinctrl/pinctrl-stm32.txt
+
+Example:
+sound_card {
+ compatible = "audio-graph-card";
+ dais = <&sai1b_port>;
+};
+
+sai1: sai1@40015800 {
+ compatible = "st,stm32f4-sai";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ reg = <0x40015800 0x4>;
+ clocks = <&rcc 1 CLK_SAIQ_PDIV>, <&rcc 1 CLK_I2SQ_PDIV>;
+ clock-names = "x8k", "x11k";
+ interrupts = <87>;
+
+ sai1b: audio-controller@40015824 {
+ #sound-dai-cells = <0>;
+ compatible = "st,stm32-sai-sub-b";
+ reg = <0x40015824 0x1C>;
+ clocks = <&rcc 1 CLK_SAI2>;
+ clock-names = "sai_ck";
+ dmas = <&dma2 5 0 0x400 0x0>;
+ dma-names = "tx";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_sai1b>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sai1b_port: port@0 {
+ reg = <0>;
+ cpu_endpoint: endpoint {
+ remote-endpoint = <&codec_endpoint>;
+ audio-graph-card,format = "i2s";
+ audio-graph-card,bitclock-master = <&codec_endpoint>;
+ audio-graph-card,frame-master = <&codec_endpoint>;
+ };
+ };
+ };
+ };
+};
+
+audio-codec {
+ codec_port: port {
+ codec_endpoint: endpoint {
+ remote-endpoint = <&cpu_endpoint>;
+ };
+ };
+};
--
1.9.1
^ permalink raw reply related
* Re: [PATCH] drm: Document code of conduct
From: Alex Deucher @ 2017-04-11 15:50 UTC (permalink / raw)
To: Daniel Vetter
Cc: Keith Packard, Daniel Stone, Intel Graphics Development,
DRI Development, Daniel Vetter, Tollef Fog Heen
In-Reply-To: <20170411064815.5399-1-daniel.vetter@ffwll.ch>
On Tue, Apr 11, 2017 at 2:48 AM, Daniel Vetter <daniel.vetter@ffwll.ch> wrote:
> freedesktop.org has adopted a formal&enforced code of conduct:
>
> https://www.fooishbar.org/blog/fdo-contributor-covenant/
> https://www.freedesktop.org/wiki/CodeOfConduct/
>
> Besides formalizing things a bit more I don't think this changes
> anything for us, we've already peer-enforced respectful and
> constructive interactions since a long time. But it's good to document
> things properly.
>
> Note: As Daniel Stone mentioned in the announcement fd.o admins
> started chatting with the communities their hosting, which includs the
typos:
"they're" and "includes"
> X.org foundation board, to figure out how to fan out enforcement and
> allow projects to run things on their own (with fd.o still as the
> fallback). So the details of enforcement (and appealing decisions)
> might still change, but since this involves the board and lots more
> people it'll take a while to get there. For now this is good enough I
> think.
Might want to clarify this paragraph. This is a bit confusing for
those not following the discussions closely. I think there is too
much mixing of projects and hosting and foundations and all three
should be distinct. This patch proposes a CoC for the drm subsystem
of the kernel, not freedesktop, or Xorg or some other project and that
should be made clear.
Alex
>
> For the text itself I went with the same blurb as the Wayland project,
> didn't feel creative yet this early in the morning:
>
> https://cgit.freedesktop.org/wayland/wayland/commit/?id=0eefe99fe0683ae409b665a8b18cc7eb648c6c0c
>
> Cc: Daniel Stone <daniels@collabora.com>
> Cc: Keith Packard <keithp@keithp.com>
> Cc: tfheen@err.no
> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
> ---
> Documentation/gpu/introduction.rst | 11 +++++++++++
> 1 file changed, 11 insertions(+)
>
> diff --git a/Documentation/gpu/introduction.rst b/Documentation/gpu/introduction.rst
> index 05a82bdfbca4..0f5173e29bdc 100644
> --- a/Documentation/gpu/introduction.rst
> +++ b/Documentation/gpu/introduction.rst
> @@ -85,3 +85,14 @@ This means that there's a blackout-period of about one month where feature work
> can't be merged. The recommended way to deal with that is having a -next tree
> that's always open, but making sure to not feed it into linux-next during the
> blackout period. As an example, drm-misc works like that.
> +
> +Code of Conduct
> +---------------
> +
> +As a freedesktop.org project, dri-devel and the DRM community follows the
> +Contributor Covenant, found at: https://www.freedesktop.org/wiki/CodeOfConduct
> +
> +Please conduct yourself in a respectful and civilised manner when
> +interacting with community members on mailing lists, IRC, or bug
> +trackers. The community represents the project as a whole, and abusive
> +or bullying behaviour is not tolerated by the project.
> --
> 2.11.0
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply
* [PATCH v4 2/2] ASoC: stm32: add SAI driver
From: olivier moysan @ 2017-04-11 15:47 UTC (permalink / raw)
To: lgirdwood, broonie, perex, tiwai, mcoquelin.stm32,
alexandre.torgue, alsa-devel, robh, mark.rutland, devicetree,
linux-arm-kernel, kernel, linux-kernel, olivier.moysan
Cc: arnaud.pouliquen, benjamin.gaignard
In-Reply-To: <1491925646-29113-1-git-send-email-olivier.moysan@st.com>
This patch implements SAI ASoC driver for STM32.
Signed-off-by: olivier moysan <olivier.moysan@st.com>
---
sound/soc/Kconfig | 1 +
sound/soc/Makefile | 1 +
sound/soc/stm/Kconfig | 8 +
sound/soc/stm/Makefile | 6 +
sound/soc/stm/stm32_sai.c | 115 ++++++
sound/soc/stm/stm32_sai.h | 199 ++++++++++
sound/soc/stm/stm32_sai_sub.c | 881 ++++++++++++++++++++++++++++++++++++++++++
7 files changed, 1211 insertions(+)
create mode 100644 sound/soc/stm/Kconfig
create mode 100644 sound/soc/stm/Makefile
create mode 100644 sound/soc/stm/stm32_sai.c
create mode 100644 sound/soc/stm/stm32_sai.h
create mode 100644 sound/soc/stm/stm32_sai_sub.c
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 9df9658..c0abad2 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -64,6 +64,7 @@ source "sound/soc/sh/Kconfig"
source "sound/soc/sirf/Kconfig"
source "sound/soc/spear/Kconfig"
source "sound/soc/sti/Kconfig"
+source "sound/soc/stm/Kconfig"
source "sound/soc/sunxi/Kconfig"
source "sound/soc/tegra/Kconfig"
source "sound/soc/txx9/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 2f6aabb..39c27a5 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_SND_SOC) += sh/
obj-$(CONFIG_SND_SOC) += sirf/
obj-$(CONFIG_SND_SOC) += spear/
obj-$(CONFIG_SND_SOC) += sti/
+obj-$(CONFIG_SND_SOC) += stm/
obj-$(CONFIG_SND_SOC) += sunxi/
obj-$(CONFIG_SND_SOC) += tegra/
obj-$(CONFIG_SND_SOC) += txx9/
diff --git a/sound/soc/stm/Kconfig b/sound/soc/stm/Kconfig
new file mode 100644
index 0000000..a6372de
--- /dev/null
+++ b/sound/soc/stm/Kconfig
@@ -0,0 +1,8 @@
+menuconfig SND_SOC_STM32
+ tristate "STMicroelectronics STM32 SOC audio support"
+ depends on ARCH_STM32 || COMPILE_TEST
+ depends on SND_SOC
+ select SND_SOC_GENERIC_DMAENGINE_PCM
+ select REGMAP_MMIO
+ help
+ Say Y if you want to enable ASoC support for STM32
diff --git a/sound/soc/stm/Makefile b/sound/soc/stm/Makefile
new file mode 100644
index 0000000..e466a47
--- /dev/null
+++ b/sound/soc/stm/Makefile
@@ -0,0 +1,6 @@
+# SAI
+snd-soc-stm32-sai-sub-objs := stm32_sai_sub.o
+obj-$(CONFIG_SND_SOC_STM32) += snd-soc-stm32-sai-sub.o
+
+snd-soc-stm32-sai-objs := stm32_sai.o
+obj-$(CONFIG_SND_SOC_STM32) += snd-soc-stm32-sai.o
diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c
new file mode 100644
index 0000000..6159d66
--- /dev/null
+++ b/sound/soc/stm/stm32_sai.c
@@ -0,0 +1,115 @@
+/*
+ * STM32 ALSA SoC Digital Audio Interface (SAI) driver.
+ *
+ * Copyright (C) 2016, STMicroelectronics - All Rights Reserved
+ * Author(s): Olivier Moysan <olivier.moysan@st.com> for STMicroelectronics.
+ *
+ * License terms: GPL V2.0.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed 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/clk.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/reset.h>
+
+#include <sound/dmaengine_pcm.h>
+#include <sound/core.h>
+
+#include "stm32_sai.h"
+
+static const struct of_device_id stm32_sai_ids[] = {
+ { .compatible = "st,stm32f4-sai", .data = (void *)SAI_STM32F4 },
+ {}
+};
+
+static int stm32_sai_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct stm32_sai_data *sai;
+ struct reset_control *rst;
+ struct resource *res;
+ void __iomem *base;
+ const struct of_device_id *of_id;
+
+ sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
+ if (!sai)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ of_id = of_match_device(stm32_sai_ids, &pdev->dev);
+ if (of_id)
+ sai->version = (enum stm32_sai_version)of_id->data;
+ else
+ return -EINVAL;
+
+ sai->clk_x8k = devm_clk_get(&pdev->dev, "x8k");
+ if (IS_ERR(sai->clk_x8k)) {
+ dev_err(&pdev->dev, "missing x8k parent clock\n");
+ return PTR_ERR(sai->clk_x8k);
+ }
+
+ sai->clk_x11k = devm_clk_get(&pdev->dev, "x11k");
+ if (IS_ERR(sai->clk_x11k)) {
+ dev_err(&pdev->dev, "missing x11k parent clock\n");
+ return PTR_ERR(sai->clk_x11k);
+ }
+
+ /* init irqs */
+ sai->irq = platform_get_irq(pdev, 0);
+ if (sai->irq < 0) {
+ dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
+ return sai->irq;
+ }
+
+ /* reset */
+ rst = reset_control_get(&pdev->dev, NULL);
+ if (!IS_ERR(rst)) {
+ reset_control_assert(rst);
+ udelay(2);
+ reset_control_deassert(rst);
+ }
+
+ sai->pdev = pdev;
+ platform_set_drvdata(pdev, sai);
+
+ return of_platform_populate(np, NULL, NULL, &pdev->dev);
+}
+
+static int stm32_sai_remove(struct platform_device *pdev)
+{
+ of_platform_depopulate(&pdev->dev);
+
+ return 0;
+}
+
+MODULE_DEVICE_TABLE(of, stm32_sai_ids);
+
+static struct platform_driver stm32_sai_driver = {
+ .driver = {
+ .name = "st,stm32-sai",
+ .of_match_table = stm32_sai_ids,
+ },
+ .probe = stm32_sai_probe,
+ .remove = stm32_sai_remove,
+};
+
+module_platform_driver(stm32_sai_driver);
+
+MODULE_DESCRIPTION("STM32 Soc SAI Interface");
+MODULE_AUTHOR("Olivier Moysan <olivier.moysan@st.com>");
+MODULE_ALIAS("platform:st,stm32-sai");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/stm/stm32_sai.h b/sound/soc/stm/stm32_sai.h
new file mode 100644
index 0000000..270be93
--- /dev/null
+++ b/sound/soc/stm/stm32_sai.h
@@ -0,0 +1,199 @@
+/*
+ * STM32 ALSA SoC Digital Audio Interface (SAI) driver.
+ *
+ * Copyright (C) 2016, STMicroelectronics - All Rights Reserved
+ * Author(s): Olivier Moysan <olivier.moysan@st.com> for STMicroelectronics.
+ *
+ * License terms: GPL V2.0.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed 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.
+ */
+
+/******************** SAI Register Map **************************************/
+
+/* common register */
+#define STM_SAI_GCR 0x00
+
+/* Sub-block A&B registers offsets, relative to A&B sub-block addresses */
+#define STM_SAI_CR1_REGX 0x00 /* A offset: 0x04. B offset: 0x24 */
+#define STM_SAI_CR2_REGX 0x04
+#define STM_SAI_FRCR_REGX 0x08
+#define STM_SAI_SLOTR_REGX 0x0C
+#define STM_SAI_IMR_REGX 0x10
+#define STM_SAI_SR_REGX 0x14
+#define STM_SAI_CLRFR_REGX 0x18
+#define STM_SAI_DR_REGX 0x1C
+
+/******************** Bit definition for SAI_GCR register *******************/
+#define SAI_GCR_SYNCIN_SHIFT 0
+#define SAI_GCR_SYNCIN_MASK GENMASK(1, SAI_GCR_SYNCIN_SHIFT)
+#define SAI_GCR_SYNCIN_SET(x) ((x) << SAI_GCR_SYNCIN_SHIFT)
+
+#define SAI_GCR_SYNCOUT_SHIFT 4
+#define SAI_GCR_SYNCOUT_MASK GENMASK(5, SAI_GCR_SYNCOUT_SHIFT)
+#define SAI_GCR_SYNCOUT_SET(x) ((x) << SAI_GCR_SYNCOUT_SHIFT)
+
+/******************* Bit definition for SAI_XCR1 register *******************/
+#define SAI_XCR1_RX_TX_SHIFT 0
+#define SAI_XCR1_RX_TX BIT(SAI_XCR1_RX_TX_SHIFT)
+#define SAI_XCR1_SLAVE_SHIFT 1
+#define SAI_XCR1_SLAVE BIT(SAI_XCR1_SLAVE_SHIFT)
+
+#define SAI_XCR1_PRTCFG_SHIFT 2
+#define SAI_XCR1_PRTCFG_MASK GENMASK(3, SAI_XCR1_PRTCFG_SHIFT)
+#define SAI_XCR1_PRTCFG_SET(x) ((x) << SAI_XCR1_PRTCFG_SHIFT)
+
+#define SAI_XCR1_DS_SHIFT 5
+#define SAI_XCR1_DS_MASK GENMASK(7, SAI_XCR1_DS_SHIFT)
+#define SAI_XCR1_DS_SET(x) ((x) << SAI_XCR1_DS_SHIFT)
+
+#define SAI_XCR1_LSBFIRST_SHIFT 8
+#define SAI_XCR1_LSBFIRST BIT(SAI_XCR1_LSBFIRST_SHIFT)
+#define SAI_XCR1_CKSTR_SHIFT 9
+#define SAI_XCR1_CKSTR BIT(SAI_XCR1_CKSTR_SHIFT)
+
+#define SAI_XCR1_SYNCEN_SHIFT 10
+#define SAI_XCR1_SYNCEN_MASK GENMASK(11, SAI_XCR1_SYNCEN_SHIFT)
+#define SAI_XCR1_SYNCEN_SET(x) ((x) << SAI_XCR1_SYNCEN_SHIFT)
+
+#define SAI_XCR1_MONO_SHIFT 12
+#define SAI_XCR1_MONO BIT(SAI_XCR1_MONO_SHIFT)
+#define SAI_XCR1_OUTDRIV_SHIFT 13
+#define SAI_XCR1_OUTDRIV BIT(SAI_XCR1_OUTDRIV_SHIFT)
+#define SAI_XCR1_SAIEN_SHIFT 16
+#define SAI_XCR1_SAIEN BIT(SAI_XCR1_SAIEN_SHIFT)
+#define SAI_XCR1_DMAEN_SHIFT 17
+#define SAI_XCR1_DMAEN BIT(SAI_XCR1_DMAEN_SHIFT)
+#define SAI_XCR1_NODIV_SHIFT 19
+#define SAI_XCR1_NODIV BIT(SAI_XCR1_NODIV_SHIFT)
+
+#define SAI_XCR1_MCKDIV_SHIFT 20
+#define SAI_XCR1_MCKDIV_WIDTH 4
+#define SAI_XCR1_MCKDIV_MASK GENMASK(24, SAI_XCR1_MCKDIV_SHIFT)
+#define SAI_XCR1_MCKDIV_SET(x) ((x) << SAI_XCR1_MCKDIV_SHIFT)
+#define SAI_XCR1_MCKDIV_MAX ((1 << SAI_XCR1_MCKDIV_WIDTH) - 1)
+
+#define SAI_XCR1_OSR_SHIFT 26
+#define SAI_XCR1_OSR BIT(SAI_XCR1_OSR_SHIFT)
+
+/******************* Bit definition for SAI_XCR2 register *******************/
+#define SAI_XCR2_FTH_SHIFT 0
+#define SAI_XCR2_FTH_MASK GENMASK(2, SAI_XCR2_FTH_SHIFT)
+#define SAI_XCR2_FTH_SET(x) ((x) << SAI_XCR2_FTH_SHIFT)
+
+#define SAI_XCR2_FFLUSH_SHIFT 3
+#define SAI_XCR2_FFLUSH BIT(SAI_XCR2_FFLUSH_SHIFT)
+#define SAI_XCR2_TRIS_SHIFT 4
+#define SAI_XCR2_TRIS BIT(SAI_XCR2_TRIS_SHIFT)
+#define SAI_XCR2_MUTE_SHIFT 5
+#define SAI_XCR2_MUTE BIT(SAI_XCR2_MUTE_SHIFT)
+#define SAI_XCR2_MUTEVAL_SHIFT 6
+#define SAI_XCR2_MUTEVAL BIT(SAI_XCR2_MUTEVAL_SHIFT)
+
+#define SAI_XCR2_MUTECNT_SHIFT 7
+#define SAI_XCR2_MUTECNT_MASK GENMASK(12, SAI_XCR2_MUTECNT_SHIFT)
+#define SAI_XCR2_MUTECNT_SET(x) ((x) << SAI_XCR2_MUTECNT_SHIFT)
+
+#define SAI_XCR2_CPL_SHIFT 13
+#define SAI_XCR2_CPL BIT(SAI_XCR2_CPL_SHIFT)
+
+#define SAI_XCR2_COMP_SHIFT 14
+#define SAI_XCR2_COMP_MASK GENMASK(15, SAI_XCR2_COMP_SHIFT)
+#define SAI_XCR2_COMP_SET(x) ((x) << SAI_XCR2_COMP_SHIFT)
+
+/****************** Bit definition for SAI_XFRCR register *******************/
+#define SAI_XFRCR_FRL_SHIFT 0
+#define SAI_XFRCR_FRL_MASK GENMASK(7, SAI_XFRCR_FRL_SHIFT)
+#define SAI_XFRCR_FRL_SET(x) ((x) << SAI_XFRCR_FRL_SHIFT)
+
+#define SAI_XFRCR_FSALL_SHIFT 8
+#define SAI_XFRCR_FSALL_MASK GENMASK(14, SAI_XFRCR_FSALL_SHIFT)
+#define SAI_XFRCR_FSALL_SET(x) ((x) << SAI_XFRCR_FSALL_SHIFT)
+
+#define SAI_XFRCR_FSDEF_SHIFT 16
+#define SAI_XFRCR_FSDEF BIT(SAI_XFRCR_FSDEF_SHIFT)
+#define SAI_XFRCR_FSPOL_SHIFT 17
+#define SAI_XFRCR_FSPOL BIT(SAI_XFRCR_FSPOL_SHIFT)
+#define SAI_XFRCR_FSOFF_SHIFT 18
+#define SAI_XFRCR_FSOFF BIT(SAI_XFRCR_FSOFF_SHIFT)
+
+/****************** Bit definition for SAI_XSLOTR register ******************/
+#define SAI_XSLOTR_FBOFF_SHIFT 0
+#define SAI_XSLOTR_FBOFF_MASK GENMASK(4, SAI_XSLOTR_FBOFF_SHIFT)
+#define SAI_XSLOTR_FBOFF_SET(x) ((x) << SAI_XSLOTR_FBOFF_SHIFT)
+
+#define SAI_XSLOTR_SLOTSZ_SHIFT 6
+#define SAI_XSLOTR_SLOTSZ_MASK GENMASK(7, SAI_XSLOTR_SLOTSZ_SHIFT)
+#define SAI_XSLOTR_SLOTSZ_SET(x) ((x) << SAI_XSLOTR_SLOTSZ_SHIFT)
+
+#define SAI_XSLOTR_NBSLOT_SHIFT 8
+#define SAI_XSLOTR_NBSLOT_MASK GENMASK(11, SAI_XSLOTR_NBSLOT_SHIFT)
+#define SAI_XSLOTR_NBSLOT_SET(x) ((x) << SAI_XSLOTR_NBSLOT_SHIFT)
+
+#define SAI_XSLOTR_SLOTEN_SHIFT 16
+#define SAI_XSLOTR_SLOTEN_WIDTH 16
+#define SAI_XSLOTR_SLOTEN_MASK GENMASK(31, SAI_XSLOTR_SLOTEN_SHIFT)
+#define SAI_XSLOTR_SLOTEN_SET(x) ((x) << SAI_XSLOTR_SLOTEN_SHIFT)
+
+/******************* Bit definition for SAI_XIMR register *******************/
+#define SAI_XIMR_OVRUDRIE BIT(0)
+#define SAI_XIMR_MUTEDETIE BIT(1)
+#define SAI_XIMR_WCKCFGIE BIT(2)
+#define SAI_XIMR_FREQIE BIT(3)
+#define SAI_XIMR_CNRDYIE BIT(4)
+#define SAI_XIMR_AFSDETIE BIT(5)
+#define SAI_XIMR_LFSDETIE BIT(6)
+
+#define SAI_XIMR_SHIFT 0
+#define SAI_XIMR_MASK GENMASK(6, SAI_XIMR_SHIFT)
+
+/******************** Bit definition for SAI_XSR register *******************/
+#define SAI_XSR_OVRUDR BIT(0)
+#define SAI_XSR_MUTEDET BIT(1)
+#define SAI_XSR_WCKCFG BIT(2)
+#define SAI_XSR_FREQ BIT(3)
+#define SAI_XSR_CNRDY BIT(4)
+#define SAI_XSR_AFSDET BIT(5)
+#define SAI_XSR_LFSDET BIT(6)
+
+#define SAI_XSR_SHIFT 0
+#define SAI_XSR_MASK GENMASK(6, SAI_XSR_SHIFT)
+
+/****************** Bit definition for SAI_XCLRFR register ******************/
+#define SAI_XCLRFR_COVRUDR BIT(0)
+#define SAI_XCLRFR_CMUTEDET BIT(1)
+#define SAI_XCLRFR_CWCKCFG BIT(2)
+#define SAI_XCLRFR_CFREQ BIT(3)
+#define SAI_XCLRFR_CCNRDY BIT(4)
+#define SAI_XCLRFR_CAFSDET BIT(5)
+#define SAI_XCLRFR_CLFSDET BIT(6)
+
+#define SAI_XCLRFR_SHIFT 0
+#define SAI_XCLRFR_MASK GENMASK(6, SAI_XCLRFR_SHIFT)
+
+enum stm32_sai_version {
+ SAI_STM32F4
+};
+
+/**
+ * struct stm32_sai_data - private data of SAI instance driver
+ * @pdev: device data pointer
+ * @clk_x8k: SAI parent clock for sampling frequencies multiple of 8kHz
+ * @clk_x11k: SAI parent clock for sampling frequencies multiple of 11kHz
+ * @version: SOC version
+ * @irq: SAI interrupt line
+ */
+struct stm32_sai_data {
+ struct platform_device *pdev;
+ struct clk *clk_x8k;
+ struct clk *clk_x11k;
+ int version;
+ int irq;
+};
diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
new file mode 100644
index 0000000..24b8874
--- /dev/null
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -0,0 +1,881 @@
+/*
+ * STM32 ALSA SoC Digital Audio Interface (SAI) driver.
+ *
+ * Copyright (C) 2016, STMicroelectronics - All Rights Reserved
+ * Author(s): Olivier Moysan <olivier.moysan@st.com> for STMicroelectronics.
+ *
+ * License terms: GPL V2.0.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed 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/clk.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+
+#include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/pcm_params.h>
+
+#include "stm32_sai.h"
+
+#define SAI_FREE_PROTOCOL 0x0
+
+#define SAI_SLOT_SIZE_AUTO 0x0
+#define SAI_SLOT_SIZE_16 0x1
+#define SAI_SLOT_SIZE_32 0x2
+
+#define SAI_DATASIZE_8 0x2
+#define SAI_DATASIZE_10 0x3
+#define SAI_DATASIZE_16 0x4
+#define SAI_DATASIZE_20 0x5
+#define SAI_DATASIZE_24 0x6
+#define SAI_DATASIZE_32 0x7
+
+#define STM_SAI_FIFO_SIZE 8
+#define STM_SAI_DAI_NAME_SIZE 15
+
+#define STM_SAI_IS_PLAYBACK(ip) ((ip)->dir == SNDRV_PCM_STREAM_PLAYBACK)
+#define STM_SAI_IS_CAPTURE(ip) ((ip)->dir == SNDRV_PCM_STREAM_CAPTURE)
+
+#define STM_SAI_A_ID 0x0
+#define STM_SAI_B_ID 0x1
+
+#define STM_SAI_BLOCK_NAME(x) (((x)->id == STM_SAI_A_ID) ? "A" : "B")
+
+/**
+ * struct stm32_sai_sub_data - private data of SAI sub block (block A or B)
+ * @pdev: device data pointer
+ * @regmap: SAI register map pointer
+ * @dma_params: dma configuration data for rx or tx channel
+ * @cpu_dai_drv: DAI driver data pointer
+ * @cpu_dai: DAI runtime data pointer
+ * @substream: PCM substream data pointer
+ * @pdata: SAI block parent data pointer
+ * @sai_ck: kernel clock feeding the SAI clock generator
+ * @phys_addr: SAI registers physical base address
+ * @mclk_rate: SAI block master clock frequency (Hz). set at init
+ * @id: SAI sub block id corresponding to sub-block A or B
+ * @dir: SAI block direction (playback or capture). set at init
+ * @master: SAI block mode flag. (true=master, false=slave) set at init
+ * @fmt: SAI block format. relevant only for custom protocols. set at init
+ * @sync: SAI block synchronization mode. (none, internal or external)
+ * @fs_length: frame synchronization length. depends on protocol settings
+ * @slots: rx or tx slot number
+ * @slot_width: rx or tx slot width in bits
+ * @slot_mask: rx or tx active slots mask. set at init or at runtime
+ * @data_size: PCM data width. corresponds to PCM substream width.
+ */
+struct stm32_sai_sub_data {
+ struct platform_device *pdev;
+ struct regmap *regmap;
+ struct snd_dmaengine_dai_dma_data dma_params;
+ struct snd_soc_dai_driver *cpu_dai_drv;
+ struct snd_soc_dai *cpu_dai;
+ struct snd_pcm_substream *substream;
+ struct stm32_sai_data *pdata;
+ struct clk *sai_ck;
+ dma_addr_t phys_addr;
+ unsigned int mclk_rate;
+ unsigned int id;
+ int dir;
+ bool master;
+ int fmt;
+ int sync;
+ int fs_length;
+ int slots;
+ int slot_width;
+ int slot_mask;
+ int data_size;
+};
+
+enum stm32_sai_fifo_th {
+ STM_SAI_FIFO_TH_EMPTY,
+ STM_SAI_FIFO_TH_QUARTER,
+ STM_SAI_FIFO_TH_HALF,
+ STM_SAI_FIFO_TH_3_QUARTER,
+ STM_SAI_FIFO_TH_FULL,
+};
+
+static bool stm32_sai_sub_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case STM_SAI_CR1_REGX:
+ case STM_SAI_CR2_REGX:
+ case STM_SAI_FRCR_REGX:
+ case STM_SAI_SLOTR_REGX:
+ case STM_SAI_IMR_REGX:
+ case STM_SAI_SR_REGX:
+ case STM_SAI_CLRFR_REGX:
+ case STM_SAI_DR_REGX:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool stm32_sai_sub_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case STM_SAI_DR_REGX:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool stm32_sai_sub_writeable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case STM_SAI_CR1_REGX:
+ case STM_SAI_CR2_REGX:
+ case STM_SAI_FRCR_REGX:
+ case STM_SAI_SLOTR_REGX:
+ case STM_SAI_IMR_REGX:
+ case STM_SAI_SR_REGX:
+ case STM_SAI_CLRFR_REGX:
+ case STM_SAI_DR_REGX:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config stm32_sai_sub_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = STM_SAI_DR_REGX,
+ .readable_reg = stm32_sai_sub_readable_reg,
+ .volatile_reg = stm32_sai_sub_volatile_reg,
+ .writeable_reg = stm32_sai_sub_writeable_reg,
+ .fast_io = true,
+};
+
+static irqreturn_t stm32_sai_isr(int irq, void *devid)
+{
+ struct stm32_sai_sub_data *sai = (struct stm32_sai_sub_data *)devid;
+ struct snd_pcm_substream *substream = sai->substream;
+ struct platform_device *pdev = sai->pdev;
+ unsigned int sr, imr, flags;
+ snd_pcm_state_t status = SNDRV_PCM_STATE_RUNNING;
+
+ regmap_read(sai->regmap, STM_SAI_IMR_REGX, &imr);
+ regmap_read(sai->regmap, STM_SAI_SR_REGX, &sr);
+
+ flags = sr & imr;
+ if (!flags)
+ return IRQ_NONE;
+
+ regmap_update_bits(sai->regmap, STM_SAI_CLRFR_REGX, SAI_XCLRFR_MASK,
+ SAI_XCLRFR_MASK);
+
+ if (flags & SAI_XIMR_OVRUDRIE) {
+ dev_err(&pdev->dev, "IRQ %s\n",
+ STM_SAI_IS_PLAYBACK(sai) ? "underrun" : "overrun");
+ status = SNDRV_PCM_STATE_XRUN;
+ }
+
+ if (flags & SAI_XIMR_MUTEDETIE)
+ dev_dbg(&pdev->dev, "IRQ mute detected\n");
+
+ if (flags & SAI_XIMR_WCKCFGIE) {
+ dev_err(&pdev->dev, "IRQ wrong clock configuration\n");
+ status = SNDRV_PCM_STATE_DISCONNECTED;
+ }
+
+ if (flags & SAI_XIMR_CNRDYIE)
+ dev_err(&pdev->dev, "IRQ Codec not ready\n");
+
+ if (flags & SAI_XIMR_AFSDETIE) {
+ dev_err(&pdev->dev, "IRQ Anticipated frame synchro\n");
+ status = SNDRV_PCM_STATE_XRUN;
+ }
+
+ if (flags & SAI_XIMR_LFSDETIE) {
+ dev_err(&pdev->dev, "IRQ Late frame synchro\n");
+ status = SNDRV_PCM_STATE_XRUN;
+ }
+
+ if (status != SNDRV_PCM_STATE_RUNNING) {
+ snd_pcm_stream_lock(substream);
+ snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+ snd_pcm_stream_unlock(substream);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int stm32_sai_set_sysclk(struct snd_soc_dai *cpu_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
+
+ if ((dir == SND_SOC_CLOCK_OUT) && sai->master) {
+ sai->mclk_rate = freq;
+ dev_dbg(cpu_dai->dev, "SAI MCLK frequency is %uHz\n", freq);
+ }
+
+ return 0;
+}
+
+static int stm32_sai_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask,
+ u32 rx_mask, int slots, int slot_width)
+{
+ struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ int slotr, slotr_mask, slot_size;
+
+ dev_dbg(cpu_dai->dev, "Masks tx/rx:%#x/%#x, slots:%d, width:%d\n",
+ tx_mask, rx_mask, slots, slot_width);
+
+ switch (slot_width) {
+ case 16:
+ slot_size = SAI_SLOT_SIZE_16;
+ break;
+ case 32:
+ slot_size = SAI_SLOT_SIZE_32;
+ break;
+ default:
+ slot_size = SAI_SLOT_SIZE_AUTO;
+ break;
+ }
+
+ slotr = SAI_XSLOTR_SLOTSZ_SET(slot_size) |
+ SAI_XSLOTR_NBSLOT_SET(slots - 1);
+ slotr_mask = SAI_XSLOTR_SLOTSZ_MASK | SAI_XSLOTR_NBSLOT_MASK;
+
+ /* tx/rx mask set in machine init, if slot number defined in DT */
+ if (STM_SAI_IS_PLAYBACK(sai)) {
+ sai->slot_mask = tx_mask;
+ slotr |= SAI_XSLOTR_SLOTEN_SET(tx_mask);
+ }
+
+ if (STM_SAI_IS_CAPTURE(sai)) {
+ sai->slot_mask = rx_mask;
+ slotr |= SAI_XSLOTR_SLOTEN_SET(rx_mask);
+ }
+
+ slotr_mask |= SAI_XSLOTR_SLOTEN_MASK;
+
+ regmap_update_bits(sai->regmap, STM_SAI_SLOTR_REGX, slotr_mask, slotr);
+
+ sai->slot_width = slot_width;
+ sai->slots = slots;
+
+ return 0;
+}
+
+static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
+{
+ struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ int cr1 = 0, frcr = 0;
+ int cr1_mask = 0, frcr_mask = 0;
+ int ret;
+
+ dev_dbg(cpu_dai->dev, "fmt %x\n", fmt);
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ /* SCK active high for all protocols */
+ case SND_SOC_DAIFMT_I2S:
+ cr1 |= SAI_XCR1_CKSTR;
+ frcr |= SAI_XFRCR_FSOFF | SAI_XFRCR_FSDEF;
+ break;
+ /* Left justified */
+ case SND_SOC_DAIFMT_MSB:
+ frcr |= SAI_XFRCR_FSPOL | SAI_XFRCR_FSDEF;
+ break;
+ /* Right justified */
+ case SND_SOC_DAIFMT_LSB:
+ frcr |= SAI_XFRCR_FSPOL | SAI_XFRCR_FSDEF;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ frcr |= SAI_XFRCR_FSPOL | SAI_XFRCR_FSOFF;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ frcr |= SAI_XFRCR_FSPOL;
+ break;
+ default:
+ dev_err(cpu_dai->dev, "Unsupported protocol %#x\n",
+ fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+ return -EINVAL;
+ }
+
+ cr1_mask |= SAI_XCR1_PRTCFG_MASK | SAI_XCR1_CKSTR;
+ frcr_mask |= SAI_XFRCR_FSPOL | SAI_XFRCR_FSOFF |
+ SAI_XFRCR_FSDEF;
+
+ /* DAI clock strobing. Invert setting previously set */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ cr1 ^= SAI_XCR1_CKSTR;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ frcr ^= SAI_XFRCR_FSPOL;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ /* Invert fs & sck */
+ cr1 ^= SAI_XCR1_CKSTR;
+ frcr ^= SAI_XFRCR_FSPOL;
+ break;
+ default:
+ dev_err(cpu_dai->dev, "Unsupported strobing %#x\n",
+ fmt & SND_SOC_DAIFMT_INV_MASK);
+ return -EINVAL;
+ }
+ cr1_mask |= SAI_XCR1_CKSTR;
+ frcr_mask |= SAI_XFRCR_FSPOL;
+
+ regmap_update_bits(sai->regmap, STM_SAI_FRCR_REGX, frcr_mask, frcr);
+
+ /* DAI clock master masks */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* codec is master */
+ cr1 |= SAI_XCR1_SLAVE;
+ sai->master = false;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ sai->master = true;
+ break;
+ default:
+ dev_err(cpu_dai->dev, "Unsupported mode %#x\n",
+ fmt & SND_SOC_DAIFMT_MASTER_MASK);
+ return -EINVAL;
+ }
+ cr1_mask |= SAI_XCR1_SLAVE;
+
+ ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, cr1_mask, cr1);
+ if (ret < 0) {
+ dev_err(cpu_dai->dev, "Failed to update CR1 register\n");
+ return ret;
+ }
+
+ sai->fmt = fmt;
+
+ return 0;
+}
+
+static int stm32_sai_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ int imr, cr2, ret;
+
+ sai->substream = substream;
+
+ ret = clk_prepare_enable(sai->sai_ck);
+ if (ret < 0) {
+ dev_err(cpu_dai->dev, "Failed to enable clock: %d\n", ret);
+ return ret;
+ }
+
+ /* Enable ITs */
+ regmap_update_bits(sai->regmap, STM_SAI_SR_REGX,
+ SAI_XSR_MASK, (unsigned int)~SAI_XSR_MASK);
+
+ regmap_update_bits(sai->regmap, STM_SAI_CLRFR_REGX,
+ SAI_XCLRFR_MASK, SAI_XCLRFR_MASK);
+
+ imr = SAI_XIMR_OVRUDRIE;
+ if (STM_SAI_IS_CAPTURE(sai)) {
+ regmap_read(sai->regmap, STM_SAI_CR2_REGX, &cr2);
+ if (cr2 & SAI_XCR2_MUTECNT_MASK)
+ imr |= SAI_XIMR_MUTEDETIE;
+ }
+
+ if (sai->master)
+ imr |= SAI_XIMR_WCKCFGIE;
+ else
+ imr |= SAI_XIMR_AFSDETIE | SAI_XIMR_LFSDETIE;
+
+ regmap_update_bits(sai->regmap, STM_SAI_IMR_REGX,
+ SAI_XIMR_MASK, imr);
+
+ return 0;
+}
+
+static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai,
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ int cr1, cr1_mask, ret;
+ int fth = STM_SAI_FIFO_TH_HALF;
+
+ /* FIFO config */
+ regmap_update_bits(sai->regmap, STM_SAI_CR2_REGX,
+ SAI_XCR2_FFLUSH | SAI_XCR2_FTH_MASK,
+ SAI_XCR2_FFLUSH | SAI_XCR2_FTH_SET(fth));
+
+ /* Mode, data format and channel config */
+ cr1 = SAI_XCR1_PRTCFG_SET(SAI_FREE_PROTOCOL);
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S8:
+ cr1 |= SAI_XCR1_DS_SET(SAI_DATASIZE_8);
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ cr1 |= SAI_XCR1_DS_SET(SAI_DATASIZE_16);
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ cr1 |= SAI_XCR1_DS_SET(SAI_DATASIZE_32);
+ break;
+ default:
+ dev_err(cpu_dai->dev, "Data format not supported");
+ return -EINVAL;
+ }
+ cr1_mask = SAI_XCR1_DS_MASK | SAI_XCR1_PRTCFG_MASK;
+
+ cr1_mask |= SAI_XCR1_RX_TX;
+ if (STM_SAI_IS_CAPTURE(sai))
+ cr1 |= SAI_XCR1_RX_TX;
+
+ cr1_mask |= SAI_XCR1_MONO;
+ if ((sai->slots == 2) && (params_channels(params) == 1))
+ cr1 |= SAI_XCR1_MONO;
+
+ ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, cr1_mask, cr1);
+ if (ret < 0) {
+ dev_err(cpu_dai->dev, "Failed to update CR1 register\n");
+ return ret;
+ }
+
+ /* DMA config */
+ sai->dma_params.maxburst = STM_SAI_FIFO_SIZE * fth / sizeof(u32);
+ snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)&sai->dma_params);
+
+ return 0;
+}
+
+static int stm32_sai_set_slots(struct snd_soc_dai *cpu_dai)
+{
+ struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ int slotr, slot_sz;
+
+ regmap_read(sai->regmap, STM_SAI_SLOTR_REGX, &slotr);
+
+ /*
+ * If SLOTSZ is set to auto in SLOTR, align slot width on data size
+ * By default slot width = data size, if not forced from DT
+ */
+ slot_sz = slotr & SAI_XSLOTR_SLOTSZ_MASK;
+ if (slot_sz == SAI_XSLOTR_SLOTSZ_SET(SAI_SLOT_SIZE_AUTO))
+ sai->slot_width = sai->data_size;
+
+ if (sai->slot_width < sai->data_size) {
+ dev_err(cpu_dai->dev,
+ "Data size %d larger than slot width\n",
+ sai->data_size);
+ return -EINVAL;
+ }
+
+ /* Slot number is set to 2, if not specified in DT */
+ if (!sai->slots)
+ sai->slots = 2;
+
+ /* The number of slots in the audio frame is equal to NBSLOT[3:0] + 1*/
+ regmap_update_bits(sai->regmap, STM_SAI_SLOTR_REGX,
+ SAI_XSLOTR_NBSLOT_MASK,
+ SAI_XSLOTR_NBSLOT_SET((sai->slots - 1)));
+
+ /* Set default slots mask if not already set from DT */
+ if (!(slotr & SAI_XSLOTR_SLOTEN_MASK)) {
+ sai->slot_mask = (1 << sai->slots) - 1;
+ regmap_update_bits(sai->regmap,
+ STM_SAI_SLOTR_REGX, SAI_XSLOTR_SLOTEN_MASK,
+ SAI_XSLOTR_SLOTEN_SET(sai->slot_mask));
+ }
+
+ dev_dbg(cpu_dai->dev, "Slots %d, slot width %d\n",
+ sai->slots, sai->slot_width);
+
+ return 0;
+}
+
+static void stm32_sai_set_frame(struct snd_soc_dai *cpu_dai)
+{
+ struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ int fs_active, offset, format;
+ int frcr, frcr_mask;
+
+ format = sai->fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+ sai->fs_length = sai->slot_width * sai->slots;
+
+ fs_active = sai->fs_length / 2;
+ if ((format == SND_SOC_DAIFMT_DSP_A) ||
+ (format == SND_SOC_DAIFMT_DSP_B))
+ fs_active = 1;
+
+ frcr = SAI_XFRCR_FRL_SET((sai->fs_length - 1));
+ frcr |= SAI_XFRCR_FSALL_SET((fs_active - 1));
+ frcr_mask = SAI_XFRCR_FRL_MASK | SAI_XFRCR_FSALL_MASK;
+
+ dev_dbg(cpu_dai->dev, "Frame length %d, frame active %d\n",
+ sai->fs_length, fs_active);
+
+ regmap_update_bits(sai->regmap, STM_SAI_FRCR_REGX, frcr_mask, frcr);
+
+ if ((sai->fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_LSB) {
+ offset = sai->slot_width - sai->data_size;
+
+ regmap_update_bits(sai->regmap, STM_SAI_SLOTR_REGX,
+ SAI_XSLOTR_FBOFF_MASK,
+ SAI_XSLOTR_FBOFF_SET(offset));
+ }
+}
+
+static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai,
+ struct snd_pcm_hw_params *params)
+{
+ struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ int cr1, mask, div = 0;
+ int sai_clk_rate, ret;
+
+ if (!sai->mclk_rate) {
+ dev_err(cpu_dai->dev, "Mclk rate is null\n");
+ return -EINVAL;
+ }
+
+ if (!(params_rate(params) % 11025))
+ clk_set_parent(sai->sai_ck, sai->pdata->clk_x11k);
+ else
+ clk_set_parent(sai->sai_ck, sai->pdata->clk_x8k);
+ sai_clk_rate = clk_get_rate(sai->sai_ck);
+
+ /*
+ * mclk_rate = 256 * fs
+ * MCKDIV = 0 if sai_ck < 3/2 * mclk_rate
+ * MCKDIV = sai_ck / (2 * mclk_rate) otherwise
+ */
+ if (2 * sai_clk_rate >= 3 * sai->mclk_rate)
+ div = DIV_ROUND_CLOSEST(sai_clk_rate, 2 * sai->mclk_rate);
+
+ if (div > SAI_XCR1_MCKDIV_MAX) {
+ dev_err(cpu_dai->dev, "Divider %d out of range\n", div);
+ return -EINVAL;
+ }
+ dev_dbg(cpu_dai->dev, "SAI clock %d, divider %d\n", sai_clk_rate, div);
+
+ mask = SAI_XCR1_MCKDIV_MASK;
+ cr1 = SAI_XCR1_MCKDIV_SET(div);
+ ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, mask, cr1);
+ if (ret < 0) {
+ dev_err(cpu_dai->dev, "Failed to update CR1 register\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int stm32_sai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ int ret;
+
+ sai->data_size = params_width(params);
+
+ ret = stm32_sai_set_slots(cpu_dai);
+ if (ret < 0)
+ return ret;
+ stm32_sai_set_frame(cpu_dai);
+
+ ret = stm32_sai_set_config(cpu_dai, substream, params);
+ if (ret)
+ return ret;
+
+ if (sai->master)
+ ret = stm32_sai_configure_clock(cpu_dai, params);
+
+ return ret;
+}
+
+static int stm32_sai_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ int ret;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ dev_dbg(cpu_dai->dev, "Enable DMA and SAI\n");
+
+ regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX,
+ SAI_XCR1_DMAEN, SAI_XCR1_DMAEN);
+
+ /* Enable SAI */
+ ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX,
+ SAI_XCR1_SAIEN, SAI_XCR1_SAIEN);
+ if (ret < 0)
+ dev_err(cpu_dai->dev, "Failed to update CR1 register\n");
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_STOP:
+ dev_dbg(cpu_dai->dev, "Disable DMA and SAI\n");
+
+ regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX,
+ SAI_XCR1_DMAEN,
+ (unsigned int)~SAI_XCR1_DMAEN);
+
+ ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX,
+ SAI_XCR1_SAIEN,
+ (unsigned int)~SAI_XCR1_SAIEN);
+ if (ret < 0)
+ dev_err(cpu_dai->dev, "Failed to update CR1 register\n");
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static void stm32_sai_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
+
+ regmap_update_bits(sai->regmap, STM_SAI_IMR_REGX, SAI_XIMR_MASK, 0);
+
+ clk_disable_unprepare(sai->sai_ck);
+ sai->substream = NULL;
+}
+
+static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
+{
+ struct stm32_sai_sub_data *sai = dev_get_drvdata(cpu_dai->dev);
+
+ sai->dma_params.addr = (dma_addr_t)(sai->phys_addr + STM_SAI_DR_REGX);
+ sai->dma_params.maxburst = 1;
+ /* Buswidth will be set by framework at runtime */
+ sai->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED;
+
+ if (STM_SAI_IS_PLAYBACK(sai))
+ snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params, NULL);
+ else
+ snd_soc_dai_init_dma_data(cpu_dai, NULL, &sai->dma_params);
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops stm32_sai_pcm_dai_ops = {
+ .set_sysclk = stm32_sai_set_sysclk,
+ .set_fmt = stm32_sai_set_dai_fmt,
+ .set_tdm_slot = stm32_sai_set_dai_tdm_slot,
+ .startup = stm32_sai_startup,
+ .hw_params = stm32_sai_hw_params,
+ .trigger = stm32_sai_trigger,
+ .shutdown = stm32_sai_shutdown,
+};
+
+static const struct snd_pcm_hardware stm32_sai_pcm_hw = {
+ .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP,
+ .buffer_bytes_max = 8 * PAGE_SIZE,
+ .period_bytes_min = 1024, /* 5ms at 48kHz */
+ .period_bytes_max = PAGE_SIZE,
+ .periods_min = 2,
+ .periods_max = 8,
+};
+
+static struct snd_soc_dai_driver stm32_sai_playback_dai[] = {
+{
+ .probe = stm32_sai_dai_probe,
+ .id = 1, /* avoid call to fmt_single_name() */
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ /* DMA does not support 24 bits transfers */
+ .formats =
+ SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &stm32_sai_pcm_dai_ops,
+ }
+};
+
+static struct snd_soc_dai_driver stm32_sai_capture_dai[] = {
+{
+ .probe = stm32_sai_dai_probe,
+ .id = 1, /* avoid call to fmt_single_name() */
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ /* DMA does not support 24 bits transfers */
+ .formats =
+ SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &stm32_sai_pcm_dai_ops,
+ }
+};
+
+static const struct snd_dmaengine_pcm_config stm32_sai_pcm_config = {
+ .pcm_hardware = &stm32_sai_pcm_hw,
+ .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
+};
+
+static const struct snd_soc_component_driver stm32_component = {
+ .name = "stm32-sai",
+};
+
+static const struct of_device_id stm32_sai_sub_ids[] = {
+ { .compatible = "st,stm32-sai-sub-a",
+ .data = (void *)STM_SAI_A_ID},
+ { .compatible = "st,stm32-sai-sub-b",
+ .data = (void *)STM_SAI_B_ID},
+ {}
+};
+MODULE_DEVICE_TABLE(of, stm32_sai_sub_ids);
+
+static int stm32_sai_sub_parse_of(struct platform_device *pdev,
+ struct stm32_sai_sub_data *sai)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct resource *res;
+ void __iomem *base;
+
+ if (!np)
+ return -ENODEV;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ sai->phys_addr = res->start;
+ sai->regmap = devm_regmap_init_mmio(&pdev->dev, base,
+ &stm32_sai_sub_regmap_config);
+
+ /* Get direction property */
+ if (of_property_match_string(np, "dma-names", "tx") >= 0) {
+ sai->dir = SNDRV_PCM_STREAM_PLAYBACK;
+ } else if (of_property_match_string(np, "dma-names", "rx") >= 0) {
+ sai->dir = SNDRV_PCM_STREAM_CAPTURE;
+ } else {
+ dev_err(&pdev->dev, "Unsupported direction\n");
+ return -EINVAL;
+ }
+
+ sai->sai_ck = devm_clk_get(&pdev->dev, "sai_ck");
+ if (IS_ERR(sai->sai_ck)) {
+ dev_err(&pdev->dev, "Missing kernel clock sai_ck\n");
+ return PTR_ERR(sai->sai_ck);
+ }
+
+ return 0;
+}
+
+static int stm32_sai_sub_dais_init(struct platform_device *pdev,
+ struct stm32_sai_sub_data *sai)
+{
+ sai->cpu_dai_drv = devm_kzalloc(&pdev->dev,
+ sizeof(struct snd_soc_dai_driver),
+ GFP_KERNEL);
+ if (!sai->cpu_dai_drv)
+ return -ENOMEM;
+
+ sai->cpu_dai_drv->name = dev_name(&pdev->dev);
+ if (STM_SAI_IS_PLAYBACK(sai)) {
+ memcpy(sai->cpu_dai_drv, &stm32_sai_playback_dai,
+ sizeof(stm32_sai_playback_dai));
+ sai->cpu_dai_drv->playback.stream_name = sai->cpu_dai_drv->name;
+ } else {
+ memcpy(sai->cpu_dai_drv, &stm32_sai_capture_dai,
+ sizeof(stm32_sai_capture_dai));
+ sai->cpu_dai_drv->capture.stream_name = sai->cpu_dai_drv->name;
+ }
+
+ return 0;
+}
+
+static int stm32_sai_sub_probe(struct platform_device *pdev)
+{
+ struct stm32_sai_sub_data *sai;
+ const struct of_device_id *of_id;
+ int ret;
+
+ sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
+ if (!sai)
+ return -ENOMEM;
+
+ of_id = of_match_device(stm32_sai_sub_ids, &pdev->dev);
+ if (!of_id)
+ return -EINVAL;
+ sai->id = (uintptr_t)of_id->data;
+
+ sai->pdev = pdev;
+ platform_set_drvdata(pdev, sai);
+
+ sai->pdata = dev_get_drvdata(pdev->dev.parent);
+ if (!sai->pdata) {
+ dev_err(&pdev->dev, "Parent device data not available\n");
+ return -EINVAL;
+ }
+
+ ret = stm32_sai_sub_parse_of(pdev, sai);
+ if (ret)
+ return ret;
+
+ ret = stm32_sai_sub_dais_init(pdev, sai);
+ if (ret)
+ return ret;
+
+ ret = devm_request_irq(&pdev->dev, sai->pdata->irq, stm32_sai_isr,
+ IRQF_SHARED, dev_name(&pdev->dev), sai);
+ if (ret) {
+ dev_err(&pdev->dev, "IRQ request returned %d\n", ret);
+ return ret;
+ }
+
+ ret = devm_snd_soc_register_component(&pdev->dev, &stm32_component,
+ sai->cpu_dai_drv, 1);
+ if (ret)
+ return ret;
+
+ ret = devm_snd_dmaengine_pcm_register(&pdev->dev,
+ &stm32_sai_pcm_config, 0);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not register pcm dma\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct platform_driver stm32_sai_sub_driver = {
+ .driver = {
+ .name = "st,stm32-sai-sub",
+ .of_match_table = stm32_sai_sub_ids,
+ },
+ .probe = stm32_sai_sub_probe,
+};
+
+module_platform_driver(stm32_sai_sub_driver);
+
+MODULE_DESCRIPTION("STM32 Soc SAI sub-block Interface");
+MODULE_AUTHOR("Olivier Moysan <olivier.moysan@st.com>");
+MODULE_ALIAS("platform:st,stm32-sai-sub");
+MODULE_LICENSE("GPL v2");
--
1.9.1
^ permalink raw reply related
* [PATCH v4 0/2] Add STM32 SAI support
From: olivier moysan @ 2017-04-11 15:47 UTC (permalink / raw)
To: lgirdwood, broonie, perex, tiwai, mcoquelin.stm32,
alexandre.torgue, alsa-devel, robh, mark.rutland, devicetree,
linux-arm-kernel, kernel, linux-kernel, olivier.moysan
Cc: arnaud.pouliquen, benjamin.gaignard
This patch-set handles the Serial Audio Interface (SAI) IP on STM32 platforms.
The SAI IP is composed of two Sub-block A and B. (see the figure below)
Each sub-block makes use of individual and shared resources.
Shared resources:
- Reset line. Reset common and sub-block registers.
- Bus interface clocks. This clock is not exposed in device
as it it managed by clock driver, according to kernel clocks gating.
- Common register. SAI IP exhibits a common configuration register
to manage synchronization modes. NB: These modes are not yet implemented
in this version of the SAI driver.
- Interrupt. Sub-blocks have their own interrupt status registers but they
share the same interrupt line.
Individual resources:
- Register set
- DMA request line.
- Communication interface.
Each sub-block has its own GPIOs and associated bus lines.
- Kernel clock.
Each sub-block has its own dedicated clock for its communication interface.
To reflect this architecture Sub-block A and B are handled by 2 child devices.
Sub-block A and B devices can be configured independently either as transmitter
or receiver. A PCM device is associated to each sub-block.
A sub-block has to select the appropriated parent clock at runtime,
depending on the audio stream sampling rate to be played or captured.
Two parent clocks must be provided to support sampling rates multiples
of 8 kHz or 11.025kHz.
Interface clock +--------------------------------+
+---------------> | SAI IP |
Reset | +-----------------+ |
+---------------> | |common registers | |
| +-----------------+ |
| |
| +----------------------+ |
| | Sub-block A | |
Kernel clock A | | | | Bus A
+--------------------> | +----------------+ +---------------->
| | |A registers | | |
| | +----------------+ | |
| +----------------------+ |
| |
| +----------------------+ |
| | Sub-block B | |
Kernel clock B | | | | Bus B
+--------------------> | +----------------+ +----------------->
| | |B registers | | |
| | +----------------+ | |
| +----------------------+ |
| |
+--------------------------------+
v3 -> v4
Apply minor changes from Peter review
olivier moysan (2):
ASoC: stm32: add bindings for SAI
ASoC: stm32: add SAI driver
.../devicetree/bindings/sound/st,stm32-sai.txt | 89 +++
sound/soc/Kconfig | 1 +
sound/soc/Makefile | 1 +
sound/soc/stm/Kconfig | 8 +
sound/soc/stm/Makefile | 6 +
sound/soc/stm/stm32_sai.c | 115 +++
sound/soc/stm/stm32_sai.h | 199 +++++
sound/soc/stm/stm32_sai_sub.c | 881 +++++++++++++++++++++
8 files changed, 1300 insertions(+)
create mode 100644 Documentation/devicetree/bindings/sound/st,stm32-sai.txt
create mode 100644 sound/soc/stm/Kconfig
create mode 100644 sound/soc/stm/Makefile
create mode 100644 sound/soc/stm/stm32_sai.c
create mode 100644 sound/soc/stm/stm32_sai.h
create mode 100644 sound/soc/stm/stm32_sai_sub.c
--
1.9.1
^ permalink raw reply
* [Intel-wired-lan] [PATCH 1/3] ixgbe: Complete support for X553 sgmii
From: Singh, Krishneil K @ 2017-04-11 15:50 UTC (permalink / raw)
To: intel-wired-lan
In-Reply-To: <1483150034-35128-1-git-send-email-donald.c.skidmore@intel.com>
-----Original Message-----
From: Intel-wired-lan [mailto:intel-wired-lan-bounces at lists.osuosl.org] On Behalf Of Donald C Skidmore
Sent: Friday, December 30, 2016 6:07 PM
To: intel-wired-lan@lists.osuosl.org
Subject: [Intel-wired-lan] [PATCH 1/3] ixgbe: Complete support for X553 sgmii
The initial patches supporting X553 sgmii forgot some details. This patch should cover those missing spots.
Signed-off-by: Don Skidmore <donald.c.skidmore@intel.com>
---
Tested-by: Krishneil Singh <krishneil.k.singh@intel.com>
^ permalink raw reply
* [RFC PATCH v0.2] PCI: Add support for tango PCIe host bridge
From: Marc Zyngier @ 2017-04-11 15:49 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <30f662a6-5dab-515b-e35a-a312f3c7b509@free.fr>
On 11/04/17 16:13, Mason wrote:
> On 27/03/2017 19:09, Marc Zyngier wrote:
>
>> Here's what your system looks like:
>>
>> PCI-EP -------> MSI Controller ------> INTC
>> MSI IRQ
>>
>> A PCI MSI is always edge. No ifs, no buts. That's what it is, and nothing
>> else. Now, your MSI controller signals its output using a level interrupt,
>> since you need to whack it on the head so that it lowers its line.
>>
>> There is not a single trigger, because there is not a single interrupt.
>
> Hello Marc,
>
> I was hoping you or Thomas might help clear some confusion
> in my mind around IRQ domains (struct irq_domain).
>
> I have read https://www.kernel.org/doc/Documentation/IRQ-domain.txt
>
> IIUC, there should be one IRQ domain per IRQ controller.
>
> I have this MSI controller handling 256 interrupts, so I should
> have *one* domain for all possible MSIs. Yet the Altera driver
> registers *two* domains (msi_domain and inner_domain).
>
> Could I make everything work with a single IRQ domain?
No, because you have two irqchips. One that deals with the HW, and the
other that deals with the MSIs how they are presented to the kernel,
depending on the bus (PCI or something else). The fact that it doesn't
really drive any HW doesn't make it irrelevant.
> I'm confused by the sequence:
>
> irq_dom = irq_domain_create_linear(fwnode, MSI_COUNT, &msi_dom_ops, pcie);
> msi_dom = pci_msi_create_irq_domain(fwnode, &msi_domain_info, irq_dom);
>
> It seems I should be able to call only pci_msi_create_irq_domain...
> And the parent of the MSI controller is given in the DT.
No, see above.
> I'm not quite sure how I tell pci_msi_create_irq_domain how many
> MSIs it's supposed to manage. Nor how I pass my private struct.
You don't need to tell it anything about the number of interrupts you
manage. As for your private structure, you've already given it to your
low level domain, and there is no need to propagate it any further.
Thanks,
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply
* Re: [RFC PATCH v0.2] PCI: Add support for tango PCIe host bridge
From: Marc Zyngier @ 2017-04-11 15:49 UTC (permalink / raw)
To: Mason, Thomas Gleixner
Cc: Bjorn Helgaas, Robin Murphy, Lorenzo Pieralisi, Liviu Dudau,
David Laight, linux-pci, Linux ARM, Thibaud Cornic, Phuong Nguyen,
LKML
In-Reply-To: <30f662a6-5dab-515b-e35a-a312f3c7b509@free.fr>
On 11/04/17 16:13, Mason wrote:
> On 27/03/2017 19:09, Marc Zyngier wrote:
>
>> Here's what your system looks like:
>>
>> PCI-EP -------> MSI Controller ------> INTC
>> MSI IRQ
>>
>> A PCI MSI is always edge. No ifs, no buts. That's what it is, and nothing
>> else. Now, your MSI controller signals its output using a level interrupt,
>> since you need to whack it on the head so that it lowers its line.
>>
>> There is not a single trigger, because there is not a single interrupt.
>
> Hello Marc,
>
> I was hoping you or Thomas might help clear some confusion
> in my mind around IRQ domains (struct irq_domain).
>
> I have read https://www.kernel.org/doc/Documentation/IRQ-domain.txt
>
> IIUC, there should be one IRQ domain per IRQ controller.
>
> I have this MSI controller handling 256 interrupts, so I should
> have *one* domain for all possible MSIs. Yet the Altera driver
> registers *two* domains (msi_domain and inner_domain).
>
> Could I make everything work with a single IRQ domain?
No, because you have two irqchips. One that deals with the HW, and the
other that deals with the MSIs how they are presented to the kernel,
depending on the bus (PCI or something else). The fact that it doesn't
really drive any HW doesn't make it irrelevant.
> I'm confused by the sequence:
>
> irq_dom = irq_domain_create_linear(fwnode, MSI_COUNT, &msi_dom_ops, pcie);
> msi_dom = pci_msi_create_irq_domain(fwnode, &msi_domain_info, irq_dom);
>
> It seems I should be able to call only pci_msi_create_irq_domain...
> And the parent of the MSI controller is given in the DT.
No, see above.
> I'm not quite sure how I tell pci_msi_create_irq_domain how many
> MSIs it's supposed to manage. Nor how I pass my private struct.
You don't need to tell it anything about the number of interrupts you
manage. As for your private structure, you've already given it to your
low level domain, and there is no need to propagate it any further.
Thanks,
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply
* Re: [rdma-core/srp_daemon PATCH] Correct method field for PathRecord request
From: Jason Gunthorpe @ 2017-04-11 15:49 UTC (permalink / raw)
To: Honggang LI
Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, sagig-VPRAkNaXOzVWk0Htik3J/w,
bart.vanassche-XdAiOPVOjttBDgjK7y7TUQ
In-Reply-To: <1491924533-2548-1-git-send-email-honli-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
On Tue, Apr 11, 2017 at 11:28:53PM +0800, Honggang LI wrote:
> From: Honggang Li <honli-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
>
> According to InfiniBand Architecture Release 1.2.1, Table 208
> Example PathRecord Request MAD Header Fields, MADHeader:Method
> should setup to 0x12 (SubnAdmGetTable()).
That is just an example, Table 192 shows that Get and GetTable are
both valid query types.
I however expect that the SM will fail when using GetTable if the
query returns more than one result, could that be what is happening?
When you convert it to GET_TABLE does it return more than one result?
Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v3] x86, pmem: fix broken __copy_user_nocache cache-bypass assumptions
From: Ross Zwisler @ 2017-04-11 15:49 UTC (permalink / raw)
To: Dan Williams
Cc: linux-nvdimm, Jan Kara, Toshi Kani, Matthew Wilcox, x86,
linux-kernel, stable, Christoph Hellwig, Jeff Moyer, Ingo Molnar,
Al Viro, H. Peter Anvin, Thomas Gleixner, Ross Zwisler
In-Reply-To: <149187075199.40875.9829505688202257056.stgit@dwillia2-desk3.amr.corp.intel.com>
On Mon, Apr 10, 2017 at 05:35:02PM -0700, Dan Williams wrote:
> Before we rework the "pmem api" to stop abusing __copy_user_nocache()
> for memcpy_to_pmem() we need to fix cases where we may strand dirty data
> in the cpu cache. The problem occurs when copy_from_iter_pmem() is used
> for arbitrary data transfers from userspace. There is no guarantee that
> these transfers, performed by dax_iomap_actor(), will have aligned
> destinations or aligned transfer lengths. Backstop the usage
> __copy_user_nocache() with explicit cache management in these unaligned
> cases.
>
> Yes, copy_from_iter_pmem() is now too big for an inline, but addressing
> that is saved for a later patch that moves the entirety of the "pmem
> api" into the pmem driver directly.
>
> Fixes: 5de490daec8b ("pmem: add copy_from_iter_pmem() and clear_pmem()")
> Cc: <stable@vger.kernel.org>
> Cc: <x86@kernel.org>
> Cc: Jan Kara <jack@suse.cz>
> Cc: Jeff Moyer <jmoyer@redhat.com>
> Cc: Ingo Molnar <mingo@redhat.com>
> Cc: Christoph Hellwig <hch@lst.de>
> Cc: "H. Peter Anvin" <hpa@zytor.com>
> Cc: Al Viro <viro@zeniv.linux.org.uk>
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Cc: Matthew Wilcox <mawilcox@microsoft.com>
> Cc: Ross Zwisler <ross.zwisler@linux.intel.com>
> Signed-off-by: Toshi Kani <toshi.kani@hpe.com>
> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
This looks good to me, thanks for fixing this.
Reviewed-by: Ross Zwisler <ross.zwisler@linux.intel.com>
^ permalink raw reply
* Re: [PATCH v3] x86, pmem: fix broken __copy_user_nocache cache-bypass assumptions
From: Ross Zwisler @ 2017-04-11 15:49 UTC (permalink / raw)
To: Dan Williams
Cc: linux-nvdimm, Jan Kara, Toshi Kani, Matthew Wilcox, x86,
linux-kernel, stable, Christoph Hellwig, Jeff Moyer, Ingo Molnar,
Al Viro, H. Peter Anvin, Thomas Gleixner, Ross Zwisler
In-Reply-To: <149187075199.40875.9829505688202257056.stgit@dwillia2-desk3.amr.corp.intel.com>
On Mon, Apr 10, 2017 at 05:35:02PM -0700, Dan Williams wrote:
> Before we rework the "pmem api" to stop abusing __copy_user_nocache()
> for memcpy_to_pmem() we need to fix cases where we may strand dirty data
> in the cpu cache. The problem occurs when copy_from_iter_pmem() is used
> for arbitrary data transfers from userspace. There is no guarantee that
> these transfers, performed by dax_iomap_actor(), will have aligned
> destinations or aligned transfer lengths. Backstop the usage
> __copy_user_nocache() with explicit cache management in these unaligned
> cases.
>
> Yes, copy_from_iter_pmem() is now too big for an inline, but addressing
> that is saved for a later patch that moves the entirety of the "pmem
> api" into the pmem driver directly.
>
> Fixes: 5de490daec8b ("pmem: add copy_from_iter_pmem() and clear_pmem()")
> Cc: <stable@vger.kernel.org>
> Cc: <x86@kernel.org>
> Cc: Jan Kara <jack@suse.cz>
> Cc: Jeff Moyer <jmoyer@redhat.com>
> Cc: Ingo Molnar <mingo@redhat.com>
> Cc: Christoph Hellwig <hch@lst.de>
> Cc: "H. Peter Anvin" <hpa@zytor.com>
> Cc: Al Viro <viro@zeniv.linux.org.uk>
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Cc: Matthew Wilcox <mawilcox@microsoft.com>
> Cc: Ross Zwisler <ross.zwisler@linux.intel.com>
> Signed-off-by: Toshi Kani <toshi.kani@hpe.com>
> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
This looks good to me, thanks for fixing this.
Reviewed-by: Ross Zwisler <ross.zwisler@linux.intel.com>
^ permalink raw reply
* Re: [PATCH v3] x86, pmem: fix broken __copy_user_nocache cache-bypass assumptions
From: Ross Zwisler @ 2017-04-11 15:49 UTC (permalink / raw)
To: Dan Williams
Cc: Jan Kara, Matthew Wilcox, x86, linux-kernel, stable, linux-nvdimm,
Ingo Molnar, Al Viro, H. Peter Anvin, Thomas Gleixner,
Christoph Hellwig
In-Reply-To: <149187075199.40875.9829505688202257056.stgit@dwillia2-desk3.amr.corp.intel.com>
On Mon, Apr 10, 2017 at 05:35:02PM -0700, Dan Williams wrote:
> Before we rework the "pmem api" to stop abusing __copy_user_nocache()
> for memcpy_to_pmem() we need to fix cases where we may strand dirty data
> in the cpu cache. The problem occurs when copy_from_iter_pmem() is used
> for arbitrary data transfers from userspace. There is no guarantee that
> these transfers, performed by dax_iomap_actor(), will have aligned
> destinations or aligned transfer lengths. Backstop the usage
> __copy_user_nocache() with explicit cache management in these unaligned
> cases.
>
> Yes, copy_from_iter_pmem() is now too big for an inline, but addressing
> that is saved for a later patch that moves the entirety of the "pmem
> api" into the pmem driver directly.
>
> Fixes: 5de490daec8b ("pmem: add copy_from_iter_pmem() and clear_pmem()")
> Cc: <stable@vger.kernel.org>
> Cc: <x86@kernel.org>
> Cc: Jan Kara <jack@suse.cz>
> Cc: Jeff Moyer <jmoyer@redhat.com>
> Cc: Ingo Molnar <mingo@redhat.com>
> Cc: Christoph Hellwig <hch@lst.de>
> Cc: "H. Peter Anvin" <hpa@zytor.com>
> Cc: Al Viro <viro@zeniv.linux.org.uk>
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Cc: Matthew Wilcox <mawilcox@microsoft.com>
> Cc: Ross Zwisler <ross.zwisler@linux.intel.com>
> Signed-off-by: Toshi Kani <toshi.kani@hpe.com>
> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
This looks good to me, thanks for fixing this.
Reviewed-by: Ross Zwisler <ross.zwisler@linux.intel.com>
_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm
^ permalink raw reply
* Re: [PATCH] net/tap: add support for fixed mac addresses
From: Ferruh Yigit @ 2017-04-11 15:49 UTC (permalink / raw)
To: Wiles, Keith, Pascal Mazon; +Cc: dev@dpdk.org
In-Reply-To: <AA7E2728-D9AA-466F-9E43-33FCF1D34063@intel.com>
On 4/11/2017 4:42 PM, Wiles, Keith wrote:
>
>> On Apr 11, 2017, at 10:09 AM, Pascal Mazon <pascal.mazon@6wind.com> wrote:
>>
>> Support for a fixed MAC address for testing with the last octet
>> incrementing by one for each interface defined with the new 'mac=fixed'
>> string on the --vdev option. The default option is still to randomize
>> the MAC address for each tap interface.
>>
>> Signed-off-by: Keith Wiles <keith.wiles@intel.com>
<...>
> This does not show up as a change in the patch, I thought it should.
It does: http://dpdk.org/dev/patchwork/patch/23508/
^ permalink raw reply
* Re: [PATCH] drm/i915: Bail if we do not setup the RCS engine
From: Chris Wilson @ 2017-04-11 15:48 UTC (permalink / raw)
To: intel-gfx
In-Reply-To: <20170411153022.8962-1-chris@chris-wilson.co.uk>
On Tue, Apr 11, 2017 at 04:30:22PM +0100, Chris Wilson wrote:
> In places, we assume that RCS exists. This has been true forever, but
> let us catch this failure during bringup by adding an explicit check
> that we do have an RCS engine.
Note that some might argue that I'm using the RCS engine as a proxy for
a missing dev_priv->gt function table... You know who you are!
-Chris
--
Chris Wilson, Intel Open Source Technology Centre
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply
* Re: [Printing-architecture] REMINDER - OP Call Tuesday (11 April 2017)
From: Till Kamppeter @ 2017-04-11 15:48 UTC (permalink / raw)
To: Aveek Basu, Ira McDonald; +Cc: printing-architecture@lists.linux-foundation.org
In-Reply-To: <CAKSHSL4YYhF2GkoDxv6dagAt3J_sNsF2gvpFwA2d73NXy5HPBw@mail.gmail.com>
On 04/11/2017 12:35 PM, Aveek Basu wrote:
> Hi Ira \ Till,
>
> Is there any way, I can connect from India using a Toll free number?
>
There is no Indian national or toll-free number, but there is an app for
smartphones to call in via VoIP. So if you have WiFi or a fast 3G/4G
connection where you are, you can call in with the app.
At least under Android it is called FCCI Dialer.
I use this app for calling in from Brazil and it works.
Till
^ permalink raw reply
* [PATCH] clockevents/tcb_clksrc: implement suspend/resume
From: Alexandre Belloni @ 2017-04-11 15:48 UTC (permalink / raw)
To: Daniel Lezcano, Nicolas Ferre, Thomas Gleixner
Cc: Boris Brezillon, linux-arm-kernel, linux-kernel,
Alexandre Belloni
On sama5d2, power to the core may be cut while entering suspend mode. It is
necessary to save and restore the TCB registers.
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
---
drivers/clocksource/tcb_clksrc.c | 46 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/drivers/clocksource/tcb_clksrc.c b/drivers/clocksource/tcb_clksrc.c
index d4ca9962a759..57f5d72328f4 100644
--- a/drivers/clocksource/tcb_clksrc.c
+++ b/drivers/clocksource/tcb_clksrc.c
@@ -9,6 +9,7 @@
#include <linux/ioport.h>
#include <linux/io.h>
#include <linux/platform_device.h>
+#include <linux/syscore_ops.h>
#include <linux/atmel_tc.h>
@@ -40,6 +41,14 @@
*/
static void __iomem *tcaddr;
+static struct
+{
+ u32 cmr;
+ u32 imr;
+ u32 rc;
+ bool clken;
+} tcb_cache[3];
+static u32 bmr_cache;
static u64 tc_get_cycles(struct clocksource *cs)
{
@@ -61,12 +70,49 @@ static u64 tc_get_cycles32(struct clocksource *cs)
return __raw_readl(tcaddr + ATMEL_TC_REG(0, CV));
}
+void tc_clksrc_suspend(struct clocksource *cs)
+{
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ tcb_cache[i].cmr = readl(tcaddr + ATMEL_TC_REG(i, CMR));
+ tcb_cache[i].imr = readl(tcaddr + ATMEL_TC_REG(i, IMR));
+ tcb_cache[i].rc = readl(tcaddr + ATMEL_TC_REG(i, RC));
+ tcb_cache[i].clken = !!(readl(tcaddr + ATMEL_TC_REG(i, SR)) &
+ ATMEL_TC_CLKSTA);
+ }
+
+ bmr_cache = readl(tcaddr + ATMEL_TC_BMR);
+}
+
+void tc_clksrc_resume(struct clocksource *cs)
+{
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ __raw_writel(tcb_cache[i].cmr, tcaddr + ATMEL_TC_REG(i, CMR));
+ __raw_writel(0, tcaddr + ATMEL_TC_REG(i, RA));
+ __raw_writel(0, tcaddr + ATMEL_TC_REG(i, RB));
+ __raw_writel(tcb_cache[i].rc, tcaddr + ATMEL_TC_REG(i, RC));
+ __raw_writel(0xff, tcaddr + ATMEL_TC_REG(i, IDR));
+ __raw_writel(tcb_cache[i].imr, tcaddr + ATMEL_TC_REG(i, IER));
+ if (tcb_cache[i].clken)
+ __raw_writel(ATMEL_TC_CLKEN, tcaddr +
+ ATMEL_TC_REG(i, CCR));
+ }
+
+ writel(bmr_cache, tcaddr + ATMEL_TC_BMR);
+ writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR);
+}
+
static struct clocksource clksrc = {
.name = "tcb_clksrc",
.rating = 200,
.read = tc_get_cycles,
.mask = CLOCKSOURCE_MASK(32),
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
+ .suspend = tc_clksrc_suspend,
+ .resume = tc_clksrc_resume,
};
#ifdef CONFIG_GENERIC_CLOCKEVENTS
--
2.11.0
^ permalink raw reply related
* [PATCH] clockevents/tcb_clksrc: implement suspend/resume
From: Alexandre Belloni @ 2017-04-11 15:48 UTC (permalink / raw)
To: linux-arm-kernel
On sama5d2, power to the core may be cut while entering suspend mode. It is
necessary to save and restore the TCB registers.
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
---
drivers/clocksource/tcb_clksrc.c | 46 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/drivers/clocksource/tcb_clksrc.c b/drivers/clocksource/tcb_clksrc.c
index d4ca9962a759..57f5d72328f4 100644
--- a/drivers/clocksource/tcb_clksrc.c
+++ b/drivers/clocksource/tcb_clksrc.c
@@ -9,6 +9,7 @@
#include <linux/ioport.h>
#include <linux/io.h>
#include <linux/platform_device.h>
+#include <linux/syscore_ops.h>
#include <linux/atmel_tc.h>
@@ -40,6 +41,14 @@
*/
static void __iomem *tcaddr;
+static struct
+{
+ u32 cmr;
+ u32 imr;
+ u32 rc;
+ bool clken;
+} tcb_cache[3];
+static u32 bmr_cache;
static u64 tc_get_cycles(struct clocksource *cs)
{
@@ -61,12 +70,49 @@ static u64 tc_get_cycles32(struct clocksource *cs)
return __raw_readl(tcaddr + ATMEL_TC_REG(0, CV));
}
+void tc_clksrc_suspend(struct clocksource *cs)
+{
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ tcb_cache[i].cmr = readl(tcaddr + ATMEL_TC_REG(i, CMR));
+ tcb_cache[i].imr = readl(tcaddr + ATMEL_TC_REG(i, IMR));
+ tcb_cache[i].rc = readl(tcaddr + ATMEL_TC_REG(i, RC));
+ tcb_cache[i].clken = !!(readl(tcaddr + ATMEL_TC_REG(i, SR)) &
+ ATMEL_TC_CLKSTA);
+ }
+
+ bmr_cache = readl(tcaddr + ATMEL_TC_BMR);
+}
+
+void tc_clksrc_resume(struct clocksource *cs)
+{
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ __raw_writel(tcb_cache[i].cmr, tcaddr + ATMEL_TC_REG(i, CMR));
+ __raw_writel(0, tcaddr + ATMEL_TC_REG(i, RA));
+ __raw_writel(0, tcaddr + ATMEL_TC_REG(i, RB));
+ __raw_writel(tcb_cache[i].rc, tcaddr + ATMEL_TC_REG(i, RC));
+ __raw_writel(0xff, tcaddr + ATMEL_TC_REG(i, IDR));
+ __raw_writel(tcb_cache[i].imr, tcaddr + ATMEL_TC_REG(i, IER));
+ if (tcb_cache[i].clken)
+ __raw_writel(ATMEL_TC_CLKEN, tcaddr +
+ ATMEL_TC_REG(i, CCR));
+ }
+
+ writel(bmr_cache, tcaddr + ATMEL_TC_BMR);
+ writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR);
+}
+
static struct clocksource clksrc = {
.name = "tcb_clksrc",
.rating = 200,
.read = tc_get_cycles,
.mask = CLOCKSOURCE_MASK(32),
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
+ .suspend = tc_clksrc_suspend,
+ .resume = tc_clksrc_resume,
};
#ifdef CONFIG_GENERIC_CLOCKEVENTS
--
2.11.0
^ permalink raw reply related
* Re: [PATCH 3/4] x86/PCI: Enable a 64bit BAR on AMD Family 15h (Models 30h-3fh) Processors
From: Christian König @ 2017-04-11 15:48 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: linux-pci, dri-devel, platform-driver-x86, amd-gfx, linux-kernel
In-Reply-To: <20170324154744.GE25380@bhelgaas-glaptop.roam.corp.google.com>
Am 24.03.2017 um 16:47 schrieb Bjorn Helgaas:
> On Mon, Mar 13, 2017 at 01:41:35PM +0100, Christian König wrote:
>> From: Christian König <christian.koenig@amd.com>
>>
>> Most BIOS don't enable this because of compatibility reasons.
> Can you give any more details here? Without more hints, it's hard to
> know whether any of the compatibility reasons might apply to Linux as
> well.
Unfortunately not, I could try to ask a few more people at AMD if they
know the background.
I was told that there are a few boards which offers that as a BIOS
option, but so far I haven't found any (and I have quite a few here).
My best guess is that older windows versions have a problem with that.
>> Manually enable a 64bit BAR of 64GB size so that we have
>> enough room for PCI devices.
> From the context, I'm guessing this is enabling a new 64GB window
> through the PCI host bridge?
Yes, exactly. Sorry for the confusion.
> That might be documented as a "BAR", but
> it's not anything the Linux PCI core would recognize as a BAR.
At least the AMD NB documentation calls this the host BARs. But I'm
perfectly fine with any terminology.
How about calling it host bridge window instead?
> I think the specs would envision this being done via an ACPI _SRS
> method on the PNP0A03 host bridge device. That would be a more
> generic path that would work on any host bridge. Did you explore that
> possibility? I would prefer to avoid adding device-specific code if
> that's possible.
I've checked quite a few boards, but none of them actually implements it
this way.
M$ is working on a new ACPI table to enable this vendor neutral, but I
guess that will still take a while.
I want to support this for all AMD CPU released in the past 5 years or
so, so we are going to deal with a bunch of older boards as well.
>> + pci_bus_add_resource(dev->bus, res, 0);
> We would need some sort of printk here to explain how this new window
> magically appeared.
Good point, consider this done.
But is this actually the right place of doing it? Or would you prefer
something to be added to the probing code?
I think those fixups are applied a bit later, aren't they?
Best regards,
Christian.
^ permalink raw reply
* Re: [PATCH 3/4] x86/PCI: Enable a 64bit BAR on AMD Family 15h (Models 30h-3fh) Processors
From: Christian König @ 2017-04-11 15:48 UTC (permalink / raw)
To: Bjorn Helgaas
Cc: linux-pci-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
amd-gfx-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
platform-driver-x86-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20170324154744.GE25380-1RhO1Y9PlrlHTL0Zs8A6p5iNqAH0jzoTYJqu5kTmcBRl57MIdRCFDg@public.gmane.org>
Am 24.03.2017 um 16:47 schrieb Bjorn Helgaas:
> On Mon, Mar 13, 2017 at 01:41:35PM +0100, Christian König wrote:
>> From: Christian König <christian.koenig@amd.com>
>>
>> Most BIOS don't enable this because of compatibility reasons.
> Can you give any more details here? Without more hints, it's hard to
> know whether any of the compatibility reasons might apply to Linux as
> well.
Unfortunately not, I could try to ask a few more people at AMD if they
know the background.
I was told that there are a few boards which offers that as a BIOS
option, but so far I haven't found any (and I have quite a few here).
My best guess is that older windows versions have a problem with that.
>> Manually enable a 64bit BAR of 64GB size so that we have
>> enough room for PCI devices.
> From the context, I'm guessing this is enabling a new 64GB window
> through the PCI host bridge?
Yes, exactly. Sorry for the confusion.
> That might be documented as a "BAR", but
> it's not anything the Linux PCI core would recognize as a BAR.
At least the AMD NB documentation calls this the host BARs. But I'm
perfectly fine with any terminology.
How about calling it host bridge window instead?
> I think the specs would envision this being done via an ACPI _SRS
> method on the PNP0A03 host bridge device. That would be a more
> generic path that would work on any host bridge. Did you explore that
> possibility? I would prefer to avoid adding device-specific code if
> that's possible.
I've checked quite a few boards, but none of them actually implements it
this way.
M$ is working on a new ACPI table to enable this vendor neutral, but I
guess that will still take a while.
I want to support this for all AMD CPU released in the past 5 years or
so, so we are going to deal with a bunch of older boards as well.
>> + pci_bus_add_resource(dev->bus, res, 0);
> We would need some sort of printk here to explain how this new window
> magically appeared.
Good point, consider this done.
But is this actually the right place of doing it? Or would you prefer
something to be added to the probing code?
I think those fixups are applied a bit later, aren't they?
Best regards,
Christian.
_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx
^ permalink raw reply
* Re: [PATCH] drm: Document code of conduct
From: Alex Deucher @ 2017-04-11 15:48 UTC (permalink / raw)
To: Luc Verhaegen
Cc: Daniel Vetter, Intel Graphics Development, Xorg Members List,
DRI Development
In-Reply-To: <20170411151450.GB31533@skynet.be>
On Tue, Apr 11, 2017 at 11:14 AM, Luc Verhaegen <libv@skynet.be> wrote:
> On Tue, Apr 11, 2017 at 04:58:51PM +0300, Jani Nikula wrote:
>> On Tue, 11 Apr 2017, Luc Verhaegen <libv@skynet.be> wrote:
>> > On Tue, Apr 11, 2017 at 03:36:32PM +0200, Daniel Vetter wrote:
>> >> On Tue, Apr 11, 2017 at 3:30 PM, Luc Verhaegen <libv@skynet.be> wrote:
>> >> > On Tue, Apr 11, 2017 at 03:24:04PM +0200, Daniel Vetter wrote:
>> >> >> On Tue, Apr 11, 2017 at 3:12 PM, Luc Verhaegen <libv@skynet.be> wrote:
>> >> >> > On Tue, Apr 11, 2017 at 08:48:15AM +0200, Daniel Vetter wrote:
>> >> >> >> freedesktop.org has adopted a formal&enforced code of conduct:
>> >> >> >>
>> >> >> >> https://www.fooishbar.org/blog/fdo-contributor-covenant/
>> >> >> >> https://www.freedesktop.org/wiki/CodeOfConduct/
>> >> >> >>
>> >> >> >> Besides formalizing things a bit more I don't think this changes
>> >> >> >> anything for us, we've already peer-enforced respectful and
>> >> >> >> constructive interactions since a long time. But it's good to document
>> >> >> >> things properly.
>> >> >> >>
>> >> >> >> Note: As Daniel Stone mentioned in the announcement fd.o admins
>> >> >> >> started chatting with the communities their hosting, which includs the
>> >> >> >
>> >> >> > "started" and "chatting"? That is very weakly formulated.
>> >> >>
>> >> >> Intentionally so ...
>> >> >>
>> >> >> >> X.org foundation board, to figure out how to fan out enforcement and
>> >> >> >
>> >> >> > This was not voted upon or even mentioned during the last board meeting.
>> >> >> > And i think the next board meeting is only in 2 days time. As such, this
>> >> >> > seems like it is not something that's officially sanctioned by the X.org
>> >> >> > foundation board, but you sure do try to make it sound like such.
>> >> >>
>> >> >> ... because it is not yet sanctioned by the board in any way. So not
>> >> >> exactly sure where you're reading this into my commit message, because
>> >> >> it wasn't my intention to make it sounds like this is sanctioned by
>> >> >> the xorg board officially, nor did I state that anywhere. I just said
>> >> >> that discussions already started to happen, that's really all there
>> >> >> is.
>> >> >
>> >> > Thanks for making that clear.
>> >>
>> >> Yeah I understand the confusion, since it wasn't clear that this mail
>> >> was written by me with my drm maintainer hat on, not me in my role as
>> >> xorg bod secretary. Nor me as an intel employee. I should have made
>> >> that clearer.
>> >
>> > I was not confused about that, especially since you mentioned the board.
>> > But this clearly was not something already approved by the X.org
>> > foundation board.
>>
>> Since there is a lot of "it" and "this" in both your and Daniel's
>> messages, without clarifying what you're both actually talking about, I
>> think for clarity it should be noted that, AFAIU, the decision to adopt
>> the CoC is up to the freedesktop.org admins, not the X.org board, and
>> the discussion about enforcing is to take place between the two.
>
> It's the way in which this is being done that makes me very weary of
> this code of conduct.
>
> It seems like a very unilateral move, quite likely by just a single
> person. There is no record of any prior discussion, not with the
> affected projects, not on any mailing list, not on the irc channels
> where i am on (and i doubt it is logged publicly anywhere). This commit
> Daniel Vetter just posted comes the closest to any discussion, wayland
> never was so lucky. This feels like the typical freedesktop.org move,
> and i am quite allergic to those as i and the projects i have been
> involved in have been the target of such unilateral decisions several
> times.
Isn't this thread the discussion? Daniel proposed a code of conduct
for drm. Let's discuss. AFAIK, the previous discussion was mostly
just reaching out to various contributors to see if they were
interested in the first place. I agree that the commit message
wording is confusing.
Alex
>
> I see the mentioning of the X.org foundation board here as an attempt to
> give this surprise Code of Conduct some gravitas which it didn't
> deserve, as it was far too easily debunked. The board of directors never
> voted on this, and i would like to see the emails of the discussion
> prior to this mentioning here. If there were any, they were not before
> the surprise wayland commit.
>
> I would welcome such a code of conduct though, if it had been the result
> of an honest, open and transparent community discussion. But that's not
> something i have often seen at freedesktop.org. And i have a feeling as
> to how it will be applied and who or what projects it will be applied
> to, and how transparent that process will be. If people would be
> interested in seeing this Code of Conduct retro-actively, i might have a
> few cases that i would want to bring up, though.
>
> Luc Verhaegen.
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply
* [PATCH v4 2/2] ASoC: stm32: add SAI driver
From: olivier moysan @ 2017-04-11 15:47 UTC (permalink / raw)
To: lgirdwood, broonie, perex, tiwai, mcoquelin.stm32,
alexandre.torgue, alsa-devel, robh, mark.rutland, devicetree,
linux-arm-kernel, kernel, linux-kernel, olivier.moysan
Cc: arnaud.pouliquen, benjamin.gaignard
In-Reply-To: <1491925646-29113-1-git-send-email-olivier.moysan@st.com>
This patch implements SAI ASoC driver for STM32.
Signed-off-by: olivier moysan <olivier.moysan@st.com>
---
sound/soc/Kconfig | 1 +
sound/soc/Makefile | 1 +
sound/soc/stm/Kconfig | 8 +
sound/soc/stm/Makefile | 6 +
sound/soc/stm/stm32_sai.c | 115 ++++++
sound/soc/stm/stm32_sai.h | 199 ++++++++++
sound/soc/stm/stm32_sai_sub.c | 881 ++++++++++++++++++++++++++++++++++++++++++
7 files changed, 1211 insertions(+)
create mode 100644 sound/soc/stm/Kconfig
create mode 100644 sound/soc/stm/Makefile
create mode 100644 sound/soc/stm/stm32_sai.c
create mode 100644 sound/soc/stm/stm32_sai.h
create mode 100644 sound/soc/stm/stm32_sai_sub.c
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 9df9658..c0abad2 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -64,6 +64,7 @@ source "sound/soc/sh/Kconfig"
source "sound/soc/sirf/Kconfig"
source "sound/soc/spear/Kconfig"
source "sound/soc/sti/Kconfig"
+source "sound/soc/stm/Kconfig"
source "sound/soc/sunxi/Kconfig"
source "sound/soc/tegra/Kconfig"
source "sound/soc/txx9/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 2f6aabb..39c27a5 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_SND_SOC) += sh/
obj-$(CONFIG_SND_SOC) += sirf/
obj-$(CONFIG_SND_SOC) += spear/
obj-$(CONFIG_SND_SOC) += sti/
+obj-$(CONFIG_SND_SOC) += stm/
obj-$(CONFIG_SND_SOC) += sunxi/
obj-$(CONFIG_SND_SOC) += tegra/
obj-$(CONFIG_SND_SOC) += txx9/
diff --git a/sound/soc/stm/Kconfig b/sound/soc/stm/Kconfig
new file mode 100644
index 0000000..a6372de
--- /dev/null
+++ b/sound/soc/stm/Kconfig
@@ -0,0 +1,8 @@
+menuconfig SND_SOC_STM32
+ tristate "STMicroelectronics STM32 SOC audio support"
+ depends on ARCH_STM32 || COMPILE_TEST
+ depends on SND_SOC
+ select SND_SOC_GENERIC_DMAENGINE_PCM
+ select REGMAP_MMIO
+ help
+ Say Y if you want to enable ASoC support for STM32
diff --git a/sound/soc/stm/Makefile b/sound/soc/stm/Makefile
new file mode 100644
index 0000000..e466a47
--- /dev/null
+++ b/sound/soc/stm/Makefile
@@ -0,0 +1,6 @@
+# SAI
+snd-soc-stm32-sai-sub-objs := stm32_sai_sub.o
+obj-$(CONFIG_SND_SOC_STM32) += snd-soc-stm32-sai-sub.o
+
+snd-soc-stm32-sai-objs := stm32_sai.o
+obj-$(CONFIG_SND_SOC_STM32) += snd-soc-stm32-sai.o
diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c
new file mode 100644
index 0000000..6159d66
--- /dev/null
+++ b/sound/soc/stm/stm32_sai.c
@@ -0,0 +1,115 @@
+/*
+ * STM32 ALSA SoC Digital Audio Interface (SAI) driver.
+ *
+ * Copyright (C) 2016, STMicroelectronics - All Rights Reserved
+ * Author(s): Olivier Moysan <olivier.moysan@st.com> for STMicroelectronics.
+ *
+ * License terms: GPL V2.0.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed 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/clk.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/reset.h>
+
+#include <sound/dmaengine_pcm.h>
+#include <sound/core.h>
+
+#include "stm32_sai.h"
+
+static const struct of_device_id stm32_sai_ids[] = {
+ { .compatible = "st,stm32f4-sai", .data = (void *)SAI_STM32F4 },
+ {}
+};
+
+static int stm32_sai_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct stm32_sai_data *sai;
+ struct reset_control *rst;
+ struct resource *res;
+ void __iomem *base;
+ const struct of_device_id *of_id;
+
+ sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
+ if (!sai)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ of_id = of_match_device(stm32_sai_ids, &pdev->dev);
+ if (of_id)
+ sai->version = (enum stm32_sai_version)of_id->data;
+ else
+ return -EINVAL;
+
+ sai->clk_x8k = devm_clk_get(&pdev->dev, "x8k");
+ if (IS_ERR(sai->clk_x8k)) {
+ dev_err(&pdev->dev, "missing x8k parent clock\n");
+ return PTR_ERR(sai->clk_x8k);
+ }
+
+ sai->clk_x11k = devm_clk_get(&pdev->dev, "x11k");
+ if (IS_ERR(sai->clk_x11k)) {
+ dev_err(&pdev->dev, "missing x11k parent clock\n");
+ return PTR_ERR(sai->clk_x11k);
+ }
+
+ /* init irqs */
+ sai->irq = platform_get_irq(pdev, 0);
+ if (sai->irq < 0) {
+ dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
+ return sai->irq;
+ }
+
+ /* reset */
+ rst = reset_control_get(&pdev->dev, NULL);
+ if (!IS_ERR(rst)) {
+ reset_control_assert(rst);
+ udelay(2);
+ reset_control_deassert(rst);
+ }
+
+ sai->pdev = pdev;
+ platform_set_drvdata(pdev, sai);
+
+ return of_platform_populate(np, NULL, NULL, &pdev->dev);
+}
+
+static int stm32_sai_remove(struct platform_device *pdev)
+{
+ of_platform_depopulate(&pdev->dev);
+
+ return 0;
+}
+
+MODULE_DEVICE_TABLE(of, stm32_sai_ids);
+
+static struct platform_driver stm32_sai_driver = {
+ .driver = {
+ .name = "st,stm32-sai",
+ .of_match_table = stm32_sai_ids,
+ },
+ .probe = stm32_sai_probe,
+ .remove = stm32_sai_remove,
+};
+
+module_platform_driver(stm32_sai_driver);
+
+MODULE_DESCRIPTION("STM32 Soc SAI Interface");
+MODULE_AUTHOR("Olivier Moysan <olivier.moysan@st.com>");
+MODULE_ALIAS("platform:st,stm32-sai");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/stm/stm32_sai.h b/sound/soc/stm/stm32_sai.h
new file mode 100644
index 0000000..270be93
--- /dev/null
+++ b/sound/soc/stm/stm32_sai.h
@@ -0,0 +1,199 @@
+/*
+ * STM32 ALSA SoC Digital Audio Interface (SAI) driver.
+ *
+ * Copyright (C) 2016, STMicroelectronics - All Rights Reserved
+ * Author(s): Olivier Moysan <olivier.moysan@st.com> for STMicroelectronics.
+ *
+ * License terms: GPL V2.0.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed 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.
+ */
+
+/******************** SAI Register Map **************************************/
+
+/* common register */
+#define STM_SAI_GCR 0x00
+
+/* Sub-block A&B registers offsets, relative to A&B sub-block addresses */
+#define STM_SAI_CR1_REGX 0x00 /* A offset: 0x04. B offset: 0x24 */
+#define STM_SAI_CR2_REGX 0x04
+#define STM_SAI_FRCR_REGX 0x08
+#define STM_SAI_SLOTR_REGX 0x0C
+#define STM_SAI_IMR_REGX 0x10
+#define STM_SAI_SR_REGX 0x14
+#define STM_SAI_CLRFR_REGX 0x18
+#define STM_SAI_DR_REGX 0x1C
+
+/******************** Bit definition for SAI_GCR register *******************/
+#define SAI_GCR_SYNCIN_SHIFT 0
+#define SAI_GCR_SYNCIN_MASK GENMASK(1, SAI_GCR_SYNCIN_SHIFT)
+#define SAI_GCR_SYNCIN_SET(x) ((x) << SAI_GCR_SYNCIN_SHIFT)
+
+#define SAI_GCR_SYNCOUT_SHIFT 4
+#define SAI_GCR_SYNCOUT_MASK GENMASK(5, SAI_GCR_SYNCOUT_SHIFT)
+#define SAI_GCR_SYNCOUT_SET(x) ((x) << SAI_GCR_SYNCOUT_SHIFT)
+
+/******************* Bit definition for SAI_XCR1 register *******************/
+#define SAI_XCR1_RX_TX_SHIFT 0
+#define SAI_XCR1_RX_TX BIT(SAI_XCR1_RX_TX_SHIFT)
+#define SAI_XCR1_SLAVE_SHIFT 1
+#define SAI_XCR1_SLAVE BIT(SAI_XCR1_SLAVE_SHIFT)
+
+#define SAI_XCR1_PRTCFG_SHIFT 2
+#define SAI_XCR1_PRTCFG_MASK GENMASK(3, SAI_XCR1_PRTCFG_SHIFT)
+#define SAI_XCR1_PRTCFG_SET(x) ((x) << SAI_XCR1_PRTCFG_SHIFT)
+
+#define SAI_XCR1_DS_SHIFT 5
+#define SAI_XCR1_DS_MASK GENMASK(7, SAI_XCR1_DS_SHIFT)
+#define SAI_XCR1_DS_SET(x) ((x) << SAI_XCR1_DS_SHIFT)
+
+#define SAI_XCR1_LSBFIRST_SHIFT 8
+#define SAI_XCR1_LSBFIRST BIT(SAI_XCR1_LSBFIRST_SHIFT)
+#define SAI_XCR1_CKSTR_SHIFT 9
+#define SAI_XCR1_CKSTR BIT(SAI_XCR1_CKSTR_SHIFT)
+
+#define SAI_XCR1_SYNCEN_SHIFT 10
+#define SAI_XCR1_SYNCEN_MASK GENMASK(11, SAI_XCR1_SYNCEN_SHIFT)
+#define SAI_XCR1_SYNCEN_SET(x) ((x) << SAI_XCR1_SYNCEN_SHIFT)
+
+#define SAI_XCR1_MONO_SHIFT 12
+#define SAI_XCR1_MONO BIT(SAI_XCR1_MONO_SHIFT)
+#define SAI_XCR1_OUTDRIV_SHIFT 13
+#define SAI_XCR1_OUTDRIV BIT(SAI_XCR1_OUTDRIV_SHIFT)
+#define SAI_XCR1_SAIEN_SHIFT 16
+#define SAI_XCR1_SAIEN BIT(SAI_XCR1_SAIEN_SHIFT)
+#define SAI_XCR1_DMAEN_SHIFT 17
+#define SAI_XCR1_DMAEN BIT(SAI_XCR1_DMAEN_SHIFT)
+#define SAI_XCR1_NODIV_SHIFT 19
+#define SAI_XCR1_NODIV BIT(SAI_XCR1_NODIV_SHIFT)
+
+#define SAI_XCR1_MCKDIV_SHIFT 20
+#define SAI_XCR1_MCKDIV_WIDTH 4
+#define SAI_XCR1_MCKDIV_MASK GENMASK(24, SAI_XCR1_MCKDIV_SHIFT)
+#define SAI_XCR1_MCKDIV_SET(x) ((x) << SAI_XCR1_MCKDIV_SHIFT)
+#define SAI_XCR1_MCKDIV_MAX ((1 << SAI_XCR1_MCKDIV_WIDTH) - 1)
+
+#define SAI_XCR1_OSR_SHIFT 26
+#define SAI_XCR1_OSR BIT(SAI_XCR1_OSR_SHIFT)
+
+/******************* Bit definition for SAI_XCR2 register *******************/
+#define SAI_XCR2_FTH_SHIFT 0
+#define SAI_XCR2_FTH_MASK GENMASK(2, SAI_XCR2_FTH_SHIFT)
+#define SAI_XCR2_FTH_SET(x) ((x) << SAI_XCR2_FTH_SHIFT)
+
+#define SAI_XCR2_FFLUSH_SHIFT 3
+#define SAI_XCR2_FFLUSH BIT(SAI_XCR2_FFLUSH_SHIFT)
+#define SAI_XCR2_TRIS_SHIFT 4
+#define SAI_XCR2_TRIS BIT(SAI_XCR2_TRIS_SHIFT)
+#define SAI_XCR2_MUTE_SHIFT 5
+#define SAI_XCR2_MUTE BIT(SAI_XCR2_MUTE_SHIFT)
+#define SAI_XCR2_MUTEVAL_SHIFT 6
+#define SAI_XCR2_MUTEVAL BIT(SAI_XCR2_MUTEVAL_SHIFT)
+
+#define SAI_XCR2_MUTECNT_SHIFT 7
+#define SAI_XCR2_MUTECNT_MASK GENMASK(12, SAI_XCR2_MUTECNT_SHIFT)
+#define SAI_XCR2_MUTECNT_SET(x) ((x) << SAI_XCR2_MUTECNT_SHIFT)
+
+#define SAI_XCR2_CPL_SHIFT 13
+#define SAI_XCR2_CPL BIT(SAI_XCR2_CPL_SHIFT)
+
+#define SAI_XCR2_COMP_SHIFT 14
+#define SAI_XCR2_COMP_MASK GENMASK(15, SAI_XCR2_COMP_SHIFT)
+#define SAI_XCR2_COMP_SET(x) ((x) << SAI_XCR2_COMP_SHIFT)
+
+/****************** Bit definition for SAI_XFRCR register *******************/
+#define SAI_XFRCR_FRL_SHIFT 0
+#define SAI_XFRCR_FRL_MASK GENMASK(7, SAI_XFRCR_FRL_SHIFT)
+#define SAI_XFRCR_FRL_SET(x) ((x) << SAI_XFRCR_FRL_SHIFT)
+
+#define SAI_XFRCR_FSALL_SHIFT 8
+#define SAI_XFRCR_FSALL_MASK GENMASK(14, SAI_XFRCR_FSALL_SHIFT)
+#define SAI_XFRCR_FSALL_SET(x) ((x) << SAI_XFRCR_FSALL_SHIFT)
+
+#define SAI_XFRCR_FSDEF_SHIFT 16
+#define SAI_XFRCR_FSDEF BIT(SAI_XFRCR_FSDEF_SHIFT)
+#define SAI_XFRCR_FSPOL_SHIFT 17
+#define SAI_XFRCR_FSPOL BIT(SAI_XFRCR_FSPOL_SHIFT)
+#define SAI_XFRCR_FSOFF_SHIFT 18
+#define SAI_XFRCR_FSOFF BIT(SAI_XFRCR_FSOFF_SHIFT)
+
+/****************** Bit definition for SAI_XSLOTR register ******************/
+#define SAI_XSLOTR_FBOFF_SHIFT 0
+#define SAI_XSLOTR_FBOFF_MASK GENMASK(4, SAI_XSLOTR_FBOFF_SHIFT)
+#define SAI_XSLOTR_FBOFF_SET(x) ((x) << SAI_XSLOTR_FBOFF_SHIFT)
+
+#define SAI_XSLOTR_SLOTSZ_SHIFT 6
+#define SAI_XSLOTR_SLOTSZ_MASK GENMASK(7, SAI_XSLOTR_SLOTSZ_SHIFT)
+#define SAI_XSLOTR_SLOTSZ_SET(x) ((x) << SAI_XSLOTR_SLOTSZ_SHIFT)
+
+#define SAI_XSLOTR_NBSLOT_SHIFT 8
+#define SAI_XSLOTR_NBSLOT_MASK GENMASK(11, SAI_XSLOTR_NBSLOT_SHIFT)
+#define SAI_XSLOTR_NBSLOT_SET(x) ((x) << SAI_XSLOTR_NBSLOT_SHIFT)
+
+#define SAI_XSLOTR_SLOTEN_SHIFT 16
+#define SAI_XSLOTR_SLOTEN_WIDTH 16
+#define SAI_XSLOTR_SLOTEN_MASK GENMASK(31, SAI_XSLOTR_SLOTEN_SHIFT)
+#define SAI_XSLOTR_SLOTEN_SET(x) ((x) << SAI_XSLOTR_SLOTEN_SHIFT)
+
+/******************* Bit definition for SAI_XIMR register *******************/
+#define SAI_XIMR_OVRUDRIE BIT(0)
+#define SAI_XIMR_MUTEDETIE BIT(1)
+#define SAI_XIMR_WCKCFGIE BIT(2)
+#define SAI_XIMR_FREQIE BIT(3)
+#define SAI_XIMR_CNRDYIE BIT(4)
+#define SAI_XIMR_AFSDETIE BIT(5)
+#define SAI_XIMR_LFSDETIE BIT(6)
+
+#define SAI_XIMR_SHIFT 0
+#define SAI_XIMR_MASK GENMASK(6, SAI_XIMR_SHIFT)
+
+/******************** Bit definition for SAI_XSR register *******************/
+#define SAI_XSR_OVRUDR BIT(0)
+#define SAI_XSR_MUTEDET BIT(1)
+#define SAI_XSR_WCKCFG BIT(2)
+#define SAI_XSR_FREQ BIT(3)
+#define SAI_XSR_CNRDY BIT(4)
+#define SAI_XSR_AFSDET BIT(5)
+#define SAI_XSR_LFSDET BIT(6)
+
+#define SAI_XSR_SHIFT 0
+#define SAI_XSR_MASK GENMASK(6, SAI_XSR_SHIFT)
+
+/****************** Bit definition for SAI_XCLRFR register ******************/
+#define SAI_XCLRFR_COVRUDR BIT(0)
+#define SAI_XCLRFR_CMUTEDET BIT(1)
+#define SAI_XCLRFR_CWCKCFG BIT(2)
+#define SAI_XCLRFR_CFREQ BIT(3)
+#define SAI_XCLRFR_CCNRDY BIT(4)
+#define SAI_XCLRFR_CAFSDET BIT(5)
+#define SAI_XCLRFR_CLFSDET BIT(6)
+
+#define SAI_XCLRFR_SHIFT 0
+#define SAI_XCLRFR_MASK GENMASK(6, SAI_XCLRFR_SHIFT)
+
+enum stm32_sai_version {
+ SAI_STM32F4
+};
+
+/**
+ * struct stm32_sai_data - private data of SAI instance driver
+ * @pdev: device data pointer
+ * @clk_x8k: SAI parent clock for sampling frequencies multiple of 8kHz
+ * @clk_x11k: SAI parent clock for sampling frequencies multiple of 11kHz
+ * @version: SOC version
+ * @irq: SAI interrupt line
+ */
+struct stm32_sai_data {
+ struct platform_device *pdev;
+ struct clk *clk_x8k;
+ struct clk *clk_x11k;
+ int version;
+ int irq;
+};
diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c
new file mode 100644
index 0000000..24b8874
--- /dev/null
+++ b/sound/soc/stm/stm32_sai_sub.c
@@ -0,0 +1,881 @@
+/*
+ * STM32 ALSA SoC Digital Audio Interface (SAI) driver.
+ *
+ * Copyright (C) 2016, STMicroelectronics - All Rights Reserved
+ * Author(s): Olivier Moysan <olivier.moysan@st.com> for STMicroelectronics.
+ *
+ * License terms: GPL V2.0.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed 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/clk.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+
+#include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/pcm_params.h>
+
+#include "stm32_sai.h"
+
+#define SAI_FREE_PROTOCOL 0x0
+
+#define SAI_SLOT_SIZE_AUTO 0x0
+#define SAI_SLOT_SIZE_16 0x1
+#define SAI_SLOT_SIZE_32 0x2
+
+#define SAI_DATASIZE_8 0x2
+#define SAI_DATASIZE_10 0x3
+#define SAI_DATASIZE_16 0x4
+#define SAI_DATASIZE_20 0x5
+#define SAI_DATASIZE_24 0x6
+#define SAI_DATASIZE_32 0x7
+
+#define STM_SAI_FIFO_SIZE 8
+#define STM_SAI_DAI_NAME_SIZE 15
+
+#define STM_SAI_IS_PLAYBACK(ip) ((ip)->dir == SNDRV_PCM_STREAM_PLAYBACK)
+#define STM_SAI_IS_CAPTURE(ip) ((ip)->dir == SNDRV_PCM_STREAM_CAPTURE)
+
+#define STM_SAI_A_ID 0x0
+#define STM_SAI_B_ID 0x1
+
+#define STM_SAI_BLOCK_NAME(x) (((x)->id == STM_SAI_A_ID) ? "A" : "B")
+
+/**
+ * struct stm32_sai_sub_data - private data of SAI sub block (block A or B)
+ * @pdev: device data pointer
+ * @regmap: SAI register map pointer
+ * @dma_params: dma configuration data for rx or tx channel
+ * @cpu_dai_drv: DAI driver data pointer
+ * @cpu_dai: DAI runtime data pointer
+ * @substream: PCM substream data pointer
+ * @pdata: SAI block parent data pointer
+ * @sai_ck: kernel clock feeding the SAI clock generator
+ * @phys_addr: SAI registers physical base address
+ * @mclk_rate: SAI block master clock frequency (Hz). set at init
+ * @id: SAI sub block id corresponding to sub-block A or B
+ * @dir: SAI block direction (playback or capture). set at init
+ * @master: SAI block mode flag. (true=master, false=slave) set at init
+ * @fmt: SAI block format. relevant only for custom protocols. set at init
+ * @sync: SAI block synchronization mode. (none, internal or external)
+ * @fs_length: frame synchronization length. depends on protocol settings
+ * @slots: rx or tx slot number
+ * @slot_width: rx or tx slot width in bits
+ * @slot_mask: rx or tx active slots mask. set at init or at runtime
+ * @data_size: PCM data width. corresponds to PCM substream width.
+ */
+struct stm32_sai_sub_data {
+ struct platform_device *pdev;
+ struct regmap *regmap;
+ struct snd_dmaengine_dai_dma_data dma_params;
+ struct snd_soc_dai_driver *cpu_dai_drv;
+ struct snd_soc_dai *cpu_dai;
+ struct snd_pcm_substream *substream;
+ struct stm32_sai_data *pdata;
+ struct clk *sai_ck;
+ dma_addr_t phys_addr;
+ unsigned int mclk_rate;
+ unsigned int id;
+ int dir;
+ bool master;
+ int fmt;
+ int sync;
+ int fs_length;
+ int slots;
+ int slot_width;
+ int slot_mask;
+ int data_size;
+};
+
+enum stm32_sai_fifo_th {
+ STM_SAI_FIFO_TH_EMPTY,
+ STM_SAI_FIFO_TH_QUARTER,
+ STM_SAI_FIFO_TH_HALF,
+ STM_SAI_FIFO_TH_3_QUARTER,
+ STM_SAI_FIFO_TH_FULL,
+};
+
+static bool stm32_sai_sub_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case STM_SAI_CR1_REGX:
+ case STM_SAI_CR2_REGX:
+ case STM_SAI_FRCR_REGX:
+ case STM_SAI_SLOTR_REGX:
+ case STM_SAI_IMR_REGX:
+ case STM_SAI_SR_REGX:
+ case STM_SAI_CLRFR_REGX:
+ case STM_SAI_DR_REGX:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool stm32_sai_sub_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case STM_SAI_DR_REGX:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool stm32_sai_sub_writeable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case STM_SAI_CR1_REGX:
+ case STM_SAI_CR2_REGX:
+ case STM_SAI_FRCR_REGX:
+ case STM_SAI_SLOTR_REGX:
+ case STM_SAI_IMR_REGX:
+ case STM_SAI_SR_REGX:
+ case STM_SAI_CLRFR_REGX:
+ case STM_SAI_DR_REGX:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config stm32_sai_sub_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = STM_SAI_DR_REGX,
+ .readable_reg = stm32_sai_sub_readable_reg,
+ .volatile_reg = stm32_sai_sub_volatile_reg,
+ .writeable_reg = stm32_sai_sub_writeable_reg,
+ .fast_io = true,
+};
+
+static irqreturn_t stm32_sai_isr(int irq, void *devid)
+{
+ struct stm32_sai_sub_data *sai = (struct stm32_sai_sub_data *)devid;
+ struct snd_pcm_substream *substream = sai->substream;
+ struct platform_device *pdev = sai->pdev;
+ unsigned int sr, imr, flags;
+ snd_pcm_state_t status = SNDRV_PCM_STATE_RUNNING;
+
+ regmap_read(sai->regmap, STM_SAI_IMR_REGX, &imr);
+ regmap_read(sai->regmap, STM_SAI_SR_REGX, &sr);
+
+ flags = sr & imr;
+ if (!flags)
+ return IRQ_NONE;
+
+ regmap_update_bits(sai->regmap, STM_SAI_CLRFR_REGX, SAI_XCLRFR_MASK,
+ SAI_XCLRFR_MASK);
+
+ if (flags & SAI_XIMR_OVRUDRIE) {
+ dev_err(&pdev->dev, "IRQ %s\n",
+ STM_SAI_IS_PLAYBACK(sai) ? "underrun" : "overrun");
+ status = SNDRV_PCM_STATE_XRUN;
+ }
+
+ if (flags & SAI_XIMR_MUTEDETIE)
+ dev_dbg(&pdev->dev, "IRQ mute detected\n");
+
+ if (flags & SAI_XIMR_WCKCFGIE) {
+ dev_err(&pdev->dev, "IRQ wrong clock configuration\n");
+ status = SNDRV_PCM_STATE_DISCONNECTED;
+ }
+
+ if (flags & SAI_XIMR_CNRDYIE)
+ dev_err(&pdev->dev, "IRQ Codec not ready\n");
+
+ if (flags & SAI_XIMR_AFSDETIE) {
+ dev_err(&pdev->dev, "IRQ Anticipated frame synchro\n");
+ status = SNDRV_PCM_STATE_XRUN;
+ }
+
+ if (flags & SAI_XIMR_LFSDETIE) {
+ dev_err(&pdev->dev, "IRQ Late frame synchro\n");
+ status = SNDRV_PCM_STATE_XRUN;
+ }
+
+ if (status != SNDRV_PCM_STATE_RUNNING) {
+ snd_pcm_stream_lock(substream);
+ snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+ snd_pcm_stream_unlock(substream);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int stm32_sai_set_sysclk(struct snd_soc_dai *cpu_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
+
+ if ((dir == SND_SOC_CLOCK_OUT) && sai->master) {
+ sai->mclk_rate = freq;
+ dev_dbg(cpu_dai->dev, "SAI MCLK frequency is %uHz\n", freq);
+ }
+
+ return 0;
+}
+
+static int stm32_sai_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask,
+ u32 rx_mask, int slots, int slot_width)
+{
+ struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ int slotr, slotr_mask, slot_size;
+
+ dev_dbg(cpu_dai->dev, "Masks tx/rx:%#x/%#x, slots:%d, width:%d\n",
+ tx_mask, rx_mask, slots, slot_width);
+
+ switch (slot_width) {
+ case 16:
+ slot_size = SAI_SLOT_SIZE_16;
+ break;
+ case 32:
+ slot_size = SAI_SLOT_SIZE_32;
+ break;
+ default:
+ slot_size = SAI_SLOT_SIZE_AUTO;
+ break;
+ }
+
+ slotr = SAI_XSLOTR_SLOTSZ_SET(slot_size) |
+ SAI_XSLOTR_NBSLOT_SET(slots - 1);
+ slotr_mask = SAI_XSLOTR_SLOTSZ_MASK | SAI_XSLOTR_NBSLOT_MASK;
+
+ /* tx/rx mask set in machine init, if slot number defined in DT */
+ if (STM_SAI_IS_PLAYBACK(sai)) {
+ sai->slot_mask = tx_mask;
+ slotr |= SAI_XSLOTR_SLOTEN_SET(tx_mask);
+ }
+
+ if (STM_SAI_IS_CAPTURE(sai)) {
+ sai->slot_mask = rx_mask;
+ slotr |= SAI_XSLOTR_SLOTEN_SET(rx_mask);
+ }
+
+ slotr_mask |= SAI_XSLOTR_SLOTEN_MASK;
+
+ regmap_update_bits(sai->regmap, STM_SAI_SLOTR_REGX, slotr_mask, slotr);
+
+ sai->slot_width = slot_width;
+ sai->slots = slots;
+
+ return 0;
+}
+
+static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
+{
+ struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ int cr1 = 0, frcr = 0;
+ int cr1_mask = 0, frcr_mask = 0;
+ int ret;
+
+ dev_dbg(cpu_dai->dev, "fmt %x\n", fmt);
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ /* SCK active high for all protocols */
+ case SND_SOC_DAIFMT_I2S:
+ cr1 |= SAI_XCR1_CKSTR;
+ frcr |= SAI_XFRCR_FSOFF | SAI_XFRCR_FSDEF;
+ break;
+ /* Left justified */
+ case SND_SOC_DAIFMT_MSB:
+ frcr |= SAI_XFRCR_FSPOL | SAI_XFRCR_FSDEF;
+ break;
+ /* Right justified */
+ case SND_SOC_DAIFMT_LSB:
+ frcr |= SAI_XFRCR_FSPOL | SAI_XFRCR_FSDEF;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ frcr |= SAI_XFRCR_FSPOL | SAI_XFRCR_FSOFF;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ frcr |= SAI_XFRCR_FSPOL;
+ break;
+ default:
+ dev_err(cpu_dai->dev, "Unsupported protocol %#x\n",
+ fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+ return -EINVAL;
+ }
+
+ cr1_mask |= SAI_XCR1_PRTCFG_MASK | SAI_XCR1_CKSTR;
+ frcr_mask |= SAI_XFRCR_FSPOL | SAI_XFRCR_FSOFF |
+ SAI_XFRCR_FSDEF;
+
+ /* DAI clock strobing. Invert setting previously set */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ cr1 ^= SAI_XCR1_CKSTR;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ frcr ^= SAI_XFRCR_FSPOL;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ /* Invert fs & sck */
+ cr1 ^= SAI_XCR1_CKSTR;
+ frcr ^= SAI_XFRCR_FSPOL;
+ break;
+ default:
+ dev_err(cpu_dai->dev, "Unsupported strobing %#x\n",
+ fmt & SND_SOC_DAIFMT_INV_MASK);
+ return -EINVAL;
+ }
+ cr1_mask |= SAI_XCR1_CKSTR;
+ frcr_mask |= SAI_XFRCR_FSPOL;
+
+ regmap_update_bits(sai->regmap, STM_SAI_FRCR_REGX, frcr_mask, frcr);
+
+ /* DAI clock master masks */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* codec is master */
+ cr1 |= SAI_XCR1_SLAVE;
+ sai->master = false;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ sai->master = true;
+ break;
+ default:
+ dev_err(cpu_dai->dev, "Unsupported mode %#x\n",
+ fmt & SND_SOC_DAIFMT_MASTER_MASK);
+ return -EINVAL;
+ }
+ cr1_mask |= SAI_XCR1_SLAVE;
+
+ ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, cr1_mask, cr1);
+ if (ret < 0) {
+ dev_err(cpu_dai->dev, "Failed to update CR1 register\n");
+ return ret;
+ }
+
+ sai->fmt = fmt;
+
+ return 0;
+}
+
+static int stm32_sai_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ int imr, cr2, ret;
+
+ sai->substream = substream;
+
+ ret = clk_prepare_enable(sai->sai_ck);
+ if (ret < 0) {
+ dev_err(cpu_dai->dev, "Failed to enable clock: %d\n", ret);
+ return ret;
+ }
+
+ /* Enable ITs */
+ regmap_update_bits(sai->regmap, STM_SAI_SR_REGX,
+ SAI_XSR_MASK, (unsigned int)~SAI_XSR_MASK);
+
+ regmap_update_bits(sai->regmap, STM_SAI_CLRFR_REGX,
+ SAI_XCLRFR_MASK, SAI_XCLRFR_MASK);
+
+ imr = SAI_XIMR_OVRUDRIE;
+ if (STM_SAI_IS_CAPTURE(sai)) {
+ regmap_read(sai->regmap, STM_SAI_CR2_REGX, &cr2);
+ if (cr2 & SAI_XCR2_MUTECNT_MASK)
+ imr |= SAI_XIMR_MUTEDETIE;
+ }
+
+ if (sai->master)
+ imr |= SAI_XIMR_WCKCFGIE;
+ else
+ imr |= SAI_XIMR_AFSDETIE | SAI_XIMR_LFSDETIE;
+
+ regmap_update_bits(sai->regmap, STM_SAI_IMR_REGX,
+ SAI_XIMR_MASK, imr);
+
+ return 0;
+}
+
+static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai,
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ int cr1, cr1_mask, ret;
+ int fth = STM_SAI_FIFO_TH_HALF;
+
+ /* FIFO config */
+ regmap_update_bits(sai->regmap, STM_SAI_CR2_REGX,
+ SAI_XCR2_FFLUSH | SAI_XCR2_FTH_MASK,
+ SAI_XCR2_FFLUSH | SAI_XCR2_FTH_SET(fth));
+
+ /* Mode, data format and channel config */
+ cr1 = SAI_XCR1_PRTCFG_SET(SAI_FREE_PROTOCOL);
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S8:
+ cr1 |= SAI_XCR1_DS_SET(SAI_DATASIZE_8);
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ cr1 |= SAI_XCR1_DS_SET(SAI_DATASIZE_16);
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ cr1 |= SAI_XCR1_DS_SET(SAI_DATASIZE_32);
+ break;
+ default:
+ dev_err(cpu_dai->dev, "Data format not supported");
+ return -EINVAL;
+ }
+ cr1_mask = SAI_XCR1_DS_MASK | SAI_XCR1_PRTCFG_MASK;
+
+ cr1_mask |= SAI_XCR1_RX_TX;
+ if (STM_SAI_IS_CAPTURE(sai))
+ cr1 |= SAI_XCR1_RX_TX;
+
+ cr1_mask |= SAI_XCR1_MONO;
+ if ((sai->slots == 2) && (params_channels(params) == 1))
+ cr1 |= SAI_XCR1_MONO;
+
+ ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, cr1_mask, cr1);
+ if (ret < 0) {
+ dev_err(cpu_dai->dev, "Failed to update CR1 register\n");
+ return ret;
+ }
+
+ /* DMA config */
+ sai->dma_params.maxburst = STM_SAI_FIFO_SIZE * fth / sizeof(u32);
+ snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)&sai->dma_params);
+
+ return 0;
+}
+
+static int stm32_sai_set_slots(struct snd_soc_dai *cpu_dai)
+{
+ struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ int slotr, slot_sz;
+
+ regmap_read(sai->regmap, STM_SAI_SLOTR_REGX, &slotr);
+
+ /*
+ * If SLOTSZ is set to auto in SLOTR, align slot width on data size
+ * By default slot width = data size, if not forced from DT
+ */
+ slot_sz = slotr & SAI_XSLOTR_SLOTSZ_MASK;
+ if (slot_sz == SAI_XSLOTR_SLOTSZ_SET(SAI_SLOT_SIZE_AUTO))
+ sai->slot_width = sai->data_size;
+
+ if (sai->slot_width < sai->data_size) {
+ dev_err(cpu_dai->dev,
+ "Data size %d larger than slot width\n",
+ sai->data_size);
+ return -EINVAL;
+ }
+
+ /* Slot number is set to 2, if not specified in DT */
+ if (!sai->slots)
+ sai->slots = 2;
+
+ /* The number of slots in the audio frame is equal to NBSLOT[3:0] + 1*/
+ regmap_update_bits(sai->regmap, STM_SAI_SLOTR_REGX,
+ SAI_XSLOTR_NBSLOT_MASK,
+ SAI_XSLOTR_NBSLOT_SET((sai->slots - 1)));
+
+ /* Set default slots mask if not already set from DT */
+ if (!(slotr & SAI_XSLOTR_SLOTEN_MASK)) {
+ sai->slot_mask = (1 << sai->slots) - 1;
+ regmap_update_bits(sai->regmap,
+ STM_SAI_SLOTR_REGX, SAI_XSLOTR_SLOTEN_MASK,
+ SAI_XSLOTR_SLOTEN_SET(sai->slot_mask));
+ }
+
+ dev_dbg(cpu_dai->dev, "Slots %d, slot width %d\n",
+ sai->slots, sai->slot_width);
+
+ return 0;
+}
+
+static void stm32_sai_set_frame(struct snd_soc_dai *cpu_dai)
+{
+ struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ int fs_active, offset, format;
+ int frcr, frcr_mask;
+
+ format = sai->fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+ sai->fs_length = sai->slot_width * sai->slots;
+
+ fs_active = sai->fs_length / 2;
+ if ((format == SND_SOC_DAIFMT_DSP_A) ||
+ (format == SND_SOC_DAIFMT_DSP_B))
+ fs_active = 1;
+
+ frcr = SAI_XFRCR_FRL_SET((sai->fs_length - 1));
+ frcr |= SAI_XFRCR_FSALL_SET((fs_active - 1));
+ frcr_mask = SAI_XFRCR_FRL_MASK | SAI_XFRCR_FSALL_MASK;
+
+ dev_dbg(cpu_dai->dev, "Frame length %d, frame active %d\n",
+ sai->fs_length, fs_active);
+
+ regmap_update_bits(sai->regmap, STM_SAI_FRCR_REGX, frcr_mask, frcr);
+
+ if ((sai->fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_LSB) {
+ offset = sai->slot_width - sai->data_size;
+
+ regmap_update_bits(sai->regmap, STM_SAI_SLOTR_REGX,
+ SAI_XSLOTR_FBOFF_MASK,
+ SAI_XSLOTR_FBOFF_SET(offset));
+ }
+}
+
+static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai,
+ struct snd_pcm_hw_params *params)
+{
+ struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ int cr1, mask, div = 0;
+ int sai_clk_rate, ret;
+
+ if (!sai->mclk_rate) {
+ dev_err(cpu_dai->dev, "Mclk rate is null\n");
+ return -EINVAL;
+ }
+
+ if (!(params_rate(params) % 11025))
+ clk_set_parent(sai->sai_ck, sai->pdata->clk_x11k);
+ else
+ clk_set_parent(sai->sai_ck, sai->pdata->clk_x8k);
+ sai_clk_rate = clk_get_rate(sai->sai_ck);
+
+ /*
+ * mclk_rate = 256 * fs
+ * MCKDIV = 0 if sai_ck < 3/2 * mclk_rate
+ * MCKDIV = sai_ck / (2 * mclk_rate) otherwise
+ */
+ if (2 * sai_clk_rate >= 3 * sai->mclk_rate)
+ div = DIV_ROUND_CLOSEST(sai_clk_rate, 2 * sai->mclk_rate);
+
+ if (div > SAI_XCR1_MCKDIV_MAX) {
+ dev_err(cpu_dai->dev, "Divider %d out of range\n", div);
+ return -EINVAL;
+ }
+ dev_dbg(cpu_dai->dev, "SAI clock %d, divider %d\n", sai_clk_rate, div);
+
+ mask = SAI_XCR1_MCKDIV_MASK;
+ cr1 = SAI_XCR1_MCKDIV_SET(div);
+ ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, mask, cr1);
+ if (ret < 0) {
+ dev_err(cpu_dai->dev, "Failed to update CR1 register\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int stm32_sai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ int ret;
+
+ sai->data_size = params_width(params);
+
+ ret = stm32_sai_set_slots(cpu_dai);
+ if (ret < 0)
+ return ret;
+ stm32_sai_set_frame(cpu_dai);
+
+ ret = stm32_sai_set_config(cpu_dai, substream, params);
+ if (ret)
+ return ret;
+
+ if (sai->master)
+ ret = stm32_sai_configure_clock(cpu_dai, params);
+
+ return ret;
+}
+
+static int stm32_sai_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
+ int ret;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ dev_dbg(cpu_dai->dev, "Enable DMA and SAI\n");
+
+ regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX,
+ SAI_XCR1_DMAEN, SAI_XCR1_DMAEN);
+
+ /* Enable SAI */
+ ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX,
+ SAI_XCR1_SAIEN, SAI_XCR1_SAIEN);
+ if (ret < 0)
+ dev_err(cpu_dai->dev, "Failed to update CR1 register\n");
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_STOP:
+ dev_dbg(cpu_dai->dev, "Disable DMA and SAI\n");
+
+ regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX,
+ SAI_XCR1_DMAEN,
+ (unsigned int)~SAI_XCR1_DMAEN);
+
+ ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX,
+ SAI_XCR1_SAIEN,
+ (unsigned int)~SAI_XCR1_SAIEN);
+ if (ret < 0)
+ dev_err(cpu_dai->dev, "Failed to update CR1 register\n");
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static void stm32_sai_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai);
+
+ regmap_update_bits(sai->regmap, STM_SAI_IMR_REGX, SAI_XIMR_MASK, 0);
+
+ clk_disable_unprepare(sai->sai_ck);
+ sai->substream = NULL;
+}
+
+static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai)
+{
+ struct stm32_sai_sub_data *sai = dev_get_drvdata(cpu_dai->dev);
+
+ sai->dma_params.addr = (dma_addr_t)(sai->phys_addr + STM_SAI_DR_REGX);
+ sai->dma_params.maxburst = 1;
+ /* Buswidth will be set by framework at runtime */
+ sai->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED;
+
+ if (STM_SAI_IS_PLAYBACK(sai))
+ snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params, NULL);
+ else
+ snd_soc_dai_init_dma_data(cpu_dai, NULL, &sai->dma_params);
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops stm32_sai_pcm_dai_ops = {
+ .set_sysclk = stm32_sai_set_sysclk,
+ .set_fmt = stm32_sai_set_dai_fmt,
+ .set_tdm_slot = stm32_sai_set_dai_tdm_slot,
+ .startup = stm32_sai_startup,
+ .hw_params = stm32_sai_hw_params,
+ .trigger = stm32_sai_trigger,
+ .shutdown = stm32_sai_shutdown,
+};
+
+static const struct snd_pcm_hardware stm32_sai_pcm_hw = {
+ .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP,
+ .buffer_bytes_max = 8 * PAGE_SIZE,
+ .period_bytes_min = 1024, /* 5ms at 48kHz */
+ .period_bytes_max = PAGE_SIZE,
+ .periods_min = 2,
+ .periods_max = 8,
+};
+
+static struct snd_soc_dai_driver stm32_sai_playback_dai[] = {
+{
+ .probe = stm32_sai_dai_probe,
+ .id = 1, /* avoid call to fmt_single_name() */
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ /* DMA does not support 24 bits transfers */
+ .formats =
+ SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &stm32_sai_pcm_dai_ops,
+ }
+};
+
+static struct snd_soc_dai_driver stm32_sai_capture_dai[] = {
+{
+ .probe = stm32_sai_dai_probe,
+ .id = 1, /* avoid call to fmt_single_name() */
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ /* DMA does not support 24 bits transfers */
+ .formats =
+ SNDRV_PCM_FMTBIT_S8 |
+ SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
+ },
+ .ops = &stm32_sai_pcm_dai_ops,
+ }
+};
+
+static const struct snd_dmaengine_pcm_config stm32_sai_pcm_config = {
+ .pcm_hardware = &stm32_sai_pcm_hw,
+ .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
+};
+
+static const struct snd_soc_component_driver stm32_component = {
+ .name = "stm32-sai",
+};
+
+static const struct of_device_id stm32_sai_sub_ids[] = {
+ { .compatible = "st,stm32-sai-sub-a",
+ .data = (void *)STM_SAI_A_ID},
+ { .compatible = "st,stm32-sai-sub-b",
+ .data = (void *)STM_SAI_B_ID},
+ {}
+};
+MODULE_DEVICE_TABLE(of, stm32_sai_sub_ids);
+
+static int stm32_sai_sub_parse_of(struct platform_device *pdev,
+ struct stm32_sai_sub_data *sai)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct resource *res;
+ void __iomem *base;
+
+ if (!np)
+ return -ENODEV;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ sai->phys_addr = res->start;
+ sai->regmap = devm_regmap_init_mmio(&pdev->dev, base,
+ &stm32_sai_sub_regmap_config);
+
+ /* Get direction property */
+ if (of_property_match_string(np, "dma-names", "tx") >= 0) {
+ sai->dir = SNDRV_PCM_STREAM_PLAYBACK;
+ } else if (of_property_match_string(np, "dma-names", "rx") >= 0) {
+ sai->dir = SNDRV_PCM_STREAM_CAPTURE;
+ } else {
+ dev_err(&pdev->dev, "Unsupported direction\n");
+ return -EINVAL;
+ }
+
+ sai->sai_ck = devm_clk_get(&pdev->dev, "sai_ck");
+ if (IS_ERR(sai->sai_ck)) {
+ dev_err(&pdev->dev, "Missing kernel clock sai_ck\n");
+ return PTR_ERR(sai->sai_ck);
+ }
+
+ return 0;
+}
+
+static int stm32_sai_sub_dais_init(struct platform_device *pdev,
+ struct stm32_sai_sub_data *sai)
+{
+ sai->cpu_dai_drv = devm_kzalloc(&pdev->dev,
+ sizeof(struct snd_soc_dai_driver),
+ GFP_KERNEL);
+ if (!sai->cpu_dai_drv)
+ return -ENOMEM;
+
+ sai->cpu_dai_drv->name = dev_name(&pdev->dev);
+ if (STM_SAI_IS_PLAYBACK(sai)) {
+ memcpy(sai->cpu_dai_drv, &stm32_sai_playback_dai,
+ sizeof(stm32_sai_playback_dai));
+ sai->cpu_dai_drv->playback.stream_name = sai->cpu_dai_drv->name;
+ } else {
+ memcpy(sai->cpu_dai_drv, &stm32_sai_capture_dai,
+ sizeof(stm32_sai_capture_dai));
+ sai->cpu_dai_drv->capture.stream_name = sai->cpu_dai_drv->name;
+ }
+
+ return 0;
+}
+
+static int stm32_sai_sub_probe(struct platform_device *pdev)
+{
+ struct stm32_sai_sub_data *sai;
+ const struct of_device_id *of_id;
+ int ret;
+
+ sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
+ if (!sai)
+ return -ENOMEM;
+
+ of_id = of_match_device(stm32_sai_sub_ids, &pdev->dev);
+ if (!of_id)
+ return -EINVAL;
+ sai->id = (uintptr_t)of_id->data;
+
+ sai->pdev = pdev;
+ platform_set_drvdata(pdev, sai);
+
+ sai->pdata = dev_get_drvdata(pdev->dev.parent);
+ if (!sai->pdata) {
+ dev_err(&pdev->dev, "Parent device data not available\n");
+ return -EINVAL;
+ }
+
+ ret = stm32_sai_sub_parse_of(pdev, sai);
+ if (ret)
+ return ret;
+
+ ret = stm32_sai_sub_dais_init(pdev, sai);
+ if (ret)
+ return ret;
+
+ ret = devm_request_irq(&pdev->dev, sai->pdata->irq, stm32_sai_isr,
+ IRQF_SHARED, dev_name(&pdev->dev), sai);
+ if (ret) {
+ dev_err(&pdev->dev, "IRQ request returned %d\n", ret);
+ return ret;
+ }
+
+ ret = devm_snd_soc_register_component(&pdev->dev, &stm32_component,
+ sai->cpu_dai_drv, 1);
+ if (ret)
+ return ret;
+
+ ret = devm_snd_dmaengine_pcm_register(&pdev->dev,
+ &stm32_sai_pcm_config, 0);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not register pcm dma\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct platform_driver stm32_sai_sub_driver = {
+ .driver = {
+ .name = "st,stm32-sai-sub",
+ .of_match_table = stm32_sai_sub_ids,
+ },
+ .probe = stm32_sai_sub_probe,
+};
+
+module_platform_driver(stm32_sai_sub_driver);
+
+MODULE_DESCRIPTION("STM32 Soc SAI sub-block Interface");
+MODULE_AUTHOR("Olivier Moysan <olivier.moysan@st.com>");
+MODULE_ALIAS("platform:st,stm32-sai-sub");
+MODULE_LICENSE("GPL v2");
--
1.9.1
^ permalink raw reply related
* [PATCH v4 1/2] ASoC: stm32: add bindings for SAI
From: olivier moysan @ 2017-04-11 15:47 UTC (permalink / raw)
To: lgirdwood, broonie, perex, tiwai, mcoquelin.stm32,
alexandre.torgue, alsa-devel, robh, mark.rutland, devicetree,
linux-arm-kernel, kernel, linux-kernel, olivier.moysan
Cc: arnaud.pouliquen, benjamin.gaignard
In-Reply-To: <1491925646-29113-1-git-send-email-olivier.moysan@st.com>
This patch adds documentation of device tree bindings for the
STM32 SAI ASoC driver.
Signed-off-by: olivier moysan <olivier.moysan@st.com>
---
.../devicetree/bindings/sound/st,stm32-sai.txt | 89 ++++++++++++++++++++++
1 file changed, 89 insertions(+)
create mode 100644 Documentation/devicetree/bindings/sound/st,stm32-sai.txt
diff --git a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt
new file mode 100644
index 0000000..c59a3d7
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt
@@ -0,0 +1,89 @@
+STMicroelectronics STM32 Serial Audio Interface (SAI).
+
+The SAI interface (Serial Audio Interface) offers a wide set of audio protocols
+as I2S standards, LSB or MSB-justified, PCM/DSP, TDM, and AC'97.
+The SAI contains two independent audio sub-blocks. Each sub-block has
+its own clock generator and I/O lines controller.
+
+Required properties:
+ - compatible: Should be "st,stm32f4-sai"
+ - reg: Base address and size of SAI common register set.
+ - clocks: Must contain phandle and clock specifier pairs for each entry
+ in clock-names.
+ - clock-names: Must contain "x8k" and "x11k"
+ "x8k": SAI parent clock for sampling rates multiple of 8kHz.
+ "x11k": SAI parent clock for sampling rates multiple of 11.025kHz.
+ - interrupts: cpu DAI interrupt line shared by SAI sub-blocks
+
+Optional properties:
+ - resets: Reference to a reset controller asserting the SAI
+
+SAI subnodes:
+Two subnodes corresponding to SAI sub-block instances A et B can be defined.
+Subnode can be omitted for unsused sub-block.
+
+SAI subnodes required properties:
+ - compatible: Should be "st,stm32-sai-sub-a" or "st,stm32-sai-sub-b"
+ for SAI sub-block A or B respectively.
+ - reg: Base address and size of SAI sub-block register set.
+ - clocks: Must contain one phandle and clock specifier pair
+ for sai_ck which feeds the internal clock generator.
+ - clock-names: Must contain "sai_ck".
+ - dmas: see Documentation/devicetree/bindings/dma/stm32-dma.txt
+ - dma-names: identifier string for each DMA request line
+ "tx": if sai sub-block is configured as playback DAI
+ "rx": if sai sub-block is configured as capture DAI
+ - pinctrl-names: should contain only value "default"
+ - pinctrl-0: see Documentation/devicetree/bindings/pinctrl/pinctrl-stm32.txt
+
+Example:
+sound_card {
+ compatible = "audio-graph-card";
+ dais = <&sai1b_port>;
+};
+
+sai1: sai1@40015800 {
+ compatible = "st,stm32f4-sai";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ reg = <0x40015800 0x4>;
+ clocks = <&rcc 1 CLK_SAIQ_PDIV>, <&rcc 1 CLK_I2SQ_PDIV>;
+ clock-names = "x8k", "x11k";
+ interrupts = <87>;
+
+ sai1b: audio-controller@40015824 {
+ #sound-dai-cells = <0>;
+ compatible = "st,stm32-sai-sub-b";
+ reg = <0x40015824 0x1C>;
+ clocks = <&rcc 1 CLK_SAI2>;
+ clock-names = "sai_ck";
+ dmas = <&dma2 5 0 0x400 0x0>;
+ dma-names = "tx";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_sai1b>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sai1b_port: port@0 {
+ reg = <0>;
+ cpu_endpoint: endpoint {
+ remote-endpoint = <&codec_endpoint>;
+ audio-graph-card,format = "i2s";
+ audio-graph-card,bitclock-master = <&codec_endpoint>;
+ audio-graph-card,frame-master = <&codec_endpoint>;
+ };
+ };
+ };
+ };
+};
+
+audio-codec {
+ codec_port: port {
+ codec_endpoint: endpoint {
+ remote-endpoint = <&cpu_endpoint>;
+ };
+ };
+};
--
1.9.1
^ permalink raw reply related
* [PATCH v4 0/2] Add STM32 SAI support
From: olivier moysan @ 2017-04-11 15:47 UTC (permalink / raw)
To: lgirdwood, broonie, perex, tiwai, mcoquelin.stm32,
alexandre.torgue, alsa-devel, robh, mark.rutland, devicetree,
linux-arm-kernel, kernel, linux-kernel, olivier.moysan
Cc: arnaud.pouliquen, benjamin.gaignard
This patch-set handles the Serial Audio Interface (SAI) IP on STM32 platforms.
The SAI IP is composed of two Sub-block A and B. (see the figure below)
Each sub-block makes use of individual and shared resources.
Shared resources:
- Reset line. Reset common and sub-block registers.
- Bus interface clocks. This clock is not exposed in device
as it it managed by clock driver, according to kernel clocks gating.
- Common register. SAI IP exhibits a common configuration register
to manage synchronization modes. NB: These modes are not yet implemented
in this version of the SAI driver.
- Interrupt. Sub-blocks have their own interrupt status registers but they
share the same interrupt line.
Individual resources:
- Register set
- DMA request line.
- Communication interface.
Each sub-block has its own GPIOs and associated bus lines.
- Kernel clock.
Each sub-block has its own dedicated clock for its communication interface.
To reflect this architecture Sub-block A and B are handled by 2 child devices.
Sub-block A and B devices can be configured independently either as transmitter
or receiver. A PCM device is associated to each sub-block.
A sub-block has to select the appropriated parent clock at runtime,
depending on the audio stream sampling rate to be played or captured.
Two parent clocks must be provided to support sampling rates multiples
of 8 kHz or 11.025kHz.
Interface clock +--------------------------------+
+---------------> | SAI IP |
Reset | +-----------------+ |
+---------------> | |common registers | |
| +-----------------+ |
| |
| +----------------------+ |
| | Sub-block A | |
Kernel clock A | | | | Bus A
+--------------------> | +----------------+ +---------------->
| | |A registers | | |
| | +----------------+ | |
| +----------------------+ |
| |
| +----------------------+ |
| | Sub-block B | |
Kernel clock B | | | | Bus B
+--------------------> | +----------------+ +----------------->
| | |B registers | | |
| | +----------------+ | |
| +----------------------+ |
| |
+--------------------------------+
v3 -> v4
Apply minor changes from Peter review
olivier moysan (2):
ASoC: stm32: add bindings for SAI
ASoC: stm32: add SAI driver
.../devicetree/bindings/sound/st,stm32-sai.txt | 89 +++
sound/soc/Kconfig | 1 +
sound/soc/Makefile | 1 +
sound/soc/stm/Kconfig | 8 +
sound/soc/stm/Makefile | 6 +
sound/soc/stm/stm32_sai.c | 115 +++
sound/soc/stm/stm32_sai.h | 199 +++++
sound/soc/stm/stm32_sai_sub.c | 881 +++++++++++++++++++++
8 files changed, 1300 insertions(+)
create mode 100644 Documentation/devicetree/bindings/sound/st,stm32-sai.txt
create mode 100644 sound/soc/stm/Kconfig
create mode 100644 sound/soc/stm/Makefile
create mode 100644 sound/soc/stm/stm32_sai.c
create mode 100644 sound/soc/stm/stm32_sai.h
create mode 100644 sound/soc/stm/stm32_sai_sub.c
--
1.9.1
^ permalink raw reply
* Re: [Qemu-devel] [PATCH for-2.9?] block/io: Comment out permission assertions
From: Peter Maydell @ 2017-04-11 15:47 UTC (permalink / raw)
To: Max Reitz
Cc: Qemu-block, Kevin Wolf, Laurent Vivier, Fam Zheng,
QEMU Developers, Stefan Hajnoczi
In-Reply-To: <20170411145050.31290-1-mreitz@redhat.com>
On 11 April 2017 at 15:50, Max Reitz <mreitz@redhat.com> wrote:
> In case of block migration, there may be writes to BlockBackends that do
> not have the write permission taken. Before this issue is fixed (which
> is not going to happen in 2.9), we therefore cannot assert that this is
> the case.
>
> Suggested-by: Kevin Wolf <kwolf@redhat.com>
> Signed-off-by: Max Reitz <mreitz@redhat.com>
Applied, thanks.
-- PMM
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.