* [GIT PULL 2/5] memory: tegra: Changes for v4.18-rc1
From: Dmitry Osipenko @ 2018-05-25 12:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180525121158.dk5hv525ilakmshz@localhost>
On 25.05.2018 15:11, Olof Johansson wrote:
> On Fri, May 18, 2018 at 04:22:42PM +0200, Thierry Reding wrote:
>> Hi ARM SoC maintainers,
>>
>> The following changes since commit 60cc43fc888428bb2f18f08997432d426a243338:
>>
>> Linux 4.17-rc1 (2018-04-15 18:24:20 -0700)
>>
>> are available in the Git repository at:
>>
>> git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux.git tags/tegra-for-4.18-memory
>>
>> for you to fetch changes up to bef89a8d81ca97aca864778746b110cf52847868:
>>
>> memory: tegra: Remove Tegra114 SATA and AFI reset definitions (2018-05-18 12:33:02 +0200)
>>
>> Thanks,
>> Thierry
>>
>> ----------------------------------------------------------------
>> memory: tegra: Changes for v4.18-rc1
>>
>> This contains some cleanup of the memory controller driver as well as
>> unification work to share more code between Tegra20 and later SoC
>> generations. Also included are an implementation for the hot resets
>> functionality by the memory controller which is required to properly
>> reset busy hardware.
>>
>> ----------------------------------------------------------------
>> Dmitry Osipenko (14):
>> dt-bindings: memory: tegra: Add hot resets definitions
>> memory: tegra: Do not handle spurious interrupts
>> memory: tegra: Setup interrupts mask before requesting IRQ
>> memory: tegra: Apply interrupts mask per SoC
>> memory: tegra: Remove unused headers inclusions
>> memory: tegra: Squash tegra20-mc into common tegra-mc driver
>> memory: tegra: Introduce memory client hot reset
>> memory: tegra: Add Tegra20 memory controller hot resets
>> memory: tegra: Add Tegra30 memory controller hot resets
>> memory: tegra: Add Tegra114 memory controller hot resets
>> memory: tegra: Add Tegra124 memory controller hot resets
>> memory: tegra: Register SMMU after MC driver became ready
>> dt-bindings: memory: tegra: Remove Tegra114 SATA and AFI reset definitions
>> memory: tegra: Remove Tegra114 SATA and AFI reset definitions
>>
>> Thierry Reding (1):
>> memory: tegra: Add Tegra210 memory controller hot resets
>
> Looks like this is just additional/proper resets, are there any backwards
> compatibility concerns with older device trees or new assumptions of properties
> that should be handled?
Hello Olof,
AFAIK, memory resets never been used anywhere before. The device drivers would
have to take into account the backwards compatibility, like for example we do in
the proposed video-decoder patch that optionally utilizes the MC reset [0].
[0] https://patchwork.ozlabs.org/patch/917176/
^ permalink raw reply
* [PATCH v2]irqchip/irq-gic-v3:Avoid a waste of LPI resource
From: Zhang, Lei @ 2018-05-25 12:45 UTC (permalink / raw)
To: linux-arm-kernel
The current implementation of irq-gic-v3-its driver allocates at least 32 LPIs (interrupt numbers)
for each Device ID even if the number of requested LPIs is only one.
I think it is a waste for LPI resource.
And if we use many devices over ITS, this implementation may cause a shortage of LPI .
I have a patch to avoid this problem by changing method of lpis management.
For detail, I use free list instead of chunk method to manage lpis.
The points of this patch are as follows.
Point1:Not always allocates at least 32 LPIs.
Round numbers of lpi requested up to nearest power of two.
Point2: Guarantee base lpi number is aligned a power of two.
For example if you want 2 lpis, you will get 2 lpis, and base lpi number will be aligned by 2.
If you want 15 lpis, you will get 16 lpis, and base lpi number will be aligned by 16.
Point3: Lpis be allocated as a contiguous range,
Signed-off-by: Lei Zhang <zhang.lei@jp.fujitsu.com>
------------------------------------------------
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 5416f2b..e68fca6 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -1405,82 +1405,122 @@ static int its_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu_info)
.irq_set_vcpu_affinity = its_irq_set_vcpu_affinity,
};
-/*
- * How we allocate LPIs:
- *
- * The GIC has id_bits bits for interrupt identifiers. From there, we
- * must subtract 8192 which are reserved for SGIs/PPIs/SPIs. Then, as
- * we allocate LPIs by chunks of 32, we can shift the whole thing by 5
- * bits to the right.
- *
- * This gives us (((1UL << id_bits) - 8192) >> 5) possible allocations.
- */
-#define IRQS_PER_CHUNK_SHIFT 5
-#define IRQS_PER_CHUNK (1UL << IRQS_PER_CHUNK_SHIFT)
-#define ITS_MAX_LPI_NRBITS 16 /* 64K LPIs */
+static struct list_head lpi_free_list;
+static struct list_head lpi_alloc_list; struct lpi_mng {
+ struct list_head lpi_list;
+ int base;
+ int len;
+};
-static unsigned long *lpi_bitmap;
-static u32 lpi_chunks;
+#define ITS_MAX_LPI_NRBITS 16 /* 64K LPIs */
static DEFINE_SPINLOCK(lpi_lock);
-static int its_lpi_to_chunk(int lpi)
-{
- return (lpi - 8192) >> IRQS_PER_CHUNK_SHIFT;
-}
-
-static int its_chunk_to_lpi(int chunk)
-{
- return (chunk << IRQS_PER_CHUNK_SHIFT) + 8192;
-}
static int __init its_lpi_init(u32 id_bits) {
- lpi_chunks = its_lpi_to_chunk(1UL << id_bits);
+ u32 nr_irq = 1UL << id_bits;
+ struct lpi_mng *lpi_free_mng = NULL;
+ struct lpi_mng *lpi_new = NULL;
+
+ INIT_LIST_HEAD(&lpi_free_list);
+ INIT_LIST_HEAD(&lpi_alloc_list);
- lpi_bitmap = kzalloc(BITS_TO_LONGS(lpi_chunks) * sizeof(long),
- GFP_KERNEL);
- if (!lpi_bitmap) {
- lpi_chunks = 0;
+ lpi_free_mng = kzalloc(sizeof(struct lpi_mng), GFP_KERNEL);
+ if (!lpi_free_mng)
return -ENOMEM;
- }
- pr_info("ITS: Allocated %d chunks for LPIs\n", (int)lpi_chunks);
+ lpi_free_mng->base = 0;
+ lpi_free_mng->len = nr_irq;
+ list_add(&lpi_free_mng->lpi_list, &lpi_free_list);
+
+ do {
+ lpi_free_mng = list_first_entry(&lpi_free_list, struct lpi_mng,
+ lpi_list);
+ if (lpi_free_mng->len == 8192) {
+ /*It is not lpi, so we delete */
+ if (lpi_free_mng->base == 0) {
+ list_del_init(&lpi_free_mng->lpi_list);
+ kfree(lpi_free_mng);
+ continue;
+ }
+ if (lpi_free_mng->base == 8192)
+ goto out;
+ }
+ if (lpi_free_mng->len > 8192) {
+ lpi_new = kzalloc(sizeof(struct lpi_mng),
+ GFP_ATOMIC);
+ if (!lpi_new)
+ return -ENOMEM;
+ lpi_free_mng->len /= 2;
+ lpi_new->base = lpi_free_mng->base + lpi_free_mng->len;
+ lpi_new->len = lpi_free_mng->len;
+ list_add(&lpi_new->lpi_list, &lpi_free_mng->lpi_list);
+ }
+ } while (1);
+
+out:
+ pr_info("ITS: Allocated %d LPIs\n", nr_irq - 8192);
return 0;
}
+static struct lpi_mng *its_alloc_lpi(int nr_irqs) {
+ struct lpi_mng *lpi_alloc_mng = NULL;
+ struct lpi_mng *lpi_split = NULL;
+ struct lpi_mng *lpi_new = NULL;
+ int base;
+
+ base = INT_MAX;
+ do {
+ list_for_each_entry(lpi_alloc_mng, &lpi_free_list, lpi_list) {
+ if (nr_irqs > lpi_alloc_mng->len)
+ continue;
+ if (nr_irqs == lpi_alloc_mng->len) {
+ list_del_init(&lpi_alloc_mng->lpi_list);
+ list_add(&lpi_alloc_mng->lpi_list,
+ &lpi_alloc_list);
+ return lpi_alloc_mng;
+ }
+ if ((nr_irqs < lpi_alloc_mng->len)
+ && (lpi_alloc_mng->base < base)) {
+ base = lpi_alloc_mng->base;
+ lpi_split = lpi_alloc_mng;
+ }
+ }
+ lpi_new = kzalloc(sizeof(struct lpi_mng),
+ GFP_ATOMIC);
+ if (!lpi_new || !lpi_split)
+ return NULL;
+
+ lpi_split->len /= 2;
+ lpi_new->base = lpi_split->base + lpi_split->len;
+ lpi_new->len = lpi_split->len;
+ list_add(&lpi_new->lpi_list, &lpi_split->lpi_list);
+
+ } while (1);
+}
+
static unsigned long *its_lpi_alloc_chunks(int nr_irqs, int *base, int *nr_ids) {
unsigned long *bitmap = NULL;
- int chunk_id;
- int nr_chunks;
- int i;
-
- nr_chunks = DIV_ROUND_UP(nr_irqs, IRQS_PER_CHUNK);
+ struct lpi_mng *lpi_alloc_mng = NULL;
spin_lock(&lpi_lock);
- do {
- chunk_id = bitmap_find_next_zero_area(lpi_bitmap, lpi_chunks,
- 0, nr_chunks, 0);
- if (chunk_id < lpi_chunks)
- break;
-
- nr_chunks--;
- } while (nr_chunks > 0);
+ lpi_alloc_mng = its_alloc_lpi(nr_irqs);
- if (!nr_chunks)
+ if (!lpi_alloc_mng)
goto out;
- bitmap = kzalloc(BITS_TO_LONGS(nr_chunks * IRQS_PER_CHUNK) * sizeof (long),
- GFP_ATOMIC);
+ bitmap = kzalloc(BITS_TO_LONGS(nr_irqs) * sizeof(long),
+ GFP_ATOMIC);
if (!bitmap)
goto out;
- for (i = 0; i < nr_chunks; i++)
- set_bit(chunk_id + i, lpi_bitmap);
- *base = its_chunk_to_lpi(chunk_id);
- *nr_ids = nr_chunks * IRQS_PER_CHUNK;
+ *base = lpi_alloc_mng->base;
+ *nr_ids = lpi_alloc_mng->len;
out:
spin_unlock(&lpi_lock);
@@ -1491,23 +1531,53 @@ static unsigned long *its_lpi_alloc_chunks(int nr_irqs, int *base, int *nr_ids)
return bitmap;
}
+static void its_joint_free_list(struct lpi_mng *free, struct lpi_mng
+*alloc) {
+ free->len = free->len * 2;
+ if (free->base > alloc->base)
+ free->base = alloc->base;
+}
+
static void its_lpi_free_chunks(unsigned long *bitmap, int base, int nr_ids) {
- int lpi;
+ struct lpi_mng *lpi_alloc_mng = NULL;
+ struct lpi_mng *lpi_free_mng = NULL;
+ bool first_half;
+ int pair_base;
spin_lock(&lpi_lock);
- for (lpi = base; lpi < (base + nr_ids); lpi += IRQS_PER_CHUNK) {
- int chunk = its_lpi_to_chunk(lpi);
-
- BUG_ON(chunk > lpi_chunks);
- if (test_bit(chunk, lpi_bitmap)) {
- clear_bit(chunk, lpi_bitmap);
- } else {
- pr_err("Bad LPI chunk %d\n", chunk);
+ list_for_each_entry(lpi_alloc_mng, &lpi_alloc_list, lpi_list) {
+ if (lpi_alloc_mng->base == base) {
+ list_del_init(&lpi_alloc_mng->lpi_list);
+ break;
}
}
+ first_half = (lpi_alloc_mng->base % (lpi_alloc_mng->len * 2))
+ ? false : true;
+ if (first_half)
+ pair_base = lpi_alloc_mng->base + lpi_alloc_mng->len;
+ else
+ pair_base = lpi_alloc_mng->base - lpi_alloc_mng->len;
+
+ // found the other half
+ list_for_each_entry(lpi_free_mng, &lpi_free_list, lpi_list) {
+ if (lpi_free_mng->base == pair_base) {
+ its_joint_free_list(lpi_free_mng, lpi_alloc_mng);
+ kfree(lpi_alloc_mng);
+ goto out;
+ }
+ }
+ // Not found the other half
+ list_for_each_entry(lpi_free_mng, &lpi_free_list, lpi_list) {
+ if (lpi_alloc_mng->base < lpi_free_mng->base) {
+ list_add_tail(&lpi_alloc_mng->lpi_list,
+ &lpi_free_mng->lpi_list);
+ break;
+ }
+ }
+out:
spin_unlock(&lpi_lock);
kfree(bitmap);
@@ -2117,12 +2187,13 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
* We allocate at least one chunk worth of LPIs bet device,
* and thus that many ITEs. The device may require less though.
*/
- nr_ites = max(IRQS_PER_CHUNK, roundup_pow_of_two(nvecs));
+ nr_ites = max(2UL, roundup_pow_of_two(nvecs));
sz = nr_ites * its->ite_size;
sz = max(sz, ITS_ITT_ALIGN) + ITS_ITT_ALIGN - 1;
itt = kzalloc(sz, GFP_KERNEL);
if (alloc_lpis) {
- lpi_map = its_lpi_alloc_chunks(nvecs, &lpi_base, &nr_lpis);
+ lpi_map = its_lpi_alloc_chunks(roundup_pow_of_two(nvecs),
+ &lpi_base, &nr_lpis);
if (lpi_map)
col_map = kzalloc(sizeof(*col_map) * nr_lpis,
GFP_KERNEL);
----------------------------------------------------
Regards,
Lei Zhang
--
Lei Zhang e-mail: zhang.lei at jp.fujitsu.com FUJITSU LIMITED
^ permalink raw reply related
* [PATCH] mmc: sdhci-*: Don't emit error msg if sdhci_add_host() fails
From: Patrice CHOTARD @ 2018-05-25 12:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180525151509.0270dbe1@xhacker.debian>
Hi Jisheng
On 05/25/2018 09:15 AM, Jisheng Zhang wrote:
> I noticed below error msg with sdhci-pxav3 on some berlin platforms:
>
> [.....] sdhci-pxav3 f7ab0000.sdhci failed to add host
>
> It is due to getting related vmmc or vqmmc regulator returns
> -EPROBE_DEFER. It doesn't matter at all but it's confusing.
>
> From another side, if driver probing fails and the error number isn't
> -EPROBE_DEFER, the core will tell us something as below:
>
> [.....] sdhci-pxav3: probe of f7ab0000.sdhci failed with error -EXX
>
> So it's not necessary to emit error msg if sdhci_add_host() fails. And
> some other sdhci host drivers also have this issue, let's fix them
> together.
>
> Signed-off-by: Jisheng Zhang <Jisheng.Zhang@synaptics.com>
> ---
> drivers/mmc/host/sdhci-bcm-kona.c | 4 +---
> drivers/mmc/host/sdhci-pic32.c | 4 +---
> drivers/mmc/host/sdhci-pxav2.c | 4 +---
> drivers/mmc/host/sdhci-pxav3.c | 4 +---
> drivers/mmc/host/sdhci-s3c.c | 4 +---
> drivers/mmc/host/sdhci-spear.c | 4 +---
> drivers/mmc/host/sdhci-st.c | 4 +---
> 7 files changed, 7 insertions(+), 21 deletions(-)
>
> diff --git a/drivers/mmc/host/sdhci-bcm-kona.c b/drivers/mmc/host/sdhci-bcm-kona.c
> index 11ca95c60bcf..bdbd4897c0f7 100644
> --- a/drivers/mmc/host/sdhci-bcm-kona.c
> +++ b/drivers/mmc/host/sdhci-bcm-kona.c
> @@ -284,10 +284,8 @@ static int sdhci_bcm_kona_probe(struct platform_device *pdev)
> sdhci_bcm_kona_sd_init(host);
>
> ret = sdhci_add_host(host);
> - if (ret) {
> - dev_err(dev, "Failed sdhci_add_host\n");
> + if (ret)
> goto err_reset;
> - }
>
> /* if device is eMMC, emulate card insert right here */
> if (!mmc_card_is_removable(host->mmc)) {
> diff --git a/drivers/mmc/host/sdhci-pic32.c b/drivers/mmc/host/sdhci-pic32.c
> index a6caa49ca25a..a11e6397d4ff 100644
> --- a/drivers/mmc/host/sdhci-pic32.c
> +++ b/drivers/mmc/host/sdhci-pic32.c
> @@ -200,10 +200,8 @@ static int pic32_sdhci_probe(struct platform_device *pdev)
> }
>
> ret = sdhci_add_host(host);
> - if (ret) {
> - dev_err(&pdev->dev, "error adding host\n");
> + if (ret)
> goto err_base_clk;
> - }
>
> dev_info(&pdev->dev, "Successfully added sdhci host\n");
> return 0;
> diff --git a/drivers/mmc/host/sdhci-pxav2.c b/drivers/mmc/host/sdhci-pxav2.c
> index 8986f9d9cf98..2c3827f54927 100644
> --- a/drivers/mmc/host/sdhci-pxav2.c
> +++ b/drivers/mmc/host/sdhci-pxav2.c
> @@ -221,10 +221,8 @@ static int sdhci_pxav2_probe(struct platform_device *pdev)
> host->ops = &pxav2_sdhci_ops;
>
> ret = sdhci_add_host(host);
> - if (ret) {
> - dev_err(&pdev->dev, "failed to add host\n");
> + if (ret)
> goto disable_clk;
> - }
>
> return 0;
>
> diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c
> index a34434166ca7..b8e96f392428 100644
> --- a/drivers/mmc/host/sdhci-pxav3.c
> +++ b/drivers/mmc/host/sdhci-pxav3.c
> @@ -472,10 +472,8 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
> pm_suspend_ignore_children(&pdev->dev, 1);
>
> ret = sdhci_add_host(host);
> - if (ret) {
> - dev_err(&pdev->dev, "failed to add host\n");
> + if (ret)
> goto err_add_host;
> - }
>
> if (host->mmc->pm_caps & MMC_PM_WAKE_SDIO_IRQ)
> device_init_wakeup(&pdev->dev, 1);
> diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c
> index cda83ccb2702..9ef89d00970e 100644
> --- a/drivers/mmc/host/sdhci-s3c.c
> +++ b/drivers/mmc/host/sdhci-s3c.c
> @@ -655,10 +655,8 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
> goto err_req_regs;
>
> ret = sdhci_add_host(host);
> - if (ret) {
> - dev_err(dev, "sdhci_add_host() failed\n");
> + if (ret)
> goto err_req_regs;
> - }
>
> #ifdef CONFIG_PM
> if (pdata->cd_type != S3C_SDHCI_CD_INTERNAL)
> diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c
> index 14511526a3a8..9247d51f2eed 100644
> --- a/drivers/mmc/host/sdhci-spear.c
> +++ b/drivers/mmc/host/sdhci-spear.c
> @@ -126,10 +126,8 @@ static int sdhci_probe(struct platform_device *pdev)
> }
>
> ret = sdhci_add_host(host);
> - if (ret) {
> - dev_dbg(&pdev->dev, "error adding host\n");
> + if (ret)
> goto disable_clk;
> - }
>
> platform_set_drvdata(pdev, host);
>
> diff --git a/drivers/mmc/host/sdhci-st.c b/drivers/mmc/host/sdhci-st.c
> index c32daed0d418..8f95647195d9 100644
> --- a/drivers/mmc/host/sdhci-st.c
> +++ b/drivers/mmc/host/sdhci-st.c
> @@ -422,10 +422,8 @@ static int sdhci_st_probe(struct platform_device *pdev)
> st_mmcss_cconfig(np, host);
>
> ret = sdhci_add_host(host);
> - if (ret) {
> - dev_err(&pdev->dev, "Failed sdhci_add_host\n");
> + if (ret)
> goto err_out;
> - }
>
> host_version = readw_relaxed((host->ioaddr + SDHCI_HOST_VERSION));
>
>
For drivers/mmc/host/sdhci-st.c:
Acked-by: Patrice Chotard <patrice.chotard@st.com>
Thanks
^ permalink raw reply
* [PATCH v4 7/7] ARM: dts: at91: sama5d2 Xplained: add pin muxing for I2S
From: Codrin Ciubotariu @ 2018-05-25 12:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1527251668-31396-1-git-send-email-codrin.ciubotariu@microchip.com>
From: Cyrille Pitchen <cyrille.pitchen@atmel.com>
This patch sets the pin muxing for the I2S controllers
Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
[codrin.ciubotariu at microchip.com: added pin muxing for the second
controller]
Signed-off-by: Codrin Ciubotariu <codrin.ciubotariu@microchip.com>
---
arch/arm/boot/dts/at91-sama5d2_xplained.dts | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts
index e4bbb7e..0391731 100644
--- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts
+++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts
@@ -281,6 +281,11 @@
status = "okay";
};
+ i2s0: i2s at f8050000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2s0_default>;
+ };
+
can0: can at f8054000 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_can0_default>;
@@ -424,6 +429,24 @@
bias-disable;
};
+ pinctrl_i2s0_default: i2s0_default {
+ pinmux = <PIN_PC1__I2SC0_CK>,
+ <PIN_PC2__I2SC0_MCK>,
+ <PIN_PC3__I2SC0_WS>,
+ <PIN_PC4__I2SC0_DI0>,
+ <PIN_PC5__I2SC0_DO0>;
+ bias-disable;
+ };
+
+ pinctrl_i2s1_default: i2s1_default {
+ pinmux = <PIN_PA15__I2SC1_CK>,
+ <PIN_PA14__I2SC1_MCK>,
+ <PIN_PA16__I2SC1_WS>,
+ <PIN_PA17__I2SC1_DI0>,
+ <PIN_PA18__I2SC1_DO0>;
+ bias-disable;
+ };
+
pinctrl_key_gpio_default: key_gpio_default {
pinmux = <PIN_PB9__GPIO>;
bias-pull-up;
@@ -546,6 +569,11 @@
status = "okay";
};
+ i2s1: i2s at fc04c000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2s1_default>;
+ };
+
can1: can at fc050000 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_can1_default>;
--
2.7.4
^ permalink raw reply related
* [PATCH v4 6/7] ARM: dts: at91: sama5d2: add nodes for I2S controllers
From: Codrin Ciubotariu @ 2018-05-25 12:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1527251668-31396-1-git-send-email-codrin.ciubotariu@microchip.com>
From: Cyrille Pitchen <cyrille.pitchen@atmel.com>
This patch adds DT nodes for I2S0 and I2S1. It also adds an alias for
each I2S node.
Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
[codrin.ciubotariu at microchip.com: added phandle to new mux clock]
Signed-off-by: Codrin Ciubotariu <codrin.ciubotariu@microchip.com>
---
arch/arm/boot/dts/sama5d2.dtsi | 34 ++++++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi
index eeb6afa..eca73ce 100644
--- a/arch/arm/boot/dts/sama5d2.dtsi
+++ b/arch/arm/boot/dts/sama5d2.dtsi
@@ -58,6 +58,8 @@
serial1 = &uart3;
tcb0 = &tcb0;
tcb1 = &tcb1;
+ i2s0 = &i2s0;
+ i2s1 = &i2s1;
};
cpus {
@@ -1313,6 +1315,22 @@
clocks = <&clk32k>;
};
+ i2s0: i2s at f8050000 {
+ compatible = "atmel,sama5d2-i2s";
+ reg = <0xf8050000 0x100>;
+ interrupts = <54 IRQ_TYPE_LEVEL_HIGH 7>;
+ dmas = <&dma0
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+ AT91_XDMAC_DT_PERID(31))>,
+ <&dma0
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+ AT91_XDMAC_DT_PERID(32))>;
+ dma-names = "tx", "rx";
+ clocks = <&i2s0_clk>, <&i2s0_gclk>, <&audio_pll_pmc>, <&i2s0muxck>;
+ clock-names = "pclk", "gclk", "aclk", "muxclk";
+ status = "disabled";
+ };
+
can0: can at f8054000 {
compatible = "bosch,m_can";
reg = <0xf8054000 0x4000>, <0x210000 0x4000>;
@@ -1506,6 +1524,22 @@
status = "disabled";
};
+ i2s1: i2s at fc04c000 {
+ compatible = "atmel,sama5d2-i2s";
+ reg = <0xfc04c000 0x100>;
+ interrupts = <55 IRQ_TYPE_LEVEL_HIGH 7>;
+ dmas = <&dma0
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+ AT91_XDMAC_DT_PERID(33))>,
+ <&dma0
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+ AT91_XDMAC_DT_PERID(34))>;
+ dma-names = "tx", "rx";
+ clocks = <&i2s1_clk>, <&i2s1_gclk>, <&audio_pll_pmc>, <&i2s1muxck>;
+ clock-names = "pclk", "gclk", "aclk", "muxclk";
+ status = "disabled";
+ };
+
can1: can at fc050000 {
compatible = "bosch,m_can";
reg = <0xfc050000 0x4000>, <0x210000 0x4000>;
--
2.7.4
^ permalink raw reply related
* [PATCH v4 5/7] ASoC: atmel-i2s: add driver for the new Atmel I2S controller
From: Codrin Ciubotariu @ 2018-05-25 12:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1527251668-31396-1-git-send-email-codrin.ciubotariu@microchip.com>
From: Cyrille Pitchen <cyrille.pitchen@atmel.com>
This patch adds support for the Atmel I2S controller embedded into
sama5d2x SoCs.
Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
Signed-off-by: Codrin Ciubotariu <codrin.ciubotariu@microchip.com>
---
Changes in v4:
- treated -EPROBE_DEFER on probe;
- replaced ternary operator with if;
- return -EINVAL if we don't support the number of audio channels.
sound/soc/atmel/Kconfig | 9 +
sound/soc/atmel/Makefile | 2 +
sound/soc/atmel/atmel-i2s.c | 765 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 776 insertions(+)
create mode 100644 sound/soc/atmel/atmel-i2s.c
diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig
index dcee145..64b784e 100644
--- a/sound/soc/atmel/Kconfig
+++ b/sound/soc/atmel/Kconfig
@@ -88,4 +88,13 @@ config SND_ATMEL_SOC_TSE850_PCM5142
help
Say Y if you want to add support for the ASoC driver for the
Axentia TSE-850 with a PCM5142 codec.
+
+config SND_ATMEL_SOC_I2S
+ tristate "Atmel ASoC driver for boards using I2S"
+ depends on OF && (ARCH_AT91 || COMPILE_TEST)
+ select SND_SOC_GENERIC_DMAENGINE_PCM
+ select REGMAP_MMIO
+ help
+ Say Y or M if you want to add support for Atmel ASoc driver for boards
+ using I2S.
endif
diff --git a/sound/soc/atmel/Makefile b/sound/soc/atmel/Makefile
index 4440646..cd87cb4 100644
--- a/sound/soc/atmel/Makefile
+++ b/sound/soc/atmel/Makefile
@@ -3,10 +3,12 @@
snd-soc-atmel-pcm-pdc-objs := atmel-pcm-pdc.o
snd-soc-atmel-pcm-dma-objs := atmel-pcm-dma.o
snd-soc-atmel_ssc_dai-objs := atmel_ssc_dai.o
+snd-soc-atmel-i2s-objs := atmel-i2s.o
obj-$(CONFIG_SND_ATMEL_SOC_PDC) += snd-soc-atmel-pcm-pdc.o
obj-$(CONFIG_SND_ATMEL_SOC_DMA) += snd-soc-atmel-pcm-dma.o
obj-$(CONFIG_SND_ATMEL_SOC_SSC) += snd-soc-atmel_ssc_dai.o
+obj-$(CONFIG_SND_ATMEL_SOC_I2S) += snd-soc-atmel-i2s.o
# AT91 Machine Support
snd-soc-sam9g20-wm8731-objs := sam9g20_wm8731.o
diff --git a/sound/soc/atmel/atmel-i2s.c b/sound/soc/atmel/atmel-i2s.c
new file mode 100644
index 0000000..5d3b5af
--- /dev/null
+++ b/sound/soc/atmel/atmel-i2s.c
@@ -0,0 +1,765 @@
+/*
+ * Driver for Atmel I2S controller
+ *
+ * Copyright (C) 2015 Atmel Corporation
+ *
+ * Author: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/mfd/syscon.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+
+#define ATMEL_I2SC_MAX_TDM_CHANNELS 8
+
+/*
+ * ---- I2S Controller Register map ----
+ */
+#define ATMEL_I2SC_CR 0x0000 /* Control Register */
+#define ATMEL_I2SC_MR 0x0004 /* Mode Register */
+#define ATMEL_I2SC_SR 0x0008 /* Status Register */
+#define ATMEL_I2SC_SCR 0x000c /* Status Clear Register */
+#define ATMEL_I2SC_SSR 0x0010 /* Status Set Register */
+#define ATMEL_I2SC_IER 0x0014 /* Interrupt Enable Register */
+#define ATMEL_I2SC_IDR 0x0018 /* Interrupt Disable Register */
+#define ATMEL_I2SC_IMR 0x001c /* Interrupt Mask Register */
+#define ATMEL_I2SC_RHR 0x0020 /* Receiver Holding Register */
+#define ATMEL_I2SC_THR 0x0024 /* Transmitter Holding Register */
+#define ATMEL_I2SC_VERSION 0x0028 /* Version Register */
+
+/*
+ * ---- Control Register (Write-only) ----
+ */
+#define ATMEL_I2SC_CR_RXEN BIT(0) /* Receiver Enable */
+#define ATMEL_I2SC_CR_RXDIS BIT(1) /* Receiver Disable */
+#define ATMEL_I2SC_CR_CKEN BIT(2) /* Clock Enable */
+#define ATMEL_I2SC_CR_CKDIS BIT(3) /* Clock Disable */
+#define ATMEL_I2SC_CR_TXEN BIT(4) /* Transmitter Enable */
+#define ATMEL_I2SC_CR_TXDIS BIT(5) /* Transmitter Disable */
+#define ATMEL_I2SC_CR_SWRST BIT(7) /* Software Reset */
+
+/*
+ * ---- Mode Register (Read/Write) ----
+ */
+#define ATMEL_I2SC_MR_MODE_MASK GENMASK(0, 0)
+#define ATMEL_I2SC_MR_MODE_SLAVE (0 << 0)
+#define ATMEL_I2SC_MR_MODE_MASTER (1 << 0)
+
+#define ATMEL_I2SC_MR_DATALENGTH_MASK GENMASK(4, 2)
+#define ATMEL_I2SC_MR_DATALENGTH_32_BITS (0 << 2)
+#define ATMEL_I2SC_MR_DATALENGTH_24_BITS (1 << 2)
+#define ATMEL_I2SC_MR_DATALENGTH_20_BITS (2 << 2)
+#define ATMEL_I2SC_MR_DATALENGTH_18_BITS (3 << 2)
+#define ATMEL_I2SC_MR_DATALENGTH_16_BITS (4 << 2)
+#define ATMEL_I2SC_MR_DATALENGTH_16_BITS_COMPACT (5 << 2)
+#define ATMEL_I2SC_MR_DATALENGTH_8_BITS (6 << 2)
+#define ATMEL_I2SC_MR_DATALENGTH_8_BITS_COMPACT (7 << 2)
+
+#define ATMEL_I2SC_MR_FORMAT_MASK GENMASK(7, 6)
+#define ATMEL_I2SC_MR_FORMAT_I2S (0 << 6)
+#define ATMEL_I2SC_MR_FORMAT_LJ (1 << 6) /* Left Justified */
+#define ATMEL_I2SC_MR_FORMAT_TDM (2 << 6)
+#define ATMEL_I2SC_MR_FORMAT_TDMLJ (3 << 6)
+
+/* Left audio samples duplicated to right audio channel */
+#define ATMEL_I2SC_MR_RXMONO BIT(8)
+
+/* Receiver uses one DMA channel ... */
+#define ATMEL_I2SC_MR_RXDMA_MASK GENMASK(9, 9)
+#define ATMEL_I2SC_MR_RXDMA_SINGLE (0 << 9) /* for all audio channels */
+#define ATMEL_I2SC_MR_RXDMA_MULTIPLE (1 << 9) /* per audio channel */
+
+/* I2SDO output of I2SC is internally connected to I2SDI input */
+#define ATMEL_I2SC_MR_RXLOOP BIT(10)
+
+/* Left audio samples duplicated to right audio channel */
+#define ATMEL_I2SC_MR_TXMONO BIT(12)
+
+/* Transmitter uses one DMA channel ... */
+#define ATMEL_I2SC_MR_TXDMA_MASK GENMASK(13, 13)
+#define ATMEL_I2SC_MR_TXDMA_SINGLE (0 << 13) /* for all audio channels */
+#define ATMEL_I2SC_MR_TXDME_MULTIPLE (1 << 13) /* per audio channel */
+
+/* x sample transmitted when underrun */
+#define ATMEL_I2SC_MR_TXSAME_MASK GENMASK(14, 14)
+#define ATMEL_I2SC_MR_TXSAME_ZERO (0 << 14) /* Zero sample */
+#define ATMEL_I2SC_MR_TXSAME_PREVIOUS (1 << 14) /* Previous sample */
+
+/* Audio Clock to I2SC Master Clock ratio */
+#define ATMEL_I2SC_MR_IMCKDIV_MASK GENMASK(21, 16)
+#define ATMEL_I2SC_MR_IMCKDIV(div) \
+ (((div) << 16) & ATMEL_I2SC_MR_IMCKDIV_MASK)
+
+/* Master Clock to fs ratio */
+#define ATMEL_I2SC_MR_IMCKFS_MASK GENMASK(29, 24)
+#define ATMEL_I2SC_MR_IMCKFS(fs) \
+ (((fs) << 24) & ATMEL_I2SC_MR_IMCKFS_MASK)
+
+/* Master Clock mode */
+#define ATMEL_I2SC_MR_IMCKMODE_MASK GENMASK(30, 30)
+/* 0: No master clock generated (selected clock drives I2SCK pin) */
+#define ATMEL_I2SC_MR_IMCKMODE_I2SCK (0 << 30)
+/* 1: master clock generated (internally generated clock drives I2SMCK pin) */
+#define ATMEL_I2SC_MR_IMCKMODE_I2SMCK (1 << 30)
+
+/* Slot Width */
+/* 0: slot is 32 bits wide for DATALENGTH = 18/20/24 bits. */
+/* 1: slot is 24 bits wide for DATALENGTH = 18/20/24 bits. */
+#define ATMEL_I2SC_MR_IWS BIT(31)
+
+/*
+ * ---- Status Registers ----
+ */
+#define ATMEL_I2SC_SR_RXEN BIT(0) /* Receiver Enabled */
+#define ATMEL_I2SC_SR_RXRDY BIT(1) /* Receive Ready */
+#define ATMEL_I2SC_SR_RXOR BIT(2) /* Receive Overrun */
+
+#define ATMEL_I2SC_SR_TXEN BIT(4) /* Transmitter Enabled */
+#define ATMEL_I2SC_SR_TXRDY BIT(5) /* Transmit Ready */
+#define ATMEL_I2SC_SR_TXUR BIT(6) /* Transmit Underrun */
+
+/* Receive Overrun Channel */
+#define ATMEL_I2SC_SR_RXORCH_MASK GENMASK(15, 8)
+#define ATMEL_I2SC_SR_RXORCH(ch) (1 << (((ch) & 0x7) + 8))
+
+/* Transmit Underrun Channel */
+#define ATMEL_I2SC_SR_TXURCH_MASK GENMASK(27, 20)
+#define ATMEL_I2SC_SR_TXURCH(ch) (1 << (((ch) & 0x7) + 20))
+
+/*
+ * ---- Interrupt Enable/Disable/Mask Registers ----
+ */
+#define ATMEL_I2SC_INT_RXRDY ATMEL_I2SC_SR_RXRDY
+#define ATMEL_I2SC_INT_RXOR ATMEL_I2SC_SR_RXOR
+#define ATMEL_I2SC_INT_TXRDY ATMEL_I2SC_SR_TXRDY
+#define ATMEL_I2SC_INT_TXUR ATMEL_I2SC_SR_TXUR
+
+static const struct regmap_config atmel_i2s_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = ATMEL_I2SC_VERSION,
+};
+
+struct atmel_i2s_gck_param {
+ int fs;
+ unsigned long mck;
+ int imckdiv;
+ int imckfs;
+};
+
+#define I2S_MCK_12M288 12288000UL
+#define I2S_MCK_11M2896 11289600UL
+
+/* mck = (32 * (imckfs+1) / (imckdiv+1)) * fs */
+static const struct atmel_i2s_gck_param gck_params[] = {
+ /* mck = 12.288MHz */
+ { 8000, I2S_MCK_12M288, 0, 47}, /* mck = 1536 fs */
+ { 16000, I2S_MCK_12M288, 1, 47}, /* mck = 768 fs */
+ { 24000, I2S_MCK_12M288, 3, 63}, /* mck = 512 fs */
+ { 32000, I2S_MCK_12M288, 3, 47}, /* mck = 384 fs */
+ { 48000, I2S_MCK_12M288, 7, 63}, /* mck = 256 fs */
+ { 64000, I2S_MCK_12M288, 7, 47}, /* mck = 192 fs */
+ { 96000, I2S_MCK_12M288, 7, 31}, /* mck = 128 fs */
+ {192000, I2S_MCK_12M288, 7, 15}, /* mck = 64 fs */
+
+ /* mck = 11.2896MHz */
+ { 11025, I2S_MCK_11M2896, 1, 63}, /* mck = 1024 fs */
+ { 22050, I2S_MCK_11M2896, 3, 63}, /* mck = 512 fs */
+ { 44100, I2S_MCK_11M2896, 7, 63}, /* mck = 256 fs */
+ { 88200, I2S_MCK_11M2896, 7, 31}, /* mck = 128 fs */
+ {176400, I2S_MCK_11M2896, 7, 15}, /* mck = 64 fs */
+};
+
+struct atmel_i2s_dev;
+
+struct atmel_i2s_caps {
+ int (*mck_init)(struct atmel_i2s_dev *, struct device_node *np);
+};
+
+struct atmel_i2s_dev {
+ struct device *dev;
+ struct regmap *regmap;
+ struct clk *pclk;
+ struct clk *gclk;
+ struct clk *aclk;
+ struct snd_dmaengine_dai_dma_data playback;
+ struct snd_dmaengine_dai_dma_data capture;
+ unsigned int fmt;
+ const struct atmel_i2s_gck_param *gck_param;
+ const struct atmel_i2s_caps *caps;
+};
+
+static irqreturn_t atmel_i2s_interrupt(int irq, void *dev_id)
+{
+ struct atmel_i2s_dev *dev = dev_id;
+ unsigned int sr, imr, pending, ch, mask;
+ irqreturn_t ret = IRQ_NONE;
+
+ regmap_read(dev->regmap, ATMEL_I2SC_SR, &sr);
+ regmap_read(dev->regmap, ATMEL_I2SC_IMR, &imr);
+ pending = sr & imr;
+
+ if (!pending)
+ return IRQ_NONE;
+
+ if (pending & ATMEL_I2SC_INT_RXOR) {
+ mask = ATMEL_I2SC_SR_RXOR;
+
+ for (ch = 0; ch < ATMEL_I2SC_MAX_TDM_CHANNELS; ++ch) {
+ if (sr & ATMEL_I2SC_SR_RXORCH(ch)) {
+ mask |= ATMEL_I2SC_SR_RXORCH(ch);
+ dev_err(dev->dev,
+ "RX overrun on channel %d\n", ch);
+ }
+ }
+ regmap_write(dev->regmap, ATMEL_I2SC_SCR, mask);
+ ret = IRQ_HANDLED;
+ }
+
+ if (pending & ATMEL_I2SC_INT_TXUR) {
+ mask = ATMEL_I2SC_SR_TXUR;
+
+ for (ch = 0; ch < ATMEL_I2SC_MAX_TDM_CHANNELS; ++ch) {
+ if (sr & ATMEL_I2SC_SR_TXURCH(ch)) {
+ mask |= ATMEL_I2SC_SR_TXURCH(ch);
+ dev_err(dev->dev,
+ "TX underrun on channel %d\n", ch);
+ }
+ }
+ regmap_write(dev->regmap, ATMEL_I2SC_SCR, mask);
+ ret = IRQ_HANDLED;
+ }
+
+ return ret;
+}
+
+#define ATMEL_I2S_RATES SNDRV_PCM_RATE_8000_192000
+
+#define ATMEL_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
+ SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S18_3LE | \
+ SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static int atmel_i2s_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+ dev->fmt = fmt;
+ return 0;
+}
+
+static int atmel_i2s_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+ bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+ unsigned int rhr, sr = 0;
+
+ if (is_playback) {
+ regmap_read(dev->regmap, ATMEL_I2SC_SR, &sr);
+ if (sr & ATMEL_I2SC_SR_RXRDY) {
+ /*
+ * The RX Ready flag should not be set. However if here,
+ * we flush (read) the Receive Holding Register to start
+ * from a clean state.
+ */
+ dev_dbg(dev->dev, "RXRDY is set\n");
+ regmap_read(dev->regmap, ATMEL_I2SC_RHR, &rhr);
+ }
+ }
+
+ return 0;
+}
+
+static int atmel_i2s_get_gck_param(struct atmel_i2s_dev *dev, int fs)
+{
+ int i, best;
+
+ if (!dev->gclk || !dev->aclk) {
+ dev_err(dev->dev, "cannot generate the I2S Master Clock\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Find the best possible settings to generate the I2S Master Clock
+ * from the PLL Audio.
+ */
+ dev->gck_param = NULL;
+ best = INT_MAX;
+ for (i = 0; i < ARRAY_SIZE(gck_params); ++i) {
+ const struct atmel_i2s_gck_param *gck_param = &gck_params[i];
+ int val = abs(fs - gck_param->fs);
+
+ if (val < best) {
+ best = val;
+ dev->gck_param = gck_param;
+ }
+ }
+
+ return 0;
+}
+
+static int atmel_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+ bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+ unsigned int mr = 0;
+ int ret;
+
+ switch (dev->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ mr |= ATMEL_I2SC_MR_FORMAT_I2S;
+ break;
+
+ default:
+ dev_err(dev->dev, "unsupported bus format\n");
+ return -EINVAL;
+ }
+
+ switch (dev->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /* codec is slave, so cpu is master */
+ mr |= ATMEL_I2SC_MR_MODE_MASTER;
+ ret = atmel_i2s_get_gck_param(dev, params_rate(params));
+ if (ret)
+ return ret;
+ break;
+
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* codec is master, so cpu is slave */
+ mr |= ATMEL_I2SC_MR_MODE_SLAVE;
+ dev->gck_param = NULL;
+ break;
+
+ default:
+ dev_err(dev->dev, "unsupported master/slave mode\n");
+ return -EINVAL;
+ }
+
+ switch (params_channels(params)) {
+ case 1:
+ if (is_playback)
+ mr |= ATMEL_I2SC_MR_TXMONO;
+ else
+ mr |= ATMEL_I2SC_MR_RXMONO;
+ break;
+ case 2:
+ break;
+ default:
+ dev_err(dev->dev, "unsupported number of audio channels\n");
+ return -EINVAL;
+ }
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S8:
+ mr |= ATMEL_I2SC_MR_DATALENGTH_8_BITS;
+ break;
+
+ case SNDRV_PCM_FORMAT_S16_LE:
+ mr |= ATMEL_I2SC_MR_DATALENGTH_16_BITS;
+ break;
+
+ case SNDRV_PCM_FORMAT_S18_3LE:
+ mr |= ATMEL_I2SC_MR_DATALENGTH_18_BITS | ATMEL_I2SC_MR_IWS;
+ break;
+
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ mr |= ATMEL_I2SC_MR_DATALENGTH_20_BITS | ATMEL_I2SC_MR_IWS;
+ break;
+
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ mr |= ATMEL_I2SC_MR_DATALENGTH_24_BITS | ATMEL_I2SC_MR_IWS;
+ break;
+
+ case SNDRV_PCM_FORMAT_S24_LE:
+ mr |= ATMEL_I2SC_MR_DATALENGTH_24_BITS;
+ break;
+
+ case SNDRV_PCM_FORMAT_S32_LE:
+ mr |= ATMEL_I2SC_MR_DATALENGTH_32_BITS;
+ break;
+
+ default:
+ dev_err(dev->dev, "unsupported size/endianness for audio samples\n");
+ return -EINVAL;
+ }
+
+ return regmap_write(dev->regmap, ATMEL_I2SC_MR, mr);
+}
+
+static int atmel_i2s_switch_mck_generator(struct atmel_i2s_dev *dev,
+ bool enabled)
+{
+ unsigned int mr, mr_mask;
+ unsigned long aclk_rate;
+ int ret;
+
+ mr = 0;
+ mr_mask = (ATMEL_I2SC_MR_IMCKDIV_MASK |
+ ATMEL_I2SC_MR_IMCKFS_MASK |
+ ATMEL_I2SC_MR_IMCKMODE_MASK);
+
+ if (!enabled) {
+ /* Disable the I2S Master Clock generator. */
+ ret = regmap_write(dev->regmap, ATMEL_I2SC_CR,
+ ATMEL_I2SC_CR_CKDIS);
+ if (ret)
+ return ret;
+
+ /* Reset the I2S Master Clock generator settings. */
+ ret = regmap_update_bits(dev->regmap, ATMEL_I2SC_MR,
+ mr_mask, mr);
+ if (ret)
+ return ret;
+
+ /* Disable/unprepare the PMC generated clock. */
+ clk_disable_unprepare(dev->gclk);
+
+ /* Disable/unprepare the PLL audio clock. */
+ clk_disable_unprepare(dev->aclk);
+ return 0;
+ }
+
+ if (!dev->gck_param)
+ return -EINVAL;
+
+ aclk_rate = dev->gck_param->mck * (dev->gck_param->imckdiv + 1);
+
+ /* Fist change the PLL audio clock frequency ... */
+ ret = clk_set_rate(dev->aclk, aclk_rate);
+ if (ret)
+ return ret;
+
+ /*
+ * ... then set the PMC generated clock rate to the very same frequency
+ * to set the gclk parent to aclk.
+ */
+ ret = clk_set_rate(dev->gclk, aclk_rate);
+ if (ret)
+ return ret;
+
+ /* Prepare and enable the PLL audio clock first ... */
+ ret = clk_prepare_enable(dev->aclk);
+ if (ret)
+ return ret;
+
+ /* ... then prepare and enable the PMC generated clock. */
+ ret = clk_prepare_enable(dev->gclk);
+ if (ret)
+ return ret;
+
+ /* Update the Mode Register to generate the I2S Master Clock. */
+ mr |= ATMEL_I2SC_MR_IMCKDIV(dev->gck_param->imckdiv);
+ mr |= ATMEL_I2SC_MR_IMCKFS(dev->gck_param->imckfs);
+ mr |= ATMEL_I2SC_MR_IMCKMODE_I2SMCK;
+ ret = regmap_update_bits(dev->regmap, ATMEL_I2SC_MR, mr_mask, mr);
+ if (ret)
+ return ret;
+
+ /* Finally enable the I2S Master Clock generator. */
+ return regmap_write(dev->regmap, ATMEL_I2SC_CR,
+ ATMEL_I2SC_CR_CKEN);
+}
+
+static int atmel_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+ bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+ bool is_master, mck_enabled;
+ unsigned int cr, mr;
+ int err;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ cr = is_playback ? ATMEL_I2SC_CR_TXEN : ATMEL_I2SC_CR_RXEN;
+ mck_enabled = true;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ cr = is_playback ? ATMEL_I2SC_CR_TXDIS : ATMEL_I2SC_CR_RXDIS;
+ mck_enabled = false;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Read the Mode Register to retrieve the master/slave state. */
+ err = regmap_read(dev->regmap, ATMEL_I2SC_MR, &mr);
+ if (err)
+ return err;
+ is_master = (mr & ATMEL_I2SC_MR_MODE_MASK) == ATMEL_I2SC_MR_MODE_MASTER;
+
+ /* If master starts, enable the audio clock. */
+ if (is_master && mck_enabled)
+ err = atmel_i2s_switch_mck_generator(dev, true);
+ if (err)
+ return err;
+
+ err = regmap_write(dev->regmap, ATMEL_I2SC_CR, cr);
+ if (err)
+ return err;
+
+ /* If master stops, disable the audio clock. */
+ if (is_master && !mck_enabled)
+ err = atmel_i2s_switch_mck_generator(dev, false);
+
+ return err;
+}
+
+static const struct snd_soc_dai_ops atmel_i2s_dai_ops = {
+ .prepare = atmel_i2s_prepare,
+ .trigger = atmel_i2s_trigger,
+ .hw_params = atmel_i2s_hw_params,
+ .set_fmt = atmel_i2s_set_dai_fmt,
+};
+
+static int atmel_i2s_dai_probe(struct snd_soc_dai *dai)
+{
+ struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+ snd_soc_dai_init_dma_data(dai, &dev->playback, &dev->capture);
+ return 0;
+}
+
+static struct snd_soc_dai_driver atmel_i2s_dai = {
+ .probe = atmel_i2s_dai_probe,
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = ATMEL_I2S_RATES,
+ .formats = ATMEL_I2S_FORMATS,
+ },
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = ATMEL_I2S_RATES,
+ .formats = ATMEL_I2S_FORMATS,
+ },
+ .ops = &atmel_i2s_dai_ops,
+ .symmetric_rates = 1,
+};
+
+static const struct snd_soc_component_driver atmel_i2s_component = {
+ .name = "atmel-i2s",
+};
+
+static int atmel_i2s_sama5d2_mck_init(struct atmel_i2s_dev *dev,
+ struct device_node *np)
+{
+ struct clk *muxclk;
+ int err;
+
+ if (!dev->gclk)
+ return 0;
+
+ /* muxclk is optional, so we return error for probe defer only */
+ muxclk = devm_clk_get(dev->dev, "muxclk");
+ if (IS_ERR(muxclk)) {
+ err = PTR_ERR(muxclk);
+ if (err == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ dev_warn(dev->dev,
+ "failed to get the I2S clock control: %d\n", err);
+ return 0;
+ }
+
+ return clk_set_parent(muxclk, dev->gclk);
+}
+
+static const struct atmel_i2s_caps atmel_i2s_sama5d2_caps = {
+ .mck_init = atmel_i2s_sama5d2_mck_init,
+};
+
+static const struct of_device_id atmel_i2s_dt_ids[] = {
+ {
+ .compatible = "atmel,sama5d2-i2s",
+ .data = (void *)&atmel_i2s_sama5d2_caps,
+ },
+
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, atmel_i2s_dt_ids);
+
+static int atmel_i2s_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ const struct of_device_id *match;
+ struct atmel_i2s_dev *dev;
+ struct resource *mem;
+ struct regmap *regmap;
+ void __iomem *base;
+ int irq;
+ int err = -ENXIO;
+ unsigned int pcm_flags = 0;
+ unsigned int version;
+
+ /* Get memory for driver data. */
+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ /* Get hardware capabilities. */
+ match = of_match_node(atmel_i2s_dt_ids, np);
+ if (match)
+ dev->caps = match->data;
+
+ /* Map I/O registers. */
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ regmap = devm_regmap_init_mmio(&pdev->dev, base,
+ &atmel_i2s_regmap_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ /* Request IRQ. */
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ err = devm_request_irq(&pdev->dev, irq, atmel_i2s_interrupt, 0,
+ dev_name(&pdev->dev), dev);
+ if (err)
+ return err;
+
+ /* Get the peripheral clock. */
+ dev->pclk = devm_clk_get(&pdev->dev, "pclk");
+ if (IS_ERR(dev->pclk)) {
+ err = PTR_ERR(dev->pclk);
+ dev_err(&pdev->dev,
+ "failed to get the peripheral clock: %d\n", err);
+ return err;
+ }
+
+ /* Get audio clocks to generate the I2S Master Clock (I2S_MCK) */
+ dev->aclk = devm_clk_get(&pdev->dev, "aclk");
+ dev->gclk = devm_clk_get(&pdev->dev, "gclk");
+ if (IS_ERR(dev->aclk) && IS_ERR(dev->gclk)) {
+ if (PTR_ERR(dev->aclk) == -EPROBE_DEFER ||
+ PTR_ERR(dev->gclk) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ /* Master Mode not supported */
+ dev->aclk = NULL;
+ dev->gclk = NULL;
+ } else if (IS_ERR(dev->gclk)) {
+ err = PTR_ERR(dev->gclk);
+ dev_err(&pdev->dev,
+ "failed to get the PMC generated clock: %d\n", err);
+ return err;
+ } else if (IS_ERR(dev->aclk)) {
+ err = PTR_ERR(dev->aclk);
+ dev_err(&pdev->dev,
+ "failed to get the PLL audio clock: %d\n", err);
+ return err;
+ }
+
+ dev->dev = &pdev->dev;
+ dev->regmap = regmap;
+ platform_set_drvdata(pdev, dev);
+
+ /* Do hardware specific settings to initialize I2S_MCK generator */
+ if (dev->caps && dev->caps->mck_init) {
+ err = dev->caps->mck_init(dev, np);
+ if (err)
+ return err;
+ }
+
+ /* Enable the peripheral clock. */
+ err = clk_prepare_enable(dev->pclk);
+ if (err)
+ return err;
+
+ /* Get IP version. */
+ regmap_read(dev->regmap, ATMEL_I2SC_VERSION, &version);
+ dev_info(&pdev->dev, "hw version: %#x\n", version);
+
+ /* Enable error interrupts. */
+ regmap_write(dev->regmap, ATMEL_I2SC_IER,
+ ATMEL_I2SC_INT_RXOR | ATMEL_I2SC_INT_TXUR);
+
+ err = devm_snd_soc_register_component(&pdev->dev,
+ &atmel_i2s_component,
+ &atmel_i2s_dai, 1);
+ if (err) {
+ dev_err(&pdev->dev, "failed to register DAI: %d\n", err);
+ clk_disable_unprepare(dev->pclk);
+ return err;
+ }
+
+ /* Prepare DMA config. */
+ dev->playback.addr = (dma_addr_t)mem->start + ATMEL_I2SC_THR;
+ dev->playback.maxburst = 1;
+ dev->capture.addr = (dma_addr_t)mem->start + ATMEL_I2SC_RHR;
+ dev->capture.maxburst = 1;
+
+ if (of_property_match_string(np, "dma-names", "rx-tx") == 0)
+ pcm_flags |= SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX;
+ err = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, pcm_flags);
+ if (err) {
+ dev_err(&pdev->dev, "failed to register PCM: %d\n", err);
+ clk_disable_unprepare(dev->pclk);
+ return err;
+ }
+
+ return 0;
+}
+
+static int atmel_i2s_remove(struct platform_device *pdev)
+{
+ struct atmel_i2s_dev *dev = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(dev->pclk);
+
+ return 0;
+}
+
+static struct platform_driver atmel_i2s_driver = {
+ .driver = {
+ .name = "atmel_i2s",
+ .of_match_table = of_match_ptr(atmel_i2s_dt_ids),
+ },
+ .probe = atmel_i2s_probe,
+ .remove = atmel_i2s_remove,
+};
+module_platform_driver(atmel_i2s_driver);
+
+MODULE_DESCRIPTION("Atmel I2S Controller driver");
+MODULE_AUTHOR("Cyrille Pitchen <cyrille.pitchen@atmel.com>");
+MODULE_LICENSE("GPL v2");
--
2.7.4
^ permalink raw reply related
* [PATCH v4 4/7] ASoC: atmel-i2s: dt-bindings: add DT bindings for I2S controller
From: Codrin Ciubotariu @ 2018-05-25 12:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1527251668-31396-1-git-send-email-codrin.ciubotariu@microchip.com>
From: Cyrille Pitchen <cyrille.pitchen@atmel.com>
This patch adds DT bindings for the new Atmel I2S controller embedded
inside sama5d2x SoCs.
Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
Signed-off-by: Codrin Ciubotariu <codrin.ciubotariu@microchip.com>
---
Changes in v4:
- more specific description for dmas, dma-names, clocks, clock-names
properties;
- removed SoC and internal details of the block IP;
- added description for the new clock mux phandle;
.../devicetree/bindings/sound/atmel-i2s.txt | 47 ++++++++++++++++++++++
1 file changed, 47 insertions(+)
create mode 100644 Documentation/devicetree/bindings/sound/atmel-i2s.txt
diff --git a/Documentation/devicetree/bindings/sound/atmel-i2s.txt b/Documentation/devicetree/bindings/sound/atmel-i2s.txt
new file mode 100644
index 0000000..735368b
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/atmel-i2s.txt
@@ -0,0 +1,47 @@
+* Atmel I2S controller
+
+Required properties:
+- compatible: Should be "atmel,sama5d2-i2s".
+- reg: Should be the physical base address of the controller and the
+ length of memory mapped region.
+- interrupts: Should contain the interrupt for the controller.
+- dmas: Should be one per channel name listed in the dma-names property,
+ as described in atmel-dma.txt and dma.txt files.
+- dma-names: Two dmas have to be defined, "tx" and "rx".
+ This IP also supports one shared channel for both rx and tx;
+ if this mode is used, one "rx-tx" name must be used.
+- clocks: Must contain an entry for each entry in clock-names.
+ Please refer to clock-bindings.txt.
+- clock-names: Should be one of each entry matching the clocks phandles list:
+ - "pclk" (peripheral clock) Required.
+ - "gclk" (generated clock) Optional (1).
+ - "aclk" (Audio PLL clock) Optional (1).
+ - "muxclk" (I2S mux clock) Optional (1).
+
+Optional properties:
+- pinctrl-0: Should specify pin control groups used for this controller.
+- princtrl-names: Should contain only one value - "default".
+
+
+(1) : Only the peripheral clock is required. The generated clock, the Audio
+ PLL clock adn the I2S mux clock are optional and should only be set
+ together, when Master Mode is required.
+
+Example:
+
+ i2s at f8050000 {
+ compatible = "atmel,sama5d2-i2s";
+ reg = <0xf8050000 0x300>;
+ interrupts = <54 IRQ_TYPE_LEVEL_HIGH 7>;
+ dmas = <&dma0
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+ AT91_XDMAC_DT_PERID(31))>,
+ <&dma0
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+ AT91_XDMAC_DT_PERID(32))>;
+ dma-names = "tx", "rx";
+ clocks = <&i2s0_clk>, <&i2s0_gclk>, <&audio_pll_pmc>, <&i2s0muxck>;
+ clock-names = "pclk", "gclk", "aclk", "muxclk";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2s0_default>;
+ };
--
2.7.4
^ permalink raw reply related
* [PATCH v4 3/7] ARM: dts: at91: sama5d2: add I2S clock muxing nodes
From: Codrin Ciubotariu @ 2018-05-25 12:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1527251668-31396-1-git-send-email-codrin.ciubotariu@microchip.com>
This patch adds two clock muxes for the two I2S
buses present on sama5d2 platforms.
Signed-off-by: Codrin Ciubotariu <codrin.ciubotariu@microchip.com>
---
arch/arm/boot/dts/sama5d2.dtsi | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi
index 61f68e5..eeb6afa 100644
--- a/arch/arm/boot/dts/sama5d2.dtsi
+++ b/arch/arm/boot/dts/sama5d2.dtsi
@@ -992,6 +992,24 @@
atmel,clk-output-range = <0 100000000>;
};
};
+
+ i2s_clkmux {
+ compatible = "atmel,sama5d2-clk-i2s-mux";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2s0muxck: i2s0_muxclk {
+ clocks = <&i2s0_clk>, <&i2s0_gclk>;
+ #clock-cells = <0>;
+ reg = <0>;
+ };
+
+ i2s1muxck: i2s1_muxclk {
+ clocks = <&i2s1_clk>, <&i2s1_gclk>;
+ #clock-cells = <0>;
+ reg = <1>;
+ };
+ };
};
qspi0: spi at f0020000 {
--
2.7.4
^ permalink raw reply related
* [PATCH v4 2/7] clk: at91: add I2S clock mux driver
From: Codrin Ciubotariu @ 2018-05-25 12:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1527251668-31396-1-git-send-email-codrin.ciubotariu@microchip.com>
This driver is a simple muxing driver that controls the
I2S's clock input by using syscon/regmap to change the parrent.
The available inputs can be Peripheral clock and Generated clock.
Signed-off-by: Codrin Ciubotariu <codrin.ciubotariu@microchip.com>
---
arch/arm/mach-at91/Kconfig | 4 ++
drivers/clk/at91/Makefile | 1 +
drivers/clk/at91/clk-i2s-mux.c | 117 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 122 insertions(+)
create mode 100644 drivers/clk/at91/clk-i2s-mux.c
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index 1254bf9..903f23c 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -27,6 +27,7 @@ config SOC_SAMA5D2
select HAVE_AT91_H32MX
select HAVE_AT91_GENERATED_CLK
select HAVE_AT91_AUDIO_PLL
+ select HAVE_AT91_I2S_MUX_CLK
select PINCTRL_AT91PIO4
help
Select this if ou are using one of Microchip's SAMA5D2 family SoC.
@@ -129,6 +130,9 @@ config HAVE_AT91_GENERATED_CLK
config HAVE_AT91_AUDIO_PLL
bool
+config HAVE_AT91_I2S_MUX_CLK
+ bool
+
config SOC_SAM_V4_V5
bool
diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile
index 082596f..facc169 100644
--- a/drivers/clk/at91/Makefile
+++ b/drivers/clk/at91/Makefile
@@ -13,3 +13,4 @@ obj-$(CONFIG_HAVE_AT91_USB_CLK) += clk-usb.o
obj-$(CONFIG_HAVE_AT91_SMD) += clk-smd.o
obj-$(CONFIG_HAVE_AT91_H32MX) += clk-h32mx.o
obj-$(CONFIG_HAVE_AT91_GENERATED_CLK) += clk-generated.o
+obj-$(CONFIG_HAVE_AT91_I2S_MUX_CLK) += clk-i2s-mux.o
diff --git a/drivers/clk/at91/clk-i2s-mux.c b/drivers/clk/at91/clk-i2s-mux.c
new file mode 100644
index 0000000..2d56ded
--- /dev/null
+++ b/drivers/clk/at91/clk-i2s-mux.c
@@ -0,0 +1,117 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 Microchip Technology Inc,
+ * Codrin Ciubotariu <codrin.ciubotariu@microchip.com>
+ *
+ *
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include <soc/at91/atmel-sfr.h>
+
+#define I2S_BUS_NR 2
+
+struct clk_i2s_mux {
+ struct clk_hw hw;
+ struct regmap *regmap;
+ u32 bus_id;
+};
+
+#define to_clk_i2s_mux(hw) container_of(hw, struct clk_i2s_mux, hw)
+
+static u8 clk_i2s_mux_get_parent(struct clk_hw *hw)
+{
+ struct clk_i2s_mux *mux = to_clk_i2s_mux(hw);
+ u32 val;
+
+ regmap_read(mux->regmap, AT91_SFR_I2SCLKSEL, &val);
+
+ return (val & BIT(mux->bus_id)) >> mux->bus_id;
+}
+
+static int clk_i2s_mux_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct clk_i2s_mux *mux = to_clk_i2s_mux(hw);
+
+ return regmap_update_bits(mux->regmap, AT91_SFR_I2SCLKSEL,
+ BIT(mux->bus_id), index << mux->bus_id);
+}
+
+const struct clk_ops clk_i2s_mux_ops = {
+ .get_parent = clk_i2s_mux_get_parent,
+ .set_parent = clk_i2s_mux_set_parent,
+ .determine_rate = __clk_mux_determine_rate,
+};
+
+static struct clk_hw * __init
+at91_clk_i2s_mux_register(struct regmap *regmap, const char *name,
+ const char * const *parent_names,
+ unsigned int num_parents, u32 bus_id)
+{
+ struct clk_init_data init = {};
+ struct clk_i2s_mux *i2s_ck;
+ int ret;
+
+ i2s_ck = kzalloc(sizeof(*i2s_ck), GFP_KERNEL);
+ if (!i2s_ck)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &clk_i2s_mux_ops;
+ init.parent_names = parent_names;
+ init.num_parents = num_parents;
+ init.flags = CLK_IGNORE_UNUSED;
+
+ i2s_ck->hw.init = &init;
+ i2s_ck->bus_id = bus_id;
+ i2s_ck->regmap = regmap;
+
+ ret = clk_hw_register(NULL, &i2s_ck->hw);
+ if (ret) {
+ kfree(i2s_ck);
+ return ERR_PTR(ret);
+ }
+
+ return &i2s_ck->hw;
+}
+
+static void __init of_sama5d2_clk_i2s_mux_setup(struct device_node *np)
+{
+ struct regmap *regmap_sfr;
+ u32 bus_id;
+ const char *parent_names[2];
+ struct device_node *i2s_mux_np;
+ struct clk_hw *hw;
+ int ret;
+
+ regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr");
+ if (IS_ERR(regmap_sfr))
+ return;
+
+ for_each_child_of_node(np, i2s_mux_np) {
+ if (of_property_read_u32(i2s_mux_np, "reg", &bus_id))
+ continue;
+
+ if (bus_id > I2S_BUS_NR)
+ continue;
+
+ ret = of_clk_parent_fill(i2s_mux_np, parent_names, 2);
+ if (ret != 2)
+ continue;
+
+ hw = at91_clk_i2s_mux_register(regmap_sfr, i2s_mux_np->name,
+ parent_names, 2, bus_id);
+ if (IS_ERR(hw))
+ continue;
+
+ of_clk_add_hw_provider(i2s_mux_np, of_clk_hw_simple_get, hw);
+ }
+}
+
+CLK_OF_DECLARE(sama5d2_clk_i2s_mux, "atmel,sama5d2-clk-i2s-mux",
+ of_sama5d2_clk_i2s_mux_setup);
--
2.7.4
^ permalink raw reply related
* [PATCH v4 1/7] dt-bindings: clk: at91: add an I2S mux clock
From: Codrin Ciubotariu @ 2018-05-25 12:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1527251668-31396-1-git-send-email-codrin.ciubotariu@microchip.com>
The I2S mux clock can be used to select the I2S input clock. The
available parents are the peripheral and the generated clocks.
Signed-off-by: Codrin Ciubotariu <codrin.ciubotariu@microchip.com>
---
.../devicetree/bindings/clock/at91-clock.txt | 34 ++++++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/Documentation/devicetree/bindings/clock/at91-clock.txt b/Documentation/devicetree/bindings/clock/at91-clock.txt
index 51c259a..1c46b3c 100644
--- a/Documentation/devicetree/bindings/clock/at91-clock.txt
+++ b/Documentation/devicetree/bindings/clock/at91-clock.txt
@@ -90,6 +90,8 @@ Required properties:
"atmel,sama5d2-clk-audio-pll-pmc"
at91 audio pll output on AUDIOPLLCLK that feeds the PMC
and can be used by peripheral clock or generic clock
+ "atmel,sama5d2-clk-i2s-mux":
+ at91 I2S clock source selection
Required properties for SCKC node:
- reg : defines the IO memory reserved for the SCKC.
@@ -507,3 +509,35 @@ For example:
atmel,clk-output-range = <0 83000000>;
};
};
+
+Required properties for I2S mux clocks:
+- #size-cells : shall be 0 (reg is used to encode I2S bus id).
+- #address-cells : shall be 1 (reg is used to encode I2S bus id).
+- name: device tree node describing a specific mux clock.
+ * #clock-cells : from common clock binding; shall be set to 0.
+ * clocks : shall be the mux clock parent phandles; shall be 2 phandles:
+ peripheral and generated clock; the first phandle shall belong to the
+ peripheral clock and the second one shall belong to the generated
+ clock; "clock-indices" property can be user to specify
+ the correct order.
+ * reg: I2S bus id of the corresponding mux clock.
+ e.g. reg = <0>; for i2s0, reg = <1>; for i2s1
+
+For example:
+ i2s_clkmux {
+ compatible = "atmel,sama5d2-clk-i2s-mux";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2s0muxck: i2s0_muxclk {
+ clocks = <&i2s0_clk>, <&i2s0_gclk>;
+ #clock-cells = <0>;
+ reg = <0>;
+ };
+
+ i2s1muxck: i2s1_muxclk {
+ clocks = <&i2s1_clk>, <&i2s1_gclk>;
+ #clock-cells = <0>;
+ reg = <1>;
+ };
+ };
--
2.7.4
^ permalink raw reply related
* [PATCH v4 0/7] ASoC: add driver for Atmel I2S controller
From: Codrin Ciubotariu @ 2018-05-25 12:34 UTC (permalink / raw)
To: linux-arm-kernel
This is a rework of Cyrille's patches named:
[PATCH v3 0/2] ASoC: add driver for Atmel I2S controller
https://lkml.org/lkml/2015/9/29/454
This is the version 4 of the series, and addresses the received feedback
on the mailing lists.
This series applies on top of asoc-next branch of broonie/sound.git.
Based on received feedback, I created a mux clock driver to select the I2S
clock source, that also includes proper devicetree bindings and nodes.
Also, I added the I2S nodes in sama5d2's devicetree, with the missing
pin muxing for the second I2S controller.
This series of patches adds support to the new Atmel I2S controller
embedded on sama5d2 SoCs.
ChangeLog
v3 -> v4
- as suggested by Rob Herring:
- added a clock mux driver for I2S's clock control bit;
- more precise description of I2S's devicetree bindings;
- removed SoC and internal detalls from bindings;
- addressed comments from Mark Brown;
- added devicetree nodes and pin muxing for I2S;
v2 -> v3
- fix the coding style, add some more comments and add a section dedicated
to sama5d2 SoCs in the DT binding documentation as suggested by Mark
Brown.
v1 -> v2
- initialize dev->dev before calling dev->caps->mck_init()
Codrin Ciubotariu (3):
dt-bindings: clk: at91: add an I2S mux clock
clk: at91: add I2S clock mux driver
ARM: dts: at91: sama5d2: add I2S clock muxing nodes
Cyrille Pitchen (4):
ASoC: atmel-i2s: dt-bindings: add DT bindings for I2S controller
ASoC: atmel-i2s: add driver for the new Atmel I2S controller
ARM: dts: at91: sama5d2: add nodes for I2S controllers
ARM: dts: at91: sama5d2 Xplained: add pin muxing for I2S
.../devicetree/bindings/clock/at91-clock.txt | 34 +
.../devicetree/bindings/sound/atmel-i2s.txt | 47 ++
arch/arm/boot/dts/at91-sama5d2_xplained.dts | 28 +
arch/arm/boot/dts/sama5d2.dtsi | 52 ++
arch/arm/mach-at91/Kconfig | 4 +
drivers/clk/at91/Makefile | 1 +
drivers/clk/at91/clk-i2s-mux.c | 117 ++++
sound/soc/atmel/Kconfig | 9 +
sound/soc/atmel/Makefile | 2 +
sound/soc/atmel/atmel-i2s.c | 765 +++++++++++++++++++++
10 files changed, 1059 insertions(+)
create mode 100644 Documentation/devicetree/bindings/sound/atmel-i2s.txt
create mode 100644 drivers/clk/at91/clk-i2s-mux.c
create mode 100644 sound/soc/atmel/atmel-i2s.c
--
2.7.4
^ permalink raw reply
* [PATCH 9/9] PM / Domains: Add dev_pm_domain_attach_by_id() to manage multi PM domains
From: Ulf Hansson @ 2018-05-25 12:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <b3a94d63-678c-eab6-47a8-43eca95da979@nvidia.com>
On 25 May 2018 at 13:07, Jon Hunter <jonathanh@nvidia.com> wrote:
>
>
> On 25/05/18 11:45, Ulf Hansson wrote:
>
> ...
>
>>> Right, but this case still seems like an error. My understanding is that
>>> only drivers will use this API directly and it will not be used by the
>>> device driver core (unlike dev_pm_domain_attach), so if anyone calls this
>>> attempting to attach another PM domain when one is already attached, they
>>> are doing something wrong.
>>
>>
>> [...]
>>
>> You may be right!
>>
>> What I was thinking of is whether multiple PM domains may be optional
>> in some cases, but instead a PM domain have already been attached by
>> dev_pm_domain_attach(), prior the driver starts to probe.
>>
>> Then, assuming we return an error for this case, that means the caller
>> then need to check the dev->pm_domain pointer, prior calling
>> dev_pm_domain_attach_by_id(). Wouldn't it? Perhaps that is more clear
>> though?
>
>
> IMO the driver should know whether is needs multiple power-domains or not
> and if it needs multiple then it should just call
> dev_pm_domain_attach_by_id() N times without needing to checking
> dev->pm_domain first. If it fails then either the PM domain core did
> something wrong or power-domains are missing from DT, but either way there
> is an error, so let it fail.
Right, sounds reasonable!
Kind regards
Uffe
^ permalink raw reply
* [GIT PULL] arm64: dts: uniphier: UniPhier DT updates for v4.18
From: Olof Johansson @ 2018-05-25 12:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAK7LNASUq_9osPdzbiMCbYzeqc=W3Yv7tB63V+5gXqcZ9QBtYA@mail.gmail.com>
On Sun, May 20, 2018 at 11:38:39AM +0900, Masahiro Yamada wrote:
> Hi Arnd, Olof,
>
> Here are UniPhier DT (64bit) updates for the v4.18 merge window.
> Please pull!
>
>
> The following changes since commit 60cc43fc888428bb2f18f08997432d426a243338:
>
> Linux 4.17-rc1 (2018-04-15 18:24:20 -0700)
>
> are available in the git repository at:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-uniphier.git
> tags/uniphier-dt64-v4.18
>
> for you to fetch changes up to b076ff8bddfba793d49bca14feb49a0e84f41843:
>
> arm64: dts: uniphier: add syscon-phy-mode property to each ethernet
> node (2018-04-25 00:21:14 +0900)
>
> ----------------------------------------------------------------
> UniPhier ARM64 SoC DT updates for v4.18
>
> - add more properties to ethernet nodes
>
> ----------------------------------------------------------------
> Kunihiko Hayashi (2):
> arm64: dts: uniphier: add clock-names and reset-names to ethernet node
> arm64: dts: uniphier: add syscon-phy-mode property to each ethernet node
Merged, same comment as for the 32-bit pull request. Thanks!
-Olof
^ permalink raw reply
* [GIT PULL] ARM: dts: uniphier: UniPhier DT updates for v4.18
From: Olof Johansson @ 2018-05-25 12:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAK7LNATphrRyYvMXMMJz--UtfNk2BZLWHAp3XXpQLob5=5w2Qg@mail.gmail.com>
On Sun, May 20, 2018 at 11:34:08AM +0900, Masahiro Yamada wrote:
> Hi Arnd, Olof,
>
> Here are UniPhier DT (32bit) updates for the v4.18 merge window.
> Please pull!
>
>
> The following changes since commit 60cc43fc888428bb2f18f08997432d426a243338:
>
> Linux 4.17-rc1 (2018-04-15 18:24:20 -0700)
>
> are available in the git repository at:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-uniphier.git
> tags/uniphier-dt-v4.18
>
> for you to fetch changes up to 526f872b8492fbfb1a0f342e601bdc5ba322f16b:
>
> ARM: dts: uniphier: add syscon-phy-mode property to each ethernet
> node (2018-04-25 00:21:51 +0900)
>
> ----------------------------------------------------------------
> UniPhier ARM SoC DT updates for v4.18
>
> - add more properties to ethernet nodes
>
> ----------------------------------------------------------------
> Kunihiko Hayashi (2):
> ARM: dts: uniphier: add required clocks and resets to Pro4 ethernet node
> ARM: dts: uniphier: add syscon-phy-mode property to each ethernet node
Hi,
Merged, but please spend a little more effort on the tag description (what are
these new properties giving you in functionality?)
-Olof
^ permalink raw reply
* [PATCH v2 1/8] driver core: make deferring probe after init optional
From: Robin Murphy @ 2018-05-25 12:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAL_JsqJK69A3W=YrSfvPetM95CROOJhU1bW1rMEOGtji=t0ORQ@mail.gmail.com>
On 24/05/18 21:57, Rob Herring wrote:
> On Thu, May 24, 2018 at 2:00 PM, Greg Kroah-Hartman
> <gregkh@linuxfoundation.org> wrote:
>> On Thu, May 24, 2018 at 12:50:17PM -0500, Rob Herring wrote:
>>> Deferred probe will currently wait forever on dependent devices to probe,
>>> but sometimes a driver will never exist. It's also not always critical for
>>> a driver to exist. Platforms can rely on default configuration from the
>>> bootloader or reset defaults for things such as pinctrl and power domains.
>>> This is often the case with initial platform support until various drivers
>>> get enabled. There's at least 2 scenarios where deferred probe can render
>>> a platform broken. Both involve using a DT which has more devices and
>>> dependencies than the kernel supports. The 1st case is a driver may be
>>> disabled in the kernel config. The 2nd case is the kernel version may
>>> simply not have the dependent driver. This can happen if using a newer DT
>>> (provided by firmware perhaps) with a stable kernel version.
>>>
>>> Subsystems or drivers may opt-in to this behavior by calling
>>> driver_deferred_probe_check_init_done() instead of just returning
>>> -EPROBE_DEFER. They may use additional information from DT or kernel's
>>> config to decide whether to continue to defer probe or not.
>>>
>>> Cc: Alexander Graf <agraf@suse.de>
>>> Signed-off-by: Rob Herring <robh@kernel.org>
>>> ---
>>> drivers/base/dd.c | 17 +++++++++++++++++
>>> include/linux/device.h | 2 ++
>>> 2 files changed, 19 insertions(+)
>>>
>>> diff --git a/drivers/base/dd.c b/drivers/base/dd.c
>>> index c9f54089429b..d6034718da6f 100644
>>> --- a/drivers/base/dd.c
>>> +++ b/drivers/base/dd.c
>>> @@ -226,6 +226,16 @@ void device_unblock_probing(void)
>>> driver_deferred_probe_trigger();
>>> }
>>>
>>> +int driver_deferred_probe_check_init_done(struct device *dev, bool optional)
>>> +{
>>> + if (optional && initcalls_done) {
>>
>> Wait, what's the "optional" mess here?
>
> My intent was that subsystems just always call this function and never
> return EPROBE_DEFER themselves. Then the driver core can make
> decisions as to what to do (such as the timeout added in the next
> patch). Or it can print common error/debug messages. So optional is a
> hint to allow subsystems per device control.
Maybe just driver_defer_probe() might be a more descriptive name? To me,
calling "foo_check_x()" with a parameter that says "I don't actually
care about x" is the really unintuitive bit.
>>
>> The caller knows this value, so why do you need to even pass it in here?
>
> Because regardless of the value, we always stop deferring when/if we
> hit the timeout and the caller doesn't know about the timeout. If we
> get rid of it, we'd need functions for both init done and for deferred
> timeout.
>
>> And bool values that are not obvious are horrid. I had to go look this
>> up when reading the later patches that just passed "true" in this
>> variable as I had no idea what that meant.
>
> Perhaps inverting it and calling it "keep_deferring" would be better.
> However, the flag is ignored if we have timed out.
Perhaps an enum (or bitmask of named flags) then? That would allow the
most readability at callsites, plus it seems quite likely that we may
want intermediate degrees of "deferral strictness" eventually.
Robin.
>>
>> So as-is, no, this isn't ok, sorry.
>>
>> And at the least, this needs some kerneldoc to explain it :)
>
> That part is easy enough to fix.
>
> Rob
>
^ permalink raw reply
* [GIT PULL] ARM: mvebu: dt64 for v4.18 (#1)
From: Olof Johansson @ 2018-05-25 12:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <871se829iq.fsf@bootlin.com>
On Fri, May 18, 2018 at 06:50:21PM +0200, Gregory CLEMENT wrote:
> Hi,
>
> Here is the first pull request for dt64 for mvebu for v4.18.
>
> Gregory
>
> The following changes since commit 60cc43fc888428bb2f18f08997432d426a243338:
>
> Linux 4.17-rc1 (2018-04-15 18:24:20 -0700)
>
> are available in the Git repository at:
>
> git://git.infradead.org/linux-mvebu.git tags/mvebu-dt64-4.18-1
>
> for you to fetch changes up to bd473ecda24c6214868d58500c4d7569f6597946:
>
> arm64: dts: marvell: armada-37xx: mark the gpio controllers as irq controller (2018-05-18 18:35:16 +0200)
Merged, thanks!
-Olof
^ permalink raw reply
* [GIT PULL] ARM: mvebu: dt for v4.18 (#1)
From: Olof Johansson @ 2018-05-25 12:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <8736yo29jb.fsf@bootlin.com>
On Fri, May 18, 2018 at 06:50:00PM +0200, Gregory CLEMENT wrote:
> Hi,
>
> Here is the first pull request for dt for mvebu for v4.18.
>
> Gregory
>
> The following changes since commit 60cc43fc888428bb2f18f08997432d426a243338:
>
> Linux 4.17-rc1 (2018-04-15 18:24:20 -0700)
>
> are available in the Git repository at:
>
> git://git.infradead.org/linux-mvebu.git tags/mvebu-dt-4.18-1
>
> for you to fetch changes up to 163043ab55210dbb92e36c1220a721f404df6834:
>
> ARM: dts: armada-xp-98dx: Add NAND pinctrl information (2018-05-18 18:36:57 +0200)
Definitely a pretty noisy pull request, but it's a good move from the format
that requires mimicing the tree structure and using phandles instead.
Merged!
-Olof
^ permalink raw reply
* [PATCH v3 6/6] tty/serial: atmel: changed the driver to work under at91-usart mfd
From: Radu Pirea @ 2018-05-25 12:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <4d70c73e-9db7-bdff-7414-04a4843acae3@sorico.fr>
On 05/15/2018 04:14 PM, Richard Genoud wrote:
> On 15/05/2018 14:47, Radu Pirea wrote:
>> On Mon, 2018-05-14 at 12:57 +0200, Richard Genoud wrote:
>>> After your patch, the DMA is not selected anymore:
>>> atmel_usart_serial atmel_usart_serial.0.auto: TX channel not
>>> available, switch to pio
>>> instead of:
>>> atmel_usart fffff200.serial: using dma1chan2 for tx DMA transfers
>>>
>> Fixed.
>>> And the kernel doesn't log anymore on the serial console, despite the
>>> loglevel=8
>>> (after reverting this series, the kernel logs reappears on the serial
>>> console)
>>>
>> Which serial are you using as console?
> fffff200.serial (sam9g35-cm)
> ( stdout-path = "serial0:115200n8"; in the DTS )
>
> With this series applied, all the kernel log goes on the screen.
> Without, it goes on the serial debug.
>
I tested again with archlinux arm and poky-linux4sam release as distros
and kernel log goes on the serial debug. Can you give me more details
like cmdline?
>>> (tests done on sam9g35)
>>>
>> I will consider the rest of suggestions.
>>> regards,
>>> Richard
>
^ permalink raw reply
* [GIT PULL] ARM: mvebu: arm64 for v4.18 (#1)
From: Olof Johansson @ 2018-05-25 12:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <874lj429kq.fsf@bootlin.com>
On Fri, May 18, 2018 at 06:49:09PM +0200, Gregory CLEMENT wrote:
> Hi,
>
> Here is the first pull request for arm64 for mvebu for v4.18.
>
> Gregory
>
> The following changes since commit 60cc43fc888428bb2f18f08997432d426a243338:
>
> Linux 4.17-rc1 (2018-04-15 18:24:20 -0700)
>
> are available in the Git repository at:
>
> git://git.infradead.org/linux-mvebu.git tags/mvebu-arm64-4.18-1
>
> for you to fetch changes up to 3eb0a48af488b5e83d2986943a1b6905ca753571:
>
> arm64: defconfig: enable the Armada thermal driver (2018-05-16 20:08:31 +0200)
Merged, thanks!
-Olof
^ permalink raw reply
* [GIT PULL 5/5] arm64: tegra: Device tree changes for v4.18-rc1
From: Olof Johansson @ 2018-05-25 12:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180518142245.20242-5-thierry.reding@gmail.com>
On Fri, May 18, 2018 at 04:22:45PM +0200, Thierry Reding wrote:
> Hi ARM SoC maintainers,
>
> The following changes since commit 60cc43fc888428bb2f18f08997432d426a243338:
>
> Linux 4.17-rc1 (2018-04-15 18:24:20 -0700)
>
> are available in the Git repository at:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux.git tags/tegra-for-4.18-arm64-dt
>
> for you to fetch changes up to 9df50ba76ac1485b844beffa1f3f5d9659d9cdaf:
>
> arm64: tegra: Make BCM89610 PHY interrupt as active low (2018-05-03 11:48:16 +0200)
>
> I already sent this out as a fix for v4.17, so if you decide to pick
> that up you can ignore this one. I've only included it here in case you
> had objections to take it into v4.17 at this point.
Ok, thanks -- merged the fix so not touching this.
-Olof
^ permalink raw reply
* [GIT PULL 4/5] ARM: tegra: Device tree changes for v4.18-rc1
From: Olof Johansson @ 2018-05-25 12:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180518142245.20242-4-thierry.reding@gmail.com>
On Fri, May 18, 2018 at 04:22:44PM +0200, Thierry Reding wrote:
> Hi ARM SoC maintainers,
>
> The following changes since commit 60cc43fc888428bb2f18f08997432d426a243338:
>
> Linux 4.17-rc1 (2018-04-15 18:24:20 -0700)
>
> are available in the Git repository at:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux.git tags/tegra-for-4.18-arm-dt
>
> for you to fetch changes up to dc4ea601be724d7ad37c8c5b1059417126e97e27:
>
> ARM: dts: tegra114: Add IOMMU nodes to Host1x and its clients (2018-05-04 17:21:02 +0200)
>
> Thanks,
> Thierry
>
> ----------------------------------------------------------------
> ARM: tegra: Device tree changes for v4.18-rc1
>
> Contains a fix for the high-speed UART on Toradex Apalis TK1 boards as
> well as IOMMU enablement for various devices on Tegra30 and Tegra30.
>
> ----------------------------------------------------------------
> Dmitry Osipenko (2):
> ARM: dts: tegra30: Add IOMMU nodes to Host1x and its clients
> ARM: dts: tegra114: Add IOMMU nodes to Host1x and its clients
>
> Marcel Ziswiler (1):
> ARM: tegra: apalis-tk1: Fix high speed UART compatible
Merged, thanks!
-Olof
^ permalink raw reply
* [GIT PULL 3/5] ARM: tegra: Core changes for v4.18-rc1
From: Olof Johansson @ 2018-05-25 12:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180518142245.20242-3-thierry.reding@gmail.com>
On Fri, May 18, 2018 at 04:22:43PM +0200, Thierry Reding wrote:
> Hi ARM SoC maintainers,
>
> The following changes since commit 60cc43fc888428bb2f18f08997432d426a243338:
>
> Linux 4.17-rc1 (2018-04-15 18:24:20 -0700)
>
> are available in the Git repository at:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux.git tags/tegra-for-4.18-arm-soc
>
> for you to fetch changes up to 15164e0072b579f77c9025f3da3ed931869b89cd:
>
> ARM: tegra: Create platform device for tegra20-cpufreq driver (2018-05-18 11:15:42 +0200)
>
> Thanks,
> Thierry
>
> ----------------------------------------------------------------
> ARM: tegra: Core changes for v4.18-rc1
>
> Contains a single patch that instantiates a platform device for the CPU
> frequency driver.
Merged, thanks.
-Olof
^ permalink raw reply
* [GIT PULL v2 2/5] memory: tegra: Changes for v4.18-rc1
From: Olof Johansson @ 2018-05-25 12:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180518215837.29076-1-thierry.reding@gmail.com>
On Fri, May 18, 2018 at 11:58:37PM +0200, Thierry Reding wrote:
> Hi ARM SoC maintainers,
>
> The following changes since commit 60cc43fc888428bb2f18f08997432d426a243338:
>
> Linux 4.17-rc1 (2018-04-15 18:24:20 -0700)
>
> are available in the Git repository at:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux.git tags/tegra-for-4.18-memory-v2
>
> for you to fetch changes up to a1be3cfdfb81cc55c1b2feb73aca6945f61acddb:
>
> dt-bindings: memory: tegra: Remove Tegra114 SATA and AFI reset definitions (2018-05-18 22:45:01 +0200)
>
> This contains the same patches as the previous pull request with the exception
> that the final two are reordered to keep the set bisectible.
>
> Thanks,
> Thierry
>
> ----------------------------------------------------------------
> memory: tegra: Changes for v4.18-rc1
>
> This contains some cleanup of the memory controller driver as well as
> unification work to share more code between Tegra20 and later SoC
> generations. Also included are an implementation for the hot resets
> functionality by the memory controller which is required to properly
> reset busy hardware.
>
> ----------------------------------------------------------------
> Dmitry Osipenko (14):
> dt-bindings: memory: tegra: Add hot resets definitions
> memory: tegra: Do not handle spurious interrupts
> memory: tegra: Setup interrupts mask before requesting IRQ
> memory: tegra: Apply interrupts mask per SoC
> memory: tegra: Remove unused headers inclusions
> memory: tegra: Squash tegra20-mc into common tegra-mc driver
> memory: tegra: Introduce memory client hot reset
> memory: tegra: Add Tegra20 memory controller hot resets
> memory: tegra: Add Tegra30 memory controller hot resets
> memory: tegra: Add Tegra114 memory controller hot resets
> memory: tegra: Add Tegra124 memory controller hot resets
> memory: tegra: Register SMMU after MC driver became ready
> memory: tegra: Remove Tegra114 SATA and AFI reset definitions
> dt-bindings: memory: tegra: Remove Tegra114 SATA and AFI reset definitions
>
> Thierry Reding (1):
> memory: tegra: Add Tegra210 memory controller hot resets
Merged, thanks.
-Olof
^ permalink raw reply
* [PATCH] drm/rockchip: vop: fix irq disabled after vop driver probed
From: Heiko Stuebner @ 2018-05-25 12:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <8495bffd-2a52-ca85-1bc9-afc3ea0af8e4@arm.com>
Hi Marc,
Am Freitag, 25. Mai 2018, 13:07:02 CEST schrieb Marc Zyngier:
> [Thanks Robin for pointing me to that patch.]
>
> Hi Heiko,
>
> On 24/05/18 23:06, Heiko St?bner wrote:
> > From: Sandy Huang <hjc@rock-chips.com>
> >
> > The vop irq is shared between vop and iommu and irq probing in the
> > iommu driver moved to the probe function recently. This can in some
> > cases lead to a stall if the irq is triggered while the vop driver
> > still has it disabled.
> >
> > But there is no real need to disable the irq, as the vop can simply
> > also track its enabled state and ignore irqs in that case.
> >
> > So remove the enable/disable handling and add appropriate condition
> > to the irq handler.
> >
> > Signed-off-by: Sandy Huang <hjc@rock-chips.com>
> > [added an actual commit message]
> > Signed-off-by: Heiko Stuebner <heiko@sntech.de>
> > ---
> > Hi Ezequiel,
> >
> > this patch came from a discussion I had with Rockchip people over the
> > iommu changes and resulting issues back in april, but somehow was
> > forgotten and not posted to the lists. Correcting that now.
> >
> > So removing the enable/disable voodoo on the shared interrupt is
> > the preferred way.
> >
> > drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 13 ++++++-------
> > 1 file changed, 7 insertions(+), 7 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
> > index 510cdf0..61493d4 100644
> > --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
> > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
> > @@ -549,8 +549,6 @@ static int vop_enable(struct drm_crtc *crtc)
> >
> > spin_unlock(&vop->reg_lock);
> >
> > - enable_irq(vop->irq);
> > -
> > drm_crtc_vblank_on(crtc);
> >
> > return 0;
> > @@ -596,8 +594,6 @@ static void vop_crtc_atomic_disable(struct drm_crtc *crtc,
> >
> > vop_dsp_hold_valid_irq_disable(vop);
> >
> > - disable_irq(vop->irq);
> > -
> > vop->is_enabled = false;
> >
> > /*
> > @@ -1168,6 +1164,13 @@ static irqreturn_t vop_isr(int irq, void *data)
> > int ret = IRQ_NONE;
> >
> > /*
> > + * since the irq is shared with iommu, iommu irq is enabled before vop
> > + * enable, so before vop enable we do nothing.
> > + */
> > + if (!vop->is_enabled)
> > + return IRQ_NONE;
> > +
>
> What guarantee do we have that the IOMMU will actually service that
> interrupt? Can't we get into a situation where the interrupt gets
> ignored by both drivers and subsequently disabled by the core irq code
> as being spurious?
>
> From what I understood of the way things are plugged together on the
> rockchip platforms, each individual VOP is behind a single IOMMU, hence
> there there is hardly any point in handling IOMMU interrupts if the VOP
> is off.
Yeah, which is probably the reason that patch fell through the cracks
initially. I resurrected it from the internal discussion because of the issue
described below.
> But I'm missing the actual reason behind this patch. Could you enlighten me?
Recently the iommu driver moved the irq request from the iommu enablement
to its probe function. With that change Ezequiel got various stalls, see
https://lkml.org/lkml/2018/5/24/1347
Heiko
^ permalink raw reply
* [GIT PULL 2/5] memory: tegra: Changes for v4.18-rc1
From: Olof Johansson @ 2018-05-25 12:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180518204351.GA26800@ulmo>
On Fri, May 18, 2018 at 10:43:51PM +0200, Thierry Reding wrote:
> On Fri, May 18, 2018 at 04:22:42PM +0200, Thierry Reding wrote:
> > Hi ARM SoC maintainers,
> >
> > The following changes since commit 60cc43fc888428bb2f18f08997432d426a243338:
> >
> > Linux 4.17-rc1 (2018-04-15 18:24:20 -0700)
> >
> > are available in the Git repository at:
> >
> > git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux.git tags/tegra-for-4.18-memory
> >
> > for you to fetch changes up to bef89a8d81ca97aca864778746b110cf52847868:
> >
> > memory: tegra: Remove Tegra114 SATA and AFI reset definitions (2018-05-18 12:33:02 +0200)
> >
> > Thanks,
> > Thierry
> >
> > ----------------------------------------------------------------
> > memory: tegra: Changes for v4.18-rc1
> >
> > This contains some cleanup of the memory controller driver as well as
> > unification work to share more code between Tegra20 and later SoC
> > generations. Also included are an implementation for the hot resets
> > functionality by the memory controller which is required to properly
> > reset busy hardware.
> >
> > ----------------------------------------------------------------
> > Dmitry Osipenko (14):
> > dt-bindings: memory: tegra: Add hot resets definitions
> > memory: tegra: Do not handle spurious interrupts
> > memory: tegra: Setup interrupts mask before requesting IRQ
> > memory: tegra: Apply interrupts mask per SoC
> > memory: tegra: Remove unused headers inclusions
> > memory: tegra: Squash tegra20-mc into common tegra-mc driver
> > memory: tegra: Introduce memory client hot reset
> > memory: tegra: Add Tegra20 memory controller hot resets
> > memory: tegra: Add Tegra30 memory controller hot resets
> > memory: tegra: Add Tegra114 memory controller hot resets
> > memory: tegra: Add Tegra124 memory controller hot resets
> > memory: tegra: Register SMMU after MC driver became ready
> > dt-bindings: memory: tegra: Remove Tegra114 SATA and AFI reset definitions
> > memory: tegra: Remove Tegra114 SATA and AFI reset definitions
>
> Please don't pull this just yet. Dmitry just pointed out to me that the
> final two patches here break bisectibility. I'll reorder them and will
> send out a new pull request.
Please delete the tag when you withdraw a pull request, and do the next request
with a new tag name. That way I don't have to scan my mailbox to make sure all
pull requests are still valid when I go through it and won't accidentally merge
something that you have withdrawn.
-Olof
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox