Framework 16 Pcie x 16 slot for expansion bay

It’s definitely my EEPROM file since its for my oculink board and I disable that power rail there as I do not need it.

Ah. How do I build my own custom eeprom file that enables the power rails?

This line for gpio_vsys just needs to be changed to GPIO_FUNC_HIGH like gpu_3v_5v_en and gpio_fan. Then you can compile the configurator and generate the file for x8 config.

3 Likes

Ah, and POWER_G3 might have to be changed to POWER_S3. You could also try to just generate the config from the official repository located in pcie.c file, so using just the -b flag instead of -l and -g.

1 Like

I think someone on here just dumped the EEPROM from a GPU card.
You can use that same image to write to your EEPROM.
It would set the correct PCIe lanes and GPU power.

Ok that fixed it. I am now getting power and GPU fans spin when I turn on the laptop however no GPU is seen and I am unsure if it is a PCIE issue or smth else. I will try debugging it later tonight

Just did some more testing and the GPU seems to never initiate PCIE link training. On boot, CLKREQ is pulled high, Wake is pulled high (GPU fans start spinning) however REFCLK+/- has no signal and PEX_RST# does not get pulled high.
Im not sure if it is supposed to get pulled high by the GPU (Device) or the motherboard (Host) or if i should manually pull it high

You might need to read a PCIe standards doc to get the answer.
One doc explaining the CLKREQ etc, is this one:

1 Like

So PEX_RST# is actively being pulled low by either the host (laptop) or device (GPU) and when low, no PCIE link training will start.
PEX_RST# is low bc it only goes high once REFCLK has stabilized however there is no REFCLK differential signal being produced by host

I speculate that PWR_GOOD needs to be pulled high to 3.3v. My only basis is the 7700s module and trying to see what different connections to the interposer it uses compared to my board . This change would require another PCB redesign…

What does this output? Is it seeing a GPU ? :
sudo ./framework_tool --expansion-bay

Also post the output of this command:
sudo ectool gpioget

The complexity here is that the EC controls some of the PCIe bits, but the CPU also controls other bits.
The EC reads the --expansion-bay information, and the BIOS gets it from the EC, and then uses it to do its PCIe control bits.

The EC also uses it to do its PCIe control bits.

The “ectool gpioget” allows you to see what the EC has done as a result of what it detects in the expansion bay.
Essentially, unless the I2C EEPROM on the expansion bay says its a GPU, the PCIE bus and power to it will be disabled.

The PINs are explained a bit here:

Direction “I” is from the mainboard towards the expansion bay.

1 Like

C:\Framework>framework_tool.exe --expansion-bay
Expansion Bay
Enabled: true
No fault: true
Door closed: true
Board: DualInterposer
Serial Number:
Config: Pcie8x1
Vendor: PcieAccessory
Expansion Bay EEPROM
Valid: true
HW Version: 8.0

C:\Framework>ectool gpioget
1 ec_soc_rsmrst_l 0x60800
0 ec_espi_rst_l 0x10800
1 ec_sci_l 0x60006
1 ovp 0x10000
0 ec_smb_ck0 0x10800
0 ec_smb_da0 0x10800
0 ec_smb_ck1 0x10000
0 ec_smb_da1 0x10000
0 ec_smb_ck2 0x10000
0 ec_smb_da2 0x10000
0 ec_smb_ck3 0x10000
0 ec_smb_da3 0x10000
0 ec_smb_ck4 0x60006
0 ec_smb_da4 0x60006
0 ec_smb_s0_ck5 0x10000
0 ec_smb_s0_da5 0x10000
1 ssd2_pwr_en 0x60000
1 ssd_gpu_sel 0xA0000
0 ec_smb_ck6 0x60006
0 ec_smb_da6 0x60006
0 ec_smb_ck7 0x10000
0 ec_smb_da7 0x10000
1 mic_sw 0x10000
1 gpu_b_gpio00_ec 0x10000
1 gpu_b_gpio01_ec 0x10000
1 gpu_b_gpio02_ec 0x10000
0 gpu_b_gpio03_ec 0x10000
1 fp_en 0x60000
1 5valw_c_en 0x60000
0 gpu_b_dp_hpd 0x60000
1 ec_mute_l 0x60006
1 gpu_3v_5v_en 0x60000
1 wlan_en 0x60000
1 gpu_vsys_en 0x60000
1 apu_ec_int_l 0xA0006
0 rtc_dis 0x60000
0 gpu_vdap_en 0x60000
0 ec_pwm_en 0x60000
1 ac_present_pd_l 0x10000
1 sm_panel_bken_ec 0x60000
0 ec_b2b_dis 0x60000
1 gpu_fan_en 0x60000
1 usb30_hub_en 0x60000
1 module_oc_l 0x10000
1 ec_edp_reset 0x60000
1 gpu_alert_l 0x10000
1 on_off_btn_l 0x10000
1 chassis_open_l 0x10000
1 hw_acav_in 0x10000
1 lid_sw_l 0x10000
1 0p75_1p8valw_pwren 0x60000
1 hub_b_pwr_en 0x60000
1 als_int_l 0x10000
1 pch_pwr_en 0x60000
1 h_prochot_l 0xA0006
1 slp_s3_l 0x10000
1 slp_s5_l 0x10000
1 cam_en 0x60000
1 sys_pwrgd_ec 0x60000
1 vr_on 0x60000
1 susp_l 0x60000
1 left_side 0x60000
0 right_side 0x60000
1 syson 0x60000
1 ec_edp_pwm 0x10000
0 fp_control 0x10000
0 battery_present 0x10000
0 mux_a0 0x60000
0 mux_a1 0x60000
1 mux_a2 0x60000
1 f_beam_open_l 0x10000
1 enbkl_apu 0x10000
1 0p75vs_pwr_en 0x60000
1 apu_aud_pwr_en 0x60000
1 i2c_int_tp_1 0xA0006
1 i2c_int_tp_2 0x10000
0 cam_sw 0x10000
1 spok 0x10000
1 vr_pwrgd 0x10000
1 gpu_i2c_s5_int 0x10000
1 usb_hub_re_en 0x60000
1 wl_rst_l 0x60000
1 ec_sense_al 0x10000
1 en_invpwr 0x60000
1 sleep_l 0x60000
1 pd_b_i2c_int_ec_l 0x10000
1 pd_a_i2c_int_ec_l 0x10000
1 pbtn_out_l 0x60806
1 thermtrip 0x10000
1 dgpu_pwr_en 0x10000
1 apu_ec_int2_l 0xA0006
1 ssd1_pwr_en 0x60000
0 edp_mux_pwm_sw 0x60000

No idea what the gpioget info means

The laptop turns on the power to the interposer which then gets converted from the 15-20V down to 12V and 3.3v to meet the PCIE slot 75w requirement.
I believe my issue is that my board does not pull PWR_GOOD (PL1) up to 3.3v to signal the motherboard that power to the device (the 7700s in the case of Framework’s GPU module) is stable and that the next steps to PCIE link training can proceed.

I was referencing @Filip 's schematic and he did not have any connection to PWR_GOOD however he does not use the power coming off of the interposer (aside from the 3.3v standby for the EEPROM)

I will redesign the board tonight however will wait on ordering as i am moving soon and am unsure of some dates and details regarding it

Ok, it looks like the EC is setting the correct GPIOs. Enabling various power enable GPIOs towards the expansion bay.

Maybe the BIOS expects more before it sends a clock signal.
Apparently PWR_GOOD signal controls which pin the mainboard expects the clkreq signal on.

The BIOS controls the CLK signal.
I think this might be a good time to ask FW support for help.
The question would be:
What input does the BIOS expect before it starts sending a CLKREF signal out.
Is it only a CLKREQ or is it also certain names or bits being set in the EEPROM.

1 Like

In case it helps, the EC source code has some code for the settings it uses.
Maybe the BIOS is expecting some specific things in there before it switches on CLKREF.
./zephyr/program/framework/lotus/src/gpu_configuration.c

static struct default_gpu_cfg gpu_cfg = {
        .descriptor = {
                .magic = {0x32, 0xac, 0x00, 0x00},
                .length = sizeof(struct gpu_cfg_descriptor),
                .descriptor_version_major = 0,
                .descriptor_version_minor = 1,
                .hardware_version = 0x0008,
                .hardware_revision = 0,
                .serial = {'F', 'R', 'A', 'K', 'M', 'B', 'C', 'P', '8', '1',
                                        '3', '3', '1', 'A', 'S', 'S', 'Y', '0', '\0', '\0'},
                .descriptor_length = sizeof(struct default_gpu_cfg) - sizeof(struct gpu_cfg_descriptor),
                .descriptor_crc32 = 0,
                .crc32 = 0
        },
        .hdr0 = {.block_type = GPUCFG_TYPE_PCIE, .block_length = sizeof(uint8_t)},
        .pcie_cfg = PCIE_8X1,

        .hdr1 = {.block_type = GPUCFG_TYPE_FAN, .block_length = sizeof(struct gpu_cfg_fan)},
        .fan0_cfg = {.idx = 0, .flags = 0, .min_rpm = 1000, .start_rpm = 1000, .max_rpm = 4700},

        .hdr2 = {.block_type = GPUCFG_TYPE_FAN, .block_length = sizeof(struct gpu_cfg_fan)},
        .fan1_cfg = {.idx = 1, .flags = 0, .min_rpm = 1000, .start_rpm = 1000, .max_rpm = 4500},

        .hdr3 = {.block_type = GPUCFG_TYPE_VENDOR, .block_length = sizeof(gpu_vendor)},
        .vendor = GPU_AMD_R23M,

        .hdr4 = {.block_type = GPUCFG_TYPE_GPIO, .block_length = (sizeof(struct gpu_cfg_gpio) * 8)},
        /* Critical temperature fault input */
        .gpio0 = {.gpio = GPU_1G1_GPIO0_EC, .function = GPIO_FUNC_TEMPFAULT, .flags = GPIO_INPUT, .power_domain = POWER_S3},
        /* DP HPD status from PD */
        .gpio1 = {.gpio = GPU_1H1_GPIO1_EC, .function = GPIO_FUNC_HPD, .flags = GPIO_INPUT, .power_domain = POWER_S5},
        /* AC/DC mode setting */
        .gpio2 = {.gpio = GPU_2A2_GPIO2_EC, .function = GPIO_FUNC_ACDC, .flags = GPIO_OUTPUT_LOW, .power_domain = POWER_S3},
        /* UNUSED */
        .gpio3 = {.gpio = GPU_2L7_GPIO3_EC, .function = GPIO_FUNC_UNUSED, .flags = GPIO_OUTPUT_LOW, .power_domain = POWER_G3},
        /* GPU_VSYS_EN */
        .gpio_vsys = {.gpio = GPU_VSYS_EN, .function = GPIO_FUNC_GPU_PWR, .flags = GPIO_OUTPUT_LOW, .power_domain = POWER_S3},
        /* GPU_VADP_EN */
        .gpu_vadp_en = {.gpio = GPU_VADP_EN, .function = GPIO_FUNC_UNUSED, .flags = GPIO_OUTPUT_LOW, .power_domain = POWER_G3},

        .gpio_fan = {.gpio = GPU_FAN_EN, .function = GPIO_FUNC_HIGH, .flags = GPIO_OUTPUT_LOW, .power_domain = POWER_S0},

        .gpu_3v_5v_en = {.gpio = GPU_3V_5V_EN, .function = GPIO_FUNC_HIGH, .flags = GPIO_OUTPUT_LOW, .power_domain = POWER_S5},

        .hdr5 = {.block_type = GPUCFG_TYPE_PD, .block_length = sizeof(struct gpu_subsys_pd)},
        .pd = {.gpu_pd_type = PD_TYPE_ETRON_EJ889I, .address = 0x60,
                        .flags = 0, .pdo = 0, .rdo = 0, .power_domain = POWER_S5,
                        .gpio_hpd = GPU_1H1_GPIO1_EC, .gpio_interrupt = GPU_1F2_I2C_S5_INT
        },

        .hdr6 = {.block_type = GPUCFG_TYPE_THERMAL_SENSOR, .block_length = sizeof(struct gpu_cfg_thermal)},
        .therm = {.thermal_type = GPU_THERM_F75303, .address = 0x4D},

        .hdr7 = {.block_type = GPUCFG_TYPE_CUSTOM_TEMP, .block_length = sizeof(struct gpu_cfg_custom_temp)},
        .custom_temp = {.idx = 2, .temp_fan_off = C_TO_K(47), .temp_fan_max = C_TO_K(62)},

        .hdr8 = {.block_type = GPUCFG_TYPE_SUBSYS, .block_length = sizeof(struct gpu_subsys_serial)},
        .pcba_serial = {.gpu_subsys = GPU_PCB, .serial = {'F', 'R', 'A', 'G', 'M', 'A', 'S', 'P', '8', '1',
                                        '3', '3', '1', 'P', 'C', 'B', '0', '0', '\0', '\0'},}
};
1 Like

Thanks for the insight and ideas. I’m not sure FW support would know much about the specifics of the bios and what it expects b4 sending out a CLK signal however I will try anyway as I’m out of ideas.

I will send out the pre compiled c file I used to create my eeprom descriptor in about 10 minutes

The reason i think the bios might need something more is because for some reason a new bios was needed to get the nvidia gpu working.
But on the other hand, the oculink 8i card seems to be working ok, and your pcie card should work exactly the same way, as in, with the same Eeprom as the 8i card.

Close, however the 8i EEPROM disabled the power output from the interposer which i use to power the 12v and 3.3v rail of the PCIE slot.
Here is the C file i used to generate the EEPROM file
#include <config_definition.h>

#include <ssd.h>

struct default_pcie_cfg pcie_accessory_cfg = {

.descriptor = {

    .magic = {0x32, 0xac, 0x00, 0x00},

    .length = sizeof(struct gpu_cfg_descriptor),

    .descriptor_version_major = 0,

    .descriptor_version_minor = 1,

    .hardware_version = 0x0008,

    .hardware_revision = 0,

    .serial = {'F', 'R', 'A', 'P', 'C', 'I', 'E', '0', '0', '0',

                '0', '0', '0', 'T', 'E', 'S', 'T', '8', '\\0', '\\0'},

    .descriptor_length = sizeof(struct default_pcie_cfg) - sizeof(struct gpu_cfg_descriptor),

    .descriptor_crc32 = 0,

    .crc32 = 0

},

.hdr0 = {.block_type = GPUCFG_TYPE_PCIE, .block_length = sizeof(uint8_t)},

.pcie_cfg = PCIE_8X1,



.hdr1 = {.block_type = GPUCFG_TYPE_FAN, .block_length = sizeof(struct gpu_cfg_fan)},

.fan0_cfg = {.idx = 0, .flags = 0, .min_rpm = 1000, .start_rpm = 1000, .max_rpm = 3700},



.hdr2 = {.block_type = GPUCFG_TYPE_FAN, .block_length = sizeof(struct gpu_cfg_fan)},

.fan1_cfg = {.idx = 1, .flags = 0, .min_rpm = 1000, .start_rpm = 1000, .max_rpm = 3700},



.hdr3 = {.block_type = GPUCFG_TYPE_VENDOR, .block_length = sizeof(enum gpu_vendor)},

.vendor = GPU_PCIE_ACCESSORY,



/\* Power enable for 12V \*/

.hdr4 = {.block_type = GPUCFG_TYPE_GPIO, .block_length = sizeof(struct gpu_cfg_gpio) \* 8},

.gpio0 = {.gpio = GPU_1G1_GPIO0_EC, .function = GPIO_FUNC_HIGH, .flags = GPIO_OUTPUT_LOW, .power_domain = POWER_S3},

/\* Power enable for 3.3V \*/

.gpio1 = {.gpio = GPU_1H1_GPIO1_EC, .function = GPIO_FUNC_HIGH, .flags = GPIO_OUTPUT_LOW, .power_domain = POWER_S3},

/\* UNUSED \*/

.gpio2 = {.gpio = GPU_2A2_GPIO2_EC, .function = GPIO_FUNC_UNUSED, .flags = GPIO_INPUT, .power_domain = POWER_G3},

/\* UNUSED \*/

.gpio3 = {.gpio = GPU_2L7_GPIO3_EC, .function = GPIO_FUNC_UNUSED, .flags = GPIO_INPUT, .power_domain = POWER_G3},

/\* set mux configuration on mainboard for SSD \*/

.gpio_edpaux = {.gpio = GPU_PCIE_MUX_SEL, .function = GPIO_FUNC_HIGH, .flags = GPIO_OUTPUT_LOW, .power_domain = POWER_S3},

/\* GPU_VSYS_EN \*/

.gpio_vsys = {.gpio = GPU_VSYS_EN, .function = GPIO_FUNC_HIGH, .flags = GPIO_OUTPUT_LOW, .power_domain = POWER_S3},



.gpio_fan = {.gpio = GPU_FAN_EN, .function = GPIO_FUNC_HIGH, .flags = GPIO_OUTPUT_LOW, .power_domain = POWER_S0},



.gpu_3v_5v_en = {.gpio = GPU_3V_5V_EN, .function = GPIO_FUNC_HIGH, .flags = GPIO_OUTPUT_LOW, .power_domain = POWER_S5},

};

Sorry I didn’t quite get if you got your original mainboard working again or not.

But if not, it certainly does sound like full schematics are indeed available to repair shops.

(that was from May 2022)

A note confirming that independent repair shops can get it,

An earlier blog post, if you could use an official-type announcement to point a repair shop to,

Makes it sound like they have a standard procedure set up for it.

Thanks! Was looking for that post. I got my old motherboard “half” working. I have to boot from an external drive (a USB drive in my case) as both M.2 slots are dead. I am using it as my test bench so i dont have to repeatedly disassemble my laptop (which i use daily for school) to test my board

1 Like