blob: 84abadfa467aac8862d18429550a7298b954d875 [file] [log] [blame]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include <linux/version.h>
#include <linux/string.h>
#include <linux/io.h>
#include <linux/mm.h>
#include <linux/uaccess.h>
#include <linux/delay.h>
#include <linux/major.h>
#include <linux/sched.h>
#include <linux/vmalloc.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/platform_device.h>
#include <linux/amlogic/media/vout/lcd/aml_ldim.h>
#include "../../lcd_common.h"
#include "ldim_drv.h"
void ldc_mem_dump(unsigned char *vaddr, unsigned int size)
{
char *buf;
unsigned char *p;
unsigned int i, j, k, n;
if (!vaddr) {
LDIMERR("%s: vaddr is null\n", __func__);
return;
}
buf = kcalloc(128, sizeof(char), GFP_KERNEL);
if (!buf)
return;
p = vaddr;
for (i = 0; i < size; i += 16) {
n = 0;
for (j = 0; j < 16; j++) {
k = i * 16 + j;
n += sprintf(buf + n, " %02x", p[k]);
}
pr_info("%08x:%s\n", i, buf);
}
kfree(buf);
}
void ldc_mem_save(char *path, unsigned long mem_paddr, unsigned int mem_size)
{
struct file *filp = NULL;
loff_t pos = 0;
mm_segment_t old_fs = get_fs();
unsigned int span = 0, remain = 0, count = 0;
unsigned long phys;
void *vaddr = NULL;
unsigned int highmem_flag = 0;
int i;
pos = 0;
set_fs(KERNEL_DS);
filp = filp_open(path, O_RDWR | O_CREAT, 0666);
if (IS_ERR(filp)) {
pr_info("%s: create %s error\n", __func__, path);
set_fs(old_fs);
return;
}
highmem_flag = PageHighMem(phys_to_page(mem_paddr));
LDIMPR("%s: highmem_flag: %d\n", __func__, highmem_flag);
if (highmem_flag == 0) {
vaddr = phys_to_virt(mem_paddr);
if (!vaddr)
goto lcd_ldc_axi_rmem_save_end;
LDIMPR("%s: directly write: paddr=0x%lx, vaddr=0x%px, size: 0x%x\n",
__func__, mem_paddr, vaddr, mem_size);
vfs_write(filp, vaddr, mem_size, &pos);
} else {
span = SZ_1M;
count = mem_size / PAGE_ALIGN(span);
remain = mem_size % PAGE_ALIGN(span);
for (i = 0; i < count; i++) {
phys = mem_paddr + i * span;
vaddr = lcd_vmap(phys, span);
if (!vaddr)
goto lcd_ldc_axi_rmem_save_end;
LDIMPR("%s: write: paddr=0x%lx, vaddr=0x%px, size: 0x%x\n",
__func__, phys, vaddr, span);
vfs_write(filp, vaddr, span, &pos);
lcd_unmap_phyaddr(vaddr);
}
if (remain) {
phys = mem_paddr + count * span;
vaddr = lcd_vmap(phys, remain);
if (!vaddr)
goto lcd_ldc_axi_rmem_save_end;
LDIMPR("%s: write: paddr=0x%lx, vaddr=0x%px, size: 0x%x\n",
__func__, phys, vaddr, remain);
vfs_write(filp, vaddr, remain, &pos);
lcd_unmap_phyaddr(vaddr);
}
}
vfs_fsync(filp, 0);
filp_close(filp, NULL);
set_fs(old_fs);
LDIMPR("save buf to %s finished\n", path);
return;
lcd_ldc_axi_rmem_save_end:
vfs_fsync(filp, 0);
filp_close(filp, NULL);
set_fs(old_fs);
LDIMERR("buf mapping failed: 0x%lx\n", mem_paddr);
}
void ldc_mem_write(char *path, unsigned long mem_paddr, unsigned int mem_size)
{
unsigned int size;
struct file *filp = NULL;
loff_t pos = 0;
mm_segment_t old_fs = get_fs();
unsigned int span = 0, remain = 0, count = 0;
unsigned long phys;
void *vaddr = NULL;
unsigned int highmem_flag = 0;
unsigned char *buf, *p;
int i, ret;
pos = 0;
buf = vmalloc(mem_size);
if (!buf)
return;
set_fs(KERNEL_DS);
filp = filp_open(path, O_RDONLY, 0);
if (IS_ERR_OR_NULL(filp)) {
pr_info("read %s error or filp is NULL.\n", path);
set_fs(old_fs);
vfree(buf);
return;
}
ret = vfs_read(filp, buf, mem_size, &pos);
if (ret < 0) {
pr_info("read %s error\n", path);
filp_close(filp, NULL);
set_fs(old_fs);
vfree(buf);
return;
}
size = ret;
pr_info("%s: read %s size %u\n", __func__, path, size);
vfs_fsync(filp, 0);
filp_close(filp, NULL);
set_fs(old_fs);
highmem_flag = PageHighMem(phys_to_page(mem_paddr));
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL)
LDIMPR("%s: highmem_flag: %d\n", __func__, highmem_flag);
if (highmem_flag == 0) {
vaddr = phys_to_virt(mem_paddr);
if (!vaddr)
goto lcd_ldc_axi_rmem_write_end;
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL)
LDIMPR("%s: directly write: paddr=0x%lx, vaddr=0x%px, size: 0x%x\n",
__func__, mem_paddr, vaddr, size);
memcpy(vaddr, buf, size);
} else {
span = SZ_1M;
count = size / PAGE_ALIGN(span);
remain = size % PAGE_ALIGN(span);
for (i = 0; i < count; i++) {
phys = mem_paddr + i * span;
vaddr = lcd_vmap(phys, span);
if (!vaddr)
goto lcd_ldc_axi_rmem_write_end;
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL)
LDIMPR("%s: write: paddr=0x%lx, vaddr=0x%px, size: 0x%x\n",
__func__, phys, vaddr, span);
p = buf + i * span;
memcpy(vaddr, p, span);
lcd_unmap_phyaddr(vaddr);
}
if (remain) {
phys = mem_paddr + count * span;
vaddr = lcd_vmap(phys, remain);
if (!vaddr)
goto lcd_ldc_axi_rmem_write_end;
if (lcd_debug_print_flag & LCD_DBG_PR_BL_NORMAL)
LDIMPR("%s: write: paddr=0x%lx, vaddr=0x%px, size: 0x%x\n",
__func__, phys, vaddr, remain);
p = buf + count * span;
memcpy(vaddr, p, remain);
lcd_unmap_phyaddr(vaddr);
}
}
vfree(buf);
LDIMPR("write %s to buf finished\n", path);
return;
lcd_ldc_axi_rmem_write_end:
vfree(buf);
LDIMERR("buf mapping failed: 0x%lx\n", mem_paddr);
}
void ldc_mem_clear(unsigned long mem_paddr, unsigned int mem_size)
{
unsigned int span = 0, remain = 0, count = 0;
unsigned long phys;
void *vaddr = NULL;
unsigned int highmem_flag = 0;
int i;
highmem_flag = PageHighMem(phys_to_page(mem_paddr));
LDIMPR("%s: highmem_flag: %d\n", __func__, highmem_flag);
if (highmem_flag == 0) {
vaddr = phys_to_virt(mem_paddr);
if (!vaddr)
goto ldc_rmem_clear_end;
LDIMPR("%s: directly clear: paddr=0x%lx, vaddr=0x%px, size: 0x%x\n",
__func__, mem_paddr, vaddr, mem_size);
memset(vaddr, 0, mem_size);
} else {
span = SZ_1M;
count = mem_size / PAGE_ALIGN(span);
remain = mem_size % PAGE_ALIGN(span);
for (i = 0; i < count; i++) {
phys = mem_paddr + i * span;
vaddr = lcd_vmap(phys, span);
if (!vaddr)
goto ldc_rmem_clear_end;
LDIMPR("%s: clear: paddr=0x%lx, vaddr=0x%px, size: 0x%x\n",
__func__, phys, vaddr, span);
memset(vaddr, 0, span);
lcd_unmap_phyaddr(vaddr);
}
if (remain) {
phys = mem_paddr + count * span;
vaddr = lcd_vmap(phys, remain);
if (!vaddr)
goto ldc_rmem_clear_end;
LDIMPR("%s: clear: paddr=0x%lx, vaddr=0x%px, size: 0x%x\n",
__func__, phys, vaddr, remain);
memset(vaddr, 0, remain);
lcd_unmap_phyaddr(vaddr);
}
}
LDIMPR("%s: finished\n", __func__);
return;
ldc_rmem_clear_end:
LDIMERR("buf mapping failed: 0x%lx\n", mem_paddr);
}
void ldc_mem_set(unsigned long mem_paddr, unsigned int mem_size)
{
unsigned int span = 0, remain = 0, count = 0;
unsigned long phys;
void *vaddr = NULL;
unsigned int highmem_flag = 0;
int i;
highmem_flag = PageHighMem(phys_to_page(mem_paddr));
LDIMPR("%s: highmem_flag: %d\n", __func__, highmem_flag);
if (highmem_flag == 0) {
vaddr = phys_to_virt(mem_paddr);
if (!vaddr)
goto ldc_rmem_set_end;
LDIMPR("%s: set: paddr=0x%lx, vaddr=0x%px, size:0x%x\n",
__func__, mem_paddr, vaddr, mem_size);
memset(vaddr, 0xff, mem_size);
} else {
span = SZ_1M;
count = mem_size / PAGE_ALIGN(span);
remain = mem_size % PAGE_ALIGN(span);
for (i = 0; i < count; i++) {
phys = mem_paddr + i * span;
vaddr = lcd_vmap(phys, span);
if (!vaddr)
goto ldc_rmem_set_end;
LDIMPR("%s: set: paddr=0x%lx, vaddr=0x%px, size:0x%x\n",
__func__, phys, vaddr, span);
memset(vaddr, 0xff, span);
lcd_unmap_phyaddr(vaddr);
}
if (remain) {
phys = mem_paddr + count * span;
vaddr = lcd_vmap(phys, remain);
if (!vaddr)
goto ldc_rmem_set_end;
LDIMPR("%s: set: paddr=0x%lx, vaddr=0x%px, size:0x%x\n",
__func__, phys, vaddr, remain);
memset(vaddr, 0xff, remain);
lcd_unmap_phyaddr(vaddr);
}
}
LDIMPR("%s: finished\n", __func__);
return;
ldc_rmem_set_end:
LDIMERR("buf mapping failed: 0x%lx\n", mem_paddr);
}