mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	memory: renesas-rpc-if: Add support for RZ/G2L
SPI Multi I/O Bus Controller on RZ/G2L SoC is almost identical to the RPC-IF interface found on R-Car Gen3 SoC's. This patch adds a new compatible string for the RZ/G2L family so that the timing values on RZ/G2L can be adjusted. Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com> Reviewed-by: Biju Das <biju.das.jz@bp.renesas.com> Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com> Link: https://lore.kernel.org/r/20211025205631.21151-8-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
This commit is contained in:
		
							parent
							
								
									5da9b59b23
								
							
						
					
					
						commit
						b04cc0d912
					
				
					 4 changed files with 75 additions and 13 deletions
				
			
		| 
						 | 
					@ -12,6 +12,7 @@
 | 
				
			||||||
#include <linux/module.h>
 | 
					#include <linux/module.h>
 | 
				
			||||||
#include <linux/platform_device.h>
 | 
					#include <linux/platform_device.h>
 | 
				
			||||||
#include <linux/of.h>
 | 
					#include <linux/of.h>
 | 
				
			||||||
 | 
					#include <linux/of_device.h>
 | 
				
			||||||
#include <linux/regmap.h>
 | 
					#include <linux/regmap.h>
 | 
				
			||||||
#include <linux/reset.h>
 | 
					#include <linux/reset.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,8 +28,8 @@
 | 
				
			||||||
#define RPCIF_CMNCR_MOIIO_HIZ	(RPCIF_CMNCR_MOIIO0(3) | \
 | 
					#define RPCIF_CMNCR_MOIIO_HIZ	(RPCIF_CMNCR_MOIIO0(3) | \
 | 
				
			||||||
				 RPCIF_CMNCR_MOIIO1(3) | \
 | 
									 RPCIF_CMNCR_MOIIO1(3) | \
 | 
				
			||||||
				 RPCIF_CMNCR_MOIIO2(3) | RPCIF_CMNCR_MOIIO3(3))
 | 
									 RPCIF_CMNCR_MOIIO2(3) | RPCIF_CMNCR_MOIIO3(3))
 | 
				
			||||||
#define RPCIF_CMNCR_IO3FV(val)	(((val) & 0x3) << 14) /* undocumented */
 | 
					#define RPCIF_CMNCR_IO3FV(val)	(((val) & 0x3) << 14) /* documented for RZ/G2L */
 | 
				
			||||||
#define RPCIF_CMNCR_IO2FV(val)	(((val) & 0x3) << 12) /* undocumented */
 | 
					#define RPCIF_CMNCR_IO2FV(val)	(((val) & 0x3) << 12) /* documented for RZ/G2L */
 | 
				
			||||||
#define RPCIF_CMNCR_IO0FV(val)	(((val) & 0x3) << 8)
 | 
					#define RPCIF_CMNCR_IO0FV(val)	(((val) & 0x3) << 8)
 | 
				
			||||||
#define RPCIF_CMNCR_IOFV_HIZ	(RPCIF_CMNCR_IO0FV(3) | RPCIF_CMNCR_IO2FV(3) | \
 | 
					#define RPCIF_CMNCR_IOFV_HIZ	(RPCIF_CMNCR_IO0FV(3) | RPCIF_CMNCR_IO2FV(3) | \
 | 
				
			||||||
				 RPCIF_CMNCR_IO3FV(3))
 | 
									 RPCIF_CMNCR_IO3FV(3))
 | 
				
			||||||
| 
						 | 
					@ -126,6 +127,9 @@
 | 
				
			||||||
#define RPCIF_SMDRENR_OPDRE	BIT(4)
 | 
					#define RPCIF_SMDRENR_OPDRE	BIT(4)
 | 
				
			||||||
#define RPCIF_SMDRENR_SPIDRE	BIT(0)
 | 
					#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		0x007C	/* R/W */
 | 
				
			||||||
#define RPCIF_PHYCNT_CAL	BIT(31)
 | 
					#define RPCIF_PHYCNT_CAL	BIT(31)
 | 
				
			||||||
#define RPCIF_PHYCNT_OCTA(v)	(((v) & 0x3) << 22)
 | 
					#define RPCIF_PHYCNT_OCTA(v)	(((v) & 0x3) << 22)
 | 
				
			||||||
| 
						 | 
					@ -133,10 +137,12 @@
 | 
				
			||||||
#define RPCIF_PHYCNT_OCT	BIT(20)
 | 
					#define RPCIF_PHYCNT_OCT	BIT(20)
 | 
				
			||||||
#define RPCIF_PHYCNT_DDRCAL	BIT(19)
 | 
					#define RPCIF_PHYCNT_DDRCAL	BIT(19)
 | 
				
			||||||
#define RPCIF_PHYCNT_HS		BIT(18)
 | 
					#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_WBUF2	BIT(4)
 | 
				
			||||||
#define RPCIF_PHYCNT_WBUF	BIT(2)
 | 
					#define RPCIF_PHYCNT_WBUF	BIT(2)
 | 
				
			||||||
#define RPCIF_PHYCNT_PHYMEM(v)	(((v) & 0x3) << 0)
 | 
					#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	0x0080	/* R/W */
 | 
				
			||||||
#define RPCIF_PHYOFFSET1_DDRTMG(v) (((v) & 0x3) << 28)
 | 
					#define RPCIF_PHYOFFSET1_DDRTMG(v) (((v) & 0x3) << 28)
 | 
				
			||||||
| 
						 | 
					@ -244,18 +250,46 @@ int rpcif_sw_init(struct rpcif *rpc, struct device *dev)
 | 
				
			||||||
		return PTR_ERR(rpc->dirmap);
 | 
							return PTR_ERR(rpc->dirmap);
 | 
				
			||||||
	rpc->size = resource_size(res);
 | 
						rpc->size = resource_size(res);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rpc->type = (enum rpcif_type)of_device_get_match_data(dev);
 | 
				
			||||||
	rpc->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
 | 
						rpc->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return PTR_ERR_OR_ZERO(rpc->rstc);
 | 
						return PTR_ERR_OR_ZERO(rpc->rstc);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(rpcif_sw_init);
 | 
					EXPORT_SYMBOL(rpcif_sw_init);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void rpcif_hw_init(struct rpcif *rpc, bool hyperflash)
 | 
					static void rpcif_rzg2l_timing_adjust_sdr(struct rpcif *rpc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u32 data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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_read(rpc->regmap, RPCIF_PHYCNT, &data);
 | 
				
			||||||
 | 
						regmap_write(rpc->regmap, RPCIF_PHYCNT, data | 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;
 | 
						u32 dummy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pm_runtime_get_sync(rpc->dev);
 | 
						pm_runtime_get_sync(rpc->dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * NOTE: The 0x260 are undocumented bits, but they must be set.
 | 
						 * NOTE: The 0x260 are undocumented bits, but they must be set.
 | 
				
			||||||
	 *	 RPCIF_PHYCNT_STRTIM is strobe timing adjustment bits,
 | 
						 *	 RPCIF_PHYCNT_STRTIM is strobe timing adjustment bits,
 | 
				
			||||||
| 
						 | 
					@ -264,8 +298,15 @@ void rpcif_hw_init(struct rpcif *rpc, bool hyperflash)
 | 
				
			||||||
	 *	 On H3 ES1.x, the value should be 0, while on others,
 | 
						 *	 On H3 ES1.x, the value should be 0, while on others,
 | 
				
			||||||
	 *	 the value should be 7.
 | 
						 *	 the value should be 7.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
 | 
						if (rpc->type == RPCIF_RCAR_GEN3) {
 | 
				
			||||||
		regmap_write(rpc->regmap, RPCIF_PHYCNT, RPCIF_PHYCNT_STRTIM(7) |
 | 
							regmap_write(rpc->regmap, RPCIF_PHYCNT, RPCIF_PHYCNT_STRTIM(7) |
 | 
				
			||||||
			     RPCIF_PHYCNT_PHYMEM(hyperflash ? 3 : 0) | 0x260);
 | 
								     RPCIF_PHYCNT_PHYMEM(hyperflash ? 3 : 0) | 0x260);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							regmap_read(rpc->regmap, RPCIF_PHYCNT, &dummy);
 | 
				
			||||||
 | 
							dummy &= ~RPCIF_PHYCNT_PHYMEM_MASK;
 | 
				
			||||||
 | 
							dummy |= RPCIF_PHYCNT_PHYMEM(hyperflash ? 3 : 0) | 0x260;
 | 
				
			||||||
 | 
							regmap_write(rpc->regmap, RPCIF_PHYCNT, dummy);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * NOTE: The 0x1511144 are undocumented bits, but they must be set
 | 
						 * NOTE: The 0x1511144 are undocumented bits, but they must be set
 | 
				
			||||||
| 
						 | 
					@ -282,9 +323,17 @@ void rpcif_hw_init(struct rpcif *rpc, bool hyperflash)
 | 
				
			||||||
		regmap_update_bits(rpc->regmap, RPCIF_PHYINT,
 | 
							regmap_update_bits(rpc->regmap, RPCIF_PHYINT,
 | 
				
			||||||
				   RPCIF_PHYINT_WPVAL, 0);
 | 
									   RPCIF_PHYINT_WPVAL, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (rpc->type == RPCIF_RCAR_GEN3)
 | 
				
			||||||
		regmap_write(rpc->regmap, RPCIF_CMNCR, RPCIF_CMNCR_SFDE |
 | 
							regmap_write(rpc->regmap, RPCIF_CMNCR, RPCIF_CMNCR_SFDE |
 | 
				
			||||||
			     RPCIF_CMNCR_MOIIO_HIZ | RPCIF_CMNCR_IOFV_HIZ |
 | 
								     RPCIF_CMNCR_MOIIO_HIZ | RPCIF_CMNCR_IOFV_HIZ |
 | 
				
			||||||
			     RPCIF_CMNCR_BSZ(hyperflash ? 1 : 0));
 | 
								     RPCIF_CMNCR_BSZ(hyperflash ? 1 : 0));
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							regmap_write(rpc->regmap, RPCIF_CMNCR, RPCIF_CMNCR_SFDE |
 | 
				
			||||||
 | 
								     RPCIF_CMNCR_MOIIO3(1) | RPCIF_CMNCR_MOIIO2(1) |
 | 
				
			||||||
 | 
								     RPCIF_CMNCR_MOIIO1(1) | RPCIF_CMNCR_MOIIO0(1) |
 | 
				
			||||||
 | 
								     RPCIF_CMNCR_IO3FV(2) | RPCIF_CMNCR_IO2FV(2) |
 | 
				
			||||||
 | 
								     RPCIF_CMNCR_IO0FV(2) | RPCIF_CMNCR_BSZ(hyperflash ? 1 : 0));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Set RCF after BSZ update */
 | 
						/* Set RCF after BSZ update */
 | 
				
			||||||
	regmap_write(rpc->regmap, RPCIF_DRCR, RPCIF_DRCR_RCF);
 | 
						regmap_write(rpc->regmap, RPCIF_DRCR, RPCIF_DRCR_RCF);
 | 
				
			||||||
	/* Dummy read according to spec */
 | 
						/* Dummy read according to spec */
 | 
				
			||||||
| 
						 | 
					@ -295,6 +344,8 @@ void rpcif_hw_init(struct rpcif *rpc, bool hyperflash)
 | 
				
			||||||
	pm_runtime_put(rpc->dev);
 | 
						pm_runtime_put(rpc->dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rpc->bus_size = hyperflash ? 2 : 1;
 | 
						rpc->bus_size = hyperflash ? 2 : 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(rpcif_hw_init);
 | 
					EXPORT_SYMBOL(rpcif_hw_init);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -657,7 +708,8 @@ static int rpcif_remove(struct platform_device *pdev)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct of_device_id rpcif_of_match[] = {
 | 
					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);
 | 
					MODULE_DEVICE_TABLE(of, rpcif_of_match);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -130,7 +130,9 @@ static int rpcif_hb_probe(struct platform_device *pdev)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rpcif_enable_rpm(&hyperbus->rpc);
 | 
						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.size = hyperbus->rpc.size;
 | 
				
			||||||
	hyperbus->hbdev.map.virt = hyperbus->rpc.dirmap;
 | 
						hyperbus->hbdev.map.virt = hyperbus->rpc.dirmap;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_QUAD | SPI_RX_QUAD;
 | 
				
			||||||
	ctlr->flags = SPI_CONTROLLER_HALF_DUPLEX;
 | 
						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);
 | 
						error = spi_register_controller(ctlr);
 | 
				
			||||||
	if (error) {
 | 
						if (error) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -57,6 +57,11 @@ struct rpcif_op {
 | 
				
			||||||
	} data;
 | 
						} data;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum rpcif_type {
 | 
				
			||||||
 | 
						RPCIF_RCAR_GEN3,
 | 
				
			||||||
 | 
						RPCIF_RZ_G2L,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct rpcif {
 | 
					struct rpcif {
 | 
				
			||||||
	struct device *dev;
 | 
						struct device *dev;
 | 
				
			||||||
	void __iomem *base;
 | 
						void __iomem *base;
 | 
				
			||||||
| 
						 | 
					@ -64,6 +69,7 @@ struct rpcif {
 | 
				
			||||||
	struct regmap *regmap;
 | 
						struct regmap *regmap;
 | 
				
			||||||
	struct reset_control *rstc;
 | 
						struct reset_control *rstc;
 | 
				
			||||||
	size_t size;
 | 
						size_t size;
 | 
				
			||||||
 | 
						enum rpcif_type type;
 | 
				
			||||||
	enum rpcif_data_dir dir;
 | 
						enum rpcif_data_dir dir;
 | 
				
			||||||
	u8 bus_size;
 | 
						u8 bus_size;
 | 
				
			||||||
	void *buffer;
 | 
						void *buffer;
 | 
				
			||||||
| 
						 | 
					@ -78,7 +84,7 @@ struct rpcif {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int rpcif_sw_init(struct rpcif *rpc, struct device *dev);
 | 
					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,
 | 
					void rpcif_prepare(struct rpcif *rpc, const struct rpcif_op *op, u64 *offs,
 | 
				
			||||||
		   size_t *len);
 | 
							   size_t *len);
 | 
				
			||||||
int rpcif_manual_xfer(struct rpcif *rpc);
 | 
					int rpcif_manual_xfer(struct rpcif *rpc);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue