diff options
Diffstat (limited to 'arch/arm/mach-omap2/omap_hwmod.c')
-rw-r--r-- | arch/arm/mach-omap2/omap_hwmod.c | 121 |
1 files changed, 65 insertions, 56 deletions
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 2c12e8cd7183..95c9a5f774e1 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c | |||
@@ -2,12 +2,12 @@ | |||
2 | * omap_hwmod implementation for OMAP2/3/4 | 2 | * omap_hwmod implementation for OMAP2/3/4 |
3 | * | 3 | * |
4 | * Copyright (C) 2009 Nokia Corporation | 4 | * Copyright (C) 2009 Nokia Corporation |
5 | * Paul Walmsley | ||
6 | * With fixes and testing from Kevin Hilman | ||
7 | * | 5 | * |
8 | * Created in collaboration with (alphabetical order): Benoit Cousson, | 6 | * Paul Walmsley, BenoƮt Cousson, Kevin Hilman |
9 | * Kevin Hilman, Tony Lindgren, Rajendra Nayak, Vikram Pandita, Sakari | 7 | * |
10 | * Poussa, Anand Sawant, Santosh Shilimkar, Richard Woodruff | 8 | * Created in collaboration with (alphabetical order): Thara Gopinath, |
9 | * Tony Lindgren, Rajendra Nayak, Vikram Pandita, Sakari Poussa, Anand | ||
10 | * Sawant, Santosh Shilimkar, Richard Woodruff | ||
11 | * | 11 | * |
12 | * This program is free software; you can redistribute it and/or modify | 12 | * This program is free software; you can redistribute it and/or modify |
13 | * it under the terms of the GNU General Public License version 2 as | 13 | * it under the terms of the GNU General Public License version 2 as |
@@ -57,7 +57,7 @@ | |||
57 | #define MAX_MODULE_RESET_WAIT 10000 | 57 | #define MAX_MODULE_RESET_WAIT 10000 |
58 | 58 | ||
59 | /* Name of the OMAP hwmod for the MPU */ | 59 | /* Name of the OMAP hwmod for the MPU */ |
60 | #define MPU_INITIATOR_NAME "mpu_hwmod" | 60 | #define MPU_INITIATOR_NAME "mpu" |
61 | 61 | ||
62 | /* omap_hwmod_list contains all registered struct omap_hwmods */ | 62 | /* omap_hwmod_list contains all registered struct omap_hwmods */ |
63 | static LIST_HEAD(omap_hwmod_list); | 63 | static LIST_HEAD(omap_hwmod_list); |
@@ -403,21 +403,20 @@ static int _del_initiator_dep(struct omap_hwmod *oh, struct omap_hwmod *init_oh) | |||
403 | */ | 403 | */ |
404 | static int _init_main_clk(struct omap_hwmod *oh) | 404 | static int _init_main_clk(struct omap_hwmod *oh) |
405 | { | 405 | { |
406 | struct clk *c; | ||
407 | int ret = 0; | 406 | int ret = 0; |
408 | 407 | ||
409 | if (!oh->main_clk) | 408 | if (!oh->main_clk) |
410 | return 0; | 409 | return 0; |
411 | 410 | ||
412 | c = omap_clk_get_by_name(oh->main_clk); | 411 | oh->_clk = omap_clk_get_by_name(oh->main_clk); |
413 | WARN(IS_ERR(c), "omap_hwmod: %s: cannot clk_get main_clk %s\n", | 412 | if (!oh->_clk) |
414 | oh->name, oh->main_clk); | 413 | pr_warning("omap_hwmod: %s: cannot clk_get main_clk %s\n", |
415 | if (IS_ERR(c)) | 414 | oh->name, oh->main_clk); |
416 | ret = -EINVAL; | 415 | return -EINVAL; |
417 | oh->_clk = c; | ||
418 | 416 | ||
419 | WARN(!c->clkdm, "omap_hwmod: %s: missing clockdomain for %s.\n", | 417 | if (!oh->_clk->clkdm) |
420 | oh->main_clk, c->name); | 418 | pr_warning("omap_hwmod: %s: missing clockdomain for %s.\n", |
419 | oh->main_clk, oh->_clk->name); | ||
421 | 420 | ||
422 | return ret; | 421 | return ret; |
423 | } | 422 | } |
@@ -431,7 +430,6 @@ static int _init_main_clk(struct omap_hwmod *oh) | |||
431 | */ | 430 | */ |
432 | static int _init_interface_clks(struct omap_hwmod *oh) | 431 | static int _init_interface_clks(struct omap_hwmod *oh) |
433 | { | 432 | { |
434 | struct omap_hwmod_ocp_if *os; | ||
435 | struct clk *c; | 433 | struct clk *c; |
436 | int i; | 434 | int i; |
437 | int ret = 0; | 435 | int ret = 0; |
@@ -439,14 +437,16 @@ static int _init_interface_clks(struct omap_hwmod *oh) | |||
439 | if (oh->slaves_cnt == 0) | 437 | if (oh->slaves_cnt == 0) |
440 | return 0; | 438 | return 0; |
441 | 439 | ||
442 | for (i = 0, os = *oh->slaves; i < oh->slaves_cnt; i++, os++) { | 440 | for (i = 0; i < oh->slaves_cnt; i++) { |
441 | struct omap_hwmod_ocp_if *os = oh->slaves[i]; | ||
442 | |||
443 | if (!os->clk) | 443 | if (!os->clk) |
444 | continue; | 444 | continue; |
445 | 445 | ||
446 | c = omap_clk_get_by_name(os->clk); | 446 | c = omap_clk_get_by_name(os->clk); |
447 | WARN(IS_ERR(c), "omap_hwmod: %s: cannot clk_get " | 447 | if (!c) |
448 | "interface_clk %s\n", oh->name, os->clk); | 448 | pr_warning("omap_hwmod: %s: cannot clk_get interface_clk %s\n", |
449 | if (IS_ERR(c)) | 449 | oh->name, os->clk); |
450 | ret = -EINVAL; | 450 | ret = -EINVAL; |
451 | os->_clk = c; | 451 | os->_clk = c; |
452 | } | 452 | } |
@@ -470,9 +470,9 @@ static int _init_opt_clks(struct omap_hwmod *oh) | |||
470 | 470 | ||
471 | for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++) { | 471 | for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++) { |
472 | c = omap_clk_get_by_name(oc->clk); | 472 | c = omap_clk_get_by_name(oc->clk); |
473 | WARN(IS_ERR(c), "omap_hwmod: %s: cannot clk_get opt_clk " | 473 | if (!c) |
474 | "%s\n", oh->name, oc->clk); | 474 | pr_warning("omap_hwmod: %s: cannot clk_get opt_clk %s\n", |
475 | if (IS_ERR(c)) | 475 | oh->name, oc->clk); |
476 | ret = -EINVAL; | 476 | ret = -EINVAL; |
477 | oc->_clk = c; | 477 | oc->_clk = c; |
478 | } | 478 | } |
@@ -489,19 +489,19 @@ static int _init_opt_clks(struct omap_hwmod *oh) | |||
489 | */ | 489 | */ |
490 | static int _enable_clocks(struct omap_hwmod *oh) | 490 | static int _enable_clocks(struct omap_hwmod *oh) |
491 | { | 491 | { |
492 | struct omap_hwmod_ocp_if *os; | ||
493 | int i; | 492 | int i; |
494 | 493 | ||
495 | pr_debug("omap_hwmod: %s: enabling clocks\n", oh->name); | 494 | pr_debug("omap_hwmod: %s: enabling clocks\n", oh->name); |
496 | 495 | ||
497 | if (oh->_clk && !IS_ERR(oh->_clk)) | 496 | if (oh->_clk) |
498 | clk_enable(oh->_clk); | 497 | clk_enable(oh->_clk); |
499 | 498 | ||
500 | if (oh->slaves_cnt > 0) { | 499 | if (oh->slaves_cnt > 0) { |
501 | for (i = 0, os = *oh->slaves; i < oh->slaves_cnt; i++, os++) { | 500 | for (i = 0; i < oh->slaves_cnt; i++) { |
501 | struct omap_hwmod_ocp_if *os = oh->slaves[i]; | ||
502 | struct clk *c = os->_clk; | 502 | struct clk *c = os->_clk; |
503 | 503 | ||
504 | if (c && !IS_ERR(c) && (os->flags & OCPIF_SWSUP_IDLE)) | 504 | if (c && (os->flags & OCPIF_SWSUP_IDLE)) |
505 | clk_enable(c); | 505 | clk_enable(c); |
506 | } | 506 | } |
507 | } | 507 | } |
@@ -519,19 +519,19 @@ static int _enable_clocks(struct omap_hwmod *oh) | |||
519 | */ | 519 | */ |
520 | static int _disable_clocks(struct omap_hwmod *oh) | 520 | static int _disable_clocks(struct omap_hwmod *oh) |
521 | { | 521 | { |
522 | struct omap_hwmod_ocp_if *os; | ||
523 | int i; | 522 | int i; |
524 | 523 | ||
525 | pr_debug("omap_hwmod: %s: disabling clocks\n", oh->name); | 524 | pr_debug("omap_hwmod: %s: disabling clocks\n", oh->name); |
526 | 525 | ||
527 | if (oh->_clk && !IS_ERR(oh->_clk)) | 526 | if (oh->_clk) |
528 | clk_disable(oh->_clk); | 527 | clk_disable(oh->_clk); |
529 | 528 | ||
530 | if (oh->slaves_cnt > 0) { | 529 | if (oh->slaves_cnt > 0) { |
531 | for (i = 0, os = *oh->slaves; i < oh->slaves_cnt; i++, os++) { | 530 | for (i = 0; i < oh->slaves_cnt; i++) { |
531 | struct omap_hwmod_ocp_if *os = oh->slaves[i]; | ||
532 | struct clk *c = os->_clk; | 532 | struct clk *c = os->_clk; |
533 | 533 | ||
534 | if (c && !IS_ERR(c) && (os->flags & OCPIF_SWSUP_IDLE)) | 534 | if (c && (os->flags & OCPIF_SWSUP_IDLE)) |
535 | clk_disable(c); | 535 | clk_disable(c); |
536 | } | 536 | } |
537 | } | 537 | } |
@@ -550,14 +550,15 @@ static int _disable_clocks(struct omap_hwmod *oh) | |||
550 | */ | 550 | */ |
551 | static int _find_mpu_port_index(struct omap_hwmod *oh) | 551 | static int _find_mpu_port_index(struct omap_hwmod *oh) |
552 | { | 552 | { |
553 | struct omap_hwmod_ocp_if *os; | ||
554 | int i; | 553 | int i; |
555 | int found = 0; | 554 | int found = 0; |
556 | 555 | ||
557 | if (!oh || oh->slaves_cnt == 0) | 556 | if (!oh || oh->slaves_cnt == 0) |
558 | return -EINVAL; | 557 | return -EINVAL; |
559 | 558 | ||
560 | for (i = 0, os = *oh->slaves; i < oh->slaves_cnt; i++, os++) { | 559 | for (i = 0; i < oh->slaves_cnt; i++) { |
560 | struct omap_hwmod_ocp_if *os = oh->slaves[i]; | ||
561 | |||
561 | if (os->user & OCP_USER_MPU) { | 562 | if (os->user & OCP_USER_MPU) { |
562 | found = 1; | 563 | found = 1; |
563 | break; | 564 | break; |
@@ -592,7 +593,7 @@ static void __iomem *_find_mpu_rt_base(struct omap_hwmod *oh, u8 index) | |||
592 | if (!oh || oh->slaves_cnt == 0) | 593 | if (!oh || oh->slaves_cnt == 0) |
593 | return NULL; | 594 | return NULL; |
594 | 595 | ||
595 | os = *oh->slaves + index; | 596 | os = oh->slaves[index]; |
596 | 597 | ||
597 | for (i = 0, mem = os->addr; i < os->addr_cnt; i++, mem++) { | 598 | for (i = 0, mem = os->addr; i < os->addr_cnt; i++, mem++) { |
598 | if (mem->flags & ADDR_TYPE_RT) { | 599 | if (mem->flags & ADDR_TYPE_RT) { |
@@ -780,9 +781,10 @@ static int _init_clocks(struct omap_hwmod *oh) | |||
780 | ret |= _init_interface_clks(oh); | 781 | ret |= _init_interface_clks(oh); |
781 | ret |= _init_opt_clks(oh); | 782 | ret |= _init_opt_clks(oh); |
782 | 783 | ||
783 | oh->_state = _HWMOD_STATE_CLKS_INITED; | 784 | if (!ret) |
785 | oh->_state = _HWMOD_STATE_CLKS_INITED; | ||
784 | 786 | ||
785 | return ret; | 787 | return 0; |
786 | } | 788 | } |
787 | 789 | ||
788 | /** | 790 | /** |
@@ -805,9 +807,9 @@ static int _wait_target_ready(struct omap_hwmod *oh) | |||
805 | if (oh->_int_flags & _HWMOD_NO_MPU_PORT) | 807 | if (oh->_int_flags & _HWMOD_NO_MPU_PORT) |
806 | return 0; | 808 | return 0; |
807 | 809 | ||
808 | os = *oh->slaves + oh->_mpu_port_index; | 810 | os = oh->slaves[oh->_mpu_port_index]; |
809 | 811 | ||
810 | if (!(os->flags & OCPIF_HAS_IDLEST)) | 812 | if (oh->flags & HWMOD_NO_IDLEST) |
811 | return 0; | 813 | return 0; |
812 | 814 | ||
813 | /* XXX check module SIDLEMODE */ | 815 | /* XXX check module SIDLEMODE */ |
@@ -818,11 +820,8 @@ static int _wait_target_ready(struct omap_hwmod *oh) | |||
818 | ret = omap2_cm_wait_module_ready(oh->prcm.omap2.module_offs, | 820 | ret = omap2_cm_wait_module_ready(oh->prcm.omap2.module_offs, |
819 | oh->prcm.omap2.idlest_reg_id, | 821 | oh->prcm.omap2.idlest_reg_id, |
820 | oh->prcm.omap2.idlest_idle_bit); | 822 | oh->prcm.omap2.idlest_idle_bit); |
821 | #if 0 | ||
822 | } else if (cpu_is_omap44xx()) { | 823 | } else if (cpu_is_omap44xx()) { |
823 | ret = omap4_cm_wait_module_ready(oh->prcm.omap4.module_offs, | 824 | ret = omap4_cm_wait_module_ready(oh->prcm.omap4.clkctrl_reg); |
824 | oh->prcm.omap4.device_offs); | ||
825 | #endif | ||
826 | } else { | 825 | } else { |
827 | BUG(); | 826 | BUG(); |
828 | }; | 827 | }; |
@@ -911,16 +910,21 @@ static int _enable(struct omap_hwmod *oh) | |||
911 | _add_initiator_dep(oh, mpu_oh); | 910 | _add_initiator_dep(oh, mpu_oh); |
912 | _enable_clocks(oh); | 911 | _enable_clocks(oh); |
913 | 912 | ||
914 | if (oh->class->sysc) { | ||
915 | if (!(oh->_int_flags & _HWMOD_SYSCONFIG_LOADED)) | ||
916 | _update_sysc_cache(oh); | ||
917 | _sysc_enable(oh); | ||
918 | } | ||
919 | |||
920 | r = _wait_target_ready(oh); | 913 | r = _wait_target_ready(oh); |
921 | if (!r) | 914 | if (!r) { |
922 | oh->_state = _HWMOD_STATE_ENABLED; | 915 | oh->_state = _HWMOD_STATE_ENABLED; |
923 | 916 | ||
917 | /* Access the sysconfig only if the target is ready */ | ||
918 | if (oh->class->sysc) { | ||
919 | if (!(oh->_int_flags & _HWMOD_SYSCONFIG_LOADED)) | ||
920 | _update_sysc_cache(oh); | ||
921 | _sysc_enable(oh); | ||
922 | } | ||
923 | } else { | ||
924 | pr_debug("omap_hwmod: %s: _wait_target_ready: %d\n", | ||
925 | oh->name, r); | ||
926 | } | ||
927 | |||
924 | return r; | 928 | return r; |
925 | } | 929 | } |
926 | 930 | ||
@@ -997,18 +1001,18 @@ static int _shutdown(struct omap_hwmod *oh) | |||
997 | */ | 1001 | */ |
998 | static int _setup(struct omap_hwmod *oh) | 1002 | static int _setup(struct omap_hwmod *oh) |
999 | { | 1003 | { |
1000 | struct omap_hwmod_ocp_if *os; | 1004 | int i, r; |
1001 | int i; | ||
1002 | 1005 | ||
1003 | if (!oh) | 1006 | if (!oh) |
1004 | return -EINVAL; | 1007 | return -EINVAL; |
1005 | 1008 | ||
1006 | /* Set iclk autoidle mode */ | 1009 | /* Set iclk autoidle mode */ |
1007 | if (oh->slaves_cnt > 0) { | 1010 | if (oh->slaves_cnt > 0) { |
1008 | for (i = 0, os = *oh->slaves; i < oh->slaves_cnt; i++, os++) { | 1011 | for (i = 0; i < oh->slaves_cnt; i++) { |
1012 | struct omap_hwmod_ocp_if *os = oh->slaves[i]; | ||
1009 | struct clk *c = os->_clk; | 1013 | struct clk *c = os->_clk; |
1010 | 1014 | ||
1011 | if (!c || IS_ERR(c)) | 1015 | if (!c) |
1012 | continue; | 1016 | continue; |
1013 | 1017 | ||
1014 | if (os->flags & OCPIF_SWSUP_IDLE) { | 1018 | if (os->flags & OCPIF_SWSUP_IDLE) { |
@@ -1022,7 +1026,12 @@ static int _setup(struct omap_hwmod *oh) | |||
1022 | 1026 | ||
1023 | oh->_state = _HWMOD_STATE_INITIALIZED; | 1027 | oh->_state = _HWMOD_STATE_INITIALIZED; |
1024 | 1028 | ||
1025 | _enable(oh); | 1029 | r = _enable(oh); |
1030 | if (r) { | ||
1031 | pr_warning("omap_hwmod: %s: cannot be enabled (%d)\n", | ||
1032 | oh->name, oh->_state); | ||
1033 | return 0; | ||
1034 | } | ||
1026 | 1035 | ||
1027 | if (!(oh->flags & HWMOD_INIT_NO_RESET)) { | 1036 | if (!(oh->flags & HWMOD_INIT_NO_RESET)) { |
1028 | /* | 1037 | /* |
@@ -1430,7 +1439,7 @@ int omap_hwmod_count_resources(struct omap_hwmod *oh) | |||
1430 | ret = oh->mpu_irqs_cnt + oh->sdma_chs_cnt; | 1439 | ret = oh->mpu_irqs_cnt + oh->sdma_chs_cnt; |
1431 | 1440 | ||
1432 | for (i = 0; i < oh->slaves_cnt; i++) | 1441 | for (i = 0; i < oh->slaves_cnt; i++) |
1433 | ret += (*oh->slaves + i)->addr_cnt; | 1442 | ret += oh->slaves[i]->addr_cnt; |
1434 | 1443 | ||
1435 | return ret; | 1444 | return ret; |
1436 | } | 1445 | } |
@@ -1471,7 +1480,7 @@ int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res) | |||
1471 | for (i = 0; i < oh->slaves_cnt; i++) { | 1480 | for (i = 0; i < oh->slaves_cnt; i++) { |
1472 | struct omap_hwmod_ocp_if *os; | 1481 | struct omap_hwmod_ocp_if *os; |
1473 | 1482 | ||
1474 | os = *oh->slaves + i; | 1483 | os = oh->slaves[i]; |
1475 | 1484 | ||
1476 | for (j = 0; j < os->addr_cnt; j++) { | 1485 | for (j = 0; j < os->addr_cnt; j++) { |
1477 | (res + r)->start = (os->addr + j)->pa_start; | 1486 | (res + r)->start = (os->addr + j)->pa_start; |