[PATCH RESEND 1/2] i2c: tegra: Add GPCDMA support

Akhil R
2022-08-19T12:23:55Z

Update the DMA initialization and checks to support GPCDMA.
Also add a mechanism to fall back to PIO mode, if DMA is
not available or if initialization returns error.

Signed-off-by: Akhil R <akhilrajeev@nvidia.com>
---
drivers/i2c/busses/i2c-tegra.c | 39 ++++++++++++++++------------------
1 file changed, 18 insertions(+), 21 deletions(-)

diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 031c78ac42e6..8c4610c78b54 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -188,7 +188,6 @@ enum msg_end_type {
* allowing 0 length transfers.
* @supports_bus_clear: Bus Clear support to recover from bus hang during
* SDA stuck low from device for some unknown reasons.
- * @has_apb_dma: Support of APBDMA on corresponding Tegra chip.
* @tlow_std_mode: Low period of the clock in standard mode.
* @thigh_std_mode: High period of the clock in standard mode.
* @tlow_fast_fastplus_mode: Low period of the clock in fast/fast-plus modes.
@@ -215,7 +214,6 @@ struct tegra_i2c_hw_feature {
bool has_mst_fifo;
const struct i2c_adapter_quirks *quirks;
bool supports_bus_clear;
- bool has_apb_dma;
u32 tlow_std_mode;
u32 thigh_std_mode;
u32 tlow_fast_fastplus_mode;
@@ -253,6 +251,7 @@ struct tegra_i2c_hw_feature {
* @dma_phys: handle to DMA resources
* @dma_buf: pointer to allocated DMA buffer
* @dma_buf_size: DMA buffer size
+ * @dma_support: indicates if DMA can be enabled
* @dma_mode: indicates active DMA transfer
* @dma_complete: DMA completion notifier
* @atomic_mode: indicates active atomic transfer
@@ -289,6 +288,7 @@ struct tegra_i2c_dev {

bool multimaster_mode;
bool atomic_mode;
+ bool dma_support;
bool dma_mode;
bool msg_read;
bool is_dvc;
@@ -443,13 +443,8 @@ static int tegra_i2c_init_dma(struct tegra_i2c_dev *i2c_dev)
u32 *dma_buf;
int err;

- if (!i2c_dev->hw->has_apb_dma || i2c_dev->is_vi)
- return 0;
-
- if (!IS_ENABLED(CONFIG_TEGRA20_APB_DMA)) {
- dev_dbg(i2c_dev->dev, "DMA support not enabled\n");
- return 0;
- }
+ if (!i2c_dev->dma_support)
+ return -EOPNOTSUPP;

chan = dma_request_chan(i2c_dev->dev, "rx");
if (IS_ERR(chan)) {
@@ -486,6 +481,7 @@ static int tegra_i2c_init_dma(struct tegra_i2c_dev *i2c_dev)
err_out:
tegra_i2c_release_dma(i2c_dev);
if (err != -EPROBE_DEFER) {
+ i2c_dev->dma_support = false;
dev_err(i2c_dev->dev, "cannot use DMA: %d\n", err);
dev_err(i2c_dev->dev, "falling back to PIO\n");
return 0;
@@ -1251,7 +1247,16 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
xfer_size = ALIGN(xfer_size, BYTES_PER_FIFO_WORD);

i2c_dev->dma_mode = xfer_size > I2C_PIO_MODE_PREFERRED_LEN &&
- i2c_dev->dma_buf && !i2c_dev->atomic_mode;
+ i2c_dev->dma_support && !i2c_dev->atomic_mode;
+
+ /* If DMA is not initialized, initialize it now.
+ * Fall back to PIO mode, if it fails.
+ */
+ if (i2c_dev->dma_mode && !i2c_dev->dma_buf) {
+ err = tegra_i2c_init_dma(i2c_dev);
+ if (err)
+ i2c_dev->dma_mode = false;
+ }

tegra_i2c_config_fifo_trig(i2c_dev, xfer_size);

@@ -1473,7 +1478,6 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = {
.has_mst_fifo = false,
.quirks = &tegra_i2c_quirks,
.supports_bus_clear = false,
- .has_apb_dma = true,
.tlow_std_mode = 0x4,
.thigh_std_mode = 0x2,
.tlow_fast_fastplus_mode = 0x4,
@@ -1497,7 +1501,6 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = {
.has_mst_fifo = false,
.quirks = &tegra_i2c_quirks,
.supports_bus_clear = false,
- .has_apb_dma = true,
.tlow_std_mode = 0x4,
.thigh_std_mode = 0x2,
.tlow_fast_fastplus_mode = 0x4,
@@ -1521,7 +1524,6 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = {
.has_mst_fifo = false,
.quirks = &tegra_i2c_quirks,
.supports_bus_clear = true,
- .has_apb_dma = true,
.tlow_std_mode = 0x4,
.thigh_std_mode = 0x2,
.tlow_fast_fastplus_mode = 0x4,
@@ -1545,7 +1547,6 @@ static const struct tegra_i2c_hw_feature tegra124_i2c_hw = {
.has_mst_fifo = false,
.quirks = &tegra_i2c_quirks,
.supports_bus_clear = true,
- .has_apb_dma = true,
.tlow_std_mode = 0x4,
.thigh_std_mode = 0x2,
.tlow_fast_fastplus_mode = 0x4,
@@ -1569,7 +1570,6 @@ static const struct tegra_i2c_hw_feature tegra210_i2c_hw = {
.has_mst_fifo = false,
.quirks = &tegra_i2c_quirks,
.supports_bus_clear = true,
- .has_apb_dma = true,
.tlow_std_mode = 0x4,
.thigh_std_mode = 0x2,
.tlow_fast_fastplus_mode = 0x4,
@@ -1593,7 +1593,6 @@ static const struct tegra_i2c_hw_feature tegra186_i2c_hw = {
.has_mst_fifo = false,
.quirks = &tegra_i2c_quirks,
.supports_bus_clear = true,
- .has_apb_dma = false,
.tlow_std_mode = 0x4,
.thigh_std_mode = 0x3,
.tlow_fast_fastplus_mode = 0x4,
@@ -1617,7 +1616,6 @@ static const struct tegra_i2c_hw_feature tegra194_i2c_hw = {
.has_mst_fifo = true,
.quirks = &tegra194_i2c_quirks,
.supports_bus_clear = true,
- .has_apb_dma = false,
.tlow_std_mode = 0x8,
.thigh_std_mode = 0x7,
.tlow_fast_fastplus_mode = 0x2,
@@ -1657,6 +1655,8 @@ static void tegra_i2c_parse_dt(struct tegra_i2c_dev *i2c_dev)

if (of_device_is_compatible(np, "nvidia,tegra210-i2c-vi"))
i2c_dev->is_vi = true;
+ else
+ i2c_dev->dma_support = !!(of_find_property(np, "dmas", NULL));
}

static int tegra_i2c_init_reset(struct tegra_i2c_dev *i2c_dev)
@@ -1789,9 +1789,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
if (err)
return err;

- err = tegra_i2c_init_dma(i2c_dev);
- if (err)
- goto release_clocks;
+ tegra_i2c_init_dma(i2c_dev);

/*
* VI I2C is in VE power domain which is not always ON and not
@@ -1838,7 +1836,6 @@ static int tegra_i2c_probe(struct platform_device *pdev)
pm_runtime_disable(i2c_dev->dev);

tegra_i2c_release_dma(i2c_dev);
-release_clocks:
tegra_i2c_release_clocks(i2c_dev);

return err;
--
2.17.1