1 /* $NetBSD: amdgpu_gpio_base.c,v 1.2 2021/12/18 23:45:04 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 /*
29 * Pre-requisites: headers required by header of this unit
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: amdgpu_gpio_base.c,v 1.2 2021/12/18 23:45:04 riastradh Exp $");
34
35 #include <linux/slab.h>
36
37 #include "dm_services.h"
38
39 #include "include/gpio_interface.h"
40 #include "include/gpio_service_interface.h"
41 #include "hw_gpio.h"
42 #include "hw_translate.h"
43 #include "hw_factory.h"
44 #include "gpio_service.h"
45
46 /*
47 * Post-requisites: headers required by this unit
48 */
49
50 /*
51 * This unit
52 */
53
54 /*
55 * @brief
56 * Public API
57 */
58
dal_gpio_open(struct gpio * gpio,enum gpio_mode mode)59 enum gpio_result dal_gpio_open(
60 struct gpio *gpio,
61 enum gpio_mode mode)
62 {
63 return dal_gpio_open_ex(gpio, mode);
64 }
65
dal_gpio_open_ex(struct gpio * gpio,enum gpio_mode mode)66 enum gpio_result dal_gpio_open_ex(
67 struct gpio *gpio,
68 enum gpio_mode mode)
69 {
70 if (gpio->pin) {
71 ASSERT_CRITICAL(false);
72 return GPIO_RESULT_ALREADY_OPENED;
73 }
74
75 // No action if allocation failed during gpio construct
76 if (!gpio->hw_container.ddc) {
77 ASSERT_CRITICAL(false);
78 return GPIO_RESULT_NON_SPECIFIC_ERROR;
79 }
80 gpio->mode = mode;
81
82 return dal_gpio_service_open(gpio);
83 }
84
dal_gpio_get_value(const struct gpio * gpio,uint32_t * value)85 enum gpio_result dal_gpio_get_value(
86 const struct gpio *gpio,
87 uint32_t *value)
88 {
89 if (!gpio->pin) {
90 BREAK_TO_DEBUGGER();
91 return GPIO_RESULT_NULL_HANDLE;
92 }
93
94 return gpio->pin->funcs->get_value(gpio->pin, value);
95 }
96
dal_gpio_set_value(const struct gpio * gpio,uint32_t value)97 enum gpio_result dal_gpio_set_value(
98 const struct gpio *gpio,
99 uint32_t value)
100 {
101 if (!gpio->pin) {
102 BREAK_TO_DEBUGGER();
103 return GPIO_RESULT_NULL_HANDLE;
104 }
105
106 return gpio->pin->funcs->set_value(gpio->pin, value);
107 }
108
dal_gpio_get_mode(const struct gpio * gpio)109 enum gpio_mode dal_gpio_get_mode(
110 const struct gpio *gpio)
111 {
112 return gpio->mode;
113 }
114
dal_gpio_lock_pin(struct gpio * gpio)115 enum gpio_result dal_gpio_lock_pin(
116 struct gpio *gpio)
117 {
118 return dal_gpio_service_lock(gpio->service, gpio->id, gpio->en);
119 }
120
dal_gpio_unlock_pin(struct gpio * gpio)121 enum gpio_result dal_gpio_unlock_pin(
122 struct gpio *gpio)
123 {
124 return dal_gpio_service_unlock(gpio->service, gpio->id, gpio->en);
125 }
126
dal_gpio_change_mode(struct gpio * gpio,enum gpio_mode mode)127 enum gpio_result dal_gpio_change_mode(
128 struct gpio *gpio,
129 enum gpio_mode mode)
130 {
131 if (!gpio->pin) {
132 BREAK_TO_DEBUGGER();
133 return GPIO_RESULT_NULL_HANDLE;
134 }
135
136 return gpio->pin->funcs->change_mode(gpio->pin, mode);
137 }
138
dal_gpio_get_id(const struct gpio * gpio)139 enum gpio_id dal_gpio_get_id(
140 const struct gpio *gpio)
141 {
142 return gpio->id;
143 }
144
dal_gpio_get_enum(const struct gpio * gpio)145 uint32_t dal_gpio_get_enum(
146 const struct gpio *gpio)
147 {
148 return gpio->en;
149 }
150
dal_gpio_set_config(struct gpio * gpio,const struct gpio_config_data * config_data)151 enum gpio_result dal_gpio_set_config(
152 struct gpio *gpio,
153 const struct gpio_config_data *config_data)
154 {
155 if (!gpio->pin) {
156 BREAK_TO_DEBUGGER();
157 return GPIO_RESULT_NULL_HANDLE;
158 }
159
160 return gpio->pin->funcs->set_config(gpio->pin, config_data);
161 }
162
dal_gpio_get_pin_info(const struct gpio * gpio,struct gpio_pin_info * pin_info)163 enum gpio_result dal_gpio_get_pin_info(
164 const struct gpio *gpio,
165 struct gpio_pin_info *pin_info)
166 {
167 return gpio->service->translate.funcs->id_to_offset(
168 gpio->id, gpio->en, pin_info) ?
169 GPIO_RESULT_OK : GPIO_RESULT_INVALID_DATA;
170 }
171
dal_gpio_get_sync_source(const struct gpio * gpio)172 enum sync_source dal_gpio_get_sync_source(
173 const struct gpio *gpio)
174 {
175 switch (gpio->id) {
176 case GPIO_ID_GENERIC:
177 switch (gpio->en) {
178 case GPIO_GENERIC_A:
179 return SYNC_SOURCE_IO_GENERIC_A;
180 case GPIO_GENERIC_B:
181 return SYNC_SOURCE_IO_GENERIC_B;
182 case GPIO_GENERIC_C:
183 return SYNC_SOURCE_IO_GENERIC_C;
184 case GPIO_GENERIC_D:
185 return SYNC_SOURCE_IO_GENERIC_D;
186 case GPIO_GENERIC_E:
187 return SYNC_SOURCE_IO_GENERIC_E;
188 case GPIO_GENERIC_F:
189 return SYNC_SOURCE_IO_GENERIC_F;
190 default:
191 return SYNC_SOURCE_NONE;
192 }
193 break;
194 case GPIO_ID_SYNC:
195 switch (gpio->en) {
196 case GPIO_SYNC_HSYNC_A:
197 return SYNC_SOURCE_IO_HSYNC_A;
198 case GPIO_SYNC_VSYNC_A:
199 return SYNC_SOURCE_IO_VSYNC_A;
200 case GPIO_SYNC_HSYNC_B:
201 return SYNC_SOURCE_IO_HSYNC_B;
202 case GPIO_SYNC_VSYNC_B:
203 return SYNC_SOURCE_IO_VSYNC_B;
204 default:
205 return SYNC_SOURCE_NONE;
206 }
207 break;
208 case GPIO_ID_HPD:
209 switch (gpio->en) {
210 case GPIO_HPD_1:
211 return SYNC_SOURCE_IO_HPD1;
212 case GPIO_HPD_2:
213 return SYNC_SOURCE_IO_HPD2;
214 default:
215 return SYNC_SOURCE_NONE;
216 }
217 break;
218 case GPIO_ID_GSL:
219 switch (gpio->en) {
220 case GPIO_GSL_GENLOCK_CLOCK:
221 return SYNC_SOURCE_GSL_IO_GENLOCK_CLOCK;
222 case GPIO_GSL_GENLOCK_VSYNC:
223 return SYNC_SOURCE_GSL_IO_GENLOCK_VSYNC;
224 case GPIO_GSL_SWAPLOCK_A:
225 return SYNC_SOURCE_GSL_IO_SWAPLOCK_A;
226 case GPIO_GSL_SWAPLOCK_B:
227 return SYNC_SOURCE_GSL_IO_SWAPLOCK_B;
228 default:
229 return SYNC_SOURCE_NONE;
230 }
231 break;
232 default:
233 return SYNC_SOURCE_NONE;
234 }
235 }
236
dal_gpio_get_output_state(const struct gpio * gpio)237 enum gpio_pin_output_state dal_gpio_get_output_state(
238 const struct gpio *gpio)
239 {
240 return gpio->output_state;
241 }
242
dal_gpio_get_ddc(struct gpio * gpio)243 struct hw_ddc *dal_gpio_get_ddc(struct gpio *gpio)
244 {
245 return gpio->hw_container.ddc;
246 }
247
dal_gpio_get_hpd(struct gpio * gpio)248 struct hw_hpd *dal_gpio_get_hpd(struct gpio *gpio)
249 {
250 return gpio->hw_container.hpd;
251 }
252
dal_gpio_get_generic(struct gpio * gpio)253 struct hw_generic *dal_gpio_get_generic(struct gpio *gpio)
254 {
255 return gpio->hw_container.generic;
256 }
257
dal_gpio_close(struct gpio * gpio)258 void dal_gpio_close(
259 struct gpio *gpio)
260 {
261 if (!gpio)
262 return;
263
264 dal_gpio_service_close(gpio->service, &gpio->pin);
265
266 gpio->mode = GPIO_MODE_UNKNOWN;
267 }
268
269 /*
270 * @brief
271 * Creation and destruction
272 */
273
dal_gpio_create(struct gpio_service * service,enum gpio_id id,uint32_t en,enum gpio_pin_output_state output_state)274 struct gpio *dal_gpio_create(
275 struct gpio_service *service,
276 enum gpio_id id,
277 uint32_t en,
278 enum gpio_pin_output_state output_state)
279 {
280 struct gpio *gpio = kzalloc(sizeof(struct gpio), GFP_KERNEL);
281
282 if (!gpio) {
283 ASSERT_CRITICAL(false);
284 return NULL;
285 }
286
287 gpio->service = service;
288 gpio->pin = NULL;
289 gpio->id = id;
290 gpio->en = en;
291 gpio->mode = GPIO_MODE_UNKNOWN;
292 gpio->output_state = output_state;
293
294 //initialize hw_container union based on id
295 switch (gpio->id) {
296 case GPIO_ID_DDC_DATA:
297 gpio->service->factory.funcs->init_ddc_data(&gpio->hw_container.ddc, service->ctx, id, en);
298 break;
299 case GPIO_ID_DDC_CLOCK:
300 gpio->service->factory.funcs->init_ddc_data(&gpio->hw_container.ddc, service->ctx, id, en);
301 break;
302 case GPIO_ID_GENERIC:
303 gpio->service->factory.funcs->init_generic(&gpio->hw_container.generic, service->ctx, id, en);
304 break;
305 case GPIO_ID_HPD:
306 gpio->service->factory.funcs->init_hpd(&gpio->hw_container.hpd, service->ctx, id, en);
307 break;
308 // TODO: currently gpio for sync and gsl does not get created, might need it later
309 case GPIO_ID_SYNC:
310 break;
311 case GPIO_ID_GSL:
312 break;
313 default:
314 ASSERT_CRITICAL(false);
315 gpio->pin = NULL;
316 }
317
318 return gpio;
319 }
320
dal_gpio_destroy(struct gpio ** gpio)321 void dal_gpio_destroy(
322 struct gpio **gpio)
323 {
324 if (!gpio || !*gpio) {
325 ASSERT_CRITICAL(false);
326 return;
327 }
328
329 switch ((*gpio)->id) {
330 case GPIO_ID_DDC_DATA:
331 kfree((*gpio)->hw_container.ddc);
332 (*gpio)->hw_container.ddc = NULL;
333 break;
334 case GPIO_ID_DDC_CLOCK:
335 //TODO: might want to change it to init_ddc_clock
336 kfree((*gpio)->hw_container.ddc);
337 (*gpio)->hw_container.ddc = NULL;
338 break;
339 case GPIO_ID_GENERIC:
340 kfree((*gpio)->hw_container.generic);
341 (*gpio)->hw_container.generic = NULL;
342 break;
343 case GPIO_ID_HPD:
344 kfree((*gpio)->hw_container.hpd);
345 (*gpio)->hw_container.hpd = NULL;
346 break;
347 // TODO: currently gpio for sync and gsl does not get created, might need it later
348 case GPIO_ID_SYNC:
349 break;
350 case GPIO_ID_GSL:
351 break;
352 default:
353 break;
354 }
355
356 kfree(*gpio);
357
358 *gpio = NULL;
359 }
360