[PATCH v5 5/8] PM / devfreq: event: support rockchip dfi controller

2016-08-09 Thread Lin Huang
on rk3399 platform, there is dfi conroller can monitor
ddr load, base on this result, we can do ddr freqency
scaling.

Signed-off-by: Lin Huang 
Acked-by: Chanwoo Choi 
---
Changes in v5:
-None

Changes in v4:
-None

Changes in v3:
-None

Changes in v2:
-None 

Changes in v1:
-None

 drivers/devfreq/event/Kconfig|   7 +
 drivers/devfreq/event/Makefile   |   1 +
 drivers/devfreq/event/rockchip-dfi.c | 253 +++
 3 files changed, 261 insertions(+)
 create mode 100644 drivers/devfreq/event/rockchip-dfi.c

diff --git a/drivers/devfreq/event/Kconfig b/drivers/devfreq/event/Kconfig
index eb6f74a..20d82c2 100644
--- a/drivers/devfreq/event/Kconfig
+++ b/drivers/devfreq/event/Kconfig
@@ -30,4 +30,11 @@ config DEVFREQ_EVENT_EXYNOS_PPMU
  (Platform Performance Monitoring Unit) counters to estimate the
  utilization of each module.
 
+config DEVFREQ_EVENT_ROCKCHIP_DFI
+   tristate "ROCKCHIP DFI DEVFREQ event Driver"
+   depends on ARCH_ROCKCHIP
+   help
+ This add the devfreq-event driver for Rockchip SoC. It provides DFI
+ (DDR Monitor Module) driver to count ddr load.
+
 endif # PM_DEVFREQ_EVENT
diff --git a/drivers/devfreq/event/Makefile b/drivers/devfreq/event/Makefile
index 3d6afd3..dda7090 100644
--- a/drivers/devfreq/event/Makefile
+++ b/drivers/devfreq/event/Makefile
@@ -2,3 +2,4 @@
 
 obj-$(CONFIG_DEVFREQ_EVENT_EXYNOS_NOCP) += exynos-nocp.o
 obj-$(CONFIG_DEVFREQ_EVENT_EXYNOS_PPMU) += exynos-ppmu.o
+obj-$(CONFIG_DEVFREQ_EVENT_ROCKCHIP_DFI) += rockchip-dfi.o
diff --git a/drivers/devfreq/event/rockchip-dfi.c 
b/drivers/devfreq/event/rockchip-dfi.c
new file mode 100644
index 000..3f12be7
--- /dev/null
+++ b/drivers/devfreq/event/rockchip-dfi.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd
+ * Author: Lin Huang 
+ *
+ * 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 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define RK3399_DMC_NUM_CH  2
+
+/* DDRMON_CTRL */
+#define DDRMON_CTRL0x04
+#define CLR_DDRMON_CTRL(0x1f << 0)
+#define LPDDR4_EN  (0x10001 << 4)
+#define HARDWARE_EN(0x10001 << 3)
+#define LPDDR3_EN  (0x10001 << 2)
+#define SOFTWARE_EN(0x10001 << 1)
+#define TIME_CNT_EN(0x10001 << 0)
+
+#define DDRMON_CH0_COUNT_NUM   0x28
+#define DDRMON_CH0_DFI_ACCESS_NUM  0x2c
+#define DDRMON_CH1_COUNT_NUM   0x3c
+#define DDRMON_CH1_DFI_ACCESS_NUM  0x40
+
+/* pmu grf */
+#define PMUGRF_OS_REG2 0x308
+#define DDRTYPE_SHIFT  13
+#define DDRTYPE_MASK   7
+
+enum {
+   DDR3 = 3,
+   LPDDR3 = 6,
+   LPDDR4 = 7,
+   UNUSED = 0xFF
+};
+
+struct dmc_usage {
+   u32 access;
+   u32 total;
+};
+
+struct rockchip_dfi {
+   struct devfreq_event_dev *edev;
+   struct devfreq_event_desc *desc;
+   struct dmc_usage ch_usage[RK3399_DMC_NUM_CH];
+   struct device *dev;
+   void __iomem *regs;
+   struct regmap *regmap_pmu;
+   struct clk *clk;
+};
+
+static void rockchip_dfi_start_hardware_counter(struct devfreq_event_dev *edev)
+{
+   struct rockchip_dfi *info = devfreq_event_get_drvdata(edev);
+   void __iomem *dfi_regs = info->regs;
+   u32 val;
+   u32 ddr_type;
+
+   /* get ddr type */
+   regmap_read(info->regmap_pmu, PMUGRF_OS_REG2, );
+   ddr_type = (val >> DDRTYPE_SHIFT) & DDRTYPE_MASK;
+
+   /* clear DDRMON_CTRL setting */
+   writel_relaxed(CLR_DDRMON_CTRL, dfi_regs + DDRMON_CTRL);
+
+   /* set ddr type to dfi */
+   if (ddr_type == LPDDR3)
+   writel_relaxed(LPDDR3_EN, dfi_regs + DDRMON_CTRL);
+   else if (ddr_type == LPDDR4)
+   writel_relaxed(LPDDR4_EN, dfi_regs + DDRMON_CTRL);
+
+   /* enable count, use software mode */
+   writel_relaxed(SOFTWARE_EN, dfi_regs + DDRMON_CTRL);
+}
+
+static void rockchip_dfi_stop_hardware_counter(struct devfreq_event_dev *edev)
+{
+   struct rockchip_dfi *info = devfreq_event_get_drvdata(edev);
+   void __iomem *dfi_regs = info->regs;
+   u32 val;
+
+   val = readl_relaxed(dfi_regs + DDRMON_CTRL);
+   val &= ~SOFTWARE_EN;
+   writel_relaxed(val, dfi_regs + DDRMON_CTRL);
+}
+
+static int rockchip_dfi_get_busier_ch(struct devfreq_event_dev *edev)
+{
+   struct rockchip_dfi *info = devfreq_event_get_drvdata(edev);
+   u32 tmp, max = 0;
+   u32 i, busier_ch = 0;
+   void 

[PATCH v5 5/8] PM / devfreq: event: support rockchip dfi controller

2016-08-09 Thread Lin Huang
on rk3399 platform, there is dfi conroller can monitor
ddr load, base on this result, we can do ddr freqency
scaling.

Signed-off-by: Lin Huang 
Acked-by: Chanwoo Choi 
---
Changes in v5:
-None

Changes in v4:
-None

Changes in v3:
-None

Changes in v2:
-None 

Changes in v1:
-None

 drivers/devfreq/event/Kconfig|   7 +
 drivers/devfreq/event/Makefile   |   1 +
 drivers/devfreq/event/rockchip-dfi.c | 253 +++
 3 files changed, 261 insertions(+)
 create mode 100644 drivers/devfreq/event/rockchip-dfi.c

diff --git a/drivers/devfreq/event/Kconfig b/drivers/devfreq/event/Kconfig
index eb6f74a..20d82c2 100644
--- a/drivers/devfreq/event/Kconfig
+++ b/drivers/devfreq/event/Kconfig
@@ -30,4 +30,11 @@ config DEVFREQ_EVENT_EXYNOS_PPMU
  (Platform Performance Monitoring Unit) counters to estimate the
  utilization of each module.
 
+config DEVFREQ_EVENT_ROCKCHIP_DFI
+   tristate "ROCKCHIP DFI DEVFREQ event Driver"
+   depends on ARCH_ROCKCHIP
+   help
+ This add the devfreq-event driver for Rockchip SoC. It provides DFI
+ (DDR Monitor Module) driver to count ddr load.
+
 endif # PM_DEVFREQ_EVENT
diff --git a/drivers/devfreq/event/Makefile b/drivers/devfreq/event/Makefile
index 3d6afd3..dda7090 100644
--- a/drivers/devfreq/event/Makefile
+++ b/drivers/devfreq/event/Makefile
@@ -2,3 +2,4 @@
 
 obj-$(CONFIG_DEVFREQ_EVENT_EXYNOS_NOCP) += exynos-nocp.o
 obj-$(CONFIG_DEVFREQ_EVENT_EXYNOS_PPMU) += exynos-ppmu.o
+obj-$(CONFIG_DEVFREQ_EVENT_ROCKCHIP_DFI) += rockchip-dfi.o
diff --git a/drivers/devfreq/event/rockchip-dfi.c 
b/drivers/devfreq/event/rockchip-dfi.c
new file mode 100644
index 000..3f12be7
--- /dev/null
+++ b/drivers/devfreq/event/rockchip-dfi.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2016, Fuzhou Rockchip Electronics Co., Ltd
+ * Author: Lin Huang 
+ *
+ * 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 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define RK3399_DMC_NUM_CH  2
+
+/* DDRMON_CTRL */
+#define DDRMON_CTRL0x04
+#define CLR_DDRMON_CTRL(0x1f << 0)
+#define LPDDR4_EN  (0x10001 << 4)
+#define HARDWARE_EN(0x10001 << 3)
+#define LPDDR3_EN  (0x10001 << 2)
+#define SOFTWARE_EN(0x10001 << 1)
+#define TIME_CNT_EN(0x10001 << 0)
+
+#define DDRMON_CH0_COUNT_NUM   0x28
+#define DDRMON_CH0_DFI_ACCESS_NUM  0x2c
+#define DDRMON_CH1_COUNT_NUM   0x3c
+#define DDRMON_CH1_DFI_ACCESS_NUM  0x40
+
+/* pmu grf */
+#define PMUGRF_OS_REG2 0x308
+#define DDRTYPE_SHIFT  13
+#define DDRTYPE_MASK   7
+
+enum {
+   DDR3 = 3,
+   LPDDR3 = 6,
+   LPDDR4 = 7,
+   UNUSED = 0xFF
+};
+
+struct dmc_usage {
+   u32 access;
+   u32 total;
+};
+
+struct rockchip_dfi {
+   struct devfreq_event_dev *edev;
+   struct devfreq_event_desc *desc;
+   struct dmc_usage ch_usage[RK3399_DMC_NUM_CH];
+   struct device *dev;
+   void __iomem *regs;
+   struct regmap *regmap_pmu;
+   struct clk *clk;
+};
+
+static void rockchip_dfi_start_hardware_counter(struct devfreq_event_dev *edev)
+{
+   struct rockchip_dfi *info = devfreq_event_get_drvdata(edev);
+   void __iomem *dfi_regs = info->regs;
+   u32 val;
+   u32 ddr_type;
+
+   /* get ddr type */
+   regmap_read(info->regmap_pmu, PMUGRF_OS_REG2, );
+   ddr_type = (val >> DDRTYPE_SHIFT) & DDRTYPE_MASK;
+
+   /* clear DDRMON_CTRL setting */
+   writel_relaxed(CLR_DDRMON_CTRL, dfi_regs + DDRMON_CTRL);
+
+   /* set ddr type to dfi */
+   if (ddr_type == LPDDR3)
+   writel_relaxed(LPDDR3_EN, dfi_regs + DDRMON_CTRL);
+   else if (ddr_type == LPDDR4)
+   writel_relaxed(LPDDR4_EN, dfi_regs + DDRMON_CTRL);
+
+   /* enable count, use software mode */
+   writel_relaxed(SOFTWARE_EN, dfi_regs + DDRMON_CTRL);
+}
+
+static void rockchip_dfi_stop_hardware_counter(struct devfreq_event_dev *edev)
+{
+   struct rockchip_dfi *info = devfreq_event_get_drvdata(edev);
+   void __iomem *dfi_regs = info->regs;
+   u32 val;
+
+   val = readl_relaxed(dfi_regs + DDRMON_CTRL);
+   val &= ~SOFTWARE_EN;
+   writel_relaxed(val, dfi_regs + DDRMON_CTRL);
+}
+
+static int rockchip_dfi_get_busier_ch(struct devfreq_event_dev *edev)
+{
+   struct rockchip_dfi *info = devfreq_event_get_drvdata(edev);
+   u32 tmp, max = 0;
+   u32 i, busier_ch = 0;
+   void __iomem *dfi_regs = info->regs;
+
+