mirror of
https://github.com/hardkernel/kernel_common_drivers.git
synced 2026-06-25 12:03:48 +09:00
ambilight: support ambilight for t3x [1/1]
PD#SWPL-128669 Problem: need support ambilight driver Solution: add ambilight driver support for t3x Verify: bc302 Change-Id: Ic4b998006eaf09ec5f3fd9a9d5da736ca2ec385a Signed-off-by: Evoke Zhang <evoke.zhang@amlogic.com>
This commit is contained in:
committed by
gerrit autosubmit
parent
f38b40750a
commit
02750fb3ea
@@ -2251,6 +2251,14 @@
|
||||
interrupt-names = "vsync";
|
||||
};
|
||||
|
||||
ambilight: ambilight {
|
||||
compatible = "amlogic, ambilight-t3x";
|
||||
status = "disabled";
|
||||
interrupts = <0 115 1>;
|
||||
interrupt-names = "vsync";
|
||||
zone_h_v = <32 20>;
|
||||
};
|
||||
|
||||
ir: ir@8000 {
|
||||
compatible = "amlogic, meson-ir";
|
||||
reg = <0x0 0xfe084040 0x0 0x44>,
|
||||
|
||||
@@ -1861,6 +1861,11 @@
|
||||
};
|
||||
};
|
||||
|
||||
&ambilight {
|
||||
status = "okay";
|
||||
zone_h_v = <32 20>;
|
||||
};
|
||||
|
||||
&amhdmitx {
|
||||
status = "disabled";
|
||||
pxp_mode = <1>; /* run on pxp */
|
||||
|
||||
@@ -1838,6 +1838,11 @@
|
||||
};
|
||||
};
|
||||
|
||||
&ambilight {
|
||||
status = "okay";
|
||||
zone_h_v = <32 20>;
|
||||
};
|
||||
|
||||
&amhdmitx {
|
||||
status = "disabled";
|
||||
pxp_mode = <1>; /* run on pxp */
|
||||
|
||||
@@ -171,6 +171,7 @@ CONFIG_AMLOGIC_BL_EXTERN=y
|
||||
CONFIG_AMLOGIC_BL_LDIM=y
|
||||
CONFIG_AMLOGIC_BL_LDIM_IW7027=y
|
||||
CONFIG_AMLOGIC_BL_LDIM_BLMCU=y
|
||||
CONFIG_AMLOGIC_AMBILIGHT=y
|
||||
CONFIG_AMLOGIC_CVBS_OUTPUT=y
|
||||
CONFIG_AMLOGIC_WSS=y
|
||||
CONFIG_AMLOGIC_VDAC=y
|
||||
|
||||
@@ -53,6 +53,7 @@ static int __init media_main_init(void)
|
||||
call_sub_init(aml_bl_init);
|
||||
call_sub_init(aml_bl_extern_init);
|
||||
call_sub_init(ldim_dev_init);
|
||||
call_sub_init(ambilight_init);
|
||||
call_sub_init(peripheral_lcd_init);
|
||||
call_sub_init(dummy_venc_init);
|
||||
call_sub_init(vout_sys_serve_init);
|
||||
|
||||
@@ -517,6 +517,15 @@ static inline int aml_bl_init(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_AMBILIGHT
|
||||
int ambilight_init(void);
|
||||
#else
|
||||
static inline int ambilight_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_MEDIA_DEINTERLACE
|
||||
int dil_init(void);
|
||||
int di_module_init(void);
|
||||
|
||||
@@ -37,6 +37,7 @@ config AMLOGIC_LCD_TABLET
|
||||
if AMLOGIC_LCD
|
||||
source "$(COMMON_DRIVERS_DIR)/drivers/media/vout/lcd/backlight/Kconfig"
|
||||
source "$(COMMON_DRIVERS_DIR)/drivers/media/vout/lcd/lcd_extern/Kconfig"
|
||||
source "$(COMMON_DRIVERS_DIR)/drivers/media/vout/lcd/ambilight/Kconfig"
|
||||
endif
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -19,10 +19,12 @@ include $(COMMON_DRIVERS_DIR)/drivers/media/vout/lcd/lcd_tv/Makefile
|
||||
|
||||
include $(COMMON_DRIVERS_DIR)/drivers/media/vout/lcd/lcd_tablet/Makefile
|
||||
|
||||
include $(COMMON_DRIVERS_DIR)/drivers/media/vout/lcd/lcd_clk/Makefile
|
||||
|
||||
include $(COMMON_DRIVERS_DIR)/drivers/media/vout/lcd/lcd_phy/Makefile
|
||||
|
||||
include $(COMMON_DRIVERS_DIR)/drivers/media/vout/lcd/lcd_extern/Makefile
|
||||
|
||||
include $(COMMON_DRIVERS_DIR)/drivers/media/vout/lcd/backlight/Makefile
|
||||
|
||||
include $(COMMON_DRIVERS_DIR)/drivers/media/vout/lcd/lcd_clk/Makefile
|
||||
|
||||
include $(COMMON_DRIVERS_DIR)/drivers/media/vout/lcd/lcd_phy/Makefile
|
||||
include $(COMMON_DRIVERS_DIR)/drivers/media/vout/lcd/ambilight/Makefile
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
||||
|
||||
#
|
||||
# Ambilight configuration
|
||||
#
|
||||
menu "Amlogic Ambilight Support"
|
||||
|
||||
config AMLOGIC_AMBILIGHT
|
||||
bool "Amlogic ambilight support"
|
||||
default n
|
||||
help
|
||||
Say Y here if you want to use the Ambilight.
|
||||
Ambilight can provide rgb sum for each zone.
|
||||
|
||||
endmenu
|
||||
@@ -0,0 +1,4 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
||||
|
||||
$(MEDIA_MODULE_NAME)-$(CONFIG_AMLOGIC_AMBILIGHT) += vout/lcd/ambilight/ambilight_drv.o
|
||||
$(MEDIA_MODULE_NAME)-$(CONFIG_AMLOGIC_AMBILIGHT) += vout/lcd/ambilight/ambilight_debug.o
|
||||
@@ -0,0 +1,145 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
|
||||
/*
|
||||
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _AMBILIGHT_H_
|
||||
#define _AMBILIGHT_H_
|
||||
#include <linux/amlogic/media/vout/lcd/lcd_vout.h>
|
||||
|
||||
//20230613, init version
|
||||
#define AMBLT_DRV_VER "20230613"
|
||||
|
||||
#define AMBLTPR(fmt, args...) pr_info("ambilight: " fmt "", ## args)
|
||||
#define AMBLTERR(fmt, args...) pr_err("error: ambilight: " fmt "", ## args)
|
||||
|
||||
#define AMBLT_CLASS_NAME "amblt"
|
||||
#define AMBLT_DEVICE_NAME "amblt"
|
||||
|
||||
enum LUT_DMA_WR_ID_e {
|
||||
LC_STTS_0_DMA_ID = 0,
|
||||
LC_STTS_1_DMA_ID = 1,
|
||||
VI_HIST_SPL_0_DMA_ID = 2,
|
||||
VI_HIST_SPL_1_DMA_ID = 3,
|
||||
CM2_HIST_0_DMA_ID = 4,
|
||||
CM2_HIST_1_DMA_ID = 5,
|
||||
VD1_HDR_0_DMA_ID = 6,
|
||||
VD1_HDR_1_DMA_ID = 7,
|
||||
VD2_HDR_DMA_ID = 8,
|
||||
AMBLT_DMA_ID = 9,
|
||||
LUT_WR_MAX_ID = 10
|
||||
};
|
||||
|
||||
struct vpu_lut_dma_wr_s {
|
||||
enum LUT_DMA_WR_ID_e dma_wr_id;
|
||||
unsigned int wr_sel;
|
||||
unsigned int offset;
|
||||
unsigned int stride;
|
||||
unsigned int baddr0;
|
||||
unsigned int baddr1;
|
||||
unsigned int addr_mode;
|
||||
unsigned int rpt_num;
|
||||
};
|
||||
|
||||
struct amblt_dma_mem_s {
|
||||
unsigned char flag;
|
||||
void *vaddr;
|
||||
phys_addr_t paddr;
|
||||
unsigned int size;
|
||||
};
|
||||
|
||||
struct amblt_data_sum_s {
|
||||
unsigned int sum_b;
|
||||
unsigned int sum_g;
|
||||
unsigned int sum_r;
|
||||
unsigned short x;
|
||||
unsigned short y;
|
||||
};
|
||||
|
||||
struct amblt_data_s {
|
||||
unsigned int sum_r;
|
||||
unsigned int sum_g;
|
||||
unsigned int sum_b;
|
||||
unsigned short avg_r;
|
||||
unsigned short avg_g;
|
||||
unsigned short avg_b;
|
||||
unsigned char err;
|
||||
};
|
||||
|
||||
struct amblt_drv_data_s {
|
||||
enum lcd_chip_e chip_type;
|
||||
const char *chip_name;
|
||||
unsigned int zone_h_max;
|
||||
unsigned int zone_v_max;
|
||||
unsigned int zone_size_max;
|
||||
unsigned int zone_size_min;
|
||||
};
|
||||
|
||||
#define AMBLT_STATE_EN BIT(0)
|
||||
|
||||
struct amblt_drv_s {
|
||||
unsigned int state;
|
||||
unsigned int en;
|
||||
unsigned int zone_h;
|
||||
unsigned int zone_v;
|
||||
unsigned int zone_size;
|
||||
unsigned int zone_pixel;
|
||||
unsigned int frm_idex;
|
||||
unsigned int dbg_level;
|
||||
|
||||
struct amblt_drv_data_s *drv_data;
|
||||
struct amblt_dma_mem_s dma_mem;
|
||||
struct vpu_lut_dma_wr_s lut_dma;
|
||||
struct amblt_data_s *buf;
|
||||
|
||||
dev_t devno;
|
||||
struct cdev cdev;
|
||||
struct device *dev;
|
||||
struct class *clsp;
|
||||
struct resource *res_vs_irq;
|
||||
spinlock_t isr_lock; //for vsync ir
|
||||
struct mutex power_mutex; //for on/off sequence
|
||||
};
|
||||
|
||||
extern unsigned int amblt_debug_print;
|
||||
|
||||
void amblt_zone_pixel_init(struct amblt_drv_s *amblt_drv);
|
||||
int amblt_debug_file_add(struct amblt_drv_s *amblt_drv);
|
||||
int amblt_debug_file_remove(struct amblt_drv_s *amblt_drv);
|
||||
int amblt_function_enable(struct amblt_drv_s *amblt_drv);
|
||||
int amblt_function_disable(struct amblt_drv_s *amblt_drv);
|
||||
|
||||
/********************ioctl************************/
|
||||
#define AMBLT_IOC_TYPE 'B'
|
||||
#define AMBLT_IOC_EN_CTRL 0x1
|
||||
#define AMBLT_IOC_GET_ZONE_SIZE 0x2
|
||||
#define AMBLT_IOC_GET_DATA 0x3
|
||||
|
||||
#define AMBLT_IOC_CMD_POWER_CTRL \
|
||||
_IOW(AMBLT_IOC_TYPE, AMBLT_IOC_EN_CTRL, unsigned int)
|
||||
#define AMBLT_IOC_CMD_GET_SS \
|
||||
_IOR(AMBLT_IOC_TYPE, AMBLT_IOC_GET_ZONE_SIZE, unsigned int)
|
||||
|
||||
/********************regs************************/
|
||||
#define LCD_OLED_SIZE 0x14ec
|
||||
#define LDC_REG_INPUT_STAT_NUM 0x14ef
|
||||
|
||||
#define VPU_DMA_WRMIF_CTRL 0x27d5
|
||||
#define VPU_DMA_WRMIF0_CTRL 0x27d6
|
||||
#define VPU_DMA_WRMIF1_CTRL 0x27d7
|
||||
#define VPU_DMA_WRMIF2_CTRL 0x27d8
|
||||
#define VPU_DMA_WRMIF3_CTRL 0x27d9
|
||||
#define VPU_DMA_WRMIF4_CTRL 0x27da
|
||||
#define VPU_DMA_WRMIF0_BADR0 0x27de
|
||||
#define VPU_DMA_WRMIF0_BADR1 0x27df
|
||||
#define VPU_DMA_WRMIF1_BADR0 0x27e0
|
||||
#define VPU_DMA_WRMIF1_BADR1 0x27e1
|
||||
#define VPU_DMA_WRMIF2_BADR0 0x27e2
|
||||
#define VPU_DMA_WRMIF2_BADR1 0x27e3
|
||||
#define VPU_DMA_WRMIF3_BADR0 0x27e4
|
||||
#define VPU_DMA_WRMIF3_BADR1 0x27e5
|
||||
#define VPU_DMA_WRMIF4_BADR0 0x27e6
|
||||
#define VPU_DMA_WRMIF4_BADR1 0x27e7
|
||||
#define VPU_DMA_WRMIF_SEL 0x27ee
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,517 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
||||
/*
|
||||
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/of_reserved_mem.h>
|
||||
#include <linux/cma.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/sched/clock.h>
|
||||
#include <linux/amlogic/pm.h>
|
||||
#include "ambilight.h"
|
||||
#include "../lcd_reg.h"
|
||||
|
||||
static void amblt_buffer_dump(struct amblt_drv_s *amblt_drv)
|
||||
{
|
||||
unsigned int *vaddr;
|
||||
char *print_buf;
|
||||
int i, j, n, len;
|
||||
|
||||
if (amblt_drv->dma_mem.flag == 0) {
|
||||
AMBLTERR("dma_mem is null\n");
|
||||
return;
|
||||
}
|
||||
|
||||
vaddr = amblt_drv->dma_mem.vaddr;
|
||||
print_buf = kzalloc(20 * 3 + 10, GFP_KERNEL);
|
||||
if (!print_buf) {
|
||||
AMBLTERR("print_buf is null\n");
|
||||
return;
|
||||
}
|
||||
pr_info("ambilight buffer:\n");
|
||||
for (i = 0; i < amblt_drv->zone_size; i++) {
|
||||
len = 0;
|
||||
n = i * 4;
|
||||
for (j = 0; j < 4; j++)
|
||||
len += sprintf(print_buf + len, " 0x%08x", vaddr[n + j]);
|
||||
pr_info("[%d]:%s\n", i, print_buf);
|
||||
}
|
||||
pr_info("\n");
|
||||
kfree(print_buf);
|
||||
}
|
||||
|
||||
static void amblt_data_sum_dump(struct amblt_drv_s *amblt_drv)
|
||||
{
|
||||
struct amblt_data_s *data;
|
||||
char *print_buf;
|
||||
int x, y, n, len;
|
||||
|
||||
if (!amblt_drv->buf) {
|
||||
AMBLTERR("data buf is null\n");
|
||||
return;
|
||||
}
|
||||
|
||||
print_buf = kzalloc(5 * 30 + 10, GFP_KERNEL);
|
||||
if (!print_buf) {
|
||||
AMBLTERR("print_buf is null\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (y = 0; y < amblt_drv->zone_v; y++) {
|
||||
for (x = 0; x < amblt_drv->zone_h; x++) {
|
||||
len = 0;
|
||||
n = y * amblt_drv->zone_h + x;
|
||||
data = amblt_drv->buf + n;
|
||||
len += sprintf(print_buf + len, " %8d %8d %8d",
|
||||
data->sum_r, data->sum_g, data->sum_b);
|
||||
if (data->err)
|
||||
len += sprintf(print_buf + len, " (x)");
|
||||
pr_info("[x:%02d, y:%02d]: %s\n", x, y, print_buf);
|
||||
}
|
||||
}
|
||||
|
||||
kfree(print_buf);
|
||||
}
|
||||
|
||||
static void amblt_data_avg_dump(struct amblt_drv_s *amblt_drv)
|
||||
{
|
||||
struct amblt_data_s *data;
|
||||
char *print_buf;
|
||||
int x, y, n, len;
|
||||
|
||||
if (!amblt_drv->buf) {
|
||||
AMBLTERR("data buf is null\n");
|
||||
return;
|
||||
}
|
||||
|
||||
print_buf = kzalloc(5 * 20 + 10, GFP_KERNEL);
|
||||
if (!print_buf) {
|
||||
AMBLTERR("print_buf is null\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (y = 0; y < amblt_drv->zone_v; y++) {
|
||||
for (x = 0; x < amblt_drv->zone_h; x++) {
|
||||
len = 0;
|
||||
n = y * amblt_drv->zone_h + x;
|
||||
data = amblt_drv->buf + n;
|
||||
len += sprintf(print_buf + len, " %3d %3d %3d",
|
||||
data->avg_r, data->avg_g, data->avg_b);
|
||||
if (data->err)
|
||||
len += sprintf(print_buf + len, " (x)");
|
||||
pr_info("[x:%02d, y:%02d]: %s\n", x, y, print_buf);
|
||||
}
|
||||
}
|
||||
|
||||
kfree(print_buf);
|
||||
}
|
||||
|
||||
ssize_t amblt_status_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct amblt_drv_s *amblt_drv = dev_get_drvdata(dev);
|
||||
ssize_t len = 0;
|
||||
|
||||
if (!amblt_drv)
|
||||
return sprintf(buf, "amblt_drv is NULL\n");
|
||||
|
||||
len = sprintf(buf, "ambilight status:\n"
|
||||
"en: %d\n"
|
||||
"state: 0x%x\n"
|
||||
"zone_h: %d\n"
|
||||
"zone_v: %d\n"
|
||||
"zone_size: %d\n"
|
||||
"zone_size: %d\n"
|
||||
"dbg_level: 0x%x\n\n",
|
||||
amblt_drv->en,
|
||||
amblt_drv->state,
|
||||
amblt_drv->zone_h,
|
||||
amblt_drv->zone_v,
|
||||
amblt_drv->zone_size,
|
||||
amblt_drv->zone_pixel,
|
||||
amblt_drv->dbg_level);
|
||||
|
||||
len += sprintf(buf + len, "ambilight lut_dma:\n"
|
||||
"dma_wr_id: %d\n"
|
||||
"wr_sel: %d\n"
|
||||
"offset: %d\n"
|
||||
"stride: %d\n"
|
||||
"rpt_num: %d\n"
|
||||
"addr_mode: %d\n"
|
||||
"baddr0: 0x%08x\n"
|
||||
"baddr1: 0x%08x\n\n",
|
||||
amblt_drv->lut_dma.dma_wr_id,
|
||||
amblt_drv->lut_dma.wr_sel,
|
||||
amblt_drv->lut_dma.offset,
|
||||
amblt_drv->lut_dma.stride,
|
||||
amblt_drv->lut_dma.rpt_num,
|
||||
amblt_drv->lut_dma.addr_mode,
|
||||
amblt_drv->lut_dma.baddr0,
|
||||
amblt_drv->lut_dma.baddr1);
|
||||
|
||||
lcd_vcbus_write(VPU_DMA_WRMIF_SEL, (0xff0 + amblt_drv->lut_dma.wr_sel));
|
||||
len += sprintf(buf + len, "ambilight regs:\n");
|
||||
len += sprintf(buf + len, "LDC_REG_INPUT_STAT_NUM 0x%04x = 0x%08x\n",
|
||||
LDC_REG_INPUT_STAT_NUM, lcd_vcbus_read(LDC_REG_INPUT_STAT_NUM));
|
||||
len += sprintf(buf + len, "LCD_OLED_SIZE 0x%04x = 0x%08x\n",
|
||||
LCD_OLED_SIZE, lcd_vcbus_read(LCD_OLED_SIZE));
|
||||
len += sprintf(buf + len, "VPU_DMA_WRMIF_SEL 0x%04x = 0x%08x\n",
|
||||
VPU_DMA_WRMIF_SEL, lcd_vcbus_read(VPU_DMA_WRMIF_SEL));
|
||||
len += sprintf(buf + len, "VPU_DMA_WRMIF_CTRL 0x%04x = 0x%08x\n",
|
||||
VPU_DMA_WRMIF_CTRL, lcd_vcbus_read(VPU_DMA_WRMIF_CTRL));
|
||||
len += sprintf(buf + len, "VPU_DMA_WRMIF1_CTRL 0x%04x = 0x%08x\n",
|
||||
VPU_DMA_WRMIF1_CTRL, lcd_vcbus_read(VPU_DMA_WRMIF1_CTRL));
|
||||
len += sprintf(buf + len, "VPU_DMA_WRMIF1_BADR0 0x%04x = 0x%08x\n",
|
||||
VPU_DMA_WRMIF1_BADR0, lcd_vcbus_read(VPU_DMA_WRMIF1_BADR0));
|
||||
len += sprintf(buf + len, "VPU_DMA_WRMIF1_BADR1 0x%04x = 0x%08x\n",
|
||||
VPU_DMA_WRMIF1_BADR1, lcd_vcbus_read(VPU_DMA_WRMIF1_BADR1));
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static const char *amblt_debug_usage_str = {
|
||||
"Usage:\n"
|
||||
" cat /sys/class/amblt/amblt/status\n"
|
||||
" echo 0 >/sys/class/amblt/amblt/enable\n"
|
||||
" echo 1 >/sys/class/amblt/amblt/enable\n"
|
||||
" echo reg >/sys/class/amblt/amblt/debug\n"
|
||||
" echo data >/sys/class/amblt/amblt/debug\n"
|
||||
" echo buffer >/sys/class/amblt/amblt/debug\n"
|
||||
" echo 1 >/sys/class/amblt/amblt/print\n"
|
||||
};
|
||||
|
||||
static ssize_t amblt_debug_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%s\n", amblt_debug_usage_str);
|
||||
}
|
||||
|
||||
static ssize_t amblt_debug_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct amblt_drv_s *amblt_drv = dev_get_drvdata(dev);
|
||||
unsigned int data[5];
|
||||
int ret;
|
||||
|
||||
if (!buf)
|
||||
return count;
|
||||
if (!amblt_drv)
|
||||
return count;
|
||||
|
||||
switch (buf[0]) {
|
||||
case 'z': //zone
|
||||
ret = sscanf(buf, "zone %d %d", &data[0], &data[1]);
|
||||
if (ret == 2) {
|
||||
amblt_drv->zone_h = data[0];
|
||||
amblt_drv->zone_v = data[1];
|
||||
amblt_drv->zone_size = data[0] * data[1];
|
||||
}
|
||||
pr_info("zone_h=%d, zone_v=%d\n",
|
||||
amblt_drv->zone_h, amblt_drv->zone_v);
|
||||
break;
|
||||
case 'r': //reg
|
||||
pr_info("LDC_REG_INPUT_STAT_NUM 0x%04x = 0x%08x\n",
|
||||
LDC_REG_INPUT_STAT_NUM, lcd_vcbus_read(LDC_REG_INPUT_STAT_NUM));
|
||||
pr_info("LCD_OLED_SIZE 0x%04x = 0x%08x\n",
|
||||
LCD_OLED_SIZE, lcd_vcbus_read(LCD_OLED_SIZE));
|
||||
pr_info("VPU_DMA_WRMIF_CTRL 0x%04x = 0x%08x\n",
|
||||
VPU_DMA_WRMIF_CTRL, lcd_vcbus_read(VPU_DMA_WRMIF_CTRL));
|
||||
pr_info("VPU_DMA_WRMIF_SEL 0x%04x = 0x%08x\n",
|
||||
VPU_DMA_WRMIF_SEL, lcd_vcbus_read(VPU_DMA_WRMIF_SEL));
|
||||
pr_info("VPU_DMA_WRMIF1_CTRL 0x%04x = 0x%08x\n",
|
||||
VPU_DMA_WRMIF1_CTRL, lcd_vcbus_read(VPU_DMA_WRMIF1_CTRL));
|
||||
pr_info("VPU_DMA_WRMIF1_BADR0 0x%04x = 0x%08x\n",
|
||||
VPU_DMA_WRMIF1_BADR0, lcd_vcbus_read(VPU_DMA_WRMIF1_BADR0));
|
||||
pr_info("VPU_DMA_WRMIF1_BADR1 0x%04x = 0x%08x\n",
|
||||
VPU_DMA_WRMIF1_BADR1, lcd_vcbus_read(VPU_DMA_WRMIF1_BADR1));
|
||||
break;
|
||||
case 'd': //dma
|
||||
ret = sscanf(buf, "dma %d %d %d", &data[0], &data[1], &data[2]);
|
||||
if (ret == 3) {
|
||||
amblt_drv->lut_dma.stride = data[0];
|
||||
amblt_drv->lut_dma.rpt_num = data[1];
|
||||
amblt_drv->lut_dma.addr_mode = data[2];
|
||||
}
|
||||
pr_info("lut_dma: stride=%d, rpt_num=%d, addr_mode=%d\n",
|
||||
amblt_drv->lut_dma.stride,
|
||||
amblt_drv->lut_dma.rpt_num,
|
||||
amblt_drv->lut_dma.addr_mode);
|
||||
break;
|
||||
case 'b': //buffer
|
||||
amblt_buffer_dump(amblt_drv);
|
||||
break;
|
||||
case 's': //sum
|
||||
amblt_data_sum_dump(amblt_drv);
|
||||
break;
|
||||
case 'a': //avg
|
||||
amblt_data_avg_dump(amblt_drv);
|
||||
break;
|
||||
default:
|
||||
pr_info("invalid cmd\n");
|
||||
break;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t amblt_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct amblt_drv_s *amblt_drv = dev_get_drvdata(dev);
|
||||
unsigned int temp;
|
||||
|
||||
temp = (amblt_drv->state & AMBLT_STATE_EN) ? 1 : 0;
|
||||
|
||||
return sprintf(buf, "%d\n", temp);
|
||||
}
|
||||
|
||||
static ssize_t amblt_enable_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct amblt_drv_s *amblt_drv = dev_get_drvdata(dev);
|
||||
unsigned int temp, zone_h, zone_v;
|
||||
int ret;
|
||||
|
||||
if (!buf)
|
||||
return count;
|
||||
|
||||
ret = sscanf(buf, "%d %d %d", &temp, &zone_h, &zone_v);
|
||||
if (ret == 3) {
|
||||
if (temp) {
|
||||
amblt_drv->zone_h = zone_h;
|
||||
amblt_drv->zone_v = zone_v;
|
||||
amblt_drv->zone_size = zone_h * zone_v;
|
||||
amblt_zone_pixel_init(amblt_drv);
|
||||
amblt_function_enable(amblt_drv);
|
||||
} else {
|
||||
amblt_function_disable(amblt_drv);
|
||||
}
|
||||
} else if (ret == 1) {
|
||||
if (temp)
|
||||
amblt_function_enable(amblt_drv);
|
||||
else
|
||||
amblt_function_disable(amblt_drv);
|
||||
} else {
|
||||
pr_info("invalid data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t amblt_print_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%d\n", amblt_debug_print);
|
||||
}
|
||||
|
||||
static ssize_t amblt_print_store(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned int temp;
|
||||
int ret;
|
||||
|
||||
if (!buf)
|
||||
return count;
|
||||
|
||||
ret = kstrtouint(buf, 16, &temp);
|
||||
if (ret) {
|
||||
pr_info("invalid data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
amblt_debug_print = (unsigned int)temp;
|
||||
pr_info("set debug print flag: 0x%x\n", amblt_debug_print);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct device_attribute amblt_debug_attrs[] = {
|
||||
__ATTR(status, 0444, amblt_status_show, NULL),
|
||||
__ATTR(debug, 0644, amblt_debug_show, amblt_debug_store),
|
||||
__ATTR(enable, 0644, amblt_enable_show, amblt_enable_store),
|
||||
__ATTR(print, 0644, amblt_print_show, amblt_print_store)
|
||||
};
|
||||
|
||||
/* ************************************************************* */
|
||||
/* vout ioctl */
|
||||
/* ************************************************************* */
|
||||
static int amblt_io_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct amblt_drv_s *amblt_drv;
|
||||
|
||||
if (amblt_debug_print)
|
||||
AMBLTPR("amblt io_open\n");
|
||||
amblt_drv = container_of(inode->i_cdev, struct amblt_drv_s, cdev);
|
||||
file->private_data = amblt_drv;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amblt_io_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
if (amblt_debug_print)
|
||||
AMBLTPR("amblt io_release\n");
|
||||
file->private_data = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long amblt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct amblt_drv_s *amblt_drv;
|
||||
void __user *argp;
|
||||
int mcd_nr;
|
||||
unsigned int temp;
|
||||
int ret = 0;
|
||||
|
||||
amblt_drv = (struct amblt_drv_s *)file->private_data;
|
||||
if (!amblt_drv)
|
||||
return -1;
|
||||
|
||||
mcd_nr = _IOC_NR(cmd);
|
||||
if (amblt_debug_print) {
|
||||
AMBLTPR("%s: cmd: 0x%x, cmd_dir = 0x%x, cmd_nr = 0x%x\n",
|
||||
__func__, cmd, _IOC_DIR(cmd), mcd_nr);
|
||||
}
|
||||
|
||||
argp = (void __user *)arg;
|
||||
switch (mcd_nr) {
|
||||
case AMBLT_IOC_EN_CTRL:
|
||||
if (copy_from_user(&temp, argp, sizeof(unsigned int)))
|
||||
ret = -EFAULT;
|
||||
if (amblt_debug_print)
|
||||
AMBLTPR("%s: AMBLT_IOC_EN_CTRL: %d\n", __func__, temp);
|
||||
if (temp)
|
||||
amblt_function_enable(amblt_drv);
|
||||
else
|
||||
amblt_function_disable(amblt_drv);
|
||||
break;
|
||||
case AMBLT_IOC_GET_ZONE_SIZE:
|
||||
if (amblt_debug_print) {
|
||||
AMBLTPR("%s: AMBLT_IOC_GET_ZONE_SIZE: %d\n",
|
||||
__func__, amblt_drv->zone_size);
|
||||
}
|
||||
|
||||
temp = amblt_drv->zone_size;
|
||||
if (copy_to_user(argp, &temp, sizeof(unsigned int)))
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
default:
|
||||
AMBLTERR("%s: invalid mcd_nr 0x%x\n", __func__, mcd_nr);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
static long amblt_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
unsigned long ret;
|
||||
|
||||
arg = (unsigned long)compat_ptr(arg);
|
||||
ret = amblt_ioctl(file, cmd, arg);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct file_operations amblt_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = amblt_io_open,
|
||||
.release = amblt_io_release,
|
||||
.unlocked_ioctl = amblt_ioctl,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = amblt_compat_ioctl,
|
||||
#endif
|
||||
};
|
||||
|
||||
int amblt_debug_file_add(struct amblt_drv_s *amblt_drv)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
amblt_drv->clsp = class_create(THIS_MODULE, AMBLT_CLASS_NAME);
|
||||
if (IS_ERR(amblt_drv->clsp)) {
|
||||
AMBLTERR("failed to create class\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = alloc_chrdev_region(&amblt_drv->devno, 0, 1, AMBLT_DEVICE_NAME);
|
||||
if (ret < 0) {
|
||||
AMBLTERR("failed to alloc major number\n");
|
||||
goto err1;
|
||||
}
|
||||
|
||||
amblt_drv->dev = device_create(amblt_drv->clsp, NULL,
|
||||
amblt_drv->devno, (void *)amblt_drv, AMBLT_DEVICE_NAME);
|
||||
if (IS_ERR(amblt_drv->dev)) {
|
||||
AMBLTERR("failed to create device\n");
|
||||
goto err2;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(amblt_debug_attrs); i++) {
|
||||
if (device_create_file(amblt_drv->dev, &amblt_debug_attrs[i])) {
|
||||
AMBLTERR("tcon: create tcon debug attribute %s fail\n",
|
||||
amblt_debug_attrs[i].attr.name);
|
||||
goto err3;
|
||||
}
|
||||
}
|
||||
|
||||
/* connect the file operations with cdev */
|
||||
cdev_init(&amblt_drv->cdev, &amblt_fops);
|
||||
amblt_drv->cdev.owner = THIS_MODULE;
|
||||
|
||||
/* connect the major/minor number to the cdev */
|
||||
ret = cdev_add(&amblt_drv->cdev, amblt_drv->devno, 1);
|
||||
if (ret) {
|
||||
AMBLTERR("failed to add device\n");
|
||||
goto err4;
|
||||
}
|
||||
|
||||
AMBLTPR("%s: OK\n", __func__);
|
||||
return 0;
|
||||
|
||||
err4:
|
||||
for (i = 0; i < ARRAY_SIZE(amblt_debug_attrs); i++)
|
||||
device_remove_file(amblt_drv->dev, &amblt_debug_attrs[i]);
|
||||
err3:
|
||||
device_destroy(amblt_drv->clsp, amblt_drv->devno);
|
||||
amblt_drv->dev = NULL;
|
||||
err2:
|
||||
unregister_chrdev_region(amblt_drv->devno, 1);
|
||||
err1:
|
||||
class_destroy(amblt_drv->clsp);
|
||||
amblt_drv->clsp = NULL;
|
||||
AMBLTERR("%s error\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int amblt_debug_file_remove(struct amblt_drv_s *amblt_drv)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(amblt_debug_attrs); i++)
|
||||
device_remove_file(amblt_drv->dev, &amblt_debug_attrs[i]);
|
||||
|
||||
cdev_del(&amblt_drv->cdev);
|
||||
device_destroy(amblt_drv->clsp, amblt_drv->devno);
|
||||
amblt_drv->dev = NULL;
|
||||
class_destroy(amblt_drv->clsp);
|
||||
amblt_drv->clsp = NULL;
|
||||
unregister_chrdev_region(amblt_drv->devno, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,454 @@
|
||||
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
||||
/*
|
||||
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/of_reserved_mem.h>
|
||||
#include <linux/cma.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/sched/clock.h>
|
||||
#include <linux/amlogic/pm.h>
|
||||
#include "ambilight.h"
|
||||
#include "../lcd_reg.h"
|
||||
|
||||
unsigned int amblt_debug_print;
|
||||
|
||||
static void vpu_lut_dma_clr_fcnt(struct vpu_lut_dma_wr_s *lut_dma)
|
||||
{
|
||||
lcd_vcbus_write(VPU_DMA_WRMIF_SEL, (0xff0 + lut_dma->wr_sel));
|
||||
lcd_vcbus_setb(VPU_DMA_WRMIF0_CTRL + lut_dma->offset, 1, 30, 1);
|
||||
}
|
||||
|
||||
static void set_vpu_lut_dma_mif_wr(struct vpu_lut_dma_wr_s *lut_dma, int flag)
|
||||
{
|
||||
unsigned int ofst = lut_dma->offset;
|
||||
|
||||
if (flag) {
|
||||
//Bit 31 ro_lut_wr_hs_r // unsigned , RO , default = 0
|
||||
//Bit 30:27 ro_lut_wr_id // unsigned , RO , default = 0
|
||||
//Bit 26 pls_hold_clr // unsigned , pls , default = 0
|
||||
//Bit 25 ro_hold_timeout // unsigned , RO , default = 0
|
||||
//Bit 24:12 ro_wrmif_cnt // unsigned , RO , default = 0
|
||||
//Bit 11:4 reg_hold_line // unsigned , RW, default = 8'hff
|
||||
//Bit 3 ro_lut_wr_hs_s // unsigned , RO , default = 0
|
||||
//Bit 2 wrmif_hw_reset // unsigned , RW , default = 0
|
||||
//Bit 1 lut_wr_cnt_sel // unsigned , RW , default = 0
|
||||
//Bit 0 lut_wr_reg_sel // unsigned , RW , default = 0,
|
||||
// 0: sel lut0,1,2,...,7 1:sel lut8,9,...,15
|
||||
lcd_vcbus_write(VPU_DMA_WRMIF_SEL, (0xff0 + lut_dma->wr_sel));
|
||||
lcd_vcbus_write(VPU_DMA_WRMIF0_CTRL + ofst,
|
||||
((lut_dma->addr_mode & 0x3) << 28) |
|
||||
((lut_dma->rpt_num & 0xff) << 18) |
|
||||
(1 << 16) | //chn_enable
|
||||
(lut_dma->stride & 0x1fff));
|
||||
lcd_vcbus_write(VPU_DMA_WRMIF0_BADR0 + (ofst << 1), lut_dma->baddr0);
|
||||
lcd_vcbus_write(VPU_DMA_WRMIF0_BADR1 + (ofst << 1), lut_dma->baddr1);
|
||||
} else {
|
||||
lcd_vcbus_write(VPU_DMA_WRMIF_SEL, (0xff0 + lut_dma->wr_sel));
|
||||
lcd_vcbus_setb(VPU_DMA_WRMIF0_CTRL + ofst, 0, 16, 1); //chn_disable
|
||||
}
|
||||
}
|
||||
|
||||
static void amblt_hw_ctrl(struct amblt_drv_s *amblt_drv)
|
||||
{
|
||||
if (amblt_drv->en) {
|
||||
set_vpu_lut_dma_mif_wr(&amblt_drv->lut_dma, 1);
|
||||
|
||||
lcd_vcbus_setb(LDC_REG_INPUT_STAT_NUM, amblt_drv->zone_h, 0, 6); //x num
|
||||
lcd_vcbus_setb(LDC_REG_INPUT_STAT_NUM, amblt_drv->zone_v, 8, 5); //y num
|
||||
lcd_vcbus_setb(LDC_REG_INPUT_STAT_NUM, 1, 15, 1); //reverse vs pol
|
||||
lcd_vcbus_setb(LDC_REG_INPUT_STAT_NUM, 1, 21, 1); //reverse vs pol
|
||||
lcd_vcbus_setb(LDC_REG_INPUT_STAT_NUM, 1, 16, 1); //en
|
||||
//AMBLTPR("LDC_REG_INPUT_STAT_NUM 0x%04x = 0x%08x\n",
|
||||
// LDC_REG_INPUT_STAT_NUM, lcd_vcbus_read(LDC_REG_INPUT_STAT_NUM));
|
||||
amblt_drv->state |= AMBLT_STATE_EN;
|
||||
if (amblt_debug_print) {
|
||||
AMBLTPR("ambilight enable: zone x:%d, y:%d\n",
|
||||
amblt_drv->zone_h, amblt_drv->zone_v);
|
||||
}
|
||||
} else {
|
||||
amblt_drv->state &= ~AMBLT_STATE_EN;
|
||||
lcd_vcbus_setb(LDC_REG_INPUT_STAT_NUM, 0, 16, 1);
|
||||
set_vpu_lut_dma_mif_wr(&amblt_drv->lut_dma, 0);
|
||||
if (amblt_debug_print)
|
||||
AMBLTPR("ambilight disable\n");
|
||||
}
|
||||
}
|
||||
|
||||
int amblt_function_enable(struct amblt_drv_s *amblt_drv)
|
||||
{
|
||||
struct amblt_dma_mem_s *dma_mem = &amblt_drv->dma_mem;
|
||||
|
||||
if (dma_mem->flag == 0) {
|
||||
AMBLTERR("%s: dma memory failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
if (amblt_drv->state & AMBLT_STATE_EN) {
|
||||
AMBLTPR("%s: already enabled\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
amblt_drv->lut_dma.rpt_num = (amblt_drv->zone_size + 3) / 4;
|
||||
vpu_lut_dma_clr_fcnt(&amblt_drv->lut_dma);
|
||||
|
||||
AMBLTPR("ambilight mem paddr: 0x%x, vaddr: 0x%px, size: 0x%x, zone_h=%d, zone_v=%d\n",
|
||||
(unsigned int)dma_mem->paddr, dma_mem->vaddr, dma_mem->size,
|
||||
amblt_drv->zone_h, amblt_drv->zone_v);
|
||||
memset(dma_mem->vaddr, 0, dma_mem->size);
|
||||
|
||||
amblt_drv->en = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int amblt_function_disable(struct amblt_drv_s *amblt_drv)
|
||||
{
|
||||
if ((amblt_drv->state & AMBLT_STATE_EN) == 0) {
|
||||
AMBLTPR("%s: already disabled\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
amblt_drv->en = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void amblt_data_refersh(struct amblt_drv_s *amblt_drv)
|
||||
{
|
||||
struct amblt_data_sum_s *sum, *p;
|
||||
int x, y, n;
|
||||
|
||||
if (amblt_drv->dma_mem.flag == 0)
|
||||
return;
|
||||
if (!amblt_drv->buf)
|
||||
return;
|
||||
|
||||
p = (struct amblt_data_sum_s *)amblt_drv->dma_mem.vaddr;
|
||||
for (y = 0; y < amblt_drv->zone_v; y++) {
|
||||
for (x = 0; x < amblt_drv->zone_h; x++) {
|
||||
n = y * amblt_drv->zone_h + x;
|
||||
sum = p + n;
|
||||
amblt_drv->buf[n].sum_r = sum->sum_r;
|
||||
amblt_drv->buf[n].sum_g = sum->sum_g;
|
||||
amblt_drv->buf[n].sum_b = sum->sum_b;
|
||||
amblt_drv->buf[n].avg_r = sum->sum_r / amblt_drv->zone_pixel;
|
||||
amblt_drv->buf[n].avg_g = sum->sum_g / amblt_drv->zone_pixel;
|
||||
amblt_drv->buf[n].avg_b = sum->sum_b / amblt_drv->zone_pixel;
|
||||
if (x != sum->x || y != sum->y)
|
||||
amblt_drv->buf[n].err = 1;
|
||||
else
|
||||
amblt_drv->buf[n].err = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t amblt_vsync_isr(int irq, void *data)
|
||||
{
|
||||
struct amblt_drv_s *amblt_drv = (struct amblt_drv_s *)data;
|
||||
unsigned int state;
|
||||
|
||||
if (!amblt_drv)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
state = amblt_drv->state & AMBLT_STATE_EN;
|
||||
if (amblt_drv->en != state) {
|
||||
amblt_hw_ctrl(amblt_drv);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (state)
|
||||
amblt_data_refersh(amblt_drv);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int amblt_vsync_irq_init(struct amblt_drv_s *amblt_drv)
|
||||
{
|
||||
if (!amblt_drv->res_vs_irq)
|
||||
return -1;
|
||||
|
||||
if (request_irq(amblt_drv->res_vs_irq->start,
|
||||
amblt_vsync_isr, IRQF_SHARED, "amblt_vs", (void *)amblt_drv)) {
|
||||
AMBLTERR("can't request amblt_vsync_isr\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void amblt_vsync_irq_remove(struct amblt_drv_s *amblt_drv)
|
||||
{
|
||||
if (amblt_drv->res_vs_irq)
|
||||
free_irq(amblt_drv->res_vs_irq->start, (void *)amblt_drv);
|
||||
}
|
||||
|
||||
static int amblt_get_config(struct amblt_drv_s *amblt_drv, struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *of_node;
|
||||
unsigned int para[2];
|
||||
int ret;
|
||||
|
||||
of_node = pdev->dev.of_node;
|
||||
ret = of_property_read_u32_array(of_node, "zone_h_v", ¶[0], 2);
|
||||
if (ret) {
|
||||
AMBLTERR("%s: get zone_h_v error\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
amblt_drv->zone_h = para[0];
|
||||
amblt_drv->zone_v = para[1];
|
||||
amblt_drv->zone_size = para[0] * para[1];
|
||||
AMBLTPR("%s: zone h=%d, v=%d, size=%d\n",
|
||||
__func__, amblt_drv->zone_h, amblt_drv->zone_v, amblt_drv->zone_size);
|
||||
amblt_zone_pixel_init(amblt_drv);
|
||||
|
||||
amblt_drv->res_vs_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "vsync");
|
||||
if (!amblt_drv->res_vs_irq) {
|
||||
AMBLTERR("%s: can't get vsync irq\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void amblt_zone_pixel_init(struct amblt_drv_s *amblt_drv)
|
||||
{
|
||||
struct aml_lcd_drv_s *pdrv = aml_lcd_get_driver(0);
|
||||
unsigned int h_active, v_active, h_pixel, v_pixel;
|
||||
|
||||
if (!pdrv)
|
||||
return;
|
||||
h_active = pdrv->config.basic.h_active;
|
||||
v_active = pdrv->config.basic.v_active;
|
||||
|
||||
h_pixel = h_active / amblt_drv->zone_h;
|
||||
v_pixel = v_active / amblt_drv->zone_v;
|
||||
amblt_drv->zone_pixel = h_pixel * v_pixel;
|
||||
AMBLTPR("%s: %d x %d = %d\n", __func__, h_pixel, v_pixel, amblt_drv->zone_pixel);
|
||||
|
||||
kfree(amblt_drv->buf);
|
||||
amblt_drv->buf = kcalloc(amblt_drv->zone_size, sizeof(struct amblt_data_s), GFP_KERNEL);
|
||||
if (!amblt_drv->buf)
|
||||
AMBLTERR("%s: data buf is NULL\n", __func__);
|
||||
}
|
||||
|
||||
static void amblt_lut_dma_init(struct amblt_drv_s *amblt_drv)
|
||||
{
|
||||
struct vpu_lut_dma_wr_s *lut_dma = &amblt_drv->lut_dma;
|
||||
unsigned int rpt_num;
|
||||
|
||||
rpt_num = (amblt_drv->zone_size + 3) / 4;
|
||||
|
||||
lut_dma->dma_wr_id = AMBLT_DMA_ID;
|
||||
lut_dma->wr_sel = 1;
|
||||
lut_dma->offset = AMBLT_DMA_ID - 8;
|
||||
lut_dma->stride = 4;//0x280; //8; //unit:128bit
|
||||
lut_dma->baddr0 = amblt_drv->dma_mem.paddr >> 4;
|
||||
lut_dma->baddr1 = amblt_drv->dma_mem.paddr >> 4;
|
||||
lut_dma->addr_mode = 1;//0; //1;
|
||||
lut_dma->rpt_num = rpt_num;
|
||||
|
||||
lcd_vcbus_setb(VPU_DMA_WRMIF_CTRL, 1, 13, 1);//wr dma enable
|
||||
}
|
||||
|
||||
static int amblt_dma_malloc(struct amblt_drv_s *amblt_drv, struct device *dev)
|
||||
{
|
||||
struct amblt_dma_mem_s *dma_mem = &amblt_drv->dma_mem;
|
||||
unsigned int mem_size;
|
||||
|
||||
mem_size = 32 * 20 * 16; //byte
|
||||
dma_mem->size = mem_size;
|
||||
dma_mem->vaddr = dma_alloc_coherent(dev, mem_size, &dma_mem->paddr, GFP_KERNEL);
|
||||
if (!dma_mem->vaddr) {
|
||||
AMBLTERR("%s: failed! dma_mem size: 0x%x\n", __func__, mem_size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
dma_mem->flag = 1;
|
||||
AMBLTPR("%s: dma paddr: 0x%lx, vaddr: 0x%px, size: 0x%x, flag: %d\n",
|
||||
__func__, (unsigned long)dma_mem->paddr, dma_mem->vaddr,
|
||||
dma_mem->size, dma_mem->flag);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ************************************************************* */
|
||||
/* amblt driver data */
|
||||
/* ************************************************************* */
|
||||
static struct amblt_drv_data_s amblt_data_t3x = {
|
||||
.chip_type = LCD_CHIP_T3X,
|
||||
.chip_name = "t3x",
|
||||
.zone_h_max = 32,
|
||||
.zone_v_max = 20,
|
||||
.zone_size_max = 640,
|
||||
.zone_size_min = 4,
|
||||
};
|
||||
|
||||
static const struct of_device_id amblt_dt_match_table[] = {
|
||||
{
|
||||
.compatible = "amlogic, ambilight-t3x",
|
||||
.data = &amblt_data_t3x,
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static int amblt_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct amblt_drv_s *amblt_drv;
|
||||
const struct of_device_id *match;
|
||||
struct amblt_drv_data_s *amblt_data;
|
||||
int ret = 0;
|
||||
|
||||
match = of_match_device(amblt_dt_match_table, &pdev->dev);
|
||||
if (!match) {
|
||||
AMBLTERR("%s: no match table\n", __func__);
|
||||
goto amblt_probe_err_0;
|
||||
}
|
||||
amblt_data = (struct amblt_drv_data_s *)match->data;
|
||||
AMBLTPR("driver version: %s(%d-%s)\n",
|
||||
AMBLT_DRV_VER,
|
||||
amblt_data->chip_type,
|
||||
amblt_data->chip_name);
|
||||
|
||||
amblt_drv = kzalloc(sizeof(*amblt_drv), GFP_KERNEL);
|
||||
if (!amblt_drv)
|
||||
goto amblt_probe_err_0;
|
||||
|
||||
amblt_drv->dev = &pdev->dev;
|
||||
amblt_drv->drv_data = amblt_data;
|
||||
platform_set_drvdata(pdev, amblt_drv);
|
||||
|
||||
ret = amblt_get_config(amblt_drv, pdev);
|
||||
if (ret)
|
||||
goto amblt_probe_err_1;
|
||||
|
||||
ret = amblt_dma_malloc(amblt_drv, &pdev->dev);
|
||||
if (ret)
|
||||
goto amblt_probe_err_1;
|
||||
amblt_lut_dma_init(amblt_drv);
|
||||
spin_lock_init(&amblt_drv->isr_lock);
|
||||
mutex_init(&amblt_drv->power_mutex);
|
||||
|
||||
amblt_debug_file_add(amblt_drv);
|
||||
ret = amblt_vsync_irq_init(amblt_drv);
|
||||
if (ret)
|
||||
goto amblt_probe_err_2;
|
||||
|
||||
AMBLTPR("driver probe ok\n");
|
||||
|
||||
return 0;
|
||||
|
||||
amblt_probe_err_2:
|
||||
amblt_debug_file_remove(amblt_drv);
|
||||
amblt_probe_err_1:
|
||||
/* free drvdata */
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
/* free drv */
|
||||
kfree(amblt_drv);
|
||||
amblt_probe_err_0:
|
||||
AMBLTERR("driver probe failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int amblt_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct amblt_drv_s *amblt_drv = platform_get_drvdata(pdev);
|
||||
|
||||
if (!amblt_drv)
|
||||
return 0;
|
||||
|
||||
amblt_vsync_irq_remove(amblt_drv);
|
||||
amblt_debug_file_remove(amblt_drv);
|
||||
|
||||
/* free drvdata */
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
kfree(amblt_drv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amblt_resume(struct platform_device *pdev)
|
||||
{
|
||||
struct amblt_drv_s *amblt_drv = platform_get_drvdata(pdev);
|
||||
|
||||
if (!amblt_drv)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&amblt_drv->power_mutex);
|
||||
AMBLTPR("resume done\n");
|
||||
mutex_unlock(&amblt_drv->power_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amblt_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
{
|
||||
struct amblt_drv_s *amblt_drv = platform_get_drvdata(pdev);
|
||||
|
||||
if (!amblt_drv)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&amblt_drv->power_mutex);
|
||||
AMBLTPR("suspend done\n");
|
||||
mutex_unlock(&amblt_drv->power_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void amblt_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
struct amblt_drv_s *amblt_drv = platform_get_drvdata(pdev);
|
||||
|
||||
if (!amblt_drv)
|
||||
return;
|
||||
|
||||
AMBLTPR("shutdown done\n");
|
||||
}
|
||||
|
||||
static struct platform_driver ambilight_platform_driver = {
|
||||
.probe = amblt_probe,
|
||||
.remove = amblt_remove,
|
||||
.suspend = amblt_suspend,
|
||||
.resume = amblt_resume,
|
||||
.shutdown = amblt_shutdown,
|
||||
.driver = {
|
||||
.name = "ambilight",
|
||||
.owner = THIS_MODULE,
|
||||
#ifdef CONFIG_OF
|
||||
.of_match_table = of_match_ptr(amblt_dt_match_table),
|
||||
#endif
|
||||
},
|
||||
};
|
||||
|
||||
int __init ambilight_init(void)
|
||||
{
|
||||
if (platform_driver_register(&ambilight_platform_driver)) {
|
||||
AMBLTERR("failed to register ambilight driver module\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __exit ambilight_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&ambilight_platform_driver);
|
||||
}
|
||||
Reference in New Issue
Block a user