c1432423a1
Commit674fa8daa8
("pinctrl: aspeed-g5: Delay acquisition of regmaps") was determined to be a partial fix to the problem of acquiring the LPC Host Controller and GFX regmaps: The AST2500 pin controller may need to fetch syscon regmaps during expression evaluation as well as when setting mux state. For example, this case is hit by attempting to export pins exposing the LPC Host Controller as GPIOs. An optional eval() hook is added to the Aspeed pinmux operation struct and called from aspeed_sig_expr_eval() if the pointer is set by the SoC-specific driver. This enables the AST2500 to perform the custom action of acquiring its regmap dependencies as required. John Wang tested the fix on an Inspur FP5280G2 machine (AST2500-based) where the issue was found, and I've booted the fix on Witherspoon (AST2500) and Palmetto (AST2400) machines, and poked at relevant pins under QEMU by forcing mux configurations via devmem before exporting GPIOs to exercise the driver. Fixes:7d29ed88ac
("pinctrl: aspeed: Read and write bits in LPC and GFX controllers") Fixes:674fa8daa8
("pinctrl: aspeed-g5: Delay acquisition of regmaps") Reported-by: John Wang <wangzqbj@inspur.com> Tested-by: John Wang <wangzqbj@inspur.com> Signed-off-by: Andrew Jeffery <andrew@aj.id.au> Link: https://lore.kernel.org/r/20190829071738.2523-1-andrew@aj.id.au Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
100 lines
3.2 KiB
C
100 lines
3.2 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/* Copyright (C) 2019 IBM Corp. */
|
|
|
|
/* Pieces to enable drivers to implement the .set callback */
|
|
|
|
#include "pinmux-aspeed.h"
|
|
|
|
static const char *const aspeed_pinmux_ips[] = {
|
|
[ASPEED_IP_SCU] = "SCU",
|
|
[ASPEED_IP_GFX] = "GFX",
|
|
[ASPEED_IP_LPC] = "LPC",
|
|
};
|
|
|
|
static inline void aspeed_sig_desc_print_val(
|
|
const struct aspeed_sig_desc *desc, bool enable, u32 rv)
|
|
{
|
|
pr_debug("Want %s%X[0x%08X]=0x%X, got 0x%X from 0x%08X\n",
|
|
aspeed_pinmux_ips[desc->ip], desc->reg,
|
|
desc->mask, enable ? desc->enable : desc->disable,
|
|
(rv & desc->mask) >> __ffs(desc->mask), rv);
|
|
}
|
|
|
|
/**
|
|
* Query the enabled or disabled state of a signal descriptor
|
|
*
|
|
* @desc: The signal descriptor of interest
|
|
* @enabled: True to query the enabled state, false to query disabled state
|
|
* @map: The IP block's regmap instance
|
|
*
|
|
* Return: 1 if the descriptor's bitfield is configured to the state
|
|
* selected by @enabled, 0 if not, and less than zero if an unrecoverable
|
|
* failure occurred
|
|
*
|
|
* Evaluation of descriptor state is non-trivial in that it is not a binary
|
|
* outcome: The bitfields can be greater than one bit in size and thus can take
|
|
* a value that is neither the enabled nor disabled state recorded in the
|
|
* descriptor (typically this means a different function to the one of interest
|
|
* is enabled). Thus we must explicitly test for either condition as required.
|
|
*/
|
|
int aspeed_sig_desc_eval(const struct aspeed_sig_desc *desc,
|
|
bool enabled, struct regmap *map)
|
|
{
|
|
int ret;
|
|
unsigned int raw;
|
|
u32 want;
|
|
|
|
if (!map)
|
|
return -ENODEV;
|
|
|
|
ret = regmap_read(map, desc->reg, &raw);
|
|
if (ret)
|
|
return ret;
|
|
|
|
aspeed_sig_desc_print_val(desc, enabled, raw);
|
|
want = enabled ? desc->enable : desc->disable;
|
|
|
|
return ((raw & desc->mask) >> __ffs(desc->mask)) == want;
|
|
}
|
|
|
|
/**
|
|
* Query the enabled or disabled state for a mux function's signal on a pin
|
|
*
|
|
* @ctx: The driver context for the pinctrl IP
|
|
* @expr: An expression controlling the signal for a mux function on a pin
|
|
* @enabled: True to query the enabled state, false to query disabled state
|
|
*
|
|
* Return: 1 if the expression composed by @enabled evaluates true, 0 if not,
|
|
* and less than zero if an unrecoverable failure occurred.
|
|
*
|
|
* A mux function is enabled or disabled if the function's signal expression
|
|
* for each pin in the function's pin group evaluates true for the desired
|
|
* state. An signal expression evaluates true if all of its associated signal
|
|
* descriptors evaluate true for the desired state.
|
|
*
|
|
* If an expression's state is described by more than one bit, either through
|
|
* multi-bit bitfields in a single signal descriptor or through multiple signal
|
|
* descriptors of a single bit then it is possible for the expression to be in
|
|
* neither the enabled nor disabled state. Thus we must explicitly test for
|
|
* either condition as required.
|
|
*/
|
|
int aspeed_sig_expr_eval(struct aspeed_pinmux_data *ctx,
|
|
const struct aspeed_sig_expr *expr, bool enabled)
|
|
{
|
|
int ret;
|
|
int i;
|
|
|
|
if (ctx->ops->eval)
|
|
return ctx->ops->eval(ctx, expr, enabled);
|
|
|
|
for (i = 0; i < expr->ndescs; i++) {
|
|
const struct aspeed_sig_desc *desc = &expr->descs[i];
|
|
|
|
ret = aspeed_sig_desc_eval(desc, enabled, ctx->maps[desc->ip]);
|
|
if (ret <= 0)
|
|
return ret;
|
|
}
|
|
|
|
return 1;
|
|
}
|