1/* $NetBSD: amdgpu_irq_service_dce110.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_dce110.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_dce110.h" 38 39#include "dce/dce_11_0_d.h" 40#include "dce/dce_11_0_sh_mask.h" 41 42#include "ivsrcid/ivsrcid_vislands30.h" 43 44#include "dc.h" 45#include "core_types.h" 46#define DC_LOGGER \ 47 irq_service->ctx->logger 48 49static bool hpd_ack(struct irq_service *irq_service, 50 const struct irq_source_info *info) 51{ 52 uint32_t addr = info->status_reg; 53 uint32_t value = dm_read_reg(irq_service->ctx, addr); 54 uint32_t current_status = get_reg_field_value(value, 55 DC_HPD_INT_STATUS, 56 DC_HPD_SENSE_DELAYED); 57 58 dal_irq_service_ack_generic(irq_service, info); 59 60 value = dm_read_reg(irq_service->ctx, info->enable_reg); 61 62 set_reg_field_value(value, current_status ? 0 : 1, 63 DC_HPD_INT_CONTROL, 64 DC_HPD_INT_POLARITY); 65 66 dm_write_reg(irq_service->ctx, info->enable_reg, value); 67 68 return true; 69} 70 71static const struct irq_source_info_funcs hpd_irq_info_funcs = { 72 .set = NULL, 73 .ack = hpd_ack 74}; 75 76static const struct irq_source_info_funcs hpd_rx_irq_info_funcs = { 77 .set = NULL, 78 .ack = NULL 79}; 80 81static const struct irq_source_info_funcs pflip_irq_info_funcs = { 82 .set = NULL, 83 .ack = NULL 84}; 85 86static const struct irq_source_info_funcs vblank_irq_info_funcs = { 87 .set = dce110_vblank_set, 88 .ack = NULL 89}; 90 91static const struct irq_source_info_funcs vupdate_irq_info_funcs = { 92 .set = NULL, 93 .ack = NULL 94}; 95 96#define hpd_int_entry(reg_num)\ 97 [DC_IRQ_SOURCE_HPD1 + reg_num] = {\ 98 .enable_reg = mmHPD ## reg_num ## _DC_HPD_INT_CONTROL,\ 99 .enable_mask = DC_HPD_INT_CONTROL__DC_HPD_INT_EN_MASK,\ 100 .enable_value = {\ 101 DC_HPD_INT_CONTROL__DC_HPD_INT_EN_MASK,\ 102 ~DC_HPD_INT_CONTROL__DC_HPD_INT_EN_MASK\ 103 },\ 104 .ack_reg = mmHPD ## reg_num ## _DC_HPD_INT_CONTROL,\ 105 .ack_mask = DC_HPD_INT_CONTROL__DC_HPD_INT_ACK_MASK,\ 106 .ack_value = DC_HPD_INT_CONTROL__DC_HPD_INT_ACK_MASK,\ 107 .status_reg = mmHPD ## reg_num ## _DC_HPD_INT_STATUS,\ 108 .funcs = &hpd_irq_info_funcs\ 109 } 110 111#define hpd_rx_int_entry(reg_num)\ 112 [DC_IRQ_SOURCE_HPD1RX + reg_num] = {\ 113 .enable_reg = mmHPD ## reg_num ## _DC_HPD_INT_CONTROL,\ 114 .enable_mask = DC_HPD_INT_CONTROL__DC_HPD_RX_INT_EN_MASK,\ 115 .enable_value = {\ 116 DC_HPD_INT_CONTROL__DC_HPD_RX_INT_EN_MASK,\ 117 ~DC_HPD_INT_CONTROL__DC_HPD_RX_INT_EN_MASK },\ 118 .ack_reg = mmHPD ## reg_num ## _DC_HPD_INT_CONTROL,\ 119 .ack_mask = DC_HPD_INT_CONTROL__DC_HPD_RX_INT_ACK_MASK,\ 120 .ack_value = DC_HPD_INT_CONTROL__DC_HPD_RX_INT_ACK_MASK,\ 121 .status_reg = mmHPD ## reg_num ## _DC_HPD_INT_STATUS,\ 122 .funcs = &hpd_rx_irq_info_funcs\ 123 } 124#define pflip_int_entry(reg_num)\ 125 [DC_IRQ_SOURCE_PFLIP1 + reg_num] = {\ 126 .enable_reg = mmDCP ## reg_num ## _GRPH_INTERRUPT_CONTROL,\ 127 .enable_mask =\ 128 GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK,\ 129 .enable_value = {\ 130 GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK,\ 131 ~GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK},\ 132 .ack_reg = mmDCP ## reg_num ## _GRPH_INTERRUPT_STATUS,\ 133 .ack_mask = GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_CLEAR_MASK,\ 134 .ack_value = GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_CLEAR_MASK,\ 135 .status_reg = mmDCP ## reg_num ##_GRPH_INTERRUPT_STATUS,\ 136 .funcs = &pflip_irq_info_funcs\ 137 } 138 139#define vupdate_int_entry(reg_num)\ 140 [DC_IRQ_SOURCE_VUPDATE1 + reg_num] = {\ 141 .enable_reg = mmCRTC ## reg_num ## _CRTC_INTERRUPT_CONTROL,\ 142 .enable_mask =\ 143 CRTC_INTERRUPT_CONTROL__CRTC_V_UPDATE_INT_MSK_MASK,\ 144 .enable_value = {\ 145 CRTC_INTERRUPT_CONTROL__CRTC_V_UPDATE_INT_MSK_MASK,\ 146 ~CRTC_INTERRUPT_CONTROL__CRTC_V_UPDATE_INT_MSK_MASK},\ 147 .ack_reg = mmCRTC ## reg_num ## _CRTC_V_UPDATE_INT_STATUS,\ 148 .ack_mask =\ 149 CRTC_V_UPDATE_INT_STATUS__CRTC_V_UPDATE_INT_CLEAR_MASK,\ 150 .ack_value =\ 151 CRTC_V_UPDATE_INT_STATUS__CRTC_V_UPDATE_INT_CLEAR_MASK,\ 152 .funcs = &vupdate_irq_info_funcs\ 153 } 154 155#define vblank_int_entry(reg_num)\ 156 [DC_IRQ_SOURCE_VBLANK1 + reg_num] = {\ 157 .enable_reg = mmCRTC ## reg_num ## _CRTC_VERTICAL_INTERRUPT0_CONTROL,\ 158 .enable_mask =\ 159 CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_INT_ENABLE_MASK,\ 160 .enable_value = {\ 161 CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_INT_ENABLE_MASK,\ 162 ~CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_INT_ENABLE_MASK},\ 163 .ack_reg = mmCRTC ## reg_num ## _CRTC_VERTICAL_INTERRUPT0_CONTROL,\ 164 .ack_mask =\ 165 CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_CLEAR_MASK,\ 166 .ack_value =\ 167 CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_CLEAR_MASK,\ 168 .funcs = &vblank_irq_info_funcs,\ 169 .src_id = VISLANDS30_IV_SRCID_D1_VERTICAL_INTERRUPT0 + reg_num\ 170 } 171 172#define dummy_irq_entry() \ 173 {\ 174 .funcs = &dummy_irq_info_funcs\ 175 } 176 177#define i2c_int_entry(reg_num) \ 178 [DC_IRQ_SOURCE_I2C_DDC ## reg_num] = dummy_irq_entry() 179 180#define dp_sink_int_entry(reg_num) \ 181 [DC_IRQ_SOURCE_DPSINK ## reg_num] = dummy_irq_entry() 182 183#define gpio_pad_int_entry(reg_num) \ 184 [DC_IRQ_SOURCE_GPIOPAD ## reg_num] = dummy_irq_entry() 185 186#define dc_underflow_int_entry(reg_num) \ 187 [DC_IRQ_SOURCE_DC ## reg_num ## UNDERFLOW] = dummy_irq_entry() 188 189bool dal_irq_service_dummy_set(struct irq_service *irq_service, 190 const struct irq_source_info *info, 191 bool enable) 192{ 193 DC_LOG_ERROR("%s: called for non-implemented irq source\n", 194 __func__); 195 return false; 196} 197 198bool dal_irq_service_dummy_ack(struct irq_service *irq_service, 199 const struct irq_source_info *info) 200{ 201 DC_LOG_ERROR("%s: called for non-implemented irq source\n", 202 __func__); 203 return false; 204} 205 206 207bool dce110_vblank_set(struct irq_service *irq_service, 208 const struct irq_source_info *info, 209 bool enable) 210{ 211 struct dc_context *dc_ctx = irq_service->ctx; 212 struct dc *dc = irq_service->ctx->dc; 213 enum dc_irq_source dal_irq_src = 214 dc_interrupt_to_irq_source(irq_service->ctx->dc, 215 info->src_id, 216 info->ext_id); 217 uint8_t pipe_offset = dal_irq_src - IRQ_TYPE_VBLANK; 218 219 struct timing_generator *tg = 220 dc->current_state->res_ctx.pipe_ctx[pipe_offset].stream_res.tg; 221 222 if (enable) { 223 if (!tg || !tg->funcs->arm_vert_intr(tg, 2)) { 224 DC_ERROR("Failed to get VBLANK!\n"); 225 return false; 226 } 227 } 228 229 dal_irq_service_set_generic(irq_service, info, enable); 230 return true; 231} 232 233static const struct irq_source_info_funcs dummy_irq_info_funcs = { 234 .set = dal_irq_service_dummy_set, 235 .ack = dal_irq_service_dummy_ack 236}; 237 238static const struct irq_source_info 239irq_source_info_dce110[DAL_IRQ_SOURCES_NUMBER] = { 240 [DC_IRQ_SOURCE_INVALID] = dummy_irq_entry(), 241 hpd_int_entry(0), 242 hpd_int_entry(1), 243 hpd_int_entry(2), 244 hpd_int_entry(3), 245 hpd_int_entry(4), 246 hpd_int_entry(5), 247 hpd_rx_int_entry(0), 248 hpd_rx_int_entry(1), 249 hpd_rx_int_entry(2), 250 hpd_rx_int_entry(3), 251 hpd_rx_int_entry(4), 252 hpd_rx_int_entry(5), 253 i2c_int_entry(1), 254 i2c_int_entry(2), 255 i2c_int_entry(3), 256 i2c_int_entry(4), 257 i2c_int_entry(5), 258 i2c_int_entry(6), 259 dp_sink_int_entry(1), 260 dp_sink_int_entry(2), 261 dp_sink_int_entry(3), 262 dp_sink_int_entry(4), 263 dp_sink_int_entry(5), 264 dp_sink_int_entry(6), 265 [DC_IRQ_SOURCE_TIMER] = dummy_irq_entry(), 266 pflip_int_entry(0), 267 pflip_int_entry(1), 268 pflip_int_entry(2), 269 pflip_int_entry(3), 270 pflip_int_entry(4), 271 pflip_int_entry(5), 272 [DC_IRQ_SOURCE_PFLIP_UNDERLAY0] = dummy_irq_entry(), 273 gpio_pad_int_entry(0), 274 gpio_pad_int_entry(1), 275 gpio_pad_int_entry(2), 276 gpio_pad_int_entry(3), 277 gpio_pad_int_entry(4), 278 gpio_pad_int_entry(5), 279 gpio_pad_int_entry(6), 280 gpio_pad_int_entry(7), 281 gpio_pad_int_entry(8), 282 gpio_pad_int_entry(9), 283 gpio_pad_int_entry(10), 284 gpio_pad_int_entry(11), 285 gpio_pad_int_entry(12), 286 gpio_pad_int_entry(13), 287 gpio_pad_int_entry(14), 288 gpio_pad_int_entry(15), 289 gpio_pad_int_entry(16), 290 gpio_pad_int_entry(17), 291 gpio_pad_int_entry(18), 292 gpio_pad_int_entry(19), 293 gpio_pad_int_entry(20), 294 gpio_pad_int_entry(21), 295 gpio_pad_int_entry(22), 296 gpio_pad_int_entry(23), 297 gpio_pad_int_entry(24), 298 gpio_pad_int_entry(25), 299 gpio_pad_int_entry(26), 300 gpio_pad_int_entry(27), 301 gpio_pad_int_entry(28), 302 gpio_pad_int_entry(29), 303 gpio_pad_int_entry(30), 304 dc_underflow_int_entry(1), 305 dc_underflow_int_entry(2), 306 dc_underflow_int_entry(3), 307 dc_underflow_int_entry(4), 308 dc_underflow_int_entry(5), 309 dc_underflow_int_entry(6), 310 [DC_IRQ_SOURCE_DMCU_SCP] = dummy_irq_entry(), 311 [DC_IRQ_SOURCE_VBIOS_SW] = dummy_irq_entry(), 312 vupdate_int_entry(0), 313 vupdate_int_entry(1), 314 vupdate_int_entry(2), 315 vupdate_int_entry(3), 316 vupdate_int_entry(4), 317 vupdate_int_entry(5), 318 vblank_int_entry(0), 319 vblank_int_entry(1), 320 vblank_int_entry(2), 321 vblank_int_entry(3), 322 vblank_int_entry(4), 323 vblank_int_entry(5), 324 325}; 326 327enum dc_irq_source to_dal_irq_source_dce110( 328 struct irq_service *irq_service, 329 uint32_t src_id, 330 uint32_t ext_id) 331{ 332 switch (src_id) { 333 case VISLANDS30_IV_SRCID_D1_VERTICAL_INTERRUPT0: 334 return DC_IRQ_SOURCE_VBLANK1; 335 case VISLANDS30_IV_SRCID_D2_VERTICAL_INTERRUPT0: 336 return DC_IRQ_SOURCE_VBLANK2; 337 case VISLANDS30_IV_SRCID_D3_VERTICAL_INTERRUPT0: 338 return DC_IRQ_SOURCE_VBLANK3; 339 case VISLANDS30_IV_SRCID_D4_VERTICAL_INTERRUPT0: 340 return DC_IRQ_SOURCE_VBLANK4; 341 case VISLANDS30_IV_SRCID_D5_VERTICAL_INTERRUPT0: 342 return DC_IRQ_SOURCE_VBLANK5; 343 case VISLANDS30_IV_SRCID_D6_VERTICAL_INTERRUPT0: 344 return DC_IRQ_SOURCE_VBLANK6; 345 case VISLANDS30_IV_SRCID_D1_V_UPDATE_INT: 346 return DC_IRQ_SOURCE_VUPDATE1; 347 case VISLANDS30_IV_SRCID_D2_V_UPDATE_INT: 348 return DC_IRQ_SOURCE_VUPDATE2; 349 case VISLANDS30_IV_SRCID_D3_V_UPDATE_INT: 350 return DC_IRQ_SOURCE_VUPDATE3; 351 case VISLANDS30_IV_SRCID_D4_V_UPDATE_INT: 352 return DC_IRQ_SOURCE_VUPDATE4; 353 case VISLANDS30_IV_SRCID_D5_V_UPDATE_INT: 354 return DC_IRQ_SOURCE_VUPDATE5; 355 case VISLANDS30_IV_SRCID_D6_V_UPDATE_INT: 356 return DC_IRQ_SOURCE_VUPDATE6; 357 case VISLANDS30_IV_SRCID_D1_GRPH_PFLIP: 358 return DC_IRQ_SOURCE_PFLIP1; 359 case VISLANDS30_IV_SRCID_D2_GRPH_PFLIP: 360 return DC_IRQ_SOURCE_PFLIP2; 361 case VISLANDS30_IV_SRCID_D3_GRPH_PFLIP: 362 return DC_IRQ_SOURCE_PFLIP3; 363 case VISLANDS30_IV_SRCID_D4_GRPH_PFLIP: 364 return DC_IRQ_SOURCE_PFLIP4; 365 case VISLANDS30_IV_SRCID_D5_GRPH_PFLIP: 366 return DC_IRQ_SOURCE_PFLIP5; 367 case VISLANDS30_IV_SRCID_D6_GRPH_PFLIP: 368 return DC_IRQ_SOURCE_PFLIP6; 369 370 case VISLANDS30_IV_SRCID_HOTPLUG_DETECT_A: 371 /* generic src_id for all HPD and HPDRX interrupts */ 372 switch (ext_id) { 373 case VISLANDS30_IV_EXTID_HOTPLUG_DETECT_A: 374 return DC_IRQ_SOURCE_HPD1; 375 case VISLANDS30_IV_EXTID_HOTPLUG_DETECT_B: 376 return DC_IRQ_SOURCE_HPD2; 377 case VISLANDS30_IV_EXTID_HOTPLUG_DETECT_C: 378 return DC_IRQ_SOURCE_HPD3; 379 case VISLANDS30_IV_EXTID_HOTPLUG_DETECT_D: 380 return DC_IRQ_SOURCE_HPD4; 381 case VISLANDS30_IV_EXTID_HOTPLUG_DETECT_E: 382 return DC_IRQ_SOURCE_HPD5; 383 case VISLANDS30_IV_EXTID_HOTPLUG_DETECT_F: 384 return DC_IRQ_SOURCE_HPD6; 385 case VISLANDS30_IV_EXTID_HPD_RX_A: 386 return DC_IRQ_SOURCE_HPD1RX; 387 case VISLANDS30_IV_EXTID_HPD_RX_B: 388 return DC_IRQ_SOURCE_HPD2RX; 389 case VISLANDS30_IV_EXTID_HPD_RX_C: 390 return DC_IRQ_SOURCE_HPD3RX; 391 case VISLANDS30_IV_EXTID_HPD_RX_D: 392 return DC_IRQ_SOURCE_HPD4RX; 393 case VISLANDS30_IV_EXTID_HPD_RX_E: 394 return DC_IRQ_SOURCE_HPD5RX; 395 case VISLANDS30_IV_EXTID_HPD_RX_F: 396 return DC_IRQ_SOURCE_HPD6RX; 397 default: 398 return DC_IRQ_SOURCE_INVALID; 399 } 400 break; 401 402 default: 403 return DC_IRQ_SOURCE_INVALID; 404 } 405} 406 407static const struct irq_service_funcs irq_service_funcs_dce110 = { 408 .to_dal_irq_source = to_dal_irq_source_dce110 409}; 410 411static void dce110_irq_construct(struct irq_service *irq_service, 412 struct irq_service_init_data *init_data) 413{ 414 dal_irq_service_construct(irq_service, init_data); 415 416 irq_service->info = irq_source_info_dce110; 417 irq_service->funcs = &irq_service_funcs_dce110; 418} 419 420struct irq_service * 421dal_irq_service_dce110_create(struct irq_service_init_data *init_data) 422{ 423 struct irq_service *irq_service = kzalloc(sizeof(*irq_service), 424 GFP_KERNEL); 425 426 if (!irq_service) 427 return NULL; 428 429 dce110_irq_construct(irq_service, init_data); 430 return irq_service; 431} 432