Commit 4d341056 authored by Stephen Boyd's avatar Stephen Boyd

Merge branch 'for-4.2/ti-clk-move' of https://github.com/t-kristo/linux-pm into clk-next

From Tero Kristo:
  "This pull request contains the TI clock driver set to move the
   clock implementations under clock driver. Some small portions of
   the clock driver code still remain under mach-omap2 after this,
   it should be decided whether this code is now obsolete and should
   be deleted or should someone try to fix it."

Slight merge conflicts with determine_rate prototype changes.
parents e306479a 989feafb
...@@ -12,8 +12,7 @@ obj-y := id.o io.o control.o mux.o devices.o fb.o serial.o timer.o pm.o \ ...@@ -12,8 +12,7 @@ obj-y := id.o io.o control.o mux.o devices.o fb.o serial.o timer.o pm.o \
hwmod-common = omap_hwmod.o omap_hwmod_reset.o \ hwmod-common = omap_hwmod.o omap_hwmod_reset.o \
omap_hwmod_common_data.o omap_hwmod_common_data.o
clock-common = clock.o clock_common_data.o \ clock-common = clock.o
clkt_dpll.o clkt_clksel.o
secure-common = omap-smc.o omap-secure.o secure-common = omap-smc.o omap-secure.o
obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(hwmod-common) obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(hwmod-common)
...@@ -182,24 +181,17 @@ obj-$(CONFIG_SOC_DRA7XX) += $(clockdomain-common) ...@@ -182,24 +181,17 @@ obj-$(CONFIG_SOC_DRA7XX) += $(clockdomain-common)
obj-$(CONFIG_SOC_DRA7XX) += clockdomains7xx_data.o obj-$(CONFIG_SOC_DRA7XX) += clockdomains7xx_data.o
# Clock framework # Clock framework
obj-$(CONFIG_ARCH_OMAP2) += $(clock-common) clock2xxx.o obj-$(CONFIG_ARCH_OMAP2) += $(clock-common)
obj-$(CONFIG_ARCH_OMAP2) += clkt2xxx_dpllcore.o obj-$(CONFIG_ARCH_OMAP2) += clkt2xxx_dpllcore.o
obj-$(CONFIG_ARCH_OMAP2) += clkt2xxx_virt_prcm_set.o obj-$(CONFIG_ARCH_OMAP2) += clkt2xxx_virt_prcm_set.o
obj-$(CONFIG_ARCH_OMAP2) += clkt2xxx_dpll.o clkt_iclk.o obj-$(CONFIG_ARCH_OMAP2) += clkt2xxx_dpll.o
obj-$(CONFIG_SOC_OMAP2430) += clock2430.o obj-$(CONFIG_ARCH_OMAP3) += $(clock-common)
obj-$(CONFIG_ARCH_OMAP3) += $(clock-common) clock3xxx.o obj-$(CONFIG_ARCH_OMAP3) += clkt34xx_dpll3m2.o
obj-$(CONFIG_ARCH_OMAP3) += clock34xx.o clkt34xx_dpll3m2.o
obj-$(CONFIG_ARCH_OMAP3) += clock3517.o clock36xx.o
obj-$(CONFIG_ARCH_OMAP3) += dpll3xxx.o
obj-$(CONFIG_ARCH_OMAP3) += clkt_iclk.o
obj-$(CONFIG_ARCH_OMAP4) += $(clock-common) obj-$(CONFIG_ARCH_OMAP4) += $(clock-common)
obj-$(CONFIG_ARCH_OMAP4) += dpll3xxx.o dpll44xx.o obj-$(CONFIG_SOC_AM33XX) += $(clock-common)
obj-$(CONFIG_SOC_AM33XX) += $(clock-common) dpll3xxx.o
obj-$(CONFIG_SOC_OMAP5) += $(clock-common) obj-$(CONFIG_SOC_OMAP5) += $(clock-common)
obj-$(CONFIG_SOC_OMAP5) += dpll3xxx.o dpll44xx.o
obj-$(CONFIG_SOC_DRA7XX) += $(clock-common) obj-$(CONFIG_SOC_DRA7XX) += $(clock-common)
obj-$(CONFIG_SOC_DRA7XX) += dpll3xxx.o dpll44xx.o obj-$(CONFIG_SOC_AM43XX) += $(clock-common)
obj-$(CONFIG_SOC_AM43XX) += $(clock-common) dpll3xxx.o
# OMAP2 clock rate set data (old "OPP" data) # OMAP2 clock rate set data (old "OPP" data)
obj-$(CONFIG_SOC_OMAP2420) += opp2420_data.o obj-$(CONFIG_SOC_OMAP2420) += opp2420_data.o
......
...@@ -23,12 +23,13 @@ ...@@ -23,12 +23,13 @@
#include "clock.h" #include "clock.h"
#include "clock3xxx.h" #include "clock3xxx.h"
#include "clock34xx.h"
#include "sdrc.h" #include "sdrc.h"
#include "sram.h" #include "sram.h"
#define CYCLES_PER_MHZ 1000000 #define CYCLES_PER_MHZ 1000000
struct clk *sdrc_ick_p, *arm_fck_p;
/* /*
* CORE DPLL (DPLL3) M2 divider rate programming functions * CORE DPLL (DPLL3) M2 divider rate programming functions
* *
...@@ -60,7 +61,9 @@ int omap3_core_dpll_m2_set_rate(struct clk_hw *hw, unsigned long rate, ...@@ -60,7 +61,9 @@ int omap3_core_dpll_m2_set_rate(struct clk_hw *hw, unsigned long rate,
if (!clk || !rate) if (!clk || !rate)
return -EINVAL; return -EINVAL;
validrate = omap2_clksel_round_rate_div(clk, rate, &new_div); new_div = DIV_ROUND_UP(parent_rate, rate);
validrate = parent_rate / new_div;
if (validrate != rate) if (validrate != rate)
return -EINVAL; return -EINVAL;
......
This diff is collapsed.
This diff is collapsed.
...@@ -23,90 +23,6 @@ ...@@ -23,90 +23,6 @@
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/clk/ti.h> #include <linux/clk/ti.h>
struct omap_clk {
u16 cpu;
struct clk_lookup lk;
};
#define CLK(dev, con, ck) \
{ \
.lk = { \
.dev_id = dev, \
.con_id = con, \
.clk = ck, \
}, \
}
struct clockdomain;
#define DEFINE_STRUCT_CLK(_name, _parent_array_name, _clkops_name) \
static struct clk_core _name##_core = { \
.name = #_name, \
.hw = &_name##_hw.hw, \
.parent_names = _parent_array_name, \
.num_parents = ARRAY_SIZE(_parent_array_name), \
.ops = &_clkops_name, \
}; \
static struct clk _name = { \
.core = &_name##_core, \
};
#define DEFINE_STRUCT_CLK_FLAGS(_name, _parent_array_name, \
_clkops_name, _flags) \
static struct clk_core _name##_core = { \
.name = #_name, \
.hw = &_name##_hw.hw, \
.parent_names = _parent_array_name, \
.num_parents = ARRAY_SIZE(_parent_array_name), \
.ops = &_clkops_name, \
.flags = _flags, \
}; \
static struct clk _name = { \
.core = &_name##_core, \
};
#define DEFINE_STRUCT_CLK_HW_OMAP(_name, _clkdm_name) \
static struct clk_hw_omap _name##_hw = { \
.hw = { \
.clk = &_name, \
}, \
.clkdm_name = _clkdm_name, \
};
#define DEFINE_CLK_OMAP_MUX(_name, _clkdm_name, _clksel, \
_clksel_reg, _clksel_mask, \
_parent_names, _ops) \
static struct clk _name; \
static struct clk_hw_omap _name##_hw = { \
.hw = { \
.clk = &_name, \
}, \
.clksel = _clksel, \
.clksel_reg = _clksel_reg, \
.clksel_mask = _clksel_mask, \
.clkdm_name = _clkdm_name, \
}; \
DEFINE_STRUCT_CLK(_name, _parent_names, _ops);
#define DEFINE_CLK_OMAP_MUX_GATE(_name, _clkdm_name, _clksel, \
_clksel_reg, _clksel_mask, \
_enable_reg, _enable_bit, \
_hwops, _parent_names, _ops) \
static struct clk _name; \
static struct clk_hw_omap _name##_hw = { \
.hw = { \
.clk = &_name, \
}, \
.ops = _hwops, \
.enable_reg = _enable_reg, \
.enable_bit = _enable_bit, \
.clksel = _clksel, \
.clksel_reg = _clksel_reg, \
.clksel_mask = _clksel_mask, \
.clkdm_name = _clkdm_name, \
}; \
DEFINE_STRUCT_CLK(_name, _parent_names, _ops);
/* struct clksel_rate.flags possibilities */ /* struct clksel_rate.flags possibilities */
#define RATE_IN_242X (1 << 0) #define RATE_IN_242X (1 << 0)
#define RATE_IN_243X (1 << 1) #define RATE_IN_243X (1 << 1)
...@@ -127,38 +43,6 @@ struct clockdomain; ...@@ -127,38 +43,6 @@ struct clockdomain;
/* RATE_IN_3430ES2PLUS_36XX includes 34xx/35xx with ES >=2, and all 36xx/37xx */ /* RATE_IN_3430ES2PLUS_36XX includes 34xx/35xx with ES >=2, and all 36xx/37xx */
#define RATE_IN_3430ES2PLUS_36XX (RATE_IN_3430ES2PLUS | RATE_IN_36XX) #define RATE_IN_3430ES2PLUS_36XX (RATE_IN_3430ES2PLUS | RATE_IN_36XX)
/**
* struct clksel_rate - register bitfield values corresponding to clk divisors
* @val: register bitfield value (shifted to bit 0)
* @div: clock divisor corresponding to @val
* @flags: (see "struct clksel_rate.flags possibilities" above)
*
* @val should match the value of a read from struct clk.clksel_reg
* AND'ed with struct clk.clksel_mask, shifted right to bit 0.
*
* @div is the divisor that should be applied to the parent clock's rate
* to produce the current clock's rate.
*/
struct clksel_rate {
u32 val;
u8 div;
u16 flags;
};
/**
* struct clksel - available parent clocks, and a pointer to their divisors
* @parent: struct clk * to a possible parent clock
* @rates: available divisors for this parent clock
*
* A struct clksel is always associated with one or more struct clks
* and one or more struct clksel_rates.
*/
struct clksel {
struct clk *parent;
const struct clksel_rate *rates;
};
/* CM_CLKSEL2_PLL.CORE_CLK_SRC bits (2XXX) */ /* CM_CLKSEL2_PLL.CORE_CLK_SRC bits (2XXX) */
#define CORE_CLK_SRC_32K 0x0 #define CORE_CLK_SRC_32K 0x0
#define CORE_CLK_SRC_DPLL 0x1 #define CORE_CLK_SRC_DPLL 0x1
...@@ -180,105 +64,18 @@ struct clksel { ...@@ -180,105 +64,18 @@ struct clksel {
#define OMAP4XXX_EN_DPLL_FRBYPASS 0x6 #define OMAP4XXX_EN_DPLL_FRBYPASS 0x6
#define OMAP4XXX_EN_DPLL_LOCKED 0x7 #define OMAP4XXX_EN_DPLL_LOCKED 0x7
u32 omap3_dpll_autoidle_read(struct clk_hw_omap *clk);
void omap3_dpll_allow_idle(struct clk_hw_omap *clk);
void omap3_dpll_deny_idle(struct clk_hw_omap *clk);
void omap4_dpllmx_allow_gatectrl(struct clk_hw_omap *clk);
void omap4_dpllmx_deny_gatectrl(struct clk_hw_omap *clk);
void __init omap2_clk_disable_clkdm_control(void);
/* clkt_clksel.c public functions */
u32 omap2_clksel_round_rate_div(struct clk_hw_omap *clk,
unsigned long target_rate,
u32 *new_div);
u8 omap2_clksel_find_parent_index(struct clk_hw *hw);
unsigned long omap2_clksel_recalc(struct clk_hw *hw, unsigned long parent_rate);
long omap2_clksel_round_rate(struct clk_hw *hw, unsigned long target_rate,
unsigned long *parent_rate);
int omap2_clksel_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate);
int omap2_clksel_set_parent(struct clk_hw *hw, u8 field_val);
/* clkt_iclk.c public functions */
extern void omap2_clkt_iclk_allow_idle(struct clk_hw_omap *clk);
extern void omap2_clkt_iclk_deny_idle(struct clk_hw_omap *clk);
unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk);
void omap2_clk_dflt_find_companion(struct clk_hw_omap *clk,
void __iomem **other_reg,
u8 *other_bit);
void omap2_clk_dflt_find_idlest(struct clk_hw_omap *clk,
void __iomem **idlest_reg,
u8 *idlest_bit, u8 *idlest_val);
int omap2_clk_enable_autoidle_all(void);
int omap2_clk_allow_idle(struct clk *clk);
int omap2_clk_deny_idle(struct clk *clk);
int omap2_clk_switch_mpurate_at_boot(const char *mpurate_ck_name);
void omap2_clk_print_new_rates(const char *hfclkin_ck_name, void omap2_clk_print_new_rates(const char *hfclkin_ck_name,
const char *core_ck_name, const char *core_ck_name,
const char *mpu_ck_name); const char *mpu_ck_name);
u32 omap2_clk_readl(struct clk_hw_omap *clk, void __iomem *reg);
void omap2_clk_writel(u32 val, struct clk_hw_omap *clk, void __iomem *reg);
extern u16 cpu_mask; extern u16 cpu_mask;
/*
* Clock features setup. Used instead of CPU type checks.
*/
struct ti_clk_features {
u32 flags;
long fint_min;
long fint_max;
long fint_band1_max;
long fint_band2_min;
u8 dpll_bypass_vals;
u8 cm_idlest_val;
};
#define TI_CLK_DPLL_HAS_FREQSEL (1 << 0)
#define TI_CLK_DPLL4_DENY_REPROGRAM (1 << 1)
extern struct ti_clk_features ti_clk_features;
extern const struct clkops clkops_omap2_dflt_wait; extern const struct clkops clkops_omap2_dflt_wait;
extern const struct clkops clkops_omap2_dflt; extern const struct clkops clkops_omap2_dflt;
extern struct clk_functions omap2_clk_functions; extern struct clk_functions omap2_clk_functions;
extern const struct clksel_rate gpt_32k_rates[]; int __init omap2_clk_setup_ll_ops(void);
extern const struct clksel_rate gpt_sys_rates[];
extern const struct clksel_rate gfx_l3_rates[];
extern const struct clksel_rate dsp_ick_rates[];
extern const struct clk_hw_omap_ops clkhwops_iclk_wait;
extern const struct clk_hw_omap_ops clkhwops_wait;
extern const struct clk_hw_omap_ops clkhwops_omap3430es2_ssi_wait;
extern const struct clk_hw_omap_ops clkhwops_omap3430es2_dss_usbhost_wait;
extern const struct clk_hw_omap_ops clkhwops_omap3430es2_hsotgusb_wait;
extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_module_wait;
extern const struct clk_hw_omap_ops clkhwops_apll54;
extern const struct clk_hw_omap_ops clkhwops_apll96;
/* clksel_rate blocks shared between OMAP44xx and AM33xx */
extern const struct clksel_rate div_1_0_rates[];
extern const struct clksel_rate div3_1to4_rates[];
extern const struct clksel_rate div_1_1_rates[];
extern const struct clksel_rate div_1_2_rates[];
extern const struct clksel_rate div_1_3_rates[];
extern const struct clksel_rate div_1_4_rates[];
extern const struct clksel_rate div31_1to31_rates[];
extern int omap2_clkops_enable_clkdm(struct clk_hw *hw);
extern void omap2_clkops_disable_clkdm(struct clk_hw *hw);
struct regmap;
int __init omap2_clk_provider_init(struct device_node *np, int index,
struct regmap *syscon, void __iomem *mem);
void __init omap2_clk_legacy_provider_init(int index, void __iomem *mem);
void __init ti_clk_init_features(void); void __init ti_clk_init_features(void);
#endif #endif
/*
* clock2430.c - OMAP2430-specific clock integration code
*
* Copyright (C) 2005-2008 Texas Instruments, Inc.
* Copyright (C) 2004-2010 Nokia Corporation
*
* Contacts:
* Richard Woodruff <r-woodruff2@ti.com>
* Paul Walmsley
*
* Based on earlier work by Tuukka Tikkanen, Tony Lindgren,
* Gordon McNutt and RidgeRun, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#undef DEBUG
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/io.h>
#include "soc.h"
#include "iomap.h"
#include "clock.h"
#include "clock2xxx.h"
#include "cm2xxx.h"
#include "cm-regbits-24xx.h"
/**
* omap2430_clk_i2chs_find_idlest - return CM_IDLEST info for 2430 I2CHS
* @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
*
* OMAP2430 I2CHS CM_IDLEST bits are in CM_IDLEST1_CORE, but the
* CM_*CLKEN bits are in CM_{I,F}CLKEN2_CORE. This custom function
* passes back the correct CM_IDLEST register address for I2CHS
* modules. No return value.
*/
static void omap2430_clk_i2chs_find_idlest(struct clk_hw_omap *clk,
void __iomem **idlest_reg,
u8 *idlest_bit,
u8 *idlest_val)
{
*idlest_reg = OMAP2430_CM_REGADDR(CORE_MOD, CM_IDLEST);
*idlest_bit = clk->enable_bit;
*idlest_val = OMAP24XX_CM_IDLEST_VAL;
}
/* 2430 I2CHS has non-standard IDLEST register */
const struct clk_hw_omap_ops clkhwops_omap2430_i2chs_wait = {
.find_idlest = omap2430_clk_i2chs_find_idlest,
.find_companion = omap2_clk_dflt_find_companion,
};
/*
* clock2xxx.c - OMAP2xxx-specific clock integration code
*
* Copyright (C) 2005-2008 Texas Instruments, Inc.
* Copyright (C) 2004-2010 Nokia Corporation
*
* Contacts:
* Richard Woodruff <r-woodruff2@ti.com>
* Paul Walmsley
*
* Based on earlier work by Tuukka Tikkanen, Tony Lindgren,
* Gordon McNutt and RidgeRun, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#undef DEBUG
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/clk.h>
#include <linux/io.h>
#include "soc.h"
#include "clock.h"
#include "clock2xxx.h"
#include "cm.h"
#include "cm-regbits-24xx.h"
struct clk_hw *dclk_hw;
/*
* Omap24xx specific clock functions
*/
/*
* Switch the MPU rate if specified on cmdline. We cannot do this
* early until cmdline is parsed. XXX This should be removed from the
* clock code and handled by the OPP layer code in the near future.
*/
static int __init omap2xxx_clk_arch_init(void)
{
int ret;
if (!cpu_is_omap24xx())
return 0;
ret = omap2_clk_switch_mpurate_at_boot("virt_prcm_set");
if (!ret)
omap2_clk_print_new_rates("sys_ck", "dpll_ck", "mpu_ck");
return ret;
}
omap_arch_initcall(omap2xxx_clk_arch_init);
/*
* OMAP3-specific clock framework functions
*
* Copyright (C) 2007-2008 Texas Instruments, Inc.
* Copyright (C) 2007-2011 Nokia Corporation
*
* Paul Walmsley
* Jouni Högander
*
* Parts of this code are based on code written by
* Richard Woodruff, Tony Lindgren, Tuukka Tikkanen, Karthik Dasu,
* Russell King
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#undef DEBUG
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/io.h>
#include "clock.h"
#include "clock34xx.h"
#include "cm3xxx.h"
#include "cm-regbits-34xx.h"
/**
* 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,
void __iomem **idlest_reg,
u8 *idlest_bit,
u8 *idlest_val)
{
u32 r;
r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20);
*idlest_reg = (__force void __iomem *)r;
*idlest_bit = OMAP3430ES2_ST_SSI_IDLE_SHIFT;
*idlest_val = OMAP34XX_CM_IDLEST_VAL;
}
const struct clk_hw_omap_ops clkhwops_omap3430es2_ssi_wait = {
.find_idlest = omap3430es2_clk_ssi_find_idlest,
.find_companion = omap2_clk_dflt_find_companion,
};
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,
void __iomem **idlest_reg,
u8 *idlest_bit,
u8 *idlest_val)
{
u32 r;
r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20);
*idlest_reg = (__force void __iomem *)r;
/* 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,
void __iomem **idlest_reg,
u8 *idlest_bit,
u8 *idlest_val)
{
u32 r;
r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20);
*idlest_reg = (__force void __iomem *)r;
*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,
};
const struct clk_hw_omap_ops clkhwops_omap3430es2_hsotgusb_wait = {
.find_idlest = omap3430es2_clk_hsotgusb_find_idlest,
.find_companion = omap2_clk_dflt_find_companion,
};
/*
* OMAP34xx clock function prototypes and macros
*
* Copyright (C) 2007-2010 Texas Instruments, Inc.
* Copyright (C) 2007-2011 Nokia Corporation
*/
#ifndef __ARCH_ARM_MACH_OMAP2_CLOCK34XX_H
#define __ARCH_ARM_MACH_OMAP2_CLOCK34XX_H
extern const struct clkops clkops_omap3430es2_ssi_wait;
extern const struct clkops clkops_omap3430es2_iclk_ssi_wait;
extern const struct clkops clkops_omap3430es2_hsotgusb_wait;
extern const struct clkops clkops_omap3430es2_iclk_hsotgusb_wait;
extern const struct clkops clkops_omap3430es2_dss_usbhost_wait;
extern const struct clkops clkops_omap3430es2_iclk_dss_usbhost_wait;
#endif
/*
* OMAP3517/3505-specific clock framework functions
*
* Copyright (C) 2010 Texas Instruments, Inc.
* Copyright (C) 2011 Nokia Corporation
*
* Ranjith Lohithakshan
* Paul Walmsley
*
* Parts of this code are based on code written by
* Richard Woodruff, Tony Lindgren, Tuukka Tikkanen, Karthik Dasu,
* Russell King
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#undef DEBUG
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/io.h>
#include "clock.h"
#include "clock3517.h"
#include "cm3xxx.h"
#include "cm-regbits-34xx.h"
/*
* In AM35xx IPSS, the {ICK,FCK} enable bits for modules are exported
* in the same register at a bit offset of 0x8. The EN_ACK for ICK is
* at an offset of 4 from ICK enable bit.
*/
#define AM35XX_IPSS_ICK_MASK 0xF
#define AM35XX_IPSS_ICK_EN_ACK_OFFSET 0x4
#define AM35XX_IPSS_ICK_FCK_OFFSET 0x8
#define AM35XX_IPSS_CLK_IDLEST_VAL 0
/**
* 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,
void __iomem **idlest_reg,
u8 *idlest_bit,
u8 *idlest_val)
{
*idlest_reg = (__force void __iomem *)(clk->enable_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,
void __iomem **other_reg,
u8 *other_bit)
{
*other_reg = (__force void __iomem *)(clk->enable_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,
void __iomem **idlest_reg,
u8 *idlest_bit,
u8 *idlest_val)
{
u32 r;
r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20);
*idlest_reg = (__force void __iomem *)r;
*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,
};
/*
* OMAP3517/3505 clock function prototypes and macros
*
* Copyright (C) 2010 Texas Instruments, Inc.
* Copyright (C) 2010 Nokia Corporation
*/
#ifndef __ARCH_ARM_MACH_OMAP2_CLOCK3517_H
#define __ARCH_ARM_MACH_OMAP2_CLOCK3517_H
extern const struct clkops clkops_am35xx_ipss_module_wait;
extern const struct clkops clkops_am35xx_ipss_wait;
#endif
/*
* OMAP36xx-specific clkops
*
* Copyright (C) 2010 Texas Instruments, Inc.
* Copyright (C) 2010 Nokia Corporation
*
* Mike Turquette
* Vijaykumar GN
* Paul Walmsley
*
* Parts of this code are based on code written by
* Richard Woodruff, Tony Lindgren, Tuukka Tikkanen, Karthik Dasu,
* Russell King
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#undef DEBUG
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include "clock.h"
#include "clock36xx.h"
#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
/**
* omap36xx_pwrdn_clk_enable_with_hsdiv_restore - enable clocks suffering
* from HSDivider PWRDN problem Implements Errata ID: i556.
* @clk: DPLL output struct clk
*
* 3630 only: dpll3_m3_ck, dpll4_m2_ck, dpll4_m3_ck, dpll4_m4_ck,
* dpll4_m5_ck & dpll4_m6_ck dividers gets loaded with reset
* valueafter their respective PWRDN bits are set. Any dummy write
* (Any other value different from the Read value) to the
* corresponding CM_CLKSEL register will refresh the dividers.
*/
int omap36xx_pwrdn_clk_enable_with_hsdiv_restore(struct clk_hw *clk)
{
struct clk_divider *parent;
struct clk_hw *parent_hw;
u32 dummy_v, orig_v;
struct clk_hw_omap *omap_clk = to_clk_hw_omap(clk);
int ret;
/* Clear PWRDN bit of HSDIVIDER */
ret = omap2_dflt_clk_enable(clk);
parent_hw = __clk_get_hw(__clk_get_parent(clk->clk));
parent = to_clk_divider(parent_hw);
/* Restore the dividers */
if (!ret) {
orig_v = omap2_clk_readl(omap_clk, parent->reg);
dummy_v = orig_v;
/* Write any other value different from the Read value */
dummy_v ^= (1 << parent->shift);
omap2_clk_writel(dummy_v, omap_clk, parent->reg);
/* Write the original divider */
omap2_clk_writel(orig_v, omap_clk, parent->reg);
}
return ret;
}
/*
* OMAP36xx clock function prototypes and macros
*
* Copyright (C) 2010 Texas Instruments, Inc.
* Copyright (C) 2010 Nokia Corporation
*/
#ifndef __ARCH_ARM_MACH_OMAP2_CLOCK36XX_H
#define __ARCH_ARM_MACH_OMAP2_CLOCK36XX_H
extern int omap36xx_pwrdn_clk_enable_with_hsdiv_restore(struct clk_hw *hw);
#endif
/*
* OMAP3-specific clock framework functions
*
* Copyright (C) 2007-2008 Texas Instruments, Inc.
* Copyright (C) 2007-2010 Nokia Corporation
*
* Paul Walmsley
* Jouni Högander
*
* Parts of this code are based on code written by
* Richard Woodruff, Tony Lindgren, Tuukka Tikkanen, Karthik Dasu
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#undef DEBUG
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/clk.h>
#include <linux/io.h>
#include "soc.h"
#include "clock.h"
#include "clock3xxx.h"
#include "prm2xxx_3xxx.h"
#include "prm-regbits-34xx.h"
#include "cm2xxx_3xxx.h"
#include "cm-regbits-34xx.h"
/*
* DPLL5_FREQ_FOR_USBHOST: USBHOST and USBTLL are the only clocks
* that are sourced by DPLL5, and both of these require this clock
* to be at 120 MHz for proper operation.
*/
#define DPLL5_FREQ_FOR_USBHOST 120000000
/* needed by omap3_core_dpll_m2_set_rate() */
struct clk *sdrc_ick_p, *arm_fck_p;
/**
* omap3_dpll4_set_rate - set rate for omap3 per-dpll
* @hw: clock to change
* @rate: target rate for clock
* @parent_rate: rate of the parent clock
*
* Check if the current SoC supports the per-dpll reprogram operation
* or not, and then do the rate change if supported. Returns -EINVAL
* if not supported, 0 for success, and potential error codes from the
* clock rate change.
*/
int omap3_dpll4_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
/*
* According to the 12-5 CDP code from TI, "Limitation 2.5"
* on 3430ES1 prevents us from changing DPLL multipliers or dividers
* on DPLL4.
*/
if (ti_clk_features.flags & TI_CLK_DPLL4_DENY_REPROGRAM) {
pr_err("clock: DPLL4 cannot change rate due to silicon 'Limitation 2.5' on 3430ES1.\n");
return -EINVAL;
}
return omap3_noncore_dpll_set_rate(hw, rate, parent_rate);
}
/**
* omap3_dpll4_set_rate_and_parent - set rate and parent for omap3 per-dpll
* @hw: clock to change
* @rate: target rate for clock
* @parent_rate: rate of the parent clock
* @index: parent index, 0 - reference clock, 1 - bypass clock
*
* Check if the current SoC support the per-dpll reprogram operation
* or not, and then do the rate + parent change if supported. Returns
* -EINVAL if not supported, 0 for success, and potential error codes
* from the clock rate change.
*/
int omap3_dpll4_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate, u8 index)
{
if (ti_clk_features.flags & TI_CLK_DPLL4_DENY_REPROGRAM) {
pr_err("clock: DPLL4 cannot change rate due to silicon 'Limitation 2.5' on 3430ES1.\n");
return -EINVAL;
}
return omap3_noncore_dpll_set_rate_and_parent(hw, rate, parent_rate,
index);
}
void __init omap3_clk_lock_dpll5(void)
{
struct clk *dpll5_clk;
struct clk *dpll5_m2_clk;
dpll5_clk = clk_get(NULL, "dpll5_ck");
clk_set_rate(dpll5_clk, DPLL5_FREQ_FOR_USBHOST);
clk_prepare_enable(dpll5_clk);
/* Program dpll5_m2_clk divider for no division */
dpll5_m2_clk = clk_get(NULL, "dpll5_m2_ck");
clk_prepare_enable(dpll5_m2_clk);
clk_set_rate(dpll5_m2_clk, DPLL5_FREQ_FOR_USBHOST);
clk_disable_unprepare(dpll5_m2_clk);
clk_disable_unprepare(dpll5_clk);
return;
}
/* Common clock code */
/*
* Switch the MPU rate if specified on cmdline. We cannot do this
* early until cmdline is parsed. XXX This should be removed from the
* clock code and handled by the OPP layer code in the near future.
*/
static int __init omap3xxx_clk_arch_init(void)
{
int ret;
if (!cpu_is_omap34xx())
return 0;
ret = omap2_clk_switch_mpurate_at_boot("dpll1_ck");
if (!ret)
omap2_clk_print_new_rates("osc_sys_ck", "core_ck", "arm_fck");
return ret;
}
omap_arch_initcall(omap3xxx_clk_arch_init);
/*
* OMAP4 clock function prototypes and macros
*
* Copyright (C) 2009 Texas Instruments, Inc.
* Copyright (C) 2010 Nokia Corporation
*/
#ifndef __ARCH_ARM_MACH_OMAP2_CLOCK44XX_H
#define __ARCH_ARM_MACH_OMAP2_CLOCK44XX_H
/*
* OMAP4430_REGM4XEN_MULT: If the CM_CLKMODE_DPLL_ABE.DPLL_REGM4XEN bit is
* set, then the DPLL's lock frequency is multiplied by 4 (OMAP4430 TRM
* vV Section 3.6.3.3.1 "DPLLs Output Clocks Parameters")
*/
#define OMAP4430_REGM4XEN_MULT 4
int omap4xxx_clk_init(void);
#endif
/*
* linux/arch/arm/mach-omap2/clock_common_data.c
*
* Copyright (C) 2005-2009 Texas Instruments, Inc.
* Copyright (C) 2004-2009 Nokia Corporation
*
* Contacts:
* Richard Woodruff <r-woodruff2@ti.com>
* Paul Walmsley
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This file contains clock data that is common to both the OMAP2xxx and
* OMAP3xxx clock definition files.
*/
#include "clock.h"
/* clksel_rate data common to 24xx/343x */
const struct clksel_rate gpt_32k_rates[] = {
{ .div = 1, .val = 0, .flags = RATE_IN_24XX | RATE_IN_3XXX },
{ .div = 0 }
};
const struct clksel_rate gpt_sys_rates[] = {
{ .div = 1, .val = 1, .flags = RATE_IN_24XX | RATE_IN_3XXX },
{ .div = 0 }
};
const struct clksel_rate gfx_l3_rates[] = {
{ .div = 1, .val = 1, .flags = RATE_IN_24XX | RATE_IN_3XXX },
{ .div = 2, .val = 2, .flags = RATE_IN_24XX | RATE_IN_3XXX },
{ .div = 3, .val = 3, .flags = RATE_IN_243X | RATE_IN_3XXX },
{ .div = 4, .val = 4, .flags = RATE_IN_243X | RATE_IN_3XXX },
{ .div = 0 }
};
const struct clksel_rate dsp_ick_rates[] = {
{ .div = 1, .val = 1, .flags = RATE_IN_24XX },
{ .div = 2, .val = 2, .flags = RATE_IN_24XX },
{ .div = 3, .val = 3, .flags = RATE_IN_243X },
{ .div = 0 },
};
/* clksel_rate blocks shared between OMAP44xx and AM33xx */
const struct clksel_rate div_1_0_rates[] = {
{ .div = 1, .val = 0, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
{ .div = 0 },
};
const struct clksel_rate div3_1to4_rates[] = {
{ .div = 1, .val = 0, .flags = RATE_IN_4430 },
{ .div = 2, .val = 1, .flags = RATE_IN_4430 },
{ .div = 4, .val = 2, .flags = RATE_IN_4430 },
{ .div = 0 },
};
const struct clksel_rate div_1_1_rates[] = {
{ .div = 1, .val = 1, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
{ .div = 0 },
};
const struct clksel_rate div_1_2_rates[] = {
{ .div = 1, .val = 2, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
{ .div = 0 },
};
const struct clksel_rate div_1_3_rates[] = {
{ .div = 1, .val = 3, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
{ .div = 0 },
};
const struct clksel_rate div_1_4_rates[] = {
{ .div = 1, .val = 4, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
{ .div = 0 },
};
const struct clksel_rate div31_1to31_rates[] = {
{ .div = 1, .val = 1, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
{ .div = 2, .val = 2, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
{ .div = 3, .val = 3, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
{ .div = 4, .val = 4, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
{ .div = 5, .val = 5, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
{ .div = 6, .val = 6, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
{ .div = 7, .val = 7, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
{ .div = 8, .val = 8, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
{ .div = 9, .val = 9, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
{ .div = 10, .val = 10, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
{ .div = 11, .val = 11, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
{ .div = 12, .val = 12, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
{ .div = 13, .val = 13, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
{ .div = 14, .val = 14, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
{ .div = 15, .val = 15, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
{ .div = 16, .val = 16, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
{ .div = 17, .val = 17, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
{ .div = 18, .val = 18, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
{ .div = 19, .val = 19, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
{ .div = 20, .val = 20, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
{ .div = 21, .val = 21, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
{ .div = 22, .val = 22, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
{ .div = 23, .val = 23, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
{ .div = 24, .val = 24, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
{ .div = 25, .val = 25, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
{ .div = 26, .val = 26, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
{ .div = 27, .val = 27, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
{ .div = 28, .val = 28, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
{ .div = 29, .val = 29, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
{ .div = 30, .val = 30, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
{ .div = 31, .val = 31, .flags = RATE_IN_4430 | RATE_IN_AM33XX },
{ .div = 0 },
};
...@@ -37,7 +37,6 @@ ...@@ -37,7 +37,6 @@
#include "clock.h" #include "clock.h"
#include "clock2xxx.h" #include "clock2xxx.h"
#include "clock3xxx.h" #include "clock3xxx.h"
#include "clock44xx.h"
#include "omap-pm.h" #include "omap-pm.h"
#include "sdrc.h" #include "sdrc.h"
#include "control.h" #include "control.h"
...@@ -723,6 +722,8 @@ int __init omap_clk_init(void) ...@@ -723,6 +722,8 @@ int __init omap_clk_init(void)
ti_clk_init_features(); ti_clk_init_features();
omap2_clk_setup_ll_ops();
if (of_have_populated_dt()) { if (of_have_populated_dt()) {
ret = omap_control_init(); ret = omap_control_init();
if (ret) if (ret)
......
obj-y += clk.o autoidle.o clockdomain.o obj-y += clk.o autoidle.o clockdomain.o
clk-common = dpll.o composite.o divider.o gate.o \ clk-common = dpll.o composite.o divider.o gate.o \
fixed-factor.o mux.o apll.o fixed-factor.o mux.o apll.o \
obj-$(CONFIG_SOC_AM33XX) += $(clk-common) clk-33xx.o clkt_dpll.o clkt_iclk.o clkt_dflt.o
obj-$(CONFIG_SOC_AM33XX) += $(clk-common) clk-33xx.o dpll3xxx.o
obj-$(CONFIG_SOC_TI81XX) += $(clk-common) fapll.o clk-816x.o obj-$(CONFIG_SOC_TI81XX) += $(clk-common) fapll.o clk-816x.o
obj-$(CONFIG_ARCH_OMAP2) += $(clk-common) interface.o clk-2xxx.o obj-$(CONFIG_ARCH_OMAP2) += $(clk-common) interface.o clk-2xxx.o
obj-$(CONFIG_ARCH_OMAP3) += $(clk-common) interface.o \ obj-$(CONFIG_ARCH_OMAP3) += $(clk-common) interface.o \
clk-3xxx.o clk-3xxx.o dpll3xxx.o
obj-$(CONFIG_ARCH_OMAP4) += $(clk-common) clk-44xx.o obj-$(CONFIG_ARCH_OMAP4) += $(clk-common) clk-44xx.o \
obj-$(CONFIG_SOC_OMAP5) += $(clk-common) clk-54xx.o dpll3xxx.o dpll44xx.o
obj-$(CONFIG_SOC_OMAP5) += $(clk-common) clk-54xx.o \
dpll3xxx.o dpll44xx.o
obj-$(CONFIG_SOC_DRA7XX) += $(clk-common) clk-7xx.o \ obj-$(CONFIG_SOC_DRA7XX) += $(clk-common) clk-7xx.o \
clk-dra7-atl.o clk-dra7-atl.o dpll3xxx.o dpll44xx.o
obj-$(CONFIG_SOC_AM43XX) += $(clk-common) clk-43xx.o obj-$(CONFIG_SOC_AM43XX) += $(clk-common) dpll3xxx.o clk-43xx.o
ifdef CONFIG_ATAGS ifdef CONFIG_ATAGS
obj-$(CONFIG_ARCH_OMAP3) += clk-3xxx-legacy.o obj-$(CONFIG_ARCH_OMAP3) += clk-3xxx-legacy.o
......
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
#include <linux/clk/ti.h> #include <linux/clk/ti.h>
#include <linux/delay.h> #include <linux/delay.h>
#include "clock.h"
#define APLL_FORCE_LOCK 0x1 #define APLL_FORCE_LOCK 0x1
#define APLL_AUTO_IDLE 0x2 #define APLL_AUTO_IDLE 0x2
#define MAX_APLL_WAIT_TRIES 1000000 #define MAX_APLL_WAIT_TRIES 1000000
......
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/clk/ti.h> #include <linux/clk/ti.h>
#include "clock.h"
struct clk_ti_autoidle { struct clk_ti_autoidle {
void __iomem *reg; void __iomem *reg;
u8 shift; u8 shift;
...@@ -33,8 +35,47 @@ struct clk_ti_autoidle { ...@@ -33,8 +35,47 @@ struct clk_ti_autoidle {
#define AUTOIDLE_LOW 0x1 #define AUTOIDLE_LOW 0x1
static LIST_HEAD(autoidle_clks); static LIST_HEAD(autoidle_clks);
static LIST_HEAD(clk_hw_omap_clocks);
static void ti_allow_autoidle(struct clk_ti_autoidle *clk) /**
* omap2_clk_deny_idle - disable autoidle on an OMAP clock
* @clk: struct clk * to disable autoidle for
*
* Disable autoidle on an OMAP clock.
*/
int omap2_clk_deny_idle(struct clk *clk)
{
struct clk_hw_omap *c;
if (__clk_get_flags(clk) & CLK_IS_BASIC)
return -EINVAL;
c = to_clk_hw_omap(__clk_get_hw(clk));
if (c->ops && c->ops->deny_idle)
c->ops->deny_idle(c);
return 0;
}
/**
* omap2_clk_allow_idle - enable autoidle on an OMAP clock
* @clk: struct clk * to enable autoidle for
*
* Enable autoidle on an OMAP clock.
*/
int omap2_clk_allow_idle(struct clk *clk)
{
struct clk_hw_omap *c;
if (__clk_get_flags(clk) & CLK_IS_BASIC)
return -EINVAL;
c = to_clk_hw_omap(__clk_get_hw(clk));
if (c->ops && c->ops->allow_idle)
c->ops->allow_idle(c);
return 0;
}
static void _allow_autoidle(struct clk_ti_autoidle *clk)
{ {
u32 val; u32 val;
...@@ -48,7 +89,7 @@ static void ti_allow_autoidle(struct clk_ti_autoidle *clk) ...@@ -48,7 +89,7 @@ static void ti_allow_autoidle(struct clk_ti_autoidle *clk)
ti_clk_ll_ops->clk_writel(val, clk->reg); ti_clk_ll_ops->clk_writel(val, clk->reg);
} }
static void ti_deny_autoidle(struct clk_ti_autoidle *clk) static void _deny_autoidle(struct clk_ti_autoidle *clk)
{ {
u32 val; u32 val;
...@@ -63,31 +104,31 @@ static void ti_deny_autoidle(struct clk_ti_autoidle *clk) ...@@ -63,31 +104,31 @@ static void ti_deny_autoidle(struct clk_ti_autoidle *clk)
} }
/** /**
* of_ti_clk_allow_autoidle_all - enable autoidle for all clocks * _clk_generic_allow_autoidle_all - enable autoidle for all clocks
* *
* Enables hardware autoidle for all registered DT clocks, which have * Enables hardware autoidle for all registered DT clocks, which have
* the feature. * the feature.
*/ */
void of_ti_clk_allow_autoidle_all(void) static void _clk_generic_allow_autoidle_all(void)
{ {
struct clk_ti_autoidle *c; struct clk_ti_autoidle *c;
list_for_each_entry(c, &autoidle_clks, node) list_for_each_entry(c, &autoidle_clks, node)
ti_allow_autoidle(c); _allow_autoidle(c);
} }
/** /**
* of_ti_clk_deny_autoidle_all - disable autoidle for all clocks * _clk_generic_deny_autoidle_all - disable autoidle for all clocks
* *
* Disables hardware autoidle for all registered DT clocks, which have * Disables hardware autoidle for all registered DT clocks, which have
* the feature. * the feature.
*/ */
void of_ti_clk_deny_autoidle_all(void) static void _clk_generic_deny_autoidle_all(void)
{ {
struct clk_ti_autoidle *c; struct clk_ti_autoidle *c;
list_for_each_entry(c, &autoidle_clks, node) list_for_each_entry(c, &autoidle_clks, node)
ti_deny_autoidle(c); _deny_autoidle(c);
} }
/** /**
...@@ -131,3 +172,67 @@ int __init of_ti_clk_autoidle_setup(struct device_node *node) ...@@ -131,3 +172,67 @@ int __init of_ti_clk_autoidle_setup(struct device_node *node)
return 0; return 0;
} }
/**
* omap2_init_clk_hw_omap_clocks - initialize an OMAP clock
* @clk: struct clk * to initialize
*
* Add an OMAP clock @clk to the internal list of OMAP clocks. Used
* temporarily for autoidle handling, until this support can be
* integrated into the common clock framework code in some way. No
* return value.
*/
void omap2_init_clk_hw_omap_clocks(struct clk *clk)
{
struct clk_hw_omap *c;
if (__clk_get_flags(clk) & CLK_IS_BASIC)
return;
c = to_clk_hw_omap(__clk_get_hw(clk));
list_add(&c->node, &clk_hw_omap_clocks);
}
/**
* omap2_clk_enable_autoidle_all - enable autoidle on all OMAP clocks that
* support it
*
* Enable clock autoidle on all OMAP clocks that have allow_idle
* function pointers associated with them. This function is intended
* to be temporary until support for this is added to the common clock
* code. Returns 0.
*/
int omap2_clk_enable_autoidle_all(void)
{
struct clk_hw_omap *c;
list_for_each_entry(c, &clk_hw_omap_clocks, node)
if (c->ops && c->ops->allow_idle)
c->ops->allow_idle(c);
_clk_generic_allow_autoidle_all();
return 0;
}
/**
* omap2_clk_disable_autoidle_all - disable autoidle on all OMAP clocks that
* support it
*
* Disable clock autoidle on all OMAP clocks that have allow_idle
* function pointers associated with them. This function is intended
* to be temporary until support for this is added to the common clock
* code. Returns 0.
*/
int omap2_clk_disable_autoidle_all(void)
{
struct clk_hw_omap *c;
list_for_each_entry(c, &clk_hw_omap_clocks, node)
if (c->ops && c->ops->deny_idle)
c->ops->deny_idle(c);
_clk_generic_deny_autoidle_all();
return 0;
}
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/clk/ti.h> #include <linux/clk/ti.h>
#include "clock.h"
static struct ti_dt_clk omap2xxx_clks[] = { static struct ti_dt_clk omap2xxx_clks[] = {
DT_CLK(NULL, "func_32k_ck", "func_32k_ck"), DT_CLK(NULL, "func_32k_ck", "func_32k_ck"),
DT_CLK(NULL, "secure_32k_ck", "secure_32k_ck"), DT_CLK(NULL, "secure_32k_ck", "secure_32k_ck"),
......
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/clk/ti.h> #include <linux/clk/ti.h>
#include "clock.h"
static struct ti_dt_clk am33xx_clks[] = { static struct ti_dt_clk am33xx_clks[] = {
DT_CLK(NULL, "clk_32768_ck", "clk_32768_ck"), DT_CLK(NULL, "clk_32768_ck", "clk_32768_ck"),
DT_CLK(NULL, "clk_rc32k_ck", "clk_rc32k_ck"), DT_CLK(NULL, "clk_rc32k_ck", "clk_rc32k_ck"),
......
...@@ -19,6 +19,226 @@ ...@@ -19,6 +19,226 @@
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/clk/ti.h> #include <linux/clk/ti.h>
#include "clock.h"
/*
* DPLL5_FREQ_FOR_USBHOST: USBHOST and USBTLL are the only clocks
* that are sourced by DPLL5, and both of these require this clock
* to be at 120 MHz for proper operation.
*/
#define DPLL5_FREQ_FOR_USBHOST 120000000
#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 0x8. The EN_ACK for ICK is
* at an offset of 4 from ICK enable bit.
*/
#define AM35XX_IPSS_ICK_MASK 0xF
#define AM35XX_IPSS_ICK_EN_ACK_OFFSET 0x4
#define AM35XX_IPSS_ICK_FCK_OFFSET 0x8
#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,
void __iomem **idlest_reg,
u8 *idlest_bit,
u8 *idlest_val)
{
u32 r;
r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20);
*idlest_reg = (__force void __iomem *)r;
*idlest_bit = OMAP3430ES2_ST_SSI_IDLE_SHIFT;
*idlest_val = OMAP34XX_CM_IDLEST_VAL;
}
const struct clk_hw_omap_ops clkhwops_omap3430es2_ssi_wait = {
.find_idlest = omap3430es2_clk_ssi_find_idlest,
.find_companion = omap2_clk_dflt_find_companion,
};
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,
void __iomem **idlest_reg,
u8 *idlest_bit,
u8 *idlest_val)
{
u32 r;
r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20);
*idlest_reg = (__force void __iomem *)r;
/* 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,
void __iomem **idlest_reg,
u8 *idlest_bit,
u8 *idlest_val)
{
u32 r;
r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20);
*idlest_reg = (__force void __iomem *)r;
*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,
};
const struct clk_hw_omap_ops clkhwops_omap3430es2_hsotgusb_wait = {
.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,
void __iomem **idlest_reg,
u8 *idlest_bit,
u8 *idlest_val)
{
*idlest_reg = (__force void __iomem *)(clk->enable_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,
void __iomem **other_reg,
u8 *other_bit)
{
*other_reg = (__force void __iomem *)(clk->enable_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,
void __iomem **idlest_reg,
u8 *idlest_bit,
u8 *idlest_val)
{
u32 r;
r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20);
*idlest_reg = (__force void __iomem *)r;
*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[] = { static struct ti_dt_clk omap3xxx_clks[] = {
DT_CLK(NULL, "apb_pclk", "dummy_apb_pclk"), DT_CLK(NULL, "apb_pclk", "dummy_apb_pclk"),
...@@ -324,6 +544,30 @@ enum { ...@@ -324,6 +544,30 @@ enum {
OMAP3_SOC_OMAP3630, 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;
dpll5_clk = clk_get(NULL, "dpll5_ck");
clk_set_rate(dpll5_clk, DPLL5_FREQ_FOR_USBHOST);
clk_prepare_enable(dpll5_clk);
/* Program dpll5_m2_clk divider for no division */
dpll5_m2_clk = clk_get(NULL, "dpll5_m2_ck");
clk_prepare_enable(dpll5_m2_clk);
clk_set_rate(dpll5_m2_clk, 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) static int __init omap3xxx_dt_clk_init(int soc_type)
{ {
if (soc_type == OMAP3_SOC_AM35XX || soc_type == OMAP3_SOC_OMAP3630 || if (soc_type == OMAP3_SOC_AM35XX || soc_type == OMAP3_SOC_OMAP3630 ||
......
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/clk/ti.h> #include <linux/clk/ti.h>
#include "clock.h"
static struct ti_dt_clk am43xx_clks[] = { static struct ti_dt_clk am43xx_clks[] = {
DT_CLK(NULL, "clk_32768_ck", "clk_32768_ck"), DT_CLK(NULL, "clk_32768_ck", "clk_32768_ck"),
DT_CLK(NULL, "clk_rc32k_ck", "clk_rc32k_ck"), DT_CLK(NULL, "clk_rc32k_ck", "clk_rc32k_ck"),
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
#include <linux/clkdev.h> #include <linux/clkdev.h>
#include <linux/clk/ti.h> #include <linux/clk/ti.h>
#include "clock.h"
/* /*
* OMAP4 ABE DPLL default frequency. In OMAP4460 TRM version V, section * OMAP4 ABE DPLL default frequency. In OMAP4460 TRM version V, section
* "3.6.3.2.3 CM1_ABE Clock Generator" states that the "DPLL_ABE_X2_CLK * "3.6.3.2.3 CM1_ABE Clock Generator" states that the "DPLL_ABE_X2_CLK
......
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/clk/ti.h> #include <linux/clk/ti.h>
#include "clock.h"
#define OMAP5_DPLL_ABE_DEFFREQ 98304000 #define OMAP5_DPLL_ABE_DEFFREQ 98304000
/* /*
......
...@@ -16,11 +16,12 @@ ...@@ -16,11 +16,12 @@
#include <linux/clkdev.h> #include <linux/clkdev.h>
#include <linux/clk/ti.h> #include <linux/clk/ti.h>
#include "clock.h"
#define DRA7_DPLL_ABE_DEFFREQ 180633600 #define DRA7_DPLL_ABE_DEFFREQ 180633600
#define DRA7_DPLL_GMAC_DEFFREQ 1000000000 #define DRA7_DPLL_GMAC_DEFFREQ 1000000000
#define DRA7_DPLL_USB_DEFFREQ 960000000 #define DRA7_DPLL_USB_DEFFREQ 960000000
static struct ti_dt_clk dra7xx_clks[] = { static struct ti_dt_clk dra7xx_clks[] = {
DT_CLK(NULL, "atl_clkin0_ck", "atl_clkin0_ck"), DT_CLK(NULL, "atl_clkin0_ck", "atl_clkin0_ck"),
DT_CLK(NULL, "atl_clkin1_ck", "atl_clkin1_ck"), DT_CLK(NULL, "atl_clkin1_ck", "atl_clkin1_ck"),
......
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/clk/ti.h> #include <linux/clk/ti.h>
#include "clock.h"
static struct ti_dt_clk dm816x_clks[] = { static struct ti_dt_clk dm816x_clks[] = {
DT_CLK(NULL, "sys_clkin", "sys_clkin_ck"), DT_CLK(NULL, "sys_clkin", "sys_clkin_ck"),
DT_CLK(NULL, "timer_sys_ck", "sys_clkin_ck"), DT_CLK(NULL, "timer_sys_ck", "sys_clkin_ck"),
......
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/regmap.h>
#include <linux/bootmem.h>
#include "clock.h" #include "clock.h"
...@@ -30,6 +32,63 @@ ...@@ -30,6 +32,63 @@
struct ti_clk_ll_ops *ti_clk_ll_ops; struct ti_clk_ll_ops *ti_clk_ll_ops;
static struct device_node *clocks_node_ptr[CLK_MAX_MEMMAPS]; static struct device_node *clocks_node_ptr[CLK_MAX_MEMMAPS];
struct ti_clk_features ti_clk_features;
struct clk_iomap {
struct regmap *regmap;
void __iomem *mem;
};
static struct clk_iomap *clk_memmaps[CLK_MAX_MEMMAPS];
static void clk_memmap_writel(u32 val, void __iomem *reg)
{
struct clk_omap_reg *r = (struct clk_omap_reg *)&reg;
struct clk_iomap *io = clk_memmaps[r->index];
if (io->regmap)
regmap_write(io->regmap, r->offset, val);
else
writel_relaxed(val, io->mem + r->offset);
}
static u32 clk_memmap_readl(void __iomem *reg)
{
u32 val;
struct clk_omap_reg *r = (struct clk_omap_reg *)&reg;
struct clk_iomap *io = clk_memmaps[r->index];
if (io->regmap)
regmap_read(io->regmap, r->offset, &val);
else
val = readl_relaxed(io->mem + r->offset);
return val;
}
/**
* ti_clk_setup_ll_ops - setup low level clock operations
* @ops: low level clock ops descriptor
*
* Sets up low level clock operations for TI clock driver. This is used
* to provide various callbacks for the clock driver towards platform
* specific code. Returns 0 on success, -EBUSY if ll_ops have been
* registered already.
*/
int ti_clk_setup_ll_ops(struct ti_clk_ll_ops *ops)
{
if (ti_clk_ll_ops) {
pr_err("Attempt to register ll_ops multiple times.\n");
return -EBUSY;
}
ti_clk_ll_ops = ops;
ops->clk_readl = clk_memmap_readl;
ops->clk_writel = clk_memmap_writel;
return 0;
}
/** /**
* ti_dt_clocks_register - register DT alias clocks during boot * ti_dt_clocks_register - register DT alias clocks during boot
* @oclks: list of clocks to register * @oclks: list of clocks to register
...@@ -138,28 +197,61 @@ void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index) ...@@ -138,28 +197,61 @@ void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index)
} }
/** /**
* ti_dt_clk_init_provider - init master clock provider * omap2_clk_provider_init - init master clock provider
* @parent: master node * @parent: master node
* @index: internal index for clk_reg_ops * @index: internal index for clk_reg_ops
* @syscon: syscon regmap pointer for accessing clock registers
* @mem: iomem pointer for the clock provider memory area, only used if
* syscon is not provided
* *
* Initializes a master clock IP block. This basically sets up the * Initializes a master clock IP block. This basically sets up the
* mapping from clocks node to the memory map index. All the clocks * mapping from clocks node to the memory map index. All the clocks
* are then initialized through the common of_clk_init call, and the * are then initialized through the common of_clk_init call, and the
* clocks will access their memory maps based on the node layout. * clocks will access their memory maps based on the node layout.
* Returns 0 in success.
*/ */
void ti_dt_clk_init_provider(struct device_node *parent, int index) int __init omap2_clk_provider_init(struct device_node *parent, int index,
struct regmap *syscon, void __iomem *mem)
{ {
struct device_node *clocks; struct device_node *clocks;
struct clk_iomap *io;
/* get clocks for this parent */ /* get clocks for this parent */
clocks = of_get_child_by_name(parent, "clocks"); clocks = of_get_child_by_name(parent, "clocks");
if (!clocks) { if (!clocks) {
pr_err("%s missing 'clocks' child node.\n", parent->name); pr_err("%s missing 'clocks' child node.\n", parent->name);
return; return -EINVAL;
} }
/* add clocks node info */ /* add clocks node info */
clocks_node_ptr[index] = clocks; clocks_node_ptr[index] = clocks;
io = kzalloc(sizeof(*io), GFP_KERNEL);
io->regmap = syscon;
io->mem = mem;
clk_memmaps[index] = io;
return 0;
}
/**
* omap2_clk_legacy_provider_init - initialize a legacy clock provider
* @index: index for the clock provider
* @mem: iomem pointer for the clock provider memory area
*
* Initializes a legacy clock provider memory mapping.
*/
void __init omap2_clk_legacy_provider_init(int index, void __iomem *mem)
{
struct clk_iomap *io;
io = memblock_virt_alloc(sizeof(*io), 0);
io->mem = mem;
clk_memmaps[index] = io;
} }
/** /**
...@@ -311,3 +403,50 @@ int __init ti_clk_register_legacy_clks(struct ti_clk_alias *clks) ...@@ -311,3 +403,50 @@ int __init ti_clk_register_legacy_clks(struct ti_clk_alias *clks)
return 0; return 0;
} }
#endif #endif
/**
* ti_clk_setup_features - setup clock features flags
* @features: features definition to use
*
* Initializes the clock driver features flags based on platform
* provided data. No return value.
*/
void __init ti_clk_setup_features(struct ti_clk_features *features)
{
memcpy(&ti_clk_features, features, sizeof(*features));
}
/**
* ti_clk_get_features - get clock driver features flags
*
* Get TI clock driver features description. Returns a pointer
* to the current feature setup.
*/
const struct ti_clk_features *ti_clk_get_features(void)
{
return &ti_clk_features;
}
/**
* omap2_clk_enable_init_clocks - prepare & enable a list of clocks
* @clk_names: ptr to an array of strings of clock names to enable
* @num_clocks: number of clock names in @clk_names
*
* Prepare and enable a list of clocks, named by @clk_names. No
* return value. XXX Deprecated; only needed until these clocks are
* properly claimed and enabled by the drivers or core code that uses
* them. XXX What code disables & calls clk_put on these clocks?
*/
void omap2_clk_enable_init_clocks(const char **clk_names, u8 num_clocks)
{
struct clk *init_clk;
int i;
for (i = 0; i < num_clocks; i++) {
init_clk = clk_get(NULL, clk_names[i]);
if (WARN(IS_ERR(init_clk), "could not find init clock %s\n",
clk_names[i]))
continue;
clk_prepare_enable(init_clk);
}
}
This diff is collapsed.
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/clk/ti.h>
#include <asm/div64.h> #include <asm/div64.h>
...@@ -80,8 +81,8 @@ static int _dpll_test_fint(struct clk_hw_omap *clk, unsigned int n) ...@@ -80,8 +81,8 @@ static int _dpll_test_fint(struct clk_hw_omap *clk, unsigned int n)
fint_min = OMAP3PLUS_DPLL_FINT_JTYPE_MIN; fint_min = OMAP3PLUS_DPLL_FINT_JTYPE_MIN;
fint_max = OMAP3PLUS_DPLL_FINT_JTYPE_MAX; fint_max = OMAP3PLUS_DPLL_FINT_JTYPE_MAX;
} else { } else {
fint_min = ti_clk_features.fint_min; fint_min = ti_clk_get_features()->fint_min;
fint_max = ti_clk_features.fint_max; fint_max = ti_clk_get_features()->fint_max;
} }
if (!fint_min || !fint_max) { if (!fint_min || !fint_max) {
...@@ -89,18 +90,18 @@ static int _dpll_test_fint(struct clk_hw_omap *clk, unsigned int n) ...@@ -89,18 +90,18 @@ static int _dpll_test_fint(struct clk_hw_omap *clk, unsigned int n)
return DPLL_FINT_INVALID; return DPLL_FINT_INVALID;
} }
if (fint < ti_clk_features.fint_min) { if (fint < ti_clk_get_features()->fint_min) {
pr_debug("rejecting n=%d due to Fint failure, lowering max_divider\n", pr_debug("rejecting n=%d due to Fint failure, lowering max_divider\n",
n); n);
dd->max_divider = n; dd->max_divider = n;
ret = DPLL_FINT_UNDERFLOW; ret = DPLL_FINT_UNDERFLOW;
} else if (fint > ti_clk_features.fint_max) { } else if (fint > ti_clk_get_features()->fint_max) {
pr_debug("rejecting n=%d due to Fint failure, boosting min_divider\n", pr_debug("rejecting n=%d due to Fint failure, boosting min_divider\n",
n); n);
dd->min_divider = n; dd->min_divider = n;
ret = DPLL_FINT_INVALID; ret = DPLL_FINT_INVALID;
} else if (fint > ti_clk_features.fint_band1_max && } else if (fint > ti_clk_get_features()->fint_band1_max &&
fint < ti_clk_features.fint_band2_min) { fint < ti_clk_get_features()->fint_band2_min) {
pr_debug("rejecting n=%d due to Fint failure\n", n); pr_debug("rejecting n=%d due to Fint failure\n", n);
ret = DPLL_FINT_INVALID; ret = DPLL_FINT_INVALID;
} }
...@@ -183,7 +184,7 @@ static int _omap2_dpll_is_in_bypass(u32 v) ...@@ -183,7 +184,7 @@ static int _omap2_dpll_is_in_bypass(u32 v)
{ {
u8 mask, val; u8 mask, val;
mask = ti_clk_features.dpll_bypass_vals; mask = ti_clk_get_features()->dpll_bypass_vals;
/* /*
* Each set bit in the mask corresponds to a bypass value equal * Each set bit in the mask corresponds to a bypass value equal
...@@ -211,7 +212,7 @@ u8 omap2_init_dpll_parent(struct clk_hw *hw) ...@@ -211,7 +212,7 @@ u8 omap2_init_dpll_parent(struct clk_hw *hw)
if (!dd) if (!dd)
return -EINVAL; return -EINVAL;
v = omap2_clk_readl(clk, dd->control_reg); v = ti_clk_ll_ops->clk_readl(dd->control_reg);
v &= dd->enable_mask; v &= dd->enable_mask;
v >>= __ffs(dd->enable_mask); v >>= __ffs(dd->enable_mask);
...@@ -247,20 +248,20 @@ unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk) ...@@ -247,20 +248,20 @@ unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk)
return 0; return 0;
/* Return bypass rate if DPLL is bypassed */ /* Return bypass rate if DPLL is bypassed */
v = omap2_clk_readl(clk, dd->control_reg); v = ti_clk_ll_ops->clk_readl(dd->control_reg);
v &= dd->enable_mask; v &= dd->enable_mask;
v >>= __ffs(dd->enable_mask); v >>= __ffs(dd->enable_mask);
if (_omap2_dpll_is_in_bypass(v)) if (_omap2_dpll_is_in_bypass(v))
return __clk_get_rate(dd->clk_bypass); return __clk_get_rate(dd->clk_bypass);
v = omap2_clk_readl(clk, dd->mult_div1_reg); v = ti_clk_ll_ops->clk_readl(dd->mult_div1_reg);
dpll_mult = v & dd->mult_mask; dpll_mult = v & dd->mult_mask;
dpll_mult >>= __ffs(dd->mult_mask); dpll_mult >>= __ffs(dd->mult_mask);
dpll_div = v & dd->div1_mask; dpll_div = v & dd->div1_mask;
dpll_div >>= __ffs(dd->div1_mask); dpll_div >>= __ffs(dd->div1_mask);
dpll_clk = (long long) __clk_get_rate(dd->clk_ref) * dpll_mult; dpll_clk = (long long)__clk_get_rate(dd->clk_ref) * dpll_mult;
do_div(dpll_clk, dpll_div + 1); do_div(dpll_clk, dpll_div + 1);
return dpll_clk; return dpll_clk;
...@@ -310,7 +311,6 @@ long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, ...@@ -310,7 +311,6 @@ long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
dd->last_rounded_rate = 0; dd->last_rounded_rate = 0;
for (n = dd->min_divider; n <= dd->max_divider; n++) { for (n = dd->min_divider; n <= dd->max_divider; n++) {
/* Is the (input clk, divider) pair valid for the DPLL? */ /* Is the (input clk, divider) pair valid for the DPLL? */
r = _dpll_test_fint(clk, n); r = _dpll_test_fint(clk, n);
if (r == DPLL_FINT_UNDERFLOW) if (r == DPLL_FINT_UNDERFLOW)
...@@ -367,4 +367,3 @@ long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate, ...@@ -367,4 +367,3 @@ long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
return dd->last_rounded_rate; return dd->last_rounded_rate;
} }
...@@ -13,12 +13,17 @@ ...@@ -13,12 +13,17 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/clk/ti.h>
#include "clock.h" #include "clock.h"
/* Register offsets */ /* Register offsets */
#define OMAP24XX_CM_FCLKEN2 0x04
#define CM_AUTOIDLE 0x30 #define CM_AUTOIDLE 0x30
#define CM_ICLKEN 0x10 #define CM_ICLKEN 0x10
#define CM_IDLEST 0x20
#define OMAP24XX_CM_IDLEST_VAL 0
/* Private functions */ /* Private functions */
...@@ -31,9 +36,9 @@ void omap2_clkt_iclk_allow_idle(struct clk_hw_omap *clk) ...@@ -31,9 +36,9 @@ void omap2_clkt_iclk_allow_idle(struct clk_hw_omap *clk)
r = (__force void __iomem *) r = (__force void __iomem *)
((__force u32)clk->enable_reg ^ (CM_AUTOIDLE ^ CM_ICLKEN)); ((__force u32)clk->enable_reg ^ (CM_AUTOIDLE ^ CM_ICLKEN));
v = omap2_clk_readl(clk, r); v = ti_clk_ll_ops->clk_readl(r);
v |= (1 << clk->enable_bit); v |= (1 << clk->enable_bit);
omap2_clk_writel(v, clk, r); ti_clk_ll_ops->clk_writel(v, r);
} }
/* XXX */ /* XXX */
...@@ -45,9 +50,34 @@ void omap2_clkt_iclk_deny_idle(struct clk_hw_omap *clk) ...@@ -45,9 +50,34 @@ void omap2_clkt_iclk_deny_idle(struct clk_hw_omap *clk)
r = (__force void __iomem *) r = (__force void __iomem *)
((__force u32)clk->enable_reg ^ (CM_AUTOIDLE ^ CM_ICLKEN)); ((__force u32)clk->enable_reg ^ (CM_AUTOIDLE ^ CM_ICLKEN));
v = omap2_clk_readl(clk, r); v = ti_clk_ll_ops->clk_readl(r);
v &= ~(1 << clk->enable_bit); v &= ~(1 << clk->enable_bit);
omap2_clk_writel(v, clk, r); ti_clk_ll_ops->clk_writel(v, r);
}
/**
* omap2430_clk_i2chs_find_idlest - return CM_IDLEST info for 2430 I2CHS
* @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
*
* OMAP2430 I2CHS CM_IDLEST bits are in CM_IDLEST1_CORE, but the
* CM_*CLKEN bits are in CM_{I,F}CLKEN2_CORE. This custom function
* passes back the correct CM_IDLEST register address for I2CHS
* modules. No return value.
*/
static void omap2430_clk_i2chs_find_idlest(struct clk_hw_omap *clk,
void __iomem **idlest_reg,
u8 *idlest_bit,
u8 *idlest_val)
{
u32 r;
r = ((__force u32)clk->enable_reg ^ (OMAP24XX_CM_FCLKEN2 ^ CM_IDLEST));
*idlest_reg = (__force void __iomem *)r;
*idlest_bit = clk->enable_bit;
*idlest_val = OMAP24XX_CM_IDLEST_VAL;
} }
/* Public data */ /* Public data */
...@@ -64,5 +94,8 @@ const struct clk_hw_omap_ops clkhwops_iclk_wait = { ...@@ -64,5 +94,8 @@ const struct clk_hw_omap_ops clkhwops_iclk_wait = {
.find_companion = omap2_clk_dflt_find_companion, .find_companion = omap2_clk_dflt_find_companion,
}; };
/* 2430 I2CHS has non-standard IDLEST register */
const struct clk_hw_omap_ops clkhwops_omap2430_i2chs_wait = {
.find_idlest = omap2430_clk_i2chs_find_idlest,
.find_companion = omap2_clk_dflt_find_companion,
};
...@@ -154,6 +154,35 @@ struct ti_clk_dpll { ...@@ -154,6 +154,35 @@ struct ti_clk_dpll {
u8 recal_st_bit; u8 recal_st_bit;
}; };
/* Composite clock component types */
enum {
CLK_COMPONENT_TYPE_GATE = 0,
CLK_COMPONENT_TYPE_DIVIDER,
CLK_COMPONENT_TYPE_MUX,
CLK_COMPONENT_TYPE_MAX,
};
/**
* struct ti_dt_clk - OMAP DT clock alias declarations
* @lk: clock lookup definition
* @node_name: clock DT node to map to
*/
struct ti_dt_clk {
struct clk_lookup lk;
char *node_name;
};
#define DT_CLK(dev, con, name) \
{ \
.lk = { \
.dev_id = dev, \
.con_id = con, \
}, \
.node_name = name, \
}
typedef void (*ti_of_clk_init_cb_t)(struct clk_hw *, struct device_node *);
struct clk *ti_clk_register_gate(struct ti_clk *setup); struct clk *ti_clk_register_gate(struct ti_clk *setup);
struct clk *ti_clk_register_interface(struct ti_clk *setup); struct clk *ti_clk_register_interface(struct ti_clk *setup);
struct clk *ti_clk_register_mux(struct ti_clk *setup); struct clk *ti_clk_register_mux(struct ti_clk *setup);
...@@ -169,4 +198,80 @@ void ti_clk_patch_legacy_clks(struct ti_clk **patch); ...@@ -169,4 +198,80 @@ void ti_clk_patch_legacy_clks(struct ti_clk **patch);
struct clk *ti_clk_register_clk(struct ti_clk *setup); struct clk *ti_clk_register_clk(struct ti_clk *setup);
int ti_clk_register_legacy_clks(struct ti_clk_alias *clks); int ti_clk_register_legacy_clks(struct ti_clk_alias *clks);
void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index);
void ti_dt_clocks_register(struct ti_dt_clk *oclks);
int ti_clk_retry_init(struct device_node *node, struct clk_hw *hw,
ti_of_clk_init_cb_t func);
int ti_clk_add_component(struct device_node *node, struct clk_hw *hw, int type);
void omap2_init_clk_hw_omap_clocks(struct clk *clk);
int of_ti_clk_autoidle_setup(struct device_node *node);
void omap2_clk_enable_init_clocks(const char **clk_names, u8 num_clocks);
extern const struct clk_hw_omap_ops clkhwops_omap3_dpll;
extern const struct clk_hw_omap_ops clkhwops_omap4_dpllmx;
extern const struct clk_hw_omap_ops clkhwops_wait;
extern const struct clk_hw_omap_ops clkhwops_iclk;
extern const struct clk_hw_omap_ops clkhwops_iclk_wait;
extern const struct clk_hw_omap_ops clkhwops_omap2430_i2chs_wait;
extern const struct clk_hw_omap_ops clkhwops_omap3430es2_dss_usbhost_wait;
extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_hsotgusb_wait;
extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_dss_usbhost_wait;
extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_ssi_wait;
extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_module_wait;
extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_wait;
extern const struct clk_ops ti_clk_divider_ops;
extern const struct clk_ops ti_clk_mux_ops;
int omap2_clkops_enable_clkdm(struct clk_hw *hw);
void omap2_clkops_disable_clkdm(struct clk_hw *hw);
int omap2_dflt_clk_enable(struct clk_hw *hw);
void omap2_dflt_clk_disable(struct clk_hw *hw);
int omap2_dflt_clk_is_enabled(struct clk_hw *hw);
void omap2_clk_dflt_find_companion(struct clk_hw_omap *clk,
void __iomem **other_reg,
u8 *other_bit);
void omap2_clk_dflt_find_idlest(struct clk_hw_omap *clk,
void __iomem **idlest_reg,
u8 *idlest_bit, u8 *idlest_val);
void omap2_clkt_iclk_allow_idle(struct clk_hw_omap *clk);
void omap2_clkt_iclk_deny_idle(struct clk_hw_omap *clk);
u8 omap2_init_dpll_parent(struct clk_hw *hw);
int omap3_noncore_dpll_enable(struct clk_hw *hw);
void omap3_noncore_dpll_disable(struct clk_hw *hw);
int omap3_noncore_dpll_set_parent(struct clk_hw *hw, u8 index);
int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate);
int omap3_noncore_dpll_set_rate_and_parent(struct clk_hw *hw,
unsigned long rate,
unsigned long parent_rate,
u8 index);
int omap3_noncore_dpll_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req);
long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
unsigned long *parent_rate);
unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw,
unsigned long parent_rate);
unsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate);
int omap3_dpll4_set_rate(struct clk_hw *clk, unsigned long rate,
unsigned long parent_rate);
int omap3_dpll4_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate, u8 index);
void omap3_clk_lock_dpll5(void);
unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw,
unsigned long parent_rate);
long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw,
unsigned long target_rate,
unsigned long *parent_rate);
int omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req);
extern struct ti_clk_ll_ops *ti_clk_ll_ops;
#endif #endif
...@@ -21,9 +21,87 @@ ...@@ -21,9 +21,87 @@
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/clk/ti.h> #include <linux/clk/ti.h>
#include "clock.h"
#undef pr_fmt #undef pr_fmt
#define pr_fmt(fmt) "%s: " fmt, __func__ #define pr_fmt(fmt) "%s: " fmt, __func__
/**
* omap2_clkops_enable_clkdm - increment usecount on clkdm of @hw
* @hw: struct clk_hw * of the clock being enabled
*
* Increment the usecount of the clockdomain of the clock pointed to
* by @hw; if the usecount is 1, the clockdomain will be "enabled."
* Only needed for clocks that don't use omap2_dflt_clk_enable() as
* their enable function pointer. Passes along the return value of
* clkdm_clk_enable(), -EINVAL if @hw is not associated with a
* clockdomain, or 0 if clock framework-based clockdomain control is
* not implemented.
*/
int omap2_clkops_enable_clkdm(struct clk_hw *hw)
{
struct clk_hw_omap *clk;
int ret = 0;
clk = to_clk_hw_omap(hw);
if (unlikely(!clk->clkdm)) {
pr_err("%s: %s: no clkdm set ?!\n", __func__,
__clk_get_name(hw->clk));
return -EINVAL;
}
if (unlikely(clk->enable_reg))
pr_err("%s: %s: should use dflt_clk_enable ?!\n", __func__,
__clk_get_name(hw->clk));
if (ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL) {
pr_err("%s: %s: clkfw-based clockdomain control disabled ?!\n",
__func__, __clk_get_name(hw->clk));
return 0;
}
ret = ti_clk_ll_ops->clkdm_clk_enable(clk->clkdm, hw->clk);
WARN(ret, "%s: could not enable %s's clockdomain %s: %d\n",
__func__, __clk_get_name(hw->clk), clk->clkdm_name, ret);
return ret;
}
/**
* omap2_clkops_disable_clkdm - decrement usecount on clkdm of @hw
* @hw: struct clk_hw * of the clock being disabled
*
* Decrement the usecount of the clockdomain of the clock pointed to
* by @hw; if the usecount is 0, the clockdomain will be "disabled."
* Only needed for clocks that don't use omap2_dflt_clk_disable() as their
* disable function pointer. No return value.
*/
void omap2_clkops_disable_clkdm(struct clk_hw *hw)
{
struct clk_hw_omap *clk;
clk = to_clk_hw_omap(hw);
if (unlikely(!clk->clkdm)) {
pr_err("%s: %s: no clkdm set ?!\n", __func__,
__clk_get_name(hw->clk));
return;
}
if (unlikely(clk->enable_reg))
pr_err("%s: %s: should use dflt_clk_disable ?!\n", __func__,
__clk_get_name(hw->clk));
if (ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL) {
pr_err("%s: %s: clkfw-based clockdomain control disabled ?!\n",
__func__, __clk_get_name(hw->clk));
return;
}
ti_clk_ll_ops->clkdm_clk_disable(clk->clkdm, hw->clk);
}
static void __init of_ti_clockdomain_setup(struct device_node *node) static void __init of_ti_clockdomain_setup(struct device_node *node)
{ {
struct clk *clk; struct clk *clk;
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/clk/ti.h>
#include "clock.h" #include "clock.h"
...@@ -29,14 +30,14 @@ ...@@ -29,14 +30,14 @@
/* /*
* Bitfield declarations * Bitfield declarations
*/ */
#define OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK (1 << 8) #define OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK BIT(8)
#define OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK (1 << 10) #define OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK BIT(10)
#define OMAP4430_DPLL_REGM4XEN_MASK (1 << 11) #define OMAP4430_DPLL_REGM4XEN_MASK BIT(11)
/* Static rate multiplier for OMAP4 REGM4XEN clocks */ /* Static rate multiplier for OMAP4 REGM4XEN clocks */
#define OMAP4430_REGM4XEN_MULT 4 #define OMAP4430_REGM4XEN_MULT 4
void omap4_dpllmx_allow_gatectrl(struct clk_hw_omap *clk) static void omap4_dpllmx_allow_gatectrl(struct clk_hw_omap *clk)
{ {
u32 v; u32 v;
u32 mask; u32 mask;
...@@ -48,13 +49,13 @@ void omap4_dpllmx_allow_gatectrl(struct clk_hw_omap *clk) ...@@ -48,13 +49,13 @@ void omap4_dpllmx_allow_gatectrl(struct clk_hw_omap *clk)
OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK : OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK :
OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK; OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK;
v = omap2_clk_readl(clk, clk->clksel_reg); v = ti_clk_ll_ops->clk_readl(clk->clksel_reg);
/* Clear the bit to allow gatectrl */ /* Clear the bit to allow gatectrl */
v &= ~mask; v &= ~mask;
omap2_clk_writel(v, clk, clk->clksel_reg); ti_clk_ll_ops->clk_writel(v, clk->clksel_reg);
} }
void omap4_dpllmx_deny_gatectrl(struct clk_hw_omap *clk) static void omap4_dpllmx_deny_gatectrl(struct clk_hw_omap *clk)
{ {
u32 v; u32 v;
u32 mask; u32 mask;
...@@ -66,10 +67,10 @@ void omap4_dpllmx_deny_gatectrl(struct clk_hw_omap *clk) ...@@ -66,10 +67,10 @@ void omap4_dpllmx_deny_gatectrl(struct clk_hw_omap *clk)
OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK : OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK :
OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK; OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK;
v = omap2_clk_readl(clk, clk->clksel_reg); v = ti_clk_ll_ops->clk_readl(clk->clksel_reg);
/* Set the bit to deny gatectrl */ /* Set the bit to deny gatectrl */
v |= mask; v |= mask;
omap2_clk_writel(v, clk, clk->clksel_reg); ti_clk_ll_ops->clk_writel(v, clk->clksel_reg);
} }
const struct clk_hw_omap_ops clkhwops_omap4_dpllmx = { const struct clk_hw_omap_ops clkhwops_omap4_dpllmx = {
...@@ -127,7 +128,7 @@ unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw, ...@@ -127,7 +128,7 @@ unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw,
rate = omap2_get_dpll_rate(clk); rate = omap2_get_dpll_rate(clk);
/* regm4xen adds a multiplier of 4 to DPLL calculations */ /* regm4xen adds a multiplier of 4 to DPLL calculations */
v = omap2_clk_readl(clk, dd->control_reg); v = ti_clk_ll_ops->clk_readl(dd->control_reg);
if (v & OMAP4430_DPLL_REGM4XEN_MASK) if (v & OMAP4430_DPLL_REGM4XEN_MASK)
rate *= OMAP4430_REGM4XEN_MULT; rate *= OMAP4430_REGM4XEN_MULT;
......
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/clk/ti.h> #include <linux/clk/ti.h>
#include "clock.h"
#undef pr_fmt #undef pr_fmt
#define pr_fmt(fmt) "%s: " fmt, __func__ #define pr_fmt(fmt) "%s: " fmt, __func__
......
...@@ -188,33 +188,6 @@ struct clk_hw_omap { ...@@ -188,33 +188,6 @@ struct clk_hw_omap {
/* DPLL Type and DCO Selection Flags */ /* DPLL Type and DCO Selection Flags */
#define DPLL_J_TYPE 0x1 #define DPLL_J_TYPE 0x1
/* Composite clock component types */
enum {
CLK_COMPONENT_TYPE_GATE = 0,
CLK_COMPONENT_TYPE_DIVIDER,
CLK_COMPONENT_TYPE_MUX,
CLK_COMPONENT_TYPE_MAX,
};
/**
* struct ti_dt_clk - OMAP DT clock alias declarations
* @lk: clock lookup definition
* @node_name: clock DT node to map to
*/
struct ti_dt_clk {
struct clk_lookup lk;
char *node_name;
};
#define DT_CLK(dev, con, name) \
{ \
.lk = { \
.dev_id = dev, \
.con_id = con, \
}, \
.node_name = name, \
}
/* Static memmap indices */ /* Static memmap indices */
enum { enum {
TI_CLKM_CM = 0, TI_CLKM_CM = 0,
...@@ -225,8 +198,6 @@ enum { ...@@ -225,8 +198,6 @@ enum {
CLK_MAX_MEMMAPS CLK_MAX_MEMMAPS
}; };
typedef void (*ti_of_clk_init_cb_t)(struct clk_hw *, struct device_node *);
/** /**
* struct clk_omap_reg - OMAP register declaration * struct clk_omap_reg - OMAP register declaration
* @offset: offset from the master IP module base address * @offset: offset from the master IP module base address
...@@ -238,85 +209,56 @@ struct clk_omap_reg { ...@@ -238,85 +209,56 @@ struct clk_omap_reg {
}; };
/** /**
* struct ti_clk_ll_ops - low-level register access ops for a clock * struct ti_clk_ll_ops - low-level ops for clocks
* @clk_readl: pointer to register read function * @clk_readl: pointer to register read function
* @clk_writel: pointer to register write function * @clk_writel: pointer to register write function
* @clkdm_clk_enable: pointer to clockdomain enable function
* @clkdm_clk_disable: pointer to clockdomain disable function
* @cm_wait_module_ready: pointer to CM module wait ready function
* @cm_split_idlest_reg: pointer to CM module function to split idlest reg
* *
* Low-level register access ops are generally used by the basic clock types * Low-level ops are generally used by the basic clock types (clk-gate,
* (clk-gate, clk-mux, clk-divider etc.) to provide support for various * clk-mux, clk-divider etc.) to provide support for various low-level
* low-level hardware interfaces (direct MMIO, regmap etc.), but can also be * hadrware interfaces (direct MMIO, regmap etc.), and is initialized
* used by other hardware-specific clock drivers if needed. * by board code. Low-level ops also contain some other platform specific
* operations not provided directly by clock drivers.
*/ */
struct ti_clk_ll_ops { struct ti_clk_ll_ops {
u32 (*clk_readl)(void __iomem *reg); u32 (*clk_readl)(void __iomem *reg);
void (*clk_writel)(u32 val, void __iomem *reg); void (*clk_writel)(u32 val, void __iomem *reg);
int (*clkdm_clk_enable)(struct clockdomain *clkdm, struct clk *clk);
int (*clkdm_clk_disable)(struct clockdomain *clkdm,
struct clk *clk);
int (*cm_wait_module_ready)(u8 part, s16 prcm_mod, u16 idlest_reg,
u8 idlest_shift);
int (*cm_split_idlest_reg)(void __iomem *idlest_reg, s16 *prcm_inst,
u8 *idlest_reg_id);
}; };
extern struct ti_clk_ll_ops *ti_clk_ll_ops;
extern const struct clk_ops ti_clk_divider_ops;
extern const struct clk_ops ti_clk_mux_ops;
#define to_clk_hw_omap(_hw) container_of(_hw, struct clk_hw_omap, hw) #define to_clk_hw_omap(_hw) container_of(_hw, struct clk_hw_omap, hw)
void omap2_init_clk_hw_omap_clocks(struct clk *clk);
int omap3_noncore_dpll_enable(struct clk_hw *hw);
void omap3_noncore_dpll_disable(struct clk_hw *hw);
int omap3_noncore_dpll_set_parent(struct clk_hw *hw, u8 index);
int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate);
int omap3_noncore_dpll_set_rate_and_parent(struct clk_hw *hw,
unsigned long rate,
unsigned long parent_rate,
u8 index);
int omap3_noncore_dpll_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req);
unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw,
unsigned long parent_rate);
long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw,
unsigned long target_rate,
unsigned long *parent_rate);
int omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req);
u8 omap2_init_dpll_parent(struct clk_hw *hw);
unsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate);
long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
unsigned long *parent_rate);
void omap2_init_clk_clkdm(struct clk_hw *clk); void omap2_init_clk_clkdm(struct clk_hw *clk);
unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw,
unsigned long parent_rate);
int omap3_clkoutx2_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate);
long omap3_clkoutx2_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate);
int omap2_clkops_enable_clkdm(struct clk_hw *hw);
void omap2_clkops_disable_clkdm(struct clk_hw *hw);
int omap2_clk_disable_autoidle_all(void); int omap2_clk_disable_autoidle_all(void);
void omap2_clk_enable_init_clocks(const char **clk_names, u8 num_clocks); int omap2_clk_enable_autoidle_all(void);
int omap3_dpll4_set_rate(struct clk_hw *clk, unsigned long rate, int omap2_clk_allow_idle(struct clk *clk);
unsigned long parent_rate); int omap2_clk_deny_idle(struct clk *clk);
int omap3_dpll4_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate, u8 index);
int omap2_dflt_clk_enable(struct clk_hw *hw);
void omap2_dflt_clk_disable(struct clk_hw *hw);
int omap2_dflt_clk_is_enabled(struct clk_hw *hw);
void omap3_clk_lock_dpll5(void);
unsigned long omap2_dpllcore_recalc(struct clk_hw *hw, unsigned long omap2_dpllcore_recalc(struct clk_hw *hw,
unsigned long parent_rate); unsigned long parent_rate);
int omap2_reprogram_dpllcore(struct clk_hw *clk, unsigned long rate, int omap2_reprogram_dpllcore(struct clk_hw *clk, unsigned long rate,
unsigned long parent_rate); unsigned long parent_rate);
void omap2xxx_clkt_dpllcore_init(struct clk_hw *hw); void omap2xxx_clkt_dpllcore_init(struct clk_hw *hw);
void omap2xxx_clkt_vps_init(void); void omap2xxx_clkt_vps_init(void);
unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk);
void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index);
void ti_dt_clocks_register(struct ti_dt_clk *oclks);
void ti_dt_clk_init_provider(struct device_node *np, int index);
void ti_dt_clk_init_retry_clks(void); void ti_dt_clk_init_retry_clks(void);
void ti_dt_clockdomains_setup(void); void ti_dt_clockdomains_setup(void);
int ti_clk_retry_init(struct device_node *node, struct clk_hw *hw, int ti_clk_setup_ll_ops(struct ti_clk_ll_ops *ops);
ti_of_clk_init_cb_t func);
int of_ti_clk_autoidle_setup(struct device_node *node); struct regmap;
int ti_clk_add_component(struct device_node *node, struct clk_hw *hw, int type);
int omap2_clk_provider_init(struct device_node *parent, int index,
struct regmap *syscon, void __iomem *mem);
void omap2_clk_legacy_provider_init(int index, void __iomem *mem);
int omap3430_dt_clk_init(void); int omap3430_dt_clk_init(void);
int omap3630_dt_clk_init(void); int omap3630_dt_clk_init(void);
...@@ -330,27 +272,24 @@ int am43xx_dt_clk_init(void); ...@@ -330,27 +272,24 @@ int am43xx_dt_clk_init(void);
int omap2420_dt_clk_init(void); int omap2420_dt_clk_init(void);
int omap2430_dt_clk_init(void); int omap2430_dt_clk_init(void);
#ifdef CONFIG_OF struct ti_clk_features {
void of_ti_clk_allow_autoidle_all(void); u32 flags;
void of_ti_clk_deny_autoidle_all(void); long fint_min;
#else long fint_max;
static inline void of_ti_clk_allow_autoidle_all(void) { } long fint_band1_max;
static inline void of_ti_clk_deny_autoidle_all(void) { } long fint_band2_min;
#endif u8 dpll_bypass_vals;
u8 cm_idlest_val;
};
#define TI_CLK_DPLL_HAS_FREQSEL BIT(0)
#define TI_CLK_DPLL4_DENY_REPROGRAM BIT(1)
#define TI_CLK_DISABLE_CLKDM_CONTROL BIT(2)
void ti_clk_setup_features(struct ti_clk_features *features);
const struct ti_clk_features *ti_clk_get_features(void);
extern const struct clk_hw_omap_ops clkhwops_omap2xxx_dpll; extern const struct clk_hw_omap_ops clkhwops_omap2xxx_dpll;
extern const struct clk_hw_omap_ops clkhwops_omap2430_i2chs_wait;
extern const struct clk_hw_omap_ops clkhwops_omap3_dpll;
extern const struct clk_hw_omap_ops clkhwops_omap4_dpllmx;
extern const struct clk_hw_omap_ops clkhwops_wait;
extern const struct clk_hw_omap_ops clkhwops_omap3430es2_dss_usbhost_wait;
extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_module_wait;
extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_wait;
extern const struct clk_hw_omap_ops clkhwops_iclk;
extern const struct clk_hw_omap_ops clkhwops_iclk_wait;
extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_ssi_wait;
extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_dss_usbhost_wait;
extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_hsotgusb_wait;
#ifdef CONFIG_ATAGS #ifdef CONFIG_ATAGS
int omap3430_clk_legacy_init(void); int omap3430_clk_legacy_init(void);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment