412 lines
11 KiB
C
Executable File
412 lines
11 KiB
C
Executable File
/* Copyright (c) 2012, 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/delay.h>
|
|
#include "msm_jpeg_hw.h"
|
|
#include "msm_jpeg_common.h"
|
|
|
|
#include <linux/io.h>
|
|
|
|
int msm_jpeg_hw_pingpong_update(struct msm_jpeg_hw_pingpong *pingpong_hw,
|
|
struct msm_jpeg_hw_buf *buf, void *base)
|
|
{
|
|
int buf_free_index = -1;
|
|
|
|
if (!pingpong_hw->buf_status[0]) {
|
|
buf_free_index = 0;
|
|
} else if (!pingpong_hw->buf_status[1]) {
|
|
buf_free_index = 1;
|
|
} else {
|
|
JPEG_PR_ERR("%s:%d: pingpong buffer busy\n",
|
|
__func__, __LINE__);
|
|
return -EBUSY;
|
|
}
|
|
|
|
pingpong_hw->buf[buf_free_index] = *buf;
|
|
pingpong_hw->buf_status[buf_free_index] = 1;
|
|
|
|
if (pingpong_hw->is_fe) {
|
|
/* it is fe */
|
|
msm_jpeg_hw_fe_buffer_update(
|
|
&pingpong_hw->buf[buf_free_index], buf_free_index,
|
|
base);
|
|
} else {
|
|
/* it is we */
|
|
msm_jpeg_hw_we_buffer_update(
|
|
&pingpong_hw->buf[buf_free_index], buf_free_index,
|
|
base);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void *msm_jpeg_hw_pingpong_irq(struct msm_jpeg_hw_pingpong *pingpong_hw)
|
|
{
|
|
struct msm_jpeg_hw_buf *buf_p = NULL;
|
|
|
|
if (pingpong_hw->buf_status[pingpong_hw->buf_active_index]) {
|
|
buf_p = &pingpong_hw->buf[pingpong_hw->buf_active_index];
|
|
pingpong_hw->buf_status[pingpong_hw->buf_active_index] = 0;
|
|
}
|
|
|
|
pingpong_hw->buf_active_index = !pingpong_hw->buf_active_index;
|
|
|
|
return (void *) buf_p;
|
|
}
|
|
|
|
void *msm_jpeg_hw_pingpong_active_buffer(
|
|
struct msm_jpeg_hw_pingpong *pingpong_hw)
|
|
{
|
|
struct msm_jpeg_hw_buf *buf_p = NULL;
|
|
|
|
if (pingpong_hw->buf_status[pingpong_hw->buf_active_index])
|
|
buf_p = &pingpong_hw->buf[pingpong_hw->buf_active_index];
|
|
|
|
return (void *) buf_p;
|
|
}
|
|
|
|
struct msm_jpeg_hw_cmd hw_cmd_irq_get_status[] = {
|
|
/* type, repeat n times, offset, mask, data or pdata */
|
|
{MSM_JPEG_HW_CMD_TYPE_READ, 1, JPEG_IRQ_STATUS_ADDR,
|
|
JPEG_IRQ_STATUS_BMSK, {0} },
|
|
};
|
|
|
|
int msm_jpeg_hw_irq_get_status(void *base)
|
|
{
|
|
uint32_t n_irq_status = 0;
|
|
n_irq_status = msm_jpeg_hw_read(&hw_cmd_irq_get_status[0], base);
|
|
return n_irq_status;
|
|
}
|
|
|
|
struct msm_jpeg_hw_cmd hw_cmd_encode_output_size[] = {
|
|
/* type, repeat n times, offset, mask, data or pdata */
|
|
{MSM_JPEG_HW_CMD_TYPE_READ, 1,
|
|
JPEG_ENCODE_OUTPUT_SIZE_STATUS_ADDR,
|
|
JPEG_ENCODE_OUTPUT_SIZE_STATUS_BMSK, {0} } ,
|
|
};
|
|
|
|
long msm_jpeg_hw_encode_output_size(void *base)
|
|
{
|
|
uint32_t encode_output_size = 0;
|
|
|
|
encode_output_size = msm_jpeg_hw_read(&hw_cmd_encode_output_size[0],
|
|
base);
|
|
|
|
return encode_output_size;
|
|
}
|
|
|
|
struct msm_jpeg_hw_cmd hw_cmd_irq_clear[] = {
|
|
/* type, repeat n times, offset, mask, data or pdata */
|
|
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_CLEAR_ADDR,
|
|
JPEG_IRQ_CLEAR_BMSK, {JPEG_IRQ_CLEAR_ALL} },
|
|
};
|
|
|
|
void msm_jpeg_hw_irq_clear(uint32_t mask, uint32_t data, void *base)
|
|
{
|
|
JPEG_DBG("%s:%d] mask %0x data %0x", __func__, __LINE__, mask, data);
|
|
hw_cmd_irq_clear[0].mask = mask;
|
|
hw_cmd_irq_clear[0].data = data;
|
|
msm_jpeg_hw_write(&hw_cmd_irq_clear[0], base);
|
|
}
|
|
|
|
struct msm_jpeg_hw_cmd hw_cmd_fe_ping_update[] = {
|
|
/* type, repeat n times, offset, mask, data or pdata */
|
|
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_MASK_ADDR,
|
|
JPEG_IRQ_MASK_BMSK, {JPEG_IRQ_ALLSOURCES_ENABLE} },
|
|
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_CMD_ADDR,
|
|
JPEG_CMD_BMSK, {JPEG_CMD_CLEAR_WRITE_PLN_QUEUES} },
|
|
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN0_RD_OFFSET_ADDR,
|
|
JPEG_PLN0_RD_OFFSET_BMSK, {0} },
|
|
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN0_RD_PNTR_ADDR,
|
|
JPEG_PLN0_RD_PNTR_BMSK, {0} },
|
|
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN1_RD_OFFSET_ADDR,
|
|
JPEG_PLN1_RD_OFFSET_BMSK, {0} },
|
|
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN1_RD_PNTR_ADDR,
|
|
JPEG_PLN1_RD_PNTR_BMSK, {0} },
|
|
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN2_RD_OFFSET_ADDR,
|
|
JPEG_PLN1_RD_OFFSET_BMSK, {0} },
|
|
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN2_RD_PNTR_ADDR,
|
|
JPEG_PLN2_RD_PNTR_BMSK, {0} },
|
|
};
|
|
|
|
void msm_jpeg_hw_fe_buffer_update(struct msm_jpeg_hw_buf *p_input,
|
|
uint8_t pingpong_index, void *base)
|
|
{
|
|
struct msm_jpeg_hw_cmd *hw_cmd_p;
|
|
|
|
if (pingpong_index == 0) {
|
|
hw_cmd_p = &hw_cmd_fe_ping_update[0];
|
|
wmb();
|
|
msm_jpeg_hw_write(hw_cmd_p++, base);
|
|
wmb();
|
|
msm_jpeg_hw_write(hw_cmd_p++, base);
|
|
wmb();
|
|
msm_jpeg_hw_write(hw_cmd_p++, base);
|
|
wmb();
|
|
hw_cmd_p->data = p_input->y_buffer_addr;
|
|
msm_jpeg_hw_write(hw_cmd_p++, base);
|
|
wmb();
|
|
msm_jpeg_hw_write(hw_cmd_p++, base);
|
|
wmb();
|
|
hw_cmd_p->data = p_input->cbcr_buffer_addr;
|
|
msm_jpeg_hw_write(hw_cmd_p++, base);
|
|
wmb();
|
|
msm_jpeg_hw_write(hw_cmd_p++, base);
|
|
wmb();
|
|
hw_cmd_p->data = p_input->pln2_addr;
|
|
msm_jpeg_hw_write(hw_cmd_p++, base);
|
|
wmb();
|
|
}
|
|
return;
|
|
}
|
|
|
|
struct msm_jpeg_hw_cmd hw_cmd_fe_start[] = {
|
|
/* type, repeat n times, offset, mask, data or pdata */
|
|
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_CMD_ADDR,
|
|
JPEG_CMD_BMSK, {JPEG_OFFLINE_CMD_START} },
|
|
};
|
|
|
|
void msm_jpeg_hw_fe_start(void *base)
|
|
{
|
|
msm_jpeg_hw_write(&hw_cmd_fe_start[0], base);
|
|
|
|
return;
|
|
}
|
|
|
|
struct msm_jpeg_hw_cmd hw_cmd_we_ping_update[] = {
|
|
/* type, repeat n times, offset, mask, data or pdata */
|
|
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN0_WR_PNTR_ADDR,
|
|
JPEG_PLN0_WR_PNTR_BMSK, {0} },
|
|
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN1_WR_PNTR_ADDR,
|
|
JPEG_PLN0_WR_PNTR_BMSK, {0} },
|
|
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_PLN2_WR_PNTR_ADDR,
|
|
JPEG_PLN0_WR_PNTR_BMSK, {0} },
|
|
};
|
|
|
|
void msm_jpeg_decode_status(void *base)
|
|
{
|
|
uint32_t data;
|
|
data = readl_relaxed(base + JPEG_DECODE_MCUS_DECODED_STATUS);
|
|
JPEG_DBG_HIGH("Decode MCUs decode status %u", data);
|
|
data = readl_relaxed(base + JPEG_DECODE_BITS_CONSUMED_STATUS);
|
|
JPEG_DBG_HIGH("Decode bits consumed status %u", data);
|
|
data = readl_relaxed(base + JPEG_DECODE_PRED_Y_STATE);
|
|
JPEG_DBG_HIGH("Decode prediction Y state %u", data);
|
|
data = readl_relaxed(base + JPEG_DECODE_PRED_C_STATE);
|
|
JPEG_DBG_HIGH("Decode prediction C state %u", data);
|
|
data = readl_relaxed(base + JPEG_DECODE_RSM_STATE);
|
|
JPEG_DBG_HIGH("Decode prediction RSM state %u", data);
|
|
}
|
|
|
|
|
|
void msm_jpeg_hw_we_buffer_update(struct msm_jpeg_hw_buf *p_input,
|
|
uint8_t pingpong_index, void *base)
|
|
{
|
|
struct msm_jpeg_hw_cmd *hw_cmd_p;
|
|
|
|
if (pingpong_index == 0) {
|
|
hw_cmd_p = &hw_cmd_we_ping_update[0];
|
|
hw_cmd_p->data = p_input->y_buffer_addr;
|
|
JPEG_PR_ERR("%s Output pln0 buffer address is %x\n", __func__,
|
|
p_input->y_buffer_addr);
|
|
msm_jpeg_hw_write(hw_cmd_p++, base);
|
|
hw_cmd_p->data = p_input->cbcr_buffer_addr;
|
|
JPEG_PR_ERR("%s Output pln1 buffer address is %x\n", __func__,
|
|
p_input->cbcr_buffer_addr);
|
|
msm_jpeg_hw_write(hw_cmd_p++, base);
|
|
hw_cmd_p->data = p_input->pln2_addr;
|
|
JPEG_PR_ERR("%s Output pln2 buffer address is %x\n", __func__,
|
|
p_input->pln2_addr);
|
|
msm_jpeg_hw_write(hw_cmd_p++, base);
|
|
}
|
|
return;
|
|
}
|
|
|
|
struct msm_jpeg_hw_cmd hw_cmd_reset[] = {
|
|
/* type, repeat n times, offset, mask, data or pdata */
|
|
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_MASK_ADDR,
|
|
JPEG_IRQ_MASK_BMSK, {JPEG_IRQ_DISABLE_ALL} },
|
|
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_CLEAR_ADDR,
|
|
JPEG_IRQ_MASK_BMSK, {JPEG_IRQ_CLEAR_ALL} },
|
|
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_IRQ_MASK_ADDR,
|
|
JPEG_IRQ_MASK_BMSK, {JPEG_IRQ_ALLSOURCES_ENABLE} },
|
|
{MSM_JPEG_HW_CMD_TYPE_WRITE, 1, JPEG_RESET_CMD_ADDR,
|
|
JPEG_RESET_CMD_RMSK, {JPEG_RESET_DEFAULT} },
|
|
};
|
|
|
|
void msm_jpeg_hw_reset(void *base, int size)
|
|
{
|
|
struct msm_jpeg_hw_cmd *hw_cmd_p;
|
|
|
|
hw_cmd_p = &hw_cmd_reset[0];
|
|
wmb();
|
|
msm_jpeg_hw_write(hw_cmd_p++, base);
|
|
wmb();
|
|
msm_jpeg_hw_write(hw_cmd_p++, base);
|
|
wmb();
|
|
msm_jpeg_hw_write(hw_cmd_p++, base);
|
|
wmb();
|
|
msm_jpeg_hw_write(hw_cmd_p, base);
|
|
wmb();
|
|
|
|
return;
|
|
}
|
|
|
|
uint32_t msm_jpeg_hw_read(struct msm_jpeg_hw_cmd *hw_cmd_p,
|
|
void *jpeg_region_base)
|
|
{
|
|
uint32_t *paddr;
|
|
uint32_t data;
|
|
|
|
paddr = jpeg_region_base + hw_cmd_p->offset;
|
|
|
|
data = readl_relaxed(paddr);
|
|
data &= hw_cmd_p->mask;
|
|
|
|
return data;
|
|
}
|
|
|
|
void msm_jpeg_hw_write(struct msm_jpeg_hw_cmd *hw_cmd_p,
|
|
void *jpeg_region_base)
|
|
{
|
|
uint32_t *paddr;
|
|
uint32_t old_data, new_data;
|
|
|
|
paddr = jpeg_region_base + hw_cmd_p->offset;
|
|
|
|
if (hw_cmd_p->mask == 0xffffffff) {
|
|
old_data = 0;
|
|
} else {
|
|
old_data = readl_relaxed(paddr);
|
|
old_data &= ~hw_cmd_p->mask;
|
|
}
|
|
|
|
new_data = hw_cmd_p->data & hw_cmd_p->mask;
|
|
new_data |= old_data;
|
|
writel_relaxed(new_data, paddr);
|
|
}
|
|
|
|
int msm_jpeg_hw_wait(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_us,
|
|
void *base)
|
|
{
|
|
int tm = hw_cmd_p->n;
|
|
uint32_t data;
|
|
uint32_t wait_data = hw_cmd_p->data & hw_cmd_p->mask;
|
|
|
|
data = msm_jpeg_hw_read(hw_cmd_p, base);
|
|
if (data != wait_data) {
|
|
while (tm) {
|
|
udelay(m_us);
|
|
data = msm_jpeg_hw_read(hw_cmd_p, base);
|
|
if (data == wait_data)
|
|
break;
|
|
tm--;
|
|
}
|
|
}
|
|
hw_cmd_p->data = data;
|
|
return tm;
|
|
}
|
|
|
|
void msm_jpeg_hw_delay(struct msm_jpeg_hw_cmd *hw_cmd_p, int m_us)
|
|
{
|
|
int tm = hw_cmd_p->n;
|
|
while (tm) {
|
|
udelay(m_us);
|
|
tm--;
|
|
}
|
|
}
|
|
|
|
int msm_jpeg_hw_exec_cmds(struct msm_jpeg_hw_cmd *hw_cmd_p, uint32_t m_cmds,
|
|
uint32_t max_size, void *base)
|
|
{
|
|
int is_copy_to_user = -1;
|
|
uint32_t data;
|
|
|
|
while (m_cmds--) {
|
|
if (hw_cmd_p->offset > max_size) {
|
|
JPEG_PR_ERR("%s:%d] %d exceed hw region %d\n", __func__,
|
|
__LINE__, hw_cmd_p->offset, max_size);
|
|
return -EFAULT;
|
|
}
|
|
|
|
switch (hw_cmd_p->type) {
|
|
case MSM_JPEG_HW_CMD_TYPE_READ:
|
|
hw_cmd_p->data = msm_jpeg_hw_read(hw_cmd_p, base);
|
|
is_copy_to_user = 1;
|
|
break;
|
|
|
|
case MSM_JPEG_HW_CMD_TYPE_WRITE:
|
|
msm_jpeg_hw_write(hw_cmd_p, base);
|
|
break;
|
|
|
|
case MSM_JPEG_HW_CMD_TYPE_WRITE_OR:
|
|
data = msm_jpeg_hw_read(hw_cmd_p, base);
|
|
hw_cmd_p->data = (hw_cmd_p->data & hw_cmd_p->mask) |
|
|
data;
|
|
msm_jpeg_hw_write(hw_cmd_p, base);
|
|
break;
|
|
|
|
case MSM_JPEG_HW_CMD_TYPE_UWAIT:
|
|
msm_jpeg_hw_wait(hw_cmd_p, 1, base);
|
|
break;
|
|
|
|
case MSM_JPEG_HW_CMD_TYPE_MWAIT:
|
|
msm_jpeg_hw_wait(hw_cmd_p, 1000, base);
|
|
break;
|
|
|
|
case MSM_JPEG_HW_CMD_TYPE_UDELAY:
|
|
msm_jpeg_hw_delay(hw_cmd_p, 1);
|
|
break;
|
|
|
|
case MSM_JPEG_HW_CMD_TYPE_MDELAY:
|
|
msm_jpeg_hw_delay(hw_cmd_p, 1000);
|
|
break;
|
|
|
|
default:
|
|
JPEG_PR_ERR("wrong hw command type\n");
|
|
break;
|
|
}
|
|
|
|
hw_cmd_p++;
|
|
}
|
|
return is_copy_to_user;
|
|
}
|
|
|
|
void msm_jpeg_io_dump(void *base, int size)
|
|
{
|
|
char line_str[128], *p_str;
|
|
void __iomem *addr = (void __iomem *)base;
|
|
int i;
|
|
u32 *p = (u32 *) addr;
|
|
u32 data;
|
|
JPEG_DBG_HIGH("%s:%d] %p %d", __func__, __LINE__, addr, size);
|
|
line_str[0] = '\0';
|
|
p_str = line_str;
|
|
for (i = 0; i < size/4; i++) {
|
|
if (i % 4 == 0) {
|
|
snprintf(p_str, 12, "%08x: ", (u32) p);
|
|
p_str += 10;
|
|
}
|
|
data = readl_relaxed(p++);
|
|
snprintf(p_str, 12, "%08x ", data);
|
|
p_str += 9;
|
|
if ((i + 1) % 4 == 0) {
|
|
JPEG_DBG_HIGH("%s\n", line_str);
|
|
line_str[0] = '\0';
|
|
p_str = line_str;
|
|
}
|
|
}
|
|
if (line_str[0] != '\0')
|
|
JPEG_DBG_HIGH("%s\n", line_str);
|
|
}
|
|
|