forked from Minki/linux
memory: renesas-rpc-if: Fix HF/OSPI data transfer in Manual Mode
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: fff53a551d
("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>
This commit is contained in:
parent
67e473a303
commit
7e842d70fe
@ -164,25 +164,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);
|
||||
@ -469,6 +499,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) {
|
||||
@ -533,6 +564,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;
|
||||
|
@ -72,6 +72,7 @@ struct rpcif {
|
||||
enum rpcif_type type;
|
||||
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