25 Nov, 2020

1 commit

  • When SPI DW memory ops support was introduced, there was a check for
    excluding controllers which supplied their own CS function. Even so,
    the mem_ops pointer is *always* presented to the SPI core.

    This causes the SPI core sanity check in spi_controller_check_ops() to
    refuse registration, since a mem_ops pointer is being supplied without
    an exec_op member function.

    The end result is failure of the SPI DW driver on sparx5 and similar
    platforms.

    The fix in the core SPI DW driver is to avoid presenting the mem_ops
    pointer if the exec_op function is not set.

    Fixes: 6423207e57ea (spi: dw: Add memory operations support)
    Signed-off-by: Lars Povlsen
    Acked-by: Serge Semin
    Link: https://lore.kernel.org/r/20201120213414.339701-1-lars.povlsen@microchip.com
    Signed-off-by: Mark Brown

    Lars Povlsen
     

18 Nov, 2020

1 commit

  • It turns out the IRQs most like can be unmasked before the controller is
    enabled with no problematic consequences. The manual doesn't explicitly
    state that, but the examples perform the controller initialization
    procedure in that order. So the commit da8f58909e7e ("spi: dw: Unmask IRQs
    after enabling the chip") hasn't been that required as I thought. But
    anyway setting the IRQs up after the chip enabling still worth adding
    since it has simplified the code a bit. The problem is that it has
    introduced a potential bug. The transfer handler pointer is now
    initialized after the IRQs are enabled. That may and eventually will cause
    an invalid or uninitialized callback invocation. Fix that just by
    performing the callback initialization before the IRQ unmask procedure.

    Fixes: da8f58909e7e ("spi: dw: Unmask IRQs after enabling the chip")
    Signed-off-by: Serge Semin
    Link: https://lore.kernel.org/r/20201117094054.4696-1-Sergey.Semin@baikalelectronics.ru
    Signed-off-by: Mark Brown

    Serge Semin
     

09 Oct, 2020

17 commits

  • A functionality of the poll-based transfer has been removed by
    commit 1ceb09717e98 ("spi: dw: remove cs_control and poll_mode members
    from chip_data") with a justification that "there is no user of one
    anymore". It turns out one of our DW APB SSI core is synthesized with no
    IRQ line attached and the only possible way of using it is to implement a
    poll-based SPI transfer procedure. So we have to get the removed
    functionality back, but with some alterations described below.

    First of all the poll-based transfer is activated only if the DW SPI
    controller doesn't have an IRQ line attached and the Linux IRQ number is
    initialized with the IRQ_NOTCONNECTED value. Secondly the transfer
    procedure is now executed with a delay performed between writer and reader
    methods. The delay value is calculated based on the number of data words
    expected to be received on the current iteration. Finally the errors
    status is checked on each iteration.

    Signed-off-by: Serge Semin
    Link: https://lore.kernel.org/r/20201007235511.4935-20-Sergey.Semin@baikalelectronics.ru
    Signed-off-by: Mark Brown

    Serge Semin
     
  • In some circumstances the current implementation of the SPI memory
    operations may occasionally fail even though they are executed in the
    atomic context. This may happen if the system bus is relatively slow in
    comparison to the SPI bus frequency, or there is a concurrent access to
    it, which makes the MMIO-operations occasionally stalling before
    push-pulling data from the DW APB SPI FIFOs. These two problems we've
    discovered on the Baikal-T1 SoC. In order to fix them we have no choice
    but to set an artificial limitation on the SPI bus speed.

    Note currently this limitation will be only applicable for the memory
    operations, since the standard SPI core interface is implemented with an
    assumption that there is no problem with the automatic CS toggling.

    Signed-off-by: Serge Semin
    Link: https://lore.kernel.org/r/20201007235511.4935-19-Sergey.Semin@baikalelectronics.ru
    Signed-off-by: Mark Brown

    Serge Semin
     
  • Aside from the synchronous Tx-Rx mode, which has been utilized to create
    the normal SPI transfers in the framework of the DW SSI driver, DW SPI
    controller supports Tx-only and EEPROM-read modes. The former one just
    enables the controller to transmit all the data from the Tx FIFO ignoring
    anything retrieved from the MISO lane. The later mode is so called
    write-then-read operation: DW SPI controller first pushes out all the data
    from the Tx FIFO, after that it'll automatically receive as much data as
    has been specified by means of the CTRLR1 register. Both of those modes
    can be used to implement the memory operations supported by the SPI-memory
    subsystem.

    The memory operation implementation is pretty much straightforward, except
    a few peculiarities we have had to take into account to make things
    working. Since DW SPI controller doesn't provide a way to directly set and
    clear the native CS lane level, but instead automatically de-asserts it
    when a transfer going on, we have to make sure the Tx FIFO isn't empty
    during entire Tx procedure. In addition we also need to read data from the
    Rx FIFO as fast as possible to prevent it' overflow with automatically
    fetched incoming traffic. The denoted peculiarities get to cause even more
    problems if DW SSI controller is equipped with relatively small FIFO and
    is connected to a relatively slow system bus (APB) (with respect to the
    SPI bus speed). In order to workaround the problems for as much as it's
    possible, the memory operation execution procedure collects all the Tx
    data into a single buffer and disables the local IRQs to speed the
    write-then-optionally-read method up.

    Note the provided memory operations are utilized by default only if
    a glue driver hasn't provided a custom version of ones and this is not
    a DW APB SSI controller with fixed automatic CS toggle functionality.

    Co-developed-by: Ramil Zaripov
    Signed-off-by: Ramil Zaripov
    Signed-off-by: Serge Semin
    Link: https://lore.kernel.org/r/20201007235511.4935-18-Sergey.Semin@baikalelectronics.ru
    Signed-off-by: Mark Brown

    Serge Semin
     
  • The DW SSI errors handling method can be generically implemented for all
    types of the transfers: IRQ, DMA and poll-based ones. It will be a
    function which checks the overflow/underflow error flags and resets the
    controller if any of them is set. In the framework of this commit we make
    use of the new method to detect the errors in the IRQ- and DMA-based SPI
    transfer execution procedures.

    Signed-off-by: Serge Semin
    Link: https://lore.kernel.org/r/20201007235511.4935-17-Sergey.Semin@baikalelectronics.ru
    Signed-off-by: Mark Brown

    Serge Semin
     
  • By design of the currently available native set_cs callback, the CS
    de-assertion will be done only if it's required by the corresponding
    controller capability. But in order to pre-fill the Tx FIFO buffer with
    data during the SPI memory ops execution the SER register needs to be left
    cleared before that. We'll also need a way to explicitly set and clear the
    corresponding CS bit at a certain moment of the operation. Let's alter
    the set_cs function then to also de-activate the CS, when it's required.

    Signed-off-by: Serge Semin
    Link: https://lore.kernel.org/r/20201007235511.4935-15-Sergey.Semin@baikalelectronics.ru
    Signed-off-by: Mark Brown

    Serge Semin
     
  • It's pointless to enable the chip back if the DMA setup procedure fails,
    since we'll disable it on the next transfer anyway. For the same reason We
    don't do that in case of a failure detected in any other methods called
    from the transfer_one() method.

    While at it consider any non-zero value returned from the dma_setup
    callback to be erroneous as it's supposed to be in the kernel.

    Signed-off-by: Serge Semin
    Link: https://lore.kernel.org/r/20201007235511.4935-13-Sergey.Semin@baikalelectronics.ru
    Signed-off-by: Mark Brown

    Serge Semin
     
  • It's theoretically erroneous to enable IRQ before the chip is turned on.
    If IRQ handler gets executed before the chip is enabled, then any data
    written to the Tx FIFO will be just ignored.

    I say "theoretically" because we haven't noticed any problem with that,
    but let's fix it anyway just in case...

    Signed-off-by: Serge Semin
    Link: https://lore.kernel.org/r/20201007235511.4935-12-Sergey.Semin@baikalelectronics.ru
    Signed-off-by: Mark Brown

    Serge Semin
     
  • In order to make the transfer_one() callback method more readable and
    for unification with the DMA-based transfer, let's detach the IRQ setup
    procedure into a dedicated function. While at it rename the IRQ-based
    transfer handler function to be dw_spi-prefixe and looking more like the
    DMA-related one.

    Signed-off-by: Serge Semin
    Link: https://lore.kernel.org/r/20201007235511.4935-11-Sergey.Semin@baikalelectronics.ru
    Signed-off-by: Mark Brown

    Serge Semin
     
  • Current IRQ-based SPI transfer execution procedure doesn't work well at
    the final stage of the execution. If all the Tx data is sent out (written
    to the Tx FIFO) but there is some data left to receive, the Tx FIFO Empty
    IRQ will constantly happen until all of the requested inbound data is
    received. Though for a short period of time, but it will make the system
    less responsive. In order to fix that let's refactor the SPI transfer
    execution procedure by taking the Rx FIFO Full IRQ into account. We'll read
    and write SPI transfer data each time the IRQ happens as before. If all
    the outbound data is sent out, we'll disable the Tx FIFO Empty IRQ. If
    there is still some data to receive, we'll adjust the Rx FIFO Threshold
    level, so the next IRQ would be raised at the moment of all incoming data
    being available in the Rx FIFO.

    Signed-off-by: Serge Semin
    Link: https://lore.kernel.org/r/20201007235511.4935-10-Sergey.Semin@baikalelectronics.ru
    Signed-off-by: Mark Brown

    Serge Semin
     
  • The Tx and Rx data write/read procedure can be significantly simplified by
    using Tx/Rx transfer lengths instead of the end pointers. By having the
    Tx/Rx data leftover lengths (in the number of transfer words) we can get
    rid of all subtraction and division operations utilized here and there in
    the tx_max(), rx_max(), dw_writer() and dw_reader() methods. Such
    modification will not only give us the more optimized IO procedures, but
    will make the data IO methods much more readable than before.

    Signed-off-by: Serge Semin
    Link: https://lore.kernel.org/r/20201007235511.4935-9-Sergey.Semin@baikalelectronics.ru
    Signed-off-by: Mark Brown

    Serge Semin
     
  • DW APB SSI controller can be used by the two SPI core interfaces:
    traditional SPI transfers and SPI memory operations. The controller needs
    to be accordingly configured at runtime when the corresponding operations
    are executed. In order to do that for the both interfaces from a single
    function we introduce a new data wrapper for the transfer mode, data
    width, number of data frames (for the automatic data transfer) and the bus
    frequency. It will be used by the update_config() method to tune the DW
    APB SSI up.

    The update_config() method is made exported to be used not only by the DW
    SPI core driver, but by the glue layer drivers too. This will be required
    in a coming further commit.

    Signed-off-by: Serge Semin
    Link: https://lore.kernel.org/r/20201007235511.4935-8-Sergey.Semin@baikalelectronics.ru
    Signed-off-by: Mark Brown

    Serge Semin
     
  • Rx sample delay can be SPI device specific, and should be synchronously
    initialized with the rest of the communication and peripheral device
    related controller setups. So let's move the Rx-sample delay setup into
    the DW APB SSI configuration update method.

    Signed-off-by: Serge Semin
    Link: https://lore.kernel.org/r/20201007235511.4935-7-Sergey.Semin@baikalelectronics.ru
    Signed-off-by: Mark Brown

    Serge Semin
     
  • The code currently responsible for the SPI communication speed setting up
    is a bit messy. Most likely for some historical reason the bus frequency
    is saved in the peripheral chip private data. It's pointless now since the
    custom communication speed is a SPI-transfer-specific thing and only if
    there is no SPI transfer data specified (like during the SPI memory
    operations) it can be taken from the SPI device structure. But even in the
    later case there is no point in having the clock divider and the SPI bus
    frequency saved in the chip data, because the controller can be used for
    both SPI-transfer-based and SPI-transfer-less communications. From
    software point of view keeping the current clock divider in an SPI-device
    specific storage may give a small performance gain (to avoid sometimes a
    round-up division), but in comparison to the total SPI transfer time it
    just doesn't worth saving a few CPU cycles in comparison to the total SPI
    transfer time while having the harder to read code. The only optimization,
    which could worth preserving in the code is to avoid unnecessary DW SPI
    controller registers update if it's possible. So to speak let's simplify
    the SPI communication speed update procedure by removing the clock-related
    fields from the peripheral chip data and update the DW SPI clock divider
    only if it's really changed. The later change is reached by keeping the
    effective SPI bus speed in the internal DW SPI private data.

    Signed-off-by: Serge Semin
    Link: https://lore.kernel.org/r/20201007235511.4935-6-Sergey.Semin@baikalelectronics.ru
    Signed-off-by: Mark Brown

    Serge Semin
     
  • The SPI bus speed update functionality will be useful in another parts of
    the driver too (like to implement the SPI memory operations and from the
    DW SPI glue layers). Let's move it to the update_cr0() method then and
    since the later is now updating not only the CTRLR0 register alter its
    prototype to have a generic function name not related to CR0.

    Leave the too long line with the chip->clk_div setting as is for now,
    since it's going to be changed later anyway.

    Signed-off-by: Serge Semin
    Link: https://lore.kernel.org/r/20201007235511.4935-5-Sergey.Semin@baikalelectronics.ru
    Signed-off-by: Mark Brown

    Serge Semin
     
  • Indeed there is no point in detecting the SPI peripheral device parameters
    and initializing the CR0 register fields each time an SPI transfer is
    executed. Instead let's define a dedicated CR0 chip-data member, which
    will be initialized in accordance with the SPI device settings at the
    moment of setting it up.

    By doing so we'll finally make the SPI device chip_data serving as it's
    supposed to - to preserve the SPI device specific DW SPI configuration.
    See spi-fsl-dspi.c, spi-pl022.c, spi-pxa2xx.c drivers for example of the
    way the chip data is utilized.

    Signed-off-by: Serge Semin
    Link: https://lore.kernel.org/r/20201007235511.4935-4-Sergey.Semin@baikalelectronics.ru
    Signed-off-by: Mark Brown

    Serge Semin
     
  • Currently DWC SSI core is supported by means of setting up the
    core-specific update_cr0() callback. It isn't suitable for multiple
    reasons. First of all having exported several methods doing the same thing
    but for different chips makes the code harder to maintain. Secondly the
    spi-dw-core driver exports the methods, then the spi-dw-mmio driver sets
    the private data callback with one of them so to be called by the core
    driver again. That makes the code logic too complicated. Thirdly using
    callbacks for just updating the CR0 register is problematic, since in case
    if the register needed to be updated from different parts of the code,
    we'd have to create another callback (for instance the SPI device-specific
    parameters don't need to be calculated each time the SPI transfer is
    submitted, so it's better to pre-calculate the CR0 data at the SPI-device
    setup stage).

    So keeping all the above in mind let's discard the update_cr0() callbacks,
    define a generic and static dw_spi_update_cr0() method and create the
    DW_SPI_CAP_DWC_SSI capability, which when enabled would activate the
    alternative CR0 register layout.

    While at it add the comments to the code path of the normal DW APB SSI
    controller setup to make the dw_spi_update_cr0() method looking coherent.

    Signed-off-by: Serge Semin
    Link: https://lore.kernel.org/r/20201007235511.4935-3-Sergey.Semin@baikalelectronics.ru
    Signed-off-by: Mark Brown

    Serge Semin
     
  • Simplify the dw_spi_add_host() method a bit by replacing the currently
    implemented default set_cs callback setting up and later having it
    overwritten by a custom function with direct if-else-based callback
    assignment.

    Signed-off-by: Serge Semin
    Link: https://lore.kernel.org/r/20201007235511.4935-2-Sergey.Semin@baikalelectronics.ru
    Signed-off-by: Mark Brown

    Serge Semin
     

30 Sep, 2020

6 commits

  • There is no point in having the commit 19b61392c5a8 ("spi: spi-dw: Add
    lock protect dw_spi rx/tx to prevent concurrent calls") applied. The
    commit author made an assumption that the problem with the rx data
    mismatch was due to the lack of the data protection. While most likely it
    was caused by the lack of the memory barrier. So having the
    commit bfda044533b2 ("spi: dw: use "smp_mb()" to avoid sending spi data
    error") applied would be enough to fix the problem.

    Indeed the spin unlock operation makes sure each memory operation issued
    before the release will be completed before it's completed. In other words
    it works as an implicit one way memory barrier. So having both smp_mb()
    and the spin_unlock_irqrestore() here is just redundant. One of them would
    be enough. It's better to leave the smp_mb() since the Tx/Rx buffers
    consistency is provided by the data transfer algorithm implementation:
    first we initialize the buffers pointers, then make sure the assignments
    are visible by the other CPUs by calling the smp_mb(), only after that
    enable the interrupt, which handler uses the buffers.

    Signed-off-by: Serge Semin
    Link: https://lore.kernel.org/r/20200920112914.26501-5-Sergey.Semin@baikalelectronics.ru
    Signed-off-by: Mark Brown

    Serge Semin
     
  • In a further commit we'll have to get rid of the update_cr0() callback and
    define a DW SSI capability instead. Since Keem Bay master/slave
    functionality is controller by the CTRL0 register bitfield, we need to
    first move the master mode selection into the internal corresponding
    update_cr0 method, which would be activated by means of the dedicated
    DW_SPI_CAP_KEEMBAY_MST capability setup.

    Note this will be also useful if the driver will be ever altered to
    support the DW SPI slave interface.

    Signed-off-by: Serge Semin
    Link: https://lore.kernel.org/r/20200920112914.26501-11-Sergey.Semin@baikalelectronics.ru
    Signed-off-by: Mark Brown

    Serge Semin
     
  • There are several vendor-specific versions of the DW SPI controllers,
    each of which may have some peculiarities with respect to the original
    IP-core. Seeing it has already caused adding flags and a callback into the
    DW SPI private data, let's introduce a generic capabilities interface to
    tune the generic DW SPI controller driver up in accordance with the
    particular controller specifics. It's done by converting a simple
    Alpine-specific CS-override capability into the DW SPI controller
    capability activated by setting the DW_SPI_CAP_CS_OVERRIDE flag.

    Signed-off-by: Serge Semin
    Link: https://lore.kernel.org/r/20200920112914.26501-10-Sergey.Semin@baikalelectronics.ru
    Signed-off-by: Mark Brown

    Serge Semin
     
  • Keeping SPI peripheral devices type is pointless since first it hasn't
    been functionally utilized by any of the client drivers/code and second it
    won't work for Microwire type at the very least. Moreover there is no
    point in setting up the type by means of the chip-data in the modern
    kernel. The peripheral devices with specific interface type need to be
    detected in order to activate the corresponding frame format. It most
    likely will require some peripheral device specific DT property or
    whatever to find out the interface protocol. So let's remove the serial
    interface type fields from the DW APB SSI controller and the SPI
    peripheral device private data.

    Note we'll preserve the explicit SSI_MOTO_SPI interface type setting up to
    signify the only currently supported interface protocol.

    Signed-off-by: Serge Semin
    Link: https://lore.kernel.org/r/20200920112914.26501-9-Sergey.Semin@baikalelectronics.ru
    Signed-off-by: Mark Brown

    Serge Semin
     
  • It's a good practice to disable all IRQs if a device is fully unused. In
    our case it is supposed to be done before requesting the IRQ and after the
    last byte of an SPI transfer is received. In the former case it's required
    to prevent the IRQ handler invocation before the driver data is fully
    initialized (which may happen if the IRQs status has been left uncleared
    before the device is probed). So we just moved the spi_hw_init() method
    invocation to the earlier stage before requesting the IRQ. In the later
    case there is just no point in having any of the IRQs enabled between SPI
    transfers and when there is no SPI message currently being processed.

    Signed-off-by: Serge Semin
    Link: https://lore.kernel.org/r/20200920112914.26501-7-Sergey.Semin@baikalelectronics.ru
    Signed-off-by: Mark Brown

    Serge Semin
     
  • Since n_bytes field of the DW SPI private data is also utilized by the
    IRQ handler, we need to make sure it' initialization is done before the
    memory barrier.

    Signed-off-by: Serge Semin
    Link: https://lore.kernel.org/r/20200920112914.26501-4-Sergey.Semin@baikalelectronics.ru
    Signed-off-by: Mark Brown

    Serge Semin
     

08 Sep, 2020

1 commit

  • This add support for the RX_SAMPLE_DLY register. If enabled in the
    Designware IP, it allows tuning of the rx data signal by means of an
    internal rx sample fifo.

    The register is controlled by the rx-sample-delay-ns DT property,
    which is defined per SPI slave as well on controller level.

    The controller level rx-sample-delay-ns will apply to all slaves
    without the property explicitly defined.

    The register is located at offset 0xf0, and if the option is not
    enabled in the IP, changing the register will have no effect. The
    register will only be written if any slave defines a nonzero value
    (after scaling by the clock period).

    Signed-off-by: Lars Povlsen
    Link: https://lore.kernel.org/r/20200824203010.2033-2-lars.povlsen@microchip.com
    Signed-off-by: Mark Brown

    Lars Povlsen
     

30 May, 2020

1 commit


29 May, 2020

2 commits

  • DebugFS kernel interface provides a dedicated method to create the
    registers dump file. Use it instead of creating a generic DebugFS
    file with manually written read callback function.

    Signed-off-by: Serge Semin
    Reviewed-by: Andy Shevchenko
    Cc: Georgy Vlasov
    Cc: Ramil Zaripov
    Cc: Alexey Malahov
    Cc: Thomas Bogendoerfer
    Cc: Arnd Bergmann
    Cc: Feng Tang
    Cc: Rob Herring
    Cc: linux-mips@vger.kernel.org
    Cc: devicetree@vger.kernel.org
    Link: https://lore.kernel.org/r/20200529131205.31838-16-Sergey.Semin@baikalelectronics.ru
    Signed-off-by: Mark Brown

    Serge Semin
     
  • Generic DMA support is going to be part of the DW APB SSI core object.
    In order to preserve the kernel loadable module name as spi-dw.ko, let's
    add the "-core" suffix to the object with generic DW APB SSI code and
    build it into the target spi-dw.ko driver.

    Suggested-by: Andy Shevchenko
    Signed-off-by: Serge Semin
    Reviewed-by: Andy Shevchenko
    Cc: Georgy Vlasov
    Cc: Ramil Zaripov
    Cc: Alexey Malahov
    Cc: Thomas Bogendoerfer
    Cc: Feng Tang
    Cc: Rob Herring
    Cc: Arnd Bergmann
    Cc: linux-mips@vger.kernel.org
    Cc: devicetree@vger.kernel.org
    Link: https://lore.kernel.org/r/20200529131205.31838-10-Sergey.Semin@baikalelectronics.ru
    Signed-off-by: Mark Brown

    Serge Semin