/**************************************************************************** * * The MIT License (MIT) * * Copyright (c) 2020 VeriSilicon Holdings Co., Ltd. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * ***************************************************************************** * * The GPL License (GPL) * * Copyright (c) 2020 VeriSilicon Holdings Co., Ltd. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; * ***************************************************************************** * * Note: This software is released under dual MIT and GPL licenses. A * recipient may use this file under the terms of either the MIT license or * GPL License. If you wish to use only one license not the other, you can * indicate your decision by deleting one of the above license notices in your * version of this file. * *****************************************************************************/ #include "dwe_driver.h" #include "dwe_ioctl.h" LIST_HEAD(devcore_list); static DEFINE_SPINLOCK(devcore_list_lock); long dwe_devcore_ioctl(struct dwe_device *dwe, unsigned int cmd, void *args) { struct dwe_ic_dev *dev = &dwe->core->ic_dev; int which; long ret = 0; switch (cmd) { case DWEIOC_RESET: break; case DWEIOC_S_PARAMS: which = dev->which[dwe->id]; /*just set the current one*/ viv_check_retval(copy_from_user(&dev->info[dwe->id][which], args, sizeof(dev->info[dwe->id][which]))); break; case DWEIOC_START: if (dwe->state & STATE_DRIVER_STARTED) break; mutex_lock(&dwe->core->mutex); if (dwe->core->state == 0) { ret = dwe_priv_ioctl(&dwe->core->ic_dev, DWEIOC_RESET, NULL); ret |= dwe_priv_ioctl(&dwe->core->ic_dev, cmd, args); } dwe->core->state++; mutex_unlock(&dwe->core->mutex); dwe->state |= STATE_DRIVER_STARTED; break; case DWEIOC_STOP: if (!(dwe->state & STATE_DRIVER_STARTED)) break; dwe->state &= ~STATE_DRIVER_STARTED; mutex_lock(&dwe->core->mutex); dwe->core->state--; if (dwe->core->state == 0) ret = dwe_priv_ioctl(&dwe->core->ic_dev, cmd, args); mutex_unlock(&dwe->core->mutex); break; case DWEIOC_SET_LUT: { struct lut_info info; viv_check_retval(copy_from_user(&info, args, sizeof(info))); if (info.port < MAX_CFG_NUM) dev->dist_map[dwe->id][info.port] = info.addr; else pr_err("map num exceeds the max cfg num.\n"); break; } case VIDIOC_QUERYCAP: { struct v4l2_capability *cap = (struct v4l2_capability *)args; strcpy((char *)cap->driver, "viv_dewarp100"); cap->bus_info[0] = (__u8)dwe->id; break; } default: return dwe_priv_ioctl(&dwe->core->ic_dev, cmd, args); } return ret; } static int dwe_core_match(struct dwe_devcore *core, struct resource *res) { return core && res && core->start == res->start && core->end == res->end; } static int dwe_core_get_index(struct dwe_ic_dev *dev, struct vb2_dc_buf *buf) { struct dwe_devcore *core = container_of(dev, struct dwe_devcore, ic_dev); int i; for (i = 0; i < MAX_DWE_NUM; ++i) if (core->src_pads[i] == buf->pad) return i; return -1; } struct dwe_devcore *dwe_devcore_init(struct dwe_device *dwe, struct resource *res) { struct dwe_devcore *core, *found = NULL; unsigned long flags; int rc; spin_lock_irqsave(&devcore_list_lock, flags); if (!list_empty(&devcore_list)) { list_for_each_entry(core, &devcore_list, entry) { if (core->match && core->match(core, res)) { found = core; break; } } } spin_unlock_irqrestore(&devcore_list_lock, flags); if (found) { found->src_pads[dwe->id] = &dwe->pads[DWE_PAD_SINK]; found->ic_dev.src_bctx[dwe->id] = &dwe->bctx[DWE_PAD_SOURCE]; found->ic_dev.state[dwe->id] = &dwe->state; refcount_inc(&found->refcount); return found; } core = kzalloc(sizeof(struct dwe_devcore), GFP_KERNEL); if (!core) return NULL; core->ic_dev.base = devm_ioremap_resource(dwe->sd.dev, res); if (IS_ERR(core->ic_dev.base)) { pr_err("failed to get ioremap resource.\n"); goto end; } core->start = res->start; core->end = res->end; #ifdef DWE_REG_RESET core->ic_dev.reset = ioremap(DWE_REG_RESET, 4); #endif pr_debug("dwe ioremap addr: %llx\n", (u64)core->ic_dev.base); vvbuf_ctx_init(&core->bctx[DWE_PAD_SINK]); core->ic_dev.sink_bctx = &core->bctx[DWE_PAD_SINK]; core->irq = dwe->irq; pr_debug("request_irq num:%d, rc:%d\n", dwe->irq, rc); spin_lock_init(&core->ic_dev.irqlock); core->match = dwe_core_match; core->src_pads[dwe->id] = &dwe->pads[DWE_PAD_SINK]; core->ic_dev.src_bctx[dwe->id] = &dwe->bctx[DWE_PAD_SOURCE]; core->ic_dev.state[dwe->id] = &dwe->state; core->ic_dev.get_index = dwe_core_get_index; mutex_init(&core->mutex); refcount_set(&core->refcount, 1); spin_lock_irqsave(&devcore_list_lock, flags); list_add_tail(&core->entry, &devcore_list); spin_unlock_irqrestore(&devcore_list_lock, flags); return core; end: kfree(core); return NULL; } void dwe_devcore_deinit(struct dwe_device *dwe) { struct dwe_devcore *core = dwe->core; unsigned long flags; if (!core) return; if (refcount_dec_and_test(&core->refcount)) { spin_lock_irqsave(&devcore_list_lock, flags); list_del(&core->entry); spin_unlock_irqrestore(&devcore_list_lock, flags); vvbuf_ctx_deinit(&core->bctx[DWE_PAD_SINK]); #ifdef DWE_REG_RESET iounmap(core->ic_dev.reset); #endif mutex_destroy(&core->mutex); kfree(core); } }