drm/msm: add SDE IRQ domain before creating DRM objects

Currently all connectors list SDE as their parent interrupt
controller.

With commit <f5dd86c92d63df7a2790149d1cb9588c004695b0>
(<drm/msm/sde: reorganize top level interrupt handling code>),
the SDE IRQ domains get added after DRM init functions of the
connectors. This is incorrect as the irq request calls of the
connectors shall fail if the domain of the parent is not added yet.
Fix this by re-ordering the sde_kms_int() function to reflect the
correct order and remove the IRQ domain addition from irq_preinstall
calls as that will be very late for the connectors.

Change-Id: Ie1364840e2f018361e54470516d48c3facf59272
Signed-off-by: Abhinav Kumar <abhinavk@codeaurora.org>
This commit is contained in:
Abhinav Kumar 2017-01-30 23:07:08 -08:00
parent 83fc94fbb9
commit 9a0a010c8e
4 changed files with 125 additions and 90 deletions

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2017, The Linux Foundation. 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 version 2 and
@ -432,6 +432,99 @@ void sde_core_irq_uninstall(struct sde_kms *sde_kms)
sde_kms->irq_obj.total_irqs = 0;
}
static void sde_hw_irq_mask(struct irq_data *irqd)
{
struct sde_kms *sde_kms;
if (!irqd || !irq_data_get_irq_chip_data(irqd)) {
SDE_ERROR("invalid parameters irqd %d\n", irqd != 0);
return;
}
sde_kms = irq_data_get_irq_chip_data(irqd);
smp_mb__before_atomic();
clear_bit(irqd->hwirq, &sde_kms->irq_controller.enabled_mask);
smp_mb__after_atomic();
}
static void sde_hw_irq_unmask(struct irq_data *irqd)
{
struct sde_kms *sde_kms;
if (!irqd || !irq_data_get_irq_chip_data(irqd)) {
SDE_ERROR("invalid parameters irqd %d\n", irqd != 0);
return;
}
sde_kms = irq_data_get_irq_chip_data(irqd);
smp_mb__before_atomic();
set_bit(irqd->hwirq, &sde_kms->irq_controller.enabled_mask);
smp_mb__after_atomic();
}
static struct irq_chip sde_hw_irq_chip = {
.name = "sde",
.irq_mask = sde_hw_irq_mask,
.irq_unmask = sde_hw_irq_unmask,
};
static int sde_hw_irqdomain_map(struct irq_domain *domain,
unsigned int irq, irq_hw_number_t hwirq)
{
struct sde_kms *sde_kms;
int rc;
if (!domain || !domain->host_data) {
SDE_ERROR("invalid parameters domain %d\n", domain != 0);
return -EINVAL;
}
sde_kms = domain->host_data;
irq_set_chip_and_handler(irq, &sde_hw_irq_chip, handle_level_irq);
rc = irq_set_chip_data(irq, sde_kms);
return rc;
}
static struct irq_domain_ops sde_hw_irqdomain_ops = {
.map = sde_hw_irqdomain_map,
.xlate = irq_domain_xlate_onecell,
};
int sde_core_irq_domain_add(struct sde_kms *sde_kms)
{
struct device *dev;
struct irq_domain *domain;
if (!sde_kms->dev || !sde_kms->dev->dev) {
pr_err("invalid device handles\n");
return -EINVAL;
}
dev = sde_kms->dev->dev;
domain = irq_domain_add_linear(dev->of_node, 32,
&sde_hw_irqdomain_ops, sde_kms);
if (!domain) {
pr_err("failed to add irq_domain\n");
return -EINVAL;
}
sde_kms->irq_controller.enabled_mask = 0;
sde_kms->irq_controller.domain = domain;
return 0;
}
int sde_core_irq_domain_fini(struct sde_kms *sde_kms)
{
if (sde_kms->irq_controller.domain) {
irq_domain_remove(sde_kms->irq_controller.domain);
sde_kms->irq_controller.domain = NULL;
}
return 0;
}
irqreturn_t sde_core_irq(struct sde_kms *sde_kms)
{
/*

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2017, The Linux Foundation. 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 version 2 and
@ -37,6 +37,20 @@ int sde_core_irq_postinstall(struct sde_kms *sde_kms);
*/
void sde_core_irq_uninstall(struct sde_kms *sde_kms);
/**
* sde_core_irq_domain_add - Add core IRQ domain for SDE
* @sde_kms: SDE handle
* @return: none
*/
int sde_core_irq_domain_add(struct sde_kms *sde_kms);
/**
* sde_core_irq_domain_fini - uninstall core IRQ domain
* @sde_kms: SDE handle
* @return: 0 if success; error code otherwise
*/
int sde_core_irq_domain_fini(struct sde_kms *sde_kms);
/**
* sde_core_irq - core IRQ handler
* @sde_kms: SDE handle

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2017, The Linux Foundation. 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 version 2 and
@ -49,86 +49,14 @@ irqreturn_t sde_irq(struct msm_kms *kms)
return IRQ_HANDLED;
}
static void sde_hw_irq_mask(struct irq_data *irqd)
{
struct sde_kms *sde_kms;
if (!irqd || !irq_data_get_irq_chip_data(irqd)) {
SDE_ERROR("invalid parameters irqd %d\n", irqd != 0);
return;
}
sde_kms = irq_data_get_irq_chip_data(irqd);
smp_mb__before_atomic();
clear_bit(irqd->hwirq, &sde_kms->irq_controller.enabled_mask);
smp_mb__after_atomic();
}
static void sde_hw_irq_unmask(struct irq_data *irqd)
{
struct sde_kms *sde_kms;
if (!irqd || !irq_data_get_irq_chip_data(irqd)) {
SDE_ERROR("invalid parameters irqd %d\n", irqd != 0);
return;
}
sde_kms = irq_data_get_irq_chip_data(irqd);
smp_mb__before_atomic();
set_bit(irqd->hwirq, &sde_kms->irq_controller.enabled_mask);
smp_mb__after_atomic();
}
static struct irq_chip sde_hw_irq_chip = {
.name = "sde",
.irq_mask = sde_hw_irq_mask,
.irq_unmask = sde_hw_irq_unmask,
};
static int sde_hw_irqdomain_map(struct irq_domain *domain,
unsigned int irq, irq_hw_number_t hwirq)
{
struct sde_kms *sde_kms;
int rc;
if (!domain || !domain->host_data) {
SDE_ERROR("invalid parameters domain %d\n", domain != 0);
return -EINVAL;
}
sde_kms = domain->host_data;
irq_set_chip_and_handler(irq, &sde_hw_irq_chip, handle_level_irq);
rc = irq_set_chip_data(irq, sde_kms);
return rc;
}
static struct irq_domain_ops sde_hw_irqdomain_ops = {
.map = sde_hw_irqdomain_map,
.xlate = irq_domain_xlate_onecell,
};
void sde_irq_preinstall(struct msm_kms *kms)
{
struct sde_kms *sde_kms = to_sde_kms(kms);
struct device *dev;
struct irq_domain *domain;
if (!sde_kms->dev || !sde_kms->dev->dev) {
pr_err("invalid device handles\n");
return;
}
dev = sde_kms->dev->dev;
domain = irq_domain_add_linear(dev->of_node, 32,
&sde_hw_irqdomain_ops, sde_kms);
if (!domain) {
pr_err("failed to add irq_domain\n");
return;
}
sde_kms->irq_controller.enabled_mask = 0;
sde_kms->irq_controller.domain = domain;
sde_core_irq_preinstall(sde_kms);
}
@ -158,9 +86,5 @@ void sde_irq_uninstall(struct msm_kms *kms)
}
sde_core_irq_uninstall(sde_kms);
if (sde_kms->irq_controller.domain) {
irq_domain_remove(sde_kms->irq_controller.domain);
sde_kms->irq_controller.domain = NULL;
}
sde_core_irq_domain_fini(sde_kms);
}

View file

@ -811,6 +811,9 @@ static int _sde_kms_drm_obj_init(struct sde_kms *sde_kms)
priv = dev->dev_private;
catalog = sde_kms->catalog;
ret = sde_core_irq_domain_add(sde_kms);
if (ret)
goto fail_irq;
/*
* Query for underlying display drivers, and create connectors,
* bridges and encoders for them.
@ -869,6 +872,8 @@ static int _sde_kms_drm_obj_init(struct sde_kms *sde_kms)
return 0;
fail:
_sde_kms_drm_obj_destroy(sde_kms);
fail_irq:
sde_core_irq_domain_fini(sde_kms);
return ret;
}
@ -1219,6 +1224,14 @@ static int sde_kms_hw_init(struct msm_kms *kms)
goto perf_err;
}
sde_kms->hw_intr = sde_hw_intr_init(sde_kms->mmio, sde_kms->catalog);
if (IS_ERR_OR_NULL(sde_kms->hw_intr)) {
rc = PTR_ERR(sde_kms->hw_intr);
SDE_ERROR("hw_intr init failed: %d\n", rc);
sde_kms->hw_intr = NULL;
goto hw_intr_init_err;
}
/*
* _sde_kms_drm_obj_init should create the DRM related objects
* i.e. CRTCs, planes, encoders, connectors and so forth
@ -1244,21 +1257,12 @@ static int sde_kms_hw_init(struct msm_kms *kms)
*/
dev->mode_config.allow_fb_modifiers = true;
sde_kms->hw_intr = sde_hw_intr_init(sde_kms->mmio, sde_kms->catalog);
if (IS_ERR_OR_NULL(sde_kms->hw_intr)) {
rc = PTR_ERR(sde_kms->hw_intr);
SDE_ERROR("hw_intr init failed: %d\n", rc);
sde_kms->hw_intr = NULL;
goto hw_intr_init_err;
}
sde_power_resource_enable(&priv->phandle, sde_kms->core_client, false);
return 0;
hw_intr_init_err:
_sde_kms_drm_obj_destroy(sde_kms);
drm_obj_init_err:
sde_core_perf_destroy(&sde_kms->perf);
hw_intr_init_err:
perf_err:
power_error:
sde_power_resource_enable(&priv->phandle, sde_kms->core_client, false);