apbio.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. /*
  2. * Copyright (C) 2010 NVIDIA Corporation.
  3. * Copyright (C) 2010 Google, Inc.
  4. *
  5. * This software is licensed under the terms of the GNU General Public
  6. * License version 2, as published by the Free Software Foundation, and
  7. * may be copied, distributed, and modified under those terms.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. */
  15. #include <linux/kernel.h>
  16. #include <linux/io.h>
  17. #include <linux/dma-mapping.h>
  18. #include <linux/spinlock.h>
  19. #include <linux/completion.h>
  20. #include <linux/sched.h>
  21. #include <linux/mutex.h>
  22. #include <mach/dma.h>
  23. #include <mach/iomap.h>
  24. #include "apbio.h"
  25. static DEFINE_MUTEX(tegra_apb_dma_lock);
  26. static struct tegra_dma_channel *tegra_apb_dma;
  27. static u32 *tegra_apb_bb;
  28. static dma_addr_t tegra_apb_bb_phys;
  29. static DECLARE_COMPLETION(tegra_apb_wait);
  30. bool tegra_apb_init(void)
  31. {
  32. struct tegra_dma_channel *ch;
  33. mutex_lock(&tegra_apb_dma_lock);
  34. /* Check to see if we raced to setup */
  35. if (tegra_apb_dma)
  36. goto out;
  37. ch = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT |
  38. TEGRA_DMA_SHARED);
  39. if (!ch)
  40. goto out_fail;
  41. tegra_apb_bb = dma_alloc_coherent(NULL, sizeof(u32),
  42. &tegra_apb_bb_phys, GFP_KERNEL);
  43. if (!tegra_apb_bb) {
  44. pr_err("%s: can not allocate bounce buffer\n", __func__);
  45. tegra_dma_free_channel(ch);
  46. goto out_fail;
  47. }
  48. tegra_apb_dma = ch;
  49. out:
  50. mutex_unlock(&tegra_apb_dma_lock);
  51. return true;
  52. out_fail:
  53. mutex_unlock(&tegra_apb_dma_lock);
  54. return false;
  55. }
  56. static void apb_dma_complete(struct tegra_dma_req *req)
  57. {
  58. complete(&tegra_apb_wait);
  59. }
  60. u32 tegra_apb_readl(unsigned long offset)
  61. {
  62. struct tegra_dma_req req;
  63. int ret;
  64. if (!tegra_apb_dma && !tegra_apb_init())
  65. return readl(IO_TO_VIRT(offset));
  66. mutex_lock(&tegra_apb_dma_lock);
  67. req.complete = apb_dma_complete;
  68. req.to_memory = 1;
  69. req.dest_addr = tegra_apb_bb_phys;
  70. req.dest_bus_width = 32;
  71. req.dest_wrap = 1;
  72. req.source_addr = offset;
  73. req.source_bus_width = 32;
  74. req.source_wrap = 4;
  75. req.req_sel = TEGRA_DMA_REQ_SEL_CNTR;
  76. req.size = 4;
  77. INIT_COMPLETION(tegra_apb_wait);
  78. tegra_dma_enqueue_req(tegra_apb_dma, &req);
  79. ret = wait_for_completion_timeout(&tegra_apb_wait,
  80. msecs_to_jiffies(50));
  81. if (WARN(ret == 0, "apb read dma timed out")) {
  82. tegra_dma_dequeue_req(tegra_apb_dma, &req);
  83. *(u32 *)tegra_apb_bb = 0;
  84. }
  85. mutex_unlock(&tegra_apb_dma_lock);
  86. return *((u32 *)tegra_apb_bb);
  87. }
  88. void tegra_apb_writel(u32 value, unsigned long offset)
  89. {
  90. struct tegra_dma_req req;
  91. int ret;
  92. if (!tegra_apb_dma && !tegra_apb_init()) {
  93. writel(value, IO_TO_VIRT(offset));
  94. return;
  95. }
  96. mutex_lock(&tegra_apb_dma_lock);
  97. *((u32 *)tegra_apb_bb) = value;
  98. req.complete = apb_dma_complete;
  99. req.to_memory = 0;
  100. req.dest_addr = offset;
  101. req.dest_wrap = 4;
  102. req.dest_bus_width = 32;
  103. req.source_addr = tegra_apb_bb_phys;
  104. req.source_bus_width = 32;
  105. req.source_wrap = 1;
  106. req.req_sel = TEGRA_DMA_REQ_SEL_CNTR;
  107. req.size = 4;
  108. INIT_COMPLETION(tegra_apb_wait);
  109. tegra_dma_enqueue_req(tegra_apb_dma, &req);
  110. ret = wait_for_completion_timeout(&tegra_apb_wait,
  111. msecs_to_jiffies(50));
  112. if (WARN(ret == 0, "apb write dma timed out"))
  113. tegra_dma_dequeue_req(tegra_apb_dma, &req);
  114. mutex_unlock(&tegra_apb_dma_lock);
  115. }