/*++ * Common interface for WonderMedia SoC hardware encoder and decoder drivers * * Copyright (c) 2008-2013 WonderMedia Technologies, Inc. * * 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * WonderMedia Technologies, Inc. * 4F, 533, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C --*/ #ifndef CODEC_C #define CODEC_C #include /* For EXPORT_SYMBOL() */ #include #include #include #include /* for kmalloc and kfree */ #include /* for semaphore */ #include "wmt-codec.h" #define CFG_CODEC_PERFORM_EN /* Flag for codec performance analysis */ /*#define CODEC_DEBUG*/ #undef CODEC_DEBUG #ifdef CODEC_DEBUG #define DBG_MSG(fmt, args...) \ do {\ printk(KERN_INFO "{%s} " fmt, __func__, ## args);\ } while (0) #else #define DBG_MSG(fmt, args...) #endif #undef DBG_ERR #define DBG_ERR(fmt, args...) \ do {\ printk(KERN_ERR "*E* {%s} " fmt, __func__, ## args);\ } while (0) #undef PRINTK #define PRINTK(fmt, args...) printk(KERN_INFO "{%s} " fmt, __func__, ## args) /*#define CODEC_REG_TRACE*/ #ifdef CODEC_REG_TRACE #define REG_WRITE(addr, val) \ do {\ PRINTK("REG_SET:0x%x -> 0x%0x\n", addr, val);\ REG32_VAL(addr) = (val);\ } while (0) #else #define REG_WRITE(addr, val) (REG32_VAL(addr) = (val)) #endif struct codec_lock { struct semaphore sem; unsigned int is_init; unsigned int is_locked; }; static struct codec_lock codec_lock[CODEC_MAX]; static int msvd_clk_enable_cnt; DEFINE_MUTEX(wmt_clk_mutex); #ifdef CFG_CODEC_PERFORM_EN static int wmt_codec_debug; struct wmt_tm { unsigned long seq_id; /* seqence number */ char name[16]; /* name */ unsigned int initial; /* initial flag */ unsigned int total_tm; /* total time */ unsigned int interval_tm; /* interval time */ unsigned int reset; /* reset counter */ unsigned int total_cnt; /* total counter */ unsigned int count; /* interval counter */ unsigned int max; /* max time */ unsigned int min; /* min time */ unsigned int threshold; struct timeval start; /* start time */ struct timeval end; /* end time */ } ; #endif /*!************************************************************************* * wmt_power_en * * Private Function * * \retval 0 if success */ static int wmt_power_en(int enable) { static DEFINE_SPINLOCK(wmt_power_lock); unsigned long flags = 0; unsigned int value; int ret = 0; static int wmt_open_cnt=0; if(enable){ spin_lock_irqsave(&wmt_power_lock, flags); wmt_open_cnt++; spin_unlock_irqrestore(&wmt_power_lock, flags); if(wmt_open_cnt == 1){ value = REG32_VAL(PM_CTRL_BASE_ADDR + 0x0604); *(volatile unsigned int *)(PM_CTRL_BASE_ADDR + 0x0604) = (value | 0x1); while((REG32_VAL(PM_CTRL_BASE_ADDR + 0x0604) & 0xf5) != 0xf1){}; } }else { spin_lock_irqsave(&wmt_power_lock, flags); if( wmt_open_cnt >= 1) { wmt_open_cnt--; }else { DBG_ERR("Unexpected WMT Codec power off, ignore it!\n"); ret = -1; } spin_unlock_irqrestore(&wmt_power_lock, flags); if(wmt_open_cnt == 0){ value = REG32_VAL(PM_CTRL_BASE_ADDR + 0x0604); *(volatile unsigned char *)(PM_CTRL_BASE_ADDR + 0x0604) = (value & ~(0x1)); while((REG32_VAL(PM_CTRL_BASE_ADDR + 0x0604) & 0xf5) != 0x00){}; } } return ret; } /* End of wmt_power_en() */ /*!************************************************************************* * msvd_power_en * * Private Function * * \retval 0 if success */ static int msvd_power_en(int enable) { static DEFINE_SPINLOCK(msvd_power_lock); unsigned long flags = 0; unsigned int value; int ret = 0; static int msvd_open_cnt = 0; if (enable) { spin_lock_irqsave(&msvd_power_lock, flags); msvd_open_cnt++; spin_unlock_irqrestore(&msvd_power_lock, flags); if(msvd_open_cnt == 1){ value = REG32_VAL(PM_CTRL_BASE_ADDR + 0x062C); *(volatile unsigned int *)(PM_CTRL_BASE_ADDR + 0x062C) = (value | 0x1); while((REG32_VAL(PM_CTRL_BASE_ADDR + 0x062C) & 0xf5) != 0xf1){}; } } else { spin_lock_irqsave(&msvd_power_lock, flags); if( msvd_open_cnt >= 1) { msvd_open_cnt--; }else { DBG_ERR("Unexpected MSVD Codec power off, ignore it!\n"); ret = -1; } spin_unlock_irqrestore(&msvd_power_lock, flags); if(msvd_open_cnt == 0){ value = REG32_VAL(PM_CTRL_BASE_ADDR + 0x062C); *(volatile unsigned int *)(PM_CTRL_BASE_ADDR + 0x062C) = (value & ~(0x1)); while((REG32_VAL(PM_CTRL_BASE_ADDR + 0x062C) & 0xf5) != 0x00){}; } } return 0; } /* End of msvd_power_en() */ /*!************************************************************************* * wmt_clock_en * * Public Function */ /*! * \brief * Set source PRD table * * \retval 0 if success */ int wmt_clock_en(int codec_type, int enable) { static DEFINE_SPINLOCK(clk_lock); unsigned long flags = 0; if ((codec_type < 0 ) || (codec_type >= CODEC_MAX)) { DBG_ERR("Unsupported codec ID %d\n", codec_type); return -1; } if (codec_type == CODEC_VD_JPEG) { spin_lock_irqsave(&clk_lock, flags); if (enable) { auto_pll_divisor(DEV_JDEC, CLK_ENABLE, 0, 0); auto_pll_divisor(DEV_MSVD, CLK_ENABLE, 0, 0); auto_pll_divisor(DEV_WMTVDU, CLK_ENABLE, 0, 0); auto_pll_divisor(DEV_WMTNA, CLK_ENABLE, 0, 0); } else { auto_pll_divisor(DEV_WMTNA, CLK_DISABLE, 0, 0); auto_pll_divisor(DEV_WMTVDU, CLK_DISABLE, 0, 0); auto_pll_divisor(DEV_MSVD, CLK_DISABLE, 0, 0); auto_pll_divisor(DEV_JDEC, CLK_DISABLE, 0, 0); } spin_unlock_irqrestore(&clk_lock, flags); } else if (codec_type == CODEC_VD_MSVD) { mutex_lock(&wmt_clk_mutex); if (enable) { auto_pll_divisor(DEV_WMTNA, CLK_ENABLE, 0, 0); auto_pll_divisor(DEV_CNMNA, CLK_ENABLE, 0, 0); auto_pll_divisor(DEV_MSVD, CLK_ENABLE, 0, 0); } else { auto_pll_divisor(DEV_MSVD, CLK_DISABLE, 0, 0); auto_pll_divisor(DEV_CNMNA, CLK_DISABLE, 0, 0); auto_pll_divisor(DEV_WMTNA, CLK_DISABLE, 0, 0); } mutex_unlock(&wmt_clk_mutex); } else if (codec_type == CODEC_VE_H264) { spin_lock_irqsave(&clk_lock, flags); if (enable) { auto_pll_divisor(DEV_WMTNA, CLK_ENABLE, 0, 0); auto_pll_divisor(DEV_MSVD, CLK_ENABLE, 0, 0); auto_pll_divisor(DEV_WMTVDU, CLK_ENABLE, 0, 0); auto_pll_divisor(DEV_H264, CLK_ENABLE, 0, 0); } else { auto_pll_divisor(DEV_H264, CLK_DISABLE, 0, 0); auto_pll_divisor(DEV_MSVD, CLK_DISABLE, 0, 0); auto_pll_divisor(DEV_WMTNA, CLK_DISABLE, 0, 0); auto_pll_divisor(DEV_WMTVDU, CLK_DISABLE, 0, 0); } spin_unlock_irqrestore(&clk_lock, flags); } else if (codec_type == CODEC_VE_JPEG) { spin_lock_irqsave(&clk_lock, flags); if (enable) { auto_pll_divisor(DEV_JENC, CLK_ENABLE, 0, 0); auto_pll_divisor(DEV_MSVD, CLK_ENABLE, 0, 0); auto_pll_divisor(DEV_WMTVDU, CLK_ENABLE, 0, 0); auto_pll_divisor(DEV_WMTNA, CLK_ENABLE, 0, 0); } else { auto_pll_divisor(DEV_WMTNA, CLK_DISABLE, 0, 0); auto_pll_divisor(DEV_WMTVDU, CLK_DISABLE, 0, 0); auto_pll_divisor(DEV_MSVD, CLK_DISABLE, 0, 0); auto_pll_divisor(DEV_JENC, CLK_DISABLE, 0, 0); } spin_unlock_irqrestore(&clk_lock, flags); } return 0; } /* End of wmt_clock_en() */ /*!************************************************************************* * wmt_get_codec_clock_count * * Private Function * * \retval 0 if success */ int wmt_get_codec_clock_count(void) { return msvd_clk_enable_cnt; } EXPORT_SYMBOL(wmt_get_codec_clock_count); /*!************************************************************************* * wmt_reset_codec_clock_count * * Private Function * * \retval 0 if success */ void wmt_reset_codec_clock_count(void) { msvd_clk_enable_cnt = 0; } EXPORT_SYMBOL(wmt_reset_codec_clock_count); /*!************************************************************************* * wmt_codec_clock_en * * Public Function */ /*! * \brief * * \retval 0 if success */ int wmt_codec_clock_en(int codec_type, int enable) { static DEFINE_SPINLOCK(clk_lock); unsigned long flags = 0; int ret = 0; if ((codec_type < 0 ) || (codec_type >= CODEC_MAX)) { DBG_ERR("Unsupported codec ID %d\n", codec_type); return -1; } if (codec_type == CODEC_VD_JPEG) { spin_lock_irqsave(&clk_lock, flags); if (enable) { REG_WRITE(MSVD_BASE_ADDR + 0x020, 0x0F); } else { REG_WRITE(MSVD_BASE_ADDR + 0x020, 0x00); } spin_unlock_irqrestore(&clk_lock, flags); } else if (codec_type == CODEC_VD_MSVD) { mutex_lock(&wmt_clk_mutex); if(enable) { msvd_clk_enable_cnt++; if(msvd_clk_enable_cnt == 1){ auto_pll_divisor(DEV_CNMVDU, CLK_ENABLE, 0, 0); REG_WRITE(MSVD_BASE_ADDR + 0x000, 0x07); } }else { if( msvd_clk_enable_cnt >= 1) { msvd_clk_enable_cnt--; if(msvd_clk_enable_cnt == 0){ REG_WRITE(MSVD_BASE_ADDR + 0x000, 0x00); auto_pll_divisor(DEV_CNMVDU, CLK_DISABLE, 0, 0); } }else { DBG_ERR("Unexpected MSVD Codec power off, ignore it!\n"); ret = -1; } } mutex_unlock(&wmt_clk_mutex); } else if (codec_type == CODEC_VE_H264 ) { spin_lock_irqsave(&clk_lock, flags); if(enable) { REG_WRITE(MSVD_BASE_ADDR + 0x040, 0x0F); }else { REG_WRITE(MSVD_BASE_ADDR + 0x040, 0x00); } spin_unlock_irqrestore(&clk_lock, flags); } else if (codec_type == CODEC_VE_JPEG) { spin_lock_irqsave(&clk_lock, flags); if (enable) { REG_WRITE(MSVD_BASE_ADDR + 0x060, 0x0F); } else { REG_WRITE(MSVD_BASE_ADDR + 0x060, 0x00); } spin_unlock_irqrestore(&clk_lock, flags); } return ret; } /* End of wmt_codec_clock_en() */ EXPORT_SYMBOL(wmt_codec_clock_en); /*!************************************************************************* * wmt_codec_pmc_ctl * * Public Function */ /*! * \brief * * \retval 0 if success */ int wmt_codec_pmc_ctl(int codec_type, int enable) { if ((codec_type < 0 ) || (codec_type >= CODEC_MAX)) { DBG_ERR("Unsupported codec ID %d\n", codec_type); return -1; } if (enable){ wmt_clock_en(codec_type, 1); /* WMT clock on */ wmt_power_en(1); /* WMT Codec power cotrol *//*PMC.0x604 */ if (codec_type == CODEC_VD_MSVD) msvd_power_en(1); /* MSVD Codec power control */ /*PMC.0x62c */ }else{ if (codec_type == CODEC_VD_MSVD) msvd_power_en(0); /* MSVD Codec power control */ /*PMC.0x62c */ wmt_power_en(0); /* WMT Codec power cotrol *//*PMC.0x604 */ wmt_clock_en(codec_type, 0); /* WMT clock on */ } return 0; } /* End of wmt_codec_pmc_ctl() */ EXPORT_SYMBOL(wmt_codec_pmc_ctl); /*!************************************************************************* * wmt_codec_msvd_reset * * Public Function */ /*! * \brief * * \retval 0 if success */ int wmt_codec_msvd_reset(int codec_type) { if (codec_type == CODEC_VD_MSVD) { /* Do MSVD SW reset */ REG_WRITE(MSVD_BASE_ADDR + 0x008, 0x07); REG_WRITE(MSVD_BASE_ADDR + 0x008, 0x00); /* automatic disable clock , BIT0 AHB, BIT1 core, BIT2 NA bus*/ REG_WRITE(MSVD_BASE_ADDR + 0x004, 0x00); /* Disable SRAM Power Down */ REG_WRITE(MSVD_BASE_ADDR + 0x00C, 0x00); } else if (codec_type == CODEC_VD_JPEG) { REG_WRITE(MSVD_BASE_ADDR + 0x028, 0xF); /* Enable MSVD SW reset */ REG_WRITE(MSVD_BASE_ADDR + 0x028, 0x0); /* Disable MSVD SW reset */ REG_WRITE(MSVD_BASE_ADDR + 0x02C, 0x0); /* Disable MSVD SW reset */ } else if (codec_type == CODEC_VE_H264) { REG_WRITE(MSVD_BASE_ADDR + 0x048, 0xF); /* Enable MSVD SW reset */ REG_WRITE(MSVD_BASE_ADDR + 0x048, 0x0); /* Disable MSVD SW reset */ REG_WRITE(MSVD_BASE_ADDR + 0x044, 0xC); /* Enable Auto disable clock */ REG_WRITE(MSVD_BASE_ADDR + 0x04C, 0x0); /* Disable SRAM Power down */ } else if (codec_type == CODEC_VE_JPEG) { REG_WRITE(MSVD_BASE_ADDR + 0x068, 0x0F); REG_WRITE(MSVD_BASE_ADDR + 0x068, 0x00); REG_WRITE(MSVD_BASE_ADDR + 0x06C, 0x00); } return 0; } /* End of wmt_codec_msvd_reset() */ EXPORT_SYMBOL(wmt_codec_msvd_reset); /*!************************************************************************* * wmt_codec_lock * * Public Function */ /*! * \brief * * \retval 0 if success */ int wmt_codec_lock(int codec_type, int timeout) { struct semaphore *sem; int ret = ret; if ((codec_type != CODEC_VD_JPEG) && (codec_type != CODEC_VE_JPEG)) return -1; if (codec_lock[codec_type].is_init != 1) { sema_init(&codec_lock[codec_type].sem, 1); codec_lock[codec_type].is_init = 1; } sem = &codec_lock[codec_type].sem; if (timeout == 0) { ret = down_trylock(sem); if (ret) ret = -ETIME; /* reasonable if lock holded by other */ } else if (timeout == -1) { ret = down_interruptible(sem); if (ret) DBG_ERR("<%d> down_interruptible fail (ret: %d)\n", codec_type, ret); } else { ret = down_timeout(sem, msecs_to_jiffies(timeout)); if (ret) DBG_MSG("<%d> down_timeout(%d ms) fail (ret: %d)\n", codec_type, timeout, ret); } if (ret == 0) codec_lock[codec_type].is_locked = 1; return ret; } /* End of wmt_codec_lock() */ EXPORT_SYMBOL(wmt_codec_lock); /*!************************************************************************* * wmt_codec_unlock * * Public Function */ /*! * \brief * * \retval 0 if success */ int wmt_codec_unlock(int codec_type) { if ((codec_type != CODEC_VD_JPEG) && (codec_type != CODEC_VE_JPEG)) return -1; if (codec_lock[codec_type].is_locked == 1) { up(&codec_lock[codec_type].sem); codec_lock[codec_type].is_locked = 0; } else { DBG_ERR("Try to unlock non-locked sem (%s)", (codec_type == CODEC_VD_JPEG) ? "jdec" : "jenc"); return -1; } return 0; } /* End of wmt_codec_unlock() */ EXPORT_SYMBOL(wmt_codec_unlock); /*!************************************************************************* * wmt_codec_write_prd * * Public Function */ /*! * \brief * Transfer the buffer address as PRD foramt * * \parameter * prd_addr [IN] Phyical address * * \retval 0 if success */ int wmt_codec_write_prd( unsigned int src_buf, unsigned int src_size, unsigned int prd_addr_in, unsigned int prd_buf_size) { #define PRD_MAX_SIZE (60*1024) unsigned char *buf_addr = (unsigned char *)src_buf; unsigned int buf_size = src_size; unsigned int *prd_addr = (unsigned int *)prd_addr_in; unsigned int items; unsigned int count = 0; /*---------------------------------------------------------------------- Transfer the input address as PRD foramt ----------------------------------------------------------------------*/ DBG_MSG("src_buf: 0x%x, src_size: %d, prd_addr_in: 0x%x\n", src_buf, src_size, prd_addr_in); items = prd_buf_size/8; while (buf_size > 0) { if (buf_size > PRD_MAX_SIZE) { *prd_addr++ = (unsigned int)buf_addr; *prd_addr++ = PRD_MAX_SIZE; buf_size -= PRD_MAX_SIZE; buf_addr += PRD_MAX_SIZE; } else { *prd_addr++ = (unsigned int)buf_addr; *prd_addr++ = (0x80000000 | buf_size); buf_size = 0; } count++; if (count > items) return -1; } return 0; } /* End of wmt_codec_write_prd() */ EXPORT_SYMBOL(wmt_codec_write_prd); /*!************************************************************************* * wmt_codec_dump_prd * * Public Function */ /*! * \brief * Dump data in PRD foramt for buffer * * \parameter * prd_addr [IN] Phyical address * * \retval 0 if success */ int wmt_codec_dump_prd(unsigned int prd_virt_in, int dump_data) { unsigned int prd_addr_in, prd_data_size = 0; unsigned int addr, len; int i, j; prd_addr_in = prd_virt_in; for (i = 0; ; i += 2) { addr = *(unsigned int *)(prd_addr_in + i * 4); len = *(unsigned int *)(prd_addr_in + (i + 1) * 4); prd_data_size += (len & 0xFFFF); PRINTK("[%02d]Addr: 0x%08x\n", i, addr); PRINTK(" Len: 0x%08x (%d)\n", len, (len & 0xFFFF)); if (dump_data) { unsigned char *ptr; ptr = (unsigned char *)phys_to_virt(addr); for (j = 0; j < (len & 0xFFFF); j++) { if ((j%16) == 15) PRINTK("0x%02x\n", *ptr); else PRINTK("0x%02x ", *ptr); ptr++; } } if (len & 0x80000000) break; } /* for(i=0; ; i+=2) */ PRINTK("Data size in PRD table: %d\n", prd_data_size); return 0; } /* End of wmt_codec_dump_prd() */ EXPORT_SYMBOL(wmt_codec_dump_prd); /*!************************************************************************* * check_debug_option * * Private Function */ /*! * \brief * Initial VD timer * * \retval 0 if success */ #ifdef CFG_CODEC_PERFORM_EN static void check_debug_option(void) { extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); static int s_first_run; if (s_first_run == 0) { char buf[80] = {0}; int varlen = 80; /* Read u-boot parameter to decide value of wmt_codec_debug */ if (wmt_getsyspara("wmt.codec.debug", buf, &varlen) == 0) wmt_codec_debug = simple_strtol(buf, NULL, 10); s_first_run = 1; } } /* End of check_debug_option() */ #endif /* #ifdef CFG_CODEC_PERFORM_EN */ /*!************************************************************************* * wmt_codec_timer_init * * API Function */ /*! * \brief * Initial VD timer * * \retval 0 if success */ int wmt_codec_timer_init( void **pphandle, const char *name, unsigned int count, int threshold_ms) { #ifdef CFG_CODEC_PERFORM_EN static atomic_t s_Seq_id = ATOMIC_INIT(0); struct wmt_tm *pcodec; check_debug_option(); if (wmt_codec_debug == 0) return 0; pcodec = kmalloc(sizeof(struct wmt_tm), GFP_KERNEL); if (pcodec == 0) DBG_ERR("Allocate %d bytes fail\n", sizeof(struct wmt_tm)); memset(pcodec, 0, sizeof(struct wmt_tm)); pcodec->reset = count; pcodec->threshold = threshold_ms * 1000; /* us */ pcodec->max = 0; pcodec->min = 0xFFFFFFF; pcodec->initial = 1; strcpy(pcodec->name, name); pcodec->seq_id = (unsigned long)(atomic_add_return(1, &s_Seq_id)); *pphandle = pcodec; #endif /* #ifdef CFG_CODEC_PERFORM_EN */ return 0; } /* End of wmt_codec_timer_init() */ EXPORT_SYMBOL(wmt_codec_timer_init); /*!************************************************************************* * wmt_codec_timer_reset_count * * API Function */ /*! * \brief * Release VD timer * * \retval 0 if success */ int wmt_codec_timer_reset(void *phandle, unsigned int count, int threshold_ms) { #ifdef CFG_CODEC_PERFORM_EN struct wmt_tm *pcodec = (struct wmt_tm *)phandle; if (pcodec) { pcodec->reset = count; pcodec->threshold = threshold_ms * 1000; /* us */ } #endif /* #ifdef CFG_CODEC_PERFORM_EN */ return 0; } /* End of wmt_codec_timer_reset_count() */ EXPORT_SYMBOL(wmt_codec_timer_reset); /*!************************************************************************* * wmt_codec_timer_start * * API Function */ /*! * \brief * Start a VD timer * * \retval 0 if success */ int wmt_codec_timer_start(void *phandle) { #ifdef CFG_CODEC_PERFORM_EN struct wmt_tm *pcodec = (struct wmt_tm *)phandle; if (wmt_codec_debug == 0) return 0; if (pcodec->initial != 1) { DBG_ERR("Timer was not initialized!\n"); return -1; } do_gettimeofday(&pcodec->start); #endif return 0; } /* End of wmt_codec_timer_start()*/ EXPORT_SYMBOL(wmt_codec_timer_start); /*!************************************************************************* * wmt_codec_timer_stop * * API Function */ /*! * \brief * Stop a VD timer * * \retval 0 if success */ int wmt_codec_timer_stop(void *phandle) { #ifdef CFG_CODEC_PERFORM_EN struct wmt_tm *pcodec = (struct wmt_tm *)phandle; int this_time; if (wmt_codec_debug == 0) return 0; if (pcodec->initial != 1) { DBG_ERR("timer was not initialized!\n"); return -1; } do_gettimeofday(&pcodec->end); /* unit in us */ if (pcodec->start.tv_sec == pcodec->end.tv_sec) { this_time = pcodec->end.tv_usec - pcodec->start.tv_usec; } else { this_time = (pcodec->end.tv_sec - pcodec->start.tv_sec)*1000000 + (pcodec->end.tv_usec - pcodec->start.tv_usec); } if (this_time < 0) { PRINTK("Start sec: %ld, usec: %ld\n", pcodec->start.tv_sec, pcodec->start.tv_usec); PRINTK("End sec: %ld, usec: %ld\n", pcodec->end.tv_sec, pcodec->end.tv_usec); } pcodec->total_tm += this_time; pcodec->interval_tm += this_time; pcodec->total_cnt++; if (this_time >= pcodec->max) pcodec->max = this_time; if (this_time <= pcodec->min) pcodec->min = this_time; if (pcodec->threshold && (this_time > pcodec->threshold)) { PRINTK("[%s] (%d) Decode time(%d) over %d (usec)\n", pcodec->name, pcodec->total_cnt, this_time, pcodec->threshold); } pcodec->count++; if ((pcodec->reset != 0) && (pcodec->count >= pcodec->reset)) { PRINTK("=================================================\n"); PRINTK("[%s] Avg. time = %d (usec)\n", pcodec->name, pcodec->interval_tm/pcodec->count); PRINTK("(~ %d) Decode Time Range[%d ~ %d](usec)\n", pcodec->total_cnt, pcodec->min, pcodec->max); pcodec->interval_tm = 0; pcodec->count = 0; } #endif /* #ifdef CFG_CODEC_PERFORM_EN */ return 0; } /* End of wmt_codec_timer_stop()*/ EXPORT_SYMBOL(wmt_codec_timer_stop); /*!************************************************************************* * wmt_codec_timer_exit * * API Function */ /*! * \brief * Release VD timer * * \retval 0 if success */ int wmt_codec_timer_exit(void *phandle) { #ifdef CFG_CODEC_PERFORM_EN struct wmt_tm *pcodec = (struct wmt_tm *)phandle; if (wmt_codec_debug == 0) return 0; if (pcodec == 0) DBG_ERR("Illegal NULL handle!\n"); if (pcodec->initial != 1) { DBG_ERR("Codec(%s) timer was not initialized!\n", pcodec->name); return -1; } if (pcodec->total_cnt) { unsigned int avg_tm = pcodec->total_tm/pcodec->total_cnt; PRINTK("=== [seq_id: %ld %s] Timer status:\n", pcodec->seq_id, pcodec->name); PRINTK("Total count = %d\n", pcodec->total_cnt); PRINTK("Total time = %d (usec)\n", pcodec->total_tm); PRINTK("Avg. time = %d (usec)\n", avg_tm); PRINTK("Max time = %d (usec)\n", pcodec->max); PRINTK("Min time = %d (usec)\n", pcodec->min); PRINTK("==========================================\n"); } /* reset all */ memset(pcodec, 0, sizeof(struct wmt_tm)); kfree(pcodec); #endif /* #ifdef CFG_CODEC_PERFORM_EN */ return 0; } /* End of wmt_codec_timer_exit()*/ EXPORT_SYMBOL(wmt_codec_timer_exit); MODULE_AUTHOR("WonderMedia Technologies, Inc."); MODULE_LICENSE("GPL"); /*--------------------End of Function Body -----------------------------------*/ #endif /* ifndef CODEC_C */