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