diff mbox

[linux-next,v2,1/1] spi: imx: dynamic burst length adjust for PIO mode

Message ID 1493634704-3545-2-git-send-email-jiada_wang@mentor.com (mailing list archive)
State Accepted
Commit 8d4a6cad7adb3ddac32cd52635f20e11de11a658
Headers show

Commit Message

Wang, Jiada May 1, 2017, 10:31 a.m. UTC
From: Jiada Wang <jiada_wang@mentor.com>

previously burst length (BURST_LENGTH) is always set to equal
to bits_per_word, causes a 10us gap between each word in
transfer, which significantly affects performance.

This patch uses 32 bits transfer to simulate lower bits transfer,
and adjusts burst length runtimely to use biggeest burst length
as possible to reduce the gaps in transfer for PIO mode.

Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
---
 drivers/spi/spi-imx.c | 157 +++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 149 insertions(+), 8 deletions(-)

Comments

Leonard Crestez May 17, 2017, 5:32 p.m. UTC | #1
On Mon, 2017-05-01 at 03:31 -0700, jiada_wang@mentor.com wrote:
> From: Jiada Wang <jiada_wang@mentor.com>
> 
> previously burst length (BURST_LENGTH) is always set to equal
> to bits_per_word, causes a 10us gap between each word in
> transfer, which significantly affects performance.
> 
> This patch uses 32 bits transfer to simulate lower bits transfer,
> and adjusts burst length runtimely to use biggeest burst length
> as possible to reduce the gaps in transfer for PIO mode.
> 
> Signed-off-by: Jiada Wang <jiada_wang@mentor.com>
> ---
>  drivers/spi/spi-imx.c | 157 +++++++++++++++++++++++++++++++++++++++++++++++---
>  1 file changed, 149 insertions(+), 8 deletions(-)

This patch made it's way to linux-next and broke boot on imx6dl-
sabreauto and imx6sl-evk boards (but others work). The crashes look
like this:

[    1.442384] spi_imx 2008000.ecspi: dma setup error -19, use pio
[    1.452930] Unable to handle kernel NULL pointer dereference at virtual address 00000000
[    1.461320] pgd = c0004000
[    1.464078] [00000000] *pgd=00000000
[    1.467821] Internal error: Oops: 5 [#1] SMP ARM
[    1.472464] Modules linked in:
[    1.475558] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.12.0-rc1-00001-g8d4a6ca #90
[    1.483234] Hardware name: Freescale i.MX6 SoloLite (Device Tree)
[    1.489349] task: ef058000 task.stack: ef054000
[    1.493926] PC is at spi_imx_transfer+0x2d8/0x364
[    1.498659] LR is at spi_bitbang_transfer_one+0x80/0xa0
[    1.503910] pc : [<c05f6264>]    lr : [<c05f3440>]    psr: 20000013
[    1.503910] sp : ef0558b0  ip : ef0558e0  fp : ef0558dc
[    1.515412] r10: ee938a98  r9 : ef340c28  r8 : ee938800
[    1.520658] r7 : ee938800  r6 : ef340800  r5 : ef055aac  r4 : ef340ce0
[    1.527206] r3 : 00000001  r2 : fffffffc  r1 : 00000000  r0 : ee938800
[    1.533757] Flags: nzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
[    1.540913] Control: 10c5387d  Table: 8000404a  DAC: 00000051
[    1.546680] Process swapper/0 (pid: 1, stack limit = 0xef054210)
[    1.552709] Stack: (0xef0558b0 to 0xef056000)
[    1.557093] 58a0:                                     c05f5cfc c05f587c 00000000 ef055aac
[    1.565301] 58c0: ef340800 ef340ce0 ee938800 ef340c28 ef055904 ef0558e0 c05f3440 c05f5f98
[    1.573509] 58e0: ee938800 ef055aac ef340800 ef055a38 00000000 ef340c28 ef055944 ef055908
[    1.581714] 5900: c05f21c0 c05f33cc ee938800 00000000 ef05592c ef055920 c0496c3c 00000000
[    1.589920] 5920: ef340800 ef055a38 00000000 00000000 ee938a98 00000000 ef055984 ef055948
[    1.598126] 5940: c05f28c8 c05f2118 ef055a38 ef340800 ef05596c ef340a80 c016d518 ef055990
[    1.606332] 5960: ee938800 ef055a38 ef340800 ef340c28 ee938a98 00000000 ef055a14 ef055988
[    1.614537] 5980: c05f2bf0 c05f24e0 ef340ac4 60000013 00000000 00000000 dead4ead ffffffff
[    1.622743] 59a0: ffffffff c1669b70 00000000 00000000 c0be1d7c ef0559b4 ef0559b4 00000000
[    1.630948] 59c0: 00000000 dead4ead ffffffff ffffffff c1669b70 00000000 00000000 c0be1d7c
[    1.639153] 59e0: ef0559b4 ef0559b4 ee938800 ee938800 ef055a38 ef055a38 00000006 c1669b3c
[    1.647359] 5a00: ee938800 ef055b27 ef055a2c ef055a18 c05f2c34 c05f2a30 ef0c8bc1 ef0c8bc0
[    1.655565] 5a20: ef055b14 ef055a30 c05f2d20 c05f2c10 ef055a54 ef055b4a ef055aa4 ef055ae0
[    1.663770] 5a40: ee938800 00000000 c05f0640 ef055990 00000007 00000001 ffffff8d ef055a5c
[    1.671975] 5a60: ef055a5c 00000000 ef055a68 ef055a68 ef0c8bc0 00000000 00000001 00000000
[    1.680179] 5a80: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000802
[    1.688384] 5aa0: 01312d00 ef055ae0 ef055a38 00000000 ef0c8bc1 00000006 00000000 00000000
[    1.696588] 5ac0: 00000000 00000000 00000000 00000000 00000000 00000000 00000810 01312d00
[    1.704794] 5ae0: ef055a38 ef055aa4 ef058000 c05c298c ee938800 ee938a70 ee938800 ef341018
[    1.712999] 5b00: ef7e6f0c c0a669a4 ef055b3c ef055b18 c05c29c4 c05f2c58 00000006 00000000
[    1.721206] 5b20: ef055b4c 9f055b30 c05c298c c0a669a4 ef055b74 ef055b40 c05d4970 c05c2998
[    1.729412] 5b40: ef055b5c ef055b50 c016d518 c016d320 ef055b74 ef341018 c0a669a4 ee938a70
[    1.737617] 5b60: ee938800 00000000 ef055bb4 ef055b78 c05d5634 c05d4954 ef341010 ef341050
[    1.745822] 5b80: 00000000 ef341018 00000000 ef341010 ee938a70 00000000 ef341018 00000000
[    1.754027] 5ba0: 00000000 00000000 ef055be4 ef055bb8 c05c2f88 c05d5300 c0e3ed44 00000000
[    1.762232] 5bc0: 00000000 ee938800 c0e3ed34 00000000 c0e3ed44 00000000 ef055c04 ef055be8
[    1.770437] 5be0: c05f0070 c05c2e78 ee938800 c166767c 00000000 c0e3ed44 ef055c2c ef055c08
[    1.778643] 5c00: c053ed28 c05efff8 c0e3ed44 ef055c78 ee938800 00000001 00000000 c1667638
[    1.786848] 5c20: ef055c4c ef055c30 c053ef1c c053eacc 00000000 ef055c78 c053ee7c 00000001
[    1.795055] 5c40: ef055c74 ef055c50 c053d050 c053ee88 ef0c0ed4 ee8adfd4 ee938800 ee938800
[    1.803261] 5c60: ee938834 c0e403a4 ef055c9c ef055c78 c053e998 c053cff0 ee938800 00000001
[    1.811466] 5c80: ee938808 ee938800 c0e403a4 00000000 ef055cac ef055ca0 c053ef9c c053e8ec
[    1.819671] 5ca0: ef055ccc ef055cb0 c053df88 c053ef94 ee938808 ef340800 ee938800 00000000
[    1.827877] 5cc0: ef055d0c ef055cd0 c053c0ec c053df04 c05f07d8 c0450bd8 00000000 ee938800
[    1.836083] 5ce0: ef055d0c ee938800 ef340800 00000000 ef0f5010 00000000 ef340800 00000000
[    1.844288] 5d00: ef055d2c ef055d10 c05f1044 c053bd28 ef7e6f0c ef7e6f5c ee938800 00000001
[    1.852493] 5d20: ef055d74 ef055d30 c05f18f0 c05f0fb8 00000000 c04289b8 ef055d64 ef0f5010
[    1.860699] 5d40: c040f6f4 01312d00 ef055d74 ef340800 ef340ce0 ef340a60 ffffffed ef0f5010
[    1.868905] 5d60: ef0f5000 ee8d4f80 ef055d8c ef055d78 c05f3508 c05f14b8 ef340ce0 ef340800
[    1.877111] 5d80: ef055ddc ef055d90 c05f6700 c05f346c 00000000 ef0c5840 ef340ce0 00000002
[    1.885316] 5da0: c1667638 ef0f5010 00000000 00000000 c0e40ccc ef0f5010 fffffffe c0e40ccc
[    1.893522] 5dc0: fffffdfb 00000000 00000000 c0d00618 ef055dfc ef055de0 c05409cc c05f6394
[    1.901728] 5de0: ef0f5010 c166767c 00000000 c0e40ccc ef055e24 ef055e00 c053ed28 c0540980
[    1.909934] 5e00: ef0f5010 c0e40ccc ef0f5044 00000000 00000000 c0d5f858 ef055e44 ef055e28
[    1.918139] 5e20: c053ee78 c053eacc 00000000 c0e40ccc c053edb0 00000000 ef055e6c ef055e48
[    1.926345] 5e40: c053cf8c c053edbc ef009aa4 ef0bbcd0 ef009ad4 c0e40ccc ee8d7300 c0e3b068
[    1.934551] 5e60: ef055e7c ef055e70 c053e680 c053cf24 ef055ea4 ef055e80 c053e1a4 c053e66c
[    1.942756] 5e80: c0c4a470 ef055e90 c0e40ccc ffffe000 c0d5f850 c0cdd42c ef055ebc ef055ea8
[    1.950963] 5ea0: c053f814 c053e0ac c0d47a14 ffffe000 ef055ecc ef055ec0 c054091c c053f7a0
[    1.959168] 5ec0: ef055edc ef055ed0 c0d47a2c c05408f0 ef055f4c ef055ee0 c0101934 c0d47a20
[    1.967374] 5ee0: c0d00634 c04157f0 c0cde600 000000ef ef055f4c ef055f00 c0147468 c0d00624
[    1.975578] 5f00: 00000000 00000006 00000006 00000000 c0cdd42c c0c53d64 efffcc3a efffcc42
[    1.983784] 5f20: c0e179e4 00000006 c0e7c000 c0d70ee8 c0e7c000 c0d5f850 c0cdd42c 000000ef
[    1.991990] 5f40: ef055f94 ef055f50 c0d00e74 c01018fc 00000006 00000006 00000000 c0d00618
[    2.000194] 5f60: 96fb16ef 00000007 c09af0d8 00000000 c09af0d8 00000000 00000000 00000000
[    2.008401] 5f80: 00000000 00000000 ef055fac ef055f98 c09af0e8 c0d00d54 00000000 c09af0d8
[    2.016605] 5fa0: 00000000 ef055fb0 c0107d30 c09af0e4 00000000 00000000 00000000 00000000
[    2.024810] 5fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[    2.033015] 5fe0: 00000000 00000000 00000000 00000000 00000013 00000000 def4d473 a64cea87
[    2.041206] Backtrace:
[    2.043707] [<c05f5f8c>] (spi_imx_transfer) from [<c05f3440>] (spi_bitbang_transfer_one+0x80/0xa0)
[    2.052699]  r9:ef340c28 r8:ee938800 r7:ef340ce0 r6:ef340800 r5:ef055aac r4:00000000
[    2.060479] [<c05f33c0>] (spi_bitbang_transfer_one) from [<c05f21c0>] (spi_transfer_one_message+0xb4/0x3c8)
[    2.070251]  r9:ef340c28 r8:00000000 r7:ef055a38 r6:ef340800 r5:ef055aac r4:ee938800
[    2.078029] [<c05f210c>] (spi_transfer_one_message) from [<c05f28c8>] (__spi_pump_messages+0x3f4/0x534)
[    2.087452]  r10:00000000 r9:ee938a98 r8:00000000 r7:00000000 r6:ef055a38 r5:ef340800
[    2.095301]  r4:00000000
[    2.097869] [<c05f24d4>] (__spi_pump_messages) from [<c05f2bf0>] (__spi_sync+0x1cc/0x1e0)
[    2.106079]  r10:00000000 r9:ee938a98 r8:ef340c28 r7:ef340800 r6:ef055a38 r5:ee938800
[    2.113927]  r4:ef055990
[    2.116492] [<c05f2a24>] (__spi_sync) from [<c05f2c34>] (spi_sync+0x30/0x48)
[    2.123570]  r10:ef055b27 r9:ee938800 r8:c1669b3c r7:00000006 r6:ef055a38 r5:ef055a38
[    2.131418]  r4:ee938800
[    2.133985] [<c05f2c04>] (spi_sync) from [<c05f2d20>] (spi_write_then_read+0xd4/0x184)
[    2.141924]  r5:ef0c8bc0 r4:ef0c8bc1
[    2.145534] [<c05f2c4c>] (spi_write_then_read) from [<c05c29c4>] (m25p80_read_reg+0x38/0x70)
[    2.154002]  r10:c0a669a4 r9:ef7e6f0c r8:ef341018 r7:ee938800 r6:ee938a70 r5:ee938800
[    2.161851]  r4:c05c298c
[    2.164415] [<c05c298c>] (m25p80_read_reg) from [<c05d4970>] (spi_nor_read_id+0x28/0xc0)
[    2.172527]  r5:c0a669a4 r4:c05c298c
[    2.176132] [<c05d4948>] (spi_nor_read_id) from [<c05d5634>] (spi_nor_scan+0x340/0x8f8)
[    2.184164]  r8:00000000 r7:ee938800 r6:ee938a70 r5:c0a669a4 r4:ef341018
[    2.190894] [<c05d52f4>] (spi_nor_scan) from [<c05c2f88>] (m25p_probe+0x11c/0x168)
[    2.198494]  r10:00000000 r9:00000000 r8:00000000 r7:ef341018 r6:00000000 r5:ee938a70
[    2.206342]  r4:ef341010
[    2.208907] [<c05c2e6c>] (m25p_probe) from [<c05f0070>] (spi_drv_probe+0x84/0xb4)
[    2.216418]  r8:00000000 r7:c0e3ed44 r6:00000000 r5:c0e3ed34 r4:ee938800
[    2.223162] [<c05effec>] (spi_drv_probe) from [<c053ed28>] (driver_probe_device+0x268/0x2f0)
[    2.231626]  r7:c0e3ed44 r6:00000000 r5:c166767c r4:ee938800
[    2.237321] [<c053eac0>] (driver_probe_device) from [<c053ef1c>] (__device_attach_driver+0xa0/0xd4)
[    2.246396]  r9:c1667638 r8:00000000 r7:00000001 r6:ee938800 r5:ef055c78 r4:c0e3ed44
[    2.254174] [<c053ee7c>] (__device_attach_driver) from [<c053d050>] (bus_for_each_drv+0x6c/0xa0)
[    2.262984]  r7:00000001 r6:c053ee7c r5:ef055c78 r4:00000000
[    2.268675] [<c053cfe4>] (bus_for_each_drv) from [<c053e998>] (__device_attach+0xb8/0x120)
[    2.276963]  r6:c0e403a4 r5:ee938834 r4:ee938800
[    2.281614] [<c053e8e0>] (__device_attach) from [<c053ef9c>] (device_initial_probe+0x14/0x18)
[    2.290164]  r7:00000000 r6:c0e403a4 r5:ee938800 r4:ee938808
[    2.295857] [<c053ef88>] (device_initial_probe) from [<c053df88>] (bus_probe_device+0x90/0x98)
[    2.304501] [<c053def8>] (bus_probe_device) from [<c053c0ec>] (device_add+0x3d0/0x584)
[    2.312443]  r7:00000000 r6:ee938800 r5:ef340800 r4:ee938808
[    2.318134] [<c053bd1c>] (device_add) from [<c05f1044>] (spi_add_device+0x98/0x13c)
[    2.325821]  r10:00000000 r9:ef340800 r8:00000000 r7:ef0f5010 r6:00000000 r5:ef340800
[    2.333669]  r4:ee938800
[    2.336235] [<c05f0fac>] (spi_add_device) from [<c05f18f0>] (spi_register_master+0x444/0x7a4)
[    2.344786]  r7:00000001 r6:ee938800 r5:ef7e6f5c r4:ef7e6f0c
[    2.350478] [<c05f14ac>] (spi_register_master) from [<c05f3508>] (spi_bitbang_start+0xa8/0x12c)
[    2.359207]  r10:ee8d4f80 r9:ef0f5000 r8:ef0f5010 r7:ffffffed r6:ef340a60 r5:ef340ce0
[    2.367055]  r4:ef340800
[    2.369623] [<c05f3460>] (spi_bitbang_start) from [<c05f6700>] (spi_imx_probe+0x378/0x604)
[    2.377909]  r5:ef340800 r4:ef340ce0
[    2.381518] [<c05f6388>] (spi_imx_probe) from [<c05409cc>] (platform_drv_probe+0x58/0xb8)
[    2.389727]  r10:c0d00618 r9:00000000 r8:00000000 r7:fffffdfb r6:c0e40ccc r5:fffffffe
[    2.397574]  r4:ef0f5010
[    2.400140] [<c0540974>] (platform_drv_probe) from [<c053ed28>] (driver_probe_device+0x268/0x2f0)
[    2.409037]  r7:c0e40ccc r6:00000000 r5:c166767c r4:ef0f5010
[    2.414730] [<c053eac0>] (driver_probe_device) from [<c053ee78>] (__driver_attach+0xc8/0xcc)
[    2.423197]  r9:c0d5f858 r8:00000000 r7:00000000 r6:ef0f5044 r5:c0e40ccc r4:ef0f5010
[    2.430973] [<c053edb0>] (__driver_attach) from [<c053cf8c>] (bus_for_each_dev+0x74/0xa8)
[    2.439175]  r7:00000000 r6:c053edb0 r5:c0e40ccc r4:00000000
[    2.444867] [<c053cf18>] (bus_for_each_dev) from [<c053e680>] (driver_attach+0x20/0x28)
[    2.452894]  r6:c0e3b068 r5:ee8d7300 r4:c0e40ccc
[    2.457544] [<c053e660>] (driver_attach) from [<c053e1a4>] (bus_add_driver+0x104/0x214)
[    2.465582] [<c053e0a0>] (bus_add_driver) from [<c053f814>] (driver_register+0x80/0xfc)
[    2.473611]  r7:c0cdd42c r6:c0d5f850 r5:ffffe000 r4:c0e40ccc
[    2.479302] [<c053f794>] (driver_register) from [<c054091c>] (__platform_driver_register+0x38/0x4c)
[    2.488369]  r5:ffffe000 r4:c0d47a14
[    2.491984] [<c05408e4>] (__platform_driver_register) from [<c0d47a2c>] (spi_imx_driver_init+0x18/0x20)
[    2.501412] [<c0d47a14>] (spi_imx_driver_init) from [<c0101934>] (do_one_initcall+0x44/0x178)
[    2.509977] [<c01018f0>] (do_one_initcall) from [<c0d00e74>] (kernel_init_freeable+0x12c/0x1ec)
[    2.518704]  r8:000000ef r7:c0cdd42c r6:c0d5f850 r5:c0e7c000 r4:c0d70ee8
[    2.525441] [<c0d00d48>] (kernel_init_freeable) from [<c09af0e8>] (kernel_init+0x10/0x118)
[    2.533735]  r10:00000000 r9:00000000 r8:00000000 r7:00000000 r6:00000000 r5:c09af0d8
[    2.541582]  r4:00000000
[    2.544153] [<c09af0d8>] (kernel_init) from [<c0107d30>] (ret_from_fork+0x14/0x24)
[    2.551745]  r5:c09af0d8 r4:00000000
[    2.555349] Code: e1b03123 0affff6a e2422004 e3a01000 (e5923004)
[    2.561619] ---[ end trace 5e472bb4310ae461 ]---
[    2.566504] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b
[    2.566504]
[    2.575695] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b
[    2.575695]
[    2.604346] random: fast init done

This is at commit 8d4a6cad7adb3ddac32cd52635f20e11de11a658 from
broonie/spi/topic/imx which has no other patches on top of v4.12-rc1.

From a very brief investigation it seems this is not handling correctly
the cases where spi_transfer->rx_buf or tx_buf are NULL?

--
Regards,
Leonard
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index b402530..782045f 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -56,9 +56,11 @@ 
 
 /* The maximum  bytes that a sdma BD can transfer.*/
 #define MAX_SDMA_BD_BYTES  (1 << 15)
+#define MX51_ECSPI_CTRL_MAX_BURST	512
 struct spi_imx_config {
 	unsigned int speed_hz;
 	unsigned int bpw;
+	unsigned int len;
 };
 
 enum spi_imx_devtype {
@@ -97,12 +99,14 @@  struct spi_imx_data {
 	unsigned int bytes_per_word;
 	unsigned int spi_drctl;
 
-	unsigned int count;
+	unsigned int count, count_index;
 	void (*tx)(struct spi_imx_data *);
 	void (*rx)(struct spi_imx_data *);
 	void *rx_buf;
 	const void *tx_buf;
 	unsigned int txfifo; /* number of words pushed in tx FIFO */
+	unsigned int dynamic_burst, bpw_rx;
+	unsigned int bpw_w;
 
 	/* DMA */
 	bool usedma;
@@ -252,6 +256,7 @@  static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
 #define MX51_ECSPI_CTRL_PREDIV_OFFSET	12
 #define MX51_ECSPI_CTRL_CS(cs)		((cs) << 18)
 #define MX51_ECSPI_CTRL_BL_OFFSET	20
+#define MX51_ECSPI_CTRL_BL_MASK		(0xfff << 20)
 
 #define MX51_ECSPI_CONFIG	0x0c
 #define MX51_ECSPI_CONFIG_SCLKPHA(cs)	(1 << ((cs) +  0))
@@ -279,6 +284,71 @@  static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
 #define MX51_ECSPI_TESTREG	0x20
 #define MX51_ECSPI_TESTREG_LBC	BIT(31)
 
+static void spi_imx_u32_swap_u8(struct spi_transfer *transfer, u32 *buf)
+{
+	int i;
+
+	for (i = 0; i < transfer->len / 4; i++)
+		*(buf + i) = cpu_to_be32(*(buf + i));
+}
+
+static void spi_imx_u32_swap_u16(struct spi_transfer *transfer, u32 *buf)
+{
+	int i;
+
+	for (i = 0; i < transfer->len / 4; i++) {
+		u16 *temp = (u16 *)buf;
+
+		*(temp + i * 2) = cpu_to_be16(*(temp + i * 2));
+		*(temp + i * 2 + 1) = cpu_to_be16(*(temp + i * 2 + 1));
+
+		*(buf + i) = cpu_to_be32(*(buf + i));
+	}
+}
+
+static void spi_imx_buf_rx_swap(struct spi_imx_data *spi_imx)
+{
+	if (!spi_imx->bpw_rx) {
+		spi_imx_buf_rx_u32(spi_imx);
+		return;
+	}
+
+	if (spi_imx->bpw_w == 1)
+		spi_imx_buf_rx_u8(spi_imx);
+	else if (spi_imx->bpw_w == 2)
+		spi_imx_buf_rx_u16(spi_imx);
+}
+
+static void spi_imx_buf_tx_swap(struct spi_imx_data *spi_imx)
+{
+	u32 ctrl, val;
+
+	if (spi_imx->count == spi_imx->count_index) {
+		spi_imx->count_index = spi_imx->count > sizeof(u32) ?
+					spi_imx->count % sizeof(u32) : 0;
+		ctrl = readl(spi_imx->base + MX51_ECSPI_CTRL);
+		ctrl &= ~MX51_ECSPI_CTRL_BL_MASK;
+		if (spi_imx->count >= sizeof(u32)) {
+			val = spi_imx->count - spi_imx->count_index;
+		} else {
+			val = spi_imx->bpw_w;
+			spi_imx->bpw_rx = 1;
+		}
+		ctrl |= ((val * 8 - 1) << MX51_ECSPI_CTRL_BL_OFFSET);
+		writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
+	}
+
+	if (spi_imx->count >= sizeof(u32)) {
+		spi_imx_buf_tx_u32(spi_imx);
+		return;
+	}
+
+	if (spi_imx->bpw_w == 1)
+		spi_imx_buf_tx_u8(spi_imx);
+	else if (spi_imx->bpw_w == 2)
+		spi_imx_buf_tx_u16(spi_imx);
+}
+
 /* MX51 eCSPI */
 static unsigned int mx51_ecspi_clkdiv(struct spi_imx_data *spi_imx,
 				      unsigned int fspi, unsigned int *fres)
@@ -370,7 +440,15 @@  static int mx51_ecspi_config(struct spi_device *spi,
 	/* set chip select to use */
 	ctrl |= MX51_ECSPI_CTRL_CS(spi->chip_select);
 
-	ctrl |= (config->bpw - 1) << MX51_ECSPI_CTRL_BL_OFFSET;
+	if (spi_imx->dynamic_burst) {
+		if (config->len > MX51_ECSPI_CTRL_MAX_BURST)
+			ctrl |= MX51_ECSPI_CTRL_BL_MASK;
+		else
+			ctrl |= (((config->len - config->len % 4) * 8 - 1) <<
+				MX51_ECSPI_CTRL_BL_OFFSET);
+	} else {
+		ctrl |= (config->bpw - 1) << MX51_ECSPI_CTRL_BL_OFFSET;
+	}
 
 	cfg |= MX51_ECSPI_CONFIG_SBBCTRL(spi->chip_select);
 
@@ -805,6 +883,8 @@  static void spi_imx_push(struct spi_imx_data *spi_imx)
 	while (spi_imx->txfifo < spi_imx_get_fifosize(spi_imx)) {
 		if (!spi_imx->count)
 			break;
+		if (spi_imx->txfifo && (spi_imx->count == spi_imx->count_index))
+			break;
 		spi_imx->tx(spi_imx);
 		spi_imx->txfifo++;
 	}
@@ -895,8 +975,12 @@  static int spi_imx_setupxfer(struct spi_device *spi,
 	struct spi_imx_config config;
 	int ret;
 
+	spi_imx->dynamic_burst = 0;
+	spi_imx->bpw_rx = 0;
+
 	config.bpw = t ? t->bits_per_word : spi->bits_per_word;
 	config.speed_hz  = t ? t->speed_hz : spi->max_speed_hz;
+	config.len = t->len;
 
 	if (!config.speed_hz)
 		config.speed_hz = spi->max_speed_hz;
@@ -905,14 +989,32 @@  static int spi_imx_setupxfer(struct spi_device *spi,
 
 	/* Initialize the functions for transfer */
 	if (config.bpw <= 8) {
-		spi_imx->rx = spi_imx_buf_rx_u8;
-		spi_imx->tx = spi_imx_buf_tx_u8;
+		if (t->len >= sizeof(u32) && is_imx51_ecspi(spi_imx)) {
+			spi_imx->dynamic_burst = 1;
+			spi_imx->rx = spi_imx_buf_rx_swap;
+			spi_imx->tx = spi_imx_buf_tx_swap;
+		} else {
+			spi_imx->rx = spi_imx_buf_rx_u8;
+			spi_imx->tx = spi_imx_buf_tx_u8;
+		}
 	} else if (config.bpw <= 16) {
-		spi_imx->rx = spi_imx_buf_rx_u16;
-		spi_imx->tx = spi_imx_buf_tx_u16;
+		if (t->len >= sizeof(u32) && is_imx51_ecspi(spi_imx)) {
+			spi_imx->dynamic_burst = 1;
+			spi_imx->rx = spi_imx_buf_rx_swap;
+			spi_imx->tx = spi_imx_buf_tx_swap;
+		} else {
+			spi_imx->rx = spi_imx_buf_rx_u16;
+			spi_imx->tx = spi_imx_buf_tx_u16;
+		}
 	} else {
-		spi_imx->rx = spi_imx_buf_rx_u32;
-		spi_imx->tx = spi_imx_buf_tx_u32;
+		if (is_imx51_ecspi(spi_imx)) {
+			spi_imx->dynamic_burst = 1;
+			spi_imx->rx = spi_imx_buf_rx_swap;
+			spi_imx->tx = spi_imx_buf_tx_swap;
+		} else {
+			spi_imx->rx = spi_imx_buf_rx_u32;
+			spi_imx->tx = spi_imx_buf_tx_u32;
+		}
 	}
 
 	if (spi_imx_can_dma(spi_imx->bitbang.master, spi, t))
@@ -920,6 +1022,8 @@  static int spi_imx_setupxfer(struct spi_device *spi,
 	else
 		spi_imx->usedma = 0;
 
+	spi_imx->bpw_w = DIV_ROUND_UP(config.bpw, 8);
+
 	if (spi_imx->usedma) {
 		ret = spi_imx_dma_configure(spi->master,
 					    spi_imx_bytes_per_word(config.bpw));
@@ -1094,6 +1198,27 @@  static int spi_imx_pio_transfer(struct spi_device *spi,
 	spi_imx->count = transfer->len;
 	spi_imx->txfifo = 0;
 
+	if (spi_imx->dynamic_burst) {
+		if (spi_imx->count > MX51_ECSPI_CTRL_MAX_BURST)
+			spi_imx->count_index = spi_imx->count %
+					       MX51_ECSPI_CTRL_MAX_BURST;
+		else
+			spi_imx->count_index = spi_imx->count % sizeof(u32);
+
+		switch (spi_imx->bpw_w) {
+		case 1:
+			spi_imx_u32_swap_u8(transfer,
+					    (u32 *)transfer->tx_buf);
+			break;
+		case 2:
+			spi_imx_u32_swap_u16(transfer,
+					     (u32 *)transfer->tx_buf);
+			break;
+		default:
+			break;
+		}
+	}
+
 	reinit_completion(&spi_imx->xfer_done);
 
 	spi_imx_push(spi_imx);
@@ -1110,6 +1235,22 @@  static int spi_imx_pio_transfer(struct spi_device *spi,
 		return -ETIMEDOUT;
 	}
 
+	if (spi_imx->dynamic_burst) {
+		switch (spi_imx->bpw_w) {
+		case 1:
+			spi_imx_u32_swap_u8(transfer,
+					    (u32 *)transfer->rx_buf);
+			break;
+		case 2:
+			spi_imx_u32_swap_u16(transfer,
+					     (u32 *)transfer->rx_buf);
+			break;
+		default:
+			break;
+		}
+		spi_imx->dynamic_burst = 0;
+	}
+
 	return transfer->len;
 }