当前位置:   article > 正文

zync spi flash 频率配置_spi-max-frequency

spi-max-frequency

spi  flash的频率配置 代码流程及最终的频率值。

驱动目录

  基于4.14.55 内核,

 \drivers\spi\spi-dw-fmsh.c (控制器)
\drivers\spi\spi-dw.c
\drivers\mtd\devices\m25p80.c  (设备)

\drivers\spi\spi.c 

spi dts配置说明

  1. spi0: spi@e0001000 {
  2. compatible = "fmsh,dw-apb-ssi","snps,dw-apb-ssi";
  3. #address-cells = <1>;
  4. #size-cells = <0>;
  5. reg = <0xe0001000 0x1000>;
  6. interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
  7. num-cs = <3>;
  8. clocks = <&clkc NCLK_SPI0>, <&clkc NCLK_APB_SPI0>;
  9. clock-names = "clk_ref", "pclk";
  10. reg-io-width = <4>;
  11. spi-max-frequency = <1000000>;
  12. cs-gpios = <&portb 10 0>;
  13. status = "disabled";
  14. flash1@0 {
  15. compatible = "spi-flash","spansion,s25fl256s1", "jedec,spi-nor";
  16. reg = <0>;
  17. spi-max-frequency = <500000>;
  18. };
  19. spidev@1 {
  20. compatible = "spidev";
  21. spi-max-frequency = <20000000>;
  22. reg = <1>;
  23. };
  24. };
属性说明
cs-gpios 片选的配置。对于zync,其可能采用MIO或者EMIO,在设计时,vivado里面就配置好管脚

初始化流程

很多设备的套路都是先初始化控制器,然后再扫描控制器下的设备,对设备进行初始化。

初始化包括对硬件的初始化,以及根据硬件及DTS等配置初始化相关结构体,最终构成软件操作依赖。

控制器的初始化比较简单,只要明了驱动,进入probe就可以。

控制器

  probe探测

   

  1. static int dw_spi_fmsh_probe(struct platform_device *pdev)
  2. {
  3. struct dw_spi_mmio *dwsmmio;
  4. struct dw_spi *dws;
  5. struct resource *mem;
  6. int ret;
  7. dws->bus_num = pdev->id;
  8. //读取控制的输入频率,例如166M HZ
  9. dws->max_freq = clk_get_rate(dwsmmio->clk);
  10. ret = dw_spi_add_host(&pdev->dev, dws);
  11. if (ret)
  12. goto fail;
  13. printk("xiehj end: dw_spi_fmsh_probe\n");
  14. platform_set_drvdata(pdev, dwsmmio);
  15. return 0;
  16. fail:
  17. clk_disable_unprepare(dwsmmio->pclk);
  18. fail_pclk:
  19. clk_disable_unprepare(dwsmmio->clk);
  20. return ret;
  21. }

初始化

   如下将其配置为master,SPI 通信分为master  、slave。

  1. int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
  2. {
  3. struct spi_master *master;
  4. int ret;
  5. ret = request_irq(dws->irq, dw_spi_irq, IRQF_SHARED, dev_name(dev),
  6. master);
  7. if (ret < 0) {
  8. dev_err(dev, "can not get IRQ\n");
  9. goto err_free_master;
  10. }
  11. // 注册操作接口,这些操作接口在设备初始化时可能会回调,
  12. master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP;
  13. master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
  14. master->bus_num = dws->bus_num;
  15. master->num_chipselect = dws->num_cs;
  16. master->setup = dw_spi_setup;
  17. master->cleanup = dw_spi_cleanup;
  18. master->set_cs = dw_spi_set_cs;
  19. master->transfer_one = dw_spi_transfer_one;
  20. master->handle_err = dw_spi_handle_err;
  21. master->max_speed_hz = dws->max_freq; //master是控制器设备,设置为166M
  22. master->dev.of_node = dev->of_node;
  23. master->flags = SPI_MASTER_GPIO_SS;
  24. }

将控制器添加到设备后,后续芯片初始化时,命令的发送如何知道走整个控制器的相关接口的呢?此为通用的注册流程,即在下面的接口后,会进一步扫描DTS中的设备子节点,进而建立关联,此处非本文重点,感兴趣的自行阅读代码。套路都一样的。

ret = devm_spi_register_master(dev, master);

控制器的注册

  

  1. int spi_register_controller(struct spi_controller *ctlr)
  2. {
  3. struct device *dev = ctlr->dev.parent;
  4. struct boardinfo *bi;
  5. int status = -ENODEV;
  6. int id, first_dynamic;
  7. .......................省去一堆
  8. /* add statistics */
  9. spin_lock_init(&ctlr->statistics.lock);
  10. mutex_lock(&board_lock);
  11. list_add_tail(&ctlr->list, &spi_controller_list);
  12. list_for_each_entry(bi, &board_list, list)
  13. spi_match_controller_to_boardinfo(ctlr, &bi->board_info);
  14. mutex_unlock(&board_lock);
  15. /* Register devices from the device tree and ACPI */
  16. 这里注册SPI下挂的设备
  17. of_register_spi_devices(ctlr);
  18. acpi_register_spi_devices(ctlr);
  19. done:
  20. return status;
  21. }

解析设备树

获取设备树里面配置

  1. static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
  2. struct device_node *nc)
  3. {
  4. u32 value;
  5. int rc;
  6. /* Mode (clock phase/polarity/etc.) */
  7. /* Device speed */
  8. rc = of_property_read_u32(nc, "spi-max-frequency", &value);
  9. if (rc) {
  10. dev_err(&ctlr->dev,
  11. "%pOF has no valid 'spi-max-frequency' property (%d)\n", nc, rc);
  12. return rc;
  13. }
  14. //注意这里从DTS读出的值,翻到了spi_device中,也就是FLASH等端点设备中,也就是端点设备需要的速率。
  15. spi->max_speed_hz = value;
  16. return 0;
  17. }

 设备添加

  所谓的设备添加,即将控制器下面的设备添加到系统中,以便匹配后续的驱动。

  在此流程中,如果设备最大频率没有配置,则采用控制器的最大频率

  1. int spi_setup(struct spi_device *spi)
  2. {
  3. //如下判断是否需要采用控制器的最大频率
  4. if (!spi->max_speed_hz)
  5. spi->max_speed_hz = spi->controller->max_speed_hz;
  6. if (spi->controller->setup)
  7. status = spi->controller->setup(spi);
  8. spi_set_cs(spi, false);
  9. dev_dbg(&spi->dev, "setup mode %d, %s%s%s%s%u bits/w, %u Hz max --> %d\n",
  10. (int) (spi->mode & (SPI_CPOL | SPI_CPHA)),
  11. (spi->mode & SPI_CS_HIGH) ? "cs_high, " : "",
  12. (spi->mode & SPI_LSB_FIRST) ? "lsb, " : "",
  13. (spi->mode & SPI_3WIRE) ? "3wire, " : "",
  14. (spi->mode & SPI_LOOP) ? "loopback, " : "",
  15. spi->bits_per_word, spi->max_speed_hz,
  16. status);
  17. return status;
  18. }

设备初始化

   设备添加到系统后,就调用驱动

  1. /*
  2. * board specific setup should have ensured the SPI clock used here
  3. * matches what the READ command supports, at least until this driver
  4. * understands FAST_READ (for clocks over 25 MHz).
  5. */
  6. static int m25p_probe(struct spi_device *spi)
  7. {
  8. struct flash_platform_data *data;
  9. struct m25p *flash;
  10. struct spi_nor *nor;
  11. nor = &flash->spi_nor;
  12. /* install the hooks */
  13. nor->read = m25p80_read;
  14. nor->write = m25p80_write;
  15. nor->write_reg = m25p80_write_reg;
  16. nor->read_reg = m25p80_read_reg;
  17. nor->dev = &spi->dev;
  18. spi_nor_set_flash_node(nor, spi->dev.of_node);
  19. nor->priv = flash;
  20. spi_set_drvdata(spi, flash);
  21. flash->spi = spi;
  22. if (spi->mode & SPI_RX_QUAD) {
  23. hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4;
  24. if (spi->mode & SPI_TX_QUAD)
  25. hwcaps.mask |= (SNOR_HWCAPS_READ_1_4_4 |
  26. SNOR_HWCAPS_PP_1_1_4 |
  27. SNOR_HWCAPS_PP_1_4_4);
  28. } else if (spi->mode & SPI_RX_DUAL) {
  29. hwcaps.mask |= SNOR_HWCAPS_READ_1_1_2;
  30. if (spi->mode & SPI_TX_DUAL)
  31. hwcaps.mask |= SNOR_HWCAPS_READ_1_2_2;
  32. }
  33. if (data && data->name)
  34. nor->mtd.name = data->name;
  35. /* For some (historical?) reason many platforms provide two different
  36. * names in flash_platform_data: "name" and "type". Quite often name is
  37. * set to "m25p80" and then "type" provides a real chip name.
  38. * If that's the case, respect "type" and ignore a "name".
  39. */
  40. if (data && data->type)
  41. flash_name = data->type;
  42. else if (!strcmp(spi->modalias, "spi-nor"))
  43. flash_name = NULL; /* auto-detect */
  44. else
  45. flash_name = spi->modalias;
  46. ret = spi_nor_scan(nor, flash_name, &hwcaps);
  47. if (ret)
  48. return ret;
  49. return mtd_device_register(&nor->mtd, data ? data->parts : NULL,
  50. data ? data->nr_parts : 0);
  51. }

  提供: 

   1) flash 的读写接口,及寄存器读写接口。在通用的nor驱动里面回调这些接口。通用nor驱动主要对nor 命令进行封装。

   2) 扫描设备。在设备驱动中扫描设备逻辑存在问题。在控制器中扫描更合适。

   3) 将设备注册为MTD设备。

  这里只要兼容,jedec,spi-nor 都会进到这个驱动中。  

  1. static const struct of_device_id m25p_of_table[] = {
  2. /*
  3. * Generic compatibility for SPI NOR that can be identified by the
  4. * JEDEC READ ID opcode (0x9F). Use this, if possible.
  5. */
  6. { .compatible = "jedec,spi-nor" },
  7. {}
  8. };

读写flash的流程 

具体控制器的transfer接口

 SPI的频率设置在每次transfer时都会进行,因而需要关注此流程。从下面代码我们了解到

进行分频系数的设置,但是涉及到transfer->speed-hz

  1. static inline void spi_set_clk(struct dw_spi *dws, u16 div)
  2. {
  3. dw_writel(dws, DW_SPI_BAUDR, div);
  4. }
  5. static int dw_spi_transfer_one(struct spi_master *master,
  6. struct spi_device *spi, struct spi_transfer *transfer)
  7. {
  8. struct dw_spi *dws = spi_master_get_devdata(master);
  9. struct chip_data *chip = spi_get_ctldata(spi);
  10. u8 imask = 0;
  11. u16 txlevel = 0;
  12. u32 cr0;
  13. int ret;
  14. //在发送的时候,设置波特率的分频,每次都单打设置。
  15. /* Handle per transfer options for bpw and speed */
  16. if (transfer->speed_hz != dws->current_freq) {
  17. if (transfer->speed_hz != chip->speed_hz) {
  18. /* clk_div doesn't support odd number */
  19. chip->clk_div = (DIV_ROUND_UP(dws->max_freq, transfer->speed_hz) + 1) & 0xfffe;
  20. chip->speed_hz = transfer->speed_hz;
  21. }
  22. dws->current_freq = transfer->speed_hz;
  23. spi_set_clk(dws, chip->clk_div);
  24. }
  25. if (chip->poll_mode)
  26. return poll_transfer(dws);
  27. return 1;
  28. }

transfer speed hz

\drivers\spi\spi.c

__spi_sync ---》 status = __spi_validate(spi, message);

  1. static int __spi_validate(struct spi_device *spi, struct spi_message *message)
  2. {
  3. struct spi_controller *ctlr = spi->controller;
  4. struct spi_transfer *xfer;
  5. int w_size;
  6. if (!xfer->speed_hz)
  7. xfer->speed_hz = spi->max_speed_hz; //首先将xfer的频率设置为设备请求的最大频率
  8. if (!xfer->speed_hz)
  9. xfer->speed_hz = ctlr->max_speed_hz; //如果没有则设置控制器的最大频率
  10. if (ctlr->max_speed_hz && xfer->speed_hz > ctlr->max_speed_hz)
  11. xfer->speed_hz = ctlr->max_speed_hz;
  12. if (__spi_validate_bits_per_word(ctlr, xfer->bits_per_word))
  13. return -EINVAL;
  14. /*
  15. * SPI transfer length should be multiple of SPI word size
  16. * where SPI word size should be power-of-two multiple
  17. */
  18. if (xfer->bits_per_word <= 8)
  19. w_size = 1;
  20. else if (xfer->bits_per_word <= 16)
  21. w_size = 2;
  22. else
  23. w_size = 4;
  24. /* No partial transfers accepted */
  25. if (xfer->len % w_size)
  26. return -EINVAL;
  27. if (xfer->speed_hz && ctlr->min_speed_hz &&
  28. xfer->speed_hz < ctlr->min_speed_hz)
  29. return -EINVAL;
  30. if (xfer->tx_buf && !xfer->tx_nbits)
  31. xfer->tx_nbits = SPI_NBITS_SINGLE;
  32. if (xfer->rx_buf && !xfer->rx_nbits)
  33. xfer->rx_nbits = SPI_NBITS_SINGLE;
  34. /* check transfer tx/rx_nbits:
  35. * 1. check the value matches one of single, dual and quad
  36. * 2. check tx/rx_nbits match the mode in spi_device
  37. */
  38. if (xfer->tx_buf) {
  39. if (xfer->tx_nbits != SPI_NBITS_SINGLE &&
  40. xfer->tx_nbits != SPI_NBITS_DUAL &&
  41. xfer->tx_nbits != SPI_NBITS_QUAD)
  42. return -EINVAL;
  43. if ((xfer->tx_nbits == SPI_NBITS_DUAL) &&
  44. !(spi->mode & (SPI_TX_DUAL | SPI_TX_QUAD)))
  45. return -EINVAL;
  46. if ((xfer->tx_nbits == SPI_NBITS_QUAD) &&
  47. !(spi->mode & SPI_TX_QUAD))
  48. return -EINVAL;
  49. }
  50. /* check transfer rx_nbits */
  51. if (xfer->rx_buf) {
  52. if (xfer->rx_nbits != SPI_NBITS_SINGLE &&
  53. xfer->rx_nbits != SPI_NBITS_DUAL &&
  54. xfer->rx_nbits != SPI_NBITS_QUAD)
  55. return -EINVAL;
  56. if ((xfer->rx_nbits == SPI_NBITS_DUAL) &&
  57. !(spi->mode & (SPI_RX_DUAL | SPI_RX_QUAD)))
  58. return -EINVAL;
  59. if ((xfer->rx_nbits == SPI_NBITS_QUAD) &&
  60. !(spi->mode & SPI_RX_QUAD))
  61. return -EINVAL;
  62. }
  63. }
  64. message->status = -EINPROGRESS;
  65. return 0;
  66. }

频率配置总结

频率的来源

1) 控制器的时钟配置

2) DTS 中设备 频率字段的配置

真正工作频率

  在spi dw中,实际工作的频率计算公式为:

  chip->clk_div = (DIV_ROUND_UP(dws->max_freq, transfer->speed_hz) + 1) & 0xfffe;
            chip->speed_hz = transfer->speed_hz;

此处计算分频值,计算

DIV_ROUND_UP(A,B) = int( (A+B-1)/B ),

例如,max_freq =166M,  speed_hz配置为20M

则clk_div =(166.7+20-1)/20 +1= 9.285+1= 10也就是分频系数是10,此时设备期望的最大工作频率是20Mhz,实际工作为16.66MHZ=166.6/10

​​​​​​​

比如25M (166.7+24)/25=8.6 =8;  实际工作频率 166.7/8= 20.83Mhz

spi 信号在没有操作时,连时钟都没有输出,或者是由于这个流程。

问题分析

读取ID 失败

m25p80 spi2.0: unrecognized JEDEC id bytes: 00, 00, 00

偶尔能读出一次。

经分析,由于 spi控制器与设备间经过逻辑转换,导致CS信号没有到设备侧导致。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/712503
推荐阅读
相关标签
  

闽ICP备14008679号