// SPDX-License-Identifier: GPL-2.0-only
/*
* OMAP3 Clock init
*
* Copyright ( C ) 2013 Texas Instruments , Inc
* Tero Kristo ( t - kristo @ ti . com )
*/
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clk/ti.h>
#include "clock.h"
#define OMAP3430ES2_ST_DSS_IDLE_SHIFT 1
#define OMAP3430ES2_ST_HSOTGUSB_IDLE_SHIFT 5
#define OMAP3430ES2_ST_SSI_IDLE_SHIFT 8
#define OMAP34XX_CM_IDLEST_VAL 1
/*
* In AM35xx IPSS , the { ICK , FCK } enable bits for modules are exported
* in the same register at a bit offset of 0 x8 . The EN_ACK for ICK is
* at an offset of 4 from ICK enable bit .
*/
#define AM35XX_IPSS_ICK_MASK 0 xF
#define AM35XX_IPSS_ICK_EN_ACK_OFFSET 0 x4
#define AM35XX_IPSS_ICK_FCK_OFFSET 0 x8
#define AM35XX_IPSS_CLK_IDLEST_VAL 0
#define AM35XX_ST_IPSS_SHIFT 5
/**
* omap3430es2_clk_ssi_find_idlest - return CM_IDLEST info for SSI
* @ clk : struct clk * being enabled
* @ idlest_reg : void _ _ iomem * * to store CM_IDLEST reg address into
* @ idlest_bit : pointer to a u8 to store the CM_IDLEST bit shift into
* @ idlest_val : pointer to a u8 to store the CM_IDLEST indicator
*
* The OMAP3430ES2 SSI target CM_IDLEST bit is at a different shift
* from the CM_ { I , F } CLKEN bit . Pass back the correct info via
* @ idlest_reg and @ idlest_bit . No return value .
*/
static void omap3430es2_clk_ssi_find_idlest(struct clk_hw_omap *clk,
struct clk_omap_reg *idlest_reg,
u8 *idlest_bit,
u8 *idlest_val)
{
memcpy(idlest_reg, &clk->enable_reg, sizeof (*idlest_reg));
idlest_reg->offset &= ~0 xf0;
idlest_reg->offset |= 0 x20;
*idlest_bit = OMAP3430ES2_ST_SSI_IDLE_SHIFT;
*idlest_val = OMAP34XX_CM_IDLEST_VAL;
}
const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_ssi_wait = {
.allow_idle = omap2_clkt_iclk_allow_idle,
.deny_idle = omap2_clkt_iclk_deny_idle,
.find_idlest = omap3430es2_clk_ssi_find_idlest,
.find_companion = omap2_clk_dflt_find_companion,
};
/**
* omap3430es2_clk_dss_usbhost_find_idlest - CM_IDLEST info for DSS , USBHOST
* @ clk : struct clk * being enabled
* @ idlest_reg : void _ _ iomem * * to store CM_IDLEST reg address into
* @ idlest_bit : pointer to a u8 to store the CM_IDLEST bit shift into
* @ idlest_val : pointer to a u8 to store the CM_IDLEST indicator
*
* Some OMAP modules on OMAP3 ES2 + chips have both initiator and
* target IDLEST bits . For our purposes , we are concerned with the
* target IDLEST bits , which exist at a different bit position than
* the * CLKEN bit position for these modules ( DSS and USBHOST ) ( The
* default find_idlest code assumes that they are at the same
* position . ) No return value .
*/
static void
omap3430es2_clk_dss_usbhost_find_idlest(struct clk_hw_omap *clk,
struct clk_omap_reg *idlest_reg,
u8 *idlest_bit, u8 *idlest_val)
{
memcpy(idlest_reg, &clk->enable_reg, sizeof (*idlest_reg));
idlest_reg->offset &= ~0 xf0;
idlest_reg->offset |= 0 x20;
/* USBHOST_IDLE has same shift */
*idlest_bit = OMAP3430ES2_ST_DSS_IDLE_SHIFT;
*idlest_val = OMAP34XX_CM_IDLEST_VAL;
}
const struct clk_hw_omap_ops clkhwops_omap3430es2_dss_usbhost_wait = {
.find_idlest = omap3430es2_clk_dss_usbhost_find_idlest,
.find_companion = omap2_clk_dflt_find_companion,
};
const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_dss_usbhost_wait = {
.allow_idle = omap2_clkt_iclk_allow_idle,
.deny_idle = omap2_clkt_iclk_deny_idle,
.find_idlest = omap3430es2_clk_dss_usbhost_find_idlest,
.find_companion = omap2_clk_dflt_find_companion,
};
/**
* omap3430es2_clk_hsotgusb_find_idlest - return CM_IDLEST info for HSOTGUSB
* @ clk : struct clk * being enabled
* @ idlest_reg : void _ _ iomem * * to store CM_IDLEST reg address into
* @ idlest_bit : pointer to a u8 to store the CM_IDLEST bit shift into
* @ idlest_val : pointer to a u8 to store the CM_IDLEST indicator
*
* The OMAP3430ES2 HSOTGUSB target CM_IDLEST bit is at a different
* shift from the CM_ { I , F } CLKEN bit . Pass back the correct info via
* @ idlest_reg and @ idlest_bit . No return value .
*/
static void
omap3430es2_clk_hsotgusb_find_idlest(struct clk_hw_omap *clk,
struct clk_omap_reg *idlest_reg,
u8 *idlest_bit,
u8 *idlest_val)
{
memcpy(idlest_reg, &clk->enable_reg, sizeof (*idlest_reg));
idlest_reg->offset &= ~0 xf0;
idlest_reg->offset |= 0 x20;
*idlest_bit = OMAP3430ES2_ST_HSOTGUSB_IDLE_SHIFT;
*idlest_val = OMAP34XX_CM_IDLEST_VAL;
}
const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_hsotgusb_wait = {
.allow_idle = omap2_clkt_iclk_allow_idle,
.deny_idle = omap2_clkt_iclk_deny_idle,
.find_idlest = omap3430es2_clk_hsotgusb_find_idlest,
.find_companion = omap2_clk_dflt_find_companion,
};
/**
* am35xx_clk_find_idlest - return clock ACK info for AM35XX IPSS
* @ clk : struct clk * being enabled
* @ idlest_reg : void _ _ iomem * * to store CM_IDLEST reg address into
* @ idlest_bit : pointer to a u8 to store the CM_IDLEST bit shift into
* @ idlest_val : pointer to a u8 to store the CM_IDLEST indicator
*
* The interface clocks on AM35xx IPSS reflects the clock idle status
* in the enable register itsel at a bit offset of 4 from the enable
* bit . A value of 1 indicates that clock is enabled .
*/
static void am35xx_clk_find_idlest(struct clk_hw_omap *clk,
struct clk_omap_reg *idlest_reg,
u8 *idlest_bit,
u8 *idlest_val)
{
memcpy(idlest_reg, &clk->enable_reg, sizeof (*idlest_reg));
*idlest_bit = clk->enable_bit + AM35XX_IPSS_ICK_EN_ACK_OFFSET;
*idlest_val = AM35XX_IPSS_CLK_IDLEST_VAL;
}
/**
* am35xx_clk_find_companion - find companion clock to @ clk
* @ clk : struct clk * to find the companion clock of
* @ other_reg : void _ _ iomem * * to return the companion clock CM_ * CLKEN va in
* @ other_bit : u8 * * to return the companion clock bit shift in
*
* Some clocks don ' t have companion clocks . For example , modules with
* only an interface clock ( such as HECC ) don ' t have a companion
* clock . Right now , this code relies on the hardware exporting a bit
* in the correct companion register that indicates that the
* nonexistent ' companion clock ' is active . Future patches will
* associate this type of code with per - module data structures to
* avoid this issue , and remove the casts . No return value .
*/
static void am35xx_clk_find_companion(struct clk_hw_omap *clk,
struct clk_omap_reg *other_reg,
u8 *other_bit)
{
memcpy(other_reg, &clk->enable_reg, sizeof (*other_reg));
if (clk->enable_bit & AM35XX_IPSS_ICK_MASK)
*other_bit = clk->enable_bit + AM35XX_IPSS_ICK_FCK_OFFSET;
else
*other_bit = clk->enable_bit - AM35XX_IPSS_ICK_FCK_OFFSET;
}
const struct clk_hw_omap_ops clkhwops_am35xx_ipss_module_wait = {
.find_idlest = am35xx_clk_find_idlest,
.find_companion = am35xx_clk_find_companion,
};
/**
* am35xx_clk_ipss_find_idlest - return CM_IDLEST info for IPSS
* @ clk : struct clk * being enabled
* @ idlest_reg : void _ _ iomem * * to store CM_IDLEST reg address into
* @ idlest_bit : pointer to a u8 to store the CM_IDLEST bit shift into
* @ idlest_val : pointer to a u8 to store the CM_IDLEST indicator
*
* The IPSS target CM_IDLEST bit is at a different shift from the
* CM_ { I , F } CLKEN bit . Pass back the correct info via @ idlest_reg
* and @ idlest_bit . No return value .
*/
static void am35xx_clk_ipss_find_idlest(struct clk_hw_omap *clk,
struct clk_omap_reg *idlest_reg,
u8 *idlest_bit,
u8 *idlest_val)
{
memcpy(idlest_reg, &clk->enable_reg, sizeof (*idlest_reg));
idlest_reg->offset &= ~0 xf0;
idlest_reg->offset |= 0 x20;
*idlest_bit = AM35XX_ST_IPSS_SHIFT;
*idlest_val = OMAP34XX_CM_IDLEST_VAL;
}
const struct clk_hw_omap_ops clkhwops_am35xx_ipss_wait = {
.allow_idle = omap2_clkt_iclk_allow_idle,
.deny_idle = omap2_clkt_iclk_deny_idle,
.find_idlest = am35xx_clk_ipss_find_idlest,
.find_companion = omap2_clk_dflt_find_companion,
};
static struct ti_dt_clk omap3xxx_clks[] = {
DT_CLK(NULL, "timer_32k_ck" , "omap_32k_fck" ),
DT_CLK(NULL, "timer_sys_ck" , "sys_ck" ),
{ .node_name = NULL },
};
static struct ti_dt_clk omap36xx_omap3430es2plus_clks[] = {
DT_CLK(NULL, "ssi_ssr_fck" , "ssi_ssr_fck_3430es2" ),
DT_CLK(NULL, "ssi_sst_fck" , "ssi_sst_fck_3430es2" ),
DT_CLK(NULL, "hsotgusb_ick" , "hsotgusb_ick_3430es2" ),
DT_CLK(NULL, "ssi_ick" , "ssi_ick_3430es2" ),
{ .node_name = NULL },
};
static struct ti_dt_clk omap3430es1_clks[] = {
DT_CLK(NULL, "ssi_ssr_fck" , "ssi_ssr_fck_3430es1" ),
DT_CLK(NULL, "ssi_sst_fck" , "ssi_sst_fck_3430es1" ),
DT_CLK(NULL, "hsotgusb_ick" , "hsotgusb_ick_3430es1" ),
DT_CLK(NULL, "ssi_ick" , "ssi_ick_3430es1" ),
DT_CLK(NULL, "dss1_alwon_fck" , "dss1_alwon_fck_3430es1" ),
DT_CLK(NULL, "dss_ick" , "dss_ick_3430es1" ),
{ .node_name = NULL },
};
static struct ti_dt_clk omap36xx_am35xx_omap3430es2plus_clks[] = {
DT_CLK(NULL, "dss1_alwon_fck" , "dss1_alwon_fck_3430es2" ),
DT_CLK(NULL, "dss_ick" , "dss_ick_3430es2" ),
{ .node_name = NULL },
};
static struct ti_dt_clk am35xx_clks[] = {
DT_CLK(NULL, "hsotgusb_ick" , "hsotgusb_ick_am35xx" ),
DT_CLK(NULL, "hsotgusb_fck" , "hsotgusb_fck_am35xx" ),
DT_CLK(NULL, "uart4_ick" , "uart4_ick_am35xx" ),
DT_CLK(NULL, "uart4_fck" , "uart4_fck_am35xx" ),
{ .node_name = NULL },
};
static const char *enable_init_clks[] = {
"sdrc_ick" ,
"gpmc_fck" ,
"omapctrl_ick" ,
};
enum {
OMAP3_SOC_AM35XX,
OMAP3_SOC_OMAP3430_ES1,
OMAP3_SOC_OMAP3430_ES2_PLUS,
OMAP3_SOC_OMAP3630,
};
/**
* omap3_clk_lock_dpll5 - locks DPLL5
*
* Locks DPLL5 to a pre - defined frequency . This is required for proper
* operation of USB .
*/
void __init omap3_clk_lock_dpll5(void )
{
struct clk *dpll5_clk;
struct clk *dpll5_m2_clk;
/*
* Errata sprz319f advisory 2 . 1 documents a USB host clock drift issue
* that can be worked around using specially crafted dpll5 settings
* with a dpll5_m2 divider set to 8 . Set the dpll5 rate to 8 x the USB
* host clock rate , its . set_rate handler ( ) will detect that frequency
* and use the errata settings .
*/
dpll5_clk = clk_get(NULL, "dpll5_ck" );
clk_set_rate(dpll5_clk, OMAP3_DPLL5_FREQ_FOR_USBHOST * 8 );
clk_prepare_enable(dpll5_clk);
/* Program dpll5_m2_clk divider */
dpll5_m2_clk = clk_get(NULL, "dpll5_m2_ck" );
clk_prepare_enable(dpll5_m2_clk);
clk_set_rate(dpll5_m2_clk, OMAP3_DPLL5_FREQ_FOR_USBHOST);
clk_disable_unprepare(dpll5_m2_clk);
clk_disable_unprepare(dpll5_clk);
}
static int __init omap3xxx_dt_clk_init(int soc_type)
{
if (soc_type == OMAP3_SOC_AM35XX || soc_type == OMAP3_SOC_OMAP3630 ||
soc_type == OMAP3_SOC_OMAP3430_ES1 ||
soc_type == OMAP3_SOC_OMAP3430_ES2_PLUS)
ti_dt_clocks_register(omap3xxx_clks);
if (soc_type == OMAP3_SOC_AM35XX)
ti_dt_clocks_register(am35xx_clks);
if (soc_type == OMAP3_SOC_OMAP3630 || soc_type == OMAP3_SOC_AM35XX ||
soc_type == OMAP3_SOC_OMAP3430_ES2_PLUS)
ti_dt_clocks_register(omap36xx_am35xx_omap3430es2plus_clks);
if (soc_type == OMAP3_SOC_OMAP3430_ES1)
ti_dt_clocks_register(omap3430es1_clks);
if (soc_type == OMAP3_SOC_OMAP3430_ES2_PLUS ||
soc_type == OMAP3_SOC_OMAP3630)
ti_dt_clocks_register(omap36xx_omap3430es2plus_clks);
omap2_clk_disable_autoidle_all();
ti_clk_add_aliases();
omap2_clk_enable_init_clocks(enable_init_clks,
ARRAY_SIZE(enable_init_clks));
pr_info("Clocking rate (Crystal/Core/MPU): %ld.%01ld/%ld/%ld MHz\n" ,
(clk_get_rate(clk_get_sys(NULL, "osc_sys_ck" )) / 1000000 ),
(clk_get_rate(clk_get_sys(NULL, "osc_sys_ck" )) / 100000 ) % 10 ,
(clk_get_rate(clk_get_sys(NULL, "core_ck" )) / 1000000 ),
(clk_get_rate(clk_get_sys(NULL, "arm_fck" )) / 1000000 ));
if (soc_type != OMAP3_SOC_OMAP3430_ES1)
omap3_clk_lock_dpll5();
return 0 ;
}
int __init omap3430_dt_clk_init(void )
{
return omap3xxx_dt_clk_init(OMAP3_SOC_OMAP3430_ES2_PLUS);
}
int __init omap3630_dt_clk_init(void )
{
return omap3xxx_dt_clk_init(OMAP3_SOC_OMAP3630);
}
int __init am35xx_dt_clk_init(void )
{
return omap3xxx_dt_clk_init(OMAP3_SOC_AM35XX);
}
Messung V0.5 in Prozent C=97 H=99 G=97
¤ Dauer der Verarbeitung: 0.14 Sekunden
(vorverarbeitet am 2026-09-28)
¤
*© Formatika GbR, Deutschland