Re: [PATCH v3 04/21] pinctrl: starfive: Add StarFive JHB100 sys0 controller driver
Changhuang Liang <[email protected]>
| Newsgroups | org.kernel.vger.linux-devicetree,org.infradead.lists.linux-riscv,org.kernel.vger.linux-gpio,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <ZQ4PR01MB1202DC395D0213BABE68FF31F2D52@ZQ4PR01MB1202.CHNPR01.prod.partner.outlook.cn> |
Hi, linus Thanks for the review. > On Thu, Jul 30, 2026 at 12:58 PM Changhuang Liang > <[email protected]> wrote: > > > > If a pin controller back-end is used, the GPIO controller or > > > hardware description needs to provide "GPIO ranges" mapping the GPIO > > > line offsets to pin numbers on the pin controller so they can > > > properly cross-reference each other." > > > > I tried this change, but it doesn't work. In my new version, the GPIO > > direction is set via the `struct pinmux_ops .gpio_set_direction` > > callback, which is executed after `mutex_lock(&pctldev->mutex);`. I > > need to configure some pinconf settings while setting the GPIO direction > inside `.gpio_set_direction`, for example: > > > > config = pinconf_to_config_packed(PIN_CONFIG_INPUT_ENABLE, 0); > > ret = pinctrl_gpio_set_config(gc, gpio, config); > > > > However, `pinctrl_gpio_set_config` will again acquire the lock with > > `mutex_lock(&pctldev->mutex);`. > > > > So this approach may no longer work? > > I can't see all your code so I don't know exactly why this happens, but > nominally you implement the GPIO helpers: > > struct pinmux_ops { > (...) > int (*gpio_request_enable) (struct pinctrl_dev *pctldev, > struct pinctrl_gpio_range > *range, > unsigned int offset); > void (*gpio_disable_free) (struct pinctrl_dev *pctldev, > struct pinctrl_gpio_range *range, > unsigned int offset); > int (*gpio_set_direction) (struct pinctrl_dev *pctldev, > struct pinctrl_gpio_range *range, > unsigned int offset, > bool input); > > Then on the GPIO side: > > static int my_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) > { > return pinctrl_gpio_direction_input(chip, offset); } > > static int my_gpio_direction_output(struct gpio_chip *chip, unsigned int > offset, > int value) { > int ret; > > ret = my_gpio_set(chip, offset, value); > if (ret) > return ret; > > return pinctrl_gpio_direction_output(chip, offset); } > > static const struct gpio_chip my_gpio_chip = { > .direction_input = my_gpio_direction_input, > .direction_output = my_gpio_direction_output, > .set_config = gpiochip_generic_config, }; > > And these will call into the pin controller backend for you, so you do not need > to set this yourself? Copy from v4: -----------: static int jhb100_gpio_direction_input(struct gpio_chip *gc, unsigned int gpio) { struct jhb100_gpio_bank *bank = jhb100_gc_to_bank(gc); struct jhb100_pinctrl *sfp = gpiochip_get_data(gc); const struct jhb100_pinctrl_domain_info *info = sfp->info; const struct config_reg_layout_desc *crl_desc; unsigned int pin = jhb100_gpio_to_pin(gc, gpio); unsigned int offset = 4 * bank->id; void __iomem *reg_gpio_oen; u32 doen = 0; crl_desc = get_crl_desc_by_pin(sfp, pin); if (!crl_desc) { dev_err(sfp->dev, "pin %d can't not found reg layout descriptor\n", pin); return -EINVAL; } jhb100_padcfg_rmw(sfp, pin, RL_DESC_GENMASK(crl_desc, PAD_CFG_INPUT_ENABLE) | RL_DESC_GENMASK(crl_desc, PAD_CFG_SCHMITT_TRIGGER_SELECT), RL_DESC_GENMASK(crl_desc, PAD_CFG_INPUT_ENABLE) | RL_DESC_GENMASK(crl_desc, PAD_CFG_SCHMITT_TRIGGER_SELECT)); reg_gpio_oen = sfp->base + info->regs->output_en + offset; guard(raw_spinlock_irqsave)(&sfp->lock); doen = readl_relaxed(reg_gpio_oen) | BIT(gpio); writel_relaxed(doen, reg_gpio_oen); return 0; } static int jhb100_gpio_direction_output(struct gpio_chip *gc, unsigned int gpio) { struct jhb100_gpio_bank *bank = jhb100_gc_to_bank(gc); struct jhb100_pinctrl *sfp = gpiochip_get_data(gc); const struct jhb100_pinctrl_domain_info *info = sfp->info; const struct config_reg_layout_desc *crl_desc; unsigned int pin = jhb100_gpio_to_pin(gc, gpio); unsigned int offset = 4 * bank->id; void __iomem *reg_gpio_oen; u32 doen = 0; crl_desc = get_crl_desc_by_pin(sfp, pin); if (!crl_desc) { dev_err(sfp->dev, "pin %d can't not found reg layout descriptor\n", pin); return -EINVAL; } jhb100_padcfg_rmw(sfp, pin, RL_DESC_GENMASK(crl_desc, PAD_CFG_INPUT_ENABLE) | RL_DESC_GENMASK(crl_desc, PAD_CFG_SCHMITT_TRIGGER_SELECT) | RL_DESC_GENMASK(crl_desc, PAD_CFG_PULL_DOWN) | RL_DESC_GENMASK(crl_desc, PAD_CFG_PULL_UP), 0); reg_gpio_oen = sfp->base + info->regs->output_en + offset; guard(raw_spinlock_irqsave)(&sfp->lock); doen = readl_relaxed(reg_gpio_oen) & ~BIT(gpio); writel_relaxed(doen, reg_gpio_oen); return 0; } static int jhb100_gpio_set_direction(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned int pin, bool input) { struct jhb100_pinctrl *sfp = pinctrl_dev_get_drvdata(pctldev); unsigned int id = pin / JHB100_NR_GPIOS_PER_BANK; unsigned int gpio = pin % JHB100_NR_GPIOS_PER_BANK; if (input) return jhb100_gpio_direction_input(&sfp->banks[id].chip.gc, gpio); return jhb100_gpio_direction_output(&sfp->banks[id].chip.gc, gpio); } static const struct pinmux_ops jhb100_pinmux_ops = { .get_functions_count = pinmux_generic_get_function_count, .get_function_name = pinmux_generic_get_function_name, .get_function_groups = pinmux_generic_get_function_groups, .set_mux = jhb100_set_mux, .gpio_request_enable = jhb100_gpio_request_enable, .gpio_set_direction = jhb100_gpio_set_direction, }; Yes, I sent the new version as above. However, I still kept jhb100_gpio_to_pin() in jhb100_gpio_direction_input(). The first time I wanted to replace this part: ----------------------------------------------------------------------------- unsigned int pin = jhb100_gpio_to_pin(gc, gpio); jhb100_padcfg_rmw(sfp, pin, RL_DESC_GENMASK(crl_desc, PAD_CFG_INPUT_ENABLE) | RL_DESC_GENMASK(crl_desc, PAD_CFG_SCHMITT_TRIGGER_SELECT), RL_DESC_GENMASK(crl_desc, PAD_CFG_INPUT_ENABLE) | RL_DESC_GENMASK(crl_desc, PAD_CFG_SCHMITT_TRIGGER_SELECT)); ----------------------------------------------------------------------------- with ------------------------------------------------------------------------------ config = pinconf_to_config_packed(PIN_CONFIG_INPUT_ENABLE, 1); ret = pinctrl_gpio_set_config(gc, gpio, config); config = pinconf_to_config_packed(PAD_CFG_SCHMITT_TRIGGER_SELECT, 1); ret = pinctrl_gpio_set_config(gc, gpio, config); ------------------------------------------------------------------------------- However, during testing, I found a recursive lock issue: pinctrl_gpio_direction() mutex_lock(&pctldev->mutex); -> pinmux_gpio_direction() -> ops->gpio_set_direction -> jhb100_gpio_set_direction() -> jhb100_gpio_direction_input() -> pinctrl_gpio_set_config() -> pinctrl_get_device_gpio_range() -> pinctrl_match_gpio_range() -> mutex_lock(&pctldev->mutex); ====> Executes mutex_lock(&pctldev->mutex); again mutex_unlock(&pctldev->mutex); ------------------------------------- So in v4, I temporarily kept jhb100_gpio_to_pin(). Best Regards, Changhuang