blob: dc9b6643300add0e4d0595fda3604ebe91fb1979 [file] [log] [blame]
/* Copyright (c) 2012-2015, 2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only 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 <linux/module.h>
#include <linux/sched.h>
#include "msm_jpeg_hw.h"
#include "msm_jpeg_core.h"
#include "msm_jpeg_platform.h"
#include "msm_jpeg_common.h"
int msm_jpeg_core_reset(struct msm_jpeg_device *pgmn_dev, uint8_t op_mode,
void *base, int size) {
unsigned long flags;
int rc = 0;
int tm = 500; /*500ms*/
JPEG_DBG("%s:%d] reset", __func__, __LINE__);
memset(&pgmn_dev->fe_pingpong_buf, 0,
sizeof(pgmn_dev->fe_pingpong_buf));
pgmn_dev->fe_pingpong_buf.is_fe = 1;
memset(&pgmn_dev->we_pingpong_buf, 0,
sizeof(pgmn_dev->we_pingpong_buf));
spin_lock_irqsave(&pgmn_dev->reset_lock, flags);
pgmn_dev->reset_done_ack = 0;
if (pgmn_dev->core_type == MSM_JPEG_CORE_CODEC)
msm_jpeg_hw_reset(base, size);
else
msm_jpeg_hw_reset_dma(base, size);
spin_unlock_irqrestore(&pgmn_dev->reset_lock, flags);
rc = wait_event_timeout(
pgmn_dev->reset_wait,
pgmn_dev->reset_done_ack,
msecs_to_jiffies(tm));
if (!pgmn_dev->reset_done_ack) {
JPEG_DBG("%s: reset ACK failed %d", __func__, rc);
return -EBUSY;
}
JPEG_DBG("%s: reset_done_ack rc %d", __func__, rc);
spin_lock_irqsave(&pgmn_dev->reset_lock, flags);
pgmn_dev->reset_done_ack = 0;
pgmn_dev->state = MSM_JPEG_RESET;
spin_unlock_irqrestore(&pgmn_dev->reset_lock, flags);
return 0;
}
void msm_jpeg_core_release(struct msm_jpeg_device *pgmn_dev)
{
int i = 0;
for (i = 0; i < 2; i++) {
if (pgmn_dev->we_pingpong_buf.buf_status[i] &&
pgmn_dev->release_buf)
msm_jpeg_platform_p2v(pgmn_dev->iommu_hdl,
pgmn_dev->we_pingpong_buf.buf[i].ion_fd);
pgmn_dev->we_pingpong_buf.buf_status[i] = 0;
}
}
void msm_jpeg_core_init(struct msm_jpeg_device *pgmn_dev)
{
init_waitqueue_head(&pgmn_dev->reset_wait);
spin_lock_init(&pgmn_dev->reset_lock);
}
int msm_jpeg_core_fe_start(struct msm_jpeg_device *pgmn_dev)
{
msm_jpeg_hw_fe_start(pgmn_dev->base);
return 0;
}
/* fetch engine */
int msm_jpeg_core_fe_buf_update(struct msm_jpeg_device *pgmn_dev,
struct msm_jpeg_core_buf *buf)
{
int rc = 0;
if (buf->cbcr_len == 0)
buf->cbcr_buffer_addr = 0x0;
JPEG_DBG("%s:%d] 0x%08x %d 0x%08x %d\n", __func__, __LINE__,
(int) buf->y_buffer_addr, buf->y_len,
(int) buf->cbcr_buffer_addr, buf->cbcr_len);
if (pgmn_dev->core_type == MSM_JPEG_CORE_CODEC) {
rc = msm_jpeg_hw_pingpong_update(&pgmn_dev->fe_pingpong_buf,
buf, pgmn_dev->base);
if (rc < 0)
return rc;
msm_jpeg_hw_fe_mmu_prefetch(buf, pgmn_dev->base,
pgmn_dev->decode_flag);
} else {
rc = msm_jpegdma_hw_pingpong_update(
&pgmn_dev->fe_pingpong_buf, buf, pgmn_dev->base);
if (rc < 0)
return rc;
msm_jpegdma_hw_fe_mmu_prefetch(buf, pgmn_dev->base);
}
return rc;
}
static void *msm_jpeg_core_fe_pingpong_irq(int jpeg_irq_status,
struct msm_jpeg_device *pgmn_dev)
{
return msm_jpeg_hw_pingpong_irq(&pgmn_dev->fe_pingpong_buf);
}
/* write engine */
int msm_jpeg_core_we_buf_update(struct msm_jpeg_device *pgmn_dev,
struct msm_jpeg_core_buf *buf) {
JPEG_DBG("%s:%d] 0x%08x 0x%08x %d\n", __func__, __LINE__,
(int) buf->y_buffer_addr, (int) buf->cbcr_buffer_addr,
buf->y_len);
pgmn_dev->we_pingpong_buf.buf[0] = *buf;
pgmn_dev->we_pingpong_buf.buf_status[0] = 1;
if (pgmn_dev->core_type == MSM_JPEG_CORE_CODEC) {
msm_jpeg_hw_we_buffer_update(
&pgmn_dev->we_pingpong_buf.buf[0], 0, pgmn_dev->base);
msm_jpeg_hw_we_mmu_prefetch(buf, pgmn_dev->base,
pgmn_dev->decode_flag);
} else {
msm_jpegdma_hw_we_buffer_update(
&pgmn_dev->we_pingpong_buf.buf[0], 0, pgmn_dev->base);
msm_jpegdma_hw_we_mmu_prefetch(buf, pgmn_dev->base);
}
return 0;
}
int msm_jpeg_core_we_buf_reset(struct msm_jpeg_device *pgmn_dev,
struct msm_jpeg_hw_buf *buf)
{
int i = 0;
for (i = 0; i < 2; i++) {
if (pgmn_dev->we_pingpong_buf.buf[i].y_buffer_addr
== buf->y_buffer_addr)
pgmn_dev->we_pingpong_buf.buf_status[i] = 0;
}
return 0;
}
static void *msm_jpeg_core_we_pingpong_irq(int jpeg_irq_status,
struct msm_jpeg_device *pgmn_dev)
{
JPEG_DBG("%s:%d]\n", __func__, __LINE__);
return msm_jpeg_hw_pingpong_irq(&pgmn_dev->we_pingpong_buf);
}
static void *msm_jpeg_core_framedone_irq(int jpeg_irq_status,
struct msm_jpeg_device *pgmn_dev)
{
struct msm_jpeg_hw_buf *buf_p;
JPEG_DBG("%s:%d]\n", __func__, __LINE__);
buf_p = msm_jpeg_hw_pingpong_active_buffer(
&pgmn_dev->we_pingpong_buf);
if (buf_p && !pgmn_dev->decode_flag) {
buf_p->framedone_len =
msm_jpeg_hw_encode_output_size(pgmn_dev->base);
JPEG_DBG("%s:%d] framedone_len %d\n", __func__, __LINE__,
buf_p->framedone_len);
}
return buf_p;
}
static void *msm_jpeg_core_reset_ack_irq(int jpeg_irq_status,
struct msm_jpeg_device *pgmn_dev)
{
/* @todo return the status back to msm_jpeg_core_reset */
JPEG_DBG("%s:%d]\n", __func__, __LINE__);
return NULL;
}
static void *msm_jpeg_core_err_irq(int jpeg_irq_status,
struct msm_jpeg_device *pgmn_dev)
{
JPEG_PR_ERR("%s: Error %x\n", __func__, jpeg_irq_status);
return NULL;
}
static int (*msm_jpeg_irq_handler)(int, void *, void *);
static void msm_jpeg_core_return_buffers(struct msm_jpeg_device *pgmn_dev,
int jpeg_irq_status)
{
void *data = NULL;
data = msm_jpeg_core_fe_pingpong_irq(jpeg_irq_status,
pgmn_dev);
if (msm_jpeg_irq_handler)
msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_FE,
pgmn_dev, data);
data = msm_jpeg_core_we_pingpong_irq(jpeg_irq_status,
pgmn_dev);
if (msm_jpeg_irq_handler)
msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_WE,
pgmn_dev, data);
}
irqreturn_t msm_jpeg_core_irq(int irq_num, void *context)
{
void *data = NULL;
unsigned long flags;
int jpeg_irq_status;
struct msm_jpeg_device *pgmn_dev = (struct msm_jpeg_device *)context;
JPEG_DBG("%s:%d] irq_num = %d\n", __func__, __LINE__, irq_num);
jpeg_irq_status = msm_jpeg_hw_irq_get_status(pgmn_dev->base);
JPEG_DBG("%s:%d] jpeg_irq_status = %0x\n", __func__, __LINE__,
jpeg_irq_status);
/*For reset and framedone IRQs, clear all bits*/
if (pgmn_dev->state == MSM_JPEG_IDLE) {
JPEG_DBG_HIGH("%s %d ] Error IRQ received state %d",
__func__, __LINE__, pgmn_dev->state);
JPEG_DBG_HIGH("%s %d ] Ignoring the Error", __func__,
__LINE__);
msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK,
JPEG_IRQ_CLEAR_ALL, pgmn_dev->base);
return IRQ_HANDLED;
} else if (jpeg_irq_status & 0x10000000) {
msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK,
JPEG_IRQ_CLEAR_ALL, pgmn_dev->base);
} else if (jpeg_irq_status & 0x1) {
msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK,
JPEG_IRQ_CLEAR_ALL, pgmn_dev->base);
if (pgmn_dev->decode_flag)
msm_jpeg_decode_status(pgmn_dev->base);
} else {
msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK,
jpeg_irq_status, pgmn_dev->base);
}
if (msm_jpeg_hw_irq_is_frame_done(jpeg_irq_status)) {
/* send fe ping pong irq */
JPEG_DBG_HIGH("%s:%d] Session done\n", __func__, __LINE__);
data = msm_jpeg_core_fe_pingpong_irq(jpeg_irq_status,
pgmn_dev);
if (msm_jpeg_irq_handler)
msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_FE,
context, data);
data = msm_jpeg_core_framedone_irq(jpeg_irq_status,
pgmn_dev);
if (msm_jpeg_irq_handler)
msm_jpeg_irq_handler(
MSM_JPEG_HW_MASK_COMP_FRAMEDONE,
context, data);
pgmn_dev->state = MSM_JPEG_INIT;
}
if (msm_jpeg_hw_irq_is_reset_ack(jpeg_irq_status)) {
data = msm_jpeg_core_reset_ack_irq(jpeg_irq_status,
pgmn_dev);
spin_lock_irqsave(&pgmn_dev->reset_lock, flags);
pgmn_dev->reset_done_ack = 1;
spin_unlock_irqrestore(&pgmn_dev->reset_lock, flags);
wake_up(&pgmn_dev->reset_wait);
if (msm_jpeg_irq_handler)
msm_jpeg_irq_handler(
MSM_JPEG_HW_MASK_COMP_RESET_ACK,
context, data);
}
/* Unexpected/unintended HW interrupt */
if (msm_jpeg_hw_irq_is_err(jpeg_irq_status)) {
if (pgmn_dev->state != MSM_JPEG_EXECUTING) {
/*Clear all the bits and ignore the IRQ*/
JPEG_DBG_HIGH("%s %d ] Error IRQ received state %d",
__func__, __LINE__, pgmn_dev->state);
JPEG_DBG_HIGH("%s %d ] Ignoring the Error", __func__,
__LINE__);
msm_jpeg_hw_irq_clear(JPEG_IRQ_CLEAR_BMSK,
JPEG_IRQ_CLEAR_ALL, pgmn_dev->base);
} else {
if (pgmn_dev->decode_flag)
msm_jpeg_decode_status(pgmn_dev->base);
msm_jpeg_core_return_buffers(pgmn_dev, jpeg_irq_status);
data = msm_jpeg_core_err_irq(jpeg_irq_status, pgmn_dev);
if (msm_jpeg_irq_handler) {
msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_ERR,
context, data);
}
}
}
return IRQ_HANDLED;
}
irqreturn_t msm_jpegdma_core_irq(int irq_num, void *context)
{
void *data = NULL;
unsigned long flags;
int jpeg_irq_status;
struct msm_jpeg_device *pgmn_dev = context;
JPEG_DBG("%s:%d] irq_num = %d\n", __func__, __LINE__, irq_num);
jpeg_irq_status = msm_jpegdma_hw_irq_get_status(pgmn_dev->base);
JPEG_DBG("%s:%d] jpeg_irq_status = %0x\n", __func__, __LINE__,
jpeg_irq_status);
/*For reset and framedone IRQs, clear all bits*/
if (pgmn_dev->state == MSM_JPEG_IDLE) {
JPEG_DBG_HIGH("%s %d ] Error IRQ received state %d",
__func__, __LINE__, pgmn_dev->state);
JPEG_DBG_HIGH("%s %d ] Ignoring the Error", __func__,
__LINE__);
msm_jpegdma_hw_irq_clear(JPEGDMA_IRQ_CLEAR_BMSK,
JPEGDMA_IRQ_CLEAR_ALL, pgmn_dev->base);
return IRQ_HANDLED;
} else if (jpeg_irq_status & 0x00000400) {
msm_jpegdma_hw_irq_clear(JPEGDMA_IRQ_CLEAR_BMSK,
JPEGDMA_IRQ_CLEAR_ALL, pgmn_dev->base);
} else if (jpeg_irq_status & 0x1) {
msm_jpegdma_hw_irq_clear(JPEGDMA_IRQ_CLEAR_BMSK,
JPEGDMA_IRQ_CLEAR_ALL, pgmn_dev->base);
} else {
msm_jpegdma_hw_irq_clear(JPEGDMA_IRQ_CLEAR_BMSK,
jpeg_irq_status, pgmn_dev->base);
}
if (msm_jpegdma_hw_irq_is_frame_done(jpeg_irq_status)) {
/* send fe ping pong irq */
JPEG_DBG_HIGH("%s:%d] Session done\n", __func__, __LINE__);
data = msm_jpeg_core_fe_pingpong_irq(jpeg_irq_status,
pgmn_dev);
if (msm_jpeg_irq_handler)
msm_jpeg_irq_handler(MSM_JPEG_HW_MASK_COMP_FE,
context, data);
data = msm_jpeg_core_framedone_irq(jpeg_irq_status,
pgmn_dev);
if (msm_jpeg_irq_handler)
msm_jpeg_irq_handler(
MSM_JPEG_HW_MASK_COMP_FRAMEDONE,
context, data);
pgmn_dev->state = MSM_JPEG_INIT;
}
if (msm_jpegdma_hw_irq_is_reset_ack(jpeg_irq_status)) {
data = msm_jpeg_core_reset_ack_irq(jpeg_irq_status,
pgmn_dev);
spin_lock_irqsave(&pgmn_dev->reset_lock, flags);
pgmn_dev->reset_done_ack = 1;
spin_unlock_irqrestore(&pgmn_dev->reset_lock, flags);
wake_up(&pgmn_dev->reset_wait);
if (msm_jpeg_irq_handler)
msm_jpeg_irq_handler(
MSM_JPEG_HW_MASK_COMP_RESET_ACK,
context, data);
}
return IRQ_HANDLED;
}
void msm_jpeg_core_irq_install(int (*irq_handler) (int, void *, void *))
{
msm_jpeg_irq_handler = irq_handler;
}
void msm_jpeg_core_irq_remove(void)
{
msm_jpeg_irq_handler = NULL;
}