Jump to content

Mainline:Broadcom Kona/BCM590xx/Regulators

From dissonant.dev wiki

(note: this article has not been cleaned up at all, it is imported from my local notes as-is.)

Revisions

BCMPMU_59054_ID is ID for 59054

BCMPMU_59054A1_ANA_REV refers to A1 which has ACLD, A0 does not

Downstream driver notes

  • The downstream driver used is BCM59xxx, which despite the name is only for the BCM59054
    • In the tree there are also drivers for BCM59056, a handful of other PMUs including BCM59055, and BCM590xx (which confusingly is not the same as BCM59xxx).
  • The whole driver is fragmented as it's an MFD device, but the most important files are:
    • arch/arm/mach-{codename}/board-bcm59xxx_{device}.c - contains PMU setup data, including voltages, regulator modes, battery values, etc.
    • various files in drivers/mfd/ starting from bcmpmu59xxx-
    • drivers/regulator/bcmpmu-rgltr-bcm59xxx.c and drivers/regulator/bcmpmu59xxx-regulator.c
    • there's some OTG related driver in drivers/usb/otg/? investigate
    • drivers/misc/bcmpmu59xxx_audio.c
    • include/linux/mfd/bcmpmu59xxx_reg.h and include/linux/mfd/bcmpmu59054_reg.h
    • and others not mentioned here. todo

Regulators

SR apparently means "switcher" (drivers/regulator/bcmpmu-regulator-56.c line 249). Rest is LDOs.

Modes

(see drivers/regulator/bcmpmu59xxx-regulator.c, include/linux/mfd/bcmpmu59xxx.h)

There are two mode settings: 3bit (GPLDOs only) and 2bit (everything else, including all regs in bcm59056).

A standard regulator can have 3 modes: * ON (REGULATOR_MODE_FAST, REGULATOR_MODE_NORMAL) (0) * LPM (REGULATOR_MODE_IDLE) (1) * OFF (REGULATOR_MODE_STANDBY) (2)

  • 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 2 PMMODE registers. (PMCTRL1 and PMCTRL2)
  • 3-bit mode regulators have 2 PM values in the PMMODE registers, at offsets 0 and 3 respectively, and 4 PMMODE registers. (PMCTRL1->4)

Each PM value corresponds to a different mode.

BCM59056 and modes

(see drivers/regulator/bcmpmu-regulator-56.c)

Unlike BCM59054, there's only one PMMODE register (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.

I have a sneaking suspicion, based on the mainline driver, and the fact that the function described in the "Enabling the regulator" part will gleefuly ignore PM0 mostly, that PM0 may be some sort of "perma-override"

/*State of enabled regualtor in deep sleep     
Used to program PC2PC1 = 0b10 & 0b00 case     
when the regulator is enabled*/     
enum {     
        BCMPMU_REGL_ON_IN_DSM = 1,     
        BCMPMU_REGL_LPM_IN_DSM,     
        BCMPMU_REGL_OFF_IN_DSM     
};

...a PC reference? You'll see these in the next section.

BCM59054 and modes

Here, the situation is a bit more complicated because there are multiple PMMODE regs. (Actually BCM59056 seems to have these as well? weird.)

Enabling a regulator

In theory, enabling a regulator can be done by setting all of its modes to PMMODE_ON. In practice, however, each regulator has specific "pins" which, when enabled, will enable the regulator. The pins used are stored in arch/arm/mach-java/board-bcm59xxx_*, under pc_pins_map.

This has a value created with the "PCPIN_MAP_ENC" macro, which effectively packs two "sets":

  • Set 1, which is the first parameter - if this is set, then all pins in this set must be enabled to enable this regulator.
  • Set 0, which is the second parameter - if this is set, then one of the pins in this set must be enabled to enable this regulator.

The functions __is_2bit_pmmode_regl_enabled and __is_3bit_pmmode_regl_enabled check if a regulator is enabled based on those pin maps, and the pmmode value as read out from the PMMODE registers.

For every i from 0 to 7 (REGL_PMMODE_VAL_MAX):

  • get the PM reg shift by PMMODE_2BIT_PMx_MASK & i (PMMODE_2BIT_PMx_MASK == 3)
  • if this i gives a value through setval & i in set0 or set1, then the value of whether the regulator is enabled is calculated using PMMODE_2BIT_PMx_MASK & (pmmode[inx] >> shift), where inx is increased for every value where PMMODE_2BIT_PMx_MASK & i == 3.

In normal words: if the mode corresponding to the pin in any of the PMMODE registers is ON, then the regulator is on.

Here's a table of what that looks like:

(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)

i s x set0   pc1   pc2   pc3
0 0 0 False [False, False, False]
1 2 0 True [True, False, False]
2 4 0 True [False, True, False]
3 6 0 True [True, True, False]
4 0 1 True [False, False, True]
5 2 1 True [True, False, True]
6 4 1 True [False, True, True]
7 6 1 True [True, True, True]

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.

So, how can the BCM59056 driver ignore that second register? Maybe I just didn't read something right? (probably...) (update: I think it's just BCM59054 that pokes multiple regs?)

Update: I found this a little later, in the bcm590xx driver (actually for the BCM59055).

#define PC2_IS_0_PC1_IS_0                       0    
#define PC2_IS_0_PC1_IS_1                       2    
#define PC2_IS_1_PC1_IS_0                       4    
#define PC2_IS_1_PC1_IS_1                       6

I suppose this should match the table above?

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.

The actual function called to prepare the enable value

Now that we know how these pins work, we can analyze the second function, __2bit_pmmode_frm_map.

This one's similar to the previous function:

For every i from 0 to 7 (REGL_PMMODE_VAL_MAX):

  • If the value is in set0 or set1, set the value to PMMODE_ON; otherwise, use dsm_pmmode (a variable passed at init time). Oooh, DSM again!
  • Figure out the shift and register like before.
  • Add the value to a temp variable by ORing val << shift to it.

Here's the thing: dsm_pmmode... is the mode value provided in __bcmpmuldo_set_mode.

The mode is set in a few places in the code, and next to one of them, I found this:

                        /* We need to set mode here as regulator framework     
                        (set_machine_constraints) set the mode first and     
                        then call enable. We have updated enable function     
                        to set ON for all states based on customer request     
                        set_mode function sets PMMODE as needed*/

TL;DR, summary

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.

As a gross oversimplification, you can simply set every register to PMMODE_ON and it should work.

PM0 and PM2 (offsets 0 and 4) may or may not be related to deep sleep mode.

A note about PC pins

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's connected, as PMU_PC3, to the GPIO1 pin on the PMIC.

Turns out, the function of the GPIO pins can be programmed by writing to the GPIOCTRL registers. Here's the relevant downstream code:

(arch/arm/mach-java/board-bcm59xxx_ss_baffinlite.c)

 121         /*  enable PC3 function */
 122         {.addr = PMU_REG_GPIOCTRL2, .val = 0x0E, .mask = 0xFF},

Sadly, these regs are completely undocumented, so we can't know for sure which exact bit enables this function. We also don't know what happens if it's not enabled.

What about the regulator modes?

Somehow, __2bit_pmmode_frm_map doesn't set all of the PMMODE offsets! For the offsets matching the PC pin map, it actually leaves them on, and only sets the requested mode for the remaining ones! Given that the variable name for the provided mode is dsm_pmmode, I suspect that Broadcom might've abused the mode system to provide the deep sleep regulator mode instead.

Still, this doesn't explain how the PC pins are controlled. I can't find any place in the downstream code that would do it. I suspect I should look at the suspend code...

Note to self: CHIPREG seems interesting. Has a whole bunch of stuff.

Another unrelated note: looks like i2c sets up slew rate for its pins in the driver, investigate