1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500 |
- /*
- * Copyright (c) 2016 MediaTek Inc.
- * Copyright (C) 2021 XiaoMi, Inc.
- * Author: Andrew-CT Chen <andrew-ct.chen@mediatek.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * 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 <asm/cacheflush.h>
- #include <linux/cdev.h>
- #include <linux/delay.h>
- #include <linux/dma-mapping.h>
- #include <linux/file.h>
- #include <linux/firmware.h>
- #include <linux/fs.h>
- #include <linux/init.h>
- #include <linux/interrupt.h>
- #include <linux/list.h>
- #include <linux/kernel.h>
- #include <linux/kthread.h>
- #include <linux/module.h>
- #include <linux/of_address.h>
- #include <linux/of_irq.h>
- #include <linux/of_platform.h>
- #include <linux/sched.h>
- #include <linux/sched/signal.h>
- #include <linux/sched/task.h>
- #include <linux/semaphore.h>
- #include <linux/suspend.h>
- #include <linux/uaccess.h>
- #include <linux/compat.h>
- #include <linux/freezer.h>
- #include <linux/pm_runtime.h>
- #include <linux/pm_wakeup.h>
- #include <linux/soc/mediatek/mtk-cmdq.h>
- #include <linux/mailbox/mtk-cmdq-mailbox.h>
- #include <linux/mailbox_controller.h>
- #include <linux/signal.h>
- #include <trace/events/signal.h>
- #include <linux/string.h>
- #ifdef CONFIG_MTK_IOMMU_V2
- #include <linux/iommu.h>
- #endif
- #include "mtk_vcodec_mem.h"
- #include <uapi/linux/mtk_vcu_controls.h>
- #include "mtk_vcu.h"
- #include "smi_public.h"
- /*
- #undef pr_debug
- #define pr_debug pr_info
- #undef dev_dbg
- #define dev_dbg dev_info
- */
- /**
- * VCU (Video Communication/Controller Unit) is a tiny processor
- * controlling video hardware related to video codec, scaling and color
- * format converting.
- * VCU interfaces with other blocks by share memory and interrupt.
- **/
- #define VCU_PATH "/dev/vpud"
- #define MDP_PATH "/dev/mdpd"
- #define CAM_PATH "/dev/camd"
- #define VCU_DEVNAME "vcu"
- #ifdef CONFIG_MTK_ENG_BUILD
- #define IPI_TIMEOUT_MS 16000U
- #else
- #define IPI_TIMEOUT_MS 5000U
- #endif
- #define VCU_FW_VER_LEN 16
- #define VCODEC_INST_MAX 64
- #define GCE_EVENT_MAX 64
- #define GCE_THNUM_MAX 2
- #define GCE_PENDING_CNT 10
- /*mtk vcu support mpd max value*/
- #define MTK_VCU_NR_MAX 3
- /* vcu extended mapping length */
- #define VCU_PMEM0_LEN(vcu_data) (vcu_data->extmem.p_len)
- #define VCU_DMEM0_LEN(vcu_data) (vcu_data->extmem.d_len)
- /* vcu extended user virtural address */
- #define VCU_PMEM0_VMA(vcu_data) (vcu_data->extmem.p_vma)
- #define VCU_DMEM0_VMA(vcu_data) (vcu_data->extmem.d_vma)
- /* vcu extended kernel virtural address */
- #define VCU_PMEM0_VIRT(vcu_data) (vcu_data->extmem.p_va)
- #define VCU_DMEM0_VIRT(vcu_data) (vcu_data->extmem.d_va)
- /* vcu extended phsyial address */
- #define VCU_PMEM0_PHY(vcu_data) (vcu_data->extmem.p_pa)
- #define VCU_DMEM0_PHY(vcu_data) (vcu_data->extmem.d_pa)
- /* vcu extended iova address*/
- #define VCU_PMEM0_IOVA(vcu_data) (vcu_data->extmem.p_iova)
- #define VCU_DMEM0_IOVA(vcu_data) (vcu_data->extmem.d_iova)
- #define VCU_SHMEM_SIZE 0x80000
- #define MAP_SHMEM_ALLOC_BASE 0x80000000UL
- #define MAP_SHMEM_ALLOC_RANGE VCU_SHMEM_SIZE
- #define MAP_SHMEM_ALLOC_END (MAP_SHMEM_ALLOC_BASE + MAP_SHMEM_ALLOC_RANGE)
- #define MAP_SHMEM_COMMIT_BASE 0x88000000UL
- #define MAP_SHMEM_COMMIT_RANGE VCU_SHMEM_SIZE
- #define MAP_SHMEM_COMMIT_END (MAP_SHMEM_COMMIT_BASE + MAP_SHMEM_COMMIT_RANGE)
- #define MAP_SHMEM_MM_BASE 0x200000000UL
- #define MAP_SHMEM_MM_CACHEABLE_BASE 0x400000000UL
- #define MAP_SHMEM_PA_BASE 0x800000000UL
- #define MAP_SHMEM_MM_RANGE 0x1FFFFFFFFUL
- #define MAP_SHMEM_MM_END (MAP_SHMEM_MM_BASE + MAP_SHMEM_MM_RANGE)
- #define MAP_SHMEM_MM_CACHEABLE_END (MAP_SHMEM_MM_CACHEABLE_BASE \
- + MAP_SHMEM_MM_RANGE)
- struct mtk_vcu *vcu_ptr;
- static char *vcodec_param_string = "";
- inline unsigned int ipi_id_to_inst_id(int id)
- {
- /* Assume VENC uses instance 1 and others use 0. */
- if (id < IPI_VENC_COMMON && id >= IPI_VCU_INIT)
- return VCU_VDEC;
- else
- return VCU_VENC;
- }
- #define vcu_dbg_log(fmt, arg...) do { \
- if (vcu_ptr->enable_vcu_dbg_log) \
- pr_info(fmt, ##arg); \
- } while (0)
- #define MAP_PA_BASE_1GB 0x40000000 /* < 1GB registers */
- #define VCU_MAP_HW_REG_NUM 4
- /* VDEC VDEC_LAT VENC_CORE0 VENC_CORE1 */
- /* Default vcu_mtkdev[0] handle vdec, vcu_mtkdev[1] handle mdp */
- static struct mtk_vcu *vcu_mtkdev[MTK_VCU_NR_MAX];
- static struct task_struct *vcud_task;
- static struct files_struct *files;
- /* for protecting vpud file struct */
- struct mutex vpud_file_mutex;
- static __attribute__((used)) unsigned int time_ms_s, time_ms_e;
- #define time_check_start() { \
- time_ms_s = jiffies_to_msecs(jiffies); \
- }
- #define time_check_end(timeout_ms, debug) do { \
- time_ms_e = jiffies_to_msecs(jiffies); \
- if ((time_ms_e - time_ms_s) > timeout_ms || \
- debug) \
- pr_info("[VCU][Info] %s L:%d take %u timeout %u ms", \
- __func__, __LINE__, \
- time_ms_e - time_ms_s, \
- timeout_ms); \
- } while (0)
- /**
- * struct vcu_mem - VCU memory information
- *
- * @p_vma: the user virtual memory address of
- * VCU extended program memory
- * @d_vma: the user virtual memory address of VCU extended data memory
- * @p_va: the kernel virtual memory address of
- * VCU extended program memory
- * @d_va: the kernel virtual memory address of VCU extended data memory
- * @p_pa: the physical memory address of VCU extended program memory
- * @d_pa: the physical memory address of VCU extended data memory
- * @p_iova: the iova memory address of VCU extended program memory
- * @d_iova: the iova memory address of VCU extended data memory
- */
- struct vcu_mem {
- unsigned long p_vma;
- unsigned long d_vma;
- void *p_va;
- void *d_va;
- dma_addr_t p_pa;
- dma_addr_t d_pa;
- dma_addr_t p_iova;
- dma_addr_t d_iova;
- unsigned long p_len;
- unsigned long d_len;
- };
- /**
- * struct vcu_run - VCU initialization status
- *
- * @signaled: the signal of vcu initialization completed
- * @fw_ver: VCU firmware version
- * @dec_capability: decoder capability which is not used for now and
- * the value is reserved for future use
- * @enc_capability: encoder capability which is not used for now and
- * the value is reserved for future use
- * @wq: wait queue for VCU initialization status
- */
- struct vcu_run {
- u32 signaled;
- char fw_ver[VCU_FW_VER_LEN];
- unsigned int dec_capability;
- unsigned int enc_capability;
- wait_queue_head_t wq;
- };
- /**
- * struct vcu_ipi_desc - VCU IPI descriptor
- *
- * @handler: IPI handler
- * @name: the name of IPI handler
- * @priv: the private data of IPI handler
- */
- struct vcu_ipi_desc {
- ipi_handler_t handler;
- const char *name;
- void *priv;
- };
- struct map_hw_reg {
- unsigned long base;
- unsigned long len;
- };
- struct gce_callback_data {
- struct gce_cmdq_obj cmdq_buff;
- struct mtk_vcu *vcu_ptr;
- struct cmdq_pkt *pkt_ptr;
- struct mtk_vcu_queue *vcu_queue;
- };
- struct gce_ctx_info {
- void *v4l2_ctx;
- u64 user_hdl;
- atomic_t flush_done;
- /* gce callbacked but user not waited cnt */
- struct gce_callback_data buff[GCE_PENDING_CNT];
- atomic_t flush_pending;
- /* gce not callbacked cnt */
- };
- /**
- * struct mtk_vcu - vcu driver data
- * @extmem: VCU extended memory information
- * @run: VCU initialization status
- * @ipi_desc: VCU IPI descriptor
- * @dev: VCU struct device
- * @vcu_mutex: protect mtk_vcu (except recv_buf) and ensure only
- * one client to use VCU service at a time. For example,
- * suppose a client is using VCU to decode VP8.
- * If the other client wants to encode VP8,
- * it has to wait until VP8 decode completes.
- * @vcu_gce_mutex protect mtk_vcu gce flush & callback power sequence
- * @file: VCU daemon file pointer
- * @is_open: The flag to indicate if VCUD device is open.
- * @ack_wq: The wait queue for each codec and mdp. When sleeping
- * processes wake up, they will check the condition
- * "ipi_id_ack" to run the corresponding action or
- * go back to sleep.
- * @ipi_id_ack: The ACKs for registered IPI function sending
- * interrupt to VCU
- * @get_wq: When sleeping process waking up, it will check the
- * condition "ipi_got" to run the corresponding action or
- * go back to sleep.
- * @ipi_got: The flags for IPI message polling from user.
- * @ipi_done: The flags for IPI message polling from user again, which
- * means the previous messages has been dispatched done in
- * daemon.
- * @user_obj: Temporary share_obj used for ipi_msg_get.
- * @vcu_devno: The vcu_devno for vcu init vcu character device
- * @vcu_cdev: The point of vcu character device.
- * @vcu_class: The class_create for create vcu device
- * @vcu_device: VCU struct device
- * @vcuname: VCU struct device name in dtsi
- * @path: The path to keep mdpd path or vcud path.
- * @vpuid: VCU device id
- *
- */
- struct mtk_vcu {
- struct vcu_mem extmem;
- struct vcu_run run;
- struct vcu_ipi_desc ipi_desc[IPI_MAX];
- struct device *dev;
- struct mutex vcu_mutex[VCU_CODEC_MAX];
- struct mutex vcu_gce_mutex[VCU_CODEC_MAX];
- struct mutex ctx_ipi_binding[VCU_CODEC_MAX];
- /* for protecting vcu data structure */
- struct mutex vcu_share;
- struct file *file;
- struct iommu_domain *io_domain;
- bool iommu_padding;
- /* temp for 33bits larb adding bits "1" iommu */
- struct map_hw_reg map_base[VCU_MAP_HW_REG_NUM];
- bool is_open;
- wait_queue_head_t ack_wq[VCU_CODEC_MAX];
- bool ipi_id_ack[IPI_MAX];
- wait_queue_head_t get_wq[VCU_CODEC_MAX];
- atomic_t ipi_got[VCU_CODEC_MAX];
- atomic_t ipi_done[VCU_CODEC_MAX];
- struct share_obj user_obj[VCU_CODEC_MAX];
- dev_t vcu_devno;
- struct cdev *vcu_cdev;
- struct class *vcu_class;
- struct device *vcu_device;
- const char *vcuname;
- const char *path;
- int vcuid;
- struct log_test_nofuse *vdec_log_info;
- wait_queue_head_t vdec_log_get_wq;
- atomic_t vdec_log_got;
- struct cmdq_base *clt_base;
- struct cmdq_client *clt_vdec[GCE_THNUM_MAX];
- struct cmdq_client *clt_venc[GCE_THNUM_MAX];
- struct cmdq_client *clt_venc_sec[GCE_THNUM_MAX];
- int gce_th_num[VCU_CODEC_MAX];
- int gce_codec_eid[GCE_EVENT_MAX];
- struct gce_cmds *gce_cmds[VCU_CODEC_MAX];
- void *curr_ctx[VCU_CODEC_MAX];
- struct vb2_buffer *curr_src_vb[VCU_CODEC_MAX];
- struct vb2_buffer *curr_dst_vb[VCU_CODEC_MAX];
- wait_queue_head_t gce_wq[VCU_CODEC_MAX];
- struct gce_ctx_info gce_info[VCODEC_INST_MAX];
- atomic_t gce_job_cnt[VCU_CODEC_MAX][GCE_THNUM_MAX];
- unsigned long flags[VCU_CODEC_MAX];
- int open_cnt;
- bool abort;
- struct semaphore vpud_killed;
- bool is_entering_suspend;
- u32 gce_gpr[GCE_THNUM_MAX];
- /* for gce poll timer, multi-thread sync */
- /* for vpud sig check */
- spinlock_t vpud_sig_lock;
- int vpud_is_going_down;
- /* for vcu dbg log*/
- int enable_vcu_dbg_log;
- };
- static inline bool vcu_running(struct mtk_vcu *vcu)
- {
- return (bool)vcu->run.signaled;
- }
- int vcu_ipi_register(struct platform_device *pdev,
- enum ipi_id id, ipi_handler_t handler,
- const char *name, void *priv)
- {
- struct mtk_vcu *vcu = platform_get_drvdata(pdev);
- struct vcu_ipi_desc *ipi_desc;
- unsigned int i = 0;
- if (vcu == NULL) {
- dev_err(&pdev->dev, "vcu device in not ready\n");
- return -EPROBE_DEFER;
- }
- if (id < IPI_VCU_INIT || id >= IPI_MAX) {
- dev_info(&pdev->dev, "[VCU] failed to register ipi message (Invalid arg.)\n");
- return -EINVAL;
- }
- i = ipi_id_to_inst_id(id);
- mutex_lock(&vcu->vcu_mutex[i]);
- if (id >= IPI_VCU_INIT && id < IPI_MAX && handler != NULL) {
- ipi_desc = vcu->ipi_desc;
- ipi_desc[id].name = name;
- ipi_desc[id].handler = handler;
- ipi_desc[id].priv = priv;
- mutex_unlock(&vcu->vcu_mutex[i]);
- return 0;
- }
- mutex_unlock(&vcu->vcu_mutex[i]);
- dev_err(&pdev->dev, "register vcu ipi id %d with invalid arguments\n",
- id);
- return -EINVAL;
- }
- EXPORT_SYMBOL_GPL(vcu_ipi_register);
- int vcu_ipi_send(struct platform_device *pdev,
- enum ipi_id id, void *buf,
- unsigned int len, void *priv)
- {
- unsigned int i = 0;
- struct mtk_vcu *vcu = platform_get_drvdata(pdev);
- struct vcu_ipi_desc *ipi_desc;
- struct share_obj send_obj;
- unsigned long timeout;
- int ret;
- if (id <= IPI_VCU_INIT || id >= IPI_MAX ||
- len > sizeof(send_obj.share_buf) || buf == NULL) {
- dev_err(&pdev->dev, "[VCU] failed to send ipi message (Invalid arg.)\n");
- return -EINVAL;
- }
- if (vcu_running(vcu) == false) {
- dev_err(&pdev->dev, "[VCU] %s: VCU is not running\n", __func__);
- return -EPERM;
- }
- i = ipi_id_to_inst_id(id);
- mutex_lock(&vcu->vcu_mutex[i]);
- if (vcu_ptr->abort) {
- if (vcu_ptr->open_cnt > 0) {
- dev_info(vcu->dev, "wait for vpud killed %d\n",
- vcu_ptr->vpud_killed.count);
- ret = down_interruptible(&vcu_ptr->vpud_killed);
- }
- dev_info(&pdev->dev, "[VCU] vpud killed\n");
- mutex_unlock(&vcu->vcu_mutex[i]);
- return -EIO;
- }
- vcu->ipi_id_ack[id] = false;
- if (id >= IPI_VCU_INIT && id < IPI_MAX) {
- ipi_desc = vcu->ipi_desc;
- ipi_desc[id].priv = priv;
- }
- /* send the command to VCU */
- memcpy((void *)vcu->user_obj[i].share_buf, buf, len);
- vcu->user_obj[i].len = len;
- vcu->user_obj[i].id = (int)id;
- atomic_set(&vcu->ipi_got[i], 1);
- atomic_set(&vcu->ipi_done[i], 0);
- wake_up(&vcu->get_wq[i]);
- /* wait for VCU's ACK */
- timeout = msecs_to_jiffies(IPI_TIMEOUT_MS);
- ret = wait_event_timeout(vcu->ack_wq[i], vcu->ipi_id_ack[id], timeout);
- vcu->ipi_id_ack[id] = false;
- if (vcu_ptr->abort || ret == 0) {
- dev_info(&pdev->dev, "vcu ipi %d ack time out !%d", id, ret);
- if (!vcu_ptr->abort) {
- task_lock(vcud_task);
- send_sig(SIGTERM, vcud_task, 0);
- task_unlock(vcud_task);
- }
- if (vcu_ptr->open_cnt > 0) {
- dev_info(vcu->dev, "wait for vpud killed %d\n",
- vcu_ptr->vpud_killed.count);
- ret = down_interruptible(&vcu_ptr->vpud_killed);
- }
- dev_info(&pdev->dev, "[VCU] vpud killed\n");
- ret = -EIO;
- mutex_unlock(&vcu->vcu_mutex[i]);
- goto end;
- } else if (-ERESTARTSYS == ret) {
- dev_err(&pdev->dev, "vcu ipi %d ack wait interrupted by a signal",
- id);
- ret = -ERESTARTSYS;
- mutex_unlock(&vcu->vcu_mutex[i]);
- goto end;
- } else {
- ret = 0;
- mutex_unlock(&vcu->vcu_mutex[i]);
- }
- /* Waiting ipi_done, success means the daemon receiver thread
- * dispatchs ipi msg done and returns to kernel for get next
- * ipi msg.
- * The dispatched ipi msg is being processed by app service.
- * Usually, it takes dozens of microseconds in average.
- */
- while (atomic_read(&vcu->ipi_done[i]) == 0)
- cond_resched();
- end:
- return ret;
- }
- EXPORT_SYMBOL_GPL(vcu_ipi_send);
- static int vcu_ipi_get(struct mtk_vcu *vcu, unsigned long arg)
- {
- unsigned int i = 0;
- int ret;
- unsigned char *user_data_addr = NULL;
- struct share_obj share_buff_data;
- user_data_addr = (unsigned char *)arg;
- ret = (long)copy_from_user(&share_buff_data, user_data_addr,
- (unsigned long)sizeof(struct share_obj));
- if (ret != 0) {
- pr_info("[VCU] %s(%d) Copy data from user failed!\n",
- __func__, __LINE__);
- return -EINVAL;
- }
- i = ipi_id_to_inst_id(share_buff_data.id);
- /* mutex protection here is unnecessary, since different app service
- * threads of daemon are corresponding to different vcu_ipi_get thread.
- * Different threads use differnet variables, e.g. ipi_done.
- */
- atomic_set(&vcu->ipi_done[i], 1);
- ret = wait_event_freezable(vcu->get_wq[i],
- atomic_read(&vcu->ipi_got[i]));
- if (ret != 0) {
- pr_info("[VCU][%d][%d] wait event return %d @%s\n",
- vcu->vcuid, i, ret, __func__);
- return ret;
- }
- ret = copy_to_user(user_data_addr, &vcu->user_obj[i],
- (unsigned long)sizeof(struct share_obj));
- if (ret != 0) {
- pr_info("[VCU] %s(%d) Copy data to user failed!\n",
- __func__, __LINE__);
- ret = -EINVAL;
- }
- atomic_set(&vcu->ipi_got[i], 0);
- return ret;
- }
- static int vcu_log_get(struct mtk_vcu *vcu, unsigned long arg)
- {
- int ret;
- unsigned char *user_data_addr = NULL;
- user_data_addr = (unsigned char *)arg;
- ret = wait_event_freezable(vcu->vdec_log_get_wq,
- atomic_read(&vcu->vdec_log_got));
- if (ret != 0) {
- pr_info("[VCU][%d] wait event return %d @%s\n",
- vcu->vcuid, ret, __func__);
- return ret;
- }
- ret = copy_to_user(user_data_addr, vcu->vdec_log_info,
- (unsigned long)sizeof(struct log_test_nofuse));
- if (ret != 0) {
- pr_info("[VCU] %s(%d) Copy data to user failed!\n",
- __func__, __LINE__);
- ret = -EINVAL;
- }
- atomic_set(&vcu->vdec_log_got, 0);
- return ret;
- }
- static int vcu_gce_set_inst_id(void *ctx, u64 gce_handle)
- {
- int i;
- char data;
- mutex_lock(&vcu_ptr->vcu_share);
- for (i = 0; i < VCODEC_INST_MAX; i++) {
- if (vcu_ptr->gce_info[i].v4l2_ctx == NULL &&
- !probe_kernel_address(ctx, data)) {
- vcu_ptr->gce_info[i].v4l2_ctx = ctx;
- vcu_ptr->gce_info[i].user_hdl = gce_handle;
- mutex_unlock(&vcu_ptr->vcu_share);
- vcu_dbg_log("[VCU] %s ctx %p hndl %llu create id %d\n",
- __func__, ctx, gce_handle, i);
- return i;
- }
- }
- mutex_unlock(&vcu_ptr->vcu_share);
- pr_info("[VCU] %s fail ctx %p hndl %llu\n",
- __func__, ctx, gce_handle);
- return -1;
- }
- static int vcu_gce_get_inst_id(u64 gce_handle)
- {
- int i, temp;
- mutex_lock(&vcu_ptr->vcu_share);
- for (i = 0; i < VCODEC_INST_MAX; i++) {
- if (vcu_ptr->gce_info[i].user_hdl == gce_handle) {
- temp = atomic_read(&vcu_ptr->gce_info[i].flush_done);
- mutex_unlock(&vcu_ptr->vcu_share);
- vcu_dbg_log("[VCU] %s hndl %llu get id %d cnt %d\n",
- __func__, gce_handle, i, temp);
- return i;
- }
- }
- mutex_unlock(&vcu_ptr->vcu_share);
- return -1;
- }
- static void vcu_gce_clear_inst_id(void *ctx)
- {
- int i, temp, temp2;
- u64 gce_handle;
- mutex_lock(&vcu_ptr->vcu_share);
- for (i = 0; i < VCODEC_INST_MAX; i++) {
- if (vcu_ptr->gce_info[i].v4l2_ctx == ctx) {
- gce_handle = vcu_ptr->gce_info[i].user_hdl;
- vcu_ptr->gce_info[i].v4l2_ctx = NULL;
- vcu_ptr->gce_info[i].user_hdl = 0;
- temp = atomic_read(&vcu_ptr->gce_info[i].flush_pending);
- /* flush_pending > 0, ctx hw not unprepared */
- temp2 = atomic_read(&vcu_ptr->gce_info[i].flush_done);
- /* flush_done > 0, user event not waited */
- atomic_set(&vcu_ptr->gce_info[i].flush_done, 0);
- atomic_set(&vcu_ptr->gce_info[i].flush_pending, 0);
- mutex_unlock(&vcu_ptr->vcu_share);
- if (temp > 0)
- vcu_aee_print(
- "%s %p hndl %llu free id %d cnt %d %d\n",
- __func__, ctx, gce_handle,
- i, temp, temp2);
- else if (temp2 > 0)
- pr_info("%s %p hndl %llu free id %d cnt %d %d\n",
- __func__, ctx, gce_handle,
- i, temp, temp2);
- else
- vcu_dbg_log(
- "%s %p hndl %llu free id %d cnt %d %d\n",
- __func__, ctx, gce_handle,
- i, temp, temp2);
- return;
- }
- }
- mutex_unlock(&vcu_ptr->vcu_share);
- pr_info("%s ctx %p not found!\n", __func__, ctx);
- }
- static void *vcu_check_gce_pa_base(struct mtk_vcu_queue *vcu_queue, u64 addr, u64 length)
- {
- struct vcu_pa_pages *tmp;
- struct list_head *p, *q;
- list_for_each_safe(p, q, &vcu_queue->pa_pages.list) {
- tmp = list_entry(p, struct vcu_pa_pages, list);
- if (addr >= (u64)tmp->pa &&
- addr + length <= (u64)tmp->pa + PAGE_SIZE)
- return tmp;
- }
- pr_info("%s addr %x length %x not found!\n", __func__, addr, length);
- return NULL;
- }
- static int vcu_check_reg_base(struct mtk_vcu *vcu, u64 addr, u64 length)
- {
- int i;
- if (vcu->vcuid != 0 || addr >= MAP_PA_BASE_1GB)
- return -EINVAL;
- for (i = 0; i < (int)VCU_MAP_HW_REG_NUM; i++)
- if (addr >= (u64)vcu->map_base[i].base &&
- addr + length <= (u64)vcu->map_base[i].base + vcu->map_base[i].len)
- return 0;
- pr_info("%s addr %x length %x not found!\n", __func__, addr, length);
- return -EINVAL;
- }
- static void vcu_set_gce_cmd(struct cmdq_pkt *pkt,
- struct mtk_vcu *vcu, struct mtk_vcu_queue *q, unsigned char cmd,
- u64 addr, u64 data, u32 mask, u32 gpr, u32 dma_offset, u32 dma_size)
- {
- switch (cmd) {
- case CMD_READ:
- if (vcu_check_reg_base(vcu, addr, 4) == 0)
- cmdq_pkt_read_addr(pkt, addr, CMDQ_THR_SPR_IDX1);
- else
- pr_info("[VCU] CMD_READ wrong addr: 0x%x\n", addr);
- break;
- case CMD_WRITE:
- if (vcu_check_reg_base(vcu, addr, 4) == 0)
- cmdq_pkt_write(pkt, vcu->clt_base, addr, data, mask);
- else
- pr_info("[VCU] CMD_WRITE wrong addr: 0x%x 0x%x 0x%x\n",
- addr, data, mask);
- break;
- #if defined(CONFIG_MTK_SEC_VIDEO_PATH_SUPPORT)
- case CMD_SEC_WRITE:
- #if defined(CONFIG_MTK_CMDQ_MBOX_EXT)
- if (vcu_check_reg_base(vcu, addr, 4) == 0)
- cmdq_sec_pkt_write_reg(pkt,
- addr,
- data,
- CMDQ_IWC_H_2_MVA,
- dma_offset,
- dma_size,
- 0);
- else
- pr_info("[VCU] CMD_SEC_WRITE wrong addr: 0x%x 0x%x 0x%x 0x%x\n",
- addr, data, dma_offset, dma_size);
- #endif
- pr_debug("[VCU] %s addr: 0x%x, data: 0x%x, offset: 0x%x, size: 0x%x\n",
- __func__, addr, data, dma_offset, dma_size);
- break;
- #endif
- case CMD_POLL_REG:
- if (vcu_check_reg_base(vcu, addr, 4) == 0)
- cmdq_pkt_poll_addr(pkt, data, addr, mask, gpr);
- else
- pr_info("[VCU] CMD_POLL_REG wrong addr: 0x%x 0x%x 0x%x\n",
- addr, data, mask);
- break;
- case CMD_WAIT_EVENT:
- if (data < GCE_EVENT_MAX)
- cmdq_pkt_wfe(pkt, vcu->gce_codec_eid[data]);
- else
- pr_info("[VCU] %s got wrong eid %llu\n",
- __func__, data);
- break;
- case CMD_MEM_MV:
- if ((vcu_check_reg_base(vcu, addr, 4) == 0 ||
- vcu_check_gce_pa_base(q, addr, 4) != NULL) &&
- vcu_check_gce_pa_base(q, data, 4) != NULL)
- cmdq_pkt_mem_move(pkt, vcu->clt_base, addr,
- data, CMDQ_THR_SPR_IDX1);
- else
- pr_info("[VCU] CMD_MEM_MV wrong addr/data: 0x%x 0x%x\n",
- addr, data);
- break;
- case CMD_POLL_ADDR:
- if (vcu_check_reg_base(vcu, addr, 4) == 0 ||
- vcu_check_gce_pa_base(q, addr, 4) != NULL)
- cmdq_pkt_poll_timeout(pkt, data, SUBSYS_NO_SUPPORT,
- addr, mask, ~0, gpr);
- else
- pr_info("[VCU] CMD_POLL_REG wrong addr: 0x%x 0x%x 0x%x\n",
- addr, data, mask);
- break;
- default:
- vcu_dbg_log("[VCU] unknown GCE cmd %d\n", cmd);
- break;
- }
- }
- static void vcu_gce_flush_callback(struct cmdq_cb_data data)
- {
- int i, j;
- struct gce_callback_data *buff;
- struct mtk_vcu *vcu;
- unsigned int core_id;
- buff = (struct gce_callback_data *)data.data;
- i = (buff->cmdq_buff.codec_type == VCU_VDEC) ? VCU_VDEC : VCU_VENC;
- core_id = buff->cmdq_buff.core_id;
- vcu = buff->vcu_ptr;
- j = vcu_gce_get_inst_id(buff->cmdq_buff.gce_handle);
- if (j < 0) {
- pr_info("[VCU] flush_callback get_inst_id fail!!%d\n", j);
- return;
- }
- atomic_inc(&vcu->gce_info[j].flush_done);
- atomic_dec(&vcu->gce_info[j].flush_pending);
- mutex_lock(&vcu->vcu_gce_mutex[i]);
- venc_encode_pmqos_gce_end(vcu->gce_info[j].v4l2_ctx, core_id,
- vcu->gce_job_cnt[i][core_id].counter);
- if (atomic_dec_and_test(&vcu->gce_job_cnt[i][core_id]) &&
- vcu->gce_info[j].v4l2_ctx != NULL){
- if (i == VCU_VENC)
- venc_encode_unprepare(vcu->gce_info[j].v4l2_ctx,
- buff->cmdq_buff.core_id, &vcu->flags[i]);
- }
- mutex_unlock(&vcu->vcu_gce_mutex[i]);
- wake_up(&vcu->gce_wq[i]);
- vcu_dbg_log("[VCU][%d] %s: buff %p type %d order %d handle %llx\n",
- core_id, __func__, buff, buff->cmdq_buff.codec_type,
- buff->cmdq_buff.flush_order, buff->cmdq_buff.gce_handle);
- cmdq_pkt_destroy(buff->pkt_ptr);
- }
- static void vcu_gce_timeout_callback(struct cmdq_cb_data data)
- {
- struct gce_callback_data *buff;
- struct mtk_vcu *vcu;
- struct list_head *p, *q;
- struct mtk_vcu_queue *vcu_queue;
- struct vcu_pa_pages *tmp;
- buff = (struct gce_callback_data *)data.data;
- vcu = buff->vcu_ptr;
- vcu_queue = buff->vcu_queue;
- vcu_dbg_log("%s: buff %p vcu: %p, codec_typ: %d\n",
- __func__, buff, vcu, buff->cmdq_buff.codec_type);
- if (buff->cmdq_buff.codec_type == VCU_VENC)
- mtk_vcodec_gce_timeout_dump(vcu->curr_ctx[VCU_VENC]);
- else if (buff->cmdq_buff.codec_type == VCU_VDEC)
- mtk_vcodec_gce_timeout_dump(vcu->curr_ctx[VCU_VDEC]);
- list_for_each_safe(p, q, &vcu_queue->pa_pages.list) {
- tmp = list_entry(p, struct vcu_pa_pages, list);
- pr_info("%s: vcu_pa_pages %lx kva %lx data %lx\n",
- __func__, tmp->pa, tmp->kva,
- *(unsigned long *)tmp->kva);
- }
- }
- static int vcu_gce_cmd_flush(struct mtk_vcu *vcu,
- struct mtk_vcu_queue *q, unsigned long arg)
- {
- int i, j, ret;
- unsigned char *user_data_addr = NULL;
- struct gce_callback_data buff;
- struct cmdq_pkt *pkt_ptr;
- struct cmdq_client *cl;
- struct gce_cmds *cmds;
- unsigned int suspend_block_cnt = 0;
- unsigned int core_id;
- vcu_dbg_log("[VCU] %s +\n", __func__);
- time_check_start();
- user_data_addr = (unsigned char *)arg;
- ret = (long)copy_from_user(&buff.cmdq_buff, user_data_addr,
- (unsigned long)sizeof(struct gce_cmdq_obj));
- if (ret != 0L) {
- pr_info("[VCU] %s(%d) gce_cmdq_obj copy_from_user failed!%d\n",
- __func__, __LINE__, ret);
- return -EINVAL;
- }
- i = (buff.cmdq_buff.codec_type == VCU_VDEC) ? VCU_VDEC : VCU_VENC;
- cmds = vcu->gce_cmds[i];
- user_data_addr = (unsigned char *)
- (unsigned long)buff.cmdq_buff.cmds_user_ptr;
- ret = (long)copy_from_user(cmds, user_data_addr,
- (unsigned long)sizeof(struct gce_cmds));
- if (ret != 0L) {
- pr_info("[VCU] %s(%d) gce_cmds copy_from_user failed!%d\n",
- __func__, __LINE__, ret);
- return -EINVAL;
- }
- buff.cmdq_buff.cmds_user_ptr = (u64)(unsigned long)cmds;
- core_id = buff.cmdq_buff.core_id;
- if (buff.cmdq_buff.codec_type >= VCU_CODEC_MAX ||
- core_id >=
- vcu->gce_th_num[buff.cmdq_buff.codec_type]) {
- pr_info("[VCU] %s invalid core(th) id %d\n",
- __func__, core_id);
- return -EINVAL;
- }
- cl = (buff.cmdq_buff.codec_type == VCU_VDEC) ?
- vcu->clt_vdec[core_id] :
- vcu->clt_venc[core_id];
- #if defined(CONFIG_MTK_SEC_VIDEO_PATH_SUPPORT)
- if (buff.cmdq_buff.codec_type == VCU_VENC) {
- if (buff.cmdq_buff.secure != 0) {
- cl = vcu->clt_venc_sec[0];
- }
- }
- #endif
- if (cl == NULL) {
- pr_info("[VCU] %s gce thread is null id %d type %d\n",
- __func__, core_id,
- buff.cmdq_buff.codec_type);
- return -EINVAL;
- }
- buff.vcu_ptr = vcu;
- buff.vcu_queue = q;
- while (vcu_ptr->is_entering_suspend == 1) {
- suspend_block_cnt++;
- if (suspend_block_cnt > 500) {
- pr_info("[VCU] gce_flush blocked by suspend\n");
- suspend_block_cnt = 0;
- }
- usleep_range(10000, 20000);
- }
- j = vcu_gce_get_inst_id(buff.cmdq_buff.gce_handle);
- if (j < 0)
- j = vcu_gce_set_inst_id(vcu->curr_ctx[i],
- buff.cmdq_buff.gce_handle);
- if (j < 0) {
- return -EINVAL;
- }
- time_check_end(100, strlen(vcodec_param_string));
- time_check_start();
- mutex_lock(&vcu->vcu_gce_mutex[i]);
- if (atomic_read(&vcu->gce_job_cnt[i][core_id]) == 0 &&
- vcu->gce_info[j].v4l2_ctx != NULL){
- if (i == VCU_VENC) {
- venc_encode_prepare(vcu->gce_info[j].v4l2_ctx,
- core_id, &vcu->flags[i]);
- }
- }
- vcu_dbg_log("vcu gce_info[%d].v4l2_ctx %p\n",
- j, vcu->gce_info[j].v4l2_ctx);
- if (i == VCU_VENC) {
- venc_encode_pmqos_gce_begin(vcu->gce_info[j].v4l2_ctx, core_id,
- vcu->gce_job_cnt[i][core_id].counter);
- }
- atomic_inc(&vcu->gce_job_cnt[i][core_id]);
- mutex_unlock(&vcu->vcu_gce_mutex[i]);
- time_check_end(100, strlen(vcodec_param_string));
- time_check_start();
- pkt_ptr = cmdq_pkt_create(cl);
- if (IS_ERR_OR_NULL(pkt_ptr)) {
- pr_info("[VCU] cmdq_pkt_create fail\n");
- pkt_ptr = NULL;
- }
- buff.pkt_ptr = pkt_ptr;
- if (cmds->cmd_cnt >= VCODEC_CMDQ_CMD_MAX) {
- pr_info("[VCU] cmd_cnt (%d) overflow!!\n", cmds->cmd_cnt);
- cmds->cmd_cnt = VCODEC_CMDQ_CMD_MAX;
- ret = -EINVAL;
- }
- #if defined(CONFIG_MTK_SEC_VIDEO_PATH_SUPPORT)
- if (buff.cmdq_buff.codec_type == VCU_VENC) {
- if (buff.cmdq_buff.secure != 0) {
- const u64 dapc_engine =
- (1LL << CMDQ_SEC_VENC_BSDMA) |
- (1LL << CMDQ_SEC_VENC_CUR_LUMA) |
- (1LL << CMDQ_SEC_VENC_CUR_CHROMA) |
- (1LL << CMDQ_SEC_VENC_REF_LUMA) |
- (1LL << CMDQ_SEC_VENC_REF_CHROMA) |
- (1LL << CMDQ_SEC_VENC_REC) |
- (1LL << CMDQ_SEC_VENC_SV_COMV) |
- (1LL << CMDQ_SEC_VENC_RD_COMV);
- const u64 port_sec_engine =
- (1LL << CMDQ_SEC_VENC_BSDMA) |
- (1LL << CMDQ_SEC_VENC_CUR_LUMA) |
- (1LL << CMDQ_SEC_VENC_CUR_CHROMA) |
- (1LL << CMDQ_SEC_VENC_REF_LUMA) |
- (1LL << CMDQ_SEC_VENC_REF_CHROMA) |
- (1LL << CMDQ_SEC_VENC_REC) |
- (1LL << CMDQ_SEC_VENC_SV_COMV) |
- (1LL << CMDQ_SEC_VENC_RD_COMV);
- pr_debug("[VCU] dapc_engine: 0x%llx, port_sec_engine: 0x%llx\n",
- dapc_engine, port_sec_engine);
- #if defined(CONFIG_MTK_CMDQ_MBOX_EXT)
- cmdq_sec_pkt_set_data(pkt_ptr, dapc_engine,
- port_sec_engine, CMDQ_SEC_KERNEL_CONFIG_GENERAL,
- CMDQ_METAEX_VENC);
- #endif
- }
- }
- #endif
- for (i = 0; i < cmds->cmd_cnt; i++) {
- vcu_set_gce_cmd(pkt_ptr, vcu, q, cmds->cmd[i],
- cmds->addr[i], cmds->data[i],
- cmds->mask[i], vcu->gce_gpr[core_id],
- cmds->dma_offset[i], cmds->dma_size[i]);
- }
- i = buff.cmdq_buff.flush_order % GCE_PENDING_CNT;
- memcpy(&vcu_ptr->gce_info[j].buff[i], &buff, sizeof(buff));
- pkt_ptr->err_cb.cb =
- (buff.cmdq_buff.secure == 0)?vcu_gce_timeout_callback:NULL;
- pkt_ptr->err_cb.data = (void *)&vcu_ptr->gce_info[j].buff[i];
- pr_info("[VCU][%d] %s: buff %p type %d cnt %d order %d hndl %llx %d %d\n",
- core_id, __func__, &vcu_ptr->gce_info[j].buff[i],
- buff.cmdq_buff.codec_type,
- cmds->cmd_cnt, buff.cmdq_buff.flush_order,
- buff.cmdq_buff.gce_handle, ret, j);
- /* flush cmd async */
- cmdq_pkt_flush_threaded(pkt_ptr,
- vcu_gce_flush_callback, (void *)&vcu_ptr->gce_info[j].buff[i]);
- atomic_inc(&vcu_ptr->gce_info[j].flush_pending);
- time_check_end(100, strlen(vcodec_param_string));
- return ret;
- }
- static int vcu_wait_gce_callback(struct mtk_vcu *vcu, unsigned long arg)
- {
- int ret, i, j;
- unsigned char *user_data_addr = NULL;
- struct gce_obj obj;
- user_data_addr = (unsigned char *)arg;
- ret = (long)copy_from_user(&obj, user_data_addr,
- (unsigned long)sizeof(struct gce_obj));
- if (ret != 0L) {
- pr_info("[VCU] %s(%d) copy_from_user failed!%d\n",
- __func__, __LINE__, ret);
- return -EINVAL;
- }
- i = (obj.codec_type == VCU_VDEC) ? VCU_VDEC : VCU_VENC;
- vcu_dbg_log("[VCU] %s: type %d handle %llx\n",
- __func__, obj.codec_type, obj.gce_handle);
- /* use wait_event_interruptible not freezable due to
- * slowmotion GCE case vcu_gce_cmd_flush will hold
- * mutex in user process which cannot be freezed
- */
- j = vcu_gce_get_inst_id(obj.gce_handle);
- if (j < 0)
- return -EINVAL;
- ret = wait_event_interruptible(vcu->gce_wq[i],
- atomic_read(&vcu->gce_info[j].flush_done) > 0);
- if (ret != 0) {
- pr_info("[VCU][%d][%d] wait event return %d @%s\n",
- vcu->vcuid, i, ret, __func__);
- return ret;
- }
- atomic_dec(&vcu->gce_info[j].flush_done);
- return ret;
- }
- int vcu_get_ctx_ipi_binding_lock(struct platform_device *pdev,
- struct mutex **mutex, unsigned long type)
- {
- struct mtk_vcu *vcu = platform_get_drvdata(pdev);
- *mutex = &vcu->ctx_ipi_binding[type];
- return 0;
- }
- int vcu_set_codec_ctx(struct platform_device *pdev,
- void *codec_ctx, struct vb2_buffer *src_vb,
- struct vb2_buffer *dst_vb, unsigned long type)
- {
- struct mtk_vcu *vcu = platform_get_drvdata(pdev);
- pr_debug("[VCU] type %lu vcu_set_codec_ctx %p src_vb %p dst_vb %p\n",
- type, codec_ctx, src_vb, dst_vb);
- vcu_dbg_log("[VCU] %s %p type %lu src_vb %p dst_vb %p\n",
- __func__, codec_ctx, type, src_vb, dst_vb);
- vcu->curr_ctx[type] = codec_ctx;
- vcu->curr_src_vb[type] = src_vb;
- vcu->curr_dst_vb[type] = dst_vb;
- return 0;
- }
- int vcu_clear_codec_ctx(struct platform_device *pdev,
- void *codec_ctx, unsigned long type)
- {
- struct mtk_vcu *vcu = platform_get_drvdata(pdev);
- vcu_dbg_log("[VCU] %s %p type %lu\n", __func__, codec_ctx, type);
- mutex_lock(&vcu->vcu_gce_mutex[type]);
- vcu_gce_clear_inst_id(codec_ctx);
- vcu->curr_ctx[type] = NULL;
- vcu->curr_src_vb[type] = NULL;
- vcu->curr_dst_vb[type] = NULL;
- mutex_unlock(&vcu->vcu_gce_mutex[type]);
- return 0;
- }
- unsigned int vcu_get_vdec_hw_capa(struct platform_device *pdev)
- {
- struct mtk_vcu *vcu = platform_get_drvdata(pdev);
- return vcu->run.dec_capability;
- }
- EXPORT_SYMBOL_GPL(vcu_get_vdec_hw_capa);
- unsigned int vcu_get_venc_hw_capa(struct platform_device *pdev)
- {
- struct mtk_vcu *vcu = platform_get_drvdata(pdev);
- return vcu->run.enc_capability;
- }
- EXPORT_SYMBOL_GPL(vcu_get_venc_hw_capa);
- void *vcu_mapping_dm_addr(struct platform_device *pdev,
- uintptr_t dtcm_dmem_addr)
- {
- struct mtk_vcu *vcu;
- uintptr_t d_vma, d_va_start;
- uintptr_t d_off, d_va;
- if (!IS_ERR_OR_NULL(pdev))
- vcu = platform_get_drvdata(pdev);
- else {
- dev_info(&pdev->dev, "[VCU] %s: Invalid pdev %p\n",
- __func__, pdev);
- return NULL;
- }
- d_vma = (uintptr_t)(dtcm_dmem_addr);
- d_va_start = (uintptr_t)VCU_DMEM0_VIRT(vcu);
- d_off = d_vma - VCU_DMEM0_VMA(vcu);
- if (dtcm_dmem_addr == 0UL || d_off > VCU_DMEM0_LEN(vcu)) {
- dev_info(&pdev->dev, "[VCU] %s: Invalid vma 0x%lx len %lx\n",
- __func__, dtcm_dmem_addr, VCU_DMEM0_LEN(vcu));
- return NULL;
- }
- d_va = d_va_start + d_off;
- dev_dbg(&pdev->dev, "[VCU] %s: 0x%lx -> 0x%lx\n",
- __func__, d_vma, d_va);
- return (void *)d_va;
- }
- EXPORT_SYMBOL_GPL(vcu_mapping_dm_addr);
- struct platform_device *vcu_get_plat_device(struct platform_device *pdev)
- {
- struct device *dev = &pdev->dev;
- struct device_node *vcu_node = NULL;
- struct platform_device *vcu_pdev = NULL;
- dev_dbg(&pdev->dev, "[VCU] %s\n", __func__);
- vcu_node = of_parse_phandle(dev->of_node, "mediatek,vcu", 0);
- if (vcu_node == NULL) {
- dev_err(dev, "[VCU] can't get vcu node\n");
- return NULL;
- }
- vcu_pdev = of_find_device_by_node(vcu_node);
- if (WARN_ON(vcu_pdev == NULL) == true) {
- dev_err(dev, "[VCU] vcu pdev failed\n");
- of_node_put(vcu_node);
- return NULL;
- }
- return vcu_pdev;
- }
- EXPORT_SYMBOL_GPL(vcu_get_plat_device);
- int vcu_load_firmware(struct platform_device *pdev)
- {
- if (pdev == NULL) {
- dev_err(&pdev->dev, "[VCU] VCU platform device is invalid\n");
- return -EINVAL;
- }
- return 0;
- }
- EXPORT_SYMBOL_GPL(vcu_load_firmware);
- int vcu_compare_version(struct platform_device *pdev,
- const char *expected_version)
- {
- struct mtk_vcu *vcu = platform_get_drvdata(pdev);
- int cur_major, cur_minor, cur_build, cur_rel, cur_ver_num;
- int major, minor, build, rel, ver_num;
- char *cur_version = vcu->run.fw_ver;
- cur_ver_num = sscanf(cur_version, "%d.%d.%d-rc%d",
- &cur_major, &cur_minor, &cur_build, &cur_rel);
- if (cur_ver_num < 3)
- return -1;
- ver_num = sscanf(expected_version, "%d.%d.%d-rc%d",
- &major, &minor, &build, &rel);
- if (ver_num < 3)
- return -1;
- if (cur_major < major)
- return -1;
- if (cur_major > major)
- return 1;
- if (cur_minor < minor)
- return -1;
- if (cur_minor > minor)
- return 1;
- if (cur_build < build)
- return -1;
- if (cur_build > build)
- return 1;
- if (cur_ver_num < ver_num)
- return -1;
- if (cur_ver_num > ver_num)
- return 1;
- if (ver_num > 3) {
- if (cur_rel < rel)
- return -1;
- if (cur_rel > rel)
- return 1;
- }
- return 0;
- }
- EXPORT_SYMBOL_GPL(vcu_compare_version);
- void vcu_get_file_lock(void)
- {
- mutex_lock(&vpud_file_mutex);
- }
- EXPORT_SYMBOL_GPL(vcu_get_file_lock);
- void vcu_put_file_lock(void)
- {
- mutex_unlock(&vpud_file_mutex);
- }
- EXPORT_SYMBOL_GPL(vcu_put_file_lock);
- int vcu_get_sig_lock(unsigned long *flags)
- {
- return spin_trylock_irqsave(&vcu_ptr->vpud_sig_lock, *flags);
- }
- EXPORT_SYMBOL_GPL(vcu_get_sig_lock);
- void vcu_put_sig_lock(unsigned long flags)
- {
- spin_unlock_irqrestore(&vcu_ptr->vpud_sig_lock, flags);
- }
- EXPORT_SYMBOL_GPL(vcu_put_sig_lock);
- int vcu_check_vpud_alive(void)
- {
- return (vcu_ptr->vpud_is_going_down > 0) ? 0:1;
- }
- EXPORT_SYMBOL_GPL(vcu_check_vpud_alive);
- void vcu_get_task(struct task_struct **task, struct files_struct **f,
- int reset)
- {
- vcu_dbg_log("mtk_vcu_get_task %p\n", vcud_task);
- if (reset == 1) {
- vcud_task = NULL;
- files = NULL;
- }
- *task = vcud_task;
- *f = files;
- }
- EXPORT_SYMBOL_GPL(vcu_get_task);
- static int vcu_ipi_handler(struct mtk_vcu *vcu, struct share_obj *rcv_obj)
- {
- struct vcu_ipi_desc *ipi_desc = vcu->ipi_desc;
- int non_ack = 0;
- int ret = -1;
- unsigned int i = 0;
- i = ipi_id_to_inst_id(rcv_obj->id);
- if (rcv_obj->id < (int)IPI_MAX &&
- ipi_desc[rcv_obj->id].handler != NULL) {
- non_ack = ipi_desc[rcv_obj->id].handler(rcv_obj->share_buf,
- rcv_obj->len,
- ipi_desc[rcv_obj->id].priv);
- if (rcv_obj->id > (int)IPI_VCU_INIT && non_ack == 0) {
- vcu->ipi_id_ack[rcv_obj->id] = true;
- wake_up(&vcu->ack_wq[i]);
- }
- ret = 0;
- } else
- dev_err(vcu->dev, "[VCU] No such ipi id = %d\n", rcv_obj->id);
- return ret;
- }
- static int vcu_ipi_init(struct mtk_vcu *vcu)
- {
- vcu->is_open = false;
- mutex_init(&vcu->vcu_mutex[VCU_VDEC]);
- mutex_init(&vcu->vcu_mutex[VCU_VENC]);
- mutex_init(&vcu->vcu_gce_mutex[VCU_VDEC]);
- mutex_init(&vcu->vcu_gce_mutex[VCU_VENC]);
- mutex_init(&vcu->ctx_ipi_binding[VCU_VDEC]);
- mutex_init(&vcu->ctx_ipi_binding[VCU_VENC]);
- mutex_init(&vcu->vcu_share);
- mutex_init(&vpud_file_mutex);
- return 0;
- }
- static int vcu_init_ipi_handler(void *data, unsigned int len, void *priv)
- {
- struct mtk_vcu *vcu = (struct mtk_vcu *)priv;
- struct vcu_run *run = (struct vcu_run *)data;
- int wait_cnt = 0;
- /* handle uninitialize message */
- if (vcu->run.signaled == 1u && run->signaled == 0u) {
- /* smi debug dump before wake up ack to worker
- * which will send error event to omx
- * to avoid omx release and disable larb
- * which may cause smi dump devapc
- */
- //smi_debug_bus_hang_detect(0, "VDEC");
- int i;
- /* wake up the threads in daemon
- * clear all pending ipi_msg
- * release worker waiting timeout
- */
- vcu->abort = true;
- for (i = 0; i < IPI_MAX; i++)
- vcu->ipi_id_ack[i] = true;
- /* wait for GCE done & let IPI ack power off */
- while (
- atomic_read(&vcu_ptr->gce_job_cnt[VCU_VDEC][0]) > 0 ||
- atomic_read(&vcu_ptr->gce_job_cnt[VCU_VDEC][1]) > 0 ||
- atomic_read(&vcu_ptr->gce_job_cnt[VCU_VENC][0]) > 0 ||
- atomic_read(&vcu_ptr->gce_job_cnt[VCU_VENC][1]) > 0) {
- wait_cnt++;
- if (wait_cnt > 5) {
- pr_info("[VCU] Vpud killed gce status %d %d\n",
- atomic_read(
- &vcu_ptr->gce_job_cnt[VCU_VDEC][0]),
- atomic_read(
- &vcu_ptr->gce_job_cnt[VCU_VENC][0]));
- break;
- }
- usleep_range(10000, 20000);
- }
- for (i = 0; i < 2; i++) {
- atomic_set(&vcu->ipi_got[i], 1);
- atomic_set(&vcu->ipi_done[i], 0);
- memset(&vcu->user_obj[i], 0,
- sizeof(struct share_obj));
- wake_up(&vcu->get_wq[i]);
- wake_up(&vcu->ack_wq[i]);
- }
- atomic_set(&vcu->vdec_log_got, 1);
- wake_up(&vcu->vdec_log_get_wq);
- vcud_task = NULL;
- files = NULL;
- dev_info(vcu->dev, "[VCU] vpud killing\n");
- return 0;
- }
- vcu->run.signaled = run->signaled;
- strncpy(vcu->run.fw_ver, run->fw_ver, VCU_FW_VER_LEN);
- vcu->run.dec_capability = run->dec_capability;
- vcu->run.enc_capability = run->enc_capability;
- dev_dbg(vcu->dev, "[VCU] fw ver: %s\n", vcu->run.fw_ver);
- dev_dbg(vcu->dev, "[VCU] dec cap: %x\n", vcu->run.dec_capability);
- dev_dbg(vcu->dev, "[VCU] enc cap: %x\n", vcu->run.enc_capability);
- return 0;
- }
- static int mtk_vcu_open(struct inode *inode, struct file *file)
- {
- int vcuid = 0;
- struct mtk_vcu_queue *vcu_queue;
- if (strcmp(current->comm, "camd") == 0)
- vcuid = 2;
- else if (strcmp(current->comm, "mdpd") == 0)
- vcuid = 1;
- else if (strcmp(current->comm, "vpud") == 0) {
- vcud_task = current;
- files = vcud_task->files;
- vcuid = 0;
- } else if (strcmp(current->comm, "vdec_srv") == 0 ||
- strcmp(current->comm, "venc_srv") == 0) {
- vcuid = 0;
- } else {
- pr_info("[VCU] thread name: %s\n", current->comm);
- }
- vcu_mtkdev[vcuid]->vcuid = vcuid;
- if (IS_ERR_OR_NULL(vcu_mtkdev[vcuid]->clt_vdec[0]))
- return -EINVAL;
- vcu_queue = mtk_vcu_mem_init(vcu_mtkdev[vcuid]->dev,
- vcu_mtkdev[vcuid]->clt_vdec[0]->chan->mbox->dev);
- if (vcu_queue == NULL)
- return -ENOMEM;
- vcu_queue->vcu = vcu_mtkdev[vcuid];
- file->private_data = vcu_queue;
- vcu_ptr->vpud_killed.count = 0;
- vcu_ptr->open_cnt++;
- vcu_ptr->abort = false;
- vcu_ptr->vpud_is_going_down = 0;
- pr_info("[VCU] %s name: %s pid %d open_cnt %d\n", __func__,
- current->comm, current->tgid, vcu_ptr->open_cnt);
- return 0;
- }
- static int mtk_vcu_release(struct inode *inode, struct file *file)
- {
- struct task_struct *task = NULL;
- struct files_struct *f = NULL;
- unsigned long flags;
- if (file->private_data)
- mtk_vcu_mem_release((struct mtk_vcu_queue *)file->private_data);
- pr_info("[VCU] %s name: %s pid %d open_cnt %d\n", __func__,
- current->comm, current->tgid, vcu_ptr->open_cnt);
- vcu_ptr->open_cnt--;
- if (vcu_ptr->open_cnt == 0) {
- /* reset vpud due to abnormal situations. */
- vcu_ptr->abort = true;
- vcu_get_file_lock();
- vcu_get_task(&task, &f, 1);
- vcu_put_file_lock();
- up(&vcu_ptr->vpud_killed); /* vdec worker */
- up(&vcu_ptr->vpud_killed); /* venc worker */
- /* reset vpud_is_going_down only on abnormal situations */
- spin_lock_irqsave(&vcu_ptr->vpud_sig_lock, flags);
- vcu_ptr->vpud_is_going_down = 0;
- spin_unlock_irqrestore(&vcu_ptr->vpud_sig_lock, flags);
- }
- return 0;
- }
- static void vcu_free_d_ext_mem(struct mtk_vcu *vcu)
- {
- mutex_lock(&vcu->vcu_share);
- mutex_lock(&vcu->vcu_mutex[VCU_VDEC]);
- mutex_lock(&vcu->vcu_mutex[VCU_VENC]);
- kfree(VCU_DMEM0_VIRT(vcu));
- VCU_DMEM0_VIRT(vcu) = NULL;
- mutex_unlock(&vcu->vcu_mutex[VCU_VENC]);
- mutex_unlock(&vcu->vcu_mutex[VCU_VDEC]);
- mutex_unlock(&vcu->vcu_share);
- }
- static int vcu_alloc_d_ext_mem(struct mtk_vcu *vcu, unsigned long len)
- {
- mutex_lock(&vcu->vcu_share);
- mutex_lock(&vcu->vcu_mutex[VCU_VDEC]);
- mutex_lock(&vcu->vcu_mutex[VCU_VENC]);
- VCU_DMEM0_VIRT(vcu) = kmalloc(len, GFP_KERNEL);
- VCU_DMEM0_PHY(vcu) = virt_to_phys(VCU_DMEM0_VIRT(vcu));
- VCU_DMEM0_LEN(vcu) = len;
- mutex_unlock(&vcu->vcu_mutex[VCU_VENC]);
- mutex_unlock(&vcu->vcu_mutex[VCU_VDEC]);
- mutex_unlock(&vcu->vcu_share);
- if (!VCU_DMEM0_VIRT(vcu))
- return -1;
- dev_dbg(vcu->dev,
- "[VCU] Data extend memory (len:%lu) phy=0x%llx virt=0x%p iova=0x%llx\n",
- VCU_DMEM0_LEN(vcu),
- (unsigned long long)VCU_DMEM0_PHY(vcu),
- VCU_DMEM0_VIRT(vcu),
- (unsigned long long)VCU_DMEM0_IOVA(vcu));
- return 0;
- }
- static void mtk_vcu_page_vm_close(struct vm_area_struct *vma)
- {
- struct vcu_pa_pages *vcu_page = (struct vcu_pa_pages *)vma->vm_private_data;
- if (atomic_read(&vcu_page->ref_cnt) > 0)
- atomic_dec(&vcu_page->ref_cnt);
- else
- pr_info("[VCU][Error] %s ummap fail\n", __func__);
- vcu_dbg_log("[VCU] %s vma->start 0x%lx, end 0x%lx, pgoff 0x%lx\n",
- __func__, vma->vm_start, vma->vm_end, vma->vm_pgoff);
- }
- const struct vm_operations_struct mtk_vcu_page_vm_ops = {
- .close = mtk_vcu_page_vm_close,
- };
- static void mtk_vcu_buf_vm_close(struct vm_area_struct *vma)
- {
- void *mem_priv = (void *)vma->vm_private_data;
- struct file *file = vma->vm_file;
- struct mtk_vcu_queue *vcu_queue =
- (struct mtk_vcu_queue *)file->private_data;
- mtk_vcu_buffer_ref_dec(vcu_queue, mem_priv);
- vcu_dbg_log("[VCU] %s vma->start 0x%lx, end 0x%lx, pgoff 0x%lx\n",
- __func__, vma->vm_start, vma->vm_end, vma->vm_pgoff);
- }
- const struct vm_operations_struct mtk_vcu_buf_vm_ops = {
- .close = mtk_vcu_buf_vm_close,
- };
- static int mtk_vcu_mmap(struct file *file, struct vm_area_struct *vma)
- {
- unsigned long length = vma->vm_end - vma->vm_start;
- unsigned long pa_start = vma->vm_pgoff << PAGE_SHIFT;
- unsigned long pa_start_base = pa_start;
- unsigned long pa_end = pa_start + length;
- #ifdef CONFIG_MTK_IOMMU_V2
- unsigned long start = vma->vm_start;
- unsigned long pos = 0;
- #endif
- struct mtk_vcu *vcu_dev;
- struct mtk_vcu_queue *vcu_queue =
- (struct mtk_vcu_queue *)file->private_data;
- struct mem_obj mem_buff_data;
- struct vb2_buffer *src_vb, *dst_vb;
- void *ret = NULL;
- vcu_dev = (struct mtk_vcu *)vcu_queue->vcu;
- vcu_dbg_log("[VCU] %s vma->start 0x%lx, end 0x%lx, pgoff 0x%lx\n",
- __func__, vma->vm_start, vma->vm_end, vma->vm_pgoff);
- // First handle map pa case, because maybe pa will smaller than
- // MAP_PA_BASE_1GB in 32bit project
- if (vcu_queue->map_buf_pa >= MAP_SHMEM_PA_BASE) {
- vcu_queue->map_buf_pa = 0;
- ret = vcu_check_gce_pa_base(vcu_queue, pa_start, length);
- if (ret != NULL) {
- atomic_inc(&((struct vcu_pa_pages *)ret)->ref_cnt);
- vma->vm_ops = &mtk_vcu_page_vm_ops;
- vma->vm_private_data = ret;
- vma->vm_pgoff = pa_start >> PAGE_SHIFT;
- vma->vm_page_prot =
- pgprot_writecombine(vma->vm_page_prot);
- goto valid_map;
- }
- pr_info("[VCU] map pa fail with pa_start=0x%lx\n",
- pa_start);
- return -EINVAL;
- }
- /*only vcud need this case*/
- if (pa_start < MAP_PA_BASE_1GB) {
- if (vcu_check_reg_base(vcu_dev, pa_start, length) == 0) {
- vma->vm_pgoff = pa_start >> PAGE_SHIFT;
- goto reg_valid_map;
- }
- }
- if (pa_start >= MAP_SHMEM_ALLOC_BASE && pa_end <= MAP_SHMEM_ALLOC_END) {
- vma->vm_pgoff =
- (unsigned long)(VCU_DMEM0_PHY(vcu_dev) >> PAGE_SHIFT);
- goto valid_map;
- }
- if (pa_start >= MAP_SHMEM_COMMIT_BASE &&
- pa_end <= MAP_SHMEM_COMMIT_END) {
- VCU_DMEM0_VMA(vcu_dev) = vma->vm_start;
- vma->vm_pgoff =
- (unsigned long)(VCU_DMEM0_PHY(vcu_dev) >> PAGE_SHIFT);
- goto valid_map;
- }
- if (pa_start_base >= MAP_SHMEM_MM_BASE &&
- pa_start_base < MAP_SHMEM_PA_BASE) {
- if (pa_start_base >= MAP_SHMEM_MM_CACHEABLE_BASE)
- pa_start -= MAP_SHMEM_MM_CACHEABLE_BASE;
- else
- pa_start -= MAP_SHMEM_MM_BASE;
- mem_buff_data.iova = (vcu_ptr->iommu_padding) ?
- (pa_start | 0x100000000UL) : pa_start;
- mem_buff_data.len = length;
- src_vb = NULL;
- dst_vb = NULL;
- if (strcmp(current->comm, "vdec_srv") == 0) {
- src_vb = vcu_dev->curr_src_vb[VCU_VDEC];
- dst_vb = vcu_dev->curr_dst_vb[VCU_VDEC];
- } else if (strcmp(current->comm, "venc_srv") == 0) {
- src_vb = vcu_dev->curr_src_vb[VCU_VENC];
- dst_vb = vcu_dev->curr_dst_vb[VCU_VENC];
- }
- ret = mtk_vcu_set_buffer(vcu_queue, &mem_buff_data,
- src_vb, dst_vb);
- if (!IS_ERR_OR_NULL(ret)) {
- vma->vm_ops = &mtk_vcu_buf_vm_ops;
- vma->vm_private_data = ret;
- vma->vm_file = file;
- }
- #ifdef CONFIG_MTK_IOMMU_V2
- while (length > 0) {
- vma->vm_pgoff = iommu_iova_to_phys(vcu_dev->io_domain,
- (vcu_ptr->iommu_padding) ?
- ((pa_start + pos) | 0x100000000UL) :
- (pa_start + pos));
- if (vma->vm_pgoff == 0) {
- dev_info(vcu_dev->dev, "[VCU] iommu_iova_to_phys fail\n");
- return -EINVAL;
- }
- vma->vm_pgoff >>= PAGE_SHIFT;
- if (pa_start_base < MAP_SHMEM_MM_CACHEABLE_BASE) {
- vma->vm_page_prot =
- pgprot_writecombine(vma->vm_page_prot);
- }
- if (remap_pfn_range(vma, start, vma->vm_pgoff,
- PAGE_SIZE, vma->vm_page_prot) == true)
- return -EAGAIN;
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
- if (length > PAGE_SIZE)
- length -= PAGE_SIZE;
- else
- length = 0;
- }
- return 0;
- #endif
- }
- dev_info(vcu_dev->dev, "[VCU] Invalid argument\n");
- return -EINVAL;
- reg_valid_map:
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- valid_map:
- dev_dbg(vcu_dev->dev, "[VCU] Mapping pgoff 0x%lx\n", vma->vm_pgoff);
- if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
- vma->vm_end - vma->vm_start,
- vma->vm_page_prot) != 0)
- return -EAGAIN;
- return 0;
- }
- static long mtk_vcu_unlocked_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
- {
- long ret = -1;
- void *mem_priv;
- unsigned char *user_data_addr = NULL;
- struct mtk_vcu *vcu_dev;
- struct device *dev;
- struct share_obj share_buff_data;
- struct mem_obj mem_buff_data;
- struct mtk_vcu_queue *vcu_queue =
- (struct mtk_vcu_queue *)file->private_data;
- vcu_dev = (struct mtk_vcu *)vcu_queue->vcu;
- dev = vcu_dev->dev;
- switch (cmd) {
- case VCU_SET_OBJECT:
- user_data_addr = (unsigned char *)arg;
- ret = (long)copy_from_user(&share_buff_data, user_data_addr,
- (unsigned long)sizeof(struct share_obj));
- if (ret != 0L || share_buff_data.id >= (int)IPI_MAX ||
- share_buff_data.id < (int)IPI_VCU_INIT) {
- pr_info("[VCU] %s(%d) Copy data from user failed!\n",
- __func__, __LINE__);
- return -EINVAL;
- }
- ret = vcu_ipi_handler(vcu_dev, &share_buff_data);
- ret = (long)copy_to_user(user_data_addr, &share_buff_data,
- (unsigned long)sizeof(struct share_obj));
- if (ret != 0L) {
- pr_info("[VCU] %s(%d) Copy data to user failed!\n",
- __func__, __LINE__);
- return -EINVAL;
- }
- break;
- case VCU_GET_OBJECT:
- ret = vcu_ipi_get(vcu_dev, arg);
- break;
- case VCU_GET_LOG_OBJECT:
- ret = vcu_log_get(vcu_dev, arg);
- break;
- case VCU_MVA_ALLOCATION:
- case VCU_PA_ALLOCATION:
- user_data_addr = (unsigned char *)arg;
- ret = (long)copy_from_user(&mem_buff_data, user_data_addr,
- (unsigned long)sizeof(struct mem_obj));
- if (ret != 0L) {
- pr_info("[VCU] %s(%d) Copy data from user failed!\n",
- __func__, __LINE__);
- return -EINVAL;
- }
- if (cmd == VCU_MVA_ALLOCATION) {
- mem_priv =
- mtk_vcu_get_buffer(vcu_queue, &mem_buff_data);
- } else {
- mem_priv =
- mtk_vcu_get_page(vcu_queue, &mem_buff_data);
- }
- if (IS_ERR_OR_NULL(mem_priv) == true) {
- mem_buff_data.va = (unsigned long)-1;
- mem_buff_data.pa = (unsigned long)-1;
- mem_buff_data.iova = (unsigned long)-1;
- ret = (long)copy_to_user(user_data_addr,
- &mem_buff_data,
- (unsigned long)sizeof(struct mem_obj));
- pr_info("[VCU] ALLOCATION %d failed!\n", cmd == VCU_MVA_ALLOCATION);
- return PTR_ERR(mem_priv);
- }
- vcu_dbg_log("[VCU] ALLOCATION %d va %llx, pa %llx, iova %llx\n",
- cmd == VCU_MVA_ALLOCATION, mem_buff_data.va,
- mem_buff_data.pa, mem_buff_data.iova);
- ret = (long)copy_to_user(user_data_addr, &mem_buff_data,
- (unsigned long)sizeof(struct mem_obj));
- if (ret != 0L) {
- pr_info("[VCU] %s(%d) Copy data to user failed!\n",
- __func__, __LINE__);
- return -EINVAL;
- }
- /* store map pa buffer type flag which will use in mmap*/
- if (cmd == VCU_PA_ALLOCATION)
- vcu_queue->map_buf_pa = mem_buff_data.pa + MAP_SHMEM_PA_BASE;
- ret = 0;
- break;
- case VCU_MVA_FREE:
- case VCU_PA_FREE:
- user_data_addr = (unsigned char *)arg;
- ret = (long)copy_from_user(&mem_buff_data, user_data_addr,
- (unsigned long)sizeof(struct mem_obj));
- if ((ret != 0L) ||
- (mem_buff_data.iova == 0UL &&
- mem_buff_data.va == 0UL)) {
- pr_info("[VCU] %s(%d) Free buf failed!\n",
- __func__, __LINE__);
- return -EINVAL;
- }
- if (cmd == VCU_MVA_FREE) {
- if (vcu_ptr->iommu_padding)
- mem_buff_data.iova |= 0x100000000UL;
- ret = mtk_vcu_free_buffer(vcu_queue, &mem_buff_data);
- } else {
- ret = mtk_vcu_free_page(vcu_queue, &mem_buff_data);
- }
- if (ret != 0L) {
- pr_info("[VCU] VCU_FREE failed %d va %llx, pa %llx, iova %llx\n",
- cmd == VCU_MVA_FREE, mem_buff_data.va,
- mem_buff_data.pa, mem_buff_data.iova);
- return -EINVAL;
- }
- vcu_dbg_log("[VCU] FREE %d va %llx, pa %llx, iova %llx\n",
- cmd == VCU_MVA_FREE, mem_buff_data.va,
- mem_buff_data.pa, mem_buff_data.iova);
- mem_buff_data.va = 0;
- mem_buff_data.iova = 0;
- mem_buff_data.pa = 0;
- ret = (long)copy_to_user(user_data_addr, &mem_buff_data,
- (unsigned long)sizeof(struct mem_obj));
- if (ret != 0L) {
- pr_info("[VCU] %s(%d) Copy data to user failed!\n",
- __func__, __LINE__);
- return -EINVAL;
- }
- ret = 0;
- break;
- case VCU_CACHE_FLUSH_ALL:
- dev_dbg(dev, "[VCU] Flush cache in kernel\n");
- vcu_buffer_flush_all(dev, vcu_queue);
- ret = 0;
- break;
- case VCU_CACHE_FLUSH_BUFF:
- case VCU_CACHE_INVALIDATE_BUFF:
- user_data_addr = (unsigned char *)arg;
- ret = (long)copy_from_user(&mem_buff_data, user_data_addr,
- (unsigned long)sizeof(struct mem_obj));
- if (ret != 0L) {
- pr_info("[VCU] %s(%d) Copy data from user failed!\n",
- __func__, __LINE__);
- return -EINVAL;
- }
- if (vcu_ptr->iommu_padding)
- mem_buff_data.iova |= 0x100000000UL;
- ret = vcu_buffer_cache_sync(dev, vcu_queue,
- (dma_addr_t)mem_buff_data.iova,
- (size_t)mem_buff_data.len,
- (cmd == VCU_CACHE_FLUSH_BUFF) ?
- DMA_TO_DEVICE : DMA_FROM_DEVICE);
- if (ret < 0)
- return -EINVAL;
- dev_dbg(dev, "[VCU] Cache flush buffer pa = %llx, size = %d\n",
- mem_buff_data.iova, (unsigned int)mem_buff_data.len);
- ret = (long)copy_to_user(user_data_addr, &mem_buff_data,
- (unsigned long)sizeof(struct mem_obj));
- if (ret != 0L) {
- pr_info("[VCU] %s(%d) Copy data to user failed!\n",
- __func__, __LINE__);
- return -EINVAL;
- }
- ret = 0;
- break;
- case VCU_GCE_SET_CMD_FLUSH:
- ret = vcu_gce_cmd_flush(vcu_dev, vcu_queue, arg);
- break;
- case VCU_GCE_WAIT_CALLBACK:
- ret = vcu_wait_gce_callback(vcu_dev, arg);
- break;
- default:
- dev_err(dev, "[VCU] Unknown cmd\n");
- break;
- }
- return ret;
- }
- #if IS_ENABLED(CONFIG_COMPAT)
- static int compat_get_vpud_allocation_data(
- struct compat_mem_obj __user *data32,
- struct mem_obj __user *data)
- {
- compat_ulong_t l;
- compat_u64 u;
- unsigned int err = 0;
- err = get_user(l, &data32->iova);
- err |= put_user(l, &data->iova);
- err |= get_user(l, &data32->len);
- err |= put_user(l, &data->len);
- err |= get_user(u, &data32->pa);
- err |= put_user(u, &data->pa);
- err |= get_user(u, &data32->va);
- err |= put_user(u, &data->va);
- return (int)err;
- }
- static int compat_put_vpud_allocation_data(
- struct compat_mem_obj __user *data32,
- struct mem_obj __user *data)
- {
- compat_ulong_t l;
- compat_u64 u;
- unsigned int err = 0;
- err = get_user(l, &data->iova);
- err |= put_user(l, &data32->iova);
- err |= get_user(l, &data->len);
- err |= put_user(l, &data32->len);
- err |= get_user(u, &data->pa);
- err |= put_user(u, &data32->pa);
- err |= get_user(u, &data->va);
- err |= put_user(u, &data32->va);
- return (int)err;
- }
- static long mtk_vcu_unlocked_compat_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
- {
- int err = 0;
- long ret = -1;
- struct share_obj __user *share_data32;
- struct compat_mem_obj __user *data32;
- struct mem_obj __user *data;
- switch (cmd) {
- case COMPAT_VCU_SET_OBJECT:
- case VCU_GET_OBJECT:
- case VCU_GET_LOG_OBJECT:
- case VCU_GCE_SET_CMD_FLUSH:
- case VCU_GCE_WAIT_CALLBACK:
- share_data32 = compat_ptr((uint32_t)arg);
- ret = file->f_op->unlocked_ioctl(file,
- cmd, (unsigned long)share_data32);
- break;
- case COMPAT_VCU_MVA_ALLOCATION:
- case COMPAT_VCU_PA_ALLOCATION:
- data32 = compat_ptr((uint32_t)arg);
- data = compat_alloc_user_space(sizeof(struct mem_obj));
- if (data == NULL)
- return -EFAULT;
- err = compat_get_vpud_allocation_data(data32, data);
- if (err != 0)
- return err;
- if (cmd == COMPAT_VCU_MVA_ALLOCATION)
- ret = file->f_op->unlocked_ioctl(file,
- (uint32_t)VCU_MVA_ALLOCATION,
- (unsigned long)data);
- else
- ret = file->f_op->unlocked_ioctl(file,
- (uint32_t)VCU_PA_ALLOCATION,
- (unsigned long)data);
- err = compat_put_vpud_allocation_data(data32, data);
- if (err != 0)
- return err;
- break;
- case COMPAT_VCU_MVA_FREE:
- case COMPAT_VCU_PA_FREE:
- data32 = compat_ptr((uint32_t)arg);
- data = compat_alloc_user_space(sizeof(struct mem_obj));
- if (data == NULL)
- return -EFAULT;
- err = compat_get_vpud_allocation_data(data32, data);
- if (err != 0)
- return err;
- if (cmd == COMPAT_VCU_MVA_FREE)
- ret = file->f_op->unlocked_ioctl(file,
- (uint32_t)VCU_MVA_FREE, (unsigned long)data);
- else
- ret = file->f_op->unlocked_ioctl(file,
- (uint32_t)VCU_PA_FREE, (unsigned long)data);
- err = compat_put_vpud_allocation_data(data32, data);
- if (err != 0)
- return err;
- break;
- case COMPAT_VCU_CACHE_FLUSH_ALL:
- ret = file->f_op->unlocked_ioctl(file,
- (uint32_t)VCU_CACHE_FLUSH_ALL, 0);
- break;
- case COMPAT_VCU_CACHE_FLUSH_BUFF:
- case COMPAT_VCU_CACHE_INVALIDATE_BUFF:
- data32 = compat_ptr((uint32_t)arg);
- data = compat_alloc_user_space(sizeof(struct mem_obj));
- if (data == NULL)
- return -EFAULT;
- err = compat_get_vpud_allocation_data(data32, data);
- if (err != 0)
- return err;
- if (cmd == COMPAT_VCU_CACHE_FLUSH_BUFF) {
- ret = file->f_op->unlocked_ioctl(file,
- (uint32_t)VCU_CACHE_FLUSH_BUFF,
- (unsigned long)data);
- } else {
- ret = file->f_op->unlocked_ioctl(file,
- (uint32_t)VCU_CACHE_INVALIDATE_BUFF,
- (unsigned long)data);
- }
- err = compat_put_vpud_allocation_data(data32, data);
- if (err != 0)
- return err;
- break;
- default:
- pr_err("[VCU] Invalid cmd_number 0x%x.\n", cmd);
- break;
- }
- return ret;
- }
- #endif
- static int mtk_vcu_write(const char *val, const struct kernel_param *kp)
- {
- long ret = -1;
- if (vcu_ptr != NULL &&
- vcu_ptr->vdec_log_info != NULL &&
- val != NULL) {
- ret = param_set_charp(val, kp);
- if (ret != 0)
- return -EINVAL;
- memcpy(vcu_ptr->vdec_log_info->log_info,
- val, strnlen(val, LOG_INFO_SIZE - 1) + 1);
- } else
- return -EFAULT;
- vcu_ptr->vdec_log_info->log_info[LOG_INFO_SIZE - 1] = '\0';
- // check if need to enable VCU debug log
- if (strstr(vcu_ptr->vdec_log_info->log_info, "vcu_log 1")) {
- vcu_ptr->enable_vcu_dbg_log = 1;
- return 0;
- } else if (strstr(vcu_ptr->vdec_log_info->log_info, "vcu_log 0")) {
- vcu_ptr->enable_vcu_dbg_log = 0;
- return 0;
- }
- pr_info("[log wakeup VPUD] log_info %p vcu_ptr %p val %p: %s %lu\n",
- (char *)vcu_ptr->vdec_log_info->log_info,
- vcu_ptr, val, val,
- (unsigned long)strnlen(val, LOG_INFO_SIZE - 1) + 1);
- atomic_set(&vcu_ptr->vdec_log_got, 1);
- wake_up(&vcu_ptr->vdec_log_get_wq);
- return 0;
- }
- static struct kernel_param_ops log_param_ops = {
- .set = mtk_vcu_write,
- .get = param_get_charp,
- };
- module_param_cb(test_info, &log_param_ops, &vcodec_param_string, 0644);
- static const struct file_operations vcu_fops = {
- .owner = THIS_MODULE,
- .unlocked_ioctl = mtk_vcu_unlocked_ioctl,
- .open = mtk_vcu_open,
- .release = mtk_vcu_release,
- .mmap = mtk_vcu_mmap,
- #if IS_ENABLED(CONFIG_COMPAT)
- .compat_ioctl = mtk_vcu_unlocked_compat_ioctl,
- #endif
- };
- /**
- * Suspsend callbacks after user space processes are frozen
- * Since user space processes are frozen, there is no need and cannot hold same
- * mutex that protects lock owner while checking status.
- * If video codec hardware is still active now, must not to enter suspend.
- **/
- static int mtk_vcu_suspend(struct device *pDev)
- {
- if (atomic_read(&vcu_ptr->ipi_done[VCU_VDEC]) == 0 ||
- atomic_read(&vcu_ptr->ipi_done[VCU_VENC]) == 0 ||
- atomic_read(&vcu_ptr->gce_job_cnt[VCU_VDEC][0]) > 0 ||
- atomic_read(&vcu_ptr->gce_job_cnt[VCU_VDEC][1]) > 0 ||
- atomic_read(&vcu_ptr->gce_job_cnt[VCU_VENC][0]) > 0 ||
- atomic_read(&vcu_ptr->gce_job_cnt[VCU_VENC][1]) > 0) {
- pr_info("[VCU] %s fail due to videocodec activity\n", __func__);
- return -EBUSY;
- }
- pr_info("[VCU] %s done\n", __func__);
- return 0;
- }
- static int mtk_vcu_resume(struct device *pDev)
- {
- pr_info("[VCU] %s done\n", __func__);
- return 0;
- }
- /**
- * Suspend notifiers before user space processes are frozen.
- * User space driver can still complete decoding/encoding of current frame.
- * Change state to is_entering_suspend to stop send ipi_msg but allow current
- * wait ipi_msg to be done.
- * Since there is no critical section proection, it is possible for a new task
- * to start after changing to is_entering_suspend state. This case will be
- * handled by suspend callback mtk_vcu_suspend.
- **/
- static int mtk_vcu_suspend_notifier(struct notifier_block *nb,
- unsigned long action, void *data)
- {
- int wait_cnt = 0;
- pr_info("[VCU] %s ok action = %ld\n", __func__, action);
- switch (action) {
- case PM_SUSPEND_PREPARE:
- vcu_ptr->is_entering_suspend = 1;
- while (atomic_read(&vcu_ptr->ipi_done[VCU_VDEC]) == 0 ||
- atomic_read(&vcu_ptr->ipi_done[VCU_VENC]) == 0 ||
- atomic_read(&vcu_ptr->gce_job_cnt[VCU_VDEC][0]) > 0 ||
- atomic_read(&vcu_ptr->gce_job_cnt[VCU_VDEC][1]) > 0 ||
- atomic_read(&vcu_ptr->gce_job_cnt[VCU_VENC][0]) > 0 ||
- atomic_read(&vcu_ptr->gce_job_cnt[VCU_VENC][1]) > 0) {
- wait_cnt++;
- if (wait_cnt > 5) {
- pr_info("vcodec_pm_suspend waiting %d %d %d %d %d %d\n",
- atomic_read(&vcu_ptr->ipi_done[VCU_VDEC]),
- atomic_read(&vcu_ptr->ipi_done[VCU_VENC]),
- atomic_read(
- &vcu_ptr->gce_job_cnt[VCU_VDEC][0]),
- atomic_read(
- &vcu_ptr->gce_job_cnt[VCU_VDEC][1]),
- atomic_read(
- &vcu_ptr->gce_job_cnt[VCU_VENC][0]),
- atomic_read(
- &vcu_ptr->gce_job_cnt[VCU_VENC][1]));
- /* Current task is still not finished, don't
- * care, will check again in real suspend
- */
- return NOTIFY_DONE;
- }
- usleep_range(10000, 20000);
- }
- return NOTIFY_OK;
- case PM_POST_SUSPEND:
- vcu_ptr->is_entering_suspend = 0;
- return NOTIFY_OK;
- default:
- return NOTIFY_DONE;
- }
- return NOTIFY_DONE;
- }
- static const char stat_nam[] = "OOXX";
- static void probe_death_signal(void *ignore, int sig, struct siginfo *info,
- struct task_struct *task, int _group, int result)
- {
- unsigned long flags;
- if (strstr(task->comm, "vpud") && sig == SIGKILL) {
- pr_info("[VPUD_PROBE_DEATH][signal][%d:%s]send death sig %d to[%d:%s]\n",
- current->pid, current->comm,
- sig, task->pid, task->comm);
- spin_lock_irqsave(&vcu_ptr->vpud_sig_lock, flags);
- vcu_ptr->vpud_is_going_down = 1;
- spin_unlock_irqrestore(&vcu_ptr->vpud_sig_lock, flags);
- }
- }
- static int mtk_vcu_probe(struct platform_device *pdev)
- {
- struct mtk_vcu *vcu;
- struct device *dev;
- struct resource *res;
- int i, ret = 0;
- unsigned int vcuid;
- dev_dbg(&pdev->dev, "[VCU] initialization\n");
- dev = &pdev->dev;
- vcu = devm_kzalloc(dev, sizeof(*vcu), GFP_KERNEL);
- if (vcu == NULL)
- return -ENOMEM;
- vcu_ptr = vcu;
- ret = of_property_read_u32(dev->of_node, "mediatek,vcuid", &vcuid);
- if (ret != 0) {
- dev_err(dev, "[VCU] failed to find mediatek,vcuid\n");
- return ret;
- }
- vcu_mtkdev[vcuid] = vcu;
- #ifdef CONFIG_MTK_IOMMU_V2
- vcu_mtkdev[vcuid]->io_domain = iommu_get_domain_for_dev(dev);
- if (vcu_mtkdev[vcuid]->io_domain == NULL) {
- dev_err(dev,
- "[VCU] vcuid: %d get io_domain fail !!\n", vcuid);
- return -EPROBE_DEFER;
- }
- dev_dbg(dev, "vcu io_domain: %p,vcuid:%d\n",
- vcu_mtkdev[vcuid]->io_domain,
- vcuid);
- ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
- if (ret) {
- ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
- if (ret) {
- dev_info(&pdev->dev, "64-bit DMA enable failed\n");
- return ret;
- }
- vcu->iommu_padding = 0;
- } else
- vcu->iommu_padding = 1;
- #endif
- if (vcuid == 2)
- vcu_mtkdev[vcuid]->path = CAM_PATH;
- else if (vcuid == 1)
- vcu_mtkdev[vcuid]->path = MDP_PATH;
- else if (vcuid == 0) {
- vcu_mtkdev[vcuid]->vdec_log_info = devm_kzalloc(dev,
- sizeof(struct log_test_nofuse), GFP_KERNEL);
- pr_info("[VCU] vdec_log_info %p %d vcuid %d vcu_ptr %p\n",
- vcu_mtkdev[vcuid]->vdec_log_info,
- (int)sizeof(struct log_test_nofuse),
- (int)vcuid, vcu_ptr);
- vcu_mtkdev[vcuid]->path = VCU_PATH;
- } else
- return -ENXIO;
- ret = of_property_read_string(dev->of_node, "mediatek,vcuname",
- &vcu_mtkdev[vcuid]->vcuname);
- if (ret != 0) {
- dev_err(dev, "[VCU] failed to find mediatek,vcuname\n");
- return ret;
- }
- vcu->dev = &pdev->dev;
- platform_set_drvdata(pdev, vcu_mtkdev[vcuid]);
- if (vcuid == 0) {
- for (i = 0; i < (int)VCU_MAP_HW_REG_NUM; i++) {
- res = platform_get_resource(pdev, IORESOURCE_MEM, i);
- if (res == NULL) {
- break;
- }
- vcu->map_base[i].base = res->start;
- vcu->map_base[i].len = resource_size(res);
- dev_dbg(dev, "[VCU] base[%d]: 0x%lx 0x%lx",
- i, vcu->map_base[i].base,
- vcu->map_base[i].len);
- }
- }
- dev_dbg(dev, "[VCU] vcu ipi init\n");
- ret = vcu_ipi_init(vcu);
- if (ret != 0) {
- dev_err(dev, "[VCU] Failed to init ipi\n");
- goto err_ipi_init;
- }
- /* register vcu initialization IPI */
- ret = vcu_ipi_register(pdev, IPI_VCU_INIT, vcu_init_ipi_handler,
- "vcu_init", vcu);
- if (ret != 0) {
- dev_err(dev, "Failed to register IPI_VCU_INIT\n");
- goto vcu_mutex_destroy;
- }
- init_waitqueue_head(&vcu->ack_wq[VCU_VDEC]);
- init_waitqueue_head(&vcu->ack_wq[VCU_VENC]);
- init_waitqueue_head(&vcu->get_wq[VCU_VDEC]);
- init_waitqueue_head(&vcu->get_wq[VCU_VENC]);
- init_waitqueue_head(&vcu->gce_wq[VCU_VDEC]);
- init_waitqueue_head(&vcu->gce_wq[VCU_VENC]);
- init_waitqueue_head(&vcu->vdec_log_get_wq);
- atomic_set(&vcu->ipi_got[VCU_VDEC], 0);
- atomic_set(&vcu->ipi_got[VCU_VENC], 0);
- atomic_set(&vcu->ipi_done[VCU_VDEC], 1);
- atomic_set(&vcu->ipi_done[VCU_VENC], 1);
- atomic_set(&vcu->vdec_log_got, 0);
- for (i = 0; i < (int)VCODEC_INST_MAX; i++) {
- atomic_set(&vcu->gce_info[i].flush_done, 0);
- atomic_set(&vcu->gce_info[i].flush_pending, 0);
- vcu->gce_info[i].user_hdl = 0;
- vcu->gce_info[i].v4l2_ctx = NULL;
- }
- atomic_set(&vcu->gce_job_cnt[VCU_VDEC][0], 0);
- atomic_set(&vcu->gce_job_cnt[VCU_VDEC][1], 0);
- atomic_set(&vcu->gce_job_cnt[VCU_VENC][0], 0);
- atomic_set(&vcu->gce_job_cnt[VCU_VENC][1], 0);
- /* init character device */
- ret = alloc_chrdev_region(&vcu_mtkdev[vcuid]->vcu_devno, 0, 1,
- vcu_mtkdev[vcuid]->vcuname);
- if (ret < 0) {
- dev_err(dev,
- "[VCU] alloc_chrdev_region failed (%d)\n", ret);
- goto err_alloc;
- }
- vcu_mtkdev[vcuid]->vcu_cdev = cdev_alloc();
- vcu_mtkdev[vcuid]->vcu_cdev->owner = THIS_MODULE;
- vcu_mtkdev[vcuid]->vcu_cdev->ops = &vcu_fops;
- ret = cdev_add(vcu_mtkdev[vcuid]->vcu_cdev,
- vcu_mtkdev[vcuid]->vcu_devno, 1);
- if (ret < 0) {
- dev_err(dev, "[VCU] class create fail (ret=%d)", ret);
- goto err_add;
- }
- vcu_mtkdev[vcuid]->vcu_class = class_create(THIS_MODULE,
- vcu_mtkdev[vcuid]->vcuname);
- if (IS_ERR_OR_NULL(vcu_mtkdev[vcuid]->vcu_class) == true) {
- ret = (int)PTR_ERR(vcu_mtkdev[vcuid]->vcu_class);
- dev_err(dev, "[VCU] class create fail (ret=%d)", ret);
- goto err_add;
- }
- vcu_mtkdev[vcuid]->vcu_device =
- device_create(vcu_mtkdev[vcuid]->vcu_class,
- NULL,
- vcu_mtkdev[vcuid]->vcu_devno,
- NULL, vcu_mtkdev[vcuid]->vcuname);
- if (IS_ERR_OR_NULL(vcu_mtkdev[vcuid]->vcu_device) == true) {
- ret = (int)PTR_ERR(vcu_mtkdev[vcuid]->vcu_device);
- dev_err(dev, "[VCU] device_create fail (ret=%d)", ret);
- goto err_device;
- }
- ret = of_property_read_u32(dev->of_node, "mediatek,dec_gce_th_num",
- &vcu->gce_th_num[VCU_VDEC]);
- if (ret != 0 || vcu->gce_th_num[VCU_VDEC] > GCE_THNUM_MAX)
- vcu->gce_th_num[VCU_VDEC] = 1;
- ret = of_property_read_u32(dev->of_node, "mediatek,enc_gce_th_num",
- &vcu->gce_th_num[VCU_VENC]);
- if (ret != 0 || vcu->gce_th_num[VCU_VENC] > GCE_THNUM_MAX)
- vcu->gce_th_num[VCU_VENC] = 1;
- for (i = 0; i < ARRAY_SIZE(vcu->gce_gpr); i++) {
- ret = of_property_read_u32_index(dev->of_node, "gce-gpr",
- i, &vcu->gce_gpr[i]);
- if (ret < 0)
- break;
- }
- vcu->clt_base = cmdq_register_device(dev);
- for (i = 0; i < vcu->gce_th_num[VCU_VDEC]; i++)
- vcu->clt_vdec[i] = cmdq_mbox_create(dev, i);
- for (i = 0; i < vcu->gce_th_num[VCU_VENC]; i++)
- vcu->clt_venc[i] =
- cmdq_mbox_create(dev, i + vcu->gce_th_num[VCU_VDEC]);
- vcu->clt_venc_sec[0] =
- cmdq_mbox_create(dev,
- vcu->gce_th_num[VCU_VDEC] + vcu->gce_th_num[VCU_VENC]);
- if (IS_ERR_OR_NULL(vcu->clt_vdec[0]))
- goto err_device;
- dev_dbg(dev, "[VCU] GCE clt_base %p clt_vdec %d %p %p clt_venc %d %p %p %p dev %p",
- vcu->clt_base, vcu->gce_th_num[VCU_VDEC],
- vcu->clt_vdec[0], vcu->clt_vdec[1],
- vcu->gce_th_num[VCU_VENC], vcu->clt_venc[0],
- vcu->clt_venc[1], vcu->clt_venc_sec[0], dev);
- for (i = 0; i < GCE_EVENT_MAX; i++)
- vcu->gce_codec_eid[i] = -1;
- vcu->gce_codec_eid[VDEC_EVENT_0] =
- cmdq_dev_get_event(dev, "vdec_pic_start");
- vcu->gce_codec_eid[VDEC_EVENT_1] =
- cmdq_dev_get_event(dev, "vdec_decode_done");
- vcu->gce_codec_eid[VDEC_EVENT_2] =
- cmdq_dev_get_event(dev, "vdec_pause");
- vcu->gce_codec_eid[VDEC_EVENT_3] =
- cmdq_dev_get_event(dev, "vdec_dec_error");
- vcu->gce_codec_eid[VDEC_EVENT_4] =
- cmdq_dev_get_event(dev, "vdec_mc_busy_overflow_timeout");
- vcu->gce_codec_eid[VDEC_EVENT_5] =
- cmdq_dev_get_event(dev, "vdec_all_dram_req_done");
- vcu->gce_codec_eid[VDEC_EVENT_6] =
- cmdq_dev_get_event(dev, "vdec_ini_fetch_rdy");
- vcu->gce_codec_eid[VDEC_EVENT_7] =
- cmdq_dev_get_event(dev, "vdec_process_flag");
- vcu->gce_codec_eid[VDEC_EVENT_8] =
- cmdq_dev_get_event(dev, "vdec_search_start_code_done");
- vcu->gce_codec_eid[VDEC_EVENT_9] =
- cmdq_dev_get_event(dev, "vdec_ref_reorder_done");
- vcu->gce_codec_eid[VDEC_EVENT_10] =
- cmdq_dev_get_event(dev, "vdec_wp_tble_done");
- vcu->gce_codec_eid[VDEC_EVENT_11] =
- cmdq_dev_get_event(dev, "vdec_count_sram_clr_done");
- vcu->gce_codec_eid[VDEC_EVENT_15] =
- cmdq_dev_get_event(dev, "vdec_gce_cnt_op_threshold");
- vcu->gce_codec_eid[VDEC_LAT_EVENT_0] =
- cmdq_dev_get_event(dev, "vdec_lat_pic_start");
- vcu->gce_codec_eid[VDEC_LAT_EVENT_1] =
- cmdq_dev_get_event(dev, "vdec_lat_decode_done");
- vcu->gce_codec_eid[VDEC_LAT_EVENT_2] =
- cmdq_dev_get_event(dev, "vdec_lat_pause");
- vcu->gce_codec_eid[VDEC_LAT_EVENT_3] =
- cmdq_dev_get_event(dev, "vdec_lat_dec_error");
- vcu->gce_codec_eid[VDEC_LAT_EVENT_4] =
- cmdq_dev_get_event(dev, "vdec_lat_mc_busy_overflow_timeout");
- vcu->gce_codec_eid[VDEC_LAT_EVENT_5] =
- cmdq_dev_get_event(dev, "vdec_lat_all_dram_req_done");
- vcu->gce_codec_eid[VDEC_LAT_EVENT_6] =
- cmdq_dev_get_event(dev, "vdec_lat_ini_fetch_rdy");
- vcu->gce_codec_eid[VDEC_LAT_EVENT_7] =
- cmdq_dev_get_event(dev, "vdec_lat_process_flag");
- vcu->gce_codec_eid[VDEC_LAT_EVENT_8] =
- cmdq_dev_get_event(dev, "vdec_lat_search_start_code_done");
- vcu->gce_codec_eid[VDEC_LAT_EVENT_9] =
- cmdq_dev_get_event(dev, "vdec_lat_ref_reorder_done");
- vcu->gce_codec_eid[VDEC_LAT_EVENT_10] =
- cmdq_dev_get_event(dev, "vdec_lat_wp_tble_done");
- vcu->gce_codec_eid[VDEC_LAT_EVENT_11] =
- cmdq_dev_get_event(dev, "vdec_lat_count_sram_clr_done");
- vcu->gce_codec_eid[VDEC_LAT_EVENT_15] =
- cmdq_dev_get_event(dev, "vdec_lat_gce_cnt_op_threshold");
- vcu->gce_codec_eid[VENC_EOF] =
- cmdq_dev_get_event(dev, "venc_eof");
- vcu->gce_codec_eid[VENC_CMDQ_PAUSE_DONE] =
- cmdq_dev_get_event(dev, "venc_cmdq_pause_done");
- vcu->gce_codec_eid[VENC_MB_DONE] =
- cmdq_dev_get_event(dev, "venc_mb_done");
- vcu->gce_codec_eid[VENC_128BYTE_CNT_DONE] =
- cmdq_dev_get_event(dev, "venc_128B_cnt_done");
- vcu->gce_codec_eid[VENC_EOF_C1] =
- cmdq_dev_get_event(dev, "venc_eof_c1");
- vcu->gce_codec_eid[VENC_WP_2ND_DONE] =
- cmdq_dev_get_event(dev, "venc_wp_2nd_done");
- vcu->gce_codec_eid[VENC_WP_3ND_DONE] =
- cmdq_dev_get_event(dev, "venc_wp_3nd_done");
- vcu->gce_codec_eid[VENC_SPS_DONE] =
- cmdq_dev_get_event(dev, "venc_sps_done");
- vcu->gce_codec_eid[VENC_PPS_DONE] =
- cmdq_dev_get_event(dev, "venc_pps_done");
- for (i = 0; i < (int)VCU_CODEC_MAX; i++) {
- vcu->gce_cmds[i] = devm_kzalloc(dev,
- sizeof(struct gce_cmds), GFP_KERNEL);
- if (vcu->gce_cmds[i] == NULL)
- goto err_device;
- }
- sema_init(&vcu->vpud_killed, 1);
- for (i = 0; i < (int)VCU_CODEC_MAX; i++) {
- vcu->curr_ctx[i] = NULL;
- vcu->curr_src_vb[i] = NULL;
- vcu->curr_dst_vb[i] = NULL;
- }
- vcu->is_entering_suspend = 0;
- pm_notifier(mtk_vcu_suspend_notifier, 0);
- ret = vcu_alloc_d_ext_mem(vcu, VCU_SHMEM_SIZE);
- if (ret != 0) {
- dev_dbg(dev, "[VCU] allocate SHMEM failed\n");
- goto err_device;
- }
- register_trace_signal_generate(probe_death_signal, NULL);
- spin_lock_init(&vcu_ptr->vpud_sig_lock);
- vcu_ptr->vpud_is_going_down = 0;
- vcu_ptr->enable_vcu_dbg_log = 0;
- dev_dbg(dev, "[VCU] initialization completed\n");
- return 0;
- err_device:
- class_destroy(vcu_mtkdev[vcuid]->vcu_class);
- err_add:
- cdev_del(vcu_mtkdev[vcuid]->vcu_cdev);
- err_alloc:
- unregister_chrdev_region(vcu_mtkdev[vcuid]->vcu_devno, 1);
- vcu_mutex_destroy:
- mutex_destroy(&vcu->vcu_mutex[VCU_VDEC]);
- mutex_destroy(&vcu->vcu_mutex[VCU_VENC]);
- mutex_destroy(&vcu->vcu_gce_mutex[VCU_VDEC]);
- mutex_destroy(&vcu->vcu_gce_mutex[VCU_VENC]);
- mutex_destroy(&vcu->ctx_ipi_binding[VCU_VDEC]);
- mutex_destroy(&vcu->ctx_ipi_binding[VCU_VENC]);
- mutex_destroy(&vcu->vcu_share);
- mutex_destroy(&vpud_file_mutex);
- err_ipi_init:
- devm_kfree(dev, vcu);
- return ret;
- }
- static const struct of_device_id mtk_vcu_match[] = {
- {.compatible = "mediatek,mt8173-vcu",},
- {.compatible = "mediatek,mt2701-vpu",},
- {.compatible = "mediatek,mt2712-vcu",},
- {.compatible = "mediatek,mt6771-vcu",},
- {.compatible = "mediatek-vcu",},
- {},
- };
- MODULE_DEVICE_TABLE(of, mtk_vcu_match);
- static int mtk_vcu_remove(struct platform_device *pdev)
- {
- struct mtk_vcu *vcu = platform_get_drvdata(pdev);
- vcu_free_d_ext_mem(vcu);
- if (vcu->is_open == true) {
- filp_close(vcu->file, NULL);
- vcu->is_open = false;
- }
- devm_kfree(&pdev->dev, vcu);
- device_destroy(vcu->vcu_class, vcu->vcu_devno);
- class_destroy(vcu->vcu_class);
- cdev_del(vcu->vcu_cdev);
- unregister_chrdev_region(vcu->vcu_devno, 1);
- return 0;
- }
- static const struct dev_pm_ops mtk_vcu_pm_ops = {
- .suspend = mtk_vcu_suspend,
- .resume = mtk_vcu_resume,
- };
- static struct platform_driver mtk_vcu_driver = {
- .probe = mtk_vcu_probe,
- .remove = mtk_vcu_remove,
- .driver = {
- .name = "mtk_vcu",
- .owner = THIS_MODULE,
- .pm = &mtk_vcu_pm_ops,
- .of_match_table = mtk_vcu_match,
- },
- };
- module_platform_driver(mtk_vcu_driver);
- MODULE_LICENSE("GPL v2");
- MODULE_DESCRIPTION("Mediatek Video Communication And Controller Unit driver");
|