How do I change the SD card controller that's used by U-boot for the Raspberry Pi 3 Model B+? - u-boot

The Raspberry Pi 3 Model B+ has two SD card controllers.
There is custom controller called sdhost as shown by the device tree node:
/* SDHOST is used to drive the SD card */
&sdhost {
pinctrl-names = "default";
pinctrl-0 = <&sdhost_gpio48>;
status = "okay";
bus-width = <4>;
};
And an SDHCI-compliant controller as shown by the following device tree node:
/* SDHCI is used to control the SDIO for wireless */
&sdhci {
#address-cells = <1>;
#size-cells = <0>;
pinctrl-names = "default";
pinctrl-0 = <&emmc_gpio34>;
status = "okay";
bus-width = <4>;
non-removable;
mmc-pwrseq = <&wifi_pwrseq>;
brcmf: wifi#1 {
reg = <1>;
compatible = "brcm,bcm4329-fmac";
};
};
As referenced by the U-boot comments, U-boot is using SDHOST as the SD card controller and SDHCI as the WiFi controller.
/* SDHOST is used to drive the SD card */
...
/* SDHCI is used to control the SDIO for wireless */
The problem I'm facing is that I'm unable to run this SD card driver (source code here) via U-boot, which uses the Pi's SDHCI controller to interact with SD cards.
The SD card driver runs successfully bare-metal via the Pi's existing bootloader as shown by the output below:
EMMC: GPIO set up
EMMC: reset OK
sd_clk divisor 00000068, shift 00000006
EMMC: Sending command 00000000 arg 00000000
EMMC: Sending command 08020000 arg 000001AA
EMMC: Sending command 37000000 arg 00000000
EMMC: Sending command 29020000 arg 51FF8000
EMMC: CMD_SEND_OP_COND returned VOLTAGE CCS 0000000040F98000
...
However, when I try to run the binary via U-Boot using the go command, the code is stuck during the initialisation phase of the SDHCI controller (exact line in source code here) as shown below:
EMMC: GPIO set up
EMMC: reset OK
sd_clk divisor 00000068, shift 00000006
EMMC: Sending command 00000000 arg 00000000
EMMC: Sending command 08020000 arg 000001AA
ERROR: failed to send EMMC command
My suspicion is that since U-boot has configured the SDHCI controller for Wifi (and not for SD cards), I can no longer use it as an SD card controller. However, I want to use the SDHCI controller as the SD Card controller.
What is the best way to get my SD card binary running via U-boot?
Is the only option to configure/recompile U-boot to use the SDHCI controller as the main SD card controller (and forget about WiFi)?
If so, some pointers on how to go about this would be much appreciated.
Alternatively, is there a U-boot shell command (like some sort of reset command) that give binaries a runtime environment similar to a bare-metal environment that has been un-modified by U-boot?
Edit:
Here is my progress so far. I've figured out how to exclude the custom SDHOST driver from being initialised via two methods:
Modifying the DTS file by replacing status = "okay" with status = "disabled" for the custom SDHOST driver.
Adding CONFIG_MMC_BCM2835=n to U-Boot's configs/rpi_3_b_plus_defconfig file.
When I launch U-boot, and run mmc list, I see only the SDHCI controller, which is great:
U-Boot> mmc list
mmc#7e300000: 0
I know the above is the SDHCI controller because its device registers are mapped to the physical address of 7e300000 as shown in arch/arm/dts/bcm283x.dtsi below:
sdhci: mmc#7e300000 {
compatible = "brcm,bcm2835-sdhci";
reg = <0x7e300000 0x100>;
interrupts = <2 30>;
clocks = <&clocks BCM2835_CLOCK_EMMC>;
status = "disabled";
};
However, as shown in the following boot logs, U-boot is still not happy to use this controller as the SD card controller:
MMC: mmc#7e300000: 0
Loading Environment from FAT... Card did not respond to voltage select! : -110
** Bad device specification mmc 0 **
Below is the entire boot log:
U-Boot 2023.01-00790-g8c80619653-dirty (Feb 11 2023 - 10:04:49 +1100)
DRAM: 948 MiB
RPI 3 Model B+ (0xa020d3)
Core: 63 devices, 14 uclasses, devicetree: embed
MMC: mmc#7e300000: 0
Loading Environment from FAT... Card did not respond to voltage select! : -110
** Bad device specification mmc 0 **
In: serial
Out: vidconsole
Err: vidconsole
Net: No ethernet found.
starting USB...
Bus usb#7e980000: USB DWC2
scanning bus usb#7e980000 for devices... 4 USB Device(s) found
scanning usb for storage devices... 0 Storage Device(s) found
Hit any key to stop autoboot: 0
U-Boot> mmc list
mmc#7e300000: 0
My suspicion is that the SDHCI controller is still being treated by U-Boot as a WiFi controller (I can't tell for sure). What are some troubleshooting steps I can take to figure out what is going on?

My solution is to change the following line in the sdhci node of the DT located at arch/arm/dts/bcm2837-rpi-3-b-plus.dts from
pinctrl-0 = <&emmc_gpio34>;
to
pinctrl-0 = <&sdhost_gpio48>;
Then I recompile U-boot and use the resultant U-boot binary as the Pi’s bootloader.
The final and desired result is that:
U-boot can still use the sdhost driver and controller to access the SD card when it is running (which is U-boot’s default preference).
The binary run by U-boot (via the go command) can also manipulate the sdhci controller’s device registers to interact with the SD card.
For additional context around the solution, the sdhost_gpio48 reference above is located in this DTSI file located at arch/arm/dts/bcm283x.dtsi:
sdhost_gpio48: sdhost_gpio48 {
brcm,pins = <48 49 50 51 52 53>;
brcm,function = <BCM2835_FSEL_ALT0>;
};
The pinctrl-0 parameter we have changed refers to “Pin Control” and detailed documentation about this parameter can be found here.
From my understanding, our change specifies the same GPIO pins that are being used for the SDHOST controller for the SDHCI controller, which enables us to use the SDHCI controller as an SD card controller.

Related

U-Boot add node to devicetree during startup

I work on a custom board with a Cyclone V SoC.
I need to add some informations to U-Boot device tree at startup and these informations are stored in an I2C device.
It appears that U-Boot device tree is read-only during its execution but before relocation. The function board_fix_fdt (void *rw_fdt_blob) can be used to make changes on the device tree before relocation.
The problem I have is that I cannot access the I2C device at this time. The driver doesn't seem to be loaded yet.
Can someone give me any hints on how I can enable the I2C at this stage ?
U-Boot version is 2018-05.
The solution is to add in u-boot device tree the i2c driver and also the reset driver for pre-relocation states :
&rst {
status = "okay";
u-boot,dm-pre-reloc; // HERE
};
&i2c2 {
status = "okay";
u-boot,dm-pre-reloc; // and HERE
}

I've added a MAX7320 i2c output chip. How can I get the kernel to load the driver for it?

I've added a MAX7320 i2c expander chip to i2c bus 0 on my ARM Linux board.
The chip works correctly from userspace with commands such as /usr/sbin/i2cset -y 0 0x5d 0x02 and /usr/sbin/i2cget -y 0 0x5d.
There is a drivers/gpio/gpio-max732x.c file in the kernel source, which is compiled into the kernel that I'm running. (I've built it from source.)
How do I tell the kernel that it should instantiate the gpio-max732x driver on "i2c bus 0, chip id 0x5d"?
Do I need to modify the device tree .dts file and put a new .dtb file in /boot/dtbs/?
What would the clause for instantiating a gpio-max732x module look like?
P.S. I've seen https://lkml.org/lkml/2015/1/13/305 but I can't figure out how to get the patch files.
Device Tree
There must be appropriate Device Tree definition for your chip, in order for driver to instantiate. There are 2 ways to do so:
Modify .dts Device Tree file for your board (look in arch/arm/boot/dts/), then recompile it and re-flash it to your device.
This way is preferred in case when you have access you kernel sources for your board and you are able to re-flash .dtb file to your device.
Create Device Tree Overlay file, compile it and load it on your device.
This way is preferred when you don't have access to kernel sources for your board, or you are unable to flash new device tree blob to your device.
Your device definition in Device Tree should look like (according to Documentation/devicetree/bindings/gpio/gpio-max732x.txt):
&i2c0 {
expander: max7320#5d {
compatible = "maxim,max7320";
reg = <0x5d>;
gpio-controller;
#gpio-cells = <2>;
};
};
Kernel configuration
As your expander chip (MAX7320) has no input GPIOs, you don't need IRQ support for MAX732x. So you can disable CONFIG_GPIO_MAX732X_IRQ in your kernel configuration.
Matching device with driver
Once you have your Device Tree loaded (with definition for MAX7320), MAX732x driver will be matched with device definition, and instantiated. Below is explained how matching happens.
In Device Tree file you have compatible property:
compatible = "maxim,max7320";
In MAX732x driver you can see this table:
static const struct of_device_id max732x_of_table[] = {
...
{ .compatible = "maxim,max7320" },
...
When driver is being loaded, and when Device Tree blob is being loaded, kernel tries to find the match for each driver and Device Tree definition. Just by comparing strings above. If strings are matched -- kernel instantiates driver, passing corresponding device parameters to it. Look at i2c_device_match() function for details.
Obtaining patches
The best way is to use kernel sources that already have Device Tree support of MAX732x (v4.0+). But if it's not the case, then...
You can cherry-pick patches from upstream kernel to your kernel:
$ git remote add upstream git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
$ git fetch --all
$ git cherry-pick 43c4bcf9425e
$ git cherry-pick 479f8a5744d8
$ git cherry-pick 09afa276d52e
$ git cherry-pick 996bd13f28e6
And if you still want to apply patches manually (worst option, actually), here you can find direct links to patches. Click (patch) link to get a raw patch.
Also check later patches for gpio-max732x.c here.
Hardware concerns
To be sure that your chip has 0x5d I2C address, check that configuration pins are tied to next lines (as per datasheet):
Pin Line
-----------
AD2 V+
AD0 V+

Load u-boot.ldr in bf548 ezkit using sd card

i am working on BF548 EZKIT LITE, i had done tftp booting in it. Kernel and jffs2 file system loaded successfully and got the root prompt.
But now i need to use SD card for booting, I had made ext2 partition into sd card and copy u-boot.ldr(boot loader) in it, but when try to load this file after inserting SD card into board i had got an error like
tranfering data failed
** ext4fs_devread read error - block
Failed to mount ext2 filesystem...
** Unrecognized filesystem type **
search on net but could not find anything , add log for detail which shows SD card is detected.
bfin> mmcinfo
Device: Blackfin SDH
Manufacturer ID: 3
OEM: 5344
Name: SD02G
Tran Speed: 25000000
Rd Block Len: 512
SD version 2.0
High Capacity: No
Capacity: 1.8 GiB
Bus Width: 4-bit
bfin>
bfin> ext2load mmc 0 0x1000000 u-boot.ldr
tranfering data failed
** ext4fs_devread read error - block
Failed to mount ext2 filesystem...
** Unrecognized filesystem type **
bfin>
I had tried different sd card also but still got the same problem, Any one have clue about this? Please share.
U-boot version= 2014.07.
Linux kernel = 4.5.4
I am using Buildroot for making board support package.
Thank in advance....
Ah, so your problem is:
bfin> ext2load mmc 0 0x1000000 u-boot.ldr
and this should be:
bfin> ext4load mmc 0:1 0x1000000 u-boot.ldr
as you need to specify both the MMC device (0) and the partition on the device (1 as you made 1 partition on the SD card and formatted that). Just saying 0 causes it to try and read the whole device as where the filesystem is which fails when it runs into the partition table. And you need to use 'ext4load' (or just load, if you have the generic commands enabled) as well since you've got ext3/ext4 most likely and not just ext2.

Raspberry PI, GPIO Pull UP/DOWN resistors with SYSFS

Just off the bat I'd like to state that I'm aware of Python and other high level implementations for manipulating GPIO on the Raspberry PI. I've also been using the WiringPI C API and am experiencing problems with it on Raspbian Jessie that I was not having on Raspbian Wheezy even though I have not changed a single line of code. Also the WiringPI C API developer says he has no immediate plans to support Raspbian Jessie so I'm kind of up a creek without a paddle.
For this reason I've been reading the following tutorial (among others) on accessing Raspberry PI GPIOs using sysfs since this seems to be one way of addressing GPIO without using WiringPI and without writing my own GPIO library:
http://www.hertaville.com/introduction-to-accessing-the-raspberry-pis-gpio-in-c.html
According to this tutorial, to set GPIO17 as an input, you write the string 'in' to the file handle:
/sys/class/gpio/gpio/17/direction
...and then I can read GPIO input values from:
/sys/class/gpio/gpio17/value
This is all well and good but I do not have the option of retro fitting pull-up resistors to my production boards. Is it possible to set the Raspberry PI's built in pull-up and pull-down resistors using sysfs?
Also, if setting the pull-up and pull-down resistors via sysfs is not possible am I correct in assuming that even in the latest Raspbian Jessie the only other way to do this is write directly to GPIO registers? i.e. even in Raspbian Jessie there is no official C API for GPIO programming?
You can use a device-tree overlay to activate the pull-ups and port direction at boot up.
You will have to modify and compile the dts (source), place it in /boot/overlays, and enable it in config.txt. The instructions are in the source header. (Thanks to PhillE for his help!)
/*
* Overlay for enabling gpio's to pull at boot time
* this overlay uses pincctrl to initialize the pull-up register for the the listed gpios
* the compatible="gpio-leds" forces a module probe so the pinctrl does something
*
* To use this dts:
* copy this to a file named gpio_pull-overlay.dts
* modify the brcm,pins, brcm,function, and brcm,pull values
* apt-get install device-tree-compiler
* dtc -# -I dts -O dtb -o gpio_pull-overlay.dtb gpio_pull-overlay.dts
* sudo cp gpio_pull-overlay.dtb /boot/overlays
* add this line to the end config.txt: dtoverlay=gpio_pull
* reboot
*/
/dts-v1/;
/plugin/;
/ {
compatible = "brcm,bcm2835", "brcm,bcm2708";
fragment#0 {
target = <&gpio>;
__overlay__ {
gpio_pins: gpio_pins {
brcm,pins = <30 31 32 33>; /* list of gpio(n) pins to pull */
brcm,function = <0 1 0 1>; /* boot up direction:in=0 out=1 */
brcm,pull = <2 0 1 0>; /* pull direction: none=0, 1 = down, 2 = up */
};
};
};
fragment#1 {
target-path = "/soc";
__overlay__ {
gpiopull:gpiopull {
compatible = "gpio-leds";
pinctrl-names = "default";
pinctrl-0 = <&gpio_pins>;
status = "okay";
};
};
};
__overrides__ {
gpio_pull = <&gpiopull>,"status";
};
};
user1967890's solution worked fine for me until about May 28 or 29 of 2020, then I did an apt update/upgrade and I believe there was a Raspberry Pi kernel upgrade, after which this stopped working. In any case I had to resort to using a Python solution. So I now use the following at bootup to set the pullup resistors on GPIO pins 17 and 18, and to make sure that neither the pullup nor pulldown resistors are set on GPIO 22 through 25. And yes I realize this code could be shortened by using a loop to set GPIO_PIN_NUMBER, but it only runs once at bootup, so I am not too worried about it.
#!/usr/bin/python
import RPi.GPIO as GPIO
GPIO_PIN_NUMBER=17
GPIO.setmode(GPIO.BCM)
GPIO.setup(GPIO_PIN_NUMBER, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO_PIN_NUMBER=18
GPIO.setmode(GPIO.BCM)
GPIO.setup(GPIO_PIN_NUMBER, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO_PIN_NUMBER=22
GPIO.setmode(GPIO.BCM)
GPIO.setup(GPIO_PIN_NUMBER, GPIO.IN, pull_up_down=GPIO.PUD_OFF)
GPIO_PIN_NUMBER=23
GPIO.setmode(GPIO.BCM)
GPIO.setup(GPIO_PIN_NUMBER, GPIO.IN, pull_up_down=GPIO.PUD_OFF)
GPIO_PIN_NUMBER=24
GPIO.setmode(GPIO.BCM)
GPIO.setup(GPIO_PIN_NUMBER, GPIO.IN, pull_up_down=GPIO.PUD_OFF)
GPIO_PIN_NUMBER=25
GPIO.setmode(GPIO.BCM)
GPIO.setup(GPIO_PIN_NUMBER, GPIO.IN, pull_up_down=GPIO.PUD_OFF)
Obviously if I had wanted to pull a GPIO pin down I could have used GPIO.PUD_DOWN rather than GPIO.PUD_UP. I did not have to install anything that wasn't already present on my Raspberry Pi, although it's possible that something might have been installed during a previous software setup that would not be present on a brand new install of Raspbian.

Can't boot basic OpenEmbedded-Core on Freescale i.MX28

I've been trying to build and boot OpenEmbedded-Core on the evaluation kit for Freescale's ARM i.MX28, using the Freescale ARM layer for OpenEmbedded-Core. Unfortunately, I can't find a basic "Getting Started" guide (though there is a Yocto getting-started guide). Unfortunately, I haven't been able to "get started", to the point of successfully booting to a basic command prompt on the board's debug serial port.
Here is what I've been able to piece together, and as far as I've managed to get so far.
Fetch sources
mkdir -p oe-core/freescale-arm
cd oe-core/freescale-arm
git clone git://git.openembedded.org/openembedded-core oe-core
git clone git://github.com/Freescale/meta-fsl-arm.git
cd oe-core
git clone git://git.openembedded.org/meta-openembedded
git clone git://git.openembedded.org/bitbake bitbake
Set up environment
. ./oe-init-build-env
That puts us in a new sub-directory build and sets certain environment variables.
Edit configuration
Edit the conf/bblayers.conf and local.conf files:
conf/bblayers.conf should have the meta-fls-arm and meta-oe layers added for BBLAYERS. E.g.:
BBLAYERS ?= " \
/home/craigm/oe-core/freescale-arm/oe-core/meta \
/home/craigm/oe-core/freescale-arm/oe-core/meta-openembedded/meta-oe \
${TOPDIR}/../../meta-fsl-arm \
"
In conf/local.conf, I set:
BB_NUMBER_THREADS = "4"
PARALLEL_MAKE = "-j 4"
MACHINE = "imx28evk"
Build
bitbake core-image-minimal
I ran this build overnight, and it has completed successfully for me. Output files were in ~/oe-core/freescale-arm/oe-core/build/tmp-eglibc/deploy/images.
There are two boot options that I'd like to try, as described below. Boot from SD card is simpler, but takes quite a long time (~30 min) to write the image to the SD card. Booting from TFTP + NFS is faster, but requires more set-up.
Boot from SD Card
Write image to SD card:
sudo dd if=tmp-eglibc/deploy/images/core-image-minimal-imx28evk.sdcard of=/dev/sdc
It took something like 30 minutes (3.5 GB file). Then I put it in the board's SD card slot 0, and powered-up. It got as far as loading the kernel, then stopped:
U-Boot 2012.04.01-00059-g4e6e824 (Aug 23 2012 - 18:08:54)
Freescale i.MX28 family at 454 MHz
BOOT: SSP SD/MMC #0, 3V3
DRAM: 128 MiB
MMC: MXS MMC: 0
*** Warning - bad CRC, using default environment
In: serial
Out: serial
Err: serial
Net: FEC0, FEC1
Hit any key to stop autoboot: 0
reading boot.scr
** Unable to read "boot.scr" from mmc 0:2 **
reading uImage
2598200 bytes read
Booting from mmc ...
## Booting kernel from Legacy Image at 42000000 ...
Image Name: Linux-2.6.35.3-11.09.01+yocto-20
Created: 2012-08-23 7:53:40 UTC
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 2598136 Bytes = 2.5 MiB
Load Address: 40008000
Entry Point: 40008000
Verifying Checksum ... OK
Loading Kernel Image ... OK
OK
Starting kernel ...
Uncompressing Linux... done, booting the kernel.
Boot from TFTP + NFS
First, I tried to write U-Boot onto an SD card:
sudo dd if=tmp-eglibc/deploy/images/u-boot-imx28evk.mxsboot-sdcard of=/dev/sdc
Then I put it in the board's SD card slot 0, and powered-up. But all I got in the debug serial port was:
0x8020a01d
So, I decided to use Freescale's distribution of U-Boot for i.MX28 (from their LTIB distribution) onto an SD card. I set suitable U-Boot parameters for NFS booting with parameters from DHCP.
setenv bootargs console=ttyAMA0,115200n8
setenv bootargs_nfs setenv bootargs ${bootargs} root=/dev/nfs ip=dhcp nfsroot=,v3,tcp fec_mac=${ethaddr}
saveenv
I connected to a DD-WRT router with the following DNSmasq settings:
dhcp-boot=,,192.168.250.106
dhcp-option=17,"192.168.250.106:/home/craigm/rootfs"
On my host PC, I set up a TFTP server to serve the uImage file from ~/oe-core/freescale-arm/oe-core/build/tmp-eglibc/deploy/images/.
I also set up a root NFS server to serve the root file system. I edited /etc/exports to serve /home/craigm/rootfs. I extracted the root file system:
bitbake meta-ide-support
rm -Rf ~/rootfs
runqemu-extract-sdk tmp-eglibc/deploy/images/core-image-minimal-imx28evk.tar.bz2 ~/rootfs
Then I put the U-Boot SD card in the board's SD card slot 0, and powered-up. It got as far as this, then stopped:
...
TCP cubic registered
NET: Registered protocol family 17
can: controller area network core (rev 20090105 abi 8)
NET: Registered protocol family 29
can: raw protocol (rev 20090105)
mxs-rtc mxs-rtc.0: setting system clock to 1970-01-01 00:03:33 UTC (213)
eth0: Freescale FEC PHY driver [Generic PHY] (mii_bus:phy_addr=0:00, irq=-1)
eth1: Freescale FEC PHY driver [Generic PHY] (mii_bus:phy_addr=0:01, irq=-1)
Sending DHCP requests .
PHY: 0:00 - Link is Up - 100/Full
., OK
IP-Config: Got DHCP answer from 192.168.250.106, my address is 192.168.250.142
IP-Config: Complete:
device=eth0, addr=192.168.250.142, mask=255.255.255.0, gw=192.168.250.1,
host=192.168.250.142, domain=, nis-domain=(none),
bootserver=192.168.250.106, rootserver=192.168.250.106, rootpath=/home/craigm/rootfs
Looking up port of RPC 100003/3 on 192.168.250.106
Looking up port of RPC 100005/3 on 192.168.250.106
VFS: Mounted root (nfs filesystem) on device 0:15.
Freeing init memory: 160K
I'm not sure if it's running without a serial console, or some other problem. I can ping it on 192.168.250.142, but I can't Telnet or SSH to it.
Questions
Is there any sort of "getting started" guide for OpenEmbedded-Core on Freescale's i.MX28?
Is the Freescale ARM layer really intended for use with OpenEmbedded-Core, Yocto, or what? I don't really understand how those projects relate.
Has anyone else had success booting a minimal image of OpenEmbedded-Core on Freescale's i.MX28? If so, how did your procedure differ from mine?
I'm not sure at this stage whether the problem is just a non-functional serial console, or some other sort of issue. It's hard to diagnose these problems that prevent even getting a basic system running. Any pointers on how to diagnose at this point?
Why would the U-Boot be broken so it can't even boot?
From the boot message it looks like U-boot is working fine. U-boot is not broken.
The following boot message
2598200 bytes read
Booting from mmc ...
## Booting kernel from Legacy Image at 42000000 ...
Image Name: Linux-2.6.35.3-11.09.01+yocto-20
Created: 2012-08-23 7:53:40 UTC
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 2598136 Bytes = 2.5 MiB
Load Address: 40008000
Entry Point: 40008000
Verifying Checksum ... OK
Loading Kernel Image ... OK
OK
Starting kernel ...
Uncompressing Linux... done, booting the kernel.
By the above log u-boot has done its job.
"Booting the kernel" is the point where bootloader given the control to the kernel.
I guess the problem might be in kernel image or in memory.
To eliminate the problem of memory, try to check the manual and try to read and write in the RAM using the board's reference manual.
From the boot log RAM looks like has no problem. It has been initialized.
DRAM: 128 MiB
Check if the following message is not causing any problem.
* Warning - bad CRC, using default environment
Check if all the devices have been initialized and nothing is skipped after the bad crc warning.

Resources