Difference between revisions of "Quartz64 Model A Using a battery"

From PINE64
Jump to navigation Jump to search
(If capitalized then "the" and "a" not)
 
(24 intermediate revisions by 4 users not shown)
Line 1: Line 1:
The Quartz64 Model A allows for it to be powered from a single-cell 3.7V lithium-polymer battery. Because of [https://en.wikipedia.org/wiki/UPS_Airlines_Flight_6 unfortunate incidents], batteries are not easy to ship internationally, so PINE Store does not sell a matching battery for the board.
The [[Quartz64|Quartz64 Model A]] allows for it to be powered from a single-cell 3.7V lithium-polymer battery. Because of [https://en.wikipedia.org/wiki/UPS_Airlines_Flight_6 unfortunate incidents], batteries are not easy to ship internationally, so PINE Store does not sell a matching battery for the board.


= Pin-out =
== Pin-out ==


[[File:Quartz64 Model A VBAT Connector Pinout.png|right]]
[[File:Quartz64 Model A VBAT Connector Pinout.png|right]]
Line 7: Line 7:
The pins on the board are a JST PH-3 compatible header labelled ''+VBAT-''. As one might guess, the positive wire should be towards the +, and the ground wire towards -. The center pin of the connector is for a temperature probe.
The pins on the board are a JST PH-3 compatible header labelled ''+VBAT-''. As one might guess, the positive wire should be towards the +, and the ground wire towards -. The center pin of the connector is for a temperature probe.


= Ways to get a battery =
== Ways to get a battery ==


We will now go into various ways one might go about getting a working battery.
We will now go into various ways one might go about getting a working battery.


== Crimping one yourself ==
=== Crimping one yourself ===


You will need:
You will need:
* an Engineer PA-20 or Hozan P-707 or similar crimp tool (<$80, good to have around anyway)
* an Engineer PA-20 ([https://www.amazon.com/s?k=Engineer+Pa-20 Amazon Search], [https://www.ebay.com/sch/i.html?kw=Engineer%20PA-20 eBay Search]) or Hozan P-707 ([https://www.amazon.com/s?k=Hozan+P-707 Amazon Search], [https://www.ebay.com/sch/i.html?kw=Hozan%20P-707 eBay Search]) or similar crimp tool (<$80, good to have around anyway)
** The Hozan P-707 is also comparatively good at crimping "Dupont"-style terminals, in case you find yourself doing that a lot, because it provides round crimping holes in addition to rectangular ones.
* JST PHR-3 receptacles ([https://www.digikey.com/en/products/detail/jst-sales-america-inc/PHR-3/527357 ~$0.05 on digikey])
* JST PHR-3 receptacles ([https://www.digikey.com/en/products/detail/jst-sales-america-inc/PHR-3/527357 ~$0.05 on digikey])
* 3&times; JST SPH-002T-P0.5L crimp terminals ([https://www.digikey.com/en/products/detail/jst-sales-america-inc/SPH-002T-P0-5L/1300246 ~$0.03 on digikey per terminal])
* 3&times; JST SPH-002T-P0.5L crimp terminals ([https://www.digikey.com/en/products/detail/jst-sales-america-inc/SPH-002T-P0-5L/1300246 ~$0.03 on digikey per terminal])
** When ordering from digikey, try to hit the minimum order cost to qualify for free shipping; you'll get free fast courier shipping with all customs and duties pre-paid.
* a single-cell 3.7V lithium-polymer battery, ideally with a temperature probe
* a single-cell 3.7V lithium-polymer battery, ideally with a temperature probe
** 2800 mAh Renata ICP606168PRT on [https://www.conrad.de/de/p/renata-icp606168prt-spezial-akku-prismatisch-kabel-lipo-3-7-v-2800-mah-1214021.html Conrad Germany], [https://www.conrad.ch/de/p/renata-icp606168prt-spezial-akku-prismatisch-kabel-lipo-3-7-v-2800-mah-1214021.html Conrad Switzerland]
** 2800 mAh Renata ICP606168PRT on [https://www.conrad.de/de/p/renata-icp606168prt-spezial-akku-prismatisch-kabel-lipo-3-7-v-2800-mah-1214021.html Conrad Germany], [https://www.conrad.ch/de/p/renata-icp606168prt-spezial-akku-prismatisch-kabel-lipo-3-7-v-2800-mah-1214021.html Conrad Switzerland]
Line 24: Line 26:
Crimp the terminals onto the wires, crimp the strain relief onto the insulation, slide them into the connector until they firmly click in place.
Crimp the terminals onto the wires, crimp the strain relief onto the insulation, slide them into the connector until they firmly click in place.


== PINE64 18650 battery case ==
=== PINE64 18650 battery case ===


You will need:
You will need:
Line 32: Line 34:
'''TODO:''' Get one of these and document how to use them
'''TODO:''' Get one of these and document how to use them


= Using the battery =
'''TODO''' Could please one of the Pine64 staff clarify the following points:
* has that case a battery protection circuit (probably)`?
* what are the paremeters of the NTC resistor in the battery pack? Without those parameters it is impossible to translate the sensor readings into an actual temperature.
* What is its nominal resistance at the pivot temperature point (e.g. 10kOhm at 20 degrees Celsius or whatever)?
* What is its B-constant?


== Hardware ==
 
== Using the battery ==
 
=== Hardware ===


# Ensure the wires in the connector are in the right order.
# Ensure the wires in the connector are in the right order.
Line 42: Line 51:
# It is now ready to use if your device tree has been set up correctly.
# It is now ready to use if your device tree has been set up correctly.


== Software ==
=== Caveats ===
 
Not all parts of the board can be supplied from the battery. When you use battery as backup power for the board keep in mind that following parts of Quartz64-A will lose power when DCIN loses power:
 
* 12V Fan connector
* EDP LCD backlight
* 5V power rails on the 20 pin GPIO header
* PCIe socket (both 12V and 3.3V supplies)
* All USB ports except for the black one
* Black USB port's VBUS (the one above the USB 3.0 port) will go through a 22ms brownout to approximately VCC_SYS - 0.6V voltage, before the RK817 BOOST regulator kicks in. This will likely cause the connected USB device to reset or have its internal state corrupted.
 
[[File:Quartz 64 Model A VBUS Brownout.png|640px]]
 
=== Software ===
 
==== Device-Tree Additions ====
 
For the battery to be correctly detected, you will need to edit the device tree to add the charger and battery nodes, like this:
 
<pre>
// add this to root node (you may need to modify the values to fit your chosen battery)
battery: battery {
compatible = "simple-battery";
charge-full-design-microamp-hours = <6400000>;
charge-term-current-microamp = <200000>;
constant-charge-current-max-microamp = <2000000>;
constant-charge-voltage-max-microvolt = <4200000>;
factory-internal-resistance-micro-ohms = <117000>;
voltage-max-design-microvolt = <4200000>;
voltage-min-design-microvolt = <3200000>;
 
ocv-capacity-celsius = <20>;
ocv-capacity-table-0 =  <4200000 100>, <4054000 95>, <3984000 90>, <3926000 85>,
<3874000 80>, <3826000 75>, <3783000 70>, <3746000 65>,
<3714000 60>, <3683000 55>, <3650000 50>, <3628000 45>,
<3612000 40>, <3600000 35>, <3587000 30>, <3571000 25>,
<3552000 20>, <3525000 15>, <3492000 10>, <3446000 5>,
<3400000 0>;
};
 
// add this to &rk817 node
rk817_charger: charger {
monitored-battery = <&battery>;
rockchip,resistor-sense-micro-ohms = <10000>;
rockchip,sleep-enter-current-microamp = <300000>;
rockchip,sleep-filter-current-microamp = <100000>;
};
</pre>
 
You will also need to make sure that CONFIG_CHARGER_RK817 is enabled in your kernel.
 
==== Device-Tree Overlay ====
 
On some Linux distributions it may be possible to add the device-tree additions via an overlay, example given for the Renata 2800 mAh battery mentioned above ([[#Device Tree Additions|see here for Armbian on how to install the overlay]]):
 
<pre>
/dts-v1/;
/plugin/;
 
/ {
    compatible = "pine64,quartz64-a", "rockchip,rk3566";
 
    // add this to root node (you may need to modify the values to fit your chosen battery)
    // Values for Renata 2800 mAh ICP606168PRT
    fragment@0 {
        target-path = "/";
        __overlay__ {
            battery: battery {
                compatible = "simple-battery";
                charge-full-design-microamp-hours = <2800000>;
                charge-term-current-microamp = <150000>;
                constant-charge-current-max-microamp = <1400000>;
                constant-charge-voltage-max-microvolt = <4200000>;
                factory-internal-resistance-micro-ohms = <200000>;
                voltage-max-design-microvolt = <4200000>;
                voltage-min-design-microvolt = <3200000>;
           
                ocv-capacity-celsius = <20>;
                ocv-capacity-table-0 =  <4200000 100>, <4054000 95>, <3984000 90>, <3926000 85>,
                    <3874000 80>, <3826000 75>, <3783000 70>, <3746000 65>,
                    <3714000 60>, <3683000 55>, <3650000 50>, <3628000 45>,
                    <3612000 40>, <3600000 35>, <3587000 30>, <3571000 25>,
                    <3552000 20>, <3525000 15>, <3492000 10>, <3446000 5>,
                    <3400000 0>;
            };
        };
    };
 
    // add this to &rk817 node
    fragment@1 {
        target = <&rk817>;
        __overlay__ {
            rk817_charger: charger {
                monitored-battery = <&battery>;
                rockchip,resistor-sense-micro-ohms = <10000>;
                rockchip,sleep-enter-current-microamp = <300000>;
                rockchip,sleep-filter-current-microamp = <100000>;
            };
        };
    };
};
</pre>
 
==== Battery Parameter Limitations ====
 
* the hardware limits the possible max. charge current to the discrete values 0.5A, 1.0A, 1.5A, 2.0A, 2.5A, 2.75A, 3.0A or 3.5A. The kernel driver will therefore use the largest value smaller or equal the configured value.
 
==== Device Driver Limitations ====
 
* up to kernel version 6.11.2 the value of the temperature sensor is not exposed by the device driver
 
==== Recovering the PCIe-Slot after Power Cycling ====
 
As mentioned above the PCIe-slot is no longer powered when running on battery. The question is then: how to recover the PCIe-controller after power cycling such that a plugged in extension card (e.g. a SATA controller of whatever) is operational again. One use case is kind of a low-power mode, a NAS system with a decent number of hard-disks may consume about 40W-50W even when idle, while the Quartz64 running from battery consumes less than 2W (when idle).
 
===== Soft Reset and Rescan (not working) =====
Unfortunately, the following does not work:
<syntaxhighlight lang="Bash" line copy>
echo 1 > /sys/bus/pci/devices/0000:00:00.0/remove
# turn power off, wait, turn power on
sleep 5 # or whatever periode
echo 1 > /sys/bus/pci/rescan
</syntaxhighlight>
The PCIe-slot is then "back again" but not quite. The attached extension card is not reinitialized, and also an additional
<syntaxhighlight lang="Bash" line copy>
echo 1 > /sys/bus/pci/devices/0000:00:00.0/rescan
</syntaxhighlight>
does not change improve the situation. Without power cycle the above mentioned lines actually do work.
 
===== Basic Idea =====
 
However, some device drivers in Linux can be compiled as loadable modules which can be removed and reloaded again. The hope was that the device driver for the DW PCIe-controller does some reinitialization during the boot sequence which it does not when a mere "rescan" request is issued. If the device driver existed as loadable module then removing the driver and reloading it should in some sense simulate the boot initialization.
 
===== Kernel Patch =====
 
Unfortunately, the device driver '''drivers/pci/controller/dwc/pcie-dw-rockchip.c''' has not been designed as loadable module (as of Linux 6.11.3), but the necessary changes are only few. The following source-code patch will add the loadable module feature:
 
[[Media:Kernel-rockchip64-pcie-dwc-module.tar]]
 
(sorry for wrapping it into a tar archive, but '''.patch''' files are not allowed by this MediaWiki instance)
 
===== Using the patched Device Driver =====
 
After applying the patch, reconfiguring the kernel to use the PCIe driver as a module and recompiling and installing the kernel one is almost done. Of course, in order to do this you have to know how to apply patches to source code and how to recompile the kernel. It is beyond the scope of this Wiki page to elaborate on this, however, below are some [[#Patching the Kernel|notes for Armbian]] on this topic.
 
Disengaging the PCIe slot prior to power cycling:
<syntaxhighlight lang="Bash" line copy>
# turn off anything using the PCIe extension card, unmount drives etc. then:
echo 1 > /sys/bus/pci/devices/0000:00:00.0/remove
rmmod pcie_dw_rockchip
</syntaxhighlight>
 
Then switch off the 12V main power supply. The PCIe slot will then remain unpowered as mentioned above. In order to recover the PCIe slot and an attached extension card one has -- of course -- to switch on the main power supply and can then proceed as follows:
 
<syntaxhighlight lang="Bash" line copy>
# wait some seconds after reattaching the main power supply
modprobe pcie_dw_rockchip
</syntaxhighlight>
 
Afterwards there chances that the PCIe bus has been reinitialized and works as before.
 
==== Specific Linux Distributions ====
 
===== Armbian =====
 
====== Device Tree Additions ======
 
Save the [[#Device-Tree Overlay|DTB-overlay snippet mentioned above]] to a file, e.g. "battery.dts" and then use
<syntaxhighlight lang="bash" line copy>
sudo /usr/sbin/armbian-add-overlay battery.dts
</syntaxhighlight>
in order to compile and add the overlay to "/boot/armbianEnv.txt".
 
====== Patching the Kernel ======


For the battery to be correctly detected, you will need to edit the device tree.
When using the Armbian build system, see https://github.com/armbian/build, it is possible to apply custom "user" patches by placing the patch file in '''userpatches/kernel/archive/KERNEL_NAME_AND_VERSION/PATCHFILE'''. For the example of using Ubunut "Noble" and trying to apply above mentioned [[Media:Kernel-rockchip64-pcie-dwc-module.tar|patch to turn the PCIe driver into a loadable module]] this would be
<pre>
userpatches/kernel/archive/rockchip64-6.6/kernel-rockchip64-pcie-dwc-module.patch
</pre>
Afterwards, it is possible to reconfigure and recompile the kernel using the commands:
<syntaxhighlight lang="Bash" line copy>
# after a while, the following will show the configuration menu
# go to "Device Drivers" -> "PCI Support" -> "PCI Controller Drivers" -> "DesignWare-based PCIe controllers"
# and configure "Rockchip DesignWare PCIe controller" to be built as module
./compile.sh  BOARD=quartz64a BRANCH=current kernel-config
# recompile the kernel
./compile.sh  BOARD=quartz64a BRANCH=current kernel
# recompile uboot (needed?)
./compile.sh  BOARD=quartz64a BRANCH=current uboot
</syntaxhighlight>
The resulting '''.deb''' packages can be found in '''output/debs/''', copy them to your running Quartz64 system and install them and reboot. On reboot the '''pcie_dw_rockchip''' module should be loaded automatically


'''TODO:''' Either write this section detailing how to edit the device tree, or get FDT overlays working and write about how to make an overlay
[[Category:Quartz64]]

Latest revision as of 08:48, 23 October 2024

The Quartz64 Model A allows for it to be powered from a single-cell 3.7V lithium-polymer battery. Because of unfortunate incidents, batteries are not easy to ship internationally, so PINE Store does not sell a matching battery for the board.

Pin-out

Quartz64 Model A VBAT Connector Pinout.png

The pins on the board are a JST PH-3 compatible header labelled +VBAT-. As one might guess, the positive wire should be towards the +, and the ground wire towards -. The center pin of the connector is for a temperature probe.

Ways to get a battery

We will now go into various ways one might go about getting a working battery.

Crimping one yourself

You will need:

  • an Engineer PA-20 (Amazon Search, eBay Search) or Hozan P-707 (Amazon Search, eBay Search) or similar crimp tool (<$80, good to have around anyway)
    • The Hozan P-707 is also comparatively good at crimping "Dupont"-style terminals, in case you find yourself doing that a lot, because it provides round crimping holes in addition to rectangular ones.
  • JST PHR-3 receptacles (~$0.05 on digikey)
  • 3× JST SPH-002T-P0.5L crimp terminals (~$0.03 on digikey per terminal)
    • When ordering from digikey, try to hit the minimum order cost to qualify for free shipping; you'll get free fast courier shipping with all customs and duties pre-paid.
  • a single-cell 3.7V lithium-polymer battery, ideally with a temperature probe
    • 2800 mAh Renata ICP606168PRT on Conrad Germany, Conrad Switzerland
    • 2000 mAh Adafruit on Adafruit US (no temperature probe, pre-crimped with JST PHR-2; just lift up the plastic tabs and pull out the terminals and shove them back into a PHR-3 connector)
    • Aliexpress: try keywords "3.7v lithium battery temperature probe"

Crimp the terminals onto the wires, crimp the strain relief onto the insulation, slide them into the connector until they firmly click in place.

PINE64 18650 battery case

You will need:

TODO: Get one of these and document how to use them

TODO Could please one of the Pine64 staff clarify the following points:

  • has that case a battery protection circuit (probably)`?
  • what are the paremeters of the NTC resistor in the battery pack? Without those parameters it is impossible to translate the sensor readings into an actual temperature.
  • What is its nominal resistance at the pivot temperature point (e.g. 10kOhm at 20 degrees Celsius or whatever)?
  • What is its B-constant?


Using the battery

Hardware

  1. Ensure the wires in the connector are in the right order.
  2. Turn off your Quartz64 Model A.
  3. Remove the BAT ON/OFF jumper.
  4. Plug in your battery.
  5. It is now ready to use if your device tree has been set up correctly.

Caveats

Not all parts of the board can be supplied from the battery. When you use battery as backup power for the board keep in mind that following parts of Quartz64-A will lose power when DCIN loses power:

  • 12V Fan connector
  • EDP LCD backlight
  • 5V power rails on the 20 pin GPIO header
  • PCIe socket (both 12V and 3.3V supplies)
  • All USB ports except for the black one
  • Black USB port's VBUS (the one above the USB 3.0 port) will go through a 22ms brownout to approximately VCC_SYS - 0.6V voltage, before the RK817 BOOST regulator kicks in. This will likely cause the connected USB device to reset or have its internal state corrupted.

Quartz 64 Model A VBUS Brownout.png

Software

Device-Tree Additions

For the battery to be correctly detected, you will need to edit the device tree to add the charger and battery nodes, like this:

	// add this to root node (you may need to modify the values to fit your chosen battery)
	battery: battery {
		compatible = "simple-battery";
		charge-full-design-microamp-hours = <6400000>;
		charge-term-current-microamp = <200000>;
		constant-charge-current-max-microamp = <2000000>;
		constant-charge-voltage-max-microvolt = <4200000>;
		factory-internal-resistance-micro-ohms = <117000>;
		voltage-max-design-microvolt = <4200000>;
		voltage-min-design-microvolt = <3200000>;

		ocv-capacity-celsius = <20>;
		ocv-capacity-table-0 =  <4200000 100>, <4054000 95>, <3984000 90>, <3926000 85>,
					<3874000 80>, <3826000 75>, <3783000 70>, <3746000 65>,
					<3714000 60>, <3683000 55>, <3650000 50>, <3628000 45>,
					<3612000 40>, <3600000 35>, <3587000 30>, <3571000 25>,
					<3552000 20>, <3525000 15>, <3492000 10>, <3446000 5>,
					<3400000 0>;
	};

	// add this to &rk817 node
	rk817_charger: charger {
		monitored-battery = <&battery>;
		rockchip,resistor-sense-micro-ohms = <10000>;
		rockchip,sleep-enter-current-microamp = <300000>;
		rockchip,sleep-filter-current-microamp = <100000>;
	};

You will also need to make sure that CONFIG_CHARGER_RK817 is enabled in your kernel.

Device-Tree Overlay

On some Linux distributions it may be possible to add the device-tree additions via an overlay, example given for the Renata 2800 mAh battery mentioned above (see here for Armbian on how to install the overlay):

/dts-v1/;
/plugin/;

/ {
    compatible = "pine64,quartz64-a", "rockchip,rk3566";

    // add this to root node (you may need to modify the values to fit your chosen battery)
    // Values for Renata 2800 mAh ICP606168PRT
    fragment@0 {
        target-path = "/";
        __overlay__ {
            battery: battery {
                compatible = "simple-battery";
                charge-full-design-microamp-hours = <2800000>;
                charge-term-current-microamp = <150000>;
                constant-charge-current-max-microamp = <1400000>;
                constant-charge-voltage-max-microvolt = <4200000>;
                factory-internal-resistance-micro-ohms = <200000>;
                voltage-max-design-microvolt = <4200000>;
                voltage-min-design-microvolt = <3200000>;
            
                ocv-capacity-celsius = <20>;
                ocv-capacity-table-0 =  <4200000 100>, <4054000 95>, <3984000 90>, <3926000 85>,
                    <3874000 80>, <3826000 75>, <3783000 70>, <3746000 65>,
                    <3714000 60>, <3683000 55>, <3650000 50>, <3628000 45>,
                    <3612000 40>, <3600000 35>, <3587000 30>, <3571000 25>,
                    <3552000 20>, <3525000 15>, <3492000 10>, <3446000 5>,
                    <3400000 0>;
            };
        };
    };

    // add this to &rk817 node
    fragment@1 {
        target = <&rk817>;
        __overlay__ {
            rk817_charger: charger {
                monitored-battery = <&battery>;
                rockchip,resistor-sense-micro-ohms = <10000>;
                rockchip,sleep-enter-current-microamp = <300000>;
                rockchip,sleep-filter-current-microamp = <100000>;
            };
        };
    };
};

Battery Parameter Limitations

  • the hardware limits the possible max. charge current to the discrete values 0.5A, 1.0A, 1.5A, 2.0A, 2.5A, 2.75A, 3.0A or 3.5A. The kernel driver will therefore use the largest value smaller or equal the configured value.

Device Driver Limitations

  • up to kernel version 6.11.2 the value of the temperature sensor is not exposed by the device driver

Recovering the PCIe-Slot after Power Cycling

As mentioned above the PCIe-slot is no longer powered when running on battery. The question is then: how to recover the PCIe-controller after power cycling such that a plugged in extension card (e.g. a SATA controller of whatever) is operational again. One use case is kind of a low-power mode, a NAS system with a decent number of hard-disks may consume about 40W-50W even when idle, while the Quartz64 running from battery consumes less than 2W (when idle).

Soft Reset and Rescan (not working)

Unfortunately, the following does not work:

echo 1 > /sys/bus/pci/devices/0000:00:00.0/remove
# turn power off, wait, turn power on
sleep 5 # or whatever periode
echo 1 > /sys/bus/pci/rescan

The PCIe-slot is then "back again" but not quite. The attached extension card is not reinitialized, and also an additional

echo 1 > /sys/bus/pci/devices/0000:00:00.0/rescan

does not change improve the situation. Without power cycle the above mentioned lines actually do work.

Basic Idea

However, some device drivers in Linux can be compiled as loadable modules which can be removed and reloaded again. The hope was that the device driver for the DW PCIe-controller does some reinitialization during the boot sequence which it does not when a mere "rescan" request is issued. If the device driver existed as loadable module then removing the driver and reloading it should in some sense simulate the boot initialization.

Kernel Patch

Unfortunately, the device driver drivers/pci/controller/dwc/pcie-dw-rockchip.c has not been designed as loadable module (as of Linux 6.11.3), but the necessary changes are only few. The following source-code patch will add the loadable module feature:

Media:Kernel-rockchip64-pcie-dwc-module.tar

(sorry for wrapping it into a tar archive, but .patch files are not allowed by this MediaWiki instance)

Using the patched Device Driver

After applying the patch, reconfiguring the kernel to use the PCIe driver as a module and recompiling and installing the kernel one is almost done. Of course, in order to do this you have to know how to apply patches to source code and how to recompile the kernel. It is beyond the scope of this Wiki page to elaborate on this, however, below are some notes for Armbian on this topic.

Disengaging the PCIe slot prior to power cycling:

# turn off anything using the PCIe extension card, unmount drives etc. then:
echo 1 > /sys/bus/pci/devices/0000:00:00.0/remove
rmmod pcie_dw_rockchip

Then switch off the 12V main power supply. The PCIe slot will then remain unpowered as mentioned above. In order to recover the PCIe slot and an attached extension card one has -- of course -- to switch on the main power supply and can then proceed as follows:

# wait some seconds after reattaching the main power supply
modprobe pcie_dw_rockchip

Afterwards there chances that the PCIe bus has been reinitialized and works as before.

Specific Linux Distributions

Armbian
Device Tree Additions

Save the DTB-overlay snippet mentioned above to a file, e.g. "battery.dts" and then use

sudo /usr/sbin/armbian-add-overlay battery.dts

in order to compile and add the overlay to "/boot/armbianEnv.txt".

Patching the Kernel

When using the Armbian build system, see https://github.com/armbian/build, it is possible to apply custom "user" patches by placing the patch file in userpatches/kernel/archive/KERNEL_NAME_AND_VERSION/PATCHFILE. For the example of using Ubunut "Noble" and trying to apply above mentioned patch to turn the PCIe driver into a loadable module this would be

userpatches/kernel/archive/rockchip64-6.6/kernel-rockchip64-pcie-dwc-module.patch

Afterwards, it is possible to reconfigure and recompile the kernel using the commands:

# after a while, the following will show the configuration menu
# go to "Device Drivers" -> "PCI Support" -> "PCI Controller Drivers" -> "DesignWare-based PCIe controllers"
# and configure "Rockchip DesignWare PCIe controller" to be built as module
./compile.sh  BOARD=quartz64a BRANCH=current kernel-config
# recompile the kernel
./compile.sh  BOARD=quartz64a BRANCH=current kernel
# recompile uboot (needed?)
./compile.sh  BOARD=quartz64a BRANCH=current uboot

The resulting .deb packages can be found in output/debs/, copy them to your running Quartz64 system and install them and reboot. On reboot the pcie_dw_rockchip module should be loaded automatically