dice-extension.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * dice-extension.c - a part of driver for DICE based devices
  4. *
  5. * Copyright (c) 2018 Takashi Sakamoto
  6. */
  7. #include "dice.h"
  8. /* For TCD2210/2220, TCAT defines extension of application protocol. */
  9. #define DICE_EXT_APP_SPACE 0xffffe0200000uLL
  10. #define DICE_EXT_APP_CAPS_OFFSET 0x00
  11. #define DICE_EXT_APP_CAPS_SIZE 0x04
  12. #define DICE_EXT_APP_CMD_OFFSET 0x08
  13. #define DICE_EXT_APP_CMD_SIZE 0x0c
  14. #define DICE_EXT_APP_MIXER_OFFSET 0x10
  15. #define DICE_EXT_APP_MIXER_SIZE 0x14
  16. #define DICE_EXT_APP_PEAK_OFFSET 0x18
  17. #define DICE_EXT_APP_PEAK_SIZE 0x1c
  18. #define DICE_EXT_APP_ROUTER_OFFSET 0x20
  19. #define DICE_EXT_APP_ROUTER_SIZE 0x24
  20. #define DICE_EXT_APP_STREAM_OFFSET 0x28
  21. #define DICE_EXT_APP_STREAM_SIZE 0x2c
  22. #define DICE_EXT_APP_CURRENT_OFFSET 0x30
  23. #define DICE_EXT_APP_CURRENT_SIZE 0x34
  24. #define DICE_EXT_APP_STANDALONE_OFFSET 0x38
  25. #define DICE_EXT_APP_STANDALONE_SIZE 0x3c
  26. #define DICE_EXT_APP_APPLICATION_OFFSET 0x40
  27. #define DICE_EXT_APP_APPLICATION_SIZE 0x44
  28. #define EXT_APP_STREAM_TX_NUMBER 0x0000
  29. #define EXT_APP_STREAM_RX_NUMBER 0x0004
  30. #define EXT_APP_STREAM_ENTRIES 0x0008
  31. #define EXT_APP_STREAM_ENTRY_SIZE 0x010c
  32. #define EXT_APP_NUMBER_AUDIO 0x0000
  33. #define EXT_APP_NUMBER_MIDI 0x0004
  34. #define EXT_APP_NAMES 0x0008
  35. #define EXT_APP_NAMES_SIZE 256
  36. #define EXT_APP_AC3 0x0108
  37. #define EXT_APP_CONFIG_LOW_ROUTER 0x0000
  38. #define EXT_APP_CONFIG_LOW_STREAM 0x1000
  39. #define EXT_APP_CONFIG_MIDDLE_ROUTER 0x2000
  40. #define EXT_APP_CONFIG_MIDDLE_STREAM 0x3000
  41. #define EXT_APP_CONFIG_HIGH_ROUTER 0x4000
  42. #define EXT_APP_CONFIG_HIGH_STREAM 0x5000
  43. static inline int read_transaction(struct snd_dice *dice, u64 section_addr,
  44. u32 offset, void *buf, size_t len)
  45. {
  46. return snd_fw_transaction(dice->unit,
  47. len == 4 ? TCODE_READ_QUADLET_REQUEST :
  48. TCODE_READ_BLOCK_REQUEST,
  49. section_addr + offset, buf, len, 0);
  50. }
  51. static int read_stream_entries(struct snd_dice *dice, u64 section_addr,
  52. u32 base_offset, unsigned int stream_count,
  53. unsigned int mode,
  54. unsigned int pcm_channels[MAX_STREAMS][3],
  55. unsigned int midi_ports[MAX_STREAMS])
  56. {
  57. u32 entry_offset;
  58. __be32 reg[2];
  59. int err;
  60. int i;
  61. for (i = 0; i < stream_count; ++i) {
  62. entry_offset = base_offset + i * EXT_APP_STREAM_ENTRY_SIZE;
  63. err = read_transaction(dice, section_addr,
  64. entry_offset + EXT_APP_NUMBER_AUDIO,
  65. reg, sizeof(reg));
  66. if (err < 0)
  67. return err;
  68. pcm_channels[i][mode] = be32_to_cpu(reg[0]);
  69. midi_ports[i] = max(midi_ports[i], be32_to_cpu(reg[1]));
  70. }
  71. return 0;
  72. }
  73. static int detect_stream_formats(struct snd_dice *dice, u64 section_addr)
  74. {
  75. u32 base_offset;
  76. __be32 reg[2];
  77. unsigned int stream_count;
  78. int mode;
  79. int err = 0;
  80. for (mode = 0; mode < SND_DICE_RATE_MODE_COUNT; ++mode) {
  81. unsigned int cap;
  82. /*
  83. * Some models report stream formats at highest mode, however
  84. * they don't support the mode. Check clock capabilities.
  85. */
  86. if (mode == 2) {
  87. cap = CLOCK_CAP_RATE_176400 | CLOCK_CAP_RATE_192000;
  88. } else if (mode == 1) {
  89. cap = CLOCK_CAP_RATE_88200 | CLOCK_CAP_RATE_96000;
  90. } else {
  91. cap = CLOCK_CAP_RATE_32000 | CLOCK_CAP_RATE_44100 |
  92. CLOCK_CAP_RATE_48000;
  93. }
  94. if (!(cap & dice->clock_caps))
  95. continue;
  96. base_offset = 0x2000 * mode + 0x1000;
  97. err = read_transaction(dice, section_addr,
  98. base_offset + EXT_APP_STREAM_TX_NUMBER,
  99. &reg, sizeof(reg));
  100. if (err < 0)
  101. break;
  102. base_offset += EXT_APP_STREAM_ENTRIES;
  103. stream_count = be32_to_cpu(reg[0]);
  104. err = read_stream_entries(dice, section_addr, base_offset,
  105. stream_count, mode,
  106. dice->tx_pcm_chs,
  107. dice->tx_midi_ports);
  108. if (err < 0)
  109. break;
  110. base_offset += stream_count * EXT_APP_STREAM_ENTRY_SIZE;
  111. stream_count = be32_to_cpu(reg[1]);
  112. err = read_stream_entries(dice, section_addr, base_offset,
  113. stream_count,
  114. mode, dice->rx_pcm_chs,
  115. dice->rx_midi_ports);
  116. if (err < 0)
  117. break;
  118. }
  119. return err;
  120. }
  121. int snd_dice_detect_extension_formats(struct snd_dice *dice)
  122. {
  123. __be32 *pointers;
  124. unsigned int i;
  125. u64 section_addr;
  126. int err;
  127. pointers = kmalloc_array(9, sizeof(__be32) * 2, GFP_KERNEL);
  128. if (pointers == NULL)
  129. return -ENOMEM;
  130. err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
  131. DICE_EXT_APP_SPACE, pointers,
  132. 9 * sizeof(__be32) * 2, 0);
  133. if (err < 0)
  134. goto end;
  135. /* Check two of them for offset have the same value or not. */
  136. for (i = 0; i < 9; ++i) {
  137. int j;
  138. for (j = i + 1; j < 9; ++j) {
  139. if (pointers[i * 2] == pointers[j * 2]) {
  140. // Fallback to limited functionality.
  141. err = -ENXIO;
  142. goto end;
  143. }
  144. }
  145. }
  146. section_addr = DICE_EXT_APP_SPACE + be32_to_cpu(pointers[12]) * 4;
  147. err = detect_stream_formats(dice, section_addr);
  148. end:
  149. kfree(pointers);
  150. return err;
  151. }