在分析完Voltage Domain和Power Domain之后,现在我们来分析Clock Domain。这是通过linux-3.8.1/arch/arm/mach-omap2/clockdomains33xx_data.c 中am33xx_clockdomains_init()实现的。
不过在进一步分析在之前,先来看Clock Domain的定义【来自AM335X TRM】:
这里的clockdomains_am33xx[]对应于【AM335X TRM 8.1.12 Clock Module Registers】中各个模块的XXX_ CLKSTCTRL寄存器(不全)。
现在从am33xx_clockdomains_init()中几个的函数开始分析Clock Domain管理的实现。首先是clkdm_register_platform_funcs(),这个函数由全局的static struct clkdm_ops *arch_clkdm来直接指向参数struct clkdm_ops *co。而这里的struct clkdm_ops定义如下:
其中前面的几个函数指针,是在Clock Domain之间存在依赖性时,通过结构体中的struct clkdm_dep *wkdep_srcs和struct clkdm_dep *sleepdep_srcs来建立起这种依赖性。
- Wake Up依赖:如果一个Clock Domain 2是Clock Domain 1的Wake Up依赖,则Clock Domain 2在Clock Domain 1的wkdep_srcs数组中,并且Clock Domain 2在Wake Up时,硬件会自动唤醒 Clock Domain 1。
- Sleep 依赖:如果一个Clock Domain 2是Clock Domain 1的Sleep依赖,则Clock Domain 2在Clock Domain 1的sleepdep_srcs数组中,并且Clock Domain 2在Active时,硬件会保证Clock Domain 1不会Sleep。
AM335X硬件不支持这种hardwired and software-programmable dependencies between the power domains特性,但是OMAP35XX支持这种特性,下面是从OMAP35XX PRCM文档中摘录的内容:
因此,OMAP35XX的struct clkdm_ops omap3_clkdm_operations就包含对这项依赖性的处理:
而这个clockdomains_omap3430会被omap3xxx_clockdomains_init()调用来注册OMAP35XX的Clock Domain:clkdm_register_clkdms(clockdomains_omap3430)。以MPU Domain为例,按照文档所说,在添加Wake Up依赖性时,应该同时处理PM_WKDEP_MPU和PM_MPUGRPSEL_PER 寄存器。然而实际的omap2_clkdm_add_wkdep()却只处理了PM_WKDEP_MPU(见linux-3.8.1/arch/arm/mach-omap2/prm2xxx_3xxx.c)。
然而在linux-3.8.1/drivers/staging/tidspbridge/core/tiomap3430.c中,却存在一个对硬编码的对PM_MPUGRPSEL_PER的处理。因此,这里应该还是设计得不够完善的地方。
而这里注册的实际struct clkdm_ops am33xx_clkdm_operations如下:
这里am33xx_clkdm_sleep()直接调用的am33xx_cm_clkdm_force_sleep()来强制使得该Clock Domain进入SLEEP模式。am33xx_clkdm_wakeup()的实现与此类似。
而am33xx_clkdm_allow_idle()直接调用am33xx_cm_clkdm_enable_hwsup()来使能hardware-supervised idle mode。而am33xx_clkdm_deny_idle()与之类似,调用am33xx_cm_clkdm_disable_hwsup()来禁止hardware-supervised idle mode,从而进入software-supervised idle mode。
那么什么是所谓的hardware-supervised idle mode呢?参见下面的介绍【来自OMAP35XX PRCM TRM】:
am33xx_clkdm_clk_enable()和am33xx_clkdm_clk_disable()是对am33xx_clkdm_wakeup()和am33xx_clkdm_sleep()的封装,实际根据是否允许软件来控制,来实现对它们的调用。