631 lines
13 KiB
C
631 lines
13 KiB
C
|
// SPDX-License-Identifier: GPL-2.0
|
||
|
/*
|
||
|
* Samsung Exynos SoC series dsp driver
|
||
|
*
|
||
|
* Copyright (c) 2020 Samsung Electronics Co., Ltd.
|
||
|
* http://www.samsung.com/
|
||
|
*/
|
||
|
|
||
|
#include <linux/platform_device.h>
|
||
|
#include <linux/io.h>
|
||
|
#include <linux/delay.h>
|
||
|
|
||
|
#include "dsp-log.h"
|
||
|
#include "dsp-dump.h"
|
||
|
#include "dsp-device.h"
|
||
|
#include "dsp-hw-common-system.h"
|
||
|
|
||
|
int dsp_hw_common_system_request_control(struct dsp_system *sys,
|
||
|
unsigned int id, union dsp_control *cmd)
|
||
|
{
|
||
|
int ret;
|
||
|
|
||
|
dsp_enter();
|
||
|
switch (id) {
|
||
|
case DSP_CONTROL_ENABLE_DVFS:
|
||
|
ret = sys->pm.ops->dvfs_enable(&sys->pm, cmd->dvfs.pm_qos);
|
||
|
if (ret)
|
||
|
goto p_err;
|
||
|
break;
|
||
|
case DSP_CONTROL_DISABLE_DVFS:
|
||
|
ret = sys->pm.ops->dvfs_disable(&sys->pm, cmd->dvfs.pm_qos);
|
||
|
if (ret)
|
||
|
goto p_err;
|
||
|
break;
|
||
|
case DSP_CONTROL_ENABLE_BOOST:
|
||
|
mutex_lock(&sys->boost_lock);
|
||
|
if (!sys->boost) {
|
||
|
ret = sys->pm.ops->boost_enable(&sys->pm);
|
||
|
if (ret) {
|
||
|
mutex_unlock(&sys->boost_lock);
|
||
|
goto p_err;
|
||
|
}
|
||
|
|
||
|
ret = sys->bus.ops->mo_get_by_id(&sys->bus,
|
||
|
sys->bus.max_scen_id);
|
||
|
if (ret) {
|
||
|
sys->pm.ops->boost_disable(&sys->pm);
|
||
|
mutex_unlock(&sys->boost_lock);
|
||
|
goto p_err;
|
||
|
}
|
||
|
|
||
|
sys->boost = true;
|
||
|
}
|
||
|
mutex_unlock(&sys->boost_lock);
|
||
|
break;
|
||
|
case DSP_CONTROL_DISABLE_BOOST:
|
||
|
mutex_lock(&sys->boost_lock);
|
||
|
if (sys->boost) {
|
||
|
sys->bus.ops->mo_put_by_id(&sys->bus,
|
||
|
sys->bus.max_scen_id);
|
||
|
sys->pm.ops->boost_disable(&sys->pm);
|
||
|
sys->boost = false;
|
||
|
}
|
||
|
mutex_unlock(&sys->boost_lock);
|
||
|
break;
|
||
|
case DSP_CONTROL_REQUEST_MO:
|
||
|
ret = sys->bus.ops->mo_get_by_name(&sys->bus,
|
||
|
cmd->mo.scenario_name);
|
||
|
if (ret)
|
||
|
goto p_err;
|
||
|
break;
|
||
|
case DSP_CONTROL_RELEASE_MO:
|
||
|
sys->bus.ops->mo_put_by_name(&sys->bus, cmd->mo.scenario_name);
|
||
|
break;
|
||
|
case DSP_CONTROL_REQUEST_PRESET:
|
||
|
sys->governor.ops->request(&sys->governor, &cmd->preset);
|
||
|
break;
|
||
|
default:
|
||
|
ret = -EINVAL;
|
||
|
dsp_err("control cmd id is invalid(%u)\n", id);
|
||
|
goto p_err;
|
||
|
}
|
||
|
dsp_leave();
|
||
|
return 0;
|
||
|
p_err:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static int __dsp_hw_common_system_wait_task(struct dsp_system *sys,
|
||
|
struct dsp_task *task)
|
||
|
{
|
||
|
int ret;
|
||
|
unsigned int wait_time;
|
||
|
long timeout;
|
||
|
|
||
|
dsp_enter();
|
||
|
wait_time = sys->wait[DSP_SYSTEM_WAIT_MAILBOX];
|
||
|
#ifndef ENABLE_DSP_VELOCE
|
||
|
dsp_dbg("wait mode : %u / task : %u/%u\n",
|
||
|
sys->wait_mode, task->id, task->message_id);
|
||
|
if (sys->wait_mode == DSP_SYSTEM_WAIT_MODE_INTERRUPT) {
|
||
|
timeout = dsp_task_manager_wait_done(task,
|
||
|
msecs_to_jiffies(wait_time));
|
||
|
if (!timeout) {
|
||
|
sys->interface.ops->check_irq(&sys->interface);
|
||
|
if (task->state == DSP_TASK_STATE_COMPLETE) {
|
||
|
timeout = 1;
|
||
|
dsp_warn("interrupt was unstable\n");
|
||
|
}
|
||
|
}
|
||
|
} else if (sys->wait_mode == DSP_SYSTEM_WAIT_MODE_BUSY_WAITING) {
|
||
|
timeout = wait_time * 1000;
|
||
|
|
||
|
while (timeout) {
|
||
|
if (task->state == DSP_TASK_STATE_COMPLETE)
|
||
|
break;
|
||
|
|
||
|
sys->interface.ops->check_irq(&sys->interface);
|
||
|
timeout -= 10;
|
||
|
udelay(10);
|
||
|
}
|
||
|
} else {
|
||
|
ret = -EINVAL;
|
||
|
dsp_err("wait mode(%u) is invalid\n", sys->wait_mode);
|
||
|
goto p_err;
|
||
|
}
|
||
|
#else
|
||
|
while (1) {
|
||
|
if (task->state == DSP_TASK_STATE_COMPLETE)
|
||
|
break;
|
||
|
|
||
|
dsp_ctrl_pc_dump();
|
||
|
dsp_ctrl_userdefined_dump();
|
||
|
mdelay(100);
|
||
|
}
|
||
|
timeout = 1;
|
||
|
#endif
|
||
|
if (!timeout) {
|
||
|
ret = -ETIMEDOUT;
|
||
|
dsp_err("task wait time(%ums) is expired(%u/%u)\n",
|
||
|
sys->wait[DSP_SYSTEM_WAIT_MAILBOX],
|
||
|
task->id, task->message_id);
|
||
|
if (sys->timeout_handler) {
|
||
|
sys->timeout_handler(sys, DSP_SYSTEM_WAIT_MAILBOX);
|
||
|
} else {
|
||
|
dsp_warn("timeout handler was not registered\n");
|
||
|
dsp_dump_ctrl();
|
||
|
dsp_dump_task_count();
|
||
|
}
|
||
|
goto p_err;
|
||
|
}
|
||
|
|
||
|
dsp_leave();
|
||
|
return 0;
|
||
|
p_err:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static void __dsp_hw_common_system_flush(struct dsp_system *sys)
|
||
|
{
|
||
|
unsigned long flags;
|
||
|
|
||
|
dsp_enter();
|
||
|
dsp_task_manager_lock(&flags);
|
||
|
dsp_task_manager_set_block_mode(true);
|
||
|
dsp_task_manager_flush_process(-ENOSTR);
|
||
|
dsp_task_manager_unlock(flags);
|
||
|
|
||
|
sys->ops->reset(sys);
|
||
|
dsp_leave();
|
||
|
}
|
||
|
|
||
|
static void __dsp_hw_common_system_recovery(struct dsp_system *sys)
|
||
|
{
|
||
|
int ret;
|
||
|
unsigned long flags;
|
||
|
|
||
|
dsp_enter();
|
||
|
ret = sys->ops->boot(sys);
|
||
|
if (ret) {
|
||
|
dsp_err("Failed to recovery device\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
dsp_graph_manager_recovery(&sys->dspdev->core.graph_manager);
|
||
|
|
||
|
dsp_task_manager_lock(&flags);
|
||
|
dsp_task_manager_set_block_mode(false);
|
||
|
dsp_task_manager_unlock(flags);
|
||
|
dsp_leave();
|
||
|
}
|
||
|
|
||
|
int dsp_hw_common_system_execute_task(struct dsp_system *sys,
|
||
|
struct dsp_task *task)
|
||
|
{
|
||
|
int ret;
|
||
|
struct dsp_mailbox_pool *pool;
|
||
|
|
||
|
dsp_enter();
|
||
|
pool = task->pool;
|
||
|
|
||
|
if (task->message_id == DSP_COMMON_EXECUTE_MSG)
|
||
|
sys->governor.ops->check_done(&sys->governor);
|
||
|
|
||
|
sys->pm.ops->update_devfreq_busy(&sys->pm, pool->pm_qos);
|
||
|
ret = sys->mailbox.ops->send_task(&sys->mailbox, task);
|
||
|
if (ret)
|
||
|
goto p_err;
|
||
|
|
||
|
dsp_dump_mailbox_pool_debug(pool);
|
||
|
|
||
|
/* TODO Devfreq change criteria required if not waiting */
|
||
|
if (task->wait) {
|
||
|
ret = __dsp_hw_common_system_wait_task(sys, task);
|
||
|
if (ret) {
|
||
|
if (task->recovery) {
|
||
|
__dsp_hw_common_system_flush(sys);
|
||
|
__dsp_hw_common_system_recovery(sys);
|
||
|
}
|
||
|
goto p_err;
|
||
|
}
|
||
|
|
||
|
if (task->result) {
|
||
|
ret = task->result;
|
||
|
dsp_err("task result is failure(%d/%u/%u)\n",
|
||
|
ret, task->id, task->message_id);
|
||
|
goto p_err;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sys->pm.ops->update_devfreq_idle(&sys->pm, pool->pm_qos);
|
||
|
task->owner->normal_count++;
|
||
|
dsp_leave();
|
||
|
return 0;
|
||
|
p_err:
|
||
|
sys->pm.ops->update_devfreq_idle(&sys->pm, pool->pm_qos);
|
||
|
task->owner->error_count++;
|
||
|
dsp_dump_mailbox_pool_error(pool);
|
||
|
dsp_dump_task_count();
|
||
|
dsp_dump_kernel();
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
void dsp_hw_common_system_iovmm_fault_dump(struct dsp_system *sys)
|
||
|
{
|
||
|
dsp_enter();
|
||
|
dsp_dump_ctrl();
|
||
|
dsp_dump_task_count();
|
||
|
dsp_dump_kernel();
|
||
|
dsp_leave();
|
||
|
}
|
||
|
|
||
|
int dsp_hw_common_system_power_active(struct dsp_system *sys)
|
||
|
{
|
||
|
dsp_check();
|
||
|
return sys->pm.ops->devfreq_active(&sys->pm);
|
||
|
}
|
||
|
|
||
|
int dsp_hw_common_system_set_boot_qos(struct dsp_system *sys, int val)
|
||
|
{
|
||
|
int ret;
|
||
|
|
||
|
dsp_enter();
|
||
|
ret = sys->pm.ops->set_boot_qos(&sys->pm, val);
|
||
|
if (ret)
|
||
|
goto p_err;
|
||
|
dsp_leave();
|
||
|
return 0;
|
||
|
p_err:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
int dsp_hw_common_system_runtime_resume(struct dsp_system *sys)
|
||
|
{
|
||
|
int ret;
|
||
|
|
||
|
dsp_enter();
|
||
|
ret = sys->pm.ops->enable(&sys->pm);
|
||
|
if (ret)
|
||
|
goto p_err_pm;
|
||
|
|
||
|
ret = sys->clk.ops->enable(&sys->clk);
|
||
|
if (ret)
|
||
|
goto p_err_clk;
|
||
|
|
||
|
sys->sysevent.ops->get(&sys->sysevent);
|
||
|
|
||
|
dsp_leave();
|
||
|
return 0;
|
||
|
p_err_clk:
|
||
|
sys->pm.ops->disable(&sys->pm);
|
||
|
p_err_pm:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
int dsp_hw_common_system_runtime_suspend(struct dsp_system *sys)
|
||
|
{
|
||
|
dsp_enter();
|
||
|
sys->sysevent.ops->put(&sys->sysevent);
|
||
|
sys->governor.ops->flush_work(&sys->governor);
|
||
|
sys->clk.ops->disable(&sys->clk);
|
||
|
sys->pm.ops->disable(&sys->pm);
|
||
|
dsp_leave();
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int dsp_hw_common_system_resume(struct dsp_system *sys)
|
||
|
{
|
||
|
dsp_enter();
|
||
|
__dsp_hw_common_system_recovery(sys);
|
||
|
dsp_leave();
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int dsp_hw_common_system_suspend(struct dsp_system *sys)
|
||
|
{
|
||
|
dsp_enter();
|
||
|
__dsp_hw_common_system_flush(sys);
|
||
|
dsp_leave();
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int dsp_hw_common_system_npu_start(struct dsp_system *sys, bool boot,
|
||
|
dma_addr_t fw_iova)
|
||
|
{
|
||
|
dsp_enter();
|
||
|
dsp_leave();
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int dsp_hw_common_system_start(struct dsp_system *sys)
|
||
|
{
|
||
|
int ret;
|
||
|
unsigned long flags;
|
||
|
|
||
|
dsp_enter();
|
||
|
ret = sys->interface.ops->start(&sys->interface);
|
||
|
if (ret)
|
||
|
goto p_err_interface;
|
||
|
|
||
|
dsp_task_manager_lock(&flags);
|
||
|
dsp_task_manager_set_block_mode(false);
|
||
|
dsp_task_manager_unlock(flags);
|
||
|
|
||
|
dsp_leave();
|
||
|
return 0;
|
||
|
p_err_interface:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
int dsp_hw_common_system_stop(struct dsp_system *sys)
|
||
|
{
|
||
|
dsp_enter();
|
||
|
sys->interface.ops->stop(&sys->interface);
|
||
|
dsp_leave();
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int dsp_hw_common_system_open(struct dsp_system *sys)
|
||
|
{
|
||
|
int ret;
|
||
|
|
||
|
dsp_enter();
|
||
|
ret = sys->pm.ops->open(&sys->pm);
|
||
|
if (ret)
|
||
|
goto p_err_pm;
|
||
|
|
||
|
ret = sys->clk.ops->open(&sys->clk);
|
||
|
if (ret)
|
||
|
goto p_err_clk;
|
||
|
|
||
|
ret = sys->bus.ops->open(&sys->bus);
|
||
|
if (ret)
|
||
|
goto p_err_bus;
|
||
|
|
||
|
ret = sys->llc.ops->open(&sys->llc);
|
||
|
if (ret)
|
||
|
goto p_err_llc;
|
||
|
|
||
|
ret = sys->memory.ops->open(&sys->memory);
|
||
|
if (ret)
|
||
|
goto p_err_memory;
|
||
|
|
||
|
ret = sys->interface.ops->open(&sys->interface);
|
||
|
if (ret)
|
||
|
goto p_err_interface;
|
||
|
|
||
|
ret = sys->ctrl.ops->open(&sys->ctrl);
|
||
|
if (ret)
|
||
|
goto p_err_ctrl;
|
||
|
|
||
|
ret = sys->mailbox.ops->open(&sys->mailbox);
|
||
|
if (ret)
|
||
|
goto p_err_mbox;
|
||
|
|
||
|
ret = sys->governor.ops->open(&sys->governor);
|
||
|
if (ret)
|
||
|
goto p_err_governor;
|
||
|
|
||
|
dsp_leave();
|
||
|
return 0;
|
||
|
p_err_governor:
|
||
|
sys->mailbox.ops->close(&sys->mailbox);
|
||
|
p_err_mbox:
|
||
|
sys->ctrl.ops->close(&sys->ctrl);
|
||
|
p_err_ctrl:
|
||
|
sys->interface.ops->close(&sys->interface);
|
||
|
p_err_interface:
|
||
|
sys->memory.ops->close(&sys->memory);
|
||
|
p_err_memory:
|
||
|
sys->llc.ops->close(&sys->llc);
|
||
|
p_err_llc:
|
||
|
sys->bus.ops->close(&sys->bus);
|
||
|
p_err_bus:
|
||
|
sys->clk.ops->close(&sys->clk);
|
||
|
p_err_clk:
|
||
|
sys->pm.ops->close(&sys->pm);
|
||
|
p_err_pm:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
int dsp_hw_common_system_close(struct dsp_system *sys)
|
||
|
{
|
||
|
dsp_enter();
|
||
|
sys->governor.ops->close(&sys->governor);
|
||
|
sys->mailbox.ops->close(&sys->mailbox);
|
||
|
sys->ctrl.ops->close(&sys->ctrl);
|
||
|
sys->interface.ops->close(&sys->interface);
|
||
|
sys->memory.ops->close(&sys->memory);
|
||
|
sys->llc.ops->close(&sys->llc);
|
||
|
sys->bus.ops->close(&sys->bus);
|
||
|
sys->clk.ops->close(&sys->clk);
|
||
|
sys->pm.ops->close(&sys->pm);
|
||
|
dsp_leave();
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int dsp_hw_common_system_probe(struct dsp_system *sys, void *dspdev,
|
||
|
timeout_handler_t handler)
|
||
|
{
|
||
|
int ret;
|
||
|
struct platform_device *pdev;
|
||
|
struct resource *res;
|
||
|
void __iomem *regs;
|
||
|
|
||
|
dsp_enter();
|
||
|
sys->dspdev = dspdev;
|
||
|
sys->dev = sys->dspdev->dev;
|
||
|
pdev = to_platform_device(sys->dev);
|
||
|
|
||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||
|
if (!res) {
|
||
|
ret = -EINVAL;
|
||
|
dsp_err("Failed to get resource0\n");
|
||
|
goto p_err_resource0;
|
||
|
}
|
||
|
|
||
|
regs = devm_ioremap_resource(sys->dev, res);
|
||
|
if (IS_ERR(regs)) {
|
||
|
ret = PTR_ERR(regs);
|
||
|
dsp_err("Failed to remap resource0(%d)\n", ret);
|
||
|
goto p_err_ioremap0;
|
||
|
}
|
||
|
|
||
|
sys->sfr_pa = res->start;
|
||
|
sys->sfr = regs;
|
||
|
sys->sfr_size = resource_size(res);
|
||
|
|
||
|
regs = devm_ioremap(sys->dev, 0x10000000, 0x4);
|
||
|
if (IS_ERR(regs)) {
|
||
|
ret = PTR_ERR(regs);
|
||
|
dsp_err("Failed to remap product_id(%d)\n", ret);
|
||
|
goto p_err_product_id;
|
||
|
}
|
||
|
sys->product_id = regs;
|
||
|
|
||
|
/*
|
||
|
* CHIPID_REV[31:24] Reserved
|
||
|
* CHIPID_REV[23:20] Main revision
|
||
|
* CHIPID_REV[19:16] Sub revision
|
||
|
* CHIPID_REV[15:0] Reserved
|
||
|
*/
|
||
|
regs = devm_ioremap(sys->dev, 0x10000010, 0x4);
|
||
|
if (IS_ERR(regs)) {
|
||
|
ret = PTR_ERR(regs);
|
||
|
dsp_err("Failed to remap chip_id(%d)\n", ret);
|
||
|
goto p_err_chipid;
|
||
|
}
|
||
|
sys->chip_id = regs;
|
||
|
|
||
|
init_waitqueue_head(&sys->system_wq);
|
||
|
|
||
|
sys->wait[DSP_SYSTEM_WAIT_BOOT] = DSP_WAIT_BOOT_TIME;
|
||
|
sys->wait[DSP_SYSTEM_WAIT_MAILBOX] = DSP_WAIT_MAILBOX_TIME;
|
||
|
sys->wait[DSP_SYSTEM_WAIT_RESET] = DSP_WAIT_RESET_TIME;
|
||
|
sys->wait_mode = DSP_SYSTEM_WAIT_MODE_INTERRUPT;
|
||
|
sys->boost = false;
|
||
|
mutex_init(&sys->boost_lock);
|
||
|
|
||
|
sys->layer_start = DSP_SET_DEFAULT_LAYER;
|
||
|
sys->layer_end = DSP_SET_DEFAULT_LAYER;
|
||
|
|
||
|
ret = sys->pm.ops->probe(&sys->pm, sys);
|
||
|
if (ret)
|
||
|
goto p_err_pm;
|
||
|
|
||
|
ret = sys->clk.ops->probe(&sys->clk, sys);
|
||
|
if (ret)
|
||
|
goto p_err_clk;
|
||
|
|
||
|
ret = sys->bus.ops->probe(&sys->bus, sys);
|
||
|
if (ret)
|
||
|
goto p_err_bus;
|
||
|
|
||
|
ret = sys->llc.ops->probe(&sys->llc, sys);
|
||
|
if (ret)
|
||
|
goto p_err_llc;
|
||
|
|
||
|
ret = sys->memory.ops->probe(&sys->memory, sys);
|
||
|
if (ret)
|
||
|
goto p_err_memory;
|
||
|
|
||
|
ret = sys->interface.ops->probe(&sys->interface, sys);
|
||
|
if (ret)
|
||
|
goto p_err_interface;
|
||
|
|
||
|
ret = sys->ctrl.ops->probe(&sys->ctrl, sys);
|
||
|
if (ret)
|
||
|
goto p_err_ctrl;
|
||
|
|
||
|
ret = sys->mailbox.ops->probe(&sys->mailbox, sys);
|
||
|
if (ret)
|
||
|
goto p_err_mbox;
|
||
|
|
||
|
ret = sys->governor.ops->probe(&sys->governor, sys);
|
||
|
if (ret)
|
||
|
goto p_err_governor;
|
||
|
|
||
|
ret = sys->imgloader.ops->probe(&sys->imgloader, sys);
|
||
|
if (ret)
|
||
|
goto p_err_imgloader;
|
||
|
|
||
|
ret = sys->sysevent.ops->probe(&sys->sysevent, sys);
|
||
|
if (ret)
|
||
|
goto p_err_sysevent;
|
||
|
|
||
|
ret = sys->memlogger.ops->probe(&sys->memlogger, sys);
|
||
|
if (ret)
|
||
|
goto p_err_memlogger;
|
||
|
|
||
|
ret = sys->log.ops->probe(&sys->log, sys);
|
||
|
if (ret)
|
||
|
goto p_err_log;
|
||
|
|
||
|
ret = sys->dump.ops->probe(&sys->dump, sys);
|
||
|
if (ret)
|
||
|
goto p_err_dump;
|
||
|
|
||
|
if (handler)
|
||
|
sys->timeout_handler = handler;
|
||
|
|
||
|
dsp_leave();
|
||
|
return 0;
|
||
|
p_err_dump:
|
||
|
sys->log.ops->remove(&sys->log);
|
||
|
p_err_log:
|
||
|
sys->memlogger.ops->remove(&sys->memlogger);
|
||
|
p_err_memlogger:
|
||
|
sys->sysevent.ops->remove(&sys->sysevent);
|
||
|
p_err_sysevent:
|
||
|
sys->imgloader.ops->remove(&sys->imgloader);
|
||
|
p_err_imgloader:
|
||
|
sys->governor.ops->remove(&sys->governor);
|
||
|
p_err_governor:
|
||
|
sys->mailbox.ops->remove(&sys->mailbox);
|
||
|
p_err_mbox:
|
||
|
sys->ctrl.ops->remove(&sys->ctrl);
|
||
|
p_err_ctrl:
|
||
|
sys->interface.ops->remove(&sys->interface);
|
||
|
p_err_interface:
|
||
|
sys->memory.ops->remove(&sys->memory);
|
||
|
p_err_memory:
|
||
|
sys->llc.ops->remove(&sys->llc);
|
||
|
p_err_llc:
|
||
|
sys->bus.ops->remove(&sys->bus);
|
||
|
p_err_bus:
|
||
|
sys->clk.ops->remove(&sys->clk);
|
||
|
p_err_clk:
|
||
|
sys->pm.ops->remove(&sys->pm);
|
||
|
p_err_pm:
|
||
|
devm_iounmap(sys->dev, sys->chip_id);
|
||
|
p_err_chipid:
|
||
|
devm_iounmap(sys->dev, sys->product_id);
|
||
|
p_err_product_id:
|
||
|
devm_iounmap(sys->dev, sys->sfr);
|
||
|
p_err_ioremap0:
|
||
|
p_err_resource0:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
void dsp_hw_common_system_remove(struct dsp_system *sys)
|
||
|
{
|
||
|
dsp_enter();
|
||
|
sys->dump.ops->remove(&sys->dump);
|
||
|
sys->log.ops->remove(&sys->log);
|
||
|
sys->memlogger.ops->remove(&sys->memlogger);
|
||
|
sys->sysevent.ops->remove(&sys->sysevent);
|
||
|
sys->imgloader.ops->remove(&sys->imgloader);
|
||
|
sys->governor.ops->remove(&sys->governor);
|
||
|
sys->mailbox.ops->remove(&sys->mailbox);
|
||
|
sys->ctrl.ops->remove(&sys->ctrl);
|
||
|
sys->interface.ops->remove(&sys->interface);
|
||
|
sys->memory.ops->remove(&sys->memory);
|
||
|
sys->llc.ops->remove(&sys->llc);
|
||
|
sys->bus.ops->remove(&sys->bus);
|
||
|
sys->clk.ops->remove(&sys->clk);
|
||
|
sys->pm.ops->remove(&sys->pm);
|
||
|
devm_iounmap(sys->dev, sys->chip_id);
|
||
|
devm_iounmap(sys->dev, sys->product_id);
|
||
|
devm_iounmap(sys->dev, sys->sfr);
|
||
|
dsp_leave();
|
||
|
}
|
||
|
|
||
|
int dsp_hw_common_system_set_ops(struct dsp_system *sys, const void *ops)
|
||
|
{
|
||
|
dsp_enter();
|
||
|
sys->ops = ops;
|
||
|
dsp_leave();
|
||
|
return 0;
|
||
|
}
|