memory: renesas-rpc-if: Fix HF/OSPI data transfer in Manual Mode
[ Upstream commit 7e842d70fe599bc13594b650b2144c4b6e6d6bf1 ] HyperFlash devices fail to probe: rpc-if-hyperflash rpc-if-hyperflash: probing of hyperbus device failed In HyperFlash or Octal-SPI Flash mode, the Transfer Data Enable bits (SPIDE) in the Manual Mode Enable Setting Register (SMENR) are derived from half of the transfer size, cfr. the rpcif_bits_set() helper function. However, rpcif_reg_{read,write}() does not take the bus size into account, and does not double all Manual Mode Data Register access sizes when communicating with a HyperFlash or Octal-SPI Flash device. Fix this, and avoid the back-and-forth conversion between transfer size and Transfer Data Enable bits, by explicitly storing the transfer size in struct rpcif, and using that value to determine access size in rpcif_reg_{read,write}(). Enforce that the "high" Manual Mode Read/Write Data Registers (SM[RW]DR1) are only used for 8-byte data accesses. While at it, forbid writing to the Manual Mode Read Data Registers, as they are read-only. Fixes: fff53a551db50f5e ("memory: renesas-rpc-if: Correct QSPI data transfer in Manual mode") Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> Tested-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com> Tested-by: Wolfram Sang <wsa+renesas@sang-engineering.com> Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com> Link: https://lore.kernel.org/r/cde9bfacf704c81865f57b15d1b48a4793da4286.1649681476.git.geert+renesas@glider.be Link: https://lore.kernel.org/r/20220420070526.9367-1-krzysztof.kozlowski@linaro.org' Signed-off-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
690c1bc4bf
commit
14cc2044c1
@ -163,25 +163,39 @@ static const struct regmap_access_table rpcif_volatile_table = {
|
||||
|
||||
|
||||
/*
|
||||
* Custom accessor functions to ensure SMRDR0 and SMWDR0 are always accessed
|
||||
* with proper width. Requires SMENR_SPIDE to be correctly set before!
|
||||
* Custom accessor functions to ensure SM[RW]DR[01] are always accessed with
|
||||
* proper width. Requires rpcif.xfer_size to be correctly set before!
|
||||
*/
|
||||
static int rpcif_reg_read(void *context, unsigned int reg, unsigned int *val)
|
||||
{
|
||||
struct rpcif *rpc = context;
|
||||
|
||||
if (reg == RPCIF_SMRDR0 || reg == RPCIF_SMWDR0) {
|
||||
u32 spide = readl(rpc->base + RPCIF_SMENR) & RPCIF_SMENR_SPIDE(0xF);
|
||||
|
||||
if (spide == 0x8) {
|
||||
switch (reg) {
|
||||
case RPCIF_SMRDR0:
|
||||
case RPCIF_SMWDR0:
|
||||
switch (rpc->xfer_size) {
|
||||
case 1:
|
||||
*val = readb(rpc->base + reg);
|
||||
return 0;
|
||||
} else if (spide == 0xC) {
|
||||
|
||||
case 2:
|
||||
*val = readw(rpc->base + reg);
|
||||
return 0;
|
||||
} else if (spide != 0xF) {
|
||||
|
||||
case 4:
|
||||
case 8:
|
||||
*val = readl(rpc->base + reg);
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return -EILSEQ;
|
||||
}
|
||||
|
||||
case RPCIF_SMRDR1:
|
||||
case RPCIF_SMWDR1:
|
||||
if (rpc->xfer_size != 8)
|
||||
return -EILSEQ;
|
||||
break;
|
||||
}
|
||||
|
||||
*val = readl(rpc->base + reg);
|
||||
@ -193,18 +207,34 @@ static int rpcif_reg_write(void *context, unsigned int reg, unsigned int val)
|
||||
{
|
||||
struct rpcif *rpc = context;
|
||||
|
||||
if (reg == RPCIF_SMRDR0 || reg == RPCIF_SMWDR0) {
|
||||
u32 spide = readl(rpc->base + RPCIF_SMENR) & RPCIF_SMENR_SPIDE(0xF);
|
||||
|
||||
if (spide == 0x8) {
|
||||
switch (reg) {
|
||||
case RPCIF_SMWDR0:
|
||||
switch (rpc->xfer_size) {
|
||||
case 1:
|
||||
writeb(val, rpc->base + reg);
|
||||
return 0;
|
||||
} else if (spide == 0xC) {
|
||||
|
||||
case 2:
|
||||
writew(val, rpc->base + reg);
|
||||
return 0;
|
||||
} else if (spide != 0xF) {
|
||||
|
||||
case 4:
|
||||
case 8:
|
||||
writel(val, rpc->base + reg);
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return -EILSEQ;
|
||||
}
|
||||
|
||||
case RPCIF_SMWDR1:
|
||||
if (rpc->xfer_size != 8)
|
||||
return -EILSEQ;
|
||||
break;
|
||||
|
||||
case RPCIF_SMRDR0:
|
||||
case RPCIF_SMRDR1:
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
writel(val, rpc->base + reg);
|
||||
@ -455,6 +485,7 @@ int rpcif_manual_xfer(struct rpcif *rpc)
|
||||
|
||||
smenr |= RPCIF_SMENR_SPIDE(rpcif_bits_set(rpc, nbytes));
|
||||
regmap_write(rpc->regmap, RPCIF_SMENR, smenr);
|
||||
rpc->xfer_size = nbytes;
|
||||
|
||||
memcpy(data, rpc->buffer + pos, nbytes);
|
||||
if (nbytes == 8) {
|
||||
@ -519,6 +550,7 @@ int rpcif_manual_xfer(struct rpcif *rpc)
|
||||
regmap_write(rpc->regmap, RPCIF_SMENR, smenr);
|
||||
regmap_write(rpc->regmap, RPCIF_SMCR,
|
||||
rpc->smcr | RPCIF_SMCR_SPIE);
|
||||
rpc->xfer_size = nbytes;
|
||||
ret = wait_msg_xfer_end(rpc);
|
||||
if (ret)
|
||||
goto err_out;
|
||||
|
@ -65,6 +65,7 @@ struct rpcif {
|
||||
size_t size;
|
||||
enum rpcif_data_dir dir;
|
||||
u8 bus_size;
|
||||
u8 xfer_size;
|
||||
void *buffer;
|
||||
u32 xferlen;
|
||||
u32 smcr;
|
||||
|
Loading…
Reference in New Issue
Block a user