Merge "Merge Amlogic mainline partially." into odroidg12-4.9.y-android

This commit is contained in:
Chris
2020-08-26 15:41:49 +09:00
committed by Gerrit Code Review
158 changed files with 38397 additions and 3422 deletions

View File

@@ -14370,6 +14370,7 @@ F: drivers/amlogic/media/vout/vout_serve/vout2_notify.c
F: drivers/amlogic/media/vout/vout_serve/vout2_serve.c
F: drivers/amlogic/media/vout/vout_serve/vout_func.c
F: drivers/amlogic/media/vout/vout_serve/vout_func.h
F: drivers/amlogic/media/vout/vout_serve/vout_reg.h
AMLOGIC GPIO IRQ
M: Xingyu Chen <xingyu.chen@amlogic.com>
@@ -14759,6 +14760,7 @@ F: arch/arm64/boot/dts/amlogic/partition_mbox_ab_P_32.dtsi
AMLOGIC BACKLIGHT LDIM DRIVER
M: Evoke Zhang <evoke.zhang@amlogic.com>
F: drivers/amlogic/media/vout/backlight/aml_ldim/ldim_spi.c
F: drivers/amlogic/media/vout/backlight/aml_ldim/ldim_hw.c
AMLOGIC CAMERA DRIVER
M: Guosong Zhou <guosong.zhou@amlogic.com>

View File

@@ -104,6 +104,7 @@
DEBUGFS_CREATE_NODE(atvdemod_isr_en, 0640, dentry, bool)\
DEBUGFS_CREATE_NODE(atv_audio_overmodulated_cnt, 0640, dentry, u32)\
DEBUGFS_CREATE_NODE(support_secam_l, 0640, dentry, bool)\
DEBUGFS_CREATE_NODE(atvdemod_horiz_freq_det_en, 0640, dentry, bool)\
}

View File

@@ -44,8 +44,10 @@
#include "atvdemod_func.h"
#include "atvauddemod_func.h"
#define AMLATVDEMOD_VER "V2.13"
/********************************CODE CHANGE LIST*****************************/
/* Date --- Version --- Note *************************************************/
/* 2019/11/05 --- V2.15 --- Add dynamic monitoring line frequency deviation. */
#define AMLATVDEMOD_VER "V2.15"
struct aml_atvdemod_device *amlatvdemod_devp;
@@ -358,7 +360,7 @@ static ssize_t aml_atvdemod_store(struct class *class,
int blk = 0, reg = 0;
for (blk = 0; blk <= APB_BLOCK_ADDR_TOP; ++blk) {
for (reg = 0; reg <= 0x40; ++reg) {
for (reg = 0; reg < 0x40; ++reg) {
val = atv_dmd_rd_long(blk, reg);
pr_err("[0x%04x] = 0x%x.\n",
(blk << 8) + (reg << 2), val);

View File

@@ -37,6 +37,7 @@ bool audio_thd_en;
bool atvdemod_det_nonstd_en;
bool atvaudio_det_outputmode_en = true;
bool audio_carrier_offset_det_en;
bool atvdemod_horiz_freq_det_en = true;
unsigned int atvdemod_timer_delay = 100; /* 1s */
unsigned int atvdemod_timer_delay2 = 10; /* 100ms */
@@ -87,6 +88,9 @@ static void atv_demod_monitor_do_work(struct work_struct *work)
if (atvdemod_det_nonstd_en)
atv_dmd_non_std_set(true);
if (atvdemod_horiz_freq_det_en)
atvdemod_horiz_freq_detection();
}
static void atv_demod_monitor_timer_handler(unsigned long arg)

View File

@@ -129,6 +129,11 @@ int aml_atvdemod_get_btsc_sap_mode(void)
return btsc_sap_mode;
}
static bool atvdemod_check_exited(struct atv_demod_priv *priv)
{
return (priv->state != ATVDEMOD_STATE_WORK);
}
int atv_demod_enter_mode(struct dvb_frontend *fe)
{
int err_code = 0;
@@ -532,9 +537,16 @@ static void atvdemod_fe_try_analog_format(struct v4l2_frontend *v4l2_fe,
unsigned int broad_std = 0;
unsigned int audio = 0;
*video_fmt = 0;
*audio_fmt = 0;
*soundsys = 0;
if (auto_search_std & AUTO_DETECT_COLOR) {
for (i = 0; i < try_vfmt_cnt; i++) {
if (atvdemod_check_exited(priv))
return;
/* SECAM-L/L' */
if ((p->std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC))
&& (p->std & V4L2_COLOR_STD_SECAM)) {
@@ -719,6 +731,9 @@ static void atvdemod_fe_try_signal(struct v4l2_frontend *v4l2_fe,
*lock = false;
do {
if (atvdemod_check_exited(priv))
break;
if (tuner_id == AM_TUNER_MXL661) {
usleep_range(30 * 1000, 30 * 1000 + 100);
} else if (tuner_id == AM_TUNER_R840 ||
@@ -844,6 +859,9 @@ static int atvdemod_fe_afc_closer(struct v4l2_frontend *v4l2_fe, int minafcfreq,
set_freq = p->frequency;
while (abs(afc) > AFC_BEST_LOCK) {
if (atvdemod_check_exited(priv))
return -1;
if (tuner_id == AM_TUNER_MXL661)
usleep_range(30 * 1000, 30 * 1000 + 100);
else
@@ -1118,13 +1136,15 @@ static enum v4l2_search atvdemod_fe_search(struct v4l2_frontend *v4l2_fe)
v4l2_std_id std_bk = 0;
unsigned int audio = 0;
unsigned int soundsys = 0;
int double_check_cnt = 1;
/* int double_check_cnt = 1; */
int auto_search_std = 0;
int search_count = 0;
/* bool try_secam = false; */
int ret = -1;
unsigned int tuner_id = 0;
int priv_cfg = 0;
int exit_status = 0;
char *exit_str = "";
if (unlikely(!fe || !p ||
!fe->ops.tuner_ops.get_status ||
@@ -1137,7 +1157,7 @@ static enum v4l2_search atvdemod_fe_search(struct v4l2_frontend *v4l2_fe)
}
priv = fe->analog_demod_priv;
if (priv->state != ATVDEMOD_STATE_WORK) {
if (atvdemod_check_exited(priv)) {
pr_err("[%s] ATV state is not work.\n", __func__);
return V4L2_SEARCH_INVALID;
}
@@ -1217,6 +1237,11 @@ static enum v4l2_search atvdemod_fe_search(struct v4l2_frontend *v4l2_fe)
while (minafcfreq <= p->frequency &&
p->frequency <= maxafcfreq) {
if (atvdemod_check_exited(priv)) {
exit_status = 1;
break;
}
pr_dbg("[%s] [%d] is processing, [min=%d, max=%d].\n",
__func__, p->frequency, minafcfreq, maxafcfreq);
@@ -1250,6 +1275,9 @@ static enum v4l2_search atvdemod_fe_search(struct v4l2_frontend *v4l2_fe)
p->soundsys = soundsys;
std_bk = 0;
audio = 0;
} else {
exit_status = 1;
break;
}
/* sync param */
@@ -1265,9 +1293,12 @@ static enum v4l2_search atvdemod_fe_search(struct v4l2_frontend *v4l2_fe)
(uint32_t) p->std, p->frequency);
/* when manual search, just search current freq */
if (p->flag == ANALOG_FLAG_MANUL_SCAN)
if (p->flag == ANALOG_FLAG_MANUL_SCAN) {
exit_status = 2;
break;
}
#ifdef DOUBLE_CHECK_44_25MHZ
if (p->frequency >= 44200000 &&
p->frequency <= 44300000 &&
double_check_cnt) {
@@ -1278,10 +1309,22 @@ static enum v4l2_search atvdemod_fe_search(struct v4l2_frontend *v4l2_fe)
p->frequency += afc_step * ((search_count % 2) ?
-search_count : search_count);
}
#else
++search_count;
p->frequency += afc_step * ((search_count % 2) ?
-search_count : search_count);
#endif
}
pr_dbg("[%s] [%d] over of range [min=%d, max=%d], search failed.\n",
__func__, p->frequency, minafcfreq, maxafcfreq);
if (!exit_status)
exit_str = "over of range, search failed";
else if (exit_status == 1)
exit_str = "search exited";
else
exit_str = "search failed";
pr_dbg("[%s] [%d] %s.\n", __func__, p->frequency, exit_str);
p->frequency = set_freq;
priv_cfg = AML_ATVDEMOD_UNSCAN_MODE;

View File

@@ -872,7 +872,7 @@ void set_mono_dk(void)
{
int aa;
adec_wr_reg(ADDR_ADEC_CTRL, AUDIO_STANDARD_NICAM_DK);
adec_wr_reg(ADDR_ADEC_CTRL, AUDIO_STANDARD_NICAM_DK | (3 << 4));
set_filter(filter_100k, ADDR_DDC_FIR0_COEF, 65);
set_filter(filter_100k, ADDR_DDC_FIR1_COEF, 65);
@@ -889,7 +889,7 @@ void set_mono_i(void)
{
int aa;
adec_wr_reg(ADDR_ADEC_CTRL, AUDIO_STANDARD_NICAM_I);
adec_wr_reg(ADDR_ADEC_CTRL, AUDIO_STANDARD_NICAM_I | (3 << 4));
set_filter(filter_100k, ADDR_DDC_FIR0_COEF, 65);
set_filter(filter_100k, ADDR_DDC_FIR1_COEF, 65);
@@ -906,7 +906,7 @@ void set_mono_bg(void)
{
int aa;
adec_wr_reg(ADDR_ADEC_CTRL, AUDIO_STANDARD_NICAM_BG);
adec_wr_reg(ADDR_ADEC_CTRL, AUDIO_STANDARD_NICAM_BG | (3 << 4));
set_filter(filter_100k, ADDR_DDC_FIR0_COEF, 65);
set_filter(filter_100k, ADDR_DDC_FIR1_COEF, 65);
@@ -923,7 +923,7 @@ void set_mono_l(void)
{
int aa;
adec_wr_reg(ADDR_ADEC_CTRL, AUDIO_STANDARD_NICAM_L);
adec_wr_reg(ADDR_ADEC_CTRL, AUDIO_STANDARD_NICAM_L | (3 << 4));
set_filter(filter_100k, ADDR_DDC_FIR0_COEF, 65);
set_filter(filter_100k, ADDR_DDC_FIR1_COEF, 65);
@@ -1586,7 +1586,7 @@ void set_outputmode(uint32_t standard, uint32_t outmode)
case AUDIO_STANDARD_MONO_I:
case AUDIO_STANDARD_MONO_L:
/* for FM MONO system to detection nicam status */
if (!aud_reinit && get_nicam_lock_status()) {
if (!aud_mono_only && !aud_reinit && get_nicam_lock_status()) {
if (standard == AUDIO_STANDARD_MONO_I)
aud_std = AUDIO_STANDARD_NICAM_I;
else if (standard == AUDIO_STANDARD_MONO_L)

View File

@@ -260,7 +260,7 @@ void atv_dmd_misc(void)
/* for audio non-standard signal, first set gain 0 to mute,
* then unmute in detection.
*/
if (audio_atv_ov || atv_audio_overmodulated_en)
if ((audio_atv_ov || atv_audio_overmodulated_en) && non_std_en == 0)
aml_audio_valume_gain_set(0);
else
aml_audio_valume_gain_set(audio_gain_val);
@@ -287,8 +287,8 @@ void atv_dmd_misc(void)
atv_dmd_wr_long(APB_BLOCK_ADDR_VDAGC, 0x0c, 0x387c0831);
atv_dmd_wr_long(APB_BLOCK_ADDR_CARR_RCVY, 0x24, 0xc020901);
} else {
if (tuner_id == AM_TUNER_R840 || tuner_id == AM_TUNER_R842
|| non_std_en == 4) {
if ((tuner_id == AM_TUNER_R840 || tuner_id == AM_TUNER_R842) &&
non_std_en == 4) {
/* Reduce target amplitude and response speed */
atv_dmd_wr_long(APB_BLOCK_ADDR_AGC_PWM, 0x08,
0x17070200);
@@ -338,45 +338,67 @@ void atv_dmd_misc(void)
pr_dbg("%s done.\n", __func__);
}
void atv_dmd_ring_filter(bool on)
void atv_dmd_ring_filter(bool on, int std)
{
unsigned long filter_status = 0;
int i = 0;
int filter = 0;
unsigned long status = 0;
unsigned long data = 0;
const unsigned int reg_addr[10] = {
0x10, 0x14, 0x18, 0x1c, 0x20, 0x24, 0x28, 0x2c, 0x30, 0x34,
};
const unsigned int peak_filter[][10] = {
/* default */
{ 0x8423F6, 0xFF86A967, 0x37FE45, 0xFF86A967, 0x3C223B,
0x8423F6, 0xFF86A967, 0x37FE45, 0xFF86A967, 0x3C223B },
/* ntsc-m */
{ 0x8274bf, 0x1d175c, 0x2aa526, 0x1d175c, 0x2d19e4,
0x8274bf, 0x1d175c, 0x2aa526, 0x1d175c, 0x2d19e4 },
/* pal-i */
{ 0x94d888, 0x5a39fb, 0xd8ebb, 0x5a39fb, 0x226744,
0x94d888, 0x5a39fb, 0xd8ebb, 0x5a39fb, 0x226744 }
};
if (!is_meson_tl1_cpu() && !is_meson_tm2_cpu())
return;
filter_status = atv_dmd_rd_long(APB_BLOCK_ADDR_GDE_EQUAL, 0x4c);
if (((filter_status & 0x01) && on) || (!(filter_status & 0x01) && !on))
if (on) {
if (std == AML_ATV_DEMOD_VIDEO_MODE_PROP_PAL_BG) {
filter = 2;
} else if (std == AML_ATV_DEMOD_VIDEO_MODE_PROP_PAL_DK) {
filter = 2;
} else if (std == AML_ATV_DEMOD_VIDEO_MODE_PROP_PAL_I) {
filter = 2;
} else if (std == AML_ATV_DEMOD_VIDEO_MODE_PROP_NTSC_M ||
std == AML_ATV_DEMOD_VIDEO_MODE_PROP_NTSC) {
filter = 1;
} else {
filter = 0;
on = false;
}
} else {
filter = 0;
}
status = atv_dmd_rd_long(APB_BLOCK_ADDR_GDE_EQUAL, 0x4c);
data = atv_dmd_rd_long(APB_BLOCK_ADDR_GDE_EQUAL, reg_addr[0]);
if ((data == peak_filter[filter][0]) && on && (status & 0x01))
return;
if (on) {
atv_dmd_wr_long(APB_BLOCK_ADDR_GDE_EQUAL, 0x10, 0x8274bf);
atv_dmd_wr_long(APB_BLOCK_ADDR_GDE_EQUAL, 0x14, 0x1d175c);
atv_dmd_wr_long(APB_BLOCK_ADDR_GDE_EQUAL, 0x18, 0x2aa526);
atv_dmd_wr_long(APB_BLOCK_ADDR_GDE_EQUAL, 0x1c, 0x1d175c);
atv_dmd_wr_long(APB_BLOCK_ADDR_GDE_EQUAL, 0x20, 0x2d19e4);
atv_dmd_wr_long(APB_BLOCK_ADDR_GDE_EQUAL, 0x24, 0x8274bf);
atv_dmd_wr_long(APB_BLOCK_ADDR_GDE_EQUAL, 0x28, 0x1d175c);
atv_dmd_wr_long(APB_BLOCK_ADDR_GDE_EQUAL, 0x2c, 0x2aa526);
atv_dmd_wr_long(APB_BLOCK_ADDR_GDE_EQUAL, 0x30, 0x1d175c);
atv_dmd_wr_long(APB_BLOCK_ADDR_GDE_EQUAL, 0x34, 0x2d19e4);
if (!on && !(status & 0x01))
return;
/* disable filter */
atv_dmd_wr_long(APB_BLOCK_ADDR_GDE_EQUAL, 0x4c, 0x0);
for (i = 0; i < 10; ++i) {
atv_dmd_wr_long(APB_BLOCK_ADDR_GDE_EQUAL,
reg_addr[i], peak_filter[filter][i]);
}
if (on) {
/* enable filter */
atv_dmd_wr_long(APB_BLOCK_ADDR_GDE_EQUAL, 0x4c, 0x1);
} else {
/* default value */
atv_dmd_wr_long(APB_BLOCK_ADDR_GDE_EQUAL, 0x10, 0x8423F6);
atv_dmd_wr_long(APB_BLOCK_ADDR_GDE_EQUAL, 0x14, 0xFF86A967);
atv_dmd_wr_long(APB_BLOCK_ADDR_GDE_EQUAL, 0x18, 0x37FE45);
atv_dmd_wr_long(APB_BLOCK_ADDR_GDE_EQUAL, 0x1c, 0xFF86A967);
atv_dmd_wr_long(APB_BLOCK_ADDR_GDE_EQUAL, 0x20, 0x3C223B);
atv_dmd_wr_long(APB_BLOCK_ADDR_GDE_EQUAL, 0x24, 0x8423F6);
atv_dmd_wr_long(APB_BLOCK_ADDR_GDE_EQUAL, 0x28, 0xFF86A967);
atv_dmd_wr_long(APB_BLOCK_ADDR_GDE_EQUAL, 0x2c, 0x37FE45);
atv_dmd_wr_long(APB_BLOCK_ADDR_GDE_EQUAL, 0x30, 0xFF86A967);
atv_dmd_wr_long(APB_BLOCK_ADDR_GDE_EQUAL, 0x34, 0x3C223B);
/* disable filter */
atv_dmd_wr_long(APB_BLOCK_ADDR_GDE_EQUAL, 0x4c, 0x0);
}
pr_dbg("%s do atv_dmd_ring_filter %d ...\n", __func__, on);
@@ -2021,12 +2043,10 @@ int atvdemod_init(struct atv_demod_priv *priv)
if (!priv->scanning || non_std_en)
atv_dmd_misc();
if (!priv->scanning &&
(broad_std == AML_ATV_DEMOD_VIDEO_MODE_PROP_NTSC_M ||
broad_std == AML_ATV_DEMOD_VIDEO_MODE_PROP_NTSC))
atv_dmd_ring_filter(true);
if (!priv->scanning)
atv_dmd_ring_filter(true, broad_std);
else
atv_dmd_ring_filter(false);
atv_dmd_ring_filter(false, broad_std);
atv_dmd_soft_reset();
@@ -2525,3 +2545,45 @@ void aml_audio_overmodulation(int enable)
#endif
}
}
void atvdemod_horiz_freq_detection(void)
{
unsigned long data = 0;
int field_lock = 0;
int line_lock = 0;
int line = 0;
int std_line = 0;
unsigned long horiz_freq = 0;
data = atv_dmd_rd_long(APB_BLOCK_ADDR_VDAGC, 0x4c);
field_lock = data & 0x4; /* bit2 */
line_lock = data & 0x10; /* bit4 */
line = (data >> 6) & 0x3ff; /* bit[15-6] */
switch (broad_std) {
case AML_ATV_DEMOD_VIDEO_MODE_PROP_NTSC:
case AML_ATV_DEMOD_VIDEO_MODE_PROP_PAL_M:
std_line = 525;
break;
default:
std_line = 625;
break;
}
if (field_lock == 0 && line_lock == 0) {
/* bit[31-8] */
data = atv_dmd_rd_long(APB_BLOCK_ADDR_VDAGC, 0x10);
/* fh +/- (200 / 0.23841858) */
if ((line - std_line) > 7)
horiz_freq = freq_hz_cvrt + 0x347;
else if ((line - std_line) < -7)
horiz_freq = freq_hz_cvrt - 0x347;
else
horiz_freq = freq_hz_cvrt;
data = (horiz_freq << 8) | (data & 0xff);
atv_dmd_wr_long(APB_BLOCK_ADDR_VDAGC, 0x10, data);
}
}

View File

@@ -31,6 +31,7 @@ extern unsigned int aud_std;
extern unsigned int aud_mode;
extern bool audio_thd_en;
extern bool aud_reinit;
extern bool aud_mono_only;
extern bool atv_audio_overmodulated_en;
extern unsigned int non_std_en;
@@ -70,7 +71,7 @@ extern void read_version_register(void);
extern void check_communication_interface(void);
extern void power_on_receiver(void);
extern void atv_dmd_misc(void);
extern void atv_dmd_ring_filter(bool on);
void atv_dmd_ring_filter(bool on, int std);
extern void configure_receiver(int Broadcast_Standard,
unsigned int Tuner_IF_Frequency,
int Tuner_Input_IF_inverted, int GDE_Curve,
@@ -214,6 +215,7 @@ extern void set_atvdemod_scan_mode(int val);
extern int atvauddemod_init(void);
extern int amlfmt_aud_standard(int broad_std);
extern void atvauddemod_set_outputmode(void);
void atvdemod_horiz_freq_detection(void);
/*from amldemod/amlfrontend.c*/
extern int vdac_enable_check_dtv(void);

View File

@@ -40,9 +40,9 @@
#include "meson_fb.h"
#endif
#include "meson_drv.h"
#include "meson_vpu.h"
#include "meson_vpu_pipeline.h"
#define DRIVER_NAME "meson"
#define DRIVER_DESC "Amlogic Meson DRM driver"
@@ -114,23 +114,313 @@ static void am_meson_disable_vblank(struct drm_device *dev, unsigned int crtc)
priv->crtc_funcs[crtc]->disable_vblank(priv->crtc);
}
static void am_meson_load(struct drm_device *dev)
{
#if 0
struct meson_drm *priv = dev->dev_private;
struct drm_crtc *crtc = priv->crtc;
int pipe = drm_crtc_index(crtc);
struct am_meson_logo logo;
core_param(fb_width, logo.width, uint, 0644);
core_param(fb_height, logo.height, uint, 0644);
core_param(display_bpp, logo.bpp, uint, 0644);
core_param(outputmode, logo.outputmode_t, charp, 0644);
if (priv->crtc_funcs[pipe] &&
priv->crtc_funcs[pipe]->loader_protect)
priv->crtc_funcs[pipe]->loader_protect(crtc, true);
#endif
static struct drm_framebuffer *am_meson_logo_init_fb(struct drm_device *dev)
{
struct drm_mode_fb_cmd2 mode_cmd;
struct drm_framebuffer *fb;
struct am_meson_fb *meson_fb;
DRM_INFO("width=%d,height=%d,start_addr=0x%pa,size=%d\n",
logo.width, logo.height, &logo.start, logo.size);
DRM_INFO("bpp=%d,alloc_flag=%d\n", logo.bpp, logo.alloc_flag);
DRM_INFO("outputmode=%s\n", logo.outputmode);
if (logo.bpp == 16)
mode_cmd.pixel_format = DRM_FORMAT_RGB565;
else
mode_cmd.pixel_format = DRM_FORMAT_XRGB8888;
mode_cmd.offsets[0] = 0;
mode_cmd.width = logo.width;
mode_cmd.height = logo.height;
mode_cmd.modifier[0] = DRM_FORMAT_MOD_LINEAR;
/*ToDo*/
mode_cmd.pitches[0] = ALIGN(mode_cmd.width * logo.bpp, 32) / 8;
fb = am_meson_fb_alloc(dev, &mode_cmd, NULL);
if (IS_ERR_OR_NULL(fb))
return NULL;
meson_fb = to_am_meson_fb(fb);
meson_fb->logo = &logo;
return fb;
}
#define FPS_DELTA_LIMIT 1
struct drm_display_mode *
am_meson_drm_display_mode_init(struct drm_connector *connector)
{
struct drm_display_mode *mode;
struct drm_device *dev;
u32 found, num_modes;
if (!connector || !connector->dev)
return NULL;
dev = connector->dev;
found = 0;
drm_modeset_lock_all(dev);
if (drm_modeset_is_locked(&dev->mode_config.connection_mutex))
drm_modeset_unlock(&dev->mode_config.connection_mutex);
num_modes = connector->funcs->fill_modes(connector,
dev->mode_config.max_width,
dev->mode_config.max_height);
drm_modeset_unlock_all(dev);
if (!num_modes) {
DRM_INFO("%s:num_modes is zero\n", __func__);
return NULL;
}
list_for_each_entry(mode, &connector->modes, head) {
if (am_meson_crtc_check_mode(mode, logo.outputmode) == true) {
found = 1;
break;
}
}
if (found)
return mode;
else
return NULL;
}
static int am_meson_update_output_state(struct drm_atomic_state *state,
struct drm_mode_set *set)
{
struct drm_device *dev = set->crtc->dev;
struct drm_crtc *crtc;
struct drm_crtc_state *crtc_state;
struct drm_connector *connector;
struct drm_connector_state *conn_state;
int ret, i;
ret = drm_modeset_lock(&dev->mode_config.connection_mutex,
state->acquire_ctx);
if (ret)
return ret;
/* First disable all connectors on the target crtc. */
ret = drm_atomic_add_affected_connectors(state, set->crtc);
if (ret)
return ret;
for_each_connector_in_state(state, connector, conn_state, i) {
if (conn_state->crtc == set->crtc) {
ret = drm_atomic_set_crtc_for_connector(conn_state,
NULL);
if (ret)
return ret;
}
}
/* Then set all connectors from set->connectors on the target crtc */
for (i = 0; i < set->num_connectors; i++) {
conn_state = drm_atomic_get_connector_state(state,
set->connectors[i]);
if (IS_ERR(conn_state))
return PTR_ERR(conn_state);
ret = drm_atomic_set_crtc_for_connector(conn_state,
set->crtc);
if (ret)
return ret;
}
for_each_crtc_in_state(state, crtc, crtc_state, i) {
/* Don't update ->enable for the CRTC in the set_config request,
* since a mismatch would indicate a bug in the upper layers.
* The actual modeset code later on will catch any
* inconsistencies here.
*/
if (crtc == set->crtc)
continue;
if (!crtc_state->connector_mask) {
ret = drm_atomic_set_mode_prop_for_crtc(crtc_state,
NULL);
if (ret < 0)
return ret;
crtc_state->active = false;
}
}
return 0;
}
static int __am_meson_drm_set_config(struct drm_mode_set *set,
struct drm_atomic_state *state)
{
struct drm_crtc_state *crtc_state;
struct drm_plane_state *primary_state;
struct drm_crtc *crtc = set->crtc;
int hdisplay, vdisplay;
int ret;
crtc_state = drm_atomic_get_crtc_state(state, crtc);
if (IS_ERR(crtc_state))
return PTR_ERR(crtc_state);
primary_state = drm_atomic_get_plane_state(state, crtc->primary);
if (IS_ERR(primary_state))
return PTR_ERR(primary_state);
if (!set->mode) {
WARN_ON(set->fb);
WARN_ON(set->num_connectors);
ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL);
if (ret != 0)
return ret;
crtc_state->active = false;
ret = drm_atomic_set_crtc_for_plane(primary_state, NULL);
if (ret != 0)
return ret;
drm_atomic_set_fb_for_plane(primary_state, NULL);
goto commit;
}
WARN_ON(!set->fb);
WARN_ON(!set->num_connectors);
ret = drm_atomic_set_mode_for_crtc(crtc_state, set->mode);
if (ret != 0)
return ret;
crtc_state->active = true;
ret = drm_atomic_set_crtc_for_plane(primary_state, crtc);
if (ret != 0)
return ret;
drm_crtc_get_hv_timing(set->mode, &hdisplay, &vdisplay);
drm_atomic_set_fb_for_plane(primary_state, set->fb);
primary_state->crtc_x = 0;
primary_state->crtc_y = 0;
primary_state->crtc_w = hdisplay;
primary_state->crtc_h = vdisplay;
primary_state->src_x = set->x << 16;
primary_state->src_y = set->y << 16;
if (drm_rotation_90_or_270(primary_state->rotation)) {
primary_state->src_w = set->fb->height << 16;
primary_state->src_h = set->fb->width << 16;
} else {
primary_state->src_w = set->fb->width << 16;
primary_state->src_h = set->fb->height << 16;
}
commit:
ret = am_meson_update_output_state(state, set);
if (ret)
return ret;
return 0;
}
static int am_meson_drm_set_config(struct drm_mode_set *set)
{
struct drm_atomic_state *state;
struct drm_crtc *crtc = set->crtc;
int ret = 0;
state = drm_atomic_state_alloc(crtc->dev);
if (!state)
return -ENOMEM;
state->legacy_set_config = true;
state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc);
retry:
ret = __am_meson_drm_set_config(set, state);
if (ret != 0)
goto fail;
ret = drm_atomic_commit(state);
if (ret != 0)
goto fail;
/* Driver takes ownership of state on successful commit. */
return 0;
fail:
if (ret == -EDEADLK)
goto backoff;
drm_atomic_state_free(state);
return ret;
backoff:
drm_atomic_state_clear(state);
drm_atomic_legacy_backoff(state);
/*
* Someone might have exchanged the framebuffer while we dropped locks
* in the backoff code. We need to fix up the fb refcount tracking the
* core does for us.
*/
crtc->primary->old_fb = crtc->primary->fb;
goto retry;
}
static void am_meson_load_logo(struct drm_device *dev)
{
struct drm_mode_set set;
struct drm_framebuffer *fb;
struct drm_display_mode *mode;
struct drm_connector **connector_set;
struct meson_drm *private = dev->dev_private;
if (!logo.alloc_flag) {
DRM_INFO("%s: logo memory is not cma alloc\n", __func__);
return;
}
fb = am_meson_logo_init_fb(dev);
if (!fb) {
DRM_INFO("%s:framebuffer is NULL!\n", __func__);
return;
}
connector_set = kmalloc_array(1, sizeof(struct drm_connector *),
GFP_KERNEL);
if (!connector_set)
return;
connector_set[0] = am_meson_hdmi_connector();
if (!connector_set[0]) {
DRM_INFO("%s:connector is NULL!\n", __func__);
kfree(connector_set);
return;
}
mode = am_meson_drm_display_mode_init(connector_set[0]);
if (!mode) {
DRM_INFO("%s:display mode is NULL!\n", __func__);
kfree(connector_set);
return;
}
DRM_INFO("find the match display mode:%s\n", mode->name);
set.crtc = private->crtc;
set.x = 0;
set.y = 0;
set.mode = mode;
set.connectors = connector_set;
set.num_connectors = 1;
set.fb = fb;
drm_modeset_lock_all(dev);
if (am_meson_drm_set_config(&set))
DRM_INFO("[%s]am_meson_drm_set_config fail\n", __func__);
if (drm_framebuffer_read_refcount(fb) > 1)
drm_framebuffer_unreference(fb);
drm_modeset_unlock_all(dev);
kfree(connector_set);
}
#ifdef CONFIG_DRM_MESON_USE_ION
static const struct drm_ioctl_desc meson_ioctls[] = {
DRM_IOCTL_DEF_DRV(MESON_GEM_CREATE, am_meson_gem_create_ioctl,
DRM_UNLOCKED | DRM_AUTH | DRM_RENDER_ALLOW),
DRM_UNLOCKED | DRM_AUTH | DRM_RENDER_ALLOW),
};
#endif
@@ -277,7 +567,7 @@ static int am_meson_drm_bind(struct device *dev)
drm_kms_helper_poll_init(drm);
am_meson_load(drm);
am_meson_load_logo(drm);
#ifdef CONFIG_DRM_MESON_EMULATE_FBDEV
ret = am_meson_drm_fbdev_init(drm);
@@ -290,7 +580,6 @@ static int am_meson_drm_bind(struct device *dev)
return 0;
err_fbdev_fini:
#ifdef CONFIG_DRM_MESON_EMULATE_FBDEV
am_meson_drm_fbdev_fini(drm);
@@ -384,10 +673,10 @@ static bool am_meson_drv_use_osd(void)
if (strcmp(str, "okay") && strcmp(str, "ok")) {
DRM_INFO("device %s status is %s\n",
node->name, str);
node->name, str);
} else {
DRM_INFO("device %s status is %s\n",
node->name, str);
node->name, str);
return true;
}
}
@@ -466,6 +755,7 @@ static int am_meson_drv_probe(struct platform_device *pdev)
struct component_match *match = NULL;
int i;
pr_info("[%s] in\n", __func__);
if (am_meson_drv_use_osd())
return am_meson_drv_probe_prune(pdev);
@@ -518,7 +808,7 @@ static int am_meson_drv_probe(struct platform_device *pdev)
am_meson_add_endpoints(dev, &match, port);
of_node_put(port);
}
pr_info("[%s] out\n", __func__);
return component_master_add_with_match(dev, &am_meson_drm_ops, match);
}

View File

@@ -59,6 +59,7 @@ struct meson_drm {
struct meson_vpu_pipeline *pipeline;
struct meson_vpu_funcs *funcs;
struct am_meson_logo *logo;
u32 num_crtcs;
struct am_meson_crtc *crtcs[MESON_MAX_CRTC];
@@ -76,6 +77,7 @@ static inline int meson_vpu_is_compatible(struct meson_drm *priv,
extern int am_meson_register_crtc_funcs(struct drm_crtc *crtc,
const struct meson_crtc_funcs *crtc_funcs);
extern void am_meson_unregister_crtc_funcs(struct drm_crtc *crtc);
struct drm_connector *am_meson_hdmi_connector(void);
#ifdef CONFIG_DEBUG_FS
int meson_debugfs_init(struct drm_minor *minor);

View File

@@ -18,8 +18,7 @@
#include <drm/drm_atomic_helper.h>
#include "meson_fb.h"
#define to_am_meson_fb(x) container_of(x, struct am_meson_fb, base)
#include "meson_vpu.h"
void am_meson_fb_destroy(struct drm_framebuffer *fb)
{
@@ -27,6 +26,9 @@ void am_meson_fb_destroy(struct drm_framebuffer *fb)
drm_gem_object_unreference_unlocked(&meson_fb->bufp->base);
drm_framebuffer_cleanup(fb);
if (meson_fb->logo && meson_fb->logo->alloc_flag)
am_meson_free_logo_memory();
DRM_DEBUG("meson_fb=0x%p,\n", meson_fb);
kfree(meson_fb);
}
@@ -58,9 +60,12 @@ am_meson_fb_alloc(struct drm_device *dev,
if (!meson_fb)
return ERR_PTR(-ENOMEM);
meson_gem = container_of(obj, struct am_meson_gem_object, base);
meson_fb->bufp = meson_gem;
if (obj) {
meson_gem = container_of(obj, struct am_meson_gem_object, base);
meson_fb->bufp = meson_gem;
} else {
meson_fb->bufp = NULL;
}
drm_helper_mode_fill_fb_struct(&meson_fb->base, mode_cmd);
ret = drm_framebuffer_init(dev, &meson_fb->base,
@@ -70,6 +75,10 @@ am_meson_fb_alloc(struct drm_device *dev,
ret);
goto err_free_fb;
}
DRM_INFO("meson_fb[id:%d,ref:%d]=0x%p,meson_fb->bufp=0x%p\n",
meson_fb->base.base.id,
atomic_read(&meson_fb->base.base.refcount.refcount),
meson_fb, meson_fb->bufp);
return &meson_fb->base;
@@ -113,6 +122,10 @@ struct drm_framebuffer *am_meson_fb_create(struct drm_device *dev,
kfree(meson_fb);
return ERR_PTR(ret);
}
DRM_DEBUG("meson_fb[in:%d,ref:%d]=0x%px,meson_fb->bufp=0x%p\n",
meson_fb->base.base.id,
atomic_read(&meson_fb->base.base.refcount.refcount),
meson_fb, meson_fb->bufp);
return &meson_fb->base;
}

View File

@@ -24,16 +24,40 @@
#include "meson_gem.h"
#define to_am_meson_fb(x) container_of(x, struct am_meson_fb, base)
#define VMODE_NAME_LEN_MAX 64
struct am_meson_logo {
struct page *logo_page;
phys_addr_t start;
u32 size;
u32 width;
u32 height;
u32 bpp;
u32 alloc_flag;
u32 info_loaded_mask;
char *outputmode_t;
char outputmode[VMODE_NAME_LEN_MAX];
};
struct am_meson_fb {
struct drm_framebuffer base;
struct am_meson_gem_object *bufp;
struct am_meson_logo *logo;
};
struct drm_framebuffer *am_meson_fb_create(struct drm_device *dev,
struct drm_file *file_priv,
const struct drm_mode_fb_cmd2 *mode_cmd);
struct drm_framebuffer *am_meson_drm_framebuffer_init(
struct drm_device *dev,
struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object *obj);
struct drm_framebuffer *
am_meson_fb_create(struct drm_device *dev,
struct drm_file *file_priv,
const struct drm_mode_fb_cmd2 *mode_cmd);
struct drm_framebuffer *
am_meson_drm_framebuffer_init(struct drm_device *dev,
struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object *obj);
struct drm_framebuffer *
am_meson_fb_alloc(struct drm_device *dev,
struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_gem_object *obj);
#endif

View File

@@ -55,7 +55,7 @@ static int am_meson_gem_alloc_ion_buff(
bscatter = true;
}
if (IS_ERR(handle)) {
if (IS_ERR_OR_NULL(handle)) {
DRM_ERROR("%s: FAILED, flags:0x%x.\n",
__func__, flags);
return -ENOMEM;

View File

@@ -35,17 +35,11 @@
#include <linux/amlogic/media/vout/hdmi_tx/hdmi_tx_module.h>
#include "meson_hdmi.h"
#include "meson_hdcp.h"
#include "meson_vpu.h"
#define DEVICE_NAME "amhdmitx"
struct am_hdmi_tx am_hdmi_info;
struct am_vout_mode {
char name[DRM_DISPLAY_MODE_LEN];
enum vmode_e mode;
int width, height, vrefresh;
unsigned int flags;
};
static struct am_vout_mode am_vout_modes[] = {
{ "1080p60hz", VMODE_HDMI, 1920, 1080, 60, 0},
{ "1080p30hz", VMODE_HDMI, 1920, 1080, 30, 0},
@@ -300,7 +294,6 @@ void am_hdmi_encoder_enable(struct drm_encoder *encoder)
vout_notifier_call_chain(VOUT_EVENT_MODE_CHANGE_PRE, &vmode);
set_vout_vmode(vmode);
vout_notifier_call_chain(VOUT_EVENT_MODE_CHANGE, &vmode);
am_hdmi->hdcp_work = NULL;
mdelay(1000);
am_hdmi_hdcp_work_state_change(am_hdmi, 0);
}
@@ -584,6 +577,11 @@ static const struct of_device_id am_meson_hdmi_dt_ids[] = {
MODULE_DEVICE_TABLE(of, am_meson_hdmi_dt_ids);
struct drm_connector *am_meson_hdmi_connector(void)
{
return &am_hdmi_info.connector;
}
static int am_meson_hdmi_bind(struct device *dev,
struct device *master, void *data)
{
@@ -596,12 +594,9 @@ static int am_meson_hdmi_bind(struct device *dev,
int ret;
int irq;
am_hdmi = devm_kzalloc(priv->dev, sizeof(*am_hdmi),
GFP_KERNEL);
if (!am_hdmi)
return -ENOMEM;
memcpy(&am_hdmi_info, am_hdmi, sizeof(*am_hdmi));
DRM_INFO("[%s] in\n", __func__);
am_hdmi = &am_hdmi_info;
memset(am_hdmi, 0, sizeof(*am_hdmi));
DRM_INFO("drm hdmitx init and version:%s\n", DRM_HDMITX_VER);
am_hdmi->priv = priv;
@@ -662,6 +657,7 @@ static int am_meson_hdmi_bind(struct device *dev,
DRM_DEBUG_KMS("HDCP init failed, skipping.\n");
}
}
DRM_INFO("[%s] out\n", __func__);
return 0;
}
@@ -679,6 +675,7 @@ static const struct component_ops am_meson_hdmi_ops = {
static int am_meson_hdmi_probe(struct platform_device *pdev)
{
DRM_INFO("[%s] in\n", __func__);
return component_add(&pdev->dev, &am_meson_hdmi_ops);
}

View File

@@ -42,12 +42,18 @@ static u64 afbc_wb_modifier[] = {
DRM_FORMAT_MOD_INVALID
};
static void meson_plane_position_calc(
struct meson_vpu_osd_layer_info *plane_info,
struct drm_plane_state *state,
struct drm_display_mode *mode)
static void
meson_plane_position_calc(struct meson_vpu_osd_layer_info *plane_info,
struct drm_plane_state *state,
struct drm_display_mode *disp_mode)
{
u32 dst_w, dst_h, src_w, src_h, scan_mode_out;
struct drm_display_mode *mode;
if (IS_ERR_OR_NULL(state->crtc))
mode = disp_mode;
else
mode = &state->crtc->mode;
scan_mode_out = mode->flags & DRM_MODE_FLAG_INTERLACE;
plane_info->src_x = state->src_x;
@@ -147,7 +153,7 @@ static int meson_plane_fb_check(struct drm_plane *plane,
#else
struct drm_gem_cma_object *gem;
#endif
dma_addr_t phyaddr;
phys_addr_t phyaddr;
#ifdef CONFIG_DRM_MESON_USE_ION
meson_fb = container_of(fb, struct am_meson_fb, base);
@@ -155,9 +161,21 @@ static int meson_plane_fb_check(struct drm_plane *plane,
DRM_INFO("meson_fb is NULL!\n");
return -EINVAL;
}
phyaddr = am_meson_gem_object_get_phyaddr(drv, meson_fb->bufp);
if (meson_fb->bufp->bscatter)
DRM_ERROR("am_meson_plane meet a scatter framebuffer.\n");
DRM_DEBUG("meson_fb[id:%d,ref:%d]=0x%p\n",
meson_fb->base.base.id,
atomic_read(&meson_fb->base.base.refcount.refcount),
meson_fb);
if (meson_fb->logo && meson_fb->logo->alloc_flag &&
meson_fb->logo->start) {
phyaddr = meson_fb->logo->start;
DRM_DEBUG("logo->phyaddr=0x%pa\n", &phyaddr);
} else if (meson_fb->bufp) {
phyaddr = am_meson_gem_object_get_phyaddr(drv, meson_fb->bufp);
} else {
phyaddr = 0;
DRM_INFO("don't find phyaddr!\n");
return -EINVAL;
}
#else
if (!fb) {
DRM_INFO("fb is NULL!\n");
@@ -182,12 +200,6 @@ static int meson_plane_get_fb_info(struct drm_plane *plane,
struct am_osd_plane *osd_plane = to_am_osd_plane(plane);
struct drm_framebuffer *fb = new_state->fb;
struct meson_drm *drv = osd_plane->drv;
#ifdef CONFIG_DRM_MESON_USE_ION
struct am_meson_fb *meson_fb;
#else
struct drm_gem_cma_object *gem;
#endif
dma_addr_t phyaddr;
if (!drv) {
DRM_INFO("%s new_state/meson_drm is NULL!\n", __func__);
@@ -197,29 +209,7 @@ static int meson_plane_get_fb_info(struct drm_plane *plane,
DRM_INFO("%s invalid plane_index!\n", __func__);
return -EINVAL;
}
#ifdef CONFIG_DRM_MESON_USE_ION
meson_fb = container_of(fb, struct am_meson_fb, base);
if (!meson_fb) {
DRM_INFO("meson_fb is NULL!\n");
return 0;
}
phyaddr = am_meson_gem_object_get_phyaddr(drv, meson_fb->bufp);
if (meson_fb->bufp->bscatter)
DRM_ERROR("ERROR:am_meson_plane meet a scatter framebuffer.\n");
plane_info->fb_size = meson_fb->bufp->base.size;
#else
if (!fb) {
DRM_INFO("fb is NULL!\n");
return -EINVAL;
}
/* Update Canvas with buffer address */
gem = drm_fb_cma_get_gem_obj(fb, 0);
phyaddr = gem->paddr;
#endif
plane_info->pixel_format = fb->pixel_format;
plane_info->phy_addr = phyaddr;
plane_info->byte_stride = fb->pitches[0];
/*setup afbc info*/
@@ -261,6 +251,13 @@ static int meson_plane_atomic_get_property(struct drm_plane *plane,
struct drm_property *property,
uint64_t *val)
{
struct am_osd_plane *osd_plane;
struct am_meson_plane_state *plane_state;
osd_plane = to_am_osd_plane(plane);
plane_state = to_am_meson_plane_state(state);
if (property == osd_plane->prop_premult_en)
*val = plane_state->premult_en;
return 0;
}
@@ -269,6 +266,14 @@ static int meson_plane_atomic_set_property(struct drm_plane *plane,
struct drm_property *property,
uint64_t val)
{
struct am_osd_plane *osd_plane;
struct am_meson_plane_state *plane_state;
osd_plane = to_am_osd_plane(plane);
plane_state = to_am_meson_plane_state(state);
if (property == osd_plane->prop_premult_en)
plane_state->premult_en = val;
return 0;
}
@@ -355,7 +360,7 @@ static void meson_plane_cleanup_fb(struct drm_plane *plane,
{
struct am_osd_plane *osd_plane = to_am_osd_plane(plane);
DRM_DEBUG("%s osd %d.\n", __func__, osd_plane->plane_index);
DRM_DEBUG("osd %d.\n", osd_plane->plane_index);
}
static void meson_plane_atomic_update(struct drm_plane *plane,
@@ -372,6 +377,7 @@ static int meson_plane_atomic_check(struct drm_plane *plane,
struct meson_vpu_pipeline_state *mvps;
struct am_osd_plane *osd_plane = to_am_osd_plane(plane);
struct meson_drm *drv = osd_plane->drv;
struct am_meson_plane_state *plane_state;
int ret;
if (!state || !drv) {
@@ -410,6 +416,8 @@ static int meson_plane_atomic_check(struct drm_plane *plane,
return ret;
}
plane_state = to_am_meson_plane_state(state);
plane_info->premult_en = plane_state->premult_en;
plane_info->enable = 1;
DRM_DEBUG("index=%d, zorder=%d\n",
plane_info->plane_index, plane_info->zorder);
@@ -438,6 +446,24 @@ static const struct drm_plane_helper_funcs am_osd_helper_funcs = {
.atomic_disable = meson_plane_atomic_disable,
};
int drm_plane_create_premult_en_property(struct drm_plane *plane)
{
struct drm_device *dev = plane->dev;
struct drm_property *prop;
struct am_osd_plane *osd_plane;
osd_plane = to_am_osd_plane(plane);
prop = drm_property_create_bool(dev, DRM_MODE_PROP_ATOMIC,
"PREMULT_EN");
if (!prop)
return -ENOMEM;
drm_object_attach_property(&plane->base, prop, 0);
osd_plane->prop_premult_en = prop;
return 0;
}
static struct am_osd_plane *am_plane_create(struct meson_drm *priv, int i)
{
struct am_osd_plane *osd_plane;
@@ -469,6 +495,7 @@ static struct am_osd_plane *am_plane_create(struct meson_drm *priv, int i)
format_modifiers,
type, plane_name);
drm_plane_create_premult_en_property(plane);
drm_plane_helper_add(plane, &am_osd_helper_funcs);
osd_drm_debugfs_add(&osd_plane->plane_debugfs_dir,
plane_name, osd_plane->plane_index);

View File

@@ -31,6 +31,7 @@
struct am_meson_plane_state {
struct drm_plane_state base;
u32 premult_en;
};
struct am_osd_plane {
@@ -38,6 +39,7 @@ struct am_osd_plane {
struct meson_drm *drv; //point to struct parent.
struct dentry *plane_debugfs_dir;
int plane_index;
struct drm_property *prop_premult_en;
};
#define to_am_osd_plane(x) container_of(x, \

View File

@@ -256,9 +256,6 @@ static struct osd_device_data_s osd_tm2 = {
.osd0_sc_independ = 1,
};
struct osd_device_data_s osd_meson_dev;
static u32 logo_memsize;
static struct page *logo_page;
static struct delayed_work osd_dwork;
static struct platform_device *gp_dev;
static unsigned long gem_mem_start, gem_mem_size;
@@ -350,6 +347,28 @@ char *am_meson_crtc_get_voutmode(struct drm_display_mode *mode)
return NULL;
}
bool am_meson_crtc_check_mode(struct drm_display_mode *mode, char *outputmode)
{
int i;
if (!mode || !outputmode)
return false;
if (!strcmp(mode->name, "panel"))
return true;
for (i = 0; i < ARRAY_SIZE(am_vout_modes); i++) {
if (!strcmp(am_vout_modes[i].name, outputmode) &&
am_vout_modes[i].width == mode->hdisplay &&
am_vout_modes[i].height == mode->vdisplay &&
am_vout_modes[i].vrefresh == mode->vrefresh &&
am_vout_modes[i].flags ==
(mode->flags & DRM_MODE_FLAG_INTERLACE)) {
return true;
}
}
return false;
}
void am_meson_crtc_handle_vsync(struct am_meson_crtc *amcrtc)
{
unsigned long flags;
@@ -390,18 +409,43 @@ static irqreturn_t am_meson_vpu_irq(int irq, void *arg)
return IRQ_HANDLED;
}
static void mem_free_work(struct work_struct *work)
void am_meson_free_logo_memory(void)
{
if (logo_memsize > 0) {
phys_addr_t logo_addr = page_to_phys(logo.logo_page);
if (logo.size > 0) {
#ifdef CONFIG_CMA
pr_info("%s, free memory: addr:0x%x\n",
__func__, logo_memsize);
DRM_INFO("%s, free memory: addr:0x%pa,size:0x%x\n",
__func__, &logo_addr, logo.size);
dma_release_from_contiguous(&gp_dev->dev,
logo_page,
logo_memsize >> PAGE_SHIFT);
logo.logo_page,
logo.size >> PAGE_SHIFT);
#endif
}
logo.alloc_flag = 0;
}
static int am_meson_logo_info_update(struct meson_drm *priv)
{
logo.start = page_to_phys(logo.logo_page);
logo.alloc_flag = 1;
/*config 1080p logo as default*/
if (!logo.width || !logo.height) {
logo.width = 1920;
logo.height = 1080;
}
if (!logo.bpp)
logo.bpp = 16;
if (!logo.outputmode_t) {
strcpy(logo.outputmode, "1080p60hz");
} else {
strncpy(logo.outputmode, logo.outputmode_t, VMODE_NAME_LEN_MAX);
logo.outputmode[VMODE_NAME_LEN_MAX - 1] = '\0';
}
priv->logo = &logo;
return 0;
}
static int am_meson_vpu_bind(struct device *dev,
@@ -418,7 +462,7 @@ static int am_meson_vpu_bind(struct device *dev,
int ret, irq;
/* Allocate crtc struct */
pr_info("[%s] in\n", __func__);
DRM_INFO("[%s] in\n", __func__);
amcrtc = devm_kzalloc(dev, sizeof(*amcrtc),
GFP_KERNEL);
if (!amcrtc)
@@ -434,34 +478,40 @@ static int am_meson_vpu_bind(struct device *dev,
ret = of_reserved_mem_device_init(&pdev->dev);
if (ret != 0) {
dev_err(dev, "failed to init reserved memory\n");
} else {
#ifdef CONFIG_CMA
gp_dev = pdev;
cma = dev_get_cma_area(&pdev->dev);
if (cma) {
logo_memsize = cma_get_size(cma);
pr_info("reserved memory base:0x%x, size:0x%x\n",
(u32)cma_get_base(cma), logo_memsize);
if (logo_memsize > 0) {
logo_page =
logo.size = cma_get_size(cma);
DRM_INFO("reserved memory base:0x%x, size:0x%x\n",
(u32)cma_get_base(cma), logo.size);
if (logo.size > 0) {
logo.logo_page =
dma_alloc_from_contiguous(&pdev->dev,
logo_memsize >>
logo.size >>
PAGE_SHIFT,
0);
if (!logo_page) {
pr_err("allocate buffer failed:%d\n",
logo_memsize);
}
if (!logo.logo_page)
DRM_INFO("allocate buffer failed\n");
else
am_meson_logo_info_update(private);
}
} else {
pr_info("------ NO CMA\n");
DRM_INFO("------ NO CMA\n");
}
#endif
} else {
dma_declare_coherent_memory(drm_dev->dev, gem_mem_start,
gem_mem_start, gem_mem_size,
DMA_MEMORY_EXCLUSIVE);
pr_info("meson drm mem_start = 0x%x, size = 0x%x\n",
(u32)gem_mem_start, (u32)gem_mem_size);
if (gem_mem_start) {
dma_declare_coherent_memory(drm_dev->dev,
gem_mem_start,
gem_mem_start,
gem_mem_size,
DMA_MEMORY_EXCLUSIVE);
pr_info("meson drm mem_start = 0x%x, size = 0x%x\n",
(u32)gem_mem_start, (u32)gem_mem_size);
} else {
DRM_INFO("------ NO reserved dma\n");
}
}
ret = am_meson_plane_create(private);
@@ -495,10 +545,7 @@ static int am_meson_vpu_bind(struct device *dev,
return ret;
disable_irq(amcrtc->vblank_irq);
INIT_DELAYED_WORK(&osd_dwork, mem_free_work);
schedule_delayed_work(&osd_dwork, msecs_to_jiffies(60 * 1000));
pr_info("[%s] out\n", __func__);
DRM_INFO("[%s] out\n", __func__);
return 0;
}

View File

@@ -31,7 +31,10 @@ struct am_vout_mode {
unsigned int flags;
};
extern struct am_meson_logo logo;
extern struct osd_device_data_s osd_meson_dev;
char *am_meson_crtc_get_voutmode(struct drm_display_mode *mode);
void am_meson_free_logo_memory(void);
bool am_meson_crtc_check_mode(struct drm_display_mode *mode, char *outputmode);
#endif /* __AM_MESON_VPU_H */

View File

@@ -39,7 +39,7 @@
#define MESON_BLOCK_MAX_NAME_LEN 32
/*ratio base for scaler calc;maybe need bigger than 1000*/
#define RATIO_BASE 1000
#define MESON_OSD_INPUT_W_LIMIT 1920
#define MESON_OSD_INPUT_W_LIMIT 3840
#define MAX_DIN_NUM 4
#define MAX_DOUT_NUM 2
@@ -169,6 +169,7 @@ struct meson_vpu_osd_layer_info {
u32 afbc_inter_format;
u32 afbc_en;
u32 fb_size;
u32 premult_en;
};
struct meson_vpu_osd {
@@ -205,6 +206,7 @@ struct meson_vpu_osd_state {
int r_mode;
u32 plane_index;
u32 fb_size;
u32 premult_en;
};
struct meson_vpu_afbc {

View File

@@ -80,6 +80,34 @@ static unsigned int __osd_filter_coefs_bicubic[] = { /* bicubic coef0 */
0xf84d42f9, 0xf84a45f9, 0xf84848f8
};
static unsigned int __osd_filter_coefs_2point_binilear[] = {
/* 2 point bilinear, bank_length == 2 coef2 */
0x80000000, 0x7e020000, 0x7c040000, 0x7a060000, 0x78080000, 0x760a0000,
0x740c0000, 0x720e0000, 0x70100000, 0x6e120000, 0x6c140000, 0x6a160000,
0x68180000, 0x661a0000, 0x641c0000, 0x621e0000, 0x60200000, 0x5e220000,
0x5c240000, 0x5a260000, 0x58280000, 0x562a0000, 0x542c0000, 0x522e0000,
0x50300000, 0x4e320000, 0x4c340000, 0x4a360000, 0x48380000, 0x463a0000,
0x443c0000, 0x423e0000, 0x40400000
};
static unsigned int __osd_filter_coefs_4point_triangle[] = {
0x20402000, 0x20402000, 0x1f3f2101, 0x1f3f2101,
0x1e3e2202, 0x1e3e2202, 0x1d3d2303, 0x1d3d2303,
0x1c3c2404, 0x1c3c2404, 0x1b3b2505, 0x1b3b2505,
0x1a3a2606, 0x1a3a2606, 0x19392707, 0x19392707,
0x18382808, 0x18382808, 0x17372909, 0x17372909,
0x16362a0a, 0x16362a0a, 0x15352b0b, 0x15352b0b,
0x14342c0c, 0x14342c0c, 0x13332d0d, 0x13332d0d,
0x12322e0e, 0x12322e0e, 0x11312f0f, 0x11312f0f,
0x10303010
};
static unsigned int *osd_scaler_filter_table[] = {
__osd_filter_coefs_bicubic,
__osd_filter_coefs_2point_binilear,
__osd_filter_coefs_4point_triangle
};
/*********vsc config begin**********/
/*vsc phase_step=(v_in << 20)/v_out */
void osd_vsc_phase_step_set(struct osd_scaler_reg_s *reg, u32 phase_step)
@@ -309,7 +337,7 @@ void osd_sc_out_vert_set(struct osd_scaler_reg_s *reg, u32 start, u32 end)
*1:config horizontal coef
*0:config vertical coef
*/
void osd_sc_coef_set(struct osd_scaler_reg_s *reg, bool flag)
void osd_sc_coef_set(struct osd_scaler_reg_s *reg, bool flag, u32 *coef)
{
u8 i;
@@ -320,8 +348,7 @@ void osd_sc_coef_set(struct osd_scaler_reg_s *reg, bool flag)
(flag << 8) |
(0 << 0)/*coef index 7bits*/);
for (i = 0; i < 33; i++)
VSYNCOSD_WR_MPEG_REG(reg->vpp_osd_scale_coef,
__osd_filter_coefs_bicubic[i]);
VSYNCOSD_WR_MPEG_REG(reg->vpp_osd_scale_coef, coef[i]);
}
/*********sc top ctrl end************/
static void f2v_get_vertical_phase(
@@ -381,6 +408,8 @@ void osd_scaler_config(struct osd_scaler_reg_s *reg,
u32 width_out = scaler_state->output_width;
u32 height_out = scaler_state->output_height;
u32 scan_mode_out = scaler_state->scan_mode_out;
u32 vsc_double_line_mode;
u32 *coef_h, *coef_v;
bool scaler_enable;
if (width_in == width_out && height_in == height_out &&
@@ -389,10 +418,13 @@ void osd_scaler_config(struct osd_scaler_reg_s *reg,
else
scaler_enable = true;
if (width_out > linebuffer)
if (width_in > linebuffer) {
vsc_bank_length = bank_length >> 1;
else
vsc_double_line_mode = 1;
} else {
vsc_bank_length = bank_length;
vsc_double_line_mode = 0;
}
hsc_init_rec_num = bank_length;
hsc_bank_length = bank_length;
hsc_init_rpt_p0_num = bank_length / 2 - 1;
@@ -432,6 +464,17 @@ void osd_scaler_config(struct osd_scaler_reg_s *reg,
phase_step_v <<= (OSD_ZOOM_TOTAL_BITS - OSD_ZOOM_HEIGHT_BITS);
phase_step_h = (width_in << OSD_ZOOM_WIDTH_BITS) / width_out;
phase_step_h <<= (OSD_ZOOM_TOTAL_BITS - OSD_ZOOM_WIDTH_BITS);
/*check coef*/
if (scan_mode_out && width_out <= 720) {
coef_h = osd_scaler_filter_table[COEFS_4POINT_TRIANGLE];
coef_v = osd_scaler_filter_table[COEFS_4POINT_TRIANGLE];
} else if (vsc_double_line_mode == 1) {
coef_h = osd_scaler_filter_table[COEFS_BICUBIC];
coef_v = osd_scaler_filter_table[COEFS_2POINT_BINILEAR];
} else {
coef_h = osd_scaler_filter_table[COEFS_BICUBIC];
coef_v = osd_scaler_filter_table[COEFS_BICUBIC];
}
/*input size config*/
osd_sc_in_h_set(reg, height_in);
@@ -449,13 +492,14 @@ void osd_scaler_config(struct osd_scaler_reg_s *reg,
osd_sc_dummy_data_set(reg, 0x80808080);
/*h/v coef config*/
osd_sc_coef_set(reg, 1);
osd_sc_coef_set(reg, 0);
osd_sc_coef_set(reg, OSD_SCALER_COEFF_H, coef_h);
osd_sc_coef_set(reg, OSD_SCALER_COEFF_V, coef_v);
/*init recv line num*/
osd_vsc_top_ini_rcv_num_set(reg, vsc_top_init_rec_num);
osd_vsc_bot_ini_rcv_num_set(reg, vsc_bot_init_rec_num);
osd_hsc_ini_rcv_num0_set(reg, hsc_init_rec_num);
osd_vsc_double_line_mode_set(reg, vsc_double_line_mode);
/*repeate line0 num*/
osd_vsc_top_rpt_l0_num_set(reg, vsc_top_rpt_l0_num);
@@ -650,9 +694,6 @@ static void scaler_hw_init(struct meson_vpu_block *vblk)
scaler->reg = &osd_scaler_reg[vblk->index];
scaler->linebuffer = OSD_SCALE_LINEBUFFER;
scaler->bank_length = OSD_SCALE_BANK_LENGTH;
/*disable sc*/
osd_sc_en_set(scaler->reg, 0);
osd_sc_path_en_set(scaler->reg, 0);
DRM_DEBUG("%s hw_init called.\n", scaler->base.name);
}

View File

@@ -79,6 +79,15 @@
#define OSD_ZOOM_TOTAL_BITS 24
#define OSD_PHASE_BITS 16
#define OSD_SCALER_COEFF_H 1
#define OSD_SCALER_COEFF_V 0
enum scaler_coef_e {
COEFS_BICUBIC = 0,
COEFS_2POINT_BINILEAR,
COEFS_4POINT_TRIANGLE
};
enum f2v_vphase_type_e {
F2V_IT2IT = 0,
F2V_IB2IB,

View File

@@ -227,6 +227,14 @@ void osd_block_enable(struct osd_mif_reg_s *reg, bool flag)
VSYNCOSD_WR_MPEG_REG_BITS(reg->viu_osd_ctrl_stat, flag, 0, 1);
}
/*osd alpha_div en
*if input is premult,alpha_div=1,else alpha_div=0
*/
void osd_alpha_div_enable(struct osd_mif_reg_s *reg, bool flag)
{
VSYNCOSD_WR_MPEG_REG_BITS(reg->viu_osd_mali_unpack_ctrl, flag, 28, 1);
}
/*osd ctrl config*/
void osd_ctrl_set(struct osd_mif_reg_s *reg)
{
@@ -354,6 +362,7 @@ static int osd_check_state(struct meson_vpu_block *vblk,
mvos->phy_addr = plane_info->phy_addr;
mvos->pixel_format = plane_info->pixel_format;
mvos->fb_size = plane_info->fb_size;
mvos->premult_en = plane_info->premult_en;
return 0;
}
@@ -371,6 +380,7 @@ static void osd_set_state(struct meson_vpu_block *vblk,
u32 pixel_format, canvas_index, src_h, byte_stride, phy_addr;
struct osd_scope_s scope_src = {0, 1919, 0, 1079};
struct osd_mif_reg_s *reg = osd->reg;
bool alpha_div_en;
crtc = vblk->pipeline->crtc;
amc = to_am_meson_crtc(crtc);
@@ -379,6 +389,7 @@ static void osd_set_state(struct meson_vpu_block *vblk,
DRM_DEBUG("set_state break for NULL.\n");
return;
}
alpha_div_en = mvos->premult_en ? 1 : 0;
src_h = mvos->src_h;
byte_stride = mvos->byte_stride;
phy_addr = mvos->phy_addr;
@@ -388,12 +399,15 @@ static void osd_set_state(struct meson_vpu_block *vblk,
scope_src.v_end = mvos->src_y + mvos->src_h - 1;
pixel_format = mvos->pixel_format;
canvas_index = osd_canvas[vblk->index][osd_canvas_index[vblk->index]];
/*Toto: need to separate*/
osd_ctrl_set(osd->reg);
canvas_config(canvas_index, phy_addr, byte_stride, src_h,
CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
osd_canvas_index[vblk->index] ^= 1;
osd_canvas_config(reg, canvas_index);
osd_input_size_config(reg, scope_src);
osd_color_config(reg, pixel_format);
osd_alpha_div_enable(reg, alpha_div_en);
DRM_DEBUG("plane_index=%d,HW-OSD=%d\n",
mvos->plane_index, vblk->index);
DRM_DEBUG("canvas_index[%d]=0x%x,phy_addr=0x%x\n",
@@ -519,7 +533,6 @@ static void osd_hw_init(struct meson_vpu_block *vblk)
return;
}
osd->reg = &osd_mif_reg[vblk->index];
osd_ctrl_set(osd->reg);
DRM_DEBUG("%s hw_init done.\n", osd->base.name);
}

View File

@@ -256,6 +256,10 @@ static int meson_gpio_kp_probe(struct platform_device *pdev)
return -EINVAL;
}
}
//get all gpio desc.
desc = devm_gpiod_get_index(&pdev->dev, "key", i, GPIOD_IN);
if (IS_ERR_OR_NULL(desc))
return -EINVAL;
keypad->key[i].desc = desc;
//The gpio default is high level.
keypad->key[i].current_status = 1;

View File

@@ -492,8 +492,19 @@ static int fts_input_dev_report_b(struct ts_event *event, struct fts_ts_data *da
}
input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->area[i]);
input_report_abs(data->input_dev, ABS_MT_POSITION_X, event->au16_x[i]);
input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->au16_y[i]);
if (data->pdata->rotation) {
input_report_abs(data->input_dev, ABS_MT_POSITION_X,
data->pdata->x_max - event->au16_y[i]);
input_report_abs(data->input_dev, ABS_MT_POSITION_Y,
event->au16_x[i]);
} else {
input_report_abs(data->input_dev, ABS_MT_POSITION_X,
event->au16_x[i]);
input_report_abs(data->input_dev, ABS_MT_POSITION_Y,
event->au16_y[i]);
}
touchs |= BIT(event->au8_finger_id[i]);
data->touchs |= BIT(event->au8_finger_id[i]);
@@ -994,10 +1005,15 @@ static int fts_parse_dt(struct device *dev, struct fts_ts_platform_data *pdata)
rc = of_property_read_u32(np, "y_max", &temp_val);
if (!rc)
{
pdata->x_max = temp_val;
FTS_DEBUG("y_max=%d", pdata->x_max);
pdata->y_max = temp_val;
FTS_DEBUG("y_max=%d", pdata->y_max);
}
rc = of_property_read_u32(np, "rotation", &temp_val);
if (!rc) {
pdata->rotation = temp_val;
FTS_DEBUG("rotation = %d", pdata->rotation);
}
FTS_FUNC_EXIT();
return 0;

View File

@@ -109,20 +109,21 @@
struct fts_ts_platform_data
{
s32 irq_gpio;
u32 irq_gpio_flags;
s32 reset_gpio;
u32 reset_gpio_flags;
bool have_key;
u32 key_number;
u32 keys[4];
u32 key_y_coord;
u32 key_x_coords[4];
u32 x_max;
u32 y_max;
u32 x_min;
u32 y_min;
u32 max_touch_number;
s32 irq_gpio;
u32 irq_gpio_flags;
s32 reset_gpio;
u32 reset_gpio_flags;
bool have_key;
u32 key_number;
u32 keys[4];
u32 key_y_coord;
u32 key_x_coords[4];
u32 x_max;
u32 y_max;
u32 x_min;
u32 y_min;
u32 max_touch_number;
u32 rotation;
};
struct ts_event

View File

@@ -89,6 +89,7 @@ source "drivers/amlogic/media/vout/Kconfig"
source "drivers/amlogic/media/osd/Kconfig"
source "drivers/amlogic/media/osd_ext/Kconfig"
source "drivers/amlogic/media/deinterlace/Kconfig"
source "drivers/amlogic/media/di_multi/Kconfig"
source "drivers/amlogic/media/di_local/Kconfig"
source "drivers/amlogic/media/vin/Kconfig"
source "drivers/amlogic/media/video_processor/Kconfig"

View File

@@ -5,6 +5,7 @@ obj-$(CONFIG_AMLOGIC_MEDIA_FB) += osd/
obj-$(CONFIG_AMLOGIC_MEDIA_FB_EXT) += osd_ext/
obj-$(CONFIG_AMLOGIC_VOUT) += vout/
obj-$(CONFIG_AMLOGIC_MEDIA_DEINTERLACE) += deinterlace/
obj-$(CONFIG_AMLOGIC_MEDIA_DEINTERLACE) += di_multi/
obj-$(CONFIG_AMLOGIC_MEDIA_DEINTERLACE) += di_local/
obj-$(CONFIG_AMLOGIC_MEDIA_VIN) += vin/
obj-$(CONFIG_AMLOGIC_MEDIA_VIDEO_PROCESSOR) += video_processor/

View File

@@ -516,8 +516,8 @@ static void canvas_pool_config(void)
canvas_pool_register_const_canvas(0, 0x25, "amvdec");
canvas_pool_register_const_canvas(0x26, 0x39, "vdin");
canvas_pool_register_const_canvas(0x78, 0xbf, "amvdec");
canvas_pool_register_const_canvas(0x60, 0x65, "display");
canvas_pool_register_const_canvas(0x66, 0x6b, "display2");
canvas_pool_register_const_canvas(0x58, 0x6f, "display");
/* canvas_pool_register_const_canvas(0x66, 0x6b, "display2"); */
canvas_pool_register_const_canvas(0x70, 0x77, "ppmgr");
canvas_pool_register_const_canvas(0xe4, 0xef, "encoder");
canvas_pool_register_const_canvas(0x40, 0x48, "osd");

View File

@@ -800,6 +800,11 @@ void codec_mm_release(struct codec_mm_s *mem, const char *owner)
return;
spin_lock_irqsave(&mgt->lock, flags);
if (!codec_mm_valid_mm_locked(mem)) {
pr_err("codec mm not valied!\n");
spin_unlock_irqrestore(&mgt->lock, flags);
return;
}
index = atomic_dec_return(&mem->use_cnt);
max_owner = mem->owner[index];
for (i = 0; i < index; i++) {

View File

@@ -54,6 +54,7 @@ static void _fillrect(struct ge2d_context_s *wq,
ge2d_cmd_cfg->alpha_blend_mode = OPERATION_LOGIC;
ge2d_cmd_cfg->alpha_logic_op = LOGIC_OPERATION_COPY;
ge2d_cmd_cfg->wait_done_flag = 1;
ge2dgen_disable_matrix(wq);
ge2d_wq_add_work(wq);
}

View File

@@ -102,9 +102,9 @@ static void aml_dma_put(void *buf_priv)
buf->vaddr = NULL;
clear_dma_buffer((struct aml_dma_buffer *)buf->priv, buf->index);
put_device(buf->dev);
kfree(buf);
ge2d_log_dbg("ge2d free:aml_dma_buf=0x%p,buf->index=%d\n",
buf, buf->index);
kfree(buf);
}
static void *aml_dma_alloc(struct device *dev, unsigned long attrs,
@@ -129,6 +129,7 @@ static void *aml_dma_alloc(struct device *dev, unsigned long attrs,
if (cma_pages) {
paddr = page_to_phys(cma_pages);
} else {
kfree(buf);
pr_err("failed to alloc cma pages.\n");
return NULL;
}
@@ -148,7 +149,7 @@ static int aml_dma_mmap(void *buf_priv, struct vm_area_struct *vma)
{
struct aml_dma_buf *buf = buf_priv;
unsigned long pfn = 0;
unsigned long vsize = vma->vm_end - vma->vm_start;
unsigned long vsize;
int ret = -1;
if (!buf || !vma) {
@@ -156,6 +157,8 @@ static int aml_dma_mmap(void *buf_priv, struct vm_area_struct *vma)
return -EINVAL;
}
vsize = vma->vm_end - vma->vm_start;
pfn = buf->dma_addr >> PAGE_SHIFT;
ret = remap_pfn_range(vma, vma->vm_start, pfn,
vsize, vma->vm_page_prot);
@@ -206,11 +209,6 @@ static int aml_dmabuf_ops_attach(struct dma_buf *dbuf, struct device *dev,
for_each_sg(sgt->sgl, sg, sgt->nents, i) {
struct page *page = phys_to_page(phys);
if (!page) {
sg_free_table(sgt);
kfree(attach);
return -ENOMEM;
}
sg_set_page(sg, page, PAGE_SIZE, 0);
phys += PAGE_SIZE;
}

View File

@@ -260,7 +260,7 @@ static int ge2d_ioctl_config_ex_mem(struct ge2d_context_s *context,
ge2d_config_ex_mem = &(ge2d_para_config.para_config_memtype);
if (ge2d_para_config.para_config_memtype.ge2d_magic
== sizeof(struct config_para_ex_memtype_s)) {
== sizeof(struct compat_config_para_ex_memtype_s)) {
struct config_para_ex_ion_s *pge2d_config_ex;
uf_ex_mem =

View File

@@ -806,7 +806,7 @@ static int build_ge2d_config(struct ge2d_context_s *context,
update_canvas_cfg(canvas_cfg,
cfg->dst_planes[i].addr,
cfg->dst_planes[i].w *
src->bpp / 8,
dst->bpp / 8,
cfg->dst_planes[i].h);
}
}
@@ -824,7 +824,8 @@ static int setup_display_property(struct src_dst_para_s *src_dst, int index)
u32 cs_width = 0, cs_height = 0, cs_addr = 0;
unsigned int data32;
unsigned int bpp;
unsigned int block_mode[] = {2, 4, 8, 16, 16, 32, 0, 24};
unsigned int block_mode[] = {2, 4, 8, 16, 16, 32, 0, 24,
0, 0, 0, 0, 0, 0, 0, 0};
src_dst->canvas_index = index;
if (ge2d_meson_dev.canvas_status == 0) {

View File

@@ -430,3 +430,11 @@ void ge2dgen_const_color(struct ge2d_context_s *wq,
wq->config.update_flag |= UPDATE_DP_GEN;
}
}
void ge2dgen_disable_matrix(struct ge2d_context_s *wq)
{
struct ge2d_dp_gen_s *dp_gen_cfg = ge2d_wq_get_dp_gen(wq);
dp_gen_cfg->conv_matrix_en = 0;
wq->config.update_flag |= UPDATE_DP_GEN;
}

View File

@@ -84,6 +84,6 @@ void ge2dgen_cb(struct ge2d_context_s *wq,
void ge2dgen_const_color(struct ge2d_context_s *wq,
unsigned int color);
void ge2dgen_disable_matrix(struct ge2d_context_s *wq);
#endif

View File

@@ -254,8 +254,8 @@ static void line_n_int_rdma_irq(void *arg)
force_rdma_config[LINE_N_INT_RDMA] = 1;
else
force_rdma_config[LINE_N_INT_RDMA] = 0;
rdma_done[VSYNC_RDMA] = true;
irq_count[VSYNC_RDMA]++;
rdma_done[LINE_N_INT_RDMA] = true;
irq_count[LINE_N_INT_RDMA]++;
}
u32 VSYNC_RD_MPEG_REG(u32 adr)
@@ -428,8 +428,10 @@ static int __init rdma_init(void)
{
second_rdma_feature = 0;
#if 0 /*def LINE_INT_WORK_AROUND */
if (is_meson_g12b_revb())
second_rdma_feature = 1;
#endif
cur_enable[VSYNC_RDMA] = 0;
enable[VSYNC_RDMA] = 1;

View File

@@ -107,11 +107,18 @@ struct rdma_instance_s {
int prev_trigger_type;
};
#define MAX_CONFLICT 32
struct rdma_conflict_regs_s {
u32 adr[MAX_CONFLICT];
u32 val[MAX_CONFLICT];
};
struct rdma_device_info {
const char *device_name;
struct platform_device *rdma_dev;
struct class *clsp;
struct rdma_instance_s rdma_ins[RDMA_NUM];
struct rdma_conflict_regs_s rdma_reg;
};
static struct rdma_device_data_s rdma_meson_dev;
@@ -360,6 +367,7 @@ irqreturn_t rdma_mgr_isr(int irq, void *dev_id)
int retry_count = 0;
u32 rdma_status;
int i;
u32 read_val;
if (debug_flag & 0x10)
return IRQ_HANDLED;
rdma_isr_count++;
@@ -399,6 +407,13 @@ QUERY:
if ((rdma_status & 0xff000000) && (retry_count < 100))
goto QUERY;
#endif
for (i = 0; i < MAX_CONFLICT; i++) {
if (info->rdma_reg.adr[i]) {
read_val = READ_VCBUS_REG(info->rdma_reg.adr[i]);
if (read_val == info->rdma_reg.val[i])
info->rdma_reg.adr[i] = 0;
}
}
return IRQ_HANDLED;
}
@@ -622,19 +637,30 @@ u32 rdma_read_reg(int handle, u32 adr)
int i, j = 0;
u32 *write_table;
int match = 0;
int match_oth = 0;
int read_from = 0;
struct rdma_device_info *info = &rdma_info;
struct rdma_instance_s *ins = &info->rdma_ins[handle];
u32 read_val = READ_VCBUS_REG(adr);
for (i = (ins->rdma_item_count - 1); i >= 0; i--) {
if (ins->reg_buf[i << 1] == adr) {
read_val = ins->reg_buf[(i << 1) + 1];
match = 1;
read_from = 1;
for (i = 0; i < MAX_CONFLICT; i++) {
if (info->rdma_reg.adr[i] == adr) {
read_val = info->rdma_reg.val[i];
match_oth = 1;
read_from = 3;
break;
}
}
if (!match_oth) {
for (i = (ins->rdma_item_count - 1); i >= 0; i--) {
if (ins->reg_buf[i << 1] == adr) {
read_val = ins->reg_buf[(i << 1) + 1];
match = 1;
read_from = 1;
break;
}
}
}
if (!match) {
write_table = ins->rdma_table_addr;
for (i = (ins->rdma_write_count - 1);
@@ -650,7 +676,13 @@ u32 rdma_read_reg(int handle, u32 adr)
if (rdma_trace_enable) {
for (j = 0; j < rdma_trace_num; j++) {
if (adr == rdma_trace_reg[j]) {
if (read_from == 2)
if (read_from == 3)
pr_info("(%s) handle %d, %04x=0x%08x from conflict table(%d)\n",
__func__,
handle, adr,
read_val,
ins->rdma_write_count);
else if (read_from == 2)
pr_info("(%s) handle %d, %04x=0x%08x from write table(%d)\n",
__func__,
handle, adr,
@@ -704,6 +736,71 @@ int rdma_watchdog_setting(int flag)
}
EXPORT_SYMBOL(rdma_watchdog_setting);
static bool rdma_check_conflict(int handle, u32 adr, u32 *read_val)
{
struct rdma_instance_s *oth_ins;
int i, j, k, n;
for (i = 0; i < MAX_CONFLICT; i++) {
if (rdma_info.rdma_reg.adr[i] == adr) {
if (read_val != NULL)
*read_val = rdma_info.rdma_reg.val[i];
return true;
}
}
for (i = 0; i < RDMA_NUM; i++) {
oth_ins = &rdma_info.rdma_ins[i];
if ((!oth_ins->rdma_table_size)
|| (!oth_ins->rdma_item_count)
|| (i == handle))
continue;
for (j = 0; j < oth_ins->rdma_item_count; j++) {
if (oth_ins->reg_buf[j << 1] != adr)
continue;
for (n = 0; n < rdma_trace_num; n++) {
if ((adr == rdma_trace_reg[n]) ||
(debug_flag & 0x20))
pr_info(
"(%s) handle %d, conflict write %04x=0x%08x (oth handle %d)\n",
__func__,
handle, adr,
oth_ins->reg_buf[(j << 1) + 1],
i);
}
for (k = 0; k < MAX_CONFLICT; k++) {
if (!rdma_info.rdma_reg.adr[i]) {
rdma_info.rdma_reg.adr[k] = adr;
rdma_info.rdma_reg.val[k] =
oth_ins->reg_buf[(j << 1) + 1];
if (read_val != NULL)
*read_val = oth_ins->
reg_buf[(j << 1) + 1];
return true;
}
}
}
}
return false;
}
static void rdma_update_conflict(u32 adr, u32 val)
{
int i;
for (i = 0; i < MAX_CONFLICT; i++) {
if (rdma_info.rdma_reg.adr[i] == adr) {
rdma_info.rdma_reg.val[i] = val;
if (debug_flag & 0x20)
pr_info(
"(%s) %04x=0x%08x\n",
__func__,
adr, val);
break;
}
}
}
int rdma_write_reg(int handle, u32 adr, u32 val)
{
struct rdma_device_info *info = &rdma_info;
@@ -716,6 +813,9 @@ int rdma_write_reg(int handle, u32 adr, u32 val)
if (debug_flag & 1)
pr_info("rdma_write(%d) %d(%x)<=%x\n",
handle, ins->rdma_item_count, adr, val);
if (rdma_check_conflict(handle, adr, NULL))
rdma_update_conflict(adr, val);
if (((ins->rdma_item_count << 1) + 1) <
(ins->rdma_table_size / sizeof(u32))) {
ins->reg_buf[ins->rdma_item_count << 1] = adr;
@@ -755,20 +855,30 @@ int rdma_write_reg_bits(int handle, u32 adr, u32 val, u32 start, u32 len)
int i, j = 0;
u32 *write_table;
int match = 0;
int match_oth = 0;
int read_from = 0;
struct rdma_device_info *info = &rdma_info;
struct rdma_instance_s *ins = &info->rdma_ins[handle];
u32 read_val = READ_VCBUS_REG(adr);
u32 oth_val = 0;
u32 write_val;
if (ins->rdma_table_size == 0)
return -1;
if (rdma_check_conflict(handle, adr, &oth_val)) {
match_oth = 1;
read_val = oth_val;
read_from = 3;
}
for (i = (ins->rdma_item_count - 1); i >= 0; i--) {
if (ins->reg_buf[i << 1] == adr) {
read_val = ins->reg_buf[(i << 1) + 1];
match = 1;
read_from = 1;
if (!match_oth) {
read_val = ins->reg_buf[(i << 1) + 1];
read_from = 1;
}
break;
}
}
@@ -777,40 +887,48 @@ int rdma_write_reg_bits(int handle, u32 adr, u32 val, u32 start, u32 len)
for (i = (ins->rdma_write_count - 1);
i >= 0; i--) {
if (write_table[i << 1] == adr) {
read_val =
write_table[(i << 1) + 1];
read_from = 2;
if (!match_oth) {
read_val =
write_table[(i << 1) + 1];
read_from = 2;
}
break;
}
}
}
write_val = (read_val & ~(((1L<<(len))-1)<<(start)))
|((unsigned int)(val) << (start));
if (rdma_trace_enable) {
for (j = 0; j < rdma_trace_num; j++) {
if (adr == rdma_trace_reg[j]) {
if (read_from == 2)
pr_info("(%s) handle %d, %04x=0x%08x->0x%08x from write table(%d)\n",
__func__,
handle, adr,
read_val,
write_val,
ins->rdma_write_count);
else if (read_from == 1)
pr_info("(%s) handle %d, %04x=0x%08x->0x%08x from item table(%d)\n",
__func__,
handle, adr,
read_val,
write_val,
ins->rdma_item_count);
else
pr_info("(%s) handle %d, %04x=0x%08x->0x%08x from real reg\n",
__func__,
handle, adr,
read_val,
write_val);
}
if (match_oth)
rdma_update_conflict(adr, write_val);
for (j = 0; j < rdma_trace_num; j++) {
if (adr == rdma_trace_reg[j]) {
if (read_from == 3)
pr_info("(%s) handle %d, %04x=0x%08x->0x%08x from conflict table(%d)\n",
__func__,
handle, adr,
read_val,
write_val,
ins->rdma_write_count);
else if (read_from == 2)
pr_info("(%s) handle %d, %04x=0x%08x->0x%08x from write table(%d)\n",
__func__,
handle, adr,
read_val,
write_val,
ins->rdma_write_count);
else if (read_from == 1)
pr_info("(%s) handle %d, %04x=0x%08x->0x%08x from item table(%d)\n",
__func__,
handle, adr,
read_val,
write_val,
ins->rdma_item_count);
else
pr_info("(%s) handle %d, %04x=0x%08x->0x%08x from real reg\n",
__func__,
handle, adr,
read_val,
write_val);
}
}
if (match) {
@@ -1035,6 +1153,7 @@ static int rdma_probe(struct platform_device *pdev)
rdma_mgr_irq_request = 0;
memset((void *)&info->rdma_reg, 0, sizeof(struct rdma_conflict_regs_s));
for (i = 0; i < RDMA_NUM; i++) {
info->rdma_ins[i].rdma_table_size = 0;
if (rdma_meson_dev.rdma_ver == RDMA_VER_1)
@@ -1081,12 +1200,15 @@ static int rdma_probe(struct platform_device *pdev)
NULL, RDMA_TABLE_SIZE);
set_rdma_handle(VSYNC_RDMA, handle);
#if 0 /*def LINE_INT_WORK_AROUND */
if (is_meson_g12b_revb()) {
pr_info("g12b revb!!!!\n");
handle = rdma_register(get_rdma_ops(LINE_N_INT_RDMA),
NULL, RDMA_TABLE_SIZE);
set_rdma_handle(LINE_N_INT_RDMA, handle);
}
#endif
info->clsp = class_create(THIS_MODULE,
RDMA_MGR_CLASS_NAME);
if (IS_ERR(info->clsp)) {

View File

@@ -139,6 +139,8 @@ int vfm_map_remove(char *id)
int index;
int ret = 0;
if (IS_ERR_OR_NULL(id))
return -1;
if (!strcmp(id, "all")) {
for (i = 0; i < vfm_map_num; i++) {
if (vfm_map[i])
@@ -157,45 +159,56 @@ int vfm_map_add(char *id, char *name_chain)
{
int i, j;
int ret = -1;
char *ptr, *token = NULL;
char *ptr = NULL, *token = NULL;
struct vfm_map_s *p;
int old_num = vfm_map_num;
unsigned long flags;
int add_ok = 0;
int cnt = 10;
ulong addr;
p = kmalloc(sizeof(struct vfm_map_s), GFP_KERNEL);
if (!p) {
pr_err("%s: Error, map no mem!!\n", __func__);
return -ENOMEM;
}
ptr = kstrdup(name_chain, GFP_KERNEL);
addr = (ulong)ptr;
if (!ptr) {
kfree(p);
return -ENOMEM;
}
memset(p, 0, sizeof(struct vfm_map_s));
if (strlen(id) >= sizeof(p->id)) {
memcpy(p->id, id, sizeof(p->id));
p->id[sizeof(p->id)-1] = '\0';
} else
if (strlen(id) >= VFM_NAME_LEN - 1) {
memcpy(p->id, id, VFM_NAME_LEN - 1);
p->id[VFM_NAME_LEN - 1] = '\0';
} else {
memcpy(p->id, id, strlen(id));
}
p->valid = 1;
ptr = name_chain;
do {
token = strsep(&ptr, "\n ");
if (token == NULL)
if (!token)
break;
if (*token == '\0')
continue;
if (strlen(token) >= sizeof(p->name[p->vfm_map_size])) {
if (p->vfm_map_size >= VFM_MAP_SIZE)
break;
if (strlen(token) >= VFM_NAME_LEN - 1) {
memcpy(p->name[p->vfm_map_size], token,
sizeof(p->name[p->vfm_map_size]));
p->name[p->vfm_map_size][
sizeof(p->name[p->vfm_map_size])-1] = '\0';
} else
VFM_NAME_LEN - 1);
p->name[p->vfm_map_size][VFM_NAME_LEN - 1] = '\0';
} else {
memcpy(p->name[p->vfm_map_size], token, strlen(token));
}
p->vfm_map_size++;
} while (token && cnt--);
cnt = 10; /*limit the cnt of retry to avoid the infinite loop*/
kfree((void *)addr);
retry:
for (i = 0; i < vfm_map_num; i++) {
struct vfm_map_s *pi = vfm_map[i];
@@ -349,53 +362,53 @@ static void vfm_init(void)
{
#if ((defined CONFIG_AMLOGIC_POST_PROCESS_MANAGER) && \
(defined CONFIG_AMLOGIC_MEDIA_DEINTERLACE))
char def_id[] = "default";
char def_id[VFM_NAME_LEN] = "default";
#ifndef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
char def_name_chain[] = "decoder ppmgr deinterlace amvideo";
#else
char def_name_chain[] = "decoder amvideo";
#endif
#elif (defined CONFIG_AMLOGIC_POST_PROCESS_MANAGER)
char def_id[] = "default";
char def_id[VFM_NAME_LEN] = "default";
char def_name_chain[] = "decoder ppmgr amvideo";
#elif (defined CONFIG_AMLOGIC_MEDIA_DEINTERLACE)
char def_id[] = "default";
char def_id[VFM_NAME_LEN] = "default";
char def_name_chain[] = "decoder deinterlace amvideo";
#else /**/
char def_id[] = "default";
char def_id[VFM_NAME_LEN] = "default";
char def_name_chain[] = "decoder amvideo";
#endif /**/
#ifdef CONFIG_TVIN_VIUIN
char def_ext_id[] = "default_ext";
char def_ext_id[VFM_NAME_LEN] = "default_ext";
char def_ext_name_chain[] = "vdin amvideo2";
#endif /**/
#ifdef CONFIG_VDIN_MIPI
char def_mipi_id[] = "default_mipi";
char def_mipi_id[VFM_NAME_LEN] = "default_mipi";
char def_mipi_name_chain[] = "vdin mipi";
#endif /**/
#ifdef CONFIG_AMLOGIC_V4L_VIDEO2
char def_amlvideo2_id[] = "default_amlvideo2";
char def_amlvideo2_id[VFM_NAME_LEN] = "default_amlvideo2";
char def_amlvideo2_chain[] = "vdin1 amlvideo2.1";
#endif /**/
#if (defined CONFIG_TVIN_AFE) || (defined CONFIG_TVIN_HDMI)
#ifdef CONFIG_AMLOGIC_POST_PROCESS_MANAGER
char tvpath_id[] = "tvpath";
char tvpath_id[VFM_NAME_LEN] = "tvpath";
char tvpath_chain[] = "vdin0 ppmgr deinterlace amvideo";
#else
char tvpath_id[] = "tvpath";
char tvpath_id[VFM_NAME_LEN] = "tvpath";
char tvpath_chain[] = "vdin0 deinterlace amvideo";
#endif
#endif /**/
#ifdef CONFIG_AMLOGIC_MEDIA_ENHANCEMENT_DOLBYVISION
char def_dvbl_id[] = "dvblpath";
char def_dvbl_id[VFM_NAME_LEN] = "dvblpath";
/* char def_dvbl_chain[] = "dvbldec dvbl amvideo";*/
char def_dvbl_chain[] = "dvbldec amvideo";
char def_dvel_id[] = "dvelpath";
char def_dvel_id[VFM_NAME_LEN] = "dvelpath";
char def_dvel_chain[] = "dveldec dvel";
#endif
#if 1/*def CONFIG_AM_HDMIIN_DV*/
char def_dvhdmiin_id[] = "dvhdmiin";
char def_dvhdmiin_id[VFM_NAME_LEN] = "dvhdmiin";
char def_dvhdmiin_chain[] = "dv_vdin amvideo";
#endif
int i;
@@ -476,17 +489,20 @@ static inline struct vframe_s *vfm_vf_peek(
static void vfm_dump_provider(const char *name)
{
struct vframe_provider_s *prov = vf_get_provider_by_name(name);
struct vframe_provider_s *prov;
struct vframe_states states;
unsigned long flags;
struct vframe_s *vf;
char *buf, *pbuf;
if (!prov)
if (IS_ERR_OR_NULL(name))
return;
prov = vf_get_provider_by_name(name);
if (IS_ERR_OR_NULL(prov))
return;
buf = kzalloc(0x400, GFP_KERNEL);
if (buf == NULL)
if (!buf)
return;
pbuf = buf;
@@ -738,19 +754,23 @@ static long vfm_ioctl(struct file *file, unsigned int cmd, ulong arg)
struct vfmctl *user_argp = (void __user *)arg;
struct vfmctl argp;
if (IS_ERR_OR_NULL(user_argp))
return -EINVAL;
memset(&argp, 0, sizeof(struct vfmctl));
switch (cmd) {
case VFM_IOCTL_CMD_SET:{
ret =
copy_from_user(argp.name, user_argp->name, sizeof(argp.name)-1);
ret |=
copy_from_user(argp.val, user_argp->val, sizeof(argp.val) - 1);
ret = copy_from_user(argp.name, user_argp->name,
sizeof(argp.name) - 1);
argp.name[sizeof(argp.name) - 1] = '\0';
ret |= copy_from_user(argp.val, user_argp->val,
sizeof(argp.val) - 1);
argp.val[sizeof(argp.val) - 1] = '\0';
if (ret)
ret = -EINVAL;
else
ret =
vfm_map_store(NULL, NULL, argp.val, sizeof(argp.val) - 1);
ret = vfm_map_store(NULL, NULL, argp.val,
sizeof(argp.val) - 1);
}
break;
case VFM_IOCTL_CMD_GET:{
@@ -766,39 +786,46 @@ static long vfm_ioctl(struct file *file, unsigned int cmd, ulong arg)
}
break;
case VFM_IOCTL_CMD_ADD:{
ret =
copy_from_user(argp.name, user_argp->name, sizeof(argp.name)-1);
ret |=
copy_from_user(argp.val, user_argp->val, sizeof(argp.val) - 1);
ret = copy_from_user(argp.name, user_argp->name,
sizeof(argp.name) - 1);
argp.name[sizeof(argp.name) - 1] = '\0';
ret |= copy_from_user(argp.val, user_argp->val,
sizeof(argp.val) - 1);
argp.val[sizeof(argp.val) - 1] = '\0';
if (ret)
ret = -EINVAL;
else
ret = vfm_map_add(argp.name, argp.val);
ret = vfm_map_add(argp.name, argp.val);
}
break;
case VFM_IOCTL_CMD_RM:{
ret =
copy_from_user(argp.val, user_argp->val, sizeof(argp.val) - 1);
ret = copy_from_user(argp.val, user_argp->val,
sizeof(argp.val) - 1);
argp.val[sizeof(argp.val) - 1] = '\0';
if (ret)
ret = -EINVAL;
else
ret = vfm_map_remove(argp.val);
ret = vfm_map_remove(argp.val);
}
break;
case VFM_IOCTL_CMD_DUMP:{
ret =
copy_from_user(argp.val, user_argp->val, sizeof(argp.val) - 1);
ret = copy_from_user(argp.val, user_argp->val,
sizeof(argp.val) - 1);
argp.val[sizeof(argp.val) - 1] = '\0';
if (ret)
ret = -EINVAL;
vfm_dump_provider(argp.val);
else
vfm_dump_provider(argp.val);
}
break;
case VFM_IOCTL_CMD_ADDDUMMY:{
ret =
copy_from_user(argp.val, user_argp->val, sizeof(argp.val) - 1);
ret = copy_from_user(argp.val, user_argp->val,
sizeof(argp.val) - 1);
argp.val[sizeof(argp.val) - 1] = '\0';
if (ret)
ret = -EINVAL;
add_dummy_receiver(argp.val);
else
add_dummy_receiver(argp.val);
}
break;

View File

@@ -510,7 +510,9 @@ static struct vpu_ctrl_s vpu_mem_pd_tm2[] = {
{VPU_TCON, HHI_VPU_MEM_PD_REG3, 0x3, 16, 16},
{VPU_AXI_WR1, HHI_VPU_MEM_PD_REG4, 0x3, 0, 2},
{VPU_AXI_WR0, HHI_VPU_MEM_PD_REG4, 0x3, 2, 2},
{VPU_DMA, HHI_VPU_MEM_PD_REG4, 0xf, 4, 4},
{VPU_AFBCE, HHI_VPU_MEM_PD_REG4, 0x3, 4, 2},
{VPU_VDIN_WR_MIF2, HHI_VPU_MEM_PD_REG4, 0x3, 6, 2},
{VPU_DMA, HHI_VPU_MEM_PD_REG4, 0xf, 8, 4},
{VPU_MOD_MAX, VPU_REG_END, 0, 0, 0},
};

View File

@@ -85,7 +85,8 @@ static char *vpu_mod_table[] = {
"axi_wr1",
"axi_wr0",
"afbce",
"dma"
"vdin_wr_mif2",
"dma",
"vpu_mod_max",

View File

@@ -118,6 +118,7 @@ static bool mc_mem_alloc;
static unsigned int di_pre_rdma_enable;
static struct mutex di_event_mutex;
static atomic_t di_flag_unreg; //ary 2019-05-27
static atomic_t di_trig_free_mem;
static unsigned int di_force_bit_mode = 10;
module_param(di_force_bit_mode, uint, 0664);
@@ -319,7 +320,8 @@ void trigger_pre_di_process(unsigned char idx)
{
if (di_sema_init_flag == 0)
return;
if (!active_flag)
return;
log_buffer_state((idx == 'i') ? "irq" : ((idx == 'p') ?
"put" : ((idx == 'r') ? "rdy" : "oth")));
@@ -461,6 +463,7 @@ static int lDI_POST_WR_REG_BITS(u32 adr, u32 val, u32 start, u32 len)
static const struct di_ext_ops di_ext = {
.di_post_reg_rd = lDI_POST_REG_RD,
.di_post_wr_reg_bits = lDI_POST_WR_REG_BITS,
.post_update_mc = di_patch_post_update_mc,
};
#endif
@@ -561,6 +564,42 @@ int get_di_dump_state_flag(void)
{
return dump_state_flag;
}
/********************************************
* function: for releas mirror mem
* need call this after unreg di
********************************************/
void di_trig_free_mirror_mem(void)
{
if (atomic_read(&di_flag_unreg)
&& de_devp->flag_cma != 2
&& de_devp->flag_cma != 0
&& active_flag) {
atomic_set(&di_trig_free_mem, 1);
up(&di_sema);
di_pr_info("%s\n", __func__);
}
}
EXPORT_SYMBOL(di_trig_free_mirror_mem);
static bool di_free_mem_pre(void)
{
if (!atomic_read(&di_trig_free_mem))
return false;
if (di_pre_stru.cma_alloc_done)
return false;
if (!di_post_stru.keep_buf
|| !atomic_read(&di_flag_unreg)) {
atomic_set(&di_trig_free_mem, 0);
return false;
}
/*free mirror memory*/
di_post_stru.keep_buf = NULL;
return true;
}
/*--------------------------*/
static void parse_param_di(char *buf_orig, char **parm)
@@ -656,6 +695,8 @@ store_dbg(struct device *dev,
dump_post_mif_reg();
} else if (strncmp(buf, "recycle_buf", 11) == 0) {
recycle_keep_buffer();
} else if (strncmp(buf, "free_mirror", 11) == 0) {
di_trig_free_mirror_mem();
} else if (strncmp(buf, "recycle_post", 12) == 0) {
if (di_vf_peek(NULL))
di_vf_put(di_vf_get(NULL), NULL);
@@ -1055,10 +1096,10 @@ struct di_buf_s *get_di_buf(int queue_idx, int *start_pos)
if (di_log_flag & DI_LOG_QUEUE) {
if (di_buf)
di_print("%s: %x(%d,%d)\n", __func__, di_buf,
pool_idx, di_buf_idx);
di_print("%s: 0x%p(%d,%d)\n", __func__, di_buf,
pool_idx, di_buf_idx);
else
di_print("%s: %x\n", __func__, di_buf);
di_print("%s: 0x%p\n", __func__, di_buf);
}
return di_buf;
@@ -1113,10 +1154,10 @@ static struct di_buf_s *get_di_buf_head(int queue_idx)
if (di_log_flag & DI_LOG_QUEUE) {
if (di_buf)
di_print("%s: %x(%d,%d)\n", __func__, di_buf,
pool_idx, di_buf_idx);
di_print("%s: 0x%p(%d,%d)\n", __func__, di_buf,
pool_idx, di_buf_idx);
else
di_print("%s: %x\n", __func__, di_buf);
di_print("%s: 0x%p\n", __func__, di_buf);
}
return di_buf;
@@ -1141,9 +1182,9 @@ static void queue_out(struct di_buf_s *di_buf)
q = &(queue[di_buf->queue_index]);
if (di_log_flag & DI_LOG_QUEUE)
di_print("%s:<%d:%d,%d,%d> %x\n", __func__,
di_buf->queue_index, q->num, q->in_idx,
q->out_idx, di_buf);
di_print("%s:<%d:%d,%d,%d> 0x%p\n", __func__,
di_buf->queue_index, q->num, q->in_idx,
q->out_idx, di_buf);
if (q->num > 0) {
if (q->type == 0) {
@@ -1264,8 +1305,8 @@ static void queue_in(struct di_buf_s *di_buf, int queue_idx)
}
q = &(queue[queue_idx]);
if (di_log_flag & DI_LOG_QUEUE)
di_print("%s:<%d:%d,%d,%d> %x\n", __func__, queue_idx,
q->num, q->in_idx, q->out_idx, di_buf);
di_print("%s:<%d:%d,%d,%d> 0x%p\n", __func__, queue_idx,
q->num, q->in_idx, q->out_idx, di_buf);
if (q->type == 0) {
q->pool[q->in_idx] = (di_buf->type << 8) | (di_buf->index);
@@ -1702,6 +1743,10 @@ unsigned char is_bypass(vframe_t *vf_in)
return 1;
if (vf_in && (vf_in->type & VIDTYPE_PIC))
return 1;
if ((is_meson_gxl_package_805X() || is_meson_gxl_package_805Y()) &&
vf_in && is_progressive(vf_in))
return 1;
#if 0
if (vf_in && (vf_in->type & VIDTYPE_COMPRESS))
return 1;
@@ -2407,6 +2452,173 @@ static void di_cma_release(struct di_dev_s *devp)
__func__, rels_cnt, delta_time, start_time, end_time);
}
#endif
static void di_patch_mov_ini(void)
{
struct di_patch_mov_s *pmov;
if (!de_devp)
return;
pmov = &de_devp->mov;
if (!cpu_after_eq(MESON_CPU_MAJOR_ID_TL1)) {
pmov->en_support = false;
return;
}
pmov->en_support = true;
pmov->mode = -1;
pmov->nub = 0;
}
bool di_patch_mov_db(unsigned int addr, unsigned int val)
{
bool ret = false;
int i;
struct di_patch_mov_s *pmov;
struct di_patch_mov_d_s *pmv;
if (!de_devp)
return ret;
pmov = &de_devp->mov;
if (!pmov->en_support || !pmov->nub)
return ret;
for (i = 0; i < pmov->nub; i++) {
if (addr == pmov->reg_addr[i]) {
pmv = &pmov->val_db[i];
pmv->val = val;
pmv->en = true;
pmv->mask = 0xffffffff;
ret = true;
}
}
return ret;
}
void di_patch_mov_setreg(unsigned int nub, unsigned int *preg)
{
struct di_patch_mov_s *pmov;
unsigned int i;
if (!de_devp)
return;
pmov = &de_devp->mov;
if (!pmov->en_support)
return;
pmov->nub = nub;
if (nub > DI_PATCH_MOV_MAX_NUB) {
pr_error("err: %s:nub is overflow %d\n",
__func__, nub);
pmov->nub = DI_PATCH_MOV_MAX_NUB;
}
pmov->mode = -1;
for (i = 0; i < pmov->nub; i++) {
pmov->reg_addr[i] = preg[i];
di_pr_info("reg:0x%x\n", preg[i]);
}
}
EXPORT_SYMBOL(di_patch_mov_setreg);
/**************************************************
* pdate:
* value / mask
* value / mask
* need keep same order with di_patch_mov_setreg
**************************************************/
bool di_api_mov_sel(unsigned int mode, unsigned int *pdate)
{
struct di_patch_mov_s *pmov;
int i;
struct di_patch_mov_d_s *pmv;
bool ret = true;
if (!de_devp)
return false;
pmov = &de_devp->mov;
if (!pmov ||
!pmov->en_support ||
!init_flag)
return false;
switch (mode) {
case 0:/*setting from db*/
pmov->mode = 0;
pmov->update = 1;
break;
case 1:/*setting from pq*/
pmov->update = 0;
for (i = 0; i < pmov->nub; i++) {
pmv = &pmov->val_pq[i];
pmv->val = pdate[i * 2];
pmv->mask = pdate[i * 2 + 1];
pmv->en = true;
}
pmov->mode = 1;
pmov->update = true;
break;
default:
ret = false;
break;
}
return ret;
}
EXPORT_SYMBOL(di_api_mov_sel);
static void di_patch_mov_setting(void)
{
struct di_patch_mov_s *pmov;
int i;
struct di_patch_mov_d_s *pmv;
unsigned int val;
if (!de_devp)
return;
pmov = &de_devp->mov;
if (!pmov ||
!pmov->en_support ||
pmov->mode < 0 ||
pmov->mode > 1 ||
!pmov->update)
return;
if (pmov->mode == 0)
pmv = &pmov->val_db[0];
else
pmv = &pmov->val_pq[0];
for (i = 0; i < pmov->nub; i++) {
if (pmv->en) {
if (pmv->mask != 0xffffffff) {
val = ((RDMA_RD(pmov->reg_addr[i]) &
(~(pmv->mask))) |
(pmv->val & pmv->mask));
} else {
val = pmv->val;
}
DI_Wr(pmov->reg_addr[i], val);
}
pmv++;
}
pmov->update = 0;
}
void di_set_comb_mode(unsigned int mode)
{
di_pre_stru.comb_mode = mode;
}
EXPORT_SYMBOL(di_set_comb_mode);
static int di_init_buf(int width, int height, unsigned char prog_flag)
{
int i;
@@ -2997,7 +3209,7 @@ config_di_pre_mc_mif(struct DI_MC_MIF_s *di_mcinfo_mif,
if (di_buf) {
pre_size_w = di_buf->vframe->width;
pre_size_h = (di_buf->vframe->height + 1) / 2;
di_mcinfo_mif->size_x = (pre_size_h + 1) / 2 - 1;
di_mcinfo_mif->size_x = pre_size_h / 2 - 1;
di_mcinfo_mif->size_y = 1;
di_mcinfo_mif->canvas_num = di_buf->mcinfo_canvas_idx;
@@ -3127,7 +3339,7 @@ static void config_di_mif(struct DI_MIF_s *di_mif, struct di_buf_s *di_buf)
di_buf->vframe->width / 2 - 1;
di_mif->chroma_y_start0 = 0;
di_mif->chroma_y_end0 =
di_buf->vframe->height / 2 - 1;
(di_buf->vframe->height + 1) / 2 - 1;
} else {
if (di_pre_stru.cur_inp_type & VIDTYPE_INTERLACE)
di_mif->src_prog = 0;
@@ -3143,14 +3355,13 @@ static void config_di_mif(struct DI_MIF_s *di_mif, struct di_buf_s *di_buf)
di_buf->vframe->width - 1;
di_mif->luma_y_start0 = 0;
di_mif->luma_y_end0 =
di_buf->vframe->height - 2;
di_buf->vframe->height - 1;
di_mif->chroma_x_start0 = 0;
di_mif->chroma_x_end0 =
di_buf->vframe->width / 2 - 1;
di_mif->chroma_y_start0 = 0;
di_mif->chroma_y_end0 =
di_buf->vframe->height / 2
- (di_mif->src_prog?1:2);
(di_buf->vframe->height + 1) / 2 - 1;
} else {
di_mif->output_field_num = 1;
/* bottom */
@@ -3166,7 +3377,7 @@ static void config_di_mif(struct DI_MIF_s *di_mif, struct di_buf_s *di_buf)
di_mif->chroma_y_start0 =
(di_mif->src_prog?0:1);
di_mif->chroma_y_end0 =
di_buf->vframe->height / 2 - 1;
(di_buf->vframe->height + 1) / 2 - 1;
}
}
}
@@ -3350,6 +3561,7 @@ static void pre_de_process(void)
di_pre_stru.input_size_change_flag = false;
}
di_patch_mov_setting();
if (cpu_after_eq(MESON_CPU_MAJOR_ID_G12A)) {
if (de_devp->nrds_enable) {
nr_ds_mif_config();
@@ -3407,6 +3619,9 @@ static void pre_de_process(void)
}
di_pre_stru.field_count_for_cont++;
if (di_pre_stru.field_count_for_cont >= 5)
DI_Wr_reg_bits(DI_MTN_CTRL, 0, 30, 1);
di_txl_patch_prog(di_pre_stru.cur_prog_flag,
di_pre_stru.field_count_for_cont, mcpre_en);
@@ -3424,14 +3639,16 @@ static void pre_de_process(void)
* otherwise may cause watch dog reboot
*/
di_lock_irqfiq_save(irq_flag2);
if (cpu_after_eq(MESON_CPU_MAJOR_ID_G12A))
if (cpu_after_eq(MESON_CPU_MAJOR_ID_G12A)) {
/* enable mc pre mif*/
enable_di_pre_mif(true, mcpre_en);
pre_frame_reset_g12(di_pre_stru.madi_enable,
di_pre_stru.mcdi_enable);
else
} else {
pre_frame_reset();
/* enable mc pre mif*/
enable_di_pre_mif(true, mcpre_en);
/* enable mc pre mif*/
enable_di_pre_mif(true, mcpre_en);
}
di_unlock_irqfiq_restore(irq_flag2);
/*reinit pre busy flag*/
di_pre_stru.pre_de_busy_timer_count = 0;
@@ -3536,8 +3753,10 @@ static void pre_de_done_buf_config(void)
di_pre_stru.di_post_wr_buf = di_pre_stru.di_wr_buf;
post_wr_buf = di_pre_stru.di_post_wr_buf;
if (post_wr_buf)
if (post_wr_buf) {
post_wr_buf->vframe->di_pulldown = 0;
post_wr_buf->vframe->di_gmv = 0;
}
if (post_wr_buf && !di_pre_stru.cur_prog_flag) {
read_pulldown_info(&glb_frame_mot_num,
@@ -3552,7 +3771,8 @@ static void pre_de_done_buf_config(void)
}
post_wr_buf->vframe->di_pulldown |= 0x08;
if (combing_fix_en)
post_wr_buf->vframe->di_gmv = glb_frame_mot_num;
if (di_pre_stru.combing_fix_en)
cur_lev = adaptive_combing_fixing(
di_pre_stru.mtn_status,
glb_field_mot_num,
@@ -3890,7 +4110,9 @@ static unsigned char pre_de_buf_config(void)
unsigned int width_roundup = 2;
u32 rls_timeout;
u32 afbc_busy;
u32 is_afbc_mode;
u32 is_afbc_mode = 0;
bool flg_1080i = false;
bool flg_480i = false;
if (di_blocking || !atomic_read(&de_devp->mem_flag))
return 0;
@@ -3960,7 +4182,8 @@ static unsigned char pre_de_buf_config(void)
/*for support compress from dec*/
if (IS_COMP_MODE(vframe->type) &&
!is_bypass(vframe)) {
!is_bypass(vframe) &&
afbc_is_supported()) {
is_afbc_mode = true;
if (IS_VDIN_SRC(vframe->source_type)
&& IS_I_SRC(vframe->type)) {
@@ -4395,14 +4618,11 @@ jiffies_to_msecs(jiffies_64 - vframe->ready_jiffies64));
} else {
/*********************************/
if ((di_buf->vframe->width >= 1920) &&
(di_buf->vframe->height >= 1080) &&
is_meson_tl1_cpu()) {
if (combing_fix_en) {
combing_fix_en = false;
fix_tl1_1080i_sawtooth_patch();
}
} else
combing_fix_en = true;
(di_buf->vframe->height >= 1080))
flg_1080i = true;
else if ((di_buf->vframe->width == 720) &&
(di_buf->vframe->height == 480))
flg_480i = true;
/*********************************/
if (
@@ -4586,6 +4806,23 @@ jiffies_to_msecs(jiffies_64 - vframe->ready_jiffies64));
recovery_flag++;
return 0;
}
if (is_meson_tl1_cpu() &&
di_pre_stru.comb_mode &&
flg_1080i) {
di_pre_stru.combing_fix_en = false;
fix_tl1_1080i_patch_sel(di_pre_stru.comb_mode);
} else {
di_pre_stru.combing_fix_en = combing_fix_en;
}
if (di_pre_stru.combing_fix_en) {
if (flg_1080i)
com_patch_pre_sw_set(1);
else if (flg_480i)
com_patch_pre_sw_set(2);
else
com_patch_pre_sw_set(0);
}
return 1;
}
@@ -4594,10 +4831,16 @@ static int check_recycle_buf(void)
struct di_buf_s *di_buf = NULL;/* , *ptmp; */
int itmp;
int ret = 0;
bool blk_flg = 0;
#ifdef DI_KEEP_HIS
if (di_blocking)
return ret;
#endif
queue_for_each_entry(di_buf, ptmp, QUEUE_RECYCLE, list) {
if (di_blocking)
blk_flg = 1;
if ((di_buf->pre_ref_count == 0) &&
(di_buf->post_ref_count == 0)) {
if (di_buf->type == VFRAME_TYPE_IN) {
@@ -4610,7 +4853,7 @@ static int check_recycle_buf(void)
VFRAME_EVENT_RECEIVER_PUT,
NULL);
di_print(
"%s: vf_put(%d) %x, %u ms\n",
"%s: vf_put(%d) 0x%p, %u ms\n",
__func__,
di_pre_stru.recycle_seq,
vframe_in[di_buf->index],
@@ -4649,6 +4892,10 @@ static int check_recycle_buf(void)
#endif
}
}
if (blk_flg)
pr_info("di:blk:recycle\n");
return ret;
}
@@ -4890,8 +5137,10 @@ static irqreturn_t de_irq(int irq, void *dev_instance)
DI_Wr(DI_INTR_CTRL, data32);
}
#else
if (flag)
if (flag) {
di_hpre_gl_sw(false);
DI_Wr(DI_INTR_CTRL, (data32&0xfffffffb)|(intr_mode<<30));
}
#endif
if (di_pre_stru.pre_de_busy == 0) {
@@ -6737,9 +6986,10 @@ static void di_pre_size_change(unsigned short width,
}
di_load_pq_table();
#ifdef OLD_PRE_GL
if (cpu_after_eq(MESON_CPU_MAJOR_ID_G12A))
RDMA_WR(DI_PRE_GL_CTRL, 0x80000005);
#endif
if (de_devp->nrds_enable)
nr_ds_init(width, height);
if (de_devp->pps_enable && pps_position) {
@@ -6766,6 +7016,10 @@ static void di_pre_size_change(unsigned short width,
static bool need_bypass(struct vframe_s *vf)
{
needbypass_flag = true;
if ((is_meson_gxl_package_805X() || is_meson_gxl_package_805Y()) &&
is_progressive(vf))
return true;
if (vf->type & VIDTYPE_MVC)
return true;
@@ -6881,6 +7135,7 @@ static void di_reg_process_irq(void)
DI_Wr(DI_CLKG_CTRL, 0xfef60001);
/* nr/blend0/ei0/mtn0 clock gate */
}
di_hdr2_hist_init();
if (di_printk_flag & 2)
di_printk_flag = 1;
@@ -6955,7 +7210,7 @@ static void di_reg_process_irq(void)
di_pre_stru.retry_index = 0;
init_flag = 1;
di_pre_stru.reg_req_flag_irq = 1;
/*di_pre_stru.reg_req_flag_irq = 1;*/
}
di_pre_stru.reg_irq_busy = false;
}
@@ -7149,66 +7404,79 @@ static int di_task_handle(void *data)
ret = down_interruptible(&di_sema);
if (ret != 0)
continue;
if (active_flag) {
if ((di_pre_stru.unreg_req_flag ||
di_pre_stru.force_unreg_req_flag ||
di_pre_stru.disable_req_flag) &&
(di_pre_stru.pre_de_busy == 0)) {
di_unreg_process();
if (!de_devp)
continue;
if (!active_flag)
continue;
if ((di_pre_stru.unreg_req_flag ||
di_pre_stru.force_unreg_req_flag ||
di_pre_stru.disable_req_flag) &&
(di_pre_stru.pre_de_busy == 0)) {
di_unreg_process();
#if 0
/* if mirror mode, can't speed down the clk*/
/* set min rate for power saving */
if (de_devp->vpu_clkb) {
clk_set_rate(de_devp->vpu_clkb,
de_devp->clkb_min_rate);
}
/* if mirror mode, can't speed down the clk*/
/* set min rate for power saving */
if (de_devp->vpu_clkb) {
clk_set_rate(de_devp->vpu_clkb,
de_devp->clkb_min_rate);
}
#endif
}
if (di_pre_stru.reg_req_flag_irq ||
di_pre_stru.reg_req_flag) {
di_reg_process();
di_pre_stru.reg_req_flag = 0;
di_pre_stru.reg_req_flag_irq = 0;
}
#ifdef CONFIG_CMA
/* mutex_lock(&de_devp->cma_mutex);*/
if (di_pre_stru.cma_release_req) {
atomic_set(&devp->mem_flag, 0);
di_cma_release(devp);
di_pre_stru.cma_release_req = 0;
di_pre_stru.cma_alloc_done = 0;
}
if (di_pre_stru.cma_alloc_req) {
if (di_cma_alloc(devp))
atomic_set(&devp->mem_flag, 1);
else
atomic_set(&devp->mem_flag, 0);
di_pre_stru.cma_alloc_req = 0;
di_pre_stru.cma_alloc_done = 1;
}
/* mutex_unlock(&de_devp->cma_mutex); */
#endif
}
if (/*di_pre_stru.reg_req_flag_irq ||*/
di_pre_stru.reg_req_flag) {
di_reg_process();
di_pre_stru.reg_req_flag = 0;
/*di_pre_stru.reg_req_flag_irq = 0;*/
}
#ifdef CONFIG_CMA
/* mutex_lock(&de_devp->cma_mutex);*/
if (di_pre_stru.cma_release_req) {
atomic_set(&devp->mem_flag, 0);
di_cma_release(devp);
di_pre_stru.cma_release_req = 0;
di_pre_stru.cma_alloc_done = 0;
}
if (di_pre_stru.cma_alloc_req) {
if (di_cma_alloc(devp))
atomic_set(&devp->mem_flag, 1);
else
atomic_set(&devp->mem_flag, 0);
di_pre_stru.cma_alloc_req = 0;
di_pre_stru.cma_alloc_done = 1;
}
if (di_free_mem_pre()) {
di_cma_release(devp);
di_pr_info("release mirror\n");
atomic_set(&di_trig_free_mem, 0);
}
/* mutex_unlock(&de_devp->cma_mutex); */
#endif
if (de_devp->flags & DI_VPU_CLKB_SET) {
if (is_meson_txlx_cpu()) {
if (!use_2_interlace_buff) {
#ifdef CLK_TREE_SUPPORT
clk_set_rate(de_devp->vpu_clkb,
de_devp->clkb_min_rate);
de_devp->clkb_min_rate);
#endif
} else {
#ifdef CLK_TREE_SUPPORT
clk_set_rate(de_devp->vpu_clkb,
de_devp->clkb_max_rate);
de_devp->clkb_max_rate);
#endif
}
}
if (is_meson_g12a_cpu() || is_meson_g12b_cpu()
|| is_meson_tl1_cpu() || is_meson_tm2_cpu() ||
is_meson_sm1_cpu()) {
if (is_meson_g12a_cpu() ||
is_meson_g12b_cpu() ||
is_meson_tl1_cpu() ||
is_meson_tm2_cpu() ||
is_meson_sm1_cpu()) {
#ifdef CLK_TREE_SUPPORT
clk_set_rate(de_devp->vpu_clkb,
de_devp->clkb_max_rate);
de_devp->clkb_max_rate);
#endif
}
de_devp->flags &= (~DI_VPU_CLKB_SET);
@@ -7230,7 +7498,7 @@ static void di_pre_process_irq(struct di_pre_stru_s *pre_stru_p)
if (pre_stru_p->unreg_req_flag_irq &&
(di_pre_stru.pre_de_busy == 0))
di_unreg_process_irq();
if (init_flag == 0 && pre_stru_p->reg_req_flag_irq == 0
if (init_flag == 0 /*&& pre_stru_p->reg_req_flag_irq == 0*/
&& (!atomic_read(&di_flag_unreg)))
di_reg_process_irq();
}
@@ -7258,9 +7526,38 @@ static enum hrtimer_restart di_pre_hrtimer_func(struct hrtimer *timer)
if (!di_pre_stru.bypass_flag)
di_pre_trigger_work(&di_pre_stru);
hrtimer_forward_now(&di_pre_hrtimer, ms_to_ktime(10));
di_patch_post_update_mc();
/*di_patch_post_update_mc();*/
return HRTIMER_RESTART;
}
static void post_display_buf_clear(void)
{
struct di_buf_s *p = NULL;
int itmp;
pr_info("%s:\n", __func__);
queue_for_each_entry(p, ptmp, QUEUE_DISPLAY, list) {
pr_info("\t%s,%d\n", vframe_type_name[p->type], p->index);
if (p->type == VFRAME_TYPE_POST) {
if (!atomic_dec_and_test(&p->di_cnt))
di_print("%s,di_cnt > 0\n", __func__);
recycle_vframe_type_post(p);
} else {
queue_in(p, QUEUE_RECYCLE);
di_print("%s: %s[%d] =>recycle_list\n", __func__,
vframe_type_name[p->type], p->index);
}
}
}
static void dbg_check_list(void)
{
unsigned int post_display;
post_display = list_count(QUEUE_DISPLAY);
di_pr_info("display:%d\n", post_display);
}
/*
* provider/receiver interface
*/
@@ -7330,40 +7627,64 @@ static int di_receiver_event_fun(int type, void *data, void *arg)
mutex_unlock(&di_event_mutex);
pr_info("DI: unreg f\n");
} else if (type == VFRAME_EVENT_PROVIDER_RESET) {
di_blocking = 1;
/*di_blocking = 1;*/
mutex_lock(&di_event_mutex);
pr_info("%s: VFRAME_EVENT_PROVIDER_RESET\n", __func__);
if (is_bypass(NULL)
|| bypass_state
|| di_pre_stru.bypass_flag) {
/* only if di is bypassed, then we send the message of
* VFRAME_EVENT_PROVIDER_RESET to video and notify
* it to keep the last canvas buffer which was
* alloced by codec not by di.
*/
vf_notify_receiver(VFM_NAME,
VFRAME_EVENT_PROVIDER_RESET,
NULL);
di_blocking = 1;
spin_lock_irqsave(&plist_lock, flags);
post_display_buf_clear();
spin_unlock_irqrestore(&plist_lock, flags);
}
goto light_unreg;
} else if (type == VFRAME_EVENT_PROVIDER_LIGHT_UNREG) {
di_blocking = 1;
pr_info("%s: vf_notify_receiver ligth unreg\n", __func__);
light_unreg:
/*-----------------------------------*/
spin_lock_irqsave(&plist_lock, flags);
for (i = 0; i < MAX_IN_BUF_NUM; i++) {
if (vframe_in[i])
pr_dbg("DI:clear vframe_in[%d]\n", i);
pr_info("DI:clear vframe_in[%d]\n", i);
vframe_in[i] = NULL;
}
spin_unlock_irqrestore(&plist_lock, flags);
di_blocking = 0;
mutex_unlock(&di_event_mutex);
pr_info("\treset:end\n");
/*goto light_unreg;*/
} else if (type == VFRAME_EVENT_PROVIDER_LIGHT_UNREG) {
mutex_lock(&di_event_mutex);
di_blocking = 1;
pr_info("%s: LIGHT_UNREG\n", __func__);
/*light_unreg:*/
#if 1
spin_lock_irqsave(&plist_lock, flags);
for (i = 0; i < MAX_IN_BUF_NUM; i++) {
if (vframe_in[i])
pr_info("DI:clear vframe_in[%d]\n", i);
vframe_in[i] = NULL;
}
spin_unlock_irqrestore(&plist_lock, flags);
#endif
di_blocking = 0;
mutex_unlock(&di_event_mutex);
pr_info("\tlight unreg:end\n");
} else if (type == VFRAME_EVENT_PROVIDER_LIGHT_UNREG_RETURN_VFRAME) {
unsigned char vf_put_flag = 0;
pr_dbg(
"%s:VFRAME_EVENT_PROVIDER_LIGHT_UNREG_RETURN_VFRAME\n",
__func__);
pr_info("%s:LIGHT_UNREG_RETURN_VFRAME\n", __func__);
/*
* do not display garbage when 2d->3d or 3d->2d
*/
@@ -7500,6 +7821,7 @@ light_unreg:
if (reg_flag) {
pr_err("[DI] no muti instance.\n");
mutex_unlock(&di_event_mutex);
dbg_check_list();
return -1;
}
pr_info("%s: vframe provider reg %s\n", __func__,
@@ -7785,9 +8107,11 @@ get_vframe:
log_buffer_state("get");
}
if (vframe_ret) {
di_print("%s: %s[%d]:%x %u ms\n", __func__,
vframe_type_name[di_buf->type], di_buf->index, vframe_ret,
jiffies_to_msecs(jiffies_64 - vframe_ret->ready_jiffies64));
di_print("%s: %s[%d]:0x%p %u ms\n", __func__,
vframe_type_name[di_buf->type],
di_buf->index, vframe_ret,
jiffies_to_msecs
(jiffies_64 - vframe_ret->ready_jiffies64));
}
if (!post_wr_en && di_post_stru.run_early_proc_fun_flag && vframe_ret) {
@@ -7821,8 +8145,10 @@ static void di_vf_put(vframe_t *vf, void *arg)
di_print("%s: 0x%p\n", __func__, vf);
return;
}
#ifdef DI_KEEP_HIS
if (di_blocking)
return;
#endif
log_buffer_state("pu_");
di_buf = (struct di_buf_s *)vf->private_data;
if (IS_ERR_OR_NULL(di_buf)) {
@@ -8496,7 +8822,7 @@ static int di_probe(struct platform_device *pdev)
vf_receiver_init(&di_vf_recv, VFM_NAME, &di_vf_receiver, NULL);
vf_reg_receiver(&di_vf_recv);
vf_provider_init(&di_vf_prov, VFM_NAME, &deinterlace_vf_provider, NULL);
active_flag = 1;
/*active_flag = 1;*/
sema_init(&di_sema, 1);
ret = request_irq(di_devp->pre_irq, &de_irq, IRQF_SHARED,
"pre_di", (void *)"pre_di");
@@ -8523,10 +8849,12 @@ static int di_probe(struct platform_device *pdev)
di_devp->task = kthread_run(di_task_handle, di_devp, "kthread_di");
if (IS_ERR(di_devp->task))
pr_err("%s create kthread error.\n", __func__);
active_flag = 1;
di_debugfs_init(); /*2018-07-18 add debugfs*/
di_patch_post_update_mc_sw(DI_MC_SW_IC, true);
dil_attach_ext_api(&di_ext);
di_patch_mov_ini();
di_pr_info("%s:ok\n", __func__);
return ret;
@@ -8619,6 +8947,8 @@ static void di_shutdown(struct platform_device *pdev)
struct di_dev_s *di_devp = NULL;
int ret = 0;
active_flag = 0;
di_devp = platform_get_drvdata(pdev);
ret = hrtimer_cancel(&di_pre_hrtimer);
pr_info("di pre hrtimer canel %d.\n", ret);
@@ -8635,6 +8965,7 @@ static void di_shutdown(struct platform_device *pdev)
switch_vpu_clk_gate_vmod(VPU_VPU_CLKB,
VPU_CLK_GATE_OFF);
kfree(di_devp);
di_devp = NULL;
pr_info("[DI] shutdown done.\n");
}
@@ -8658,9 +8989,11 @@ static void di_clear_for_suspend(struct di_dev_s *di_devp)
di_pre_stru.cma_alloc_done = 0;
}
#endif
#ifdef DI_KEEP_HIS
hrtimer_cancel(&di_pre_hrtimer);
tasklet_kill(&di_pre_tasklet); //ary.sui
tasklet_disable(&di_pre_tasklet);
#endif
pr_info("%s end\n", __func__);
}
static int save_init_flag;
@@ -8674,10 +9007,16 @@ static int di_suspend(struct device *dev)
di_devp->flags |= DI_SUSPEND_FLAG;
di_clear_for_suspend(di_devp);//add
active_flag = 0;
/* fix suspend/resume crash problem */
save_init_flag = init_flag;
init_flag = 0;
hrtimer_cancel(&di_pre_hrtimer);
tasklet_kill(&di_pre_tasklet);
tasklet_disable(&di_pre_tasklet);
#if 0 /*2019-01-18*/
if (di_pre_stru.di_inp_buf) {
if (vframe_in[di_pre_stru.di_inp_buf->index]) {
@@ -8718,6 +9057,7 @@ static int di_resume(struct device *dev)
di_pre_hrtimer.function = di_pre_hrtimer_func;
hrtimer_start(&di_pre_hrtimer, ms_to_ktime(10), HRTIMER_MODE_REL);
tasklet_enable(&di_pre_tasklet);
active_flag = 1;
/************/
pr_info("di: resume module\n");
return 0;

View File

@@ -220,6 +220,29 @@ extern bool is_vsync_rdma_enable(void);
#define TABLE_LEN_MAX 10000
#define TABLE_FLG_END (0xfffffffe)
/******************************************
* patch for TV-10258 multiwave group issue
*****************************************/
#define DI_PATCH_MOV_MAX_NUB 5
struct di_patch_mov_d_s {
unsigned int val;
unsigned int mask;
bool en;
};
struct di_patch_mov_s {
unsigned int reg_addr[DI_PATCH_MOV_MAX_NUB];
struct di_patch_mov_d_s val_db[DI_PATCH_MOV_MAX_NUB];
struct di_patch_mov_d_s val_pq[DI_PATCH_MOV_MAX_NUB];
int mode;/*-1 : not set; 0: set from db, 1: set from pq*/
bool en_support;
bool update;
unsigned int nub;
};
bool di_patch_mov_db(unsigned int addr, unsigned int val);
struct di_dev_s {
dev_t devt;
struct cdev cdev; /* The cdev structure */
@@ -254,6 +277,7 @@ struct di_dev_s {
struct page *total_pages;
atomic_t mem_flag;
struct dentry *dbg_root; /*dbg_fs*/
struct di_patch_mov_s mov;
};
struct di_pre_stru_s {
@@ -299,7 +323,7 @@ struct di_pre_stru_s {
int unreg_req_flag_irq;
int unreg_req_flag_cnt;
int reg_req_flag;
int reg_req_flag_irq;
/*int reg_req_flag_irq;*/
int reg_req_flag_cnt;
int reg_irq_busy;
int force_unreg_req_flag;
@@ -376,6 +400,10 @@ struct di_pre_stru_s {
bool retry_en;
unsigned int retry_index;
unsigned int retry_cnt;
/*****************/
bool combing_fix_en;
unsigned int comb_mode;
/*struct di_patch_mov_s mov;*/
};
struct di_post_stru_s {
@@ -473,4 +501,6 @@ struct di_buf_s *get_di_buf(int queue_idx, int *start_pos);
#define pr_error(fmt, args ...) pr_err("DI: " fmt, ## args)
/******************************************/
/*#define DI_KEEP_HIS 0*/
#endif

View File

@@ -475,8 +475,10 @@ void dump_di_pre_stru(struct di_pre_stru_s *di_pre_stru_p)
di_pre_stru_p->unreg_req_flag_irq);
pr_info("reg_req_flag = %d\n",
di_pre_stru_p->reg_req_flag);
#ifdef DI_KEEP_HIS
pr_info("reg_req_flag_irq = %d\n",
di_pre_stru_p->reg_req_flag_irq);
#endif
pr_info("cur_width = %d\n",
di_pre_stru_p->cur_width);
pr_info("cur_height = %d\n",
@@ -547,8 +549,10 @@ static int dump_di_pre_stru_seq(struct seq_file *seq, void *v)
di_pre_stru_p->unreg_req_flag_irq);
seq_printf(seq, "%-25s = %d\n", "reg_req_flag",
di_pre_stru_p->reg_req_flag);
#ifdef DI_KEEP_HIS
seq_printf(seq, "%-25s = %d\n", "reg_req_flag_irq",
di_pre_stru_p->reg_req_flag_irq);
#endif
seq_printf(seq, "%-25s = %d\n", "cur_width",
di_pre_stru_p->cur_width);
seq_printf(seq, "%-25s = %d\n", "cur_height",
@@ -583,6 +587,10 @@ static int dump_di_pre_stru_seq(struct seq_file *seq, void *v)
di_pre_stru_p->bypass_pre ? "true" : "false");
seq_printf(seq, "%-25s = %s\n", "invert_flag",
di_pre_stru_p->invert_flag ? "true" : "false");
seq_printf(seq, "%-25s = %s\n", "combing_fix_en",
di_pre_stru_p->combing_fix_en ? "true" : "false");
seq_printf(seq, "%-25s = %d\n", "comb_mode",
di_pre_stru_p->comb_mode);
return 0;
}
@@ -875,6 +883,7 @@ void dump_vframe(struct vframe_s *vf)
pr_info("pixel_ratio %d list %p\n",
vf->pixel_ratio, &vf->list);
pr_info("di_pulldown 0x%x\n", vf->di_pulldown);
pr_info("di_gmv 0x%x\n", vf->di_gmv);
}
void print_di_buf(struct di_buf_s *di_buf, int format)
@@ -1071,6 +1080,30 @@ void dump_afbcd_reg(void)
VD2_AFBCD1_MISC_CTRL, RDMA_RD(VD2_AFBCD1_MISC_CTRL));
}
static int dbg_patch_mov_data_show(struct seq_file *seq, void *v)
{
struct di_dev_s *de_devp = get_di_de_devp();
struct di_patch_mov_s *pmov = &de_devp->mov;
int i;
seq_printf(seq, "mode:%d\n", pmov->mode);
seq_printf(seq, "en_support:%d\n", pmov->en_support);
seq_printf(seq, "number:%d\n", pmov->nub);
seq_printf(seq, "update:%d\n", pmov->update);
for (i = 0; i < DI_PATCH_MOV_MAX_NUB; i++) {
seq_printf(seq, "index:[%d]\n", i);
seq_printf(seq, "\treg:0x%x\n", pmov->reg_addr[i]);
if (i < pmov->nub)
seq_printf(seq, "\t\t= 0x%x\n",
RDMA_RD(pmov->reg_addr[i]));
seq_printf(seq, "\tdb_val:0x%x\n", pmov->val_db[i].val);
seq_printf(seq, "\tdb_en :0x%x\n", pmov->val_db[i].en);
seq_printf(seq, "\tpq_val:0x%x\n", pmov->val_pq[i].val);
seq_printf(seq, "\tpq_val:0x%x\n", pmov->val_pq[i].en);
}
return 0;
}
/*2018-08-17 add debugfs*/
/*same as dump_state*/
static int seq_file_di_state_show(struct seq_file *seq, void *v)
@@ -1250,6 +1283,7 @@ DEFINE_SHOW_DI(seq_file_dump_di_reg);
DEFINE_SHOW_DI(seq_file_dump_mif_size_state);
DEFINE_SHOW_DI(seq_file_afbc);
DEFINE_SHOW_DI(reg_cue_int);
DEFINE_SHOW_DI(dbg_patch_mov_data);
struct di_debugfs_files_t {
const char *name;
@@ -1263,6 +1297,7 @@ static struct di_debugfs_files_t di_debugfs_files[] = {
{"dumpmif", S_IFREG | 0644, &seq_file_dump_mif_size_state_fops},
{"dumpafbc", S_IFREG | 0644, &seq_file_afbc_fops},
{"reg_cue", S_IFREG | 0644, &reg_cue_int_fops},
{"dumpmov", S_IFREG | 0644, &dbg_patch_mov_data_fops},
};
void di_debugfs_init(void)

View File

@@ -33,6 +33,8 @@
#include "deinterlace.h"
#include "register.h"
#include "register_nr4.h"
#include "nr_drv.h"
#ifdef DET3D
#include "detect3d.h"
#endif
@@ -139,6 +141,8 @@ static void ma_di_init(void)
/* mtn setting */
if (cpu_after_eq(MESON_CPU_MAJOR_ID_G12B)) {
DI_Wr_reg_bits(DI_MTN_CTRL, 1, 0, 1);
DI_Wr_reg_bits(DI_MTN_CTRL, 1, 30, 1);
DI_Wr_reg_bits(DI_MTN_CTRL, 0xf, 24, 4);
DI_Wr(DI_MTN_1_CTRL1, 0x202015);
} else
DI_Wr(DI_MTN_1_CTRL1, 0xa0202015);
@@ -331,7 +335,7 @@ void calc_lmv_base_mcinfo(unsigned int vf_height, unsigned short *mcinfo_vadr)
if (!lmv_lock_win_en)
return;
if (!cpu_after_eq(MESON_CPU_MAJOR_ID_G12A)) {
if (!cpu_after_eq(MESON_CPU_MAJOR_ID_G12A)) {
pr_debug("%s: only support G12A and after chips.\n", __func__);
return;
}
@@ -431,7 +435,11 @@ static void pre_hold_block_mode_config(void)
if (cpu_after_eq(MESON_CPU_MAJOR_ID_G12A)) {
DI_Wr(DI_PRE_HOLD, 0);
/* go field after 2 lines */
#ifdef OLD_PRE_GL
DI_Wr(DI_PRE_GL_CTRL, (0x80000000|line_num_pre_frst));
#else
di_hpre_gl_sw(false);
#endif
} else if (is_meson_txlx_cpu()) {
/* setup pre process ratio to 66.6%*/
DI_Wr(DI_PRE_HOLD, (1 << 31) | (1 << 16) | 3);
@@ -754,9 +762,10 @@ void enable_di_pre_aml(
/*
* enable&disable contwr txt
*/
if (cpu_after_eq(MESON_CPU_MAJOR_ID_G12B))
RDMA_WR_BITS(DI_MTN_CTRL, madi_en?5:0, 29, 3);
else
if (cpu_after_eq(MESON_CPU_MAJOR_ID_G12B)) {
RDMA_WR_BITS(DI_MTN_CTRL, madi_en, 29, 1);
RDMA_WR_BITS(DI_MTN_CTRL, madi_en, 31, 1);
} else
RDMA_WR_BITS(DI_MTN_1_CTRL1, madi_en?5:0, 29, 3);
if (cpu_after_eq(MESON_CPU_MAJOR_ID_G12A)) {
@@ -3227,11 +3236,28 @@ void pre_frame_reset_g12(unsigned char madi_en,
RDMA_WR_BITS(MCVECWR_CAN_SIZE, 0, 14, 1);
RDMA_WR_BITS(MCINFWR_CAN_SIZE, 0, 14, 1);
#ifdef OLD_PRE_GL
reg_val = 0xc3200000 | line_num_pre_frst;
RDMA_WR(DI_PRE_GL_CTRL, reg_val);
reg_val = 0x83200000 | line_num_pre_frst;
RDMA_WR(DI_PRE_GL_CTRL, reg_val);
#else
di_hpre_gl_sw(true);
#endif
}
/*2019-12-25 by feijun*/
void di_hpre_gl_sw(bool on)
{
if (!cpu_after_eq(MESON_CPU_MAJOR_ID_G12A))
return;
if (on)
RDMA_WR(DI_PRE_GL_CTRL,
0x80200000 | line_num_pre_frst);
else
RDMA_WR(DI_PRE_GL_CTRL, 0xc0000000);
}
/*
* frame + soft reset for the pre modules
*/
@@ -3362,6 +3388,15 @@ void diwr_set_power_control(unsigned char enable)
enable?VPU_MEM_POWER_ON:VPU_MEM_POWER_DOWN);
}
void di_hdr2_hist_init(void)
{
if (cpu_after_eq(MESON_CPU_MAJOR_ID_TM2)) {
RDMA_WR(DI_HDR2_HIST_CTRL, 0x5510);
RDMA_WR(DI_HDR2_HIST_H_START_END, 0x10000);
RDMA_WR(DI_HDR2_HIST_V_START_END, 0x0);
}
}
void di_top_gate_control(bool top_en, bool mc_en)
{
if (top_en) {
@@ -3835,30 +3870,35 @@ void pulldown_vof_win_config(struct pulldown_detected_s *wins)
wins->regs[3].win_vs, 17, 12);
DI_VSYNC_WR_MPEG_REG_BITS(DI_BLEND_REG3_Y,
wins->regs[3].win_ve, 1, 12);
/* revert the setting of top two lines do weave for */
/* interlace video, suggest by vlsi-feijun */
DI_VSYNC_WR_MPEG_REG_BITS(DI_BLEND_CTRL,
(wins->regs[0].win_ve > wins->regs[0].win_vs)
? 1 : 0, 16, 1);
DI_VSYNC_WR_MPEG_REG_BITS(DI_BLEND_CTRL,
wins->regs[0].blend_mode, 8, 2);
/*wins->regs[0].blend_mode*/
0x03, 8, 2);
DI_VSYNC_WR_MPEG_REG_BITS(DI_BLEND_CTRL,
(wins->regs[1].win_ve > wins->regs[1].win_vs)
? 1 : 0, 17, 1);
DI_VSYNC_WR_MPEG_REG_BITS(DI_BLEND_CTRL,
wins->regs[1].blend_mode, 10, 2);
/*wins->regs[1].blend_mode*/
0x03, 10, 2);
DI_VSYNC_WR_MPEG_REG_BITS(DI_BLEND_CTRL,
(wins->regs[2].win_ve > wins->regs[2].win_vs)
? 1 : 0, 18, 1);
DI_VSYNC_WR_MPEG_REG_BITS(DI_BLEND_CTRL,
wins->regs[2].blend_mode, 12, 2);
/*wins->regs[2].blend_mode*/
0x03, 12, 2);
DI_VSYNC_WR_MPEG_REG_BITS(DI_BLEND_CTRL,
(wins->regs[3].win_ve > wins->regs[3].win_vs)
? 1 : 0, 19, 1);
DI_VSYNC_WR_MPEG_REG_BITS(DI_BLEND_CTRL,
wins->regs[3].blend_mode, 14, 2);
/*wins->regs[3].blend_mode*/
0x03, 14, 2);
}
@@ -3868,6 +3908,7 @@ void di_load_regs(struct di_pq_parm_s *di_pq_ptr)
unsigned int table_name = 0, nr_table = 0;
bool ctrl_reg_flag = false;
struct am_reg_s *regs_p = NULL;
bool mov_flg = false;
if (pq_load_dbg == 1)
return;
@@ -3889,6 +3930,11 @@ void di_load_regs(struct di_pq_parm_s *di_pq_ptr)
addr = regs_p->addr;
value = regs_p->val;
mask = regs_p->mask;
if (nr_demo_flag) {
if (addr == NR4_TOP_CTRL)
mask &= ~(0x7 << 6);
}
if (pq_load_dbg == 2)
pr_info("[%u][0x%x] = [0x%x]&[0x%x]\n",
i, addr, value, mask);
@@ -3911,7 +3957,9 @@ void di_load_regs(struct di_pq_parm_s *di_pq_ptr)
}
if (table_name & nr_table)
ctrl_reg_flag = set_nr_ctrl_reg_table(addr, value);
if (!ctrl_reg_flag)
if (table_name & TABLE_NAME_DI)
mov_flg = di_patch_mov_db(addr, value);
if (!ctrl_reg_flag && !mov_flg)
DI_Wr(addr, value);
if (pq_load_dbg == 2)
pr_info("[%u][0x%x] = [0x%x] %s\n", i, addr,

View File

@@ -184,6 +184,7 @@ void di_post_switch_buffer(
);
void di_post_read_reverse_irq(bool reverse,
unsigned char mc_pre_flag, bool mc_enable);
void di_hdr2_hist_init(void);
void di_top_gate_control(bool top_en, bool mc_en);
void di_pre_gate_control(bool enable, bool mc_enable);
void di_post_gate_control(bool gate);
@@ -201,6 +202,7 @@ void pulldown_vof_win_config(struct pulldown_detected_s *wins);
void di_load_regs(struct di_pq_parm_s *di_pq_ptr);
void pre_frame_reset_g12(unsigned char madi_en, unsigned char mcdi_en);
void pre_frame_reset(void);
void di_hpre_gl_sw(bool on);
void di_interrupt_ctrl(unsigned char ma_en,
unsigned char det3d_en, unsigned char nrds_en,
unsigned char post_wr, unsigned char mc_en);

View File

@@ -161,7 +161,6 @@ static unsigned int combing_bias_static_setting[MAX_NUM_DI_REG] = {
0x00000166
};
static unsigned int combing_normal_setting[MAX_NUM_DI_REG] = {
0x00202015,
0x1A1A3A62,
@@ -182,18 +181,18 @@ static unsigned int combing_normal_setting[MAX_NUM_DI_REG] = {
};
static unsigned int combing_bias_motion_setting[MAX_NUM_DI_REG] = {
0x00202015,
0x1A1A3A62,
0x15200101,
0x01200440,
0x74200D0D,
0x0D5A1520,
0x0A0A0201,
0x1A1A2662,
0x0D200302,
0x02020606,
0x05080344,
0x40020a04,
0x00202015, /* 0 */
0x1A1A3A62, /* 1 */
0x15200101, /* 2 */
0x01200440, /* 3 */
0x74200D0D, /* 4 */
0x0D5A1520, /* 5 */
0x0A0A0201, /* 6 */
0x1A1A2662, /* 7 */
0x0D200302, /* 8 */
0x02020606, /* 9 */
0x05080344, /* 10 */
0x40020a04, /* 11 */
/*idea from mingliang.dong & vlsi zheng.bao begin*/
0x0001FF12, /* 0x0001ff0c */
0x00200204, /* 0x00400204 */
@@ -203,17 +202,17 @@ static unsigned int combing_bias_motion_setting[MAX_NUM_DI_REG] = {
};
static unsigned int combing_very_motion_setting[MAX_NUM_DI_REG] = {
0x00202015,
0x1A1A3A62,
0x15200101,
0x01200440,
0x74200D0D,
0x0D5A1520,
0x0A0A0201,
0x1A1A2662,
0x0D200302,
0x02020606,
0x05080344,
0x00202015, /* 0 */
0x1A1A3A62, /* 1 */
0x15200101, /* 2 */
0x01200440, /* 3 */
0x74200D0D, /* 4 */
0x0D5A1520, /* 5 */
0x0A0A0201, /* 6 */
0x1A1A2662, /* 7 */
0x0D200302, /* 8 */
0x02020606, /* 9 */
0x05080344, /* 10 */
/*idea from mingliang.dong & vlsi zheng.bao begin*/
0x60000404, /* 0x40020a04*/
0x0001FF12, /* 0x0001ff0c */
@@ -222,6 +221,177 @@ static unsigned int combing_very_motion_setting[MAX_NUM_DI_REG] = {
/*idea from mingliang.dong & vlsi zheng.bao end*/
0x00000131
};
/**************************************************
*
**************************************************/
/*same as: combing_bias_motion_setting*/
static const unsigned int combing_bias_p_ori[] = {
/**/
0x00202015, /* 0 */
0x1A1A3A62, /* 1 */
0x15200101, /* 2 */
0x01200440, /* 3 */
0x74200D0D, /* 4 */
0x0D5A1520, /* 5 */
0x0A0A0201, /* 6 */
0x1A1A2662, /* 7 */
0x0D200302, /* 8 */
0x02020606, /* 9 */
0x05080344, /* 10 */
0x40020a04, /* 11 */
/*idea from mingliang.dong & vlsi zheng.bao begin*/
0x0001FF12, /* 0x0001ff0c */
0x00200204, /* 0x00400204 */
0x00012002, /* 0x00016404 */
/*idea from mingliang.dong & vlsi zheng.bao end*/
0x00000142
};
static const unsigned int combing_very_p_ori[] = {
0x00202015, /* 0 */
0x1A1A3A62, /* 1 */
0x15200101, /* 2 */
0x01200440, /* 3 */
0x74200D0D, /* 4 */
0x0D5A1520, /* 5 */
0x0A0A0201, /* 6 */
0x1A1A2662, /* 7 */
0x0D200302, /* 8 */
0x02020606, /* 9 */
0x05080344, /* 10 */
/*idea from mingliang.dong & vlsi zheng.bao begin*/
0x60000404, /* 0x40020a04*/
0x0001FF12, /* 0x0001ff0c */
0x00200204, /* 0x00400204 */
0x00012002, /* 0x00016404 */
/*idea from mingliang.dong & vlsi zheng.bao end*/
0x00000131
};
static const unsigned int combing_bias_p_1080i[] = {
/**/
0x00202015, /* 0 */
0x1A1A3A62, /* 1 */
0x15200101, /* 2 */
0x01200440, /* 3 */
0x74200D0D, /* 4 */
0x0D5A1520, /* 5 */
0x0A0A0201, /* 6 */
0x1A1A2662, /* 7 */
0x0D200302, /* 8 */
0x02020606, /* 9 */
0x05080344, /* 10 */
0x40020a04, /* 11 */
/*idea from mingliang.dong & vlsi zheng.bao begin*/
0x0001ff0c,
0x00400204,
0x00016404,
/*idea from mingliang.dong & vlsi zheng.bao end*/
0x00000142
};
static const unsigned int combing_very_p_1080i[] = {
0x00202015, /* 0 */
0x1A1A3A62, /* 1 */
0x15200101, /* 2 */
0x01200440, /* 3 */
0x74200D0D, /* 4 */
0x0D5A1520, /* 5 */
0x0A0A0201, /* 6 */
0x1A1A2662, /* 7 */
0x0D200302, /* 8 */
0x02020606, /* 9 */
0x05080344, /* 10 */
/*idea from mingliang.dong & vlsi zheng.bao begin*/
0x40020a04,
0x0001ff0c,
0x00400204,
0x00016404,
/*idea from mingliang.dong & vlsi zheng.bao end*/
0x00000131
};
/*same as combing_bias_motion_setting ex:*/
/* 3nd : from 0x15200101 to 0x15200301*/
static unsigned int combing_bias_p_480i[] = {
0x00202015, /* 0 */
0x1A1A3A62, /* 1 */
0x15200301, /* 2 */
0x01200440, /* 3 */
0x74200D0D, /* 4 */
0x0D5A1520, /* 5 */
0x0A0A0201, /* 6 */
0x1A1A2662, /* 7 */
0x0D200302, /* 8 */
0x02020606, /* 9 */
0x05080344, /* 10 */
0x40020a04, /* 11 */
/*idea from mingliang.dong & vlsi zheng.bao begin*/
0x0001FF12, /* 0x0001ff0c */
0x00200204, /* 0x00400204 */
0x00012002, /* 0x00016404 */
/*idea from mingliang.dong & vlsi zheng.bao end*/
0x00000142
};
/*same as combing_very_motion_setting ex:*/
/* 3nd : from 0x15200101 to 0x15200301*/
static unsigned int combing_very_p_480i[] = {
0x00202015, /* 0 */
0x1A1A3A62, /* 1 */
0x15200301, /* 2 */
0x01200440, /* 3 */
0x74200D0D, /* 4 */
0x0D5A1520, /* 5 */
0x0A0A0201, /* 6 */
0x1A1A2662, /* 7 */
0x0D200302, /* 8 */
0x02020606, /* 9 */
0x05080344, /* 10 */
/*idea from mingliang.dong & vlsi zheng.bao begin*/
0x60000404, /* 0x40020a04*/
0x0001FF12, /* 0x0001ff0c */
0x00200204, /* 0x00400204 */
0x00012002, /* 0x00016404 */
/*idea from mingliang.dong & vlsi zheng.bao end*/
0x00000131
};
static unsigned int di_mtn_p_mode;
void com_patch_pre_sw_set(unsigned int mode)
{
unsigned int *p1, *p2;
/* mode is 0: ori */
/* mode is 1: 1080i */
/* mode is 2: 480i */
if (mode == di_mtn_p_mode)
return;
p1 = &combing_bias_motion_setting[0];
p2 = &combing_very_motion_setting[0];
if (mode == 0) {
memcpy(p1, &combing_bias_p_ori[0],
sizeof(combing_bias_p_ori));
memcpy(p2, &combing_very_p_ori[0],
sizeof(combing_very_p_ori));
di_mtn_p_mode = 0;
} else if (mode == 1) {
memcpy(p1, &combing_bias_p_1080i[0],
sizeof(combing_bias_p_1080i));
memcpy(p2, &combing_very_p_1080i[0],
sizeof(combing_very_p_1080i));
di_mtn_p_mode = 1;
} else if (mode == 2) {
memcpy(p1, &combing_bias_p_480i[0],
sizeof(combing_bias_p_480i));
memcpy(p2, &combing_very_p_480i[0],
sizeof(combing_very_p_480i));
di_mtn_p_mode = 2;
}
}
/*special for resolution test file*/
static unsigned int combing_resolution_setting[MAX_NUM_DI_REG] = {
0x00202015,
@@ -301,6 +471,7 @@ void mtn_int_combing_glbmot(void)
if (is_meson_tl1_cpu() || is_meson_tm2_cpu()) {/*from VLSI yanling.liu*/
combing_glbmot_radprat[0] = 30;
}
di_mtn_p_mode = 0;
}
void adpative_combing_exit(void)
{
@@ -495,13 +666,19 @@ static unsigned int small_local_mtn = 70;
module_param(small_local_mtn, uint, 0644);
MODULE_PARM_DESC(small_local_mtn, "small_local_mtn");
static unsigned int small_local_mtn1 = 30;
module_param(small_local_mtn1, uint, 0644);
MODULE_PARM_DESC(small_local_mtn1, "small_local_mtn1");
unsigned int adp_set_mtn_ctrl10(unsigned int diff, unsigned int dlvel,
unsigned int frame_diff_avg)
{
int istp = 0, idats = 0, idatm = 0, idatr = 0;
unsigned int rst = 0;
if (frame_diff_avg < small_local_mtn)
if (
(frame_diff_avg < small_local_mtn) &&
(frame_diff_avg > small_local_mtn1))
rst = combing_very_motion_setting[9];
else if (dlvel == 0) {
if (cpu_after_eq(MESON_CPU_MAJOR_ID_TXLX))
@@ -636,7 +813,7 @@ MODULE_PARM_DESC(di_debug_readreg, "di_debug_readreg");
/*from VLSI yanling.liu, the patch fix TL1 1080I in some dark */
/*scenes and roller coasters have small sawtooth, when turn off*/
/*combing_fix_en, set the registers*/
void fix_tl1_1080i_sawtooth_patch(void)
static void fix_tl1_1080i_sawtooth_patch(void)
{
DI_Wr(0x1741, 0x0A0A1A22);
DI_Wr(0x1742, 0x0a100101);
@@ -651,6 +828,35 @@ void fix_tl1_1080i_sawtooth_patch(void)
DI_Wr(0x17af, 0x60020a60);
}
static void fix_tl1_1080i_patch2(void)
{
DI_Wr(0x1741, 0x010a010a);
DI_Wr(0x1742, 0x01010101);
DI_Wr(0x1743, 0x00000101);
DI_Wr(0x1744, 0x00000101);
DI_Wr(0x17a9, 0x01010102);
DI_Wr(0x17aa, 0x02020101);
DI_Wr(0x17ab, 0x010a010a);
DI_Wr(0x17ac, 0x010a0102);
DI_Wr(0x17ad, 0x08080808);
DI_Wr(0x17ae, 0x01010101);
DI_Wr(0x17af, 0xff00031f);
}
void fix_tl1_1080i_patch_sel(unsigned int mode)
{
switch (mode) {
case 0:/*not set*/
break;
case 1:
fix_tl1_1080i_sawtooth_patch();
break;
case 2:
fix_tl1_1080i_patch2();
break;
}
}
static int combing_cnt;
int combing_diff_min = 2000;
int combing_diff_max = 2000;
@@ -714,9 +920,16 @@ int adaptive_combing_fixing(
combing_cnt = combing_cnt + 1;
else
combing_cnt = 0;
if (glb_mot[0] < combing_diff_min && glb_mot[1] > combing_diff_max &&
combing_cnt <= combing_cnt_thd)
glb_mot[0] = glb_mot[1];
if (
is_meson_txhd_cpu() ||
is_meson_tl1_cpu() ||
is_meson_tm2_cpu()) {
if (
glb_mot[0] < combing_diff_min &&
glb_mot[1] > combing_diff_max &&
combing_cnt <= combing_cnt_thd)
glb_mot[0] = glb_mot[1];
}
glb_mot_avg5 =
(glb_mot[0] + glb_mot[1] + glb_mot[2] + glb_mot[3] +
glb_mot[4]) / 5;
@@ -816,9 +1029,10 @@ module_param_named(cmb_adpset_cnt, cmb_adpset_cnt, int, 0644);
static const struct mtn_op_s di_ops_mtn = {
.mtn_int_combing_glbmot = mtn_int_combing_glbmot,
.adpative_combing_exit = adpative_combing_exit,
.fix_tl1_1080i_sawtooth_patch = fix_tl1_1080i_sawtooth_patch,
.fix_tl1_1080i_patch_sel = fix_tl1_1080i_patch_sel,
.adaptive_combing_fixing = adaptive_combing_fixing,
.adpative_combing_config = adpative_combing_config,
.com_patch_pre_sw_set = com_patch_pre_sw_set,
/*.module_para = dim_seq_file_module_para_mtn,*/
};

View File

@@ -39,12 +39,13 @@ struct combing_status_s *adpative_combing_config(unsigned int width,
unsigned int height,
enum vframe_source_type_e src_type, bool prog,
enum tvin_sig_fmt_e fmt);
extern void fix_tl1_1080i_sawtooth_patch(void);
void fix_tl1_1080i_patch_sel(unsigned int mode);
int adaptive_combing_fixing(
struct combing_status_s *cmb_status,
unsigned int field_diff, unsigned int frame_diff,
int bit_mode);
void adpative_combing_exit(void);
extern void mtn_int_combing_glbmot(void);
void com_patch_pre_sw_set(unsigned int mode);
#endif

View File

@@ -111,7 +111,7 @@ bool di_attach_ops_nr(const struct nr_op_s **ops);
struct mtn_op_s {
void (*mtn_int_combing_glbmot)(void);
void (*adpative_combing_exit)(void);
void (*fix_tl1_1080i_sawtooth_patch)(void);
void (*fix_tl1_1080i_patch_sel)(unsigned int mode);
int (*adaptive_combing_fixing)(
struct combing_status_s *cmb_status,
unsigned int field_diff, unsigned int frame_diff,
@@ -123,6 +123,7 @@ struct mtn_op_s {
enum vframe_source_type_e src_type,
bool prog,
enum tvin_sig_fmt_e fmt);
void (*com_patch_pre_sw_set)(unsigned int mode);
int (*module_para)(struct seq_file *seq);
};

View File

@@ -235,6 +235,29 @@ static int dif01_ratio = 10;
module_param(dif01_ratio, int, 0644);
MODULE_PARM_DESC(dif01_ratio, "dif01_ratio");
static int nflagch4_ratio = 1;
module_param(nflagch4_ratio, int, 0644);
MODULE_PARM_DESC(nflagch4_ratio, "nflagch4_ratio");
static int nflagch5_ratio = 2;
module_param(nflagch5_ratio, int, 0644);
MODULE_PARM_DESC(nflagch5_ratio, "nflagch5_ratio");
static int nflagch4_th = 0;
module_param(nflagch4_th, int, 0644);
MODULE_PARM_DESC(nflagch4_th, "nflagch4_th");
static int nflagch5_th = 0;
module_param(nflagch5_th, int, 0644);
MODULE_PARM_DESC(nflagch5_th, "nflagch5_th");
static int dif02_flag = 1;
module_param(dif02_flag, int, 0644);
MODULE_PARM_DESC(dif02_flag, "dif02_flag");
static int dif02_ratio = 20;
module_param(dif02_ratio, int, 0644);
MODULE_PARM_DESC(dif02_ratio, "dif02_ratio");
static int flm22_force;
@@ -697,6 +720,9 @@ int Flm32DetSft(struct sFlmDatSt *pRDat, int *nDif02,
int nFlgChk1 = 0;
int nFlgChk2 = 0;
int nFlgChk3 = 0; /* for Mit32VHLine */
int nFlgChk4 = 0;
int nFlgChk5 = 0;
int nMean = 0;
int luma_avg = 0;
int flm32_dif02_gap = 0;
@@ -749,7 +775,11 @@ int Flm32DetSft(struct sFlmDatSt *pRDat, int *nDif02,
nSM += nT1;
}
}
nAV11 = (nSM - nMx + nT2 / 2) / (nT2 - 1);
/* for coverity error,"nT2 - 1" which may be zero */
if (nT2 != 1)
nAV11 = (nSM - nMx + nT2 / 2) / (nT2 - 1);
else
pr_info("%s: Error nT2 is one\n", __func__);
nAV1 = (sFrmDifAvgRat * nAV11 + (32 - sFrmDifAvgRat) * nAV12);
nAV1 = ((nAV1 + 16) >> 5);
@@ -819,6 +849,35 @@ int Flm32DetSft(struct sFlmDatSt *pRDat, int *nDif02,
nFlgChk1 = 0;
nFlgChk2 = 0;
}
//nFlgChk4/5 large dif change quit mode
if (
pFlg32[HISDETNUM - 1] > 1 && (dif02_flag ||
nDif02[HISDIFNUM - 1] > (1 << dif02_ratio))) {
nFlgChk4 = nDif02[HISDIFNUM - 1] - nDif02[HISDIFNUM - 6];
if (nFlgChk4 < 0)
nFlgChk4 = -nFlgChk4;
nFlgChk4 = nFlgChk4;
nMean = (nDif02[HISDIFNUM - 1] + nDif01[HISDIFNUM - 6]) / 2;
nFlgChk4 = nflagch4_ratio * nFlgChk4 / nMean;
} else {
nFlgChk4 = 0;
}
if (
pFlg32[HISDETNUM - 1] == 1 ||
pFlg32[HISDETNUM - 1] == 2 ||
pFlg32[HISDETNUM - 1] == 4) {
nFlgChk5 = nDif01[HISDIFNUM - 1] - nDif01[HISDIFNUM - 6];
if (nFlgChk5 < 0)
nFlgChk5 = -nFlgChk5;
nMean = (nDif01[HISDIFNUM - 1] + nDif01[HISDIFNUM - 6]) / 2;
nFlgChk5 = nflagch5_ratio * nFlgChk5 / nMean;
} else {
nFlgChk5 = 0;
}
if (prt_flg)
sprintf(debug_str + strlen(debug_str),
"nFlgChk4/5=(%2d,%2d)\n",
nFlgChk4, nFlgChk5);
nT2 = 5 * nDif02[HISDIFNUM - 1] / (nMn + sFrmDifLgTDif + 1);
nT2 = nT2>>1;
@@ -839,7 +898,9 @@ int Flm32DetSft(struct sFlmDatSt *pRDat, int *nDif02,
if (nSTP > 16)
nSTP = 16;
/*patch for dark scenes don't into pulldown32 by vlsi yanling*/
if (((nMx + nMn/2) / (nMn + 1)) < flm32_dif02_gap)
if (
((nMx + nMn / 2) / (nMn + 1)) < flm32_dif02_gap &&
pFlg32[HISDETNUM - 1] > 1)
nSTP = 0;
/*---------------*/
for (nT0 = 1; nT0 < HISDETNUM; nT0++) {
@@ -913,6 +974,9 @@ int Flm32DetSft(struct sFlmDatSt *pRDat, int *nDif02,
}
nFlg12[nT0] = ((nSTP + 8) >> 4);
if (nT0 == 5 && nMIX == 1 && nFlg01[nT0] == 0)
nFlg12[nT0] = 0;
}
/* -------------------------------------------- */
@@ -964,7 +1028,9 @@ int Flm32DetSft(struct sFlmDatSt *pRDat, int *nDif02,
(nFlgChk3 > flm32_ck13_rtn))
|| (nFlgChk2 > flm32_chk2_rtn)
|| ((pFlg32[HISDETNUM-1] == 4) &&
(nFlgChk3 > flm32_chk3_rtn))) {
(nFlgChk3 > flm32_chk3_rtn)) ||
(nFlgChk4 > nflagch4_th ||
nFlgChk5 > nflagch5_th)) {
pRDat->pMod32[HISDETNUM - 1] = 0;
pRDat->pFlg32[HISDETNUM - 1] = 0;
@@ -1376,8 +1442,17 @@ int Flm22DetSft(struct sFlmDatSt *pRDat, int *nDif02,
}
nFlgChk6 = nFlgChk6 / 6;
nAV21 = (nSM21 + nL21 / 2) / nL21; /* High average */
nAV22 = (nSM22 + nL22 / 2) / nL22; /* Low average */
/* for coverity error,"nL21/nL22" which may be zero */
if (nL21)
nAV21 = (nSM21 + nL21 / 2) / nL21; /* High average */
else
pr_info("%s: Error nL21 is zero\n", __func__);
if (nL22)
nAV22 = (nSM22 + nL22 / 2) / nL22; /* Low average */
else
pr_info("%s: Error nL22 is zero\n", __func__);
nOfst = nAV21 - nAV22;
if (prt_flg)

View File

@@ -47,6 +47,8 @@ module_param_named(nr2_en, nr2_en, uint, 0644);
static bool nr_ctrl_reg;
bool nr_demo_flag;
int global_bs_calc_sw(int *pGbsVldCnt,
int *pGbsVldFlg,
int *pGbs,
@@ -1196,6 +1198,18 @@ static void nr_all_ctrl(bool enable)
DI_Wr_reg_bits(DNR_CTRL, value, 16, 1);
}
static void nr_demo_mode(bool enable)
{
if (enable) {
DI_Wr_reg_bits(NR4_TOP_CTRL, 0, 6, 3);
nr_demo_flag = 1;
} else {
DI_Wr_reg_bits(NR4_TOP_CTRL, 7, 6, 3);
nr_demo_flag = 0;
}
}
static ssize_t nr_dbg_store(struct device *dev,
struct device_attribute *attr,
const char *buff, size_t count)
@@ -1208,6 +1222,15 @@ static ssize_t nr_dbg_store(struct device *dev,
nr_all_ctrl(false);
else if (!strcmp(parm[0], "enable"))
nr_all_ctrl(true);
else if (!strcmp(parm[0], "demo")) {
if (!strcmp(parm[1], "enable")) {
nr_demo_mode(true);
pr_info("nr demo enable\n");
} else if (!strcmp(parm[1], "disable")) {
nr_demo_mode(false);
pr_info("nr demo disable\n");
}
}
kfree(buf_orig);
return count;

View File

@@ -186,5 +186,6 @@ bool set_nr_ctrl_reg_table(unsigned int addr, unsigned int value);
extern void cue_int(struct vframe_s *vf);
extern bool nr_demo_flag;
#endif

View File

@@ -180,6 +180,13 @@ void DI_VSYNC_WR_MPEG_REG_BITS(unsigned int addr,
#define MCINFWR_Y 0x37f6
#define MCINFWR_CTRL 0x37f7
#define MCINFWR_CAN_SIZE 0x37f8
/* from TM2 new added */
/* DI HDR2 */
#define DI_HDR2_HIST_CTRL 0x37ad
#define DI_HDR2_HIST_H_START_END 0x37ae
#define DI_HDR2_HIST_V_START_END 0x37af
/* DI SCALE */
#define DI_SCO_FIFO_CTRL 0x374e
#define DI_SC_TOP_CTRL 0x374f

View File

@@ -127,6 +127,13 @@ int DI_POST_WR_REG_BITS(u32 adr, u32 val, u32 start, u32 len)
}
EXPORT_SYMBOL(DI_POST_WR_REG_BITS);
void DI_POST_UPDATE_MC(void)
{
if (dil_api && dil_api->post_update_mc)
dil_api->post_update_mc();
}
EXPORT_SYMBOL(DI_POST_UPDATE_MC);
/***************************************
* reserved mem for di *
**************************************/

View File

@@ -21,6 +21,7 @@
struct di_ext_ops {
unsigned int (*di_post_reg_rd)(unsigned int addr);
int (*di_post_wr_reg_bits)(u32 adr, u32 val, u32 start, u32 len);
void (*post_update_mc)(void);
};
#endif /*__DI_LOCAL_H__*/

View File

@@ -0,0 +1,15 @@
#
# Deinterlace driver configuration
#
menu "DI_MULTI driver"
config AMLOGIC_MEDIA_DEINTERLACE
tristate "DI_MULTI driver"
default n
help
Select to enable AMLOGIC DEINTERLACE driver
process interlace source need three continueed fields,
wave progressive source with two interlace fields from
one progreesive fields
endmenu

View File

@@ -0,0 +1,34 @@
# # Makefile for the Post Process Manager device #
ifeq ($(TARGET_BUILD_VARIANT),userdebug)
ccflags-y := -D DEBUG_SUPPORT
ccflags-y := -DDEBUG
else
ccflags-y := -DDEBUG
endif
ccflags-y += -I.
CFLAGS_dim.o := -I$(src)
obj-$(CONFIG_AMLOGIC_MEDIA_DEINTERLACE) += dim.o
dim-objs += deinterlace.o
dim-objs += deinterlace_hw.o
#dim-objs += deinterlace_mtn.o
dim-objs += deinterlace_dbg.o
#dim-objs += nr_drv.o
#dim-objs += pulldown_drv.o
#dim-objs += detect3d.o
dim-objs += nr_downscale.o
dim-objs += di_pps.o
dim-objs += di_vframe.o
dim-objs += di_prc.o
dim-objs += di_pre.o
dim-objs += di_post.o
dim-objs += di_reg_tab.o
dim-objs += di_dbg.o
dim-objs += di_que.o
dim-objs += di_sys.o
dim-objs += di_task.o
dim-objs += di_api.o
#dim-objs += film_mode_fmw/vof_soft_top.o
#dim-objs += film_mode_fmw/flm_mod_xx.o
#dim-objs += film_mode_fmw/film_fw1.o
ccflags-y += -Idrivers/amlogic/media/common/rdma/
ccflags-y += -I$(src)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,658 @@
/*
* drivers/amlogic/media/di_multi/deinterlace.h
*
* Copyright (C) 2017 Amlogic, Inc. 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
*/
#ifndef _DI_H
#define _DI_H
#include <linux/cdev.h>
#include <linux/types.h>
#include <linux/amlogic/media/vfm/vframe.h>
#include <linux/amlogic/media/vfm/vframe_provider.h>
#include "../di_local/di_local.h"
#include <linux/clk.h>
#include <linux/atomic.h>
#include "deinterlace_hw.h"
#include "../deinterlace/di_pqa.h"
/*trigger_pre_di_process param*/
#define TRIGGER_PRE_BY_PUT 'p'
#define TRIGGER_PRE_BY_DE_IRQ 'i'
#define TRIGGER_PRE_BY_UNREG 'u'
/*di_timer_handle*/
#define TRIGGER_PRE_BY_TIMER 't'
#define TRIGGER_PRE_BY_FORCE_UNREG 'f'
#define TRIGGER_PRE_BY_VFRAME_READY 'r'
#define TRIGGER_PRE_BY_PROVERDER_UNREG 'n'
#define TRIGGER_PRE_BY_DEBUG_DISABLE 'd'
#define TRIGGER_PRE_BY_PROVERDER_REG 'R'
#define DI_RUN_FLAG_RUN 0
#define DI_RUN_FLAG_PAUSE 1
#define DI_RUN_FLAG_STEP 2
#define DI_RUN_FLAG_STEP_DONE 3
#define USED_LOCAL_BUF_MAX 3
#define BYPASS_GET_MAX_BUF_NUM 4
/* buffer management related */
#define MAX_IN_BUF_NUM (4)
#define MAX_LOCAL_BUF_NUM (7)
#define MAX_POST_BUF_NUM (7) /*(5)*/ /* 16 */
#define VFRAME_TYPE_IN 1
#define VFRAME_TYPE_LOCAL 2
#define VFRAME_TYPE_POST 3
#define VFRAME_TYPE_NUM 3
#define DI_POST_GET_LIMIT 4
#define DI_PRE_READY_LIMIT 4
/*vframe define*/
#define vframe_t struct vframe_s
#define is_from_vdin(vframe) ((vframe)->type & VIDTYPE_VIU_422)
/* canvas defination */
#define DI_USE_FIXED_CANVAS_IDX
/*#define DET3D */
#undef SUPPORT_MPEG_TO_VDIN
#define CLK_TREE_SUPPORT
#ifndef CONFIG_AMLOGIC_MEDIA_RDMA
#ifndef VSYNC_WR_MPEG_REG
#define VSYNC_WR_MPEG_REG(adr, val) aml_write_vcbus(adr, val)
#define VSYNC_WR_MPEG_REG_BITS(adr, val, start, len) \
aml_vcbus_update_bits((adr), \
((1 << (len)) - 1) << (start), (val) << (start))
#define VSYNC_RD_MPEG_REG(adr) aml_read_vcbus(adr)
#endif
#endif
#define IS_VDIN_SRC(src) ( \
((src) == VFRAME_SOURCE_TYPE_TUNER) || \
((src) == VFRAME_SOURCE_TYPE_CVBS) || \
((src) == VFRAME_SOURCE_TYPE_COMP) || \
((src) == VFRAME_SOURCE_TYPE_HDMI))
#define IS_I_SRC(vftype) ((vftype) & VIDTYPE_INTERLACE_BOTTOM)
#define IS_COMP_MODE(vftype) ((vftype) & VIDTYPE_COMPRESS)
enum process_fun_index_e {
PROCESS_FUN_NULL = 0,
PROCESS_FUN_DI,
PROCESS_FUN_PD,
PROCESS_FUN_PROG,
PROCESS_FUN_BOB
};
#define process_fun_index_t enum process_fun_index_e
enum canvas_idx_e {
NR_CANVAS,
MTN_CANVAS,
MV_CANVAS,
};
#define pulldown_mode_t enum pulldown_mode_e
struct di_buf_s {
struct vframe_s *vframe;
int index; /* index in vframe_in_dup[] or vframe_in[],
* only for type of VFRAME_TYPE_IN
*/
int post_proc_flag; /* 0,no post di; 1, normal post di;
* 2, edge only; 3, dummy
*/
int new_format_flag;
int type;
int throw_flag;
int invert_top_bot_flag;
int seq;
int pre_ref_count; /* none zero, is used by mem_mif,
* chan2_mif, or wr_buf
*/
int post_ref_count; /* none zero, is used by post process */
int queue_index;
/*below for type of VFRAME_TYPE_LOCAL */
unsigned long nr_adr;
int nr_canvas_idx;
unsigned long mtn_adr;
int mtn_canvas_idx;
unsigned long cnt_adr;
int cnt_canvas_idx;
unsigned long mcinfo_adr;
int mcinfo_canvas_idx;
unsigned long mcvec_adr;
int mcvec_canvas_idx;
struct mcinfo_pre_s {
unsigned int highvertfrqflg;
unsigned int motionparadoxflg;
unsigned int regs[26];/* reg 0x2fb0~0x2fc9 */
} curr_field_mcinfo;
/* blend window */
struct pulldown_detected_s
pd_config;
/* tff bff check result bit[1:0]*/
unsigned int privated;
unsigned int canvas_config_flag;
/* 0,configed; 1,config type 1 (prog);
* 2, config type 2 (interlace)
*/
unsigned int canvas_height;
unsigned int canvas_height_mc; /*ary add for mc h is diff*/
unsigned int canvas_width[3];/* nr/mtn/mv */
process_fun_index_t process_fun_index;
int early_process_fun_index;
int left_right;/*1,left eye; 0,right eye in field alternative*/
/*below for type of VFRAME_TYPE_POST*/
struct di_buf_s *di_buf[2];
struct di_buf_s *di_buf_dup_p[5];
/* 0~4: n-2, n-1, n, n+1, n+2; n is the field to display*/
/*0: n-2*/
/*1: n-1*/
/*2: n*/
/*3: n+1*/
/*4: n+2*/
struct di_buf_s *di_wr_linked_buf;
/* debug for di-vf-get/put
* 1: after get
* 0: after put
*/
atomic_t di_cnt;
struct page *pages;
/*ary add */
unsigned int channel;
unsigned int width_bk; /*move from ppre*/
};
#define RDMA_DET3D_IRQ 0x20
/* vdin0 rdma irq */
#define RDMA_DEINT_IRQ 0x2
#define RDMA_TABLE_SIZE ((PAGE_SIZE) << 1)
#define MAX_CANVAS_WIDTH 1920
#define MAX_CANVAS_HEIGHT 1088
/* #define DI_BUFFER_DEBUG */
#define DI_LOG_MTNINFO 0x02
#define DI_LOG_PULLDOWN 0x10
#define DI_LOG_BUFFER_STATE 0x20
#define DI_LOG_TIMESTAMP 0x100
#define DI_LOG_PRECISE_TIMESTAMP 0x200
#define DI_LOG_QUEUE 0x40
#define DI_LOG_VFRAME 0x80
#if 0
#define QUEUE_LOCAL_FREE 0
#define QUEUE_IN_FREE 1
#define QUEUE_PRE_READY 2
#define QUEUE_POST_FREE 3
#define QUEUE_POST_READY 4
#define QUEUE_RECYCLE 5
#define QUEUE_DISPLAY 6
#define QUEUE_TMP 7
#define QUEUE_POST_DOING 8
#define QUEUE_NUM 9
#else
#define QUEUE_LOCAL_FREE 0
#define QUEUE_RECYCLE 1 /* 5 */
#define QUEUE_DISPLAY 2 /* 6 */
#define QUEUE_TMP 3 /* 7 */
#define QUEUE_POST_DOING 4 /* 8 */
#define QUEUE_IN_FREE 5 /* 1 */
#define QUEUE_PRE_READY 6 /* 2 */
#define QUEUE_POST_FREE 7 /* 3 */
#define QUEUE_POST_READY 8 /* 4 QUE_POST_READY */
/*new use this for put back control*/
#define QUEUE_POST_PUT_BACK (9)
#define QUEUE_NUM 5 /* 9 */
#define QUEUE_NEW_THD_MIN (QUEUE_IN_FREE - 1)
#define QUEUE_NEW_THD_MAX (QUEUE_POST_READY + 1)
#endif
#define queue_t struct queue_s
#define VFM_NAME "deinterlace"
#ifdef CONFIG_AMLOGIC_MEDIA_VSYNC_RDMA
void enable_rdma(int enable_flag);
int VSYNC_WR_MPEG_REG(u32 adr, u32 val);
int VSYNC_WR_MPEG_REG_BITS(u32 adr, u32 val, u32 start, u32 len);
u32 VSYNC_RD_MPEG_REG(u32 adr);
bool is_vsync_rdma_enable(void);
#else
#ifndef VSYNC_WR_MPEG_REG
#define VSYNC_WR_MPEG_REG(adr, val) aml_write_vcbus(adr, val)
#define VSYNC_WR_MPEG_REG_BITS(adr, val, start, len) \
aml_vcbus_update_bits((adr), \
((1 << (len)) - 1) << (start), (val) << (start))
#define VSYNC_RD_MPEG_REG(adr) aml_read_vcbus(adr)
#endif
#endif
#define DI_COUNT 1
#define DI_MAP_FLAG 0x1
#define DI_SUSPEND_FLAG 0x2
#define DI_LOAD_REG_FLAG 0x4
#define DI_VPU_CLKB_SET 0x8
struct di_dev_s {
dev_t devt;
struct cdev cdev; /* The cdev structure */
struct device *dev;
struct platform_device *pdev;
dev_t devno;
struct class *pclss;
bool sema_flg; /*di_sema_init_flag*/
struct task_struct *task;
struct clk *vpu_clkb;
unsigned long clkb_max_rate;
unsigned long clkb_min_rate;
struct list_head pq_table_list;
atomic_t pq_flag;
unsigned char di_event;
unsigned int pre_irq;
unsigned int post_irq;
unsigned int flags;
unsigned long jiffy;
unsigned long mem_start;
unsigned int mem_size;
bool mem_flg; /*ary add for make sure mem is ok*/
unsigned int buffer_size;
unsigned int post_buffer_size;
unsigned int buf_num_avail;
int rdma_handle;
/* is support nr10bit */
unsigned int nr10bit_support;
/* is DI support post wr to mem for OMX */
unsigned int post_wr_support;
unsigned int nrds_enable;
unsigned int pps_enable;
unsigned int h_sc_down_en;/*sm1, tm2 ...*/
/*struct mutex cma_mutex;*/
unsigned int flag_cma;
struct page *total_pages;
struct dentry *dbg_root; /*dbg_fs*/
/***************************/
/*struct di_data_l_s data_l;*/
void *data_l;
};
struct di_pre_stru_s {
/* pre input */
struct DI_MIF_s di_inp_mif;
struct DI_MIF_s di_mem_mif;
struct DI_MIF_s di_chan2_mif;
struct di_buf_s *di_inp_buf;
struct di_buf_s *di_post_inp_buf;
struct di_buf_s *di_inp_buf_next;
/* p_asi_next: ary:add for p */
struct di_buf_s *p_asi_next;
struct di_buf_s *di_mem_buf_dup_p;
struct di_buf_s *di_chan2_buf_dup_p;
/* pre output */
struct DI_SIM_MIF_s di_nrwr_mif;
struct DI_SIM_MIF_s di_mtnwr_mif;
struct di_buf_s *di_wr_buf;
struct di_buf_s *di_post_wr_buf;
struct DI_SIM_MIF_s di_contp2rd_mif;
struct DI_SIM_MIF_s di_contprd_mif;
struct DI_SIM_MIF_s di_contwr_mif;
int field_count_for_cont;
/*
* 0 (f0,null,f0)->nr0,
* 1 (f1,nr0,f1)->nr1_cnt,
* 2 (f2,nr1_cnt,nr0)->nr2_cnt
* 3 (f3,nr2_cnt,nr1_cnt)->nr3_cnt
*/
struct DI_MC_MIF_s di_mcinford_mif;
struct DI_MC_MIF_s di_mcvecwr_mif;
struct DI_MC_MIF_s di_mcinfowr_mif;
/* pre state */
int in_seq;
int recycle_seq;
int pre_ready_seq;
int pre_de_busy; /* 1 if pre_de is not done */
int pre_de_process_flag; /* flag when dim_pre_de_process done */
int pre_de_clear_flag;
/* flag is set when VFRAME_EVENT_PROVIDER_UNREG*/
int unreg_req_flag_cnt;
int reg_req_flag_cnt;
int force_unreg_req_flag;
int disable_req_flag;
/* current source info */
int cur_width;
int cur_height;
int cur_inp_type;
int cur_source_type;
int cur_sig_fmt;
unsigned int orientation;
int cur_prog_flag; /* 1 for progressive source */
/* valid only when prog_proc_type is 0, for
* progressive source: top field 1, bot field 0
*/
int source_change_flag;
/* input size change flag, 1: need reconfig pre/nr/dnr size */
/* 0: not need config pre/nr/dnr size*/
bool input_size_change_flag;
/* true: bypass di all logic, false: not bypass */
bool bypass_flag;
unsigned char prog_proc_type;
/* set by prog_proc_config when source is vdin,0:use 2 i
* serial buffer,1:use 1 p buffer,3:use 2 i paralleling buffer
*/
/* ary: loacal play p mode is 0
* local play i mode is 0
*/
unsigned char buf_alloc_mode;
/* alloc di buf as p or i;0: alloc buf as i;
* 1: alloc buf as p;
*/
unsigned char madi_enable;
unsigned char mcdi_enable;
unsigned int pps_dstw; /*no use ?*/
unsigned int pps_dsth; /*no use ?*/
int left_right;/*1,left eye; 0,right eye in field alternative*/
/*input2pre*/
int bypass_start_count;
/* need discard some vframe when input2pre => bypass */
unsigned char vdin2nr;
enum tvin_trans_fmt source_trans_fmt;
enum tvin_trans_fmt det3d_trans_fmt;
unsigned int det_lr;
unsigned int det_tp;
unsigned int det_la;
unsigned int det_null;
unsigned int width_bk;
#ifdef DET3D
int vframe_interleave_flag;
#endif
/**/
int pre_de_irq_timeout_count;
int pre_throw_flag;
int bad_frame_throw_count;
/*for static pic*/
int static_frame_count;
bool force_interlace;
bool bypass_pre;
bool invert_flag;
bool vdin_source;
int nr_size;
int count_size;
int mcinfo_size;
int mv_size;
int mtn_size;
int cma_release_req;
/* for performance debug */
unsigned long irq_time[2];
/* combing adaptive */
struct combing_status_s *mtn_status;
bool combing_fix_en;
unsigned int comb_mode;
};
struct di_post_stru_s {
struct DI_MIF_s di_buf0_mif;
struct DI_MIF_s di_buf1_mif;
struct DI_MIF_s di_buf2_mif;
struct DI_SIM_MIF_s di_diwr_mif;
struct DI_SIM_MIF_s di_mtnprd_mif;
struct DI_MC_MIF_s di_mcvecrd_mif;
/*post doing buf and write buf to post ready*/
struct di_buf_s *cur_post_buf;
struct di_buf_s *keep_buf;
struct di_buf_s *keep_buf_post; /*ary add for keep post buf*/
int update_post_reg_flag;
int run_early_proc_fun_flag;
int cur_disp_index;
int canvas_id;
int next_canvas_id;
bool toggle_flag;
bool vscale_skip_flag;
uint start_pts;
int buf_type;
int de_post_process_done;
int post_de_busy;
int di_post_num;
unsigned int post_peek_underflow;
unsigned int di_post_process_cnt;
unsigned int check_recycle_buf_cnt;/*cp to di_hpre_s*/
/* performance debug */
unsigned int post_wr_cnt;
unsigned long irq_time;
/*frame cnt*/
unsigned int frame_cnt; /*cnt for post process*/
};
#define MAX_QUEUE_POOL_SIZE 256
struct queue_s {
unsigned int num;
unsigned int in_idx;
unsigned int out_idx;
unsigned int type;
/* 0, first in first out;
* 1, general;2, fix position for di buf
*/
unsigned int pool[MAX_QUEUE_POOL_SIZE];
};
struct di_buf_pool_s {
struct di_buf_s *di_buf_ptr;
unsigned int size;
};
struct dim_mm_s {
struct page *ppage;
unsigned long addr;
};
bool dim_mm_alloc(int cma_mode, size_t count, struct dim_mm_s *o);
bool dim_mm_release(int cma_mode,
struct page *pages,
int count,
unsigned long addr);
unsigned char dim_is_bypass(vframe_t *vf_in, unsigned int channel);
bool dim_bypass_first_frame(unsigned int ch);
int di_cnt_buf(int width, int height, int prog_flag, int mc_mm,
int bit10_support, int pack422);
/*---get di state parameter---*/
struct di_dev_s *get_dim_de_devp(void);
const char *dim_get_version_s(void);
int dim_get_dump_state_flag(void);
int dim_get_blocking(void);
struct di_buf_s *dim_get_recovery_log_di_buf(void);
unsigned long dim_get_reg_unreg_timeout_cnt(void);
struct vframe_s **dim_get_vframe_in(unsigned int ch);
int dim_check_recycle_buf(unsigned int channel);
int dim_seq_file_module_para_di(struct seq_file *seq);
int dim_seq_file_module_para_hw(struct seq_file *seq);
int dim_seq_file_module_para_film_fw1(struct seq_file *seq);
int dim_seq_file_module_para_mtn(struct seq_file *seq);
int dim_seq_file_module_para_pps(struct seq_file *seq);
int dim_seq_file_module_para_(struct seq_file *seq);
/***********************/
unsigned int di_get_dts_nrds_en(void);
int di_get_disp_cnt(void);
/*---------------------*/
long dim_pq_load_io(unsigned long arg);
int dim_get_canvas(void);
unsigned int dim_cma_alloc_total(struct di_dev_s *de_devp);
irqreturn_t dim_irq(int irq, void *dev_instance);
irqreturn_t dim_post_irq(int irq, void *dev_instance);
void dim_rdma_init(void);
void dim_rdma_exit(void);
void dim_set_di_flag(void);
void dim_get_vpu_clkb(struct device *dev, struct di_dev_s *pdev);
void dim_log_buffer_state(unsigned char *tag, unsigned int channel);
unsigned char dim_pre_de_buf_config(unsigned int channel);
void dim_pre_de_process(unsigned int channel);
void dim_pre_de_done_buf_config(unsigned int channel, bool flg_timeout);
void dim_pre_de_done_buf_clear(unsigned int channel);
void di_reg_setting(unsigned int channel, struct vframe_s *vframe);
void di_reg_variable(unsigned int channel, struct vframe_s *vframe);
void dim_unreg_process_irq(unsigned int channel);
void di_unreg_variable(unsigned int channel);
void di_unreg_setting(void);
void dim_uninit_buf(unsigned int disable_mirror, unsigned int channel);
void dim_unreg_process(unsigned int channel);
int dim_process_post_vframe(unsigned int channel);
unsigned char dim_check_di_buf(struct di_buf_s *di_buf, int reason,
unsigned int channel);
int dim_do_post_wr_fun(void *arg, vframe_t *disp_vf);
int dim_post_process(void *arg, unsigned int zoom_start_x_lines,
unsigned int zoom_end_x_lines,
unsigned int zoom_start_y_lines,
unsigned int zoom_end_y_lines, vframe_t *disp_vf);
void dim_post_de_done_buf_config(unsigned int channel);
void dim_recycle_post_back(unsigned int channel);
void recycle_post_ready_local(struct di_buf_s *di_buf,
unsigned int channel);
/*--------------------------*/
unsigned char dim_vcry_get_flg(void);
void dim_vcry_flg_inc(void);
void dim_vcry_set_flg(unsigned char val);
/*--------------------------*/
unsigned int dim_vcry_get_log_reason(void);
void dim_vcry_set_log_reason(unsigned int val);
/*--------------------------*/
unsigned char dim_vcry_get_log_q_idx(void);
void dim_vcry_set_log_q_idx(unsigned int val);
/*--------------------------*/
struct di_buf_s **dim_vcry_get_log_di_buf(void);
void dim_vcry_set_log_di_buf(struct di_buf_s *di_bufp);
void dim_vcry_set(unsigned int reason, unsigned int idx,
struct di_buf_s *di_bufp);
const char *dim_get_vfm_type_name(unsigned int nub);
bool dim_cma_top_alloc(unsigned int ch);
bool dim_cma_top_release(unsigned int ch);
int dim_get_reg_unreg_cnt(void);
void dim_reg_timeout_inc(void);
void dim_reg_process(unsigned int channel);
bool is_bypass2(struct vframe_s *vf_in, unsigned int ch);
/*--------------------------*/
int di_ori_event_unreg(unsigned int channel);
int di_ori_event_reg(void *data, unsigned int channel);
int di_ori_event_qurey_vdin2nr(unsigned int channel);
int di_ori_event_reset(unsigned int channel);
int di_ori_event_light_unreg(unsigned int channel);
int di_ori_event_light_unreg_revframe(unsigned int channel);
int di_ori_event_ready(unsigned int channel);
int di_ori_event_qurey_state(unsigned int channel);
void di_ori_event_set_3D(int type, void *data, unsigned int channel);
/*--------------------------*/
extern int pre_run_flag;
extern unsigned int dbg_first_cnt_pre;
extern spinlock_t plist_lock;
void dim_dbg_pre_cnt(unsigned int channel, char *item);
void diext_clk_b_sw(bool on);
int di_vf_l_states(struct vframe_states *states, unsigned int channel);
struct vframe_s *di_vf_l_peek(unsigned int channel);
void di_vf_l_put(struct vframe_s *vf, unsigned char channel);
struct vframe_s *di_vf_l_get(unsigned int channel);
unsigned char pre_p_asi_de_buf_config(unsigned int ch);
/*---------------------*/
ssize_t
store_config(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count);
ssize_t
store_dbg(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count);
ssize_t
store_dump_mem(struct device *dev, struct device_attribute *attr,
const char *buf, size_t len);
ssize_t
store_log(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count);
ssize_t
show_vframe_status(struct device *dev,
struct device_attribute *attr,
char *buf);
ssize_t dim_read_log(char *buf);
/*---------------------*/
struct di_buf_s *dim_get_buf(unsigned int channel,
int queue_idx, int *start_pos);
#define queue_for_each_entry(di_buf, channel, queue_idx, list) \
for (itmp = 0; \
((di_buf = dim_get_buf(channel, queue_idx, &itmp)) != NULL);)
#define di_dev_t struct di_dev_s
#define di_pr_info(fmt, args ...) pr_info("DI: " fmt, ## args)
#define pr_dbg(fmt, args ...) pr_debug("DI: " fmt, ## args)
#define pr_error(fmt, args ...) pr_err("DI: " fmt, ## args)
/*this is debug for buf*/
/*#define DI_DEBUG_POST_BUF_FLOW (1)*/
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,43 @@
/*
* drivers/amlogic/media/di_multi/deinterlace_dbg.h
*
* Copyright (C) 2017 Amlogic, Inc. 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
*/
#ifndef _DI_DBG_H
#define _DI_DBG_H
#include "deinterlace.h"
void dim_parse_cmd_params(char *buf_orig, char **parm);
void dim_dump_pre_stru(struct di_pre_stru_s *ppre);
void dim_dump_post_stru(struct di_post_stru_s *di_post_stru_p);
void dim_dump_di_buf(struct di_buf_s *di_buf);
void dim_dump_pool(struct queue_s *q);
void dim_dump_vframe(vframe_t *vf);
void dim_print_di_buf(struct di_buf_s *di_buf, int format);
void dim_dump_pre_mif_state(void);
void dim_dump_post_mif_reg(void);
void dim_dump_buf_addr(struct di_buf_s *di_buf, unsigned int num);
void dim_dump_mif_size_state(struct di_pre_stru_s *pre,
struct di_post_stru_s *post);
void debug_device_files_add(struct device *dev);
void debug_device_files_del(struct device *dev);
void dim_debugfs_init(void);
void dim_debugfs_exit(void);
int dim_state_show(struct seq_file *seq, void *v,
unsigned int channel);
int dim_dump_mif_size_state_show(struct seq_file *seq, void *v,
unsigned int channel);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,277 @@
/*
* drivers/amlogic/media/di_multi/deinterlace_hw.h
*
* Copyright (C) 2017 Amlogic, Inc. 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
*/
#ifndef _DI_HW_H
#define _DI_HW_H
#include <linux/amlogic/media/amvecm/amvecm.h>
#include "../deinterlace/di_pqa.h"
/* if post size < 80, filter of ei can't work */
#define MIN_POST_WIDTH 80
#define MIN_BLEND_WIDTH 27
#define SKIP_CTRE_NUM 13
/*move from deinterlace.c*/
enum eAFBC_REG {
eAFBC_ENABLE,
eAFBC_MODE,
eAFBC_SIZE_IN,
eAFBC_DEC_DEF_COLOR,
eAFBC_CONV_CTRL,
eAFBC_LBUF_DEPTH,
eAFBC_HEAD_BADDR,
eAFBC_BODY_BADDR,
eAFBC_SIZE_OUT,
eAFBC_OUT_YSCOPE,
eAFBC_STAT,
eAFBC_VD_CFMT_CTRL,
eAFBC_VD_CFMT_W,
eAFBC_MIF_HOR_SCOPE,
eAFBC_MIF_VER_SCOPE,
eAFBC_PIXEL_HOR_SCOPE,
eAFBC_PIXEL_VER_SCOPE,
eAFBC_VD_CFMT_H,
};
enum eAFBC_DEC {
eAFBC_DEC0,
eAFBC_DEC1,
};
#define AFBC_REG_INDEX_NUB (18)
#define AFBC_DEC_NUB (2)
struct DI_MIF_s {
unsigned short luma_x_start0;
unsigned short luma_x_end0;
unsigned short luma_y_start0;
unsigned short luma_y_end0;
unsigned short chroma_x_start0;
unsigned short chroma_x_end0;
unsigned short chroma_y_start0;
unsigned short chroma_y_end0;
unsigned int nocompress;
unsigned set_separate_en:2;
unsigned src_field_mode:1;
unsigned src_prog:1;
unsigned video_mode:1;
unsigned output_field_num:1;
unsigned bit_mode:2;
/*
* unsigned burst_size_y:2; set 3 as default
* unsigned burst_size_cb:2;set 1 as default
* unsigned burst_size_cr:2;set 1 as default
*/
unsigned canvas0_addr0:8;
unsigned canvas0_addr1:8;
unsigned canvas0_addr2:8;
};
struct DI_SIM_MIF_s {
unsigned short start_x;
unsigned short end_x;
unsigned short start_y;
unsigned short end_y;
unsigned short canvas_num;
unsigned short bit_mode;
};
struct DI_MC_MIF_s {
unsigned short start_x;
unsigned short start_y;
unsigned short end_y;
unsigned short size_x;
unsigned short size_y;
unsigned short canvas_num;
unsigned short blend_en;
unsigned short vecrd_offset;
};
enum gate_mode_e {
GATE_AUTO,
GATE_ON,
GATE_OFF,
};
struct mcinfo_lmv_s {
unsigned char lock_flag;
char lmv;
unsigned short lock_cnt;
};
struct di_pq_parm_s {
struct am_pq_parm_s pq_parm;
struct am_reg_s *regs;
struct list_head list;
};
void dim_read_pulldown_info(unsigned int *glb_frm_mot_num,
unsigned int *glb_fid_mot_num);
#if 0
void read_new_pulldown_info(struct FlmModReg_t *pFMRegp);
#endif
void dim_pulldown_info_clear_g12a(void);
void dimh_combing_pd22_window_config(unsigned int width, unsigned int height);
void dimh_hw_init(bool pulldown_en, bool mc_enable);
void dimh_hw_uninit(void);
void dimh_enable_di_pre_aml(struct DI_MIF_s *di_inp_mif,
struct DI_MIF_s *di_mem_mif,
struct DI_MIF_s *di_chan2_mif,
struct DI_SIM_MIF_s *di_nrwr_mif,
struct DI_SIM_MIF_s *di_mtnwr_mif,
struct DI_SIM_MIF_s *di_contp2rd_mif,
struct DI_SIM_MIF_s *di_contprd_mif,
struct DI_SIM_MIF_s *di_contwr_mif,
unsigned char madi_en,
unsigned char pre_field_num,
unsigned char pre_vdin_link);
void dimh_enable_afbc_input(struct vframe_s *vf);
void dimh_mc_pre_mv_irq(void);
void dimh_enable_mc_di_pre(struct DI_MC_MIF_s *di_mcinford_mif,
struct DI_MC_MIF_s *di_mcinfowr_mif,
struct DI_MC_MIF_s *di_mcvecwr_mif,
unsigned char mcdi_en);
void dimh_enable_mc_di_pre_g12(struct DI_MC_MIF_s *di_mcinford_mif,
struct DI_MC_MIF_s *di_mcinfowr_mif,
struct DI_MC_MIF_s *di_mcvecwr_mif,
unsigned char mcdi_en);
void dimh_enable_mc_di_post(struct DI_MC_MIF_s *di_mcvecrd_mif,
int urgent, bool reverse, int invert_mv);
void dimh_enable_mc_di_post_g12(struct DI_MC_MIF_s *di_mcvecrd_mif,
int urgent, bool reverse, int invert_mv);
void dimh_disable_post_deinterlace_2(void);
void dimh_initial_di_post_2(int hsize_post, int vsize_post,
int hold_line, bool write_en);
void dimh_enable_di_post_2(
struct DI_MIF_s *di_buf0_mif,
struct DI_MIF_s *di_buf1_mif,
struct DI_MIF_s *di_buf2_mif,
struct DI_SIM_MIF_s *di_diwr_mif,
struct DI_SIM_MIF_s *di_mtnprd_mif,
int ei_en, int blend_en, int blend_mtn_en, int blend_mode,
int di_vpp_en, int di_ddr_en,
int post_field_num, int hold_line, int urgent,
int invert_mv, int vskip_cnt
);
void dimh_post_switch_buffer(
struct DI_MIF_s *di_buf0_mif,
struct DI_MIF_s *di_buf1_mif,
struct DI_MIF_s *di_buf2_mif,
struct DI_SIM_MIF_s *di_diwr_mif,
struct DI_SIM_MIF_s *di_mtnprd_mif,
struct DI_MC_MIF_s *di_mcvecrd_mif,
int ei_en, int blend_en, int blend_mtn_en, int blend_mode,
int di_vpp_en, int di_ddr_en,
int post_field_num, int hold_line, int urgent,
int invert_mv, bool pd_en, bool mc_enable,
int vskip_cnt
);
void dim_post_read_reverse_irq(bool reverse,
unsigned char mc_pre_flag, bool mc_enable);
void dim_top_gate_control(bool top_en, bool mc_en);
void dim_pre_gate_control(bool enable, bool mc_enable);
void dim_post_gate_control(bool gate);
void dim_set_power_control(unsigned char enable);
void dim_hw_disable(bool mc_enable);
void dimh_enable_di_pre_mif(bool enable, bool mc_enable);
void dimh_enable_di_post_mif(enum gate_mode_e mode);
void dimh_combing_pd22_window_config(unsigned int width, unsigned int height);
void dimh_calc_lmv_init(void);
void dimh_calc_lmv_base_mcinfo(unsigned int vf_height,
unsigned long mcinfo_adr,
unsigned int mcinfo_size);
void dimh_init_field_mode(unsigned short height);
void dim_film_mode_win_config(unsigned int width, unsigned int height);
void dimh_pulldown_vof_win_config(struct pulldown_detected_s *wins);
void dimh_load_regs(struct di_pq_parm_s *di_pq_ptr);
void dim_pre_frame_reset_g12(unsigned char madi_en, unsigned char mcdi_en);
void dim_pre_frame_reset(void);
void dimh_interrupt_ctrl(unsigned char ma_en,
unsigned char det3d_en, unsigned char nrds_en,
unsigned char post_wr, unsigned char mc_en);
void dimh_txl_patch_prog(int prog_flg, unsigned int cnt, bool mc_en);
bool dimh_afbc_is_supported(void);
void dimh_afbc_reg_sw(bool on);
void dump_vd2_afbc(void);
u8 *dim_vmap(ulong addr, u32 size, bool *bflg);
void dim_unmap_phyaddr(u8 *vaddr);
int dim_print(const char *fmt, ...);
#define DI_MC_SW_OTHER (1 << 0)
#define DI_MC_SW_REG (1 << 1)
/*#define DI_MC_SW_POST (1 << 2)*/
#define DI_MC_SW_IC (1 << 2)
#define DI_MC_SW_ON_MASK (DI_MC_SW_REG | DI_MC_SW_OTHER | DI_MC_SW_IC)
void dimh_patch_post_update_mc(void);
void dimh_patch_post_update_mc_sw(unsigned int cmd, bool on);
void dim_rst_protect(bool on);
void dim_pre_nr_wr_done_sel(bool on);
void dim_arb_sw(bool on);
void dbg_set_DI_PRE_CTRL(void);
void di_async_reset2(void); /*2019-04-05 add for debug*/
enum DI_HW_POST_CTRL {
DI_HW_POST_CTRL_INIT,
DI_HW_POST_CTRL_RESET,
};
void dimh_post_ctrl(enum DI_HW_POST_CTRL contr,
unsigned int post_write_en);
void dimh_int_ctr(unsigned int set_mod, unsigned char ma_en,
unsigned char det3d_en, unsigned char nrds_en,
unsigned char post_wr, unsigned char mc_en);
void h_dbg_reg_set(unsigned int val);
enum eDI_POST_FLOW {
eDI_POST_FLOW_STEP1_STOP,
eDI_POST_FLOW_STEP2_START,
/* eDI_POST_FLOW_STEP3_RESET_INT,*/
};
void di_post_set_flow(unsigned int post_wr_en, enum eDI_POST_FLOW step);
void post_mif_sw(bool on);
void post_dbg_contr(void);
void post_close_new(void);
void di_post_reset(void);
void dimh_pst_trig_resize(void);
void hpst_power_ctr(bool on);
void hpst_dbg_power_ctr_trig(unsigned int cmd);
void hpst_dbg_mem_pd_trig(unsigned int cmd);
void hpst_dbg_trig_gate(unsigned int cmd);
void hpst_dbg_trig_mif(unsigned int cmd);
void hpst_mem_pd_sw(unsigned int on);
void hpst_vd1_sw(unsigned int on);
void dim_init_setting_once(void);
void dim_hw_init_reg(void);
#endif

View File

@@ -0,0 +1,107 @@
/*
* drivers/amlogic/media/di_multi/di_api.c
*
* Copyright (C) 2017 Amlogic, Inc. 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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/types.h>
#include <linux/slab.h>
#include <linux/amlogic/media/vpu/vpu.h>
#include "di_api.h"
/**********************************
* DI api is used for other module
*********************************/
static const struct di_ext_ops di_ext = {
.di_post_reg_rd = l_DI_POST_REG_RD,
.di_post_wr_reg_bits = l_DI_POST_WR_REG_BITS,
.post_update_mc = NULL,
};
void dim_attach_to_local(void)
{
dil_attach_ext_api(&di_ext);
}
bool dim_attach_ext_api(struct di_ext_ops *di_api)
{
#if 1
if (!di_api)
return false;
memcpy(di_api, &di_ext, sizeof(struct di_ext_ops));
#else
di_api = &di_ext;
#endif
return true;
}
/*EXPORT_SYMBOL(dim_attach_ext_api);*/
/**********************************
* ext_api used by DI
********************************/
#define ARY_TEMP2
#ifdef ARY_TEMP2
void ext_switch_vpu_mem_pd_vmod(unsigned int vmod, bool on)
{
switch_vpu_mem_pd_vmod(vmod,
on ? VPU_MEM_POWER_ON : VPU_MEM_POWER_DOWN);
}
const struct ext_ops_s ext_ops = {
.switch_vpu_mem_pd_vmod = ext_switch_vpu_mem_pd_vmod,
/*no use ?*/
/* .vf_get_receiver_name = vf_get_receiver_name,*/
.switch_vpu_clk_gate_vmod = switch_vpu_clk_gate_vmod,
.get_current_vscale_skip_count = get_current_vscale_skip_count,
.canvas_pool_alloc_canvas_table = canvas_pool_alloc_canvas_table,
};
#else
void n_switch_vpu_mem_pd_vmod(unsigned int vmod, bool on)
{
}
char *n_vf_get_receiver_name(const char *provider_name)
{
return "";
}
void n_switch_vpu_clk_gate_vmod(unsigned int vmod, int flag)
{
}
int n_get_current_vscale_skip_count(struct vframe_s *vf)
{
return 0;
}
u32 n_canvas_pool_alloc_canvas_table(const char *owner, u32 *tab,
int size,
enum canvas_map_type_e type)
{
return 0;
}
const struct ext_ops_s ext_ops = {
.switch_vpu_mem_pd_vmod = n_switch_vpu_mem_pd_vmod,
.vf_get_receiver_name = n_vf_get_receiver_name,
.switch_vpu_clk_gate_vmod = n_switch_vpu_clk_gate_vmod,
.get_current_vscale_skip_count = n_get_current_vscale_skip_count,
.canvas_pool_alloc_canvas_table = n_canvas_pool_alloc_canvas_table,
};
#endif

View File

@@ -0,0 +1,55 @@
/*
* drivers/amlogic/media/di_multi/di_api.h
*
* Copyright (C) 2017 Amlogic, Inc. 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
*/
#ifndef __DI_API_H__
#define __DI_API_H__
#include <linux/amlogic/media/canvas/canvas_mgr.h>
#include <linux/amlogic/media/vfm/vframe.h>
#include "../di_local/di_local.h"
/*--------------------------*/
unsigned int l_DI_POST_REG_RD(unsigned int addr);
int l_DI_POST_WR_REG_BITS(u32 adr, u32 val, u32 start, u32 len);
/*--------------------------*/
bool di_attach_ext_api(struct di_ext_ops *di_api);
/*attach di_ops to di_local*/
bool dil_attach_ext_api(const struct di_ext_ops *di_api);
void dim_attach_to_local(void);
/*--------------------------*/
int get_current_vscale_skip_count(struct vframe_s *vf);
struct ext_ops_s {
void (*switch_vpu_mem_pd_vmod)(unsigned int vmod, bool on);
/* char *(*vf_get_receiver_name)(const char *provider_name);*/
void (*switch_vpu_clk_gate_vmod)(unsigned int vmod, int flag);
int (*get_current_vscale_skip_count)(struct vframe_s *vf);
u32 (*canvas_pool_alloc_canvas_table)(const char *owner, u32 *tab,
int size,
enum canvas_map_type_e type);
};
extern const struct ext_ops_s ext_ops;
/*--------------------------*/
void dil_get_rev_mem(unsigned long *mstart, unsigned int *msize);
void dil_get_flg(unsigned int *flg);
#endif /*__DI_API_H__*/

View File

@@ -0,0 +1,21 @@
/*
* drivers/amlogic/media/di_multi/di_data.h
*
* Copyright (C) 2017 Amlogic, Inc. 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
*/
#ifndef __DI_DATA_H__
#define __DI_DATA_H__
#endif /*__DI_DATA_H__*/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,69 @@
/*
* drivers/amlogic/media/di_multi/di_dbg.h
*
* Copyright (C) 2017 Amlogic, Inc. 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
*/
#ifndef __DI_DBG_H__
#define __DI_DBG_H__
#include <linux/amlogic/media/vfm/vframe.h>
#include <linux/amlogic/media/vfm/vframe_provider.h>
#include <linux/amlogic/media/vfm/vframe_receiver.h>
void didbg_fs_init(void);
void didbg_fs_exit(void);
void di_cfgx_init_val(void);
void didbg_vframe_in_copy(unsigned int ch, struct vframe_s *pvfm);
void didbg_vframe_out_save(struct vframe_s *pvfm);
/********************************
*debug register:
*******************************/
void ddbg_reg_save(unsigned int addr, unsigned int val,
unsigned int st, unsigned int bw);
void dim_ddbg_mod_save(unsigned int mod,
unsigned int ch,
unsigned int cnt);
void ddbg_sw(unsigned int mode, bool on);
/********************************
*time:
*******************************/
u64 cur_to_msecs(void);
u64 cur_to_usecs(void); /*2019*/
/********************************
*trace:
*******************************/
struct dim_tr_ops_s {
void (*pre)(unsigned int index, unsigned long ctime);
void (*post)(unsigned int index, unsigned long ctime);
void (*pre_get)(unsigned int index);
void (*pre_set)(unsigned int index);
void (*pre_ready)(unsigned int index);
void (*post_ready)(unsigned int index);
void (*post_get)(unsigned int index);
void (*post_get2)(unsigned int index);
void (*post_set)(unsigned int index);
void (*post_ir)(unsigned int index);
void (*post_do)(unsigned int index);
void (*post_peek)(unsigned int index);
};
extern const struct dim_tr_ops_s dim_tr_ops;
#endif /*__DI_DBG_H__*/

View File

@@ -0,0 +1,389 @@
/*
* drivers/amlogic/media/di_multi/di_post.c
*
* Copyright (C) 2017 Amlogic, Inc. 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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/kernel.h>
#include <linux/err.h>
#include <linux/seq_file.h>
#include <linux/amlogic/media/vfm/vframe.h>
#include "deinterlace.h"
#include "deinterlace_dbg.h"
#include "di_data_l.h"
#include "di_data.h"
#include "di_dbg.h"
#include "di_vframe.h"
#include "di_que.h"
#include "di_task.h"
#include "di_prc.h"
#include "di_post.h"
#include "nr_downscale.h"
#include "register.h"
void dpost_clear(void)/*not been called*/
{
struct di_hpst_s *pst = get_hw_pst();
memset(pst, 0, sizeof(struct di_hpst_s));
}
void dpost_init(void)
{/*reg:*/
struct di_hpst_s *pst = get_hw_pst();
pst->state = eDI_PST_ST_IDLE;
/*timer out*/
di_tout_int(&pst->tout, 40); /*ms*/
}
void pw_use_hw_post(enum eDI_SUB_ID channel, bool on)
{
struct di_hpst_s *post = get_hw_pst();
post->hw_flg_busy_post = on;
if (on)
post->curr_ch = channel;
}
static bool pw_try_sw_ch_next_post(enum eDI_SUB_ID channel)
{
bool ret = false;
struct di_hpst_s *post = get_hw_pst();
enum eDI_SUB_ID lst_ch, nch;
lst_ch = channel;
nch = pw_ch_next_count(lst_ch);
if (!get_reg_flag(nch) || get_flag_trig_unreg(nch))
return false;
if (nch != channel)
dim_ddbg_mod_save(eDI_DBG_MOD_POST_CH_CHG, nch, 0);/*dbg*/
post->curr_ch = nch;
post->hw_flg_busy_post = true;
ret = true;
/*dim_print("%s:%d->%d:%d\n", __func__, lst_ch, nch, ret);*/
return ret;
}
/*****************************/
/* debug */
/*****************************/
/*****************************/
/* STEP */
/*****************************/
bool dpst_step_idle(void)
{
struct di_hpst_s *pst = get_hw_pst();
bool reflesh = false;
if (!pw_try_sw_ch_next_post(pst->curr_ch))
return false;
pst->pres = get_pre_stru(pst->curr_ch);
pst->psts = get_post_stru(pst->curr_ch);
pst->state++;/*tmp*/
reflesh = true;
return reflesh;
}
bool dpst_step_check(void)
{
struct di_hpst_s *pst = get_hw_pst();
unsigned int ch;
struct di_post_stru_s *ppost;
bool reflesh = false;
ch = pst->curr_ch;
ppost = get_post_stru(ch);
if (queue_empty(ch, QUEUE_POST_DOING)) {
ppost->post_peek_underflow++;
pst->state--;
return reflesh;
}
pst->state++;
reflesh = true;
return reflesh;
}
bool dpst_step_set(void)
{
struct di_buf_s *di_buf = NULL;
vframe_t *vf_p = NULL;
struct di_post_stru_s *ppost;
struct di_hpst_s *pst = get_hw_pst();
unsigned int ch;
bool reflesh = false;
ulong flags = 0;
ch = pst->curr_ch;
ppost = get_post_stru(ch);
di_buf = get_di_buf_head(ch, QUEUE_POST_DOING);
if (dim_check_di_buf(di_buf, 20, ch)) {
PR_ERR("%s:err1\n", __func__);
return reflesh;
}
vf_p = di_buf->vframe;
if (ppost->run_early_proc_fun_flag) {
if (vf_p->early_process_fun)
vf_p->early_process_fun = dim_do_post_wr_fun;
}
dim_print("%s:pr_index=%d\n", __func__, di_buf->process_fun_index);
if (di_buf->process_fun_index) { /*not bypass?*/
ppost->post_wr_cnt++;
spin_lock_irqsave(&plist_lock, flags);
dim_post_process(di_buf, 0, vf_p->width - 1,
0, vf_p->height - 1, vf_p);
spin_unlock_irqrestore(&plist_lock, flags);
/*begin to count timer*/
di_tout_contr(eDI_TOUT_CONTR_EN, &pst->tout);
ppost->post_de_busy = 1;
ppost->irq_time = cur_to_msecs();
/*state*/
pst->state++;
/*reflesh = true;*/
} else {
ppost->de_post_process_done = 1; /*trig done*/
pst->flg_int_done = 1;
/*state*/
pst->state++;/*pst->state = eDI_PST_ST_DONE;*/
reflesh = true;
}
ppost->cur_post_buf = di_buf;
return reflesh;
}
bool dpst_step_wait_int(void)
{
struct di_hpst_s *pst = get_hw_pst();
unsigned int ch;
struct di_post_stru_s *ppost;
bool reflesh = false;
ulong flags = 0;
ch = pst->curr_ch;
dim_print("%s:ch[%d],done_flg[%d]\n", __func__,
pst->curr_ch, pst->flg_int_done);
if (pst->flg_int_done) {
/*finish to count timer*/
di_tout_contr(eDI_TOUT_CONTR_FINISH, &pst->tout);
spin_lock_irqsave(&plist_lock, flags);
dim_post_de_done_buf_config(ch);
spin_unlock_irqrestore(&plist_lock, flags);
pst->flg_int_done = false;
/*state*/
pst->state = eDI_PST_ST_IDLE;
reflesh = true;
} else {
/*check if timeout:*/
if (di_tout_contr(eDI_TOUT_CONTR_CHECK, &pst->tout)) {
ppost = get_post_stru(ch);
PR_WARN("ch[%d]:post timeout[%d]\n", ch,
ppost->cur_post_buf->seq);
dim_ddbg_mod_save(eDI_DBG_MOD_POST_TIMEOUT, ch, 0);
/*state*/
pst->state = eDI_PST_ST_TIMEOUT;
reflesh = true;
}
}
return reflesh;
}
void dpst_timeout(unsigned int ch)
{
hpst_dbg_mem_pd_trig(0);
post_close_new();
#if 0
di_post_set_flow(1, eDI_POST_FLOW_STEP1_STOP);
di_post_reset();
#endif
dimh_pst_trig_resize();
}
bool dpst_step_timeout(void)
{
struct di_hpst_s *pst = get_hw_pst();
unsigned int ch;
bool reflesh = false;
ulong flags = 0;
ch = pst->curr_ch;
dpst_timeout(ch);
spin_lock_irqsave(&plist_lock, flags);
dim_post_de_done_buf_config(ch);
spin_unlock_irqrestore(&plist_lock, flags);
pst->flg_int_done = false;
/*state*/
pst->state = eDI_PST_ST_IDLE;
reflesh = true;
return reflesh;
}
bool dpst_step_done(void)/*this step no use ?*/
{
struct di_hpst_s *pst = get_hw_pst();
unsigned int ch;
bool reflesh = false;
ch = pst->curr_ch;
/* dim_post_de_done_buf_config(ch);*/
/*state*/
pst->state = eDI_PST_ST_IDLE;
reflesh = true;
return reflesh;
}
const struct di_func_tab_s di_pst_func_tab[] = {
{eDI_PST_ST_EXIT, NULL},
{eDI_PST_ST_IDLE, dpst_step_idle},
{eDI_PST_ST_CHECK, dpst_step_check},
{eDI_PST_ST_SET, dpst_step_set},
{eDI_PST_ST_WAIT_INT, dpst_step_wait_int},
{eDI_PST_ST_TIMEOUT, dpst_step_timeout},
{eDI_PST_ST_DONE, dpst_step_done},
};
const char * const dpst_state_name[] = {
"EXIT",
"IDLE", /*swith to next channel?*/
"CHECK",
"SET",
"WAIT_INT",
"TIMEOUT",
"DONE",
};
const char *dpst_state_name_get(enum eDI_PST_ST state)
{
if (state > eDI_PST_ST_DONE)
return "nothing";
return dpst_state_name[state];
}
bool dpst_can_exit(unsigned int ch)
{
struct di_hpst_s *pst = get_hw_pst();
bool ret = false;
if (ch != pst->curr_ch) {
ret = true;
} else {
if (pst->state <= eDI_PST_ST_IDLE)
ret = true;
}
pr_info("%s:ch[%d]:curr[%d]:stat[%s] ret[%d]\n",
__func__,
ch, pst->curr_ch,
dpst_state_name_get(pst->state),
ret);
return ret;
}
static bool dpst_process_step2(void)
{
struct di_hpst_s *pst = get_hw_pst();
enum eDI_PST_ST pst_st = pst->state;
unsigned int ch;
ch = pst->curr_ch;
if (pst_st > eDI_PST_ST_EXIT)
dim_recycle_post_back(ch);
if ((pst_st <= eDI_PST_ST_DONE) &&
di_pst_func_tab[pst_st].func)
return di_pst_func_tab[pst_st].func();
else
return false;
}
void dpst_dbg_f_trig(unsigned int cmd)
{
struct di_task *tsk = get_task();
struct di_hpst_s *pst = get_hw_pst();
if (down_interruptible(&tsk->sem)) {
PR_ERR("%s:can't get sem\n", __func__);
return;
}
/*set on/off and trig*/
if (cmd & 0x10) {
pst->dbg_f_en = 1;
pst->dbg_f_cnt = cmd & 0xf;
pst->dbg_f_lstate = pst->state;
} else {
pst->dbg_f_en = 0;
}
up(&tsk->sem);
}
void dpst_process(void)
{
bool reflesh;
struct di_hpst_s *pst = get_hw_pst();
if (pst->dbg_f_en) {
if (pst->dbg_f_cnt) {
dpst_process_step2();
pst->dbg_f_cnt--;
}
if (pst->dbg_f_lstate != pst->state) {
pr_info("ch[%d]:state:%s->%s\n",
pst->curr_ch,
dpst_state_name_get(pst->dbg_f_lstate),
dpst_state_name_get(pst->state));
pst->dbg_f_lstate = pst->state;
}
return;
}
reflesh = true;
while (reflesh)
reflesh = dpst_process_step2();
}

View File

@@ -0,0 +1,27 @@
/*
* drivers/amlogic/media/di_multi/di_post.h
*
* Copyright (C) 2017 Amlogic, Inc. 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
*/
#ifndef __DI_POST_H__
#define __DI_POST_H__
void dpost_init(void);
void dpst_process(void);
const char *dpst_state_name_get(enum eDI_PST_ST state);
void dpst_dbg_f_trig(unsigned int cmd);
bool dpst_can_exit(unsigned int ch);
#endif /*__DI_POST_H__*/

View File

@@ -0,0 +1,628 @@
/*
* drivers/amlogic/media/di_multi/di_pps.c
*
* Copyright (C) 2017 Amlogic, Inc. 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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/kernel.h>
#include <linux/err.h>
#include <linux/amlogic/media/registers/regs/di_regs.h>
#include <linux/amlogic/media/vfm/vframe.h>
#include "di_pps.h"
#include "register.h"
#include <linux/seq_file.h>
#if 0
/* pps filter coefficients */
#define COEF_BICUBIC 0
#define COEF_3POINT_TRIANGLE 1
#define COEF_4POINT_TRIANGLE 2
#define COEF_BILINEAR 3
#define COEF_2POINT_BILINEAR 4
#define COEF_BICUBIC_SHARP 5
#define COEF_3POINT_TRIANGLE_SHARP 6
#define COEF_3POINT_BSPLINE 7
#define COEF_4POINT_BSPLINE 8
#define COEF_3D_FILTER 9
#define COEF_NULL 0xff
#define TOTAL_FILTERS 10
#define MAX_NONLINEAR_FACTOR 0x40
const u32 vpp_filter_coefs_bicubic_sharp[] = {
3,
33 | 0x8000,
/* 0x01f80090, 0x01f80100, 0xff7f0200, 0xfe7f0300, */
0x01fa008c, 0x01fa0100, 0xff7f0200, 0xfe7f0300,
0xfd7e0500, 0xfc7e0600, 0xfb7d0800, 0xfb7c0900,
0xfa7b0b00, 0xfa7a0dff, 0xf9790fff, 0xf97711ff,
0xf87613ff, 0xf87416fe, 0xf87218fe, 0xf8701afe,
0xf76f1dfd, 0xf76d1ffd, 0xf76b21fd, 0xf76824fd,
0xf76627fc, 0xf76429fc, 0xf7612cfc, 0xf75f2ffb,
0xf75d31fb, 0xf75a34fb, 0xf75837fa, 0xf7553afa,
0xf8523cfa, 0xf8503ff9, 0xf84d42f9, 0xf84a45f9,
0xf84848f8
};
const u32 vpp_filter_coefs_bicubic[] = {
4,
33,
0x00800000, 0x007f0100, 0xff7f0200, 0xfe7f0300,
0xfd7e0500, 0xfc7e0600, 0xfb7d0800, 0xfb7c0900,
0xfa7b0b00, 0xfa7a0dff, 0xf9790fff, 0xf97711ff,
0xf87613ff, 0xf87416fe, 0xf87218fe, 0xf8701afe,
0xf76f1dfd, 0xf76d1ffd, 0xf76b21fd, 0xf76824fd,
0xf76627fc, 0xf76429fc, 0xf7612cfc, 0xf75f2ffb,
0xf75d31fb, 0xf75a34fb, 0xf75837fa, 0xf7553afa,
0xf8523cfa, 0xf8503ff9, 0xf84d42f9, 0xf84a45f9,
0xf84848f8
};
const u32 vpp_filter_coefs_bilinear[] = {
4,
33,
0x00800000, 0x007e0200, 0x007c0400, 0x007a0600,
0x00780800, 0x00760a00, 0x00740c00, 0x00720e00,
0x00701000, 0x006e1200, 0x006c1400, 0x006a1600,
0x00681800, 0x00661a00, 0x00641c00, 0x00621e00,
0x00602000, 0x005e2200, 0x005c2400, 0x005a2600,
0x00582800, 0x00562a00, 0x00542c00, 0x00522e00,
0x00503000, 0x004e3200, 0x004c3400, 0x004a3600,
0x00483800, 0x00463a00, 0x00443c00, 0x00423e00,
0x00404000
};
const u32 vpp_3d_filter_coefs_bilinear[] = {
2,
33,
0x80000000, 0x7e020000, 0x7c040000, 0x7a060000,
0x78080000, 0x760a0000, 0x740c0000, 0x720e0000,
0x70100000, 0x6e120000, 0x6c140000, 0x6a160000,
0x68180000, 0x661a0000, 0x641c0000, 0x621e0000,
0x60200000, 0x5e220000, 0x5c240000, 0x5a260000,
0x58280000, 0x562a0000, 0x542c0000, 0x522e0000,
0x50300000, 0x4e320000, 0x4c340000, 0x4a360000,
0x48380000, 0x463a0000, 0x443c0000, 0x423e0000,
0x40400000
};
const u32 vpp_filter_coefs_3point_triangle[] = {
3,
33,
0x40400000, 0x3f400100, 0x3d410200, 0x3c410300,
0x3a420400, 0x39420500, 0x37430600, 0x36430700,
0x35430800, 0x33450800, 0x32450900, 0x31450a00,
0x30450b00, 0x2e460c00, 0x2d460d00, 0x2c470d00,
0x2b470e00, 0x29480f00, 0x28481000, 0x27481100,
0x26491100, 0x25491200, 0x24491300, 0x234a1300,
0x224a1400, 0x214a1500, 0x204a1600, 0x1f4b1600,
0x1e4b1700, 0x1d4b1800, 0x1c4c1800, 0x1b4c1900,
0x1a4c1a00
};
/* point_num =4, filt_len =4, group_num = 64, [1 2 1] */
const u32 vpp_filter_coefs_4point_triangle[] = {
4,
33,
0x20402000, 0x20402000, 0x1f3f2101, 0x1f3f2101,
0x1e3e2202, 0x1e3e2202, 0x1d3d2303, 0x1d3d2303,
0x1c3c2404, 0x1c3c2404, 0x1b3b2505, 0x1b3b2505,
0x1a3a2606, 0x1a3a2606, 0x19392707, 0x19392707,
0x18382808, 0x18382808, 0x17372909, 0x17372909,
0x16362a0a, 0x16362a0a, 0x15352b0b, 0x15352b0b,
0x14342c0c, 0x14342c0c, 0x13332d0d, 0x13332d0d,
0x12322e0e, 0x12322e0e, 0x11312f0f, 0x11312f0f,
0x10303010
};
/*
*4th order (cubic) b-spline
*filt_cubic point_num =4, filt_len =4, group_num = 64, [1 5 1]
*/
const u32 vpp_filter_coefs_4point_bspline[] = {
4,
33,
0x15561500, 0x14561600, 0x13561700, 0x12561800,
0x11551a00, 0x11541b00, 0x10541c00, 0x0f541d00,
0x0f531e00, 0x0e531f00, 0x0d522100, 0x0c522200,
0x0b522300, 0x0b512400, 0x0a502600, 0x0a4f2700,
0x094e2900, 0x084e2a00, 0x084d2b00, 0x074c2c01,
0x074b2d01, 0x064a2f01, 0x06493001, 0x05483201,
0x05473301, 0x05463401, 0x04453601, 0x04433702,
0x04423802, 0x03413a02, 0x03403b02, 0x033f3c02,
0x033d3d03
};
/*3rd order (quadratic) b-spline*/
/*filt_quadratic, point_num =3, filt_len =3, group_num = 64, [1 6 1] */
const u32 vpp_filter_coefs_3point_bspline[] = {
3,
33,
0x40400000, 0x3e420000, 0x3c440000, 0x3a460000,
0x38480000, 0x364a0000, 0x344b0100, 0x334c0100,
0x314e0100, 0x304f0100, 0x2e500200, 0x2c520200,
0x2a540200, 0x29540300, 0x27560300, 0x26570300,
0x24580400, 0x23590400, 0x215a0500, 0x205b0500,
0x1e5c0600, 0x1d5c0700, 0x1c5d0700, 0x1a5e0800,
0x195e0900, 0x185e0a00, 0x175f0a00, 0x15600b00,
0x14600c00, 0x13600d00, 0x12600e00, 0x11600f00,
0x10601000
};
/*filt_triangle, point_num =3, filt_len =2.6, group_num = 64, [1 7 1] */
const u32 vpp_filter_coefs_3point_triangle_sharp[] = {
3,
33,
0x40400000, 0x3e420000, 0x3d430000, 0x3b450000,
0x3a460000, 0x38480000, 0x37490000, 0x354b0000,
0x344c0000, 0x324e0000, 0x314f0000, 0x2f510000,
0x2e520000, 0x2c540000, 0x2b550000, 0x29570000,
0x28580000, 0x265a0000, 0x245c0000, 0x235d0000,
0x215f0000, 0x20600000, 0x1e620000, 0x1d620100,
0x1b620300, 0x19630400, 0x17630600, 0x15640700,
0x14640800, 0x12640a00, 0x11640b00, 0x0f650c00,
0x0d660d00
};
const u32 vpp_filter_coefs_2point_binilear[] = {
2,
33,
0x80000000, 0x7e020000, 0x7c040000, 0x7a060000,
0x78080000, 0x760a0000, 0x740c0000, 0x720e0000,
0x70100000, 0x6e120000, 0x6c140000, 0x6a160000,
0x68180000, 0x661a0000, 0x641c0000, 0x621e0000,
0x60200000, 0x5e220000, 0x5c240000, 0x5a260000,
0x58280000, 0x562a0000, 0x542c0000, 0x522e0000,
0x50300000, 0x4e320000, 0x4c340000, 0x4a360000,
0x48380000, 0x463a0000, 0x443c0000, 0x423e0000,
0x40400000
};
static const u32 *filter_table[] = {
vpp_filter_coefs_bicubic,
vpp_filter_coefs_3point_triangle,
vpp_filter_coefs_4point_triangle,
vpp_filter_coefs_bilinear,
vpp_filter_coefs_2point_binilear,
vpp_filter_coefs_bicubic_sharp,
vpp_filter_coefs_3point_triangle_sharp,
vpp_filter_coefs_3point_bspline,
vpp_filter_coefs_4point_bspline,
vpp_3d_filter_coefs_bilinear
};
static int chroma_filter_table[] = {
COEF_BICUBIC, /* bicubic */
COEF_3POINT_TRIANGLE,
COEF_4POINT_TRIANGLE,
COEF_4POINT_TRIANGLE, /* bilinear */
COEF_2POINT_BILINEAR,
COEF_3POINT_TRIANGLE, /* bicubic_sharp */
COEF_3POINT_TRIANGLE, /* 3point_triangle_sharp */
COEF_3POINT_TRIANGLE, /* 3point_bspline */
COEF_4POINT_TRIANGLE, /* 4point_bspline */
COEF_3D_FILTER /* can not change */
};
static unsigned int vert_scaler_filter = 0xff;
module_param(vert_scaler_filter, uint, 0664);
MODULE_PARM_DESC(vert_scaler_filter, "vert_scaler_filter");
static unsigned int vert_chroma_scaler_filter = 0xff;
module_param(vert_chroma_scaler_filter, uint, 0664);
MODULE_PARM_DESC(vert_chroma_scaler_filter, "vert_chroma_scaler_filter");
static unsigned int horz_scaler_filter = 0xff;
module_param(horz_scaler_filter, uint, 0664);
MODULE_PARM_DESC(horz_scaler_filter, "horz_scaler_filter");
bool pre_scaler_en = true;
module_param(pre_scaler_en, bool, 0664);
MODULE_PARM_DESC(pre_scaler_en, "pre_scaler_en");
#endif
/*bicubic*/
static const unsigned int di_filt_coef0[] = {
0x00800000,
0x007f0100,
0xff7f0200,
0xfe7f0300,
0xfd7e0500,
0xfc7e0600,
0xfb7d0800,
0xfb7c0900,
0xfa7b0b00,
0xfa7a0dff,
0xf9790fff,
0xf97711ff,
0xf87613ff,
0xf87416fe,
0xf87218fe,
0xf8701afe,
0xf76f1dfd,
0xf76d1ffd,
0xf76b21fd,
0xf76824fd,
0xf76627fc,
0xf76429fc,
0xf7612cfc,
0xf75f2ffb,
0xf75d31fb,
0xf75a34fb,
0xf75837fa,
0xf7553afa,
0xf8523cfa,
0xf8503ff9,
0xf84d42f9,
0xf84a45f9,
0xf84848f8
};
/* 2 point bilinear */
static const unsigned int di_filt_coef1[] = {
0x00800000,
0x007e0200,
0x007c0400,
0x007a0600,
0x00780800,
0x00760a00,
0x00740c00,
0x00720e00,
0x00701000,
0x006e1200,
0x006c1400,
0x006a1600,
0x00681800,
0x00661a00,
0x00641c00,
0x00621e00,
0x00602000,
0x005e2200,
0x005c2400,
0x005a2600,
0x00582800,
0x00562a00,
0x00542c00,
0x00522e00,
0x00503000,
0x004e3200,
0x004c3400,
0x004a3600,
0x00483800,
0x00463a00,
0x00443c00,
0x00423e00,
0x00404000
};
/* 2 point bilinear, bank_length == 2*/
static const unsigned int di_filt_coef2[] = {
0x80000000,
0x7e020000,
0x7c040000,
0x7a060000,
0x78080000,
0x760a0000,
0x740c0000,
0x720e0000,
0x70100000,
0x6e120000,
0x6c140000,
0x6a160000,
0x68180000,
0x661a0000,
0x641c0000,
0x621e0000,
0x60200000,
0x5e220000,
0x5c240000,
0x5a260000,
0x58280000,
0x562a0000,
0x542c0000,
0x522e0000,
0x50300000,
0x4e320000,
0x4c340000,
0x4a360000,
0x48380000,
0x463a0000,
0x443c0000,
0x423e0000,
0x40400000
};
#define ZOOM_BITS 20
#define PHASE_BITS 16
static enum f2v_vphase_type_e top_conv_type = F2V_P2P;
static enum f2v_vphase_type_e bot_conv_type = F2V_P2P;
static unsigned int prehsc_en;
static unsigned int prevsc_en;
static const unsigned char f2v_420_in_pos_luma[F2V_TYPE_MAX] = {
0, 2, 0, 2, 0, 0, 0, 2, 0};
#if 0
static const unsigned char f2v_420_in_pos_chroma[F2V_TYPE_MAX] = {
1, 5, 1, 5, 2, 2, 1, 5, 2};
#endif
static const unsigned char f2v_420_out_pos[F2V_TYPE_MAX] = {
0, 2, 2, 0, 0, 2, 0, 0, 0};
static void f2v_get_vertical_phase(unsigned int zoom_ratio,
enum f2v_vphase_type_e type,
unsigned char bank_length,
struct pps_f2v_vphase_s *vphase)
{
int offset_in, offset_out;
/* luma */
offset_in = f2v_420_in_pos_luma[type] << PHASE_BITS;
offset_out = (f2v_420_out_pos[type] * zoom_ratio)
>> (ZOOM_BITS - PHASE_BITS);
vphase->rcv_num = bank_length;
if (bank_length == 4 || bank_length == 3)
vphase->rpt_num = 1;
else
vphase->rpt_num = 0;
if (offset_in > offset_out) {
vphase->rpt_num = vphase->rpt_num + 1;
vphase->phase =
((4 << PHASE_BITS) + offset_out - offset_in) >> 2;
} else {
while ((offset_in + (4 << PHASE_BITS)) <= offset_out) {
if (vphase->rpt_num == 1)
vphase->rpt_num = 0;
else
vphase->rcv_num++;
offset_in += 4 << PHASE_BITS;
}
vphase->phase = (offset_out - offset_in) >> 2;
}
}
/*
* patch 1: inp scaler 0: di wr scaler
* support: TM2
* not support: SM1
*/
void dim_pps_config(unsigned char path, int src_w, int src_h,
int dst_w, int dst_h)
{
struct pps_f2v_vphase_s vphase;
int i;
int hsc_en = 0, vsc_en = 0;
int vsc_double_line_mode;
unsigned int p_src_w, p_src_h;
unsigned int vert_phase_step, horz_phase_step;
unsigned char top_rcv_num, bot_rcv_num;
unsigned char top_rpt_num, bot_rpt_num;
unsigned short top_vphase, bot_vphase;
unsigned char is_frame;
int vert_bank_length = 4;
const unsigned int *filt_coef0 = di_filt_coef0;
/*unsigned int *filt_coef1 = di_filt_coef1;*/
const unsigned int *filt_coef2 = di_filt_coef2;
vsc_double_line_mode = 0;
if (src_h != dst_h)
vsc_en = 1;
if (src_w != dst_w)
hsc_en = 1;
/* config hdr size */
Wr_reg_bits(DI_HDR_IN_HSIZE, dst_w, 0, 13);
Wr_reg_bits(DI_HDR_IN_VSIZE, dst_h, 0, 13);
p_src_w = (prehsc_en ? ((src_w + 1) >> 1) : src_w);
p_src_h = prevsc_en ? ((src_h + 1) >> 1) : src_h;
Wr(DI_SC_HOLD_LINE, 0x10);
if (p_src_w > 2048) {
/*force vert bank length = 2*/
vert_bank_length = 2;
vsc_double_line_mode = 1;
}
/*write vert filter coefs*/
Wr(DI_SC_COEF_IDX, 0x0000);
for (i = 0; i < 33; i++) {
if (vert_bank_length == 2)
Wr(DI_SC_COEF, filt_coef2[i]); /*bilinear*/
else
Wr(DI_SC_COEF, filt_coef0[i]); /*bicubic*/
}
/*write horz filter coefs*/
Wr(DI_SC_COEF_IDX, 0x0100);
for (i = 0; i < 33; i++)
Wr(DI_SC_COEF, filt_coef0[i]); /*bicubic*/
if (p_src_h > 2048)
vert_phase_step = ((p_src_h << 18) / dst_h) << 2;
else
vert_phase_step = (p_src_h << 20) / dst_h;
if (p_src_w > 2048)
horz_phase_step = ((p_src_w << 18) / dst_w) << 2;
else
horz_phase_step = (p_src_w << 20) / dst_w;
is_frame = ((top_conv_type == F2V_IT2P) ||
(top_conv_type == F2V_IB2P) ||
(top_conv_type == F2V_P2P));
if (is_frame) {
f2v_get_vertical_phase(vert_phase_step, top_conv_type,
vert_bank_length, &vphase);
top_rcv_num = vphase.rcv_num;
top_rpt_num = vphase.rpt_num;
top_vphase = vphase.phase;
bot_rcv_num = 0;
bot_rpt_num = 0;
bot_vphase = 0;
} else {
f2v_get_vertical_phase(vert_phase_step, top_conv_type,
vert_bank_length, &vphase);
top_rcv_num = vphase.rcv_num;
top_rpt_num = vphase.rpt_num;
top_vphase = vphase.phase;
f2v_get_vertical_phase(vert_phase_step, bot_conv_type,
vert_bank_length, &vphase);
bot_rcv_num = vphase.rcv_num;
bot_rpt_num = vphase.rpt_num;
bot_vphase = vphase.phase;
}
vert_phase_step = (vert_phase_step << 4);
horz_phase_step = (horz_phase_step << 4);
Wr(DI_SC_LINE_IN_LENGTH, src_w);
Wr(DI_SC_PIC_IN_HEIGHT, src_h);
Wr(DI_VSC_REGION12_STARTP, 0);
Wr(DI_VSC_REGION34_STARTP, ((dst_h << 16) | dst_h));
Wr(DI_VSC_REGION4_ENDP, (dst_h - 1));
Wr(DI_VSC_START_PHASE_STEP, vert_phase_step);
Wr(DI_VSC_REGION0_PHASE_SLOPE, 0);
Wr(DI_VSC_REGION1_PHASE_SLOPE, 0);
Wr(DI_VSC_REGION3_PHASE_SLOPE, 0);
Wr(DI_VSC_REGION4_PHASE_SLOPE, 0);
Wr(DI_VSC_PHASE_CTRL,
((vsc_double_line_mode << 17) |
(!is_frame) << 16) |
(0 << 15) |
(bot_rpt_num << 13) |
(bot_rcv_num << 8) |
(0 << 7) |
(top_rpt_num << 5) |
(top_rcv_num));
Wr(DI_VSC_INI_PHASE, (bot_vphase << 16) | top_vphase);
Wr(DI_HSC_REGION12_STARTP, 0);
Wr(DI_HSC_REGION34_STARTP, (dst_w << 16) | dst_w);
Wr(DI_HSC_REGION4_ENDP, dst_w - 1);
Wr(DI_HSC_START_PHASE_STEP, horz_phase_step);
Wr(DI_HSC_REGION0_PHASE_SLOPE, 0);
Wr(DI_HSC_REGION1_PHASE_SLOPE, 0);
Wr(DI_HSC_REGION3_PHASE_SLOPE, 0);
Wr(DI_HSC_REGION4_PHASE_SLOPE, 0);
Wr(DI_HSC_PHASE_CTRL, (1 << 21) | (4 << 16) | 0);
Wr_reg_bits(DI_SC_TOP_CTRL, (path ? 3 : 0), 29, 2);
Wr(DI_SC_MISC,
(prevsc_en << 21) |
(prehsc_en << 20) | /* prehsc_en */
(prevsc_en << 19) | /* prevsc_en */
(vsc_en << 18) | /* vsc_en */
(hsc_en << 17) | /* hsc_en */
((vsc_en | hsc_en) << 16) | /* sc_top_en */
(1 << 15) | /* vd1 sc out enable */
(0 << 12) | /* horz nonlinear 4region enable */
(4 << 8) | /* horz scaler bank length */
(0 << 5) | /* vert scaler phase field enable */
(0 << 4) | /* vert nonlinear 4region enable */
(vert_bank_length << 0) /* vert scaler bank length */
);
pr_info("[pps] %s input %d %d output %d %d.\n",
path ? "pre" : "post", src_w, src_h, dst_w, dst_h);
}
/*
* 0x374e ~ 0x376d, 20 regs
*/
void dim_dump_pps_reg(unsigned int base_addr)
{
unsigned int i = 0x374e;
pr_info("-----dump pps start-----\n");
for (i = 0x374e; i < 0x376e; i++) {
pr_info("[0x%x][0x%x]=0x%x\n",
base_addr + (i << 2),
i, dim_RDMA_RD(i));
}
pr_info("-----dump pps end-----\n");
}
/*
* di pre h scaling down function
* only have h scaling down
* support: sm1 tm2 ...
* 0x37b0 ~ 0x37b5
*/
void dim_inp_hsc_setting(u32 src_w, u32 dst_w)
{
u32 i;
u32 hsc_en;
u32 horz_phase_step;
const int *filt_coef0 = di_filt_coef0;
/*int *filt_coef1 = di_filt_coef1;*/
/*int *filt_coef2 = di_filt_coef2;*/
if (src_w == dst_w) {
hsc_en = 0;
} else {
hsc_en = 1;
/*write horz filter coefs*/
dim_RDMA_WR(DI_VIU_HSC_COEF_IDX, 0x0100);
for (i = 0; i < 33; i++) /*bicubic*/
dim_RDMA_WR(DI_VIU_HSC_COEF, filt_coef0[i]);
horz_phase_step = (src_w << 20) / dst_w;
horz_phase_step = (horz_phase_step << 4);
dim_RDMA_WR(DI_VIU_HSC_WIDTHM1,
(src_w - 1) << 16 | (dst_w - 1));
dim_RDMA_WR(DI_VIU_HSC_PHASE_STEP, horz_phase_step);
dim_RDMA_WR(DI_VIU_HSC_PHASE_CTRL, 0);
}
dim_RDMA_WR(DI_VIU_HSC_CTRL,
(4 << 20) | /* initial receive number*/
(0 << 12) | /* initial pixel ptr*/
(1 << 10) | /* repeat first pixel number*/
(0 << 8) | /* sp422 mode*/
(4 << 4) | /* horz scaler bank length*/
(0 << 2) | /* phase0 always en*/
(0 << 1) | /* nearest_en*/
(hsc_en << 0)); /* hsc_en*/
}
/*
* 0x37b0 ~ 0x37b5
*/
void dim_dump_hdownscler_reg(unsigned int base_addr)
{
unsigned int i = 0x374e;
pr_info("-----dump hdownscler start-----\n");
for (i = 0x37b0; i < 0x37b5; i++) {
pr_info("[0x%x][0x%x]=0x%x\n",
base_addr + (i << 2),
i, dim_RDMA_RD(i));
}
pr_info("-----dump hdownscler end-----\n");
}
int dim_seq_file_module_para_pps(struct seq_file *seq)
{
seq_puts(seq, "pps---------------\n");
return 0;
}

View File

@@ -0,0 +1,112 @@
/*
* drivers/amlogic/media/di_multi/di_pps.h
*
* Copyright (C) 2017 Amlogic, Inc. 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
*/
#ifndef DI_PPS_H
#define DI_PPS_H
#include <linux/amlogic/media/video_sink/video.h>
#include <linux/amlogic/media/video_sink/vpp.h>
#if 0
#define VPP_FLAG_WIDEMODE_MASK 0x0000000F
#define VPP_FLAG_INTERLACE_OUT 0x00000010
#define VPP_FLAG_INTERLACE_IN 0x00000020
#define VPP_FLAG_CBCR_SEPARATE 0x00000040
#define VPP_FLAG_ZOOM_SHORTSIDE 0x00000080
#define VPP_FLAG_AR_MASK 0x0003ff00
#define VPP_FLAG_AR_BITS 8
#define VPP_FLAG_PORTRAIT_MODE 0x00040000
#define VPP_FLAG_VSCALE_DISABLE 0x00080000
#define IDX_H (2 << 8)
#define IDX_V_Y (1 << 13)
#define IDX_V_CBCR ((1 << 13) | (1 << 8))
#define ASPECT_4_3 ((3 << 8) / 4)
#define ASPECT_16_9 ((9 << 8) / 16)
#define SPEED_CHECK_DONE 0
#define SPEED_CHECK_HSKIP 1
#define SPEED_CHECK_VSKIP 2
enum f2v_vphase_type_e {
F2V_IT2IT = 0,
F2V_IB2IB,
F2V_IT2IB,
F2V_IB2IT,
F2V_P2IT,
F2V_P2IB,
F2V_IT2P,
F2V_IB2P,
F2V_P2P,
F2V_TYPE_MAX
}; /* frame to video conversion type */
#endif
enum hdr2_scaler_e {
hdr2_scaler_postdi = 0,
hdr2_scaler_predi = 1,
};
struct pps_f2v_vphase_s {
unsigned char rcv_num;
unsigned char rpt_num;
unsigned short phase;
};
struct ppsfilter_mode_s {
u32 pps_hf_start_phase_step;
u32 pps_hf_start_phase_slope;
u32 pps_hf_end_phase_slope;
const u32 *pps_vert_coeff;
const u32 *pps_horz_coeff;
u32 pps_sc_misc_;
u32 pps_vsc_start_phase_step;
u32 pps_hsc_start_phase_step;
bool pps_pre_vsc_en;
bool pps_pre_hsc_en;
u32 pps_vert_filter;
u32 pps_horz_filter;
const u32 *pps_chroma_coeff;
u32 pps_chroma_filter_en;
};
struct pps_frame_par_s {
u32 pps_vsc_startp;
u32 pps_vsc_endp;
u32 pps_hsc_startp;
u32 pps_hsc_linear_startp;
u32 pps_hsc_linear_endp;
u32 pps_hsc_endp;
u32 VPP_hf_ini_phase_;
struct f2v_vphase_s VPP_vf_ini_phase_[9];
u32 pps_pic_in_height_;
u32 pps_line_in_length_;
struct ppsfilter_mode_s pps_filter;
u32 pps_3d_mode;
u32 trans_fmt;
/* bit[1:0] 0: 1 pic,1:two pic one buf,2:tow pic two buf */
/* bit[2]0:select pic0,1:select pic1 */
/* bit[3]0:pic0 first,1:pic1 first */
bool pps_3d_scale;
};
void dim_pps_config(unsigned char path, int src_w, int src_h,
int dst_w, int dst_h);
void dim_dump_pps_reg(unsigned int base_addr);
void dim_inp_hsc_setting(u32 src_w, u32 dst_w);
void dim_dump_hdownscler_reg(unsigned int base_addr);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,131 @@
/*
* drivers/amlogic/media/di_multi/di_prc.h
*
* Copyright (C) 2017 Amlogic, Inc. 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
*/
#ifndef __DI_PRC_H__
#define __DI_PRC_H__
bool dip_prob(void);
void dip_exit(void);
void dip_even_reg_init_val(unsigned int ch);
void dip_even_unreg_val(unsigned int ch);
/************************/
/* CMA */
/************************/
void dip_wq_cma_run(unsigned char ch, bool reg_cmd);
bool dip_cma_st_is_ready(unsigned int ch);
bool dip_cma_st_is_idle(unsigned int ch);
bool dip_cma_st_is_idl_all(void);
enum eDI_CMA_ST dip_cma_get_st(unsigned int ch);
void dip_cma_st_set_ready_all(void);
void dip_cma_close(void);
const char *di_cma_dbg_get_st_name(unsigned int ch);
/*************************/
/* STATE*/
/*************************/
bool dip_event_reg_chst(unsigned int ch);
bool dip_event_unreg_chst(unsigned int ch);
void dip_chst_process_reg(unsigned int ch);
void dip_hw_process(void);
void dip_chst_process_ch(void);
bool dip_chst_change_2unreg(void);
enum eDI_TOP_STATE dip_chst_get(unsigned int ch);
const char *dip_chst_get_name_curr(unsigned int ch);
const char *dip_chst_get_name(enum eDI_TOP_STATE chst);
/**************************************
*
* summmary variable
*
**************************************/
void di_sum_reg_init(unsigned int ch);
void di_sum_set(unsigned int ch, enum eDI_SUM id, unsigned int val);
unsigned int di_sum_inc(unsigned int ch, enum eDI_SUM id);
unsigned int di_sum_get(unsigned int ch, enum eDI_SUM id);
void di_sum_get_info(unsigned int ch, enum eDI_SUM id, char **name,
unsigned int *pval);
unsigned int di_sum_get_tab_size(void);
bool di_sum_check(unsigned int ch, enum eDI_SUM id);
/**************************************
*
* cfg ctr top
* bool
**************************************/
char *di_cfg_top_get_name(enum eDI_CFG_TOP_IDX idx);
void di_cfg_top_get_info(unsigned int idx, char **name);
void di_cfg_top_init_val(void);
bool di_cfg_top_get(enum eDI_CFG_TOP_IDX id);
void di_cfg_top_set(enum eDI_CFG_TOP_IDX id, bool en);
/**************************************
*
* cfg ctr x
* bool
**************************************/
char *di_cfgx_get_name(enum eDI_CFGX_IDX idx);
void di_cfgx_get_info(enum eDI_CFGX_IDX idx, char **name);
void di_cfgx_init_val(void);
bool di_cfgx_get(unsigned int ch, enum eDI_CFGX_IDX idx);
void di_cfgx_set(unsigned int ch, enum eDI_CFGX_IDX idx, bool en);
/**************************************
*
* module para top
* int
**************************************/
char *di_mp_uit_get_name(enum eDI_MP_UI_T idx);
void di_mp_uit_init_val(void);
int di_mp_uit_get(enum eDI_MP_UI_T idx);
void di_mp_uit_set(enum eDI_MP_UI_T idx, int val);
/**************************************
*
* module para x
* unsigned int
**************************************/
char *di_mp_uix_get_name(enum eDI_MP_UIX_T idx);
void di_mp_uix_init_val(void);
unsigned int di_mp_uix_get(unsigned int ch, enum eDI_MP_UIX_T idx);
void di_mp_uix_set(unsigned int ch, enum eDI_MP_UIX_T idx,
unsigned int val);
/****************************************/
/* do_table */
/****************************************/
void do_table_init(struct do_table_s *pdo,
const struct do_table_ops_s *ptable,
unsigned int size_tab);
/* now only call in same thread */
void do_talbe_cmd(struct do_table_s *pdo, enum eDO_TABLE_CMD cmd);
void do_table_working(struct do_table_s *pdo);
bool do_table_is_crr(struct do_table_s *pdo, unsigned int state);
enum eDI_SUB_ID pw_ch_next_count(enum eDI_SUB_ID channel);
void dip_init_value_reg(unsigned int ch);
bool di_is_pause(unsigned int ch);
void di_pause_step_done(unsigned int ch);
void di_pause(unsigned int ch, bool on);
#endif /*__DI_PRC_H__*/

View File

@@ -0,0 +1,985 @@
/*
* drivers/amlogic/media/di_multi/di_pre.c
*
* Copyright (C) 2017 Amlogic, Inc. 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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/kernel.h>
#include <linux/err.h>
#include <linux/seq_file.h>
#include <linux/amlogic/media/vfm/vframe.h>
#include "deinterlace.h"
#include "deinterlace_dbg.h"
#include "di_data_l.h"
#include "di_data.h"
#include "di_dbg.h"
#include "di_vframe.h"
#include "di_que.h"
#include "di_task.h"
#include "di_prc.h"
#include "di_pre.h"
#include "nr_downscale.h"
#include "register.h"
/****************************************
* 1. copy curr to last
* 2. set curr
****************************************/
void pre_vinfo_set(unsigned int ch,
struct vframe_s *ori_vframe)
{
struct di_hpre_s *pre = get_hw_pre();
struct di_vinfo_s *vc = &pre->vinf_curr;
struct di_vinfo_s *vl = &pre->vinf_lst;
memcpy(vl, vc, sizeof(struct di_vinfo_s));
vc->ch = ch;
vc->vtype = ori_vframe->type;
vc->src_type = ori_vframe->source_type;
vc->trans_fmt = ori_vframe->trans_fmt;
if (COM_ME(ori_vframe->type, VIDTYPE_COMPRESS)) {
vc->h = ori_vframe->compWidth;
vc->v = ori_vframe->compHeight;
} else {
vc->h = ori_vframe->width;
vc->v = ori_vframe->height;
}
}
/****************************************
* compare current vframe info with last
* return
* 0. no change
* 1. video format channge
* 2. scan mode channge?
****************************************/
unsigned int is_vinfo_change(unsigned int ch)
{
struct di_hpre_s *pre = get_hw_pre();
struct di_vinfo_s *vc = &pre->vinf_curr;
struct di_vinfo_s *vl = &pre->vinf_lst;
struct di_pre_stru_s *ppre = get_pre_stru(ch);
unsigned int ret = 0;
if (vc->src_type != vl->src_type ||
!COM_M(DI_VFM_T_MASK_CHANGE, vc->vtype, vl->vtype) ||
vc->v != vl->v ||
vc->h != vl->h ||
vc->trans_fmt != vl->trans_fmt) {
/* video format changed */
ret = 1;
} else if (!COM_M(VIDTYPE_VIU_FIELD, vc->vtype, vl->vtype))
/* just scan mode changed */
ret = 2;
if (ret) {
dim_print(
"%s:ch[%d]: %dth source change 2: 0x%x/%d/%d/%d=>0x%x/%d/%d/%d\n",
__func__,
ch,
/*jiffies_to_msecs(jiffies_64),*/
ppre->in_seq,
vl->vtype,
vl->h,
vl->v,
vl->src_type,
vc->vtype,
vc->h,
vc->v,
vc->src_type);
}
return ret;
}
bool dim_bypass_detect(unsigned int ch, struct vframe_s *vfm)
{
bool ret = false;
if (!vfm)
return ret;
pre_vinfo_set(ch, vfm);
if (is_vinfo_change(ch)) {
if (!is_bypass2(vfm, ch)) {
set_bypass2_complete(ch, false);
PR_INF("%s:\n", __func__);
/*task_send_ready();*/
task_send_cmd(LCMD1(eCMD_CHG, ch));
ret = true;
}
}
return ret;
}
unsigned int di_get_other_ch(unsigned int curr)
{
return curr ? 0 : 1;
}
bool is_bypass_i_p(void)
{
bool ret = false;
struct di_hpre_s *pre = get_hw_pre();
struct di_vinfo_s *vc = &pre->vinf_curr;
#if 0
struct di_vinfo_s *vl = &pre->vinf_lst;
if (vl->ch != vc->ch &&
vf_type_is_interlace(vl->vtype) &&
vf_type_is_prog(vc->vtype)) {
ret = true;
}
#else
unsigned int ch_c, ch_l;
struct di_pre_stru_s *ppre_c, *ppre_l;
if (!get_reg_flag(0) ||
!get_reg_flag(1))
return ret;
ch_c = vc->ch;
ch_l = (ch_c ? 0 : 1);
ppre_c = get_pre_stru(ch_c);
ppre_l = get_pre_stru(ch_l);
if (vf_type_is_interlace(ppre_l->cur_inp_type) &&
vf_type_is_prog(ppre_c->cur_inp_type)) {
ret = true;
dim_print("ch[%d]:bypass p\n", ch_c);
}
#endif
return ret;
}
void dpre_clear(void)
{
struct di_hpre_s *pre = get_hw_pre();
memset(pre, 0, sizeof(struct di_hpre_s));
}
void dpre_init(void)
{/*reg:*/
struct di_hpre_s *pre = get_hw_pre();
pre->pre_st = eDI_PRE_ST_IDLE;
/*timer out*/
di_tout_int(&pre->tout, 40); /*ms*/
}
void pw_use_hw_pre(enum eDI_SUB_ID channel, bool on)
{
struct di_hpre_s *pre = get_hw_pre();
pre->hw_flg_busy_pre = on;
if (on)
pre->curr_ch = channel;
}
enum eDI_SUB_ID pw_ch_next_count(enum eDI_SUB_ID channel)
{
int i;
unsigned int lch, nch;
nch = channel;
for (i = 0; i < DI_CHANNEL_NUB; i++) {
lch = channel + i + 1;
if (lch >= DI_CHANNEL_NUB)
lch -= DI_CHANNEL_NUB;
#if 0
if (pbm->sub_act_flg[lch]) {
nch = lch;
break;
}
#else
if (get_reg_flag(lch) &&
!get_flag_trig_unreg(lch) &&
!is_bypss2_complete(lch)) {
nch = lch;
break;
}
#endif
}
return nch;
}
/****************************************/
static bool pw_try_sw_ch_next_pre(enum eDI_SUB_ID channel)
{
bool ret = false;
struct di_hpre_s *pre = get_hw_pre();
enum eDI_SUB_ID lst_ch, nch;
lst_ch = channel;
nch = pw_ch_next_count(lst_ch);
if (!get_reg_flag(nch) ||
get_flag_trig_unreg(nch) ||
is_bypss2_complete(nch))
return false;
pre->curr_ch = nch;
pre->hw_flg_busy_pre = true;
ret = true;
/*dim_print("%s:%d->%d:%d\n", __func__, lst_ch, nch, ret);*/
return ret;
}
/*****************************/
/* debug */
/*****************************/
unsigned int di_dbg_pre_cnt;
void dbg_cnt_begin(void)
{
di_dbg_pre_cnt = 0x10;
}
void dbg_cnt_print(void)
{
if (di_dbg_pre_cnt < 0xf)
return;
if (di_dbg_pre_cnt > 0x10) {
di_dbg_pre_cnt++;
pr_info("di:[%d]\n", di_dbg_pre_cnt);
}
if (di_dbg_pre_cnt > 0x15)
di_dbg_pre_cnt = 0;
}
/*****************************/
/* STEP */
/*****************************/
void dpre_recyc(unsigned int ch)
{
struct di_hpre_s *pre = get_hw_pre();
pre->check_recycle_buf_cnt = 0;
while (dim_check_recycle_buf(ch) & 1) {
if (pre->check_recycle_buf_cnt++ > MAX_IN_BUF_NUM) {
di_pr_info("%s: dim_check_recycle_buf time out!!\n",
__func__);
break;
}
}
}
void dpre_vdoing(unsigned int ch)
{
struct di_post_stru_s *ppost = get_post_stru(ch);
ppost->di_post_process_cnt = 0;
while (dim_process_post_vframe(ch)) {
if (ppost->di_post_process_cnt++ >
MAX_POST_BUF_NUM) {
di_pr_info("%s: dim_process_post_vframe time out!!\n",
__func__);
break;
}
}
}
bool dpre_can_exit(unsigned int ch)
{
struct di_hpre_s *pre = get_hw_pre();
bool ret = false;
if (ch != pre->curr_ch) {
ret = true;
} else {
if (pre->pre_st <= eDI_PRE_ST4_IDLE)
ret = true;
}
pr_info("%s:ch[%d]:curr[%d]:stat[%s] ret[%d]\n",
__func__,
ch, pre->curr_ch,
dpre_state4_name_get(pre->pre_st),
ret);
return ret;
}
void dpre_dbg_f_trig(unsigned int cmd)
{
struct di_task *tsk = get_task();
struct di_hpre_s *pre = get_hw_pre();
if (down_interruptible(&tsk->sem)) {
PR_ERR("%s:can't get sem\n", __func__);
return;
}
/*set on/off and trig*/
if (cmd & 0x10) {
pre->dbg_f_en = 1;
pre->dbg_f_cnt = cmd & 0xf;
pre->dbg_f_lstate = pre->pre_st;
} else {
pre->dbg_f_en = 0;
}
up(&tsk->sem);
}
void dpre_process(void)
{
bool reflesh;
struct di_hpre_s *pre = get_hw_pre();
if (pre->dbg_f_en) {
if (pre->dbg_f_cnt) {
dpre_process_step4();
pre->dbg_f_cnt--;
}
if (pre->dbg_f_lstate != pre->pre_st) {
pr_info("ch[%d]:state:%s->%s\n",
pre->curr_ch,
dpre_state4_name_get(pre->dbg_f_lstate),
dpre_state4_name_get(pre->pre_st));
pre->dbg_f_lstate = pre->pre_st;
}
return;
}
reflesh = true;
while (reflesh) {
reflesh = dpre_process_step4();
#if 0 /*debug only*/
dbg_tsk("ch[%d]:st[%s]r[%d]\n", pre->curr_ch,
dpre_state4_name_get(pre->pre_st), reflesh);
#endif
}
}
enum eDI_PRE_MT {
eDI_PRE_MT_CHECK = K_DO_TABLE_ID_START,
eDI_PRE_MT_SET,
eDI_PRE_MT_WAIT_INT,
eDI_PRE_MT_TIME_OUT,
};
/*use do_table:*/
unsigned int dpre_mtotal_check(void *data)
{
struct di_hpre_s *pre = get_hw_pre();
unsigned int ret = K_DO_R_NOT_FINISH;
if ((pre_run_flag == DI_RUN_FLAG_RUN) ||
(pre_run_flag == DI_RUN_FLAG_STEP)) {
if (pre_run_flag == DI_RUN_FLAG_STEP)
pre_run_flag = DI_RUN_FLAG_STEP_DONE;
/*dim_print("%s:\n", __func__);*/
if (dim_pre_de_buf_config(pre->curr_ch))
ret = K_DO_R_FINISH;
else
ret = K_DO_R_JUMP(K_DO_TABLE_ID_STOP);
dim_dbg_pre_cnt(pre->curr_ch, "x");
}
return ret;
}
unsigned int dpre_mtotal_set(void *data)
{
struct di_hpre_s *pre = get_hw_pre();
ulong flags = 0;
/*dim_print("%s:\n", __func__);*/
spin_lock_irqsave(&plist_lock, flags);
dim_pre_de_process(pre->curr_ch);
spin_unlock_irqrestore(&plist_lock, flags);
/*begin to count timer*/
di_tout_contr(eDI_TOUT_CONTR_EN, &pre->tout);
return K_DO_R_FINISH;
}
enum eDI_WAIT_INT {
eDI_WAIT_INT_NEED_WAIT,
eDI_WAIT_INT_HAVE_INT,
eDI_WAIT_INT_TIME_OUT,
};
/*
*return: enum eDI_WAIT_INT
*
*/
enum eDI_WAIT_INT di_pre_wait_int(void *data)
{
struct di_hpre_s *pre = get_hw_pre();
ulong flags = 0;
struct di_pre_stru_s *ppre;
enum eDI_WAIT_INT ret = eDI_WAIT_INT_NEED_WAIT;
if (pre->flg_int_done) {
/*have INT done flg*/
/*DI_INTR_CTRL[bit 0], NRWR_done, set by
* hardware when NRWR is done,clear by write 1
* by code;[bit 1]
* MTNWR_done, set by hardware when MTNWR
* is done, clear by write 1 by code;these two
* bits have nothing to do with
* DI_INTR_CTRL[16](NRW irq mask, 0 to enable
* irq) and DI_INTR_CTRL[17]
* (MTN irq mask, 0 to enable irq).two
* interrupts are raised if both
* DI_INTR_CTRL[16] and DI_INTR_CTRL[17] are 0
*/
#if 0
data32 = Rd(DI_INTR_CTRL);
if (((data32 & 0x1) &&
((ppre->enable_mtnwr == 0) || (data32 & 0x2))) ||
(ppre->pre_de_clear_flag == 2)) {
dim_RDMA_WR(DI_INTR_CTRL, data32);
}
#endif
di_pre_wait_irq_set(false);
/*finish to count timer*/
di_tout_contr(eDI_TOUT_CONTR_FINISH, &pre->tout);
spin_lock_irqsave(&plist_lock, flags);
dim_pre_de_done_buf_config(pre->curr_ch, false);
pre->flg_int_done = 0;
dpre_recyc(pre->curr_ch);
dpre_vdoing(pre->curr_ch);
spin_unlock_irqrestore(&plist_lock, flags);
ppre = get_pre_stru(pre->curr_ch);
#if 0
if (ppre->field_count_for_cont == 1) {
usleep_range(2000, 2001);
pr_info("delay 1ms\n");
}
#endif
ret = eDI_WAIT_INT_HAVE_INT;
} else {
/*check if timeout:*/
if (di_tout_contr(eDI_TOUT_CONTR_CHECK, &pre->tout)) {
di_pre_wait_irq_set(false);
/*return K_DO_R_FINISH;*/
ret = eDI_WAIT_INT_TIME_OUT;
}
}
/*debug:*/
if (dbg_first_cnt_pre)
dbg_first_frame("ch[%d],w_int[%d]\n", pre->curr_ch, ret);
return ret;
}
unsigned int dpre_mtotal_wait_int(void *data)
{
enum eDI_WAIT_INT wret;
unsigned int ret = K_DO_R_NOT_FINISH;
wret = di_pre_wait_int(NULL);
switch (wret) {
case eDI_WAIT_INT_NEED_WAIT:
ret = K_DO_R_NOT_FINISH;
break;
case eDI_WAIT_INT_HAVE_INT:
ret = K_DO_R_JUMP(K_DO_TABLE_ID_STOP);
break;
case eDI_WAIT_INT_TIME_OUT:
ret = K_DO_R_FINISH;
break;
}
return ret;
}
void dpre_mtotal_timeout_contr(void)
{
struct di_hpre_s *pre = get_hw_pre();
/*move from di_pre_trigger_work*/
if (dimp_get(eDI_MP_di_dbg_mask) & 4)
dim_dump_mif_size_state(pre->pres, pre->psts);
dimh_enable_di_pre_mif(false, dimp_get(eDI_MP_mcpre_en));
if (di_get_dts_nrds_en())
dim_nr_ds_hw_ctrl(false);
pre->pres->pre_de_irq_timeout_count++;
pre->pres->pre_de_busy = 0;
pre->pres->pre_de_clear_flag = 2;
if ((dimp_get(eDI_MP_di_dbg_mask) & 0x2)) {
pr_info("DI:ch[%d]*****wait %d timeout 0x%x(%d ms)*****\n",
pre->curr_ch,
pre->pres->field_count_for_cont,
Rd(DI_INTR_CTRL),
(unsigned int)(cur_to_msecs() -
pre->pres->irq_time[1]));
}
/*******************************/
dim_pre_de_done_buf_config(pre->curr_ch, true);
dpre_recyc(pre->curr_ch);
dpre_vdoing(pre->curr_ch);
/*******************************/
/*dpre_recyc(pre->curr_ch);*/
}
unsigned int dpre_mtotal_timeout(void *data)
{
ulong flags = 0;
spin_lock_irqsave(&plist_lock, flags);
dpre_mtotal_timeout_contr();
spin_unlock_irqrestore(&plist_lock, flags);
return K_DO_R_JUMP(K_DO_TABLE_ID_STOP);
}
const struct do_table_ops_s pr_mode_total[] = {
/*fix*/
[K_DO_TABLE_ID_PAUSE] = {
.id = K_DO_TABLE_ID_PAUSE,
.mark = 0,
.con = NULL,
.do_op = NULL,
.do_stop_op = NULL,
.name = "pause",
},
[K_DO_TABLE_ID_STOP] = {
.id = K_DO_TABLE_ID_STOP,
.mark = 0,
.con = NULL,
.do_op = NULL,
.do_stop_op = NULL,
.name = "stop",
},
/******************/
[K_DO_TABLE_ID_START] = { /*eDI_PRE_MT_CHECK*/
.id = K_DO_TABLE_ID_START,
.mark = 0,
.con = NULL,
.do_op = dpre_mtotal_check,
.do_stop_op = NULL,
.name = "start-check",
},
[eDI_PRE_MT_SET] = {
.id = eDI_PRE_MT_SET,
.mark = 0,
.con = NULL,
.do_op = dpre_mtotal_set,
.do_stop_op = NULL,
.name = "set",
},
[eDI_PRE_MT_WAIT_INT] = {
.id = eDI_PRE_MT_WAIT_INT,
.mark = 0,
.con = NULL,
.do_op = dpre_mtotal_wait_int,
.do_stop_op = NULL,
.name = "wait_int",
},
[eDI_PRE_MT_TIME_OUT] = {
.id = eDI_PRE_MT_TIME_OUT,
.mark = 0,
.con = NULL,
.do_op = dpre_mtotal_timeout,
.do_stop_op = NULL,
.name = "timeout",
},
};
/****************************
*
* mode for p
*
****************************/
enum eDI_PRE_MP {
eDI_PRE_MP_CHECK = K_DO_TABLE_ID_START,
eDI_PRE_MP_SET,
eDI_PRE_MP_WAIT_INT,
eDI_PRE_MP_TIME_OUT,
eDI_PRE_MP_CHECK2,
eDI_PRE_MP_SET2,
eDI_PRE_MP_WAIT_INT2,
eDI_PRE_MP_TIME_OUT2,
};
unsigned int dpre_mp_check(void *data)
{
struct di_hpre_s *pre = get_hw_pre();
unsigned int ret = K_DO_R_NOT_FINISH;
if ((pre_run_flag == DI_RUN_FLAG_RUN) ||
(pre_run_flag == DI_RUN_FLAG_STEP)) {
if (pre_run_flag == DI_RUN_FLAG_STEP)
pre_run_flag = DI_RUN_FLAG_STEP_DONE;
/*dim_print("%s:\n", __func__);*/
if (dim_pre_de_buf_config(pre->curr_ch)) {
/*pre->flg_wait_int = false;*/
/*pre_p_asi_set_next(pre->curr_ch);*/
ret = K_DO_R_FINISH;
} else {
/*pre->flg_wait_int = false;*/
ret = K_DO_R_JUMP(K_DO_TABLE_ID_STOP);
}
dim_dbg_pre_cnt(pre->curr_ch, "x");
}
return ret;
}
unsigned int dpre_mp_check2(void *data)
{
struct di_hpre_s *pre = get_hw_pre();
unsigned int ret = K_DO_R_NOT_FINISH;
if (dim_pre_de_buf_config(pre->curr_ch)) {
/*pre->flg_wait_int = false;*/
ret = K_DO_R_FINISH;
}
#if 0
else {
PR_ERR("%s:not second?ch[%d]\n", __func__, pre->curr_ch);
ret = K_DO_R_JUMP(K_DO_TABLE_ID_STOP);
}
#endif
return ret;
}
unsigned int dpre_mp_wait_int(void *data)
{
enum eDI_WAIT_INT wret;
unsigned int ret = K_DO_R_NOT_FINISH;
wret = di_pre_wait_int(NULL);
switch (wret) {
case eDI_WAIT_INT_NEED_WAIT:
ret = K_DO_R_NOT_FINISH;
break;
case eDI_WAIT_INT_HAVE_INT:
ret = K_DO_R_JUMP(eDI_PRE_MP_CHECK2);
break;
case eDI_WAIT_INT_TIME_OUT:
ret = K_DO_R_FINISH;
break;
}
return ret;
}
unsigned int dpre_mp_wait_int2(void *data)
{
enum eDI_WAIT_INT wret;
unsigned int ret = K_DO_R_NOT_FINISH;
wret = di_pre_wait_int(NULL);
switch (wret) {
case eDI_WAIT_INT_NEED_WAIT:
ret = K_DO_R_NOT_FINISH;
break;
case eDI_WAIT_INT_HAVE_INT:
ret = K_DO_R_JUMP(K_DO_TABLE_ID_STOP);
break;
case eDI_WAIT_INT_TIME_OUT:
ret = K_DO_R_FINISH;
break;
}
return ret;
}
unsigned int dpre_mp_timeout(void *data)
{
dpre_mtotal_timeout_contr();
return K_DO_R_FINISH;
}
unsigned int dpre_mp_timeout2(void *data)
{
dpre_mtotal_timeout_contr();
return K_DO_R_JUMP(K_DO_TABLE_ID_STOP);
}
const struct do_table_ops_s pre_mode_proc[] = {
/*fix*/
[K_DO_TABLE_ID_PAUSE] = {
.id = K_DO_TABLE_ID_PAUSE,
.mark = 0,
.con = NULL,
.do_op = NULL,
.do_stop_op = NULL,
.name = "pause",
},
[K_DO_TABLE_ID_STOP] = {
.id = K_DO_TABLE_ID_STOP,
.mark = 0, /*stop / pause*/
.con = NULL,
.do_op = NULL,
.do_stop_op = NULL,
.name = "stop",
},
/******************/
[K_DO_TABLE_ID_START] = { /*eDI_PRE_MP_CHECK*/
.id = K_DO_TABLE_ID_START,
.mark = 0, /*stop / pause*/
.con = NULL,
.do_op = dpre_mp_check,
.do_stop_op = NULL,
.name = "start-check",
},
[eDI_PRE_MP_SET] = {
.id = eDI_PRE_MP_SET,
.mark = 0, /*stop / pause*/
.con = NULL, /*condition*/
.do_op = dpre_mtotal_set,
.do_stop_op = NULL,
.name = "pset",
},
[eDI_PRE_MP_WAIT_INT] = {
.id = eDI_PRE_MP_WAIT_INT,
.mark = 0, /*stop / pause*/
.con = NULL, /*condition*/
.do_op = dpre_mp_wait_int,
.do_stop_op = NULL,
.name = "pwait_int",
},
[eDI_PRE_MP_TIME_OUT] = {
.id = eDI_PRE_MP_TIME_OUT,
.mark = 0, /*stop / pause*/
.con = NULL, /*condition*/
.do_op = dpre_mp_timeout,
.do_stop_op = NULL,
.name = "ptimeout",
},
/******/
[eDI_PRE_MP_CHECK2] = { /*eDI_PRE_MP_CHECK2*/
.id = eDI_PRE_MP_CHECK2,
.mark = 0, /*stop / pause*/
.con = NULL, /*condition*/
.do_op = dpre_mp_check2,
.do_stop_op = NULL,
.name = "start-check",
},
[eDI_PRE_MP_SET2] = {
.id = eDI_PRE_MP_SET2,
.mark = 0, /*stop / pause*/
.con = NULL, /*condition*/
.do_op = dpre_mtotal_set,
.do_stop_op = NULL,
.name = "psetp2",
},
[eDI_PRE_MP_WAIT_INT2] = {
.id = eDI_PRE_MP_WAIT_INT2,
.mark = 0, /*stop / pause*/
.con = NULL, /*condition*/
.do_op = dpre_mp_wait_int2,
.do_stop_op = NULL,
.name = "pwait_int2",
},
[eDI_PRE_MP_TIME_OUT2] = {
.id = eDI_PRE_MP_TIME_OUT2,
.mark = 0, /*stop / pause*/
.con = NULL, /*condition*/
.do_op = dpre_mp_timeout2,
.do_stop_op = NULL,
.name = "ptimeout2",
},
};
void pre_mode_setting(void)
{
struct di_hpre_s *pre = get_hw_pre();
if (pre->pre_st != eDI_PRE_ST4_DO_TABLE)
return;
do_table_working(&pre->sdt_mode);
}
/*--------------------------*/
enum eDI_WORK_MODE pre_cfg_count_mode(unsigned int ch, struct vframe_s *vframe)
{
enum eDI_WORK_MODE pmode;
if (is_bypass2(vframe, ch)) {
pmode = eDI_WORK_MODE_bypass_all;
return pmode;
}
if (COM_ME(vframe->type, VIDTYPE_INTERLACE)) {
/*interlace:*/
pmode = eDI_WORK_MODE_i;
return pmode;
}
if (dimp_get(eDI_MP_prog_proc_config) & 0x10)
pmode = eDI_WORK_MODE_p_as_p;
else if (is_from_vdin(vframe))
pmode = eDI_WORK_MODE_p_use_ibuf;
else
pmode = eDI_WORK_MODE_p_as_i;
return pmode;
}
unsigned int dpre_check_mode(unsigned int ch)
{
struct vframe_s *vframe;
unsigned int mode;
vframe = pw_vf_peek(ch);
if (!vframe)
return eDI_WORK_MODE_NONE;
mode = pre_cfg_count_mode(ch, vframe);/*eDI_WORK_MODE_all;*/
return mode;
}
/*--------------------------*/
bool dpre_step4_idle(void)
{
struct di_hpre_s *pre = get_hw_pre();
bool reflesh = false;
unsigned int ch;
ch = pre->curr_ch;
if (!pw_try_sw_ch_next_pre(ch))
return false;
if (pre->idle_cnt >= DI_CHANNEL_NUB) {
pre->idle_cnt = 0;
return false;
}
pre->pres = get_pre_stru(pre->curr_ch);
pre->psts = get_post_stru(pre->curr_ch);
/*state*/
pre->pre_st++;/*tmp*/
reflesh = true;
return reflesh;
}
bool dpre_step4_check(void)
{
struct di_hpre_s *pre = get_hw_pre();
bool reflesh = false;
unsigned int mode;
/*get vframe and select mode
* now: fix use total table
*/
mode = dpre_check_mode(pre->curr_ch);
if (mode == eDI_WORK_MODE_NONE) {
pre->pre_st--;
pre->idle_cnt++;
return true;
}
pre->idle_cnt = 0;
if (mode == eDI_WORK_MODE_p_as_i) {
do_table_init(&pre->sdt_mode,
&pre_mode_proc[0],
ARRAY_SIZE(pre_mode_proc));
} else {
do_table_init(&pre->sdt_mode,
&pr_mode_total[0],
ARRAY_SIZE(pr_mode_total));
}
do_talbe_cmd(&pre->sdt_mode, eDO_TABLE_CMD_START);
/*state*/
pre->pre_st++;
reflesh = true;
return reflesh;
}
bool dpre_step4_do_table(void)
{
struct di_hpre_s *pre = get_hw_pre();
bool reflesh = false;
if (do_table_is_crr(&pre->sdt_mode, K_DO_TABLE_ID_STOP)) {
pre->pre_st = eDI_PRE_ST4_IDLE;
reflesh = true;
}
return reflesh;
}
const struct di_func_tab_s di_pre_func_tab4[] = {
{eDI_PRE_ST4_EXIT, NULL},
{eDI_PRE_ST4_IDLE, dpre_step4_idle},
{eDI_PRE_ST4_CHECK, dpre_step4_check},
{eDI_PRE_ST4_DO_TABLE, dpre_step4_do_table},
};
const char * const dpre_state_name4[] = {
"EXIT",
"IDLE", /*swith to next channel?*/
"CHECK",
"DO_TABLE",
};
const char *dpre_state4_name_get(enum eDI_PRE_ST4 state)
{
if (state > eDI_PRE_ST4_DO_TABLE)
return "nothing";
return dpre_state_name4[state];
}
bool dpre_process_step4(void)
{
struct di_hpre_s *pre = get_hw_pre();
enum eDI_PRE_ST4 pre_st = pre->pre_st;
ulong flags = 0;
if (pre_st > eDI_PRE_ST4_EXIT) {
spin_lock_irqsave(&plist_lock, flags);
dim_recycle_post_back(pre->curr_ch);
dpre_recyc(pre->curr_ch);
dpre_vdoing(pre->curr_ch);
spin_unlock_irqrestore(&plist_lock, flags);
}
if ((pre_st <= eDI_PRE_ST4_DO_TABLE) &&
di_pre_func_tab4[pre_st].func) {
return di_pre_func_tab4[pre_st].func();
}
return false;
}

View File

@@ -0,0 +1,38 @@
/*
* drivers/amlogic/media/di_multi/di_pre.h
*
* Copyright (C) 2017 Amlogic, Inc. 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
*/
#ifndef __DI_PRE_H__
#define __DI_PRE_H__
void dpre_process(void);
void dpre_init(void);
const char *dpre_state_name_get(enum eDI_PRE_ST state);
void dpre_dbg_f_trig(unsigned int cmd);
void pre_vinfo_set(unsigned int ch,
struct vframe_s *ori_vframe);
unsigned int is_vinfo_change(unsigned int ch);
bool dpre_can_exit(unsigned int ch);
bool is_bypass_i_p(void);
bool dim_bypass_detect(unsigned int ch, struct vframe_s *vfm);
void pre_mode_setting(void);
bool dpre_process_step4(void);
const char *dpre_state4_name_get(enum eDI_PRE_ST4 state);
#endif /*__DI_PRE_H__*/

View File

@@ -0,0 +1,995 @@
/*
* drivers/amlogic/media/di_multi/di_que.c
*
* Copyright (C) 2017 Amlogic, Inc. 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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/kernel.h>
#include <linux/err.h>
#include <linux/seq_file.h>
#include <linux/kfifo.h>
#include <linux/amlogic/media/vfm/vframe.h>
#include "deinterlace.h"
#include "di_data_l.h"
#include "di_que.h"
#include "di_vframe.h"
#include "di_prc.h"
const char * const di_name_new_que[QUE_NUB] = {
"QUE_IN_FREE", /*0*/
"QUE_PRE_READY", /*1*/
"QUE_POST_FREE", /*2*/
"QUE_POST_READY", /*3*/
"QUE_POST_BACK", /*4*/
"QUE_DBG",
/* "QUE_NUB",*/
};
#define que_dbg dim_print
static void pw_queue_clear(unsigned int ch, enum QUE_TYPE qtype)
{
struct di_ch_s *pch = get_chdata(ch);
#if 0
if (qtype >= QUE_NUB)
return;
#endif
kfifo_reset(&pch->fifo[qtype]);
}
bool pw_queue_in(unsigned int ch, enum QUE_TYPE qtype, unsigned int buf_index)
{
struct di_ch_s *pch = get_chdata(ch);
#if 0
if (qtype >= QUE_NUB)
return false;
#endif
if (kfifo_in(&pch->fifo[qtype], &buf_index, sizeof(unsigned int))
!= sizeof(unsigned int))
return false;
#if 0
/*below for debug: save in que*/
if (qtype <= QUE_POST_RECYC) {
if (buf_index >= MAX_POST_BUF_NUM) {
pr_err("%s:err:overflow?[%d]\n", __func__, buf_index);
} else {
ppw = &pch->lpost_buf[buf_index];
ppw->in_qtype = qtype;
}
}
#endif
return true;
}
bool pw_queue_out(unsigned int ch, enum QUE_TYPE qtype,
unsigned int *buf_index)
{
struct di_ch_s *pch = get_chdata(ch);
unsigned int index;
#if 0
if (qtype >= QUE_NUB)
return false;
#endif
if (kfifo_out(&pch->fifo[qtype], &index, sizeof(unsigned int))
!= sizeof(unsigned int))
return false;
*buf_index = index;
return true;
}
static bool pw_queue_peek(unsigned int ch, enum QUE_TYPE qtype,
unsigned int *buf_index)
{
struct di_ch_s *pch = get_chdata(ch);
unsigned int index;
#if 0
if (qtype >= QUE_NUB)
return false;
#endif
if (kfifo_out_peek(&pch->fifo[qtype], &index, sizeof(unsigned int))
!= sizeof(unsigned int))
return false;
*buf_index = index;
return true;
}
bool pw_queue_move(unsigned int ch, enum QUE_TYPE qtypef, enum QUE_TYPE qtypet,
unsigned int *oindex)
{
struct di_ch_s *pch = get_chdata(ch);
unsigned int index;
/*struct di_post_buf_s *ppw;*/ /*debug only*/
#if 0
if (qtypef >= QUE_NUB || qtypet >= QUE_NUB)
return false;
#endif
if (kfifo_out(&pch->fifo[qtypef], &index, sizeof(unsigned int))
!= sizeof(unsigned int)) {
PR_ERR("qtypef[%d] is empty\n", qtypef);
return false;
}
if (kfifo_in(&pch->fifo[qtypet], &index, sizeof(unsigned int))
!= sizeof(unsigned int)) {
PR_ERR("qtypet[%d] is full\n", qtypet);
return false;
}
*oindex = index;
#if 0
if (qtypet <= QUE_POST_RECYC) {
/*below for debug: save in que*/
if (index >= MAX_POST_BUF_NUM) {
pr_err("%s:err:overflow?[%d]\n", __func__, index);
} else {
ppw = &pch->lpost_buf[index];
ppw->in_qtype = qtypet;
}
}
#endif
return true;
}
bool pw_queue_empty(unsigned int ch, enum QUE_TYPE qtype)
{
struct di_ch_s *pch = get_chdata(ch);
if (kfifo_is_empty(&pch->fifo[qtype]))
return true;
return false;
}
int di_que_list_count(unsigned int ch, enum QUE_TYPE qtype)
{
struct di_ch_s *pch = get_chdata(ch);
unsigned int length;
#if 0
if (qtype >= QUE_NUB)
return -1;
#endif
length = kfifo_len(&pch->fifo[qtype]);
length = length / sizeof(unsigned int);
return length;
}
/***************************************/
/*outbuf : array size MAX_FIFO_SIZE*/
/***************************************/
bool di_que_list(unsigned int ch, enum QUE_TYPE qtype, unsigned int *outbuf,
unsigned int *rsize)
{
struct di_ch_s *pch = get_chdata(ch);
/* unsigned int tmp[MAX_FIFO_SIZE + 1];*/
int i;
unsigned int index;
bool ret = false;
/*que_dbg("%s:begin\n", __func__);*/
for (i = 0; i < MAX_FIFO_SIZE; i++)
outbuf[i] = 0xff;
if (kfifo_is_empty(&pch->fifo[qtype])) {
que_dbg("\t%d:empty\n", qtype);
*rsize = 0;
return true;
}
ret = true;
memcpy(&pch->fifo[QUE_DBG], &pch->fifo[qtype],
sizeof(pch->fifo[qtype]));
#if 0
if (kfifo_is_empty(&pbm->fifo[QUE_DBG]))
pr_err("%s:err, kfifo can not copy?\n", __func__);
#endif
i = 0;
*rsize = 0;
while (kfifo_out(&pch->fifo[QUE_DBG], &index, sizeof(unsigned int))
== sizeof(unsigned int)) {
outbuf[i] = index;
/*pr_info("%d->%d\n",i,index);*/
i++;
}
*rsize = di_que_list_count(ch, qtype);
#if 0 /*debug only*/
que_dbg("%s: size[%d]\n", di_name_new_que[qtype], *rsize);
for (i = 0; i < *rsize; i++)
que_dbg("%d,", outbuf[i]);
que_dbg("\n");
#endif
/*que_dbg("finish\n");*/
return ret;
}
int di_que_is_empty(unsigned int ch, enum QUE_TYPE qtype)
{
struct di_ch_s *pch = get_chdata(ch);
#if 0
if (qtype >= QUE_NUB)
return -1;
#endif
return kfifo_is_empty(&pch->fifo[qtype]);
}
void di_que_init(unsigned int ch)
{
int i;
for (i = 0; i < QUE_NUB; i++)
pw_queue_clear(ch, i);
}
bool di_que_alloc(unsigned int ch)
{
int i;
int ret;
bool flg_err;
struct di_ch_s *pch = get_chdata(ch);
/*kfifo----------------------------*/
flg_err = 0;
for (i = 0; i < QUE_NUB; i++) {
ret = kfifo_alloc(&pch->fifo[i],
sizeof(unsigned int) * MAX_FIFO_SIZE,
GFP_KERNEL);
if (ret < 0) {
flg_err = 1;
PR_ERR("%s:%d:can't get kfifo\n", __func__, i);
break;
}
pch->flg_fifo[i] = 1;
}
#if 0
/*canvas-----------------------------*/
canvas_alloc();
#endif
/* pdp_clear();*/
if (!flg_err) {
/*pbm->flg_fifo = 1;*/
pr_info("%s:ok\n", __func__);
ret = true;
} else {
di_que_release(ch);
ret = false;
}
return ret;
}
void di_que_release(unsigned int ch)
{
struct di_ch_s *pch = get_chdata(ch);
int i;
/* canvas_release();*/
for (i = 0; i < QUE_NUB; i++) {
if (pch->flg_fifo[i]) {
kfifo_free(&pch->fifo[i]);
pch->flg_fifo[i] = 0;
}
}
pr_info("%s:ok\n", __func__);
}
/********************************************
*get di_buf from index that same in que
* (di_buf->type << 8) | (di_buf->index)
********************************************/
struct di_buf_s *pw_qindex_2_buf(unsigned int ch, unsigned int qindex)
{
union uDI_QBUF_INDEX index;
struct di_buf_s *di_buf;
struct di_buf_pool_s *pbuf_pool = get_buf_pool(ch);
index.d32 = qindex;
di_buf = &pbuf_pool[index.b.type - 1].di_buf_ptr[index.b.index];
return di_buf;
}
/********************************************/
/*get di_buf from index that same in que*/
/*(di_buf->type << 8) | (di_buf->index)*/
/********************************************/
static unsigned int pw_buf_2_qindex(unsigned int ch, struct di_buf_s *pdi_buf)
{
union uDI_QBUF_INDEX index;
index.b.index = pdi_buf->index;
index.b.type = pdi_buf->type;
return index.d32;
}
/*di_buf is out*/
struct di_buf_s *di_que_out_to_di_buf(unsigned int ch, enum QUE_TYPE qtype)
{
unsigned int q_index;
struct di_buf_s *pdi_buf = NULL;
if (!pw_queue_peek(ch, qtype, &q_index))
return pdi_buf;
pdi_buf = pw_qindex_2_buf(ch, q_index);
if (!pdi_buf) {
PR_ERR("di:err:%s:buf is null[%d]\n", __func__, q_index);
return NULL;
}
pw_queue_out(ch, qtype, &q_index);
pdi_buf->queue_index = -1;
return pdi_buf;
}
/*di_buf is input*/
bool di_que_out(unsigned int ch, enum QUE_TYPE qtype, struct di_buf_s *di_buf)
{
unsigned int q_index;
unsigned int q_index2;
if (!pw_queue_peek(ch, qtype, &q_index))
return false;
q_index2 = pw_buf_2_qindex(ch, di_buf);
if (q_index2 != q_index) {
PR_ERR("di:%s:not map[%d,%d]\n", __func__, q_index2, q_index);
return false;
}
pw_queue_out(ch, qtype, &q_index);
di_buf->queue_index = -1;
return true;
}
bool di_que_in(unsigned int ch, enum QUE_TYPE qtype, struct di_buf_s *di_buf)
{
unsigned int q_index;
if (!di_buf) {
PR_ERR("di:%s:err:di_buf is NULL,ch[%d],qtype[%d]\n",
__func__, ch, qtype);
return false;
}
if (di_buf->queue_index != -1) {
PR_ERR("di:%s:buf in some que,ch[%d],qt[%d],qi[%d],bi[%d]\n",
__func__,
ch, qtype, di_buf->queue_index, di_buf->index);
return false;
}
q_index = pw_buf_2_qindex(ch, di_buf);
if (!pw_queue_in(ch, qtype, q_index)) {
PR_ERR("di:%s:err:can't que in,ch[%d],qtype[%d],q_index[%d]\n",
__func__,
ch, qtype, q_index);
return false;
}
di_buf->queue_index = qtype + QUEUE_NUM;
if (qtype == QUE_PRE_READY)
dim_print("di:pre_ready in %d\n", di_buf->index);
return true;
}
bool di_que_is_in_que(unsigned int ch, enum QUE_TYPE qtype,
struct di_buf_s *di_buf)
{
unsigned int q_index;
unsigned int arr[MAX_FIFO_SIZE + 1];
unsigned int asize = 0;
bool ret = false;
unsigned int i;
if (!di_buf)
return false;
q_index = pw_buf_2_qindex(ch, di_buf);
di_que_list(ch, qtype, &arr[0], &asize);
if (asize == 0)
return ret;
for (i = 0; i < asize; i++) {
if (arr[i] == q_index) {
ret = true;
break;
}
}
return ret;
}
/*same as get_di_buf_head*/
struct di_buf_s *di_que_peek(unsigned int ch, enum QUE_TYPE qtype)
{
struct di_buf_s *di_buf = NULL;
unsigned int q_index;
if (!pw_queue_peek(ch, qtype, &q_index))
return di_buf;
di_buf = pw_qindex_2_buf(ch, q_index);
return di_buf;
}
bool di_que_type_2_new(unsigned int q_type, enum QUE_TYPE *nqtype)
{
if (!F_IN(q_type, QUEUE_NEW_THD_MIN, QUEUE_NEW_THD_MAX))
return false;
*nqtype = (enum QUE_TYPE)(q_type - QUEUE_NUM);
return true;
}
/**********************************************************/
/**********************************************************/
/*ary add this function for reg ini value, no need wait peek*/
void queue_init2(unsigned int channel)
{
int i, j;
struct queue_s *pqueue = get_queue(channel);
for (i = 0; i < QUEUE_NUM; i++) {
queue_t *q = &pqueue[i];
for (j = 0; j < MAX_QUEUE_POOL_SIZE; j++)
q->pool[j] = 0;
q->in_idx = 0;
q->out_idx = 0;
q->num = 0;
q->type = 0;
if ((i == QUEUE_RECYCLE) ||
(i == QUEUE_DISPLAY) ||
(i == QUEUE_TMP) ||
(i == QUEUE_POST_DOING))
q->type = 1;
#if 0
if ((i == QUEUE_LOCAL_FREE) && dim_get_use_2_int_buf())
q->type = 2;
#endif
}
}
void queue_init(unsigned int channel, int local_buffer_num)
{
int i, j;
struct di_buf_s *pbuf_local = get_buf_local(channel);
struct di_buf_s *pbuf_in = get_buf_in(channel);
struct di_buf_s *pbuf_post = get_buf_post(channel);
struct queue_s *pqueue = get_queue(channel);
struct di_buf_pool_s *pbuf_pool = get_buf_pool(channel);
for (i = 0; i < QUEUE_NUM; i++) {
queue_t *q = &pqueue[i];
for (j = 0; j < MAX_QUEUE_POOL_SIZE; j++)
q->pool[j] = 0;
q->in_idx = 0;
q->out_idx = 0;
q->num = 0;
q->type = 0;
if ((i == QUEUE_RECYCLE) ||
(i == QUEUE_DISPLAY) ||
(i == QUEUE_TMP)
/*||(i == QUEUE_POST_DOING)*/
)
q->type = 1;
if ((i == QUEUE_LOCAL_FREE) &&
dimp_get(eDI_MP_use_2_interlace_buff))
q->type = 2;
}
if (local_buffer_num > 0) {
pbuf_pool[VFRAME_TYPE_IN - 1].di_buf_ptr = &pbuf_in[0];
pbuf_pool[VFRAME_TYPE_IN - 1].size = MAX_IN_BUF_NUM;
pbuf_pool[VFRAME_TYPE_LOCAL - 1].di_buf_ptr = &pbuf_local[0];
pbuf_pool[VFRAME_TYPE_LOCAL - 1].size = local_buffer_num;
pbuf_pool[VFRAME_TYPE_POST - 1].di_buf_ptr = &pbuf_post[0];
pbuf_pool[VFRAME_TYPE_POST - 1].size = MAX_POST_BUF_NUM;
}
}
struct di_buf_s *get_di_buf_head(unsigned int channel, int queue_idx)
{
struct queue_s *pqueue = get_queue(channel);
queue_t *q = &pqueue[queue_idx];
int idx;
unsigned int pool_idx, di_buf_idx;
struct di_buf_s *di_buf = NULL;
struct di_buf_pool_s *pbuf_pool = get_buf_pool(channel);
enum QUE_TYPE nqtype;/*new que*/
if (dimp_get(eDI_MP_di_log_flag) & DI_LOG_QUEUE)
dim_print("%s:<%d:%d,%d,%d>\n", __func__, queue_idx,
q->num, q->in_idx, q->out_idx);
/* ****new que***** */
if (di_que_type_2_new(queue_idx, &nqtype))
return di_que_peek(channel, nqtype);
/* **************** */
if (q->num > 0) {
if (q->type == 0) {
idx = q->out_idx;
} else {
for (idx = 0; idx < MAX_QUEUE_POOL_SIZE; idx++)
if (q->pool[idx] != 0)
break;
}
if (idx < MAX_QUEUE_POOL_SIZE) {
pool_idx = ((q->pool[idx] >> 8) & 0xff) - 1;
di_buf_idx = q->pool[idx] & 0xff;
if (pool_idx < VFRAME_TYPE_NUM) {
if (di_buf_idx < pbuf_pool[pool_idx].size)
di_buf = &pbuf_pool[pool_idx].di_buf_ptr[di_buf_idx];
}
}
}
if ((di_buf) && ((((pool_idx + 1) << 8) | di_buf_idx) !=
((di_buf->type << 8) | (di_buf->index)))) {
pr_dbg("%s: Error (%x,%x)\n", __func__,
(((pool_idx + 1) << 8) | di_buf_idx),
((di_buf->type << 8) | (di_buf->index)));
if (dim_vcry_get_flg() == 0) {
dim_vcry_set_log_reason(2);
dim_vcry_set_log_q_idx(queue_idx);
dim_vcry_set_log_di_buf(di_buf);
}
dim_vcry_flg_inc();
di_buf = NULL;
}
if (dimp_get(eDI_MP_di_log_flag) & DI_LOG_QUEUE) {
if (di_buf)
dim_print("%s: 0x%p(%d,%d)\n", __func__, di_buf,
pool_idx, di_buf_idx);
else
dim_print("%s: 0x%p\n", __func__, di_buf);
}
return di_buf;
}
/*ary: note:*/
/*a. di_buf->queue_index = -1*/
/*b. */
void queue_out(unsigned int channel, struct di_buf_s *di_buf)
{
int i;
queue_t *q;
struct queue_s *pqueue = get_queue(channel);
enum QUE_TYPE nqtype;/*new que*/
if (!di_buf) {
PR_ERR("%s:Error\n", __func__);
if (dim_vcry_get_flg() == 0)
dim_vcry_set_log_reason(3);
dim_vcry_flg_inc();
return;
}
/* ****new que***** */
if (di_que_type_2_new(di_buf->queue_index, &nqtype)) {
di_que_out(channel, nqtype, di_buf); /*?*/
return;
}
/* **************** */
if (di_buf->queue_index >= 0 && di_buf->queue_index < QUEUE_NUM) {
q = &pqueue[di_buf->queue_index];
if (dimp_get(eDI_MP_di_log_flag) & DI_LOG_QUEUE)
dim_print("%s:<%d:%d,%d,%d> 0x%p\n", __func__,
di_buf->queue_index, q->num, q->in_idx,
q->out_idx, di_buf);
if (q->num > 0) {
if (q->type == 0) {
if (q->pool[q->out_idx] ==
((di_buf->type << 8) | (di_buf->index))) {
q->num--;
q->pool[q->out_idx] = 0;
q->out_idx++;
if (q->out_idx >= MAX_QUEUE_POOL_SIZE)
q->out_idx = 0;
di_buf->queue_index = -1;
} else {
PR_ERR(
"%s: Error (%d, %x,%x)\n",
__func__,
di_buf->queue_index,
q->pool[q->out_idx],
((di_buf->type << 8) |
(di_buf->index)));
if (dim_vcry_get_flg() == 0) {
dim_vcry_set_log_reason(4);
dim_vcry_set_log_q_idx(di_buf->queue_index);
dim_vcry_set_log_di_buf(di_buf);
}
dim_vcry_flg_inc();
}
} else if (q->type == 1) {
int pool_val =
(di_buf->type << 8) | (di_buf->index);
for (i = 0; i < MAX_QUEUE_POOL_SIZE; i++) {
if (q->pool[i] == pool_val) {
q->num--;
q->pool[i] = 0;
di_buf->queue_index = -1;
break;
}
}
if (i == MAX_QUEUE_POOL_SIZE) {
PR_ERR("%s: Error\n", __func__);
if (dim_vcry_get_flg() == 0) {
dim_vcry_set_log_reason(5);
dim_vcry_set_log_q_idx(di_buf->queue_index);
dim_vcry_set_log_di_buf(di_buf);
}
dim_vcry_flg_inc();
}
} else if (q->type == 2) {
int pool_val =
(di_buf->type << 8) | (di_buf->index);
if ((di_buf->index < MAX_QUEUE_POOL_SIZE) &&
(q->pool[di_buf->index] == pool_val)) {
q->num--;
q->pool[di_buf->index] = 0;
di_buf->queue_index = -1;
} else {
PR_ERR("%s: Error\n", __func__);
if (dim_vcry_get_flg() == 0) {
dim_vcry_set_log_reason(5);
dim_vcry_set_log_q_idx(di_buf->queue_index);
dim_vcry_set_log_di_buf(di_buf);
}
dim_vcry_flg_inc();
}
}
}
} else {
PR_ERR("%s: Error, queue_index %d is not right\n",
__func__, di_buf->queue_index);
if (dim_vcry_get_flg() == 0) {
dim_vcry_set_log_reason(6);
dim_vcry_set_log_q_idx(0);
dim_vcry_set_log_di_buf(di_buf);
}
dim_vcry_flg_inc();
}
if (dimp_get(eDI_MP_di_log_flag) & DI_LOG_QUEUE)
dim_print("%s done\n", __func__);
}
void queue_out_dbg(unsigned int channel, struct di_buf_s *di_buf)
{
int i;
queue_t *q;
struct queue_s *pqueue = get_queue(channel);
enum QUE_TYPE nqtype;/*new que*/
if (!di_buf) {
PR_ERR("%s:Error\n", __func__);
if (dim_vcry_get_flg() == 0)
dim_vcry_set_log_reason(3);
dim_vcry_flg_inc();
return;
}
/* ****new que***** */
if (di_que_type_2_new(di_buf->queue_index, &nqtype)) {
di_que_out(channel, nqtype, di_buf); /*?*/
pr_info("dbg1:nqtype=%d\n", nqtype);
return;
}
/* **************** */
if (di_buf->queue_index >= 0 && di_buf->queue_index < QUEUE_NUM) {
q = &pqueue[di_buf->queue_index];
if (dimp_get(eDI_MP_di_log_flag) & DI_LOG_QUEUE)
dim_print("%s:<%d:%d,%d,%d> 0x%p\n", __func__,
di_buf->queue_index, q->num, q->in_idx,
q->out_idx, di_buf);
if (q->num > 0) {
if (q->type == 0) {
pr_info("dbg3\n");
if (q->pool[q->out_idx] ==
((di_buf->type << 8) | (di_buf->index))) {
q->num--;
q->pool[q->out_idx] = 0;
q->out_idx++;
if (q->out_idx >= MAX_QUEUE_POOL_SIZE)
q->out_idx = 0;
di_buf->queue_index = -1;
} else {
PR_ERR(
"%s: Error (%d, %x,%x)\n",
__func__,
di_buf->queue_index,
q->pool[q->out_idx],
((di_buf->type << 8) |
(di_buf->index)));
if (dim_vcry_get_flg() == 0) {
dim_vcry_set_log_reason(4);
dim_vcry_set_log_q_idx(di_buf->queue_index);
dim_vcry_set_log_di_buf(di_buf);
}
dim_vcry_flg_inc();
}
} else if (q->type == 1) {
int pool_val =
(di_buf->type << 8) | (di_buf->index);
for (i = 0; i < MAX_QUEUE_POOL_SIZE; i++) {
if (q->pool[i] == pool_val) {
q->num--;
q->pool[i] = 0;
di_buf->queue_index = -1;
break;
}
}
pr_info("dbg2:i=%d,qindex=%d\n", i,
di_buf->queue_index);
if (i == MAX_QUEUE_POOL_SIZE) {
PR_ERR("%s: Error\n", __func__);
if (dim_vcry_get_flg() == 0) {
dim_vcry_set_log_reason(5);
dim_vcry_set_log_q_idx(di_buf->queue_index);
dim_vcry_set_log_di_buf(di_buf);
}
dim_vcry_flg_inc();
}
} else if (q->type == 2) {
int pool_val =
(di_buf->type << 8) | (di_buf->index);
pr_info("dbg4\n");
if ((di_buf->index < MAX_QUEUE_POOL_SIZE) &&
(q->pool[di_buf->index] == pool_val)) {
q->num--;
q->pool[di_buf->index] = 0;
di_buf->queue_index = -1;
} else {
PR_ERR("%s: Error\n", __func__);
if (dim_vcry_get_flg() == 0) {
dim_vcry_set(5,
di_buf->queue_index,
di_buf);
}
dim_vcry_flg_inc();
}
}
}
} else {
PR_ERR("%s: Error, queue_index %d is not right\n",
__func__, di_buf->queue_index);
if (dim_vcry_get_flg() == 0) {
dim_vcry_set_log_reason(6);
dim_vcry_set_log_q_idx(0);
dim_vcry_set_log_di_buf(di_buf);
}
dim_vcry_flg_inc();
}
if (dimp_get(eDI_MP_di_log_flag) & DI_LOG_QUEUE)
dim_print("%s done\n", __func__);
}
/***************************************/
/* set di_buf->queue_index*/
/***************************************/
void queue_in(unsigned int channel, struct di_buf_s *di_buf, int queue_idx)
{
queue_t *q = NULL;
struct queue_s *pqueue = get_queue(channel);
enum QUE_TYPE nqtype;/*new que*/
if (!di_buf) {
PR_ERR("%s:Error\n", __func__);
if (dim_vcry_get_flg() == 0) {
dim_vcry_set_log_reason(7);
dim_vcry_set_log_q_idx(queue_idx);
dim_vcry_set_log_di_buf(di_buf);
}
dim_vcry_flg_inc();
return;
}
/* ****new que***** */
if (di_que_type_2_new(queue_idx, &nqtype)) {
di_que_in(channel, nqtype, di_buf);
return;
}
/* **************** */
if (di_buf->queue_index != -1) {
PR_ERR("%s:%s[%d] queue_index(%d) is not -1, to que[%d]\n",
__func__, dim_get_vfm_type_name(di_buf->type),
di_buf->index, di_buf->queue_index, queue_idx);
if (dim_vcry_get_flg() == 0) {
dim_vcry_set_log_reason(8);
dim_vcry_set_log_q_idx(queue_idx);
dim_vcry_set_log_di_buf(di_buf);
}
dim_vcry_flg_inc();
return;
}
q = &pqueue[queue_idx];
if (dimp_get(eDI_MP_di_log_flag) & DI_LOG_QUEUE)
dim_print("%s:<%d:%d,%d,%d> 0x%p\n", __func__, queue_idx,
q->num, q->in_idx, q->out_idx, di_buf);
if (q->type == 0) {
q->pool[q->in_idx] = (di_buf->type << 8) | (di_buf->index);
di_buf->queue_index = queue_idx;
q->in_idx++;
if (q->in_idx >= MAX_QUEUE_POOL_SIZE)
q->in_idx = 0;
q->num++;
} else if (q->type == 1) {
int i;
for (i = 0; i < MAX_QUEUE_POOL_SIZE; i++) {
if (q->pool[i] == 0) {
q->pool[i] =
(di_buf->type << 8) | (di_buf->index);
di_buf->queue_index = queue_idx;
q->num++;
break;
}
}
if (i == MAX_QUEUE_POOL_SIZE) {
pr_dbg("%s: Error\n", __func__);
if (dim_vcry_get_flg() == 0) {
dim_vcry_set_log_reason(9);
dim_vcry_set_log_q_idx(queue_idx);
}
dim_vcry_flg_inc();
}
} else if (q->type == 2) {
if ((di_buf->index < MAX_QUEUE_POOL_SIZE) &&
(q->pool[di_buf->index] == 0)) {
q->pool[di_buf->index] =
(di_buf->type << 8) | (di_buf->index);
di_buf->queue_index = queue_idx;
q->num++;
} else {
pr_dbg("%s: Error\n", __func__);
if (dim_vcry_get_flg() == 0) {
dim_vcry_set_log_reason(9);
dim_vcry_set_log_q_idx(queue_idx);
}
dim_vcry_flg_inc();
}
}
if (dimp_get(eDI_MP_di_log_flag) & DI_LOG_QUEUE)
dim_print("%s done\n", __func__);
}
int list_count(unsigned int channel, int queue_idx)
{
struct queue_s *pqueue;
enum QUE_TYPE nqtype;/*new que*/
/* ****new que***** */
if (di_que_type_2_new(queue_idx, &nqtype)) {
PR_ERR("%s:err: over flow\n", __func__);
return di_que_list_count(channel, nqtype);
}
/* **************** */
pqueue = get_queue(channel);
return pqueue[queue_idx].num;
}
bool queue_empty(unsigned int channel, int queue_idx)
{
struct queue_s *pqueue;
bool ret;
enum QUE_TYPE nqtype;/*new que*/
/* ****new que***** */
if (di_que_type_2_new(queue_idx, &nqtype)) {
PR_ERR("%s:err: over flow\n", __func__);
return di_que_is_empty(channel, nqtype);
}
/* **************** */
pqueue = get_queue(channel);
ret = (pqueue[queue_idx].num == 0);
return ret;
}
bool is_in_queue(unsigned int channel, struct di_buf_s *di_buf, int queue_idx)
{
bool ret = 0;
struct di_buf_s *p = NULL;
int itmp;
unsigned int overflow_cnt;
enum QUE_TYPE nqtype;/*new que*/
/* ****new que***** */
if (di_que_type_2_new(queue_idx, &nqtype))
return di_que_is_in_que(channel, nqtype, di_buf);
/* **************** */
overflow_cnt = 0;
if (!di_buf || (queue_idx < 0) || (queue_idx >= QUEUE_NUM)) {
ret = 0;
dim_print("%s: not in queue:%d!!!\n", __func__, queue_idx);
return ret;
}
queue_for_each_entry(p, channel, queue_idx, list) {
if (p == di_buf) {
ret = 1;
break;
}
if (overflow_cnt++ > MAX_QUEUE_POOL_SIZE) {
ret = 0;
dim_print("%s: overflow_cnt!!!\n", __func__);
break;
}
}
return ret;
}

View File

@@ -0,0 +1,76 @@
/*
* drivers/amlogic/media/di_multi/di_que.h
*
* Copyright (C) 2017 Amlogic, Inc. 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
*/
#ifndef __DI_QUE_H__
#define __DI_QUE_H__
void queue_init(unsigned int channel, int local_buffer_num);
void queue_out(unsigned int channel, struct di_buf_s *di_buf);
void queue_in(unsigned int channel, struct di_buf_s *di_buf,
int queue_idx);
int list_count(unsigned int channel, int queue_idx);
bool queue_empty(unsigned int channel, int queue_idx);
bool is_in_queue(unsigned int channel, struct di_buf_s *di_buf,
int queue_idx);
struct di_buf_s *get_di_buf_head(unsigned int channel,
int queue_idx);
void queue_init2(unsigned int channel);
/*new buf:*/
bool pw_queue_in(unsigned int ch, enum QUE_TYPE qtype,
unsigned int buf_index);
bool pw_queue_out(unsigned int ch, enum QUE_TYPE qtype,
unsigned int *buf_index);
bool pw_queue_empty(unsigned int ch, enum QUE_TYPE qtype);
/******************************************/
/*new api*/
/******************************************/
union uDI_QBUF_INDEX {
unsigned int d32;
struct {
unsigned int index:8, /*low*/
type:8,
reserved0:16;
} b;
};
void di_que_init(unsigned int ch);
bool di_que_alloc(unsigned int ch);
void di_que_release(unsigned int ch);
int di_que_is_empty(unsigned int ch, enum QUE_TYPE qtype);
bool di_que_out(unsigned int ch, enum QUE_TYPE qtype,
struct di_buf_s *di_buf);
struct di_buf_s *di_que_out_to_di_buf(unsigned int ch,
enum QUE_TYPE qtype);
bool di_que_in(unsigned int ch, enum QUE_TYPE qtype,
struct di_buf_s *di_buf);
bool di_que_is_in_que(unsigned int ch, enum QUE_TYPE qtype,
struct di_buf_s *di_buf);
struct di_buf_s *di_que_peek(unsigned int ch, enum QUE_TYPE qtype);
bool di_que_type_2_new(unsigned int q_type, enum QUE_TYPE *nqtype);
int di_que_list_count(unsigned int ch, enum QUE_TYPE qtype);
bool di_que_list(unsigned int ch, enum QUE_TYPE qtype,
unsigned int *outbuf, unsigned int *rsize);
struct di_buf_s *pw_qindex_2_buf(unsigned int ch, unsigned int qindex);
void queue_out_dbg(unsigned int channel, struct di_buf_s *di_buf);
#endif /*__DI_QUE_H__*/

View File

@@ -0,0 +1,249 @@
/*
* drivers/amlogic/media/di_multi/di_reg_tab.c
*
* Copyright (C) 2017 Amlogic, Inc. 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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/kernel.h>
#include <linux/err.h>
#include <linux/seq_file.h>
#include <linux/amlogic/iomap.h>
#include "deinterlace.h"
#include "di_data_l.h"
#include "register.h"
static const struct reg_t rtab_contr[] = {
/*--------------------------*/
{VD1_AFBCD0_MISC_CTRL, 20, 2, 0, "VD1_AFBCD0_MISC_CTRL",
"vd1_go_field_sel",
"0: gofile;1: post;2: pre"},
{VD1_AFBCD0_MISC_CTRL, 9, 1, 0, "",
"afbc0_mux_vpp_mad",
"afbc0 to 0:vpp; 1:di"},
{VD1_AFBCD0_MISC_CTRL, 8, 1, 0, "",
"di_mif0_en",
":mif to 0-vpp;1-di"},
/*--------------------------*/
{DI_POST_CTRL, 12, 1, 0, "DI_POST_CTRL",
"di_post_viu_link",
""},
{DI_POST_CTRL, 8, 1, 0, "",
"di_vpp_out_en",
""},
/*--------------------------*/
{VIU_MISC_CTRL0, 20, 1, 0, "VIU_MISC_CTRL0",
"?",
"?"},
{VIU_MISC_CTRL0, 18, 1, 0, "",
"Vdin0_wr_out_ctrl",
"0: nr_inp to vdin; 1: vdin wr dout"},
{VIU_MISC_CTRL0, 17, 1, 0, "",
"Afbc_inp_sel",
"0: mif to INP; 1: afbc to INP"},
{VIU_MISC_CTRL0, 16, 1, 0, "",
"di_mif0_en",
" vd1(afbc) to di post(if0) enable"},
/*--------------------------*/
{DI_IF1_GEN_REG, 0, 1, 0, "DI_IF1_GEN_REG",
"enable",
""},
/*--------------------------*/
{DI_IF1_GEN_REG3, 8, 2, 0, "DI_IF1_GEN_REG3",
"cntl_bits_mode",
"0:8bit;1:10bit 422;2:10bit 444"},
/*--------------------------*/
{DI_IF2_GEN_REG3, 8, 2, 0, "DI_IF2_GEN_REG3",
"cntl_bits_mode",
"0:8bit;1:10bit 422;2:10bit 444"},
/*--------------------------*/
{DI_IF0_GEN_REG3, 8, 2, 0, "DI_IF0_GEN_REG3",
"cntl_bits_mode",
"0:8bit;1:10bit 422;2:10bit 444"},
/*--------------------------*/
{DI_POST_GL_CTRL, 31, 1, 0, "DI_POST_GL_CTRL",
"post count enable",
""},
{DI_POST_GL_CTRL, 30, 1, 0, "",
"post count reset",
""},
{DI_POST_GL_CTRL, 16, 14, 0, "",
"total line number for post count",
""},
{DI_POST_GL_CTRL, 0, 14, 0, "",
"the line number of post frame reset",
""},
{TABLE_FLG_END, 0, 0, 0, "end", "end", ""},
};
/**********************/
/* debug register */
/**********************/
static unsigned int get_reg_bits(unsigned int val, unsigned int bstart,
unsigned int bw)
{
return((val &
(((1L << bw) - 1) << bstart)) >> (bstart));
}
static void dbg_reg_tab(struct seq_file *s, const struct reg_t *pRegTab)
{
struct reg_t creg;
int i;
unsigned int l_add;
unsigned int val32 = 1, val;
char *bname;
char *info;
i = 0;
l_add = 0;
creg = pRegTab[i];
do {
if (creg.add != l_add) {
val32 = Rd(creg.add); /*RD*/
seq_printf(s, "add:0x%x = 0x%08x, %s\n",
creg.add, val32, creg.name);
l_add = creg.add;
}
val = get_reg_bits(val32, creg.bit, creg.wid); /*RD_B*/
if (creg.bname)
bname = creg.bname;
else
bname = "";
if (creg.info)
info = creg.info;
else
info = "";
seq_printf(s, "\tbit[%d,%d]:\t0x%x[%d]:\t%s:\t%s\n",
creg.bit, creg.wid, val, val, bname, info);
i++;
creg = pRegTab[i];
if (i > TABLE_LEN_MAX) {
pr_info("warn: too long, stop\n");
break;
}
} while (creg.add != TABLE_FLG_END);
}
int reg_con_show(struct seq_file *seq, void *v)
{
dbg_reg_tab(seq, &rtab_contr[0]);
return 0;
}
static const struct reg_t rtab_cue_int[] = {
/*--------------------------*/
{NR2_CUE_CON_DIF0, 0, 32, 0x1400, "NR2_CUE_CON_DIF0",
NULL,
NULL},
{NR2_CUE_CON_DIF1, 0, 32, 0x80064, "NR2_CUE_CON_DIF1",
NULL,
NULL},
{NR2_CUE_CON_DIF2, 0, 32, 0x80064, "NR2_CUE_CON_DIF2",
NULL,
NULL},
{NR2_CUE_CON_DIF3, 0, 32, 0x80a0a, "NR2_CUE_CON_DIF3",
NULL,
NULL},
{NR2_CUE_PRG_DIF, 0, 32, 0x80a0a, "NR2_CUE_PRG_DIF",
NULL,
NULL},
{TABLE_FLG_END, 0, 0, 0, "end", "end", ""},
/*--------------------------*/
};
/************************************************
* register table
************************************************/
static bool di_g_rtab_cue(const struct reg_t **tab, unsigned int *tabsize)
{
*tab = &rtab_cue_int[0];
*tabsize = ARRAY_SIZE(rtab_cue_int);
return true;
}
static unsigned int dim_reg_read(unsigned int addr)
{
return aml_read_vcbus(addr);
}
static const struct reg_acc di_pre_regset = {
.wr = dim_DI_Wr,
.rd = dim_reg_read,
.bwr = dim_RDMA_WR_BITS,
.brd = dim_RDMA_RD_BITS,
};
static bool di_wr_tab(const struct reg_acc *ops,
const struct reg_t *ptab, unsigned int tabsize)
{
int i;
const struct reg_t *pl;
pl = ptab;
if (!ops ||
!tabsize ||
!ptab)
return false;
for (i = 0; i < tabsize; i++) {
if (pl->add == TABLE_FLG_END ||
i > TABLE_LEN_MAX) {
break;
}
if (pl->wid == 32)
ops->wr(pl->add, pl->df_val);
else
ops->bwr(pl->add, pl->df_val, pl->bit, pl->wid);
pl++;
}
return true;
}
bool dim_wr_cue_int(void)
{
const struct reg_t *ptab;
unsigned int tabsize;
di_g_rtab_cue(&ptab, &tabsize);
di_wr_tab(&di_pre_regset,
ptab,
tabsize);
PR_INF("%s:finish\n", __func__);
return true;
}
int dim_reg_cue_int_show(struct seq_file *seq, void *v)
{
dbg_reg_tab(seq, &rtab_cue_int[0]);
return 0;
}

View File

@@ -0,0 +1,26 @@
/*
* drivers/amlogic/media/di_multi/di_reg_tab.h
*
* Copyright (C) 2017 Amlogic, Inc. 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
*/
#ifndef __DI_REG_TABL_H__
#define __DI_REG_TABL_H__
int reg_con_show(struct seq_file *seq, void *v);
bool dim_wr_cue_int(void);
int dim_reg_cue_int_show(struct seq_file *seq, void *v);
#endif /*__DI_REG_TABL_H__*/

View File

@@ -0,0 +1,754 @@
/*
* drivers/amlogic/media/di_multi/di_sys.c
*
* Copyright (C) 2017 Amlogic, Inc. 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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/version.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/semaphore.h>
#include <linux/workqueue.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/major.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
#include <linux/cdev.h>
#include <linux/proc_fs.h>
#include <linux/list.h>
#include <linux/of_reserved_mem.h>
#include <linux/of_irq.h>
#include <linux/uaccess.h>
#include <linux/of_fdt.h>
#include <linux/cma.h>
#include <linux/dma-contiguous.h>
#include <linux/ctype.h>
#include <linux/string.h>
#include <linux/of_device.h>
#include <linux/amlogic/media/vfm/vframe.h>
/*dma_get_cma_size_int_byte*/
#include <linux/amlogic/media/codec_mm/codec_mm.h>
#include "deinterlace_dbg.h"
#include "deinterlace.h"
#include "di_data_l.h"
#include "di_data.h"
#include "di_dbg.h"
#include "di_vframe.h"
#include "di_task.h"
#include "di_prc.h"
#include "di_sys.h"
#include "di_api.h"
#include "register.h"
#include "nr_downscale.h"
static di_dev_t *di_pdev;
struct di_dev_s *get_dim_de_devp(void)
{
return di_pdev;
}
unsigned int di_get_dts_nrds_en(void)
{
return get_dim_de_devp()->nrds_enable;
}
/********************************************
* mem
*******************************************/
/********************************************/
static ssize_t
show_config(struct device *dev,
struct device_attribute *attr, char *buf)
{
int pos = 0;
return pos;
}
static ssize_t show_tvp_region(struct device *dev,
struct device_attribute *attr, char *buff)
{
ssize_t len = 0;
struct di_dev_s *de_devp = get_dim_de_devp();
len = sprintf(buff, "segment DI:%lx - %lx (size:0x%x)\n",
de_devp->mem_start,
de_devp->mem_start + de_devp->mem_size - 1,
de_devp->mem_size);
return len;
}
static
ssize_t
show_log(struct device *dev, struct device_attribute *attr, char *buf)
{
return dim_read_log(buf);
}
static ssize_t
show_frame_format(struct device *dev,
struct device_attribute *attr, char *buf)
{
int ret = 0;
unsigned int channel = get_current_channel(); /*debug only*/
struct di_pre_stru_s *ppre = get_pre_stru(channel);
if (get_init_flag(channel))
ret += sprintf(buf + ret, "%s\n",
ppre->cur_prog_flag
? "progressive" : "interlace");
else
ret += sprintf(buf + ret, "%s\n", "null");
return ret;
}
static DEVICE_ATTR(frame_format, 0444, show_frame_format, NULL);
static DEVICE_ATTR(config, 0640, show_config, store_config);
static DEVICE_ATTR(debug, 0200, NULL, store_dbg);
static DEVICE_ATTR(dump_pic, 0200, NULL, store_dump_mem);
static DEVICE_ATTR(log, 0640, show_log, store_log);
static DEVICE_ATTR(provider_vframe_status, 0444, show_vframe_status, NULL);
static DEVICE_ATTR(tvp_region, 0444, show_tvp_region, NULL);
/********************************************/
static int di_open(struct inode *node, struct file *file)
{
di_dev_t *di_in_devp;
/* Get the per-device structure that contains this cdev */
di_in_devp = container_of(node->i_cdev, di_dev_t, cdev);
file->private_data = di_in_devp;
return 0;
}
static int di_release(struct inode *node, struct file *file)
{
/* di_dev_t *di_in_devp = file->private_data; */
/* Reset file pointer */
/* Release some other fields */
file->private_data = NULL;
return 0;
}
static long di_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
long ret = 0;
if (_IOC_TYPE(cmd) != _DI_) {
PR_ERR("%s invalid command: %u\n", __func__, cmd);
return -EFAULT;
}
#if 0
dbg_reg("no pq\n");
return 0;
#endif
switch (cmd) {
case AMDI_IOC_SET_PQ_PARM:
ret = dim_pq_load_io(arg);
break;
default:
break;
}
return ret;
}
#ifdef CONFIG_COMPAT
static long di_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
unsigned long ret;
arg = (unsigned long)compat_ptr(arg);
ret = di_ioctl(file, cmd, arg);
return ret;
}
#endif
static const struct file_operations di_fops = {
.owner = THIS_MODULE,
.open = di_open,
.release = di_release,
.unlocked_ioctl = di_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = di_compat_ioctl,
#endif
};
static int dim_rev_mem(struct di_dev_s *di_devp)
{
unsigned int ch;
unsigned int o_size;
unsigned long rmstart;
unsigned int rmsize;
unsigned int flg_map;
if (di_devp && !di_devp->flag_cma) {
dil_get_rev_mem(&rmstart, &rmsize);
dil_get_flg(&flg_map);
if (!rmstart) {
PR_ERR("%s:reserved mem start add is 0\n", __func__);
return -1;
}
di_devp->mem_start = rmstart;
di_devp->mem_size = rmsize;
if (!flg_map)
di_devp->flags |= DI_MAP_FLAG;
o_size = rmsize / DI_CHANNEL_NUB;
for (ch = 0; ch < DI_CHANNEL_NUB; ch++) {
di_set_mem_info(ch,
di_devp->mem_start + (o_size * ch),
o_size);
PR_INF("rmem:ch[%d]:start:0x%lx, size:%uB\n",
ch,
(di_devp->mem_start + (o_size * ch)),
o_size);
}
PR_INF("rmem:0x%lx, size %uMB.\n",
di_devp->mem_start, (di_devp->mem_size >> 20));
di_devp->mem_flg = true;
return 0;
}
PR_INF("%s:no dev or no rev mem\n", __func__);
return -1;
}
bool dim_rev_mem_check(void)/*tmp*/
{
di_dev_t *di_devp = get_dim_de_devp();
if (di_devp && !di_devp->flag_cma && di_devp->mem_flg)
return true;
if (!di_devp) {
PR_ERR("%s:no dev\n", __func__);
return false;
}
PR_INF("%s\n", __func__);
dim_rev_mem(di_devp);
return true;
}
#define ARY_MATCH (1)
#ifdef ARY_MATCH
static const struct di_meson_data data_g12a = {
.name = "dim_g12a",
};
static const struct di_meson_data data_sm1 = {
.name = "dim_sm1",
};
/* #ifdef CONFIG_USE_OF */
static const struct of_device_id amlogic_deinterlace_dt_match[] = {
/*{ .compatible = "amlogic, deinterlace", },*/
{ .compatible = "amlogic, dim-g12a",
.data = &data_g12a,
}, { .compatible = "amlogic, dim-g12b",
.data = &data_sm1,
}, { .compatible = "amlogic, dim-sm1",
.data = &data_sm1,
}, {}
};
#endif
static int dim_probe(struct platform_device *pdev)
{
int ret = 0;
struct di_dev_s *di_devp = NULL;
int i;
#ifdef ARY_MATCH
const struct of_device_id *match;
struct di_data_l_s *pdata;
#endif
PR_INF("%s:\n", __func__);
#if 1 /*move from init to here*/
di_pdev = kzalloc(sizeof(*di_pdev), GFP_KERNEL);
if (!di_pdev) {
PR_ERR("%s fail to allocate memory.\n", __func__);
goto fail_kmalloc_dev;
}
/******************/
ret = alloc_chrdev_region(&di_pdev->devno, 0, DI_COUNT, DEVICE_NAME);
if (ret < 0) {
PR_ERR("%s: failed to allocate major number\n", __func__);
goto fail_alloc_cdev_region;
}
PR_INF("%s: major %d\n", __func__, MAJOR(di_pdev->devno));
di_pdev->pclss = class_create(THIS_MODULE, CLASS_NAME);
if (IS_ERR(di_pdev->pclss)) {
ret = PTR_ERR(di_pdev->pclss);
PR_ERR("%s: failed to create class\n", __func__);
goto fail_class_create;
}
#endif
di_devp = di_pdev;
/* *********new********* */
di_pdev->data_l = NULL;
di_pdev->data_l = kzalloc(sizeof(struct di_data_l_s), GFP_KERNEL);
if (!di_pdev->data_l) {
PR_ERR("%s fail to allocate data l.\n", __func__);
goto fail_kmalloc_datal;
}
/*memset(di_pdev->data_l, 0, sizeof(struct di_data_l_s));*/
/*pr_info("\tdata size: %ld\n", sizeof(struct di_data_l_s));*/
/************************/
if (!dip_prob())
goto fail_cdev_add;
di_devp->flags |= DI_SUSPEND_FLAG;
cdev_init(&di_devp->cdev, &di_fops);
di_devp->cdev.owner = THIS_MODULE;
ret = cdev_add(&di_devp->cdev, di_devp->devno, DI_COUNT);
if (ret)
goto fail_cdev_add;
di_devp->devt = MKDEV(MAJOR(di_devp->devno), 0);
di_devp->dev = device_create(di_devp->pclss, &pdev->dev,
di_devp->devt, di_devp, "di%d", 0);
if (!di_devp->dev) {
pr_error("device_create create error\n");
goto fail_cdev_add;
}
dev_set_drvdata(di_devp->dev, di_devp);
platform_set_drvdata(pdev, di_devp);
#ifdef ARY_MATCH
/************************/
match = of_match_device(amlogic_deinterlace_dt_match,
&pdev->dev);
if (!match) {
PR_ERR("%s,no matched table\n", __func__);
goto fail_cdev_add;
}
pdata = (struct di_data_l_s *)di_pdev->data_l;
pdata->mdata = match->data;
PR_INF("match name: %s\n", pdata->mdata->name);
#endif
ret = of_reserved_mem_device_init(&pdev->dev);
if (ret != 0)
PR_INF("no reserved mem.\n");
ret = of_property_read_u32(pdev->dev.of_node,
"flag_cma", &di_devp->flag_cma);
if (ret)
PR_ERR("DI-%s: get flag_cma error.\n", __func__);
else
PR_INF("flag_cma=%d\n", di_devp->flag_cma);
dim_rev_mem(di_devp);
ret = of_property_read_u32(pdev->dev.of_node,
"nrds-enable", &di_devp->nrds_enable);
ret = of_property_read_u32(pdev->dev.of_node,
"pps-enable", &di_devp->pps_enable);
/*di pre h scaling down :sm1 tm2*/
/*pre_hsc_down_en;*/
di_devp->h_sc_down_en = di_mp_uit_get(eDI_MP_pre_hsc_down_en);
if (di_devp->flag_cma >= 1) {
#ifdef CONFIG_CMA
di_devp->pdev = pdev;
di_devp->flags |= DI_MAP_FLAG;
#if 0
di_devp->mem_size = dma_get_cma_size_int_byte(&pdev->dev);
#else
if (di_devp->flag_cma == 1 ||
di_devp->flag_cma == 2) {
di_devp->mem_size
= dma_get_cma_size_int_byte(&pdev->dev);
PR_INF("mem size from dts:0x%x\n", di_devp->mem_size);
}
if (di_devp->mem_size <= 0x800000) {/*need check??*/
di_devp->mem_size = 0x2800000;
/*(flag_cma ? 3) reserved in*/
/*codec mm : cma in codec mm*/
if (di_devp->flag_cma != 3) {
/*no di cma, try use*/
/*cma from codec mm*/
di_devp->flag_cma = 4;
}
}
#endif
pr_info("DI: CMA size 0x%x.\n", di_devp->mem_size);
if (di_devp->flag_cma == 2) {
if (dim_cma_alloc_total(di_devp))
dip_cma_st_set_ready_all();
}
#endif
} else {
dip_cma_st_set_ready_all();
}
/* mutex_init(&di_devp->cma_mutex); */
INIT_LIST_HEAD(&di_devp->pq_table_list);
atomic_set(&di_devp->pq_flag, 0);
di_devp->pre_irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
pr_info("pre_irq:%d\n",
di_devp->pre_irq);
di_devp->post_irq = irq_of_parse_and_map(pdev->dev.of_node, 1);
pr_info("post_irq:%d\n",
di_devp->post_irq);
di_pr_info("%s allocate rdma channel %d.\n", __func__,
di_devp->rdma_handle);
if (cpu_after_eq(MESON_CPU_MAJOR_ID_TXL)) {
dim_get_vpu_clkb(&pdev->dev, di_devp);
#ifdef CLK_TREE_SUPPORT
clk_prepare_enable(di_devp->vpu_clkb);
pr_info("DI:enable vpu clkb.\n");
#else
aml_write_hiubus(HHI_VPU_CLKB_CNTL, 0x1000100);
#endif
}
di_devp->flags &= (~DI_SUSPEND_FLAG);
ret = of_property_read_u32(pdev->dev.of_node,
"buffer-size", &di_devp->buffer_size);
if (ret)
PR_ERR("DI-%s: get buffer size error.\n", __func__);
/* set flag to indicate that post_wr is supportted */
ret = of_property_read_u32(pdev->dev.of_node,
"post-wr-support",
&di_devp->post_wr_support);
if (ret)
dimp_set(eDI_MP_post_wr_support, 0);/*post_wr_support = 0;*/
else /*post_wr_support = di_devp->post_wr_support;*/
dimp_set(eDI_MP_post_wr_support, di_devp->post_wr_support);
ret = of_property_read_u32(pdev->dev.of_node,
"nr10bit-support",
&di_devp->nr10bit_support);
if (ret)
dimp_set(eDI_MP_nr10bit_support, 0);/*nr10bit_support = 0;*/
else /*nr10bit_support = di_devp->nr10bit_support;*/
dimp_set(eDI_MP_nr10bit_support, di_devp->nr10bit_support);
#ifdef DI_USE_FIXED_CANVAS_IDX
if (dim_get_canvas()) {
pr_dbg("DI get canvas error.\n");
ret = -EEXIST;
return ret;
}
#endif
device_create_file(di_devp->dev, &dev_attr_config);
device_create_file(di_devp->dev, &dev_attr_debug);
device_create_file(di_devp->dev, &dev_attr_dump_pic);
device_create_file(di_devp->dev, &dev_attr_log);
device_create_file(di_devp->dev, &dev_attr_provider_vframe_status);
device_create_file(di_devp->dev, &dev_attr_frame_format);
device_create_file(di_devp->dev, &dev_attr_tvp_region);
/*pd_device_files_add*/
get_ops_pd()->prob(di_devp->dev);
get_ops_nr()->nr_drv_init(di_devp->dev);
for (i = 0; i < DI_CHANNEL_NUB; i++) {
set_init_flag(i, false);
set_reg_flag(i, false);
}
set_or_act_flag(true);
/*PR_INF("\t 11\n");*/
ret = devm_request_irq(&pdev->dev, di_devp->pre_irq, &dim_irq,
IRQF_SHARED,
"pre_di", (void *)"pre_di");
if (di_devp->post_wr_support) {
ret = devm_request_irq(&pdev->dev, di_devp->post_irq,
&dim_post_irq,
IRQF_SHARED, "post_di",
(void *)"post_di");
}
di_devp->sema_flg = 1; /*di_sema_init_flag = 1;*/
dimh_hw_init(dimp_get(eDI_MP_pulldown_enable),
dimp_get(eDI_MP_mcpre_en));
dim_set_di_flag();
task_start();
post_mif_sw(false);
dim_debugfs_init(); /*2018-07-18 add debugfs*/
dimh_patch_post_update_mc_sw(DI_MC_SW_IC, true);
pr_info("%s:ok\n", __func__);
return ret;
fail_cdev_add:
pr_info("%s:fail_cdev_add\n", __func__);
kfree(di_devp->data_l);
fail_kmalloc_datal:
pr_info("%s:fail_kmalloc datal\n", __func__);
#if 1 /*move from init*/
/*fail_pdrv_register:*/
class_destroy(di_pdev->pclss);
fail_class_create:
unregister_chrdev_region(di_pdev->devno, DI_COUNT);
fail_alloc_cdev_region:
kfree(di_pdev);
fail_kmalloc_dev:
return ret;
#endif
return ret;
}
static int dim_remove(struct platform_device *pdev)
{
struct di_dev_s *di_devp = NULL;
PR_INF("%s:\n", __func__);
di_devp = platform_get_drvdata(pdev);
dimh_hw_uninit();
if (cpu_after_eq(MESON_CPU_MAJOR_ID_TXLX))
clk_disable_unprepare(di_devp->vpu_clkb);
di_devp->di_event = 0xff;
dim_uninit_buf(1, 0);/*channel 0*/
di_set_flg_hw_int(false);
task_stop();
dim_rdma_exit();
/* Remove the cdev */
device_remove_file(di_devp->dev, &dev_attr_config);
device_remove_file(di_devp->dev, &dev_attr_debug);
device_remove_file(di_devp->dev, &dev_attr_log);
device_remove_file(di_devp->dev, &dev_attr_dump_pic);
device_remove_file(di_devp->dev, &dev_attr_provider_vframe_status);
device_remove_file(di_devp->dev, &dev_attr_frame_format);
device_remove_file(di_devp->dev, &dev_attr_tvp_region);
/*pd_device_files_del*/
get_ops_pd()->remove(di_devp->dev);
get_ops_nr()->nr_drv_uninit(di_devp->dev);
cdev_del(&di_devp->cdev);
if (di_devp->flag_cma == 2) {
if (dma_release_from_contiguous(&pdev->dev,
di_devp->total_pages,
di_devp->mem_size >> PAGE_SHIFT)) {
di_devp->total_pages = NULL;
di_devp->mem_start = 0;
pr_dbg("DI CMA total release ok.\n");
} else {
pr_dbg("DI CMA total release fail.\n");
}
if (di_pdev->nrds_enable) {
dim_nr_ds_buf_uninit(di_pdev->flag_cma,
&pdev->dev);
}
}
device_destroy(di_devp->pclss, di_devp->devno);
/* free drvdata */
dev_set_drvdata(&pdev->dev, NULL);
platform_set_drvdata(pdev, NULL);
#if 1 /*move to remove*/
class_destroy(di_pdev->pclss);
dim_debugfs_exit();
dip_exit();
unregister_chrdev_region(di_pdev->devno, DI_COUNT);
#endif
kfree(di_devp->data_l);
kfree(di_pdev);
PR_INF("%s:finish\n", __func__);
return 0;
}
static void dim_shutdown(struct platform_device *pdev)
{
struct di_dev_s *di_devp = NULL;
int i;
di_devp = platform_get_drvdata(pdev);
for (i = 0; i < DI_CHANNEL_NUB; i++)
set_init_flag(i, false);
if (is_meson_txlx_cpu())
dim_top_gate_control(true, true);
else
dim_DI_Wr(DI_CLKG_CTRL, 0x2);
if (!is_meson_txlx_cpu())
diext_clk_b_sw(false);
PR_INF("%s.\n", __func__);
}
#ifdef CONFIG_PM
static void di_clear_for_suspend(struct di_dev_s *di_devp)
{
unsigned int channel = get_current_channel(); /*tmp*/
pr_info("%s\n", __func__);
di_vframe_unreg(channel);/*have flag*/
if (dip_chst_get(channel) != eDI_TOP_STATE_IDLE)
dim_unreg_process_irq(channel);
dip_cma_close();
pr_info("%s end\n", __func__);
}
/* must called after lcd */
static int di_suspend(struct device *dev)
{
struct di_dev_s *di_devp = NULL;
di_devp = dev_get_drvdata(dev);
di_devp->flags |= DI_SUSPEND_FLAG;
di_clear_for_suspend(di_devp);
if (!is_meson_txlx_cpu())
diext_clk_b_sw(false);
if (cpu_after_eq(MESON_CPU_MAJOR_ID_TXHD))
clk_disable_unprepare(di_devp->vpu_clkb);
PR_INF("%s\n", __func__);
return 0;
}
/* must called before lcd */
static int di_resume(struct device *dev)
{
struct di_dev_s *di_devp = NULL;
PR_INF("%s\n", __func__);
di_devp = dev_get_drvdata(dev);
if (cpu_after_eq(MESON_CPU_MAJOR_ID_TXL))
clk_prepare_enable(di_devp->vpu_clkb);
di_devp->flags &= ~DI_SUSPEND_FLAG;
/************/
PR_INF("%s finish\n", __func__);
return 0;
}
static const struct dev_pm_ops di_pm_ops = {
.suspend_late = di_suspend,
.resume_early = di_resume,
};
#endif
#ifndef ARY_MATCH
/* #ifdef CONFIG_USE_OF */
static const struct of_device_id amlogic_deinterlace_dt_match[] = {
/*{ .compatible = "amlogic, deinterlace", },*/
{ .compatible = "amlogic, dim-g12a", },
{}
};
#endif
/* #else */
/* #define amlogic_deinterlace_dt_match NULL */
/* #endif */
static struct platform_driver di_driver = {
.probe = dim_probe,
.remove = dim_remove,
.shutdown = dim_shutdown,
.driver = {
.name = DEVICE_NAME,
.owner = THIS_MODULE,
.of_match_table = amlogic_deinterlace_dt_match,
#ifdef CONFIG_PM
.pm = &di_pm_ops,
#endif
}
};
static int __init dim_module_init(void)
{
int ret = 0;
PR_INF("%s\n", __func__);
ret = platform_driver_register(&di_driver);
if (ret != 0) {
PR_ERR("%s: failed to register driver\n", __func__);
/*goto fail_pdrv_register;*/
return -ENODEV;
}
PR_INF("%s finish\n", __func__);
return 0;
}
static void __exit dim_module_exit(void)
{
platform_driver_unregister(&di_driver);
PR_INF("%s: ok.\n", __func__);
}
module_init(dim_module_init);
module_exit(dim_module_exit);
MODULE_DESCRIPTION("AMLOGIC MULTI-DI driver");
MODULE_LICENSE("GPL");
MODULE_VERSION("4.0.0");

View File

@@ -0,0 +1,26 @@
/*
* drivers/amlogic/media/di_multi/di_sys.h
*
* Copyright (C) 2017 Amlogic, Inc. 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
*/
#ifndef __DI_SYS_H__
#define __DI_SYS_H__
#define DEVICE_NAME "di_multi"
#define CLASS_NAME "deinterlace"
bool dim_rev_mem_check(void);
#endif /*__DI_SYS_H__*/

View File

@@ -0,0 +1,315 @@
/*
* drivers/amlogic/media/di_multi/di_task.c
*
* Copyright (C) 2017 Amlogic, Inc. 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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/kthread.h> /*ary add*/
#include <linux/freezer.h>
#include <linux/semaphore.h>
#include <linux/kfifo.h>
#include <linux/spinlock.h>
#include "deinterlace.h"
#include "di_data_l.h"
#include "di_prc.h"
#include "di_task.h"
#include "di_vframe.h"
static void task_wakeup(struct di_task *tsk);
unsigned int di_dbg_task_flg; /*debug only*/
bool task_send_cmd(unsigned int cmd)
{
struct di_task *tsk = get_task();
unsigned int val;
dbg_reg("%s:cmd[%d]:\n", __func__, cmd);
if (kfifo_is_full(&tsk->fifo_cmd)) {
if (kfifo_out(&tsk->fifo_cmd, &val, sizeof(unsigned int))
!= sizeof(unsigned int)) {
PR_ERR("%s:can't out\n", __func__);
return false;
}
PR_ERR("%s:lost cmd[%d]\n", __func__, val);
tsk->err_cmd_cnt++;
/*return false;*/
}
kfifo_in_spinlocked(&tsk->fifo_cmd, &cmd, sizeof(unsigned int),
&tsk->lock_cmd);
task_wakeup(tsk);
return true;
}
void task_send_ready(void)
{
struct di_task *tsk = get_task();
task_wakeup(tsk);
}
#if 0
bool task_have_vf(unsigned int ch)
{
struct di_task *tsk = get_task();
task_wakeup(tsk);
}
#endif
bool task_get_cmd(unsigned int *cmd)
{
struct di_task *tsk = get_task();
unsigned int val;
if (kfifo_is_empty(&tsk->fifo_cmd))
return false;
if (kfifo_out(&tsk->fifo_cmd, &val, sizeof(unsigned int))
!= sizeof(unsigned int))
return false;
*cmd = val;
return true;
}
void task_polling_cmd(void)
{
int i;
union DI_L_CMD_BITS cmdbyte;
for (i = 0; i < MAX_KFIFO_L_CMD_NUB; i++) {
if (!task_get_cmd(&cmdbyte.cmd32))
break;
dip_chst_process_reg(cmdbyte.b.ch);
}
}
static int task_is_exiting(struct di_task *tsk)
{
if (tsk->exit)
return 1;
/* if (afepriv->dvbdev->writers == 1)
* if (time_after_eq(jiffies, fepriv->release_jiffies +
* dvb_shutdown_timeout * HZ))
* return 1;
*/
return 0;
}
static int task_should_wakeup(struct di_task *tsk)
{
if (tsk->wakeup) {
tsk->wakeup = 0;
/*dbg only dbg_tsk("wkg[%d]\n", di_dbg_task_flg);*/
return 1;
}
return task_is_exiting(tsk);
}
static void task_wakeup(struct di_task *tsk)
{
tsk->wakeup = 1;
wake_up_interruptible(&tsk->wait_queue);
/*dbg_tsk("wks[%d]\n", di_dbg_task_flg);*/
}
static int di_test_thread(void *data)
{
struct di_task *tsk = data;
bool semheld = false;
tsk->delay = HZ;
tsk->status = 0;
tsk->wakeup = 0;
#if 0
tsk->reinitialise = 0;
tsk->needfinish = 0;
tsk->finishflg = 0;
#endif
set_freezable();
while (1) {
up(&tsk->sem);/* is locked when we enter the thread... */
restart:
wait_event_interruptible_timeout(tsk->wait_queue,
task_should_wakeup(tsk) ||
kthread_should_stop() ||
freezing(current),
tsk->delay);
di_dbg_task_flg = 1;
if (kthread_should_stop() || task_is_exiting(tsk)) {
/* got signal or quitting */
if (!down_interruptible(&tsk->sem))
semheld = true;
tsk->exit = 1;
break;
}
if (try_to_freeze())
goto restart;
if (down_interruptible(&tsk->sem))
break;
#if 0
if (tsk->reinitialise) {
/*dvb_frontend_init(fe);*/
tsk->reinitialise = 0;
}
#endif
di_dbg_task_flg = 2;
task_polling_cmd();
di_dbg_task_flg = 3;
dip_chst_process_ch();
di_dbg_task_flg = 4;
if (get_reg_flag_all())
dip_hw_process();
di_dbg_task_flg = 0;
}
tsk->thread = NULL;
if (kthread_should_stop())
tsk->exit = 1;
else
tsk->exit = 0;
/*mb();*/
if (semheld)
up(&tsk->sem);
task_wakeup(tsk);/*?*/
return 0;
}
void task_stop(void/*struct di_task *tsk*/)
{
struct di_task *tsk = get_task();
#if 1 /*not use cmd*/
pr_info(".");
/*--------------------*/
/*cmd buf*/
if (tsk->flg_cmd) {
kfifo_free(&tsk->fifo_cmd);
tsk->flg_cmd = 0;
}
/*tsk->lock_cmd = SPIN_LOCK_UNLOCKED;*/
spin_lock_init(&tsk->lock_cmd);
tsk->err_cmd_cnt = 0;
/*--------------------*/
#endif
tsk->exit = 1;
/*mb();*/
if (!tsk->thread)
return;
kthread_stop(tsk->thread);
sema_init(&tsk->sem, 1);
tsk->status = 0;
/* paranoia check in case a signal arrived */
if (tsk->thread)
PR_ERR("warning: thread %p won't exit\n", tsk->thread);
}
int task_start(void)
{
int ret;
int flg_err;
struct di_task *tsk = get_task();
struct task_struct *fe_thread;
struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 };
pr_info(".");
flg_err = 0;
#if 1 /*not use cmd*/
/*--------------------*/
/*cmd buf*/
/*tsk->lock_cmd = SPIN_LOCK_UNLOCKED;*/
spin_lock_init(&tsk->lock_cmd);
tsk->err_cmd_cnt = 0;
ret = kfifo_alloc(&tsk->fifo_cmd,
sizeof(unsigned int) * MAX_KFIFO_L_CMD_NUB,
GFP_KERNEL);
if (ret < 0) {
tsk->flg_cmd = false;
PR_ERR("%s:can't get kfifo\n", __func__);
return -1;
}
tsk->flg_cmd = true;
#endif
/*--------------------*/
sema_init(&tsk->sem, 1);
init_waitqueue_head(&tsk->wait_queue);
if (tsk->thread) {
if (!tsk->exit)
return 0;
task_stop();
}
if (signal_pending(current)) {
if (tsk->flg_cmd) {
kfifo_free(&tsk->fifo_cmd);
tsk->flg_cmd = 0;
}
return -EINTR;
}
if (down_interruptible(&tsk->sem)) {
if (tsk->flg_cmd) {
kfifo_free(&tsk->fifo_cmd);
tsk->flg_cmd = 0;
}
return -EINTR;
}
tsk->status = 0;
tsk->exit = 0;
tsk->thread = NULL;
/*mb();*/
fe_thread = kthread_run(di_test_thread, tsk, "aml-ditest-0");
if (IS_ERR(fe_thread)) {
ret = PTR_ERR(fe_thread);
PR_ERR(" failed to start kthread (%d)\n", ret);
up(&tsk->sem);
tsk->flg_init = 0;
return ret;
}
sched_setscheduler_nocheck(fe_thread, SCHED_FIFO, &param);
tsk->flg_init = 1;
tsk->thread = fe_thread;
return 0;
}
void dbg_task(void)
{
struct di_task *tsk = get_task();
tsk->status = 1;
task_wakeup(tsk);
}

View File

@@ -0,0 +1,36 @@
/*
* drivers/amlogic/media/di_multi/di_task.h
*
* Copyright (C) 2017 Amlogic, Inc. 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
*/
#ifndef __DI_TASK_H__
#define __DI_TASK_H__
extern unsigned int di_dbg_task_flg; /*debug only*/
enum eTSK_STATE {
eTSK_STATE_IDLE,
eTSK_STATE_WORKING,
};
void task_stop(void);
int task_start(void);
void dbg_task(void);
bool task_send_cmd(unsigned int cmd);
void task_send_ready(void);
#endif /*__DI_TASK_H__*/

View File

@@ -0,0 +1,556 @@
/*
* drivers/amlogic/media/di_multi/di_vframe.c
*
* Copyright (C) 2017 Amlogic, Inc. 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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/semaphore.h>
#include <linux/kfifo.h>
#include <linux/spinlock.h>
#include "deinterlace.h"
#include "di_data_l.h"
#include "di_pre.h"
#include "di_prc.h"
#include "di_dbg.h"
#include "di_vframe.h"
struct dev_vfram_t *get_dev_vframe(unsigned int ch)
{
if (ch < DI_CHANNEL_NUB)
return &get_datal()->ch_data[ch].vfm;
pr_info("err:%s ch overflow %d\n", __func__, ch);
return &get_datal()->ch_data[0].vfm;
}
const char * const di_rev_name[4] = {
"deinterlace",
"dimulti.1",
"dimulti.2",
"dimulti.3",
};
void dev_vframe_reg(struct dev_vfram_t *pvfm)
{
if (pvfm->reg) {
PR_WARN("duplicate reg\n");
return;
}
vf_reg_provider(&pvfm->di_vf_prov);
vf_notify_receiver(pvfm->name, VFRAME_EVENT_PROVIDER_START, NULL);
pvfm->reg = 1;
}
void dev_vframe_unreg(struct dev_vfram_t *pvfm)
{
if (pvfm->reg) {
vf_unreg_provider(&pvfm->di_vf_prov);
pvfm->reg = 0;
} else {
PR_WARN("duplicate ureg\n");
}
}
void di_vframe_reg(unsigned int ch)
{
struct dev_vfram_t *pvfm;
pvfm = get_dev_vframe(ch);
dev_vframe_reg(pvfm);
}
void di_vframe_unreg(unsigned int ch)
{
struct dev_vfram_t *pvfm;
pvfm = get_dev_vframe(ch);
dev_vframe_unreg(pvfm);
}
/*--------------------------*/
const char * const di_receiver_event_cmd[] = {
"",
"_UNREG",
"_LIGHT_UNREG",
"_START",
NULL, /* "_VFRAME_READY", */
NULL, /* "_QUREY_STATE", */
"_RESET",
NULL, /* "_FORCE_BLACKOUT", */
"_REG",
"_LIGHT_UNREG_RETURN_VFRAME",
NULL, /* "_DPBUF_CONFIG", */
NULL, /* "_QUREY_VDIN2NR", */
NULL, /* "_SET_3D_VFRAME_INTERLEAVE", */
NULL, /* "_FR_HINT", */
NULL, /* "_FR_END_HINT", */
NULL, /* "_QUREY_DISPLAY_INFO", */
NULL, /* "_PROPERTY_CHANGED", */
};
#define VFRAME_EVENT_PROVIDER_CMD_MAX 16
static int di_receiver_event_fun(int type, void *data, void *arg)
{
struct dev_vfram_t *pvfm;
unsigned int ch;
int ret = 0;
ch = *(int *)arg;
pvfm = get_dev_vframe(ch);
if (type <= VFRAME_EVENT_PROVIDER_CMD_MAX &&
di_receiver_event_cmd[type]) {
dbg_ev("ch[%d]:%s,%d:%s\n", ch, __func__,
type,
di_receiver_event_cmd[type]);
}
switch (type) {
case VFRAME_EVENT_PROVIDER_UNREG:
ret = di_ori_event_unreg(ch);
/* task_send_cmd(LCMD1(eCMD_UNREG, 0));*/
break;
case VFRAME_EVENT_PROVIDER_REG:
/*dev_vframe_reg(pvfm);*/
ret = di_ori_event_reg(data, ch);
/* task_send_cmd(LCMD1(eCMD_REG, 0));*/
break;
case VFRAME_EVENT_PROVIDER_START:
break;
case VFRAME_EVENT_PROVIDER_LIGHT_UNREG:
ret = di_ori_event_light_unreg(ch);
break;
case VFRAME_EVENT_PROVIDER_VFRAME_READY:
ret = di_ori_event_ready(ch);
break;
case VFRAME_EVENT_PROVIDER_QUREY_STATE:
ret = di_ori_event_qurey_state(ch);
break;
case VFRAME_EVENT_PROVIDER_RESET:
ret = di_ori_event_reset(ch);
break;
case VFRAME_EVENT_PROVIDER_LIGHT_UNREG_RETURN_VFRAME:
ret = di_ori_event_light_unreg_revframe(ch);
break;
case VFRAME_EVENT_PROVIDER_QUREY_VDIN2NR:
ret = di_ori_event_qurey_vdin2nr(ch);
break;
case VFRAME_EVENT_PROVIDER_SET_3D_VFRAME_INTERLEAVE:
di_ori_event_set_3D(type, data, ch);
break;
case VFRAME_EVENT_PROVIDER_FR_HINT:
case VFRAME_EVENT_PROVIDER_FR_END_HINT:
vf_notify_receiver(pvfm->name, type, data);
break;
default:
break;
}
return ret;
}
static const struct vframe_receiver_op_s di_vf_receiver = {
.event_cb = di_receiver_event_fun
};
bool vf_type_is_prog(unsigned int type)
{
bool ret = (type & VIDTYPE_TYPEMASK) == 0 ? true : false;
return ret;
}
bool vf_type_is_interlace(unsigned int type)
{
bool ret = (type & VIDTYPE_INTERLACE) ? true : false;
return ret;
}
bool vf_type_is_top(unsigned int type)
{
bool ret = ((type & VIDTYPE_TYPEMASK) == VIDTYPE_INTERLACE_TOP)
? true : false;
return ret;
}
bool vf_type_is_bottom(unsigned int type)
{
bool ret = ((type & VIDTYPE_INTERLACE_BOTTOM)
== VIDTYPE_INTERLACE_BOTTOM)
? true : false;
return ret;
}
bool vf_type_is_inter_first(unsigned int type)
{
bool ret = (type & VIDTYPE_INTERLACE_TOP) ? true : false;
return ret;
}
bool vf_type_is_mvc(unsigned int type)
{
bool ret = (type & VIDTYPE_MVC) ? true : false;
return ret;
}
bool vf_type_is_no_video_en(unsigned int type)
{
bool ret = (type & VIDTYPE_NO_VIDEO_ENABLE) ? true : false;
return ret;
}
bool vf_type_is_VIU422(unsigned int type)
{
bool ret = (type & VIDTYPE_VIU_422) ? true : false;
return ret;
}
bool vf_type_is_VIU_FIELD(unsigned int type)
{
bool ret = (type & VIDTYPE_VIU_FIELD) ? true : false;
return ret;
}
bool vf_type_is_VIU_SINGLE(unsigned int type)
{
bool ret = (type & VIDTYPE_VIU_SINGLE_PLANE) ? true : false;
return ret;
}
bool vf_type_is_VIU444(unsigned int type)
{
bool ret = (type & VIDTYPE_VIU_444) ? true : false;
return ret;
}
bool vf_type_is_VIUNV21(unsigned int type)
{
bool ret = (type & VIDTYPE_VIU_NV21) ? true : false;
return ret;
}
bool vf_type_is_vscale_dis(unsigned int type)
{
bool ret = (type & VIDTYPE_VSCALE_DISABLE) ? true : false;
return ret;
}
bool vf_type_is_canvas_toggle(unsigned int type)
{
bool ret = (type & VIDTYPE_CANVAS_TOGGLE) ? true : false;
return ret;
}
bool vf_type_is_pre_interlace(unsigned int type)
{
bool ret = (type & VIDTYPE_PRE_INTERLACE) ? true : false;
return ret;
}
bool vf_type_is_highrun(unsigned int type)
{
bool ret = (type & VIDTYPE_HIGHRUN) ? true : false;
return ret;
}
bool vf_type_is_compress(unsigned int type)
{
bool ret = (type & VIDTYPE_COMPRESS) ? true : false;
return ret;
}
bool vf_type_is_pic(unsigned int type)
{
bool ret = (type & VIDTYPE_PIC) ? true : false;
return ret;
}
bool vf_type_is_scatter(unsigned int type)
{
bool ret = (type & VIDTYPE_SCATTER) ? true : false;
return ret;
}
bool vf_type_is_vd2(unsigned int type)
{
bool ret = (type & VIDTYPE_VD2) ? true : false;
return ret;
}
bool is_bypss_complete(struct dev_vfram_t *pvfm)
{
return pvfm->bypass_complete;
}
#if 0
bool is_reg(unsigned int ch)
{
struct dev_vfram_t *pvfm;
pvfm = get_dev_vframe(ch);
return pvfm->reg;
}
#endif
void set_bypass_complete(struct dev_vfram_t *pvfm, bool on)
{
if (on)
pvfm->bypass_complete = true;
else
pvfm->bypass_complete = false;
}
void set_bypass2_complete(unsigned int ch, bool on)
{
struct dev_vfram_t *pvfm;
pvfm = get_dev_vframe(ch);
set_bypass_complete(pvfm, on);
}
bool is_bypss2_complete(unsigned int ch)
{
struct dev_vfram_t *pvfm;
pvfm = get_dev_vframe(ch);
return is_bypss_complete(pvfm);
}
#if 0
static void set_reg(unsigned int ch, int on)
{
struct dev_vfram_t *pvfm;
pvfm = get_dev_vframe(ch);
if (on)
pvfm->reg = true;
else
pvfm->reg = false;
}
#endif
static struct vframe_s *di_vf_peek(void *arg)
{
unsigned int ch = *(int *)arg;
/*dim_print("%s:ch[%d]\n",__func__,ch);*/
if (di_is_pause(ch))
return NULL;
if (is_bypss2_complete(ch))
return pw_vf_peek(ch);
else
return di_vf_l_peek(ch);
}
static struct vframe_s *di_vf_get(void *arg)
{
unsigned int ch = *(int *)arg;
/*struct vframe_s *vfm;*/
dim_tr_ops.post_get2(5);
if (di_is_pause(ch))
return NULL;
di_pause_step_done(ch);
/*pvfm = get_dev_vframe(ch);*/
if (is_bypss2_complete(ch))
#if 0
vfm = pw_vf_peek(ch);
if (dim_bypass_detect(ch, vfm))
return NULL;
#endif
return pw_vf_get(ch);
return di_vf_l_get(ch);
}
static void di_vf_put(struct vframe_s *vf, void *arg)
{
unsigned int ch = *(int *)arg;
if (is_bypss2_complete(ch)) {
pw_vf_put(vf, ch);
pw_vf_notify_provider(ch,
VFRAME_EVENT_RECEIVER_PUT, NULL);
return;
}
di_vf_l_put(vf, ch);
}
static int di_event_cb(int type, void *data, void *private_data)
{
if (type == VFRAME_EVENT_RECEIVER_FORCE_UNREG) {
pr_info("%s: RECEIVER_FORCE_UNREG return\n",
__func__);
return 0;
}
return 0;
}
static int di_vf_states(struct vframe_states *states, void *arg)
{
unsigned int ch = *(int *)arg;
if (!states)
return -1;
dim_print("%s:ch[%d]\n", __func__, ch);
di_vf_l_states(states, ch);
return 0;
}
static const struct vframe_operations_s deinterlace_vf_provider = {
.peek = di_vf_peek,
.get = di_vf_get,
.put = di_vf_put,
.event_cb = di_event_cb,
.vf_states = di_vf_states,
};
#if 1
struct vframe_s *pw_vf_get(unsigned int ch)
{
sum_g_inc(ch);
return vf_get(di_rev_name[ch]);
}
struct vframe_s *pw_vf_peek(unsigned int ch)
{
return vf_peek(di_rev_name[ch]);
}
void pw_vf_put(struct vframe_s *vf, unsigned int ch)
{
sum_p_inc(ch);
vf_put(vf, di_rev_name[ch]);
}
int pw_vf_notify_provider(unsigned int channel, int event_type, void *data)
{
return vf_notify_provider(di_rev_name[channel], event_type, data);
}
int pw_vf_notify_receiver(unsigned int channel, int event_type, void *data)
{
return vf_notify_receiver(di_rev_name[channel], event_type, data);
}
void pw_vf_light_unreg_provider(unsigned int ch)
{
struct dev_vfram_t *pvfm;
struct vframe_provider_s *prov;
pvfm = get_dev_vframe(ch);
prov = &pvfm->di_vf_prov;
vf_light_unreg_provider(prov);
}
#else
struct vframe_s *pw_vf_get(unsigned int channel)
{
return vf_get(VFM_NAME);
}
struct vframe_s *pw_vf_peek(unsigned int channel)
{
return vf_peek(VFM_NAME);
}
void pw_vf_put(struct vframe_s *vf, unsigned int channel)
{
vf_put(vf, VFM_NAME);
}
int pw_vf_notify_provider(unsigned int channel, int event_type, void *data)
{
return vf_notify_provider(VFM_NAME, event_type, data);
}
int pw_vf_notify_receiver(unsigned int channel, int event_type, void *data)
{
return vf_notify_receiver(VFM_NAME, event_type, data);
}
#endif
void dev_vframe_exit(void)
{
struct dev_vfram_t *pvfm;
int ch;
for (ch = 0; ch < DI_CHANNEL_NUB; ch++) {
pvfm = get_dev_vframe(ch);
vf_unreg_provider(&pvfm->di_vf_prov);
vf_unreg_receiver(&pvfm->di_vf_recv);
}
pr_info("%s finish\n", __func__);
}
void dev_vframe_init(void)
{
struct dev_vfram_t *pvfm;
int ch;
for (ch = 0; ch < DI_CHANNEL_NUB; ch++) {
pvfm = get_dev_vframe(ch);
pvfm->name = di_rev_name[ch];
pvfm->indx = ch;
/*set_bypass_complete(pvfm, true);*/ /*test only*/
/*receiver:*/
vf_receiver_init(&pvfm->di_vf_recv, pvfm->name,
&di_vf_receiver, &pvfm->indx);
vf_reg_receiver(&pvfm->di_vf_recv);
/*provider:*/
vf_provider_init(&pvfm->di_vf_prov, pvfm->name,
&deinterlace_vf_provider, &pvfm->indx);
}
pr_info("%s finish\n", __func__);
}

View File

@@ -0,0 +1,68 @@
/*
* drivers/amlogic/media/di_multi/di_vframe.h
*
* Copyright (C) 2017 Amlogic, Inc. 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
*/
#ifndef __DI_VFRAME_H__
#define __DI_VFRAME_H__
#include <linux/amlogic/media/vfm/vframe.h>
#include <linux/amlogic/media/vfm/vframe_provider.h>
#include <linux/amlogic/media/vfm/vframe_receiver.h>
void dev_vframe_init(void);
void dev_vframe_exit(void);
void di_vframe_reg(unsigned int ch);
void di_vframe_unreg(unsigned int ch);
bool vf_type_is_prog(unsigned int type);
bool vf_type_is_interlace(unsigned int type);
bool vf_type_is_top(unsigned int type);
bool vf_type_is_bottom(unsigned int type);
bool vf_type_is_inter_first(unsigned int type);
bool vf_type_is_mvc(unsigned int type);
bool vf_type_is_no_video_en(unsigned int type);
bool vf_type_is_VIU422(unsigned int type);
bool vf_type_is_VIU_FIELD(unsigned int type);
bool vf_type_is_VIU_SINGLE(unsigned int type);
bool vf_type_is_VIU444(unsigned int type);
bool vf_type_is_VIUNV21(unsigned int type);
bool vf_type_is_vscale_dis(unsigned int type);
bool vf_type_is_canvas_toggle(unsigned int type);
bool vf_type_is_pre_interlace(unsigned int type);
bool vf_type_is_highrun(unsigned int type);
bool vf_type_is_compress(unsigned int type);
bool vf_type_is_pic(unsigned int type);
bool vf_type_is_scatter(unsigned int type);
bool vf_type_is_vd2(unsigned int type);
extern const char * const di_rev_name[4];
struct vframe_s *pw_vf_get(unsigned int ch);
struct vframe_s *pw_vf_peek(unsigned int ch);
void pw_vf_put(struct vframe_s *vf, unsigned int ch);
int pw_vf_notify_provider(unsigned int channel,
int event_type,
void *data);
int pw_vf_notify_receiver(unsigned int channel,
int event_type,
void *data);
void pw_vf_light_unreg_provider(unsigned int ch);
void set_bypass2_complete(unsigned int ch, bool on);
bool is_bypss_complete(struct dev_vfram_t *pvfm);
bool is_bypss2_complete(unsigned int ch);
#endif /*__DI_VFRAME_H__*/

View File

@@ -0,0 +1,71 @@
/*
* drivers/amlogic/media/di_multi/dim_trace.h
*
* Copyright (C) 2017 Amlogic, Inc. 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
*/
#undef TRACE_SYSTEM
#define TRACE_SYSTEM dim
#if !defined(_DIM_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
#define _DIM_TRACE_H
#include <linux/tracepoint.h>
/* single lifecycle events */
DECLARE_EVENT_CLASS(di_event_class,
TP_PROTO(const char *name, int field_cnt, unsigned long time),
TP_ARGS(name, field_cnt, time),
TP_STRUCT__entry(
__string(name, name)
__field(int, field_cnt)
__field(unsigned long, time)
),
TP_fast_assign(
__assign_str(name, name);
__entry->field_cnt = field_cnt;
__entry->time = time;
),
TP_printk("[%s-%-4dth-%lums]", __get_str(name),
__entry->field_cnt, __entry->time)
);
#define DEFINE_DI_EVENT(name) \
DEFINE_EVENT(di_event_class, name, \
TP_PROTO(const char *name, int field_cnt, unsigned long time), \
TP_ARGS(name, field_cnt, time))
DEFINE_DI_EVENT(dim_pre);
DEFINE_DI_EVENT(dim_post);
/*2019-06-18*/
DEFINE_DI_EVENT(dim_pre_getxx);
DEFINE_DI_EVENT(dim_pre_setxx);
DEFINE_DI_EVENT(dim_pre_ready);
DEFINE_DI_EVENT(dim_pst_ready);
DEFINE_DI_EVENT(dim_pst_getxx);
DEFINE_DI_EVENT(dim_pst_setxx);
DEFINE_DI_EVENT(dim_pst_irxxx);
DEFINE_DI_EVENT(dim_pst_doing);
DEFINE_DI_EVENT(dim_pst_peekx);
DEFINE_DI_EVENT(dim_pst_get2x);
#endif /* _DIM_TRACE_H */
#if 0
#undef TRACE_INCLUDE_PATH
#undef TRACE_INCLUDE_FILE
#define TRACE_INCLUDE_PATH .
#define TRACE_INCLUDE_FILE deinterlace_trace
#include <trace/define_trace.h>
#endif

View File

@@ -0,0 +1,218 @@
/*
* drivers/amlogic/media/di_multi/nr_downscale.c
*
* Copyright (C) 2017 Amlogic, Inc. 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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/types.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/dma-contiguous.h>
#include <linux/amlogic/iomap.h>
#include <linux/amlogic/media/canvas/canvas.h>
#include <linux/amlogic/media/canvas/canvas_mgr.h>
#include "register.h"
#include "nr_downscale.h"
#include "deinterlace.h"
#include "di_data_l.h"
#include "di_api.h"
static struct nr_ds_s nrds_dev;
static void nr_ds_hw_init(unsigned int width, unsigned int height)
{
unsigned char h_step = 0, v_step = 0;
unsigned int width_out, height_out;
width_out = NR_DS_WIDTH;
height_out = NR_DS_HEIGHT;
h_step = width / width_out;
v_step = height / height_out;
/*Switch MIF to NR_DS*/
dim_RDMA_WR_BITS(VIUB_MISC_CTRL0, 3, 5, 2);
/* config dsbuf_ocol*/
dim_RDMA_WR_BITS(NR_DS_BUF_SIZE_REG, width_out, 0, 8);
/* config dsbuf_orow*/
dim_RDMA_WR_BITS(NR_DS_BUF_SIZE_REG, height_out, 8, 8);
dim_RDMA_WR_BITS(NRDSWR_X, (width_out - 1), 0, 13);
dim_RDMA_WR_BITS(NRDSWR_Y, (height_out - 1), 0, 13);
dim_RDMA_WR_BITS(NRDSWR_CAN_SIZE, (height_out - 1), 0, 13);
dim_RDMA_WR_BITS(NRDSWR_CAN_SIZE, (width_out - 1), 16, 13);
/* little endian */
dim_RDMA_WR_BITS(NRDSWR_CAN_SIZE, 1, 13, 1);
dim_RDMA_WR_BITS(NR_DS_CTRL, v_step, 16, 6);
dim_RDMA_WR_BITS(NR_DS_CTRL, h_step, 24, 6);
}
/*
* init nr ds buffer
*/
void dim_nr_ds_buf_init(unsigned int cma_flag, unsigned long mem_start,
struct device *dev)
{
unsigned int i = 0;
bool ret;
struct dim_mm_s omm;
if (cma_flag == 0) {
nrds_dev.nrds_addr = mem_start;
} else {
#if 0
nrds_dev.nrds_pages = dma_alloc_from_contiguous(dev,
NR_DS_PAGE_NUM, 0);
if (nrds_dev.nrds_pages)
nrds_dev.nrds_addr = page_to_phys(nrds_dev.nrds_pages);
else
PR_ERR("DI: alloc nr ds mem error.\n");
#else
ret = dim_mm_alloc(cma_flag, NR_DS_PAGE_NUM, &omm);
if (ret) {
nrds_dev.nrds_pages = omm.ppage;
nrds_dev.nrds_addr = omm.addr;
} else {
PR_ERR("alloc nr ds mem error.\n");
}
#endif
}
for (i = 0; i < NR_DS_BUF_NUM; i++)
nrds_dev.buf[i] = nrds_dev.nrds_addr + (NR_DS_BUF_SIZE * i);
nrds_dev.cur_buf_idx = 0;
}
void dim_nr_ds_buf_uninit(unsigned int cma_flag, struct device *dev)
{
unsigned int i = 0;
if (cma_flag == 0) {
nrds_dev.nrds_addr = 0;
} else {
if (nrds_dev.nrds_pages) {
#if 0
dma_release_from_contiguous(dev,
nrds_dev.nrds_pages,
NR_DS_PAGE_NUM);
#else
dim_mm_release(cma_flag,
nrds_dev.nrds_pages,
NR_DS_PAGE_NUM,
nrds_dev.nrds_addr);
#endif
nrds_dev.nrds_addr = 0;
nrds_dev.nrds_pages = NULL;
} else
pr_info("DI: no release nr ds mem.\n");
}
for (i = 0; i < NR_DS_BUF_NUM; i++)
nrds_dev.buf[i] = 0;
nrds_dev.cur_buf_idx = 0;
}
/*
* hw config, alloc canvas
*/
void dim_nr_ds_init(unsigned int width, unsigned int height)
{
nr_ds_hw_init(width, height);
nrds_dev.field_num = 0;
if (nrds_dev.canvas_idx != 0)
return;
if (ext_ops.canvas_pool_alloc_canvas_table("nr_ds",
&nrds_dev.canvas_idx, 1, CANVAS_MAP_TYPE_1)) {
PR_ERR("%s alloc nrds canvas error.\n", __func__);
return;
}
pr_info("%s alloc nrds canvas %u.\n",
__func__, nrds_dev.canvas_idx);
}
/*
* config nr ds mif, switch buffer
*/
void dim_nr_ds_mif_config(void)
{
unsigned long mem_addr = 0;
mem_addr = nrds_dev.buf[nrds_dev.cur_buf_idx];
canvas_config(nrds_dev.canvas_idx, mem_addr,
NR_DS_WIDTH, NR_DS_HEIGHT, 0, 0);
dim_RDMA_WR_BITS(NRDSWR_CTRL,
nrds_dev.canvas_idx, 0, 8);
dim_nr_ds_hw_ctrl(true);
}
/*
* enable/disable nr ds mif&hw
*/
void dim_nr_ds_hw_ctrl(bool enable)
{
/*Switch MIF to NR_DS*/
dim_RDMA_WR_BITS(VIUB_MISC_CTRL0, enable ? 3 : 2, 5, 2);
dim_RDMA_WR_BITS(NRDSWR_CTRL, enable ? 1 : 0, 12, 1);
dim_RDMA_WR_BITS(NR_DS_CTRL, enable ? 1 : 0, 30, 1);
}
/*
* process in irq
*/
void dim_nr_ds_irq(void)
{
dim_nr_ds_hw_ctrl(false);
nrds_dev.field_num++;
nrds_dev.cur_buf_idx++;
if (nrds_dev.cur_buf_idx >= NR_DS_BUF_NUM)
nrds_dev.cur_buf_idx = 0;
}
/*
* get buf addr&size for dump
*/
void dim_get_nr_ds_buf(unsigned long *addr, unsigned long *size)
{
*addr = nrds_dev.nrds_addr;
*size = NR_DS_BUF_SIZE;
pr_info("%s addr 0x%lx, size 0x%lx.\n",
__func__, *addr, *size);
}
/*
* 0x37f9 ~ 0x37fc 0x3740 ~ 0x3743 8 regs
*/
void dim_dump_nrds_reg(unsigned int base_addr)
{
unsigned int i = 0x37f9;
pr_info("-----nrds reg start-----\n");
pr_info("[0x%x][0x%x]=0x%x\n",
base_addr + (0x2006 << 2), i, dim_RDMA_RD(0x2006));
for (i = 0x37f9; i < 0x37fd; i++)
pr_info("[0x%x][0x%x]=0x%x\n",
base_addr + (i << 2), i, dim_RDMA_RD(i));
for (i = 0x3740; i < 0x3744; i++)
pr_info("[0x%x][0x%x]=0x%x\n",
base_addr + (i << 2), i, dim_RDMA_RD(i));
pr_info("-----nrds reg end-----\n");
}

View File

@@ -0,0 +1,46 @@
/*
* drivers/amlogic/media/di_multi/nr_downscale.h
*
* Copyright (C) 2017 Amlogic, Inc. 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
*/
#ifndef _NR_DS_H
#define _NR_DS_H
#define NR_DS_WIDTH 128
#define NR_DS_HEIGHT 96
#define NR_DS_BUF_SIZE (96 << 7)
#define NR_DS_BUF_NUM 6
#define NR_DS_MEM_SIZE (NR_DS_BUF_SIZE * NR_DS_BUF_NUM)
#define NR_DS_PAGE_NUM (NR_DS_MEM_SIZE >> PAGE_SHIFT)
struct nr_ds_s {
unsigned int field_num;
unsigned long nrds_addr;
struct page *nrds_pages;
unsigned int canvas_idx;
unsigned char cur_buf_idx;
unsigned long buf[NR_DS_BUF_NUM];
};
void dim_nr_ds_buf_init(unsigned int cma_flag, unsigned long mem_start,
struct device *dev);
void dim_nr_ds_buf_uninit(unsigned int cma_flag, struct device *dev);
void dim_nr_ds_init(unsigned int width, unsigned int height);
void dim_nr_ds_mif_config(void);
void dim_nr_ds_hw_ctrl(bool enable);
void dim_nr_ds_irq(void);
void dim_get_nr_ds_buf(unsigned long *addr, unsigned long *size);
void dim_dump_nrds_reg(unsigned int base_addr);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,149 @@
/*
* drivers/amlogic/media/di_multi/register_nr4.h
*
* Copyright (C) 2017 Amlogic, Inc. 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 as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
*/
#define NR4_DRT_CTRL ((0x2da4))
#define NR4_DRT_YSAD_GAIN ((0x2da5))
#define NR4_DRT_CSAD_GAIN ((0x2da6))
#define NR4_DRT_SAD_ALP_CORE ((0x2da7))
#define NR4_DRT_ALP_MINMAX ((0x2da8))
#define NR4_SNR_CTRL_REG ((0x2da9))
#define NR4_SNR_ALPHA0_MAX_MIN ((0x2daa))
#define NR4_ALP0C_ERR2CURV_LIMIT0 ((0x2dab))
#define NR4_ALP0C_ERR2CURV_LIMIT1 ((0x2dac))
#define NR4_ALP0Y_ERR2CURV_LIMIT0 ((0x2dad))
#define NR4_ALP0Y_ERR2CURV_LIMIT1 ((0x2dae))
#define NR4_SNR_ALPA1_RATE_AND_OFST ((0x2daf))
#define NR4_SNR_ALPHA1_MAX_MIN ((0x2db0))
#define NR4_ALP1C_ERR2CURV_LIMIT0 ((0x2db1))
#define NR4_ALP1C_ERR2CURV_LIMIT1 ((0x2db2))
#define NR4_ALP1Y_ERR2CURV_LIMIT0 ((0x2db3))
#define NR4_ALP1Y_ERR2CURV_LIMIT1 ((0x2db4))
#define NR4_MTN_CTRL ((0x2db5))
#define NR4_MTN_REF_PAR0 ((0x2db6))
#define NR4_MTN_REF_PAR1 ((0x2db7))
#define NR4_MCNR_LUMA_ENH_CTRL ((0x2db8))
#define NR4_MCNR_LUMA_STAT_LIMTX ((0x2db9))
#define NR4_MCNR_LUMA_STAT_LIMTY ((0x2dba))
#define NR4_MCNR_LUMA_DIF_CALC ((0x2dbb))
#define NR4_MCNR_LUMAPRE_CAL_PRAM ((0x2dbc))
#define NR4_MCNR_LUMACUR_CAL_PRAM ((0x2dbd))
#define NR4_MCNR_MV_CTRL_REG ((0x2dbe))
#define NR4_MCNR_MV_GAIN0 ((0x2dbf))
#define NR4_MCNR_LMV_PARM ((0x2dc0))
#define NR4_MCNR_ALP0_REG (0x2dc1)
#define NR4_MCNR_ALP1_AND_BET0_REG (0x2dc2)
#define NR4_MCNR_BET1_AND_BET2_REG (0x2dc3)
#define NR4_MCNR_AC_DC_CRTL (0x2dc4)
#define NR4_MCNR_CM_CTRL0 (0x2dc5)
#define NR4_MCNR_CM_PRAM (0x2dc6)
#define NR4_MCNR_CM_RSHFT_ALP0 (0x2dc7)
#define NR4_MCNR_BLUE_CENT (0x2dc8)
#define NR4_MCNR_BLUE_GAIN_PAR0 (0x2dc9)
#define NR4_MCNR_BLUE_GAIN_PAR1 (0x2dca)
#define NR4_MCNR_CM_BLUE_CLIP0 (0x2dcb)
#define NR4_MCNR_CM_BLUE_CLIP1 (0x2dcc)
#define NR4_MCNR_GREEN_CENT (0x2dcd)
#define NR4_MCNR_GREEN_GAIN_PAR0 (0x2dce)
#define NR4_MCNR_GREEN_GAIN_PAR1 (0x2dcf)
#define NR4_MCNR_GREEN_CLIP0 (0x2dd0)
#define NR4_MCNR_GREEN_CLIP2 (0x2dd1)
#define NR4_MCNR_SKIN_CENT (0x2dd2)
#define NR4_MCNR_SKIN_GAIN_PAR0 (0x2dd3)
#define NR4_MCNR_SKIN_GAIN_PAR1 (0x2dd4)
#define NR4_MCNR_SKIN_CLIP0 (0x2dd5)
#define NR4_MCNR_SKIN_CLIP1 (0x2dd6)
#define NR4_MCNR_ALP1_GLB_CTRL (0x2dd7)
#define NR4_MCNR_DC2NORM_LUT0 (0x2dd8)
#define NR4_MCNR_DC2NORM_LUT1 (0x2dd9)
#define NR4_MCNR_DC2NORM_LUT2 (0x2dda)
#define NR4_MCNR_AC2NORM_LUT0 (0x2ddb)
#define NR4_MCNR_AC2NORM_LUT1 (0x2ddc)
#define NR4_MCNR_AC2NORM_LUT2 (0x2ddd)
#define NR4_MCNR_SAD2ALP0_LUT0 (0x2dde)
#define NR4_MCNR_SAD2ALP0_LUT1 (0x2ddf)
#define NR4_MCNR_SAD2ALP0_LUT2 (0x2de0)
#define NR4_MCNR_SAD2ALP0_LUT3 (0x2de1)
#define NR4_MCNR_SAD2ALP1_LUT0 (0x2de2)
#define NR4_MCNR_SAD2ALP1_LUT1 (0x2de3)
#define NR4_MCNR_SAD2ALP1_LUT2 (0x2de4)
#define NR4_MCNR_SAD2ALP1_LUT3 (0x2de5)
#define NR4_MCNR_SAD2BET0_LUT0 (0x2de6)
#define NR4_MCNR_SAD2BET0_LUT1 (0x2de7)
#define NR4_MCNR_SAD2BET0_LUT2 (0x2de8)
#define NR4_MCNR_SAD2BET0_LUT3 (0x2de9)
#define NR4_MCNR_SAD2BET1_LUT0 (0x2dea)
#define NR4_MCNR_SAD2BET1_LUT1 (0x2deb)
#define NR4_MCNR_SAD2BET1_LUT2 (0x2dec)
#define NR4_MCNR_SAD2BET1_LUT3 (0x2ded)
#define NR4_MCNR_SAD2BET2_LUT0 (0x2dee)
#define NR4_MCNR_SAD2BET2_LUT1 (0x2def)
#define NR4_MCNR_SAD2BET2_LUT2 (0x2df0)
#define NR4_MCNR_SAD2BET2_LUT3 (0x2df1)
#define NR4_MCNR_RO_U_SUM (0x2df2)
#define NR4_MCNR_RO_V_SUM (0x2df3)
#define NR4_MCNR_RO_GRDU_SUM (0x2df4)
#define NR4_MCNR_RO_GRDV_SUM (0x2df5)
#define NR4_TOP_CTRL (0x2dff)
#define NR4_MCNR_SAD_GAIN (0x3700)
#define NR4_MCNR_LPF_CTRL (0x3701)
#define NR4_MCNR_BLD_VS3LUT0 (0x3702)
#define NR4_MCNR_BLD_VS3LUT1 (0x3703)
#define NR4_MCNR_BLD_VS3LUT2 (0x3704)
#define NR4_MCNR_BLD_VS2LUT0 (0x3705)
#define NR4_MCNR_BLD_VS2LUT1 (0x3706)
#define NR4_COEFBLT_LUT10 (0x3707)
#define NR4_COEFBLT_LUT11 (0x3708)
#define NR4_COEFBLT_LUT12 (0x3709)
#define NR4_COEFBLT_LUT20 (0x370a)
#define NR4_COEFBLT_LUT21 (0x370b)
#define NR4_COEFBLT_LUT22 (0x370c)
#define NR4_COEFBLT_LUT30 (0x370d)
#define NR4_COEFBLT_LUT31 (0x370e)
#define NR4_COEFBLT_LUT32 (0x370f)
#define NR4_COEFBLT_CONV (0x3710)
#define NR4_DBGWIN_YX0 (0x3711)
#define NR4_DBGWIN_YX1 (0x3712)
#define NR4_NM_X_CFG (0x3713)
#define NR4_NM_Y_CFG (0x3714)
#define NR4_NM_SAD_THD (0x3715)
#define NR4_MCNR_BANDSPLIT_PRAM (0x3716)
#define NR4_MCNR_ALP1_SGN_COR (0x3717)
#define NR4_MCNR_ALP1_SGN_PRAM (0x3718)
#define NR4_MCNR_ALP1_MVX_LUT1 (0x3719)
#define NR4_MCNR_ALP1_MVX_LUT2 (0x371a)
#define NR4_MCNR_ALP1_MVX_LUT3 (0x371b)
#define NR4_MCNR_ALP1_LP_PRAM (0x371c)
#define NR4_MCNR_ALP1_SGN_LUT1 (0x371d)
#define NR4_MCNR_ALP1_SGN_LUT2 (0x371e)
#define NR4_RO_NM_SAD_SUM (0x371f)
#define NR4_RO_NM_SAD_CNT (0x3720)
#define NR4_RO_NM_VAR_SUM (0x3721)
#define NR4_RO_NM_VAR_SCNT (0x3722)
#define NR4_RO_NM_VAR_MIN_MAX (0x3723)
#define NR4_RO_NR4_DBGPIX_NUM (0x3724)
#define NR4_RO_NR4_BLDVS2_SUM (0x3725)
#define NR4_BLDVS3_SUM (0x3726)
#define NR4_COEF12_SUM (0x3727)
#define NR4_COEF123_SUM (0x3728)
#define NR_DB_FLT_CTRL (0x3738)
#define NR_DB_FLT_YC_THRD (0x3739)
#define NR_DB_FLT_RANDLUT (0x373a)
#define NR_DB_FLT_PXI_THRD (0x373b)
#define NR_DB_FLT_SEED_Y (0x373c)
#define NR_DB_FLT_SEED_V (0x373e)
#define NR_DB_FLT_SEED3 (0x373f)
#define LBUF_TOP_CTRL (0x2fff)

View File

@@ -1204,23 +1204,23 @@ static int Gxtv_Demod_Dvbc_Init(/*struct aml_fe_dev *dev, */int mode)
sys.demod_clk = Demod_Clk_200M;
demod_status.tmp = Adc_mode;
} else {
sys.adc_clk = Adc_Clk_24M;
sys.adc_clk = ADC_CLK_24M;
sys.demod_clk = Demod_Clk_72M;
demod_status.tmp = Cry_mode;
}
if (is_ic_ver(IC_VER_TL1)) {
sys.adc_clk = Adc_Clk_24M;
sys.adc_clk = ADC_CLK_24M;
/*for timeshift mosaic issue,already fixed with tm2*/
sys.demod_clk = Demod_Clk_167M;
demod_status.tmp = Cry_mode;
} else if (is_ic_ver(IC_VER_TM2)) {
sys.adc_clk = Adc_Clk_24M;
sys.adc_clk = ADC_CLK_24M;
sys.demod_clk = Demod_Clk_250M;
demod_status.tmp = Cry_mode;
}
demod_status.ch_if = Si2176_5M_If * 1000;
demod_status.ch_if = SI2176_5M_IF * 1000;
PR_DBG("[%s]adc_clk is %d,demod_clk is %d\n", __func__, sys.adc_clk,
sys.demod_clk);
autoFlagsTrig = 0;
@@ -1404,9 +1404,9 @@ int Gxtv_Demod_Dvbt_Init(void)
/* 0 -DVBC, 1-DVBT, ISDBT, 2-ATSC*/
demod_status.dvb_mode = Gxtv_Dvbt_Isdbt;
sys.adc_clk = Adc_Clk_24M;
sys.adc_clk = ADC_CLK_24M;
sys.demod_clk = Demod_Clk_60M;
demod_status.ch_if = Si2176_5M_If * 1000;
demod_status.ch_if = SI2176_5M_IF * 1000;
demod_set_sys(&demod_status, &sys);
demod_mode_para = AML_DVBT;
@@ -1742,7 +1742,7 @@ static int gxtv_demod_atsc_set_frontend(struct dvb_frontend *fe)
else
atsc_write_reg_v4(ATSC_DEMOD_REG_0X56, 0x0);
if (demod_status.adc_freq == Adc_Clk_24M) {
if (demod_status.adc_freq == ADC_CLK_24M) {
atsc_write_reg_v4(ATSC_DEMOD_REG_0X54,
0x1aaaaa);
@@ -2184,7 +2184,7 @@ int Gxtv_Demod_Atsc_Init(void/*struct aml_fe_dev *dev*/)
memset(&demod_status, 0, sizeof(demod_status));
/* 0 -DVBC, 1-DVBT, ISDBT, 2-ATSC*/
demod_status.dvb_mode = Gxtv_Atsc;
sys.adc_clk = Adc_Clk_24M; /*Adc_Clk_26M;*/
sys.adc_clk = ADC_CLK_24M; /*Adc_Clk_26M;*/
if (is_ic_ver(IC_VER_TL1) || is_ic_ver(IC_VER_TM2))
sys.demod_clk = Demod_Clk_250M;
else
@@ -2551,6 +2551,11 @@ static int gxtv_demod_dtmb_set_frontend(struct dvb_frontend *fe)
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct aml_demod_dtmb param;
int times;
/*[0]: specturm inverse(1),normal(0); [1]:if_frequency*/
unsigned int tuner_freq[2] = {0};
if (!demod_thread)
return 0;
times = 2;
PR_DBG("gxtv_demod_dtmb_set_frontend,freq is %d\n", c->frequency);
@@ -2563,6 +2568,17 @@ static int gxtv_demod_dtmb_set_frontend(struct dvb_frontend *fe)
msleep(100);
/* demod_power_switch(PWR_ON); */
if (cpu_after_eq(MESON_CPU_MAJOR_ID_TL1)) {
if (fe->ops.tuner_ops.get_if_frequency)
fe->ops.tuner_ops.get_if_frequency(fe, tuner_freq);
if (tuner_freq[0] == 0)
demod_status.spectrum = 0;
else if (tuner_freq[0] == 1)
demod_status.spectrum = 1;
else
pr_err("wrong specturm val get from tuner\n");
}
dtmb_set_ch(&demod_status, /*&demod_i2c,*/ &param);
return 0;
@@ -2596,10 +2612,10 @@ int Gxtv_Demod_Dtmb_Init(struct amldtvdemod_device_s *dev)
sys.adc_clk = Adc_Clk_25M;
sys.demod_clk = Demod_Clk_225M;
} else if (is_ic_ver(IC_VER_TL1) || is_ic_ver(IC_VER_TM2)) {
sys.adc_clk = Adc_Clk_24M;
sys.adc_clk = ADC_CLK_24M;
sys.demod_clk = Demod_Clk_250M;
} else {
sys.adc_clk = Adc_Clk_24M;
sys.adc_clk = ADC_CLK_24M;
sys.demod_clk = Demod_Clk_225M;
}
} else {
@@ -2607,7 +2623,7 @@ int Gxtv_Demod_Dtmb_Init(struct amldtvdemod_device_s *dev)
return -1;
}
demod_status.ch_if = Si2176_5M_If;
demod_status.ch_if = SI2176_5M_IF;
demod_status.tmp = Adc_mode;
demod_status.spectrum = dev->spectrum;
/*demod_set_sys(&demod_status, &i2c, &sys);*/

View File

@@ -827,15 +827,14 @@ int cci_run(void)
int cfo_run(void)
{
int crRate0, crRate1, crRate2, crRate;
int Fcent, Fs;
int cfo_sta, cr_peak_sta;
int i, j;
int cr_rate0, cr_rate1, cr_rate2, cr_rate;
int f_cent = SI2176_5M_IF * 1000;/* if */
int fs = ADC_CLK_24M;/* crystal */
int cfo_sta = UNLOCK, cr_peak_sta = UNLOCK;
unsigned int i, j;
int sys_state;
int table_count;
int max_count;
int freq_table[] = {0, -50, 50, -100, 100, -150, 150};
int scan_range;
int Offset;
int detec_cfo_times = 3;
@@ -846,34 +845,35 @@ int cfo_run(void)
max_count = 5;
else
max_count = 7;
/*for field test do 3 times*/
/* for field test do 3 times */
if (field_test_version) {
max_count = 1;
detec_cfo_times = 20;
}
Fcent = Si2176_5M_If*1000;/*if*/
Fs = Adc_Clk_24M;/*crystal*/
cfo_sta = 0;
cr_peak_sta = 0;
table_count = 0;
scan_range = 10;
Offset = freq_table[table_count];
PR_ATSC("Fcent[%d], Fs[%d]\n", Fcent, Fs);
for (i = -(scan_range-1); i <= scan_range+1; i++) {
PR_ATSC("Fcent[%d], Fs[%d]\n", f_cent, fs);
for (i = 0; i < 7; i++) {
if (i > (max_count - 1))
return CFO_FAIL;
Offset = freq_table[i];
atsc_reset();
cfo_sta = UnLock;
cr_peak_sta = UnLock;
crRate = (1<<10)*(Fcent+Offset)/Fs;
crRate *= (1<<13);
crRate0 = crRate&0xff;
crRate1 = (crRate>>8)&0xff;
crRate2 = (crRate>>16)&0xff;
cfo_sta = UNLOCK;
cr_peak_sta = UNLOCK;
cr_rate = (1 << 10) * (f_cent + Offset) / fs;
cr_rate *= (1 << 13);
cr_rate0 = cr_rate & 0xff;
cr_rate1 = (cr_rate >> 8) & 0xff;
cr_rate2 = (cr_rate >> 16) & 0xff;
/*set ddc init*/
atsc_write_reg(0x70e, crRate0);
atsc_write_reg(0x70d, crRate1);
atsc_write_reg(0x70c, crRate2);
atsc_write_reg(0x70e, cr_rate0);
atsc_write_reg(0x70d, cr_rate1);
atsc_write_reg(0x70c, cr_rate2);
PR_ATSC("[autoscan]crRate is %x, Offset is %dkhz\n ",
crRate, Offset);
cr_rate, Offset);
/*detec cfo signal*/
for (j = 0; j < detec_cfo_times; j++) {
sys_state = read_atsc_fsm();
@@ -886,18 +886,18 @@ int cfo_run(void)
}
msleep(20);
}
PR_ATSC("fsm[%x]cfo_sta is %d\n",
read_atsc_fsm(), cfo_sta);
PR_ATSC("fsm[%x]cfo_sta is %d\n", read_atsc_fsm(), cfo_sta);
/*detec cr peak signal*/
if (cfo_sta == Lock) {
for (j = 0; j < cfo_times; j++) {
sys_state = read_atsc_fsm();
PR_ATSC("fsm[%x]in CR LOCK\n", read_atsc_fsm());
PR_ATSC("fsm[%x]in CR LOCK\n",
read_atsc_fsm());
/*sys_state = (sys_state >> 4) & 0x0f;*/
if (sys_state >= CR_Peak_Lock) {
cr_peak_sta = Lock;
PR_ATSC(
"fsm[%x][autoscan]cr peak lock\n",
PR_ATSC("fsm[0x%x]cr peak lock\n",
read_atsc_fsm());
break;
} else if (sys_state <= 20) {
@@ -906,13 +906,9 @@ int cfo_run(void)
}
msleep(20);
}
} else {
if (table_count >= (max_count-1))
break;
table_count++;
Offset = freq_table[table_count];
} else
continue;
}
/*reset*/
if (cr_peak_sta == Lock) {
/*atsc_reset();*/
@@ -920,17 +916,9 @@ int cfo_run(void)
read_atsc_fsm());
return Cfo_Ok;
} else {
if (table_count >= (max_count-1)) {
PR_ATSC("cfo not lock,will try again\n");
return Cfo_Fail;
}
table_count++;
Offset = freq_table[table_count];
}
}
return 0;
}
@@ -1124,7 +1112,7 @@ void atsc_thread(void)
time_table[1] = (time[2] - time[1]);
PR_ATSC("fsm[%x][atsc_time]cfo done,cost %d ms,\n",
read_atsc_fsm(), time_table[1]);
if (ret == Cfo_Fail)
if (ret == CFO_FAIL)
return;
if (cci_enable)
ret = cci_run();

View File

@@ -133,7 +133,7 @@ void adc_dpll_setup(int clk_a, int clk_b, int clk_sys, int dvb_mode)
int sts_pll;
if (is_ic_ver(IC_VER_TL1) || is_ic_ver(IC_VER_TM2)) {
if (clk_b == Adc_Clk_24M) {
if (clk_b == ADC_CLK_24M) {
dtvpll_init_flag(1);
return;
} else if (clk_b == Adc_Clk_25M) {

View File

@@ -94,9 +94,87 @@ void dtmb_clk_set(unsigned int adc_clk)
}
#endif
static void dtmb_24m_coeff(void)
{
#if 0
dtmb_write_reg(DTMB_FRONT_COEF_SET19, 0xf230ee02);
dtmb_write_reg(DTMB_FRONT_COEF_SET18, 0x0be241ed);
dtmb_write_reg(DTMB_FRONT_COEF_SET17, 0x0306031d);
dtmb_write_reg(DTMB_FRONT_COEF_SET16, 0x051d191c);
dtmb_write_reg(DTMB_FRONT_COEF_SET15, 0x171a0308);
dtmb_write_reg(DTMB_FRONT_COEF_SET14, 0x0b071d);
dtmb_write_reg(DTMB_FRONT_COEF_SET13, 0x3d333703);
dtmb_write_reg(DTMB_FRONT_COEF_SET12, 0x33030f0a);
dtmb_write_reg(DTMB_FRONT_COEF_SET11, 0x140f3c2f);
dtmb_write_reg(DTMB_FRONT_COEF_SET10, 0x292d04);
dtmb_write_reg(DTMB_FRONT_COEF_SET9, 0x041c177c);
dtmb_write_reg(DTMB_FRONT_COEF_SET8, 0x247c5e64);
dtmb_write_reg(DTMB_FRONT_COEF_SET7, 0x2b);
dtmb_write_reg(DTMB_FRONT_COEF_SET6, 0xc8d104);
dtmb_write_reg(DTMB_FRONT_COEF_SET5, 0x0431fc);
dtmb_write_reg(DTMB_FRONT_COEF_SET4, 0x51);
dtmb_write_reg(DTMB_FRONT_COEF_SET3, 0x392004);
dtmb_write_reg(DTMB_FRONT_COEF_SET2, 0x372);
dtmb_write_reg(DTMB_FRONT_COEF_SET1, 0x1187fc);
dtmb_write_reg(DTMB_FRONT_ACF_BYPASS,
((dtmb_read_reg(DTMB_FRONT_ACF_BYPASS) & ~0xffffff)
| 0x2af236));
#else
dtmb_write_reg(DTMB_FRONT_COEF_SET19, 0xebd2530d);
dtmb_write_reg(DTMB_FRONT_COEF_SET18, 0x04dad364);
dtmb_write_reg(DTMB_FRONT_COEF_SET17, 0x181e0508);
dtmb_write_reg(DTMB_FRONT_COEF_SET16, 0x080a031a);
dtmb_write_reg(DTMB_FRONT_COEF_SET15, 0x0217161f);
dtmb_write_reg(DTMB_FRONT_COEF_SET14, 0x000c0c);
dtmb_write_reg(DTMB_FRONT_COEF_SET13, 0x0e3f3334);
dtmb_write_reg(DTMB_FRONT_COEF_SET12, 0x2e330310);
dtmb_write_reg(DTMB_FRONT_COEF_SET11, 0x08160f3c);
dtmb_write_reg(DTMB_FRONT_COEF_SET10, 0x352731);
dtmb_write_reg(DTMB_FRONT_COEF_SET9, 0x70101f11);
dtmb_write_reg(DTMB_FRONT_COEF_SET8, 0x2d126b5c);
dtmb_write_reg(DTMB_FRONT_COEF_SET7, 0x1f);
dtmb_write_reg(DTMB_FRONT_COEF_SET6, 0xd4c8ef);
dtmb_write_reg(DTMB_FRONT_COEF_SET5, 0x04e013);
dtmb_write_reg(DTMB_FRONT_COEF_SET4, 0x46);
dtmb_write_reg(DTMB_FRONT_COEF_SET3, 0x3883ee);
dtmb_write_reg(DTMB_FRONT_COEF_SET2, 0x37e);
dtmb_write_reg(DTMB_FRONT_COEF_SET1, 0x123013);
dtmb_write_reg(DTMB_FRONT_ACF_BYPASS,
((dtmb_read_reg(DTMB_FRONT_ACF_BYPASS) & ~0xffffff)
| 0x29922b));
#endif
}
static void dtmb_25m_coeff(void)
{
dtmb_write_reg(DTMB_FRONT_COEF_SET19, 0x242fde12);
dtmb_write_reg(DTMB_FRONT_COEF_SET18, 0x451dce);
dtmb_write_reg(DTMB_FRONT_COEF_SET17, 0x051f1a1b);
dtmb_write_reg(DTMB_FRONT_COEF_SET16, 0x181c0307);
dtmb_write_reg(DTMB_FRONT_COEF_SET15, 0x0809031b);
dtmb_write_reg(DTMB_FRONT_COEF_SET14, 0x15161f);
dtmb_write_reg(DTMB_FRONT_COEF_SET13, 0x060e0a3e);
dtmb_write_reg(DTMB_FRONT_COEF_SET12, 0x06363038);
dtmb_write_reg(DTMB_FRONT_COEF_SET11, 0x2d3e0f12);
dtmb_write_reg(DTMB_FRONT_COEF_SET10, 0x133c2b);
dtmb_write_reg(DTMB_FRONT_COEF_SET9, 0x5f700c1b);
dtmb_write_reg(DTMB_FRONT_COEF_SET8, 0x23270b6a);
dtmb_write_reg(DTMB_FRONT_COEF_SET7, 0x7e);
dtmb_write_reg(DTMB_FRONT_COEF_SET6, 0xf3cbd4);
dtmb_write_reg(DTMB_FRONT_COEF_SET5, 0x04f031);
dtmb_write_reg(DTMB_FRONT_COEF_SET4, 0x29);
dtmb_write_reg(DTMB_FRONT_COEF_SET3, 0x37f3cc);
dtmb_write_reg(DTMB_FRONT_COEF_SET2, 0x396);
dtmb_write_reg(DTMB_FRONT_COEF_SET1, 0x131036);
dtmb_write_reg(DTMB_FRONT_ACF_BYPASS,
((dtmb_read_reg(DTMB_FRONT_ACF_BYPASS) & ~0xffffff)
| 0x274217));
}
void dtmb_all_reset(void)
{
int temp_data = 0;
unsigned int reg_val;
if (is_ic_ver(IC_VER_TXL)) {
/*fix bug 139044: DTMB lost sync*/
@@ -139,22 +217,41 @@ void dtmb_all_reset(void)
/*fix agc problem,skip warm_up status*/
dtmb_write_reg(DTMB_FRONT_46_CONFIG, 0x1a000f0f);
dtmb_write_reg(DTMB_FRONT_ST_FREQ, 0xf2400000);
dtmb_clk_set(Adc_Clk_24M);
dtmb_clk_set(ADC_CLK_24M);
} else if (is_ic_ver(IC_VER_TL1) || is_ic_ver(IC_VER_TM2)) {
if (demod_get_adc_clk() == Adc_Clk_24M) {
if (demod_get_adc_clk() == ADC_CLK_24M) {
dtmb_write_reg(DTMB_FRONT_DDC_BYPASS, 0x6aaaaa);
dtmb_write_reg(DTMB_FRONT_SRC_CONFIG1, 0x13196596);
dtmb_write_reg(0x5b << 2, 0x50a30a25);
dtmb_24m_coeff();
} else if (demod_get_adc_clk() == Adc_Clk_25M) {
dtmb_write_reg(DTMB_FRONT_DDC_BYPASS, 0x62c1a5);
dtmb_write_reg(DTMB_FRONT_SRC_CONFIG1, 0x131a747d);
dtmb_write_reg(0x5b << 2, 0x4d6a0a25);
dtmb_25m_coeff();
}
/*for timeshift mosaic issue*/
dtmb_write_reg(0x4e << 2, 0x256cf604);
/*delay fec lock to prevent eq is confused by signal*/
dtmb_write_reg(DTMB_FRONT_DEBUG_CFG, 0x5680000);
/*for timeshift mosaic issue
*bit 30:ts_sync_sel,0=ts_sync,1=searched ts_sync
*/
dtmb_write_reg(DTMB_FRONT_4e_CONFIG, 0x656cf604);
/*delay fec lock & make fec lost faster
*to prevent eq is confused by signal
*/
dtmb_write_reg(DTMB_FRONT_DEBUG_CFG, 0x5480000);
/*reduce fec lost timeout*/
dtmb_write_reg(DTMB_FRONT_19_CONFIG, 0x30);
reg_val = dtmb_read_reg(DTMB_TOP_CTRL_TPS);
/* for Task 19:Switch mode and modulation parameters test
* dtmb_spectrum: 0=normal, 1=inverted
*/
if (dtmb_spectrum == 0)
reg_val |= 0x4;
else if (dtmb_spectrum == 1)
reg_val &= ~0x4;
dtmb_write_reg(DTMB_TOP_CTRL_TPS, reg_val);
} else {
dtmb_write_reg(DTMB_FRONT_AGC_CONFIG1, 0x10127);
dtmb_write_reg(DTMB_CHE_IBDFE_CONFIG6, 0x943228cc);

View File

@@ -22,47 +22,48 @@
#define DTMB_FRONT_ADDR(x) (DTMB_DEMOD_BASE + (x << 2))
#define DTMB_FRONT_AFIFO_ADC DTMB_FRONT_ADDR(0x20)
#define DTMB_FRONT_AGC_CONFIG1 DTMB_FRONT_ADDR(0x21)
#define DTMB_FRONT_AGC_CONFIG2 DTMB_FRONT_ADDR(0x22)
#define DTMB_FRONT_AGC_CONFIG3 DTMB_FRONT_ADDR(0x23)
#define DTMB_FRONT_AGC_CONFIG4 DTMB_FRONT_ADDR(0x24)
#define DTMB_FRONT_DDC_BYPASS DTMB_FRONT_ADDR(0x25)
#define DTMB_FRONT_DC_HOLD DTMB_FRONT_ADDR(0x28)
#define DTMB_FRONT_DAGC_TARGET_POWER DTMB_FRONT_ADDR(0x29)
#define DTMB_FRONT_ACF_BYPASS DTMB_FRONT_ADDR(0x2a)
#define DTMB_FRONT_COEF_SET1 DTMB_FRONT_ADDR(0x2b)
#define DTMB_FRONT_COEF_SET2 DTMB_FRONT_ADDR(0x2c)
#define DTMB_FRONT_COEF_SET3 DTMB_FRONT_ADDR(0x2d)
#define DTMB_FRONT_COEF_SET4 DTMB_FRONT_ADDR(0x2e)
#define DTMB_FRONT_COEF_SET5 DTMB_FRONT_ADDR(0x2f)
#define DTMB_FRONT_COEF_SET6 DTMB_FRONT_ADDR(0x30)
#define DTMB_FRONT_COEF_SET7 DTMB_FRONT_ADDR(0x31)
#define DTMB_FRONT_COEF_SET8 DTMB_FRONT_ADDR(0x32)
#define DTMB_FRONT_COEF_SET9 DTMB_FRONT_ADDR(0x33)
#define DTMB_FRONT_COEF_SET10 DTMB_FRONT_ADDR(0x34)
#define DTMB_FRONT_COEF_SET11 DTMB_FRONT_ADDR(0x35)
#define DTMB_FRONT_COEF_SET12 DTMB_FRONT_ADDR(0x36)
#define DTMB_FRONT_COEF_SET13 DTMB_FRONT_ADDR(0x37)
#define DTMB_FRONT_COEF_SET14 DTMB_FRONT_ADDR(0x38)
#define DTMB_FRONT_COEF_SET15 DTMB_FRONT_ADDR(0x39)
#define DTMB_FRONT_COEF_SET16 DTMB_FRONT_ADDR(0x3a)
#define DTMB_FRONT_COEF_SET17 DTMB_FRONT_ADDR(0x3b)
#define DTMB_FRONT_COEF_SET18 DTMB_FRONT_ADDR(0x3c)
#define DTMB_FRONT_COEF_SET19 DTMB_FRONT_ADDR(0x3d)
#define DTMB_FRONT_SRC_CONFIG1 DTMB_FRONT_ADDR(0x3e)
#define DTMB_FRONT_SRC_CONFIG2 DTMB_FRONT_ADDR(0x3f)
#define DTMB_FRONT_SFIFO_OUT_LEN DTMB_FRONT_ADDR(0x40)
#define DTMB_FRONT_DAGC_GAIN DTMB_FRONT_ADDR(0x41)
#define DTMB_FRONT_IQIB_STEP DTMB_FRONT_ADDR(0x42)
#define DTMB_FRONT_IQIB_CONFIG DTMB_FRONT_ADDR(0x43)
#define DTMB_FRONT_ST_CONFIG DTMB_FRONT_ADDR(0x44)
#define DTMB_FRONT_ST_FREQ DTMB_FRONT_ADDR(0x45)
#define DTMB_FRONT_46_CONFIG DTMB_FRONT_ADDR(0x46)
#define DTMB_FRONT_47_CONFIG DTMB_FRONT_ADDR(0x47)
#define DTMB_FRONT_DEBUG_CFG DTMB_FRONT_ADDR(0x48)
#define DTMB_FRONT_MEM_ADDR DTMB_FRONT_ADDR(0x49)
#define DTMB_FRONT_19_CONFIG DTMB_FRONT_ADDR(0x19)
#define DTMB_FRONT_4d_CONFIG DTMB_FRONT_ADDR(0x4d)
#define DTMB_FRONT_19_CONFIG DTMB_FRONT_ADDR(0x19)
#define DTMB_FRONT_AFIFO_ADC DTMB_FRONT_ADDR(0x20)
#define DTMB_FRONT_AGC_CONFIG1 DTMB_FRONT_ADDR(0x21)
#define DTMB_FRONT_AGC_CONFIG2 DTMB_FRONT_ADDR(0x22)
#define DTMB_FRONT_AGC_CONFIG3 DTMB_FRONT_ADDR(0x23)
#define DTMB_FRONT_AGC_CONFIG4 DTMB_FRONT_ADDR(0x24)
#define DTMB_FRONT_DDC_BYPASS DTMB_FRONT_ADDR(0x25)
#define DTMB_FRONT_DC_HOLD DTMB_FRONT_ADDR(0x28)
#define DTMB_FRONT_DAGC_TARGET_POWER DTMB_FRONT_ADDR(0x29)
#define DTMB_FRONT_ACF_BYPASS DTMB_FRONT_ADDR(0x2a)
#define DTMB_FRONT_COEF_SET1 DTMB_FRONT_ADDR(0x2b)
#define DTMB_FRONT_COEF_SET2 DTMB_FRONT_ADDR(0x2c)
#define DTMB_FRONT_COEF_SET3 DTMB_FRONT_ADDR(0x2d)
#define DTMB_FRONT_COEF_SET4 DTMB_FRONT_ADDR(0x2e)
#define DTMB_FRONT_COEF_SET5 DTMB_FRONT_ADDR(0x2f)
#define DTMB_FRONT_COEF_SET6 DTMB_FRONT_ADDR(0x30)
#define DTMB_FRONT_COEF_SET7 DTMB_FRONT_ADDR(0x31)
#define DTMB_FRONT_COEF_SET8 DTMB_FRONT_ADDR(0x32)
#define DTMB_FRONT_COEF_SET9 DTMB_FRONT_ADDR(0x33)
#define DTMB_FRONT_COEF_SET10 DTMB_FRONT_ADDR(0x34)
#define DTMB_FRONT_COEF_SET11 DTMB_FRONT_ADDR(0x35)
#define DTMB_FRONT_COEF_SET12 DTMB_FRONT_ADDR(0x36)
#define DTMB_FRONT_COEF_SET13 DTMB_FRONT_ADDR(0x37)
#define DTMB_FRONT_COEF_SET14 DTMB_FRONT_ADDR(0x38)
#define DTMB_FRONT_COEF_SET15 DTMB_FRONT_ADDR(0x39)
#define DTMB_FRONT_COEF_SET16 DTMB_FRONT_ADDR(0x3a)
#define DTMB_FRONT_COEF_SET17 DTMB_FRONT_ADDR(0x3b)
#define DTMB_FRONT_COEF_SET18 DTMB_FRONT_ADDR(0x3c)
#define DTMB_FRONT_COEF_SET19 DTMB_FRONT_ADDR(0x3d)
#define DTMB_FRONT_SRC_CONFIG1 DTMB_FRONT_ADDR(0x3e)
#define DTMB_FRONT_SRC_CONFIG2 DTMB_FRONT_ADDR(0x3f)
#define DTMB_FRONT_SFIFO_OUT_LEN DTMB_FRONT_ADDR(0x40)
#define DTMB_FRONT_DAGC_GAIN DTMB_FRONT_ADDR(0x41)
#define DTMB_FRONT_IQIB_STEP DTMB_FRONT_ADDR(0x42)
#define DTMB_FRONT_IQIB_CONFIG DTMB_FRONT_ADDR(0x43)
#define DTMB_FRONT_ST_CONFIG DTMB_FRONT_ADDR(0x44)
#define DTMB_FRONT_ST_FREQ DTMB_FRONT_ADDR(0x45)
#define DTMB_FRONT_46_CONFIG DTMB_FRONT_ADDR(0x46)
#define DTMB_FRONT_47_CONFIG DTMB_FRONT_ADDR(0x47)
#define DTMB_FRONT_DEBUG_CFG DTMB_FRONT_ADDR(0x48)
#define DTMB_FRONT_MEM_ADDR DTMB_FRONT_ADDR(0x49)
#define DTMB_FRONT_4d_CONFIG DTMB_FRONT_ADDR(0x4d)
#define DTMB_FRONT_4e_CONFIG DTMB_FRONT_ADDR(0x4e)
#endif

View File

@@ -29,8 +29,8 @@ struct amlfe_config {
int tuner_addr;
};
enum Gxtv_Demod_Tuner_If {
Si2176_5M_If = 5,
Si2176_6M_If = 6
SI2176_5M_IF = 5,
SI2176_6M_IF = 6
};
/* 0 -DVBC, 1-DVBT, ISDBT, 2-ATSC */
enum Gxtv_Demod_Dvb_Mode {
@@ -54,7 +54,7 @@ enum demod_md {
#define Adc_Clk_35M 35714 /* adc clk dvbc */
#define Demod_Clk_71M 71428 /* demod clk */
#define Adc_Clk_24M 24000
#define ADC_CLK_24M 24000
#define Demod_Clk_72M 72000
#define Demod_Clk_60M 60000

View File

@@ -36,9 +36,9 @@ enum atsc_performance {
};
#define Lock 1
#define UnLock 0
#define UNLOCK 0
#define Cfo_Ok 1
#define Cfo_Fail 0
#define CFO_FAIL 0
#define Dagc_Open 1
#define Dagc_Close 0
#define Atsc_BandWidth (6000)

View File

@@ -503,6 +503,7 @@ static int pts_checkin_offset_inline(u8 type, u32 offset, u32 val, u64 uS64)
#ifdef CALC_CACHED_TIME
pts_checkin_offset_calc_cached(offset, val, pTable);
#endif
timestamp_clac_pts_latency(type, val);
list_move_tail(&rec->list, &pTable->valid_list);
@@ -515,7 +516,7 @@ static int pts_checkin_offset_inline(u8 type, u32 offset, u32 val, u64 uS64)
if (tsync_get_debug_apts() && (type == PTS_TYPE_AUDIO))
pr_info("init apts[%d] at 0x%x\n", type, val);
if (type == PTS_TYPE_VIDEO)
if (type == PTS_TYPE_VIDEO && !tsync_get_tunnel_mode())
timestamp_vpts_set(val);
else if (type == PTS_TYPE_AUDIO)
timestamp_apts_set(val);
@@ -566,7 +567,8 @@ int pts_checkin_wrptr(u8 type, u32 ptr, u32 val)
get_wrpage_offset(type, &page, &cur_offset);
page_no = (offset > cur_offset) ? (page - 1) : page;
if (type == PTS_TYPE_VIDEO)
val += tsync_get_vpts_adjust();
return pts_checkin_offset(type,
pts_table[type].buf_size * page_no + offset,
val);

View File

@@ -43,6 +43,8 @@ static u32 first_apts;
static u32 pcrscr_lantcy = 200*90;
static u32 video_pts;
static u32 audio_pts;
static u32 last_apts_gap;
static u32 last_vpts_gap;
static u32 system_time_scale_base = 1;
static u32 system_time_scale_remainder;
@@ -123,7 +125,7 @@ EXPORT_SYMBOL(timestamp_apts_started);
u32 timestamp_pcrscr_get(void)
{
if (tsync_get_mode() == TSYNC_MODE_AMASTER)
if (tsync_get_mode() != TSYNC_MODE_PCRMASTER)
return system_time;
if (tsdemux_pcrscr_valid_cb && tsdemux_pcrscr_valid_cb()) {
@@ -150,6 +152,8 @@ void timestamp_set_pcrlatency(u32 latency)
{
if (latency < 500 * 90)
pcrscr_lantcy = latency;
else
pcrscr_lantcy = 500 * 90;
}
EXPORT_SYMBOL(timestamp_set_pcrlatency);
@@ -159,6 +163,102 @@ u32 timestamp_get_pcrlatency(void)
}
EXPORT_SYMBOL(timestamp_get_pcrlatency);
void timestamp_clac_pts_latency(u8 type, u32 pts)
{
u32 demux_pcr = 0;
u32 t1, t2, pts_diff;
if (tsync_get_mode() != TSYNC_MODE_PCRMASTER)
return;
if (tsdemux_pcrscr_valid_cb && tsdemux_pcrscr_valid_cb()
&& tsync_pcr_demux_pcr_used()) {
if (tsdemux_pcrscr_get_cb)
demux_pcr = tsdemux_pcrscr_get_cb();
else
return;
if (demux_pcr == 0 ||
demux_pcr == 0xffffffff) {
last_apts_gap = 0;
last_vpts_gap = 0;
return;
}
if (type == 0) {
if (demux_pcr > pts) {
last_vpts_gap = 0;
return;
}
pts_diff = pts - demux_pcr;
if (pts_diff > 500 * 90)
return;
t1 = ((last_vpts_gap >> 16) & 0xff);
if (t1 > 5)
t1 = 0;
t2 = (last_vpts_gap & 0xffff);
if (t2 == 0) {
last_vpts_gap = pts_diff;
return;
}
if (abs(t2 - pts_diff) < 30 * 90) {
last_vpts_gap = t2;
return;
}
t1++;
if (t1 >= 5)
last_vpts_gap = pts_diff;
else
last_vpts_gap = ((t1 << 16) | t2);
} else if (type == 1) {
if (demux_pcr > pts) {
last_apts_gap = 0;
return;
}
pts_diff = pts - demux_pcr;
if (pts_diff > 500 * 90)
return;
t1 = ((last_apts_gap >> 16) & 0xff);
if (t1 > 5)
t1 = 0;
t2 = (last_apts_gap & 0xffff);
if (t2 == 0) {
last_apts_gap = pts_diff;
return;
}
if (abs(t2 - pts_diff) < 30 * 90) {
last_apts_gap = t2;
return;
}
t1++;
if (t1 >= 5)
last_apts_gap = pts_diff;
else
last_apts_gap = ((t1 << 16) | t2);
}
} else {
last_apts_gap = 0;
last_vpts_gap = 0;
}
}
EXPORT_SYMBOL(timestamp_clac_pts_latency);
u32 timestamp_get_pts_latency(u8 type)
{
if (type == 0)
return (last_vpts_gap & 0xffff);
else if (type == 1)
return (last_apts_gap & 0xffff);
return 0;
}
EXPORT_SYMBOL(timestamp_get_pts_latency);
void timestamp_clean_pts_latency(u8 type)
{
if (type == 0)
last_vpts_gap = 0;
else if (type == 1)
last_apts_gap = 0;
}
EXPORT_SYMBOL(timestamp_clean_pts_latency);
u32 timestamp_tsdemux_pcr_get(void)
{
if (tsdemux_pcrscr_get_cb)
@@ -193,6 +293,7 @@ void timestamp_checkin_firstvpts_set(u32 pts)
{
first_checkin_vpts = pts;
pr_info("video first checkin pts = %x\n", first_checkin_vpts);
timestamp_clean_pts_latency(0);
}
EXPORT_SYMBOL(timestamp_checkin_firstvpts_set);
@@ -200,6 +301,7 @@ void timestamp_checkin_firstapts_set(u32 pts)
{
first_checkin_apts = pts;
pr_info("audio first checkin pts =%x\n", first_checkin_apts);
timestamp_clean_pts_latency(1);
}
EXPORT_SYMBOL(timestamp_checkin_firstapts_set);

Some files were not shown because too many files have changed in this diff Show More