|
51 | 51 | */ |
52 | 52 | #define UMA_WAIT_ITERATIONS 100 |
53 | 53 |
|
| 54 | +/* The memory-mapped view of flash is 16 MiB long */ |
| 55 | +#define MAX_MEMORY_SIZE_PER_CS (16 << 20) |
| 56 | +#define MAX_MEMORY_SIZE_TOTAL (4 * MAX_MEMORY_SIZE_PER_CS) |
| 57 | + |
54 | 58 | struct wpcm_fiu_spi { |
55 | 59 | struct device *dev; |
56 | 60 | struct clk *clk; |
57 | 61 | void __iomem *regs; |
| 62 | + void __iomem *memory; |
| 63 | + size_t memory_size; |
58 | 64 | struct regmap *shm_regmap; |
59 | 65 | }; |
60 | 66 |
|
@@ -367,14 +373,64 @@ static int wpcm_fiu_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) |
367 | 373 | return 0; |
368 | 374 | } |
369 | 375 |
|
| 376 | +static int wpcm_fiu_dirmap_create(struct spi_mem_dirmap_desc *desc) |
| 377 | +{ |
| 378 | + struct wpcm_fiu_spi *fiu = spi_controller_get_devdata(desc->mem->spi->controller); |
| 379 | + int cs = desc->mem->spi->chip_select; |
| 380 | + |
| 381 | + if (desc->info.op_tmpl.data.dir != SPI_MEM_DATA_IN) |
| 382 | + return -ENOTSUPP; |
| 383 | + |
| 384 | + /* |
| 385 | + * Unfortunately, FIU only supports a 16 MiB direct mapping window (per |
| 386 | + * attached flash chip), but the SPI MEM core doesn't support partial |
| 387 | + * direct mappings. This means that we can't support direct mapping on |
| 388 | + * flashes that are bigger than 16 MiB. |
| 389 | + */ |
| 390 | + if (desc->info.offset + desc->info.length > MAX_MEMORY_SIZE_PER_CS) |
| 391 | + return -ENOTSUPP; |
| 392 | + |
| 393 | + /* Don't read past the memory window */ |
| 394 | + if (cs * MAX_MEMORY_SIZE_PER_CS + desc->info.offset + desc->info.length > fiu->memory_size) |
| 395 | + return -ENOTSUPP; |
| 396 | + |
| 397 | + return 0; |
| 398 | +} |
| 399 | + |
| 400 | +static ssize_t wpcm_fiu_direct_read(struct spi_mem_dirmap_desc *desc, u64 offs, size_t len, void *buf) |
| 401 | +{ |
| 402 | + struct wpcm_fiu_spi *fiu = spi_controller_get_devdata(desc->mem->spi->controller); |
| 403 | + int cs = desc->mem->spi->chip_select; |
| 404 | + |
| 405 | + if (offs >= MAX_MEMORY_SIZE_PER_CS) |
| 406 | + return -ENOTSUPP; |
| 407 | + |
| 408 | + offs += cs * MAX_MEMORY_SIZE_PER_CS; |
| 409 | + |
| 410 | + if (!fiu->memory || offs >= fiu->memory_size) |
| 411 | + return -ENOTSUPP; |
| 412 | + |
| 413 | + len = min_t(size_t, len, fiu->memory_size - offs); |
| 414 | + memcpy_fromio(buf, fiu->memory + offs, len); |
| 415 | + |
| 416 | + return len; |
| 417 | +} |
| 418 | + |
370 | 419 | static const struct spi_controller_mem_ops wpcm_fiu_mem_ops = { |
371 | 420 | .adjust_op_size = wpcm_fiu_adjust_op_size, |
372 | 421 | .supports_op = wpcm_fiu_supports_op, |
373 | 422 | .exec_op = wpcm_fiu_exec_op, |
| 423 | + .dirmap_create = wpcm_fiu_dirmap_create, |
| 424 | + .dirmap_read = wpcm_fiu_direct_read, |
374 | 425 | }; |
375 | 426 |
|
376 | 427 | static void wpcm_fiu_hw_init(struct wpcm_fiu_spi *fiu) |
377 | 428 | { |
| 429 | + /* Configure memory-mapped flash access */ |
| 430 | + writeb(FIU_BURST_CFG_R16, fiu->regs + FIU_BURST_BFG); |
| 431 | + writeb(MAX_MEMORY_SIZE_TOTAL / (512 << 10), fiu->regs + FIU_CFG); |
| 432 | + writeb(MAX_MEMORY_SIZE_PER_CS / (512 << 10) | BIT(6), fiu->regs + FIU_SPI_FL_CFG); |
| 433 | + |
378 | 434 | /* Deassert all manually asserted chip selects */ |
379 | 435 | writeb(0x0f, fiu->regs + FIU_UMA_ECTS); |
380 | 436 | } |
@@ -404,6 +460,14 @@ static int wpcm_fiu_probe(struct platform_device *pdev) |
404 | 460 | if (IS_ERR(fiu->clk)) |
405 | 461 | return PTR_ERR(fiu->clk); |
406 | 462 |
|
| 463 | + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "memory"); |
| 464 | + fiu->memory = devm_ioremap_resource(dev, res); |
| 465 | + fiu->memory_size = min_t(size_t, resource_size(res), MAX_MEMORY_SIZE_TOTAL); |
| 466 | + if (IS_ERR(fiu->memory)) { |
| 467 | + dev_err(dev, "Failed to map flash memory window\n"); |
| 468 | + return PTR_ERR(fiu->memory); |
| 469 | + } |
| 470 | + |
407 | 471 | fiu->shm_regmap = syscon_regmap_lookup_by_phandle_optional(dev->of_node, "nuvoton,shm"); |
408 | 472 |
|
409 | 473 | wpcm_fiu_hw_init(fiu); |
|
0 commit comments