您的位置:首页 > 产品设计 > 产品经理

MTK6573电源管理(PM)小结

2013-11-01 10:49 387 查看
继续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,

};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: