From 8aefb9d1399ea75318d11a3817c1be8377a2155d Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Thu, 27 Aug 2015 14:15:23 -0600 Subject: [PATCH] SAMV71 QSPI: Redesign some functions to better matched new interface definition --- arch/arm/src/samv7/chip/sam_qspi.h | 2 + arch/arm/src/samv7/sam_qspi.c | 338 ++++++++++++----------------- 2 files changed, 139 insertions(+), 201 deletions(-) diff --git a/arch/arm/src/samv7/chip/sam_qspi.h b/arch/arm/src/samv7/chip/sam_qspi.h index b23aea26da..0954e2d782 100644 --- a/arch/arm/src/samv7/chip/sam_qspi.h +++ b/arch/arm/src/samv7/chip/sam_qspi.h @@ -225,6 +225,8 @@ # define QSPI_IFR_OPTL_4BIT (2 << QSPI_IFR_OPTL_SHIFT) /* Option is 4 bits */ # define QSPI_IFR_OPTL_8BIT (3 << QSPI_IFR_OPTL_SHIFT) /* Option is 8 bits */ #define QSPI_IFR_ADDRL (1 << 10) /* Bit 10: Address Length */ +# define QSPI_IFR_ADDRL_24BIT (0 << 10) /* 0=24-bit */ +# define QSPI_IFR_ADDRL_32BIT (1 << 10) /* 1=32-bit */ #define QSPI_IFR_TFRTYP_SHIFT (12) /* Bits 12-13: Data Transfer Type */ #define QSPI_IFR_TFRTYP_MASK (3 << QSPI_IFR_TFRTYP_SHIFT) # define QSPI_IFR_TFRTYP_READ (0 << QSPI_IFR_TFRTYP_SHIFT) /* Read transfer from serial memory */ diff --git a/arch/arm/src/samv7/sam_qspi.c b/arch/arm/src/samv7/sam_qspi.c index c94f450c1a..1dd39aafc4 100644 --- a/arch/arm/src/samv7/sam_qspi.c +++ b/arch/arm/src/samv7/sam_qspi.c @@ -264,11 +264,8 @@ static int qspi_lock(struct qspi_dev_s *dev, bool lock); static uint32_t qspi_setfrequency(struct qspi_dev_s *dev, uint32_t frequency); static void qspi_setmode(struct qspi_dev_s *dev, enum qspi_mode_e mode); static void qspi_setbits(struct qspi_dev_s *dev, int nbits); -static int qspi_command(struct qspi_dev_s *dev, uint16_t cmd); -static int qspi_command_write(struct qspi_dev_s *dev, uint16_t cmd, - const void *buffer, size_t buflen); -static int qspi_command_read(struct qspi_dev_s *dev, uint16_t cmd, - void *buffer, size_t buflen); +static int qspi_command(struct qspi_dev_s *dev, + struct qspi_xfrinfo_s *xfrinfo); /* Initialization */ @@ -288,8 +285,6 @@ static const struct qspi_ops_s g_qspi0ops = .setmode = qspi_setmode, .setbits = qspi_setbits, .command = qspi_command, - .command_write = qspi_command_write, - .command_read = qspi_command_read, }; /* This is the overall state of the QSPI0 controller */ @@ -1004,54 +999,161 @@ static void qspi_setbits(struct qspi_dev_s *dev, int nbits) * Name: qspi_command * * Description: - * Send a command to the QSPI device + * Perform one QSPI data transfer * * Input Parameters: - * dev - Device-specific state data - * cmd - The command to send. the size of the data is determined by the - * number of bits selected for the QSPI interface. + * dev - Device-specific state data + * xfrinfo - Describes the transfer to be performed. * * Returned Value: * Zero (OK) on SUCCESS, a negated errno on value of failure * ****************************************************************************/ -static int qspi_command(struct qspi_dev_s *dev, uint16_t cmd) +static int qspi_command(struct qspi_dev_s *dev, + struct qspi_xfrinfo_s *xfrinfo) { struct sam_qspidev_s *priv = (struct sam_qspidev_s *)dev; uint32_t regval; + uint32_t ifr; - spivdbg("cmd: %04x\n"); - DEBUGASSERT(priv != NULL && cmd < 256); + DEBUGASSERT(priv != NULL && xfrinfo != NULL); - /* Write the the Instruction code register: +#ifdef CONFIG_DEBUG_SPI + spivdbg("Transfer:\n"); + spivdbg(" flags: %02x\n", xfrinfo->flags); + spivdbg(" cmd: %04x\n", xfrinfo->cmd); + if (QSPIXFR_ISADDRESS(xfrinfo->flags)) + { + spivdbg(" address/length: %08lx %d\n", + (unsigned long)xfrinfo->addr, xfrinfo->addrlen); + } + + if (QSPIXFR_ISDATA(xfrinfo->flags)) + { + spivdbg(" %s Data:\n", QSPIXFR_ISWRITE(xfrinfo->flags) ? "Write" : "Read"); + spivdbg(" buffer/length: %p %d\n", xfrinfo->buffer, xfrinfo->buflen); + } +#endif + + DEBUGASSERT(xfrinfo->cmd < 256); + + /* Write the instruction address register */ + + ifr = 0; + if (QSPIXFR_ISADDRESS(xfrinfo->flags)) + { + DEBUGASSERT(xfrinfo->addrlen == 3 || xfrinfo->addrlen == 4); + + qspi_putreg(priv, xfrinfo->addr, SAM_QSPI_IFR_OFFSET); + ifr |= QSPI_IFR_ADDREN; + + if (xfrinfo->addrlen == 3) + { + ifr |= QSPI_IFR_ADDRL_24BIT; + } + else if (xfrinfo->addrlen == 4) + { + ifr |= QSPI_IFR_ADDRL_32BIT; + } + else + { + return -EINVAL; + } + } + + /* Write the Instruction code register: * * QSPI_ICR_INST(cmd) 8-bit command * QSPI_ICR_OPT(0) No option */ - regval = QSPI_ICR_INST(cmd) | QSPI_ICR_OPT(0); + regval = QSPI_ICR_INST(xfrinfo->cmd) | QSPI_ICR_OPT(0); qspi_putreg(priv, regval, SAM_QSPI_ICR_OFFSET); - /* Write Instruction Frame Register: - * - * QSPI_IFR_WIDTH_SINGLE Instruction=single bit - * QSPI_IFR_INSTEN=1 Instruction Enable - * QSPI_IFR_ADDREN=0 Address Disable - * QSPI_IFR_OPTEN=0 Option Disable - * QSPI_IFR_DATAEN=0 Data Disable - * QSPI_IFR_OPTL_* Not used (zero) - * QSPI_IFR_ADDRL=0 Not used (zero) - * QSPI_IFR_TFRTYP_READ Shouldn't matter - * QSPI_IFR_CRM=0 Not continuous read - * QSPI_IFR_NBDUM(0) No dummy cycles - */ + if (QSPIXFR_ISDATA(xfrinfo->flags)) + { + uint16_t buflen; - regval = QSPI_IFR_WIDTH_SINGLE | QSPI_IFR_INSTEN | QSPI_IFR_TFRTYP_READ | - QSPI_IFR_NBDUM(0); - qspi_putreg(priv, regval, SAM_QSPI_IFR_OFFSET); + DEBUGASSERT(xfrinfo->buffer != NULL && xfrinfo->buflen > 0); - MEMORY_SYNC(); + /* Make sure that the length is an even multiple of 32-bit words. */ + + DEBUGASSERT((xfrinfo->buflen & 3) == 0); + buflen = (xfrinfo->buflen + 3) & ~3; + + /* Write Instruction Frame Register: + * + * QSPI_IFR_WIDTH_SINGLE Instruction=single bit + * QSPI_IFR_INSTEN=1 Instruction Enable + * QSPI_IFR_ADDREN=? (See logic above) + * QSPI_IFR_OPTEN=0 Option Disable + * QSPI_IFR_DATAEN=1 Data Enable + * QSPI_IFR_OPTL_* Not used (zero) + * QSPI_IFR_ADDRL=0 Not used (zero) + * QSPI_IFR_TFRTYP_WRITE Write transfer into serial memory, OR + * QSPI_IFR_TFRTYP_READ Read transfer from serial memory + * QSPI_IFR_CRM=0 Not continuous read + * QSPI_IFR_NBDUM(0) No dummy cycles + */ + + ifr |= QSPI_IFR_WIDTH_SINGLE | QSPI_IFR_INSTEN | QSPI_IFR_DATAEN | + QSPI_IFR_NBDUM(0); + + if (QSPIXFR_ISWRITE(xfrinfo->flags)) + { + ifr |= QSPI_IFR_TFRTYP_WRITE; + qspi_putreg(priv, ifr, SAM_QSPI_IFR_OFFSET); + + (void)qspi_getreg(priv, SAM_QSPI_IFR_OFFSET); + + /* Copy the data to write to QSPI_RAM */ + + memcpy((void *)SAM_QSPIMEM_BASE, xfrinfo->buffer, buflen); + } + else + { + ifr |= QSPI_IFR_TFRTYP_READ; + qspi_putreg(priv, ifr, SAM_QSPI_IFR_OFFSET); + + (void)qspi_getreg(priv, SAM_QSPI_IFR_OFFSET); + + /* Copy the data from QSPI memory into the user buffer */ + + memcpy(xfrinfo->buffer, (const void *)SAM_QSPIMEM_BASE, buflen); + } + + MEMORY_SYNC(); + + /* Indicate the end of the transfer as soon as the transmission + * registers are empty. + */ + + while ((qspi_getreg(priv, SAM_QSPI_SR_OFFSET) & QSPI_INT_TXEMPTY) == 0); + qspi_putreg(priv, QSPI_CR_LASTXFER, SAM_QSPI_CR_OFFSET); + } + else + { + /* Write Instruction Frame Register: + * + * QSPI_IFR_WIDTH_SINGLE Instruction=single bit + * QSPI_IFR_INSTEN=1 Instruction Enable + * QSPI_IFR_ADDREN=? (See logic above) + * QSPI_IFR_OPTEN=0 Option Disable + * QSPI_IFR_DATAEN=0 Data Disable + * QSPI_IFR_OPTL_* Not used (zero) + * QSPI_IFR_ADDRL=0 Not used (zero) + * QSPI_IFR_TFRTYP_READ Shouldn't matter + * QSPI_IFR_CRM=0 Not continuous read + * QSPI_IFR_NBDUM(0) No dummy cycles + */ + + ifr = QSPI_IFR_WIDTH_SINGLE | QSPI_IFR_INSTEN | QSPI_IFR_TFRTYP_READ | + QSPI_IFR_NBDUM(0); + qspi_putreg(priv, ifr, SAM_QSPI_IFR_OFFSET); + + MEMORY_SYNC(); + } /* When the command has been sent, Instruction End Status (INTRE) will be * set in the QSPI status register. @@ -1061,172 +1163,6 @@ static int qspi_command(struct qspi_dev_s *dev, uint16_t cmd) return OK; } -/**************************************************************************** - * Name: qspi_command_write - * - * Description: - * Send a command then send a block of data. - * - * Input Parameters: - * dev - Device-specific state data - * cmd - The command to send. the size of the data is determined by - * the number of bits selected for the QSPI interface. - * buffer - A pointer to the buffer of data to be sent - * buflen - the length of data to send from the buffer in number of words. - * The wordsize is determined by the number of bits-per-word - * selected for the QSPI interface. If nbits <= 8, the data is - * packed into uint8_t's; if nbits >8, the data is packed into - * uint16_t's - * - * Returned Value: - * Zero (OK) on SUCCESS, a negated errno on value of failure - * - ****************************************************************************/ - -static int qspi_command_write(struct qspi_dev_s *dev, uint16_t cmd, - const void *buffer, size_t buflen) -{ - struct sam_qspidev_s *priv = (struct sam_qspidev_s *)dev; - uint32_t regval; - - spivdbg("cmd: %04x buflen: %lu\n", cmd, (unsigned long)buflen); - DEBUGASSERT(priv != NULL && cmd < 256 && buffer != NULL;); - - /* Make sure that the length is an even multiple of 32-bit words. */ - - DEBUGASSERT((buflen & 3) == 0); - buflen = (buflen + 3) & ~3; - - /* Write the the Instruction code register: - * - * QSPI_ICR_INST(cmd) 8-bit command - * QSPI_ICR_OPT(0) No option - */ - - regval = QSPI_ICR_INST(cmd) | QSPI_ICR_OPT(0); - qspi_putreg(priv, regval, SAM_QSPI_ICR_OFFSET); - - /* Write Instruction Frame Register: - * - * QSPI_IFR_WIDTH_SINGLE Instruction=single bit - * QSPI_IFR_INSTEN=1 Instruction Enable - * QSPI_IFR_ADDREN=0 Address Disable - * QSPI_IFR_OPTEN=0 Option Disable - * QSPI_IFR_DATAEN=1 Data Enable - * QSPI_IFR_OPTL_* Not used (zero) - * QSPI_IFR_ADDRL=0 Not used (zero) - * QSPI_IFR_TFRTYP_WRITE Write transfer into serial memory - * QSPI_IFR_CRM=0 Not continuous read - * QSPI_IFR_NBDUM(0) No dummy cycles - */ - - regval = QSPI_IFR_WIDTH_SINGLE | QSPI_IFR_INSTEN | QSPI_IFR_DATAEN | - QSPI_IFR_TFRTYP_WRITE | QSPI_IFR_NBDUM(0); - qspi_putreg(priv, regval, SAM_QSPI_IFR_OFFSET); - - (void)qspi_getreg(priv, SAM_QSPI_IFR_OFFSET); - - /* Copy the data to write to QSPI_RAM */ - - memcpy((void *)SAM_QSPIMEM_BASE, buffer, buflen); - MEMORY_SYNC(); - - /* Indicate the end of the transfer as soon as the transmission - * registers are empty. - */ - - while ((qspi_getreg(priv, SAM_QSPI_SR_OFFSET) & QSPI_INT_TXEMPTY) == 0); - qspi_putreg(priv, QSPI_CR_LASTXFER, SAM_QSPI_CR_OFFSET); - - /* Wait for the end of the transfer */ - - while ((qspi_getreg(priv, SAM_QSPI_SR_OFFSET) & QSPI_SR_INSTRE) == 0); - return OK; -} - -/**************************************************************************** - * Name: qspi_command_read - * - * Description: - * Receive a block of data from QSPI. Required. - * - * Input Parameters: - * dev - Device-specific state data - * cmd - The command to send. the size of the data is determined by - * the number of bits selected for the QSPI interface. - * buffer - A pointer to the buffer in which to receive data - * buflen - the length of data that can be received in the buffer in number - * of words. The wordsize is determined by the number of bits- - * per-word selected for the QSPI interface. If nbits <= 8, the - * data is packed into uint8_t's; if nbits >8, the data is packed - * into uint16_t's - * - * Returned Value: - * Zero (OK) on SUCCESS, a negated errno on value of failure - * - ****************************************************************************/ - -static int qspi_command_read(struct qspi_dev_s *dev, uint16_t cmd, - void *buffer, size_t buflen) -{ - struct sam_qspidev_s *priv = (struct sam_qspidev_s *)dev; - uint32_t regval; - - spivdbg("cmd: %04x buflen: %lu\n", cmd, (unsigned long)buflen); - DEBUGASSERT(priv != NULL && cmd < 256 && buffer != NULL;); - - /* Make sure that the length is an even multiple of 32-bit words. */ - - DEBUGASSERT((buflen & 3) == 0); - buflen = (buflen + 3) & ~3; - - /* Write the the Instruction code register: - * - * QSPI_ICR_INST(cmd) 8-bit command - * QSPI_ICR_OPT(0) No option - */ - - regval = QSPI_ICR_INST(cmd) | QSPI_ICR_OPT(0); - qspi_putreg(priv, regval, SAM_QSPI_ICR_OFFSET); - - /* Write Instruction Frame Register: - * - * QSPI_IFR_WIDTH_SINGLE Instruction=single bit - * QSPI_IFR_INSTEN=1 Instruction Enable - * QSPI_IFR_ADDREN=0 Address Disable - * QSPI_IFR_OPTEN=0 Option Disable - * QSPI_IFR_DATAEN=1 Data Enable - * QSPI_IFR_OPTL_* Not used (zero) - * QSPI_IFR_ADDRL=0 Not used (zero) - * QSPI_IFR_TFRTYP_READ Read transfer from serial memory - * QSPI_IFR_CRM=0 Not continuous read - * QSPI_IFR_NBDUM(0) No dummy cycles - */ - - regval = QSPI_IFR_WIDTH_SINGLE | QSPI_IFR_INSTEN | QSPI_IFR_DATAEN | - QSPI_IFR_TFRTYP_READ | QSPI_IFR_NBDUM(0); - qspi_putreg(priv, regval, SAM_QSPI_IFR_OFFSET); - - (void)qspi_getreg(priv, SAM_QSPI_IFR_OFFSET); - - /* Copy the data from QSPI memory into the user buffer */ - - memcpy(buffer, (const void *)SAM_QSPIMEM_BASE, buflen); - MEMORY_SYNC(); - - /* Indicate the end of the transfer as soon as the transmission - * registers are empty. - */ - - while ((qspi_getreg(priv, SAM_QSPI_SR_OFFSET) & QSPI_INT_TXEMPTY) == 0); - qspi_putreg(priv, QSPI_CR_LASTXFER, SAM_QSPI_CR_OFFSET); - - /* Wait for the end of the transfer */ - - while ((qspi_getreg(priv, SAM_QSPI_SR_OFFSET) & QSPI_SR_INSTRE) == 0); - return OK; -} - /**************************************************************************** * Name: qspi_hw_initialize * @@ -1321,9 +1257,9 @@ static int qspi_hw_initialize(struct sam_qspidev_s *priv) * ****************************************************************************/ -FAR struct qspi_dev_s *sam_qspi_initialize(int intf) +struct qspi_dev_s *sam_qspi_initialize(int intf) { - FAR struct sam_qspidev_s *priv; + struct sam_qspidev_s *priv; int ret; /* The support SAM parts have only a single QSPI port */