1 /*
2  * Copyright 2020 Mauro Rossi <issor.oruam@gmail.com>
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_dce60.h"
33 #include "../dce110/irq_service_dce110.h"
34 
35 #include "dce/dce_6_0_d.h"
36 #include "dce/dce_6_0_sh_mask.h"
37 
38 #include "ivsrcid/ivsrcid_vislands30.h"
39 
40 #define VISLANDS30_IV_SRCID_D1_VBLANK                        1
41 #define VISLANDS30_IV_SRCID_D2_VBLANK                        2
42 #define VISLANDS30_IV_SRCID_D3_VBLANK                        3
43 #define VISLANDS30_IV_SRCID_D4_VBLANK                        4
44 #define VISLANDS30_IV_SRCID_D5_VBLANK                        5
45 #define VISLANDS30_IV_SRCID_D6_VBLANK                        6
46 
47 #include "dc_types.h"
48 
hpd_ack(struct irq_service * irq_service,const struct irq_source_info * info)49 static bool hpd_ack(
50 	struct irq_service *irq_service,
51 	const struct irq_source_info *info)
52 {
53 	uint32_t addr = info->status_reg;
54 	uint32_t value = dm_read_reg(irq_service->ctx, addr);
55 	uint32_t current_status =
56 		get_reg_field_value(
57 			value,
58 			DC_HPD1_INT_STATUS,
59 			DC_HPD1_SENSE_DELAYED);
60 
61 	dal_irq_service_ack_generic(irq_service, info);
62 
63 	value = dm_read_reg(irq_service->ctx, info->enable_reg);
64 
65 	set_reg_field_value(
66 		value,
67 		current_status ? 0 : 1,
68 		DC_HPD1_INT_CONTROL,
69 		DC_HPD1_INT_POLARITY);
70 
71 	dm_write_reg(irq_service->ctx, info->enable_reg, value);
72 
73 	return true;
74 }
75 
76 static struct irq_source_info_funcs hpd_irq_info_funcs  = {
77 	.set = NULL,
78 	.ack = hpd_ack
79 };
80 
81 static struct irq_source_info_funcs hpd_rx_irq_info_funcs = {
82 	.set = NULL,
83 	.ack = NULL
84 };
85 
86 static struct irq_source_info_funcs pflip_irq_info_funcs = {
87 	.set = NULL,
88 	.ack = NULL
89 };
90 
91 static struct irq_source_info_funcs vblank_irq_info_funcs = {
92 	.set = dce110_vblank_set,
93 	.ack = NULL
94 };
95 
96 static struct irq_source_info_funcs vblank_irq_info_funcs_dce60 = {
97 	.set = NULL,
98 	.ack = NULL
99 };
100 
101 #define hpd_int_entry(reg_num)\
102 	[DC_IRQ_SOURCE_INVALID + reg_num] = {\
103 		.enable_reg = mmDC_HPD ## reg_num ## _INT_CONTROL,\
104 		.enable_mask = DC_HPD1_INT_CONTROL__DC_HPD1_INT_EN_MASK,\
105 		.enable_value = {\
106 			DC_HPD1_INT_CONTROL__DC_HPD1_INT_EN_MASK,\
107 			~DC_HPD1_INT_CONTROL__DC_HPD1_INT_EN_MASK\
108 		},\
109 		.ack_reg = mmDC_HPD ## reg_num ## _INT_CONTROL,\
110 		.ack_mask = DC_HPD1_INT_CONTROL__DC_HPD1_INT_ACK_MASK,\
111 		.ack_value = DC_HPD1_INT_CONTROL__DC_HPD1_INT_ACK_MASK,\
112 		.status_reg = mmDC_HPD ## reg_num ## _INT_STATUS,\
113 		.funcs = &hpd_irq_info_funcs\
114 	}
115 
116 #define hpd_rx_int_entry(reg_num)\
117 	[DC_IRQ_SOURCE_HPD6 + reg_num] = {\
118 		.enable_reg = mmDC_HPD ## reg_num ## _INT_CONTROL,\
119 		.enable_mask = DC_HPD1_INT_CONTROL__DC_HPD1_RX_INT_EN_MASK,\
120 		.enable_value = {\
121 				DC_HPD1_INT_CONTROL__DC_HPD1_RX_INT_EN_MASK,\
122 			~DC_HPD1_INT_CONTROL__DC_HPD1_RX_INT_EN_MASK },\
123 		.ack_reg = mmDC_HPD ## reg_num ## _INT_CONTROL,\
124 		.ack_mask = DC_HPD1_INT_CONTROL__DC_HPD1_RX_INT_ACK_MASK,\
125 		.ack_value = DC_HPD1_INT_CONTROL__DC_HPD1_RX_INT_ACK_MASK,\
126 		.status_reg = mmDC_HPD ## reg_num ## _INT_STATUS,\
127 		.funcs = &hpd_rx_irq_info_funcs\
128 	}
129 
130 #define pflip_int_entry(reg_num)\
131 	[DC_IRQ_SOURCE_PFLIP1 + reg_num] = {\
132 		.enable_reg = mmDCP ## reg_num ## _GRPH_INTERRUPT_CONTROL,\
133 		.enable_mask =\
134 		GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK,\
135 		.enable_value = {\
136 			GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK,\
137 			~GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK},\
138 		.ack_reg = mmDCP ## reg_num ## _GRPH_INTERRUPT_STATUS,\
139 		.ack_mask = GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_CLEAR_MASK,\
140 		.ack_value = GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_CLEAR_MASK,\
141 		.status_reg = mmDCP ## reg_num ##_GRPH_INTERRUPT_STATUS,\
142 		.funcs = &pflip_irq_info_funcs\
143  	}
144 
145 #define vupdate_int_entry(reg_num)\
146 	[DC_IRQ_SOURCE_VUPDATE1 + reg_num] = {\
147 		.enable_reg = mmCRTC ## reg_num ## _CRTC_INTERRUPT_CONTROL,\
148 		.enable_mask =\
149 		CRTC_INTERRUPT_CONTROL__CRTC_V_UPDATE_INT_MSK_MASK,\
150 		.enable_value = {\
151 			CRTC_INTERRUPT_CONTROL__CRTC_V_UPDATE_INT_MSK_MASK,\
152 			~CRTC_INTERRUPT_CONTROL__CRTC_V_UPDATE_INT_MSK_MASK},\
153 		.ack_reg = mmCRTC ## reg_num ## _CRTC_V_UPDATE_INT_STATUS,\
154 		.ack_mask =\
155 		CRTC_V_UPDATE_INT_STATUS__CRTC_V_UPDATE_INT_CLEAR_MASK,\
156 		.ack_value =\
157 		CRTC_V_UPDATE_INT_STATUS__CRTC_V_UPDATE_INT_CLEAR_MASK,\
158 		.funcs = &vblank_irq_info_funcs\
159 	}
160 
161 #define vblank_int_entry(reg_num)\
162 	[DC_IRQ_SOURCE_VBLANK1 + reg_num] = {\
163 		.enable_reg = mmLB ## reg_num ## _INT_MASK,\
164 		.enable_mask =\
165 			INT_MASK__VBLANK_INT_MASK,\
166 		.enable_value = {\
167 			INT_MASK__VBLANK_INT_MASK,\
168 			~INT_MASK__VBLANK_INT_MASK},\
169 		.ack_reg = mmLB ## reg_num ## _VBLANK_STATUS,\
170 		.ack_mask =\
171 		VBLANK_STATUS__VBLANK_ACK_MASK,\
172 		.ack_value =\
173 		VBLANK_STATUS__VBLANK_ACK_MASK,\
174 		.funcs = &vblank_irq_info_funcs_dce60\
175 	}
176 
177 #define dummy_irq_entry() \
178 	{\
179 		.funcs = &dummy_irq_info_funcs\
180 	}
181 
182 #define i2c_int_entry(reg_num) \
183 	[DC_IRQ_SOURCE_I2C_DDC ## reg_num] = dummy_irq_entry()
184 
185 #define dp_sink_int_entry(reg_num) \
186 	[DC_IRQ_SOURCE_DPSINK ## reg_num] = dummy_irq_entry()
187 
188 #define gpio_pad_int_entry(reg_num) \
189 	[DC_IRQ_SOURCE_GPIOPAD ## reg_num] = dummy_irq_entry()
190 
191 #define dc_underflow_int_entry(reg_num) \
192 	[DC_IRQ_SOURCE_DC ## reg_num ## UNDERFLOW] = dummy_irq_entry()
193 
194 
195 static struct irq_source_info_funcs dummy_irq_info_funcs = {
196 	.set = dal_irq_service_dummy_set,
197 	.ack = dal_irq_service_dummy_ack
198 };
199 
200 static const struct irq_source_info
201 irq_source_info_dce60[DAL_IRQ_SOURCES_NUMBER] = {
202 	[DC_IRQ_SOURCE_INVALID] = dummy_irq_entry(),
203 	hpd_int_entry(1),
204 	hpd_int_entry(2),
205 	hpd_int_entry(3),
206 	hpd_int_entry(4),
207 	hpd_int_entry(5),
208 	hpd_int_entry(6),
209 	hpd_rx_int_entry(1),
210 	hpd_rx_int_entry(2),
211 	hpd_rx_int_entry(3),
212 	hpd_rx_int_entry(4),
213 	hpd_rx_int_entry(5),
214 	hpd_rx_int_entry(6),
215 	i2c_int_entry(1),
216 	i2c_int_entry(2),
217 	i2c_int_entry(3),
218 	i2c_int_entry(4),
219 	i2c_int_entry(5),
220 	i2c_int_entry(6),
221 	dp_sink_int_entry(1),
222 	dp_sink_int_entry(2),
223 	dp_sink_int_entry(3),
224 	dp_sink_int_entry(4),
225 	dp_sink_int_entry(5),
226 	dp_sink_int_entry(6),
227 	[DC_IRQ_SOURCE_TIMER] = dummy_irq_entry(),
228 	pflip_int_entry(0),
229 	pflip_int_entry(1),
230 	pflip_int_entry(2),
231 	pflip_int_entry(3),
232 	pflip_int_entry(4),
233 	pflip_int_entry(5),
234 	[DC_IRQ_SOURCE_PFLIP_UNDERLAY0] = dummy_irq_entry(),
235 	gpio_pad_int_entry(0),
236 	gpio_pad_int_entry(1),
237 	gpio_pad_int_entry(2),
238 	gpio_pad_int_entry(3),
239 	gpio_pad_int_entry(4),
240 	gpio_pad_int_entry(5),
241 	gpio_pad_int_entry(6),
242 	gpio_pad_int_entry(7),
243 	gpio_pad_int_entry(8),
244 	gpio_pad_int_entry(9),
245 	gpio_pad_int_entry(10),
246 	gpio_pad_int_entry(11),
247 	gpio_pad_int_entry(12),
248 	gpio_pad_int_entry(13),
249 	gpio_pad_int_entry(14),
250 	gpio_pad_int_entry(15),
251 	gpio_pad_int_entry(16),
252 	gpio_pad_int_entry(17),
253 	gpio_pad_int_entry(18),
254 	gpio_pad_int_entry(19),
255 	gpio_pad_int_entry(20),
256 	gpio_pad_int_entry(21),
257 	gpio_pad_int_entry(22),
258 	gpio_pad_int_entry(23),
259 	gpio_pad_int_entry(24),
260 	gpio_pad_int_entry(25),
261 	gpio_pad_int_entry(26),
262 	gpio_pad_int_entry(27),
263 	gpio_pad_int_entry(28),
264 	gpio_pad_int_entry(29),
265 	gpio_pad_int_entry(30),
266 	dc_underflow_int_entry(1),
267 	dc_underflow_int_entry(2),
268 	dc_underflow_int_entry(3),
269 	dc_underflow_int_entry(4),
270 	dc_underflow_int_entry(5),
271 	dc_underflow_int_entry(6),
272 	[DC_IRQ_SOURCE_DMCU_SCP] = dummy_irq_entry(),
273 	[DC_IRQ_SOURCE_VBIOS_SW] = dummy_irq_entry(),
274 	vupdate_int_entry(0),
275 	vupdate_int_entry(1),
276 	vupdate_int_entry(2),
277 	vupdate_int_entry(3),
278 	vupdate_int_entry(4),
279 	vupdate_int_entry(5),
280 	vblank_int_entry(0),
281 	vblank_int_entry(1),
282 	vblank_int_entry(2),
283 	vblank_int_entry(3),
284 	vblank_int_entry(4),
285 	vblank_int_entry(5),
286 };
287 
to_dal_irq_source_dce60(struct irq_service * irq_service,uint32_t src_id,uint32_t ext_id)288 enum dc_irq_source to_dal_irq_source_dce60(
289 		struct irq_service *irq_service,
290 		uint32_t src_id,
291 		uint32_t ext_id)
292 {
293 	switch (src_id) {
294 	case VISLANDS30_IV_SRCID_D1_VBLANK:
295 		return DC_IRQ_SOURCE_VBLANK1;
296 	case VISLANDS30_IV_SRCID_D2_VBLANK:
297 		return DC_IRQ_SOURCE_VBLANK2;
298 	case VISLANDS30_IV_SRCID_D3_VBLANK:
299 		return DC_IRQ_SOURCE_VBLANK3;
300 	case VISLANDS30_IV_SRCID_D4_VBLANK:
301 		return DC_IRQ_SOURCE_VBLANK4;
302 	case VISLANDS30_IV_SRCID_D5_VBLANK:
303 		return DC_IRQ_SOURCE_VBLANK5;
304 	case VISLANDS30_IV_SRCID_D6_VBLANK:
305 		return DC_IRQ_SOURCE_VBLANK6;
306 	case VISLANDS30_IV_SRCID_D1_V_UPDATE_INT:
307 		return DC_IRQ_SOURCE_VUPDATE1;
308 	case VISLANDS30_IV_SRCID_D2_V_UPDATE_INT:
309 		return DC_IRQ_SOURCE_VUPDATE2;
310 	case VISLANDS30_IV_SRCID_D3_V_UPDATE_INT:
311 		return DC_IRQ_SOURCE_VUPDATE3;
312 	case VISLANDS30_IV_SRCID_D4_V_UPDATE_INT:
313 		return DC_IRQ_SOURCE_VUPDATE4;
314 	case VISLANDS30_IV_SRCID_D5_V_UPDATE_INT:
315 		return DC_IRQ_SOURCE_VUPDATE5;
316 	case VISLANDS30_IV_SRCID_D6_V_UPDATE_INT:
317 		return DC_IRQ_SOURCE_VUPDATE6;
318 	case VISLANDS30_IV_SRCID_D1_GRPH_PFLIP:
319 		return DC_IRQ_SOURCE_PFLIP1;
320 	case VISLANDS30_IV_SRCID_D2_GRPH_PFLIP:
321 		return DC_IRQ_SOURCE_PFLIP2;
322 	case VISLANDS30_IV_SRCID_D3_GRPH_PFLIP:
323 		return DC_IRQ_SOURCE_PFLIP3;
324 	case VISLANDS30_IV_SRCID_D4_GRPH_PFLIP:
325 		return DC_IRQ_SOURCE_PFLIP4;
326 	case VISLANDS30_IV_SRCID_D5_GRPH_PFLIP:
327 		return DC_IRQ_SOURCE_PFLIP5;
328 	case VISLANDS30_IV_SRCID_D6_GRPH_PFLIP:
329 		return DC_IRQ_SOURCE_PFLIP6;
330 
331 	case VISLANDS30_IV_SRCID_HOTPLUG_DETECT_A:
332 		/* generic src_id for all HPD and HPDRX interrupts */
333 		switch (ext_id) {
334 		case VISLANDS30_IV_EXTID_HOTPLUG_DETECT_A:
335 			return DC_IRQ_SOURCE_HPD1;
336 		case VISLANDS30_IV_EXTID_HOTPLUG_DETECT_B:
337 			return DC_IRQ_SOURCE_HPD2;
338 		case VISLANDS30_IV_EXTID_HOTPLUG_DETECT_C:
339 			return DC_IRQ_SOURCE_HPD3;
340 		case VISLANDS30_IV_EXTID_HOTPLUG_DETECT_D:
341 			return DC_IRQ_SOURCE_HPD4;
342 		case VISLANDS30_IV_EXTID_HOTPLUG_DETECT_E:
343 			return DC_IRQ_SOURCE_HPD5;
344 		case VISLANDS30_IV_EXTID_HOTPLUG_DETECT_F:
345 			return DC_IRQ_SOURCE_HPD6;
346 		case VISLANDS30_IV_EXTID_HPD_RX_A:
347 			return DC_IRQ_SOURCE_HPD1RX;
348 		case VISLANDS30_IV_EXTID_HPD_RX_B:
349 			return DC_IRQ_SOURCE_HPD2RX;
350 		case VISLANDS30_IV_EXTID_HPD_RX_C:
351 			return DC_IRQ_SOURCE_HPD3RX;
352 		case VISLANDS30_IV_EXTID_HPD_RX_D:
353 			return DC_IRQ_SOURCE_HPD4RX;
354 		case VISLANDS30_IV_EXTID_HPD_RX_E:
355 			return DC_IRQ_SOURCE_HPD5RX;
356 		case VISLANDS30_IV_EXTID_HPD_RX_F:
357 			return DC_IRQ_SOURCE_HPD6RX;
358 		default:
359 			return DC_IRQ_SOURCE_INVALID;
360 		}
361 		break;
362 
363 	default:
364 		return DC_IRQ_SOURCE_INVALID;
365 	}
366 }
367 
368 static const struct irq_service_funcs irq_service_funcs_dce60 = {
369 		.to_dal_irq_source = to_dal_irq_source_dce60
370 };
371 
dce60_irq_construct(struct irq_service * irq_service,struct irq_service_init_data * init_data)372 static void dce60_irq_construct(
373 	struct irq_service *irq_service,
374 	struct irq_service_init_data *init_data)
375 {
376 	dal_irq_service_construct(irq_service, init_data);
377 
378 	irq_service->info = irq_source_info_dce60;
379 	irq_service->funcs = &irq_service_funcs_dce60;
380 }
381 
dal_irq_service_dce60_create(struct irq_service_init_data * init_data)382 struct irq_service *dal_irq_service_dce60_create(
383 	struct irq_service_init_data *init_data)
384 {
385 	struct irq_service *irq_service = kzalloc(sizeof(*irq_service),
386 						  GFP_KERNEL);
387 
388 	if (!irq_service)
389 		return NULL;
390 
391 	dce60_irq_construct(irq_service, init_data);
392 	return irq_service;
393 }
394 
395 
396