2010年6月13日 星期日

power management 4 Linux

Propose : 在 low power design 上, "Power Management" 佔了很重要的地位. 利用 Power ON/OFF 來開關 Devices, 讓沒有在 work 的 devices 能進入 "Sleep" or "Shutdown" Mode... ,而這些判斷機制主要是透過上層的 software 演算法來決策. 因為過度的 ON/OFF 會消耗 "switch power", 讓電容不斷的 charge and discharge 導致不必要的 Power 消耗, 有時甚至比待機時候還來的耗電. 所以在 Power Management software design 上, 透過 control signal 打給底層的 hardware, 讓 hardware 有 state 上的變化, 再藉由每個不同的 state 來 define devices 的 on/off. Target : 用 c++ 來模擬 Power Management 的 hardware mode. 底下我們用 Linux 的 Power Management 來當例子. Ref: state define and detail info Linux power management other Refs : Android Power Management Power Planning power_man.h


#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <list>

using namespace std;

enum PWSTATE {
 PW_RUN  =0,
 PW_STANDBY =1,
 PW_SLEEP =2,
 PW_SHUTDOWN =3,
 PW_NOP  =4,
};

enum PWSWITCH {
 ON =0,
 OFF =1,
 SLEEP =2,
 LOW =3,
};

enum PWERROR {
 CUR2NXT_OK =0,
 CUR2NXT_ERR  =1,
 CUR2PUT_OK =2,
 CUR2PUT_ERR =3,
};

template<class T>
class Power_Man_IN {

public:
        T       ReBoot;
        T       Activity;
        T       InActivity;
        T       ShutDown;
        T       CLK;
 T Button;
};

template<class T>
class Power_Man_OT {

public:
       T   CPU;
       T   LCD;
       T   Keys;
       T   Audio;
}; 

class Power_Man {

public:  
  Power_Man_IN<int8_t> PW_MN_IN_Pt;
  Power_Man_OT<int8_t> PW_MN_OT_Pt;

  list<Power_Man_IN<int8_t> > TST_VEC_LIST;  
  
  int8_t Cur_ST;
  int8_t Nxt_ST;
 
  void SET2PW_MN_IN(int8_t r,int8_t a,int8_t i,int8_t s,int8_t c,int8_t b);
  void SET2PW_MN_OT(int8_t c,int8_t l,int8_t k,int8_t a);
  int8_t PRO2PW_MN();
  int8_t Put2OutREG();

  void DisPlaySET2PW_MN_IN();
  void DisPlaySET2PW_MN_OT();

//================================
// Test Bench 
//================================
  void SET_TEST_VECTOR(int8_t r,int8_t a,int8_t i,int8_t s,int8_t c,int8_t b);
  void SET_TEST_LIST();
};
power_man.cpp

 
//#include <systemc.h>
#include "power_man.h"

void Power_Man::SET_TEST_VECTOR(int8_t r,int8_t a,int8_t i,int8_t s,int8_t c,int8_t b){
  Power_Man_IN<int8_t> *VECPt = new Power_Man_IN<int8_t>;
    VECPt->ReBoot = r;
    VECPt->Activity = a;
    VECPt->InActivity = i;
    VECPt->ShutDown = s;
    VECPt->CLK  = c;
    VECPt->Button = b;
  
    TST_VEC_LIST.push_back(*VECPt);

  delete VECPt;
 }

//====================================
// Write your Test Bench here
//====================================
void Power_Man::SET_TEST_LIST(){

Cur_ST = PW_NOP;
Nxt_ST = PW_NOP;

SET_TEST_VECTOR(OFF, OFF, OFF, OFF, OFF, OFF);
// Set to  Run ST
SET_TEST_VECTOR(ON,  OFF, OFF, OFF, OFF, OFF);
SET_TEST_VECTOR(OFF, OFF, OFF, OFF, OFF, OFF);
SET_TEST_VECTOR(OFF, OFF, OFF, OFF, OFF, OFF);

// Set to STANDBY
SET_TEST_VECTOR(OFF, OFF, ON,  OFF, OFF, OFF);
SET_TEST_VECTOR(OFF, OFF, OFF, OFF, OFF, OFF);
SET_TEST_VECTOR(OFF, OFF, OFF, OFF, OFF, OFF);

}


void Power_Man::SET2PW_MN_IN(int8_t r,int8_t a,int8_t i,int8_t s,int8_t c,int8_t b){
 PW_MN_IN_Pt.ReBoot  = r;
 PW_MN_IN_Pt.Activity = a;
 PW_MN_IN_Pt.InActivity = i;
 PW_MN_IN_Pt.ShutDown = s;
 PW_MN_IN_Pt.CLK  = c;
 PW_MN_IN_Pt.Button = b;
}

void Power_Man::SET2PW_MN_OT(int8_t c,int8_t l,int8_t k,int8_t a){
 PW_MN_OT_Pt.CPU  = c;
 PW_MN_OT_Pt.LCD  = l;
 PW_MN_OT_Pt.Keys = k;
 PW_MN_OT_Pt.Audio = a;
}

int8_t Power_Man::PRO2PW_MN(){
 
 switch(Cur_ST){
 case PW_RUN : Nxt_ST = (PW_MN_IN_Pt.InActivity == ON )? PW_STANDBY  :
       (PW_MN_IN_Pt.ShutDown   == ON )? PW_SHUTDOWN : PW_RUN;       break;
 case PW_STANDBY : Nxt_ST = (PW_MN_IN_Pt.InActivity == ON )? PW_SLEEP    :
                                   (PW_MN_IN_Pt.Activity   == ON )? PW_RUN      : PW_STANDBY;   break; 
 case PW_SLEEP : Nxt_ST = (PW_MN_IN_Pt.Activity   == ON )? PW_RUN      : PW_SLEEP;     break;
 case PW_SHUTDOWN: Nxt_ST = (PW_MN_IN_Pt.Button     == ON )? PW_RUN      : PW_SHUTDOWN;  break;
 case PW_NOP : Nxt_ST = (PW_MN_IN_Pt.ReBoot     == ON )? PW_RUN      : PW_NOP; break;
 default:                return   CUR2NXT_ERR;  break;
        }
     
      Cur_ST = Nxt_ST;

 return CUR2NXT_OK;
}  

int8_t Power_Man::Put2OutREG(){
 switch(Cur_ST){
 case PW_RUN : SET2PW_MN_OT(ON,   ON,  ON,  ON ); break;
 case PW_STANDBY : SET2PW_MN_OT(LOW,  OFF, ON,  ON ); break;
 case PW_SLEEP : SET2PW_MN_OT(SLEEP,OFF, OFF, OFF); break;
 case PW_SHUTDOWN: SET2PW_MN_OT(SLEEP,OFF, OFF, OFF); break;
 case PW_NOP : SET2PW_MN_OT(OFF,  OFF, OFF, OFF); break;
 default:                       return  CUR2PUT_ERR; break;
 }

return CUR2PUT_OK;
}

void Power_Man::DisPlaySET2PW_MN_IN(){
int8_t r = PW_MN_IN_Pt.ReBoot;  
int8_t a = PW_MN_IN_Pt.Activity; 
int8_t i = PW_MN_IN_Pt.InActivity; 
int8_t s = PW_MN_IN_Pt.ShutDown; 
int8_t c = PW_MN_IN_Pt.CLK;
int8_t  b = PW_MN_IN_Pt.Button;

cout<<"CTL\t"<<"CLK:\t"<<int(c)<<"\tREBT:\t"<<int(r)<<"\tACT:\t"<<int(a)<<"\tINACT:\t"<<int(i)<<"\tSHTDN:\t"<<int(s)<<"\tBUTTON:\t"<<int(b)<<endl;  
}

void Power_Man::DisPlaySET2PW_MN_OT(){
int8_t c = PW_MN_OT_Pt.CPU;
int8_t l = PW_MN_OT_Pt.LCD;
int8_t k = PW_MN_OT_Pt.Keys;
int8_t a = PW_MN_OT_Pt.Audio;

cout<<"PUT\t"<<"CPU:\t"<<int(c)<<"\tLCD:\t"<<int(l)<<"\tKEYS:\t"<<int(k)<<"\tAUDIO:\t"<<int(a)<<endl;

}



int main() {

_List_iterator<Power_Man_IN<int8_t> > it;

Power_Man *PW_MN_Pt = new Power_Man;

PW_MN_Pt->SET_TEST_LIST();

for(it=PW_MN_Pt->TST_VEC_LIST.begin(); it!=PW_MN_Pt->TST_VEC_LIST.end(); it++){

if( PW_MN_Pt->Put2OutREG()!= CUR2PUT_OK ){
  cout<<"CUR2PUT Error"<<endl; return -1; }

  PW_MN_Pt->DisPlaySET2PW_MN_OT();
  
  int8_t r = it->ReBoot;
  int8_t a = it->Activity;
  int8_t i = it->InActivity;
  int8_t s = it->ShutDown;
  int8_t c = it->CLK;
  int8_t b = it->Button;

  PW_MN_Pt->SET2PW_MN_IN( r, a, i, s, c, b);
  PW_MN_Pt->DisPlaySET2PW_MN_IN();

if( PW_MN_Pt->PRO2PW_MN()!= CUR2NXT_OK ){
 cout<<"CUR2NXT Error"<<endl; return -1; }


}

delete PW_MN_Pt;

return 0;
}
Results: PUT CPU: 1 LCD: 1 KEYS: 1 AUDIO: 1 CTL CLK: 1 REBT: 1 ACT: 1 INACT: 1 SHTDN: 1 BUTTON: 1 PUT CPU: 1 LCD: 1 KEYS: 1 AUDIO: 1 CTL CLK: 1 REBT: 0 ACT: 1 INACT: 1 SHTDN: 1 BUTTON: 1 PUT CPU: 0 LCD: 0 KEYS: 0 AUDIO: 0 CTL CLK: 1 REBT: 1 ACT: 1 INACT: 1 SHTDN: 1 BUTTON: 1 PUT CPU: 0 LCD: 0 KEYS: 0 AUDIO: 0 CTL CLK: 1 REBT: 1 ACT: 1 INACT: 1 SHTDN: 1 BUTTON: 1 PUT CPU: 0 LCD: 0 KEYS: 0 AUDIO: 0 CTL CLK: 1 REBT: 1 ACT: 1 INACT: 0 SHTDN: 1 BUTTON: 1 PUT CPU: 3 LCD: 1 KEYS: 0 AUDIO: 0 PS:目前只有考慮 CPU, LCD, KEYS, AUDIO 的 control. 當然你也可以自己 define 所要 control 的 devices download : http://sites.google.com/site/funningboy/c/power_man.cpp?attredirects=0&d=1 http://sites.google.com/site/funningboy/c/power_man.h?attredirects=0&d=1

2 則留言:

  1. Essential Linux Device Drivers

    http://elinuxdd.com/~elinuxdd/elinuxdd.docs/sources.html

    回覆刪除
  2. ACPI

    http://www.acpica.org/download/acpica-reference.pdf

    回覆刪除