Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

dmaengine: ti-dma-crossbar: Add support for crossbar on AM33xx/AM43xx

The DMA event crossbar on AM33xx/AM43xx is different from the one found in
DRA7x family.
Instead of a single event crossbar it has 64 identical mux attached to each
eDMA event line. When the 0 event mux is selected, the default mapped event
is going to be routed to the corresponding eDMA event line. If different
mux is selected, then the selected event is going to be routed to the given
eDMA event.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>

authored by

Peter Ujfalusi and committed by
Vinod Koul
42dbdcc6 966a87b5

+234 -32
+13 -2
Documentation/devicetree/bindings/dma/ti-dma-crossbar.txt
··· 2 2 3 3 Required properties: 4 4 - compatible: "ti,dra7-dma-crossbar" for DRA7xx DMA crossbar 5 + "ti,am335x-edma-crossbar" for AM335x and AM437x 5 6 - reg: Memory map for accessing module 6 - - #dma-cells: Should be set to <1>. 7 - Clients should use the crossbar request number (input) 7 + - #dma-cells: Should be set to to match with the DMA controller's dma-cells 8 + for ti,dra7-dma-crossbar and <3> for ti,am335x-edma-crossbar. 8 9 - dma-requests: Number of DMA requests the crossbar can receive 9 10 - dma-masters: phandle pointing to the DMA controller 10 11 ··· 14 13 15 14 Optional properties: 16 15 - ti,dma-safe-map: Safe routing value for unused request lines 16 + 17 + Notes: 18 + When requesting channel via ti,dra7-dma-crossbar, the DMA clinet must request 19 + the DMA event number as crossbar ID (input to the DMA crossbar). 20 + 21 + For ti,am335x-edma-crossbar: the meaning of parameters of dmas for clients: 22 + dmas = <&edma_xbar 12 0 1>; where <12> is the DMA request number, <0> is the TC 23 + the event should be assigned and <1> is the mux selection for in the crossbar. 24 + When mux 0 is used the DMA channel can be requested directly from edma node. 17 25 18 26 Example: 19 27 ··· 57 47 ti,hwmods = "uart1"; 58 48 clock-frequency = <48000000>; 59 49 status = "disabled"; 50 + /* Requesting crossbar input 49 and 50 */ 60 51 dmas = <&sdma_xbar 49>, <&sdma_xbar 50>; 61 52 dma-names = "tx", "rx"; 62 53 };
+221 -30
drivers/dma/ti-dma-crossbar.c
··· 17 17 #include <linux/of_device.h> 18 18 #include <linux/of_dma.h> 19 19 20 - #define TI_XBAR_OUTPUTS 127 21 - #define TI_XBAR_INPUTS 256 20 + #define TI_XBAR_DRA7 0 21 + #define TI_XBAR_AM335X 1 22 + 23 + static const struct of_device_id ti_dma_xbar_match[] = { 24 + { 25 + .compatible = "ti,dra7-dma-crossbar", 26 + .data = (void *)TI_XBAR_DRA7, 27 + }, 28 + { 29 + .compatible = "ti,am335x-edma-crossbar", 30 + .data = (void *)TI_XBAR_AM335X, 31 + }, 32 + {}, 33 + }; 34 + 35 + /* Crossbar on AM335x/AM437x family */ 36 + #define TI_AM335X_XBAR_LINES 64 37 + 38 + struct ti_am335x_xbar_data { 39 + void __iomem *iomem; 40 + 41 + struct dma_router dmarouter; 42 + 43 + u32 xbar_events; /* maximum number of events to select in xbar */ 44 + u32 dma_requests; /* number of DMA requests on eDMA */ 45 + }; 46 + 47 + struct ti_am335x_xbar_map { 48 + u16 dma_line; 49 + u16 mux_val; 50 + }; 51 + 52 + static inline void ti_am335x_xbar_write(void __iomem *iomem, int event, u16 val) 53 + { 54 + writeb_relaxed(val & 0x1f, iomem + event); 55 + } 56 + 57 + static void ti_am335x_xbar_free(struct device *dev, void *route_data) 58 + { 59 + struct ti_am335x_xbar_data *xbar = dev_get_drvdata(dev); 60 + struct ti_am335x_xbar_map *map = route_data; 61 + 62 + dev_dbg(dev, "Unmapping XBAR event %u on channel %u\n", 63 + map->mux_val, map->dma_line); 64 + 65 + ti_am335x_xbar_write(xbar->iomem, map->dma_line, 0); 66 + kfree(map); 67 + } 68 + 69 + static void *ti_am335x_xbar_route_allocate(struct of_phandle_args *dma_spec, 70 + struct of_dma *ofdma) 71 + { 72 + struct platform_device *pdev = of_find_device_by_node(ofdma->of_node); 73 + struct ti_am335x_xbar_data *xbar = platform_get_drvdata(pdev); 74 + struct ti_am335x_xbar_map *map; 75 + 76 + if (dma_spec->args_count != 3) 77 + return ERR_PTR(-EINVAL); 78 + 79 + if (dma_spec->args[2] >= xbar->xbar_events) { 80 + dev_err(&pdev->dev, "Invalid XBAR event number: %d\n", 81 + dma_spec->args[2]); 82 + return ERR_PTR(-EINVAL); 83 + } 84 + 85 + if (dma_spec->args[0] >= xbar->dma_requests) { 86 + dev_err(&pdev->dev, "Invalid DMA request line number: %d\n", 87 + dma_spec->args[0]); 88 + return ERR_PTR(-EINVAL); 89 + } 90 + 91 + /* The of_node_put() will be done in the core for the node */ 92 + dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", 0); 93 + if (!dma_spec->np) { 94 + dev_err(&pdev->dev, "Can't get DMA master\n"); 95 + return ERR_PTR(-EINVAL); 96 + } 97 + 98 + map = kzalloc(sizeof(*map), GFP_KERNEL); 99 + if (!map) { 100 + of_node_put(dma_spec->np); 101 + return ERR_PTR(-ENOMEM); 102 + } 103 + 104 + map->dma_line = (u16)dma_spec->args[0]; 105 + map->mux_val = (u16)dma_spec->args[2]; 106 + 107 + dma_spec->args[2] = 0; 108 + dma_spec->args_count = 2; 109 + 110 + dev_dbg(&pdev->dev, "Mapping XBAR event%u to DMA%u\n", 111 + map->mux_val, map->dma_line); 112 + 113 + ti_am335x_xbar_write(xbar->iomem, map->dma_line, map->mux_val); 114 + 115 + return map; 116 + } 117 + 118 + static const struct of_device_id ti_am335x_master_match[] = { 119 + { .compatible = "ti,edma3-tpcc", }, 120 + {}, 121 + }; 122 + 123 + static int ti_am335x_xbar_probe(struct platform_device *pdev) 124 + { 125 + struct device_node *node = pdev->dev.of_node; 126 + const struct of_device_id *match; 127 + struct device_node *dma_node; 128 + struct ti_am335x_xbar_data *xbar; 129 + struct resource *res; 130 + void __iomem *iomem; 131 + int i, ret; 132 + 133 + if (!node) 134 + return -ENODEV; 135 + 136 + xbar = devm_kzalloc(&pdev->dev, sizeof(*xbar), GFP_KERNEL); 137 + if (!xbar) 138 + return -ENOMEM; 139 + 140 + dma_node = of_parse_phandle(node, "dma-masters", 0); 141 + if (!dma_node) { 142 + dev_err(&pdev->dev, "Can't get DMA master node\n"); 143 + return -ENODEV; 144 + } 145 + 146 + match = of_match_node(ti_am335x_master_match, dma_node); 147 + if (!match) { 148 + dev_err(&pdev->dev, "DMA master is not supported\n"); 149 + return -EINVAL; 150 + } 151 + 152 + if (of_property_read_u32(dma_node, "dma-requests", 153 + &xbar->dma_requests)) { 154 + dev_info(&pdev->dev, 155 + "Missing XBAR output information, using %u.\n", 156 + TI_AM335X_XBAR_LINES); 157 + xbar->dma_requests = TI_AM335X_XBAR_LINES; 158 + } 159 + of_node_put(dma_node); 160 + 161 + if (of_property_read_u32(node, "dma-requests", &xbar->xbar_events)) { 162 + dev_info(&pdev->dev, 163 + "Missing XBAR input information, using %u.\n", 164 + TI_AM335X_XBAR_LINES); 165 + xbar->xbar_events = TI_AM335X_XBAR_LINES; 166 + } 167 + 168 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 169 + iomem = devm_ioremap_resource(&pdev->dev, res); 170 + if (IS_ERR(iomem)) 171 + return PTR_ERR(iomem); 172 + 173 + xbar->iomem = iomem; 174 + 175 + xbar->dmarouter.dev = &pdev->dev; 176 + xbar->dmarouter.route_free = ti_am335x_xbar_free; 177 + 178 + platform_set_drvdata(pdev, xbar); 179 + 180 + /* Reset the crossbar */ 181 + for (i = 0; i < xbar->dma_requests; i++) 182 + ti_am335x_xbar_write(xbar->iomem, i, 0); 183 + 184 + ret = of_dma_router_register(node, ti_am335x_xbar_route_allocate, 185 + &xbar->dmarouter); 186 + 187 + return ret; 188 + } 189 + 190 + /* Crossbar on DRA7xx family */ 191 + #define TI_DRA7_XBAR_OUTPUTS 127 192 + #define TI_DRA7_XBAR_INPUTS 256 22 193 23 194 #define TI_XBAR_EDMA_OFFSET 0 24 195 #define TI_XBAR_SDMA_OFFSET 1 25 196 26 - struct ti_dma_xbar_data { 197 + struct ti_dra7_xbar_data { 27 198 void __iomem *iomem; 28 199 29 200 struct dma_router dmarouter; ··· 206 35 u32 dma_offset; 207 36 }; 208 37 209 - struct ti_dma_xbar_map { 38 + struct ti_dra7_xbar_map { 210 39 u16 xbar_in; 211 40 int xbar_out; 212 41 }; 213 42 214 - static inline void ti_dma_xbar_write(void __iomem *iomem, int xbar, u16 val) 43 + static inline void ti_dra7_xbar_write(void __iomem *iomem, int xbar, u16 val) 215 44 { 216 45 writew_relaxed(val, iomem + (xbar * 2)); 217 46 } 218 47 219 - static void ti_dma_xbar_free(struct device *dev, void *route_data) 48 + static void ti_dra7_xbar_free(struct device *dev, void *route_data) 220 49 { 221 - struct ti_dma_xbar_data *xbar = dev_get_drvdata(dev); 222 - struct ti_dma_xbar_map *map = route_data; 50 + struct ti_dra7_xbar_data *xbar = dev_get_drvdata(dev); 51 + struct ti_dra7_xbar_map *map = route_data; 223 52 224 53 dev_dbg(dev, "Unmapping XBAR%u (was routed to %d)\n", 225 54 map->xbar_in, map->xbar_out); 226 55 227 - ti_dma_xbar_write(xbar->iomem, map->xbar_out, xbar->safe_val); 56 + ti_dra7_xbar_write(xbar->iomem, map->xbar_out, xbar->safe_val); 228 57 idr_remove(&xbar->map_idr, map->xbar_out); 229 58 kfree(map); 230 59 } 231 60 232 - static void *ti_dma_xbar_route_allocate(struct of_phandle_args *dma_spec, 233 - struct of_dma *ofdma) 61 + static void *ti_dra7_xbar_route_allocate(struct of_phandle_args *dma_spec, 62 + struct of_dma *ofdma) 234 63 { 235 64 struct platform_device *pdev = of_find_device_by_node(ofdma->of_node); 236 - struct ti_dma_xbar_data *xbar = platform_get_drvdata(pdev); 237 - struct ti_dma_xbar_map *map; 65 + struct ti_dra7_xbar_data *xbar = platform_get_drvdata(pdev); 66 + struct ti_dra7_xbar_map *map; 238 67 239 68 if (dma_spec->args[0] >= xbar->xbar_requests) { 240 69 dev_err(&pdev->dev, "Invalid XBAR request number: %d\n", ··· 264 93 dev_dbg(&pdev->dev, "Mapping XBAR%u to DMA%d\n", 265 94 map->xbar_in, map->xbar_out); 266 95 267 - ti_dma_xbar_write(xbar->iomem, map->xbar_out, map->xbar_in); 96 + ti_dra7_xbar_write(xbar->iomem, map->xbar_out, map->xbar_in); 268 97 269 98 return map; 270 99 } 271 100 272 - static const struct of_device_id ti_dma_master_match[] = { 101 + static const struct of_device_id ti_dra7_master_match[] = { 273 102 { 274 103 .compatible = "ti,omap4430-sdma", 275 104 .data = (void *)TI_XBAR_SDMA_OFFSET, ··· 281 110 {}, 282 111 }; 283 112 284 - static int ti_dma_xbar_probe(struct platform_device *pdev) 113 + static int ti_dra7_xbar_probe(struct platform_device *pdev) 285 114 { 286 115 struct device_node *node = pdev->dev.of_node; 287 116 const struct of_device_id *match; 288 117 struct device_node *dma_node; 289 - struct ti_dma_xbar_data *xbar; 118 + struct ti_dra7_xbar_data *xbar; 290 119 struct resource *res; 291 120 u32 safe_val; 292 121 void __iomem *iomem; ··· 307 136 return -ENODEV; 308 137 } 309 138 310 - match = of_match_node(ti_dma_master_match, dma_node); 139 + match = of_match_node(ti_dra7_master_match, dma_node); 311 140 if (!match) { 312 141 dev_err(&pdev->dev, "DMA master is not supported\n"); 313 142 return -EINVAL; ··· 317 146 &xbar->dma_requests)) { 318 147 dev_info(&pdev->dev, 319 148 "Missing XBAR output information, using %u.\n", 320 - TI_XBAR_OUTPUTS); 321 - xbar->dma_requests = TI_XBAR_OUTPUTS; 149 + TI_DRA7_XBAR_OUTPUTS); 150 + xbar->dma_requests = TI_DRA7_XBAR_OUTPUTS; 322 151 } 323 152 of_node_put(dma_node); 324 153 325 154 if (of_property_read_u32(node, "dma-requests", &xbar->xbar_requests)) { 326 155 dev_info(&pdev->dev, 327 156 "Missing XBAR input information, using %u.\n", 328 - TI_XBAR_INPUTS); 329 - xbar->xbar_requests = TI_XBAR_INPUTS; 157 + TI_DRA7_XBAR_INPUTS); 158 + xbar->xbar_requests = TI_DRA7_XBAR_INPUTS; 330 159 } 331 160 332 161 if (!of_property_read_u32(node, "ti,dma-safe-map", &safe_val)) ··· 340 169 xbar->iomem = iomem; 341 170 342 171 xbar->dmarouter.dev = &pdev->dev; 343 - xbar->dmarouter.route_free = ti_dma_xbar_free; 172 + xbar->dmarouter.route_free = ti_dra7_xbar_free; 344 173 xbar->dma_offset = (u32)match->data; 345 174 346 175 platform_set_drvdata(pdev, xbar); 347 176 348 177 /* Reset the crossbar */ 349 178 for (i = 0; i < xbar->dma_requests; i++) 350 - ti_dma_xbar_write(xbar->iomem, i, xbar->safe_val); 179 + ti_dra7_xbar_write(xbar->iomem, i, xbar->safe_val); 351 180 352 - ret = of_dma_router_register(node, ti_dma_xbar_route_allocate, 181 + ret = of_dma_router_register(node, ti_dra7_xbar_route_allocate, 353 182 &xbar->dmarouter); 354 183 if (ret) { 355 184 /* Restore the defaults for the crossbar */ 356 185 for (i = 0; i < xbar->dma_requests; i++) 357 - ti_dma_xbar_write(xbar->iomem, i, i); 186 + ti_dra7_xbar_write(xbar->iomem, i, i); 358 187 } 359 188 360 189 return ret; 361 190 } 362 191 363 - static const struct of_device_id ti_dma_xbar_match[] = { 364 - { .compatible = "ti,dra7-dma-crossbar" }, 365 - {}, 366 - }; 192 + static int ti_dma_xbar_probe(struct platform_device *pdev) 193 + { 194 + const struct of_device_id *match; 195 + int ret; 196 + 197 + match = of_match_node(ti_dma_xbar_match, pdev->dev.of_node); 198 + if (unlikely(!match)) 199 + return -EINVAL; 200 + 201 + switch ((u32)match->data) { 202 + case TI_XBAR_DRA7: 203 + ret = ti_dra7_xbar_probe(pdev); 204 + break; 205 + case TI_XBAR_AM335X: 206 + ret = ti_am335x_xbar_probe(pdev); 207 + break; 208 + default: 209 + dev_err(&pdev->dev, "Unsupported crossbar\n"); 210 + ret = -ENODEV; 211 + break; 212 + } 213 + 214 + return ret; 215 + } 367 216 368 217 static struct platform_driver ti_dma_xbar_driver = { 369 218 .driver = {