1 // SPDX-License-Identifier: GPL-2.0
3 * dice-extension.c - a part of driver for DICE based devices
5 * Copyright (c) 2018 Takashi Sakamoto
10 /* For TCD2210/2220, TCAT defines extension of application protocol. */
12 #define DICE_EXT_APP_SPACE 0xffffe0200000uLL
14 #define DICE_EXT_APP_CAPS_OFFSET 0x00
15 #define DICE_EXT_APP_CAPS_SIZE 0x04
16 #define DICE_EXT_APP_CMD_OFFSET 0x08
17 #define DICE_EXT_APP_CMD_SIZE 0x0c
18 #define DICE_EXT_APP_MIXER_OFFSET 0x10
19 #define DICE_EXT_APP_MIXER_SIZE 0x14
20 #define DICE_EXT_APP_PEAK_OFFSET 0x18
21 #define DICE_EXT_APP_PEAK_SIZE 0x1c
22 #define DICE_EXT_APP_ROUTER_OFFSET 0x20
23 #define DICE_EXT_APP_ROUTER_SIZE 0x24
24 #define DICE_EXT_APP_STREAM_OFFSET 0x28
25 #define DICE_EXT_APP_STREAM_SIZE 0x2c
26 #define DICE_EXT_APP_CURRENT_OFFSET 0x30
27 #define DICE_EXT_APP_CURRENT_SIZE 0x34
28 #define DICE_EXT_APP_STANDALONE_OFFSET 0x38
29 #define DICE_EXT_APP_STANDALONE_SIZE 0x3c
30 #define DICE_EXT_APP_APPLICATION_OFFSET 0x40
31 #define DICE_EXT_APP_APPLICATION_SIZE 0x44
33 #define EXT_APP_STREAM_TX_NUMBER 0x0000
34 #define EXT_APP_STREAM_RX_NUMBER 0x0004
35 #define EXT_APP_STREAM_ENTRIES 0x0008
36 #define EXT_APP_STREAM_ENTRY_SIZE 0x010c
37 #define EXT_APP_NUMBER_AUDIO 0x0000
38 #define EXT_APP_NUMBER_MIDI 0x0004
39 #define EXT_APP_NAMES 0x0008
40 #define EXT_APP_NAMES_SIZE 256
41 #define EXT_APP_AC3 0x0108
43 #define EXT_APP_CONFIG_LOW_ROUTER 0x0000
44 #define EXT_APP_CONFIG_LOW_STREAM 0x1000
45 #define EXT_APP_CONFIG_MIDDLE_ROUTER 0x2000
46 #define EXT_APP_CONFIG_MIDDLE_STREAM 0x3000
47 #define EXT_APP_CONFIG_HIGH_ROUTER 0x4000
48 #define EXT_APP_CONFIG_HIGH_STREAM 0x5000
50 static inline int read_transaction(struct snd_dice
*dice
, u64 section_addr
,
51 u32 offset
, void *buf
, size_t len
)
53 return snd_fw_transaction(dice
->unit
,
54 len
== 4 ? TCODE_READ_QUADLET_REQUEST
:
55 TCODE_READ_BLOCK_REQUEST
,
56 section_addr
+ offset
, buf
, len
, 0);
59 static int read_stream_entries(struct snd_dice
*dice
, u64 section_addr
,
60 u32 base_offset
, unsigned int stream_count
,
62 unsigned int pcm_channels
[MAX_STREAMS
][3],
63 unsigned int midi_ports
[MAX_STREAMS
])
70 for (i
= 0; i
< stream_count
; ++i
) {
71 entry_offset
= base_offset
+ i
* EXT_APP_STREAM_ENTRY_SIZE
;
72 err
= read_transaction(dice
, section_addr
,
73 entry_offset
+ EXT_APP_NUMBER_AUDIO
,
77 pcm_channels
[i
][mode
] = be32_to_cpu(reg
[0]);
78 midi_ports
[i
] = max(midi_ports
[i
], be32_to_cpu(reg
[1]));
84 static int detect_stream_formats(struct snd_dice
*dice
, u64 section_addr
)
88 unsigned int stream_count
;
92 for (mode
= 0; mode
< SND_DICE_RATE_MODE_COUNT
; ++mode
) {
96 * Some models report stream formats at highest mode, however
97 * they don't support the mode. Check clock capabilities.
100 cap
= CLOCK_CAP_RATE_176400
| CLOCK_CAP_RATE_192000
;
101 } else if (mode
== 1) {
102 cap
= CLOCK_CAP_RATE_88200
| CLOCK_CAP_RATE_96000
;
104 cap
= CLOCK_CAP_RATE_32000
| CLOCK_CAP_RATE_44100
|
105 CLOCK_CAP_RATE_48000
;
107 if (!(cap
& dice
->clock_caps
))
110 base_offset
= 0x2000 * mode
+ 0x1000;
112 err
= read_transaction(dice
, section_addr
,
113 base_offset
+ EXT_APP_STREAM_TX_NUMBER
,
118 base_offset
+= EXT_APP_STREAM_ENTRIES
;
119 stream_count
= be32_to_cpu(reg
[0]);
120 err
= read_stream_entries(dice
, section_addr
, base_offset
,
123 dice
->tx_midi_ports
);
127 base_offset
+= stream_count
* EXT_APP_STREAM_ENTRY_SIZE
;
128 stream_count
= be32_to_cpu(reg
[1]);
129 err
= read_stream_entries(dice
, section_addr
, base_offset
,
131 mode
, dice
->rx_pcm_chs
,
132 dice
->rx_midi_ports
);
140 int snd_dice_detect_extension_formats(struct snd_dice
*dice
)
147 pointers
= kmalloc_array(9, sizeof(__be32
) * 2, GFP_KERNEL
);
148 if (pointers
== NULL
)
151 err
= snd_fw_transaction(dice
->unit
, TCODE_READ_BLOCK_REQUEST
,
152 DICE_EXT_APP_SPACE
, pointers
,
153 9 * sizeof(__be32
) * 2, 0);
157 /* Check two of them for offset have the same value or not. */
158 for (i
= 0; i
< 9; ++i
) {
161 for (j
= i
+ 1; j
< 9; ++j
) {
162 if (pointers
[i
* 2] == pointers
[j
* 2])
167 section_addr
= DICE_EXT_APP_SPACE
+ be32_to_cpu(pointers
[12]) * 4;
168 err
= detect_stream_formats(dice
, section_addr
);