clock.c 6.4 KB
Newer Older
1 2 3
/*
 *  linux/arch/arm/mach-omap2/clock.c
 *
4
 *  Copyright (C) 2005-2008 Texas Instruments, Inc.
5
 *  Copyright (C) 2004-2010 Nokia Corporation
6
 *
7 8
 *  Contacts:
 *  Richard Woodruff <r-woodruff2@ti.com>
9 10 11 12 13 14 15 16 17
 *  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.
 */
#undef DEBUG

#include <linux/kernel.h>
18
#include <linux/export.h>
19 20
#include <linux/list.h>
#include <linux/errno.h>
21 22
#include <linux/err.h>
#include <linux/delay.h>
23
#include <linux/clk-provider.h>
24
#include <linux/io.h>
25
#include <linux/bitops.h>
26
#include <linux/of_address.h>
27
#include <asm/cpu.h>
28 29 30 31 32

#include <trace/events/power.h>

#include "soc.h"
#include "clockdomain.h"
33
#include "clock.h"
34
#include "cm.h"
35 36
#include "cm2xxx.h"
#include "cm3xxx.h"
37 38
#include "cm-regbits-24xx.h"
#include "cm-regbits-34xx.h"
39 40
#include "common.h"

41
u16 cpu_mask;
42

43 44 45 46 47 48 49 50 51 52 53 54 55
/* DPLL valid Fint frequency band limits - from 34xx TRM Section 4.7.6.2 */
#define OMAP3430_DPLL_FINT_BAND1_MIN	750000
#define OMAP3430_DPLL_FINT_BAND1_MAX	2100000
#define OMAP3430_DPLL_FINT_BAND2_MIN	7500000
#define OMAP3430_DPLL_FINT_BAND2_MAX	21000000

/*
 * DPLL valid Fint frequency range for OMAP36xx and OMAP4xxx.
 * From device data manual section 4.3 "DPLL and DLL Specifications".
 */
#define OMAP3PLUS_DPLL_FINT_MIN		32000
#define OMAP3PLUS_DPLL_FINT_MAX		52000000

56
static struct ti_clk_ll_ops omap_clk_ll_ops = {
57 58
	.clkdm_clk_enable = clkdm_clk_enable,
	.clkdm_clk_disable = clkdm_clk_disable,
59 60
	.cm_wait_module_ready = omap_cm_wait_module_ready,
	.cm_split_idlest_reg = cm_split_idlest_reg,
61 62
};

63 64 65 66 67 68 69 70 71 72 73 74 75
/**
 * omap2_clk_setup_ll_ops - setup clock driver low-level ops
 *
 * Sets up clock driver low-level platform ops. These are needed
 * for register accesses and various other misc platform operations.
 * Returns 0 on success, -EBUSY if low level ops have been registered
 * already.
 */
int __init omap2_clk_setup_ll_ops(void)
{
	return ti_clk_setup_ll_ops(&omap_clk_ll_ops);
}

76 77 78
/*
 * OMAP2+ specific clock functions
 */
79

80 81 82 83
/* Private functions */

/* Public functions */

84 85 86 87 88 89 90 91
/**
 * omap2_init_clk_clkdm - look up a clockdomain name, store pointer in clk
 * @clk: OMAP clock struct ptr to use
 *
 * Convert a clockdomain name stored in a struct clk 'clk' into a
 * clockdomain pointer, and save it into the struct clk.  Intended to be
 * called during clk_register().  No return value.
 */
92 93 94
void omap2_init_clk_clkdm(struct clk_hw *hw)
{
	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
95
	struct clockdomain *clkdm;
96
	const char *clk_name;
97 98 99 100

	if (!clk->clkdm_name)
		return;

101
	clk_name = __clk_get_name(hw->clk);
102

103 104 105
	clkdm = clkdm_lookup(clk->clkdm_name);
	if (clkdm) {
		pr_debug("clock: associated clk %s to clkdm %s\n",
106
			 clk_name, clk->clkdm_name);
107 108
		clk->clkdm = clkdm;
	} else {
P
Paul Walmsley 已提交
109
		pr_debug("clock: could not associate clk %s to clkdm %s\n",
110
			 clk_name, clk->clkdm_name);
111 112 113
	}
}

114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
static int __initdata mpurate;

/*
 * By default we use the rate set by the bootloader.
 * You can override this with mpurate= cmdline option.
 */
static int __init omap_clk_setup(char *str)
{
	get_option(&str, &mpurate);

	if (!mpurate)
		return 1;

	if (mpurate < 1000)
		mpurate *= 1000000;

	return 1;
}
__setup("mpurate=", omap_clk_setup);

134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
/**
 * omap2_clk_print_new_rates - print summary of current clock tree rates
 * @hfclkin_ck_name: clk name for the off-chip HF oscillator
 * @core_ck_name: clk name for the on-chip CORE_CLK
 * @mpu_ck_name: clk name for the ARM MPU clock
 *
 * Prints a short message to the console with the HFCLKIN oscillator
 * rate, the rate of the CORE clock, and the rate of the ARM MPU clock.
 * Called by the boot-time MPU rate switching code.   XXX This is intended
 * to be handled by the OPP layer code in the near future and should be
 * removed from the clock code.  No return value.
 */
void __init omap2_clk_print_new_rates(const char *hfclkin_ck_name,
				      const char *core_ck_name,
				      const char *mpu_ck_name)
{
	struct clk *hfclkin_ck, *core_ck, *mpu_ck;
	unsigned long hfclkin_rate;

	mpu_ck = clk_get(NULL, mpu_ck_name);
	if (WARN(IS_ERR(mpu_ck), "clock: failed to get %s.\n", mpu_ck_name))
		return;

	core_ck = clk_get(NULL, core_ck_name);
	if (WARN(IS_ERR(core_ck), "clock: failed to get %s.\n", core_ck_name))
		return;

	hfclkin_ck = clk_get(NULL, hfclkin_ck_name);
	if (WARN(IS_ERR(hfclkin_ck), "Failed to get %s.\n", hfclkin_ck_name))
		return;

	hfclkin_rate = clk_get_rate(hfclkin_ck);

P
Paul Walmsley 已提交
167 168
	pr_info("Switched to new clocking rate (Crystal/Core/MPU): %ld.%01ld/%ld/%ld MHz\n",
		(hfclkin_rate / 1000000), ((hfclkin_rate / 100000) % 10),
169 170 171
		(clk_get_rate(core_ck) / 1000000),
		(clk_get_rate(mpu_ck) / 1000000));
}
172 173 174 175 176 177 178 179

/**
 * ti_clk_init_features - init clock features struct for the SoC
 *
 * Initializes the clock features struct based on the SoC type.
 */
void __init ti_clk_init_features(void)
{
180
	struct ti_clk_features features = { 0 };
181 182
	/* Fint setup for DPLLs */
	if (cpu_is_omap3430()) {
183 184 185 186
		features.fint_min = OMAP3430_DPLL_FINT_BAND1_MIN;
		features.fint_max = OMAP3430_DPLL_FINT_BAND2_MAX;
		features.fint_band1_max = OMAP3430_DPLL_FINT_BAND1_MAX;
		features.fint_band2_min = OMAP3430_DPLL_FINT_BAND2_MIN;
187
	} else {
188 189
		features.fint_min = OMAP3PLUS_DPLL_FINT_MIN;
		features.fint_max = OMAP3PLUS_DPLL_FINT_MAX;
190
	}
191 192 193

	/* Bypass value setup for DPLLs */
	if (cpu_is_omap24xx()) {
194
		features.dpll_bypass_vals |=
195 196 197
			(1 << OMAP2XXX_EN_DPLL_LPBYPASS) |
			(1 << OMAP2XXX_EN_DPLL_FRBYPASS);
	} else if (cpu_is_omap34xx()) {
198
		features.dpll_bypass_vals |=
199 200 201 202
			(1 << OMAP3XXX_EN_DPLL_LPBYPASS) |
			(1 << OMAP3XXX_EN_DPLL_FRBYPASS);
	} else if (soc_is_am33xx() || cpu_is_omap44xx() || soc_is_am43xx() ||
		   soc_is_omap54xx() || soc_is_dra7xx()) {
203
		features.dpll_bypass_vals |=
204 205 206 207
			(1 << OMAP4XXX_EN_DPLL_LPBYPASS) |
			(1 << OMAP4XXX_EN_DPLL_FRBYPASS) |
			(1 << OMAP4XXX_EN_DPLL_MNBYPASS);
	}
208 209 210

	/* Jitter correction only available on OMAP343X */
	if (cpu_is_omap343x())
211
		features.flags |= TI_CLK_DPLL_HAS_FREQSEL;
212 213 214 215 216 217 218

	/* Idlest value for interface clocks.
	 * 24xx uses 0 to indicate not ready, and 1 to indicate ready.
	 * 34xx reverses this, just to keep us on our toes
	 * AM35xx uses both, depending on the module.
	 */
	if (cpu_is_omap24xx())
219
		features.cm_idlest_val = OMAP24XX_CM_IDLEST_VAL;
220
	else if (cpu_is_omap34xx())
221
		features.cm_idlest_val = OMAP34XX_CM_IDLEST_VAL;
222 223 224

	/* On OMAP3430 ES1.0, DPLL4 can't be re-programmed */
	if (omap_rev() == OMAP3430_REV_ES1_0)
225 226 227
		features.flags |= TI_CLK_DPLL4_DENY_REPROGRAM;

	ti_clk_setup_features(&features);
228
}