File Index
Files and directories
Sign in
FILE

irq_service_dcn36.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/amd/display/dc/irq/dcn36/irq_service_dcn36.c C
  1/* SPDX-License-Identifier: MIT */
  2/* Copyright 2025 Advanced Micro Devices, Inc. */
  3
  4#include "dm_services.h"
  5#include "include/logger_interface.h"
  6#include "../dce110/irq_service_dce110.h"
  7
  8#include "dcn/dcn_3_6_0_offset.h"
  9#include "dcn/dcn_3_6_0_sh_mask.h"
 10
 11#include "irq_service_dcn36.h"
 12
 13#include "ivsrcid/dcn/irqsrcs_dcn_1_0.h"
 14
 15static enum dc_irq_source to_dal_irq_source_dcn36(
 16		struct irq_service *irq_service,
 17		uint32_t src_id,
 18		uint32_t ext_id)
 19{
 20	switch (src_id) {
 21	case DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP:
 22		return DC_IRQ_SOURCE_VBLANK1;
 23	case DCN_1_0__SRCID__DC_D2_OTG_VSTARTUP:
 24		return DC_IRQ_SOURCE_VBLANK2;
 25	case DCN_1_0__SRCID__DC_D3_OTG_VSTARTUP:
 26		return DC_IRQ_SOURCE_VBLANK3;
 27	case DCN_1_0__SRCID__DC_D4_OTG_VSTARTUP:
 28		return DC_IRQ_SOURCE_VBLANK4;
 29	case DCN_1_0__SRCID__DC_D5_OTG_VSTARTUP:
 30		return DC_IRQ_SOURCE_VBLANK5;
 31	case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP:
 32		return DC_IRQ_SOURCE_VBLANK6;
 33	case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
 34		return DC_IRQ_SOURCE_DC1_VLINE0;
 35	case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
 36		return DC_IRQ_SOURCE_DC2_VLINE0;
 37	case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
 38		return DC_IRQ_SOURCE_DC3_VLINE0;
 39	case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
 40		return DC_IRQ_SOURCE_DC4_VLINE0;
 41	case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
 42		return DC_IRQ_SOURCE_DC5_VLINE0;
 43	case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
 44		return DC_IRQ_SOURCE_DC6_VLINE0;
 45	case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
 46		return DC_IRQ_SOURCE_PFLIP1;
 47	case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
 48		return DC_IRQ_SOURCE_PFLIP2;
 49	case DCN_1_0__SRCID__HUBP2_FLIP_INTERRUPT:
 50		return DC_IRQ_SOURCE_PFLIP3;
 51	case DCN_1_0__SRCID__HUBP3_FLIP_INTERRUPT:
 52		return DC_IRQ_SOURCE_PFLIP4;
 53	case DCN_1_0__SRCID__HUBP4_FLIP_INTERRUPT:
 54		return DC_IRQ_SOURCE_PFLIP5;
 55	case DCN_1_0__SRCID__HUBP5_FLIP_INTERRUPT:
 56		return DC_IRQ_SOURCE_PFLIP6;
 57	case DCN_1_0__SRCID__OTG0_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
 58		return DC_IRQ_SOURCE_VUPDATE1;
 59	case DCN_1_0__SRCID__OTG1_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
 60		return DC_IRQ_SOURCE_VUPDATE2;
 61	case DCN_1_0__SRCID__OTG2_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
 62		return DC_IRQ_SOURCE_VUPDATE3;
 63	case DCN_1_0__SRCID__OTG3_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
 64		return DC_IRQ_SOURCE_VUPDATE4;
 65	case DCN_1_0__SRCID__OTG4_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
 66		return DC_IRQ_SOURCE_VUPDATE5;
 67	case DCN_1_0__SRCID__OTG5_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
 68		return DC_IRQ_SOURCE_VUPDATE6;
 69	case DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT:
 70		return DC_IRQ_SOURCE_DMCUB_OUTBOX;
 71	case DCN_1_0__SRCID__DC_HPD1_INT:
 72		/* generic src_id for all HPD and HPDRX interrupts */
 73		switch (ext_id) {
 74		case DCN_1_0__CTXID__DC_HPD1_INT:
 75			return DC_IRQ_SOURCE_HPD1;
 76		case DCN_1_0__CTXID__DC_HPD2_INT:
 77			return DC_IRQ_SOURCE_HPD2;
 78		case DCN_1_0__CTXID__DC_HPD3_INT:
 79			return DC_IRQ_SOURCE_HPD3;
 80		case DCN_1_0__CTXID__DC_HPD4_INT:
 81			return DC_IRQ_SOURCE_HPD4;
 82		case DCN_1_0__CTXID__DC_HPD5_INT:
 83			return DC_IRQ_SOURCE_HPD5;
 84		case DCN_1_0__CTXID__DC_HPD6_INT:
 85			return DC_IRQ_SOURCE_HPD6;
 86		case DCN_1_0__CTXID__DC_HPD1_RX_INT:
 87			return DC_IRQ_SOURCE_HPD1RX;
 88		case DCN_1_0__CTXID__DC_HPD2_RX_INT:
 89			return DC_IRQ_SOURCE_HPD2RX;
 90		case DCN_1_0__CTXID__DC_HPD3_RX_INT:
 91			return DC_IRQ_SOURCE_HPD3RX;
 92		case DCN_1_0__CTXID__DC_HPD4_RX_INT:
 93			return DC_IRQ_SOURCE_HPD4RX;
 94		case DCN_1_0__CTXID__DC_HPD5_RX_INT:
 95			return DC_IRQ_SOURCE_HPD5RX;
 96		case DCN_1_0__CTXID__DC_HPD6_RX_INT:
 97			return DC_IRQ_SOURCE_HPD6RX;
 98		default:
 99			return DC_IRQ_SOURCE_INVALID;
100		}
101		break;
102
103	default:
104		return DC_IRQ_SOURCE_INVALID;
105	}
106}
107
108static struct irq_source_info_funcs hpd_irq_info_funcs = {
109	.set = NULL,
110	.ack = hpd0_ack
111};
112
113static struct irq_source_info_funcs hpd_rx_irq_info_funcs = {
114	.set = NULL,
115	.ack = NULL
116};
117
118static struct irq_source_info_funcs pflip_irq_info_funcs = {
119	.set = NULL,
120	.ack = NULL
121};
122
123static struct irq_source_info_funcs vupdate_no_lock_irq_info_funcs = {
124	.set = NULL,
125	.ack = NULL
126};
127
128static struct irq_source_info_funcs vblank_irq_info_funcs = {
129	.set = NULL,
130	.ack = NULL
131};
132
133static struct irq_source_info_funcs outbox_irq_info_funcs = {
134	.set = NULL,
135	.ack = NULL
136};
137
138static struct irq_source_info_funcs vline0_irq_info_funcs = {
139	.set = NULL,
140	.ack = NULL
141};
142
143#undef BASE_INNER
144#define BASE_INNER(seg) ctx->dcn_reg_offsets[seg]
145
146/* compile time expand base address. */
147#define BASE(seg) \
148	BASE_INNER(seg)
149
150#define SRI(reg_name, block, id)\
151	BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
152			reg ## block ## id ## _ ## reg_name
153
154#define SRI_DMUB(reg_name)\
155	BASE(reg ## reg_name ## _BASE_IDX) + \
156			reg ## reg_name
157
158#define IRQ_REG_ENTRY(base, block, reg_num, reg1, mask1, reg2, mask2)\
159	REG_STRUCT[base + reg_num].enable_reg = SRI(reg1, block, reg_num),\
160	REG_STRUCT[base + reg_num].enable_mask = \
161		block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\
162	REG_STRUCT[base + reg_num].enable_value[0] = \
163		block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\
164	REG_STRUCT[base + reg_num].enable_value[1] = \
165		~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK, \
166	REG_STRUCT[base + reg_num].ack_reg = SRI(reg2, block, reg_num),\
167	REG_STRUCT[base + reg_num].ack_mask = \
168		block ## reg_num ## _ ## reg2 ## __ ## mask2 ## _MASK,\
169	REG_STRUCT[base + reg_num].ack_value = \
170		block ## reg_num ## _ ## reg2 ## __ ## mask2 ## _MASK \
171
172#define IRQ_REG_ENTRY_DMUB(base, reg1, mask1, reg2, mask2)\
173	REG_STRUCT[base].enable_reg = SRI_DMUB(reg1),\
174	REG_STRUCT[base].enable_mask = \
175		reg1 ## __ ## mask1 ## _MASK,\
176	REG_STRUCT[base].enable_value[0] = \
177		reg1 ## __ ## mask1 ## _MASK,\
178	REG_STRUCT[base].enable_value[1] = \
179		~reg1 ## __ ## mask1 ## _MASK, \
180	REG_STRUCT[base].ack_reg = SRI_DMUB(reg2),\
181	REG_STRUCT[base].ack_mask = \
182		reg2 ## __ ## mask2 ## _MASK,\
183	REG_STRUCT[base].ack_value = \
184		reg2 ## __ ## mask2 ## _MASK \
185
186#define hpd_int_entry(reg_num)\
187		IRQ_REG_ENTRY(DC_IRQ_SOURCE_HPD1, HPD, reg_num,\
188			DC_HPD_INT_CONTROL, DC_HPD_INT_EN,\
189			DC_HPD_INT_CONTROL, DC_HPD_INT_ACK),\
190		REG_STRUCT[DC_IRQ_SOURCE_HPD1 + reg_num].funcs = &hpd_irq_info_funcs;\
191		REG_STRUCT[DC_IRQ_SOURCE_HPD1 + reg_num].status_reg = SRI(DC_HPD_INT_STATUS, HPD, reg_num);\
192
193#define hpd_rx_int_entry(reg_num)\
194		IRQ_REG_ENTRY(DC_IRQ_SOURCE_HPD1RX, HPD, reg_num,\
195			DC_HPD_INT_CONTROL, DC_HPD_RX_INT_EN,\
196			DC_HPD_INT_CONTROL, DC_HPD_RX_INT_ACK),\
197		REG_STRUCT[DC_IRQ_SOURCE_HPD1RX + reg_num].status_reg = SRI(DC_HPD_INT_STATUS, HPD, reg_num);\
198		REG_STRUCT[DC_IRQ_SOURCE_HPD1RX + reg_num].funcs = &hpd_rx_irq_info_funcs;\
199
200#define pflip_int_entry(reg_num)\
201		IRQ_REG_ENTRY(DC_IRQ_SOURCE_PFLIP1, HUBPREQ, reg_num,\
202			DCSURF_SURFACE_FLIP_INTERRUPT, SURFACE_FLIP_INT_MASK,\
203			DCSURF_SURFACE_FLIP_INTERRUPT, SURFACE_FLIP_CLEAR),\
204		REG_STRUCT[DC_IRQ_SOURCE_PFLIP1 + reg_num].funcs = &pflip_irq_info_funcs\
205
206/* vupdate_no_lock_int_entry maps to DC_IRQ_SOURCE_VUPDATEx, to match semantic
207 * of DCE's DC_IRQ_SOURCE_VUPDATEx.
208 */
209#define vupdate_no_lock_int_entry(reg_num)\
210		IRQ_REG_ENTRY(DC_IRQ_SOURCE_VUPDATE1, OTG, reg_num,\
211			OTG_GLOBAL_SYNC_STATUS, VUPDATE_NO_LOCK_INT_EN,\
212			OTG_GLOBAL_SYNC_STATUS, VUPDATE_NO_LOCK_EVENT_CLEAR),\
213		REG_STRUCT[DC_IRQ_SOURCE_VUPDATE1 + reg_num].funcs = &vupdate_no_lock_irq_info_funcs\
214
215#define vblank_int_entry(reg_num)\
216		IRQ_REG_ENTRY(DC_IRQ_SOURCE_VBLANK1, OTG, reg_num,\
217			OTG_GLOBAL_SYNC_STATUS, VSTARTUP_INT_EN,\
218			OTG_GLOBAL_SYNC_STATUS, VSTARTUP_EVENT_CLEAR),\
219		REG_STRUCT[DC_IRQ_SOURCE_VBLANK1 + reg_num].funcs = &vblank_irq_info_funcs\
220
221#define vline0_int_entry(reg_num)\
222		IRQ_REG_ENTRY(DC_IRQ_SOURCE_DC1_VLINE0, OTG, reg_num,\
223			OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_INT_ENABLE,\
224			OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_CLEAR),\
225		REG_STRUCT[DC_IRQ_SOURCE_DC1_VLINE0 + reg_num].funcs = &vline0_irq_info_funcs\
226
227#define dmub_outbox_int_entry()\
228		IRQ_REG_ENTRY_DMUB(DC_IRQ_SOURCE_DMCUB_OUTBOX, \
229			DMCUB_INTERRUPT_ENABLE, DMCUB_OUTBOX1_READY_INT_EN,\
230			DMCUB_INTERRUPT_ACK, DMCUB_OUTBOX1_READY_INT_ACK),\
231		REG_STRUCT[DC_IRQ_SOURCE_DMCUB_OUTBOX].funcs = &outbox_irq_info_funcs
232
233#define dummy_irq_entry(irqno) \
234	REG_STRUCT[irqno].funcs = &dummy_irq_info_funcs\
235
236#define i2c_int_entry(reg_num) \
237	dummy_irq_entry(DC_IRQ_SOURCE_I2C_DDC ## reg_num)
238
239#define dp_sink_int_entry(reg_num) \
240	dummy_irq_entry(DC_IRQ_SOURCE_DPSINK ## reg_num)
241
242#define gpio_pad_int_entry(reg_num) \
243	dummy_irq_entry(DC_IRQ_SOURCE_GPIOPAD ## reg_num)
244
245#define dc_underflow_int_entry(reg_num) \
246	dummy_irq_entry(DC_IRQ_SOURCE_DC ## reg_num ## UNDERFLOW)
247
248static struct irq_source_info_funcs dummy_irq_info_funcs = {
249	.set = dal_irq_service_dummy_set,
250	.ack = dal_irq_service_dummy_ack
251};
252
253#define dcn36_irq_init_part_1() {\
254	dummy_irq_entry(DC_IRQ_SOURCE_INVALID); \
255	hpd_int_entry(0); \
256	hpd_int_entry(1); \
257	hpd_int_entry(2); \
258	hpd_int_entry(3); \
259	hpd_int_entry(4); \
260	hpd_rx_int_entry(0); \
261	hpd_rx_int_entry(1); \
262	hpd_rx_int_entry(2); \
263	hpd_rx_int_entry(3); \
264	hpd_rx_int_entry(4); \
265	i2c_int_entry(1); \
266	i2c_int_entry(2); \
267	i2c_int_entry(3); \
268	i2c_int_entry(4); \
269	i2c_int_entry(5); \
270	i2c_int_entry(6); \
271	dp_sink_int_entry(1); \
272	dp_sink_int_entry(2); \
273	dp_sink_int_entry(3); \
274	dp_sink_int_entry(4); \
275	dp_sink_int_entry(5); \
276	dp_sink_int_entry(6); \
277	dummy_irq_entry(DC_IRQ_SOURCE_TIMER); \
278	pflip_int_entry(0); \
279	pflip_int_entry(1); \
280	pflip_int_entry(2); \
281	pflip_int_entry(3); \
282	dummy_irq_entry(DC_IRQ_SOURCE_PFLIP5); \
283	dummy_irq_entry(DC_IRQ_SOURCE_PFLIP6); \
284	dummy_irq_entry(DC_IRQ_SOURCE_PFLIP_UNDERLAY0); \
285	gpio_pad_int_entry(0); \
286	gpio_pad_int_entry(1); \
287	gpio_pad_int_entry(2); \
288	gpio_pad_int_entry(3); \
289	gpio_pad_int_entry(4); \
290	gpio_pad_int_entry(5); \
291	gpio_pad_int_entry(6); \
292	gpio_pad_int_entry(7); \
293	gpio_pad_int_entry(8); \
294	gpio_pad_int_entry(9); \
295	gpio_pad_int_entry(10); \
296	gpio_pad_int_entry(11); \
297	gpio_pad_int_entry(12); \
298	gpio_pad_int_entry(13); \
299	gpio_pad_int_entry(14); \
300	gpio_pad_int_entry(15); \
301	gpio_pad_int_entry(16); \
302	gpio_pad_int_entry(17); \
303	gpio_pad_int_entry(18); \
304	gpio_pad_int_entry(19); \
305	gpio_pad_int_entry(20); \
306	gpio_pad_int_entry(21); \
307	gpio_pad_int_entry(22); \
308	gpio_pad_int_entry(23); \
309	gpio_pad_int_entry(24); \
310	gpio_pad_int_entry(25); \
311	gpio_pad_int_entry(26); \
312	gpio_pad_int_entry(27); \
313	gpio_pad_int_entry(28); \
314	gpio_pad_int_entry(29); \
315	gpio_pad_int_entry(30); \
316	dc_underflow_int_entry(1); \
317	dc_underflow_int_entry(2); \
318	dc_underflow_int_entry(3); \
319	dc_underflow_int_entry(4); \
320	dc_underflow_int_entry(5); \
321	dc_underflow_int_entry(6); \
322	dummy_irq_entry(DC_IRQ_SOURCE_DMCU_SCP); \
323	dummy_irq_entry(DC_IRQ_SOURCE_VBIOS_SW); \
324}
325
326#define dcn36_irq_init_part_2() {\
327	vupdate_no_lock_int_entry(0); \
328	vupdate_no_lock_int_entry(1); \
329	vupdate_no_lock_int_entry(2); \
330	vupdate_no_lock_int_entry(3); \
331	vblank_int_entry(0); \
332	vblank_int_entry(1); \
333	vblank_int_entry(2); \
334	vblank_int_entry(3); \
335	vline0_int_entry(0); \
336	vline0_int_entry(1); \
337	vline0_int_entry(2); \
338	vline0_int_entry(3); \
339	dummy_irq_entry(DC_IRQ_SOURCE_DC5_VLINE1); \
340	dummy_irq_entry(DC_IRQ_SOURCE_DC6_VLINE1); \
341	dmub_outbox_int_entry(); \
342}
343
344#define dcn36_irq_init() {\
345	dcn36_irq_init_part_1(); \
346	dcn36_irq_init_part_2(); \
347}
348
349static struct irq_source_info irq_source_info_dcn36[DAL_IRQ_SOURCES_NUMBER] = {0};
350
351static struct irq_service_funcs irq_service_funcs_dcn36 = {
352		.to_dal_irq_source = to_dal_irq_source_dcn36
353};
354
355static void dcn36_irq_construct(
356	struct irq_service *irq_service,
357	struct irq_service_init_data *init_data)
358{
359	struct dc_context *ctx = init_data->ctx;
360
361#define REG_STRUCT irq_source_info_dcn36
362	dcn36_irq_init();
363
364	dal_irq_service_construct(irq_service, init_data);
365
366	irq_service->info = irq_source_info_dcn36;
367	irq_service->funcs = &irq_service_funcs_dcn36;
368}
369
370struct irq_service *dal_irq_service_dcn36_create(
371	struct irq_service_init_data *init_data)
372{
373	struct irq_service *irq_service = kzalloc(sizeof(*irq_service),
374						  GFP_KERNEL);
375
376	if (!irq_service)
377		return NULL;
378
379	dcn36_irq_construct(irq_service, init_data);
380	return irq_service;
381}
~/ Read-only file preview.