Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * OMAP3xxx CM module functions
0004  *
0005  * Copyright (C) 2009 Nokia Corporation
0006  * Copyright (C) 2008-2010, 2012 Texas Instruments, Inc.
0007  * Paul Walmsley
0008  * Rajendra Nayak <rnayak@ti.com>
0009  */
0010 
0011 #include <linux/kernel.h>
0012 #include <linux/types.h>
0013 #include <linux/delay.h>
0014 #include <linux/errno.h>
0015 #include <linux/err.h>
0016 #include <linux/io.h>
0017 
0018 #include "prm2xxx_3xxx.h"
0019 #include "cm.h"
0020 #include "cm3xxx.h"
0021 #include "cm-regbits-34xx.h"
0022 #include "clockdomain.h"
0023 
0024 static const u8 omap3xxx_cm_idlest_offs[] = {
0025     CM_IDLEST1, CM_IDLEST2, OMAP2430_CM_IDLEST3
0026 };
0027 
0028 /*
0029  *
0030  */
0031 
0032 static void _write_clktrctrl(u8 c, s16 module, u32 mask)
0033 {
0034     u32 v;
0035 
0036     v = omap2_cm_read_mod_reg(module, OMAP2_CM_CLKSTCTRL);
0037     v &= ~mask;
0038     v |= c << __ffs(mask);
0039     omap2_cm_write_mod_reg(v, module, OMAP2_CM_CLKSTCTRL);
0040 }
0041 
0042 static bool omap3xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask)
0043 {
0044     u32 v;
0045 
0046     v = omap2_cm_read_mod_reg(module, OMAP2_CM_CLKSTCTRL);
0047     v &= mask;
0048     v >>= __ffs(mask);
0049 
0050     return (v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ? 1 : 0;
0051 }
0052 
0053 static void omap3xxx_cm_clkdm_enable_hwsup(s16 module, u32 mask)
0054 {
0055     _write_clktrctrl(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, module, mask);
0056 }
0057 
0058 static void omap3xxx_cm_clkdm_disable_hwsup(s16 module, u32 mask)
0059 {
0060     _write_clktrctrl(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, module, mask);
0061 }
0062 
0063 static void omap3xxx_cm_clkdm_force_sleep(s16 module, u32 mask)
0064 {
0065     _write_clktrctrl(OMAP34XX_CLKSTCTRL_FORCE_SLEEP, module, mask);
0066 }
0067 
0068 static void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask)
0069 {
0070     _write_clktrctrl(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, module, mask);
0071 }
0072 
0073 /*
0074  *
0075  */
0076 
0077 /**
0078  * omap3xxx_cm_wait_module_ready - wait for a module to leave idle or standby
0079  * @part: PRCM partition, ignored for OMAP3
0080  * @prcm_mod: PRCM module offset
0081  * @idlest_id: CM_IDLESTx register ID (i.e., x = 1, 2, 3)
0082  * @idlest_shift: shift of the bit in the CM_IDLEST* register to check
0083  *
0084  * Wait for the PRCM to indicate that the module identified by
0085  * (@prcm_mod, @idlest_id, @idlest_shift) is clocked.  Return 0 upon
0086  * success or -EBUSY if the module doesn't enable in time.
0087  */
0088 static int omap3xxx_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_id,
0089                      u8 idlest_shift)
0090 {
0091     int ena = 0, i = 0;
0092     u8 cm_idlest_reg;
0093     u32 mask;
0094 
0095     if (!idlest_id || (idlest_id > ARRAY_SIZE(omap3xxx_cm_idlest_offs)))
0096         return -EINVAL;
0097 
0098     cm_idlest_reg = omap3xxx_cm_idlest_offs[idlest_id - 1];
0099 
0100     mask = 1 << idlest_shift;
0101     ena = 0;
0102 
0103     omap_test_timeout(((omap2_cm_read_mod_reg(prcm_mod, cm_idlest_reg) &
0104                 mask) == ena), MAX_MODULE_READY_TIME, i);
0105 
0106     return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
0107 }
0108 
0109 /**
0110  * omap3xxx_cm_split_idlest_reg - split CM_IDLEST reg addr into its components
0111  * @idlest_reg: CM_IDLEST* virtual address
0112  * @prcm_inst: pointer to an s16 to return the PRCM instance offset
0113  * @idlest_reg_id: pointer to a u8 to return the CM_IDLESTx register ID
0114  *
0115  * XXX This function is only needed until absolute register addresses are
0116  * removed from the OMAP struct clk records.
0117  */
0118 static int omap3xxx_cm_split_idlest_reg(struct clk_omap_reg *idlest_reg,
0119                     s16 *prcm_inst,
0120                     u8 *idlest_reg_id)
0121 {
0122     unsigned long offs;
0123     u8 idlest_offs;
0124     int i;
0125 
0126     idlest_offs = idlest_reg->offset & 0xff;
0127     for (i = 0; i < ARRAY_SIZE(omap3xxx_cm_idlest_offs); i++) {
0128         if (idlest_offs == omap3xxx_cm_idlest_offs[i]) {
0129             *idlest_reg_id = i + 1;
0130             break;
0131         }
0132     }
0133 
0134     if (i == ARRAY_SIZE(omap3xxx_cm_idlest_offs))
0135         return -EINVAL;
0136 
0137     offs = idlest_reg->offset;
0138     offs &= 0xff00;
0139     *prcm_inst = offs;
0140 
0141     return 0;
0142 }
0143 
0144 /* Clockdomain low-level operations */
0145 
0146 static int omap3xxx_clkdm_add_sleepdep(struct clockdomain *clkdm1,
0147                        struct clockdomain *clkdm2)
0148 {
0149     omap2_cm_set_mod_reg_bits((1 << clkdm2->dep_bit),
0150                   clkdm1->pwrdm.ptr->prcm_offs,
0151                   OMAP3430_CM_SLEEPDEP);
0152     return 0;
0153 }
0154 
0155 static int omap3xxx_clkdm_del_sleepdep(struct clockdomain *clkdm1,
0156                        struct clockdomain *clkdm2)
0157 {
0158     omap2_cm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
0159                     clkdm1->pwrdm.ptr->prcm_offs,
0160                     OMAP3430_CM_SLEEPDEP);
0161     return 0;
0162 }
0163 
0164 static int omap3xxx_clkdm_read_sleepdep(struct clockdomain *clkdm1,
0165                     struct clockdomain *clkdm2)
0166 {
0167     return omap2_cm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs,
0168                         OMAP3430_CM_SLEEPDEP,
0169                         (1 << clkdm2->dep_bit));
0170 }
0171 
0172 static int omap3xxx_clkdm_clear_all_sleepdeps(struct clockdomain *clkdm)
0173 {
0174     struct clkdm_dep *cd;
0175     u32 mask = 0;
0176 
0177     for (cd = clkdm->sleepdep_srcs; cd && cd->clkdm_name; cd++) {
0178         if (!cd->clkdm)
0179             continue; /* only happens if data is erroneous */
0180 
0181         mask |= 1 << cd->clkdm->dep_bit;
0182         cd->sleepdep_usecount = 0;
0183     }
0184     omap2_cm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs,
0185                     OMAP3430_CM_SLEEPDEP);
0186     return 0;
0187 }
0188 
0189 static int omap3xxx_clkdm_sleep(struct clockdomain *clkdm)
0190 {
0191     omap3xxx_cm_clkdm_force_sleep(clkdm->pwrdm.ptr->prcm_offs,
0192                       clkdm->clktrctrl_mask);
0193     return 0;
0194 }
0195 
0196 static int omap3xxx_clkdm_wakeup(struct clockdomain *clkdm)
0197 {
0198     omap3xxx_cm_clkdm_force_wakeup(clkdm->pwrdm.ptr->prcm_offs,
0199                        clkdm->clktrctrl_mask);
0200     return 0;
0201 }
0202 
0203 static void omap3xxx_clkdm_allow_idle(struct clockdomain *clkdm)
0204 {
0205     if (clkdm->usecount > 0)
0206         clkdm_add_autodeps(clkdm);
0207 
0208     omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
0209                        clkdm->clktrctrl_mask);
0210 }
0211 
0212 static void omap3xxx_clkdm_deny_idle(struct clockdomain *clkdm)
0213 {
0214     omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
0215                     clkdm->clktrctrl_mask);
0216 
0217     if (clkdm->usecount > 0)
0218         clkdm_del_autodeps(clkdm);
0219 }
0220 
0221 static int omap3xxx_clkdm_clk_enable(struct clockdomain *clkdm)
0222 {
0223     bool hwsup = false;
0224 
0225     if (!clkdm->clktrctrl_mask)
0226         return 0;
0227 
0228     /*
0229      * The CLKDM_MISSING_IDLE_REPORTING flag documentation has
0230      * more details on the unpleasant problem this is working
0231      * around
0232      */
0233     if ((clkdm->flags & CLKDM_MISSING_IDLE_REPORTING) &&
0234         (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)) {
0235         omap3xxx_clkdm_wakeup(clkdm);
0236         return 0;
0237     }
0238 
0239     hwsup = omap3xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
0240                           clkdm->clktrctrl_mask);
0241 
0242     if (hwsup) {
0243         /* Disable HW transitions when we are changing deps */
0244         omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
0245                         clkdm->clktrctrl_mask);
0246         clkdm_add_autodeps(clkdm);
0247         omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
0248                            clkdm->clktrctrl_mask);
0249     } else {
0250         if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
0251             omap3xxx_clkdm_wakeup(clkdm);
0252     }
0253 
0254     return 0;
0255 }
0256 
0257 static int omap3xxx_clkdm_clk_disable(struct clockdomain *clkdm)
0258 {
0259     bool hwsup = false;
0260 
0261     if (!clkdm->clktrctrl_mask)
0262         return 0;
0263 
0264     /*
0265      * The CLKDM_MISSING_IDLE_REPORTING flag documentation has
0266      * more details on the unpleasant problem this is working
0267      * around
0268      */
0269     if (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING &&
0270         !(clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) {
0271         omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
0272                            clkdm->clktrctrl_mask);
0273         return 0;
0274     }
0275 
0276     hwsup = omap3xxx_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
0277                           clkdm->clktrctrl_mask);
0278 
0279     if (hwsup) {
0280         /* Disable HW transitions when we are changing deps */
0281         omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
0282                         clkdm->clktrctrl_mask);
0283         clkdm_del_autodeps(clkdm);
0284         omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
0285                            clkdm->clktrctrl_mask);
0286     } else {
0287         if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP)
0288             omap3xxx_clkdm_sleep(clkdm);
0289     }
0290 
0291     return 0;
0292 }
0293 
0294 struct clkdm_ops omap3_clkdm_operations = {
0295     .clkdm_add_wkdep    = omap2_clkdm_add_wkdep,
0296     .clkdm_del_wkdep    = omap2_clkdm_del_wkdep,
0297     .clkdm_read_wkdep   = omap2_clkdm_read_wkdep,
0298     .clkdm_clear_all_wkdeps = omap2_clkdm_clear_all_wkdeps,
0299     .clkdm_add_sleepdep = omap3xxx_clkdm_add_sleepdep,
0300     .clkdm_del_sleepdep = omap3xxx_clkdm_del_sleepdep,
0301     .clkdm_read_sleepdep    = omap3xxx_clkdm_read_sleepdep,
0302     .clkdm_clear_all_sleepdeps  = omap3xxx_clkdm_clear_all_sleepdeps,
0303     .clkdm_sleep        = omap3xxx_clkdm_sleep,
0304     .clkdm_wakeup       = omap3xxx_clkdm_wakeup,
0305     .clkdm_allow_idle   = omap3xxx_clkdm_allow_idle,
0306     .clkdm_deny_idle    = omap3xxx_clkdm_deny_idle,
0307     .clkdm_clk_enable   = omap3xxx_clkdm_clk_enable,
0308     .clkdm_clk_disable  = omap3xxx_clkdm_clk_disable,
0309 };
0310 
0311 /*
0312  * Context save/restore code - OMAP3 only
0313  */
0314 struct omap3_cm_regs {
0315     u32 iva2_cm_clksel1;
0316     u32 iva2_cm_clksel2;
0317     u32 cm_sysconfig;
0318     u32 sgx_cm_clksel;
0319     u32 dss_cm_clksel;
0320     u32 cam_cm_clksel;
0321     u32 per_cm_clksel;
0322     u32 emu_cm_clksel;
0323     u32 emu_cm_clkstctrl;
0324     u32 pll_cm_autoidle;
0325     u32 pll_cm_autoidle2;
0326     u32 pll_cm_clksel4;
0327     u32 pll_cm_clksel5;
0328     u32 pll_cm_clken2;
0329     u32 cm_polctrl;
0330     u32 iva2_cm_fclken;
0331     u32 iva2_cm_clken_pll;
0332     u32 core_cm_fclken1;
0333     u32 core_cm_fclken3;
0334     u32 sgx_cm_fclken;
0335     u32 wkup_cm_fclken;
0336     u32 dss_cm_fclken;
0337     u32 cam_cm_fclken;
0338     u32 per_cm_fclken;
0339     u32 usbhost_cm_fclken;
0340     u32 core_cm_iclken1;
0341     u32 core_cm_iclken2;
0342     u32 core_cm_iclken3;
0343     u32 sgx_cm_iclken;
0344     u32 wkup_cm_iclken;
0345     u32 dss_cm_iclken;
0346     u32 cam_cm_iclken;
0347     u32 per_cm_iclken;
0348     u32 usbhost_cm_iclken;
0349     u32 iva2_cm_autoidle2;
0350     u32 mpu_cm_autoidle2;
0351     u32 iva2_cm_clkstctrl;
0352     u32 mpu_cm_clkstctrl;
0353     u32 core_cm_clkstctrl;
0354     u32 sgx_cm_clkstctrl;
0355     u32 dss_cm_clkstctrl;
0356     u32 cam_cm_clkstctrl;
0357     u32 per_cm_clkstctrl;
0358     u32 neon_cm_clkstctrl;
0359     u32 usbhost_cm_clkstctrl;
0360     u32 core_cm_autoidle1;
0361     u32 core_cm_autoidle2;
0362     u32 core_cm_autoidle3;
0363     u32 wkup_cm_autoidle;
0364     u32 dss_cm_autoidle;
0365     u32 cam_cm_autoidle;
0366     u32 per_cm_autoidle;
0367     u32 usbhost_cm_autoidle;
0368     u32 sgx_cm_sleepdep;
0369     u32 dss_cm_sleepdep;
0370     u32 cam_cm_sleepdep;
0371     u32 per_cm_sleepdep;
0372     u32 usbhost_cm_sleepdep;
0373     u32 cm_clkout_ctrl;
0374 };
0375 
0376 static struct omap3_cm_regs cm_context;
0377 
0378 void omap3_cm_save_context(void)
0379 {
0380     cm_context.iva2_cm_clksel1 =
0381         omap2_cm_read_mod_reg(OMAP3430_IVA2_MOD, CM_CLKSEL1);
0382     cm_context.iva2_cm_clksel2 =
0383         omap2_cm_read_mod_reg(OMAP3430_IVA2_MOD, CM_CLKSEL2);
0384     cm_context.cm_sysconfig =
0385         omap2_cm_read_mod_reg(OCP_MOD, OMAP3430_CM_SYSCONFIG);
0386     cm_context.sgx_cm_clksel =
0387         omap2_cm_read_mod_reg(OMAP3430ES2_SGX_MOD, CM_CLKSEL);
0388     cm_context.dss_cm_clksel =
0389         omap2_cm_read_mod_reg(OMAP3430_DSS_MOD, CM_CLKSEL);
0390     cm_context.cam_cm_clksel =
0391         omap2_cm_read_mod_reg(OMAP3430_CAM_MOD, CM_CLKSEL);
0392     cm_context.per_cm_clksel =
0393         omap2_cm_read_mod_reg(OMAP3430_PER_MOD, CM_CLKSEL);
0394     cm_context.emu_cm_clksel =
0395         omap2_cm_read_mod_reg(OMAP3430_EMU_MOD, CM_CLKSEL1);
0396     cm_context.emu_cm_clkstctrl =
0397         omap2_cm_read_mod_reg(OMAP3430_EMU_MOD, OMAP2_CM_CLKSTCTRL);
0398     /*
0399      * As per erratum i671, ROM code does not respect the PER DPLL
0400      * programming scheme if CM_AUTOIDLE_PLL.AUTO_PERIPH_DPLL == 1.
0401      * In this case, even though this register has been saved in
0402      * scratchpad contents, we need to restore AUTO_PERIPH_DPLL
0403      * by ourselves. So, we need to save it anyway.
0404      */
0405     cm_context.pll_cm_autoidle =
0406         omap2_cm_read_mod_reg(PLL_MOD, CM_AUTOIDLE);
0407     cm_context.pll_cm_autoidle2 =
0408         omap2_cm_read_mod_reg(PLL_MOD, CM_AUTOIDLE2);
0409     cm_context.pll_cm_clksel4 =
0410         omap2_cm_read_mod_reg(PLL_MOD, OMAP3430ES2_CM_CLKSEL4);
0411     cm_context.pll_cm_clksel5 =
0412         omap2_cm_read_mod_reg(PLL_MOD, OMAP3430ES2_CM_CLKSEL5);
0413     cm_context.pll_cm_clken2 =
0414         omap2_cm_read_mod_reg(PLL_MOD, OMAP3430ES2_CM_CLKEN2);
0415     cm_context.cm_polctrl =
0416         omap2_cm_read_mod_reg(OCP_MOD, OMAP3430_CM_POLCTRL);
0417     cm_context.iva2_cm_fclken =
0418         omap2_cm_read_mod_reg(OMAP3430_IVA2_MOD, CM_FCLKEN);
0419     cm_context.iva2_cm_clken_pll =
0420         omap2_cm_read_mod_reg(OMAP3430_IVA2_MOD, OMAP3430_CM_CLKEN_PLL);
0421     cm_context.core_cm_fclken1 =
0422         omap2_cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
0423     cm_context.core_cm_fclken3 =
0424         omap2_cm_read_mod_reg(CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
0425     cm_context.sgx_cm_fclken =
0426         omap2_cm_read_mod_reg(OMAP3430ES2_SGX_MOD, CM_FCLKEN);
0427     cm_context.wkup_cm_fclken =
0428         omap2_cm_read_mod_reg(WKUP_MOD, CM_FCLKEN);
0429     cm_context.dss_cm_fclken =
0430         omap2_cm_read_mod_reg(OMAP3430_DSS_MOD, CM_FCLKEN);
0431     cm_context.cam_cm_fclken =
0432         omap2_cm_read_mod_reg(OMAP3430_CAM_MOD, CM_FCLKEN);
0433     cm_context.per_cm_fclken =
0434         omap2_cm_read_mod_reg(OMAP3430_PER_MOD, CM_FCLKEN);
0435     cm_context.usbhost_cm_fclken =
0436         omap2_cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, CM_FCLKEN);
0437     cm_context.core_cm_iclken1 =
0438         omap2_cm_read_mod_reg(CORE_MOD, CM_ICLKEN1);
0439     cm_context.core_cm_iclken2 =
0440         omap2_cm_read_mod_reg(CORE_MOD, CM_ICLKEN2);
0441     cm_context.core_cm_iclken3 =
0442         omap2_cm_read_mod_reg(CORE_MOD, CM_ICLKEN3);
0443     cm_context.sgx_cm_iclken =
0444         omap2_cm_read_mod_reg(OMAP3430ES2_SGX_MOD, CM_ICLKEN);
0445     cm_context.wkup_cm_iclken =
0446         omap2_cm_read_mod_reg(WKUP_MOD, CM_ICLKEN);
0447     cm_context.dss_cm_iclken =
0448         omap2_cm_read_mod_reg(OMAP3430_DSS_MOD, CM_ICLKEN);
0449     cm_context.cam_cm_iclken =
0450         omap2_cm_read_mod_reg(OMAP3430_CAM_MOD, CM_ICLKEN);
0451     cm_context.per_cm_iclken =
0452         omap2_cm_read_mod_reg(OMAP3430_PER_MOD, CM_ICLKEN);
0453     cm_context.usbhost_cm_iclken =
0454         omap2_cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, CM_ICLKEN);
0455     cm_context.iva2_cm_autoidle2 =
0456         omap2_cm_read_mod_reg(OMAP3430_IVA2_MOD, CM_AUTOIDLE2);
0457     cm_context.mpu_cm_autoidle2 =
0458         omap2_cm_read_mod_reg(MPU_MOD, CM_AUTOIDLE2);
0459     cm_context.iva2_cm_clkstctrl =
0460         omap2_cm_read_mod_reg(OMAP3430_IVA2_MOD, OMAP2_CM_CLKSTCTRL);
0461     cm_context.mpu_cm_clkstctrl =
0462         omap2_cm_read_mod_reg(MPU_MOD, OMAP2_CM_CLKSTCTRL);
0463     cm_context.core_cm_clkstctrl =
0464         omap2_cm_read_mod_reg(CORE_MOD, OMAP2_CM_CLKSTCTRL);
0465     cm_context.sgx_cm_clkstctrl =
0466         omap2_cm_read_mod_reg(OMAP3430ES2_SGX_MOD, OMAP2_CM_CLKSTCTRL);
0467     cm_context.dss_cm_clkstctrl =
0468         omap2_cm_read_mod_reg(OMAP3430_DSS_MOD, OMAP2_CM_CLKSTCTRL);
0469     cm_context.cam_cm_clkstctrl =
0470         omap2_cm_read_mod_reg(OMAP3430_CAM_MOD, OMAP2_CM_CLKSTCTRL);
0471     cm_context.per_cm_clkstctrl =
0472         omap2_cm_read_mod_reg(OMAP3430_PER_MOD, OMAP2_CM_CLKSTCTRL);
0473     cm_context.neon_cm_clkstctrl =
0474         omap2_cm_read_mod_reg(OMAP3430_NEON_MOD, OMAP2_CM_CLKSTCTRL);
0475     cm_context.usbhost_cm_clkstctrl =
0476         omap2_cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
0477                       OMAP2_CM_CLKSTCTRL);
0478     cm_context.core_cm_autoidle1 =
0479         omap2_cm_read_mod_reg(CORE_MOD, CM_AUTOIDLE1);
0480     cm_context.core_cm_autoidle2 =
0481         omap2_cm_read_mod_reg(CORE_MOD, CM_AUTOIDLE2);
0482     cm_context.core_cm_autoidle3 =
0483         omap2_cm_read_mod_reg(CORE_MOD, CM_AUTOIDLE3);
0484     cm_context.wkup_cm_autoidle =
0485         omap2_cm_read_mod_reg(WKUP_MOD, CM_AUTOIDLE);
0486     cm_context.dss_cm_autoidle =
0487         omap2_cm_read_mod_reg(OMAP3430_DSS_MOD, CM_AUTOIDLE);
0488     cm_context.cam_cm_autoidle =
0489         omap2_cm_read_mod_reg(OMAP3430_CAM_MOD, CM_AUTOIDLE);
0490     cm_context.per_cm_autoidle =
0491         omap2_cm_read_mod_reg(OMAP3430_PER_MOD, CM_AUTOIDLE);
0492     cm_context.usbhost_cm_autoidle =
0493         omap2_cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, CM_AUTOIDLE);
0494     cm_context.sgx_cm_sleepdep =
0495         omap2_cm_read_mod_reg(OMAP3430ES2_SGX_MOD,
0496                       OMAP3430_CM_SLEEPDEP);
0497     cm_context.dss_cm_sleepdep =
0498         omap2_cm_read_mod_reg(OMAP3430_DSS_MOD, OMAP3430_CM_SLEEPDEP);
0499     cm_context.cam_cm_sleepdep =
0500         omap2_cm_read_mod_reg(OMAP3430_CAM_MOD, OMAP3430_CM_SLEEPDEP);
0501     cm_context.per_cm_sleepdep =
0502         omap2_cm_read_mod_reg(OMAP3430_PER_MOD, OMAP3430_CM_SLEEPDEP);
0503     cm_context.usbhost_cm_sleepdep =
0504         omap2_cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
0505                       OMAP3430_CM_SLEEPDEP);
0506     cm_context.cm_clkout_ctrl =
0507         omap2_cm_read_mod_reg(OMAP3430_CCR_MOD,
0508                       OMAP3_CM_CLKOUT_CTRL_OFFSET);
0509 }
0510 
0511 void omap3_cm_restore_context(void)
0512 {
0513     omap2_cm_write_mod_reg(cm_context.iva2_cm_clksel1, OMAP3430_IVA2_MOD,
0514                    CM_CLKSEL1);
0515     omap2_cm_write_mod_reg(cm_context.iva2_cm_clksel2, OMAP3430_IVA2_MOD,
0516                    CM_CLKSEL2);
0517     omap2_cm_write_mod_reg(cm_context.cm_sysconfig, OCP_MOD,
0518                    OMAP3430_CM_SYSCONFIG);
0519     omap2_cm_write_mod_reg(cm_context.sgx_cm_clksel, OMAP3430ES2_SGX_MOD,
0520                    CM_CLKSEL);
0521     omap2_cm_write_mod_reg(cm_context.dss_cm_clksel, OMAP3430_DSS_MOD,
0522                    CM_CLKSEL);
0523     omap2_cm_write_mod_reg(cm_context.cam_cm_clksel, OMAP3430_CAM_MOD,
0524                    CM_CLKSEL);
0525     omap2_cm_write_mod_reg(cm_context.per_cm_clksel, OMAP3430_PER_MOD,
0526                    CM_CLKSEL);
0527     omap2_cm_write_mod_reg(cm_context.emu_cm_clksel, OMAP3430_EMU_MOD,
0528                    CM_CLKSEL1);
0529     omap2_cm_write_mod_reg(cm_context.emu_cm_clkstctrl, OMAP3430_EMU_MOD,
0530                    OMAP2_CM_CLKSTCTRL);
0531     /*
0532      * As per erratum i671, ROM code does not respect the PER DPLL
0533      * programming scheme if CM_AUTOIDLE_PLL.AUTO_PERIPH_DPLL == 1.
0534      * In this case, we need to restore AUTO_PERIPH_DPLL by ourselves.
0535      */
0536     omap2_cm_write_mod_reg(cm_context.pll_cm_autoidle, PLL_MOD,
0537                    CM_AUTOIDLE);
0538     omap2_cm_write_mod_reg(cm_context.pll_cm_autoidle2, PLL_MOD,
0539                    CM_AUTOIDLE2);
0540     omap2_cm_write_mod_reg(cm_context.pll_cm_clksel4, PLL_MOD,
0541                    OMAP3430ES2_CM_CLKSEL4);
0542     omap2_cm_write_mod_reg(cm_context.pll_cm_clksel5, PLL_MOD,
0543                    OMAP3430ES2_CM_CLKSEL5);
0544     omap2_cm_write_mod_reg(cm_context.pll_cm_clken2, PLL_MOD,
0545                    OMAP3430ES2_CM_CLKEN2);
0546     omap2_cm_write_mod_reg(cm_context.cm_polctrl, OCP_MOD,
0547                    OMAP3430_CM_POLCTRL);
0548     omap2_cm_write_mod_reg(cm_context.iva2_cm_fclken, OMAP3430_IVA2_MOD,
0549                    CM_FCLKEN);
0550     omap2_cm_write_mod_reg(cm_context.iva2_cm_clken_pll, OMAP3430_IVA2_MOD,
0551                    OMAP3430_CM_CLKEN_PLL);
0552     omap2_cm_write_mod_reg(cm_context.core_cm_fclken1, CORE_MOD,
0553                    CM_FCLKEN1);
0554     omap2_cm_write_mod_reg(cm_context.core_cm_fclken3, CORE_MOD,
0555                    OMAP3430ES2_CM_FCLKEN3);
0556     omap2_cm_write_mod_reg(cm_context.sgx_cm_fclken, OMAP3430ES2_SGX_MOD,
0557                    CM_FCLKEN);
0558     omap2_cm_write_mod_reg(cm_context.wkup_cm_fclken, WKUP_MOD, CM_FCLKEN);
0559     omap2_cm_write_mod_reg(cm_context.dss_cm_fclken, OMAP3430_DSS_MOD,
0560                    CM_FCLKEN);
0561     omap2_cm_write_mod_reg(cm_context.cam_cm_fclken, OMAP3430_CAM_MOD,
0562                    CM_FCLKEN);
0563     omap2_cm_write_mod_reg(cm_context.per_cm_fclken, OMAP3430_PER_MOD,
0564                    CM_FCLKEN);
0565     omap2_cm_write_mod_reg(cm_context.usbhost_cm_fclken,
0566                    OMAP3430ES2_USBHOST_MOD, CM_FCLKEN);
0567     omap2_cm_write_mod_reg(cm_context.core_cm_iclken1, CORE_MOD,
0568                    CM_ICLKEN1);
0569     omap2_cm_write_mod_reg(cm_context.core_cm_iclken2, CORE_MOD,
0570                    CM_ICLKEN2);
0571     omap2_cm_write_mod_reg(cm_context.core_cm_iclken3, CORE_MOD,
0572                    CM_ICLKEN3);
0573     omap2_cm_write_mod_reg(cm_context.sgx_cm_iclken, OMAP3430ES2_SGX_MOD,
0574                    CM_ICLKEN);
0575     omap2_cm_write_mod_reg(cm_context.wkup_cm_iclken, WKUP_MOD, CM_ICLKEN);
0576     omap2_cm_write_mod_reg(cm_context.dss_cm_iclken, OMAP3430_DSS_MOD,
0577                    CM_ICLKEN);
0578     omap2_cm_write_mod_reg(cm_context.cam_cm_iclken, OMAP3430_CAM_MOD,
0579                    CM_ICLKEN);
0580     omap2_cm_write_mod_reg(cm_context.per_cm_iclken, OMAP3430_PER_MOD,
0581                    CM_ICLKEN);
0582     omap2_cm_write_mod_reg(cm_context.usbhost_cm_iclken,
0583                    OMAP3430ES2_USBHOST_MOD, CM_ICLKEN);
0584     omap2_cm_write_mod_reg(cm_context.iva2_cm_autoidle2, OMAP3430_IVA2_MOD,
0585                    CM_AUTOIDLE2);
0586     omap2_cm_write_mod_reg(cm_context.mpu_cm_autoidle2, MPU_MOD,
0587                    CM_AUTOIDLE2);
0588     omap2_cm_write_mod_reg(cm_context.iva2_cm_clkstctrl, OMAP3430_IVA2_MOD,
0589                    OMAP2_CM_CLKSTCTRL);
0590     omap2_cm_write_mod_reg(cm_context.mpu_cm_clkstctrl, MPU_MOD,
0591                    OMAP2_CM_CLKSTCTRL);
0592     omap2_cm_write_mod_reg(cm_context.core_cm_clkstctrl, CORE_MOD,
0593                    OMAP2_CM_CLKSTCTRL);
0594     omap2_cm_write_mod_reg(cm_context.sgx_cm_clkstctrl, OMAP3430ES2_SGX_MOD,
0595                    OMAP2_CM_CLKSTCTRL);
0596     omap2_cm_write_mod_reg(cm_context.dss_cm_clkstctrl, OMAP3430_DSS_MOD,
0597                    OMAP2_CM_CLKSTCTRL);
0598     omap2_cm_write_mod_reg(cm_context.cam_cm_clkstctrl, OMAP3430_CAM_MOD,
0599                    OMAP2_CM_CLKSTCTRL);
0600     omap2_cm_write_mod_reg(cm_context.per_cm_clkstctrl, OMAP3430_PER_MOD,
0601                    OMAP2_CM_CLKSTCTRL);
0602     omap2_cm_write_mod_reg(cm_context.neon_cm_clkstctrl, OMAP3430_NEON_MOD,
0603                    OMAP2_CM_CLKSTCTRL);
0604     omap2_cm_write_mod_reg(cm_context.usbhost_cm_clkstctrl,
0605                    OMAP3430ES2_USBHOST_MOD, OMAP2_CM_CLKSTCTRL);
0606     omap2_cm_write_mod_reg(cm_context.core_cm_autoidle1, CORE_MOD,
0607                    CM_AUTOIDLE1);
0608     omap2_cm_write_mod_reg(cm_context.core_cm_autoidle2, CORE_MOD,
0609                    CM_AUTOIDLE2);
0610     omap2_cm_write_mod_reg(cm_context.core_cm_autoidle3, CORE_MOD,
0611                    CM_AUTOIDLE3);
0612     omap2_cm_write_mod_reg(cm_context.wkup_cm_autoidle, WKUP_MOD,
0613                    CM_AUTOIDLE);
0614     omap2_cm_write_mod_reg(cm_context.dss_cm_autoidle, OMAP3430_DSS_MOD,
0615                    CM_AUTOIDLE);
0616     omap2_cm_write_mod_reg(cm_context.cam_cm_autoidle, OMAP3430_CAM_MOD,
0617                    CM_AUTOIDLE);
0618     omap2_cm_write_mod_reg(cm_context.per_cm_autoidle, OMAP3430_PER_MOD,
0619                    CM_AUTOIDLE);
0620     omap2_cm_write_mod_reg(cm_context.usbhost_cm_autoidle,
0621                    OMAP3430ES2_USBHOST_MOD, CM_AUTOIDLE);
0622     omap2_cm_write_mod_reg(cm_context.sgx_cm_sleepdep, OMAP3430ES2_SGX_MOD,
0623                    OMAP3430_CM_SLEEPDEP);
0624     omap2_cm_write_mod_reg(cm_context.dss_cm_sleepdep, OMAP3430_DSS_MOD,
0625                    OMAP3430_CM_SLEEPDEP);
0626     omap2_cm_write_mod_reg(cm_context.cam_cm_sleepdep, OMAP3430_CAM_MOD,
0627                    OMAP3430_CM_SLEEPDEP);
0628     omap2_cm_write_mod_reg(cm_context.per_cm_sleepdep, OMAP3430_PER_MOD,
0629                    OMAP3430_CM_SLEEPDEP);
0630     omap2_cm_write_mod_reg(cm_context.usbhost_cm_sleepdep,
0631                    OMAP3430ES2_USBHOST_MOD, OMAP3430_CM_SLEEPDEP);
0632     omap2_cm_write_mod_reg(cm_context.cm_clkout_ctrl, OMAP3430_CCR_MOD,
0633                    OMAP3_CM_CLKOUT_CTRL_OFFSET);
0634 }
0635 
0636 void omap3_cm_save_scratchpad_contents(u32 *ptr)
0637 {
0638     *ptr++ = omap2_cm_read_mod_reg(CORE_MOD, CM_CLKSEL);
0639     *ptr++ = omap2_cm_read_mod_reg(WKUP_MOD, CM_CLKSEL);
0640     *ptr++ = omap2_cm_read_mod_reg(PLL_MOD, CM_CLKEN);
0641 
0642     /*
0643      * As per erratum i671, ROM code does not respect the PER DPLL
0644      * programming scheme if CM_AUTOIDLE_PLL..AUTO_PERIPH_DPLL == 1.
0645      * Then,  in any case, clear these bits to avoid extra latencies.
0646      */
0647     *ptr++ = omap2_cm_read_mod_reg(PLL_MOD, CM_AUTOIDLE) &
0648         ~OMAP3430_AUTO_PERIPH_DPLL_MASK;
0649     *ptr++ = omap2_cm_read_mod_reg(PLL_MOD, OMAP3430_CM_CLKSEL1_PLL);
0650     *ptr++ = omap2_cm_read_mod_reg(PLL_MOD, OMAP3430_CM_CLKSEL2_PLL);
0651     *ptr++ = omap2_cm_read_mod_reg(PLL_MOD, OMAP3430_CM_CLKSEL3);
0652     *ptr++ = omap2_cm_read_mod_reg(MPU_MOD, OMAP3430_CM_CLKEN_PLL);
0653     *ptr++ = omap2_cm_read_mod_reg(MPU_MOD, OMAP3430_CM_AUTOIDLE_PLL);
0654     *ptr++ = omap2_cm_read_mod_reg(MPU_MOD, OMAP3430_CM_CLKSEL1_PLL);
0655     *ptr++ = omap2_cm_read_mod_reg(MPU_MOD, OMAP3430_CM_CLKSEL2_PLL);
0656 }
0657 
0658 /*
0659  *
0660  */
0661 
0662 static const struct cm_ll_data omap3xxx_cm_ll_data = {
0663     .split_idlest_reg   = &omap3xxx_cm_split_idlest_reg,
0664     .wait_module_ready  = &omap3xxx_cm_wait_module_ready,
0665 };
0666 
0667 int __init omap3xxx_cm_init(const struct omap_prcm_init_data *data)
0668 {
0669     omap2_clk_legacy_provider_init(TI_CLKM_CM, cm_base.va +
0670                        OMAP3430_IVA2_MOD);
0671     return cm_register(&omap3xxx_cm_ll_data);
0672 }
0673 
0674 static void __exit omap3xxx_cm_exit(void)
0675 {
0676     cm_unregister(&omap3xxx_cm_ll_data);
0677 }
0678 __exitcall(omap3xxx_cm_exit);