u-boot 设置qspi speed

sf probe



  do_spi_flash (cmd/sf.c)



    do_spi_flash_probe (cmd/sf.c)

      /* Remove the old device, otherwise probe will just be a nop */

      spi_find_bus_and_cs (spi-uclass.c)



        uclass_find_device_by_seq   (drivers/core/uclasee.c)//寻找spi总线设备(SPI控制器) 没有probe

        //ret = uclass_find_device_by_seq(UCLASS_SPI, busnum, false, &bus);

        spi_find_chip_select  (drivers/spi/spi-uclass.c)//在SPI总线设备下找到FLASH设备



      spi_flash_probe_bus_cs(driver/mtd/spi/sf-uclass.c)



        spi_get_bus_and_cs  (drivers/spi/spi-uclass.c)

        /*ret = spi_get_bus_and_cs(busnum, cs, max_hz, spi_mode,
                  "spi_flash_std", str, &bus, &slave); 这里直接指定了driver name*/


          uclass_get_device_by_seq(UCLASS_SPI, busnum, &bus); //UCLASS_SPI cadence_spi_probe

 //driver/core/device.c 的device_probe

//ret = drv->ofdata_to_platdata(dev);

//ret = drv->probe(dev); 会读到设备树里的spi-max-frequency=50MHz 

//plat->max_hz = fdtdec_get_uint(blob, subnode, "spi-max-frequency",500000);

 

          spi_find_chip_select(bus, cs, &dev);

          if (ret == -ENODEV && drv_name) 

            ret = device_bind_driver(bus, drv_name, dev_name, &dev);



          device_probe (qspi flash颗粒 激活)

plat = dev_get_parent_platdata(dev);
if (!speed) {
speed = plat->max_hz; //speed=50MHz
mode = plat->mode;
}

ret = spi_set_speed_mode(bus, speed, mode); 传入50M

if (ops->set_speed)
ret = ops->set_speed(bus, speed);

调用cadence_spi_set_speed 传入50MHz

static int cadence_spi_set_speed(struct udevice *bus, uint hz)
{
    struct cadence_spi_platdata *plat = bus->platdata;
    struct cadence_spi_priv *priv = dev_get_priv(bus);
    int err;

    if (hz > plat->max_hz)
        hz = plat->max_hz;

    /* Disable QSPI */
    cadence_qspi_apb_controller_disable(priv->regbase);

    /*
     * Calibration required for different current SCLK speed, requested
     * SCLK speed or chip select
     */
    if (priv->previous_hz != hz ||
        priv->qspi_calibrated_hz != hz ||
        priv->qspi_calibrated_cs != spi_chip_select(bus)) {
        err = spi_calibration(bus, hz);//50MHz
        if (err)
            return err;

        /* prevent calibration run when same as previous request */
        priv->previous_hz = hz;
    }
/* Calibration sequence to determine the read data capture delay register */
static int spi_calibration(struct udevice *bus, uint hz)
{
    struct cadence_spi_priv *priv = dev_get_priv(bus);
    void *base = priv->regbase;
    u8 opcode_rdid = 0x9F;
    unsigned int idcode = 0, temp = 0;
    int err = 0, i, range_lo = -1, range_hi = -1;

    /* start with slowest clock (1 MHz) */
    cadence_spi_write_speed(bus, 1000000);

    /* configure the read data capture delay register to 0 */
    cadence_qspi_apb_readdata_capture(base, 1, 0);

    /* Enable QSPI */
    cadence_qspi_apb_controller_enable(base);

    /* read the ID which will be our golden value */
    err = cadence_qspi_apb_command_read(base, 1, &opcode_rdid,
        3, (u8 *)&idcode);
    if (err) {
        puts("SF: Calibration failed (read)
");
        return err;
    }

    /* use back the intended clock and find low range */
    cadence_spi_write_speed(bus, hz);//50MHz
    for (i = 0; i < CQSPI_READ_CAPTURE_MAX_DELAY; i++) {
        /* Disable QSPI */
        cadence_qspi_apb_controller_disable(base);

        /* reconfigure the read data capture delay register */
        cadence_qspi_apb_readdata_capture(base, 1, i);

        /* Enable back QSPI */
        cadence_qspi_apb_controller_enable(base);

        /* issue a RDID to get the ID value */
        err = cadence_qspi_apb_command_read(base, 1, &opcode_rdid,
            3, (u8 *)&temp);
        if (err) {
            puts("SF: Calibration failed (read)
");
            return err;
        }

        /* search for range lo */
        if (range_lo == -1 && temp == idcode) {
            range_lo = i;
            continue;
        }

        /* search for range hi */
        if (range_lo != -1 && temp != idcode) {
            range_hi = i - 1;
            break;
        }
        range_hi = i;
    }

    if (range_lo == -1) {
        puts("SF: Calibration failed (low range)
");
        return err;
    }

    /* Disable QSPI for subsequent initialization */
    cadence_qspi_apb_controller_disable(base);

    /* configure the final value for read data capture delay register */
    cadence_qspi_apb_readdata_capture(base, 1, (range_hi + range_lo) / 2);
    debug("SF: Read data capture delay calibrated to %i (%i - %i)
",
          (range_hi + range_lo) / 2, range_lo, range_hi);

    /* just to ensure we do once only when speed or chip select change */
    priv->qspi_calibrated_hz = hz;
    priv->qspi_calibrated_cs = spi_chip_select(bus);

    return 0;
}
static int cadence_spi_write_speed(struct udevice *bus, uint hz)
{
    struct cadence_spi_platdata *plat = bus->platdata;
    struct cadence_spi_priv *priv = dev_get_priv(bus);

    cadence_qspi_apb_config_baudrate_div(priv->regbase,
                         CONFIG_CQSPI_REF_CLK, hz);//算分频系数

    /* Reconfigure delay timing if speed is changed. */
    cadence_qspi_apb_delay(priv->regbase, CONFIG_CQSPI_REF_CLK, hz,
                   plat->tshsl_ns, plat->tsd2d_ns,
                   plat->tchsh_ns, plat->tslch_ns);

    return 0;
}
原文地址:https://www.cnblogs.com/idyllcheung/p/14063639.html