1 /*
2  * Copyright 2022 NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/drivers/pinctrl.h>
8 #include <soc.h>
9 
10 static MCI_IO_MUX_Type *mci_iomux =
11 	(MCI_IO_MUX_Type *)DT_REG_ADDR(DT_NODELABEL(pinctrl));
12 
13 static SOCCIU_Type *soc_ctrl =
14 	(SOCCIU_Type *)DT_REG_ADDR(DT_NODELABEL(soc_ctrl));
15 static AON_SOC_CIU_Type *aon_soc_ciu =
16 	(AON_SOC_CIU_Type *)DT_REG_ADDR(DT_NODELABEL(aon_soc_ctrl));
17 
18 /*
19  * GPIO mux option definitions. Stored as a static array, because
20  * these mux options are needed to clear pin mux settings to
21  * a known good state before selecting a new alternate function.
22  */
23 static uint64_t gpio_muxes[] = {IOMUX_GPIO_OPS};
24 
25 /*
26  * Helper function to handle setting pin properties,
27  * such as pin bias and slew rate
28  */
configure_pin_props(uint32_t pin_mux,uint8_t gpio_idx)29 static void configure_pin_props(uint32_t pin_mux, uint8_t gpio_idx)
30 {
31 	uint32_t mask, set;
32 	volatile uint32_t *pull_reg = &soc_ctrl->PAD_PU_PD_EN0;
33 	volatile uint32_t *slew_reg = &soc_ctrl->SR_CONFIG0;
34 	volatile uint32_t *sleep_force_en = &soc_ctrl->PAD_SLP_EN0;
35 	volatile uint32_t *sleep_force_val = &soc_ctrl->PAD_SLP_VAL0;
36 
37 	/* GPIO 22-27 use always on configuration registers */
38 	if (gpio_idx > 21 && gpio_idx < 28) {
39 		pull_reg = (&aon_soc_ciu->PAD_PU_PD_EN1 - 1);
40 		slew_reg = (&aon_soc_ciu->SR_CONFIG1 - 1);
41 		sleep_force_en = &aon_soc_ciu->PAD_SLP_EN0;
42 		sleep_force_val = &aon_soc_ciu->PAD_SLP_VAL0;
43 	}
44 	/* Calculate register offset for pull and slew regs.
45 	 * Use bit shifting as opposed to division
46 	 */
47 	pull_reg += (gpio_idx >> 4);
48 	slew_reg += (gpio_idx >> 4);
49 	sleep_force_en += (gpio_idx >> 5);
50 	sleep_force_val += (gpio_idx >> 5);
51 	/* Set pull-up/pull-down */
52 	/* Use mask and bitshift here as opposed to modulo and multiplication.
53 	 * equivalent to ((gpio_idx % 16) * 2)
54 	 */
55 	mask = 0x3 << ((gpio_idx & 0xF) << 1);
56 	set = IOMUX_PAD_GET_PULL(pin_mux) << ((gpio_idx & 0xF) << 1);
57 	*pull_reg = (*pull_reg & ~mask) | set;
58 
59 	/* Set slew rate */
60 	set = IOMUX_PAD_GET_SLEW(pin_mux) << ((gpio_idx & 0xF) << 1);
61 	*slew_reg = (*slew_reg & ~mask) | set;
62 
63 	/* Set sleep force enable bit */
64 	mask = (0x1 << (gpio_idx & 0x1F));
65 	set = (IOMUX_PAD_GET_SLEEP_FORCE_EN(pin_mux) << (gpio_idx & 0x1F));
66 	*sleep_force_en = (*sleep_force_en & ~mask) | set;
67 	set = (IOMUX_PAD_GET_SLEEP_FORCE_VAL(pin_mux) << (gpio_idx & 0x1F));
68 	*sleep_force_val = (*sleep_force_val & ~mask) | set;
69 }
70 
select_gpio_mode(uint8_t gpio_idx)71 static void select_gpio_mode(uint8_t gpio_idx)
72 {
73 	uint64_t gpio_setting = gpio_muxes[gpio_idx];
74 	volatile uint32_t *flexcomm_reg = &mci_iomux->FC0;
75 
76 	/* Clear flexcomm settings */
77 	flexcomm_reg += IOMUX_GET_FLEXCOMM_CLR_IDX(gpio_setting);
78 	*flexcomm_reg &= ~IOMUX_GET_FLEXCOMM_CLR_MASK(gpio_setting);
79 	/* Clear fsel settings */
80 	mci_iomux->FSEL &= ~IOMUX_GET_FSEL_CLR_MASK(gpio_setting);
81 	/* Clear CTimer in/out, if required */
82 	if (IOMUX_GET_SCTIMER_IN_CLR_ENABLE(gpio_setting)) {
83 		mci_iomux->C_TIMER_IN &=
84 			~(0x1 << IOMUX_GET_CTIMER_CLR_OFFSET(gpio_setting));
85 		mci_iomux->C_TIMER_OUT &=
86 			~(0x1 << IOMUX_GET_CTIMER_CLR_OFFSET(gpio_setting));
87 	}
88 	/* Clear SCTimer in/out, if required */
89 	if (IOMUX_GET_SCTIMER_IN_CLR_ENABLE(gpio_setting)) {
90 		mci_iomux->SC_TIMER &=
91 			~(0x1 << IOMUX_GET_SCTIMER_IN_CLR_OFFSET(gpio_setting));
92 	}
93 	if (IOMUX_GET_SCTIMER_OUT_CLR_ENABLE(gpio_setting)) {
94 		mci_iomux->SC_TIMER &=
95 			~(0x1 << (IOMUX_GET_SCTIMER_OUT_CLR_OFFSET(gpio_setting) + 16));
96 	}
97 	/* Clear security gpio enable */
98 	mci_iomux->S_GPIO &= ~(0x1 << (gpio_idx - 32));
99 }
100 
101 
pinctrl_configure_pins(const pinctrl_soc_pin_t * pins,uint8_t pin_cnt,uintptr_t reg)102 int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt,
103 			   uintptr_t reg)
104 {
105 	volatile uint32_t *flexcomm_reg;
106 	volatile uint32_t *iomux_en_reg;
107 
108 	for (uint8_t i = 0; i < pin_cnt; i++) {
109 		flexcomm_reg = &mci_iomux->FC0;
110 		iomux_en_reg = &soc_ctrl->MCI_IOMUX_EN0;
111 		uint32_t pin_mux = pins[i];
112 		uint8_t gpio_idx = IOMUX_GET_GPIO_IDX(pin_mux);
113 		uint8_t type = IOMUX_GET_TYPE(pin_mux);
114 		/*
115 		 * Before selecting an alternate function, we must clear any
116 		 * conflicting pin configuration. We do this by resetting the
117 		 * pin to a gpio configuration, then selecting the alternate
118 		 * function.
119 		 */
120 		select_gpio_mode(gpio_idx);
121 		switch (type) {
122 		case IOMUX_FLEXCOMM:
123 			flexcomm_reg += IOMUX_GET_FLEXCOMM_IDX(pin_mux);
124 			*flexcomm_reg |=
125 				(0x1 << IOMUX_GET_FLEXCOMM_BIT(pin_mux));
126 			break;
127 		case IOMUX_FSEL:
128 			mci_iomux->FSEL |=
129 				(0x1 << IOMUX_GET_FSEL_BIT(pin_mux));
130 			break;
131 		case IOMUX_CTIMER_IN:
132 			mci_iomux->C_TIMER_IN |=
133 				(0x1 << IOMUX_GET_CTIMER_BIT(pin_mux));
134 			break;
135 		case IOMUX_CTIMER_OUT:
136 			mci_iomux->C_TIMER_OUT |=
137 				(0x1 << IOMUX_GET_CTIMER_BIT(pin_mux));
138 			break;
139 		case IOMUX_SCTIMER_IN:
140 			mci_iomux->SC_TIMER |=
141 				(0x1 << IOMUX_GET_SCTIMER_BIT(pin_mux));
142 			break;
143 		case IOMUX_SCTIMER_OUT:
144 			mci_iomux->SC_TIMER |=
145 				(0x1 << (IOMUX_GET_SCTIMER_BIT(pin_mux) + 16));
146 			break;
147 		case IOMUX_SGPIO:
148 			mci_iomux->S_GPIO |= (0x1 << (gpio_idx - 32));
149 			break;
150 		case IOMUX_GPIO:
151 			if (gpio_idx > 32) {
152 				mci_iomux->GPIO_GRP1 |= (0x1 << (gpio_idx - 32));
153 			} else {
154 				mci_iomux->GPIO_GRP0 |= (0x1 << gpio_idx);
155 			}
156 			break;
157 		case IOMUX_AON:
158 			/* No selection bits should be set */
159 			break;
160 		default:
161 			/* Unsupported type passed */
162 			return -ENOTSUP;
163 		}
164 		configure_pin_props(pin_mux, gpio_idx);
165 		/* Now, enable pin controller access to this pin */
166 		if (gpio_idx > 21 && gpio_idx < 28) {
167 			/* GPIO 22-27 use always on soc controller */
168 			iomux_en_reg = &aon_soc_ciu->MCI_IOMUX_EN0;
169 		}
170 		iomux_en_reg += (gpio_idx >> 5);
171 		*iomux_en_reg |= (0x1 << (gpio_idx & 0x1F));
172 	}
173 	return 0;
174 }
175