blob: 6880d485b023e5f2f44c010f3a385b59eff30927 [file] [log] [blame]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* 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)) {
if (di_que_is_empty(ch, QUE_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;
//ary 2020-12-09 ulong flags = 0;
struct di_ch_s *pch;
ch = pst->curr_ch;
ppost = get_post_stru(ch);
//di_buf = get_di_buf_head(ch, QUEUE_POST_DOING);
di_buf = di_que_peek(ch, QUE_POST_DOING);
if (dim_check_di_buf(di_buf, 20, ch)) {
PR_ERR("%s:err1\n", __func__);
return reflesh;
}
vf_p = di_buf->vframe;
pch = get_chdata(ch);
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++;
//ary 2020-12-09 spin_lock_irqsave(&plist_lock, flags);
dim_post_process(di_buf, 0, vf_p->width - 1,
0, vf_p->height - 1, vf_p);
//ary 2020-12-09 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;
//ary 2020-12-07 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);
//ary 2020-12-07 spin_lock_irqsave(&plist_lock, flags);
dim_post_de_done_buf_config(ch);
//ary 2020-12-07 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_post);
hpst_timeout_read();
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();
dimh_pst_trig_resize();
}
bool dpst_step_timeout(void)
{
struct di_hpst_s *pst = get_hw_pst();
unsigned int ch;
bool reflesh = false;
//ary 2020-12-07 ulong flags = 0;
ch = pst->curr_ch;
dpst_timeout(ch);
//ary 2020-12-07 spin_lock_irqsave(&plist_lock, flags);
dim_post_de_done_buf_config(ch);
//ary 2020-12-07 spin_unlock_irqrestore(&plist_lock, flags);
pst->flg_int_done = false;
pst->flg_have_set = 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", /*switch 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;
}
if (!ret)
PR_INF("%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();
}