0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #include <linux/kernel.h>
0016 #include <linux/types.h>
0017 #include <linux/errno.h>
0018 #include <linux/err.h>
0019 #include <linux/io.h>
0020
0021 #include "clockdomain.h"
0022 #include "cm.h"
0023 #include "cm1_44xx.h"
0024 #include "cm2_44xx.h"
0025 #include "cm44xx.h"
0026 #include "cm-regbits-34xx.h"
0027 #include "prcm44xx.h"
0028 #include "prm44xx.h"
0029 #include "prcm_mpu44xx.h"
0030 #include "prcm-common.h"
0031
0032 #define OMAP4430_IDLEST_SHIFT 16
0033 #define OMAP4430_IDLEST_MASK (0x3 << 16)
0034 #define OMAP4430_CLKTRCTRL_SHIFT 0
0035 #define OMAP4430_CLKTRCTRL_MASK (0x3 << 0)
0036 #define OMAP4430_MODULEMODE_SHIFT 0
0037 #define OMAP4430_MODULEMODE_MASK (0x3 << 0)
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050 #define CLKCTRL_IDLEST_FUNCTIONAL 0x0
0051 #define CLKCTRL_IDLEST_INTRANSITION 0x1
0052 #define CLKCTRL_IDLEST_INTERFACE_IDLE 0x2
0053 #define CLKCTRL_IDLEST_DISABLED 0x3
0054
0055 static struct omap_domain_base _cm_bases[OMAP4_MAX_PRCM_PARTITIONS];
0056
0057
0058
0059
0060
0061
0062
0063 static void omap_cm_base_init(void)
0064 {
0065 memcpy(&_cm_bases[OMAP4430_PRM_PARTITION], &prm_base, sizeof(prm_base));
0066 memcpy(&_cm_bases[OMAP4430_CM1_PARTITION], &cm_base, sizeof(cm_base));
0067 memcpy(&_cm_bases[OMAP4430_CM2_PARTITION], &cm2_base, sizeof(cm2_base));
0068 memcpy(&_cm_bases[OMAP4430_PRCM_MPU_PARTITION], &prcm_mpu_base,
0069 sizeof(prcm_mpu_base));
0070 }
0071
0072
0073
0074 static u32 omap4_cminst_read_inst_reg(u8 part, u16 inst, u16 idx);
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085 static u32 _clkctrl_idlest(u8 part, u16 inst, u16 clkctrl_offs)
0086 {
0087 u32 v = omap4_cminst_read_inst_reg(part, inst, clkctrl_offs);
0088 v &= OMAP4430_IDLEST_MASK;
0089 v >>= OMAP4430_IDLEST_SHIFT;
0090 return v;
0091 }
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102 static bool _is_module_ready(u8 part, u16 inst, u16 clkctrl_offs)
0103 {
0104 u32 v;
0105
0106 v = _clkctrl_idlest(part, inst, clkctrl_offs);
0107
0108 return (v == CLKCTRL_IDLEST_FUNCTIONAL ||
0109 v == CLKCTRL_IDLEST_INTERFACE_IDLE) ? true : false;
0110 }
0111
0112
0113 static u32 omap4_cminst_read_inst_reg(u8 part, u16 inst, u16 idx)
0114 {
0115 BUG_ON(part >= OMAP4_MAX_PRCM_PARTITIONS ||
0116 part == OMAP4430_INVALID_PRCM_PARTITION ||
0117 !_cm_bases[part].va);
0118 return readl_relaxed(_cm_bases[part].va + inst + idx);
0119 }
0120
0121
0122 static void omap4_cminst_write_inst_reg(u32 val, u8 part, u16 inst, u16 idx)
0123 {
0124 BUG_ON(part >= OMAP4_MAX_PRCM_PARTITIONS ||
0125 part == OMAP4430_INVALID_PRCM_PARTITION ||
0126 !_cm_bases[part].va);
0127 writel_relaxed(val, _cm_bases[part].va + inst + idx);
0128 }
0129
0130
0131 static u32 omap4_cminst_rmw_inst_reg_bits(u32 mask, u32 bits, u8 part, u16 inst,
0132 s16 idx)
0133 {
0134 u32 v;
0135
0136 v = omap4_cminst_read_inst_reg(part, inst, idx);
0137 v &= ~mask;
0138 v |= bits;
0139 omap4_cminst_write_inst_reg(v, part, inst, idx);
0140
0141 return v;
0142 }
0143
0144 static u32 omap4_cminst_set_inst_reg_bits(u32 bits, u8 part, u16 inst, s16 idx)
0145 {
0146 return omap4_cminst_rmw_inst_reg_bits(bits, bits, part, inst, idx);
0147 }
0148
0149 static u32 omap4_cminst_clear_inst_reg_bits(u32 bits, u8 part, u16 inst,
0150 s16 idx)
0151 {
0152 return omap4_cminst_rmw_inst_reg_bits(bits, 0x0, part, inst, idx);
0153 }
0154
0155 static u32 omap4_cminst_read_inst_reg_bits(u8 part, u16 inst, s16 idx, u32 mask)
0156 {
0157 u32 v;
0158
0159 v = omap4_cminst_read_inst_reg(part, inst, idx);
0160 v &= mask;
0161 v >>= __ffs(mask);
0162
0163 return v;
0164 }
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180 static void _clktrctrl_write(u8 c, u8 part, u16 inst, u16 cdoffs)
0181 {
0182 u32 v;
0183
0184 v = omap4_cminst_read_inst_reg(part, inst, cdoffs + OMAP4_CM_CLKSTCTRL);
0185 v &= ~OMAP4430_CLKTRCTRL_MASK;
0186 v |= c << OMAP4430_CLKTRCTRL_SHIFT;
0187 omap4_cminst_write_inst_reg(v, part, inst, cdoffs + OMAP4_CM_CLKSTCTRL);
0188 }
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199 static bool omap4_cminst_is_clkdm_in_hwsup(u8 part, u16 inst, u16 cdoffs)
0200 {
0201 u32 v;
0202
0203 v = omap4_cminst_read_inst_reg(part, inst, cdoffs + OMAP4_CM_CLKSTCTRL);
0204 v &= OMAP4430_CLKTRCTRL_MASK;
0205 v >>= OMAP4430_CLKTRCTRL_SHIFT;
0206
0207 return (v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ? true : false;
0208 }
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219 static void omap4_cminst_clkdm_enable_hwsup(u8 part, u16 inst, u16 cdoffs)
0220 {
0221 _clktrctrl_write(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, part, inst, cdoffs);
0222 }
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234 static void omap4_cminst_clkdm_disable_hwsup(u8 part, u16 inst, u16 cdoffs)
0235 {
0236 _clktrctrl_write(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, part, inst, cdoffs);
0237 }
0238
0239
0240
0241
0242
0243
0244
0245
0246
0247
0248 static void omap4_cminst_clkdm_force_wakeup(u8 part, u16 inst, u16 cdoffs)
0249 {
0250 _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, part, inst, cdoffs);
0251 }
0252
0253
0254
0255
0256
0257 static void omap4_cminst_clkdm_force_sleep(u8 part, u16 inst, u16 cdoffs)
0258 {
0259 _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_SLEEP, part, inst, cdoffs);
0260 }
0261
0262
0263
0264
0265
0266
0267
0268
0269
0270
0271
0272
0273
0274 static int omap4_cminst_wait_module_ready(u8 part, s16 inst, u16 clkctrl_offs,
0275 u8 bit_shift)
0276 {
0277 int i = 0;
0278
0279 omap_test_timeout(_is_module_ready(part, inst, clkctrl_offs),
0280 MAX_MODULE_READY_TIME, i);
0281
0282 return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
0283 }
0284
0285
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297 static int omap4_cminst_wait_module_idle(u8 part, s16 inst, u16 clkctrl_offs,
0298 u8 bit_shift)
0299 {
0300 int i = 0;
0301
0302 omap_test_timeout((_clkctrl_idlest(part, inst, clkctrl_offs) ==
0303 CLKCTRL_IDLEST_DISABLED),
0304 MAX_MODULE_DISABLE_TIME, i);
0305
0306 return (i < MAX_MODULE_DISABLE_TIME) ? 0 : -EBUSY;
0307 }
0308
0309
0310
0311
0312
0313
0314
0315
0316
0317
0318 static void omap4_cminst_module_enable(u8 mode, u8 part, u16 inst,
0319 u16 clkctrl_offs)
0320 {
0321 u32 v;
0322
0323 v = omap4_cminst_read_inst_reg(part, inst, clkctrl_offs);
0324 v &= ~OMAP4430_MODULEMODE_MASK;
0325 v |= mode << OMAP4430_MODULEMODE_SHIFT;
0326 omap4_cminst_write_inst_reg(v, part, inst, clkctrl_offs);
0327 }
0328
0329
0330
0331
0332
0333
0334
0335
0336
0337 static void omap4_cminst_module_disable(u8 part, u16 inst, u16 clkctrl_offs)
0338 {
0339 u32 v;
0340
0341 v = omap4_cminst_read_inst_reg(part, inst, clkctrl_offs);
0342 v &= ~OMAP4430_MODULEMODE_MASK;
0343 omap4_cminst_write_inst_reg(v, part, inst, clkctrl_offs);
0344 }
0345
0346
0347
0348
0349
0350 static int omap4_clkdm_add_wkup_sleep_dep(struct clockdomain *clkdm1,
0351 struct clockdomain *clkdm2)
0352 {
0353 omap4_cminst_set_inst_reg_bits((1 << clkdm2->dep_bit),
0354 clkdm1->prcm_partition,
0355 clkdm1->cm_inst, clkdm1->clkdm_offs +
0356 OMAP4_CM_STATICDEP);
0357 return 0;
0358 }
0359
0360 static int omap4_clkdm_del_wkup_sleep_dep(struct clockdomain *clkdm1,
0361 struct clockdomain *clkdm2)
0362 {
0363 omap4_cminst_clear_inst_reg_bits((1 << clkdm2->dep_bit),
0364 clkdm1->prcm_partition,
0365 clkdm1->cm_inst, clkdm1->clkdm_offs +
0366 OMAP4_CM_STATICDEP);
0367 return 0;
0368 }
0369
0370 static int omap4_clkdm_read_wkup_sleep_dep(struct clockdomain *clkdm1,
0371 struct clockdomain *clkdm2)
0372 {
0373 return omap4_cminst_read_inst_reg_bits(clkdm1->prcm_partition,
0374 clkdm1->cm_inst,
0375 clkdm1->clkdm_offs +
0376 OMAP4_CM_STATICDEP,
0377 (1 << clkdm2->dep_bit));
0378 }
0379
0380 static int omap4_clkdm_clear_all_wkup_sleep_deps(struct clockdomain *clkdm)
0381 {
0382 struct clkdm_dep *cd;
0383 u32 mask = 0;
0384
0385 if (!clkdm->prcm_partition)
0386 return 0;
0387
0388 for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) {
0389 if (!cd->clkdm)
0390 continue;
0391
0392 mask |= 1 << cd->clkdm->dep_bit;
0393 cd->wkdep_usecount = 0;
0394 }
0395
0396 omap4_cminst_clear_inst_reg_bits(mask, clkdm->prcm_partition,
0397 clkdm->cm_inst, clkdm->clkdm_offs +
0398 OMAP4_CM_STATICDEP);
0399 return 0;
0400 }
0401
0402 static int omap4_clkdm_sleep(struct clockdomain *clkdm)
0403 {
0404 if (clkdm->flags & CLKDM_CAN_HWSUP)
0405 omap4_cminst_clkdm_enable_hwsup(clkdm->prcm_partition,
0406 clkdm->cm_inst,
0407 clkdm->clkdm_offs);
0408 else if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP)
0409 omap4_cminst_clkdm_force_sleep(clkdm->prcm_partition,
0410 clkdm->cm_inst,
0411 clkdm->clkdm_offs);
0412 else
0413 return -EINVAL;
0414
0415 return 0;
0416 }
0417
0418 static int omap4_clkdm_wakeup(struct clockdomain *clkdm)
0419 {
0420 omap4_cminst_clkdm_force_wakeup(clkdm->prcm_partition,
0421 clkdm->cm_inst, clkdm->clkdm_offs);
0422 return 0;
0423 }
0424
0425 static void omap4_clkdm_allow_idle(struct clockdomain *clkdm)
0426 {
0427 omap4_cminst_clkdm_enable_hwsup(clkdm->prcm_partition,
0428 clkdm->cm_inst, clkdm->clkdm_offs);
0429 }
0430
0431 static void omap4_clkdm_deny_idle(struct clockdomain *clkdm)
0432 {
0433 if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
0434 omap4_clkdm_wakeup(clkdm);
0435 else
0436 omap4_cminst_clkdm_disable_hwsup(clkdm->prcm_partition,
0437 clkdm->cm_inst,
0438 clkdm->clkdm_offs);
0439 }
0440
0441 static int omap4_clkdm_clk_enable(struct clockdomain *clkdm)
0442 {
0443 if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
0444 return omap4_clkdm_wakeup(clkdm);
0445
0446 return 0;
0447 }
0448
0449 static int omap4_clkdm_clk_disable(struct clockdomain *clkdm)
0450 {
0451 bool hwsup = false;
0452
0453 if (!clkdm->prcm_partition)
0454 return 0;
0455
0456
0457
0458
0459
0460
0461 if (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING &&
0462 !(clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) {
0463 omap4_clkdm_allow_idle(clkdm);
0464 return 0;
0465 }
0466
0467 hwsup = omap4_cminst_is_clkdm_in_hwsup(clkdm->prcm_partition,
0468 clkdm->cm_inst, clkdm->clkdm_offs);
0469
0470 if (!hwsup && (clkdm->flags & CLKDM_CAN_FORCE_SLEEP))
0471 omap4_clkdm_sleep(clkdm);
0472
0473 return 0;
0474 }
0475
0476 static u32 omap4_cminst_xlate_clkctrl(u8 part, u16 inst, u16 offset)
0477 {
0478 return _cm_bases[part].pa + inst + offset;
0479 }
0480
0481
0482
0483
0484
0485
0486
0487 static int omap4_clkdm_save_context(struct clockdomain *clkdm)
0488 {
0489 clkdm->context = omap4_cminst_read_inst_reg(clkdm->prcm_partition,
0490 clkdm->cm_inst,
0491 clkdm->clkdm_offs +
0492 OMAP4_CM_CLKSTCTRL);
0493 clkdm->context &= OMAP4430_MODULEMODE_MASK;
0494 return 0;
0495 }
0496
0497
0498
0499
0500
0501
0502
0503 static int omap4_clkdm_restore_context(struct clockdomain *clkdm)
0504 {
0505 switch (clkdm->context) {
0506 case OMAP34XX_CLKSTCTRL_DISABLE_AUTO:
0507 omap4_clkdm_deny_idle(clkdm);
0508 break;
0509 case OMAP34XX_CLKSTCTRL_FORCE_SLEEP:
0510 omap4_clkdm_sleep(clkdm);
0511 break;
0512 case OMAP34XX_CLKSTCTRL_FORCE_WAKEUP:
0513 omap4_clkdm_wakeup(clkdm);
0514 break;
0515 case OMAP34XX_CLKSTCTRL_ENABLE_AUTO:
0516 omap4_clkdm_allow_idle(clkdm);
0517 break;
0518 }
0519 return 0;
0520 }
0521
0522 struct clkdm_ops omap4_clkdm_operations = {
0523 .clkdm_add_wkdep = omap4_clkdm_add_wkup_sleep_dep,
0524 .clkdm_del_wkdep = omap4_clkdm_del_wkup_sleep_dep,
0525 .clkdm_read_wkdep = omap4_clkdm_read_wkup_sleep_dep,
0526 .clkdm_clear_all_wkdeps = omap4_clkdm_clear_all_wkup_sleep_deps,
0527 .clkdm_add_sleepdep = omap4_clkdm_add_wkup_sleep_dep,
0528 .clkdm_del_sleepdep = omap4_clkdm_del_wkup_sleep_dep,
0529 .clkdm_read_sleepdep = omap4_clkdm_read_wkup_sleep_dep,
0530 .clkdm_clear_all_sleepdeps = omap4_clkdm_clear_all_wkup_sleep_deps,
0531 .clkdm_sleep = omap4_clkdm_sleep,
0532 .clkdm_wakeup = omap4_clkdm_wakeup,
0533 .clkdm_allow_idle = omap4_clkdm_allow_idle,
0534 .clkdm_deny_idle = omap4_clkdm_deny_idle,
0535 .clkdm_clk_enable = omap4_clkdm_clk_enable,
0536 .clkdm_clk_disable = omap4_clkdm_clk_disable,
0537 .clkdm_save_context = omap4_clkdm_save_context,
0538 .clkdm_restore_context = omap4_clkdm_restore_context,
0539 };
0540
0541 struct clkdm_ops am43xx_clkdm_operations = {
0542 .clkdm_sleep = omap4_clkdm_sleep,
0543 .clkdm_wakeup = omap4_clkdm_wakeup,
0544 .clkdm_allow_idle = omap4_clkdm_allow_idle,
0545 .clkdm_deny_idle = omap4_clkdm_deny_idle,
0546 .clkdm_clk_enable = omap4_clkdm_clk_enable,
0547 .clkdm_clk_disable = omap4_clkdm_clk_disable,
0548 };
0549
0550 static const struct cm_ll_data omap4xxx_cm_ll_data = {
0551 .wait_module_ready = &omap4_cminst_wait_module_ready,
0552 .wait_module_idle = &omap4_cminst_wait_module_idle,
0553 .module_enable = &omap4_cminst_module_enable,
0554 .module_disable = &omap4_cminst_module_disable,
0555 .xlate_clkctrl = &omap4_cminst_xlate_clkctrl,
0556 };
0557
0558 int __init omap4_cm_init(const struct omap_prcm_init_data *data)
0559 {
0560 omap_cm_base_init();
0561
0562 return cm_register(&omap4xxx_cm_ll_data);
0563 }
0564
0565 static void __exit omap4_cm_exit(void)
0566 {
0567 cm_unregister(&omap4xxx_cm_ll_data);
0568 }
0569 __exitcall(omap4_cm_exit);