1/* $NetBSD: amdgpu_irq_service.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.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/irq_service_interface.h" 36#include "include/logger_interface.h" 37 38#include "dce110/irq_service_dce110.h" 39 40 41#include "dce80/irq_service_dce80.h" 42 43#include "dce120/irq_service_dce120.h" 44 45 46#if defined(CONFIG_DRM_AMD_DC_DCN) 47#include "dcn10/irq_service_dcn10.h" 48#endif 49 50#include "reg_helper.h" 51#include "irq_service.h" 52 53 54 55#define CTX \ 56 irq_service->ctx 57#define DC_LOGGER \ 58 irq_service->ctx->logger 59 60void dal_irq_service_construct( 61 struct irq_service *irq_service, 62 struct irq_service_init_data *init_data) 63{ 64 if (!init_data || !init_data->ctx) { 65 BREAK_TO_DEBUGGER(); 66 return; 67 } 68 69 irq_service->ctx = init_data->ctx; 70} 71 72void dal_irq_service_destroy(struct irq_service **irq_service) 73{ 74 if (!irq_service || !*irq_service) { 75 BREAK_TO_DEBUGGER(); 76 return; 77 } 78 79 kfree(*irq_service); 80 81 *irq_service = NULL; 82} 83 84const struct irq_source_info *find_irq_source_info( 85 struct irq_service *irq_service, 86 enum dc_irq_source source) 87{ 88 if (source >= DAL_IRQ_SOURCES_NUMBER || source < DC_IRQ_SOURCE_INVALID) 89 return NULL; 90 91 return &irq_service->info[source]; 92} 93 94void dal_irq_service_set_generic( 95 struct irq_service *irq_service, 96 const struct irq_source_info *info, 97 bool enable) 98{ 99 uint32_t addr = info->enable_reg; 100 uint32_t value = dm_read_reg(irq_service->ctx, addr); 101 102 value = (value & ~info->enable_mask) | 103 (info->enable_value[enable ? 0 : 1] & info->enable_mask); 104 dm_write_reg(irq_service->ctx, addr, value); 105} 106 107bool dal_irq_service_set( 108 struct irq_service *irq_service, 109 enum dc_irq_source source, 110 bool enable) 111{ 112 const struct irq_source_info *info = 113 find_irq_source_info(irq_service, source); 114 115 if (!info) { 116 DC_LOG_ERROR("%s: cannot find irq info table entry for %d\n", 117 __func__, 118 source); 119 return false; 120 } 121 122 dal_irq_service_ack(irq_service, source); 123 124 if (info->funcs->set) 125 return info->funcs->set(irq_service, info, enable); 126 127 dal_irq_service_set_generic(irq_service, info, enable); 128 129 return true; 130} 131 132void dal_irq_service_ack_generic( 133 struct irq_service *irq_service, 134 const struct irq_source_info *info) 135{ 136 uint32_t addr = info->ack_reg; 137 uint32_t value = dm_read_reg(irq_service->ctx, addr); 138 139 value = (value & ~info->ack_mask) | 140 (info->ack_value & info->ack_mask); 141 dm_write_reg(irq_service->ctx, addr, value); 142} 143 144bool dal_irq_service_ack( 145 struct irq_service *irq_service, 146 enum dc_irq_source source) 147{ 148 const struct irq_source_info *info = 149 find_irq_source_info(irq_service, source); 150 151 if (!info) { 152 DC_LOG_ERROR("%s: cannot find irq info table entry for %d\n", 153 __func__, 154 source); 155 return false; 156 } 157 158 if (info->funcs->ack) 159 return info->funcs->ack(irq_service, info); 160 161 dal_irq_service_ack_generic(irq_service, info); 162 163 return true; 164} 165 166enum dc_irq_source dal_irq_service_to_irq_source( 167 struct irq_service *irq_service, 168 uint32_t src_id, 169 uint32_t ext_id) 170{ 171 return irq_service->funcs->to_dal_irq_source( 172 irq_service, 173 src_id, 174 ext_id); 175} 176