Forum Discussion

Silvan's avatar
Silvan
Icon for Occasional Contributor rankOccasional Contributor
6 years ago
Solved

driver for HPS I2C Hardware in u-boot 04.2020 deactivates clocks

Hello all,

I have an Arria 10 SoC device on our custom board. The board boots from an SD Card, loading u-boot and than a Linux kernel.

Until now, I used an old u-boot build flow utilized Quartus and the bsp-editor. With a small adaption, u-boot (2014.10) is able to read a MAC address from an external EEPROM connected through an I2C interface.

Now I have to switch to a the new u-boot build flow created on the sources: https://github.com/altera-opensource/u-boot-socfpga (2020.04) as described on: https://rocketboards.org/foswiki/Documentation/BuildingBootloader?erpm_id=6579622_ts1606222496230

For our custom board, I adapted the u-boot configuration and device tree blob of the Arria 10 SoC DevKit included in the sources. When configuring the basic Hardware (SD Card, UART, Ethernet, ...) our board is able to boot the Liunx kernel.

As soon as, I try to enable and use the I2C interface in u-boot, the kernel isn't able to boot anymore. In configuration I added and activated the following configs:

CONFIG_MISC=y
CONFIG_I2C_EEPROM=y
CONFIG_SYS_I2C_EEPROM_BUS=0
CONFIG_SYS_I2C_EEPROM_ADDR=0x50
CONFIG_SYS_I2C_EEPROM_ADDR_LEN=2
CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW=0
CONFIG_SYS_EEPROM_SIZE=512
CONFIG_SYS_EEPROM_PAGE_WRITE_BITS=0
CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS=0
CONFIG_CMD_EEPROM=y
CONFIG_CMD_I2C=y
CONFIG_SYS_I2C_DW=y

And in the device tree blob I have the I2C hardware:

&i2c1 {
  status = "okay";
  clock-frequency = <100000>;
  eeprom@50 {
    compatible = "atmel,24c512";
    reg = <0x50>;
    pagesize = <32>;
  };
};

With this adaption I could enable the I2C hardware in the u-boot console. When I try to boot the Linux kernel afterwards, the HPS gets stuck. I could enclose the issue to the u-boot function dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL); which is called before the kernel starts.

The function loops over the device tree blob and disable all active hardware. This is also done for the I2C driver and its clocks. So the designware_i2c_remove function disables the clock and after disabling the l4_sp_clk the device hangs.

Does anyone know, how to prevent the deactivation of the clocks? Does anyone has experience with the use of I2C in u-boot 2020.04?

Cheers

Silvan

  • Hello,

    We had a similar problem trying to migrate to the socfpga_v2021.04 branch of uBoot. We have an on-board EEPROM (I2C) that contains factory configuration data that is needed during the uBoot TPL phase.

    We are seeing that the designware_i2c I2C controller is resetting the l4_sp_clk when it is removed prior to starting the linux kernel. The result is that there is a bus hang when the kernel tries to access the UART peripheral (which needs that clock). The kernel we are trying to use is from 4.9.78-ltsi. It's possible that later versions of the kernel properly re-enable the l4_sp_clk, but this doesn't seem to be the case for our particular configuration (which works fine with uboot 2014.10). We also had to set the socfpga_legacy_reset_compat=1 uBoot environment variable as well, as without it this version of uBoot will reset all the peripherals as it switches to linux, resulting in a similar hang.

    Our work-around can be found in this patch here:

    Critical Link LLC git repositories. - u-boot-socfpga.git/blobdiff - drivers/i2c/designware_i2c.c

    -Mike

33 Replies

  • alasadi's avatar
    alasadi
    Icon for New Contributor rankNew Contributor

    We have experienced this as well.

    You have tracked the problem down correctly to DM_REMOVE_ACTIVE_ALL.

    The problem is that uboot Device Model will try to deactivate the i2c device node, taking down the associated l4_sp_clk with it. There is probably a proper fix for this problem, however doing the following is a workaround:

    1. Create a virtual fixed-clock in your uboot dts file. Something like this:

    clk_virt_l4_sp: clk_virt_l4_sp {
    #clock-cells = <0>;
    compatible = "fixed-clock";
    clock-frequency = <100000000>;
    };

    The frequency (100MHz here) has to match your FPGA design (check your HPS clock configuration in qsys..).

    2.

    Re-assign the clock of the i2c node you are using to the new virtual fixed clock. Something like this, when done in a dts or dtsi file which includes the main dtsi file (where i2c0 is defined):

    &i2c0 {

    clocks = <&clk_virt_l4_sp>;

    }

    With this workaround, uboot will not try to deactivate l4_sp_clk before starting the linux kernel and it should boot fine.

    Hope it helps.

    Hussein Alasadi

    ARECS GmbH

    • Silvan's avatar
      Silvan
      Icon for Occasional Contributor rankOccasional Contributor

      Hi Hussein,

      Many thanks for your answer. For me it make sens, that a "fixed-clock" is a workaround to solve this issue. In a first step, I try to implement this on in the device tree for the development board (right now in u-boot 2020.10).

      I added the clk_virt_l4_sp node in the clock section of the device tree where also the other fixed clocks (osc1, f2s_free_clk, ...) are. For your interest I put the updated socfpga_arria10.dtsi (renamed to *.txt) file in the attach.

      Now I see an issue when loading the i2c driver. It seams, that no clock frequency is given by the instantiated clock node. One debug output from the driver is: dw_i2c: mode 0, ic_clk 0, speed 100000, period 0 rise 0 fall 0 tlow 0 thigh 0 spk 0 which shows, that the clock frequency is 0.

      I think, maybe I put the clk_virt_l4_sp definition in the wrong location in the device tree? Do you know the correct location of it?

      Thanks and best regards,

      Silvan

  • MWill5's avatar
    MWill5
    Icon for New Contributor rankNew Contributor

    Hello,

    We had a similar problem trying to migrate to the socfpga_v2021.04 branch of uBoot. We have an on-board EEPROM (I2C) that contains factory configuration data that is needed during the uBoot TPL phase.

    We are seeing that the designware_i2c I2C controller is resetting the l4_sp_clk when it is removed prior to starting the linux kernel. The result is that there is a bus hang when the kernel tries to access the UART peripheral (which needs that clock). The kernel we are trying to use is from 4.9.78-ltsi. It's possible that later versions of the kernel properly re-enable the l4_sp_clk, but this doesn't seem to be the case for our particular configuration (which works fine with uboot 2014.10). We also had to set the socfpga_legacy_reset_compat=1 uBoot environment variable as well, as without it this version of uBoot will reset all the peripherals as it switches to linux, resulting in a similar hang.

    Our work-around can be found in this patch here:

    Critical Link LLC git repositories. - u-boot-socfpga.git/blobdiff - drivers/i2c/designware_i2c.c

    -Mike

    • Silvan's avatar
      Silvan
      Icon for Occasional Contributor rankOccasional Contributor

      Hi Mike,

      Thanks for that nice patch. The system works with it. Also, many thanks for the hint to the u-boot variable socfpga_legacy_reset_compat

      Silvan

  • Hi Silvan,

    I noticed that you changed from the default configuration, thus you may need to change the Linux's device tree as well, you may find in similar directory:

    \linux-socfpga-socfpga-5.4.54-lts\arch\arm\boot\dts

    The file is called "socfpga_arria10_socdk".

    From my experience of changing Uboot settings for a custom board, if you opt to use the Linux, you need to check the Linux's device tree as well. In addition, before changing the device tree, you need to check if the other config of the I2C is reliable to what you looking for, the frequency, compatible, etc..

    Also, are you using "I2C1" in the old Uboot that worked?

    • Silvan's avatar
      Silvan
      Icon for Occasional Contributor rankOccasional Contributor

      Hi Eberlazare,

      Thanks for your feedback.

      I didn’t changed the Linux device tree during the u-boot migration from 2014.10 to 2020.04. Is it required? I think the issue which I observe in u-boot 2020.04 is shortly before the Linux kernel starts.

      Our u-boot device tree is based on \arch\arm\dts\socfpga_arria10.dtsi which includes the I2C1 device information (compatible, clock, ...). I think, its configuration is correct because I’m able to communicate with our EEPROM from u-boot.

      The issue which I’m observe is when u-boot switch to the Linux kernel. Before loading the kernel, u-boot has a clean-up routine to release allocated hardware resources. And at the point when the enabled I2C hardware is released, the system stops to work. I added additional debug/print-outputs in the u-boot sources to isolate the issue. I attached the log on this reply and a description follows bellow.

      Yes, the old u-boot version 2014.10 used also I2C1 to read the MAC address from an external EEPROM. As far as I understand, the Hardware and FPGA firmware work correctly. So what is the recommendation to enable and use the I2C hardware in u-boot 2020.04? Is it wrong to just enable the i2c hardware based on \arch\arm\dts\socfpga_arria10.dtsi?

      Short log description:

      1. Enabling the I2C device with ‘i2c dev 0’ (Line 44) and list available devices with ‘i2c prob’ (Line 52).
      2. Boot Linux kernel with ‘run bootcmd’ (Line 54)
      3. Starting log in file: \arch\arm\lib\bootm.c In function ‘announce_and_cleanup(int fake)’ dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL); is called. (Line 87)
      4. The function is implemented in \drivers\core\root.c and calls ‘device_remove’ from \drivers\core\device-remove.c which loops over all active devices and disable it and there child. (Line 88)
      5. If I2C active (which is true after calling ‘i2c prob’) (Line 305) the remove function ‘designware_i2c_remove(struct udevice *dev)’ in /drivers/i2c/designware_i2c.c is called (Line 337). This function stops the l4_sp_clkclk_disable clock which results in a non working system and after a while the watchdog reboot the device… (Line 339)

      • EBERLAZARE_I_Intel's avatar
        EBERLAZARE_I_Intel
        Icon for Regular Contributor rankRegular Contributor

        Hi,

        Yes as per my experience, it is required as you are running in Linux.

        Correct me if I am wrong, you did change in the Uboot device tree, and in Uboot you are not seeing such issue, but only in Linux am I correct?

        Have you tried changing the Linux device tree as well?

  • Hi,

    Have you reassigned in the device tree (included where memory is define), that your i2c is using:

    &i2c0 {

    clocks = <&clk_virt_l4_sp>;

    }

    Instead of for example GHRD's :

    &i2c0 {

    clocks = <1000000>;

    }

    • Silvan's avatar
      Silvan
      Icon for Occasional Contributor rankOccasional Contributor

      Hi Eberlazare

      Please have a look to the file attached in the previous answer!!!!!!!!!

      I added clocks = <&clk_virt_l4_sp>; to the i2c1 device because the EEPROM which i would use on the DevKit is connected on i2c1 and not i2c0. Do you still think i2c0 is the right place for clocks = <&clk_virt_l4_sp>; ? And what do you think is the reason for that?

      Please could you put me in touch with an expert from intelFPGA to assist me for solving that issue? Otherwise it seems that we will not be successful!

      Thanks

      Silvan

  • In the function designware_i2c_remove,

    comment the following lines.

    int designware_i2c_remove(struct udevice *dev)
    {
    struct dw_i2c *priv = dev_get_priv(dev);

    #if CONFIG_IS_ENABLED(CLK)
    //clk_disable(&priv->clk);
    clk_free(&priv->clk);
    #endif

    //return reset_release_bulk(&priv->resets);
    return 0;
    }

    This will fix the booting issue.

  • Hi Silvan,

    We found the root cause of the issue, it seems to be an issue when disabling the l4_sp_clk when Starting the Kernel. So, when I2C is removed before Kernel, it removes the l4_sp_clk, then this would impact other peripherals running, triggering the hang in Uboot when dessaserting the peripherals.

    To fix the issue, together with enabling the I2C in U-boot, please use the patch (attached) following the steps from:

    https://rocketboards.org/foswiki/Documentation/BuildingBootloader#Arria_10_SoC_45_Boot_from_SD_Card

    How to apply the patch, after following "Build U-boot” steps after:

    git checkout -b test-bootloader -t origin/socfpga_v2021.04

    Copy the patch file in the “software/bootloader” folder, and run:

    patch -p1 < ../enable_i2c_uboot_kernel_fix.patch

  • Hi all,

    I am facing a similar issue with USB boot. When i try to boot from USB from u-boot, its hanging at starting kernel. In function "dwc2_usb_remove" of drivers/usb/host/dwc2.c, I tried commenting out two functions,

    //clk_disable_bulk(&priv->clks);
    //clk_release_bulk(&priv->clks);

    Now I am able to see the print " Deasserting all peripheral resets ", but still it's not booting. I also tried not to call "dwc2_usb_remove" function but observed the same. Any idea on this issue?