irq_service_dce110.c revision 1.1
1198090Srdivacky/*
2198090Srdivacky * Copyright 2012-15 Advanced Micro Devices, Inc.
3198090Srdivacky *
4198090Srdivacky * Permission is hereby granted, free of charge, to any person obtaining a
5198090Srdivacky * copy of this software and associated documentation files (the "Software"),
6198090Srdivacky * to deal in the Software without restriction, including without limitation
7198090Srdivacky * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8198090Srdivacky * and/or sell copies of the Software, and to permit persons to whom the
9198090Srdivacky * Software is furnished to do so, subject to the following conditions:
10198090Srdivacky *
11198090Srdivacky * The above copyright notice and this permission notice shall be included in
12198090Srdivacky * all copies or substantial portions of the Software.
13198090Srdivacky *
14198090Srdivacky * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15198090Srdivacky * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16198090Srdivacky * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17288943Sdim * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18234353Sdim * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19249423Sdim * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20234353Sdim * OTHER DEALINGS IN THE SOFTWARE.
21198090Srdivacky *
22198090Srdivacky * Authors: AMD
23234353Sdim *
24234353Sdim */
25208599Srdivacky
26208599Srdivacky#include "dm_services.h"
27234353Sdim
28234353Sdim#include "include/logger_interface.h"
29234353Sdim
30234353Sdim#include "irq_service_dce110.h"
31198396Srdivacky
32261991Sdim#include "dce/dce_11_0_d.h"
33261991Sdim#include "dce/dce_11_0_sh_mask.h"
34261991Sdim
35261991Sdim#include "ivsrcid/ivsrcid_vislands30.h"
36198090Srdivacky
37198090Srdivacky#include "dc.h"
38198090Srdivacky#include "core_types.h"
39208599Srdivacky#define DC_LOGGER \
40207618Srdivacky	irq_service->ctx->logger
41207618Srdivacky
42261991Sdimstatic bool hpd_ack(struct irq_service *irq_service,
43261991Sdim		    const struct irq_source_info *info)
44207618Srdivacky{
45198090Srdivacky	uint32_t addr = info->status_reg;
46198396Srdivacky	uint32_t value = dm_read_reg(irq_service->ctx, addr);
47212904Sdim	uint32_t current_status = get_reg_field_value(value,
48226633Sdim						      DC_HPD_INT_STATUS,
49198396Srdivacky						      DC_HPD_SENSE_DELAYED);
50261991Sdim
51212904Sdim	dal_irq_service_ack_generic(irq_service, info);
52212904Sdim
53261991Sdim	value = dm_read_reg(irq_service->ctx, info->enable_reg);
54261991Sdim
55198090Srdivacky	set_reg_field_value(value, current_status ? 0 : 1,
56208599Srdivacky			    DC_HPD_INT_CONTROL,
57198090Srdivacky			    DC_HPD_INT_POLARITY);
58261991Sdim
59198090Srdivacky	dm_write_reg(irq_service->ctx, info->enable_reg, value);
60276479Sdim
61198090Srdivacky	return true;
62198396Srdivacky}
63261991Sdim
64261991Sdimstatic const struct irq_source_info_funcs hpd_irq_info_funcs = {
65261991Sdim	.set = NULL,
66261991Sdim	.ack = hpd_ack
67226633Sdim};
68198396Srdivacky
69261991Sdimstatic const struct irq_source_info_funcs hpd_rx_irq_info_funcs = {
70261991Sdim	.set = NULL,
71198090Srdivacky	.ack = NULL
72198090Srdivacky};
73261991Sdim
74261991Sdimstatic const struct irq_source_info_funcs pflip_irq_info_funcs = {
75198090Srdivacky	.set = NULL,
76198396Srdivacky	.ack = NULL
77261991Sdim};
78261991Sdim
79198090Srdivackystatic const struct irq_source_info_funcs vblank_irq_info_funcs = {
80198396Srdivacky	.set = dce110_vblank_set,
81261991Sdim	.ack = NULL
82261991Sdim};
83198090Srdivacky
84261991Sdim#define hpd_int_entry(reg_num)\
85261991Sdim	[DC_IRQ_SOURCE_HPD1 + reg_num] = {\
86261991Sdim		.enable_reg = mmHPD ## reg_num ## _DC_HPD_INT_CONTROL,\
87198090Srdivacky		.enable_mask = DC_HPD_INT_CONTROL__DC_HPD_INT_EN_MASK,\
88261991Sdim		.enable_value = {\
89198090Srdivacky			DC_HPD_INT_CONTROL__DC_HPD_INT_EN_MASK,\
90198090Srdivacky			~DC_HPD_INT_CONTROL__DC_HPD_INT_EN_MASK\
91198090Srdivacky		},\
92198090Srdivacky		.ack_reg = mmHPD ## reg_num ## _DC_HPD_INT_CONTROL,\
93198090Srdivacky		.ack_mask = DC_HPD_INT_CONTROL__DC_HPD_INT_ACK_MASK,\
94261991Sdim		.ack_value = DC_HPD_INT_CONTROL__DC_HPD_INT_ACK_MASK,\
95198090Srdivacky		.status_reg = mmHPD ## reg_num ## _DC_HPD_INT_STATUS,\
96198090Srdivacky		.funcs = &hpd_irq_info_funcs\
97198090Srdivacky	}
98198090Srdivacky
99198090Srdivacky#define hpd_rx_int_entry(reg_num)\
100198090Srdivacky	[DC_IRQ_SOURCE_HPD1RX + reg_num] = {\
101198090Srdivacky		.enable_reg = mmHPD ## reg_num ## _DC_HPD_INT_CONTROL,\
102198396Srdivacky		.enable_mask = DC_HPD_INT_CONTROL__DC_HPD_RX_INT_EN_MASK,\
103261991Sdim		.enable_value = {\
104261991Sdim			DC_HPD_INT_CONTROL__DC_HPD_RX_INT_EN_MASK,\
105261991Sdim			~DC_HPD_INT_CONTROL__DC_HPD_RX_INT_EN_MASK },\
106261991Sdim		.ack_reg = mmHPD ## reg_num ## _DC_HPD_INT_CONTROL,\
107261991Sdim		.ack_mask = DC_HPD_INT_CONTROL__DC_HPD_RX_INT_ACK_MASK,\
108261991Sdim		.ack_value = DC_HPD_INT_CONTROL__DC_HPD_RX_INT_ACK_MASK,\
109261991Sdim		.status_reg = mmHPD ## reg_num ## _DC_HPD_INT_STATUS,\
110198090Srdivacky		.funcs = &hpd_rx_irq_info_funcs\
111198396Srdivacky	}
112261991Sdim#define pflip_int_entry(reg_num)\
113261991Sdim	[DC_IRQ_SOURCE_PFLIP1 + reg_num] = {\
114261991Sdim		.enable_reg = mmDCP ## reg_num ## _GRPH_INTERRUPT_CONTROL,\
115261991Sdim		.enable_mask =\
116212904Sdim		GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK,\
117212904Sdim		.enable_value = {\
118212904Sdim			GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK,\
119198090Srdivacky			~GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK},\
120198090Srdivacky		.ack_reg = mmDCP ## reg_num ## _GRPH_INTERRUPT_STATUS,\
121207618Srdivacky		.ack_mask = GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_CLEAR_MASK,\
122288943Sdim		.ack_value = GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_CLEAR_MASK,\
123288943Sdim		.status_reg = mmDCP ## reg_num ##_GRPH_INTERRUPT_STATUS,\
124198090Srdivacky		.funcs = &pflip_irq_info_funcs\
125261991Sdim	}
126261991Sdim
127261991Sdim#define vupdate_int_entry(reg_num)\
128261991Sdim	[DC_IRQ_SOURCE_VUPDATE1 + reg_num] = {\
129218893Sdim		.enable_reg = mmCRTC ## reg_num ## _CRTC_INTERRUPT_CONTROL,\
130218893Sdim		.enable_mask =\
131218893Sdim		CRTC_INTERRUPT_CONTROL__CRTC_V_UPDATE_INT_MSK_MASK,\
132218893Sdim		.enable_value = {\
133218893Sdim			CRTC_INTERRUPT_CONTROL__CRTC_V_UPDATE_INT_MSK_MASK,\
134218893Sdim			~CRTC_INTERRUPT_CONTROL__CRTC_V_UPDATE_INT_MSK_MASK},\
135218893Sdim		.ack_reg = mmCRTC ## reg_num ## _CRTC_V_UPDATE_INT_STATUS,\
136218893Sdim		.ack_mask =\
137276479Sdim		CRTC_V_UPDATE_INT_STATUS__CRTC_V_UPDATE_INT_CLEAR_MASK,\
138218893Sdim		.ack_value =\
139288943Sdim		CRTC_V_UPDATE_INT_STATUS__CRTC_V_UPDATE_INT_CLEAR_MASK,\
140224145Sdim		.funcs = &vblank_irq_info_funcs\
141218893Sdim	}
142276479Sdim
143261991Sdim#define vblank_int_entry(reg_num)\
144261991Sdim	[DC_IRQ_SOURCE_VBLANK1 + reg_num] = {\
145261991Sdim		.enable_reg = mmCRTC ## reg_num ## _CRTC_VERTICAL_INTERRUPT0_CONTROL,\
146261991Sdim		.enable_mask =\
147261991Sdim		CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_INT_ENABLE_MASK,\
148218893Sdim		.enable_value = {\
149276479Sdim			CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_INT_ENABLE_MASK,\
150261991Sdim			~CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_INT_ENABLE_MASK},\
151261991Sdim		.ack_reg = mmCRTC ## reg_num ## _CRTC_VERTICAL_INTERRUPT0_CONTROL,\
152261991Sdim		.ack_mask =\
153261991Sdim		CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_CLEAR_MASK,\
154218893Sdim		.ack_value =\
155234353Sdim		CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_CLEAR_MASK,\
156276479Sdim		.funcs = &vblank_irq_info_funcs,\
157261991Sdim		.src_id = VISLANDS30_IV_SRCID_D1_VERTICAL_INTERRUPT0 + reg_num\
158261991Sdim	}
159218893Sdim
160218893Sdim#define dummy_irq_entry() \
161276479Sdim	{\
162261991Sdim		.funcs = &dummy_irq_info_funcs\
163261991Sdim	}
164218893Sdim
165218893Sdim#define i2c_int_entry(reg_num) \
166198090Srdivacky	[DC_IRQ_SOURCE_I2C_DDC ## reg_num] = dummy_irq_entry()
167261991Sdim
168218893Sdim#define dp_sink_int_entry(reg_num) \
169218893Sdim	[DC_IRQ_SOURCE_DPSINK ## reg_num] = dummy_irq_entry()
170218893Sdim
171261991Sdim#define gpio_pad_int_entry(reg_num) \
172224145Sdim	[DC_IRQ_SOURCE_GPIOPAD ## reg_num] = dummy_irq_entry()
173224145Sdim
174218893Sdim#define dc_underflow_int_entry(reg_num) \
175218893Sdim	[DC_IRQ_SOURCE_DC ## reg_num ## UNDERFLOW] = dummy_irq_entry()
176198090Srdivacky
177198090Srdivackybool dal_irq_service_dummy_set(struct irq_service *irq_service,
178198090Srdivacky			       const struct irq_source_info *info,
179			       bool enable)
180{
181	DC_LOG_ERROR("%s: called for non-implemented irq source\n",
182		     __func__);
183	return false;
184}
185
186bool dal_irq_service_dummy_ack(struct irq_service *irq_service,
187			       const struct irq_source_info *info)
188{
189	DC_LOG_ERROR("%s: called for non-implemented irq source\n",
190		     __func__);
191	return false;
192}
193
194
195bool dce110_vblank_set(struct irq_service *irq_service,
196		       const struct irq_source_info *info,
197		       bool enable)
198{
199	struct dc_context *dc_ctx = irq_service->ctx;
200	struct dc *core_dc = irq_service->ctx->dc;
201	enum dc_irq_source dal_irq_src =
202			dc_interrupt_to_irq_source(irq_service->ctx->dc,
203						   info->src_id,
204						   info->ext_id);
205	uint8_t pipe_offset = dal_irq_src - IRQ_TYPE_VBLANK;
206
207	struct timing_generator *tg =
208			core_dc->current_state->res_ctx.pipe_ctx[pipe_offset].stream_res.tg;
209
210	if (enable) {
211		if (!tg || !tg->funcs->arm_vert_intr(tg, 2)) {
212			DC_ERROR("Failed to get VBLANK!\n");
213			return false;
214		}
215	}
216
217	dal_irq_service_set_generic(irq_service, info, enable);
218	return true;
219}
220
221static const struct irq_source_info_funcs dummy_irq_info_funcs = {
222	.set = dal_irq_service_dummy_set,
223	.ack = dal_irq_service_dummy_ack
224};
225
226static const struct irq_source_info
227irq_source_info_dce110[DAL_IRQ_SOURCES_NUMBER] = {
228	[DC_IRQ_SOURCE_INVALID] = dummy_irq_entry(),
229	hpd_int_entry(0),
230	hpd_int_entry(1),
231	hpd_int_entry(2),
232	hpd_int_entry(3),
233	hpd_int_entry(4),
234	hpd_int_entry(5),
235	hpd_rx_int_entry(0),
236	hpd_rx_int_entry(1),
237	hpd_rx_int_entry(2),
238	hpd_rx_int_entry(3),
239	hpd_rx_int_entry(4),
240	hpd_rx_int_entry(5),
241	i2c_int_entry(1),
242	i2c_int_entry(2),
243	i2c_int_entry(3),
244	i2c_int_entry(4),
245	i2c_int_entry(5),
246	i2c_int_entry(6),
247	dp_sink_int_entry(1),
248	dp_sink_int_entry(2),
249	dp_sink_int_entry(3),
250	dp_sink_int_entry(4),
251	dp_sink_int_entry(5),
252	dp_sink_int_entry(6),
253	[DC_IRQ_SOURCE_TIMER] = dummy_irq_entry(),
254	pflip_int_entry(0),
255	pflip_int_entry(1),
256	pflip_int_entry(2),
257	pflip_int_entry(3),
258	pflip_int_entry(4),
259	pflip_int_entry(5),
260	[DC_IRQ_SOURCE_PFLIP_UNDERLAY0] = dummy_irq_entry(),
261	gpio_pad_int_entry(0),
262	gpio_pad_int_entry(1),
263	gpio_pad_int_entry(2),
264	gpio_pad_int_entry(3),
265	gpio_pad_int_entry(4),
266	gpio_pad_int_entry(5),
267	gpio_pad_int_entry(6),
268	gpio_pad_int_entry(7),
269	gpio_pad_int_entry(8),
270	gpio_pad_int_entry(9),
271	gpio_pad_int_entry(10),
272	gpio_pad_int_entry(11),
273	gpio_pad_int_entry(12),
274	gpio_pad_int_entry(13),
275	gpio_pad_int_entry(14),
276	gpio_pad_int_entry(15),
277	gpio_pad_int_entry(16),
278	gpio_pad_int_entry(17),
279	gpio_pad_int_entry(18),
280	gpio_pad_int_entry(19),
281	gpio_pad_int_entry(20),
282	gpio_pad_int_entry(21),
283	gpio_pad_int_entry(22),
284	gpio_pad_int_entry(23),
285	gpio_pad_int_entry(24),
286	gpio_pad_int_entry(25),
287	gpio_pad_int_entry(26),
288	gpio_pad_int_entry(27),
289	gpio_pad_int_entry(28),
290	gpio_pad_int_entry(29),
291	gpio_pad_int_entry(30),
292	dc_underflow_int_entry(1),
293	dc_underflow_int_entry(2),
294	dc_underflow_int_entry(3),
295	dc_underflow_int_entry(4),
296	dc_underflow_int_entry(5),
297	dc_underflow_int_entry(6),
298	[DC_IRQ_SOURCE_DMCU_SCP] = dummy_irq_entry(),
299	[DC_IRQ_SOURCE_VBIOS_SW] = dummy_irq_entry(),
300	vupdate_int_entry(0),
301	vupdate_int_entry(1),
302	vupdate_int_entry(2),
303	vupdate_int_entry(3),
304	vupdate_int_entry(4),
305	vupdate_int_entry(5),
306	vblank_int_entry(0),
307	vblank_int_entry(1),
308	vblank_int_entry(2),
309	vblank_int_entry(3),
310	vblank_int_entry(4),
311	vblank_int_entry(5),
312
313};
314
315enum dc_irq_source to_dal_irq_source_dce110(
316		struct irq_service *irq_service,
317		uint32_t src_id,
318		uint32_t ext_id)
319{
320	switch (src_id) {
321	case VISLANDS30_IV_SRCID_D1_VERTICAL_INTERRUPT0:
322		return DC_IRQ_SOURCE_VBLANK1;
323	case VISLANDS30_IV_SRCID_D2_VERTICAL_INTERRUPT0:
324		return DC_IRQ_SOURCE_VBLANK2;
325	case VISLANDS30_IV_SRCID_D3_VERTICAL_INTERRUPT0:
326		return DC_IRQ_SOURCE_VBLANK3;
327	case VISLANDS30_IV_SRCID_D4_VERTICAL_INTERRUPT0:
328		return DC_IRQ_SOURCE_VBLANK4;
329	case VISLANDS30_IV_SRCID_D5_VERTICAL_INTERRUPT0:
330		return DC_IRQ_SOURCE_VBLANK5;
331	case VISLANDS30_IV_SRCID_D6_VERTICAL_INTERRUPT0:
332		return DC_IRQ_SOURCE_VBLANK6;
333	case VISLANDS30_IV_SRCID_D1_V_UPDATE_INT:
334		return DC_IRQ_SOURCE_VUPDATE1;
335	case VISLANDS30_IV_SRCID_D2_V_UPDATE_INT:
336		return DC_IRQ_SOURCE_VUPDATE2;
337	case VISLANDS30_IV_SRCID_D3_V_UPDATE_INT:
338		return DC_IRQ_SOURCE_VUPDATE3;
339	case VISLANDS30_IV_SRCID_D4_V_UPDATE_INT:
340		return DC_IRQ_SOURCE_VUPDATE4;
341	case VISLANDS30_IV_SRCID_D5_V_UPDATE_INT:
342		return DC_IRQ_SOURCE_VUPDATE5;
343	case VISLANDS30_IV_SRCID_D6_V_UPDATE_INT:
344		return DC_IRQ_SOURCE_VUPDATE6;
345	case VISLANDS30_IV_SRCID_D1_GRPH_PFLIP:
346		return DC_IRQ_SOURCE_PFLIP1;
347	case VISLANDS30_IV_SRCID_D2_GRPH_PFLIP:
348		return DC_IRQ_SOURCE_PFLIP2;
349	case VISLANDS30_IV_SRCID_D3_GRPH_PFLIP:
350		return DC_IRQ_SOURCE_PFLIP3;
351	case VISLANDS30_IV_SRCID_D4_GRPH_PFLIP:
352		return DC_IRQ_SOURCE_PFLIP4;
353	case VISLANDS30_IV_SRCID_D5_GRPH_PFLIP:
354		return DC_IRQ_SOURCE_PFLIP5;
355	case VISLANDS30_IV_SRCID_D6_GRPH_PFLIP:
356		return DC_IRQ_SOURCE_PFLIP6;
357
358	case VISLANDS30_IV_SRCID_HOTPLUG_DETECT_A:
359		/* generic src_id for all HPD and HPDRX interrupts */
360		switch (ext_id) {
361		case VISLANDS30_IV_EXTID_HOTPLUG_DETECT_A:
362			return DC_IRQ_SOURCE_HPD1;
363		case VISLANDS30_IV_EXTID_HOTPLUG_DETECT_B:
364			return DC_IRQ_SOURCE_HPD2;
365		case VISLANDS30_IV_EXTID_HOTPLUG_DETECT_C:
366			return DC_IRQ_SOURCE_HPD3;
367		case VISLANDS30_IV_EXTID_HOTPLUG_DETECT_D:
368			return DC_IRQ_SOURCE_HPD4;
369		case VISLANDS30_IV_EXTID_HOTPLUG_DETECT_E:
370			return DC_IRQ_SOURCE_HPD5;
371		case VISLANDS30_IV_EXTID_HOTPLUG_DETECT_F:
372			return DC_IRQ_SOURCE_HPD6;
373		case VISLANDS30_IV_EXTID_HPD_RX_A:
374			return DC_IRQ_SOURCE_HPD1RX;
375		case VISLANDS30_IV_EXTID_HPD_RX_B:
376			return DC_IRQ_SOURCE_HPD2RX;
377		case VISLANDS30_IV_EXTID_HPD_RX_C:
378			return DC_IRQ_SOURCE_HPD3RX;
379		case VISLANDS30_IV_EXTID_HPD_RX_D:
380			return DC_IRQ_SOURCE_HPD4RX;
381		case VISLANDS30_IV_EXTID_HPD_RX_E:
382			return DC_IRQ_SOURCE_HPD5RX;
383		case VISLANDS30_IV_EXTID_HPD_RX_F:
384			return DC_IRQ_SOURCE_HPD6RX;
385		default:
386			return DC_IRQ_SOURCE_INVALID;
387		}
388		break;
389
390	default:
391		return DC_IRQ_SOURCE_INVALID;
392	}
393}
394
395static const struct irq_service_funcs irq_service_funcs_dce110 = {
396		.to_dal_irq_source = to_dal_irq_source_dce110
397};
398
399static void construct(struct irq_service *irq_service,
400		      struct irq_service_init_data *init_data)
401{
402	dal_irq_service_construct(irq_service, init_data);
403
404	irq_service->info = irq_source_info_dce110;
405	irq_service->funcs = &irq_service_funcs_dce110;
406}
407
408struct irq_service *
409dal_irq_service_dce110_create(struct irq_service_init_data *init_data)
410{
411	struct irq_service *irq_service = kzalloc(sizeof(*irq_service),
412						  GFP_KERNEL);
413
414	if (!irq_service)
415		return NULL;
416
417	construct(irq_service, init_data);
418	return irq_service;
419}
420