Debian on the XPS13 Plus (9320)

TL;DR; Still no sound, but I learned a couple of new things…

So, I finally got around to upgrading my laptop. I decided to go for my fourth XPS13, and this time I opted for a maxed out XPS13 Plus. A really nice machine. However, the driver stack isn’t quite there yet. Yes, I should have read up more before buying, but I didn’t and I know it will be sorted out over time.

As a vim user, the touch Esc key will be a challenge. Perhaps this is where I learn to bind to capslock, but I’ve not come to that point yet.

So, after installing using the netinst image with non-free drivers (and my phone over USB tether for networking since the wifi still didn’t work), I had to move to testing for anything to work. Then I installed firmware-iwlwifi, iwlwifi and firmware-sof-signed from non-free. This got me into a graphical desktop and most things work (I could configure the touch pad for tap-to-click, and so on). I run a KDE desktop, so I installed some Plymouth stuff, breeze for SDDM and such, but that shouldn’t affect the issues described here.

My current issues are the sound, the webcam and hibernation. The two latter items aren’t huge problems, but I do need sound. Both the webcam and sound issues are known. Hibernation is mostly about getting around to configuring it with the encrypted disk setup.

So, let’s start by diving into the audio issue. The early boot process looks like this:

[   20.595666] sof-audio-pci-intel-tgl 0000:00:1f.3: DSP detected with PCI class/subclass/prog-if info 0x040100
[   20.595750] sof-audio-pci-intel-tgl 0000:00:1f.3: SoundWire enabled on CannonLake+ platform, using SOF driver
[   20.595778] sof-audio-pci-intel-tgl 0000:00:1f.3: enabling device (0000 -> 0002)
[   20.596001] sof-audio-pci-intel-tgl 0000:00:1f.3: DSP detected with PCI class/subclass/prog-if 0x040100
[   20.596073] sof-audio-pci-intel-tgl 0000:00:1f.3: bound 0000:00:02.0 (ops i915_audio_component_bind_ops [i915])
[   20.602984] sof-audio-pci-intel-tgl 0000:00:1f.3: use msi interrupt mode
[   20.651283] sof-audio-pci-intel-tgl 0000:00:1f.3: hda codecs found, mask 4
[   20.652476] sof-audio-pci-intel-tgl 0000:00:1f.3: firmware: direct-loading firmware intel/sof/sof-adl.ri
[   20.652482] sof-audio-pci-intel-tgl 0000:00:1f.3: Firmware info: version 2:2:0-57864
[   20.652483] sof-audio-pci-intel-tgl 0000:00:1f.3: Firmware: ABI 3:22:1 Kernel ABI 3:23:0
[   20.652488] sof-audio-pci-intel-tgl 0000:00:1f.3: unknown sof_ext_man header type 3 size 0x30
[   20.747032] sof-audio-pci-intel-tgl 0000:00:1f.3: Firmware info: version 2:2:0-57864
[   20.747036] sof-audio-pci-intel-tgl 0000:00:1f.3: Firmware: ABI 3:22:1 Kernel ABI 3:23:0
[   25.758149] sof_sdw sof_sdw: snd_soc_register_card failed -517
[   25.768995] sof_sdw sof_sdw: snd_soc_register_card failed -517
[   25.799027] sof_sdw sof_sdw: snd_soc_register_card failed -517

If I later force a reload of the module, it all works:

sudo modprobe -r snd-sof-pci-intel-tgl; sudo modprobe snd-sof-pci-intel-tgl

Gives:

[  169.407671] sof-audio-pci-intel-tgl 0000:00:1f.3: DSP detected with PCI class/subclass/prog-if info 0x040100
[  169.407784] sof-audio-pci-intel-tgl 0000:00:1f.3: SoundWire enabled on CannonLake+ platform, using SOF driver
[  169.408027] sof-audio-pci-intel-tgl 0000:00:1f.3: DSP detected with PCI class/subclass/prog-if 0x040100
[  169.408133] sof-audio-pci-intel-tgl 0000:00:1f.3: bound 0000:00:02.0 (ops i915_audio_component_bind_ops [i915])
[  169.414240] sof-audio-pci-intel-tgl 0000:00:1f.3: use msi interrupt mode
[  169.428614] sof-audio-pci-intel-tgl 0000:00:1f.3: hda codecs found, mask 4
[  169.428802] sof-audio-pci-intel-tgl 0000:00:1f.3: firmware: direct-loading firmware intel/sof/sof-adl.ri
[  169.428809] sof-audio-pci-intel-tgl 0000:00:1f.3: Firmware info: version 2:2:0-57864
[  169.428810] sof-audio-pci-intel-tgl 0000:00:1f.3: Firmware: ABI 3:22:1 Kernel ABI 3:23:0
[  169.428814] sof-audio-pci-intel-tgl 0000:00:1f.3: unknown sof_ext_man header type 3 size 0x30
[  169.547087] sof-audio-pci-intel-tgl 0000:00:1f.3: Firmware info: version 2:2:0-57864
[  169.547115] sof-audio-pci-intel-tgl 0000:00:1f.3: Firmware: ABI 3:22:1 Kernel ABI 3:23:0
[  169.563645] sof-audio-pci-intel-tgl 0000:00:1f.3: firmware: direct-loading firmware intel/sof-tplg/sof-adl-rt1316-l12-rt714-l0.tplg
[  169.563665] sof-audio-pci-intel-tgl 0000:00:1f.3: Topology: ABI 3:22:1 Kernel ABI 3:23:0
[  169.564019] sof_sdw sof_sdw: ASoC: Parent card not yet available, widget card binding deferred
[  169.605390] sof_sdw sof_sdw: hda_dsp_hdmi_build_controls: no PCM in topology for HDMI converter 3
[  169.627693] input: sof-soundwire HDMI/DP,pcm=5 as /devices/pci0000:00/0000:00:1f.3/sof_sdw/sound/card0/input26
[  169.627738] input: sof-soundwire HDMI/DP,pcm=6 as /devices/pci0000:00/0000:00:1f.3/sof_sdw/sound/card0/input27
[  169.631375] input: sof-soundwire HDMI/DP,pcm=7 as /devices/pci0000:00/0000:00:1f.3/sof_sdw/sound/card0/input28

So, something happens after sof-adl.ri is loaded. This causes the driver to just stop before loading the sof-adl-rtl316-l12-rt714-l0.tplg firmware, causing the snd_soc_register_card to fail. Let’t have a look at the reasons.

First up, the excellent Arch Linux Wiki says to include the two firmware files and a bunch of modules in the initramfs. However, Arch and Debian uses different tools to build the initramfs, so let’s confirm the issue first:

lsinitramfs -l /boot/initrd.img-6.0.0-5-amd64  | grep 'intel/sof'

This call results in a list of nothing. Just to confirm, grepping for firmware or intel returns long lists of files. So, the firmware is not in the early initramfs image. How do I get the firmware files into the initramfs? Apparently I have to write what is known as an initramfs-tools hook script.

There lives a bunch of them over at /usr/share/initramfs-tools/hooks, so I started a very brute force one called intel-sof-firmware and tried to learn from the surrounding scripts and the manpage linked above. The result can be found in a gist here.

Notice that this is happy code. There is way too few sanity checks in there to make this useful to the general public. Your milage may vary.

So, I added the modules to /etc/initramfs/modules, and then updated the early initramfs images with this command:

sudo update-initramfs -k all -u

And then verified that the files made it to the image (I also had a look at the file listing in general to ensure that the image is ok):

lsinitramfs -l /boot/initrd.img-6.0.0-5-amd64  | grep 'intel/sof'

drwxr-xr-x   2 root     root            0 Dec 11 15:51 usr/lib/firmware/intel/sof
drwxr-xr-x   2 root     root            0 Dec 11 15:51 usr/lib/firmware/intel/sof-tplg
-rw-r--r--   1 root     root        28907 Dec 11 15:51 usr/lib/firmware/intel/sof-tplg/sof-adl-rt1316-l12-rt714-l0.tplg
-rw-r--r--   1 root     root       525056 Dec 11 15:51 usr/lib/firmware/intel/sof/sof-adl.ri

It all seems to work, so let’s reboot and see what comes out the other side. Notice – this can brick your computer if you make a mistake. And if something to do with a computer can brick your computer, you know that it will brick your computer. Don’t say I did not tell you.

Side note: I run an encrypted lvm setup, and if you try to fix this problem by removing all modules (go from many to netbook in the initramfs.conf) you will enjoy re-installing your machine. I’m sure you can unbrick it by booting from a USB stick and fixing stuff, but since I’ve not really installed anything, I don’t really care.

Guess what – after a couple of hours digging at this – I still have no sound…

sudo dmesg | grep sof

Results in this (yay, a new error code – that must mean that I’m doing something):

[    1.760559] sof-audio-pci-intel-tgl 0000:00:1f.3: DSP detected with PCI class/subclass/prog-if info 0x040100
[    1.760629] sof-audio-pci-intel-tgl 0000:00:1f.3: SoundWire enabled on CannonLake+ platform, using SOF driver
[    1.760643] sof-audio-pci-intel-tgl 0000:00:1f.3: enabling device (0000 -> 0002)
[    1.760785] sof-audio-pci-intel-tgl 0000:00:1f.3: DSP detected with PCI class/subclass/prog-if 0x040100
[    3.491343] sof-audio-pci-intel-tgl 0000:00:1f.3: bound 0000:00:02.0 (ops i915_audio_component_bind_ops [i915])
[    3.569000] sof-audio-pci-intel-tgl 0000:00:1f.3: use msi interrupt mode
[    3.585475] sof-audio-pci-intel-tgl 0000:00:1f.3: codec #2 probe error, ret: -2
[    3.585859] sof-audio-pci-intel-tgl 0000:00:1f.3: no hda codecs found!
[    3.585990] sof-audio-pci-intel-tgl 0000:00:1f.3: firmware: direct-loading firmware intel/sof/sof-adl.ri
[    3.585996] sof-audio-pci-intel-tgl 0000:00:1f.3: Firmware info: version 2:2:0-57864
[    3.585998] sof-audio-pci-intel-tgl 0000:00:1f.3: Firmware: ABI 3:22:1 Kernel ABI 3:23:0
[    3.586007] sof-audio-pci-intel-tgl 0000:00:1f.3: unknown sof_ext_man header type 3 size 0x30
[    3.702740] sof-audio-pci-intel-tgl 0000:00:1f.3: Firmware info: version 2:2:0-57864
[    3.702756] sof-audio-pci-intel-tgl 0000:00:1f.3: Firmware: ABI 3:22:1 Kernel ABI 3:23:0
[    3.709727] sof-audio-pci-intel-tgl 0000:00:1f.3: firmware: direct-loading firmware intel/sof-tplg/sof-adl-rt1316-l12-rt714-l0.tplg
[    3.709742] sof-audio-pci-intel-tgl 0000:00:1f.3: Topology: ABI 3:22:1 Kernel ABI 3:23:0
[    3.709825] sof-audio-pci-intel-tgl 0000:00:1f.3: error: can't connect DAI HDA0.OUT stream iDisp1
[    3.709920] sof-audio-pci-intel-tgl 0000:00:1f.3: error: failed to add widget id 0 type 27 name : HDA0.OUT stream iDisp1
[    3.710026] sof_sdw sof_sdw: ASoC: failed to load widget HDA0.OUT
[    3.710086] sof_sdw sof_sdw: ASoC: topology: could not load header: -22
[    3.710162] sof-audio-pci-intel-tgl 0000:00:1f.3: error: tplg component load failed -22
[    3.710247] sof-audio-pci-intel-tgl 0000:00:1f.3: error: failed to load DSP topology -22
[    3.710326] sof-audio-pci-intel-tgl 0000:00:1f.3: ASoC: error at snd_soc_component_probe on 0000:00:1f.3: -22
[    3.710447] sof_sdw sof_sdw: ASoC: failed to instantiate card -22
[    3.710692] sof_sdw sof_sdw: snd_soc_register_card failed -22
[    3.710758] sof_sdw: probe of sof_sdw failed with error -22

I suspect I’m missing another driver in the initramfs. Still, the modprobe trick shown above still fixes sound, so I guess I’ll leave it for today…

fosdem 2022

Yet another virtual fosdem. The organizer team does an amazing job putting it together, but fosdem without the hallway track will never be the same.

Nevertheless, I gave two talks in the Conference Organisation devroom. One on the topic of of the video flow that is used at foss-north, using OBS, Jitsi and Kdenlive. The other talk was about using pgeu-system to run a conference. Here, I was joined by the project author, Magnus Hagander, during the Q&A.

All in all, good fun. But I’m already looking forward to 2023 and a physical event in Brussels. Take care and I’ll see you there!

The Next Step

I recently blogged about my departure from MBition after a four year stint helping to build a software department within Mercedes Benz. Having contemplated various possible paths, I decided to leave my comfort zone and move away from automotive on-board software, which has been my life for the past 11 years.

Instead, I will help Autoliv Research’s ML/AI team to help them build awesome detection tools to help save more lives. This means working with a group of very smart people ranging from domain experts on things such as psychology, bio-mechanics, machine learning, embedded systems, mechatronics and more. I’m really really excited about this – so much fun to learn.

It is still early days and I still have a lot to learn, so I don’t know the details yet. I’ve been meeting people from all around the world for the past week and a half, and will continue to do so until Christmas, but the real fun starts in 2022.

The team is growing, so if you are interested in joining me in a quest to save lives and learning about real life applications of ML/AI in small embedded systems, don’t hesitate to reach out.

Moving on

In the autumn of 2017, me and my family moved down to Berlin for a month to start the infotainment software part of MBition. We were a handful of people at Mindspace in Mitte. I’ve never done so many interviews in my life – and I’ve never had the opportunity to get to know so many great people.

Fast forward to today, and we have grown to over 400 people in the project and are about to deliver an amazing product. The architecture team has grown from a one man team consisting of me, into one of the best groups of engineers I’ve ever worked with.

We wanted to change the world. We could not change everything, but I feel that we are bringing improvements to the project, as well as building a better foundation for future work at Mercedes Benz. I very much want to buy the first car with the MBient platform in it, as I know it will be an amazing product.

This has been a fantastic journey and one of the most challenging, but also rewarding, parts in my career. However, all things must come to an end. I’m sad to leave, but I’m also happy to say that I’m staying with the project as a part of the MBition Advisory Council. I’m happy not to go to Berlin twice a month, but I’m already missing the city, so I’m glad that I know that I will come back.

There are so many I’d like to thank and mention so I cannot begin to try to list you all – I’ll just forget someone. You know who you are! Keep up the great work and let’s meet the next time I’m in town!

Sharing dimensions

Continuing my adventures in FreeCAD, I now had to design a top to my Raspberry Pi enclosure. The FreeCAD people were friendly and told me to checkout spreadsheets.

However, since I already started down another path, I decided to name my constraints. Something I picked up from a random YouTube tutorial I cannot seem to find again.

Having done so, I can then refer to the name in a formula and thus, reuse the old value.

Now, let’s see how the lid will fit. :-)

FreeCAD-ing

I just got myself a 3D printer. It is my second one – I built a reprap back in 2013 – but this one is slightly more convenient to use. I went for the Creality CR6-SE. It works good enough for me out of the box, even though 3D printing is a topic where you can spend infinite time tweaking things.

I used to use OpenSCAD to create my models, as it maps well to my way of thinking (i.e. coding). However, I’ve decided to take some time to learn some new skills and this time around I went for FreeCAD.

FreeCAD is a free, as in freedom, parametric CAD program with a vibrant community. I’m new to CAD – parametric or not – so this is a learning experience for me.

I decided to create a case for my Raspberry Pi and PiTFT based home automation control panel shown in the video below.

To make this happen I first drew the important parts of the Raspberry Pi and the PiTFT hat, to be able to check that the case actually fits the contents. Then I dove into the creation of an enclosure.

The process of sketching, padding, rinse, and repeat is easy and somewhat tedious. I bet there are lots of ways to optimize this. E.g. by parametrize some dimensions to avoid having to “hardcode” them into each sketch. I guess smarter people can share some reference points between sketches too, e.g. to align the holes in the Raspberry Pi to the pegs and peg feet. I’ll learn this the next time around.

Having designed a bottom half, I decided to test fit it, so time to slice it up and then print it. Yes, I use the slicer that came with the printer, as I don’t want to tinker with the printer, but rather with the things I print.

Slicing the bottom of the case

Below, you can see the end result from the first test fitting. Hopefully the picture below shows something that fits as I bravely wrote this while printing. If not, then I really learned something, because I made a mistake.

Update! Turns out I made a 1mm mistake towards the bottom. The two HDMI connectors and the audio port project out more than I expected. Apart from that it sort of works. Now I’m printing v2 with 0.5mm thicker walls and the necessary adjustments to fit the ports.

Book Review: Cross-Platform Development with Qt 6 and Modern C++

I recently received a review copy of the Cross-Platform Development with Qt 6 and Modern C++ by Nibedit Dey available from Packt. I find it interesting to read books on Qt in the midst of a major version shift, as many of the underpinnings of Qt are revisited and updated by the development teams.

In his book, Nibedit balances between the newer technologies used, e.g. CMake, function reference based signals and slots, etc while referring back to Qt 5 (and even Qt 4) practices such as QMake, the SIGNAL and SLOT macros, and more. This gives a good context to the reader, which is good for the reader, as older practices still are used in older Qt-based codebases.

The book is divided into blocks with increasing depth and complexity. This makes it a good read for the beginner, as well as the more experienced used of Qt. Either you start from the beginning and get introduced to both widgets and QML, or you can dive straight into the more advanced topics such as the model-view concepts.

What I particularly like about the book is the focus on the cross-platform capabilities of Qt. This is how Qt was started, and something that is often lost these days. Qt is more than a UI toolkit and the real strength is the ability to use a single code base to build native applications for the major desktop (and some not so major) as well as the major mobile platforms. This is a reoccuring theme throughout the book where it starts by installing the Qt development environment on all major platforms, discusses how to setup Qt for mobile development, as well as for how to deploy Qt applications in all these scenarios.

There are other highlights too such as the chapter on testing, discussions on profiling and optimizations, and other topics not commonly found in this type of book.

What could be said to be missing is any content on embedded device development, 3D tooling and classes, the design focused tooling, and more. But Qt is such a broad topic these days that it would be impossible to cover it all in a single book.

All in all, this is a recommended read!

Time for PineTime

I just recieved my PineTime and set it up with GadgetBridge on my Android device. So far it has been a pleasant experience.

The unboxing experience was good. Inside a very anonymous brown cardboard box was a white box with the device.

The device itself was nicely presented. Under the clock is a tiny users manual and a charging dock.

My device was shipped with version 1.2 of the InfiniTime firmware, so I’m one release behind. I ordered the sealed device (because the price is amazing), but I already am itching to get coding.

Some highlights:

  • Just works!
  • Snappy UX
  • Some cute phone apps included

Left to do:

  • Get the heart rate sensor reading over to GadgetBridge
  • Is there a way to clear the notifications on the clock?
  • More watch faces and apps!

All in all, this was more then I expected and I’m really looking forward to playing with it (and hopefully not brick it…)

XmlListModels in Qt 6

I had a look at a small XmlListModel based project of mine and started migrating the code from Qt 5.12 to Qt 6.2. The code ports pretty cleanly, but there are some caveats to be aware of.

As I’m lazy, I started by changing the imports from 2.12 to 6.2 and tried running the code. The first changes I had to make was to change the import from QtQuick.XmlListModel to QtQml.XmlListModel. I also learned that the import statement no longer requires a specific version to be specified – I’m not sure if I’m a fan of that quite yet.

The second change was that XmlRole has been renamed to XmlListModelRole, and that it no longer has a query property, but an elementName and attributeName property. I guess that saves Qt from having to implement support for XPath queries, and in my use-case (and most others), this should still be enough.

The last change I had to made was to silence a warning. It is no longer encouraged to connect objects directly to signals in QML. In my case, it was animations triggered by the onAdd and onRemove signals in a model. The trick is to declare the animation (in my case, a pair of SequentialAnimation instances, separately. Provide an id for them, and then call start on that id in the signal handler.

All in all, a quite pleasant migration experience with only superficial API changes to handle. All logic could be used as is. Nice!

Upgrading NextCloudPi

So I finally got around to upgrading my NextCloudPi to version 20 with the hub and all. I really like it so far.

It also seems that I bumped into a know issue. All of a sudden I could not upload files over 8kB. It turns out that for some reasons the sys_temp_dir in /etc/php/7.3/php.ini had shifted from my USB media (a portable HDD) to the default location (/var/www/nextcloud/tmp) during the upgrade. After a quick move back to /media/USBDrive/data/tmp, everything is back to normal.

I found the solution over at the nextcloud forums.