All of lore.kernel.org
 help / color / mirror / Atom feed
* ucsi_acpi: ThinkPad X13 Gen 1 (AMD) - VERSION reads 0, and GET_PDOS returns one PDO per command
@ 2026-10-20  9:55 Vlad Mykhailichenko
  2026-10-26 13:08 ` Heikki Krogerus
  2026-10-26 13:55 ` Mark Pearson
  0 siblings, 2 replies; 3+ messages in thread
From: Vlad Mykhailichenko @ 2026-10-20  9:55 UTC (permalink / raw)
  To: Heikki Krogerus; +Cc: linux-usb, Mark Pearson

Hi Heikki,

On a ThinkPad X13 Gen 1 (AMD Ryzen 5 PRO 4650U, 20UGS2K101, BIOS
R1CET86W 1.55, 2026-05-08), UCSI never comes up, and once it is forced up it
reports only the first source PDO. Seen on 6.18.56 and 7.2.10 (NixOS), with
identical PPM responses on both. The relevant code in ucsi.c looks unchanged
in current master (7.3).

1) ucsi_acpi probe fails silently with -ENODEV

ucsi_acpi loads, USBC000:00 has _STA 0xF, but the device stays unbound and
/sys/class/typec is empty. Nothing is logged, even with dyndbg=+p. A manual
bind returns ENODEV:

   # echo USBC000:00 > /sys/bus/platform/drivers/ucsi_acpi/bind
   echo: write error: No such device

USBC000:00 is not in devices_deferred. The silent path is the version check
in ucsi_register():

   if (!ucsi->version)
           return -ENODEV;

The firmware's SSDT (LENOVO UsbCTabl rev 1) declares the mailbox as
\_SB.UBTC.USBC at 0xCC235000 (0x30 bytes; VER1, VER2, RSV1, RSV2, CCI0-3,
CTL0-7, MGI0-F, MGO0-F). Its _DSM read path (ECRD) copies CCI and MGI 
from the
EC. Nothing in any table writes VER1/VER2, so VERSION presumably stays 0
unless the BIOS fills it during POST, which it evidently does not. I could
not read the mailbox directly because of STRICT_DEVMEM.

As a workaround, an additional SSDT from the initrd (not a replacement of
UsbCTabl) sets VERSION to 1.0 at load time:

   DefinitionBlock ("", "SSDT", 2, "WATTSN", "UcsiVer", 0x00000001)
   {
       External (\_SB.UBTC.VER1, FieldUnitObj)
       External (\_SB.UBTC.VER2, FieldUnitObj)

       If (CondRefOf (\_SB.UBTC.VER2))
       {
           If (((\_SB.UBTC.VER1 == Zero) && (\_SB.UBTC.VER2 == Zero)))
           {
               \_SB.UBTC.VER2 = One
           }
       }
   }

With that, ucsi_acpi binds, port0/port1 register and are linked to
usb2/usb3-port1 and usb4/usb5-port1, and no PPM errors are logged. On 7.2.10
the existing reserved-bit check also fires, so GET_CAPABILITY from the same
firmware sets bit 7 of bNumConnectors as well (0x82 for 2 connectors):

   ucsi_acpi USBC000:00: UCSI: Invalid num_connectors 130. Likely buggy FW

2) GET_PDOS returns a single PDO regardless of the number requested

With a 45 W USB PD charger on connector 2, the partner's source caps show
only "1:fixed_supply 5000mV 3000mA". ucsi-source-psy-USBC000:002 reports
voltage_now 0, current_now 2250000, current_max 3000000, voltage_min/max
5000000.

GET_PDOS via debugfs (partner, source, connector 2), one PDO at a time:

   offset 0  0x400820010 -> ...5383ff01 0801912c   fixed  5 V 3.00 A
   offset 1  0x401820010 -> ...5383ff01 0002d12c   fixed  9 V 3.00 A
   offset 2  0x402820010 -> ...5383ff01 0003c12c   fixed 12 V 3.00 A
   offset 3  0x403820010 -> ...5383ff01 0004b12c   fixed 15 V 3.00 A
   offset 4  0x404820010 -> ...5383ff01 000640e1   fixed 20 V 2.25 A
   offset 5  0x405820010 -> ...5383ff01 c8dc325a   PPS 5.0-11.0 V 4.5 A
   offset 6  0x406820010 -> ...5383ff01 00000000

Four at a time, only the first dword of the response is a valid PDO and the
rest looks stale:

   offset 0  0x700820010 -> 0x01100200012000015383ff010801912c
   offset 4  0x704820010 -> 0x01100200012000015383ff01000640e1

ucsi_get_pdos() reads one PDO, takes num_pdos < UCSI_MAX_PDOS as the end of
the list, and stops. GET_CONNECTOR_STATUS shows the RDO selecting object
position 5, operating current 2.25 A:

   0x20012 -> 0x0110020001200001538384e1202b5b60

so the contract is 20 V / 2.25 A, but the psy cannot report the voltage,
because the kernel only has PDO 1.

Questions:

- Would a dev_err()/dev_warn() for the version == 0 case be acceptable? It
   would have saved most of this.
- For VERSION, is a DMI quirk that assumes 1.0 acceptable, or would you 
rather
   this stays a firmware problem for Lenovo? Mark, is this something 
that can
   be raised with the BIOS team?
- For GET_PDOS, would you take a fallback (or a quirk) that reads one PDO at
   a time when a multi-PDO read returns exactly one?

I am happy to test patches on this machine.

Thanks,
Vlad Mykhailichenko


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: ucsi_acpi: ThinkPad X13 Gen 1 (AMD) - VERSION reads 0, and GET_PDOS returns one PDO per command
  2026-10-20  9:55 ucsi_acpi: ThinkPad X13 Gen 1 (AMD) - VERSION reads 0, and GET_PDOS returns one PDO per command Vlad Mykhailichenko
@ 2026-10-26 13:08 ` Heikki Krogerus
  2026-10-26 13:55 ` Mark Pearson
  1 sibling, 0 replies; 3+ messages in thread
From: Heikki Krogerus @ 2026-10-26 13:08 UTC (permalink / raw)
  To: Vlad Mykhailichenko; +Cc: linux-usb, Mark Pearson

Hi Vlad,

On Tue, Oct 20, 2026 at 12:55:36PM +0300, Vlad Mykhailichenko wrote:
> Hi Heikki,
> 
> On a ThinkPad X13 Gen 1 (AMD Ryzen 5 PRO 4650U, 20UGS2K101, BIOS
> R1CET86W 1.55, 2026-05-08), UCSI never comes up, and once it is forced up it
> reports only the first source PDO. Seen on 6.18.56 and 7.2.10 (NixOS), with
> identical PPM responses on both. The relevant code in ucsi.c looks unchanged
> in current master (7.3).
> 
> 1) ucsi_acpi probe fails silently with -ENODEV
> 
> ucsi_acpi loads, USBC000:00 has _STA 0xF, but the device stays unbound and
> /sys/class/typec is empty. Nothing is logged, even with dyndbg=+p. A manual
> bind returns ENODEV:
> 
>   # echo USBC000:00 > /sys/bus/platform/drivers/ucsi_acpi/bind
>   echo: write error: No such device
> 
> USBC000:00 is not in devices_deferred. The silent path is the version check
> in ucsi_register():
> 
>   if (!ucsi->version)
>           return -ENODEV;
> 
> The firmware's SSDT (LENOVO UsbCTabl rev 1) declares the mailbox as
> \_SB.UBTC.USBC at 0xCC235000 (0x30 bytes; VER1, VER2, RSV1, RSV2, CCI0-3,
> CTL0-7, MGI0-F, MGO0-F). Its _DSM read path (ECRD) copies CCI and MGI from
> the
> EC. Nothing in any table writes VER1/VER2, so VERSION presumably stays 0
> unless the BIOS fills it during POST, which it evidently does not. I could
> not read the mailbox directly because of STRICT_DEVMEM.
> 
> As a workaround, an additional SSDT from the initrd (not a replacement of
> UsbCTabl) sets VERSION to 1.0 at load time:
> 
>   DefinitionBlock ("", "SSDT", 2, "WATTSN", "UcsiVer", 0x00000001)
>   {
>       External (\_SB.UBTC.VER1, FieldUnitObj)
>       External (\_SB.UBTC.VER2, FieldUnitObj)
> 
>       If (CondRefOf (\_SB.UBTC.VER2))
>       {
>           If (((\_SB.UBTC.VER1 == Zero) && (\_SB.UBTC.VER2 == Zero)))
>           {
>               \_SB.UBTC.VER2 = One
>           }
>       }
>   }
> 
> With that, ucsi_acpi binds, port0/port1 register and are linked to
> usb2/usb3-port1 and usb4/usb5-port1, and no PPM errors are logged. On 7.2.10
> the existing reserved-bit check also fires, so GET_CAPABILITY from the same
> firmware sets bit 7 of bNumConnectors as well (0x82 for 2 connectors):
> 
>   ucsi_acpi USBC000:00: UCSI: Invalid num_connectors 130. Likely buggy FW
> 
> 2) GET_PDOS returns a single PDO regardless of the number requested
> 
> With a 45 W USB PD charger on connector 2, the partner's source caps show
> only "1:fixed_supply 5000mV 3000mA". ucsi-source-psy-USBC000:002 reports
> voltage_now 0, current_now 2250000, current_max 3000000, voltage_min/max
> 5000000.
> 
> GET_PDOS via debugfs (partner, source, connector 2), one PDO at a time:
> 
>   offset 0  0x400820010 -> ...5383ff01 0801912c   fixed  5 V 3.00 A
>   offset 1  0x401820010 -> ...5383ff01 0002d12c   fixed  9 V 3.00 A
>   offset 2  0x402820010 -> ...5383ff01 0003c12c   fixed 12 V 3.00 A
>   offset 3  0x403820010 -> ...5383ff01 0004b12c   fixed 15 V 3.00 A
>   offset 4  0x404820010 -> ...5383ff01 000640e1   fixed 20 V 2.25 A
>   offset 5  0x405820010 -> ...5383ff01 c8dc325a   PPS 5.0-11.0 V 4.5 A
>   offset 6  0x406820010 -> ...5383ff01 00000000
> 
> Four at a time, only the first dword of the response is a valid PDO and the
> rest looks stale:
> 
>   offset 0  0x700820010 -> 0x01100200012000015383ff010801912c
>   offset 4  0x704820010 -> 0x01100200012000015383ff01000640e1
> 
> ucsi_get_pdos() reads one PDO, takes num_pdos < UCSI_MAX_PDOS as the end of
> the list, and stops. GET_CONNECTOR_STATUS shows the RDO selecting object
> position 5, operating current 2.25 A:
> 
>   0x20012 -> 0x0110020001200001538384e1202b5b60
> 
> so the contract is 20 V / 2.25 A, but the psy cannot report the voltage,
> because the kernel only has PDO 1.
> 
> Questions:
> 
> - Would a dev_err()/dev_warn() for the version == 0 case be acceptable? It
>   would have saved most of this.
> - For VERSION, is a DMI quirk that assumes 1.0 acceptable, or would you
> rather
>   this stays a firmware problem for Lenovo? Mark, is this something that can
>   be raised with the BIOS team?

This one really should be fixed in the firmware.

> - For GET_PDOS, would you take a fallback (or a quirk) that reads one PDO at
>   a time when a multi-PDO read returns exactly one?
> 
> I am happy to test patches on this machine.

And I would be happy to see patches. It sounds like you are capable
and willing to write the code, so just do it. That's how things are
proposed in Linux kernel - with code.

Thanks,

-- 
heikki

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: ucsi_acpi: ThinkPad X13 Gen 1 (AMD) - VERSION reads 0, and GET_PDOS returns one PDO per command
  2026-10-20  9:55 ucsi_acpi: ThinkPad X13 Gen 1 (AMD) - VERSION reads 0, and GET_PDOS returns one PDO per command Vlad Mykhailichenko
  2026-10-26 13:08 ` Heikki Krogerus
@ 2026-10-26 13:55 ` Mark Pearson
  1 sibling, 0 replies; 3+ messages in thread
From: Mark Pearson @ 2026-10-26 13:55 UTC (permalink / raw)
  To: Vlad Mykhailichenko, Heikki Krogerus; +Cc: linux-usb

On Tue, Oct 20, 2026, at 5:55 AM, Vlad Mykhailichenko wrote:
> Hi Heikki,
>
> On a ThinkPad X13 Gen 1 (AMD Ryzen 5 PRO 4650U, 20UGS2K101, BIOS
> R1CET86W 1.55, 2026-05-08), UCSI never comes up, and once it is forced up it
> reports only the first source PDO. Seen on 6.18.56 and 7.2.10 (NixOS), with
> identical PPM responses on both. The relevant code in ucsi.c looks unchanged
> in current master (7.3).
>
> 1) ucsi_acpi probe fails silently with -ENODEV
>
> ucsi_acpi loads, USBC000:00 has _STA 0xF, but the device stays unbound and
> /sys/class/typec is empty. Nothing is logged, even with dyndbg=+p. A manual
> bind returns ENODEV:
>
>    # echo USBC000:00 > /sys/bus/platform/drivers/ucsi_acpi/bind
>    echo: write error: No such device
>
> USBC000:00 is not in devices_deferred. The silent path is the version check
> in ucsi_register():
>
>    if (!ucsi->version)
>            return -ENODEV;
>
> The firmware's SSDT (LENOVO UsbCTabl rev 1) declares the mailbox as
> \_SB.UBTC.USBC at 0xCC235000 (0x30 bytes; VER1, VER2, RSV1, RSV2, CCI0-3,
> CTL0-7, MGI0-F, MGO0-F). Its _DSM read path (ECRD) copies CCI and MGI 
> from the
> EC. Nothing in any table writes VER1/VER2, so VERSION presumably stays 0
> unless the BIOS fills it during POST, which it evidently does not. I could
> not read the mailbox directly because of STRICT_DEVMEM.
>
> As a workaround, an additional SSDT from the initrd (not a replacement of
> UsbCTabl) sets VERSION to 1.0 at load time:
>
>    DefinitionBlock ("", "SSDT", 2, "WATTSN", "UcsiVer", 0x00000001)
>    {
>        External (\_SB.UBTC.VER1, FieldUnitObj)
>        External (\_SB.UBTC.VER2, FieldUnitObj)
>
>        If (CondRefOf (\_SB.UBTC.VER2))
>        {
>            If (((\_SB.UBTC.VER1 == Zero) && (\_SB.UBTC.VER2 == Zero)))
>            {
>                \_SB.UBTC.VER2 = One
>            }
>        }
>    }
>
> With that, ucsi_acpi binds, port0/port1 register and are linked to
> usb2/usb3-port1 and usb4/usb5-port1, and no PPM errors are logged. On 7.2.10
> the existing reserved-bit check also fires, so GET_CAPABILITY from the same
> firmware sets bit 7 of bNumConnectors as well (0x82 for 2 connectors):
>
>    ucsi_acpi USBC000:00: UCSI: Invalid num_connectors 130. Likely buggy FW
>
> 2) GET_PDOS returns a single PDO regardless of the number requested
>
> With a 45 W USB PD charger on connector 2, the partner's source caps show
> only "1:fixed_supply 5000mV 3000mA". ucsi-source-psy-USBC000:002 reports
> voltage_now 0, current_now 2250000, current_max 3000000, voltage_min/max
> 5000000.
>
> GET_PDOS via debugfs (partner, source, connector 2), one PDO at a time:
>
>    offset 0  0x400820010 -> ...5383ff01 0801912c   fixed  5 V 3.00 A
>    offset 1  0x401820010 -> ...5383ff01 0002d12c   fixed  9 V 3.00 A
>    offset 2  0x402820010 -> ...5383ff01 0003c12c   fixed 12 V 3.00 A
>    offset 3  0x403820010 -> ...5383ff01 0004b12c   fixed 15 V 3.00 A
>    offset 4  0x404820010 -> ...5383ff01 000640e1   fixed 20 V 2.25 A
>    offset 5  0x405820010 -> ...5383ff01 c8dc325a   PPS 5.0-11.0 V 4.5 A
>    offset 6  0x406820010 -> ...5383ff01 00000000
>
> Four at a time, only the first dword of the response is a valid PDO and the
> rest looks stale:
>
>    offset 0  0x700820010 -> 0x01100200012000015383ff010801912c
>    offset 4  0x704820010 -> 0x01100200012000015383ff01000640e1
>
> ucsi_get_pdos() reads one PDO, takes num_pdos < UCSI_MAX_PDOS as the end of
> the list, and stops. GET_CONNECTOR_STATUS shows the RDO selecting object
> position 5, operating current 2.25 A:
>
>    0x20012 -> 0x0110020001200001538384e1202b5b60
>
> so the contract is 20 V / 2.25 A, but the psy cannot report the voltage,
> because the kernel only has PDO 1.
>
> Questions:
>
> - Would a dev_err()/dev_warn() for the version == 0 case be acceptable? It
>    would have saved most of this.
> - For VERSION, is a DMI quirk that assumes 1.0 acceptable, or would you 
> rather
>    this stays a firmware problem for Lenovo? Mark, is this something 
> that can
>    be raised with the BIOS team?

I'd missed that I was tagged on this until I saw Heiki's response. Apologies (so many emails...)

I've created internal ticket LO-4726 so we can see if we can repro this and follow up with the FW team.

 - As Heiki notes, probably not suitable for following up on the mailing list as it is a FW issue. Would recommend either a ticket on the Lenovo forum (forums.lenovo.com/linux) or just follow up with me directly by email

 - This platform is old and right at the end of support. A heads up that it's going to be tough to get the FW team engaged at this point. I don't seem to have this HW on hand either so asking my colleagues to see if we can repro. Just flagging that getting a fix in FW, whilst likely the right thing, is going to be a challenge.

Mark

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-10-26 13:55 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-20  9:55 ucsi_acpi: ThinkPad X13 Gen 1 (AMD) - VERSION reads 0, and GET_PDOS returns one PDO per command Vlad Mykhailichenko
2026-10-26 13:08 ` Heikki Krogerus
2026-10-26 13:55 ` Mark Pearson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.