Le 06/12/2016 à 07:54, Naga Sureshkumar Relli a écrit :
> Hi Cyrille,
> 
>> -----Original Message-----
>> From: Cyrille Pitchen [mailto:cyrille.pitc...@atmel.com]
>> Sent: Monday, December 05, 2016 6:34 PM
>> To: Naga Sureshkumar Relli <nagas...@xilinx.com>; broo...@kernel.org;
>> michal.si...@xilinx.com; Soren Brinkmann <sor...@xilinx.com>; Harini
>> Katakam <hari...@xilinx.com>; Punnaiah Choudary Kalluri
>> <punn...@xilinx.com>
>> Cc: linux-...@vger.kernel.org; linux-arm-ker...@lists.infradead.org; linux-
>> ker...@vger.kernel.org; linux-...@lists.infradead.org
>> Subject: Re: [LINUX RFC v4 3/4] mtd: spi-nor: add stripe support
>>
>> Hi Naga,
>>
>> Le 05/12/2016 à 08:02, Naga Sureshkumar Relli a écrit :
>>> Hi Cyrille,
>>>
>>>>> Hi Cyrille,
>>>>>
>>>>>> I have not finished to review the whole series yet but here some
>>>>>> first
>>>>>> comments:
>>>>>
>>>>> Thanks for reviewing these patch series.
>>>>>
>>>>>>
>>>>>> Le 27/11/2016 à 09:33, Naga Sureshkumar Relli a écrit :
>>>>>>> This patch adds stripe support and it is needed for GQSPI parallel
>>>>>>> configuration mode by:
>>>>>>>
>>>>>>> - Adding required parameters like stripe and shift to spi_nor
>>>>>>>   structure.
>>>>>>> - Initializing all added parameters in spi_nor_scan()
>>>>>>> - Updating read_sr() and read_fsr() for getting status from both
>>>>>>>   flashes
>>>>>>> - Increasing page_size, sector_size, erase_size and toatal flash
>>>>>>>   size as and when required.
>>>>>>> - Dividing address by 2
>>>>>>> - Updating spi->master->flags for qspi driver to change CS
>>>>>>>
>>>>>>> Signed-off-by: Naga Sureshkumar Relli <nagas...@xilinx.com>
>>>>>>> ---
>>>>>>> Changes for v4:
>>>>>>>  - rename isparallel to stripe
>>>>>>> Changes for v3:
>>>>>>>  - No change
>>>>>>> Changes for v2:
>>>>>>>  - Splitted to separate MTD layer changes from SPI core changes
>>>>>>> ---
>>>>>>>  drivers/mtd/spi-nor/spi-nor.c | 130
>>>>>> ++++++++++++++++++++++++++++++++----------
>>>>>>>  include/linux/mtd/spi-nor.h   |   2 +
>>>>>>>  2 files changed, 103 insertions(+), 29 deletions(-)
>>>>>>>
>>>>>>> diff --git a/drivers/mtd/spi-nor/spi-nor.c
>>>>>>> b/drivers/mtd/spi-nor/spi-nor.c index d0fc165..4252239 100644
>>>>>>> --- a/drivers/mtd/spi-nor/spi-nor.c
>>>>>>> +++ b/drivers/mtd/spi-nor/spi-nor.c
>>>>>>> @@ -22,6 +22,7 @@
>>>>>>>  #include <linux/of_platform.h>
>>>>>>>  #include <linux/spi/flash.h>
>>>>>>>  #include <linux/mtd/spi-nor.h>
>>>>>>> +#include <linux/spi/spi.h>
>>>>>>>
>>>>>>>  /* Define max times to check status register before we give up.
>>>>>>> */
>>>>>>>
>>>>>>> @@ -89,15 +90,24 @@ static const struct flash_info
>>>>>>> *spi_nor_match_id(const char *name);  static int read_sr(struct
>>>>>>> spi_nor *nor)  {
>>>>>>>   int ret;
>>>>>>> - u8 val;
>>>>>>> + u8 val[2];
>>>>>>>
>>>>>>> - ret = nor->read_reg(nor, SPINOR_OP_RDSR, &val, 1);
>>>>>>> - if (ret < 0) {
>>>>>>> -         pr_err("error %d reading SR\n", (int) ret);
>>>>>>> -         return ret;
>>>>>>> + if (nor->stripe) {
>>>>>>> +         ret = nor->read_reg(nor, SPINOR_OP_RDSR, &val[0], 2);
>>>>>>> +         if (ret < 0) {
>>>>>>> +                 pr_err("error %d reading SR\n", (int) ret);
>>>>>>> +                 return ret;
>>>>>>> +         }
>>>>>>> +         val[0] |= val[1];
>>>>>> Why '|' rather than '&' ?
>>>>>> I guess because of the 'Write In Progress/Busy' bit: when called by
>>>>>> spi_nor_sr_ready(), you want to be sure that this 'BUSY' bit is
>>>>>> cleared on both memories.
>>>>>>
>>>>>> But what about when the Status Register is read for purpose other
>>>>>> than checking the state of the 'BUSY' bit?
>>>>>>
>>>>> Yes you are correct, I will change this.
>>>>>
>>>>>> What about SPI controllers supporting more than 2 memories in
>> parallel?
>>>>>>
>>>>>> This solution might fit the ZynqMP controller but doesn't look so
>> generic.
>>>>>>
>>>>>>> + } else {
>>>>>>> +         ret = nor->read_reg(nor, SPINOR_OP_RDSR, &val[0], 1);
>>>>>>> +         if (ret < 0) {
>>>>>>> +                 pr_err("error %d reading SR\n", (int) ret);
>>>>>>> +                 return ret;
>>>>>>> +         }
>>>>>>>   }
>>>>>>>
>>>>>>> - return val;
>>>>>>> + return val[0];
>>>>>>>  }
>>>>>>>
>>>>>>>  /*
>>>>>>> @@ -108,15 +118,24 @@ static int read_sr(struct spi_nor *nor)
>>>>>>> static int read_fsr(struct spi_nor *nor)  {
>>>>>>>   int ret;
>>>>>>> - u8 val;
>>>>>>> + u8 val[2];
>>>>>>>
>>>>>>> - ret = nor->read_reg(nor, SPINOR_OP_RDFSR, &val, 1);
>>>>>>> - if (ret < 0) {
>>>>>>> -         pr_err("error %d reading FSR\n", ret);
>>>>>>> -         return ret;
>>>>>>> + if (nor->stripe) {
>>>>>>> +         ret = nor->read_reg(nor, SPINOR_OP_RDFSR, &val[0], 2);
>>>>>>> +         if (ret < 0) {
>>>>>>> +                 pr_err("error %d reading FSR\n", ret);
>>>>>>> +                 return ret;
>>>>>>> +         }
>>>>>>> +         val[0] &= val[1];
>>>>>> Same comment here: why '&' rather than '|'?
>>>>>> Surely because of the the 'READY' bit which should be set for both
>>>> memories.
>>>>> I will update this also.
>>>>>>
>>>>>>> + } else {
>>>>>>> +         ret = nor->read_reg(nor, SPINOR_OP_RDFSR, &val[0], 1);
>>>>>>> +         if (ret < 0) {
>>>>>>> +                 pr_err("error %d reading FSR\n", ret);
>>>>>>> +                 return ret;
>>>>>>> +         }
>>>>>>>   }
>>>>>>>
>>>>>>> - return val;
>>>>>>> + return val[0];
>>>>>>>  }
>>>>>>>
>>>>>>>  /*
>>>>>>> @@ -290,9 +309,16 @@ static int spi_nor_wait_till_ready(struct
>>>>>>> spi_nor
>>>>>> *nor)
>>>>>>>   */
>>>>>>>  static int erase_chip(struct spi_nor *nor)  {
>>>>>>> + u32 ret;
>>>>>>> +
>>>>>>>   dev_dbg(nor->dev, " %lldKiB\n", (long long)(nor->mtd.size >>
>>>>>>> 10));
>>>>>>>
>>>>>>> - return nor->write_reg(nor, SPINOR_OP_CHIP_ERASE, NULL, 0);
>>>>>>> + ret = nor->write_reg(nor, SPINOR_OP_CHIP_ERASE, NULL, 0); if
>>>>>>> + (ret)
>>>>>>> +         return ret;
>>>>>>> +
>>>>>>> + return ret;
>>>>>>> +
>>>>>>
>>>>>>    if (ret)
>>>>>>            return ret;
>>>>>>    else
>>>>>>            return ret;
>>>>>>
>>>>>> This chunk should be removed, it doesn't ease the patch review ;)
>>>>> Ok, I will remove.
>>>>>>
>>>>>>>  }
>>>>>>>
>>>>>>>  static int spi_nor_lock_and_prep(struct spi_nor *nor, enum
>>>>>>> spi_nor_ops ops) @@ -349,7 +375,7 @@ static int
>>>>>>> spi_nor_erase_sector(struct spi_nor *nor, u32 addr)  static int
>>>>>>> spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr)  {
>>>>>>>   struct spi_nor *nor = mtd_to_spi_nor(mtd);
>>>>>>> - u32 addr, len;
>>>>>>> + u32 addr, len, offset;
>>>>>>>   uint32_t rem;
>>>>>>>   int ret;
>>>>>>>
>>>>>>> @@ -399,9 +425,13 @@ static int spi_nor_erase(struct mtd_info
>>>>>>> *mtd,
>>>>>> struct erase_info *instr)
>>>>>>>   /* "sector"-at-a-time erase */
>>>>>>>   } else {
>>>>>>>           while (len) {
>>>>>>> +
>>>>>>>                   write_enable(nor);
>>>>>>> +                 offset = addr;
>>>>>>> +                 if (nor->stripe)
>>>>>>> +                         offset /= 2;
>>>>>>
>>>>>> I guess this should be /= 4 for controllers supporting 4 memories
>>>>>> in
>>>> parallel.
>>>>>> Shouldn't you use nor->shift and define shift as an unsigned int
>>>>>> instead of a bool?
>>>>>> offset >>= nor->shift;
>>>>>>
>>>>> Yes we can use this shift, I will update
>>>>>
>>>>>> Anyway, by tuning the address here in spi-nor.c rather than in the
>>>>>> SPI controller driver, you impose a model to support parallel
>>>>>> memories that might not be suited to other controllers.
>>>>>
>>>>> For this ZynqMP GQSPI controller parallel configuration, globally
>>>>> spi-nor should know about this stripe feature And based on that
>>>>> address
>>>> has to change.
>>>>> As I mentioned in cover letter, this controller in parallel
>>>>> configuration will
>>>> work with even addresses only.
>>>>> i.e. Before creating address format(m25p_addr2cmd) in mtd layer,
>>>>> spi-nor
>>>> should change that address based on stripe option.
>>>>>
>>>>> I am updating this offset based on stripe option, and stripe option
>>>>> will
>>>> update by reading dt property in nor_scan().
>>>>> So the controller which doesn't support, then the stripe will be zero.
>>>>> Or Can you please suggest any other way?
>>>>>
>>>>>>
>>>>>>>
>>>>>>> -                 ret = spi_nor_erase_sector(nor, addr);
>>>>>>> +                 ret = spi_nor_erase_sector(nor, offset);
>>>>>>>                   if (ret)
>>>>>>>                           goto erase_err;
>>>>>>>
>>>>>>> @@ -525,6 +555,8 @@ static int stm_lock(struct spi_nor *nor,
>>>>>>> loff_t ofs,
>>>>>> uint64_t len)
>>>>>>>   bool use_top;
>>>>>>>   int ret;
>>>>>>>
>>>>>>> + ofs = ofs >> nor->shift;
>>>>>>> +
>>>>>>>   status_old = read_sr(nor);
>>>>>>>   if (status_old < 0)
>>>>>>>           return status_old;
>>>>>>> @@ -610,6 +642,8 @@ static int stm_unlock(struct spi_nor *nor,
>>>>>>> loff_t ofs,
>>>>>> uint64_t len)
>>>>>>>   bool use_top;
>>>>>>>   int ret;
>>>>>>>
>>>>>>> + ofs = ofs >> nor->shift;
>>>>>>> +
>>>>>>>   status_old = read_sr(nor);
>>>>>>>   if (status_old < 0)
>>>>>>>           return status_old;
>>>>>>> @@ -709,6 +743,8 @@ static int spi_nor_lock(struct mtd_info *mtd,
>>>>>>> loff_t
>>>>>> ofs, uint64_t len)
>>>>>>>   if (ret)
>>>>>>>           return ret;
>>>>>>>
>>>>>>> + ofs = ofs >> nor->shift;
>>>>>>> +
>>>>>>>   ret = nor->flash_lock(nor, ofs, len);
>>>>>>>
>>>>>>>   spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_UNLOCK); @@ -
>>>>>> 724,6 +760,8
>>>>>>> @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs,
>>>>>>> uint64_t
>>>>>> len)
>>>>>>>   if (ret)
>>>>>>>           return ret;
>>>>>>>
>>>>>>> + ofs = ofs >> nor->shift;
>>>>>>> +
>>>>>>>   ret = nor->flash_unlock(nor, ofs, len);
>>>>>>>
>>>>>>>   spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK); @@ -
>>>>>> 1018,6 +1056,9
>>>>>>> @@ static const struct flash_info *spi_nor_read_id(struct spi_nor
>> *nor)
>>>>>>>   u8                      id[SPI_NOR_MAX_ID_LEN];
>>>>>>>   const struct flash_info *info;
>>>>>>>
>>>>>>> + nor->spi->master->flags &= ~(SPI_MASTER_BOTH_CS |
>>>>>>> +                                 SPI_MASTER_DATA_STRIPE);
>>>>>>> +
>>>>>>>   tmp = nor->read_reg(nor, SPINOR_OP_RDID, id,
>>>>>> SPI_NOR_MAX_ID_LEN);
>>>>>>>   if (tmp < 0) {
>>>>>>>           dev_dbg(nor->dev, "error %d reading JEDEC ID\n", tmp);
>>>>>> @@ -1041,6
>>>>>>> +1082,7 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t
>>>>>>> +from,
>>>>>>> size_t len,  {
>>>>>>>   struct spi_nor *nor = mtd_to_spi_nor(mtd);
>>>>>>>   int ret;
>>>>>>> + u32 offset = from;
>>>>>>>
>>>>>>>   dev_dbg(nor->dev, "from 0x%08x, len %zd\n", (u32)from, len);
>>>>>>>
>>>>>>> @@ -1049,7 +1091,13 @@ static int spi_nor_read(struct mtd_info
>>>>>>> *mtd,
>>>>>> loff_t from, size_t len,
>>>>>>>           return ret;
>>>>>>>
>>>>>>>   while (len) {
>>>>>>> -         ret = nor->read(nor, from, len, buf);
>>>>>>> +
>>>>>>> +         offset = from;
>>>>>>> +
>>>>>>> +         if (nor->stripe)
>>>>>>> +                 offset /= 2;
>>>>>>> +
>>>>>>> +         ret = nor->read(nor, offset, len, buf);
>>>>>>>           if (ret == 0) {
>>>>>>>                   /* We shouldn't see 0-length reads */
>>>>>>>                   ret = -EIO;
>>>>>>> @@ -1161,6 +1209,7 @@ static int spi_nor_write(struct mtd_info
>>>>>>> *mtd,
>>>>>> loff_t to, size_t len,
>>>>>>>   struct spi_nor *nor = mtd_to_spi_nor(mtd);
>>>>>>>   size_t page_offset, page_remain, i;
>>>>>>>   ssize_t ret;
>>>>>>> + u32 offset;
>>>>>>>
>>>>>>>   dev_dbg(nor->dev, "to 0x%08x, len %zd\n", (u32)to, len);
>>>>>>>
>>>>>>> @@ -1178,9 +1227,13 @@ static int spi_nor_write(struct mtd_info
>>>>>>> *mtd,
>>>>>> loff_t to, size_t len,
>>>>>>>           /* the size of data remaining on the first page */
>>>>>>>           page_remain = min_t(size_t,
>>>>>>>                               nor->page_size - page_offset, len -
>>>>>>> i);
>>>>>>> +         offset = (to + i);
>>>>>>> +
>>>>>>> +         if (nor->stripe)
>>>>>>> +                 offset /= 2;
>>>>>>>
>>>>>>>           write_enable(nor);
>>>>>>> -         ret = nor->write(nor, to + i, page_remain, buf + i);
>>>>>>> +         ret = nor->write(nor, (offset), page_remain, buf + i);
>>>>>>>           if (ret < 0)
>>>>>>>                   goto write_err;
>>>>>>>           written = ret;
>>>>>>> @@ -1302,22 +1355,22 @@ static int spi_nor_check(struct spi_nor
>>>>>>> *nor)
>>>>>>>
>>>>>>>  int spi_nor_scan(struct spi_nor *nor, const char *name, enum
>>>>>>> read_mode mode)  {
>>>>>>> - const struct flash_info *info = NULL;
>>>>>>> + struct flash_info *info = NULL;
>>>>>>
>>>>>> You should not remove the const and should not try to modify
>>>>>> members of *info.
>>>>>>
>>>>>>>   struct device *dev = nor->dev;
>>>>>>>   struct mtd_info *mtd = &nor->mtd;
>>>>>>>   struct device_node *np = spi_nor_get_flash_node(nor);
>>>>>>> - int ret;
>>>>>>> - int i;
>>>>>>> + struct device_node *np_spi;
>>>>>>> + int ret, i, xlnx_qspi_mode;
>>>>>>>
>>>>>>>   ret = spi_nor_check(nor);
>>>>>>>   if (ret)
>>>>>>>           return ret;
>>>>>>>
>>>>>>>   if (name)
>>>>>>> -         info = spi_nor_match_id(name);
>>>>>>> +         info = (struct flash_info *)spi_nor_match_id(name);
>>>>>>>   /* Try to auto-detect if chip name wasn't specified or not found */
>>>>>>>   if (!info)
>>>>>>> -         info = spi_nor_read_id(nor);
>>>>>>> +         info = (struct flash_info *)spi_nor_read_id(nor);
>>>>>>>   if (IS_ERR_OR_NULL(info))
>>>>>>>           return -ENOENT;
>>>>>>>
>>>>>> Both spi_nor_match_id() and spi_nor_read_id(), when they succeed,
>>>>>> return a pointer to an entry of the spi_nor_ids[] array, which is
>>>>>> located in a read- only memory area.
>>>>>>
>>>>>> Since your patch doesn't remove the const attribute of the
>>>>>> spi_nor_ids[], I wonder whether it has been tested. I expect it not
>>>>>> to work on most architecture.
>>>>>>
>>>>>> Anyway spi_nor_ids[] should remain const. Let's take the case of
>>>>>> eXecution In Place (XIP) from an external memory: if spi_nor_ids[]
>>>>>> is const, it can be read directly from this external (read-only)
>>>>>> memory and we never need to copy the array in RAM, so we save
>> some
>>>>>> KB of
>>>> RAM.
>>>>>> This is just an example but I guess we can find other reasons to
>>>>>> keep this array const.
>>>>>>
>>>>>>> @@ -1341,7 +1394,7 @@ int spi_nor_scan(struct spi_nor *nor, const
>>>>>>> char
>>>>>> *name, enum read_mode mode)
>>>>>>>                    */
>>>>>>>                   dev_warn(dev, "found %s, expected %s\n",
>>>>>>>                            jinfo->name, info->name);
>>>>>>> -                 info = jinfo;
>>>>>>> +                 info = (struct flash_info *)jinfo;
>>>>>>>           }
>>>>>>>   }
>>>>>>>
>>>>>>> @@ -1370,6 +1423,27 @@ int spi_nor_scan(struct spi_nor *nor, const
>>>>>>> char
>>>>>> *name, enum read_mode mode)
>>>>>>>   mtd->size = info->sector_size * info->n_sectors;
>>>>>>>   mtd->_erase = spi_nor_erase;
>>>>>>>   mtd->_read = spi_nor_read;
>>>>>>> +#ifdef CONFIG_OF
>>>>>>> + np_spi = of_get_next_parent(np);
>>>>>>> +
>>>>>>> + if (of_property_read_u32(np_spi, "xlnx,qspi-mode",
>>>>>>> +                         &xlnx_qspi_mode) < 0) {
>>>>>> This really looks controller specific so should not be placed in
>>>>>> the generic spi- nor.c file.
>>>>>
>>>>> Const is removed in info struct, because to update info members
>>>>> based
>>>> parallel configuration.
>>>>> As I mentioned above,  for this parallel configuration, mtd and
>>>>> spi-nor should know the details like
>>>>> mtd->size, info->sectors, sector_size and page_size.
>>>>
>>>> You can tune the values of nor->mtd.size, nor->mtd.erasesize, nor-
>>>>> page_size or whatever member of nor/nor.mtd as needed without ever
>>>> modifying members of *info.
>>>>
>>>> If you modify *info then spi_nor_scan() is called a 2nd time to probe
>>>> and configure SPI memories of the same part but connected to another
>>>> controller, the values of the modified members in this *info would
>>>> not be those expected.
>>>> So *info and the spi_nor_ids[] array must remain const.
>>>>
>>>> The *info structure is not used outside spi_nor_scan(); none of
>>>> spi_nor_read(),
>>>> spi_nor_write() and spi_nor_erase() refers to *info hence every
>>>> relevant value can be set only nor or nor->mtd members.
>>>>
>>>>
>>>> Anyway, I think OR'ing or AND'ing values of memory registers
>>>> depending on the relevant bit we want to check is not the right solution.
>>>> If done in spi-nor.c, there would be a specific case for each memory
>>>> register we read, each register bit would have to be handled differently.
>>>>
>>>> spi-nor.c tries to support as much memory parts as possible, it deals
>>>> with many registers and bits: Status/Control registers, Quad Enable bits...
>>>>
>>>> If we start to OR or AND each of these register values to support the
>>>> stripping mode, spi-nor will become really hard to maintain.
>>>>
>>>> I don't know whether it could be done with the xilinx controller but
>>>> I thought about first configuring the two memories independently
>>>> calling
>>>> spi_nor_scan() twice; one call for each memory.
>>>>
>>>> Then the xilinx driver could register only one struct mtd_info,
>>>> overriding
>>>> mtd->_read() [and likely mtd->_write() and mtd->_erase() too] set by
>>>> spi_nor_scan() with a xilinx driver custom implementation so this
>>>> driver supports its controller stripping mode as it wants.
>>>>
>>>> Of course, this solution assumes that the SPI controller has one
>>>> dedicated chip-select line for each memory and not a single
>>>> chip-select line shared by both memories. The memories should be
>>>> configured independently: you can't assume multiple instances of the
>>>> very same memory part always return the exact same value when reading
>>>> one of their register. Logical AND/OR is not a generic solution, IMHO.
>>>>
>>>> If the xilinx controller has only one shared chip-select line then
>>>> let's see whether 2 GPIO lines could be used as independent chip-select
>> lines.
>>>>
>>>>
>>> In parallel configuration, Physically we have two flashes but mtd will
>>> see as single flash memory (sum of both memories) If we call
>> spi_nor_scan(), twice then read/write will override but nor->mtd.size, nor-
>>> mtd.erasesize, nor->page_size  will remain same, I,e they will also 
>>> override,
>> they won't append.
>>> I tried calling spi_nor_scan() twice by some hacks but nor->mtd.size,
>>> nor->mtd.erasesize, nor->page_size are not changing Also the same issue
>> we are getting for flash address, need to shift the address to work in this
>> configuration.
>>> Also to tune  nor->mtd.size, nor->mtd.erasesize, nor->page_size, we
>>> need to touch this spi-nor.c
>>>
>>> Please kindly suggest, if I am wrong.
>>>
>>
>> What I've been suggesting is:
>>
>> {
>>       struct spi_nor *nor1, *nor2;
>>       struct mtd_info *mtd;
>>       enum read_mode mode = SPI_NOR_QUAD;
>>       int err;
>>
>>       [...]
>>
>>       err = spi_nor_scan(nor1, NULL, mode);
>>       if (err)
>>               return err; /* or handle error properly. */
>>
>>       err = spi_nor_scan(nor2, NULL, mode);
>>       if (err)
>>               return err;
>>
>>       mtd = &nor1->mtd;
>>       mtd->erasesize <<= 1;
>>       mtd->size <<= 1;
>>       mtd->writebufsize <<= 1;
>>       nor1->page_size <<= 1;
>>       /* tune all other relevant members of nor1/mtd. */
>>
>>       /* override relevant mtd hooks. */
>>       mtd->_read = stripping_read;
>>       mtd->_erase = stripping_erase;
>>       mtd->_write = stripping_write;
>>       mtd->_lock = ...;
>>       mtd->_unlock = ...;
>>       mtd->_is_lock = ...;
>>
>>       /* register a single mtd_info structure. */
>>       err = mtd_device_register(mtd, NULL, 0);
>>       if (err)
>>               return err;
>>
>>       [...]
>> }
>>
> 
> It's really good for us to have our controller specific mtd hooks instead of 
> changing the layer calls and thanks for this suggestion.
> But spi-zynqmp-gqspi.c is spi driver and all above mentioned parameters and 
> function pointers are related to flash layer.
> So is it ok to update and change flash related stuff in our spi driver?
> 

Check with the SPI sub-system people, especially Mark Brown, but I don't
think would be good to put too much mtd/spi-nor stuff in the SPI sub-system.

Anyway, the solution I've proposed is not suited if you use m25p80.c as an
adaptation layer between spi-nor.c and the SPI controller driver.
Indeed, in that case, spi_nor_scan() is called from m25p_probe() in
m25p80.c and I still think there would be too many side effects if we
modified either spi-nor.c or m25p80.c the way you propose to compute
logical operations on register values. This solution is not maintainable
regarding the number memory registers we already manage.

You might need to develop a new driver to substitute m25p80.c and make the
link between spi-nor, mostly spi_nor_scan(), and you SPI controller driver.

Honestly I have no real idea how you could proceed to add support to such a
feature: accessing 2 SPI flashes at the time to perform stripping
operations doesn't sound really reliable to me because I don't see how you
plan to handle errors properly and also cover all the features provided by
SPI flash memory and supported by spi-nor.c (sector/block protection, ...).

>> Best regards,
>>
>> Cyrille
>>
> Thanks,
> Naga Sureshkumar Relli
> 
> 
> This email and any attachments are intended for the sole use of the named 
> recipient(s) and contain(s) confidential information that may be proprietary, 
> privileged or copyrighted under applicable law. If you are not the intended 
> recipient, do not read, copy, or forward this email message or any 
> attachments. Delete this email message and any attachments immediately.
> 
> 

Reply via email to