diff options
author | Tony Lindgren <tony@atomide.com> | 2010-05-20 14:35:19 -0400 |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2010-05-20 14:35:19 -0400 |
commit | 4fa73a1bf89ebea4eba8a9982b5f64d266d8b5e9 (patch) | |
tree | 9d4558065a2586c25a0c0c3d87ed8402981d616d /arch/arm/mach-omap2/omap_hwmod.c | |
parent | c8f626fe1c7e6de983b0c3b6375da69ded3313b6 (diff) | |
parent | 59dd7224892142fe1d8505cf2c90bd732d730005 (diff) |
Merge branch 'for_2.6.35' of git://git.pwsan.com/linux-2.6 into omap-for-linus
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 e436dcb19795..0a563a671dde 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 |
@@ -58,7 +58,7 @@ | |||
58 | #define MAX_MODULE_RESET_WAIT 10000 | 58 | #define MAX_MODULE_RESET_WAIT 10000 |
59 | 59 | ||
60 | /* Name of the OMAP hwmod for the MPU */ | 60 | /* Name of the OMAP hwmod for the MPU */ |
61 | #define MPU_INITIATOR_NAME "mpu_hwmod" | 61 | #define MPU_INITIATOR_NAME "mpu" |
62 | 62 | ||
63 | /* omap_hwmod_list contains all registered struct omap_hwmods */ | 63 | /* omap_hwmod_list contains all registered struct omap_hwmods */ |
64 | static LIST_HEAD(omap_hwmod_list); | 64 | static LIST_HEAD(omap_hwmod_list); |
@@ -404,21 +404,20 @@ static int _del_initiator_dep(struct omap_hwmod *oh, struct omap_hwmod *init_oh) | |||
404 | */ | 404 | */ |
405 | static int _init_main_clk(struct omap_hwmod *oh) | 405 | static int _init_main_clk(struct omap_hwmod *oh) |
406 | { | 406 | { |
407 | struct clk *c; | ||
408 | int ret = 0; | 407 | int ret = 0; |
409 | 408 | ||
410 | if (!oh->main_clk) | 409 | if (!oh->main_clk) |
411 | return 0; | 410 | return 0; |
412 | 411 | ||
413 | c = omap_clk_get_by_name(oh->main_clk); | 412 | oh->_clk = omap_clk_get_by_name(oh->main_clk); |
414 | WARN(IS_ERR(c), "omap_hwmod: %s: cannot clk_get main_clk %s\n", | 413 | if (!oh->_clk) |
415 | oh->name, oh->main_clk); | 414 | pr_warning("omap_hwmod: %s: cannot clk_get main_clk %s\n", |
416 | if (IS_ERR(c)) | 415 | oh->name, oh->main_clk); |
417 | ret = -EINVAL; | 416 | return -EINVAL; |
418 | oh->_clk = c; | ||
419 | 417 | ||
420 | WARN(!c->clkdm, "omap_hwmod: %s: missing clockdomain for %s.\n", | 418 | if (!oh->_clk->clkdm) |
421 | oh->main_clk, c->name); | 419 | pr_warning("omap_hwmod: %s: missing clockdomain for %s.\n", |
420 | oh->main_clk, oh->_clk->name); | ||
422 | 421 | ||
423 | return ret; | 422 | return ret; |
424 | } | 423 | } |
@@ -432,7 +431,6 @@ static int _init_main_clk(struct omap_hwmod *oh) | |||
432 | */ | 431 | */ |
433 | static int _init_interface_clks(struct omap_hwmod *oh) | 432 | static int _init_interface_clks(struct omap_hwmod *oh) |
434 | { | 433 | { |
435 | struct omap_hwmod_ocp_if *os; | ||
436 | struct clk *c; | 434 | struct clk *c; |
437 | int i; | 435 | int i; |
438 | int ret = 0; | 436 | int ret = 0; |
@@ -440,14 +438,16 @@ static int _init_interface_clks(struct omap_hwmod *oh) | |||
440 | if (oh->slaves_cnt == 0) | 438 | if (oh->slaves_cnt == 0) |
441 | return 0; | 439 | return 0; |
442 | 440 | ||
443 | for (i = 0, os = *oh->slaves; i < oh->slaves_cnt; i++, os++) { | 441 | for (i = 0; i < oh->slaves_cnt; i++) { |
442 | struct omap_hwmod_ocp_if *os = oh->slaves[i]; | ||
443 | |||
444 | if (!os->clk) | 444 | if (!os->clk) |
445 | continue; | 445 | continue; |
446 | 446 | ||
447 | c = omap_clk_get_by_name(os->clk); | 447 | c = omap_clk_get_by_name(os->clk); |
448 | WARN(IS_ERR(c), "omap_hwmod: %s: cannot clk_get " | 448 | if (!c) |
449 | "interface_clk %s\n", oh->name, os->clk); | 449 | pr_warning("omap_hwmod: %s: cannot clk_get interface_clk %s\n", |
450 | if (IS_ERR(c)) | 450 | oh->name, os->clk); |
451 | ret = -EINVAL; | 451 | ret = -EINVAL; |
452 | os->_clk = c; | 452 | os->_clk = c; |
453 | } | 453 | } |
@@ -471,9 +471,9 @@ static int _init_opt_clks(struct omap_hwmod *oh) | |||
471 | 471 | ||
472 | for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++) { | 472 | for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++) { |
473 | c = omap_clk_get_by_name(oc->clk); | 473 | c = omap_clk_get_by_name(oc->clk); |
474 | WARN(IS_ERR(c), "omap_hwmod: %s: cannot clk_get opt_clk " | 474 | if (!c) |
475 | "%s\n", oh->name, oc->clk); | 475 | pr_warning("omap_hwmod: %s: cannot clk_get opt_clk %s\n", |
476 | if (IS_ERR(c)) | 476 | oh->name, oc->clk); |
477 | ret = -EINVAL; | 477 | ret = -EINVAL; |
478 | oc->_clk = c; | 478 | oc->_clk = c; |
479 | } | 479 | } |
@@ -490,19 +490,19 @@ static int _init_opt_clks(struct omap_hwmod *oh) | |||
490 | */ | 490 | */ |
491 | static int _enable_clocks(struct omap_hwmod *oh) | 491 | static int _enable_clocks(struct omap_hwmod *oh) |
492 | { | 492 | { |
493 | struct omap_hwmod_ocp_if *os; | ||
494 | int i; | 493 | int i; |
495 | 494 | ||
496 | pr_debug("omap_hwmod: %s: enabling clocks\n", oh->name); | 495 | pr_debug("omap_hwmod: %s: enabling clocks\n", oh->name); |
497 | 496 | ||
498 | if (oh->_clk && !IS_ERR(oh->_clk)) | 497 | if (oh->_clk) |
499 | clk_enable(oh->_clk); | 498 | clk_enable(oh->_clk); |
500 | 499 | ||
501 | if (oh->slaves_cnt > 0) { | 500 | if (oh->slaves_cnt > 0) { |
502 | for (i = 0, os = *oh->slaves; i < oh->slaves_cnt; i++, os++) { | 501 | for (i = 0; i < oh->slaves_cnt; i++) { |
502 | struct omap_hwmod_ocp_if *os = oh->slaves[i]; | ||
503 | struct clk *c = os->_clk; | 503 | struct clk *c = os->_clk; |
504 | 504 | ||
505 | if (c && !IS_ERR(c) && (os->flags & OCPIF_SWSUP_IDLE)) | 505 | if (c && (os->flags & OCPIF_SWSUP_IDLE)) |
506 | clk_enable(c); | 506 | clk_enable(c); |
507 | } | 507 | } |
508 | } | 508 | } |
@@ -520,19 +520,19 @@ static int _enable_clocks(struct omap_hwmod *oh) | |||
520 | */ | 520 | */ |
521 | static int _disable_clocks(struct omap_hwmod *oh) | 521 | static int _disable_clocks(struct omap_hwmod *oh) |
522 | { | 522 | { |
523 | struct omap_hwmod_ocp_if *os; | ||
524 | int i; | 523 | int i; |
525 | 524 | ||
526 | pr_debug("omap_hwmod: %s: disabling clocks\n", oh->name); | 525 | pr_debug("omap_hwmod: %s: disabling clocks\n", oh->name); |
527 | 526 | ||
528 | if (oh->_clk && !IS_ERR(oh->_clk)) | 527 | if (oh->_clk) |
529 | clk_disable(oh->_clk); | 528 | clk_disable(oh->_clk); |
530 | 529 | ||
531 | if (oh->slaves_cnt > 0) { | 530 | if (oh->slaves_cnt > 0) { |
532 | for (i = 0, os = *oh->slaves; i < oh->slaves_cnt; i++, os++) { | 531 | for (i = 0; i < oh->slaves_cnt; i++) { |
532 | struct omap_hwmod_ocp_if *os = oh->slaves[i]; | ||
533 | struct clk *c = os->_clk; | 533 | struct clk *c = os->_clk; |
534 | 534 | ||
535 | if (c && !IS_ERR(c) && (os->flags & OCPIF_SWSUP_IDLE)) | 535 | if (c && (os->flags & OCPIF_SWSUP_IDLE)) |
536 | clk_disable(c); | 536 | clk_disable(c); |
537 | } | 537 | } |
538 | } | 538 | } |
@@ -551,14 +551,15 @@ static int _disable_clocks(struct omap_hwmod *oh) | |||
551 | */ | 551 | */ |
552 | static int _find_mpu_port_index(struct omap_hwmod *oh) | 552 | static int _find_mpu_port_index(struct omap_hwmod *oh) |
553 | { | 553 | { |
554 | struct omap_hwmod_ocp_if *os; | ||
555 | int i; | 554 | int i; |
556 | int found = 0; | 555 | int found = 0; |
557 | 556 | ||
558 | if (!oh || oh->slaves_cnt == 0) | 557 | if (!oh || oh->slaves_cnt == 0) |
559 | return -EINVAL; | 558 | return -EINVAL; |
560 | 559 | ||
561 | for (i = 0, os = *oh->slaves; i < oh->slaves_cnt; i++, os++) { | 560 | for (i = 0; i < oh->slaves_cnt; i++) { |
561 | struct omap_hwmod_ocp_if *os = oh->slaves[i]; | ||
562 | |||
562 | if (os->user & OCP_USER_MPU) { | 563 | if (os->user & OCP_USER_MPU) { |
563 | found = 1; | 564 | found = 1; |
564 | break; | 565 | break; |
@@ -593,7 +594,7 @@ static void __iomem *_find_mpu_rt_base(struct omap_hwmod *oh, u8 index) | |||
593 | if (!oh || oh->slaves_cnt == 0) | 594 | if (!oh || oh->slaves_cnt == 0) |
594 | return NULL; | 595 | return NULL; |
595 | 596 | ||
596 | os = *oh->slaves + index; | 597 | os = oh->slaves[index]; |
597 | 598 | ||
598 | for (i = 0, mem = os->addr; i < os->addr_cnt; i++, mem++) { | 599 | for (i = 0, mem = os->addr; i < os->addr_cnt; i++, mem++) { |
599 | if (mem->flags & ADDR_TYPE_RT) { | 600 | if (mem->flags & ADDR_TYPE_RT) { |
@@ -781,9 +782,10 @@ static int _init_clocks(struct omap_hwmod *oh) | |||
781 | ret |= _init_interface_clks(oh); | 782 | ret |= _init_interface_clks(oh); |
782 | ret |= _init_opt_clks(oh); | 783 | ret |= _init_opt_clks(oh); |
783 | 784 | ||
784 | oh->_state = _HWMOD_STATE_CLKS_INITED; | 785 | if (!ret) |
786 | oh->_state = _HWMOD_STATE_CLKS_INITED; | ||
785 | 787 | ||
786 | return ret; | 788 | return 0; |
787 | } | 789 | } |
788 | 790 | ||
789 | /** | 791 | /** |
@@ -806,9 +808,9 @@ static int _wait_target_ready(struct omap_hwmod *oh) | |||
806 | if (oh->_int_flags & _HWMOD_NO_MPU_PORT) | 808 | if (oh->_int_flags & _HWMOD_NO_MPU_PORT) |
807 | return 0; | 809 | return 0; |
808 | 810 | ||
809 | os = *oh->slaves + oh->_mpu_port_index; | 811 | os = oh->slaves[oh->_mpu_port_index]; |
810 | 812 | ||
811 | if (!(os->flags & OCPIF_HAS_IDLEST)) | 813 | if (oh->flags & HWMOD_NO_IDLEST) |
812 | return 0; | 814 | return 0; |
813 | 815 | ||
814 | /* XXX check module SIDLEMODE */ | 816 | /* XXX check module SIDLEMODE */ |
@@ -819,11 +821,8 @@ static int _wait_target_ready(struct omap_hwmod *oh) | |||
819 | ret = omap2_cm_wait_module_ready(oh->prcm.omap2.module_offs, | 821 | ret = omap2_cm_wait_module_ready(oh->prcm.omap2.module_offs, |
820 | oh->prcm.omap2.idlest_reg_id, | 822 | oh->prcm.omap2.idlest_reg_id, |
821 | oh->prcm.omap2.idlest_idle_bit); | 823 | oh->prcm.omap2.idlest_idle_bit); |
822 | #if 0 | ||
823 | } else if (cpu_is_omap44xx()) { | 824 | } else if (cpu_is_omap44xx()) { |
824 | ret = omap4_cm_wait_module_ready(oh->prcm.omap4.module_offs, | 825 | ret = omap4_cm_wait_module_ready(oh->prcm.omap4.clkctrl_reg); |
825 | oh->prcm.omap4.device_offs); | ||
826 | #endif | ||
827 | } else { | 826 | } else { |
828 | BUG(); | 827 | BUG(); |
829 | }; | 828 | }; |
@@ -912,16 +911,21 @@ static int _enable(struct omap_hwmod *oh) | |||
912 | _add_initiator_dep(oh, mpu_oh); | 911 | _add_initiator_dep(oh, mpu_oh); |
913 | _enable_clocks(oh); | 912 | _enable_clocks(oh); |
914 | 913 | ||
915 | if (oh->class->sysc) { | ||
916 | if (!(oh->_int_flags & _HWMOD_SYSCONFIG_LOADED)) | ||
917 | _update_sysc_cache(oh); | ||
918 | _sysc_enable(oh); | ||
919 | } | ||
920 | |||
921 | r = _wait_target_ready(oh); | 914 | r = _wait_target_ready(oh); |
922 | if (!r) | 915 | if (!r) { |
923 | oh->_state = _HWMOD_STATE_ENABLED; | 916 | oh->_state = _HWMOD_STATE_ENABLED; |
924 | 917 | ||
918 | /* Access the sysconfig only if the target is ready */ | ||
919 | if (oh->class->sysc) { | ||
920 | if (!(oh->_int_flags & _HWMOD_SYSCONFIG_LOADED)) | ||
921 | _update_sysc_cache(oh); | ||
922 | _sysc_enable(oh); | ||
923 | } | ||
924 | } else { | ||
925 | pr_debug("omap_hwmod: %s: _wait_target_ready: %d\n", | ||
926 | oh->name, r); | ||
927 | } | ||
928 | |||
925 | return r; | 929 | return r; |
926 | } | 930 | } |
927 | 931 | ||
@@ -998,18 +1002,18 @@ static int _shutdown(struct omap_hwmod *oh) | |||
998 | */ | 1002 | */ |
999 | static int _setup(struct omap_hwmod *oh) | 1003 | static int _setup(struct omap_hwmod *oh) |
1000 | { | 1004 | { |
1001 | struct omap_hwmod_ocp_if *os; | 1005 | int i, r; |
1002 | int i; | ||
1003 | 1006 | ||
1004 | if (!oh) | 1007 | if (!oh) |
1005 | return -EINVAL; | 1008 | return -EINVAL; |
1006 | 1009 | ||
1007 | /* Set iclk autoidle mode */ | 1010 | /* Set iclk autoidle mode */ |
1008 | if (oh->slaves_cnt > 0) { | 1011 | if (oh->slaves_cnt > 0) { |
1009 | for (i = 0, os = *oh->slaves; i < oh->slaves_cnt; i++, os++) { | 1012 | for (i = 0; i < oh->slaves_cnt; i++) { |
1013 | struct omap_hwmod_ocp_if *os = oh->slaves[i]; | ||
1010 | struct clk *c = os->_clk; | 1014 | struct clk *c = os->_clk; |
1011 | 1015 | ||
1012 | if (!c || IS_ERR(c)) | 1016 | if (!c) |
1013 | continue; | 1017 | continue; |
1014 | 1018 | ||
1015 | if (os->flags & OCPIF_SWSUP_IDLE) { | 1019 | if (os->flags & OCPIF_SWSUP_IDLE) { |
@@ -1023,7 +1027,12 @@ static int _setup(struct omap_hwmod *oh) | |||
1023 | 1027 | ||
1024 | oh->_state = _HWMOD_STATE_INITIALIZED; | 1028 | oh->_state = _HWMOD_STATE_INITIALIZED; |
1025 | 1029 | ||
1026 | _enable(oh); | 1030 | r = _enable(oh); |
1031 | if (r) { | ||
1032 | pr_warning("omap_hwmod: %s: cannot be enabled (%d)\n", | ||
1033 | oh->name, oh->_state); | ||
1034 | return 0; | ||
1035 | } | ||
1027 | 1036 | ||
1028 | if (!(oh->flags & HWMOD_INIT_NO_RESET)) { | 1037 | if (!(oh->flags & HWMOD_INIT_NO_RESET)) { |
1029 | /* | 1038 | /* |
@@ -1431,7 +1440,7 @@ int omap_hwmod_count_resources(struct omap_hwmod *oh) | |||
1431 | ret = oh->mpu_irqs_cnt + oh->sdma_chs_cnt; | 1440 | ret = oh->mpu_irqs_cnt + oh->sdma_chs_cnt; |
1432 | 1441 | ||
1433 | for (i = 0; i < oh->slaves_cnt; i++) | 1442 | for (i = 0; i < oh->slaves_cnt; i++) |
1434 | ret += (*oh->slaves + i)->addr_cnt; | 1443 | ret += oh->slaves[i]->addr_cnt; |
1435 | 1444 | ||
1436 | return ret; | 1445 | return ret; |
1437 | } | 1446 | } |
@@ -1472,7 +1481,7 @@ int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res) | |||
1472 | for (i = 0; i < oh->slaves_cnt; i++) { | 1481 | for (i = 0; i < oh->slaves_cnt; i++) { |
1473 | struct omap_hwmod_ocp_if *os; | 1482 | struct omap_hwmod_ocp_if *os; |
1474 | 1483 | ||
1475 | os = *oh->slaves + i; | 1484 | os = oh->slaves[i]; |
1476 | 1485 | ||
1477 | for (j = 0; j < os->addr_cnt; j++) { | 1486 | for (j = 0; j < os->addr_cnt; j++) { |
1478 | (res + r)->start = (os->addr + j)->pa_start; | 1487 | (res + r)->start = (os->addr + j)->pa_start; |