/* * Copyright 2022 NXP * * SPDX-License-Identifier: Apache-2.0 */ #include #include static MCI_IO_MUX_Type *mci_iomux = (MCI_IO_MUX_Type *)DT_REG_ADDR(DT_NODELABEL(pinctrl)); static SOCCIU_Type *soc_ctrl = (SOCCIU_Type *)DT_REG_ADDR(DT_NODELABEL(soc_ctrl)); static AON_SOC_CIU_Type *aon_soc_ciu = (AON_SOC_CIU_Type *)DT_REG_ADDR(DT_NODELABEL(aon_soc_ctrl)); /* * GPIO mux option definitions. Stored as a static array, because * these mux options are needed to clear pin mux settings to * a known good state before selecting a new alternate function. */ static uint64_t gpio_muxes[] = {IOMUX_GPIO_OPS}; /* * Helper function to handle setting pin properties, * such as pin bias and slew rate */ static void configure_pin_props(uint32_t pin_mux, uint8_t gpio_idx) { uint32_t mask, set; volatile uint32_t *pull_reg = &soc_ctrl->PAD_PU_PD_EN0; volatile uint32_t *slew_reg = &soc_ctrl->SR_CONFIG0; volatile uint32_t *sleep_force_en = &soc_ctrl->PAD_SLP_EN0; volatile uint32_t *sleep_force_val = &soc_ctrl->PAD_SLP_VAL0; /* GPIO 22-27 use always on configuration registers */ if (gpio_idx > 21 && gpio_idx < 28) { pull_reg = (&aon_soc_ciu->PAD_PU_PD_EN1 - 1); slew_reg = (&aon_soc_ciu->SR_CONFIG1 - 1); sleep_force_en = &aon_soc_ciu->PAD_SLP_EN0; sleep_force_val = &aon_soc_ciu->PAD_SLP_VAL0; } /* Calculate register offset for pull and slew regs. * Use bit shifting as opposed to division */ pull_reg += (gpio_idx >> 4); slew_reg += (gpio_idx >> 4); sleep_force_en += (gpio_idx >> 5); sleep_force_val += (gpio_idx >> 5); /* Set pull-up/pull-down */ /* Use mask and bitshift here as opposed to modulo and multiplication. * equivalent to ((gpio_idx % 16) * 2) */ mask = 0x3 << ((gpio_idx & 0xF) << 1); set = IOMUX_PAD_GET_PULL(pin_mux) << ((gpio_idx & 0xF) << 1); *pull_reg = (*pull_reg & ~mask) | set; /* Set slew rate */ set = IOMUX_PAD_GET_SLEW(pin_mux) << ((gpio_idx & 0xF) << 1); *slew_reg = (*slew_reg & ~mask) | set; /* Set sleep force enable bit */ mask = (0x1 << (gpio_idx & 0x1F)); set = (IOMUX_PAD_GET_SLEEP_FORCE_EN(pin_mux) << (gpio_idx & 0x1F)); *sleep_force_en = (*sleep_force_en & ~mask) | set; set = (IOMUX_PAD_GET_SLEEP_FORCE_VAL(pin_mux) << (gpio_idx & 0x1F)); *sleep_force_val = (*sleep_force_val & ~mask) | set; } static void select_gpio_mode(uint8_t gpio_idx) { uint64_t gpio_setting = gpio_muxes[gpio_idx]; volatile uint32_t *flexcomm_reg = &mci_iomux->FC0; /* Clear flexcomm settings */ flexcomm_reg += IOMUX_GET_FLEXCOMM_CLR_IDX(gpio_setting); *flexcomm_reg &= ~IOMUX_GET_FLEXCOMM_CLR_MASK(gpio_setting); /* Clear fsel settings */ mci_iomux->FSEL &= ~IOMUX_GET_FSEL_CLR_MASK(gpio_setting); /* Clear CTimer in/out, if required */ if (IOMUX_GET_SCTIMER_IN_CLR_ENABLE(gpio_setting)) { mci_iomux->C_TIMER_IN &= ~(0x1 << IOMUX_GET_CTIMER_CLR_OFFSET(gpio_setting)); mci_iomux->C_TIMER_OUT &= ~(0x1 << IOMUX_GET_CTIMER_CLR_OFFSET(gpio_setting)); } /* Clear SCTimer in/out, if required */ if (IOMUX_GET_SCTIMER_IN_CLR_ENABLE(gpio_setting)) { mci_iomux->SC_TIMER &= ~(0x1 << IOMUX_GET_SCTIMER_IN_CLR_OFFSET(gpio_setting)); } if (IOMUX_GET_SCTIMER_OUT_CLR_ENABLE(gpio_setting)) { mci_iomux->SC_TIMER &= ~(0x1 << (IOMUX_GET_SCTIMER_OUT_CLR_OFFSET(gpio_setting) + 16)); } /* Clear security gpio enable */ mci_iomux->S_GPIO &= ~(0x1 << (gpio_idx - 32)); } int pinctrl_configure_pins(const pinctrl_soc_pin_t *pins, uint8_t pin_cnt, uintptr_t reg) { volatile uint32_t *flexcomm_reg; volatile uint32_t *iomux_en_reg; for (uint8_t i = 0; i < pin_cnt; i++) { flexcomm_reg = &mci_iomux->FC0; iomux_en_reg = &soc_ctrl->MCI_IOMUX_EN0; uint32_t pin_mux = pins[i]; uint8_t gpio_idx = IOMUX_GET_GPIO_IDX(pin_mux); uint8_t type = IOMUX_GET_TYPE(pin_mux); /* * Before selecting an alternate function, we must clear any * conflicting pin configuration. We do this by resetting the * pin to a gpio configuration, then selecting the alternate * function. */ select_gpio_mode(gpio_idx); switch (type) { case IOMUX_FLEXCOMM: flexcomm_reg += IOMUX_GET_FLEXCOMM_IDX(pin_mux); *flexcomm_reg |= (0x1 << IOMUX_GET_FLEXCOMM_BIT(pin_mux)); break; case IOMUX_FSEL: mci_iomux->FSEL |= (0x1 << IOMUX_GET_FSEL_BIT(pin_mux)); break; case IOMUX_CTIMER_IN: mci_iomux->C_TIMER_IN |= (0x1 << IOMUX_GET_CTIMER_BIT(pin_mux)); break; case IOMUX_CTIMER_OUT: mci_iomux->C_TIMER_OUT |= (0x1 << IOMUX_GET_CTIMER_BIT(pin_mux)); break; case IOMUX_SCTIMER_IN: mci_iomux->SC_TIMER |= (0x1 << IOMUX_GET_SCTIMER_BIT(pin_mux)); break; case IOMUX_SCTIMER_OUT: mci_iomux->SC_TIMER |= (0x1 << (IOMUX_GET_SCTIMER_BIT(pin_mux) + 16)); break; case IOMUX_SGPIO: mci_iomux->S_GPIO |= (0x1 << (gpio_idx - 32)); break; case IOMUX_GPIO: if (gpio_idx > 32) { mci_iomux->GPIO_GRP1 |= (0x1 << (gpio_idx - 32)); } else { mci_iomux->GPIO_GRP0 |= (0x1 << gpio_idx); } break; case IOMUX_AON: /* No selection bits should be set */ break; default: /* Unsupported type passed */ return -ENOTSUP; } configure_pin_props(pin_mux, gpio_idx); /* Now, enable pin controller access to this pin */ if (gpio_idx > 21 && gpio_idx < 28) { /* GPIO 22-27 use always on soc controller */ iomux_en_reg = &aon_soc_ciu->MCI_IOMUX_EN0; } iomux_en_reg += (gpio_idx >> 5); *iomux_en_reg |= (0x1 << (gpio_idx & 0x1F)); } return 0; }