Commit 6cbc8b5893b49d84abf1222e0c6984540314d466
1 parent
990b4fff61
Exists in
smarc_8mq_lf_v2020.04
and in
4 other branches
fsl_qspi: Provide config to map full AHB space
iMX platforms provide large AHB mapped space for QSPI, each controller has 256MB. However, current driver only maps small size (AHB buffer size) of AHB space, this implementation causes iMX failed to boot M4 with QSPI XIP image. Add config CONFIG_FSL_QSPI_AHB_FULL_MAP (default enabled for iMX) to address above problem. When the config is set: 1. Full AHB space is divided to each CS. 2. A dedicated LUT entry is used for AHB read only. 3. The MODE instruction in LUT is replaced to standard ADDR instruction 4. The address in spi_mem_op is used to SFAR and AHB read Signed-off-by: Ye Li <ye.li@nxp.com>
Showing 2 changed files with 80 additions and 10 deletions Side-by-side Diff
drivers/spi/Kconfig
... | ... | @@ -420,6 +420,13 @@ |
420 | 420 | used to access the SPI NOR flash on platforms embedding this |
421 | 421 | Freescale IP core. |
422 | 422 | |
423 | +config FSL_QSPI_AHB_FULL_MAP | |
424 | + bool "Use full AHB memory map space" | |
425 | + depends on FSL_QSPI | |
426 | + default y if ARCH_MX6 || ARCH_MX7 || ARCH_MX7ULP || ARCH_IMX8M | |
427 | + help | |
428 | + Enable the Freescale QSPI driver to use full AHB memory map space | |
429 | + | |
423 | 430 | config DAVINCI_SPI |
424 | 431 | bool "Davinci & Keystone SPI driver" |
425 | 432 | depends on ARCH_DAVINCI || ARCH_KEYSTONE |
drivers/spi/fsl_qspi.c
... | ... | @@ -40,6 +40,7 @@ |
40 | 40 | * read operation, so let's use the last entry (15). |
41 | 41 | */ |
42 | 42 | #define SEQID_LUT 15 |
43 | +#define SEQID_LUT_AHB 14 | |
43 | 44 | |
44 | 45 | /* Registers used by the driver */ |
45 | 46 | #define QUADSPI_MCR 0x00 |
... | ... | @@ -116,6 +117,10 @@ |
116 | 117 | #define QUADSPI_LUT_REG(idx) \ |
117 | 118 | (QUADSPI_LUT_BASE + QUADSPI_LUT_OFFSET + (idx) * 4) |
118 | 119 | |
120 | +#define QUADSPI_AHB_LUT_OFFSET (SEQID_LUT_AHB * 4 * 4) | |
121 | +#define QUADSPI_AHB_LUT_REG(idx) \ | |
122 | + (QUADSPI_LUT_BASE + QUADSPI_AHB_LUT_OFFSET + (idx) * 4) | |
123 | + | |
119 | 124 | /* Instruction set for the LUT register */ |
120 | 125 | #define LUT_STOP 0 |
121 | 126 | #define LUT_CMD 1 |
... | ... | @@ -183,6 +188,11 @@ |
183 | 188 | */ |
184 | 189 | #define QUADSPI_QUIRK_USE_TDH_SETTING BIT(5) |
185 | 190 | |
191 | +/* | |
192 | + * Controller only has Two CS on flash A, no flash B port | |
193 | + */ | |
194 | +#define QUADSPI_QUIRK_SINGLE_BUS BIT(6) | |
195 | + | |
186 | 196 | struct fsl_qspi_devtype_data { |
187 | 197 | unsigned int rxfifo; |
188 | 198 | unsigned int txfifo; |
... | ... | @@ -230,7 +240,7 @@ |
230 | 240 | .txfifo = SZ_64, |
231 | 241 | .ahb_buf_size = SZ_128, |
232 | 242 | .quirks = QUADSPI_QUIRK_TKT253890 | QUADSPI_QUIRK_4X_INT_CLK | |
233 | - QUADSPI_QUIRK_USE_TDH_SETTING, | |
243 | + QUADSPI_QUIRK_USE_TDH_SETTING | QUADSPI_QUIRK_SINGLE_BUS, | |
234 | 244 | .little_endian = true, |
235 | 245 | }; |
236 | 246 | |
... | ... | @@ -263,6 +273,7 @@ |
263 | 273 | void __iomem *iobase; |
264 | 274 | void __iomem *ahb_addr; |
265 | 275 | u32 memmap_phy; |
276 | + u32 memmap_size; | |
266 | 277 | const struct fsl_qspi_devtype_data *devtype_data; |
267 | 278 | int selected; |
268 | 279 | }; |
... | ... | @@ -297,6 +308,11 @@ |
297 | 308 | return q->devtype_data->quirks & QUADSPI_QUIRK_USE_TDH_SETTING; |
298 | 309 | } |
299 | 310 | |
311 | +static inline int needs_single_bus(struct fsl_qspi *q) | |
312 | +{ | |
313 | + return q->devtype_data->quirks & QUADSPI_QUIRK_SINGLE_BUS; | |
314 | +} | |
315 | + | |
300 | 316 | /* |
301 | 317 | * An IC bug makes it necessary to rearrange the 32-bit data. |
302 | 318 | * Later chips, such as IMX6SLX, have fixed this bug. |
... | ... | @@ -399,6 +415,14 @@ |
399 | 415 | lutval[0] |= LUT_DEF(0, LUT_CMD, LUT_PAD(op->cmd.buswidth), |
400 | 416 | op->cmd.opcode); |
401 | 417 | |
418 | +#ifdef CONFIG_FSL_QSPI_AHB_FULL_MAP | |
419 | + if (op->addr.nbytes) { | |
420 | + lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_ADDR, | |
421 | + LUT_PAD(op->addr.buswidth), | |
422 | + (op->addr.nbytes == 4)? 0x20 : 0x18); | |
423 | + lutidx++; | |
424 | + } | |
425 | +#else | |
402 | 426 | /* |
403 | 427 | * For some unknown reason, using LUT_ADDR doesn't work in some |
404 | 428 | * cases (at least with only one byte long addresses), so |
... | ... | @@ -412,6 +436,7 @@ |
412 | 436 | addrbyte); |
413 | 437 | lutidx++; |
414 | 438 | } |
439 | +#endif | |
415 | 440 | |
416 | 441 | if (op->dummy.nbytes) { |
417 | 442 | lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_DUMMY, |
... | ... | @@ -443,6 +468,14 @@ |
443 | 468 | for (i = 0; i < ARRAY_SIZE(lutval); i++) |
444 | 469 | qspi_writel(q, lutval[i], base + QUADSPI_LUT_REG(i)); |
445 | 470 | |
471 | +#ifdef CONFIG_FSL_QSPI_AHB_FULL_MAP | |
472 | + if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_IN && | |
473 | + op->addr.nbytes) { | |
474 | + for (i = 0; i < ARRAY_SIZE(lutval); i++) | |
475 | + qspi_writel(q, lutval[i], base + QUADSPI_AHB_LUT_REG(i)); | |
476 | + } | |
477 | +#endif | |
478 | + | |
446 | 479 | /* lock LUT */ |
447 | 480 | qspi_writel(q, QUADSPI_LUTKEY_VALUE, q->iobase + QUADSPI_LUTKEY); |
448 | 481 | qspi_writel(q, QUADSPI_LCKER_LOCK, q->iobase + QUADSPI_LCKCR); |
449 | 482 | |
450 | 483 | |
... | ... | @@ -485,10 +518,27 @@ |
485 | 518 | fsl_qspi_invalidate(q); |
486 | 519 | } |
487 | 520 | |
521 | +static u32 fsl_qspi_memsize_per_cs(struct fsl_qspi *q) | |
522 | +{ | |
523 | +#ifdef CONFIG_FSL_QSPI_AHB_FULL_MAP | |
524 | + if (needs_single_bus(q)) | |
525 | + return q->memmap_size / 2; | |
526 | + else | |
527 | + return q->memmap_size / 4; | |
528 | +#else | |
529 | + return ALIGN(q->devtype_data->ahb_buf_size, 0x400); | |
530 | +#endif | |
531 | +} | |
532 | + | |
488 | 533 | static void fsl_qspi_read_ahb(struct fsl_qspi *q, const struct spi_mem_op *op) |
489 | 534 | { |
535 | + void __iomem *ahb_read_addr = q->ahb_addr; | |
536 | +#ifdef CONFIG_FSL_QSPI_AHB_FULL_MAP | |
537 | + if (op->addr.nbytes) | |
538 | + ahb_read_addr += op->addr.val; | |
539 | +#endif | |
490 | 540 | memcpy_fromio(op->data.buf.in, |
491 | - q->ahb_addr + q->selected * ALIGN(q->devtype_data->ahb_buf_size, 0x400), | |
541 | + ahb_read_addr + q->selected * fsl_qspi_memsize_per_cs(q), | |
492 | 542 | op->data.nbytes); |
493 | 543 | } |
494 | 544 | |
495 | 545 | |
... | ... | @@ -591,8 +641,12 @@ |
591 | 641 | if (needs_amba_base_offset(q)) |
592 | 642 | addr_offset = q->memmap_phy; |
593 | 643 | |
644 | +#ifdef CONFIG_FSL_QSPI_AHB_FULL_MAP | |
645 | + if (op->addr.nbytes) | |
646 | + addr_offset += op->addr.val; | |
647 | +#endif | |
594 | 648 | qspi_writel(q, |
595 | - q->selected * ALIGN(q->devtype_data->ahb_buf_size, 0x400) + addr_offset, | |
649 | + q->selected * fsl_qspi_memsize_per_cs(q) + addr_offset, | |
596 | 650 | base + QUADSPI_SFAR); |
597 | 651 | |
598 | 652 | qspi_writel(q, qspi_readl(q, base + QUADSPI_MCR) | |
... | ... | @@ -649,7 +703,7 @@ |
649 | 703 | static int fsl_qspi_default_setup(struct fsl_qspi *q) |
650 | 704 | { |
651 | 705 | void __iomem *base = q->iobase; |
652 | - u32 reg, addr_offset = 0; | |
706 | + u32 reg, addr_offset = 0, memsize_cs; | |
653 | 707 | |
654 | 708 | /* Reset the module */ |
655 | 709 | qspi_writel(q, QUADSPI_MCR_SWRSTSD_MASK | QUADSPI_MCR_SWRSTHD_MASK, |
656 | 710 | |
... | ... | @@ -681,8 +735,13 @@ |
681 | 735 | qspi_writel(q, 0, base + QUADSPI_BUF1IND); |
682 | 736 | qspi_writel(q, 0, base + QUADSPI_BUF2IND); |
683 | 737 | |
738 | +#ifdef CONFIG_FSL_QSPI_AHB_FULL_MAP | |
739 | + qspi_writel(q, QUADSPI_BFGENCR_SEQID(SEQID_LUT_AHB), | |
740 | + q->iobase + QUADSPI_BFGENCR); | |
741 | +#else | |
684 | 742 | qspi_writel(q, QUADSPI_BFGENCR_SEQID(SEQID_LUT), |
685 | 743 | q->iobase + QUADSPI_BFGENCR); |
744 | +#endif | |
686 | 745 | qspi_writel(q, QUADSPI_RBCT_WMRK_MASK, base + QUADSPI_RBCT); |
687 | 746 | qspi_writel(q, QUADSPI_BUF3CR_ALLMST_MASK | |
688 | 747 | QUADSPI_BUF3CR_ADATSZ(q->devtype_data->ahb_buf_size / 8), |
689 | 748 | |
690 | 749 | |
... | ... | @@ -698,14 +757,17 @@ |
698 | 757 | * We use ahb_buf_size for each chip and set SFA1AD, SFA2AD, SFB1AD, |
699 | 758 | * SFB2AD accordingly. |
700 | 759 | */ |
701 | - qspi_writel(q, ALIGN(q->devtype_data->ahb_buf_size, 0x400) + addr_offset, | |
760 | + memsize_cs = fsl_qspi_memsize_per_cs(q); | |
761 | + qspi_writel(q, memsize_cs + addr_offset, | |
702 | 762 | base + QUADSPI_SFA1AD); |
703 | - qspi_writel(q, ALIGN(q->devtype_data->ahb_buf_size, 0x400) * 2 + addr_offset, | |
763 | + qspi_writel(q, memsize_cs * 2 + addr_offset, | |
704 | 764 | base + QUADSPI_SFA2AD); |
705 | - qspi_writel(q, ALIGN(q->devtype_data->ahb_buf_size, 0x400) * 3 + addr_offset, | |
706 | - base + QUADSPI_SFB1AD); | |
707 | - qspi_writel(q, ALIGN(q->devtype_data->ahb_buf_size, 0x400) * 4 + addr_offset, | |
708 | - base + QUADSPI_SFB2AD); | |
765 | + if (!needs_single_bus(q)) { | |
766 | + qspi_writel(q, memsize_cs * 3 + addr_offset, | |
767 | + base + QUADSPI_SFB1AD); | |
768 | + qspi_writel(q, memsize_cs * 4 + addr_offset, | |
769 | + base + QUADSPI_SFB2AD); | |
770 | + } | |
709 | 771 | |
710 | 772 | q->selected = -1; |
711 | 773 | |
... | ... | @@ -753,6 +815,7 @@ |
753 | 815 | |
754 | 816 | q->ahb_addr = map_physmem(res.start, res.end - res.start, MAP_NOCACHE); |
755 | 817 | q->memmap_phy = res.start; |
818 | + q->memmap_size = res.end - res.start; | |
756 | 819 | |
757 | 820 | dm_bus->max_hz = fdtdec_get_int(blob, node, "spi-max-frequency", |
758 | 821 | 66000000); |