Unverified Commit 7e842d70 authored by Geert Uytterhoeven's avatar Geert Uytterhoeven Committed by Arnd Bergmann
Browse files

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: fff53a55 ("memory: renesas-rpc-if: Correct QSPI data transfer in Manual mode")
Signed-off-by: default avatarGeert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: default avatarKrzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Tested-by: default avatarLad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Tested-by: default avatarWolfram Sang <wsa+renesas@sang-engineering.com>
Reviewed-by: default avatarWolfram 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: default avatarArnd Bergmann <arnd@arndb.de>
parent 67e473a3
Loading
Loading
Loading
Loading
+46 −14
Original line number Diff line number Diff line
@@ -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;
+1 −0
Original line number Diff line number Diff line
@@ -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;