MTK6573电源管理(PM)小结
繼續(xù)MTK平臺的研究
開始研究電源管理,因為PM永遠是嵌入式的核心技術(shù),所以靜下來走一遍流程。
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等等各種設(shè)備。
其中mt6573_power_management_init();初始化各種電源管理。下面是這個函數(shù)的源碼:
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;
??? }
}
從代碼中看是加載備用設(shè)備,但spar0 = 0所以后面的代碼應(yīng)該不會執(zhí)行了。這是我個人的觀點,希望有提出意見的。拋開這個問題可以看出主要是讀標(biāo)志位來給設(shè)的變量賦TURE or FALSE.
再看:mt6573_CG_init();
void mt6573_CG_init(void)
{
??? UINT32 u4Val;
??? struct cust_mt65xx_led *cust_led_list = get_cust_led_list();????????? //設(shè)置各種Led背光
??? set_clock_listen(TRUE);
??? DRV_SetReg32(APMCU_CG_CLR0, 0xffffffff);
??? ... ...
??? 后面設(shè)置一些設(shè)備模塊的時鐘
}
mt6573_chip_dep_init();? 設(shè)置芯片寄存器
。。。
重點看看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();
}
從代碼上看,當(dāng)睡眠有兩種電壓模式,一種是1.1V,還有一種是0.9V。依據(jù)芯片具體用哪種電壓模式,然后寫入寄存器。
再看: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,
};
即初始化這個數(shù)據(jù)結(jié)構(gòu)里的成員函數(shù)
其中重要的函數(shù)是
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);
}
這個函數(shù)是判斷機器是以何種方式喚醒的,比如:電源鍵,USB中斷,modem電話,時鐘等等。
函數(shù)?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,
};
總結(jié)
以上是生活随笔為你收集整理的MTK6573电源管理(PM)小结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 在Ubuntu上为Android系统编写
- 下一篇: MT6573驱动开发日志之touchpa