aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/clock.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-omap2/clock.c')
-rw-r--r--arch/arm/mach-omap2/clock.c146
1 files changed, 123 insertions, 23 deletions
diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c
index d1b648a4efbf..0de201c3d50b 100644
--- a/arch/arm/mach-omap2/clock.c
+++ b/arch/arm/mach-omap2/clock.c
@@ -32,10 +32,14 @@
32#include "memory.h" 32#include "memory.h"
33#include "clock.h" 33#include "clock.h"
34 34
35#undef DEBUG
36
35//#define DOWN_VARIABLE_DPLL 1 /* Experimental */ 37//#define DOWN_VARIABLE_DPLL 1 /* Experimental */
36 38
37static struct prcm_config *curr_prcm_set; 39static struct prcm_config *curr_prcm_set;
38static u32 curr_perf_level = PRCM_FULL_SPEED; 40static u32 curr_perf_level = PRCM_FULL_SPEED;
41static struct clk *vclk;
42static struct clk *sclk;
39 43
40/*------------------------------------------------------------------------- 44/*-------------------------------------------------------------------------
41 * Omap2 specific clock functions 45 * Omap2 specific clock functions
@@ -79,6 +83,14 @@ static void omap2_propagate_rate(struct clk * clk)
79 propagate_rate(clk); 83 propagate_rate(clk);
80} 84}
81 85
86static void omap2_set_osc_ck(int enable)
87{
88 if (enable)
89 PRCM_CLKSRC_CTRL &= ~(0x3 << 3);
90 else
91 PRCM_CLKSRC_CTRL |= 0x3 << 3;
92}
93
82/* Enable an APLL if off */ 94/* Enable an APLL if off */
83static void omap2_clk_fixed_enable(struct clk *clk) 95static void omap2_clk_fixed_enable(struct clk *clk)
84{ 96{
@@ -101,12 +113,54 @@ static void omap2_clk_fixed_enable(struct clk *clk)
101 else if (clk == &apll54_ck) 113 else if (clk == &apll54_ck)
102 cval = (1 << 6); 114 cval = (1 << 6);
103 115
104 while (!CM_IDLEST_CKGEN & cval) { /* Wait for lock */ 116 while (!(CM_IDLEST_CKGEN & cval)) { /* Wait for lock */
105 ++i; 117 ++i;
106 udelay(1); 118 udelay(1);
107 if (i == 100000) 119 if (i == 100000) {
120 printk(KERN_ERR "Clock %s didn't lock\n", clk->name);
121 break;
122 }
123 }
124}
125
126static void omap2_clk_wait_ready(struct clk *clk)
127{
128 unsigned long reg, other_reg, st_reg;
129 u32 bit;
130 int i;
131
132 reg = (unsigned long) clk->enable_reg;
133 if (reg == (unsigned long) &CM_FCLKEN1_CORE ||
134 reg == (unsigned long) &CM_FCLKEN2_CORE)
135 other_reg = (reg & ~0xf0) | 0x10;
136 else if (reg == (unsigned long) &CM_ICLKEN1_CORE ||
137 reg == (unsigned long) &CM_ICLKEN2_CORE)
138 other_reg = (reg & ~0xf0) | 0x00;
139 else
140 return;
141
142 /* No check for DSS or cam clocks */
143 if ((reg & 0x0f) == 0) {
144 if (clk->enable_bit <= 1 || clk->enable_bit == 31)
145 return;
146 }
147
148 /* Check if both functional and interface clocks
149 * are running. */
150 bit = 1 << clk->enable_bit;
151 if (!(__raw_readl(other_reg) & bit))
152 return;
153 st_reg = (other_reg & ~0xf0) | 0x20;
154 i = 0;
155 while (!(__raw_readl(st_reg) & bit)) {
156 i++;
157 if (i == 100000) {
158 printk(KERN_ERR "Timeout enabling clock %s\n", clk->name);
108 break; 159 break;
160 }
109 } 161 }
162 if (i)
163 pr_debug("Clock %s stable after %d loops\n", clk->name, i);
110} 164}
111 165
112/* Enables clock without considering parent dependencies or use count 166/* Enables clock without considering parent dependencies or use count
@@ -119,6 +173,11 @@ static int _omap2_clk_enable(struct clk * clk)
119 if (clk->flags & ALWAYS_ENABLED) 173 if (clk->flags & ALWAYS_ENABLED)
120 return 0; 174 return 0;
121 175
176 if (unlikely(clk == &osc_ck)) {
177 omap2_set_osc_ck(1);
178 return 0;
179 }
180
122 if (unlikely(clk->enable_reg == 0)) { 181 if (unlikely(clk->enable_reg == 0)) {
123 printk(KERN_ERR "clock.c: Enable for %s without enable code\n", 182 printk(KERN_ERR "clock.c: Enable for %s without enable code\n",
124 clk->name); 183 clk->name);
@@ -133,6 +192,9 @@ static int _omap2_clk_enable(struct clk * clk)
133 regval32 = __raw_readl(clk->enable_reg); 192 regval32 = __raw_readl(clk->enable_reg);
134 regval32 |= (1 << clk->enable_bit); 193 regval32 |= (1 << clk->enable_bit);
135 __raw_writel(regval32, clk->enable_reg); 194 __raw_writel(regval32, clk->enable_reg);
195 wmb();
196
197 omap2_clk_wait_ready(clk);
136 198
137 return 0; 199 return 0;
138} 200}
@@ -155,6 +217,11 @@ static void _omap2_clk_disable(struct clk *clk)
155{ 217{
156 u32 regval32; 218 u32 regval32;
157 219
220 if (unlikely(clk == &osc_ck)) {
221 omap2_set_osc_ck(0);
222 return;
223 }
224
158 if (clk->enable_reg == 0) 225 if (clk->enable_reg == 0)
159 return; 226 return;
160 227
@@ -166,6 +233,7 @@ static void _omap2_clk_disable(struct clk *clk)
166 regval32 = __raw_readl(clk->enable_reg); 233 regval32 = __raw_readl(clk->enable_reg);
167 regval32 &= ~(1 << clk->enable_bit); 234 regval32 &= ~(1 << clk->enable_bit);
168 __raw_writel(regval32, clk->enable_reg); 235 __raw_writel(regval32, clk->enable_reg);
236 wmb();
169} 237}
170 238
171static int omap2_clk_enable(struct clk *clk) 239static int omap2_clk_enable(struct clk *clk)
@@ -695,12 +763,14 @@ static int omap2_clk_set_rate(struct clk *clk, unsigned long rate)
695 reg_val = __raw_readl(reg); 763 reg_val = __raw_readl(reg);
696 reg_val &= ~(field_mask << div_off); 764 reg_val &= ~(field_mask << div_off);
697 reg_val |= (field_val << div_off); 765 reg_val |= (field_val << div_off);
698
699 __raw_writel(reg_val, reg); 766 __raw_writel(reg_val, reg);
767 wmb();
700 clk->rate = clk->parent->rate / field_val; 768 clk->rate = clk->parent->rate / field_val;
701 769
702 if (clk->flags & DELAYED_APP) 770 if (clk->flags & DELAYED_APP) {
703 __raw_writel(0x1, (void __iomem *)&PRCM_CLKCFG_CTRL); 771 __raw_writel(0x1, (void __iomem *)&PRCM_CLKCFG_CTRL);
772 wmb();
773 }
704 ret = 0; 774 ret = 0;
705 } else if (clk->set_rate != 0) 775 } else if (clk->set_rate != 0)
706 ret = clk->set_rate(clk, rate); 776 ret = clk->set_rate(clk, rate);
@@ -836,10 +906,12 @@ static int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent)
836 reg_val = __raw_readl(reg) & ~(field_mask << src_off); 906 reg_val = __raw_readl(reg) & ~(field_mask << src_off);
837 reg_val |= (field_val << src_off); 907 reg_val |= (field_val << src_off);
838 __raw_writel(reg_val, reg); 908 __raw_writel(reg_val, reg);
909 wmb();
839 910
840 if (clk->flags & DELAYED_APP) 911 if (clk->flags & DELAYED_APP) {
841 __raw_writel(0x1, (void __iomem *)&PRCM_CLKCFG_CTRL); 912 __raw_writel(0x1, (void __iomem *)&PRCM_CLKCFG_CTRL);
842 913 wmb();
914 }
843 if (clk->usecount > 0) 915 if (clk->usecount > 0)
844 _omap2_clk_enable(clk); 916 _omap2_clk_enable(clk);
845 917
@@ -953,12 +1025,29 @@ static int omap2_select_table_rate(struct clk * clk, unsigned long rate)
953 * Omap2 clock reset and init functions 1025 * Omap2 clock reset and init functions
954 *-------------------------------------------------------------------------*/ 1026 *-------------------------------------------------------------------------*/
955 1027
1028#ifdef CONFIG_OMAP_RESET_CLOCKS
1029static void __init omap2_clk_disable_unused(struct clk *clk)
1030{
1031 u32 regval32;
1032
1033 regval32 = __raw_readl(clk->enable_reg);
1034 if ((regval32 & (1 << clk->enable_bit)) == 0)
1035 return;
1036
1037 printk(KERN_INFO "Disabling unused clock \"%s\"\n", clk->name);
1038 _omap2_clk_disable(clk);
1039}
1040#else
1041#define omap2_clk_disable_unused NULL
1042#endif
1043
956static struct clk_functions omap2_clk_functions = { 1044static struct clk_functions omap2_clk_functions = {
957 .clk_enable = omap2_clk_enable, 1045 .clk_enable = omap2_clk_enable,
958 .clk_disable = omap2_clk_disable, 1046 .clk_disable = omap2_clk_disable,
959 .clk_round_rate = omap2_clk_round_rate, 1047 .clk_round_rate = omap2_clk_round_rate,
960 .clk_set_rate = omap2_clk_set_rate, 1048 .clk_set_rate = omap2_clk_set_rate,
961 .clk_set_parent = omap2_clk_set_parent, 1049 .clk_set_parent = omap2_clk_set_parent,
1050 .clk_disable_unused = omap2_clk_disable_unused,
962}; 1051};
963 1052
964static void __init omap2_get_crystal_rate(struct clk *osc, struct clk *sys) 1053static void __init omap2_get_crystal_rate(struct clk *osc, struct clk *sys)
@@ -984,27 +1073,19 @@ static void __init omap2_get_crystal_rate(struct clk *osc, struct clk *sys)
984 sys->rate = sclk; 1073 sys->rate = sclk;
985} 1074}
986 1075
987#ifdef CONFIG_OMAP_RESET_CLOCKS 1076/*
988static void __init omap2_disable_unused_clocks(void) 1077 * Set clocks for bypass mode for reboot to work.
1078 */
1079void omap2_clk_prepare_for_reboot(void)
989{ 1080{
990 struct clk *ck; 1081 u32 rate;
991 u32 regval32;
992 1082
993 list_for_each_entry(ck, &clocks, node) { 1083 if (vclk == NULL || sclk == NULL)
994 if (ck->usecount > 0 || (ck->flags & ALWAYS_ENABLED) || 1084 return;
995 ck->enable_reg == 0)
996 continue;
997
998 regval32 = __raw_readl(ck->enable_reg);
999 if ((regval32 & (1 << ck->enable_bit)) == 0)
1000 continue;
1001 1085
1002 printk(KERN_INFO "Disabling unused clock \"%s\"\n", ck->name); 1086 rate = clk_get_rate(sclk);
1003 _omap2_clk_disable(ck); 1087 clk_set_rate(vclk, rate);
1004 }
1005} 1088}
1006late_initcall(omap2_disable_unused_clocks);
1007#endif
1008 1089
1009/* 1090/*
1010 * Switch the MPU rate if specified on cmdline. 1091 * Switch the MPU rate if specified on cmdline.
@@ -1077,8 +1158,27 @@ int __init omap2_clk_init(void)
1077 */ 1158 */
1078 clk_enable(&sync_32k_ick); 1159 clk_enable(&sync_32k_ick);
1079 clk_enable(&omapctrl_ick); 1160 clk_enable(&omapctrl_ick);
1161
1162 /* Force the APLLs active during bootup to avoid disabling and
1163 * enabling them unnecessarily. */
1164 clk_enable(&apll96_ck);
1165 clk_enable(&apll54_ck);
1166
1080 if (cpu_is_omap2430()) 1167 if (cpu_is_omap2430())
1081 clk_enable(&sdrc_ick); 1168 clk_enable(&sdrc_ick);
1082 1169
1170 /* Avoid sleeping sleeping during omap2_clk_prepare_for_reboot() */
1171 vclk = clk_get(NULL, "virt_prcm_set");
1172 sclk = clk_get(NULL, "sys_ck");
1173
1174 return 0;
1175}
1176
1177static int __init omap2_disable_aplls(void)
1178{
1179 clk_disable(&apll96_ck);
1180 clk_disable(&apll54_ck);
1181
1083 return 0; 1182 return 0;
1084} 1183}
1184late_initcall(omap2_disable_aplls);