linux/drivers/gpu/drm/amd/display/dc/irq/dcn303/irq_service_dcn303.c
<<
>>
Prefs
   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
  18static 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        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                return DC_IRQ_SOURCE_VBLANK2;
  27        case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
  28                return DC_IRQ_SOURCE_PFLIP1;
  29        case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
  30                return DC_IRQ_SOURCE_PFLIP2;
  31        case DCN_1_0__SRCID__OTG0_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
  32                return DC_IRQ_SOURCE_VUPDATE1;
  33        case DCN_1_0__SRCID__OTG1_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
  34                return DC_IRQ_SOURCE_VUPDATE2;
  35
  36        case DCN_1_0__SRCID__DC_HPD1_INT:
  37                /* generic src_id for all HPD and HPDRX interrupts */
  38                switch (ext_id) {
  39                case DCN_1_0__CTXID__DC_HPD1_INT:
  40                        return DC_IRQ_SOURCE_HPD1;
  41                case DCN_1_0__CTXID__DC_HPD2_INT:
  42                        return DC_IRQ_SOURCE_HPD2;
  43                case DCN_1_0__CTXID__DC_HPD1_RX_INT:
  44                        return DC_IRQ_SOURCE_HPD1RX;
  45                case DCN_1_0__CTXID__DC_HPD2_RX_INT:
  46                        return DC_IRQ_SOURCE_HPD2RX;
  47                default:
  48                        return DC_IRQ_SOURCE_INVALID;
  49                }
  50                break;
  51
  52        default:
  53                return DC_IRQ_SOURCE_INVALID;
  54        }
  55}
  56
  57static bool hpd_ack(struct irq_service *irq_service, const struct irq_source_info *info)
  58{
  59        uint32_t addr = info->status_reg;
  60        uint32_t value = dm_read_reg(irq_service->ctx, addr);
  61        uint32_t current_status = get_reg_field_value(value, HPD0_DC_HPD_INT_STATUS, DC_HPD_SENSE_DELAYED);
  62
  63        dal_irq_service_ack_generic(irq_service, info);
  64
  65        value = dm_read_reg(irq_service->ctx, info->enable_reg);
  66
  67        set_reg_field_value(value, current_status ? 0 : 1, HPD0_DC_HPD_INT_CONTROL, 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 vupdate_no_lock_irq_info_funcs = {
  90        .set = NULL,
  91        .ack = NULL
  92};
  93
  94static const struct irq_source_info_funcs vblank_irq_info_funcs = {
  95                .set = NULL,
  96                .ack = NULL
  97};
  98
  99#undef BASE_INNER
 100#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
 101
 102/* compile time expand base address. */
 103#define BASE(seg) 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 = block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\
 113                .enable_value = {\
 114                                block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\
 115                                ~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK \
 116                },\
 117                .ack_reg = SRI(reg2, block, reg_num),\
 118                .ack_mask = block ## reg_num ## _ ## reg2 ## __ ## mask2 ## _MASK,\
 119                .ack_value = block ## reg_num ## _ ## reg2 ## __ ## mask2 ## _MASK \
 120
 121
 122
 123#define hpd_int_entry(reg_num)\
 124                [DC_IRQ_SOURCE_HPD1 + reg_num] = {\
 125                                IRQ_REG_ENTRY(HPD, reg_num,\
 126                                                DC_HPD_INT_CONTROL, DC_HPD_INT_EN,\
 127                                                DC_HPD_INT_CONTROL, DC_HPD_INT_ACK),\
 128                                                .status_reg = SRI(DC_HPD_INT_STATUS, HPD, reg_num),\
 129                                                .funcs = &hpd_irq_info_funcs\
 130}
 131
 132#define hpd_rx_int_entry(reg_num)\
 133                [DC_IRQ_SOURCE_HPD1RX + reg_num] = {\
 134                                IRQ_REG_ENTRY(HPD, reg_num,\
 135                                                DC_HPD_INT_CONTROL, DC_HPD_RX_INT_EN,\
 136                                                DC_HPD_INT_CONTROL, DC_HPD_RX_INT_ACK),\
 137                                                .status_reg = SRI(DC_HPD_INT_STATUS, HPD, reg_num),\
 138                                                .funcs = &hpd_rx_irq_info_funcs\
 139}
 140#define pflip_int_entry(reg_num)\
 141                [DC_IRQ_SOURCE_PFLIP1 + reg_num] = {\
 142                                IRQ_REG_ENTRY(HUBPREQ, reg_num,\
 143                                                DCSURF_SURFACE_FLIP_INTERRUPT, SURFACE_FLIP_INT_MASK,\
 144                                                DCSURF_SURFACE_FLIP_INTERRUPT, SURFACE_FLIP_CLEAR),\
 145                                                .funcs = &pflip_irq_info_funcs\
 146}
 147
 148/* vupdate_no_lock_int_entry maps to DC_IRQ_SOURCE_VUPDATEx, to match semantic
 149 * of DCE's DC_IRQ_SOURCE_VUPDATEx.
 150 */
 151#define vupdate_no_lock_int_entry(reg_num)\
 152        [DC_IRQ_SOURCE_VUPDATE1 + reg_num] = {\
 153                IRQ_REG_ENTRY(OTG, reg_num,\
 154                        OTG_GLOBAL_SYNC_STATUS, VUPDATE_NO_LOCK_INT_EN,\
 155                        OTG_GLOBAL_SYNC_STATUS, VUPDATE_NO_LOCK_EVENT_CLEAR),\
 156                .funcs = &vupdate_no_lock_irq_info_funcs\
 157        }
 158
 159#define vblank_int_entry(reg_num)\
 160        [DC_IRQ_SOURCE_VBLANK1 + reg_num] = {\
 161                IRQ_REG_ENTRY(OTG, reg_num,\
 162                        OTG_GLOBAL_SYNC_STATUS, VSTARTUP_INT_EN,\
 163                        OTG_GLOBAL_SYNC_STATUS, VSTARTUP_EVENT_CLEAR),\
 164                .funcs = &vblank_irq_info_funcs\
 165        }
 166
 167#define dummy_irq_entry() { .funcs = &dummy_irq_info_funcs }
 168
 169#define i2c_int_entry(reg_num) \
 170                [DC_IRQ_SOURCE_I2C_DDC ## reg_num] = dummy_irq_entry()
 171
 172#define dp_sink_int_entry(reg_num) \
 173                [DC_IRQ_SOURCE_DPSINK ## reg_num] = dummy_irq_entry()
 174
 175#define gpio_pad_int_entry(reg_num) \
 176                [DC_IRQ_SOURCE_GPIOPAD ## reg_num] = dummy_irq_entry()
 177
 178#define dc_underflow_int_entry(reg_num) \
 179                [DC_IRQ_SOURCE_DC ## reg_num ## UNDERFLOW] = dummy_irq_entry()
 180
 181static const struct irq_source_info_funcs dummy_irq_info_funcs = {
 182                .set = dal_irq_service_dummy_set,
 183                .ack = dal_irq_service_dummy_ack
 184};
 185
 186static const struct irq_source_info irq_source_info_dcn303[DAL_IRQ_SOURCES_NUMBER] = {
 187                [DC_IRQ_SOURCE_INVALID] = dummy_irq_entry(),
 188                hpd_int_entry(0),
 189                hpd_int_entry(1),
 190                hpd_rx_int_entry(0),
 191                hpd_rx_int_entry(1),
 192                i2c_int_entry(1),
 193                i2c_int_entry(2),
 194                dp_sink_int_entry(1),
 195                dp_sink_int_entry(2),
 196                [DC_IRQ_SOURCE_TIMER] = dummy_irq_entry(),
 197                pflip_int_entry(0),
 198                pflip_int_entry(1),
 199                [DC_IRQ_SOURCE_PFLIP_UNDERLAY0] = dummy_irq_entry(),
 200                gpio_pad_int_entry(0),
 201                gpio_pad_int_entry(1),
 202                gpio_pad_int_entry(2),
 203                gpio_pad_int_entry(3),
 204                gpio_pad_int_entry(4),
 205                gpio_pad_int_entry(5),
 206                gpio_pad_int_entry(6),
 207                gpio_pad_int_entry(7),
 208                gpio_pad_int_entry(8),
 209                gpio_pad_int_entry(9),
 210                gpio_pad_int_entry(10),
 211                gpio_pad_int_entry(11),
 212                gpio_pad_int_entry(12),
 213                gpio_pad_int_entry(13),
 214                gpio_pad_int_entry(14),
 215                gpio_pad_int_entry(15),
 216                gpio_pad_int_entry(16),
 217                gpio_pad_int_entry(17),
 218                gpio_pad_int_entry(18),
 219                gpio_pad_int_entry(19),
 220                gpio_pad_int_entry(20),
 221                gpio_pad_int_entry(21),
 222                gpio_pad_int_entry(22),
 223                gpio_pad_int_entry(23),
 224                gpio_pad_int_entry(24),
 225                gpio_pad_int_entry(25),
 226                gpio_pad_int_entry(26),
 227                gpio_pad_int_entry(27),
 228                gpio_pad_int_entry(28),
 229                gpio_pad_int_entry(29),
 230                gpio_pad_int_entry(30),
 231                dc_underflow_int_entry(1),
 232                dc_underflow_int_entry(2),
 233                [DC_IRQ_SOURCE_DMCU_SCP] = dummy_irq_entry(),
 234                [DC_IRQ_SOURCE_VBIOS_SW] = dummy_irq_entry(),
 235                vupdate_no_lock_int_entry(0),
 236                vupdate_no_lock_int_entry(1),
 237                vblank_int_entry(0),
 238                vblank_int_entry(1),
 239};
 240
 241static const struct irq_service_funcs irq_service_funcs_dcn303 = {
 242                .to_dal_irq_source = to_dal_irq_source_dcn303
 243};
 244
 245static void dcn303_irq_construct(struct irq_service *irq_service, struct irq_service_init_data *init_data)
 246{
 247        dal_irq_service_construct(irq_service, init_data);
 248
 249        irq_service->info = irq_source_info_dcn303;
 250        irq_service->funcs = &irq_service_funcs_dcn303;
 251}
 252
 253struct irq_service *dal_irq_service_dcn303_create(struct irq_service_init_data *init_data)
 254{
 255        struct irq_service *irq_service = kzalloc(sizeof(*irq_service), GFP_KERNEL);
 256
 257        if (!irq_service)
 258                return NULL;
 259
 260        dcn303_irq_construct(irq_service, init_data);
 261        return irq_service;
 262}
 263