Unverified Commit e8f78756 authored by Arnd Bergmann's avatar Arnd Bergmann
Browse files

Merge tag 'memory-controller-drv-renesas-5.17' of...

Merge tag 'memory-controller-drv-renesas-5.17' of git://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl into arm/drivers

Memory controller drivers for v5.17 - Renesas

Changes to the Renesas RPC-IF driver:
1. Add support for R9A07G044 / RZ/G2L.
2. Several minor fixes and improvements to the driver.

* tag 'memory-controller-drv-renesas-5.17' of git://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl:
  memory: renesas-rpc-if: refactor MOIIO and IOFV macros
  memory: renesas-rpc-if: avoid use of undocumented bits
  memory: renesas-rpc-if: simplify register update
  memory: renesas-rpc-if: Silence clang warning
  memory: renesas-rpc-if: Add support for RZ/G2L
  memory: renesas-rpc-if: Drop usage of RPCIF_DIRMAP_SIZE macro
  memory: renesas-rpc-if: Return error in case devm_ioremap_resource() fails
  dt-bindings: memory: renesas,rpc-if: Add optional interrupts property
  dt-bindings: memory: renesas,rpc-if: Add support for the R9A07G044

Link: https://lore.kernel.org/r/20211213105618.5686-1-krzysztof.kozlowski@canonical.com


Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
parents c6e5bdae 3542de6a
Loading
Loading
Loading
Loading
+40 −14
Original line number Diff line number Diff line
@@ -24,7 +24,8 @@ allOf:

properties:
  compatible:
    items:
    oneOf:
      - items:
          - enum:
              - renesas,r8a774a1-rpc-if       # RZ/G2M
              - renesas,r8a774b1-rpc-if       # RZ/G2N
@@ -34,7 +35,12 @@ properties:
              - renesas,r8a77980-rpc-if       # R-Car V3H
              - renesas,r8a77995-rpc-if       # R-Car D3
              - renesas,r8a779a0-rpc-if       # R-Car V3U
      - const: renesas,rcar-gen3-rpc-if   # a generic R-Car gen3 or RZ/G2 device
          - const: renesas,rcar-gen3-rpc-if   # a generic R-Car gen3 or RZ/G2{E,H,M,N} device

      - items:
          - enum:
              - renesas,r9a07g044-rpc-if      # RZ/G2{L,LC}
          - const: renesas,rzg2l-rpc-if       # RZ/G2L family

  reg:
    items:
@@ -48,7 +54,9 @@ properties:
      - const: dirmap
      - const: wbuf

  clocks:
  clocks: true

  interrupts:
    maxItems: 1

  power-domains:
@@ -67,8 +75,6 @@ patternProperties:
            - cfi-flash
            - jedec,spi-nor

unevaluatedProperties: false

required:
  - compatible
  - reg
@@ -79,6 +85,26 @@ required:
  - '#address-cells'
  - '#size-cells'

if:
  properties:
    compatible:
      contains:
        enum:
          - renesas,rzg2l-rpc-if
then:
  properties:
    clocks:
      items:
        - description: SPI Multi IO Register access clock (SPI_CLK2)
        - description: SPI Multi IO Main clock (SPI_CLK).

else:
  properties:
    clocks:
      maxItems: 1

unevaluatedProperties: false

examples:
  - |
    #include <dt-bindings/clock/renesas-cpg-mssr.h>
+69 −40
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/reset.h>

@@ -19,19 +20,17 @@

#define RPCIF_CMNCR		0x0000	/* R/W */
#define RPCIF_CMNCR_MD		BIT(31)
#define RPCIF_CMNCR_SFDE	BIT(24) /* undocumented but must be set */
#define RPCIF_CMNCR_MOIIO3(val)	(((val) & 0x3) << 22)
#define RPCIF_CMNCR_MOIIO2(val)	(((val) & 0x3) << 20)
#define RPCIF_CMNCR_MOIIO1(val)	(((val) & 0x3) << 18)
#define RPCIF_CMNCR_MOIIO0(val)	(((val) & 0x3) << 16)
#define RPCIF_CMNCR_MOIIO_HIZ	(RPCIF_CMNCR_MOIIO0(3) | \
				 RPCIF_CMNCR_MOIIO1(3) | \
				 RPCIF_CMNCR_MOIIO2(3) | RPCIF_CMNCR_MOIIO3(3))
#define RPCIF_CMNCR_IO3FV(val)	(((val) & 0x3) << 14) /* undocumented */
#define RPCIF_CMNCR_IO2FV(val)	(((val) & 0x3) << 12) /* undocumented */
#define RPCIF_CMNCR_MOIIO(val)	(RPCIF_CMNCR_MOIIO0(val) | RPCIF_CMNCR_MOIIO1(val) | \
				 RPCIF_CMNCR_MOIIO2(val) | RPCIF_CMNCR_MOIIO3(val))
#define RPCIF_CMNCR_IO3FV(val)	(((val) & 0x3) << 14) /* documented for RZ/G2L */
#define RPCIF_CMNCR_IO2FV(val)	(((val) & 0x3) << 12) /* documented for RZ/G2L */
#define RPCIF_CMNCR_IO0FV(val)	(((val) & 0x3) << 8)
#define RPCIF_CMNCR_IOFV_HIZ	(RPCIF_CMNCR_IO0FV(3) | RPCIF_CMNCR_IO2FV(3) | \
				 RPCIF_CMNCR_IO3FV(3))
#define RPCIF_CMNCR_IOFV(val)	(RPCIF_CMNCR_IO0FV(val) | RPCIF_CMNCR_IO2FV(val) | \
				 RPCIF_CMNCR_IO3FV(val))
#define RPCIF_CMNCR_BSZ(val)	(((val) & 0x3) << 0)

#define RPCIF_SSLDR		0x0004	/* R/W */
@@ -126,6 +125,9 @@
#define RPCIF_SMDRENR_OPDRE	BIT(4)
#define RPCIF_SMDRENR_SPIDRE	BIT(0)

#define RPCIF_PHYADD		0x0070	/* R/W available on R-Car E3/D3/V3M and RZ/G2{E,L} */
#define RPCIF_PHYWR		0x0074	/* R/W available on R-Car E3/D3/V3M and RZ/G2{E,L} */

#define RPCIF_PHYCNT		0x007C	/* R/W */
#define RPCIF_PHYCNT_CAL	BIT(31)
#define RPCIF_PHYCNT_OCTA(v)	(((v) & 0x3) << 22)
@@ -133,10 +135,12 @@
#define RPCIF_PHYCNT_OCT	BIT(20)
#define RPCIF_PHYCNT_DDRCAL	BIT(19)
#define RPCIF_PHYCNT_HS		BIT(18)
#define RPCIF_PHYCNT_STRTIM(v)	(((v) & 0x7) << 15)
#define RPCIF_PHYCNT_CKSEL(v)	(((v) & 0x3) << 16) /* valid only for RZ/G2L */
#define RPCIF_PHYCNT_STRTIM(v)	(((v) & 0x7) << 15) /* valid for R-Car and RZ/G2{E,H,M,N} */
#define RPCIF_PHYCNT_WBUF2	BIT(4)
#define RPCIF_PHYCNT_WBUF	BIT(2)
#define RPCIF_PHYCNT_PHYMEM(v)	(((v) & 0x3) << 0)
#define RPCIF_PHYCNT_PHYMEM_MASK GENMASK(1, 0)

#define RPCIF_PHYOFFSET1	0x0080	/* R/W */
#define RPCIF_PHYOFFSET1_DDRTMG(v) (((v) & 0x3) << 28)
@@ -147,8 +151,6 @@
#define RPCIF_PHYINT		0x0088	/* R/W */
#define RPCIF_PHYINT_WPVAL	BIT(1)

#define RPCIF_DIRMAP_SIZE	0x4000000

static const struct regmap_range rpcif_volatile_ranges[] = {
	regmap_reg_range(RPCIF_SMRDR0, RPCIF_SMRDR1),
	regmap_reg_range(RPCIF_SMWDR0, RPCIF_SMWDR1),
@@ -243,50 +245,74 @@ int rpcif_sw_init(struct rpcif *rpc, struct device *dev)
	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dirmap");
	rpc->dirmap = devm_ioremap_resource(&pdev->dev, res);
	if (IS_ERR(rpc->dirmap))
		rpc->dirmap = NULL;
		return PTR_ERR(rpc->dirmap);
	rpc->size = resource_size(res);

	rpc->type = (uintptr_t)of_device_get_match_data(dev);
	rpc->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);

	return PTR_ERR_OR_ZERO(rpc->rstc);
}
EXPORT_SYMBOL(rpcif_sw_init);

void rpcif_hw_init(struct rpcif *rpc, bool hyperflash)
static void rpcif_rzg2l_timing_adjust_sdr(struct rpcif *rpc)
{
	regmap_write(rpc->regmap, RPCIF_PHYWR, 0xa5390000);
	regmap_write(rpc->regmap, RPCIF_PHYADD, 0x80000000);
	regmap_write(rpc->regmap, RPCIF_PHYWR, 0x00008080);
	regmap_write(rpc->regmap, RPCIF_PHYADD, 0x80000022);
	regmap_write(rpc->regmap, RPCIF_PHYWR, 0x00008080);
	regmap_write(rpc->regmap, RPCIF_PHYADD, 0x80000024);
	regmap_update_bits(rpc->regmap, RPCIF_PHYCNT, RPCIF_PHYCNT_CKSEL(3),
			   RPCIF_PHYCNT_CKSEL(3));
	regmap_write(rpc->regmap, RPCIF_PHYWR, 0x00000030);
	regmap_write(rpc->regmap, RPCIF_PHYADD, 0x80000032);
}

int rpcif_hw_init(struct rpcif *rpc, bool hyperflash)
{
	u32 dummy;

	pm_runtime_get_sync(rpc->dev);

	/*
	 * NOTE: The 0x260 are undocumented bits, but they must be set.
	 *	 RPCIF_PHYCNT_STRTIM is strobe timing adjustment bits,
	 *	 0x0 : the delay is biggest,
	 *	 0x1 : the delay is 2nd biggest,
	 *	 On H3 ES1.x, the value should be 0, while on others,
	 *	 the value should be 7.
	 */
	regmap_write(rpc->regmap, RPCIF_PHYCNT, RPCIF_PHYCNT_STRTIM(7) |
		     RPCIF_PHYCNT_PHYMEM(hyperflash ? 3 : 0) | 0x260);
	if (rpc->type == RPCIF_RZ_G2L) {
		int ret;

	/*
	 * NOTE: The 0x1511144 are undocumented bits, but they must be set
	 *       for RPCIF_PHYOFFSET1.
	 *	 The 0x31 are undocumented bits, but they must be set
	 *	 for RPCIF_PHYOFFSET2.
	 */
	regmap_write(rpc->regmap, RPCIF_PHYOFFSET1, 0x1511144 |
		ret = reset_control_reset(rpc->rstc);
		if (ret)
			return ret;
		usleep_range(200, 300);
		rpcif_rzg2l_timing_adjust_sdr(rpc);
	}

	regmap_update_bits(rpc->regmap, RPCIF_PHYCNT, RPCIF_PHYCNT_PHYMEM_MASK,
			   RPCIF_PHYCNT_PHYMEM(hyperflash ? 3 : 0));

	if (rpc->type == RPCIF_RCAR_GEN3)
		regmap_update_bits(rpc->regmap, RPCIF_PHYCNT,
				   RPCIF_PHYCNT_STRTIM(7), RPCIF_PHYCNT_STRTIM(7));

	regmap_update_bits(rpc->regmap, RPCIF_PHYOFFSET1, RPCIF_PHYOFFSET1_DDRTMG(3),
			   RPCIF_PHYOFFSET1_DDRTMG(3));
	regmap_write(rpc->regmap, RPCIF_PHYOFFSET2, 0x31 |
	regmap_update_bits(rpc->regmap, RPCIF_PHYOFFSET2, RPCIF_PHYOFFSET2_OCTTMG(7),
			   RPCIF_PHYOFFSET2_OCTTMG(4));

	if (hyperflash)
		regmap_update_bits(rpc->regmap, RPCIF_PHYINT,
				   RPCIF_PHYINT_WPVAL, 0);

	regmap_write(rpc->regmap, RPCIF_CMNCR, RPCIF_CMNCR_SFDE |
		     RPCIF_CMNCR_MOIIO_HIZ | RPCIF_CMNCR_IOFV_HIZ |
	if (rpc->type == RPCIF_RCAR_GEN3)
		regmap_update_bits(rpc->regmap, RPCIF_CMNCR,
				   RPCIF_CMNCR_MOIIO(3) | RPCIF_CMNCR_BSZ(3),
				   RPCIF_CMNCR_MOIIO(3) |
				   RPCIF_CMNCR_BSZ(hyperflash ? 1 : 0));
	else
		regmap_update_bits(rpc->regmap, RPCIF_CMNCR,
				   RPCIF_CMNCR_MOIIO(3) | RPCIF_CMNCR_IOFV(3) |
				   RPCIF_CMNCR_BSZ(3),
				   RPCIF_CMNCR_MOIIO(1) | RPCIF_CMNCR_IOFV(2) |
				   RPCIF_CMNCR_BSZ(hyperflash ? 1 : 0));

	/* Set RCF after BSZ update */
	regmap_write(rpc->regmap, RPCIF_DRCR, RPCIF_DRCR_RCF);
	/* Dummy read according to spec */
@@ -297,6 +323,8 @@ void rpcif_hw_init(struct rpcif *rpc, bool hyperflash)
	pm_runtime_put(rpc->dev);

	rpc->bus_size = hyperflash ? 2 : 1;

	return 0;
}
EXPORT_SYMBOL(rpcif_hw_init);

@@ -588,8 +616,8 @@ static void memcpy_fromio_readw(void *to,

ssize_t rpcif_dirmap_read(struct rpcif *rpc, u64 offs, size_t len, void *buf)
{
	loff_t from = offs & (RPCIF_DIRMAP_SIZE - 1);
	size_t size = RPCIF_DIRMAP_SIZE - from;
	loff_t from = offs & (rpc->size - 1);
	size_t size = rpc->size - from;

	if (len > size)
		len = size;
@@ -659,7 +687,8 @@ static int rpcif_remove(struct platform_device *pdev)
}

static const struct of_device_id rpcif_of_match[] = {
	{ .compatible = "renesas,rcar-gen3-rpc-if", },
	{ .compatible = "renesas,rcar-gen3-rpc-if", .data = (void *)RPCIF_RCAR_GEN3 },
	{ .compatible = "renesas,rzg2l-rpc-if", .data = (void *)RPCIF_RZ_G2L },
	{},
};
MODULE_DEVICE_TABLE(of, rpcif_of_match);
+3 −1
Original line number Diff line number Diff line
@@ -130,7 +130,9 @@ static int rpcif_hb_probe(struct platform_device *pdev)

	rpcif_enable_rpm(&hyperbus->rpc);

	rpcif_hw_init(&hyperbus->rpc, true);
	error = rpcif_hw_init(&hyperbus->rpc, true);
	if (error)
		return error;

	hyperbus->hbdev.map.size = hyperbus->rpc.size;
	hyperbus->hbdev.map.virt = hyperbus->rpc.dirmap;
+3 −1
Original line number Diff line number Diff line
@@ -156,7 +156,9 @@ static int rpcif_spi_probe(struct platform_device *pdev)
	ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_QUAD | SPI_RX_QUAD;
	ctlr->flags = SPI_CONTROLLER_HALF_DUPLEX;

	rpcif_hw_init(rpc, false);
	error = rpcif_hw_init(rpc, false);
	if (error)
		return error;

	error = spi_register_controller(ctlr);
	if (error) {
+7 −1
Original line number Diff line number Diff line
@@ -57,6 +57,11 @@ struct rpcif_op {
	} data;
};

enum rpcif_type {
	RPCIF_RCAR_GEN3,
	RPCIF_RZ_G2L,
};

struct rpcif {
	struct device *dev;
	void __iomem *base;
@@ -64,6 +69,7 @@ struct rpcif {
	struct regmap *regmap;
	struct reset_control *rstc;
	size_t size;
	enum rpcif_type type;
	enum rpcif_data_dir dir;
	u8 bus_size;
	void *buffer;
@@ -78,7 +84,7 @@ struct rpcif {
};

int rpcif_sw_init(struct rpcif *rpc, struct device *dev);
void rpcif_hw_init(struct rpcif *rpc, bool hyperflash);
int rpcif_hw_init(struct rpcif *rpc, bool hyperflash);
void rpcif_prepare(struct rpcif *rpc, const struct rpcif_op *op, u64 *offs,
		   size_t *len);
int rpcif_manual_xfer(struct rpcif *rpc);