diff options
Diffstat (limited to 'drivers/dma/amba-pl08x.c')
-rw-r--r-- | drivers/dma/amba-pl08x.c | 192 |
1 files changed, 189 insertions, 3 deletions
diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 5de3cf453f35..9b42c0588550 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c | |||
@@ -83,6 +83,8 @@ | |||
83 | #include <linux/init.h> | 83 | #include <linux/init.h> |
84 | #include <linux/interrupt.h> | 84 | #include <linux/interrupt.h> |
85 | #include <linux/module.h> | 85 | #include <linux/module.h> |
86 | #include <linux/of.h> | ||
87 | #include <linux/of_dma.h> | ||
86 | #include <linux/pm_runtime.h> | 88 | #include <linux/pm_runtime.h> |
87 | #include <linux/seq_file.h> | 89 | #include <linux/seq_file.h> |
88 | #include <linux/slab.h> | 90 | #include <linux/slab.h> |
@@ -2030,10 +2032,188 @@ static inline void init_pl08x_debugfs(struct pl08x_driver_data *pl08x) | |||
2030 | } | 2032 | } |
2031 | #endif | 2033 | #endif |
2032 | 2034 | ||
2035 | #ifdef CONFIG_OF | ||
2036 | static struct dma_chan *pl08x_find_chan_id(struct pl08x_driver_data *pl08x, | ||
2037 | u32 id) | ||
2038 | { | ||
2039 | struct pl08x_dma_chan *chan; | ||
2040 | |||
2041 | list_for_each_entry(chan, &pl08x->slave.channels, vc.chan.device_node) { | ||
2042 | if (chan->signal == id) | ||
2043 | return &chan->vc.chan; | ||
2044 | } | ||
2045 | |||
2046 | return NULL; | ||
2047 | } | ||
2048 | |||
2049 | static struct dma_chan *pl08x_of_xlate(struct of_phandle_args *dma_spec, | ||
2050 | struct of_dma *ofdma) | ||
2051 | { | ||
2052 | 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; | ||
2056 | |||
2057 | if (!pl08x) | ||
2058 | return NULL; | ||
2059 | |||
2060 | if (dma_spec->args_count != 2) | ||
2061 | return NULL; | ||
2062 | |||
2063 | dma_chan = pl08x_find_chan_id(pl08x, dma_spec->args[0]); | ||
2064 | if (dma_chan) | ||
2065 | return dma_get_slave_channel(dma_chan); | ||
2066 | |||
2067 | chan = devm_kzalloc(pl08x->slave.dev, sizeof(*chan) + sizeof(*data), | ||
2068 | GFP_KERNEL); | ||
2069 | if (!chan) | ||
2070 | return NULL; | ||
2071 | |||
2072 | data = (void *)&chan[1]; | ||
2073 | data->bus_id = "(none)"; | ||
2074 | data->periph_buses = dma_spec->args[1]; | ||
2075 | |||
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 | return dma_get_slave_channel(&chan->vc.chan); | ||
2087 | } | ||
2088 | |||
2089 | static int pl08x_of_probe(struct amba_device *adev, | ||
2090 | struct pl08x_driver_data *pl08x, | ||
2091 | struct device_node *np) | ||
2092 | { | ||
2093 | struct pl08x_platform_data *pd; | ||
2094 | u32 cctl_memcpy = 0; | ||
2095 | u32 val; | ||
2096 | int ret; | ||
2097 | |||
2098 | pd = devm_kzalloc(&adev->dev, sizeof(*pd), GFP_KERNEL); | ||
2099 | if (!pd) | ||
2100 | return -ENOMEM; | ||
2101 | |||
2102 | /* Eligible bus masters for fetching LLIs */ | ||
2103 | if (of_property_read_bool(np, "lli-bus-interface-ahb1")) | ||
2104 | pd->lli_buses |= PL08X_AHB1; | ||
2105 | if (of_property_read_bool(np, "lli-bus-interface-ahb2")) | ||
2106 | pd->lli_buses |= PL08X_AHB2; | ||
2107 | if (!pd->lli_buses) { | ||
2108 | dev_info(&adev->dev, "no bus masters for LLIs stated, assume all\n"); | ||
2109 | pd->lli_buses |= PL08X_AHB1 | PL08X_AHB2; | ||
2110 | } | ||
2111 | |||
2112 | /* Eligible bus masters for memory access */ | ||
2113 | if (of_property_read_bool(np, "mem-bus-interface-ahb1")) | ||
2114 | pd->mem_buses |= PL08X_AHB1; | ||
2115 | if (of_property_read_bool(np, "mem-bus-interface-ahb2")) | ||
2116 | pd->mem_buses |= PL08X_AHB2; | ||
2117 | if (!pd->mem_buses) { | ||
2118 | dev_info(&adev->dev, "no bus masters for memory stated, assume all\n"); | ||
2119 | pd->mem_buses |= PL08X_AHB1 | PL08X_AHB2; | ||
2120 | } | ||
2121 | |||
2122 | /* Parse the memcpy channel properties */ | ||
2123 | ret = of_property_read_u32(np, "memcpy-burst-size", &val); | ||
2124 | if (ret) { | ||
2125 | dev_info(&adev->dev, "no memcpy burst size specified, using 1 byte\n"); | ||
2126 | val = 1; | ||
2127 | } | ||
2128 | switch (val) { | ||
2129 | default: | ||
2130 | dev_err(&adev->dev, "illegal burst size for memcpy, set to 1\n"); | ||
2131 | /* Fall through */ | ||
2132 | case 1: | ||
2133 | cctl_memcpy |= PL080_BSIZE_1 << PL080_CONTROL_SB_SIZE_SHIFT | | ||
2134 | PL080_BSIZE_1 << PL080_CONTROL_DB_SIZE_SHIFT; | ||
2135 | break; | ||
2136 | case 4: | ||
2137 | cctl_memcpy |= PL080_BSIZE_4 << PL080_CONTROL_SB_SIZE_SHIFT | | ||
2138 | PL080_BSIZE_4 << PL080_CONTROL_DB_SIZE_SHIFT; | ||
2139 | break; | ||
2140 | case 8: | ||
2141 | cctl_memcpy |= PL080_BSIZE_8 << PL080_CONTROL_SB_SIZE_SHIFT | | ||
2142 | PL080_BSIZE_8 << PL080_CONTROL_DB_SIZE_SHIFT; | ||
2143 | break; | ||
2144 | case 16: | ||
2145 | cctl_memcpy |= PL080_BSIZE_16 << PL080_CONTROL_SB_SIZE_SHIFT | | ||
2146 | PL080_BSIZE_16 << PL080_CONTROL_DB_SIZE_SHIFT; | ||
2147 | break; | ||
2148 | case 32: | ||
2149 | cctl_memcpy |= PL080_BSIZE_32 << PL080_CONTROL_SB_SIZE_SHIFT | | ||
2150 | PL080_BSIZE_32 << PL080_CONTROL_DB_SIZE_SHIFT; | ||
2151 | break; | ||
2152 | case 64: | ||
2153 | cctl_memcpy |= PL080_BSIZE_64 << PL080_CONTROL_SB_SIZE_SHIFT | | ||
2154 | PL080_BSIZE_64 << PL080_CONTROL_DB_SIZE_SHIFT; | ||
2155 | break; | ||
2156 | case 128: | ||
2157 | cctl_memcpy |= PL080_BSIZE_128 << PL080_CONTROL_SB_SIZE_SHIFT | | ||
2158 | PL080_BSIZE_128 << PL080_CONTROL_DB_SIZE_SHIFT; | ||
2159 | break; | ||
2160 | case 256: | ||
2161 | cctl_memcpy |= PL080_BSIZE_256 << PL080_CONTROL_SB_SIZE_SHIFT | | ||
2162 | PL080_BSIZE_256 << PL080_CONTROL_DB_SIZE_SHIFT; | ||
2163 | break; | ||
2164 | } | ||
2165 | |||
2166 | ret = of_property_read_u32(np, "memcpy-bus-width", &val); | ||
2167 | if (ret) { | ||
2168 | dev_info(&adev->dev, "no memcpy bus width specified, using 8 bits\n"); | ||
2169 | val = 8; | ||
2170 | } | ||
2171 | switch (val) { | ||
2172 | default: | ||
2173 | dev_err(&adev->dev, "illegal bus width for memcpy, set to 8 bits\n"); | ||
2174 | /* Fall through */ | ||
2175 | case 8: | ||
2176 | cctl_memcpy |= PL080_WIDTH_8BIT << PL080_CONTROL_SWIDTH_SHIFT | | ||
2177 | PL080_WIDTH_8BIT << PL080_CONTROL_DWIDTH_SHIFT; | ||
2178 | break; | ||
2179 | case 16: | ||
2180 | cctl_memcpy |= PL080_WIDTH_16BIT << PL080_CONTROL_SWIDTH_SHIFT | | ||
2181 | PL080_WIDTH_16BIT << PL080_CONTROL_DWIDTH_SHIFT; | ||
2182 | break; | ||
2183 | case 32: | ||
2184 | cctl_memcpy |= PL080_WIDTH_32BIT << PL080_CONTROL_SWIDTH_SHIFT | | ||
2185 | PL080_WIDTH_32BIT << PL080_CONTROL_DWIDTH_SHIFT; | ||
2186 | break; | ||
2187 | } | ||
2188 | |||
2189 | /* This is currently the only thing making sense */ | ||
2190 | cctl_memcpy |= PL080_CONTROL_PROT_SYS; | ||
2191 | |||
2192 | /* Set up memcpy channel */ | ||
2193 | pd->memcpy_channel.bus_id = "memcpy"; | ||
2194 | pd->memcpy_channel.cctl_memcpy = cctl_memcpy; | ||
2195 | /* Use the buses that can access memory, obviously */ | ||
2196 | pd->memcpy_channel.periph_buses = pd->mem_buses; | ||
2197 | |||
2198 | pl08x->pd = pd; | ||
2199 | |||
2200 | return of_dma_controller_register(adev->dev.of_node, pl08x_of_xlate, | ||
2201 | pl08x); | ||
2202 | } | ||
2203 | #else | ||
2204 | static inline int pl08x_of_probe(struct amba_device *adev, | ||
2205 | struct pl08x_driver_data *pl08x, | ||
2206 | struct device_node *np) | ||
2207 | { | ||
2208 | return -EINVAL; | ||
2209 | } | ||
2210 | #endif | ||
2211 | |||
2033 | static int pl08x_probe(struct amba_device *adev, const struct amba_id *id) | 2212 | static int pl08x_probe(struct amba_device *adev, const struct amba_id *id) |
2034 | { | 2213 | { |
2035 | struct pl08x_driver_data *pl08x; | 2214 | struct pl08x_driver_data *pl08x; |
2036 | const struct vendor_data *vd = id->data; | 2215 | const struct vendor_data *vd = id->data; |
2216 | struct device_node *np = adev->dev.of_node; | ||
2037 | u32 tsfr_size; | 2217 | u32 tsfr_size; |
2038 | int ret = 0; | 2218 | int ret = 0; |
2039 | int i; | 2219 | int i; |
@@ -2093,9 +2273,15 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id) | |||
2093 | /* Get the platform data */ | 2273 | /* Get the platform data */ |
2094 | pl08x->pd = dev_get_platdata(&adev->dev); | 2274 | pl08x->pd = dev_get_platdata(&adev->dev); |
2095 | if (!pl08x->pd) { | 2275 | if (!pl08x->pd) { |
2096 | dev_err(&adev->dev, "no platform data supplied\n"); | 2276 | if (np) { |
2097 | ret = -EINVAL; | 2277 | ret = pl08x_of_probe(adev, pl08x, np); |
2098 | goto out_no_platdata; | 2278 | if (ret) |
2279 | goto out_no_platdata; | ||
2280 | } else { | ||
2281 | dev_err(&adev->dev, "no platform data supplied\n"); | ||
2282 | ret = -EINVAL; | ||
2283 | goto out_no_platdata; | ||
2284 | } | ||
2099 | } | 2285 | } |
2100 | 2286 | ||
2101 | /* Assign useful pointers to the driver state */ | 2287 | /* Assign useful pointers to the driver state */ |