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