diff options
author | Tony Lindgren <tony@atomide.com> | 2017-12-15 12:41:23 -0500 |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2017-12-21 10:28:54 -0500 |
commit | c5a2de97fbd2979fab291fb048084d3fddd322dd (patch) | |
tree | 45dfca45e1e9c683c961cb20936d464a2380f673 | |
parent | 566a9b05e1fa47dcfb93a4459145d0fdc06d3046 (diff) |
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 { | |||
39 | 39 | ||
40 | static const char * const clock_names[] = { "fck", "ick", }; | 40 | static const char * const clock_names[] = { "fck", "ick", }; |
41 | 41 | ||
42 | #define SYSC_IDLEMODE_MASK 3 | ||
43 | #define SYSC_CLOCKACTIVITY_MASK 3 | ||
44 | |||
42 | /** | 45 | /** |
43 | * struct sysc - TI sysc interconnect target module registers and capabilities | 46 | * struct sysc - TI sysc interconnect target module registers and capabilities |
44 | * @dev: struct device pointer | 47 | * @dev: struct device pointer |
@@ -517,6 +520,91 @@ static int sysc_init_module(struct sysc *ddata) | |||
517 | return 0; | 520 | return 0; |
518 | } | 521 | } |
519 | 522 | ||
523 | static int sysc_init_sysc_mask(struct sysc *ddata) | ||
524 | { | ||
525 | struct device_node *np = ddata->dev->of_node; | ||
526 | int error; | ||
527 | u32 val; | ||
528 | |||
529 | error = of_property_read_u32(np, "ti,sysc-mask", &val); | ||
530 | if (error) | ||
531 | return 0; | ||
532 | |||
533 | if (val) | ||
534 | ddata->cfg.sysc_val = val & ddata->cap->sysc_mask; | ||
535 | else | ||
536 | ddata->cfg.sysc_val = ddata->cap->sysc_mask; | ||
537 | |||
538 | return 0; | ||
539 | } | ||
540 | |||
541 | static int sysc_init_idlemode(struct sysc *ddata, u8 *idlemodes, | ||
542 | const char *name) | ||
543 | { | ||
544 | struct device_node *np = ddata->dev->of_node; | ||
545 | struct property *prop; | ||
546 | const __be32 *p; | ||
547 | u32 val; | ||
548 | |||
549 | of_property_for_each_u32(np, name, prop, p, val) { | ||
550 | if (val >= SYSC_NR_IDLEMODES) { | ||
551 | dev_err(ddata->dev, "invalid idlemode: %i\n", val); | ||
552 | return -EINVAL; | ||
553 | } | ||
554 | *idlemodes |= (1 << val); | ||
555 | } | ||
556 | |||
557 | return 0; | ||
558 | } | ||
559 | |||
560 | static int sysc_init_idlemodes(struct sysc *ddata) | ||
561 | { | ||
562 | int error; | ||
563 | |||
564 | error = sysc_init_idlemode(ddata, &ddata->cfg.midlemodes, | ||
565 | "ti,sysc-midle"); | ||
566 | if (error) | ||
567 | return error; | ||
568 | |||
569 | error = sysc_init_idlemode(ddata, &ddata->cfg.sidlemodes, | ||
570 | "ti,sysc-sidle"); | ||
571 | if (error) | ||
572 | return error; | ||
573 | |||
574 | return 0; | ||
575 | } | ||
576 | |||
577 | /* | ||
578 | * Only some devices on omap4 and later have SYSCONFIG reset done | ||
579 | * bit. We can detect this if there is no SYSSTATUS at all, or the | ||
580 | * SYSTATUS bit 0 is not used. Note that some SYSSTATUS registers | ||
581 | * have multiple bits for the child devices like OHCI and EHCI. | ||
582 | * Depends on SYSC being parsed first. | ||
583 | */ | ||
584 | static int sysc_init_syss_mask(struct sysc *ddata) | ||
585 | { | ||
586 | struct device_node *np = ddata->dev->of_node; | ||
587 | int error; | ||
588 | u32 val; | ||
589 | |||
590 | error = of_property_read_u32(np, "ti,syss-mask", &val); | ||
591 | if (error) { | ||
592 | if ((ddata->cap->type == TI_SYSC_OMAP4 || | ||
593 | ddata->cap->type == TI_SYSC_OMAP4_TIMER) && | ||
594 | (ddata->cfg.sysc_val & SYSC_OMAP4_SOFTRESET)) | ||
595 | ddata->cfg.quirks |= SYSC_QUIRK_RESET_STATUS; | ||
596 | |||
597 | return 0; | ||
598 | } | ||
599 | |||
600 | if (!(val & 1) && (ddata->cfg.sysc_val & SYSC_OMAP4_SOFTRESET)) | ||
601 | ddata->cfg.quirks |= SYSC_QUIRK_RESET_STATUS; | ||
602 | |||
603 | ddata->cfg.syss_mask = val; | ||
604 | |||
605 | return 0; | ||
606 | } | ||
607 | |||
520 | /* Device tree configured quirks */ | 608 | /* Device tree configured quirks */ |
521 | struct sysc_dts_quirk { | 609 | struct sysc_dts_quirk { |
522 | const char *name; | 610 | const char *name; |
@@ -820,6 +908,18 @@ static int sysc_probe(struct platform_device *pdev) | |||
820 | if (error) | 908 | if (error) |
821 | goto unprepare; | 909 | goto unprepare; |
822 | 910 | ||
911 | error = sysc_init_sysc_mask(ddata); | ||
912 | if (error) | ||
913 | goto unprepare; | ||
914 | |||
915 | error = sysc_init_idlemodes(ddata); | ||
916 | if (error) | ||
917 | goto unprepare; | ||
918 | |||
919 | error = sysc_init_syss_mask(ddata); | ||
920 | if (error) | ||
921 | goto unprepare; | ||
922 | |||
823 | pm_runtime_enable(ddata->dev); | 923 | pm_runtime_enable(ddata->dev); |
824 | 924 | ||
825 | error = sysc_init_module(ddata); | 925 | 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 { | |||
41 | s8 emufree_shift; | 41 | s8 emufree_shift; |
42 | }; | 42 | }; |
43 | 43 | ||
44 | #define SYSC_QUIRK_RESET_STATUS BIT(7) | ||
44 | #define SYSC_QUIRK_NO_IDLE_ON_INIT BIT(6) | 45 | #define SYSC_QUIRK_NO_IDLE_ON_INIT BIT(6) |
45 | #define SYSC_QUIRK_NO_RESET_ON_INIT BIT(5) | 46 | #define SYSC_QUIRK_NO_RESET_ON_INIT BIT(5) |
46 | #define SYSC_QUIRK_OPT_CLKS_NEEDED BIT(4) | 47 | #define SYSC_QUIRK_OPT_CLKS_NEEDED BIT(4) |
@@ -49,6 +50,8 @@ struct sysc_regbits { | |||
49 | #define SYSC_QUIRK_UNCACHED BIT(1) | 50 | #define SYSC_QUIRK_UNCACHED BIT(1) |
50 | #define SYSC_QUIRK_USE_CLOCKACT BIT(0) | 51 | #define SYSC_QUIRK_USE_CLOCKACT BIT(0) |
51 | 52 | ||
53 | #define SYSC_NR_IDLEMODES 4 | ||
54 | |||
52 | /** | 55 | /** |
53 | * struct sysc_capabilities - capabilities for an interconnect target module | 56 | * struct sysc_capabilities - capabilities for an interconnect target module |
54 | * | 57 | * |
@@ -65,10 +68,17 @@ struct sysc_capabilities { | |||
65 | 68 | ||
66 | /** | 69 | /** |
67 | * struct sysc_config - configuration for an interconnect target module | 70 | * struct sysc_config - configuration for an interconnect target module |
71 | * @sysc_val: configured value for sysc register | ||
72 | * @midlemodes: bitmask of supported master idle modes | ||
73 | * @sidlemodes: bitmask of supported master idle modes | ||
68 | * @srst_udelay: optional delay needed after OCP soft reset | 74 | * @srst_udelay: optional delay needed after OCP soft reset |
69 | * @quirks: bitmask of enabled quirks | 75 | * @quirks: bitmask of enabled quirks |
70 | */ | 76 | */ |
71 | struct sysc_config { | 77 | struct sysc_config { |
78 | u32 sysc_val; | ||
79 | u32 syss_mask; | ||
80 | u8 midlemodes; | ||
81 | u8 sidlemodes; | ||
72 | u8 srst_udelay; | 82 | u8 srst_udelay; |
73 | u32 quirks; | 83 | u32 quirks; |
74 | }; | 84 | }; |