Skip to content

Commit

Permalink
drm: zynqmp_dp: Use AUX IRQs instead of polling
Browse files Browse the repository at this point in the history
Instead of polling the status register for the AUX status, just enable
the IRQs and signal a completion.

Signed-off-by: Sean Anderson <sean.anderson@linux.dev>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240809193600.3360015-6-sean.anderson@linux.dev
  • Loading branch information
Sean Anderson authored and Tomi Valkeinen committed Oct 30, 2024
1 parent 948a944 commit 2425dee
Showing 1 changed file with 25 additions and 10 deletions.
35 changes: 25 additions & 10 deletions drivers/gpu/drm/xlnx/zynqmp_dp.c
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@ struct zynqmp_dp_config {
* @next_bridge: The downstream bridge
* @config: IP core configuration from DTS
* @aux: aux channel
* @aux_done: Completed when we get an AUX reply or timeout
* @phy: PHY handles for DP lanes
* @num_lanes: number of enabled phy lanes
* @hpd_work: hot plug detection worker
Expand All @@ -306,6 +307,7 @@ struct zynqmp_dp {
struct drm_bridge bridge;
struct work_struct hpd_work;
struct work_struct hpd_irq_work;
struct completion aux_done;
struct mutex lock;

struct drm_bridge *next_bridge;
Expand Down Expand Up @@ -942,12 +944,15 @@ static int zynqmp_dp_aux_cmd_submit(struct zynqmp_dp *dp, u32 cmd, u16 addr,
u8 *buf, u8 bytes, u8 *reply)
{
bool is_read = (cmd & AUX_READ_BIT) ? true : false;
unsigned long time_left;
u32 reg, i;

reg = zynqmp_dp_read(dp, ZYNQMP_DP_INTERRUPT_SIGNAL_STATE);
if (reg & ZYNQMP_DP_INTERRUPT_SIGNAL_STATE_REQUEST)
return -EBUSY;

reinit_completion(&dp->aux_done);

zynqmp_dp_write(dp, ZYNQMP_DP_AUX_ADDRESS, addr);
if (!is_read)
for (i = 0; i < bytes; i++)
Expand All @@ -962,17 +967,14 @@ static int zynqmp_dp_aux_cmd_submit(struct zynqmp_dp *dp, u32 cmd, u16 addr,
zynqmp_dp_write(dp, ZYNQMP_DP_AUX_COMMAND, reg);

/* Wait for reply to be delivered upto 2ms */
for (i = 0; ; i++) {
reg = zynqmp_dp_read(dp, ZYNQMP_DP_INTERRUPT_SIGNAL_STATE);
if (reg & ZYNQMP_DP_INTERRUPT_SIGNAL_STATE_REPLY)
break;
time_left = wait_for_completion_timeout(&dp->aux_done,
msecs_to_jiffies(2));
if (!time_left)
return -ETIMEDOUT;

if (reg & ZYNQMP_DP_INTERRUPT_SIGNAL_STATE_REPLY_TIMEOUT ||
i == 2)
return -ETIMEDOUT;

usleep_range(1000, 1100);
}
reg = zynqmp_dp_read(dp, ZYNQMP_DP_INTERRUPT_SIGNAL_STATE);
if (reg & ZYNQMP_DP_INTERRUPT_SIGNAL_STATE_REPLY_TIMEOUT)
return -ETIMEDOUT;

reg = zynqmp_dp_read(dp, ZYNQMP_DP_AUX_REPLY_CODE);
if (reply)
Expand Down Expand Up @@ -1056,6 +1058,9 @@ static int zynqmp_dp_aux_init(struct zynqmp_dp *dp)
(w << ZYNQMP_DP_AUX_CLK_DIVIDER_AUX_FILTER_SHIFT) |
(rate / (1000 * 1000)));

zynqmp_dp_write(dp, ZYNQMP_DP_INT_EN, ZYNQMP_DP_INT_REPLY_RECEIVED |
ZYNQMP_DP_INT_REPLY_TIMEOUT);

dp->aux.name = "ZynqMP DP AUX";
dp->aux.dev = dp->dev;
dp->aux.drm_dev = dp->bridge.dev;
Expand All @@ -1073,6 +1078,9 @@ static int zynqmp_dp_aux_init(struct zynqmp_dp *dp)
static void zynqmp_dp_aux_cleanup(struct zynqmp_dp *dp)
{
drm_dp_aux_unregister(&dp->aux);

zynqmp_dp_write(dp, ZYNQMP_DP_INT_DS, ZYNQMP_DP_INT_REPLY_RECEIVED |
ZYNQMP_DP_INT_REPLY_TIMEOUT);
}

/* -----------------------------------------------------------------------------
Expand Down Expand Up @@ -1730,6 +1738,12 @@ static irqreturn_t zynqmp_dp_irq_handler(int irq, void *data)
if (status & ZYNQMP_DP_INT_HPD_IRQ)
schedule_work(&dp->hpd_irq_work);

if (status & ZYNQMP_DP_INTERRUPT_SIGNAL_STATE_REPLY)
complete(&dp->aux_done);

if (status & ZYNQMP_DP_INTERRUPT_SIGNAL_STATE_REPLY_TIMEOUT)
complete(&dp->aux_done);

return IRQ_HANDLED;
}

Expand All @@ -1753,6 +1767,7 @@ int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub)
dp->dpsub = dpsub;
dp->status = connector_status_disconnected;
mutex_init(&dp->lock);
init_completion(&dp->aux_done);

INIT_WORK(&dp->hpd_work, zynqmp_dp_hpd_work_func);
INIT_WORK(&dp->hpd_irq_work, zynqmp_dp_hpd_irq_work_func);
Expand Down

0 comments on commit 2425dee

Please sign in to comment.