[linux-sunxi] Re: [PATCH v3 01/13] pinctrl: sunxi: Add A83T R_PIO controller support

2016-03-08 Thread Linus Walleij
On Sat, Mar 5, 2016 at 10:42 PM, Vishnu Patekar
 wrote:

> The A83T has R_PIO pin controller, it's same as A23, execpt A83T
> interrupt bit is 6th and A83T has one extra pin PL12.
>
> Signed-off-by: Vishnu Patekar 
> Acked-by: Chen-Yu Tsai 
> Acked-by: Rob Herring 

As partly noted by others:

> +config PINCTRL_SUN8I_A83T_R
> +   def_bool MACH_SUN8I

bool

> +   depends on RESET_CONTROLLER

Should it rather select RESET_CONTROLLER?

> +static const struct of_device_id sun8i_a83t_r_pinctrl_match[] = {
> +   { .compatible = "allwinner,sun8i-a83t-r-pinctrl", },
> +   {}
> +};
> +MODULE_DEVICE_TABLE(of, sun8i_a83t_r_pinctrl_match);

Module talk in bool driver.

> +static struct platform_driver sun8i_a83t_r_pinctrl_driver = {
> +   .probe  = sun8i_a83t_r_pinctrl_probe,
> +   .driver = {
> +   .name   = "sun8i-a83t-r-pinctrl",
> +   .of_match_table = sun8i_a83t_r_pinctrl_match,
> +   },
> +};
> +module_platform_driver(sun8i_a83t_r_pinctrl_driver);

Should be builtin?

Yours,
Linus Walleij

-- 
You received this message because you are subscribed to the Google Groups 
"linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to linux-sunxi+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[linux-sunxi] Re: [PATCH 4/7] scatterlist: add sg_alloc_table_from_buf() helper

2016-03-08 Thread Boris Brezillon
Hi Laurent,

On Tue, 08 Mar 2016 18:51:49 +0200
Laurent Pinchart  wrote:

> Hi Boris,
> 
> Thank you for the patch.
> 
> On Tuesday 08 March 2016 12:15:12 Boris Brezillon wrote:
> > sg_alloc_table_from_buf() provides an easy solution to create an sg_table
> > from a virtual address pointer. This function takes care of dealing with
> > vmallocated buffers, buffer alignment, or DMA engine limitations (maximum
> > DMA transfer size).
> > 
> > Signed-off-by: Boris Brezillon 
> > ---
> >  include/linux/scatterlist.h |  24 
> >  lib/scatterlist.c   | 142 +
> >  2 files changed, 166 insertions(+)
> > 
> > diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h
> > index 556ec1e..4a75362 100644
> > --- a/include/linux/scatterlist.h
> > +++ b/include/linux/scatterlist.h
> > @@ -41,6 +41,27 @@ struct sg_table {
> > unsigned int orig_nents;/* original size of list */
> >  };
> > 
> > +/**
> > + * struct sg_constraints - SG constraints structure
> > + *
> > + * @max_chunk_len: maximum chunk buffer length. Each SG entry has to be
> > smaller
> > + *than this value. Zero means no constraint.
> > + * @required_alignment: minimum alignment. Is used for both size and
> > pointer
> > + * alignment. If this constraint is not met, the function
> > + * should return -EINVAL.
> > + * @preferred_alignment: preferred alignment. Mainly used to optimize
> > + *  throughput when the DMA engine performs better when
> > + *  doing aligned accesses.
> > + *
> > + * This structure is here to help sg_alloc_table_from_buf() create the
> > optimal
> > + * SG list based on DMA engine constraints.
> > + */
> > +struct sg_constraints {
> > +   size_t max_chunk_len;
> > +   size_t required_alignment;
> > +   size_t preferred_alignment;
> > +};
> > +
> >  /*
> >   * Notes on SG table design.
> >   *
> > @@ -265,6 +286,9 @@ int sg_alloc_table_from_pages(struct sg_table *sgt,
> > struct page **pages, unsigned int n_pages,
> > unsigned long offset, unsigned long size,
> > gfp_t gfp_mask);
> > +int sg_alloc_table_from_buf(struct sg_table *sgt, const void *buf, size_t
> > len,
> > +   const struct sg_constraints *constraints,
> > +   gfp_t gfp_mask);
> > 
> >  size_t sg_copy_buffer(struct scatterlist *sgl, unsigned int nents, void
> > *buf, size_t buflen, off_t skip, bool to_buffer);
> > diff --git a/lib/scatterlist.c b/lib/scatterlist.c
> > index bafa993..706b583 100644
> > --- a/lib/scatterlist.c
> > +++ b/lib/scatterlist.c
> > @@ -433,6 +433,148 @@ int sg_alloc_table_from_pages(struct sg_table *sgt,
> >  }
> >  EXPORT_SYMBOL(sg_alloc_table_from_pages);
> > 
> > +static size_t sg_buf_chunk_len(const void *buf, size_t len,
> > +  const struct sg_constraints *cons)
> > +{
> > +   size_t chunk_len = len;
> > +
> > +   if (cons->max_chunk_len)
> > +   chunk_len = min_t(size_t, chunk_len, cons->max_chunk_len);
> > +
> > +   if (is_vmalloc_addr(buf))
> > +   chunk_len = min_t(size_t, chunk_len,
> > + PAGE_SIZE - offset_in_page(buf));
> 
> This will lead to page-sized scatter-gather entries even for pages of the 
> vmalloc memory that happen to be physically contiguous. That works, but I 
> wonder whether we'd want to be more efficient.

Hm, I thought dma_map_sg() was taking care of merging pĥysically
contiguous memory regions, but maybe I'm wrong. Anyway, that's
definitely something I can add at this level.

> 
> > +   if (!IS_ALIGNED((unsigned long)buf, cons->preferred_alignment)) {
> > +   const void *aligned_buf = PTR_ALIGN(buf,
> > +   cons->preferred_alignment);
> > +   size_t unaligned_len = (unsigned long)(aligned_buf - buf);
> > +
> > +   chunk_len = min_t(size_t, chunk_len, unaligned_len);
> > +   } else if (chunk_len > cons->preferred_alignment) {
> > +   chunk_len &= ~(cons->preferred_alignment - 1);
> > +   }
> > +
> > +   return chunk_len;
> > +}
> > +
> > +#define sg_for_each_chunk_in_buf(buf, len, chunk_len, constraints) \
> > +   for (chunk_len = sg_buf_chunk_len(buf, len, constraints);   \
> > +len;   \
> > +len -= chunk_len, buf += chunk_len,\
> > +chunk_len = sg_buf_chunk_len(buf, len, constraints))
> > +
> > +static int sg_check_constraints(struct sg_constraints *cons,
> > +   const void *buf, size_t len)
> > +{
> > +   if (!cons->required_alignment)
> > +   cons->required_alignment = 1;
> > +
> > +   if (!cons->preferred_alignment)
> > +   cons->preferred_alignment = cons->required_alignment;
> > +
> > +   /* Test if buf and len are properly aligned. */
> > +   if (!IS_ALIGNED((unsigned long)buf, cons->required_alignment) ||
> > +   !IS_AL

[linux-sunxi] Re: [PATCH 4/7] scatterlist: add sg_alloc_table_from_buf() helper

2016-03-08 Thread Laurent Pinchart
Hi Boris,

Thank you for the patch.

On Tuesday 08 March 2016 12:15:12 Boris Brezillon wrote:
> sg_alloc_table_from_buf() provides an easy solution to create an sg_table
> from a virtual address pointer. This function takes care of dealing with
> vmallocated buffers, buffer alignment, or DMA engine limitations (maximum
> DMA transfer size).
> 
> Signed-off-by: Boris Brezillon 
> ---
>  include/linux/scatterlist.h |  24 
>  lib/scatterlist.c   | 142 +
>  2 files changed, 166 insertions(+)
> 
> diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h
> index 556ec1e..4a75362 100644
> --- a/include/linux/scatterlist.h
> +++ b/include/linux/scatterlist.h
> @@ -41,6 +41,27 @@ struct sg_table {
>   unsigned int orig_nents;/* original size of list */
>  };
> 
> +/**
> + * struct sg_constraints - SG constraints structure
> + *
> + * @max_chunk_len: maximum chunk buffer length. Each SG entry has to be
> smaller
> + *  than this value. Zero means no constraint.
> + * @required_alignment: minimum alignment. Is used for both size and
> pointer
> + *   alignment. If this constraint is not met, the function
> + *   should return -EINVAL.
> + * @preferred_alignment: preferred alignment. Mainly used to optimize
> + *throughput when the DMA engine performs better when
> + *doing aligned accesses.
> + *
> + * This structure is here to help sg_alloc_table_from_buf() create the
> optimal
> + * SG list based on DMA engine constraints.
> + */
> +struct sg_constraints {
> + size_t max_chunk_len;
> + size_t required_alignment;
> + size_t preferred_alignment;
> +};
> +
>  /*
>   * Notes on SG table design.
>   *
> @@ -265,6 +286,9 @@ int sg_alloc_table_from_pages(struct sg_table *sgt,
>   struct page **pages, unsigned int n_pages,
>   unsigned long offset, unsigned long size,
>   gfp_t gfp_mask);
> +int sg_alloc_table_from_buf(struct sg_table *sgt, const void *buf, size_t
> len,
> + const struct sg_constraints *constraints,
> + gfp_t gfp_mask);
> 
>  size_t sg_copy_buffer(struct scatterlist *sgl, unsigned int nents, void
> *buf, size_t buflen, off_t skip, bool to_buffer);
> diff --git a/lib/scatterlist.c b/lib/scatterlist.c
> index bafa993..706b583 100644
> --- a/lib/scatterlist.c
> +++ b/lib/scatterlist.c
> @@ -433,6 +433,148 @@ int sg_alloc_table_from_pages(struct sg_table *sgt,
>  }
>  EXPORT_SYMBOL(sg_alloc_table_from_pages);
> 
> +static size_t sg_buf_chunk_len(const void *buf, size_t len,
> +const struct sg_constraints *cons)
> +{
> + size_t chunk_len = len;
> +
> + if (cons->max_chunk_len)
> + chunk_len = min_t(size_t, chunk_len, cons->max_chunk_len);
> +
> + if (is_vmalloc_addr(buf))
> + chunk_len = min_t(size_t, chunk_len,
> +   PAGE_SIZE - offset_in_page(buf));

This will lead to page-sized scatter-gather entries even for pages of the 
vmalloc memory that happen to be physically contiguous. That works, but I 
wonder whether we'd want to be more efficient.

> + if (!IS_ALIGNED((unsigned long)buf, cons->preferred_alignment)) {
> + const void *aligned_buf = PTR_ALIGN(buf,
> + cons->preferred_alignment);
> + size_t unaligned_len = (unsigned long)(aligned_buf - buf);
> +
> + chunk_len = min_t(size_t, chunk_len, unaligned_len);
> + } else if (chunk_len > cons->preferred_alignment) {
> + chunk_len &= ~(cons->preferred_alignment - 1);
> + }
> +
> + return chunk_len;
> +}
> +
> +#define sg_for_each_chunk_in_buf(buf, len, chunk_len, constraints)   \
> + for (chunk_len = sg_buf_chunk_len(buf, len, constraints);   \
> +  len;   \
> +  len -= chunk_len, buf += chunk_len,\
> +  chunk_len = sg_buf_chunk_len(buf, len, constraints))
> +
> +static int sg_check_constraints(struct sg_constraints *cons,
> + const void *buf, size_t len)
> +{
> + if (!cons->required_alignment)
> + cons->required_alignment = 1;
> +
> + if (!cons->preferred_alignment)
> + cons->preferred_alignment = cons->required_alignment;
> +
> + /* Test if buf and len are properly aligned. */
> + if (!IS_ALIGNED((unsigned long)buf, cons->required_alignment) ||
> + !IS_ALIGNED(len, cons->required_alignment))
> + return -EINVAL;
> +
> + /*
> +  * if the buffer has been vmallocated and required_alignment is
> +  * more than PAGE_SIZE we cannot guarantee it.
> +  */
> + if (is_vmalloc_addr(buf) && cons->required_alignment > PAGE_SIZE)
> + return -EINVAL;
> +
> + /*
> +  * max_chunk_len has to be aligned to require

[linux-sunxi] Re: [PATCH 02/16] mtd: nand: sunxi: fix clk rate calculation

2016-03-08 Thread Boris Brezillon
On Tue, 8 Mar 2016 15:58:03 +0100
Thomas Petazzoni  wrote:

> Boris,
> 
> On Mon,  7 Mar 2016 17:18:19 +0100, Boris Brezillon wrote:
> > Unlike what is specified in the Allwinner datasheets, the NAND clock rate
> > is not equal to 2/T but 1/T. Fix the clock rate selection accordingly.
> > 
> > Signed-off-by: Boris Brezillon 
> > ---
> >  drivers/mtd/nand/sunxi_nand.c | 8 +---
> >  1 file changed, 1 insertion(+), 7 deletions(-)
> > 
> > diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
> > index 4d01e65..ab66d8d 100644
> > --- a/drivers/mtd/nand/sunxi_nand.c
> > +++ b/drivers/mtd/nand/sunxi_nand.c
> > @@ -1208,13 +1208,7 @@ static int sunxi_nand_chip_set_timings(struct 
> > sunxi_nand_chip *chip,
> > /* Convert min_clk_period from picoseconds to nanoseconds */
> > min_clk_period = DIV_ROUND_UP(min_clk_period, 1000);
> >  
> > -   /*
> > -* Convert min_clk_period into a clk frequency, then get the
> > -* appropriate rate for the NAND controller IP given this formula
> > -* (specified in the datasheet):
> > -* nand clk_rate = 2 * min_clk_rate
> > -*/
> 
> When some HW works in a way that is *NOT* the one specified in the
> datasheet, I think you should rather add *more* comments about this
> aspect, rather than removing existing comments.

Fair enough (but you know how much I like documenting my code ;)). I'll
add a comment explaining why it differs from the datasheet
description :P.


-- 
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

-- 
You received this message because you are subscribed to the Google Groups 
"linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to linux-sunxi+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[linux-sunxi] Re: [PATCH 02/16] mtd: nand: sunxi: fix clk rate calculation

2016-03-08 Thread Thomas Petazzoni
Boris,

On Mon,  7 Mar 2016 17:18:19 +0100, Boris Brezillon wrote:
> Unlike what is specified in the Allwinner datasheets, the NAND clock rate
> is not equal to 2/T but 1/T. Fix the clock rate selection accordingly.
> 
> Signed-off-by: Boris Brezillon 
> ---
>  drivers/mtd/nand/sunxi_nand.c | 8 +---
>  1 file changed, 1 insertion(+), 7 deletions(-)
> 
> diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
> index 4d01e65..ab66d8d 100644
> --- a/drivers/mtd/nand/sunxi_nand.c
> +++ b/drivers/mtd/nand/sunxi_nand.c
> @@ -1208,13 +1208,7 @@ static int sunxi_nand_chip_set_timings(struct 
> sunxi_nand_chip *chip,
>   /* Convert min_clk_period from picoseconds to nanoseconds */
>   min_clk_period = DIV_ROUND_UP(min_clk_period, 1000);
>  
> - /*
> -  * Convert min_clk_period into a clk frequency, then get the
> -  * appropriate rate for the NAND controller IP given this formula
> -  * (specified in the datasheet):
> -  * nand clk_rate = 2 * min_clk_rate
> -  */

When some HW works in a way that is *NOT* the one specified in the
datasheet, I think you should rather add *more* comments about this
aspect, rather than removing existing comments.

Thomas
-- 
Thomas Petazzoni, CTO, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

-- 
You received this message because you are subscribed to the Google Groups 
"linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to linux-sunxi+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[linux-sunxi] Re: [PATCH 5/7] mtd: provide helper to prepare buffers for DMA operations

2016-03-08 Thread Boris Brezillon
On Tue, 8 Mar 2016 19:48:53 +0530
Vinod Koul  wrote:

> On Tue, Mar 08, 2016 at 12:15:13PM +0100, Boris Brezillon wrote:
> >  
> > +#ifdef CONFIG_HAS_DMA
> 
> Shouldn't this be CONFIG_DMA_ENGINE as you are preparing these descriptors
> for DMA transfer?
> 

Nope, scatterlist users are not necessarily using a dmaengine, some IPs
are directly embedding a dedicated DMA engine, which has no driver in
drivers/dma/.

-- 
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

-- 
You received this message because you are subscribed to the Google Groups 
"linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to linux-sunxi+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[linux-sunxi] Re: [PATCH] dma: sun4i: expose block size and wait cycle configuration to DMA users

2016-03-08 Thread Stefan Monnier
>>> Why does dmaengine need to wait? Can you explain that
[...]
> I see 2 possible reasons why waiting till checking for drq can help:

Any chance something similar is causing the "max 50MB/s" limit on SATA
transfers for A10/A20?


Stefan

-- 
You received this message because you are subscribed to the Google Groups 
"linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to linux-sunxi+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[linux-sunxi] Re: [PATCH 5/7] mtd: provide helper to prepare buffers for DMA operations

2016-03-08 Thread Vinod Koul
On Tue, Mar 08, 2016 at 12:15:13PM +0100, Boris Brezillon wrote:
>  
> +#ifdef CONFIG_HAS_DMA

Shouldn't this be CONFIG_DMA_ENGINE as you are preparing these descriptors
for DMA transfer?

-- 
~Vinod

-- 
You received this message because you are subscribed to the Google Groups 
"linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to linux-sunxi+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[linux-sunxi] [PATCH 0/7] mtd: nand: sunxi: add support for DMA operations

2016-03-08 Thread Boris Brezillon
Hello,

This patch series aims at adding support for DMA assisted operations to
the sunxi_nand driver.

The first 3 patches are just reworks in the existing driver preparing
things for DMA ->read/write_page() operations. Those ones are mainly
re-arranging existing functions, and moving some code into dedicated
functions so we can reuse them when adding the read/write_page()
implementation.

Patch 4 is an attempt to generalize some logic that are duplicated in a
lot of places. It provides a generic solution to create an SG table
from a buffer (passed by virtual address) and its length.
This generic implementation tries to take all possible constraints into
account, like:
- vmallocated buffers
- alignement requirement/preference
- maximum DMA transfer length

I may have missed other things (is there a need for a minimum DMA
transfer constraint?), so don't hesitate to point problems or missing
elements in this implementation.
Note that other subsystems doing the same kind of thing (like SPI of V4L)
could use this implementation. This is why I've put the SPI and V4L
maintainers in Cc.

Patch 5 is providing functions to map/unmap buffers for DMA operations
at the MTD level. This will hopefully limit the number of open-coded
implementations we're currently seeing in a lot of NAND drivers.
Of course, it's making use of sg_alloc_table_from_buf(), introduced in
patch 4.

Patch 6 and 7 are patching the sunxi NAND driver and its DT binding doc
to add DMA support.

I'm particularly interested in getting feedbacks on patch 4 and 5.
Is there a reason nobody ever tried to create such generic functions
(at the scatterlist and MTD levels), and if there are, could you detail
them?

Thanks,

Boris

Side note: patches touching the sunxi NAND driver are depending on
a series posted yesterday [1].

[1]https://lkml.org/lkml/2016/3/7/444

Boris Brezillon (7):
  mtd: nand: sunxi: move some ECC related operations to their own
functions
  mtd: nand: sunxi: make OOB retrieval optional
  mtd: nand: sunxi: make cur_off parameter optional in extra oob helpers
  scatterlist: add sg_alloc_table_from_buf() helper
  mtd: provide helper to prepare buffers for DMA operations
  mtd: nand: sunxi: add support for DMA assisted operations
  mtd: nand: sunxi: update DT bindings

 .../devicetree/bindings/mtd/sunxi-nand.txt |   4 +
 drivers/mtd/mtdcore.c  |  66 +++
 drivers/mtd/nand/sunxi_nand.c  | 483 ++---
 include/linux/mtd/mtd.h|  25 ++
 include/linux/scatterlist.h|  24 +
 lib/scatterlist.c  | 142 ++
 6 files changed, 679 insertions(+), 65 deletions(-)

-- 
2.1.4

-- 
You received this message because you are subscribed to the Google Groups 
"linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to linux-sunxi+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[linux-sunxi] [PATCH 4/7] scatterlist: add sg_alloc_table_from_buf() helper

2016-03-08 Thread Boris Brezillon
sg_alloc_table_from_buf() provides an easy solution to create an sg_table
from a virtual address pointer. This function takes care of dealing with
vmallocated buffers, buffer alignment, or DMA engine limitations (maximum
DMA transfer size).

Signed-off-by: Boris Brezillon 
---
 include/linux/scatterlist.h |  24 
 lib/scatterlist.c   | 142 
 2 files changed, 166 insertions(+)

diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h
index 556ec1e..4a75362 100644
--- a/include/linux/scatterlist.h
+++ b/include/linux/scatterlist.h
@@ -41,6 +41,27 @@ struct sg_table {
unsigned int orig_nents;/* original size of list */
 };
 
+/**
+ * struct sg_constraints - SG constraints structure
+ *
+ * @max_chunk_len: maximum chunk buffer length. Each SG entry has to be smaller
+ *than this value. Zero means no constraint.
+ * @required_alignment: minimum alignment. Is used for both size and pointer
+ * alignment. If this constraint is not met, the function
+ * should return -EINVAL.
+ * @preferred_alignment: preferred alignment. Mainly used to optimize
+ *  throughput when the DMA engine performs better when
+ *  doing aligned accesses.
+ *
+ * This structure is here to help sg_alloc_table_from_buf() create the optimal
+ * SG list based on DMA engine constraints.
+ */
+struct sg_constraints {
+   size_t max_chunk_len;
+   size_t required_alignment;
+   size_t preferred_alignment;
+};
+
 /*
  * Notes on SG table design.
  *
@@ -265,6 +286,9 @@ int sg_alloc_table_from_pages(struct sg_table *sgt,
struct page **pages, unsigned int n_pages,
unsigned long offset, unsigned long size,
gfp_t gfp_mask);
+int sg_alloc_table_from_buf(struct sg_table *sgt, const void *buf, size_t len,
+   const struct sg_constraints *constraints,
+   gfp_t gfp_mask);
 
 size_t sg_copy_buffer(struct scatterlist *sgl, unsigned int nents, void *buf,
  size_t buflen, off_t skip, bool to_buffer);
diff --git a/lib/scatterlist.c b/lib/scatterlist.c
index bafa993..706b583 100644
--- a/lib/scatterlist.c
+++ b/lib/scatterlist.c
@@ -433,6 +433,148 @@ int sg_alloc_table_from_pages(struct sg_table *sgt,
 }
 EXPORT_SYMBOL(sg_alloc_table_from_pages);
 
+static size_t sg_buf_chunk_len(const void *buf, size_t len,
+  const struct sg_constraints *cons)
+{
+   size_t chunk_len = len;
+
+   if (cons->max_chunk_len)
+   chunk_len = min_t(size_t, chunk_len, cons->max_chunk_len);
+
+   if (is_vmalloc_addr(buf))
+   chunk_len = min_t(size_t, chunk_len,
+ PAGE_SIZE - offset_in_page(buf));
+
+   if (!IS_ALIGNED((unsigned long)buf, cons->preferred_alignment)) {
+   const void *aligned_buf = PTR_ALIGN(buf,
+   cons->preferred_alignment);
+   size_t unaligned_len = (unsigned long)(aligned_buf - buf);
+
+   chunk_len = min_t(size_t, chunk_len, unaligned_len);
+   } else if (chunk_len > cons->preferred_alignment) {
+   chunk_len &= ~(cons->preferred_alignment - 1);
+   }
+
+   return chunk_len;
+}
+
+#define sg_for_each_chunk_in_buf(buf, len, chunk_len, constraints) \
+   for (chunk_len = sg_buf_chunk_len(buf, len, constraints);   \
+len;   \
+len -= chunk_len, buf += chunk_len,\
+chunk_len = sg_buf_chunk_len(buf, len, constraints))
+
+static int sg_check_constraints(struct sg_constraints *cons,
+   const void *buf, size_t len)
+{
+   if (!cons->required_alignment)
+   cons->required_alignment = 1;
+
+   if (!cons->preferred_alignment)
+   cons->preferred_alignment = cons->required_alignment;
+
+   /* Test if buf and len are properly aligned. */
+   if (!IS_ALIGNED((unsigned long)buf, cons->required_alignment) ||
+   !IS_ALIGNED(len, cons->required_alignment))
+   return -EINVAL;
+
+   /*
+* if the buffer has been vmallocated and required_alignment is
+* more than PAGE_SIZE we cannot guarantee it.
+*/
+   if (is_vmalloc_addr(buf) && cons->required_alignment > PAGE_SIZE)
+   return -EINVAL;
+
+   /*
+* max_chunk_len has to be aligned to required_alignment to
+* guarantee that all buffer chunks are aligned correctly.
+*/
+   if (!IS_ALIGNED(cons->max_chunk_len, cons->required_alignment))
+   return -EINVAL;
+
+   /*
+* preferred_alignment has to be aligned to required_alignment
+* to avoid misalignment of buffer chunks.
+*/
+   if (!IS_ALIGNED(cons->preferred_alignment,

[linux-sunxi] [PATCH 7/7] mtd: nand: sunxi: update DT bindings

2016-03-08 Thread Boris Brezillon
Document dmas and dma-names properties.

Signed-off-by: Boris Brezillon 
---
 Documentation/devicetree/bindings/mtd/sunxi-nand.txt | 4 
 1 file changed, 4 insertions(+)

diff --git a/Documentation/devicetree/bindings/mtd/sunxi-nand.txt 
b/Documentation/devicetree/bindings/mtd/sunxi-nand.txt
index 086d6f4..6fdf8f6 100644
--- a/Documentation/devicetree/bindings/mtd/sunxi-nand.txt
+++ b/Documentation/devicetree/bindings/mtd/sunxi-nand.txt
@@ -11,6 +11,10 @@ Required properties:
 * "ahb" : AHB gating clock
 * "mod" : nand controller clock
 
+Optional properties:
+- dmas : shall reference DMA channel associated to the NAND controller.
+- dma-names : shall be "rxtx".
+
 Optional children nodes:
 Children nodes represent the available nand chips.
 
-- 
2.1.4

-- 
You received this message because you are subscribed to the Google Groups 
"linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to linux-sunxi+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[linux-sunxi] [PATCH 3/7] mtd: nand: sunxi: make cur_off parameter optional in extra oob helpers

2016-03-08 Thread Boris Brezillon
Allow for NULL cur_offs values when the caller does not know where the
NAND page register pointer point to.

Signed-off-by: Boris Brezillon 
---
 drivers/mtd/nand/sunxi_nand.c | 10 ++
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index 7b3ae72..07c3af7 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -957,7 +957,7 @@ static void sunxi_nfc_hw_ecc_read_extra_oob(struct mtd_info 
*mtd,
if (len <= 0)
return;
 
-   if (*cur_off != offset)
+   if (!cur_off || *cur_off != offset)
nand->cmdfunc(mtd, NAND_CMD_RNDOUT,
  offset + mtd->writesize, -1);
 
@@ -967,7 +967,8 @@ static void sunxi_nfc_hw_ecc_read_extra_oob(struct mtd_info 
*mtd,
sunxi_nfc_randomizer_read_buf(mtd, oob + offset, len,
  false, page);
 
-   *cur_off = mtd->oobsize + mtd->writesize;
+   if (cur_off)
+   *cur_off = mtd->oobsize + mtd->writesize;
 }
 
 static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd,
@@ -1022,13 +1023,14 @@ static void sunxi_nfc_hw_ecc_write_extra_oob(struct 
mtd_info *mtd,
if (len <= 0)
return;
 
-   if (*cur_off != offset)
+   if (!cur_off || *cur_off != offset)
nand->cmdfunc(mtd, NAND_CMD_RNDIN,
  offset + mtd->writesize, -1);
 
sunxi_nfc_randomizer_write_buf(mtd, oob + offset, len, false, page);
 
-   *cur_off = mtd->oobsize + mtd->writesize;
+   if (cur_off)
+   *cur_off = mtd->oobsize + mtd->writesize;
 }
 
 static int sunxi_nfc_hw_ecc_read_page(struct mtd_info *mtd,
-- 
2.1.4

-- 
You received this message because you are subscribed to the Google Groups 
"linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to linux-sunxi+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[linux-sunxi] [PATCH 6/7] mtd: nand: sunxi: add support for DMA assisted operations

2016-03-08 Thread Boris Brezillon
The sunxi NAND controller is able to pipeline ECC operations only when
operated in DMA mode, which improves a lot NAND throughput while keeping
CPU usage low.

Signed-off-by: Boris Brezillon 
---
 drivers/mtd/nand/sunxi_nand.c | 301 +-
 1 file changed, 297 insertions(+), 4 deletions(-)

diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index 07c3af7..7ba285e 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -277,6 +277,7 @@ struct sunxi_nfc {
unsigned long clk_rate;
struct list_head chips;
struct completion complete;
+   struct dma_chan *dmac;
 };
 
 static inline struct sunxi_nfc *to_sunxi_nfc(struct nand_hw_control *ctrl)
@@ -369,6 +370,68 @@ static int sunxi_nfc_rst(struct sunxi_nfc *nfc)
return ret;
 }
 
+static int sunxi_nfc_dma_op_prepare(struct mtd_info *mtd, const void *buf,
+   int chunksize, int nchunks,
+   enum dma_data_direction ddir,
+   struct sg_table *sgt)
+{
+   struct nand_chip *nand = mtd_to_nand(mtd);
+   struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+   struct dma_async_tx_descriptor *dmad;
+   enum dma_transfer_direction tdir;
+   dma_cookie_t dmat;
+   int ret;
+
+   if (ddir == DMA_FROM_DEVICE)
+   tdir = DMA_DEV_TO_MEM;
+   else
+   tdir = DMA_MEM_TO_DEV;
+
+   ret = mtd_map_buf(mtd, nfc->dev, sgt, buf, nchunks * chunksize,
+ NULL, ddir);
+   if (ret)
+   return ret;
+
+   dmad = dmaengine_prep_slave_sg(nfc->dmac, sgt->sgl, sgt->nents,
+  tdir, DMA_CTRL_ACK);
+   if (IS_ERR(dmad)) {
+   ret = PTR_ERR(dmad);
+   goto err_unmap_buf;
+   }
+
+   writel(readl(nfc->regs + NFC_REG_CTL) | NFC_RAM_METHOD,
+  nfc->regs + NFC_REG_CTL);
+   writel(nchunks, nfc->regs + NFC_REG_SECTOR_NUM);
+   writel(chunksize, nfc->regs + NFC_REG_CNT);
+   dmat = dmaengine_submit(dmad);
+
+   ret = dma_submit_error(dmat);
+   if (ret)
+   goto err_clr_dma_flag;
+
+   return 0;
+
+err_clr_dma_flag:
+   writel(readl(nfc->regs + NFC_REG_CTL) & ~NFC_RAM_METHOD,
+  nfc->regs + NFC_REG_CTL);
+
+err_unmap_buf:
+   mtd_unmap_buf(mtd, nfc->dev, sgt, ddir);
+   return ret;
+}
+
+static void sunxi_nfc_dma_op_cleanup(struct mtd_info *mtd,
+enum dma_data_direction ddir,
+struct sg_table *sgt)
+{
+   struct nand_chip *nand = mtd_to_nand(mtd);
+   struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+
+   mtd_unmap_buf(mtd, nfc->dev, sgt, ddir);
+   writel(readl(nfc->regs + NFC_REG_CTL) & ~NFC_RAM_METHOD,
+  nfc->regs + NFC_REG_CTL);
+}
+
 static int sunxi_nfc_dev_ready(struct mtd_info *mtd)
 {
struct nand_chip *nand = mtd_to_nand(mtd);
@@ -971,6 +1034,106 @@ static void sunxi_nfc_hw_ecc_read_extra_oob(struct 
mtd_info *mtd,
*cur_off = mtd->oobsize + mtd->writesize;
 }
 
+static int sunxi_nfc_hw_ecc_read_chunks_dma(struct mtd_info *mtd, uint8_t *buf,
+   int oob_required, int page,
+   int nchunks)
+{
+   struct nand_chip *nand = mtd_to_nand(mtd);
+   struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+   struct nand_ecc_ctrl *ecc = &nand->ecc;
+   unsigned int max_bitflips = 0;
+   int ret, i, raw_mode = 0;
+   struct sg_table sgt;
+
+   ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);
+   if (ret)
+   return ret;
+
+   ret = sunxi_nfc_dma_op_prepare(mtd, buf, ecc->size, nchunks,
+  DMA_FROM_DEVICE, &sgt);
+   if (ret)
+   return ret;
+
+   sunxi_nfc_hw_ecc_enable(mtd);
+   sunxi_nfc_randomizer_config(mtd, page, false);
+   sunxi_nfc_randomizer_enable(mtd);
+
+   writel((NAND_CMD_RNDOUTSTART << 16) | (NAND_CMD_RNDOUT << 8) |
+  NAND_CMD_READSTART, nfc->regs + NFC_REG_RCMD_SET);
+
+   dma_async_issue_pending(nfc->dmac);
+
+   writel(NFC_PAGE_OP | NFC_DATA_SWAP_METHOD | NFC_DATA_TRANS,
+  nfc->regs + NFC_REG_CMD);
+
+   ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, true, 0);
+   if (ret)
+   dmaengine_terminate_all(nfc->dmac);
+
+   sunxi_nfc_randomizer_disable(mtd);
+   sunxi_nfc_hw_ecc_disable(mtd);
+
+   sunxi_nfc_dma_op_cleanup(mtd, DMA_FROM_DEVICE, &sgt);
+
+   if (ret)
+   return ret;
+
+   for (i = 0; i < nchunks; i++) {
+   int data_off = i * ecc->size;
+   int oob_off = i * (ecc->bytes + 4);
+   u8 *data = buf + data_off;
+   u8 *oob = nand->oob_poi + oob_off;
+   bool randomi

[linux-sunxi] [PATCH 5/7] mtd: provide helper to prepare buffers for DMA operations

2016-03-08 Thread Boris Brezillon
Some NAND controller drivers are making use of DMA to transfer data from
the controller to the buffer passed by the MTD user.
Provide a generic mtd_map/unmap_buf() implementation to avoid open coded
(and sometime erroneous) implementations.

Signed-off-by: Boris Brezillon 
---
 drivers/mtd/mtdcore.c   | 66 +
 include/linux/mtd/mtd.h | 25 +++
 2 files changed, 91 insertions(+)

diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 3096251..3c368f0 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -1253,6 +1253,72 @@ void *mtd_kmalloc_up_to(const struct mtd_info *mtd, 
size_t *size)
 }
 EXPORT_SYMBOL_GPL(mtd_kmalloc_up_to);
 
+#ifdef CONFIG_HAS_DMA
+/**
+ * mtd_map_buf - create an SG table and prepare it for DMA operations
+ *
+ * @mtd: mtd device description object pointer
+ * @dev: device handling the DMA operation
+ * @buf: buf used to create the SG table
+ * @len: length of buf
+ * @constraints: optional constraints to take into account when creating
+ *  the SG table. Can be NULL if no specific constraints
+ *  are required.
+ * @dir: direction of the DMA operation
+ *
+ * This function should be used when an MTD driver wants to do DMA operations
+ * on a buffer passed by the MTD layer. This functions takes care of
+ * vmallocated buffer constraints, and return and sg_table that you can safely
+ * use.
+ */
+int mtd_map_buf(struct mtd_info *mtd, struct device *dev,
+   struct sg_table *sgt, const void *buf, size_t len,
+   const struct sg_constraints *constraints,
+   enum dma_data_direction dir)
+{
+   int ret;
+
+   ret = sg_alloc_table_from_buf(sgt, buf, len, constraints, GFP_KERNEL);
+   if (ret)
+   return ret;
+
+   ret = dma_map_sg(dev, sgt->sgl, sgt->nents, dir);
+   if (!ret)
+   ret = -ENOMEM;
+
+   if (ret < 0) {
+   sg_free_table(sgt);
+   return ret;
+   }
+
+   sgt->nents = ret;
+
+   return 0;
+}
+EXPORT_SYMBOL_GPL(mtd_map_buf);
+
+/**
+ * mtd_map_buf - unmap an SG table and release its resources
+ *
+ * @mtd: mtd device description object pointer
+ * @dev: device handling the DMA operation
+ * @sgt: SG table
+ * @dir: direction of the DMA operation
+ *
+ * This function unmaps a previously mapped SG table and release SG table
+ * resources. Should be called when your DMA operation is done.
+ */
+void mtd_unmap_buf(struct mtd_info *mtd, struct device *dev,
+  struct sg_table *sgt, enum dma_data_direction dir)
+{
+   if (sgt->orig_nents) {
+   dma_unmap_sg(dev, sgt->sgl, sgt->orig_nents, dir);
+   sg_free_table(sgt);
+   }
+}
+EXPORT_SYMBOL_GPL(mtd_unmap_buf);
+#endif /* !CONFIG_HAS_DMA */
+
 #ifdef CONFIG_PROC_FS
 
 /**/
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index cc84923..11c63f1 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -24,6 +24,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 
@@ -406,6 +407,30 @@ extern void register_mtd_user (struct mtd_notifier *new);
 extern int unregister_mtd_user (struct mtd_notifier *old);
 void *mtd_kmalloc_up_to(const struct mtd_info *mtd, size_t *size);
 
+#ifdef CONFIG_HAS_DMA
+int mtd_map_buf(struct mtd_info *mtd, struct device *dev,
+   struct sg_table *sgt, const void *buf, size_t len,
+   const struct sg_constraints *constraints,
+   enum dma_data_direction dir);
+void mtd_unmap_buf(struct mtd_info *mtd, struct device *dev,
+  struct sg_table *sgt, enum dma_data_direction dir);
+#else
+static inline int mtd_map_buf(struct mtd_info *mtd, struct device *dev,
+ struct sg_table *sgt, const void *buf,
+ size_t len,
+ const struct sg_constraints *constraints
+ enum dma_data_direction dir)
+{
+   return -ENOTSUPP;
+}
+
+static void mtd_unmap_buf(struct mtd_info *mtd, struct device *dev,
+ struct sg_table *sgt, enum dma_data_direction dir)
+{
+   return -ENOTSUPP;
+}
+#endif
+
 void mtd_erase_callback(struct erase_info *instr);
 
 static inline int mtd_is_bitflip(int err) {
-- 
2.1.4

-- 
You received this message because you are subscribed to the Google Groups 
"linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to linux-sunxi+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[linux-sunxi] [PATCH 2/7] mtd: nand: sunxi: make OOB retrieval optional

2016-03-08 Thread Boris Brezillon
sunxi_nfc_hw_ecc_read_chunk() always retrieves the ECC and protected free
bytes, no matter if the user really asked for it or not. This can take a
non negligible amount of time, especially on NAND chips exposing large OOB
areas (> 1KB). Make it optional.

Signed-off-by: Boris Brezillon 
---
 drivers/mtd/nand/sunxi_nand.c | 27 ---
 1 file changed, 16 insertions(+), 11 deletions(-)

diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index 90c121d..7b3ae72 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -869,7 +869,7 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
   u8 *oob, int oob_off,
   int *cur_off,
   unsigned int *max_bitflips,
-  bool bbm, int page)
+  bool bbm, bool oob_required, int page)
 {
struct nand_chip *nand = mtd_to_nand(mtd);
struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
@@ -901,7 +901,8 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
 
*cur_off = oob_off + ecc->bytes + 4;
 
-   ret = sunxi_nfc_hw_ecc_correct(mtd, data, oob, 0, &erased);
+   ret = sunxi_nfc_hw_ecc_correct(mtd, data, oob_required ? oob : NULL, 0,
+  &erased);
if (erased)
return 1;
 
@@ -929,12 +930,14 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info 
*mtd,
} else {
memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE, ecc->size);
 
-   nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1);
-   sunxi_nfc_randomizer_read_buf(mtd, oob, ecc->bytes + 4,
- true, page);
+   if (oob_required) {
+   nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1);
+   sunxi_nfc_randomizer_read_buf(mtd, oob, ecc->bytes + 4,
+ true, page);
 
-   sunxi_nfc_hw_ecc_get_prot_oob_bytes(mtd, oob, 0,
-   bbm, page);
+   sunxi_nfc_hw_ecc_get_prot_oob_bytes(mtd, oob, 0,
+   bbm, page);
+   }
}
 
sunxi_nfc_hw_ecc_update_stats(mtd, max_bitflips, ret);
@@ -1048,7 +1051,7 @@ static int sunxi_nfc_hw_ecc_read_page(struct mtd_info 
*mtd,
ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, oob,
  oob_off + mtd->writesize,
  &cur_off, &max_bitflips,
- !i, page);
+ !i, oob_required, page);
if (ret < 0)
return ret;
else if (ret)
@@ -1086,8 +1089,8 @@ static int sunxi_nfc_hw_ecc_read_subpage(struct mtd_info 
*mtd,
ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off,
  oob,
  oob_off + mtd->writesize,
- &cur_off, &max_bitflips,
- !i, page);
+ &cur_off, &max_bitflips, !i,
+ false, page);
if (ret < 0)
return ret;
}
@@ -1149,7 +1152,9 @@ static int sunxi_nfc_hw_syndrome_ecc_read_page(struct 
mtd_info *mtd,
 
ret = sunxi_nfc_hw_ecc_read_chunk(mtd, data, data_off, oob,
  oob_off, &cur_off,
- &max_bitflips, !i, page);
+ &max_bitflips, !i,
+ oob_required,
+ page);
if (ret < 0)
return ret;
else if (ret)
-- 
2.1.4

-- 
You received this message because you are subscribed to the Google Groups 
"linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to linux-sunxi+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[linux-sunxi] [PATCH 1/7] mtd: nand: sunxi: move some ECC related operations to their own functions

2016-03-08 Thread Boris Brezillon
In order to support DMA operations in a clean way we need to extract some
of the logic coded in sunxi_nfc_hw_ecc_read/write_page() into their own
function.

Signed-off-by: Boris Brezillon 
---
 drivers/mtd/nand/sunxi_nand.c | 163 --
 1 file changed, 108 insertions(+), 55 deletions(-)

diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index 0616f3b..90c121d 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -776,6 +776,94 @@ static inline void sunxi_nfc_user_data_to_buf(u32 
user_data, u8 *buf)
buf[3] = user_data >> 24;
 }
 
+static inline u32 sunxi_nfc_buf_to_user_data(const u8 *buf)
+{
+   return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
+}
+
+static void sunxi_nfc_hw_ecc_get_prot_oob_bytes(struct mtd_info *mtd, u8 *oob,
+   int step, bool bbm, int page)
+{
+   struct nand_chip *nand = mtd_to_nand(mtd);
+   struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+
+   sunxi_nfc_user_data_to_buf(readl(nfc->regs + NFC_REG_USER_DATA(step)),
+  oob);
+
+   /* De-randomize the Bad Block Marker. */
+   if (bbm && (nand->options & NAND_NEED_SCRAMBLING))
+   sunxi_nfc_randomize_bbm(mtd, page, oob);
+}
+
+static void sunxi_nfc_hw_ecc_set_prot_oob_bytes(struct mtd_info *mtd,
+   const u8 *oob, int step,
+   bool bbm, int page)
+{
+   struct nand_chip *nand = mtd_to_nand(mtd);
+   struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+   u8 user_data[4];
+
+   /* Randomize the Bad Block Marker. */
+   if (bbm && (nand->options & NAND_NEED_SCRAMBLING)) {
+   memcpy(user_data, oob, sizeof(user_data));
+   sunxi_nfc_randomize_bbm(mtd, page, user_data);
+   oob = user_data;
+   }
+
+   writel(sunxi_nfc_buf_to_user_data(oob),
+  nfc->regs + NFC_REG_USER_DATA(step));
+}
+
+static void sunxi_nfc_hw_ecc_update_stats(struct mtd_info *mtd,
+ unsigned int *max_bitflips, int ret)
+{
+   if (ret < 0) {
+   mtd->ecc_stats.failed++;
+   } else {
+   mtd->ecc_stats.corrected += ret;
+   *max_bitflips = max_t(unsigned int, *max_bitflips, ret);
+   }
+}
+
+static int sunxi_nfc_hw_ecc_correct(struct mtd_info *mtd, u8 *data, u8 *oob,
+   int step, bool *erased)
+{
+   struct nand_chip *nand = mtd_to_nand(mtd);
+   struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+   struct nand_ecc_ctrl *ecc = &nand->ecc;
+   u32 status, tmp;
+
+   *erased = false;
+
+   status = readl(nfc->regs + NFC_REG_ECC_ST);
+
+   if (status & NFC_ECC_ERR(step))
+   return -EBADMSG;
+
+   if (status & NFC_ECC_PAT_FOUND(step)) {
+   u8 pattern;
+
+   if (unlikely(!(readl(nfc->regs + NFC_REG_PAT_ID) & 0x1))) {
+   pattern = 0x0;
+   } else {
+   pattern = 0xff;
+   *erased = true;
+   }
+
+   if (data)
+   memset(data, pattern, ecc->size);
+
+   if (oob)
+   memset(oob, pattern, ecc->bytes + 4);
+
+   return 0;
+   }
+
+   tmp = readl(nfc->regs + NFC_REG_ECC_ERR_CNT(step));
+
+   return NFC_ECC_ERR_CNT(step, tmp);
+}
+
 static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
   u8 *data, int data_off,
   u8 *oob, int oob_off,
@@ -787,7 +875,7 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd,
struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
struct nand_ecc_ctrl *ecc = &nand->ecc;
int raw_mode = 0;
-   u32 status;
+   bool erased;
int ret;
 
if (*cur_off != data_off)
@@ -813,27 +901,11 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info 
*mtd,
 
*cur_off = oob_off + ecc->bytes + 4;
 
-   status = readl(nfc->regs + NFC_REG_ECC_ST);
-   if (status & NFC_ECC_PAT_FOUND(0)) {
-   u8 pattern = 0xff;
-
-   if (unlikely(!(readl(nfc->regs + NFC_REG_PAT_ID) & 0x1)))
-   pattern = 0x0;
-
-   memset(data, pattern, ecc->size);
-   memset(oob, pattern, ecc->bytes + 4);
-
+   ret = sunxi_nfc_hw_ecc_correct(mtd, data, oob, 0, &erased);
+   if (erased)
return 1;
-   }
-
-   ret = NFC_ECC_ERR_CNT(0, readl(nfc->regs + NFC_REG_ECC_ERR_CNT(0)));
-
-   memcpy_fromio(data, nfc->regs + NFC_RAM0_BASE, ecc->size);
 
-   nand->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_off, -1);
-   sunxi_nfc_randomizer_read_buf(mtd, oob, ecc->bytes + 4, true, page);
-
-   if (status & NFC_

Re: [linux-sunxi] Re: [PATCH v4 1/2] ehci-platform: Add support for controllers with multiple reset lines

2016-03-08 Thread Hans de Goede

Hi,

On 05-03-16 21:02, Greg Kroah-Hartman wrote:

On Fri, Mar 04, 2016 at 08:27:26AM +0100, Hans de Goede wrote:

Hi,

On 04-03-16 05:35, Greg Kroah-Hartman wrote:

On Sat, Feb 27, 2016 at 05:58:58PM +0100, Hans de Goede wrote:

From: Reinder de Haan 

At least the EHCI/OHCI found on the Allwinnner H3 SoC needs multiple
reset lines, the controller will not initialize while the reset for
its companion is still asserted, which means we need to de-assert
2 resets for the controller to work.

Signed-off-by: Reinder de Haan 
Signed-off-by: Hans de Goede 
Acked-by: Alan Stern 
Acked-by: Rob Herring 
---
Changes in v2:
-Use the new reset_control_[de]assert_shared reset-controller functions
Changes in v3:
-Adjust for changes to shared-reset reset-controller functions
Changes in v4:
-Fix Ugly continuation line


This breaks the build horribly :(

As does patch 2/2, ugh.


As said in the cover letter:

"These patches apply on top of the related
reset-controller patches which have just been merged here:

git://git.pengutronix.de/git/pza/linux.git reset/next"

I guess I should have done s/apply on top of/depend on/
in the above bit. These patches apply fine without those
changes, but indeed they will not build.


Then I can't take them, you know this :(


You may want to ask Philipp Zabel (added to the To: list)
to create a topic branch for this which you can merge into
your tree.


If you all want me to do that, fine, otherwise just resend them after
4.6-rc1 is out and the build will not break at that time.


Ok I will resend these after 4.6-rc1

Regards,

Hans

--
You received this message because you are subscribed to the Google Groups 
"linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to linux-sunxi+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [linux-sunxi] Re: [PATCH] dma: sun4i: expose block size and wait cycle configuration to DMA users

2016-03-08 Thread Vinod Koul
On Tue, Mar 08, 2016 at 09:42:31AM +0100, Hans de Goede wrote:
> 
> 
> I see 2 possible reasons why waiting till checking for drq can help:
> 
> 1) A lot of devices have an internal fifo hooked up to a single mmio data
> register which gets read using the general purpose dma-engine, it allows
> this fifo to fill, and thus do burst transfers
> (We've seen similar issues with the scanout engine for the display which
>  has its own dma engine, and doing larger transfers helps a lot).
> 
> 2) Physical memory on the sunxi SoCs is (often) divided into banks
> with a shared data / address bus doing bank-switches is expensive, so
> this wait cycles may introduce latency which allows a user of another
> bank to complete its RAM accesses before the dma engine forces a
> bank switch, which ends up avoiding a lot of (interleaved) bank switches
> while both try to access a different banj and thus waiting makes things
> (much) faster in the end (again a known problem with the display
> scanout engine).
> 
> 
> 
> Note the differences these kinda tweaks make can be quite dramatic,
> when using a 1920x1080p60 hdmi output on the A10 SoC with a 16 bit
> memory bus (real world worst case scenario), the memory bandwidth
> left for userspace processes (measured through memset) almost doubles
> from 48 MB/s to 85 MB/s, source:
> http://ssvb.github.io/2014/11/11/revisiting-fullhd-x11-desktop-performance-of-the-allwinner-a10.html
> 
> TL;DR: Waiting before starting DMA allows for doing larger burst
> transfers which ends up making things more efficient.
> 
> Given this, I really expect there to be other dma-engines which
> have some option to wait a bit before starting/unpausing a transfer
> instead of starting it as soon as (more) data is available, so I think
> this would make a good addition to dma_slave_config.

I tend to agree but before we do that I would like this hypothesis to be
confirmed :)

-- 
~Vinod

-- 
You received this message because you are subscribed to the Google Groups 
"linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to linux-sunxi+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[linux-sunxi] Re: [PATCH] dma: sun4i: expose block size and wait cycle configuration to DMA users

2016-03-08 Thread Vinod Koul
On Tue, Mar 08, 2016 at 09:46:25AM +0100, Boris Brezillon wrote:
> On Tue, 8 Mar 2016 08:51:31 +0100
> Maxime Ripard  wrote:
> 
> > On Tue, Mar 08, 2016 at 08:25:47AM +0530, Vinod Koul wrote:
> > > On Mon, Mar 07, 2016 at 09:30:24PM +0100, Maxime Ripard wrote:
> > > > On Mon, Mar 07, 2016 at 04:08:57PM +0100, Boris Brezillon wrote:
> > > > > Hi Vinod,
> > > > > 
> > > > > On Mon, 7 Mar 2016 20:24:29 +0530
> > > > > Vinod Koul  wrote:
> > > > > 
> > > > > > On Mon, Mar 07, 2016 at 10:59:31AM +0100, Boris Brezillon wrote:
> > > > > > > +/* Dedicated DMA parameter register layout */
> > > > > > > +#define SUN4I_DDMA_PARA_DST_DATA_BLK_SIZE(n) (((n) - 1) << 
> > > > > > > 24)
> > > > > > > +#define SUN4I_DDMA_PARA_DST_WAIT_CYCLES(n)   (((n) - 1) << 
> > > > > > > 16)
> > > > > > > +#define SUN4I_DDMA_PARA_SRC_DATA_BLK_SIZE(n) (((n) - 1) << 8)
> > > > > > > +#define SUN4I_DDMA_PARA_SRC_WAIT_CYCLES(n)   (((n) - 1) << 0)
> > > > > > > +
> > > > > > > +/**
> > > > > > > + * struct sun4i_dma_chan_config - DMA channel config
> > > > > > > + *
> > > > > > > + * @para: contains information about block size and time before 
> > > > > > > checking
> > > > > > > + * DRQ line. This is device specific and only applicable 
> > > > > > > to dedicated
> > > > > > > + * DMA channels
> > > > > > 
> > > > > > What information, can you elobrate.. And why can't you use existing
> > > > > > dma_slave_config for this?
> > > > > 
> > > > > Block size is related to the device FIFO size. I guess it allows the
> > > > > DMA channel to launch a transfer of X bytes without having to check 
> > > > > the
> > > > > DRQ line (the line telling the DMA engine it can transfer more data
> > > > > to/from the device). The wait cycles information is apparently related
> > > > > to the number of clks the engine should wait before polling/checking
> > > > > the DRQ line status between each block transfer. I'm not sure what it
> > > > > saves to put WAIT_CYCLES() to something != 1, but in their BSP,
> > > > > Allwinner tweak that depending on the device.
> > > 
> > > we already have block size aka src/dst_maxburst, why not use that one.
> > 
> > I'm not sure it's really the same thing. The DMA controller also has a
> > burst parameter, that is either 1 byte or 8 bytes, and ends up being
> > different from this one.
> 
> Well, that's what I understood to, but when reading more carefully the
> src/dst_maxburst description, it seems to match the block_size concept
> exposed by the sun4i dmaengine. But how should we choose the real burst
> size then.

maxburst is block size as you describe in this context

> IIRC, in most documentation/datasheets, burst size is referred as the
> maximum number of words (word size depends on the selected width) a
> master is allowed to transfer to a slave through the bus without
> being interrupted by other master requests.
> Am I correct?

maxburst is defined as words not bytes. Word is specfied with the
src/dst_addr_width.

> 
> > 
> > > Why does dmaengine need to wait? Can you explain that
> > 
> > We have no idea, we thought you might have one :)
> 
> Yes, it's really unclear to us why this is needed. There might be some
> kind of contention, or maybe the slave device takes some time to put
> DRQ line to low state, and without these wait_cycles the dmaengine
> would assume some data are still available in the FIFO while there's
> actually no more data to retrieve.
> 
> > 
> > It doesn't really makes sense to us, but it does have a significant
> > impact on the throughput.
> 
> I wouldn't say significant impact, but tweaking those parameters has
> some impact on the performances, and since it's not that complicated to
> implement, I thought it was worth a try, but maybe I'm wrong.

Can you guys check with HW folks and see why it is required, if that is a
possiblity!

-- 
~Vinod

-- 
You received this message because you are subscribed to the Google Groups 
"linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to linux-sunxi+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[linux-sunxi] Re: [PATCH] dma: sun4i: expose block size and wait cycle configuration to DMA users

2016-03-08 Thread Vinod Koul
On Tue, Mar 08, 2016 at 08:51:31AM +0100, Maxime Ripard wrote:
> > > > > > + * struct sun4i_dma_chan_config - DMA channel config
> > > > > > + *
> > > > > > + * @para: contains information about block size and time before 
> > > > > > checking
> > > > > > + *   DRQ line. This is device specific and only applicable to 
> > > > > > dedicated
> > > > > > + *   DMA channels
> > > > > 
> > > > > What information, can you elobrate.. And why can't you use existing
> > > > > dma_slave_config for this?
> > > > 
> > > > Block size is related to the device FIFO size. I guess it allows the
> > > > DMA channel to launch a transfer of X bytes without having to check the
> > > > DRQ line (the line telling the DMA engine it can transfer more data
> > > > to/from the device). The wait cycles information is apparently related
> > > > to the number of clks the engine should wait before polling/checking
> > > > the DRQ line status between each block transfer. I'm not sure what it
> > > > saves to put WAIT_CYCLES() to something != 1, but in their BSP,
> > > > Allwinner tweak that depending on the device.
> > 
> > we already have block size aka src/dst_maxburst, why not use that one.
> 
> I'm not sure it's really the same thing. The DMA controller also has a
> burst parameter, that is either 1 byte or 8 bytes, and ends up being
> different from this one.

Nope that is buswidth. maxburst is words which cna be sent to device FIFO.
> 
> > Why does dmaengine need to wait? Can you explain that
> 
> We have no idea, we thought you might have one :)

Well that is hardware dependent. From DMAengine API usage we dont ahve to
wait at all. We should submit next descriptor as soon as possible.

> It doesn't really makes sense to us, but it does have a significant
> impact on the throughput.

-- 
~Vinod

-- 
You received this message because you are subscribed to the Google Groups 
"linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to linux-sunxi+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


signature.asc
Description: Digital signature


[linux-sunxi] [PATCH v4] drivers: pinctrl: add driver for Allwinner A64 SoC

2016-03-08 Thread Andre Przywara
Based on the Allwinner A64 user manual and on the previous sunxi
pinctrl drivers this introduces the pin multiplex assignments for
the ARMv8 Allwinner A64 SoC.
Port A is apparently used for the fixed function DRAM controller, so
the ports start at B here (the manual mentions "n from 1 to 7", so
not starting at 0).

Signed-off-by: Andre Przywara 
Acked-by: Rob Herring 
Acked-by: Maxime Ripard 
---
Hi Linus,

as requested a rebased version of the driver, now based upon
pinctrl/devel.
I adjusted the PINCTRL_SUNXI symbol name in the Kconfig, which got
renamed lately, that should be fixed for the sun8i-h3-r driver as
well.
Also I dropped the arm64 Kconfig.platforms line as requested and
removed the no longer needed MODULE_DEVICE_TABLE entry.

Cheers,
Andre.

 .../bindings/pinctrl/allwinner,sunxi-pinctrl.txt   |   1 +
 drivers/pinctrl/sunxi/Kconfig  |   4 +
 drivers/pinctrl/sunxi/Makefile |   1 +
 drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c | 601 +
 4 files changed, 607 insertions(+)
 create mode 100644 drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c

diff --git 
a/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt 
b/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt
index 3e56b16..6961722 100644
--- a/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt
@@ -22,6 +22,7 @@ Required properties:
   "allwinner,sun8i-a83t-pinctrl"
   "allwinner,sun8i-h3-pinctrl"
   "allwinner,sun8i-h3-r-pinctrl"
+  "allwinner,sun50i-a64-pinctrl"
 
 - reg: Should contain the register physical address and length for the
   pin controller.
diff --git a/drivers/pinctrl/sunxi/Kconfig b/drivers/pinctrl/sunxi/Kconfig
index 1868b82..aaf075b 100644
--- a/drivers/pinctrl/sunxi/Kconfig
+++ b/drivers/pinctrl/sunxi/Kconfig
@@ -68,4 +68,8 @@ config PINCTRL_SUN9I_A80_R
depends on RESET_CONTROLLER
select PINCTRL_SUNXI
 
+config PINCTRL_SUN50I_A64
+   bool
+   select PINCTRL_SUNXI
+
 endif
diff --git a/drivers/pinctrl/sunxi/Makefile b/drivers/pinctrl/sunxi/Makefile
index f22de0e..2d8b64e 100644
--- a/drivers/pinctrl/sunxi/Makefile
+++ b/drivers/pinctrl/sunxi/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_PINCTRL_SUN7I_A20)   += 
pinctrl-sun7i-a20.o
 obj-$(CONFIG_PINCTRL_SUN8I_A23)+= pinctrl-sun8i-a23.o
 obj-$(CONFIG_PINCTRL_SUN8I_A23_R)  += pinctrl-sun8i-a23-r.o
 obj-$(CONFIG_PINCTRL_SUN8I_A33)+= pinctrl-sun8i-a33.o
+obj-$(CONFIG_PINCTRL_SUN50I_A64)   += pinctrl-sun50i-a64.o
 obj-$(CONFIG_PINCTRL_SUN8I_A83T)   += pinctrl-sun8i-a83t.o
 obj-$(CONFIG_PINCTRL_SUN8I_H3) += pinctrl-sun8i-h3.o
 obj-$(CONFIG_PINCTRL_SUN8I_H3_R)   += pinctrl-sun8i-h3-r.o
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c 
b/drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c
new file mode 100644
index 000..4f2a726
--- /dev/null
+++ b/drivers/pinctrl/sunxi/pinctrl-sun50i-a64.c
@@ -0,0 +1,601 @@
+/*
+ * Allwinner A64 SoCs pinctrl driver.
+ *
+ * Copyright (C) 2016 - ARM Ltd.
+ * Author: Andre Przywara 
+ *
+ * Based on pinctrl-sun7i-a20.c, which is:
+ * Copyright (C) 2014 Maxime Ripard 
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "pinctrl-sunxi.h"
+
+static const struct sunxi_desc_pin a64_pins[] = {
+   SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart2"), /* TX */
+ SUNXI_FUNCTION(0x4, "jtag"),  /* MS0 */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 0)),  /* EINT0 */
+   SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart2"), /* RX */
+ SUNXI_FUNCTION(0x4, "jtag"),  /* CK0 */
+ SUNXI_FUNCTION(0x5, "sim"),   /* VCCEN */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 1)),  /* EINT1 */
+   SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart2"), /* RTS */
+ SUNXI_FUNCTION(0x4, "jtag"),  /* DO0 */
+ SUNXI_FUNCTION(0x5, "sim"),   /* VPPEN */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 2)),  /* EINT2 */
+   SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart2"), /* CTS */
+ S

Re: [linux-sunxi] Re: [PATCH] dma: sun4i: expose block size and wait cycle configuration to DMA users

2016-03-08 Thread Priit Laes
On Tue, 2016-03-08 at 09:46 +0100, Boris Brezillon wrote:
> On Tue, 8 Mar 2016 08:51:31 +0100
> Maxime Ripard  wrote:
> 
> > On Tue, Mar 08, 2016 at 08:25:47AM +0530, Vinod Koul wrote:
> > > On Mon, Mar 07, 2016 at 09:30:24PM +0100, Maxime Ripard wrote:
> > > > On Mon, Mar 07, 2016 at 04:08:57PM +0100, Boris Brezillon
> > > > wrote:
> > > > > Hi Vinod,
> > > > > 
> > > > > On Mon, 7 Mar 2016 20:24:29 +0530
> > > > > Vinod Koul  wrote:
> > > > > 
> > > > > > On Mon, Mar 07, 2016 at 10:59:31AM +0100, Boris Brezillon
> > > > > > wrote:
> > > > > > > +/* Dedicated DMA parameter register layout */
> > > > > > > +#define SUN4I_DDMA_PARA_DST_DATA_BLK_SIZE(n) (((n
> > > > > > > ) - 1) << 24)
> > > > > > > +#define SUN4I_DDMA_PARA_DST_WAIT_CYCLES(n)   (((n) 
> > > > > > > - 1) << 16)
> > > > > > > +#define SUN4I_DDMA_PARA_SRC_DATA_BLK_SIZE(n) (((n
> > > > > > > ) - 1) << 8)
> > > > > > > +#define SUN4I_DDMA_PARA_SRC_WAIT_CYCLES(n)   (((n) 
> > > > > > > - 1) << 0)
> > > > > > > +
> > > > > > > +/**
> > > > > > > + * struct sun4i_dma_chan_config - DMA channel config
> > > > > > > + *
> > > > > > > + * @para: contains information about block size and time
> > > > > > > before checking
> > > > > > > + * DRQ line. This is device specific and only
> > > > > > > applicable to dedicated
> > > > > > > + * DMA channels
> > > > > > 
> > > > > > What information, can you elobrate.. And why can't you use
> > > > > > existing
> > > > > > dma_slave_config for this?
> > > > > 
> > > > > Block size is related to the device FIFO size. I guess it
> > > > > allows the
> > > > > DMA channel to launch a transfer of X bytes without having to
> > > > > check the
> > > > > DRQ line (the line telling the DMA engine it can transfer
> > > > > more data
> > > > > to/from the device). The wait cycles information is
> > > > > apparently related
> > > > > to the number of clks the engine should wait before
> > > > > polling/checking
> > > > > the DRQ line status between each block transfer. I'm not sure
> > > > > what it
> > > > > saves to put WAIT_CYCLES() to something != 1, but in their
> > > > > BSP,
> > > > > Allwinner tweak that depending on the device.
> > > 
> > > we already have block size aka src/dst_maxburst, why not use that
> > > one.
> > 
> > I'm not sure it's really the same thing. The DMA controller also
> > has a
> > burst parameter, that is either 1 byte or 8 bytes, and ends up
> > being
> > different from this one.
> 
> Well, that's what I understood to, but when reading more carefully
> the
> src/dst_maxburst description, it seems to match the block_size
> concept
> exposed by the sun4i dmaengine. But how should we choose the real
> burst
> size then.
> IIRC, in most documentation/datasheets, burst size is referred as the
> maximum number of words (word size depends on the selected width) a
> master is allowed to transfer to a slave through the bus without
> being interrupted by other master requests.
> Am I correct?
> 
> > 
> > > Why does dmaengine need to wait? Can you explain that
> > 
> > We have no idea, we thought you might have one :)
> 
> Yes, it's really unclear to us why this is needed. There might be
> some
> kind of contention, or maybe the slave device takes some time to put
> DRQ line to low state, and without these wait_cycles the dmaengine
> would assume some data are still available in the FIFO while there's
> actually no more data to retrieve.
> 
> > 
> > It doesn't really makes sense to us, but it does have a significant
> > impact on the throughput.
> 
> I wouldn't say significant impact, but tweaking those parameters has
> some impact on the performances, and since it's not that complicated
> to
> implement, I thought it was worth a try, but maybe I'm wrong.

Somewhat offtopic, but there was also another patchset a while ago for
sun4i SPI that removed the 64 byte limit for SPI transfers (although
this was DMA-less case) back then.

http://lists.infradead.org/pipermail/linux-arm-kernel/2014-March/241392
.html

(This patchset made it possible to use SPI-based small TFT displays via
fbtft, when I tested it some time ago).

As it currently stands, sun4i SPI is not using DMA and transfers are
limited to 64 bytes.

Päikest,
Priit ;)

-- 
You received this message because you are subscribed to the Google Groups 
"linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to linux-sunxi+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[linux-sunxi] Re: [PATCH 2/2] pinctrl: sunxi: Change mux setting on PI irq pins

2016-03-08 Thread Linus Walleij
On Mon, Feb 29, 2016 at 6:13 AM, Henry Paulissen  wrote:

> While I was testing irq's on the cubietruck I found a couple of
> not working irq pins. Further diving into the problem it opened
> up a mess called "manual".
>
> This so called manual (A20 user manual v1.3 dated 2014-10-10) says:
>
> Pin overview:
> Page 237:   EINT26 is on mux 5.
> Page 288:   EINT26 is on mux 6.
>
> The manual is so contradicting that further tests had to be made
> to see which of the 2 statements where correct.
>
> This patch is based on actual outcome of these tests and not what
> the manual says.
>
> Test procedure used:
>
> Connect a 1 pulse per second (GPS) line to the pin.
>
> echo pin### > /sys/class/gpio/export
> echo in > /sys/class/gpio/gpio###/direction
> echo rising > /sys/class/gpio/gpio###/edge
>
> Check /proc/interrupts if a irq was attached and if irq's where
> received.
>
> Hardware used:
> Henry Paulissen: Cubietruck
> Andere Przywara: BananaPi M1
>
> Tested-by: Andre Przywara 
> Reviewed-by: Andre Przywara 
> Signed-off-by: Henry Paulissen 

Patch applied with Maxime's ACK.

Yours,
Linus Walleij

-- 
You received this message because you are subscribed to the Google Groups 
"linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to linux-sunxi+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[linux-sunxi] Re: [PATCH 1/2] pinctrl: sunxi: Remove non existing irq's

2016-03-08 Thread Linus Walleij
On Mon, Feb 29, 2016 at 6:13 AM, Henry Paulissen  wrote:

> While I was testing irq's on the cubietruck I found a couple of
> not working irq pins. Further diving into the problem it opened
> up a mess called "manual".
>
> This so called manual (A20 user manual v1.3 dated 2014-10-10) says:
>
> Pin overview:
> Page 233:   EINT12 is on pin PC19 mux6.
> Page 236:   EINT12 is on pin PH12 mux6.
>
> Now, it is a bit strange to have the same IRQ on 2 different pins,
> but I guess this could still be possible hardware wise. But then:
>
> Pin registers:
> Page 253:   EINT12 is *not* on pin PC19.
> Page 281:   EINT12 is on pin PH12.
>
> The manual is so contradicting that further tests had to be made
> to see which of the 2 statements where correct.
>
> This patch is based on actual outcome of these tests and not what
> the manual says.
>
> Test procedure used:
>
> Connect a 1 pulse per second (GPS) line to the pin.
>
> echo pin### > /sys/class/gpio/export
> echo in > /sys/class/gpio/gpio###/direction
> echo rising > /sys/class/gpio/gpio###/edge
>
> Check /proc/interrupts if a irq was attached and if irq's where
> received.
>
> Signed-off-by: Henry Paulissen 

Patch applied with Maxime's ACK.

Yours,
Linus Walleij

-- 
You received this message because you are subscribed to the Google Groups 
"linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to linux-sunxi+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[linux-sunxi] Re: [PATCH] dma: sun4i: expose block size and wait cycle configuration to DMA users

2016-03-08 Thread Boris Brezillon
On Tue, 8 Mar 2016 08:51:31 +0100
Maxime Ripard  wrote:

> On Tue, Mar 08, 2016 at 08:25:47AM +0530, Vinod Koul wrote:
> > On Mon, Mar 07, 2016 at 09:30:24PM +0100, Maxime Ripard wrote:
> > > On Mon, Mar 07, 2016 at 04:08:57PM +0100, Boris Brezillon wrote:
> > > > Hi Vinod,
> > > > 
> > > > On Mon, 7 Mar 2016 20:24:29 +0530
> > > > Vinod Koul  wrote:
> > > > 
> > > > > On Mon, Mar 07, 2016 at 10:59:31AM +0100, Boris Brezillon wrote:
> > > > > > +/* Dedicated DMA parameter register layout */
> > > > > > +#define SUN4I_DDMA_PARA_DST_DATA_BLK_SIZE(n)   (((n) - 1) << 
> > > > > > 24)
> > > > > > +#define SUN4I_DDMA_PARA_DST_WAIT_CYCLES(n) (((n) - 1) << 16)
> > > > > > +#define SUN4I_DDMA_PARA_SRC_DATA_BLK_SIZE(n)   (((n) - 1) << 8)
> > > > > > +#define SUN4I_DDMA_PARA_SRC_WAIT_CYCLES(n) (((n) - 1) << 0)
> > > > > > +
> > > > > > +/**
> > > > > > + * struct sun4i_dma_chan_config - DMA channel config
> > > > > > + *
> > > > > > + * @para: contains information about block size and time before 
> > > > > > checking
> > > > > > + *   DRQ line. This is device specific and only applicable to 
> > > > > > dedicated
> > > > > > + *   DMA channels
> > > > > 
> > > > > What information, can you elobrate.. And why can't you use existing
> > > > > dma_slave_config for this?
> > > > 
> > > > Block size is related to the device FIFO size. I guess it allows the
> > > > DMA channel to launch a transfer of X bytes without having to check the
> > > > DRQ line (the line telling the DMA engine it can transfer more data
> > > > to/from the device). The wait cycles information is apparently related
> > > > to the number of clks the engine should wait before polling/checking
> > > > the DRQ line status between each block transfer. I'm not sure what it
> > > > saves to put WAIT_CYCLES() to something != 1, but in their BSP,
> > > > Allwinner tweak that depending on the device.
> > 
> > we already have block size aka src/dst_maxburst, why not use that one.
> 
> I'm not sure it's really the same thing. The DMA controller also has a
> burst parameter, that is either 1 byte or 8 bytes, and ends up being
> different from this one.

Well, that's what I understood to, but when reading more carefully the
src/dst_maxburst description, it seems to match the block_size concept
exposed by the sun4i dmaengine. But how should we choose the real burst
size then.
IIRC, in most documentation/datasheets, burst size is referred as the
maximum number of words (word size depends on the selected width) a
master is allowed to transfer to a slave through the bus without
being interrupted by other master requests.
Am I correct?

> 
> > Why does dmaengine need to wait? Can you explain that
> 
> We have no idea, we thought you might have one :)

Yes, it's really unclear to us why this is needed. There might be some
kind of contention, or maybe the slave device takes some time to put
DRQ line to low state, and without these wait_cycles the dmaengine
would assume some data are still available in the FIFO while there's
actually no more data to retrieve.

> 
> It doesn't really makes sense to us, but it does have a significant
> impact on the throughput.

I wouldn't say significant impact, but tweaking those parameters has
some impact on the performances, and since it's not that complicated to
implement, I thought it was worth a try, but maybe I'm wrong.

Best Regards,

Boris

-- 
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

-- 
You received this message because you are subscribed to the Google Groups 
"linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to linux-sunxi+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [linux-sunxi] Re: [PATCH] dma: sun4i: expose block size and wait cycle configuration to DMA users

2016-03-08 Thread Hans de Goede

Hi,

On 08-03-16 08:51, Maxime Ripard wrote:

On Tue, Mar 08, 2016 at 08:25:47AM +0530, Vinod Koul wrote:

On Mon, Mar 07, 2016 at 09:30:24PM +0100, Maxime Ripard wrote:

On Mon, Mar 07, 2016 at 04:08:57PM +0100, Boris Brezillon wrote:

Hi Vinod,

On Mon, 7 Mar 2016 20:24:29 +0530
Vinod Koul  wrote:


On Mon, Mar 07, 2016 at 10:59:31AM +0100, Boris Brezillon wrote:

+/* Dedicated DMA parameter register layout */
+#define SUN4I_DDMA_PARA_DST_DATA_BLK_SIZE(n)   (((n) - 1) << 24)
+#define SUN4I_DDMA_PARA_DST_WAIT_CYCLES(n) (((n) - 1) << 16)
+#define SUN4I_DDMA_PARA_SRC_DATA_BLK_SIZE(n)   (((n) - 1) << 8)
+#define SUN4I_DDMA_PARA_SRC_WAIT_CYCLES(n) (((n) - 1) << 0)
+
+/**
+ * struct sun4i_dma_chan_config - DMA channel config
+ *
+ * @para: contains information about block size and time before checking
+ *   DRQ line. This is device specific and only applicable to dedicated
+ *   DMA channels


What information, can you elobrate.. And why can't you use existing
dma_slave_config for this?


Block size is related to the device FIFO size. I guess it allows the
DMA channel to launch a transfer of X bytes without having to check the
DRQ line (the line telling the DMA engine it can transfer more data
to/from the device). The wait cycles information is apparently related
to the number of clks the engine should wait before polling/checking
the DRQ line status between each block transfer. I'm not sure what it
saves to put WAIT_CYCLES() to something != 1, but in their BSP,
Allwinner tweak that depending on the device.


we already have block size aka src/dst_maxburst, why not use that one.


I'm not sure it's really the same thing. The DMA controller also has a
burst parameter, that is either 1 byte or 8 bytes, and ends up being
different from this one.


Why does dmaengine need to wait? Can you explain that


We have no idea, we thought you might have one :)

It doesn't really makes sense to us, but it does have a significant
impact on the throughput.




I see 2 possible reasons why waiting till checking for drq can help:

1) A lot of devices have an internal fifo hooked up to a single mmio data
register which gets read using the general purpose dma-engine, it allows
this fifo to fill, and thus do burst transfers
(We've seen similar issues with the scanout engine for the display which
 has its own dma engine, and doing larger transfers helps a lot).

2) Physical memory on the sunxi SoCs is (often) divided into banks
with a shared data / address bus doing bank-switches is expensive, so
this wait cycles may introduce latency which allows a user of another
bank to complete its RAM accesses before the dma engine forces a
bank switch, which ends up avoiding a lot of (interleaved) bank switches
while both try to access a different banj and thus waiting makes things
(much) faster in the end (again a known problem with the display
scanout engine).



Note the differences these kinda tweaks make can be quite dramatic,
when using a 1920x1080p60 hdmi output on the A10 SoC with a 16 bit
memory bus (real world worst case scenario), the memory bandwidth
left for userspace processes (measured through memset) almost doubles
from 48 MB/s to 85 MB/s, source:
http://ssvb.github.io/2014/11/11/revisiting-fullhd-x11-desktop-performance-of-the-allwinner-a10.html

TL;DR: Waiting before starting DMA allows for doing larger burst
transfers which ends up making things more efficient.

Given this, I really expect there to be other dma-engines which
have some option to wait a bit before starting/unpausing a transfer
instead of starting it as soon as (more) data is available, so I think
this would make a good addition to dma_slave_config.

Regards,

Hans

--
You received this message because you are subscribed to the Google Groups 
"linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to linux-sunxi+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.