[audio][sherlock] Add L+R HW mixing for woofer

Note that this does not imply frequency filtering.

Test: audio uapp and manually crafted input checked on a scope.
Change-Id: I772b28cb21b0ae01d7a4bb3ffcebca06651de83b
diff --git a/system/dev/audio/astro-tdm-output/audio-stream-out.cpp b/system/dev/audio/astro-tdm-output/audio-stream-out.cpp
index e71852c..3620891 100644
--- a/system/dev/audio/astro-tdm-output/audio-stream-out.cpp
+++ b/system/dev/audio/astro-tdm-output/audio-stream-out.cpp
@@ -77,8 +77,8 @@
 
     // Setup TDM.
 
-    // 3 bitoffset, 4 slots, 32 bits/slot, 16 bits/sample.
-    aml_audio_->ConfigTdmOutSlot(3, 3, 31, 15);
+    // 3 bitoffset, 4 slots, 32 bits/slot, 16 bits/sample, no mixing.
+    aml_audio_->ConfigTdmOutSlot(3, 3, 31, 15, 0);
 
     // Lane0 right channel.
     aml_audio_->ConfigTdmOutSwaps(0x00000010);
diff --git a/system/dev/audio/sherlock-tdm-output/audio-stream-out.cpp b/system/dev/audio/sherlock-tdm-output/audio-stream-out.cpp
index 1927e85..586700a 100644
--- a/system/dev/audio/sherlock-tdm-output/audio-stream-out.cpp
+++ b/system/dev/audio/sherlock-tdm-output/audio-stream-out.cpp
@@ -13,8 +13,9 @@
 namespace audio {
 namespace sherlock {
 
-// Expects L tweeter + R tweeter + Woofer.
-constexpr size_t kNumberOfChannels = 3;
+// Expects L+R for tweeters + L+R for the 1 Woofer (mixed in HW).
+// The user must perform crossover filtering on these channels.
+constexpr size_t kNumberOfChannels = 4;
 // Calculate ring buffer size for 1 second of 16-bit, 48kHz.
 constexpr size_t kRingBufferSize = fbl::round_up<size_t, size_t>(48000 * 2 * kNumberOfChannels,
                                                                  PAGE_SIZE);
@@ -98,19 +99,20 @@
     // data lines  (ConfigTdmOutSlot bitoffset=4 below accomplishes this).
     // -3072MHz/64 = 48KHz.
 
-    // 4 bitoffset, 2 slots, 32 bits/slot, 16 bits/sample.
-    aml_audio_->ConfigTdmOutSlot(4, 1, 31, 15);
+    // 4 bitoffset, 2 slots, 32 bits/slot, 16 bits/sample, enable mix L+R on lane 1.
+    aml_audio_->ConfigTdmOutSlot(4, 1, 31, 15, (1 << 1));
 
-    // Lane 0 left channel set to FRDDR slot 0.
-    // Lane 0 right channel set to FRDDR slot 1.
-    // Lane 1 left channel set to FRDDR slot 2.
-    aml_audio_->ConfigTdmOutSwaps(0x00000210);
+    // Lane 0 L channel set to FRDDR slot 0.
+    // Lane 0 R channel set to FRDDR slot 1.
+    // Lane 1 L channel set to FRDDR slot 2.  Mixed with R, see ConfigTdmOutSlot above.
+    // Lane 1 R channel set to FRDDR slot 3.  Mixed with L, see ConfigTdmOutSlot above.
+    aml_audio_->ConfigTdmOutSwaps(0x00003210);
 
     // Tweeters: Lane 0, unmask TDM slots 0 & 1 (L+R FRDDR slots 0 & 1).
     aml_audio_->ConfigTdmOutLane(0, 0x00000003);
 
-    // Woofer: Lane 1, unmask TDM slot 0 (Woofer FRDDR slot 2).
-    aml_audio_->ConfigTdmOutLane(1, 0x00000001);
+    // Woofer: Lane 1, unmask TDM slot 0 & 1 (Woofer FRDDR slots 2 & 3).
+    aml_audio_->ConfigTdmOutLane(1, 0x00000003);
 
     // mclk = T931_HIFI_PLL_RATE/125 = 1536MHz/125 = 12.288MHz.
     aml_audio_->SetMclkDiv(124);
diff --git a/system/dev/lib/amlogic/aml-tdm-audio.cpp b/system/dev/lib/amlogic/aml-tdm-audio.cpp
index fe67ec5..56cdd95 100644
--- a/system/dev/lib/amlogic/aml-tdm-audio.cpp
+++ b/system/dev/lib/amlogic/aml-tdm-audio.cpp
@@ -71,6 +71,11 @@
     //Value to be inserted in a slot if it is masked
     mmio_.Write32(0x00000000, GetTdmOffset(TDMOUT_MASK_VAL_OFFS));
 
+    mmio_.Write32(0x00000000, GetTdmOffset(TDMOUT_MUTE0_OFFS)); // Disable lane 0 muting.
+    mmio_.Write32(0x00000000, GetTdmOffset(TDMOUT_MUTE1_OFFS)); // Disable lane 1 muting.
+    mmio_.Write32(0x00000000, GetTdmOffset(TDMOUT_MUTE2_OFFS)); // Disable lane 2 muting.
+    mmio_.Write32(0x00000000, GetTdmOffset(TDMOUT_MUTE3_OFFS)); // Disable lane 3 muting.
+
     // Datasheets state that PAD_CTRL1 controls sclk and lrclk source selection (which mclk),
     // it does this per pad (0, 1, 2).  These pads are tied to the TDM channel in use
     // (this is not specified in the datasheets but confirmed empirically) such that TDM_OUT_A
@@ -175,11 +180,13 @@
     num_slots - number of slots per frame minus one
     bits_per_slot - width of each slot minus one
     bits_per_sample - number of bits in sample minus one
+    mix_mask - lanes to mix L+R.
 */
 void AmlTdmDevice::ConfigTdmOutSlot(uint8_t bit_offset, uint8_t num_slots,
-                                    uint8_t bits_per_slot, uint8_t bits_per_sample) {
+                                    uint8_t bits_per_slot, uint8_t bits_per_sample,
+                                    uint8_t mix_mask) {
 
-    uint32_t reg = bits_per_slot | (num_slots << 5) | (bit_offset << 15);
+    uint32_t reg = bits_per_slot | (num_slots << 5) | (bit_offset << 15) | (mix_mask << 20);
     mmio_.Write32(reg, GetTdmOffset(TDMOUT_CTRL0_OFFS));
 
     reg = (bits_per_sample << 8) | (frddr_ch_ << 24);
@@ -187,7 +194,7 @@
         // 8 bit sample, left justify in frame, split 64-bit dma fetch into 8 samples
         reg |= (0 << 4);
     } else if (bits_per_sample <= 16) {
-        // 16 bit sample, left justify in frame, split 64-bit dma fetch into 2 samples
+        // 16 bit sample, left justify in frame, split 64-bit dma fetch into 4 samples
         reg |= (2 << 4);
     } else {
         // 32/24 bit sample, left justify in slot, split 64-bit dma fetch into 2 samples
diff --git a/system/dev/lib/amlogic/include/soc/aml-common/aml-tdm-audio.h b/system/dev/lib/amlogic/include/soc/aml-common/aml-tdm-audio.h
index 40f864d..165a668 100644
--- a/system/dev/lib/amlogic/include/soc/aml-common/aml-tdm-audio.h
+++ b/system/dev/lib/amlogic/include/soc/aml-common/aml-tdm-audio.h
@@ -35,8 +35,8 @@
     zx_status_t SetMClkPad(aml_tdm_mclk_pad_t mclk_pad);
 
     // Configures placement of data on the tdm bus
-    void ConfigTdmOutSlot(uint8_t bit_offset, uint8_t num_slots,
-                          uint8_t bits_per_slot, uint8_t bits_per_sample);
+    void ConfigTdmOutSlot(uint8_t bit_offset, uint8_t num_slots, uint8_t bits_per_slot,
+                          uint8_t bits_per_sample, uint8_t mix_mask);
 
     // Configures Lanes.
     zx_status_t ConfigTdmOutLane(size_t lane, uint32_t mask);