aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/omap_hwmod.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-05-16 11:31:32 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2019-05-16 11:31:32 -0400
commit22c58fd70ca48a29505922b1563826593b08cc00 (patch)
treeee3154075bcd0a867fd0abf7e00ba3b4055999d4 /arch/arm/mach-omap2/omap_hwmod.c
parenta455eda33faafcaac1effb31d682765b14ef868c (diff)
parent7a0c4c17089a8aff52f516f0f52002be52950aae (diff)
Merge tag 'armsoc-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
Pull ARM SoC platform updates from Olof Johansson: "SoC updates, mostly refactorings and cleanups of old legacy platforms. Major themes this release: - Conversion of ixp4xx to a modern platform (drivers, DT, bindings) - Moving some of the ep93xx headers around to get it closer to multiplatform enabled. - Cleanups of Davinci This also contains a few patches that were queued up as fixes before 5.1 but I didn't get sent in before release" * tag 'armsoc-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (123 commits) ARM: debug-ll: add default address for digicolor ARM: u300: regulator: add MODULE_LICENSE() ARM: ep93xx: move private headers out of mach/* ARM: ep93xx: move pinctrl interfaces into include/linux/soc ARM: ep93xx: keypad: stop using mach/platform.h ARM: ep93xx: move network platform data to separate header ARM: stm32: add AMBA support for stm32 family MAINTAINERS: update arch/arm/mach-davinci ARM: rockchip: add missing of_node_put in rockchip_smp_prepare_pmu ARM: dts: Add queue manager and NPE to the IXP4xx DTSI soc: ixp4xx: qmgr: Add DT probe code soc: ixp4xx: qmgr: Add DT bindings for IXP4xx qmgr soc: ixp4xx: npe: Add DT probe code soc: ixp4xx: Add DT bindings for IXP4xx NPE soc: ixp4xx: qmgr: Pass resources soc: ixp4xx: Remove unused functions soc: ixp4xx: Uninline several functions soc: ixp4xx: npe: Pass addresses as resources ARM: ixp4xx: Turn the QMGR into a platform device ARM: ixp4xx: Turn the NPE into a platform device ...
Diffstat (limited to 'arch/arm/mach-omap2/omap_hwmod.c')
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c210
1 files changed, 184 insertions, 26 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index baadddf9aad4..405ac24def05 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -155,6 +155,8 @@
155#include "soc.h" 155#include "soc.h"
156#include "common.h" 156#include "common.h"
157#include "clockdomain.h" 157#include "clockdomain.h"
158#include "hdq1w.h"
159#include "mmc.h"
158#include "powerdomain.h" 160#include "powerdomain.h"
159#include "cm2xxx.h" 161#include "cm2xxx.h"
160#include "cm3xxx.h" 162#include "cm3xxx.h"
@@ -165,6 +167,7 @@
165#include "prm33xx.h" 167#include "prm33xx.h"
166#include "prminst44xx.h" 168#include "prminst44xx.h"
167#include "pm.h" 169#include "pm.h"
170#include "wd_timer.h"
168 171
169/* Name of the OMAP hwmod for the MPU */ 172/* Name of the OMAP hwmod for the MPU */
170#define MPU_INITIATOR_NAME "mpu" 173#define MPU_INITIATOR_NAME "mpu"
@@ -205,6 +208,20 @@ struct clkctrl_provider {
205static LIST_HEAD(clkctrl_providers); 208static LIST_HEAD(clkctrl_providers);
206 209
207/** 210/**
211 * struct omap_hwmod_reset - IP specific reset functions
212 * @match: string to match against the module name
213 * @len: number of characters to match
214 * @reset: IP specific reset function
215 *
216 * Used only in cases where struct omap_hwmod is dynamically allocated.
217 */
218struct omap_hwmod_reset {
219 const char *match;
220 int len;
221 int (*reset)(struct omap_hwmod *oh);
222};
223
224/**
208 * struct omap_hwmod_soc_ops - fn ptrs for some SoC-specific operations 225 * struct omap_hwmod_soc_ops - fn ptrs for some SoC-specific operations
209 * @enable_module: function to enable a module (via MODULEMODE) 226 * @enable_module: function to enable a module (via MODULEMODE)
210 * @disable_module: function to disable a module (via MODULEMODE) 227 * @disable_module: function to disable a module (via MODULEMODE)
@@ -235,6 +252,7 @@ static struct omap_hwmod_soc_ops soc_ops;
235 252
236/* omap_hwmod_list contains all registered struct omap_hwmods */ 253/* omap_hwmod_list contains all registered struct omap_hwmods */
237static LIST_HEAD(omap_hwmod_list); 254static LIST_HEAD(omap_hwmod_list);
255static DEFINE_MUTEX(list_lock);
238 256
239/* mpu_oh: used to add/remove MPU initiator from sleepdep list */ 257/* mpu_oh: used to add/remove MPU initiator from sleepdep list */
240static struct omap_hwmod *mpu_oh; 258static struct omap_hwmod *mpu_oh;
@@ -2465,7 +2483,7 @@ static void _setup_iclk_autoidle(struct omap_hwmod *oh)
2465 */ 2483 */
2466static int _setup_reset(struct omap_hwmod *oh) 2484static int _setup_reset(struct omap_hwmod *oh)
2467{ 2485{
2468 int r; 2486 int r = 0;
2469 2487
2470 if (oh->_state != _HWMOD_STATE_INITIALIZED) 2488 if (oh->_state != _HWMOD_STATE_INITIALIZED)
2471 return -EINVAL; 2489 return -EINVAL;
@@ -2624,7 +2642,7 @@ static int _setup(struct omap_hwmod *oh, void *data)
2624 * that the copy process would be relatively complex due to the large number 2642 * that the copy process would be relatively complex due to the large number
2625 * of substructures. 2643 * of substructures.
2626 */ 2644 */
2627static int __init _register(struct omap_hwmod *oh) 2645static int _register(struct omap_hwmod *oh)
2628{ 2646{
2629 if (!oh || !oh->name || !oh->class || !oh->class->name || 2647 if (!oh || !oh->name || !oh->class || !oh->class->name ||
2630 (oh->_state != _HWMOD_STATE_UNKNOWN)) 2648 (oh->_state != _HWMOD_STATE_UNKNOWN))
@@ -2663,7 +2681,7 @@ static int __init _register(struct omap_hwmod *oh)
2663 * locking in this code. Changes to this assumption will require 2681 * locking in this code. Changes to this assumption will require
2664 * additional locking. Returns 0. 2682 * additional locking. Returns 0.
2665 */ 2683 */
2666static int __init _add_link(struct omap_hwmod_ocp_if *oi) 2684static int _add_link(struct omap_hwmod_ocp_if *oi)
2667{ 2685{
2668 pr_debug("omap_hwmod: %s -> %s: adding link\n", oi->master->name, 2686 pr_debug("omap_hwmod: %s -> %s: adding link\n", oi->master->name,
2669 oi->slave->name); 2687 oi->slave->name);
@@ -3241,9 +3259,10 @@ static int omap_hwmod_init_regbits(struct device *dev,
3241 * @sysc_offs: sysc register offset 3259 * @sysc_offs: sysc register offset
3242 * @syss_offs: syss register offset 3260 * @syss_offs: syss register offset
3243 */ 3261 */
3244int omap_hwmod_init_reg_offs(struct device *dev, 3262static int omap_hwmod_init_reg_offs(struct device *dev,
3245 const struct ti_sysc_module_data *data, 3263 const struct ti_sysc_module_data *data,
3246 s32 *rev_offs, s32 *sysc_offs, s32 *syss_offs) 3264 s32 *rev_offs, s32 *sysc_offs,
3265 s32 *syss_offs)
3247{ 3266{
3248 *rev_offs = -ENODEV; 3267 *rev_offs = -ENODEV;
3249 *sysc_offs = 0; 3268 *sysc_offs = 0;
@@ -3267,9 +3286,9 @@ int omap_hwmod_init_reg_offs(struct device *dev,
3267 * @data: module data 3286 * @data: module data
3268 * @sysc_flags: module configuration 3287 * @sysc_flags: module configuration
3269 */ 3288 */
3270int omap_hwmod_init_sysc_flags(struct device *dev, 3289static int omap_hwmod_init_sysc_flags(struct device *dev,
3271 const struct ti_sysc_module_data *data, 3290 const struct ti_sysc_module_data *data,
3272 u32 *sysc_flags) 3291 u32 *sysc_flags)
3273{ 3292{
3274 *sysc_flags = 0; 3293 *sysc_flags = 0;
3275 3294
@@ -3341,9 +3360,9 @@ int omap_hwmod_init_sysc_flags(struct device *dev,
3341 * @data: module data 3360 * @data: module data
3342 * @idlemodes: module supported idle modes 3361 * @idlemodes: module supported idle modes
3343 */ 3362 */
3344int omap_hwmod_init_idlemodes(struct device *dev, 3363static int omap_hwmod_init_idlemodes(struct device *dev,
3345 const struct ti_sysc_module_data *data, 3364 const struct ti_sysc_module_data *data,
3346 u32 *idlemodes) 3365 u32 *idlemodes)
3347{ 3366{
3348 *idlemodes = 0; 3367 *idlemodes = 0;
3349 3368
@@ -3434,14 +3453,18 @@ static int omap_hwmod_check_module(struct device *dev,
3434 * 3453 *
3435 * Note that the allocations here cannot use devm as ti-sysc can rebind. 3454 * Note that the allocations here cannot use devm as ti-sysc can rebind.
3436 */ 3455 */
3437int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh, 3456static int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh,
3438 const struct ti_sysc_module_data *data, 3457 const struct ti_sysc_module_data *data,
3439 struct sysc_regbits *sysc_fields, 3458 struct sysc_regbits *sysc_fields,
3440 s32 rev_offs, s32 sysc_offs, s32 syss_offs, 3459 s32 rev_offs, s32 sysc_offs,
3441 u32 sysc_flags, u32 idlemodes) 3460 s32 syss_offs, u32 sysc_flags,
3461 u32 idlemodes)
3442{ 3462{
3443 struct omap_hwmod_class_sysconfig *sysc; 3463 struct omap_hwmod_class_sysconfig *sysc;
3444 struct omap_hwmod_class *class; 3464 struct omap_hwmod_class *class = NULL;
3465 struct omap_hwmod_ocp_if *oi = NULL;
3466 struct clockdomain *clkdm = NULL;
3467 struct clk *clk = NULL;
3445 void __iomem *regs = NULL; 3468 void __iomem *regs = NULL;
3446 unsigned long flags; 3469 unsigned long flags;
3447 3470
@@ -3465,26 +3488,128 @@ int omap_hwmod_allocate_module(struct device *dev, struct omap_hwmod *oh,
3465 } 3488 }
3466 3489
3467 /* 3490 /*
3468 * We need new oh->class as the other devices in the same class 3491 * We may need a new oh->class as the other devices in the same class
3469 * may not yet have ioremapped their registers. 3492 * may not yet have ioremapped their registers.
3470 */ 3493 */
3471 class = kmemdup(oh->class, sizeof(*oh->class), GFP_KERNEL); 3494 if (oh->class->name && strcmp(oh->class->name, data->name)) {
3472 if (!class) 3495 class = kmemdup(oh->class, sizeof(*oh->class), GFP_KERNEL);
3473 return -ENOMEM; 3496 if (!class)
3497 return -ENOMEM;
3498 }
3474 3499
3475 class->sysc = sysc; 3500 if (list_empty(&oh->slave_ports)) {
3501 oi = kcalloc(1, sizeof(*oi), GFP_KERNEL);
3502 if (!oi)
3503 return -ENOMEM;
3504
3505 /*
3506 * Note that we assume interconnect interface clocks will be
3507 * managed by the interconnect driver for OCPIF_SWSUP_IDLE case
3508 * on omap24xx and omap3.
3509 */
3510 oi->slave = oh;
3511 oi->user = OCP_USER_MPU | OCP_USER_SDMA;
3512 }
3513
3514 if (!oh->_clk) {
3515 struct clk_hw_omap *hwclk;
3516
3517 clk = of_clk_get_by_name(dev->of_node, "fck");
3518 if (!IS_ERR(clk))
3519 clk_prepare(clk);
3520 else
3521 clk = NULL;
3522
3523 /*
3524 * Populate clockdomain based on dts clock. It is needed for
3525 * clkdm_deny_idle() and clkdm_allow_idle() until we have have
3526 * interconnect driver and reset driver capable of blocking
3527 * clockdomain idle during reset, enable and idle.
3528 */
3529 if (clk) {
3530 hwclk = to_clk_hw_omap(__clk_get_hw(clk));
3531 if (hwclk && hwclk->clkdm_name)
3532 clkdm = clkdm_lookup(hwclk->clkdm_name);
3533 }
3534
3535 /*
3536 * Note that we assume interconnect driver manages the clocks
3537 * and do not need to populate oh->_clk for dynamically
3538 * allocated modules.
3539 */
3540 clk_unprepare(clk);
3541 clk_put(clk);
3542 }
3476 3543
3477 spin_lock_irqsave(&oh->_lock, flags); 3544 spin_lock_irqsave(&oh->_lock, flags);
3478 if (regs) 3545 if (regs)
3479 oh->_mpu_rt_va = regs; 3546 oh->_mpu_rt_va = regs;
3480 oh->class = class; 3547 if (class)
3548 oh->class = class;
3549 oh->class->sysc = sysc;
3550 if (oi)
3551 _add_link(oi);
3552 if (clkdm)
3553 oh->clkdm = clkdm;
3481 oh->_state = _HWMOD_STATE_INITIALIZED; 3554 oh->_state = _HWMOD_STATE_INITIALIZED;
3555 oh->_postsetup_state = _HWMOD_STATE_DEFAULT;
3482 _setup(oh, NULL); 3556 _setup(oh, NULL);
3483 spin_unlock_irqrestore(&oh->_lock, flags); 3557 spin_unlock_irqrestore(&oh->_lock, flags);
3484 3558
3485 return 0; 3559 return 0;
3486} 3560}
3487 3561
3562static const struct omap_hwmod_reset omap24xx_reset_quirks[] = {
3563 { .match = "msdi", .len = 4, .reset = omap_msdi_reset, },
3564};
3565
3566static const struct omap_hwmod_reset dra7_reset_quirks[] = {
3567 { .match = "pcie", .len = 4, .reset = dra7xx_pciess_reset, },
3568};
3569
3570static const struct omap_hwmod_reset omap_reset_quirks[] = {
3571 { .match = "dss", .len = 3, .reset = omap_dss_reset, },
3572 { .match = "hdq1w", .len = 5, .reset = omap_hdq1w_reset, },
3573 { .match = "i2c", .len = 3, .reset = omap_i2c_reset, },
3574 { .match = "wd_timer", .len = 8, .reset = omap2_wd_timer_reset, },
3575};
3576
3577static void
3578omap_hwmod_init_reset_quirk(struct device *dev, struct omap_hwmod *oh,
3579 const struct ti_sysc_module_data *data,
3580 const struct omap_hwmod_reset *quirks,
3581 int quirks_sz)
3582{
3583 const struct omap_hwmod_reset *quirk;
3584 int i;
3585
3586 for (i = 0; i < quirks_sz; i++) {
3587 quirk = &quirks[i];
3588 if (!strncmp(data->name, quirk->match, quirk->len)) {
3589 oh->class->reset = quirk->reset;
3590
3591 return;
3592 }
3593 }
3594}
3595
3596static void
3597omap_hwmod_init_reset_quirks(struct device *dev, struct omap_hwmod *oh,
3598 const struct ti_sysc_module_data *data)
3599{
3600 if (soc_is_omap24xx())
3601 omap_hwmod_init_reset_quirk(dev, oh, data,
3602 omap24xx_reset_quirks,
3603 ARRAY_SIZE(omap24xx_reset_quirks));
3604
3605 if (soc_is_dra7xx())
3606 omap_hwmod_init_reset_quirk(dev, oh, data, dra7_reset_quirks,
3607 ARRAY_SIZE(dra7_reset_quirks));
3608
3609 omap_hwmod_init_reset_quirk(dev, oh, data, omap_reset_quirks,
3610 ARRAY_SIZE(omap_reset_quirks));
3611}
3612
3488/** 3613/**
3489 * omap_hwmod_init_module - initialize new module 3614 * omap_hwmod_init_module - initialize new module
3490 * @dev: struct device 3615 * @dev: struct device
@@ -3505,8 +3630,31 @@ int omap_hwmod_init_module(struct device *dev,
3505 return -EINVAL; 3630 return -EINVAL;
3506 3631
3507 oh = _lookup(data->name); 3632 oh = _lookup(data->name);
3508 if (!oh) 3633 if (!oh) {
3509 return -ENODEV; 3634 oh = kzalloc(sizeof(*oh), GFP_KERNEL);
3635 if (!oh)
3636 return -ENOMEM;
3637
3638 oh->name = data->name;
3639 oh->_state = _HWMOD_STATE_UNKNOWN;
3640 lockdep_register_key(&oh->hwmod_key);
3641
3642 /* Unused, can be handled by PRM driver handling resets */
3643 oh->prcm.omap4.flags = HWMOD_OMAP4_NO_CONTEXT_LOSS_BIT;
3644
3645 oh->class = kzalloc(sizeof(*oh->class), GFP_KERNEL);
3646 if (!oh->class) {
3647 kfree(oh);
3648 return -ENOMEM;
3649 }
3650
3651 omap_hwmod_init_reset_quirks(dev, oh, data);
3652
3653 oh->class->name = data->name;
3654 mutex_lock(&list_lock);
3655 error = _register(oh);
3656 mutex_unlock(&list_lock);
3657 }
3510 3658
3511 cookie->data = oh; 3659 cookie->data = oh;
3512 3660
@@ -3527,10 +3675,20 @@ int omap_hwmod_init_module(struct device *dev,
3527 if (error) 3675 if (error)
3528 return error; 3676 return error;
3529 3677
3678 if (data->cfg->quirks & SYSC_QUIRK_NO_IDLE)
3679 oh->flags |= HWMOD_NO_IDLE;
3530 if (data->cfg->quirks & SYSC_QUIRK_NO_IDLE_ON_INIT) 3680 if (data->cfg->quirks & SYSC_QUIRK_NO_IDLE_ON_INIT)
3531 oh->flags |= HWMOD_INIT_NO_IDLE; 3681 oh->flags |= HWMOD_INIT_NO_IDLE;
3532 if (data->cfg->quirks & SYSC_QUIRK_NO_RESET_ON_INIT) 3682 if (data->cfg->quirks & SYSC_QUIRK_NO_RESET_ON_INIT)
3533 oh->flags |= HWMOD_INIT_NO_RESET; 3683 oh->flags |= HWMOD_INIT_NO_RESET;
3684 if (data->cfg->quirks & SYSC_QUIRK_USE_CLOCKACT)
3685 oh->flags |= HWMOD_SET_DEFAULT_CLOCKACT;
3686 if (data->cfg->quirks & SYSC_QUIRK_SWSUP_SIDLE)
3687 oh->flags |= HWMOD_SWSUP_SIDLE;
3688 if (data->cfg->quirks & SYSC_QUIRK_SWSUP_SIDLE_ACT)
3689 oh->flags |= HWMOD_SWSUP_SIDLE_ACT;
3690 if (data->cfg->quirks & SYSC_QUIRK_SWSUP_MSTANDBY)
3691 oh->flags |= HWMOD_SWSUP_MSTANDBY;
3534 3692
3535 error = omap_hwmod_check_module(dev, oh, data, sysc_fields, 3693 error = omap_hwmod_check_module(dev, oh, data, sysc_fields,
3536 rev_offs, sysc_offs, syss_offs, 3694 rev_offs, sysc_offs, syss_offs,