[PATCH V7 2/2] mtd: spi-nor: Add driver for Cadence Quad SPI Flash Controller.
Vikas MANOCHA
vikas.manocha at st.com
Fri Aug 21 00:09:13 PDT 2015
Hi,
> On Aug 20, 2015, at 10:20 PM, Marek Vasut <marex at denx.de> wrote:
>
>> On Tuesday, August 18, 2015 at 04:34:53 AM, vikas wrote:
>> Hi Marek,
>
> Hi,
>
> [...]
>
>>> +#define CQSPI_POLL_IDLE_RETRY 3
>>> +
>>> +#define CQSPI_REG_SRAM_RESV_WORDS 2
>>> +#define CQSPI_REG_SRAM_PARTITION_WR 1
>>
>> remove unused macros.
>>
>>> +#define CQSPI_REG_SRAM_THRESHOLD_BYTES 50
>>
>> the macro is used only for write sram watermark, something like
>> ...WR_THRESH_BYTES would be better. Infact instead of magic number like
>> 50, it should be based on sram_depth similar to read watermark
>> configuration.
>
> I suppose if the fifo falls below 1/8, that might be a sensible time to
> trigger an underflow interrupt.
>
>>> +
>>> +/* Instruction type */
>>> +#define CQSPI_INST_TYPE_SINGLE 0
>>> +#define CQSPI_INST_TYPE_DUAL 1
>>> +#define CQSPI_INST_TYPE_QUAD 2
>>> +
>>> +#define CQSPI_DUMMY_CLKS_MAX 31
>>> +
>>> +#define CQSPI_STIG_DATA_LEN_MAX 8
>>> +
>>> +/* Register map */
>>> +#define CQSPI_REG_CONFIG 0x00
>>> +#define CQSPI_REG_CONFIG_ENABLE_MASK BIT(0)
>>> +#define CQSPI_REG_CONFIG_DECODE_MASK BIT(9)
>>> +#define CQSPI_REG_CONFIG_CHIPSELECT_LSB 10
>>> +#define CQSPI_REG_CONFIG_DMA_MASK BIT(15)
>>> +#define CQSPI_REG_CONFIG_BAUD_LSB 19
>>> +#define CQSPI_REG_CONFIG_IDLE_LSB 31
>>
>> To be consistent, it would be good to use BIT(nr) for all bit positions.
>
> You don't use BIT() macro for bitfields and the above are bitfields.
> Thus, this is not applicable.
>
>>> +#define CQSPI_REG_CONFIG_CHIPSELECT_MASK 0xF
>>> +#define CQSPI_REG_CONFIG_BAUD_MASK 0xF
>
> [...]
>
>>> +#define CQSPI_REG_CMDADDRESS 0x94
>>> +#define CQSPI_REG_CMDREADDATALOWER 0xA0
>>> +#define CQSPI_REG_CMDREADDATAUPPER 0xA4
>>> +#define CQSPI_REG_CMDWRITEDATALOWER 0xA8
>>> +#define CQSPI_REG_CMDWRITEDATAUPPER 0xAC
>>
>> I am not sure if there is any recommended way but instread of register
>> macros with offset, isn't it better to use something like struct cdns_qspi
>> {
>> u32 config,
>> u32 rd_instn,
>> ....
>> };
>> & then configuring the pointer to this structure to the peripheral's (qspi
>> controller in this case) base address.
>
> U-Boot is slowly abolishing this practice as it turned out to be a horrible
> mistake, which is annoying to deal with . No, I will not do this.
>
>> It helps in debugging also as you can have all registers under one
>> structure, easy/clean access of register like cdsn_qspi_ptr->config
>> instead of adding offset for every access & also clean picture of all
>> peripheral registers.
>
> Once you have three similar controllers with only one register mapped
> elsewhere, you'd need three such structures. This approach does look
> nice at first, but certainly does not scale.
>
>>> +
>>> +/* Interrupt status bits */
>>> +#define CQSPI_REG_IRQ_MODE_ERR BIT(0)
>>> +#define CQSPI_REG_IRQ_UNDERFLOW BIT(1)
>>> +#define CQSPI_REG_IRQ_IND_COMP BIT(2)
>>> +#define CQSPI_REG_IRQ_IND_RD_REJECT BIT(3)
>>> +#define CQSPI_REG_IRQ_WR_PROTECTED_ERR BIT(4)
>>> +#define CQSPI_REG_IRQ_ILLEGAL_AHB_ERR BIT(5)
>>> +#define CQSPI_REG_IRQ_WATERMARK BIT(6)
>>> +#define CQSPI_REG_IRQ_IND_RD_OVERFLOW BIT(12)
>
> [...]
>
>>> +
>>> +static unsigned int cqspi_check_timeout(const unsigned long timeout)
>>> +{
>>> + return time_before(jiffies, timeout);
>>> +}
>>
>> try to replace using blocking jiffies check using kernel timeout function.
>
> What function do you refer to ?
>
> [...]
>
>>> +static int cqspi_indirect_read_execute(struct spi_nor *nor,
>>> + u8 *rxbuf, const unsigned n_rx)
>>> +{
>>> + struct cqspi_flash_pdata *f_pdata = nor->priv;
>>> + struct cqspi_st *cqspi = f_pdata->cqspi;
>>> + void __iomem *reg_base = cqspi->iobase;
>>> + void __iomem *ahb_base = cqspi->ahb_base;
>>> + unsigned int remaining = n_rx;
>>> + unsigned int reg = 0;
>>> + unsigned int bytes_to_read = 0;
>>> + unsigned int timeout;
>>> + int ret = 0;
>>> +
>>> + writel(remaining, reg_base + CQSPI_REG_INDIRECTRDBYTES);
>>> +
>>> + /* Clear all interrupts. */
>>> + writel(CQSPI_IRQ_STATUS_MASK, reg_base + CQSPI_REG_IRQSTATUS);
>>> +
>>> + cqspi->irq_mask = CQSPI_IRQ_MASK_RD;
>>> + writel(cqspi->irq_mask, reg_base + CQSPI_REG_IRQMASK);
>>
>> here interrupt mask is being configured for every read, better would be to
>> move it in init.
>
> It certainly would not, it is configured differently for READ and WRITE.
And what is blocking to configure read and write mask together at one time in the register ?
>
>>> +
>>> + reinit_completion(&cqspi->transfer_complete);
>>> + writel(CQSPI_REG_INDIRECTRD_START_MASK,
>>> + reg_base + CQSPI_REG_INDIRECTRD);
>>> +
>>> + while (remaining > 0) {
>>> + ret =
>
> [...]
>
>>> +static void cqspi_controller_init(struct cqspi_st *cqspi)
>>> +{
>>> + cqspi_controller_disable(cqspi);
>>> +
>>> + /* Configure the remap address register, no remap */
>>> + writel(0, cqspi->iobase + CQSPI_REG_REMAP);
>>> +
>>> + /* Disable all interrupts. */
>>> + writel(0, cqspi->iobase + CQSPI_REG_IRQMASK);
>>> +
>>> + /* Configure the SRAM split to 1:1 . */
>>> + writel(cqspi->fifo_depth / 2, cqspi->iobase +
>>> CQSPI_REG_SRAMPARTITION); +
>>> + /* Load indirect trigger address. */
>>
>> almost all comments of this function seems unnecessary.
>
> I disagree, having sensible comments in code makes my life easier after
> I have to revisit the code a few years later.
Yes for sensible comments , you are loading value in one register and commenting it.
Cheers,
Vikas
>
>>> + writel(cqspi->trigger_address,
>>> + cqspi->iobase + CQSPI_REG_INDIRECTTRIGGER);
>>> +
>>> + /* Program read and write watermark. */
>>> + writel(cqspi->fifo_depth * cqspi->fifo_width / 2,
>>> + cqspi->iobase + CQSPI_REG_INDIRECTRDWATERMARK);
>>> + writel(CQSPI_REG_SRAM_THRESHOLD_BYTES,
>>> + cqspi->iobase + CQSPI_REG_INDIRECTWRWATERMARK);
>
> [...]
>
> Best regards,
More information about the linux-mtd
mailing list