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