`
mmdev
  • 浏览: 12956997 次
  • 性别: Icon_minigender_1
  • 来自: 大连
文章分类
社区版块
存档分类
最新评论

MTK6573电源管理(PM)小结

 
阅读更多

继续MTK平台的研究

开始研究电源管理,因为PM永远是嵌入式的核心技术,所以静下来走一遍流程。

MTK启动的过程:

硬件板载的启动入口为

static __init int board_init(void)
{
mt6573_power_management_init();
mt6573_board_init();
return 0;
}


其中mt6573_board_init();的作用如下:

mt6573_board_init() is used for chip-dependent code.
* It is suggested to put driver code in this function to do:
* 1). Capability structure of platform devices.
* 2). Define platform devices with their resources.
* 3). Register MT65XX platform devices.

即注册各种devices 如:&pmem_multimedia_device,&mt6573_device_uart[i],&AudDrv_device,&mt6573_nand_dev,&kpd_pdev等等各种设备。

其中mt6573_power_management_init();初始化各种电源管理。下面是这个函数的源码:

void mt6573_power_management_init(void)
{
/* Check Chip Version */
gChipVer = DRV_Reg32(APHW_VER);
printk("[%s]: gChipVer = 0x%x\r\n",__FUNCTION__, gChipVer);
/* Load DVFS, DCM Setting from Spare*/
mt6573_load_spare_settings();
/* Clock Gating init, gated un-necessary power*/
mt6573_CG_init();
/* Set specific chip setting*/
mt6573_chip_dep_init();
/* Power mamagement log init*/
mt6573_log_init();
/* DCM init*/
mt6573_dcm_init();
/* Thermal protect Init*/
hwThermalProtectInit();
/* Sleep Controller init*/
slp_mod_init();
}

首先看mt6573_load_spare_settings();

void mt6573_load_spare_settings(void)
{
u16 spar0;
spar0 = 0;
if (spar0 & SPARE_SECRET_KEY)
{
if(spar0 & SPARE_E1_PATCH)
gChipVer = CHIP_VER_E2;

if(spar0 & SPARE_DVFS_EN)
bCanEnDVFS = TRUE;
else
bCanEnDVFS = FALSE;

if(spar0 & SPARE_VAPROC_ADJUST_EN)
bBUCK_ADJUST = TRUE;
else
bBUCK_ADJUST = FALSE;

if(spar0 & SPARE_DVFS_LOG)
bEnDVFSLog = TRUE;
else
bEnDVFSLog = FALSE;
}
}
从代码中看是加载备用设备,但spar0 = 0所以后面的代码应该不会执行了。这是我个人的观点,希望有提出意见的。抛开这个问题可以看出主要是读标志位来给設的变量赋TURE or FALSE.

再看:mt6573_CG_init();

void mt6573_CG_init(void)
{
UINT32 u4Val;
struct cust_mt65xx_led *cust_led_list = get_cust_led_list(); //设置各种Led背光

set_clock_listen(TRUE);
DRV_SetReg32(APMCU_CG_CLR0, 0xffffffff);
... ...

后面设置一些设备模块的时钟
}

mt6573_chip_dep_init(); 设置芯片寄存器

。。。

重点看看sleep 控制器的初始化。

void slp_mod_init(void)
{
slp_pmu_init();

ost_mod_init();

suspend_set_ops(&slp_suspend_ops);

proc_create_data("slp_md_sta", 0444, NULL, &slp_md_sta_fops, NULL);
}

先看slp_pmu_init();

static void slp_pmu_init(void)
{
u16 con1;

#ifdef VCORE_1_1_V_IN_SLEEP
/* Vcore = 1.1V in sleep mode */
con1 = (slp_read16(VCORE_CON1) & 0xfe0f) | (28 << 4);
slp_write16(VCORE_CON1, con1);
#else
/* Vcore = 0.9V in sleep mode */
con1 = (slp_read16(VCORE_CON1) & 0xfe0f) | (20 << 4);
slp_write16(VCORE_CON1, con1);
#endif

/* Vaproc = 0.9V in sleep mode */
con1 = (slp_read16(VAPROC_CON1) & 0xfe0f) | (20 << 4);
slp_write16(VAPROC_CON1, con1);

/* clear CCI_SRCLKEN to enable HW sleep-mode control */
con1 = slp_read16(VA28_CON1) & ~(1U << 8);
slp_write16(VA28_CON1, con1);

slp_write_sync();
}
从代码上看,当睡眠有两种电压模式,一种是1.1V,还有一种是0.9V。依据芯片具体用哪种电压模式,然后写入寄存器。

再看:suspend_set_ops(&slp_suspend_ops);

void suspend_set_ops(struct platform_suspend_ops *ops)
{
mutex_lock(&pm_mutex);
suspend_ops = ops;
mutex_unlock(&pm_mutex);
}

所以就是给slp_suspend_ops赋值就可以拉:

static struct platform_suspend_ops slp_suspend_ops = {
.valid = slp_suspend_ops_valid,
.begin = slp_suspend_ops_begin,
.prepare = slp_suspend_ops_prepare,
.enter = slp_suspend_ops_enter,
.finish = slp_suspend_ops_finish,
.end = slp_suspend_ops_end,
};

即初始化这个数据结构里的成员函数

其中重要的函数是

static int slp_suspend_ops_enter(suspend_state_t state)
{
/* legacy log */
printk("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
printk("_Chip_pm_enter @@@@@@@@@@@@@@@@@@@@@@\n");
printk(" @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");

if (slp_dump_gpio)
gpio_dump_regs();

if (get_chip_eco_ver() == CHIP_E1) {
/* disable DCM to workaround EMI auto-refresh issue */
MT6573_DISABLE_HW_DCM_AP();
} else {
MT6573_ENABLE_HW_DCM_AP();
}

if (slp_dump_regs)
slp_dump_pm_regs();

rtc_disable_writeif();

slp_wake_reason = ost_go_to_sleep();

rtc_enable_writeif();

MT6573_DISABLE_HW_DCM_AP();

return 0;
}

wake_reason_t ost_go_to_sleep(void)
{
int i;
unsigned long flags;
struct mtk_irq_mask mask;
wake_reason_t wr;

spin_lock_irqsave(&ost_lock, flags);
for (i = 0; i < NUM_WAKE_SRC; i++) {
if (ost_wake_src & (1U << i))
ost_enable_wake_irq(ost_wake_irq[i], false);
}

mt6573_irq_mask_all(&mask);

ost_enable_wake_irq(MT6573_APOST_IRQ_LINE, true);

/* OST will periodically wake up */
wr = ost_enter_pwake_pause_mode();

mt6573_irq_mask_restore(&mask);
spin_unlock_irqrestore(&ost_lock, flags);

return wr;
}
static wake_reason_t __tcmfunc ost_enter_pwake_pause_mode(void)
{
u16 isr;
u32 ufn, wakesta;
unsigned long vbat, cnt = 0;

while (1) {
ufn = ost_get_wake_period(cnt) * 1000000 / OST_FRM_VAL;
ost_write32(OST_UFN, ufn);
ost_write32(OST_AFN, 0);

/* unmask wakeup sources */
ost_write32(OST_EVENT_MASK, ~ost_wake_src);

/* unmask Pause Interrupt, Pause Abort and UFN Timeout */
ost_write32(OST_INT_MASK, 0x0003);

ost_write16(OST_CON, OST_CON_UFN_DOWN | OST_CON_EN);
ost_write32(OST_CMD, OST_CMD_KEY | OST_CMD_CON_WR | OST_CMD_AFN_WR |
OST_CMD_UFN_WR | OST_CMD_OST_WR);
while (!(ost_read16(OST_STA) & OST_STA_CMD_CPL));

ost_write32(OST_CMD, OST_CMD_KEY | OST_CMD_PAUSE_STR);
while (!(ost_read16(OST_STA) & OST_STA_CMD_CPL));

/* flush L1 and L2 store buffers */
ost_write_sync();

/* enter WFI mode */
__asm__ __volatile__("mcr p15, 0, %0, c7, c0, 4" : : "r" (0));

wakesta = ost_read32(OST_WAKEUP_STA);
isr = ost_read16(OST_ISR);

ost_write32(OST_INT_MASK, 0x001f);
ost_write16(OST_ISR, 0x001f); /* write 1 clear */
ost_write_sync();

if (isr == 0x0004) { /* UFN Timeout */
vbat = BAT_Get_Battery_Voltage();
printk("vbat-%lu = %lu\n", ++cnt, vbat);
if (vbat <= SYSTEM_OFF_VOLTAGE) {
printk("low battery => wake up\n");
return WR_LOW_BAT;
}
} else {
ost_output_wake_reason(wakesta, isr);
return WR_WAKE_SRC;
}
}

return WR_NONE;
}
static void ost_output_wake_reason(u32 wakesta, u16 isr)
{
char str[128] = { 0 };

if (wakesta & WAKE_SRC_KP)
strcat(str, "KP ");

if (wakesta & WAKE_SRC_MSDC0)
strcat(str, "MSDC0 ");

if (wakesta & WAKE_SRC_EINT)
strcat(str, "EINT ");

if (wakesta & WAKE_SRC_RTC)
strcat(str, "RTC ");

if (wakesta & WAKE_SRC_CCIF_MD)
strcat(str, "CCIF_MD ");

printk("wake up by %s(0x%x)(0x%x)\n", str, wakesta, isr);
}

这个函数是判断机器是以何种方式唤醒的,比如:电源键,USB中断,modem电话,时钟等等。


函数proc_create_data("slp_md_sta", 0444, NULL, &slp_md_sta_fops, NULL);

static struct file_operations slp_md_sta_fops = {
.open = slp_md_sta_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};



分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics