diff options
| author | Linus Walleij <linus.walleij@stericsson.com> | 2010-08-04 07:37:45 -0400 |
|---|---|---|
| committer | Dan Williams <dan.j.williams@intel.com> | 2010-08-04 17:14:05 -0400 |
| commit | 95e1400fa1317e566b316ff4af947bd5341332c8 (patch) | |
| tree | a2bdcd9729209f75eca11bc5b49b1b681a66c150 | |
| parent | c156d0a5b0c667999e06d0bb52e3d1376faec8bf (diff) | |
DMAENGINE: add runtime slave config to DMA40 v3
This extends the DMA engine driver for the DMA40 used in the
U8500 platform with the generic runtime slave configuration
interface.
Signed-off-by: Linus Walleij <linus.walleij@stericsson.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
| -rw-r--r-- | drivers/dma/ste_dma40.c | 141 |
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 */ | ||
| 2090 | static 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 | |||
| 2073 | static int d40_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, | 2200 | static 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 */ |
