blob: 7612a3046a7acaa5fc8bdaa8cc0656805cf01c34 [file] [log] [blame]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/io.h>
#include "auto_write.h"
#define FIRST_FRAME_OUTPUT_ADDR 0x40000000
static unsigned long auto_write_get_base(u32 p_type, void *base)
{
void __iomem *base_addr = NULL;
struct autowr_dev_base *dev_base = NULL;
dev_base = base;
switch (p_type) {
case AUTOWR_FR_PATH:
base_addr = dev_base->fr_base;
break;
case AUTOWR_DS1_PATH:
base_addr = dev_base->ds1_base;
break;
case AUTOWR_DS2_PATH:
base_addr = dev_base->ds2_base;
break;
default:
pr_err("Error path type\n");
break;
}
return (unsigned long)base_addr;
}
static unsigned int auto_write_frmae_cnt(void *base, void *frm_info)
{
u32 val = 0;
unsigned long base_addr = 0;
void __iomem *addr;
struct autowr_frm_info *f_info = NULL;
if (!frm_info || !base) {
pr_err("Error input param\n");
return val;
}
f_info = frm_info;
base_addr = auto_write_get_base(f_info->path_type, base);
if (base_addr == 0) {
pr_err("Failed to get base addr");
return 0;
}
addr = (void __iomem *)(base_addr + MIPI_BL_COUNT);
val = readl(addr);
return val;
}
static unsigned int auto_write_frmbuff_base(void *base, void *frm_info)
{
u32 val = 0;
unsigned long base_addr = 0;
void __iomem *addr;
struct autowr_frm_info *f_info = NULL;
if (!frm_info || !base) {
pr_err("Error input param\n");
return val;
}
f_info = frm_info;
base_addr = auto_write_get_base(f_info->path_type, base);
if (base_addr == 0) {
pr_err("Failed to get base addr");
return 0;
}
addr = (void __iomem *)(base_addr + MIPI_BL_FRAME_BUFFER_START_ADDR0);
val = readl(addr);
return val;
}
static unsigned int auto_write_frmbuff_size(void *base, void *frm_info)
{
u32 val = 0;
unsigned long base_addr = 0;
void __iomem *addr;
struct autowr_frm_info *f_info = NULL;
if (!frm_info || !base) {
pr_err("Error input param\n");
return val;
}
f_info = frm_info;
base_addr = auto_write_get_base(f_info->path_type, base);
if (base_addr == 0) {
pr_err("Failed to get base addr");
return 0;
}
addr = (void __iomem *)(base_addr + MIPI_BL_FRAME_BUF_SIZE0);
val = readl(addr);
return val;
}
static unsigned int auto_write_frame_size(void *base, void *frm_info)
{
u32 val = 0;
unsigned long base_addr = 0;
void __iomem *addr;
struct autowr_frm_info *f_info = NULL;
if (!frm_info || !base) {
pr_err("Error input param\n");
return val;
}
f_info = frm_info;
base_addr = auto_write_get_base(f_info->path_type, base);
if (base_addr == 0) {
pr_err("Failed to get base addr");
return 0;
}
addr = (void __iomem *)(base_addr + MIPI_BL_FRAME_SIZE0);
val = readl(addr);
return val;
}
static void auto_write_stop_capture(void *base, void *frm_info)
{
u32 val = 0;
unsigned long base_addr = 0;
void __iomem *addr;
struct autowr_frm_info *f_info = NULL;
if (!frm_info || !base) {
pr_err("Error input param\n");
return;
}
f_info = frm_info;
base_addr = auto_write_get_base(f_info->path_type, base);
if (base_addr == 0) {
pr_err("Failed to get base addr");
return;
}
addr = (void __iomem *)(base_addr + MIPI_BL_CTRL0);
val = readl(addr);
val = val & (~(1 << 13)) & (~(1 << 0));
writel(val, addr); // ladder disable
}
static void auto_write_save_frmbuf_base(void *base,
void *frm_info,
uint32_t frmbuf_base)
{
struct autowr_frm_info *f_info = NULL;
struct autowr_dev_base *dev_base = NULL;
if (!frm_info || !base) {
pr_err("Error input param\n");
return;
}
f_info = frm_info;
dev_base = base;
switch (f_info->path_type) {
case AUTOWR_FR_PATH:
dev_base->fr_frmbuf_base = frmbuf_base;
break;
case AUTOWR_DS1_PATH:
dev_base->ds1_frmbuf_base = frmbuf_base;
break;
case AUTOWR_DS2_PATH:
dev_base->ds2_frmbuf_base = frmbuf_base;
break;
default:
pr_err("Error path type\n");
break;
}
}
static unsigned int auto_write_get_frmbuf_base(void *base, void *frm_info)
{
u32 frmbuf_base = 0;
struct autowr_frm_info *f_info = NULL;
struct autowr_dev_base *dev_base = NULL;
if (!frm_info || !base) {
pr_err("Error input param\n");
return 0;
}
f_info = frm_info;
dev_base = base;
switch (f_info->path_type) {
case AUTOWR_FR_PATH:
frmbuf_base = dev_base->fr_frmbuf_base;
break;
case AUTOWR_DS1_PATH:
frmbuf_base = dev_base->ds1_frmbuf_base;
break;
case AUTOWR_DS2_PATH:
frmbuf_base = dev_base->ds2_frmbuf_base;
break;
default:
pr_err("Error path type\n");
break;
}
return frmbuf_base;
}
int autowr_get_frmbuf_info(void *base, void *frmbuf_info)
{
s32 rtn = -1;
struct autowr_frm_info frm_info;
struct autowr_frmbuf_info *fbuf_info = NULL;
struct autowr_dev_base *dev_base = NULL;
if (!base || !frmbuf_info) {
pr_err("Error input param\n");
return rtn;
}
dev_base = base;
fbuf_info = frmbuf_info;
frm_info.path_type = fbuf_info->path_type;
fbuf_info->frmbuf_base = auto_write_frmbuff_base(base, &frm_info);
fbuf_info->frmbuf_size = auto_write_frmbuff_size(base, &frm_info);
fbuf_info->frm_size = auto_write_frame_size(base, &frm_info);
rtn = 0;
return rtn;
}
int autowr_mmap_frmbuf_base(void *base, void *p_vma)
{
s32 rtn = -1;
unsigned long vsize = 0;
unsigned long pfn = 0;
u32 frmbuf_base = 0;
struct vm_area_struct *vma = NULL;
struct autowr_dev_base *dev_base = NULL;
struct autowr_frm_info frm_info;
if (!base || !p_vma) {
pr_err("Error input param\n");
return rtn;
}
dev_base = base;
vma = p_vma;
vsize = vma->vm_end - vma->vm_start;
frm_info.path_type = dev_base->f_mmap;
frmbuf_base = auto_write_frmbuff_base(base, &frm_info);
pfn = frmbuf_base >> PAGE_SHIFT;
rtn = remap_pfn_range(vma, vma->vm_start,
pfn,
vsize,
vma->vm_page_prot);
if (rtn != 0)
pr_err("Failed to remap frame buff\n");
return rtn;
}
int autowr_get_frminfo(void *base, void *frm_info)
{
s32 rtn = 0;
u32 f_cnt = 0;
u32 fbuf_base = 0;
u32 p_fbuf_base = 0;
u32 fbuf_size = 0;
u32 f_size = 0;
u32 fbuf_cnt = 0;
u32 wr_cnt = 0;
u32 wr_pos = 0;
u32 p_cnt = 0;
struct autowr_frm_info *f_info = NULL;
struct autowr_dev_base *dev_base = NULL;
if (!frm_info || !base) {
pr_err("Error input param\n");
return rtn;
}
f_info = frm_info;
dev_base = base;
fbuf_size = auto_write_frmbuff_size(base, frm_info);
f_size = auto_write_frame_size(base, frm_info);
fbuf_cnt = fbuf_size / f_size;
f_cnt = auto_write_frmae_cnt(base, frm_info);
wr_cnt = f_cnt / fbuf_cnt;
wr_pos = f_cnt % fbuf_cnt;
if (wr_cnt == 0) {
if (f_info->frame_idx >= wr_pos) {
f_info->input_addr = 0;
f_info->output_addr = 0;
return rtn;
}
fbuf_base = auto_write_frmbuff_base(base, frm_info);
if (f_info->frame_idx == 0) {
f_info->input_addr = fbuf_base;
f_info->output_addr = FIRST_FRAME_OUTPUT_ADDR;
} else {
f_info->input_addr =
fbuf_base + f_info->frame_idx * f_size;
f_info->output_addr =
fbuf_base + (f_info->frame_idx - 1) * f_size;
}
} else {
fbuf_base = auto_write_frmbuff_base(base, frm_info);
if (f_info->frame_idx == 0) {
f_info->input_addr = fbuf_base + wr_pos * f_size;
f_info->output_addr = FIRST_FRAME_OUTPUT_ADDR;
auto_write_save_frmbuf_base(base,
frm_info,
f_info->input_addr);
} else {
p_fbuf_base =
auto_write_get_frmbuf_base(base, frm_info);
f_info->input_addr =
p_fbuf_base + f_info->frame_idx * f_size;
f_info->output_addr =
p_fbuf_base + (f_info->frame_idx - 1) * f_size;
if (f_info->input_addr >= (fbuf_base + fbuf_size)) {
p_cnt = (f_info->input_addr - fbuf_base) /
fbuf_size;
f_info->input_addr =
f_info->input_addr - p_cnt * fbuf_size;
}
if (f_info->output_addr >= (fbuf_base + fbuf_size)) {
p_cnt = (f_info->output_addr - fbuf_base) /
fbuf_size;
f_info->output_addr =
f_info->output_addr - p_cnt * fbuf_size;
}
if (f_info->input_addr ==
(fbuf_base + wr_pos * f_size)) {
f_info->input_addr = 0;
f_info->output_addr = 0;
}
}
}
return rtn;
}
int autowr_stop_capture(void *base, void *frm_info)
{
s32 rtn = -1;
if (!frm_info || !base) {
pr_err("Error input param\n");
return rtn;
}
auto_write_stop_capture(base, frm_info);
return 0;
}