This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Linux/TMDXIDK5718: How SPL can read EEPROM behind Mux on I2C bus 2

Part Number: TMDXIDK5718

Tool/software: Linux

Hi

I'm using Linux SDK 5.1, custom HW, strongly based on IDK574.

I have EEPROM (chip address 0x51) on I2C bus 2 behind an pca9546 (chip address 0x70) on channel 1 (In IDK, EPROM and PMIC are both on I2C bus 0.)

I can successfully read eeprom in U-boot as follows:

Setting bus 2: i2c dev 2

setting channel 1 on mux: i2c mw 70 0.1 1

Read 400h bytes: i2c md 51 0.2 400

Now I tried to do same in do_board_detect() of SPL. 

int save = i2c_get_bus_num(); // save the bus number because later in board_late_init() we have to talk to bus 0 again

gpi2c_init()

rc = i2c_set_bus_num(i2c_bus /* 2 */);

if (rc)    return rc;

// set mux to channel 1
uint8_t buffer = 1; // channel 1
rc = i2c_write(0x70, 0, 0, &buffer, 1); // here I always get return code 1
if (rc) return rc;

rc = i2c_probe(0x51);

if (rc) return rc;

rc = i2c_read(0x51, 0x0, 0x2, (uint8_t *)ep, sizeof (struct my_eeprom));
if (rc) return rc;

i2c_set_bus_num(save); // restore bus number

So How I can I use bus number 0 in SPL? Do I have to add the mux and EEPROM in devicetree?  I just enabled i2c2:

&i2c2 {

clock-frequency = <100000>;

u-boot,dm-spl;

status = "okay";

};

Or do I have to set CONFIG_SYS_OMAP24_I2C_SLAVE<n> or some other CONFIG_?

BR, Chris

  • Hello Christian,

    Due to the US holidays, on this particular E2E thread, our response may get delayed until the week of Jan 2, 2019.

    Warmest Wishes for Happy Holidays and a Happy New Year!

    best regards,
    David Zhou
  • From where does the pca9546 receive its power (AM57 or some other source)? Be sure the device is first powered.

  • Hi Marcus,

    The mux is powered. We have checked that.

    I was digging deeper: in SPL, ti_i2c_eeprom_get() is called.

    in SPL CONFIG_DM_I2C not set (I checked spl/u-boot.cfg and also be single stepping), so 

    the "#else part" of ti_i2c_eeprom_get() is taken:

    #else
    u32 byte;

    gpi2c_init();
    rc = ti_i2c_eeprom_init(bus_addr, dev_addr);
    if (rc)
    return rc;

    /*
    * Read the header first then only read the other contents.
    */
    byte = 2;

    rc = ti_i2c_set_alen(bus_addr, dev_addr, byte);
    if (rc)
    return rc;

     

    The error happes in ti_i2c_set_alen():

    int __maybe_unused ti_i2c_set_alen(int bus_addr, int dev_addr, int alen)
    {
    struct udevice *dev;
    struct udevice *bus;
    int rc;

    rc = uclass_get_device_by_seq(UCLASS_I2C, bus_addr, &bus);
    if (rc)
    return rc;

    uclass_get_device_by_seq returns -ENODEV.

    I also checked SPL device tree (fdtdump -s spl/u-boot.bin) and many I2C busses are shown, at least number 0.

    I wonder how this uclass structures are populated? 

    Regards, Chris

  • Ok - Well let's start with the fact that the i2c eeprom read is successful at the u-boot prompt.  This indicates the read function call stack or initialization is different from the point at which you attempt to read the eeprom in SPL.  This is the reason I asked if the eeprom is powered up at the point when SPL attempts to read.  Since power is provided you should do a comparison of the call stack & initialization between the working case and failing case (with debug logs enabled). 

  • It's seems the eeprom initialization you've implemented deviates from what is provided in the SDK. Have you tried using the existing procedure (see below)

    #ifdef CONFIG_TI_I2C_BOARD_DETECT
    void do_board_detect(void)
    {
    enable_i2c0_pin_mux();
    i2c_init(CONFIG_SYS_OMAP24_I2C_SPEED, CONFIG_SYS_OMAP24_I2C_SLAVE);

    if (ti_i2c_eeprom_am_get(CONFIG_EEPROM_BUS_ADDRESS,
    CONFIG_EEPROM_CHIP_ADDRESS))
    printf("ti_i2c_eeprom_init failed\n");
    }
    #endif
  • Sorry but I was euphoric.

    What I have done: added two lines to early_padconf

    const struct pad_conf_entry early_padconf[] = {

    {I2C2_SDA, (M0 | PIN_INPUT)}, // i2c2_sda.i2c2_sda
    {I2C2_SCL, (M0 | PIN_INPUT)}, // i2c2_scl.i2c2_scl

    then made sure I2C2 is initialized:

    // set bus number
    if (i2c_bus >= 0) {
    rc = i2c_set_bus_num(2);
    if (rc)
    return rc;
    }

    gpi2c_init(); // actually i2c_set_bus_num(2) should already initialize I2C2

    u32 byte = 0; // Address length = 0

    uint8_t buffer = 1;
    rc = i2c_write(0x70, 0, byte, &buffer, 1); // trying to select channel 0 of PCA9546

    still getting rc = 1.. - no Ack

    So: Pinmux is ok, I2C2 controller is inited. What is missing?

    Regards, Chris
  • Your PIN MUX should also add "pull up enabled" and" slew control" on both pins (PULLUDEN | SLEWCTRL) .
  • We have external pull-ups. So no need to set PULLUDEN, I guess.

    We are using cloud based Pinmux tool which suggest

    {GPIO6_15, (M9 | PIN_INPUT)}, /* gpio6_15.i2c3_scl */

    {MCASP1_ACLKX, (M10 | PIN_INPUT)}, /* mcasp1_aclkx.i2c3_sda */

    Do we have add add SLEWCTRL manually, which would mean that Pinmux tool output is wrong / incomplete? 

    Regards, Chris

  • Are you observing signals on the clk and data pins?
  • I checked with scope no signal on clk and data. 

    I have also moved all pinmuxing to early pinmux.

    And wait 100us before accessing I2Cmux after reset.

    I had an issue in the past that e.g. clock for UART COM8 was not set in the Bootloader so I got a patch from TI.

    Could there be a similar issue: Obviously I2C0 does work. It's used on all IDK types. But maybe some initialization or clock is missing for I2C3?

    Regards, Chris

  • Yes - most likely then I2C3 is not being initialized or the pinmux is incorrect. Let me create patch or example code to enable I2C3.

  • Using i2c1 as an example, edit file

    ./arch/arm/mach-omap2/am33xx/clock_am33xx.c
    function enable_basic_clocks()
    structure clk_modules_explicit_en[].

    Add the configuration and entry for i2c3 similar to "cmper->i2c1clkctrl"