irq_service_dce80.c revision 1.2
1/*
2 * Copyright 2012-15 Advanced Micro Devices, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: AMD
23 *
24 */
25
26#include <linux/slab.h>
27
28#include "dm_services.h"
29
30#include "include/logger_interface.h"
31
32#include "irq_service_dce80.h"
33#include "../dce110/irq_service_dce110.h"
34
35#include "dce/dce_8_0_d.h"
36#include "dce/dce_8_0_sh_mask.h"
37
38#include "ivsrcid/ivsrcid_vislands30.h"
39
40#include "dc_types.h"
41
42static bool hpd_ack(
43	struct irq_service *irq_service,
44	const struct irq_source_info *info)
45{
46	uint32_t addr = info->status_reg;
47	uint32_t value = dm_read_reg(irq_service->ctx, addr);
48	uint32_t current_status =
49		get_reg_field_value(
50			value,
51			DC_HPD1_INT_STATUS,
52			DC_HPD1_SENSE_DELAYED);
53
54	dal_irq_service_ack_generic(irq_service, info);
55
56	value = dm_read_reg(irq_service->ctx, info->enable_reg);
57
58	set_reg_field_value(
59		value,
60		current_status ? 0 : 1,
61		DC_HPD1_INT_CONTROL,
62		DC_HPD1_INT_POLARITY);
63
64	dm_write_reg(irq_service->ctx, info->enable_reg, value);
65
66	return true;
67}
68
69static const struct irq_source_info_funcs hpd_irq_info_funcs = {
70	.set = NULL,
71	.ack = hpd_ack
72};
73
74static const struct irq_source_info_funcs hpd_rx_irq_info_funcs = {
75	.set = NULL,
76	.ack = NULL
77};
78
79static const struct irq_source_info_funcs pflip_irq_info_funcs = {
80	.set = NULL,
81	.ack = NULL
82};
83
84static const struct irq_source_info_funcs vblank_irq_info_funcs = {
85	.set = dce110_vblank_set,
86	.ack = NULL
87};
88
89static const struct irq_source_info_funcs vupdate_irq_info_funcs = {
90	.set = NULL,
91	.ack = NULL
92};
93
94#define hpd_int_entry(reg_num)\
95	[DC_IRQ_SOURCE_INVALID + reg_num] = {\
96		.enable_reg = mmDC_HPD ## reg_num ## _INT_CONTROL,\
97		.enable_mask = DC_HPD1_INT_CONTROL__DC_HPD1_INT_EN_MASK,\
98		.enable_value = {\
99			DC_HPD1_INT_CONTROL__DC_HPD1_INT_EN_MASK,\
100			~DC_HPD1_INT_CONTROL__DC_HPD1_INT_EN_MASK\
101		},\
102		.ack_reg = mmDC_HPD ## reg_num ## _INT_CONTROL,\
103		.ack_mask = DC_HPD1_INT_CONTROL__DC_HPD1_INT_ACK_MASK,\
104		.ack_value = DC_HPD1_INT_CONTROL__DC_HPD1_INT_ACK_MASK,\
105		.status_reg = mmDC_HPD ## reg_num ## _INT_STATUS,\
106		.funcs = &hpd_irq_info_funcs\
107	}
108
109#define hpd_rx_int_entry(reg_num)\
110	[DC_IRQ_SOURCE_HPD6 + reg_num] = {\
111		.enable_reg = mmDC_HPD ## reg_num ## _INT_CONTROL,\
112		.enable_mask = DC_HPD1_INT_CONTROL__DC_HPD1_RX_INT_EN_MASK,\
113		.enable_value = {\
114				DC_HPD1_INT_CONTROL__DC_HPD1_RX_INT_EN_MASK,\
115			~DC_HPD1_INT_CONTROL__DC_HPD1_RX_INT_EN_MASK },\
116		.ack_reg = mmDC_HPD ## reg_num ## _INT_CONTROL,\
117		.ack_mask = DC_HPD1_INT_CONTROL__DC_HPD1_RX_INT_ACK_MASK,\
118		.ack_value = DC_HPD1_INT_CONTROL__DC_HPD1_RX_INT_ACK_MASK,\
119		.status_reg = mmDC_HPD ## reg_num ## _INT_STATUS,\
120		.funcs = &hpd_rx_irq_info_funcs\
121	}
122
123#define pflip_int_entry(reg_num)\
124	[DC_IRQ_SOURCE_PFLIP1 + reg_num] = {\
125		.enable_reg = mmDCP ## reg_num ## _GRPH_INTERRUPT_CONTROL,\
126		.enable_mask =\
127		GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK,\
128		.enable_value = {\
129			GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK,\
130			~GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK},\
131		.ack_reg = mmDCP ## reg_num ## _GRPH_INTERRUPT_STATUS,\
132		.ack_mask = GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_CLEAR_MASK,\
133		.ack_value = GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_CLEAR_MASK,\
134		.status_reg = mmDCP ## reg_num ##_GRPH_INTERRUPT_STATUS,\
135		.funcs = &pflip_irq_info_funcs\
136 	}
137
138#define vupdate_int_entry(reg_num)\
139	[DC_IRQ_SOURCE_VUPDATE1 + reg_num] = {\
140		.enable_reg = mmCRTC ## reg_num ## _CRTC_INTERRUPT_CONTROL,\
141		.enable_mask =\
142		CRTC_INTERRUPT_CONTROL__CRTC_V_UPDATE_INT_MSK_MASK,\
143		.enable_value = {\
144			CRTC_INTERRUPT_CONTROL__CRTC_V_UPDATE_INT_MSK_MASK,\
145			~CRTC_INTERRUPT_CONTROL__CRTC_V_UPDATE_INT_MSK_MASK},\
146		.ack_reg = mmCRTC ## reg_num ## _CRTC_V_UPDATE_INT_STATUS,\
147		.ack_mask =\
148		CRTC_V_UPDATE_INT_STATUS__CRTC_V_UPDATE_INT_CLEAR_MASK,\
149		.ack_value =\
150		CRTC_V_UPDATE_INT_STATUS__CRTC_V_UPDATE_INT_CLEAR_MASK,\
151		.funcs = &vupdate_irq_info_funcs\
152	}
153
154#define vblank_int_entry(reg_num)\
155	[DC_IRQ_SOURCE_VBLANK1 + reg_num] = {\
156		.enable_reg = mmCRTC ## reg_num ## _CRTC_VERTICAL_INTERRUPT0_CONTROL,\
157		.enable_mask =\
158		CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_INT_ENABLE_MASK,\
159		.enable_value = {\
160			CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_INT_ENABLE_MASK,\
161			~CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_INT_ENABLE_MASK},\
162		.ack_reg = mmCRTC ## reg_num ## _CRTC_VERTICAL_INTERRUPT0_CONTROL,\
163		.ack_mask =\
164		CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_CLEAR_MASK,\
165		.ack_value =\
166		CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_CLEAR_MASK,\
167		.funcs = &vblank_irq_info_funcs,\
168		.src_id = VISLANDS30_IV_SRCID_D1_VERTICAL_INTERRUPT0 + reg_num\
169	}
170
171#define dummy_irq_entry() \
172	{\
173		.funcs = &dummy_irq_info_funcs\
174	}
175
176#define i2c_int_entry(reg_num) \
177	[DC_IRQ_SOURCE_I2C_DDC ## reg_num] = dummy_irq_entry()
178
179#define dp_sink_int_entry(reg_num) \
180	[DC_IRQ_SOURCE_DPSINK ## reg_num] = dummy_irq_entry()
181
182#define gpio_pad_int_entry(reg_num) \
183	[DC_IRQ_SOURCE_GPIOPAD ## reg_num] = dummy_irq_entry()
184
185#define dc_underflow_int_entry(reg_num) \
186	[DC_IRQ_SOURCE_DC ## reg_num ## UNDERFLOW] = dummy_irq_entry()
187
188
189static const struct irq_source_info_funcs dummy_irq_info_funcs = {
190	.set = dal_irq_service_dummy_set,
191	.ack = dal_irq_service_dummy_ack
192};
193
194static const struct irq_source_info
195irq_source_info_dce80[DAL_IRQ_SOURCES_NUMBER] = {
196	[DC_IRQ_SOURCE_INVALID] = dummy_irq_entry(),
197	hpd_int_entry(1),
198	hpd_int_entry(2),
199	hpd_int_entry(3),
200	hpd_int_entry(4),
201	hpd_int_entry(5),
202	hpd_int_entry(6),
203	hpd_rx_int_entry(1),
204	hpd_rx_int_entry(2),
205	hpd_rx_int_entry(3),
206	hpd_rx_int_entry(4),
207	hpd_rx_int_entry(5),
208	hpd_rx_int_entry(6),
209	i2c_int_entry(1),
210	i2c_int_entry(2),
211	i2c_int_entry(3),
212	i2c_int_entry(4),
213	i2c_int_entry(5),
214	i2c_int_entry(6),
215	dp_sink_int_entry(1),
216	dp_sink_int_entry(2),
217	dp_sink_int_entry(3),
218	dp_sink_int_entry(4),
219	dp_sink_int_entry(5),
220	dp_sink_int_entry(6),
221	[DC_IRQ_SOURCE_TIMER] = dummy_irq_entry(),
222	pflip_int_entry(0),
223	pflip_int_entry(1),
224	pflip_int_entry(2),
225	pflip_int_entry(3),
226	pflip_int_entry(4),
227	pflip_int_entry(5),
228	[DC_IRQ_SOURCE_PFLIP_UNDERLAY0] = dummy_irq_entry(),
229	gpio_pad_int_entry(0),
230	gpio_pad_int_entry(1),
231	gpio_pad_int_entry(2),
232	gpio_pad_int_entry(3),
233	gpio_pad_int_entry(4),
234	gpio_pad_int_entry(5),
235	gpio_pad_int_entry(6),
236	gpio_pad_int_entry(7),
237	gpio_pad_int_entry(8),
238	gpio_pad_int_entry(9),
239	gpio_pad_int_entry(10),
240	gpio_pad_int_entry(11),
241	gpio_pad_int_entry(12),
242	gpio_pad_int_entry(13),
243	gpio_pad_int_entry(14),
244	gpio_pad_int_entry(15),
245	gpio_pad_int_entry(16),
246	gpio_pad_int_entry(17),
247	gpio_pad_int_entry(18),
248	gpio_pad_int_entry(19),
249	gpio_pad_int_entry(20),
250	gpio_pad_int_entry(21),
251	gpio_pad_int_entry(22),
252	gpio_pad_int_entry(23),
253	gpio_pad_int_entry(24),
254	gpio_pad_int_entry(25),
255	gpio_pad_int_entry(26),
256	gpio_pad_int_entry(27),
257	gpio_pad_int_entry(28),
258	gpio_pad_int_entry(29),
259	gpio_pad_int_entry(30),
260	dc_underflow_int_entry(1),
261	dc_underflow_int_entry(2),
262	dc_underflow_int_entry(3),
263	dc_underflow_int_entry(4),
264	dc_underflow_int_entry(5),
265	dc_underflow_int_entry(6),
266	[DC_IRQ_SOURCE_DMCU_SCP] = dummy_irq_entry(),
267	[DC_IRQ_SOURCE_VBIOS_SW] = dummy_irq_entry(),
268	vupdate_int_entry(0),
269	vupdate_int_entry(1),
270	vupdate_int_entry(2),
271	vupdate_int_entry(3),
272	vupdate_int_entry(4),
273	vupdate_int_entry(5),
274	vblank_int_entry(0),
275	vblank_int_entry(1),
276	vblank_int_entry(2),
277	vblank_int_entry(3),
278	vblank_int_entry(4),
279	vblank_int_entry(5),
280};
281
282static const struct irq_service_funcs irq_service_funcs_dce80 = {
283		.to_dal_irq_source = to_dal_irq_source_dce110
284};
285
286static void dce80_irq_construct(
287	struct irq_service *irq_service,
288	struct irq_service_init_data *init_data)
289{
290	dal_irq_service_construct(irq_service, init_data);
291
292	irq_service->info = irq_source_info_dce80;
293	irq_service->funcs = &irq_service_funcs_dce80;
294}
295
296struct irq_service *dal_irq_service_dce80_create(
297	struct irq_service_init_data *init_data)
298{
299	struct irq_service *irq_service = kzalloc(sizeof(*irq_service),
300						  GFP_KERNEL);
301
302	if (!irq_service)
303		return NULL;
304
305	dce80_irq_construct(irq_service, init_data);
306	return irq_service;
307}
308
309
310