sun6i MIPI DSI driver EoTp

2019-03-11 Thread Sergey Suloev

Hi, Maxime,

according to MIPI DSI spec chapter 8.8.2  the EoTp packet can be enabled 
or disabled on the protocol level.
It seems like that it might be required for the panel I am working on 
(Himax HX8379A-based panel).
Here is some crappy driver I found on github showing that it might be an 
issue  [1]


May I ask you if this feature supported by sun6i MIPI DSI driver and 
where ?
As there is no datasheet available, could you please help to support 
this feature (if not yet) ?


The second point is that the panel requires NON-BURST-WITH-SYNC-EVENTS 
mode.

Could it be a problem with the current driver?

[1] 
https://github.com/lnfamous/Kernel_Htc_Pico_CyanogenMod12.1/blob/ff5eed4b86f5c9e653ebde4d89fe969c6abf611a/drivers/video/msm/mipi_hx8379a_video_wvga_pt.c#L107


[2] 
https://github.com/lnfamous/Kernel_Htc_Pico_CyanogenMod12.1/blob/ff5eed4b86f5c9e653ebde4d89fe969c6abf611a/drivers/video/msm/mipi_hx8379a_video_wvga_pt.c#L92


Thank you,
Sergey



Compilation issue with Linaro ARM toolchain

2021-01-18 Thread Sergey Suloev

Hi, guys,

I am having an issue builduing kernel 5.11 (rc4) with Linaro ARM 
toolchain. The issue seems to be related to CC plugins sources.
Here is my build log: https://pastebin.com/DTn7Szax. I have never seen 
this before with versions 5.10 and below.


Thank you,
Sergey



Re: Compilation issue with Linaro ARM toolchain

2021-01-18 Thread Sergey Suloev

Hi, Maxim,

thank you for the reply.
Installing libmpc-dev helped.

On 18.01.2021 19:04, Maxim Kuvyrkov wrote:

On 18 Jan 2021, at 18:59, Mathieu Poirier  wrote:

Adding the Linaro toolchain group mailing list.

On Mon, Jan 18, 2021 at 05:49:39PM +0300, Sergey Suloev wrote:

Hi, guys,

I am having an issue builduing kernel 5.11 (rc4) with Linaro ARM toolchain.
The issue seems to be related to CC plugins sources.
Here is my build log: https://pastebin.com/DTn7Szax. I have never seen this
before with versions 5.10 and below.

Thanks, Mathieu.

Hi Sergey,

MPC (along with GMP and MPFR) are libraries that GCC and its plugins depend on. 
 I think, installing libmpc-dev or equivalent should fix the problem; 
installing an equivalent of “apt build-dep gcc” might be more robust.

Linux kernel has recently relaxed the way it detects support for compiler 
plugins, so it’s now enabling them more often than before.

Hope this helps,

--
Maxim Kuvyrkov
https://www.linaro.org


Thanks,
Sergey



Re: [PATCH v2 12/26] drm/sun4i: Add support for multiple DW HDMI PHY clock parents

2018-05-18 Thread Sergey Suloev

Hi, guys,

On 05/18/2018 05:46 PM, Jernej Škrabec wrote:

Hi,

Dne petek, 18. maj 2018 ob 12:01:16 CEST je Maxime Ripard napisal(a):

On Fri, May 18, 2018 at 03:15:22PM +0530, Jagan Teki wrote:

From: Jernej Skrabec 

Some SoCs with DW HDMI have multiple possible clock parents, like A64
and R40.

Expand HDMI PHY clock driver to support second clock parent.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Jagan Teki 
---
Changes for v2:
- new patch

  drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h  |  9 ++-
  drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 33 ---
  drivers/gpu/drm/sun4i/sun8i_hdmi_phy_clk.c | 89
  ++ 3 files changed, 96 insertions(+), 35
  deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h index 79154f0f674a..303189d6602c
100644
--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
+++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
@@ -98,7 +98,8 @@

  #define SUN8I_HDMI_PHY_PLL_CFG1_LDO2_EN   BIT(29)
  #define SUN8I_HDMI_PHY_PLL_CFG1_LDO1_EN   BIT(28)
  #define SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33  BIT(27)

-#define SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL   BIT(26)
+#define SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK   BIT(26)
+#define SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_SHIFT 26

  #define SUN8I_HDMI_PHY_PLL_CFG1_PLLEN BIT(25)
  #define SUN8I_HDMI_PHY_PLL_CFG1_LDO_VSET(x)   ((x) << 22)
  #define SUN8I_HDMI_PHY_PLL_CFG1_UNKNOWN(x)((x) << 20)

@@ -146,7 +147,7 @@

  struct sun8i_hdmi_phy;
  
  struct sun8i_hdmi_phy_variant {


-   bool has_phy_clk;
+   int  phy_clk_num;

void (*phy_init)(struct sun8i_hdmi_phy *phy);
void (*phy_disable)(struct dw_hdmi *hdmi,

struct sun8i_hdmi_phy *phy);

@@ -160,6 +161,7 @@ struct sun8i_hdmi_phy {

struct clk  *clk_mod;
struct clk  *clk_phy;
struct clk  *clk_pll0;

+   struct clk  *clk_pll1;

unsigned intrcal;
struct regmap   *regs;
struct reset_control*rst_phy;

@@ -188,6 +190,7 @@ void sun8i_hdmi_phy_remove(struct sun8i_dw_hdmi
*hdmi);

  void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy);
  const struct dw_hdmi_phy_ops *sun8i_hdmi_phy_get_ops(void);

-int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device *dev);
+int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device *dev,
+int clk_num);

  #endif /* _SUN8I_DW_HDMI_H_ */

diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c index 5a52fc489a9d..0eadf087fc46
100644
--- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
+++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
@@ -183,7 +183,13 @@ static int sun8i_hdmi_phy_config_h3(struct dw_hdmi
*hdmi,>
regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,

   SUN8I_HDMI_PHY_ANA_CFG1_TXEN_MASK, 0);

-   regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, pll_cfg1_init);
+   /*
+* NOTE: We have to be careful not to overwrite PHY parent
+* clock selection bit and clock divider.
+*/
+   regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG,
+  (u32)~SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK,
+  pll_cfg1_init);

regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG2_REG,

   (u32)~SUN8I_HDMI_PHY_PLL_CFG2_PREDIV_MSK,
   pll_cfg2_init);

@@ -232,7 +238,7 @@ static int sun8i_hdmi_phy_config(struct dw_hdmi *hdmi,
void *data,>
regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG,

   SUN8I_HDMI_PHY_DBG_CTRL_POL_MASK, val);

-   if (phy->variant->has_phy_clk)
+   if (phy->variant->phy_clk_num)

clk_set_rate(phy->clk_phy, mode->crtc_clock * 1000);

return phy->variant->phy_config(hdmi, phy, mode->crtc_clock * 1000);

@@ -393,7 +399,7 @@ static const struct sun8i_hdmi_phy_variant
sun8i_a83t_hdmi_phy = {>
  };
  
  static const struct sun8i_hdmi_phy_variant sun8i_h3_hdmi_phy = {


-   .has_phy_clk = true,
+   .phy_clk_num = 1,

.phy_init = &sun8i_hdmi_phy_init_h3,
.phy_disable = &sun8i_hdmi_phy_disable_h3,
.phy_config = &sun8i_hdmi_phy_config_h3,

@@ -464,7 +470,7 @@ int sun8i_hdmi_phy_probe(struct sun8i_dw_hdmi *hdmi,
struct device_node *node)>
goto err_put_clk_bus;

}

-   if (phy->variant->has_phy_clk) {
+   if (phy->variant->phy_clk_num) {

phy->clk_pll0 = of_clk_get_by_name(node, "pll-0");
if (IS_ERR(phy->clk_pll0)) {

dev_err(dev, "Could not get pll-0 clock\n");

@@ -472,7 +478,16 @@ int sun8i_hdmi_phy_probe(struct sun8i_dw_hdmi *hdmi,
struct device_node *node)>

Re: [PATCH v2 12/26] drm/sun4i: Add support for multiple DW HDMI PHY clock parents

2018-05-18 Thread Sergey Suloev

Hi, Jernej,

On 05/18/2018 06:15 PM, Jernej Škrabec wrote:

Hi,

Dne petek, 18. maj 2018 ob 17:09:40 CEST je Sergey Suloev napisal(a):

Hi, guys,

On 05/18/2018 05:46 PM, Jernej Škrabec wrote:

Hi,

Dne petek, 18. maj 2018 ob 12:01:16 CEST je Maxime Ripard napisal(a):

On Fri, May 18, 2018 at 03:15:22PM +0530, Jagan Teki wrote:

From: Jernej Skrabec 

Some SoCs with DW HDMI have multiple possible clock parents, like A64
and R40.

Expand HDMI PHY clock driver to support second clock parent.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Jagan Teki 
---
Changes for v2:
- new patch

   drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h  |  9 ++-
   drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 33 ---
   drivers/gpu/drm/sun4i/sun8i_hdmi_phy_clk.c | 89
   ++ 3 files changed, 96 insertions(+), 35
   deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h index 79154f0f674a..303189d6602c
100644
--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
+++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
@@ -98,7 +98,8 @@

   #define SUN8I_HDMI_PHY_PLL_CFG1_LDO2_EN  BIT(29)
   #define SUN8I_HDMI_PHY_PLL_CFG1_LDO1_EN  BIT(28)
   #define SUN8I_HDMI_PHY_PLL_CFG1_HV_IS_33 BIT(27)

-#define SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL   BIT(26)
+#define SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK   BIT(26)
+#define SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_SHIFT 26

   #define SUN8I_HDMI_PHY_PLL_CFG1_PLLENBIT(25)
   #define SUN8I_HDMI_PHY_PLL_CFG1_LDO_VSET(x)  ((x) << 22)
   #define SUN8I_HDMI_PHY_PLL_CFG1_UNKNOWN(x)   ((x) << 20)

@@ -146,7 +147,7 @@

   struct sun8i_hdmi_phy;
   
   struct sun8i_hdmi_phy_variant {


-   bool has_phy_clk;
+   int  phy_clk_num;

void (*phy_init)(struct sun8i_hdmi_phy *phy);
void (*phy_disable)(struct dw_hdmi *hdmi,

struct sun8i_hdmi_phy *phy);

@@ -160,6 +161,7 @@ struct sun8i_hdmi_phy {

struct clk  *clk_mod;
struct clk  *clk_phy;
struct clk  *clk_pll0;

+   struct clk  *clk_pll1;

unsigned intrcal;
struct regmap   *regs;
struct reset_control*rst_phy;

@@ -188,6 +190,7 @@ void sun8i_hdmi_phy_remove(struct sun8i_dw_hdmi
*hdmi);

   void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy);
   const struct dw_hdmi_phy_ops *sun8i_hdmi_phy_get_ops(void);

-int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device
*dev);
+int sun8i_phy_clk_create(struct sun8i_hdmi_phy *phy, struct device
*dev,
+int clk_num);

   #endif /* _SUN8I_DW_HDMI_H_ */

diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c index
5a52fc489a9d..0eadf087fc46
100644
--- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
+++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
@@ -183,7 +183,13 @@ static int sun8i_hdmi_phy_config_h3(struct dw_hdmi
*hdmi,>

regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_ANA_CFG1_REG,

   SUN8I_HDMI_PHY_ANA_CFG1_TXEN_MASK, 0);

-   regmap_write(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG, pll_cfg1_init);
+   /*
+* NOTE: We have to be careful not to overwrite PHY parent
+* clock selection bit and clock divider.
+*/
+   regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG1_REG,
+  (u32)~SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK,
+  pll_cfg1_init);

regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_PLL_CFG2_REG,

   (u32)~SUN8I_HDMI_PHY_PLL_CFG2_PREDIV_MSK,
   pll_cfg2_init);

@@ -232,7 +238,7 @@ static int sun8i_hdmi_phy_config(struct dw_hdmi
*hdmi,
void *data,>

regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG,

   SUN8I_HDMI_PHY_DBG_CTRL_POL_MASK, val);

-   if (phy->variant->has_phy_clk)
+   if (phy->variant->phy_clk_num)

clk_set_rate(phy->clk_phy, mode->crtc_clock * 1000);

return phy->variant->phy_config(hdmi, phy, mode->crtc_clock * 1000);

@@ -393,7 +399,7 @@ static const struct sun8i_hdmi_phy_variant
sun8i_a83t_hdmi_phy = {>

   };
   
   static const struct sun8i_hdmi_phy_variant sun8i_h3_hdmi_phy = {


-   .has_phy_clk = true,
+   .phy_clk_num = 1,

.phy_init = &sun8i_hdmi_phy_init_h3,
.phy_disable = &sun8i_hdmi_phy_disable_h3,
.phy_config = &sun8i_hdmi_phy_config_h3,

@@ -464,7 +470,7 @@ int sun8i_hdmi_phy_probe(struct sun8i_dw_hdmi *hdmi,
struct device_node *node)>

goto err_put_clk_bus;

}

-   if (phy->variant->has_phy_clk) {
+   if (phy->variant->phy_clk_num) {

p

Re: [PATCH 7/7] ARM: dts: sun7i: Add dts file for the A20-linova1-7 HMI

2018-05-04 Thread Sergey Suloev

Hi, Giulio,

On 05/05/2018 12:52 AM, Giulio Benetti wrote:

Hi Maxime!

Il 04/05/2018 10:06, Maxime Ripard ha scritto:

Hi,

On Wed, May 02, 2018 at 06:41:34PM +0200, Giulio Benetti wrote:

You don't have to handcode the fragments anymore with the new syntax,
and U-Boot makes it really trivial to use if you use the FIT image
format to have multiple overlays bundled in the same image. You can
choose to apply them dynamically, for example based on an EEPROM or
some other metric to see which combination you have.


Ah, this is interesting. I'm going to experiment with that.



I'm struggling against this, I don't really know how to proceed,
except keeping monolithic dts files including other dtsi files.

About dt-overlays I've tried to look around lot of time,
but the only thing I've found is this:
https://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers.git/tree/arch/arm/boot/dts?h=topic/renesas-overlays 



where they use .dtso tagging them as "/plugin/;"
and compile all .dtso found in dts folder.
Then they obtain .dtbo files that should be the dt-overlays we have 
spoken

about right?


Yes. You don't have to do that though, you can just rely on dtc to
compile them, outside of the linux build system.


What I can't understand is if there's a real standard at this time to
follow, because on renesas-driver they use their way to handle all 
.dtso

files, but on mainline there seems to be nothing about that.


I'm not sure what you mean here. It's just fragments of device tree,
that have to be compiled using dtc, that's it. You can use the Linux
build system infrastructure to do that, or you can build your own
simpler one. That's really up to you. See for example
https://github.com/NextThingCo/CHIP-dt-overlays/blob/master/Makefile

(even though the overlays themselves use the legacy syntax and
shouldn't really be used an examples)


Everything works now!
Thank you very much!
I've setted up a Repo on Github to give an example on how make it work 
with no pain:

https://github.com/micronovasrl/linova-dtoverlays

At the moment it's a mess all around, but it's working and give an 
idea on how to make it work. Though I'm going to clean it up well as a 
base for linova dtoverlays.


Ah, btw, can you confirm me that base dts file must be compiled 
outside kernel with:

dtc -@ 
Otherwise as in-tree dts with make dtbs "-@" argument is not passed.
Right?

Thank you a lot for your help and time again!

Best regards!

I'd highly recommend you to look at Armbian overlay support: it is easy 
and elegant.


https://github.com/armbian/build/blob/master/patch/kernel/sunxi-next/add-overlay-compilation-support.patch

https://github.com/armbian/build/blob/master/patch/kernel/sunxi-next/add-sunxi-overlays.patch


Sergey



Re: [PATCH 0/3] Fix broken bananapi m2 devicetree/regulators

2018-02-10 Thread Sergey Suloev

On 02/09/2018 08:52 PM, Philipp Rossak wrote:

This patchseries fixes the bananapi m1 devicetree, to be able to boot again.
The first two patches update/improve the devicetree and the last patch adds
all missing regulators.

Regards,
Philipp

Philipp Rossak (3):
   arm: dts: sun6i: a31s: bpi-m2: update mmc supply nodes
   arm: dts: sun6i: a31s: bpi-m2: improve pmic properties
   arm: dts: sun6i: a31s: fix: bpi-m2: add missing regulators

  arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts | 70 +++-
  1 file changed, 67 insertions(+), 3 deletions(-)


patches are not working

Thanks



Re: [PATCH 0/3] Fix broken bananapi m2 devicetree/regulators

2018-02-10 Thread Sergey Suloev

On 02/11/2018 12:01 AM, Philipp Rossak wrote:

Hey Sergey,

Thanks for mentioning, but I think the problem has nothing to do with 
those patches. I tested them with the v4.15.0 Kernel since this is the 
last stable release and we are right now in the merging window.


I tested the latest mainline, without those patches and the kernel is 
not booting (I can't see any uart output).


Thanks,
Philipp

On 10.02.2018 14:56, Sergey Suloev wrote:

On 02/09/2018 08:52 PM, Philipp Rossak wrote:
This patchseries fixes the bananapi m1 devicetree, to be able to 
boot again.
The first two patches update/improve the devicetree and the last 
patch adds

all missing regulators.

Regards,
Philipp

Philipp Rossak (3):
   arm: dts: sun6i: a31s: bpi-m2: update mmc supply nodes
   arm: dts: sun6i: a31s: bpi-m2: improve pmic properties
   arm: dts: sun6i: a31s: fix: bpi-m2: add missing regulators

  arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts | 70 
+++-

  1 file changed, 67 insertions(+), 3 deletions(-)


patches are not working

Thanks


same problem, but after applying the patches my device is till hanging.




Re: [PATCH v3 3/6] spi: sun6i: restrict transfer length in PIO-mode

2018-04-05 Thread Sergey Suloev

On 04/05/2018 12:19 PM, Maxime Ripard wrote:

On Wed, Apr 04, 2018 at 02:35:14PM +0300, Sergey Suloev wrote:

On 04/04/2018 09:50 AM, Maxime Ripard wrote:

On Tue, Apr 03, 2018 at 06:44:46PM +0300, Sergey Suloev wrote:

There is no need to handle 3/4 empty interrupt as the maximum
supported transfer length in PIO mode is equal to FIFO depth,
i.e. 128 bytes for sun6i and 64 bytes for sun8i SoCs.

Changes in v3:
1) Restored processing of 3/4 FIFO full interrupt.

Signed-off-by: Sergey Suloev 
---
   drivers/spi/spi-sun6i.c | 41 +
   1 file changed, 17 insertions(+), 24 deletions(-)

diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index 78acc1f..c09ad10 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -207,7 +207,10 @@ static void sun6i_spi_set_cs(struct spi_device *spi, bool 
enable)
   static size_t sun6i_spi_max_transfer_size(struct spi_device *spi)
   {
-   return SUN6I_MAX_XFER_SIZE - 1;
+   struct spi_master *master = spi->master;
+   struct sun6i_spi *sspi = spi_master_get_devdata(master);
+
+   return sspi->fifo_depth;

Doesn't that effectively revert 3288d5cb40c0 ?

Why do you need to do so?

Need what?

Why do you need to revert that change.


Change is supposed to restrict max transfer size for PIO mode otherwise it
will fail.
The maximum transfer length = FIFO depth for PIO mode.

The point of that patch was precisely to allow to send more data than
the FIFO. You're breaking that behaviour without any justification,
and this is not ok.


I am sorry, but you can't. That's a hardware limitation.

   }
   static int sun6i_spi_prepare_message(struct spi_master *master,
@@ -255,8 +258,14 @@ static int sun6i_spi_transfer_one(struct spi_master 
*master,
int ret = 0;
u32 reg;
-   if (tfr->len > SUN6I_MAX_XFER_SIZE)
-   return -EINVAL;
+   /* A zero length transfer never finishes if programmed
+  in the hardware */

Improper comment style here. Please make sure to run checkpatch before
sending your patches.

ok

+   if (!tfr->len)
+   return 0;

Can that case even happen?

Not sure, just for safety.

+   /* Don't support transfer larger than the FIFO */
+   if (tfr->len > sspi->fifo_depth)
+   return -EMSGSIZE;

You're changing the return type, why?

As  a more appropriate one

The fact that it's more appropriate should be justified.


reinit_completion(&sspi->done);
sspi->tx_buf = tfr->tx_buf;
@@ -278,8 +287,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
 */
trig_level = sspi->fifo_depth / 4 * 3;
sun6i_spi_write(sspi, SUN6I_FIFO_CTL_REG,
-   (trig_level << SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_BITS) |
-   (trig_level << SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_BITS));
+   (trig_level << SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_BITS));
reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
@@ -343,11 +351,8 @@ static int sun6i_spi_transfer_one(struct spi_master 
*master,
sun6i_spi_fill_fifo(sspi, sspi->fifo_depth);
/* Enable the interrupts */
-   sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, SUN6I_INT_CTL_TC);
sun6i_spi_enable_interrupt(sspi, SUN6I_INT_CTL_TC |
 SUN6I_INT_CTL_RF_RDY);
-   if (tx_len > sspi->fifo_depth)
-   sun6i_spi_enable_interrupt(sspi, SUN6I_INT_CTL_TF_ERQ);

This would also need to be explained in your commit log.

What exactly and in what way ?

You should explain, at least:
A) What is the current behaviour
B) Why that is a problem, or what problem does it cause
C) What solution you implement and why you think it's justified


/* Start the transfer */
reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
@@ -376,7 +381,9 @@ out:
   static irqreturn_t sun6i_spi_handler(int irq, void *dev_id)
   {
struct sun6i_spi *sspi = dev_id;
-   u32 status = sun6i_spi_read(sspi, SUN6I_INT_STA_REG);
+   u32 status;
+
+   status = sun6i_spi_read(sspi, SUN6I_INT_STA_REG);

Why is this change needed?

A minor one, for readability.

That's arguable, and you should have a single logical change per
patch. So this doesn't belong in this one.

Maxime



___
linux-arm-kernel mailing list
linux-arm-ker...@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel





Re: [PATCH v3 3/6] spi: sun6i: restrict transfer length in PIO-mode

2018-04-05 Thread Sergey Suloev

On 04/05/2018 04:17 PM, Mark Brown wrote:

On Thu, Apr 05, 2018 at 12:59:35PM +0300, Sergey Suloev wrote:

On 04/05/2018 12:19 PM, Maxime Ripard wrote:

The point of that patch was precisely to allow to send more data than
the FIFO. You're breaking that behaviour without any justification,
and this is not ok.

I am sorry, but you can't. That's a hardware limitation.

Are you positive about that?  Normally you can add things to hardware
FIFOs while they're being drained so so long as you can keep data
flowing in at least as fast as it's being consumed.


Well, normally yes, but this is not the case with the hardware that I 
own. My a20 (BPiM1+) and a31 (BPiM2) boards behaves differently. With a 
transfer larger than FIFO then TC interrupt never happens.




Re: [PATCH v3 3/6] spi: sun6i: restrict transfer length in PIO-mode

2018-04-06 Thread Sergey Suloev

On 04/06/2018 10:34 AM, Maxime Ripard wrote:

On Thu, Apr 05, 2018 at 04:44:16PM +0300, Sergey Suloev wrote:

On 04/05/2018 04:17 PM, Mark Brown wrote:

On Thu, Apr 05, 2018 at 12:59:35PM +0300, Sergey Suloev wrote:

On 04/05/2018 12:19 PM, Maxime Ripard wrote:

The point of that patch was precisely to allow to send more data than
the FIFO. You're breaking that behaviour without any justification,
and this is not ok.

I am sorry, but you can't. That's a hardware limitation.

Are you positive about that?  Normally you can add things to hardware
FIFOs while they're being drained so so long as you can keep data
flowing in at least as fast as it's being consumed.

Well, normally yes, but this is not the case with the hardware that I own.
My a20 (BPiM1+) and a31 (BPiM2) boards behaves differently. With a transfer
larger than FIFO then TC interrupt never happens.

Because you're not supposed to have a transfer larger than the FIFO,
but to have to setup at first a transfer the size of the FIFO, and
then when it's (or starts to be) depleted, fill it up again.


According to what you said the driver must implement 
"transfer_one_message" instead of "transfer_one"




That's the point of the patch you're reverting, and if it doesn't
work, you should make it work and not simply revert it.

Maxime





Re: [PATCH v3 3/6] spi: sun6i: restrict transfer length in PIO-mode

2018-04-06 Thread Sergey Suloev

On 04/06/2018 10:34 AM, Maxime Ripard wrote:

On Thu, Apr 05, 2018 at 04:44:16PM +0300, Sergey Suloev wrote:

On 04/05/2018 04:17 PM, Mark Brown wrote:

On Thu, Apr 05, 2018 at 12:59:35PM +0300, Sergey Suloev wrote:

On 04/05/2018 12:19 PM, Maxime Ripard wrote:

The point of that patch was precisely to allow to send more data than
the FIFO. You're breaking that behaviour without any justification,
and this is not ok.

I am sorry, but you can't. That's a hardware limitation.

Are you positive about that?  Normally you can add things to hardware
FIFOs while they're being drained so so long as you can keep data
flowing in at least as fast as it's being consumed.

Well, normally yes, but this is not the case with the hardware that I own.
My a20 (BPiM1+) and a31 (BPiM2) boards behaves differently. With a transfer
larger than FIFO then TC interrupt never happens.

Because you're not supposed to have a transfer larger than the FIFO,
but to have to setup at first a transfer the size of the FIFO, and
then when it's (or starts to be) depleted, fill it up again.
According to what you said the driver must implement 
"transfer_one_message" instead of "transfer_one",
because the maximum transfer length is 64 bytes (for sun4i) and we 
shouldn't allow "transfer_one" handle

more than 64 bytes. Otherwise it breaks the concept.


That's the point of the patch you're reverting, and if it doesn't
work, you should make it work and not simply revert it.

Maxime





Re: [PATCH 2/6] spi: sun4i: restrict transfer length in PIO-mode

2018-04-03 Thread Sergey Suloev

On 04/03/2018 11:10 AM, Maxime Ripard wrote:

On Thu, Mar 29, 2018 at 09:59:03PM +0300, Sergey Suloev wrote:

There is no need to handle 3/4 empty/full interrupts as the maximum
supported transfer length in PIO mode is 64 bytes for sun4i-family
SoCs.

That assumes that you'll be able to treat the FIFO full interrupt and
drain the FIFO before we have the next byte coming in. This would
require a real time system, and we're not in one of them.

Maxime



___
linux-arm-kernel mailing list
linux-arm-ker...@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel


so you think we should still handle 3/4 FIFO full ?



Re: [PATCH 5/6] spi: sun4i: introduce register set/unset helpers

2018-04-03 Thread Sergey Suloev

On 04/03/2018 11:14 AM, Maxime Ripard wrote:

On Thu, Mar 29, 2018 at 09:59:06PM +0300, Sergey Suloev wrote:

Two helper functions were added in order to update
registers easily.

Signed-off-by: Sergey Suloev 

I'm not really sure what's easier about this one.

Maxime



___
linux-arm-kernel mailing list
linux-arm-ker...@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel


well, just seems more readable vs doing "read, or, write" every time



Re: [PATCH 2/6] spi: sun4i: restrict transfer length in PIO-mode

2018-04-03 Thread Sergey Suloev

On 04/03/2018 11:10 AM, Maxime Ripard wrote:

On Thu, Mar 29, 2018 at 09:59:03PM +0300, Sergey Suloev wrote:

There is no need to handle 3/4 empty/full interrupts as the maximum
supported transfer length in PIO mode is 64 bytes for sun4i-family
SoCs.

That assumes that you'll be able to treat the FIFO full interrupt and
drain the FIFO before we have the next byte coming in. This would
require a real time system, and we're not in one of them.

Maxime

AFAIK in SPI protocol we send and receive at the same time. As soon as 
the transfer length


is <= FIFO depth then it means that at the moment we get TC interrupt 
all data for this transfer


sent/received already.

Is your point here that draining FIFO might be a long operation and we 
can lose next portion of data ?





Re: [PATCH 2/6] spi: sun4i: restrict transfer length in PIO-mode

2018-04-03 Thread Sergey Suloev

On 04/03/2018 02:40 PM, Maxime Ripard wrote:

On Tue, Apr 03, 2018 at 02:08:43PM +0300, Sergey Suloev wrote:

On 04/03/2018 11:10 AM, Maxime Ripard wrote:

On Thu, Mar 29, 2018 at 09:59:03PM +0300, Sergey Suloev wrote:

There is no need to handle 3/4 empty/full interrupts as the maximum
supported transfer length in PIO mode is 64 bytes for sun4i-family
SoCs.

That assumes that you'll be able to treat the FIFO full interrupt and
drain the FIFO before we have the next byte coming in. This would
require a real time system, and we're not in one of them.

AFAIK in SPI protocol we send and receive at the same time.

It depends. The protocol allows it yes, but most devices I've seen can
only operate in half duplex. But it's not really the point.


As soon as the transfer length is <= FIFO depth then it means that
at the moment we get TC interrupt all data for this transfer
sent/received already.

Is your point here that draining FIFO might be a long operation and we can
lose next portion of data ?

My point is that, if you get another interrupt(s) right before the
FIFO full interrupt, that interrupt is going to be masked for as long
as it is needed for the previous handler(s) to execute.

If you're having another byte received while the interrupt is masked,
you're losing data.

Maxime



___
linux-arm-kernel mailing list
linux-arm-ker...@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel


ok, I am going to put back 3/4 full handler then.



Re: [PATCH 6/6] spi: sun4i: add DMA transfers support

2018-04-03 Thread Sergey Suloev

On 04/03/2018 11:17 AM, Maxime Ripard wrote:

On Thu, Mar 29, 2018 at 09:59:07PM +0300, Sergey Suloev wrote:

+static int sun4i_spi_dma_setup(struct device *dev,
+  struct resource *res)
+{
+   struct spi_master *master = dev_get_drvdata(dev);
+   struct dma_slave_config dma_sconf;
+   int ret;
+
+   master->dma_tx = dma_request_slave_channel_reason(dev, "tx");
+   if (IS_ERR(master->dma_tx)) {
+   dev_err(dev, "Unable to acquire DMA TX channel\n");
+   ret = PTR_ERR(master->dma_tx);
+   goto out;
+   }
+
+   dma_sconf.direction = DMA_MEM_TO_DEV;
+   dma_sconf.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+   dma_sconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;

I guess that would depend on the size of the transfer, right?

no
"this is the width in bytes of the source (RX)register where DMA data 
shall be read. If the sourceis memory this may be ignored depending on 
architecture."
AFAIK is should be 1 byte for SPI side and seems to be ignored for 
memory side, but as soon as I don't know what should be correct value 
for memory side I just put 1 there too.



+   dma_sconf.dst_addr = res->start + SUN4I_TXDATA_REG;
+   dma_sconf.dst_maxburst = 1;
+   dma_sconf.src_maxburst = 1;

And a burst of 1 seems sub-optimal here.
I did some tests before with 3/4 FIFO size but it didn't work and I got 
stuck with 1 byte.
It seems like 1 byte is the correct value because in SPI protocol we can 
only send 1 byte in 1 burst.





+   ret = sun4i_spi_dma_setup(&pdev->dev, res);
+   if (ret) {
+   if (ret == -EPROBE_DEFER) {
+   /* wait for the dma driver to load */
+   goto err_free_master;
+   }
+   dev_warn(&pdev->dev, "DMA transfer not supported\n");

Saying why it's not supported would be great.

I can put more info in this log
but there is already a message printed from sun4_spi_dma_setup() if any 
error occurs


Maxime





[PATCH v2 0/6] spi: Add support for DMA transfers in sun4i SPI driver

2018-04-03 Thread Sergey Suloev
The following patchset provides corrections for PIO-mode
and support for DMA transfers in sun4i SPI driver.

Changes in v2:
1) Restored processing of 3/4 FIFO full interrupt.

2) Debug log enhancements.

Sergey Suloev (6):
  spi: core: handle timeout error from transfer_one()
  spi: sun4i: restrict transfer length in PIO-mode
  spi: sun4i: coding style/readability improvements
  spi: sun4i: use completion provided by SPI core driver
  spi: sun4i: introduce register set/unset helpers
  spi: sun4i: add DMA transfers support

 drivers/spi/spi-sun4i.c | 442 +---
 drivers/spi/spi.c   |   5 +-
 2 files changed, 347 insertions(+), 100 deletions(-)

-- 
2.16.2



[PATCH v2 2/6] spi: sun4i: restrict transfer length in PIO-mode

2018-04-03 Thread Sergey Suloev
There is no need to handle the 3/4 FIFO empty interrupt
as the maximum supported transfer length in PIO mode
is 64 bytes.
As long as a problem was reported previously with filling FIFO
on A10s we want to stick with 63 bytes depth.

Changes in v2:
1) Restored processing of 3/4 FIFO full interrupt.

Signed-off-by: Sergey Suloev 
---
 drivers/spi/spi-sun4i.c | 37 ++---
 1 file changed, 10 insertions(+), 27 deletions(-)

diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c
index 4141003..08fd007 100644
--- a/drivers/spi/spi-sun4i.c
+++ b/drivers/spi/spi-sun4i.c
@@ -22,7 +22,12 @@
 
 #include 
 
-#define SUN4I_FIFO_DEPTH   64
+/*
+ * FIFO length is 64 bytes
+ * But filling the FIFO fully might cause a timeout
+ * on some devices, for example on spi2 on A10s
+ */
+#define SUN4I_FIFO_DEPTH   63
 
 #define SUN4I_RXDATA_REG   0x00
 
@@ -202,7 +207,7 @@ static void sun4i_spi_set_cs(struct spi_device *spi, bool 
enable)
 
 static size_t sun4i_spi_max_transfer_size(struct spi_device *spi)
 {
-   return SUN4I_FIFO_DEPTH - 1;
+   return SUN4I_FIFO_DEPTH;
 }
 
 static int sun4i_spi_transfer_one(struct spi_master *master,
@@ -216,11 +221,8 @@ static int sun4i_spi_transfer_one(struct spi_master 
*master,
int ret = 0;
u32 reg;
 
-   /* We don't support transfer larger than the FIFO */
-   if (tfr->len > SUN4I_MAX_XFER_SIZE)
-   return -EMSGSIZE;
-
-   if (tfr->tx_buf && tfr->len >= SUN4I_MAX_XFER_SIZE)
+   /* We don't support transfers larger than FIFO depth */
+   if (tfr->len > SUN4I_FIFO_DEPTH)
return -EMSGSIZE;
 
reinit_completion(&sspi->done);
@@ -313,17 +315,12 @@ static int sun4i_spi_transfer_one(struct spi_master 
*master,
 
/*
 * Fill the TX FIFO
-* Filling the FIFO fully causes timeout for some reason
-* at least on spi2 on A10s
 */
-   sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH - 1);
+   sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH);
 
/* Enable the interrupts */
sun4i_spi_enable_interrupt(sspi, SUN4I_INT_CTL_TC |
 SUN4I_INT_CTL_RF_F34);
-   /* Only enable Tx FIFO interrupt if we really need it */
-   if (tx_len > SUN4I_FIFO_DEPTH)
-   sun4i_spi_enable_interrupt(sspi, SUN4I_INT_CTL_TF_E34);
 
/* Start the transfer */
reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
@@ -371,20 +368,6 @@ static irqreturn_t sun4i_spi_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
 
-   /* Transmit FIFO 3/4 empty */
-   if (status & SUN4I_INT_CTL_TF_E34) {
-   sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH);
-
-   if (!sspi->len)
-   /* nothing left to transmit */
-   sun4i_spi_disable_interrupt(sspi, SUN4I_INT_CTL_TF_E34);
-
-   /* Only clear the interrupt _after_ re-seeding the FIFO */
-   sun4i_spi_write(sspi, SUN4I_INT_STA_REG, SUN4I_INT_CTL_TF_E34);
-
-   return IRQ_HANDLED;
-   }
-
return IRQ_NONE;
 }
 
-- 
2.16.2



[PATCH v2 6/6] spi: sun4i: add DMA transfers support

2018-04-03 Thread Sergey Suloev
DMA transfers are now available for sun4i-family SoCs.
The DMA mode is used automatically as soon as requested
transfer length is more than FIFO length.

Changes in v2:
1) Debug log enhancements.

Signed-off-by: Sergey Suloev 
---
 drivers/spi/spi-sun4i.c | 299 
 1 file changed, 277 insertions(+), 22 deletions(-)

diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c
index d81d31c..dda7922 100644
--- a/drivers/spi/spi-sun4i.c
+++ b/drivers/spi/spi-sun4i.c
@@ -14,6 +14,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -39,6 +41,7 @@
 #define SUN4I_CTL_CPHA BIT(2)
 #define SUN4I_CTL_CPOL BIT(3)
 #define SUN4I_CTL_CS_ACTIVE_LOWBIT(4)
+#define SUN4I_CTL_DMA_DEDICATEDBIT(5)
 #define SUN4I_CTL_LMTF BIT(6)
 #define SUN4I_CTL_TF_RST   BIT(8)
 #define SUN4I_CTL_RF_RST   BIT(9)
@@ -58,6 +61,8 @@
 #define SUN4I_INT_STA_REG  0x10
 
 #define SUN4I_DMA_CTL_REG  0x14
+#define SUN4I_CTL_DMA_RF_READY BIT(0)
+#define SUN4I_CTL_DMA_TF_NOT_FULL  BIT(10)
 
 #define SUN4I_WAIT_REG 0x18
 
@@ -169,6 +174,13 @@ static inline void sun4i_spi_fill_fifo(struct sun4i_spi 
*sspi, int len)
}
 }
 
+static bool sun4i_spi_can_dma(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *tfr)
+{
+   return tfr->len > SUN4I_FIFO_DEPTH;
+}
+
 static void sun4i_spi_set_cs(struct spi_device *spi, bool enable)
 {
struct sun4i_spi *sspi = spi_master_get_devdata(spi->master);
@@ -208,6 +220,11 @@ static void sun4i_spi_set_cs(struct spi_device *spi, bool 
enable)
 
 static size_t sun4i_spi_max_transfer_size(struct spi_device *spi)
 {
+   struct spi_master *master = spi->master;
+
+   if (master->can_dma)
+   return SUN4I_MAX_XFER_SIZE;
+
return SUN4I_FIFO_DEPTH;
 }
 
@@ -235,6 +252,164 @@ static int sun4i_spi_wait_for_transfer(struct spi_device 
*spi,
return 0;
 }
 
+static void sun4i_spi_dma_callback(void *param)
+{
+   struct spi_master *master = param;
+
+   dev_dbg(&master->dev, "DMA transfer complete\n");
+   spi_finalize_current_transfer(master);
+}
+
+static int sun4i_spi_dmap_prep_tx(struct spi_master *master,
+ struct spi_transfer *tfr,
+ dma_cookie_t *cookie)
+{
+   struct dma_async_tx_descriptor *chan_desc = NULL;
+
+   chan_desc = dmaengine_prep_slave_sg(master->dma_tx,
+   tfr->tx_sg.sgl, tfr->tx_sg.nents,
+   DMA_TO_DEVICE,
+   DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+   if (!chan_desc) {
+   dev_err(&master->dev,
+   "Couldn't prepare TX DMA slave\n");
+   return -EIO;
+   }
+
+   chan_desc->callback = sun4i_spi_dma_callback;
+   chan_desc->callback_param = master;
+
+   *cookie = dmaengine_submit(chan_desc);
+   dma_async_issue_pending(master->dma_tx);
+
+   return 0;
+}
+
+static int sun4i_spi_dmap_prep_rx(struct spi_master *master,
+ struct spi_transfer *tfr,
+ dma_cookie_t *cookie)
+{
+   struct dma_async_tx_descriptor *chan_desc = NULL;
+
+   chan_desc = dmaengine_prep_slave_sg(master->dma_rx,
+   tfr->rx_sg.sgl, tfr->rx_sg.nents,
+   DMA_FROM_DEVICE,
+   DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+   if (!chan_desc) {
+   dev_err(&master->dev,
+   "Couldn't prepare RX DMA slave\n");
+   return -EIO;
+   }
+
+   chan_desc->callback = sun4i_spi_dma_callback;
+   chan_desc->callback_param = master;
+
+   *cookie = dmaengine_submit(chan_desc);
+   dma_async_issue_pending(master->dma_rx);
+
+   return 0;
+}
+
+static int sun4i_spi_transfer_one_dma(struct spi_device *spi,
+ struct spi_transfer *tfr)
+{
+   struct spi_master *master = spi->master;
+   struct sun4i_spi *sspi = spi_master_get_devdata(master);
+   dma_cookie_t tx_cookie = 0, rx_cookie = 0;
+   enum dma_status status;
+   int ret;
+   u32 reg = 0;
+
+   dev_dbg(&master->dev, "Using DMA mode for transfer\n");
+
+   /* Disable interrupts */
+   sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, 0);
+
+   if (sspi->tx_buf) {
+   ret = sun4i_spi_dmap_prep_tx(master, tfr, &tx_cookie);
+   

[PATCH v2 5/6] spi: sun4i: introduce register set/unset helpers

2018-04-03 Thread Sergey Suloev
Two helper functions were added in order to set/unset
specified flags in registers.

Signed-off-by: Sergey Suloev 
---
 drivers/spi/spi-sun4i.c | 40 +++-
 1 file changed, 19 insertions(+), 21 deletions(-)

diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c
index 9d1bc20..d81d31c 100644
--- a/drivers/spi/spi-sun4i.c
+++ b/drivers/spi/spi-sun4i.c
@@ -107,29 +107,29 @@ static inline void sun4i_spi_write(struct sun4i_spi 
*sspi, u32 reg, u32 value)
writel(value, sspi->base_addr + reg);
 }
 
-static inline u32 sun4i_spi_get_tx_fifo_count(struct sun4i_spi *sspi)
+static inline void sun4i_spi_set(struct sun4i_spi *sspi, u32 addr, u32 val)
 {
-   u32 reg = sun4i_spi_read(sspi, SUN4I_FIFO_STA_REG);
-
-   reg >>= SUN4I_FIFO_STA_TF_CNT_BITS;
+   u32 reg = sun4i_spi_read(sspi, addr);
 
-   return reg & SUN4I_FIFO_STA_TF_CNT_MASK;
+   reg |= val;
+   sun4i_spi_write(sspi, addr, reg);
 }
 
-static inline void sun4i_spi_enable_interrupt(struct sun4i_spi *sspi, u32 mask)
+static inline void sun4i_spi_unset(struct sun4i_spi *sspi, u32 addr, u32 val)
 {
-   u32 reg = sun4i_spi_read(sspi, SUN4I_INT_CTL_REG);
+   u32 reg = sun4i_spi_read(sspi, addr);
 
-   reg |= mask;
-   sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, reg);
+   reg &= ~val;
+   sun4i_spi_write(sspi, addr, reg);
 }
 
-static inline void sun4i_spi_disable_interrupt(struct sun4i_spi *sspi, u32 
mask)
+static inline u32 sun4i_spi_get_tx_fifo_count(struct sun4i_spi *sspi)
 {
-   u32 reg = sun4i_spi_read(sspi, SUN4I_INT_CTL_REG);
+   u32 reg = sun4i_spi_read(sspi, SUN4I_FIFO_STA_REG);
 
-   reg &= ~mask;
-   sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, reg);
+   reg >>= SUN4I_FIFO_STA_TF_CNT_BITS;
+
+   return reg & SUN4I_FIFO_STA_TF_CNT_MASK;
 }
 
 static inline void sun4i_spi_drain_fifo(struct sun4i_spi *sspi, int len)
@@ -256,13 +256,12 @@ static int sun4i_spi_transfer_one(struct spi_master 
*master,
/* Clear pending interrupts */
sun4i_spi_write(sspi, SUN4I_INT_STA_REG, ~0);
 
+   /* Reset FIFOs */
+   sun4i_spi_set(sspi, SUN4I_CTL_REG,
+ SUN4I_CTL_RF_RST | SUN4I_CTL_TF_RST);
 
reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
 
-   /* Reset FIFOs */
-   sun4i_spi_write(sspi, SUN4I_CTL_REG,
-   reg | SUN4I_CTL_RF_RST | SUN4I_CTL_TF_RST);
-
/*
 * Setup the transfer control register: Chip Select,
 * polarities, etc.
@@ -342,12 +341,11 @@ static int sun4i_spi_transfer_one(struct spi_master 
*master,
sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH);
 
/* Enable the interrupts */
-   sun4i_spi_enable_interrupt(sspi, SUN4I_INT_CTL_TC |
-SUN4I_INT_CTL_RF_F34);
+   sun4i_spi_set(sspi, SUN4I_INT_CTL_REG, SUN4I_INT_CTL_TC |
+  SUN4I_INT_CTL_RF_F34);
 
/* Start the transfer */
-   reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
-   sun4i_spi_write(sspi, SUN4I_CTL_REG, reg | SUN4I_CTL_XCH);
+   sun4i_spi_set(sspi, SUN4I_CTL_REG, SUN4I_CTL_XCH);
 
ret = sun4i_spi_wait_for_transfer(spi, tfr);
 
-- 
2.16.2



[PATCH v2 4/6] spi: sun4i: use completion provided by SPI core driver

2018-04-03 Thread Sergey Suloev
As long as the completion already provided by the SPI core
then there is no need to waste extra-memory on this.
Also a waiting function was added to avoid code duplication.

Signed-off-by: Sergey Suloev 
---
 drivers/spi/spi-sun4i.c | 62 -
 1 file changed, 35 insertions(+), 27 deletions(-)

diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c
index 899e956..9d1bc20 100644
--- a/drivers/spi/spi-sun4i.c
+++ b/drivers/spi/spi-sun4i.c
@@ -92,8 +92,6 @@ struct sun4i_spi {
struct clk  *hclk;
struct clk  *mclk;
 
-   struct completion   done;
-
const u8*tx_buf;
u8  *rx_buf;
int len;
@@ -213,13 +211,36 @@ static size_t sun4i_spi_max_transfer_size(struct 
spi_device *spi)
return SUN4I_FIFO_DEPTH;
 }
 
+static int sun4i_spi_wait_for_transfer(struct spi_device *spi,
+  struct spi_transfer *tfr)
+{
+   struct spi_master *master = spi->master;
+   unsigned int start, end, tx_time;
+   unsigned int timeout;
+
+   /* calc required timeout from given speed & len values */
+   tx_time = max(tfr->len * 8 * 2 / (tfr->speed_hz / 1000), 100U);
+   start = jiffies;
+   timeout = wait_for_completion_timeout(&master->xfer_completion,
+ msecs_to_jiffies(tx_time));
+   end = jiffies;
+   if (!timeout) {
+   dev_warn(&master->dev,
+"%s: timeout transferring %u bytes@%iHz for %i(%i)ms",
+dev_name(&spi->dev), tfr->len, tfr->speed_hz,
+jiffies_to_msecs(end - start), tx_time);
+   return -ETIMEDOUT;
+   }
+
+   return 0;
+}
+
 static int sun4i_spi_transfer_one(struct spi_master *master,
  struct spi_device *spi,
  struct spi_transfer *tfr)
 {
struct sun4i_spi *sspi = spi_master_get_devdata(master);
-   unsigned int mclk_rate, div, timeout;
-   unsigned int start, end, tx_time;
+   unsigned int mclk_rate, div;
unsigned int tx_len = 0;
int ret = 0;
u32 reg;
@@ -228,7 +249,6 @@ static int sun4i_spi_transfer_one(struct spi_master *master,
if (tfr->len > SUN4I_FIFO_DEPTH)
return -EMSGSIZE;
 
-   reinit_completion(&sspi->done);
sspi->tx_buf = tfr->tx_buf;
sspi->rx_buf = tfr->rx_buf;
sspi->len = tfr->len;
@@ -329,22 +349,8 @@ static int sun4i_spi_transfer_one(struct spi_master 
*master,
reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
sun4i_spi_write(sspi, SUN4I_CTL_REG, reg | SUN4I_CTL_XCH);
 
-   tx_time = max(tfr->len * 8 * 2 / (tfr->speed_hz / 1000), 100U);
-   start = jiffies;
-   timeout = wait_for_completion_timeout(&sspi->done,
- msecs_to_jiffies(tx_time));
-   end = jiffies;
-   if (!timeout) {
-   dev_warn(&master->dev,
-"%s: timeout transferring %u bytes@%iHz for %i(%i)ms",
-dev_name(&spi->dev), tfr->len, tfr->speed_hz,
-jiffies_to_msecs(end - start), tx_time);
-   ret = -ETIMEDOUT;
-   goto out;
-   }
-
+   ret = sun4i_spi_wait_for_transfer(spi, tfr);
 
-out:
sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, 0);
 
return ret;
@@ -352,14 +358,18 @@ out:
 
 static irqreturn_t sun4i_spi_handler(int irq, void *dev_id)
 {
-   struct sun4i_spi *sspi = dev_id;
-   u32 status = sun4i_spi_read(sspi, SUN4I_INT_STA_REG);
+   struct spi_master *master = dev_id;
+   struct sun4i_spi *sspi = spi_master_get_devdata(master);
+   u32 status;
+
+   status = sun4i_spi_read(sspi, SUN4I_INT_STA_REG);
 
/* Transfer complete */
if (status & SUN4I_INT_CTL_TC) {
-   sun4i_spi_write(sspi, SUN4I_INT_STA_REG, SUN4I_INT_CTL_TC);
+   sun4i_spi_write(sspi, SUN4I_INT_STA_REG,
+   SUN4I_INT_CTL_TC);
sun4i_spi_drain_fifo(sspi, SUN4I_FIFO_DEPTH);
-   complete(&sspi->done);
+   spi_finalize_current_transfer(master);
return IRQ_HANDLED;
}
 
@@ -456,7 +466,7 @@ static int sun4i_spi_probe(struct platform_device *pdev)
}
 
ret = devm_request_irq(&pdev->dev, irq, sun4i_spi_handler,
-  0, dev_name(&pdev->dev), sspi);
+  0, dev_name(&pdev->dev), master);
if (ret) {
dev_err(&pdev->dev, "Cannot request IRQ\n");
goto err_free_master;
@@ -476,8 +486,6 @@ static int sun4i_spi_probe(struct 

[PATCH v2 3/6] spi: sun4i: coding style/readability improvements

2018-04-03 Thread Sergey Suloev
Minor changes to fulfill the coding style and
improve the readability.

Signed-off-by: Sergey Suloev 
---
 drivers/spi/spi-sun4i.c | 32 +---
 1 file changed, 17 insertions(+), 15 deletions(-)

diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c
index 08fd007..899e956 100644
--- a/drivers/spi/spi-sun4i.c
+++ b/drivers/spi/spi-sun4i.c
@@ -83,8 +83,11 @@
 #define SUN4I_FIFO_STA_TF_CNT_MASK 0x7f
 #define SUN4I_FIFO_STA_TF_CNT_BITS 16
 
+#define SUN4I_SPI_MAX_SPEED_HZ 100 * 1000 * 1000
+#define SUN4I_SPI_MIN_SPEED_HZ 3 * 1000
+#define SUN4I_SPI_MODE_BITS(SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | 
SPI_LSB_FIRST)
+
 struct sun4i_spi {
-   struct spi_master   *master;
void __iomem*base_addr;
struct clk  *hclk;
struct clk  *mclk;
@@ -418,12 +421,23 @@ static int sun4i_spi_probe(struct platform_device *pdev)
struct resource *res;
int ret = 0, irq;
 
-   master = spi_alloc_master(&pdev->dev, sizeof(struct sun4i_spi));
+   master = spi_alloc_master(&pdev->dev, sizeof(*sspi));
if (!master) {
dev_err(&pdev->dev, "Unable to allocate SPI Master\n");
return -ENOMEM;
}
 
+   master->max_speed_hz = SUN4I_SPI_MAX_SPEED_HZ;
+   master->min_speed_hz = SUN4I_SPI_MIN_SPEED_HZ;
+   master->num_chipselect = 4;
+   master->mode_bits = SUN4I_SPI_MODE_BITS;
+   master->bits_per_word_mask = SPI_BPW_MASK(8);
+   master->set_cs = sun4i_spi_set_cs;
+   master->transfer_one = sun4i_spi_transfer_one;
+   master->max_transfer_size = sun4i_spi_max_transfer_size;
+   master->dev.of_node = pdev->dev.of_node;
+   master->auto_runtime_pm = true;
+
platform_set_drvdata(pdev, master);
sspi = spi_master_get_devdata(master);
 
@@ -442,24 +456,12 @@ static int sun4i_spi_probe(struct platform_device *pdev)
}
 
ret = devm_request_irq(&pdev->dev, irq, sun4i_spi_handler,
-  0, "sun4i-spi", sspi);
+  0, dev_name(&pdev->dev), sspi);
if (ret) {
dev_err(&pdev->dev, "Cannot request IRQ\n");
goto err_free_master;
}
 
-   sspi->master = master;
-   master->max_speed_hz = 100 * 1000 * 1000;
-   master->min_speed_hz = 3 * 1000;
-   master->set_cs = sun4i_spi_set_cs;
-   master->transfer_one = sun4i_spi_transfer_one;
-   master->num_chipselect = 4;
-   master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
-   master->bits_per_word_mask = SPI_BPW_MASK(8);
-   master->dev.of_node = pdev->dev.of_node;
-   master->auto_runtime_pm = true;
-   master->max_transfer_size = sun4i_spi_max_transfer_size;
-
sspi->hclk = devm_clk_get(&pdev->dev, "ahb");
if (IS_ERR(sspi->hclk)) {
dev_err(&pdev->dev, "Unable to acquire AHB clock\n");
-- 
2.16.2



[PATCH v2 1/6] spi: core: handle timeout error from transfer_one()

2018-04-03 Thread Sergey Suloev
As long as sun4i/sun6i SPI drivers have overriden the default
"wait for completion" procedure then we need to properly
handle -ETIMEDOUT error from transfer_one().

Signed-off-by: Sergey Suloev 
---
 drivers/spi/spi.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index b33a727..2dcd4f6 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -1028,7 +1028,7 @@ static int spi_transfer_one_message(struct spi_controller 
*ctlr,
reinit_completion(&ctlr->xfer_completion);
 
ret = ctlr->transfer_one(ctlr, msg->spi, xfer);
-   if (ret < 0) {
+   if (ret < 0 && ret != -ETIMEDOUT) {
SPI_STATISTICS_INCREMENT_FIELD(statm,
   errors);
SPI_STATISTICS_INCREMENT_FIELD(stats,
@@ -1051,7 +1051,7 @@ static int spi_transfer_one_message(struct spi_controller 
*ctlr,
 
msecs_to_jiffies(ms));
}
 
-   if (ms == 0) {
+   if (ms == 0 || ret == -ETIMEDOUT) {
SPI_STATISTICS_INCREMENT_FIELD(statm,
   timedout);
SPI_STATISTICS_INCREMENT_FIELD(stats,
@@ -1059,6 +1059,7 @@ static int spi_transfer_one_message(struct spi_controller 
*ctlr,
dev_err(&msg->spi->dev,
"SPI transfer timed out\n");
msg->status = -ETIMEDOUT;
+   ret = 0;
}
} else {
if (xfer->len)
-- 
2.16.2



[PATCH v3 6/6] spi: sun6i: add DMA transfers support

2018-04-03 Thread Sergey Suloev
DMA transfers are now available for sun6i and sun8i SoCs.
The DMA mode is used automatically as soon as requested
transfer length is more than FIFO length.

Changes in v3:
1) Debug log enhancements.

Signed-off-by: Sergey Suloev 
---
 drivers/spi/spi-sun6i.c | 331 ++--
 1 file changed, 294 insertions(+), 37 deletions(-)

diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index 2fa9d6e..7f41871 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -14,6 +14,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -55,17 +57,20 @@
 
 #define SUN6I_FIFO_CTL_REG 0x18
 #define SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_MASK  0xff
-#define SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_BITS  0
+#define SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_POS   0
+#define SUN6I_FIFO_CTL_RF_DRQ_EN   BIT(8)
 #define SUN6I_FIFO_CTL_RF_RST  BIT(15)
 #define SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_MASK  0xff
-#define SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_BITS  16
+#define SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_POS   16
+#define SUN6I_FIFO_CTL_TF_DRQ_EN   BIT(24)
 #define SUN6I_FIFO_CTL_TF_RST  BIT(31)
+#define SUN6I_FIFO_CTL_DMA_DEDICATEBIT(9)|BIT(25)
 
 #define SUN6I_FIFO_STA_REG 0x1c
 #define SUN6I_FIFO_STA_RF_CNT_MASK 0x7f
-#define SUN6I_FIFO_STA_RF_CNT_BITS 0
+#define SUN6I_FIFO_STA_RF_CNT_POS  0
 #define SUN6I_FIFO_STA_TF_CNT_MASK 0x7f
-#define SUN6I_FIFO_STA_TF_CNT_BITS 16
+#define SUN6I_FIFO_STA_TF_CNT_POS  16
 
 #define SUN6I_CLK_CTL_REG  0x24
 #define SUN6I_CLK_CTL_CDR2_MASK0xff
@@ -135,7 +140,7 @@ static inline u32 sun6i_spi_get_tx_fifo_count(struct 
sun6i_spi *sspi)
 {
u32 reg = sun6i_spi_read(sspi, SUN6I_FIFO_STA_REG);
 
-   reg >>= SUN6I_FIFO_STA_TF_CNT_BITS;
+   reg >>= SUN6I_FIFO_STA_TF_CNT_POS;
 
return reg & SUN6I_FIFO_STA_TF_CNT_MASK;
 }
@@ -148,7 +153,7 @@ static inline void sun6i_spi_drain_fifo(struct sun6i_spi 
*sspi, int len)
/* See how much data is available */
reg = sun6i_spi_read(sspi, SUN6I_FIFO_STA_REG);
reg &= SUN6I_FIFO_STA_RF_CNT_MASK;
-   cnt = reg >> SUN6I_FIFO_STA_RF_CNT_BITS;
+   cnt = reg >> SUN6I_FIFO_STA_RF_CNT_POS;
 
if (len > cnt)
len = cnt;
@@ -177,6 +182,15 @@ static inline void sun6i_spi_fill_fifo(struct sun6i_spi 
*sspi, int len)
}
 }
 
+static bool sun6i_spi_can_dma(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *tfr)
+{
+   struct sun6i_spi *sspi = spi_master_get_devdata(master);
+
+   return tfr->len > sspi->fifo_depth;
+}
+
 static void sun6i_spi_set_cs(struct spi_device *spi, bool enable)
 {
struct sun6i_spi *sspi = spi_master_get_devdata(spi->master);
@@ -208,6 +222,9 @@ static size_t sun6i_spi_max_transfer_size(struct spi_device 
*spi)
struct spi_master *master = spi->master;
struct sun6i_spi *sspi = spi_master_get_devdata(master);
 
+   if (master->can_dma)
+   return SUN6I_MAX_XFER_SIZE;
+
return sspi->fifo_depth;
 }
 
@@ -268,16 +285,187 @@ static int sun6i_spi_wait_for_transfer(struct spi_device 
*spi,
return 0;
 }
 
+static void sun6i_spi_dma_callback(void *param)
+{
+   struct spi_master *master = param;
+
+   dev_dbg(&master->dev, "DMA transfer complete\n");
+   spi_finalize_current_transfer(master);
+}
+
+static int sun6i_spi_dmap_prep_tx(struct spi_master *master,
+ struct spi_transfer *tfr,
+ dma_cookie_t *cookie)
+{
+   struct dma_async_tx_descriptor *chan_desc = NULL;
+
+   chan_desc = dmaengine_prep_slave_sg(master->dma_tx,
+   tfr->tx_sg.sgl, tfr->tx_sg.nents,
+   DMA_TO_DEVICE,
+   DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+   if (!chan_desc) {
+   dev_err(&master->dev,
+   "Couldn't prepare TX DMA slave\n");
+   return -EIO;
+   }
+
+   chan_desc->callback = sun6i_spi_dma_callback;
+   chan_desc->callback_param = master;
+
+   *cookie = dmaengine_submit(chan_desc);
+   dma_async_issue_pending(master->dma_tx);
+
+   return 0;
+}
+
+static int sun6i_spi_dmap_prep_rx(struct spi_master *master,
+ struct spi_transfer *tfr,
+ dma_cookie_t *cookie)
+{
+   struct dma_async_tx_descriptor *chan_desc = NULL;
+
+   chan_desc = dmaengine_prep_slave_sg(master->dma_rx,
+

[PATCH v3 5/6] spi: sun6i: introduce register set/unset helpers

2018-04-03 Thread Sergey Suloev
Two helper functions were added in order to set/unset
specified flags in registers.

Signed-off-by: Sergey Suloev 
---
 drivers/spi/spi-sun6i.c | 37 -
 1 file changed, 16 insertions(+), 21 deletions(-)

diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index 0912404..2fa9d6e 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -115,29 +115,29 @@ static inline void sun6i_spi_write(struct sun6i_spi 
*sspi, u32 reg, u32 value)
writel(value, sspi->base_addr + reg);
 }
 
-static inline u32 sun6i_spi_get_tx_fifo_count(struct sun6i_spi *sspi)
+static inline void sun6i_spi_set(struct sun6i_spi *sspi, u32 addr, u32 val)
 {
-   u32 reg = sun6i_spi_read(sspi, SUN6I_FIFO_STA_REG);
-
-   reg >>= SUN6I_FIFO_STA_TF_CNT_BITS;
+   u32 reg = sun6i_spi_read(sspi, addr);
 
-   return reg & SUN6I_FIFO_STA_TF_CNT_MASK;
+   reg |= val;
+   sun6i_spi_write(sspi, addr, reg);
 }
 
-static inline void sun6i_spi_enable_interrupt(struct sun6i_spi *sspi, u32 mask)
+static inline void sun6i_spi_unset(struct sun6i_spi *sspi, u32 addr, u32 val)
 {
-   u32 reg = sun6i_spi_read(sspi, SUN6I_INT_CTL_REG);
+   u32 reg = sun6i_spi_read(sspi, addr);
 
-   reg |= mask;
-   sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, reg);
+   reg &= ~val;
+   sun6i_spi_write(sspi, addr, reg);
 }
 
-static inline void sun6i_spi_disable_interrupt(struct sun6i_spi *sspi, u32 
mask)
+static inline u32 sun6i_spi_get_tx_fifo_count(struct sun6i_spi *sspi)
 {
-   u32 reg = sun6i_spi_read(sspi, SUN6I_INT_CTL_REG);
+   u32 reg = sun6i_spi_read(sspi, SUN6I_FIFO_STA_REG);
 
-   reg &= ~mask;
-   sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, reg);
+   reg >>= SUN6I_FIFO_STA_TF_CNT_BITS;
+
+   return reg & SUN6I_FIFO_STA_TF_CNT_MASK;
 }
 
 static inline void sun6i_spi_drain_fifo(struct sun6i_spi *sspi, int len)
@@ -310,18 +310,14 @@ static int sun6i_spi_transfer_one(struct spi_master 
*master,
sun6i_spi_write(sspi, SUN6I_FIFO_CTL_REG,
(trig_level << SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_BITS));
 
-
-   reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
/*
 * If it's a TX only transfer, we don't want to fill the RX
 * FIFO with bogus data
 */
if (sspi->rx_buf)
-   reg &= ~SUN6I_TFR_CTL_DHB;
+   sun6i_spi_unset(sspi, SUN6I_TFR_CTL_REG, SUN6I_TFR_CTL_DHB);
else
-   reg |= SUN6I_TFR_CTL_DHB;
-
-   sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
+   sun6i_spi_set(sspi, SUN6I_TFR_CTL_REG, SUN6I_TFR_CTL_DHB);
 
 
/* Ensure that we have a parent clock fast enough */
@@ -376,8 +372,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
 SUN6I_INT_CTL_RF_RDY);
 
/* Start the transfer */
-   reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
-   sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg | SUN6I_TFR_CTL_XCH);
+   sun6i_spi_set(sspi, SUN6I_TFR_CTL_REG, SUN6I_TFR_CTL_XCH);
 
/* Wait for completion */
ret = sun6i_spi_wait_for_transfer(spi, tfr);
-- 
2.16.2



[PATCH v3 3/6] spi: sun6i: restrict transfer length in PIO-mode

2018-04-03 Thread Sergey Suloev
There is no need to handle 3/4 empty interrupt as the maximum
supported transfer length in PIO mode is equal to FIFO depth,
i.e. 128 bytes for sun6i and 64 bytes for sun8i SoCs.

Changes in v3:
1) Restored processing of 3/4 FIFO full interrupt.

Signed-off-by: Sergey Suloev 
---
 drivers/spi/spi-sun6i.c | 41 +
 1 file changed, 17 insertions(+), 24 deletions(-)

diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index 78acc1f..c09ad10 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -207,7 +207,10 @@ static void sun6i_spi_set_cs(struct spi_device *spi, bool 
enable)
 
 static size_t sun6i_spi_max_transfer_size(struct spi_device *spi)
 {
-   return SUN6I_MAX_XFER_SIZE - 1;
+   struct spi_master *master = spi->master;
+   struct sun6i_spi *sspi = spi_master_get_devdata(master);
+
+   return sspi->fifo_depth;
 }
 
 static int sun6i_spi_prepare_message(struct spi_master *master,
@@ -255,8 +258,14 @@ static int sun6i_spi_transfer_one(struct spi_master 
*master,
int ret = 0;
u32 reg;
 
-   if (tfr->len > SUN6I_MAX_XFER_SIZE)
-   return -EINVAL;
+   /* A zero length transfer never finishes if programmed
+  in the hardware */
+   if (!tfr->len)
+   return 0;
+
+   /* Don't support transfer larger than the FIFO */
+   if (tfr->len > sspi->fifo_depth)
+   return -EMSGSIZE;
 
reinit_completion(&sspi->done);
sspi->tx_buf = tfr->tx_buf;
@@ -278,8 +287,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
 */
trig_level = sspi->fifo_depth / 4 * 3;
sun6i_spi_write(sspi, SUN6I_FIFO_CTL_REG,
-   (trig_level << SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_BITS) |
-   (trig_level << SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_BITS));
+   (trig_level << SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_BITS));
 
 
reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
@@ -343,11 +351,8 @@ static int sun6i_spi_transfer_one(struct spi_master 
*master,
sun6i_spi_fill_fifo(sspi, sspi->fifo_depth);
 
/* Enable the interrupts */
-   sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, SUN6I_INT_CTL_TC);
sun6i_spi_enable_interrupt(sspi, SUN6I_INT_CTL_TC |
 SUN6I_INT_CTL_RF_RDY);
-   if (tx_len > sspi->fifo_depth)
-   sun6i_spi_enable_interrupt(sspi, SUN6I_INT_CTL_TF_ERQ);
 
/* Start the transfer */
reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
@@ -376,7 +381,9 @@ out:
 static irqreturn_t sun6i_spi_handler(int irq, void *dev_id)
 {
struct sun6i_spi *sspi = dev_id;
-   u32 status = sun6i_spi_read(sspi, SUN6I_INT_STA_REG);
+   u32 status;
+
+   status = sun6i_spi_read(sspi, SUN6I_INT_STA_REG);
 
/* Transfer complete */
if (status & SUN6I_INT_CTL_TC) {
@@ -388,26 +395,12 @@ static irqreturn_t sun6i_spi_handler(int irq, void 
*dev_id)
 
/* Receive FIFO 3/4 full */
if (status & SUN6I_INT_CTL_RF_RDY) {
-   sun6i_spi_drain_fifo(sspi, SUN6I_FIFO_DEPTH);
+   sun6i_spi_drain_fifo(sspi, sspi->fifo_depth);
/* Only clear the interrupt _after_ draining the FIFO */
sun6i_spi_write(sspi, SUN6I_INT_STA_REG, SUN6I_INT_CTL_RF_RDY);
return IRQ_HANDLED;
}
 
-   /* Transmit FIFO 3/4 empty */
-   if (status & SUN6I_INT_CTL_TF_ERQ) {
-   sun6i_spi_fill_fifo(sspi, SUN6I_FIFO_DEPTH);
-
-   if (!sspi->len)
-   /* nothing left to transmit */
-   sun6i_spi_disable_interrupt(sspi, SUN6I_INT_CTL_TF_ERQ);
-
-   /* Only clear the interrupt _after_ re-seeding the FIFO */
-   sun6i_spi_write(sspi, SUN6I_INT_STA_REG, SUN6I_INT_CTL_TF_ERQ);
-
-   return IRQ_HANDLED;
-   }
-
return IRQ_NONE;
 }
 
-- 
2.16.2



[PATCH v3 0/6] spi: Add support for DMA transfers in sun6i SPI driver

2018-04-03 Thread Sergey Suloev
The following patchset provides corrections for PIO-mode
and support for DMA transfers in sun6i SPI driver.

Changes in v2:
1) Fixed issue with misplacing a piece of code that requires access
to the transfer structure into sun6i_spi_prepare_message() function
where the transfer structure is not available.

2) Fixed issue with passing an invalid argument into devm_request_irq()
function.

Changes in v3:
1) Restored processing of 3/4 FIFO full interrupt.

2) Debug log enhancements.

Sergey Suloev (6):
  spi: sun6i: coding style/readability improvements
  spi: sun6i: handle chip select polarity flag
  spi: sun6i: restrict transfer length in PIO-mode
  spi: sun6i: use completion provided by SPI core
  spi: sun6i: introduce register set/unset helpers
  spi: sun6i: add DMA transfers support

 drivers/spi/spi-sun6i.c | 526 
 1 file changed, 402 insertions(+), 124 deletions(-)

-- 
2.16.2



[PATCH v3 4/6] spi: sun6i: use completion provided by SPI core

2018-04-03 Thread Sergey Suloev
As long as the completion is already provided by the SPI core
then there is no need to waste extra-memory on this.
Also a waiting function was added to avoid code duplication.

Changes in v2:
1) Fixed issue with passing an invalid argument into devm_request_irq()
function.

Signed-off-by: Sergey Suloev 
---
 drivers/spi/spi-sun6i.c | 52 -
 1 file changed, 30 insertions(+), 22 deletions(-)

diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index c09ad10..0912404 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -99,8 +99,6 @@ struct sun6i_spi {
struct clk  *mclk;
struct reset_control*rstc;
 
-   struct completion   done;
-
const u8*tx_buf;
u8  *rx_buf;
int len;
@@ -246,6 +244,30 @@ static int sun6i_spi_prepare_message(struct spi_master 
*master,
return 0;
 }
 
+static int sun6i_spi_wait_for_transfer(struct spi_device *spi,
+  struct spi_transfer *tfr)
+{
+   struct spi_master *master = spi->master;
+   unsigned int start, end, tx_time;
+   unsigned int timeout;
+
+   /* smart wait for completion */
+   tx_time = max(tfr->len * 8 * 2 / (tfr->speed_hz / 1000), 100U);
+   start = jiffies;
+   timeout = wait_for_completion_timeout(&master->xfer_completion,
+ msecs_to_jiffies(tx_time));
+   end = jiffies;
+   if (!timeout) {
+   dev_warn(&master->dev,
+"%s: timeout transferring %u bytes@%iHz for %i(%i)ms",
+dev_name(&spi->dev), tfr->len, tfr->speed_hz,
+jiffies_to_msecs(end - start), tx_time);
+   return -ETIMEDOUT;
+   }
+
+   return 0;
+}
+
 static int sun6i_spi_transfer_one(struct spi_master *master,
  struct spi_device *spi,
  struct spi_transfer *tfr)
@@ -267,7 +289,6 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
if (tfr->len > sspi->fifo_depth)
return -EMSGSIZE;
 
-   reinit_completion(&sspi->done);
sspi->tx_buf = tfr->tx_buf;
sspi->rx_buf = tfr->rx_buf;
sspi->len = tfr->len;
@@ -358,21 +379,9 @@ static int sun6i_spi_transfer_one(struct spi_master 
*master,
reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg | SUN6I_TFR_CTL_XCH);
 
-   tx_time = max(tfr->len * 8 * 2 / (tfr->speed_hz / 1000), 100U);
-   start = jiffies;
-   timeout = wait_for_completion_timeout(&sspi->done,
- msecs_to_jiffies(tx_time));
-   end = jiffies;
-   if (!timeout) {
-   dev_warn(&master->dev,
-"%s: timeout transferring %u bytes@%iHz for %i(%i)ms",
-dev_name(&spi->dev), tfr->len, tfr->speed_hz,
-jiffies_to_msecs(end - start), tx_time);
-   ret = -ETIMEDOUT;
-   goto out;
-   }
+   /* Wait for completion */
+   ret = sun6i_spi_wait_for_transfer(spi, tfr);
 
-out:
sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, 0);
 
return ret;
@@ -380,7 +389,8 @@ out:
 
 static irqreturn_t sun6i_spi_handler(int irq, void *dev_id)
 {
-   struct sun6i_spi *sspi = dev_id;
+   struct spi_master *master = dev_id;
+   struct sun6i_spi *sspi = spi_master_get_devdata(master);
u32 status;
 
status = sun6i_spi_read(sspi, SUN6I_INT_STA_REG);
@@ -389,7 +399,7 @@ static irqreturn_t sun6i_spi_handler(int irq, void *dev_id)
if (status & SUN6I_INT_CTL_TC) {
sun6i_spi_write(sspi, SUN6I_INT_STA_REG, SUN6I_INT_CTL_TC);
sun6i_spi_drain_fifo(sspi, sspi->fifo_depth);
-   complete(&sspi->done);
+   spi_finalize_current_transfer(master);
return IRQ_HANDLED;
}
 
@@ -496,7 +506,7 @@ static int sun6i_spi_probe(struct platform_device *pdev)
}
 
ret = devm_request_irq(&pdev->dev, irq, sun6i_spi_handler,
-  0, dev_name(&pdev->dev), sspi);
+  0, dev_name(&pdev->dev), master);
if (ret) {
dev_err(&pdev->dev, "Cannot request IRQ\n");
goto err_free_master;
@@ -518,8 +528,6 @@ static int sun6i_spi_probe(struct platform_device *pdev)
goto err_free_master;
}
 
-   init_completion(&sspi->done);
-
sspi->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
if (IS_ERR(sspi->rstc)) {
dev_err(&pdev->dev, "Couldn't get reset controller\n");
-- 
2.16.2



[PATCH v3 2/6] spi: sun6i: handle chip select polarity flag

2018-04-03 Thread Sergey Suloev
The chip select polarity flag is declared as supported
but is not handled in the code.

Signed-off-by: Sergey Suloev 
---
 drivers/spi/spi-sun6i.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index 88ad45e..78acc1f 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -193,6 +193,12 @@ static void sun6i_spi_set_cs(struct spi_device *spi, bool 
enable)
else
reg &= ~SUN6I_TFR_CTL_CS_LEVEL;
 
+   /* Handle chip select "reverse" polarity */
+   if (spi->mode & SPI_CS_HIGH)
+   reg &= ~SUN6I_TFR_CTL_SPOL;
+   else
+   reg |= SUN6I_TFR_CTL_SPOL;
+
/* We want to control the chip select manually */
reg |= SUN6I_TFR_CTL_CS_MANUAL;
 
-- 
2.16.2



[PATCH v3 1/6] spi: sun6i: coding style/readability improvements

2018-04-03 Thread Sergey Suloev
Minor changes to fulfill the coding style and improve
the readability of the code.

Changes in v2:
1) Fixed issue with misplacing a piece of code that requires access
to the transfer structure into sun6i_spi_prepare_message() function
where the transfer structure is not available.

Signed-off-by: Sergey Suloev 
---
 drivers/spi/spi-sun6i.c | 97 +
 1 file changed, 58 insertions(+), 39 deletions(-)

diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index 8533f4e..88ad45e 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -88,8 +88,12 @@
 #define SUN6I_TXDATA_REG   0x200
 #define SUN6I_RXDATA_REG   0x300
 
+#define SUN6I_SPI_MODE_BITS(SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | 
SPI_LSB_FIRST)
+
+#define SUN6I_SPI_MAX_SPEED_HZ 1
+#define SUN6I_SPI_MIN_SPEED_HZ 3000
+
 struct sun6i_spi {
-   struct spi_master   *master;
void __iomem*base_addr;
struct clk  *hclk;
struct clk  *mclk;
@@ -189,6 +193,9 @@ static void sun6i_spi_set_cs(struct spi_device *spi, bool 
enable)
else
reg &= ~SUN6I_TFR_CTL_CS_LEVEL;
 
+   /* We want to control the chip select manually */
+   reg |= SUN6I_TFR_CTL_CS_MANUAL;
+
sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
 }
 
@@ -197,6 +204,39 @@ static size_t sun6i_spi_max_transfer_size(struct 
spi_device *spi)
return SUN6I_MAX_XFER_SIZE - 1;
 }
 
+static int sun6i_spi_prepare_message(struct spi_master *master,
+struct spi_message *msg)
+{
+   struct spi_device *spi = msg->spi;
+   struct sun6i_spi *sspi = spi_master_get_devdata(master);
+   u32 reg;
+
+   /*
+* Setup the transfer control register: Chip Select,
+* polarities, etc.
+*/
+   reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
+
+   if (spi->mode & SPI_CPOL)
+   reg |= SUN6I_TFR_CTL_CPOL;
+   else
+   reg &= ~SUN6I_TFR_CTL_CPOL;
+
+   if (spi->mode & SPI_CPHA)
+   reg |= SUN6I_TFR_CTL_CPHA;
+   else
+   reg &= ~SUN6I_TFR_CTL_CPHA;
+
+   if (spi->mode & SPI_LSB_FIRST)
+   reg |= SUN6I_TFR_CTL_FBS;
+   else
+   reg &= ~SUN6I_TFR_CTL_FBS;
+
+   sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
+
+   return 0;
+}
+
 static int sun6i_spi_transfer_one(struct spi_master *master,
  struct spi_device *spi,
  struct spi_transfer *tfr)
@@ -235,27 +275,8 @@ static int sun6i_spi_transfer_one(struct spi_master 
*master,
(trig_level << SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_BITS) |
(trig_level << SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_BITS));
 
-   /*
-* Setup the transfer control register: Chip Select,
-* polarities, etc.
-*/
-   reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
-
-   if (spi->mode & SPI_CPOL)
-   reg |= SUN6I_TFR_CTL_CPOL;
-   else
-   reg &= ~SUN6I_TFR_CTL_CPOL;
-
-   if (spi->mode & SPI_CPHA)
-   reg |= SUN6I_TFR_CTL_CPHA;
-   else
-   reg &= ~SUN6I_TFR_CTL_CPHA;
-
-   if (spi->mode & SPI_LSB_FIRST)
-   reg |= SUN6I_TFR_CTL_FBS;
-   else
-   reg &= ~SUN6I_TFR_CTL_FBS;
 
+   reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
/*
 * If it's a TX only transfer, we don't want to fill the RX
 * FIFO with bogus data
@@ -265,11 +286,9 @@ static int sun6i_spi_transfer_one(struct spi_master 
*master,
else
reg |= SUN6I_TFR_CTL_DHB;
 
-   /* We want to control the chip select manually */
-   reg |= SUN6I_TFR_CTL_CS_MANUAL;
-
sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
 
+
/* Ensure that we have a parent clock fast enough */
mclk_rate = clk_get_rate(sspi->mclk);
if (mclk_rate < (2 * tfr->speed_hz)) {
@@ -442,12 +461,24 @@ static int sun6i_spi_probe(struct platform_device *pdev)
struct resource *res;
int ret = 0, irq;
 
-   master = spi_alloc_master(&pdev->dev, sizeof(struct sun6i_spi));
+   master = spi_alloc_master(&pdev->dev, sizeof(*sspi));
if (!master) {
dev_err(&pdev->dev, "Unable to allocate SPI Master\n");
return -ENOMEM;
}
 
+   master->max_speed_hz = SUN6I_SPI_MAX_SPEED_HZ;
+   master->min_speed_hz = SUN6I_SPI_MIN_SPEED_HZ;
+   master->num_chipselect = 4;
+   master->mode_bits = SUN6I_SPI_MODE_BITS;
+   master->bits_per_word_mask = SPI_BPW_MASK(8);
+   master->set_cs = sun6i_spi_set_cs;
+   master->prepare_message = sun6i_spi_prepare_message

Re: [PATCH v2 1/6] spi: core: handle timeout error from transfer_one()

2018-04-03 Thread Sergey Suloev

On 04/03/2018 06:52 PM, Mark Brown wrote:

On Tue, Apr 03, 2018 at 06:29:00PM +0300, Sergey Suloev wrote:

As long as sun4i/sun6i SPI drivers have overriden the default
"wait for completion" procedure then we need to properly
handle -ETIMEDOUT error from transfer_one().

Why is this connected to those drivers specifically?


These 2 drivers have their own "waiting" code and not using the code 
from SPI core.




Re: [PATCH v2 1/6] spi: core: handle timeout error from transfer_one()

2018-04-03 Thread Sergey Suloev

On 04/03/2018 07:18 PM, Mark Brown wrote:

On Tue, Apr 03, 2018 at 07:00:55PM +0300, Sergey Suloev wrote:

On 04/03/2018 06:52 PM, Mark Brown wrote:

On Tue, Apr 03, 2018 at 06:29:00PM +0300, Sergey Suloev wrote:

As long as sun4i/sun6i SPI drivers have overriden the default
"wait for completion" procedure then we need to properly
handle -ETIMEDOUT error from transfer_one().

Why is this connected to those drivers specifically?

These 2 drivers have their own "waiting" code and not using the code from
SPI core.

Does this not apply to any other driver - why is this something we only
have to do when these drivers do it?  That's what's setting off alarm
bells.


sun4i/sun6i drivers have let's say "smart" waiting while SPI core uses a 
fixed interval to wait.


I can't say for every SPI driver in kernel, that's outside of my area of 
expertise.





Re: [PATCH v3 3/6] spi: sun6i: restrict transfer length in PIO-mode

2018-04-04 Thread Sergey Suloev

On 04/04/2018 09:50 AM, Maxime Ripard wrote:

On Tue, Apr 03, 2018 at 06:44:46PM +0300, Sergey Suloev wrote:

There is no need to handle 3/4 empty interrupt as the maximum
supported transfer length in PIO mode is equal to FIFO depth,
i.e. 128 bytes for sun6i and 64 bytes for sun8i SoCs.

Changes in v3:
1) Restored processing of 3/4 FIFO full interrupt.

Signed-off-by: Sergey Suloev 
---
  drivers/spi/spi-sun6i.c | 41 +
  1 file changed, 17 insertions(+), 24 deletions(-)

diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index 78acc1f..c09ad10 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -207,7 +207,10 @@ static void sun6i_spi_set_cs(struct spi_device *spi, bool 
enable)
  
  static size_t sun6i_spi_max_transfer_size(struct spi_device *spi)

  {
-   return SUN6I_MAX_XFER_SIZE - 1;
+   struct spi_master *master = spi->master;
+   struct sun6i_spi *sspi = spi_master_get_devdata(master);
+
+   return sspi->fifo_depth;

Doesn't that effectively revert 3288d5cb40c0 ?

Why do you need to do so?

Need what?

Change is supposed to restrict max transfer size for PIO mode otherwise 
it will fail.

The maximum transfer length = FIFO depth for PIO mode.




  }
  
  static int sun6i_spi_prepare_message(struct spi_master *master,

@@ -255,8 +258,14 @@ static int sun6i_spi_transfer_one(struct spi_master 
*master,
int ret = 0;
u32 reg;
  
-	if (tfr->len > SUN6I_MAX_XFER_SIZE)

-   return -EINVAL;
+   /* A zero length transfer never finishes if programmed
+  in the hardware */

Improper comment style here. Please make sure to run checkpatch before
sending your patches.

ok



+   if (!tfr->len)
+   return 0;

Can that case even happen?

Not sure, just for safety.



+   /* Don't support transfer larger than the FIFO */
+   if (tfr->len > sspi->fifo_depth)
+   return -EMSGSIZE;

You're changing the return type, why?

As  a more appropriate one



reinit_completion(&sspi->done);
sspi->tx_buf = tfr->tx_buf;
@@ -278,8 +287,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
 */
trig_level = sspi->fifo_depth / 4 * 3;
sun6i_spi_write(sspi, SUN6I_FIFO_CTL_REG,
-   (trig_level << SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_BITS) |
-   (trig_level << SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_BITS));
+   (trig_level << SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_BITS));
  
  
  	reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);

@@ -343,11 +351,8 @@ static int sun6i_spi_transfer_one(struct spi_master 
*master,
sun6i_spi_fill_fifo(sspi, sspi->fifo_depth);
  
  	/* Enable the interrupts */

-   sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, SUN6I_INT_CTL_TC);
sun6i_spi_enable_interrupt(sspi, SUN6I_INT_CTL_TC |
 SUN6I_INT_CTL_RF_RDY);
-   if (tx_len > sspi->fifo_depth)
-   sun6i_spi_enable_interrupt(sspi, SUN6I_INT_CTL_TF_ERQ);

This would also need to be explained in your commit log.

What exactly and in what way ?


  
  	/* Start the transfer */

reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
@@ -376,7 +381,9 @@ out:
  static irqreturn_t sun6i_spi_handler(int irq, void *dev_id)
  {
struct sun6i_spi *sspi = dev_id;
-   u32 status = sun6i_spi_read(sspi, SUN6I_INT_STA_REG);
+   u32 status;
+
+   status = sun6i_spi_read(sspi, SUN6I_INT_STA_REG);

Why is this change needed?

A minor one, for readability.


Maxime





Re: [PATCH v2 1/6] spi: core: handle timeout error from transfer_one()

2018-04-04 Thread Sergey Suloev

On 04/04/2018 10:08 AM, Maxime Ripard wrote:

On Tue, Apr 03, 2018 at 07:24:11PM +0300, Sergey Suloev wrote:

On 04/03/2018 07:18 PM, Mark Brown wrote:

On Tue, Apr 03, 2018 at 07:00:55PM +0300, Sergey Suloev wrote:

On 04/03/2018 06:52 PM, Mark Brown wrote:

On Tue, Apr 03, 2018 at 06:29:00PM +0300, Sergey Suloev wrote:

As long as sun4i/sun6i SPI drivers have overriden the default
"wait for completion" procedure then we need to properly
handle -ETIMEDOUT error from transfer_one().

Why is this connected to those drivers specifically?

These 2 drivers have their own "waiting" code and not using the code from
SPI core.

Does this not apply to any other driver - why is this something we only
have to do when these drivers do it?  That's what's setting off alarm
bells.

sun4i/sun6i drivers have let's say "smart" waiting while SPI core uses a
fixed interval to wait.

I can't say for every SPI driver in kernel, that's outside of my area of
expertise.

I'm not sure what's specific about the sun4i / sun6i case here. Your
patch doesn't have anything to do with the delay before the timeout,
but the fact that we return -ETIMEDOUT in the first place.

And I'm pretty sure that papering over an error returned by a driver
is not the right thing to do.

Maxime



___
linux-arm-kernel mailing list
linux-arm-ker...@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel


do you mean the changes in spi.c are not required at all ?

My point was to eat ETIMEDOUT error from transfer_one() as it is just a 
mark and


shouldn't be handled as a normal error.



Re: [PATCH v3 3/6] spi: sun6i: restrict transfer length in PIO-mode

2018-04-09 Thread Sergey Suloev

On 04/09/2018 12:27 PM, Maxime Ripard wrote:

On Fri, Apr 06, 2018 at 06:48:23PM +0300, Sergey Suloev wrote:

On 04/06/2018 10:34 AM, Maxime Ripard wrote:

On Thu, Apr 05, 2018 at 04:44:16PM +0300, Sergey Suloev wrote:

On 04/05/2018 04:17 PM, Mark Brown wrote:

On Thu, Apr 05, 2018 at 12:59:35PM +0300, Sergey Suloev wrote:

On 04/05/2018 12:19 PM, Maxime Ripard wrote:

The point of that patch was precisely to allow to send more data than
the FIFO. You're breaking that behaviour without any justification,
and this is not ok.

I am sorry, but you can't. That's a hardware limitation.

Are you positive about that?  Normally you can add things to hardware
FIFOs while they're being drained so so long as you can keep data
flowing in at least as fast as it's being consumed.

Well, normally yes, but this is not the case with the hardware that I own.
My a20 (BPiM1+) and a31 (BPiM2) boards behaves differently. With a transfer
larger than FIFO then TC interrupt never happens.

Because you're not supposed to have a transfer larger than the FIFO,
but to have to setup at first a transfer the size of the FIFO, and
then when it's (or starts to be) depleted, fill it up again.

According to what you said the driver must implement
"transfer_one_message" instead of "transfer_one"

I'm not sure what makes you think that I said that.

Maxime



___
linux-arm-kernel mailing list
linux-arm-ker...@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel


Because current implementation tries to send more than FIFO-depth of 
data in a single call to "transfer_one" which is wrong.




Re: [PATCH v3 3/6] spi: sun6i: restrict transfer length in PIO-mode

2018-04-09 Thread Sergey Suloev

On 04/09/2018 01:50 PM, Mark Brown wrote:

On Mon, Apr 09, 2018 at 01:26:23PM +0300, Sergey Suloev wrote:

On 04/09/2018 12:27 PM, Maxime Ripard wrote:

On Fri, Apr 06, 2018 at 06:48:23PM +0300, Sergey Suloev wrote:

On 04/06/2018 10:34 AM, Maxime Ripard wrote:
According to what you said the driver must implement
"transfer_one_message" instead of "transfer_one"

I'm not sure what makes you think that I said that.

Because current implementation tries to send more than FIFO-depth of data in
a single call to "transfer_one" which is wrong.

No, that's absolutely not the case.  All any of these functions has to
do is transfer whatever they were asked to, how they do it is not at all
important to the framework.


I think you don't fully understand the issue. Let's talk about sun4i 
and  sun6i SPI  drivers separately.


sun4i

1)it is correctly declaring max_transfer_size=FIFO depth for PIO mode  
but transfer_one() function doesn't follow the declaration allowing PIO 
transfers longer than FIFO depth  by just refilling FIFO using 3/4 FIFO 
empty interrupt. I can definitely state here that long transfers WON'T 
WORK on real hardware. I tested it and that's why I can say that. But as 
soon as sun4i SPI driver  is correctly declaring max_transfer_size then 
"smart" clients will work well by limiting a single transfer size to 
FIFO depth. I tested it with real hardware, again.



sun6i

2) it allows PIO transfers of any length by declaring max_transfer_size 
to a huge number, i.e. you can ONLY make this driver work in PIO mode  
by limiting a single transfer size to FIFO depth (64 or 128 bytes) on 
client side  and ignore max_transfer_size  exposed by the driver. Again, 
tested with real hardware.


All above doesn't work for DMA mode as there is no such limitation.

I can't clearly explain what is happening in the hardware in PIO mode 
but it seems that TC interrupt doesn't arrive in time when refilling 
FIFO multiple times takes place and every long transfer will end up with 
a timeout error.





Re: [PATCH v3 3/6] spi: sun6i: restrict transfer length in PIO-mode

2018-04-09 Thread Sergey Suloev

On 04/09/2018 02:36 PM, Maxime Ripard wrote:

On Mon, Apr 09, 2018 at 02:10:40PM +0300, Sergey Suloev wrote:

On 04/09/2018 01:50 PM, Mark Brown wrote:

On Mon, Apr 09, 2018 at 01:26:23PM +0300, Sergey Suloev wrote:

On 04/09/2018 12:27 PM, Maxime Ripard wrote:

On Fri, Apr 06, 2018 at 06:48:23PM +0300, Sergey Suloev wrote:

On 04/06/2018 10:34 AM, Maxime Ripard wrote:
According to what you said the driver must implement
"transfer_one_message" instead of "transfer_one"

I'm not sure what makes you think that I said that.

Because current implementation tries to send more than FIFO-depth of data in
a single call to "transfer_one" which is wrong.

No, that's absolutely not the case.  All any of these functions has to
do is transfer whatever they were asked to, how they do it is not at all
important to the framework.

I think you don't fully understand the issue. Let's talk about sun4i and
sun6i SPI  drivers separately.

sun4i

1)it is correctly declaring max_transfer_size=FIFO depth for PIO mode  but
transfer_one() function doesn't follow the declaration allowing PIO
transfers longer than FIFO depth  by just refilling FIFO using 3/4 FIFO
empty interrupt. I can definitely state here that long transfers WON'T WORK
on real hardware.

Surely the original author of the patch allowing to do just that
disagrees with you.
I am not getting the point why the driver is declaring the max transfer 
length value and not following the rule.

And it's not about the hardware itself, it's about
how the driver operates as well.


I tested it and that's why I can say that.

Then it must be fixed, and not silently reverted.


But as soon as sun4i SPI driver  is correctly declaring
max_transfer_size then "smart" clients will work well by limiting a
single transfer size to FIFO depth. I tested it with real hardware,
again.

This is really not my point. What would prevent you from doing
multiple transfers in that case, and filling the FIFO entirely,
waiting for it to be done, then resuming until you have sent the right
number of bytes?
Because it makes no sense IMHO. I can't see any single point in allowing 
long PIO transfers. Can you find at least one ?


I think we should reuse as much SPI core code as possible. The SPI core 
can handle an SPI message with multiple transfers,
all we need is to have max_transfer_size = FIFO depth and restrict it in 
transfer_one().




Maxime



___
linux-arm-kernel mailing list
linux-arm-ker...@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel





[PATCH 5/6] spi: sun4i: introduce register set/unset helpers

2018-03-29 Thread Sergey Suloev
Two helper functions were added in order to update
registers easily.

Signed-off-by: Sergey Suloev 

---
 drivers/spi/spi-sun4i.c | 40 +++-
 1 file changed, 19 insertions(+), 21 deletions(-)

diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c
index 4f24e12..fc913d4 100644
--- a/drivers/spi/spi-sun4i.c
+++ b/drivers/spi/spi-sun4i.c
@@ -107,29 +107,29 @@ static inline void sun4i_spi_write(struct sun4i_spi 
*sspi, u32 reg, u32 value)
writel(value, sspi->base_addr + reg);
 }
 
-static inline u32 sun4i_spi_get_tx_fifo_count(struct sun4i_spi *sspi)
+static inline void sun4i_spi_set(struct sun4i_spi *sspi, u32 addr, u32 val)
 {
-   u32 reg = sun4i_spi_read(sspi, SUN4I_FIFO_STA_REG);
-
-   reg >>= SUN4I_FIFO_STA_TF_CNT_BITS;
+   u32 reg = sun4i_spi_read(sspi, addr);
 
-   return reg & SUN4I_FIFO_STA_TF_CNT_MASK;
+   reg |= val;
+   sun4i_spi_write(sspi, addr, reg);
 }
 
-static inline void sun4i_spi_enable_interrupt(struct sun4i_spi *sspi, u32 mask)
+static inline void sun4i_spi_unset(struct sun4i_spi *sspi, u32 addr, u32 val)
 {
-   u32 reg = sun4i_spi_read(sspi, SUN4I_INT_CTL_REG);
+   u32 reg = sun4i_spi_read(sspi, addr);
 
-   reg |= mask;
-   sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, reg);
+   reg &= ~val;
+   sun4i_spi_write(sspi, addr, reg);
 }
 
-static inline void sun4i_spi_disable_interrupt(struct sun4i_spi *sspi, u32 
mask)
+static inline u32 sun4i_spi_get_tx_fifo_count(struct sun4i_spi *sspi)
 {
-   u32 reg = sun4i_spi_read(sspi, SUN4I_INT_CTL_REG);
+   u32 reg = sun4i_spi_read(sspi, SUN4I_FIFO_STA_REG);
 
-   reg &= ~mask;
-   sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, reg);
+   reg >>= SUN4I_FIFO_STA_TF_CNT_BITS;
+
+   return reg & SUN4I_FIFO_STA_TF_CNT_MASK;
 }
 
 static inline void sun4i_spi_drain_fifo(struct sun4i_spi *sspi, int len)
@@ -256,13 +256,12 @@ static int sun4i_spi_transfer_one(struct spi_master 
*master,
/* Clear pending interrupts */
sun4i_spi_write(sspi, SUN4I_INT_STA_REG, ~0);
 
+   /* Reset FIFOs */
+   sun4i_spi_set(sspi, SUN4I_CTL_REG,
+ SUN4I_CTL_RF_RST | SUN4I_CTL_TF_RST);
 
reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
 
-   /* Reset FIFOs */
-   sun4i_spi_write(sspi, SUN4I_CTL_REG,
-   reg | SUN4I_CTL_RF_RST | SUN4I_CTL_TF_RST);
-
/*
 * Setup the transfer control register: Chip Select,
 * polarities, etc.
@@ -341,12 +340,11 @@ static int sun4i_spi_transfer_one(struct spi_master 
*master,
 */
sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH);
 
-   /* Enable the transfer complete interrupt */
-   sun4i_spi_enable_interrupt(sspi, SUN4I_INT_CTL_TC);
+   /* Enable transfer complete interrupt */
+   sun4i_spi_set(sspi, SUN4I_INT_CTL_REG, SUN4I_INT_CTL_TC);
 
/* Start the transfer */
-   reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
-   sun4i_spi_write(sspi, SUN4I_CTL_REG, reg | SUN4I_CTL_XCH);
+   sun4i_spi_set(sspi, SUN4I_CTL_REG, SUN4I_CTL_XCH);
 
ret = sun4i_spi_wait_for_transfer(spi, tfr);
 
-- 
2.16.2



[PATCH 6/6] spi: sun4i: add DMA transfers support

2018-03-29 Thread Sergey Suloev
DMA transfers are now available for sun4i-family SoCs.
The DMA mode is used automatically as soon as requested
transfer length is more than FIFO length.

Signed-off-by: Sergey Suloev 

---
 drivers/spi/spi-sun4i.c | 291 
 1 file changed, 271 insertions(+), 20 deletions(-)

diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c
index fc913d4..9928af7 100644
--- a/drivers/spi/spi-sun4i.c
+++ b/drivers/spi/spi-sun4i.c
@@ -14,6 +14,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -39,6 +41,7 @@
 #define SUN4I_CTL_CPHA BIT(2)
 #define SUN4I_CTL_CPOL BIT(3)
 #define SUN4I_CTL_CS_ACTIVE_LOWBIT(4)
+#define SUN4I_CTL_DMA_DEDICATEDBIT(5)
 #define SUN4I_CTL_LMTF BIT(6)
 #define SUN4I_CTL_TF_RST   BIT(8)
 #define SUN4I_CTL_RF_RST   BIT(9)
@@ -58,6 +61,8 @@
 #define SUN4I_INT_STA_REG  0x10
 
 #define SUN4I_DMA_CTL_REG  0x14
+#define SUN4I_CTL_DMA_RF_READY BIT(0)
+#define SUN4I_CTL_DMA_TF_NOT_FULL  BIT(10)
 
 #define SUN4I_WAIT_REG 0x18
 
@@ -169,6 +174,13 @@ static inline void sun4i_spi_fill_fifo(struct sun4i_spi 
*sspi, int len)
}
 }
 
+static bool sun4i_spi_can_dma(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *tfr)
+{
+   return tfr->len > SUN4I_FIFO_DEPTH;
+}
+
 static void sun4i_spi_set_cs(struct spi_device *spi, bool enable)
 {
struct sun4i_spi *sspi = spi_master_get_devdata(spi->master);
@@ -208,6 +220,11 @@ static void sun4i_spi_set_cs(struct spi_device *spi, bool 
enable)
 
 static size_t sun4i_spi_max_transfer_size(struct spi_device *spi)
 {
+   struct spi_master *master = spi->master;
+
+   if (master->can_dma)
+   return SUN4I_MAX_XFER_SIZE;
+
return SUN4I_FIFO_DEPTH;
 }
 
@@ -235,6 +252,160 @@ static int sun4i_spi_wait_for_transfer(struct spi_device 
*spi,
return 0;
 }
 
+static void sun4i_spi_dma_callback(void *param)
+{
+   struct spi_master *master = param;
+
+   dev_dbg(&master->dev, "DMA transfer complete\n");
+   spi_finalize_current_transfer(master);
+}
+
+static int sun4i_spi_dmap_prep_tx(struct spi_master *master,
+ struct spi_transfer *tfr,
+ dma_cookie_t *cookie)
+{
+   struct dma_async_tx_descriptor *chan_desc = NULL;
+
+   chan_desc = dmaengine_prep_slave_sg(master->dma_tx,
+   tfr->tx_sg.sgl, tfr->tx_sg.nents,
+   DMA_TO_DEVICE,
+   DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+   if (!chan_desc) {
+   dev_err(&master->dev,
+   "Couldn't prepare TX DMA slave\n");
+   return -EIO;
+   }
+
+   chan_desc->callback = sun4i_spi_dma_callback;
+   chan_desc->callback_param = master;
+
+   *cookie = dmaengine_submit(chan_desc);
+   dma_async_issue_pending(master->dma_tx);
+
+   return 0;
+}
+
+static int sun4i_spi_dmap_prep_rx(struct spi_master *master,
+ struct spi_transfer *tfr,
+ dma_cookie_t *cookie)
+{
+   struct dma_async_tx_descriptor *chan_desc = NULL;
+
+   chan_desc = dmaengine_prep_slave_sg(master->dma_rx,
+   tfr->rx_sg.sgl, tfr->rx_sg.nents,
+   DMA_FROM_DEVICE,
+   DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+   if (!chan_desc) {
+   dev_err(&master->dev,
+   "Couldn't prepare RX DMA slave\n");
+   return -EIO;
+   }
+
+   chan_desc->callback = sun4i_spi_dma_callback;
+   chan_desc->callback_param = master;
+
+   *cookie = dmaengine_submit(chan_desc);
+   dma_async_issue_pending(master->dma_rx);
+
+   return 0;
+}
+
+static int sun4i_spi_transfer_one_dma(struct spi_device *spi,
+ struct spi_transfer *tfr)
+{
+   struct spi_master *master = spi->master;
+   struct sun4i_spi *sspi = spi_master_get_devdata(master);
+   dma_cookie_t tx_cookie = 0, rx_cookie = 0;
+   enum dma_status status;
+   int ret;
+   u32 reg = 0;
+
+   dev_dbg(&master->dev, "Using DMA mode for transfer\n");
+
+   if (sspi->tx_buf) {
+   ret = sun4i_spi_dmap_prep_tx(master, tfr, &tx_cookie);
+   if (ret)
+   goto out;
+
+   reg |= SUN4I_CTL_DMA_TF_NOT_FULL;
+   }
+
+   if (s

[PATCH 1/6] spi: core: handle timeout error from transfer_one()

2018-03-29 Thread Sergey Suloev
As long as sun4i/sun6i SPI drivers have overriden the default
"wait for completion" procedure then we need to properly
handle -ETIMEDOUT error from transfer_one().

Signed-off-by: Sergey Suloev 

---
 drivers/spi/spi.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index b33a727..2dcd4f6 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -1028,7 +1028,7 @@ static int spi_transfer_one_message(struct spi_controller 
*ctlr,
reinit_completion(&ctlr->xfer_completion);
 
ret = ctlr->transfer_one(ctlr, msg->spi, xfer);
-   if (ret < 0) {
+   if (ret < 0 && ret != -ETIMEDOUT) {
SPI_STATISTICS_INCREMENT_FIELD(statm,
   errors);
SPI_STATISTICS_INCREMENT_FIELD(stats,
@@ -1051,7 +1051,7 @@ static int spi_transfer_one_message(struct spi_controller 
*ctlr,
 
msecs_to_jiffies(ms));
}
 
-   if (ms == 0) {
+   if (ms == 0 || ret == -ETIMEDOUT) {
SPI_STATISTICS_INCREMENT_FIELD(statm,
   timedout);
SPI_STATISTICS_INCREMENT_FIELD(stats,
@@ -1059,6 +1059,7 @@ static int spi_transfer_one_message(struct spi_controller 
*ctlr,
dev_err(&msg->spi->dev,
"SPI transfer timed out\n");
msg->status = -ETIMEDOUT;
+   ret = 0;
}
} else {
if (xfer->len)
-- 
2.16.2



[PATCH 0/6] spi: Add support for DMA transfers in sun4i SPI driver

2018-03-29 Thread Sergey Suloev
The following patchset provides corrections for PIO-mode
and support for DMA transfers in sun4i SPI driver.

Sergey Suloev (6):
  spi: core: handle timeout error from transfer_one()
  spi: sun4i: restrict transfer length in PIO-mode
  spi: sun4i: coding style/readability improvements
  spi: sun4i: use completion provided by SPI core driver
  spi: sun4i: introduce register set/unset helpers
  spi: sun4i: add DMA transfers support

 drivers/spi/spi-sun4i.c | 443 
 drivers/spi/spi.c   |   5 +-
 2 files changed, 341 insertions(+), 107 deletions(-)

-- 
2.16.2



[PATCH 4/6] spi: sun4i: use completion provided by SPI core driver

2018-03-29 Thread Sergey Suloev
As long as the completion already provided by the SPI core
then there is no need to waste extra-memory on this.
Also a waiting function was added to avoid code duplication.

Signed-off-by: Sergey Suloev 

---
 drivers/spi/spi-sun4i.c | 62 -
 1 file changed, 35 insertions(+), 27 deletions(-)

diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c
index 2d716f1..4f24e12 100644
--- a/drivers/spi/spi-sun4i.c
+++ b/drivers/spi/spi-sun4i.c
@@ -92,8 +92,6 @@ struct sun4i_spi {
struct clk  *hclk;
struct clk  *mclk;
 
-   struct completion   done;
-
const u8*tx_buf;
u8  *rx_buf;
int len;
@@ -213,13 +211,36 @@ static size_t sun4i_spi_max_transfer_size(struct 
spi_device *spi)
return SUN4I_FIFO_DEPTH;
 }
 
+static int sun4i_spi_wait_for_transfer(struct spi_device *spi,
+  struct spi_transfer *tfr)
+{
+   struct spi_master *master = spi->master;
+   unsigned int start, end, tx_time;
+   unsigned int timeout;
+
+   /* calc required timeout from given speed & len values */
+   tx_time = max(tfr->len * 8 * 2 / (tfr->speed_hz / 1000), 100U);
+   start = jiffies;
+   timeout = wait_for_completion_timeout(&master->xfer_completion,
+ msecs_to_jiffies(tx_time));
+   end = jiffies;
+   if (!timeout) {
+   dev_warn(&master->dev,
+"%s: timeout transferring %u bytes@%iHz for %i(%i)ms",
+dev_name(&spi->dev), tfr->len, tfr->speed_hz,
+jiffies_to_msecs(end - start), tx_time);
+   return -ETIMEDOUT;
+   }
+
+   return 0;
+}
+
 static int sun4i_spi_transfer_one(struct spi_master *master,
  struct spi_device *spi,
  struct spi_transfer *tfr)
 {
struct sun4i_spi *sspi = spi_master_get_devdata(master);
-   unsigned int mclk_rate, div, timeout;
-   unsigned int start, end, tx_time;
+   unsigned int mclk_rate, div;
unsigned int tx_len = 0;
int ret = 0;
u32 reg;
@@ -228,7 +249,6 @@ static int sun4i_spi_transfer_one(struct spi_master *master,
if (tfr->len > SUN4I_FIFO_DEPTH)
return -EMSGSIZE;
 
-   reinit_completion(&sspi->done);
sspi->tx_buf = tfr->tx_buf;
sspi->rx_buf = tfr->rx_buf;
sspi->len = tfr->len;
@@ -328,22 +348,8 @@ static int sun4i_spi_transfer_one(struct spi_master 
*master,
reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
sun4i_spi_write(sspi, SUN4I_CTL_REG, reg | SUN4I_CTL_XCH);
 
-   tx_time = max(tfr->len * 8 * 2 / (tfr->speed_hz / 1000), 100U);
-   start = jiffies;
-   timeout = wait_for_completion_timeout(&sspi->done,
- msecs_to_jiffies(tx_time));
-   end = jiffies;
-   if (!timeout) {
-   dev_warn(&master->dev,
-"%s: timeout transferring %u bytes@%iHz for %i(%i)ms",
-dev_name(&spi->dev), tfr->len, tfr->speed_hz,
-jiffies_to_msecs(end - start), tx_time);
-   ret = -ETIMEDOUT;
-   goto out;
-   }
-
+   ret = sun4i_spi_wait_for_transfer(spi, tfr);
 
-out:
sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, 0);
 
return ret;
@@ -351,14 +357,18 @@ out:
 
 static irqreturn_t sun4i_spi_handler(int irq, void *dev_id)
 {
-   struct sun4i_spi *sspi = dev_id;
-   u32 status = sun4i_spi_read(sspi, SUN4I_INT_STA_REG);
+   struct spi_master *master = dev_id;
+   struct sun4i_spi *sspi = spi_master_get_devdata(master);
+   u32 status;
+
+   status = sun4i_spi_read(sspi, SUN4I_INT_STA_REG);
 
/* Transfer complete */
if (status & SUN4I_INT_CTL_TC) {
-   sun4i_spi_write(sspi, SUN4I_INT_STA_REG, SUN4I_INT_CTL_TC);
+   sun4i_spi_write(sspi, SUN4I_INT_STA_REG,
+   SUN4I_INT_CTL_TC);
sun4i_spi_drain_fifo(sspi, SUN4I_FIFO_DEPTH);
-   complete(&sspi->done);
+   spi_finalize_current_transfer(master);
return IRQ_HANDLED;
}
 
@@ -447,7 +457,7 @@ static int sun4i_spi_probe(struct platform_device *pdev)
}
 
ret = devm_request_irq(&pdev->dev, irq, sun4i_spi_handler,
-  0, dev_name(&pdev->dev), sspi);
+  0, dev_name(&pdev->dev), master);
if (ret) {
dev_err(&pdev->dev, "Cannot request IRQ\n");
goto err_free_master;
@@ -467,8 +477,6 @@ static int sun4i_spi_probe(stru

[PATCH 3/6] spi: sun4i: coding style/readability improvements

2018-03-29 Thread Sergey Suloev
Minor changes to fulfill the coding style and
improve the readability.

Signed-off-by: Sergey Suloev 

---
 drivers/spi/spi-sun4i.c | 32 +---
 1 file changed, 17 insertions(+), 15 deletions(-)

diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c
index 2a49c22..2d716f1 100644
--- a/drivers/spi/spi-sun4i.c
+++ b/drivers/spi/spi-sun4i.c
@@ -83,8 +83,11 @@
 #define SUN4I_FIFO_STA_TF_CNT_MASK 0x7f
 #define SUN4I_FIFO_STA_TF_CNT_BITS 16
 
+#define SUN4I_SPI_MAX_SPEED_HZ 100 * 1000 * 1000
+#define SUN4I_SPI_MIN_SPEED_HZ 3 * 1000
+#define SUN4I_SPI_MODE_BITS(SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | 
SPI_LSB_FIRST)
+
 struct sun4i_spi {
-   struct spi_master   *master;
void __iomem*base_addr;
struct clk  *hclk;
struct clk  *mclk;
@@ -409,12 +412,23 @@ static int sun4i_spi_probe(struct platform_device *pdev)
struct resource *res;
int ret = 0, irq;
 
-   master = spi_alloc_master(&pdev->dev, sizeof(struct sun4i_spi));
+   master = spi_alloc_master(&pdev->dev, sizeof(*sspi));
if (!master) {
dev_err(&pdev->dev, "Unable to allocate SPI Master\n");
return -ENOMEM;
}
 
+   master->max_speed_hz = SUN4I_SPI_MAX_SPEED_HZ;
+   master->min_speed_hz = SUN4I_SPI_MIN_SPEED_HZ;
+   master->num_chipselect = 4;
+   master->mode_bits = SUN4I_SPI_MODE_BITS;
+   master->bits_per_word_mask = SPI_BPW_MASK(8);
+   master->set_cs = sun4i_spi_set_cs;
+   master->transfer_one = sun4i_spi_transfer_one;
+   master->max_transfer_size = sun4i_spi_max_transfer_size;
+   master->dev.of_node = pdev->dev.of_node;
+   master->auto_runtime_pm = true;
+
platform_set_drvdata(pdev, master);
sspi = spi_master_get_devdata(master);
 
@@ -433,24 +447,12 @@ static int sun4i_spi_probe(struct platform_device *pdev)
}
 
ret = devm_request_irq(&pdev->dev, irq, sun4i_spi_handler,
-  0, "sun4i-spi", sspi);
+  0, dev_name(&pdev->dev), sspi);
if (ret) {
dev_err(&pdev->dev, "Cannot request IRQ\n");
goto err_free_master;
}
 
-   sspi->master = master;
-   master->max_speed_hz = 100 * 1000 * 1000;
-   master->min_speed_hz = 3 * 1000;
-   master->set_cs = sun4i_spi_set_cs;
-   master->transfer_one = sun4i_spi_transfer_one;
-   master->num_chipselect = 4;
-   master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
-   master->bits_per_word_mask = SPI_BPW_MASK(8);
-   master->dev.of_node = pdev->dev.of_node;
-   master->auto_runtime_pm = true;
-   master->max_transfer_size = sun4i_spi_max_transfer_size;
-
sspi->hclk = devm_clk_get(&pdev->dev, "ahb");
if (IS_ERR(sspi->hclk)) {
dev_err(&pdev->dev, "Unable to acquire AHB clock\n");
-- 
2.16.2



[PATCH 2/6] spi: sun4i: restrict transfer length in PIO-mode

2018-03-29 Thread Sergey Suloev
There is no need to handle 3/4 empty/full interrupts
as the maximum supported transfer length in PIO mode
is 64 bytes for sun4i-family SoCs. As long as a
problem was reported previously with filling FIFO
on A10s then we stick with 63 bytes depth.

Signed-off-by: Sergey Suloev 

---
 drivers/spi/spi-sun4i.c | 50 -
 1 file changed, 12 insertions(+), 38 deletions(-)

diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c
index 4141003..2a49c22 100644
--- a/drivers/spi/spi-sun4i.c
+++ b/drivers/spi/spi-sun4i.c
@@ -22,7 +22,12 @@
 
 #include 
 
-#define SUN4I_FIFO_DEPTH   64
+/*
+ * FIFO length is 64 bytes
+ * But filling the FIFO fully might cause a timeout
+ * on some devices, for example on spi2 on A10s
+ */
+#define SUN4I_FIFO_DEPTH   63
 
 #define SUN4I_RXDATA_REG   0x00
 
@@ -202,7 +207,7 @@ static void sun4i_spi_set_cs(struct spi_device *spi, bool 
enable)
 
 static size_t sun4i_spi_max_transfer_size(struct spi_device *spi)
 {
-   return SUN4I_FIFO_DEPTH - 1;
+   return SUN4I_FIFO_DEPTH;
 }
 
 static int sun4i_spi_transfer_one(struct spi_master *master,
@@ -216,11 +221,8 @@ static int sun4i_spi_transfer_one(struct spi_master 
*master,
int ret = 0;
u32 reg;
 
-   /* We don't support transfer larger than the FIFO */
-   if (tfr->len > SUN4I_MAX_XFER_SIZE)
-   return -EMSGSIZE;
-
-   if (tfr->tx_buf && tfr->len >= SUN4I_MAX_XFER_SIZE)
+   /* We don't support transfers larger than FIFO depth */
+   if (tfr->len > SUN4I_FIFO_DEPTH)
return -EMSGSIZE;
 
reinit_completion(&sspi->done);
@@ -313,17 +315,11 @@ static int sun4i_spi_transfer_one(struct spi_master 
*master,
 
/*
 * Fill the TX FIFO
-* Filling the FIFO fully causes timeout for some reason
-* at least on spi2 on A10s
 */
-   sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH - 1);
+   sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH);
 
-   /* Enable the interrupts */
-   sun4i_spi_enable_interrupt(sspi, SUN4I_INT_CTL_TC |
-SUN4I_INT_CTL_RF_F34);
-   /* Only enable Tx FIFO interrupt if we really need it */
-   if (tx_len > SUN4I_FIFO_DEPTH)
-   sun4i_spi_enable_interrupt(sspi, SUN4I_INT_CTL_TF_E34);
+   /* Enable the transfer complete interrupt */
+   sun4i_spi_enable_interrupt(sspi, SUN4I_INT_CTL_TC);
 
/* Start the transfer */
reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
@@ -363,28 +359,6 @@ static irqreturn_t sun4i_spi_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
 
-   /* Receive FIFO 3/4 full */
-   if (status & SUN4I_INT_CTL_RF_F34) {
-   sun4i_spi_drain_fifo(sspi, SUN4I_FIFO_DEPTH);
-   /* Only clear the interrupt _after_ draining the FIFO */
-   sun4i_spi_write(sspi, SUN4I_INT_STA_REG, SUN4I_INT_CTL_RF_F34);
-   return IRQ_HANDLED;
-   }
-
-   /* Transmit FIFO 3/4 empty */
-   if (status & SUN4I_INT_CTL_TF_E34) {
-   sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH);
-
-   if (!sspi->len)
-   /* nothing left to transmit */
-   sun4i_spi_disable_interrupt(sspi, SUN4I_INT_CTL_TF_E34);
-
-   /* Only clear the interrupt _after_ re-seeding the FIFO */
-   sun4i_spi_write(sspi, SUN4I_INT_STA_REG, SUN4I_INT_CTL_TF_E34);
-
-   return IRQ_HANDLED;
-   }
-
return IRQ_NONE;
 }
 
-- 
2.16.2



[PATCH 4/6] spi: sun6i: use completion provided by SPI core

2018-03-30 Thread Sergey Suloev
As long as the completion is already provided by the SPI core
then there is no need to waste extra-memory on this.
Also a waiting function was added to avoid code duplication.

Signed-off-by: Sergey Suloev 

---
 drivers/spi/spi-sun6i.c | 50 -
 1 file changed, 29 insertions(+), 21 deletions(-)

diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index 13396bd..fc43752 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -99,8 +99,6 @@ struct sun6i_spi {
struct clk  *mclk;
struct reset_control*rstc;
 
-   struct completion   done;
-
const u8*tx_buf;
u8  *rx_buf;
int len;
@@ -255,6 +253,30 @@ static int sun6i_spi_prepare_message(struct spi_master 
*master,
return 0;
 }
 
+static int sun6i_spi_wait_for_transfer(struct spi_device *spi,
+  struct spi_transfer *tfr)
+{
+   struct spi_master *master = spi->master;
+   unsigned int start, end, tx_time;
+   unsigned int timeout;
+
+   /* smart wait for completion */
+   tx_time = max(tfr->len * 8 * 2 / (tfr->speed_hz / 1000), 100U);
+   start = jiffies;
+   timeout = wait_for_completion_timeout(&master->xfer_completion,
+ msecs_to_jiffies(tx_time));
+   end = jiffies;
+   if (!timeout) {
+   dev_warn(&master->dev,
+"%s: timeout transferring %u bytes@%iHz for %i(%i)ms",
+dev_name(&spi->dev), tfr->len, tfr->speed_hz,
+jiffies_to_msecs(end - start), tx_time);
+   return -ETIMEDOUT;
+   }
+
+   return 0;
+}
+
 static int sun6i_spi_transfer_one(struct spi_master *master,
  struct spi_device *spi,
  struct spi_transfer *tfr)
@@ -275,7 +297,6 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
if (tfr->len > sspi->fifo_depth)
return -EMSGSIZE;
 
-   reinit_completion(&sspi->done);
sspi->tx_buf = tfr->tx_buf;
sspi->rx_buf = tfr->rx_buf;
sspi->len = tfr->len;
@@ -342,21 +363,9 @@ static int sun6i_spi_transfer_one(struct spi_master 
*master,
reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg | SUN6I_TFR_CTL_XCH);
 
-   tx_time = max(tfr->len * 8 * 2 / (tfr->speed_hz / 1000), 100U);
-   start = jiffies;
-   timeout = wait_for_completion_timeout(&sspi->done,
- msecs_to_jiffies(tx_time));
-   end = jiffies;
-   if (!timeout) {
-   dev_warn(&master->dev,
-"%s: timeout transferring %u bytes@%iHz for %i(%i)ms",
-dev_name(&spi->dev), tfr->len, tfr->speed_hz,
-jiffies_to_msecs(end - start), tx_time);
-   ret = -ETIMEDOUT;
-   goto out;
-   }
+   /* Wait for completion */
+   ret = sun6i_spi_wait_for_transfer(spi, tfr);
 
-out:
sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, 0);
 
return ret;
@@ -364,7 +373,8 @@ out:
 
 static irqreturn_t sun6i_spi_handler(int irq, void *dev_id)
 {
-   struct sun6i_spi *sspi = dev_id;
+   struct spi_master *master = dev_id;
+   struct sun6i_spi *sspi = spi_master_get_devdata(master);
u32 status;
 
status = sun6i_spi_read(sspi, SUN6I_INT_STA_REG);
@@ -373,7 +383,7 @@ static irqreturn_t sun6i_spi_handler(int irq, void *dev_id)
if (status & SUN6I_INT_CTL_TC) {
sun6i_spi_write(sspi, SUN6I_INT_STA_REG, SUN6I_INT_CTL_TC);
sun6i_spi_drain_fifo(sspi, sspi->fifo_depth);
-   complete(&sspi->done);
+   spi_finalize_current_transfer(master);
return IRQ_HANDLED;
}
 
@@ -494,8 +504,6 @@ static int sun6i_spi_probe(struct platform_device *pdev)
goto err_free_master;
}
 
-   init_completion(&sspi->done);
-
sspi->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
if (IS_ERR(sspi->rstc)) {
dev_err(&pdev->dev, "Couldn't get reset controller\n");
-- 
2.16.2



[PATCH 5/6] spi: sun6i: introduce register set/unset helpers

2018-03-30 Thread Sergey Suloev
Two helper functions were added in order to update
registers easily.

Signed-off-by: Sergey Suloev 

---
 drivers/spi/spi-sun6i.c | 31 +++
 1 file changed, 15 insertions(+), 16 deletions(-)

diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index fc43752..a6e6812 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -115,29 +115,29 @@ static inline void sun6i_spi_write(struct sun6i_spi 
*sspi, u32 reg, u32 value)
writel(value, sspi->base_addr + reg);
 }
 
-static inline u32 sun6i_spi_get_tx_fifo_count(struct sun6i_spi *sspi)
+static inline void sun6i_spi_set(struct sun6i_spi *sspi, u32 addr, u32 val)
 {
-   u32 reg = sun6i_spi_read(sspi, SUN6I_FIFO_STA_REG);
-
-   reg >>= SUN6I_FIFO_STA_TF_CNT_BITS;
+   u32 reg = sun6i_spi_read(sspi, addr);
 
-   return reg & SUN6I_FIFO_STA_TF_CNT_MASK;
+   reg |= val;
+   sun6i_spi_write(sspi, addr, reg);
 }
 
-static inline void sun6i_spi_enable_interrupt(struct sun6i_spi *sspi, u32 mask)
+static inline void sun6i_spi_unset(struct sun6i_spi *sspi, u32 addr, u32 val)
 {
-   u32 reg = sun6i_spi_read(sspi, SUN6I_INT_CTL_REG);
+   u32 reg = sun6i_spi_read(sspi, addr);
 
-   reg |= mask;
-   sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, reg);
+   reg &= ~val;
+   sun6i_spi_write(sspi, addr, reg);
 }
 
-static inline void sun6i_spi_disable_interrupt(struct sun6i_spi *sspi, u32 
mask)
+static inline u32 sun6i_spi_get_tx_fifo_count(struct sun6i_spi *sspi)
 {
-   u32 reg = sun6i_spi_read(sspi, SUN6I_INT_CTL_REG);
+   u32 reg = sun6i_spi_read(sspi, SUN6I_FIFO_STA_REG);
+
+   reg >>= SUN6I_FIFO_STA_TF_CNT_BITS;
 
-   reg &= ~mask;
-   sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, reg);
+   return reg & SUN6I_FIFO_STA_TF_CNT_MASK;
 }
 
 static inline void sun6i_spi_drain_fifo(struct sun6i_spi *sspi, int len)
@@ -357,11 +357,10 @@ static int sun6i_spi_transfer_one(struct spi_master 
*master,
sun6i_spi_fill_fifo(sspi, sspi->fifo_depth);
 
/* Enable transfer complete interrupt */
-   sun6i_spi_enable_interrupt(sspi, SUN6I_INT_CTL_TC);
+   sun6i_spi_set(sspi, SUN6I_INT_CTL_REG, SUN6I_INT_CTL_TC);
 
/* Start the transfer */
-   reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
-   sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg | SUN6I_TFR_CTL_XCH);
+   sun6i_spi_set(sspi, SUN6I_TFR_CTL_REG, SUN6I_TFR_CTL_XCH);
 
/* Wait for completion */
ret = sun6i_spi_wait_for_transfer(spi, tfr);
-- 
2.16.2



[PATCH 6/6] spi: sun6i: add DMA transfers support

2018-03-30 Thread Sergey Suloev
DMA transfers are now available for sun6i and sun8i SoCs.
The DMA mode is used automatically as soon as requested
transfer length is more than FIFO length.

Signed-off-by: Sergey Suloev 

---
 drivers/spi/spi-sun6i.c | 296 
 1 file changed, 275 insertions(+), 21 deletions(-)

diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index a6e6812..e74fa3d 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -14,6 +14,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -55,11 +57,14 @@
 
 #define SUN6I_FIFO_CTL_REG 0x18
 #define SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_MASK  0xff
-#define SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_BITS  0
+#define SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_POS   0
+#define SUN6I_FIFO_CTL_RF_DRQ_EN   BIT(8)
 #define SUN6I_FIFO_CTL_RF_RST  BIT(15)
 #define SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_MASK  0xff
-#define SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_BITS  16
+#define SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_POS   16
+#define SUN6I_FIFO_CTL_TF_DRQ_EN   BIT(24)
 #define SUN6I_FIFO_CTL_TF_RST  BIT(31)
+#define SUN6I_FIFO_CTL_DMA_DEDICATEBIT(9)|BIT(25)
 
 #define SUN6I_FIFO_STA_REG 0x1c
 #define SUN6I_FIFO_STA_RF_CNT_MASK 0x7f
@@ -177,6 +182,15 @@ static inline void sun6i_spi_fill_fifo(struct sun6i_spi 
*sspi, int len)
}
 }
 
+static bool sun6i_spi_can_dma(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *tfr)
+{
+   struct sun6i_spi *sspi = spi_master_get_devdata(master);
+
+   return tfr->len > sspi->fifo_depth;
+}
+
 static void sun6i_spi_set_cs(struct spi_device *spi, bool enable)
 {
struct sun6i_spi *sspi = spi_master_get_devdata(spi->master);
@@ -208,6 +222,9 @@ static size_t sun6i_spi_max_transfer_size(struct spi_device 
*spi)
struct spi_master *master = spi->master;
struct sun6i_spi *sspi = spi_master_get_devdata(master);
 
+   if (master->can_dma)
+   return SUN6I_MAX_XFER_SIZE;
+
return sspi->fifo_depth;
 }
 
@@ -277,15 +294,174 @@ static int sun6i_spi_wait_for_transfer(struct spi_device 
*spi,
return 0;
 }
 
+static void sun6i_spi_dma_callback(void *param)
+{
+   struct spi_master *master = param;
+
+   dev_dbg(&master->dev, "DMA transfer complete\n");
+   spi_finalize_current_transfer(master);
+}
+
+static int sun6i_spi_dmap_prep_tx(struct spi_master *master,
+ struct spi_transfer *tfr,
+ dma_cookie_t *cookie)
+{
+   struct dma_async_tx_descriptor *chan_desc = NULL;
+
+   chan_desc = dmaengine_prep_slave_sg(master->dma_tx,
+   tfr->tx_sg.sgl, tfr->tx_sg.nents,
+   DMA_TO_DEVICE,
+   DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+   if (!chan_desc) {
+   dev_err(&master->dev,
+   "Couldn't prepare TX DMA slave\n");
+   return -EIO;
+   }
+
+   chan_desc->callback = sun6i_spi_dma_callback;
+   chan_desc->callback_param = master;
+
+   *cookie = dmaengine_submit(chan_desc);
+   dma_async_issue_pending(master->dma_tx);
+
+   return 0;
+}
+
+static int sun6i_spi_dmap_prep_rx(struct spi_master *master,
+ struct spi_transfer *tfr,
+ dma_cookie_t *cookie)
+{
+   struct dma_async_tx_descriptor *chan_desc = NULL;
+
+   chan_desc = dmaengine_prep_slave_sg(master->dma_rx,
+   tfr->rx_sg.sgl, tfr->rx_sg.nents,
+   DMA_FROM_DEVICE,
+   DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+   if (!chan_desc) {
+   dev_err(&master->dev,
+   "Couldn't prepare RX DMA slave\n");
+   return -EIO;
+   }
+
+   chan_desc->callback = sun6i_spi_dma_callback;
+   chan_desc->callback_param = master;
+
+   *cookie = dmaengine_submit(chan_desc);
+   dma_async_issue_pending(master->dma_rx);
+
+   return 0;
+}
+
+static int sun6i_spi_transfer_one_dma(struct spi_device *spi,
+ struct spi_transfer *tfr)
+{
+   struct spi_master *master = spi->master;
+   struct sun6i_spi *sspi = spi_master_get_devdata(master);
+   dma_cookie_t tx_cookie = 0,rx_cookie = 0;
+   enum dma_status status;
+   int ret;
+   u32 reg, trig_level = 0;
+
+   dev_dbg(&master->dev, "Using DMA mode for transfer\n");
+
+   reg = sun6i_spi_read(sspi, SUN6I_FIFO_CTL_REG);
+
+   if (sspi-&

[PATCH 3/6] spi: sun6i: restrict transfer length in PIO-mode

2018-03-30 Thread Sergey Suloev
There is no need to handle 3/4 empty/full interrupts as
the maximum supported transfer length in PIO mode is
128 bytes for sun6i- and 64 bytes for sun8i-family SoCs.

Signed-off-by: Sergey Suloev 

---
 drivers/spi/spi-sun6i.c | 61 ++---
 1 file changed, 17 insertions(+), 44 deletions(-)

diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index f992a7d..13396bd 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -207,7 +207,10 @@ static void sun6i_spi_set_cs(struct spi_device *spi, bool 
enable)
 
 static size_t sun6i_spi_max_transfer_size(struct spi_device *spi)
 {
-   return SUN6I_MAX_XFER_SIZE - 1;
+   struct spi_master *master = spi->master;
+   struct sun6i_spi *sspi = spi_master_get_devdata(master);
+
+   return sspi->fifo_depth;
 }
 
 static int sun6i_spi_prepare_message(struct spi_master *master,
@@ -259,13 +262,18 @@ static int sun6i_spi_transfer_one(struct spi_master 
*master,
struct sun6i_spi *sspi = spi_master_get_devdata(master);
unsigned int mclk_rate, div, timeout;
unsigned int start, end, tx_time;
-   unsigned int trig_level;
unsigned int tx_len = 0;
int ret = 0;
u32 reg;
 
-   if (tfr->len > SUN6I_MAX_XFER_SIZE)
-   return -EINVAL;
+   /* A zero length transfer never finishes if programmed
+  in the hardware */
+   if (!tfr->len)
+   return 0;
+
+   /* Don't support transfer larger than the FIFO */
+   if (tfr->len > sspi->fifo_depth)
+   return -EMSGSIZE;
 
reinit_completion(&sspi->done);
sspi->tx_buf = tfr->tx_buf;
@@ -279,17 +287,6 @@ static int sun6i_spi_transfer_one(struct spi_master 
*master,
sun6i_spi_write(sspi, SUN6I_FIFO_CTL_REG,
SUN6I_FIFO_CTL_RF_RST | SUN6I_FIFO_CTL_TF_RST);
 
-   /*
-* Setup FIFO interrupt trigger level
-* Here we choose 3/4 of the full fifo depth, as it's the hardcoded
-* value used in old generation of Allwinner SPI controller.
-* (See spi-sun4i.c)
-*/
-   trig_level = sspi->fifo_depth / 4 * 3;
-   sun6i_spi_write(sspi, SUN6I_FIFO_CTL_REG,
-   (trig_level << SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_BITS) |
-   (trig_level << SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_BITS));
-
 
/* Ensure that we have a parent clock fast enough */
mclk_rate = clk_get_rate(sspi->mclk);
@@ -338,12 +335,8 @@ static int sun6i_spi_transfer_one(struct spi_master 
*master,
/* Fill the TX FIFO */
sun6i_spi_fill_fifo(sspi, sspi->fifo_depth);
 
-   /* Enable the interrupts */
-   sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, SUN6I_INT_CTL_TC);
-   sun6i_spi_enable_interrupt(sspi, SUN6I_INT_CTL_TC |
-SUN6I_INT_CTL_RF_RDY);
-   if (tx_len > sspi->fifo_depth)
-   sun6i_spi_enable_interrupt(sspi, SUN6I_INT_CTL_TF_ERQ);
+   /* Enable transfer complete interrupt */
+   sun6i_spi_enable_interrupt(sspi, SUN6I_INT_CTL_TC);
 
/* Start the transfer */
reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
@@ -372,7 +365,9 @@ out:
 static irqreturn_t sun6i_spi_handler(int irq, void *dev_id)
 {
struct sun6i_spi *sspi = dev_id;
-   u32 status = sun6i_spi_read(sspi, SUN6I_INT_STA_REG);
+   u32 status;
+
+   status = sun6i_spi_read(sspi, SUN6I_INT_STA_REG);
 
/* Transfer complete */
if (status & SUN6I_INT_CTL_TC) {
@@ -382,28 +377,6 @@ static irqreturn_t sun6i_spi_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
 
-   /* Receive FIFO 3/4 full */
-   if (status & SUN6I_INT_CTL_RF_RDY) {
-   sun6i_spi_drain_fifo(sspi, SUN6I_FIFO_DEPTH);
-   /* Only clear the interrupt _after_ draining the FIFO */
-   sun6i_spi_write(sspi, SUN6I_INT_STA_REG, SUN6I_INT_CTL_RF_RDY);
-   return IRQ_HANDLED;
-   }
-
-   /* Transmit FIFO 3/4 empty */
-   if (status & SUN6I_INT_CTL_TF_ERQ) {
-   sun6i_spi_fill_fifo(sspi, SUN6I_FIFO_DEPTH);
-
-   if (!sspi->len)
-   /* nothing left to transmit */
-   sun6i_spi_disable_interrupt(sspi, SUN6I_INT_CTL_TF_ERQ);
-
-   /* Only clear the interrupt _after_ re-seeding the FIFO */
-   sun6i_spi_write(sspi, SUN6I_INT_STA_REG, SUN6I_INT_CTL_TF_ERQ);
-
-   return IRQ_HANDLED;
-   }
-
return IRQ_NONE;
 }
 
-- 
2.16.2



[PATCH 2/6] spi: sun6i: handle chip select polarity flag

2018-03-30 Thread Sergey Suloev
The chip select polarity flag is declared as supported
but is not handled in the code.

Signed-off-by: Sergey Suloev 

---
 drivers/spi/spi-sun6i.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index ff790dc..f992a7d 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -193,6 +193,12 @@ static void sun6i_spi_set_cs(struct spi_device *spi, bool 
enable)
else
reg &= ~SUN6I_TFR_CTL_CS_LEVEL;
 
+   /* Handle chip select "reverse" polarity */
+   if (spi->mode & SPI_CS_HIGH)
+   reg &= ~SUN6I_TFR_CTL_SPOL;
+   else
+   reg |= SUN6I_TFR_CTL_SPOL;
+
/* We want to control the chip select manually */
reg |= SUN6I_TFR_CTL_CS_MANUAL;
 
-- 
2.16.2



[PATCH 0/6] spi: Add support for DMA transfers in sun6i SPI driver

2018-03-30 Thread Sergey Suloev
The following patchset provides corrections for PIO-mode
and support for DMA transfers in sun6i SPI driver.

Sergey Suloev (6):
  spi: sun6i: coding style/readability improvements
  spi: sun6i: handle chip select polarity flag
  spi: sun6i: restrict transfer length in PIO-mode
  spi: sun6i: use completion provided by SPI core
  spi: sun6i: introduce register set/unset helpers
  spi: sun6i: add DMA transfers support

 drivers/spi/spi-sun6i.c | 501 
 1 file changed, 378 insertions(+), 123 deletions(-)

-- 
2.16.2



[PATCH 1/6] spi: sun6i: coding style/readability improvements

2018-03-30 Thread Sergey Suloev
Minor changes to fulfill the coding style and
improve the readability.

Signed-off-by: Sergey Suloev 

---
 drivers/spi/spi-sun6i.c | 115 +++-
 1 file changed, 65 insertions(+), 50 deletions(-)

diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index 8533f4e..ff790dc 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -88,8 +88,12 @@
 #define SUN6I_TXDATA_REG   0x200
 #define SUN6I_RXDATA_REG   0x300
 
+#define SUN6I_SPI_MODE_BITS(SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | 
SPI_LSB_FIRST)
+
+#define SUN6I_SPI_MAX_SPEED_HZ 1
+#define SUN6I_SPI_MIN_SPEED_HZ 3000
+
 struct sun6i_spi {
-   struct spi_master   *master;
void __iomem*base_addr;
struct clk  *hclk;
struct clk  *mclk;
@@ -189,6 +193,9 @@ static void sun6i_spi_set_cs(struct spi_device *spi, bool 
enable)
else
reg &= ~SUN6I_TFR_CTL_CS_LEVEL;
 
+   /* We want to control the chip select manually */
+   reg |= SUN6I_TFR_CTL_CS_MANUAL;
+
sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
 }
 
@@ -197,6 +204,48 @@ static size_t sun6i_spi_max_transfer_size(struct 
spi_device *spi)
return SUN6I_MAX_XFER_SIZE - 1;
 }
 
+static int sun6i_spi_prepare_message(struct spi_master *master,
+struct spi_message *msg)
+{
+   struct spi_device *spi = msg->spi;
+   struct sun6i_spi *sspi = spi_master_get_devdata(master);
+   u32 reg;
+
+   /*
+* Setup the transfer control register: Chip Select,
+* polarities, etc.
+*/
+   reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
+
+   if (spi->mode & SPI_CPOL)
+   reg |= SUN6I_TFR_CTL_CPOL;
+   else
+   reg &= ~SUN6I_TFR_CTL_CPOL;
+
+   if (spi->mode & SPI_CPHA)
+   reg |= SUN6I_TFR_CTL_CPHA;
+   else
+   reg &= ~SUN6I_TFR_CTL_CPHA;
+
+   if (spi->mode & SPI_LSB_FIRST)
+   reg |= SUN6I_TFR_CTL_FBS;
+   else
+   reg &= ~SUN6I_TFR_CTL_FBS;
+
+   /*
+* If it's a TX only transfer, we don't want to fill the RX
+* FIFO with bogus data
+*/
+   if (sspi->rx_buf)
+   reg &= ~SUN6I_TFR_CTL_DHB;
+   else
+   reg |= SUN6I_TFR_CTL_DHB;
+
+   sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
+
+   return 0;
+}
+
 static int sun6i_spi_transfer_one(struct spi_master *master,
  struct spi_device *spi,
  struct spi_transfer *tfr)
@@ -235,40 +284,6 @@ static int sun6i_spi_transfer_one(struct spi_master 
*master,
(trig_level << SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_BITS) |
(trig_level << SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_BITS));
 
-   /*
-* Setup the transfer control register: Chip Select,
-* polarities, etc.
-*/
-   reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
-
-   if (spi->mode & SPI_CPOL)
-   reg |= SUN6I_TFR_CTL_CPOL;
-   else
-   reg &= ~SUN6I_TFR_CTL_CPOL;
-
-   if (spi->mode & SPI_CPHA)
-   reg |= SUN6I_TFR_CTL_CPHA;
-   else
-   reg &= ~SUN6I_TFR_CTL_CPHA;
-
-   if (spi->mode & SPI_LSB_FIRST)
-   reg |= SUN6I_TFR_CTL_FBS;
-   else
-   reg &= ~SUN6I_TFR_CTL_FBS;
-
-   /*
-* If it's a TX only transfer, we don't want to fill the RX
-* FIFO with bogus data
-*/
-   if (sspi->rx_buf)
-   reg &= ~SUN6I_TFR_CTL_DHB;
-   else
-   reg |= SUN6I_TFR_CTL_DHB;
-
-   /* We want to control the chip select manually */
-   reg |= SUN6I_TFR_CTL_CS_MANUAL;
-
-   sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
 
/* Ensure that we have a parent clock fast enough */
mclk_rate = clk_get_rate(sspi->mclk);
@@ -442,12 +457,24 @@ static int sun6i_spi_probe(struct platform_device *pdev)
struct resource *res;
int ret = 0, irq;
 
-   master = spi_alloc_master(&pdev->dev, sizeof(struct sun6i_spi));
+   master = spi_alloc_master(&pdev->dev, sizeof(*sspi));
if (!master) {
dev_err(&pdev->dev, "Unable to allocate SPI Master\n");
return -ENOMEM;
}
 
+   master->max_speed_hz = SUN6I_SPI_MAX_SPEED_HZ;
+   master->min_speed_hz = SUN6I_SPI_MIN_SPEED_HZ;
+   master->num_chipselect = 4;
+   master->mode_bits = SUN6I_SPI_MODE_BITS;
+   master->bits_per_word_mask = SPI_BPW_MASK(8);
+   master->set_cs = sun6i_spi_set_cs;
+   master->prepare_message = sun6i_spi_prepare_message;
+   master->transfer_one =

[PATCH v2 2/6] spi: sun6i: handle chip select polarity flag

2018-03-30 Thread Sergey Suloev
The chip select polarity flag is declared as supported
but is not handled in the code.

Signed-off-by: Sergey Suloev 

---
 drivers/spi/spi-sun6i.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index 88ad45e..78acc1f 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -193,6 +193,12 @@ static void sun6i_spi_set_cs(struct spi_device *spi, bool 
enable)
else
reg &= ~SUN6I_TFR_CTL_CS_LEVEL;
 
+   /* Handle chip select "reverse" polarity */
+   if (spi->mode & SPI_CS_HIGH)
+   reg &= ~SUN6I_TFR_CTL_SPOL;
+   else
+   reg |= SUN6I_TFR_CTL_SPOL;
+
/* We want to control the chip select manually */
reg |= SUN6I_TFR_CTL_CS_MANUAL;
 
-- 
2.16.2



[PATCH v2 6/6] spi: sun6i: add DMA transfers support

2018-03-30 Thread Sergey Suloev
DMA transfers are now available for sun6i and sun8i SoCs.
The DMA mode is used automatically as soon as requested
transfer length is more than FIFO length.

Signed-off-by: Sergey Suloev 

---
 drivers/spi/spi-sun6i.c | 296 
 1 file changed, 275 insertions(+), 21 deletions(-)

diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index 18f9344..5665c84 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -14,6 +14,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -55,11 +57,14 @@
 
 #define SUN6I_FIFO_CTL_REG 0x18
 #define SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_MASK  0xff
-#define SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_BITS  0
+#define SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_POS   0
+#define SUN6I_FIFO_CTL_RF_DRQ_EN   BIT(8)
 #define SUN6I_FIFO_CTL_RF_RST  BIT(15)
 #define SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_MASK  0xff
-#define SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_BITS  16
+#define SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_POS   16
+#define SUN6I_FIFO_CTL_TF_DRQ_EN   BIT(24)
 #define SUN6I_FIFO_CTL_TF_RST  BIT(31)
+#define SUN6I_FIFO_CTL_DMA_DEDICATEBIT(9)|BIT(25)
 
 #define SUN6I_FIFO_STA_REG 0x1c
 #define SUN6I_FIFO_STA_RF_CNT_MASK 0x7f
@@ -177,6 +182,15 @@ static inline void sun6i_spi_fill_fifo(struct sun6i_spi 
*sspi, int len)
}
 }
 
+static bool sun6i_spi_can_dma(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *tfr)
+{
+   struct sun6i_spi *sspi = spi_master_get_devdata(master);
+
+   return tfr->len > sspi->fifo_depth;
+}
+
 static void sun6i_spi_set_cs(struct spi_device *spi, bool enable)
 {
struct sun6i_spi *sspi = spi_master_get_devdata(spi->master);
@@ -208,6 +222,9 @@ static size_t sun6i_spi_max_transfer_size(struct spi_device 
*spi)
struct spi_master *master = spi->master;
struct sun6i_spi *sspi = spi_master_get_devdata(master);
 
+   if (master->can_dma)
+   return SUN6I_MAX_XFER_SIZE;
+
return sspi->fifo_depth;
 }
 
@@ -268,15 +285,174 @@ static int sun6i_spi_wait_for_transfer(struct spi_device 
*spi,
return 0;
 }
 
+static void sun6i_spi_dma_callback(void *param)
+{
+   struct spi_master *master = param;
+
+   dev_dbg(&master->dev, "DMA transfer complete\n");
+   spi_finalize_current_transfer(master);
+}
+
+static int sun6i_spi_dmap_prep_tx(struct spi_master *master,
+ struct spi_transfer *tfr,
+ dma_cookie_t *cookie)
+{
+   struct dma_async_tx_descriptor *chan_desc = NULL;
+
+   chan_desc = dmaengine_prep_slave_sg(master->dma_tx,
+   tfr->tx_sg.sgl, tfr->tx_sg.nents,
+   DMA_TO_DEVICE,
+   DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+   if (!chan_desc) {
+   dev_err(&master->dev,
+   "Couldn't prepare TX DMA slave\n");
+   return -EIO;
+   }
+
+   chan_desc->callback = sun6i_spi_dma_callback;
+   chan_desc->callback_param = master;
+
+   *cookie = dmaengine_submit(chan_desc);
+   dma_async_issue_pending(master->dma_tx);
+
+   return 0;
+}
+
+static int sun6i_spi_dmap_prep_rx(struct spi_master *master,
+ struct spi_transfer *tfr,
+ dma_cookie_t *cookie)
+{
+   struct dma_async_tx_descriptor *chan_desc = NULL;
+
+   chan_desc = dmaengine_prep_slave_sg(master->dma_rx,
+   tfr->rx_sg.sgl, tfr->rx_sg.nents,
+   DMA_FROM_DEVICE,
+   DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+   if (!chan_desc) {
+   dev_err(&master->dev,
+   "Couldn't prepare RX DMA slave\n");
+   return -EIO;
+   }
+
+   chan_desc->callback = sun6i_spi_dma_callback;
+   chan_desc->callback_param = master;
+
+   *cookie = dmaengine_submit(chan_desc);
+   dma_async_issue_pending(master->dma_rx);
+
+   return 0;
+}
+
+static int sun6i_spi_transfer_one_dma(struct spi_device *spi,
+ struct spi_transfer *tfr)
+{
+   struct spi_master *master = spi->master;
+   struct sun6i_spi *sspi = spi_master_get_devdata(master);
+   dma_cookie_t tx_cookie = 0,rx_cookie = 0;
+   enum dma_status status;
+   int ret;
+   u32 reg, trig_level = 0;
+
+   dev_dbg(&master->dev, "Using DMA mode for transfer\n");
+
+   reg = sun6i_spi_read(sspi, SUN6I_FIFO_CTL_REG);
+
+   if (sspi-&

[PATCH v2 0/6] spi: Add support for DMA transfers in sun6i SPI driver

2018-03-30 Thread Sergey Suloev
The following patchset provides corrections for PIO-mode
and support for DMA transfers in sun6i SPI driver.

Changes in v2:
1) Fixed issue with misplacing a piece of code that requires access
to the transfer structure into sun6i_spi_prepare_message() function
where the transfer structure is not available.

2) Fixed issue with passing an invalid argument into devm_request_irq()
function.

Sergey Suloev (6):
  spi: sun6i: coding style/readability improvements
  spi: sun6i: handle chip select polarity flag
  spi: sun6i: restrict transfer length in PIO-mode
  spi: sun6i: use completion provided by SPI core
  spi: sun6i: introduce register set/unset helpers
  spi: sun6i: add DMA transfers support

 drivers/spi/spi-sun6i.c | 507 
 1 file changed, 381 insertions(+), 126 deletions(-)

-- 
2.16.2



[PATCH v2 3/6] spi: sun6i: restrict transfer length in PIO-mode

2018-03-30 Thread Sergey Suloev
There is no need to handle 3/4 empty/full interrupts as
the maximum supported transfer length in PIO mode is
128 bytes for sun6i- and 64 bytes for sun8i-family SoCs.

Signed-off-by: Sergey Suloev 

---
 drivers/spi/spi-sun6i.c | 61 ++---
 1 file changed, 17 insertions(+), 44 deletions(-)

diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index 78acc1f..4db1f20 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -207,7 +207,10 @@ static void sun6i_spi_set_cs(struct spi_device *spi, bool 
enable)
 
 static size_t sun6i_spi_max_transfer_size(struct spi_device *spi)
 {
-   return SUN6I_MAX_XFER_SIZE - 1;
+   struct spi_master *master = spi->master;
+   struct sun6i_spi *sspi = spi_master_get_devdata(master);
+
+   return sspi->fifo_depth;
 }
 
 static int sun6i_spi_prepare_message(struct spi_master *master,
@@ -250,13 +253,18 @@ static int sun6i_spi_transfer_one(struct spi_master 
*master,
struct sun6i_spi *sspi = spi_master_get_devdata(master);
unsigned int mclk_rate, div, timeout;
unsigned int start, end, tx_time;
-   unsigned int trig_level;
unsigned int tx_len = 0;
int ret = 0;
u32 reg;
 
-   if (tfr->len > SUN6I_MAX_XFER_SIZE)
-   return -EINVAL;
+   /* A zero length transfer never finishes if programmed
+  in the hardware */
+   if (!tfr->len)
+   return 0;
+
+   /* Don't support transfer larger than the FIFO */
+   if (tfr->len > sspi->fifo_depth)
+   return -EMSGSIZE;
 
reinit_completion(&sspi->done);
sspi->tx_buf = tfr->tx_buf;
@@ -270,17 +278,6 @@ static int sun6i_spi_transfer_one(struct spi_master 
*master,
sun6i_spi_write(sspi, SUN6I_FIFO_CTL_REG,
SUN6I_FIFO_CTL_RF_RST | SUN6I_FIFO_CTL_TF_RST);
 
-   /*
-* Setup FIFO interrupt trigger level
-* Here we choose 3/4 of the full fifo depth, as it's the hardcoded
-* value used in old generation of Allwinner SPI controller.
-* (See spi-sun4i.c)
-*/
-   trig_level = sspi->fifo_depth / 4 * 3;
-   sun6i_spi_write(sspi, SUN6I_FIFO_CTL_REG,
-   (trig_level << SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_BITS) |
-   (trig_level << SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_BITS));
-
 
reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
/*
@@ -342,12 +339,8 @@ static int sun6i_spi_transfer_one(struct spi_master 
*master,
/* Fill the TX FIFO */
sun6i_spi_fill_fifo(sspi, sspi->fifo_depth);
 
-   /* Enable the interrupts */
-   sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, SUN6I_INT_CTL_TC);
-   sun6i_spi_enable_interrupt(sspi, SUN6I_INT_CTL_TC |
-SUN6I_INT_CTL_RF_RDY);
-   if (tx_len > sspi->fifo_depth)
-   sun6i_spi_enable_interrupt(sspi, SUN6I_INT_CTL_TF_ERQ);
+   /* Enable transfer complete interrupt */
+   sun6i_spi_enable_interrupt(sspi, SUN6I_INT_CTL_TC);
 
/* Start the transfer */
reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
@@ -376,7 +369,9 @@ out:
 static irqreturn_t sun6i_spi_handler(int irq, void *dev_id)
 {
struct sun6i_spi *sspi = dev_id;
-   u32 status = sun6i_spi_read(sspi, SUN6I_INT_STA_REG);
+   u32 status;
+
+   status = sun6i_spi_read(sspi, SUN6I_INT_STA_REG);
 
/* Transfer complete */
if (status & SUN6I_INT_CTL_TC) {
@@ -386,28 +381,6 @@ static irqreturn_t sun6i_spi_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
 
-   /* Receive FIFO 3/4 full */
-   if (status & SUN6I_INT_CTL_RF_RDY) {
-   sun6i_spi_drain_fifo(sspi, SUN6I_FIFO_DEPTH);
-   /* Only clear the interrupt _after_ draining the FIFO */
-   sun6i_spi_write(sspi, SUN6I_INT_STA_REG, SUN6I_INT_CTL_RF_RDY);
-   return IRQ_HANDLED;
-   }
-
-   /* Transmit FIFO 3/4 empty */
-   if (status & SUN6I_INT_CTL_TF_ERQ) {
-   sun6i_spi_fill_fifo(sspi, SUN6I_FIFO_DEPTH);
-
-   if (!sspi->len)
-   /* nothing left to transmit */
-   sun6i_spi_disable_interrupt(sspi, SUN6I_INT_CTL_TF_ERQ);
-
-   /* Only clear the interrupt _after_ re-seeding the FIFO */
-   sun6i_spi_write(sspi, SUN6I_INT_STA_REG, SUN6I_INT_CTL_TF_ERQ);
-
-   return IRQ_HANDLED;
-   }
-
return IRQ_NONE;
 }
 
-- 
2.16.2



[PATCH v2 5/6] spi: sun6i: introduce register set/unset helpers

2018-03-30 Thread Sergey Suloev
Two helper functions were added in order to update registers
easily.

Signed-off-by: Sergey Suloev 

---
 drivers/spi/spi-sun6i.c | 39 +--
 1 file changed, 17 insertions(+), 22 deletions(-)

diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index 210cef9..18f9344 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -115,29 +115,29 @@ static inline void sun6i_spi_write(struct sun6i_spi 
*sspi, u32 reg, u32 value)
writel(value, sspi->base_addr + reg);
 }
 
-static inline u32 sun6i_spi_get_tx_fifo_count(struct sun6i_spi *sspi)
+static inline void sun6i_spi_set(struct sun6i_spi *sspi, u32 addr, u32 val)
 {
-   u32 reg = sun6i_spi_read(sspi, SUN6I_FIFO_STA_REG);
-
-   reg >>= SUN6I_FIFO_STA_TF_CNT_BITS;
+   u32 reg = sun6i_spi_read(sspi, addr);
 
-   return reg & SUN6I_FIFO_STA_TF_CNT_MASK;
+   reg |= val;
+   sun6i_spi_write(sspi, addr, reg);
 }
 
-static inline void sun6i_spi_enable_interrupt(struct sun6i_spi *sspi, u32 mask)
+static inline void sun6i_spi_unset(struct sun6i_spi *sspi, u32 addr, u32 val)
 {
-   u32 reg = sun6i_spi_read(sspi, SUN6I_INT_CTL_REG);
+   u32 reg = sun6i_spi_read(sspi, addr);
 
-   reg |= mask;
-   sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, reg);
+   reg &= ~val;
+   sun6i_spi_write(sspi, addr, reg);
 }
 
-static inline void sun6i_spi_disable_interrupt(struct sun6i_spi *sspi, u32 
mask)
+static inline u32 sun6i_spi_get_tx_fifo_count(struct sun6i_spi *sspi)
 {
-   u32 reg = sun6i_spi_read(sspi, SUN6I_INT_CTL_REG);
+   u32 reg = sun6i_spi_read(sspi, SUN6I_FIFO_STA_REG);
 
-   reg &= ~mask;
-   sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, reg);
+   reg >>= SUN6I_FIFO_STA_TF_CNT_BITS;
+
+   return reg & SUN6I_FIFO_STA_TF_CNT_MASK;
 }
 
 static inline void sun6i_spi_drain_fifo(struct sun6i_spi *sspi, int len)
@@ -299,18 +299,14 @@ static int sun6i_spi_transfer_one(struct spi_master 
*master,
sun6i_spi_write(sspi, SUN6I_FIFO_CTL_REG,
SUN6I_FIFO_CTL_RF_RST | SUN6I_FIFO_CTL_TF_RST);
 
-
-   reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
/*
 * If it's a TX only transfer, we don't want to fill the RX
 * FIFO with bogus data
 */
if (sspi->rx_buf)
-   reg &= ~SUN6I_TFR_CTL_DHB;
+   sun6i_spi_unset(sspi, SUN6I_TFR_CTL_REG, SUN6I_TFR_CTL_DHB);
else
-   reg |= SUN6I_TFR_CTL_DHB;
-
-   sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
+   sun6i_spi_set(sspi, SUN6I_TFR_CTL_REG, SUN6I_TFR_CTL_DHB);
 
 
/* Ensure that we have a parent clock fast enough */
@@ -361,11 +357,10 @@ static int sun6i_spi_transfer_one(struct spi_master 
*master,
sun6i_spi_fill_fifo(sspi, sspi->fifo_depth);
 
/* Enable transfer complete interrupt */
-   sun6i_spi_enable_interrupt(sspi, SUN6I_INT_CTL_TC);
+   sun6i_spi_set(sspi, SUN6I_INT_CTL_REG, SUN6I_INT_CTL_TC);
 
/* Start the transfer */
-   reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
-   sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg | SUN6I_TFR_CTL_XCH);
+   sun6i_spi_set(sspi, SUN6I_TFR_CTL_REG, SUN6I_TFR_CTL_XCH);
 
/* Wait for completion */
ret = sun6i_spi_wait_for_transfer(spi, tfr);
-- 
2.16.2



[PATCH v2 4/6] spi: sun6i: use completion provided by SPI core

2018-03-30 Thread Sergey Suloev
As long as the completion is already provided by the SPI core
then there is no need to waste extra-memory on this.
Also a waiting function was added to avoid code duplication.

Changes in v2:
1) Fixed issue with passing an invalid argument into devm_request_irq()
function.

Signed-off-by: Sergey Suloev 

---
 drivers/spi/spi-sun6i.c | 52 -
 1 file changed, 30 insertions(+), 22 deletions(-)

diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index 4db1f20..210cef9 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -99,8 +99,6 @@ struct sun6i_spi {
struct clk  *mclk;
struct reset_control*rstc;
 
-   struct completion   done;
-
const u8*tx_buf;
u8  *rx_buf;
int len;
@@ -246,6 +244,30 @@ static int sun6i_spi_prepare_message(struct spi_master 
*master,
return 0;
 }
 
+static int sun6i_spi_wait_for_transfer(struct spi_device *spi,
+  struct spi_transfer *tfr)
+{
+   struct spi_master *master = spi->master;
+   unsigned int start, end, tx_time;
+   unsigned int timeout;
+
+   /* smart wait for completion */
+   tx_time = max(tfr->len * 8 * 2 / (tfr->speed_hz / 1000), 100U);
+   start = jiffies;
+   timeout = wait_for_completion_timeout(&master->xfer_completion,
+ msecs_to_jiffies(tx_time));
+   end = jiffies;
+   if (!timeout) {
+   dev_warn(&master->dev,
+"%s: timeout transferring %u bytes@%iHz for %i(%i)ms",
+dev_name(&spi->dev), tfr->len, tfr->speed_hz,
+jiffies_to_msecs(end - start), tx_time);
+   return -ETIMEDOUT;
+   }
+
+   return 0;
+}
+
 static int sun6i_spi_transfer_one(struct spi_master *master,
  struct spi_device *spi,
  struct spi_transfer *tfr)
@@ -266,7 +288,6 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
if (tfr->len > sspi->fifo_depth)
return -EMSGSIZE;
 
-   reinit_completion(&sspi->done);
sspi->tx_buf = tfr->tx_buf;
sspi->rx_buf = tfr->rx_buf;
sspi->len = tfr->len;
@@ -346,21 +367,9 @@ static int sun6i_spi_transfer_one(struct spi_master 
*master,
reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg | SUN6I_TFR_CTL_XCH);
 
-   tx_time = max(tfr->len * 8 * 2 / (tfr->speed_hz / 1000), 100U);
-   start = jiffies;
-   timeout = wait_for_completion_timeout(&sspi->done,
- msecs_to_jiffies(tx_time));
-   end = jiffies;
-   if (!timeout) {
-   dev_warn(&master->dev,
-"%s: timeout transferring %u bytes@%iHz for %i(%i)ms",
-dev_name(&spi->dev), tfr->len, tfr->speed_hz,
-jiffies_to_msecs(end - start), tx_time);
-   ret = -ETIMEDOUT;
-   goto out;
-   }
+   /* Wait for completion */
+   ret = sun6i_spi_wait_for_transfer(spi, tfr);
 
-out:
sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, 0);
 
return ret;
@@ -368,7 +377,8 @@ out:
 
 static irqreturn_t sun6i_spi_handler(int irq, void *dev_id)
 {
-   struct sun6i_spi *sspi = dev_id;
+   struct spi_master *master = dev_id;
+   struct sun6i_spi *sspi = spi_master_get_devdata(master);
u32 status;
 
status = sun6i_spi_read(sspi, SUN6I_INT_STA_REG);
@@ -377,7 +387,7 @@ static irqreturn_t sun6i_spi_handler(int irq, void *dev_id)
if (status & SUN6I_INT_CTL_TC) {
sun6i_spi_write(sspi, SUN6I_INT_STA_REG, SUN6I_INT_CTL_TC);
sun6i_spi_drain_fifo(sspi, sspi->fifo_depth);
-   complete(&sspi->done);
+   spi_finalize_current_transfer(master);
return IRQ_HANDLED;
}
 
@@ -476,7 +486,7 @@ static int sun6i_spi_probe(struct platform_device *pdev)
}
 
ret = devm_request_irq(&pdev->dev, irq, sun6i_spi_handler,
-  0, dev_name(&pdev->dev), sspi);
+  0, dev_name(&pdev->dev), master);
if (ret) {
dev_err(&pdev->dev, "Cannot request IRQ\n");
goto err_free_master;
@@ -498,8 +508,6 @@ static int sun6i_spi_probe(struct platform_device *pdev)
goto err_free_master;
}
 
-   init_completion(&sspi->done);
-
sspi->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
if (IS_ERR(sspi->rstc)) {
dev_err(&pdev->dev, "Couldn't get reset controller\n");
-- 
2.16.2



[PATCH v2 1/6] spi: sun6i: coding style/readability improvements

2018-03-30 Thread Sergey Suloev
Minor changes to fulfill the coding style and improve
the readability of the code.

Changes in v2:
1) Fixed issue with misplacing a piece of code that requires access
to the transfer structure into sun6i_spi_prepare_message() function
where the transfer structure is not available.

Signed-off-by: Sergey Suloev 

---
 drivers/spi/spi-sun6i.c | 97 +
 1 file changed, 58 insertions(+), 39 deletions(-)

diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index 8533f4e..88ad45e 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -88,8 +88,12 @@
 #define SUN6I_TXDATA_REG   0x200
 #define SUN6I_RXDATA_REG   0x300
 
+#define SUN6I_SPI_MODE_BITS(SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | 
SPI_LSB_FIRST)
+
+#define SUN6I_SPI_MAX_SPEED_HZ 1
+#define SUN6I_SPI_MIN_SPEED_HZ 3000
+
 struct sun6i_spi {
-   struct spi_master   *master;
void __iomem*base_addr;
struct clk  *hclk;
struct clk  *mclk;
@@ -189,6 +193,9 @@ static void sun6i_spi_set_cs(struct spi_device *spi, bool 
enable)
else
reg &= ~SUN6I_TFR_CTL_CS_LEVEL;
 
+   /* We want to control the chip select manually */
+   reg |= SUN6I_TFR_CTL_CS_MANUAL;
+
sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
 }
 
@@ -197,6 +204,39 @@ static size_t sun6i_spi_max_transfer_size(struct 
spi_device *spi)
return SUN6I_MAX_XFER_SIZE - 1;
 }
 
+static int sun6i_spi_prepare_message(struct spi_master *master,
+struct spi_message *msg)
+{
+   struct spi_device *spi = msg->spi;
+   struct sun6i_spi *sspi = spi_master_get_devdata(master);
+   u32 reg;
+
+   /*
+* Setup the transfer control register: Chip Select,
+* polarities, etc.
+*/
+   reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
+
+   if (spi->mode & SPI_CPOL)
+   reg |= SUN6I_TFR_CTL_CPOL;
+   else
+   reg &= ~SUN6I_TFR_CTL_CPOL;
+
+   if (spi->mode & SPI_CPHA)
+   reg |= SUN6I_TFR_CTL_CPHA;
+   else
+   reg &= ~SUN6I_TFR_CTL_CPHA;
+
+   if (spi->mode & SPI_LSB_FIRST)
+   reg |= SUN6I_TFR_CTL_FBS;
+   else
+   reg &= ~SUN6I_TFR_CTL_FBS;
+
+   sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
+
+   return 0;
+}
+
 static int sun6i_spi_transfer_one(struct spi_master *master,
  struct spi_device *spi,
  struct spi_transfer *tfr)
@@ -235,27 +275,8 @@ static int sun6i_spi_transfer_one(struct spi_master 
*master,
(trig_level << SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_BITS) |
(trig_level << SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_BITS));
 
-   /*
-* Setup the transfer control register: Chip Select,
-* polarities, etc.
-*/
-   reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
-
-   if (spi->mode & SPI_CPOL)
-   reg |= SUN6I_TFR_CTL_CPOL;
-   else
-   reg &= ~SUN6I_TFR_CTL_CPOL;
-
-   if (spi->mode & SPI_CPHA)
-   reg |= SUN6I_TFR_CTL_CPHA;
-   else
-   reg &= ~SUN6I_TFR_CTL_CPHA;
-
-   if (spi->mode & SPI_LSB_FIRST)
-   reg |= SUN6I_TFR_CTL_FBS;
-   else
-   reg &= ~SUN6I_TFR_CTL_FBS;
 
+   reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
/*
 * If it's a TX only transfer, we don't want to fill the RX
 * FIFO with bogus data
@@ -265,11 +286,9 @@ static int sun6i_spi_transfer_one(struct spi_master 
*master,
else
reg |= SUN6I_TFR_CTL_DHB;
 
-   /* We want to control the chip select manually */
-   reg |= SUN6I_TFR_CTL_CS_MANUAL;
-
sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
 
+
/* Ensure that we have a parent clock fast enough */
mclk_rate = clk_get_rate(sspi->mclk);
if (mclk_rate < (2 * tfr->speed_hz)) {
@@ -442,12 +461,24 @@ static int sun6i_spi_probe(struct platform_device *pdev)
struct resource *res;
int ret = 0, irq;
 
-   master = spi_alloc_master(&pdev->dev, sizeof(struct sun6i_spi));
+   master = spi_alloc_master(&pdev->dev, sizeof(*sspi));
if (!master) {
dev_err(&pdev->dev, "Unable to allocate SPI Master\n");
return -ENOMEM;
}
 
+   master->max_speed_hz = SUN6I_SPI_MAX_SPEED_HZ;
+   master->min_speed_hz = SUN6I_SPI_MIN_SPEED_HZ;
+   master->num_chipselect = 4;
+   master->mode_bits = SUN6I_SPI_MODE_BITS;
+   master->bits_per_word_mask = SPI_BPW_MASK(8);
+   master->set_cs = sun6i_spi_set_cs;
+   master->prepare_message = sun6i_spi_prepare_message

Re: [PATCH 0/3] Fix broken bananapi m2 devicetree/regulators

2018-02-10 Thread Sergey Suloev

On 02/11/2018 01:07 AM, Philipp Rossak wrote:



On 10.02.2018 22:08, Sergey Suloev wrote:

On 02/11/2018 12:01 AM, Philipp Rossak wrote:

Hey Sergey,

Thanks for mentioning, but I think the problem has nothing to do 
with those patches. I tested them with the v4.15.0 Kernel since this 
is the last stable release and we are right now in the merging window.


I tested the latest mainline, without those patches and the kernel 
is not booting (I can't see any uart output).


Thanks,
Philipp

On 10.02.2018 14:56, Sergey Suloev wrote:

On 02/09/2018 08:52 PM, Philipp Rossak wrote:
This patchseries fixes the bananapi m1 devicetree, to be able to 
boot again.
The first two patches update/improve the devicetree and the last 
patch adds

all missing regulators.

Regards,
Philipp

Philipp Rossak (3):
   arm: dts: sun6i: a31s: bpi-m2: update mmc supply nodes
   arm: dts: sun6i: a31s: bpi-m2: improve pmic properties
   arm: dts: sun6i: a31s: fix: bpi-m2: add missing regulators

  arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts | 70 
+++-

  1 file changed, 67 insertions(+), 3 deletions(-)


patches are not working

Thanks


same problem, but after applying the patches my device is till hanging.


Can you please share a bootlog? Here is mine [1]. As you can see I'm 
able to boot.
I build it with this branch [2]. For testing you should replace the 
dtb and the uImage/zImage


Philipp


[1]: https://pastebin.com/mVjv3LDf
[2]: 
https://github.com/embed-3d/linux/tree/testing/bpi-m2-regulator-test-2


I am going to test it and come back with outcome

Thanks



Re: [PATCH 0/3] Fix broken bananapi m2 devicetree/regulators

2018-02-10 Thread Sergey Suloev

On 02/11/2018 01:07 AM, Philipp Rossak wrote:



On 10.02.2018 22:08, Sergey Suloev wrote:

On 02/11/2018 12:01 AM, Philipp Rossak wrote:

Hey Sergey,

Thanks for mentioning, but I think the problem has nothing to do 
with those patches. I tested them with the v4.15.0 Kernel since this 
is the last stable release and we are right now in the merging window.


I tested the latest mainline, without those patches and the kernel 
is not booting (I can't see any uart output).


Thanks,
Philipp

On 10.02.2018 14:56, Sergey Suloev wrote:

On 02/09/2018 08:52 PM, Philipp Rossak wrote:
This patchseries fixes the bananapi m1 devicetree, to be able to 
boot again.
The first two patches update/improve the devicetree and the last 
patch adds

all missing regulators.

Regards,
Philipp

Philipp Rossak (3):
   arm: dts: sun6i: a31s: bpi-m2: update mmc supply nodes
   arm: dts: sun6i: a31s: bpi-m2: improve pmic properties
   arm: dts: sun6i: a31s: fix: bpi-m2: add missing regulators

  arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts | 70 
+++-

  1 file changed, 67 insertions(+), 3 deletions(-)


patches are not working

Thanks


same problem, but after applying the patches my device is till hanging.


Can you please share a bootlog? Here is mine [1]. As you can see I'm 
able to boot.
I build it with this branch [2]. For testing you should replace the 
dtb and the uImage/zImage


Philipp


[1]: https://pastebin.com/mVjv3LDf
[2]: 
https://github.com/embed-3d/linux/tree/testing/bpi-m2-regulator-test-2


My dmesg is very similar to yours unless it hangs on the last line [1]. 
For this test I used kernel from tag v4.15 with no additional patching.


[1] https://pastebin.com/3a6bk5Dk




Re: [PATCH 0/3] Fix broken bananapi m2 devicetree/regulators

2018-02-11 Thread Sergey Suloev

On 02/11/2018 02:30 PM, Philipp Rossak wrote:

Am Sonntag, den 11.02.2018, 10:55 +0300 schrieb Sergey Suloev:

On 02/11/2018 01:07 AM, Philipp Rossak wrote:


On 10.02.2018 22:08, Sergey Suloev wrote:

On 02/11/2018 12:01 AM, Philipp Rossak wrote:

Hey Sergey,

Thanks for mentioning, but I think the problem has nothing to
do
with those patches. I tested them with the v4.15.0 Kernel since
this
is the last stable release and we are right now in the merging
window.

I tested the latest mainline, without those patches and the
kernel
is not booting (I can't see any uart output).

Thanks,
Philipp

On 10.02.2018 14:56, Sergey Suloev wrote:

On 02/09/2018 08:52 PM, Philipp Rossak wrote:

This patchseries fixes the bananapi m1 devicetree, to be
able to
boot again.
The first two patches update/improve the devicetree and the
last
patch adds
all missing regulators.

Regards,
Philipp

Philipp Rossak (3):
    arm: dts: sun6i: a31s: bpi-m2: update mmc supply nodes
    arm: dts: sun6i: a31s: bpi-m2: improve pmic properties
    arm: dts: sun6i: a31s: fix: bpi-m2: add missing
regulators

   arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts | 70
+++-
   1 file changed, 67 insertions(+), 3 deletions(-)


patches are not working

Thanks


same problem, but after applying the patches my device is till
hanging.



Can you please share a bootlog? Here is mine [1]. As you can see
I'm
able to boot.
I build it with this branch [2]. For testing you should replace
the
dtb and the uImage/zImage

Philipp


[1]: https://pastebin.com/mVjv3LDf
[2]:
https://github.com/embed-3d/linux/tree/testing/bpi-m2-regulator-tes
t-2

My dmesg is very similar to yours unless it hangs on the last line
[1].
For this test I used kernel from tag v4.15 with no additional
patching.

[1] https://pastebin.com/3a6bk5Dk



For me it looks like you have a different kernel and also an different
dtb that you patch! And you are applying also a fixup script.
These patches should be applied on top of linux mainline.

fixup script:
Applying kernel provided DT fixup script (sun6i-a31s-fixup.scr)


Linux versions:
4.15.0-3-g1bbe5edde691   vs   4.15.0-sunxi-dirty

In addition to that you are also booting into fb/hdmi.

If you use my branch (uImage and dtb) and replace the current boot.cmd
with this (to get the boot.scr you need to use mkimage) it should work:

setenv bootargs console=ttyS0,115200 root=/dev/mmcblk0p2 rw rootwait
panic=10
load mmc 0:1 0x4300 ${fdtfile} || load mmc 0:1 0x4300
boot/${fdtfile}
load mmc 0:1 0x4200 uImage || load mmc 0:1 0x4200 boot/uImage
bootm 0x4200 - 0x4300


the script is doing nothing, it is empty. The problem is related to hdmi.

The following dts code makes it happen:

&hdmi {
    status = "okay";
};




Re: [PATCH 0/3] Fix broken bananapi m2 devicetree/regulators

2018-02-11 Thread Sergey Suloev

On 02/11/2018 02:30 PM, Philipp Rossak wrote:

Am Sonntag, den 11.02.2018, 10:55 +0300 schrieb Sergey Suloev:

On 02/11/2018 01:07 AM, Philipp Rossak wrote:


On 10.02.2018 22:08, Sergey Suloev wrote:

On 02/11/2018 12:01 AM, Philipp Rossak wrote:

Hey Sergey,

Thanks for mentioning, but I think the problem has nothing to
do
with those patches. I tested them with the v4.15.0 Kernel since
this
is the last stable release and we are right now in the merging
window.

I tested the latest mainline, without those patches and the
kernel
is not booting (I can't see any uart output).

Thanks,
Philipp

On 10.02.2018 14:56, Sergey Suloev wrote:

On 02/09/2018 08:52 PM, Philipp Rossak wrote:

This patchseries fixes the bananapi m1 devicetree, to be
able to
boot again.
The first two patches update/improve the devicetree and the
last
patch adds
all missing regulators.

Regards,
Philipp

Philipp Rossak (3):
    arm: dts: sun6i: a31s: bpi-m2: update mmc supply nodes
    arm: dts: sun6i: a31s: bpi-m2: improve pmic properties
    arm: dts: sun6i: a31s: fix: bpi-m2: add missing
regulators

   arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts | 70
+++-
   1 file changed, 67 insertions(+), 3 deletions(-)


patches are not working

Thanks


same problem, but after applying the patches my device is till
hanging.



Can you please share a bootlog? Here is mine [1]. As you can see
I'm
able to boot.
I build it with this branch [2]. For testing you should replace
the
dtb and the uImage/zImage

Philipp


[1]: https://pastebin.com/mVjv3LDf
[2]:
https://github.com/embed-3d/linux/tree/testing/bpi-m2-regulator-tes
t-2

My dmesg is very similar to yours unless it hangs on the last line
[1].
For this test I used kernel from tag v4.15 with no additional
patching.

[1] https://pastebin.com/3a6bk5Dk



For me it looks like you have a different kernel and also an different
dtb that you patch! And you are applying also a fixup script.
These patches should be applied on top of linux mainline.

fixup script:
Applying kernel provided DT fixup script (sun6i-a31s-fixup.scr)


Linux versions:
4.15.0-3-g1bbe5edde691   vs   4.15.0-sunxi-dirty

In addition to that you are also booting into fb/hdmi.

If you use my branch (uImage and dtb) and replace the current boot.cmd
with this (to get the boot.scr you need to use mkimage) it should work:

setenv bootargs console=ttyS0,115200 root=/dev/mmcblk0p2 rw rootwait
panic=10
load mmc 0:1 0x4300 ${fdtfile} || load mmc 0:1 0x4300
boot/${fdtfile}
load mmc 0:1 0x4200 uImage || load mmc 0:1 0x4200 boot/uImage
bootm 0x4200 - 0x4300

ok, I confirm that your patches are not related to the issue. It is the 
problem with sun4i drm / hdmi which is not working on bpi m2.


Thanks



Re: [PATCH 20/21] ASoC: sun4i-i2s: Add support for TDM slots

2019-08-23 Thread Sergey Suloev

Hi, Maxime,

On 8/21/19 3:05 PM, Maxime Ripard wrote:

Hi,

On Tue, Aug 20, 2019 at 08:46:30AM +0300, Sergey Suloev wrote:

Hi, Maxime,

On 8/19/19 10:25 PM, Maxime Ripard wrote:

From: Maxime Ripard 

The i2s controller supports TDM, for up to 8 slots. Let's support the TDM
API.

Signed-off-by: Maxime Ripard 
---
   sound/soc/sunxi/sun4i-i2s.c | 40 --
   1 file changed, 34 insertions(+), 6 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 0dac09814b65..4f76daeaaed7 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -168,6 +168,8 @@ struct sun4i_i2s {
struct reset_control *rst;
unsigned intmclk_freq;
+   unsigned intslots;
+   unsigned intslot_width;
struct snd_dmaengine_dai_dma_data   capture_dma_data;
struct snd_dmaengine_dai_dma_data   playback_dma_data;
@@ -287,7 +289,7 @@ static bool sun4i_i2s_oversample_is_valid(unsigned int 
oversample)
   static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
  unsigned int rate,
- unsigned int channels,
+ unsigned int slots,
  unsigned int word_size)
   {
struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
@@ -335,7 +337,7 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
bclk_parent_rate = i2s->variant->get_bclk_parent_rate(i2s);
bclk_div = sun4i_i2s_get_bclk_div(i2s, bclk_parent_rate,
- rate, channels, word_size);
+ rate, slots, word_size);
if (bclk_div < 0) {
dev_err(dai->dev, "Unsupported BCLK divider: %d\n", bclk_div);
return -EINVAL;
@@ -419,6 +421,10 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s 
*i2s,
  const struct snd_pcm_hw_params *params)
   {
unsigned int channels = params_channels(params);
+   unsigned int slots = channels;
+
+   if (i2s->slots)
+   slots = i2s->slots;
/* Map the channels for playback and capture */
regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG, 0x76543210);
@@ -428,7 +434,6 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s 
*i2s,
regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
   SUN4I_I2S_CHAN_SEL_MASK,
   SUN4I_I2S_CHAN_SEL(channels));
-
regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG,
   SUN4I_I2S_CHAN_SEL_MASK,
   SUN4I_I2S_CHAN_SEL(channels));
@@ -452,10 +457,18 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream 
*substream,
   struct snd_soc_dai *dai)
   {
struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+   unsigned int word_size = params_width(params);
unsigned int channels = params_channels(params);
+   unsigned int slots = channels;
int ret, sr, wss;
u32 width;
+   if (i2s->slots)
+   slots = i2s->slots;
+
+   if (i2s->slot_width)
+   word_size = i2s->slot_width;
+
ret = i2s->variant->set_chan_cfg(i2s, params);
if (ret < 0) {
dev_err(dai->dev, "Invalid channel configuration\n");
@@ -477,15 +490,14 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream 
*substream,
if (sr < 0)
return -EINVAL;
-   wss = i2s->variant->get_wss(i2s, params_width(params));
+   wss = i2s->variant->get_wss(i2s, word_size);
if (wss < 0)
return -EINVAL;
regmap_field_write(i2s->field_fmt_wss, wss);
regmap_field_write(i2s->field_fmt_sr, sr);
-   return sun4i_i2s_set_clk_rate(dai, params_rate(params),
- channels, params_width(params));
+   return sun4i_i2s_set_clk_rate(dai, params_rate(params), slots, 
word_size);
   }
   static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,
@@ -785,10 +797,26 @@ static int sun4i_i2s_set_sysclk(struct snd_soc_dai *dai, 
int clk_id,
return 0;
   }
+static int sun4i_i2s_set_tdm_slot(struct snd_soc_dai *dai,
+ unsigned int tx_mask, unsigned int rx_mask,
+ int slots, int slot_width)
+{
+   struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+   if (slots > 8)
+   return -EINVAL;
+
+   i2s->slots = slots;
+   i2s->slot_width = slot_width;
+
+   return 0;
+}
+
   static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = {
.hw_params  = sun4i_i2s_hw_params,
.set_fmt= sun4i_i2s_set_fmt,
.set_sysclk = sun4i_i2s_set_sysclk,
+

Re: [PATCH 20/21] ASoC: sun4i-i2s: Add support for TDM slots

2019-08-19 Thread Sergey Suloev

Hi, Maxime,

On 8/19/19 10:25 PM, Maxime Ripard wrote:

From: Maxime Ripard 

The i2s controller supports TDM, for up to 8 slots. Let's support the TDM
API.

Signed-off-by: Maxime Ripard 
---
  sound/soc/sunxi/sun4i-i2s.c | 40 --
  1 file changed, 34 insertions(+), 6 deletions(-)

diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 0dac09814b65..4f76daeaaed7 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -168,6 +168,8 @@ struct sun4i_i2s {
struct reset_control *rst;
  
  	unsigned int	mclk_freq;

+   unsigned intslots;
+   unsigned intslot_width;
  
  	struct snd_dmaengine_dai_dma_data	capture_dma_data;

struct snd_dmaengine_dai_dma_data   playback_dma_data;
@@ -287,7 +289,7 @@ static bool sun4i_i2s_oversample_is_valid(unsigned int 
oversample)
  
  static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,

  unsigned int rate,
- unsigned int channels,
+ unsigned int slots,
  unsigned int word_size)
  {
struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
@@ -335,7 +337,7 @@ static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai,
  
  	bclk_parent_rate = i2s->variant->get_bclk_parent_rate(i2s);

bclk_div = sun4i_i2s_get_bclk_div(i2s, bclk_parent_rate,
- rate, channels, word_size);
+ rate, slots, word_size);
if (bclk_div < 0) {
dev_err(dai->dev, "Unsupported BCLK divider: %d\n", bclk_div);
return -EINVAL;
@@ -419,6 +421,10 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s 
*i2s,
  const struct snd_pcm_hw_params *params)
  {
unsigned int channels = params_channels(params);
+   unsigned int slots = channels;
+
+   if (i2s->slots)
+   slots = i2s->slots;
  
  	/* Map the channels for playback and capture */

regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG, 0x76543210);
@@ -428,7 +434,6 @@ static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s 
*i2s,
regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG,
   SUN4I_I2S_CHAN_SEL_MASK,
   SUN4I_I2S_CHAN_SEL(channels));
-
regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG,
   SUN4I_I2S_CHAN_SEL_MASK,
   SUN4I_I2S_CHAN_SEL(channels));
@@ -452,10 +457,18 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream 
*substream,
   struct snd_soc_dai *dai)
  {
struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+   unsigned int word_size = params_width(params);
unsigned int channels = params_channels(params);
+   unsigned int slots = channels;
int ret, sr, wss;
u32 width;
  
+	if (i2s->slots)

+   slots = i2s->slots;
+
+   if (i2s->slot_width)
+   word_size = i2s->slot_width;
+
ret = i2s->variant->set_chan_cfg(i2s, params);
if (ret < 0) {
dev_err(dai->dev, "Invalid channel configuration\n");
@@ -477,15 +490,14 @@ static int sun4i_i2s_hw_params(struct snd_pcm_substream 
*substream,
if (sr < 0)
return -EINVAL;
  
-	wss = i2s->variant->get_wss(i2s, params_width(params));

+   wss = i2s->variant->get_wss(i2s, word_size);
if (wss < 0)
return -EINVAL;
  
  	regmap_field_write(i2s->field_fmt_wss, wss);

regmap_field_write(i2s->field_fmt_sr, sr);
  
-	return sun4i_i2s_set_clk_rate(dai, params_rate(params),

- channels, params_width(params));
+   return sun4i_i2s_set_clk_rate(dai, params_rate(params), slots, 
word_size);
  }
  
  static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s,

@@ -785,10 +797,26 @@ static int sun4i_i2s_set_sysclk(struct snd_soc_dai *dai, 
int clk_id,
return 0;
  }
  
+static int sun4i_i2s_set_tdm_slot(struct snd_soc_dai *dai,

+ unsigned int tx_mask, unsigned int rx_mask,
+ int slots, int slot_width)
+{
+   struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+   if (slots > 8)
+   return -EINVAL;
+
+   i2s->slots = slots;
+   i2s->slot_width = slot_width;
+
+   return 0;
+}
+
  static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = {
.hw_params  = sun4i_i2s_hw_params,
.set_fmt= sun4i_i2s_set_fmt,
.set_sysclk = sun4i_i2s_set_sysclk,
+   .set_tdm_slot   = sun4i_i2s_set_tdm_slot,
.trigger= sun4i_i2s_trigger,
  };
  



it seems like you forgot to implement sun4i_i2s_dai_ops.set_bclk_ratio 
because, as I far as I understand, it should alter tdm slots 
functionality ind

Re: BananaPi M2 support

2020-11-18 Thread Sergey Suloev

Hi, ChenYu,

thanks for for the help. I tried to use 
"root=PARTUUID=a09ef512-7f29-47b8-8e9a-db5d1d58d8be" in kernel boot 
parameters,

the new log is here  https://pastebin.com/EL3uaRpE.

Nothing has actually changed, the only difference  is that it now says:

[    1.750270] Waiting for root device 
PARTUUID=a09ef512-7f29-47b8-8e9a-db5d1d58d8be...



I verified that a09ef512-7f29-47b8-8e9a-db5d1d58d8be is the actual 
partition id from my sdcard.



Thank you,
Sergey


On 17.11.2020 20:36, Chen-Yu Tsai wrote:

Hi,

On Wed, Nov 18, 2020 at 1:06 AM Sergey Suloev  wrote:

Hi, ChenYu,

I have tried to build and run linux-next  by tag  "next-20201117".
Now the boot log looks different but the kernel still hangs. See
https://pastebin.com/gFk7XuBc

Due to the new asynchronous probing of mmc controllers, the mmcblock
device numbers likely have changed, as seen here:

[ 1.652275] mmc1: new high speed SDHC card at address 0001
[ 1.652568] hub 1-1:1.0: USB hub found
[ 1.658587] mmcblk1: mmc1:0001 EB1QT 29.8 GiB
[ 1.661777] hub 1-1:1.0: 4 ports detected
[ 1.670263] mmcblk1: p1

You should change your root device specification to use PARTUUID,
instead of hardcoding the index.


Regards
ChenYu


Thank you,
Sergey


On 17.11.2020 11:06, Chen-Yu Tsai wrote:

Hi,

Please try linux-next. There were some regulator fixes that got merged recently.
One of them fixes an infinite recursion when resolving regulator supplies.

ChenYu

On Tue, Nov 17, 2020 at 1:12 AM Sergey Suloev  wrote:

Hi, Maxime,

it just hangs on that last lines and nothing happens anymore, see 5.18 log.


On 16.11.2020 18:52, Maxime Ripard wrote:

Hi,

On Sat, Nov 14, 2020 at 08:20:54PM +0300, Sergey Suloev wrote:

Hi,

I noticed that BananaPi M2 (A31 SoC) does not boot anymore on modern
kernels. The problem arises somewhere between 5.7.19 - 5.8.18. I have saved
boot logs for both versions https://pastebin.com/DTRZi8R7  and
https://pastebin.com/PS2hq07A. Logs have been taken on clean/non-patched
kernel with default config, u-boot v2020.10.

The kernel versions 5.7.x and below work well (I tried 5.5.19 and 5.6.19).
The versions 5.8.18 and above all fail (5.9 and 5.10).

Could you look at the problem or provide an advice about further
investigation, please ?

I'm not quite sure what the issue is exactly? How does it fail to boot?

Maxime

Thank you,
Sergey





BananaPi M2 support

2020-11-14 Thread Sergey Suloev

Hi,

I noticed that BananaPi M2 (A31 SoC) does not boot anymore on modern 
kernels. The problem arises somewhere between 5.7.19 - 5.8.18. I have 
saved boot logs for both versions https://pastebin.com/DTRZi8R7  and  
https://pastebin.com/PS2hq07A. Logs have been taken on clean/non-patched 
kernel with default config, u-boot v2020.10.


The kernel versions 5.7.x and below work well (I tried 5.5.19 and 
5.6.19). The versions 5.8.18 and above all fail (5.9 and 5.10).


Could you look at the problem or provide an advice about further 
investigation, please ?



Thank you



Re: BananaPi M2 support

2020-11-16 Thread Sergey Suloev

Hi, Maxime,

it just hangs on that last lines and nothing happens anymore, see 5.18 log.


On 16.11.2020 18:52, Maxime Ripard wrote:

Hi,

On Sat, Nov 14, 2020 at 08:20:54PM +0300, Sergey Suloev wrote:

Hi,

I noticed that BananaPi M2 (A31 SoC) does not boot anymore on modern
kernels. The problem arises somewhere between 5.7.19 - 5.8.18. I have saved
boot logs for both versions https://pastebin.com/DTRZi8R7  and
https://pastebin.com/PS2hq07A. Logs have been taken on clean/non-patched
kernel with default config, u-boot v2020.10.

The kernel versions 5.7.x and below work well (I tried 5.5.19 and 5.6.19).
The versions 5.8.18 and above all fail (5.9 and 5.10).

Could you look at the problem or provide an advice about further
investigation, please ?

I'm not quite sure what the issue is exactly? How does it fail to boot?

Maxime



Thank you,
Sergey



Re: BananaPi M2 support

2020-11-17 Thread Sergey Suloev

Hi, ChenYu,

I have tried to build and run linux-next  by tag  "next-20201117".
Now the boot log looks different but the kernel still hangs. See 
https://pastebin.com/gFk7XuBc


Thank you,
Sergey


On 17.11.2020 11:06, Chen-Yu Tsai wrote:

Hi,

Please try linux-next. There were some regulator fixes that got merged recently.
One of them fixes an infinite recursion when resolving regulator supplies.

ChenYu

On Tue, Nov 17, 2020 at 1:12 AM Sergey Suloev  wrote:

Hi, Maxime,

it just hangs on that last lines and nothing happens anymore, see 5.18 log.


On 16.11.2020 18:52, Maxime Ripard wrote:

Hi,

On Sat, Nov 14, 2020 at 08:20:54PM +0300, Sergey Suloev wrote:

Hi,

I noticed that BananaPi M2 (A31 SoC) does not boot anymore on modern
kernels. The problem arises somewhere between 5.7.19 - 5.8.18. I have saved
boot logs for both versions https://pastebin.com/DTRZi8R7  and
https://pastebin.com/PS2hq07A. Logs have been taken on clean/non-patched
kernel with default config, u-boot v2020.10.

The kernel versions 5.7.x and below work well (I tried 5.5.19 and 5.6.19).
The versions 5.8.18 and above all fail (5.9 and 5.10).

Could you look at the problem or provide an advice about further
investigation, please ?

I'm not quite sure what the issue is exactly? How does it fail to boot?

Maxime


Thank you,
Sergey