1 /*
2  * Copyright (c) 2012 Travis Geiselbrecht
3  * Copyright (c) 2016 Erik Gilling
4  *
5  * Use of this source code is governed by a MIT-style
6  * license that can be found in the LICENSE file or at
7  * https://opensource.org/licenses/MIT
8  */
9 
10 #include <assert.h>
11 #include <lk/debug.h>
12 #include <dev/gpio.h>
13 #include <platform/gpio.h>
14 #include <platform/rcc.h>
15 #include <platform/stm32.h>
16 #include <stm32f0xx.h>
17 
18 typedef GPIO_TypeDef stm32_gpio_t;
19 
20 typedef enum {
21     STM32_GPIO_SPEED_2_MHZ  = 0x0,
22     STM32_GPIO_SPEED_20_MHZ = 0x1,
23     STM32_GPIO_SPEED_50_MHZ = 0x3,
24 } stm32_goio_speed_t;
25 
26 typedef enum {
27     STM32_GPIO_OTYPE_PP = 0x0,
28     STM32_GPIO_OTYPE_OD = 0x1,
29 } stm32_gpio_otype_t;
30 
31 typedef enum {
32     STM32_GPIO_MODE_IN  = 0x0,
33     STM32_GPIO_MODE_OUT = 0x1,
34     STM32_GPIO_MODE_AF  = 0x2,
35     STM32_GPIO_MODE_AN  = 0x3,
36 } stm32_gpio_mode_t;
37 
38 typedef enum {
39     STM32_GPIO_PUPD_NONE = 0x0,
40     STM32_GPIO_PUPD_UP   = 0x1,
41     STM32_GPIO_PUPD_DOWN = 0x2,
42 } stm32_gpio_pupd_t;
43 
stm32_gpio_port_to_pointer(unsigned int port)44 static stm32_gpio_t *stm32_gpio_port_to_pointer(unsigned int port) {
45     switch (port) {
46         default:
47 #ifdef GPIOA
48         case GPIO_PORT_A:
49             return GPIOA;
50 #endif
51 #ifdef GPIOB
52         case GPIO_PORT_B:
53             return GPIOB;
54 #endif
55 #ifdef GPIOC
56         case GPIO_PORT_C:
57             return GPIOC;
58 #endif
59 #ifdef GPIOD
60         case GPIO_PORT_D:
61             return GPIOD;
62 #endif
63 #ifdef GPIOE
64         case GPIO_PORT_E:
65             return GPIOE;
66 #endif
67 #ifdef GPIOF
68         case GPIO_PORT_F:
69             return GPIOF;
70 #endif
71     }
72 }
73 
stm32_gpio_enable_port(unsigned int port)74 static void stm32_gpio_enable_port(unsigned int port) {
75     DEBUG_ASSERT(port <= GPIO_PORT_F);
76 
77     switch (port) {
78         default:
79 #ifdef GPIOA
80         case GPIO_PORT_A:
81             stm32_rcc_set_enable(STM32_RCC_CLK_IOPA, true);
82             break;
83 #endif
84 #ifdef GPIOB
85         case GPIO_PORT_B:
86             stm32_rcc_set_enable(STM32_RCC_CLK_IOPB, true);
87             break;
88 #endif
89 #ifdef GPIOC
90         case GPIO_PORT_C:
91             stm32_rcc_set_enable(STM32_RCC_CLK_IOPC, true);
92             break;
93 #endif
94 #ifdef GPIOD
95         case GPIO_PORT_D:
96             stm32_rcc_set_enable(STM32_RCC_CLK_IOPD, true);
97             break;
98 #endif
99 #ifdef GPIOE
100         case GPIO_PORT_E:
101             stm32_rcc_set_enable(STM32_RCC_CLK_IOPE, true);
102             break;
103 #endif
104 #ifdef GPIOF
105         case GPIO_PORT_F:
106             stm32_rcc_set_enable(STM32_RCC_CLK_IOPF, true);
107             break;
108 #endif
109     }
110 }
111 
stm32_gpio_early_init(void)112 void stm32_gpio_early_init(void) {
113 }
114 
stm32_gpio_af_config(stm32_gpio_t * gpio,uint32_t pin,uint32_t af_num)115 static void stm32_gpio_af_config(stm32_gpio_t *gpio, uint32_t pin,
116                                  uint32_t af_num) {
117     // 8 AF entries per register
118     uint32_t reg_index = pin >> 3;
119     uint32_t entry_shift = (pin & 0x7) * 4;
120 
121     gpio->AFR[reg_index] &= ~(0xf << entry_shift);
122     gpio->AFR[reg_index] |= (af_num & 0xf) << entry_shift;
123 }
124 
gpio_config(unsigned nr,unsigned flags)125 int gpio_config(unsigned nr, unsigned flags) {
126     uint32_t port = GPIO_PORT(nr);
127     uint32_t pin = GPIO_PIN(nr);
128     stm32_gpio_t *gpio = stm32_gpio_port_to_pointer(port);
129 
130     assert(pin < 16);
131 
132     stm32_gpio_enable_port(port);
133 
134     if (flags & GPIO_STM32_AF) {
135         stm32_gpio_af_config(gpio, pin, GPIO_AFNUM(flags));
136     }
137 
138     if ((flags & GPIO_OUTPUT) || (flags & GPIO_STM32_AF)) {
139         // All pins configured to 50MHz.
140         gpio->OSPEEDR &= ~(GPIO_OSPEEDER_OSPEEDR0 << (pin * 2));
141         gpio->OSPEEDR |= STM32_GPIO_SPEED_50_MHZ << (pin * 2);
142 
143         // Output mode configuration
144         gpio->OTYPER &= ~((GPIO_OTYPER_OT_0) << pin);
145         if (flags & GPIO_STM32_OD) {
146             gpio->OTYPER |= STM32_GPIO_OTYPE_OD << pin;
147         } else {
148             gpio->OTYPER |= STM32_GPIO_OTYPE_PP << pin;
149         }
150     }
151 
152     stm32_gpio_mode_t mode;
153     if (flags & GPIO_OUTPUT) {
154         mode = STM32_GPIO_MODE_OUT;
155     } else if (flags & GPIO_STM32_AF) {
156         mode = STM32_GPIO_MODE_AF;
157     } else {
158         mode = STM32_GPIO_MODE_IN;
159     }
160 
161     gpio->MODER  &= ~(GPIO_MODER_MODER0 << (pin * 2));
162     gpio->MODER |= (mode << (pin * 2));
163 
164     stm32_gpio_pupd_t pupd = STM32_GPIO_PUPD_NONE;
165     if (flags & GPIO_PULLUP) {
166         pupd = STM32_GPIO_PUPD_UP;
167     } else if (flags & GPIO_PULLDOWN) {
168         pupd = STM32_GPIO_PUPD_DOWN;
169     }
170 
171     gpio->PUPDR &= ~(GPIO_PUPDR_PUPDR0 << (pin * 2));
172     gpio->PUPDR |= pupd << (pin * 2);
173 
174     return 0;
175 }
176 
gpio_set(unsigned nr,unsigned on)177 void gpio_set(unsigned nr, unsigned on) {
178     stm32_gpio_t *gpio = stm32_gpio_port_to_pointer(GPIO_PORT(nr));
179     if (on) {
180         gpio->BSRR = 1 << GPIO_PIN(nr);
181     } else {
182         gpio->BRR = 1 << GPIO_PIN(nr);
183     }
184 }
185 
gpio_get(unsigned nr)186 int gpio_get(unsigned nr) {
187     stm32_gpio_t *gpio = stm32_gpio_port_to_pointer(GPIO_PORT(nr));
188     return (gpio->IDR & (1 << GPIO_PIN(nr))) != 0;
189 }
190 
191