OSHW-DEIMOS/SOFTWARE/A64-TERES/linux-a64/drivers/soc/allwinner/pm/mem_timing.c
Dimitar Gamishev f9b0e7a283 linux
2017-10-13 14:07:04 +03:00

275 lines
5.5 KiB
C

#include "pm_types.h"
#include "./pm.h"
#include "./pm_i.h"
static __u32 cpu_freq = 0;
static __u32 overhead = 0;
static __u32 backup_perf_counter_ctrl_reg = 0;
static __u32 backup_perf_counter_enable_reg = 0;
static __u32 match_event_counter(enum counter_type_e type);
void init_perfcounters (__u32 do_reset, __u32 enable_divider)
{
// in general enable all counters (including cycle counter)
__u32 value = 1;
// peform reset:
if (do_reset)
{
value |= 2; // reset all counters to zero.
value |= 4; // reset cycle counter to zero.
}
if (enable_divider)
value |= 8; // enable "by 64" divider for CCNT.
value |= 16;
// program the performance-counter control-register:
asm volatile ("mcr p15, 0, %0, c9, c12, 0" : : "r"(value));
// enable all counters:
value = 0x8000000f;
asm volatile ("mcr p15, 0, %0, c9, c12, 1" : : "r"(value));
// clear overflows:
asm volatile ("MCR p15, 0, %0, c9, c12, 3" : : "r"(value));
asm volatile ("dsb");
asm volatile ("isb");
return;
}
void backup_perfcounter(void)
{
//backup performance-counter ctrl reg
asm volatile ("MRC p15, 0, %0, c9, c12, 0\t\n": "=r"(backup_perf_counter_ctrl_reg));
//backup enable reg
asm volatile ("MRC p15, 0, %0, c9, c12, 1\t\n": "=r"(backup_perf_counter_enable_reg));
}
void restore_perfcounter(void)
{
// restore performance-counter control-register:
asm volatile ("mcr p15, 0, %0, c9, c12, 0" : : "r"(backup_perf_counter_ctrl_reg));
// restore enable reg
asm volatile ("mcr p15, 0, %0, c9, c12, 1" : : "r"(backup_perf_counter_enable_reg));
}
__u32 get_cyclecount (void)
{
__u32 value;
// Read CCNT Register
asm volatile ("MRC p15, 0, %0, c9, c13, 0\t\n": "=r"(value));
return value;
}
void reset_counter(void)
{
__u32 value = 0;
asm volatile ("mrc p15, 0, %0, c9, c12, 0" : "=r"(value));
value |= 4; // reset cycle counter to zero.
// program the performance-counter control-register:
//__asm {MCR p15, 0, value, c9, c12, 0}
asm volatile ("mcr p15, 0, %0, c9, c12, 0" : : "r"(value));
}
void change_runtime_env(void)
{
__u32 start = 0;
__u32 end = 0;
//init counters:
//init_perfcounters (1, 0);
// measure the counting overhead:
start = get_cyclecount();
end = get_cyclecount();
overhead = (end >= start) ? (end-start) : (0xffffffff - start + end);
//busy_waiting();
cpu_freq = mem_clk_get_cpu_freq();
}
/*
* input para range: 1-1000 us, so the max us_cnt equal = 1008*1000;
*/
void delay_us(__u32 us)
{
__u32 us_cnt = 0;
__u32 cur = 0;
__u32 target = 0;
__u32 counter_enable = 0;
//__u32 cnt = 0;
if(cpu_freq > 1000){
us_cnt = ((raw_lib_udiv(cpu_freq, 1000)) + 1)*us;
}else{
//32 <--> 32k, 1cycle = 1s/32k =32us
goto out;
}
cur = get_cyclecount();
target = cur - overhead + us_cnt;
//judge whether counter is enable
asm volatile ("mrc p15, 0, %0, c9, c12, 1" :"=r"(counter_enable));
if( 0x8000000f != (counter_enable&0x8000000f) ){
init_perfcounters (1, 0);
}
#if 1
while(!counter_after_eq(cur, target)){
cur = get_cyclecount();
//cnt++;
}
#endif
#if 0
__s32 s_cur = 0;
__s32 s_target = 0;
__s32 result = 0;
s_cur = (__s32)(cur);
s_target = (__s32)(target);
result = s_cur - s_target;
if(s_cur - s_target >= 0){
cnt++;
}
while((typecheck(__u32, cur) && \
typecheck(__u32, target) && \
((__s32)(cur) - (__s32)(target) >= 0))){
s_cur = (__s32)(cur);
s_target = (__s32)(target);
if(s_cur - s_target >= 0){
cnt++;
}
cur = get_cyclecount();
}
#endif
//busy_waiting();
out:
asm("dmb");
asm("isb");
return;
}
//the overflow limit is: 0x7fff,ffff / 720M = 2982ms;
//each delay cycle can not exceed 10ms, in case of overflow.
void delay_ms(__u32 ms)
{
while(ms > 10){
delay_us(10*1000);
ms -= 10;
}
delay_us(ms*1000);
return;
}
/*============================================== event counter ==========================*/
static __u32 match_event_counter(enum counter_type_e type)
{
int cnter = 0;
switch(type){
case I_CACHE_MISS:
cnter = 0;
break;
case I_TLB_MISS:
cnter = 1;
break;
case D_CACHE_MISS:
cnter = 2;
break;
case D_TLB_MISS:
cnter = 3;
break;
default:
break;
}
return cnter;
}
void init_event_counter (__u32 do_reset, __u32 enable_divider)
{
// in general enable all counters (including cycle counter)
__u32 value = 1;
// peform reset:
if (do_reset)
{
value |= 2; // reset all counters to zero.
value |= 4; // reset cycle counter to zero.
}
if (enable_divider)
value |= 8; // enable "by 64" divider for CCNT.
value |= 16;
// program the performance-counter control-register:
asm volatile ("mcr p15, 0, %0, c9, c12, 0" : : "r"(value));
// enable all counters:
value = 0x8000000f;
asm volatile ("mcr p15, 0, %0, c9, c12, 1" : : "r"(value));
// clear overflows:
asm volatile ("MCR p15, 0, %0, c9, c12, 3" : : "r"(value));
return;
}
void set_event_counter(enum counter_type_e type)
{
__u32 cnter = 0;
cnter = match_event_counter(type);
//set counter selection reg
asm volatile ("MCR p15, 0, %0, c9, c12, 5" : : "r"(cnter));
//set event type
asm volatile ("MCR p15, 0, %0, c9, c13, 1" : : "r"(type));
asm volatile ("dsb");
asm volatile ("isb");
return;
}
int get_event_counter(enum counter_type_e type)
{
int cnter = 0;
int event_cnt = 0;
cnter = match_event_counter(type);
//set counter selection reg
asm volatile ("MCR p15, 0, %0, c9, c12, 5" : : "r"(cnter));
//read event counter
asm volatile ("MRC p15, 0, %0, c9, c13, 2\t\n": "=r"(event_cnt));
asm volatile ("dsb");
asm volatile ("isb");
return event_cnt;
}