1
0
mirror of https://github.com/physwizz/a155-U-u1.git synced 2024-11-19 13:27:49 +00:00
a155-U-u1/kernel-5.10/drivers/misc/mediatek/jpeg/jpeg_drv.c
2024-03-11 06:53:12 +11:00

1054 lines
27 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2021 MediaTek Inc.
*/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/wait.h>
#include <linux/proc_fs.h>
#include <linux/io.h>
#include <linux/suspend.h>
#include <linux/timer.h>
#include <soc/mediatek/smi.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/pm_qos.h>
#include <linux/pm_runtime.h>
#include "jpeg_drv.h"
#include "jpeg_drv_reg.h"
#define JPEG_DEVNAME "mtk_jpeg"
#define JPEG_DEC_PROCESS 0x1
static struct JpegDeviceStruct gJpegqDev;
static atomic_t nodeCount;
static const struct of_device_id jdec_hybrid_of_ids[] = {
{.compatible = "mediatek,jpgdec0",},
{.compatible = "mediatek,jpgdec1",},
{}
};
/* hybrid decoder */
static wait_queue_head_t hybrid_dec_wait_queue[HW_CORE_NUMBER];
static DEFINE_MUTEX(jpeg_hybrid_dec_lock);
static bool dec_hwlocked[HW_CORE_NUMBER] = {false, false/*, false*/};
static unsigned int _jpeg_hybrid_dec_int_status[HW_CORE_NUMBER];
static struct dmabuf_info bufInfo[HW_CORE_NUMBER];
int jpg_dbg_level;
module_param(jpg_dbg_level, int, 0644);
static int jpeg_isr_hybrid_dec_lisr(int id)
{
unsigned int tmp = 0;
tmp = IMG_REG_READ(REG_JPGDEC_HYBRID_274(id));
if (tmp) {
_jpeg_hybrid_dec_int_status[id] = tmp;
IMG_REG_WRITE(tmp, REG_JPGDEC_HYBRID_274(id));
JPEG_LOG(1, "return 0");
return 0;
}
JPEG_LOG(1, "return -1");
return -1;
}
static int jpeg_drv_hybrid_dec_start(unsigned int data[],
unsigned int id,
int *index_buf_fd)
{
u64 ibuf_iova, obuf_iova;
int ret;
void *ptr;
unsigned int node_id;
JPEG_LOG(1, "+ id:%d", id);
ret = 0;
ibuf_iova = 0;
obuf_iova = 0;
node_id = id / 2;
bufInfo[id].o_dbuf = jpg_dmabuf_alloc(data[20], 128, 0);
bufInfo[id].o_attach = NULL;
bufInfo[id].o_sgt = NULL;
bufInfo[id].i_dbuf = jpg_dmabuf_get(data[7]);
bufInfo[id].i_attach = NULL;
bufInfo[id].i_sgt = NULL;
if (!bufInfo[id].o_dbuf) {
JPEG_LOG(0, "o_dbuf alloc failed");
return -1;
}
if (!bufInfo[id].i_dbuf) {
JPEG_LOG(0, "i_dbuf null error");
return -1;
}
ret = jpg_dmabuf_get_iova(bufInfo[id].o_dbuf, &obuf_iova, gJpegqDev.pDev[node_id], &bufInfo[id].o_attach, &bufInfo[id].o_sgt);
JPEG_LOG(1, "obuf_iova:0x%llx lsb:0x%lx msb:0x%lx", obuf_iova,
(unsigned long)(unsigned char*)obuf_iova,
(unsigned long)(unsigned char*)(obuf_iova>>32));
ptr = jpg_dmabuf_vmap(bufInfo[id].o_dbuf);
if (ptr != NULL && data[20] > 0)
memset(ptr, 0, data[20]);
jpg_dmabuf_vunmap(bufInfo[id].o_dbuf, ptr);
jpg_get_dmabuf(bufInfo[id].o_dbuf);
// get obuf for adding reference count, avoid early release in userspace.
*index_buf_fd = jpg_dmabuf_fd(bufInfo[id].o_dbuf);
ret = jpg_dmabuf_get_iova(bufInfo[id].i_dbuf, &ibuf_iova, gJpegqDev.pDev[node_id], &bufInfo[id].i_attach, &bufInfo[id].i_sgt);
JPEG_LOG(1, "ibuf_iova 0x%llx lsb:0x%lx msb:0x%lx", ibuf_iova,
(unsigned long)(unsigned char*)ibuf_iova,
(unsigned long)(unsigned char*)(ibuf_iova>>32));
if (ret != 0) {
JPEG_LOG(0, "get iova fail i:0x%llx o:0x%llx", ibuf_iova, obuf_iova);
return ret;
}
IMG_REG_WRITE(data[0], REG_JPGDEC_HYBRID_090(id));
IMG_REG_WRITE(data[1], REG_JPGDEC_HYBRID_090(id));
IMG_REG_WRITE(data[2], REG_JPGDEC_HYBRID_0FC(id));
IMG_REG_WRITE(data[3], REG_JPGDEC_HYBRID_14C(id));
IMG_REG_WRITE(data[4], REG_JPGDEC_HYBRID_150(id));
IMG_REG_WRITE(data[5], REG_JPGDEC_HYBRID_154(id));
IMG_REG_WRITE(data[6], REG_JPGDEC_HYBRID_17C(id));
IMG_REG_WRITE((unsigned long)(unsigned char*)ibuf_iova, REG_JPGDEC_HYBRID_200(id));
IMG_REG_WRITE((unsigned long)(unsigned char*)(ibuf_iova>>32), REG_JPGDEC_HYBRID_378(id));
IMG_REG_WRITE(data[8], REG_JPGDEC_HYBRID_20C(id));
IMG_REG_WRITE(data[9], REG_JPGDEC_HYBRID_210(id));
IMG_REG_WRITE(data[10], REG_JPGDEC_HYBRID_224(id));
IMG_REG_WRITE(data[11], REG_JPGDEC_HYBRID_23C(id));
IMG_REG_WRITE(data[12], REG_JPGDEC_HYBRID_24C(id));
IMG_REG_WRITE(data[13], REG_JPGDEC_HYBRID_270(id));
IMG_REG_WRITE(data[14], REG_JPGDEC_HYBRID_31C(id));
IMG_REG_WRITE(data[15], REG_JPGDEC_HYBRID_330(id));
IMG_REG_WRITE(data[16], REG_JPGDEC_HYBRID_334(id));
IMG_REG_WRITE((unsigned long)(unsigned char*)obuf_iova, REG_JPGDEC_HYBRID_338(id));
IMG_REG_WRITE((unsigned long)(unsigned char*)(obuf_iova>>32), REG_JPGDEC_HYBRID_384(id));
IMG_REG_WRITE((unsigned long)(unsigned char*)obuf_iova, REG_JPGDEC_HYBRID_36C(id));
IMG_REG_WRITE((unsigned long)(unsigned char*)obuf_iova + data[20], REG_JPGDEC_HYBRID_370(id));
IMG_REG_WRITE((unsigned long)(unsigned char*)obuf_iova + data[20]*2, REG_JPGDEC_HYBRID_374(id));
IMG_REG_WRITE(data[17], REG_JPGDEC_HYBRID_33C(id));
IMG_REG_WRITE(data[18], REG_JPGDEC_HYBRID_344(id));
IMG_REG_WRITE(data[19], REG_JPGDEC_HYBRID_240(id));
JPEG_LOG(1, "-");
return ret;
}
static void jpeg_drv_hybrid_dec_get_p_n_s(
unsigned int id,
int *progress_n_status)
{
int progress, status;
progress = IMG_REG_READ(REG_JPGDEC_HYBRID_340(id)) - 1;
status = IMG_REG_READ(REG_JPGDEC_HYBRID_348(id));
*progress_n_status = progress << 4 | status;
JPEG_LOG(1, "progress_n_status %d", *progress_n_status);
}
static irqreturn_t jpeg_drv_hybrid_dec_isr(int irq, void *dev_id)
{
int ret = 0;
int i;
JPEG_LOG(1, "JPEG Hybrid Decoder Interrupt %d", irq);
for (i = 0 ; i < HW_CORE_NUMBER; i++) {
if (irq == gJpegqDev.hybriddecIrqId[i]) {
if (!dec_hwlocked[i]) {
JPEG_LOG(0, "JPEG isr from unlocked HW %d",
i);
return IRQ_HANDLED;
}
ret = jpeg_isr_hybrid_dec_lisr(i);
if (ret == 0)
wake_up_interruptible(
&(hybrid_dec_wait_queue[i]));
JPEG_LOG(1, "JPEG Hybrid Dec clear Interrupt %d ret %d"
, irq, ret);
break;
}
}
return IRQ_HANDLED;
}
void jpeg_drv_hybrid_dec_prepare_dvfs(unsigned int id)
{
int ret;
struct dev_pm_opp *opp = 0;
unsigned long freq = 0;
int i = 0;
ret = dev_pm_opp_of_add_table(gJpegqDev.pDev[id]);
if (ret < 0) {
JPEG_LOG(0, "Failed to get opp table (%d)", ret);
return;
}
gJpegqDev.jpeg_reg[id] = devm_regulator_get(gJpegqDev.pDev[id],
"dvfsrc-vcore");
if (gJpegqDev.jpeg_reg[id] == 0) {
JPEG_LOG(0, "Failed to get regulator");
return;
}
gJpegqDev.jpeg_freq_cnt[id] = dev_pm_opp_get_opp_count(gJpegqDev.pDev[id]);
freq = 0;
while (!IS_ERR(opp =
dev_pm_opp_find_freq_ceil(gJpegqDev.pDev[id], &freq))) {
gJpegqDev.jpeg_freqs[id][i] = freq;
freq++;
i++;
dev_pm_opp_put(opp);
}
}
void jpeg_drv_hybrid_dec_unprepare_dvfs(void)
{
}
void jpeg_drv_hybrid_dec_start_dvfs(unsigned int id)
{
struct dev_pm_opp *opp = 0;
int volt = 0;
int ret = 0;
if (gJpegqDev.jpeg_reg[id] != 0) {
JPEG_LOG(1, "request freq %lu",
gJpegqDev.jpeg_freqs[id][gJpegqDev.jpeg_freq_cnt[id]-1]);
opp = dev_pm_opp_find_freq_ceil(gJpegqDev.pDev[id],
&gJpegqDev.jpeg_freqs[id][gJpegqDev.jpeg_freq_cnt[id]-1]);
volt = dev_pm_opp_get_voltage(opp);
dev_pm_opp_put(opp);
ret = regulator_set_voltage(gJpegqDev.jpeg_reg[id], volt, INT_MAX);
if (ret) {
JPEG_LOG(0 ,"Failed to set regulator voltage %d",
volt);
}
}
}
void jpeg_drv_hybrid_dec_end_dvfs(unsigned int id)
{
struct dev_pm_opp *opp = 0;
int volt = 0;
int ret = 0;
if (gJpegqDev.jpeg_reg[id] != 0) {
JPEG_LOG(1, "request freq %lu", gJpegqDev.jpeg_freqs[id][0]);
opp = dev_pm_opp_find_freq_ceil(gJpegqDev.pDev[id],
&gJpegqDev.jpeg_freqs[id][0]);
volt = dev_pm_opp_get_voltage(opp);
dev_pm_opp_put(opp);
ret = regulator_set_voltage(gJpegqDev.jpeg_reg[id], volt, INT_MAX);
if (ret) {
JPEG_LOG(0 ,"Failed to set regulator voltage %d",
volt);
}
}
}
void jpeg_drv_hybrid_dec_power_on(int id)
{
int ret;
if (!dec_hwlocked[(id+1)%HW_CORE_NUMBER]/*&& !dec_hwlocked[(id+2)%HW_CORE_NUM]*/) {
if (gJpegqDev.jpegLarb[0]) {
JPEG_LOG(1, "power on larb7");
ret = mtk_smi_larb_get(gJpegqDev.jpegLarb[0]);
if (ret)
JPEG_LOG(0, "mtk_smi_larb_get failed %d",
ret);
}
ret = clk_prepare_enable(gJpegqDev.jpegClk.clk_venc_jpgDec);
if (ret)
JPEG_LOG(0, "clk MT_CG_VENC_JPGDEC failed %d",
ret);
ret = clk_prepare_enable(gJpegqDev.jpegClk.clk_venc_jpgDec_c1);
if (ret)
JPEG_LOG(0, "clk MT_CG_VENC_JPGDEC_C1 failed %d",
ret);
}
if (id == 2) {
if (gJpegqDev.jpegLarb[1]) {
JPEG_LOG(1, "power on larb8");
ret = mtk_smi_larb_get(gJpegqDev.jpegLarb[1]);
if (ret)
JPEG_LOG(0, "mtk_smi_larb_get failed %d",
ret);
}
ret = clk_prepare_enable(gJpegqDev.jpegClk.clk_venc_c1_jpgDec);
if (ret)
JPEG_LOG(0, "clk enable MT_CG_VENC_C1_JPGDEC failed %d",
ret);
jpeg_drv_hybrid_dec_start_dvfs(1);
} else
jpeg_drv_hybrid_dec_start_dvfs(0);
JPEG_LOG(1, "JPEG Hybrid Decoder Power On %d", id);
}
void jpeg_drv_hybrid_dec_power_off(int id)
{
if (id == 2) {
jpeg_drv_hybrid_dec_end_dvfs(1);
clk_disable_unprepare(gJpegqDev.jpegClk.clk_venc_c1_jpgDec);
if (gJpegqDev.jpegLarb[1])
mtk_smi_larb_put(gJpegqDev.jpegLarb[1]);
} else
jpeg_drv_hybrid_dec_end_dvfs(0);
if (!dec_hwlocked[(id+1)%HW_CORE_NUMBER]/* && !dec_hwlocked[(id+2)%3]*/) {
clk_disable_unprepare(gJpegqDev.jpegClk.clk_venc_jpgDec);
clk_disable_unprepare(gJpegqDev.jpegClk.clk_venc_jpgDec_c1);
if (gJpegqDev.jpegLarb[0])
mtk_smi_larb_put(gJpegqDev.jpegLarb[0]);
}
JPEG_LOG(1, "JPEG Hybrid Decoder Power Off %d", id);
}
static int jpeg_drv_hybrid_dec_lock(int *hwid)
{
int retValue = 0;
int id = 0;
if (gJpegqDev.is_suspending) {
JPEG_LOG(0, "jpeg dec is suspending");
*hwid = -1;
return -EBUSY;
}
mutex_lock(&jpeg_hybrid_dec_lock);
for (id = 0; id < HW_CORE_NUMBER; id++) {
if (dec_hwlocked[id]) {
JPEG_LOG(1, "jpeg dec HW core %d is busy", id);
continue;
} else {
*hwid = id;
dec_hwlocked[id] = true;
JPEG_LOG(1, "jpeg dec get %d HW core", id);
_jpeg_hybrid_dec_int_status[id] = 0;
jpeg_drv_hybrid_dec_power_on(id);
enable_irq(gJpegqDev.hybriddecIrqId[id]);
break;
}
}
mutex_unlock(&jpeg_hybrid_dec_lock);
if (id == HW_CORE_NUMBER) {
JPEG_LOG(1, "jpeg dec HW core all busy");
*hwid = -1;
retValue = -EBUSY;
}
return retValue;
}
static void jpeg_drv_hybrid_dec_unlock(unsigned int hwid)
{
mutex_lock(&jpeg_hybrid_dec_lock);
if (!dec_hwlocked[hwid]) {
JPEG_LOG(0, "try to unlock a free core %d", hwid);
} else {
dec_hwlocked[hwid] = false;
JPEG_LOG(1, "jpeg dec HW core %d is unlocked", hwid);
jpeg_drv_hybrid_dec_power_off(hwid);
disable_irq(gJpegqDev.hybriddecIrqId[hwid]);
jpg_dmabuf_free_iova(bufInfo[hwid].i_dbuf,
bufInfo[hwid].i_attach,
bufInfo[hwid].i_sgt);
jpg_dmabuf_free_iova(bufInfo[hwid].o_dbuf,
bufInfo[hwid].o_attach,
bufInfo[hwid].o_sgt);
jpg_dmabuf_put(bufInfo[hwid].i_dbuf);
jpg_dmabuf_put(bufInfo[hwid].o_dbuf);
// we manually add 1 ref count, need to put it.
}
mutex_unlock(&jpeg_hybrid_dec_lock);
}
static int jpeg_drv_hybrid_dec_suspend_notifier(
struct notifier_block *nb,
unsigned long action, void *data)
{
int i;
int wait_cnt = 0;
JPEG_LOG(0, "action:%ld", action);
switch (action) {
case PM_SUSPEND_PREPARE:
gJpegqDev.is_suspending = 1;
for (i = 0 ; i < HW_CORE_NUMBER; i++) {
JPEG_LOG(1, "jpeg dec sn wait core %d", i);
while (dec_hwlocked[i]) {
JPEG_LOG(1, "jpeg dec sn core %d locked. wait...", i);
usleep_range(10000, 20000);
wait_cnt++;
if (wait_cnt > 5) {
JPEG_LOG(0, "jpeg dec sn unlock core %d", i);
jpeg_drv_hybrid_dec_unlock(i);
return NOTIFY_DONE;
}
}
}
return NOTIFY_OK;
case PM_POST_SUSPEND:
gJpegqDev.is_suspending = 0;
return NOTIFY_OK;
default:
return NOTIFY_DONE;
}
return NOTIFY_DONE;
}
static int jpeg_drv_hybrid_dec_suspend(void)
{
int i;
JPEG_LOG(0, "+");
for (i = 0 ; i < HW_CORE_NUMBER; i++) {
JPEG_LOG(1, "jpeg dec suspend core %d", i);
if (dec_hwlocked[i]) {
JPEG_LOG(0, "suspend unlock core %d\n", i);
jpeg_drv_hybrid_dec_unlock(i);
}
}
return 0;
}
static int jpeg_drv_hybrid_dec_get_status(int hwid)
{
int p_n_s;
p_n_s = -1;
mutex_lock(&jpeg_hybrid_dec_lock);
if (!dec_hwlocked[hwid]) {
JPEG_LOG(1, "hw %d unlocked, return -1 status", hwid);
} else {
JPEG_LOG(1, "get p_n_s @ hw %d", hwid);
jpeg_drv_hybrid_dec_get_p_n_s(hwid, &p_n_s);
}
mutex_unlock(&jpeg_hybrid_dec_lock);
return p_n_s;
}
static unsigned int jpeg_get_node_index(const char *name)
{
if (strncmp(name, "jpgdec0", strlen("jpgdec0")) == 0) {
JPEG_LOG(0, "name %s", name);
return 0;
}
else if (strncmp(name, "jpgdec1", strlen("jpgdec1")) == 0) {
JPEG_LOG(0, "name %s", name);
return 1;
}
else {
JPEG_LOG(0, "name not found %s", name);
return 0;
}
}
static int jpeg_hybrid_dec_ioctl(unsigned int cmd, unsigned long arg,
struct file *file)
{
unsigned int *pStatus;
int hwid;
int index_buf_fd;
long timeout_jiff;
int progress_n_status;
struct JPEG_DEC_DRV_HYBRID_TASK taskParams;
struct JPEG_DEC_DRV_HYBRID_P_N_S pnsParmas;
pStatus = (unsigned int *)file->private_data;
if (pStatus == NULL) {
JPEG_LOG
(0, "Private data is null");
return -EFAULT;
}
switch (cmd) {
case JPEG_DEC_IOCTL_HYBRID_START:
JPEG_LOG(1, "JPEG DEC IOCTL HYBRID START");
if (copy_from_user(
&taskParams, (void *)arg,
sizeof(struct JPEG_DEC_DRV_HYBRID_TASK))) {
JPEG_LOG(0, "Copy from user error");
return -EFAULT;
}
if (taskParams.timeout != 3000) // JPEG oal magic number
return -EFAULT;
if (jpeg_drv_hybrid_dec_lock(&hwid) == 0) {
*pStatus = JPEG_DEC_PROCESS;
} else {
JPEG_LOG(1, "jpeg_drv_hybrid_dec_lock failed (hw busy)");
return -EBUSY;
}
if (jpeg_drv_hybrid_dec_start(taskParams.data, hwid, &index_buf_fd) == 0) {
JPEG_LOG(1, "jpeg_drv_hybrid_dec_start success %u index buf fd:%d", hwid, index_buf_fd);
if (copy_to_user(
taskParams.hwid, &hwid, sizeof(int))) {
JPEG_LOG(0, "Copy to user error");
return -EFAULT;
}
if (copy_to_user(
taskParams.index_buf_fd, &index_buf_fd, sizeof(int))) {
JPEG_LOG(0, "Copy to user error");
return -EFAULT;
}
} else {
JPEG_LOG(0, "jpeg_drv_dec_hybrid_start failed");
jpeg_drv_hybrid_dec_unlock(hwid);
return -EFAULT;
}
break;
case JPEG_DEC_IOCTL_HYBRID_WAIT:
JPEG_LOG(1,"JPEG DEC IOCTL HYBRID WAIT");
if (*pStatus != JPEG_DEC_PROCESS) {
JPEG_LOG(0,
"Permission Denied! This process cannot access decoder");
return -EFAULT;
}
if (copy_from_user(
&pnsParmas, (void *)arg,
sizeof(struct JPEG_DEC_DRV_HYBRID_P_N_S))) {
JPEG_LOG(0, "Copy from user error");
return -EFAULT;
}
/* set timeout */
timeout_jiff = msecs_to_jiffies(3000);
JPEG_LOG(1, "JPEG Hybrid Decoder Wait Resume Time: %ld",
timeout_jiff);
hwid = pnsParmas.hwid;
if (hwid < 0 || hwid >= HW_CORE_NUMBER) {
JPEG_LOG(0, "get hybrid dec id failed");
return -EFAULT;
}
#ifdef FPGA_VERSION
JPEG_LOG(1, "Polling JPEG Hybrid Dec Status hwid: %d",
hwid);
do {
_jpeg_hybrid_dec_int_status[hwid] =
IMG_REG_READ(REG_JPGDEC_HYBRID_INT_STATUS(hwid));
JPEG_LOG(1, "Hybrid Polling status %d",
_jpeg_hybrid_dec_int_status[hwid]);
} while (_jpeg_hybrid_dec_int_status[hwid] == 0);
#else
if (jpeg_isr_hybrid_dec_lisr(hwid) < 0) {
long ret = 0;
int waitfailcnt = 0;
do {
ret = wait_event_interruptible_timeout(
hybrid_dec_wait_queue[hwid],
_jpeg_hybrid_dec_int_status[hwid],
timeout_jiff);
if (ret == 0)
JPEG_LOG(0,
"JPEG Hybrid Dec Wait timeout!");
if (ret < 0) {
waitfailcnt++;
JPEG_LOG(0,
"JPEG Hybrid Dec Wait Error %d",
waitfailcnt);
usleep_range(10000, 20000);
}
} while (ret < 0 && waitfailcnt < 500);
} else
JPEG_LOG(1, "JPEG Hybrid Dec IRQ Wait Already Done!");
_jpeg_hybrid_dec_int_status[hwid] = 0;
#endif
progress_n_status = jpeg_drv_hybrid_dec_get_status(hwid);
JPEG_LOG(1, "jpeg_drv_hybrid_dec_get_status %d", progress_n_status);
if (copy_to_user(
pnsParmas.progress_n_status, &progress_n_status, sizeof(int))) {
JPEG_LOG(0, "Copy to user error");
return -EFAULT;
}
IMG_REG_WRITE(0x0, REG_JPGDEC_HYBRID_090(hwid));
IMG_REG_WRITE(0x00000010, REG_JPGDEC_HYBRID_090(hwid));
jpeg_drv_hybrid_dec_unlock(hwid);
break;
case JPEG_DEC_IOCTL_HYBRID_GET_PROGRESS_STATUS:
JPEG_LOG(1,"JPEG DEC IOCTL HYBRID GET PROGRESS N STATUS");
if (*pStatus != JPEG_DEC_PROCESS) {
JPEG_LOG(0,
"Permission Denied! This process cannot access decoder");
return -EFAULT;
}
if (copy_from_user(
&pnsParmas, (void *)arg,
sizeof(struct JPEG_DEC_DRV_HYBRID_P_N_S))) {
JPEG_LOG(0, "JPEG Decoder : Copy from user error");
return -EFAULT;
}
hwid = pnsParmas.hwid;
if (hwid < 0 || hwid >= HW_CORE_NUMBER) {
JPEG_LOG(0, "get P_N_S hwid invalid");
return -EFAULT;
}
progress_n_status = jpeg_drv_hybrid_dec_get_status(hwid);
if (copy_to_user(
pnsParmas.progress_n_status, &progress_n_status, sizeof(int))) {
JPEG_LOG(0, "JPEG Decoder: Copy to user error");
return -EFAULT;
}
break;
default:
JPEG_LOG(0, "JPEG DEC IOCTL NO THIS COMMAND");
break;
}
return 0;
}
#if IS_ENABLED(CONFIG_COMPAT)
static int compat_get_jpeg_hybrid_task_data(
struct compat_JPEG_DEC_DRV_HYBRID_TASK __user *data32,
struct JPEG_DEC_DRV_HYBRID_TASK __user *data)
{
compat_long_t timeout;
compat_uptr_t hwid;
compat_uptr_t index_buf_fd;
int err, i;
unsigned int temp;
err = get_user(timeout, &data32->timeout);
err |= put_user(timeout, &data->timeout);
err |= get_user(hwid, &data32->hwid);
err |= put_user(compat_ptr(hwid), &data->hwid);
err |= get_user(index_buf_fd, &data32->index_buf_fd);
err |= put_user(compat_ptr(index_buf_fd), &data->index_buf_fd);
for (i = 0; i < 21; i++) {
err |= get_user(temp, &data32->data[i]);
err |= put_user(temp, &data->data[i]);
}
return err;
}
static int compat_get_jpeg_hybrid_pns_data(
struct compat_JPEG_DEC_DRV_HYBRID_P_N_S __user *data32,
struct JPEG_DEC_DRV_HYBRID_P_N_S __user *data)
{
int hwid;
compat_uptr_t progress_n_status;
int err;
err = get_user(hwid, &data32->hwid);
err |= put_user(hwid, &data->hwid);
err |= get_user(progress_n_status, &data32->progress_n_status);
err |= put_user(compat_ptr(progress_n_status), &data->progress_n_status);
return err;
}
static long compat_jpeg_ioctl(
struct file *filp,
unsigned int cmd,
unsigned long arg)
{
long ret;
if (!filp->f_op || !filp->f_op->unlocked_ioctl)
return -ENOTTY;
switch (cmd) {
case COMPAT_JPEG_DEC_IOCTL_HYBRID_START:
{
struct compat_JPEG_DEC_DRV_HYBRID_TASK __user *data32;
struct JPEG_DEC_DRV_HYBRID_TASK __user *data;
int err;
JPEG_LOG(1, "COMPAT_JPEG_DEC_IOCTL_HYBRID_START");
data32 = compat_ptr(arg);
data = compat_alloc_user_space(sizeof(*data));
if (data == NULL)
return -EFAULT;
err = compat_get_jpeg_hybrid_task_data(data32, data);
if (err)
return err;
ret =
filp->f_op->unlocked_ioctl(filp, JPEG_DEC_IOCTL_HYBRID_START,
(unsigned long)data);
return ret ? ret : err;
}
case COMPAT_JPEG_DEC_IOCTL_HYBRID_WAIT:
{
struct compat_JPEG_DEC_DRV_HYBRID_P_N_S __user *data32;
struct JPEG_DEC_DRV_HYBRID_P_N_S __user *data;
int err;
JPEG_LOG(1, "COMPAT_JPEG_DEC_IOCTL_HYBRID_WAIT");
data32 = compat_ptr(arg);
data = compat_alloc_user_space(sizeof(*data));
if (data == NULL)
return -EFAULT;
err = compat_get_jpeg_hybrid_pns_data(data32, data);
if (err)
return err;
ret =
filp->f_op->unlocked_ioctl(
filp, JPEG_DEC_IOCTL_HYBRID_WAIT,
(unsigned long)data);
return ret ? ret : err;
}
case COMPAT_JPEG_DEC_IOCTL_HYBRID_GET_PROGRESS_STATUS:
{
struct compat_JPEG_DEC_DRV_HYBRID_P_N_S __user *data32;
struct JPEG_DEC_DRV_HYBRID_P_N_S __user *data;
int err;
JPEG_LOG(1, "COMPAT_JPEG_DEC_IOCTL_HYBRID_GET_PROGRESS_STATUS");
data32 = compat_ptr(arg);
data = compat_alloc_user_space(sizeof(*data));
if (data == NULL)
return -EFAULT;
err = compat_get_jpeg_hybrid_pns_data(data32, data);
if (err)
return err;
ret =
filp->f_op->unlocked_ioctl(filp, JPEG_DEC_IOCTL_HYBRID_GET_PROGRESS_STATUS,
(unsigned long)data);
return ret ? ret : err;
}
default:
return -ENOIOCTLCMD;
}
}
#endif
static long jpeg_unlocked_ioctl(
struct file *file,
unsigned int cmd,
unsigned long arg)
{
switch (cmd) {
case JPEG_DEC_IOCTL_HYBRID_START:
case JPEG_DEC_IOCTL_HYBRID_WAIT:
case JPEG_DEC_IOCTL_HYBRID_GET_PROGRESS_STATUS:
return jpeg_hybrid_dec_ioctl(cmd, arg, file);
default:
break;
}
return -EINVAL;
}
static int jpeg_open(struct inode *inode, struct file *file)
{
unsigned int *pStatus;
/* Allocate and initialize private data */
file->private_data = kmalloc(sizeof(unsigned int), GFP_ATOMIC);
if (file->private_data == NULL) {
JPEG_LOG(0, "Not enough entry for JPEG open operation");
return -ENOMEM;
}
pStatus = (unsigned int *)file->private_data;
*pStatus = 0;
return 0;
}
static ssize_t jpeg_read(
struct file *file,
char __user *data,
size_t len, loff_t *ppos)
{
JPEG_LOG(1, "jpeg driver read");
return 0;
}
static int jpeg_release(struct inode *inode, struct file *file)
{
if (file->private_data != NULL) {
kfree(file->private_data);
file->private_data = NULL;
}
return 0;
}
/* Kernel interface */
static const struct proc_ops jpeg_fops = {
.proc_ioctl = jpeg_unlocked_ioctl,
#if IS_ENABLED(CONFIG_COMPAT)
.proc_compat_ioctl = compat_jpeg_ioctl,
#endif
.proc_open = jpeg_open,
.proc_release = jpeg_release,
.proc_read = jpeg_read,
};
const long jpeg_dev_get_hybrid_decoder_base_VA(int id)
{
return gJpegqDev.hybriddecRegBaseVA[id];
}
static int jpeg_probe(struct platform_device *pdev)
{
struct device_node *node = NULL, *larbnode = NULL;
struct platform_device *larbdev;
int i, node_index, ret;
JPEG_LOG(0, "JPEG Probe");
atomic_inc(&nodeCount);
node_index = jpeg_get_node_index(pdev->dev.of_node->name);
if (atomic_read(&nodeCount) == 1)
memset(&gJpegqDev, 0x0, sizeof(struct JpegDeviceStruct));
gJpegqDev.pDev[node_index] = &pdev->dev;
node = pdev->dev.of_node;
if (node_index == 0) {
for (i = 0; i < HW_CORE_NUMBER; i++) {
gJpegqDev.hybriddecRegBaseVA[i] =
(unsigned long)of_iomap(node, i);
gJpegqDev.hybriddecIrqId[i] = irq_of_parse_and_map(node, i);
JPEG_LOG(0, "Jpeg Hybrid Dec Probe %d base va 0x%lx irqid %d",
i, gJpegqDev.hybriddecRegBaseVA[i],
gJpegqDev.hybriddecIrqId[i]);
JPEG_LOG(0, "Request irq %d", gJpegqDev.hybriddecIrqId[i]);
init_waitqueue_head(&(hybrid_dec_wait_queue[i]));
if (request_irq(gJpegqDev.hybriddecIrqId[i],
jpeg_drv_hybrid_dec_isr, IRQF_TRIGGER_HIGH,
"jpeg_dec_driver", NULL))
JPEG_LOG(0, "JPEG Hybrid DEC requestirq %d failed", i);
disable_irq(gJpegqDev.hybriddecIrqId[i]);
}
gJpegqDev.jpegClk.clk_venc_jpgDec =
of_clk_get_by_name(node, "MT_CG_VENC_JPGDEC");
if (IS_ERR(gJpegqDev.jpegClk.clk_venc_jpgDec))
JPEG_LOG(0, "get MT_CG_VENC_JPGDEC clk error!");
gJpegqDev.jpegClk.clk_venc_jpgDec_c1 =
of_clk_get_by_name(node, "MT_CG_VENC_JPGDEC_C1");
if (IS_ERR(gJpegqDev.jpegClk.clk_venc_jpgDec_c1))
JPEG_LOG(0, "get MT_CG_VENC_JPGDEC_C1 clk error!");
} /*else {
i = HW_CORE_NUMBER - 1;
gJpegqDev.hybriddecRegBaseVA[i] =
(unsigned long)of_iomap(node, 0);
gJpegqDev.hybriddecIrqId[i] =
irq_of_parse_and_map(node, 0);
JPEG_LOG(0, "Jpeg Hybrid Dec Probe %d base va 0x%lx irqid %d",
i,
gJpegqDev.hybriddecRegBaseVA[i],
gJpegqDev.hybriddecIrqId[i]);
JPEG_LOG(0, "Request irq %d", gJpegqDev.hybriddecIrqId[i]);
init_waitqueue_head(&(hybrid_dec_wait_queue[i]));
if (request_irq(gJpegqDev.hybriddecIrqId[i],
jpeg_drv_hybrid_dec_isr, IRQF_TRIGGER_HIGH,
"jpeg_dec_driver", NULL))
JPEG_LOG(0, "JPEG Hybrid DEC requestirq %d failed", i);
disable_irq(gJpegqDev.hybriddecIrqId[i]);
gJpegqDev.jpegClk.clk_venc_c1_jpgDec =
of_clk_get_by_name(node, "MT_CG_VENC_C1_JPGDEC");
if (IS_ERR(gJpegqDev.jpegClk.clk_venc_c1_jpgDec))
JPEG_LOG(0, "get MT_CG_VENC_C1_JPGDEC clk error!");
}
*/
larbnode = of_parse_phandle(node, "mediatek,larbs", 0);
if (!larbnode) {
JPEG_LOG(0, "fail to get larbnode %d", node_index);
return -1;
}
larbdev = of_find_device_by_node(larbnode);
if (WARN_ON(!larbdev)) {
of_node_put(larbnode);
JPEG_LOG(0, "fail to get larbdev %d", node_index);
return -1;
}
gJpegqDev.jpegLarb[node_index] = &larbdev->dev;
JPEG_LOG(0, "get larb from node %d", node_index);
ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34));
if (ret) {
JPEG_LOG(0, "64-bit DMA enable failed");
return ret;
}
if (!pdev->dev.dma_parms) {
pdev->dev.dma_parms =
devm_kzalloc(&pdev->dev, sizeof(*pdev->dev.dma_parms), GFP_KERNEL);
}
if (pdev->dev.dma_parms) {
ret = dma_set_max_seg_size(&pdev->dev, (unsigned int)DMA_BIT_MASK(34));
if (ret)
JPEG_LOG(0, "Failed to set DMA segment size\n");
}
pm_runtime_enable(&pdev->dev);
jpeg_drv_hybrid_dec_prepare_dvfs(node_index);
if (atomic_read(&nodeCount) == 1) {
gJpegqDev.pm_notifier.notifier_call = jpeg_drv_hybrid_dec_suspend_notifier;
register_pm_notifier(&gJpegqDev.pm_notifier);
gJpegqDev.is_suspending = 0;
memset(_jpeg_hybrid_dec_int_status, 0, HW_CORE_NUMBER);
proc_create("mtk_jpeg", 0x644, NULL, &jpeg_fops);
}
JPEG_LOG(0, "JPEG Probe Done");
return 0;
}
static int jpeg_remove(struct platform_device *pdev)
{
int i, node_index;
JPEG_LOG(0, "JPEG Codec remove");
atomic_dec(&nodeCount);
node_index = jpeg_get_node_index(pdev->dev.of_node->name);
if (node_index == 0)
for (i = 0; i < HW_CORE_NUMBER - 1; i++)
free_irq(gJpegqDev.hybriddecIrqId[i], NULL);
else {
i = HW_CORE_NUMBER - 1;
free_irq(gJpegqDev.hybriddecIrqId[i], NULL);
}
jpeg_drv_hybrid_dec_unprepare_dvfs();
return 0;
}
static void jpeg_shutdown(struct platform_device *pdev)
{
JPEG_LOG(0, "JPEG Codec shutdown");
}
/* PM suspend */
static int jpeg_suspend(struct platform_device *pdev, pm_message_t mesg)
{
int ret;
ret = jpeg_drv_hybrid_dec_suspend();
if (ret != 0)
return ret;
return 0;
}
/* PM resume */
static int jpeg_resume(struct platform_device *pdev)
{
return 0;
}
static int jpeg_pm_suspend(struct device *pDevice)
{
struct platform_device *pdev = to_platform_device(pDevice);
WARN_ON(pdev == NULL);
return jpeg_suspend(pdev, PMSG_SUSPEND);
}
static int jpeg_pm_resume(struct device *pDevice)
{
struct platform_device *pdev = to_platform_device(pDevice);
WARN_ON(pdev == NULL);
return jpeg_resume(pdev);
}
static int jpeg_pm_restore_noirq(struct device *pDevice)
{
return 0;
}
static struct dev_pm_ops const jpeg_pm_ops = {
.suspend = jpeg_pm_suspend,
.resume = jpeg_pm_resume,
.freeze = NULL,
.thaw = NULL,
.poweroff = NULL,
.restore = NULL,
.restore_noirq = jpeg_pm_restore_noirq,
};
static struct platform_driver jpeg_driver = {
.probe = jpeg_probe,
.remove = jpeg_remove,
.shutdown = jpeg_shutdown,
.suspend = jpeg_suspend,
.resume = jpeg_resume,
.driver = {
.name = JPEG_DEVNAME,
.pm = &jpeg_pm_ops,
.of_match_table = jdec_hybrid_of_ids,
},
};
static int __init jpeg_init(void)
{
int ret;
JPEG_LOG(0, "Register the JPEG Codec driver");
atomic_set(&nodeCount, 0);
if (platform_driver_register(&jpeg_driver)) {
JPEG_LOG(0, "failed to register jpeg codec driver");
ret = -ENODEV;
return ret;
}
return 0;
}
static void __exit jpeg_exit(void)
{
remove_proc_entry("mtk_jpeg", NULL);
platform_driver_unregister(&jpeg_driver);
}
module_init(jpeg_init);
module_exit(jpeg_exit);
MODULE_AUTHOR("Jason Hsu <yeong-cherng.hsu@mediatek.com>");
MODULE_DESCRIPTION("JPEG Dec Codec Driver");
MODULE_LICENSE("GPL");