aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/dma/ste_dma40.c
diff options
context:
space:
mode:
authorRabin Vincent <rabin.vincent@stericsson.com>2011-06-27 05:33:38 -0400
committerVinod Koul <vinod.koul@intel.com>2011-07-13 18:39:10 -0400
commit98ca528916c47ad17f78a07b45e49de3940fba77 (patch)
tree259527144337e2203c4f390c34e557bf2e425846 /drivers/dma/ste_dma40.c
parentf4b89764c470230bbf9d18c0a3411887c48bb5a2 (diff)
dmaengine/ste_dma40: allow memory buswidth/burst to be configured
Currently the runtime config implementation forces the memory side parameters to be the same as the peripheral side. Allow these to be different, and check for misconfiguration. Signed-off-by: Rabin Vincent <rabin.vincent@stericsson.com> Reviewed-by: Ulf HANSSON <ulf.hansson@stericsson.com> Tested-by: Stefan Nilsson <stefan.xk.nilsson@stericsson.com> Reviewed-by: Per Forlin <per.forlin@stericsson.com> Reviewed-by: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com> Cc: Robert Marklund <robert.marklund@stericsson.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Diffstat (limited to 'drivers/dma/ste_dma40.c')
-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 }