Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2012-15 Advanced Micro Devices, Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  * Authors: AMD
0023  *
0024  */
0025 
0026 #include "dm_services.h"
0027 
0028 #include "include/logger_interface.h"
0029 
0030 #include "irq_service_dce110.h"
0031 
0032 #include "dce/dce_11_0_d.h"
0033 #include "dce/dce_11_0_sh_mask.h"
0034 
0035 #include "ivsrcid/ivsrcid_vislands30.h"
0036 
0037 #include "dc.h"
0038 #include "core_types.h"
0039 #define DC_LOGGER \
0040     irq_service->ctx->logger
0041 
0042 static bool hpd_ack(struct irq_service *irq_service,
0043             const struct irq_source_info *info)
0044 {
0045     uint32_t addr = info->status_reg;
0046     uint32_t value = dm_read_reg(irq_service->ctx, addr);
0047     uint32_t current_status = get_reg_field_value(value,
0048                               DC_HPD_INT_STATUS,
0049                               DC_HPD_SENSE_DELAYED);
0050 
0051     dal_irq_service_ack_generic(irq_service, info);
0052 
0053     value = dm_read_reg(irq_service->ctx, info->enable_reg);
0054 
0055     set_reg_field_value(value, current_status ? 0 : 1,
0056                 DC_HPD_INT_CONTROL,
0057                 DC_HPD_INT_POLARITY);
0058 
0059     dm_write_reg(irq_service->ctx, info->enable_reg, value);
0060 
0061     return true;
0062 }
0063 
0064 static const struct irq_source_info_funcs hpd_irq_info_funcs = {
0065     .set = NULL,
0066     .ack = hpd_ack
0067 };
0068 
0069 static const struct irq_source_info_funcs hpd_rx_irq_info_funcs = {
0070     .set = NULL,
0071     .ack = NULL
0072 };
0073 
0074 static const struct irq_source_info_funcs pflip_irq_info_funcs = {
0075     .set = NULL,
0076     .ack = NULL
0077 };
0078 
0079 static const struct irq_source_info_funcs vblank_irq_info_funcs = {
0080     .set = dce110_vblank_set,
0081     .ack = NULL
0082 };
0083 
0084 static const struct irq_source_info_funcs vupdate_irq_info_funcs = {
0085     .set = NULL,
0086     .ack = NULL
0087 };
0088 
0089 #define hpd_int_entry(reg_num)\
0090     [DC_IRQ_SOURCE_HPD1 + reg_num] = {\
0091         .enable_reg = mmHPD ## reg_num ## _DC_HPD_INT_CONTROL,\
0092         .enable_mask = DC_HPD_INT_CONTROL__DC_HPD_INT_EN_MASK,\
0093         .enable_value = {\
0094             DC_HPD_INT_CONTROL__DC_HPD_INT_EN_MASK,\
0095             ~DC_HPD_INT_CONTROL__DC_HPD_INT_EN_MASK\
0096         },\
0097         .ack_reg = mmHPD ## reg_num ## _DC_HPD_INT_CONTROL,\
0098         .ack_mask = DC_HPD_INT_CONTROL__DC_HPD_INT_ACK_MASK,\
0099         .ack_value = DC_HPD_INT_CONTROL__DC_HPD_INT_ACK_MASK,\
0100         .status_reg = mmHPD ## reg_num ## _DC_HPD_INT_STATUS,\
0101         .funcs = &hpd_irq_info_funcs\
0102     }
0103 
0104 #define hpd_rx_int_entry(reg_num)\
0105     [DC_IRQ_SOURCE_HPD1RX + reg_num] = {\
0106         .enable_reg = mmHPD ## reg_num ## _DC_HPD_INT_CONTROL,\
0107         .enable_mask = DC_HPD_INT_CONTROL__DC_HPD_RX_INT_EN_MASK,\
0108         .enable_value = {\
0109             DC_HPD_INT_CONTROL__DC_HPD_RX_INT_EN_MASK,\
0110             ~DC_HPD_INT_CONTROL__DC_HPD_RX_INT_EN_MASK },\
0111         .ack_reg = mmHPD ## reg_num ## _DC_HPD_INT_CONTROL,\
0112         .ack_mask = DC_HPD_INT_CONTROL__DC_HPD_RX_INT_ACK_MASK,\
0113         .ack_value = DC_HPD_INT_CONTROL__DC_HPD_RX_INT_ACK_MASK,\
0114         .status_reg = mmHPD ## reg_num ## _DC_HPD_INT_STATUS,\
0115         .funcs = &hpd_rx_irq_info_funcs\
0116     }
0117 #define pflip_int_entry(reg_num)\
0118     [DC_IRQ_SOURCE_PFLIP1 + reg_num] = {\
0119         .enable_reg = mmDCP ## reg_num ## _GRPH_INTERRUPT_CONTROL,\
0120         .enable_mask =\
0121         GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK,\
0122         .enable_value = {\
0123             GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK,\
0124             ~GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK},\
0125         .ack_reg = mmDCP ## reg_num ## _GRPH_INTERRUPT_STATUS,\
0126         .ack_mask = GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_CLEAR_MASK,\
0127         .ack_value = GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_CLEAR_MASK,\
0128         .status_reg = mmDCP ## reg_num ##_GRPH_INTERRUPT_STATUS,\
0129         .funcs = &pflip_irq_info_funcs\
0130     }
0131 
0132 #define vupdate_int_entry(reg_num)\
0133     [DC_IRQ_SOURCE_VUPDATE1 + reg_num] = {\
0134         .enable_reg = mmCRTC ## reg_num ## _CRTC_INTERRUPT_CONTROL,\
0135         .enable_mask =\
0136         CRTC_INTERRUPT_CONTROL__CRTC_V_UPDATE_INT_MSK_MASK,\
0137         .enable_value = {\
0138             CRTC_INTERRUPT_CONTROL__CRTC_V_UPDATE_INT_MSK_MASK,\
0139             ~CRTC_INTERRUPT_CONTROL__CRTC_V_UPDATE_INT_MSK_MASK},\
0140         .ack_reg = mmCRTC ## reg_num ## _CRTC_V_UPDATE_INT_STATUS,\
0141         .ack_mask =\
0142         CRTC_V_UPDATE_INT_STATUS__CRTC_V_UPDATE_INT_CLEAR_MASK,\
0143         .ack_value =\
0144         CRTC_V_UPDATE_INT_STATUS__CRTC_V_UPDATE_INT_CLEAR_MASK,\
0145         .funcs = &vupdate_irq_info_funcs\
0146     }
0147 
0148 #define vblank_int_entry(reg_num)\
0149     [DC_IRQ_SOURCE_VBLANK1 + reg_num] = {\
0150         .enable_reg = mmCRTC ## reg_num ## _CRTC_VERTICAL_INTERRUPT0_CONTROL,\
0151         .enable_mask =\
0152         CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_INT_ENABLE_MASK,\
0153         .enable_value = {\
0154             CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_INT_ENABLE_MASK,\
0155             ~CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_INT_ENABLE_MASK},\
0156         .ack_reg = mmCRTC ## reg_num ## _CRTC_VERTICAL_INTERRUPT0_CONTROL,\
0157         .ack_mask =\
0158         CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_CLEAR_MASK,\
0159         .ack_value =\
0160         CRTC_VERTICAL_INTERRUPT0_CONTROL__CRTC_VERTICAL_INTERRUPT0_CLEAR_MASK,\
0161         .funcs = &vblank_irq_info_funcs,\
0162         .src_id = VISLANDS30_IV_SRCID_D1_VERTICAL_INTERRUPT0 + reg_num\
0163     }
0164 
0165 #define dummy_irq_entry() \
0166     {\
0167         .funcs = &dummy_irq_info_funcs\
0168     }
0169 
0170 #define i2c_int_entry(reg_num) \
0171     [DC_IRQ_SOURCE_I2C_DDC ## reg_num] = dummy_irq_entry()
0172 
0173 #define dp_sink_int_entry(reg_num) \
0174     [DC_IRQ_SOURCE_DPSINK ## reg_num] = dummy_irq_entry()
0175 
0176 #define gpio_pad_int_entry(reg_num) \
0177     [DC_IRQ_SOURCE_GPIOPAD ## reg_num] = dummy_irq_entry()
0178 
0179 #define dc_underflow_int_entry(reg_num) \
0180     [DC_IRQ_SOURCE_DC ## reg_num ## UNDERFLOW] = dummy_irq_entry()
0181 
0182 bool dal_irq_service_dummy_set(struct irq_service *irq_service,
0183                    const struct irq_source_info *info,
0184                    bool enable)
0185 {
0186     DC_LOG_ERROR("%s: called for non-implemented irq source, src_id=%u, ext_id=%u\n",
0187              __func__, info->src_id, info->ext_id);
0188 
0189     return false;
0190 }
0191 
0192 bool dal_irq_service_dummy_ack(struct irq_service *irq_service,
0193                    const struct irq_source_info *info)
0194 {
0195     DC_LOG_ERROR("%s: called for non-implemented irq source, src_id=%u, ext_id=%u\n",
0196              __func__, info->src_id, info->ext_id);
0197 
0198     return false;
0199 }
0200 
0201 
0202 bool dce110_vblank_set(struct irq_service *irq_service,
0203                const struct irq_source_info *info,
0204                bool enable)
0205 {
0206     struct dc_context *dc_ctx = irq_service->ctx;
0207     struct dc *dc = irq_service->ctx->dc;
0208     enum dc_irq_source dal_irq_src =
0209             dc_interrupt_to_irq_source(irq_service->ctx->dc,
0210                            info->src_id,
0211                            info->ext_id);
0212     uint8_t pipe_offset = dal_irq_src - IRQ_TYPE_VBLANK;
0213 
0214     struct timing_generator *tg =
0215             dc->current_state->res_ctx.pipe_ctx[pipe_offset].stream_res.tg;
0216 
0217     if (enable) {
0218         if (!tg || !tg->funcs->arm_vert_intr(tg, 2)) {
0219             DC_ERROR("Failed to get VBLANK!\n");
0220             return false;
0221         }
0222     }
0223 
0224     dal_irq_service_set_generic(irq_service, info, enable);
0225     return true;
0226 }
0227 
0228 static const struct irq_source_info_funcs dummy_irq_info_funcs = {
0229     .set = dal_irq_service_dummy_set,
0230     .ack = dal_irq_service_dummy_ack
0231 };
0232 
0233 static const struct irq_source_info
0234 irq_source_info_dce110[DAL_IRQ_SOURCES_NUMBER] = {
0235     [DC_IRQ_SOURCE_INVALID] = dummy_irq_entry(),
0236     hpd_int_entry(0),
0237     hpd_int_entry(1),
0238     hpd_int_entry(2),
0239     hpd_int_entry(3),
0240     hpd_int_entry(4),
0241     hpd_int_entry(5),
0242     hpd_rx_int_entry(0),
0243     hpd_rx_int_entry(1),
0244     hpd_rx_int_entry(2),
0245     hpd_rx_int_entry(3),
0246     hpd_rx_int_entry(4),
0247     hpd_rx_int_entry(5),
0248     i2c_int_entry(1),
0249     i2c_int_entry(2),
0250     i2c_int_entry(3),
0251     i2c_int_entry(4),
0252     i2c_int_entry(5),
0253     i2c_int_entry(6),
0254     dp_sink_int_entry(1),
0255     dp_sink_int_entry(2),
0256     dp_sink_int_entry(3),
0257     dp_sink_int_entry(4),
0258     dp_sink_int_entry(5),
0259     dp_sink_int_entry(6),
0260     [DC_IRQ_SOURCE_TIMER] = dummy_irq_entry(),
0261     pflip_int_entry(0),
0262     pflip_int_entry(1),
0263     pflip_int_entry(2),
0264     pflip_int_entry(3),
0265     pflip_int_entry(4),
0266     pflip_int_entry(5),
0267     [DC_IRQ_SOURCE_PFLIP_UNDERLAY0] = dummy_irq_entry(),
0268     gpio_pad_int_entry(0),
0269     gpio_pad_int_entry(1),
0270     gpio_pad_int_entry(2),
0271     gpio_pad_int_entry(3),
0272     gpio_pad_int_entry(4),
0273     gpio_pad_int_entry(5),
0274     gpio_pad_int_entry(6),
0275     gpio_pad_int_entry(7),
0276     gpio_pad_int_entry(8),
0277     gpio_pad_int_entry(9),
0278     gpio_pad_int_entry(10),
0279     gpio_pad_int_entry(11),
0280     gpio_pad_int_entry(12),
0281     gpio_pad_int_entry(13),
0282     gpio_pad_int_entry(14),
0283     gpio_pad_int_entry(15),
0284     gpio_pad_int_entry(16),
0285     gpio_pad_int_entry(17),
0286     gpio_pad_int_entry(18),
0287     gpio_pad_int_entry(19),
0288     gpio_pad_int_entry(20),
0289     gpio_pad_int_entry(21),
0290     gpio_pad_int_entry(22),
0291     gpio_pad_int_entry(23),
0292     gpio_pad_int_entry(24),
0293     gpio_pad_int_entry(25),
0294     gpio_pad_int_entry(26),
0295     gpio_pad_int_entry(27),
0296     gpio_pad_int_entry(28),
0297     gpio_pad_int_entry(29),
0298     gpio_pad_int_entry(30),
0299     dc_underflow_int_entry(1),
0300     dc_underflow_int_entry(2),
0301     dc_underflow_int_entry(3),
0302     dc_underflow_int_entry(4),
0303     dc_underflow_int_entry(5),
0304     dc_underflow_int_entry(6),
0305     [DC_IRQ_SOURCE_DMCU_SCP] = dummy_irq_entry(),
0306     [DC_IRQ_SOURCE_VBIOS_SW] = dummy_irq_entry(),
0307     vupdate_int_entry(0),
0308     vupdate_int_entry(1),
0309     vupdate_int_entry(2),
0310     vupdate_int_entry(3),
0311     vupdate_int_entry(4),
0312     vupdate_int_entry(5),
0313     vblank_int_entry(0),
0314     vblank_int_entry(1),
0315     vblank_int_entry(2),
0316     vblank_int_entry(3),
0317     vblank_int_entry(4),
0318     vblank_int_entry(5),
0319 
0320 };
0321 
0322 enum dc_irq_source to_dal_irq_source_dce110(
0323         struct irq_service *irq_service,
0324         uint32_t src_id,
0325         uint32_t ext_id)
0326 {
0327     switch (src_id) {
0328     case VISLANDS30_IV_SRCID_D1_VERTICAL_INTERRUPT0:
0329         return DC_IRQ_SOURCE_VBLANK1;
0330     case VISLANDS30_IV_SRCID_D2_VERTICAL_INTERRUPT0:
0331         return DC_IRQ_SOURCE_VBLANK2;
0332     case VISLANDS30_IV_SRCID_D3_VERTICAL_INTERRUPT0:
0333         return DC_IRQ_SOURCE_VBLANK3;
0334     case VISLANDS30_IV_SRCID_D4_VERTICAL_INTERRUPT0:
0335         return DC_IRQ_SOURCE_VBLANK4;
0336     case VISLANDS30_IV_SRCID_D5_VERTICAL_INTERRUPT0:
0337         return DC_IRQ_SOURCE_VBLANK5;
0338     case VISLANDS30_IV_SRCID_D6_VERTICAL_INTERRUPT0:
0339         return DC_IRQ_SOURCE_VBLANK6;
0340     case VISLANDS30_IV_SRCID_D1_V_UPDATE_INT:
0341         return DC_IRQ_SOURCE_VUPDATE1;
0342     case VISLANDS30_IV_SRCID_D2_V_UPDATE_INT:
0343         return DC_IRQ_SOURCE_VUPDATE2;
0344     case VISLANDS30_IV_SRCID_D3_V_UPDATE_INT:
0345         return DC_IRQ_SOURCE_VUPDATE3;
0346     case VISLANDS30_IV_SRCID_D4_V_UPDATE_INT:
0347         return DC_IRQ_SOURCE_VUPDATE4;
0348     case VISLANDS30_IV_SRCID_D5_V_UPDATE_INT:
0349         return DC_IRQ_SOURCE_VUPDATE5;
0350     case VISLANDS30_IV_SRCID_D6_V_UPDATE_INT:
0351         return DC_IRQ_SOURCE_VUPDATE6;
0352     case VISLANDS30_IV_SRCID_D1_GRPH_PFLIP:
0353         return DC_IRQ_SOURCE_PFLIP1;
0354     case VISLANDS30_IV_SRCID_D2_GRPH_PFLIP:
0355         return DC_IRQ_SOURCE_PFLIP2;
0356     case VISLANDS30_IV_SRCID_D3_GRPH_PFLIP:
0357         return DC_IRQ_SOURCE_PFLIP3;
0358     case VISLANDS30_IV_SRCID_D4_GRPH_PFLIP:
0359         return DC_IRQ_SOURCE_PFLIP4;
0360     case VISLANDS30_IV_SRCID_D5_GRPH_PFLIP:
0361         return DC_IRQ_SOURCE_PFLIP5;
0362     case VISLANDS30_IV_SRCID_D6_GRPH_PFLIP:
0363         return DC_IRQ_SOURCE_PFLIP6;
0364 
0365     case VISLANDS30_IV_SRCID_HOTPLUG_DETECT_A:
0366         /* generic src_id for all HPD and HPDRX interrupts */
0367         switch (ext_id) {
0368         case VISLANDS30_IV_EXTID_HOTPLUG_DETECT_A:
0369             return DC_IRQ_SOURCE_HPD1;
0370         case VISLANDS30_IV_EXTID_HOTPLUG_DETECT_B:
0371             return DC_IRQ_SOURCE_HPD2;
0372         case VISLANDS30_IV_EXTID_HOTPLUG_DETECT_C:
0373             return DC_IRQ_SOURCE_HPD3;
0374         case VISLANDS30_IV_EXTID_HOTPLUG_DETECT_D:
0375             return DC_IRQ_SOURCE_HPD4;
0376         case VISLANDS30_IV_EXTID_HOTPLUG_DETECT_E:
0377             return DC_IRQ_SOURCE_HPD5;
0378         case VISLANDS30_IV_EXTID_HOTPLUG_DETECT_F:
0379             return DC_IRQ_SOURCE_HPD6;
0380         case VISLANDS30_IV_EXTID_HPD_RX_A:
0381             return DC_IRQ_SOURCE_HPD1RX;
0382         case VISLANDS30_IV_EXTID_HPD_RX_B:
0383             return DC_IRQ_SOURCE_HPD2RX;
0384         case VISLANDS30_IV_EXTID_HPD_RX_C:
0385             return DC_IRQ_SOURCE_HPD3RX;
0386         case VISLANDS30_IV_EXTID_HPD_RX_D:
0387             return DC_IRQ_SOURCE_HPD4RX;
0388         case VISLANDS30_IV_EXTID_HPD_RX_E:
0389             return DC_IRQ_SOURCE_HPD5RX;
0390         case VISLANDS30_IV_EXTID_HPD_RX_F:
0391             return DC_IRQ_SOURCE_HPD6RX;
0392         default:
0393             return DC_IRQ_SOURCE_INVALID;
0394         }
0395         break;
0396 
0397     default:
0398         return DC_IRQ_SOURCE_INVALID;
0399     }
0400 }
0401 
0402 static const struct irq_service_funcs irq_service_funcs_dce110 = {
0403         .to_dal_irq_source = to_dal_irq_source_dce110
0404 };
0405 
0406 static void dce110_irq_construct(struct irq_service *irq_service,
0407               struct irq_service_init_data *init_data)
0408 {
0409     dal_irq_service_construct(irq_service, init_data);
0410 
0411     irq_service->info = irq_source_info_dce110;
0412     irq_service->funcs = &irq_service_funcs_dce110;
0413 }
0414 
0415 struct irq_service *
0416 dal_irq_service_dce110_create(struct irq_service_init_data *init_data)
0417 {
0418     struct irq_service *irq_service = kzalloc(sizeof(*irq_service),
0419                           GFP_KERNEL);
0420 
0421     if (!irq_service)
0422         return NULL;
0423 
0424     dce110_irq_construct(irq_service, init_data);
0425     return irq_service;
0426 }