blob: e3b658a4941fba68f093b4fb88cd85d81f87db51 [file] [log] [blame]
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07001/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
Alan Kwongf5dd86c2016-08-09 18:08:17 -040013#define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__
14
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070015#include <linux/irqdomain.h>
16#include <linux/irq.h>
Ben Chan78647cd2016-06-26 22:02:47 -040017#include <linux/kthread.h>
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070018
Alan Kwongf5dd86c2016-08-09 18:08:17 -040019#include "sde_irq.h"
20#include "sde_core_irq.h"
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070021
22irqreturn_t sde_irq(struct msm_kms *kms)
23{
Ben Chan78647cd2016-06-26 22:02:47 -040024 struct sde_kms *sde_kms = to_sde_kms(kms);
25 u32 interrupts;
26
27 sde_kms->hw_intr->ops.get_interrupt_sources(sde_kms->hw_intr,
28 &interrupts);
29
30 /*
31 * Taking care of MDP interrupt
32 */
33 if (interrupts & IRQ_SOURCE_MDP) {
34 interrupts &= ~IRQ_SOURCE_MDP;
Alan Kwongf5dd86c2016-08-09 18:08:17 -040035 sde_core_irq(sde_kms);
Ben Chan78647cd2016-06-26 22:02:47 -040036 }
37
38 /*
39 * Routing all other interrupts to external drivers
40 */
41 while (interrupts) {
42 irq_hw_number_t hwirq = fls(interrupts) - 1;
43
44 generic_handle_irq(irq_find_mapping(
Alan Kwongf5dd86c2016-08-09 18:08:17 -040045 sde_kms->irq_controller.domain, hwirq));
Ben Chan78647cd2016-06-26 22:02:47 -040046 interrupts &= ~(1 << hwirq);
47 }
48
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070049 return IRQ_HANDLED;
50}
51
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070052static void sde_hw_irq_mask(struct irq_data *irqd)
53{
Alan Kwongf5dd86c2016-08-09 18:08:17 -040054 struct sde_kms *sde_kms;
55
56 if (!irqd || !irq_data_get_irq_chip_data(irqd)) {
57 SDE_ERROR("invalid parameters irqd %d\n", irqd != 0);
58 return;
59 }
60 sde_kms = irq_data_get_irq_chip_data(irqd);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070061
62 /* memory barrier */
63 smp_mb__before_atomic();
Alan Kwongf5dd86c2016-08-09 18:08:17 -040064 clear_bit(irqd->hwirq, &sde_kms->irq_controller.enabled_mask);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070065 /* memory barrier */
66 smp_mb__after_atomic();
67}
68
69static void sde_hw_irq_unmask(struct irq_data *irqd)
70{
Alan Kwongf5dd86c2016-08-09 18:08:17 -040071 struct sde_kms *sde_kms;
72
73 if (!irqd || !irq_data_get_irq_chip_data(irqd)) {
74 SDE_ERROR("invalid parameters irqd %d\n", irqd != 0);
75 return;
76 }
77 sde_kms = irq_data_get_irq_chip_data(irqd);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070078
79 /* memory barrier */
80 smp_mb__before_atomic();
Alan Kwongf5dd86c2016-08-09 18:08:17 -040081 set_bit(irqd->hwirq, &sde_kms->irq_controller.enabled_mask);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070082 /* memory barrier */
83 smp_mb__after_atomic();
84}
85
86static struct irq_chip sde_hw_irq_chip = {
87 .name = "sde",
88 .irq_mask = sde_hw_irq_mask,
89 .irq_unmask = sde_hw_irq_unmask,
90};
91
Alan Kwongf5dd86c2016-08-09 18:08:17 -040092static int sde_hw_irqdomain_map(struct irq_domain *domain,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070093 unsigned int irq, irq_hw_number_t hwirq)
94{
Alan Kwongf5dd86c2016-08-09 18:08:17 -040095 struct sde_kms *sde_kms;
96 int rc;
Ben Chan78647cd2016-06-26 22:02:47 -040097
Alan Kwongf5dd86c2016-08-09 18:08:17 -040098 if (!domain || !domain->host_data) {
99 SDE_ERROR("invalid parameters domain %d\n", domain != 0);
100 return -EINVAL;
101 }
102 sde_kms = domain->host_data;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700103
104 irq_set_chip_and_handler(irq, &sde_hw_irq_chip, handle_level_irq);
Alan Kwongf5dd86c2016-08-09 18:08:17 -0400105 rc = irq_set_chip_data(irq, sde_kms);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700106
Alan Kwongf5dd86c2016-08-09 18:08:17 -0400107 return rc;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700108}
109
110static const struct irq_domain_ops sde_hw_irqdomain_ops = {
111 .map = sde_hw_irqdomain_map,
112 .xlate = irq_domain_xlate_onecell,
113};
114
Alan Kwongf5dd86c2016-08-09 18:08:17 -0400115void sde_irq_preinstall(struct msm_kms *kms)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700116{
Alan Kwongf5dd86c2016-08-09 18:08:17 -0400117 struct sde_kms *sde_kms = to_sde_kms(kms);
118 struct device *dev;
119 struct irq_domain *domain;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700120
Alan Kwongf5dd86c2016-08-09 18:08:17 -0400121 if (!sde_kms->dev || !sde_kms->dev->dev) {
122 pr_err("invalid device handles\n");
123 return;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700124 }
Alan Kwongf5dd86c2016-08-09 18:08:17 -0400125 dev = sde_kms->dev->dev;
126
127 domain = irq_domain_add_linear(dev->of_node, 32,
128 &sde_hw_irqdomain_ops, sde_kms);
129 if (!domain) {
130 pr_err("failed to add irq_domain\n");
131 return;
132 }
133
134 sde_kms->irq_controller.enabled_mask = 0;
135 sde_kms->irq_controller.domain = domain;
136
137 sde_core_irq_preinstall(sde_kms);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700138}
139
Alan Kwongf5dd86c2016-08-09 18:08:17 -0400140int sde_irq_postinstall(struct msm_kms *kms)
141{
142 struct sde_kms *sde_kms = to_sde_kms(kms);
143 int rc;
144
145 if (!kms) {
146 SDE_ERROR("invalid parameters\n");
147 return -EINVAL;
148 }
149
150 rc = sde_core_irq_postinstall(sde_kms);
151
152 return rc;
153}
154
155void sde_irq_uninstall(struct msm_kms *kms)
156{
157 struct sde_kms *sde_kms = to_sde_kms(kms);
158
159 if (!kms) {
160 SDE_ERROR("invalid parameters\n");
161 return;
162 }
163
164 sde_core_irq_uninstall(sde_kms);
165
166 if (sde_kms->irq_controller.domain) {
167 irq_domain_remove(sde_kms->irq_controller.domain);
168 sde_kms->irq_controller.domain = NULL;
169 }
170}