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/*
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/
};
}; /* 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 / */
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 {
<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 {
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{
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";
+ };
};
};
};/* 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 {
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"
source "drivers/amlogic/iio/Kconfig"
-source "drivers/amlogic/ddr_window/Kconfig"
+source "drivers/amlogic/ddr_tool/Kconfig"
source "drivers/amlogic/drm/Kconfig"
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/
--- /dev/null
+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.
--- /dev/null
+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
+
--- /dev/null
+/*
+ * 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
+};
--- /dev/null
+/*
+ * 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
+};
--- /dev/null
+/*
+ * 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
+};
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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");
--- /dev/null
+/*
+ * drivers/amlogic/ddr_tool/ddr_window.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/slab.h>
+#include <linux/io.h>
+#include <linux/workqueue.h>
+#include <linux/timer.h>
+#include <linux/amlogic/cpu_version.h>
+
+static unsigned int reg_base;
+static void __iomem *map;
+
+static unsigned int reg_base_debug;
+static void __iomem *map_debug;
+
+static unsigned int reg_base_debug_a;
+static void __iomem *map_debug_a;
+
+static ssize_t window_reg_show(struct class *cla,
+ struct class_attribute *attr, char *buf)
+{
+ unsigned int val;
+
+ if (reg_base == 0) {
+ pr_err("please set register base first\n");
+ return -EINVAL;
+ }
+ map = NULL;
+ map = (void *)ioremap(reg_base, 4);
+ pr_err("map:%p, base:%x\n", map, reg_base);
+ if (map) {
+ val = readl(map);
+ iounmap(map);
+ return sprintf(buf, "0x%08x\n", val);
+ }
+
+ return 0;
+}
+
+static ssize_t window_reg_store(struct class *cla,
+ struct class_attribute *attr, const char *buf, size_t count)
+{
+ int ret = -1, i;
+ unsigned int val;
+ char *arg[2] = {}, *para, *buf_work, *p;
+
+ map = NULL;
+ buf_work = kstrdup(buf, GFP_KERNEL);
+ p = buf_work;
+ for (i = 0; i < 2; i++) {
+ para = strsep(&p, " ");
+ if (para == NULL)
+ break;
+
+ arg[i] = para;
+ }
+ if (i < 1 || i > 2) {
+ ret = 1;
+ goto error;
+ }
+
+ ret = kstrtouint((const char *)arg[0], 16, ®_base);
+ if (i == 2) {
+ ret = kstrtouint((const char *)arg[1], 16, &val);
+ map = (void *)ioremap(reg_base, 4);
+ if (map) {
+ writel(val, map);
+ iounmap(map);
+ pr_err("set 0x%08x to %08x\n", reg_base, val);
+ }
+ } else {
+ pr_err("set reg base to 0x%08x\n", reg_base);
+ }
+error:
+ kfree(buf_work);
+ if (ret)
+ pr_err("error\n");
+
+ return count;
+}
+
+static ssize_t reg_debug_show(struct class *cla,
+ struct class_attribute *attr, char *buf)
+{
+
+
+ unsigned int val;
+
+ if (reg_base_debug == 0) {
+ pr_err("please set register base first\n");
+ return -EINVAL;
+ }
+ map_debug = NULL;
+ map_debug = (void *)ioremap(reg_base_debug, 4);
+ pr_err("map:%p, base:%x\n", map_debug, reg_base_debug);
+ if (map_debug) {
+ val = readl(map_debug);
+ iounmap(map_debug);
+ return sprintf(buf, "0x%08x\n", val);
+ }
+
+ return 0;
+}
+
+static ssize_t reg_debug_store(struct class *cla,
+ struct class_attribute *attr, const char *buf, size_t count)
+{
+
+ int ret = -1, i;
+ unsigned int val;
+ char *arg[2] = {}, *para, *buf_work, *p;
+
+ map_debug = NULL;
+ buf_work = kstrdup(buf, GFP_KERNEL);
+ p = buf_work;
+ for (i = 0; i < 2; i++) {
+ para = strsep(&p, " ");
+ if (para == NULL)
+ break;
+
+ arg[i] = para;
+ }
+ if (i < 1 || i > 2) {
+ ret = 1;
+ goto error;
+ }
+
+ ret = kstrtouint((const char *)arg[0], 16, ®_base_debug);
+ if (i == 2) {
+ ret = kstrtouint((const char *)arg[1], 16, &val);
+ map_debug = (void *)ioremap(reg_base_debug, 4);
+ if (map_debug) {
+ writel(val, map_debug);
+ iounmap(map_debug);
+ pr_err("set 0x%08x to %08x\n", reg_base_debug, val);
+ }
+ } else {
+ pr_err("set reg base to 0x%08x\n", reg_base_debug);
+ }
+error:
+ kfree(buf_work);
+ if (ret)
+ pr_err("error\n");
+ return count;
+}
+
+static ssize_t reg_debug_a_show(struct class *cla,
+ struct class_attribute *attr, char *buf)
+{
+ unsigned int val;
+
+ if (reg_base_debug_a == 0) {
+ pr_err("please set register base first\n");
+ return -EINVAL;
+ }
+ map_debug_a = NULL;
+ map_debug_a = (void *)ioremap(reg_base_debug_a, 4);
+ pr_err("map:%p, base:%x\n", map_debug_a, reg_base_debug_a);
+ if (map_debug_a) {
+ val = readl(map_debug_a);
+ iounmap(map_debug_a);
+ return sprintf(buf, "0x%08x\n", val);
+ }
+
+ return 0;
+}
+
+
+
+
+static ssize_t reg_debug_a_store(struct class *cla,
+ struct class_attribute *attr, const char *buf, size_t count)
+{
+
+ int ret = -1, i;
+ unsigned int val;
+ char *arg[2] = {}, *para, *buf_work, *p;
+
+ map_debug_a = NULL;
+ buf_work = kstrdup(buf, GFP_KERNEL);
+ p = buf_work;
+ for (i = 0; i < 2; i++) {
+ para = strsep(&p, " ");
+ if (para == NULL)
+ break;
+ arg[i] = para;
+ }
+
+ if (i < 1 || i > 2) {
+ ret = 1;
+ goto error;
+ }
+
+ ret = kstrtouint((const char *)arg[0], 16, ®_base_debug_a);
+ if (i == 2) {
+ ret = kstrtouint((const char *)arg[1], 16, &val);
+ map_debug_a = (void *)ioremap(reg_base_debug_a, 4);
+ if (map_debug_a) {
+ writel(val, map_debug_a);
+ iounmap(map_debug_a);
+ pr_err("set 0x%08x to %08x\n", reg_base_debug_a, val);
+ }
+ } else {
+ pr_err("set reg base to 0x%08x\n", reg_base_debug_a);
+ }
+error:
+ kfree(buf_work);
+ if (ret)
+ pr_err("error\n");
+
+ return count;
+}
+
+static ssize_t cpu_type_show(struct class *cla,
+ struct class_attribute *attr, char *buf)
+{
+ int cpu_type;
+
+ cpu_type = get_meson_cpu_version(0);
+ return sprintf(buf, "%x\n", cpu_type);
+}
+
+static struct class_attribute ddr_window_attr[] = {
+ __ATTR(window_reg, 0664, window_reg_show, window_reg_store),
+ __ATTR(reg_debug, 0664, reg_debug_show, reg_debug_store),
+ __ATTR(reg_debug_a, 0664, reg_debug_a_show, reg_debug_a_store),
+ __ATTR_RO(cpu_type),
+ __ATTR_NULL
+};
+
+static struct class ddr_window_class = {
+ .name = "ddr_window",
+ .class_attrs = ddr_window_attr,
+};
+
+static int ddr_window_probe(struct platform_device *pdev)
+{
+ int r;
+
+ r = class_register(&ddr_window_class);
+ if (r) {
+ pr_err("%s, class regist failed\n", __func__);
+ return -EINVAL;
+ }
+ reg_base = 0;
+ return 0;
+}
+
+static int ddr_window_remove(struct platform_device *pdev)
+{
+ class_unregister(&ddr_window_class);
+ return 0;
+}
+
+static struct platform_driver ddr_window = {
+ .driver = {
+ .name = "ddr_window",
+ .owner = THIS_MODULE,
+ },
+ .probe = ddr_window_probe,
+ .remove = ddr_window_remove,
+};
+
+static int __init ddr_window_init(void)
+{
+ struct platform_device *pdev;
+ int ret;
+
+ pdev = platform_device_alloc("ddr_window", 0);
+ if (!pdev) {
+ pr_err("%s, alloc pdev failed\n", __func__);
+ return -EINVAL;
+ }
+ ret = platform_device_add(pdev);
+ if (ret) {
+ pr_err("%s, add pdev failed\n", __func__);
+ platform_device_del(pdev);
+ return -EINVAL;
+ }
+ return platform_driver_register(&ddr_window);
+}
+
+static void __exit ddr_window_exit(void)
+{
+ platform_driver_unregister(&ddr_window);
+}
+
+module_init(ddr_window_init);
+module_exit(ddr_window_exit);
+MODULE_LICENSE("GPL v2");
+++ /dev/null
-config AMLOGIC_DDR_WINDOW_TOOL
- tristate "Meson cpu ddr window test tool"
- default n
- help
- This add ddr window test tools
+++ /dev/null
-obj-$(CONFIG_AMLOGIC_DDR_WINDOW_TOOL) += ddr_window.o
+++ /dev/null
-/*
- * drivers/amlogic/ddr_window/ddr_window.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/slab.h>
-#include <linux/io.h>
-#include <linux/workqueue.h>
-#include <linux/timer.h>
-#include <linux/amlogic/cpu_version.h>
-
-static unsigned int reg_base;
-static void __iomem *map;
-
-static unsigned int reg_base_debug;
-static void __iomem *map_debug;
-
-static unsigned int reg_base_debug_a;
-static void __iomem *map_debug_a;
-
-static ssize_t window_reg_show(struct class *cla,
- struct class_attribute *attr, char *buf)
-{
- unsigned int val;
-
- if (reg_base == 0) {
- pr_err("please set register base first\n");
- return -EINVAL;
- }
- map = NULL;
- map = (void *)ioremap(reg_base, 4);
- pr_err("map:%p, base:%x\n", map, reg_base);
- if (map) {
- val = readl(map);
- iounmap(map);
- return sprintf(buf, "0x%08x\n", val);
- }
-
- return 0;
-}
-
-static ssize_t window_reg_store(struct class *cla,
- struct class_attribute *attr, const char *buf, size_t count)
-{
- int ret = -1, i;
- unsigned int val;
- char *arg[2] = {}, *para, *buf_work, *p;
-
- map = NULL;
- buf_work = kstrdup(buf, GFP_KERNEL);
- p = buf_work;
- for (i = 0; i < 2; i++) {
- para = strsep(&p, " ");
- if (para == NULL)
- break;
-
- arg[i] = para;
- }
- if (i < 1 || i > 2) {
- ret = 1;
- goto error;
- }
-
- ret = kstrtouint((const char *)arg[0], 16, ®_base);
- if (i == 2) {
- ret = kstrtouint((const char *)arg[1], 16, &val);
- map = (void *)ioremap(reg_base, 4);
- if (map) {
- writel(val, map);
- iounmap(map);
- pr_err("set 0x%08x to %08x\n", reg_base, val);
- }
- } else {
- pr_err("set reg base to 0x%08x\n", reg_base);
- }
-error:
- kfree(buf_work);
- if (ret)
- pr_err("error\n");
-
- return count;
-}
-
-static ssize_t reg_debug_show(struct class *cla,
- struct class_attribute *attr, char *buf)
-{
-
-
- unsigned int val;
-
- if (reg_base_debug == 0) {
- pr_err("please set register base first\n");
- return -EINVAL;
- }
- map_debug = NULL;
- map_debug = (void *)ioremap(reg_base_debug, 4);
- pr_err("map:%p, base:%x\n", map_debug, reg_base_debug);
- if (map_debug) {
- val = readl(map_debug);
- iounmap(map_debug);
- return sprintf(buf, "0x%08x\n", val);
- }
-
- return 0;
-}
-
-static ssize_t reg_debug_store(struct class *cla,
- struct class_attribute *attr, const char *buf, size_t count)
-{
-
- int ret = -1, i;
- unsigned int val;
- char *arg[2] = {}, *para, *buf_work, *p;
-
- map_debug = NULL;
- buf_work = kstrdup(buf, GFP_KERNEL);
- p = buf_work;
- for (i = 0; i < 2; i++) {
- para = strsep(&p, " ");
- if (para == NULL)
- break;
-
- arg[i] = para;
- }
- if (i < 1 || i > 2) {
- ret = 1;
- goto error;
- }
-
- ret = kstrtouint((const char *)arg[0], 16, ®_base_debug);
- if (i == 2) {
- ret = kstrtouint((const char *)arg[1], 16, &val);
- map_debug = (void *)ioremap(reg_base_debug, 4);
- if (map_debug) {
- writel(val, map_debug);
- iounmap(map_debug);
- pr_err("set 0x%08x to %08x\n", reg_base_debug, val);
- }
- } else {
- pr_err("set reg base to 0x%08x\n", reg_base_debug);
- }
-error:
- kfree(buf_work);
- if (ret)
- pr_err("error\n");
- return count;
-}
-
-static ssize_t reg_debug_a_show(struct class *cla,
- struct class_attribute *attr, char *buf)
-{
- unsigned int val;
-
- if (reg_base_debug_a == 0) {
- pr_err("please set register base first\n");
- return -EINVAL;
- }
- map_debug_a = NULL;
- map_debug_a = (void *)ioremap(reg_base_debug_a, 4);
- pr_err("map:%p, base:%x\n", map_debug_a, reg_base_debug_a);
- if (map_debug_a) {
- val = readl(map_debug_a);
- iounmap(map_debug_a);
- return sprintf(buf, "0x%08x\n", val);
- }
-
- return 0;
-}
-
-
-
-
-static ssize_t reg_debug_a_store(struct class *cla,
- struct class_attribute *attr, const char *buf, size_t count)
-{
-
- int ret = -1, i;
- unsigned int val;
- char *arg[2] = {}, *para, *buf_work, *p;
-
- map_debug_a = NULL;
- buf_work = kstrdup(buf, GFP_KERNEL);
- p = buf_work;
- for (i = 0; i < 2; i++) {
- para = strsep(&p, " ");
- if (para == NULL)
- break;
- arg[i] = para;
- }
-
- if (i < 1 || i > 2) {
- ret = 1;
- goto error;
- }
-
- ret = kstrtouint((const char *)arg[0], 16, ®_base_debug_a);
- if (i == 2) {
- ret = kstrtouint((const char *)arg[1], 16, &val);
- map_debug_a = (void *)ioremap(reg_base_debug_a, 4);
- if (map_debug_a) {
- writel(val, map_debug_a);
- iounmap(map_debug_a);
- pr_err("set 0x%08x to %08x\n", reg_base_debug_a, val);
- }
- } else {
- pr_err("set reg base to 0x%08x\n", reg_base_debug_a);
- }
-error:
- kfree(buf_work);
- if (ret)
- pr_err("error\n");
-
- return count;
-}
-
-static ssize_t cpu_type_show(struct class *cla,
- struct class_attribute *attr, char *buf)
-{
- int cpu_type;
-
- cpu_type = get_meson_cpu_version(0);
- return sprintf(buf, "%x\n", cpu_type);
-}
-
-static struct class_attribute ddr_window_attr[] = {
- __ATTR(window_reg, 0664, window_reg_show, window_reg_store),
- __ATTR(reg_debug, 0664, reg_debug_show, reg_debug_store),
- __ATTR(reg_debug_a, 0664, reg_debug_a_show, reg_debug_a_store),
- __ATTR_RO(cpu_type),
- __ATTR_NULL
-};
-
-static struct class ddr_window_class = {
- .name = "ddr_window",
- .class_attrs = ddr_window_attr,
-};
-
-static int ddr_window_probe(struct platform_device *pdev)
-{
- int r;
-
- r = class_register(&ddr_window_class);
- if (r) {
- pr_err("%s, class regist failed\n", __func__);
- return -EINVAL;
- }
- reg_base = 0;
- return 0;
-}
-
-static int ddr_window_remove(struct platform_device *pdev)
-{
- class_unregister(&ddr_window_class);
- return 0;
-}
-
-static struct platform_driver ddr_window = {
- .driver = {
- .name = "ddr_window",
- .owner = THIS_MODULE,
- },
- .probe = ddr_window_probe,
- .remove = ddr_window_remove,
-};
-
-static int __init ddr_window_init(void)
-{
- struct platform_device *pdev;
- int ret;
-
- pdev = platform_device_alloc("ddr_window", 0);
- if (!pdev) {
- pr_err("%s, alloc pdev failed\n", __func__);
- return -EINVAL;
- }
- ret = platform_device_add(pdev);
- if (ret) {
- pr_err("%s, add pdev failed\n", __func__);
- platform_device_del(pdev);
- return -EINVAL;
- }
- return platform_driver_register(&ddr_window);
-}
-
-static void __exit ddr_window_exit(void)
-{
- platform_driver_unregister(&ddr_window);
-}
-
-module_init(ddr_window_init);
-module_exit(ddr_window_exit);
-MODULE_LICENSE("GPL v2");
--- /dev/null
+/*
+ * 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__ */