+++ /dev/null
-Device tree configuration for the Mellanox I2C SMBus on BlueField SoCs
-
-Required Properties:
-
-- compatible : should be "mellanox,i2c-mlxbf1" or "mellanox,i2c-mlxbf2".
-
-- reg : address offset and length of the device registers. The
- registers consist of the following set of resources:
- 1) Smbus block registers.
- 2) Cause master registers.
- 3) Cause slave registers.
- 4) Cause coalesce registers (if compatible isn't set
- to "mellanox,i2c-mlxbf1").
-
-- interrupts : interrupt number.
-
-Optional Properties:
-
-- clock-frequency : bus frequency used to configure timing registers;
- allowed values are 100000, 400000 and 1000000;
- those are expressed in Hz. Default is 100000.
-
-Example:
-
-i2c@2804000 {
- compatible = "mellanox,i2c-mlxbf1";
- reg = <0x02804000 0x800>,
- <0x02801200 0x020>,
- <0x02801260 0x020>;
- interrupts = <57>;
- clock-frequency = <100000>;
-};
-
-i2c@2808800 {
- compatible = "mellanox,i2c-mlxbf2";
- reg = <0x02808800 0x600>,
- <0x02808e00 0x020>,
- <0x02808e20 0x020>,
- <0x02808e40 0x010>;
- interrupts = <57>;
- clock-frequency = <400000>;
-};
--- /dev/null
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/i2c/mellanox,i2c-mlxbf.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Mellanox I2C SMBus on BlueField SoCs
+
+maintainers:
+ - Khalil Blaiech <kblaiech@nvidia.com>
+
+allOf:
+ - $ref: /schemas/i2c/i2c-controller.yaml#
+
+properties:
+ compatible:
+ enum:
+ - mellanox,i2c-mlxbf1
+ - mellanox,i2c-mlxbf2
+
+ reg:
+ minItems: 3
+ maxItems: 4
+ items:
+ - description: Smbus block registers
+ - description: Cause master registers
+ - description: Cause slave registers
+ - description: Cause coalesce registers
+
+ interrupts:
+ maxItems: 1
+
+ clock-frequency:
+ enum: [ 100000, 400000, 1000000 ]
+ description:
+ bus frequency used to configure timing registers;
+ The frequency is expressed in Hz. Default is 100000.
+
+required:
+ - compatible
+ - reg
+ - interrupts
+
+unevaluatedProperties: false
+
+if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - mellanox,i2c-mlxbf1
+
+then:
+ properties:
+ reg:
+ maxItems: 3
+
+examples:
+ - |
+ i2c@2804000 {
+ compatible = "mellanox,i2c-mlxbf1";
+ reg = <0x02804000 0x800>,
+ <0x02801200 0x020>,
+ <0x02801260 0x020>;
+ interrupts = <57>;
+ clock-frequency = <100000>;
+ };
+
+ - |
+ i2c@2808800 {
+ compatible = "mellanox,i2c-mlxbf2";
+ reg = <0x02808800 0x600>,
+ <0x02808e00 0x020>,
+ <0x02808e20 0x020>,
+ <0x02808e40 0x010>;
+ interrupts = <57>;
+ clock-frequency = <400000>;
+ };
M: Khalil Blaiech <kblaiech@nvidia.com>
L: linux-i2c@vger.kernel.org
S: Supported
+F: Documentation/devicetree/bindings/i2c/mellanox,i2c-mlxbf.yaml
F: drivers/i2c/busses/i2c-mlxbf.c
MELLANOX ETHERNET DRIVER (mlx4_en)
#include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
-#include <linux/platform_data/dma-atmel.h>
#include <linux/pm_runtime.h>
#include "i2c-at91.h"
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/i2c.h>
-#include <linux/platform_data/dma-atmel.h>
#include <linux/platform_device.h>
#define AT91_I2C_TIMEOUT msecs_to_jiffies(100) /* transfer timeout */
bool has_adv_dig_filtr;
bool has_ana_filtr;
bool has_clear_cmd;
- struct at_dma_slave dma_slave;
};
struct at91_twi_dma {
init_completion(&i2c->msg_complete);
i2c->irq = ret = platform_get_irq(pdev, 0);
- if (ret <= 0) {
- dev_err(&pdev->dev, "cannot find HS-I2C IRQ\n");
- ret = -EINVAL;
+ if (ret < 0)
goto err_clk;
- }
ret = devm_request_irq(&pdev->dev, i2c->irq, exynos5_i2c_irq,
IRQF_NO_SUSPEND, dev_name(&pdev->dev), i2c);
};
-static const struct platform_device_id imx_i2c_devtype[] = {
- {
- .name = "imx1-i2c",
- .driver_data = (kernel_ulong_t)&imx1_i2c_hwdata,
- }, {
- .name = "imx21-i2c",
- .driver_data = (kernel_ulong_t)&imx21_i2c_hwdata,
- }, {
- /* sentinel */
- }
-};
-MODULE_DEVICE_TABLE(platform, imx_i2c_devtype);
-
static const struct of_device_id i2c_imx_dt_ids[] = {
{ .compatible = "fsl,imx1-i2c", .data = &imx1_i2c_hwdata, },
{ .compatible = "fsl,imx21-i2c", .data = &imx21_i2c_hwdata, },
return -ENOMEM;
match = device_get_match_data(&pdev->dev);
- if (match)
- i2c_imx->hwdata = match;
- else
- i2c_imx->hwdata = (struct imx_i2c_hwdata *)
- platform_get_device_id(pdev)->driver_data;
+ i2c_imx->hwdata = match;
/* Setup i2c_imx driver structure */
strlcpy(i2c_imx->adapter.name, pdev->name, sizeof(i2c_imx->adapter.name));
.of_match_table = i2c_imx_dt_ids,
.acpi_match_table = i2c_imx_acpi_ids,
},
- .id_table = imx_i2c_devtype,
};
static int __init i2c_adap_imx_init(void)
* Features supported by this driver:
* Hardware PEC yes
* Block buffer yes
- * Block process call transaction no
+ * Block process call transaction yes
* Slave mode no
*/
if (desc->status & ISMT_DESC_SCS) {
if (read_write == I2C_SMBUS_WRITE &&
- size != I2C_SMBUS_PROC_CALL)
+ size != I2C_SMBUS_PROC_CALL &&
+ size != I2C_SMBUS_BLOCK_PROC_CALL)
return 0;
switch (size) {
data->word = dma_buffer[0] | (dma_buffer[1] << 8);
break;
case I2C_SMBUS_BLOCK_DATA:
+ case I2C_SMBUS_BLOCK_PROC_CALL:
if (desc->rxbytes != dma_buffer[0] + 1)
return -EMSGSIZE;
}
break;
+ case I2C_SMBUS_BLOCK_PROC_CALL:
+ dev_dbg(dev, "I2C_SMBUS_BLOCK_PROC_CALL\n");
+ dma_size = I2C_SMBUS_BLOCK_MAX;
+ desc->tgtaddr_rw = ISMT_DESC_ADDR_RW(addr, 1);
+ desc->wr_len_cmd = data->block[0] + 1;
+ desc->rd_len = dma_size;
+ desc->control |= ISMT_DESC_BLK;
+ dma_direction = DMA_BIDIRECTIONAL;
+ dma_buffer[0] = command;
+ memcpy(&dma_buffer[1], &data->block[1], data->block[0]);
+ break;
+
case I2C_SMBUS_I2C_BLOCK_DATA:
/* Make sure the length is valid */
if (data->block[0] < 1)
I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_DATA |
I2C_FUNC_SMBUS_PROC_CALL |
+ I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
I2C_FUNC_SMBUS_BLOCK_DATA |
I2C_FUNC_SMBUS_I2C_BLOCK |
I2C_FUNC_SMBUS_PEC;
#include <linux/interrupt.h>
#include <linux/mv643xx_i2c.h>
#include <linux/platform_device.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/reset.h>
#include <linux/io.h>
#include <linux/of.h>
bool irq_clear_inverted;
/* Clk div is 2 to the power n, not 2 to the power n + 1 */
bool clk_n_base_0;
+ struct i2c_bus_recovery_info rinfo;
};
static struct mv64xxx_i2c_regs mv64xxx_i2c_regs_mv64xxx = {
drv_data->msg->flags);
drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
mv64xxx_i2c_hw_init(drv_data);
- drv_data->rc = -EIO;
+ i2c_recover_bus(&drv_data->adapter);
+ drv_data->rc = -EAGAIN;
}
}
"time_left: %d\n", drv_data->block,
(int)time_left);
mv64xxx_i2c_hw_init(drv_data);
+ i2c_recover_bus(&drv_data->adapter);
}
} else
spin_unlock_irqrestore(&drv_data->lock, flags);
}
#endif /* CONFIG_OF */
+static int mv64xxx_i2c_init_recovery_info(struct mv64xxx_i2c_data *drv_data,
+ struct device *dev)
+{
+ struct i2c_bus_recovery_info *rinfo = &drv_data->rinfo;
+
+ rinfo->pinctrl = devm_pinctrl_get(dev);
+ if (IS_ERR(rinfo->pinctrl)) {
+ if (PTR_ERR(rinfo->pinctrl) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ dev_info(dev, "can't get pinctrl, bus recovery not supported\n");
+ return PTR_ERR(rinfo->pinctrl);
+ } else if (!rinfo->pinctrl) {
+ return -ENODEV;
+ }
+
+ drv_data->adapter.bus_recovery_info = rinfo;
+ return 0;
+}
+
static int
mv64xxx_i2c_probe(struct platform_device *pd)
{
goto exit_reset;
}
+ rc = mv64xxx_i2c_init_recovery_info(drv_data, &pd->dev);
+ if (rc == -EPROBE_DEFER)
+ goto exit_reset;
+
drv_data->adapter.dev.parent = &pd->dev;
drv_data->adapter.algo = &mv64xxx_i2c_algo;
drv_data->adapter.owner = THIS_MODULE;
return 0;
}
-static const struct platform_device_id mxs_i2c_devtype[] = {
- {
- .name = "imx23-i2c",
- .driver_data = MXS_I2C_V1,
- }, {
- .name = "imx28-i2c",
- .driver_data = MXS_I2C_V2,
- }, { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(platform, mxs_i2c_devtype);
-
static const struct of_device_id mxs_i2c_dt_ids[] = {
- { .compatible = "fsl,imx23-i2c", .data = &mxs_i2c_devtype[0], },
- { .compatible = "fsl,imx28-i2c", .data = &mxs_i2c_devtype[1], },
+ { .compatible = "fsl,imx23-i2c", .data = (void *)MXS_I2C_V1, },
+ { .compatible = "fsl,imx28-i2c", .data = (void *)MXS_I2C_V2, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mxs_i2c_dt_ids);
static int mxs_i2c_probe(struct platform_device *pdev)
{
- const struct of_device_id *of_id =
- of_match_device(mxs_i2c_dt_ids, &pdev->dev);
struct device *dev = &pdev->dev;
struct mxs_i2c_dev *i2c;
struct i2c_adapter *adap;
if (!i2c)
return -ENOMEM;
- if (of_id) {
- const struct platform_device_id *device_id = of_id->data;
- i2c->dev_type = device_id->driver_data;
- }
+ i2c->dev_type = (enum mxs_i2c_devtype)of_device_get_match_data(&pdev->dev);
i2c->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(i2c->regs))
pci_free_irq_vectors(pdev);
}
-/*
- * We need gpu_i2c_suspend() even if it is stub, for runtime pm to work
- * correctly. Without it, lspci shows runtime pm status as "D0" for the card.
- * Documentation/power/pci.rst also insists for driver to provide this.
- */
-static __maybe_unused int gpu_i2c_suspend(struct device *dev)
-{
- return 0;
-}
+#define gpu_i2c_suspend NULL
static __maybe_unused int gpu_i2c_resume(struct device *dev)
{
#define TYPE_OCORES 0
#define TYPE_GRLIB 1
-#define TYPE_SIFIVE_REV0 2
#define OCORES_FLAG_BROKEN_IRQ BIT(1) /* Broken IRQ for FU540-C000 SoC */
},
{
.compatible = "sifive,fu540-c000-i2c",
- .data = (void *)TYPE_SIFIVE_REV0,
},
{
.compatible = "sifive,i2c0",
- .data = (void *)TYPE_SIFIVE_REV0,
},
{},
};
{
struct ocores_i2c *i2c;
struct ocores_i2c_platform_data *pdata;
- const struct of_device_id *match;
struct resource *res;
int irq;
int ret;
init_waitqueue_head(&i2c->wait);
- irq = platform_get_irq(pdev, 0);
+ irq = platform_get_irq_optional(pdev, 0);
+ /*
+ * Since the SoC does have an interrupt, its DT has an interrupt
+ * property - But this should be bypassed as the IRQ logic in this
+ * SoC is broken.
+ */
+ if (of_device_is_compatible(pdev->dev.of_node,
+ "sifive,fu540-c000-i2c")) {
+ i2c->flags |= OCORES_FLAG_BROKEN_IRQ;
+ irq = -ENXIO;
+ }
+
if (irq == -ENXIO) {
ocores_algorithm.master_xfer = ocores_xfer_polling;
-
- /*
- * Set in OCORES_FLAG_BROKEN_IRQ to enable workaround for
- * FU540-C000 SoC in polling mode.
- */
- match = of_match_node(ocores_i2c_match, pdev->dev.of_node);
- if (match && (long)match->data == TYPE_SIFIVE_REV0)
- i2c->flags |= OCORES_FLAG_BROKEN_IRQ;
} else {
if (irq < 0)
return irq;
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/of_device.h>
#define OWL_I2C_FIFOCTL_TFR BIT(2)
/* I2Cc_FIFOSTAT Bit Mask */
+#define OWL_I2C_FIFOSTAT_CECB BIT(0)
#define OWL_I2C_FIFOSTAT_RNB BIT(1)
#define OWL_I2C_FIFOSTAT_RFE BIT(2)
#define OWL_I2C_FIFOSTAT_TFF BIT(5)
#define OWL_I2C_FIFOSTAT_RFD GENMASK(15, 8)
/* I2C bus timeout */
-#define OWL_I2C_TIMEOUT msecs_to_jiffies(4 * 1000)
+#define OWL_I2C_TIMEOUT_MS (4 * 1000)
+#define OWL_I2C_TIMEOUT msecs_to_jiffies(OWL_I2C_TIMEOUT_MS)
#define OWL_I2C_MAX_RETRIES 50
writel(OWL_I2C_DIV_FACTOR(val), i2c_dev->base + OWL_I2C_REG_CLKDIV);
}
-static irqreturn_t owl_i2c_interrupt(int irq, void *_dev)
+static void owl_i2c_xfer_data(struct owl_i2c_dev *i2c_dev)
{
- struct owl_i2c_dev *i2c_dev = _dev;
struct i2c_msg *msg = i2c_dev->msg;
unsigned int stat, fifostat;
- spin_lock(&i2c_dev->lock);
-
i2c_dev->err = 0;
/* Handle NACK from slave */
/* Clear NACK error bit by writing "1" */
owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_FIFOSTAT,
OWL_I2C_FIFOSTAT_RNB, true);
- goto stop;
+ return;
}
/* Handle bus error */
/* Clear BUS error bit by writing "1" */
owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_STAT,
OWL_I2C_STAT_BEB, true);
- goto stop;
+ return;
}
/* Handle FIFO read */
i2c_dev->base + OWL_I2C_REG_TXDAT);
}
}
+}
+
+static irqreturn_t owl_i2c_interrupt(int irq, void *_dev)
+{
+ struct owl_i2c_dev *i2c_dev = _dev;
+
+ spin_lock(&i2c_dev->lock);
+
+ owl_i2c_xfer_data(i2c_dev);
-stop:
/* Clear pending interrupts */
owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_STAT,
OWL_I2C_STAT_IRQP, true);
return 0;
}
-static int owl_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
- int num)
+static int owl_i2c_xfer_common(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ int num, bool atomic)
{
struct owl_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
struct i2c_msg *msg;
goto err_exit;
}
- reinit_completion(&i2c_dev->msg_complete);
+ if (!atomic)
+ reinit_completion(&i2c_dev->msg_complete);
- /* Enable I2C controller interrupt */
+ /* Enable/disable I2C controller interrupt */
owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL,
- OWL_I2C_CTL_IRQE, true);
+ OWL_I2C_CTL_IRQE, !atomic);
/*
* Select: FIFO enable, Master mode, Stop enable, Data count enable,
spin_unlock_irqrestore(&i2c_dev->lock, flags);
- time_left = wait_for_completion_timeout(&i2c_dev->msg_complete,
- adap->timeout);
+ if (atomic) {
+ /* Wait for Command Execute Completed or NACK Error bits */
+ ret = readl_poll_timeout_atomic(i2c_dev->base + OWL_I2C_REG_FIFOSTAT,
+ val, val & (OWL_I2C_FIFOSTAT_CECB |
+ OWL_I2C_FIFOSTAT_RNB),
+ 10, OWL_I2C_TIMEOUT_MS * 1000);
+ } else {
+ time_left = wait_for_completion_timeout(&i2c_dev->msg_complete,
+ adap->timeout);
+ if (!time_left)
+ ret = -ETIMEDOUT;
+ }
spin_lock_irqsave(&i2c_dev->lock, flags);
- if (time_left == 0) {
+
+ if (ret) {
dev_err(&adap->dev, "Transaction timed out\n");
/* Send stop condition and release the bus */
owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL,
OWL_I2C_CTL_GBCC_STOP | OWL_I2C_CTL_RB,
true);
- ret = -ETIMEDOUT;
goto err_exit;
}
+ if (atomic)
+ owl_i2c_xfer_data(i2c_dev);
+
ret = i2c_dev->err < 0 ? i2c_dev->err : num;
err_exit:
return ret;
}
+static int owl_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ int num)
+{
+ return owl_i2c_xfer_common(adap, msgs, num, false);
+}
+
+static int owl_i2c_xfer_atomic(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ return owl_i2c_xfer_common(adap, msgs, num, true);
+}
+
static const struct i2c_algorithm owl_i2c_algorithm = {
- .master_xfer = owl_i2c_master_xfer,
- .functionality = owl_i2c_func,
+ .master_xfer = owl_i2c_xfer,
+ .master_xfer_atomic = owl_i2c_xfer_atomic,
+ .functionality = owl_i2c_func,
};
static const struct i2c_adapter_quirks owl_i2c_quirks = {
.driver = {
.name = "owl-i2c",
.of_match_table = of_match_ptr(owl_i2c_of_match),
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
};
module_platform_driver(owl_i2c_driver);
wait_queue_head_t wait;
struct i2c_adapter adap;
struct i2c_algo_pca_data algo_data;
- unsigned long io_base;
- unsigned long io_size;
};
/* Read/Write functions for different register alignments */
init_waitqueue_head(&i2c->wait);
- i2c->io_base = res->start;
- i2c->io_size = resource_size(res);
i2c->irq = irq;
i2c->adap.nr = pdev->id;
{
dma_addr_t rx_dma;
unsigned long time_left;
- void *dma_buf = NULL;
+ void *dma_buf;
struct geni_se *se = &gi2c->se;
size_t len = msg->len;
- if (!of_machine_is_compatible("lenovo,yoga-c630"))
- dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
-
+ dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
if (dma_buf)
geni_se_select_mode(se, GENI_SE_DMA);
else
geni_se_select_mode(se, GENI_SE_FIFO);
writel_relaxed(len, se->base + SE_I2C_RX_TRANS_LEN);
+ geni_se_setup_m_cmd(se, I2C_READ, m_param);
if (dma_buf && geni_se_rx_dma_prep(se, dma_buf, len, &rx_dma)) {
geni_se_select_mode(se, GENI_SE_FIFO);
dma_buf = NULL;
}
- geni_se_setup_m_cmd(se, I2C_READ, m_param);
-
time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
if (!time_left)
geni_i2c_abort_xfer(gi2c);
{
dma_addr_t tx_dma;
unsigned long time_left;
- void *dma_buf = NULL;
+ void *dma_buf;
struct geni_se *se = &gi2c->se;
size_t len = msg->len;
- if (!of_machine_is_compatible("lenovo,yoga-c630"))
- dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
-
+ dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
if (dma_buf)
geni_se_select_mode(se, GENI_SE_DMA);
else
geni_se_select_mode(se, GENI_SE_FIFO);
writel_relaxed(len, se->base + SE_I2C_TX_TRANS_LEN);
+ geni_se_setup_m_cmd(se, I2C_WRITE, m_param);
if (dma_buf && geni_se_tx_dma_prep(se, dma_buf, len, &tx_dma)) {
geni_se_select_mode(se, GENI_SE_FIFO);
dma_buf = NULL;
}
- geni_se_setup_m_cmd(se, I2C_WRITE, m_param);
-
if (!dma_buf) /* Get FIFO IRQ */
writel_relaxed(1, se->base + SE_GENI_TX_WATERMARK_REG);
static void geni_se_select_fifo_mode(struct geni_se *se)
{
u32 proto = geni_se_read_proto(se);
- u32 val;
+ u32 val, val_old;
geni_se_irq_clear(se);
- val = readl_relaxed(se->base + SE_GENI_M_IRQ_EN);
+ /*
+ * The RX path for the UART is asynchronous and so needs more
+ * complex logic for enabling / disabling its interrupts.
+ *
+ * Specific notes:
+ * - The done and TX-related interrupts are managed manually.
+ * - We don't RX from the main sequencer (we use the secondary) so
+ * we don't need the RX-related interrupts enabled in the main
+ * sequencer for UART.
+ */
if (proto != GENI_SE_UART) {
+ val_old = val = readl_relaxed(se->base + SE_GENI_M_IRQ_EN);
val |= M_CMD_DONE_EN | M_TX_FIFO_WATERMARK_EN;
val |= M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN;
- }
- writel_relaxed(val, se->base + SE_GENI_M_IRQ_EN);
+ if (val != val_old)
+ writel_relaxed(val, se->base + SE_GENI_M_IRQ_EN);
- val = readl_relaxed(se->base + SE_GENI_S_IRQ_EN);
- if (proto != GENI_SE_UART)
+ val_old = val = readl_relaxed(se->base + SE_GENI_S_IRQ_EN);
val |= S_CMD_DONE_EN;
- writel_relaxed(val, se->base + SE_GENI_S_IRQ_EN);
+ if (val != val_old)
+ writel_relaxed(val, se->base + SE_GENI_S_IRQ_EN);
+ }
- val = readl_relaxed(se->base + SE_GENI_DMA_MODE_EN);
+ val_old = val = readl_relaxed(se->base + SE_GENI_DMA_MODE_EN);
val &= ~GENI_DMA_MODE_EN;
- writel_relaxed(val, se->base + SE_GENI_DMA_MODE_EN);
+ if (val != val_old)
+ writel_relaxed(val, se->base + SE_GENI_DMA_MODE_EN);
}
static void geni_se_select_dma_mode(struct geni_se *se)
{
- u32 val;
+ u32 proto = geni_se_read_proto(se);
+ u32 val, val_old;
geni_se_irq_clear(se);
- val = readl_relaxed(se->base + SE_GENI_DMA_MODE_EN);
+ if (proto != GENI_SE_UART) {
+ val_old = val = readl_relaxed(se->base + SE_GENI_M_IRQ_EN);
+ val &= ~(M_CMD_DONE_EN | M_TX_FIFO_WATERMARK_EN);
+ val &= ~(M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN);
+ if (val != val_old)
+ writel_relaxed(val, se->base + SE_GENI_M_IRQ_EN);
+
+ val_old = val = readl_relaxed(se->base + SE_GENI_S_IRQ_EN);
+ val &= ~S_CMD_DONE_EN;
+ if (val != val_old)
+ writel_relaxed(val, se->base + SE_GENI_S_IRQ_EN);
+ }
+
+ val_old = val = readl_relaxed(se->base + SE_GENI_DMA_MODE_EN);
val |= GENI_DMA_MODE_EN;
- writel_relaxed(val, se->base + SE_GENI_DMA_MODE_EN);
+ if (val != val_old)
+ writel_relaxed(val, se->base + SE_GENI_DMA_MODE_EN);
}
/**
writel_relaxed(lower_32_bits(*iova), se->base + SE_DMA_TX_PTR_L);
writel_relaxed(upper_32_bits(*iova), se->base + SE_DMA_TX_PTR_H);
writel_relaxed(GENI_SE_DMA_EOT_BUF, se->base + SE_DMA_TX_ATTR);
- writel_relaxed(len, se->base + SE_DMA_TX_LEN);
+ writel(len, se->base + SE_DMA_TX_LEN);
return 0;
}
EXPORT_SYMBOL(geni_se_tx_dma_prep);
writel_relaxed(upper_32_bits(*iova), se->base + SE_DMA_RX_PTR_H);
/* RX does not have EOT buffer type bit. So just reset RX_ATTR */
writel_relaxed(0, se->base + SE_DMA_RX_ATTR);
- writel_relaxed(len, se->base + SE_DMA_RX_LEN);
+ writel(len, se->base + SE_DMA_RX_LEN);
return 0;
}
EXPORT_SYMBOL(geni_se_rx_dma_prep);