pinctrl: aspeed-g5: Delay acquisition of regmaps

While sorting out some devicetree issues I found that the pinctrl driver
was failing to acquire its GFX regmap even though the phandle was
present in the devicetree:

    [    0.124190] aspeed-g5-pinctrl 1e6e2000.syscon:pinctrl: No GFX phandle found, some mux configurations may fail

Without access to the GFX regmap we fail to configure the mux for the
VPO function:

    [    1.548866] pinctrl core: add 1 pinctrl maps
    [    1.549826] aspeed-g5-pinctrl 1e6e2000.syscon:pinctrl: found group selector 164 for VPO
    [    1.550638] aspeed-g5-pinctrl 1e6e2000.syscon:pinctrl: request pin 144 (V20) for 1e6e6000.display
    [    1.551346] aspeed-g5-pinctrl 1e6e2000.syscon:pinctrl: request pin 145 (U19) for 1e6e6000.display
    ...
    [    1.562057] aspeed-g5-pinctrl 1e6e2000.syscon:pinctrl: request pin 218 (T22) for 1e6e6000.display
    [    1.562541] aspeed-g5-pinctrl 1e6e2000.syscon:pinctrl: request pin 219 (R20) for 1e6e6000.display
    [    1.563113] Muxing pin 144 for VPO
    [    1.563456] Want SCU8C[0x00000001]=0x1, got 0x0 from 0x00000000
    [    1.564624] aspeed_gfx 1e6e6000.display: Error applying setting, reverse things back

This turned out to be a simple problem of timing: The ASPEED pinctrl
driver is probed during arch_initcall(), while GFX is processed much
later. As such the GFX syscon is not yet registered during the pinctrl
probe() and we get an -EPROBE_DEFER when we try to look it up, however
we must not defer probing the pinctrl driver for the inability to mux
some GFX-related functions.

Switch to lazily grabbing the regmaps when they're first required by the
mux configuration. This generates a bit of noise in the patch as we have
to drop the `const` qualifier on arguments for several function
prototypes, but has the benefit of working.

I've smoke tested this for the ast2500-evb under qemu with a dummy
graphics device. We now succeed in our attempts to configure the SoC's
VPO pinmux function.

Fixes: 7d29ed88ac ("pinctrl: aspeed: Read and write bits in LPC and GFX controllers")
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
Link: https://lore.kernel.org/r/20190724080155.12209-1-andrew@aj.id.au
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
This commit is contained in:
Andrew Jeffery 2019-07-24 17:31:55 +09:30 committed by Linus Walleij
parent 5f9e832c13
commit 674fa8daa8
4 changed files with 74 additions and 37 deletions

View File

@ -2412,7 +2412,7 @@ static const struct aspeed_pin_config aspeed_g4_configs[] = {
{ PIN_CONFIG_INPUT_DEBOUNCE, { C14, B14 }, SCUA8, 27 }, { PIN_CONFIG_INPUT_DEBOUNCE, { C14, B14 }, SCUA8, 27 },
}; };
static int aspeed_g4_sig_expr_set(const struct aspeed_pinmux_data *ctx, static int aspeed_g4_sig_expr_set(struct aspeed_pinmux_data *ctx,
const struct aspeed_sig_expr *expr, const struct aspeed_sig_expr *expr,
bool enable) bool enable)
{ {

View File

@ -2507,6 +2507,61 @@ static struct aspeed_pin_config aspeed_g5_configs[] = {
{ PIN_CONFIG_INPUT_DEBOUNCE, { A20, B19 }, SCUA8, 27 }, { PIN_CONFIG_INPUT_DEBOUNCE, { A20, B19 }, SCUA8, 27 },
}; };
static struct regmap *aspeed_g5_acquire_regmap(struct aspeed_pinmux_data *ctx,
int ip)
{
if (ip == ASPEED_IP_SCU) {
WARN(!ctx->maps[ip], "Missing SCU syscon!");
return ctx->maps[ip];
}
if (ip >= ASPEED_NR_PINMUX_IPS)
return ERR_PTR(-EINVAL);
if (likely(ctx->maps[ip]))
return ctx->maps[ip];
if (ip == ASPEED_IP_GFX) {
struct device_node *node;
struct regmap *map;
node = of_parse_phandle(ctx->dev->of_node,
"aspeed,external-nodes", 0);
if (node) {
map = syscon_node_to_regmap(node);
of_node_put(node);
if (IS_ERR(map))
return map;
} else
return ERR_PTR(-ENODEV);
ctx->maps[ASPEED_IP_GFX] = map;
dev_dbg(ctx->dev, "Acquired GFX regmap");
return map;
}
if (ip == ASPEED_IP_LPC) {
struct device_node *node;
struct regmap *map;
node = of_parse_phandle(ctx->dev->of_node,
"aspeed,external-nodes", 1);
if (node) {
map = syscon_node_to_regmap(node->parent);
of_node_put(node);
if (IS_ERR(map))
return map;
} else
map = ERR_PTR(-ENODEV);
ctx->maps[ASPEED_IP_LPC] = map;
dev_dbg(ctx->dev, "Acquired LPC regmap");
return map;
}
return ERR_PTR(-EINVAL);
}
/** /**
* Configure a pin's signal by applying an expression's descriptor state for * Configure a pin's signal by applying an expression's descriptor state for
* all descriptors in the expression. * all descriptors in the expression.
@ -2520,7 +2575,7 @@ static struct aspeed_pin_config aspeed_g5_configs[] = {
* Return: 0 if the expression is configured as requested and a negative error * Return: 0 if the expression is configured as requested and a negative error
* code otherwise * code otherwise
*/ */
static int aspeed_g5_sig_expr_set(const struct aspeed_pinmux_data *ctx, static int aspeed_g5_sig_expr_set(struct aspeed_pinmux_data *ctx,
const struct aspeed_sig_expr *expr, const struct aspeed_sig_expr *expr,
bool enable) bool enable)
{ {
@ -2531,9 +2586,15 @@ static int aspeed_g5_sig_expr_set(const struct aspeed_pinmux_data *ctx,
const struct aspeed_sig_desc *desc = &expr->descs[i]; const struct aspeed_sig_desc *desc = &expr->descs[i];
u32 pattern = enable ? desc->enable : desc->disable; u32 pattern = enable ? desc->enable : desc->disable;
u32 val = (pattern << __ffs(desc->mask)); u32 val = (pattern << __ffs(desc->mask));
struct regmap *map;
if (!ctx->maps[desc->ip]) map = aspeed_g5_acquire_regmap(ctx, desc->ip);
return -ENODEV; if (IS_ERR(map)) {
dev_err(ctx->dev,
"Failed to acquire regmap for IP block %d\n",
desc->ip);
return PTR_ERR(map);
}
/* /*
* Strap registers are configured in hardware or by early-boot * Strap registers are configured in hardware or by early-boot
@ -2641,34 +2702,11 @@ static struct pinctrl_desc aspeed_g5_pinctrl_desc = {
static int aspeed_g5_pinctrl_probe(struct platform_device *pdev) static int aspeed_g5_pinctrl_probe(struct platform_device *pdev)
{ {
int i; int i;
struct regmap *map;
struct device_node *node;
for (i = 0; i < ARRAY_SIZE(aspeed_g5_pins); i++) for (i = 0; i < ARRAY_SIZE(aspeed_g5_pins); i++)
aspeed_g5_pins[i].number = i; aspeed_g5_pins[i].number = i;
node = of_parse_phandle(pdev->dev.of_node, "aspeed,external-nodes", 0); aspeed_g5_pinctrl_data.pinmux.dev = &pdev->dev;
map = syscon_node_to_regmap(node);
of_node_put(node);
if (IS_ERR(map)) {
dev_warn(&pdev->dev, "No GFX phandle found, some mux configurations may fail\n");
map = NULL;
}
aspeed_g5_pinctrl_data.pinmux.maps[ASPEED_IP_GFX] = map;
node = of_parse_phandle(pdev->dev.of_node, "aspeed,external-nodes", 1);
if (node) {
map = syscon_node_to_regmap(node->parent);
if (IS_ERR(map)) {
dev_warn(&pdev->dev, "LHC parent is not a syscon, some mux configurations may fail\n");
map = NULL;
}
} else {
dev_warn(&pdev->dev, "No LHC phandle found, some mux configurations may fail\n");
map = NULL;
}
of_node_put(node);
aspeed_g5_pinctrl_data.pinmux.maps[ASPEED_IP_LPC] = map;
return aspeed_pinctrl_probe(pdev, &aspeed_g5_pinctrl_desc, return aspeed_pinctrl_probe(pdev, &aspeed_g5_pinctrl_desc,
&aspeed_g5_pinctrl_data); &aspeed_g5_pinctrl_data);

View File

@ -71,7 +71,7 @@ int aspeed_pinmux_get_fn_groups(struct pinctrl_dev *pctldev,
return 0; return 0;
} }
static int aspeed_sig_expr_enable(const struct aspeed_pinmux_data *ctx, static int aspeed_sig_expr_enable(struct aspeed_pinmux_data *ctx,
const struct aspeed_sig_expr *expr) const struct aspeed_sig_expr *expr)
{ {
int ret; int ret;
@ -86,7 +86,7 @@ static int aspeed_sig_expr_enable(const struct aspeed_pinmux_data *ctx,
return 0; return 0;
} }
static int aspeed_sig_expr_disable(const struct aspeed_pinmux_data *ctx, static int aspeed_sig_expr_disable(struct aspeed_pinmux_data *ctx,
const struct aspeed_sig_expr *expr) const struct aspeed_sig_expr *expr)
{ {
int ret; int ret;
@ -109,7 +109,7 @@ static int aspeed_sig_expr_disable(const struct aspeed_pinmux_data *ctx,
* *
* Return: 0 if all expressions are disabled, otherwise a negative error code * Return: 0 if all expressions are disabled, otherwise a negative error code
*/ */
static int aspeed_disable_sig(const struct aspeed_pinmux_data *ctx, static int aspeed_disable_sig(struct aspeed_pinmux_data *ctx,
const struct aspeed_sig_expr **exprs) const struct aspeed_sig_expr **exprs)
{ {
int ret = 0; int ret = 0;
@ -217,8 +217,7 @@ int aspeed_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function,
{ {
int i; int i;
int ret; int ret;
const struct aspeed_pinctrl_data *pdata = struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
pinctrl_dev_get_drvdata(pctldev);
const struct aspeed_pin_group *pgroup = &pdata->pinmux.groups[group]; const struct aspeed_pin_group *pgroup = &pdata->pinmux.groups[group];
const struct aspeed_pin_function *pfunc = const struct aspeed_pin_function *pfunc =
&pdata->pinmux.functions[function]; &pdata->pinmux.functions[function];
@ -306,8 +305,7 @@ int aspeed_gpio_request_enable(struct pinctrl_dev *pctldev,
unsigned int offset) unsigned int offset)
{ {
int ret; int ret;
const struct aspeed_pinctrl_data *pdata = struct aspeed_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev);
pinctrl_dev_get_drvdata(pctldev);
const struct aspeed_pin_desc *pdesc = pdata->pins[offset].drv_data; const struct aspeed_pin_desc *pdesc = pdata->pins[offset].drv_data;
const struct aspeed_sig_expr ***prios, **funcs, *expr; const struct aspeed_sig_expr ***prios, **funcs, *expr;

View File

@ -702,11 +702,12 @@ struct aspeed_pin_function {
struct aspeed_pinmux_data; struct aspeed_pinmux_data;
struct aspeed_pinmux_ops { struct aspeed_pinmux_ops {
int (*set)(const struct aspeed_pinmux_data *ctx, int (*set)(struct aspeed_pinmux_data *ctx,
const struct aspeed_sig_expr *expr, bool enabled); const struct aspeed_sig_expr *expr, bool enabled);
}; };
struct aspeed_pinmux_data { struct aspeed_pinmux_data {
struct device *dev;
struct regmap *maps[ASPEED_NR_PINMUX_IPS]; struct regmap *maps[ASPEED_NR_PINMUX_IPS];
const struct aspeed_pinmux_ops *ops; const struct aspeed_pinmux_ops *ops;
@ -725,7 +726,7 @@ int aspeed_sig_expr_eval(const struct aspeed_pinmux_data *ctx,
const struct aspeed_sig_expr *expr, const struct aspeed_sig_expr *expr,
bool enabled); bool enabled);
static inline int aspeed_sig_expr_set(const struct aspeed_pinmux_data *ctx, static inline int aspeed_sig_expr_set(struct aspeed_pinmux_data *ctx,
const struct aspeed_sig_expr *expr, const struct aspeed_sig_expr *expr,
bool enabled) bool enabled)
{ {