am335x 的MUSB控制器解读

2024-05-25 04:18
文章标签 解读 控制器 am335x musb

本文主要是介绍am335x 的MUSB控制器解读,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1.在board-am335xevm.c中有关于musb设备的定义

static struct omap_musb_board_data musb_board_data = {.interface_type = MUSB_INTERFACE_ULPI,/** mode[0:3] = USB0PORT's mode* mode[4:7] = USB1PORT's mode* AM335X beta EVM has USB0 in OTG mode and USB1 in host mode.*/// .mode = (MUSB_HOST << 4) | MUSB_OTG,.mode = (MUSB_HOST << 4) | MUSB_HOST,.power = 500,.instances = 1,};

然后对usb设备进行初始化

usb_musb_init(&musb_board_data);

该函数填充了设备名称name = "musb-ti81xx"

并且调用了omap_device_build();

进行USB设备注册

omap_device_buitd-->omap_device_build_ss()->omap_device_register(pdev)

2.ti81xx.c中有关于musb驱动的定义

static struct platform_driver ti81xx_musb_driver = {.remove = __exit_p(ti81xx_remove),.driver = {.name = "musb-ti81xx",.pm = DEV_PM_OPS,},};

以及一个函数指针操作集合

static struct musb_platform_ops ti81xx_ops = {.fifo_mode = 4,.flags = MUSB_GLUE_EP_ADDR_FLAT_MAPPING | MUSB_GLUE_DMA_CPPI41,.init = ti81xx_musb_init,.exit = ti81xx_musb_exit,.enable = ti81xx_musb_enable,.disable = ti81xx_musb_disable,.try_idle = ti81xx_musb_try_idle,.set_mode = ti81xx_musb_set_mode,.read_fifo = ti81xx_musb_read_fifo,.write_fifo = musb_write_fifo,.dma_controller_create = cppi41_dma_controller_create,.dma_controller_destroy = cppi41_dma_controller_destroy,.simulate_babble_intr = musb_simulate_babble,#ifdef CONFIG_USB_TI_CPPI41_DMA.txfifoempty_intr_enable = txfifoempty_intr_enable,.txfifoempty_intr_disable = txfifoempty_intr_disable,#endif.reinit = musb_reinit,.enable_sof = ti81xx_musb_enable_sof,.disable_sof = ti81xx_musb_disable_sof};

在ti81xx_glue_init(void)中填充probe函数到drv中

platform_driver_probe()-->drv->probe = probe-->platform_driver_register(drv)

3.ti81xx_probe()最后会调用ti81xx_create_musb_pdev()

这个函数有俩个变量较为重要

struct musb_hdrc_platform_data *pdata = dev->platform_data;struct platform_device *musb;

后面会为musb申请内存空间,以及填充内部数据结构需要注意的是操作函数集合的填充,就是上面我们定义的那些操作函数。pdata->platform_ops= &ti81xx_ops;后面会打印dev_info(dev, "musb%d, board_mode=0x%x, plat_mode=0x%x\n",id, bdata->mode, pdata->mode);就是我们在内核启动信息中看到的musb-ti81xx musb-ti81xx: musb0, board_mode=0x11, plat_mode=0x1,musb-ti81xx musb-ti81xx: musb1, board_mode=0x11, plat_mode=0x1。

最后调用 platform_device_add(musb)添加musb主控制器设备

4.在musb_core.c中会注册一个驱动

static struct platform_driver musb_driver = {.driver = {.name = (char *)musb_driver_name,.bus = &platform_bus_type,.owner = THIS_MODULE,.pm = MUSB_DEV_PM_OPS,},.probe = musb_probe,.remove = __exit_p(musb_remove),.shutdown = musb_shutdown,};static int __init musb_init(void){if (usb_disabled())return 0;pr_info("%s: version " MUSB_VERSION ", ""?dma?"", ""otg (peripheral+host)",musb_driver_name);return platform_driver_register(&musb_driver);}

在musb_init中会首先判断usb的使能,然后输出一条打印信息。就是我们在内核打印中看到的

musb-hdrc: version 6.0, ?dma?, otg (peripheral+host),接着调用 platform_driver_register注册驱动程序,在总线上寻找对应的设备,匹配成功后调用对应的probe函数 musb_probe(),在musb_probe函数中首先会对device的部分属性进行判断填充然后会调用musb_init_controller(dev, irq, base)初始化musb主控制器。

musb_init_controller(dev, irq, base)首先是内存申请,以及电源管理的配置,接着填充musb的各项属性,需要关注的是musb->ops = plat->platform_ops这句赋值。这里的的platform_ops就是我们之前在设备初始化那边传进来的static struct musb_platform_ops ti81xx_ops。后面会输出打印信息dev_info (dev, "dma type: %s\n", get_dma_name(musb))就是我们在内核打印信息中看到的musb-hdrc musb-hdrc.0: dma type: dma-cppi41。

下面是中断函数的填充musb->isr = generic_interrupt。我们找到该中断函数的定义,通过config配置可以发现这个函数其实指向了NULL。接着是status = musb_platform_init(musb)。我们直接查看该函数的原型

static inline int musb_platform_init(struct musb *musb){if (!musb->ops->init)return -EINVAL;return musb->ops->init(musb);}

该函数调用了设备的操作集合中的初始化函数,而我们知道这个集合就是 ti81xx_ops,在ti81xx_ops里找到init函数ti81xx_musb_init(struct musb *musb)。该函数中前面可以看到pr_info("MUSB%d controller's USBSS revision = %08x\n", musb->id, rev),也就是我们在内核打印信息中看到的MUSB0 controller's USBSS revision = 4ea20800。id是驱动传递过来的第一个MUSB传的是0,第二个人传的是1,revision是通过读取SOC寄存器得到的。经过一系列的寄存器设置我们可以看到 musb->isr = ti81xx_interrupt。这里musb的中断函数被正式绑定。接着是data->set_phy_power,我们在usb_musb_init()中设置board_data->set_phy_power = ti81xx_musb_phy_power,这里就会运行

ti81xx_musb_phy_power(),该函数中打印了内核信息host-only。后面musb_platform_set_mode()中会调用ti81xx_musb_set_mode。我们在musb_board_data中定义了俩路usb均为host这里就会被设置为host模式。紧接着是musb->txfifo_intr_enable的判断,我们不深入分析,由内核的打印信息TxFifo Empty intr disabled,可知这里txfifo_intr_enable是有值的。最后是我们的babble_ctrl判断。在 usb_musb_init()我们对这个值进行了赋值。我们不详细研究,只从musb0: Enabled SW babble control打印信息中可以推测出这个值部不为0.

现在我们回到musb_init_controller()中,现在我们知道status = musb_platform_init(musb)执行成功后,它发生的结果中包含了我们向musb绑定了一个中断函数。接着经过一系列设置我们运行了下面这个函数musb_core_init();该函数内打印了一些我们在内核中看到的信息musb-hdrc: ConfigData=0xde (UTMI-8, dyn FIFOs, bulk combine, bulk split, HB-ISO Rx, HB-ISO Tx, SoftConn)

musb-hdrc: MHDRC RTL version 2.0musb-hdrc: setup fifo_mode 4musb-hdrc: 28/31 max ep, 16384/16384 memorymusb-hdrc.0: bulk split disabledmusb-hdrc.0: bulk combine disabled。

里面主要涉及到的书mbus主控制器核心部分的初始化。

接着回到musb_init_controller()中,if (!is_otg_enabled(musb) && is_host_enabled(musb)),由于我们的设置这里判断条件成立,所以会运行status = usb_add_hcd(musb_to_hcd(musb), -1, 0)。注册我们的USB主机控制器。关于主机控制机hcd部分不详细说明,我们只注意到在这个函数中我们为USB主机控制器申请了数据缓存hcd_buffer_create(hcd),向USB总线驱动注册了USB主机控制器usb_register_bus(&hcd->self),并为USB主机控制器申请了内存usb_alloc_dev(NULL, &hcd->self, 0)。另外在刚进入usb_add_hcd()时,会打印hcd->product_desc。就是内核打印信息中的musb-hdrc musb-hdrc.0: MUSB HDRC host driver。它来自于musb_host.c中的const struct hc_driver musb_hc_driver 结构体中的product_desc,这里不详细说明。在执行usb_register_bus时会打印另一条信息dev_info (bus->controller, "new USB bus registered, assigned bus ""number %d\n", bus->busnum);就是我们在内核打印信息中看到的musb-hdrc musb-hdrc.0: new USB bus registered, assigned bus number 1。我们的USB主控制器有俩个所有busnum分别是1和2。这里打印的是第一个USB控制器加载的时候打印的信息。后面会调用retval = register_root_hub(hcd),root_hub的概念可以理解为与usb主机控制器绑定在一起的一种结构。他是该控制器控制的所有usb接口的源头。在register_root_hub中可以看到root_hub设备被真正注册的函数usb_new_device (usb_dev)。

从usb_add_hcd返回后,主机控制器就直接被USB总线识别(这里直接识别的原因还没有做详细分析),出现如下打印信息,这部分打印信息来自hub.c文件

usb usb2: New USB device found, idVendor=1d6b, idProduct=0002usb usb2: New USB device strings: Mfr=3, Product=2, SerialNumber=1usb usb2: Product: MUSB HDRC host driverusb usb2: Manufacturer: Linux 3.2.0-svn2045 musb-hcdusb usb2: SerialNumber: musb-hdrc.1hub 2-0:1.0: USB hub foundhub 2-0:1.0: 1 port detectedmusb_init_controller()再往下接着是有关于USB控制器的打印信息musb-hdrc musb-hdrc.1: USB Host mode controller at d083e800 using DMA, IRQ 19

5.设备如何被识别

usb_hub_init(void)-->hub_thread()-->hub_events()-->if (connect_change)-->hub_port_connect_change()

6.识别后要做那些事情

(1).usb_alloc_dev

(2).usb_set_device_state

这个函数用来设置设备的状态,struct usb_device 结

构体中,有一个成员,enum usb_device_state state,这一刻,会把这个设备的状态设置为

USB_STATE_POWERED,即上电状态.

(3).choose_devnum

为设备选择一个devnum,从1-128之间轮询选择

(4). hub_port_init

端口初始化,主要就是获取设备的描述符。该函数会输出打印信息dev_info(&udev->dev,"%s %s USB device number %d using %s\n",(udev->config) ? "reset" : "new", speed,devnum, udev->bus->controller->driver->name);也就是我们插入USB设备后在内核中看到的打印信息usb 2-1.1: new high-speed USB device number 3 using musb-hdrc。

(5).usb_get_status

(6).check_highspeed

如果设备当前是全速状态,但设备描述符中的bcdUSB有0200H(一个设备如果能够进行高速传输,那么它就应该在设备描述符里的bcdUSB 这一项写上0200H),且HUB口支持高速模式时,设备会检查自身是否支持高速运行,并切换到高速运行状态。

(7).usb_new_device

前半部分是和电源管理相关的部分然后是调用函数 usb_enumerate_device(udev)获取描述符枚举设备然后会调用announce_device(udev);打印调试信息,就是在插入USB设备时在内核空间看到的

usb 2-1.1: New USB device found, idVendor=14cd, idProduct=1212,usb 2-1.1: New USB device strings: Mfr=1, Product=3, SerialNumber=2最后调用device_add添加设备。这个函数执行后,系统里就真正有了这个设备,/sysfs 下面也能看到了,而且将会去遍历注册到usb 总线上的所有的驱动程序,如果找到合适的,就去调用该驱动的probe 函数

(8).hub_power_remaining

与电源管理相关的函数

7.关于hub_irq()

8.设备发现机制

 

 

 

 

 

 

 

这篇关于am335x 的MUSB控制器解读的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1000455

相关文章

MySQL中时区参数time_zone解读

《MySQL中时区参数time_zone解读》MySQL时区参数time_zone用于控制系统函数和字段的DEFAULTCURRENT_TIMESTAMP属性,修改时区可能会影响timestamp类型... 目录前言1.时区参数影响2.如何设置3.字段类型选择总结前言mysql 时区参数 time_zon

MySQL中的锁和MVCC机制解读

《MySQL中的锁和MVCC机制解读》MySQL事务、锁和MVCC机制是确保数据库操作原子性、一致性和隔离性的关键,事务必须遵循ACID原则,锁的类型包括表级锁、行级锁和意向锁,MVCC通过非锁定读和... 目录mysql的锁和MVCC机制事务的概念与ACID特性锁的类型及其工作机制锁的粒度与性能影响多版本

Redis过期键删除策略解读

《Redis过期键删除策略解读》Redis通过惰性删除策略和定期删除策略来管理过期键,惰性删除策略在键被访问时检查是否过期并删除,节省CPU开销但可能导致过期键滞留,定期删除策略定期扫描并删除过期键,... 目录1.Redis使用两种不同的策略来删除过期键,分别是惰性删除策略和定期删除策略1.1惰性删除策略

Redis与缓存解读

《Redis与缓存解读》文章介绍了Redis作为缓存层的优势和缺点,并分析了六种缓存更新策略,包括超时剔除、先删缓存再更新数据库、旁路缓存、先更新数据库再删缓存、先更新数据库再更新缓存、读写穿透和异步... 目录缓存缓存优缺点缓存更新策略超时剔除先删缓存再更新数据库旁路缓存(先更新数据库,再删缓存)先更新数

C#反射编程之GetConstructor()方法解读

《C#反射编程之GetConstructor()方法解读》C#中Type类的GetConstructor()方法用于获取指定类型的构造函数,该方法有多个重载版本,可以根据不同的参数获取不同特性的构造函... 目录C# GetConstructor()方法有4个重载以GetConstructor(Type[]

MCU7.keil中build产生的hex文件解读

1.hex文件大致解读 闲来无事,查看了MCU6.用keil新建项目的hex文件 用FlexHex打开 给我的第一印象是:经过软件的解释之后,发现这些数据排列地十分整齐 :02000F0080FE71:03000000020003F8:0C000300787FE4F6D8FD75810702000F3D:00000001FF 把解释后的数据当作十六进制来观察 1.每一行数据

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

Spring 源码解读:自定义实现Bean定义的注册与解析

引言 在Spring框架中,Bean的注册与解析是整个依赖注入流程的核心步骤。通过Bean定义,Spring容器知道如何创建、配置和管理每个Bean实例。本篇文章将通过实现一个简化版的Bean定义注册与解析机制,帮助你理解Spring框架背后的设计逻辑。我们还将对比Spring中的BeanDefinition和BeanDefinitionRegistry,以全面掌握Bean注册和解析的核心原理。

GPT系列之:GPT-1,GPT-2,GPT-3详细解读

一、GPT1 论文:Improving Language Understanding by Generative Pre-Training 链接:https://cdn.openai.com/research-covers/languageunsupervised/language_understanding_paper.pdf 启发点:生成loss和微调loss同时作用,让下游任务来适应预训

LLM系列 | 38:解读阿里开源语音多模态模型Qwen2-Audio

引言 模型概述 模型架构 训练方法 性能评估 实战演示 总结 引言 金山挂月窥禅径,沙鸟听经恋法门。 小伙伴们好,我是微信公众号《小窗幽记机器学习》的小编:卖铁观音的小男孩,今天这篇小作文主要是介绍阿里巴巴的语音多模态大模型Qwen2-Audio。近日,阿里巴巴Qwen团队发布了最新的大规模音频-语言模型Qwen2-Audio及其技术报告。该模型在音频理解和多模态交互