Use device tree overlay to add ssd130x i2c OLED

Barebox bootloader
Kernel 5.19.3
OctavoSystems OSD3358-basic SOC
Solomon ssd1306 128x32 i2c (address: 0x3c) OLED module

I choose kernel 5.19.3 because it has support for the ssd1306-i2c via the ssd1307fb device driver. Previous kernel versions had support for the ssd1306 via SPI.

I enabled Kernel settings to build in (*) the frame buffer (FB) and ssd1307fb driver. I added the device to my custom device tree.
Here is snippet from my custom DT.

&i2c0 {
	pinctrl-names = "default";
	pinctrl-0 = <&i2c0_pins>;

	status = "okay";
	clock-frequency = <100000>;

	tps: tps@24 {
		reg = <0x24>;
	};

	baseboard_eeprom: baseboard_eeprom@50 {
		compatible = "atmel,24c256";
		reg = <0x50>;

		#address-cells = <1>;
		#size-cells = <1>;
		baseboard_data: baseboard_data@0 {
			reg = <0 0x100>;
		};
	};
// begin of ssd
	ssd1306_i2c: oled@3c {
		compatible = "solomon,ssd1306fb-i2c";
		reg = <0x3c>;
		solomon,height = <32>;
		solomon,width = <128>;
		solomon,com-seq;
		solomon,com-invdir;
		solomon,page-offset = <0>;
		solomon,prechargep1 = <2>;
		solomon,prechargep2 = <13>;
	};
// end of ssd
};

After kernel boots, snippet from dmsg command

[    3.899152] Console: switching to mono frame buffer device 16x4                                                                    
[    3.963033] ssd1307fb 0-003c: fb0: Solomon SSD1307 framebuffer device registered, using 512 bytes of video memory

The device shows up as /dev/fb0. I can open the frame buffer device /dev/fb0 in C code as FILE and fprintf() to the panel.
I understand that enabling the device in the kernel and editing the device tree is a way to add the device. However I would like to take the oppertunity to learn how to add a device using device tree overlay. I made no changes to the kernel, i.e. the FB and ssd1307 are built into the kernel.

I removed the ssd from my DT and created my_ssd1306.dts

/dts-v1/;
/plugin/;

/ {
fragment@0 {
target = <&i2c0>;
__overlay__ {

	ssd1306_i2c: oled@3c {
		compatible = "solomon,ssd1306fb-i2c";
		reg = <0x3c>;
		solomon,height = <32>;
		solomon,width = <128>;
		solomon,com-seq;
		solomon,com-invdir;
		solomon,page-offset = <0>;
		solomon,prechargep1 = <2>;
		solomon,prechargep2 = <13>;
	};
};
};
};

I built the overlay using the kernel make command ‘make dtbs’.
I now have a ‘my_ssd1306.dtbo’ file but I don’t understand what to do next.

Do I copy the .dtbo to a folder?
If yes, which folder?
How do I tell the kernel to load/apply the overlay?

Thank you,

Hi @jakthree the dtc maintainers really want to end that older syntax…

This is the same file, with the newer syntax…

/dts-v1/;
/plugin/;

&i2c0 {
	ssd1306_i2c: oled@3c {
		compatible = "solomon,ssd1306fb-i2c";
		reg = <0x3c>;
		solomon,height = <32>;
		solomon,width = <128>;
		solomon,com-seq;
		solomon,com-invdir;
		solomon,page-offset = <0>;
		solomon,prechargep1 = <2>;
		solomon,prechargep2 = <13>;
	};
};

With the BBB, we’ve designed an overlay loader thru /boot/uEnv.txt…

As long as the *.dtbo is in under /lib/firmware/ you can load it via:

uboot_overlay_addr4=file.dtbo

If you don’t have our patchset, you need to do a custom boot script…

Regards,

RCN,
During my google searches, I have seen both syntax. I was not aware there was old and new. Thank you for the guidance.
Based upon your reply and my best guess, I understand it is by design that the bootloader is responsible for applying the overlay(s) to the device tree (DT) before passing the DT to the kernel.
Do I understand correctly?

Can you provide some history,
Has the bootloader always been designed to apply the overlay?
How was the overlay applied before the bootloader did the job?
Does the kernel have a way to apply the overlay during boot?
Does the user have a way to apply an overlay after the kernel boots?

Thank you,

That is correct…

That would be a novel that spans 10+ years of development, debugging, etc…

Today, we all agree the bootloader is the proper “sane” place to do that…

That was the initial idea 10 years ago, it ‘sorta’ worked… it was endless buggy… impossible to support…

Frank has a list here of all the fun ‘kernel’ side issues with overlays…

https://elinux.org/Frank's_Evolving_Overlay_Thoughts

The straight and simple answer, use u-boot to load the device tree and apply overlays…

Regards,

In reference to the new overlay syntax. I have read here Devicetree Overlay Notes — The Linux Kernel documentation that my-main.dts has to be built with the -@ option or the label “&i2c0” will not be available. In which case you use the target path “&{/i2c0}”. I build my-main.dts and my-ssd1306.dts with the kernel’s “make dtbs” command. I don’t know if the -@ option is used.

Is the resulting my-ssd1306.dtbo file the file to copy to the /lib/firmware folder?

Thank you,

it’s been enabled by default in my kernel builds for a very long time…

Regards,

RCN,
It has been awhile. My board has been in production for several years thanks to answers posted on this forum. I never got the device tree overlay to work. Moving forward to today. I am working with kernel 5.19.3, because it was the first that I found to have built-in support for the ssd1306 via the ssd1707fb driver. Also 5.19.3 supports DT overlays. I have the ssd1306 128x32 OLED panel to working when adding the node to my main.dts and building a main.dtb file. I now have a ssd1306 128x64 panel. I want to create an overlay .dtbo file that will change my panel from 128x32 to 128x64. I have two .dts files. First is the old style syntax that builds without warnings.

/dts-v1/;
/plugin/;

/ {
	fragment@0 {
		target = <&i2c0>;
		__overlay__ {
			status = "okay";
			#address-cells = <1>;
			#size-cells = <0>;
			ssd1306_i2c: oled@3c {
				compatible = "solomon,ssd1306fb-i2c";
				reg = <0x3c>;
				solomon,height = <32>;
				solomon,width = <128>;
				solomon,com-seq;
				solomon,com-invdir;
				solomon,page-offset = <0>;
				solomon,prechargep1 = <2>;
				solomon,prechargep2 = <13>;
			};
		};
	};
};

The second is new style syntax that builds but has warnings. The warnings are

/dts-v1/;
/plugin/;

&i2c2 {
	ssd1306_i2c: oled@3c {
		compatible = "solomon,ssd1306fb-i2c";
		reg = <0x3c>;
		solomon,height = <32>;
		solomon,width = <128>;
		solomon,com-seq;
		solomon,com-invdir;
		solomon,page-offset = <0>;
		solomon,prechargep1 = <2>;
		solomon,prechargep2 = <13>;
	};
};
dtc -@ -I dts -O dtb -o arch/arm/boot/dts/ssd1306.dtbo arch/arm/boot/dts/ssd1306.dts

  DTC arch/arm/boot/dts/ssd1306.dtbo
../arch/arm/boot/dts/ssd1306.dts:7.3-16: Warning (reg_format): /fragment@0/__overlay__/oled@3c:reg: property has invalid length (4 bytes) (#address-cells == 2, #size-cells == 1)
arch/arm/boot/dts/ssd1306.dtbo: Warning (pci_device_reg): Failed prerequisite 'reg_format'
arch/arm/boot/dts/ssd1306.dtbo: Warning (pci_device_bus_num): Failed prerequisite 'reg_format'
arch/arm/boot/dts/ssd1306.dtbo: Warning (i2c_bus_reg): Failed prerequisite 'reg_format'
arch/arm/boot/dts/ssd1306.dtbo: Warning (spi_bus_reg): Failed prerequisite 'reg_format'
../arch/arm/boot/dts/ssd1306.dts:5.23-15.4: Warning (avoid_default_addr_size): /fragment@0/__overlay__/oled@3c: Relying on default #address-cells value
../arch/arm/boot/dts/ssd1306.dts:5.23-15.4: Warning (avoid_default_addr_size): /fragment@0/__overlay__/oled@3c: Relying on default #size-cells value

I think the warning are because the new style doesn’t have #address-cells and #size-cells in it.

What is the correct new style syntax for including #address-cells and #size-cells?

Thank you,
Jack

This an overlay not a full device-tree, so some of dtc’s error checks do not apply…

Here are the ones we commonly disable: Makefile · v6.12.x-Beagle · BeagleBoard.org / BeagleBoard-DeviceTrees · GitLab

Even with the new syntax, i leave the #address/size options in: src/arm/overlays/BB-I2C1-MCP7940X-00A0.dtso · v6.12.x-Beagle · BeagleBoard.org / BeagleBoard-DeviceTrees · GitLab

Regards,

RCN,
Thank you for the links. Here is my edited overlay file.

/dts-v1/;
/plugin/;

&i2c2 {
	#address-cells = <1>;
	#size-cells = <0>;
	ssd1306_i2c: oled@3c {
		compatible = "solomon,ssd1306fb-i2c";
		reg = <0x3c>;
		solomon,height = <32>;
		solomon,width = <128>;
		solomon,com-seq;
		solomon,com-invdir;
		solomon,page-offset = <0>;
		solomon,prechargep1 = <2>;
		solomon,prechargep2 = <13>;
	};
};

I used this command line to build the overlay.
kernel: 5.19.3
dtc -@ -I dts -O dtb -o /arch/arm/boot/dts/ssd1306-128x32.dtbo /arch/arm/boot/dts/ssd1306-128x32.dts
The build produces a file size 666 bytes and I am able to apply the resulting .dtbo to my main device tree with no problem.

A follow up question. When I use the kernel’s
make ARCH=arm dtbs
It produces a files size of 555 bytes and during boot complains that symbols are not found.

make ARCH=arm dtbs DTC_EXTRA_FLAGS=“-@”
Also produces a file size of 555 bytes.

How do I get make to pass -@ to DTC?

Thank you,
Jack

Let’s see for 5.19.x, something like: https://openbeagle.org/RobertCNelson/bb-kernel/-/blob/am33x-v5.19/patches/RPi/0001-Overlays-Port-RPi-Overlay-building.patch?ref_type=heads

Regards,

RCN,
Your links pointed me in the right direction. I did not edit any Makefiles.
I used this command
DTC_FLAGS=-@ make ARCH=arm dtbs

I don’t know what else ‘DTC_FLAGS’ effects but it built the .dtb and .dtbo files with symbols.
Thank you,
Jack

Update. I was using a ssd1306 at 128x32 resolution. I found a ssd1306 with 128x64, but the original overlay file didn’t work. Here are the overlay files for the different resolutions.
They were connected to my i2c2. You may need to change the i2c to match your design.

ssd1306-128x32.dst

/dts-v1/;
/plugin/;

&i2c2 {
	#address-cells = <1>;
	#size-cells = <0>;
	ssd1306_i2c: oled@3c {
		compatible = "solomon,ssd1306fb-i2c";
		reg = <0x3c>;
		solomon,height = <32>;
		solomon,width = <128>;
		solomon,com-seq;
		solomon,com-invdir;
		solomon,page-offset = <0>;
		solomon,prechargep1 = <2>;
		solomon,prechargep2 = <13>;
	};
};

ssd1306-128x64.dts

/dts-v1/;
/plugin/;

&i2c2 {
	#address-cells = <1>;
	#size-cells = <0>;
	ssd1306_i2c: oled@3c {
		compatible = "solomon,ssd1306fb-i2c";
		reg = <0x3c>;
		solomon,height = <64>;
		solomon,width = <128>;
		solomon,com-invdir;
	};
};