ti-dma-crossbar.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. /*
  2. * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com
  3. * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License version 2 as
  7. * published by the Free Software Foundation.
  8. *
  9. */
  10. #include <linux/slab.h>
  11. #include <linux/err.h>
  12. #include <linux/init.h>
  13. #include <linux/list.h>
  14. #include <linux/io.h>
  15. #include <linux/idr.h>
  16. #include <linux/of_address.h>
  17. #include <linux/of_device.h>
  18. #include <linux/of_dma.h>
  19. #define TI_XBAR_OUTPUTS 127
  20. #define TI_XBAR_INPUTS 256
  21. #define TI_XBAR_EDMA_OFFSET 0
  22. #define TI_XBAR_SDMA_OFFSET 1
  23. struct ti_dma_xbar_data {
  24. void __iomem *iomem;
  25. struct dma_router dmarouter;
  26. struct idr map_idr;
  27. u16 safe_val; /* Value to rest the crossbar lines */
  28. u32 xbar_requests; /* number of DMA requests connected to XBAR */
  29. u32 dma_requests; /* number of DMA requests forwarded to DMA */
  30. u32 dma_offset;
  31. };
  32. struct ti_dma_xbar_map {
  33. u16 xbar_in;
  34. int xbar_out;
  35. };
  36. static inline void ti_dma_xbar_write(void __iomem *iomem, int xbar, u16 val)
  37. {
  38. writew_relaxed(val, iomem + (xbar * 2));
  39. }
  40. static void ti_dma_xbar_free(struct device *dev, void *route_data)
  41. {
  42. struct ti_dma_xbar_data *xbar = dev_get_drvdata(dev);
  43. struct ti_dma_xbar_map *map = route_data;
  44. dev_dbg(dev, "Unmapping XBAR%u (was routed to %d)\n",
  45. map->xbar_in, map->xbar_out);
  46. ti_dma_xbar_write(xbar->iomem, map->xbar_out, xbar->safe_val);
  47. idr_remove(&xbar->map_idr, map->xbar_out);
  48. kfree(map);
  49. }
  50. static void *ti_dma_xbar_route_allocate(struct of_phandle_args *dma_spec,
  51. struct of_dma *ofdma)
  52. {
  53. struct platform_device *pdev = of_find_device_by_node(ofdma->of_node);
  54. struct ti_dma_xbar_data *xbar = platform_get_drvdata(pdev);
  55. struct ti_dma_xbar_map *map;
  56. if (dma_spec->args[0] >= xbar->xbar_requests) {
  57. dev_err(&pdev->dev, "Invalid XBAR request number: %d\n",
  58. dma_spec->args[0]);
  59. return ERR_PTR(-EINVAL);
  60. }
  61. /* The of_node_put() will be done in the core for the node */
  62. dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", 0);
  63. if (!dma_spec->np) {
  64. dev_err(&pdev->dev, "Can't get DMA master\n");
  65. return ERR_PTR(-EINVAL);
  66. }
  67. map = kzalloc(sizeof(*map), GFP_KERNEL);
  68. if (!map) {
  69. of_node_put(dma_spec->np);
  70. return ERR_PTR(-ENOMEM);
  71. }
  72. map->xbar_out = idr_alloc(&xbar->map_idr, NULL, 0, xbar->dma_requests,
  73. GFP_KERNEL);
  74. map->xbar_in = (u16)dma_spec->args[0];
  75. dma_spec->args[0] = map->xbar_out + xbar->dma_offset;
  76. dev_dbg(&pdev->dev, "Mapping XBAR%u to DMA%d\n",
  77. map->xbar_in, map->xbar_out);
  78. ti_dma_xbar_write(xbar->iomem, map->xbar_out, map->xbar_in);
  79. return map;
  80. }
  81. static const struct of_device_id ti_dma_master_match[] = {
  82. {
  83. .compatible = "ti,omap4430-sdma",
  84. .data = (void *)TI_XBAR_SDMA_OFFSET,
  85. },
  86. {
  87. .compatible = "ti,edma3",
  88. .data = (void *)TI_XBAR_EDMA_OFFSET,
  89. },
  90. {},
  91. };
  92. static int ti_dma_xbar_probe(struct platform_device *pdev)
  93. {
  94. struct device_node *node = pdev->dev.of_node;
  95. const struct of_device_id *match;
  96. struct device_node *dma_node;
  97. struct ti_dma_xbar_data *xbar;
  98. struct resource *res;
  99. u32 safe_val;
  100. void __iomem *iomem;
  101. int i, ret;
  102. if (!node)
  103. return -ENODEV;
  104. xbar = devm_kzalloc(&pdev->dev, sizeof(*xbar), GFP_KERNEL);
  105. if (!xbar)
  106. return -ENOMEM;
  107. idr_init(&xbar->map_idr);
  108. dma_node = of_parse_phandle(node, "dma-masters", 0);
  109. if (!dma_node) {
  110. dev_err(&pdev->dev, "Can't get DMA master node\n");
  111. return -ENODEV;
  112. }
  113. match = of_match_node(ti_dma_master_match, dma_node);
  114. if (!match) {
  115. dev_err(&pdev->dev, "DMA master is not supported\n");
  116. return -EINVAL;
  117. }
  118. if (of_property_read_u32(dma_node, "dma-requests",
  119. &xbar->dma_requests)) {
  120. dev_info(&pdev->dev,
  121. "Missing XBAR output information, using %u.\n",
  122. TI_XBAR_OUTPUTS);
  123. xbar->dma_requests = TI_XBAR_OUTPUTS;
  124. }
  125. of_node_put(dma_node);
  126. if (of_property_read_u32(node, "dma-requests", &xbar->xbar_requests)) {
  127. dev_info(&pdev->dev,
  128. "Missing XBAR input information, using %u.\n",
  129. TI_XBAR_INPUTS);
  130. xbar->xbar_requests = TI_XBAR_INPUTS;
  131. }
  132. if (!of_property_read_u32(node, "ti,dma-safe-map", &safe_val))
  133. xbar->safe_val = (u16)safe_val;
  134. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  135. iomem = devm_ioremap_resource(&pdev->dev, res);
  136. if (IS_ERR(iomem))
  137. return PTR_ERR(iomem);
  138. xbar->iomem = iomem;
  139. xbar->dmarouter.dev = &pdev->dev;
  140. xbar->dmarouter.route_free = ti_dma_xbar_free;
  141. xbar->dma_offset = (u32)match->data;
  142. platform_set_drvdata(pdev, xbar);
  143. /* Reset the crossbar */
  144. for (i = 0; i < xbar->dma_requests; i++)
  145. ti_dma_xbar_write(xbar->iomem, i, xbar->safe_val);
  146. ret = of_dma_router_register(node, ti_dma_xbar_route_allocate,
  147. &xbar->dmarouter);
  148. if (ret) {
  149. /* Restore the defaults for the crossbar */
  150. for (i = 0; i < xbar->dma_requests; i++)
  151. ti_dma_xbar_write(xbar->iomem, i, i);
  152. }
  153. return ret;
  154. }
  155. static const struct of_device_id ti_dma_xbar_match[] = {
  156. { .compatible = "ti,dra7-dma-crossbar" },
  157. {},
  158. };
  159. static struct platform_driver ti_dma_xbar_driver = {
  160. .driver = {
  161. .name = "ti-dma-crossbar",
  162. .of_match_table = of_match_ptr(ti_dma_xbar_match),
  163. },
  164. .probe = ti_dma_xbar_probe,
  165. };
  166. int omap_dmaxbar_init(void)
  167. {
  168. return platform_driver_register(&ti_dma_xbar_driver);
  169. }
  170. arch_initcall(omap_dmaxbar_init);