mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
Merge branch 'for-v5.16/renesas-rpc' into mem-ctrl-next
This commit is contained in:
commit
d611d7ea12
@ -33,6 +33,7 @@ properties:
|
||||
- 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
|
||||
|
||||
reg:
|
||||
|
@ -210,6 +210,7 @@ config RENESAS_RPCIF
|
||||
tristate "Renesas RPC-IF driver"
|
||||
depends on ARCH_RENESAS || COMPILE_TEST
|
||||
select REGMAP_MMIO
|
||||
select RESET_CONTROLLER
|
||||
help
|
||||
This supports Renesas R-Car Gen3 or RZ/G2 RPC-IF which provides
|
||||
either SPI host or HyperFlash. You'll have to select individual
|
||||
|
@ -160,10 +160,61 @@ static const struct regmap_access_table rpcif_volatile_table = {
|
||||
.n_yes_ranges = ARRAY_SIZE(rpcif_volatile_ranges),
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Custom accessor functions to ensure SMRDR0 and SMWDR0 are always accessed
|
||||
* with proper width. Requires SMENR_SPIDE 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) {
|
||||
*val = readb(rpc->base + reg);
|
||||
return 0;
|
||||
} else if (spide == 0xC) {
|
||||
*val = readw(rpc->base + reg);
|
||||
return 0;
|
||||
} else if (spide != 0xF) {
|
||||
return -EILSEQ;
|
||||
}
|
||||
}
|
||||
|
||||
*val = readl(rpc->base + reg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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) {
|
||||
writeb(val, rpc->base + reg);
|
||||
return 0;
|
||||
} else if (spide == 0xC) {
|
||||
writew(val, rpc->base + reg);
|
||||
return 0;
|
||||
} else if (spide != 0xF) {
|
||||
return -EILSEQ;
|
||||
}
|
||||
}
|
||||
|
||||
writel(val, rpc->base + reg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct regmap_config rpcif_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.reg_read = rpcif_reg_read,
|
||||
.reg_write = rpcif_reg_write,
|
||||
.fast_io = true,
|
||||
.max_register = RPCIF_PHYINT,
|
||||
.volatile_table = &rpcif_volatile_table,
|
||||
@ -173,17 +224,15 @@ int rpcif_sw_init(struct rpcif *rpc, struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct resource *res;
|
||||
void __iomem *base;
|
||||
|
||||
rpc->dev = dev;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
|
||||
base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
rpc->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(rpc->base))
|
||||
return PTR_ERR(rpc->base);
|
||||
|
||||
rpc->regmap = devm_regmap_init_mmio(&pdev->dev, base,
|
||||
&rpcif_regmap_config);
|
||||
rpc->regmap = devm_regmap_init(&pdev->dev, NULL, rpc, &rpcif_regmap_config);
|
||||
if (IS_ERR(rpc->regmap)) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to init regmap for rpcif, error %ld\n",
|
||||
@ -354,20 +403,16 @@ void rpcif_prepare(struct rpcif *rpc, const struct rpcif_op *op, u64 *offs,
|
||||
nbytes = op->data.nbytes;
|
||||
rpc->xferlen = nbytes;
|
||||
|
||||
rpc->enable |= RPCIF_SMENR_SPIDE(rpcif_bits_set(rpc, nbytes)) |
|
||||
RPCIF_SMENR_SPIDB(rpcif_bit_size(op->data.buswidth));
|
||||
rpc->enable |= RPCIF_SMENR_SPIDB(rpcif_bit_size(op->data.buswidth));
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(rpcif_prepare);
|
||||
|
||||
int rpcif_manual_xfer(struct rpcif *rpc)
|
||||
{
|
||||
u32 smenr, smcr, pos = 0, max = 4;
|
||||
u32 smenr, smcr, pos = 0, max = rpc->bus_size == 2 ? 8 : 4;
|
||||
int ret = 0;
|
||||
|
||||
if (rpc->bus_size == 2)
|
||||
max = 8;
|
||||
|
||||
pm_runtime_get_sync(rpc->dev);
|
||||
|
||||
regmap_update_bits(rpc->regmap, RPCIF_PHYCNT,
|
||||
@ -378,37 +423,36 @@ int rpcif_manual_xfer(struct rpcif *rpc)
|
||||
regmap_write(rpc->regmap, RPCIF_SMOPR, rpc->option);
|
||||
regmap_write(rpc->regmap, RPCIF_SMDMCR, rpc->dummy);
|
||||
regmap_write(rpc->regmap, RPCIF_SMDRENR, rpc->ddr);
|
||||
regmap_write(rpc->regmap, RPCIF_SMADR, rpc->smadr);
|
||||
smenr = rpc->enable;
|
||||
|
||||
switch (rpc->dir) {
|
||||
case RPCIF_DATA_OUT:
|
||||
while (pos < rpc->xferlen) {
|
||||
u32 nbytes = rpc->xferlen - pos;
|
||||
u32 data[2];
|
||||
u32 bytes_left = rpc->xferlen - pos;
|
||||
u32 nbytes, data[2];
|
||||
|
||||
smcr = rpc->smcr | RPCIF_SMCR_SPIE;
|
||||
if (nbytes > max) {
|
||||
nbytes = max;
|
||||
|
||||
/* nbytes may only be 1, 2, 4, or 8 */
|
||||
nbytes = bytes_left >= max ? max : (1 << ilog2(bytes_left));
|
||||
if (bytes_left > nbytes)
|
||||
smcr |= RPCIF_SMCR_SSLKP;
|
||||
}
|
||||
|
||||
smenr |= RPCIF_SMENR_SPIDE(rpcif_bits_set(rpc, nbytes));
|
||||
regmap_write(rpc->regmap, RPCIF_SMENR, smenr);
|
||||
|
||||
memcpy(data, rpc->buffer + pos, nbytes);
|
||||
if (nbytes > 4) {
|
||||
if (nbytes == 8) {
|
||||
regmap_write(rpc->regmap, RPCIF_SMWDR1,
|
||||
data[0]);
|
||||
regmap_write(rpc->regmap, RPCIF_SMWDR0,
|
||||
data[1]);
|
||||
} else if (nbytes > 2) {
|
||||
} else {
|
||||
regmap_write(rpc->regmap, RPCIF_SMWDR0,
|
||||
data[0]);
|
||||
} else {
|
||||
regmap_write(rpc->regmap, RPCIF_SMWDR0,
|
||||
data[0] << 16);
|
||||
}
|
||||
|
||||
regmap_write(rpc->regmap, RPCIF_SMADR,
|
||||
rpc->smadr + pos);
|
||||
regmap_write(rpc->regmap, RPCIF_SMENR, smenr);
|
||||
regmap_write(rpc->regmap, RPCIF_SMCR, smcr);
|
||||
ret = wait_msg_xfer_end(rpc);
|
||||
if (ret)
|
||||
@ -448,14 +492,16 @@ int rpcif_manual_xfer(struct rpcif *rpc)
|
||||
break;
|
||||
}
|
||||
while (pos < rpc->xferlen) {
|
||||
u32 nbytes = rpc->xferlen - pos;
|
||||
u32 data[2];
|
||||
u32 bytes_left = rpc->xferlen - pos;
|
||||
u32 nbytes, data[2];
|
||||
|
||||
if (nbytes > max)
|
||||
nbytes = max;
|
||||
/* nbytes may only be 1, 2, 4, or 8 */
|
||||
nbytes = bytes_left >= max ? max : (1 << ilog2(bytes_left));
|
||||
|
||||
regmap_write(rpc->regmap, RPCIF_SMADR,
|
||||
rpc->smadr + pos);
|
||||
smenr &= ~RPCIF_SMENR_SPIDE(0xF);
|
||||
smenr |= RPCIF_SMENR_SPIDE(rpcif_bits_set(rpc, nbytes));
|
||||
regmap_write(rpc->regmap, RPCIF_SMENR, smenr);
|
||||
regmap_write(rpc->regmap, RPCIF_SMCR,
|
||||
rpc->smcr | RPCIF_SMCR_SPIE);
|
||||
@ -463,18 +509,14 @@ int rpcif_manual_xfer(struct rpcif *rpc)
|
||||
if (ret)
|
||||
goto err_out;
|
||||
|
||||
if (nbytes > 4) {
|
||||
if (nbytes == 8) {
|
||||
regmap_read(rpc->regmap, RPCIF_SMRDR1,
|
||||
&data[0]);
|
||||
regmap_read(rpc->regmap, RPCIF_SMRDR0,
|
||||
&data[1]);
|
||||
} else if (nbytes > 2) {
|
||||
} else {
|
||||
regmap_read(rpc->regmap, RPCIF_SMRDR0,
|
||||
&data[0]);
|
||||
} else {
|
||||
regmap_read(rpc->regmap, RPCIF_SMRDR0,
|
||||
&data[0]);
|
||||
data[0] >>= 16;
|
||||
}
|
||||
memcpy(rpc->buffer + pos, data, nbytes);
|
||||
|
||||
@ -502,6 +544,48 @@ err_out:
|
||||
}
|
||||
EXPORT_SYMBOL(rpcif_manual_xfer);
|
||||
|
||||
static void memcpy_fromio_readw(void *to,
|
||||
const void __iomem *from,
|
||||
size_t count)
|
||||
{
|
||||
const int maxw = (IS_ENABLED(CONFIG_64BIT)) ? 8 : 4;
|
||||
u8 buf[2];
|
||||
|
||||
if (count && ((unsigned long)from & 1)) {
|
||||
*(u16 *)buf = __raw_readw((void __iomem *)((unsigned long)from & ~1));
|
||||
*(u8 *)to = buf[1];
|
||||
from++;
|
||||
to++;
|
||||
count--;
|
||||
}
|
||||
while (count >= 2 && !IS_ALIGNED((unsigned long)from, maxw)) {
|
||||
*(u16 *)to = __raw_readw(from);
|
||||
from += 2;
|
||||
to += 2;
|
||||
count -= 2;
|
||||
}
|
||||
while (count >= maxw) {
|
||||
#ifdef CONFIG_64BIT
|
||||
*(u64 *)to = __raw_readq(from);
|
||||
#else
|
||||
*(u32 *)to = __raw_readl(from);
|
||||
#endif
|
||||
from += maxw;
|
||||
to += maxw;
|
||||
count -= maxw;
|
||||
}
|
||||
while (count >= 2) {
|
||||
*(u16 *)to = __raw_readw(from);
|
||||
from += 2;
|
||||
to += 2;
|
||||
count -= 2;
|
||||
}
|
||||
if (count) {
|
||||
*(u16 *)buf = __raw_readw(from);
|
||||
*(u8 *)to = buf[0];
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t rpcif_dirmap_read(struct rpcif *rpc, u64 offs, size_t len, void *buf)
|
||||
{
|
||||
loff_t from = offs & (RPCIF_DIRMAP_SIZE - 1);
|
||||
@ -523,7 +607,10 @@ ssize_t rpcif_dirmap_read(struct rpcif *rpc, u64 offs, size_t len, void *buf)
|
||||
regmap_write(rpc->regmap, RPCIF_DRDMCR, rpc->dummy);
|
||||
regmap_write(rpc->regmap, RPCIF_DRDRENR, rpc->ddr);
|
||||
|
||||
memcpy_fromio(buf, rpc->dirmap + from, len);
|
||||
if (rpc->bus_size == 2)
|
||||
memcpy_fromio_readw(buf, rpc->dirmap + from, len);
|
||||
else
|
||||
memcpy_fromio(buf, rpc->dirmap + from, len);
|
||||
|
||||
pm_runtime_put(rpc->dev);
|
||||
|
||||
|
@ -59,6 +59,7 @@ struct rpcif_op {
|
||||
|
||||
struct rpcif {
|
||||
struct device *dev;
|
||||
void __iomem *base;
|
||||
void __iomem *dirmap;
|
||||
struct regmap *regmap;
|
||||
struct reset_control *rstc;
|
||||
|
Loading…
Reference in New Issue
Block a user