| // 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; |
| } |