aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTony Lindgren <tony@atomide.com>2017-12-15 12:41:19 -0500
committerTony Lindgren <tony@atomide.com>2017-12-21 10:28:54 -0500
commit566a9b05e1fa47dcfb93a4459145d0fdc06d3046 (patch)
tree6b7d9d55fd4872ce316462906d5c10a6286d2ccb
parenta7199e2b91ded41adbb6fd384a85e358d25f48c8 (diff)
bus: ti-sysc: Handle module quirks based dts configuration
Let's configure few module quirks via device tree using the properties for "ti,no-idle-on-init", "ti,no-reset-on-init" and "ti,sysc-delay-us". Let's also reorder the probe a bit so we have pdata available earlier, and move the PM runtime calls to sysc_init_module() from sysc_read_revision(). Signed-off-by: Tony Lindgren <tony@atomide.com>
-rw-r--r--drivers/bus/ti-sysc.c114
-rw-r--r--include/linux/platform_data/ti-sysc.h6
2 files changed, 102 insertions, 18 deletions
diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c
index 4c1e59e53a0c..090612460cef 100644
--- a/drivers/bus/ti-sysc.c
+++ b/drivers/bus/ti-sysc.c
@@ -50,6 +50,8 @@ static const char * const clock_names[] = { "fck", "ick", };
50 * @legacy_mode: configured for legacy mode if set 50 * @legacy_mode: configured for legacy mode if set
51 * @cap: interconnect target module capabilities 51 * @cap: interconnect target module capabilities
52 * @cfg: interconnect target module configuration 52 * @cfg: interconnect target module configuration
53 * @name: name if available
54 * @revision: interconnect target module revision
53 */ 55 */
54struct sysc { 56struct sysc {
55 struct device *dev; 57 struct device *dev;
@@ -61,12 +63,32 @@ struct sysc {
61 const char *legacy_mode; 63 const char *legacy_mode;
62 const struct sysc_capabilities *cap; 64 const struct sysc_capabilities *cap;
63 struct sysc_config cfg; 65 struct sysc_config cfg;
66 const char *name;
67 u32 revision;
64}; 68};
65 69
70static u32 sysc_read(struct sysc *ddata, int offset)
71{
72 if (ddata->cfg.quirks & SYSC_QUIRK_16BIT) {
73 u32 val;
74
75 val = readw_relaxed(ddata->module_va + offset);
76 val |= (readw_relaxed(ddata->module_va + offset + 4) << 16);
77
78 return val;
79 }
80
81 return readl_relaxed(ddata->module_va + offset);
82}
83
66static u32 sysc_read_revision(struct sysc *ddata) 84static u32 sysc_read_revision(struct sysc *ddata)
67{ 85{
68 return readl_relaxed(ddata->module_va + 86 int offset = ddata->offsets[SYSC_REVISION];
69 ddata->offsets[SYSC_REVISION]); 87
88 if (offset < 0)
89 return 0;
90
91 return sysc_read(ddata, offset);
70} 92}
71 93
72static int sysc_get_one_clock(struct sysc *ddata, 94static int sysc_get_one_clock(struct sysc *ddata,
@@ -393,22 +415,12 @@ static int sysc_map_and_check_registers(struct sysc *ddata)
393 */ 415 */
394static int sysc_show_rev(char *bufp, struct sysc *ddata) 416static int sysc_show_rev(char *bufp, struct sysc *ddata)
395{ 417{
396 int error, len; 418 int len;
397 419
398 if (ddata->offsets[SYSC_REVISION] < 0) 420 if (ddata->offsets[SYSC_REVISION] < 0)
399 return sprintf(bufp, ":NA"); 421 return sprintf(bufp, ":NA");
400 422
401 error = pm_runtime_get_sync(ddata->dev); 423 len = sprintf(bufp, ":%08x", ddata->revision);
402 if (error < 0) {
403 pm_runtime_put_noidle(ddata->dev);
404
405 return 0;
406 }
407
408 len = sprintf(bufp, ":%08x", sysc_read_revision(ddata));
409
410 pm_runtime_mark_last_busy(ddata->dev);
411 pm_runtime_put_autosuspend(ddata->dev);
412 424
413 return len; 425 return len;
414} 426}
@@ -488,6 +500,66 @@ static const struct dev_pm_ops sysc_pm_ops = {
488 NULL) 500 NULL)
489}; 501};
490 502
503/* At this point the module is configured enough to read the revision */
504static int sysc_init_module(struct sysc *ddata)
505{
506 int error;
507
508 error = pm_runtime_get_sync(ddata->dev);
509 if (error < 0) {
510 pm_runtime_put_noidle(ddata->dev);
511
512 return 0;
513 }
514 ddata->revision = sysc_read_revision(ddata);
515 pm_runtime_put_sync(ddata->dev);
516
517 return 0;
518}
519
520/* Device tree configured quirks */
521struct sysc_dts_quirk {
522 const char *name;
523 u32 mask;
524};
525
526static const struct sysc_dts_quirk sysc_dts_quirks[] = {
527 { .name = "ti,no-idle-on-init",
528 .mask = SYSC_QUIRK_NO_IDLE_ON_INIT, },
529 { .name = "ti,no-reset-on-init",
530 .mask = SYSC_QUIRK_NO_RESET_ON_INIT, },
531};
532
533static int sysc_init_dts_quirks(struct sysc *ddata)
534{
535 struct device_node *np = ddata->dev->of_node;
536 const struct property *prop;
537 int i, len, error;
538 u32 val;
539
540 ddata->legacy_mode = of_get_property(np, "ti,hwmods", NULL);
541
542 for (i = 0; i < ARRAY_SIZE(sysc_dts_quirks); i++) {
543 prop = of_get_property(np, sysc_dts_quirks[i].name, &len);
544 if (!prop)
545 break;
546
547 ddata->cfg.quirks |= sysc_dts_quirks[i].mask;
548 }
549
550 error = of_property_read_u32(np, "ti,sysc-delay-us", &val);
551 if (!error) {
552 if (val > 255) {
553 dev_warn(ddata->dev, "bad ti,sysc-delay-us: %i\n",
554 val);
555 }
556
557 ddata->cfg.srst_udelay = (u8)val;
558 }
559
560 return 0;
561}
562
491static void sysc_unprepare(struct sysc *ddata) 563static void sysc_unprepare(struct sysc *ddata)
492{ 564{
493 int i; 565 int i;
@@ -722,7 +794,6 @@ static int sysc_init_match(struct sysc *ddata)
722 794
723static int sysc_probe(struct platform_device *pdev) 795static int sysc_probe(struct platform_device *pdev)
724{ 796{
725 struct device_node *np = pdev->dev.of_node;
726 struct sysc *ddata; 797 struct sysc *ddata;
727 int error; 798 int error;
728 799
@@ -731,12 +802,16 @@ static int sysc_probe(struct platform_device *pdev)
731 return -ENOMEM; 802 return -ENOMEM;
732 803
733 ddata->dev = &pdev->dev; 804 ddata->dev = &pdev->dev;
734 ddata->legacy_mode = of_get_property(np, "ti,hwmods", NULL); 805 platform_set_drvdata(pdev, ddata);
735 806
736 error = sysc_init_match(ddata); 807 error = sysc_init_match(ddata);
737 if (error) 808 if (error)
738 return error; 809 return error;
739 810
811 error = sysc_init_dts_quirks(ddata);
812 if (error)
813 goto unprepare;
814
740 error = sysc_get_clocks(ddata); 815 error = sysc_get_clocks(ddata);
741 if (error) 816 if (error)
742 return error; 817 return error;
@@ -745,9 +820,12 @@ static int sysc_probe(struct platform_device *pdev)
745 if (error) 820 if (error)
746 goto unprepare; 821 goto unprepare;
747 822
748 platform_set_drvdata(pdev, ddata);
749
750 pm_runtime_enable(ddata->dev); 823 pm_runtime_enable(ddata->dev);
824
825 error = sysc_init_module(ddata);
826 if (error)
827 goto unprepare;
828
751 error = pm_runtime_get_sync(ddata->dev); 829 error = pm_runtime_get_sync(ddata->dev);
752 if (error < 0) { 830 if (error < 0) {
753 pm_runtime_put_noidle(ddata->dev); 831 pm_runtime_put_noidle(ddata->dev);
diff --git a/include/linux/platform_data/ti-sysc.h b/include/linux/platform_data/ti-sysc.h
index 059be6f6fa94..28e5a61d4abc 100644
--- a/include/linux/platform_data/ti-sysc.h
+++ b/include/linux/platform_data/ti-sysc.h
@@ -41,6 +41,10 @@ struct sysc_regbits {
41 s8 emufree_shift; 41 s8 emufree_shift;
42}; 42};
43 43
44#define SYSC_QUIRK_NO_IDLE_ON_INIT BIT(6)
45#define SYSC_QUIRK_NO_RESET_ON_INIT BIT(5)
46#define SYSC_QUIRK_OPT_CLKS_NEEDED BIT(4)
47#define SYSC_QUIRK_OPT_CLKS_IN_RESET BIT(3)
44#define SYSC_QUIRK_16BIT BIT(2) 48#define SYSC_QUIRK_16BIT BIT(2)
45#define SYSC_QUIRK_UNCACHED BIT(1) 49#define SYSC_QUIRK_UNCACHED BIT(1)
46#define SYSC_QUIRK_USE_CLOCKACT BIT(0) 50#define SYSC_QUIRK_USE_CLOCKACT BIT(0)
@@ -61,9 +65,11 @@ struct sysc_capabilities {
61 65
62/** 66/**
63 * struct sysc_config - configuration for an interconnect target module 67 * struct sysc_config - configuration for an interconnect target module
68 * @srst_udelay: optional delay needed after OCP soft reset
64 * @quirks: bitmask of enabled quirks 69 * @quirks: bitmask of enabled quirks
65 */ 70 */
66struct sysc_config { 71struct sysc_config {
72 u8 srst_udelay;
67 u32 quirks; 73 u32 quirks;
68}; 74};
69 75