Update Linux to v5.10.109
Sourced from [1]
[1] https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.10.109.tar.xz
Change-Id: I19bca9fc6762d4e63bcf3e4cba88bbe560d9c76c
Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
index 1d948fe..dfa7c91 100644
--- a/drivers/spi/spi-s3c64xx.c
+++ b/drivers/spi/spi-s3c64xx.c
@@ -29,7 +29,7 @@
#define S3C64XX_SPI_CH_CFG 0x00
#define S3C64XX_SPI_CLK_CFG 0x04
#define S3C64XX_SPI_MODE_CFG 0x08
-#define S3C64XX_SPI_SLAVE_SEL 0x0C
+#define S3C64XX_SPI_CS_REG 0x0C
#define S3C64XX_SPI_INT_EN 0x10
#define S3C64XX_SPI_STATUS 0x14
#define S3C64XX_SPI_TX_DATA 0x18
@@ -64,9 +64,9 @@
#define S3C64XX_SPI_MODE_TXDMA_ON (1<<1)
#define S3C64XX_SPI_MODE_4BURST (1<<0)
-#define S3C64XX_SPI_SLAVE_AUTO (1<<1)
-#define S3C64XX_SPI_SLAVE_SIG_INACT (1<<0)
-#define S3C64XX_SPI_SLAVE_NSC_CNT_2 (2<<4)
+#define S3C64XX_SPI_CS_NSC_CNT_2 (2<<4)
+#define S3C64XX_SPI_CS_AUTO (1<<1)
+#define S3C64XX_SPI_CS_SIG_INACT (1<<0)
#define S3C64XX_SPI_INT_TRAILING_EN (1<<6)
#define S3C64XX_SPI_INT_RX_OVERRUN_EN (1<<5)
@@ -131,9 +131,11 @@ struct s3c64xx_spi_dma_data {
* @fifo_lvl_mask: Bit-mask for {TX|RX}_FIFO_LVL bits in SPI_STATUS register.
* @rx_lvl_offset: Bit offset of RX_FIFO_LVL bits in SPI_STATUS regiter.
* @tx_st_done: Bit offset of TX_DONE bit in SPI_STATUS regiter.
+ * @quirks: Bitmask of known quirks
* @high_speed: True, if the controller supports HIGH_SPEED_EN bit.
* @clk_from_cmu: True, if the controller does not include a clock mux and
* prescaler unit.
+ * @clk_ioclk: True if clock is present on this device
*
* The Samsung s3c64xx SPI controller are used on various Samsung SoC's but
* differ in some aspects such as the size of the fifo and spi bus clock
@@ -155,19 +157,21 @@ struct s3c64xx_spi_port_config {
* @clk: Pointer to the spi clock.
* @src_clk: Pointer to the clock used to generate SPI signals.
* @ioclk: Pointer to the i/o clock between master and slave
+ * @pdev: Pointer to device's platform device data
* @master: Pointer to the SPI Protocol master.
* @cntrlr_info: Platform specific data for the controller this driver manages.
* @lock: Controller specific lock.
* @state: Set of FLAGS to indicate status.
- * @rx_dmach: Controller's DMA channel for Rx.
- * @tx_dmach: Controller's DMA channel for Tx.
* @sfr_start: BUS address of SPI controller regs.
* @regs: Pointer to ioremap'ed controller registers.
- * @irq: interrupt
* @xfer_completion: To indicate completion of xfer task.
* @cur_mode: Stores the active configuration of the controller.
* @cur_bpw: Stores the active bits per word settings.
- * @cur_speed: Stores the active xfer clock speed.
+ * @cur_speed: Current clock speed
+ * @rx_dma: Local receive DMA data (e.g. chan and direction)
+ * @tx_dma: Local transmit DMA data (e.g. chan and direction)
+ * @port_conf: Local SPI port configuartion data
+ * @port_id: Port identification number
*/
struct s3c64xx_spi_driver_data {
void __iomem *regs;
@@ -176,7 +180,7 @@ struct s3c64xx_spi_driver_data {
struct clk *ioclk;
struct platform_device *pdev;
struct spi_master *master;
- struct s3c64xx_spi_info *cntrlr_info;
+ struct s3c64xx_spi_info *cntrlr_info;
spinlock_t lock;
unsigned long sfr_start;
struct completion xfer_completion;
@@ -325,18 +329,18 @@ static void s3c64xx_spi_set_cs(struct spi_device *spi, bool enable)
if (enable) {
if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO)) {
- writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
+ writel(0, sdd->regs + S3C64XX_SPI_CS_REG);
} else {
- u32 ssel = readl(sdd->regs + S3C64XX_SPI_SLAVE_SEL);
+ u32 ssel = readl(sdd->regs + S3C64XX_SPI_CS_REG);
- ssel |= (S3C64XX_SPI_SLAVE_AUTO |
- S3C64XX_SPI_SLAVE_NSC_CNT_2);
- writel(ssel, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
+ ssel |= (S3C64XX_SPI_CS_AUTO |
+ S3C64XX_SPI_CS_NSC_CNT_2);
+ writel(ssel, sdd->regs + S3C64XX_SPI_CS_REG);
}
} else {
if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO))
- writel(S3C64XX_SPI_SLAVE_SIG_INACT,
- sdd->regs + S3C64XX_SPI_SLAVE_SEL);
+ writel(S3C64XX_SPI_CS_SIG_INACT,
+ sdd->regs + S3C64XX_SPI_CS_REG);
}
}
@@ -469,7 +473,8 @@ static int s3c64xx_wait_for_dma(struct s3c64xx_spi_driver_data *sdd,
/* millisecs to xfer 'len' bytes @ 'cur_speed' */
ms = xfer->len * 8 * 1000 / sdd->cur_speed;
- ms += 10; /* some tolerance */
+ ms += 30; /* some tolerance */
+ ms = max(ms, 100); /* minimum timeout */
val = msecs_to_jiffies(ms) + 10;
val = wait_for_completion_timeout(&sdd->xfer_completion, val);
@@ -622,6 +627,7 @@ static int s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
ret = clk_set_rate(sdd->src_clk, sdd->cur_speed * 2);
if (ret)
return ret;
+ sdd->cur_speed = clk_get_rate(sdd->src_clk) / 2;
} else {
/* Configure Clock */
val = readl(regs + S3C64XX_SPI_CLK_CFG);
@@ -724,17 +730,28 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
if (status) {
dev_err(&spi->dev,
- "I/O Error: rx-%d tx-%d res:rx-%c tx-%c len-%d\n",
+ "I/O Error: rx-%d tx-%d rx-%c tx-%c len-%d dma-%d res-(%d)\n",
xfer->rx_buf ? 1 : 0, xfer->tx_buf ? 1 : 0,
(sdd->state & RXBUSY) ? 'f' : 'p',
(sdd->state & TXBUSY) ? 'f' : 'p',
- xfer->len);
+ xfer->len, use_dma ? 1 : 0, status);
if (use_dma) {
- if (xfer->tx_buf && (sdd->state & TXBUSY))
+ struct dma_tx_state s;
+
+ if (xfer->tx_buf && (sdd->state & TXBUSY)) {
+ dmaengine_pause(sdd->tx_dma.ch);
+ dmaengine_tx_status(sdd->tx_dma.ch, sdd->tx_dma.cookie, &s);
dmaengine_terminate_all(sdd->tx_dma.ch);
- if (xfer->rx_buf && (sdd->state & RXBUSY))
+ dev_err(&spi->dev, "TX residue: %d\n", s.residue);
+
+ }
+ if (xfer->rx_buf && (sdd->state & RXBUSY)) {
+ dmaengine_pause(sdd->rx_dma.ch);
+ dmaengine_tx_status(sdd->rx_dma.ch, sdd->rx_dma.cookie, &s);
dmaengine_terminate_all(sdd->rx_dma.ch);
+ dev_err(&spi->dev, "RX residue: %d\n", s.residue);
+ }
}
} else {
s3c64xx_flush_fifo(sdd);
@@ -964,9 +981,9 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd)
sdd->cur_speed = 0;
if (sci->no_cs)
- writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
+ writel(0, sdd->regs + S3C64XX_SPI_CS_REG);
else if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO))
- writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
+ writel(S3C64XX_SPI_CS_SIG_INACT, sdd->regs + S3C64XX_SPI_CS_REG);
/* Disable Interrupts - we use Polling if not DMA mode */
writel(0, regs + S3C64XX_SPI_INT_EN);
@@ -1186,15 +1203,13 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
if (!is_polling(sdd)) {
/* Acquire DMA channels */
- sdd->rx_dma.ch = dma_request_slave_channel_reason(&pdev->dev,
- "rx");
+ sdd->rx_dma.ch = dma_request_chan(&pdev->dev, "rx");
if (IS_ERR(sdd->rx_dma.ch)) {
dev_err(&pdev->dev, "Failed to get RX DMA channel\n");
ret = PTR_ERR(sdd->rx_dma.ch);
goto err_disable_io_clk;
}
- sdd->tx_dma.ch = dma_request_slave_channel_reason(&pdev->dev,
- "tx");
+ sdd->tx_dma.ch = dma_request_chan(&pdev->dev, "tx");
if (IS_ERR(sdd->tx_dma.ch)) {
dev_err(&pdev->dev, "Failed to get TX DMA channel\n");
ret = PTR_ERR(sdd->tx_dma.ch);
@@ -1363,6 +1378,10 @@ static int s3c64xx_spi_runtime_resume(struct device *dev)
s3c64xx_spi_hwinit(sdd);
+ writel(S3C64XX_SPI_INT_RX_OVERRUN_EN | S3C64XX_SPI_INT_RX_UNDERRUN_EN |
+ S3C64XX_SPI_INT_TX_OVERRUN_EN | S3C64XX_SPI_INT_TX_UNDERRUN_EN,
+ sdd->regs + S3C64XX_SPI_INT_EN);
+
return 0;
err_disable_src_clk:
@@ -1406,6 +1425,7 @@ static struct s3c64xx_spi_port_config exynos4_spi_port_config = {
.tx_st_done = 25,
.high_speed = true,
.clk_from_cmu = true,
+ .quirks = S3C64XX_SPI_QUIRK_CS_AUTO,
};
static struct s3c64xx_spi_port_config exynos7_spi_port_config = {