mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-22 17:25:35 +03:00
tegra-cec: poll WR_LOCK for TX data sync
After programming the TX Register, it takes 3-4 clock cycles for TX data synchronization to the CEC core domain. The TX_EMPTY interrupt should not be cleared until this data synchronization is complete. Enable CEC HW feature to automatically clears the TX_EMPTY interrupt after TX data synchronization is complete. It takes time for HW to clear the interrupt and TX_EMPTY can still appear high, hence SW needs to poll WR_LOCK until it goes to 0. This will avoid SW to attempt the next TX block during the same TX_EMPTY interrupt. Also read RX_REGISTER based on the buffer occupancy which is indicated by the CEC_RX_BUFFER_STAT_0 register. Bug 4954851 Change-Id: I3ec3792c9ae3b8a00c800c921cf4e4d09369e6b9 Signed-off-by: Ken Chang <kenc@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3322519 Reviewed-by: Bitan Biswas <bbiswas@nvidia.com> Reviewed-by: Prafull Suryawanshi <prafulls@nvidia.com> Tested-by: Ruopeng Huang (SW-TEGRA) <robhuang@nvidia.com> GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
This commit is contained in:
@@ -119,10 +119,16 @@ static int tegra_cec_release(struct inode *inode, struct file *file)
|
||||
|
||||
static inline void tegra_cec_native_tx(const struct tegra_cec *cec, u32 block)
|
||||
{
|
||||
tegra_cec_writel(block, cec->cec_base + TEGRA_CEC_TX_REGISTER);
|
||||
tegra_cec_writel(TEGRA_CEC_INT_STAT_TX_REGISTER_EMPTY,
|
||||
cec->cec_base + TEGRA_CEC_INT_STAT);
|
||||
u32 tx_reg, retry;
|
||||
|
||||
tegra_cec_writel(block, cec->cec_base + TEGRA_CEC_TX_REGISTER);
|
||||
|
||||
tx_reg = tegra_cec_readl(cec->cec_base + TEGRA_CEC_TX_REGISTER);
|
||||
retry = 10;
|
||||
while ((tx_reg & 0x80000000) && retry--) {
|
||||
udelay(31); // one clock cycle = 30.5us
|
||||
tx_reg = tegra_cec_readl(cec->cec_base + TEGRA_CEC_TX_REGISTER);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void tegra_cec_error_recovery(struct tegra_cec *cec)
|
||||
@@ -235,24 +241,16 @@ static ssize_t tegra_cec_read(struct file *file, char __user *buffer,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (cec->rx_fifo_data != 0) {
|
||||
count = sizeof(cec->rx_fifo[0]) * (cec->rx_fifo_data);
|
||||
if (copy_to_user(buffer, &(cec->rx_fifo_data), count))
|
||||
return -EFAULT;
|
||||
count = sizeof(cec->rx_fifo[0]) * (cec->rx_fifo_data);
|
||||
if (copy_to_user(buffer, &(cec->rx_fifo[0]), count))
|
||||
return -EFAULT;
|
||||
|
||||
dev_dbg(cec->dev, "%s: %*phC", __func__, (int)count,
|
||||
&(cec->rx_fifo[0]));
|
||||
} else {
|
||||
count = sizeof(cec->rx_buffer);
|
||||
if (copy_to_user(buffer, &(cec->rx_buffer), count))
|
||||
return -EFAULT;
|
||||
dev_dbg(cec->dev, "%s: %*phC", __func__, (int)count,
|
||||
&(cec->rx_fifo[0]));
|
||||
|
||||
dev_dbg(cec->dev, "%s: %*phC", __func__, (int)count,
|
||||
&(cec->rx_buffer));
|
||||
}
|
||||
|
||||
cec->rx_buffer = 0x0;
|
||||
memset(&(cec->rx_fifo[0]), 0, count);
|
||||
cec->rx_wake = 0;
|
||||
cec->rx_fifo_data = 0;
|
||||
return count;
|
||||
}
|
||||
|
||||
@@ -332,28 +330,27 @@ static irqreturn_t tegra_cec_irq_handler(int irq, void *data)
|
||||
TEGRA_CEC_INT_STAT_RX_BUS_ERROR_DETECTED),
|
||||
cec->cec_base + TEGRA_CEC_INT_STAT);
|
||||
} else if (status & TEGRA_CEC_INT_STAT_RX_REGISTER_FULL) {
|
||||
/*
|
||||
Read TEGRA_CEC_RX_BUFFER_STAT_0 which have total number of blocks,
|
||||
then read every block continuously from TEGRA_CEC_RX_REGISTER.
|
||||
TEGRA_CEC_INT_STAT_RX_REGISTER_FULL sets only once and not for
|
||||
every block if there are more than 1 block in FIFO.
|
||||
*/
|
||||
cec->rx_fifo_data =
|
||||
tegra_cec_readl(cec->cec_base + TEGRA_CEC_RX_BUFFER_STAT_0);
|
||||
for (i = 0; i < cec->rx_fifo_data; i++) {
|
||||
cec->rx_fifo[i] =
|
||||
readw(cec->cec_base + TEGRA_CEC_RX_REGISTER);
|
||||
}
|
||||
|
||||
tegra_cec_writel(TEGRA_CEC_INT_STAT_RX_REGISTER_FULL,
|
||||
cec->cec_base + TEGRA_CEC_INT_STAT);
|
||||
if (cec->is_tegra_cec_suspended) {
|
||||
/*
|
||||
Read TEGRA_CEC_RX_BUFFER_STAT_0 which have total number of blocks,
|
||||
then read every block continuously from TEGRA_CEC_RX_REGISTER.
|
||||
TEGRA_CEC_INT_STAT_RX_REGISTER_FULL sets only once and not for
|
||||
every block if there are more than 1 block in FIFO.
|
||||
*/
|
||||
cec->rx_fifo_data =
|
||||
tegra_cec_readl(cec->cec_base + TEGRA_CEC_RX_BUFFER_STAT_0);
|
||||
for (i = 0; i < cec->rx_fifo_data; i++) {
|
||||
cec->rx_fifo[i] =
|
||||
readw(cec->cec_base + TEGRA_CEC_RX_REGISTER);
|
||||
}
|
||||
pm_wakeup_event(dev, 0);
|
||||
} else {
|
||||
cec->rx_buffer = readw(cec->cec_base + TEGRA_CEC_RX_REGISTER);
|
||||
cec->rx_fifo_data = 0;
|
||||
}
|
||||
cec->rx_wake = 1;
|
||||
wake_up_interruptible(&cec->rx_waitq);
|
||||
|
||||
if (cec->is_tegra_cec_suspended)
|
||||
pm_wakeup_event(dev, 0);
|
||||
|
||||
cec->rx_wake = 1;
|
||||
wake_up_interruptible(&cec->rx_waitq);
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -545,8 +542,9 @@ static void tegra_cec_init(struct tegra_cec *cec)
|
||||
|
||||
cec->logical_addr = TEGRA_CEC_HWCTRL_RX_LADDR_UNREG;
|
||||
|
||||
tegra_cec_writel(TEGRA_CEC_HWCTRL_RX_LADDR(cec->logical_addr),
|
||||
cec->cec_base + TEGRA_CEC_HW_CONTROL);
|
||||
state = TEGRA_CEC_HWCTRL_AUTO_CLR_TX_EMPTY_INTR |
|
||||
TEGRA_CEC_HWCTRL_RX_LADDR(cec->logical_addr);
|
||||
tegra_cec_writel(state, cec->cec_base + TEGRA_CEC_HW_CONTROL);
|
||||
|
||||
state = (0xff << TEGRA_CEC_RX_TIMING_1_RX_DATA_BIT_MAX_LO_TIME_MASK) |
|
||||
(0x22 << TEGRA_CEC_RX_TIMING_1_RX_DATA_BIT_SAMPLE_TIME_MASK) |
|
||||
|
||||
@@ -34,7 +34,6 @@ struct tegra_cec {
|
||||
struct work_struct work;
|
||||
unsigned int rx_wake;
|
||||
unsigned int tx_wake;
|
||||
u16 rx_buffer;
|
||||
long tx_error;
|
||||
u32 tx_buf[TEGRA_CEC_FRAME_MAX_LENGTH];
|
||||
u8 tx_buf_cur;
|
||||
@@ -90,6 +89,7 @@ struct tegra_cec {
|
||||
#define TEGRA_CEC_HWCTRL_RX_SNOOP (1<<15)
|
||||
#define TEGRA_CEC_HWCTRL_RX_NAK_MODE (1<<16)
|
||||
#define TEGRA_CEC_HWCTRL_TX_NAK_MODE (1<<24)
|
||||
#define TEGRA_CEC_HWCTRL_AUTO_CLR_TX_EMPTY_INTR (1<<29)
|
||||
#define TEGRA_CEC_HWCTRL_FAST_SIM_MODE (1<<30)
|
||||
#define TEGRA_CEC_HWCTRL_TX_RX_MODE (1<<31)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user