1 /*
2 * Copyright (c) 2020-2022 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "device_resource_if.h"
17 #include "gpio/gpio_core.h"
18 #ifdef PL061_GPIO_USER_SUPPORT
19 #include "gpio_dev.h"
20 #endif
21 #include "hdf_device_desc.h"
22 #include "hdf_log.h"
23 #include "osal_io.h"
24 #include "osal_irq.h"
25 #include "osal_mem.h"
26 #include "osal_spinlock.h"
27 #include "platform_dumper.h"
28
29 #define HDF_LOG_TAG gpio_hi35xx
30 #define PL061_GROUP_MAX 32
31 #define PL061_BIT_MAX 16
32 #define GPIO_MAX_INFO_NUM 96
33
34 #define GPIO_DUMPER_NAME_PREFIX "gpio_dumper_"
35 #define GPIO_DUMPER_NAME_LEN 64
36 #define GPIO_DUMPER_DATAS_REGISTER_SIZE 10
37
38 #define PL061_GPIO_DATA_ALL(base) ((base) + 0x3FC)
39 #define PL061_GPIO_DATA(base, bit) ((base) + 0x000 + (1 << ((bit) + 2)))
40 #define PL061_GPIO_DIR(base) ((base) + 0x400)
41 #define PL061_GPIO_IS(base) ((base) + 0x404)
42 #define PL061_GPIO_IBE(base) ((base) + 0x408)
43 #define PL061_GPIO_IEV(base) ((base) + 0x40C)
44 #define PL061_GPIO_IE(base) ((base) + 0x410)
45 #define PL061_GPIO_RIS(base) ((base) + 0x414)
46 #define PL061_GPIO_MIS(base) ((base) + 0x418)
47 #define PL061_GPIO_IC(base) ((base) + 0x41C)
48
49 struct Pl061GpioGroup {
50 struct GpioCntlr cntlr;
51 volatile unsigned char *regBase;
52 unsigned int index;
53 unsigned int irq;
54 OsalIRQHandle irqFunc;
55 OsalSpinlock lock;
56 uint32_t irqSave;
57 bool irqShare;
58 struct PlatformDumper *dumper;
59 char *dumperName;
60 };
61
62 struct Pl061GpioData {
63 volatile unsigned char *regBase;
64 uint32_t phyBase;
65 uint32_t regStep;
66 uint32_t irqStart;
67 uint16_t groupNum;
68 uint16_t bitNum;
69 uint8_t irqShare;
70 struct Pl061GpioGroup *groups;
71 struct GpioInfo *gpioInfo;
72 void *priv;
73 };
74
75 static struct Pl061GpioData g_pl061 = {
76 .groups = NULL,
77 .groupNum = PL061_GROUP_MAX,
78 .bitNum = PL061_BIT_MAX,
79 };
80
GpioDumperCreate(struct Pl061GpioGroup * group)81 static int32_t GpioDumperCreate(struct Pl061GpioGroup *group)
82 {
83 struct PlatformDumper *dumper = NULL;
84 char *name = NULL;
85
86 name = (char *)OsalMemCalloc(GPIO_DUMPER_NAME_LEN);
87 if (name == NULL) {
88 HDF_LOGE("%s: alloc name fail", __func__);
89 return HDF_ERR_MALLOC_FAIL;
90 }
91
92 if (snprintf_s(name, GPIO_DUMPER_NAME_LEN, GPIO_DUMPER_NAME_LEN - 1, "%s%d",
93 GPIO_DUMPER_NAME_PREFIX, group->index) < 0) {
94 HDF_LOGE("%s: snprintf_s name fail!", __func__);
95 OsalMemFree(name);
96 return HDF_ERR_IO;
97 }
98 dumper = PlatformDumperCreate(name);
99 if (dumper == NULL) {
100 HDF_LOGE("%s: get dumper for %s fail!", __func__, name);
101 OsalMemFree(name);
102 return HDF_ERR_IO;
103 }
104 group->dumper = dumper;
105 group->dumperName = name;
106
107 return HDF_SUCCESS;
108 }
109
GpioDumperDump(struct Pl061GpioGroup * group)110 static void GpioDumperDump(struct Pl061GpioGroup *group)
111 {
112 int32_t ret;
113 struct PlatformDumperData datas[] = {
114 {"PL061_GPIO_DIR", PLATFORM_DUMPER_REGISTERB, (void *)(PL061_GPIO_DIR(group->regBase))},
115 {"PL061_GPIO_IS", PLATFORM_DUMPER_REGISTERB, (void *)(PL061_GPIO_IS(group->regBase))},
116 {"PL061_GPIO_IBE", PLATFORM_DUMPER_REGISTERB, (void *)(PL061_GPIO_IBE(group->regBase))},
117 {"PL061_GPIO_IEV", PLATFORM_DUMPER_REGISTERB, (void *)(PL061_GPIO_IEV(group->regBase))},
118 {"PL061_GPIO_IE", PLATFORM_DUMPER_REGISTERB, (void *)(PL061_GPIO_IE(group->regBase))},
119 {"PL061_GPIO_RIS", PLATFORM_DUMPER_REGISTERB, (void *)(PL061_GPIO_RIS(group->regBase))},
120 {"PL061_GPIO_MIS", PLATFORM_DUMPER_REGISTERB, (void *)(PL061_GPIO_MIS(group->regBase))},
121 {"PL061_GPIO_IC", PLATFORM_DUMPER_REGISTERB, (void *)(PL061_GPIO_IC(group->regBase))},
122 };
123
124 if (group->dumper == NULL) {
125 HDF_LOGE("%s: group dumper is NULL!", __func__);
126 return;
127 }
128 ret = PlatformDumperAddDatas(group->dumper, datas, sizeof(datas) / sizeof(struct PlatformDumperData));
129 if (ret != HDF_SUCCESS) {
130 return;
131 }
132 (void)PlatformDumperDump(group->dumper);
133 (void)PlatformDumperClearDatas(group->dumper);
134 }
135
GpioDumperDestroy(struct Pl061GpioGroup * group)136 static inline void GpioDumperDestroy(struct Pl061GpioGroup *group)
137 {
138 PlatformDumperDestroy(group->dumper);
139 OsalMemFree(group->dumperName);
140 }
141
Pl061GpioSetDir(struct GpioCntlr * cntlr,uint16_t local,uint16_t dir)142 static int32_t Pl061GpioSetDir(struct GpioCntlr *cntlr, uint16_t local, uint16_t dir)
143 {
144 unsigned int val;
145 volatile unsigned char *addr = NULL;
146 unsigned int bitNum = local;
147 struct Pl061GpioGroup *group = (struct Pl061GpioGroup *)cntlr;
148
149 HDF_LOGV("%s: local:%hu, dir:%hu", __func__, local, dir);
150
151 if (OsalSpinLockIrqSave(&group->lock, &group->irqSave) != HDF_SUCCESS) {
152 return HDF_ERR_DEVICE_BUSY;
153 }
154 addr = PL061_GPIO_DIR(group->regBase);
155 val = OSAL_READL(addr);
156 if (dir == GPIO_DIR_IN) {
157 val &= ~(1 << bitNum);
158 } else if (dir == GPIO_DIR_OUT) {
159 val |= 1 << bitNum;
160 }
161 OSAL_WRITEL(val, addr);
162 (void)OsalSpinUnlockIrqRestore(&group->lock, &group->irqSave);
163
164 return HDF_SUCCESS;
165 }
166
Pl061GpioGetDir(struct GpioCntlr * cntlr,uint16_t local,uint16_t * dir)167 static int32_t Pl061GpioGetDir(struct GpioCntlr *cntlr, uint16_t local, uint16_t *dir)
168 {
169 unsigned int val;
170 volatile unsigned char *addr = NULL;
171 unsigned int bitNum = local;
172 struct Pl061GpioGroup *group = (struct Pl061GpioGroup *)cntlr;
173
174 HDF_LOGV("%s: local:%hu", __func__, local);
175
176 addr = PL061_GPIO_DIR(group->regBase);
177 val = OSAL_READL(addr);
178 if (val & (1 << bitNum)) {
179 *dir = GPIO_DIR_OUT;
180 } else {
181 *dir = GPIO_DIR_IN;
182 }
183 return HDF_SUCCESS;
184 }
185
Pl061GpioWrite(struct GpioCntlr * cntlr,uint16_t local,uint16_t val)186 static int32_t Pl061GpioWrite(struct GpioCntlr *cntlr, uint16_t local, uint16_t val)
187 {
188 unsigned int valCur;
189 volatile unsigned char *addr = NULL;
190 unsigned int bitNum = local;
191 struct Pl061GpioGroup *group = (struct Pl061GpioGroup *)cntlr;
192
193 if (OsalSpinLockIrqSave(&group->lock, &group->irqSave) != HDF_SUCCESS) {
194 return HDF_ERR_DEVICE_BUSY;
195 }
196 addr = PL061_GPIO_DATA(group->regBase, bitNum);
197 valCur = OSAL_READL(addr);
198 if (val == GPIO_VAL_LOW) {
199 valCur &= ~(1 << bitNum);
200 } else {
201 valCur |= (1 << bitNum);
202 }
203 OSAL_WRITEL(valCur, addr);
204 (void)OsalSpinUnlockIrqRestore(&group->lock, &group->irqSave);
205
206 return HDF_SUCCESS;
207 }
208
Pl061GpioRead(struct GpioCntlr * cntlr,uint16_t local,uint16_t * val)209 static int32_t Pl061GpioRead(struct GpioCntlr *cntlr, uint16_t local, uint16_t *val)
210 {
211 unsigned int valCur;
212 volatile unsigned char *addr = NULL;
213 unsigned int bitNum = local;
214 struct Pl061GpioGroup *group = (struct Pl061GpioGroup *)cntlr;
215
216 addr = PL061_GPIO_DATA(group->regBase, bitNum);
217 valCur = OSAL_READL(addr);
218 if (valCur & (1 << bitNum)) {
219 *val = GPIO_VAL_HIGH;
220 } else {
221 *val = GPIO_VAL_LOW;
222 }
223 return HDF_SUCCESS;
224 }
225
Pl061IrqHandleShare(uint32_t irq,void * data)226 static uint32_t Pl061IrqHandleShare(uint32_t irq, void *data)
227 {
228 (void)irq;
229 (void)data;
230 return HDF_SUCCESS;
231 }
232
Pl061IrqHandleNoShare(uint32_t irq,void * data)233 static uint32_t Pl061IrqHandleNoShare(uint32_t irq, void *data)
234 {
235 unsigned int i;
236 unsigned int val;
237 struct Pl061GpioGroup *group = (struct Pl061GpioGroup *)data;
238
239 if (data == NULL) {
240 HDF_LOGW("%s: data is NULL!", __func__);
241 return HDF_ERR_INVALID_PARAM;
242 }
243 val = OSAL_READL(PL061_GPIO_MIS(group->regBase));
244 OSAL_WRITEL(val, PL061_GPIO_IC(group->regBase));
245 if (val == 0) {
246 HDF_LOGW("%s: share irq(%u) trigerred but not hit any, mis=%x", __func__, irq, val);
247 GpioDumperDump(group);
248 return HDF_FAILURE;
249 }
250 for (i = 0; i < group->cntlr.count && val != 0; i++, val >>= 1) {
251 if ((val & 0x1) != 0) {
252 GpioCntlrIrqCallback(&group->cntlr, i);
253 }
254 }
255 return HDF_SUCCESS;
256 }
257
Pl061GpioRegisterGroupIrqUnsafe(struct Pl061GpioGroup * group)258 static int32_t Pl061GpioRegisterGroupIrqUnsafe(struct Pl061GpioGroup *group)
259 {
260 int ret;
261 if (group->irqShare == 1) {
262 ret = OsalRegisterIrq(group->irq, 0, Pl061IrqHandleShare, "GPIO", NULL);
263 if (ret != 0) {
264 HDF_LOGE("%s: share irq:%u reg fail:%d!", __func__, group->irq, ret);
265 return HDF_FAILURE;
266 }
267 group->irqFunc = Pl061IrqHandleShare;
268 } else {
269 ret = OsalRegisterIrq(group->irq, 0, Pl061IrqHandleNoShare, "GPIO", group);
270 if (ret != 0) {
271 (void)OsalUnregisterIrq(group->irq, group);
272 ret = OsalRegisterIrq(group->irq, 0, Pl061IrqHandleNoShare, "GPIO", group);
273 }
274 if (ret != 0) {
275 HDF_LOGE("%s: noshare irq:%u reg fail:%d!", __func__, group->irq, ret);
276 GpioDumperDump(group);
277 return HDF_FAILURE;
278 }
279 ret = OsalEnableIrq(group->irq);
280 if (ret != 0) {
281 HDF_LOGE("%s: noshare irq:%u enable fail:%d!", __func__, group->irq, ret);
282 (void)OsalUnregisterIrq(group->irq, group);
283 GpioDumperDump(group);
284 return HDF_FAILURE;
285 }
286 group->irqFunc = Pl061IrqHandleNoShare;
287 }
288
289 return HDF_SUCCESS;
290 }
291
Pl061GpioClearIrqUnsafe(struct Pl061GpioGroup * group,uint16_t bitNum)292 static void Pl061GpioClearIrqUnsafe(struct Pl061GpioGroup *group, uint16_t bitNum)
293 {
294 unsigned int val;
295
296 val = OSAL_READL(PL061_GPIO_IC(group->regBase));
297 val |= 1 << bitNum;
298 OSAL_WRITEL(val, PL061_GPIO_IC(group->regBase));
299 }
300
Pl061GpioSetIrqEnableUnsafe(struct Pl061GpioGroup * group,uint16_t bitNum,int flag)301 static void Pl061GpioSetIrqEnableUnsafe(struct Pl061GpioGroup *group, uint16_t bitNum, int flag)
302 {
303 unsigned int val;
304 volatile unsigned char *addr = NULL;
305
306 addr = PL061_GPIO_IE(group->regBase);
307 val = OSAL_READL(addr);
308 if (flag == 1) {
309 val |= (1 << bitNum);
310 } else {
311 val &= ~(1 << bitNum);
312 }
313 OSAL_WRITEL(val, addr);
314 }
315
Pl061GpioEnableIrq(struct GpioCntlr * cntlr,uint16_t local)316 static int32_t Pl061GpioEnableIrq(struct GpioCntlr *cntlr, uint16_t local)
317 {
318 unsigned int bitNum = local;
319 struct Pl061GpioGroup *group = (struct Pl061GpioGroup *)cntlr;
320
321 if (OsalSpinLockIrqSave(&group->lock, &group->irqSave) != HDF_SUCCESS) {
322 return HDF_ERR_DEVICE_BUSY;
323 }
324 Pl061GpioSetIrqEnableUnsafe(group, bitNum, 1);
325 (void)OsalSpinUnlockIrqRestore(&group->lock, &group->irqSave);
326 return HDF_SUCCESS;
327 }
328
Pl061GpioDisableIrq(struct GpioCntlr * cntlr,uint16_t local)329 static int32_t Pl061GpioDisableIrq(struct GpioCntlr *cntlr, uint16_t local)
330 {
331 unsigned int bitNum = local;
332 struct Pl061GpioGroup *group = (struct Pl061GpioGroup *)cntlr;
333
334 if (OsalSpinLockIrqSave(&group->lock, &group->irqSave) != HDF_SUCCESS) {
335 return HDF_ERR_DEVICE_BUSY;
336 }
337 Pl061GpioSetIrqEnableUnsafe(group, bitNum, 0);
338 (void)OsalSpinUnlockIrqRestore(&group->lock, &group->irqSave);
339 return HDF_SUCCESS;
340 }
341
Pl061GpioSetIrqTypeUnsafe(struct Pl061GpioGroup * group,uint16_t bitNum,uint16_t mode)342 static void Pl061GpioSetIrqTypeUnsafe(struct Pl061GpioGroup *group, uint16_t bitNum, uint16_t mode)
343 {
344 unsigned int gpioIbe;
345 unsigned int gpioIs;
346 unsigned int gpioIev;
347
348 if (mode == 0) {
349 return;
350 }
351
352 gpioIs = OSAL_READL(PL061_GPIO_IS(group->regBase));
353 gpioIev = OSAL_READL(PL061_GPIO_IEV(group->regBase));
354
355 if ((mode & (OSAL_IRQF_TRIGGER_LOW | OSAL_IRQF_TRIGGER_HIGH)) != 0) {
356 gpioIs |= 1 << bitNum;
357 if ((mode & OSAL_IRQF_TRIGGER_HIGH) != 0) {
358 gpioIev |= 1 << bitNum;
359 } else {
360 gpioIev &= ~(1 << bitNum);
361 }
362 } else {
363 gpioIbe = OSAL_READL(PL061_GPIO_IBE(group->regBase));
364 gpioIs &= ~(1 << bitNum);
365 if (((mode & OSAL_IRQF_TRIGGER_RISING) != 0) && ((mode & OSAL_IRQF_TRIGGER_FALLING) != 0)) {
366 gpioIbe |= 1 << bitNum;
367 } else if ((mode & OSAL_IRQF_TRIGGER_RISING) != 0) {
368 gpioIbe &= ~(1 << bitNum);
369 gpioIev |= 1 << bitNum;
370 } else if ((mode & OSAL_IRQF_TRIGGER_FALLING) != 0) {
371 gpioIbe &= ~(1 << bitNum);
372 gpioIev &= ~(1 << bitNum);
373 }
374 OSAL_WRITEL(gpioIbe, PL061_GPIO_IBE(group->regBase));
375 }
376 OSAL_WRITEL(gpioIs, PL061_GPIO_IS(group->regBase));
377 OSAL_WRITEL(gpioIev, PL061_GPIO_IEV(group->regBase));
378 }
379
Pl061GpioSetIrq(struct GpioCntlr * cntlr,uint16_t local,uint16_t mode)380 static int32_t Pl061GpioSetIrq(struct GpioCntlr *cntlr, uint16_t local, uint16_t mode)
381 {
382 int32_t ret;
383 unsigned int bitNum = local;
384 struct Pl061GpioGroup *group = (struct Pl061GpioGroup *)cntlr;
385
386 if (OsalSpinLockIrqSave(&group->lock, &group->irqSave) != HDF_SUCCESS) {
387 return HDF_ERR_DEVICE_BUSY;
388 }
389 Pl061GpioSetIrqTypeUnsafe(group, bitNum, mode);
390 Pl061GpioSetIrqEnableUnsafe(group, bitNum, 0); // disable irq on set
391 Pl061GpioClearIrqUnsafe(group, bitNum); // clear irq on set
392
393 if (group->irqFunc != NULL) {
394 (void)OsalSpinUnlockIrqRestore(&group->lock, &group->irqSave);
395 HDF_LOGI("%s: group irq(%u) already registered!", __func__, group->irq);
396 return HDF_SUCCESS;
397 }
398 ret = Pl061GpioRegisterGroupIrqUnsafe(group);
399 (void)OsalSpinUnlockIrqRestore(&group->lock, &group->irqSave);
400 HDF_LOGI("%s: group irq(%u) registered!", __func__, group->irq);
401 return ret;
402 }
403
Pl061GpioUnsetIrq(struct GpioCntlr * cntlr,uint16_t local)404 static int32_t Pl061GpioUnsetIrq(struct GpioCntlr *cntlr, uint16_t local)
405 {
406 unsigned int bitNum = local;
407 struct Pl061GpioGroup *group = (struct Pl061GpioGroup *)cntlr;
408
409 if (OsalSpinLockIrqSave(&group->lock, &group->irqSave) != HDF_SUCCESS) {
410 return HDF_ERR_DEVICE_BUSY;
411 }
412 Pl061GpioSetIrqEnableUnsafe(group, bitNum, 0); // disable irq when unset
413 Pl061GpioClearIrqUnsafe(group, bitNum); // clear irq when unset
414 (void)OsalSpinUnlockIrqRestore(&group->lock, &group->irqSave);
415 return HDF_SUCCESS;
416 }
417
418 static struct GpioMethod g_method = {
419 .request = NULL,
420 .release = NULL,
421 .write = Pl061GpioWrite,
422 .read = Pl061GpioRead,
423 .setDir = Pl061GpioSetDir,
424 .getDir = Pl061GpioGetDir,
425 .toIrq = NULL,
426 .setIrq = Pl061GpioSetIrq,
427 .unsetIrq = Pl061GpioUnsetIrq,
428 .enableIrq = Pl061GpioEnableIrq,
429 .disableIrq = Pl061GpioDisableIrq,
430 };
431
Pl061GpioInitGroups(struct Pl061GpioData * pl061)432 static int32_t Pl061GpioInitGroups(struct Pl061GpioData *pl061)
433 {
434 int32_t ret;
435 uint16_t i;
436 struct Pl061GpioGroup *groups = NULL;
437
438 if (pl061 == NULL) {
439 return HDF_ERR_INVALID_PARAM;
440 }
441
442 groups = (struct Pl061GpioGroup *)OsalMemCalloc(sizeof(*groups) * pl061->groupNum);
443 if (groups == NULL) {
444 return HDF_ERR_MALLOC_FAIL;
445 }
446 pl061->groups = groups;
447
448 for (i = 0; i < pl061->groupNum; i++) {
449 groups[i].index = i;
450 groups[i].regBase = pl061->regBase + i * pl061->regStep;
451 groups[i].irq = pl061->irqStart + i;
452 groups[i].irqShare = pl061->irqShare;
453 groups[i].cntlr.start = i * pl061->bitNum;
454 groups[i].cntlr.count = pl061->bitNum;
455 groups[i].cntlr.ops = &g_method;
456 groups[i].cntlr.ginfos = &pl061->gpioInfo[i * pl061->bitNum];
457
458 if ((ret = OsalSpinInit(&groups[i].lock)) != HDF_SUCCESS) {
459 goto ERR_EXIT;
460 }
461
462 ret = GpioCntlrAdd(&groups[i].cntlr);
463 if (ret != HDF_SUCCESS) {
464 HDF_LOGE("%s: err add controller(%hu:%hu):%d", __func__,
465 groups[i].cntlr.start, groups[i].cntlr.count, ret);
466 (void)OsalSpinDestroy(&groups[i].lock);
467 goto ERR_EXIT;
468 }
469 ret = GpioDumperCreate(&pl061->groups[i]);
470 if (ret != HDF_SUCCESS) {
471 HDF_LOGE("%s: create dumper failed:%d", __func__, ret);
472 return ret;
473 }
474 }
475
476 return HDF_SUCCESS;
477
478 ERR_EXIT:
479 while (i-- > 0) {
480 GpioCntlrRemove(&groups[i].cntlr);
481 (void)OsalSpinDestroy(&groups[i].lock);
482 }
483 pl061->groups = NULL;
484 OsalMemFree(groups);
485 return ret;
486 }
487
Pl061GpioUninitGroups(struct Pl061GpioData * pl061)488 static void Pl061GpioUninitGroups(struct Pl061GpioData *pl061)
489 {
490 uint16_t i;
491 struct Pl061GpioGroup *group = NULL;
492
493 for (i = 0; i < pl061->groupNum; i++) {
494 group = &pl061->groups[i];
495 GpioDumperDestroy(&pl061->groups[i]);
496 GpioCntlrRemove(&group->cntlr);
497 }
498
499 OsalMemFree(pl061->groups);
500 pl061->groups = NULL;
501 }
502
Pl061GpioReadInfo(struct Pl061GpioData * pl061,const struct DeviceResourceNode * node,struct DeviceResourceIface * drsOps)503 static int32_t Pl061GpioReadInfo(struct Pl061GpioData *pl061, const struct DeviceResourceNode *node,
504 struct DeviceResourceIface *drsOps)
505 {
506 int32_t ret;
507 uint32_t gpioIndex = 0;
508 const struct DeviceResourceNode *childNode = NULL;
509 const char *tempName = NULL;
510
511 DEV_RES_NODE_FOR_EACH_CHILD_NODE(node, childNode) {
512 if (gpioIndex >= GPIO_MAX_INFO_NUM) {
513 break;
514 }
515 ret = drsOps->GetString(childNode, "gpioCustomName", &tempName, "");
516 if (ret != HDF_SUCCESS) {
517 HDF_LOGW("%s: failed to read gpioCustomName!", __func__);
518 }
519 ret = strcpy_s(pl061->gpioInfo[gpioIndex].name, GPIO_NAME_LEN, tempName);
520 if (ret != EOK) {
521 HDF_LOGE("%s: failed to copy name for gpioInfo name:%d", __func__, ret);
522 return HDF_ERR_IO;
523 }
524
525 gpioIndex++;
526 }
527 return HDF_SUCCESS;
528 }
529
Pl061GpioReadDrs(struct Pl061GpioData * pl061,const struct DeviceResourceNode * node)530 static int32_t Pl061GpioReadDrs(struct Pl061GpioData *pl061, const struct DeviceResourceNode *node)
531 {
532 int32_t ret;
533 struct DeviceResourceIface *drsOps = NULL;
534
535 drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
536 if (drsOps == NULL || drsOps->GetUint32 == NULL || drsOps->GetUint16 == NULL ||
537 drsOps->GetUint8 == NULL || drsOps->GetUint8 == NULL || drsOps->GetString == NULL) {
538 HDF_LOGE("%s: invalid drs ops!", __func__);
539 return HDF_FAILURE;
540 }
541
542 ret = drsOps->GetUint32(node, "regBase", &pl061->phyBase, 0);
543 if (ret != HDF_SUCCESS) {
544 HDF_LOGE("%s: failed to read regBase!", __func__);
545 return ret;
546 }
547
548 ret = drsOps->GetUint32(node, "regStep", &pl061->regStep, 0);
549 if (ret != HDF_SUCCESS) {
550 HDF_LOGE("%s: failed to read regStep!", __func__);
551 return ret;
552 }
553
554 ret = drsOps->GetUint16(node, "groupNum", &pl061->groupNum, 0);
555 if (ret != HDF_SUCCESS) {
556 HDF_LOGE("%s: failed to read groupNum!", __func__);
557 return ret;
558 }
559
560 ret = drsOps->GetUint16(node, "bitNum", &pl061->bitNum, 0);
561 if (ret != HDF_SUCCESS) {
562 HDF_LOGE("%s: failed to read bitNum!", __func__);
563 return ret;
564 }
565
566 ret = drsOps->GetUint32(node, "irqStart", &pl061->irqStart, 0);
567 if (ret != HDF_SUCCESS) {
568 HDF_LOGE("%s: failed to read irqStart!", __func__);
569 return ret;
570 }
571
572 ret = drsOps->GetUint8(node, "irqShare", &pl061->irqShare, 0);
573 if (ret != HDF_SUCCESS) {
574 HDF_LOGE("%s: failed to read irqShare!", __func__);
575 return ret;
576 }
577
578 ret = Pl061GpioReadInfo(pl061, node, drsOps);
579 if (ret != HDF_SUCCESS) {
580 HDF_LOGE("%s: failed to read info!", __func__);
581 return ret;
582 }
583
584 return HDF_SUCCESS;
585 }
586
Pl061GpioDebug(const struct Pl061GpioData * pl061)587 static void Pl061GpioDebug(const struct Pl061GpioData *pl061)
588 {
589 #ifdef PL061_GPIO_DEBUG
590 uint16_t i;
591 struct Pl061GpioGroup *group = NULL;
592
593 HDF_LOGI("%s:groupNum:%hu, bitNum:%hu", __func__, pl061->groupNum, pl061->bitNum);
594 for (i = 0; i < pl061->groupNum; i++) {
595 group = &pl061->groups[i];
596 HDF_LOGI("group[%hu]: index:%u, regBase:0x%x, irq:%u(cntlr:%hu:%hu)",
597 i, group->index, group->regBase, group->irq, group->cntlr.start, group->cntlr.count);
598 }
599 #else
600 (void)pl061;
601 #endif
602 }
603
Pl061GpioBind(struct HdfDeviceObject * device)604 static int32_t Pl061GpioBind(struct HdfDeviceObject *device)
605 {
606 (void)device;
607 return HDF_SUCCESS;
608 }
609
Pl061GpioInit(struct HdfDeviceObject * device)610 static int32_t Pl061GpioInit(struct HdfDeviceObject *device)
611 {
612 int32_t ret;
613 struct Pl061GpioData *pl061 = &g_pl061;
614
615 if (device == NULL || device->property == NULL) {
616 HDF_LOGE("%s: device or property null!", __func__);
617 return HDF_ERR_INVALID_OBJECT;
618 }
619
620 pl061->gpioInfo = OsalMemCalloc(sizeof(struct GpioInfo) * GPIO_MAX_INFO_NUM);
621 if (pl061->gpioInfo == NULL) {
622 HDF_LOGE("%s: failed to calloc gpioInfo!", __func__);
623 return HDF_ERR_MALLOC_FAIL;
624 }
625
626 ret = Pl061GpioReadDrs(pl061, device->property);
627 if (ret != HDF_SUCCESS) {
628 HDF_LOGE("%s: failed to read drs:%d", __func__, ret);
629 return ret;
630 }
631
632 if (pl061->groupNum > PL061_GROUP_MAX || pl061->groupNum <= 0 ||
633 pl061->bitNum > PL061_BIT_MAX || pl061->bitNum <= 0) {
634 HDF_LOGE("%s: err groupNum:%hu, bitNum:%hu", __func__, pl061->groupNum, pl061->bitNum);
635 return HDF_ERR_INVALID_PARAM;
636 }
637
638 pl061->regBase = OsalIoRemap(pl061->phyBase, pl061->groupNum * pl061->regStep);
639 if (pl061->regBase == NULL) {
640 HDF_LOGE("%s: err remap phy:0x%x", __func__, pl061->phyBase);
641 return HDF_ERR_IO;
642 }
643
644 ret = Pl061GpioInitGroups(pl061);
645 if (ret != HDF_SUCCESS) {
646 HDF_LOGE("%s: err init groups:%d", __func__, ret);
647 OsalIoUnmap((void *)pl061->regBase);
648 pl061->regBase = NULL;
649 return ret;
650 }
651 pl061->priv = (void *)device->property;
652 device->priv = (void *)pl061;
653 Pl061GpioDebug(pl061);
654
655 #ifdef PL061_GPIO_USER_SUPPORT
656 if (GpioAddVfs(pl061->bitNum) != HDF_SUCCESS) {
657 HDF_LOGE("%s: add vfs fail!", __func__);
658 }
659 #endif
660 HDF_LOGI("%s: dev service:%s init success!", __func__, HdfDeviceGetServiceName(device));
661 return HDF_SUCCESS;
662 }
663
Pl061GpioRelease(struct HdfDeviceObject * device)664 static void Pl061GpioRelease(struct HdfDeviceObject *device)
665 {
666 struct Pl061GpioData *pl061 = NULL;
667
668 HDF_LOGI("%s: enter", __func__);
669 if (device == NULL) {
670 HDF_LOGE("%s: device is null!", __func__);
671 return;
672 }
673
674 #ifdef PL061_GPIO_USER_SUPPORT
675 GpioRemoveVfs();
676 #endif
677
678 pl061 = (struct Pl061GpioData *)device->priv;
679 if (pl061 == NULL) {
680 HDF_LOGE("%s: device priv is null", __func__);
681 return;
682 }
683
684 Pl061GpioUninitGroups(pl061);
685 OsalMemFree(pl061->gpioInfo);
686 pl061->gpioInfo = NULL;
687 OsalIoUnmap((void *)pl061->regBase);
688 pl061->regBase = NULL;
689 }
690
691 struct HdfDriverEntry g_gpioDriverEntry = {
692 .moduleVersion = 1,
693 .Bind = Pl061GpioBind,
694 .Init = Pl061GpioInit,
695 .Release = Pl061GpioRelease,
696 .moduleName = "hisi_pl061_driver",
697 };
698 HDF_INIT(g_gpioDriverEntry);
699