diff options
-rw-r--r-- | drivers/dma/ste_dma40.c | 168 |
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 | ||
2182 | static int | ||
2183 | dma40_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 */ |
2183 | static void d40_set_runtime_config(struct dma_chan *chan, | 2240 | static 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 | ||
2313 | static int d40_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, | 2350 | static 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 | } |