#include <linux/clk.h>
#include <linux/devfreq-event.h>
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/seqlock.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/perf_event.h>
#include <soc/rockchip/rockchip_grf.h>
#include <soc/rockchip/rk3399_grf.h>
#include <soc/rockchip/rk3568_grf.h>
#include <soc/rockchip/rk3588_grf.h>
#define DMC_MAX_CHANNELS …
#define HIWORD_UPDATE(val, mask) …
#define DDRMON_CTRL …
#define DDRMON_CTRL_DDR4 …
#define DDRMON_CTRL_LPDDR4 …
#define DDRMON_CTRL_HARDWARE_EN …
#define DDRMON_CTRL_LPDDR23 …
#define DDRMON_CTRL_SOFTWARE_EN …
#define DDRMON_CTRL_TIMER_CNT_EN …
#define DDRMON_CTRL_DDR_TYPE_MASK …
#define DDRMON_CH0_WR_NUM …
#define DDRMON_CH0_RD_NUM …
#define DDRMON_CH0_COUNT_NUM …
#define DDRMON_CH0_DFI_ACCESS_NUM …
#define DDRMON_CH1_COUNT_NUM …
#define DDRMON_CH1_DFI_ACCESS_NUM …
#define PERF_EVENT_CYCLES …
#define PERF_EVENT_READ_BYTES …
#define PERF_EVENT_WRITE_BYTES …
#define PERF_EVENT_READ_BYTES0 …
#define PERF_EVENT_WRITE_BYTES0 …
#define PERF_EVENT_READ_BYTES1 …
#define PERF_EVENT_WRITE_BYTES1 …
#define PERF_EVENT_READ_BYTES2 …
#define PERF_EVENT_WRITE_BYTES2 …
#define PERF_EVENT_READ_BYTES3 …
#define PERF_EVENT_WRITE_BYTES3 …
#define PERF_EVENT_BYTES …
#define PERF_ACCESS_TYPE_MAX …
struct dmc_count_channel { … };
struct dmc_count { … };
struct rockchip_dfi { … };
static int rockchip_dfi_enable(struct rockchip_dfi *dfi)
{ … }
static void rockchip_dfi_disable(struct rockchip_dfi *dfi)
{ … }
static void rockchip_dfi_read_counters(struct rockchip_dfi *dfi, struct dmc_count *res)
{ … }
static int rockchip_dfi_event_disable(struct devfreq_event_dev *edev)
{ … }
static int rockchip_dfi_event_enable(struct devfreq_event_dev *edev)
{ … }
static int rockchip_dfi_set_event(struct devfreq_event_dev *edev)
{ … }
static int rockchip_dfi_get_event(struct devfreq_event_dev *edev,
struct devfreq_event_data *edata)
{ … }
static const struct devfreq_event_ops rockchip_dfi_ops = …;
#ifdef CONFIG_PERF_EVENTS
static void rockchip_ddr_perf_counters_add(struct rockchip_dfi *dfi,
const struct dmc_count *now,
struct dmc_count *res)
{ … }
static ssize_t ddr_perf_cpumask_show(struct device *dev,
struct device_attribute *attr, char *buf)
{ … }
static struct device_attribute ddr_perf_cpumask_attr = …;
static struct attribute *ddr_perf_cpumask_attrs[] = …;
static const struct attribute_group ddr_perf_cpumask_attr_group = …;
PMU_EVENT_ATTR_STRING(cycles, ddr_pmu_cycles, "event="__stringify(PERF_EVENT_CYCLES))
#define DFI_PMU_EVENT_ATTR(_name, _var, _str) …
DFI_PMU_EVENT_ATTR(read-bytes0, ddr_pmu_read_bytes0, "event="__stringify(PERF_EVENT_READ_BYTES0));
DFI_PMU_EVENT_ATTR(write-bytes0, ddr_pmu_write_bytes0, "event="__stringify(PERF_EVENT_WRITE_BYTES0));
DFI_PMU_EVENT_ATTR(read-bytes1, ddr_pmu_read_bytes1, "event="__stringify(PERF_EVENT_READ_BYTES1));
DFI_PMU_EVENT_ATTR(write-bytes1, ddr_pmu_write_bytes1, "event="__stringify(PERF_EVENT_WRITE_BYTES1));
DFI_PMU_EVENT_ATTR(read-bytes2, ddr_pmu_read_bytes2, "event="__stringify(PERF_EVENT_READ_BYTES2));
DFI_PMU_EVENT_ATTR(write-bytes2, ddr_pmu_write_bytes2, "event="__stringify(PERF_EVENT_WRITE_BYTES2));
DFI_PMU_EVENT_ATTR(read-bytes3, ddr_pmu_read_bytes3, "event="__stringify(PERF_EVENT_READ_BYTES3));
DFI_PMU_EVENT_ATTR(write-bytes3, ddr_pmu_write_bytes3, "event="__stringify(PERF_EVENT_WRITE_BYTES3));
DFI_PMU_EVENT_ATTR(read-bytes, ddr_pmu_read_bytes, "event="__stringify(PERF_EVENT_READ_BYTES));
DFI_PMU_EVENT_ATTR(write-bytes, ddr_pmu_write_bytes, "event="__stringify(PERF_EVENT_WRITE_BYTES));
DFI_PMU_EVENT_ATTR(bytes, ddr_pmu_bytes, "event="__stringify(PERF_EVENT_BYTES));
#define DFI_ATTR_MB(_name) …
static struct attribute *ddr_perf_events_attrs[] = …;
static const struct attribute_group ddr_perf_events_attr_group = …;
PMU_FORMAT_ATTR(…);
static struct attribute *ddr_perf_format_attrs[] = …;
static const struct attribute_group ddr_perf_format_attr_group = …;
static const struct attribute_group *attr_groups[] = …;
static int rockchip_ddr_perf_event_init(struct perf_event *event)
{ … }
static u64 rockchip_ddr_perf_event_get_count(struct perf_event *event)
{ … }
static void rockchip_ddr_perf_event_update(struct perf_event *event)
{ … }
static void rockchip_ddr_perf_event_start(struct perf_event *event, int flags)
{ … }
static int rockchip_ddr_perf_event_add(struct perf_event *event, int flags)
{ … }
static void rockchip_ddr_perf_event_stop(struct perf_event *event, int flags)
{ … }
static void rockchip_ddr_perf_event_del(struct perf_event *event, int flags)
{ … }
static enum hrtimer_restart rockchip_dfi_timer(struct hrtimer *timer)
{
struct rockchip_dfi *dfi = container_of(timer, struct rockchip_dfi, timer);
struct dmc_count now, total;
rockchip_dfi_read_counters(dfi, &now);
write_seqlock(&dfi->count_seqlock);
rockchip_ddr_perf_counters_add(dfi, &now, &total);
dfi->total_count = total;
dfi->last_perf_count = now;
write_sequnlock(&dfi->count_seqlock);
hrtimer_forward_now(&dfi->timer, ns_to_ktime(NSEC_PER_SEC));
return HRTIMER_RESTART;
};
static int ddr_perf_offline_cpu(unsigned int cpu, struct hlist_node *node)
{ … }
static void rockchip_ddr_cpuhp_remove_state(void *data)
{ … }
static void rockchip_ddr_cpuhp_remove_instance(void *data)
{ … }
static void rockchip_ddr_perf_remove(void *data)
{ … }
static int rockchip_ddr_perf_init(struct rockchip_dfi *dfi)
{ … }
#else
static int rockchip_ddr_perf_init(struct rockchip_dfi *dfi)
{
return 0;
}
#endif
static int rk3399_dfi_init(struct rockchip_dfi *dfi)
{
struct regmap *regmap_pmu = dfi->regmap_pmu;
u32 val;
dfi->clk = devm_clk_get(dfi->dev, "pclk_ddr_mon");
if (IS_ERR(dfi->clk))
return dev_err_probe(dfi->dev, PTR_ERR(dfi->clk),
"Cannot get the clk pclk_ddr_mon\n");
regmap_read(regmap_pmu, RK3399_PMUGRF_OS_REG2, &val);
dfi->ddr_type = FIELD_GET(RK3399_PMUGRF_OS_REG2_DDRTYPE, val);
dfi->channel_mask = GENMASK(1, 0);
dfi->max_channels = 2;
dfi->buswidth[0] = FIELD_GET(RK3399_PMUGRF_OS_REG2_BW_CH0, val) == 0 ? 4 : 2;
dfi->buswidth[1] = FIELD_GET(RK3399_PMUGRF_OS_REG2_BW_CH1, val) == 0 ? 4 : 2;
dfi->ddrmon_stride = 0x14;
dfi->ddrmon_ctrl_single = true;
return 0;
};
static int rk3568_dfi_init(struct rockchip_dfi *dfi)
{
struct regmap *regmap_pmu = dfi->regmap_pmu;
u32 reg2, reg3;
regmap_read(regmap_pmu, RK3568_PMUGRF_OS_REG2, ®2);
regmap_read(regmap_pmu, RK3568_PMUGRF_OS_REG3, ®3);
dfi->ddr_type = FIELD_GET(RK3568_PMUGRF_OS_REG2_DRAMTYPE_INFO, reg2);
if (FIELD_GET(RK3568_PMUGRF_OS_REG3_SYSREG_VERSION, reg3) >= 0x3)
dfi->ddr_type |= FIELD_GET(RK3568_PMUGRF_OS_REG3_DRAMTYPE_INFO_V3, reg3) << 3;
dfi->channel_mask = BIT(0);
dfi->max_channels = 1;
dfi->buswidth[0] = FIELD_GET(RK3568_PMUGRF_OS_REG2_BW_CH0, reg2) == 0 ? 4 : 2;
dfi->ddrmon_stride = 0x0;
dfi->ddrmon_ctrl_single = true;
return 0;
};
static int rk3588_dfi_init(struct rockchip_dfi *dfi)
{
struct regmap *regmap_pmu = dfi->regmap_pmu;
u32 reg2, reg3, reg4;
regmap_read(regmap_pmu, RK3588_PMUGRF_OS_REG2, ®2);
regmap_read(regmap_pmu, RK3588_PMUGRF_OS_REG3, ®3);
regmap_read(regmap_pmu, RK3588_PMUGRF_OS_REG4, ®4);
dfi->ddr_type = FIELD_GET(RK3588_PMUGRF_OS_REG2_DRAMTYPE_INFO, reg2);
if (FIELD_GET(RK3588_PMUGRF_OS_REG3_SYSREG_VERSION, reg3) >= 0x3)
dfi->ddr_type |= FIELD_GET(RK3588_PMUGRF_OS_REG3_DRAMTYPE_INFO_V3, reg3) << 3;
dfi->buswidth[0] = FIELD_GET(RK3588_PMUGRF_OS_REG2_BW_CH0, reg2) == 0 ? 4 : 2;
dfi->buswidth[1] = FIELD_GET(RK3588_PMUGRF_OS_REG2_BW_CH1, reg2) == 0 ? 4 : 2;
dfi->buswidth[2] = FIELD_GET(RK3568_PMUGRF_OS_REG2_BW_CH0, reg4) == 0 ? 4 : 2;
dfi->buswidth[3] = FIELD_GET(RK3588_PMUGRF_OS_REG2_BW_CH1, reg4) == 0 ? 4 : 2;
dfi->channel_mask = FIELD_GET(RK3588_PMUGRF_OS_REG2_CH_INFO, reg2) |
FIELD_GET(RK3588_PMUGRF_OS_REG2_CH_INFO, reg4) << 2;
dfi->max_channels = 4;
dfi->ddrmon_stride = 0x4000;
return 0;
};
static const struct of_device_id rockchip_dfi_id_match[] = …;
MODULE_DEVICE_TABLE(of, rockchip_dfi_id_match);
static int rockchip_dfi_probe(struct platform_device *pdev)
{ … }
static struct platform_driver rockchip_dfi_driver = …;
module_platform_driver(…) …;
MODULE_LICENSE(…) …;
MODULE_AUTHOR(…) …;
MODULE_DESCRIPTION(…) …;