diff options
Diffstat (limited to 'drivers/spi/spi-geni-qcom.c')
-rw-r--r-- | drivers/spi/spi-geni-qcom.c | 372 |
1 files changed, 234 insertions, 138 deletions
diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c index c3972424af71..80cea5cd3612 100644 --- a/drivers/spi/spi-geni-qcom.c +++ b/drivers/spi/spi-geni-qcom.c @@ -7,6 +7,7 @@ #include <linux/log2.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/pm_opp.h> #include <linux/pm_runtime.h> #include <linux/qcom-geni-se.h> #include <linux/spi/spi.h> @@ -51,7 +52,6 @@ /* M_CMD OP codes for SPI */ #define SPI_TX_ONLY 1 #define SPI_RX_ONLY 2 -#define SPI_FULL_DUPLEX 3 #define SPI_TX_RX 7 #define SPI_CS_ASSERT 8 #define SPI_CS_DEASSERT 9 @@ -63,29 +63,26 @@ #define TIMESTAMP_AFTER BIT(3) #define POST_CMD_DELAY BIT(4) -enum spi_m_cmd_opcode { - CMD_NONE, - CMD_XFER, - CMD_CS, - CMD_CANCEL, -}; - struct spi_geni_master { struct geni_se se; struct device *dev; u32 tx_fifo_depth; u32 fifo_width_bits; u32 tx_wm; + u32 last_mode; unsigned long cur_speed_hz; + unsigned long cur_sclk_hz; unsigned int cur_bits_per_word; unsigned int tx_rem_bytes; unsigned int rx_rem_bytes; const struct spi_transfer *cur_xfer; - struct completion xfer_done; + struct completion cs_done; + struct completion cancel_done; + struct completion abort_done; unsigned int oversampling; spinlock_t lock; - enum spi_m_cmd_opcode cur_mcmd; int irq; + bool cs_flag; }; static int get_spi_clk_cfg(unsigned int speed_hz, @@ -95,7 +92,6 @@ static int get_spi_clk_cfg(unsigned int speed_hz, { unsigned long sclk_freq; unsigned int actual_hz; - struct geni_se *se = &mas->se; int ret; ret = geni_se_clk_freq_match(&mas->se, @@ -112,9 +108,12 @@ static int get_spi_clk_cfg(unsigned int speed_hz, dev_dbg(mas->dev, "req %u=>%u sclk %lu, idx %d, div %d\n", speed_hz, actual_hz, sclk_freq, *clk_idx, *clk_div); - ret = clk_set_rate(se->clk, sclk_freq); + ret = dev_pm_opp_set_rate(mas->dev, sclk_freq); if (ret) - dev_err(mas->dev, "clk_set_rate failed %d\n", ret); + dev_err(mas->dev, "dev_pm_opp_set_rate failed %d\n", ret); + else + mas->cur_sclk_hz = sclk_freq; + return ret; } @@ -122,24 +121,26 @@ static void handle_fifo_timeout(struct spi_master *spi, struct spi_message *msg) { struct spi_geni_master *mas = spi_master_get_devdata(spi); - unsigned long time_left, flags; + unsigned long time_left; struct geni_se *se = &mas->se; - spin_lock_irqsave(&mas->lock, flags); - reinit_completion(&mas->xfer_done); - mas->cur_mcmd = CMD_CANCEL; - geni_se_cancel_m_cmd(se); + spin_lock_irq(&mas->lock); + reinit_completion(&mas->cancel_done); writel(0, se->base + SE_GENI_TX_WATERMARK_REG); - spin_unlock_irqrestore(&mas->lock, flags); - time_left = wait_for_completion_timeout(&mas->xfer_done, HZ); + mas->cur_xfer = NULL; + geni_se_cancel_m_cmd(se); + spin_unlock_irq(&mas->lock); + + time_left = wait_for_completion_timeout(&mas->cancel_done, HZ); if (time_left) return; - spin_lock_irqsave(&mas->lock, flags); - reinit_completion(&mas->xfer_done); + spin_lock_irq(&mas->lock); + reinit_completion(&mas->abort_done); geni_se_abort_m_cmd(se); - spin_unlock_irqrestore(&mas->lock, flags); - time_left = wait_for_completion_timeout(&mas->xfer_done, HZ); + spin_unlock_irq(&mas->lock); + + time_left = wait_for_completion_timeout(&mas->abort_done, HZ); if (!time_left) dev_err(mas->dev, "Failed to cancel/abort m_cmd\n"); } @@ -151,18 +152,24 @@ static void spi_geni_set_cs(struct spi_device *slv, bool set_flag) struct geni_se *se = &mas->se; unsigned long time_left; - reinit_completion(&mas->xfer_done); - pm_runtime_get_sync(mas->dev); if (!(slv->mode & SPI_CS_HIGH)) set_flag = !set_flag; - mas->cur_mcmd = CMD_CS; + if (set_flag == mas->cs_flag) + return; + + mas->cs_flag = set_flag; + + pm_runtime_get_sync(mas->dev); + spin_lock_irq(&mas->lock); + reinit_completion(&mas->cs_done); if (set_flag) geni_se_setup_m_cmd(se, SPI_CS_ASSERT, 0); else geni_se_setup_m_cmd(se, SPI_CS_DEASSERT, 0); + spin_unlock_irq(&mas->lock); - time_left = wait_for_completion_timeout(&mas->xfer_done, HZ); + time_left = wait_for_completion_timeout(&mas->cs_done, HZ); if (!time_left) handle_fifo_timeout(spi, NULL); @@ -177,8 +184,6 @@ static void spi_setup_word_len(struct spi_geni_master *mas, u16 mode, struct geni_se *se = &mas->se; u32 word_len; - word_len = readl(se->base + SE_SPI_WORD_LEN); - /* * If bits_per_word isn't a byte aligned value, set the packing to be * 1 SPI word per FIFO word. @@ -187,74 +192,94 @@ static void spi_setup_word_len(struct spi_geni_master *mas, u16 mode, pack_words = mas->fifo_width_bits / bits_per_word; else pack_words = 1; - word_len &= ~WORD_LEN_MSK; - word_len |= ((bits_per_word - MIN_WORD_LEN) & WORD_LEN_MSK); geni_se_config_packing(&mas->se, bits_per_word, pack_words, msb_first, true, true); + word_len = (bits_per_word - MIN_WORD_LEN) & WORD_LEN_MSK; writel(word_len, se->base + SE_SPI_WORD_LEN); } -static int setup_fifo_params(struct spi_device *spi_slv, - struct spi_master *spi) +static int geni_spi_set_clock_and_bw(struct spi_geni_master *mas, + unsigned long clk_hz) { - struct spi_geni_master *mas = spi_master_get_devdata(spi); + u32 clk_sel, m_clk_cfg, idx, div; struct geni_se *se = &mas->se; - u32 loopback_cfg, cpol, cpha, demux_output_inv; - u32 demux_sel, clk_sel, m_clk_cfg, idx, div; int ret; - loopback_cfg = readl(se->base + SE_SPI_LOOPBACK); - cpol = readl(se->base + SE_SPI_CPOL); - cpha = readl(se->base + SE_SPI_CPHA); - demux_output_inv = 0; - loopback_cfg &= ~LOOPBACK_MSK; - cpol &= ~CPOL; - cpha &= ~CPHA; - - if (spi_slv->mode & SPI_LOOP) - loopback_cfg |= LOOPBACK_ENABLE; - - if (spi_slv->mode & SPI_CPOL) - cpol |= CPOL; - - if (spi_slv->mode & SPI_CPHA) - cpha |= CPHA; - - if (spi_slv->mode & SPI_CS_HIGH) - demux_output_inv = BIT(spi_slv->chip_select); - - demux_sel = spi_slv->chip_select; - mas->cur_speed_hz = spi_slv->max_speed_hz; - mas->cur_bits_per_word = spi_slv->bits_per_word; + if (clk_hz == mas->cur_speed_hz) + return 0; - ret = get_spi_clk_cfg(mas->cur_speed_hz, mas, &idx, &div); + ret = get_spi_clk_cfg(clk_hz, mas, &idx, &div); if (ret) { - dev_err(mas->dev, "Err setting clks ret(%d) for %ld\n", - ret, mas->cur_speed_hz); + dev_err(mas->dev, "Err setting clk to %lu: %d\n", clk_hz, ret); return ret; } + /* + * SPI core clock gets configured with the requested frequency + * or the frequency closer to the requested frequency. + * For that reason requested frequency is stored in the + * cur_speed_hz and referred in the consecutive transfer instead + * of calling clk_get_rate() API. + */ + mas->cur_speed_hz = clk_hz; + clk_sel = idx & CLK_SEL_MSK; m_clk_cfg = (div << CLK_DIV_SHFT) | SER_CLK_EN; - spi_setup_word_len(mas, spi_slv->mode, spi_slv->bits_per_word); - writel(loopback_cfg, se->base + SE_SPI_LOOPBACK); - writel(demux_sel, se->base + SE_SPI_DEMUX_SEL); - writel(cpha, se->base + SE_SPI_CPHA); - writel(cpol, se->base + SE_SPI_CPOL); - writel(demux_output_inv, se->base + SE_SPI_DEMUX_OUTPUT_INV); writel(clk_sel, se->base + SE_GENI_CLK_SEL); writel(m_clk_cfg, se->base + GENI_SER_M_CLK_CFG); + + /* Set BW quota for CPU as driver supports FIFO mode only. */ + se->icc_paths[CPU_TO_GENI].avg_bw = Bps_to_icc(mas->cur_speed_hz); + ret = geni_icc_set_bw(se); + if (ret) + return ret; + return 0; } +static int setup_fifo_params(struct spi_device *spi_slv, + struct spi_master *spi) +{ + struct spi_geni_master *mas = spi_master_get_devdata(spi); + struct geni_se *se = &mas->se; + u32 loopback_cfg = 0, cpol = 0, cpha = 0, demux_output_inv = 0; + u32 demux_sel; + + if (mas->last_mode != spi_slv->mode) { + if (spi_slv->mode & SPI_LOOP) + loopback_cfg = LOOPBACK_ENABLE; + + if (spi_slv->mode & SPI_CPOL) + cpol = CPOL; + + if (spi_slv->mode & SPI_CPHA) + cpha = CPHA; + + if (spi_slv->mode & SPI_CS_HIGH) + demux_output_inv = BIT(spi_slv->chip_select); + + demux_sel = spi_slv->chip_select; + mas->cur_bits_per_word = spi_slv->bits_per_word; + + spi_setup_word_len(mas, spi_slv->mode, spi_slv->bits_per_word); + writel(loopback_cfg, se->base + SE_SPI_LOOPBACK); + writel(demux_sel, se->base + SE_SPI_DEMUX_SEL); + writel(cpha, se->base + SE_SPI_CPHA); + writel(cpol, se->base + SE_SPI_CPOL); + writel(demux_output_inv, se->base + SE_SPI_DEMUX_OUTPUT_INV); + + mas->last_mode = spi_slv->mode; + } + + return geni_spi_set_clock_and_bw(mas, spi_slv->max_speed_hz); +} + static int spi_geni_prepare_message(struct spi_master *spi, struct spi_message *spi_msg) { int ret; struct spi_geni_master *mas = spi_master_get_devdata(spi); - struct geni_se *se = &mas->se; - geni_se_select_mode(se, GENI_SE_FIFO); ret = setup_fifo_params(spi_msg->spi, spi); if (ret) dev_err(mas->dev, "Couldn't select mode %d\n", ret); @@ -283,7 +308,7 @@ static int spi_geni_init(struct spi_geni_master *mas) * Hardware programming guide suggests to configure * RX FIFO RFR level to fifo_depth-2. */ - geni_se_init(se, 0x0, mas->tx_fifo_depth - 2); + geni_se_init(se, mas->tx_fifo_depth / 2, mas->tx_fifo_depth - 2); /* Transmit an entire FIFO worth of data per IRQ */ mas->tx_wm = 1; ver = geni_se_get_qup_hw_version(se); @@ -295,6 +320,8 @@ static int spi_geni_init(struct spi_geni_master *mas) else mas->oversampling = 1; + geni_se_select_mode(se, GENI_SE_FIFO); + pm_runtime_put(mas->dev); return 0; } @@ -306,6 +333,22 @@ static void setup_fifo_xfer(struct spi_transfer *xfer, u32 m_cmd = 0; u32 spi_tx_cfg, len; struct geni_se *se = &mas->se; + int ret; + + /* + * Ensure that our interrupt handler isn't still running from some + * prior command before we start messing with the hardware behind + * its back. We don't need to _keep_ the lock here since we're only + * worried about racing with out interrupt handler. The SPI core + * already handles making sure that we're not trying to do two + * transfers at once or setting a chip select and doing a transfer + * concurrently. + * + * NOTE: we actually _can't_ hold the lock here because possibly we + * might call clk_set_rate() which needs to be able to sleep. + */ + spin_lock_irq(&mas->lock); + spin_unlock_irq(&mas->lock); spi_tx_cfg = readl(se->base + SE_SPI_TRANS_CFG); if (xfer->bits_per_word != mas->cur_bits_per_word) { @@ -314,38 +357,12 @@ static void setup_fifo_xfer(struct spi_transfer *xfer, } /* Speed and bits per word can be overridden per transfer */ - if (xfer->speed_hz != mas->cur_speed_hz) { - int ret; - u32 clk_sel, m_clk_cfg; - unsigned int idx, div; - - ret = get_spi_clk_cfg(xfer->speed_hz, mas, &idx, &div); - if (ret) { - dev_err(mas->dev, "Err setting clks:%d\n", ret); - return; - } - /* - * SPI core clock gets configured with the requested frequency - * or the frequency closer to the requested frequency. - * For that reason requested frequency is stored in the - * cur_speed_hz and referred in the consecutive transfer instead - * of calling clk_get_rate() API. - */ - mas->cur_speed_hz = xfer->speed_hz; - clk_sel = idx & CLK_SEL_MSK; - m_clk_cfg = (div << CLK_DIV_SHFT) | SER_CLK_EN; - writel(clk_sel, se->base + SE_GENI_CLK_SEL); - writel(m_clk_cfg, se->base + GENI_SER_M_CLK_CFG); - } + ret = geni_spi_set_clock_and_bw(mas, xfer->speed_hz); + if (ret) + return; mas->tx_rem_bytes = 0; mas->rx_rem_bytes = 0; - if (xfer->tx_buf && xfer->rx_buf) - m_cmd = SPI_FULL_DUPLEX; - else if (xfer->tx_buf) - m_cmd = SPI_TX_ONLY; - else if (xfer->rx_buf) - m_cmd = SPI_RX_ONLY; spi_tx_cfg &= ~CS_TOGGLE; @@ -356,17 +373,24 @@ static void setup_fifo_xfer(struct spi_transfer *xfer, len &= TRANS_LEN_MSK; mas->cur_xfer = xfer; - if (m_cmd & SPI_TX_ONLY) { + if (xfer->tx_buf) { + m_cmd |= SPI_TX_ONLY; mas->tx_rem_bytes = xfer->len; writel(len, se->base + SE_SPI_TX_TRANS_LEN); } - if (m_cmd & SPI_RX_ONLY) { + if (xfer->rx_buf) { + m_cmd |= SPI_RX_ONLY; writel(len, se->base + SE_SPI_RX_TRANS_LEN); mas->rx_rem_bytes = xfer->len; } writel(spi_tx_cfg, se->base + SE_SPI_TRANS_CFG); - mas->cur_mcmd = CMD_XFER; + + /* + * Lock around right before we start the transfer since our + * interrupt could come in at any time now. + */ + spin_lock_irq(&mas->lock); geni_se_setup_m_cmd(se, m_cmd, FRAGMENTATION); /* @@ -376,6 +400,7 @@ static void setup_fifo_xfer(struct spi_transfer *xfer, */ if (m_cmd & SPI_TX_ONLY) writel(mas->tx_wm, se->base + SE_GENI_TX_WATERMARK_REG); + spin_unlock_irq(&mas->lock); } static int spi_geni_transfer_one(struct spi_master *spi, @@ -477,13 +502,17 @@ static irqreturn_t geni_spi_isr(int irq, void *data) struct spi_geni_master *mas = spi_master_get_devdata(spi); struct geni_se *se = &mas->se; u32 m_irq; - unsigned long flags; - if (mas->cur_mcmd == CMD_NONE) + m_irq = readl(se->base + SE_GENI_M_IRQ_STATUS); + if (!m_irq) return IRQ_NONE; - spin_lock_irqsave(&mas->lock, flags); - m_irq = readl(se->base + SE_GENI_M_IRQ_STATUS); + if (m_irq & (M_CMD_OVERRUN_EN | M_ILLEGAL_CMD_EN | M_CMD_FAILURE_EN | + M_RX_FIFO_RD_ERR_EN | M_RX_FIFO_WR_ERR_EN | + M_TX_FIFO_RD_ERR_EN | M_TX_FIFO_WR_ERR_EN)) + dev_warn(mas->dev, "Unexpected IRQ err status %#010x\n", m_irq); + + spin_lock(&mas->lock); if ((m_irq & M_RX_FIFO_WATERMARK_EN) || (m_irq & M_RX_FIFO_LAST_EN)) geni_spi_handle_rx(mas); @@ -492,39 +521,57 @@ static irqreturn_t geni_spi_isr(int irq, void *data) geni_spi_handle_tx(mas); if (m_irq & M_CMD_DONE_EN) { - if (mas->cur_mcmd == CMD_XFER) + if (mas->cur_xfer) { spi_finalize_current_transfer(spi); - else if (mas->cur_mcmd == CMD_CS) - complete(&mas->xfer_done); - mas->cur_mcmd = CMD_NONE; - /* - * If this happens, then a CMD_DONE came before all the Tx - * buffer bytes were sent out. This is unusual, log this - * condition and disable the WM interrupt to prevent the - * system from stalling due an interrupt storm. - * If this happens when all Rx bytes haven't been received, log - * the condition. - * The only known time this can happen is if bits_per_word != 8 - * and some registers that expect xfer lengths in num spi_words - * weren't written correctly. - */ - if (mas->tx_rem_bytes) { - writel(0, se->base + SE_GENI_TX_WATERMARK_REG); - dev_err(mas->dev, "Premature done. tx_rem = %d bpw%d\n", - mas->tx_rem_bytes, mas->cur_bits_per_word); + mas->cur_xfer = NULL; + /* + * If this happens, then a CMD_DONE came before all the + * Tx buffer bytes were sent out. This is unusual, log + * this condition and disable the WM interrupt to + * prevent the system from stalling due an interrupt + * storm. + * + * If this happens when all Rx bytes haven't been + * received, log the condition. The only known time + * this can happen is if bits_per_word != 8 and some + * registers that expect xfer lengths in num spi_words + * weren't written correctly. + */ + if (mas->tx_rem_bytes) { + writel(0, se->base + SE_GENI_TX_WATERMARK_REG); + dev_err(mas->dev, "Premature done. tx_rem = %d bpw%d\n", + mas->tx_rem_bytes, mas->cur_bits_per_word); + } + if (mas->rx_rem_bytes) + dev_err(mas->dev, "Premature done. rx_rem = %d bpw%d\n", + mas->rx_rem_bytes, mas->cur_bits_per_word); + } else { + complete(&mas->cs_done); } - if (mas->rx_rem_bytes) - dev_err(mas->dev, "Premature done. rx_rem = %d bpw%d\n", - mas->rx_rem_bytes, mas->cur_bits_per_word); } - if ((m_irq & M_CMD_CANCEL_EN) || (m_irq & M_CMD_ABORT_EN)) { - mas->cur_mcmd = CMD_NONE; - complete(&mas->xfer_done); - } + if (m_irq & M_CMD_CANCEL_EN) + complete(&mas->cancel_done); + if (m_irq & M_CMD_ABORT_EN) + complete(&mas->abort_done); + /* + * It's safe or a good idea to Ack all of our our interrupts at the + * end of the function. Specifically: + * - M_CMD_DONE_EN / M_RX_FIFO_LAST_EN: Edge triggered interrupts and + * clearing Acks. Clearing at the end relies on nobody else having + * started a new transfer yet or else we could be clearing _their_ + * done bit, but everyone grabs the spinlock before starting a new + * transfer. + * - M_RX_FIFO_WATERMARK_EN / M_TX_FIFO_WATERMARK_EN: These appear + * to be "latched level" interrupts so it's important to clear them + * _after_ you've handled the condition and always safe to do so + * since they'll re-assert if they're still happening. + */ writel(m_irq, se->base + SE_GENI_M_IRQ_CLEAR); - spin_unlock_irqrestore(&mas->lock, flags); + + spin_unlock(&mas->lock); + return IRQ_HANDLED; } @@ -561,6 +608,17 @@ static int spi_geni_probe(struct platform_device *pdev) mas->se.wrapper = dev_get_drvdata(dev->parent); mas->se.base = base; mas->se.clk = clk; + mas->se.opp_table = dev_pm_opp_set_clkname(&pdev->dev, "se"); + if (IS_ERR(mas->se.opp_table)) + return PTR_ERR(mas->se.opp_table); + /* OPP table is optional */ + ret = dev_pm_opp_of_add_table(&pdev->dev); + if (!ret) { + mas->se.has_opp_table = true; + } else if (ret != -ENODEV) { + dev_err(&pdev->dev, "invalid OPP table in device tree\n"); + return ret; + } spi->bus_num = -1; spi->dev.of_node = dev->of_node; @@ -574,10 +632,25 @@ static int spi_geni_probe(struct platform_device *pdev) spi->handle_err = handle_fifo_timeout; spi->set_cs = spi_geni_set_cs; - init_completion(&mas->xfer_done); + init_completion(&mas->cs_done); + init_completion(&mas->cancel_done); + init_completion(&mas->abort_done); spin_lock_init(&mas->lock); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, 250); pm_runtime_enable(dev); + ret = geni_icc_get(&mas->se, NULL); + if (ret) + goto spi_geni_probe_runtime_disable; + /* Set the bus quota to a reasonable value for register access */ + mas->se.icc_paths[GENI_TO_CORE].avg_bw = Bps_to_icc(CORE_2X_50_MHZ); + mas->se.icc_paths[CPU_TO_GENI].avg_bw = GENI_DEFAULT_BW; + + ret = geni_icc_set_bw(&mas->se); + if (ret) + goto spi_geni_probe_runtime_disable; + ret = spi_geni_init(mas); if (ret) goto spi_geni_probe_runtime_disable; @@ -596,6 +669,9 @@ spi_geni_probe_free_irq: spi_geni_probe_runtime_disable: pm_runtime_disable(dev); spi_master_put(spi); + if (mas->se.has_opp_table) + dev_pm_opp_of_remove_table(&pdev->dev); + dev_pm_opp_put_clkname(mas->se.opp_table); return ret; } @@ -609,6 +685,9 @@ static int spi_geni_remove(struct platform_device *pdev) free_irq(mas->irq, spi); pm_runtime_disable(&pdev->dev); + if (mas->se.has_opp_table) + dev_pm_opp_of_remove_table(&pdev->dev); + dev_pm_opp_put_clkname(mas->se.opp_table); return 0; } @@ -616,16 +695,33 @@ static int __maybe_unused spi_geni_runtime_suspend(struct device *dev) { struct spi_master *spi = dev_get_drvdata(dev); struct spi_geni_master *mas = spi_master_get_devdata(spi); + int ret; - return geni_se_resources_off(&mas->se); + /* Drop the performance state vote */ + dev_pm_opp_set_rate(dev, 0); + + ret = geni_se_resources_off(&mas->se); + if (ret) + return ret; + + return geni_icc_disable(&mas->se); } static int __maybe_unused spi_geni_runtime_resume(struct device *dev) { struct spi_master *spi = dev_get_drvdata(dev); struct spi_geni_master *mas = spi_master_get_devdata(spi); + int ret; + + ret = geni_icc_enable(&mas->se); + if (ret) + return ret; + + ret = geni_se_resources_on(&mas->se); + if (ret) + return ret; - return geni_se_resources_on(&mas->se); + return dev_pm_opp_set_rate(mas->dev, mas->cur_sclk_hz); } static int __maybe_unused spi_geni_suspend(struct device *dev) |