mirror of https://github.com/torvalds/linux.git
dmaengine: tegra210-adma: Add Tegra264 support
Add Tegra264 ADMA support with following changes: - Add soc_data for Tegra264-specific variations. - Tegra264 supports 64 channels and 10 pages, hence update the global page configuration. - In Tegra264 FIFO and outstanding request configs are moved to global registers, hence add those registers offset in adma channel struct. Also, 'has_outstanding_reqs' is removed and configuration moved to the SoC data. - Update channel direction and mode bit positions as per Tegra264. - Register offsets are updated to align with Tegra264. Signed-off-by: Sheetal <sheetal@nvidia.com> Link: https://lore.kernel.org/r/20250512050010.1025259-3-sheetal@nvidia.com Signed-off-by: Vinod Koul <vkoul@kernel.org>
This commit is contained in:
parent
b81cd165e4
commit
21e1273877
|
|
@ -27,10 +27,10 @@
|
|||
|
||||
#define ADMA_CH_INT_CLEAR 0x1c
|
||||
#define ADMA_CH_CTRL 0x24
|
||||
#define ADMA_CH_CTRL_DIR(val) (((val) & 0xf) << 12)
|
||||
#define ADMA_CH_CTRL_DIR(val, mask, shift) (((val) & (mask)) << (shift))
|
||||
#define ADMA_CH_CTRL_DIR_AHUB2MEM 2
|
||||
#define ADMA_CH_CTRL_DIR_MEM2AHUB 4
|
||||
#define ADMA_CH_CTRL_MODE_CONTINUOUS (2 << 8)
|
||||
#define ADMA_CH_CTRL_MODE_CONTINUOUS(shift) (2 << (shift))
|
||||
#define ADMA_CH_CTRL_FLOWCTRL_EN BIT(1)
|
||||
#define ADMA_CH_CTRL_XFER_PAUSE_SHIFT 0
|
||||
|
||||
|
|
@ -41,15 +41,27 @@
|
|||
#define ADMA_CH_CONFIG_MAX_BURST_SIZE 16
|
||||
#define ADMA_CH_CONFIG_WEIGHT_FOR_WRR(val) ((val) & 0xf)
|
||||
#define ADMA_CH_CONFIG_MAX_BUFS 8
|
||||
#define TEGRA186_ADMA_CH_CONFIG_OUTSTANDING_REQS(reqs) (reqs << 4)
|
||||
#define TEGRA186_ADMA_CH_CONFIG_OUTSTANDING_REQS(reqs) ((reqs) << 4)
|
||||
|
||||
#define ADMA_GLOBAL_CH_CONFIG 0x400
|
||||
#define ADMA_GLOBAL_CH_CONFIG_WEIGHT_FOR_WRR(val) ((val) & 0x7)
|
||||
#define ADMA_GLOBAL_CH_CONFIG_OUTSTANDING_REQS(reqs) ((reqs) << 8)
|
||||
|
||||
#define TEGRA186_ADMA_GLOBAL_PAGE_CHGRP 0x30
|
||||
#define TEGRA186_ADMA_GLOBAL_PAGE_RX_REQ 0x70
|
||||
#define TEGRA186_ADMA_GLOBAL_PAGE_TX_REQ 0x84
|
||||
#define TEGRA264_ADMA_GLOBAL_PAGE_CHGRP_0 0x44
|
||||
#define TEGRA264_ADMA_GLOBAL_PAGE_CHGRP_1 0x48
|
||||
#define TEGRA264_ADMA_GLOBAL_PAGE_RX_REQ_0 0x100
|
||||
#define TEGRA264_ADMA_GLOBAL_PAGE_RX_REQ_1 0x104
|
||||
#define TEGRA264_ADMA_GLOBAL_PAGE_TX_REQ_0 0x180
|
||||
#define TEGRA264_ADMA_GLOBAL_PAGE_TX_REQ_1 0x184
|
||||
#define TEGRA264_ADMA_GLOBAL_PAGE_OFFSET 0x8
|
||||
|
||||
#define ADMA_CH_FIFO_CTRL 0x2c
|
||||
#define ADMA_CH_TX_FIFO_SIZE_SHIFT 8
|
||||
#define ADMA_CH_RX_FIFO_SIZE_SHIFT 0
|
||||
#define ADMA_GLOBAL_CH_FIFO_CTRL 0x300
|
||||
|
||||
#define ADMA_CH_LOWER_SRC_ADDR 0x34
|
||||
#define ADMA_CH_LOWER_TRG_ADDR 0x3c
|
||||
|
|
@ -73,36 +85,48 @@ struct tegra_adma;
|
|||
* @adma_get_burst_config: Function callback used to set DMA burst size.
|
||||
* @global_reg_offset: Register offset of DMA global register.
|
||||
* @global_int_clear: Register offset of DMA global interrupt clear.
|
||||
* @global_ch_fifo_base: Global channel fifo ctrl base offset
|
||||
* @global_ch_config_base: Global channel config base offset
|
||||
* @ch_req_tx_shift: Register offset for AHUB transmit channel select.
|
||||
* @ch_req_rx_shift: Register offset for AHUB receive channel select.
|
||||
* @ch_dir_shift: Channel direction bit position.
|
||||
* @ch_mode_shift: Channel mode bit position.
|
||||
* @ch_base_offset: Register offset of DMA channel registers.
|
||||
* @ch_tc_offset_diff: From TC register onwards offset differs for Tegra264
|
||||
* @ch_fifo_ctrl: Default value for channel FIFO CTRL register.
|
||||
* @ch_config: Outstanding and WRR config values
|
||||
* @ch_req_mask: Mask for Tx or Rx channel select.
|
||||
* @ch_dir_mask: Mask for channel direction.
|
||||
* @ch_req_max: Maximum number of Tx or Rx channels available.
|
||||
* @ch_reg_size: Size of DMA channel register space.
|
||||
* @nr_channels: Number of DMA channels available.
|
||||
* @ch_fifo_size_mask: Mask for FIFO size field.
|
||||
* @sreq_index_offset: Slave channel index offset.
|
||||
* @max_page: Maximum ADMA Channel Page.
|
||||
* @has_outstanding_reqs: If DMA channel can have outstanding requests.
|
||||
* @set_global_pg_config: Global page programming.
|
||||
*/
|
||||
struct tegra_adma_chip_data {
|
||||
unsigned int (*adma_get_burst_config)(unsigned int burst_size);
|
||||
unsigned int global_reg_offset;
|
||||
unsigned int global_int_clear;
|
||||
unsigned int global_ch_fifo_base;
|
||||
unsigned int global_ch_config_base;
|
||||
unsigned int ch_req_tx_shift;
|
||||
unsigned int ch_req_rx_shift;
|
||||
unsigned int ch_dir_shift;
|
||||
unsigned int ch_mode_shift;
|
||||
unsigned int ch_base_offset;
|
||||
unsigned int ch_tc_offset_diff;
|
||||
unsigned int ch_fifo_ctrl;
|
||||
unsigned int ch_config;
|
||||
unsigned int ch_req_mask;
|
||||
unsigned int ch_dir_mask;
|
||||
unsigned int ch_req_max;
|
||||
unsigned int ch_reg_size;
|
||||
unsigned int nr_channels;
|
||||
unsigned int ch_fifo_size_mask;
|
||||
unsigned int sreq_index_offset;
|
||||
unsigned int max_page;
|
||||
bool has_outstanding_reqs;
|
||||
void (*set_global_pg_config)(struct tegra_adma *tdma);
|
||||
};
|
||||
|
||||
|
|
@ -112,6 +136,7 @@ struct tegra_adma_chip_data {
|
|||
struct tegra_adma_chan_regs {
|
||||
unsigned int ctrl;
|
||||
unsigned int config;
|
||||
unsigned int global_config;
|
||||
unsigned int src_addr;
|
||||
unsigned int trg_addr;
|
||||
unsigned int fifo_ctrl;
|
||||
|
|
@ -150,6 +175,9 @@ struct tegra_adma_chan {
|
|||
/* Transfer count and position info */
|
||||
unsigned int tx_buf_count;
|
||||
unsigned int tx_buf_pos;
|
||||
|
||||
unsigned int global_ch_fifo_offset;
|
||||
unsigned int global_ch_config_offset;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -246,6 +274,29 @@ static void tegra186_adma_global_page_config(struct tegra_adma *tdma)
|
|||
tdma_write(tdma, TEGRA186_ADMA_GLOBAL_PAGE_TX_REQ + (tdma->ch_page_no * 0x4), 0xffffff);
|
||||
}
|
||||
|
||||
static void tegra264_adma_global_page_config(struct tegra_adma *tdma)
|
||||
{
|
||||
u32 global_page_offset = tdma->ch_page_no * TEGRA264_ADMA_GLOBAL_PAGE_OFFSET;
|
||||
|
||||
/* If the default page (page1) is not used, then clear page1 registers */
|
||||
if (tdma->ch_page_no) {
|
||||
tdma_write(tdma, TEGRA264_ADMA_GLOBAL_PAGE_CHGRP_0, 0);
|
||||
tdma_write(tdma, TEGRA264_ADMA_GLOBAL_PAGE_CHGRP_1, 0);
|
||||
tdma_write(tdma, TEGRA264_ADMA_GLOBAL_PAGE_RX_REQ_0, 0);
|
||||
tdma_write(tdma, TEGRA264_ADMA_GLOBAL_PAGE_RX_REQ_1, 0);
|
||||
tdma_write(tdma, TEGRA264_ADMA_GLOBAL_PAGE_TX_REQ_0, 0);
|
||||
tdma_write(tdma, TEGRA264_ADMA_GLOBAL_PAGE_TX_REQ_1, 0);
|
||||
}
|
||||
|
||||
/* Program global registers for selected page */
|
||||
tdma_write(tdma, TEGRA264_ADMA_GLOBAL_PAGE_CHGRP_0 + global_page_offset, 0xffffffff);
|
||||
tdma_write(tdma, TEGRA264_ADMA_GLOBAL_PAGE_CHGRP_1 + global_page_offset, 0xffffffff);
|
||||
tdma_write(tdma, TEGRA264_ADMA_GLOBAL_PAGE_RX_REQ_0 + global_page_offset, 0xffffffff);
|
||||
tdma_write(tdma, TEGRA264_ADMA_GLOBAL_PAGE_RX_REQ_1 + global_page_offset, 0x1);
|
||||
tdma_write(tdma, TEGRA264_ADMA_GLOBAL_PAGE_TX_REQ_0 + global_page_offset, 0xffffffff);
|
||||
tdma_write(tdma, TEGRA264_ADMA_GLOBAL_PAGE_TX_REQ_1 + global_page_offset, 0x1);
|
||||
}
|
||||
|
||||
static int tegra_adma_init(struct tegra_adma *tdma)
|
||||
{
|
||||
u32 status;
|
||||
|
|
@ -404,11 +455,21 @@ static void tegra_adma_start(struct tegra_adma_chan *tdc)
|
|||
|
||||
tdc->tx_buf_pos = 0;
|
||||
tdc->tx_buf_count = 0;
|
||||
tdma_ch_write(tdc, ADMA_CH_TC, ch_regs->tc);
|
||||
tdma_ch_write(tdc, ADMA_CH_TC - tdc->tdma->cdata->ch_tc_offset_diff, ch_regs->tc);
|
||||
tdma_ch_write(tdc, ADMA_CH_CTRL, ch_regs->ctrl);
|
||||
tdma_ch_write(tdc, ADMA_CH_LOWER_SRC_ADDR, ch_regs->src_addr);
|
||||
tdma_ch_write(tdc, ADMA_CH_LOWER_TRG_ADDR, ch_regs->trg_addr);
|
||||
tdma_ch_write(tdc, ADMA_CH_FIFO_CTRL, ch_regs->fifo_ctrl);
|
||||
tdma_ch_write(tdc, ADMA_CH_LOWER_SRC_ADDR - tdc->tdma->cdata->ch_tc_offset_diff,
|
||||
ch_regs->src_addr);
|
||||
tdma_ch_write(tdc, ADMA_CH_LOWER_TRG_ADDR - tdc->tdma->cdata->ch_tc_offset_diff,
|
||||
ch_regs->trg_addr);
|
||||
|
||||
if (!tdc->tdma->cdata->global_ch_fifo_base)
|
||||
tdma_ch_write(tdc, ADMA_CH_FIFO_CTRL, ch_regs->fifo_ctrl);
|
||||
else if (tdc->global_ch_fifo_offset)
|
||||
tdma_write(tdc->tdma, tdc->global_ch_fifo_offset, ch_regs->fifo_ctrl);
|
||||
|
||||
if (tdc->global_ch_config_offset)
|
||||
tdma_write(tdc->tdma, tdc->global_ch_config_offset, ch_regs->global_config);
|
||||
|
||||
tdma_ch_write(tdc, ADMA_CH_CONFIG, ch_regs->config);
|
||||
|
||||
/* Start ADMA */
|
||||
|
|
@ -421,7 +482,8 @@ static unsigned int tegra_adma_get_residue(struct tegra_adma_chan *tdc)
|
|||
{
|
||||
struct tegra_adma_desc *desc = tdc->desc;
|
||||
unsigned int max = ADMA_CH_XFER_STATUS_COUNT_MASK + 1;
|
||||
unsigned int pos = tdma_ch_read(tdc, ADMA_CH_XFER_STATUS);
|
||||
unsigned int pos = tdma_ch_read(tdc, ADMA_CH_XFER_STATUS -
|
||||
tdc->tdma->cdata->ch_tc_offset_diff);
|
||||
unsigned int periods_remaining;
|
||||
|
||||
/*
|
||||
|
|
@ -627,13 +689,16 @@ static int tegra_adma_set_xfer_params(struct tegra_adma_chan *tdc,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
ch_regs->ctrl |= ADMA_CH_CTRL_DIR(adma_dir) |
|
||||
ADMA_CH_CTRL_MODE_CONTINUOUS |
|
||||
ch_regs->ctrl |= ADMA_CH_CTRL_DIR(adma_dir, cdata->ch_dir_mask,
|
||||
cdata->ch_dir_shift) |
|
||||
ADMA_CH_CTRL_MODE_CONTINUOUS(cdata->ch_mode_shift) |
|
||||
ADMA_CH_CTRL_FLOWCTRL_EN;
|
||||
ch_regs->config |= cdata->adma_get_burst_config(burst_size);
|
||||
ch_regs->config |= ADMA_CH_CONFIG_WEIGHT_FOR_WRR(1);
|
||||
if (cdata->has_outstanding_reqs)
|
||||
ch_regs->config |= TEGRA186_ADMA_CH_CONFIG_OUTSTANDING_REQS(8);
|
||||
|
||||
if (cdata->global_ch_config_base)
|
||||
ch_regs->global_config |= cdata->ch_config;
|
||||
else
|
||||
ch_regs->config |= cdata->ch_config;
|
||||
|
||||
/*
|
||||
* 'sreq_index' represents the current ADMAIF channel number and as per
|
||||
|
|
@ -788,12 +853,23 @@ static int __maybe_unused tegra_adma_runtime_suspend(struct device *dev)
|
|||
/* skip if channel is not active */
|
||||
if (!ch_reg->cmd)
|
||||
continue;
|
||||
ch_reg->tc = tdma_ch_read(tdc, ADMA_CH_TC);
|
||||
ch_reg->src_addr = tdma_ch_read(tdc, ADMA_CH_LOWER_SRC_ADDR);
|
||||
ch_reg->trg_addr = tdma_ch_read(tdc, ADMA_CH_LOWER_TRG_ADDR);
|
||||
ch_reg->tc = tdma_ch_read(tdc, ADMA_CH_TC - tdma->cdata->ch_tc_offset_diff);
|
||||
ch_reg->src_addr = tdma_ch_read(tdc, ADMA_CH_LOWER_SRC_ADDR -
|
||||
tdma->cdata->ch_tc_offset_diff);
|
||||
ch_reg->trg_addr = tdma_ch_read(tdc, ADMA_CH_LOWER_TRG_ADDR -
|
||||
tdma->cdata->ch_tc_offset_diff);
|
||||
ch_reg->ctrl = tdma_ch_read(tdc, ADMA_CH_CTRL);
|
||||
ch_reg->fifo_ctrl = tdma_ch_read(tdc, ADMA_CH_FIFO_CTRL);
|
||||
|
||||
if (tdc->global_ch_config_offset)
|
||||
ch_reg->global_config = tdma_read(tdc->tdma, tdc->global_ch_config_offset);
|
||||
|
||||
if (!tdc->tdma->cdata->global_ch_fifo_base)
|
||||
ch_reg->fifo_ctrl = tdma_ch_read(tdc, ADMA_CH_FIFO_CTRL);
|
||||
else if (tdc->global_ch_fifo_offset)
|
||||
ch_reg->fifo_ctrl = tdma_read(tdc->tdma, tdc->global_ch_fifo_offset);
|
||||
|
||||
ch_reg->config = tdma_ch_read(tdc, ADMA_CH_CONFIG);
|
||||
|
||||
}
|
||||
|
||||
clk_disable:
|
||||
|
|
@ -832,12 +908,23 @@ static int __maybe_unused tegra_adma_runtime_resume(struct device *dev)
|
|||
/* skip if channel was not active earlier */
|
||||
if (!ch_reg->cmd)
|
||||
continue;
|
||||
tdma_ch_write(tdc, ADMA_CH_TC, ch_reg->tc);
|
||||
tdma_ch_write(tdc, ADMA_CH_LOWER_SRC_ADDR, ch_reg->src_addr);
|
||||
tdma_ch_write(tdc, ADMA_CH_LOWER_TRG_ADDR, ch_reg->trg_addr);
|
||||
tdma_ch_write(tdc, ADMA_CH_TC - tdma->cdata->ch_tc_offset_diff, ch_reg->tc);
|
||||
tdma_ch_write(tdc, ADMA_CH_LOWER_SRC_ADDR - tdma->cdata->ch_tc_offset_diff,
|
||||
ch_reg->src_addr);
|
||||
tdma_ch_write(tdc, ADMA_CH_LOWER_TRG_ADDR - tdma->cdata->ch_tc_offset_diff,
|
||||
ch_reg->trg_addr);
|
||||
tdma_ch_write(tdc, ADMA_CH_CTRL, ch_reg->ctrl);
|
||||
tdma_ch_write(tdc, ADMA_CH_FIFO_CTRL, ch_reg->fifo_ctrl);
|
||||
|
||||
if (!tdc->tdma->cdata->global_ch_fifo_base)
|
||||
tdma_ch_write(tdc, ADMA_CH_FIFO_CTRL, ch_reg->fifo_ctrl);
|
||||
else if (tdc->global_ch_fifo_offset)
|
||||
tdma_write(tdc->tdma, tdc->global_ch_fifo_offset, ch_reg->fifo_ctrl);
|
||||
|
||||
if (tdc->global_ch_config_offset)
|
||||
tdma_write(tdc->tdma, tdc->global_ch_config_offset, ch_reg->global_config);
|
||||
|
||||
tdma_ch_write(tdc, ADMA_CH_CONFIG, ch_reg->config);
|
||||
|
||||
tdma_ch_write(tdc, ADMA_CH_CMD, ch_reg->cmd);
|
||||
}
|
||||
|
||||
|
|
@ -848,17 +935,23 @@ static const struct tegra_adma_chip_data tegra210_chip_data = {
|
|||
.adma_get_burst_config = tegra210_adma_get_burst_config,
|
||||
.global_reg_offset = 0xc00,
|
||||
.global_int_clear = 0x20,
|
||||
.global_ch_fifo_base = 0,
|
||||
.global_ch_config_base = 0,
|
||||
.ch_req_tx_shift = 28,
|
||||
.ch_req_rx_shift = 24,
|
||||
.ch_dir_shift = 12,
|
||||
.ch_mode_shift = 8,
|
||||
.ch_base_offset = 0,
|
||||
.ch_tc_offset_diff = 0,
|
||||
.ch_config = ADMA_CH_CONFIG_WEIGHT_FOR_WRR(1),
|
||||
.ch_req_mask = 0xf,
|
||||
.ch_dir_mask = 0xf,
|
||||
.ch_req_max = 10,
|
||||
.ch_reg_size = 0x80,
|
||||
.nr_channels = 22,
|
||||
.ch_fifo_size_mask = 0xf,
|
||||
.sreq_index_offset = 2,
|
||||
.max_page = 0,
|
||||
.has_outstanding_reqs = false,
|
||||
.set_global_pg_config = NULL,
|
||||
};
|
||||
|
||||
|
|
@ -866,23 +959,56 @@ static const struct tegra_adma_chip_data tegra186_chip_data = {
|
|||
.adma_get_burst_config = tegra186_adma_get_burst_config,
|
||||
.global_reg_offset = 0,
|
||||
.global_int_clear = 0x402c,
|
||||
.global_ch_fifo_base = 0,
|
||||
.global_ch_config_base = 0,
|
||||
.ch_req_tx_shift = 27,
|
||||
.ch_req_rx_shift = 22,
|
||||
.ch_dir_shift = 12,
|
||||
.ch_mode_shift = 8,
|
||||
.ch_base_offset = 0x10000,
|
||||
.ch_tc_offset_diff = 0,
|
||||
.ch_config = ADMA_CH_CONFIG_WEIGHT_FOR_WRR(1) |
|
||||
TEGRA186_ADMA_CH_CONFIG_OUTSTANDING_REQS(8),
|
||||
.ch_req_mask = 0x1f,
|
||||
.ch_dir_mask = 0xf,
|
||||
.ch_req_max = 20,
|
||||
.ch_reg_size = 0x100,
|
||||
.nr_channels = 32,
|
||||
.ch_fifo_size_mask = 0x1f,
|
||||
.sreq_index_offset = 4,
|
||||
.max_page = 4,
|
||||
.has_outstanding_reqs = true,
|
||||
.set_global_pg_config = tegra186_adma_global_page_config,
|
||||
};
|
||||
|
||||
static const struct tegra_adma_chip_data tegra264_chip_data = {
|
||||
.adma_get_burst_config = tegra186_adma_get_burst_config,
|
||||
.global_reg_offset = 0,
|
||||
.global_int_clear = 0x800c,
|
||||
.global_ch_fifo_base = ADMA_GLOBAL_CH_FIFO_CTRL,
|
||||
.global_ch_config_base = ADMA_GLOBAL_CH_CONFIG,
|
||||
.ch_req_tx_shift = 26,
|
||||
.ch_req_rx_shift = 20,
|
||||
.ch_dir_shift = 10,
|
||||
.ch_mode_shift = 7,
|
||||
.ch_base_offset = 0x10000,
|
||||
.ch_tc_offset_diff = 4,
|
||||
.ch_config = ADMA_GLOBAL_CH_CONFIG_WEIGHT_FOR_WRR(1) |
|
||||
ADMA_GLOBAL_CH_CONFIG_OUTSTANDING_REQS(8),
|
||||
.ch_req_mask = 0x3f,
|
||||
.ch_dir_mask = 7,
|
||||
.ch_req_max = 32,
|
||||
.ch_reg_size = 0x100,
|
||||
.nr_channels = 64,
|
||||
.ch_fifo_size_mask = 0x7f,
|
||||
.sreq_index_offset = 0,
|
||||
.max_page = 10,
|
||||
.set_global_pg_config = tegra264_adma_global_page_config,
|
||||
};
|
||||
|
||||
static const struct of_device_id tegra_adma_of_match[] = {
|
||||
{ .compatible = "nvidia,tegra210-adma", .data = &tegra210_chip_data },
|
||||
{ .compatible = "nvidia,tegra186-adma", .data = &tegra186_chip_data },
|
||||
{ .compatible = "nvidia,tegra264-adma", .data = &tegra264_chip_data },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tegra_adma_of_match);
|
||||
|
|
@ -985,6 +1111,15 @@ static int tegra_adma_probe(struct platform_device *pdev)
|
|||
|
||||
tdc->chan_addr = tdma->ch_base_addr + (cdata->ch_reg_size * i);
|
||||
|
||||
if (tdma->base_addr) {
|
||||
if (cdata->global_ch_fifo_base)
|
||||
tdc->global_ch_fifo_offset = cdata->global_ch_fifo_base + (4 * i);
|
||||
|
||||
if (cdata->global_ch_config_base)
|
||||
tdc->global_ch_config_offset =
|
||||
cdata->global_ch_config_base + (4 * i);
|
||||
}
|
||||
|
||||
tdc->irq = of_irq_get(pdev->dev.of_node, i);
|
||||
if (tdc->irq <= 0) {
|
||||
ret = tdc->irq ?: -ENXIO;
|
||||
|
|
|
|||
Loading…
Reference in New Issue