firewire_dice_protocols/tcat/
tcd22xx_spec.rs

1// SPDX-License-Identifier: LGPL-3.0-or-later
2// Copyright (c) 2020 Takashi Sakamoto
3
4//! Specification of TCD2210 and TCD2220 ASICs and firmware.
5
6use super::{
7    extension::{caps_section::*, cmd_section::*, current_config_section::*, router_section::*, *},
8    *,
9};
10
11/// Available source and destination blocks of TCD22xx.
12#[derive(Default, Debug, Clone, PartialEq, Eq)]
13pub struct Tcd22xxAvailableBlocks(pub Vec<SrcBlk>, pub Vec<DstBlk>);
14
15/// Descriptor for input port.
16#[derive(Debug, Copy, Clone, PartialEq, Eq)]
17pub struct Input {
18    /// Identifier of source block.
19    pub id: SrcBlkId,
20    /// Offset of channel number.
21    pub offset: u8,
22    /// Count of channel number.
23    pub count: u8,
24    /// String expression.
25    pub label: Option<&'static str>,
26}
27
28/// Descriptor for output port.
29#[derive(Debug, Copy, Clone, PartialEq, Eq)]
30pub struct Output {
31    /// Identifier of destination block.
32    pub id: DstBlkId,
33    /// Offset of channel number.
34    pub offset: u8,
35    /// Count of channel number.
36    pub count: u8,
37    /// String expression.
38    pub label: Option<&'static str>,
39}
40
41/// Specification of TCD22xx.
42pub trait Tcd22xxSpecification {
43    /// Physical input ports.
44    const INPUTS: &'static [Input];
45
46    /// Physical output ports.
47    const OUTPUTS: &'static [Output];
48
49    /// Ports with fixed position in router entries; e.g. target ports for meter display.
50    const FIXED: &'static [SrcBlk];
51
52    /// The number of mixer outputs at specification of TCD22xx.
53    const MIXER_OUT_PORTS: [u8; 3] = [16, 16, 8];
54
55    /// The number of mixer inputs at specification of TCD22xx.
56    const MIXER_IN_PORTS: [(DstBlkId, u8); 2] = [(DstBlkId::MixerTx0, 16), (DstBlkId::MixerTx1, 2)];
57
58    /// The number of ADAT channels at specification of ADAT/SMUX.
59    const ADAT_CHANNELS: [u8; 3] = [8, 4, 2];
60
61    /// Compute the number of ADAT channels.
62    fn adat_channel_count(rate_mode: RateMode) -> u8 {
63        let index = match rate_mode {
64            RateMode::Low => 0,
65            RateMode::Middle => 1,
66            RateMode::High => 2,
67        };
68        Self::ADAT_CHANNELS[index]
69    }
70
71    /// Compute the number of mixer outputs.
72    fn mixer_out_port_count(rate_mode: RateMode) -> u8 {
73        let index = match rate_mode {
74            RateMode::Low => 0,
75            RateMode::Middle => 1,
76            RateMode::High => 2,
77        };
78        Self::MIXER_OUT_PORTS[index]
79    }
80
81    /// Compute the number of mixer inputs.
82    fn mixer_in_port_count() -> u8 {
83        Self::MIXER_IN_PORTS
84            .iter()
85            .fold(0, |accum, (_, count)| accum + count)
86    }
87
88    /// Compute available destination and source blocks for physical ports.
89    fn compute_avail_real_blk_pair(rate_mode: RateMode) -> (Vec<SrcBlk>, Vec<DstBlk>) {
90        let mut srcs = Vec::<SrcBlk>::new();
91        Self::INPUTS.iter().for_each(|entry| {
92            let offset = match entry.id {
93                SrcBlkId::Adat => srcs.iter().filter(|&s| s.id.eq(&entry.id)).count() as u8,
94                _ => entry.offset,
95            };
96            let count = match entry.id {
97                SrcBlkId::Adat => Self::adat_channel_count(rate_mode),
98                _ => entry.count,
99            };
100            (offset..(offset + count)).for_each(|ch| {
101                srcs.push(SrcBlk { id: entry.id, ch });
102            });
103        });
104
105        let mut dsts = Vec::<DstBlk>::new();
106        Self::OUTPUTS.iter().for_each(|entry| {
107            let offset = match entry.id {
108                DstBlkId::Adat => dsts.iter().filter(|d| d.id.eq(&entry.id)).count() as u8,
109                _ => entry.offset,
110            };
111            let count = match entry.id {
112                DstBlkId::Adat => Self::adat_channel_count(rate_mode),
113                _ => entry.count,
114            };
115            (offset..(offset + count)).for_each(|ch| {
116                dsts.push(DstBlk { id: entry.id, ch });
117            });
118        });
119
120        (srcs, dsts)
121    }
122
123    /// Compute available destination and source blocks for Tx/Rx streams.
124    fn compute_avail_stream_blk_pair(
125        tx_entries: &[FormatEntry],
126        rx_entries: &[FormatEntry],
127    ) -> (Vec<SrcBlk>, Vec<DstBlk>) {
128        let dst_blk_list = tx_entries
129            .iter()
130            .zip([DstBlkId::Avs0, DstBlkId::Avs1])
131            .map(|(entry, id)| (0..entry.pcm_count).map(move |ch| DstBlk { id, ch }))
132            .flatten()
133            .collect();
134
135        let src_blk_list = rx_entries
136            .iter()
137            .zip([SrcBlkId::Avs0, SrcBlkId::Avs1])
138            .map(|(entry, id)| (0..entry.pcm_count).map(move |ch| SrcBlk { id, ch }))
139            .flatten()
140            .collect();
141
142        (src_blk_list, dst_blk_list)
143    }
144
145    /// Compute available destination and source blocks for mixer inputs and outputs.
146    fn compute_avail_mixer_blk_pair(
147        caps: &ExtensionCaps,
148        rate_mode: RateMode,
149    ) -> (Vec<SrcBlk>, Vec<DstBlk>) {
150        let port_count = std::cmp::min(
151            caps.mixer.output_count,
152            Self::mixer_out_port_count(rate_mode),
153        );
154
155        let id = SrcBlkId::Mixer;
156        let src_blk_list = (0..port_count).map(move |ch| SrcBlk { id, ch }).collect();
157
158        let dst_blk_list = Self::MIXER_IN_PORTS
159            .iter()
160            .flat_map(|&(id, count)| (0..count).map(move |ch| DstBlk { id, ch }))
161            .take(caps.mixer.input_count as usize)
162            .collect();
163
164        (src_blk_list, dst_blk_list)
165    }
166
167    /// Refine router entries by defined descriptors.
168    fn refine_router_entries(
169        entries: &mut Vec<RouterEntry>,
170        avail_blocks: &Tcd22xxAvailableBlocks,
171    ) {
172        entries.retain(|entry| {
173            avail_blocks
174                .0
175                .iter()
176                .find(|src| entry.src.eq(src))
177                .is_some()
178        });
179        entries.retain(|entry| {
180            avail_blocks
181                .1
182                .iter()
183                .find(|dst| entry.dst.eq(dst))
184                .is_some()
185        });
186        Self::FIXED.iter().enumerate().for_each(|(i, &src)| {
187            match entries.iter().position(|entry| entry.src.eq(&src)) {
188                Some(pos) => entries.swap(i, pos),
189                None => {
190                    let dst = DstBlk {
191                        id: DstBlkId::Reserved(0xff),
192                        ch: 0xff,
193                    };
194                    entries.insert(
195                        i,
196                        RouterEntry {
197                            dst,
198                            src,
199                            ..Default::default()
200                        },
201                    )
202                }
203            }
204        });
205    }
206}
207
208/// Operation specific to TCD22xx.
209pub trait Tcd22xxOperation:
210    Tcd22xxSpecification
211    + TcatExtensionCommandSectionOperation
212    + TcatExtensionSectionParamsOperation<CurrentStreamFormatParams>
213    + TcatExtensionSectionWholeMutableParamsOperation<RouterParams>
214{
215    /// Detect available source and destination blocks at given rate mode.
216    fn detect_available_blocks(
217        req: &FwReq,
218        node: &FwNode,
219        sections: &ExtensionSections,
220        caps: &ExtensionCaps,
221        rate_mode: RateMode,
222        avail_blocks: &mut Tcd22xxAvailableBlocks,
223        timeout_ms: u32,
224    ) -> Result<(), Error> {
225        let real_blk_pair = Self::compute_avail_real_blk_pair(rate_mode);
226
227        let pair = StreamFormatParams {
228            tx_entries: Vec::with_capacity(caps.general.max_tx_streams as usize),
229            rx_entries: Vec::with_capacity(caps.general.max_rx_streams as usize),
230        };
231        let mut params = CurrentStreamFormatParams { pair, rate_mode };
232        Self::cache_extension_whole_params(req, node, sections, caps, &mut params, timeout_ms)?;
233        let stream_blk_pair =
234            Self::compute_avail_stream_blk_pair(&params.pair.tx_entries, &params.pair.rx_entries);
235
236        let mixer_blk_pair = Self::compute_avail_mixer_blk_pair(caps, rate_mode);
237
238        avail_blocks.0 = real_blk_pair
239            .0
240            .iter()
241            .chain(&stream_blk_pair.0)
242            .chain(&mixer_blk_pair.0)
243            .copied()
244            .collect();
245
246        avail_blocks.1 = real_blk_pair
247            .1
248            .iter()
249            .chain(&stream_blk_pair.1)
250            .chain(&mixer_blk_pair.1)
251            .copied()
252            .collect();
253
254        Ok(())
255    }
256
257    /// Update router entries.
258    fn update_router_entries(
259        req: &FwReq,
260        node: &FwNode,
261        sections: &ExtensionSections,
262        caps: &ExtensionCaps,
263        rate_mode: RateMode,
264        avail_blocks: &Tcd22xxAvailableBlocks,
265        params: &mut RouterParams,
266        timeout_ms: u32,
267    ) -> Result<(), Error> {
268        Self::refine_router_entries(&mut params.0, avail_blocks);
269        if params.0.len() > caps.router.maximum_entry_count as usize {
270            let msg = format!(
271                "The number of entries for router section should be less than {} but {}",
272                caps.router.maximum_entry_count,
273                params.0.len()
274            );
275            Err(Error::new(ProtocolExtensionError::Router, &msg))?
276        }
277
278        Self::update_extension_whole_params(req, node, sections, caps, params, timeout_ms)?;
279        Self::initiate(
280            req,
281            node,
282            sections,
283            caps,
284            Opcode::LoadRouter(rate_mode),
285            timeout_ms,
286        )?;
287
288        Ok(())
289    }
290
291    /// Load configuration from on-board flash memory, including parameters in application section.
292    fn load_configuration(
293        req: &FwReq,
294        node: &FwNode,
295        sections: &ExtensionSections,
296        caps: &ExtensionCaps,
297        timeout_ms: u32,
298    ) -> Result<(), Error> {
299        Self::initiate(
300            req,
301            node,
302            sections,
303            caps,
304            Opcode::LoadConfigFromFlash,
305            timeout_ms,
306        )
307        .map(|_| ())
308    }
309
310    /// Store configuration to on-board flash memory, including parameters in application section.
311    fn store_configuration(
312        req: &FwReq,
313        node: &FwNode,
314        sections: &ExtensionSections,
315        caps: &ExtensionCaps,
316        timeout_ms: u32,
317    ) -> Result<(), Error> {
318        Self::initiate(
319            req,
320            node,
321            sections,
322            caps,
323            Opcode::StoreConfigToFlash,
324            timeout_ms,
325        )
326        .map(|_| ())
327    }
328}
329
330impl<O> Tcd22xxOperation for O where
331    O: Tcd22xxSpecification
332        + TcatExtensionCommandSectionOperation
333        + TcatExtensionSectionParamsOperation<CurrentStreamFormatParams>
334        + TcatExtensionSectionWholeMutableParamsOperation<RouterParams>
335{
336}