tegra_ahub.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. // SPDX-License-Identifier: GPL-2.0+159
  2. /*
  3. * Take from dc tegra_ahub.c
  4. *
  5. * Copyright 2018 Google LLC
  6. */
  7. #define LOG_CATEGORY UCLASS_MISC
  8. #include <common.h>
  9. #include <dm.h>
  10. #include <i2s.h>
  11. #include <log.h>
  12. #include <misc.h>
  13. #include <asm/io.h>
  14. #include <asm/arch-tegra/tegra_ahub.h>
  15. #include <asm/arch-tegra/tegra_i2s.h>
  16. #include "tegra_i2s_priv.h"
  17. struct tegra_ahub_priv {
  18. struct apbif_regs *apbif_regs;
  19. struct xbar_regs *xbar_regs;
  20. u32 full_mask;
  21. int capacity_words; /* FIFO capacity in words */
  22. /*
  23. * This is unset intially, but is set by tegra_ahub_ioctl() called
  24. * from the misc_ioctl() in tegra_sound_probe()
  25. */
  26. struct udevice *i2s;
  27. struct udevice *dma;
  28. };
  29. static int tegra_ahub_xbar_enable_i2s(struct xbar_regs *regs, int i2s_id)
  30. {
  31. /*
  32. * Enables I2S as the receiver of APBIF by writing APBIF_TX0 (0x01) to
  33. * the rx0 register
  34. */
  35. switch (i2s_id) {
  36. case 0:
  37. writel(1, &regs->i2s0_rx0);
  38. break;
  39. case 1:
  40. writel(1, &regs->i2s1_rx0);
  41. break;
  42. case 2:
  43. writel(1, &regs->i2s2_rx0);
  44. break;
  45. case 3:
  46. writel(1, &regs->i2s3_rx0);
  47. break;
  48. case 4:
  49. writel(1, &regs->i2s4_rx0);
  50. break;
  51. default:
  52. log_err("Invalid I2S component id: %d\n", i2s_id);
  53. return -EINVAL;
  54. }
  55. return 0;
  56. }
  57. static int tegra_ahub_apbif_is_full(struct udevice *dev)
  58. {
  59. struct tegra_ahub_priv *priv = dev_get_priv(dev);
  60. return readl(&priv->apbif_regs->apbdma_live_stat) & priv->full_mask;
  61. }
  62. /**
  63. * tegra_ahub_wait_for_space() - Wait for space in the FIFO
  64. *
  65. * @return 0 if OK, -ETIMEDOUT if no space was available in time
  66. */
  67. static int tegra_ahub_wait_for_space(struct udevice *dev)
  68. {
  69. int i = 100000;
  70. ulong start;
  71. /* Busy-wait initially, since this should take almost no time */
  72. while (i--) {
  73. if (!tegra_ahub_apbif_is_full(dev))
  74. return 0;
  75. }
  76. /* Failed, so do a slower loop for 100ms */
  77. start = get_timer(0);
  78. while (tegra_ahub_apbif_is_full(dev)) {
  79. if (get_timer(start) > 100)
  80. return -ETIMEDOUT;
  81. }
  82. return 0;
  83. }
  84. static int tegra_ahub_apbif_send(struct udevice *dev, int offset,
  85. const void *buf, int len)
  86. {
  87. struct tegra_ahub_priv *priv = dev_get_priv(dev);
  88. const u32 *data = (const u32 *)buf;
  89. ssize_t written = 0;
  90. if (len % sizeof(*data)) {
  91. log_err("Data size (%zd) must be aligned to %zd.\n", len,
  92. sizeof(*data));
  93. return -EFAULT;
  94. }
  95. while (written < len) {
  96. int ret = tegra_ahub_wait_for_space(dev);
  97. if (ret)
  98. return ret;
  99. writel(*data++, &priv->apbif_regs->channel0_txfifo);
  100. written += sizeof(*data);
  101. }
  102. return written;
  103. }
  104. static void tegra_ahub_apbif_set_cif(struct udevice *dev, u32 value)
  105. {
  106. struct tegra_ahub_priv *priv = dev_get_priv(dev);
  107. writel(value, &priv->apbif_regs->channel0_cif_tx0_ctrl);
  108. }
  109. static void tegra_ahub_apbif_enable_channel0(struct udevice *dev,
  110. int fifo_threshold)
  111. {
  112. struct tegra_ahub_priv *priv = dev_get_priv(dev);
  113. u32 ctrl = TEGRA_AHUB_CHANNEL_CTRL_TX_PACK_EN |
  114. TEGRA_AHUB_CHANNEL_CTRL_TX_PACK_16 |
  115. TEGRA_AHUB_CHANNEL_CTRL_TX_EN;
  116. fifo_threshold--; /* fifo_threshold starts from 1 */
  117. ctrl |= (fifo_threshold << TEGRA_AHUB_CHANNEL_CTRL_TX_THRESHOLD_SHIFT);
  118. writel(ctrl, &priv->apbif_regs->channel0_ctrl);
  119. }
  120. static u32 tegra_ahub_get_cif(bool is_receive, uint channels,
  121. uint bits_per_sample, uint fifo_threshold)
  122. {
  123. uint audio_bits = (bits_per_sample >> 2) - 1;
  124. u32 val;
  125. channels--; /* Channels in CIF starts from 1 */
  126. fifo_threshold--; /* FIFO threshold starts from 1 */
  127. /* Assume input and output are always using same channel / bits */
  128. val = channels << TEGRA_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT |
  129. channels << TEGRA_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT |
  130. audio_bits << TEGRA_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT |
  131. audio_bits << TEGRA_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT |
  132. fifo_threshold << TEGRA_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT |
  133. (is_receive ? TEGRA_AUDIOCIF_DIRECTION_RX <<
  134. TEGRA_AUDIOCIF_CTRL_DIRECTION_SHIFT : 0);
  135. return val;
  136. }
  137. static int tegra_ahub_enable(struct udevice *dev)
  138. {
  139. struct tegra_ahub_priv *priv = dev_get_priv(dev);
  140. struct i2s_uc_priv *uc_priv = dev_get_uclass_priv(priv->i2s);
  141. u32 cif_ctrl = 0;
  142. int ret;
  143. /* We use APBIF channel0 as a sender */
  144. priv->full_mask = TEGRA_AHUB_APBDMA_LIVE_STATUS_CH0_TX_CIF_FIFO_FULL;
  145. priv->capacity_words = 8;
  146. /*
  147. * FIFO is inactive until (fifo_threshold) of words are sent. For
  148. * better performance, we want to set it to half of capacity.
  149. */
  150. u32 fifo_threshold = priv->capacity_words / 2;
  151. /*
  152. * Setup audio client interface (ACIF): APBIF (channel0) as sender and
  153. * I2S as receiver
  154. */
  155. cif_ctrl = tegra_ahub_get_cif(true, uc_priv->channels,
  156. uc_priv->bitspersample, fifo_threshold);
  157. tegra_i2s_set_cif_tx_ctrl(priv->i2s, cif_ctrl);
  158. cif_ctrl = tegra_ahub_get_cif(false, uc_priv->channels,
  159. uc_priv->bitspersample, fifo_threshold);
  160. tegra_ahub_apbif_set_cif(dev, cif_ctrl);
  161. tegra_ahub_apbif_enable_channel0(dev, fifo_threshold);
  162. ret = tegra_ahub_xbar_enable_i2s(priv->xbar_regs, uc_priv->id);
  163. if (ret)
  164. return ret;
  165. log_debug("ahub: channels=%d, bitspersample=%d, cif_ctrl=%x, fifo_threshold=%d, id=%d\n",
  166. uc_priv->channels, uc_priv->bitspersample, cif_ctrl,
  167. fifo_threshold, uc_priv->id);
  168. return 0;
  169. }
  170. static int tegra_ahub_ioctl(struct udevice *dev, unsigned long request,
  171. void *buf)
  172. {
  173. struct tegra_ahub_priv *priv = dev_get_priv(dev);
  174. if (request != AHUB_MISCOP_SET_I2S)
  175. return -ENOSYS;
  176. priv->i2s = *(struct udevice **)buf;
  177. log_debug("i2s set to '%s'\n", priv->i2s->name);
  178. return tegra_ahub_enable(dev);
  179. }
  180. static int tegra_ahub_probe(struct udevice *dev)
  181. {
  182. struct tegra_ahub_priv *priv = dev_get_priv(dev);
  183. ulong addr;
  184. addr = dev_read_addr_index(dev, 0);
  185. if (addr == FDT_ADDR_T_NONE) {
  186. log_debug("Invalid apbif address\n");
  187. return -EINVAL;
  188. }
  189. priv->apbif_regs = (struct apbif_regs *)addr;
  190. addr = dev_read_addr_index(dev, 1);
  191. if (addr == FDT_ADDR_T_NONE) {
  192. log_debug("Invalid xbar address\n");
  193. return -EINVAL;
  194. }
  195. priv->xbar_regs = (struct xbar_regs *)addr;
  196. log_debug("ahub apbif_regs=%p, xbar_regs=%p\n", priv->apbif_regs,
  197. priv->xbar_regs);
  198. return 0;
  199. }
  200. static struct misc_ops tegra_ahub_ops = {
  201. .write = tegra_ahub_apbif_send,
  202. .ioctl = tegra_ahub_ioctl,
  203. };
  204. static const struct udevice_id tegra_ahub_ids[] = {
  205. { .compatible = "nvidia,tegra124-ahub" },
  206. { }
  207. };
  208. U_BOOT_DRIVER(tegra_ahub) = {
  209. .name = "tegra_ahub",
  210. .id = UCLASS_MISC,
  211. .of_match = tegra_ahub_ids,
  212. .ops = &tegra_ahub_ops,
  213. .probe = tegra_ahub_probe,
  214. .priv_auto_alloc_size = sizeof(struct tegra_ahub_priv),
  215. };