Samsung Galaxy Book4 Edge – Ubuntu 24.04 Ep.1

Summary:

  • LiveUSB drive boots into Ubuntu installer with a few workarounds.
  • USB2.0 is working while in the installer, but using eUSB2 repeater settings from bootloader stages.
  • The UFS device is identified and visible in GParted

Next Actions:

  • Find the eUSB2 repeater being used, i.e. if it is a QC SMB based repeater, or if it is another vendor, such as NXP
  • Working on identifying the I2C devices for the onboard keyboard and touchpad.
    • Need to reverse engineer, and make assumptions based on what is output from i2c-tools
  • When the eUSB2 repeater is identified, can submit next kernel series submission.

Technical Details/Findings:

eUSB2 Repeater:

In order to properly install the Ubuntu image from a bootable USB drive, the casper script has to be able to identify a storage device that contains the images. Without the eUSB2 repeater, USB device will not be identified by the Linux USB host controller. Luckily, after adding changes to relax the dependency on the eUSB2 PHY driver and the eUSB2 repeater, the USB software can piggyback off previous settings, which works enough to enumerate devices.

Casper:

How to update a bootable USB drive with custom kernel image, DTBs, and initrd:

Updating kernel image

To update the existing kernel image in the casper environment execute the following steps (ignore the kernel build if you don’t aren’t planning on building your own kernel):

#Build the kernel
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- all -j32

#Compress the kernel image
gzip -c arch/arm64/boot/Image > vmlinuz

Now you can replace the vmlinuz file within your bootable USB drive:

Updating DTBs

Similarly as with DTBs, these are generated as part of the kernel build. After executing a build, your DTBs will be all under:

For the Samsung Galaxy Book4 Edge, we are specifically interested in:
“x1e80100-samsung-galaxy-book4-edge.dtb”

You can replace the one that is present in the following casper folder:

Updating initrd

As part of not being able to prepare an Ubuntu ISO package, I had to workaround some of the module loading steps that are assumed by the casper script, as in my set up everything is statically compiled into my kernel image. In this situation, I had to update the initrd used, because that is where the casper script is located.

#Unpackage base initrd file
sudo unmkinitramfs -v initrd initrd_test/

#Make modifications to scripts.  Usually there are two
#directories, early/ and main/.  The casper script is
#within main/scripts/casper.

#Pack up changes into new initrd file
#Credit:
#https://unix.stackexchange.com/questions/591209/how-to-pack-an-extracted-initrd-x-cpio-archive
#Pack early/ first
cd early/
find . -print0 | cpio --null --create --format=newc > ../../hi/newinitrd

#Followed by main/
cd main/
find . | cpio --create --format=newc | xz --format=lzma >> ../../hi/newinitrd

Now, you can rename newinitrd –> initrd, and replace the one in the casper folder on the USB drive:


Comments

2 responses to “Samsung Galaxy Book4 Edge – Ubuntu 24.04 Ep.1”

  1. /dts-v1/;

    / {
    compatible = “samsung,galaxy-book4-edge”, “qcom,x1e80100”;
    model = “Samsung Galaxy Book4 Edge”;
    #address-cells = ;
    #size-cells = ;
    interrupt-parent = ;
    chassis-type = “laptop”;

    chosen {
    bootargs = “console=ttyMSM0,115200n8 earlycon root=/dev/ram0 rw”;
    };

    cpus {
    #address-cells = ;
    #size-cells = ;

    // Snapdragon X Elite cluster 0 (4 cores)
    cpu@0 {
    device_type = “cpu”;
    compatible = “qcom,oryon”, “arm,armv8”;
    reg = ;
    enable-method = “psci”;
    next-level-cache = ;
    };

    cpu@100 {
    device_type = “cpu”;
    compatible = “qcom,oryon”, “arm,armv8”;
    reg = ;
    enable-method = “psci”;
    next-level-cache = ;
    };

    cpu@200 {
    device_type = “cpu”;
    compatible = “qcom,oryon”, “arm,armv8”;
    reg = ;
    enable-method = “psci”;
    next-level-cache = ;
    };

    cpu@300 {
    device_type = “cpu”;
    compatible = “qcom,oryon”, “arm,armv8”;
    reg = ;
    enable-method = “psci”;
    next-level-cache = ;
    };

    // Snapdragon X Elite cluster 1 (4 cores)
    cpu@10000 {
    device_type = “cpu”;
    compatible = “qcom,oryon”, “arm,armv8”;
    reg = ;
    enable-method = “psci”;
    next-level-cache = ;
    };

    cpu@10100 {
    device_type = “cpu”;
    compatible = “qcom,oryon”, “arm,armv8”;
    reg = ;
    enable-method = “psci”;
    next-level-cache = ;
    };

    cpu@10200 {
    device_type = “cpu”;
    compatible = “qcom,oryon”, “arm,armv8”;
    reg = ;
    enable-method = “psci”;
    next-level-cache = ;
    };

    cpu@10300 {
    device_type = “cpu”;
    compatible = “qcom,oryon”, “arm,armv8”;
    reg = ;
    enable-method = “psci”;
    next-level-cache = ;
    };

    // Snapdragon X Elite cluster 2 (4 cores)
    cpu@20000 {
    device_type = “cpu”;
    compatible = “qcom,oryon”, “arm,armv8”;
    reg = ;
    enable-method = “psci”;
    next-level-cache = ;
    };

    cpu@20100 {
    device_type = “cpu”;
    compatible = “qcom,oryon”, “arm,armv8”;
    reg = ;
    enable-method = “psci”;
    next-level-cache = ;
    };

    cpu@20200 {
    device_type = “cpu”;
    compatible = “qcom,oryon”, “arm,armv8”;
    reg = ;
    enable-method = “psci”;
    next-level-cache = ;
    };

    cpu@20300 {
    device_type = “cpu”;
    compatible = “qcom,oryon”, “arm,armv8”;
    reg = ;
    enable-method = “psci”;
    next-level-cache = ;
    };

    l2_0: l2-cache {
    compatible = “cache”;
    cache-level = ;
    cache-unified;
    };

    l2_1: l2-cache {
    compatible = “cache”;
    cache-level = ;
    cache-unified;
    };

    l2_2: l2-cache {
    compatible = “cache”;
    cache-level = ;
    cache-unified;
    };

    cpu-map {
    cluster0 {
    core0 {
    cpu = ;
    };
    core1 {
    cpu = ;
    };
    core2 {
    cpu = ;
    };
    core3 {
    cpu = ;
    };
    };
    cluster1 {
    core0 {
    cpu = ;
    };
    core1 {
    cpu = ;
    };
    core2 {
    cpu = ;
    };
    core3 {
    cpu = ;
    };
    };
    cluster2 {
    core0 {
    cpu = ;
    };
    core1 {
    cpu = ;
    };
    core2 {
    cpu = ;
    };
    core3 {
    cpu = ;
    };
    };
    };
    };

    memory@80000000 {
    device_type = “memory”;
    reg = ; // 16 GB
    };

    gic: interrupt-controller@17000000 {
    compatible = “arm,gic-v3”;
    #interrupt-cells = ;
    #address-cells = ;
    #size-cells = ;
    ranges;
    interrupt-controller;
    #redistributor-regions = ;
    reg = , // GICD
    ; // GICR
    };

    timer {
    compatible = “arm,armv8-timer”;
    interrupts = ,
    ,
    ,
    ;
    };

    psci {
    compatible = “arm,psci-1.0”;
    method = “smc”;
    };

    /*
    * USB Controllers
    * – Critical for USB booting
    * – Adding specific configuration for the eUSB2 repeater
    */
    soc: soc {
    compatible = “simple-bus”;
    #address-cells = ;
    #size-cells = ;
    ranges;

    /* USB Host Controller 0 */
    usb0: usb@a200000 {
    compatible = “qcom,x1e80100-dwc3”, “qcom,dwc3”;
    reg = ;
    interrupts = ;
    clocks = ,
    ,
    ;
    clock-names = “cfg_noc”, “core”, “iface”;
    dr_mode = “host”;
    maximum-speed = “super-speed-plus”;
    /* Important: Reference the USB PHY with eUSB2 repeater */
    phys = , ;
    phy-names = “usb2-phy”, “usb3-phy”;
    status = “okay”;
    };

    /* USB Host Controller 1 */
    usb1: usb@a400000 {
    compatible = “qcom,x1e80100-dwc3”, “qcom,dwc3”;
    reg = ;
    interrupts = , ;
    clocks = ,
    ,
    ;
    clock-names = “cfg_noc”, “core”, “iface”;
    dr_mode = “host”;
    maximum-speed = “super-speed-plus”;
    phys = , ;
    phy-names = “usb2-phy”, “usb3-phy”;
    status = “okay”;
    };

    /* USB Controller (Type-C) */
    usb2: usb@a600000 {
    compatible = “qcom,x1e80100-dwc3”, “qcom,dwc3”;
    reg = ;
    interrupts = ;
    clocks = ,
    ,
    ;
    clock-names = “cfg_noc”, “core”, “iface”;
    dr_mode = “otg”;
    maximum-speed = “super-speed-plus”;
    phys = , ;
    phy-names = “usb2-phy”, “usb3-phy”;
    status = “okay”;
    };

    /* USB Controller (Type-C) */
    usb3: usb@a800000 {
    compatible = “qcom,x1e80100-dwc3”, “qcom,dwc3”;
    reg = ;
    interrupts = ;
    clocks = ,
    ,
    ;
    clock-names = “cfg_noc”, “core”, “iface”;
    dr_mode = “otg”;
    maximum-speed = “super-speed-plus”;
    phys = , ;
    phy-names = “usb2-phy”, “usb3-phy”;
    status = “okay”;
    };

    /* USB 2.0 PHY for USB0 with eUSB2 Repeater */
    usb2_phy0: phy@fd30008 {
    compatible = “qcom,x1e80100-snps-eusb2-phy”, “qcom,sm8550-snps-eusb2-phy”;
    reg = ;
    vdd-supply = ;
    status = “okay”;

    /* Key fix for USB booting – use SMB2360 eUSB2 repeater */
    eusb2_repeater: repeater {
    compatible = “qcom,smb2360-eusb2-repeater”;
    status = “okay”;
    };
    };

    /* USB 3.0 PHY for USB0 */
    usb3_phy0: phy@fd5000 {
    compatible = “qcom,x1e80100-qmp-usb3-dp-phy”;
    reg = ;
    vdd-supply = ;
    status = “okay”;
    };

    /* USB 2.0 PHY for USB1 with eUSB2 Repeater */
    usb2_phy1: phy@fd90008 {
    compatible = “qcom,x1e80100-snps-eusb2-phy”, “qcom,sm8550-snps-eusb2-phy”;
    reg = ;
    vdd-supply = ;
    status = “okay”;

    /* Key fix for USB booting */
    eusb2_repeater1: repeater {
    compatible = “qcom,smb2360-eusb2-repeater”;
    status = “okay”;
    };
    };

    /* USB 3.0 PHY for USB1 */
    usb3_phy1: phy@fda000 {
    compatible = “qcom,x1e80100-qmp-usb3-dp-phy”;
    reg = ;
    vdd-supply = ;
    status = “okay”;
    };

    /* USB 2.0 PHY for USB2 with eUSB2 Repeater */
    usb2_phy2: phy@fde0008 {
    compatible = “qcom,x1e80100-snps-eusb2-phy”, “qcom,sm8550-snps-eusb2-phy”;
    reg = ;
    vdd-supply = ;
    status = “okay”;

    /* Key fix for USB booting */
    eusb2_repeater2: repeater {
    compatible = “qcom,smb2360-eusb2-repeater”;
    status = “okay”;
    };
    };

    /* USB 3.0 PHY for USB2 */
    usb3_phy2: phy@fdf000 {
    compatible = “qcom,x1e80100-qmp-usb3-dp-phy”;
    reg = ;
    vdd-supply = ;
    status = “okay”;
    };

    /* UFS Storage Controller */
    ufs: ufshc@1d84000 {
    compatible = “qcom,x1e80100-ufshc”, “qcom,ufshc”, “jedec,ufs-2.0”;
    reg = ;
    interrupts = ;
    phys = ;
    phy-names = “ufsphy”;
    vdd-hba-supply = ;
    vcc-supply = ;
    status = “okay”;
    };

    ufs_phy: phy@1d80000 {
    compatible = “qcom,x1e80100-qmp-ufs-phy”;
    reg = ;
    vdda-phy-supply = ;
    vdda-pll-supply = ;
    status = “okay”;
    };

    /* I2C Controllers */
    i2c0: i2c@a80000 {
    compatible = “qcom,geni-i2c”;
    reg = ;
    interrupts = ;
    #address-cells = ;
    #size-cells = ;
    clock-names = “se-clk”, “m-ahb”, “s-ahb”;
    clocks = ,
    ,
    ;
    pinctrl-names = “default”;
    pinctrl-0 = ;
    status = “okay”;
    };

    i2c1: i2c@a84000 {
    compatible = “qcom,geni-i2c”;
    reg = ;
    interrupts = ;
    #address-cells = ;
    #size-cells = ;
    clock-names = “se-clk”, “m-ahb”, “s-ahb”;
    clocks = ,
    ,
    ;
    pinctrl-names = “default”;
    pinctrl-0 = ;
    status = “okay”;
    };

    /* I2C bus for touchpad */
    i2c9: i2c@a940000 {
    compatible = “qcom,geni-i2c”;
    reg = ;
    interrupts = ;
    #address-cells = ;
    #size-cells = ;
    clock-names = “se-clk”, “m-ahb”, “s-ahb”;
    clocks = ,
    ,
    ;
    pinctrl-names = “default”;
    pinctrl-0 = ;
    status = “okay”;

    /* Touchpad device */
    touchpad@40 {
    compatible = “hid-over-i2c”;
    reg = ;
    hid-descr-addr = ;
    interrupts-extended = ;
    vdd-supply = ;
    wakeup-source;
    pinctrl-names = “default”;
    pinctrl-0 = ;
    status = “okay”;
    };
    };

    /* I2C bus for keyboard */
    i2c16: i2c@b80000 {
    compatible = “qcom,geni-i2c”;
    reg = ;
    interrupts = ;
    #address-cells = ;
    #size-cells = ;
    clock-names = “se-clk”, “m-ahb”, “s-ahb”;
    clocks = ,
    ,
    ;
    pinctrl-names = “default”;
    pinctrl-0 = ;
    status = “okay”;

    /* Keyboard device */
    keyboard@a {
    compatible = “hid-over-i2c”;
    reg = ;
    hid-descr-addr = ;
    interrupts-extended = ;
    vdd-supply = ;
    pinctrl-names = “default”;
    pinctrl-0 = ;
    status = “okay”;
    };
    };

    /* Debug UART */
    serial@894000 {
    compatible = “qcom,geni-debug-uart”;
    reg = ;
    interrupts = ;
    clock-names = “se-clk”;
    clocks = ;
    pinctrl-names = “default”;
    pinctrl-0 = ;
    status = “okay”;
    };

    /* GPIO and Pin Control */
    tlmm: pinctrl@f100000 {
    compatible = “qcom,x1e80100-tlmm”;
    reg = ;
    interrupts = ;
    gpio-controller;
    #gpio-cells = ;
    interrupt-controller;
    #interrupt-cells = ;
    status = “okay”;

    /* I2C Pin Configurations */
    qup_i2c0_data_clk_state: qup-i2c0-data-clk-state {
    pins = “gpio0”, “gpio1”;
    function = “qup0_se0”;
    drive-strength = ;
    bias-pull-up;
    };

    qup_i2c1_data_clk_state: qup-i2c1-data-clk-state {
    pins = “gpio4”, “gpio5”;
    function = “qup0_se1”;
    drive-strength = ;
    bias-pull-up;
    };

    qup_i2c9_data_clk_state: qup-i2c9-data-clk-state {
    pins = “gpio36”, “gpio37”;
    function = “qup1_se1”;
    drive-strength = ;
    bias-pull-up;
    };

    qup_i2c16_data_clk_state: qup-i2c16-data-clk-state {
    pins = “gpio64”, “gpio65”;
    function = “qup2_se0”;
    drive-strength = ;
    bias-pull-up;
    };

    qup_uart2_default_state: qup-uart2-default-state {
    cts-pins {
    pins = “gpio8”;
    function = “qup0_se2”;
    drive-strength = ;
    };
    rts-pins {
    pins = “gpio9”;
    function = “qup0_se2”;
    drive-strength = ;
    };
    tx-pins {
    pins = “gpio10”;
    function = “qup0_se2”;
    drive-strength = ;
    };
    rx-pins {
    pins = “gpio11”;
    function = “qup0_se2”;
    drive-strength = ;
    };
    };

    /* Touchpad Configuration */
    tpad_default_state: tpad-default-state {
    pins = “gpio3”;
    function = “gpio”;
    drive-strength = ;
    bias-disable;
    };

    /* Keyboard Configuration */
    kybd_default_state: kybd-default-state {
    pins = “gpio67”;
    function = “gpio”;
    drive-strength = ;
    };
    };

    /* Clock Controller */
    gcc: clock-controller@100000 {
    compatible = “qcom,x1e80100-gcc”;
    reg = ;
    #clock-cells = ;
    #reset-cells = ;
    #power-domain-cells = ;
    status = “okay”;
    };

    /* SPMI Bus Controller for PMIC */
    spmi: spmi@c400000 {
    compatible = “qcom,x1e80100-spmi-pmic-arb”;
    reg = ,
    ,
    ,
    ,
    ;
    reg-names = “core”, “chnls”, “obsrvr”, “intr”, “cnfg”;
    #address-cells = ;
    #size-cells = ;
    interrupts = ;
    interrupt-names = “periph_irq”;
    status = “okay”;

    pmk8550: pmic@0 {
    compatible = “qcom,pm8550”, “qcom,spmi-pmic”;
    reg = ;
    #address-cells = ;
    #size-cells = ;

    pon@800 {
    compatible = “qcom,pmk8350-pon”;
    reg = ;
    mode-bootloader = ;
    mode-recovery = ;
    mode-rtc = ;
    mode-panic = ;
    mode-battery-interface = ;

    pwrkey {
    compatible = “qcom,pmk8350-pwrkey”;
    interrupts = ;
    linux,code = ;
    };
    };

    gpio@8800 {
    compatible = “qcom,pmk8550-gpio”, “qcom,spmi-gpio”;
    reg = ;
    gpio-controller;
    #gpio-cells = ;
    interrupt-controller;
    #interrupt-cells = ;
    };
    };

    /* PMIC for regulators */
    pm8550b: pmic@3 {
    compatible = “qcom,pm8550”, “qcom,spmi-pmic”;
    reg = ;

    regulators {
    compatible = “qcom,pm8550-regulators”;

    vreg_bob1: bob1 {
    regulator-name = “vreg_bob1”;
    regulator-min-microvolt = ;
    regulator-max-microvolt = ;
    };

    vreg_bob2: bob2 {
    regulator-name = “vreg_bob2”;
    regulator-min-microvolt = ;
    regulator-max-microvolt = ;
    };

    vreg_l3d_1p8: ldo3 {
    regulator-name = “vreg_l3d_1p8”;
    regulator-min-microvolt = ;
    regulator-max-microvolt = ;
    };

    vreg_l8b_3p0: ldo8 {
    regulator-name = “vreg_l8b_3p0”;
    regulator-min-microvolt = ;
    regulator-max-microvolt = ;
    };

    vreg_l10b_1p8: ldo10 {
    regulator-name = “vreg_l10b_1p8”;
    regulator-min-microvolt = ;
    regulator-max-microvolt = ;
    };
    };
    };
    /* PMIC for SMB2360 eUSB2 repeater
    * This is the key component needed for USB booting
    */
    smb2360_a: pmic@a {
    compatible = “qcom,smb2360”, “qcom,spmi-pmic”;
    reg = ;

    usb_repeater_a: phy@fd00 {
    compatible = “qcom,smb2360-eusb2-repeater”;
    status = “okay”;
    };
    };

    smb2360_b: pmic@b {
    compatible = “qcom,smb2360”, “qcom,spmi-pmic”;
    reg = ;

    usb_repeater_b: phy@fd00 {
    compatible = “qcom,smb2360-eusb2-repeater”;
    status = “okay”;
    };
    };
    };
    };

    /* Type-C USB Connectors */
    connector0: connector@0 {
    compatible = “usb-c-connector”;
    label = “USB-C”;
    power-role = “dual”;
    data-role = “dual”;

    ports {
    #address-cells = ;
    #size-cells = ;

    port@0 {
    reg = ;
    conn0_usb: endpoint {
    remote-endpoint = ;
    };
    };
    };
    };

    connector1: connector@1 {
    compatible = “usb-c-connector”;
    label = “USB-C”;
    power-role = “dual”;
    data-role = “dual”;

    ports {
    #address-cells = ;
    #size-cells = ;

    port@0 {
    reg = ;
    conn1_usb: endpoint {
    remote-endpoint = ;
    };
    };
    };
    };

    /*
    * Special configuration section for eUSB2 repeater settings
    * This allows the bootloader settings to be reused
    */
    eusb2_repeater_settings {
    compatible = “qcom,eusb2-repeater-settings”;

    /* Relax dependency on eUSB2 PHY driver */
    qcom,retain-bootloader-settings;

    /*
    * Settings needed for USB booting on Samsung Galaxy Book4 Edge
    * with Snapdragon X Elite
    */
    qcom,skip-phy-init;
    qcom,skip-repeater-init;
    };
    };

    1. Thanks for this, Joe. Did you confirm the onboard keyboard/touchpad functionality?

Leave a Reply to joe Cancel reply

Your email address will not be published. Required fields are marked *