Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 62 additions & 30 deletions drivers/gpu/drm/vc4/vc4_hdmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -1621,7 +1621,7 @@ static irqreturn_t vc4_hdmi_hpd_irq_thread(int irq, void *priv)
struct vc4_hdmi *vc4_hdmi = priv;
struct drm_device *dev = vc4_hdmi->connector.dev;

if (dev)
if (dev && dev->registered)
drm_kms_helper_hotplug_event(dev);

return IRQ_HANDLED;
Expand All @@ -1630,33 +1630,45 @@ static irqreturn_t vc4_hdmi_hpd_irq_thread(int irq, void *priv)
static int vc4_hdmi_hotplug_init(struct vc4_hdmi *vc4_hdmi)
{
struct platform_device *pdev = vc4_hdmi->pdev;
struct device *dev = &pdev->dev;
struct drm_connector *connector = &vc4_hdmi->connector;
int ret;

if (vc4_hdmi->variant->external_irq_controller) {
ret = devm_request_threaded_irq(dev,
platform_get_irq_byname(pdev, "hpd-connected"),
NULL,
vc4_hdmi_hpd_irq_thread, IRQF_ONESHOT,
"vc4 hdmi hpd connected", vc4_hdmi);
unsigned int hpd_con = platform_get_irq_byname(pdev, "hpd-connected");
unsigned int hpd_rm = platform_get_irq_byname(pdev, "hpd-removed");

ret = request_threaded_irq(hpd_con,
NULL,
vc4_hdmi_hpd_irq_thread, IRQF_ONESHOT,
"vc4 hdmi hpd connected", vc4_hdmi);
if (ret)
return ret;

ret = devm_request_threaded_irq(dev,
platform_get_irq_byname(pdev, "hpd-removed"),
NULL,
vc4_hdmi_hpd_irq_thread, IRQF_ONESHOT,
"vc4 hdmi hpd disconnected", vc4_hdmi);
if (ret)
ret = request_threaded_irq(hpd_rm,
NULL,
vc4_hdmi_hpd_irq_thread, IRQF_ONESHOT,
"vc4 hdmi hpd disconnected", vc4_hdmi);
if (ret) {
free_irq(hpd_con, vc4_hdmi);
return ret;
}

connector->polled = DRM_CONNECTOR_POLL_HPD;
}

return 0;
}

static void vc4_hdmi_hotplug_exit(struct vc4_hdmi *vc4_hdmi)
{
struct platform_device *pdev = vc4_hdmi->pdev;

if (vc4_hdmi->variant->external_irq_controller) {
free_irq(platform_get_irq_byname(pdev, "hpd-connected"), vc4_hdmi);
free_irq(platform_get_irq_byname(pdev, "hpd-removed"), vc4_hdmi);
}
}

#ifdef CONFIG_DRM_VC4_HDMI_CEC
static irqreturn_t vc4_cec_irq_handler_rx_thread(int irq, void *priv)
{
Expand Down Expand Up @@ -1922,38 +1934,46 @@ static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi)
vc4_hdmi_cec_update_clk_div(vc4_hdmi);

if (vc4_hdmi->variant->external_irq_controller) {
ret = devm_request_threaded_irq(&pdev->dev,
platform_get_irq_byname(pdev, "cec-rx"),
vc4_cec_irq_handler_rx_bare,
vc4_cec_irq_handler_rx_thread, 0,
"vc4 hdmi cec rx", vc4_hdmi);
ret = request_threaded_irq(platform_get_irq_byname(pdev, "cec-rx"),
vc4_cec_irq_handler_rx_bare,
vc4_cec_irq_handler_rx_thread, 0,
"vc4 hdmi cec rx", vc4_hdmi);
if (ret)
goto err_delete_cec_adap;

ret = devm_request_threaded_irq(&pdev->dev,
platform_get_irq_byname(pdev, "cec-tx"),
vc4_cec_irq_handler_tx_bare,
vc4_cec_irq_handler_tx_thread, 0,
"vc4 hdmi cec tx", vc4_hdmi);
ret = request_threaded_irq(platform_get_irq_byname(pdev, "cec-tx"),
vc4_cec_irq_handler_tx_bare,
vc4_cec_irq_handler_tx_thread, 0,
"vc4 hdmi cec tx", vc4_hdmi);
if (ret)
goto err_delete_cec_adap;
goto err_remove_cec_rx_handler;
} else {
HDMI_WRITE(HDMI_CEC_CPU_MASK_SET, 0xffffffff);

ret = devm_request_threaded_irq(&pdev->dev, platform_get_irq(pdev, 0),
vc4_cec_irq_handler,
vc4_cec_irq_handler_thread, 0,
"vc4 hdmi cec", vc4_hdmi);
ret = request_threaded_irq(platform_get_irq(pdev, 0),
vc4_cec_irq_handler,
vc4_cec_irq_handler_thread, 0,
"vc4 hdmi cec", vc4_hdmi);
if (ret)
goto err_delete_cec_adap;
}

ret = cec_register_adapter(vc4_hdmi->cec_adap, &pdev->dev);
if (ret < 0)
goto err_delete_cec_adap;
goto err_remove_handlers;

return 0;

err_remove_handlers:
if (vc4_hdmi->variant->external_irq_controller)
free_irq(platform_get_irq_byname(pdev, "cec-tx"), vc4_hdmi);
else
free_irq(platform_get_irq(pdev, 0), vc4_hdmi);

err_remove_cec_rx_handler:
if (vc4_hdmi->variant->external_irq_controller)
free_irq(platform_get_irq_byname(pdev, "cec-rx"), vc4_hdmi);

err_delete_cec_adap:
cec_delete_adapter(vc4_hdmi->cec_adap);

Expand All @@ -1962,6 +1982,15 @@ static int vc4_hdmi_cec_init(struct vc4_hdmi *vc4_hdmi)

static void vc4_hdmi_cec_exit(struct vc4_hdmi *vc4_hdmi)
{
struct platform_device *pdev = vc4_hdmi->pdev;

if (vc4_hdmi->variant->external_irq_controller) {
free_irq(platform_get_irq_byname(pdev, "cec-rx"), vc4_hdmi);
free_irq(platform_get_irq_byname(pdev, "cec-tx"), vc4_hdmi);
} else {
free_irq(platform_get_irq(pdev, 0), vc4_hdmi);
}

cec_unregister_adapter(vc4_hdmi->cec_adap);
}
#else
Expand Down Expand Up @@ -2319,7 +2348,7 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)

ret = vc4_hdmi_cec_init(vc4_hdmi);
if (ret)
goto err_destroy_conn;
goto err_free_hotplug;

ret = vc4_hdmi_audio_init(vc4_hdmi);
if (ret)
Expand All @@ -2335,6 +2364,8 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)

err_free_cec:
vc4_hdmi_cec_exit(vc4_hdmi);
err_free_hotplug:
vc4_hdmi_hotplug_exit(vc4_hdmi);
err_destroy_conn:
vc4_hdmi_connector_destroy(&vc4_hdmi->connector);
err_destroy_encoder:
Expand Down Expand Up @@ -2377,6 +2408,7 @@ static void vc4_hdmi_unbind(struct device *dev, struct device *master,
kfree(vc4_hdmi->hd_regset.regs);

vc4_hdmi_cec_exit(vc4_hdmi);
vc4_hdmi_hotplug_exit(vc4_hdmi);
vc4_hdmi_connector_destroy(&vc4_hdmi->connector);
drm_encoder_cleanup(&vc4_hdmi->encoder.base.base);

Expand Down