mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 10:41:38 -04:00
PM / devfreq: bw_hwmon: Add support for BWMON5 monitors
Add support for the fifth type of bandwidth monitor. This monitor is similar to the other types of monitors, but the register offset is slightly different, and it doesn't have a global interrupt base. Change-Id: Ib05602832b6d4712b783ebaaa5aae9e60c00e30b Signed-off-by: Stephen Boyd <[email protected]> [[email protected]: made minor styling changes] Signed-off-by: Amir Vajid <[email protected]>
This commit is contained in:
parent
77d4c0bb9c
commit
0dd9e33079
1 changed files with 269 additions and 65 deletions
|
|
@ -24,8 +24,12 @@
|
|||
#define GLB_INT_CLR(m) ((m)->global_base + 0x108)
|
||||
#define GLB_INT_EN(m) ((m)->global_base + 0x10C)
|
||||
#define MON_INT_STATUS(m) ((m)->base + 0x100)
|
||||
#define MON_INT_STATUS_MASK 0x03
|
||||
#define MON2_INT_STATUS_MASK 0xF0
|
||||
#define MON2_INT_STATUS_SHIFT 4
|
||||
#define MON_INT_CLR(m) ((m)->base + 0x108)
|
||||
#define MON_INT_EN(m) ((m)->base + 0x10C)
|
||||
#define MON_INT_ENABLE 0x1
|
||||
#define MON_EN(m) ((m)->base + 0x280)
|
||||
#define MON_CLEAR(m) ((m)->base + 0x284)
|
||||
#define MON_CNT(m) ((m)->base + 0x288)
|
||||
|
|
@ -46,9 +50,27 @@
|
|||
#define MON2_ZONE_CNT(m) ((m)->base + 0x2D8)
|
||||
#define MON2_ZONE_MAX(m, zone) ((m)->base + 0x2E0 + 0x4 * zone)
|
||||
|
||||
#define MON3_INT_STATUS(m) ((m)->base + 0x00)
|
||||
#define MON3_INT_CLR(m) ((m)->base + 0x08)
|
||||
#define MON3_INT_EN(m) ((m)->base + 0x0C)
|
||||
#define MON3_INT_STATUS_MASK 0x0F
|
||||
#define MON3_EN(m) ((m)->base + 0x10)
|
||||
#define MON3_CLEAR(m) ((m)->base + 0x14)
|
||||
#define MON3_SW(m) ((m)->base + 0x20)
|
||||
#define MON3_THRES_HI(m) ((m)->base + 0x24)
|
||||
#define MON3_THRES_MED(m) ((m)->base + 0x28)
|
||||
#define MON3_THRES_LO(m) ((m)->base + 0x2C)
|
||||
#define MON3_ZONE_ACTIONS(m) ((m)->base + 0x30)
|
||||
#define MON3_ZONE_CNT_THRES(m) ((m)->base + 0x34)
|
||||
#define MON3_BYTE_CNT(m) ((m)->base + 0x38)
|
||||
#define MON3_WIN_TIMER(m) ((m)->base + 0x3C)
|
||||
#define MON3_ZONE_CNT(m) ((m)->base + 0x40)
|
||||
#define MON3_ZONE_MAX(m, zone) ((m)->base + 0x44 + 0x4 * zone)
|
||||
|
||||
enum mon_reg_type {
|
||||
MON1,
|
||||
MON2,
|
||||
MON3,
|
||||
};
|
||||
|
||||
struct bwmon_spec {
|
||||
|
|
@ -56,6 +78,8 @@ struct bwmon_spec {
|
|||
bool overflow;
|
||||
bool throt_adj;
|
||||
bool hw_sampling;
|
||||
bool has_global_base;
|
||||
enum mon_reg_type reg_type;
|
||||
};
|
||||
|
||||
struct bwmon {
|
||||
|
|
@ -77,9 +101,6 @@ struct bwmon {
|
|||
#define ENABLE_MASK BIT(0)
|
||||
#define THROTTLE_MASK 0x1F
|
||||
#define THROTTLE_SHIFT 16
|
||||
#define INT_ENABLE_V1 0x1
|
||||
#define INT_STATUS_MASK 0x03
|
||||
#define INT_STATUS_MASK_HWS 0xF0
|
||||
|
||||
static DEFINE_SPINLOCK(glb_lock);
|
||||
|
||||
|
|
@ -92,6 +113,9 @@ static __always_inline void mon_enable(struct bwmon *m, enum mon_reg_type type)
|
|||
case MON2:
|
||||
writel_relaxed(ENABLE_MASK | m->throttle_adj, MON2_EN(m));
|
||||
break;
|
||||
case MON3:
|
||||
writel_relaxed(ENABLE_MASK | m->throttle_adj, MON3_EN(m));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -104,6 +128,9 @@ static __always_inline void mon_disable(struct bwmon *m, enum mon_reg_type type)
|
|||
case MON2:
|
||||
writel_relaxed(m->throttle_adj, MON2_EN(m));
|
||||
break;
|
||||
case MON3:
|
||||
writel_relaxed(m->throttle_adj, MON3_EN(m));
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* mon_disable() and mon_irq_clear(),
|
||||
|
|
@ -128,6 +155,12 @@ void mon_clear(struct bwmon *m, bool clear_all, enum mon_reg_type type)
|
|||
else
|
||||
writel_relaxed(MON_CLEAR_BIT, MON2_CLEAR(m));
|
||||
break;
|
||||
case MON3:
|
||||
if (clear_all)
|
||||
writel_relaxed(MON_CLEAR_ALL_BIT, MON3_CLEAR(m));
|
||||
else
|
||||
writel_relaxed(MON_CLEAR_BIT, MON3_CLEAR(m));
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* The counter clear and IRQ clear bits are not in the same 4KB
|
||||
|
|
@ -138,7 +171,9 @@ void mon_clear(struct bwmon *m, bool clear_all, enum mon_reg_type type)
|
|||
}
|
||||
|
||||
#define SAMPLE_WIN_LIM 0xFFFFF
|
||||
static void mon_set_hw_sampling_window(struct bwmon *m, unsigned int sample_ms)
|
||||
static __always_inline
|
||||
void mon_set_hw_sampling_window(struct bwmon *m, unsigned int sample_ms,
|
||||
enum mon_reg_type type)
|
||||
{
|
||||
u32 rate;
|
||||
|
||||
|
|
@ -150,7 +185,17 @@ static void mon_set_hw_sampling_window(struct bwmon *m, unsigned int sample_ms)
|
|||
pr_warn("Sample window %u larger than hw limit: %u\n",
|
||||
rate, SAMPLE_WIN_LIM);
|
||||
}
|
||||
writel_relaxed(rate, MON2_SW(m));
|
||||
switch (type) {
|
||||
case MON1:
|
||||
WARN(1, "Invalid\n");
|
||||
return;
|
||||
case MON2:
|
||||
writel_relaxed(rate, MON2_SW(m));
|
||||
break;
|
||||
case MON3:
|
||||
writel_relaxed(rate, MON3_SW(m));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -173,15 +218,20 @@ void mon_irq_enable(struct bwmon *m, enum mon_reg_type type)
|
|||
case MON1:
|
||||
mon_glb_irq_enable(m);
|
||||
val = readl_relaxed(MON_INT_EN(m));
|
||||
val |= INT_ENABLE_V1;
|
||||
val |= MON_INT_ENABLE;
|
||||
writel_relaxed(val, MON_INT_EN(m));
|
||||
break;
|
||||
case MON2:
|
||||
mon_glb_irq_enable(m);
|
||||
val = readl_relaxed(MON_INT_EN(m));
|
||||
val |= INT_STATUS_MASK_HWS;
|
||||
val |= MON2_INT_STATUS_MASK;
|
||||
writel_relaxed(val, MON_INT_EN(m));
|
||||
break;
|
||||
case MON3:
|
||||
val = readl_relaxed(MON3_INT_EN(m));
|
||||
val |= MON3_INT_STATUS_MASK;
|
||||
writel_relaxed(val, MON3_INT_EN(m));
|
||||
break;
|
||||
}
|
||||
spin_unlock(&glb_lock);
|
||||
/*
|
||||
|
|
@ -211,15 +261,20 @@ void mon_irq_disable(struct bwmon *m, enum mon_reg_type type)
|
|||
case MON1:
|
||||
mon_glb_irq_disable(m);
|
||||
val = readl_relaxed(MON_INT_EN(m));
|
||||
val &= ~INT_ENABLE_V1;
|
||||
val &= ~MON_INT_ENABLE;
|
||||
writel_relaxed(val, MON_INT_EN(m));
|
||||
break;
|
||||
case MON2:
|
||||
mon_glb_irq_disable(m);
|
||||
val = readl_relaxed(MON_INT_EN(m));
|
||||
val &= ~INT_STATUS_MASK_HWS;
|
||||
val &= ~MON2_INT_STATUS_MASK;
|
||||
writel_relaxed(val, MON_INT_EN(m));
|
||||
break;
|
||||
case MON3:
|
||||
val = readl_relaxed(MON3_INT_EN(m));
|
||||
val &= ~MON3_INT_STATUS_MASK;
|
||||
writel_relaxed(val, MON3_INT_EN(m));
|
||||
break;
|
||||
}
|
||||
spin_unlock(&glb_lock);
|
||||
/*
|
||||
|
|
@ -239,13 +294,19 @@ unsigned int mon_irq_status(struct bwmon *m, enum mon_reg_type type)
|
|||
mval = readl_relaxed(MON_INT_STATUS(m));
|
||||
dev_dbg(m->dev, "IRQ status p:%x, g:%x\n", mval,
|
||||
readl_relaxed(GLB_INT_STATUS(m)));
|
||||
mval &= INT_STATUS_MASK;
|
||||
mval &= MON_INT_STATUS_MASK;
|
||||
break;
|
||||
case MON2:
|
||||
mval = readl_relaxed(MON_INT_STATUS(m));
|
||||
dev_dbg(m->dev, "IRQ status p:%x, g:%x\n", mval,
|
||||
readl_relaxed(GLB_INT_STATUS(m)));
|
||||
mval &= INT_STATUS_MASK_HWS;
|
||||
mval &= MON2_INT_STATUS_MASK;
|
||||
mval >>= MON2_INT_STATUS_SHIFT;
|
||||
break;
|
||||
case MON3:
|
||||
mval = readl_relaxed(MON3_INT_STATUS(m));
|
||||
dev_dbg(m->dev, "IRQ status p:%x\n", mval);
|
||||
mval &= MON3_INT_STATUS_MASK;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -279,13 +340,16 @@ void mon_irq_clear(struct bwmon *m, enum mon_reg_type type)
|
|||
{
|
||||
switch (type) {
|
||||
case MON1:
|
||||
writel_relaxed(INT_STATUS_MASK, MON_INT_CLR(m));
|
||||
writel_relaxed(MON_INT_STATUS_MASK, MON_INT_CLR(m));
|
||||
mon_glb_irq_clear(m);
|
||||
break;
|
||||
case MON2:
|
||||
writel_relaxed(INT_STATUS_MASK_HWS, MON_INT_CLR(m));
|
||||
writel_relaxed(MON2_INT_STATUS_MASK, MON_INT_CLR(m));
|
||||
mon_glb_irq_clear(m);
|
||||
break;
|
||||
case MON3:
|
||||
writel_relaxed(MON3_INT_STATUS_MASK, MON3_INT_CLR(m));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -357,10 +421,13 @@ static unsigned int mbps_to_mb(unsigned long mbps, unsigned int ms)
|
|||
* Zone 3: byte count > THRES_HI
|
||||
*/
|
||||
#define THRES_LIM 0x7FFU
|
||||
static void set_zone_thres(struct bwmon *m, unsigned int sample_ms)
|
||||
static __always_inline
|
||||
void set_zone_thres(struct bwmon *m, unsigned int sample_ms,
|
||||
enum mon_reg_type type)
|
||||
{
|
||||
struct bw_hwmon *hw = &(m->hw);
|
||||
struct bw_hwmon *hw = &m->hw;
|
||||
u32 hi, med, lo;
|
||||
u32 zone_cnt_thres = calc_zone_counts(hw);
|
||||
|
||||
hi = mbps_to_mb(hw->up_wake_mbps, sample_ms);
|
||||
med = mbps_to_mb(hw->down_wake_mbps, sample_ms);
|
||||
|
|
@ -374,23 +441,36 @@ static void set_zone_thres(struct bwmon *m, unsigned int sample_ms)
|
|||
lo = min(lo, med-1);
|
||||
}
|
||||
|
||||
writel_relaxed(hi, MON2_THRES_HI(m));
|
||||
writel_relaxed(med, MON2_THRES_MED(m));
|
||||
writel_relaxed(lo, MON2_THRES_LO(m));
|
||||
switch (type) {
|
||||
case MON1:
|
||||
WARN(1, "Invalid\n");
|
||||
return;
|
||||
case MON2:
|
||||
writel_relaxed(hi, MON2_THRES_HI(m));
|
||||
writel_relaxed(med, MON2_THRES_MED(m));
|
||||
writel_relaxed(lo, MON2_THRES_LO(m));
|
||||
/* Set the zone count thresholds for interrupts */
|
||||
writel_relaxed(zone_cnt_thres, MON2_ZONE_CNT_THRES(m));
|
||||
break;
|
||||
case MON3:
|
||||
writel_relaxed(hi, MON3_THRES_HI(m));
|
||||
writel_relaxed(med, MON3_THRES_MED(m));
|
||||
writel_relaxed(lo, MON3_THRES_LO(m));
|
||||
/* Set the zone count thresholds for interrupts */
|
||||
writel_relaxed(zone_cnt_thres, MON3_ZONE_CNT_THRES(m));
|
||||
break;
|
||||
}
|
||||
|
||||
dev_dbg(m->dev, "Thres: hi:%u med:%u lo:%u\n", hi, med, lo);
|
||||
dev_dbg(m->dev, "Zone Count Thres: %0x\n", zone_cnt_thres);
|
||||
}
|
||||
|
||||
static void mon_set_zones(struct bwmon *m, unsigned int sample_ms)
|
||||
static __always_inline
|
||||
void mon_set_zones(struct bwmon *m, unsigned int sample_ms,
|
||||
enum mon_reg_type type)
|
||||
{
|
||||
struct bw_hwmon *hw = &(m->hw);
|
||||
u32 zone_cnt_thres = calc_zone_counts(hw);
|
||||
|
||||
mon_set_hw_sampling_window(m, sample_ms);
|
||||
set_zone_thres(m, sample_ms);
|
||||
/* Set the zone count thresholds for interrupts */
|
||||
writel_relaxed(zone_cnt_thres, MON2_ZONE_CNT_THRES(m));
|
||||
|
||||
dev_dbg(m->dev, "Zone Count Thres: %0x\n", zone_cnt_thres);
|
||||
mon_set_hw_sampling_window(m, sample_ms, type);
|
||||
set_zone_thres(m, sample_ms, type);
|
||||
}
|
||||
|
||||
static void mon_set_limit(struct bwmon *m, u32 count)
|
||||
|
|
@ -425,16 +505,28 @@ static unsigned long mon_get_count1(struct bwmon *m)
|
|||
return count;
|
||||
}
|
||||
|
||||
static unsigned int get_zone(struct bwmon *m)
|
||||
static __always_inline
|
||||
unsigned int get_zone(struct bwmon *m, enum mon_reg_type type)
|
||||
{
|
||||
u32 zone_counts;
|
||||
u32 zone;
|
||||
|
||||
zone = get_bitmask_order((m->intr_status & INT_STATUS_MASK_HWS) >> 4);
|
||||
zone = get_bitmask_order(m->intr_status);
|
||||
if (zone) {
|
||||
zone--;
|
||||
} else {
|
||||
zone_counts = readl_relaxed(MON2_ZONE_CNT(m));
|
||||
switch (type) {
|
||||
case MON1:
|
||||
WARN(1, "Invalid\n");
|
||||
return 0;
|
||||
case MON2:
|
||||
zone_counts = readl_relaxed(MON2_ZONE_CNT(m));
|
||||
break;
|
||||
case MON3:
|
||||
zone_counts = readl_relaxed(MON3_ZONE_CNT(m));
|
||||
break;
|
||||
}
|
||||
|
||||
if (zone_counts) {
|
||||
zone = get_bitmask_order(zone_counts) - 1;
|
||||
zone /= 8;
|
||||
|
|
@ -445,14 +537,37 @@ static unsigned int get_zone(struct bwmon *m)
|
|||
return zone;
|
||||
}
|
||||
|
||||
static unsigned long mon_get_zone_stats(struct bwmon *m)
|
||||
static __always_inline
|
||||
unsigned long get_zone_count(struct bwmon *m, unsigned int zone,
|
||||
enum mon_reg_type type)
|
||||
{
|
||||
unsigned long count;
|
||||
|
||||
switch (type) {
|
||||
case MON1:
|
||||
WARN(1, "Invalid\n");
|
||||
return 0;
|
||||
case MON2:
|
||||
count = readl_relaxed(MON2_ZONE_MAX(m, zone)) + 1;
|
||||
break;
|
||||
case MON3:
|
||||
count = readl_relaxed(MON3_ZONE_MAX(m, zone));
|
||||
if (count)
|
||||
count++;
|
||||
break;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static __always_inline
|
||||
unsigned long mon_get_zone_stats(struct bwmon *m, enum mon_reg_type type)
|
||||
{
|
||||
unsigned int zone;
|
||||
unsigned long count = 0;
|
||||
|
||||
zone = get_zone(m);
|
||||
|
||||
count = readl_relaxed(MON2_ZONE_MAX(m, zone)) + 1;
|
||||
zone = get_zone(m, type);
|
||||
count = get_zone_count(m, zone, type);
|
||||
count *= SZ_1M;
|
||||
|
||||
dev_dbg(m->dev, "Zone%d Max byte count: %08lx\n", zone, count);
|
||||
|
|
@ -470,7 +585,8 @@ unsigned long mon_get_count(struct bwmon *m, enum mon_reg_type type)
|
|||
count = mon_get_count1(m);
|
||||
break;
|
||||
case MON2:
|
||||
count = mon_get_zone_stats(m);
|
||||
case MON3:
|
||||
count = mon_get_zone_stats(m, type);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -515,6 +631,11 @@ static unsigned long get_bytes_and_clear2(struct bw_hwmon *hw)
|
|||
return __get_bytes_and_clear(hw, MON2);
|
||||
}
|
||||
|
||||
static unsigned long get_bytes_and_clear3(struct bw_hwmon *hw)
|
||||
{
|
||||
return __get_bytes_and_clear(hw, MON3);
|
||||
}
|
||||
|
||||
static unsigned long set_thres(struct bw_hwmon *hw, unsigned long bytes)
|
||||
{
|
||||
unsigned long count;
|
||||
|
|
@ -537,20 +658,33 @@ static unsigned long set_thres(struct bw_hwmon *hw, unsigned long bytes)
|
|||
return count;
|
||||
}
|
||||
|
||||
static unsigned long set_hw_events(struct bw_hwmon *hw, unsigned int sample_ms)
|
||||
static unsigned long
|
||||
__set_hw_events(struct bw_hwmon *hw, unsigned int sample_ms,
|
||||
enum mon_reg_type type)
|
||||
{
|
||||
struct bwmon *m = to_bwmon(hw);
|
||||
|
||||
mon_disable(m, MON2);
|
||||
mon_clear(m, false, MON2);
|
||||
mon_irq_clear(m, MON2);
|
||||
mon_disable(m, type);
|
||||
mon_clear(m, false, type);
|
||||
mon_irq_clear(m, type);
|
||||
|
||||
mon_set_zones(m, sample_ms);
|
||||
mon_enable(m, MON2);
|
||||
mon_set_zones(m, sample_ms, type);
|
||||
mon_enable(m, type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long set_hw_events(struct bw_hwmon *hw, unsigned int sample_ms)
|
||||
{
|
||||
return __set_hw_events(hw, sample_ms, MON2);
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
set_hw_events3(struct bw_hwmon *hw, unsigned int sample_ms)
|
||||
{
|
||||
return __set_hw_events(hw, sample_ms, MON3);
|
||||
}
|
||||
|
||||
static irqreturn_t
|
||||
__bwmon_intr_handler(int irq, void *dev, enum mon_reg_type type)
|
||||
{
|
||||
|
|
@ -576,6 +710,11 @@ static irqreturn_t bwmon_intr_handler2(int irq, void *dev)
|
|||
return __bwmon_intr_handler(irq, dev, MON2);
|
||||
}
|
||||
|
||||
static irqreturn_t bwmon_intr_handler3(int irq, void *dev)
|
||||
{
|
||||
return __bwmon_intr_handler(irq, dev, MON3);
|
||||
}
|
||||
|
||||
static irqreturn_t bwmon_intr_thread(int irq, void *dev)
|
||||
{
|
||||
struct bwmon *m = dev;
|
||||
|
|
@ -601,6 +740,10 @@ static __always_inline int __start_bw_hwmon(struct bw_hwmon *hw,
|
|||
zone_actions = calc_zone_actions();
|
||||
handler = bwmon_intr_handler2;
|
||||
break;
|
||||
case MON3:
|
||||
zone_actions = calc_zone_actions();
|
||||
handler = bwmon_intr_handler3;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = request_threaded_irq(m->irq, handler, bwmon_intr_thread,
|
||||
|
|
@ -621,10 +764,14 @@ static __always_inline int __start_bw_hwmon(struct bw_hwmon *hw,
|
|||
mon_set_limit(m, limit);
|
||||
break;
|
||||
case MON2:
|
||||
mon_set_zones(m, hw->df->profile->polling_ms);
|
||||
mon_set_zones(m, hw->df->profile->polling_ms, type);
|
||||
/* Set the zone actions to increment appropriate counters */
|
||||
writel_relaxed(zone_actions, MON2_ZONE_ACTIONS(m));
|
||||
break;
|
||||
case MON3:
|
||||
mon_set_zones(m, hw->df->profile->polling_ms, type);
|
||||
/* Set the zone actions to increment appropriate counters */
|
||||
writel_relaxed(zone_actions, MON3_ZONE_ACTIONS(m));
|
||||
}
|
||||
|
||||
mon_irq_clear(m, type);
|
||||
|
|
@ -644,6 +791,11 @@ static int start_bw_hwmon2(struct bw_hwmon *hw, unsigned long mbps)
|
|||
return __start_bw_hwmon(hw, mbps, MON2);
|
||||
}
|
||||
|
||||
static int start_bw_hwmon3(struct bw_hwmon *hw, unsigned long mbps)
|
||||
{
|
||||
return __start_bw_hwmon(hw, mbps, MON3);
|
||||
}
|
||||
|
||||
static __always_inline
|
||||
void __stop_bw_hwmon(struct bw_hwmon *hw, enum mon_reg_type type)
|
||||
{
|
||||
|
|
@ -666,6 +818,11 @@ static void stop_bw_hwmon2(struct bw_hwmon *hw)
|
|||
return __stop_bw_hwmon(hw, MON2);
|
||||
}
|
||||
|
||||
static void stop_bw_hwmon3(struct bw_hwmon *hw)
|
||||
{
|
||||
return __stop_bw_hwmon(hw, MON3);
|
||||
}
|
||||
|
||||
static __always_inline
|
||||
int __suspend_bw_hwmon(struct bw_hwmon *hw, enum mon_reg_type type)
|
||||
{
|
||||
|
|
@ -689,7 +846,13 @@ static int suspend_bw_hwmon2(struct bw_hwmon *hw)
|
|||
return __suspend_bw_hwmon(hw, MON2);
|
||||
}
|
||||
|
||||
static int __resume_bw_hwmon(struct bw_hwmon *hw, enum mon_reg_type type)
|
||||
static int suspend_bw_hwmon3(struct bw_hwmon *hw)
|
||||
{
|
||||
return __suspend_bw_hwmon(hw, MON3);
|
||||
}
|
||||
|
||||
static __always_inline
|
||||
int __resume_bw_hwmon(struct bw_hwmon *hw, enum mon_reg_type type)
|
||||
{
|
||||
struct bwmon *m = to_bwmon(hw);
|
||||
int ret;
|
||||
|
|
@ -702,6 +865,9 @@ static int __resume_bw_hwmon(struct bw_hwmon *hw, enum mon_reg_type type)
|
|||
case MON2:
|
||||
handler = bwmon_intr_handler2;
|
||||
break;
|
||||
case MON3:
|
||||
handler = bwmon_intr_handler3;
|
||||
break;
|
||||
}
|
||||
|
||||
mon_clear(m, false, type);
|
||||
|
|
@ -730,6 +896,11 @@ static int resume_bw_hwmon2(struct bw_hwmon *hw)
|
|||
return __resume_bw_hwmon(hw, MON2);
|
||||
}
|
||||
|
||||
static int resume_bw_hwmon3(struct bw_hwmon *hw)
|
||||
{
|
||||
return __resume_bw_hwmon(hw, MON3);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static const struct bwmon_spec spec[] = {
|
||||
|
|
@ -737,25 +908,40 @@ static const struct bwmon_spec spec[] = {
|
|||
.wrap_on_thres = true,
|
||||
.overflow = false,
|
||||
.throt_adj = false,
|
||||
.hw_sampling = false
|
||||
.hw_sampling = false,
|
||||
.has_global_base = true,
|
||||
.reg_type = MON1,
|
||||
},
|
||||
[1] = {
|
||||
.wrap_on_thres = false,
|
||||
.overflow = true,
|
||||
.throt_adj = false,
|
||||
.hw_sampling = false
|
||||
.hw_sampling = false,
|
||||
.has_global_base = true,
|
||||
.reg_type = MON1,
|
||||
},
|
||||
[2] = {
|
||||
.wrap_on_thres = false,
|
||||
.overflow = true,
|
||||
.throt_adj = true,
|
||||
.hw_sampling = false
|
||||
.hw_sampling = false,
|
||||
.has_global_base = true,
|
||||
.reg_type = MON1,
|
||||
},
|
||||
[3] = {
|
||||
.wrap_on_thres = false,
|
||||
.overflow = true,
|
||||
.throt_adj = true,
|
||||
.hw_sampling = true
|
||||
.hw_sampling = true,
|
||||
.has_global_base = true,
|
||||
.reg_type = MON2,
|
||||
},
|
||||
[4] = {
|
||||
.wrap_on_thres = false,
|
||||
.overflow = true,
|
||||
.throt_adj = false,
|
||||
.hw_sampling = true,
|
||||
.reg_type = MON3,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -764,6 +950,7 @@ static const struct of_device_id bimc_bwmon_match_table[] = {
|
|||
{ .compatible = "qcom,bimc-bwmon2", .data = &spec[1] },
|
||||
{ .compatible = "qcom,bimc-bwmon3", .data = &spec[2] },
|
||||
{ .compatible = "qcom,bimc-bwmon4", .data = &spec[3] },
|
||||
{ .compatible = "qcom,bimc-bwmon5", .data = &spec[4] },
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
@ -780,13 +967,6 @@ static int bimc_bwmon_driver_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
m->dev = dev;
|
||||
|
||||
ret = of_property_read_u32(dev->of_node, "qcom,mport", &data);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "mport not found! (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
m->mport = data;
|
||||
|
||||
m->spec = of_device_get_match_data(dev);
|
||||
if (!m->spec) {
|
||||
dev_err(dev, "Unknown device type!\n");
|
||||
|
|
@ -804,15 +984,26 @@ static int bimc_bwmon_driver_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "global_base");
|
||||
if (!res) {
|
||||
dev_err(dev, "global_base not found!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
m->global_base = devm_ioremap(dev, res->start, resource_size(res));
|
||||
if (!m->global_base) {
|
||||
dev_err(dev, "Unable map global_base!\n");
|
||||
return -ENOMEM;
|
||||
if (m->spec->has_global_base) {
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
"global_base");
|
||||
if (!res) {
|
||||
dev_err(dev, "global_base not found!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
m->global_base = devm_ioremap(dev, res->start,
|
||||
resource_size(res));
|
||||
if (!m->global_base) {
|
||||
dev_err(dev, "Unable map global_base!\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(dev->of_node, "qcom,mport", &data);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "mport not found! (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
m->mport = data;
|
||||
}
|
||||
|
||||
m->irq = platform_get_irq(pdev, 0);
|
||||
|
|
@ -832,20 +1023,33 @@ static int bimc_bwmon_driver_probe(struct platform_device *pdev)
|
|||
dev_err(dev, "HW sampling rate not specified!\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
switch (m->spec->reg_type) {
|
||||
case MON3:
|
||||
m->hw.start_hwmon = start_bw_hwmon3;
|
||||
m->hw.stop_hwmon = stop_bw_hwmon3;
|
||||
m->hw.suspend_hwmon = suspend_bw_hwmon3;
|
||||
m->hw.resume_hwmon = resume_bw_hwmon3;
|
||||
m->hw.get_bytes_and_clear = get_bytes_and_clear3;
|
||||
m->hw.set_hw_events = set_hw_events3;
|
||||
break;
|
||||
case MON2:
|
||||
m->hw.start_hwmon = start_bw_hwmon2;
|
||||
m->hw.stop_hwmon = stop_bw_hwmon2;
|
||||
m->hw.suspend_hwmon = suspend_bw_hwmon2;
|
||||
m->hw.resume_hwmon = resume_bw_hwmon2;
|
||||
m->hw.get_bytes_and_clear = get_bytes_and_clear2;
|
||||
m->hw.set_hw_events = set_hw_events;
|
||||
} else {
|
||||
break;
|
||||
case MON1:
|
||||
m->hw.start_hwmon = start_bw_hwmon;
|
||||
m->hw.stop_hwmon = stop_bw_hwmon;
|
||||
m->hw.suspend_hwmon = suspend_bw_hwmon;
|
||||
m->hw.resume_hwmon = resume_bw_hwmon;
|
||||
m->hw.get_bytes_and_clear = get_bytes_and_clear;
|
||||
m->hw.set_thres = set_thres;
|
||||
break;
|
||||
}
|
||||
|
||||
if (m->spec->throt_adj) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue