diff options
author | Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com> | 2011-09-29 18:39:34 +0200 |
---|---|---|
committer | Jonas ABERG <jonas.aberg@stericsson.com> | 2011-09-30 13:43:58 +0200 |
commit | 46144729b375850c24820ad96fcb90113b40db7b (patch) | |
tree | 7202ea53d9581ec2ceb9637f9d6d3ba385506adf | |
parent | b1ad83363f3a6c4d9334e1fcaac5397aa386456c (diff) |
video: mcde: Add fps logging
Add debugfs support for enabling frame rate logging to dmesg and
getting latest fps metric.
ST-Ericsson ID: 364378
ST-Ericsson Linux next: NA
ST-Ericsson FOSS-OUT ID: Trivial
Change-Id: I8d6f1447fb386b7b4d96750652602a5b9b1e8b0c
Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/32397
Reviewed-by: Marcus LORENTZON <marcus.xm.lorentzon@stericsson.com>
Tested-by: Marcus LORENTZON <marcus.xm.lorentzon@stericsson.com>
Reviewed-by: Per PERSSON <per.xb.persson@stericsson.com>
Reviewed-by: Jimmy RUBIN <jimmy.rubin@stericsson.com>
Reviewed-by: Jonas ABERG <jonas.aberg@stericsson.com>
-rw-r--r-- | drivers/video/mcde/Makefile | 11 | ||||
-rw-r--r-- | drivers/video/mcde/mcde_debugfs.c | 207 | ||||
-rw-r--r-- | drivers/video/mcde/mcde_debugfs.h | 25 | ||||
-rw-r--r-- | drivers/video/mcde/mcde_hw.c | 12 |
4 files changed, 251 insertions, 4 deletions
diff --git a/drivers/video/mcde/Makefile b/drivers/video/mcde/Makefile index 63ffeaec154..ab86a074005 100644 --- a/drivers/video/mcde/Makefile +++ b/drivers/video/mcde/Makefile @@ -1,6 +1,11 @@ - -mcde-objs := mcde_mod.o mcde_hw.o mcde_dss.o mcde_display.o mcde_bus.o mcde_fb.o -obj-$(CONFIG_FB_MCDE) += mcde.o +mcde-objs += mcde_mod.o +mcde-objs += mcde_hw.o +mcde-objs += mcde_dss.o +mcde-objs += mcde_display.o +mcde-objs += mcde_bus.o +mcde-objs += mcde_fb.o +mcde-objs += mcde_debugfs.o +obj-$(CONFIG_FB_MCDE) += mcde.o obj-$(CONFIG_MCDE_DISPLAY_GENERIC_DSI) += display-generic_dsi.o obj-$(CONFIG_MCDE_DISPLAY_SONY_ACX424AKP_DSI) += display-sony_acx424akp_dsi.o diff --git a/drivers/video/mcde/mcde_debugfs.c b/drivers/video/mcde/mcde_debugfs.c new file mode 100644 index 00000000000..0ef6cbb3715 --- /dev/null +++ b/drivers/video/mcde/mcde_debugfs.c @@ -0,0 +1,207 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson MCDE base driver + * + * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/stat.h> +#include <linux/time.h> +#include <linux/debugfs.h> +#include <linux/slab.h> +#include <asm/page.h> + +#include "mcde_debugfs.h" + +#define MAX_NUM_OVERLAYS 2 +#define MAX_NUM_CHANNELS 4 +#define DEFAULT_DMESG_FPS_LOG_INTERVAL 100 + +struct fps_info { + u32 enable_dmesg; + u32 interval_ms; + struct timespec timestamp_last; + u32 frame_counter_last; + u32 frame_counter; + u32 fpks; +}; + +struct overlay_info { + u8 id; + struct dentry *dentry; + struct fps_info fps; +}; + +struct channel_info { + u8 id; + struct dentry *dentry; + struct mcde_chnl_state *chnl; + struct fps_info fps; + struct overlay_info overlays[MAX_NUM_OVERLAYS]; +}; + +static struct mcde_info { + struct device *dev; + struct dentry *dentry; + struct channel_info channels[MAX_NUM_CHANNELS]; +} mcde; + +/* Requires: lhs > rhs */ +static inline u32 timespec_ms_diff(struct timespec lhs, struct timespec rhs) +{ + struct timespec tmp_ts = timespec_sub(lhs, rhs); + u64 tmp_ns = (u64)timespec_to_ns(&tmp_ts); + do_div(tmp_ns, NSEC_PER_MSEC); + return (u32)tmp_ns; +} + +/* Returns "frames per 1000 secs", divide by 1000 to get fps with 3 decimals */ +static u32 update_fps(struct fps_info *fps) +{ + struct timespec now; + u32 fpks = 0, ms_since_last, num_frames; + + getrawmonotonic(&now); + fps->frame_counter++; + + ms_since_last = timespec_ms_diff(now, fps->timestamp_last); + num_frames = fps->frame_counter - fps->frame_counter_last; + if (num_frames > 1 && ms_since_last >= fps->interval_ms) { + fpks = (num_frames * 1000000) / ms_since_last; + fps->timestamp_last = now; + fps->frame_counter_last = fps->frame_counter; + fps->fpks = fpks; + } + + return fpks; +} + +static void update_chnl_fps(struct channel_info *ci) +{ + u32 fpks = update_fps(&ci->fps); + if (fpks && ci->fps.enable_dmesg) + dev_info(mcde.dev, "FPS: chnl=%d fps=%d.%.3d\n", ci->id, + fpks / 1000, fpks % 1000); +} + +static void update_ovly_fps(struct channel_info *ci, struct overlay_info *oi) +{ + u32 fpks = update_fps(&oi->fps); + if (fpks && oi->fps.enable_dmesg) + dev_info(mcde.dev, "FPS: ovly=%d.%d fps=%d.%.3d\n", ci->id, + oi->id, fpks / 1000, fpks % 1000); +} + +int mcde_debugfs_create(struct device *dev) +{ + if (mcde.dev) + return -EBUSY; + + mcde.dentry = debugfs_create_dir("mcde", NULL); + if (!mcde.dentry) + return -ENOMEM; + mcde.dev = dev; + + return 0; +} + +static struct channel_info *find_chnl(u8 chnl_id) +{ + if (chnl_id > MAX_NUM_CHANNELS) + return NULL; + return &mcde.channels[chnl_id]; +} + +static struct overlay_info *find_ovly(struct channel_info *ci, u8 ovly_id) +{ + if (!ci || ovly_id > MAX_NUM_OVERLAYS) + return NULL; + return &ci->overlays[ovly_id]; +} + +static void create_fps_files(struct dentry *dentry, struct fps_info *fps) +{ + debugfs_create_u32("frame_counter", S_IRUGO, dentry, + &fps->frame_counter); + debugfs_create_u32("frames_per_ksecs", S_IRUGO, dentry, &fps->fpks); + debugfs_create_u32("interval_ms", S_IRUGO|S_IWUGO, dentry, + &fps->interval_ms); + debugfs_create_u32("dmesg", S_IRUGO|S_IWUGO, dentry, + &fps->enable_dmesg); +} + +int mcde_debugfs_channel_create(u8 chnl_id, struct mcde_chnl_state *chnl) +{ + struct channel_info *ci = find_chnl(chnl_id); + char name[10]; + + if (!chnl || !ci) + return -EINVAL; + if (ci->chnl) + return -EBUSY; + + snprintf(name, sizeof(name), "chnl%d", chnl_id); + ci->dentry = debugfs_create_dir(name, mcde.dentry); + if (!ci->dentry) + return -ENOMEM; + + create_fps_files(ci->dentry, &ci->fps); + + ci->fps.interval_ms = DEFAULT_DMESG_FPS_LOG_INTERVAL; + ci->id = chnl_id; + ci->chnl = chnl; + + return 0; +} + +int mcde_debugfs_overlay_create(u8 chnl_id, u8 ovly_id) +{ + struct channel_info *ci = find_chnl(chnl_id); + struct overlay_info *oi = find_ovly(ci, ovly_id); + char name[10]; + + if (!oi || !ci || ovly_id >= MAX_NUM_OVERLAYS) + return -EINVAL; + if (oi->dentry) + return -EBUSY; + + snprintf(name, sizeof(name), "ovly%d", ovly_id); + oi->dentry = debugfs_create_dir(name, ci->dentry); + if (!oi->dentry) + return -ENOMEM; + + create_fps_files(oi->dentry, &oi->fps); + + oi->fps.interval_ms = DEFAULT_DMESG_FPS_LOG_INTERVAL; + oi->id = ovly_id; + + return 0; +} + +void mcde_debugfs_channel_update(u8 chnl_id) +{ + struct channel_info *ci = find_chnl(chnl_id); + + if (!ci || !ci->chnl) + return; + + update_chnl_fps(ci); +} + +void mcde_debugfs_overlay_update(u8 chnl_id, u8 ovly_id) +{ + struct channel_info *ci = find_chnl(chnl_id); + struct overlay_info *oi = find_ovly(ci, ovly_id); + + if (!oi || !oi->dentry) + return; + + update_ovly_fps(ci, oi); +} + diff --git a/drivers/video/mcde/mcde_debugfs.h b/drivers/video/mcde/mcde_debugfs.h new file mode 100644 index 00000000000..9f1e7f18ea5 --- /dev/null +++ b/drivers/video/mcde/mcde_debugfs.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * ST-Ericsson MCDE base driver + * + * Author: Marcus Lorentzon <marcus.xm.lorentzon@stericsson.com> + * for ST-Ericsson. + * + * License terms: GNU General Public License (GPL), version 2. + */ + +#ifndef __MCDE_DEBUGFS__H__ +#define __MCDE_DEBUGFS__H__ + +#include <video/mcde.h> + +int mcde_debugfs_create(struct device *dev); +int mcde_debugfs_channel_create(u8 chnl_id, struct mcde_chnl_state *chnl); +int mcde_debugfs_overlay_create(u8 chnl_id, u8 ovly_id); + +void mcde_debugfs_channel_update(u8 chnl_id); +void mcde_debugfs_overlay_update(u8 chnl_id, u8 ovly_id); + +#endif /* __MCDE_DEBUGFS__H__ */ + diff --git a/drivers/video/mcde/mcde_hw.c b/drivers/video/mcde/mcde_hw.c index c85bee1872f..49ecc332ab5 100644 --- a/drivers/video/mcde/mcde_hw.c +++ b/drivers/video/mcde/mcde_hw.c @@ -29,6 +29,7 @@ #include <video/mcde.h> #include "dsilink_regs.h" #include "mcde_regs.h" +#include "mcde_debugfs.h" /* MCDE channel states @@ -2632,8 +2633,10 @@ static void chnl_update_overlay(struct mcde_chnl_state *chnl, if (!ovly) return; - if (ovly->regs.dirty_buf) + if (ovly->regs.dirty_buf) { update_overlay_registers_on_the_fly(ovly->idx, &ovly->regs); + mcde_debugfs_overlay_update(chnl->id, ovly->idx); + } if (ovly->regs.dirty) { chnl_ovly_pixel_format_apply(chnl, ovly); update_overlay_registers(ovly->idx, &ovly->regs, &chnl->port, @@ -2684,6 +2687,7 @@ static int _mcde_chnl_update(struct mcde_chnl_state *chnl, chnl_update_non_continous(chnl); dev_vdbg(&mcde_dev->dev, "Channel updated, chnl=%d\n", chnl->id); + mcde_debugfs_channel_update(chnl->id); return 0; } @@ -3325,6 +3329,7 @@ static void probe_hw(void) channels[3].ovly1 = NULL; } + mcde_debugfs_create(&mcde_dev->dev); for (i = 0; i < num_channels; i++) { channels[i].id = i; @@ -3342,6 +3347,11 @@ static void probe_hw(void) channels[i].dsi_te_timer.function = dsi_te_timer_function; channels[i].dsi_te_timer.data = i; + + mcde_debugfs_channel_create(i, &channels[i]); + mcde_debugfs_overlay_create(i, 0); + if (channels[i].ovly1) + mcde_debugfs_overlay_create(i, 1); } } |