Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * dice-extension.c - a part of driver for DICE based devices
0004  *
0005  * Copyright (c) 2018 Takashi Sakamoto
0006  */
0007 
0008 #include "dice.h"
0009 
0010 /* For TCD2210/2220, TCAT defines extension of application protocol. */
0011 
0012 #define DICE_EXT_APP_SPACE      0xffffe0200000uLL
0013 
0014 #define DICE_EXT_APP_CAPS_OFFSET    0x00
0015 #define DICE_EXT_APP_CAPS_SIZE      0x04
0016 #define DICE_EXT_APP_CMD_OFFSET     0x08
0017 #define DICE_EXT_APP_CMD_SIZE       0x0c
0018 #define DICE_EXT_APP_MIXER_OFFSET   0x10
0019 #define DICE_EXT_APP_MIXER_SIZE     0x14
0020 #define DICE_EXT_APP_PEAK_OFFSET    0x18
0021 #define DICE_EXT_APP_PEAK_SIZE      0x1c
0022 #define DICE_EXT_APP_ROUTER_OFFSET  0x20
0023 #define DICE_EXT_APP_ROUTER_SIZE    0x24
0024 #define DICE_EXT_APP_STREAM_OFFSET  0x28
0025 #define DICE_EXT_APP_STREAM_SIZE    0x2c
0026 #define DICE_EXT_APP_CURRENT_OFFSET 0x30
0027 #define DICE_EXT_APP_CURRENT_SIZE   0x34
0028 #define DICE_EXT_APP_STANDALONE_OFFSET  0x38
0029 #define DICE_EXT_APP_STANDALONE_SIZE    0x3c
0030 #define DICE_EXT_APP_APPLICATION_OFFSET 0x40
0031 #define DICE_EXT_APP_APPLICATION_SIZE   0x44
0032 
0033 #define EXT_APP_STREAM_TX_NUMBER    0x0000
0034 #define EXT_APP_STREAM_RX_NUMBER    0x0004
0035 #define EXT_APP_STREAM_ENTRIES      0x0008
0036 #define EXT_APP_STREAM_ENTRY_SIZE   0x010c
0037 #define  EXT_APP_NUMBER_AUDIO       0x0000
0038 #define  EXT_APP_NUMBER_MIDI        0x0004
0039 #define  EXT_APP_NAMES          0x0008
0040 #define   EXT_APP_NAMES_SIZE        256
0041 #define  EXT_APP_AC3            0x0108
0042 
0043 #define EXT_APP_CONFIG_LOW_ROUTER   0x0000
0044 #define EXT_APP_CONFIG_LOW_STREAM   0x1000
0045 #define EXT_APP_CONFIG_MIDDLE_ROUTER    0x2000
0046 #define EXT_APP_CONFIG_MIDDLE_STREAM    0x3000
0047 #define EXT_APP_CONFIG_HIGH_ROUTER  0x4000
0048 #define EXT_APP_CONFIG_HIGH_STREAM  0x5000
0049 
0050 static inline int read_transaction(struct snd_dice *dice, u64 section_addr,
0051                    u32 offset, void *buf, size_t len)
0052 {
0053     return snd_fw_transaction(dice->unit,
0054                   len == 4 ? TCODE_READ_QUADLET_REQUEST :
0055                          TCODE_READ_BLOCK_REQUEST,
0056                   section_addr + offset, buf, len, 0);
0057 }
0058 
0059 static int read_stream_entries(struct snd_dice *dice, u64 section_addr,
0060                    u32 base_offset, unsigned int stream_count,
0061                    unsigned int mode,
0062                    unsigned int pcm_channels[MAX_STREAMS][3],
0063                    unsigned int midi_ports[MAX_STREAMS])
0064 {
0065     u32 entry_offset;
0066     __be32 reg[2];
0067     int err;
0068     int i;
0069 
0070     for (i = 0; i < stream_count; ++i) {
0071         entry_offset = base_offset + i * EXT_APP_STREAM_ENTRY_SIZE;
0072         err = read_transaction(dice, section_addr,
0073                     entry_offset + EXT_APP_NUMBER_AUDIO,
0074                     reg, sizeof(reg));
0075         if (err < 0)
0076             return err;
0077         pcm_channels[i][mode] = be32_to_cpu(reg[0]);
0078         midi_ports[i] = max(midi_ports[i], be32_to_cpu(reg[1]));
0079     }
0080 
0081     return 0;
0082 }
0083 
0084 static int detect_stream_formats(struct snd_dice *dice, u64 section_addr)
0085 {
0086     u32 base_offset;
0087     __be32 reg[2];
0088     unsigned int stream_count;
0089     int mode;
0090     int err = 0;
0091 
0092     for (mode = 0; mode < SND_DICE_RATE_MODE_COUNT; ++mode) {
0093         unsigned int cap;
0094 
0095         /*
0096          * Some models report stream formats at highest mode, however
0097          * they don't support the mode. Check clock capabilities.
0098          */
0099         if (mode == 2) {
0100             cap = CLOCK_CAP_RATE_176400 | CLOCK_CAP_RATE_192000;
0101         } else if (mode == 1) {
0102             cap = CLOCK_CAP_RATE_88200 | CLOCK_CAP_RATE_96000;
0103         } else {
0104             cap = CLOCK_CAP_RATE_32000 | CLOCK_CAP_RATE_44100 |
0105                   CLOCK_CAP_RATE_48000;
0106         }
0107         if (!(cap & dice->clock_caps))
0108             continue;
0109 
0110         base_offset = 0x2000 * mode + 0x1000;
0111 
0112         err = read_transaction(dice, section_addr,
0113                        base_offset + EXT_APP_STREAM_TX_NUMBER,
0114                        &reg, sizeof(reg));
0115         if (err < 0)
0116             break;
0117 
0118         base_offset += EXT_APP_STREAM_ENTRIES;
0119         stream_count = be32_to_cpu(reg[0]);
0120         err = read_stream_entries(dice, section_addr, base_offset,
0121                       stream_count, mode,
0122                       dice->tx_pcm_chs,
0123                       dice->tx_midi_ports);
0124         if (err < 0)
0125             break;
0126 
0127         base_offset += stream_count * EXT_APP_STREAM_ENTRY_SIZE;
0128         stream_count = be32_to_cpu(reg[1]);
0129         err = read_stream_entries(dice, section_addr, base_offset,
0130                       stream_count,
0131                       mode, dice->rx_pcm_chs,
0132                       dice->rx_midi_ports);
0133         if (err < 0)
0134             break;
0135     }
0136 
0137     return err;
0138 }
0139 
0140 int snd_dice_detect_extension_formats(struct snd_dice *dice)
0141 {
0142     __be32 *pointers;
0143     unsigned int i;
0144     u64 section_addr;
0145     int err;
0146 
0147     pointers = kmalloc_array(9, sizeof(__be32) * 2, GFP_KERNEL);
0148     if (pointers == NULL)
0149         return -ENOMEM;
0150 
0151     err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
0152                  DICE_EXT_APP_SPACE, pointers,
0153                  9 * sizeof(__be32) * 2, 0);
0154     if (err < 0)
0155         goto end;
0156 
0157     /* Check two of them for offset have the same value or not. */
0158     for (i = 0; i < 9; ++i) {
0159         int j;
0160 
0161         for (j = i + 1; j < 9; ++j) {
0162             if (pointers[i * 2] == pointers[j * 2]) {
0163                 // Fallback to limited functionality.
0164                 err = -ENXIO;
0165                 goto end;
0166             }
0167         }
0168     }
0169 
0170     section_addr = DICE_EXT_APP_SPACE + be32_to_cpu(pointers[12]) * 4;
0171     err = detect_stream_formats(dice, section_addr);
0172 end:
0173     kfree(pointers);
0174     return err;
0175 }