Pimoroni NVME base

Hi all,

I purchased the Pimoroni NVME base with the Tachyon through the kickstarter campaign and have everything connected up with a Lexar NM800 Pro ssd. Unfortunately the Tachyon does not seem to acknowledge or recognise this additional storage being attached.

Has anybody had any luck with getting this to work? If so, did you need to do anything specific to get it working?

Thanks

Hey Chris!

Yes - we have this working well!

Can you output the text from running 'lspci' on your device?

Thanks

NIck.

Hi Nick,

Please see below, as requested. Please let me know if this is what you need (or something else).

particle@tachyon-fc3f64ac:~$ lspci
00:00.0 PCI bridge: Qualcomm Device 010b
01:00.0 Network controller: Qualcomm Device 1103 (rev 01)

I have disconnected the NVME base and reconnected in case there was an issue with my original assembly, but I still can’t see/access the drive unfortunately.

Thanks,

Chris

Hi all,

As an update to this, it seems the Lexar NM800 Pro is incompatible with the NVME base. I have tested the SSD separately and it is fully functional. I have also tested the base with another SSD which is recognised by the Tachyon.

I believe the NM800 Pro contains the InnoGrit IG5236 controller so perhaps it is one to avoid.

Chris

Thanks Chris. I picked up one of these and we’ll look into it and loop back!

lspci shows no PCIe device detected so curious as to the root cause.

Cheers,

Nick

I just tried to set up my NVMe base and it is showing up when running lspci but nothing new shows up in lsblk or /dev/.

I have tried both the below NVMe and a Western Digital PC SN720 which has a SanDisk controller.

0000:00:00.0 PCI bridge: Qualcomm Device 010b
0000:01:00.0 Network controller: Qualcomm Device 1103 (rev 01)
0001:00:00.0 PCI bridge: Qualcomm Device 010b (rev ff)
0001:01:00.0 Non-Volatile memory controller: Intel Corporation SSD Pro 7600p/760p/E 6100p Series (rev ff)

Samsung 990 Evo works with Pimoroni NVME base.

The Crucial P3 Plus (CT1000P3PSSD8) has been working well with my Tachyon and Pimoroni NVMe base.

I just found another NVMe and am still running into the same issue with this third one as well.

root@tachyon-03476d00:~# lspci
0000:00:00.0 PCI bridge: Qualcomm Device 010b
0000:01:00.0 Network controller: Qualcomm Device 1103 (rev 01)
0001:00:00.0 PCI bridge: Qualcomm Device 010b (rev ff)
0001:01:00.0 Non-Volatile memory controller: Phison Electronics Corporation E12 NVMe Controller (rev ff)

It does not show up in /dev/ at all.

I can also confirm that the WD SN720 is NOT recognized as disk but it is there as pci device.

I also use the official Pimoroni NVME base.

particle@tachyon-1faf943e:~$ lspci
0000:00:00.0 PCI bridge: Qualcomm Device 010b
0000:01:00.0 Network controller: Qualcomm Device 1103 (rev 01)
0001:00:00.0 PCI bridge: Qualcomm Device 010b (rev ff)
0001:01:00.0 Non-Volatile memory controller: Sandisk Corp WD Black 2018/PC SN720 NVMe SSD (rev ff)
particle@tachyon-1faf943e:~$ lsblk | grep disk
sda       8:0    0 116.7G  0 disk 
sdb       8:16   0     8M  0 disk 
sdc       8:32   0     8M  0 disk 
sdd       8:48   0   128M  0 disk 
sde       8:64   0   128M  0 disk 
sdf       8:80   0   144M  0 disk 
sdg       8:96   0   1.8G  0 disk 
zram0   253:0    0   3.6G  0 disk [SWAP]

Hi there,

same same.

The Kickstarter PM699 + Sandisk SN700 WD Red 4TB (which should work in principle)

lspci shows the controller
0001:01:00.0 Non-Volatile memory controller: Sandisk Corp Device 5006 (rev ff) (prog-if ff)
!!! Unknown header type 7f

But the controller never wakes up (remains in D3), and therefore no link-up.
dmesg | grep nvme
[ 9.845653] nvme 0001:01:00.0: Adding to iommu group 33
[ 9.852158] nvme nvme0: pci function 0001:01:00.0
[ 9.865167] nvme 0001:01:00.0: enabling device (0000 -> 0002)
[ 9.990699] nvme nvme0: 8/0/0 default/read/poll queues
[ 48.104988] nvme nvme0: controller is down; will reset: CSTS=0xffffffff, PCI_STATUS read failed (134)
[ 48.105812] blk_update_request: I/O error, dev nvme0n1, sector 7814036992 op 0x0:(READ) flags 0x80700 phys_seg 1 prio class 0
[ 48.118404] nvme 0001:01:00.0: Refused to change power state, currently in D3
[ 48.118443] nvme nvme0: Removing after probe failure status: -19
[ 48.118575] Buffer I/O error on dev nvme0n1, logical block 976754624, async page read

Tried both - on battery and on sufficient power supply.

Best regards
Thomas

Ok - Tried to dig a bit deeper into the problem

On RC1 (and similar solution proposed on RC0), NVMe drives enumerate, then drop off the bus shortly after boot.

dmesg shows a power-state failure path:

  • nvme nvme0: controller is down; will reset: CSTS=0xffffffff, PCI_STATUS read failed (134)
  • nvme 0001:01:00.0: Refused to change power state, currently in D3
  • nvme nvme0: Removing after probe failure status: -19

However, some drives do remain stable (as seen above), suggesting sensitivity to inrush/idle power and link power state.

What looks wrong in the BSP/DT

Boot logs for both RCs:

  • 1c08000.qcom,pcie: supply vreg-3p3 not found, using dummy regulator
  • 1c08000.qcom,pcie: supply vreg-mx not found, using dummy regulator

This implies the M.2 / 3.3 V rail and PERST# / CLKREQ# aren’t modeled; Linux cannot actually control the slot’s power/reset. When the endpoint idles or retrains, it falls into D3cold and can’t resume. After a failure, remove/rescan cannot revive the device (only a cold reboot helps), consistent with a powered-off slot.

Occasionally also see:

  • of_irq_parse_pci: failed with rc=134

indicating incomplete MSI/IRQ mapping for RC1.

What I tried (no permanent fix)

  • pcie_aspm=off or ASPM policy = performance
  • nvme_core.default_ps_max_latency_us=0 (disable APST).

Forcing power/control=on on the NVMe PCI function.
Adjusting boot cmdline (cannot reliably persist due to split boot image format).
These mitigate timing a bit but do not fix the D3/power loss when the rail isn’t really managed.

After boot:

Clock domain:

  • All PCIe RC0 and RC1 clocks (pcie_0_*, pcie_1_*, and corresponding gcc_pcie_* sources) are enabled and stable after link training.
  • PHY and PIPE clocks show valid rates (1 GHz and 19.2 MHz sources present).
  • This confirms that both root complexes (RC0/RC1) are powered and clocked correctly within the SoC.

Controller-side power/clock gating is not the cause of NVMe loss.

Regulator domain

  • Regulator summary shows only internal SoC rails:
    • 1c08000.qcom,pcie and 1c00000.qcom,pcie at 1.2 V / 0.88 V (PCIe PHY and GDSC rails).
    • gcc_pcie_0_gdsc and gcc_pcie_1_gdsc both enabled (state: normal).
  • No 3.3 V rail appears for either PCIe RC.
  • Kernel log confirms:
supply vreg-3p3 not found, using dummy regulator
  • Therefore, the external NVMe/M.2 slot 3.3 V rail is not modeled in the BSP — it’s outside kernel control.

Endpoint (NVMe) power is gated independently by CNSS/platform PM, causing D3cold and device loss.

Conclusion:

  • stability correlates with lower inrush/idle power and avoiding deep link power states, which points back to the slot power/reset not being controlled in DT.

Request:

  • Please provide a BSP/Device Tree update to:
    • Define real regulators for RC0/RC1 (no dummy fallback), e.g. vreg-3p3-supply, and wire:
      • perst-gpios (endpoint reset)
      • clkreq-gpios (clock request)
    • Fix MSI/IRQ mapping on RC1 (of_irq_parse_pci should not occur).
  • Consider disabling D3cold/ASPM L1.2 for NVMe endpoints by default until regulators are modeled.

Best regards
Thomas

2 Likes

Addition:
A question is now - do I have to use the 5 V auxiliary power hock from GPIO to the NVME base?
As I understood, the NVME power on the base is downsteped DC-DC from the 5V PCIe to 3.3V in order to power the SSD. Which max amp is provided here?
For the raspberry it is 5V/1A - IF this is the case here as well, then it might explain the NVME goes down during boot since the peak current draw of my used WD RED 4TB is higher than the max provided current thru the PCIe port.

Kind regards
Thomas

Hi there,

just an update.

It is the power management indeed. I was able to hock in the needed modifications to the kernel and the NVME is beeing recognized.
Culprit for my case - Unstable in case of the WD SN700 4TB - even with the additional 5 V power.

But if you want to give it a try for your drive I will describe what I have done.
Disclaimer : Use it at your own risk!

Get your current kernel parameters

cat /proc/cmdline

It should look like

cgroup_disable=pressure log_buf_len=256K earlycon=msm_geni_serial,0x994000 rcupdate.rcu_expedited=1 rcu_nocbs=0-7 kpti=off noinitrd console=ttyMSM0,115200,n8 video=Virtual-1:d earlycon=msm_geni_serial,0x994000 androidboot.hardware=qcom androidboot.console=ttyMSM0 androidboot.memcg=1 lpm_levels.sleep_disabled=1 msm_rtb.filter=0x237 service_locator.enable=1 firmware_class.path=/lib/firmware androidboot.usbcontroller=a600000.dwc3 swiotlb=2048 loop.max_part=7 cgroup.memory=nokmem,nosocket reboot=panic_warm net.ifnames=0 apparmor=1 security=apparmor root=PARTLABEL=system_a androidboot.bootdevice=1d84000.ufshc androidboot.fstab_suffix=default androidboot.serialno=97979b3 androidboot.baseband=msm msm_drm.dsi_display0=qcom,mdss_dsi_lt9611_720p_video: systemd.setenv="SLOT_SUFFIX=_a" skip_initramfs rootwait rw init=/sbin/init

It consists of a prefix + kernel parameters + suffix.
The parameters defined in boot_a is just this portion:

noinitrd console=ttyMSM0,115200,n8 video=Virtual-1:d earlycon=msm_geni_serial,0x994000 androidboot.hardware=qcom androidboot.console=ttyMSM0 androidboot.memcg=1 lpm_levels.sleep_disabled=1 msm_rtb.filter=0x237 service_locator.enable=1 firmware_class.path=/lib/firmware androidboot.usbcontroller=a600000.dwc3 swiotlb=2048 loop.max_part=7 cgroup.memory=nokmem,nosocket reboot=panic_warm net.ifnames=0 apparmor=1 security=apparmor

The goal is to append three additional parameters to the kernel to disable the pcie power management whilst keeping the length below 512 Byte (including the terminating NUL at the end)

Confirm that boot_a is (in my case - and it should be everywhere the same) in /dev/sdg24

lsblk -o NAME,SIZE,PARTLABEL /dev/sdg

Should output ├─sdg24 96M boot_a

Then create a working directory in root to keep our backup and as a working directory

mkdir -p /root/bootmod
cd /root/bootmod

Following will extract boot_a into boot_a.backup.img and extract the first 512 Byte starting from 0x40. The last command will show you the kernel parameters in boot_a.

dd if=/dev/sdg24 of=boot_a.backup.img bs=4M status=Progress
dd if=/dev/sdg24 of=cmdline.bin bs=1 skip=$((0x40)) count=512
tr '\0' '\n' < cmdline.bin | head -1

To append the needed parameters and make sure we do not define more then possible in boot_a

CURRENT=$(tr '\0' '\n' < cmdline.bin | head -1)
EXTRA="nvme_core.default_ps_max_latency_us=0 pcie_aspm=off pcie_port_pm=off"
NEW="$CURRENT $EXTRA"
LEN=$(printf '%s' "$NEW" | wc -c)
echo $LEN

LEN should be <= 511 - Otherwise we will destroy our boot_a

If ok - Then we can create the partial boot kernel parameter bin and overwrite boot_a only with this partial modification and cross-check the result directly from sdg24

printf '%s\0' "$NEW" > newcmdline.bin
truncate -s 512 newcmdline.bin
dd if=newcmdline.bin of=/dev/sdg24 bs=1 seek=$((0x40)) conv=notrunc
sync
dd if=/dev/sdg24 bs=1 skip=$((0x40)) count=512 | tr '\0' '\n' | head -1

Reboot and check again against

cat /proc/cmdline

Now the NVME should be kept alive during boot.
Create partition - mount - make some tests.

If you want to revert to the original boot_a

dd if=boot_a.backup.img of=/dev/sdg24 bs=4M conv=fsync

Hope it helps somewhat.

Best regards
Thomas

3 Likes