user10008009
user10008009

Reputation:

U-Boot 2020.04: Probing SPI flash fails - Invalid bus 0 (err=-19)

I'm just compiled U-Boot 2020.04 for a PINE64 ROCK64 media board. It compiles fine without errors. But I run into an issue when I try to probe the SPI flash.

The output from U-Boot command line:

=> sf probe
Invalid bus 0 (err=-19)
Failed to initialize SPI flash at 0:0 (error -19)
=>

The Device-Tree SPI section from the board:

&spi0 {
    status = "okay";

    spiflash@0 {
        compatible = "jedec,spi-nor";
        reg = <0>;

        /* maximum speed for Rockchip SPI */
        spi-max-frequency = <50000000>;
    };
};

I also tried different buses and chip selects. But didn't work. According to the schematic from the board, the SPI flash device GD25Q128CS is used.

How I compiled the sources:

$ make rock64-rk3328_defconfig
$ make CROSS_COMPILE=/path/to/gcc-arm-9.2-2019.12-x86_64-aarch64-none-elf/bin/aarch64-none-elf- -j 4

I have used the official GCC port from the ARM website.

Tried also an older and a newer versions of U-Boot. Same issue. I flashed the microSD card according to the U-Boot documentation:

$ dd if=idbloader.img of=/dev/mmcblk0 seek=64
$ dd if=u-boot.itb of=/dev/mmcblk0 seek=16384

How can I narrow down this issue? Something missing?

Update:

Seems U-Boot doesn't load the SPI driver from the board:

=> dm tree    
 [...]
  spi           0  [   ]   rockchip_spi          |-- spi@ff190000                                                        
  spi_flash     0  [   ]   spi_flash_std         |   `-- spiflash@0
 [...]
=>

What I have also tried:

I have added the following configuration to the board file:

CONFIG_ROCKCHIP_SPI=y
CONFIG_SPI_FLASH=y
CONFIG_SPI_FLASH_GIGADEVICE=y

In the driver file I have tried to put a simple printf() at the beginning of the function rockchip_spi_probe(). I also added a compatible identifier (same string as in the Device-Tree) in the driver. But unfortunately the probe function never get called.

I'm a newbie with U-Boot. Any kind of help is highly appreciated.

Upvotes: 5

Views: 5401

Answers (3)

Serge
Serge

Reputation: 1

Upstream u-boot now supports SPI flash on the Rock64

Upvotes: 0

user10008009
user10008009

Reputation:

I finally resolved the issue.

The problems were missing entries in the device tree files (error code -19 -- Thanks to @Stefan's answer) and missing support for the SPI controller in the clock driver (error code -2) from the SoC.

My working modifications:

SPI driver (drivers/spi/rk_spi.c):

static const struct udevice_id rockchip_spi_ids[] = {
    { .compatible = "rockchip,rk3066-spi" },
    { .compatible = "rockchip,rk3288-spi" },
    { .compatible = "rockchip,rk3328-spi" },
    { .compatible = "rockchip,rk3368-spi",
      .data = (ulong)&rk3399_spi_params },
    { .compatible = "rockchip,rk3399-spi",
      .data = (ulong)&rk3399_spi_params },
    { }
};

Here I have simple added the device ID string (rockchip,rk3328-spi) for the specified device. Not sure if rk3399_spi_params is also needed. But works without it.

Clock driver (drivers/clk/rockchip/clk_rk3328.c):

I have added these new functions...

static ulong rk3328_spi_get_clk(struct rk3328_cru *cru)
{
    u32 div, val;

    val = readl(&cru->clksel_con[24]);
    div = (val & CLK_SPI_DIV_CON_MASK) >> CLK_SPI_DIV_CON_SHIFT;

    return DIV_TO_RATE(OSC_HZ, div);
}

static ulong rk3328_spi_set_clk(struct rk3328_cru *cru, uint hz)
{
    u32 src_clk_div;

    src_clk_div = GPLL_HZ / hz;
    assert(src_clk_div < 128);

    rk_clrsetreg(&cru->clksel_con[24],
             CLK_PWM_PLL_SEL_MASK | CLK_PWM_DIV_CON_MASK,
             CLK_PWM_PLL_SEL_GPLL << CLK_PWM_PLL_SEL_SHIFT |
             (src_clk_div - 1) << CLK_PWM_DIV_CON_SHIFT);

    return rk3328_spi_get_clk(cru);
}

...and added the functions calls to the functions rk3328_clk_get_rate() and rk3328_clk_set_rate() in the switch statements:

static ulong rk3328_clk_get_rate(struct clk *clk)
{
    struct rk3328_clk_priv *priv = dev_get_priv(clk->dev);
    ulong rate = 0;

    switch (clk->id) {
    case 0 ... 29:
        return 0;
    case HCLK_SDMMC:
    case HCLK_EMMC:
    case SCLK_SDMMC:
    case SCLK_EMMC:
        rate = rk3328_mmc_get_clk(priv->cru, clk->id);
        break;
    case SCLK_I2C0:
    case SCLK_I2C1:
    case SCLK_I2C2:
    case SCLK_I2C3:
        rate = rk3328_i2c_get_clk(priv->cru, clk->id);
        break;
    case SCLK_PWM:
        rate = rk3328_pwm_get_clk(priv->cru);
        break;
    case SCLK_SARADC:
        rate = rk3328_saradc_get_clk(priv->cru);
        break;
    case SCLK_SPI:
        rate = rk3328_spi_get_clk(priv->cru);
        break;
    default:
        return -ENOENT;
    }

    return rate;
}

static ulong rk3328_clk_set_rate(struct clk *clk, ulong rate)
{
    struct rk3328_clk_priv *priv = dev_get_priv(clk->dev);
    ulong ret = 0;

    switch (clk->id) {
    case 0 ... 29:
        return 0;
    case HCLK_SDMMC:
    case HCLK_EMMC:
    case SCLK_SDMMC:
    case SCLK_EMMC:
        ret = rk3328_mmc_set_clk(priv->cru, clk->id, rate);
        break;
    case SCLK_I2C0:
    case SCLK_I2C1:
    case SCLK_I2C2:
    case SCLK_I2C3:
        ret = rk3328_i2c_set_clk(priv->cru, clk->id, rate);
        break;
    case SCLK_MAC2IO:
        ret = rk3328_gmac2io_set_clk(priv->cru, rate);
        break;
    case SCLK_PWM:
        ret = rk3328_pwm_set_clk(priv->cru, rate);
        break;
    case SCLK_SARADC:
        ret = rk3328_saradc_set_clk(priv->cru, rate);
        break;
    case SCLK_SPI:
        ret = rk3328_spi_set_clk(priv->cru, rate);
        break;
    case DCLK_LCDC:
    case SCLK_PDM:
    case SCLK_RTC32K:
    case SCLK_UART0:
    case SCLK_UART1:
    case SCLK_UART2:
    case SCLK_SDIO:
    case SCLK_TSP:
    case SCLK_WIFI:
    case ACLK_BUS_PRE:
    case HCLK_BUS_PRE:
    case PCLK_BUS_PRE:
    case ACLK_PERI_PRE:
    case HCLK_PERI:
    case PCLK_PERI:
    case ACLK_VIO_PRE:
    case HCLK_VIO_PRE:
    case ACLK_RGA_PRE:
    case SCLK_RGA:
    case ACLK_VOP_PRE:
    case ACLK_RKVDEC_PRE:
    case ACLK_RKVENC:
    case ACLK_VPU_PRE:
    case SCLK_VDEC_CABAC:
    case SCLK_VDEC_CORE:
    case SCLK_VENC_CORE:
    case SCLK_VENC_DSP:
    case SCLK_EFUSE:
    case PCLK_DDR:
    case ACLK_GMAC:
    case PCLK_GMAC:
    case SCLK_USB3OTG_SUSPEND:
        return 0;
    default:
        return -ENOENT;
    }

    return ret;
}

Device-Trees:

arch/arm/dts/rk3328-u-boot.dtsi:

I have added the correct alias...

/ {
    aliases {
        mmc0 = &emmc;
        mmc1 = &sdmmc;
        spi0 = &spi0;
    };

...and the SPI controller itself.

&spi0 {
    u-boot,dm-pre-reloc;
};

arch/arm/dts/rk3328-rock64-u-boot.dtsi:

For the SPI flash I added these...

&spi0 {
    spi_flash: spiflash@0 {
        u-boot,dm-pre-reloc;
    };
};

Board configuration (configs/rock64-rk3328_defconfig):

Added these configuration switches...

CONFIG_ROCKCHIP_SPI=y
CONFIG_SPI_FLASH_GIGADEVICE=y

The result:

=> sf probe
SF: Detected gd25q128 with page size 256 Bytes, erase size 4 KiB, total 16 MiB
=>

The SPI flash will be correctly detected.

Not sure if I should release a patch in the U-Boot list for this.

Upvotes: 3

Stefan
Stefan

Reputation: 11

Can you try adding:

spi0 = &spi0;

to the aliases section in the file rk3399.dtsi? Is there any change?

Upvotes: 1

Related Questions