0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/kernel.h>
0012 #include <linux/types.h>
0013 #include <linux/errno.h>
0014 #include <linux/err.h>
0015 #include <linux/io.h>
0016
0017 #include "clockdomain.h"
0018 #include "cm.h"
0019 #include "cm33xx.h"
0020 #include "cm-regbits-34xx.h"
0021 #include "cm-regbits-33xx.h"
0022 #include "prm33xx.h"
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035 #define CLKCTRL_IDLEST_FUNCTIONAL 0x0
0036 #define CLKCTRL_IDLEST_INTRANSITION 0x1
0037 #define CLKCTRL_IDLEST_INTERFACE_IDLE 0x2
0038 #define CLKCTRL_IDLEST_DISABLED 0x3
0039
0040
0041
0042
0043 static inline u32 am33xx_cm_read_reg(u16 inst, u16 idx)
0044 {
0045 return readl_relaxed(cm_base.va + inst + idx);
0046 }
0047
0048
0049 static inline void am33xx_cm_write_reg(u32 val, u16 inst, u16 idx)
0050 {
0051 writel_relaxed(val, cm_base.va + inst + idx);
0052 }
0053
0054
0055 static inline u32 am33xx_cm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx)
0056 {
0057 u32 v;
0058
0059 v = am33xx_cm_read_reg(inst, idx);
0060 v &= ~mask;
0061 v |= bits;
0062 am33xx_cm_write_reg(v, inst, idx);
0063
0064 return v;
0065 }
0066
0067 static inline u32 am33xx_cm_read_reg_bits(u16 inst, s16 idx, u32 mask)
0068 {
0069 u32 v;
0070
0071 v = am33xx_cm_read_reg(inst, idx);
0072 v &= mask;
0073 v >>= __ffs(mask);
0074
0075 return v;
0076 }
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086 static u32 _clkctrl_idlest(u16 inst, u16 clkctrl_offs)
0087 {
0088 u32 v = am33xx_cm_read_reg(inst, clkctrl_offs);
0089 v &= AM33XX_IDLEST_MASK;
0090 v >>= AM33XX_IDLEST_SHIFT;
0091 return v;
0092 }
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102 static bool _is_module_ready(u16 inst, u16 clkctrl_offs)
0103 {
0104 u32 v;
0105
0106 v = _clkctrl_idlest(inst, clkctrl_offs);
0107
0108 return (v == CLKCTRL_IDLEST_FUNCTIONAL ||
0109 v == CLKCTRL_IDLEST_INTERFACE_IDLE) ? true : false;
0110 }
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121 static void _clktrctrl_write(u8 c, u16 inst, u16 cdoffs)
0122 {
0123 u32 v;
0124
0125 v = am33xx_cm_read_reg(inst, cdoffs);
0126 v &= ~AM33XX_CLKTRCTRL_MASK;
0127 v |= c << AM33XX_CLKTRCTRL_SHIFT;
0128 am33xx_cm_write_reg(v, inst, cdoffs);
0129 }
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141 static bool am33xx_cm_is_clkdm_in_hwsup(u16 inst, u16 cdoffs)
0142 {
0143 u32 v;
0144
0145 v = am33xx_cm_read_reg(inst, cdoffs);
0146 v &= AM33XX_CLKTRCTRL_MASK;
0147 v >>= AM33XX_CLKTRCTRL_SHIFT;
0148
0149 return (v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ? true : false;
0150 }
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160 static void am33xx_cm_clkdm_enable_hwsup(u16 inst, u16 cdoffs)
0161 {
0162 _clktrctrl_write(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, inst, cdoffs);
0163 }
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174 static void am33xx_cm_clkdm_disable_hwsup(u16 inst, u16 cdoffs)
0175 {
0176 _clktrctrl_write(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, inst, cdoffs);
0177 }
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187 static void am33xx_cm_clkdm_force_sleep(u16 inst, u16 cdoffs)
0188 {
0189 _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_SLEEP, inst, cdoffs);
0190 }
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200 static void am33xx_cm_clkdm_force_wakeup(u16 inst, u16 cdoffs)
0201 {
0202 _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, inst, cdoffs);
0203 }
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221 static int am33xx_cm_wait_module_ready(u8 part, s16 inst, u16 clkctrl_offs,
0222 u8 bit_shift)
0223 {
0224 int i = 0;
0225
0226 omap_test_timeout(_is_module_ready(inst, clkctrl_offs),
0227 MAX_MODULE_READY_TIME, i);
0228
0229 return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
0230 }
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244 static int am33xx_cm_wait_module_idle(u8 part, s16 inst, u16 clkctrl_offs,
0245 u8 bit_shift)
0246 {
0247 int i = 0;
0248
0249 omap_test_timeout((_clkctrl_idlest(inst, clkctrl_offs) ==
0250 CLKCTRL_IDLEST_DISABLED),
0251 MAX_MODULE_READY_TIME, i);
0252
0253 return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
0254 }
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264
0265 static void am33xx_cm_module_enable(u8 mode, u8 part, u16 inst,
0266 u16 clkctrl_offs)
0267 {
0268 u32 v;
0269
0270 v = am33xx_cm_read_reg(inst, clkctrl_offs);
0271 v &= ~AM33XX_MODULEMODE_MASK;
0272 v |= mode << AM33XX_MODULEMODE_SHIFT;
0273 am33xx_cm_write_reg(v, inst, clkctrl_offs);
0274 }
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284 static void am33xx_cm_module_disable(u8 part, u16 inst, u16 clkctrl_offs)
0285 {
0286 u32 v;
0287
0288 v = am33xx_cm_read_reg(inst, clkctrl_offs);
0289 v &= ~AM33XX_MODULEMODE_MASK;
0290 am33xx_cm_write_reg(v, inst, clkctrl_offs);
0291 }
0292
0293
0294
0295
0296
0297 static int am33xx_clkdm_sleep(struct clockdomain *clkdm)
0298 {
0299 am33xx_cm_clkdm_force_sleep(clkdm->cm_inst, clkdm->clkdm_offs);
0300 return 0;
0301 }
0302
0303 static int am33xx_clkdm_wakeup(struct clockdomain *clkdm)
0304 {
0305 am33xx_cm_clkdm_force_wakeup(clkdm->cm_inst, clkdm->clkdm_offs);
0306 return 0;
0307 }
0308
0309 static void am33xx_clkdm_allow_idle(struct clockdomain *clkdm)
0310 {
0311 am33xx_cm_clkdm_enable_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
0312 }
0313
0314 static void am33xx_clkdm_deny_idle(struct clockdomain *clkdm)
0315 {
0316 am33xx_cm_clkdm_disable_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
0317 }
0318
0319 static int am33xx_clkdm_clk_enable(struct clockdomain *clkdm)
0320 {
0321 if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
0322 return am33xx_clkdm_wakeup(clkdm);
0323
0324 return 0;
0325 }
0326
0327 static int am33xx_clkdm_clk_disable(struct clockdomain *clkdm)
0328 {
0329 bool hwsup = false;
0330
0331 hwsup = am33xx_cm_is_clkdm_in_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
0332
0333 if (!hwsup && (clkdm->flags & CLKDM_CAN_FORCE_SLEEP))
0334 am33xx_clkdm_sleep(clkdm);
0335
0336 return 0;
0337 }
0338
0339 static u32 am33xx_cm_xlate_clkctrl(u8 part, u16 inst, u16 offset)
0340 {
0341 return cm_base.pa + inst + offset;
0342 }
0343
0344
0345
0346
0347
0348
0349
0350 static int am33xx_clkdm_save_context(struct clockdomain *clkdm)
0351 {
0352 clkdm->context = am33xx_cm_read_reg_bits(clkdm->cm_inst,
0353 clkdm->clkdm_offs,
0354 AM33XX_CLKTRCTRL_MASK);
0355
0356 return 0;
0357 }
0358
0359
0360
0361
0362
0363
0364
0365 static int am33xx_clkdm_restore_context(struct clockdomain *clkdm)
0366 {
0367 switch (clkdm->context) {
0368 case OMAP34XX_CLKSTCTRL_DISABLE_AUTO:
0369 am33xx_clkdm_deny_idle(clkdm);
0370 break;
0371 case OMAP34XX_CLKSTCTRL_FORCE_SLEEP:
0372 am33xx_clkdm_sleep(clkdm);
0373 break;
0374 case OMAP34XX_CLKSTCTRL_FORCE_WAKEUP:
0375 am33xx_clkdm_wakeup(clkdm);
0376 break;
0377 case OMAP34XX_CLKSTCTRL_ENABLE_AUTO:
0378 am33xx_clkdm_allow_idle(clkdm);
0379 break;
0380 }
0381 return 0;
0382 }
0383
0384 struct clkdm_ops am33xx_clkdm_operations = {
0385 .clkdm_sleep = am33xx_clkdm_sleep,
0386 .clkdm_wakeup = am33xx_clkdm_wakeup,
0387 .clkdm_allow_idle = am33xx_clkdm_allow_idle,
0388 .clkdm_deny_idle = am33xx_clkdm_deny_idle,
0389 .clkdm_clk_enable = am33xx_clkdm_clk_enable,
0390 .clkdm_clk_disable = am33xx_clkdm_clk_disable,
0391 .clkdm_save_context = am33xx_clkdm_save_context,
0392 .clkdm_restore_context = am33xx_clkdm_restore_context,
0393 };
0394
0395 static const struct cm_ll_data am33xx_cm_ll_data = {
0396 .wait_module_ready = &am33xx_cm_wait_module_ready,
0397 .wait_module_idle = &am33xx_cm_wait_module_idle,
0398 .module_enable = &am33xx_cm_module_enable,
0399 .module_disable = &am33xx_cm_module_disable,
0400 .xlate_clkctrl = &am33xx_cm_xlate_clkctrl,
0401 };
0402
0403 int __init am33xx_cm_init(const struct omap_prcm_init_data *data)
0404 {
0405 return cm_register(&am33xx_cm_ll_data);
0406 }
0407
0408 static void __exit am33xx_cm_exit(void)
0409 {
0410 cm_unregister(&am33xx_cm_ll_data);
0411 }
0412 __exitcall(am33xx_cm_exit);