diff options
author | Tony Lindgren <tony@atomide.com> | 2017-12-15 20:41:23 +0300 |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2017-12-21 18:28:54 +0300 |
commit | c5a2de97fbd2979fab291fb048084d3fddd322dd (patch) | |
tree | 45dfca45e1e9c683c961cb20936d464a2380f673 | |
parent | 566a9b05e1fa47dcfb93a4459145d0fdc06d3046 (diff) | |
download | linux-c5a2de97fbd2979fab291fb048084d3fddd322dd.tar.xz |
bus: ti-sysc: Add parsing of module capabilities
We need to configure the interconnect target module based on the
device three configuration.
Let's also add a new quirk for SYSC_QUIRK_RESET_STATUS to indicate
that the SYSCONFIG reset bit changes after the reset is done.
Signed-off-by: Tony Lindgren <tony@atomide.com>
-rw-r--r-- | drivers/bus/ti-sysc.c | 100 | ||||
-rw-r--r-- | include/linux/platform_data/ti-sysc.h | 10 |
2 files changed, 110 insertions, 0 deletions
diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index 090612460cef..2c62985a345f 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -39,6 +39,9 @@ enum sysc_clocks { static const char * const clock_names[] = { "fck", "ick", }; +#define SYSC_IDLEMODE_MASK 3 +#define SYSC_CLOCKACTIVITY_MASK 3 + /** * struct sysc - TI sysc interconnect target module registers and capabilities * @dev: struct device pointer @@ -517,6 +520,91 @@ static int sysc_init_module(struct sysc *ddata) return 0; } +static int sysc_init_sysc_mask(struct sysc *ddata) +{ + struct device_node *np = ddata->dev->of_node; + int error; + u32 val; + + error = of_property_read_u32(np, "ti,sysc-mask", &val); + if (error) + return 0; + + if (val) + ddata->cfg.sysc_val = val & ddata->cap->sysc_mask; + else + ddata->cfg.sysc_val = ddata->cap->sysc_mask; + + return 0; +} + +static int sysc_init_idlemode(struct sysc *ddata, u8 *idlemodes, + const char *name) +{ + struct device_node *np = ddata->dev->of_node; + struct property *prop; + const __be32 *p; + u32 val; + + of_property_for_each_u32(np, name, prop, p, val) { + if (val >= SYSC_NR_IDLEMODES) { + dev_err(ddata->dev, "invalid idlemode: %i\n", val); + return -EINVAL; + } + *idlemodes |= (1 << val); + } + + return 0; +} + +static int sysc_init_idlemodes(struct sysc *ddata) +{ + int error; + + error = sysc_init_idlemode(ddata, &ddata->cfg.midlemodes, + "ti,sysc-midle"); + if (error) + return error; + + error = sysc_init_idlemode(ddata, &ddata->cfg.sidlemodes, + "ti,sysc-sidle"); + if (error) + return error; + + return 0; +} + +/* + * Only some devices on omap4 and later have SYSCONFIG reset done + * bit. We can detect this if there is no SYSSTATUS at all, or the + * SYSTATUS bit 0 is not used. Note that some SYSSTATUS registers + * have multiple bits for the child devices like OHCI and EHCI. + * Depends on SYSC being parsed first. + */ +static int sysc_init_syss_mask(struct sysc *ddata) +{ + struct device_node *np = ddata->dev->of_node; + int error; + u32 val; + + error = of_property_read_u32(np, "ti,syss-mask", &val); + if (error) { + if ((ddata->cap->type == TI_SYSC_OMAP4 || + ddata->cap->type == TI_SYSC_OMAP4_TIMER) && + (ddata->cfg.sysc_val & SYSC_OMAP4_SOFTRESET)) + ddata->cfg.quirks |= SYSC_QUIRK_RESET_STATUS; + + return 0; + } + + if (!(val & 1) && (ddata->cfg.sysc_val & SYSC_OMAP4_SOFTRESET)) + ddata->cfg.quirks |= SYSC_QUIRK_RESET_STATUS; + + ddata->cfg.syss_mask = val; + + return 0; +} + /* Device tree configured quirks */ struct sysc_dts_quirk { const char *name; @@ -820,6 +908,18 @@ static int sysc_probe(struct platform_device *pdev) if (error) goto unprepare; + error = sysc_init_sysc_mask(ddata); + if (error) + goto unprepare; + + error = sysc_init_idlemodes(ddata); + if (error) + goto unprepare; + + error = sysc_init_syss_mask(ddata); + if (error) + goto unprepare; + pm_runtime_enable(ddata->dev); error = sysc_init_module(ddata); diff --git a/include/linux/platform_data/ti-sysc.h b/include/linux/platform_data/ti-sysc.h index 28e5a61d4abc..1be356330b96 100644 --- a/include/linux/platform_data/ti-sysc.h +++ b/include/linux/platform_data/ti-sysc.h @@ -41,6 +41,7 @@ struct sysc_regbits { s8 emufree_shift; }; +#define SYSC_QUIRK_RESET_STATUS BIT(7) #define SYSC_QUIRK_NO_IDLE_ON_INIT BIT(6) #define SYSC_QUIRK_NO_RESET_ON_INIT BIT(5) #define SYSC_QUIRK_OPT_CLKS_NEEDED BIT(4) @@ -49,6 +50,8 @@ struct sysc_regbits { #define SYSC_QUIRK_UNCACHED BIT(1) #define SYSC_QUIRK_USE_CLOCKACT BIT(0) +#define SYSC_NR_IDLEMODES 4 + /** * struct sysc_capabilities - capabilities for an interconnect target module * @@ -65,10 +68,17 @@ struct sysc_capabilities { /** * struct sysc_config - configuration for an interconnect target module + * @sysc_val: configured value for sysc register + * @midlemodes: bitmask of supported master idle modes + * @sidlemodes: bitmask of supported master idle modes * @srst_udelay: optional delay needed after OCP soft reset * @quirks: bitmask of enabled quirks */ struct sysc_config { + u32 sysc_val; + u32 syss_mask; + u8 midlemodes; + u8 sidlemodes; u8 srst_udelay; u32 quirks; }; |