162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// Copyright (c) 2017-2018, The Linux foundation. All rights reserved. 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/clk.h> 562306a36Sopenharmony_ci#include <linux/dmaengine.h> 662306a36Sopenharmony_ci#include <linux/dma-mapping.h> 762306a36Sopenharmony_ci#include <linux/dma/qcom-gpi-dma.h> 862306a36Sopenharmony_ci#include <linux/interrupt.h> 962306a36Sopenharmony_ci#include <linux/io.h> 1062306a36Sopenharmony_ci#include <linux/log2.h> 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/platform_device.h> 1362306a36Sopenharmony_ci#include <linux/pm_opp.h> 1462306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1562306a36Sopenharmony_ci#include <linux/property.h> 1662306a36Sopenharmony_ci#include <linux/soc/qcom/geni-se.h> 1762306a36Sopenharmony_ci#include <linux/spi/spi.h> 1862306a36Sopenharmony_ci#include <linux/spinlock.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/* SPI SE specific registers and respective register fields */ 2162306a36Sopenharmony_ci#define SE_SPI_CPHA 0x224 2262306a36Sopenharmony_ci#define CPHA BIT(0) 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define SE_SPI_LOOPBACK 0x22c 2562306a36Sopenharmony_ci#define LOOPBACK_ENABLE 0x1 2662306a36Sopenharmony_ci#define NORMAL_MODE 0x0 2762306a36Sopenharmony_ci#define LOOPBACK_MSK GENMASK(1, 0) 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define SE_SPI_CPOL 0x230 3062306a36Sopenharmony_ci#define CPOL BIT(2) 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define SE_SPI_DEMUX_OUTPUT_INV 0x24c 3362306a36Sopenharmony_ci#define CS_DEMUX_OUTPUT_INV_MSK GENMASK(3, 0) 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#define SE_SPI_DEMUX_SEL 0x250 3662306a36Sopenharmony_ci#define CS_DEMUX_OUTPUT_SEL GENMASK(3, 0) 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define SE_SPI_TRANS_CFG 0x25c 3962306a36Sopenharmony_ci#define CS_TOGGLE BIT(1) 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#define SE_SPI_WORD_LEN 0x268 4262306a36Sopenharmony_ci#define WORD_LEN_MSK GENMASK(9, 0) 4362306a36Sopenharmony_ci#define MIN_WORD_LEN 4 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#define SE_SPI_TX_TRANS_LEN 0x26c 4662306a36Sopenharmony_ci#define SE_SPI_RX_TRANS_LEN 0x270 4762306a36Sopenharmony_ci#define TRANS_LEN_MSK GENMASK(23, 0) 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#define SE_SPI_PRE_POST_CMD_DLY 0x274 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci#define SE_SPI_DELAY_COUNTERS 0x278 5262306a36Sopenharmony_ci#define SPI_INTER_WORDS_DELAY_MSK GENMASK(9, 0) 5362306a36Sopenharmony_ci#define SPI_CS_CLK_DELAY_MSK GENMASK(19, 10) 5462306a36Sopenharmony_ci#define SPI_CS_CLK_DELAY_SHFT 10 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#define SE_SPI_SLAVE_EN (0x2BC) 5762306a36Sopenharmony_ci#define SPI_SLAVE_EN BIT(0) 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci/* M_CMD OP codes for SPI */ 6062306a36Sopenharmony_ci#define SPI_TX_ONLY 1 6162306a36Sopenharmony_ci#define SPI_RX_ONLY 2 6262306a36Sopenharmony_ci#define SPI_TX_RX 7 6362306a36Sopenharmony_ci#define SPI_CS_ASSERT 8 6462306a36Sopenharmony_ci#define SPI_CS_DEASSERT 9 6562306a36Sopenharmony_ci#define SPI_SCK_ONLY 10 6662306a36Sopenharmony_ci/* M_CMD params for SPI */ 6762306a36Sopenharmony_ci#define SPI_PRE_CMD_DELAY BIT(0) 6862306a36Sopenharmony_ci#define TIMESTAMP_BEFORE BIT(1) 6962306a36Sopenharmony_ci#define FRAGMENTATION BIT(2) 7062306a36Sopenharmony_ci#define TIMESTAMP_AFTER BIT(3) 7162306a36Sopenharmony_ci#define POST_CMD_DELAY BIT(4) 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci#define GSI_LOOPBACK_EN BIT(0) 7462306a36Sopenharmony_ci#define GSI_CS_TOGGLE BIT(3) 7562306a36Sopenharmony_ci#define GSI_CPHA BIT(4) 7662306a36Sopenharmony_ci#define GSI_CPOL BIT(5) 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistruct spi_geni_master { 7962306a36Sopenharmony_ci struct geni_se se; 8062306a36Sopenharmony_ci struct device *dev; 8162306a36Sopenharmony_ci u32 tx_fifo_depth; 8262306a36Sopenharmony_ci u32 fifo_width_bits; 8362306a36Sopenharmony_ci u32 tx_wm; 8462306a36Sopenharmony_ci u32 last_mode; 8562306a36Sopenharmony_ci unsigned long cur_speed_hz; 8662306a36Sopenharmony_ci unsigned long cur_sclk_hz; 8762306a36Sopenharmony_ci unsigned int cur_bits_per_word; 8862306a36Sopenharmony_ci unsigned int tx_rem_bytes; 8962306a36Sopenharmony_ci unsigned int rx_rem_bytes; 9062306a36Sopenharmony_ci const struct spi_transfer *cur_xfer; 9162306a36Sopenharmony_ci struct completion cs_done; 9262306a36Sopenharmony_ci struct completion cancel_done; 9362306a36Sopenharmony_ci struct completion abort_done; 9462306a36Sopenharmony_ci struct completion tx_reset_done; 9562306a36Sopenharmony_ci struct completion rx_reset_done; 9662306a36Sopenharmony_ci unsigned int oversampling; 9762306a36Sopenharmony_ci spinlock_t lock; 9862306a36Sopenharmony_ci int irq; 9962306a36Sopenharmony_ci bool cs_flag; 10062306a36Sopenharmony_ci bool abort_failed; 10162306a36Sopenharmony_ci struct dma_chan *tx; 10262306a36Sopenharmony_ci struct dma_chan *rx; 10362306a36Sopenharmony_ci int cur_xfer_mode; 10462306a36Sopenharmony_ci}; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic void spi_slv_setup(struct spi_geni_master *mas) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci struct geni_se *se = &mas->se; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci writel(SPI_SLAVE_EN, se->base + SE_SPI_SLAVE_EN); 11162306a36Sopenharmony_ci writel(GENI_IO_MUX_0_EN, se->base + GENI_OUTPUT_CTRL); 11262306a36Sopenharmony_ci writel(START_TRIGGER, se->base + SE_GENI_CFG_SEQ_START); 11362306a36Sopenharmony_ci dev_dbg(mas->dev, "spi slave setup done\n"); 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic int get_spi_clk_cfg(unsigned int speed_hz, 11762306a36Sopenharmony_ci struct spi_geni_master *mas, 11862306a36Sopenharmony_ci unsigned int *clk_idx, 11962306a36Sopenharmony_ci unsigned int *clk_div) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci unsigned long sclk_freq; 12262306a36Sopenharmony_ci unsigned int actual_hz; 12362306a36Sopenharmony_ci int ret; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci ret = geni_se_clk_freq_match(&mas->se, 12662306a36Sopenharmony_ci speed_hz * mas->oversampling, 12762306a36Sopenharmony_ci clk_idx, &sclk_freq, false); 12862306a36Sopenharmony_ci if (ret) { 12962306a36Sopenharmony_ci dev_err(mas->dev, "Failed(%d) to find src clk for %dHz\n", 13062306a36Sopenharmony_ci ret, speed_hz); 13162306a36Sopenharmony_ci return ret; 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci *clk_div = DIV_ROUND_UP(sclk_freq, mas->oversampling * speed_hz); 13562306a36Sopenharmony_ci actual_hz = sclk_freq / (mas->oversampling * *clk_div); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci dev_dbg(mas->dev, "req %u=>%u sclk %lu, idx %d, div %d\n", speed_hz, 13862306a36Sopenharmony_ci actual_hz, sclk_freq, *clk_idx, *clk_div); 13962306a36Sopenharmony_ci ret = dev_pm_opp_set_rate(mas->dev, sclk_freq); 14062306a36Sopenharmony_ci if (ret) 14162306a36Sopenharmony_ci dev_err(mas->dev, "dev_pm_opp_set_rate failed %d\n", ret); 14262306a36Sopenharmony_ci else 14362306a36Sopenharmony_ci mas->cur_sclk_hz = sclk_freq; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci return ret; 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic void handle_se_timeout(struct spi_master *spi, 14962306a36Sopenharmony_ci struct spi_message *msg) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci struct spi_geni_master *mas = spi_master_get_devdata(spi); 15262306a36Sopenharmony_ci unsigned long time_left; 15362306a36Sopenharmony_ci struct geni_se *se = &mas->se; 15462306a36Sopenharmony_ci const struct spi_transfer *xfer; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci spin_lock_irq(&mas->lock); 15762306a36Sopenharmony_ci if (mas->cur_xfer_mode == GENI_SE_FIFO) 15862306a36Sopenharmony_ci writel(0, se->base + SE_GENI_TX_WATERMARK_REG); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci xfer = mas->cur_xfer; 16162306a36Sopenharmony_ci mas->cur_xfer = NULL; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci if (spi->slave) { 16462306a36Sopenharmony_ci /* 16562306a36Sopenharmony_ci * skip CMD Cancel sequnece since spi slave 16662306a36Sopenharmony_ci * doesn`t support CMD Cancel sequnece 16762306a36Sopenharmony_ci */ 16862306a36Sopenharmony_ci spin_unlock_irq(&mas->lock); 16962306a36Sopenharmony_ci goto unmap_if_dma; 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci reinit_completion(&mas->cancel_done); 17362306a36Sopenharmony_ci geni_se_cancel_m_cmd(se); 17462306a36Sopenharmony_ci spin_unlock_irq(&mas->lock); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci time_left = wait_for_completion_timeout(&mas->cancel_done, HZ); 17762306a36Sopenharmony_ci if (time_left) 17862306a36Sopenharmony_ci goto unmap_if_dma; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci spin_lock_irq(&mas->lock); 18162306a36Sopenharmony_ci reinit_completion(&mas->abort_done); 18262306a36Sopenharmony_ci geni_se_abort_m_cmd(se); 18362306a36Sopenharmony_ci spin_unlock_irq(&mas->lock); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci time_left = wait_for_completion_timeout(&mas->abort_done, HZ); 18662306a36Sopenharmony_ci if (!time_left) { 18762306a36Sopenharmony_ci dev_err(mas->dev, "Failed to cancel/abort m_cmd\n"); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci /* 19062306a36Sopenharmony_ci * No need for a lock since SPI core has a lock and we never 19162306a36Sopenharmony_ci * access this from an interrupt. 19262306a36Sopenharmony_ci */ 19362306a36Sopenharmony_ci mas->abort_failed = true; 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ciunmap_if_dma: 19762306a36Sopenharmony_ci if (mas->cur_xfer_mode == GENI_SE_DMA) { 19862306a36Sopenharmony_ci if (xfer) { 19962306a36Sopenharmony_ci if (xfer->tx_buf) { 20062306a36Sopenharmony_ci spin_lock_irq(&mas->lock); 20162306a36Sopenharmony_ci reinit_completion(&mas->tx_reset_done); 20262306a36Sopenharmony_ci writel(1, se->base + SE_DMA_TX_FSM_RST); 20362306a36Sopenharmony_ci spin_unlock_irq(&mas->lock); 20462306a36Sopenharmony_ci time_left = wait_for_completion_timeout(&mas->tx_reset_done, HZ); 20562306a36Sopenharmony_ci if (!time_left) 20662306a36Sopenharmony_ci dev_err(mas->dev, "DMA TX RESET failed\n"); 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci if (xfer->rx_buf) { 20962306a36Sopenharmony_ci spin_lock_irq(&mas->lock); 21062306a36Sopenharmony_ci reinit_completion(&mas->rx_reset_done); 21162306a36Sopenharmony_ci writel(1, se->base + SE_DMA_RX_FSM_RST); 21262306a36Sopenharmony_ci spin_unlock_irq(&mas->lock); 21362306a36Sopenharmony_ci time_left = wait_for_completion_timeout(&mas->rx_reset_done, HZ); 21462306a36Sopenharmony_ci if (!time_left) 21562306a36Sopenharmony_ci dev_err(mas->dev, "DMA RX RESET failed\n"); 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci } else { 21862306a36Sopenharmony_ci /* 21962306a36Sopenharmony_ci * This can happen if a timeout happened and we had to wait 22062306a36Sopenharmony_ci * for lock in this function because isr was holding the lock 22162306a36Sopenharmony_ci * and handling transfer completion at that time. 22262306a36Sopenharmony_ci */ 22362306a36Sopenharmony_ci dev_warn(mas->dev, "Cancel/Abort on completed SPI transfer\n"); 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic void handle_gpi_timeout(struct spi_master *spi, struct spi_message *msg) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci struct spi_geni_master *mas = spi_master_get_devdata(spi); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci dmaengine_terminate_sync(mas->tx); 23362306a36Sopenharmony_ci dmaengine_terminate_sync(mas->rx); 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic void spi_geni_handle_err(struct spi_master *spi, struct spi_message *msg) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci struct spi_geni_master *mas = spi_master_get_devdata(spi); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci switch (mas->cur_xfer_mode) { 24162306a36Sopenharmony_ci case GENI_SE_FIFO: 24262306a36Sopenharmony_ci case GENI_SE_DMA: 24362306a36Sopenharmony_ci handle_se_timeout(spi, msg); 24462306a36Sopenharmony_ci break; 24562306a36Sopenharmony_ci case GENI_GPI_DMA: 24662306a36Sopenharmony_ci handle_gpi_timeout(spi, msg); 24762306a36Sopenharmony_ci break; 24862306a36Sopenharmony_ci default: 24962306a36Sopenharmony_ci dev_err(mas->dev, "Abort on Mode:%d not supported", mas->cur_xfer_mode); 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistatic bool spi_geni_is_abort_still_pending(struct spi_geni_master *mas) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci struct geni_se *se = &mas->se; 25662306a36Sopenharmony_ci u32 m_irq, m_irq_en; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci if (!mas->abort_failed) 25962306a36Sopenharmony_ci return false; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci /* 26262306a36Sopenharmony_ci * The only known case where a transfer times out and then a cancel 26362306a36Sopenharmony_ci * times out then an abort times out is if something is blocking our 26462306a36Sopenharmony_ci * interrupt handler from running. Avoid starting any new transfers 26562306a36Sopenharmony_ci * until that sorts itself out. 26662306a36Sopenharmony_ci */ 26762306a36Sopenharmony_ci spin_lock_irq(&mas->lock); 26862306a36Sopenharmony_ci m_irq = readl(se->base + SE_GENI_M_IRQ_STATUS); 26962306a36Sopenharmony_ci m_irq_en = readl(se->base + SE_GENI_M_IRQ_EN); 27062306a36Sopenharmony_ci spin_unlock_irq(&mas->lock); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci if (m_irq & m_irq_en) { 27362306a36Sopenharmony_ci dev_err(mas->dev, "Interrupts pending after abort: %#010x\n", 27462306a36Sopenharmony_ci m_irq & m_irq_en); 27562306a36Sopenharmony_ci return true; 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci /* 27962306a36Sopenharmony_ci * If we're here the problem resolved itself so no need to check more 28062306a36Sopenharmony_ci * on future transfers. 28162306a36Sopenharmony_ci */ 28262306a36Sopenharmony_ci mas->abort_failed = false; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci return false; 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_cistatic void spi_geni_set_cs(struct spi_device *slv, bool set_flag) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci struct spi_geni_master *mas = spi_master_get_devdata(slv->master); 29062306a36Sopenharmony_ci struct spi_master *spi = dev_get_drvdata(mas->dev); 29162306a36Sopenharmony_ci struct geni_se *se = &mas->se; 29262306a36Sopenharmony_ci unsigned long time_left; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci if (!(slv->mode & SPI_CS_HIGH)) 29562306a36Sopenharmony_ci set_flag = !set_flag; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci if (set_flag == mas->cs_flag) 29862306a36Sopenharmony_ci return; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci pm_runtime_get_sync(mas->dev); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci if (spi_geni_is_abort_still_pending(mas)) { 30362306a36Sopenharmony_ci dev_err(mas->dev, "Can't set chip select\n"); 30462306a36Sopenharmony_ci goto exit; 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci spin_lock_irq(&mas->lock); 30862306a36Sopenharmony_ci if (mas->cur_xfer) { 30962306a36Sopenharmony_ci dev_err(mas->dev, "Can't set CS when prev xfer running\n"); 31062306a36Sopenharmony_ci spin_unlock_irq(&mas->lock); 31162306a36Sopenharmony_ci goto exit; 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci mas->cs_flag = set_flag; 31562306a36Sopenharmony_ci /* set xfer_mode to FIFO to complete cs_done in isr */ 31662306a36Sopenharmony_ci mas->cur_xfer_mode = GENI_SE_FIFO; 31762306a36Sopenharmony_ci geni_se_select_mode(se, mas->cur_xfer_mode); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci reinit_completion(&mas->cs_done); 32062306a36Sopenharmony_ci if (set_flag) 32162306a36Sopenharmony_ci geni_se_setup_m_cmd(se, SPI_CS_ASSERT, 0); 32262306a36Sopenharmony_ci else 32362306a36Sopenharmony_ci geni_se_setup_m_cmd(se, SPI_CS_DEASSERT, 0); 32462306a36Sopenharmony_ci spin_unlock_irq(&mas->lock); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci time_left = wait_for_completion_timeout(&mas->cs_done, HZ); 32762306a36Sopenharmony_ci if (!time_left) { 32862306a36Sopenharmony_ci dev_warn(mas->dev, "Timeout setting chip select\n"); 32962306a36Sopenharmony_ci handle_se_timeout(spi, NULL); 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ciexit: 33362306a36Sopenharmony_ci pm_runtime_put(mas->dev); 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cistatic void spi_setup_word_len(struct spi_geni_master *mas, u16 mode, 33762306a36Sopenharmony_ci unsigned int bits_per_word) 33862306a36Sopenharmony_ci{ 33962306a36Sopenharmony_ci unsigned int pack_words; 34062306a36Sopenharmony_ci bool msb_first = (mode & SPI_LSB_FIRST) ? false : true; 34162306a36Sopenharmony_ci struct geni_se *se = &mas->se; 34262306a36Sopenharmony_ci u32 word_len; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci /* 34562306a36Sopenharmony_ci * If bits_per_word isn't a byte aligned value, set the packing to be 34662306a36Sopenharmony_ci * 1 SPI word per FIFO word. 34762306a36Sopenharmony_ci */ 34862306a36Sopenharmony_ci if (!(mas->fifo_width_bits % bits_per_word)) 34962306a36Sopenharmony_ci pack_words = mas->fifo_width_bits / bits_per_word; 35062306a36Sopenharmony_ci else 35162306a36Sopenharmony_ci pack_words = 1; 35262306a36Sopenharmony_ci geni_se_config_packing(&mas->se, bits_per_word, pack_words, msb_first, 35362306a36Sopenharmony_ci true, true); 35462306a36Sopenharmony_ci word_len = (bits_per_word - MIN_WORD_LEN) & WORD_LEN_MSK; 35562306a36Sopenharmony_ci writel(word_len, se->base + SE_SPI_WORD_LEN); 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic int geni_spi_set_clock_and_bw(struct spi_geni_master *mas, 35962306a36Sopenharmony_ci unsigned long clk_hz) 36062306a36Sopenharmony_ci{ 36162306a36Sopenharmony_ci u32 clk_sel, m_clk_cfg, idx, div; 36262306a36Sopenharmony_ci struct geni_se *se = &mas->se; 36362306a36Sopenharmony_ci int ret; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci if (clk_hz == mas->cur_speed_hz) 36662306a36Sopenharmony_ci return 0; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci ret = get_spi_clk_cfg(clk_hz, mas, &idx, &div); 36962306a36Sopenharmony_ci if (ret) { 37062306a36Sopenharmony_ci dev_err(mas->dev, "Err setting clk to %lu: %d\n", clk_hz, ret); 37162306a36Sopenharmony_ci return ret; 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci /* 37562306a36Sopenharmony_ci * SPI core clock gets configured with the requested frequency 37662306a36Sopenharmony_ci * or the frequency closer to the requested frequency. 37762306a36Sopenharmony_ci * For that reason requested frequency is stored in the 37862306a36Sopenharmony_ci * cur_speed_hz and referred in the consecutive transfer instead 37962306a36Sopenharmony_ci * of calling clk_get_rate() API. 38062306a36Sopenharmony_ci */ 38162306a36Sopenharmony_ci mas->cur_speed_hz = clk_hz; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci clk_sel = idx & CLK_SEL_MSK; 38462306a36Sopenharmony_ci m_clk_cfg = (div << CLK_DIV_SHFT) | SER_CLK_EN; 38562306a36Sopenharmony_ci writel(clk_sel, se->base + SE_GENI_CLK_SEL); 38662306a36Sopenharmony_ci writel(m_clk_cfg, se->base + GENI_SER_M_CLK_CFG); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci /* Set BW quota for CPU as driver supports FIFO mode only. */ 38962306a36Sopenharmony_ci se->icc_paths[CPU_TO_GENI].avg_bw = Bps_to_icc(mas->cur_speed_hz); 39062306a36Sopenharmony_ci ret = geni_icc_set_bw(se); 39162306a36Sopenharmony_ci if (ret) 39262306a36Sopenharmony_ci return ret; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci return 0; 39562306a36Sopenharmony_ci} 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_cistatic int setup_fifo_params(struct spi_device *spi_slv, 39862306a36Sopenharmony_ci struct spi_master *spi) 39962306a36Sopenharmony_ci{ 40062306a36Sopenharmony_ci struct spi_geni_master *mas = spi_master_get_devdata(spi); 40162306a36Sopenharmony_ci struct geni_se *se = &mas->se; 40262306a36Sopenharmony_ci u32 loopback_cfg = 0, cpol = 0, cpha = 0, demux_output_inv = 0; 40362306a36Sopenharmony_ci u32 demux_sel; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci if (mas->last_mode != spi_slv->mode) { 40662306a36Sopenharmony_ci if (spi_slv->mode & SPI_LOOP) 40762306a36Sopenharmony_ci loopback_cfg = LOOPBACK_ENABLE; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci if (spi_slv->mode & SPI_CPOL) 41062306a36Sopenharmony_ci cpol = CPOL; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci if (spi_slv->mode & SPI_CPHA) 41362306a36Sopenharmony_ci cpha = CPHA; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci if (spi_slv->mode & SPI_CS_HIGH) 41662306a36Sopenharmony_ci demux_output_inv = BIT(spi_get_chipselect(spi_slv, 0)); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci demux_sel = spi_get_chipselect(spi_slv, 0); 41962306a36Sopenharmony_ci mas->cur_bits_per_word = spi_slv->bits_per_word; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci spi_setup_word_len(mas, spi_slv->mode, spi_slv->bits_per_word); 42262306a36Sopenharmony_ci writel(loopback_cfg, se->base + SE_SPI_LOOPBACK); 42362306a36Sopenharmony_ci writel(demux_sel, se->base + SE_SPI_DEMUX_SEL); 42462306a36Sopenharmony_ci writel(cpha, se->base + SE_SPI_CPHA); 42562306a36Sopenharmony_ci writel(cpol, se->base + SE_SPI_CPOL); 42662306a36Sopenharmony_ci writel(demux_output_inv, se->base + SE_SPI_DEMUX_OUTPUT_INV); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci mas->last_mode = spi_slv->mode; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci return geni_spi_set_clock_and_bw(mas, spi_slv->max_speed_hz); 43262306a36Sopenharmony_ci} 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_cistatic void 43562306a36Sopenharmony_cispi_gsi_callback_result(void *cb, const struct dmaengine_result *result) 43662306a36Sopenharmony_ci{ 43762306a36Sopenharmony_ci struct spi_master *spi = cb; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci spi->cur_msg->status = -EIO; 44062306a36Sopenharmony_ci if (result->result != DMA_TRANS_NOERROR) { 44162306a36Sopenharmony_ci dev_err(&spi->dev, "DMA txn failed: %d\n", result->result); 44262306a36Sopenharmony_ci spi_finalize_current_transfer(spi); 44362306a36Sopenharmony_ci return; 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci if (!result->residue) { 44762306a36Sopenharmony_ci spi->cur_msg->status = 0; 44862306a36Sopenharmony_ci dev_dbg(&spi->dev, "DMA txn completed\n"); 44962306a36Sopenharmony_ci } else { 45062306a36Sopenharmony_ci dev_err(&spi->dev, "DMA xfer has pending: %d\n", result->residue); 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci spi_finalize_current_transfer(spi); 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_cistatic int setup_gsi_xfer(struct spi_transfer *xfer, struct spi_geni_master *mas, 45762306a36Sopenharmony_ci struct spi_device *spi_slv, struct spi_master *spi) 45862306a36Sopenharmony_ci{ 45962306a36Sopenharmony_ci unsigned long flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK; 46062306a36Sopenharmony_ci struct dma_slave_config config = {}; 46162306a36Sopenharmony_ci struct gpi_spi_config peripheral = {}; 46262306a36Sopenharmony_ci struct dma_async_tx_descriptor *tx_desc, *rx_desc; 46362306a36Sopenharmony_ci int ret; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci config.peripheral_config = &peripheral; 46662306a36Sopenharmony_ci config.peripheral_size = sizeof(peripheral); 46762306a36Sopenharmony_ci peripheral.set_config = true; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci if (xfer->bits_per_word != mas->cur_bits_per_word || 47062306a36Sopenharmony_ci xfer->speed_hz != mas->cur_speed_hz) { 47162306a36Sopenharmony_ci mas->cur_bits_per_word = xfer->bits_per_word; 47262306a36Sopenharmony_ci mas->cur_speed_hz = xfer->speed_hz; 47362306a36Sopenharmony_ci } 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci if (xfer->tx_buf && xfer->rx_buf) { 47662306a36Sopenharmony_ci peripheral.cmd = SPI_DUPLEX; 47762306a36Sopenharmony_ci } else if (xfer->tx_buf) { 47862306a36Sopenharmony_ci peripheral.cmd = SPI_TX; 47962306a36Sopenharmony_ci peripheral.rx_len = 0; 48062306a36Sopenharmony_ci } else if (xfer->rx_buf) { 48162306a36Sopenharmony_ci peripheral.cmd = SPI_RX; 48262306a36Sopenharmony_ci if (!(mas->cur_bits_per_word % MIN_WORD_LEN)) { 48362306a36Sopenharmony_ci peripheral.rx_len = ((xfer->len << 3) / mas->cur_bits_per_word); 48462306a36Sopenharmony_ci } else { 48562306a36Sopenharmony_ci int bytes_per_word = (mas->cur_bits_per_word / BITS_PER_BYTE) + 1; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci peripheral.rx_len = (xfer->len / bytes_per_word); 48862306a36Sopenharmony_ci } 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci peripheral.loopback_en = !!(spi_slv->mode & SPI_LOOP); 49262306a36Sopenharmony_ci peripheral.clock_pol_high = !!(spi_slv->mode & SPI_CPOL); 49362306a36Sopenharmony_ci peripheral.data_pol_high = !!(spi_slv->mode & SPI_CPHA); 49462306a36Sopenharmony_ci peripheral.cs = spi_get_chipselect(spi_slv, 0); 49562306a36Sopenharmony_ci peripheral.pack_en = true; 49662306a36Sopenharmony_ci peripheral.word_len = xfer->bits_per_word - MIN_WORD_LEN; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci ret = get_spi_clk_cfg(mas->cur_speed_hz, mas, 49962306a36Sopenharmony_ci &peripheral.clk_src, &peripheral.clk_div); 50062306a36Sopenharmony_ci if (ret) { 50162306a36Sopenharmony_ci dev_err(mas->dev, "Err in get_spi_clk_cfg() :%d\n", ret); 50262306a36Sopenharmony_ci return ret; 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci if (!xfer->cs_change) { 50662306a36Sopenharmony_ci if (!list_is_last(&xfer->transfer_list, &spi->cur_msg->transfers)) 50762306a36Sopenharmony_ci peripheral.fragmentation = FRAGMENTATION; 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci if (peripheral.cmd & SPI_RX) { 51162306a36Sopenharmony_ci dmaengine_slave_config(mas->rx, &config); 51262306a36Sopenharmony_ci rx_desc = dmaengine_prep_slave_sg(mas->rx, xfer->rx_sg.sgl, xfer->rx_sg.nents, 51362306a36Sopenharmony_ci DMA_DEV_TO_MEM, flags); 51462306a36Sopenharmony_ci if (!rx_desc) { 51562306a36Sopenharmony_ci dev_err(mas->dev, "Err setting up rx desc\n"); 51662306a36Sopenharmony_ci return -EIO; 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci /* 52162306a36Sopenharmony_ci * Prepare the TX always, even for RX or tx_buf being null, we would 52262306a36Sopenharmony_ci * need TX to be prepared per GSI spec 52362306a36Sopenharmony_ci */ 52462306a36Sopenharmony_ci dmaengine_slave_config(mas->tx, &config); 52562306a36Sopenharmony_ci tx_desc = dmaengine_prep_slave_sg(mas->tx, xfer->tx_sg.sgl, xfer->tx_sg.nents, 52662306a36Sopenharmony_ci DMA_MEM_TO_DEV, flags); 52762306a36Sopenharmony_ci if (!tx_desc) { 52862306a36Sopenharmony_ci dev_err(mas->dev, "Err setting up tx desc\n"); 52962306a36Sopenharmony_ci return -EIO; 53062306a36Sopenharmony_ci } 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci tx_desc->callback_result = spi_gsi_callback_result; 53362306a36Sopenharmony_ci tx_desc->callback_param = spi; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci if (peripheral.cmd & SPI_RX) 53662306a36Sopenharmony_ci dmaengine_submit(rx_desc); 53762306a36Sopenharmony_ci dmaengine_submit(tx_desc); 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci if (peripheral.cmd & SPI_RX) 54062306a36Sopenharmony_ci dma_async_issue_pending(mas->rx); 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci dma_async_issue_pending(mas->tx); 54362306a36Sopenharmony_ci return 1; 54462306a36Sopenharmony_ci} 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_cistatic u32 get_xfer_len_in_words(struct spi_transfer *xfer, 54762306a36Sopenharmony_ci struct spi_geni_master *mas) 54862306a36Sopenharmony_ci{ 54962306a36Sopenharmony_ci u32 len; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci if (!(mas->cur_bits_per_word % MIN_WORD_LEN)) 55262306a36Sopenharmony_ci len = xfer->len * BITS_PER_BYTE / mas->cur_bits_per_word; 55362306a36Sopenharmony_ci else 55462306a36Sopenharmony_ci len = xfer->len / (mas->cur_bits_per_word / BITS_PER_BYTE + 1); 55562306a36Sopenharmony_ci len &= TRANS_LEN_MSK; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci return len; 55862306a36Sopenharmony_ci} 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_cistatic bool geni_can_dma(struct spi_controller *ctlr, 56162306a36Sopenharmony_ci struct spi_device *slv, struct spi_transfer *xfer) 56262306a36Sopenharmony_ci{ 56362306a36Sopenharmony_ci struct spi_geni_master *mas = spi_master_get_devdata(slv->master); 56462306a36Sopenharmony_ci u32 len, fifo_size; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci if (mas->cur_xfer_mode == GENI_GPI_DMA) 56762306a36Sopenharmony_ci return true; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci /* Set SE DMA mode for SPI slave. */ 57062306a36Sopenharmony_ci if (ctlr->slave) 57162306a36Sopenharmony_ci return true; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci len = get_xfer_len_in_words(xfer, mas); 57462306a36Sopenharmony_ci fifo_size = mas->tx_fifo_depth * mas->fifo_width_bits / mas->cur_bits_per_word; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci if (len > fifo_size) 57762306a36Sopenharmony_ci return true; 57862306a36Sopenharmony_ci else 57962306a36Sopenharmony_ci return false; 58062306a36Sopenharmony_ci} 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_cistatic int spi_geni_prepare_message(struct spi_master *spi, 58362306a36Sopenharmony_ci struct spi_message *spi_msg) 58462306a36Sopenharmony_ci{ 58562306a36Sopenharmony_ci struct spi_geni_master *mas = spi_master_get_devdata(spi); 58662306a36Sopenharmony_ci int ret; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci switch (mas->cur_xfer_mode) { 58962306a36Sopenharmony_ci case GENI_SE_FIFO: 59062306a36Sopenharmony_ci case GENI_SE_DMA: 59162306a36Sopenharmony_ci if (spi_geni_is_abort_still_pending(mas)) 59262306a36Sopenharmony_ci return -EBUSY; 59362306a36Sopenharmony_ci ret = setup_fifo_params(spi_msg->spi, spi); 59462306a36Sopenharmony_ci if (ret) 59562306a36Sopenharmony_ci dev_err(mas->dev, "Couldn't select mode %d\n", ret); 59662306a36Sopenharmony_ci return ret; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci case GENI_GPI_DMA: 59962306a36Sopenharmony_ci /* nothing to do for GPI DMA */ 60062306a36Sopenharmony_ci return 0; 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci dev_err(mas->dev, "Mode not supported %d", mas->cur_xfer_mode); 60462306a36Sopenharmony_ci return -EINVAL; 60562306a36Sopenharmony_ci} 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_cistatic int spi_geni_grab_gpi_chan(struct spi_geni_master *mas) 60862306a36Sopenharmony_ci{ 60962306a36Sopenharmony_ci int ret; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci mas->tx = dma_request_chan(mas->dev, "tx"); 61262306a36Sopenharmony_ci if (IS_ERR(mas->tx)) { 61362306a36Sopenharmony_ci ret = dev_err_probe(mas->dev, PTR_ERR(mas->tx), 61462306a36Sopenharmony_ci "Failed to get tx DMA ch\n"); 61562306a36Sopenharmony_ci goto err_tx; 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci mas->rx = dma_request_chan(mas->dev, "rx"); 61962306a36Sopenharmony_ci if (IS_ERR(mas->rx)) { 62062306a36Sopenharmony_ci ret = dev_err_probe(mas->dev, PTR_ERR(mas->rx), 62162306a36Sopenharmony_ci "Failed to get rx DMA ch\n"); 62262306a36Sopenharmony_ci goto err_rx; 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci return 0; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_cierr_rx: 62862306a36Sopenharmony_ci mas->rx = NULL; 62962306a36Sopenharmony_ci dma_release_channel(mas->tx); 63062306a36Sopenharmony_cierr_tx: 63162306a36Sopenharmony_ci mas->tx = NULL; 63262306a36Sopenharmony_ci return ret; 63362306a36Sopenharmony_ci} 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_cistatic void spi_geni_release_dma_chan(struct spi_geni_master *mas) 63662306a36Sopenharmony_ci{ 63762306a36Sopenharmony_ci if (mas->rx) { 63862306a36Sopenharmony_ci dma_release_channel(mas->rx); 63962306a36Sopenharmony_ci mas->rx = NULL; 64062306a36Sopenharmony_ci } 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci if (mas->tx) { 64362306a36Sopenharmony_ci dma_release_channel(mas->tx); 64462306a36Sopenharmony_ci mas->tx = NULL; 64562306a36Sopenharmony_ci } 64662306a36Sopenharmony_ci} 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_cistatic int spi_geni_init(struct spi_geni_master *mas) 64962306a36Sopenharmony_ci{ 65062306a36Sopenharmony_ci struct spi_master *spi = dev_get_drvdata(mas->dev); 65162306a36Sopenharmony_ci struct geni_se *se = &mas->se; 65262306a36Sopenharmony_ci unsigned int proto, major, minor, ver; 65362306a36Sopenharmony_ci u32 spi_tx_cfg, fifo_disable; 65462306a36Sopenharmony_ci int ret = -ENXIO; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci pm_runtime_get_sync(mas->dev); 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci proto = geni_se_read_proto(se); 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci if (spi->slave) { 66162306a36Sopenharmony_ci if (proto != GENI_SE_SPI_SLAVE) { 66262306a36Sopenharmony_ci dev_err(mas->dev, "Invalid proto %d\n", proto); 66362306a36Sopenharmony_ci goto out_pm; 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci spi_slv_setup(mas); 66662306a36Sopenharmony_ci } else if (proto != GENI_SE_SPI) { 66762306a36Sopenharmony_ci dev_err(mas->dev, "Invalid proto %d\n", proto); 66862306a36Sopenharmony_ci goto out_pm; 66962306a36Sopenharmony_ci } 67062306a36Sopenharmony_ci mas->tx_fifo_depth = geni_se_get_tx_fifo_depth(se); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci /* Width of Tx and Rx FIFO is same */ 67362306a36Sopenharmony_ci mas->fifo_width_bits = geni_se_get_tx_fifo_width(se); 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci /* 67662306a36Sopenharmony_ci * Hardware programming guide suggests to configure 67762306a36Sopenharmony_ci * RX FIFO RFR level to fifo_depth-2. 67862306a36Sopenharmony_ci */ 67962306a36Sopenharmony_ci geni_se_init(se, mas->tx_fifo_depth - 3, mas->tx_fifo_depth - 2); 68062306a36Sopenharmony_ci /* Transmit an entire FIFO worth of data per IRQ */ 68162306a36Sopenharmony_ci mas->tx_wm = 1; 68262306a36Sopenharmony_ci ver = geni_se_get_qup_hw_version(se); 68362306a36Sopenharmony_ci major = GENI_SE_VERSION_MAJOR(ver); 68462306a36Sopenharmony_ci minor = GENI_SE_VERSION_MINOR(ver); 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci if (major == 1 && minor == 0) 68762306a36Sopenharmony_ci mas->oversampling = 2; 68862306a36Sopenharmony_ci else 68962306a36Sopenharmony_ci mas->oversampling = 1; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci fifo_disable = readl(se->base + GENI_IF_DISABLE_RO) & FIFO_IF_DISABLE; 69262306a36Sopenharmony_ci switch (fifo_disable) { 69362306a36Sopenharmony_ci case 1: 69462306a36Sopenharmony_ci ret = spi_geni_grab_gpi_chan(mas); 69562306a36Sopenharmony_ci if (!ret) { /* success case */ 69662306a36Sopenharmony_ci mas->cur_xfer_mode = GENI_GPI_DMA; 69762306a36Sopenharmony_ci geni_se_select_mode(se, GENI_GPI_DMA); 69862306a36Sopenharmony_ci dev_dbg(mas->dev, "Using GPI DMA mode for SPI\n"); 69962306a36Sopenharmony_ci break; 70062306a36Sopenharmony_ci } else if (ret == -EPROBE_DEFER) { 70162306a36Sopenharmony_ci goto out_pm; 70262306a36Sopenharmony_ci } 70362306a36Sopenharmony_ci /* 70462306a36Sopenharmony_ci * in case of failure to get gpi dma channel, we can still do the 70562306a36Sopenharmony_ci * FIFO mode, so fallthrough 70662306a36Sopenharmony_ci */ 70762306a36Sopenharmony_ci dev_warn(mas->dev, "FIFO mode disabled, but couldn't get DMA, fall back to FIFO mode\n"); 70862306a36Sopenharmony_ci fallthrough; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci case 0: 71162306a36Sopenharmony_ci mas->cur_xfer_mode = GENI_SE_FIFO; 71262306a36Sopenharmony_ci geni_se_select_mode(se, GENI_SE_FIFO); 71362306a36Sopenharmony_ci ret = 0; 71462306a36Sopenharmony_ci break; 71562306a36Sopenharmony_ci } 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci /* We always control CS manually */ 71862306a36Sopenharmony_ci if (!spi->slave) { 71962306a36Sopenharmony_ci spi_tx_cfg = readl(se->base + SE_SPI_TRANS_CFG); 72062306a36Sopenharmony_ci spi_tx_cfg &= ~CS_TOGGLE; 72162306a36Sopenharmony_ci writel(spi_tx_cfg, se->base + SE_SPI_TRANS_CFG); 72262306a36Sopenharmony_ci } 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ciout_pm: 72562306a36Sopenharmony_ci pm_runtime_put(mas->dev); 72662306a36Sopenharmony_ci return ret; 72762306a36Sopenharmony_ci} 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_cistatic unsigned int geni_byte_per_fifo_word(struct spi_geni_master *mas) 73062306a36Sopenharmony_ci{ 73162306a36Sopenharmony_ci /* 73262306a36Sopenharmony_ci * Calculate how many bytes we'll put in each FIFO word. If the 73362306a36Sopenharmony_ci * transfer words don't pack cleanly into a FIFO word we'll just put 73462306a36Sopenharmony_ci * one transfer word in each FIFO word. If they do pack we'll pack 'em. 73562306a36Sopenharmony_ci */ 73662306a36Sopenharmony_ci if (mas->fifo_width_bits % mas->cur_bits_per_word) 73762306a36Sopenharmony_ci return roundup_pow_of_two(DIV_ROUND_UP(mas->cur_bits_per_word, 73862306a36Sopenharmony_ci BITS_PER_BYTE)); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci return mas->fifo_width_bits / BITS_PER_BYTE; 74162306a36Sopenharmony_ci} 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_cistatic bool geni_spi_handle_tx(struct spi_geni_master *mas) 74462306a36Sopenharmony_ci{ 74562306a36Sopenharmony_ci struct geni_se *se = &mas->se; 74662306a36Sopenharmony_ci unsigned int max_bytes; 74762306a36Sopenharmony_ci const u8 *tx_buf; 74862306a36Sopenharmony_ci unsigned int bytes_per_fifo_word = geni_byte_per_fifo_word(mas); 74962306a36Sopenharmony_ci unsigned int i = 0; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci /* Stop the watermark IRQ if nothing to send */ 75262306a36Sopenharmony_ci if (!mas->cur_xfer) { 75362306a36Sopenharmony_ci writel(0, se->base + SE_GENI_TX_WATERMARK_REG); 75462306a36Sopenharmony_ci return false; 75562306a36Sopenharmony_ci } 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci max_bytes = (mas->tx_fifo_depth - mas->tx_wm) * bytes_per_fifo_word; 75862306a36Sopenharmony_ci if (mas->tx_rem_bytes < max_bytes) 75962306a36Sopenharmony_ci max_bytes = mas->tx_rem_bytes; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci tx_buf = mas->cur_xfer->tx_buf + mas->cur_xfer->len - mas->tx_rem_bytes; 76262306a36Sopenharmony_ci while (i < max_bytes) { 76362306a36Sopenharmony_ci unsigned int j; 76462306a36Sopenharmony_ci unsigned int bytes_to_write; 76562306a36Sopenharmony_ci u32 fifo_word = 0; 76662306a36Sopenharmony_ci u8 *fifo_byte = (u8 *)&fifo_word; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci bytes_to_write = min(bytes_per_fifo_word, max_bytes - i); 76962306a36Sopenharmony_ci for (j = 0; j < bytes_to_write; j++) 77062306a36Sopenharmony_ci fifo_byte[j] = tx_buf[i++]; 77162306a36Sopenharmony_ci iowrite32_rep(se->base + SE_GENI_TX_FIFOn, &fifo_word, 1); 77262306a36Sopenharmony_ci } 77362306a36Sopenharmony_ci mas->tx_rem_bytes -= max_bytes; 77462306a36Sopenharmony_ci if (!mas->tx_rem_bytes) { 77562306a36Sopenharmony_ci writel(0, se->base + SE_GENI_TX_WATERMARK_REG); 77662306a36Sopenharmony_ci return false; 77762306a36Sopenharmony_ci } 77862306a36Sopenharmony_ci return true; 77962306a36Sopenharmony_ci} 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_cistatic void geni_spi_handle_rx(struct spi_geni_master *mas) 78262306a36Sopenharmony_ci{ 78362306a36Sopenharmony_ci struct geni_se *se = &mas->se; 78462306a36Sopenharmony_ci u32 rx_fifo_status; 78562306a36Sopenharmony_ci unsigned int rx_bytes; 78662306a36Sopenharmony_ci unsigned int rx_last_byte_valid; 78762306a36Sopenharmony_ci u8 *rx_buf; 78862306a36Sopenharmony_ci unsigned int bytes_per_fifo_word = geni_byte_per_fifo_word(mas); 78962306a36Sopenharmony_ci unsigned int i = 0; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci rx_fifo_status = readl(se->base + SE_GENI_RX_FIFO_STATUS); 79262306a36Sopenharmony_ci rx_bytes = (rx_fifo_status & RX_FIFO_WC_MSK) * bytes_per_fifo_word; 79362306a36Sopenharmony_ci if (rx_fifo_status & RX_LAST) { 79462306a36Sopenharmony_ci rx_last_byte_valid = rx_fifo_status & RX_LAST_BYTE_VALID_MSK; 79562306a36Sopenharmony_ci rx_last_byte_valid >>= RX_LAST_BYTE_VALID_SHFT; 79662306a36Sopenharmony_ci if (rx_last_byte_valid && rx_last_byte_valid < 4) 79762306a36Sopenharmony_ci rx_bytes -= bytes_per_fifo_word - rx_last_byte_valid; 79862306a36Sopenharmony_ci } 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci /* Clear out the FIFO and bail if nowhere to put it */ 80162306a36Sopenharmony_ci if (!mas->cur_xfer) { 80262306a36Sopenharmony_ci for (i = 0; i < DIV_ROUND_UP(rx_bytes, bytes_per_fifo_word); i++) 80362306a36Sopenharmony_ci readl(se->base + SE_GENI_RX_FIFOn); 80462306a36Sopenharmony_ci return; 80562306a36Sopenharmony_ci } 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci if (mas->rx_rem_bytes < rx_bytes) 80862306a36Sopenharmony_ci rx_bytes = mas->rx_rem_bytes; 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci rx_buf = mas->cur_xfer->rx_buf + mas->cur_xfer->len - mas->rx_rem_bytes; 81162306a36Sopenharmony_ci while (i < rx_bytes) { 81262306a36Sopenharmony_ci u32 fifo_word = 0; 81362306a36Sopenharmony_ci u8 *fifo_byte = (u8 *)&fifo_word; 81462306a36Sopenharmony_ci unsigned int bytes_to_read; 81562306a36Sopenharmony_ci unsigned int j; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci bytes_to_read = min(bytes_per_fifo_word, rx_bytes - i); 81862306a36Sopenharmony_ci ioread32_rep(se->base + SE_GENI_RX_FIFOn, &fifo_word, 1); 81962306a36Sopenharmony_ci for (j = 0; j < bytes_to_read; j++) 82062306a36Sopenharmony_ci rx_buf[i++] = fifo_byte[j]; 82162306a36Sopenharmony_ci } 82262306a36Sopenharmony_ci mas->rx_rem_bytes -= rx_bytes; 82362306a36Sopenharmony_ci} 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_cistatic int setup_se_xfer(struct spi_transfer *xfer, 82662306a36Sopenharmony_ci struct spi_geni_master *mas, 82762306a36Sopenharmony_ci u16 mode, struct spi_master *spi) 82862306a36Sopenharmony_ci{ 82962306a36Sopenharmony_ci u32 m_cmd = 0; 83062306a36Sopenharmony_ci u32 len; 83162306a36Sopenharmony_ci struct geni_se *se = &mas->se; 83262306a36Sopenharmony_ci int ret; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci /* 83562306a36Sopenharmony_ci * Ensure that our interrupt handler isn't still running from some 83662306a36Sopenharmony_ci * prior command before we start messing with the hardware behind 83762306a36Sopenharmony_ci * its back. We don't need to _keep_ the lock here since we're only 83862306a36Sopenharmony_ci * worried about racing with out interrupt handler. The SPI core 83962306a36Sopenharmony_ci * already handles making sure that we're not trying to do two 84062306a36Sopenharmony_ci * transfers at once or setting a chip select and doing a transfer 84162306a36Sopenharmony_ci * concurrently. 84262306a36Sopenharmony_ci * 84362306a36Sopenharmony_ci * NOTE: we actually _can't_ hold the lock here because possibly we 84462306a36Sopenharmony_ci * might call clk_set_rate() which needs to be able to sleep. 84562306a36Sopenharmony_ci */ 84662306a36Sopenharmony_ci spin_lock_irq(&mas->lock); 84762306a36Sopenharmony_ci spin_unlock_irq(&mas->lock); 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci if (xfer->bits_per_word != mas->cur_bits_per_word) { 85062306a36Sopenharmony_ci spi_setup_word_len(mas, mode, xfer->bits_per_word); 85162306a36Sopenharmony_ci mas->cur_bits_per_word = xfer->bits_per_word; 85262306a36Sopenharmony_ci } 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci /* Speed and bits per word can be overridden per transfer */ 85562306a36Sopenharmony_ci ret = geni_spi_set_clock_and_bw(mas, xfer->speed_hz); 85662306a36Sopenharmony_ci if (ret) 85762306a36Sopenharmony_ci return ret; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci mas->tx_rem_bytes = 0; 86062306a36Sopenharmony_ci mas->rx_rem_bytes = 0; 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci len = get_xfer_len_in_words(xfer, mas); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci mas->cur_xfer = xfer; 86562306a36Sopenharmony_ci if (xfer->tx_buf) { 86662306a36Sopenharmony_ci m_cmd |= SPI_TX_ONLY; 86762306a36Sopenharmony_ci mas->tx_rem_bytes = xfer->len; 86862306a36Sopenharmony_ci writel(len, se->base + SE_SPI_TX_TRANS_LEN); 86962306a36Sopenharmony_ci } 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci if (xfer->rx_buf) { 87262306a36Sopenharmony_ci m_cmd |= SPI_RX_ONLY; 87362306a36Sopenharmony_ci writel(len, se->base + SE_SPI_RX_TRANS_LEN); 87462306a36Sopenharmony_ci mas->rx_rem_bytes = xfer->len; 87562306a36Sopenharmony_ci } 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci /* 87862306a36Sopenharmony_ci * Select DMA mode if sgt are present; and with only 1 entry 87962306a36Sopenharmony_ci * This is not a serious limitation because the xfer buffers are 88062306a36Sopenharmony_ci * expected to fit into in 1 entry almost always, and if any 88162306a36Sopenharmony_ci * doesn't for any reason we fall back to FIFO mode anyway 88262306a36Sopenharmony_ci */ 88362306a36Sopenharmony_ci if (!xfer->tx_sg.nents && !xfer->rx_sg.nents) 88462306a36Sopenharmony_ci mas->cur_xfer_mode = GENI_SE_FIFO; 88562306a36Sopenharmony_ci else if (xfer->tx_sg.nents > 1 || xfer->rx_sg.nents > 1) { 88662306a36Sopenharmony_ci dev_warn_once(mas->dev, "Doing FIFO, cannot handle tx_nents-%d, rx_nents-%d\n", 88762306a36Sopenharmony_ci xfer->tx_sg.nents, xfer->rx_sg.nents); 88862306a36Sopenharmony_ci mas->cur_xfer_mode = GENI_SE_FIFO; 88962306a36Sopenharmony_ci } else 89062306a36Sopenharmony_ci mas->cur_xfer_mode = GENI_SE_DMA; 89162306a36Sopenharmony_ci geni_se_select_mode(se, mas->cur_xfer_mode); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci /* 89462306a36Sopenharmony_ci * Lock around right before we start the transfer since our 89562306a36Sopenharmony_ci * interrupt could come in at any time now. 89662306a36Sopenharmony_ci */ 89762306a36Sopenharmony_ci spin_lock_irq(&mas->lock); 89862306a36Sopenharmony_ci geni_se_setup_m_cmd(se, m_cmd, FRAGMENTATION); 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci if (mas->cur_xfer_mode == GENI_SE_DMA) { 90162306a36Sopenharmony_ci if (m_cmd & SPI_RX_ONLY) 90262306a36Sopenharmony_ci geni_se_rx_init_dma(se, sg_dma_address(xfer->rx_sg.sgl), 90362306a36Sopenharmony_ci sg_dma_len(xfer->rx_sg.sgl)); 90462306a36Sopenharmony_ci if (m_cmd & SPI_TX_ONLY) 90562306a36Sopenharmony_ci geni_se_tx_init_dma(se, sg_dma_address(xfer->tx_sg.sgl), 90662306a36Sopenharmony_ci sg_dma_len(xfer->tx_sg.sgl)); 90762306a36Sopenharmony_ci } else if (m_cmd & SPI_TX_ONLY) { 90862306a36Sopenharmony_ci if (geni_spi_handle_tx(mas)) 90962306a36Sopenharmony_ci writel(mas->tx_wm, se->base + SE_GENI_TX_WATERMARK_REG); 91062306a36Sopenharmony_ci } 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci spin_unlock_irq(&mas->lock); 91362306a36Sopenharmony_ci return ret; 91462306a36Sopenharmony_ci} 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_cistatic int spi_geni_transfer_one(struct spi_master *spi, 91762306a36Sopenharmony_ci struct spi_device *slv, 91862306a36Sopenharmony_ci struct spi_transfer *xfer) 91962306a36Sopenharmony_ci{ 92062306a36Sopenharmony_ci struct spi_geni_master *mas = spi_master_get_devdata(spi); 92162306a36Sopenharmony_ci int ret; 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci if (spi_geni_is_abort_still_pending(mas)) 92462306a36Sopenharmony_ci return -EBUSY; 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci /* Terminate and return success for 0 byte length transfer */ 92762306a36Sopenharmony_ci if (!xfer->len) 92862306a36Sopenharmony_ci return 0; 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci if (mas->cur_xfer_mode == GENI_SE_FIFO || mas->cur_xfer_mode == GENI_SE_DMA) { 93162306a36Sopenharmony_ci ret = setup_se_xfer(xfer, mas, slv->mode, spi); 93262306a36Sopenharmony_ci /* SPI framework expects +ve ret code to wait for transfer complete */ 93362306a36Sopenharmony_ci if (!ret) 93462306a36Sopenharmony_ci ret = 1; 93562306a36Sopenharmony_ci return ret; 93662306a36Sopenharmony_ci } 93762306a36Sopenharmony_ci return setup_gsi_xfer(xfer, mas, slv, spi); 93862306a36Sopenharmony_ci} 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_cistatic irqreturn_t geni_spi_isr(int irq, void *data) 94162306a36Sopenharmony_ci{ 94262306a36Sopenharmony_ci struct spi_master *spi = data; 94362306a36Sopenharmony_ci struct spi_geni_master *mas = spi_master_get_devdata(spi); 94462306a36Sopenharmony_ci struct geni_se *se = &mas->se; 94562306a36Sopenharmony_ci u32 m_irq; 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci m_irq = readl(se->base + SE_GENI_M_IRQ_STATUS); 94862306a36Sopenharmony_ci if (!m_irq) 94962306a36Sopenharmony_ci return IRQ_NONE; 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci if (m_irq & (M_CMD_OVERRUN_EN | M_ILLEGAL_CMD_EN | M_CMD_FAILURE_EN | 95262306a36Sopenharmony_ci M_RX_FIFO_RD_ERR_EN | M_RX_FIFO_WR_ERR_EN | 95362306a36Sopenharmony_ci M_TX_FIFO_RD_ERR_EN | M_TX_FIFO_WR_ERR_EN)) 95462306a36Sopenharmony_ci dev_warn(mas->dev, "Unexpected IRQ err status %#010x\n", m_irq); 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci spin_lock(&mas->lock); 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci if (mas->cur_xfer_mode == GENI_SE_FIFO) { 95962306a36Sopenharmony_ci if ((m_irq & M_RX_FIFO_WATERMARK_EN) || (m_irq & M_RX_FIFO_LAST_EN)) 96062306a36Sopenharmony_ci geni_spi_handle_rx(mas); 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci if (m_irq & M_TX_FIFO_WATERMARK_EN) 96362306a36Sopenharmony_ci geni_spi_handle_tx(mas); 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci if (m_irq & M_CMD_DONE_EN) { 96662306a36Sopenharmony_ci if (mas->cur_xfer) { 96762306a36Sopenharmony_ci spi_finalize_current_transfer(spi); 96862306a36Sopenharmony_ci mas->cur_xfer = NULL; 96962306a36Sopenharmony_ci /* 97062306a36Sopenharmony_ci * If this happens, then a CMD_DONE came before all the 97162306a36Sopenharmony_ci * Tx buffer bytes were sent out. This is unusual, log 97262306a36Sopenharmony_ci * this condition and disable the WM interrupt to 97362306a36Sopenharmony_ci * prevent the system from stalling due an interrupt 97462306a36Sopenharmony_ci * storm. 97562306a36Sopenharmony_ci * 97662306a36Sopenharmony_ci * If this happens when all Rx bytes haven't been 97762306a36Sopenharmony_ci * received, log the condition. The only known time 97862306a36Sopenharmony_ci * this can happen is if bits_per_word != 8 and some 97962306a36Sopenharmony_ci * registers that expect xfer lengths in num spi_words 98062306a36Sopenharmony_ci * weren't written correctly. 98162306a36Sopenharmony_ci */ 98262306a36Sopenharmony_ci if (mas->tx_rem_bytes) { 98362306a36Sopenharmony_ci writel(0, se->base + SE_GENI_TX_WATERMARK_REG); 98462306a36Sopenharmony_ci dev_err(mas->dev, "Premature done. tx_rem = %d bpw%d\n", 98562306a36Sopenharmony_ci mas->tx_rem_bytes, mas->cur_bits_per_word); 98662306a36Sopenharmony_ci } 98762306a36Sopenharmony_ci if (mas->rx_rem_bytes) 98862306a36Sopenharmony_ci dev_err(mas->dev, "Premature done. rx_rem = %d bpw%d\n", 98962306a36Sopenharmony_ci mas->rx_rem_bytes, mas->cur_bits_per_word); 99062306a36Sopenharmony_ci } else { 99162306a36Sopenharmony_ci complete(&mas->cs_done); 99262306a36Sopenharmony_ci } 99362306a36Sopenharmony_ci } 99462306a36Sopenharmony_ci } else if (mas->cur_xfer_mode == GENI_SE_DMA) { 99562306a36Sopenharmony_ci const struct spi_transfer *xfer = mas->cur_xfer; 99662306a36Sopenharmony_ci u32 dma_tx_status = readl_relaxed(se->base + SE_DMA_TX_IRQ_STAT); 99762306a36Sopenharmony_ci u32 dma_rx_status = readl_relaxed(se->base + SE_DMA_RX_IRQ_STAT); 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci if (dma_tx_status) 100062306a36Sopenharmony_ci writel(dma_tx_status, se->base + SE_DMA_TX_IRQ_CLR); 100162306a36Sopenharmony_ci if (dma_rx_status) 100262306a36Sopenharmony_ci writel(dma_rx_status, se->base + SE_DMA_RX_IRQ_CLR); 100362306a36Sopenharmony_ci if (dma_tx_status & TX_DMA_DONE) 100462306a36Sopenharmony_ci mas->tx_rem_bytes = 0; 100562306a36Sopenharmony_ci if (dma_rx_status & RX_DMA_DONE) 100662306a36Sopenharmony_ci mas->rx_rem_bytes = 0; 100762306a36Sopenharmony_ci if (dma_tx_status & TX_RESET_DONE) 100862306a36Sopenharmony_ci complete(&mas->tx_reset_done); 100962306a36Sopenharmony_ci if (dma_rx_status & RX_RESET_DONE) 101062306a36Sopenharmony_ci complete(&mas->rx_reset_done); 101162306a36Sopenharmony_ci if (!mas->tx_rem_bytes && !mas->rx_rem_bytes && xfer) { 101262306a36Sopenharmony_ci spi_finalize_current_transfer(spi); 101362306a36Sopenharmony_ci mas->cur_xfer = NULL; 101462306a36Sopenharmony_ci } 101562306a36Sopenharmony_ci } 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci if (m_irq & M_CMD_CANCEL_EN) 101862306a36Sopenharmony_ci complete(&mas->cancel_done); 101962306a36Sopenharmony_ci if (m_irq & M_CMD_ABORT_EN) 102062306a36Sopenharmony_ci complete(&mas->abort_done); 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci /* 102362306a36Sopenharmony_ci * It's safe or a good idea to Ack all of our interrupts at the end 102462306a36Sopenharmony_ci * of the function. Specifically: 102562306a36Sopenharmony_ci * - M_CMD_DONE_EN / M_RX_FIFO_LAST_EN: Edge triggered interrupts and 102662306a36Sopenharmony_ci * clearing Acks. Clearing at the end relies on nobody else having 102762306a36Sopenharmony_ci * started a new transfer yet or else we could be clearing _their_ 102862306a36Sopenharmony_ci * done bit, but everyone grabs the spinlock before starting a new 102962306a36Sopenharmony_ci * transfer. 103062306a36Sopenharmony_ci * - M_RX_FIFO_WATERMARK_EN / M_TX_FIFO_WATERMARK_EN: These appear 103162306a36Sopenharmony_ci * to be "latched level" interrupts so it's important to clear them 103262306a36Sopenharmony_ci * _after_ you've handled the condition and always safe to do so 103362306a36Sopenharmony_ci * since they'll re-assert if they're still happening. 103462306a36Sopenharmony_ci */ 103562306a36Sopenharmony_ci writel(m_irq, se->base + SE_GENI_M_IRQ_CLEAR); 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci spin_unlock(&mas->lock); 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci return IRQ_HANDLED; 104062306a36Sopenharmony_ci} 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_cistatic int spi_geni_probe(struct platform_device *pdev) 104362306a36Sopenharmony_ci{ 104462306a36Sopenharmony_ci int ret, irq; 104562306a36Sopenharmony_ci struct spi_master *spi; 104662306a36Sopenharmony_ci struct spi_geni_master *mas; 104762306a36Sopenharmony_ci void __iomem *base; 104862306a36Sopenharmony_ci struct clk *clk; 104962306a36Sopenharmony_ci struct device *dev = &pdev->dev; 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci irq = platform_get_irq(pdev, 0); 105262306a36Sopenharmony_ci if (irq < 0) 105362306a36Sopenharmony_ci return irq; 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); 105662306a36Sopenharmony_ci if (ret) 105762306a36Sopenharmony_ci return dev_err_probe(dev, ret, "could not set DMA mask\n"); 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci base = devm_platform_ioremap_resource(pdev, 0); 106062306a36Sopenharmony_ci if (IS_ERR(base)) 106162306a36Sopenharmony_ci return PTR_ERR(base); 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci clk = devm_clk_get(dev, "se"); 106462306a36Sopenharmony_ci if (IS_ERR(clk)) 106562306a36Sopenharmony_ci return PTR_ERR(clk); 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci spi = devm_spi_alloc_master(dev, sizeof(*mas)); 106862306a36Sopenharmony_ci if (!spi) 106962306a36Sopenharmony_ci return -ENOMEM; 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci platform_set_drvdata(pdev, spi); 107262306a36Sopenharmony_ci mas = spi_master_get_devdata(spi); 107362306a36Sopenharmony_ci mas->irq = irq; 107462306a36Sopenharmony_ci mas->dev = dev; 107562306a36Sopenharmony_ci mas->se.dev = dev; 107662306a36Sopenharmony_ci mas->se.wrapper = dev_get_drvdata(dev->parent); 107762306a36Sopenharmony_ci mas->se.base = base; 107862306a36Sopenharmony_ci mas->se.clk = clk; 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci ret = devm_pm_opp_set_clkname(&pdev->dev, "se"); 108162306a36Sopenharmony_ci if (ret) 108262306a36Sopenharmony_ci return ret; 108362306a36Sopenharmony_ci /* OPP table is optional */ 108462306a36Sopenharmony_ci ret = devm_pm_opp_of_add_table(&pdev->dev); 108562306a36Sopenharmony_ci if (ret && ret != -ENODEV) { 108662306a36Sopenharmony_ci dev_err(&pdev->dev, "invalid OPP table in device tree\n"); 108762306a36Sopenharmony_ci return ret; 108862306a36Sopenharmony_ci } 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci spi->bus_num = -1; 109162306a36Sopenharmony_ci spi->dev.of_node = dev->of_node; 109262306a36Sopenharmony_ci spi->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP | SPI_CS_HIGH; 109362306a36Sopenharmony_ci spi->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); 109462306a36Sopenharmony_ci spi->num_chipselect = 4; 109562306a36Sopenharmony_ci spi->max_speed_hz = 50000000; 109662306a36Sopenharmony_ci spi->max_dma_len = 0xffff0; /* 24 bits for tx/rx dma length */ 109762306a36Sopenharmony_ci spi->prepare_message = spi_geni_prepare_message; 109862306a36Sopenharmony_ci spi->transfer_one = spi_geni_transfer_one; 109962306a36Sopenharmony_ci spi->can_dma = geni_can_dma; 110062306a36Sopenharmony_ci spi->dma_map_dev = dev->parent; 110162306a36Sopenharmony_ci spi->auto_runtime_pm = true; 110262306a36Sopenharmony_ci spi->handle_err = spi_geni_handle_err; 110362306a36Sopenharmony_ci spi->use_gpio_descriptors = true; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci init_completion(&mas->cs_done); 110662306a36Sopenharmony_ci init_completion(&mas->cancel_done); 110762306a36Sopenharmony_ci init_completion(&mas->abort_done); 110862306a36Sopenharmony_ci init_completion(&mas->tx_reset_done); 110962306a36Sopenharmony_ci init_completion(&mas->rx_reset_done); 111062306a36Sopenharmony_ci spin_lock_init(&mas->lock); 111162306a36Sopenharmony_ci pm_runtime_use_autosuspend(&pdev->dev); 111262306a36Sopenharmony_ci pm_runtime_set_autosuspend_delay(&pdev->dev, 250); 111362306a36Sopenharmony_ci pm_runtime_enable(dev); 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci if (device_property_read_bool(&pdev->dev, "spi-slave")) 111662306a36Sopenharmony_ci spi->slave = true; 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci ret = geni_icc_get(&mas->se, NULL); 111962306a36Sopenharmony_ci if (ret) 112062306a36Sopenharmony_ci goto spi_geni_probe_runtime_disable; 112162306a36Sopenharmony_ci /* Set the bus quota to a reasonable value for register access */ 112262306a36Sopenharmony_ci mas->se.icc_paths[GENI_TO_CORE].avg_bw = Bps_to_icc(CORE_2X_50_MHZ); 112362306a36Sopenharmony_ci mas->se.icc_paths[CPU_TO_GENI].avg_bw = GENI_DEFAULT_BW; 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci ret = geni_icc_set_bw(&mas->se); 112662306a36Sopenharmony_ci if (ret) 112762306a36Sopenharmony_ci goto spi_geni_probe_runtime_disable; 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci ret = spi_geni_init(mas); 113062306a36Sopenharmony_ci if (ret) 113162306a36Sopenharmony_ci goto spi_geni_probe_runtime_disable; 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci /* 113462306a36Sopenharmony_ci * check the mode supported and set_cs for fifo mode only 113562306a36Sopenharmony_ci * for dma (gsi) mode, the gsi will set cs based on params passed in 113662306a36Sopenharmony_ci * TRE 113762306a36Sopenharmony_ci */ 113862306a36Sopenharmony_ci if (!spi->slave && mas->cur_xfer_mode == GENI_SE_FIFO) 113962306a36Sopenharmony_ci spi->set_cs = spi_geni_set_cs; 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci /* 114262306a36Sopenharmony_ci * TX is required per GSI spec, see setup_gsi_xfer(). 114362306a36Sopenharmony_ci */ 114462306a36Sopenharmony_ci if (mas->cur_xfer_mode == GENI_GPI_DMA) 114562306a36Sopenharmony_ci spi->flags = SPI_CONTROLLER_MUST_TX; 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci ret = request_irq(mas->irq, geni_spi_isr, 0, dev_name(dev), spi); 114862306a36Sopenharmony_ci if (ret) 114962306a36Sopenharmony_ci goto spi_geni_release_dma; 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci ret = spi_register_master(spi); 115262306a36Sopenharmony_ci if (ret) 115362306a36Sopenharmony_ci goto spi_geni_probe_free_irq; 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci return 0; 115662306a36Sopenharmony_cispi_geni_probe_free_irq: 115762306a36Sopenharmony_ci free_irq(mas->irq, spi); 115862306a36Sopenharmony_cispi_geni_release_dma: 115962306a36Sopenharmony_ci spi_geni_release_dma_chan(mas); 116062306a36Sopenharmony_cispi_geni_probe_runtime_disable: 116162306a36Sopenharmony_ci pm_runtime_disable(dev); 116262306a36Sopenharmony_ci return ret; 116362306a36Sopenharmony_ci} 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_cistatic void spi_geni_remove(struct platform_device *pdev) 116662306a36Sopenharmony_ci{ 116762306a36Sopenharmony_ci struct spi_master *spi = platform_get_drvdata(pdev); 116862306a36Sopenharmony_ci struct spi_geni_master *mas = spi_master_get_devdata(spi); 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci /* Unregister _before_ disabling pm_runtime() so we stop transfers */ 117162306a36Sopenharmony_ci spi_unregister_master(spi); 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci spi_geni_release_dma_chan(mas); 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci free_irq(mas->irq, spi); 117662306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 117762306a36Sopenharmony_ci} 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_cistatic int __maybe_unused spi_geni_runtime_suspend(struct device *dev) 118062306a36Sopenharmony_ci{ 118162306a36Sopenharmony_ci struct spi_master *spi = dev_get_drvdata(dev); 118262306a36Sopenharmony_ci struct spi_geni_master *mas = spi_master_get_devdata(spi); 118362306a36Sopenharmony_ci int ret; 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci /* Drop the performance state vote */ 118662306a36Sopenharmony_ci dev_pm_opp_set_rate(dev, 0); 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci ret = geni_se_resources_off(&mas->se); 118962306a36Sopenharmony_ci if (ret) 119062306a36Sopenharmony_ci return ret; 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci return geni_icc_disable(&mas->se); 119362306a36Sopenharmony_ci} 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_cistatic int __maybe_unused spi_geni_runtime_resume(struct device *dev) 119662306a36Sopenharmony_ci{ 119762306a36Sopenharmony_ci struct spi_master *spi = dev_get_drvdata(dev); 119862306a36Sopenharmony_ci struct spi_geni_master *mas = spi_master_get_devdata(spi); 119962306a36Sopenharmony_ci int ret; 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci ret = geni_icc_enable(&mas->se); 120262306a36Sopenharmony_ci if (ret) 120362306a36Sopenharmony_ci return ret; 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci ret = geni_se_resources_on(&mas->se); 120662306a36Sopenharmony_ci if (ret) 120762306a36Sopenharmony_ci return ret; 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci return dev_pm_opp_set_rate(mas->dev, mas->cur_sclk_hz); 121062306a36Sopenharmony_ci} 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_cistatic int __maybe_unused spi_geni_suspend(struct device *dev) 121362306a36Sopenharmony_ci{ 121462306a36Sopenharmony_ci struct spi_master *spi = dev_get_drvdata(dev); 121562306a36Sopenharmony_ci int ret; 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci ret = spi_master_suspend(spi); 121862306a36Sopenharmony_ci if (ret) 121962306a36Sopenharmony_ci return ret; 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci ret = pm_runtime_force_suspend(dev); 122262306a36Sopenharmony_ci if (ret) 122362306a36Sopenharmony_ci spi_master_resume(spi); 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci return ret; 122662306a36Sopenharmony_ci} 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_cistatic int __maybe_unused spi_geni_resume(struct device *dev) 122962306a36Sopenharmony_ci{ 123062306a36Sopenharmony_ci struct spi_master *spi = dev_get_drvdata(dev); 123162306a36Sopenharmony_ci int ret; 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci ret = pm_runtime_force_resume(dev); 123462306a36Sopenharmony_ci if (ret) 123562306a36Sopenharmony_ci return ret; 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci ret = spi_master_resume(spi); 123862306a36Sopenharmony_ci if (ret) 123962306a36Sopenharmony_ci pm_runtime_force_suspend(dev); 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci return ret; 124262306a36Sopenharmony_ci} 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_cistatic const struct dev_pm_ops spi_geni_pm_ops = { 124562306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(spi_geni_runtime_suspend, 124662306a36Sopenharmony_ci spi_geni_runtime_resume, NULL) 124762306a36Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(spi_geni_suspend, spi_geni_resume) 124862306a36Sopenharmony_ci}; 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_cistatic const struct of_device_id spi_geni_dt_match[] = { 125162306a36Sopenharmony_ci { .compatible = "qcom,geni-spi" }, 125262306a36Sopenharmony_ci {} 125362306a36Sopenharmony_ci}; 125462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, spi_geni_dt_match); 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_cistatic struct platform_driver spi_geni_driver = { 125762306a36Sopenharmony_ci .probe = spi_geni_probe, 125862306a36Sopenharmony_ci .remove_new = spi_geni_remove, 125962306a36Sopenharmony_ci .driver = { 126062306a36Sopenharmony_ci .name = "geni_spi", 126162306a36Sopenharmony_ci .pm = &spi_geni_pm_ops, 126262306a36Sopenharmony_ci .of_match_table = spi_geni_dt_match, 126362306a36Sopenharmony_ci }, 126462306a36Sopenharmony_ci}; 126562306a36Sopenharmony_cimodule_platform_driver(spi_geni_driver); 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ciMODULE_DESCRIPTION("SPI driver for GENI based QUP cores"); 126862306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1269