176 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * dice-extension.c - a part of driver for DICE based devices4 *5 * Copyright (c) 2018 Takashi Sakamoto6 */7 8#include "dice.h"9 10/* For TCD2210/2220, TCAT defines extension of application protocol. */11 12#define DICE_EXT_APP_SPACE 0xffffe0200000uLL13 14#define DICE_EXT_APP_CAPS_OFFSET 0x0015#define DICE_EXT_APP_CAPS_SIZE 0x0416#define DICE_EXT_APP_CMD_OFFSET 0x0817#define DICE_EXT_APP_CMD_SIZE 0x0c18#define DICE_EXT_APP_MIXER_OFFSET 0x1019#define DICE_EXT_APP_MIXER_SIZE 0x1420#define DICE_EXT_APP_PEAK_OFFSET 0x1821#define DICE_EXT_APP_PEAK_SIZE 0x1c22#define DICE_EXT_APP_ROUTER_OFFSET 0x2023#define DICE_EXT_APP_ROUTER_SIZE 0x2424#define DICE_EXT_APP_STREAM_OFFSET 0x2825#define DICE_EXT_APP_STREAM_SIZE 0x2c26#define DICE_EXT_APP_CURRENT_OFFSET 0x3027#define DICE_EXT_APP_CURRENT_SIZE 0x3428#define DICE_EXT_APP_STANDALONE_OFFSET 0x3829#define DICE_EXT_APP_STANDALONE_SIZE 0x3c30#define DICE_EXT_APP_APPLICATION_OFFSET 0x4031#define DICE_EXT_APP_APPLICATION_SIZE 0x4432 33#define EXT_APP_STREAM_TX_NUMBER 0x000034#define EXT_APP_STREAM_RX_NUMBER 0x000435#define EXT_APP_STREAM_ENTRIES 0x000836#define EXT_APP_STREAM_ENTRY_SIZE 0x010c37#define EXT_APP_NUMBER_AUDIO 0x000038#define EXT_APP_NUMBER_MIDI 0x000439#define EXT_APP_NAMES 0x000840#define EXT_APP_NAMES_SIZE 25641#define EXT_APP_AC3 0x010842 43#define EXT_APP_CONFIG_LOW_ROUTER 0x000044#define EXT_APP_CONFIG_LOW_STREAM 0x100045#define EXT_APP_CONFIG_MIDDLE_ROUTER 0x200046#define EXT_APP_CONFIG_MIDDLE_STREAM 0x300047#define EXT_APP_CONFIG_HIGH_ROUTER 0x400048#define EXT_APP_CONFIG_HIGH_STREAM 0x500049 50static inline int read_transaction(struct snd_dice *dice, u64 section_addr,51 u32 offset, void *buf, size_t len)52{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);57}58 59static int read_stream_entries(struct snd_dice *dice, u64 section_addr,60 u32 base_offset, unsigned int stream_count,61 unsigned int mode,62 unsigned int pcm_channels[MAX_STREAMS][3],63 unsigned int midi_ports[MAX_STREAMS])64{65 u32 entry_offset;66 __be32 reg[2];67 int err;68 int i;69 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,74 reg, sizeof(reg));75 if (err < 0)76 return err;77 pcm_channels[i][mode] = be32_to_cpu(reg[0]);78 midi_ports[i] = max(midi_ports[i], be32_to_cpu(reg[1]));79 }80 81 return 0;82}83 84static int detect_stream_formats(struct snd_dice *dice, u64 section_addr)85{86 u32 base_offset;87 __be32 reg[2];88 unsigned int stream_count;89 int mode;90 int err = 0;91 92 for (mode = 0; mode < SND_DICE_RATE_MODE_COUNT; ++mode) {93 unsigned int cap;94 95 /*96 * Some models report stream formats at highest mode, however97 * they don't support the mode. Check clock capabilities.98 */99 if (mode == 2) {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;103 } else {104 cap = CLOCK_CAP_RATE_32000 | CLOCK_CAP_RATE_44100 |105 CLOCK_CAP_RATE_48000;106 }107 if (!(cap & dice->clock_caps))108 continue;109 110 base_offset = 0x2000 * mode + 0x1000;111 112 err = read_transaction(dice, section_addr,113 base_offset + EXT_APP_STREAM_TX_NUMBER,114 ®, sizeof(reg));115 if (err < 0)116 break;117 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,121 stream_count, mode,122 dice->tx_pcm_chs,123 dice->tx_midi_ports);124 if (err < 0)125 break;126 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,130 stream_count,131 mode, dice->rx_pcm_chs,132 dice->rx_midi_ports);133 if (err < 0)134 break;135 }136 137 return err;138}139 140int snd_dice_detect_extension_formats(struct snd_dice *dice)141{142 __be32 *pointers;143 unsigned int i;144 u64 section_addr;145 int err;146 147 pointers = kmalloc_array(9, sizeof(__be32) * 2, GFP_KERNEL);148 if (pointers == NULL)149 return -ENOMEM;150 151 err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,152 DICE_EXT_APP_SPACE, pointers,153 9 * sizeof(__be32) * 2, 0);154 if (err < 0)155 goto end;156 157 /* Check two of them for offset have the same value or not. */158 for (i = 0; i < 9; ++i) {159 int j;160 161 for (j = i + 1; j < 9; ++j) {162 if (pointers[i * 2] == pointers[j * 2]) {163 // Fallback to limited functionality.164 err = -ENXIO;165 goto end;166 }167 }168 }169 170 section_addr = DICE_EXT_APP_SPACE + be32_to_cpu(pointers[12]) * 4;171 err = detect_stream_formats(dice, section_addr);172end:173 kfree(pointers);174 return err;175}176