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