Skip to contentSkip to conversation

Appended DTB files for multi-machine kernels

RFC PATCH New Daniel Mack 8 participants 38 messages Jul 4, 2013 – Aug 3, 2013 Kbuild

lore
Share & tools
lore
#0 lore raw

Hi,

I'm facing a problem with a transition from legacy board-file driven ARM machines to DTB, and I'm under the impression that a solution for it could be of broader interest.

In short, devices that have been deployed in quantities come in three hardware variants, which all boot with a unique machine-id. We ship kernel images that have board support for all three machine types, and do minor fixups to platform data of some drivers at runtime, depending on the board revision number (passed in via ATAGs).

The built-in support for attaching a DTB to the zImage does not suffice here, because we have one image for all models, and also, we couldn't do a 'per-board-revision' selection that way either.

Unless I missed some recent discussion, this case is not easy to handle. Yes, I know that these kind of things should be handled by a next-generation bootloader, but in our case, we want to avoid a loader update of already shipped hardware by all means.

As a solution, I'm thinking of a small framework that could for example work as follows.

a) A small mechanism allows storing multiple DTB binary files inside the kernel binary at compile time, and a simple function can extract them again by name at runtime (something like what the firmware framework does, but I don't know if that one can be used at such an early stage in the boot process).

b) A DT_MACHINE_START-like macro takes both the machine ID and the name of a DTB file that is compiled in. When matched, generic functions would load the given file, populate the device tree and then conduct a generic DT boot for the specified platform.

c) Allow users to open-code the DTB lookup depending on whatever kind of runtime information (be it the board_revision or anything else).

Of course, everything has to be an opt-in that stubs itself out at zero costs if not needed.

I'm open to opinion and sugesstions :)

Thanks,
Daniel

#1 lore raw
Quoted 4 lines · Daniel Mack

Unless I missed some recent discussion, this case is not easy to handle. Yes, I know that these kind of things should be handled by a next-generation bootloader, but in our case, we want to avoid a loader update of already shipped hardware by all means.

There was some discussion about appending multiple DTBs recently. I can't actually recall anything about it though so that's not an entirely helpful thing...

Quoted 8 lines

As a solution, I'm thinking of a small framework that could for example work as follows.

a) A small mechanism allows storing multiple DTB binary files inside the kernel binary at compile time, and a simple function can extract them again by name at runtime (something like what the firmware framework does, but I don't know if that one can be used at such an early stage in the boot process).

Another way of skinning this would be for either the kernel to contain
a set of machine ID to compatible string mappings or for the device
trees for the boards to have an additional properties giving the machine
IDs that the boards match. The kernel could then look for multiple DTBs
appended to the image and try to pick one based on ATAGs.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130704/ecc19fcd/attachment.sig>

#2 lore raw
Quoted 10 lines · Mark Brown
Quoted 4 lines · Daniel Mack

Unless I missed some recent discussion, this case is not easy to handle. Yes, I know that these kind of things should be handled by a next-generation bootloader, but in our case, we want to avoid a loader update of already shipped hardware by all means.

There was some discussion about appending multiple DTBs recently. I can't actually recall anything about it though so that's not an entirely helpful thing...

Yes, it keeps coming up, I think by now everybody agreed it's a good idea to extend the ATAGS compat mode, but so far nobody has implemented it. Magnus Damm was very interested in this feature last year and was planning to work on it, but I don't know how far he got.

Quoted 9 lines
Quoted 8 lines

As a solution, I'm thinking of a small framework that could for example work as follows.

a) A small mechanism allows storing multiple DTB binary files inside the kernel binary at compile time, and a simple function can extract them again by name at runtime (something like what the firmware framework does, but I don't know if that one can be used at such an early stage in the boot process).

Quoted 5 lines

Another way of skinning this would be for either the kernel to contain a set of machine ID to compatible string mappings or for the device trees for the boards to have an additional properties giving the machine IDs that the boards match. The kernel could then look for multiple DTBs appended to the image and try to pick one based on ATAGs.

IIRC there is actually an unused field in the dtb header that could be used to match a board ID.

Arnd

#3 lore raw

Hi Arnd,

Quoted 10 lines · Arnd Bergmann
Quoted 5 lines · Mark Brown

Another way of skinning this would be for either the kernel to contain a set of machine ID to compatible string mappings or for the device trees for the boards to have an additional properties giving the machine IDs that the boards match. The kernel could then look for multiple DTBs appended to the image and try to pick one based on ATAGs.

IIRC there is actually an unused field in the dtb header that could be used to match a board ID.

While that would help many users, it doesn't cover our case where different board revisions require different DTBs to be loaded, depending on the supplied ATAG.

I think I'll go for Nicolas Pitre's suggestion as first step. He's right that's it's a hack anyway, and we're just dealing with legacy systems here, and hence it might not even be worth caring too much about a proper solution.

Thanks for all the answers,
Daniel

#4 lore raw
In reply to Arnd Bergmann

Hi Arnd,

Quoted 8 lines · Arnd Bergmann
Quoted 7 lines · Mark Brown
Quoted 4 lines · Daniel Mack

Unless I missed some recent discussion, this case is not easy to handle. Yes, I know that these kind of things should be handled by a next-generation bootloader, but in our case, we want to avoid a loader update of already shipped hardware by all means.

Quoted 8 lines
Quoted 3 lines

There was some discussion about appending multiple DTBs recently. I can't actually recall anything about it though so that's not an entirely helpful thing...

Yes, it keeps coming up, I think by now everybody agreed it's a good idea to extend the ATAGS compat mode, but so far nobody has implemented it. Magnus Damm was very interested in this feature last year and was planning to work on it, but I don't know how far he got.

Correct, I was and still am a bit interested in it. I did however never get around to write any code. My apologies if that stalled anyone.

With mach-shmobile we're now getting to a point where most of our boards are using DT_MACHINE and appended DTB instead of the MACHINE and mach-type. Because of that I feel that the moment has sort of passed for me.

Regardless of this nearly all our boot loaders pass mach-type so it would be nice to match on that instead of the appended DTB.

Thanks,

/ magnus

#5 lore raw
In reply to Daniel Mack
Quoted 39 lines · Daniel Mack

Hi,

I'm facing a problem with a transition from legacy board-file driven ARM machines to DTB, and I'm under the impression that a solution for it could be of broader interest.

In short, devices that have been deployed in quantities come in three hardware variants, which all boot with a unique machine-id. We ship kernel images that have board support for all three machine types, and do minor fixups to platform data of some drivers at runtime, depending on the board revision number (passed in via ATAGs).

The built-in support for attaching a DTB to the zImage does not suffice here, because we have one image for all models, and also, we couldn't do a 'per-board-revision' selection that way either.

Unless I missed some recent discussion, this case is not easy to handle. Yes, I know that these kind of things should be handled by a next-generation bootloader, but in our case, we want to avoid a loader update of already shipped hardware by all means.

As a solution, I'm thinking of a small framework that could for example work as follows.

a) A small mechanism allows storing multiple DTB binary files inside the kernel binary at compile time, and a simple function can extract them again by name at runtime (something like what the firmware framework does, but I don't know if that one can be used at such an early stage in the boot process).

b) A DT_MACHINE_START-like macro takes both the machine ID and the name of a DTB file that is compiled in. When matched, generic functions would load the given file, populate the device tree and then conduct a generic DT boot for the specified platform.

c) Allow users to open-code the DTB lookup depending on whatever kind of runtime information (be it the board_revision or anything else).

Quoted 5 lines

Of course, everything has to be an opt-in that stubs itself out at zero costs if not needed.

I'm open to opinion and sugesstions :)

What you describe above more or less fits the definition of what I called the "impedance matcher". However it doesn't need to be part of the kernel at all. But you should make it into a separate binary.

Please have a look at the bottom of this post for a more comprehensive
description: http://article.gmane.org/gmane.linux.ports.arm.kernel/242929

Nicolas

#6 lore raw

Hi Nicolas,

Quoted 9 lines · Nicolas Pitre
Quoted 1 line · Daniel Mack

I'm open to opinion and sugesstions :)

What you describe above more or less fits the definition of what I called the "impedance matcher". However it doesn't need to be part of the kernel at all. But you should make it into a separate binary.

Please have a look at the bottom of this post for a more comprehensive
description: http://article.gmane.org/gmane.linux.ports.arm.kernel/242929

Thanks for the link. Interesting read indeed.

The only thing I'm pondering about is that we already have generic loader code in Linux and a build system that supports a wide range of platforms. I don't know whether it's worth opening that can of worms again and re-implement all details about load addresses, compiler flags, device-tree parsing code yet once again. At least in terms of LOCs, we would certainly be better off doing it inside the kernel.

But I generally second your opinion about pushing vendors to do it right, so I might give that approach a shot soon; there is no code yet anywhere I take it?

Thanks,
Daniel

#7 lore raw
Quoted 13 lines · Daniel Mack

Hi Nicolas,

Quoted 9 lines · Nicolas Pitre
Quoted 1 line · Daniel Mack

I'm open to opinion and sugesstions :)

What you describe above more or less fits the definition of what I called the "impedance matcher". However it doesn't need to be part of the kernel at all. But you should make it into a separate binary.

Please have a look at the bottom of this post for a more comprehensive
description: http://article.gmane.org/gmane.linux.ports.arm.kernel/242929

Quoted 8 lines

Thanks for the link. Interesting read indeed.

The only thing I'm pondering about is that we already have generic loader code in Linux and a build system that supports a wide range of platforms. I don't know whether it's worth opening that can of worms again and re-implement all details about load addresses, compiler flags, device-tree parsing code yet once again. At least in terms of LOCs, we would certainly be better off doing it inside the kernel.

That is still code with relatively low value that has to be carried and maintained.

And if you do it for your own device outside of the kernel then you can literally hack it the way you want quickly and forget about it once it works. Since this is useful for legacy setups only, you do not have to care about maintaining it in the future.

Quoted 3 lines

But I generally second your opinion about pushing vendors to do it right, so I might give that approach a shot soon; there is no code yet anywhere I take it?

Not that I'm aware of, besides parts of libfdt and atags_to_fdt.c from the kernel tree that can be lifted and modified according to your needs. I don't imagine you'd need much more than that anyway.

Nicolas

#8 lore raw
In reply to Nicolas Pitre
Quoted 8 lines · Nicolas Pitre
Quoted 6 lines · Daniel Mack

In short, devices that have been deployed in quantities come in three hardware variants, which all boot with a unique machine-id. We ship kernel images that have board support for all three machine types, and do minor fixups to platform data of some drivers at runtime, depending on the board revision number (passed in via ATAGs).

Quoted 6 lines

What you describe above more or less fits the definition of what I called the "impedance matcher". However it doesn't need to be part of the kernel at all. But you should make it into a separate binary.

Please have a look at the bottom of this post for a more comprehensive
description: http://article.gmane.org/gmane.linux.ports.arm.kernel/242929

FWIW, I gave that approach a try today for a PXA based hardware platform, and in fact it seems to work very well. Thanks again for sharing the idea.

In case anyone is interested, the repository is here:

https://github.com/zonque/pxa-impedance-matcher

As the README says, it's completely specific to my use case, but maybe anyone can use the code base to spin a different version for a different board.

Daniel

#9 lore raw
Quoted 20 lines · Daniel Mack
Quoted 8 lines · Nicolas Pitre
Quoted 6 lines · Daniel Mack

In short, devices that have been deployed in quantities come in three hardware variants, which all boot with a unique machine-id. We ship kernel images that have board support for all three machine types, and do minor fixups to platform data of some drivers at runtime, depending on the board revision number (passed in via ATAGs).

Quoted 6 lines

What you describe above more or less fits the definition of what I called the "impedance matcher". However it doesn't need to be part of the kernel at all. But you should make it into a separate binary.

Please have a look at the bottom of this post for a more comprehensive
description: http://article.gmane.org/gmane.linux.ports.arm.kernel/242929

FWIW, I gave that approach a try today for a PXA based hardware platform, and in fact it seems to work very well. Thanks again for sharing the idea.

Quoted 7 lines

In case anyone is interested, the repository is here:

https://github.com/zonque/pxa-impedance-matcher

As the README says, it's completely specific to my use case, but maybe anyone can use the code base to spin a different version for a different board.

That looks nice, but I'd suggest going a step further if possible.

If you could load the kernel zImage independently with a separate load command in u-boot, then people could update their kernel only without having to relink with this shim. The load address for that zImage can be totally arbitrary as longas it is known to be the same from within this shim and in the u-boot script.

Also, more related to your code, you apparently link and load it to run at 0xa0008000. This is also where the zImage code is going to decompress the final kernel image after it has relocated itself. I'm afraid the DTBs you point to might be overwritten at that point since zImage is not aware of them (in fact I'm surprized this works at all as you say). If I were you I'd use 0xa1000000 instead (and make sure the initrd is out of the way as well if you have one).

Nicolas

#10 lore raw

cover impedance-matcher generic improvements

In reply to Daniel Mack

Daniel,

Here's a patch (plus a cscope target) to attempt to make the impedance-matcher generic code. Hopefully I'll have time to test tomorrow. All I can say atm is that it compiles cleanly with and without specifying an appended zImage.

Warning: the code in string.c is little better than psuedo-code, maybe not even that good. I'm posting this so if anyone else is inclined to work on this, there's no need to duplicate effort. And, I have a firm belief in the motivating effects af posting half-assed code. ;-)

Basic idea is to replace a device's stock kernel with this impedance-matcher. Load the kernel and/or the devicetree blob to desired addresses. Add 'loadaddrs=0xXXXXXXXX,0xYYYYYYYY' to the kernel's command line. Or, if you are appending, 'loadaddrs=appended,0xYYYYYYYY'. First address is the location of the kernel, second is the location of the dtb.

Then, for u-boot, 'bootm 0xZZZZZZZZ' where 0xZZZZZZZZ is the address of the impedance-matcher.

For those interested, a public branch can be found at (prone to rebase!):

git://git.infradead.org/users/jcooper/impedance-matcher.git master

Thomas,

You weren't in the original Cc: of this thread, I added you because this may help with your shifting register base address issues.

thx,

Jason.

Jason Cooper (2):
add cscope Makefile target
WIP: Get kernel and dtb addresses from command line

 .gitignore |  1 +
 Makefile   | 31 ++++++++++------------
 atags.h    |  6 +++++
 board.c    | 88 --------------------------------------------------------------
 board.h    | 13 ----------
 led.c      | 54 --------------------------------------
 led.h      |  6 -----
 main.c     | 52 +++++++++++++++++++++----------------
 string.c   | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 string.h   |  8 ++++++
 10 files changed, 141 insertions(+), 201 deletions(-)
 delete mode 100644 board.c
 delete mode 100644 board.h
 delete mode 100644 led.c
 delete mode 100644 led.h
 create mode 100644 string.c
 create mode 100644 string.h
Signature · 1 line
1.8.3.2
#11 lore raw

PATCH 1/2 add cscope Makefile target

---
 .gitignore | 1 +
 Makefile   | 6 ++++++
 2 files changed, 7 insertions(+)
.gitignore +1 -0
index c3b59bf..ac4198c 100644
@@ -1,6 +1,7 @@
 *.sh
 *.o
 *.bin
+cscope.*
 matcher
 uImage
 input/zImage
Makefile +6 -0
index 5ad5fc0..daeafa4 100644
@@ -43,3 +43,9 @@ uImage: matcher.bin
 clean:
 	rm -fr matcher.bin matcher *.o uImage
 
+distclean:
+	rm -fr cscope.*
+
+cscope:
+	-find . -name "*.[chS]" >cscope.files
+	-cscope -b -R
Signature · 1 line
1.8.3.2
#12 lore raw

RFC PATCH 2/2 WIP: Get kernel and dtb addresses from command line

In reply to Jason Cooper

Allow for detached kernel and dtb images.

---
 Makefile | 25 ++++++------------
 atags.h  |  6 +++++
 board.c  | 88 ----------------------------------------------------------------
 board.h  | 13 ----------
 led.c    | 54 ---------------------------------------
 led.h    |  6 -----
 main.c   | 52 +++++++++++++++++++++-----------------
 string.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 string.h |  8 ++++++
 9 files changed, 134 insertions(+), 201 deletions(-)
 delete mode 100644 board.c
 delete mode 100644 board.h
 delete mode 100644 led.c
 delete mode 100644 led.h
 create mode 100644 string.c
 create mode 100644 string.h
Makefile +8 -17
index daeafa4..deb76b9 100644
@@ -1,4 +1,10 @@
-CFLAGS=-Wall -ffreestanding
+ifeq ($(origin APPEND_IMAGE), undefined)
+DOAPPEND=
+else
+DOAPPEND=-DAPPENDED_IMAGE=1
+endif
+
+CFLAGS=-Wall -ffreestanding $(DOAPPEND)
 LDFLAGS=-static -nostdlib
 GCC=$(CROSS_COMPILE)gcc
 OBJCOPY=$(CROSS_COMPILE)objcopy
@@ -6,30 +12,15 @@ LD=$(CROSS_COMPILE)ld
 LOADADDR=0xa0008000
 BINFMT=elf32-littlearm
 
-INPUT_OBJS = \
-	zimage.o		\
-	dtb-raumfeld-controller-0.o	\
-	dtb-raumfeld-controller-1.o	\
-	dtb-raumfeld-controller-2.o	\
-	dtb-raumfeld-connector-0.o	\
-	dtb-raumfeld-connector-1.o	\
-	dtb-raumfeld-connector-2.o	\
-	dtb-raumfeld-speaker-0.o	\
-	dtb-raumfeld-speaker-1.o	\
-	dtb-raumfeld-speaker-2.o
-
 all: uImage
 
-dtb-%.o: input/%.dtb
-	$(OBJCOPY) -I binary -O $(BINFMT) -B arm $^ $@
-
 zimage.o: input/zImage
 	$(OBJCOPY) -I binary -O $(BINFMT) -B arm $^ $@
 
 %.o: %.c
 	$(GCC) $(CFLAGS) -c $^
 
-matcher: main.o print.o board.o led.o $(INPUT_OBJS)
+matcher: main.o print.o string.o $(APPEND_IMAGE)
 	$(LD) $(LDFLAGS) -T matcher.lds -o $@ $^
 
 matcher.bin: matcher
atags.h +6 -0
index 30e6ee7..67d3d01 100644
@@ -10,15 +10,21 @@ struct tag_header {
 
 /* board revision */
 #define ATAG_REVISION   0x54410007
+#define ATAG_CMDLINE	0x54410009
 
 struct tag_revision {
 	__u32 rev;
 };
 
+struct tag_cmdline {
+	char cmdline[1];     /* this is the minimum size */
+};
+
 struct tag {
 	struct tag_header hdr;
 	union {
 		struct tag_revision	rev;
+		struct tag_cmdline	cmdline;
 	} u;
 };
 
board.c deleted +0 -88

88 lines not on this page · raw message

board.h deleted +0 -13
deleted file mode 100644
index b256a6c..0000000
@@ -1,13 +0,0 @@
-#ifndef _BOARD_H
-#define _BOARD_H
-
-struct board {
-	__u32		machid;
-	__u32		system_rev;
-	void		*dtb;
-	const char	*name;
-};
-
-struct board *match_board(__u32 machid, __u32 revision);
-
-#endif
led.c deleted +0 -54

54 lines not on this page · raw message

led.h deleted +0 -6
deleted file mode 100644
index 0cdcf31..0000000
@@ -1,6 +0,0 @@
-#ifndef _LED_H_
-#define _LED_H_
-
-void led_panic(void);
-
-#endif
main.c +29 -23

74 lines not on this page · raw message

string.c new file +83 -0

83 lines not on this page · raw message

string.h new file +8 -0
new file mode 100644
index 0000000..14d6764
@@ -0,0 +1,8 @@
+#ifndef _STRING_H_
+
+#include "types.h"
+
+int strncmp(const char *, const char *, int);
+void *gethexaddr(const char *, const char **);
+int getaddrs(void **, void **, const char *);
+#endif
Signature · 1 line
1.8.3.2
#13 lore raw

cover impedance-matcher generic improvements

In reply to Jason Cooper

Hi Jason,

Quoted 5 lines · Jason Cooper

Basic idea is to replace a device's stock kernel with this impedance-matcher. Load the kernel and/or the devicetree blob to desired addresses. Add 'loadaddrs=0xXXXXXXXX,0xYYYYYYYY' to the kernel's command line. Or, if you are appending, 'loadaddrs=appended,0xYYYYYYYY'. First address is the location of the kernel, second is the location of the dtb.

Nice to see that idea implemented! For me though, changing any of the U-Boot variables is out of the question, and I need the matcher just the way I implemented it, including the LED blink pattern to let the user know if things go wrong.

Hence, I won't change to your generic version on my boards, and so I think it might be best if you maintain your own tree for your approach.

Best regards,
Daniel

#14 lore raw

cover impedance-matcher generic improvements

Quoted 9 lines · Daniel Mack

Hi Jason,

Quoted 5 lines · Jason Cooper

Basic idea is to replace a device's stock kernel with this impedance-matcher. Load the kernel and/or the devicetree blob to desired addresses. Add 'loadaddrs=0xXXXXXXXX,0xYYYYYYYY' to the kernel's command line. Or, if you are appending, 'loadaddrs=appended,0xYYYYYYYY'. First address is the location of the kernel, second is the location of the dtb.

Quoted 4 lines

Nice to see that idea implemented! For me though, changing any of the U-Boot variables is out of the question, and I need the matcher just the way I implemented it, including the LED blink pattern to let the user know if things go wrong.

Understandable. After thinking about it a bit, I think I'm going to rework this patch to allow appending both kernels and dtbs (as you had), and abstract out the led blink so that your code would become a compile time option.

Quoted 2 lines

Hence, I won't change to your generic version on my boards, and so I think it might be best if you maintain your own tree for your approach.

hrmmm, I don't like forking on general principle. Let me do the above rework and see if that works for you, while adding the capabilities I need.

When I'm done, you should just be able to do:

  $ make APPEND_KERNEL=input/zImage APPEND_DTBS=input/*.dtb uImage

And get the same result.

In the meantime, would you mind adding a license to your code? If you have no preference, I like GPLv2-only, but it's your code, so whatever you like.

thx,

Jason.

#15 lore raw

cover impedance-matcher generic improvements

Hi Jason,

Quoted 13 lines · Jason Cooper
Quoted 11 lines · Daniel Mack
Quoted 5 lines · Jason Cooper

Basic idea is to replace a device's stock kernel with this impedance-matcher. Load the kernel and/or the devicetree blob to desired addresses. Add 'loadaddrs=0xXXXXXXXX,0xYYYYYYYY' to the kernel's command line. Or, if you are appending, 'loadaddrs=appended,0xYYYYYYYY'. First address is the location of the kernel, second is the location of the dtb.

Nice to see that idea implemented! For me though, changing any of the U-Boot variables is out of the question, and I need the matcher just the way I implemented it, including the LED blink pattern to let the user know if things go wrong.

Quoted 4 lines

Understandable. After thinking about it a bit, I think I'm going to rework this patch to allow appending both kernels and dtbs (as you had), and abstract out the led blink so that your code would become a compile time option.

And how would you match machids and system_rev values to the dtb files? This is how I identify my boards at least. But as Stephen Warren said in the thread that started this discussion, there might be totally different ways of detection. For instance, other boards could read GPIO lines, or even have a pseudo driver that initializes the I2C controller in order to talk to an EEPROM or such. Reading from an ADC is another option.

And the more I think about it, I believe Nicolas was right in saying that such a thing does not need to be very generic (as much as I like generic solutions in principle).

If at all, I think we should start thinking of that code base as something like a framework, consisting of a merely empty main() function body, a lds linker script and some objcopy magic in the Makefile. And then have a menuconfig which allows to select one out of many hardware types, which then uses its specific way of board detection, LED signaling and so on. The two lines of vectoring to the actual kernel can be generic then. But again, I really don't know if it's worth the hassle.

Quoted 7 lines

hrmmm, I don't like forking on general principle. Let me do the above rework and see if that works for you, while adding the capabilities I need.

When I'm done, you should just be able to do:

  $ make APPEND_KERNEL=input/zImage APPEND_DTBS=input/*.dtb uImage

Out of curiosity, I'd like to see how you dynamically create the symbol definitions for the binary blobs :)

Quoted 3 lines

In the meantime, would you mind adding a license to your code? If you have no preference, I like GPLv2-only, but it's your code, so whatever you like.

Done, GPLv2 it is.

Thanks,
Daniel

#16 lore raw

cover impedance-matcher generic improvements

Quoted 16 lines · Daniel Mack

Hi Jason,

Quoted 13 lines · Jason Cooper
Quoted 11 lines · Daniel Mack
Quoted 5 lines · Jason Cooper

Basic idea is to replace a device's stock kernel with this impedance-matcher. Load the kernel and/or the devicetree blob to desired addresses. Add 'loadaddrs=0xXXXXXXXX,0xYYYYYYYY' to the kernel's command line. Or, if you are appending, 'loadaddrs=appended,0xYYYYYYYY'. First address is the location of the kernel, second is the location of the dtb.

Nice to see that idea implemented! For me though, changing any of the U-Boot variables is out of the question, and I need the matcher just the way I implemented it, including the LED blink pattern to let the user know if things go wrong.

Quoted 6 lines
Quoted 4 lines

Understandable. After thinking about it a bit, I think I'm going to rework this patch to allow appending both kernels and dtbs (as you had), and abstract out the led blink so that your code would become a compile time option.

And how would you match machids and system_rev values to the dtb files?

I'm thinking board-specific match functions. For your use case, you would match machid/system_rev to a compatible string. Then, generic code would scan the appended dtbs for a matching string.

Quoted 6 lines

This is how I identify my boards at least. But as Stephen Warren said in the thread that started this discussion, there might be totally different ways of detection. For instance, other boards could read GPIO lines, or even have a pseudo driver that initializes the I2C controller in order to talk to an EEPROM or such. Reading from an ADC is another option.

As long as it resolves to a compatible string.

Quoted 16 lines

And the more I think about it, I believe Nicolas was right in saying that such a thing does not need to be very generic (as much as I like generic solutions in principle).

If at all, I think we should start thinking of that code base as something like a framework, consisting of a merely empty main() function body, a lds linker script and some objcopy magic in the Makefile. And then have a menuconfig which allows to select one out of many hardware types, which then uses its specific way of board detection, LED signaling and so on. The two lines of vectoring to the actual kernel can be generic then. But again, I really don't know if it's worth the hassle.

Quoted 4 lines

hrmmm, I don't like forking on general principle. Let me do the above rework and see if that works for you, while adding the capabilities I need.

Quoted 6 lines
Quoted 3 lines

When I'm done, you should just be able to do:

  $ make APPEND_KERNEL=input/zImage APPEND_DTBS=input/*.dtb uImage

Out of curiosity, I'd like to see how you dynamically create the symbol definitions for the binary blobs :)

Me too. ;-)

Quoted 5 lines
Quoted 3 lines

In the meantime, would you mind adding a license to your code? If you have no preference, I like GPLv2-only, but it's your code, so whatever you like.

Done, GPLv2 it is.

Thanks!

thx,

Jason.

#17 lore raw

v2 cover impedance-matcher generic improvements

In reply to Daniel Mack

Daniel,

Here's a new version of my attempt to make this code generically useful. I've tested this on my dreamplug both using the commandline 'loadaddrs=appended,0x0700000' and appending all kirkwood*.dtb's.

It's still hacky and can't update the dtb yet. But it definitely works.

To make it work for the Raumfeld boards, you'll need to change board-raumfeld.c to use the proper compatible strings for the boards. Then, in the Makefile, change your uart address and MFG.

For folks interested in testing:

git://git.infradead.org/users/jcooper/impedance-matcher.git generic

btw - this is the first time I've needed to tinker with linker scripts, so if it looks wrong, please let me know!

thx,

Jason.

Jason Cooper (9):
add cscope Makefile target
separate common functions from board specific rename board.c to board-raumfeld.c s/.name/.compatible/
directly include needed headers
serial: split out 8250 code, configurable reg addr add generic board code
make appending images/dtbs optional appended dtbs works!

 .gitignore        |   2 +-
 Makefile          |  59 +++++++++++++--------
 append_dtbs.sh    |   8 +++
 atags.h           |  10 ++++
 board-dreamplug.c |  28 ++++++++++
 board-generic.c   |  39 ++++++++++++++
 board-raumfeld.c  | 150 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 board.c           |  88 --------------------------------
 board.h           |  10 ++--
 dtbs.c            |  36 +++++++++++++
 dtbs.h            |   6 +++
 endian.h          |  12 +++++
 fdt.h             |  64 +++++++++++++++++++++++
 led.c             |  54 --------------------
 led.h             |   6 ---
 main.c            |  47 ++++++++---------
 matcher.lds       |   8 ++-
 print.c           |   8 +--
 print.h           |   2 +
 register.c        |  11 ++++
 register.h        |   9 ++++
 serial-8250.c     |  21 ++++++++
 serial.h          |  10 ++++
 string.c          |  99 +++++++++++++++++++++++++++++++++++
 string.h          |   9 ++++
 types.h           |   1 +
 26 files changed, 590 insertions(+), 207 deletions(-)
 create mode 100755 append_dtbs.sh
 create mode 100644 board-dreamplug.c
 create mode 100644 board-generic.c
 create mode 100644 board-raumfeld.c
 delete mode 100644 board.c
 create mode 100644 dtbs.c
 create mode 100644 dtbs.h
 create mode 100644 endian.h
 create mode 100644 fdt.h
 delete mode 100644 led.c
 delete mode 100644 led.h
 create mode 100644 register.c
 create mode 100644 register.h
 create mode 100644 serial-8250.c
 create mode 100644 serial.h
 create mode 100644 string.c
 create mode 100644 string.h
Signature · 1 line
1.8.3.2
#18 lore raw

RFC PATCH v2 1/9 add cscope Makefile target

---
 .gitignore | 1 +
 Makefile   | 6 ++++++
 2 files changed, 7 insertions(+)
.gitignore +1 -0
index c3b59bf..ac4198c 100644
@@ -1,6 +1,7 @@
 *.sh
 *.o
 *.bin
+cscope.*
 matcher
 uImage
 input/zImage
Makefile +6 -0
index 5ad5fc0..da2982a 100644
@@ -43,3 +43,9 @@ uImage: matcher.bin
 clean:
 	rm -fr matcher.bin matcher *.o uImage
 
+distclean: clean
+	rm -fr cscope.*
+
+cscope:
+	-find . -name "*.[chS]" >cscope.files
+	-cscope -b -R
Signature · 1 line
1.8.3.2
#19 lore raw

RFC PATCH v2 2/9 separate common functions from board specific

In reply to Jason Cooper
---
 Makefile   |  7 +++++-
 board.c    | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 board.h    |  2 +-
 led.c      | 54 -------------------------------------------
 led.h      |  6 -----
 main.c     | 27 ++++------------------
 register.c | 11 +++++++++
 register.h |  9 ++++++++
 8 files changed, 103 insertions(+), 90 deletions(-)
 delete mode 100644 led.c
 delete mode 100644 led.h
 create mode 100644 register.c
 create mode 100644 register.h
Makefile +6 -1
index da2982a..814326d 100644
@@ -6,6 +6,11 @@ LD=$(CROSS_COMPILE)ld
 LOADADDR=0xa0008000
 BINFMT=elf32-littlearm
 
+COMMON_OBJS = \
+	main.o \
+	print.o \
+	register.o
+
 INPUT_OBJS = \
 	zimage.o		\
 	dtb-raumfeld-controller-0.o	\
@@ -29,7 +34,7 @@ zimage.o: input/zImage
 %.o: %.c
 	$(GCC) $(CFLAGS) -c $^
 
-matcher: main.o print.o board.o led.o $(INPUT_OBJS)
+matcher: $(COMMON_OBJS) board.o $(INPUT_OBJS)
 	$(LD) $(LDFLAGS) -T matcher.lds -o $@ $^
 
 matcher.bin: matcher
board.c +71 -6

90 lines not on this page · raw message

board.h +1 -1
index b256a6c..ec2b79e 100644
@@ -8,6 +8,6 @@ struct board {
 	const char	*name;
 };
 
-struct board *match_board(__u32 machid, __u32 revision);
+struct board *match_board(__u32 machid, const struct tag *);
 
 #endif
led.c deleted +0 -54

54 lines not on this page · raw message

led.h deleted +0 -6
deleted file mode 100644
index 0cdcf31..0000000
@@ -1,6 +0,0 @@
-#ifndef _LED_H_
-#define _LED_H_
-
-void led_panic(void);
-
-#endif
main.c +5 -22
index 3dd6636..65ec9a7 100644
@@ -2,39 +2,22 @@
 #include "atags.h"
 #include "print.h"
 #include "board.h"
-#include "led.h"
 
 extern __u32 _binary_input_zImage_start;
 
 void main(__u32 dummy, __u32 machid, const struct tag *tags)
 {
-	const struct tag *t;
 	struct board *board;
-	__u32 system_rev = 0;
 	void (*start_kernel)(__u32 dummy, __u32 machid, void *dtb) =
 		(void *) &_binary_input_zImage_start;
 
 	putstr("++ Impedance Matcher (3rd stage loader) ++\n");
 
-	/* walk the atags to determine the system revision */
-	for_each_tag(t, tags)
-		switch (t->hdr.tag) {
-			case ATAG_REVISION:
-				system_rev = t->u.rev.rev;
-				break;
-		}
-
-	board = match_board(machid, system_rev & 0xff);
-	if (!board) {
-		putstr("ERROR MATCHING BOARD!\n");
-		putstr("MACHID: 0x");
-		printhex(machid);
-		putstr("\n");
-		putstr("SYSTEM_REV: 0x");
-		printhex(system_rev);
-		putstr("\n");
-		led_panic();
-	}
+	/*
+	 * error resp. is board-specific, so won't return on error
+	 * eg - raumfeld boards blink a led indefinitely
+	 */
+	board = match_board(machid, tags);
 
 	putstr("Detected board: ");
 	putstr(board->name);
register.c new file +11 -0
new file mode 100644
index 0000000..5090f63
@@ -0,0 +1,11 @@
+#include "types.h"
+
+inline void writel(__u32 val, __u32 addr)
+{
+	*(volatile __u32 *) addr = val;
+}
+
+inline __u32 readl(__u32 addr)
+{
+	return *(volatile __u32 *) addr;
+}
register.h new file +9 -0
new file mode 100644
index 0000000..2e5c10f
@@ -0,0 +1,9 @@
+#ifndef _REGISTER_H
+#define _REGISTER_H
+
+#include "types.h"
+
+void writel(__u32, __u32);
+__u32 readl(__u32);
+
+#endif
Signature · 1 line
1.8.3.2
#20 lore raw

RFC PATCH v2 3/9 rename board.c to board-raumfeld.c

In reply to Jason Cooper
---
 Makefile         |   6 ++-
 board-raumfeld.c | 153 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 board.c          | 153 -------------------------------------------------------
 3 files changed, 158 insertions(+), 154 deletions(-)
 create mode 100644 board-raumfeld.c
 delete mode 100644 board.c
Makefile +5 -1
index 814326d..bb3a154 100644
@@ -6,6 +6,10 @@ LD=$(CROSS_COMPILE)ld
 LOADADDR=0xa0008000
 BINFMT=elf32-littlearm
 
+MFG=raumfeld
+
+BOARD_OBJ = board-$(MFG).o
+
 COMMON_OBJS = \
 	main.o \
 	print.o \
@@ -34,7 +38,7 @@ zimage.o: input/zImage
 %.o: %.c
 	$(GCC) $(CFLAGS) -c $^
 
-matcher: $(COMMON_OBJS) board.o $(INPUT_OBJS)
+matcher: $(COMMON_OBJS) $(BOARD_OBJ) $(INPUT_OBJS)
 	$(LD) $(LDFLAGS) -T matcher.lds -o $@ $^
 
 matcher.bin: matcher
board-raumfeld.c new file +153 -0

153 lines not on this page · raw message

board.c deleted +0 -153

153 lines not on this page · raw message

Signature · 1 line
1.8.3.2
#21 lore raw

RFC PATCH v2 4/9 s/.name/.compatible/

In reply to Jason Cooper
---
 board-raumfeld.c | 18 +++++++++---------
 board.h          |  2 +-
 main.c           |  2 +-
 3 files changed, 11 insertions(+), 11 deletions(-)
board-raumfeld.c +9 -9
index fe51bcb..e5d4702 100644
@@ -21,19 +21,19 @@ static struct board boards[] = {
 		.machid		= 2413,
 		.system_rev	= 0,
 		.dtb		= &_binary_input_raumfeld_controller_0_dtb_start,
-		.name		= "Raumfeld Controller, revision 0",
+		.compatible	= "Raumfeld Controller, revision 0",
 	},
 	{
 		.machid		= 2413,
 		.system_rev	= 1,
 		.dtb		= &_binary_input_raumfeld_controller_1_dtb_start,
-		.name		= "Raumfeld Controller, revision 1",
+		.compatible	= "Raumfeld Controller, revision 1",
 	},
 	{
 		.machid		= 2413,
 		.system_rev	= 2,
 		.dtb		= &_binary_input_raumfeld_controller_2_dtb_start,
-		.name		= "Raumfeld Controller, revision 2",
+		.compatible	= "Raumfeld Controller, revision 2",
 	},
 
 	/* Controller */
@@ -41,19 +41,19 @@ static struct board boards[] = {
 		.machid		= 2414,
 		.system_rev	= 0,
 		.dtb		= &_binary_input_raumfeld_connector_0_dtb_start,
-		.name		= "Raumfeld Connector, revision 0",
+		.compatible	= "Raumfeld Connector, revision 0",
 	},
 	{
 		.machid		= 2414,
 		.system_rev	= 1,
 		.dtb		= &_binary_input_raumfeld_connector_1_dtb_start,
-		.name		= "Raumfeld Connector, revision 1",
+		.compatible	= "Raumfeld Connector, revision 1",
 	},
 	{
 		.machid		= 2414,
 		.system_rev	= 2,
 		.dtb		= &_binary_input_raumfeld_connector_2_dtb_start,
-		.name		= "Raumfeld Connector, revision 2",
+		.compatible	= "Raumfeld Connector, revision 2",
 	},
 
 	/* Speaker */
@@ -61,19 +61,19 @@ static struct board boards[] = {
 		.machid		= 2415,
 		.system_rev	= 0,
 		.dtb		= &_binary_input_raumfeld_speaker_0_dtb_start,
-		.name		= "Raumfeld Speaker, revision 0",
+		.compatible	= "Raumfeld Speaker, revision 0",
 	},
 	{
 		.machid		= 2415,
 		.system_rev	= 1,
 		.dtb		= &_binary_input_raumfeld_speaker_1_dtb_start,
-		.name		= "Raumfeld Speaker, revision 1",
+		.compatible	= "Raumfeld Speaker, revision 1",
 	},
 	{
 		.machid		= 2415,
 		.system_rev	= 2,
 		.dtb		= &_binary_input_raumfeld_speaker_2_dtb_start,
-		.name		= "Raumfeld Speaker, revision 2",
+		.compatible	= "Raumfeld Speaker, revision 2",
 	},
 	{ 0, 0, NULL, NULL }	/* sentinel */
 };
board.h +1 -1
index ec2b79e..5146db0 100644
@@ -5,7 +5,7 @@ struct board {
 	__u32		machid;
 	__u32		system_rev;
 	void		*dtb;
-	const char	*name;
+	const char	*compatible;
 };
 
 struct board *match_board(__u32 machid, const struct tag *);
main.c +1 -1
index 65ec9a7..8673703 100644
@@ -20,7 +20,7 @@ void main(__u32 dummy, __u32 machid, const struct tag *tags)
 	board = match_board(machid, tags);
 
 	putstr("Detected board: ");
-	putstr(board->name);
+	putstr(board->compatible);
 	putstr("\n");
 
 	putstr("Booting into Linux kernel ...\n");
Signature · 1 line
1.8.3.2
#22 lore raw

RFC PATCH v2 4/9 s/.name/.compatible/

board-raumfeld.c static struct board boards[] = { · line 24

Quoted 10 lines · Jason Cooper
board-raumfeld.c +1 -1
@@ -21,19 +21,19 @@ static struct board boards[] = {
 		.machid		= 2413,
 		.system_rev	= 0,
 		.dtb		= &_binary_input_raumfeld_controller_0_dtb_start,
-		.name		= "Raumfeld Controller, revision 0",
+		.compatible	= "Raumfeld Controller, revision 0",

This looks a little unfortunate; those values don't look like they're the contents of the DT compatible property.

#23 lore raw

RFC PATCH v2 4/9 s/.name/.compatible/

Quoted 5 lines · Stephen Warren
Quoted 3 lines · Jason Cooper
board-raumfeld.c +0 -0
Quoted 9 lines

board-raumfeld.c static struct board boards[] = { · line 24

Quoted 6 lines
board-raumfeld.c +1 -1
@@ -21,19 +21,19 @@ static struct board boards[] = {
 		.machid		= 2413,
 		.system_rev	= 0,
 		.dtb		= &_binary_input_raumfeld_controller_0_dtb_start,
-		.name		= "Raumfeld Controller, revision 0",
+		.compatible	= "Raumfeld Controller, revision 0",

This looks a little unfortunate; those values don't look like they're the contents of the DT compatible property.

Yes, this project is a week old. I figured a little volatility was allowed :-) Please see:

cb0088e board-raumfeld: tweak compatible strings

in:

https://github.com/zonque/pxa-impedance-matcher.git

I changed the api so that the user could link in a random number of dtbs _without_ hardcoding the addresses. Searching by the compatible string was the easiest way to accomplish this. Unfortunately, I didn't know his compatible strings when I made the change.

For the curious, the code that does this is here:

https://github.com/zonque/pxa-impedance-matcher/blob/master/dtbs.c

We plan to add dtb parsing in the future so that we can change the dtb based on the atags passed by the legacy bootloader.

thx,

Jason.

#24 lore raw

RFC PATCH v2 4/9 s/.name/.compatible/

Quoted 11 lines · Jason Cooper

I changed the api so that the user could link in a random number of dtbs _without_ hardcoding the addresses. Searching by the compatible string was the easiest way to accomplish this. Unfortunately, I didn't know his compatible strings when I made the change.

For the curious, the code that does this is here:

https://github.com/zonque/pxa-impedance-matcher/blob/master/dtbs.c

We plan to add dtb parsing in the future so that we can change the dtb based on the atags passed by the legacy bootloader.

... and then we can also specifically look into the compatible node of the dtb, and not just do a string search over the entire binary.

But for now, it's good enough.

Daniel

#25 lore raw

RFC PATCH v2 5/9 directly include needed headers

In reply to Jason Cooper
---
 atags.h | 2 ++
 board.h | 3 +++
 print.h | 2 ++
 3 files changed, 7 insertions(+)
atags.h +2 -0
index 30e6ee7..83f93a1 100644
@@ -1,6 +1,8 @@
 #ifndef _ATAG_H
 #define _ATAG_H
 
+#include "types.h"
+
 #define ATAG_NONE       0x00000000
 
 struct tag_header {
board.h +3 -0
index 5146db0..af64e94 100644
@@ -1,6 +1,9 @@
 #ifndef _BOARD_H
 #define _BOARD_H
 
+#include "types.h"
+#include "atags.h"
+
 struct board {
 	__u32		machid;
 	__u32		system_rev;
print.h +2 -0
index 402def6..5320727 100644
@@ -1,6 +1,8 @@
 #ifndef _PRINT_H
 #define _PRINT_H
 
+#include "types.h"
+
 void putch(char c);
 void printhex(__u32 u);
 void putstr(const char *s);
Signature · 1 line
1.8.3.2
#26 lore raw

RFC PATCH v2 6/9 serial: split out 8250 code, configurable reg addr

In reply to Jason Cooper
---
 Makefile      |  9 +++++++--
 matcher.lds   |  2 +-
 print.c       |  8 +-------
 serial-8250.c | 21 +++++++++++++++++++++
 serial.h      | 10 ++++++++++
 5 files changed, 40 insertions(+), 10 deletions(-)
 create mode 100644 serial-8250.c
 create mode 100644 serial.h
Makefile +7 -2
index bb3a154..c799012 100644
@@ -3,12 +3,17 @@ LDFLAGS=-static -nostdlib
 GCC=$(CROSS_COMPILE)gcc
 OBJCOPY=$(CROSS_COMPILE)objcopy
 LD=$(CROSS_COMPILE)ld
-LOADADDR=0xa0008000
+LOADADDR=0x10008000
 BINFMT=elf32-littlearm
 
 MFG=raumfeld
+UART=8250
+UART_BASE=0xf1012000
+
+CFLAGS+=-DUART_BASE=$(UART_BASE)
 
 BOARD_OBJ = board-$(MFG).o
+UART_OBJ = serial-$(UART).o
 
 COMMON_OBJS = \
 	main.o \
@@ -38,7 +43,7 @@ zimage.o: input/zImage
 %.o: %.c
 	$(GCC) $(CFLAGS) -c $^
 
-matcher: $(COMMON_OBJS) $(BOARD_OBJ) $(INPUT_OBJS)
+matcher: $(COMMON_OBJS) $(BOARD_OBJ) $(UART_OBJ) $(INPUT_OBJS)
 	$(LD) $(LDFLAGS) -T matcher.lds -o $@ $^
 
 matcher.bin: matcher
matcher.lds +1 -1
index f73ed1d..96eb16a 100644
@@ -1,5 +1,5 @@
 SECTIONS {
-	. = 0xa0008000;
+	. = 0x10008000;
 	.text : { * (.text); }
 	.data : { * (.data); }
 	.rodata : { * (.rodata); }
print.c +1 -7
index c799380..9dbc7b6 100644
@@ -1,5 +1,6 @@
 #include "types.h"
 #include "print.h"
+#include "serial.h"
 
 static inline void nop(int n)
 {
@@ -7,12 +8,6 @@ static inline void nop(int n)
 		asm("nop");
 }
 
-static void __putch(char c)
-{
-	*(volatile __u32 *) 0x40100000 = c;
-	nop(100);
-}
-
 void putch(char c)
 {
 	__putch(c);
@@ -39,4 +34,3 @@ void putstr(const char *s)
 	while (*s)
 		putch(*s++);
 }
-
serial-8250.c new file +21 -0
new file mode 100644
index 0000000..0d5d35e
@@ -0,0 +1,21 @@
+#include "types.h"
+#include "register.h"
+#include "serial.h"
+
+/*
+ * Whole heartedly copied from barebox's mach-mvebu debug code.  Thanks to
+ * Thomas Petazzoni for the original code.
+ */
+void __putch(char c)
+{
+	/* Wait until there is space in the FIFO */
+	while (!(readl(UART_BASE + UART_LSR) & LSR_THRE))
+		;
+
+	/* Send the character */
+	writel(c, UART_BASE + UART_THR);
+
+	/* Wait to make sure it hits the line */
+	while (!(readl(UART_BASE + UART_LSR) & LSR_THRE))
+		;
+}
serial.h new file +10 -0
new file mode 100644
index 0000000..c5e4581
@@ -0,0 +1,10 @@
+#ifndef _SERIAL_H
+#define _SERIAL_H
+
+#define BIT(nr)         (1UL << (nr))
+#define UART_THR	0x00
+#define UART_LSR	0x14
+#define   LSR_THRE	BIT(5)
+
+void __putch(char);
+#endif
Signature · 1 line
1.8.3.2
#27 lore raw

RFC PATCH v2 7/9 add generic board code

In reply to Jason Cooper
---
 Makefile        |  3 +-
 atags.h         |  8 ++++++
 board-generic.c | 39 +++++++++++++++++++++++++
 board.h         |  1 +
 main.c          |  5 +++-
 string.c        | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 string.h        |  8 ++++++
 7 files changed, 151 insertions(+), 2 deletions(-)
 create mode 100644 board-generic.c
 create mode 100644 string.c
 create mode 100644 string.h
Makefile +2 -1
index c799012..65e9f3b 100644
@@ -18,7 +18,8 @@ UART_OBJ = serial-$(UART).o
 COMMON_OBJS = \
 	main.o \
 	print.o \
-	register.o
+	register.o \
+	string.o
 
 INPUT_OBJS = \
 	zimage.o		\
atags.h +8 -0
index 83f93a1..31ed999 100644
@@ -17,10 +17,18 @@ struct tag_revision {
 	__u32 rev;
 };
 
+/* command line */
+#define ATAG_CMDLINE	0x54410009
+
+struct tag_cmdline {
+	char cmdline[1];	/* this is the minimum size */
+};
+
 struct tag {
 	struct tag_header hdr;
 	union {
 		struct tag_revision	rev;
+		struct tag_cmdline	cmdline;
 	} u;
 };
 
board-generic.c new file +39 -0
new file mode 100644
index 0000000..4fa25ca
@@ -0,0 +1,39 @@
+#include "atags.h"
+#include "board.h"
+#include "print.h"
+#include "types.h"
+#include "string.h"
+
+struct board genboard;
+
+struct board *match_board(__u32 machid, const struct tag *tags)
+{
+	const struct tag *t;
+
+	/* walk the atags to get the command line */
+	for_each_tag(t, tags)
+		switch (t->hdr.tag) {
+			case ATAG_CMDLINE:
+				getaddrs(&genboard.kernel, &genboard.dtb,
+					t->u.cmdline.cmdline);
+				break;
+		}
+
+	if (genboard.kernel) {
+		putstr("Kernel: 0x");
+		printhex((__u32)genboard.kernel);
+	} else
+		putstr("Kernel: Appended");
+	putstr("\n");
+
+	if (genboard.dtb) {
+		putstr("DTB:    0x");
+		printhex((__u32)genboard.dtb);
+	} else
+		putstr("** DTB Not Found! **");
+	putstr("\n");
+
+	genboard.compatible = NULL;
+
+	return &genboard;
+}
board.h +1 -0
index af64e94..a28fb06 100644
@@ -8,6 +8,7 @@ struct board {
 	__u32		machid;
 	__u32		system_rev;
 	void		*dtb;
+	void		*kernel;
 	const char	*compatible;
 };
 
main.c +4 -1
index 8673703..ed25842 100644
@@ -20,7 +20,10 @@ void main(__u32 dummy, __u32 machid, const struct tag *tags)
 	board = match_board(machid, tags);
 
 	putstr("Detected board: ");
-	putstr(board->compatible);
+	if (board->compatible)
+		putstr(board->compatible);
+	else
+		putstr("Not given.");
 	putstr("\n");
 
 	putstr("Booting into Linux kernel ...\n");
string.c new file +89 -0

89 lines not on this page · raw message

string.h new file +8 -0
new file mode 100644
index 0000000..59f5f0c
@@ -0,0 +1,8 @@
+#ifndef _STRING_H
+#define _STRING_H
+
+int strncmp(const char *, const char *, int);
+void *gethexaddr(const char *, const char **);
+int getaddrs(void **, void **, const char *);
+
+#endif
Signature · 1 line
1.8.3.2
#28 lore raw

RFC PATCH v2 8/9 make appending images/dtbs optional

In reply to Jason Cooper
---
 .gitignore     |  1 -
 Makefile       | 35 ++++++++++++++++-------------------
 append_dtbs.sh |  8 ++++++++
 main.c         | 15 +++++++++++++--
 matcher.lds    |  8 ++++++--
 5 files changed, 43 insertions(+), 24 deletions(-)
 create mode 100755 append_dtbs.sh
.gitignore +0 -1
index ac4198c..e0ebf62 100644
@@ -1,4 +1,3 @@
-*.sh
 *.o
 *.bin
 cscope.*
Makefile +16 -19
index 65e9f3b..c9b2381 100644
@@ -1,4 +1,13 @@
-CFLAGS=-Wall -ffreestanding
+ifneq ($(origin APPEND_KERNEL), undefined)
+INPUT_OBJS=zimage.o
+CFLAGS+=-DAPPEND_KERNEL="$(APPEND_KERNEL)"
+endif
+
+ifneq ($(origin APPEND_DTBS), undefined)
+CFLAGS+=-DAPPEND_DTBS="$(APPEND_DTBS)"
+endif
+
+CFLAGS+=-Wall -ffreestanding
 LDFLAGS=-static -nostdlib
 GCC=$(CROSS_COMPILE)gcc
 OBJCOPY=$(CROSS_COMPILE)objcopy
@@ -21,34 +30,22 @@ COMMON_OBJS = \
 	register.o \
 	string.o
 
-INPUT_OBJS = \
-	zimage.o		\
-	dtb-raumfeld-controller-0.o	\
-	dtb-raumfeld-controller-1.o	\
-	dtb-raumfeld-controller-2.o	\
-	dtb-raumfeld-connector-0.o	\
-	dtb-raumfeld-connector-1.o	\
-	dtb-raumfeld-connector-2.o	\
-	dtb-raumfeld-speaker-0.o	\
-	dtb-raumfeld-speaker-1.o	\
-	dtb-raumfeld-speaker-2.o
-
 all: uImage
 
-dtb-%.o: input/%.dtb
-	$(OBJCOPY) -I binary -O $(BINFMT) -B arm $^ $@
-
-zimage.o: input/zImage
+zimage.o: $(APPEND_KERNEL)
 	$(OBJCOPY) -I binary -O $(BINFMT) -B arm $^ $@
 
 %.o: %.c
 	$(GCC) $(CFLAGS) -c $^
 
 matcher: $(COMMON_OBJS) $(BOARD_OBJ) $(UART_OBJ) $(INPUT_OBJS)
-	$(LD) $(LDFLAGS) -T matcher.lds -o $@ $^
+	$(LD) $(LDFLAGS) -T matcher.lds -Ttext $(LOADADDR) -o $@ $^
 
 matcher.bin: matcher
-	$(OBJCOPY) -O binary $^ $@
+	$(OBJCOPY) -O binary --set-section-flags .bss=alloc,load,contents $^ $@
+ifneq ($(origin APPEND_DTBS), undefined)
+	./append_dtbs.sh $@ $(APPEND_DTBS)
+endif
 
 uImage: matcher.bin
 	mkimage -A arm -O linux -C none -T kernel \
append_dtbs.sh new file +8 -0
new file mode 100755
index 0000000..82bb463
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+OUT="$1"
+shift
+DTBS="$*"
+
+cat $DTBS >>$OUT
+dd if=/dev/zero of=$OUT oflag=append conv=notrunc bs=1 count=8 #sentinel
main.c +13 -2
index ed25842..c64a083 100644
@@ -3,13 +3,21 @@
 #include "print.h"
 #include "board.h"
 
+#ifdef APPEND_KERNEL
 extern __u32 _binary_input_zImage_start;
+#endif
+
+void main(__u32 dummy, __u32 machid, const struct tag *tags)
+	__attribute__((section(".text_main")));
 
 void main(__u32 dummy, __u32 machid, const struct tag *tags)
 {
 	struct board *board;
-	void (*start_kernel)(__u32 dummy, __u32 machid, void *dtb) =
-		(void *) &_binary_input_zImage_start;
+	void (*start_kernel)(__u32 dummy, __u32 machid, void *dtb);
+
+#ifdef APPEND_KERNEL
+	start_kernel = (void *) &_binary_input_zImage_start;
+#endif
 
 	putstr("++ Impedance Matcher (3rd stage loader) ++\n");
 
@@ -26,6 +34,9 @@ void main(__u32 dummy, __u32 machid, const struct tag *tags)
 		putstr("Not given.");
 	putstr("\n");
 
+	if (board->kernel)
+		start_kernel = board->kernel;
+
 	putstr("Booting into Linux kernel ...\n");
 	start_kernel(0, 0xffffffff, board->dtb);
 }
matcher.lds +6 -2
index 96eb16a..7b85010 100644
@@ -1,6 +1,10 @@
 SECTIONS {
-	. = 0x10008000;
-	.text : { * (.text); }
+	.text : { * (.text_main); * (.text); }
 	.data : { * (.data); }
 	.rodata : { * (.rodata); }
+	.bss :
+	{
+		* (.bss);
+	}
+	PROVIDE (__end_of_image = .) ;
 }
Signature · 1 line
1.8.3.2
#29 lore raw

RFC PATCH v2 9/9 appended dtbs works!

In reply to Jason Cooper

With this commit, the user can build a single binary with the zImage linked in and the dtbs appended.

The user needs to provide a board-*.c file, address of the uart, then:

make MFG=boardname APPEND_KERNEL=/tmp/zImage APPEND_DTBS=/tmp/*.dtb \
uImage

Look at board-raumfeld.c for an example of how to determine the board you are on and set the desired compatible string.

---
 Makefile          |  1 +
 board-dreamplug.c | 28 ++++++++++++++++++++++++
 board-raumfeld.c  | 49 ++++++++++++++++++++----------------------
 board.h           |  2 --
 dtbs.c            | 36 +++++++++++++++++++++++++++++++
 dtbs.h            |  6 ++++++
 endian.h          | 12 +++++++++++
 fdt.h             | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 string.c          | 10 +++++++++
 string.h          |  1 +
 types.h           |  1 +
 11 files changed, 182 insertions(+), 28 deletions(-)
 create mode 100644 board-dreamplug.c
 create mode 100644 dtbs.c
 create mode 100644 dtbs.h
 create mode 100644 endian.h
 create mode 100644 fdt.h
Makefile +1 -0
index c9b2381..7829a01 100644
@@ -25,6 +25,7 @@ BOARD_OBJ = board-$(MFG).o
 UART_OBJ = serial-$(UART).o
 
 COMMON_OBJS = \
+	dtbs.o \
 	main.o \
 	print.o \
 	register.o \
board-dreamplug.c new file +28 -0
new file mode 100644
index 0000000..123c0f4
@@ -0,0 +1,28 @@
+#include "board.h"
+#include "dtbs.h"
+#include "print.h"
+#include "register.h"
+#include "types.h"
+
+/*
+ * this code is just a quick PoC for appending multiple dtbs.  I don't have
+ * any boards handy with stock, non-DT bootloaders, so I have no machids to
+ * trigger off of.
+ */
+
+extern __u32 _binary_input_zImage_start;
+extern __u32 __end_of_image;
+
+struct board board;
+const char *compat = "globalscale,dreamplug";
+
+struct board *match_board(__u32 machid, const struct tag *tags)
+{
+
+	/* testing zImage linked in and dtbs appended */
+	board.kernel = &_binary_input_zImage_start;
+	board.compatible = compat;
+	board.dtb = find_dtb(&__end_of_image, compat);
+
+	return &board;
+}
board-raumfeld.c +23 -26

125 lines not on this page · raw message

board.h +0 -2
index a28fb06..75931a1 100644
@@ -5,8 +5,6 @@
 #include "atags.h"
 
 struct board {
-	__u32		machid;
-	__u32		system_rev;
 	void		*dtb;
 	void		*kernel;
 	const char	*compatible;
dtbs.c new file +36 -0
new file mode 100644
index 0000000..a761ac4
@@ -0,0 +1,36 @@
+#include "endian.h"
+#include "fdt.h"
+#include "print.h"
+#include "string.h"
+#include "types.h"
+
+/* Yes, this is a dirty hack.  But it's simple, and fast. */
+
+int find_str(char *mem, __u32 memsz, const char *str)
+{
+	__u32 len = strlen(str);
+	const char *last = mem + memsz - len;
+	const char *p;
+
+	for (p = mem; p < last; p++) {
+		if (*p == *str)
+			if (strncmp(p, str, len) == 0)
+				return 1;
+	}
+
+	return 0;
+}
+
+void *find_dtb(void *dtbs, const char *compat)
+{
+	struct fdt_header *d = (struct fdt_header *)dtbs;
+
+	while (d->magic == be_to_cpu(FDT_MAGIC)) {
+		if (find_str((char *)d, be_to_cpu(d->totalsize), compat) == 1)
+			break;
+
+		d = (struct fdt_header *)((char *)d + be_to_cpu(d->totalsize));
+	}
+
+	return d;
+}
dtbs.h new file +6 -0
new file mode 100644
index 0000000..4e14b32
@@ -0,0 +1,6 @@
+#ifndef _DTBS_H
+#define _DTBS_H
+
+void *find_dtb(void *, const char *);
+
+#endif
endian.h new file +12 -0
new file mode 100644
index 0000000..531b6b1
@@ -0,0 +1,12 @@
+#ifndef _ENDIAN_H
+#define _ENDIAN_H
+
+#include "types.h"
+
+#define be_to_cpu(x) \
+	( ((0xFF000000UL & ((__u32)x)) >> 24) | \
+	  ((0x00FF0000UL & ((__u32)x)) >> 8)  | \
+	  ((0x0000FF00UL & ((__u32)x)) << 8)  | \
+	  ((0x000000FFUL & ((__u32)x)) << 24)    )
+
+#endif
fdt.h new file +64 -0

64 lines not on this page · raw message

string.c +10 -0
index 6584378..d13e22b 100644
@@ -7,6 +7,16 @@ int hexlut[1 + 'F' - '0'] = {
 	0xa, 0xb, 0xc, 0xd, 0xe, 0xf                      /* A - F */
 };
 
+int strlen(const char *str)
+{
+	const char *c = str;
+
+	while (*(c++))
+		;
+
+	return c - str;
+}
+
 int strncmp(const char *stra, const char *strb, int len)
 {
 	int diff=0;
string.h +1 -0
index 59f5f0c..0b99785 100644
@@ -1,6 +1,7 @@
 #ifndef _STRING_H
 #define _STRING_H
 
+int strlen(const char *);
 int strncmp(const char *, const char *, int);
 void *gethexaddr(const char *, const char **);
 int getaddrs(void **, void **, const char *);
types.h +1 -0
index 27ec08e..4c078a3 100644
@@ -2,6 +2,7 @@
 #define _TYPES_H
 
 typedef unsigned int __u32;
+typedef unsigned long long __u64;
 #define NULL	((void *) 0)
 
 #endif /* _TYPES_H */
Signature · 1 line
1.8.3.2
#30 lore raw

RFC PATCH v2 9/9 appended dtbs works!

Quoted 2 lines · Jason Cooper

With this commit, the user can build a single binary with the zImage linked in and the dtbs appended.

Do you mean that you can append a DTB to the resulting binary we call the impedance matcher, or do you mean this supports the linking of a zImage with a DTB already appended?

If the later I'd recommend against
supporting this.
If the former that's fine.

This project allows for turning off CONFIG_ARM_APPENDED_DTB and that should probably be documented somewhere to avoid confusion.

Nicolas

#31 lore raw

RFC PATCH v2 9/9 appended dtbs works!

Quoted 7 lines · Nicolas Pitre
Quoted 2 lines · Jason Cooper

With this commit, the user can build a single binary with the zImage linked in and the dtbs appended.

Do you mean that you can append a DTB to the resulting binary we call the impedance matcher,

Yes.

Quoted 2 lines

This project allows for turning off CONFIG_ARM_APPENDED_DTB and that should probably be documented somewhere to avoid confusion.

Agreed.

A lot of folks can just use the generic config without writing custom board code. So, appended or addressed zImage, and addressed single dtb. Once the impedance-matcher has some more real-world testing, should we look at deprecating CONFIG_ARM_APPENDED_DTB?

thx,

Jason.

#32 lore raw

RFC PATCH v2 9/9 appended dtbs works!

In reply to Nicolas Pitre
Quoted 2 lines · Nicolas Pitre

This project allows for turning off CONFIG_ARM_APPENDED_DTB and that should probably be documented somewhere to avoid confusion.

Updated README.

thx,

Jason.

#33 lore raw

v2 cover impedance-matcher generic improvements

In reply to Jason Cooper

Hi Jason,

Quoted 5 lines · Jason Cooper

Here's a new version of my attempt to make this code generically useful. I've tested this on my dreamplug both using the commandline 'loadaddrs=appended,0x0700000' and appending all kirkwood*.dtb's.

It's still hacky and can't update the dtb yet. But it definitely works.

Merged and pushed, thanks :)

Note the changes on top of yours though. it took me a while to figure out that my boards won't boots images that are concatinated to the finale image. I changed that back so that things are treated by objcopy, and now everything's fine.

Best regards,
Daniel

#34 lore raw

v2 cover impedance-matcher generic improvements

Daniel,

Quoted 7 lines · Daniel Mack

Hi Jason,

Quoted 4 lines · Jason Cooper

Here's a new version of my attempt to make this code generically useful. I've tested this on my dreamplug both using the commandline 'loadaddrs=appended,0x0700000' and appending all kirkwood*.dtb's.

Quoted 8 lines
Quoted 1 line

It's still hacky and can't update the dtb yet. But it definitely works.

Merged and pushed, thanks :)

Note the changes on top of yours though. it took me a while to figure out that my boards won't boots images that are concatinated to the finale image. I changed that back so that things are treated by objcopy, and now everything's fine.

Ok, that's probably cleaner anyway. I did get to learn more about linker scripts, so that was fun. :-)

I have one change to catch up to yours (replacing __end_of_image), plus I added versioning support for when you want to tag a release. Feel free to pull from:

git://git.infradead.org/users/jcooper/impedance-matcher.git dreamplug

thx,

Jason.

#35 lore raw

v2 cover impedance-matcher generic improvements

Quoted 5 lines · Jason Cooper

I have one change to catch up to yours (replacing __end_of_image), plus I added versioning support for when you want to tag a release. Feel free to pull from:

git://git.infradead.org/users/jcooper/impedance-matcher.git dreamplug

Done, thanks.

#36 lore raw
In reply to Daniel Mack

Am 04.07.2013 18:56, schrieb Daniel Mack:

Quoted 39 lines

Hi,

I'm facing a problem with a transition from legacy board-file driven ARM machines to DTB, and I'm under the impression that a solution for it could be of broader interest.

In short, devices that have been deployed in quantities come in three hardware variants, which all boot with a unique machine-id. We ship kernel images that have board support for all three machine types, and do minor fixups to platform data of some drivers at runtime, depending on the board revision number (passed in via ATAGs).

The built-in support for attaching a DTB to the zImage does not suffice here, because we have one image for all models, and also, we couldn't do a 'per-board-revision' selection that way either.

Unless I missed some recent discussion, this case is not easy to handle. Yes, I know that these kind of things should be handled by a next-generation bootloader, but in our case, we want to avoid a loader update of already shipped hardware by all means.

As a solution, I'm thinking of a small framework that could for example work as follows.

a) A small mechanism allows storing multiple DTB binary files inside the kernel binary at compile time, and a simple function can extract them again by name at runtime (something like what the firmware framework does, but I don't know if that one can be used at such an early stage in the boot process).

b) A DT_MACHINE_START-like macro takes both the machine ID and the name of a DTB file that is compiled in. When matched, generic functions would load the given file, populate the device tree and then conduct a generic DT boot for the specified platform.

c) Allow users to open-code the DTB lookup depending on whatever kind of runtime information (be it the board_revision or anything else).

Quoted 5 lines

Of course, everything has to be an opt-in that stubs itself out at zero costs if not needed.

I'm open to opinion and sugesstions :)

Depending on how different the board support for all your three machine types is, there might be an (of course unimplemented) option

d) have only one DTB file which contains all the information for your three machine types and then have a mechanism which selects ("activates") the entries valid for the board you boot based on some external information, e.g. the machine ID. I.e. you have one DTB file which contains alternative entries for the different boards. And which entry is used/activated is selected at (early) kernel runtime by the machine ID.

What I'm thinking about here is an extended version of the device tree overlays used (invented?) by the Beagle board community. They have a base device tree file and for their add on boards (capes) they load device tree overlay files based on an EEPROM ID read.

http://elinux.org/BeagleBone_and_the_3.8_Kernel#Cape_Manager_and_Device_Tree_Overlays

With this, they extend the device tree at runtime based on the attached extension boards.

Going one step further, having the alternative plugin/overlay definitions already in the initial DTB file and being able to select/activate single plugin/overlay definitions already in the early boot stage should give a general mechanism to support several, similar boards with slightly different configurations with one DTB.

Best regards

Dirk

#37 lore raw
In reply to Daniel Mack

On 07/04/2013 10:56 AM, Daniel Mack wrote:
...

Quoted 3 lines

The built-in support for attaching a DTB to the zImage does not suffice here, because we have one image for all models, and also, we couldn't do a 'per-board-revision' selection that way either.

...

Quoted 5 lines

As a solution, I'm thinking of a small framework that could for example work as follows.

a) A small mechanism allows storing multiple DTB binary files inside the kernel binary at compile time...

...

Quoted 2 lines

c) Allow users to open-code the DTB lookup depending on whatever kind of runtime information (be it the board_revision or anything else).

The problem with (c) is that in general it probably requires a lot of infra-structure to be working to implement it. On Tegra, the board revision is in an EEPROM attached to an I2C bus. You'd need to have parsed DT and started instantiating devices already before you could access the ID EEPROM to know which board revision you're running on. That's a bit of a chicked-and-egg problem. Even with a much simpler scheme such as board ID encoded into GPIOs, you'll still likely run into similar problems; pinmux and GPIO controller drivers are needed just to read the GPIOs, which then requires DT to instantiate those drivers.

So, the suggestion of Nicolas's that you mentioned does solve that rather neatly.