1 /*
2 * Copyright (C) 2020 ETH Zurich and University of Bologna
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * SPDX-License-Identifier: Apache-2.0
17 */
18 /* Driver to control and configure the PULP GPIO pins */
19 /* Author: Robert Balas (balasr@iis.ee.ethz.ch)
20 */
21
22 #include <stdint.h>
23 #include <assert.h>
24 #include <hal_gpio_pulp.h>
25 #include <hal_pinmux1.h>
26 #include <bits.h>
27 #include <pulp_io.h>
28 #include "core-v-mcu-pulp-mem-map.h"
29
gpio_pin_conf_pad(int pin,uint32_t flags)30 int gpio_pin_conf_pad(int pin, uint32_t flags)
31 {
32 assert(0 <= pin && pin < 32);
33
34 /* this is only correct if the static assert in gpio.h regarding padcfg*
35 * registers doesn't fail
36 */
37 uintptr_t pad_conf_reg =
38 (((uintptr_t)pin & 0xf) >> 3) * 4 +
39 (uintptr_t)(PULP_GPIO_ADDR + GPIO_PADCFG0_OFFSET);
40 uint32_t pad_shift = (pin & 0x3) << 3; /* (0,1) (8,9) (16,17) (24,25) */
41 uint32_t val = (flags & GPIO_PULL_ENABLE) |
42 (flags & GPIO_DRIVE_STRENGTH_HIGH) << 1;
43
44 writew(val << pad_shift, pad_conf_reg);
45
46 return 0;
47 }
48
49 /* for now we only handle the gpio from 0-31 and ignore 32-63 */
gpio_pin_configure(int pin,uint32_t flags)50 int gpio_pin_configure(int pin, uint32_t flags)
51 {
52 /* check for misconfigurations */
53 assert(!((flags & GPIO_INPUT) && (flags & GPIO_OUTPUT)));
54
55 /* set pad mux to gpio */
56 pinmux_pin_set(pin, PINMUX_FUNC_B);
57
58 /* configure pad pull and drive */
59 gpio_pin_conf_pad(pin, flags);
60
61 /* configure direction */
62 uint32_t pads = readw((uintptr_t)(PULP_GPIO_ADDR + GPIO_PADDIR_OFFSET));
63 WRITE_BIT(pads, pin, flags & GPIO_OUTPUT);
64 writew(pads, (uintptr_t)(PULP_GPIO_ADDR + GPIO_PADDIR_OFFSET));
65
66 /* default value to prevent glitches */
67 if (flags & GPIO_OUTPUT_INIT_HIGH)
68 gpio_pin_set_raw(pin, 1);
69
70 if (flags & GPIO_OUTPUT_INIT_LOW)
71 gpio_pin_set_raw(pin, 0);
72
73 /* control pad clock gating: need to enable clock for inputs */
74 uint32_t en = readw((uintptr_t)(PULP_GPIO_ADDR + GPIO_GPIOEN_OFFSET));
75 WRITE_BIT(en, pin, GPIO_INPUT);
76 writew(en, (uintptr_t)(PULP_GPIO_ADDR + GPIO_GPIOEN_OFFSET));
77
78 return 0;
79 }
80
gpio_port_get_raw(uint32_t * value)81 inline int gpio_port_get_raw(uint32_t *value)
82 {
83 /* this api is a bit dumb but the return value is mean to signal an
84 * error. This never happens in our implementation.
85 */
86 *value = readw((uintptr_t)(PULP_GPIO_ADDR + GPIO_PADIN_OFFSET));
87
88 return 0;
89 }
90
gpio_port_set_masked_raw(uint32_t mask,uint32_t value)91 inline int gpio_port_set_masked_raw(uint32_t mask, uint32_t value)
92 {
93 uint32_t outval =
94 readw((uintptr_t)(PULP_GPIO_ADDR + GPIO_PADOUT_OFFSET));
95 writew((outval & ~mask) | (value & mask),
96 (uintptr_t)(PULP_GPIO_ADDR + GPIO_PADOUT_OFFSET));
97
98 return 0;
99 }
100
gpio_port_set_bits_raw(uint32_t mask)101 inline int gpio_port_set_bits_raw(uint32_t mask)
102 {
103 uint32_t outval =
104 readw((uintptr_t)(PULP_GPIO_ADDR + GPIO_PADOUT_OFFSET));
105 writew(outval | mask, (uintptr_t)(PULP_GPIO_ADDR + GPIO_PADOUT_OFFSET));
106
107 return 0;
108 }
109
gpio_port_clear_bits_raw(uint32_t mask)110 inline int gpio_port_clear_bits_raw(uint32_t mask)
111 {
112 uint32_t outval =
113 readw((uintptr_t)(PULP_GPIO_ADDR + GPIO_PADOUT_OFFSET));
114 writew(outval & ~mask,
115 (uintptr_t)(PULP_GPIO_ADDR + GPIO_PADOUT_OFFSET));
116
117 return 0;
118 }
119
gpio_port_toggle_bits(uint32_t mask)120 inline int gpio_port_toggle_bits(uint32_t mask)
121 {
122 uint32_t outval =
123 readw((uintptr_t)(PULP_GPIO_ADDR + GPIO_PADOUT_OFFSET));
124 writew(outval ^ mask, (uintptr_t)(PULP_GPIO_ADDR + GPIO_PADOUT_OFFSET));
125
126 return 0;
127 }
128
gpio_pin_get_raw(int pin)129 inline int gpio_pin_get_raw(int pin)
130 {
131 assert(0 <= pin && pin < 32);
132
133 uint32_t value = 0;
134 int ret = gpio_port_get_raw(&value);
135 if (!ret)
136 ret = (value & BIT(pin)) != 0;
137
138 return ret;
139 }
140
gpio_pin_set_raw(int pin,int value)141 inline int gpio_pin_set_raw(int pin, int value)
142 {
143 assert(0 <= pin && pin < 32);
144
145 if (value != 0)
146 gpio_port_set_bits_raw(BIT(pin));
147 else
148 gpio_port_clear_bits_raw(BIT(pin));
149
150 return 0;
151 }
152
gpio_pin_toggle(int pin)153 inline int gpio_pin_toggle(int pin)
154 {
155 return gpio_port_toggle_bits(BIT(pin));
156 }
157