aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/dma/ste_dma40.c168
1 files changed, 102 insertions, 66 deletions
diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c
index 2797f64e5e48..75ba5865d7a4 100644
--- a/drivers/dma/ste_dma40.c
+++ b/drivers/dma/ste_dma40.c
@@ -2179,17 +2179,78 @@ static void d40_issue_pending(struct dma_chan *chan)
2179 spin_unlock_irqrestore(&d40c->lock, flags); 2179 spin_unlock_irqrestore(&d40c->lock, flags);
2180} 2180}
2181 2181
2182static int
2183dma40_config_to_halfchannel(struct d40_chan *d40c,
2184 struct stedma40_half_channel_info *info,
2185 enum dma_slave_buswidth width,
2186 u32 maxburst)
2187{
2188 enum stedma40_periph_data_width addr_width;
2189 int psize;
2190
2191 switch (width) {
2192 case DMA_SLAVE_BUSWIDTH_1_BYTE:
2193 addr_width = STEDMA40_BYTE_WIDTH;
2194 break;
2195 case DMA_SLAVE_BUSWIDTH_2_BYTES:
2196 addr_width = STEDMA40_HALFWORD_WIDTH;
2197 break;
2198 case DMA_SLAVE_BUSWIDTH_4_BYTES:
2199 addr_width = STEDMA40_WORD_WIDTH;
2200 break;
2201 case DMA_SLAVE_BUSWIDTH_8_BYTES:
2202 addr_width = STEDMA40_DOUBLEWORD_WIDTH;
2203 break;
2204 default:
2205 dev_err(d40c->base->dev,
2206 "illegal peripheral address width "
2207 "requested (%d)\n",
2208 width);
2209 return -EINVAL;
2210 }
2211
2212 if (chan_is_logical(d40c)) {
2213 if (maxburst >= 16)
2214 psize = STEDMA40_PSIZE_LOG_16;
2215 else if (maxburst >= 8)
2216 psize = STEDMA40_PSIZE_LOG_8;
2217 else if (maxburst >= 4)
2218 psize = STEDMA40_PSIZE_LOG_4;
2219 else
2220 psize = STEDMA40_PSIZE_LOG_1;
2221 } else {
2222 if (maxburst >= 16)
2223 psize = STEDMA40_PSIZE_PHY_16;
2224 else if (maxburst >= 8)
2225 psize = STEDMA40_PSIZE_PHY_8;
2226 else if (maxburst >= 4)
2227 psize = STEDMA40_PSIZE_PHY_4;
2228 else
2229 psize = STEDMA40_PSIZE_PHY_1;
2230 }
2231
2232 info->data_width = addr_width;
2233 info->psize = psize;
2234 info->flow_ctrl = STEDMA40_NO_FLOW_CTRL;
2235
2236 return 0;
2237}
2238
2182/* Runtime reconfiguration extension */ 2239/* Runtime reconfiguration extension */
2183static void d40_set_runtime_config(struct dma_chan *chan, 2240static int d40_set_runtime_config(struct dma_chan *chan,
2184 struct dma_slave_config *config) 2241 struct dma_slave_config *config)
2185{ 2242{
2186 struct d40_chan *d40c = container_of(chan, struct d40_chan, chan); 2243 struct d40_chan *d40c = container_of(chan, struct d40_chan, chan);
2187 struct stedma40_chan_cfg *cfg = &d40c->dma_cfg; 2244 struct stedma40_chan_cfg *cfg = &d40c->dma_cfg;
2188 enum dma_slave_buswidth config_addr_width; 2245 enum dma_slave_buswidth src_addr_width, dst_addr_width;
2189 dma_addr_t config_addr; 2246 dma_addr_t config_addr;
2190 u32 config_maxburst; 2247 u32 src_maxburst, dst_maxburst;
2191 enum stedma40_periph_data_width addr_width; 2248 int ret;
2192 int psize; 2249
2250 src_addr_width = config->src_addr_width;
2251 src_maxburst = config->src_maxburst;
2252 dst_addr_width = config->dst_addr_width;
2253 dst_maxburst = config->dst_maxburst;
2193 2254
2194 if (config->direction == DMA_FROM_DEVICE) { 2255 if (config->direction == DMA_FROM_DEVICE) {
2195 dma_addr_t dev_addr_rx = 2256 dma_addr_t dev_addr_rx =
@@ -2208,8 +2269,11 @@ static void d40_set_runtime_config(struct dma_chan *chan,
2208 cfg->dir); 2269 cfg->dir);
2209 cfg->dir = STEDMA40_PERIPH_TO_MEM; 2270 cfg->dir = STEDMA40_PERIPH_TO_MEM;
2210 2271
2211 config_addr_width = config->src_addr_width; 2272 /* Configure the memory side */
2212 config_maxburst = config->src_maxburst; 2273 if (dst_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED)
2274 dst_addr_width = src_addr_width;
2275 if (dst_maxburst == 0)
2276 dst_maxburst = src_maxburst;
2213 2277
2214 } else if (config->direction == DMA_TO_DEVICE) { 2278 } else if (config->direction == DMA_TO_DEVICE) {
2215 dma_addr_t dev_addr_tx = 2279 dma_addr_t dev_addr_tx =
@@ -2228,68 +2292,39 @@ static void d40_set_runtime_config(struct dma_chan *chan,
2228 cfg->dir); 2292 cfg->dir);
2229 cfg->dir = STEDMA40_MEM_TO_PERIPH; 2293 cfg->dir = STEDMA40_MEM_TO_PERIPH;
2230 2294
2231 config_addr_width = config->dst_addr_width; 2295 /* Configure the memory side */
2232 config_maxburst = config->dst_maxburst; 2296 if (src_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED)
2233 2297 src_addr_width = dst_addr_width;
2298 if (src_maxburst == 0)
2299 src_maxburst = dst_maxburst;
2234 } else { 2300 } else {
2235 dev_err(d40c->base->dev, 2301 dev_err(d40c->base->dev,
2236 "unrecognized channel direction %d\n", 2302 "unrecognized channel direction %d\n",
2237 config->direction); 2303 config->direction);
2238 return; 2304 return -EINVAL;
2239 } 2305 }
2240 2306
2241 switch (config_addr_width) { 2307 if (src_maxburst * src_addr_width != dst_maxburst * dst_addr_width) {
2242 case DMA_SLAVE_BUSWIDTH_1_BYTE:
2243 addr_width = STEDMA40_BYTE_WIDTH;
2244 break;
2245 case DMA_SLAVE_BUSWIDTH_2_BYTES:
2246 addr_width = STEDMA40_HALFWORD_WIDTH;
2247 break;
2248 case DMA_SLAVE_BUSWIDTH_4_BYTES:
2249 addr_width = STEDMA40_WORD_WIDTH;
2250 break;
2251 case DMA_SLAVE_BUSWIDTH_8_BYTES:
2252 addr_width = STEDMA40_DOUBLEWORD_WIDTH;
2253 break;
2254 default:
2255 dev_err(d40c->base->dev, 2308 dev_err(d40c->base->dev,
2256 "illegal peripheral address width " 2309 "src/dst width/maxburst mismatch: %d*%d != %d*%d\n",
2257 "requested (%d)\n", 2310 src_maxburst,
2258 config->src_addr_width); 2311 src_addr_width,
2259 return; 2312 dst_maxburst,
2313 dst_addr_width);
2314 return -EINVAL;
2260 } 2315 }
2261 2316
2262 if (chan_is_logical(d40c)) { 2317 ret = dma40_config_to_halfchannel(d40c, &cfg->src_info,
2263 if (config_maxburst >= 16) 2318 src_addr_width,
2264 psize = STEDMA40_PSIZE_LOG_16; 2319 src_maxburst);
2265 else if (config_maxburst >= 8) 2320 if (ret)
2266 psize = STEDMA40_PSIZE_LOG_8; 2321 return ret;
2267 else if (config_maxburst >= 4)
2268 psize = STEDMA40_PSIZE_LOG_4;
2269 else
2270 psize = STEDMA40_PSIZE_LOG_1;
2271 } else {
2272 if (config_maxburst >= 16)
2273 psize = STEDMA40_PSIZE_PHY_16;
2274 else if (config_maxburst >= 8)
2275 psize = STEDMA40_PSIZE_PHY_8;
2276 else if (config_maxburst >= 4)
2277 psize = STEDMA40_PSIZE_PHY_4;
2278 else if (config_maxburst >= 2)
2279 psize = STEDMA40_PSIZE_PHY_2;
2280 else
2281 psize = STEDMA40_PSIZE_PHY_1;
2282 }
2283 2322
2284 /* Set up all the endpoint configs */ 2323 ret = dma40_config_to_halfchannel(d40c, &cfg->dst_info,
2285 cfg->src_info.data_width = addr_width; 2324 dst_addr_width,
2286 cfg->src_info.psize = psize; 2325 dst_maxburst);
2287 cfg->src_info.big_endian = false; 2326 if (ret)
2288 cfg->src_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL; 2327 return ret;
2289 cfg->dst_info.data_width = addr_width;
2290 cfg->dst_info.psize = psize;
2291 cfg->dst_info.big_endian = false;
2292 cfg->dst_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL;
2293 2328
2294 /* Fill in register values */ 2329 /* Fill in register values */
2295 if (chan_is_logical(d40c)) 2330 if (chan_is_logical(d40c))
@@ -2302,12 +2337,14 @@ static void d40_set_runtime_config(struct dma_chan *chan,
2302 d40c->runtime_addr = config_addr; 2337 d40c->runtime_addr = config_addr;
2303 d40c->runtime_direction = config->direction; 2338 d40c->runtime_direction = config->direction;
2304 dev_dbg(d40c->base->dev, 2339 dev_dbg(d40c->base->dev,
2305 "configured channel %s for %s, data width %d, " 2340 "configured channel %s for %s, data width %d/%d, "
2306 "maxburst %d bytes, LE, no flow control\n", 2341 "maxburst %d/%d elements, LE, no flow control\n",
2307 dma_chan_name(chan), 2342 dma_chan_name(chan),
2308 (config->direction == DMA_FROM_DEVICE) ? "RX" : "TX", 2343 (config->direction == DMA_FROM_DEVICE) ? "RX" : "TX",
2309 config_addr_width, 2344 src_addr_width, dst_addr_width,
2310 config_maxburst); 2345 src_maxburst, dst_maxburst);
2346
2347 return 0;
2311} 2348}
2312 2349
2313static int d40_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, 2350static int d40_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
@@ -2328,9 +2365,8 @@ static int d40_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
2328 case DMA_RESUME: 2365 case DMA_RESUME:
2329 return d40_resume(d40c); 2366 return d40_resume(d40c);
2330 case DMA_SLAVE_CONFIG: 2367 case DMA_SLAVE_CONFIG:
2331 d40_set_runtime_config(chan, 2368 return d40_set_runtime_config(chan,
2332 (struct dma_slave_config *) arg); 2369 (struct dma_slave_config *) arg);
2333 return 0;
2334 default: 2370 default:
2335 break; 2371 break;
2336 } 2372 }