1// Copyright 2018 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <digest/digest.h>
6#include <fbl/algorithm.h>
7#include <fbl/alloc_checker.h>
8#include <fbl/limits.h>
9#include <soc/aml-s912/s912-audio.h>
10
11#include "hdmitx.h"
12#include "vim-display.h"
13#include "vim-spdif-audio-stream.h"
14
15#define SHIFTED_MASK(_name)      ((_name##_MASK) << (_name##_SHIFT))
16#define SHIFTED_VAL(_name, _val) ((_val & _name##_MASK) << _name##_SHIFT)
17#define MOD_FIELD(_name, _val) SHFTED_MASK(_name), SHIFTED_VAL(_name, _val)
18
19namespace audio {
20namespace vim2 {
21
22namespace {
23// 128 bytes per frame.  Why?  I have no idea.  This is clearly not an audio
24// frame, nor is it a SPDIF block.  I suspect that it may be the amount of
25// data which the DMA engine tries to fetch each time it jumps on the bus,
26// but I don't really know for certain.
27constexpr uint32_t AIU_958_BYTES_PER_FRAME = 128;
28
29static const struct {
30    uint32_t rate;
31    uint32_t N;
32} STANDARD_FRAME_RATE_N_LUT[] = {
33    { .rate =  32000, .N =  4096 },
34    { .rate =  48000, .N =  6144 },
35    { .rate =  96000, .N = 12288 },
36    { .rate = 192000, .N = 25467 },
37    { .rate =  44100, .N =  6272 },
38    { .rate =  88200, .N = 12544 },
39    { .rate = 176400, .N = 28028 },
40};
41}   // anon namespace
42
43Vim2SpdifAudioStream::Vim2SpdifAudioStream(const vim2_display* display,
44                                           fbl::RefPtr<Registers> regs,
45                                           fbl::RefPtr<RefCountedVmo> ring_buffer_vmo,
46                                           fzl::PinnedVmo pinned_ring_buffer,
47                                           uint64_t display_id)
48    : SimpleAudioStream(display->parent, false),
49      display_(display),
50      display_id_(display_id),
51      regs_(fbl::move(regs)),
52      ring_buffer_vmo_(fbl::move(ring_buffer_vmo)),
53      pinned_ring_buffer_(fbl::move(pinned_ring_buffer)) {
54}
55
56void Vim2SpdifAudioStream::ShutdownHook() {
57    vim2_display_disable_audio(display_);
58    Disable(*regs_);
59}
60
61void Vim2SpdifAudioStream::RingBufferShutdown() {
62    vim2_display_disable_audio(display_);
63}
64
65zx_status_t Vim2SpdifAudioStream::ChangeFormat(const audio_proto::StreamSetFmtReq& req) {
66    // Figure out the maximum number of audio frames we can fit into our ring
67    // buffer while still guaranteeing...
68    //
69    // 1) The buffer is a multiple of audio frame size
70    // 2) The buffer is a multiple of AIU frame size
71    //
72    ZX_DEBUG_ASSERT(frame_size_ > 0);
73    usable_buffer_size_ = fbl::round_down(static_cast<uint32_t>(pinned_ring_buffer_.region(0).size),
74                                          fbl::lcm(AIU_958_BYTES_PER_FRAME, frame_size_));
75
76    // TODO(johngro): figure out the proper value for this
77    fifo_depth_ = 512;
78
79    // TODO(johngro): fill this out based on the estimate given by EDID (if any)
80    external_delay_nsec_  = 0;
81
82    // Figure out the proper values for N and CTS based on this audio mode and
83    // pixel clock.
84    // Start by going through our table of standard audio modes for standard
85    // audio clocks.  If we cannot find the answer in the LUT, then fall back on
86    // computing the answer on the fly using the recommended N as a starting
87    // point to compute CTS.
88    //
89    // See section 7.2 (Audio Sample Clock Capture and Regeneration) of the HDMI
90    // 1.3a spec (or later) for details.
91    uint32_t N = 0;
92    for (const auto& entry : STANDARD_FRAME_RATE_N_LUT) {
93        if (entry.rate == req.frames_per_second) {
94            N = entry.N;
95            break;
96        }
97    }
98
99    // This should never happen (As we are not advertising any frame rates which
100    // are not in the LUT), but JiC.
101    if (!N) {
102        zxlogf(ERROR, "Failed to find starting N value for audio frame rate (%u).\n",
103               req.frames_per_second);
104        return ZX_ERR_NOT_SUPPORTED;
105    }
106
107    // Given our suggested starting value for N, CTS should be computed as...
108    //
109    // CTS = pixel_clock * N / (128 * audio_frame_rate)
110    //
111    // Since our pixel clock is already expressed in KHz, this becomes
112    // CTS = pkhz * N * 1000 / (128 * audio_frame_rate)
113    //     = pkhz * N * 125  / (16 * audio_frame_rate)
114    //
115    // If our numerator is not divisible by 16 * frame_rate, then we would (in
116    // theory) need to dither the N/CTS values being sent, which is something we
117    // currently do not support.  For now, if this happens, return an error
118    // instead.
119    uint64_t numer = static_cast<uint64_t>(display_->p->timings.pfreq) * N * 125;
120    uint32_t denom = req.frames_per_second << 4;
121
122    if (numer % denom) {
123        zxlogf(ERROR, "Failed to find CTS value (pclk %u, N %u, frame_rate %u)\n",
124               display_->p->timings.pfreq, N, req.frames_per_second);
125        return ZX_ERR_NOT_SUPPORTED;
126    }
127
128    uint32_t CTS = static_cast<uint32_t>(numer / denom);
129    uint32_t bits_per_sample;
130    switch (req.sample_format) {
131    case AUDIO_SAMPLE_FORMAT_16BIT:         bits_per_sample = 16; break;
132    case AUDIO_SAMPLE_FORMAT_24BIT_PACKED:  __FALLTHROUGH;
133    case AUDIO_SAMPLE_FORMAT_24BIT_IN32:    bits_per_sample = 24; break;
134    default:
135        zxlogf(ERROR, "Unsupported requested sample format (0x%08x)!\n", req.sample_format);
136        return ZX_ERR_NOT_SUPPORTED;
137    }
138
139    // Set up the registers to match our format choice.
140    SetMode(req.frames_per_second, req.sample_format);
141
142    // Tell the HDMI driver about the mode we just configured.
143    zx_status_t res;
144    res = vim2_display_configure_audio_mode(display_,
145                                            N, CTS,
146                                            req.frames_per_second, bits_per_sample);
147    if (res != ZX_OK) {
148        zxlogf(ERROR, "Failed to configure VIM2 HDMI TX audio parameters! (res %d)\n", res);
149        return res;
150    }
151
152    return ZX_OK;
153}
154
155zx_status_t Vim2SpdifAudioStream::GetBuffer(const audio_proto::RingBufGetBufferReq& req,
156                                            uint32_t* out_num_rb_frames,
157                                            zx::vmo* out_buffer) {
158    uint32_t rb_frames = usable_buffer_size_ / frame_size_;
159    if (req.min_ring_buffer_frames > rb_frames) {
160        return ZX_ERR_OUT_OF_RANGE;
161    }
162
163    constexpr uint32_t rights = ZX_RIGHT_READ | ZX_RIGHT_WRITE | ZX_RIGHT_MAP | ZX_RIGHT_TRANSFER;
164    zx_status_t res = ring_buffer_vmo_->vmo().duplicate(rights, out_buffer);
165    if (res != ZX_OK) {
166        return res;
167    }
168
169    *out_num_rb_frames = rb_frames;
170    SetupBuffer();
171    return ZX_OK;
172}
173
174zx_status_t Vim2SpdifAudioStream::Start(uint64_t* out_start_time) {
175    uint64_t a, b;
176
177    Mute(cur_gain_state_.cur_mute);
178    a = zx_clock_get(ZX_CLOCK_MONOTONIC);
179    Enable();
180    b = zx_clock_get(ZX_CLOCK_MONOTONIC);
181    *out_start_time = ((b - a) >> 1) + a;
182
183    return ZX_OK;
184}
185
186zx_status_t Vim2SpdifAudioStream::Stop() {
187    Disable(*regs_);
188    Mute(false);
189    return ZX_OK;
190}
191
192zx_status_t Vim2SpdifAudioStream::SetGain(const audio_proto::SetGainReq& req) {
193    if (req.flags & AUDIO_SGF_MUTE_VALID) {
194        cur_gain_state_.cur_mute = ((req.flags & AUDIO_SGF_MUTE) != 0);
195        Mute(cur_gain_state_.cur_mute);
196    }
197
198    return ZX_OK;
199}
200
201zx_status_t Vim2SpdifAudioStream::Init() {
202    zx_status_t res;
203
204    if (!regs_ || !regs_->valid()) {
205        zxlogf(ERROR, "null or invalid registers in %s\n", __PRETTY_FUNCTION__);
206        return ZX_ERR_INVALID_ARGS;
207    }
208
209    Disable(*regs_);
210
211    if (!ring_buffer_vmo_ || !ring_buffer_vmo_->vmo().is_valid()) {
212        zxlogf(ERROR, "Bad ring buffer VMO passed to %s\n", __PRETTY_FUNCTION__);
213        return ZX_ERR_INVALID_ARGS;
214    }
215
216    // Set up the DMA addresses.
217    if ((pinned_ring_buffer_.region_count() != 1) ||
218        (pinned_ring_buffer_.region(0).size < PAGE_SIZE) ||
219       ((pinned_ring_buffer_.region(0).phys_addr + pinned_ring_buffer_.region(0).size)
220        >= fbl::numeric_limits<uint32_t>::max())) {
221        zxlogf(ERROR, "Bad ring buffer scatter/gather list passed to %s\n", __PRETTY_FUNCTION__);
222        return ZX_ERR_INVALID_ARGS;
223    }
224
225    res = CreateFormatList();
226    if (res != ZX_OK) {
227        return res;
228    }
229
230    // Set our gain capabilities.
231    cur_gain_state_.cur_gain = 0.0;
232    cur_gain_state_.cur_mute = false;
233    cur_gain_state_.cur_agc  = false;
234
235    cur_gain_state_.min_gain = 0.0;
236    cur_gain_state_.max_gain = 0.0;
237    cur_gain_state_.gain_step = 0.0;
238    cur_gain_state_.can_mute = true;
239    cur_gain_state_.can_agc  = false;
240
241    // Set our device node name.
242    snprintf(device_name_, sizeof(device_name_), "vim2-spdif-out");
243
244    // Create our unique ID by hashing portions of the EDID we get from our
245    // display.  In particular, look for and hash...
246    //
247    // 1) The vendor/product ID.
248    // 2) The first monitor descriptor, if present.
249    // 3) The monitor serial number, if present.
250    //
251    // We deliberately do not simply hash contents the entire EDID.  Timing
252    // and other configuration information can change, esp. when a device is
253    // connected to an AV receiver and changes are made to the processing
254    // configuration of the AVR.  We want to focus on attempting to identify the
255    // device we are connected to, and not the mode that it is operating in.
256    //
257    // While we are parsing this information, also extract the manufacturer name
258    // (from the vendor/product ID section), and the device name (from the first
259    // monitor descriptor, if present).
260    //
261    // TODO(johngro): Someday, when this gets split into separate DAI/Codec
262    // drivers, this code belongs in the HDMI codec section of things.
263    digest::Digest sha;
264    res = sha.Init();
265    if (res != ZX_OK) {
266        zxlogf(WARN, "Failed to initialize digest while computing unique ID.  (res %d)\n", res);
267        return res;
268    }
269
270    // Seed our SHA with a constant number taken from 'uuidgen'.
271    static const uint8_t SEED[] = { 0xd8, 0x27, 0x52, 0xb7, 0x60, 0x9a, 0x46, 0xd4,
272                                    0xa6, 0xc4, 0xdc, 0x32, 0xf5, 0xce, 0x1b, 0x7d };
273    sha.Update(SEED, sizeof(SEED));
274
275    snprintf(mfr_name_, sizeof(mfr_name_), "%s",
276             strlen(display_->manufacturer_name) ? display_->manufacturer_name : "<unknown>");
277    snprintf(prod_name_, sizeof(prod_name_), "%s",
278             strlen(display_->monitor_name) ? display_->monitor_name : "Generic HDMI");
279
280    sha.Update(mfr_name_, strnlen(mfr_name_, sizeof(mfr_name_)));
281    sha.Update(prod_name_, strnlen(prod_name_, sizeof(prod_name_)));
282    sha.Update(display_->monitor_serial,
283               strnlen(display_->monitor_serial, sizeof(display_->monitor_serial)));
284
285    // Finish the SHA and attempt to copy as much of the results to our internal
286    // cached representation as we can.
287    uint8_t digest_out[digest::Digest::kLength];
288    sha.Final();
289    res = sha.CopyTo(digest_out, sizeof(digest_out));
290    if (res != ZX_OK) {
291        zxlogf(ERROR, "Failed to copy digest while computing unique ID.  (res %d)", res);
292        return res;
293    }
294    ::memset(unique_id_.data, 0, sizeof(unique_id_.data));
295    ::memcpy(unique_id_.data, digest_out, fbl::min(sizeof(digest_out), sizeof(unique_id_.data)));
296
297    return ZX_OK;
298}
299
300void Vim2SpdifAudioStream::Disable(const Registers& regs) {
301    ZX_DEBUG_ASSERT(regs.valid());
302
303    regs[AIU_958_DCU_FF_CTRL] = 0; // Disable the FIFO
304    regs.ClrBits(AIU_MEM_IEC958_CONTROL,
305                 AIU_958_MCTRL_FILL_ENB | AIU_958_MCTRL_EMPTY_ENB); // Disable the DMA
306    regs[AIU_RST_SOFT] = AIU_RS_958_FAST_DOMAIN; // reset the unit
307}
308
309zx_status_t Vim2SpdifAudioStream::CreateFormatList() {
310    // Compute the list of audio formats that we support.  To do this, we need
311    // to intersect the capabilities of the display sink we are connect to, with
312    // the capabilities of the S912 audio hardware.
313    //
314    // The DesignWare HDMI transmitter which is integrated into the S912 can be
315    // fed a couple of different ways; either from one or more I2S units acting
316    // in parallel, or one or more SPDIF units acting in parallel.  Each unit
317    // can carry up to 2 channels of audio.  The DesignWare block also has
318    // options to synthesize its own independent DMA engine (which would have
319    // been super convenient), but these features were not enabled when the S912
320    // was synthesized.
321    //
322    // The S912 has only 1 SPDIF unit (as well as only one I2S unit), which
323    // limits our maximum number of channels to 2.
324    //
325    // In addition, the way that the clocks are being set up on VIM2, there is
326    // no factor of 7 in the clock feeding the audio units.  Because of this, we
327    // cannot generate any of the 44.1k family of audio rates.  We can, however,
328    // generate clock rates up to 192KHz, and can generate 16, 20, and 24 bit audio.
329    for (unsigned i = 0; i < display_->audio_format_count; i++) {
330        audio_stream_format_range_t range;
331        zx_status_t status = display_->dc_cb->get_audio_format(
332                display_->dc_cb_ctx, display_->display_id, i, &range);
333        ZX_ASSERT(status == ZX_OK);
334
335        constexpr uint32_t SUPPORTED_FORMATS = AUDIO_SAMPLE_FORMAT_16BIT |
336                AUDIO_SAMPLE_FORMAT_24BIT_PACKED | AUDIO_SAMPLE_FORMAT_24BIT_IN32;
337        range.sample_formats =
338                static_cast<audio_sample_format_t>(range.sample_formats & SUPPORTED_FORMATS);
339        if (range.sample_formats == 0) {
340            continue;
341        }
342
343        // Require stereo
344        if (range.max_channels <  2) {
345            continue;
346        }
347        range.max_channels = fbl::min<uint8_t>(range.max_channels, 2);
348
349        constexpr uint32_t MIN_SUPPORTED_RATE = 32000;
350        constexpr uint32_t MAX_SUPPORTED_RATE = 192000;
351        range.flags &= ASF_RANGE_FLAG_FPS_48000_FAMILY;
352        if (range.flags == 0
353                || range.max_frames_per_second < MIN_SUPPORTED_RATE
354                || range.min_frames_per_second > MAX_SUPPORTED_RATE) {
355            continue;
356        }
357        range.max_frames_per_second = fbl::min(MAX_SUPPORTED_RATE, range.max_frames_per_second);
358        range.min_frames_per_second = fbl::max(MIN_SUPPORTED_RATE, range.min_frames_per_second);
359
360        fbl::AllocChecker ac;
361        supported_formats_.push_back(range, &ac);
362        if (!ac.check()) {
363            zxlogf(ERROR, "Out of memory attempting to construct supported format list.\n");
364            return ZX_ERR_NO_MEMORY;
365        }
366    }
367
368    return ZX_OK;
369}
370
371void Vim2SpdifAudioStream::Enable() {
372    ZX_DEBUG_ASSERT((regs_ != nullptr) && regs_->valid());
373    const auto& regs = *regs_;
374
375    regs[AIU_RST_SOFT] = AIU_RS_958_FAST_DOMAIN;   // reset
376
377    // Force the next sample fetched from the FIFO to be the start of a
378    // frame by writing *any* value to the FORCE_LEFT register.
379    //
380    // Note: In the AmLogic documentation I have access to,  this register is
381    // actually missing from the documentation (but mentioned briefly in the
382    // discussion of bit 13 of AIU_958_MISC).  Notes left by the AM Logic driver
383    // author in other codebases seem to say that when the SPDIF serializer has
384    // been reset, that whether or not the next payload is supposed to be a left
385    // or right sample does not actually get reset.  In order to get a proper
386    // sequence of marker bits transmitted, we are supposed to use the
387    // FORCE_LEFT register to reset this state as well any time we reset the
388    // SPDIF TX unit.
389    regs[AIU_958_FORCE_LEFT] = 0x00;
390
391    regs.SetBits(AIU_MEM_IEC958_CONTROL,
392                 AIU_958_MCTRL_FILL_ENB | AIU_958_MCTRL_EMPTY_ENB);   // Enable the DMA
393    regs.SetBits(AIU_958_DCU_FF_CTRL, AIU_958_DCU_FF_CTRL_ENB);       // Enable the fifo
394}
395
396void Vim2SpdifAudioStream::SetupBuffer() {
397    ZX_DEBUG_ASSERT((regs_ != nullptr) && regs_->valid());
398    const auto& regs = *regs_;
399
400    // Set up the DMA addresses.
401    ZX_DEBUG_ASSERT(pinned_ring_buffer_.region_count() == 1);
402    ZX_DEBUG_ASSERT(pinned_ring_buffer_.region(0).size >= 8);
403    ZX_DEBUG_ASSERT((pinned_ring_buffer_.region(0).phys_addr +
404                     pinned_ring_buffer_.region(0).size - 1)
405                    <= fbl::numeric_limits<uint32_t>::max());
406
407    const auto& r = pinned_ring_buffer_.region(0);
408    ZX_DEBUG_ASSERT(usable_buffer_size_ >= AIU_958_BYTES_PER_FRAME);
409    ZX_DEBUG_ASSERT(usable_buffer_size_ <= r.size);
410    regs[AIU_MEM_IEC958_START_PTR] = static_cast<uint32_t>(r.phys_addr);
411    regs[AIU_MEM_IEC958_RD_PTR]    = static_cast<uint32_t>(r.phys_addr);
412    regs[AIU_MEM_IEC958_END_PTR]   = static_cast<uint32_t>(r.phys_addr + usable_buffer_size_ - 8);
413
414    // Set the masks register to all channels present, and to read from all
415    // channels.  Apparently, this is the thing to do when we are operating in
416    // "split mode"
417    regs[AIU_MEM_IEC958_MASKS] = 0xFFFF;
418
419    // Now that the buffer has been set up, perform some register writes to the
420    // CONTROL and BUF_CONTROL registers in order complete the setup.
421    //
422    // Exactly what this is accomplishing is something of a mystery.
423    // Documentation for bit 0 of the MEM_CONTROL register consists of "bit 0:
424    // cntl_init".  Documentation for the low 16 bits of the BUF_CNTL register
425    // consists of "bits [0:15]: level_hold".  Why we need to follow this
426    // sequence, or what it is accomplishing, is not documented.
427    //
428    // This sequence is here right now because it is done by the driver written
429    // by AmLogic's engineer(s) in other code bases.  They provide no
430    // real explanation for what is going on here either; so for now, this
431    // remains nothing but cargo-cult garbage.
432    regs.SetBits(AIU_MEM_IEC958_CONTROL, AIU_958_MCTRL_INIT);
433    regs.ClrBits(AIU_MEM_IEC958_CONTROL, AIU_958_MCTRL_INIT);
434    regs[AIU_MEM_IEC958_BUF_CNTL] = 1;
435    regs[AIU_MEM_IEC958_BUF_CNTL] = 0;
436}
437
438void Vim2SpdifAudioStream::SetMode(uint32_t frame_rate, audio_sample_format_t fmt) {
439    ZX_DEBUG_ASSERT((regs_ != nullptr) && regs_->valid());
440    const auto& regs = *regs_;
441
442    // Look up our frame rate to figure out our clock divider and channel status
443    // bit.  Note: clock divider values are based on a reference frame rate of
444    // 192KHz
445    static const struct {
446        uint32_t frame_rate;
447        uint32_t div_bits;
448        uint32_t ch_status_bits;
449    } RATE_LUT[] = {
450        { .frame_rate = 32000,
451          .div_bits = SHIFTED_VAL(AIU_CLK_CTRL_958_DIV, 2u) | AIU_CLK_CTRL_958_DIV_MORE,
452          .ch_status_bits = SPDIF_CS_SAMP_FREQ_32K
453        },
454        { .frame_rate = 48000,
455          .div_bits = SHIFTED_VAL(AIU_CLK_CTRL_958_DIV, 3u),
456          .ch_status_bits = SPDIF_CS_SAMP_FREQ_48K
457        },
458        { .frame_rate = 96000,
459          .div_bits = SHIFTED_VAL(AIU_CLK_CTRL_958_DIV, 1u),
460          .ch_status_bits = SPDIF_CS_SAMP_FREQ_96K
461        },
462        { .frame_rate = 192000,
463          .div_bits = SHIFTED_VAL(AIU_CLK_CTRL_958_DIV, 0u),
464          .ch_status_bits = SPDIF_CS_SAMP_FREQ_192K
465        },
466    };
467
468    uint32_t rate_ndx;
469    for (rate_ndx = 0; rate_ndx < fbl::count_of(RATE_LUT); ++rate_ndx) {
470        if (RATE_LUT[rate_ndx].frame_rate == frame_rate) {
471            break;
472        }
473    }
474
475    // The requested frame rate should already have been validated by the code
476    // before us.  If something has gone terribly wrong, log a warning and
477    // default to 48K.
478    if (rate_ndx >= fbl::count_of(RATE_LUT)) {
479        constexpr uint32_t DEFAULT_RATE_NDX = 1;
480        zxlogf(WARN, "Failed to find requested frame rate (%u) in LUT!  Defaulting to 48000\n",
481               frame_rate);
482        static_assert(DEFAULT_RATE_NDX < fbl::count_of(RATE_LUT), "Invalid default rate index!");
483        rate_ndx = DEFAULT_RATE_NDX;
484    }
485
486    const auto& RATE = RATE_LUT[rate_ndx];
487
488    // Now go ahead and set up the clock divider.
489    constexpr uint32_t DIV_MASK = SHIFTED_MASK(AIU_CLK_CTRL_958_DIV) | AIU_CLK_CTRL_958_DIV_MORE;
490    regs.ModBits(AIU_CLK_CTRL, DIV_MASK, RATE.div_bits);
491
492    // Send a 0 for the V bit in each frame.  This indicates that the audio is
493    // "valid", at least from a PCM perspective.  When packing compressed audio
494    // into a SPDIF transport, apparently the thing to do is set the V bit to 1
495    // in order to prevent older SPDIF receivers from treating the data like PCM
496    // and breaking your ears.
497    regs[AIU_958_VALID_CTRL] = AIU_958_VCTRL_SEND_VBIT;
498
499    // TODO(johngro): Should the bytes per frame vary based on the size of an
500    // audio frame?  In particular, should the bytes per frame be an integer
501    // multiple of the audio frame size?
502    regs[AIU_958_BPF] = AIU_958_BYTES_PER_FRAME;
503
504    // TODO(johngro): Provide some way to change the category code.  Shipping
505    // products should not be sending "experimental" as their category code.
506    constexpr uint32_t CH_STATUS_BASE = SPDIF_CS_SPDIF_CONSUMER
507                                      | SPDIF_CS_AUD_DATA_PCM
508                                      | SPDIF_CS_COPY_PERMITTED
509                                      | SPDIF_CS_NO_PRE_EMPHASIS
510                                      | SPDIF_CS_CCODE_EXPERIMENTAL
511                                      | SPDIF_CS_CLK_ACC_100PPM;
512    constexpr uint32_t MISC_BASE = AIU_958_MISC_FORCE_LR;
513    constexpr uint32_t MCTRL_BASE = AIU_958_MCTRL_LINEAR_RAW
514                                  | SHIFTED_VAL(AIU_958_MCTRL_ENDIAN, 0u);
515
516    uint32_t ch_status = CH_STATUS_BASE | RATE.ch_status_bits;
517    uint32_t misc = MISC_BASE;
518    uint32_t mctrl = MCTRL_BASE;
519
520    // TODO(johngro): Figure out how to get to bits >= 32 in the channel status
521    // word.  In theory, we can use bits [32, 35] to signal the number of
522    // significant bits in the encoding, as well as to indicate that the
523    // auxiliary bits are carrying audio data instead of aux signalling.
524    switch (fmt) {
525    case AUDIO_SAMPLE_FORMAT_24BIT_PACKED:
526        break;
527
528    // Notes about the 32bit shift field.
529    // The 958_MISC register has a 3-bit field in it whose documentation reads...
530    //
531    // "shift number for 32 bit mode"
532    //
533    // Experimentally, it has been determined that the SPDIF encoder expects
534    // audio to be right justified when sending data from 32 bit containers.
535    // IOW, if a user puts 24 bit samples into a 32 bit container, the SPDIF
536    // encoder expects the samples to be in bits [0, 23].
537    //
538    // If audio is left justified instead (think 32 bit samples with the low
539    // bits zeroed out), the "shift number" bits can be used.  The 32 bit words
540    // will be right shifted by this number of bits for values [0, 6], or 8 bits
541    // to the left when set to the 7.
542    //
543    // TL;DR?  When sending left justified audio in a 32 bit container, set this
544    // field to 7.
545    case AUDIO_SAMPLE_FORMAT_24BIT_IN32:
546        misc |= AIU_958_MISC_32BIT_MODE | SHIFTED_VAL(AIU_958_MISC_32BIT_SHIFT, 7u);
547        break;
548
549    default:
550        zxlogf(WARN, "Unsupported format (0x%08x), defaulting to PCM16\n", fmt);
551        __FALLTHROUGH;
552    case AUDIO_SAMPLE_FORMAT_16BIT:
553        mctrl |= AIU_958_MCTRL_16BIT_MODE;
554        misc  |= AIU_958_MISC_16BIT | SHIFTED_VAL(AIU_958_MISC_16BIT_ALIGN,
555                                                  AIU_958_MISC_16BIT_ALIGN_LEFT);
556        break;
557    }
558
559    regs[AIU_958_CHSTAT_L0] = (ch_status & 0xFFFF);
560    regs[AIU_958_CHSTAT_R0] = (ch_status & 0xFFFF);
561    regs[AIU_958_CHSTAT_L1] = (ch_status >> 16);
562    regs[AIU_958_CHSTAT_R1] = (ch_status >> 16);
563    regs[AIU_958_MISC] = misc;
564    regs[AIU_MEM_IEC958_CONTROL] = mctrl;
565
566    // Set the "level hold" to zero.  I have no idea why.
567    regs.ClrBits(AIU_MEM_IEC958_BUF_CNTL, SHIFTED_MASK(AIU_958_BCTRL_LEVEL_HOLD));
568}
569
570void Vim2SpdifAudioStream::Mute(bool muted) {
571    constexpr uint32_t MUTE_BITS = AIU_958_CTRL_MUTE_LEFT
572                                 | AIU_958_CTRL_MUTE_RIGHT
573                                 | AIU_958_CTRL_FUB_ZERO;
574    const auto& regs = *regs_;
575
576    regs[AIU_958_CTRL] = muted ? MUTE_BITS : 0u;
577}
578
579}  // namespace vim2
580}  // namespace audio
581