PM / devfreq: event: Add new Rockchip NoC probe driver

This patch adds NoC (Network on Chip) Probe driver which provides
the primitive values to get the performance data. For example, RK3399
has multiple NoC probes to monitor traffic statistics for analyzing
the transaction flow.

Change-Id: I66f6708f0d244488ca08f0f1f1cb36b19c7a2d0a
Signed-off-by: Finley Xiao <finley.xiao@rock-chips.com>
This commit is contained in:
Finley Xiao
2017-10-30 21:33:19 +08:00
parent 90454edfc6
commit ccfeccfe22
4 changed files with 197 additions and 0 deletions
@@ -0,0 +1,23 @@
* Rockchip NoC (Network on Chip) Probe device
The Rockchip SoCs have NoC (Network on Chip) Probe for NoC bus.
NoC provides the primitive values to get the performance data, The
packets that the Network on Chip (NoC) probes detects are transported
over the network infrastructure to observer units. For example, RK3399
has multiple NoC probes to monitor traffic statistics for analyzing the
transaction flow.
Required properties:
- compatible: Should be one of the following.
- "rockchip,rk3288-nocp" - for RK3288 SoC.
- "rockchip,rk3368-nocp" - for RK3368 SoC.
- "rockchip,rk3399-nocp" - for RK3399 SoC.
- reg: physical base address of each NoC Probe and length of memory mapped region.
Example : NoC Probe nodes in Device Tree are listed below.
nocp_cci_msch0: nocp-cci-msch0@ffa86000 {
compatible = "rockchip,rk3399-nocp";
reg = <0xffa86000 0x400>;
};
+7
View File
@@ -29,4 +29,11 @@ config DEVFREQ_EVENT_ROCKCHIP_DFI
This add the devfreq-event driver for Rockchip SoC. It provides DFI
(DDR Monitor Module) driver to count ddr load.
config DEVFREQ_EVENT_ROCKCHIP_NOCP
tristate "ROCKCHIP NoC (Network On Chip) Probe DEVFREQ event Driver"
depends on ARCH_ROCKCHIP
help
This add the devfreq-event driver for Rockchip SoC. It provides NoC
(Network on Chip) Probe counters to monitor traffic statistics.
endif # PM_DEVFREQ_EVENT
+1
View File
@@ -1,3 +1,4 @@
# Exynos DEVFREQ Event Drivers
obj-$(CONFIG_DEVFREQ_EVENT_EXYNOS_PPMU) += exynos-ppmu.o
obj-$(CONFIG_DEVFREQ_EVENT_ROCKCHIP_DFI) += rockchip-dfi.o
obj-$(CONFIG_DEVFREQ_EVENT_ROCKCHIP_NOCP) += rockchip-nocp.o
+166
View File
@@ -0,0 +1,166 @@
/*
* Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
#include <linux/devfreq-event.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#define EVENT_BYTE 0x08
#define EVENT_CHAIN 0x10
#define START_EN BIT(3)
#define GLOBAL_EN BIT(0)
#define START_GO BIT(0)
#define PROBE_MAINCTL 0x0008
#define PROBE_CFGCTL 0x000c
#define PROBE_STATPERIOD 0x0024
#define PROBE_STATGO 0x0028
#define PROBE_COUNTERS_0_SRC 0x0138
#define PROBE_COUNTERS_0_VAL 0x013c
#define PROBE_COUNTERS_1_SRC 0x014c
#define PROBE_COUNTERS_1_VAL 0x0150
struct rockchip_nocp {
void __iomem *reg_base;
struct device *dev;
struct devfreq_event_dev *edev;
struct devfreq_event_desc *desc;
ktime_t time;
};
static int rockchip_nocp_enable(struct devfreq_event_dev *edev)
{
struct rockchip_nocp *nocp = devfreq_event_get_drvdata(edev);
void __iomem *reg_base = nocp->reg_base;
writel_relaxed(GLOBAL_EN, reg_base + PROBE_CFGCTL);
writel_relaxed(START_EN, reg_base + PROBE_MAINCTL);
writel_relaxed(0, reg_base + PROBE_STATPERIOD);
writel_relaxed(EVENT_BYTE, reg_base + PROBE_COUNTERS_0_SRC);
writel_relaxed(EVENT_CHAIN, reg_base + PROBE_COUNTERS_1_SRC);
writel_relaxed(START_GO, reg_base + PROBE_STATGO);
nocp->time = ktime_get();
return 0;
}
static int rockchip_nocp_disable(struct devfreq_event_dev *edev)
{
struct rockchip_nocp *nocp = devfreq_event_get_drvdata(edev);
void __iomem *reg_base = nocp->reg_base;
writel_relaxed(0, reg_base + PROBE_STATGO);
writel_relaxed(0, reg_base + PROBE_MAINCTL);
writel_relaxed(0, reg_base + PROBE_CFGCTL);
writel_relaxed(0, reg_base + PROBE_COUNTERS_0_SRC);
writel_relaxed(0, reg_base + PROBE_COUNTERS_1_SRC);
return 0;
}
static int rockchip_nocp_get_event(struct devfreq_event_dev *edev,
struct devfreq_event_data *edata)
{
struct rockchip_nocp *nocp = devfreq_event_get_drvdata(edev);
void __iomem *reg_base = nocp->reg_base;
u32 counter = 0, counter0 = 0, counter1 = 0;
int time_ms = 0;
time_ms = ktime_to_ms(ktime_sub(ktime_get(), nocp->time));
counter0 = readl_relaxed(reg_base + PROBE_COUNTERS_0_VAL);
counter1 = readl_relaxed(reg_base + PROBE_COUNTERS_1_VAL);
counter = (counter0 & 0xffff) | ((counter1 & 0xffff) << 16);
counter = counter / 1000000;
if (time_ms > 0)
edata->load_count = (counter * 1000) / time_ms;
writel_relaxed(START_GO, reg_base + PROBE_STATGO);
nocp->time = ktime_get();
return 0;
}
static int rockchip_nocp_set_event(struct devfreq_event_dev *edev)
{
return 0;
}
static const struct devfreq_event_ops rockchip_nocp_ops = {
.disable = rockchip_nocp_disable,
.enable = rockchip_nocp_enable,
.get_event = rockchip_nocp_get_event,
.set_event = rockchip_nocp_set_event,
};
static const struct of_device_id rockchip_nocp_id_match[] = {
{ .compatible = "rockchip,rk3288-nocp" },
{ .compatible = "rockchip,rk3368-nocp" },
{ .compatible = "rockchip,rk3399-nocp" },
{ },
};
static int rockchip_nocp_probe(struct platform_device *pdev)
{
struct resource *res;
struct rockchip_nocp *nocp;
struct devfreq_event_desc *desc;
struct device_node *np = pdev->dev.of_node;
nocp = devm_kzalloc(&pdev->dev, sizeof(*nocp), GFP_KERNEL);
if (!nocp)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
nocp->reg_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(nocp->reg_base))
return PTR_ERR(nocp->reg_base);
desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
if (!desc)
return -ENOMEM;
desc->ops = &rockchip_nocp_ops;
desc->driver_data = nocp;
desc->name = np->name;
nocp->desc = desc;
nocp->dev = &pdev->dev;
nocp->edev = devm_devfreq_event_add_edev(&pdev->dev, desc);
if (IS_ERR(nocp->edev)) {
dev_err(&pdev->dev, "failed to add devfreq-event device\n");
return PTR_ERR(nocp->edev);
}
platform_set_drvdata(pdev, nocp);
return 0;
}
static struct platform_driver rockchip_nocp_driver = {
.probe = rockchip_nocp_probe,
.driver = {
.name = "rockchip-nocp",
.of_match_table = rockchip_nocp_id_match,
},
};
module_platform_driver(rockchip_nocp_driver);
MODULE_DESCRIPTION("Rockchip NoC (Network on Chip) Probe driver");
MODULE_AUTHOR("Finley Xiao <finley.xiao@rock-chips.com>");
MODULE_LICENSE("GPL v2");