Update Linux to v5.4.2
Change-Id: Idf6911045d9d382da2cfe01b1edff026404ac8fd
diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c
index 254e621..531c011 100644
--- a/drivers/i2c/busses/i2c-rcar.c
+++ b/drivers/i2c/busses/i2c-rcar.c
@@ -2,8 +2,8 @@
/*
* Driver for the Renesas R-Car I2C unit
*
- * Copyright (C) 2014-15 Wolfram Sang <wsa@sang-engineering.com>
- * Copyright (C) 2011-2015 Renesas Electronics Corporation
+ * Copyright (C) 2014-19 Wolfram Sang <wsa@sang-engineering.com>
+ * Copyright (C) 2011-2019 Renesas Electronics Corporation
*
* Copyright (C) 2012-14 Renesas Solutions Corp.
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
@@ -39,8 +39,8 @@
#define ICSAR 0x1C /* slave address */
#define ICMAR 0x20 /* master address */
#define ICRXTX 0x24 /* data port */
-#define ICDMAER 0x3c /* DMA enable */
-#define ICFBSCR 0x38 /* first bit setup cycle */
+#define ICFBSCR 0x38 /* first bit setup cycle (Gen3) */
+#define ICDMAER 0x3c /* DMA enable (Gen3) */
/* ICSCR */
#define SDBS (1 << 3) /* slave data buffer select */
@@ -83,9 +83,9 @@
#define TMDMAE (1 << 0) /* DMA Master Transmitted Enable */
/* ICFBSCR */
-#define TCYC06 0x04 /* 6*Tcyc delay 1st bit between SDA and SCL */
#define TCYC17 0x0f /* 17*Tcyc delay 1st bit between SDA and SCL */
+#define RCAR_MIN_DMA_LEN 8
#define RCAR_BUS_PHASE_START (MDBS | MIE | ESG)
#define RCAR_BUS_PHASE_DATA (MDBS | MIE)
@@ -139,6 +139,7 @@
enum dma_data_direction dma_direction;
struct reset_control *rstc;
+ int irq;
};
#define rcar_i2c_priv_to_dev(p) ((p)->adap.dev.parent)
@@ -212,6 +213,10 @@
rcar_i2c_write(priv, ICMSR, 0);
/* start clock */
rcar_i2c_write(priv, ICCCR, priv->icccr);
+
+ if (priv->devtype == I2C_RCAR_GEN3)
+ rcar_i2c_write(priv, ICFBSCR, TCYC17);
+
}
static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv)
@@ -355,20 +360,11 @@
rcar_i2c_prepare_msg(priv);
}
-/*
- * interrupt functions
- */
static void rcar_i2c_dma_unmap(struct rcar_i2c_priv *priv)
{
struct dma_chan *chan = priv->dma_direction == DMA_FROM_DEVICE
? priv->dma_rx : priv->dma_tx;
- /* Disable DMA Master Received/Transmitted */
- rcar_i2c_write(priv, ICDMAER, 0);
-
- /* Reset default delay */
- rcar_i2c_write(priv, ICFBSCR, TCYC06);
-
dma_unmap_single(chan->device->dev, sg_dma_address(&priv->sg),
sg_dma_len(&priv->sg), priv->dma_direction);
@@ -378,6 +374,9 @@
priv->flags |= ID_P_NO_RXDMA;
priv->dma_direction = DMA_NONE;
+
+ /* Disable DMA Master Received/Transmitted, must be last! */
+ rcar_i2c_write(priv, ICDMAER, 0);
}
static void rcar_i2c_cleanup_dma(struct rcar_i2c_priv *priv)
@@ -401,7 +400,7 @@
rcar_i2c_dma_unmap(priv);
}
-static void rcar_i2c_dma(struct rcar_i2c_priv *priv)
+static bool rcar_i2c_dma(struct rcar_i2c_priv *priv)
{
struct device *dev = rcar_i2c_priv_to_dev(priv);
struct i2c_msg *msg = priv->msg;
@@ -415,9 +414,9 @@
int len;
/* Do various checks to see if DMA is feasible at all */
- if (IS_ERR(chan) || msg->len < 8 || !(msg->flags & I2C_M_DMA_SAFE) ||
- (read && priv->flags & ID_P_NO_RXDMA))
- return;
+ if (IS_ERR(chan) || msg->len < RCAR_MIN_DMA_LEN ||
+ !(msg->flags & I2C_M_DMA_SAFE) || (read && priv->flags & ID_P_NO_RXDMA))
+ return false;
if (read) {
/*
@@ -437,7 +436,7 @@
dma_addr = dma_map_single(chan->device->dev, buf, len, dir);
if (dma_mapping_error(chan->device->dev, dma_addr)) {
dev_dbg(dev, "dma map failed, using PIO\n");
- return;
+ return false;
}
sg_dma_len(&priv->sg) = len;
@@ -451,7 +450,7 @@
if (!txdesc) {
dev_dbg(dev, "dma prep slave sg failed, using PIO\n");
rcar_i2c_cleanup_dma(priv);
- return;
+ return false;
}
txdesc->callback = rcar_i2c_dma_callback;
@@ -461,12 +460,9 @@
if (dma_submit_error(cookie)) {
dev_dbg(dev, "submitting dma failed, using PIO\n");
rcar_i2c_cleanup_dma(priv);
- return;
+ return false;
}
- /* Set delay for DMA operations */
- rcar_i2c_write(priv, ICFBSCR, TCYC17);
-
/* Enable DMA Master Received/Transmitted */
if (read)
rcar_i2c_write(priv, ICDMAER, RMDMAE);
@@ -474,6 +470,7 @@
rcar_i2c_write(priv, ICDMAER, TMDMAE);
dma_async_issue_pending(chan);
+ return true;
}
static void rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr)
@@ -484,6 +481,10 @@
if (!(msr & MDE))
return;
+ /* Check if DMA can be enabled and take over */
+ if (priv->pos == 1 && rcar_i2c_dma(priv))
+ return;
+
if (priv->pos < msg->len) {
/*
* Prepare next data to ICRXTX register.
@@ -494,13 +495,6 @@
*/
rcar_i2c_write(priv, ICRXTX, msg->buf[priv->pos]);
priv->pos++;
-
- /*
- * Try to use DMA to transmit the rest of the data if
- * address transfer phase just finished.
- */
- if (msr & MAT)
- rcar_i2c_dma(priv);
} else {
/*
* The last data was pushed to ICRXTX on _PREV_ empty irq.
@@ -617,6 +611,15 @@
return true;
}
+/*
+ * This driver has a lock-free design because there are IP cores (at least
+ * R-Car Gen2) which have an inherent race condition in their hardware design.
+ * There, we need to clear RCAR_BUS_MASK_DATA bits as soon as possible after
+ * the interrupt was generated, otherwise an unwanted repeated message gets
+ * generated. It turned out that taking a spinlock at the beginning of the ISR
+ * was already causing repeated messages. Thus, this driver was converted to
+ * the now lockless behaviour. Please keep this in mind when hacking the driver.
+ */
static irqreturn_t rcar_i2c_irq(int irq, void *ptr)
{
struct rcar_i2c_priv *priv = ptr;
@@ -859,9 +862,11 @@
WARN_ON(!priv->slave);
+ /* disable irqs and ensure none is running before clearing ptr */
rcar_i2c_write(priv, ICSIER, 0);
rcar_i2c_write(priv, ICSCR, 0);
+ synchronize_irq(priv->irq);
priv->slave = NULL;
pm_runtime_put(rcar_i2c_priv_to_dev(priv));
@@ -916,7 +921,10 @@
struct i2c_adapter *adap;
struct device *dev = &pdev->dev;
struct i2c_timings i2c_t;
- int irq, ret;
+ int ret;
+
+ /* Otherwise logic will break because some bytes must always use PIO */
+ BUILD_BUG_ON_MSG(RCAR_MIN_DMA_LEN < 3, "Invalid min DMA length");
priv = devm_kzalloc(dev, sizeof(struct rcar_i2c_priv), GFP_KERNEL);
if (!priv)
@@ -979,10 +987,10 @@
pm_runtime_put(dev);
- irq = platform_get_irq(pdev, 0);
- ret = devm_request_irq(dev, irq, rcar_i2c_irq, 0, dev_name(dev), priv);
+ priv->irq = platform_get_irq(pdev, 0);
+ ret = devm_request_irq(dev, priv->irq, rcar_i2c_irq, 0, dev_name(dev), priv);
if (ret < 0) {
- dev_err(dev, "cannot get irq %d\n", irq);
+ dev_err(dev, "cannot get irq %d\n", priv->irq);
goto out_pm_disable;
}
@@ -1017,10 +1025,37 @@
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int rcar_i2c_suspend(struct device *dev)
+{
+ struct rcar_i2c_priv *priv = dev_get_drvdata(dev);
+
+ i2c_mark_adapter_suspended(&priv->adap);
+ return 0;
+}
+
+static int rcar_i2c_resume(struct device *dev)
+{
+ struct rcar_i2c_priv *priv = dev_get_drvdata(dev);
+
+ i2c_mark_adapter_resumed(&priv->adap);
+ return 0;
+}
+
+static const struct dev_pm_ops rcar_i2c_pm_ops = {
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(rcar_i2c_suspend, rcar_i2c_resume)
+};
+
+#define DEV_PM_OPS (&rcar_i2c_pm_ops)
+#else
+#define DEV_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
static struct platform_driver rcar_i2c_driver = {
.driver = {
.name = "i2c-rcar",
.of_match_table = rcar_i2c_dt_ids,
+ .pm = DEV_PM_OPS,
},
.probe = rcar_i2c_probe,
.remove = rcar_i2c_remove,