1 /*
2  * Copyright (c) 2020 Travis Geiselbrecht
3  *
4  * Use of this source code is governed by a MIT-style
5  * license that can be found in the LICENSE file or at
6  * https://opensource.org/licenses/MIT
7  */
8 #include <lk/err.h>
9 #include <lk/reg.h>
10 #include <lk/trace.h>
11 #include <kernel/thread.h>
12 #include <platform.h>
13 #include <platform/interrupts.h>
14 #include <platform/debug.h>
15 #include <platform/sifive.h>
16 #include <sys/types.h>
17 #include <dev/gpio.h>
18 
19 #include "platform_p.h"
20 
21 static volatile unsigned int *const gpio_base = (unsigned int *)GPIO_BASE;
22 
23 #define GPIO_REG_VALUE      0
24 #define GPIO_REG_INPUT_EN   1
25 #define GPIO_REG_OUTPUT_EN  2
26 #define GPIO_REG_PORT       3
27 #define GPIO_REG_PUE        4
28 #define GPIO_REG_DS         5
29 #define GPIO_REG_RISE_IE    6
30 #define GPIO_REG_RISE_IP    7
31 #define GPIO_REG_FALL_IE    8
32 #define GPIO_REG_FALL_IP    9
33 #define GPIO_REG_HIGH_IE    10
34 #define GPIO_REG_HIGH_IP    11
35 #define GPIO_REG_LOW_IE     12
36 #define GPIO_REG_LOW_IP     13
37 #define GPIO_REG_IOF_EN     14
38 #define GPIO_REG_IOF_SEL    15
39 
gpio_early_init(void)40 void gpio_early_init(void) {}
gpio_init(void)41 void gpio_init(void) {}
42 
43 __ALWAYS_INLINE
gpio_reg_bit_set(unsigned int reg,unsigned nr,bool set)44 static inline void gpio_reg_bit_set(unsigned int reg, unsigned nr, bool set) {
45     if (set) {
46         __atomic_fetch_or(&gpio_base[reg], (1U << nr), __ATOMIC_RELAXED);
47     } else {
48         __atomic_fetch_and(&gpio_base[reg], ~(1U << nr), __ATOMIC_RELAXED);
49     }
50 }
51 
gpio_config(unsigned nr,unsigned flags)52 int gpio_config(unsigned nr, unsigned flags) {
53     if (nr >= 32) {
54         return ERR_INVALID_ARGS;
55     }
56 
57 #if PLATFORM_SIFIVE_E
58     // the alternate function feature only exists on the embedded variant
59     if (flags & GPIO_AF0) { // alternate function 0
60         gpio_reg_bit_set(GPIO_REG_IOF_SEL, nr, 0);
61         gpio_reg_bit_set(GPIO_REG_IOF_EN, nr, 1);
62     } else if (flags & GPIO_AF0) { // alternate function 1
63         gpio_reg_bit_set(GPIO_REG_IOF_SEL, nr, 1);
64         gpio_reg_bit_set(GPIO_REG_IOF_EN, nr, 1);
65     } else
66 #endif // PLATFORM_SIFIVE_E
67     {
68         if (flags & GPIO_INPUT) {
69             gpio_reg_bit_set(GPIO_REG_INPUT_EN, nr, 1);
70         }
71         if (flags & GPIO_OUTPUT) {
72             gpio_reg_bit_set(GPIO_REG_OUTPUT_EN, nr, 1);
73         }
74         if (flags & GPIO_PULLUP) {
75             gpio_reg_bit_set(GPIO_REG_PUE, nr, 1);
76         } else {
77             gpio_reg_bit_set(GPIO_REG_PUE, nr, 0);
78         }
79 
80 #if PLATFORM_SIFIVE_E
81         // clear the alternate function
82         gpio_reg_bit_set(GPIO_REG_IOF_EN, nr, 0);
83 #endif // PLATFORM_SIFIVE_E
84     }
85 
86     return 0;
87 }
88 
gpio_set(unsigned nr,unsigned on)89 void gpio_set(unsigned nr, unsigned on) {
90     if (nr >= 32) {
91         return;
92     }
93 
94     // set and clear the LED gpios using atomic instructions
95     // polarity is inverted
96     if (on) {
97         gpio_reg_bit_set(GPIO_REG_PORT, nr, 0);
98     } else {
99         gpio_reg_bit_set(GPIO_REG_PORT, nr, 1);
100     }
101 }
102 
gpio_get(unsigned nr)103 int gpio_get(unsigned nr) {
104     if (nr >= 32) {
105         return ERR_INVALID_ARGS;
106     }
107 
108     unsigned int val = gpio_base[GPIO_REG_VALUE] & (1U << nr);
109     return val ? 1 : 0;
110 }
111 
112