Line data Source code
1 : // SPDX-License-Identifier: MIT
2 : /*
3 : * Copyright (C) 2021 Advanced Micro Devices, Inc.
4 : *
5 : * Authors: AMD
6 : */
7 :
8 : #include "dm_services.h"
9 : #include "irq_service_dcn303.h"
10 : #include "../dce110/irq_service_dce110.h"
11 :
12 : #include "sienna_cichlid_ip_offset.h"
13 : #include "dcn/dcn_3_0_3_offset.h"
14 : #include "dcn/dcn_3_0_3_sh_mask.h"
15 :
16 : #include "ivsrcid/dcn/irqsrcs_dcn_1_0.h"
17 :
18 0 : static enum dc_irq_source to_dal_irq_source_dcn303(struct irq_service *irq_service,
19 : uint32_t src_id,
20 : uint32_t ext_id)
21 : {
22 0 : switch (src_id) {
23 : case DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP:
24 : return DC_IRQ_SOURCE_VBLANK1;
25 : case DCN_1_0__SRCID__DC_D2_OTG_VSTARTUP:
26 0 : return DC_IRQ_SOURCE_VBLANK2;
27 : case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
28 0 : return DC_IRQ_SOURCE_DC1_VLINE0;
29 : case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
30 0 : return DC_IRQ_SOURCE_DC2_VLINE0;
31 : case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
32 0 : return DC_IRQ_SOURCE_PFLIP1;
33 : case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
34 0 : return DC_IRQ_SOURCE_PFLIP2;
35 : case DCN_1_0__SRCID__OTG0_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
36 0 : return DC_IRQ_SOURCE_VUPDATE1;
37 : case DCN_1_0__SRCID__OTG1_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
38 0 : return DC_IRQ_SOURCE_VUPDATE2;
39 :
40 : case DCN_1_0__SRCID__DC_HPD1_INT:
41 : /* generic src_id for all HPD and HPDRX interrupts */
42 : switch (ext_id) {
43 : case DCN_1_0__CTXID__DC_HPD1_INT:
44 : return DC_IRQ_SOURCE_HPD1;
45 : case DCN_1_0__CTXID__DC_HPD2_INT:
46 : return DC_IRQ_SOURCE_HPD2;
47 : case DCN_1_0__CTXID__DC_HPD1_RX_INT:
48 : return DC_IRQ_SOURCE_HPD1RX;
49 : case DCN_1_0__CTXID__DC_HPD2_RX_INT:
50 : return DC_IRQ_SOURCE_HPD2RX;
51 : default:
52 : return DC_IRQ_SOURCE_INVALID;
53 : }
54 : break;
55 :
56 : default:
57 0 : return DC_IRQ_SOURCE_INVALID;
58 : }
59 : }
60 :
61 0 : static bool hpd_ack(struct irq_service *irq_service, const struct irq_source_info *info)
62 : {
63 0 : uint32_t addr = info->status_reg;
64 0 : uint32_t value = dm_read_reg(irq_service->ctx, addr);
65 0 : uint32_t current_status = get_reg_field_value(value, HPD0_DC_HPD_INT_STATUS, DC_HPD_SENSE_DELAYED);
66 :
67 0 : dal_irq_service_ack_generic(irq_service, info);
68 :
69 0 : value = dm_read_reg(irq_service->ctx, info->enable_reg);
70 :
71 0 : set_reg_field_value(value, current_status ? 0 : 1, HPD0_DC_HPD_INT_CONTROL, DC_HPD_INT_POLARITY);
72 :
73 0 : dm_write_reg(irq_service->ctx, info->enable_reg, value);
74 :
75 0 : return true;
76 : }
77 :
78 : static const struct irq_source_info_funcs hpd_irq_info_funcs = {
79 : .set = NULL,
80 : .ack = hpd_ack
81 : };
82 :
83 : static const struct irq_source_info_funcs hpd_rx_irq_info_funcs = {
84 : .set = NULL,
85 : .ack = NULL
86 : };
87 :
88 : static const struct irq_source_info_funcs pflip_irq_info_funcs = {
89 : .set = NULL,
90 : .ack = NULL
91 : };
92 :
93 : static const struct irq_source_info_funcs vupdate_no_lock_irq_info_funcs = {
94 : .set = NULL,
95 : .ack = NULL
96 : };
97 :
98 : static const struct irq_source_info_funcs vblank_irq_info_funcs = {
99 : .set = NULL,
100 : .ack = NULL
101 : };
102 :
103 : static const struct irq_source_info_funcs vline0_irq_info_funcs = {
104 : .set = NULL,
105 : .ack = NULL
106 : };
107 :
108 : #undef BASE_INNER
109 : #define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
110 :
111 : /* compile time expand base address. */
112 : #define BASE(seg) BASE_INNER(seg)
113 :
114 : #define SRI(reg_name, block, id)\
115 : BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
116 : mm ## block ## id ## _ ## reg_name
117 :
118 :
119 : #define IRQ_REG_ENTRY(block, reg_num, reg1, mask1, reg2, mask2)\
120 : .enable_reg = SRI(reg1, block, reg_num),\
121 : .enable_mask = block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\
122 : .enable_value = {\
123 : block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\
124 : ~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK \
125 : },\
126 : .ack_reg = SRI(reg2, block, reg_num),\
127 : .ack_mask = block ## reg_num ## _ ## reg2 ## __ ## mask2 ## _MASK,\
128 : .ack_value = block ## reg_num ## _ ## reg2 ## __ ## mask2 ## _MASK \
129 :
130 :
131 :
132 : #define hpd_int_entry(reg_num)\
133 : [DC_IRQ_SOURCE_HPD1 + reg_num] = {\
134 : IRQ_REG_ENTRY(HPD, reg_num,\
135 : DC_HPD_INT_CONTROL, DC_HPD_INT_EN,\
136 : DC_HPD_INT_CONTROL, DC_HPD_INT_ACK),\
137 : .status_reg = SRI(DC_HPD_INT_STATUS, HPD, reg_num),\
138 : .funcs = &hpd_irq_info_funcs\
139 : }
140 :
141 : #define hpd_rx_int_entry(reg_num)\
142 : [DC_IRQ_SOURCE_HPD1RX + reg_num] = {\
143 : IRQ_REG_ENTRY(HPD, reg_num,\
144 : DC_HPD_INT_CONTROL, DC_HPD_RX_INT_EN,\
145 : DC_HPD_INT_CONTROL, DC_HPD_RX_INT_ACK),\
146 : .status_reg = SRI(DC_HPD_INT_STATUS, HPD, reg_num),\
147 : .funcs = &hpd_rx_irq_info_funcs\
148 : }
149 : #define pflip_int_entry(reg_num)\
150 : [DC_IRQ_SOURCE_PFLIP1 + reg_num] = {\
151 : IRQ_REG_ENTRY(HUBPREQ, reg_num,\
152 : DCSURF_SURFACE_FLIP_INTERRUPT, SURFACE_FLIP_INT_MASK,\
153 : DCSURF_SURFACE_FLIP_INTERRUPT, SURFACE_FLIP_CLEAR),\
154 : .funcs = &pflip_irq_info_funcs\
155 : }
156 :
157 : /* vupdate_no_lock_int_entry maps to DC_IRQ_SOURCE_VUPDATEx, to match semantic
158 : * of DCE's DC_IRQ_SOURCE_VUPDATEx.
159 : */
160 : #define vupdate_no_lock_int_entry(reg_num)\
161 : [DC_IRQ_SOURCE_VUPDATE1 + reg_num] = {\
162 : IRQ_REG_ENTRY(OTG, reg_num,\
163 : OTG_GLOBAL_SYNC_STATUS, VUPDATE_NO_LOCK_INT_EN,\
164 : OTG_GLOBAL_SYNC_STATUS, VUPDATE_NO_LOCK_EVENT_CLEAR),\
165 : .funcs = &vupdate_no_lock_irq_info_funcs\
166 : }
167 :
168 : #define vblank_int_entry(reg_num)\
169 : [DC_IRQ_SOURCE_VBLANK1 + reg_num] = {\
170 : IRQ_REG_ENTRY(OTG, reg_num,\
171 : OTG_GLOBAL_SYNC_STATUS, VSTARTUP_INT_EN,\
172 : OTG_GLOBAL_SYNC_STATUS, VSTARTUP_EVENT_CLEAR),\
173 : .funcs = &vblank_irq_info_funcs\
174 : }
175 :
176 : #define vline0_int_entry(reg_num)\
177 : [DC_IRQ_SOURCE_DC1_VLINE0 + reg_num] = {\
178 : IRQ_REG_ENTRY(OTG, reg_num,\
179 : OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_INT_ENABLE,\
180 : OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_CLEAR),\
181 : .funcs = &vline0_irq_info_funcs\
182 : }
183 :
184 : #define dummy_irq_entry() { .funcs = &dummy_irq_info_funcs }
185 :
186 : #define i2c_int_entry(reg_num) \
187 : [DC_IRQ_SOURCE_I2C_DDC ## reg_num] = dummy_irq_entry()
188 :
189 : #define dp_sink_int_entry(reg_num) \
190 : [DC_IRQ_SOURCE_DPSINK ## reg_num] = dummy_irq_entry()
191 :
192 : #define gpio_pad_int_entry(reg_num) \
193 : [DC_IRQ_SOURCE_GPIOPAD ## reg_num] = dummy_irq_entry()
194 :
195 : #define dc_underflow_int_entry(reg_num) \
196 : [DC_IRQ_SOURCE_DC ## reg_num ## UNDERFLOW] = dummy_irq_entry()
197 :
198 : static const struct irq_source_info_funcs dummy_irq_info_funcs = {
199 : .set = dal_irq_service_dummy_set,
200 : .ack = dal_irq_service_dummy_ack
201 : };
202 :
203 : static const struct irq_source_info irq_source_info_dcn303[DAL_IRQ_SOURCES_NUMBER] = {
204 : [DC_IRQ_SOURCE_INVALID] = dummy_irq_entry(),
205 : hpd_int_entry(0),
206 : hpd_int_entry(1),
207 : hpd_rx_int_entry(0),
208 : hpd_rx_int_entry(1),
209 : i2c_int_entry(1),
210 : i2c_int_entry(2),
211 : dp_sink_int_entry(1),
212 : dp_sink_int_entry(2),
213 : [DC_IRQ_SOURCE_TIMER] = dummy_irq_entry(),
214 : pflip_int_entry(0),
215 : pflip_int_entry(1),
216 : [DC_IRQ_SOURCE_PFLIP_UNDERLAY0] = dummy_irq_entry(),
217 : gpio_pad_int_entry(0),
218 : gpio_pad_int_entry(1),
219 : gpio_pad_int_entry(2),
220 : gpio_pad_int_entry(3),
221 : gpio_pad_int_entry(4),
222 : gpio_pad_int_entry(5),
223 : gpio_pad_int_entry(6),
224 : gpio_pad_int_entry(7),
225 : gpio_pad_int_entry(8),
226 : gpio_pad_int_entry(9),
227 : gpio_pad_int_entry(10),
228 : gpio_pad_int_entry(11),
229 : gpio_pad_int_entry(12),
230 : gpio_pad_int_entry(13),
231 : gpio_pad_int_entry(14),
232 : gpio_pad_int_entry(15),
233 : gpio_pad_int_entry(16),
234 : gpio_pad_int_entry(17),
235 : gpio_pad_int_entry(18),
236 : gpio_pad_int_entry(19),
237 : gpio_pad_int_entry(20),
238 : gpio_pad_int_entry(21),
239 : gpio_pad_int_entry(22),
240 : gpio_pad_int_entry(23),
241 : gpio_pad_int_entry(24),
242 : gpio_pad_int_entry(25),
243 : gpio_pad_int_entry(26),
244 : gpio_pad_int_entry(27),
245 : gpio_pad_int_entry(28),
246 : gpio_pad_int_entry(29),
247 : gpio_pad_int_entry(30),
248 : dc_underflow_int_entry(1),
249 : dc_underflow_int_entry(2),
250 : [DC_IRQ_SOURCE_DMCU_SCP] = dummy_irq_entry(),
251 : [DC_IRQ_SOURCE_VBIOS_SW] = dummy_irq_entry(),
252 : vupdate_no_lock_int_entry(0),
253 : vupdate_no_lock_int_entry(1),
254 : vblank_int_entry(0),
255 : vblank_int_entry(1),
256 : vline0_int_entry(0),
257 : vline0_int_entry(1),
258 : };
259 :
260 : static const struct irq_service_funcs irq_service_funcs_dcn303 = {
261 : .to_dal_irq_source = to_dal_irq_source_dcn303
262 : };
263 :
264 : static void dcn303_irq_construct(struct irq_service *irq_service, struct irq_service_init_data *init_data)
265 : {
266 0 : dal_irq_service_construct(irq_service, init_data);
267 :
268 0 : irq_service->info = irq_source_info_dcn303;
269 0 : irq_service->funcs = &irq_service_funcs_dcn303;
270 : }
271 :
272 0 : struct irq_service *dal_irq_service_dcn303_create(struct irq_service_init_data *init_data)
273 : {
274 0 : struct irq_service *irq_service = kzalloc(sizeof(*irq_service), GFP_KERNEL);
275 :
276 0 : if (!irq_service)
277 : return NULL;
278 :
279 0 : dcn303_irq_construct(irq_service, init_data);
280 0 : return irq_service;
281 : }
|