diff options
author | Arnd Bergmann <arnd@arndb.de> | 2021-12-14 15:54:19 +0100 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2021-12-14 15:54:20 +0100 |
commit | e8f7875680aeddb717248e0467bd533243d326ef (patch) | |
tree | 17be1ff1c95d3d5c7787474cecde184922b10d12 | |
parent | Merge tag 'optee-async-notif-for-v5.17' of https://git.linaro.org/people/jens.wiklander/linux-tee into arm/drivers (diff) | |
parent | memory: renesas-rpc-if: refactor MOIIO and IOFV macros (diff) | |
download | linux-dev-e8f7875680aeddb717248e0467bd533243d326ef.tar.xz linux-dev-e8f7875680aeddb717248e0467bd533243d326ef.zip |
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: Arnd Bergmann <arnd@arndb.de>
-rw-r--r-- | Documentation/devicetree/bindings/memory-controllers/renesas,rpc-if.yaml | 54 | ||||
-rw-r--r-- | drivers/memory/renesas-rpc-if.c | 109 | ||||
-rw-r--r-- | drivers/mtd/hyperbus/rpc-if.c | 4 | ||||
-rw-r--r-- | drivers/spi/spi-rpc-if.c | 4 | ||||
-rw-r--r-- | include/memory/renesas-rpc-if.h | 8 |
5 files changed, 122 insertions, 57 deletions
diff --git a/Documentation/devicetree/bindings/memory-controllers/renesas,rpc-if.yaml b/Documentation/devicetree/bindings/memory-controllers/renesas,rpc-if.yaml index 9da80e8f2444..294f1036420d 100644 --- a/Documentation/devicetree/bindings/memory-controllers/renesas,rpc-if.yaml +++ b/Documentation/devicetree/bindings/memory-controllers/renesas,rpc-if.yaml @@ -24,17 +24,23 @@ allOf: properties: compatible: - items: - - enum: - - renesas,r8a774a1-rpc-if # RZ/G2M - - renesas,r8a774b1-rpc-if # RZ/G2N - - renesas,r8a774c0-rpc-if # RZ/G2E - - renesas,r8a774e1-rpc-if # RZ/G2H - - renesas,r8a77970-rpc-if # R-Car V3M - - 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 + oneOf: + - items: + - enum: + - renesas,r8a774a1-rpc-if # RZ/G2M + - renesas,r8a774b1-rpc-if # RZ/G2N + - renesas,r8a774c0-rpc-if # RZ/G2E + - renesas,r8a774e1-rpc-if # RZ/G2H + - renesas,r8a77970-rpc-if # R-Car V3M + - 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{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> diff --git a/drivers/memory/renesas-rpc-if.c b/drivers/memory/renesas-rpc-if.c index 7435baad0007..e4cc64f56019 100644 --- a/drivers/memory/renesas-rpc-if.c +++ b/drivers/memory/renesas-rpc-if.c @@ -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); - - /* - * 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 | - RPCIF_PHYOFFSET1_DDRTMG(3)); - regmap_write(rpc->regmap, RPCIF_PHYOFFSET2, 0x31 | - RPCIF_PHYOFFSET2_OCTTMG(4)); + if (rpc->type == RPCIF_RZ_G2L) { + int ret; + + 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_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 | - RPCIF_CMNCR_BSZ(hyperflash ? 1 : 0)); + 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); diff --git a/drivers/mtd/hyperbus/rpc-if.c b/drivers/mtd/hyperbus/rpc-if.c index ecb050ba95cd..8daa296f6eb6 100644 --- a/drivers/mtd/hyperbus/rpc-if.c +++ b/drivers/mtd/hyperbus/rpc-if.c @@ -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; diff --git a/drivers/spi/spi-rpc-if.c b/drivers/spi/spi-rpc-if.c index 83796a4ead34..fe82f3575df4 100644 --- a/drivers/spi/spi-rpc-if.c +++ b/drivers/spi/spi-rpc-if.c @@ -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) { diff --git a/include/memory/renesas-rpc-if.h b/include/memory/renesas-rpc-if.h index 77c694a19149..7c93f5177532 100644 --- a/include/memory/renesas-rpc-if.h +++ b/include/memory/renesas-rpc-if.h @@ -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); |