blob: 78a24f39d3571fb6f152143269a8350e8d11cd91 [file] [log] [blame]
/* Copyright (c) 2016 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*
* EXYNOS - BTS CAL code.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "cal_bts9610.h"
#include <linux/soc/samsung/exynos-soc.h>
#define LOG(x, ...) \
({ \
seq_printf(buf, x, ##__VA_ARGS__); \
})
#define TREX_CON 0x000
#define TREX_TIMEOUT 0x010
#define TREX_RCON 0x020
#define TREX_WCON 0x040
#define TREX_RBLOCK_UPPER 0x024
#define TREX_WBLOCK_UPPER 0x044
#define TREX_RBLOCK_UPPER_NORMAL 0x028
#define TREX_WBLOCK_UPPER_NORMAL 0x048
#define TREX_RBLOCK_UPPER_FULL 0x02C
#define TREX_WBLOCK_UPPER_FULL 0x04C
#define TREX_RBLOCK_UPPER_BUSY 0x030
#define TREX_WBLOCK_UPPER_BUSY 0x050
#define TREX_RBLOCK_UPPER_MAX 0x034
#define TREX_WBLOCK_UPPER_MAX 0x054
#define QMAX_THRESHOLD_R 0x050
#define QMAX_THRESHOLD_W 0x054
static unsigned int set_mo(unsigned int mo)
{
if (mo > BTS_MAX_MO || !mo)
mo = BTS_MAX_MO;
return mo;
}
static unsigned int set_threshold(unsigned int threshold)
{
if (threshold > BTS_QMAX_MAX_THRESHOLD || !threshold)
threshold = BTS_QMAX_MAX_THRESHOLD;
return threshold;
}
void bts_setqos(void __iomem *base, struct bts_status *stat)
{
unsigned int tmp_reg = 0;
bool block_en = false;
if (!base)
return;
if (stat->disable) {
__raw_writel(0x4000, base + TREX_RCON);
__raw_writel(0x4000, base + TREX_WCON);
__raw_writel(0x0, base + TREX_CON);
return;
}
__raw_writel(set_mo(stat->rmo), base + TREX_RBLOCK_UPPER);
__raw_writel(set_mo(stat->wmo), base + TREX_WBLOCK_UPPER);
if (stat->max_rmo || stat->max_wmo || stat->full_rmo || stat->full_wmo)
block_en = true;
__raw_writel(set_mo(stat->max_rmo), base + TREX_RBLOCK_UPPER_MAX);
__raw_writel(set_mo(stat->max_wmo), base + TREX_WBLOCK_UPPER_MAX);
__raw_writel(set_mo(stat->full_rmo), base + TREX_RBLOCK_UPPER_FULL);
__raw_writel(set_mo(stat->full_wmo), base + TREX_WBLOCK_UPPER_FULL);
if (stat->timeout_en) {
if (stat->timeout_r > 0xff)
stat->timeout_r = 0xff;
if (stat->timeout_w > 0xff)
stat->timeout_w = 0xff;
__raw_writel(stat->timeout_r | (stat->timeout_w << 16),
base + TREX_TIMEOUT);
} else {
__raw_writel(0xff | (0xff << 16), base + TREX_TIMEOUT);
}
/* override QoS value */
tmp_reg |= (1 & !stat->bypass_en) << 8;
tmp_reg |= (stat->priority & 0xf) << 12;
/* enable Blocking logic */
tmp_reg |= (1 & block_en) << 0;
__raw_writel(tmp_reg, base + TREX_RCON);
__raw_writel(tmp_reg, base + TREX_WCON);
__raw_writel(((1 & stat->timeout_en) << 20) | 0x1, base + TREX_CON);
}
void bts_showqos(void __iomem *base, struct seq_file *buf)
{
if (!base)
return;
LOG("CON0x%08X qos(%d,%d)0x%Xr%Xw, wmo: %d, rmo: %d\n",
__raw_readl(base + TREX_CON),
(__raw_readl(base + TREX_RCON) >> 8) & 0x1,
(__raw_readl(base + TREX_WCON) >> 8) & 0x1,
(__raw_readl(base + TREX_RCON) >> 12) & 0xf,
(__raw_readl(base + TREX_WCON) >> 12) & 0xf,
(__raw_readl(base + TREX_WBLOCK_UPPER)),
(__raw_readl(base + TREX_RBLOCK_UPPER))
);
}
void bts_set_qmax(void __iomem *base, unsigned int r_thsd0,
unsigned int r_thsd1, unsigned int w_thsd0,
unsigned int w_thsd1)
{
unsigned int tmp_reg = 0;
if (!base)
return;
tmp_reg |= set_threshold(r_thsd0);
tmp_reg |= set_threshold(r_thsd1) << 16;
__raw_writel(tmp_reg, base + QMAX_THRESHOLD_R);
tmp_reg = 0;
tmp_reg |= set_threshold(w_thsd0);
tmp_reg |= set_threshold(w_thsd1) << 16;
__raw_writel(tmp_reg, base + QMAX_THRESHOLD_W);
}
void bts_show_qmax(void __iomem *base, struct seq_file *buf)
{
if (!base)
return;
LOG("threshold_r(0x%04x,0x%04x), threshold_w(0x%04x,0x%04x)\n",
__raw_readl(base + QMAX_THRESHOLD_R) & 0xffff,
(__raw_readl(base + QMAX_THRESHOLD_R) >> 16) & 0xffff,
__raw_readl(base + QMAX_THRESHOLD_W) & 0xffff,
(__raw_readl(base + QMAX_THRESHOLD_W) >> 16) & 0xffff);
}