Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] arm/vdso: introduce vdso_mremap hook
From: Dmitry Safonov @ 2016-11-07 17:16 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <0b41c28b-20ef-332f-d8d6-e381e05b8252@codeaurora.org>

On 11/07/2016 08:00 PM, Christopher Covington wrote:
> Hi Dmitry,
>
> On 11/01/2016 01:22 PM, Dmitry Safonov wrote:
>>   Add vdso_mremap hook which will fix context.vdso pointer after mremap()
>> on vDSO vma. This is needed for correct landing after syscall execution.
>> Primary goal of this is for CRIU on arm - we need to restore vDSO image
>> at the exactly same place where the vma was in dumped application. With
>> the help of this hook we'll move vDSO at the new position.
>>   The CRIU code handles situations like when vDSO of dumped application
>> was different from vDSO on restoring system. This usally happens when
>> some new symbols are being added to vDSO. In these situations CRIU
>> inserts jump trampolines from old vDSO blob to new vDSO on restore.
>> By that reason even if on restore vDSO blob lies on the same address as
>> blob in dumped application - we still need to move it if it differs.
>>
>>   There was previously attempt to add this functionality for arm64 by
>> arch_mremap hook [1], while this patch introduces this with minimal
>> effort - the same way I've added it to x86:
>> commit b059a453b1cf ("x86/vdso: Add mremap hook to vm_special_mapping")
>>
>>   At this moment, vdso restoring code is disabled for arm/arm64 arch
>> in CRIU [2], so C/R is only working for !CONFIG_VDSO kernels. This patch
>> is aimed to fix that.
>>   The same hook may be introduced for arm64 kernel, but at this moment
>> arm64 vdso code is actively reworked by Kevin, so we can do it on top.
>>   Separately, I've refactored arch_remap hook out from ppc64 [3].
>>
>> [1]: https://marc.info/?i=1448455781-26660-1-git-send-email-cov at codeaurora.org
>> [2]: https://github.com/xemul/criu/blob/master/Makefile#L39
>> [3]: https://marc.info/?i=20161027170948.8279-1-dsafonov at virtuozzo.com
>>
>> Cc: Kevin Brodsky <kevin.brodsky@arm.com>
>> Cc: Christopher Covington <cov@codeaurora.org>
>> Cc: Andy Lutomirski <luto@amacapital.net>
>> Cc: Oleg Nesterov <oleg@redhat.com>
>> Cc: Russell King <linux@armlinux.org.uk>
>> Cc: Will Deacon <will.deacon@arm.com>
>> Cc: linux-arm-kernel at lists.infradead.org
>> Cc: linux-mm at kvack.org
>> Cc: Cyrill Gorcunov <gorcunov@openvz.org>
>> Cc: Pavel Emelyanov <xemul@virtuozzo.com>
>> Signed-off-by: Dmitry Safonov <dsafonov@virtuozzo.com>
>> ---
>>  arch/arm/kernel/vdso.c | 21 +++++++++++++++++++++
>>  1 file changed, 21 insertions(+)
>>
>> diff --git a/arch/arm/kernel/vdso.c b/arch/arm/kernel/vdso.c
>> index 53cf86cf2d1a..d1001f87c2f6 100644
>> --- a/arch/arm/kernel/vdso.c
>> +++ b/arch/arm/kernel/vdso.c
>> @@ -54,8 +54,11 @@ static const struct vm_special_mapping vdso_data_mapping = {
>>  	.pages = &vdso_data_page,
>>  };
>>
>> +static int vdso_mremap(const struct vm_special_mapping *sm,
>> +		struct vm_area_struct *new_vma);
>>  static struct vm_special_mapping vdso_text_mapping __ro_after_init = {
>>  	.name = "[vdso]",
>> +	.mremap = vdso_mremap,
>>  };
>>
>>  struct elfinfo {
>> @@ -254,6 +257,24 @@ void arm_install_vdso(struct mm_struct *mm, unsigned long addr)
>>  		mm->context.vdso = addr;
>>  }
>>
>> +static int vdso_mremap(const struct vm_special_mapping *sm,
>> +		struct vm_area_struct *new_vma)
>> +{
>> +	unsigned long new_size = new_vma->vm_end - new_vma->vm_start;
>> +	unsigned long vdso_size = (vdso_total_pages - 1) << PAGE_SHIFT;
>> +
>> +	/* Disallow partial vDSO blob remap */
>> +	if (vdso_size != new_size)
>> +		return -EINVAL;
>> +
>> +	if (WARN_ON_ONCE(current->mm != new_vma->vm_mm))
>> +		return -EFAULT;
>> +
>> +	current->mm->context.vdso = new_vma->vm_start;
>> +
>> +	return 0;
>> +}
>> +
>>  static void vdso_write_begin(struct vdso_data *vdata)
>>  {
>>  	++vdso_data->seq_count;
>>
>
> What do you think about putting this code somewhere generic (not under
> arch/*), so that powerpc and arm64 can reuse it once the cosmetic changes
> to make them compatible are made? My thought was that it could be defined
> underneath CONFIG_GENERIC_VDSO, which architectures could select as they
> became compatible.

Hi Chistopher,

Well, I don't think we won something out of generalization of simple 
assignment for context.vdso pointer accross arches. And a need to rename
vdso over arches for saving one single line?
Also I don't like a bit this arch_mremap hook and need to nullify
vdso pointer.

But, anyway, I don't mind if your patches got applied instead - this
unability to move vdso prevent's to support vdso vma C/R, as you know ;)

-- 
              Dmitry

^ permalink raw reply

* [PATCH] serial: sirf: Simplify a test
From: Julia Lawall @ 2016-11-07 17:19 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <2916662.De1FDumaQl@wuerfel>



On Mon, 7 Nov 2016, Arnd Bergmann wrote:

> On Tuesday, November 1, 2016 8:03:33 AM CET Christophe JAILLET wrote:
> > 'dmaengine_prep_dma_cyclic()' does not return an error pointer, so the test
> > can be simplified to be more consistent.
> >
> > Signed-off-by: Christophe JAILLET <christophe.jaillet@wanadoo.fr>
>
> The change looks correct in principle. It would be good to automate looking
> for other instances of this bug. How did you find it? Do you have e.g. a
> coccinelle script or did you just stumble over the issue by accident?

I'm working on collecting this information in a more general way.  It is
complicated by the fact that there are some functions that have the same
names but different behaviors, and I want to be clear about when that is
an issue.  There are nevertheless limits to the accuracy that can be
obtained with Coccinelle, because Coccinelle doesn't take values into
account.  Sometimes a variable is initialized to NULL, just to have a
starting value, but in practice the only way to reach an error return is
via conditionals that have the effect of ensuring that the value is
ERR_PTR.  So at least the cases that are reported as being able to return
both NULL and ERR_PTR will need some careful checking.

julia

>
> There is one problem with your patch:
>
> >  drivers/tty/serial/sirfsoc_uart.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c
> > index b186c9c4f850..666ca3156961 100644
> > --- a/drivers/tty/serial/sirfsoc_uart.c
> > +++ b/drivers/tty/serial/sirfsoc_uart.c
> > @@ -609,7 +609,7 @@ static void sirfsoc_uart_start_next_rx_dma(struct uart_port *port)
> >                 sirfport->rx_dma_items.dma_addr, SIRFSOC_RX_DMA_BUF_SIZE,
> >                 SIRFSOC_RX_DMA_BUF_SIZE / 2,
> >                 DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
> > -       if (IS_ERR_OR_NULL(sirfport->rx_dma_items.desc)) {
> > +       if (!sirfport->rx_dma_items.desc) {
> >                 dev_err(port->dev, "DMA slave single fail\n");
> >                 return;
> >         }
>
> The serial driver is for the sirf platform, which uses the sirf-dma
> dmaengine driver, and that particular driver has an incorrect
> dma_prep_cyclic implementation, so I think we also need this fix:
>
> diff --git a/drivers/dma/sirf-dma.c b/drivers/dma/sirf-dma.c
> index 8f62edad51be..220c611c89ae 100644
> --- a/drivers/dma/sirf-dma.c
> +++ b/drivers/dma/sirf-dma.c
> @@ -775,7 +775,7 @@ sirfsoc_dma_prep_cyclic(struct dma_chan *chan, dma_addr_t addr,
>  	 * BUFB
>  	 */
>  	if (buf_len !=  2 * period_len)
> -		return ERR_PTR(-EINVAL);
> +		return NULL;
>
>  	/* Get free descriptor */
>  	spin_lock_irqsave(&schan->lock, iflags);
>
>
> 	Arnd
> --
> To unsubscribe from this list: send the line "unsubscribe kernel-janitors" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

^ permalink raw reply

* [PATCH 3/6] clk: Add driver for Maxim-8997 PMIC clocks
From: Pankaj Dubey @ 2016-11-07 17:20 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <63750c2f-35cb-91ab-276b-c788f51081cb@osg.samsung.com>

Hi Javier,

On 7 November 2016 at 20:31, Javier Martinez Canillas
<javier@osg.samsung.com> wrote:
> Hello Pankaj,
>
> On 11/07/2016 07:09 AM, Pankaj Dubey wrote:
>> The MAX8997 PMIC has 32.786kHz crystal oscillator which provides an
>> accurate low frequency clock for MAX8997 internal circuit as well as
>> external circuit. This patch adds support for these two clocks.
>>
>> CC: Michael Turquette <mturquette@baylibre.com>
>> CC: Rob Herring <robh+dt@kernel.org>
>> CC: devicetree at vger.kernel.org
>> CC: linux-clk at vger.kernel.org
>> Signed-off-by: Pankaj Dubey <pankaj.dubey@samsung.com>
>> ---
>
> What kernel version are you basing this on? The Maxim common clock code

This patch series, I have prepared on Krzysztof's for-next which is 4.9-rc1,

> is going away for v4.9 and instead the clk-max77686 driver supports both
> 77686 and 77802 clocks. See commit 8ad313fe4e00 ("clk: max77686: Combine
> Maxim max77686 and max77802 driver").
>
> Since the 8997 clock IP looks very similar to 77802 AFAICT, you should
> also extend the clk-max77686 driver to have 8997 support.
>

I was not aware of this change. I will check this and if I can
reuse/extend max77686 for 8997 I will do it.

Thanks,
Pankaj Dubey

> Best regards,
> --
> Javier Martinez Canillas
> Open Source Group
> Samsung Research America
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* [PATCH 0/6] Add support for MAX8997 Clock Driver
From: Krzysztof Kozlowski @ 2016-11-07 17:27 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1478513376-14307-1-git-send-email-pankaj.dubey@samsung.com>

On Mon, Nov 07, 2016 at 03:39:30PM +0530, Pankaj Dubey wrote:
> During recent test on Exynos4210 based Origen board, I observed
> RTC1 probe is failing giving following error message:
> 
> [    2.195817] s3c-rtc 10070000.rtc: failed to find rtc source clock
> [    2.200475] s3c-rtc: probe of 10070000.rtc failed with error -2
> [    2.206597] i2c /dev entries driver
> 
> This is mainly because S3C-RTC expects two clocks "rtc" and "rtc_src".
> In case of Origen board this second clock is supplied by MAX8997 clock
> oscillator.
> This patch series modified MAX8997 MFD driver for supporting regmap, and 
> adds max8997-clk driver. Also it documentation where-ever required and
> extends RTC node in exynos4210-origen.dts for supporting both clocks.
> 
> After this patch series, RTC is getting probed properly on Origen board.
> 
> This patch series is tested for SMP boot on Origen board.

No need to re-invent the wheel:
https://lkml.org/lkml/2016/6/17/57
http://lists.infradead.org/pipermail/linux-arm-kernel/2016-June/437113.html

I won't be sending updates for these patches. Feel free to continue the
work.

BR,
Krzysztof

> 
> Pankaj Dubey (6):
>   mfd: max8997: Initialize max8997 register map
>   dt-bindings: clk: max8997: Add DT binding documentation
>   clk: Add driver for Maxim-8997 PMIC clocks
>   ARM: dts: Add clock provider specific properties to max8997 node
>   mfd: max8997: Add max8997-clk name in mfd_cell
>   ARM: dts: Extend the S3C RTC node with rtc_src clock
> 
>  .../devicetree/bindings/clock/maxim,max8997.txt    | 44 +++++++++++++
>  .../bindings/regulator/max8997-regulator.txt       |  3 +
>  arch/arm/boot/dts/exynos4210-origen.dts            |  6 +-
>  arch/arm/boot/dts/exynos4210-trats.dts             |  3 +-
>  drivers/clk/Kconfig                                | 10 +++
>  drivers/clk/Makefile                               |  1 +
>  drivers/clk/clk-max8997.c                          | 76 ++++++++++++++++++++++
>  drivers/mfd/max8997.c                              | 15 +++++
>  include/dt-bindings/clock/maxim,max8997.h          | 23 +++++++
>  include/linux/mfd/max8997-private.h                |  3 +
>  10 files changed, 182 insertions(+), 2 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/clock/maxim,max8997.txt
>  create mode 100644 drivers/clk/clk-max8997.c
>  create mode 100644 include/dt-bindings/clock/maxim,max8997.h
> 
> -- 
> 2.7.4
> 

^ permalink raw reply

* [PATCH V3 1/2] ARM: imx: mmdc perf function support i.MX6QP
From: Frank Li @ 2016-11-07 17:30 UTC (permalink / raw)
  To: linux-arm-kernel

i.MX6QP added new register bit PROFILE_SEL in MADPCR0.
need set it at perf start.

Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
Change from V2 - V3
- Use MMDC_FLAG_PROFILE_SEL
- Use flags instead of driver_data
- fix commit message typo
- add const
- use u32 val.
Change from V1 - V2
- remove fsl_mmdc_devtype

 arch/arm/mach-imx/mmdc.c | 38 ++++++++++++++++++++++++++++++++------
 1 file changed, 32 insertions(+), 6 deletions(-)

diff --git a/arch/arm/mach-imx/mmdc.c b/arch/arm/mach-imx/mmdc.c
index d82d14c..ba96bf9 100644
--- a/arch/arm/mach-imx/mmdc.c
+++ b/arch/arm/mach-imx/mmdc.c
@@ -44,6 +44,7 @@
 #define DBG_RST			0x2
 #define PRF_FRZ			0x4
 #define CYC_OVF			0x8
+#define PROFILE_SEL		0x10
 
 #define MMDC_MADPCR0	0x410
 #define MMDC_MADPSR0	0x418
@@ -55,10 +56,29 @@
 
 #define MMDC_NUM_COUNTERS	6
 
+#define MMDC_FLAG_PROFILE_SEL	0x1
+
 #define to_mmdc_pmu(p) container_of(p, struct mmdc_pmu, pmu)
 
 static int ddr_type;
 
+struct fsl_mmdc_devtype_data {
+	unsigned int flags;
+};
+
+static const struct fsl_mmdc_devtype_data imx6q_data = {
+};
+
+static const struct fsl_mmdc_devtype_data imx6qp_data = {
+	.flags = MMDC_FLAG_PROFILE_SEL,
+};
+
+static const struct of_device_id imx_mmdc_dt_ids[] = {
+	{ .compatible = "fsl,imx6q-mmdc", .data = (void *)&imx6q_data},
+	{ .compatible = "fsl,imx6qp-mmdc", .data = (void *)&imx6qp_data},
+	{ /* sentinel */ }
+};
+
 #ifdef CONFIG_PERF_EVENTS
 
 static DEFINE_IDA(mmdc_ida);
@@ -83,6 +103,7 @@ struct mmdc_pmu {
 	struct device *dev;
 	struct perf_event *mmdc_events[MMDC_NUM_COUNTERS];
 	struct hlist_node node;
+	struct fsl_mmdc_devtype_data *devtype_data;
 };
 
 /*
@@ -307,6 +328,7 @@ static void mmdc_pmu_event_start(struct perf_event *event, int flags)
 	struct mmdc_pmu *pmu_mmdc = to_mmdc_pmu(event->pmu);
 	struct hw_perf_event *hwc = &event->hw;
 	void __iomem *mmdc_base, *reg;
+	u32 val;
 
 	mmdc_base = pmu_mmdc->mmdc_base;
 	reg = mmdc_base + MMDC_MADPCR0;
@@ -321,7 +343,12 @@ static void mmdc_pmu_event_start(struct perf_event *event, int flags)
 	local64_set(&hwc->prev_count, 0);
 
 	writel(DBG_RST, reg);
-	writel(DBG_EN, reg);
+
+	val = DBG_EN;
+	if (pmu_mmdc->devtype_data->flags & MMDC_FLAG_PROFILE_SEL)
+		val |= PROFILE_SEL;
+
+	writel(val, reg);
 }
 
 static int mmdc_pmu_event_add(struct perf_event *event, int flags)
@@ -436,6 +463,8 @@ static int imx_mmdc_perf_init(struct platform_device *pdev, void __iomem *mmdc_b
 	char *name;
 	int mmdc_num;
 	int ret;
+	const struct of_device_id *of_id =
+		of_match_device(imx_mmdc_dt_ids, &pdev->dev);
 
 	pmu_mmdc = kzalloc(sizeof(*pmu_mmdc), GFP_KERNEL);
 	if (!pmu_mmdc) {
@@ -450,6 +479,8 @@ static int imx_mmdc_perf_init(struct platform_device *pdev, void __iomem *mmdc_b
 		name = devm_kasprintf(&pdev->dev,
 				GFP_KERNEL, "mmdc%d", mmdc_num);
 
+	pmu_mmdc->devtype_data = (struct fsl_mmdc_devtype_data *)of_id->data;
+
 	hrtimer_init(&pmu_mmdc->hrtimer, CLOCK_MONOTONIC,
 			HRTIMER_MODE_REL);
 	pmu_mmdc->hrtimer.function = mmdc_pmu_timer_handler;
@@ -524,11 +555,6 @@ int imx_mmdc_get_ddr_type(void)
 	return ddr_type;
 }
 
-static const struct of_device_id imx_mmdc_dt_ids[] = {
-	{ .compatible = "fsl,imx6q-mmdc", },
-	{ /* sentinel */ }
-};
-
 static struct platform_driver imx_mmdc_driver = {
 	.driver		= {
 		.name	= "imx-mmdc",
-- 
2.5.2

^ permalink raw reply related

* [PATCH V3 2/2] ARM: dts: add new compatible stream for i.MX6QP mmdc
From: Frank Li @ 2016-11-07 17:30 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1478539849-10834-1-git-send-email-Frank.Li@nxp.com>

MMDC has a slightly different programming model between imx6q and imx6qp
in terms of perf support, it's exactly same for suspend support, so we
have fsl,imx6q-mmdc here to save patching suspend driver with the new
compatible.

Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
Change from V3 to V2
- change commit message to show suspend need fsl,imx6q-mmdc

 arch/arm/boot/dts/imx6qp.dtsi | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/arm/boot/dts/imx6qp.dtsi b/arch/arm/boot/dts/imx6qp.dtsi
index 886dbf2..e0fdd0f 100644
--- a/arch/arm/boot/dts/imx6qp.dtsi
+++ b/arch/arm/boot/dts/imx6qp.dtsi
@@ -85,5 +85,12 @@
 		pcie: pcie at 0x01000000 {
 			compatible = "fsl,imx6qp-pcie", "snps,dw-pcie";
 		};
+
+		aips-bus at 02100000 {
+			mmdc0: mmdc at 021b0000 { /* MMDC0 */
+				compatible = "fsl,imx6qp-mmdc", "fsl,imx6q-mmdc";
+				reg = <0x021b0000 0x4000>;
+			};
+		};
 	};
 };
-- 
2.5.2

^ permalink raw reply related

* [PATCH V3 0/6] ARM64: Uprobe support added
From: Pratyush Anand @ 2016-11-07 17:33 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161107113944.GB28876@MBP.local>



On Monday 07 November 2016 05:09 PM, Catalin Marinas wrote:
>> diff --git a/arch/arm64/kernel/probes/decode-insn.c
>> > b/arch/arm64/kernel/probes/decode-insn.c
>> > index 8a29d29..6bf6657 100644
>> > --- a/arch/arm64/kernel/probes/decode-insn.c
>> > +++ b/arch/arm64/kernel/probes/decode-insn.c
>> > @@ -17,7 +17,6 @@
>> >  #include <linux/kprobes.h>
>> >  #include <linux/module.h>
>> >  #include <linux/kallsyms.h>
>> > -#include <asm/kprobes.h>
>> >  #include <asm/insn.h>
>> >  #include <asm/sections.h>
>> >
>> > So, do you want me to send V4 or a separate topup fixup patch. Please let me
>> > know, will do accordingly.
> Just a separate patch on top of your series would do. Also please test
> your series with CONFIG_KPROBE disabled and I assume this wasn't done
> (just in case there is an interaction we were not aware of).

OK, I tested by disabling CONFIG_KPROBE, and uprobe tests worked fine.

~Pratyush

^ permalink raw reply

* [PATCH] arm64: fix error: conflicting types for 'kprobe_fault_handler'
From: Pratyush Anand @ 2016-11-07 17:37 UTC (permalink / raw)
  To: linux-arm-kernel

When CONFIG_KPROBE is disabled but CONFIG_UPROBE_EVENT is enabled, we get
following compilation error:

In file included from
.../arch/arm64/kernel/probes/decode-insn.c:20:0:
.../arch/arm64/include/asm/kprobes.h:52:5: error:
conflicting types for 'kprobe_fault_handler'
 int kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr);
     ^~~~~~~~~~~~~~~~~~~~
In file included from
.../arch/arm64/kernel/probes/decode-insn.c:17:0:
.../include/linux/kprobes.h:398:90: note:
previous definition of 'kprobe_fault_handler' was here
 static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
                                                                                          ^
.../scripts/Makefile.build:290: recipe for target
'arch/arm64/kernel/probes/decode-insn.o' failed

<asm/kprobes.h> is already included from <linux/kprobes.h> under #ifdef
CONFIG_KPROBE. So, this patch fixes the error by removing it from
decode-insn.c.

Reported-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Pratyush Anand <panand@redhat.com>
---
 arch/arm64/kernel/probes/decode-insn.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/arch/arm64/kernel/probes/decode-insn.c b/arch/arm64/kernel/probes/decode-insn.c
index 8a29d2982eec..6bf6657a5a52 100644
--- a/arch/arm64/kernel/probes/decode-insn.c
+++ b/arch/arm64/kernel/probes/decode-insn.c
@@ -17,7 +17,6 @@
 #include <linux/kprobes.h>
 #include <linux/module.h>
 #include <linux/kallsyms.h>
-#include <asm/kprobes.h>
 #include <asm/insn.h>
 #include <asm/sections.h>
 
-- 
2.7.4

^ permalink raw reply related

* [PATCH 3/6] clk: Add driver for Maxim-8997 PMIC clocks
From: Krzysztof Kozlowski @ 2016-11-07 17:41 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1478513376-14307-4-git-send-email-pankaj.dubey@samsung.com>

On Mon, Nov 07, 2016 at 03:39:33PM +0530, Pankaj Dubey wrote:
> The MAX8997 PMIC has 32.786kHz crystal oscillator which provides an
> accurate low frequency clock for MAX8997 internal circuit as well as
> external circuit. This patch adds support for these two clocks.
> 
> CC: Michael Turquette <mturquette@baylibre.com>
> CC: Rob Herring <robh+dt@kernel.org>
> CC: devicetree at vger.kernel.org
> CC: linux-clk at vger.kernel.org
> Signed-off-by: Pankaj Dubey <pankaj.dubey@samsung.com>
> ---
>  drivers/clk/Kconfig                       | 10 ++++
>  drivers/clk/Makefile                      |  1 +
>  drivers/clk/clk-max8997.c                 | 76 +++++++++++++++++++++++++++++++
>  include/dt-bindings/clock/maxim,max8997.h | 23 ++++++++++

You need to split the dt-bindings header into separate one so others
could pull it.  Please also mention the dependencies between patches in
cover letter, because it does not look like it could be applied as is.

Best regards,
Krzysztof

^ permalink raw reply

* [PATCH 0/3] Add memremap executable mapping and extend drivers/misc/sram.c
From: Tony Lindgren @ 2016-11-07 17:43 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161107110444.GA23750@n2100.armlinux.org.uk>

* Russell King - ARM Linux <linux@armlinux.org.uk> [161107 04:05]:
> On Thu, Oct 27, 2016 at 01:56:09PM -0500, Dave Gerlach wrote:
> > There are several instances when one would want to execute out of on-chip
> > SRAM, such as PM code on ARM platforms, so once again revisiting this
> > series to allow that in a generic manner. Seems that having a solution for
> > allowing SRAM to be mapped as executable will help clean up PM code on several
> > ARM platforms that are using ARM internal __arm_ioremap_exec API
> > and also open the door for PM support on new platforms like TI AM335x and
> > AM437x. This was last sent as RFC here [1] and based on comments from Russell
> > King and Arnd Bergmann has been rewritten to use memremap API rather than
> > ioremap API, as executable iomem does not really make sense.
> 
> This is better, as it avoids the issue that I pointed out last time
> around, but I'm still left wondering about the approach.
> 
> Sure, having executable SRAM mappings sounds nice and easy, but we're
> creating WX mappings.  Folk have spent a while improving the security of
> the kernel by ensuring that there are no WX mappings, and this series
> reintroduces them.  The sad thing is that any WX mapping which appears
> at a known address can be exploited.
> 
> "A known address" can be something that appears to be random, but ends
> up being the same across the same device type... or can be discovered
> by some means.  Eg, consider if the WX mapping is dynamically allocated,
> but occurs at exactly the same point at boot - and if this happens with
> android phones, consider how many of those are out there.  Or if the
> address of the WX mapping is available via some hardware register.
> Or...
> 
> See Kees Cook's slides at last years kernel summit -
> 	https://outflux.net/slides/2015/ks/security.pdf
> 
> So, I think avoiding WX mappings - mappings should be either W or X but
> not both simultaneously (see page 19.)
> 
> I guess what I'm angling at is that we don't want memremap_exec(), but
> we need an API which changes the permissions of a SRAM mapping between
> allowing writes and allowing execution.

That should work just fine. So first copy the code to SRAM,
then set it read-only and exectuable. Note that we need to
restore the state of SRAM every time when returning from
off mode during idle on some SoCs.

Regards,

Tony

^ permalink raw reply

* [PATCH 6/6] ARM: dts: Extend the S3C RTC node with rtc_src clock
From: Krzysztof Kozlowski @ 2016-11-07 17:44 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1478513376-14307-7-git-send-email-pankaj.dubey@samsung.com>

On Mon, Nov 07, 2016 at 03:39:36PM +0530, Pankaj Dubey wrote:
> Extend the S3C RTC node with rtc_src clock so it could be operational.
> The rtc_src clock is provided by MAX8997.
> 
> CC: Rob Herring <robh+dt@kernel.org>
> CC: devicetree at vger.kernel.org
> Signed-off-by: Pankaj Dubey <pankaj.dubey@samsung.com>
> ---
>  arch/arm/boot/dts/exynos4210-origen.dts | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/exynos4210-origen.dts b/arch/arm/boot/dts/exynos4210-origen.dts
> index 6c7ef4e..4cac9b6 100644
> --- a/arch/arm/boot/dts/exynos4210-origen.dts
> +++ b/arch/arm/boot/dts/exynos4210-origen.dts
> @@ -18,6 +18,7 @@
>  #include "exynos4210.dtsi"
>  #include <dt-bindings/gpio/gpio.h>
>  #include <dt-bindings/input/input.h>
> +#include <dt-bindings/clock/maxim,max8997.h>

Just a nit: put the system-wide includes in alphabetical order, so
clock, gpio and finally input. It helps reducing conflicting changes
(when more people add includes in the same time).

Beside that, looks good, but it requires a dt-bindings in separate patch
so I could pull it.

Best regards,
Krzysztof

^ permalink raw reply

* [PATCH] iommu/arm-smmu: Fix out-of-bounds dereference
From: Will Deacon @ 2016-11-07 17:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <dea89ff1b2bd97b08d72f5c32fcf228bec767142.1478533142.git.robin.murphy@arm.com>

On Mon, Nov 07, 2016 at 03:39:02PM +0000, Robin Murphy wrote:
> When we iterate a master's config entries, what we generally care
> about is the entry's stream map index, rather than the entry index
> itself, so it's nice to have the iterator automatically assign the
> former from the latter. Unfortunately, booting with KASAN reveals
> the oversight that using a simple comma operator results in the
> entry index being dereferenced before being checked for validity,
> so we always access one element past the end of the fwspec array.
> 
> Flip things around so that the check always happens before the index
> may be dereferenced.
> 
> Fixes: adfec2e709d2 ("iommu/arm-smmu: Convert to iommu_fwspec")
> Reported-by: Mark Rutland <mark.rutland@arm.com>
> Signed-off-by: Robin Murphy <robin.murphy@arm.com>
> ---
>  drivers/iommu/arm-smmu.c | 6 ++++--
>  1 file changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
> index f86683eec446..44ffe3a391d6 100644
> --- a/drivers/iommu/arm-smmu.c
> +++ b/drivers/iommu/arm-smmu.c
> @@ -324,8 +324,10 @@ struct arm_smmu_master_cfg {
>  #define INVALID_SMENDX			-1
>  #define __fwspec_cfg(fw) ((struct arm_smmu_master_cfg *)fw->iommu_priv)
>  #define fwspec_smmu(fw)  (__fwspec_cfg(fw)->smmu)
> -#define for_each_cfg_sme(fw, i, idx) \
> -	for (i = 0; idx = __fwspec_cfg(fw)->smendx[i], i < fw->num_ids; ++i)
> +#define for_each_cfg_sme(fw, i, idx)					\
> +	for (i = 0;							\
> +	     i < fw->num_ids && (idx = __fwspec_cfg(fw)->smendx[i], true); \
> +	     ++i)

Urgh, that's vile. Is it worth wrapping that in (yet another) macro, which
either returns the index or -ENOENT if i is out of bounds?

Will

^ permalink raw reply

* [PATCH 3/4] ARM: EXYNOS: Remove static mapping of SCU SFR
From: Krzysztof Kozlowski @ 2016-11-07 17:53 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1478230764-13748-4-git-send-email-pankaj.dubey@samsung.com>

On Fri, Nov 04, 2016 at 09:09:23AM +0530, Pankaj Dubey wrote:
> Lets remove static mapping of SCU SFR mainly used in CORTEX-A9 SoC based boards.
> Instead use mapping from device tree node of SCU.
> 
> Signed-off-by: Pankaj Dubey <pankaj.dubey@samsung.com>
> ---
>  arch/arm/mach-exynos/exynos.c                | 22 ----------------------
>  arch/arm/mach-exynos/include/mach/map.h      |  2 --
>  arch/arm/mach-exynos/platsmp.c               | 18 +++++++++++-------
>  arch/arm/mach-exynos/pm.c                    | 14 +++++++++++---
>  arch/arm/mach-exynos/suspend.c               | 15 +++++++++++----
>  arch/arm/plat-samsung/include/plat/map-s5p.h |  4 ----
>  6 files changed, 33 insertions(+), 42 deletions(-)
> 
> diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c
> index 757fc11..fa08ef9 100644
> --- a/arch/arm/mach-exynos/exynos.c
> +++ b/arch/arm/mach-exynos/exynos.c
> @@ -28,15 +28,6 @@
>  
>  #include "common.h"
>  
> -static struct map_desc exynos4_iodesc[] __initdata = {
> -	{
> -		.virtual	= (unsigned long)S5P_VA_COREPERI_BASE,
> -		.pfn		= __phys_to_pfn(EXYNOS4_PA_COREPERI),
> -		.length		= SZ_8K,
> -		.type		= MT_DEVICE,
> -	},
> -};
> -
>  static struct platform_device exynos_cpuidle = {
>  	.name              = "exynos_cpuidle",
>  #ifdef CONFIG_ARM_EXYNOS_CPUIDLE
> @@ -99,17 +90,6 @@ static int __init exynos_fdt_map_chipid(unsigned long node, const char *uname,
>  	return 1;
>  }
>  
> -/*
> - * exynos_map_io
> - *
> - * register the standard cpu IO areas
> - */
> -static void __init exynos_map_io(void)
> -{
> -	if (soc_is_exynos4())
> -		iotable_init(exynos4_iodesc, ARRAY_SIZE(exynos4_iodesc));
> -}
> -
>  static void __init exynos_init_io(void)
>  {
>  	debug_ll_io_init();
> @@ -118,8 +98,6 @@ static void __init exynos_init_io(void)
>  
>  	/* detect cpu id and rev. */
>  	s5p_init_cpu(S5P_VA_CHIPID);
> -
> -	exynos_map_io();
>  }
>  
>  /*
> diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h
> index 5fb0040..0eef407 100644
> --- a/arch/arm/mach-exynos/include/mach/map.h
> +++ b/arch/arm/mach-exynos/include/mach/map.h
> @@ -18,6 +18,4 @@
>  
>  #define EXYNOS_PA_CHIPID		0x10000000
>  
> -#define EXYNOS4_PA_COREPERI		0x10500000
> -
>  #endif /* __ASM_ARCH_MAP_H */
> diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c
> index a5d6841..553d0d9 100644
> --- a/arch/arm/mach-exynos/platsmp.c
> +++ b/arch/arm/mach-exynos/platsmp.c
> @@ -224,11 +224,6 @@ static void write_pen_release(int val)
>  	sync_cache_w(&pen_release);
>  }
>  
> -static void __iomem *scu_base_addr(void)
> -{
> -	return (void __iomem *)(S5P_VA_SCU);
> -}
> -
>  static DEFINE_SPINLOCK(boot_lock);
>  
>  static void exynos_secondary_init(unsigned int cpu)
> @@ -387,14 +382,23 @@ fail:
>  
>  static void __init exynos_smp_prepare_cpus(unsigned int max_cpus)
>  {
> +	struct device_node *np;
> +	void __iomem *scu_base;
>  	int i;
>  
>  	exynos_sysram_init();
>  
>  	exynos_set_delayed_reset_assertion(true);
>  
> -	if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9)
> -		scu_enable(scu_base_addr());
> +	if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) {
> +		np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
> +		scu_base = of_iomap(np, 0);
> +		if (scu_base) {
> +			scu_enable(scu_base);
> +			iounmap(scu_base);
> +		}
> +		of_node_put(np);

I do not like the duplication - this code appears in three places and
they are the same. Could you split it into separate function?

As you mentioned to Alim, in case of lack of node, it would be nice to notify the
user (pr_err() etc).

Best regards,
Krzysztof

^ permalink raw reply

* [GIT PULL] arm64 fix for -rc5
From: Will Deacon @ 2016-11-07 17:57 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Linus,

It's been pretty quiet on the fixes side of things for us, but Artem
reported a build failure introduced during the merge window that appears
with older GCCs that do not support asm goto. The fix is bigger than I'd
like, but it's a mechnical move of some constants to break an include
dependency between atomic.h and jump_label.h when !HAVE_JUMP_LABEL.

Please pull,

Will

--->8

The following changes since commit a909d3e636995ba7c349e2ca5dbb528154d4ac30:

  Linux 4.9-rc3 (2016-10-29 13:52:02 -0700)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git tags/arm64-fixes

for you to fetch changes up to 272d01bd790fdf3f1b16372fe28136e27756756f:

  arm64: Fix circular include of asm/lse.h through linux/jump_label.h (2016-11-05 20:59:06 +0000)

----------------------------------------------------------------
arm64 fix:

- Fix build failure on compilers without asm goto

----------------------------------------------------------------
Catalin Marinas (1):
      arm64: Fix circular include of asm/lse.h through linux/jump_label.h

 arch/arm64/include/asm/alternative.h |  2 +-
 arch/arm64/include/asm/cpucaps.h     | 40 ++++++++++++++++++++++++++++++++++++
 arch/arm64/include/asm/cpufeature.h  | 20 +-----------------
 arch/arm64/include/asm/lse.h         |  1 -
 4 files changed, 42 insertions(+), 21 deletions(-)
 create mode 100644 arch/arm64/include/asm/cpucaps.h

^ permalink raw reply

* [PATCH] arm/vdso: introduce vdso_mremap hook
From: Christopher Covington @ 2016-11-07 18:08 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <714d2aea-ed4c-6272-89c1-e1d0e037855e@virtuozzo.com>

On 11/07/2016 12:16 PM, Dmitry Safonov wrote:
> On 11/07/2016 08:00 PM, Christopher Covington wrote:
>> Hi Dmitry,
>>
>> On 11/01/2016 01:22 PM, Dmitry Safonov wrote:
>>>   Add vdso_mremap hook which will fix context.vdso pointer after mremap()
>>> on vDSO vma. This is needed for correct landing after syscall execution.
>>> Primary goal of this is for CRIU on arm - we need to restore vDSO image
>>> at the exactly same place where the vma was in dumped application. With
>>> the help of this hook we'll move vDSO at the new position.
>>>   The CRIU code handles situations like when vDSO of dumped application
>>> was different from vDSO on restoring system. This usally happens when
>>> some new symbols are being added to vDSO. In these situations CRIU
>>> inserts jump trampolines from old vDSO blob to new vDSO on restore.
>>> By that reason even if on restore vDSO blob lies on the same address as
>>> blob in dumped application - we still need to move it if it differs.
>>>
>>>   There was previously attempt to add this functionality for arm64 by
>>> arch_mremap hook [1], while this patch introduces this with minimal
>>> effort - the same way I've added it to x86:
>>> commit b059a453b1cf ("x86/vdso: Add mremap hook to vm_special_mapping")
>>>
>>>   At this moment, vdso restoring code is disabled for arm/arm64 arch
>>> in CRIU [2], so C/R is only working for !CONFIG_VDSO kernels. This patch
>>> is aimed to fix that.
>>>   The same hook may be introduced for arm64 kernel, but at this moment
>>> arm64 vdso code is actively reworked by Kevin, so we can do it on top.
>>>   Separately, I've refactored arch_remap hook out from ppc64 [3].
>>>
>>> [1]: https://marc.info/?i=1448455781-26660-1-git-send-email-cov at codeaurora.org
>>> [2]: https://github.com/xemul/criu/blob/master/Makefile#L39
>>> [3]: https://marc.info/?i=20161027170948.8279-1-dsafonov at virtuozzo.com
>>>
>>> Cc: Kevin Brodsky <kevin.brodsky@arm.com>
>>> Cc: Christopher Covington <cov@codeaurora.org>
>>> Cc: Andy Lutomirski <luto@amacapital.net>
>>> Cc: Oleg Nesterov <oleg@redhat.com>
>>> Cc: Russell King <linux@armlinux.org.uk>
>>> Cc: Will Deacon <will.deacon@arm.com>
>>> Cc: linux-arm-kernel at lists.infradead.org
>>> Cc: linux-mm at kvack.org
>>> Cc: Cyrill Gorcunov <gorcunov@openvz.org>
>>> Cc: Pavel Emelyanov <xemul@virtuozzo.com>
>>> Signed-off-by: Dmitry Safonov <dsafonov@virtuozzo.com>
>>> ---
>>>  arch/arm/kernel/vdso.c | 21 +++++++++++++++++++++
>>>  1 file changed, 21 insertions(+)
>>>
>>> diff --git a/arch/arm/kernel/vdso.c b/arch/arm/kernel/vdso.c
>>> index 53cf86cf2d1a..d1001f87c2f6 100644
>>> --- a/arch/arm/kernel/vdso.c
>>> +++ b/arch/arm/kernel/vdso.c
>>> @@ -54,8 +54,11 @@ static const struct vm_special_mapping vdso_data_mapping = {
>>>      .pages = &vdso_data_page,
>>>  };
>>>
>>> +static int vdso_mremap(const struct vm_special_mapping *sm,
>>> +        struct vm_area_struct *new_vma);
>>>  static struct vm_special_mapping vdso_text_mapping __ro_after_init = {
>>>      .name = "[vdso]",
>>> +    .mremap = vdso_mremap,
>>>  };
>>>
>>>  struct elfinfo {
>>> @@ -254,6 +257,24 @@ void arm_install_vdso(struct mm_struct *mm, unsigned long addr)
>>>          mm->context.vdso = addr;
>>>  }
>>>
>>> +static int vdso_mremap(const struct vm_special_mapping *sm,
>>> +        struct vm_area_struct *new_vma)
>>> +{
>>> +    unsigned long new_size = new_vma->vm_end - new_vma->vm_start;
>>> +    unsigned long vdso_size = (vdso_total_pages - 1) << PAGE_SHIFT;
>>> +
>>> +    /* Disallow partial vDSO blob remap */
>>> +    if (vdso_size != new_size)
>>> +        return -EINVAL;
>>> +
>>> +    if (WARN_ON_ONCE(current->mm != new_vma->vm_mm))
>>> +        return -EFAULT;
>>> +
>>> +    current->mm->context.vdso = new_vma->vm_start;
>>> +
>>> +    return 0;
>>> +}
>>> +
>>>  static void vdso_write_begin(struct vdso_data *vdata)
>>>  {
>>>      ++vdso_data->seq_count;
>>>
>>
>> What do you think about putting this code somewhere generic (not under
>> arch/*), so that powerpc and arm64 can reuse it once the cosmetic changes
>> to make them compatible are made? My thought was that it could be defined
>> underneath CONFIG_GENERIC_VDSO, which architectures could select as they
>> became compatible.
> 
> Hi Chistopher,
> 
> Well, I don't think we won something out of generalization of simple assignment for context.vdso pointer accross arches. And a need to rename
> vdso over arches for saving one single line?

I count 17 lines, which duplicated across 3 architectures becomes 51 lines.
Presumable in the future other architectures will want CRIU support as well.
Additionally, should fixes ever be required, fixing one implementation instead
of 3+ is preferred.

> Also I don't like a bit this arch_mremap hook and need to nullify
> vdso pointer.

I'm sorry for the confusion but I in no way meant to imply that the
arch_mremap hook should be carried forward. I fully  agree that the function
pointer in struct vm_special_mapping is the better way to go.

If you don't want to implement a version with vdso_mremap defined in a
generic location (using it from struct vm_special_mapping), do you mind if I
propose such a version?

Thanks,
Cov

-- 
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm
Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code
Aurora Forum, a Linux Foundation Collaborative Project.

^ permalink raw reply

* [PATCH v6 0/7] add NS2 support to bgmac
From: David Miller @ 2016-11-07 18:11 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1478236262-3351-1-git-send-email-jon.mason@broadcom.com>

From: Jon Mason <jon.mason@broadcom.com>
Date: Fri,  4 Nov 2016 01:10:55 -0400

> Changes in v6:
> * Use a common bgmac_phy_connect_direct (per Rafal Milecki) 
> * Rebased on latest net-next
> * Added Reviewed-by to the relevant patches
> 
> 
> Changes in v5:
> * Change a pr_err to netdev_err (per Scott Branden)
> * Reword the lane swap binding documentation (per Andrew Lunn)
> 
> 
> Changes in v4:
> * Actually send out the lane swap binding doc patch (Per Scott Branden)
> * Remove unused #define (Per Andrew Lunn)
> 
> 
> Changes in v3:
> * Clean-up the bgmac DT binding doc (per Rob Herring)
> * Document the lane swap binding and make it generic (Per Andrew Lunn)
> 
> 
> Changes in v2:
> * Remove the PHY power-on (per Andrew Lunn)
> * Misc PHY clean-ups regarding comments and #defines (per Andrew Lunn)
>   This results on none of the original PHY code from Vikas being
>   present.  So, I'm removing him as an author and giving him
>   "Inspired-by" credit.
> * Move PHY lane swapping to PHY driver (per Andrew Lunn and Florian
>   Fainelli)
> * Remove bgmac sleep (per Florian Fainelli)
> * Re-add bgmac chip reset (per Florian Fainelli and Ray Jui)
> * Rebased on latest net-next
> * Added patch for bcm54xx_auxctl_read, which is used in the BCM54810

Series applied, thanks.

^ permalink raw reply

* [PATCH] arm/vdso: introduce vdso_mremap hook
From: Dmitry Safonov @ 2016-11-07 18:13 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <d1aa8bec-a53e-cd30-e66a-39bebb6a400a@codeaurora.org>

On 11/07/2016 09:08 PM, Christopher Covington wrote:
> On 11/07/2016 12:16 PM, Dmitry Safonov wrote:
>> On 11/07/2016 08:00 PM, Christopher Covington wrote:
>>> Hi Dmitry,
>>>
>>> On 11/01/2016 01:22 PM, Dmitry Safonov wrote:
>>>>   Add vdso_mremap hook which will fix context.vdso pointer after mremap()
>>>> on vDSO vma. This is needed for correct landing after syscall execution.
>>>> Primary goal of this is for CRIU on arm - we need to restore vDSO image
>>>> at the exactly same place where the vma was in dumped application. With
>>>> the help of this hook we'll move vDSO at the new position.
>>>>   The CRIU code handles situations like when vDSO of dumped application
>>>> was different from vDSO on restoring system. This usally happens when
>>>> some new symbols are being added to vDSO. In these situations CRIU
>>>> inserts jump trampolines from old vDSO blob to new vDSO on restore.
>>>> By that reason even if on restore vDSO blob lies on the same address as
>>>> blob in dumped application - we still need to move it if it differs.
>>>>
>>>>   There was previously attempt to add this functionality for arm64 by
>>>> arch_mremap hook [1], while this patch introduces this with minimal
>>>> effort - the same way I've added it to x86:
>>>> commit b059a453b1cf ("x86/vdso: Add mremap hook to vm_special_mapping")
>>>>
>>>>   At this moment, vdso restoring code is disabled for arm/arm64 arch
>>>> in CRIU [2], so C/R is only working for !CONFIG_VDSO kernels. This patch
>>>> is aimed to fix that.
>>>>   The same hook may be introduced for arm64 kernel, but at this moment
>>>> arm64 vdso code is actively reworked by Kevin, so we can do it on top.
>>>>   Separately, I've refactored arch_remap hook out from ppc64 [3].
>>>>
>>>> [1]: https://marc.info/?i=1448455781-26660-1-git-send-email-cov at codeaurora.org
>>>> [2]: https://github.com/xemul/criu/blob/master/Makefile#L39
>>>> [3]: https://marc.info/?i=20161027170948.8279-1-dsafonov at virtuozzo.com
>>>>
>>>> Cc: Kevin Brodsky <kevin.brodsky@arm.com>
>>>> Cc: Christopher Covington <cov@codeaurora.org>
>>>> Cc: Andy Lutomirski <luto@amacapital.net>
>>>> Cc: Oleg Nesterov <oleg@redhat.com>
>>>> Cc: Russell King <linux@armlinux.org.uk>
>>>> Cc: Will Deacon <will.deacon@arm.com>
>>>> Cc: linux-arm-kernel at lists.infradead.org
>>>> Cc: linux-mm at kvack.org
>>>> Cc: Cyrill Gorcunov <gorcunov@openvz.org>
>>>> Cc: Pavel Emelyanov <xemul@virtuozzo.com>
>>>> Signed-off-by: Dmitry Safonov <dsafonov@virtuozzo.com>
>>>> ---
>>>>  arch/arm/kernel/vdso.c | 21 +++++++++++++++++++++
>>>>  1 file changed, 21 insertions(+)
>>>>
>>>> diff --git a/arch/arm/kernel/vdso.c b/arch/arm/kernel/vdso.c
>>>> index 53cf86cf2d1a..d1001f87c2f6 100644
>>>> --- a/arch/arm/kernel/vdso.c
>>>> +++ b/arch/arm/kernel/vdso.c
>>>> @@ -54,8 +54,11 @@ static const struct vm_special_mapping vdso_data_mapping = {
>>>>      .pages = &vdso_data_page,
>>>>  };
>>>>
>>>> +static int vdso_mremap(const struct vm_special_mapping *sm,
>>>> +        struct vm_area_struct *new_vma);
>>>>  static struct vm_special_mapping vdso_text_mapping __ro_after_init = {
>>>>      .name = "[vdso]",
>>>> +    .mremap = vdso_mremap,
>>>>  };
>>>>
>>>>  struct elfinfo {
>>>> @@ -254,6 +257,24 @@ void arm_install_vdso(struct mm_struct *mm, unsigned long addr)
>>>>          mm->context.vdso = addr;
>>>>  }
>>>>
>>>> +static int vdso_mremap(const struct vm_special_mapping *sm,
>>>> +        struct vm_area_struct *new_vma)
>>>> +{
>>>> +    unsigned long new_size = new_vma->vm_end - new_vma->vm_start;
>>>> +    unsigned long vdso_size = (vdso_total_pages - 1) << PAGE_SHIFT;
>>>> +
>>>> +    /* Disallow partial vDSO blob remap */
>>>> +    if (vdso_size != new_size)
>>>> +        return -EINVAL;
>>>> +
>>>> +    if (WARN_ON_ONCE(current->mm != new_vma->vm_mm))
>>>> +        return -EFAULT;
>>>> +
>>>> +    current->mm->context.vdso = new_vma->vm_start;
>>>> +
>>>> +    return 0;
>>>> +}
>>>> +
>>>>  static void vdso_write_begin(struct vdso_data *vdata)
>>>>  {
>>>>      ++vdso_data->seq_count;
>>>>
>>>
>>> What do you think about putting this code somewhere generic (not under
>>> arch/*), so that powerpc and arm64 can reuse it once the cosmetic changes
>>> to make them compatible are made? My thought was that it could be defined
>>> underneath CONFIG_GENERIC_VDSO, which architectures could select as they
>>> became compatible.
>>
>> Hi Chistopher,
>>
>> Well, I don't think we won something out of generalization of simple assignment for context.vdso pointer accross arches. And a need to rename
>> vdso over arches for saving one single line?
>
> I count 17 lines, which duplicated across 3 architectures becomes 51 lines.
> Presumable in the future other architectures will want CRIU support as well.
> Additionally, should fixes ever be required, fixing one implementation instead
> of 3+ is preferred.
>
>> Also I don't like a bit this arch_mremap hook and need to nullify
>> vdso pointer.
>
> I'm sorry for the confusion but I in no way meant to imply that the
> arch_mremap hook should be carried forward. I fully  agree that the function
> pointer in struct vm_special_mapping is the better way to go.
>
> If you don't want to implement a version with vdso_mremap defined in a
> generic location (using it from struct vm_special_mapping), do you mind if I
> propose such a version?

Sure, do it, no objections.

-- 
              Dmitry

^ permalink raw reply

* [PATCH v3 1/3] Documentation: DT: add dma compatible for sun50i A64 SOC.
From: Hao Zhang @ 2016-11-07 18:14 UTC (permalink / raw)
  To: linux-arm-kernel

This adds documentation of the sun50i a64 dma binding compatible.

Signed-off-by: Hao Zhang <hao5781286@gmail.com>
---
 Documentation/devicetree/bindings/dma/sun6i-dma.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/dma/sun6i-dma.txt b/Documentation/devicetree/bindings/dma/sun6i-dma.txt
index 6b26704..4398b99 100644
--- a/Documentation/devicetree/bindings/dma/sun6i-dma.txt
+++ b/Documentation/devicetree/bindings/dma/sun6i-dma.txt
@@ -9,6 +9,7 @@ Required properties:
 		  "allwinner,sun8i-a23-dma"
 		  "allwinner,sun8i-a83t-dma"
 		  "allwinner,sun8i-h3-dma"
+		  "allwinner,sun50i-a64-dma"
 - reg:		Should contain the registers base address and length
 - interrupts:	Should contain a reference to the interrupt used by this device
 - clocks:	Should contain a reference to the parent AHB clock
-- 
2.7.4

^ permalink raw reply related

* [PATCH v11 00/14] Add support for FDMA DMA controller and slim core rproc found on STi chipsets
From: Peter Griffin @ 2016-11-07 18:17 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Vinod and Bjorn,

This patchset adds support for the Flexible Direct Memory Access (FDMA) core
found on STi chipsets from STMicroelectronics. The FDMA is a slim core CPU
with a dedicated firmware. It is a general purpose DMA controller supporting
16 independent channels and data can be moved from memory to memory or between
memory and paced latency critical real time targets.

In reponse to Bjorn latest mail here https://lkml.org/lkml/2016/11/7/425 and
here https://patchwork.kernel.org/patch/9368157/ I have created a v11
incorporating the minor API update, and removed the unrelated change.

As tthis series has been in linux-next for a while, some additional fixes
have been submitted and applied by Vinod. I have included these as part of
the v11 series as well.

I believe the best route as described here
https://www.spinics.net/lists/arm-kernel/msg541026.htmlforward is for Vinod
to apply the whole series on an immutable branch which is then merged into
both the dma and remoteproc trees.

regards,

Peter.

v11 Fix rproc_put to rproc_free(). Also fix unrelated change in Kconfig caused
by a bad rebase. Include additional fixes which are already in linux-next.

V10 series updates remoteproc kconfig subsystem to use 'depends on' rather
than select for the remoteproc core. Remoteproc client drivers now need to
'depends on' for the core part.

This avoids the Kconfig recursive dependency errors and reliance on the DRM
patch included with the v9 series. Patches are also included for enabling the
remoteproc core in the multi_v7 defconfig. All patches for DRM subsystem have
been removed.

Note there is no longer a depedency with the DRM_VIRTIO_GPU driver in this series,
only remoteproc and dmaengine subsystems.

regards,

Peter.

v11
 - rproc_put to rproc_free
 - Fix bad rebase with unrelated Kconfig change.
 - include additional fixes submitted since driver has been in linux-next

v10 RESEND
 - Rebase on v4.9-rc1

Changes since v9:
 - Update remoteproc Kconfig to 'depends on'
 - Add remoteproc core to multi_v7 defconfig
 - Remove drm patches
 - rebase v4.8

Changes since v8:
 - Add MODULE_ALIAS (Vinod)
 - devm_kzalloc to devm_kcalloc (Vinod)
 - quisce tasklet initialised by vchan_init() (Vinod)
 - Don't make SLIM rproc user selectable (Bjorn)
 - slim_rproc: Ensure clocks enabled before firmware load (Peter)
 - Various code style nits / commit message change (Lee)
 - Separate patch for '\n' kconfig removal (Vinod)
 - Fix clock bug when booting without clk_ignore_unused param

Changes since v7:
 - Rebase on v4.8-rc3 (Peter)
 - Double check that len is <= mem[i].size (Bjorn)
 - Remove if (!fw) checks (Bjorn)
 - Omit reference from fw_ops struct (Bjorn)
 - Call rproc_del() before rproc_put() (Bjorn)
 - Fix some odd line breaks (Bjorn)
 - Rename SLIM_* and slim_* with st prefix (Bjorn)

Changes since v6:
 - Fix recursive Kconfig warning (Patrice)
 - Fix various Intel zero day compiler warnings
 - Remove all changes related to late firmware load (now relies on initramfs) (Peter)

Changes since v5:
 - Remove optional rsc table and go back to dummy resource table (Bjorn)
 - Retry rproc_fw_config_virtio() from rproc_boot() if previously failed (Peter)
 - Fixup some kbuild warnings
 - rebase on v4.7-rc5
 - Remove some patches which were merged via ASoC tree

Changes since v4:
 - Make rsc table optional in remoteproc (Peter)
 - Various fixups to STi audio DT nodes (Arnaud)
 - Bulk rename of xp70 to slim (Peter)
 - Update my email to @linaro.org (Lee)
 - rebase on v4.7-rc2 (Peter)
 - Don't make ST_SLIM_REMOTEPROC user selectable (Bjorn)
 - -EPROBE_DEFER if rproc_boot fails when allocating DMA channel (Arnaud / Peter)
 - Drop some unnecessary headers (Vinod / Bjorn)
 - Change to writel now we have several mappings (Bjorn)
 - Remove io_res, rproc, and some unused structure fields / #define (Bjorn)
 - put clks in error path, also put clks before rproc_put() (Bjorn)
 - Make enum less generic (Bjorn)
 - Make slim_rproc_alloc() return a st_slim_rproc reference (Bjorn)
 - Alphabetical naming in Kconfig & Makefile (Vinod)
 - Add FDMA prefix to REQ_CTRL* (Vinod)
 - Print ret on some error paths (Vinod)
 - Add some acked-by (Peter)

Changes since v3:
 - Remove elf loading code from fdma driver (Vinod)
 - Remove fdma_ prefix for clock names (Arnd)
 - Make _xlate use dma_get_any_channel rather than request_channel (Arnd)
 - Make a common function for _prep_ routines (Vinod)
 - Make driver depend on COMPILE_TEST (Arnd)
 - Remove unnecessary st_fdma_filter_fn (Arnd)
 - Enable FDMA as a module (Arnd)
 - Drop fdma_ clock prefix (Arnd)
 - Fix description as well as example for st, prefix (Arnd)
 - Remove string concatenation from fdma register macros to ease grep'ability (Arnd)
 - Add a XP70 rproc driver for ELF firmware loading and start/stop control (Peter)
 - Add myself as a author of the driver (Peter)

Changes since v2:
 - Change to dma-controller (Arnd)
 - Remove platform data header file and simplifiy code (Arnd)
 - Remove FW_LOADER_USER_HELPER_FALLBACK and rework firmware loading to device config (Vinod)
 - Use SET_RUNTIME_PM_OPS helpers (Vinod)
 - Remove fdma-id dt prop and use compatibles to generate different fdma firmware names (Arnd / Lee)
 - Add sti-asoc-card DT nodes and pinmux config for uniperif player & reader (Peter)
 - Update sti-asoc-card DT binding documentation (Peter)
 - Enable STi audio drivers in multi_v7_defconfig (Peter)

Changes since v1:
 - split into smaller patches for easier / faster review (Vinod)
 - new fill_hw_mode() with common code (Vinod)
 - new config_reqctrl() called from *_prep() instead of device_config cb (Vinod)
 - fdma-xbar support removed (Peter)
 - rework firmware name mechanism so fwname isn't in DT (Peter / Lee)
 - st_fdma_seg_to_mem can be static (Paul)
 - EXPORT_SYMBOL st_fdma_filter_fn not required (Paul)
 - s/channel/channels (vinod)
 - better describe "Must be <3>" (vinod)
 - sizeof(*ehdr) (vinod)
 - print values on error debug (vinod)
 - empty line (Vinod)
 - Update to -EIO (Vinod)
 - Make st_fdma tristate (Paul)
 - Remove __exit tag from .remove (Maxime)
 - Update MAINTAINERS rule to fdma* (Lee)
 - Unit address should match reg property (Lee)

Arnd Bergmann (1):
  dmaengine: st_fdma: fix uninitialized variable access

Peter Griffin (12):
  remoteproc: Update Kconfig setup to 'depends on REMOTEPROC'
  remoteproc: st_slim_rproc: add a slimcore rproc driver
  MAINTAINERS: Add st slim core rproc driver to STi section.
  dmaengine: st_fdma: Add STMicroelectronics FDMA DT binding
    documentation
  dmaengine: st_fdma: Add STMicroelectronics FDMA driver header file
  dmaengine: st_fdma: Add STMicroelectronics FDMA engine driver support
  MAINTAINERS: Add FDMA driver files to STi section.
  ARM: multi_v7_defconfig: Enable remoteproc core
  ARM: multi_v7_defconfig: Enable st_remoteproc driver.
  ARM: multi_v7_defconfig: Enable STi FDMA driver
  ARM: multi_v7_defconfig: Enable STi and simple-card drivers.
  dmaengine: st_fdma: Update st_fdma to 'depends on REMOTEPROC'.

Wei Yongjun (1):
  dmaengine: st_fdma: Fix the error return code in st_fdma_probe()

 Documentation/devicetree/bindings/dma/st_fdma.txt |  87 +++
 MAINTAINERS                                       |   3 +
 arch/arm/configs/multi_v7_defconfig               |   6 +
 drivers/dma/Kconfig                               |  14 +
 drivers/dma/Makefile                              |   1 +
 drivers/dma/st_fdma.c                             | 889 ++++++++++++++++++++++
 drivers/dma/st_fdma.h                             | 249 ++++++
 drivers/remoteproc/Kconfig                        |  25 +-
 drivers/remoteproc/Makefile                       |   1 +
 drivers/remoteproc/st_slim_rproc.c                | 364 +++++++++
 include/linux/remoteproc/st_slim_rproc.h          |  58 ++
 11 files changed, 1688 insertions(+), 9 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/dma/st_fdma.txt
 create mode 100644 drivers/dma/st_fdma.c
 create mode 100644 drivers/dma/st_fdma.h
 create mode 100644 drivers/remoteproc/st_slim_rproc.c
 create mode 100644 include/linux/remoteproc/st_slim_rproc.h

-- 
2.7.4

^ permalink raw reply

* [PATCH v11 01/14] remoteproc: Update Kconfig setup to 'depends on REMOTEPROC'
From: Peter Griffin @ 2016-11-07 18:17 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1478542665-17089-1-git-send-email-peter.griffin@linaro.org>

Make REMOTEPROC core a selectable kconfig option, and update
remoteproc client drivers to 'depends on' the core. This avoids
some nasty Kconfig recursive dependency issues. Also when using
menuconfig client drivers will be hidden until the core has been
enabled.

Documentation/kbuild/kconfig-language.txt:

  Note:
        select should be used with care. select will force
        a symbol to a value without visiting the dependencies.
        By abusing select you are able to select a symbol FOO even
        if FOO depends on BAR that is not set.
        In general use select only for non-visible symbols
        (no prompts anywhere) and for symbols with no dependencies.
        That will limit the usefulness but on the other hand avoid
        the illegal configurations all over.

Signed-off-by: Peter Griffin <peter.griffin@linaro.org>
---
 drivers/remoteproc/Kconfig | 21 ++++++++++++---------
 1 file changed, 12 insertions(+), 9 deletions(-)

diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index f396bfe..a244b1a 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -1,20 +1,21 @@
 menu "Remoteproc drivers"
 
-# REMOTEPROC gets selected by whoever wants it
 config REMOTEPROC
-	tristate
+	tristate "Support for Remote Processor subsystem"
 	depends on HAS_DMA
 	select CRC32
 	select FW_LOADER
 	select VIRTIO
 	select VIRTUALIZATION
 
+if REMOTEPROC
+
 config OMAP_REMOTEPROC
 	tristate "OMAP remoteproc support"
 	depends on HAS_DMA
 	depends on ARCH_OMAP4 || SOC_OMAP5
 	depends on OMAP_IOMMU
-	select REMOTEPROC
+	depends on REMOTEPROC
 	select MAILBOX
 	select OMAP2PLUS_MBOX
 	select RPMSG_VIRTIO
@@ -34,7 +35,7 @@ config OMAP_REMOTEPROC
 config STE_MODEM_RPROC
 	tristate "STE-Modem remoteproc support"
 	depends on HAS_DMA
-	select REMOTEPROC
+	depends on REMOTEPROC
 	default n
 	help
 	  Say y or m here to support STE-Modem shared memory driver.
@@ -44,7 +45,7 @@ config STE_MODEM_RPROC
 config WKUP_M3_RPROC
 	tristate "AMx3xx Wakeup M3 remoteproc support"
 	depends on SOC_AM33XX || SOC_AM43XX
-	select REMOTEPROC
+	depends on REMOTEPROC
 	help
 	  Say y here to support Wakeup M3 remote processor on TI AM33xx
 	  and AM43xx family of SoCs.
@@ -57,8 +58,8 @@ config WKUP_M3_RPROC
 config DA8XX_REMOTEPROC
 	tristate "DA8xx/OMAP-L13x remoteproc support"
 	depends on ARCH_DAVINCI_DA8XX
+	depends on REMOTEPROC
 	select CMA if MMU
-	select REMOTEPROC
 	select RPMSG_VIRTIO
 	help
 	  Say y here to support DA8xx/OMAP-L13x remote processors via the
@@ -84,9 +85,9 @@ config QCOM_Q6V5_PIL
 	tristate "Qualcomm Hexagon V5 Peripherial Image Loader"
 	depends on OF && ARCH_QCOM
 	depends on QCOM_SMEM
+	depends on REMOTEPROC
 	select MFD_SYSCON
 	select QCOM_MDT_LOADER
-	select REMOTEPROC
 	help
 	  Say y here to support the Qualcomm Peripherial Image Loader for the
 	  Hexagon V5 based remote processors.
@@ -102,7 +103,7 @@ config QCOM_WCNSS_PIL
 	select QCOM_MDT_LOADER
 	select QCOM_SCM
 	select QCOM_WCNSS_IRIS
-	select REMOTEPROC
+	depends on REMOTEPROC
 	help
 	  Say y here to support the Peripheral Image Loader for the Qualcomm
 	  Wireless Connectivity Subsystem.
@@ -110,10 +111,12 @@ config QCOM_WCNSS_PIL
 config ST_REMOTEPROC
 	tristate "ST remoteproc support"
 	depends on ARCH_STI
-	select REMOTEPROC
+	depends on REMOTEPROC
 	help
 	  Say y here to support ST's adjunct processors via the remote
 	  processor framework.
 	  This can be either built-in or a loadable module.
 
+endif # REMOTEPROC
+
 endmenu
-- 
2.7.4

^ permalink raw reply related

* [PATCH v11 02/14] remoteproc: st_slim_rproc: add a slimcore rproc driver
From: Peter Griffin @ 2016-11-07 18:17 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1478542665-17089-1-git-send-email-peter.griffin@linaro.org>

slim core is used as a basis for many IPs in the STi
chipsets such as fdma and demux. To avoid duplicating
the elf loading code in each device driver a slim
rproc driver has been created.

This driver is designed to be used by other device drivers
such as fdma, or demux whose IP is based around a slim core.
The device driver can call slim_rproc_alloc() to allocate
a slim rproc and slim_rproc_put() when finished.

This driver takes care of ioremapping the slim
registers (dmem, imem, slimcore, peripherals), whose offsets
and sizes can change between IP's. It also obtains and enables
any clocks used by the device. This approach avoids having
a double mapping of the registers as slim_rproc does not register
its own platform device. It also maps well to device tree
abstraction as it allows us to have one dt node for the whole
device.

All of the generic rproc elf loading code can be reused, and
we provide start() stop() hooks to start and stop the slim
core once the firmware has been loaded. This has been tested
successfully with fdma driver.

Signed-off-by: Peter Griffin <peter.griffin@linaro.org>
---
 drivers/remoteproc/Kconfig               |   4 +
 drivers/remoteproc/Makefile              |   1 +
 drivers/remoteproc/st_slim_rproc.c       | 364 +++++++++++++++++++++++++++++++
 include/linux/remoteproc/st_slim_rproc.h |  58 +++++
 4 files changed, 427 insertions(+)
 create mode 100644 drivers/remoteproc/st_slim_rproc.c
 create mode 100644 include/linux/remoteproc/st_slim_rproc.h

diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index a244b1a..4309164 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -117,6 +117,10 @@ config ST_REMOTEPROC
 	  processor framework.
 	  This can be either built-in or a loadable module.
 
+config ST_SLIM_REMOTEPROC
+	tristate
+	depends on REMOTEPROC
+
 endif # REMOTEPROC
 
 endmenu
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index 6dfb62e..924f0cb 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_QCOM_Q6V5_PIL)		+= qcom_q6v5_pil.o
 obj-$(CONFIG_QCOM_WCNSS_IRIS)		+= qcom_wcnss_iris.o
 obj-$(CONFIG_QCOM_WCNSS_PIL)		+= qcom_wcnss.o
 obj-$(CONFIG_ST_REMOTEPROC)		+= st_remoteproc.o
+obj-$(CONFIG_ST_SLIM_REMOTEPROC)	+= st_slim_rproc.o
diff --git a/drivers/remoteproc/st_slim_rproc.c b/drivers/remoteproc/st_slim_rproc.c
new file mode 100644
index 0000000..efb49ee
--- /dev/null
+++ b/drivers/remoteproc/st_slim_rproc.c
@@ -0,0 +1,364 @@
+/*
+ * SLIM core rproc driver
+ *
+ * Copyright (C) 2016 STMicroelectronics
+ *
+ * Author: Peter Griffin <peter.griffin@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/remoteproc.h>
+#include <linux/remoteproc/st_slim_rproc.h>
+#include "remoteproc_internal.h"
+
+/* SLIM core registers */
+#define SLIM_ID_OFST		0x0
+#define SLIM_VER_OFST		0x4
+
+#define SLIM_EN_OFST		0x8
+#define SLIM_EN_RUN			BIT(0)
+
+#define SLIM_CLK_GATE_OFST	0xC
+#define SLIM_CLK_GATE_DIS		BIT(0)
+#define SLIM_CLK_GATE_RESET		BIT(2)
+
+#define SLIM_SLIM_PC_OFST	0x20
+
+/* DMEM registers */
+#define SLIM_REV_ID_OFST	0x0
+#define SLIM_REV_ID_MIN_MASK		GENMASK(15, 8)
+#define SLIM_REV_ID_MIN(id)		((id & SLIM_REV_ID_MIN_MASK) >> 8)
+#define SLIM_REV_ID_MAJ_MASK		GENMASK(23, 16)
+#define SLIM_REV_ID_MAJ(id)		((id & SLIM_REV_ID_MAJ_MASK) >> 16)
+
+
+/* peripherals registers */
+#define SLIM_STBUS_SYNC_OFST	0xF88
+#define SLIM_STBUS_SYNC_DIS		BIT(0)
+
+#define SLIM_INT_SET_OFST	0xFD4
+#define SLIM_INT_CLR_OFST	0xFD8
+#define SLIM_INT_MASK_OFST	0xFDC
+
+#define SLIM_CMD_CLR_OFST	0xFC8
+#define SLIM_CMD_MASK_OFST	0xFCC
+
+static const char *mem_names[ST_SLIM_MEM_MAX] = {
+	[ST_SLIM_DMEM]	= "dmem",
+	[ST_SLIM_IMEM]	= "imem",
+};
+
+static int slim_clk_get(struct st_slim_rproc *slim_rproc, struct device *dev)
+{
+	int clk, err;
+
+	for (clk = 0; clk < ST_SLIM_MAX_CLK; clk++) {
+		slim_rproc->clks[clk] = of_clk_get(dev->of_node, clk);
+		if (IS_ERR(slim_rproc->clks[clk])) {
+			err = PTR_ERR(slim_rproc->clks[clk]);
+			if (err == -EPROBE_DEFER)
+				goto err_put_clks;
+			slim_rproc->clks[clk] = NULL;
+			break;
+		}
+	}
+
+	return 0;
+
+err_put_clks:
+	while (--clk >= 0)
+		clk_put(slim_rproc->clks[clk]);
+
+	return err;
+}
+
+static void slim_clk_disable(struct st_slim_rproc *slim_rproc)
+{
+	int clk;
+
+	for (clk = 0; clk < ST_SLIM_MAX_CLK && slim_rproc->clks[clk]; clk++)
+		clk_disable_unprepare(slim_rproc->clks[clk]);
+}
+
+static int slim_clk_enable(struct st_slim_rproc *slim_rproc)
+{
+	int clk, ret;
+
+	for (clk = 0; clk < ST_SLIM_MAX_CLK && slim_rproc->clks[clk]; clk++) {
+		ret = clk_prepare_enable(slim_rproc->clks[clk]);
+		if (ret)
+			goto err_disable_clks;
+	}
+
+	return 0;
+
+err_disable_clks:
+	while (--clk >= 0)
+		clk_disable_unprepare(slim_rproc->clks[clk]);
+
+	return ret;
+}
+
+/*
+ * Remoteproc slim specific device handlers
+ */
+static int slim_rproc_start(struct rproc *rproc)
+{
+	struct device *dev = &rproc->dev;
+	struct st_slim_rproc *slim_rproc = rproc->priv;
+	unsigned long hw_id, hw_ver, fw_rev;
+	u32 val;
+
+	/* disable CPU pipeline clock & reset CPU pipeline */
+	val = SLIM_CLK_GATE_DIS | SLIM_CLK_GATE_RESET;
+	writel(val, slim_rproc->slimcore + SLIM_CLK_GATE_OFST);
+
+	/* disable SLIM core STBus sync */
+	writel(SLIM_STBUS_SYNC_DIS, slim_rproc->peri + SLIM_STBUS_SYNC_OFST);
+
+	/* enable cpu pipeline clock */
+	writel(!SLIM_CLK_GATE_DIS,
+		slim_rproc->slimcore + SLIM_CLK_GATE_OFST);
+
+	/* clear int & cmd mailbox */
+	writel(~0U, slim_rproc->peri + SLIM_INT_CLR_OFST);
+	writel(~0U, slim_rproc->peri + SLIM_CMD_CLR_OFST);
+
+	/* enable all channels cmd & int */
+	writel(~0U, slim_rproc->peri + SLIM_INT_MASK_OFST);
+	writel(~0U, slim_rproc->peri + SLIM_CMD_MASK_OFST);
+
+	/* enable cpu */
+	writel(SLIM_EN_RUN, slim_rproc->slimcore + SLIM_EN_OFST);
+
+	hw_id = readl_relaxed(slim_rproc->slimcore + SLIM_ID_OFST);
+	hw_ver = readl_relaxed(slim_rproc->slimcore + SLIM_VER_OFST);
+
+	fw_rev = readl(slim_rproc->mem[ST_SLIM_DMEM].cpu_addr +
+			SLIM_REV_ID_OFST);
+
+	dev_info(dev, "fw rev:%ld.%ld on SLIM %ld.%ld\n",
+		 SLIM_REV_ID_MAJ(fw_rev), SLIM_REV_ID_MIN(fw_rev),
+		 hw_id, hw_ver);
+
+	return 0;
+}
+
+static int slim_rproc_stop(struct rproc *rproc)
+{
+	struct st_slim_rproc *slim_rproc = rproc->priv;
+	u32 val;
+
+	/* mask all (cmd & int) channels */
+	writel(0UL, slim_rproc->peri + SLIM_INT_MASK_OFST);
+	writel(0UL, slim_rproc->peri + SLIM_CMD_MASK_OFST);
+
+	/* disable cpu pipeline clock */
+	writel(SLIM_CLK_GATE_DIS, slim_rproc->slimcore + SLIM_CLK_GATE_OFST);
+
+	writel(!SLIM_EN_RUN, slim_rproc->slimcore + SLIM_EN_OFST);
+
+	val = readl(slim_rproc->slimcore + SLIM_EN_OFST);
+	if (val & SLIM_EN_RUN)
+		dev_warn(&rproc->dev, "Failed to disable SLIM");
+
+	dev_dbg(&rproc->dev, "slim stopped\n");
+
+	return 0;
+}
+
+static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, int len)
+{
+	struct st_slim_rproc *slim_rproc = rproc->priv;
+	void *va = NULL;
+	int i;
+
+	for (i = 0; i < ST_SLIM_MEM_MAX; i++) {
+		if (da != slim_rproc->mem[i].bus_addr)
+			continue;
+
+		if (len <= slim_rproc->mem[i].size) {
+			/* __force to make sparse happy with type conversion */
+			va = (__force void *)slim_rproc->mem[i].cpu_addr;
+			break;
+		}
+	}
+
+	dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%x va = 0x%p\n", da, len, va);
+
+	return va;
+}
+
+static struct rproc_ops slim_rproc_ops = {
+	.start		= slim_rproc_start,
+	.stop		= slim_rproc_stop,
+	.da_to_va       = slim_rproc_da_to_va,
+};
+
+/*
+ * Firmware handler operations: sanity, boot address, load ...
+ */
+
+static struct resource_table empty_rsc_tbl = {
+	.ver = 1,
+	.num = 0,
+};
+
+static struct resource_table *slim_rproc_find_rsc_table(struct rproc *rproc,
+					       const struct firmware *fw,
+					       int *tablesz)
+{
+	*tablesz = sizeof(empty_rsc_tbl);
+	return &empty_rsc_tbl;
+}
+
+static struct rproc_fw_ops slim_rproc_fw_ops = {
+	.find_rsc_table = slim_rproc_find_rsc_table,
+};
+
+/**
+ * st_slim_rproc_alloc() - allocate and initialise slim rproc
+ * @pdev: Pointer to the platform_device struct
+ * @fw_name: Name of firmware for rproc to use
+ *
+ * Function for allocating and initialising a slim rproc for use by
+ * device drivers whose IP is based around the SLIM core. It
+ * obtains and enables any clocks required by the SLIM core and also
+ * ioremaps the various IO.
+ *
+ * Returns st_slim_rproc pointer or PTR_ERR() on error.
+ */
+
+struct st_slim_rproc *st_slim_rproc_alloc(struct platform_device *pdev,
+				char *fw_name)
+{
+	struct device *dev = &pdev->dev;
+	struct st_slim_rproc *slim_rproc;
+	struct device_node *np = dev->of_node;
+	struct rproc *rproc;
+	struct resource *res;
+	int err, i;
+	const struct rproc_fw_ops *elf_ops;
+
+	if (!fw_name)
+		return ERR_PTR(-EINVAL);
+
+	if (!of_device_is_compatible(np, "st,slim-rproc"))
+		return ERR_PTR(-EINVAL);
+
+	rproc = rproc_alloc(dev, np->name, &slim_rproc_ops,
+			fw_name, sizeof(*slim_rproc));
+	if (!rproc)
+		return ERR_PTR(-ENOMEM);
+
+	rproc->has_iommu = false;
+
+	slim_rproc = rproc->priv;
+	slim_rproc->rproc = rproc;
+
+	elf_ops = rproc->fw_ops;
+	/* Use some generic elf ops */
+	slim_rproc_fw_ops.load = elf_ops->load;
+	slim_rproc_fw_ops.sanity_check = elf_ops->sanity_check;
+
+	rproc->fw_ops = &slim_rproc_fw_ops;
+
+	/* get imem and dmem */
+	for (i = 0; i < ARRAY_SIZE(mem_names); i++) {
+		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+						mem_names[i]);
+
+		slim_rproc->mem[i].cpu_addr = devm_ioremap_resource(dev, res);
+		if (IS_ERR(slim_rproc->mem[i].cpu_addr)) {
+			dev_err(&pdev->dev, "devm_ioremap_resource failed\n");
+			err = PTR_ERR(slim_rproc->mem[i].cpu_addr);
+			goto err;
+		}
+		slim_rproc->mem[i].bus_addr = res->start;
+		slim_rproc->mem[i].size = resource_size(res);
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "slimcore");
+	slim_rproc->slimcore = devm_ioremap_resource(dev, res);
+	if (IS_ERR(slim_rproc->slimcore)) {
+		dev_err(&pdev->dev, "failed to ioremap slimcore IO\n");
+		err = PTR_ERR(slim_rproc->slimcore);
+		goto err;
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "peripherals");
+	slim_rproc->peri = devm_ioremap_resource(dev, res);
+	if (IS_ERR(slim_rproc->peri)) {
+		dev_err(&pdev->dev, "failed to ioremap peripherals IO\n");
+		err = PTR_ERR(slim_rproc->peri);
+		goto err;
+	}
+
+	err = slim_clk_get(slim_rproc, dev);
+	if (err)
+		goto err;
+
+	err = slim_clk_enable(slim_rproc);
+	if (err) {
+		dev_err(dev, "Failed to enable clocks\n");
+		goto err_clk_put;
+	}
+
+	/* Register as a remoteproc device */
+	err = rproc_add(rproc);
+	if (err) {
+		dev_err(dev, "registration of slim remoteproc failed\n");
+		goto err_clk_dis;
+	}
+
+	return slim_rproc;
+
+err_clk_dis:
+	slim_clk_disable(slim_rproc);
+err_clk_put:
+	for (i = 0; i < ST_SLIM_MAX_CLK && slim_rproc->clks[i]; i++)
+		clk_put(slim_rproc->clks[i]);
+err:
+	rproc_free(rproc);
+	return ERR_PTR(err);
+}
+EXPORT_SYMBOL(st_slim_rproc_alloc);
+
+/**
+  * st_slim_rproc_put() - put slim rproc resources
+  * @slim_rproc: Pointer to the st_slim_rproc struct
+  *
+  * Function for calling respective _put() functions on slim_rproc resources.
+  *
+  */
+void st_slim_rproc_put(struct st_slim_rproc *slim_rproc)
+{
+	int clk;
+
+	if (!slim_rproc)
+		return;
+
+	slim_clk_disable(slim_rproc);
+
+	for (clk = 0; clk < ST_SLIM_MAX_CLK && slim_rproc->clks[clk]; clk++)
+		clk_put(slim_rproc->clks[clk]);
+
+	rproc_del(slim_rproc->rproc);
+	rproc_put(slim_rproc->rproc);
+}
+EXPORT_SYMBOL(st_slim_rproc_put);
+
+MODULE_AUTHOR("Peter Griffin <peter.griffin@linaro.org>");
+MODULE_DESCRIPTION("STMicroelectronics SLIM core rproc driver");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/remoteproc/st_slim_rproc.h b/include/linux/remoteproc/st_slim_rproc.h
new file mode 100644
index 0000000..4155556
--- /dev/null
+++ b/include/linux/remoteproc/st_slim_rproc.h
@@ -0,0 +1,58 @@
+/*
+ * SLIM core rproc driver header
+ *
+ * Copyright (C) 2016 STMicroelectronics
+ *
+ * Author: Peter Griffin <peter.griffin@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#ifndef _ST_REMOTEPROC_SLIM_H
+#define _ST_REMOTEPROC_SLIM_H
+
+#define ST_SLIM_MEM_MAX 2
+#define ST_SLIM_MAX_CLK 4
+
+enum {
+	ST_SLIM_DMEM,
+	ST_SLIM_IMEM,
+};
+
+/**
+ * struct st_slim_mem - slim internal memory structure
+ * @cpu_addr: MPU virtual address of the memory region
+ * @bus_addr: Bus address used to access the memory region
+ * @size: Size of the memory region
+ */
+struct st_slim_mem {
+	void __iomem *cpu_addr;
+	phys_addr_t bus_addr;
+	size_t size;
+};
+
+/**
+ * struct st_slim_rproc - SLIM slim core
+ * @rproc: rproc handle
+ * @mem: slim memory information
+ * @slimcore: slim slimcore regs
+ * @peri: slim peripheral regs
+ * @clks: slim clocks
+ */
+struct st_slim_rproc {
+	struct rproc *rproc;
+	struct st_slim_mem mem[ST_SLIM_MEM_MAX];
+	void __iomem *slimcore;
+	void __iomem *peri;
+
+	/* st_slim_rproc private */
+	struct clk *clks[ST_SLIM_MAX_CLK];
+};
+
+struct st_slim_rproc *st_slim_rproc_alloc(struct platform_device *pdev,
+					char *fw_name);
+void st_slim_rproc_put(struct st_slim_rproc *slim_rproc);
+
+#endif
-- 
2.7.4

^ permalink raw reply related

* [PATCH v11 03/14] MAINTAINERS: Add st slim core rproc driver to STi section.
From: Peter Griffin @ 2016-11-07 18:17 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1478542665-17089-1-git-send-email-peter.griffin@linaro.org>

This patch adds the slim core rproc driver to the STi section
of the MAINTAINERS file.

Signed-off-by: Peter Griffin <peter.griffin@linaro.org>
Acked-by: Lee Jones <lee.jones@linaro.org>
---
 MAINTAINERS | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 1cd38a7..78b7f8b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1784,6 +1784,7 @@ F:	drivers/phy/phy-stih407-usb.c
 F:	drivers/phy/phy-stih41x-usb.c
 F:	drivers/pinctrl/pinctrl-st.c
 F:	drivers/remoteproc/st_remoteproc.c
+F:	drivers/remoteproc/st_slim_rproc.c
 F:	drivers/reset/sti/
 F:	drivers/rtc/rtc-st-lpc.c
 F:	drivers/tty/serial/st-asc.c
@@ -1792,6 +1793,7 @@ F:	drivers/usb/host/ehci-st.c
 F:	drivers/usb/host/ohci-st.c
 F:	drivers/watchdog/st_lpc_wdt.c
 F:	drivers/ata/ahci_st.c
+F:	include/linux/remoteproc/st_slim_rproc.h
 
 ARM/STM32 ARCHITECTURE
 M:	Maxime Coquelin <mcoquelin.stm32@gmail.com>
-- 
2.7.4

^ permalink raw reply related

* [PATCH v11 04/14] dmaengine: st_fdma: Add STMicroelectronics FDMA DT binding documentation
From: Peter Griffin @ 2016-11-07 18:17 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1478542665-17089-1-git-send-email-peter.griffin@linaro.org>

This patch adds the DT binding documentation for the FDMA constroller
found on STi based chipsets from STMicroelectronics.

Signed-off-by: Ludovic Barre <ludovic.barre@st.com>
Signed-off-by: Peter Griffin <peter.griffin@linaro.org>
Acked-by: Rob Herring <robh@kernel.org>
---
 Documentation/devicetree/bindings/dma/st_fdma.txt | 87 +++++++++++++++++++++++
 1 file changed, 87 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/dma/st_fdma.txt

diff --git a/Documentation/devicetree/bindings/dma/st_fdma.txt b/Documentation/devicetree/bindings/dma/st_fdma.txt
new file mode 100644
index 0000000..495d853
--- /dev/null
+++ b/Documentation/devicetree/bindings/dma/st_fdma.txt
@@ -0,0 +1,87 @@
+* STMicroelectronics Flexible Direct Memory Access Device Tree bindings
+
+The FDMA is a general-purpose direct memory access controller capable of
+supporting 16 independent DMA channels. It accepts up to 32 DMA requests.
+The FDMA is based on a Slim processor which requires a firmware.
+
+* FDMA Controller
+
+Required properties:
+- compatible	: Should be one of
+		 - st,stih407-fdma-mpe31-11, "st,slim-rproc";
+		 - st,stih407-fdma-mpe31-12, "st,slim-rproc";
+		 - st,stih407-fdma-mpe31-13, "st,slim-rproc";
+- reg		: Should contain an entry for each name in reg-names
+- reg-names	: Must contain "slimcore", "dmem", "peripherals", "imem" entries
+- interrupts	: Should contain one interrupt shared by all channels
+- dma-channels	: Number of channels supported by the controller
+- #dma-cells	: Must be <3>. See DMA client section below
+- clocks	: Must contain an entry for each clock
+See: Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+
+Example:
+
+	fdma0: dma-controller at 8e20000 {
+		compatible = "st,stih407-fdma-mpe31-11", "st,slim-rproc";
+		reg = <0x8e20000 0x8000>,
+		      <0x8e30000 0x3000>,
+		      <0x8e37000 0x1000>,
+		      <0x8e38000 0x8000>;
+		reg-names = "slimcore", "dmem", "peripherals", "imem";
+		clocks = <&clk_s_c0_flexgen CLK_FDMA>,
+			 <&clk_s_c0_flexgen CLK_EXT2F_A9>,
+			 <&clk_s_c0_flexgen CLK_EXT2F_A9>,
+			 <&clk_s_c0_flexgen CLK_EXT2F_A9>;
+		interrupts = <GIC_SPI 5 IRQ_TYPE_NONE>;
+		dma-channels = <16>;
+		#dma-cells = <3>;
+	};
+
+* DMA client
+
+Required properties:
+- dmas: Comma separated list of dma channel requests
+- dma-names: Names of the aforementioned requested channels
+
+Each dmas request consists of 4 cells:
+1. A phandle pointing to the FDMA controller
+2. The request line number
+3. A 32bit mask specifying (see include/linux/platform_data/dma-st-fdma.h)
+ -bit 2-0: Holdoff value, dreq will be masked for
+	0x0: 0-0.5us
+	0x1: 0.5-1us
+	0x2: 1-1.5us
+ -bit 17: data swap
+	0x0: disabled
+	0x1: enabled
+ -bit 21: Increment Address
+	0x0: no address increment between transfers
+	0x1: increment address between transfers
+ -bit 22: 2 STBus Initiator Coprocessor interface
+	0x0: high priority port
+	0x1: low priority port
+4. transfers type
+ 0 free running
+ 1 paced
+
+Example:
+
+	sti_uni_player2: sti-uni-player at 2 {
+		compatible = "st,sti-uni-player";
+		status = "disabled";
+		#sound-dai-cells = <0>;
+		st,syscfg = <&syscfg_core>;
+		clocks = <&clk_s_d0_flexgen CLK_PCM_2>;
+		assigned-clocks = <&clk_s_d0_flexgen CLK_PCM_2>;
+		assigned-clock-parents = <&clk_s_d0_quadfs 2>;
+		assigned-clock-rates = <50000000>;
+		reg = <0x8D82000 0x158>;
+		interrupts = <GIC_SPI 86 IRQ_TYPE_NONE>;
+		dmas = <&fdma0 4 0 1>;
+		dai-name = "Uni Player #1 (DAC)";
+		dma-names = "tx";
+		st,uniperiph-id = <2>;
+		st,version = <5>;
+		st,mode = "PCM";
+	};
-- 
2.7.4

^ permalink raw reply related

* [PATCH v11 05/14] dmaengine: st_fdma: Add STMicroelectronics FDMA driver header file
From: Peter Griffin @ 2016-11-07 18:17 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1478542665-17089-1-git-send-email-peter.griffin@linaro.org>

This header file will also be used by the dma xbar driver in the
future.

Signed-off-by: Ludovic Barre <ludovic.barre@st.com>
Signed-off-by: Peter Griffin <peter.griffin@linaro.org>
---
 drivers/dma/st_fdma.h | 249 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 249 insertions(+)
 create mode 100644 drivers/dma/st_fdma.h

diff --git a/drivers/dma/st_fdma.h b/drivers/dma/st_fdma.h
new file mode 100644
index 0000000..c58e00d
--- /dev/null
+++ b/drivers/dma/st_fdma.h
@@ -0,0 +1,249 @@
+/*
+ * DMA driver header for STMicroelectronics STi FDMA controller
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * Author: Ludovic Barre <Ludovic.barre@st.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#ifndef __DMA_ST_FDMA_H
+#define __DMA_ST_FDMA_H
+
+#include <linux/dmaengine.h>
+#include <linux/dmapool.h>
+#include <linux/io.h>
+#include <linux/remoteproc/st_slim_rproc.h>
+#include "virt-dma.h"
+
+#define ST_FDMA_NR_DREQS 32
+#define FW_NAME_SIZE 30
+#define DRIVER_NAME "st-fdma"
+
+/**
+ * struct st_fdma_generic_node - Free running/paced generic node
+ *
+ * @length: Length in bytes of a line in a 2D mem to mem
+ * @sstride: Stride, in bytes, between source lines in a 2D data move
+ * @dstride: Stride, in bytes, between destination lines in a 2D data move
+ */
+struct st_fdma_generic_node {
+	u32 length;
+	u32 sstride;
+	u32 dstride;
+};
+
+/**
+ * struct st_fdma_hw_node - Node structure used by fdma hw
+ *
+ * @next: Pointer to next node
+ * @control: Transfer Control Parameters
+ * @nbytes: Number of Bytes to read
+ * @saddr: Source address
+ * @daddr: Destination address
+ *
+ * @generic: generic node for free running/paced transfert type
+ * 2 others transfert type are possible, but not yet implemented
+ *
+ * The NODE structures must be aligned to a 32 byte boundary
+ */
+struct st_fdma_hw_node {
+	u32 next;
+	u32 control;
+	u32 nbytes;
+	u32 saddr;
+	u32 daddr;
+	union {
+		struct st_fdma_generic_node generic;
+	};
+} __aligned(32);
+
+/*
+ * node control parameters
+ */
+#define FDMA_NODE_CTRL_REQ_MAP_MASK	GENMASK(4, 0)
+#define FDMA_NODE_CTRL_REQ_MAP_FREE_RUN	0x0
+#define FDMA_NODE_CTRL_REQ_MAP_DREQ(n)	((n)&FDMA_NODE_CTRL_REQ_MAP_MASK)
+#define FDMA_NODE_CTRL_REQ_MAP_EXT		FDMA_NODE_CTRL_REQ_MAP_MASK
+#define FDMA_NODE_CTRL_SRC_MASK		GENMASK(6, 5)
+#define FDMA_NODE_CTRL_SRC_STATIC	BIT(5)
+#define FDMA_NODE_CTRL_SRC_INCR		BIT(6)
+#define FDMA_NODE_CTRL_DST_MASK		GENMASK(8, 7)
+#define FDMA_NODE_CTRL_DST_STATIC	BIT(7)
+#define FDMA_NODE_CTRL_DST_INCR		BIT(8)
+#define FDMA_NODE_CTRL_SECURE		BIT(15)
+#define FDMA_NODE_CTRL_PAUSE_EON	BIT(30)
+#define FDMA_NODE_CTRL_INT_EON		BIT(31)
+
+/**
+ * struct st_fdma_sw_node - descriptor structure for link list
+ *
+ * @pdesc: Physical address of desc
+ * @node: link used for putting this into a channel queue
+ */
+struct st_fdma_sw_node {
+	dma_addr_t pdesc;
+	struct st_fdma_hw_node *desc;
+};
+
+#define NAME_SZ 10
+
+struct st_fdma_driverdata {
+	u32 id;
+	char name[NAME_SZ];
+};
+
+struct st_fdma_desc {
+	struct virt_dma_desc vdesc;
+	struct st_fdma_chan *fchan;
+	bool iscyclic;
+	unsigned int n_nodes;
+	struct st_fdma_sw_node node[];
+};
+
+enum st_fdma_type {
+	ST_FDMA_TYPE_FREE_RUN,
+	ST_FDMA_TYPE_PACED,
+};
+
+struct st_fdma_cfg {
+	struct device_node *of_node;
+	enum st_fdma_type type;
+	dma_addr_t dev_addr;
+	enum dma_transfer_direction dir;
+	int req_line; /* request line */
+	long req_ctrl; /* Request control */
+};
+
+struct st_fdma_chan {
+	struct st_fdma_dev *fdev;
+	struct dma_pool *node_pool;
+	struct dma_slave_config scfg;
+	struct st_fdma_cfg cfg;
+
+	int dreq_line;
+
+	struct virt_dma_chan vchan;
+	struct st_fdma_desc *fdesc;
+	enum dma_status	status;
+};
+
+struct st_fdma_dev {
+	struct device *dev;
+	const struct st_fdma_driverdata *drvdata;
+	struct dma_device dma_device;
+
+	struct st_slim_rproc *slim_rproc;
+
+	int irq;
+
+	struct st_fdma_chan *chans;
+
+	spinlock_t dreq_lock;
+	unsigned long dreq_mask;
+
+	u32 nr_channels;
+	char fw_name[FW_NAME_SIZE];
+};
+
+/* Peripheral Registers*/
+
+#define FDMA_CMD_STA_OFST	0xFC0
+#define FDMA_CMD_SET_OFST	0xFC4
+#define FDMA_CMD_CLR_OFST	0xFC8
+#define FDMA_CMD_MASK_OFST	0xFCC
+#define FDMA_CMD_START(ch)		(0x1 << (ch << 1))
+#define FDMA_CMD_PAUSE(ch)		(0x2 << (ch << 1))
+#define FDMA_CMD_FLUSH(ch)		(0x3 << (ch << 1))
+
+#define FDMA_INT_STA_OFST	0xFD0
+#define FDMA_INT_STA_CH			0x1
+#define FDMA_INT_STA_ERR		0x2
+
+#define FDMA_INT_SET_OFST	0xFD4
+#define FDMA_INT_CLR_OFST	0xFD8
+#define FDMA_INT_MASK_OFST	0xFDC
+
+#define fdma_read(fdev, name) \
+	readl((fdev)->slim_rproc->peri + name)
+
+#define fdma_write(fdev, val, name) \
+	writel((val), (fdev)->slim_rproc->peri + name)
+
+/* fchan interface (dmem) */
+#define FDMA_CH_CMD_OFST	0x200
+#define FDMA_CH_CMD_STA_MASK		GENMASK(1, 0)
+#define FDMA_CH_CMD_STA_IDLE		(0x0)
+#define FDMA_CH_CMD_STA_START		(0x1)
+#define FDMA_CH_CMD_STA_RUNNING		(0x2)
+#define FDMA_CH_CMD_STA_PAUSED		(0x3)
+#define FDMA_CH_CMD_ERR_MASK		GENMASK(4, 2)
+#define FDMA_CH_CMD_ERR_INT		(0x0 << 2)
+#define FDMA_CH_CMD_ERR_NAND		(0x1 << 2)
+#define FDMA_CH_CMD_ERR_MCHI		(0x2 << 2)
+#define FDMA_CH_CMD_DATA_MASK		GENMASK(31, 5)
+#define fchan_read(fchan, name) \
+	readl((fchan)->fdev->slim_rproc->mem[ST_SLIM_DMEM].cpu_addr \
+			+ (fchan)->vchan.chan.chan_id * 0x4 \
+			+ name)
+
+#define fchan_write(fchan, val, name) \
+	writel((val), (fchan)->fdev->slim_rproc->mem[ST_SLIM_DMEM].cpu_addr \
+			+ (fchan)->vchan.chan.chan_id * 0x4 \
+			+ name)
+
+/* req interface */
+#define FDMA_REQ_CTRL_OFST	0x240
+#define dreq_write(fchan, val, name) \
+	writel((val), (fchan)->fdev->slim_rproc->mem[ST_SLIM_DMEM].cpu_addr \
+			+ fchan->dreq_line * 0x04 \
+			+ name)
+/* node interface */
+#define FDMA_NODE_SZ 128
+#define FDMA_PTRN_OFST		0x800
+#define FDMA_CNTN_OFST		0x808
+#define FDMA_SADDRN_OFST	0x80c
+#define FDMA_DADDRN_OFST	0x810
+#define fnode_read(fchan, name) \
+	readl((fchan)->fdev->slim_rproc->mem[ST_SLIM_DMEM].cpu_addr \
+			+ (fchan)->vchan.chan.chan_id * FDMA_NODE_SZ \
+			+ name)
+
+#define fnode_write(fchan, val, name) \
+	writel((val), (fchan)->fdev->slim_rproc->mem[ST_SLIM_DMEM].cpu_addr \
+			+ (fchan)->vchan.chan.chan_id * FDMA_NODE_SZ \
+			+ name)
+
+/*
+ * request control bits
+ */
+#define FDMA_REQ_CTRL_NUM_OPS_MASK	GENMASK(31, 24)
+#define FDMA_REQ_CTRL_NUM_OPS(n)	(FDMA_REQ_CTRL_NUM_OPS_MASK & \
+					((n) << 24))
+#define FDMA_REQ_CTRL_INITIATOR_MASK	BIT(22)
+#define FDMA_REQ_CTRL_INIT0		(0x0 << 22)
+#define FDMA_REQ_CTRL_INIT1		(0x1 << 22)
+#define FDMA_REQ_CTRL_INC_ADDR_ON	BIT(21)
+#define FDMA_REQ_CTRL_DATA_SWAP_ON	BIT(17)
+#define FDMA_REQ_CTRL_WNR		BIT(14)
+#define FDMA_REQ_CTRL_OPCODE_MASK	GENMASK(7, 4)
+#define FDMA_REQ_CTRL_OPCODE_LD_ST1	(0x0 << 4)
+#define FDMA_REQ_CTRL_OPCODE_LD_ST2	(0x1 << 4)
+#define FDMA_REQ_CTRL_OPCODE_LD_ST4	(0x2 << 4)
+#define FDMA_REQ_CTRL_OPCODE_LD_ST8	(0x3 << 4)
+#define FDMA_REQ_CTRL_OPCODE_LD_ST16	(0x4 << 4)
+#define FDMA_REQ_CTRL_OPCODE_LD_ST32	(0x5 << 4)
+#define FDMA_REQ_CTRL_OPCODE_LD_ST64	(0x6 << 4)
+#define FDMA_REQ_CTRL_HOLDOFF_MASK	GENMASK(2, 0)
+#define FDMA_REQ_CTRL_HOLDOFF(n)	((n) & FDMA_REQ_CTRL_HOLDOFF_MASK)
+
+/* bits used by client to configure request control */
+#define FDMA_REQ_CTRL_CFG_MASK (FDMA_REQ_CTRL_HOLDOFF_MASK | \
+				FDMA_REQ_CTRL_DATA_SWAP_ON | \
+				FDMA_REQ_CTRL_INC_ADDR_ON | \
+				FDMA_REQ_CTRL_INITIATOR_MASK)
+
+#endif	/* __DMA_ST_FDMA_H */
-- 
2.7.4

^ permalink raw reply related

* [PATCH v11 06/14] dmaengine: st_fdma: Add STMicroelectronics FDMA engine driver support
From: Peter Griffin @ 2016-11-07 18:17 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1478542665-17089-1-git-send-email-peter.griffin@linaro.org>

This patch adds support for the Flexible Direct Memory Access (FDMA) core
driver. The FDMA is a slim core CPU with a dedicated firmware.
It is a general purpose DMA controller capable of supporting 16
independent DMA channels. Data moves maybe from memory to memory
or between memory and paced latency critical real time targets and it
is found on al STi based chipsets.

Signed-off-by: Ludovic Barre <ludovic.barre@st.com>
Signed-off-by: Peter Griffin <peter.griffin@linaro.org>
---
 drivers/dma/Kconfig   |  13 +
 drivers/dma/Makefile  |   1 +
 drivers/dma/st_fdma.c | 899 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 913 insertions(+)
 create mode 100644 drivers/dma/st_fdma.c

diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index af63a6b..661f217 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -435,6 +435,19 @@ config STE_DMA40
 	help
 	  Support for ST-Ericsson DMA40 controller
 
+config ST_FDMA
+	tristate "ST FDMA dmaengine support"
+	depends on ARCH_STI
+	select ST_SLIM_REMOTEPROC
+	select DMA_ENGINE
+	select DMA_VIRTUAL_CHANNELS
+	help
+	  Enable support for ST FDMA controller.
+	  It supports 16 independent DMA channels, accepts up to 32 DMA requests
+
+	  Say Y here if you have such a chipset.
+	  If unsure, say N.
+
 config STM32_DMA
 	bool "STMicroelectronics STM32 DMA support"
 	depends on ARCH_STM32 || COMPILE_TEST
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index e4dc9ca..a4fa336 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -67,6 +67,7 @@ obj-$(CONFIG_TI_DMA_CROSSBAR) += ti-dma-crossbar.o
 obj-$(CONFIG_TI_EDMA) += edma.o
 obj-$(CONFIG_XGENE_DMA) += xgene-dma.o
 obj-$(CONFIG_ZX_DMA) += zx296702_dma.o
+obj-$(CONFIG_ST_FDMA) += st_fdma.o
 
 obj-y += qcom/
 obj-y += xilinx/
diff --git a/drivers/dma/st_fdma.c b/drivers/dma/st_fdma.c
new file mode 100644
index 0000000..515e1d4
--- /dev/null
+++ b/drivers/dma/st_fdma.c
@@ -0,0 +1,899 @@
+/*
+ * DMA driver for STMicroelectronics STi FDMA controller
+ *
+ * Copyright (C) 2014 STMicroelectronics
+ *
+ * Author: Ludovic Barre <Ludovic.barre@st.com>
+ *	   Peter Griffin <peter.griffin@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_dma.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/remoteproc.h>
+
+#include "st_fdma.h"
+
+static inline struct st_fdma_chan *to_st_fdma_chan(struct dma_chan *c)
+{
+	return container_of(c, struct st_fdma_chan, vchan.chan);
+}
+
+static struct st_fdma_desc *to_st_fdma_desc(struct virt_dma_desc *vd)
+{
+	return container_of(vd, struct st_fdma_desc, vdesc);
+}
+
+static int st_fdma_dreq_get(struct st_fdma_chan *fchan)
+{
+	struct st_fdma_dev *fdev = fchan->fdev;
+	u32 req_line_cfg = fchan->cfg.req_line;
+	u32 dreq_line;
+	int try = 0;
+
+	/*
+	 * dreq_mask is shared for n channels of fdma, so all accesses must be
+	 * atomic. if the dreq_mask is changed between ffz and set_bit,
+	 * we retry
+	 */
+	do {
+		if (fdev->dreq_mask == ~0L) {
+			dev_err(fdev->dev, "No req lines available\n");
+			return -EINVAL;
+		}
+
+		if (try || req_line_cfg >= ST_FDMA_NR_DREQS) {
+			dev_err(fdev->dev, "Invalid or used req line\n");
+			return -EINVAL;
+		} else {
+			dreq_line = req_line_cfg;
+		}
+
+		try++;
+	} while (test_and_set_bit(dreq_line, &fdev->dreq_mask));
+
+	dev_dbg(fdev->dev, "get dreq_line:%d mask:%#lx\n",
+		dreq_line, fdev->dreq_mask);
+
+	return dreq_line;
+}
+
+static void st_fdma_dreq_put(struct st_fdma_chan *fchan)
+{
+	struct st_fdma_dev *fdev = fchan->fdev;
+
+	dev_dbg(fdev->dev, "put dreq_line:%#x\n", fchan->dreq_line);
+	clear_bit(fchan->dreq_line, &fdev->dreq_mask);
+}
+
+static void st_fdma_xfer_desc(struct st_fdma_chan *fchan)
+{
+	struct virt_dma_desc *vdesc;
+	unsigned long nbytes, ch_cmd, cmd;
+
+	vdesc = vchan_next_desc(&fchan->vchan);
+	if (!vdesc)
+		return;
+
+	fchan->fdesc = to_st_fdma_desc(vdesc);
+	nbytes = fchan->fdesc->node[0].desc->nbytes;
+	cmd = FDMA_CMD_START(fchan->vchan.chan.chan_id);
+	ch_cmd = fchan->fdesc->node[0].pdesc | FDMA_CH_CMD_STA_START;
+
+	/* start the channel for the descriptor */
+	fnode_write(fchan, nbytes, FDMA_CNTN_OFST);
+	fchan_write(fchan, ch_cmd, FDMA_CH_CMD_OFST);
+	writel(cmd,
+		fchan->fdev->slim_rproc->peri + FDMA_CMD_SET_OFST);
+
+	dev_dbg(fchan->fdev->dev, "start chan:%d\n", fchan->vchan.chan.chan_id);
+}
+
+static void st_fdma_ch_sta_update(struct st_fdma_chan *fchan,
+				  unsigned long int_sta)
+{
+	unsigned long ch_sta, ch_err;
+	int ch_id = fchan->vchan.chan.chan_id;
+	struct st_fdma_dev *fdev = fchan->fdev;
+
+	ch_sta = fchan_read(fchan, FDMA_CH_CMD_OFST);
+	ch_err = ch_sta & FDMA_CH_CMD_ERR_MASK;
+	ch_sta &= FDMA_CH_CMD_STA_MASK;
+
+	if (int_sta & FDMA_INT_STA_ERR) {
+		dev_warn(fdev->dev, "chan:%d, error:%ld\n", ch_id, ch_err);
+		fchan->status = DMA_ERROR;
+		return;
+	}
+
+	switch (ch_sta) {
+	case FDMA_CH_CMD_STA_PAUSED:
+		fchan->status = DMA_PAUSED;
+		break;
+
+	case FDMA_CH_CMD_STA_RUNNING:
+		fchan->status = DMA_IN_PROGRESS;
+		break;
+	}
+}
+
+static irqreturn_t st_fdma_irq_handler(int irq, void *dev_id)
+{
+	struct st_fdma_dev *fdev = dev_id;
+	irqreturn_t ret = IRQ_NONE;
+	struct st_fdma_chan *fchan = &fdev->chans[0];
+	unsigned long int_sta, clr;
+
+	int_sta = fdma_read(fdev, FDMA_INT_STA_OFST);
+	clr = int_sta;
+
+	for (; int_sta != 0 ; int_sta >>= 2, fchan++) {
+		if (!(int_sta & (FDMA_INT_STA_CH | FDMA_INT_STA_ERR)))
+			continue;
+
+		spin_lock(&fchan->vchan.lock);
+		st_fdma_ch_sta_update(fchan, int_sta);
+
+		if (fchan->fdesc) {
+			if (!fchan->fdesc->iscyclic) {
+				list_del(&fchan->fdesc->vdesc.node);
+				vchan_cookie_complete(&fchan->fdesc->vdesc);
+				fchan->fdesc = NULL;
+				fchan->status = DMA_COMPLETE;
+			} else {
+				vchan_cyclic_callback(&fchan->fdesc->vdesc);
+			}
+
+			/* Start the next descriptor (if available) */
+			if (!fchan->fdesc)
+				st_fdma_xfer_desc(fchan);
+		}
+
+		spin_unlock(&fchan->vchan.lock);
+		ret = IRQ_HANDLED;
+	}
+
+	fdma_write(fdev, clr, FDMA_INT_CLR_OFST);
+
+	return ret;
+}
+
+static struct dma_chan *st_fdma_of_xlate(struct of_phandle_args *dma_spec,
+					 struct of_dma *ofdma)
+{
+	struct st_fdma_dev *fdev = ofdma->of_dma_data;
+	struct dma_chan *chan;
+	struct st_fdma_chan *fchan;
+	int ret;
+
+	if (dma_spec->args_count < 1)
+		return ERR_PTR(-EINVAL);
+
+	if (fdev->dma_device.dev->of_node != dma_spec->np)
+		return ERR_PTR(-EINVAL);
+
+	ret = rproc_boot(fdev->slim_rproc->rproc);
+	if (ret == -ENOENT)
+		return ERR_PTR(-EPROBE_DEFER);
+	else if (ret)
+		return ERR_PTR(ret);
+
+	chan = dma_get_any_slave_channel(&fdev->dma_device);
+	if (!chan)
+		goto err_chan;
+
+	fchan = to_st_fdma_chan(chan);
+
+	fchan->cfg.of_node = dma_spec->np;
+	fchan->cfg.req_line = dma_spec->args[0];
+	fchan->cfg.req_ctrl = 0;
+	fchan->cfg.type = ST_FDMA_TYPE_FREE_RUN;
+
+	if (dma_spec->args_count > 1)
+		fchan->cfg.req_ctrl = dma_spec->args[1]
+			& FDMA_REQ_CTRL_CFG_MASK;
+
+	if (dma_spec->args_count > 2)
+		fchan->cfg.type = dma_spec->args[2];
+
+	if (fchan->cfg.type == ST_FDMA_TYPE_FREE_RUN) {
+		fchan->dreq_line = 0;
+	} else {
+		fchan->dreq_line = st_fdma_dreq_get(fchan);
+		if (IS_ERR_VALUE(fchan->dreq_line)) {
+			chan = ERR_PTR(fchan->dreq_line);
+			goto err_chan;
+		}
+	}
+
+	dev_dbg(fdev->dev, "xlate req_line:%d type:%d req_ctrl:%#lx\n",
+		fchan->cfg.req_line, fchan->cfg.type, fchan->cfg.req_ctrl);
+
+	return chan;
+
+err_chan:
+	rproc_shutdown(fdev->slim_rproc->rproc);
+	return chan;
+
+}
+
+static void st_fdma_free_desc(struct virt_dma_desc *vdesc)
+{
+	struct st_fdma_desc *fdesc;
+	int i;
+
+	fdesc = to_st_fdma_desc(vdesc);
+	for (i = 0; i < fdesc->n_nodes; i++)
+		dma_pool_free(fdesc->fchan->node_pool, fdesc->node[i].desc,
+			      fdesc->node[i].pdesc);
+	kfree(fdesc);
+}
+
+static struct st_fdma_desc *st_fdma_alloc_desc(struct st_fdma_chan *fchan,
+					       int sg_len)
+{
+	struct st_fdma_desc *fdesc;
+	int i;
+
+	fdesc = kzalloc(sizeof(*fdesc) +
+			sizeof(struct st_fdma_sw_node) * sg_len, GFP_NOWAIT);
+	if (!fdesc)
+		return NULL;
+
+	fdesc->fchan = fchan;
+	fdesc->n_nodes = sg_len;
+	for (i = 0; i < sg_len; i++) {
+		fdesc->node[i].desc = dma_pool_alloc(fchan->node_pool,
+				GFP_NOWAIT, &fdesc->node[i].pdesc);
+		if (!fdesc->node[i].desc)
+			goto err;
+	}
+	return fdesc;
+
+err:
+	while (--i >= 0)
+		dma_pool_free(fchan->node_pool, fdesc->node[i].desc,
+			      fdesc->node[i].pdesc);
+	kfree(fdesc);
+	return NULL;
+}
+
+static int st_fdma_alloc_chan_res(struct dma_chan *chan)
+{
+	struct st_fdma_chan *fchan = to_st_fdma_chan(chan);
+
+	/* Create the dma pool for descriptor allocation */
+	fchan->node_pool = dma_pool_create(dev_name(&chan->dev->device),
+					    fchan->fdev->dev,
+					    sizeof(struct st_fdma_hw_node),
+					    __alignof__(struct st_fdma_hw_node),
+					    0);
+
+	if (!fchan->node_pool) {
+		dev_err(fchan->fdev->dev, "unable to allocate desc pool\n");
+		return -ENOMEM;
+	}
+
+	dev_dbg(fchan->fdev->dev, "alloc ch_id:%d type:%d\n",
+		fchan->vchan.chan.chan_id, fchan->cfg.type);
+
+	return 0;
+}
+
+static void st_fdma_free_chan_res(struct dma_chan *chan)
+{
+	struct st_fdma_chan *fchan = to_st_fdma_chan(chan);
+	struct rproc *rproc = fchan->fdev->slim_rproc->rproc;
+	unsigned long flags;
+
+	LIST_HEAD(head);
+
+	dev_dbg(fchan->fdev->dev, "%s: freeing chan:%d\n",
+		__func__, fchan->vchan.chan.chan_id);
+
+	if (fchan->cfg.type != ST_FDMA_TYPE_FREE_RUN)
+		st_fdma_dreq_put(fchan);
+
+	spin_lock_irqsave(&fchan->vchan.lock, flags);
+	fchan->fdesc = NULL;
+	spin_unlock_irqrestore(&fchan->vchan.lock, flags);
+
+	dma_pool_destroy(fchan->node_pool);
+	fchan->node_pool = NULL;
+	memset(&fchan->cfg, 0, sizeof(struct st_fdma_cfg));
+
+	rproc_shutdown(rproc);
+}
+
+static struct dma_async_tx_descriptor *st_fdma_prep_dma_memcpy(
+	struct dma_chan *chan,	dma_addr_t dst, dma_addr_t src,
+	size_t len, unsigned long flags)
+{
+	struct st_fdma_chan *fchan;
+	struct st_fdma_desc *fdesc;
+	struct st_fdma_hw_node *hw_node;
+
+	if (!len)
+		return NULL;
+
+	fchan = to_st_fdma_chan(chan);
+
+	/* We only require a single descriptor */
+	fdesc = st_fdma_alloc_desc(fchan, 1);
+	if (!fdesc) {
+		dev_err(fchan->fdev->dev, "no memory for desc\n");
+		return NULL;
+	}
+
+	hw_node = fdesc->node[0].desc;
+	hw_node->next = 0;
+	hw_node->control = FDMA_NODE_CTRL_REQ_MAP_FREE_RUN;
+	hw_node->control |= FDMA_NODE_CTRL_SRC_INCR;
+	hw_node->control |= FDMA_NODE_CTRL_DST_INCR;
+	hw_node->control |= FDMA_NODE_CTRL_INT_EON;
+	hw_node->nbytes = len;
+	hw_node->saddr = src;
+	hw_node->daddr = dst;
+	hw_node->generic.length = len;
+	hw_node->generic.sstride = 0;
+	hw_node->generic.dstride = 0;
+
+	return vchan_tx_prep(&fchan->vchan, &fdesc->vdesc, flags);
+}
+
+static int config_reqctrl(struct st_fdma_chan *fchan,
+			  enum dma_transfer_direction direction)
+{
+	u32 maxburst = 0, addr = 0;
+	enum dma_slave_buswidth width;
+	int ch_id = fchan->vchan.chan.chan_id;
+	struct st_fdma_dev *fdev = fchan->fdev;
+
+	switch (direction) {
+
+	case DMA_DEV_TO_MEM:
+		fchan->cfg.req_ctrl &= ~FDMA_REQ_CTRL_WNR;
+		maxburst = fchan->scfg.src_maxburst;
+		width = fchan->scfg.src_addr_width;
+		addr = fchan->scfg.src_addr;
+		break;
+
+	case DMA_MEM_TO_DEV:
+		fchan->cfg.req_ctrl |= FDMA_REQ_CTRL_WNR;
+		maxburst = fchan->scfg.dst_maxburst;
+		width = fchan->scfg.dst_addr_width;
+		addr = fchan->scfg.dst_addr;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	fchan->cfg.req_ctrl &= ~FDMA_REQ_CTRL_OPCODE_MASK;
+
+	switch (width) {
+
+	case DMA_SLAVE_BUSWIDTH_1_BYTE:
+		fchan->cfg.req_ctrl |= FDMA_REQ_CTRL_OPCODE_LD_ST1;
+		break;
+
+	case DMA_SLAVE_BUSWIDTH_2_BYTES:
+		fchan->cfg.req_ctrl |= FDMA_REQ_CTRL_OPCODE_LD_ST2;
+		break;
+
+	case DMA_SLAVE_BUSWIDTH_4_BYTES:
+		fchan->cfg.req_ctrl |= FDMA_REQ_CTRL_OPCODE_LD_ST4;
+		break;
+
+	case DMA_SLAVE_BUSWIDTH_8_BYTES:
+		fchan->cfg.req_ctrl |= FDMA_REQ_CTRL_OPCODE_LD_ST8;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	fchan->cfg.req_ctrl &= ~FDMA_REQ_CTRL_NUM_OPS_MASK;
+	fchan->cfg.req_ctrl |= FDMA_REQ_CTRL_NUM_OPS(maxburst-1);
+	dreq_write(fchan, fchan->cfg.req_ctrl, FDMA_REQ_CTRL_OFST);
+
+	fchan->cfg.dev_addr = addr;
+	fchan->cfg.dir = direction;
+
+	dev_dbg(fdev->dev, "chan:%d config_reqctrl:%#x req_ctrl:%#lx\n",
+		ch_id, addr, fchan->cfg.req_ctrl);
+
+	return 0;
+}
+
+static void fill_hw_node(struct st_fdma_hw_node *hw_node,
+			struct st_fdma_chan *fchan,
+			enum dma_transfer_direction direction)
+{
+	if (direction == DMA_MEM_TO_DEV) {
+		hw_node->control |= FDMA_NODE_CTRL_SRC_INCR;
+		hw_node->control |= FDMA_NODE_CTRL_DST_STATIC;
+		hw_node->daddr = fchan->cfg.dev_addr;
+	} else {
+		hw_node->control |= FDMA_NODE_CTRL_SRC_STATIC;
+		hw_node->control |= FDMA_NODE_CTRL_DST_INCR;
+		hw_node->saddr = fchan->cfg.dev_addr;
+	}
+
+	hw_node->generic.sstride = 0;
+	hw_node->generic.dstride = 0;
+}
+
+static inline struct st_fdma_chan *st_fdma_prep_common(struct dma_chan *chan,
+		size_t len, enum dma_transfer_direction direction)
+{
+	struct st_fdma_chan *fchan;
+
+	if (!chan || !len)
+		return NULL;
+
+	fchan = to_st_fdma_chan(chan);
+
+	if (!is_slave_direction(direction)) {
+		dev_err(fchan->fdev->dev, "bad direction?\n");
+		return NULL;
+	}
+
+	return fchan;
+}
+
+static struct dma_async_tx_descriptor *st_fdma_prep_dma_cyclic(
+		struct dma_chan *chan, dma_addr_t buf_addr, size_t len,
+		size_t period_len, enum dma_transfer_direction direction,
+		unsigned long flags)
+{
+	struct st_fdma_chan *fchan;
+	struct st_fdma_desc *fdesc;
+	int sg_len, i;
+
+	fchan = st_fdma_prep_common(chan, len, direction);
+	if (!fchan)
+		return NULL;
+
+	if (!period_len)
+		return NULL;
+
+	if (config_reqctrl(fchan, direction)) {
+		dev_err(fchan->fdev->dev, "bad width or direction\n");
+		return NULL;
+	}
+
+	/* the buffer length must be a multiple of period_len */
+	if (len % period_len != 0) {
+		dev_err(fchan->fdev->dev, "len is not multiple of period\n");
+		return NULL;
+	}
+
+	sg_len = len / period_len;
+	fdesc = st_fdma_alloc_desc(fchan, sg_len);
+	if (!fdesc) {
+		dev_err(fchan->fdev->dev, "no memory for desc\n");
+		return NULL;
+	}
+
+	fdesc->iscyclic = true;
+
+	for (i = 0; i < sg_len; i++) {
+		struct st_fdma_hw_node *hw_node = fdesc->node[i].desc;
+
+		hw_node->next = fdesc->node[(i + 1) % sg_len].pdesc;
+
+		hw_node->control =
+			FDMA_NODE_CTRL_REQ_MAP_DREQ(fchan->dreq_line);
+		hw_node->control |= FDMA_NODE_CTRL_INT_EON;
+
+		fill_hw_node(hw_node, fchan, direction);
+
+		if (direction == DMA_MEM_TO_DEV)
+			hw_node->saddr = buf_addr + (i * period_len);
+		else
+			hw_node->daddr = buf_addr + (i * period_len);
+
+		hw_node->nbytes = period_len;
+		hw_node->generic.length = period_len;
+	}
+
+	return vchan_tx_prep(&fchan->vchan, &fdesc->vdesc, flags);
+}
+
+static struct dma_async_tx_descriptor *st_fdma_prep_slave_sg(
+		struct dma_chan *chan, struct scatterlist *sgl,
+		unsigned int sg_len, enum dma_transfer_direction direction,
+		unsigned long flags, void *context)
+{
+	struct st_fdma_chan *fchan;
+	struct st_fdma_desc *fdesc;
+	struct st_fdma_hw_node *hw_node;
+	struct scatterlist *sg;
+	int i;
+
+	fchan = st_fdma_prep_common(chan, sg_len, direction);
+	if (!fchan)
+		return NULL;
+
+	if (!sgl)
+		return NULL;
+
+	fdesc = st_fdma_alloc_desc(fchan, sg_len);
+	if (!fdesc) {
+		dev_err(fchan->fdev->dev, "no memory for desc\n");
+		return NULL;
+	}
+
+	fdesc->iscyclic = false;
+
+	for_each_sg(sgl, sg, sg_len, i) {
+		hw_node = fdesc->node[i].desc;
+
+		hw_node->next = fdesc->node[(i + 1) % sg_len].pdesc;
+		hw_node->control = FDMA_NODE_CTRL_REQ_MAP_DREQ(fchan->dreq_line);
+
+		fill_hw_node(hw_node, fchan, direction);
+
+		if (direction == DMA_MEM_TO_DEV)
+			hw_node->saddr = sg_dma_address(sg);
+		else
+			hw_node->daddr = sg_dma_address(sg);
+
+		hw_node->nbytes = sg_dma_len(sg);
+		hw_node->generic.length = sg_dma_len(sg);
+	}
+
+	/* interrupt at end of last node */
+	hw_node->control |= FDMA_NODE_CTRL_INT_EON;
+
+	return vchan_tx_prep(&fchan->vchan, &fdesc->vdesc, flags);
+}
+
+static size_t st_fdma_desc_residue(struct st_fdma_chan *fchan,
+				   struct virt_dma_desc *vdesc,
+				   bool in_progress)
+{
+	struct st_fdma_desc *fdesc = fchan->fdesc;
+	size_t residue = 0;
+	dma_addr_t cur_addr = 0;
+	int i;
+
+	if (in_progress) {
+		cur_addr = fchan_read(fchan, FDMA_CH_CMD_OFST);
+		cur_addr &= FDMA_CH_CMD_DATA_MASK;
+	}
+
+	for (i = fchan->fdesc->n_nodes - 1 ; i >= 0; i--) {
+		if (cur_addr == fdesc->node[i].pdesc) {
+			residue += fnode_read(fchan, FDMA_CNTN_OFST);
+			break;
+		}
+		residue += fdesc->node[i].desc->nbytes;
+	}
+
+	return residue;
+}
+
+static enum dma_status st_fdma_tx_status(struct dma_chan *chan,
+					 dma_cookie_t cookie,
+					 struct dma_tx_state *txstate)
+{
+	struct st_fdma_chan *fchan = to_st_fdma_chan(chan);
+	struct virt_dma_desc *vd;
+	enum dma_status ret;
+	unsigned long flags;
+
+	ret = dma_cookie_status(chan, cookie, txstate);
+	if (ret == DMA_COMPLETE || !txstate)
+		return ret;
+
+	spin_lock_irqsave(&fchan->vchan.lock, flags);
+	vd = vchan_find_desc(&fchan->vchan, cookie);
+	if (fchan->fdesc && cookie == fchan->fdesc->vdesc.tx.cookie)
+		txstate->residue = st_fdma_desc_residue(fchan, vd, true);
+	else if (vd)
+		txstate->residue = st_fdma_desc_residue(fchan, vd, false);
+	else
+		txstate->residue = 0;
+
+	spin_unlock_irqrestore(&fchan->vchan.lock, flags);
+
+	return ret;
+}
+
+static void st_fdma_issue_pending(struct dma_chan *chan)
+{
+	struct st_fdma_chan *fchan = to_st_fdma_chan(chan);
+	unsigned long flags;
+
+	spin_lock_irqsave(&fchan->vchan.lock, flags);
+
+	if (vchan_issue_pending(&fchan->vchan) && !fchan->fdesc)
+		st_fdma_xfer_desc(fchan);
+
+	spin_unlock_irqrestore(&fchan->vchan.lock, flags);
+}
+
+static int st_fdma_pause(struct dma_chan *chan)
+{
+	unsigned long flags;
+	LIST_HEAD(head);
+	struct st_fdma_chan *fchan = to_st_fdma_chan(chan);
+	int ch_id = fchan->vchan.chan.chan_id;
+	unsigned long cmd = FDMA_CMD_PAUSE(ch_id);
+
+	dev_dbg(fchan->fdev->dev, "pause chan:%d\n", ch_id);
+
+	spin_lock_irqsave(&fchan->vchan.lock, flags);
+	if (fchan->fdesc)
+		fdma_write(fchan->fdev, cmd, FDMA_CMD_SET_OFST);
+	spin_unlock_irqrestore(&fchan->vchan.lock, flags);
+
+	return 0;
+}
+
+static int st_fdma_resume(struct dma_chan *chan)
+{
+	unsigned long flags;
+	unsigned long val;
+	struct st_fdma_chan *fchan = to_st_fdma_chan(chan);
+	int ch_id = fchan->vchan.chan.chan_id;
+
+	dev_dbg(fchan->fdev->dev, "resume chan:%d\n", ch_id);
+
+	spin_lock_irqsave(&fchan->vchan.lock, flags);
+	if (fchan->fdesc) {
+		val = fchan_read(fchan, FDMA_CH_CMD_OFST);
+		val &= FDMA_CH_CMD_DATA_MASK;
+		fchan_write(fchan, val, FDMA_CH_CMD_OFST);
+	}
+	spin_unlock_irqrestore(&fchan->vchan.lock, flags);
+
+	return 0;
+}
+
+static int st_fdma_terminate_all(struct dma_chan *chan)
+{
+	unsigned long flags;
+	LIST_HEAD(head);
+	struct st_fdma_chan *fchan = to_st_fdma_chan(chan);
+	int ch_id = fchan->vchan.chan.chan_id;
+	unsigned long cmd = FDMA_CMD_PAUSE(ch_id);
+
+	dev_dbg(fchan->fdev->dev, "terminate chan:%d\n", ch_id);
+
+	spin_lock_irqsave(&fchan->vchan.lock, flags);
+	fdma_write(fchan->fdev, cmd, FDMA_CMD_SET_OFST);
+	fchan->fdesc = NULL;
+	vchan_get_all_descriptors(&fchan->vchan, &head);
+	spin_unlock_irqrestore(&fchan->vchan.lock, flags);
+	vchan_dma_desc_free_list(&fchan->vchan, &head);
+
+	return 0;
+}
+
+static int st_fdma_slave_config(struct dma_chan *chan,
+				struct dma_slave_config *slave_cfg)
+{
+	struct st_fdma_chan *fchan = to_st_fdma_chan(chan);
+
+	memcpy(&fchan->scfg, slave_cfg, sizeof(fchan->scfg));
+	return 0;
+}
+
+static const struct st_fdma_driverdata fdma_mpe31_stih407_11 = {
+	.name = "STiH407",
+	.id = 0,
+};
+
+static const struct st_fdma_driverdata fdma_mpe31_stih407_12 = {
+	.name = "STiH407",
+	.id = 1,
+};
+
+static const struct st_fdma_driverdata fdma_mpe31_stih407_13 = {
+	.name = "STiH407",
+	.id = 2,
+};
+
+static const struct of_device_id st_fdma_match[] = {
+	{ .compatible = "st,stih407-fdma-mpe31-11"
+	  , .data = &fdma_mpe31_stih407_11 },
+	{ .compatible = "st,stih407-fdma-mpe31-12"
+	  , .data = &fdma_mpe31_stih407_12 },
+	{ .compatible = "st,stih407-fdma-mpe31-13"
+	  , .data = &fdma_mpe31_stih407_13 },
+	{},
+};
+MODULE_DEVICE_TABLE(of, st_fdma_match);
+
+static int st_fdma_parse_dt(struct platform_device *pdev,
+			const struct st_fdma_driverdata *drvdata,
+			struct st_fdma_dev *fdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	int ret;
+
+	if (!np)
+		goto err;
+
+	ret = of_property_read_u32(np, "dma-channels", &fdev->nr_channels);
+	if (ret)
+		goto err;
+
+	snprintf(fdev->fw_name, FW_NAME_SIZE, "fdma_%s_%d.elf",
+		drvdata->name, drvdata->id);
+
+err:
+	return ret;
+}
+#define FDMA_DMA_BUSWIDTHS	(BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
+				 BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
+				 BIT(DMA_SLAVE_BUSWIDTH_3_BYTES) | \
+				 BIT(DMA_SLAVE_BUSWIDTH_4_BYTES))
+
+static void st_fdma_free(struct st_fdma_dev *fdev)
+{
+	struct st_fdma_chan *fchan;
+	int i;
+
+	for (i = 0; i < fdev->nr_channels; i++) {
+		fchan = &fdev->chans[i];
+		list_del(&fchan->vchan.chan.device_node);
+		tasklet_kill(&fchan->vchan.task);
+	}
+}
+
+static int st_fdma_probe(struct platform_device *pdev)
+{
+	struct st_fdma_dev *fdev;
+	const struct of_device_id *match;
+	struct device_node *np = pdev->dev.of_node;
+	const struct st_fdma_driverdata *drvdata;
+	int ret, i;
+
+	match = of_match_device((st_fdma_match), &pdev->dev);
+	if (!match || !match->data) {
+		dev_err(&pdev->dev, "No device match found\n");
+		return -ENODEV;
+	}
+
+	drvdata = match->data;
+
+	fdev = devm_kzalloc(&pdev->dev, sizeof(*fdev), GFP_KERNEL);
+	if (!fdev)
+		return -ENOMEM;
+
+	ret = st_fdma_parse_dt(pdev, drvdata, fdev);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to find platform data\n");
+		goto err;
+	}
+
+	fdev->chans = devm_kcalloc(&pdev->dev, fdev->nr_channels,
+				   sizeof(struct st_fdma_chan), GFP_KERNEL);
+	if (!fdev->chans)
+		return -ENOMEM;
+
+	fdev->dev = &pdev->dev;
+	fdev->drvdata = drvdata;
+	platform_set_drvdata(pdev, fdev);
+
+	fdev->irq = platform_get_irq(pdev, 0);
+	if (fdev->irq < 0) {
+		dev_err(&pdev->dev, "Failed to get irq resource\n");
+		return -EINVAL;
+	}
+
+	ret = devm_request_irq(&pdev->dev, fdev->irq, st_fdma_irq_handler, 0,
+			       dev_name(&pdev->dev), fdev);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to request irq (%d)\n", ret);
+		goto err;
+	}
+
+	fdev->slim_rproc = st_slim_rproc_alloc(pdev, fdev->fw_name);
+	if (!fdev->slim_rproc) {
+		ret = PTR_ERR(fdev->slim_rproc);
+		dev_err(&pdev->dev, "slim_rproc_alloc failed (%d)\n", ret);
+		goto err;
+	}
+
+	/* Initialise list of FDMA channels */
+	INIT_LIST_HEAD(&fdev->dma_device.channels);
+	for (i = 0; i < fdev->nr_channels; i++) {
+		struct st_fdma_chan *fchan = &fdev->chans[i];
+
+		fchan->fdev = fdev;
+		fchan->vchan.desc_free = st_fdma_free_desc;
+		vchan_init(&fchan->vchan, &fdev->dma_device);
+	}
+
+	/* Initialise the FDMA dreq (reserve 0 & 31 for FDMA use) */
+	fdev->dreq_mask = BIT(0) | BIT(31);
+
+	dma_cap_set(DMA_SLAVE, fdev->dma_device.cap_mask);
+	dma_cap_set(DMA_CYCLIC, fdev->dma_device.cap_mask);
+	dma_cap_set(DMA_MEMCPY, fdev->dma_device.cap_mask);
+
+	fdev->dma_device.dev = &pdev->dev;
+	fdev->dma_device.device_alloc_chan_resources = st_fdma_alloc_chan_res;
+	fdev->dma_device.device_free_chan_resources = st_fdma_free_chan_res;
+	fdev->dma_device.device_prep_dma_cyclic	= st_fdma_prep_dma_cyclic;
+	fdev->dma_device.device_prep_slave_sg = st_fdma_prep_slave_sg;
+	fdev->dma_device.device_prep_dma_memcpy = st_fdma_prep_dma_memcpy;
+	fdev->dma_device.device_tx_status = st_fdma_tx_status;
+	fdev->dma_device.device_issue_pending = st_fdma_issue_pending;
+	fdev->dma_device.device_terminate_all = st_fdma_terminate_all;
+	fdev->dma_device.device_config = st_fdma_slave_config;
+	fdev->dma_device.device_pause = st_fdma_pause;
+	fdev->dma_device.device_resume = st_fdma_resume;
+
+	fdev->dma_device.src_addr_widths = FDMA_DMA_BUSWIDTHS;
+	fdev->dma_device.dst_addr_widths = FDMA_DMA_BUSWIDTHS;
+	fdev->dma_device.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+	fdev->dma_device.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
+
+	ret = dma_async_device_register(&fdev->dma_device);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"Failed to register DMA device (%d)\n", ret);
+		goto err_rproc;
+	}
+
+	ret = of_dma_controller_register(np, st_fdma_of_xlate, fdev);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"Failed to register controller (%d)\n", ret);
+		goto err_dma_dev;
+	}
+
+	dev_info(&pdev->dev, "ST FDMA engine driver, irq:%d\n", fdev->irq);
+
+	return 0;
+
+err_dma_dev:
+	dma_async_device_unregister(&fdev->dma_device);
+err_rproc:
+	st_fdma_free(fdev);
+	st_slim_rproc_put(fdev->slim_rproc);
+err:
+	return ret;
+}
+
+static int st_fdma_remove(struct platform_device *pdev)
+{
+	struct st_fdma_dev *fdev = platform_get_drvdata(pdev);
+
+	devm_free_irq(&pdev->dev, fdev->irq, fdev);
+	st_slim_rproc_put(fdev->slim_rproc);
+	of_dma_controller_free(pdev->dev.of_node);
+	dma_async_device_unregister(&fdev->dma_device);
+
+	return 0;
+}
+
+static struct platform_driver st_fdma_platform_driver = {
+	.driver = {
+		.name = DRIVER_NAME,
+		.of_match_table = st_fdma_match,
+	},
+	.probe = st_fdma_probe,
+	.remove = st_fdma_remove,
+};
+module_platform_driver(st_fdma_platform_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("STMicroelectronics FDMA engine driver");
+MODULE_AUTHOR("Ludovic.barre <Ludovic.barre@st.com>");
+MODULE_AUTHOR("Peter Griffin <peter.griffin@linaro.org>");
+MODULE_ALIAS("platform: " DRIVER_NAME);
-- 
2.7.4

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox