0001
0002
0003
0004
0005
0006 #include <linux/slab.h>
0007 #include <linux/err.h>
0008 #include <linux/init.h>
0009 #include <linux/list.h>
0010 #include <linux/io.h>
0011 #include <linux/of_address.h>
0012 #include <linux/of_device.h>
0013 #include <linux/of_dma.h>
0014
0015 #define TI_XBAR_DRA7 0
0016 #define TI_XBAR_AM335X 1
0017 static const u32 ti_xbar_type[] = {
0018 [TI_XBAR_DRA7] = TI_XBAR_DRA7,
0019 [TI_XBAR_AM335X] = TI_XBAR_AM335X,
0020 };
0021
0022 static const struct of_device_id ti_dma_xbar_match[] = {
0023 {
0024 .compatible = "ti,dra7-dma-crossbar",
0025 .data = &ti_xbar_type[TI_XBAR_DRA7],
0026 },
0027 {
0028 .compatible = "ti,am335x-edma-crossbar",
0029 .data = &ti_xbar_type[TI_XBAR_AM335X],
0030 },
0031 {},
0032 };
0033
0034
0035 #define TI_AM335X_XBAR_LINES 64
0036
0037 struct ti_am335x_xbar_data {
0038 void __iomem *iomem;
0039
0040 struct dma_router dmarouter;
0041
0042 u32 xbar_events;
0043 u32 dma_requests;
0044 };
0045
0046 struct ti_am335x_xbar_map {
0047 u16 dma_line;
0048 u8 mux_val;
0049 };
0050
0051 static inline void ti_am335x_xbar_write(void __iomem *iomem, int event, u8 val)
0052 {
0053
0054
0055
0056
0057
0058 if (event >= 60 && event <= 63)
0059 writeb_relaxed(val, iomem + (63 - event % 4));
0060 else
0061 writeb_relaxed(val, iomem + event);
0062 }
0063
0064 static void ti_am335x_xbar_free(struct device *dev, void *route_data)
0065 {
0066 struct ti_am335x_xbar_data *xbar = dev_get_drvdata(dev);
0067 struct ti_am335x_xbar_map *map = route_data;
0068
0069 dev_dbg(dev, "Unmapping XBAR event %u on channel %u\n",
0070 map->mux_val, map->dma_line);
0071
0072 ti_am335x_xbar_write(xbar->iomem, map->dma_line, 0);
0073 kfree(map);
0074 }
0075
0076 static void *ti_am335x_xbar_route_allocate(struct of_phandle_args *dma_spec,
0077 struct of_dma *ofdma)
0078 {
0079 struct platform_device *pdev = of_find_device_by_node(ofdma->of_node);
0080 struct ti_am335x_xbar_data *xbar = platform_get_drvdata(pdev);
0081 struct ti_am335x_xbar_map *map;
0082
0083 if (dma_spec->args_count != 3)
0084 return ERR_PTR(-EINVAL);
0085
0086 if (dma_spec->args[2] >= xbar->xbar_events) {
0087 dev_err(&pdev->dev, "Invalid XBAR event number: %d\n",
0088 dma_spec->args[2]);
0089 return ERR_PTR(-EINVAL);
0090 }
0091
0092 if (dma_spec->args[0] >= xbar->dma_requests) {
0093 dev_err(&pdev->dev, "Invalid DMA request line number: %d\n",
0094 dma_spec->args[0]);
0095 return ERR_PTR(-EINVAL);
0096 }
0097
0098
0099 dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", 0);
0100 if (!dma_spec->np) {
0101 dev_err(&pdev->dev, "Can't get DMA master\n");
0102 return ERR_PTR(-EINVAL);
0103 }
0104
0105 map = kzalloc(sizeof(*map), GFP_KERNEL);
0106 if (!map) {
0107 of_node_put(dma_spec->np);
0108 return ERR_PTR(-ENOMEM);
0109 }
0110
0111 map->dma_line = (u16)dma_spec->args[0];
0112 map->mux_val = (u8)dma_spec->args[2];
0113
0114 dma_spec->args[2] = 0;
0115 dma_spec->args_count = 2;
0116
0117 dev_dbg(&pdev->dev, "Mapping XBAR event%u to DMA%u\n",
0118 map->mux_val, map->dma_line);
0119
0120 ti_am335x_xbar_write(xbar->iomem, map->dma_line, map->mux_val);
0121
0122 return map;
0123 }
0124
0125 static const struct of_device_id ti_am335x_master_match[] __maybe_unused = {
0126 { .compatible = "ti,edma3-tpcc", },
0127 {},
0128 };
0129
0130 static int ti_am335x_xbar_probe(struct platform_device *pdev)
0131 {
0132 struct device_node *node = pdev->dev.of_node;
0133 const struct of_device_id *match;
0134 struct device_node *dma_node;
0135 struct ti_am335x_xbar_data *xbar;
0136 void __iomem *iomem;
0137 int i, ret;
0138
0139 if (!node)
0140 return -ENODEV;
0141
0142 xbar = devm_kzalloc(&pdev->dev, sizeof(*xbar), GFP_KERNEL);
0143 if (!xbar)
0144 return -ENOMEM;
0145
0146 dma_node = of_parse_phandle(node, "dma-masters", 0);
0147 if (!dma_node) {
0148 dev_err(&pdev->dev, "Can't get DMA master node\n");
0149 return -ENODEV;
0150 }
0151
0152 match = of_match_node(ti_am335x_master_match, dma_node);
0153 if (!match) {
0154 dev_err(&pdev->dev, "DMA master is not supported\n");
0155 of_node_put(dma_node);
0156 return -EINVAL;
0157 }
0158
0159 if (of_property_read_u32(dma_node, "dma-requests",
0160 &xbar->dma_requests)) {
0161 dev_info(&pdev->dev,
0162 "Missing XBAR output information, using %u.\n",
0163 TI_AM335X_XBAR_LINES);
0164 xbar->dma_requests = TI_AM335X_XBAR_LINES;
0165 }
0166 of_node_put(dma_node);
0167
0168 if (of_property_read_u32(node, "dma-requests", &xbar->xbar_events)) {
0169 dev_info(&pdev->dev,
0170 "Missing XBAR input information, using %u.\n",
0171 TI_AM335X_XBAR_LINES);
0172 xbar->xbar_events = TI_AM335X_XBAR_LINES;
0173 }
0174
0175 iomem = devm_platform_ioremap_resource(pdev, 0);
0176 if (IS_ERR(iomem))
0177 return PTR_ERR(iomem);
0178
0179 xbar->iomem = iomem;
0180
0181 xbar->dmarouter.dev = &pdev->dev;
0182 xbar->dmarouter.route_free = ti_am335x_xbar_free;
0183
0184 platform_set_drvdata(pdev, xbar);
0185
0186
0187 for (i = 0; i < xbar->dma_requests; i++)
0188 ti_am335x_xbar_write(xbar->iomem, i, 0);
0189
0190 ret = of_dma_router_register(node, ti_am335x_xbar_route_allocate,
0191 &xbar->dmarouter);
0192
0193 return ret;
0194 }
0195
0196
0197 #define TI_DRA7_XBAR_OUTPUTS 127
0198 #define TI_DRA7_XBAR_INPUTS 256
0199
0200 struct ti_dra7_xbar_data {
0201 void __iomem *iomem;
0202
0203 struct dma_router dmarouter;
0204 struct mutex mutex;
0205 unsigned long *dma_inuse;
0206
0207 u16 safe_val;
0208 u32 xbar_requests;
0209 u32 dma_requests;
0210 u32 dma_offset;
0211 };
0212
0213 struct ti_dra7_xbar_map {
0214 u16 xbar_in;
0215 int xbar_out;
0216 };
0217
0218 static inline void ti_dra7_xbar_write(void __iomem *iomem, int xbar, u16 val)
0219 {
0220 writew_relaxed(val, iomem + (xbar * 2));
0221 }
0222
0223 static void ti_dra7_xbar_free(struct device *dev, void *route_data)
0224 {
0225 struct ti_dra7_xbar_data *xbar = dev_get_drvdata(dev);
0226 struct ti_dra7_xbar_map *map = route_data;
0227
0228 dev_dbg(dev, "Unmapping XBAR%u (was routed to %d)\n",
0229 map->xbar_in, map->xbar_out);
0230
0231 ti_dra7_xbar_write(xbar->iomem, map->xbar_out, xbar->safe_val);
0232 mutex_lock(&xbar->mutex);
0233 clear_bit(map->xbar_out, xbar->dma_inuse);
0234 mutex_unlock(&xbar->mutex);
0235 kfree(map);
0236 }
0237
0238 static void *ti_dra7_xbar_route_allocate(struct of_phandle_args *dma_spec,
0239 struct of_dma *ofdma)
0240 {
0241 struct platform_device *pdev = of_find_device_by_node(ofdma->of_node);
0242 struct ti_dra7_xbar_data *xbar = platform_get_drvdata(pdev);
0243 struct ti_dra7_xbar_map *map;
0244
0245 if (dma_spec->args[0] >= xbar->xbar_requests) {
0246 dev_err(&pdev->dev, "Invalid XBAR request number: %d\n",
0247 dma_spec->args[0]);
0248 put_device(&pdev->dev);
0249 return ERR_PTR(-EINVAL);
0250 }
0251
0252
0253 dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", 0);
0254 if (!dma_spec->np) {
0255 dev_err(&pdev->dev, "Can't get DMA master\n");
0256 put_device(&pdev->dev);
0257 return ERR_PTR(-EINVAL);
0258 }
0259
0260 map = kzalloc(sizeof(*map), GFP_KERNEL);
0261 if (!map) {
0262 of_node_put(dma_spec->np);
0263 put_device(&pdev->dev);
0264 return ERR_PTR(-ENOMEM);
0265 }
0266
0267 mutex_lock(&xbar->mutex);
0268 map->xbar_out = find_first_zero_bit(xbar->dma_inuse,
0269 xbar->dma_requests);
0270 if (map->xbar_out == xbar->dma_requests) {
0271 mutex_unlock(&xbar->mutex);
0272 dev_err(&pdev->dev, "Run out of free DMA requests\n");
0273 kfree(map);
0274 of_node_put(dma_spec->np);
0275 put_device(&pdev->dev);
0276 return ERR_PTR(-ENOMEM);
0277 }
0278 set_bit(map->xbar_out, xbar->dma_inuse);
0279 mutex_unlock(&xbar->mutex);
0280
0281 map->xbar_in = (u16)dma_spec->args[0];
0282
0283 dma_spec->args[0] = map->xbar_out + xbar->dma_offset;
0284
0285 dev_dbg(&pdev->dev, "Mapping XBAR%u to DMA%d\n",
0286 map->xbar_in, map->xbar_out);
0287
0288 ti_dra7_xbar_write(xbar->iomem, map->xbar_out, map->xbar_in);
0289
0290 return map;
0291 }
0292
0293 #define TI_XBAR_EDMA_OFFSET 0
0294 #define TI_XBAR_SDMA_OFFSET 1
0295 static const u32 ti_dma_offset[] = {
0296 [TI_XBAR_EDMA_OFFSET] = 0,
0297 [TI_XBAR_SDMA_OFFSET] = 1,
0298 };
0299
0300 static const struct of_device_id ti_dra7_master_match[] __maybe_unused = {
0301 {
0302 .compatible = "ti,omap4430-sdma",
0303 .data = &ti_dma_offset[TI_XBAR_SDMA_OFFSET],
0304 },
0305 {
0306 .compatible = "ti,edma3",
0307 .data = &ti_dma_offset[TI_XBAR_EDMA_OFFSET],
0308 },
0309 {
0310 .compatible = "ti,edma3-tpcc",
0311 .data = &ti_dma_offset[TI_XBAR_EDMA_OFFSET],
0312 },
0313 {},
0314 };
0315
0316 static inline void ti_dra7_xbar_reserve(int offset, int len, unsigned long *p)
0317 {
0318 for (; len > 0; len--)
0319 set_bit(offset + (len - 1), p);
0320 }
0321
0322 static int ti_dra7_xbar_probe(struct platform_device *pdev)
0323 {
0324 struct device_node *node = pdev->dev.of_node;
0325 const struct of_device_id *match;
0326 struct device_node *dma_node;
0327 struct ti_dra7_xbar_data *xbar;
0328 struct property *prop;
0329 u32 safe_val;
0330 int sz;
0331 void __iomem *iomem;
0332 int i, ret;
0333
0334 if (!node)
0335 return -ENODEV;
0336
0337 xbar = devm_kzalloc(&pdev->dev, sizeof(*xbar), GFP_KERNEL);
0338 if (!xbar)
0339 return -ENOMEM;
0340
0341 dma_node = of_parse_phandle(node, "dma-masters", 0);
0342 if (!dma_node) {
0343 dev_err(&pdev->dev, "Can't get DMA master node\n");
0344 return -ENODEV;
0345 }
0346
0347 match = of_match_node(ti_dra7_master_match, dma_node);
0348 if (!match) {
0349 dev_err(&pdev->dev, "DMA master is not supported\n");
0350 of_node_put(dma_node);
0351 return -EINVAL;
0352 }
0353
0354 if (of_property_read_u32(dma_node, "dma-requests",
0355 &xbar->dma_requests)) {
0356 dev_info(&pdev->dev,
0357 "Missing XBAR output information, using %u.\n",
0358 TI_DRA7_XBAR_OUTPUTS);
0359 xbar->dma_requests = TI_DRA7_XBAR_OUTPUTS;
0360 }
0361 of_node_put(dma_node);
0362
0363 xbar->dma_inuse = devm_kcalloc(&pdev->dev,
0364 BITS_TO_LONGS(xbar->dma_requests),
0365 sizeof(unsigned long), GFP_KERNEL);
0366 if (!xbar->dma_inuse)
0367 return -ENOMEM;
0368
0369 if (of_property_read_u32(node, "dma-requests", &xbar->xbar_requests)) {
0370 dev_info(&pdev->dev,
0371 "Missing XBAR input information, using %u.\n",
0372 TI_DRA7_XBAR_INPUTS);
0373 xbar->xbar_requests = TI_DRA7_XBAR_INPUTS;
0374 }
0375
0376 if (!of_property_read_u32(node, "ti,dma-safe-map", &safe_val))
0377 xbar->safe_val = (u16)safe_val;
0378
0379
0380 prop = of_find_property(node, "ti,reserved-dma-request-ranges", &sz);
0381 if (prop) {
0382 const char pname[] = "ti,reserved-dma-request-ranges";
0383 u32 (*rsv_events)[2];
0384 size_t nelm = sz / sizeof(*rsv_events);
0385 int i;
0386
0387 if (!nelm)
0388 return -EINVAL;
0389
0390 rsv_events = kcalloc(nelm, sizeof(*rsv_events), GFP_KERNEL);
0391 if (!rsv_events)
0392 return -ENOMEM;
0393
0394 ret = of_property_read_u32_array(node, pname, (u32 *)rsv_events,
0395 nelm * 2);
0396 if (ret) {
0397 kfree(rsv_events);
0398 return ret;
0399 }
0400
0401 for (i = 0; i < nelm; i++) {
0402 ti_dra7_xbar_reserve(rsv_events[i][0], rsv_events[i][1],
0403 xbar->dma_inuse);
0404 }
0405 kfree(rsv_events);
0406 }
0407
0408 iomem = devm_platform_ioremap_resource(pdev, 0);
0409 if (IS_ERR(iomem))
0410 return PTR_ERR(iomem);
0411
0412 xbar->iomem = iomem;
0413
0414 xbar->dmarouter.dev = &pdev->dev;
0415 xbar->dmarouter.route_free = ti_dra7_xbar_free;
0416 xbar->dma_offset = *(u32 *)match->data;
0417
0418 mutex_init(&xbar->mutex);
0419 platform_set_drvdata(pdev, xbar);
0420
0421
0422 for (i = 0; i < xbar->dma_requests; i++) {
0423 if (!test_bit(i, xbar->dma_inuse))
0424 ti_dra7_xbar_write(xbar->iomem, i, xbar->safe_val);
0425 }
0426
0427 ret = of_dma_router_register(node, ti_dra7_xbar_route_allocate,
0428 &xbar->dmarouter);
0429 if (ret) {
0430
0431 for (i = 0; i < xbar->dma_requests; i++) {
0432 if (!test_bit(i, xbar->dma_inuse))
0433 ti_dra7_xbar_write(xbar->iomem, i, i);
0434 }
0435 }
0436
0437 return ret;
0438 }
0439
0440 static int ti_dma_xbar_probe(struct platform_device *pdev)
0441 {
0442 const struct of_device_id *match;
0443 int ret;
0444
0445 match = of_match_node(ti_dma_xbar_match, pdev->dev.of_node);
0446 if (unlikely(!match))
0447 return -EINVAL;
0448
0449 switch (*(u32 *)match->data) {
0450 case TI_XBAR_DRA7:
0451 ret = ti_dra7_xbar_probe(pdev);
0452 break;
0453 case TI_XBAR_AM335X:
0454 ret = ti_am335x_xbar_probe(pdev);
0455 break;
0456 default:
0457 dev_err(&pdev->dev, "Unsupported crossbar\n");
0458 ret = -ENODEV;
0459 break;
0460 }
0461
0462 return ret;
0463 }
0464
0465 static struct platform_driver ti_dma_xbar_driver = {
0466 .driver = {
0467 .name = "ti-dma-crossbar",
0468 .of_match_table = ti_dma_xbar_match,
0469 },
0470 .probe = ti_dma_xbar_probe,
0471 };
0472
0473 static int omap_dmaxbar_init(void)
0474 {
0475 return platform_driver_register(&ti_dma_xbar_driver);
0476 }
0477 arch_initcall(omap_dmaxbar_init);