diff options
Diffstat (limited to 'doc/develop/pmbus.rst')
| -rw-r--r-- | doc/develop/pmbus.rst | 637 |
1 files changed, 637 insertions, 0 deletions
diff --git a/doc/develop/pmbus.rst b/doc/develop/pmbus.rst new file mode 100644 index 00000000000..f5550541e83 --- /dev/null +++ b/doc/develop/pmbus.rst @@ -0,0 +1,637 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +PMBus support in U-Boot +======================= + +This document describes U-Boot's PMBus 1.x support: what it is for, +how it is structured, and how to add support for a new PMBus chipn +either from scratch from a chip datasheet or by porting an existing +Linux ``drivers/hwmon/pmbus/`` driver. + +.. contents:: + :local: + :depth: 2 + +Intent and scope +---------------- + +U-Boot's PMBus layer is not a hardware monitoring (hwmon) clone of +the Linux kernel's ``drivers/hwmon/pmbus/`` subsystem. Linux owns the +runtime side: continuous polling, sysfs publication, alert IRQ +handling, fan control loops. U-Boot owns the boot time side. Concretely +the U-Boot PMBus support exists to: + +* Identify the PMBus regulator(s) a board carries at boot: + ``MFR_ID``, ``MFR_MODEL``, ``MFR_REVISION`` reads, plus a quick + ``STATUS_WORD`` sanity check. +* Print telemetry so an operator can confirm rail voltages, input + current, and temperature before handing off to the kernel. One shot + reads, on demand, via the ``pmbus`` and ``regulator`` U-Boot + commands (``pmbus dev <name>; pmbus telemetry``, + ``regulator dev <name>; regulator value``). +* Decode chip alerts when a rail trips an over/under voltage, + over current, or thermal threshold; so a boot log shows why the + previous boot failed, before the kernel even comes up. +* Optionally trim a critical rail (typically the SoC core) before + the kernel takes over; "set the voltage prior to a kernel boot + to better protect the board". This is the existing + ``board/nxp/common/vid.c`` AVS path and any future per board + speed binning trim. + +Out of scope, by design: + +* No periodic polling. No worker thread. No background updates. +* No sysfs / procfs / userspace surface. U-Boot has none. +* No fan speed control loop. The kernel runs that. +* No long tail of virtual sensor registers (``PMBUS_VIRT_*``). +* No sensor caching / update timestamps. + +If you find yourself wanting any of those, the answer is "wait until +Linux comes up". Keep U-Boot's PMBus surface minimal. + +Architecture overview +--------------------- + +The framework is split into four layers (layer 3 comes in two +flavours, 3a and 3b), + +:: + + +----------------------------------------+ + | Layer 1: include/pmbus.h | + | Standard PMBus 1.x command codes, | + | numeric format enum, sensor class | + | enum, struct pmbus_driver_info, | + | decoder + transport prototypes, | + | STATUS_WORD bit names. | + +----------------------------------------+ + | Layer 2: lib/pmbus.c | + | Format decoders (LINEAR11/LINEAR16/| + | DIRECT) and encoder (LINEAR16), | + | two stage SMBus block read helper, | + | STATUS_*-bit print tables, generic | + | dispatcher pmbus_reg2data(). | + +----------------------------------------+ + | Layer 3a: drivers/power/regulator/ | + | <chip>.c | + | UCLASS_REGULATOR per chip drivers | + | ; one struct pmbus_driver_info | + | plus regulator set_value/get_value | + | ops. Optional: per chip identify() | + | hook to refine format from the | + | chip's own VOUT_MODE. | + +----------------------------------------+ + | Layer 3b: drivers/power/regulator/ | + | pmbus_generic.c | + | Catch all driver matching | + | compatible = "pmbus". | + | Auto detects format via VOUT_MODE | + | and PMBUS_QUERY where supported. | + | Use for compliant chips with no | + | per chip driver yet; ship | + | telemetry today, write a per chip | + | driver later only if quirks demand | + | it. | + +----------------------------------------+ + | Layer 4: board/<vendor>/<board>/ | + | <chip>_diag.c | + | Diagnostic commands only: | + | <chip>_info / <chip>_raw | + | Reads via regulator_get_value() | + | and lib/pmbus.c helpers. LINEAR / | + | DIRECT math NOT here. | + +----------------------------------------+ + +Generic vs. board specific separation rule. Layer 1, 2, and 3 +files are tree level and platform agnostic. Their comments may +reference only: + +* the PMBus 1.x specification, and +* chip manufacturer datasheets. + +Never a specific board, SoC, or product. Board-specific quirks +(a particular bus number, a particular slave address, a particular +PCB feedback divider, board local design notes) live exclusively in +``board/<vendor>/<board>/`` files. + +CLI commands +------------ + +The framework publishes one top level command, ``pmbus``, plus a +vendor namespace dispatcher so per chip code can register chip +specific extensions without touching the framework. + +Active device model +~~~~~~~~~~~~~~~~~~~ + +``pmbus`` mirrors the ``regulator`` command: select an active device +once, then operate on it across subcommands. The active device is +selected by I2C bus (decimal sequence number) and 7 bit address (hex, +``0x`` optional, à la ``i2c`` convention):: + + => pmbus dev 0:10 + pmbus: active i2c0:0x10 MFR_ID="MPS" MFR_MODEL="MPQ8785" vendor=mps + +The framework probes ``MFR_ID`` (in both natural and reverse byte +orders) at selection time, looks the result up in the chip match +registry populated by per chip code via ``pmbus_register_chip()``, +and caches the matched ``pmbus_driver_info``. All subsequent +subcommands consume that cached metadata. + +Standard subcommands +~~~~~~~~~~~~~~~~~~~~ + +:: + + pmbus list list UCLASS_REGULATOR devices (DM bound) + pmbus dev [<bus>:<addr>] show / select active PMBus device + pmbus info identification banner + driver_info + pmbus telemetry decoded VIN, VOUT, IIN, IOUT, TEMP + pmbus status decode every STATUS_* register + pmbus dump hex dump of every standard register + pmbus read <reg> [b|w|s] raw read (b=byte, w=word, s=string) + pmbus write <reg> <val> [b|w] raw write + pmbus clear [faults] issue CLEAR_FAULTS (03h) + pmbus vout [<uV>] read or set VOUT_COMMAND (microvolts) + pmbus scan [<bus>] PMBus aware probe of one or all I2C buses + +The ``<reg>`` argument accepts either a hexadecimal address +(``88``, ``0x`` optional) or a symbolic name (``READ_VIN``, +``VOUT_MODE``, ``MFR_ID``); symbolic names win when both parsed. +``<val>`` is hexadecimal too. Only ``pmbus vout``'s microvolt +argument and bus numbers are decimal. +Format selectors after the register select the SMBus transaction width: +``b`` for byte, ``w`` for 16 bit little endian word, +``s`` for the SMBus block read used by string registers. + +Decoded telemetry honours the active device's ``pmbus_driver_info``; +when no chip match has been registered, VOUT falls back to LINEAR16 +driven by ``VOUT_MODE`` and the other sensors fall back to LINEAR11. + +Vendor namespace +~~~~~~~~~~~~~~~~ + +Per chip drivers and board files publish chip specific subcommands +in the ``pmbus <vendor> ...`` namespace by calling +``pmbus_register_vendor_handler()`` at init time. The framework +dispatches ``pmbus mps last``, ``pmbus mps clear last``, and +``pmbus mps clear force`` to the MPS handler when the active +device matches the ``mps`` vendor. Additional vendor handlers for +``lltc``, ``renesas``, etc. land alongside the per chip drivers +that need them. + +Relationship to ``vdd_override`` / ``vdd_read`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The NXP Layerscape ``vdd_override <mV>`` and ``vdd_read`` commands +remain available in their original form for compatibility with +existing AVS production scripts. The new ``pmbus vout`` and +``pmbus vout <uV>`` subcommands cover the read and single shot +write paths against the same chips, but do not implement +``vdd_override``'s full sequence (board drop compensation, fuse +target derivation, multi step convergence loop, atomic +``PAGE_PLUS_WRITE`` block transaction, ``WRITE_PROTECT`` dance). +For interactive bring up ``pmbus vout`` is sufficient; for +production AVS, ``vdd_override`` stays canonical. + +Lifecycle: from board boot to Linux handoff +------------------------------------------- + +The PMBus framework spans the entire U-Boot lifecycle. This section +walks the boot timeline phase by phase, showing when each piece +comes online and how the regulator uclass and the ``pmbus`` CLI +converge on the same chip. + +Timeline overview +~~~~~~~~~~~~~~~~~ + +:: + + Phase 0 chip power on chip ramps to NVM default VOUT + Phase 1 boot ROM / SPL / TF-A PMBus typically untouched + Phase 2 U-Boot relocation, DM init regulators bound, not probed + Phase 3 first regulator probe chip driver runs, framework lights up + Phase 4 board hooks / boot scripts snapshot, AVS trim, gating + Phase 5 Linux handoff DT passed, chip state preserved + Phase 6 Linux runtime kernel pmbus driver takes over + +Phase 0: chip power on +~~~~~~~~~~~~~~~~~~~~~~ + +When the regulator chip receives its input voltage, it ramps its +output to the VOUT default programmed into its NVM at factory +provisioning. PMBus is silent: no software runs anywhere on the +SoC yet. + +Phase 1: pre U-Boot stages +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Boot ROMs, secondary boot loaders (SPL, ARM TF-A BL2 / BL31) +typically do not touch PMBus. They focus on PLLs, DDR PHY init, +and bringing up enough hardware to load the next stage. Some +platforms have a pre U-Boot AVS path in board specific TF-A +code that writes ``VOUT_COMMAND`` from a fuse derived target; +that path is independent of the U-Boot framework described here. + +Phase 2: U-Boot relocation and DM init +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +After relocation, U-Boot binds device tree nodes to drivers but +does not probe them. UCLASS_REGULATOR devices for PMBus chips +are bound (driver and DT match resolved) but the ``.probe`` +callback has not run yet. + +Framework state at this point: + +* chip match registry: empty +* vendor handler registry: empty +* active device: none +* regulator uclass: devices bound, none probed + +Phase 3: lazy regulator probe +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The first caller into the regulator uclass for a given chip +triggers the chip driver's ``.probe``. Typical first callers: + +* a board ``EVENT_SPY`` at ``EVT_LAST_STAGE_INIT`` (boot snapshot) +* a U-Boot script: ``regulator dev <name>; regulator value`` +* the ``pmbus dev <name>`` CLI command (resolves to the regulator) +* another DT consumer with a ``regulator-supplies`` reference + +The probe chain looks like this:: + + <chip>_probe(dev) + pmbus_regulator_probe_common(dev, &<chip>_info, page) + dev_read_addr(dev) -> reg = <addr> + i2c_get_chip(dev->parent, addr) -> I2C chip handle + priv->i2c_dev = handle + priv->info = &<chip>_info + priv->page = page + (page > 0) write PMBUS_PAGE + <chip>_identify_vout(priv->i2c_dev) [optional] + read VOUT_MODE; refine info->format[PSC_VOLTAGE_OUT] + pmbus_regulator_apply_voltage_scale(dev, fb_div) [optional] + write PMBUS_VOUT_SCALE_LOOP if DT property set + pmbus_register_chip(&<chip>_match) [idempotent] + pmbus_register_vendor_handler(&<chip>_op) [idempotent] + +Once probed, three independent surfaces are functional against +the same chip: + +* the regulator uclass API (``regulator_get_value``, + ``regulator_set_value``, ``regulator_get_enable``, + ``regulator_set_enable``) +* the ``pmbus`` CLI (chip is reachable by name through + ``pmbus_resolve_by_name()``, by raw ``<bus>:<addr>`` through + ``pmbus_set_active()``) +* the chip's vendor extension subcommands (``pmbus <vendor> ...``) + +Phase 4: board hooks and boot scripts +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Boards hook the boot flow at well known points to drive board +specific PMBus behaviour. The framework prescribes none of these; +they are conventions: + +* boot time rail snapshot. An ``EVENT_SPY`` at + ``EVT_LAST_STAGE_INIT`` reads telemetry through the regulator + uclass and prints a one shot summary to the console. Useful + for operator visibility on serial during bring up. + +* pre kernel rail trim (AVS). A board hook in + ``board_late_init`` or a custom event spy reads a fuse derived + target voltage and calls ``regulator_set_value_force()`` to + trim the SoC core rail before kernel handoff. + +* Linux handoff gate. A bootcmd reads the rail voltage + through the regulator command and refuses to boot Linux if + the rail is outside the expected range. + +Phase 5: Linux handoff +~~~~~~~~~~~~~~~~~~~~~~ + +When U-Boot transfers control to Linux, it passes the device +tree (potentially patched). The DT compatible strings for PMBus +regulators must match those in the upstream kernel binding so +the kernel's ``drivers/hwmon/pmbus/<chip>.c`` picks them up. +Property names are shared with the kernel binding +(``regulator-name``, ``regulator-min-microvolt``, +``mps,vout-fb-divider-ratio-permille``, etc.); see "DT alignment +with Linux" below. + +The chip itself is left in the state U-Boot wrote it to. If +U-Boot trimmed VOUT, the chip stays at the trimmed voltage +through handoff. ``CLEAR_FAULTS`` state is preserved unless an +operator explicitly issued one. + +Phase 6: Linux runtime +~~~~~~~~~~~~~~~~~~~~~~ + +Linux's ``drivers/hwmon/pmbus/pmbus_core.c`` probes the chip, +exposes telemetry under ``/sys/class/hwmon``, and takes over +runtime voltage management through its regulator subsystem. +The hwmon framework polls periodically; U-Boot does not. + +Operation paths through the regulator uclass +-------------------------------------------- + +After the first probe completes, calls into the regulator uclass +for a PMBus chip flow through the shared helper. + +Read VOUT:: + + regulator_get_value(dev) + -> dm_regulator_ops->get_value + -> pmbus_regulator_get_value(dev) + pmbus_regulator_select_page(priv) + pmbus_read_byte(priv->i2c_dev, VOUT_MODE, &mode) + pmbus_read_word(priv->i2c_dev, READ_VOUT, &raw) + pmbus_reg2data(priv->info, PSC_VOLTAGE_OUT, raw, mode) + -> reg2data_linear16 (mode = 0) + -> reg2data_direct (chip configured for DIRECT) + return engineering value (microvolts) + +Write VOUT:: + + regulator_set_value(dev, uV) + -> dm_regulator_ops->set_value + -> pmbus_regulator_set_value(dev, uV) + pmbus_regulator_select_page(priv) + pmbus_read_byte(VOUT_MODE) + check (mode == LINEAR) [LINEAR16 only today] + raw = pmbus_data2reg_linear16(uV, mode) + dm_i2c_write(VOUT_COMMAND, raw) + +Read / write enable bit:: + + regulator_get_enable(dev) + -> pmbus_regulator_get_enable(dev) + pmbus_read_byte(OPERATION) & PB_OPERATION_ON + + regulator_set_enable(dev, on) + -> pmbus_regulator_set_enable(dev, on) + read OPERATION, set or clear PB_OPERATION_ON, write back + +Bus traffic per call: + +* ``get_value`` : 1 byte read (VOUT_MODE) + 1 word read (READ_VOUT) + + 1 byte write (PAGE) when ``page > 0`` +* ``set_value`` : 1 byte read (VOUT_MODE) + 1 word write (VOUT_COMMAND) + + 1 byte write (PAGE) when ``page > 0`` +* ``get_enable`` : 1 byte read (OPERATION) +* ``set_enable`` : 1 byte read (OPERATION) + 1 byte write (OPERATION) + +Common board hook patterns +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Boot time rail snapshot:: + + static int my_board_pmbus_snapshot(void) + { + struct udevice *reg; + + if (regulator_get_by_platname("MY_RAIL", ®)) + return 0; + printf("MY_RAIL: VOUT = %d uV, enabled = %d\n", + regulator_get_value(reg), + regulator_get_enable(reg)); + return 0; + } + EVENT_SPY_SIMPLE(EVT_LAST_STAGE_INIT, my_board_pmbus_snapshot); + +The first call to ``regulator_get_value()`` triggers the chip +driver's ``.probe``, which seeds the chip match and vendor +extension registries. Subsequent ``pmbus`` CLI commands work +without further setup. + +Pre kernel rail trim (AVS):: + + int board_late_init(void) + { + struct udevice *reg; + int target_uV = compute_avs_target(); + + if (regulator_get_by_platname("VDD_CORE", ®)) + return 0; + return regulator_set_value_force(reg, target_uV); + } + +Use ``regulator_set_value_force()`` when the target may sit +outside the DT declared ``regulator-min-microvolt`` / +``regulator-max-microvolt`` range; force bypasses the bounds +check. + +Adding a new PMBus chip from scratch +------------------------------------ + +Use this path when the chip has no Linux driver yet, or when you want +to validate the U-Boot port against the datasheet alone. + +1. Confirm PMBus 1.x compliance level. Locate in the chip + datasheet: + + which PMBus standard command codes the chip implements + (``READ_VIN``, ``READ_VOUT``, ``STATUS_WORD``, ``MFR_ID`` ...), + which numeric format(s) it uses for VOUT (LINEAR16 with the + exponent in ``VOUT_MODE``, DIRECT with chip specific m/b/R, or + VID with one of the documented VRM tables), + which numeric format it uses for VIN, IIN, IOUT, TEMPERATURE + (most commonly LINEAR11; some MPS / MPS derivative chips use + DIRECT instead), + how many output rails it exposes (single page parts vs. + multi rail PMBus pages). + +2. Declare a ``struct pmbus_driver_info``. Wire each sensor + class to one ``enum pmbus_data_format``, plus the m/b/R triple if + the format is DIRECT:: + + static struct pmbus_driver_info chipname_info = { + .pages = 1, + .format[PSC_VOLTAGE_IN] = pmbus_fmt_direct, + .format[PSC_VOLTAGE_OUT] = pmbus_fmt_linear, + .format[PSC_CURRENT_OUT] = pmbus_fmt_direct, + .format[PSC_TEMPERATURE] = pmbus_fmt_direct, + .m[PSC_VOLTAGE_IN] = 4, .R[PSC_VOLTAGE_IN] = 1, + .m[PSC_CURRENT_OUT] = 16, .R[PSC_CURRENT_OUT] = 0, + .m[PSC_TEMPERATURE] = 1, .R[PSC_TEMPERATURE] = 0, + }; + +3. Bind to a DT compatible. Use the lowercase ``vendor,chip`` + tuple Linux uses (see "DT alignment with Linux" below). Add the + driver under ``drivers/power/regulator/`` matching the existing + skeleton (``fan53555.c``, ``pca9450.c``). + +4. Rely on the DT binding from the Linux kernel which is imported into + U-Boot under ``dts/upstream/Bindings/`` (for PMBus chips, + ``dts/upstream/Bindings/hwmon/pmbus/``). + +5. Smoke test. With the chip wired up in DT:: + + => regulator dev <name> + => regulator value + => regulator info + + Numbers should match the bench measurement to within the chip's + advertised LSB. + +Porting an existing Linux PMBus driver to U-Boot +------------------------------------------------ + +When the chip already has a ``linux/drivers/hwmon/pmbus/<chip>.c``, +that driver is the authoritative reference for format, coefficients, +and quirks. Take what carries; leave what does not. + +What carries verbatim +~~~~~~~~~~~~~~~~~~~~~ + +* Numeric formats (``format[PSC_*]``). +* DIRECT coefficients (``m[]``, ``b[]``, ``R[]``). +* Per page count and per page functionality bits (``pages``, + ``func[]``). +* VOUT_MODE driven per chip identify hook (e.g. MPQ8785's + switch between LINEAR16 and VID coerced DIRECT m=64 R=1). +* Vendor register addresses for chip specific quirks (fault + history, scale-loop, page mapping). + +What does not carry +~~~~~~~~~~~~~~~~~~~~~~~ + +* ``hwmon_device_register()`` and the attribute groups it consumes. +* ``struct pmbus_data`` / ``update_lock`` / ``last_updated`` + U-Boot has no caching layer. +* ALERT# IRQ wiring; U-Boot is single threaded boot code. +* Fan control hooks (``read_fan_*``, ``set_pwm_*``). +* Virtual register handling (``PMBUS_VIRT_READ_VIN_*`` etc.); those + are entirely a hwmon publication aid. +* ``module_i2c_driver(...)`` and ``MODULE_*`` macros; U-Boot uses + ``U_BOOT_DRIVER(...)``. + +Worked example: porting MPQ8785 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Linux's ``drivers/hwmon/pmbus/mpq8785.c`` is 193 LOC; the U-Boot +equivalent is ~150 LOC. + +The ``mpq8785_info`` struct transcribes verbatim:: + + .pages = 1, + .format[PSC_VOLTAGE_IN] = direct, .m[PSC_VOLTAGE_IN] = 4, .R[PSC_VOLTAGE_IN] = 1, + .format[PSC_CURRENT_OUT] = direct, .m[PSC_CURRENT_OUT] = 16, .R[PSC_CURRENT_OUT] = 0, + .format[PSC_TEMPERATURE] = direct, .m[PSC_TEMPERATURE] = 1, .R[PSC_TEMPERATURE] = 0, + +The VOUT format is decided at probe time from VOUT_MODE bits[7:5] : +mode 0 means LINEAR16, mode 1 or 2 means DIRECT m=64 R=1 (the chip's +"VID" mode is coerced to DIRECT by the driver). Translate Linux's +``mpq8785_identify()`` 1:1. + +The per chip quirks that carry over: + +* MPS NVM string byte order: chip stores ``S P M`` for the human + string ``MPS``. ``pmbus_read_string()`` accepts a ``reverse_bytes`` + flag for this case. +* ``mps,vout-fb-divider-ratio-permille`` DT property maps to + ``VOUT_SCALE_LOOP`` write at probe time. + +The quirks that do not carry over: + +* The ``PMBUS_VIRT_*`` virtual sensor wiring. Drop entirely. +* The ``hwmon_chip_info`` attribute group registration. +* The ``MODULE_AUTHOR`` / ``MODULE_LICENSE`` declarations. + +Using the generic ``compatible = "pmbus"`` driver +------------------------------------------------- + +When a board carries a PMBus chip without a per chip U-Boot driver, +the catch all ``drivers/power/regulator/pmbus_generic.c`` (Layer 3b) +binds against ``compatible = "pmbus"``. It auto detects format via +``VOUT_MODE`` and ``PMBUS_QUERY`` (where the chip supports it) and +provides telemetry + voltage set/get against the standard PMBus 1.x +subset. + +Decision tree: + +1. Try the generic driver first. Add the regulator node to the + board DT with ``compatible = "pmbus"`` plus the standard + regulator properties. Boot, run ``regulator value``, compare + against bench measurement. +2. Switch to a per chip driver only when the generic one is + wrong: telemetry shows wrong values (chip uses DIRECT with + non default coefficients), an alert can't be decoded (chip has + vendor specific status bits), AVS is needed (the boot path has + to actively trim VOUT before kernel handoff), or the chip has an + ADDR-pin auto promotion / VID coercion / vendor register quirk. + +DT alignment with Linux +----------------------- + +The same ``.dts`` file should work under both U-Boot (BL33) and Linux +post handoff. To make that possible: + +* Reuse the upstream Linux compatible for every PMBus chip. Look + in ``linux/Documentation/devicetree/bindings/hwmon/pmbus/`` and + ``linux/Documentation/devicetree/bindings/regulator/``. The + ``<vendor>,<chip>`` tuple from the kernel binding goes into U-Boot's + ``of_match_table`` unchanged. +* Reuse Linux property names verbatim: ``regulator-name``, + ``regulator-min-microvolt``, ``regulator-max-microvolt``, + ``regulator-boot-on``, ``regulator-always-on``, + ``mps,vout-fb-divider-ratio-permille``, etc. +* The DT binding is the kernel's, imported under + ``dts/upstream/Bindings/`` (PMBus chips live in + ``dts/upstream/Bindings/hwmon/pmbus/``). + +Multi rail/multi page chips (e.g. ISL68137 with seven outputs) +declare each rail as a child regulator node with ``reg = <page>``; +each child binds as a UCLASS_REGULATOR with that PMBus PAGE setting +applied at every read/write. + +Common pitfalls +--------------- + +These have all bitten contributors during nbxv3 bring up; record them +here so the next port doesn't repeat them. + +* VOUT_MODE/DIRECT format confusion. Most generic PMBus call + sites assume LINEAR16. Several MPS chips report VOUT in DIRECT + format with chip specific m/b/R after a single VOUT_MODE read, + the same chip read at the same address produces different + numbers depending on the format the driver applies. Always read + ``VOUT_MODE`` at probe time and switch the decoder accordingly. + Linux's per chip ``identify()`` callbacks document the exact + rules; copy them rather than guessing. +* SMBus block read protocol. Some I2C controllers strict check + block read transactions: the master must read the length byte + first, then reissue the read for the payload. Over reading a + fixed length and ignoring the length byte works on lenient + controllers but errors on strict ones. ``pmbus_read_string()`` + does the two stage read; use it. +* I2C bus number stability. ``uclass_get_device_by_seq()`` + uses the DT alias index (``i2c0`` -> ``UCLASS_I2C`` seq 0) when + aliases are declared, otherwise falls back to probe order which + varies with which controllers are enabled in the defconfig. + Always declare DT aliases for I2C buses you reference by index. +* ADDR-pin auto addressessing. Some chips (notably MPS parts) decode + their PMBus 7-bit address from an external resistor divider on + ADDR_VBOOT. The "default" address in the datasheet is the + factory fused slot; a board with a different divider or a die + with a different revision can land in another window. If the + driver hardcodes the default and the board side scan finds the + chip in another window, auto promote the working address rather + than failing the probe. +* MFR string byte order. Most PMBus chips return ``MFR_ID`` + characters in human order. Some MPS personalities reverse them. + Pass ``reverse_bytes=true`` to ``pmbus_read_string()`` for those; + spec compliant chips pass false. + +References +---------- + +* Linux PMBus core: ``linux/drivers/hwmon/pmbus/pmbus_core.c``, + decoder reference; ignore the hwmon publication and caching layers. +* Linux PMBus header: ``linux/drivers/hwmon/pmbus/pmbus.h``; API + surface reference; many constants and the ``struct + pmbus_driver_info`` shape are mirrored verbatim into U-Boot's + ``include/pmbus.h``. +* Linux DT bindings: + ``linux/Documentation/devicetree/bindings/hwmon/pmbus/``. |
