I have worked with the EC source code for a while, and had it working back in FW16 AMD 7040 lotus BIOS 3.0.5.
BIOS 4.0.4 changes quite a lot.
Instructions for how to do it can be found here:
I have tested the process on Ubuntu 26.04, but it should work for many other Linux distros.
I can now track down some of the bugs in the EC code on FW16 BIOS 4.0.4.
The “tulip” branch of EC should also work on the following:
azalea - framework laptop 13 amd 7040
tulip - Framework Laptop 16 Ryzen AI 300
dogwood - Framework Desktop - AMD AI 300 Series
sunflower - NOT
marigold - NOT
lotus - Framework Laptop 16 - AMD 7040 Series
lilac - Framework Laptop 13 - AMD AI 300 Series
banshee - NOT
Well, I have tracked down and fixed another EC bug.
It was a really difficult one to track down.
The initial symptom was that in some rare cases, the power adapter plug/unplug would not be detected. Investigating that, resulted in seeing that the Make/Model names/strings being read from the smart battery were missing characters. This led to the wrong battery profile being used, that then led to AC on/off state transitions not working. So, this was the first hint that something was not right with the I2C transfers.
The EC i2c_transfer() transactions were unreliable.
This resulting in, for example, the symptom of the UCSI PPM_RESET failing and other odd behavior.
Its a guess, but it might also be causing some of the stuck in 544 Mhz problems.
The reason it was so difficult to track down is because some transactions worked and some did not. They just silently fail. No indication of failed transaction. The problematic ones were the block writes. The write was happening, but the cypd USB PD chip was not seeing the transaction. I had to then go looking for something on the cypd USB PD chip i2c that I could use as a scratchpad. I could write to it, and then read it back to see if the write worked. There is no documentation on the cypd USB PD chip api, but I eventually found a scratchpad, and then a solution, as one can see from the patch linked to above.
The problem turned out to be split i2c_transfer().
If one does half the transaction in one call to i2c_transfer() with START set, and then the second half of the transaction in another call to i2c_transfer() with STOP set. It is unreliable.
Putting both parts into i2c_msg msg[ ] and then doing a single i2c_transfer() is 100% reliable.
It also seems to mainly be a problem associated with i2c writes. It seems that doing i2c reads, and splitting them across i2c_transfer() does not cause so many problems.
I think if the EC needs to do more reliable i2c transactions writes. It should also do a i2c transaction read, to double check that the data sent, arrived OK at the destination.
The I2C ACKs are supposed to help with making i2c more reliable, but it appears the EC code has no way, currently, of detecting the errors. There might be a i2c_transfer() callback, that may exist, but is not currently being used.
Here is another i2c function that I have fixed. It had the same problem of spliting the START and STOP i2c_transfer().
static int platform_ec_i2c_write(const int port, const uint16_t addr_flags,
const uint8_t *out, int out_size)
This function is used to update the EC → APU/CPU with the new PMF settings.
e.g. “PMF: SPL 45000mW, sPPT 54000mW, fPPT 65000mW, p3T 227000mW, ao_sppt 0mW”
If it fails, it will result in the settings not being successfully sent to the APU. This is separate from APU SMU hang problems, that are caused by problems on the APU side.
charge transition counter, so one can detect “battery flipping”
fine level monitoring/data capture of voltage/current using the various sensors available to the EC. Useful for discovering peak watts power draw by gpu/cpu and measuring idle watts more accurately.
ectool command to read the battery temp using the smart battery internal temp sensor. The EC has always used this, but never before made it accessible to user space.
Made i2c writes more reliable. Improves battery monitoring, power adapter detection, and EC → APU SMU reliability.
Future features i wish to add to the EC:
the mainboard can potentially supply 15W to more than one usb devices. One on the left, one on the right. The use case is when plugging in two NVME enclosures to copy data between them.
The FW16 has a 81Wh battery. Powering 2 x15W of usb devices is going to drain that pretty quickly. So, obviously only reasonable to do when a power adapter is connected.
the ports on the FW16 are dual mode power, so they can source and sink. When connecting some external power bricks that can source and sink power.
When both sides are dual mode like this, confusion and problems happen. Make an ectool command so one can force the FW16 side to be the source or the sink, thus removing the confusion.
add an ectool command to adjust the 3A vs 1.5A Rp resistor on each usb c port. The FW16 defaults to the 1.5A Rp, but the 3A Rp improves compatibility with some problem devices out there. I.e. some iphones. E.g. set the slot 1 to be 3A Rp, and then just use that slot with the problem usb devices.
Common devices this helps with are the ones that cycle through connect/disconnect about once a second.
Game mode.
Game performance suffers when charging the battery. During the game the battery will discharge slightly during peak loads. Game mode would limit the charge current to a low trickle, thus ensuring max power to the game for long periods. Otherwise, the battery charge will happilly use 80W, that causes game stutter.
Note: i don’t actually know if this will actually reduce stutter, it might instead need different charger chips.
Improver power transitions when plugging in and removing power adapter.
Currently, when transitioning from SRP 20V mode to ERP 36V mode, it goes via a 2.5W step. I.e. switches power off while switching volts. This shows user detectable slowdown when plugging and unplugging the power adapter. There are also use cases when this causes failure to boot or reboot.
Experiment with other transitions not currently implemented. E.g. from SRP 20V to ERP 20V, and then gradually step up the voltage over time to 36V. Thus not needing the 2.5W step.
(See below)
currently on FW16 AMD 7840HS, BIOS 4.0.4, “reboot rw” and “sysjump rw” do not work reliably. A few attempts from an EC CCD are needed before it works. Previously “reboot rw” worked from the EFI shell on BIOS 3.0.5. Investigate why this fails.
(See below)
ROOT CAUSE analysis complete. UNABLE to fix in EC source code:
6) if one uses the 36V FW power adapter. When it is supplying 36V, the linux kernel only registers it as 5V and shows only 5V in lmsensors/sensors output. Find where the 36V information is getting lost, and get lmsensors to report it. ← Root Cause: Bug in CYPD USB PD firmware. See (8)
8) Try to fix “ucsi_acpi USBC000:00: unknown error 256”. This is a bug associated with enumerating PDOs from any device that has more than 4 PDOs.
For example, the FW16 Power adapter has 7 PDOs, but Linux only sees 4 PDOs and 1 corrupt/bogus PDO. ← Root Cause: Bug in CYPD USB PD firmware.
Note: (8) is a problem. The CYPD USB PD chip is buggy, and does not respond to the UCSI command: “0x0000 0007 0482 0010” I.e. Command 0x10:GET_PDOS with PDO offset 4.
It deals with this GET_PDOS command correctly: “0x0000 0007 0082 0010”
Test case, is using the FW16 180W power adapter, and doing UCSI GET_PDOS commands to it. It should return 7 PDOs, but only gets the first 4 PDOs correctly. (from the first GET PDOS command, then the second GET PDOS command should get the next 3 PDOs, but it does not.
So, not fixable with either Linux kernel or EC source code changes. Its a CYPD USB PD firmware bug.