1 /* 2 * Copyright 2012-15 Advanced Micro Devices, Inc. 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 "dm_services.h" 27 28 #include "include/logger_interface.h" 29 30 #include "irq_service_dce110.h" 31 32 #include "dce/dce_11_0_d.h" 33 #include "dce/dce_11_0_sh_mask.h" 34 35 #include "ivsrcid/ivsrcid_vislands30.h" 36 37 #include "dc.h" 38 #include "core_types.h" 39 #define DC_LOGGER \ 40 irq_service->ctx->logger 41 42 static bool hpd_ack(struct irq_service *irq_service, 43 const struct irq_source_info *info) 44 { 45 uint32_t addr = info->status_reg; 46 uint32_t value = dm_read_reg(irq_service->ctx, addr); 47 uint32_t current_status = get_reg_field_value(value, 48 DC_HPD_INT_STATUS, 49 DC_HPD_SENSE_DELAYED); 50 51 dal_irq_service_ack_generic(irq_service, info); 52 53 value = dm_read_reg(irq_service->ctx, info->enable_reg); 54 55 set_reg_field_value(value, current_status ? 0 : 1, 56 DC_HPD_INT_CONTROL, 57 DC_HPD_INT_POLARITY); 58 59 dm_write_reg(irq_service->ctx, info->enable_reg, value); 60 61 return true; 62 } 63 64 static const struct irq_source_info_funcs hpd_irq_info_funcs = { 65 .set = NULL, 66 .ack = hpd_ack 67 }; 68 69 static const struct irq_source_info_funcs hpd_rx_irq_info_funcs = { 70 .set = NULL, 71 .ack = NULL 72 }; 73 74 static const struct irq_source_info_funcs pflip_irq_info_funcs = { 75 .set = NULL, 76 .ack = NULL 77 }; 78 79 static const struct irq_source_info_funcs vblank_irq_info_funcs = { 80 .set = dce110_vblank_set, 81 .ack = NULL 82 }; 83 84 #define hpd_int_entry(reg_num)\ 85 [DC_IRQ_SOURCE_HPD1 + reg_num] = {\ 86 .enable_reg = mmHPD ## reg_num ## _DC_HPD_INT_CONTROL,\ 87 .enable_mask = DC_HPD_INT_CONTROL__DC_HPD_INT_EN_MASK,\ 88 .enable_value = {\ 89 DC_HPD_INT_CONTROL__DC_HPD_INT_EN_MASK,\ 90 ~DC_HPD_INT_CONTROL__DC_HPD_INT_EN_MASK\ 91 },\ 92 .ack_reg = mmHPD ## reg_num ## _DC_HPD_INT_CONTROL,\ 93 .ack_mask = DC_HPD_INT_CONTROL__DC_HPD_INT_ACK_MASK,\ 94 .ack_value = DC_HPD_INT_CONTROL__DC_HPD_INT_ACK_MASK,\ 95 .status_reg = mmHPD ## reg_num ## _DC_HPD_INT_STATUS,\ 96 .funcs = &hpd_irq_info_funcs\ 97 } 98 99 #define hpd_rx_int_entry(reg_num)\ 100 [DC_IRQ_SOURCE_HPD1RX + reg_num] = {\ 101 .enable_reg = mmHPD ## reg_num ## _DC_HPD_INT_CONTROL,\ 102 .enable_mask = DC_HPD_INT_CONTROL__DC_HPD_RX_INT_EN_MASK,\ 103 .enable_value = {\ 104 DC_HPD_INT_CONTROL__DC_HPD_RX_INT_EN_MASK,\ 105 ~DC_HPD_INT_CONTROL__DC_HPD_RX_INT_EN_MASK },\ 106 .ack_reg = mmHPD ## reg_num ## _DC_HPD_INT_CONTROL,\ 107 .ack_mask = DC_HPD_INT_CONTROL__DC_HPD_RX_INT_ACK_MASK,\ 108 .ack_value = DC_HPD_INT_CONTROL__DC_HPD_RX_INT_ACK_MASK,\ 109 .status_reg = mmHPD ## reg_num ## _DC_HPD_INT_STATUS,\ 110 .funcs = &hpd_rx_irq_info_funcs\ 111 } 112 #define pflip_int_entry(reg_num)\ 113 [DC_IRQ_SOURCE_PFLIP1 + reg_num] = {\ 114 .enable_reg = mmDCP ## reg_num ## _GRPH_INTERRUPT_CONTROL,\ 115 .enable_mask =\ 116 GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK,\ 117 .enable_value = {\ 118 GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK,\ 119 ~GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK},\ 120 .ack_reg = mmDCP ## reg_num ## _GRPH_INTERRUPT_STATUS,\ 121 .ack_mask = GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_CLEAR_MASK,\ 122 .ack_value = GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_CLEAR_MASK,\ 123 .status_reg = mmDCP ## reg_num ##_GRPH_INTERRUPT_STATUS,\ 124 .funcs = &pflip_irq_info_funcs\ 125 } 126 127 #define vupdate_int_entry(reg_num)\ 128 [DC_IRQ_SOURCE_VUPDATE1 + reg_num] = {\ 129 .enable_reg = mmCRTC ## reg_num ## _CRTC_INTERRUPT_CONTROL,\ 130 .enable_mask =\ 131 CRTC_INTERRUPT_CONTROL__CRTC_V_UPDATE_INT_MSK_MASK,\ 132 .enable_value = {\ 133 CRTC_INTERRUPT_CONTROL__CRTC_V_UPDATE_INT_MSK_MASK,\ 134 ~CRTC_INTERRUPT_CONTROL__CRTC_V_UPDATE_INT_MSK_MASK},\ 135 .ack_reg = mmCRTC ## reg_num ## _CRTC_V_UPDATE_INT_STATUS,\ 136 .ack_mask =\ 137 CRTC_V_UPDATE_INT_STATUS__CRTC_V_UPDATE_INT_CLEAR_MASK,\ 138 .ack_value =\ 139 CRTC_V_UPDATE_INT_STATUS__CRTC_V_UPDATE_INT_CLEAR_MASK,\ 140 .funcs = &vblank_irq_info_funcs\ 141 } 142 143 #define vblank_int_entry(reg_num)\ 144 [DC_IRQ_SOURCE_VBLANK1 + reg_num] = {\ 145 .enable_reg = mmCRTC ## reg_num ## _CRTC_VERTICAL_INTERRUPT0_CONTROL,\ 146 .enable_mask =\ 147 CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_INT_ENABLE_MASK,\ 148 .enable_value = {\ 149 CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_INT_ENABLE_MASK,\ 150 ~CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_INT_ENABLE_MASK},\ 151 .ack_reg = mmCRTC ## reg_num ## _CRTC_VERTICAL_INTERRUPT0_CONTROL,\ 152 .ack_mask =\ 153 CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_CLEAR_MASK,\ 154 .ack_value =\ 155 CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_CLEAR_MASK,\ 156 .funcs = &vblank_irq_info_funcs,\ 157 .src_id = VISLANDS30_IV_SRCID_D1_VERTICAL_INTERRUPT0 + reg_num\ 158 } 159 160 #define dummy_irq_entry() \ 161 {\ 162 .funcs = &dummy_irq_info_funcs\ 163 } 164 165 #define i2c_int_entry(reg_num) \ 166 [DC_IRQ_SOURCE_I2C_DDC ## reg_num] = dummy_irq_entry() 167 168 #define dp_sink_int_entry(reg_num) \ 169 [DC_IRQ_SOURCE_DPSINK ## reg_num] = dummy_irq_entry() 170 171 #define gpio_pad_int_entry(reg_num) \ 172 [DC_IRQ_SOURCE_GPIOPAD ## reg_num] = dummy_irq_entry() 173 174 #define dc_underflow_int_entry(reg_num) \ 175 [DC_IRQ_SOURCE_DC ## reg_num ## UNDERFLOW] = dummy_irq_entry() 176 177 bool dal_irq_service_dummy_set(struct irq_service *irq_service, 178 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 186 bool 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 195 bool 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 221 static 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 226 static const struct irq_source_info 227 irq_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 315 enum 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 395 static const struct irq_service_funcs irq_service_funcs_dce110 = { 396 .to_dal_irq_source = to_dal_irq_source_dce110 397 }; 398 399 static 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 408 struct irq_service * 409 dal_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