From 7f0d078667a494466991aa7133f49594f32ff6a2 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 21 Mar 2019 11:00:21 -0700 Subject: ARM: OMAP2+: Fix potentially uninitialized return value for _setup_reset() Commit 747834ab8347 ("ARM: OMAP2+: hwmod: revise hardreset behavior") made the call to _enable() conditional based on no oh->rst_lines_cnt. This caused the return value to be potentially uninitialized. Curiously we see no compiler warnings for this, probably as this gets inlined. We call _setup_reset() from _setup() and only _setup_postsetup() if the return value is zero. Currently the return value can be uninitialized for cases where oh->rst_lines_cnt is set and HWMOD_INIT_NO_RESET is not set. Fixes: 747834ab8347 ("ARM: OMAP2+: hwmod: revise hardreset behavior") Cc: Paul Walmsley Cc: Tero Kristo Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/omap_hwmod.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm/mach-omap2/omap_hwmod.c') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 3a04c73ac03c..21afaf630caa 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -2465,7 +2465,7 @@ static void _setup_iclk_autoidle(struct omap_hwmod *oh) */ static int _setup_reset(struct omap_hwmod *oh) { - int r; + int r = 0; if (oh->_state != _HWMOD_STATE_INITIALIZED) return -EINVAL; -- cgit From 798bd175ab0d8024652ddba2cacaba6768c63c30 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 21 Mar 2019 11:00:21 -0700 Subject: ARM: OMAP2+: Make interconnect target module allocation functions static Only omap_hwmod_init_module() gets called, the rest of the interconnect target module allocation functions can be static. Cc: Paul Walmsley Cc: Tero Kristo Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/omap_hwmod.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) (limited to 'arch/arm/mach-omap2/omap_hwmod.c') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 21afaf630caa..b88cf32cf8a9 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -3241,9 +3241,10 @@ static int omap_hwmod_init_regbits(struct device *dev, * @sysc_offs: sysc register offset * @syss_offs: syss register offset */ -int omap_hwmod_init_reg_offs(struct device *dev, - const struct ti_sysc_module_data *data, - s32 *rev_offs, s32 *sysc_offs, s32 *syss_offs) +static int omap_hwmod_init_reg_offs(struct device *dev, + const struct ti_sysc_module_data *data, + s32 *rev_offs, s32 *sysc_offs, + s32 *syss_offs) { *rev_offs = -ENODEV; *sysc_offs = 0; @@ -3267,9 +3268,9 @@ int omap_hwmod_init_reg_offs(struct device *dev, * @data: module data * @sysc_flags: module configuration */ -int omap_hwmod_init_sysc_flags(struct device *dev, - const struct ti_sysc_module_data *data, - u32 *sysc_flags) +static int omap_hwmod_init_sysc_flags(struct device *dev, + const struct ti_sysc_module_data *data, + u32 *sysc_flags) { *sysc_flags = 0; @@ -3341,9 +3342,9 @@ int omap_hwmod_init_sysc_flags(struct device *dev, * @data: module data * @idlemodes: module supported idle modes */ -int omap_hwmod_init_idlemodes(struct device *dev, - const struct ti_sysc_module_data *data, - u32 *idlemodes) +static int omap_hwmod_init_idlemodes(struct device *dev, + const struct ti_sysc_module_data *data, + u32 *idlemodes) { *idlemodes = 0; @@ -3434,11 +3435,12 @@ static int omap_hwmod_check_module(struct device *dev, * * Note that the allocations here cannot use devm as ti-sysc can rebind. */ -int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh, - const struct ti_sysc_module_data *data, - struct sysc_regbits *sysc_fields, - s32 rev_offs, s32 sysc_offs, s32 syss_offs, - u32 sysc_flags, u32 idlemodes) +static int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh, + const struct ti_sysc_module_data *data, + struct sysc_regbits *sysc_fields, + s32 rev_offs, s32 sysc_offs, + s32 syss_offs, u32 sysc_flags, + u32 idlemodes) { struct omap_hwmod_class_sysconfig *sysc; struct omap_hwmod_class *class; -- cgit From 513a4abb19d55253ea9490288986ec781a78b786 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 21 Mar 2019 11:00:21 -0700 Subject: ARM: OMAP2+: Prepare class allocation for dynamically allocated modules For dynamically allocated sysconfig data we only need to allocate a new class for the cases where the class is shared. For dynamically allocated struct omap_hwmod we will always allocate a new class. Let's add detection for when we need to allocate a new class by comparing the class name against the module name. If they match, there's no need to allocate a new calls as we don't have case of mixed platform data and dts data initialized modules for the same class. Let's also move the init of class data inside the spinlock. Cc: Paul Walmsley Cc: Tero Kristo Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/omap_hwmod.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'arch/arm/mach-omap2/omap_hwmod.c') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index b88cf32cf8a9..dc172fff9ced 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -3443,7 +3443,7 @@ static int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh, u32 idlemodes) { struct omap_hwmod_class_sysconfig *sysc; - struct omap_hwmod_class *class; + struct omap_hwmod_class *class = NULL; void __iomem *regs = NULL; unsigned long flags; @@ -3467,19 +3467,21 @@ static int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh, } /* - * We need new oh->class as the other devices in the same class + * We may need a new oh->class as the other devices in the same class * may not yet have ioremapped their registers. */ - class = kmemdup(oh->class, sizeof(*oh->class), GFP_KERNEL); - if (!class) - return -ENOMEM; - - class->sysc = sysc; + if (oh->class->name && strcmp(oh->class->name, data->name)) { + class = kmemdup(oh->class, sizeof(*oh->class), GFP_KERNEL); + if (!class) + return -ENOMEM; + } spin_lock_irqsave(&oh->_lock, flags); if (regs) oh->_mpu_rt_va = regs; - oh->class = class; + if (class) + oh->class = class; + oh->class->sysc = sysc; oh->_state = _HWMOD_STATE_INITIALIZED; _setup(oh, NULL); spin_unlock_irqrestore(&oh->_lock, flags); -- cgit From b57250fa5eb35cd805e7eee7f7b5a4b3b3cb4227 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 21 Mar 2019 11:00:21 -0700 Subject: ARM: OMAP2+: Allocate struct omap_hwmod based on dts data With ti-sysc interconnect target module, we can allocate struct omap_hwmod data based on the devicetree data. This allows dropping the static SoC specific data eventually so we will only boot with data we actually need. To allocate struct omap_hwmod dynamically, we need to add a mutex for modifying the list, and remove __init for few functions. Note that we are not initialized oh->_clk or the optional clocks and their related quirks. That can be directly handled by the interconnect target module driver. Cc: Paul Walmsley Cc: Tero Kristo Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/omap_hwmod.c | 82 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 78 insertions(+), 4 deletions(-) (limited to 'arch/arm/mach-omap2/omap_hwmod.c') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index dc172fff9ced..ed3d503167f4 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -235,6 +235,7 @@ static struct omap_hwmod_soc_ops soc_ops; /* omap_hwmod_list contains all registered struct omap_hwmods */ static LIST_HEAD(omap_hwmod_list); +static DEFINE_MUTEX(list_lock); /* mpu_oh: used to add/remove MPU initiator from sleepdep list */ static struct omap_hwmod *mpu_oh; @@ -2624,7 +2625,7 @@ static int _setup(struct omap_hwmod *oh, void *data) * that the copy process would be relatively complex due to the large number * of substructures. */ -static int __init _register(struct omap_hwmod *oh) +static int _register(struct omap_hwmod *oh) { if (!oh || !oh->name || !oh->class || !oh->class->name || (oh->_state != _HWMOD_STATE_UNKNOWN)) @@ -2663,7 +2664,7 @@ static int __init _register(struct omap_hwmod *oh) * locking in this code. Changes to this assumption will require * additional locking. Returns 0. */ -static int __init _add_link(struct omap_hwmod_ocp_if *oi) +static int _add_link(struct omap_hwmod_ocp_if *oi) { pr_debug("omap_hwmod: %s -> %s: adding link\n", oi->master->name, oi->slave->name); @@ -3444,6 +3445,9 @@ static int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh, { struct omap_hwmod_class_sysconfig *sysc; struct omap_hwmod_class *class = NULL; + struct omap_hwmod_ocp_if *oi = NULL; + struct clockdomain *clkdm = NULL; + struct clk *clk = NULL; void __iomem *regs = NULL; unsigned long flags; @@ -3476,13 +3480,62 @@ static int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh, return -ENOMEM; } + if (list_empty(&oh->slave_ports)) { + oi = kcalloc(1, sizeof(*oi), GFP_KERNEL); + if (!oi) + return -ENOMEM; + + /* + * Note that we assume interconnect interface clocks will be + * managed by the interconnect driver for OCPIF_SWSUP_IDLE case + * on omap24xx and omap3. + */ + oi->slave = oh; + oi->user = OCP_USER_MPU | OCP_USER_SDMA; + } + + if (!oh->_clk) { + struct clk_hw_omap *hwclk; + + clk = of_clk_get_by_name(dev->of_node, "fck"); + if (!IS_ERR(clk)) + clk_prepare(clk); + else + clk = NULL; + + /* + * Populate clockdomain based on dts clock. It is needed for + * clkdm_deny_idle() and clkdm_allow_idle() until we have have + * interconnect driver and reset driver capable of blocking + * clockdomain idle during reset, enable and idle. + */ + if (clk) { + hwclk = to_clk_hw_omap(__clk_get_hw(clk)); + if (hwclk && hwclk->clkdm_name) + clkdm = clkdm_lookup(hwclk->clkdm_name); + } + + /* + * Note that we assume interconnect driver manages the clocks + * and do not need to populate oh->_clk for dynamically + * allocated modules. + */ + clk_unprepare(clk); + clk_put(clk); + } + spin_lock_irqsave(&oh->_lock, flags); if (regs) oh->_mpu_rt_va = regs; if (class) oh->class = class; oh->class->sysc = sysc; + if (oi) + _add_link(oi); + if (clkdm) + oh->clkdm = clkdm; oh->_state = _HWMOD_STATE_INITIALIZED; + oh->_postsetup_state = _HWMOD_STATE_DEFAULT; _setup(oh, NULL); spin_unlock_irqrestore(&oh->_lock, flags); @@ -3509,8 +3562,29 @@ int omap_hwmod_init_module(struct device *dev, return -EINVAL; oh = _lookup(data->name); - if (!oh) - return -ENODEV; + if (!oh) { + oh = kzalloc(sizeof(*oh), GFP_KERNEL); + if (!oh) + return -ENOMEM; + + oh->name = data->name; + oh->_state = _HWMOD_STATE_UNKNOWN; + lockdep_register_key(&oh->hwmod_key); + + /* Unused, can be handled by PRM driver handling resets */ + oh->prcm.omap4.flags = HWMOD_OMAP4_NO_CONTEXT_LOSS_BIT; + + oh->class = kzalloc(sizeof(*oh->class), GFP_KERNEL); + if (!oh->class) { + kfree(oh); + return -ENOMEM; + } + + oh->class->name = data->name; + mutex_lock(&list_lock); + error = _register(oh); + mutex_unlock(&list_lock); + } cookie->data = oh; -- cgit From 8b30919a4e3c7aba32dd72e8208147a6496cb16c Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 21 Mar 2019 11:00:21 -0700 Subject: ARM: OMAP2+: Handle reset quirks for dynamically allocated modules For dynamically allocated struct omap_hwmod data, we need to populate the device IP specific reset quirks. Cc: Paul Walmsley Cc: Tero Kristo Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/omap_hwmod.c | 70 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) (limited to 'arch/arm/mach-omap2/omap_hwmod.c') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index ed3d503167f4..9170fbfb7c59 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -155,6 +155,8 @@ #include "soc.h" #include "common.h" #include "clockdomain.h" +#include "hdq1w.h" +#include "mmc.h" #include "powerdomain.h" #include "cm2xxx.h" #include "cm3xxx.h" @@ -165,6 +167,7 @@ #include "prm33xx.h" #include "prminst44xx.h" #include "pm.h" +#include "wd_timer.h" /* Name of the OMAP hwmod for the MPU */ #define MPU_INITIATOR_NAME "mpu" @@ -204,6 +207,20 @@ struct clkctrl_provider { static LIST_HEAD(clkctrl_providers); +/** + * struct omap_hwmod_reset - IP specific reset functions + * @match: string to match against the module name + * @len: number of characters to match + * @reset: IP specific reset function + * + * Used only in cases where struct omap_hwmod is dynamically allocated. + */ +struct omap_hwmod_reset { + const char *match; + int len; + int (*reset)(struct omap_hwmod *oh); +}; + /** * struct omap_hwmod_soc_ops - fn ptrs for some SoC-specific operations * @enable_module: function to enable a module (via MODULEMODE) @@ -3542,6 +3559,57 @@ static int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh, return 0; } +static const struct omap_hwmod_reset omap24xx_reset_quirks[] = { + { .match = "msdi", .len = 4, .reset = omap_msdi_reset, }, +}; + +static const struct omap_hwmod_reset dra7_reset_quirks[] = { + { .match = "pcie", .len = 4, .reset = dra7xx_pciess_reset, }, +}; + +static const struct omap_hwmod_reset omap_reset_quirks[] = { + { .match = "dss", .len = 3, .reset = omap_dss_reset, }, + { .match = "hdq1w", .len = 5, .reset = omap_hdq1w_reset, }, + { .match = "i2c", .len = 3, .reset = omap_i2c_reset, }, + { .match = "wd_timer", .len = 8, .reset = omap2_wd_timer_reset, }, +}; + +static void +omap_hwmod_init_reset_quirk(struct device *dev, struct omap_hwmod *oh, + const struct ti_sysc_module_data *data, + const struct omap_hwmod_reset *quirks, + int quirks_sz) +{ + const struct omap_hwmod_reset *quirk; + int i; + + for (i = 0; i < quirks_sz; i++) { + quirk = &quirks[i]; + if (!strncmp(data->name, quirk->match, quirk->len)) { + oh->class->reset = quirk->reset; + + return; + } + } +} + +static void +omap_hwmod_init_reset_quirks(struct device *dev, struct omap_hwmod *oh, + const struct ti_sysc_module_data *data) +{ + if (soc_is_omap24xx()) + omap_hwmod_init_reset_quirk(dev, oh, data, + omap24xx_reset_quirks, + ARRAY_SIZE(omap24xx_reset_quirks)); + + if (soc_is_dra7xx()) + omap_hwmod_init_reset_quirk(dev, oh, data, dra7_reset_quirks, + ARRAY_SIZE(dra7_reset_quirks)); + + omap_hwmod_init_reset_quirk(dev, oh, data, omap_reset_quirks, + ARRAY_SIZE(omap_reset_quirks)); +} + /** * omap_hwmod_init_module - initialize new module * @dev: struct device @@ -3580,6 +3648,8 @@ int omap_hwmod_init_module(struct device *dev, return -ENOMEM; } + omap_hwmod_init_reset_quirks(dev, oh, data); + oh->class->name = data->name; mutex_lock(&list_lock); error = _register(oh); -- cgit From 386cb76681ca6248878c7b76d3d5aa0e8b8a07bb Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Fri, 22 Mar 2019 07:49:30 -0700 Subject: bus: ti-sysc: Handle missed no-idle property in addition to no-idle-on-init We have ti,no-idle in use in addition to ti,no-idle-on-init but we're missing handling for it in the ti-sysc interconnect target module driver. Let's also group the idle defines together and update the binding documentation for it. Cc: devicetree@vger.kernel.org Reviewed-by: Rob Herring Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/omap_hwmod.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/arm/mach-omap2/omap_hwmod.c') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 9170fbfb7c59..a985844dbe39 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -3675,6 +3675,8 @@ int omap_hwmod_init_module(struct device *dev, if (error) return error; + if (data->cfg->quirks & SYSC_QUIRK_NO_IDLE) + oh->flags |= HWMOD_NO_IDLE; if (data->cfg->quirks & SYSC_QUIRK_NO_IDLE_ON_INIT) oh->flags |= HWMOD_INIT_NO_IDLE; if (data->cfg->quirks & SYSC_QUIRK_NO_RESET_ON_INIT) -- cgit From 10645e81b9677c5ed9de371b382234564eb73660 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Fri, 22 Mar 2019 08:08:06 -0700 Subject: bus: ti-sysc: Pass clockactivity quirk to platform functions We already have the clockactivity quirk set for some modules like i2c, timers and smartreflex. But we're not passing it to the platform functions yet. Let's start doing that in preparation of dropping interconnect target module platform data in favor of device tree based data. Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/omap_hwmod.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'arch/arm/mach-omap2/omap_hwmod.c') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index a985844dbe39..4a924e444f8d 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -3681,6 +3681,8 @@ int omap_hwmod_init_module(struct device *dev, oh->flags |= HWMOD_INIT_NO_IDLE; if (data->cfg->quirks & SYSC_QUIRK_NO_RESET_ON_INIT) oh->flags |= HWMOD_INIT_NO_RESET; + if (data->cfg->quirks & SYSC_QUIRK_USE_CLOCKACT) + oh->flags |= HWMOD_SET_DEFAULT_CLOCKACT; error = omap_hwmod_check_module(dev, oh, data, sysc_fields, rev_offs, sysc_offs, syss_offs, -- cgit From b4a9a7a38917e9f947b5e69f7e8d4138d4c82845 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 21 Mar 2019 13:27:08 -0700 Subject: bus: ti-sysc: Handle swsup idle mode quirks In preparation of dropping interconnect target module platform data in favor of devicetree based data, we must pass swsup idle quirks to the platform data functions. For now, let's only tag the UART modules with the SWSUP_SIDLE_ACT quirk. The other modules will get tagged with swsup quirks as we drop the platform data and test the changes. Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/omap_hwmod.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'arch/arm/mach-omap2/omap_hwmod.c') diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 4a924e444f8d..4af2e9f0966d 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -3683,6 +3683,12 @@ int omap_hwmod_init_module(struct device *dev, oh->flags |= HWMOD_INIT_NO_RESET; if (data->cfg->quirks & SYSC_QUIRK_USE_CLOCKACT) oh->flags |= HWMOD_SET_DEFAULT_CLOCKACT; + if (data->cfg->quirks & SYSC_QUIRK_SWSUP_SIDLE) + oh->flags |= HWMOD_SWSUP_SIDLE; + if (data->cfg->quirks & SYSC_QUIRK_SWSUP_SIDLE_ACT) + oh->flags |= HWMOD_SWSUP_SIDLE_ACT; + if (data->cfg->quirks & SYSC_QUIRK_SWSUP_MSTANDBY) + oh->flags |= HWMOD_SWSUP_MSTANDBY; error = omap_hwmod_check_module(dev, oh, data, sysc_fields, rev_offs, sysc_offs, syss_offs, -- cgit