要搭建一个以zynq为核心的平台,必须要在zynq外部挂载一个flash设备,通常用到的flash设备主要有nor-flash、nand-flash、qspi-flash等等。对于qspi-flash,chip与cpu之间是通过SPI总线连接的,具体的驱动需要去了解spi总线驱动的框架;而nor-flash、nand-flash与cpu连接都是通过smc控制器来实现的,也就是说必须要利用smc控制器来实现对nor-flash和nand-flash的操作。

在这里,我们就一起了解下SMC控制器的驱动代码,关于nand-flash的驱动代码,将会在下一篇博客中仔细解读。

首先,你需要知道你所用的芯片集成的是哪个厂家的SMC控制器,这个可以通过查阅芯片手册就可以获知。因为CPU采用的是ZYNQ,所以查阅ug585就能知道zynq采用的是PL353 SMC控制器。那么接下来的工作就是去阅读内核中的pl35x-smc.c文件。

  • PL353 SMC 驱动程序

PL353 SMC 驱动程序位于drivers\memory中的pl35x-smc.c。结合我之前博客中写的如何看linux驱动程序的步骤,可以看到:

module_platform_driver(pl35x_smc_driver);            //平台总线注册了pl353_smc控制器的驱动

当设备树中的smc的硬件信息被使能后,就会调用pl35x-smc.c文件中的probe函数

static int pl35x_smc_probe(struct platform_device *pdev)
{struct pl35x_smc_data *pl35x_smc;struct device_node *child;struct resource *res;int err;struct device_node *of_node = pdev->dev.of_node;const struct of_device_id *matches = NULL;pl35x_smc = devm_kzalloc(&pdev->dev, sizeof(*pl35x_smc), GFP_KERNEL);        //分配一个pl35x_smc_data结构体空间if (!pl35x_smc)return -ENOMEM;/* Get the NAND controller virtual address */res = platform_get_resource(pdev, IORESOURCE_MEM, 0);        //获取设备树中的smc控制器的物理地址pl35x_smc_base = devm_ioremap_resource(&pdev->dev, res);        //地址映射if (IS_ERR(pl35x_smc_base))return PTR_ERR(pl35x_smc_base);pl35x_smc->aclk = devm_clk_get(&pdev->dev, "aclk");        //获取设备树中描述的aclk信息if (IS_ERR(pl35x_smc->aclk)) {dev_err(&pdev->dev, "aclk clock not found.\n");return PTR_ERR(pl35x_smc->aclk);}pl35x_smc->memclk = devm_clk_get(&pdev->dev, "memclk");        //获取设备树中描述的memclk信息if (IS_ERR(pl35x_smc->memclk)) {dev_err(&pdev->dev, "memclk clock not found.\n");return PTR_ERR(pl35x_smc->memclk);}err = clk_prepare_enable(pl35x_smc->aclk);        //配置aclkif (err) {dev_err(&pdev->dev, "Unable to enable AXI clock.\n");return err;}err = clk_prepare_enable(pl35x_smc->memclk);        //配置memclkif (err) {dev_err(&pdev->dev, "Unable to enable memory clock.\n");goto out_clk_dis_aper;}platform_set_drvdata(pdev, pl35x_smc);/* clear interrupts */                    //关闭中断使能writel(PL35X_SMC_CFG_CLR_DEFAULT_MASK,pl35x_smc_base + PL35X_SMC_CFG_CLR_OFFS);/* Find compatible children. Only a single child is supported *///对于设备树中smc根节点下的子节点,进行遍历扫描,来匹配对应的子节点驱动程序for_each_available_child_of_node(of_node, child) {if (of_match_node(matches_nand, child)) {    //如果子节点的compatible = "arm,pl353-nand-r2p1"pl35x_smc_init_nand_interface(pdev, child);            //则将smc配置为nand-flash接口if (!matches) {matches = matches_nand;} else {dev_err(&pdev->dev,"incompatible configuration\n");goto out_clk_disable;}}if (of_match_node(matches_nor, child)) {    //如果子节点的compatible = "cfi-flash"static int counts;if (!matches) {matches = matches_nor;} else {if (matches != matches_nor || counts > 1) {dev_err(&pdev->dev,"incompatible configuration\n");goto out_clk_disable;}}counts++;}}if (matches)        //如果匹配上,则从设备树获取数据来填充平台设备of_platform_populate(of_node, matches, NULL, &pdev->dev);        //如果子节点包含有conpatiable属性,则在此函数中向内核注册设备节点return 0;out_clk_disable:clk_disable_unprepare(pl35x_smc->memclk);
out_clk_dis_aper:clk_disable_unprepare(pl35x_smc->aclk);return err;
}

顺着刚才的代码逻辑,在probe函数中匹配子节点时,如果flash设备是nand-flash,则调用了pl35x_smc_init_nand_interface函数,那么再去看看这个函数都干啥了。

static void pl35x_smc_init_nand_interface(struct platform_device *pdev,struct device_node *nand_node)
{u32 t_rc, t_wc, t_rea, t_wp, t_clr, t_ar, t_rr;int err;unsigned long timeout = jiffies + PL35X_NAND_ECC_BUSY_TIMEOUT;/* nand-cycle-<X> property is refer to the NAND flash timing* mapping between dts and the NAND flash AC timing*  X  : AC timing name*  t0 : t_rc*  t1 : t_wc*  t2 : t_rea*  t3 : t_wp*  t4 : t_clr*  t5 : t_ar*  t6 : t_rr*/err = of_property_read_u32(nand_node, "arm,nand-cycle-t0", &t_rc);//获取子节点中arm,nand-cycle-t0属性if (err) {dev_warn(&pdev->dev, "arm,nand-cycle-t0 not in device tree");goto default_nand_timing;}err = of_property_read_u32(nand_node, "arm,nand-cycle-t1", &t_wc);//获取子节点中arm,nand-cycle-t1属性  if (err) {dev_warn(&pdev->dev, "arm,nand-cycle-t1 not in device tree");goto default_nand_timing;}err = of_property_read_u32(nand_node, "arm,nand-cycle-t2", &t_rea);//获取子节点中arm,nand-cycle-t2属性if (err) {dev_warn(&pdev->dev, "arm,nand-cycle-t2 not in device tree");goto default_nand_timing;}err = of_property_read_u32(nand_node, "arm,nand-cycle-t3", &t_wp);//获取子节点中arm,nand-cycle-t3属性if (err) {dev_warn(&pdev->dev, "arm,nand-cycle-t3 not in device tree");goto default_nand_timing;}err = of_property_read_u32(nand_node, "arm,nand-cycle-t4", &t_clr);//获取子节点中arm,nand-cycle-t4属性if (err) {dev_warn(&pdev->dev, "arm,nand-cycle-t4 not in device tree");goto default_nand_timing;}err = of_property_read_u32(nand_node, "arm,nand-cycle-t5", &t_ar);//获取子节点中arm,nand-cycle-t5属性if (err) {dev_warn(&pdev->dev, "arm,nand-cycle-t5 not in device tree");goto default_nand_timing;}err = of_property_read_u32(nand_node, "arm,nand-cycle-t6", &t_rr);//获取子节点中arm,nand-cycle-t6属性if (err) {dev_warn(&pdev->dev, "arm,nand-cycle-t6 not in device tree");goto default_nand_timing;}default_nand_timing:    //如果设备树中没有此属性,则配置为默认属性if (err) {/* set default NAND flash timing property */dev_warn(&pdev->dev, "Using default timing for");dev_warn(&pdev->dev, "2Gb Numonyx MT29F2G08ABAEAWP NAND flash");dev_warn(&pdev->dev, "t_wp, t_clr, t_ar are set to 2");dev_warn(&pdev->dev, "t_rc, t_wc, t_rr are set to 4");dev_warn(&pdev->dev, "t_rea is set to 1");t_rc = t_wc = t_rr = 4;t_rea = 1;t_wp = t_clr = t_ar = 2;}pl35x_smc_set_buswidth(PL35X_SMC_MEM_WIDTH_8);    //设置smc与nand-flash之间的带宽为8位/** Default assume 50MHz clock (20ns cycle time) and 3V operation* The SET_CYCLES_REG register value depends on the flash device.* Look in to the device datasheet and change its value, This value* is for 2Gb Numonyx flash.*/pl35x_smc_set_cycles(t_rc, t_wc, t_rea, t_wp, t_clr, t_ar, t_rr);//将内存时间参数写进寄存器writel(PL35X_SMC_CFG_CLR_INT_CLR_1,pl35x_smc_base + PL35X_SMC_CFG_CLR_OFFS);    //清中断writel(PL35X_SMC_DC_UPT_NAND_REGS, pl35x_smc_base +PL35X_SMC_DIRECT_CMD_OFFS);        //使能NAND-FLASH片选/* Wait till the ECC operation is complete */        //等待ECC检测do {if (pl35x_smc_ecc_is_busy_noirq())cpu_relax();elsebreak;} while (!time_after_eq(jiffies, timeout));if (time_after_eq(jiffies, timeout))dev_err(&pdev->dev, "nand ecc busy status timed out");/* Set the command1 and command2 register */writel(PL35X_NAND_ECC_CMD1,pl35x_smc_base + PL35X_SMC_ECC_MEMCMD1_OFFS);//使用NAND命令初始化写操作writel(PL35X_NAND_ECC_CMD2,pl35x_smc_base + PL35X_SMC_ECC_MEMCMD2_OFFS);
}

到此,smc控制器的驱动程序就结束了,显然,我们看到了SMC驱动程序中注册了驱动程序,并且在probe的最后调用of_platform_populate函数来进行设备文件的注册。在of_platform_populate函数中,需要判断子节点是否有compatible,如果没有compatible属性,则在此不创建设备文件。但如果有compatible属性,则创建相应的设备文件。显然,nand-flash设备树中子节点并没有compatible属性,因此必然需要在另外一个文件中进行设备文件的注册操作。这个文件就是drivers\mtd\nand中的pl35x_nand.c。关于nand-flash驱动框架可参照我的下一篇博客。

zynq-smc驱动框架解析相关推荐

  1. RT-Thread I/O设备模型及驱动框架解析(一)

    目录 1. 概述 2. 原理解析 3. 源码解析 3.1. 创建设备 3.2.  注册到驱动框架 3.3. 注册到IO设备管理器 4. 小结 1. 概述 本着由简入繁的原则,分析源码以STM32平台的 ...

  2. Linux内核(一) [ IMX RK ] TTY-UART驱动框架解析

    平台:NXP imx6ull 内核版本:4.1.15 文章目录 一.Linux TTY驱动框架 二.Linux Uart驱动框架 三.UART相关结构体uart_driver(UART驱动结构体) . ...

  3. RT-Thread | UART设备驱动框架解析

    1024G 嵌入式资源大放送!包括但不限于C/C++.单片机.Linux等.关注微信公众号[嵌入式大杂烩],回复1024,即可免费获取! UART简介 STM32 芯片具有多个 USART 外设用于串 ...

  4. Linux驱动框架之v4l2视频驱动框架解析

    1.简介 v4l2是专门为linux设备设计的一套视频框架,其主体框架在linux内核,可以理解为是整个 linux 系统上面的视频源捕获驱动框架.其广泛应用在嵌入式设备以及移动端.个人电脑设备上面, ...

  5. MTK平台TP驱动框架解析

    一,TP驱动代码的组成 MTK平台TP驱动主要包括两处文件: 1,kernel-3.18\drivers\input\touchscreen\mediatek\mtk_tpd.c 平台设备驱动,主要为 ...

  6. linux i2c核心,总线与设备驱动,Linux2.6.37 I2C驱动框架分析(一)

    最近工作中又使用到了I2C,所以借S3C2440开发板GT2440为硬件平台温习一遍I2C驱动体系. linux内核中IIC驱动的体系框架 linux内核中IIC部分驱动代码位于:/drivers/i ...

  7. Windows打印体系结构之打印驱动框架

    庐山烟雨浙江潮,未到千般恨不消.到得原来无别事,庐山烟雨浙江潮. 1.2.Windows打印驱动框架 Windows的打印驱动从总体架构上来说,包括一个渲染组件和一个配置组件.我们可以回想一下最开始的 ...

  8. Linux PCI驱动框架分析:(Peripheral Component Interconnect,外部设备互联)

    <DPDK 20.05 | rte_pci_bus思维导图 | 第一版> <linux系统下:IO端口,内存,PCI总线 的 读写(I/O)操作> <Linux指令:ls ...

  9. mmc驱动框架基础介绍

    mmc驱动框架基础介绍 本文主要介绍一下Linux内核的mmc子系统驱动的整体框架. (作者对SDIO设备不熟悉,所以不过多描述:鄙人才疏学浅,有不当之处,还请指教.) 大概包括以下几个部分: mmc ...

最新文章

  1. ipad html 自定义裁剪图片大小,移动端图片裁剪上传插件 Mavatar.js(原创)
  2. python 自己写个调试工具
  3. OpenCV Windows Pack but it has no binaries compatible with your configuratio
  4. java的AutoCloseable接口
  5. java+解析未知json_在Java中解析JSON时如何忽略未知属性– Jackson @JsonIgnoreProperties注释示例...
  6. HP5200打印机从控制面板手动配置TCP/IP 参数
  7. Android SharedPreferences最佳实践
  8. 从一盏路灯,看亿万级联接的智能之路
  9. Mac Android 查看dex文件内容
  10. Andriod获取本机ip地址
  11. Java如何从字符串中提取数字
  12. IE被劫持的手动解除
  13. Python - 爬虫 - 调用高德API案例
  14. 【android】项目案例(二)之京东客户端
  15. 测试过程中如何分析抓包工具抓的HTTP或TCP包
  16. MQTT协议之连接和心跳
  17. 大话数据结构二十二:图的存储结构之边集数组
  18. 欧姆龙自动化小型连接器端子台XW2K系列
  19. VSCode下载与安装使用教程【超详细讲解】
  20. 本科生毕业论文设计-论文总体-论文格式-查重经历

热门文章

  1. C#常用命名空间集合
  2. 魔兽争霸兵种相克表(终极研究)!!
  3. 台风怎么看内存颗粒_《CY》三星官网都没有的颗粒?三星T-DIE全网首测!
  4. Mac .rar文件默认用vlc打开??办它!
  5. 王者荣耀s15服务器维护,王者荣耀s15赛季更新全部内容
  6. 读大学的你,还在迷茫吗?快看看这些视频学习网站
  7. iOS开发-小白(新手)必看,基础常识
  8. 多商户商城系统功能拆解26讲-平台端分销设置
  9. 大众点评海底捞分店数据及评论数据
  10. GBase 8a服务监控