Commit 13c5f9d3 authored by Paul Walmsley's avatar Paul Walmsley Committed by Tony Lindgren

omap2 clock: add OMAP3430 clock definitions, basic code

Define the clock tree, and add basic supporting clock code, for the
OMAP34xx chips.  The definitions and code go into two new files,
clock34xx.[ch].

The 34xx clock tree and code is written to reuse as much of the
existing OMAP clock infrastructure as is reasonable, and to introduce
the minimum amount possible of special-case code.  One notable
addition is the expansion of the dpll_params structure to include the
additional DPLL control registers used on OMAP34XX; most of these
extra registers are used in subsequent patches.

The patches seek to follow the TRM closely.  One implication of this
is that several intermediary clocks are defined that are not
software-controllable, and could normally be removed.  Some examples
include omap_96m_fck, core_l3_ick, corex2_fck.  I included these
clocks for several reasons.  Any further changes in pre-production
OMAP34xx silicon revisions may cause one of these clocks to become
software-controllable; the extra clocks make it easier to double-check
this patch against the TRM, if anyone wishes to do so; and ultimately,
it is easier to remove these clocks than to add them back in.  I
anticipate that we will remove these intermediary clocks once the 3430
silicon and clock definitions mature.

There are some notable divergences between the TRM and the patch.
They include:

* Clock suffixes end in "ck" rather than "clk"; this follows OMAP2
  clock naming style to minimize driver changes in the rest of the tree.

* The dpll*_alwon_fck clocks have been removed (they are not software
  controllable, and are unlikely to change)

* Some documentation in the TRM is inconsistent; I sought to apply
  the most likely resolution in the code.
Signed-off-by: default avatarPaul Walmsley <paul@pwsan.com>
Signed-off-by: default avatarTony Lindgren <tony@atomide.com>
parent adb5ea75
......@@ -13,6 +13,7 @@ obj-$(CONFIG_PM) += pm.o sleep.o
# Clock framework
obj-$(CONFIG_ARCH_OMAP2) += clock24xx.o
obj-$(CONFIG_ARCH_OMAP3) += clock34xx.o
# DSP
obj-$(CONFIG_OMAP_MMU_FWK) += mmu_mach.o
......
......@@ -74,8 +74,7 @@ void omap2_init_clksel_parent(struct clk *clk)
if (!clk->clksel)
return;
/* XXX Should be __raw_readl for non-CM 3430 clocks ? */
r = cm_read_reg(clk->clksel_reg) & clk->clksel_mask;
r = __raw_readl(clk->clksel_reg) & clk->clksel_mask;
r >>= mask_to_shift(clk->clksel_mask);
for (clks = clk->clksel; clks->parent && !found; clks++) {
......@@ -122,6 +121,14 @@ u32 omap2_get_dpll_rate(struct clk *clk)
dpll_clk = (long long)clk->parent->rate * dpll_mult;
do_div(dpll_clk, dpll_div + 1);
/* 34XX only */
if (dd->div2_reg) {
dpll = cm_read_reg(dd->div2_reg);
dpll_div = dpll & dd->div2_mask;
dpll_div >>= mask_to_shift(dd->div2_mask);
do_div(dpll_clk, dpll_div + 1);
}
return dpll_clk;
}
......@@ -142,29 +149,39 @@ void omap2_fixed_divisor_recalc(struct clk *clk)
/**
* omap2_wait_clock_ready - wait for clock to enable
* @reg: physical address of clock IDLEST register
* @cval: value to test against to determine if the clock is active
* @mask: value to mask against to determine if the clock is active
* @name: name of the clock (for printk)
*
* Returns 1 if the clock enabled in time, or 0 if it failed to enable
* in roughly MAX_CLOCK_ENABLE_WAIT microseconds.
*/
int omap2_wait_clock_ready(void __iomem *reg, u32 cval, const char *name)
int omap2_wait_clock_ready(void __iomem *reg, u32 mask, const char *name)
{
int i = 0;
int ena = 0;
/*
* 24xx uses 0 to indicate not ready, and 1 to indicate ready.
* 34xx reverses this, just to keep us on our toes
*/
if (cpu_mask & (RATE_IN_242X | RATE_IN_243X)) {
ena = mask;
} else if (cpu_mask & RATE_IN_343X) {
ena = 0;
}
/* Wait for lock */
while (!(cm_read_reg(reg) & cval)) {
++i;
while (((cm_read_reg(reg) & mask) != ena) &&
(i++ < MAX_CLOCK_ENABLE_WAIT)) {
udelay(1);
if (i == MAX_CLOCK_ENABLE_WAIT) {
printk(KERN_ERR "Clock %s didn't enable in %d tries\n",
name, MAX_CLOCK_ENABLE_WAIT);
break;
}
}
if (i < MAX_CLOCK_ENABLE_WAIT)
pr_debug("Clock %s stable after %d loops\n", name, i);
else
printk(KERN_ERR "Clock %s didn't enable in %d tries\n",
name, MAX_CLOCK_ENABLE_WAIT);
return (i < MAX_CLOCK_ENABLE_WAIT) ? 1 : 0;
};
......@@ -180,6 +197,10 @@ static void omap2_clk_wait_ready(struct clk *clk)
void __iomem *reg, *other_reg, *st_reg;
u32 bit;
/*
* REVISIT: This code is pretty ugly. It would be nice to generalize
* it and pull it into struct clk itself somehow.
*/
reg = clk->enable_reg;
if (reg == OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1) ||
reg == OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2))
......@@ -225,7 +246,7 @@ int _omap2_clk_enable(struct clk *clk)
if (unlikely(clk->enable_reg == 0)) {
printk(KERN_ERR "clock.c: Enable for %s without enable code\n",
clk->name);
return -EINVAL;
return 0; /* REVISIT: -EINVAL */
}
regval32 = cm_read_reg(clk->enable_reg);
......
/*
* OMAP3-specific clock framework functions
*
* Copyright (C) 2007 Texas Instruments, Inc.
* Copyright (C) 2007 Nokia Corporation
*
* Written by Paul Walmsley
*
* 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/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <asm/arch/clock.h>
#include <asm/arch/sram.h>
#include <asm/div64.h>
#include "memory.h"
#include "clock.h"
#include "clock34xx.h"
#include "prm.h"
#include "prm_regbits_34xx.h"
#include "cm.h"
#include "cm_regbits_34xx.h"
/* CM_CLKEN_PLL*.EN* bit values */
#define DPLL_LOCKED 0x7
/**
* omap3_dpll_recalc - recalculate DPLL rate
* @clk: DPLL struct clk
*
* Recalculate and propagate the DPLL rate.
*/
static void omap3_dpll_recalc(struct clk *clk)
{
clk->rate = omap2_get_dpll_rate(clk);
propagate_rate(clk);
}
/**
* omap3_clkoutx2_recalc - recalculate DPLL X2 output virtual clock rate
* @clk: DPLL output struct clk
*
* Using parent clock DPLL data, look up DPLL state. If locked, set our
* rate to the dpll_clk * 2; otherwise, just use dpll_clk.
*/
static void omap3_clkoutx2_recalc(struct clk *clk)
{
const struct dpll_data *dd;
u32 v;
struct clk *pclk;
/* Walk up the parents of clk, looking for a DPLL */
pclk = clk->parent;
while (pclk && !pclk->dpll_data)
pclk = pclk->parent;
/* clk does not have a DPLL as a parent? */
WARN_ON(!pclk);
dd = pclk->dpll_data;
WARN_ON(!dd->control_reg || !dd->enable_mask);
v = cm_read_reg(dd->control_reg) & dd->enable_mask;
if (v != DPLL_LOCKED)
clk->rate = clk->parent->rate;
else
clk->rate = clk->parent->rate * 2;
if (clk->flags & RATE_PROPAGATES)
propagate_rate(clk);
}
/*
* As it is structured now, this will prevent an OMAP2/3 multiboot
* kernel from compiling. This will need further attention.
*/
#if defined(CONFIG_ARCH_OMAP3)
static struct clk_functions omap2_clk_functions = {
.clk_enable = omap2_clk_enable,
.clk_disable = omap2_clk_disable,
.clk_round_rate = omap2_clk_round_rate,
.clk_set_rate = omap2_clk_set_rate,
.clk_set_parent = omap2_clk_set_parent,
.clk_disable_unused = omap2_clk_disable_unused,
};
/*
* Set clocks for bypass mode for reboot to work.
*/
void omap2_clk_prepare_for_reboot(void)
{
/* REVISIT: Not ready for 343x */
#if 0
u32 rate;
if (vclk == NULL || sclk == NULL)
return;
rate = clk_get_rate(sclk);
clk_set_rate(vclk, rate);
#endif
}
/* REVISIT: Move this init stuff out into clock.c */
/*
* Switch the MPU rate if specified on cmdline.
* We cannot do this early until cmdline is parsed.
*/
static int __init omap2_clk_arch_init(void)
{
if (!mpurate)
return -EINVAL;
/* REVISIT: not yet ready for 343x */
#if 0
if (omap2_select_table_rate(&virt_prcm_set, mpurate))
printk(KERN_ERR "Could not find matching MPU rate\n");
#endif
recalculate_root_clocks();
printk(KERN_INFO "Switched to new clocking rate (Crystal/DPLL3/MPU): "
"%ld.%01ld/%ld/%ld MHz\n",
(osc_sys_ck.rate / 1000000), (osc_sys_ck.rate / 100000) % 10,
(core_ck.rate / 1000000), (dpll1_fck.rate / 1000000)) ;
return 0;
}
arch_initcall(omap2_clk_arch_init);
int __init omap2_clk_init(void)
{
/* struct prcm_config *prcm; */
struct clk **clkp;
/* u32 clkrate; */
u32 cpu_clkflg;
/* REVISIT: Ultimately this will be used for multiboot */
#if 0
if (cpu_is_omap242x()) {
cpu_mask = RATE_IN_242X;
cpu_clkflg = CLOCK_IN_OMAP242X;
clkp = onchip_24xx_clks;
} else if (cpu_is_omap2430()) {
cpu_mask = RATE_IN_243X;
cpu_clkflg = CLOCK_IN_OMAP243X;
clkp = onchip_24xx_clks;
}
#endif
if (cpu_is_omap34xx()) {
cpu_mask = RATE_IN_343X;
cpu_clkflg = CLOCK_IN_OMAP343X;
clkp = onchip_34xx_clks;
}
clk_init(&omap2_clk_functions);
for (clkp = onchip_34xx_clks;
clkp < onchip_34xx_clks + ARRAY_SIZE(onchip_34xx_clks);
clkp++) {
if ((*clkp)->flags & cpu_clkflg)
clk_register(*clkp);
}
/* REVISIT: Not yet ready for OMAP3 */
#if 0
/* Check the MPU rate set by bootloader */
clkrate = omap2_get_dpll_rate_24xx(&dpll_ck);
for (prcm = rate_table; prcm->mpu_speed; prcm++) {
if (!(prcm->flags & cpu_mask))
continue;
if (prcm->xtal_speed != sys_ck.rate)
continue;
if (prcm->dpll_speed <= clkrate)
break;
}
curr_prcm_set = prcm;
#endif
recalculate_root_clocks();
printk(KERN_INFO "Clocking rate (Crystal/DPLL/MPU): "
"%ld.%01ld/%ld/%ld MHz\n",
(osc_sys_ck.rate / 1000000), (osc_sys_ck.rate / 100000) % 10,
(core_ck.rate / 1000000), (dpll1_fck.rate / 1000000)) ;
/*
* Only enable those clocks we will need, let the drivers
* enable other clocks as necessary
*/
clk_enable_init_clocks();
/* Avoid sleeping during omap2_clk_prepare_for_reboot() */
/* REVISIT: not yet ready for 343x */
#if 0
vclk = clk_get(NULL, "virt_prcm_set");
sclk = clk_get(NULL, "sys_ck");
#endif
return 0;
}
#endif
This diff is collapsed.
......@@ -30,6 +30,8 @@
#define OMAP3430_CM_SYSCONFIG OMAP_CM_REGADDR(OCP_MOD, 0x0010)
#define OMAP3430_CM_POLCTRL OMAP_CM_REGADDR(OCP_MOD, 0x009c)
#define OMAP3430_CM_CLKOUT_CTRL OMAP_CM_REGADDR(OMAP3430_CCR_MOD, 0x0070)
/* Clock management global register get/set */
......
This diff is collapsed.
......@@ -159,25 +159,43 @@
/* CM_FCLKEN1_CORE, CM_ICLKEN1_CORE, PM_WKEN1_CORE shared bits */
#define OMAP3430_EN_MMC2 (1 << 25)
#define OMAP3430_EN_MMC2_SHIFT 25
#define OMAP3430_EN_MMC1 (1 << 24)
#define OMAP3430_EN_MMC1_SHIFT 24
#define OMAP3430_EN_MCSPI4 (1 << 21)
#define OMAP3430_EN_MCSPI4_SHIFT 21
#define OMAP3430_EN_MCSPI3 (1 << 20)
#define OMAP3430_EN_MCSPI3_SHIFT 20
#define OMAP3430_EN_MCSPI2 (1 << 19)
#define OMAP3430_EN_MCSPI2_SHIFT 19
#define OMAP3430_EN_MCSPI1 (1 << 18)
#define OMAP3430_EN_MCSPI1_SHIFT 18
#define OMAP3430_EN_I2C3 (1 << 17)
#define OMAP3430_EN_I2C3_SHIFT 17
#define OMAP3430_EN_I2C2 (1 << 16)
#define OMAP3430_EN_I2C2_SHIFT 16
#define OMAP3430_EN_I2C1 (1 << 15)
#define OMAP3430_EN_I2C1_SHIFT 15
#define OMAP3430_EN_UART2 (1 << 14)
#define OMAP3430_EN_UART2_SHIFT 14
#define OMAP3430_EN_UART1 (1 << 13)
#define OMAP3430_EN_UART1_SHIFT 13
#define OMAP3430_EN_GPT11 (1 << 12)
#define OMAP3430_EN_GPT11_SHIFT 12
#define OMAP3430_EN_GPT10 (1 << 11)
#define OMAP3430_EN_GPT10_SHIFT 11
#define OMAP3430_EN_MCBSP5 (1 << 10)
#define OMAP3430_EN_MCBSP5_SHIFT 10
#define OMAP3430_EN_MCBSP1 (1 << 9)
#define OMAP3430_EN_MCBSP1_SHIFT 9
#define OMAP3430_EN_FSHOSTUSB (1 << 5)
#define OMAP3430_EN_FSHOSTUSB_SHIFT 5
#define OMAP3430_EN_D2D (1 << 3)
#define OMAP3430_EN_D2D_SHIFT 3
/* CM_ICLKEN1_CORE, PM_WKEN1_CORE shared bits */
#define OMAP3430_EN_HSOTGUSB (1 << 4)
#define OMAP3430_EN_HSOTGUSB_SHIFT 4
/* PM_WKST1_CORE, CM_IDLEST1_CORE shared bits */
#define OMAP3430_ST_MMC2 (1 << 25)
......@@ -201,14 +219,19 @@
/* CM_FCLKEN_WKUP, CM_ICLKEN_WKUP, PM_WKEN_WKUP shared bits */
#define OMAP3430_EN_GPIO1 (1 << 3)
#define OMAP3430_EN_GPIO1_SHIFT 3
#define OMAP3430_EN_GPT1 (1 << 0)
#define OMAP3430_EN_GPT1_SHIFT 0
/* CM_FCLKEN_WKUP, PM_WKEN_WKUP shared bits */
#define OMAP3430_EN_SR2 (1 << 7)
#define OMAP3430_EN_SR2_SHIFT 7
#define OMAP3430_EN_SR1 (1 << 6)
#define OMAP3430_EN_SR1_SHIFT 6
/* CM_ICLKEN_WKUP, PM_WKEN_WKUP shared bits */
#define OMAP3430_EN_GPT12 (1 << 1)
#define OMAP3430_EN_GPT12_SHIFT 1
/* CM_IDLEST_WKUP, PM_WKST_WKUP shared bits */
#define OMAP3430_ST_SR2 (1 << 7)
......@@ -223,29 +246,47 @@
* PM_WKDEP_DSS, PM_WKDEP_CAM, PM_WKDEP_PER, PM_WKDEP_NEON shared bits
*/
#define OMAP3430_EN_MPU (1 << 1)
#define OMAP3430_EN_MPU_SHIFT 1
/* CM_FCLKEN_PER, CM_ICLKEN_PER, PM_WKEN_PER shared bits */
#define OMAP3430_EN_GPIO6 (1 << 17)
#define OMAP3430_EN_GPIO6_SHIFT 17
#define OMAP3430_EN_GPIO5 (1 << 16)
#define OMAP3430_EN_GPIO5_SHIFT 16
#define OMAP3430_EN_GPIO4 (1 << 15)
#define OMAP3430_EN_GPIO4_SHIFT 15
#define OMAP3430_EN_GPIO3 (1 << 14)
#define OMAP3430_EN_GPIO3_SHIFT 14
#define OMAP3430_EN_GPIO2 (1 << 13)
#define OMAP3430_EN_GPIO2_SHIFT 13
#define OMAP3430_EN_UART3 (1 << 11)
#define OMAP3430_EN_UART3_SHIFT 11
#define OMAP3430_EN_GPT9 (1 << 10)
#define OMAP3430_EN_GPT9_SHIFT 10
#define OMAP3430_EN_GPT8 (1 << 9)
#define OMAP3430_EN_GPT8_SHIFT 9
#define OMAP3430_EN_GPT7 (1 << 8)
#define OMAP3430_EN_GPT7_SHIFT 8
#define OMAP3430_EN_GPT6 (1 << 7)
#define OMAP3430_EN_GPT6_SHIFT 7
#define OMAP3430_EN_GPT5 (1 << 6)
#define OMAP3430_EN_GPT5_SHIFT 6
#define OMAP3430_EN_GPT4 (1 << 5)
#define OMAP3430_EN_GPT4_SHIFT 5
#define OMAP3430_EN_GPT3 (1 << 4)
#define OMAP3430_EN_GPT3_SHIFT 4
#define OMAP3430_EN_GPT2 (1 << 3)
#define OMAP3430_EN_GPT2_SHIFT 3
/* CM_FCLKEN_PER, CM_ICLKEN_PER, PM_WKEN_PER, PM_WKST_PER shared bits */
/* XXX Possible TI documentation bug: should the PM_WKST_PER EN_* bits
* be ST_* bits instead? */
#define OMAP3430_EN_MCBSP4 (1 << 2)
#define OMAP3430_EN_MCBSP4_SHIFT 2
#define OMAP3430_EN_MCBSP3 (1 << 1)
#define OMAP3430_EN_MCBSP3_SHIFT 1
#define OMAP3430_EN_MCBSP2 (1 << 0)
#define OMAP3430_EN_MCBSP2_SHIFT 0
/* CM_IDLEST_PER, PM_WKST_PER shared bits */
#define OMAP3430_ST_GPIO6 (1 << 17)
......
......@@ -87,6 +87,8 @@
#define OMAP3430_PRM_VP2_VOLTAGE OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00e0)
#define OMAP3430_PRM_VP2_STATUS OMAP_PRM_REGADDR(OMAP3430_GR_MOD, 0x00e4)
#define OMAP3430_PRM_CLKSEL OMAP_PRM_REGADDR(OMAP3430_CCR_MOD, 0x0040)
#define OMAP3430_PRM_CLKOUT_CTRL OMAP_PRM_REGADDR(OMAP3430_CCR_MOD, 0x0070)
/* Power/reset management global register get/set */
......
......@@ -228,9 +228,13 @@
#define OMAP3430_VP1_OPPCHANGEDONE_ST (1 << 10)
#define OMAP3430_IO_ST (1 << 9)
#define OMAP3430_PRM_IRQSTATUS_MPU_IVA2_DPLL_ST (1 << 8)
#define OMAP3430_PRM_IRQSTATUS_MPU_IVA2_DPLL_ST_SHIFT 8
#define OMAP3430_MPU_DPLL_ST (1 << 7)
#define OMAP3430_MPU_DPLL_ST_SHIFT 7
#define OMAP3430_PERIPH_DPLL_ST (1 << 6)
#define OMAP3430_PERIPH_DPLL_ST_SHIFT 6
#define OMAP3430_CORE_DPLL_ST (1 << 5)
#define OMAP3430_CORE_DPLL_ST_SHIFT 5
#define OMAP3430_TRANSITION_ST (1 << 4)
#define OMAP3430_EVGENOFF_ST (1 << 3)
#define OMAP3430_EVGENON_ST (1 << 2)
......@@ -254,9 +258,13 @@
#define OMAP3430_VP1_OPPCHANGEDONE_EN (1 << 10)
#define OMAP3430_IO_EN (1 << 9)
#define OMAP3430_PRM_IRQENABLE_MPU_IVA2_DPLL_RECAL_EN (1 << 8)
#define OMAP3430_PRM_IRQENABLE_MPU_IVA2_DPLL_RECAL_EN_SHIFT 8
#define OMAP3430_MPU_DPLL_RECAL_EN (1 << 7)
#define OMAP3430_MPU_DPLL_RECAL_EN_SHIFT 7
#define OMAP3430_PERIPH_DPLL_RECAL_EN (1 << 6)
#define OMAP3430_PERIPH_DPLL_RECAL_EN_SHIFT 6
#define OMAP3430_CORE_DPLL_RECAL_EN (1 << 5)
#define OMAP3430_CORE_DPLL_RECAL_EN_SHIFT 5
#define OMAP3430_TRANSITION_EN (1 << 4)
#define OMAP3430_EVGENOFF_EN (1 << 3)
#define OMAP3430_EVGENON_EN (1 << 2)
......@@ -365,6 +373,7 @@
/* PRM_CLKOUT_CTRL */
#define OMAP3430_CLKOUT_EN (1 << 7)
#define OMAP3430_CLKOUT_EN_SHIFT 7
/* RM_RSTST_DSS specific bits */
......
......@@ -33,6 +33,15 @@ struct dpll_data {
void __iomem *mult_div1_reg;
u32 mult_mask;
u32 div1_mask;
void __iomem *div2_reg;
u32 div2_mask;
# if defined(CONFIG_ARCH_OMAP3)
void __iomem *control_reg;
u32 enable_mask;
u8 auto_recal_bit;
u8 recal_en_bit;
u8 recal_st_bit;
# endif
};
#endif
......
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