Skip to content

Commit 671ffde

Browse files
vladimirolteanbroonie
authored andcommitted
spi: spi-fsl-dspi: Fix little endian access to PUSHR CMD and TXDATA
In XSPI mode, the 32-bit PUSHR register can be written to separately: the higher 16 bits are for commands and the lower 16 bits are for data. This has nicely been hacked around, by defining a second regmap with a width of 16 bits, and effectively splitting a 32-bit register into 2 16-bit ones, from the perspective of this regmap_pushr. The problem is the assumption about the controller's endianness. If the controller is little endian (such as anything post-LS1046A), then the first 2 bytes, in the order imposed by memory layout, will actually hold the TXDATA, and the last 2 bytes will hold the CMD. So take the controller's endianness into account when performing split writes to PUSHR. The obvious and simple solution would have been to call regmap_get_val_endian(), but that is an internal regmap function and we don't want to change regmap just for this. Therefore, we just re-read the "big-endian" device tree property. Fixes: 58ba07e ("spi: spi-fsl-dspi: Add support for XSPI mode registers") Signed-off-by: Vladimir Oltean <[email protected]> Tested-by: Michael Walle <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent 4fcc7c2 commit 671ffde

File tree

1 file changed

+20
-6
lines changed

1 file changed

+20
-6
lines changed

drivers/spi/spi-fsl-dspi.c

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -103,10 +103,6 @@
103103
#define SPI_FRAME_BITS(bits) SPI_CTAR_FMSZ((bits) - 1)
104104
#define SPI_FRAME_EBITS(bits) SPI_CTARE_FMSZE(((bits) - 1) >> 4)
105105

106-
/* Register offsets for regmap_pushr */
107-
#define PUSHR_CMD 0x0
108-
#define PUSHR_TX 0x2
109-
110106
#define DMA_COMPLETION_TIMEOUT msecs_to_jiffies(3000)
111107

112108
struct chip_data {
@@ -240,6 +236,13 @@ struct fsl_dspi {
240236

241237
int words_in_flight;
242238

239+
/*
240+
* Offsets for CMD and TXDATA within SPI_PUSHR when accessed
241+
* individually (in XSPI mode)
242+
*/
243+
int pushr_cmd;
244+
int pushr_tx;
245+
243246
void (*host_to_dev)(struct fsl_dspi *dspi, u32 *txdata);
244247
void (*dev_to_host)(struct fsl_dspi *dspi, u32 rxdata);
245248
};
@@ -673,12 +676,12 @@ static void dspi_pushr_cmd_write(struct fsl_dspi *dspi, u16 cmd)
673676
*/
674677
if (dspi->len > dspi->oper_word_size)
675678
cmd |= SPI_PUSHR_CMD_CONT;
676-
regmap_write(dspi->regmap_pushr, PUSHR_CMD, cmd);
679+
regmap_write(dspi->regmap_pushr, dspi->pushr_cmd, cmd);
677680
}
678681

679682
static void dspi_pushr_txdata_write(struct fsl_dspi *dspi, u16 txdata)
680683
{
681-
regmap_write(dspi->regmap_pushr, PUSHR_TX, txdata);
684+
regmap_write(dspi->regmap_pushr, dspi->pushr_tx, txdata);
682685
}
683686

684687
static void dspi_xspi_write(struct fsl_dspi *dspi, int cnt, bool eoq)
@@ -1259,6 +1262,7 @@ static int dspi_probe(struct platform_device *pdev)
12591262
struct fsl_dspi *dspi;
12601263
struct resource *res;
12611264
void __iomem *base;
1265+
bool big_endian;
12621266

12631267
ctlr = spi_alloc_master(&pdev->dev, sizeof(struct fsl_dspi));
12641268
if (!ctlr)
@@ -1284,6 +1288,7 @@ static int dspi_probe(struct platform_device *pdev)
12841288

12851289
/* Only Coldfire uses platform data */
12861290
dspi->devtype_data = &devtype_data[MCF5441X];
1291+
big_endian = true;
12871292
} else {
12881293

12891294
ret = of_property_read_u32(np, "spi-num-chipselects", &cs_num);
@@ -1305,6 +1310,15 @@ static int dspi_probe(struct platform_device *pdev)
13051310
ret = -EFAULT;
13061311
goto out_ctlr_put;
13071312
}
1313+
1314+
big_endian = of_device_is_big_endian(np);
1315+
}
1316+
if (big_endian) {
1317+
dspi->pushr_cmd = 0;
1318+
dspi->pushr_tx = 2;
1319+
} else {
1320+
dspi->pushr_cmd = 2;
1321+
dspi->pushr_tx = 0;
13081322
}
13091323

13101324
if (dspi->devtype_data->trans_mode == DSPI_XSPI_MODE)

0 commit comments

Comments
 (0)