brintos

brintos / linux-shallow public Read only

0
0
Text · 4.7 KiB · 02f4a83 Raw
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				       &reg, 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