162306a36Sopenharmony_ci===============================
262306a36Sopenharmony_ciRealtek PC Beep Hidden Register
362306a36Sopenharmony_ci===============================
462306a36Sopenharmony_ci
562306a36Sopenharmony_ciThis file documents the "PC Beep Hidden Register", which is present in certain
662306a36Sopenharmony_ciRealtek HDA codecs and controls a muxer and pair of passthrough mixers that can
762306a36Sopenharmony_ciroute audio between pins but aren't themselves exposed as HDA widgets. As far
862306a36Sopenharmony_cias I can tell, these hidden routes are designed to allow flexible PC Beep output
962306a36Sopenharmony_cifor codecs that don't have mixer widgets in their output paths. Why it's easier
1062306a36Sopenharmony_cito hide a mixer behind an undocumented vendor register than to just expose it
1162306a36Sopenharmony_cias a widget, I have no idea.
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ciRegister Description
1462306a36Sopenharmony_ci====================
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ciThe register is accessed via processing coefficient 0x36 on NID 20h. Bits not
1762306a36Sopenharmony_ciidentified below have no discernible effect on my machine, a Dell XPS 13 9350::
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci  MSB                           LSB
2062306a36Sopenharmony_ci  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2162306a36Sopenharmony_ci  | |h|S|L|         | B |R|       | Known bits
2262306a36Sopenharmony_ci  +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
2362306a36Sopenharmony_ci  |0|0|1|1|  0x7  |0|0x0|1|  0x7  | Reset value
2462306a36Sopenharmony_ci  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci1Ah input select (B): 2 bits
2762306a36Sopenharmony_ci  When zero, expose the PC Beep line (from the internal beep generator, when
2862306a36Sopenharmony_ci  enabled with the Set Beep Generation verb on NID 01h, or else from the
2962306a36Sopenharmony_ci  external PCBEEP pin) on the 1Ah pin node. When nonzero, expose the headphone
3062306a36Sopenharmony_ci  jack (or possibly Line In on some machines) input instead. If PC Beep is
3162306a36Sopenharmony_ci  selected, the 1Ah boost control has no effect.
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ciAmplify 1Ah loopback, left (L): 1 bit
3462306a36Sopenharmony_ci  Amplify the left channel of 1Ah before mixing it into outputs as specified
3562306a36Sopenharmony_ci  by h and S bits. Does not affect the level of 1Ah exposed to other widgets.
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ciAmplify 1Ah loopback, right (R): 1 bit
3862306a36Sopenharmony_ci  Amplify the right channel of 1Ah before mixing it into outputs as specified
3962306a36Sopenharmony_ci  by h and S bits. Does not affect the level of 1Ah exposed to other widgets.
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ciLoopback 1Ah to 21h [active low] (h): 1 bit
4262306a36Sopenharmony_ci  When zero, mix 1Ah (possibly with amplification, depending on L and R bits)
4362306a36Sopenharmony_ci  into 21h (headphone jack on my machine). Mixed signal respects the mute
4462306a36Sopenharmony_ci  setting on 21h.
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ciLoopback 1Ah to 14h (S): 1 bit
4762306a36Sopenharmony_ci  When one, mix 1Ah (possibly with amplification, depending on L and R bits)
4862306a36Sopenharmony_ci  into 14h (internal speaker on my machine). Mixed signal **ignores** the mute
4962306a36Sopenharmony_ci  setting on 14h and is present whenever 14h is configured as an output.
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ciPath diagrams
5262306a36Sopenharmony_ci=============
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci1Ah input selection (DIV is the PC Beep divider set on NID 01h)::
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci  <Beep generator>   <PCBEEP pin>    <Headphone jack>
5762306a36Sopenharmony_ci          |                |                |
5862306a36Sopenharmony_ci          +--DIV--+--!DIV--+       {1Ah boost control}
5962306a36Sopenharmony_ci                  |                         |
6062306a36Sopenharmony_ci                  +--(b == 0)--+--(b != 0)--+
6162306a36Sopenharmony_ci                               |
6262306a36Sopenharmony_ci               >1Ah (Beep/Headphone Mic/Line In)<
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ciLoopback of 1Ah to 21h/14h::
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci               <1Ah (Beep/Headphone Mic/Line In)>
6762306a36Sopenharmony_ci                               |
6862306a36Sopenharmony_ci                        {amplify if L/R}
6962306a36Sopenharmony_ci                               |
7062306a36Sopenharmony_ci                  +-----!h-----+-----S-----+
7162306a36Sopenharmony_ci                  |                        |
7262306a36Sopenharmony_ci          {21h mute control}               |
7362306a36Sopenharmony_ci                  |                        |
7462306a36Sopenharmony_ci          >21h (Headphone)<     >14h (Internal Speaker)<
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ciBackground
7762306a36Sopenharmony_ci==========
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ciAll Realtek HDA codecs have a vendor-defined widget with node ID 20h which
8062306a36Sopenharmony_ciprovides access to a bank of registers that control various codec functions.
8162306a36Sopenharmony_ciRegisters are read and written via the standard HDA processing coefficient
8262306a36Sopenharmony_civerbs (Set/Get Coefficient Index, Set/Get Processing Coefficient). The node is
8362306a36Sopenharmony_cinamed "Realtek Vendor Registers" in public datasheets' verb listings and,
8462306a36Sopenharmony_ciapart from that, is entirely undocumented.
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ciThis particular register, exposed at coefficient 0x36 and named in commits from
8762306a36Sopenharmony_ciRealtek, is of note: unlike most registers, which seem to control detailed
8862306a36Sopenharmony_ciamplifier parameters not in scope of the HDA specification, it controls audio
8962306a36Sopenharmony_cirouting which could just as easily have been defined using standard HDA mixer
9062306a36Sopenharmony_ciand selector widgets.
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ciSpecifically, it selects between two sources for the input pin widget with Node
9362306a36Sopenharmony_ciID (NID) 1Ah: the widget's signal can come either from an audio jack (on my
9462306a36Sopenharmony_cilaptop, a Dell XPS 13 9350, it's the headphone jack, but comments in Realtek
9562306a36Sopenharmony_cicommits indicate that it might be a Line In on some machines) or from the PC
9662306a36Sopenharmony_ciBeep line (which is itself multiplexed between the codec's internal beep
9762306a36Sopenharmony_cigenerator and external PCBEEP pin, depending on if the beep generator is
9862306a36Sopenharmony_cienabled via verbs on NID 01h). Additionally, it can mix (with optional
9962306a36Sopenharmony_ciamplification) that signal onto the 21h and/or 14h output pins.
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ciThe register's reset value is 0x3717, corresponding to PC Beep on 1Ah that is
10262306a36Sopenharmony_cithen amplified and mixed into both the headphones and the speakers. Not only
10362306a36Sopenharmony_cidoes this violate the HDA specification, which says that "[a vendor defined
10462306a36Sopenharmony_cibeep input pin] connection may be maintained *only* while the Link reset
10562306a36Sopenharmony_ci(**RST#**) is asserted", it means that we cannot ignore the register if we care
10662306a36Sopenharmony_ciabout the input that 1Ah would otherwise expose or if the PCBEEP trace is
10762306a36Sopenharmony_cipoorly shielded and picks up chassis noise (both of which are the case on my
10862306a36Sopenharmony_cimachine).
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ciUnfortunately, there are lots of ways to get this register configuration wrong.
11162306a36Sopenharmony_ciLinux, it seems, has gone through most of them. For one, the register resets
11262306a36Sopenharmony_ciafter S3 suspend: judging by existing code, this isn't the case for all vendor
11362306a36Sopenharmony_ciregisters, and it's led to some fixes that improve behavior on cold boot but
11462306a36Sopenharmony_cidon't last after suspend. Other fixes have successfully switched the 1Ah input
11562306a36Sopenharmony_ciaway from PC Beep but have failed to disable both loopback paths. On my
11662306a36Sopenharmony_cimachine, this means that the headphone input is amplified and looped back to
11762306a36Sopenharmony_cithe headphone output, which uses the exact same pins! As you might expect, this
11862306a36Sopenharmony_cicauses terrible headphone noise, the character of which is controlled by the
11962306a36Sopenharmony_ci1Ah boost control. (If you've seen instructions online to fix XPS 13 headphone
12062306a36Sopenharmony_cinoise by changing "Headphone Mic Boost" in ALSA, now you know why.)
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ciThe information here has been obtained through black-box reverse engineering of
12362306a36Sopenharmony_cithe ALC256 codec's behavior and is not guaranteed to be correct. It likely
12462306a36Sopenharmony_cialso applies for the ALC255, ALC257, ALC235, and ALC236, since those codecs
12562306a36Sopenharmony_ciseem to be close relatives of the ALC256. (They all share one initialization
12662306a36Sopenharmony_cifunction.) Additionally, other codecs like the ALC225 and ALC285 also have this
12762306a36Sopenharmony_ciregister, judging by existing fixups in ``patch_realtek.c``, but specific
12862306a36Sopenharmony_cidata (e.g. node IDs, bit positions, pin mappings) for those codecs may differ
12962306a36Sopenharmony_cifrom what I've described here.
130