コード例 #1
0
/*
 * only 2 interrupts may occur: screen plug/unplug and EDID read
 */
static irqreturn_t tda998x_irq_thread(int irq, void *data)
{
	struct tda998x_priv *priv = data;
	u8 sta, cec, lvl, flag0, flag1, flag2;

	if (!priv)
		return IRQ_HANDLED;
	sta = cec_read(priv, REG_CEC_INTSTATUS);
	cec = cec_read(priv, REG_CEC_RXSHPDINT);
	lvl = cec_read(priv, REG_CEC_RXSHPDLEV);
	flag0 = reg_read(priv, REG_INT_FLAGS_0);
	flag1 = reg_read(priv, REG_INT_FLAGS_1);
	flag2 = reg_read(priv, REG_INT_FLAGS_2);
	DRM_DEBUG_DRIVER(
		"tda irq sta %02x cec %02x lvl %02x f0 %02x f1 %02x f2 %02x\n",
		sta, cec, lvl, flag0, flag1, flag2);
	if ((flag2 & INT_FLAGS_2_EDID_BLK_RD) && priv->wq_edid_wait) {
		priv->wq_edid_wait = 0;
		wake_up(&priv->wq_edid);
	} else if (cec != 0) {			/* HPD change */
		if (priv->encoder && priv->encoder->dev)
			drm_helper_hpd_irq_event(priv->encoder->dev);
	}
	return IRQ_HANDLED;
}
コード例 #2
0
/*
 * only 2 interrupts may occur: screen plug/unplug and EDID read
 */
static irqreturn_t tda998x_irq_thread(int irq, void *data)
{
	struct tda998x_priv *priv = data;
	u8 sta, cec, lvl, flag0, flag1, flag2;
	bool handled = false;

	sta = cec_read(priv, REG_CEC_INTSTATUS);
	cec = cec_read(priv, REG_CEC_RXSHPDINT);
	lvl = cec_read(priv, REG_CEC_RXSHPDLEV);
	flag0 = reg_read(priv, REG_INT_FLAGS_0);
	flag1 = reg_read(priv, REG_INT_FLAGS_1);
	flag2 = reg_read(priv, REG_INT_FLAGS_2);
	DRM_DEBUG_DRIVER(
		"tda irq sta %02x cec %02x lvl %02x f0 %02x f1 %02x f2 %02x\n",
		sta, cec, lvl, flag0, flag1, flag2);

	if (cec & CEC_RXSHPDINT_HPD) {
		if (lvl & CEC_RXSHPDLEV_HPD)
			tda998x_edid_delay_start(priv);
		else
			schedule_work(&priv->detect_work);

		handled = true;
	}

	if ((flag2 & INT_FLAGS_2_EDID_BLK_RD) && priv->wq_edid_wait) {
		priv->wq_edid_wait = 0;
		wake_up(&priv->wq_edid);
		handled = true;
	}

	return IRQ_RETVAL(handled);
}
コード例 #3
0
ファイル: tegra_cec.c プロジェクト: ReneNyffenegger/linux
static int tegra_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
				   u32 signal_free_time_ms, struct cec_msg *msg)
{
	bool retry_xfer = signal_free_time_ms == CEC_SIGNAL_FREE_TIME_RETRY;
	struct tegra_cec *cec = adap->priv;
	unsigned int i;
	u32 mode = 0;
	u32 mask;

	if (cec_msg_is_broadcast(msg))
		mode = TEGRA_CEC_TX_REG_BCAST;

	cec->tx_buf_cur = 0;
	cec->tx_buf_cnt = msg->len;

	for (i = 0; i < msg->len; i++) {
		cec->tx_buf[i] = mode | msg->msg[i];
		if (i == 0)
			cec->tx_buf[i] |= TEGRA_CEC_TX_REG_START_BIT;
		if (i == msg->len - 1)
			cec->tx_buf[i] |= TEGRA_CEC_TX_REG_EOM;
		if (i == 0 && retry_xfer)
			cec->tx_buf[i] |= TEGRA_CEC_TX_REG_RETRY;
	}

	mask = cec_read(cec, TEGRA_CEC_INT_MASK);
	cec_write(cec, TEGRA_CEC_INT_MASK,
		  mask | TEGRA_CEC_INT_MASK_TX_REGISTER_EMPTY);

	return 0;
}
コード例 #4
0
ファイル: tda998x_drv.c プロジェクト: 0x000000FF/edison-linux
static enum drm_connector_status
tda998x_encoder_detect(struct tda998x_priv *priv)
{
	uint8_t val = cec_read(priv, REG_CEC_RXSHPDLEV);

	return (val & CEC_RXSHPDLEV_HPD) ? connector_status_connected :
			connector_status_disconnected;
}
コード例 #5
0
static enum drm_connector_status
tda998x_connector_detect(struct drm_connector *connector, bool force)
{
	struct tda998x_priv *priv = conn_to_tda998x_priv(connector);
	u8 val = cec_read(priv, REG_CEC_RXSHPDLEV);

	return (val & CEC_RXSHPDLEV_HPD) ? connector_status_connected :
			connector_status_disconnected;
}
コード例 #6
0
ファイル: tegra_cec.c プロジェクト: ReneNyffenegger/linux
static void tegra_cec_error_recovery(struct tegra_cec *cec)
{
	u32 hw_ctrl;

	hw_ctrl = cec_read(cec, TEGRA_CEC_HW_CONTROL);
	cec_write(cec, TEGRA_CEC_HW_CONTROL, 0);
	cec_write(cec, TEGRA_CEC_INT_STAT, 0xffffffff);
	cec_write(cec, TEGRA_CEC_HW_CONTROL, hw_ctrl);
}
コード例 #7
0
ファイル: tegra_cec.c プロジェクト: ReneNyffenegger/linux
static int tegra_cec_adap_monitor_all_enable(struct cec_adapter *adap,
					     bool enable)
{
	struct tegra_cec *cec = adap->priv;
	u32 reg = cec_read(cec, TEGRA_CEC_HW_CONTROL);

	if (enable)
		reg |= TEGRA_CEC_HWCTRL_RX_SNOOP;
	else
		reg &= ~TEGRA_CEC_HWCTRL_RX_SNOOP;
	cec_write(cec, TEGRA_CEC_HW_CONTROL, reg);
	return 0;
}
コード例 #8
0
ファイル: tegra_cec.c プロジェクト: ReneNyffenegger/linux
static int tegra_cec_adap_log_addr(struct cec_adapter *adap, u8 logical_addr)
{
	struct tegra_cec *cec = adap->priv;
	u32 state = cec_read(cec, TEGRA_CEC_HW_CONTROL);

	if (logical_addr == CEC_LOG_ADDR_INVALID)
		state &= ~TEGRA_CEC_HWCTRL_RX_LADDR_MASK;
	else
		state |= TEGRA_CEC_HWCTRL_RX_LADDR((1 << logical_addr));

	cec_write(cec, TEGRA_CEC_HW_CONTROL, state);
	return 0;
}
コード例 #9
0
ファイル: tegra_cec.c プロジェクト: ReneNyffenegger/linux
static irqreturn_t tegra_cec_irq_handler(int irq, void *data)
{
	struct device *dev = data;
	struct tegra_cec *cec = dev_get_drvdata(dev);
	u32 status, mask;

	status = cec_read(cec, TEGRA_CEC_INT_STAT);
	mask = cec_read(cec, TEGRA_CEC_INT_MASK);

	status &= mask;

	if (!status)
		return IRQ_HANDLED;

	if (status & TEGRA_CEC_INT_STAT_TX_REGISTER_UNDERRUN) {
		dev_err(dev, "TX underrun, interrupt timing issue!\n");

		tegra_cec_error_recovery(cec);
		cec_write(cec, TEGRA_CEC_INT_MASK,
			  mask & ~TEGRA_CEC_INT_MASK_TX_REGISTER_EMPTY);

		cec->tx_done = true;
		cec->tx_status = CEC_TX_STATUS_ERROR;
		return IRQ_WAKE_THREAD;
	}

	if ((status & TEGRA_CEC_INT_STAT_TX_ARBITRATION_FAILED) ||
		   (status & TEGRA_CEC_INT_STAT_TX_BUS_ANOMALY_DETECTED)) {
		tegra_cec_error_recovery(cec);
		cec_write(cec, TEGRA_CEC_INT_MASK,
			  mask & ~TEGRA_CEC_INT_MASK_TX_REGISTER_EMPTY);

		cec->tx_done = true;
		if (status & TEGRA_CEC_INT_STAT_TX_BUS_ANOMALY_DETECTED)
			cec->tx_status = CEC_TX_STATUS_LOW_DRIVE;
		else
			cec->tx_status = CEC_TX_STATUS_ARB_LOST;
		return IRQ_WAKE_THREAD;
	}

	if (status & TEGRA_CEC_INT_STAT_TX_FRAME_TRANSMITTED) {
		cec_write(cec, TEGRA_CEC_INT_STAT,
			  TEGRA_CEC_INT_STAT_TX_FRAME_TRANSMITTED);

		if (status & TEGRA_CEC_INT_STAT_TX_FRAME_OR_BLOCK_NAKD) {
			tegra_cec_error_recovery(cec);

			cec->tx_done = true;
			cec->tx_status = CEC_TX_STATUS_NACK;
		} else {
			cec->tx_done = true;
			cec->tx_status = CEC_TX_STATUS_OK;
		}
		return IRQ_WAKE_THREAD;
	}

	if (status & TEGRA_CEC_INT_STAT_TX_FRAME_OR_BLOCK_NAKD)
		dev_warn(dev, "TX NAKed on the fly!\n");

	if (status & TEGRA_CEC_INT_STAT_TX_REGISTER_EMPTY) {
		if (cec->tx_buf_cur == cec->tx_buf_cnt) {
			cec_write(cec, TEGRA_CEC_INT_MASK,
				  mask & ~TEGRA_CEC_INT_MASK_TX_REGISTER_EMPTY);
		} else {
			cec_write(cec, TEGRA_CEC_TX_REGISTER,
				  cec->tx_buf[cec->tx_buf_cur++]);
			cec_write(cec, TEGRA_CEC_INT_STAT,
				  TEGRA_CEC_INT_STAT_TX_REGISTER_EMPTY);
		}
	}

	if (status & (TEGRA_CEC_INT_STAT_RX_REGISTER_OVERRUN |
		      TEGRA_CEC_INT_STAT_RX_BUS_ANOMALY_DETECTED |
		      TEGRA_CEC_INT_STAT_RX_START_BIT_DETECTED |
		      TEGRA_CEC_INT_STAT_RX_BUS_ERROR_DETECTED)) {
		cec_write(cec, TEGRA_CEC_INT_STAT,
			  (TEGRA_CEC_INT_STAT_RX_REGISTER_OVERRUN |
			   TEGRA_CEC_INT_STAT_RX_BUS_ANOMALY_DETECTED |
			   TEGRA_CEC_INT_STAT_RX_START_BIT_DETECTED |
			   TEGRA_CEC_INT_STAT_RX_BUS_ERROR_DETECTED));
	} else if (status & TEGRA_CEC_INT_STAT_RX_REGISTER_FULL) {
		u32 v;

		cec_write(cec, TEGRA_CEC_INT_STAT,
			  TEGRA_CEC_INT_STAT_RX_REGISTER_FULL);
		v = cec_read(cec, TEGRA_CEC_RX_REGISTER);
		if (cec->rx_buf_cnt < CEC_MAX_MSG_SIZE)
			cec->rx_buf[cec->rx_buf_cnt++] = v & 0xff;
		if (v & TEGRA_CEC_RX_REGISTER_EOM) {
			cec->rx_done = true;
			return IRQ_WAKE_THREAD;
		}
	}

	return IRQ_HANDLED;
}