18c2ecf20Sopenharmony_ci===============================
28c2ecf20Sopenharmony_ciRealtek PC Beep Hidden Register
38c2ecf20Sopenharmony_ci===============================
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ciThis file documents the "PC Beep Hidden Register", which is present in certain
68c2ecf20Sopenharmony_ciRealtek HDA codecs and controls a muxer and pair of passthrough mixers that can
78c2ecf20Sopenharmony_ciroute audio between pins but aren't themselves exposed as HDA widgets. As far
88c2ecf20Sopenharmony_cias I can tell, these hidden routes are designed to allow flexible PC Beep output
98c2ecf20Sopenharmony_cifor codecs that don't have mixer widgets in their output paths. Why it's easier
108c2ecf20Sopenharmony_cito hide a mixer behind an undocumented vendor register than to just expose it
118c2ecf20Sopenharmony_cias a widget, I have no idea.
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ciRegister Description
148c2ecf20Sopenharmony_ci====================
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ciThe register is accessed via processing coefficient 0x36 on NID 20h. Bits not
178c2ecf20Sopenharmony_ciidentified below have no discernible effect on my machine, a Dell XPS 13 9350::
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci  MSB                           LSB
208c2ecf20Sopenharmony_ci  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
218c2ecf20Sopenharmony_ci  | |h|S|L|         | B |R|       | Known bits
228c2ecf20Sopenharmony_ci  +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
238c2ecf20Sopenharmony_ci  |0|0|1|1|  0x7  |0|0x0|1|  0x7  | Reset value
248c2ecf20Sopenharmony_ci  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci1Ah input select (B): 2 bits
278c2ecf20Sopenharmony_ci  When zero, expose the PC Beep line (from the internal beep generator, when
288c2ecf20Sopenharmony_ci  enabled with the Set Beep Generation verb on NID 01h, or else from the
298c2ecf20Sopenharmony_ci  external PCBEEP pin) on the 1Ah pin node. When nonzero, expose the headphone
308c2ecf20Sopenharmony_ci  jack (or possibly Line In on some machines) input instead. If PC Beep is
318c2ecf20Sopenharmony_ci  selected, the 1Ah boost control has no effect.
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ciAmplify 1Ah loopback, left (L): 1 bit
348c2ecf20Sopenharmony_ci  Amplify the left channel of 1Ah before mixing it into outputs as specified
358c2ecf20Sopenharmony_ci  by h and S bits. Does not affect the level of 1Ah exposed to other widgets.
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ciAmplify 1Ah loopback, right (R): 1 bit
388c2ecf20Sopenharmony_ci  Amplify the right channel of 1Ah before mixing it into outputs as specified
398c2ecf20Sopenharmony_ci  by h and S bits. Does not affect the level of 1Ah exposed to other widgets.
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ciLoopback 1Ah to 21h [active low] (h): 1 bit
428c2ecf20Sopenharmony_ci  When zero, mix 1Ah (possibly with amplification, depending on L and R bits)
438c2ecf20Sopenharmony_ci  into 21h (headphone jack on my machine). Mixed signal respects the mute
448c2ecf20Sopenharmony_ci  setting on 21h.
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ciLoopback 1Ah to 14h (S): 1 bit
478c2ecf20Sopenharmony_ci  When one, mix 1Ah (possibly with amplification, depending on L and R bits)
488c2ecf20Sopenharmony_ci  into 14h (internal speaker on my machine). Mixed signal **ignores** the mute
498c2ecf20Sopenharmony_ci  setting on 14h and is present whenever 14h is configured as an output.
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ciPath diagrams
528c2ecf20Sopenharmony_ci=============
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci1Ah input selection (DIV is the PC Beep divider set on NID 01h)::
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci  <Beep generator>   <PCBEEP pin>    <Headphone jack>
578c2ecf20Sopenharmony_ci          |                |                |
588c2ecf20Sopenharmony_ci          +--DIV--+--!DIV--+       {1Ah boost control}
598c2ecf20Sopenharmony_ci                  |                         |
608c2ecf20Sopenharmony_ci                  +--(b == 0)--+--(b != 0)--+
618c2ecf20Sopenharmony_ci                               |
628c2ecf20Sopenharmony_ci               >1Ah (Beep/Headphone Mic/Line In)<
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ciLoopback of 1Ah to 21h/14h::
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci               <1Ah (Beep/Headphone Mic/Line In)>
678c2ecf20Sopenharmony_ci                               |
688c2ecf20Sopenharmony_ci                        {amplify if L/R}
698c2ecf20Sopenharmony_ci                               |
708c2ecf20Sopenharmony_ci                  +-----!h-----+-----S-----+
718c2ecf20Sopenharmony_ci                  |                        |
728c2ecf20Sopenharmony_ci          {21h mute control}               |
738c2ecf20Sopenharmony_ci                  |                        |
748c2ecf20Sopenharmony_ci          >21h (Headphone)<     >14h (Internal Speaker)<
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ciBackground
778c2ecf20Sopenharmony_ci==========
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ciAll Realtek HDA codecs have a vendor-defined widget with node ID 20h which
808c2ecf20Sopenharmony_ciprovides access to a bank of registers that control various codec functions.
818c2ecf20Sopenharmony_ciRegisters are read and written via the standard HDA processing coefficient
828c2ecf20Sopenharmony_civerbs (Set/Get Coefficient Index, Set/Get Processing Coefficient). The node is
838c2ecf20Sopenharmony_cinamed "Realtek Vendor Registers" in public datasheets' verb listings and,
848c2ecf20Sopenharmony_ciapart from that, is entirely undocumented.
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ciThis particular register, exposed at coefficient 0x36 and named in commits from
878c2ecf20Sopenharmony_ciRealtek, is of note: unlike most registers, which seem to control detailed
888c2ecf20Sopenharmony_ciamplifier parameters not in scope of the HDA specification, it controls audio
898c2ecf20Sopenharmony_cirouting which could just as easily have been defined using standard HDA mixer
908c2ecf20Sopenharmony_ciand selector widgets.
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ciSpecifically, it selects between two sources for the input pin widget with Node
938c2ecf20Sopenharmony_ciID (NID) 1Ah: the widget's signal can come either from an audio jack (on my
948c2ecf20Sopenharmony_cilaptop, a Dell XPS 13 9350, it's the headphone jack, but comments in Realtek
958c2ecf20Sopenharmony_cicommits indicate that it might be a Line In on some machines) or from the PC
968c2ecf20Sopenharmony_ciBeep line (which is itself multiplexed between the codec's internal beep
978c2ecf20Sopenharmony_cigenerator and external PCBEEP pin, depending on if the beep generator is
988c2ecf20Sopenharmony_cienabled via verbs on NID 01h). Additionally, it can mix (with optional
998c2ecf20Sopenharmony_ciamplification) that signal onto the 21h and/or 14h output pins.
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ciThe register's reset value is 0x3717, corresponding to PC Beep on 1Ah that is
1028c2ecf20Sopenharmony_cithen amplified and mixed into both the headphones and the speakers. Not only
1038c2ecf20Sopenharmony_cidoes this violate the HDA specification, which says that "[a vendor defined
1048c2ecf20Sopenharmony_cibeep input pin] connection may be maintained *only* while the Link reset
1058c2ecf20Sopenharmony_ci(**RST#**) is asserted", it means that we cannot ignore the register if we care
1068c2ecf20Sopenharmony_ciabout the input that 1Ah would otherwise expose or if the PCBEEP trace is
1078c2ecf20Sopenharmony_cipoorly shielded and picks up chassis noise (both of which are the case on my
1088c2ecf20Sopenharmony_cimachine).
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ciUnfortunately, there are lots of ways to get this register configuration wrong.
1118c2ecf20Sopenharmony_ciLinux, it seems, has gone through most of them. For one, the register resets
1128c2ecf20Sopenharmony_ciafter S3 suspend: judging by existing code, this isn't the case for all vendor
1138c2ecf20Sopenharmony_ciregisters, and it's led to some fixes that improve behavior on cold boot but
1148c2ecf20Sopenharmony_cidon't last after suspend. Other fixes have successfully switched the 1Ah input
1158c2ecf20Sopenharmony_ciaway from PC Beep but have failed to disable both loopback paths. On my
1168c2ecf20Sopenharmony_cimachine, this means that the headphone input is amplified and looped back to
1178c2ecf20Sopenharmony_cithe headphone output, which uses the exact same pins! As you might expect, this
1188c2ecf20Sopenharmony_cicauses terrible headphone noise, the character of which is controlled by the
1198c2ecf20Sopenharmony_ci1Ah boost control. (If you've seen instructions online to fix XPS 13 headphone
1208c2ecf20Sopenharmony_cinoise by changing "Headphone Mic Boost" in ALSA, now you know why.)
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ciThe information here has been obtained through black-box reverse engineering of
1238c2ecf20Sopenharmony_cithe ALC256 codec's behavior and is not guaranteed to be correct. It likely
1248c2ecf20Sopenharmony_cialso applies for the ALC255, ALC257, ALC235, and ALC236, since those codecs
1258c2ecf20Sopenharmony_ciseem to be close relatives of the ALC256. (They all share one initialization
1268c2ecf20Sopenharmony_cifunction.) Additionally, other codecs like the ALC225 and ALC285 also have this
1278c2ecf20Sopenharmony_ciregister, judging by existing fixups in ``patch_realtek.c``, but specific
1288c2ecf20Sopenharmony_cidata (e.g. node IDs, bit positions, pin mappings) for those codecs may differ
1298c2ecf20Sopenharmony_cifrom what I've described here.
130