aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma/ste_dma40.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/dma/ste_dma40.c')
-rw-r--r--drivers/dma/ste_dma40.c141
1 files changed, 137 insertions, 4 deletions
diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c
index 21a759731ef1..17e2600a00cf 100644
--- a/drivers/dma/ste_dma40.c
+++ b/drivers/dma/ste_dma40.c
@@ -208,6 +208,9 @@ struct d40_chan {
208 struct d40_def_lcsp log_def; 208 struct d40_def_lcsp log_def;
209 struct d40_lcla_elem lcla; 209 struct d40_lcla_elem lcla;
210 struct d40_log_lli_full *lcpa; 210 struct d40_log_lli_full *lcpa;
211 /* Runtime reconfiguration */
212 dma_addr_t runtime_addr;
213 enum dma_data_direction runtime_direction;
211}; 214};
212 215
213/** 216/**
@@ -1886,9 +1889,16 @@ static int d40_prep_slave_sg_log(struct d40_desc *d40d,
1886 d40d->lli_tx_len = 1; 1889 d40d->lli_tx_len = 1;
1887 1890
1888 if (direction == DMA_FROM_DEVICE) 1891 if (direction == DMA_FROM_DEVICE)
1889 dev_addr = d40c->base->plat_data->dev_rx[d40c->dma_cfg.src_dev_type]; 1892 if (d40c->runtime_addr)
1893 dev_addr = d40c->runtime_addr;
1894 else
1895 dev_addr = d40c->base->plat_data->dev_rx[d40c->dma_cfg.src_dev_type];
1890 else if (direction == DMA_TO_DEVICE) 1896 else if (direction == DMA_TO_DEVICE)
1891 dev_addr = d40c->base->plat_data->dev_tx[d40c->dma_cfg.dst_dev_type]; 1897 if (d40c->runtime_addr)
1898 dev_addr = d40c->runtime_addr;
1899 else
1900 dev_addr = d40c->base->plat_data->dev_tx[d40c->dma_cfg.dst_dev_type];
1901
1892 else 1902 else
1893 return -EINVAL; 1903 return -EINVAL;
1894 1904
@@ -1931,9 +1941,15 @@ static int d40_prep_slave_sg_phy(struct d40_desc *d40d,
1931 1941
1932 if (direction == DMA_FROM_DEVICE) { 1942 if (direction == DMA_FROM_DEVICE) {
1933 dst_dev_addr = 0; 1943 dst_dev_addr = 0;
1934 src_dev_addr = d40c->base->plat_data->dev_rx[d40c->dma_cfg.src_dev_type]; 1944 if (d40c->runtime_addr)
1945 src_dev_addr = d40c->runtime_addr;
1946 else
1947 src_dev_addr = d40c->base->plat_data->dev_rx[d40c->dma_cfg.src_dev_type];
1935 } else if (direction == DMA_TO_DEVICE) { 1948 } else if (direction == DMA_TO_DEVICE) {
1936 dst_dev_addr = d40c->base->plat_data->dev_tx[d40c->dma_cfg.dst_dev_type]; 1949 if (d40c->runtime_addr)
1950 dst_dev_addr = d40c->runtime_addr;
1951 else
1952 dst_dev_addr = d40c->base->plat_data->dev_tx[d40c->dma_cfg.dst_dev_type];
1937 src_dev_addr = 0; 1953 src_dev_addr = 0;
1938 } else 1954 } else
1939 return -EINVAL; 1955 return -EINVAL;
@@ -2070,6 +2086,117 @@ static void d40_issue_pending(struct dma_chan *chan)
2070 spin_unlock_irqrestore(&d40c->lock, flags); 2086 spin_unlock_irqrestore(&d40c->lock, flags);
2071} 2087}
2072 2088
2089/* Runtime reconfiguration extension */
2090static void d40_set_runtime_config(struct dma_chan *chan,
2091 struct dma_slave_config *config)
2092{
2093 struct d40_chan *d40c = container_of(chan, struct d40_chan, chan);
2094 struct stedma40_chan_cfg *cfg = &d40c->dma_cfg;
2095 enum dma_slave_buswidth config_addr_width;
2096 dma_addr_t config_addr;
2097 u32 config_maxburst;
2098 enum stedma40_periph_data_width addr_width;
2099 int psize;
2100
2101 if (config->direction == DMA_FROM_DEVICE) {
2102 dma_addr_t dev_addr_rx =
2103 d40c->base->plat_data->dev_rx[cfg->src_dev_type];
2104
2105 config_addr = config->src_addr;
2106 if (dev_addr_rx)
2107 dev_dbg(d40c->base->dev,
2108 "channel has a pre-wired RX address %08x "
2109 "overriding with %08x\n",
2110 dev_addr_rx, config_addr);
2111 if (cfg->dir != STEDMA40_PERIPH_TO_MEM)
2112 dev_dbg(d40c->base->dev,
2113 "channel was not configured for peripheral "
2114 "to memory transfer (%d) overriding\n",
2115 cfg->dir);
2116 cfg->dir = STEDMA40_PERIPH_TO_MEM;
2117
2118 config_addr_width = config->src_addr_width;
2119 config_maxburst = config->src_maxburst;
2120
2121 } else if (config->direction == DMA_TO_DEVICE) {
2122 dma_addr_t dev_addr_tx =
2123 d40c->base->plat_data->dev_tx[cfg->dst_dev_type];
2124
2125 config_addr = config->dst_addr;
2126 if (dev_addr_tx)
2127 dev_dbg(d40c->base->dev,
2128 "channel has a pre-wired TX address %08x "
2129 "overriding with %08x\n",
2130 dev_addr_tx, config_addr);
2131 if (cfg->dir != STEDMA40_MEM_TO_PERIPH)
2132 dev_dbg(d40c->base->dev,
2133 "channel was not configured for memory "
2134 "to peripheral transfer (%d) overriding\n",
2135 cfg->dir);
2136 cfg->dir = STEDMA40_MEM_TO_PERIPH;
2137
2138 config_addr_width = config->dst_addr_width;
2139 config_maxburst = config->dst_maxburst;
2140
2141 } else {
2142 dev_err(d40c->base->dev,
2143 "unrecognized channel direction %d\n",
2144 config->direction);
2145 return;
2146 }
2147
2148 switch (config_addr_width) {
2149 case DMA_SLAVE_BUSWIDTH_1_BYTE:
2150 addr_width = STEDMA40_BYTE_WIDTH;
2151 break;
2152 case DMA_SLAVE_BUSWIDTH_2_BYTES:
2153 addr_width = STEDMA40_HALFWORD_WIDTH;
2154 break;
2155 case DMA_SLAVE_BUSWIDTH_4_BYTES:
2156 addr_width = STEDMA40_WORD_WIDTH;
2157 break;
2158 case DMA_SLAVE_BUSWIDTH_8_BYTES:
2159 addr_width = STEDMA40_DOUBLEWORD_WIDTH;
2160 break;
2161 default:
2162 dev_err(d40c->base->dev,
2163 "illegal peripheral address width "
2164 "requested (%d)\n",
2165 config->src_addr_width);
2166 return;
2167 }
2168
2169 if (config_maxburst >= 16)
2170 psize = STEDMA40_PSIZE_LOG_16;
2171 else if (config_maxburst >= 8)
2172 psize = STEDMA40_PSIZE_LOG_8;
2173 else if (config_maxburst >= 4)
2174 psize = STEDMA40_PSIZE_LOG_4;
2175 else
2176 psize = STEDMA40_PSIZE_LOG_1;
2177
2178 /* Set up all the endpoint configs */
2179 cfg->src_info.data_width = addr_width;
2180 cfg->src_info.psize = psize;
2181 cfg->src_info.endianess = STEDMA40_LITTLE_ENDIAN;
2182 cfg->src_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL;
2183 cfg->dst_info.data_width = addr_width;
2184 cfg->dst_info.psize = psize;
2185 cfg->dst_info.endianess = STEDMA40_LITTLE_ENDIAN;
2186 cfg->dst_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL;
2187
2188 /* These settings will take precedence later */
2189 d40c->runtime_addr = config_addr;
2190 d40c->runtime_direction = config->direction;
2191 dev_dbg(d40c->base->dev,
2192 "configured channel %s for %s, data width %d, "
2193 "maxburst %d bytes, LE, no flow control\n",
2194 dma_chan_name(chan),
2195 (config->direction == DMA_FROM_DEVICE) ? "RX" : "TX",
2196 config_addr_width,
2197 config_maxburst);
2198}
2199
2073static int d40_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, 2200static int d40_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
2074 unsigned long arg) 2201 unsigned long arg)
2075{ 2202{
@@ -2092,6 +2219,12 @@ static int d40_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
2092 return d40_pause(chan); 2219 return d40_pause(chan);
2093 case DMA_RESUME: 2220 case DMA_RESUME:
2094 return d40_resume(chan); 2221 return d40_resume(chan);
2222 case DMA_SLAVE_CONFIG:
2223 d40_set_runtime_config(chan,
2224 (struct dma_slave_config *) arg);
2225 return 0;
2226 default:
2227 break;
2095 } 2228 }
2096 2229
2097 /* Other commands are unimplemented */ 2230 /* Other commands are unimplemented */