author | Jun Ma <Jun.Ma@amlogic.com> | 2020-02-20 14:20:16 (GMT) |
---|---|---|
committer | Jun Ma <Jun.Ma@amlogic.com> | 2020-02-23 12:14:20 (GMT) |
commit | bb80efa5322fc44573879da35919ab5a8394f775 (patch) | |
tree | d830159b1aab003ec00ec57219249842ffa1b45d | |
parent | f97ee3efa9241b4aeba1f49bd87b2ac29febb90b (diff) | |
download | media_modules-bb80efa5322fc44573879da35919ab5a8394f775.zip media_modules-bb80efa5322fc44573879da35919ab5a8394f775.tar.gz media_modules-bb80efa5322fc44573879da35919ab5a8394f775.tar.bz2 |
encoder: bring up SM1 H.265 encoder for kernel 5.4 [1/2]
PD#SWPL-19052
Problem:
SM1 H.265 encoder driver doesn't work on kernel 5.4
Solution:
Bring up encoder driver on kernel 5.4
At the same time it is compatible with kernel 4.9
Verify:
Verified on both kernel 5.4 and 4.9 on AC214
Change-Id: I4f825b3436731e4a666451fefe68e541293fc840
Signed-off-by: Jun Ma <Jun.Ma@amlogic.com>
-rw-r--r-- | drivers/frame_sink/encoder/h265/vpu.c | 131 |
1 files changed, 118 insertions, 13 deletions
diff --git a/drivers/frame_sink/encoder/h265/vpu.c b/drivers/frame_sink/encoder/h265/vpu.c index 40b47d0..0cf693a 100644 --- a/drivers/frame_sink/encoder/h265/vpu.c +++ b/drivers/frame_sink/encoder/h265/vpu.c @@ -41,6 +41,12 @@ #include <linux/of_reserved_mem.h> #include <linux/of_address.h> #include <linux/amlogic/media/codec_mm/codec_mm.h> +#include <linux/amlogic/cpu_version.h> +#include <linux/version.h> + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,1) +#include <linux/sched/signal.h> +#endif #include <linux/amlogic/media/utils/vdec_reg.h> #include "../../../common/media_clock/switch/amports_gate.h" @@ -52,6 +58,9 @@ /* if you want to have clock gating scheme frame by frame */ /* #define VPU_SUPPORT_CLOCK_CONTROL */ +#define VPU_SUPPORT_CLOCK_CONTROL + + #define VPU_PLATFORM_DEVICE_NAME "HevcEnc" #define VPU_DEV_NAME "HevcEnc" #define VPU_CLASS_NAME "HevcEnc" @@ -60,6 +69,8 @@ #define VM_RESERVED (VM_DONTEXPAND | VM_DONTDUMP) #endif +#define MHz (1000000) + #define VPU_INIT_VIDEO_MEMORY_SIZE_IN_BYTE (64 * SZ_1M) #define LOG_ALL 0 @@ -108,6 +119,18 @@ static struct vpu_bit_firmware_info_t s_bit_firmware_info[MAX_NUM_VPU_CORE]; static struct vpu_dma_cfg dma_cfg[3]; +struct vpu_clks { + struct clk *wave_aclk; + struct clk *wave_bclk; + struct clk *wave_cclk; +}; + +static struct vpu_clks s_vpu_clks; + +#define CHECK_RET(_ret) if (ret) {enc_pr(LOG_ERROR, \ + "%s:%d:function call failed with result: %d\n",\ + __FUNCTION__, __LINE__, _ret);} + static u32 vpu_src_addr_config(struct vpu_dma_buf_info_t); static void vpu_dma_buffer_unmap(struct vpu_dma_cfg *cfg); @@ -133,17 +156,72 @@ s32 vpu_hw_reset(void) return 0; } +s32 vpu_clk_prepare(struct device *dev, struct vpu_clks *clks) +{ + int ret; + + clks->wave_aclk = devm_clk_get(dev, "wave_clk_a"); + if (IS_ERR_OR_NULL(clks->wave_aclk)) { + enc_pr(LOG_ERROR, "failed to get wave aclk\n"); + return -1; + } + + clks->wave_bclk = devm_clk_get(dev, "wave_clk_b"); + if (IS_ERR_OR_NULL(clks->wave_aclk)) { + enc_pr(LOG_ERROR, "failed to get wave aclk\n"); + return -1; + } + + clks->wave_cclk = devm_clk_get(dev, "wave_clk_c"); + if (IS_ERR_OR_NULL(clks->wave_aclk)) { + enc_pr(LOG_ERROR, "failed to get wave aclk\n"); + return -1; + } + + ret = clk_set_rate(clks->wave_aclk, 400 * MHz); + CHECK_RET(ret); + ret = clk_set_rate(clks->wave_bclk, 400 * MHz); + CHECK_RET(ret); + ret = clk_set_rate(clks->wave_cclk, 400 * MHz); + CHECK_RET(ret); + ret = clk_prepare(clks->wave_aclk); + CHECK_RET(ret); + ret = clk_prepare(clks->wave_bclk); + CHECK_RET(ret); + ret = clk_prepare(clks->wave_cclk); + CHECK_RET(ret); + + enc_pr(LOG_ERROR, "wave_clk_a: %lu MHz\n", clk_get_rate(clks->wave_aclk) / 1000000); + enc_pr(LOG_ERROR, "wave_clk_b: %lu MHz\n", clk_get_rate(clks->wave_bclk) / 1000000); + enc_pr(LOG_ERROR, "wave_clk_c: %lu MHz\n", clk_get_rate(clks->wave_cclk) / 1000000); + + return 0; +} + +void vpu_clk_unprepare(struct device *dev, struct vpu_clks *clks) +{ + clk_unprepare(clks->wave_cclk); + devm_clk_put(dev, clks->wave_cclk); + + clk_unprepare(clks->wave_bclk); + devm_clk_put(dev, clks->wave_bclk); + + clk_unprepare(clks->wave_aclk); + devm_clk_put(dev, clks->wave_aclk); +} + s32 vpu_clk_config(u32 enable) { if (enable) { - if (get_cpu_type() >= MESON_CPU_MAJOR_ID_G12A) - HevcEnc_MoreClock_enable(); - HevcEnc_clock_enable(clock_level); + clk_enable(s_vpu_clks.wave_aclk); + clk_enable(s_vpu_clks.wave_bclk); + clk_enable(s_vpu_clks.wave_cclk); } else { - HevcEnc_clock_disable(); - if (get_cpu_type() >= MESON_CPU_MAJOR_ID_G12A) - HevcEnc_MoreClock_disable(); + clk_disable(s_vpu_clks.wave_cclk); + clk_disable(s_vpu_clks.wave_bclk); + clk_disable(s_vpu_clks.wave_aclk); } + return 0; } @@ -387,7 +465,7 @@ static s32 vpu_open(struct inode *inode, struct file *filp) } s_vpu_irq_requested = true; } - amports_switch_gate("vdec", 1); + spin_lock_irqsave(&s_vpu_lock, flags); WRITE_AOREG(AO_RTI_GEN_PWR_SLEEP0, READ_AOREG(AO_RTI_GEN_PWR_SLEEP0) & @@ -415,6 +493,7 @@ static s32 vpu_open(struct inode *inode, struct file *filp) READ_MPEG_REG(RESET0_REGISTER); READ_MPEG_REG(RESET0_REGISTER); READ_MPEG_REG(RESET0_REGISTER); + #ifndef VPU_SUPPORT_CLOCK_CONTROL vpu_clk_config(1); #endif @@ -1436,7 +1515,6 @@ static s32 vpu_release(struct inode *inode, struct file *filp) ? 0x8 : (0x3<<24))); udelay(10); spin_unlock_irqrestore(&s_vpu_lock, flags); - amports_switch_gate("vdec", 0); } } up(&s_vpu_sem); @@ -1736,6 +1814,7 @@ static ssize_t hevcenc_status_show(struct class *cla, return snprintf(buf, 40, "hevcenc_status_show\n"); } +#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,13,1) static struct class_attribute hevcenc_class_attrs[] = { __ATTR(encode_status, S_IRUGO | S_IWUSR, @@ -1748,6 +1827,23 @@ static struct class hevcenc_class = { .name = VPU_CLASS_NAME, .class_attrs = hevcenc_class_attrs, }; +#else /* LINUX_VERSION_CODE <= KERNEL_VERSION(4,13,1) */ + +static CLASS_ATTR_RO(hevcenc_status); + +static struct attribute *hevcenc_class_attrs[] = { + &class_attr_hevcenc_status.attr, + NULL +}; + +ATTRIBUTE_GROUPS(hevcenc_class); + +static struct class hevcenc_class = { + .name = VPU_CLASS_NAME, + .class_groups = hevcenc_class_groups, +}; +#endif /* LINUX_VERSION_CODE <= KERNEL_VERSION(4,13,1) */ + s32 init_HevcEnc_device(void) { @@ -1896,8 +1992,12 @@ static s32 vpu_probe(struct platform_device *pdev) s_vpu_clk = clk; #endif -#ifdef VPU_SUPPORT_CLOCK_CONTROL -#else + if (vpu_clk_prepare(&pdev->dev, &s_vpu_clks)) { + err = -ENOENT; + goto ERROR_PROVE_DEVICE; + } + +#ifndef VPU_SUPPORT_CLOCK_CONTROL vpu_clk_config(1); #endif @@ -1986,7 +2086,10 @@ ERROR_PROVE_DEVICE: memset(&s_vmem, 0, sizeof(struct video_mm_t)); } +#ifndef VPU_SUPPORT_CLOCK_CONTROL vpu_clk_config(0); +#endif + vpu_clk_unprepare(&pdev->dev, &s_vpu_clks); if (s_vpu_irq_requested == true) { if (s_vpu_irq >= 0) { @@ -2040,8 +2143,10 @@ static s32 vpu_remove(struct platform_device *pdev) 0, sizeof(struct vpudrv_buffer_t)); } hevc_pdev = NULL; +#ifndef VPU_SUPPORT_CLOCK_CONTROL vpu_clk_config(0); - +#endif + vpu_clk_unprepare(&pdev->dev, &s_vpu_clks); uninit_HevcEnc_device(); return 0; } @@ -2204,7 +2309,7 @@ DONE_WAKEUP: static const struct of_device_id cnm_hevcenc_dt_match[] = { { - .compatible = "cnm, HevcEnc", + .compatible = "amlogic, HevcEnc", }, {}, }; @@ -2287,4 +2392,4 @@ MODULE_LICENSE("GPL"); module_init(vpu_init); module_exit(vpu_exit); -RESERVEDMEM_OF_DECLARE(cnm_hevc, "cnm, HevcEnc-memory", hevc_mem_setup); +RESERVEDMEM_OF_DECLARE(amlogic, "amlogic, HevcEnc-memory", hevc_mem_setup); |