xref: /aosp_15_r20/external/coreboot/src/soc/mediatek/common/gpio.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <device/mmio.h>
4 #include <gpio.h>
5 
6 enum {
7 	GPIO_DIRECTION_IN = 0,
8 	GPIO_DIRECTION_OUT = 1,
9 };
10 
11 enum {
12 	GPIO_MODE = 0,
13 };
14 
pos_bit_calc(gpio_t gpio,u32 * pos,u32 * bit)15 static void pos_bit_calc(gpio_t gpio, u32 *pos, u32 *bit)
16 {
17 	*pos = gpio.id / MAX_GPIO_REG_BITS;
18 	*bit = gpio.id % MAX_GPIO_REG_BITS;
19 }
20 
pos_bit_calc_for_mode(gpio_t gpio,u32 * pos,u32 * bit)21 static void pos_bit_calc_for_mode(gpio_t gpio, u32 *pos, u32 *bit)
22 {
23 	*pos = gpio.id / MAX_GPIO_MODE_PER_REG;
24 	*bit = (gpio.id % MAX_GPIO_MODE_PER_REG) * GPIO_MODE_BITS;
25 }
26 
gpio_set_dir(gpio_t gpio,u32 dir)27 static s32 gpio_set_dir(gpio_t gpio, u32 dir)
28 {
29 	u32 pos;
30 	u32 bit;
31 	u32 *reg;
32 
33 	pos_bit_calc(gpio, &pos, &bit);
34 
35 	if (dir == GPIO_DIRECTION_IN)
36 		reg = &mtk_gpio->dir[pos].rst;
37 	else
38 		reg = &mtk_gpio->dir[pos].set;
39 
40 	write32(reg, 1L << bit);
41 
42 	return 0;
43 }
44 
gpio_set_mode(gpio_t gpio,int mode)45 void gpio_set_mode(gpio_t gpio, int mode)
46 {
47 	u32 pos;
48 	u32 bit;
49 	u32 mask = (1L << GPIO_MODE_BITS) - 1;
50 
51 	pos_bit_calc_for_mode(gpio, &pos, &bit);
52 
53 	clrsetbits32(&mtk_gpio->mode[pos].val, mask << bit, mode << bit);
54 }
55 
gpio_get(gpio_t gpio)56 int gpio_get(gpio_t gpio)
57 {
58 	u32 pos;
59 	u32 bit;
60 	u32 *reg;
61 	u32 data;
62 
63 	pos_bit_calc(gpio, &pos, &bit);
64 
65 	reg = &mtk_gpio->din[pos].val;
66 	data = read32(reg);
67 
68 	return (data & (1L << bit)) ? 1 : 0;
69 }
70 
gpio_set(gpio_t gpio,int output)71 void gpio_set(gpio_t gpio, int output)
72 {
73 	u32 pos;
74 	u32 bit;
75 	u32 *reg;
76 
77 	pos_bit_calc(gpio, &pos, &bit);
78 
79 	if (output == 0)
80 		reg = &mtk_gpio->dout[pos].rst;
81 	else
82 		reg = &mtk_gpio->dout[pos].set;
83 
84 	write32(reg, 1L << bit);
85 }
86 
gpio_input_pulldown(gpio_t gpio)87 void gpio_input_pulldown(gpio_t gpio)
88 {
89 	gpio_set_pull(gpio, GPIO_PULL_ENABLE, GPIO_PULL_DOWN);
90 	gpio_set_dir(gpio, GPIO_DIRECTION_IN);
91 	gpio_set_mode(gpio, GPIO_MODE);
92 }
93 
gpio_input_pullup(gpio_t gpio)94 void gpio_input_pullup(gpio_t gpio)
95 {
96 	gpio_set_pull(gpio, GPIO_PULL_ENABLE, GPIO_PULL_UP);
97 	gpio_set_dir(gpio, GPIO_DIRECTION_IN);
98 	gpio_set_mode(gpio, GPIO_MODE);
99 }
100 
gpio_input(gpio_t gpio)101 void gpio_input(gpio_t gpio)
102 {
103 	gpio_set_pull(gpio, GPIO_PULL_DISABLE, GPIO_PULL_DOWN);
104 	gpio_set_dir(gpio, GPIO_DIRECTION_IN);
105 	gpio_set_mode(gpio, GPIO_MODE);
106 }
107 
gpio_output(gpio_t gpio,int value)108 void gpio_output(gpio_t gpio, int value)
109 {
110 	gpio_set_pull(gpio, GPIO_PULL_DISABLE, GPIO_PULL_DOWN);
111 	gpio_set(gpio, value);
112 	gpio_set_dir(gpio, GPIO_DIRECTION_OUT);
113 	gpio_set_mode(gpio, GPIO_MODE);
114 }
115 
116 enum {
117 	MAX_EINT_REG_BITS = 32,
118 };
119 
pos_bit_calc_for_eint(gpio_t gpio,u32 * pos,u32 * bit)120 static void pos_bit_calc_for_eint(gpio_t gpio, u32 *pos, u32 *bit)
121 {
122 	*pos = gpio.id / MAX_EINT_REG_BITS;
123 	*bit = gpio.id % MAX_EINT_REG_BITS;
124 }
125 
gpio_eint_poll(gpio_t gpio)126 int gpio_eint_poll(gpio_t gpio)
127 {
128 	u32 pos;
129 	u32 bit;
130 	u32 status;
131 
132 	pos_bit_calc_for_eint(gpio, &pos, &bit);
133 
134 	status = (read32(&mtk_eint->sta.regs[pos]) >> bit) & 0x1;
135 
136 	if (status)
137 		write32(&mtk_eint->ack.regs[pos], 1 << bit);
138 
139 	return status;
140 }
141 
gpio_eint_configure(gpio_t gpio,enum gpio_irq_type type)142 void gpio_eint_configure(gpio_t gpio, enum gpio_irq_type type)
143 {
144 	u32 pos;
145 	u32 bit, mask;
146 
147 	pos_bit_calc_for_eint(gpio, &pos, &bit);
148 	mask = 1 << bit;
149 
150 	/* Make it an input first. */
151 	gpio_input_pullup(gpio);
152 
153 	write32(&mtk_eint->d0en[pos], mask);
154 
155 	switch (type) {
156 	case IRQ_TYPE_EDGE_FALLING:
157 		write32(&mtk_eint->sens_clr.regs[pos], mask);
158 		write32(&mtk_eint->pol_clr.regs[pos], mask);
159 		break;
160 	case IRQ_TYPE_EDGE_RISING:
161 		write32(&mtk_eint->sens_clr.regs[pos], mask);
162 		write32(&mtk_eint->pol_set.regs[pos], mask);
163 		break;
164 	case IRQ_TYPE_LEVEL_LOW:
165 		write32(&mtk_eint->sens_set.regs[pos], mask);
166 		write32(&mtk_eint->pol_clr.regs[pos], mask);
167 		break;
168 	case IRQ_TYPE_LEVEL_HIGH:
169 		write32(&mtk_eint->sens_set.regs[pos], mask);
170 		write32(&mtk_eint->pol_set.regs[pos], mask);
171 		break;
172 	}
173 
174 	write32(&mtk_eint->mask_clr.regs[pos], mask);
175 }
176 
is_valid_drv(uint8_t drv)177 static inline bool is_valid_drv(uint8_t drv)
178 {
179 	return drv <= GPIO_DRV_16_MA;
180 }
181 
is_valid_drv_adv(enum gpio_drv_adv drv)182 static inline bool is_valid_drv_adv(enum gpio_drv_adv drv)
183 {
184 	return drv <= GPIO_DRV_ADV_1_MA && drv >= GPIO_DRV_ADV_125_UA;
185 }
186 
gpio_set_driving(gpio_t gpio,uint8_t drv)187 int gpio_set_driving(gpio_t gpio, uint8_t drv)
188 {
189 	uint32_t mask;
190 	const struct gpio_drv_info *info = get_gpio_driving_info(gpio.id);
191 	const struct gpio_drv_info *adv_info = get_gpio_driving_adv_info(gpio.id);
192 	void *reg, *reg_adv, *reg_addr;
193 
194 	if (!info)
195 		return -1;
196 
197 	if (!is_valid_drv(drv))
198 		return -1;
199 
200 	if (info->width == 0)
201 		return -1;
202 
203 	mask = BIT(info->width) - 1;
204 	/* Check setting value is not beyond width */
205 	if ((uint32_t)drv > mask)
206 		return -1;
207 
208 	reg_addr = gpio_find_reg_addr(gpio);
209 	reg = reg_addr + info->offset;
210 	clrsetbits32(reg, mask << info->shift, drv << info->shift);
211 
212 	/* Disable EH if supported */
213 	if (adv_info && adv_info->width != 0) {
214 		reg_adv = reg_addr + adv_info->offset;
215 		clrbits32(reg_adv, BIT(adv_info->shift));
216 	}
217 
218 	return 0;
219 }
220 
gpio_get_driving(gpio_t gpio)221 int gpio_get_driving(gpio_t gpio)
222 {
223 	const struct gpio_drv_info *info = get_gpio_driving_info(gpio.id);
224 	void *reg;
225 
226 	if (!info)
227 		return -1;
228 
229 	if (info->width == 0)
230 		return -1;
231 
232 	reg = gpio_find_reg_addr(gpio) + info->offset;
233 	return (read32(reg) >> info->shift) & (BIT(info->width) - 1);
234 }
235 
gpio_set_driving_adv(gpio_t gpio,enum gpio_drv_adv drv)236 int gpio_set_driving_adv(gpio_t gpio, enum gpio_drv_adv drv)
237 {
238 	uint32_t mask;
239 	const struct gpio_drv_info *adv_info = get_gpio_driving_adv_info(gpio.id);
240 	void *reg_adv;
241 
242 	if (!adv_info)
243 		return -1;
244 
245 	if (!is_valid_drv_adv(drv))
246 		return -1;
247 
248 	if (adv_info->width == 0)
249 		return -1;
250 
251 	/* Not include EH bit (the lowest bit) */
252 	if ((uint32_t)drv > (BIT(adv_info->width - 1) - 1))
253 		return -1;
254 
255 	reg_adv = gpio_find_reg_addr(gpio) + adv_info->offset;
256 	mask = BIT(adv_info->width) - 1;
257 	/* EH enable */
258 	drv = (drv << 1) | BIT(0);
259 
260 	clrsetbits32(reg_adv, mask << adv_info->shift, drv << adv_info->shift);
261 
262 	return 0;
263 }
264 
gpio_get_driving_adv(gpio_t gpio)265 int gpio_get_driving_adv(gpio_t gpio)
266 {
267 	const struct gpio_drv_info *adv_info = get_gpio_driving_adv_info(gpio.id);
268 	void *reg_adv;
269 	uint32_t drv;
270 
271 	if (!adv_info)
272 		return -1;
273 
274 	if (adv_info->width == 0)
275 		return -1;
276 
277 	reg_adv = gpio_find_reg_addr(gpio) + adv_info->offset;
278 	drv = (read32(reg_adv) >> adv_info->shift) & (BIT(adv_info->width) - 1);
279 
280 	/* Drop EH bit */
281 	return drv >> 1;
282 }
283