Commit a34d4197 authored by Mark Brown's avatar Mark Brown

Merge existing fixes from spi/for-5.11

parents 5c8fe583 a590370d
......@@ -83,6 +83,7 @@ struct spi_geni_master {
spinlock_t lock;
int irq;
bool cs_flag;
bool abort_failed;
};
static int get_spi_clk_cfg(unsigned int speed_hz,
......@@ -141,8 +142,49 @@ static void handle_fifo_timeout(struct spi_master *spi,
spin_unlock_irq(&mas->lock);
time_left = wait_for_completion_timeout(&mas->abort_done, HZ);
if (!time_left)
if (!time_left) {
dev_err(mas->dev, "Failed to cancel/abort m_cmd\n");
/*
* No need for a lock since SPI core has a lock and we never
* access this from an interrupt.
*/
mas->abort_failed = true;
}
}
static bool spi_geni_is_abort_still_pending(struct spi_geni_master *mas)
{
struct geni_se *se = &mas->se;
u32 m_irq, m_irq_en;
if (!mas->abort_failed)
return false;
/*
* The only known case where a transfer times out and then a cancel
* times out then an abort times out is if something is blocking our
* interrupt handler from running. Avoid starting any new transfers
* until that sorts itself out.
*/
spin_lock_irq(&mas->lock);
m_irq = readl(se->base + SE_GENI_M_IRQ_STATUS);
m_irq_en = readl(se->base + SE_GENI_M_IRQ_EN);
spin_unlock_irq(&mas->lock);
if (m_irq & m_irq_en) {
dev_err(mas->dev, "Interrupts pending after abort: %#010x\n",
m_irq & m_irq_en);
return true;
}
/*
* If we're here the problem resolved itself so no need to check more
* on future transfers.
*/
mas->abort_failed = false;
return false;
}
static void spi_geni_set_cs(struct spi_device *slv, bool set_flag)
......@@ -158,10 +200,21 @@ static void spi_geni_set_cs(struct spi_device *slv, bool set_flag)
if (set_flag == mas->cs_flag)
return;
mas->cs_flag = set_flag;
pm_runtime_get_sync(mas->dev);
if (spi_geni_is_abort_still_pending(mas)) {
dev_err(mas->dev, "Can't set chip select\n");
goto exit;
}
spin_lock_irq(&mas->lock);
if (mas->cur_xfer) {
dev_err(mas->dev, "Can't set CS when prev xfer running\n");
spin_unlock_irq(&mas->lock);
goto exit;
}
mas->cs_flag = set_flag;
reinit_completion(&mas->cs_done);
if (set_flag)
geni_se_setup_m_cmd(se, SPI_CS_ASSERT, 0);
......@@ -170,9 +223,12 @@ static void spi_geni_set_cs(struct spi_device *slv, bool set_flag)
spin_unlock_irq(&mas->lock);
time_left = wait_for_completion_timeout(&mas->cs_done, HZ);
if (!time_left)
if (!time_left) {
dev_warn(mas->dev, "Timeout setting chip select\n");
handle_fifo_timeout(spi, NULL);
}
exit:
pm_runtime_put(mas->dev);
}
......@@ -280,6 +336,9 @@ static int spi_geni_prepare_message(struct spi_master *spi,
int ret;
struct spi_geni_master *mas = spi_master_get_devdata(spi);
if (spi_geni_is_abort_still_pending(mas))
return -EBUSY;
ret = setup_fifo_params(spi_msg->spi, spi);
if (ret)
dev_err(mas->dev, "Couldn't select mode %d\n", ret);
......@@ -354,6 +413,12 @@ static bool geni_spi_handle_tx(struct spi_geni_master *mas)
unsigned int bytes_per_fifo_word = geni_byte_per_fifo_word(mas);
unsigned int i = 0;
/* Stop the watermark IRQ if nothing to send */
if (!mas->cur_xfer) {
writel(0, se->base + SE_GENI_TX_WATERMARK_REG);
return false;
}
max_bytes = (mas->tx_fifo_depth - mas->tx_wm) * bytes_per_fifo_word;
if (mas->tx_rem_bytes < max_bytes)
max_bytes = mas->tx_rem_bytes;
......@@ -396,6 +461,14 @@ static void geni_spi_handle_rx(struct spi_geni_master *mas)
if (rx_last_byte_valid && rx_last_byte_valid < 4)
rx_bytes -= bytes_per_fifo_word - rx_last_byte_valid;
}
/* Clear out the FIFO and bail if nowhere to put it */
if (!mas->cur_xfer) {
for (i = 0; i < DIV_ROUND_UP(rx_bytes, bytes_per_fifo_word); i++)
readl(se->base + SE_GENI_RX_FIFOn);
return;
}
if (mas->rx_rem_bytes < rx_bytes)
rx_bytes = mas->rx_rem_bytes;
......@@ -495,6 +568,9 @@ static int spi_geni_transfer_one(struct spi_master *spi,
{
struct spi_geni_master *mas = spi_master_get_devdata(spi);
if (spi_geni_is_abort_still_pending(mas))
return -EBUSY;
/* Terminate and return success for 0 byte length transfer */
if (!xfer->len)
return 0;
......
......@@ -493,9 +493,9 @@ static u32 stm32h7_spi_prepare_fthlv(struct stm32_spi *spi, u32 xfer_len)
/* align packet size with data registers access */
if (spi->cur_bpw > 8)
fthlv -= (fthlv % 2); /* multiple of 2 */
fthlv += (fthlv % 2) ? 1 : 0;
else
fthlv -= (fthlv % 4); /* multiple of 4 */
fthlv += (fthlv % 4) ? (4 - (fthlv % 4)) : 0;
if (!fthlv)
fthlv = 1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment