[PATCH] mtd/spi-nor: Add SPI memory controllers for Aspeed SoCs
Cyrille Pitchen
cyrille.pitchen at atmel.com
Thu Oct 20 07:33:06 PDT 2016
Hi Cédric,
Le 20/10/2016 à 11:17, Cédric Le Goater a écrit :
> Hello Cyrille,
>
> Thanks for taking a look, some answers and more questions below.
>
> On 10/19/2016 07:06 PM, Cyrille Pitchen wrote:
>> Hi Cédric,
>>
>> Le 17/10/2016 à 18:57, Cédric Le Goater a écrit :
>>> This driver adds mtd support for spi-nor attached to either or both of
>>> the Firmware Memory Controller or the SPI Flash Controller (AST2400
>>> only).
>>>
>>> The SMC controllers on the Aspeed AST2500 SoC are very similar to the
>>> ones found on the AST2400. The differences are on the number of
>>> supported flash modules and their default mappings in the SoC address
>>> space.
>>>
>>> The Aspeed AST2500 has one SPI controller for the BMC firmware and two
>>> for the host firmware. All controllers have now the same set of
>>> registers compatible with the AST2400 FMC controller and the legacy
>>> 'SMC' controller is fully gone.
>>>
>>> Based on previous work from Milton D. Miller II <miltonm at us.ibm.com>
>>>
>>> Signed-off-by: Cédric Le Goater <clg at kaod.org>
>>> ---
>> [...]
>>> +
>>> +static void aspeed_smc_send_cmd_addr(struct spi_nor *nor, u8 cmd, u32 addr)
>>> +{
>>> + struct aspeed_smc_chip *chip = nor->priv;
>>> + __be32 temp;
>>> + u32 cmdaddr;
>>> +
>>> + switch (nor->addr_width) {
>>> + default:
>>> + WARN_ONCE(1, "Unexpected address width %u, defaulting to 3\n",
>>> + nor->addr_width);
>>> + /* FALLTHROUGH */
>>> + case 3:
>>> + cmdaddr = addr & 0xFFFFFF;
>>> +
>>> + cmdaddr |= (u32)cmd << 24;
>>> +
>>> + temp = cpu_to_be32(cmdaddr);
>>> + aspeed_smc_to_fifo(chip->base, &temp, 4);
>>> + break;
>>> + case 4:
>>> + temp = cpu_to_be32(addr);
>>> + aspeed_smc_to_fifo(chip->base, &cmd, 1);
>>> + aspeed_smc_to_fifo(chip->base, &temp, 4);
>>> + break;
>>> + }
>>> +}
>>> +
>>> +static ssize_t aspeed_smc_read_user(struct spi_nor *nor, loff_t from, size_t len,
>>> + u_char *read_buf)
>>> +{
>>> + struct aspeed_smc_chip *chip = nor->priv;
>>> +
>>> + mutex_lock(&chip->controller->mutex);
>>> +
>>> + aspeed_smc_start_user(nor);
>
> I think this section of code lock+start_user should be in a prepare handler
> if I am correct ? and I could get rid of the lock in that case to rely on
> the one of the spi nor.
>
For the mutex, looking at your driver, you lock it at the beginning then unlock
at the end of the four handlers:
- nor->read()
- nor->write()
- nor->read_reg()
- nor->write_reg()
If this is the only purpose of this mutex, yes, you can remove it and relie on
the internal spi-nor one (nor->lock), which is locked from
spi_nor_lock_and_prep() hence at the beginning of spi_nor_erase(),
spi_nor_read() and spi_nor_write() calls.
However, about moving the call of aspeed_smc_start_user() into a new prepare
handler, I don't know whether it would actually fit your needs: for sure,
aspeed_smc_start_user() would be no longer called at some points.
2 examples:
A - spi_nor_write() calls:
1 - spi_nor_lock_and_prep() -> nor->prepare()
2 - write_enable() -> nor->write_reg()
3 - nor->write()
4 - spi_nor_wait_till_ready() -> nor->read_reg()
5 - spi_nor_unlock_and_unprep() -> nor->unprepare()
With your current driver, aspeed_smc_start_user()/aspeed_smc_stop_user() are
called 3 times, indeed each time a command is sent on the SPI bus:
WRITE ENABLE, PAGE PROGRAM, READ STATUS
Then if you move then into spi_nor_[un]lock_and_[un]prep(), those two functions
would only be called once each.
B - spi_nor_scan() calls:
1 - spi_nor_read_id() -> nor->read_reg()
but spi_nor_lock_and_prep() is not called before, so if you nead to call
aspeed_smc_start_user() before sending any command on the SPI bus, it won't
work.
I don't know how your SPI controller works but maybe using the nor->prepare()
handler is not what you want!
>>> + aspeed_smc_send_cmd_addr(nor, nor->read_opcode, from);
>>
>> I guess the dummy cycles are missing between address cycles and data cycles!
>> Check nor->read_dummy ;)
>
> ah yes, I meant to and I forgot to add it ... will do in v2. I suppose
> we are doing fine with the driver now because we only use normal speed.
>
Indeed, the legacy READ (03h) command has no dummy cycles as opposed to all
other FAST READ commands. Of course, the READ command is far much slower.
>> Or maybe this controller can really only perform READ operations but no FAST
>> READ commands. Hence the "spi_nor_scan(&chip->nor, NULL, SPI_NOR_NORMAL)"
>> below.
>
> yes it can. I suppose the driver should also call spi_nor_set_flash_node()
> for module supporting it. that brings another question I would like
> to discuss for possible followups patches.
>
Calling spi_nor_set_flash_node() with the relevant parameter tells
spi_nor_scan() which DT node to parse to tune some settings.
For instance, you could add the "m25p,fast-read" DT property so spi_nor_scan()
would select Fast Read operations rather than Read operations.
> The controller can be fine tuned for a particular chip module. The
> CE0 control register has a few bits to set the spi clock, the dummy
> cycles, the CS inactive width and there is also a register to setup
> read timings delay.
>
> So you need to loop on these different settings to find a correct one
> and for that, you use a gold image captured at low speed as reference.
>
> But you need to know which chip module you are dealing with. would it
> be possible to expose the jedec to the controller for this purpose ?
> and then do the training to build the timing settings in the driver.
> This is a similar approach taken by some nand controllers.
>
I'm not sure to fully understand your needs.
The spi clock is often provided in the device tree, on the controller or memory
node, with the "spi-max-frequency" DT property.
The number of dummy cycles is set in nor->read_dummy by spi_nor_scan()
according to the actual memory model and the selected (Fast) Read op code.
For chip-select timings, those settings aren't currently handled by
spi_nor_scan() but might be supported inside the SPI controller driver through
DT properties if needed.
I don't know why your SPI controller driver needs to know the exact memory
model to work. Aren't the pieces of information provided by spi-nor.c enough?
Actually, for this point I don't quite exactly understand your needs! :)
Best regards,
Cyrille
> Thanks,
>
> C.
>
>
>>> + aspeed_smc_from_fifo(read_buf, chip->base, len);
>>> + aspeed_smc_stop_user(nor);
>>> +
>>> + mutex_unlock(&chip->controller->mutex);
>>> +
>>> + return len;
>>> +}
>> [...]
>>
>> Best regards,
>>
>> Cyrille
>>
>> ______________________________________________________
>> Linux MTD discussion mailing list
>> http://lists.infradead.org/mailman/listinfo/linux-mtd/
>>
>
More information about the linux-mtd
mailing list