Skip to content

Instantly share code, notes, and snippets.

@qinghon
Created April 24, 2022 07:06
Show Gist options
  • Save qinghon/422164726d26b1d0b51254ba7a26ca8a to your computer and use it in GitHub Desktop.
Save qinghon/422164726d26b1d0b51254ba7a26ca8a to your computer and use it in GitHub Desktop.

Revisions

  1. qinghon renamed this gist Apr 24, 2022. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  2. qinghon created this gist Apr 24, 2022.
    199 changes: 199 additions & 0 deletions i2c_release.diff
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,199 @@
    // plat/nxp/drivers/ddr/nxp-ddr/ddr.c
    /* Return the bit mask of valid DIMMs found */
    static int parse_spd(struct ddr_info *priv)
    {
    struct ddr_conf *conf = &priv->conf;
    struct dimm_params *dimm = &priv->dimm;
    int j, valid_mask = 0;

    #ifdef CONFIG_DDR_NODIMM
    valid_mask = ddr_get_ddr_params(dimm, conf);
    if (valid_mask < 0) {
    ERROR("DDR params error\n");
    return valid_mask;
    }
    #else
    const int *spd_addr = priv->spd_addr;
    const int num_ctlrs = priv->num_ctlrs;
    const int num_dimm = priv->dimm_on_ctlr;
    struct ddr4_spd spd[2];
    unsigned int spd_checksum[2];
    int addr_idx = 0;
    int spd_idx = 0;
    int ret, addr, i;

    /* Scan all DIMMs */
    for (i = 0; i < num_ctlrs; i++) {
    debug("Controller %d\n", i);
    for (j = 0; j < num_dimm; j++, addr_idx++) {
    debug("DIMM %d\n", j);
    addr = spd_addr[addr_idx];
    if (!addr) {
    if (!j) {
    ERROR("First SPD addr wrong.\n");
    return -EINVAL;
    }
    continue;
    }
    debug("addr 0x%x\n", addr);
    ret = read_spd(addr, &spd[spd_idx],
    sizeof(struct ddr4_spd));
    if (ret) { /* invalid */
    debug("Invalid SPD at address 0x%x\n", addr);
    continue;
    }

    spd_checksum[spd_idx] =
    (spd[spd_idx].crc[1] << 24) |
    (spd[spd_idx].crc[0] << 16) |
    (spd[spd_idx].mod_section.uc[127] << 8) |
    (spd[spd_idx].mod_section.uc[126] << 0);
    debug("checksum 0x%x\n", spd_checksum[spd_idx]);
    if (!spd_checksum[spd_idx]) {
    debug("Bad checksum, ignored.\n");
    continue;
    }
    if (!spd_idx) {
    /* first valid SPD */
    ret = cal_dimm_params(&spd[0], dimm);
    if (ret) {
    ERROR("SPD calculation error\n");
    return -EINVAL;
    }
    }

    if (spd_idx && spd_checksum[0] !=
    spd_checksum[spd_idx]) {
    ERROR("Not identical DIMMs.\n");
    return -EINVAL;
    }
    conf->dimm_in_use[j] = 1;
    valid_mask |= 1 << addr_idx;
    spd_idx = 1;
    }
    debug("done with controller %d\n", i);
    }
    switch (num_ctlrs) {
    case 1:
    if (!(valid_mask & 0x1)) {
    ERROR("First slot cannot be empty.\n");
    return -EINVAL;
    }
    break;
    case 2:
    switch (num_dimm) {
    case 1:
    if (!valid_mask) {
    ERROR("Both slot empty\n");
    i2c_bus_release(); // 这个地方
    soc_sys_reset();
    return -EINVAL;
    }
    break;
    case 2:
    if (valid_mask != 0x5 &&
    valid_mask != 0xf &&
    (valid_mask & 0x7) != 0x4 &&
    (valid_mask & 0xd) != 0x1) {
    ERROR("Invalid DIMM combination.\n");
    return -EINVAL;
    }
    break;
    default:
    ERROR("Invalid number of DIMMs.\n");
    return -EINVAL;
    }
    break;
    default:
    ERROR("Invalid number of controllers.\n");
    return -EINVAL;
    }
    /* now we have valid and identical DIMMs on controllers */
    #endif /* CONFIG_DDR_NODIMM */

    debug("cal cs\n");
    conf->cs_in_use = 0;
    for (j = 0; j < DDRC_NUM_DIMM; j++) {
    if (!conf->dimm_in_use[j])
    continue;
    switch (dimm->n_ranks) {
    case 4:
    ERROR("Quad-rank DIMM not supported\n");
    return -EINVAL;
    case 2:
    conf->cs_on_dimm[j] = 0x3 << (j * CONFIG_CS_PER_SLOT);
    conf->cs_in_use |= conf->cs_on_dimm[j];
    break;
    case 1:
    conf->cs_on_dimm[j] = 0x1 << (j * CONFIG_CS_PER_SLOT);
    conf->cs_in_use |= conf->cs_on_dimm[j];
    break;
    default:
    ERROR("SPD error with n_ranks\n");
    return -EINVAL;
    }
    debug("cs_in_use = %x\n", conf->cs_in_use);
    debug("cs_on_dimm[%d] = %x\n", j, conf->cs_on_dimm[j]);
    }
    #ifndef CONFIG_DDR_NODIMM
    if (priv->dimm.rdimm)
    NOTICE("RDIMM %s\n", priv->dimm.mpart);
    else
    NOTICE("UDIMM %s\n", priv->dimm.mpart);
    #else
    NOTICE("%s\n", priv->dimm.mpart);
    #endif

    return valid_mask;
    }

    // plat/nxp/soc-lx2160/lx2160a_dpn4025/ddr_init.c
    void soc_sys_reset(void)
    {
    *(int *)(NXP_RST_ADDR + RSTCNTL_OFFSET) = SW_RST_REQ_INIT;
    asm volatile("dc cvac,%0"
    :
    :"r"((unsigned long long)(NXP_RST_ADDR + RSTCNTL_OFFSET)) : );
    asm volatile("dsb st": : :);
    asm volatile("isb": : :);
    }
    /*
    * errata: a-010650
    */
    void i2c_bus_release(void)
    {
    uint reg_a;
    int i;
    //step 2
    ERROR("Step 1\n");
    reg_a = in_be32(0x700100134);
    ERROR("Step 2\n");
    //step 3
    out_be32(0x700100134, reg_a | 0x400);
    udelay(10);
    ERROR("Step 3\n");
    //step 4
    out_be32(0x2300000, 0x10000000);
    udelay(10);
    ERROR("Step 4\n");
    //step 5
    for (i = 0; i < 9; ++i) {
    out_be32(0x2300008, 0x10000000);
    udelay(10);
    out_be32(0x2300008, 0);
    udelay(10);
    }
    ERROR("Step 5\n");
    //step 6
    out8(0x2000002, 0);
    udelay(10);
    out8(0x2000002, 0x80);
    ERROR("Step 6\n");
    //step 7
    out32(0x700100134, 0);
    ERROR("Step 7\n");
    //step 8
    out8(0x2000003, in8(0x2000003) & 0xef);
    ERROR("Step 8\n");
    ERROR("DDR bus 0 released . reseting\n");
    }
    9 changes: 9 additions & 0 deletions log example.log
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,9 @@
    NOTICE: BL2: v1.5(release):LSDK-20.04-4-gdcfc62e80-dirty
    NOTICE: BL2: Built : 21:23:22, Apr 22 2022
    NOTICE: time base 7 ms
    NOTICE: BL2: v1.5(release):LSDK-20.04-4-gdcfc62e80-dirty
    NOTICE: BL2: Built : 21:23:22, Apr 22 2022
    NOTICE: time base 7 ms
    ERROR: Both slot empty
    ERROR: Step 1