LS1043A using QSPI to access FPGA

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

LS1043A using QSPI to access FPGA

Jump to solution
2,024 Views
dinghui
Contributor I

We develop a custom board based on LS1043A. We want to use QSPIA interface to access the FPGA and the chip select is QSPIA-CS1. I wrote the driver code refer to fsl_qspi.c in u-boot (version 2019.04). But it doesn't work at all. Since i issue the IP command to read data from FPGA, there is nothing output from QSPIA_CLK and QSPIA_CS1. I have already programed  the QSPI_SFAR register and written the QSPI_IPCR[SEQID] field to trigger the execution of a new IP Command that prepared in LUT table.

Following is demo driver code:

static void casco_qspi_set_lut(void)
{
struct fsl_qspi_regs *regs = casco_qspi_regs;
u32 lut_base;

/* Unlock the LUT */
casco_qspi_write32(casco_qspi_flags, &regs->lutkey, LUT_KEY_VALUE);
casco_qspi_write32(casco_qspi_flags, &regs->lckcr, QSPI_LCKCR_UNLOCK);

/* read from FPGA */
lut_base = SEQID_RDFPGA * 4;
casco_qspi_write32(casco_qspi_flags, &regs->lut[lut_base],
OPRND0(0xEB) | PAD0(LUT_PAD1) |
INSTR0(LUT_CMD) | OPRND1(ADDR32BIT) |
PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
casco_qspi_write32(casco_qspi_flags, &regs->lut[lut_base + 1],
OPRND0(10) | PAD0(LUT_PAD1) | INSTR0(LUT_DUMMY) |
OPRND1(4) | PAD1(LUT_PAD1) |
INSTR1(LUT_READ));
casco_qspi_write32(casco_qspi_flags, &regs->lut[lut_base + 2], 0);
casco_qspi_write32(casco_qspi_flags, &regs->lut[lut_base + 3], 0);

/* write to FPGA */
lut_base = SEQID_WRFPGA * 4;
casco_qspi_write32(casco_qspi_flags, &regs->lut[lut_base],
OPRND0(0x32) | PAD0(LUT_PAD1) |
INSTR0(LUT_CMD) | OPRND1(ADDR32BIT) |
PAD1(LUT_PAD1) | INSTR1(LUT_ADDR));
casco_qspi_write32(casco_qspi_flags, &regs->lut[lut_base + 1],
OPRND0(4) | PAD0(LUT_PAD1) | INSTR0(LUT_WRITE));
casco_qspi_write32(casco_qspi_flags, &regs->lut[lut_base + 2], 0);
casco_qspi_write32(casco_qspi_flags, &regs->lut[lut_base + 3], 0);

/* Lock the LUT */
casco_qspi_write32(casco_qspi_flags, &regs->lutkey, LUT_KEY_VALUE);
casco_qspi_write32(casco_qspi_flags, &regs->lckcr, QSPI_LCKCR_LOCK);
}

void casco_qspi_op_read(u32 offset, u32 *rxbuf, u32 len)
{
u32 mcr_reg, data;
int i, size;
u32 to_or_from;
u32 seqid;
struct fsl_qspi_regs *regs = casco_qspi_regs;
u32 temp = 0;

seqid = SEQID_RDFPGA;

mcr_reg = casco_qspi_read32(casco_qspi_flags, &regs->mcr);
casco_qspi_write32(casco_qspi_flags, &regs->mcr,
QSPI_MCR_CLR_RXF_MASK | QSPI_MCR_CLR_TXF_MASK |
QSPI_MCR_RESERVED_MASK | QSPI_MCR_END_CFD_LE);
casco_qspi_write32(casco_qspi_flags, &regs->rbct, QSPI_RBCT_RXBRD_USEIPS);

to_or_from = casco_qspi_ctrl->amba_base[0]+offset;
printf("%s: access address 0x%x\n", __func__, to_or_from);
if(len > 0x40)
{
len = 0x40;
}

while (len > 0) {

casco_qspi_write32(casco_qspi_flags, &regs->sfar, to_or_from);
temp = casco_qspi_read32(casco_qspi_flags, &regs->sfar);
printf("%s: reg sfar read 0x%x\n", __func__, temp);
temp = casco_qspi_read32(casco_qspi_flags, &regs->sfa1ad);
printf("%s: reg sfa1ad read 0x%x\n", __func__, temp);
temp = casco_qspi_read32(casco_qspi_flags, &regs->sfa2ad);
printf("%s: reg sfa2ad read 0x%x\n", __func__, temp);
temp = casco_qspi_read32(casco_qspi_flags, &regs->sfb1ad);
printf("%s: reg sfb1ad read 0x%x\n", __func__, temp);
temp = casco_qspi_read32(casco_qspi_flags, &regs->sfb2ad);
printf("%s: reg sfb2ad read 0x%x\n", __func__, temp);

size = (len > RX_BUFFER_SIZE) ?
RX_BUFFER_SIZE : len;

casco_qspi_write32(casco_qspi_flags, &regs->ipcr,
(seqid << QSPI_IPCR_SEQID_SHIFT) |
size);

temp = casco_qspi_read32(casco_qspi_flags, &regs->lut[seqid << 2]);
printf("%s: reg lut[%d] read 0x%x\n", __func__, seqid << 2, temp);

temp = casco_qspi_read32(casco_qspi_flags, &regs->fr);
printf("%s: reg fr read 0x%x\n", __func__, temp);

while (casco_qspi_read32(casco_qspi_flags, &regs->sr) & QSPI_SR_BUSY_MASK)
;
temp = casco_qspi_read32(casco_qspi_flags, &regs->fr);
printf("%s: reg fr read 0x%x\n", __func__, temp);

to_or_from += size;
len -= size;

i = 0;
while ((RX_BUFFER_SIZE >= size) && (size > 0)) {
data = casco_qspi_read32(casco_qspi_flags, &regs->rbdr[i]);
data = casco_qspi_endian_xchg(data);
if (size < 4)
memcpy(rxbuf, &data, size);
else
memcpy(rxbuf, &data, 4);
rxbuf++;
size -= 4;
i++;
}
casco_qspi_write32(casco_qspi_flags, &regs->mcr,
casco_qspi_read32(casco_qspi_flags, &regs->mcr) |
QSPI_MCR_CLR_RXF_MASK);
}

casco_qspi_write32(casco_qspi_flags, &regs->mcr, mcr_reg);
}

int casco_qspi_init(void)
{
u32 mcr_val;
u32 amba_size_per_chip;

int i, ret;

caso_qspi_plat = (struct casco_qspi_platdata *)malloc(sizeof(struct casco_qspi_platdata));
memset(caso_qspi_plat, 0, sizeof(struct casco_qspi_platdata));
caso_qspi_plat->flags |= QSPI_FLAG_REGMAP_ENDIAN_BIG;
casco_qspi_flags |= caso_qspi_plat->flags;
caso_qspi_plat->speed_hz = 6250000;
caso_qspi_plat->num_chipselect = 4;
caso_qspi_plat->reg_base = 0x1550000;
caso_qspi_plat->amba_base = 0x40000000;
caso_qspi_plat->amba_total_size = 0x20000000;

casco_qspi_ctrl = (struct casco_qspi_priv *)malloc(sizeof(struct casco_qspi_priv));
memset(casco_qspi_ctrl, 0, sizeof(struct casco_qspi_priv));

casco_qspi_regs = (struct fsl_qspi_regs *)malloc(sizeof(struct fsl_qspi_regs));
memset(casco_qspi_regs, 0, sizeof(struct fsl_qspi_regs));

casco_qspi_write32(casco_qspi_flags, 0x157015c, 0x00100000);/* CLK 6.25MHz */

casco_qspi_ctrl->regs = (struct fsl_qspi_regs *)casco_qspi_regs;
casco_qspi_ctrl->flags = caso_qspi_plat->flags;

casco_qspi_ctrl->speed_hz = caso_qspi_plat->speed_hz;
/*
* QSPI SFADR width is 32bits, the max dest addr is 4GB-1.
* AMBA memory zone should be located on the 0~4GB space
* even on a 64bits cpu.
*/
casco_qspi_ctrl->amba_base[0] = (u32)caso_qspi_plat->amba_base;
casco_qspi_ctrl->amba_total_size = (u32)caso_qspi_plat->amba_total_size;
casco_qspi_ctrl->flash_num = caso_qspi_plat->flash_num;
casco_qspi_ctrl->num_chipselect = caso_qspi_plat->num_chipselect;

/* make sure controller is not busy anywhere */
ret = is_controller_busy(casco_qspi_ctrl);

if (ret) {
printf("ERROR : The controller is busy\n");
return ret;
}

mcr_val = casco_qspi_read32(casco_qspi_ctrl->flags, &casco_qspi_ctrl->regs->mcr);

casco_qspi_write32(casco_qspi_ctrl->flags, &casco_qspi_ctrl->regs->mcr,
QSPI_MCR_RESERVED_MASK | QSPI_MCR_MDIS_MASK |
(mcr_val & QSPI_MCR_END_CFD_MASK));

qspi_cfg_smpr(casco_qspi_ctrl, ~(QSPI_SMPR_FSDLY_MASK | QSPI_SMPR_DDRSMP_MASK |
QSPI_SMPR_FSPHS_MASK | QSPI_SMPR_HSENA_MASK), 0);

/*
* Assign AMBA memory zone for every chipselect
* QuadSPI has two channels, every channel has two chipselects.
* If the property 'num-cs' in dts is 2, the AMBA memory will be divided
* into two parts and assign to every channel. This indicate that every
* channel only has one valid chipselect.
* If the property 'num-cs' in dts is 4, the AMBA memory will be divided
* into four parts and assign to every chipselect.
* Every channel will has two valid chipselects.
*/
amba_size_per_chip = casco_qspi_ctrl->amba_total_size >>
(casco_qspi_ctrl->num_chipselect >> 1);
for (i = 1 ; i < casco_qspi_ctrl->num_chipselect ; i++)
casco_qspi_ctrl->amba_base[i] =
amba_size_per_chip + casco_qspi_ctrl->amba_base[i - 1];

/*
* Any read access to non-implemented addresses will provide
* undefined results.
*
* In case single die flash devices, TOP_ADDR_MEMA2 and
* TOP_ADDR_MEMB2 should be initialized/programmed to
* TOP_ADDR_MEMA1 and TOP_ADDR_MEMB1 respectively - in effect,
* setting the size of these devices to 0. This would ensure
* that the complete memory map is assigned to only one flash device.
*/
casco_qspi_write32(casco_qspi_ctrl->flags, &casco_qspi_ctrl->regs->sfa1ad,
casco_qspi_ctrl->amba_base[0] + amba_size_per_chip);
switch (casco_qspi_ctrl->num_chipselect) {
case 1:
break;
case 2:
casco_qspi_write32(casco_qspi_ctrl->flags, &casco_qspi_ctrl->regs->sfa2ad,
casco_qspi_ctrl->amba_base[1]);
casco_qspi_write32(casco_qspi_ctrl->flags, &casco_qspi_ctrl->regs->sfb1ad,
casco_qspi_ctrl->amba_base[1] + amba_size_per_chip);
casco_qspi_write32(casco_qspi_ctrl->flags, &casco_qspi_ctrl->regs->sfb2ad,
casco_qspi_ctrl->amba_base[1] + amba_size_per_chip);
break;
case 4:
casco_qspi_write32(casco_qspi_ctrl->flags, &casco_qspi_ctrl->regs->sfa2ad,
casco_qspi_ctrl->amba_base[2]);
casco_qspi_write32(casco_qspi_ctrl->flags, &casco_qspi_ctrl->regs->sfb1ad,
casco_qspi_ctrl->amba_base[3]);
casco_qspi_write32(casco_qspi_ctrl->flags, &casco_qspi_ctrl->regs->sfb2ad,
casco_qspi_ctrl->amba_base[3] + amba_size_per_chip);
break;
default:
printf("Error: Unsupported chipselect number %u!\n",
casco_qspi_ctrl->num_chipselect);
qspi_module_disable(casco_qspi_ctrl, 1);
return -EINVAL;
}

/*qspi_set_lut(priv);*/
casco_qspi_set_lut();

qspi_module_disable(casco_qspi_ctrl, 0);

return 0;
}

Labels (1)
0 Kudos
Reply
1 Solution
2,019 Views
dinghui
Contributor I

Found the problem:

the following code should be modified:

casco_qspi_regs = (struct fsl_qspi_regs *)malloc(sizeof(struct fsl_qspi_regs));
memset(casco_qspi_regs, 0, sizeof(struct fsl_qspi_regs));

After modified:

casco_qspi_regs = (struct fsl_qspi_regs *)(uintptr_t)0x1550000;

View solution in original post

0 Kudos
Reply
1 Reply
2,020 Views
dinghui
Contributor I

Found the problem:

the following code should be modified:

casco_qspi_regs = (struct fsl_qspi_regs *)malloc(sizeof(struct fsl_qspi_regs));
memset(casco_qspi_regs, 0, sizeof(struct fsl_qspi_regs));

After modified:

casco_qspi_regs = (struct fsl_qspi_regs *)(uintptr_t)0x1550000;

0 Kudos
Reply