Memory controller drivers for v5.16
1. Renesas RPC: fix unaligned bus access and QSPI data transfers in manual modes. 2. Renesas RPC: select RESET_CONTROLLER as it is necessary for operation. 3. FSL IFC: fix error paths. 4. Broadcom: allow building as module. -----BEGIN PGP SIGNATURE----- iQJEBAABCgAuFiEE3dJiKD0RGyM7briowTdm5oaLg9cFAmFjKNoQHGtyemtAa2Vy bmVsLm9yZwAKCRDBN2bmhouD169cEACPgbJcEFgGFO3h8/EMo2pQhEk2VqQ6zO3r ngp12fV7vFGYkABWP0DKu/BNEHO+AOqZhsE2y2xjoSsuyxqGw8oUXjYmUUgrj7C6 e0vzgQmd4xQNAA2TKrbed4RWLwGHx52Cyn4Yl4Kw/yI3MWt2wz2t5DohLLmlCCDE 3J4S06A1/GCZDoNw0Stt4XWR+7K8RFi9HugA1wcbHcPHlEx5oFk75JQaeItqmN5A wnclBB3+G2zbs5hdtVVxXKVqgK5Goi7LPhwjg1jvuvSRLbY5bmJ1GSTUoxDFCbBT RRMAVV8A+nu56gFR6kkjx8URZ0D5CvY1su1Ig7p5Ohu5cF8irU6W2RwqC9rfujPs o3vY/w7EPeWuI3Uqk7zthWECeqfCuwGRQ/JVs1jtQXa8BvgSHa2O629NlCNMnq7J lGh4D0ZRsLkFt9/AVU4hKH4M30qpKakPlltn1pSQtIHLJfLGWwTY7Z3pF0UPiapq inw+ihzqDH+94R5KRtHZPYFZSk5kkia713+XhEroOSNh1QmX//QrbdtxNiBy3LPq Njm7fBiXGANQ4EEDxA/5w/KODq6KDKhFZPIpv+Dtm1gn4nIYlaHPKLjEm3p6atnH K05Yx9MclKF+ACRKH4KVsnCSXblsd9FhRVPdSvnhoUdYGQG33VtKK6BmZQWLV1WN 2ea6dwqhJw== =ZsTv -----END PGP SIGNATURE----- gpgsig -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEo6/YBQwIrVS28WGKmmx57+YAGNkFAmFkDP4ACgkQmmx57+YA GNnOzRAAxRm9E9hFwaqKoyEopnuxJRFxxjXFS8hM8GieiwD5upJBBtB7HjGqcfBC i5RZV9RRKU2v04tdddkWhS4Pcw52eEmE/T77uMhr8UwaOzzkuVgKdOz432XuVCwf 2O6oGS2igTTWMKakb+4Zza9q3PXPuUdFgXyOBdeB1PF96RnV9qjSRviwpp+P75fj 9X0ikocRVo80hCDMsiTtYwzd10CbslVIOv9wWHSa7kKQzuHJbALYL4mjnlvF4bCo 9iDVu+UJCsAhd16Xtks2VtewYmox+n/+q/ThKDU0IB2I9kdR5tvpkQqPhdn8W0Fj LiJDfDexB5rS3o9E/ws6CJGFhMxI9QFyMLXGq8HAXHjRGTIlCKA53DqpH2r10Hlj 5mzuNRfxyo2mAu2sXzDF2ScVXImsSGN65evdsFFOlohVbivhq5AZzpYnQBT/tR1K E4srv07jl7FxI03YavNevq3fqzE+SSZ1cX8PAcKY7qeueci4yPmd9/7SiJLqyHDd Q5B2q60bbCF3E7F0UQpKMjq1ZB0jO16PKYZ1BzOtXLQloC6HRR+HuLMpsyLEb09d 4aAwWl3Xa183t9lTLCuzZuC3b8qZgwcKrVrDO+Rigb8adtlOVAQFoqWZthzhL3Ys nIRY2wc83rtJ/uSghFEe1sLZvZ+2K9nEWD0wInejtq+GqhqWn9s= =OOXj -----END PGP SIGNATURE----- Merge tag 'memory-controller-drv-5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl into arm/drivers Memory controller drivers for v5.16 1. Renesas RPC: fix unaligned bus access and QSPI data transfers in manual modes. 2. Renesas RPC: select RESET_CONTROLLER as it is necessary for operation. 3. FSL IFC: fix error paths. 4. Broadcom: allow building as module. * tag 'memory-controller-drv-5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux-mem-ctrl: memory: fsl_ifc: fix leak of irq and nand_irq in fsl_ifc_ctrl_probe memory: renesas-rpc-if: RENESAS_RPCIF should select RESET_CONTROLLER memory: brcmstb_dpfe: Allow building Broadcom STB DPFE as module memory: samsung: describe drivers in KConfig memory: renesas-rpc-if: Avoid unaligned bus access for HyperFlash memory: renesas-rpc-if: Correct QSPI data transfer in Manual mode dt-bindings: rpc: renesas-rpc-if: Add support for the R8A779A0 RPC-IF Link: https://lore.kernel.org/r/20211010175836.13302-1-krzysztof.kozlowski@canonical.com Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
commit
16667625da
@ -33,6 +33,7 @@ properties:
|
|||||||
- renesas,r8a77970-rpc-if # R-Car V3M
|
- renesas,r8a77970-rpc-if # R-Car V3M
|
||||||
- renesas,r8a77980-rpc-if # R-Car V3H
|
- renesas,r8a77980-rpc-if # R-Car V3H
|
||||||
- renesas,r8a77995-rpc-if # R-Car D3
|
- 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 device
|
||||||
|
|
||||||
reg:
|
reg:
|
||||||
|
@ -55,8 +55,8 @@ config ATMEL_EBI
|
|||||||
SRAMs, ATA devices, etc.
|
SRAMs, ATA devices, etc.
|
||||||
|
|
||||||
config BRCMSTB_DPFE
|
config BRCMSTB_DPFE
|
||||||
bool "Broadcom STB DPFE driver" if COMPILE_TEST
|
tristate "Broadcom STB DPFE driver"
|
||||||
default y if ARCH_BRCMSTB
|
default ARCH_BRCMSTB
|
||||||
depends on ARCH_BRCMSTB || COMPILE_TEST
|
depends on ARCH_BRCMSTB || COMPILE_TEST
|
||||||
help
|
help
|
||||||
This driver provides access to the DPFE interface of Broadcom
|
This driver provides access to the DPFE interface of Broadcom
|
||||||
@ -210,6 +210,7 @@ config RENESAS_RPCIF
|
|||||||
tristate "Renesas RPC-IF driver"
|
tristate "Renesas RPC-IF driver"
|
||||||
depends on ARCH_RENESAS || COMPILE_TEST
|
depends on ARCH_RENESAS || COMPILE_TEST
|
||||||
select REGMAP_MMIO
|
select REGMAP_MMIO
|
||||||
|
select RESET_CONTROLLER
|
||||||
help
|
help
|
||||||
This supports Renesas R-Car Gen3 or RZ/G2 RPC-IF which provides
|
This supports Renesas R-Car Gen3 or RZ/G2 RPC-IF which provides
|
||||||
either SPI host or HyperFlash. You'll have to select individual
|
either SPI host or HyperFlash. You'll have to select individual
|
||||||
|
@ -263,7 +263,7 @@ static int fsl_ifc_ctrl_probe(struct platform_device *dev)
|
|||||||
|
|
||||||
ret = fsl_ifc_ctrl_init(fsl_ifc_ctrl_dev);
|
ret = fsl_ifc_ctrl_init(fsl_ifc_ctrl_dev);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err;
|
goto err_unmap_nandirq;
|
||||||
|
|
||||||
init_waitqueue_head(&fsl_ifc_ctrl_dev->nand_wait);
|
init_waitqueue_head(&fsl_ifc_ctrl_dev->nand_wait);
|
||||||
|
|
||||||
@ -272,7 +272,7 @@ static int fsl_ifc_ctrl_probe(struct platform_device *dev)
|
|||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
dev_err(&dev->dev, "failed to install irq (%d)\n",
|
dev_err(&dev->dev, "failed to install irq (%d)\n",
|
||||||
fsl_ifc_ctrl_dev->irq);
|
fsl_ifc_ctrl_dev->irq);
|
||||||
goto err_irq;
|
goto err_unmap_nandirq;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fsl_ifc_ctrl_dev->nand_irq) {
|
if (fsl_ifc_ctrl_dev->nand_irq) {
|
||||||
@ -281,17 +281,16 @@ static int fsl_ifc_ctrl_probe(struct platform_device *dev)
|
|||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
dev_err(&dev->dev, "failed to install irq (%d)\n",
|
dev_err(&dev->dev, "failed to install irq (%d)\n",
|
||||||
fsl_ifc_ctrl_dev->nand_irq);
|
fsl_ifc_ctrl_dev->nand_irq);
|
||||||
goto err_nandirq;
|
goto err_free_irq;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_nandirq:
|
err_free_irq:
|
||||||
free_irq(fsl_ifc_ctrl_dev->nand_irq, fsl_ifc_ctrl_dev);
|
|
||||||
irq_dispose_mapping(fsl_ifc_ctrl_dev->nand_irq);
|
|
||||||
err_irq:
|
|
||||||
free_irq(fsl_ifc_ctrl_dev->irq, fsl_ifc_ctrl_dev);
|
free_irq(fsl_ifc_ctrl_dev->irq, fsl_ifc_ctrl_dev);
|
||||||
|
err_unmap_nandirq:
|
||||||
|
irq_dispose_mapping(fsl_ifc_ctrl_dev->nand_irq);
|
||||||
irq_dispose_mapping(fsl_ifc_ctrl_dev->irq);
|
irq_dispose_mapping(fsl_ifc_ctrl_dev->irq);
|
||||||
err:
|
err:
|
||||||
iounmap(fsl_ifc_ctrl_dev->gregs);
|
iounmap(fsl_ifc_ctrl_dev->gregs);
|
||||||
|
@ -160,10 +160,61 @@ static const struct regmap_access_table rpcif_volatile_table = {
|
|||||||
.n_yes_ranges = ARRAY_SIZE(rpcif_volatile_ranges),
|
.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 = {
|
static const struct regmap_config rpcif_regmap_config = {
|
||||||
.reg_bits = 32,
|
.reg_bits = 32,
|
||||||
.val_bits = 32,
|
.val_bits = 32,
|
||||||
.reg_stride = 4,
|
.reg_stride = 4,
|
||||||
|
.reg_read = rpcif_reg_read,
|
||||||
|
.reg_write = rpcif_reg_write,
|
||||||
.fast_io = true,
|
.fast_io = true,
|
||||||
.max_register = RPCIF_PHYINT,
|
.max_register = RPCIF_PHYINT,
|
||||||
.volatile_table = &rpcif_volatile_table,
|
.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 platform_device *pdev = to_platform_device(dev);
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
void __iomem *base;
|
|
||||||
|
|
||||||
rpc->dev = dev;
|
rpc->dev = dev;
|
||||||
|
|
||||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
|
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
|
||||||
base = devm_ioremap_resource(&pdev->dev, res);
|
rpc->base = devm_ioremap_resource(&pdev->dev, res);
|
||||||
if (IS_ERR(base))
|
if (IS_ERR(rpc->base))
|
||||||
return PTR_ERR(base);
|
return PTR_ERR(rpc->base);
|
||||||
|
|
||||||
rpc->regmap = devm_regmap_init_mmio(&pdev->dev, base,
|
rpc->regmap = devm_regmap_init(&pdev->dev, NULL, rpc, &rpcif_regmap_config);
|
||||||
&rpcif_regmap_config);
|
|
||||||
if (IS_ERR(rpc->regmap)) {
|
if (IS_ERR(rpc->regmap)) {
|
||||||
dev_err(&pdev->dev,
|
dev_err(&pdev->dev,
|
||||||
"failed to init regmap for rpcif, error %ld\n",
|
"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;
|
nbytes = op->data.nbytes;
|
||||||
rpc->xferlen = nbytes;
|
rpc->xferlen = nbytes;
|
||||||
|
|
||||||
rpc->enable |= RPCIF_SMENR_SPIDE(rpcif_bits_set(rpc, nbytes)) |
|
rpc->enable |= RPCIF_SMENR_SPIDB(rpcif_bit_size(op->data.buswidth));
|
||||||
RPCIF_SMENR_SPIDB(rpcif_bit_size(op->data.buswidth));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(rpcif_prepare);
|
EXPORT_SYMBOL(rpcif_prepare);
|
||||||
|
|
||||||
int rpcif_manual_xfer(struct rpcif *rpc)
|
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;
|
int ret = 0;
|
||||||
|
|
||||||
if (rpc->bus_size == 2)
|
|
||||||
max = 8;
|
|
||||||
|
|
||||||
pm_runtime_get_sync(rpc->dev);
|
pm_runtime_get_sync(rpc->dev);
|
||||||
|
|
||||||
regmap_update_bits(rpc->regmap, RPCIF_PHYCNT,
|
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_SMOPR, rpc->option);
|
||||||
regmap_write(rpc->regmap, RPCIF_SMDMCR, rpc->dummy);
|
regmap_write(rpc->regmap, RPCIF_SMDMCR, rpc->dummy);
|
||||||
regmap_write(rpc->regmap, RPCIF_SMDRENR, rpc->ddr);
|
regmap_write(rpc->regmap, RPCIF_SMDRENR, rpc->ddr);
|
||||||
|
regmap_write(rpc->regmap, RPCIF_SMADR, rpc->smadr);
|
||||||
smenr = rpc->enable;
|
smenr = rpc->enable;
|
||||||
|
|
||||||
switch (rpc->dir) {
|
switch (rpc->dir) {
|
||||||
case RPCIF_DATA_OUT:
|
case RPCIF_DATA_OUT:
|
||||||
while (pos < rpc->xferlen) {
|
while (pos < rpc->xferlen) {
|
||||||
u32 nbytes = rpc->xferlen - pos;
|
u32 bytes_left = rpc->xferlen - pos;
|
||||||
u32 data[2];
|
u32 nbytes, data[2];
|
||||||
|
|
||||||
smcr = rpc->smcr | RPCIF_SMCR_SPIE;
|
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;
|
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);
|
memcpy(data, rpc->buffer + pos, nbytes);
|
||||||
if (nbytes > 4) {
|
if (nbytes == 8) {
|
||||||
regmap_write(rpc->regmap, RPCIF_SMWDR1,
|
regmap_write(rpc->regmap, RPCIF_SMWDR1,
|
||||||
data[0]);
|
data[0]);
|
||||||
regmap_write(rpc->regmap, RPCIF_SMWDR0,
|
regmap_write(rpc->regmap, RPCIF_SMWDR0,
|
||||||
data[1]);
|
data[1]);
|
||||||
} else if (nbytes > 2) {
|
} else {
|
||||||
regmap_write(rpc->regmap, RPCIF_SMWDR0,
|
regmap_write(rpc->regmap, RPCIF_SMWDR0,
|
||||||
data[0]);
|
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);
|
regmap_write(rpc->regmap, RPCIF_SMCR, smcr);
|
||||||
ret = wait_msg_xfer_end(rpc);
|
ret = wait_msg_xfer_end(rpc);
|
||||||
if (ret)
|
if (ret)
|
||||||
@ -448,14 +492,16 @@ int rpcif_manual_xfer(struct rpcif *rpc)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
while (pos < rpc->xferlen) {
|
while (pos < rpc->xferlen) {
|
||||||
u32 nbytes = rpc->xferlen - pos;
|
u32 bytes_left = rpc->xferlen - pos;
|
||||||
u32 data[2];
|
u32 nbytes, data[2];
|
||||||
|
|
||||||
if (nbytes > max)
|
/* nbytes may only be 1, 2, 4, or 8 */
|
||||||
nbytes = max;
|
nbytes = bytes_left >= max ? max : (1 << ilog2(bytes_left));
|
||||||
|
|
||||||
regmap_write(rpc->regmap, RPCIF_SMADR,
|
regmap_write(rpc->regmap, RPCIF_SMADR,
|
||||||
rpc->smadr + pos);
|
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_SMENR, smenr);
|
||||||
regmap_write(rpc->regmap, RPCIF_SMCR,
|
regmap_write(rpc->regmap, RPCIF_SMCR,
|
||||||
rpc->smcr | RPCIF_SMCR_SPIE);
|
rpc->smcr | RPCIF_SMCR_SPIE);
|
||||||
@ -463,18 +509,14 @@ int rpcif_manual_xfer(struct rpcif *rpc)
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto err_out;
|
goto err_out;
|
||||||
|
|
||||||
if (nbytes > 4) {
|
if (nbytes == 8) {
|
||||||
regmap_read(rpc->regmap, RPCIF_SMRDR1,
|
regmap_read(rpc->regmap, RPCIF_SMRDR1,
|
||||||
&data[0]);
|
&data[0]);
|
||||||
regmap_read(rpc->regmap, RPCIF_SMRDR0,
|
regmap_read(rpc->regmap, RPCIF_SMRDR0,
|
||||||
&data[1]);
|
&data[1]);
|
||||||
} else if (nbytes > 2) {
|
} else {
|
||||||
regmap_read(rpc->regmap, RPCIF_SMRDR0,
|
regmap_read(rpc->regmap, RPCIF_SMRDR0,
|
||||||
&data[0]);
|
&data[0]);
|
||||||
} else {
|
|
||||||
regmap_read(rpc->regmap, RPCIF_SMRDR0,
|
|
||||||
&data[0]);
|
|
||||||
data[0] >>= 16;
|
|
||||||
}
|
}
|
||||||
memcpy(rpc->buffer + pos, data, nbytes);
|
memcpy(rpc->buffer + pos, data, nbytes);
|
||||||
|
|
||||||
@ -502,6 +544,48 @@ err_out:
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(rpcif_manual_xfer);
|
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)
|
ssize_t rpcif_dirmap_read(struct rpcif *rpc, u64 offs, size_t len, void *buf)
|
||||||
{
|
{
|
||||||
loff_t from = offs & (RPCIF_DIRMAP_SIZE - 1);
|
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_DRDMCR, rpc->dummy);
|
||||||
regmap_write(rpc->regmap, RPCIF_DRDRENR, rpc->ddr);
|
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);
|
pm_runtime_put(rpc->dev);
|
||||||
|
|
||||||
|
@ -14,11 +14,12 @@ config EXYNOS5422_DMC
|
|||||||
depends on DEVFREQ_GOV_SIMPLE_ONDEMAND
|
depends on DEVFREQ_GOV_SIMPLE_ONDEMAND
|
||||||
depends on (PM_DEVFREQ && PM_DEVFREQ_EVENT)
|
depends on (PM_DEVFREQ && PM_DEVFREQ_EVENT)
|
||||||
help
|
help
|
||||||
This adds driver for Exynos5422 DMC (Dynamic Memory Controller).
|
This adds driver for Samsung Exynos5422 SoC DMC (Dynamic Memory
|
||||||
The driver provides support for Dynamic Voltage and Frequency Scaling in
|
Controller). The driver provides support for Dynamic Voltage and
|
||||||
DMC and DRAM. It also supports changing timings of DRAM running with
|
Frequency Scaling in DMC and DRAM. It also supports changing timings
|
||||||
different frequency. The timings are calculated based on DT memory
|
of DRAM running with different frequency. The timings are calculated
|
||||||
information.
|
based on DT memory information.
|
||||||
|
If unsure, say Y on devices with Samsung Exynos SoCs.
|
||||||
|
|
||||||
config EXYNOS_SROM
|
config EXYNOS_SROM
|
||||||
bool "Exynos SROM controller driver" if COMPILE_TEST
|
bool "Exynos SROM controller driver" if COMPILE_TEST
|
||||||
@ -29,6 +30,6 @@ config EXYNOS_SROM
|
|||||||
during suspend. If however appropriate device tree configuration
|
during suspend. If however appropriate device tree configuration
|
||||||
is provided, the driver enables support for external memory
|
is provided, the driver enables support for external memory
|
||||||
or external devices.
|
or external devices.
|
||||||
If unsure, say Y on devices with Samsung Exynos SocS.
|
If unsure, say Y on devices with Samsung Exynos SoCs.
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
@ -59,6 +59,7 @@ struct rpcif_op {
|
|||||||
|
|
||||||
struct rpcif {
|
struct rpcif {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
|
void __iomem *base;
|
||||||
void __iomem *dirmap;
|
void __iomem *dirmap;
|
||||||
struct regmap *regmap;
|
struct regmap *regmap;
|
||||||
struct reset_control *rstc;
|
struct reset_control *rstc;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user