<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.dissonant.dev/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=AltUart</id>
	<title>dissonant.dev wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.dissonant.dev/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=AltUart"/>
	<link rel="alternate" type="text/html" href="https://wiki.dissonant.dev/wiki/Special:Contributions/AltUart"/>
	<updated>2026-08-09T11:42:17Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.6</generator>
	<entry>
		<id>https://wiki.dissonant.dev/index.php?title=Main_Page&amp;diff=167</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://wiki.dissonant.dev/index.php?title=Main_Page&amp;diff=167"/>
		<updated>2026-08-09T09:23:59Z</updated>

		<summary type="html">&lt;p&gt;AltUart: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* [[Meta:Infrastructure]]&lt;br /&gt;
* [[Mainline:Onyx Go 6]]&lt;br /&gt;
* [[Mainline:Broadcom Kona]]&lt;br /&gt;
* [[Mainline:Exynos 4]]&lt;br /&gt;
* [[Mainline:BCM215xx]]&lt;br /&gt;
&lt;br /&gt;
contact [https://uart.sh uart] for an account.&lt;/div&gt;</summary>
		<author><name>AltUart</name></author>
	</entry>
	<entry>
		<id>https://wiki.dissonant.dev/index.php?title=User:Knuxify/Old_BCM590xx_regulator_notes&amp;diff=166</id>
		<title>User:Knuxify/Old BCM590xx regulator notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.dissonant.dev/index.php?title=User:Knuxify/Old_BCM590xx_regulator_notes&amp;diff=166"/>
		<updated>2026-08-09T09:23:32Z</updated>

		<summary type="html">&lt;p&gt;AltUart: AltUart moved page User:Knuxify/Old BCM590xx regulator notes to User:Uart/Old BCM590xx regulator notes: Automatically moved page while renaming the user &amp;quot;Knuxify&amp;quot; to &amp;quot;Uart&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[User:Uart/Old BCM590xx regulator notes]]&lt;/div&gt;</summary>
		<author><name>AltUart</name></author>
	</entry>
	<entry>
		<id>https://wiki.dissonant.dev/index.php?title=User:Uart/Old_BCM590xx_regulator_notes&amp;diff=165</id>
		<title>User:Uart/Old BCM590xx regulator notes</title>
		<link rel="alternate" type="text/html" href="https://wiki.dissonant.dev/index.php?title=User:Uart/Old_BCM590xx_regulator_notes&amp;diff=165"/>
		<updated>2026-08-09T09:23:32Z</updated>

		<summary type="html">&lt;p&gt;AltUart: AltUart moved page User:Knuxify/Old BCM590xx regulator notes to User:Uart/Old BCM590xx regulator notes: Automatically moved page while renaming the user &amp;quot;Knuxify&amp;quot; to &amp;quot;Uart&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;(note: this article has not been cleaned up &#039;&#039;at all&#039;&#039;, it is imported from my local notes as-is.)&lt;br /&gt;
&lt;br /&gt;
== Revisions ==&lt;br /&gt;
&lt;br /&gt;
BCMPMU_59054_ID is ID for 59054&lt;br /&gt;
&lt;br /&gt;
BCMPMU_59054A1_ANA_REV refers to A1 which has ACLD, A0 does not&lt;br /&gt;
&lt;br /&gt;
== Downstream driver notes ==&lt;br /&gt;
&lt;br /&gt;
* The downstream driver used is BCM59xxx, which despite the name is only for the BCM59054&lt;br /&gt;
** In the tree there are also drivers for BCM59056, a handful of other PMUs including BCM59055, and BCM590xx (which confusingly is &#039;&#039;&#039;not&#039;&#039;&#039; the same as BCM59xxx).&lt;br /&gt;
* The whole driver is fragmented as it&#039;s an MFD device, but the most important files are:&lt;br /&gt;
** &amp;lt;code&amp;gt;arch/arm/mach-{codename}/board-bcm59xxx_{device}.c&amp;lt;/code&amp;gt; - contains PMU setup data, including voltages, regulator modes, battery values, etc.&lt;br /&gt;
** various files in &amp;lt;code&amp;gt;drivers/mfd/&amp;lt;/code&amp;gt; starting from &amp;lt;code&amp;gt;bcmpmu59xxx-&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;drivers/regulator/bcmpmu-rgltr-bcm59xxx.c&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;drivers/regulator/bcmpmu59xxx-regulator.c&amp;lt;/code&amp;gt;&lt;br /&gt;
** there&#039;s some OTG related driver in &amp;lt;code&amp;gt;drivers/usb/otg/&amp;lt;/code&amp;gt;? investigate&lt;br /&gt;
** &amp;lt;code&amp;gt;drivers/misc/bcmpmu59xxx_audio.c&amp;lt;/code&amp;gt;&lt;br /&gt;
** &amp;lt;code&amp;gt;include/linux/mfd/bcmpmu59xxx_reg.h&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;include/linux/mfd/bcmpmu59054_reg.h&amp;lt;/code&amp;gt;&lt;br /&gt;
** and others not mentioned here. todo&lt;br /&gt;
&lt;br /&gt;
== Regulators ==&lt;br /&gt;
&lt;br /&gt;
SR apparently means &amp;quot;switcher&amp;quot; (drivers/regulator/bcmpmu-regulator-56.c line 249). Rest is LDOs.&lt;br /&gt;
&lt;br /&gt;
== Modes ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;(see &amp;lt;code&amp;gt;drivers/regulator/bcmpmu59xxx-regulator.c&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;include/linux/mfd/bcmpmu59xxx.h&amp;lt;/code&amp;gt;)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
There are two mode settings: 3bit (GPLDOs only) and 2bit (everything else, including all regs in bcm59056).&lt;br /&gt;
&lt;br /&gt;
A standard regulator can have 3 modes: * ON (&amp;lt;code&amp;gt;REGULATOR_MODE_FAST&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;REGULATOR_MODE_NORMAL&amp;lt;/code&amp;gt;) (0) * LPM (&amp;lt;code&amp;gt;REGULATOR_MODE_IDLE&amp;lt;/code&amp;gt;) (1) * OFF (&amp;lt;code&amp;gt;REGULATOR_MODE_STANDBY&amp;lt;/code&amp;gt;) (2)&lt;br /&gt;
&lt;br /&gt;
* 2-bit mode regulators have 4 PM values in the PMMODE registers, at offsets 0, 2, 4 and 6 respectively (PM0, PM1, PM2, PM3), and &#039;&#039;&#039;2 PMMODE registers&#039;&#039;&#039;. (PMCTRL1 and PMCTRL2)&lt;br /&gt;
* 3-bit mode regulators have 2 PM values in the PMMODE registers, at offsets 0 and 3 respectively, and &#039;&#039;&#039;4 PMMODE registers&#039;&#039;&#039;. (PMCTRL1-&amp;gt;4)&lt;br /&gt;
&lt;br /&gt;
Each PM value corresponds to a different mode.&lt;br /&gt;
&lt;br /&gt;
== BCM59056 and modes ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;(see &amp;lt;code&amp;gt;drivers/regulator/bcmpmu-regulator-56.c&amp;lt;/code&amp;gt;)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;strike&amp;gt;Unlike BCM59054, there&#039;s only one PMMODE register&amp;lt;/strike&amp;gt; (this is completely wrong! BCM59056 also has multiple PMMODE regs), and it has values PM0 to PM3. DSM (deep sleep) is pins PM0 and PM2. Regular value is written to PM1 and PM3.&lt;br /&gt;
&lt;br /&gt;
I have a sneaking suspicion, based on the mainline driver, and the fact that the function described in the &amp;quot;Enabling the regulator&amp;quot; part will gleefuly ignore PM0 mostly, that PM0 may be some sort of &amp;quot;perma-override&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
/*State of enabled regualtor in deep sleep     &lt;br /&gt;
Used to program PC2PC1 = 0b10 &amp;amp; 0b00 case     &lt;br /&gt;
when the regulator is enabled*/     &lt;br /&gt;
enum {     &lt;br /&gt;
        BCMPMU_REGL_ON_IN_DSM = 1,     &lt;br /&gt;
        BCMPMU_REGL_LPM_IN_DSM,     &lt;br /&gt;
        BCMPMU_REGL_OFF_IN_DSM     &lt;br /&gt;
};   &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...a PC reference? You&#039;ll see these in the next section.&lt;br /&gt;
&lt;br /&gt;
=== BCM59054 and modes ===&lt;br /&gt;
&lt;br /&gt;
Here, the situation is a bit more complicated because there are multiple PMMODE regs. (Actually BCM59056 seems to have these as well? weird.)&lt;br /&gt;
&lt;br /&gt;
=== Enabling a regulator ===&lt;br /&gt;
&lt;br /&gt;
In theory, enabling a regulator can be done by setting all of its modes to &amp;lt;code&amp;gt;PMMODE_ON&amp;lt;/code&amp;gt;. In practice, however, each regulator has specific &amp;quot;pins&amp;quot; which, when enabled, will enable the regulator. The pins used are stored in &amp;lt;code&amp;gt;arch/arm/mach-java/board-bcm59xxx_*&amp;lt;/code&amp;gt;, under &amp;lt;code&amp;gt;pc_pins_map&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
This has a value created with the &amp;quot;PCPIN_MAP_ENC&amp;quot; macro, which effectively packs two &amp;quot;sets&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Set 1&#039;&#039;&#039;, which is the first parameter - if this is set, then &#039;&#039;&#039;all pins in this set must be enabled&#039;&#039;&#039; to enable this regulator.&lt;br /&gt;
* &#039;&#039;&#039;Set 0&#039;&#039;&#039;, which is the second parameter - if this is set, then &#039;&#039;&#039;one of the pins in this set must be enabled&#039;&#039;&#039; to enable this regulator.&lt;br /&gt;
&lt;br /&gt;
The functions &amp;lt;code&amp;gt;__is_2bit_pmmode_regl_enabled&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;__is_3bit_pmmode_regl_enabled&amp;lt;/code&amp;gt; check if a regulator is enabled based on those pin maps, and the &amp;lt;code&amp;gt;pmmode&amp;lt;/code&amp;gt; value as read out from the PMMODE registers.&lt;br /&gt;
&lt;br /&gt;
For every &amp;lt;code&amp;gt;i&amp;lt;/code&amp;gt; from 0 to 7 (&amp;lt;code&amp;gt;REGL_PMMODE_VAL_MAX&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
* get the PM reg shift by &amp;lt;code&amp;gt;PMMODE_2BIT_PMx_MASK &amp;amp; i&amp;lt;/code&amp;gt; (PMMODE_2BIT_PMx_MASK == 3)&lt;br /&gt;
* if this &amp;lt;code&amp;gt;i&amp;lt;/code&amp;gt; gives a value through &amp;lt;code&amp;gt;setval &amp;amp; i&amp;lt;/code&amp;gt; in set0 or set1, then the value of whether the regulator is enabled is calculated using &amp;lt;code&amp;gt;PMMODE_2BIT_PMx_MASK &amp;amp; (pmmode[inx] &amp;gt;&amp;gt; shift)&amp;lt;/code&amp;gt;, where &amp;lt;code&amp;gt;inx&amp;lt;/code&amp;gt; is increased for every value where &amp;lt;code&amp;gt;PMMODE_2BIT_PMx_MASK &amp;amp; i&amp;lt;/code&amp;gt; == 3.&lt;br /&gt;
&lt;br /&gt;
In normal words: if the mode corresponding to the pin in &#039;&#039;any&#039;&#039; of the PMMODE registers is ON, then the regulator is on.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s a table of what that looks like:&lt;br /&gt;
&lt;br /&gt;
(i - i iterator, s - pm offset, x - pmmode register no., set0 - matches against joined set0; pc1, pc2, pc3 - the result of the check for each of the possible pins in set0)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;i s x set0   pc1   pc2   pc3&lt;br /&gt;
0 0 0 False [False, False, False]&lt;br /&gt;
1 2 0 True [True, False, False]&lt;br /&gt;
2 4 0 True [False, True, False]&lt;br /&gt;
3 6 0 True [True, True, False]&lt;br /&gt;
4 0 1 True [False, False, True]&lt;br /&gt;
5 2 1 True [True, False, True]&lt;br /&gt;
6 4 1 True [False, True, True]&lt;br /&gt;
7 6 1 True [True, True, True]&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
One thing of note - PC1 matches exactly the same configuration as the non-deep-sleep pins from the BCM59056 driver mentioned earlier. PC2 matches offsets 4 and 6, and PC3 matches everything in the second register, but not the first one.&lt;br /&gt;
&lt;br /&gt;
So, how can the BCM59056 driver ignore that second register? Maybe I just didn&#039;t read something right? (probably...) (update: I think it&#039;s just BCM59054 that pokes multiple regs?)&lt;br /&gt;
&lt;br /&gt;
Update: I found this a little later, in the bcm59&#039;&#039;&#039;0xx&#039;&#039;&#039; driver (actually for the BCM59055).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;#define PC2_IS_0_PC1_IS_0                       0    &lt;br /&gt;
#define PC2_IS_0_PC1_IS_1                       2    &lt;br /&gt;
#define PC2_IS_1_PC1_IS_0                       4    &lt;br /&gt;
#define PC2_IS_1_PC1_IS_1                       6    &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
I suppose this should match the table above?&lt;br /&gt;
&lt;br /&gt;
In any case - what I think is happening here is that which registers are read from to determine the notes are controlled by some kind of pins. Each PMMODE offset represents a different combination of pins to set.&lt;br /&gt;
&lt;br /&gt;
=== The actual function called to prepare the enable value ===&lt;br /&gt;
&lt;br /&gt;
Now that we know how these pins work, we can analyze the second function, &amp;lt;code&amp;gt;__2bit_pmmode_frm_map&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
This one&#039;s similar to the previous function:&lt;br /&gt;
&lt;br /&gt;
For every &amp;lt;code&amp;gt;i&amp;lt;/code&amp;gt; from 0 to 7 (&amp;lt;code&amp;gt;REGL_PMMODE_VAL_MAX&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
* If the value is in set0 or set1, set the value to &amp;lt;code&amp;gt;PMMODE_ON&amp;lt;/code&amp;gt;; otherwise, use &#039;&#039;&#039;&amp;lt;code&amp;gt;dsm_pmmode&amp;lt;/code&amp;gt;&#039;&#039;&#039; (a variable passed at init time). Oooh, DSM again!&lt;br /&gt;
* Figure out the shift and register like before.&lt;br /&gt;
* Add the value to a temp variable by ORing &amp;lt;code&amp;gt;val &amp;lt;&amp;lt; shift&amp;lt;/code&amp;gt; to it.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s the thing: &amp;lt;code&amp;gt;dsm_pmmode&amp;lt;/code&amp;gt;... is the mode value provided in &amp;lt;code&amp;gt;__bcmpmuldo_set_mode&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The mode is set in a few places in the code, and next to one of them, I found this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;                        /* We need to set mode here as regulator framework     &lt;br /&gt;
                        (set_machine_constraints) set the mode first and     &lt;br /&gt;
                        then call enable. We have updated enable function     &lt;br /&gt;
                        to set ON for all states based on customer request     &lt;br /&gt;
                        set_mode function sets PMMODE as needed*/     &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== TL;DR, summary ====&lt;br /&gt;
&lt;br /&gt;
Regulators can be enabled by setting specific offsets at the PMMODE registers to PMMODE_ON. A combination of PC pins can be used to select which offsets and PMMODE registers actually apply - by default, only offsets in PMCTRL1 is used, but the others can be used as well if PC3 is present - see below.&lt;br /&gt;
&lt;br /&gt;
As a gross oversimplification, you can simply set &#039;&#039;every&#039;&#039; register to PMMODE_ON and it should work.&lt;br /&gt;
&lt;br /&gt;
PM0 and PM2 (offsets 0 and 4) may or may not be related to deep sleep mode.&lt;br /&gt;
&lt;br /&gt;
== A note about PC pins ==&lt;br /&gt;
&lt;br /&gt;
According to schematics, on the Grand Neo, PC1 and PC2 are connected to the accordingly named PC1 and PC2 pinctrl pins. PC3 is an alternative function of LCDCS0 - and it&#039;s connected, as PMU_PC3, to the GPIO1 pin on the PMIC.&lt;br /&gt;
&lt;br /&gt;
Turns out, the function of the GPIO pins can be programmed by writing to the GPIOCTRL registers. Here&#039;s the relevant downstream code:&lt;br /&gt;
&lt;br /&gt;
(arch/arm/mach-java/board-bcm59xxx_ss_baffinlite.c)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt; 121         /*  enable PC3 function */&lt;br /&gt;
 122         {.addr = PMU_REG_GPIOCTRL2, .val = 0x0E, .mask = 0xFF},&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Sadly, these regs are completely undocumented, so we can&#039;t know for sure which exact bit enables this function. We also don&#039;t know what happens if it&#039;s &#039;&#039;not&#039;&#039; enabled.&lt;br /&gt;
&lt;br /&gt;
== What about the regulator modes? ==&lt;br /&gt;
&lt;br /&gt;
Somehow, &amp;lt;code&amp;gt;__2bit_pmmode_frm_map&amp;lt;/code&amp;gt; &#039;&#039;doesn&#039;t&#039;&#039; set all of the PMMODE offsets! For the offsets matching the PC pin map, it actually &#039;&#039;leaves them on&#039;&#039;, and only sets the requested mode for the remaining ones! Given that the variable name for the provided mode is &amp;lt;code&amp;gt;dsm_pmmode&amp;lt;/code&amp;gt;, I suspect that Broadcom might&#039;ve abused the mode system to provide the &#039;&#039;deep sleep regulator mode&#039;&#039; instead.&lt;br /&gt;
&lt;br /&gt;
Still, this doesn&#039;t explain how the PC pins are controlled. I can&#039;t find any place in the downstream code that would do it. I suspect I should look at the suspend code...&lt;br /&gt;
&lt;br /&gt;
Note to self: CHIPREG seems interesting. Has a whole bunch of stuff.&lt;br /&gt;
&lt;br /&gt;
Another unrelated note: looks like i2c sets up slew rate for its pins in the driver, investigate&lt;/div&gt;</summary>
		<author><name>AltUart</name></author>
	</entry>
	<entry>
		<id>https://wiki.dissonant.dev/index.php?title=User:Knuxify/sidebartest&amp;diff=164</id>
		<title>User:Knuxify/sidebartest</title>
		<link rel="alternate" type="text/html" href="https://wiki.dissonant.dev/index.php?title=User:Knuxify/sidebartest&amp;diff=164"/>
		<updated>2026-08-09T09:23:32Z</updated>

		<summary type="html">&lt;p&gt;AltUart: AltUart moved page User:Knuxify/sidebartest to User:Uart/sidebartest: Automatically moved page while renaming the user &amp;quot;Knuxify&amp;quot; to &amp;quot;Uart&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[User:Uart/sidebartest]]&lt;/div&gt;</summary>
		<author><name>AltUart</name></author>
	</entry>
	<entry>
		<id>https://wiki.dissonant.dev/index.php?title=User:Uart/sidebartest&amp;diff=163</id>
		<title>User:Uart/sidebartest</title>
		<link rel="alternate" type="text/html" href="https://wiki.dissonant.dev/index.php?title=User:Uart/sidebartest&amp;diff=163"/>
		<updated>2026-08-09T09:23:32Z</updated>

		<summary type="html">&lt;p&gt;AltUart: AltUart moved page User:Knuxify/sidebartest to User:Uart/sidebartest: Automatically moved page while renaming the user &amp;quot;Knuxify&amp;quot; to &amp;quot;Uart&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is an example page&lt;br /&gt;
[[Category:Sidebar test]]&lt;/div&gt;</summary>
		<author><name>AltUart</name></author>
	</entry>
</feed>