From 9370bb92b2d16684ee45cf24e879c93c509162da Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Thu, 19 Dec 2024 01:47:39 +0000 Subject: [PATCH] add wifi6 8852be driver --- kernel/drivers/video/rockchip/mpp/mpp_rkvdec2.c | 561 ++++++++++++++++++++++++++++++++++++++++++++----------- 1 files changed, 445 insertions(+), 116 deletions(-) diff --git a/kernel/drivers/video/rockchip/mpp/mpp_rkvdec2.c b/kernel/drivers/video/rockchip/mpp/mpp_rkvdec2.c index 61364f2..a463fc2 100644 --- a/kernel/drivers/video/rockchip/mpp/mpp_rkvdec2.c +++ b/kernel/drivers/video/rockchip/mpp/mpp_rkvdec2.c @@ -7,6 +7,8 @@ * Ding Wei, leo.ding@rock-chips.com * */ +#include <linux/pm_runtime.h> + #include "mpp_debug.h" #include "mpp_common.h" #include "mpp_iommu.h" @@ -23,7 +25,7 @@ #include <soc/rockchip/rockchip_iommu.h> #ifdef CONFIG_PM_DEVFREQ -#include "../../../devfreq/governor.h" +#include "../drivers/devfreq/governor.h" #endif /* @@ -38,13 +40,22 @@ .link_info = &rkvdec_link_v2_hw_info, }; -static struct mpp_hw_info rkvdec_rk3568_hw_info = { +static struct mpp_hw_info rkvdec_rk356x_hw_info = { .reg_num = RKVDEC_REG_NUM, .reg_id = RKVDEC_REG_HW_ID_INDEX, .reg_start = RKVDEC_REG_START_INDEX, .reg_end = RKVDEC_REG_END_INDEX, .reg_en = RKVDEC_REG_START_EN_INDEX, - .link_info = &rkvdec_link_rk3568_hw_info, + .link_info = &rkvdec_link_rk356x_hw_info, +}; + +static struct mpp_hw_info rkvdec_vdpu382_hw_info = { + .reg_num = RKVDEC_REG_NUM, + .reg_id = RKVDEC_REG_HW_ID_INDEX, + .reg_start = RKVDEC_REG_START_INDEX, + .reg_end = RKVDEC_REG_END_INDEX, + .reg_en = RKVDEC_REG_START_EN_INDEX, + .link_info = &rkvdec_link_vdpu382_hw_info, }; /* @@ -182,9 +193,8 @@ return 0; } -static int mpp_set_rcbbuf(struct mpp_dev *mpp, - struct mpp_session *session, - struct rkvdec2_task *task) +int mpp_set_rcbbuf(struct mpp_dev *mpp, struct mpp_session *session, + struct mpp_task *task) { struct rkvdec2_dev *dec = to_rkvdec2_dev(mpp); struct rkvdec2_session_priv *priv = session->priv; @@ -204,10 +214,11 @@ for (i = 0; i < rcb_inf->cnt; i++) { reg_idx = rcb_inf->elem[i].index; rcb_size = rcb_inf->elem[i].size; - if (!rcb_size || - rcb_offset > dec->sram_size || - (rcb_offset + rcb_size) > dec->rcb_size) + if ((rcb_offset + rcb_size) > dec->rcb_size) { + mpp_debug(DEBUG_SRAM_INFO, + "rcb: reg %d use original buffer\n", reg_idx); continue; + } mpp_debug(DEBUG_SRAM_INFO, "rcb: reg %d offset %d, size %d\n", reg_idx, rcb_offset, rcb_size); task->reg[reg_idx] = dec->rcb_iova + rcb_offset; @@ -220,45 +231,38 @@ return 0; } -void *rkvdec2_alloc_task(struct mpp_session *session, - struct mpp_task_msgs *msgs) +int rkvdec2_task_init(struct mpp_dev *mpp, struct mpp_session *session, + struct rkvdec2_task *task, struct mpp_task_msgs *msgs) { int ret; - struct mpp_task *mpp_task = NULL; - struct rkvdec2_task *task = NULL; - struct mpp_dev *mpp = session->mpp; + struct mpp_task *mpp_task = &task->mpp_task; mpp_debug_enter(); - task = kzalloc(sizeof(*task), GFP_KERNEL); - if (!task) - return NULL; - - mpp_task = &task->mpp_task; mpp_task_init(session, mpp_task); mpp_task->hw_info = mpp->var->hw_info; mpp_task->reg = task->reg; /* extract reqs for current task */ ret = rkvdec2_extract_task_msg(session, task, msgs); if (ret) - goto fail; + return ret; /* process fd in register */ if (!(msgs->flags & MPP_FLAGS_REG_FD_NO_TRANS)) { u32 fmt = RKVDEC_GET_FORMAT(task->reg[RKVDEC_REG_FORMAT_INDEX]); - ret = mpp_translate_reg_address(session, &task->mpp_task, + ret = mpp_translate_reg_address(session, mpp_task, fmt, task->reg, &task->off_inf); if (ret) goto fail; - mpp_translate_reg_offset_info(&task->mpp_task, &task->off_inf, task->reg); + mpp_translate_reg_offset_info(mpp_task, &task->off_inf, task->reg); } - mpp_set_rcbbuf(mpp, session, task); + task->strm_addr = task->reg[RKVDEC_REG_RLC_BASE_INDEX]; task->clk_mode = CLK_MODE_NORMAL; task->slot_idx = -1; - init_waitqueue_head(&task->wait); + init_waitqueue_head(&mpp_task->wait); /* get resolution info */ if (session->priv) { struct rkvdec2_session_priv *priv = session->priv; @@ -274,18 +278,37 @@ mpp_debug_leave(); - return mpp_task; + return 0; fail: mpp_task_dump_mem_region(mpp, mpp_task); mpp_task_dump_reg(mpp, mpp_task); mpp_task_finalize(session, mpp_task); - kfree(task); - return NULL; + return ret; +} + +void *rkvdec2_alloc_task(struct mpp_session *session, + struct mpp_task_msgs *msgs) +{ + int ret; + struct rkvdec2_task *task; + + task = kzalloc(sizeof(*task), GFP_KERNEL); + if (!task) + return NULL; + + ret = rkvdec2_task_init(session->mpp, session, task, msgs); + if (ret) { + kfree(task); + return NULL; + } + mpp_set_rcbbuf(session->mpp, session, &task->mpp_task); + + return &task->mpp_task; } static void *rkvdec2_rk3568_alloc_task(struct mpp_session *session, - struct mpp_task_msgs *msgs) + struct mpp_task_msgs *msgs) { u32 fmt; struct mpp_task *mpp_task = NULL; @@ -400,7 +423,7 @@ return IRQ_HANDLED; } mpp_task->hw_cycles = mpp_read(mpp, RKVDEC_PERF_WORKING_CNT); - mpp_time_diff_with_hw_time(mpp_task, dec->core_clk_info.real_rate_hz); + mpp_time_diff_with_hw_time(mpp_task, dec->cycle_clk->real_rate_hz); mpp->cur_task = NULL; task = to_rkvdec2_task(mpp_task); task->irq_status = mpp->irq_status; @@ -410,9 +433,10 @@ RKVDEC_TIMEOUT_STA | RKVDEC_ERROR_STA; if (err_mask & task->irq_status) { atomic_inc(&mpp->reset_request); - mpp_debug(DEBUG_DUMP_ERR_REG, "irq_status: %08x\n", - task->irq_status); - mpp_task_dump_hw_reg(mpp, mpp_task); + if (mpp_debug_unlikely(DEBUG_DUMP_ERR_REG)) { + mpp_debug(DEBUG_DUMP_ERR_REG, "irq_status: %08x\n", task->irq_status); + mpp_task_dump_hw_reg(mpp); + } } mpp_task_finish(mpp_task->session, mpp_task); @@ -483,6 +507,18 @@ dec_length = dec_get - task->strm_addr; task->reg[RKVDEC_REG_RLC_BASE_INDEX] = dec_length << 10; mpp_debug(DEBUG_REGISTER, "dec_get %08x dec_length %d\n", dec_get, dec_length); + + if (mpp->srv->timing_en) { + s64 time_diff; + + mpp_task->on_finish = ktime_get(); + set_bit(TASK_TIMING_FINISH, &mpp_task->state); + + time_diff = ktime_us_delta(mpp_task->on_finish, mpp_task->on_create); + + if (mpp->timing_check && time_diff > (s64)mpp->timing_check) + mpp_task_dump_timing(mpp_task, time_diff); + } mpp_debug_leave(); @@ -565,16 +601,6 @@ } } } break; - case MPP_CMD_SET_ERR_REF_HACK: { - struct rkvdec2_dev *dec = to_rkvdec2_dev(session->mpp); - u32 err_ref_hack_en = 0; - - if (copy_from_user(&err_ref_hack_en, req->data, sizeof(u32))) { - mpp_err("copy_from_user failed\n"); - return -EINVAL; - } - dec->err_ref_hack = err_ref_hack_en; - } break; default: { mpp_err("unknown mpp ioctl cmd %x\n", req->cmd); } break; @@ -633,8 +659,15 @@ static int rkvdec2_procfs_init(struct mpp_dev *mpp) { struct rkvdec2_dev *dec = to_rkvdec2_dev(mpp); + char name[32]; - dec->procfs = proc_mkdir(mpp->dev->of_node->name, mpp->srv->procfs); + if (!mpp->dev || !mpp->dev->of_node || !mpp->dev->of_node->name || + !mpp->srv || !mpp->srv->procfs) + return -EINVAL; + + snprintf(name, sizeof(name) - 1, "%s%d", + mpp->dev->of_node->name, mpp->core_id); + dec->procfs = proc_mkdir(name, mpp->srv->procfs); if (IS_ERR_OR_NULL(dec->procfs)) { mpp_err("failed on open procfs\n"); dec->procfs = NULL; @@ -797,7 +830,7 @@ }; static struct monitor_dev_profile vdec2_mdevp = { - .type = MONITOR_TPYE_DEV, + .type = MONITOR_TYPE_DEV, .low_temp_adjust = rockchip_monitor_dev_low_temp_adjust, .high_temp_adjust = rockchip_monitor_dev_high_temp_adjust, }; @@ -905,6 +938,42 @@ return 0; } + +void mpp_devfreq_set_core_rate(struct mpp_dev *mpp, enum MPP_CLOCK_MODE mode) +{ + struct rkvdec2_dev *dec = to_rkvdec2_dev(mpp); + + if (dec->devfreq) { + unsigned long core_rate_hz; + + mutex_lock(&dec->devfreq->lock); + core_rate_hz = mpp_get_clk_info_rate_hz(&dec->core_clk_info, mode); + if (dec->core_rate_hz != core_rate_hz) { + dec->core_rate_hz = core_rate_hz; + update_devfreq(dec->devfreq); + } + mutex_unlock(&dec->devfreq->lock); + } + + mpp_clk_set_rate(&dec->core_clk_info, mode); +} +#else +static inline int rkvdec2_devfreq_init(struct mpp_dev *mpp) +{ + return 0; +} + +static inline int rkvdec2_devfreq_remove(struct mpp_dev *mpp) +{ + return 0; +} + +void mpp_devfreq_set_core_rate(struct mpp_dev *mpp, enum MPP_CLOCK_MODE mode) +{ + struct rkvdec2_dev *dec = to_rkvdec2_dev(mpp); + + mpp_clk_set_rate(&dec->core_clk_info, mode); +} #endif static int rkvdec2_init(struct mpp_dev *mpp) @@ -937,6 +1006,7 @@ mpp_set_clk_info_rate_hz(&dec->cabac_clk_info, CLK_MODE_DEFAULT, 200 * MHZ); mpp_set_clk_info_rate_hz(&dec->hevc_cabac_clk_info, CLK_MODE_DEFAULT, 300 * MHZ); + dec->cycle_clk = &dec->aclk_info; /* Get normal max workload from dtsi */ of_property_read_u32(mpp->dev->of_node, "rockchip,default-max-load", &dec->default_max_load); @@ -963,11 +1033,10 @@ if (!dec->rst_hevc_cabac) mpp_err("No hevc cabac reset resource define\n"); -#ifdef CONFIG_PM_DEVFREQ ret = rkvdec2_devfreq_init(mpp); if (ret) mpp_err("failed to add vdec devfreq\n"); -#endif + return ret; } @@ -992,9 +1061,7 @@ { struct rkvdec2_dev *dec = to_rkvdec2_dev(mpp); -#ifdef CONFIG_PM_DEVFREQ rkvdec2_devfreq_remove(mpp); -#endif if (dec->fix) mpp_dma_free(dec->fix); @@ -1073,23 +1140,7 @@ mpp_clk_set_rate(&dec->aclk_info, task->clk_mode); mpp_clk_set_rate(&dec->cabac_clk_info, task->clk_mode); mpp_clk_set_rate(&dec->hevc_cabac_clk_info, task->clk_mode); - -#ifdef CONFIG_PM_DEVFREQ - if (dec->devfreq) { - unsigned long core_rate_hz; - - mutex_lock(&dec->devfreq->lock); - core_rate_hz = mpp_get_clk_info_rate_hz(&dec->core_clk_info, task->clk_mode); - if (dec->core_rate_hz != core_rate_hz) { - dec->core_rate_hz = core_rate_hz; - update_devfreq(dec->devfreq); - } - mutex_unlock(&dec->devfreq->lock); - - return 0; - } -#endif - mpp_clk_set_rate(&dec->core_clk_info, task->clk_mode); + mpp_devfreq_set_core_rate(mpp, task->clk_mode); return 0; } @@ -1112,16 +1163,31 @@ } -static int rkvdec2_reset(struct mpp_dev *mpp) +static int rkvdec2_sip_reset(struct mpp_dev *mpp) +{ + mpp_debug_enter(); + + if (IS_REACHABLE(CONFIG_ROCKCHIP_SIP)) { + /* sip reset */ + rockchip_dmcfreq_lock(); + sip_smc_vpu_reset(0, 0, 0); + rockchip_dmcfreq_unlock(); + } else { + rkvdec2_reset(mpp); + } + + mpp_debug_leave(); + + return 0; +} + +int rkvdec2_reset(struct mpp_dev *mpp) { struct rkvdec2_dev *dec = to_rkvdec2_dev(mpp); int ret = 0; mpp_debug_enter(); -#ifdef CONFIG_PM_DEVFREQ - if (dec->devfreq) - mutex_lock(&dec->devfreq->lock); -#endif + /* safe reset first*/ ret = rkvdec2_soft_reset(mpp); @@ -1146,28 +1212,6 @@ mpp_safe_unreset(dec->rst_hevc_cabac); mpp_pmu_idle_request(mpp, false); } -#ifdef CONFIG_PM_DEVFREQ - if (dec->devfreq) - mutex_unlock(&dec->devfreq->lock); -#endif - mpp_debug_leave(); - - return 0; -} - -static int rkvdec2_sip_reset(struct mpp_dev *mpp) -{ - mpp_debug_enter(); - - if (IS_REACHABLE(CONFIG_ROCKCHIP_SIP)) { - /* sip reset */ - rockchip_dmcfreq_lock(); - sip_smc_vpu_reset(0, 0, 0); - rockchip_dmcfreq_unlock(); - } else { - rkvdec2_reset(mpp); - } - mpp_debug_leave(); return 0; @@ -1185,6 +1229,15 @@ static struct mpp_hw_ops rkvdec_rk3568_hw_ops = { .init = rkvdec2_rk3568_init, .exit = rkvdec2_rk3568_exit, + .clk_on = rkvdec2_clk_on, + .clk_off = rkvdec2_clk_off, + .get_freq = rkvdec2_get_freq, + .set_freq = rkvdec2_set_freq, + .reset = rkvdec2_sip_reset, +}; + +static struct mpp_hw_ops rkvdec_rk3588_hw_ops = { + .init = rkvdec2_init, .clk_on = rkvdec2_clk_on, .clk_off = rkvdec2_clk_off, .get_freq = rkvdec2_get_freq, @@ -1229,10 +1282,26 @@ static const struct mpp_dev_var rkvdec_rk3568_data = { .device_type = MPP_DEVICE_RKVDEC, - .hw_info = &rkvdec_rk3568_hw_info, + .hw_info = &rkvdec_rk356x_hw_info, .trans_info = rkvdec_v2_trans, .hw_ops = &rkvdec_rk3568_hw_ops, .dev_ops = &rkvdec_rk3568_dev_ops, +}; + +static const struct mpp_dev_var rkvdec_vdpu382_data = { + .device_type = MPP_DEVICE_RKVDEC, + .hw_info = &rkvdec_vdpu382_hw_info, + .trans_info = rkvdec_v2_trans, + .hw_ops = &rkvdec_v2_hw_ops, + .dev_ops = &rkvdec_v2_dev_ops, +}; + +static const struct mpp_dev_var rkvdec_rk3588_data = { + .device_type = MPP_DEVICE_RKVDEC, + .hw_info = &rkvdec_v2_hw_info, + .trans_info = rkvdec_v2_trans, + .hw_ops = &rkvdec_rk3588_hw_ops, + .dev_ops = &rkvdec_v2_dev_ops, }; static const struct of_device_id mpp_rkvdec2_dt_match[] = { @@ -1246,8 +1315,91 @@ .data = &rkvdec_rk3568_data, }, #endif +#ifdef CONFIG_CPU_RK3588 + { + .compatible = "rockchip,rkv-decoder-v2-ccu", + .data = &rkvdec_rk3588_data, + }, +#endif +#ifdef CONFIG_CPU_RK3528 + { + .compatible = "rockchip,rkv-decoder-rk3528", + .data = &rkvdec_vdpu382_data, + }, +#endif +#ifdef CONFIG_CPU_RK3562 + { + .compatible = "rockchip,rkv-decoder-rk3562", + .data = &rkvdec_vdpu382_data, + }, +#endif {}, }; + +static int rkvdec2_ccu_remove(struct device *dev) +{ + device_init_wakeup(dev, false); + pm_runtime_disable(dev); + + return 0; +} + +static int rkvdec2_ccu_probe(struct platform_device *pdev) +{ + struct rkvdec2_ccu *ccu; + struct resource *res; + struct device *dev = &pdev->dev; + u32 ccu_mode; + + ccu = devm_kzalloc(dev, sizeof(*ccu), GFP_KERNEL); + if (!ccu) + return -ENOMEM; + + ccu->dev = dev; + /* use task-level soft ccu default */ + ccu->ccu_mode = RKVDEC2_CCU_TASK_SOFT; + atomic_set(&ccu->power_enabled, 0); + INIT_LIST_HEAD(&ccu->unused_list); + INIT_LIST_HEAD(&ccu->used_list); + platform_set_drvdata(pdev, ccu); + + if (!of_property_read_u32(dev->of_node, "rockchip,ccu-mode", &ccu_mode)) { + if (ccu_mode <= RKVDEC2_CCU_MODE_NULL || ccu_mode >= RKVDEC2_CCU_MODE_BUTT) + ccu_mode = RKVDEC2_CCU_TASK_SOFT; + ccu->ccu_mode = (enum RKVDEC2_CCU_MODE)ccu_mode; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ccu"); + if (!res) { + dev_err(dev, "no memory resource defined\n"); + return -ENODEV; + } + + ccu->reg_base = devm_ioremap(dev, res->start, resource_size(res)); + if (!ccu->reg_base) { + dev_err(dev, "ioremap failed for resource %pR\n", res); + return -ENODEV; + } + + ccu->aclk_info.clk = devm_clk_get(dev, "aclk_ccu"); + if (!ccu->aclk_info.clk) + mpp_err("failed on clk_get ccu aclk\n"); + + ccu->rst_a = devm_reset_control_get(dev, "video_ccu"); + if (ccu->rst_a) + mpp_safe_unreset(ccu->rst_a); + else + mpp_err("failed on clk_get ccu reset\n"); + + /* power domain autosuspend delay 2s */ + pm_runtime_set_autosuspend_delay(dev, 2000); + pm_runtime_use_autosuspend(dev); + device_init_wakeup(dev, true); + pm_runtime_enable(dev); + + dev_info(dev, "ccu-mode: %d\n", ccu->ccu_mode); + return 0; +} static int rkvdec2_alloc_rcbbuf(struct platform_device *pdev, struct rkvdec2_dev *dec) { @@ -1342,6 +1494,22 @@ if (!ret && dec->rcb_min_width) dev_info(dev, "min_width %u\n", dec->rcb_min_width); + /* if have, read rcb_info */ + dec->rcb_info_count = device_property_count_u32(dev, "rockchip,rcb-info"); + if (dec->rcb_info_count > 0 && + dec->rcb_info_count <= (sizeof(dec->rcb_infos) / sizeof(u32))) { + int i; + + ret = device_property_read_u32_array(dev, "rockchip,rcb-info", + dec->rcb_infos, dec->rcb_info_count); + if (!ret) { + dev_info(dev, "rcb_info_count %u\n", dec->rcb_info_count); + for (i = 0; i < dec->rcb_info_count; i += 2) + dev_info(dev, "[%u, %u]\n", + dec->rcb_infos[i], dec->rcb_infos[i+1]); + } + } + return 0; err_sram_map: @@ -1350,7 +1518,94 @@ return ret; } -static int rkvdec2_probe(struct platform_device *pdev) +static int rkvdec2_core_probe(struct platform_device *pdev) +{ + int ret; + struct rkvdec2_dev *dec; + struct mpp_dev *mpp; + struct device *dev = &pdev->dev; + irq_handler_t irq_proc = NULL; + + dec = devm_kzalloc(dev, sizeof(*dec), GFP_KERNEL); + if (!dec) + return -ENOMEM; + + mpp = &dec->mpp; + platform_set_drvdata(pdev, mpp); + mpp->is_irq_startup = false; + if (dev->of_node) { + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *match; + + match = of_match_node(mpp_rkvdec2_dt_match, dev->of_node); + if (match) + mpp->var = (struct mpp_dev_var *)match->data; + mpp->core_id = of_alias_get_id(np, "rkvdec"); + } + + ret = mpp_dev_probe(mpp, pdev); + if (ret) { + dev_err(dev, "probe sub driver failed\n"); + return ret; + } + dec->mmu_base = ioremap(dec->mpp.io_base + 0x600, 0x80); + if (!dec->mmu_base) + dev_err(dev, "mmu base map failed!\n"); + + /* attach core to ccu */ + ret = rkvdec2_attach_ccu(dev, dec); + if (ret) { + dev_err(dev, "attach ccu failed\n"); + return ret; + } + + /* alloc rcb buffer */ + rkvdec2_alloc_rcbbuf(pdev, dec); + + /* set device for link */ + ret = rkvdec2_ccu_link_init(pdev, dec); + if (ret) + return ret; + + mpp->dev_ops->alloc_task = rkvdec2_ccu_alloc_task; + if (dec->ccu->ccu_mode == RKVDEC2_CCU_TASK_SOFT) { + mpp->dev_ops->task_worker = rkvdec2_soft_ccu_worker; + irq_proc = rkvdec2_soft_ccu_irq; + mpp->fault_handler = rkvdec2_soft_ccu_iommu_fault_handle; + } else if (dec->ccu->ccu_mode == RKVDEC2_CCU_TASK_HARD) { + if (mpp->core_id == 0 && mpp->task_capacity > 1) { + dec->link_dec->task_capacity = mpp->task_capacity; + ret = rkvdec2_ccu_alloc_table(dec, dec->link_dec); + if (ret) + return ret; + } + mpp->dev_ops->task_worker = rkvdec2_hard_ccu_worker; + irq_proc = rkvdec2_hard_ccu_irq; + mpp->fault_handler = rkvdec2_hard_ccu_iommu_fault_handle; + } + kthread_init_work(&mpp->work, mpp->dev_ops->task_worker); + + /* get irq request */ + ret = devm_request_threaded_irq(dev, mpp->irq, irq_proc, NULL, + IRQF_SHARED, dev_name(dev), mpp); + if (ret) { + dev_err(dev, "register interrupter runtime failed\n"); + return -EINVAL; + } + /*make sure mpp->irq is startup then can be en/disable*/ + mpp->is_irq_startup = true; + + mpp->session_max_buffers = RKVDEC_SESSION_MAX_BUFFERS; + rkvdec2_procfs_init(mpp); + + /* if is main-core, register to mpp service */ + if (mpp->core_id == 0) + mpp_dev_register_srv(mpp, mpp->srv); + + return ret; +} + +static int rkvdec2_probe_default(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct rkvdec2_dev *dec = NULL; @@ -1358,13 +1613,12 @@ const struct of_device_id *match = NULL; int ret = 0; - dev_info(dev, "probing start\n"); dec = devm_kzalloc(dev, sizeof(*dec), GFP_KERNEL); if (!dec) return -ENOMEM; mpp = &dec->mpp; - platform_set_drvdata(pdev, dec); + platform_set_drvdata(pdev, mpp); if (pdev->dev.of_node) { match = of_match_node(mpp_rkvdec2_dt_match, pdev->dev.of_node); @@ -1405,9 +1659,28 @@ rkvdec2_link_procfs_init(mpp); /* register current device to mpp service */ mpp_dev_register_srv(mpp, mpp->srv); + + return ret; +} + +static int rkvdec2_probe(struct platform_device *pdev) +{ + int ret; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + + dev_info(dev, "%s, probing start\n", np->name); + + if (strstr(np->name, "ccu")) + ret = rkvdec2_ccu_probe(pdev); + else if (strstr(np->name, "core")) + ret = rkvdec2_core_probe(pdev); + else + ret = rkvdec2_probe_default(pdev); + dev_info(dev, "probing finish\n"); - return 0; + return ret; } static int rkvdec2_free_rcbbuf(struct platform_device *pdev, struct rkvdec2_dev *dec) @@ -1416,8 +1689,9 @@ if (dec->rcb_page) { size_t page_size = PAGE_ALIGN(dec->rcb_size - dec->sram_size); + int order = min(get_order(page_size), MAX_ORDER); - __free_pages(dec->rcb_page, get_order(page_size)); + __free_pages(dec->rcb_page, order); } if (dec->rcb_iova) { domain = dec->mpp.iommu_info->domain; @@ -1430,34 +1704,88 @@ static int rkvdec2_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct rkvdec2_dev *dec = platform_get_drvdata(pdev); - dev_info(dev, "remove device\n"); - rkvdec2_free_rcbbuf(pdev, dec); - mpp_dev_remove(&dec->mpp); - rkvdec2_procfs_remove(&dec->mpp); - rkvdec2_link_remove(&dec->mpp, dec->link_dec); + if (strstr(dev_name(dev), "ccu")) { + dev_info(dev, "remove ccu device\n"); + rkvdec2_ccu_remove(dev); + } else { + struct mpp_dev *mpp = dev_get_drvdata(dev); + struct rkvdec2_dev *dec = to_rkvdec2_dev(mpp); + + dev_info(dev, "remove device\n"); + if (dec->mmu_base) { + iounmap(dec->mmu_base); + dec->mmu_base = NULL; + } + rkvdec2_free_rcbbuf(pdev, dec); + mpp_dev_remove(mpp); + rkvdec2_procfs_remove(mpp); + rkvdec2_link_remove(mpp, dec->link_dec); + } return 0; } static void rkvdec2_shutdown(struct platform_device *pdev) { - int ret; - int val; struct device *dev = &pdev->dev; - struct rkvdec2_dev *dec = platform_get_drvdata(pdev); - struct mpp_dev *mpp = &dec->mpp; - dev_info(dev, "shutdown device\n"); - - atomic_inc(&mpp->srv->shutdown_request); - ret = readx_poll_timeout(atomic_read, - &mpp->task_count, - val, val == 0, 20000, 200000); - if (ret == -ETIMEDOUT) - dev_err(dev, "wait total running time out\n"); + if (!strstr(dev_name(dev), "ccu")) + mpp_dev_shutdown(pdev); } + +static int __maybe_unused rkvdec2_runtime_suspend(struct device *dev) +{ + if (strstr(dev_name(dev), "ccu")) { + struct rkvdec2_ccu *ccu = dev_get_drvdata(dev); + + mpp_clk_safe_disable(ccu->aclk_info.clk); + } else { + struct mpp_dev *mpp = dev_get_drvdata(dev); + + if (mpp->is_irq_startup) { + /* disable core irq */ + disable_irq(mpp->irq); + if (mpp->iommu_info && mpp->iommu_info->got_irq) + /* disable mmu irq */ + disable_irq(mpp->iommu_info->irq); + } + + if (mpp->hw_ops->clk_off) + mpp->hw_ops->clk_off(mpp); + } + + return 0; +} + +static int __maybe_unused rkvdec2_runtime_resume(struct device *dev) +{ + if (strstr(dev_name(dev), "ccu")) { + struct rkvdec2_ccu *ccu = dev_get_drvdata(dev); + + mpp_clk_safe_enable(ccu->aclk_info.clk); + } else { + struct mpp_dev *mpp = dev_get_drvdata(dev); + + if (mpp->hw_ops->clk_on) + mpp->hw_ops->clk_on(mpp); + if (mpp->is_irq_startup) { + /* enable core irq */ + enable_irq(mpp->irq); + /* enable mmu irq */ + if (mpp->iommu_info && mpp->iommu_info->got_irq) + enable_irq(mpp->iommu_info->irq); + } + + } + + return 0; +} + +static const struct dev_pm_ops rkvdec2_pm_ops = { + SET_RUNTIME_PM_OPS(rkvdec2_runtime_suspend, rkvdec2_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) +}; struct platform_driver rockchip_rkvdec2_driver = { .probe = rkvdec2_probe, @@ -1466,6 +1794,7 @@ .driver = { .name = RKVDEC_DRIVER_NAME, .of_match_table = of_match_ptr(mpp_rkvdec2_dt_match), + .pm = &rkvdec2_pm_ops, }, }; EXPORT_SYMBOL(rockchip_rkvdec2_driver); -- Gitblit v1.6.2