ddr: add driver for ddr bandwidth measure
authortao zeng <tao.zeng@amlogic.com>
Mon, 26 Mar 2018 02:54:55 +0000 (10:54 +0800)
committerYixun Lan <yixun.lan@amlogic.com>
Mon, 2 Apr 2018 01:46:47 +0000 (17:46 -0800)
PD#161475: ddr : add driver for ddr bandwidth measure

1. change dtsi for related chips;
2. porting driver for each dmc contoller;
3. export sysfs for debug and upper layer.

Change-Id: Iaac6ac671bae26d9bff9c7a480ef44e2b0912b3c
Signed-off-by: tao zeng <tao.zeng@amlogic.com>
21 files changed:
MAINTAINERS
arch/arm/boot/dts/amlogic/meson8b.dtsi
arch/arm64/boot/dts/amlogic/mesonaxg.dtsi
arch/arm64/boot/dts/amlogic/mesong12a.dtsi
arch/arm64/boot/dts/amlogic/mesongxl.dtsi
arch/arm64/boot/dts/amlogic/mesongxm.dtsi
arch/arm64/boot/dts/amlogic/mesontxlx.dtsi
arch/arm64/configs/meson64_defconfig
drivers/amlogic/Kconfig
drivers/amlogic/Makefile
drivers/amlogic/ddr_tool/Kconfig [new file with mode: 0644]
drivers/amlogic/ddr_tool/Makefile [new file with mode: 0644]
drivers/amlogic/ddr_tool/ddr_band_op_g12.c [new file with mode: 0644]
drivers/amlogic/ddr_tool/ddr_band_op_gx.c [new file with mode: 0644]
drivers/amlogic/ddr_tool/ddr_band_op_gxl.c [new file with mode: 0644]
drivers/amlogic/ddr_tool/ddr_band_port_desc.c [new file with mode: 0644]
drivers/amlogic/ddr_tool/ddr_bandwidth.c [new file with mode: 0644]
drivers/amlogic/ddr_tool/ddr_window.c [moved from drivers/amlogic/ddr_window/ddr_window.c with 99% similarity]
drivers/amlogic/ddr_window/Kconfig [deleted file]
drivers/amlogic/ddr_window/Makefile [deleted file]
include/linux/amlogic/aml_ddr_bandwidth.h [new file with mode: 0644]

index af6c084..ba60c00 100644 (file)
@@ -13494,6 +13494,10 @@ AMLOGIC driver for thermal
 M: Tao Zeng <tao.zeng@amlogic.com>
 F: drivers/amlogic/thermal/*
 
+M: Tao Zeng <tao.zeng@amlogic.com>
+F: drivers/amlogic/ddr_tool/*
+F: drivers/amlogic/ddr_tool/ddr_band_port_desc.c
+
 AMLOGIC driver for cpufreq
 M: Tao Zeng <tao.zeng@amlogic.com>
 F: drivers/amlogic/cpufreq/*
@@ -14014,12 +14018,6 @@ AMLOGIC AXG ADD CLKMSR INTERFACE
 M:     wang xing <xing.wang@amlogic.com>
 F:     include/linux/amlogic/clk_measure.h
 
-AMLOGIC AXG ADD DDR WINDOW DRIVER
-M:     jiaxing.ye <jiaxing.ye@amlogic.com>
-F:     driver/amlogic/ddr_window/Makefile
-F:     driver/amlogic/ddr_window/ddr_window.c
-F:     driver/amlogic/ddr_window/Kconfig
-
 AMLOGIC AUDIO INFO
 M:     wang xing <xing.wang@amlogic.com>
 F: drivers/amlogic/audioinfo/
index 6bb0183..320c498 100644 (file)
@@ -950,4 +950,13 @@ dwc2_b {
        };
 
        }; /* end of soc*/
+
+       ddr_bandwidth {
+               compatible = "amlogic, ddr-bandwidth";
+               status = "okay";
+               reg = <0x0 0xc8006000 0x0 0x100
+                      0x0 0xc8000400 0x0 0x100>;
+               interrupts = <0 52 1>;
+               interrupt-names = "ddr_bandwidth";
+       };
 }; /* end of / */
index f1c60e1..51157cf 100644 (file)
                query_licence_cmd = <0x82000050>;
                status = "disabled";
        };
+
+       ddr_bandwidth {
+               compatible = "amlogic, ddr-bandwidth";
+               status = "okay";
+               reg = <0x0 0xff638000 0x0 0x100
+                      0x0 0xff637000 0x0 0x100>;
+               interrupts = <0 52 1>;
+               interrupt-names = "ddr_bandwidth";
+       };
 };/* end of / */
 
 &pinctrl_aobus {
index 50e1226..1cbce22 100644 (file)
                        <731000 100>;
                status = "okay";
         };
+
+       ddr_bandwidth {
+               compatible = "amlogic, ddr-bandwidth";
+               status = "okay";
+               reg = <0x0 0xff638000 0x0 0x100
+                      0x0 0xff638c00 0x0 0x100>;
+               interrupts = <0 52 1>;
+               interrupt-names = "ddr_bandwidth";
+       };
 };/* end of / */
 
 &pinctrl_aobus {
index 8593f94..079ba18 100644 (file)
                clock-names = "clkin0","clkin1","clkin2","clkin3";
                status = "disabled";
        };
+       ddr_bandwidth {
+               compatible = "amlogic, ddr-bandwidth";
+               status = "okay";
+               reg = <0x0 0xc8838000 0x0 0x100
+                      0x0 0xc8837000 0x0 0x100>;
+               interrupts = <0 52 1>;
+               interrupt-names = "ddr_bandwidth";
+       };
 };
 
 &gpu{
index eab2a40..627b956 100644 (file)
                clock-names = "clkin0","clkin1","clkin2","clkin3";
                status = "disabled";
        };
+       ddr_bandwidth {
+               compatible = "amlogic, ddr-bandwidth";
+               status = "okay";
+               reg = <0x0 0xc8838000 0x0 0x100
+                      0x0 0xc8837000 0x0 0x100>;
+               interrupts = <0 52 1>;
+               interrupt-names = "ddr_bandwidth";
+       };
 };
 
index 482289f..5fe22b9 100644 (file)
                        };
                };/* end of hiubus*/
        }; /* end of soc*/
+       ddr_bandwidth {
+               compatible = "amlogic, ddr-bandwidth";
+               status = "okay";
+               reg = <0x0 0xff638000 0x0 0x100
+                      0x0 0xff637000 0x0 0x100>;
+               interrupts = <0 52 1>;
+               interrupt-names = "ddr_bandwidth";
+       };
 }; /* end of / */
 
 &pinctrl_aobus {
index d3a1700..ab18d7e 100644 (file)
@@ -342,7 +342,8 @@ CONFIG_AMLOGIC_PCIE=y
 CONFIG_AMLOGIC_IRBLASTER=y
 CONFIG_AMLOGIC_IIO=y
 CONFIG_AMLOGIC_SARADC=y
-CONFIG_AMLOGIC_DDR_WINDOW_TOOL=m
+CONFIG_AMLOGIC_DDR_TOOL=y
+CONFIG_AMLOGIC_DDR_BANDWIDTH=y
 CONFIG_AMLOGIC_TEE=y
 CONFIG_AMLOGIC_GPIO_IRQ=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
index be057ed..329b208 100644 (file)
@@ -112,7 +112,7 @@ source "drivers/amlogic/irblaster/Kconfig"
 
 source "drivers/amlogic/iio/Kconfig"
 
-source "drivers/amlogic/ddr_window/Kconfig"
+source "drivers/amlogic/ddr_tool/Kconfig"
 
 source "drivers/amlogic/drm/Kconfig"
 
index 2805351..77bea31 100644 (file)
@@ -103,7 +103,7 @@ obj-$(CONFIG_AMLOGIC_IRBLASTER) += irblaster/
 
 obj-$(CONFIG_AMLOGIC_IIO)       += iio/
 
-obj-$(CONFIG_AMLOGIC_DDR_WINDOW_TOOL)       += ddr_window/
+obj-$(CONFIG_AMLOGIC_DDR_TOOL)       += ddr_tool/
 
 obj-$(CONFIG_DRM_MESON)        += drm/
 
diff --git a/drivers/amlogic/ddr_tool/Kconfig b/drivers/amlogic/ddr_tool/Kconfig
new file mode 100644 (file)
index 0000000..b6ffb87
--- /dev/null
@@ -0,0 +1,28 @@
+config AMLOGIC_DDR_TOOL
+       bool "Meson cpu ddr tool"
+       depends on AMLOGIC_DRIVER
+       default n
+       help
+         This config add some debug tools for DDR, including test ddr
+         bandwidth, ddr window and other configs.
+         For more information.
+         Please see folllowing configs
+
+config AMLOGIC_DDR_WINDOW_TOOL
+       bool "Meson ddr window tool"
+       default n
+       depends on AMLOGIC_DDR_TOOL
+       help
+         This config enables test for ddr window.
+         This driver acts as a kernel agent which set different ddr window
+         register value from user space, user space can generate large ddr
+         loading to test each value are stable.
+
+config AMLOGIC_DDR_BANDWIDTH
+       bool "Meson ddr bandwidth"
+       default n
+       depends on AMLOGIC_DDR_TOOL
+       help
+         This config enables ddr bandwidth measure.
+         If open it, this driver will export interface to get ddr total
+         bandwidth, it can be used for ddr DVFS/devfreq system.
diff --git a/drivers/amlogic/ddr_tool/Makefile b/drivers/amlogic/ddr_tool/Makefile
new file mode 100644 (file)
index 0000000..a3a52b2
--- /dev/null
@@ -0,0 +1,5 @@
+obj-$(CONFIG_AMLOGIC_DDR_WINDOW_TOOL)  += ddr_window.o
+obj-$(CONFIG_AMLOGIC_DDR_BANDWIDTH)    += ddr_bandwidth.o ddr_band_op_gxl.o \
+                                          ddr_band_op_gx.o ddr_band_op_g12.o \
+                                          ddr_band_port_desc.o
+
diff --git a/drivers/amlogic/ddr_tool/ddr_band_op_g12.c b/drivers/amlogic/ddr_tool/ddr_band_op_g12.c
new file mode 100644 (file)
index 0000000..1fb0000
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * drivers/amlogic/ddr_tool/ddr_band_op_g12.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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/version.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/printk.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/sysfs.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/amlogic/cpu_version.h>
+#include <linux/amlogic/aml_ddr_bandwidth.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+static void g12_dmc_port_config(struct ddr_bandwidth *db, int channel, int port)
+{
+       unsigned int val;
+       unsigned int rp[MAX_CHANNEL] = {DMC_MON_G12_CTRL1, DMC_MON_G12_CTRL3,
+                                       DMC_MON_G12_CTRL5, DMC_MON_G12_CTRL7};
+       unsigned int rs[MAX_CHANNEL] = {DMC_MON_G12_CTRL2, DMC_MON_G12_CTRL4,
+                                       DMC_MON_G12_CTRL6, DMC_MON_G12_CTRL8};
+       int subport = -1;
+
+       if (port >= PORT_MAJOR)
+               subport = port - PORT_MAJOR;
+
+       if (subport < 0) {
+               val = readl(db->ddr_reg + rp[channel]);
+               val &= ~(0xffffff << 0);
+               val |=  (1 << port);
+               writel(val, db->ddr_reg + rp[channel]);
+               val = 0xffff;
+               writel(val, db->ddr_reg + rs[channel]);
+       } else {
+               val = (0x1 << 23);      /* select device */
+               writel(val, db->ddr_reg + rp[channel]);
+               val = readl(db->ddr_reg + rs[channel]);
+               val &= ~(0xffff);
+               val |= (1 << subport);
+               writel(val, db->ddr_reg + rs[channel]);
+       }
+}
+
+static unsigned long g12_get_ddr_freq_quick(struct ddr_bandwidth *db)
+{
+       unsigned int val;
+       unsigned int n, m, od1;
+       unsigned int od_div = 0xfff;
+       unsigned long freq = 0;
+
+       val = readl(db->pll_reg);
+       val = val & 0xfffff;
+       switch ((val >> 16) & 7) {
+       case 0:
+               od_div = 2;
+               break;
+
+       case 1:
+               od_div = 3;
+               break;
+
+       case 2:
+               od_div = 4;
+               break;
+
+       case 3:
+               od_div = 6;
+               break;
+
+       case 4:
+               od_div = 8;
+               break;
+
+       default:
+               break;
+       }
+
+       m = val & 0x1ff;
+       n = ((val >> 10) & 0x1f);
+       od1 = (((val >> 19) & 0x1)) == 1 ? 2 : 1;
+       if (n)
+               freq = 2 * (((DEFAULT_XTAL_FREQ * m) / n) >> od1) / od_div;
+
+       return freq;
+}
+
+static void g12_dmc_bandwidth_enable(struct ddr_bandwidth *db)
+{
+       unsigned int val;
+
+       /* enable all channel */
+       val =  (0x01 << 31) |   /* enable bit */
+              (0x01 << 20) |   /* use timer  */
+              (0x0f <<  0);
+       writel(val, db->ddr_reg + DMC_MON_G12_CTRL0);
+}
+
+static void g12_dmc_bandwidth_init(struct ddr_bandwidth *db)
+{
+       unsigned int i;
+
+       /* set timer trigger clock_cnt */
+       writel(db->clock_count, db->ddr_reg + DMC_MON_G12_TIMER);
+       g12_dmc_bandwidth_enable(db);
+
+       for (i = 0; i < db->channels; i++)
+               g12_dmc_port_config(db, i, db->port[i]);
+}
+
+static int g12_handle_irq(struct ddr_bandwidth *db, struct ddr_grant *dg)
+{
+       unsigned int reg, i, val;
+       int ret = -1;
+
+       val = readl(db->ddr_reg + DMC_MON_G12_CTRL0);
+       if (val & DMC_QOS_IRQ) {
+               /*
+                * get total bytes by each channel, each cycle 16 bytes;
+                */
+               dg->all_grant = readl(db->ddr_reg + DMC_MON_G12_ALL_GRANT_CNT);
+               dg->all_req   = readl(db->ddr_reg + DMC_MON_G12_ALL_REQ_CNT);
+               dg->all_grant *= 16;
+               dg->all_req   *= 16;
+               for (i = 0; i < db->channels; i++) {
+                       reg = DMC_MON_G12_ONE_GRANT_CNT + (i << 2);
+                       dg->channel_grant[i] = readl(db->ddr_reg + reg) * 16;
+               }
+               /* clear irq flags */
+               writel(val, db->ddr_reg + DMC_MON_G12_CTRL0);
+               g12_dmc_bandwidth_enable(db);
+
+               ret = 0;
+       }
+       return ret;
+}
+
+#if DDR_BANDWIDTH_DEBUG
+static int g12_dump_reg(struct ddr_bandwidth *db, char *buf)
+{
+       int s = 0, i;
+       unsigned int r;
+
+       for (i = 0; i < 9; i++) {
+               r  = readl(db->ddr_reg + (DMC_MON_G12_CTRL0 + (i << 2)));
+               s += sprintf(buf + s, "DMC_MON_CTRL%d:        %08x\n", i, r);
+       }
+       r  = readl(db->ddr_reg + DMC_MON_G12_ALL_REQ_CNT);
+       s += sprintf(buf + s, "DMC_MON_ALL_REQ_CNT:  %08x\n", r);
+       r  = readl(db->ddr_reg + DMC_MON_G12_ALL_GRANT_CNT);
+       s += sprintf(buf + s, "DMC_MON_ALL_GRANT_CNT:%08x\n", r);
+       r  = readl(db->ddr_reg + DMC_MON_G12_ONE_GRANT_CNT);
+       s += sprintf(buf + s, "DMC_MON_ONE_GRANT_CNT:%08x\n", r);
+       r  = readl(db->ddr_reg + DMC_MON_G12_SEC_GRANT_CNT);
+       s += sprintf(buf + s, "DMC_MON_SEC_GRANT_CNT:%08x\n", r);
+       r  = readl(db->ddr_reg + DMC_MON_G12_THD_GRANT_CNT);
+       s += sprintf(buf + s, "DMC_MON_THD_GRANT_CNT:%08x\n", r);
+       r  = readl(db->ddr_reg + DMC_MON_G12_FOR_GRANT_CNT);
+       s += sprintf(buf + s, "DMC_MON_FOR_GRANT_CNT:%08x\n", r);
+       r  = readl(db->ddr_reg + DMC_MON_G12_TIMER);
+       s += sprintf(buf + s, "DMC_MON_TIMER:        %08x\n", r);
+
+       return s;
+}
+#endif
+
+struct ddr_bandwidth_ops g12_ddr_bw_ops = {
+       .init             = g12_dmc_bandwidth_init,
+       .config_port      = g12_dmc_port_config,
+       .get_freq         = g12_get_ddr_freq_quick,
+       .handle_irq       = g12_handle_irq,
+       .bandwidth_enable = g12_dmc_bandwidth_enable,
+#if DDR_BANDWIDTH_DEBUG
+       .dump_reg         = g12_dump_reg,
+#endif
+};
diff --git a/drivers/amlogic/ddr_tool/ddr_band_op_gx.c b/drivers/amlogic/ddr_tool/ddr_band_op_gx.c
new file mode 100644 (file)
index 0000000..1f206cc
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * drivers/amlogic/ddr_tool/ddr_band_op_gx.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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/version.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/printk.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/sysfs.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/amlogic/cpu_version.h>
+#include <linux/amlogic/aml_ddr_bandwidth.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+
+static void gx_dmc_port_config(struct ddr_bandwidth *db, int channel, int port)
+{
+       unsigned int val;
+       int subport = -1;
+
+       if (port >= PORT_MAJOR)
+               subport = port - PORT_MAJOR;
+
+       val = readl(db->ddr_reg + DMC_MON_CTRL2);
+       if (subport < 0) {
+               val &= ~(0xfffff << 0);
+               val |= ((port << 16) | 0xffff);
+       } else {
+               val &= ~(0xffff);
+               if (db->cpu_type == MESON_CPU_MAJOR_ID_M8B)
+                       val |= (0xf << 16) | (1 << subport);
+               else
+                       val |= (0x7 << 16) | (1 << subport);
+       }
+       writel(val, db->ddr_reg + DMC_MON_CTRL2);
+}
+
+
+static unsigned long gx_get_ddr_freq_quick(struct ddr_bandwidth *db)
+{
+       unsigned int val;
+       unsigned int od, n, m, od1;
+       unsigned long freq = 0;
+
+       val = readl(db->pll_reg);
+       od  = (val >> 16) & 0x03;
+       n   = (val >>  9) & 0x1f;
+       m   = (val >>  0) & 0x1ff;
+       od1 = 0;
+       if ((db->cpu_type >= MESON_CPU_MAJOR_ID_GXBB) &&
+                   (db->cpu_type < MESON_CPU_MAJOR_ID_GXL)) {
+               od1 = (val >> 14) & 0x03;
+       }
+       freq = (DEFAULT_XTAL_FREQ * m / (n * (1 + od))) >> od1;
+       return freq;
+}
+
+static void gx_dmc_bandwidth_enable(struct ddr_bandwidth *db)
+{
+       /*
+        * for old chips, only 1 port can be selected
+        */
+       writel(0x8010ffff, db->ddr_reg + DMC_MON_CTRL2);
+}
+
+static void gx_dmc_bandwidth_init(struct ddr_bandwidth *db)
+{
+       /* set timer trigger clock_cnt */
+       writel(db->clock_count, db->ddr_reg + DMC_MON_CTRL3);
+       gx_dmc_bandwidth_enable(db);
+
+       gx_dmc_port_config(db, 0, db->port[0]);
+}
+
+static int gx_handle_irq(struct ddr_bandwidth *db, struct ddr_grant *dg)
+{
+       unsigned int reg, val;
+       int ret = -1;
+
+       val = readl(db->ddr_reg + DMC_MON_CTRL2);
+       if (val & DMC_QOS_IRQ) {
+               /*
+                * get total bytes by each channel, each cycle 16 bytes;
+                */
+               dg->all_grant = readl(db->ddr_reg + DMC_MON_ALL_GRANT_CNT) * 16;
+               dg->all_req   = readl(db->ddr_reg + DMC_MON_ALL_REQ_CNT) * 16;
+               reg = DMC_MON_ONE_GRANT_CNT;
+               dg->channel_grant[0] = readl(db->ddr_reg + reg) * 16;
+               /* clear irq flags */
+               writel(val, db->ddr_reg + DMC_MON_CTRL2);
+               gx_dmc_bandwidth_enable(db);
+               ret = 0;
+       }
+       return ret;
+}
+
+#if DDR_BANDWIDTH_DEBUG
+static int gx_dump_reg(struct ddr_bandwidth *db, char *buf)
+{
+       int s = 0;
+       unsigned int r;
+
+       r  = readl(db->ddr_reg + DMC_MON_CTRL2);
+       s += sprintf(buf + s, "DMC_MON_CTRL2:        %08x\n", r);
+       r  = readl(db->ddr_reg + DMC_MON_CTRL3);
+       s += sprintf(buf + s, "DMC_MON_CTRL3:        %08x\n", r);
+       r  = readl(db->ddr_reg + DMC_MON_ALL_REQ_CNT);
+       s += sprintf(buf + s, "DMC_MON_ALL_REQ_CNT:  %08x\n", r);
+       r  = readl(db->ddr_reg + DMC_MON_ALL_GRANT_CNT);
+       s += sprintf(buf + s, "DMC_MON_ALL_GRANT_CNT:%08x\n", r);
+       r  = readl(db->ddr_reg + DMC_MON_ONE_GRANT_CNT);
+       s += sprintf(buf + s, "DMC_MON_ONE_GRANT_CNT:%08x\n", r);
+
+       return s;
+}
+#endif
+
+struct ddr_bandwidth_ops gx_ddr_bw_ops = {
+       .init             = gx_dmc_bandwidth_init,
+       .config_port      = gx_dmc_port_config,
+       .get_freq         = gx_get_ddr_freq_quick,
+       .handle_irq       = gx_handle_irq,
+       .bandwidth_enable = gx_dmc_bandwidth_enable,
+#if DDR_BANDWIDTH_DEBUG
+       .dump_reg         = gx_dump_reg,
+#endif
+};
diff --git a/drivers/amlogic/ddr_tool/ddr_band_op_gxl.c b/drivers/amlogic/ddr_tool/ddr_band_op_gxl.c
new file mode 100644 (file)
index 0000000..01dea7c
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * drivers/amlogic/ddr_tool/ddr_band_op_gxl.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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/version.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/printk.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/sysfs.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/amlogic/cpu_version.h>
+#include <linux/amlogic/aml_ddr_bandwidth.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+static void gxl_dmc_port_config(struct ddr_bandwidth *db, int channel, int port)
+{
+       unsigned int val;
+       unsigned int port_reg[MAX_CHANNEL] = {DMC_MON_CTRL1, DMC_MON_CTRL4,
+                                             DMC_MON_CTRL5, DMC_MON_CTRL6};
+       int subport = -1;
+
+       if (port >= PORT_MAJOR)
+               subport = port - PORT_MAJOR;
+
+       val = readl(db->ddr_reg + port_reg[channel]);
+       if (subport < 0) {
+               val &= ~(0xffff << 16);
+               val |= ((1 << (16 + port)) | 0xffff);
+       } else {
+               val &= ~(0xffffffff);
+               val |= (1 << 23) | (1 << subport);
+       }
+       writel(val, db->ddr_reg + port_reg[channel]);
+}
+
+static unsigned long gxl_get_ddr_freq_quick(struct ddr_bandwidth *db)
+{
+       unsigned int val;
+       unsigned int od, n, m, od1;
+       unsigned long freq = 0;
+
+       val  = readl(db->pll_reg);
+       od   = (val >>  2) & 0x03;
+       m    = (val >>  4) & 0x1ff;
+       n    = (val >> 16) & 0x1f;
+       od1  = (val >>  0) & 0x03;
+       freq = (DEFAULT_XTAL_FREQ * m / (n * (1 + od))) >> od1;
+       return freq;
+}
+
+static void gxl_dmc_bandwidth_enable(struct ddr_bandwidth *db)
+{
+       unsigned int val;
+
+       /* enable all channel */
+       val =  (0x01 << 31) |   /* enable bit */
+              (0x01 << 20) |   /* use timer  */
+              (0x0f <<  0);
+       writel(val, db->ddr_reg + DMC_MON_CTRL2);
+}
+
+static void gxl_dmc_bandwidth_init(struct ddr_bandwidth *db)
+{
+       unsigned int i;
+
+       /* set timer trigger clock_cnt */
+       writel(db->clock_count, db->ddr_reg + DMC_MON_CTRL3);
+       gxl_dmc_bandwidth_enable(db);
+
+       for (i = 0; i < db->channels; i++)
+               gxl_dmc_port_config(db, i, db->port[i]);
+}
+
+
+static int gxl_handle_irq(struct ddr_bandwidth *db, struct ddr_grant *dg)
+{
+       unsigned int reg, i, val;
+       int ret = -1;
+
+       val = readl(db->ddr_reg + DMC_MON_CTRL2);
+       if (val & DMC_QOS_IRQ) {
+               /*
+                * get total bytes by each channel, each cycle 16 bytes;
+                */
+               dg->all_grant = readl(db->ddr_reg + DMC_MON_ALL_GRANT_CNT) * 16;
+               dg->all_req   = readl(db->ddr_reg + DMC_MON_ALL_REQ_CNT) * 16;
+               for (i = 0; i < db->channels; i++) {
+                       reg = DMC_MON_ONE_GRANT_CNT + (i << 2);
+                       dg->channel_grant[i] = readl(db->ddr_reg + reg) * 16;
+               }
+               /* clear irq flags */
+               writel(val, db->ddr_reg + DMC_MON_CTRL2);
+               gxl_dmc_bandwidth_enable(db);
+               ret = 0;
+       }
+       return ret;
+}
+
+#if DDR_BANDWIDTH_DEBUG
+static int gxl_dump_reg(struct ddr_bandwidth *db, char *buf)
+{
+       int s = 0;
+       unsigned int r;
+
+
+       r  = readl(db->ddr_reg + DMC_MON_CTRL1);
+       s += sprintf(buf + s, "DMC_MON_CTRL1:        %08x\n", r);
+       r  = readl(db->ddr_reg + DMC_MON_CTRL2);
+       s += sprintf(buf + s, "DMC_MON_CTRL2:        %08x\n", r);
+       r  = readl(db->ddr_reg + DMC_MON_CTRL3);
+       s += sprintf(buf + s, "DMC_MON_CTRL3:        %08x\n", r);
+       r  = readl(db->ddr_reg + DMC_MON_CTRL4);
+       s += sprintf(buf + s, "DMC_MON_CTRL4:        %08x\n", r);
+       r  = readl(db->ddr_reg + DMC_MON_CTRL5);
+       s += sprintf(buf + s, "DMC_MON_CTRL5:        %08x\n", r);
+       r  = readl(db->ddr_reg + DMC_MON_CTRL6);
+       s += sprintf(buf + s, "DMC_MON_CTRL6:        %08x\n", r);
+
+       r  = readl(db->ddr_reg + DMC_MON_ALL_REQ_CNT);
+       s += sprintf(buf + s, "DMC_MON_ALL_REQ_CNT:  %08x\n", r);
+       r  = readl(db->ddr_reg + DMC_MON_ALL_GRANT_CNT);
+       s += sprintf(buf + s, "DMC_MON_ALL_GRANT_CNT:%08x\n", r);
+       r  = readl(db->ddr_reg + DMC_MON_ONE_GRANT_CNT);
+       s += sprintf(buf + s, "DMC_MON_ONE_GRANT_CNT:%08x\n", r);
+       r  = readl(db->ddr_reg + DMC_MON_SEC_GRANT_CNT);
+       s += sprintf(buf + s, "DMC_MON_SEC_GRANT_CNT:%08x\n", r);
+       r  = readl(db->ddr_reg + DMC_MON_THD_GRANT_CNT);
+       s += sprintf(buf + s, "DMC_MON_THD_GRANT_CNT:%08x\n", r);
+       r  = readl(db->ddr_reg + DMC_MON_FOR_GRANT_CNT);
+       s += sprintf(buf + s, "DMC_MON_FOR_GRANT_CNT:%08x\n", r);
+
+       return s;
+}
+#endif
+
+struct ddr_bandwidth_ops gxl_ddr_bw_ops = {
+       .init             = gxl_dmc_bandwidth_init,
+       .config_port      = gxl_dmc_port_config,
+       .get_freq         = gxl_get_ddr_freq_quick,
+       .handle_irq       = gxl_handle_irq,
+       .bandwidth_enable = gxl_dmc_bandwidth_enable,
+#if DDR_BANDWIDTH_DEBUG
+       .dump_reg         = gxl_dump_reg,
+#endif
+};
diff --git a/drivers/amlogic/ddr_tool/ddr_band_port_desc.c b/drivers/amlogic/ddr_tool/ddr_band_port_desc.c
new file mode 100644 (file)
index 0000000..8dd9ea5
--- /dev/null
@@ -0,0 +1,463 @@
+/*
+ * drivers/amlogic/ddr_tool/ddr_band_port_desc.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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/version.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/printk.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/sysfs.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/amlogic/cpu_version.h>
+#include <linux/amlogic/aml_ddr_bandwidth.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+static struct ddr_port_desc ddr_port_desc_m8b[] __initdata = {
+       { .port_id =  0, .port_name = "ARM"           },
+       { .port_id =  1, .port_name = "MALI0"         },
+       { .port_id =  2, .port_name = "MALI1"         },
+       { .port_id =  3, .port_name = "HEVC"          },
+       { .port_id =  8, .port_name = "VPU1"          },
+       { .port_id =  9, .port_name = "VPU2"          },
+       { .port_id = 10, .port_name = "VPU3"          },
+       { .port_id = 11, .port_name = "VDEC"          },
+       { .port_id = 12, .port_name = "HCODEC"        },
+       { .port_id = 14, .port_name = "AUDIO"         },
+       /* start of each device */
+       { .port_id = 33, .port_name = "NAND"          },
+       { .port_id = 34, .port_name = "BLKMV"         },
+       { .port_id = 35, .port_name = "ARB0"          },
+       { .port_id = 36, .port_name = "USB0"          },
+       { .port_id = 37, .port_name = "USB1"          },
+       { .port_id = 38, .port_name = "GE2D SOURCE1"  },
+       { .port_id = 39, .port_name = "GE2D SOURCE2"  },
+       { .port_id = 40, .port_name = "GE2D DEST"     },
+       { .port_id = 41, .port_name = "PASER"         },
+       { .port_id = 42, .port_name = "SANA"          },
+       { .port_id = 43, .port_name = "SDIO2"         },
+       { .port_id = 44, .port_name = "SPICC"         },
+       { .port_id = 45, .port_name = "ETHERNET"      }
+};
+
+static struct ddr_port_desc ddr_port_desc_gxbb[] __initdata = {
+       { .port_id =  0, .port_name = "ARM"           },
+       { .port_id =  1, .port_name = "MALI0"         },
+       { .port_id =  2, .port_name = "MALI1"         },
+       { .port_id =  3, .port_name = "HDCP"          },
+       { .port_id =  4, .port_name = "HEVC"          },
+       { .port_id =  8, .port_name = "VPU READ1"     },
+       { .port_id =  9, .port_name = "VPU READ2"     },
+       { .port_id = 10, .port_name = "VPU READ3"     },
+       { .port_id = 11, .port_name = "VPU WRITE1"    },
+       { .port_id = 12, .port_name = "VPU WRITE2"    },
+       { .port_id = 13, .port_name = "VDEC"          },
+       { .port_id = 14, .port_name = "HCODEC"        },
+       { .port_id = 15, .port_name = "GE2D"          },
+       /* start of each device */
+       { .port_id = 32, .port_name = "SD_EMMC_A"     },
+       { .port_id = 33, .port_name = "USB0"          },
+       { .port_id = 34, .port_name = "BLKMV"         },
+       { .port_id = 35, .port_name = "ARB0"          },
+       { .port_id = 36, .port_name = "SD_EMMC_B"     },
+       { .port_id = 37, .port_name = "USB1"          },
+       { .port_id = 38, .port_name = "AUDIO OUT"     },
+       { .port_id = 39, .port_name = "AUDIO IN"      },
+       { .port_id = 40, .port_name = "AIU"           },
+       { .port_id = 41, .port_name = "PASER"         },
+       { .port_id = 42, .port_name = "AO CPU"        },
+       { .port_id = 43, .port_name = "SD_EMMC_C"     },
+       { .port_id = 44, .port_name = "SPICC"         },
+       { .port_id = 45, .port_name = "ETHERNET"      },
+       { .port_id = 46, .port_name = "SANA"          }
+};
+
+static struct ddr_port_desc ddr_port_desc_gxl[] __initdata = {
+       { .port_id =  0, .port_name = "ARM"           },
+       { .port_id =  1, .port_name = "MALI0"         },
+       { .port_id =  2, .port_name = "MALI1"         },
+       { .port_id =  3, .port_name = "HDCP"          },
+       { .port_id =  4, .port_name = "HEVC"          },
+       { .port_id =  5, .port_name = "TEST"          },
+       { .port_id =  6, .port_name = "USB3.0"        },
+       { .port_id =  8, .port_name = "VPU READ1"     },
+       { .port_id =  9, .port_name = "VPU READ2"     },
+       { .port_id = 10, .port_name = "VPU READ3"     },
+       { .port_id = 11, .port_name = "VPU WRITE1"    },
+       { .port_id = 12, .port_name = "VPU WRITE2"    },
+       { .port_id = 13, .port_name = "VDEC"          },
+       { .port_id = 14, .port_name = "HCODEC"        },
+       { .port_id = 15, .port_name = "GE2D"          },
+       /* start of each device */
+       { .port_id = 32, .port_name = "SD_EMMC_A"     },
+       { .port_id = 33, .port_name = "USB0"          },
+       { .port_id = 34, .port_name = "DMA"           },
+       { .port_id = 35, .port_name = "ARB0"          },
+       { .port_id = 36, .port_name = "SD_EMMC_B"     },
+       { .port_id = 37, .port_name = "USB1"          },
+       { .port_id = 38, .port_name = "AUDIO OUT"     },
+       { .port_id = 39, .port_name = "AUDIO IN"      },
+       { .port_id = 40, .port_name = "AIU"           },
+       { .port_id = 41, .port_name = "PASER"         },
+       { .port_id = 42, .port_name = "AO CPU"        },
+       { .port_id = 43, .port_name = "SD_EMMC_C"     },
+       { .port_id = 44, .port_name = "SPICC"         },
+       { .port_id = 45, .port_name = "ETHERNET"      },
+       { .port_id = 46, .port_name = "SANA"          }
+};
+
+static struct ddr_port_desc ddr_port_desc_gxm[] __initdata = {
+       { .port_id =  0, .port_name = "ARM"           },
+       { .port_id =  1, .port_name = "MALI"          },
+       { .port_id =  2, .port_name = "H265ENC"       },
+       { .port_id =  3, .port_name = "HDCP"          },
+       { .port_id =  4, .port_name = "HEVC"          },
+       { .port_id =  5, .port_name = "TEST"          },
+       { .port_id =  6, .port_name = "USB3.0"        },
+       { .port_id =  8, .port_name = "VPU READ1"     },
+       { .port_id =  9, .port_name = "VPU READ2"     },
+       { .port_id = 10, .port_name = "VPU READ3"     },
+       { .port_id = 11, .port_name = "VPU WRITE1"    },
+       { .port_id = 12, .port_name = "VPU WRITE2"    },
+       { .port_id = 13, .port_name = "VDEC"          },
+       { .port_id = 14, .port_name = "HCODEC"        },
+       { .port_id = 15, .port_name = "GE2D"          },
+       /* start of each device */
+       { .port_id = 32, .port_name = "SD_EMMC_A"     },
+       { .port_id = 33, .port_name = "USB0"          },
+       { .port_id = 34, .port_name = "DMA"           },
+       { .port_id = 35, .port_name = "ARB0"          },
+       { .port_id = 36, .port_name = "SD_EMMC_B"     },
+       { .port_id = 37, .port_name = "USB1"          },
+       { .port_id = 38, .port_name = "AUDIO OUT"     },
+       { .port_id = 39, .port_name = "AUDIO IN"      },
+       { .port_id = 40, .port_name = "AIU"           },
+       { .port_id = 41, .port_name = "PASER"         },
+       { .port_id = 42, .port_name = "AO CPU"        },
+       { .port_id = 43, .port_name = "SD_EMMC_C"     },
+       { .port_id = 44, .port_name = "SPICC"         },
+       { .port_id = 45, .port_name = "ETHERNET"      },
+       { .port_id = 46, .port_name = "SANA"          }
+};
+
+static struct ddr_port_desc ddr_port_desc_gxlx[] __initdata = {
+       { .port_id =  0, .port_name = "ARM"           },
+       { .port_id =  1, .port_name = "MALI0"         },
+       { .port_id =  2, .port_name = "MALI1"         },
+       { .port_id =  3, .port_name = "HDCP"          },
+       { .port_id =  4, .port_name = "HEVC"          },
+       { .port_id =  5, .port_name = "H265ENC/TEST"  },
+       { .port_id =  6, .port_name = "USB3.0"        },
+       { .port_id =  8, .port_name = "VPU READ1"     },
+       { .port_id =  9, .port_name = "VPU READ2"     },
+       { .port_id = 10, .port_name = "VPU READ3"     },
+       { .port_id = 11, .port_name = "VPU WRITE1"    },
+       { .port_id = 12, .port_name = "VPU WRITE2"    },
+       { .port_id = 13, .port_name = "VDEC"          },
+       { .port_id = 14, .port_name = "HCODEC"        },
+       { .port_id = 15, .port_name = "GE2D"          },
+       /* start of each device */
+       { .port_id = 32, .port_name = "SD_EMMC_A"     },
+       { .port_id = 33, .port_name = "USB0"          },
+       { .port_id = 34, .port_name = "DMA"           },
+       { .port_id = 35, .port_name = "ARB0"          },
+       { .port_id = 36, .port_name = "SD_EMMC_B"     },
+       { .port_id = 37, .port_name = "USB1"          },
+       { .port_id = 38, .port_name = "AUDIO OUT"     },
+       { .port_id = 39, .port_name = "AUDIO IN"      },
+       { .port_id = 40, .port_name = "AIU"           },
+       { .port_id = 41, .port_name = "PASER"         },
+       { .port_id = 42, .port_name = "AO CPU"        },
+       { .port_id = 43, .port_name = "SD_EMMC_C"     },
+       { .port_id = 44, .port_name = "SPICC"         },
+       { .port_id = 45, .port_name = "ETHERNET"      },
+       { .port_id = 46, .port_name = "SANA"          }
+};
+
+static struct ddr_port_desc ddr_port_desc_g12a[] __initdata = {
+       { .port_id =  0, .port_name = "ARM"           },
+       { .port_id =  1, .port_name = "MALI"          },
+       { .port_id =  2, .port_name = "PCIE"          },
+       { .port_id =  3, .port_name = "HDCP"          },
+       { .port_id =  4, .port_name = "HEVC FRONT"    },
+       { .port_id =  5, .port_name = "TEST"          },
+       { .port_id =  6, .port_name = "USB3.0"        },
+       { .port_id =  8, .port_name = "HEVC BACK"     },
+       { .port_id =  9, .port_name = "H265ENC"       },
+       { .port_id = 16, .port_name = "VPU READ1"     },
+       { .port_id = 17, .port_name = "VPU READ2"     },
+       { .port_id = 18, .port_name = "VPU READ3"     },
+       { .port_id = 19, .port_name = "VPU WRITE1"    },
+       { .port_id = 20, .port_name = "VPU WRITE2"    },
+       { .port_id = 21, .port_name = "VDEC"          },
+       { .port_id = 22, .port_name = "HCODEC"        },
+       { .port_id = 23, .port_name = "GE2D"          },
+       /* start of each device */
+       { .port_id = 32, .port_name = "SPICC1"        },
+       { .port_id = 33, .port_name = "USB0"          },
+       { .port_id = 34, .port_name = "DMA"           },
+       { .port_id = 35, .port_name = "ARB0"          },
+       { .port_id = 36, .port_name = "SD_EMMC_B"     },
+       { .port_id = 37, .port_name = "USB1"          },
+       { .port_id = 38, .port_name = "AUDIO"         },
+       { .port_id = 39, .port_name = "AIFIFO"        },
+       { .port_id = 41, .port_name = "PASER"         },
+       { .port_id = 42, .port_name = "AO CPU"        },
+       { .port_id = 43, .port_name = "SD_EMMC_C"     },
+       { .port_id = 44, .port_name = "SPICC2"        },
+       { .port_id = 45, .port_name = "ETHERNET"      },
+       { .port_id = 46, .port_name = "SANA"          }
+};
+
+static struct ddr_port_desc ddr_port_desc_g12b[] __initdata = {
+       { .port_id =  0, .port_name = "ARM-ADDR-E"    },
+       { .port_id =  1, .port_name = "MALI"          },
+       { .port_id =  2, .port_name = "PCIE"          },
+       { .port_id =  3, .port_name = "HDCP"          },
+       { .port_id =  4, .port_name = "HEVC FRONT"    },
+       { .port_id =  5, .port_name = "TEST"          },
+       { .port_id =  6, .port_name = "USB3.0"        },
+       { .port_id =  8, .port_name = "HEVC BACK"     },
+       { .port_id =  9, .port_name = "H265ENC"       },
+       { .port_id = 10, .port_name = "NNA"           },
+       { .port_id = 11, .port_name = "GDC"           },
+       { .port_id = 12, .port_name = "MIPI ISP"      },
+       { .port_id = 13, .port_name = "ARM-ADDR-F"    },
+       { .port_id = 16, .port_name = "VPU READ1"     },
+       { .port_id = 17, .port_name = "VPU READ2"     },
+       { .port_id = 18, .port_name = "VPU READ3"     },
+       { .port_id = 19, .port_name = "VPU WRITE1"    },
+       { .port_id = 20, .port_name = "VPU WRITE2"    },
+       { .port_id = 21, .port_name = "VDEC"          },
+       { .port_id = 22, .port_name = "HCODEC"        },
+       { .port_id = 23, .port_name = "GE2D"          },
+       /* start of each device */
+       { .port_id = 32, .port_name = "SPICC1"        },
+       { .port_id = 33, .port_name = "USB0"          },
+       { .port_id = 34, .port_name = "DMA"           },
+       { .port_id = 35, .port_name = "ARB0"          },
+       { .port_id = 36, .port_name = "SD_EMMC_B"     },
+       { .port_id = 37, .port_name = "USB1"          },
+       { .port_id = 38, .port_name = "AUDIO"         },
+       { .port_id = 39, .port_name = "AIFIFO"        },
+       { .port_id = 40, .port_name = "SD_EMMC_A"     },
+       { .port_id = 41, .port_name = "PASER"         },
+       { .port_id = 42, .port_name = "AO CPU"        },
+       { .port_id = 43, .port_name = "SD_EMMC_C"     },
+       { .port_id = 44, .port_name = "SPICC2"        },
+       { .port_id = 45, .port_name = "ETHERNET"      },
+       { .port_id = 46, .port_name = "SANA"          }
+};
+
+static struct ddr_port_desc ddr_port_desc_axg[] __initdata = {
+       { .port_id =  0, .port_name = "ARM"           },
+       { .port_id =  1, .port_name = "PCIE-A"        },
+       { .port_id =  2, .port_name = "PCIE-B"        },
+       { .port_id =  3, .port_name = "GE2D"          },
+       { .port_id =  4, .port_name = "AUDIO"         },
+       { .port_id =  5, .port_name = "TEST"          },
+       { .port_id =  6, .port_name = "USB3.0"        },
+       { .port_id =  8, .port_name = "VPU READ0"     },
+       /* start of each device */
+       { .port_id = 34, .port_name = "DMA"           },
+       { .port_id = 35, .port_name = "ARB0"          },
+       { .port_id = 36, .port_name = "SD_EMMC_B"     },
+       { .port_id = 37, .port_name = "USB1"          },
+       { .port_id = 42, .port_name = "AO CPU"        },
+       { .port_id = 43, .port_name = "SD_EMMC_C"     },
+       { .port_id = 44, .port_name = "SPICC0"        },
+       { .port_id = 45, .port_name = "ETHERNET"      },
+       { .port_id = 46, .port_name = "SPICC1"        }
+};
+
+static struct ddr_port_desc ddr_port_desc_txl[] __initdata = {
+       { .port_id =  0, .port_name = "ARM"           },
+       { .port_id =  1, .port_name = "MALI0"         },
+       { .port_id =  2, .port_name = "MALI1"         },
+       { .port_id =  3, .port_name = "HDCP"          },
+       { .port_id =  4, .port_name = "HEVC"          },
+       { .port_id =  5, .port_name = "TEST"          },
+       { .port_id =  6, .port_name = "USB3.0"        },
+       { .port_id =  8, .port_name = "VPU READ1"     },
+       { .port_id =  9, .port_name = "VPU READ2"     },
+       { .port_id = 10, .port_name = "VPU READ3"     },
+       { .port_id = 11, .port_name = "VPU WRITE1"    },
+       { .port_id = 12, .port_name = "VPU WRITE2"    },
+       { .port_id = 13, .port_name = "VDEC"          },
+       { .port_id = 14, .port_name = "HCODEC"        },
+       { .port_id = 15, .port_name = "GE2D"          },
+       /* start of each device */
+       { .port_id = 32, .port_name = "SD_EMMC_A"     },
+       { .port_id = 33, .port_name = "USB0"          },
+       { .port_id = 34, .port_name = "DMA"           },
+       { .port_id = 35, .port_name = "ARB0"          },
+       { .port_id = 36, .port_name = "SD_EMMC_B"     },
+       { .port_id = 37, .port_name = "USB1"          },
+       { .port_id = 38, .port_name = "AUDIO OUT"     },
+       { .port_id = 39, .port_name = "AUDIO IN"      },
+       { .port_id = 40, .port_name = "AIU"           },
+       { .port_id = 41, .port_name = "PASER"         },
+       { .port_id = 42, .port_name = "AO CPU"        },
+       { .port_id = 43, .port_name = "SD_EMMC_C"     },
+       { .port_id = 44, .port_name = "SPICC"         },
+       { .port_id = 45, .port_name = "ETHERNET"      },
+       { .port_id = 46, .port_name = "SANA"          },
+       { .port_id = 47, .port_name = "DEMOD"         }
+};
+
+static struct ddr_port_desc ddr_port_desc_txlx[] __initdata = {
+       { .port_id =  0, .port_name = "ARM"           },
+       { .port_id =  1, .port_name = "MALI0"         },
+       { .port_id =  2, .port_name = "MALI1"         },
+       { .port_id =  3, .port_name = "HDCP"          },
+       { .port_id =  4, .port_name = "HEVC"          },
+       { .port_id =  5, .port_name = "TEST"          },
+       { .port_id =  6, .port_name = "USB3.0"        },
+       { .port_id =  8, .port_name = "VPU READ1"     },
+       { .port_id =  9, .port_name = "VPU READ2"     },
+       { .port_id = 10, .port_name = "VPU READ3"     },
+       { .port_id = 11, .port_name = "VPU WRITE1"    },
+       { .port_id = 12, .port_name = "VPU WRITE2"    },
+       { .port_id = 13, .port_name = "VDEC"          },
+       { .port_id = 14, .port_name = "HCODEC"        },
+       { .port_id = 15, .port_name = "GE2D"          },
+       /* start of each device */
+       { .port_id = 32, .port_name = "SPICC1"        },
+       { .port_id = 33, .port_name = "USB0"          },
+       { .port_id = 34, .port_name = "DMA"           },
+       { .port_id = 35, .port_name = "ARB0"          },
+       { .port_id = 36, .port_name = "SD_EMMC_B"     },
+       { .port_id = 37, .port_name = "USB1"          },
+       { .port_id = 38, .port_name = "AUDIO OUT"     },
+       { .port_id = 39, .port_name = "AUDIO IN"      },
+       { .port_id = 40, .port_name = "AIU"           },
+       { .port_id = 41, .port_name = "PASER"         },
+       { .port_id = 42, .port_name = "AO CPU"        },
+       { .port_id = 43, .port_name = "SD_EMMC_C"     },
+       { .port_id = 44, .port_name = "SPICC"         },
+       { .port_id = 45, .port_name = "ETHERNET"      },
+       { .port_id = 46, .port_name = "SANA"          },
+       { .port_id = 47, .port_name = "DEMOD"         }
+};
+
+static struct ddr_port_desc ddr_port_desc_txhd[] __initdata = {
+       { .port_id =  0, .port_name = "ARM"           },
+       { .port_id =  1, .port_name = "MALI0"         },
+       { .port_id =  2, .port_name = "MALI1"         },
+       { .port_id =  4, .port_name = "HEVC"          },
+       { .port_id =  5, .port_name = "TEST"          },
+       { .port_id =  6, .port_name = "USB3.0"        },
+       { .port_id =  8, .port_name = "VPU READ1"     },
+       { .port_id =  9, .port_name = "VPU READ2"     },
+       { .port_id = 10, .port_name = "VPU READ3"     },
+       { .port_id = 11, .port_name = "VPU WRITE1"    },
+       { .port_id = 12, .port_name = "VPU WRITE2"    },
+       { .port_id = 13, .port_name = "VDEC"          },
+       { .port_id = 14, .port_name = "HCODEC"        },
+       { .port_id = 15, .port_name = "GE2D"          },
+       /* start of each device */
+       { .port_id = 33, .port_name = "USB0"          },
+       { .port_id = 34, .port_name = "DMA"           },
+       { .port_id = 35, .port_name = "ARB0"          },
+       { .port_id = 36, .port_name = "SD_EMMC_B"     },
+       { .port_id = 37, .port_name = "USB1"          },
+       { .port_id = 38, .port_name = "AUDIO OUT"     },
+       { .port_id = 39, .port_name = "AUDIO IN"      },
+       { .port_id = 40, .port_name = "AIU"           },
+       { .port_id = 41, .port_name = "PASER"         },
+       { .port_id = 42, .port_name = "AO CPU"        },
+       { .port_id = 43, .port_name = "SD_EMMC_C"     },
+       { .port_id = 44, .port_name = "SPICC"         },
+       { .port_id = 45, .port_name = "ETHERNET"      },
+       { .port_id = 46, .port_name = "SANA"          },
+       { .port_id = 47, .port_name = "DEMOD"         }
+};
+
+int __init ddr_find_port_desc(int cpu_type, struct ddr_port_desc **desc)
+{
+       int desc_size = -EINVAL;
+
+       switch (cpu_type) {
+       case MESON_CPU_MAJOR_ID_M8B:
+               *desc = ddr_port_desc_m8b;
+               desc_size = ARRAY_SIZE(ddr_port_desc_m8b);
+               break;
+
+       case MESON_CPU_MAJOR_ID_GXBB:
+               *desc = ddr_port_desc_gxbb;
+               desc_size = ARRAY_SIZE(ddr_port_desc_gxbb);
+               break;
+
+       case MESON_CPU_MAJOR_ID_GXTVBB:
+               /* Not used or need implement? */
+               break;
+
+       case MESON_CPU_MAJOR_ID_GXL:
+               *desc = ddr_port_desc_gxl;
+               desc_size = ARRAY_SIZE(ddr_port_desc_gxl);
+               break;
+
+       case MESON_CPU_MAJOR_ID_GXM:
+               *desc = ddr_port_desc_gxm;
+               desc_size = ARRAY_SIZE(ddr_port_desc_gxm);
+               break;
+
+       case MESON_CPU_MAJOR_ID_TXL:
+               *desc = ddr_port_desc_txl;
+               desc_size = ARRAY_SIZE(ddr_port_desc_txl);
+               break;
+
+       case MESON_CPU_MAJOR_ID_TXLX:
+               *desc = ddr_port_desc_txlx;
+               desc_size = ARRAY_SIZE(ddr_port_desc_txlx);
+               break;
+
+       case MESON_CPU_MAJOR_ID_AXG:
+               *desc = ddr_port_desc_axg;
+               desc_size = ARRAY_SIZE(ddr_port_desc_axg);
+               break;
+
+       case MESON_CPU_MAJOR_ID_GXLX:
+               *desc = ddr_port_desc_gxlx;
+               desc_size = ARRAY_SIZE(ddr_port_desc_gxlx);
+               break;
+
+       case MESON_CPU_MAJOR_ID_TXHD:
+               *desc = ddr_port_desc_txhd;
+               desc_size = ARRAY_SIZE(ddr_port_desc_txhd);
+               break;
+
+       case MESON_CPU_MAJOR_ID_G12A:
+               *desc = ddr_port_desc_g12a;
+               desc_size = ARRAY_SIZE(ddr_port_desc_g12a);
+               break;
+
+       case MESON_CPU_MAJOR_ID_G12B:
+               *desc = ddr_port_desc_g12b;
+               desc_size = ARRAY_SIZE(ddr_port_desc_g12b);
+               break;
+
+       default:
+               break;
+       }
+
+       return desc_size;
+}
diff --git a/drivers/amlogic/ddr_tool/ddr_bandwidth.c b/drivers/amlogic/ddr_tool/ddr_bandwidth.c
new file mode 100644 (file)
index 0000000..8b8f9d7
--- /dev/null
@@ -0,0 +1,396 @@
+/*
+ * drivers/amlogic/ddr_tool/ddr_bandwidth.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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/version.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/printk.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/sysfs.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/amlogic/cpu_version.h>
+#include <linux/amlogic/aml_ddr_bandwidth.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+static struct ddr_bandwidth *aml_db;
+
+static void cal_ddr_usage(struct ddr_bandwidth *db, struct ddr_grant *dg)
+{
+       u64 mul; /* avoid overflow */
+       unsigned long i, cnt, freq = 0;
+
+       if (db->ops && db->ops->get_freq)
+               freq = db->ops->get_freq(db);
+       mul  = (dg->all_grant * 10000ULL) / 16; /* scale up to keep precision*/
+       cnt  = db->clock_count;
+       do_div(mul, cnt);
+       db->total_usage = mul;
+       if (freq) {
+               /* calculate in KB */
+               mul = (dg->all_grant * freq) / 1024;
+               do_div(mul, cnt);
+               db->total_bandwidth = mul;
+               for (i = 0; i < db->channels; i++) {
+                       mul = (dg->channel_grant[i] * freq) / 1024;
+                       do_div(mul, cnt);
+                       db->bandwidth[i] = mul;
+               }
+       }
+}
+
+static irqreturn_t dmc_irq_handler(int irq, void *dev_instance)
+{
+       struct ddr_bandwidth *db;
+       struct ddr_grant dg = {0};
+
+       db = (struct ddr_bandwidth *)dev_instance;
+       if (db->ops && db->ops->handle_irq) {
+               if (!db->ops->handle_irq(db, &dg))
+                       cal_ddr_usage(db, &dg);
+       }
+       return IRQ_HANDLED;
+}
+
+unsigned int aml_get_ddr_usage(void)
+{
+       unsigned int ret = 0;
+
+       if (aml_db)
+               ret = aml_db->total_usage;
+
+       return ret;
+}
+EXPORT_SYMBOL(aml_get_ddr_usage);
+
+static char *find_port_name(int id)
+{
+       int i;
+
+       if (!aml_db->real_ports || !aml_db->port_desc)
+               return NULL;
+
+       for (i = 0; i < aml_db->real_ports; i++) {
+               if (aml_db->port_desc[i].port_id == id)
+                       return aml_db->port_desc[i].port_name;
+       }
+       return NULL;
+}
+
+static ssize_t ddr_channel_show(struct class *cla,
+       struct class_attribute *attr, char *buf)
+{
+       int size = 0, i;
+
+       for (i = 0; i < aml_db->channels; i++)
+               size += sprintf(buf + size, "ch %d:%3d, %s\n",
+                               i, aml_db->port[i],
+                               find_port_name(aml_db->port[i]));
+
+       return size;
+}
+
+static ssize_t ddr_channel_store(struct class *cla,
+       struct class_attribute *attr, const char *buf, size_t count)
+{
+       int ch = 0, port = 0;
+
+       if (sscanf(buf, "%d:%d", &ch, &port) < 2) {
+               pr_info("invalid input:%s\n", buf);
+               return count;
+       }
+
+       if (ch >= MAX_CHANNEL ||
+           (ch && aml_db->cpu_type < MESON_CPU_MAJOR_ID_GXTVBB) ||
+           port > MAX_PORTS) {
+               pr_info("invalid channel %d or port %d\n", ch, port);
+               return count;
+       }
+
+       if (aml_db->ops && aml_db->ops->config_port) {
+               aml_db->ops->config_port(aml_db, ch, port);
+               aml_db->port[ch] = port;
+       }
+
+       return count;
+}
+
+static ssize_t clock_count_show(struct class *cla,
+       struct class_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%d\n", aml_db->clock_count);
+}
+
+static ssize_t clock_count_store(struct class *cla,
+       struct class_attribute *attr, const char *buf, size_t count)
+{
+       long val = 0;
+
+       if (kstrtoul(buf, 10, &val)) {
+               pr_info("invalid input:%s\n", buf);
+               return 0;
+       }
+       aml_db->clock_count = val;
+       if (aml_db->ops && aml_db->ops->init)
+               aml_db->ops->init(aml_db);
+
+       return count;
+}
+
+static ssize_t bandwidth_show(struct class *cla,
+       struct class_attribute *attr, char *buf)
+{
+       size_t s = 0, i;
+       int percent, rem;
+#define BANDWIDTH_PREFIX "Total bandwidth:%8d KB/s, usage:%2d.%02d%%\n"
+
+       percent = aml_db->total_usage / 100;
+       rem     = aml_db->total_usage % 100;
+       s      += sprintf(buf + s, BANDWIDTH_PREFIX,
+                       aml_db->total_bandwidth, percent, rem);
+
+       for (i = 0; i < aml_db->channels; i++) {
+               s += sprintf(buf + s, "Channel %ld, bandwidth:%8d KB/s\n",
+                               i, aml_db->bandwidth[i]);
+       }
+       return s;
+}
+
+static ssize_t freq_show(struct class *cla,
+       struct class_attribute *attr, char *buf)
+{
+       unsigned long clk = 0;
+
+       if (aml_db->ops && aml_db->ops->get_freq)
+               clk = aml_db->ops->get_freq(aml_db);
+       return sprintf(buf, "%ld MHz\n", clk / 1000000);
+}
+
+#if DDR_BANDWIDTH_DEBUG
+static ssize_t dump_reg_show(struct class *cla,
+       struct class_attribute *attr, char *buf)
+{
+       int s = 0;
+
+       if (aml_db->ops && aml_db->ops->dump_reg)
+               return aml_db->ops->dump_reg(aml_db, buf);
+
+       return s;
+}
+#endif
+
+static ssize_t cpu_type_show(struct class *cla,
+       struct class_attribute *attr, char *buf)
+{
+       int cpu_type;
+
+       cpu_type = aml_db->cpu_type;
+       return sprintf(buf, "%x\n", cpu_type);
+}
+
+static ssize_t name_of_ports_show(struct class *cla,
+       struct class_attribute *attr, char *buf)
+{
+       int i, s = 0;
+
+       if (!aml_db->real_ports || !aml_db->port_desc)
+               return -EINVAL;
+
+       for (i = 0; i < aml_db->real_ports; i++) {
+               s += sprintf(buf + s, "%2d, %s\n",
+                            aml_db->port_desc[i].port_id,
+                            aml_db->port_desc[i].port_name);
+       }
+
+       return s;
+}
+
+static struct class_attribute aml_ddr_tool_attr[] = {
+       __ATTR(port, 0664, ddr_channel_show, ddr_channel_store),
+       __ATTR(irq_clock, 0664, clock_count_show, clock_count_store),
+       __ATTR_RO(bandwidth),
+       __ATTR_RO(freq),
+       __ATTR_RO(cpu_type),
+       __ATTR_RO(name_of_ports),
+#if DDR_BANDWIDTH_DEBUG
+       __ATTR_RO(dump_reg),
+#endif
+       __ATTR_NULL
+};
+
+static struct class aml_ddr_class = {
+       .name = "aml_ddr",
+       .class_attrs = aml_ddr_tool_attr,
+};
+
+static int ddr_bandwidth_probe(struct platform_device *pdev)
+{
+       int r = 0;
+#ifdef CONFIG_OF
+       struct device_node *node = pdev->dev.of_node;
+       const char *irq_name = NULL;
+       /*struct pinctrl *p;*/
+       struct resource *res;
+       resource_size_t *base;
+#endif
+       struct ddr_port_desc *desc = NULL;
+       int pcnt;
+
+       aml_db = kzalloc(sizeof(struct ddr_bandwidth), GFP_KERNEL);
+       if (!aml_db)
+               return -ENOMEM;
+
+       aml_db->cpu_type = get_meson_cpu_version(0);
+       pr_info("chip type:0x%x\n", aml_db->cpu_type);
+       if (aml_db->cpu_type < MESON_CPU_MAJOR_ID_M8B) {
+               pr_info("unsupport chip type:%d\n", aml_db->cpu_type);
+               goto inval;
+       }
+
+       /* set channel */
+       if (aml_db->cpu_type < MESON_CPU_MAJOR_ID_GXTVBB)
+               aml_db->channels = 1;
+       else
+               aml_db->channels = 4;
+
+       /* find and configure port description */
+       pcnt = ddr_find_port_desc(aml_db->cpu_type, &desc);
+       if (pcnt < 0)
+               pr_err("can't find port descriptor,cpu:%d\n", aml_db->cpu_type);
+       else {
+               aml_db->port_desc = kcalloc(pcnt, sizeof(*desc), GFP_KERNEL);
+               if (!aml_db->port_desc)
+                       goto inval;
+               pr_info("port count:%d, desc:%p\n", pcnt, aml_db->port_desc);
+               memcpy(aml_db->port_desc, desc, sizeof(*desc) * pcnt);
+               aml_db->real_ports = pcnt;
+       }
+
+#ifdef CONFIG_OF
+       /* resource 0 for ddr register base */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res) {
+               base = ioremap(res->start, res->end - res->start);
+               aml_db->ddr_reg = (void *)base;
+       } else {
+               pr_err("can't get ddr reg base\n");
+               goto inval;
+       }
+
+       /* resource 1 for pll register base */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (res) {
+               base = ioremap(res->start, res->end - res->start);
+               aml_db->pll_reg = (void *)base;
+       } else {
+               pr_err("can't get ddr reg base\n");
+               goto inval;
+       }
+
+       aml_db->irq_num = of_irq_get(node, 0);
+       if (of_get_property(node, "interrupt-names", NULL)) {
+               r = of_property_read_string(node, "interrupt-names", &irq_name);
+               if (!r) {
+                       r = request_irq(aml_db->irq_num, dmc_irq_handler,
+                                       IRQF_SHARED, irq_name, (void *)aml_db);
+               }
+       }
+       if (r < 0) {
+               pr_info("request irq failed:%d\n", aml_db->irq_num);
+               goto inval;
+       }
+#endif
+       aml_db->clock_count = DEFAULT_CLK_CNT;
+       if (aml_db->cpu_type <= MESON_CPU_MAJOR_ID_GXTVBB)
+               aml_db->ops = &gx_ddr_bw_ops;
+       else if ((aml_db->cpu_type <= MESON_CPU_MAJOR_ID_TXHD) &&
+                (aml_db->cpu_type >= MESON_CPU_MAJOR_ID_GXL))
+               aml_db->ops = &gxl_ddr_bw_ops;
+       else if (aml_db->cpu_type >= MESON_CPU_MAJOR_ID_G12A)
+               aml_db->ops = &g12_ddr_bw_ops;
+       else {
+               pr_err("%s, can't find ops for cpu type:%d\n",
+                       __func__, aml_db->cpu_type);
+               goto inval;
+       }
+
+       if (aml_db->ops->init)
+               aml_db->ops->init(aml_db);
+       r = class_register(&aml_ddr_class);
+       if (r)
+               pr_info("%s, class regist failed\n", __func__);
+       return 0;
+inval:
+       kfree(aml_db->port_desc);
+       kfree(aml_db);
+       aml_db = NULL;
+
+       return -EINVAL;
+}
+
+static int ddr_bandwidth_remove(struct platform_device *pdev)
+{
+       if (aml_db) {
+               class_destroy(&aml_ddr_class);
+               free_irq(aml_db->irq_num, aml_db);
+               kfree(aml_db->port_desc);
+               kfree(aml_db);
+               iounmap(aml_db->ddr_reg);
+               iounmap(aml_db->pll_reg);
+               aml_db = NULL;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id aml_ddr_bandwidth_dt_match[] = {
+       {
+               .compatible = "amlogic, ddr-bandwidth",
+       }
+};
+#endif
+
+static struct platform_driver ddr_bandwidth_driver = {
+       .driver = {
+               .name = "amlogic, ddr-bandwidth",
+               .owner = THIS_MODULE,
+       #ifdef CONFIG_OF
+               .of_match_table = aml_ddr_bandwidth_dt_match,
+       #endif
+       },
+       .probe  = ddr_bandwidth_probe,
+       .remove = ddr_bandwidth_remove,
+};
+
+static int __init ddr_bandwidth_init(void)
+{
+       return platform_driver_register(&ddr_bandwidth_driver);
+}
+
+static void __exit ddr_bandwidth_exit(void)
+{
+       platform_driver_unregister(&ddr_bandwidth_driver);
+}
+
+subsys_initcall(ddr_bandwidth_init);
+module_exit(ddr_bandwidth_exit);
+MODULE_LICENSE("GPL v2");
similarity index 99%
rename from drivers/amlogic/ddr_window/ddr_window.c
rename to drivers/amlogic/ddr_tool/ddr_window.c
index f6f6232..39f6db5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * drivers/amlogic/ddr_window/ddr_window.c
+ * drivers/amlogic/ddr_tool/ddr_window.c
  *
  * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
  *
diff --git a/drivers/amlogic/ddr_window/Kconfig b/drivers/amlogic/ddr_window/Kconfig
deleted file mode 100644 (file)
index 6272335..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-config AMLOGIC_DDR_WINDOW_TOOL
-       tristate "Meson cpu ddr window test tool"
-       default n
-       help
-         This add ddr window test tools
diff --git a/drivers/amlogic/ddr_window/Makefile b/drivers/amlogic/ddr_window/Makefile
deleted file mode 100644 (file)
index f428bcb..0000000
+++ /dev/null
@@ -1 +0,0 @@
-obj-$(CONFIG_AMLOGIC_DDR_WINDOW_TOOL)  += ddr_window.o
diff --git a/include/linux/amlogic/aml_ddr_bandwidth.h b/include/linux/amlogic/aml_ddr_bandwidth.h
new file mode 100644 (file)
index 0000000..e9efe9a
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * include/linux/amlogic/aml_ddr_bandwidth.h
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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.
+ *
+ */
+
+#ifndef __AML_DDR_BANDWIDTH_H__
+#define __AML_DDR_BANDWIDTH_H__
+
+
+#define DEFAULT_CLK_CNT                        12000000
+#define DEFAULT_XTAL_FREQ              24000000
+
+#define DMC_QOS_IRQ                    (1 << 30)
+#define MAX_CHANNEL                    4
+#define MAX_PORTS                      256
+#define MAX_NAME                       15
+#define PORT_MAJOR                     32
+
+/*
+ * register offset for chips before g12
+ */
+#define DMC_MON_CTRL1                  (0x25 << 2)
+#define DMC_MON_CTRL2                  (0x26 << 2)
+#define DMC_MON_CTRL3                  (0x27 << 2)
+#define DMC_MON_ALL_REQ_CNT            (0x28 << 2)
+#define DMC_MON_ALL_GRANT_CNT          (0x29 << 2)
+#define DMC_MON_ONE_GRANT_CNT          (0x2a << 2)
+#define DMC_MON_SEC_GRANT_CNT          (0x2b << 2)
+#define DMC_MON_THD_GRANT_CNT          (0x2c << 2)
+#define DMC_MON_FOR_GRANT_CNT          (0x2d << 2)
+
+#define DMC_MON_CTRL4                  (0x18 << 2)
+#define DMC_MON_CTRL5                  (0x19 << 2)
+#define DMC_MON_CTRL6                  (0x1a << 2)
+
+/*
+ * register offset for g12a
+ */
+#define DMC_MON_G12_CTRL0              (0x20  << 2)
+#define DMC_MON_G12_CTRL1              (0x21  << 2)
+#define DMC_MON_G12_CTRL2              (0x22  << 2)
+#define DMC_MON_G12_CTRL3              (0x23  << 2)
+#define DMC_MON_G12_CTRL4              (0x24  << 2)
+#define DMC_MON_G12_CTRL5              (0x25  << 2)
+#define DMC_MON_G12_CTRL6              (0x26  << 2)
+#define DMC_MON_G12_CTRL7              (0x27  << 2)
+#define DMC_MON_G12_CTRL8              (0x28  << 2)
+
+#define DMC_MON_G12_ALL_REQ_CNT                (0x29  << 2)
+#define DMC_MON_G12_ALL_GRANT_CNT      (0x2a  << 2)
+#define DMC_MON_G12_ONE_GRANT_CNT      (0x2b  << 2)
+#define DMC_MON_G12_SEC_GRANT_CNT      (0x2c  << 2)
+#define DMC_MON_G12_THD_GRANT_CNT      (0x2d  << 2)
+#define DMC_MON_G12_FOR_GRANT_CNT      (0x2e  << 2)
+#define DMC_MON_G12_TIMER              (0x2f  << 2)
+
+/* data structure */
+#define DDR_BANDWIDTH_DEBUG            1
+
+struct ddr_bandwidth;
+
+struct ddr_grant {
+       unsigned int all_grant, all_req;
+       unsigned int channel_grant[MAX_CHANNEL];
+};
+
+struct ddr_bandwidth_ops {
+       void (*init)(struct ddr_bandwidth *db);
+       void (*config_port)(struct ddr_bandwidth *db, int channel, int port);
+       int  (*handle_irq)(struct ddr_bandwidth *db, struct ddr_grant *dg);
+       void (*bandwidth_enable)(struct ddr_bandwidth *db);
+       unsigned long (*get_freq)(struct ddr_bandwidth *db);
+#if    DDR_BANDWIDTH_DEBUG
+       int (*dump_reg)(struct ddr_bandwidth *db, char *buf);
+#endif
+};
+
+struct ddr_port_desc {
+       char port_name[MAX_NAME];
+       unsigned char port_id;
+};
+
+struct ddr_bandwidth {
+       void __iomem *ddr_reg;
+       void __iomem *pll_reg;
+       struct class *class;
+       unsigned short cpu_type;
+       unsigned short real_ports;
+       unsigned int irq_num;
+       unsigned int clock_count;
+       unsigned int channels;
+       unsigned int port[MAX_CHANNEL];
+       unsigned int bandwidth[MAX_CHANNEL];
+       unsigned int total_usage;
+       unsigned int total_bandwidth;
+       struct ddr_port_desc *port_desc;
+       struct ddr_bandwidth_ops *ops;
+};
+
+#ifdef CONFIG_AMLOGIC_DDR_BANDWIDTH
+extern unsigned int aml_get_ddr_usage(void);
+extern struct ddr_bandwidth_ops g12_ddr_bw_ops;
+extern struct ddr_bandwidth_ops gx_ddr_bw_ops;
+extern struct ddr_bandwidth_ops gxl_ddr_bw_ops;
+extern int ddr_find_port_desc(int cpu_type, struct ddr_port_desc **desc);
+#else
+static inline unsigned int aml_get_ddr_usage(void)
+{
+       return 0;
+}
+#endif
+
+#endif /* __AML_DDR_BANDWIDTH_H__ */