*
* Heavily based on Mediatek's pinctrl driver
*/
+#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/gpio/driver.h>
#include <linux/hwspinlock.h>
#include "../pinctrl-utils.h"
#include "pinctrl-stm32.h"
+#define STM32_GPIO_CID1 1
+
#define STM32_GPIO_MODER 0x00
#define STM32_GPIO_TYPER 0x04
#define STM32_GPIO_SPEEDR 0x08
#define STM32_GPIO_AFRL 0x20
#define STM32_GPIO_AFRH 0x24
#define STM32_GPIO_SECCFGR 0x30
+#define STM32_GPIO_CIDCFGR(x) (0x50 + (0x8 * (x)))
+#define STM32_GPIO_SEMCR(x) (0x54 + (0x8 * (x)))
/* custom bitfield to backup pin status */
#define STM32_GPIO_BKP_MODE_SHIFT 0
#define STM32_GPIO_BKP_TYPE 10
#define STM32_GPIO_BKP_VAL 11
+#define STM32_GPIO_CIDCFGR_CFEN BIT(0)
+#define STM32_GPIO_CIDCFGR_SEMEN BIT(1)
+#define STM32_GPIO_CIDCFGR_SCID_MASK GENMASK(5, 4)
+#define STM32_GPIO_CIDCFGR_SEMWL_CID1 BIT(16 + STM32_GPIO_CID1)
+
+#define STM32_GPIO_SEMCR_SEM_MUTEX BIT(0)
+#define STM32_GPIO_SEMCR_SEMCID_MASK GENMASK(5, 4)
+
#define STM32_GPIO_PINS_PER_BANK 16
#define STM32_GPIO_IRQ_LINE 16
u32 pin_backup[STM32_GPIO_PINS_PER_BANK];
u8 irq_type[STM32_GPIO_PINS_PER_BANK];
bool secure_control;
+ bool rif_control;
};
struct stm32_pinctrl {
bank->pin_backup[offset] |= bias << STM32_GPIO_BKP_PUPD_SHIFT;
}
+/* RIF functions */
+
+static bool stm32_gpio_rif_valid(struct stm32_gpio_bank *bank, unsigned int gpio_nr)
+{
+ u32 cid;
+
+ cid = readl_relaxed(bank->base + STM32_GPIO_CIDCFGR(gpio_nr));
+
+ if (!(cid & STM32_GPIO_CIDCFGR_CFEN))
+ return true;
+
+ if (!(cid & STM32_GPIO_CIDCFGR_SEMEN)) {
+ if (FIELD_GET(STM32_GPIO_CIDCFGR_SCID_MASK, cid) == STM32_GPIO_CID1)
+ return true;
+
+ return false;
+ }
+
+ if (cid & STM32_GPIO_CIDCFGR_SEMWL_CID1)
+ return true;
+
+ return false;
+}
+
+static bool stm32_gpio_rif_acquire_semaphore(struct stm32_gpio_bank *bank, unsigned int gpio_nr)
+{
+ u32 cid, sem;
+
+ cid = readl_relaxed(bank->base + STM32_GPIO_CIDCFGR(gpio_nr));
+
+ if (!(cid & STM32_GPIO_CIDCFGR_CFEN))
+ return true;
+
+ if (!(cid & STM32_GPIO_CIDCFGR_SEMEN)) {
+ if (FIELD_GET(STM32_GPIO_CIDCFGR_SCID_MASK, cid) == STM32_GPIO_CID1)
+ return true;
+
+ return false;
+ }
+
+ if (!(cid & STM32_GPIO_CIDCFGR_SEMWL_CID1))
+ return false;
+
+ sem = readl_relaxed(bank->base + STM32_GPIO_SEMCR(gpio_nr));
+ if (sem & STM32_GPIO_SEMCR_SEM_MUTEX) {
+ if (FIELD_GET(STM32_GPIO_SEMCR_SEMCID_MASK, sem) == STM32_GPIO_CID1)
+ return true;
+
+ return false;
+ }
+
+ writel_relaxed(STM32_GPIO_SEMCR_SEM_MUTEX, bank->base + STM32_GPIO_SEMCR(gpio_nr));
+
+ sem = readl_relaxed(bank->base + STM32_GPIO_SEMCR(gpio_nr));
+ if (sem & STM32_GPIO_SEMCR_SEM_MUTEX &&
+ FIELD_GET(STM32_GPIO_SEMCR_SEMCID_MASK, sem) == STM32_GPIO_CID1)
+ return true;
+
+ return false;
+}
+
+static void stm32_gpio_rif_release_semaphore(struct stm32_gpio_bank *bank, unsigned int gpio_nr)
+{
+ u32 cid;
+
+ cid = readl_relaxed(bank->base + STM32_GPIO_CIDCFGR(gpio_nr));
+
+ if (!(cid & STM32_GPIO_CIDCFGR_CFEN))
+ return;
+
+ if (cid & STM32_GPIO_CIDCFGR_SEMEN)
+ writel_relaxed(0, bank->base + STM32_GPIO_SEMCR(gpio_nr));
+}
+
/* GPIO functions */
static inline void __stm32_gpio_set(struct stm32_gpio_bank *bank,
return -EINVAL;
}
+ if (bank->rif_control) {
+ if (!stm32_gpio_rif_acquire_semaphore(bank, offset)) {
+ dev_err(pctl->dev, "pin %d not available.\n", pin);
+ return -EINVAL;
+ }
+ }
+
return pinctrl_gpio_request(chip, offset);
}
+static void stm32_gpio_free(struct gpio_chip *chip, unsigned int offset)
+{
+ struct stm32_gpio_bank *bank = gpiochip_get_data(chip);
+
+ pinctrl_gpio_free(chip, offset);
+
+ if (bank->rif_control)
+ stm32_gpio_rif_release_semaphore(bank, offset);
+}
+
static int stm32_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct stm32_gpio_bank *bank = gpiochip_get_data(chip);
}
}
+ if (bank->rif_control) {
+ for (i = 0; i < ngpios; i++) {
+ if (!test_bit(i, valid_mask))
+ continue;
+
+ if (stm32_gpio_rif_valid(bank, i))
+ continue;
+
+ dev_dbg(pctl->dev, "RIF semaphore ownership conflict, GPIO %u", i);
+ clear_bit(i, valid_mask);
+ }
+ }
+
return 0;
}
static const struct gpio_chip stm32_gpio_template = {
.request = stm32_gpio_request,
- .free = pinctrl_gpio_free,
+ .free = stm32_gpio_free,
.get = stm32_gpio_get,
.set_rv = stm32_gpio_set,
.direction_input = pinctrl_gpio_direction_input,
bank->bank_nr = bank_nr;
bank->bank_ioport_nr = bank_ioport_nr;
bank->secure_control = pctl->match_data->secure_control;
+ bank->rif_control = pctl->match_data->rif_control;
spin_lock_init(&bank->lock);
if (pctl->domain) {