Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+141 -51
+1
Documentation/devicetree/bindings/memory-controllers/renesas,rpc-if.yaml
··· 33 33 - renesas,r8a77970-rpc-if # R-Car V3M 34 34 - renesas,r8a77980-rpc-if # R-Car V3H 35 35 - renesas,r8a77995-rpc-if # R-Car D3 36 + - renesas,r8a779a0-rpc-if # R-Car V3U 36 37 - const: renesas,rcar-gen3-rpc-if # a generic R-Car gen3 or RZ/G2 device 37 38 38 39 reg:
+3 -2
drivers/memory/Kconfig
··· 55 55 SRAMs, ATA devices, etc. 56 56 57 57 config BRCMSTB_DPFE 58 - bool "Broadcom STB DPFE driver" if COMPILE_TEST 59 - default y if ARCH_BRCMSTB 58 + tristate "Broadcom STB DPFE driver" 59 + default ARCH_BRCMSTB 60 60 depends on ARCH_BRCMSTB || COMPILE_TEST 61 61 help 62 62 This driver provides access to the DPFE interface of Broadcom ··· 210 210 tristate "Renesas RPC-IF driver" 211 211 depends on ARCH_RENESAS || COMPILE_TEST 212 212 select REGMAP_MMIO 213 + select RESET_CONTROLLER 213 214 help 214 215 This supports Renesas R-Car Gen3 or RZ/G2 RPC-IF which provides 215 216 either SPI host or HyperFlash. You'll have to select individual
+6 -7
drivers/memory/fsl_ifc.c
··· 263 263 264 264 ret = fsl_ifc_ctrl_init(fsl_ifc_ctrl_dev); 265 265 if (ret < 0) 266 - goto err; 266 + goto err_unmap_nandirq; 267 267 268 268 init_waitqueue_head(&fsl_ifc_ctrl_dev->nand_wait); 269 269 ··· 272 272 if (ret != 0) { 273 273 dev_err(&dev->dev, "failed to install irq (%d)\n", 274 274 fsl_ifc_ctrl_dev->irq); 275 - goto err_irq; 275 + goto err_unmap_nandirq; 276 276 } 277 277 278 278 if (fsl_ifc_ctrl_dev->nand_irq) { ··· 281 281 if (ret != 0) { 282 282 dev_err(&dev->dev, "failed to install irq (%d)\n", 283 283 fsl_ifc_ctrl_dev->nand_irq); 284 - goto err_nandirq; 284 + goto err_free_irq; 285 285 } 286 286 } 287 287 288 288 return 0; 289 289 290 - err_nandirq: 291 - free_irq(fsl_ifc_ctrl_dev->nand_irq, fsl_ifc_ctrl_dev); 292 - irq_dispose_mapping(fsl_ifc_ctrl_dev->nand_irq); 293 - err_irq: 290 + err_free_irq: 294 291 free_irq(fsl_ifc_ctrl_dev->irq, fsl_ifc_ctrl_dev); 292 + err_unmap_nandirq: 293 + irq_dispose_mapping(fsl_ifc_ctrl_dev->nand_irq); 295 294 irq_dispose_mapping(fsl_ifc_ctrl_dev->irq); 296 295 err: 297 296 iounmap(fsl_ifc_ctrl_dev->gregs);
+123 -36
drivers/memory/renesas-rpc-if.c
··· 160 160 .n_yes_ranges = ARRAY_SIZE(rpcif_volatile_ranges), 161 161 }; 162 162 163 + 164 + /* 165 + * Custom accessor functions to ensure SMRDR0 and SMWDR0 are always accessed 166 + * with proper width. Requires SMENR_SPIDE to be correctly set before! 167 + */ 168 + static int rpcif_reg_read(void *context, unsigned int reg, unsigned int *val) 169 + { 170 + struct rpcif *rpc = context; 171 + 172 + if (reg == RPCIF_SMRDR0 || reg == RPCIF_SMWDR0) { 173 + u32 spide = readl(rpc->base + RPCIF_SMENR) & RPCIF_SMENR_SPIDE(0xF); 174 + 175 + if (spide == 0x8) { 176 + *val = readb(rpc->base + reg); 177 + return 0; 178 + } else if (spide == 0xC) { 179 + *val = readw(rpc->base + reg); 180 + return 0; 181 + } else if (spide != 0xF) { 182 + return -EILSEQ; 183 + } 184 + } 185 + 186 + *val = readl(rpc->base + reg); 187 + return 0; 188 + } 189 + 190 + static int rpcif_reg_write(void *context, unsigned int reg, unsigned int val) 191 + { 192 + struct rpcif *rpc = context; 193 + 194 + if (reg == RPCIF_SMRDR0 || reg == RPCIF_SMWDR0) { 195 + u32 spide = readl(rpc->base + RPCIF_SMENR) & RPCIF_SMENR_SPIDE(0xF); 196 + 197 + if (spide == 0x8) { 198 + writeb(val, rpc->base + reg); 199 + return 0; 200 + } else if (spide == 0xC) { 201 + writew(val, rpc->base + reg); 202 + return 0; 203 + } else if (spide != 0xF) { 204 + return -EILSEQ; 205 + } 206 + } 207 + 208 + writel(val, rpc->base + reg); 209 + return 0; 210 + } 211 + 163 212 static const struct regmap_config rpcif_regmap_config = { 164 213 .reg_bits = 32, 165 214 .val_bits = 32, 166 215 .reg_stride = 4, 216 + .reg_read = rpcif_reg_read, 217 + .reg_write = rpcif_reg_write, 167 218 .fast_io = true, 168 219 .max_register = RPCIF_PHYINT, 169 220 .volatile_table = &rpcif_volatile_table, ··· 224 173 { 225 174 struct platform_device *pdev = to_platform_device(dev); 226 175 struct resource *res; 227 - void __iomem *base; 228 176 229 177 rpc->dev = dev; 230 178 231 179 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); 232 - base = devm_ioremap_resource(&pdev->dev, res); 233 - if (IS_ERR(base)) 234 - return PTR_ERR(base); 180 + rpc->base = devm_ioremap_resource(&pdev->dev, res); 181 + if (IS_ERR(rpc->base)) 182 + return PTR_ERR(rpc->base); 235 183 236 - rpc->regmap = devm_regmap_init_mmio(&pdev->dev, base, 237 - &rpcif_regmap_config); 184 + rpc->regmap = devm_regmap_init(&pdev->dev, NULL, rpc, &rpcif_regmap_config); 238 185 if (IS_ERR(rpc->regmap)) { 239 186 dev_err(&pdev->dev, 240 187 "failed to init regmap for rpcif, error %ld\n", ··· 403 354 nbytes = op->data.nbytes; 404 355 rpc->xferlen = nbytes; 405 356 406 - rpc->enable |= RPCIF_SMENR_SPIDE(rpcif_bits_set(rpc, nbytes)) | 407 - RPCIF_SMENR_SPIDB(rpcif_bit_size(op->data.buswidth)); 357 + rpc->enable |= RPCIF_SMENR_SPIDB(rpcif_bit_size(op->data.buswidth)); 408 358 } 409 359 } 410 360 EXPORT_SYMBOL(rpcif_prepare); 411 361 412 362 int rpcif_manual_xfer(struct rpcif *rpc) 413 363 { 414 - u32 smenr, smcr, pos = 0, max = 4; 364 + u32 smenr, smcr, pos = 0, max = rpc->bus_size == 2 ? 8 : 4; 415 365 int ret = 0; 416 - 417 - if (rpc->bus_size == 2) 418 - max = 8; 419 366 420 367 pm_runtime_get_sync(rpc->dev); 421 368 ··· 423 378 regmap_write(rpc->regmap, RPCIF_SMOPR, rpc->option); 424 379 regmap_write(rpc->regmap, RPCIF_SMDMCR, rpc->dummy); 425 380 regmap_write(rpc->regmap, RPCIF_SMDRENR, rpc->ddr); 381 + regmap_write(rpc->regmap, RPCIF_SMADR, rpc->smadr); 426 382 smenr = rpc->enable; 427 383 428 384 switch (rpc->dir) { 429 385 case RPCIF_DATA_OUT: 430 386 while (pos < rpc->xferlen) { 431 - u32 nbytes = rpc->xferlen - pos; 432 - u32 data[2]; 387 + u32 bytes_left = rpc->xferlen - pos; 388 + u32 nbytes, data[2]; 433 389 434 390 smcr = rpc->smcr | RPCIF_SMCR_SPIE; 435 - if (nbytes > max) { 436 - nbytes = max; 391 + 392 + /* nbytes may only be 1, 2, 4, or 8 */ 393 + nbytes = bytes_left >= max ? max : (1 << ilog2(bytes_left)); 394 + if (bytes_left > nbytes) 437 395 smcr |= RPCIF_SMCR_SSLKP; 438 - } 396 + 397 + smenr |= RPCIF_SMENR_SPIDE(rpcif_bits_set(rpc, nbytes)); 398 + regmap_write(rpc->regmap, RPCIF_SMENR, smenr); 439 399 440 400 memcpy(data, rpc->buffer + pos, nbytes); 441 - if (nbytes > 4) { 401 + if (nbytes == 8) { 442 402 regmap_write(rpc->regmap, RPCIF_SMWDR1, 443 403 data[0]); 444 404 regmap_write(rpc->regmap, RPCIF_SMWDR0, 445 405 data[1]); 446 - } else if (nbytes > 2) { 406 + } else { 447 407 regmap_write(rpc->regmap, RPCIF_SMWDR0, 448 408 data[0]); 449 - } else { 450 - regmap_write(rpc->regmap, RPCIF_SMWDR0, 451 - data[0] << 16); 452 409 } 453 410 454 - regmap_write(rpc->regmap, RPCIF_SMADR, 455 - rpc->smadr + pos); 456 - regmap_write(rpc->regmap, RPCIF_SMENR, smenr); 457 411 regmap_write(rpc->regmap, RPCIF_SMCR, smcr); 458 412 ret = wait_msg_xfer_end(rpc); 459 413 if (ret) ··· 492 448 break; 493 449 } 494 450 while (pos < rpc->xferlen) { 495 - u32 nbytes = rpc->xferlen - pos; 496 - u32 data[2]; 451 + u32 bytes_left = rpc->xferlen - pos; 452 + u32 nbytes, data[2]; 497 453 498 - if (nbytes > max) 499 - nbytes = max; 454 + /* nbytes may only be 1, 2, 4, or 8 */ 455 + nbytes = bytes_left >= max ? max : (1 << ilog2(bytes_left)); 500 456 501 457 regmap_write(rpc->regmap, RPCIF_SMADR, 502 458 rpc->smadr + pos); 459 + smenr &= ~RPCIF_SMENR_SPIDE(0xF); 460 + smenr |= RPCIF_SMENR_SPIDE(rpcif_bits_set(rpc, nbytes)); 503 461 regmap_write(rpc->regmap, RPCIF_SMENR, smenr); 504 462 regmap_write(rpc->regmap, RPCIF_SMCR, 505 463 rpc->smcr | RPCIF_SMCR_SPIE); ··· 509 463 if (ret) 510 464 goto err_out; 511 465 512 - if (nbytes > 4) { 466 + if (nbytes == 8) { 513 467 regmap_read(rpc->regmap, RPCIF_SMRDR1, 514 468 &data[0]); 515 469 regmap_read(rpc->regmap, RPCIF_SMRDR0, 516 470 &data[1]); 517 - } else if (nbytes > 2) { 471 + } else { 518 472 regmap_read(rpc->regmap, RPCIF_SMRDR0, 519 473 &data[0]); 520 - } else { 521 - regmap_read(rpc->regmap, RPCIF_SMRDR0, 522 - &data[0]); 523 - data[0] >>= 16; 524 474 } 525 475 memcpy(rpc->buffer + pos, data, nbytes); 526 476 ··· 544 502 } 545 503 EXPORT_SYMBOL(rpcif_manual_xfer); 546 504 505 + static void memcpy_fromio_readw(void *to, 506 + const void __iomem *from, 507 + size_t count) 508 + { 509 + const int maxw = (IS_ENABLED(CONFIG_64BIT)) ? 8 : 4; 510 + u8 buf[2]; 511 + 512 + if (count && ((unsigned long)from & 1)) { 513 + *(u16 *)buf = __raw_readw((void __iomem *)((unsigned long)from & ~1)); 514 + *(u8 *)to = buf[1]; 515 + from++; 516 + to++; 517 + count--; 518 + } 519 + while (count >= 2 && !IS_ALIGNED((unsigned long)from, maxw)) { 520 + *(u16 *)to = __raw_readw(from); 521 + from += 2; 522 + to += 2; 523 + count -= 2; 524 + } 525 + while (count >= maxw) { 526 + #ifdef CONFIG_64BIT 527 + *(u64 *)to = __raw_readq(from); 528 + #else 529 + *(u32 *)to = __raw_readl(from); 530 + #endif 531 + from += maxw; 532 + to += maxw; 533 + count -= maxw; 534 + } 535 + while (count >= 2) { 536 + *(u16 *)to = __raw_readw(from); 537 + from += 2; 538 + to += 2; 539 + count -= 2; 540 + } 541 + if (count) { 542 + *(u16 *)buf = __raw_readw(from); 543 + *(u8 *)to = buf[0]; 544 + } 545 + } 546 + 547 547 ssize_t rpcif_dirmap_read(struct rpcif *rpc, u64 offs, size_t len, void *buf) 548 548 { 549 549 loff_t from = offs & (RPCIF_DIRMAP_SIZE - 1); ··· 607 523 regmap_write(rpc->regmap, RPCIF_DRDMCR, rpc->dummy); 608 524 regmap_write(rpc->regmap, RPCIF_DRDRENR, rpc->ddr); 609 525 610 - memcpy_fromio(buf, rpc->dirmap + from, len); 526 + if (rpc->bus_size == 2) 527 + memcpy_fromio_readw(buf, rpc->dirmap + from, len); 528 + else 529 + memcpy_fromio(buf, rpc->dirmap + from, len); 611 530 612 531 pm_runtime_put(rpc->dev); 613 532
+7 -6
drivers/memory/samsung/Kconfig
··· 14 14 depends on DEVFREQ_GOV_SIMPLE_ONDEMAND 15 15 depends on (PM_DEVFREQ && PM_DEVFREQ_EVENT) 16 16 help 17 - This adds driver for Exynos5422 DMC (Dynamic Memory Controller). 18 - The driver provides support for Dynamic Voltage and Frequency Scaling in 19 - DMC and DRAM. It also supports changing timings of DRAM running with 20 - different frequency. The timings are calculated based on DT memory 21 - information. 17 + This adds driver for Samsung Exynos5422 SoC DMC (Dynamic Memory 18 + Controller). The driver provides support for Dynamic Voltage and 19 + Frequency Scaling in DMC and DRAM. It also supports changing timings 20 + of DRAM running with different frequency. The timings are calculated 21 + based on DT memory information. 22 + If unsure, say Y on devices with Samsung Exynos SoCs. 22 23 23 24 config EXYNOS_SROM 24 25 bool "Exynos SROM controller driver" if COMPILE_TEST ··· 30 29 during suspend. If however appropriate device tree configuration 31 30 is provided, the driver enables support for external memory 32 31 or external devices. 33 - If unsure, say Y on devices with Samsung Exynos SocS. 32 + If unsure, say Y on devices with Samsung Exynos SoCs. 34 33 35 34 endif
+1
include/memory/renesas-rpc-if.h
··· 59 59 60 60 struct rpcif { 61 61 struct device *dev; 62 + void __iomem *base; 62 63 void __iomem *dirmap; 63 64 struct regmap *regmap; 64 65 struct reset_control *rstc;