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