diff options
author | Linus Walleij <linus.walleij@linaro.org> | 2016-04-04 16:44:59 -0400 |
---|---|---|
committer | Vinod Koul <vinod.koul@intel.com> | 2016-04-05 19:53:41 -0400 |
commit | f9cd476123ced488e628339becedb2cf3243a58a (patch) | |
tree | 7b017a4a63b94bcb7e032b75e5fd432dcd0c694d /drivers/dma | |
parent | f55532a0c0b8bb6148f4e07853b876ef73bc69ca (diff) |
dmaengine: pl08x: allocate OF slave channel data at probe time
The current OF translation of channels can never work with
any DMA client using the DMA channels directly: the only way
to get the channels initialized properly is in the
dma_async_device_register() call, where chan->dev etc is
allocated and initialized.
Allocate and initialize all possible DMA channels and
only augment a target channel with the periph_buses at
of_xlate(). Remove some const settings to make things work.
Cc: Maxime Ripard <maxime.ripard@free-electrons.com>
Tested-by: Joachim Eastwood <manabian@gmail.com>
Tested-by: Johannes Stezenbach <js@sig21.net>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Diffstat (limited to 'drivers/dma')
-rw-r--r-- | drivers/dma/amba-pl08x.c | 86 |
1 files changed, 58 insertions, 28 deletions
diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 9b42c0588550..81db1c4811ce 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c | |||
@@ -107,16 +107,20 @@ struct pl08x_driver_data; | |||
107 | /** | 107 | /** |
108 | * struct vendor_data - vendor-specific config parameters for PL08x derivatives | 108 | * struct vendor_data - vendor-specific config parameters for PL08x derivatives |
109 | * @channels: the number of channels available in this variant | 109 | * @channels: the number of channels available in this variant |
110 | * @signals: the number of request signals available from the hardware | ||
110 | * @dualmaster: whether this version supports dual AHB masters or not. | 111 | * @dualmaster: whether this version supports dual AHB masters or not. |
111 | * @nomadik: whether the channels have Nomadik security extension bits | 112 | * @nomadik: whether the channels have Nomadik security extension bits |
112 | * that need to be checked for permission before use and some registers are | 113 | * that need to be checked for permission before use and some registers are |
113 | * missing | 114 | * missing |
114 | * @pl080s: whether this version is a PL080S, which has separate register and | 115 | * @pl080s: whether this version is a PL080S, which has separate register and |
115 | * LLI word for transfer size. | 116 | * LLI word for transfer size. |
117 | * @max_transfer_size: the maximum single element transfer size for this | ||
118 | * PL08x variant. | ||
116 | */ | 119 | */ |
117 | struct vendor_data { | 120 | struct vendor_data { |
118 | u8 config_offset; | 121 | u8 config_offset; |
119 | u8 channels; | 122 | u8 channels; |
123 | u8 signals; | ||
120 | bool dualmaster; | 124 | bool dualmaster; |
121 | bool nomadik; | 125 | bool nomadik; |
122 | bool pl080s; | 126 | bool pl080s; |
@@ -235,7 +239,7 @@ struct pl08x_dma_chan { | |||
235 | struct virt_dma_chan vc; | 239 | struct virt_dma_chan vc; |
236 | struct pl08x_phy_chan *phychan; | 240 | struct pl08x_phy_chan *phychan; |
237 | const char *name; | 241 | const char *name; |
238 | const struct pl08x_channel_data *cd; | 242 | struct pl08x_channel_data *cd; |
239 | struct dma_slave_config cfg; | 243 | struct dma_slave_config cfg; |
240 | struct pl08x_txd *at; | 244 | struct pl08x_txd *at; |
241 | struct pl08x_driver_data *host; | 245 | struct pl08x_driver_data *host; |
@@ -1909,6 +1913,12 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x, | |||
1909 | 1913 | ||
1910 | if (slave) { | 1914 | if (slave) { |
1911 | chan->cd = &pl08x->pd->slave_channels[i]; | 1915 | chan->cd = &pl08x->pd->slave_channels[i]; |
1916 | /* | ||
1917 | * Some implementations have muxed signals, whereas some | ||
1918 | * use a mux in front of the signals and need dynamic | ||
1919 | * assignment of signals. | ||
1920 | */ | ||
1921 | chan->signal = i; | ||
1912 | pl08x_dma_slave_init(chan); | 1922 | pl08x_dma_slave_init(chan); |
1913 | } else { | 1923 | } else { |
1914 | chan->cd = &pl08x->pd->memcpy_channel; | 1924 | chan->cd = &pl08x->pd->memcpy_channel; |
@@ -2050,40 +2060,33 @@ static struct dma_chan *pl08x_of_xlate(struct of_phandle_args *dma_spec, | |||
2050 | struct of_dma *ofdma) | 2060 | struct of_dma *ofdma) |
2051 | { | 2061 | { |
2052 | struct pl08x_driver_data *pl08x = ofdma->of_dma_data; | 2062 | struct pl08x_driver_data *pl08x = ofdma->of_dma_data; |
2053 | struct pl08x_channel_data *data; | ||
2054 | struct pl08x_dma_chan *chan; | ||
2055 | struct dma_chan *dma_chan; | 2063 | struct dma_chan *dma_chan; |
2064 | struct pl08x_dma_chan *plchan; | ||
2056 | 2065 | ||
2057 | if (!pl08x) | 2066 | if (!pl08x) |
2058 | return NULL; | 2067 | return NULL; |
2059 | 2068 | ||
2060 | if (dma_spec->args_count != 2) | 2069 | if (dma_spec->args_count != 2) { |
2070 | dev_err(&pl08x->adev->dev, | ||
2071 | "DMA channel translation requires two cells\n"); | ||
2061 | return NULL; | 2072 | return NULL; |
2073 | } | ||
2062 | 2074 | ||
2063 | dma_chan = pl08x_find_chan_id(pl08x, dma_spec->args[0]); | 2075 | dma_chan = pl08x_find_chan_id(pl08x, dma_spec->args[0]); |
2064 | if (dma_chan) | 2076 | if (!dma_chan) { |
2065 | return dma_get_slave_channel(dma_chan); | 2077 | dev_err(&pl08x->adev->dev, |
2066 | 2078 | "DMA slave channel not found\n"); | |
2067 | chan = devm_kzalloc(pl08x->slave.dev, sizeof(*chan) + sizeof(*data), | ||
2068 | GFP_KERNEL); | ||
2069 | if (!chan) | ||
2070 | return NULL; | 2079 | return NULL; |
2080 | } | ||
2071 | 2081 | ||
2072 | data = (void *)&chan[1]; | 2082 | plchan = to_pl08x_chan(dma_chan); |
2073 | data->bus_id = "(none)"; | 2083 | dev_dbg(&pl08x->adev->dev, |
2074 | data->periph_buses = dma_spec->args[1]; | 2084 | "translated channel for signal %d\n", |
2075 | 2085 | dma_spec->args[0]); | |
2076 | chan->cd = data; | ||
2077 | chan->host = pl08x; | ||
2078 | chan->slave = true; | ||
2079 | chan->name = data->bus_id; | ||
2080 | chan->state = PL08X_CHAN_IDLE; | ||
2081 | chan->signal = dma_spec->args[0]; | ||
2082 | chan->vc.desc_free = pl08x_desc_free; | ||
2083 | |||
2084 | vchan_init(&chan->vc, &pl08x->slave); | ||
2085 | 2086 | ||
2086 | return dma_get_slave_channel(&chan->vc.chan); | 2087 | /* Augment channel data for applicable AHB buses */ |
2088 | plchan->cd->periph_buses = dma_spec->args[1]; | ||
2089 | return dma_get_slave_channel(dma_chan); | ||
2087 | } | 2090 | } |
2088 | 2091 | ||
2089 | static int pl08x_of_probe(struct amba_device *adev, | 2092 | static int pl08x_of_probe(struct amba_device *adev, |
@@ -2091,9 +2094,11 @@ static int pl08x_of_probe(struct amba_device *adev, | |||
2091 | struct device_node *np) | 2094 | struct device_node *np) |
2092 | { | 2095 | { |
2093 | struct pl08x_platform_data *pd; | 2096 | struct pl08x_platform_data *pd; |
2097 | struct pl08x_channel_data *chanp = NULL; | ||
2094 | u32 cctl_memcpy = 0; | 2098 | u32 cctl_memcpy = 0; |
2095 | u32 val; | 2099 | u32 val; |
2096 | int ret; | 2100 | int ret; |
2101 | int i; | ||
2097 | 2102 | ||
2098 | pd = devm_kzalloc(&adev->dev, sizeof(*pd), GFP_KERNEL); | 2103 | pd = devm_kzalloc(&adev->dev, sizeof(*pd), GFP_KERNEL); |
2099 | if (!pd) | 2104 | if (!pd) |
@@ -2195,6 +2200,27 @@ static int pl08x_of_probe(struct amba_device *adev, | |||
2195 | /* Use the buses that can access memory, obviously */ | 2200 | /* Use the buses that can access memory, obviously */ |
2196 | pd->memcpy_channel.periph_buses = pd->mem_buses; | 2201 | pd->memcpy_channel.periph_buses = pd->mem_buses; |
2197 | 2202 | ||
2203 | /* | ||
2204 | * Allocate channel data for all possible slave channels (one | ||
2205 | * for each possible signal), channels will then be allocated | ||
2206 | * for a device and have it's AHB interfaces set up at | ||
2207 | * translation time. | ||
2208 | */ | ||
2209 | chanp = devm_kcalloc(&adev->dev, | ||
2210 | pl08x->vd->signals, | ||
2211 | sizeof(struct pl08x_channel_data), | ||
2212 | GFP_KERNEL); | ||
2213 | if (!chanp) | ||
2214 | return -ENOMEM; | ||
2215 | |||
2216 | pd->slave_channels = chanp; | ||
2217 | for (i = 0; i < pl08x->vd->signals; i++) { | ||
2218 | /* chanp->periph_buses will be assigned at translation */ | ||
2219 | chanp->bus_id = kasprintf(GFP_KERNEL, "slave%d", i); | ||
2220 | chanp++; | ||
2221 | } | ||
2222 | pd->num_slave_channels = pl08x->vd->signals; | ||
2223 | |||
2198 | pl08x->pd = pd; | 2224 | pl08x->pd = pd; |
2199 | 2225 | ||
2200 | return of_dma_controller_register(adev->dev.of_node, pl08x_of_xlate, | 2226 | return of_dma_controller_register(adev->dev.of_node, pl08x_of_xlate, |
@@ -2234,6 +2260,10 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id) | |||
2234 | goto out_no_pl08x; | 2260 | goto out_no_pl08x; |
2235 | } | 2261 | } |
2236 | 2262 | ||
2263 | /* Assign useful pointers to the driver state */ | ||
2264 | pl08x->adev = adev; | ||
2265 | pl08x->vd = vd; | ||
2266 | |||
2237 | /* Initialize memcpy engine */ | 2267 | /* Initialize memcpy engine */ |
2238 | dma_cap_set(DMA_MEMCPY, pl08x->memcpy.cap_mask); | 2268 | dma_cap_set(DMA_MEMCPY, pl08x->memcpy.cap_mask); |
2239 | pl08x->memcpy.dev = &adev->dev; | 2269 | pl08x->memcpy.dev = &adev->dev; |
@@ -2284,10 +2314,6 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id) | |||
2284 | } | 2314 | } |
2285 | } | 2315 | } |
2286 | 2316 | ||
2287 | /* Assign useful pointers to the driver state */ | ||
2288 | pl08x->adev = adev; | ||
2289 | pl08x->vd = vd; | ||
2290 | |||
2291 | /* By default, AHB1 only. If dualmaster, from platform */ | 2317 | /* By default, AHB1 only. If dualmaster, from platform */ |
2292 | pl08x->lli_buses = PL08X_AHB1; | 2318 | pl08x->lli_buses = PL08X_AHB1; |
2293 | pl08x->mem_buses = PL08X_AHB1; | 2319 | pl08x->mem_buses = PL08X_AHB1; |
@@ -2438,6 +2464,7 @@ out_no_pl08x: | |||
2438 | static struct vendor_data vendor_pl080 = { | 2464 | static struct vendor_data vendor_pl080 = { |
2439 | .config_offset = PL080_CH_CONFIG, | 2465 | .config_offset = PL080_CH_CONFIG, |
2440 | .channels = 8, | 2466 | .channels = 8, |
2467 | .signals = 16, | ||
2441 | .dualmaster = true, | 2468 | .dualmaster = true, |
2442 | .max_transfer_size = PL080_CONTROL_TRANSFER_SIZE_MASK, | 2469 | .max_transfer_size = PL080_CONTROL_TRANSFER_SIZE_MASK, |
2443 | }; | 2470 | }; |
@@ -2445,6 +2472,7 @@ static struct vendor_data vendor_pl080 = { | |||
2445 | static struct vendor_data vendor_nomadik = { | 2472 | static struct vendor_data vendor_nomadik = { |
2446 | .config_offset = PL080_CH_CONFIG, | 2473 | .config_offset = PL080_CH_CONFIG, |
2447 | .channels = 8, | 2474 | .channels = 8, |
2475 | .signals = 32, | ||
2448 | .dualmaster = true, | 2476 | .dualmaster = true, |
2449 | .nomadik = true, | 2477 | .nomadik = true, |
2450 | .max_transfer_size = PL080_CONTROL_TRANSFER_SIZE_MASK, | 2478 | .max_transfer_size = PL080_CONTROL_TRANSFER_SIZE_MASK, |
@@ -2453,6 +2481,7 @@ static struct vendor_data vendor_nomadik = { | |||
2453 | static struct vendor_data vendor_pl080s = { | 2481 | static struct vendor_data vendor_pl080s = { |
2454 | .config_offset = PL080S_CH_CONFIG, | 2482 | .config_offset = PL080S_CH_CONFIG, |
2455 | .channels = 8, | 2483 | .channels = 8, |
2484 | .signals = 32, | ||
2456 | .pl080s = true, | 2485 | .pl080s = true, |
2457 | .max_transfer_size = PL080S_CONTROL_TRANSFER_SIZE_MASK, | 2486 | .max_transfer_size = PL080S_CONTROL_TRANSFER_SIZE_MASK, |
2458 | }; | 2487 | }; |
@@ -2460,6 +2489,7 @@ static struct vendor_data vendor_pl080s = { | |||
2460 | static struct vendor_data vendor_pl081 = { | 2489 | static struct vendor_data vendor_pl081 = { |
2461 | .config_offset = PL080_CH_CONFIG, | 2490 | .config_offset = PL080_CH_CONFIG, |
2462 | .channels = 2, | 2491 | .channels = 2, |
2492 | .signals = 16, | ||
2463 | .dualmaster = false, | 2493 | .dualmaster = false, |
2464 | .max_transfer_size = PL080_CONTROL_TRANSFER_SIZE_MASK, | 2494 | .max_transfer_size = PL080_CONTROL_TRANSFER_SIZE_MASK, |
2465 | }; | 2495 | }; |