Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  cm33xx.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * AM33XX CM functions
 *
 * Copyright (C) 2011-2012 Texas Instruments Incorporated - https://www.ti.com/
 * Vaibhav Hiremath <hvaibhav@ti.com>
 *
 * Reference taken from OMAP4 cminst44xx.c
 */


#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/io.h>

#include "clockdomain.h"
#include "cm.h"
#include "cm33xx.h"
#include "cm-regbits-34xx.h"
#include "cm-regbits-33xx.h"
#include "prm33xx.h"
#if IS_ENABLED(CONFIG_SUSPEND)
#include <linux/suspend.h>
#endif

/*
 * CLKCTRL_IDLEST_*: possible values for the CM_*_CLKCTRL.IDLEST bitfield:
 *
 *   0x0 func:     Module is fully functional, including OCP
 *   0x1 trans:    Module is performing transition: wakeup, or sleep, or sleep
 *                 abortion
 *   0x2 idle:     Module is in Idle mode (only OCP part). It is functional if
 *                 using separate functional clock
 *   0x3 disabled: Module is disabled and cannot be accessed
 *
 */

#define CLKCTRL_IDLEST_FUNCTIONAL  0x0
#define CLKCTRL_IDLEST_INTRANSITION  0x1
#define CLKCTRL_IDLEST_INTERFACE_IDLE  0x2
#define CLKCTRL_IDLEST_DISABLED   0x3

/* Private functions */

/* Read a register in a CM instance */
static inline u32 am33xx_cm_read_reg(u16 inst, u16 idx)
{
 return readl_relaxed(cm_base.va + inst + idx);
}

/* Write into a register in a CM */
static inline void am33xx_cm_write_reg(u32 val, u16 inst, u16 idx)
{
 writel_relaxed(val, cm_base.va + inst + idx);
}

/* Read-modify-write a register in CM */
static inline u32 am33xx_cm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx)
{
 u32 v;

 v = am33xx_cm_read_reg(inst, idx);
 v &= ~mask;
 v |= bits;
 am33xx_cm_write_reg(v, inst, idx);

 return v;
}

static inline u32 am33xx_cm_read_reg_bits(u16 inst, s16 idx, u32 mask)
{
 u32 v;

 v = am33xx_cm_read_reg(inst, idx);
 v &= mask;
 v >>= __ffs(mask);

 return v;
}

/**
 * _clkctrl_idlest - read a CM_*_CLKCTRL register; mask & shift IDLEST bitfield
 * @inst: CM instance register offset (*_INST macro)
 * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
 *
 * Return the IDLEST bitfield of a CM_*_CLKCTRL register, shifted down to
 * bit 0.
 */

static u32 _clkctrl_idlest(u16 inst, u16 clkctrl_offs)
{
 u32 v = am33xx_cm_read_reg(inst, clkctrl_offs);
 v &= AM33XX_IDLEST_MASK;
 v >>= AM33XX_IDLEST_SHIFT;
 return v;
}

/**
 * _is_module_ready - can module registers be accessed without causing an abort?
 * @inst: CM instance register offset (*_INST macro)
 * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
 *
 * Returns true if the module's CM_*_CLKCTRL.IDLEST bitfield is either
 * *FUNCTIONAL or *INTERFACE_IDLE; false otherwise.
 */

static bool _is_module_ready(u16 inst, u16 clkctrl_offs)
{
 u32 v;

 v = _clkctrl_idlest(inst, clkctrl_offs);

 return (v == CLKCTRL_IDLEST_FUNCTIONAL ||
  v == CLKCTRL_IDLEST_INTERFACE_IDLE) ? true : false;
}

/**
 * _clktrctrl_write - write @c to a CM_CLKSTCTRL.CLKTRCTRL register bitfield
 * @c: CLKTRCTRL register bitfield (LSB = bit 0, i.e., unshifted)
 * @inst: CM instance register offset (*_INST macro)
 * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
 *
 * @c must be the unshifted value for CLKTRCTRL - i.e., this function
 * will handle the shift itself.
 */

static void _clktrctrl_write(u8 c, u16 inst, u16 cdoffs)
{
 u32 v;

 v = am33xx_cm_read_reg(inst, cdoffs);
 v &= ~AM33XX_CLKTRCTRL_MASK;
 v |= c << AM33XX_CLKTRCTRL_SHIFT;
 am33xx_cm_write_reg(v, inst, cdoffs);
}

/* Public functions */

/**
 * am33xx_cm_is_clkdm_in_hwsup - is a clockdomain in hwsup idle mode?
 * @inst: CM instance register offset (*_INST macro)
 * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
 *
 * Returns true if the clockdomain referred to by (@inst, @cdoffs)
 * is in hardware-supervised idle mode, or 0 otherwise.
 */

static bool am33xx_cm_is_clkdm_in_hwsup(u16 inst, u16 cdoffs)
{
 u32 v;

 v = am33xx_cm_read_reg(inst, cdoffs);
 v &= AM33XX_CLKTRCTRL_MASK;
 v >>= AM33XX_CLKTRCTRL_SHIFT;

 return (v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ? true : false;
}

/**
 * am33xx_cm_clkdm_enable_hwsup - put a clockdomain in hwsup-idle mode
 * @inst: CM instance register offset (*_INST macro)
 * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
 *
 * Put a clockdomain referred to by (@inst, @cdoffs) into
 * hardware-supervised idle mode.  No return value.
 */

static void am33xx_cm_clkdm_enable_hwsup(u16 inst, u16 cdoffs)
{
 _clktrctrl_write(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, inst, cdoffs);
}

/**
 * am33xx_cm_clkdm_disable_hwsup - put a clockdomain in swsup-idle mode
 * @inst: CM instance register offset (*_INST macro)
 * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
 *
 * Put a clockdomain referred to by (@inst, @cdoffs) into
 * software-supervised idle mode, i.e., controlled manually by the
 * Linux OMAP clockdomain code.  No return value.
 */

static void am33xx_cm_clkdm_disable_hwsup(u16 inst, u16 cdoffs)
{
 _clktrctrl_write(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, inst, cdoffs);
}

/**
 * am33xx_cm_clkdm_force_sleep - try to put a clockdomain into idle
 * @inst: CM instance register offset (*_INST macro)
 * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
 *
 * Put a clockdomain referred to by (@inst, @cdoffs) into idle
 * No return value.
 */

static void am33xx_cm_clkdm_force_sleep(u16 inst, u16 cdoffs)
{
 _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_SLEEP, inst, cdoffs);
}

/**
 * am33xx_cm_clkdm_force_wakeup - try to take a clockdomain out of idle
 * @inst: CM instance register offset (*_INST macro)
 * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
 *
 * Take a clockdomain referred to by (@inst, @cdoffs) out of idle,
 * waking it up.  No return value.
 */

static void am33xx_cm_clkdm_force_wakeup(u16 inst, u16 cdoffs)
{
 _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, inst, cdoffs);
}

/*
 *
 */


/**
 * am33xx_cm_wait_module_ready - wait for a module to be in 'func' state
 * @part: PRCM partition, ignored for AM33xx
 * @inst: CM instance register offset (*_INST macro)
 * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
 * @bit_shift: bit shift for the register, ignored for AM33xx
 *
 * Wait for the module IDLEST to be functional. If the idle state is in any
 * the non functional state (trans, idle or disabled), module and thus the
 * sysconfig cannot be accessed and will probably lead to an "imprecise
 * external abort"
 */

static int am33xx_cm_wait_module_ready(u8 part, s16 inst, u16 clkctrl_offs,
           u8 bit_shift)
{
 int i = 0;

 omap_test_timeout(_is_module_ready(inst, clkctrl_offs),
     MAX_MODULE_READY_TIME, i);

 return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
}

/**
 * am33xx_cm_wait_module_idle - wait for a module to be in 'disabled'
 * state
 * @part: CM partition, ignored for AM33xx
 * @inst: CM instance register offset (*_INST macro)
 * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
 * @bit_shift: bit shift for the register, ignored for AM33xx
 *
 * Wait for the module IDLEST to be disabled. Some PRCM transition,
 * like reset assertion or parent clock de-activation must wait the
 * module to be fully disabled.
 */

static int am33xx_cm_wait_module_idle(u8 part, s16 inst, u16 clkctrl_offs,
          u8 bit_shift)
{
 int i = 0;

 omap_test_timeout((_clkctrl_idlest(inst, clkctrl_offs) ==
    CLKCTRL_IDLEST_DISABLED),
    MAX_MODULE_READY_TIME, i);

 return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
}

/**
 * am33xx_cm_module_enable - Enable the modulemode inside CLKCTRL
 * @mode: Module mode (SW or HW)
 * @part: CM partition, ignored for AM33xx
 * @inst: CM instance register offset (*_INST macro)
 * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
 *
 * No return value.
 */

static void am33xx_cm_module_enable(u8 mode, u8 part, u16 inst,
        u16 clkctrl_offs)
{
 u32 v;

 v = am33xx_cm_read_reg(inst, clkctrl_offs);
 v &= ~AM33XX_MODULEMODE_MASK;
 v |= mode << AM33XX_MODULEMODE_SHIFT;
 am33xx_cm_write_reg(v, inst, clkctrl_offs);
}

/**
 * am33xx_cm_module_disable - Disable the module inside CLKCTRL
 * @part: CM partition, ignored for AM33xx
 * @inst: CM instance register offset (*_INST macro)
 * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
 *
 * No return value.
 */

static void am33xx_cm_module_disable(u8 part, u16 inst, u16 clkctrl_offs)
{
 u32 v;

 v = am33xx_cm_read_reg(inst, clkctrl_offs);
 v &= ~AM33XX_MODULEMODE_MASK;
 am33xx_cm_write_reg(v, inst, clkctrl_offs);
}

/*
 * Clockdomain low-level functions
 */


static int am33xx_clkdm_sleep(struct clockdomain *clkdm)
{
 am33xx_cm_clkdm_force_sleep(clkdm->cm_inst, clkdm->clkdm_offs);
 return 0;
}

static int am33xx_clkdm_wakeup(struct clockdomain *clkdm)
{
 am33xx_cm_clkdm_force_wakeup(clkdm->cm_inst, clkdm->clkdm_offs);
 return 0;
}

static void am33xx_clkdm_allow_idle(struct clockdomain *clkdm)
{
 am33xx_cm_clkdm_enable_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
}

static void am33xx_clkdm_deny_idle(struct clockdomain *clkdm)
{
 am33xx_cm_clkdm_disable_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
}

static int am33xx_clkdm_clk_enable(struct clockdomain *clkdm)
{
 if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
  return am33xx_clkdm_wakeup(clkdm);

 return 0;
}

static int am33xx_clkdm_clk_disable(struct clockdomain *clkdm)
{
 bool hwsup = false;

#if IS_ENABLED(CONFIG_SUSPEND)
 /*
 * In case of standby, Don't put the l4ls clk domain to sleep.
 * Since CM3 PM FW doesn't wake-up/enable the l4ls clk domain
 * upon wake-up, CM3 PM FW fails to wake-up th MPU.
 */

 if (pm_suspend_target_state == PM_SUSPEND_STANDBY &&
     (clkdm->flags & CLKDM_STANDBY_FORCE_WAKEUP))
  return 0;
#endif
 hwsup = am33xx_cm_is_clkdm_in_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
 if (!hwsup && (clkdm->flags & CLKDM_CAN_FORCE_SLEEP))
  am33xx_clkdm_sleep(clkdm);

 return 0;
}

static u32 am33xx_cm_xlate_clkctrl(u8 part, u16 inst, u16 offset)
{
 return cm_base.pa + inst + offset;
}

/**
 * am33xx_clkdm_save_context - Save the clockdomain transition context
 * @clkdm: The clockdomain pointer whose context needs to be saved
 *
 * Save the clockdomain transition context.
 */

static int am33xx_clkdm_save_context(struct clockdomain *clkdm)
{
 clkdm->context = am33xx_cm_read_reg_bits(clkdm->cm_inst,
       clkdm->clkdm_offs,
       AM33XX_CLKTRCTRL_MASK);

 return 0;
}

/**
 * am33xx_clkdm_restore_context - Restore the clockdomain transition context
 * @clkdm: The clockdomain pointer whose context needs to be restored
 *
 * Restore the clockdomain transition context.
 */

static int am33xx_clkdm_restore_context(struct clockdomain *clkdm)
{
 switch (clkdm->context) {
 case OMAP34XX_CLKSTCTRL_DISABLE_AUTO:
  am33xx_clkdm_deny_idle(clkdm);
  break;
 case OMAP34XX_CLKSTCTRL_FORCE_SLEEP:
  am33xx_clkdm_sleep(clkdm);
  break;
 case OMAP34XX_CLKSTCTRL_FORCE_WAKEUP:
  am33xx_clkdm_wakeup(clkdm);
  break;
 case OMAP34XX_CLKSTCTRL_ENABLE_AUTO:
  am33xx_clkdm_allow_idle(clkdm);
  break;
 }
 return 0;
}

struct clkdm_ops am33xx_clkdm_operations = {
 .clkdm_sleep  = am33xx_clkdm_sleep,
 .clkdm_wakeup  = am33xx_clkdm_wakeup,
 .clkdm_allow_idle = am33xx_clkdm_allow_idle,
 .clkdm_deny_idle = am33xx_clkdm_deny_idle,
 .clkdm_clk_enable = am33xx_clkdm_clk_enable,
 .clkdm_clk_disable = am33xx_clkdm_clk_disable,
 .clkdm_save_context = am33xx_clkdm_save_context,
 .clkdm_restore_context = am33xx_clkdm_restore_context,
};

static const struct cm_ll_data am33xx_cm_ll_data = {
 .wait_module_ready = &am33xx_cm_wait_module_ready,
 .wait_module_idle = &am33xx_cm_wait_module_idle,
 .module_enable  = &am33xx_cm_module_enable,
 .module_disable  = &am33xx_cm_module_disable,
 .xlate_clkctrl  = &am33xx_cm_xlate_clkctrl,
};

int __init am33xx_cm_init(const struct omap_prcm_init_data *data)
{
 return cm_register(&am33xx_cm_ll_data);
}

static void __exit am33xx_cm_exit(void)
{
 cm_unregister(&am33xx_cm_ll_data);
}
__exitcall(am33xx_cm_exit);

Messung V0.5
C=95 H=100 G=97

¤ Dauer der Verarbeitung: 0.12 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge