mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-12-05 11:00:15 +00:00
d0ad8a5cbf
A future patch will implement a clock uclass driver for Tegra. That driver will call into Tegra's existing clock code to simplify the transition; this avoids tieing the clock uclass patches into significant refactoring of the existing custom clock API implementation. Some of the Tegra clock APIs that manipulate peripheral clocks require both the peripheral clock ID and parent clock ID to be passed in together. However, the clock uclass API does not require any such "parent" parameter, so the clock driver must determine this information itself. This patch implements new Tegra- specific clock API clock_get_periph_parent() for this purpose. The new API is implemented in the core Tegra clock code rather than SoC- specific clock code. The implementation uses various SoC-/clock-specific data. That data is only available in SoC-specific clock code. Consequently, two new internal APIs are added that enable the core clock code to retrieve this information from the SoC-specific clock code. Due to the structure of the Tegra clock code, this leads to some unfortunate code duplication. However, this situation predates this patch. Ideally, future work will de-duplicate the Tegra clock code, and migrate it into drivers/clk/tegra. However, such refactoring is kept separate from this series. Signed-off-by: Stephen Warren <swarren@nvidia.com> Signed-off-by: Tom Warren <twarren@nvidia.com>
1282 lines
35 KiB
C
1282 lines
35 KiB
C
/*
|
|
* (C) Copyright 2013-2015
|
|
* NVIDIA Corporation <www.nvidia.com>
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0+
|
|
*/
|
|
|
|
/* Tegra210 Clock control functions */
|
|
|
|
#include <common.h>
|
|
#include <errno.h>
|
|
#include <asm/io.h>
|
|
#include <asm/arch/clock.h>
|
|
#include <asm/arch/sysctr.h>
|
|
#include <asm/arch/tegra.h>
|
|
#include <asm/arch-tegra/clk_rst.h>
|
|
#include <asm/arch-tegra/timer.h>
|
|
#include <div64.h>
|
|
#include <fdtdec.h>
|
|
|
|
/*
|
|
* Clock types that we can use as a source. The Tegra210 has muxes for the
|
|
* peripheral clocks, and in most cases there are four options for the clock
|
|
* source. This gives us a clock 'type' and exploits what commonality exists
|
|
* in the device.
|
|
*
|
|
* Letters are obvious, except for T which means CLK_M, and S which means the
|
|
* clock derived from 32KHz. Beware that CLK_M (also called OSC in the
|
|
* datasheet) and PLL_M are different things. The former is the basic
|
|
* clock supplied to the SOC from an external oscillator. The latter is the
|
|
* memory clock PLL.
|
|
*
|
|
* See definitions in clock_id in the header file.
|
|
*/
|
|
enum clock_type_id {
|
|
CLOCK_TYPE_AXPT, /* PLL_A, PLL_X, PLL_P, CLK_M */
|
|
CLOCK_TYPE_MCPA, /* and so on */
|
|
CLOCK_TYPE_MCPT,
|
|
CLOCK_TYPE_PCM,
|
|
CLOCK_TYPE_PCMT,
|
|
CLOCK_TYPE_PDCT,
|
|
CLOCK_TYPE_ACPT,
|
|
CLOCK_TYPE_ASPTE,
|
|
CLOCK_TYPE_PMDACD2T,
|
|
CLOCK_TYPE_PCST,
|
|
CLOCK_TYPE_DP,
|
|
|
|
CLOCK_TYPE_PC2CC3M,
|
|
CLOCK_TYPE_PC2CC3S_T,
|
|
CLOCK_TYPE_PC2CC3M_T,
|
|
CLOCK_TYPE_PC2CC3M_T16, /* PC2CC3M_T, but w/16-bit divisor (I2C) */
|
|
CLOCK_TYPE_MC2CC3P_A,
|
|
CLOCK_TYPE_M,
|
|
CLOCK_TYPE_MCPTM2C2C3,
|
|
CLOCK_TYPE_PC2CC3T_S,
|
|
CLOCK_TYPE_AC2CC3P_TS2,
|
|
CLOCK_TYPE_PC01C00_C42C41TC40,
|
|
|
|
CLOCK_TYPE_COUNT,
|
|
CLOCK_TYPE_NONE = -1, /* invalid clock type */
|
|
};
|
|
|
|
enum {
|
|
CLOCK_MAX_MUX = 8 /* number of source options for each clock */
|
|
};
|
|
|
|
/*
|
|
* Clock source mux for each clock type. This just converts our enum into
|
|
* a list of mux sources for use by the code.
|
|
*
|
|
* Note:
|
|
* The extra column in each clock source array is used to store the mask
|
|
* bits in its register for the source.
|
|
*/
|
|
#define CLK(x) CLOCK_ID_ ## x
|
|
static enum clock_id clock_source[CLOCK_TYPE_COUNT][CLOCK_MAX_MUX+1] = {
|
|
{ CLK(AUDIO), CLK(XCPU), CLK(PERIPH), CLK(OSC),
|
|
CLK(NONE), CLK(NONE), CLK(NONE), CLK(NONE),
|
|
MASK_BITS_31_30},
|
|
{ CLK(MEMORY), CLK(CGENERAL), CLK(PERIPH), CLK(AUDIO),
|
|
CLK(NONE), CLK(NONE), CLK(NONE), CLK(NONE),
|
|
MASK_BITS_31_30},
|
|
{ CLK(MEMORY), CLK(CGENERAL), CLK(PERIPH), CLK(OSC),
|
|
CLK(NONE), CLK(NONE), CLK(NONE), CLK(NONE),
|
|
MASK_BITS_31_30},
|
|
{ CLK(PERIPH), CLK(CGENERAL), CLK(MEMORY), CLK(NONE),
|
|
CLK(NONE), CLK(NONE), CLK(NONE), CLK(NONE),
|
|
MASK_BITS_31_30},
|
|
{ CLK(PERIPH), CLK(CGENERAL), CLK(MEMORY), CLK(OSC),
|
|
CLK(NONE), CLK(NONE), CLK(NONE), CLK(NONE),
|
|
MASK_BITS_31_30},
|
|
{ CLK(PERIPH), CLK(DISPLAY), CLK(CGENERAL), CLK(OSC),
|
|
CLK(NONE), CLK(NONE), CLK(NONE), CLK(NONE),
|
|
MASK_BITS_31_30},
|
|
{ CLK(AUDIO), CLK(CGENERAL), CLK(PERIPH), CLK(OSC),
|
|
CLK(NONE), CLK(NONE), CLK(NONE), CLK(NONE),
|
|
MASK_BITS_31_30},
|
|
{ CLK(AUDIO), CLK(SFROM32KHZ), CLK(PERIPH), CLK(OSC),
|
|
CLK(EPCI), CLK(NONE), CLK(NONE), CLK(NONE),
|
|
MASK_BITS_31_29},
|
|
{ CLK(PERIPH), CLK(MEMORY), CLK(DISPLAY), CLK(AUDIO),
|
|
CLK(CGENERAL), CLK(DISPLAY2), CLK(OSC), CLK(NONE),
|
|
MASK_BITS_31_29},
|
|
{ CLK(PERIPH), CLK(CGENERAL), CLK(SFROM32KHZ), CLK(OSC),
|
|
CLK(NONE), CLK(NONE), CLK(NONE), CLK(NONE),
|
|
MASK_BITS_31_28},
|
|
/* CLOCK_TYPE_DP */
|
|
{ CLK(NONE), CLK(NONE), CLK(NONE), CLK(NONE),
|
|
CLK(NONE), CLK(NONE), CLK(NONE), CLK(NONE),
|
|
MASK_BITS_31_28},
|
|
|
|
/* Additional clock types on Tegra114+ */
|
|
/* CLOCK_TYPE_PC2CC3M */
|
|
{ CLK(PERIPH), CLK(CGENERAL2), CLK(CGENERAL), CLK(CGENERAL3),
|
|
CLK(MEMORY), CLK(NONE), CLK(NONE), CLK(NONE),
|
|
MASK_BITS_31_29},
|
|
/* CLOCK_TYPE_PC2CC3S_T */
|
|
{ CLK(PERIPH), CLK(CGENERAL2), CLK(CGENERAL), CLK(CGENERAL3),
|
|
CLK(SFROM32KHZ), CLK(NONE), CLK(OSC), CLK(NONE),
|
|
MASK_BITS_31_29},
|
|
/* CLOCK_TYPE_PC2CC3M_T */
|
|
{ CLK(PERIPH), CLK(CGENERAL2), CLK(CGENERAL), CLK(CGENERAL3),
|
|
CLK(MEMORY), CLK(NONE), CLK(OSC), CLK(NONE),
|
|
MASK_BITS_31_29},
|
|
/* CLOCK_TYPE_PC2CC3M_T, w/16-bit divisor (I2C) */
|
|
{ CLK(PERIPH), CLK(CGENERAL2), CLK(CGENERAL), CLK(CGENERAL3),
|
|
CLK(MEMORY), CLK(NONE), CLK(OSC), CLK(NONE),
|
|
MASK_BITS_31_29},
|
|
/* CLOCK_TYPE_MC2CC3P_A */
|
|
{ CLK(MEMORY), CLK(CGENERAL2), CLK(CGENERAL), CLK(CGENERAL3),
|
|
CLK(PERIPH), CLK(NONE), CLK(AUDIO), CLK(NONE),
|
|
MASK_BITS_31_29},
|
|
/* CLOCK_TYPE_M */
|
|
{ CLK(MEMORY), CLK(NONE), CLK(NONE), CLK(NONE),
|
|
CLK(NONE), CLK(NONE), CLK(NONE), CLK(NONE),
|
|
MASK_BITS_31_30},
|
|
/* CLOCK_TYPE_MCPTM2C2C3 */
|
|
{ CLK(MEMORY), CLK(CGENERAL), CLK(PERIPH), CLK(OSC),
|
|
CLK(MEMORY2), CLK(CGENERAL2), CLK(CGENERAL3), CLK(NONE),
|
|
MASK_BITS_31_29},
|
|
/* CLOCK_TYPE_PC2CC3T_S */
|
|
{ CLK(PERIPH), CLK(CGENERAL2), CLK(CGENERAL), CLK(CGENERAL3),
|
|
CLK(OSC), CLK(NONE), CLK(SFROM32KHZ), CLK(NONE),
|
|
MASK_BITS_31_29},
|
|
/* CLOCK_TYPE_AC2CC3P_TS2 */
|
|
{ CLK(AUDIO), CLK(CGENERAL2), CLK(CGENERAL), CLK(CGENERAL3),
|
|
CLK(PERIPH), CLK(NONE), CLK(OSC), CLK(SRC2),
|
|
MASK_BITS_31_29},
|
|
/* CLOCK_TYPE_PC01C00_C42C41TC40 */
|
|
{ CLK(PERIPH), CLK(CGENERAL_1), CLK(CGENERAL_0), CLK(NONE),
|
|
CLK(CGENERAL4_2), CLK(CGENERAL4_1), CLK(OSC), CLK(CGENERAL4_0),
|
|
MASK_BITS_31_29},
|
|
};
|
|
|
|
/*
|
|
* Clock type for each peripheral clock source. We put the name in each
|
|
* record just so it is easy to match things up
|
|
*/
|
|
#define TYPE(name, type) type
|
|
static enum clock_type_id clock_periph_type[PERIPHC_COUNT] = {
|
|
/* 0x00 */
|
|
TYPE(PERIPHC_I2S2, CLOCK_TYPE_AXPT),
|
|
TYPE(PERIPHC_I2S3, CLOCK_TYPE_AXPT),
|
|
TYPE(PERIPHC_SPDIF_OUT, CLOCK_TYPE_AXPT),
|
|
TYPE(PERIPHC_SPDIF_IN, CLOCK_TYPE_PC2CC3M),
|
|
TYPE(PERIPHC_PWM, CLOCK_TYPE_PC2CC3S_T),
|
|
TYPE(PERIPHC_05h, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_SBC2, CLOCK_TYPE_PC2CC3M_T),
|
|
TYPE(PERIPHC_SBC3, CLOCK_TYPE_PC2CC3M_T),
|
|
|
|
/* 0x08 */
|
|
TYPE(PERIPHC_08h, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_I2C1, CLOCK_TYPE_PC2CC3M_T16),
|
|
TYPE(PERIPHC_I2C5, CLOCK_TYPE_PC2CC3M_T16),
|
|
TYPE(PERIPHC_0bh, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_0ch, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_SBC1, CLOCK_TYPE_PC2CC3M_T),
|
|
TYPE(PERIPHC_DISP1, CLOCK_TYPE_PMDACD2T),
|
|
TYPE(PERIPHC_DISP2, CLOCK_TYPE_PMDACD2T),
|
|
|
|
/* 0x10 */
|
|
TYPE(PERIPHC_10h, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_11h, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_VI, CLOCK_TYPE_MC2CC3P_A),
|
|
TYPE(PERIPHC_13h, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_SDMMC1, CLOCK_TYPE_PC2CC3M_T),
|
|
TYPE(PERIPHC_SDMMC2, CLOCK_TYPE_PC2CC3M_T),
|
|
TYPE(PERIPHC_16h, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_17h, CLOCK_TYPE_NONE),
|
|
|
|
/* 0x18 */
|
|
TYPE(PERIPHC_18h, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_SDMMC4, CLOCK_TYPE_PC2CC3M_T),
|
|
TYPE(PERIPHC_VFIR, CLOCK_TYPE_PC2CC3M_T),
|
|
TYPE(PERIPHC_1Bh, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_1Ch, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_HSI, CLOCK_TYPE_PC2CC3M_T),
|
|
TYPE(PERIPHC_UART1, CLOCK_TYPE_PC2CC3M_T),
|
|
TYPE(PERIPHC_UART2, CLOCK_TYPE_PC2CC3M_T),
|
|
|
|
/* 0x20 */
|
|
TYPE(PERIPHC_HOST1X, CLOCK_TYPE_MC2CC3P_A),
|
|
TYPE(PERIPHC_21h, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_22h, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_23h, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_24h, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_25h, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_I2C2, CLOCK_TYPE_PC2CC3M_T16),
|
|
TYPE(PERIPHC_EMC, CLOCK_TYPE_MCPTM2C2C3),
|
|
|
|
/* 0x28 */
|
|
TYPE(PERIPHC_UART3, CLOCK_TYPE_PC2CC3M_T),
|
|
TYPE(PERIPHC_29h, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_VI_SENSOR, CLOCK_TYPE_MC2CC3P_A),
|
|
TYPE(PERIPHC_2bh, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_2ch, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_SBC4, CLOCK_TYPE_PC2CC3M_T),
|
|
TYPE(PERIPHC_I2C3, CLOCK_TYPE_PC2CC3M_T16),
|
|
TYPE(PERIPHC_SDMMC3, CLOCK_TYPE_PC2CC3M_T),
|
|
|
|
/* 0x30 */
|
|
TYPE(PERIPHC_UART4, CLOCK_TYPE_PC2CC3M_T),
|
|
TYPE(PERIPHC_UART5, CLOCK_TYPE_PC2CC3M_T),
|
|
TYPE(PERIPHC_VDE, CLOCK_TYPE_PC2CC3M_T),
|
|
TYPE(PERIPHC_OWR, CLOCK_TYPE_PC2CC3M_T),
|
|
TYPE(PERIPHC_NOR, CLOCK_TYPE_PC2CC3M_T),
|
|
TYPE(PERIPHC_CSITE, CLOCK_TYPE_PC2CC3M_T),
|
|
TYPE(PERIPHC_I2S1, CLOCK_TYPE_AXPT),
|
|
TYPE(PERIPHC_DTV, CLOCK_TYPE_NONE),
|
|
|
|
/* 0x38 */
|
|
TYPE(PERIPHC_38h, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_39h, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_3ah, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_3bh, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_MSENC, CLOCK_TYPE_MC2CC3P_A),
|
|
TYPE(PERIPHC_TSEC, CLOCK_TYPE_PC2CC3M_T),
|
|
TYPE(PERIPHC_3eh, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_OSC, CLOCK_TYPE_NONE),
|
|
|
|
/* 0x40 */
|
|
TYPE(PERIPHC_40h, CLOCK_TYPE_NONE), /* start with 0x3b0 */
|
|
TYPE(PERIPHC_MSELECT, CLOCK_TYPE_PC2CC3M_T),
|
|
TYPE(PERIPHC_TSENSOR, CLOCK_TYPE_PC2CC3T_S),
|
|
TYPE(PERIPHC_I2S4, CLOCK_TYPE_AXPT),
|
|
TYPE(PERIPHC_I2S5, CLOCK_TYPE_AXPT),
|
|
TYPE(PERIPHC_I2C4, CLOCK_TYPE_PC2CC3M_T16),
|
|
TYPE(PERIPHC_SBC5, CLOCK_TYPE_PC2CC3M_T),
|
|
TYPE(PERIPHC_SBC6, CLOCK_TYPE_PC2CC3M_T),
|
|
|
|
/* 0x48 */
|
|
TYPE(PERIPHC_AUDIO, CLOCK_TYPE_AC2CC3P_TS2),
|
|
TYPE(PERIPHC_49h, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_4ah, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_4bh, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_4ch, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_HDA2CODEC2X, CLOCK_TYPE_PC2CC3M_T),
|
|
TYPE(PERIPHC_ACTMON, CLOCK_TYPE_PC2CC3S_T),
|
|
TYPE(PERIPHC_EXTPERIPH1, CLOCK_TYPE_ASPTE),
|
|
|
|
/* 0x50 */
|
|
TYPE(PERIPHC_EXTPERIPH2, CLOCK_TYPE_ASPTE),
|
|
TYPE(PERIPHC_EXTPERIPH3, CLOCK_TYPE_ASPTE),
|
|
TYPE(PERIPHC_52h, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_I2CSLOW, CLOCK_TYPE_PC2CC3S_T),
|
|
TYPE(PERIPHC_SYS, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_55h, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_56h, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_57h, CLOCK_TYPE_NONE),
|
|
|
|
/* 0x58 */
|
|
TYPE(PERIPHC_58h, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_59h, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_5ah, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_5bh, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_SATAOOB, CLOCK_TYPE_PCMT),
|
|
TYPE(PERIPHC_SATA, CLOCK_TYPE_PCMT),
|
|
TYPE(PERIPHC_HDA, CLOCK_TYPE_PC2CC3M_T),
|
|
TYPE(PERIPHC_5fh, CLOCK_TYPE_NONE),
|
|
|
|
/* 0x60 */
|
|
TYPE(PERIPHC_XUSB_CORE_HOST, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_XUSB_FALCON, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_XUSB_FS, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_XUSB_CORE_DEV, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_XUSB_SS, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_CILAB, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_CILCD, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_CILE, CLOCK_TYPE_NONE),
|
|
|
|
/* 0x68 */
|
|
TYPE(PERIPHC_DSIA_LP, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_DSIB_LP, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_ENTROPY, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_DVFS_REF, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_DVFS_SOC, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_TRACECLKIN, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_6eh, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_6fh, CLOCK_TYPE_NONE),
|
|
|
|
/* 0x70 */
|
|
TYPE(PERIPHC_EMC_LATENCY, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_SOC_THERM, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_72h, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_73h, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_74h, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_75h, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_VI_SENSOR2, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_I2C6, CLOCK_TYPE_PC2CC3M_T16),
|
|
|
|
/* 0x78 */
|
|
TYPE(PERIPHC_78h, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_EMC_DLL, CLOCK_TYPE_MCPTM2C2C3),
|
|
TYPE(PERIPHC_7ah, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_CLK72MHZ, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_7ch, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_7dh, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_VIC, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_7Fh, CLOCK_TYPE_NONE),
|
|
|
|
/* 0x80 */
|
|
TYPE(PERIPHC_SDMMC_LEGACY_TM, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_NVDEC, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_NVJPG, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_NVENC, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_84h, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_85h, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_86h, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_87h, CLOCK_TYPE_NONE),
|
|
|
|
/* 0x88 */
|
|
TYPE(PERIPHC_88h, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_89h, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_DMIC3, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_APE, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_QSPI, CLOCK_TYPE_PC01C00_C42C41TC40),
|
|
TYPE(PERIPHC_VI_I2C, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_USB2_HSIC_TRK, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_PEX_SATA_USB_RX_BYP, CLOCK_TYPE_NONE),
|
|
|
|
/* 0x90 */
|
|
TYPE(PERIPHC_MAUD, CLOCK_TYPE_NONE),
|
|
TYPE(PERIPHC_TSECB, CLOCK_TYPE_NONE),
|
|
};
|
|
|
|
/*
|
|
* This array translates a periph_id to a periphc_internal_id
|
|
*
|
|
* Not present/matched up:
|
|
* uint vi_sensor; _VI_SENSOR_0, 0x1A8
|
|
* SPDIF - which is both 0x08 and 0x0c
|
|
*
|
|
*/
|
|
#define NONE(name) (-1)
|
|
#define OFFSET(name, value) PERIPHC_ ## name
|
|
#define INTERNAL_ID(id) (id & 0x000000ff)
|
|
static s8 periph_id_to_internal_id[PERIPH_ID_COUNT] = {
|
|
/* Low word: 31:0 */
|
|
NONE(CPU),
|
|
NONE(COP),
|
|
NONE(TRIGSYS),
|
|
NONE(ISPB),
|
|
NONE(RESERVED4),
|
|
NONE(TMR),
|
|
PERIPHC_UART1,
|
|
PERIPHC_UART2, /* and vfir 0x68 */
|
|
|
|
/* 8 */
|
|
NONE(GPIO),
|
|
PERIPHC_SDMMC2,
|
|
PERIPHC_SPDIF_IN,
|
|
PERIPHC_I2S2,
|
|
PERIPHC_I2C1,
|
|
NONE(RESERVED13),
|
|
PERIPHC_SDMMC1,
|
|
PERIPHC_SDMMC4,
|
|
|
|
/* 16 */
|
|
NONE(TCW),
|
|
PERIPHC_PWM,
|
|
PERIPHC_I2S3,
|
|
NONE(RESERVED19),
|
|
PERIPHC_VI,
|
|
NONE(RESERVED21),
|
|
NONE(USBD),
|
|
NONE(ISP),
|
|
|
|
/* 24 */
|
|
NONE(RESERVED24),
|
|
NONE(RESERVED25),
|
|
PERIPHC_DISP2,
|
|
PERIPHC_DISP1,
|
|
PERIPHC_HOST1X,
|
|
NONE(VCP),
|
|
PERIPHC_I2S1,
|
|
NONE(CACHE2),
|
|
|
|
/* Middle word: 63:32 */
|
|
NONE(MEM),
|
|
NONE(AHBDMA),
|
|
NONE(APBDMA),
|
|
NONE(RESERVED35),
|
|
NONE(RESERVED36),
|
|
NONE(STAT_MON),
|
|
NONE(RESERVED38),
|
|
NONE(FUSE),
|
|
|
|
/* 40 */
|
|
NONE(KFUSE),
|
|
PERIPHC_SBC1, /* SBCx = SPIx */
|
|
PERIPHC_NOR,
|
|
NONE(RESERVED43),
|
|
PERIPHC_SBC2,
|
|
NONE(XIO),
|
|
PERIPHC_SBC3,
|
|
PERIPHC_I2C5,
|
|
|
|
/* 48 */
|
|
NONE(DSI),
|
|
NONE(RESERVED49),
|
|
PERIPHC_HSI,
|
|
NONE(RESERVED51),
|
|
NONE(CSI),
|
|
NONE(RESERVED53),
|
|
PERIPHC_I2C2,
|
|
PERIPHC_UART3,
|
|
|
|
/* 56 */
|
|
NONE(MIPI_CAL),
|
|
PERIPHC_EMC,
|
|
NONE(USB2),
|
|
NONE(USB3),
|
|
NONE(RESERVED60),
|
|
PERIPHC_VDE,
|
|
NONE(BSEA),
|
|
NONE(BSEV),
|
|
|
|
/* Upper word 95:64 */
|
|
NONE(RESERVED64),
|
|
PERIPHC_UART4,
|
|
PERIPHC_UART5,
|
|
PERIPHC_I2C3,
|
|
PERIPHC_SBC4,
|
|
PERIPHC_SDMMC3,
|
|
NONE(PCIE),
|
|
PERIPHC_OWR,
|
|
|
|
/* 72 */
|
|
NONE(AFI),
|
|
PERIPHC_CSITE,
|
|
NONE(PCIEXCLK),
|
|
NONE(AVPUCQ),
|
|
NONE(LA),
|
|
NONE(TRACECLKIN),
|
|
NONE(SOC_THERM),
|
|
NONE(DTV),
|
|
|
|
/* 80 */
|
|
NONE(RESERVED80),
|
|
PERIPHC_I2CSLOW,
|
|
NONE(DSIB),
|
|
PERIPHC_TSEC,
|
|
NONE(RESERVED84),
|
|
NONE(RESERVED85),
|
|
NONE(RESERVED86),
|
|
NONE(EMUCIF),
|
|
|
|
/* 88 */
|
|
NONE(RESERVED88),
|
|
NONE(XUSB_HOST),
|
|
NONE(RESERVED90),
|
|
PERIPHC_MSENC,
|
|
NONE(RESERVED92),
|
|
NONE(RESERVED93),
|
|
NONE(RESERVED94),
|
|
NONE(XUSB_DEV),
|
|
|
|
/* V word: 31:0 */
|
|
NONE(CPUG),
|
|
NONE(CPULP),
|
|
NONE(V_RESERVED2),
|
|
PERIPHC_MSELECT,
|
|
NONE(V_RESERVED4),
|
|
PERIPHC_I2S4,
|
|
PERIPHC_I2S5,
|
|
PERIPHC_I2C4,
|
|
|
|
/* 104 */
|
|
PERIPHC_SBC5,
|
|
PERIPHC_SBC6,
|
|
PERIPHC_AUDIO,
|
|
NONE(APBIF),
|
|
NONE(V_RESERVED12),
|
|
NONE(V_RESERVED13),
|
|
NONE(V_RESERVED14),
|
|
PERIPHC_HDA2CODEC2X,
|
|
|
|
/* 112 */
|
|
NONE(ATOMICS),
|
|
NONE(V_RESERVED17),
|
|
NONE(V_RESERVED18),
|
|
NONE(V_RESERVED19),
|
|
NONE(V_RESERVED20),
|
|
NONE(V_RESERVED21),
|
|
NONE(V_RESERVED22),
|
|
PERIPHC_ACTMON,
|
|
|
|
/* 120 */
|
|
NONE(EXTPERIPH1),
|
|
NONE(EXTPERIPH2),
|
|
NONE(EXTPERIPH3),
|
|
NONE(OOB),
|
|
PERIPHC_SATA,
|
|
PERIPHC_HDA,
|
|
NONE(TZRAM),
|
|
NONE(SE),
|
|
|
|
/* W word: 31:0 */
|
|
NONE(HDA2HDMICODEC),
|
|
NONE(SATACOLD),
|
|
NONE(W_RESERVED2),
|
|
NONE(W_RESERVED3),
|
|
NONE(W_RESERVED4),
|
|
NONE(W_RESERVED5),
|
|
NONE(W_RESERVED6),
|
|
NONE(W_RESERVED7),
|
|
|
|
/* 136 */
|
|
NONE(CEC),
|
|
NONE(W_RESERVED9),
|
|
NONE(W_RESERVED10),
|
|
NONE(W_RESERVED11),
|
|
NONE(W_RESERVED12),
|
|
NONE(W_RESERVED13),
|
|
NONE(XUSB_PADCTL),
|
|
NONE(W_RESERVED15),
|
|
|
|
/* 144 */
|
|
NONE(W_RESERVED16),
|
|
NONE(W_RESERVED17),
|
|
NONE(W_RESERVED18),
|
|
NONE(W_RESERVED19),
|
|
NONE(W_RESERVED20),
|
|
NONE(ENTROPY),
|
|
NONE(DDS),
|
|
NONE(W_RESERVED23),
|
|
|
|
/* 152 */
|
|
NONE(W_RESERVED24),
|
|
NONE(W_RESERVED25),
|
|
NONE(W_RESERVED26),
|
|
NONE(DVFS),
|
|
NONE(XUSB_SS),
|
|
NONE(W_RESERVED29),
|
|
NONE(W_RESERVED30),
|
|
NONE(W_RESERVED31),
|
|
|
|
/* X word: 31:0 */
|
|
NONE(SPARE),
|
|
NONE(X_RESERVED1),
|
|
NONE(X_RESERVED2),
|
|
NONE(X_RESERVED3),
|
|
NONE(CAM_MCLK),
|
|
NONE(CAM_MCLK2),
|
|
PERIPHC_I2C6,
|
|
NONE(X_RESERVED7),
|
|
|
|
/* 168 */
|
|
NONE(X_RESERVED8),
|
|
NONE(X_RESERVED9),
|
|
NONE(X_RESERVED10),
|
|
NONE(VIM2_CLK),
|
|
NONE(X_RESERVED12),
|
|
NONE(X_RESERVED13),
|
|
NONE(EMC_DLL),
|
|
NONE(X_RESERVED15),
|
|
|
|
/* 176 */
|
|
NONE(X_RESERVED16),
|
|
NONE(CLK72MHZ),
|
|
NONE(VIC),
|
|
NONE(X_RESERVED19),
|
|
NONE(X_RESERVED20),
|
|
NONE(DPAUX),
|
|
NONE(SOR0),
|
|
NONE(X_RESERVED23),
|
|
|
|
/* 184 */
|
|
NONE(GPU),
|
|
NONE(X_RESERVED25),
|
|
NONE(X_RESERVED26),
|
|
NONE(X_RESERVED27),
|
|
NONE(X_RESERVED28),
|
|
NONE(X_RESERVED29),
|
|
NONE(X_RESERVED30),
|
|
NONE(X_RESERVED31),
|
|
|
|
/* Y: 192 (192 - 223) */
|
|
NONE(Y_RESERVED0),
|
|
PERIPHC_SDMMC_LEGACY_TM,
|
|
PERIPHC_NVDEC,
|
|
PERIPHC_NVJPG,
|
|
NONE(Y_RESERVED4),
|
|
PERIPHC_DMIC3, /* 197 */
|
|
PERIPHC_APE, /* 198 */
|
|
NONE(Y_RESERVED7),
|
|
|
|
/* 200 */
|
|
NONE(Y_RESERVED8),
|
|
NONE(Y_RESERVED9),
|
|
NONE(Y_RESERVED10),
|
|
NONE(Y_RESERVED11),
|
|
NONE(Y_RESERVED12),
|
|
NONE(Y_RESERVED13),
|
|
NONE(Y_RESERVED14),
|
|
NONE(Y_RESERVED15),
|
|
|
|
/* 208 */
|
|
PERIPHC_VI_I2C, /* 208 */
|
|
NONE(Y_RESERVED17),
|
|
NONE(Y_RESERVED18),
|
|
PERIPHC_QSPI, /* 211 */
|
|
NONE(Y_RESERVED20),
|
|
NONE(Y_RESERVED21),
|
|
NONE(Y_RESERVED22),
|
|
NONE(Y_RESERVED23),
|
|
|
|
/* 216 */
|
|
NONE(Y_RESERVED24),
|
|
NONE(Y_RESERVED25),
|
|
NONE(Y_RESERVED26),
|
|
PERIPHC_NVENC, /* 219 */
|
|
NONE(Y_RESERVED28),
|
|
NONE(Y_RESERVED29),
|
|
NONE(Y_RESERVED30),
|
|
NONE(Y_RESERVED31),
|
|
};
|
|
|
|
/*
|
|
* PLL divider shift/mask tables for all PLL IDs.
|
|
*/
|
|
struct clk_pll_info tegra_pll_info_table[CLOCK_ID_PLL_COUNT] = {
|
|
/*
|
|
* NOTE: If kcp_mask/kvco_mask == 0, they're not used in that PLL (PLLC, etc.)
|
|
* If lock_ena or lock_det are >31, they're not used in that PLL (PLLC, etc.)
|
|
*/
|
|
{ .m_shift = 0, .m_mask = 0xFF, .n_shift = 10, .n_mask = 0xFF, .p_shift = 20, .p_mask = 0x1F,
|
|
.lock_ena = 32, .lock_det = 27, .kcp_shift = 0, .kcp_mask = 0, .kvco_shift = 0, .kvco_mask = 0 }, /* PLLC */
|
|
{ .m_shift = 0, .m_mask = 0xFF, .n_shift = 8, .n_mask = 0xFF, .p_shift = 20, .p_mask = 0x1F,
|
|
.lock_ena = 4, .lock_det = 27, .kcp_shift = 1, .kcp_mask = 3, .kvco_shift = 0, .kvco_mask = 1 }, /* PLLM */
|
|
{ .m_shift = 0, .m_mask = 0xFF, .n_shift = 10, .n_mask = 0xFF, .p_shift = 20, .p_mask = 0x1F,
|
|
.lock_ena = 18, .lock_det = 27, .kcp_shift = 0, .kcp_mask = 3, .kvco_shift = 2, .kvco_mask = 1 }, /* PLLP */
|
|
{ .m_shift = 0, .m_mask = 0xFF, .n_shift = 8, .n_mask = 0xFF, .p_shift = 20, .p_mask = 0x1F,
|
|
.lock_ena = 28, .lock_det = 27, .kcp_shift = 25, .kcp_mask = 3, .kvco_shift = 24, .kvco_mask = 1 }, /* PLLA */
|
|
{ .m_shift = 0, .m_mask = 0xFF, .n_shift = 8, .n_mask = 0xFF, .p_shift = 16, .p_mask = 0x1F,
|
|
.lock_ena = 29, .lock_det = 27, .kcp_shift = 25, .kcp_mask = 3, .kvco_shift = 24, .kvco_mask = 1 }, /* PLLU */
|
|
{ .m_shift = 0, .m_mask = 0xFF, .n_shift = 11, .n_mask = 0xFF, .p_shift = 20, .p_mask = 0x07,
|
|
.lock_ena = 18, .lock_det = 27, .kcp_shift = 23, .kcp_mask = 3, .kvco_shift = 22, .kvco_mask = 1 }, /* PLLD */
|
|
{ .m_shift = 0, .m_mask = 0xFF, .n_shift = 8, .n_mask = 0xFF, .p_shift = 20, .p_mask = 0x1F,
|
|
.lock_ena = 18, .lock_det = 27, .kcp_shift = 1, .kcp_mask = 3, .kvco_shift = 0, .kvco_mask = 1 }, /* PLLX */
|
|
{ .m_shift = 0, .m_mask = 0xFF, .n_shift = 8, .n_mask = 0xFF, .p_shift = 0, .p_mask = 0,
|
|
.lock_ena = 9, .lock_det = 11, .kcp_shift = 6, .kcp_mask = 3, .kvco_shift = 0, .kvco_mask = 1 }, /* PLLE */
|
|
{ .m_shift = 0, .m_mask = 0, .n_shift = 0, .n_mask = 0, .p_shift = 0, .p_mask = 0,
|
|
.lock_ena = 0, .lock_det = 0, .kcp_shift = 0, .kcp_mask = 0, .kvco_shift = 0, .kvco_mask = 0 }, /* PLLS (gone)*/
|
|
{ .m_shift = 0, .m_mask = 0xFF, .n_shift = 8, .n_mask = 0xFF, .p_shift = 19, .p_mask = 0x1F,
|
|
.lock_ena = 30, .lock_det = 27, .kcp_shift = 25, .kcp_mask = 3, .kvco_shift = 24, .kvco_mask = 1 }, /* PLLDP */
|
|
};
|
|
|
|
/*
|
|
* Get the oscillator frequency, from the corresponding hardware configuration
|
|
* field. Note that Tegra30+ support 3 new higher freqs, but we map back
|
|
* to the old T20 freqs. Support for the higher oscillators is TBD.
|
|
*/
|
|
enum clock_osc_freq clock_get_osc_freq(void)
|
|
{
|
|
struct clk_rst_ctlr *clkrst =
|
|
(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
|
|
u32 reg;
|
|
|
|
reg = readl(&clkrst->crc_osc_ctrl);
|
|
reg = (reg & OSC_FREQ_MASK) >> OSC_FREQ_SHIFT;
|
|
/*
|
|
* 0 = 13MHz, 1 = 16.8MHz, 4 = 19.2MHz, 5 = 38.4MHz,
|
|
* 8 = 12MHz, 9 = 48MHz, 12 = 26MHz
|
|
*/
|
|
if (reg == 5) {
|
|
debug("OSC_FREQ is 38.4MHz (%d) ...\n", reg);
|
|
/* Map it to the 5th CLOCK_OSC_ enum, i.e. 4 */
|
|
return 4;
|
|
}
|
|
|
|
/*
|
|
* Map to most common (T20) freqs (except 38.4, handled above):
|
|
* 13/16.8 = 0, 19.2 = 1, 12/48 = 2, 26 = 3
|
|
*/
|
|
return reg >> 2;
|
|
}
|
|
|
|
/* Returns a pointer to the clock source register for a peripheral */
|
|
u32 *get_periph_source_reg(enum periph_id periph_id)
|
|
{
|
|
struct clk_rst_ctlr *clkrst =
|
|
(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
|
|
enum periphc_internal_id internal_id;
|
|
|
|
/* Coresight is a special case */
|
|
if (periph_id == PERIPH_ID_CSI)
|
|
return &clkrst->crc_clk_src[PERIPH_ID_CSI+1];
|
|
|
|
assert(periph_id >= PERIPH_ID_FIRST && periph_id < PERIPH_ID_COUNT);
|
|
internal_id = INTERNAL_ID(periph_id_to_internal_id[periph_id]);
|
|
assert(internal_id != -1);
|
|
|
|
if (internal_id < PERIPHC_VW_FIRST)
|
|
/* L, H, U */
|
|
return &clkrst->crc_clk_src[internal_id];
|
|
|
|
if (internal_id < PERIPHC_X_FIRST) {
|
|
/* VW */
|
|
internal_id -= PERIPHC_VW_FIRST;
|
|
return &clkrst->crc_clk_src_vw[internal_id];
|
|
}
|
|
|
|
if (internal_id < PERIPHC_Y_FIRST) {
|
|
/* X */
|
|
internal_id -= PERIPHC_X_FIRST;
|
|
return &clkrst->crc_clk_src_x[internal_id];
|
|
}
|
|
|
|
/* Y */
|
|
internal_id -= PERIPHC_Y_FIRST;
|
|
return &clkrst->crc_clk_src_y[internal_id];
|
|
}
|
|
|
|
int get_periph_clock_info(enum periph_id periph_id, int *mux_bits,
|
|
int *divider_bits, int *type)
|
|
{
|
|
enum periphc_internal_id internal_id;
|
|
|
|
if (!clock_periph_id_isvalid(periph_id))
|
|
return -1;
|
|
|
|
internal_id = periph_id_to_internal_id[periph_id];
|
|
if (!periphc_internal_id_isvalid(internal_id))
|
|
return -1;
|
|
|
|
*type = clock_periph_type[internal_id];
|
|
if (!clock_type_id_isvalid(*type))
|
|
return -1;
|
|
|
|
*mux_bits = clock_source[*type][CLOCK_MAX_MUX];
|
|
|
|
if (*type == CLOCK_TYPE_PC2CC3M_T16)
|
|
*divider_bits = 16;
|
|
else
|
|
*divider_bits = 8;
|
|
|
|
return 0;
|
|
}
|
|
|
|
enum clock_id get_periph_clock_id(enum periph_id periph_id, int source)
|
|
{
|
|
enum periphc_internal_id internal_id;
|
|
int type;
|
|
|
|
if (!clock_periph_id_isvalid(periph_id))
|
|
return CLOCK_ID_NONE;
|
|
|
|
internal_id = periph_id_to_internal_id[periph_id];
|
|
if (!periphc_internal_id_isvalid(internal_id))
|
|
return CLOCK_ID_NONE;
|
|
|
|
type = clock_periph_type[internal_id];
|
|
if (!clock_type_id_isvalid(type))
|
|
return CLOCK_ID_NONE;
|
|
|
|
return clock_source[type][source];
|
|
}
|
|
|
|
/**
|
|
* Given a peripheral ID and the required source clock, this returns which
|
|
* value should be programmed into the source mux for that peripheral.
|
|
*
|
|
* There is special code here to handle the one source type with 5 sources.
|
|
*
|
|
* @param periph_id peripheral to start
|
|
* @param source PLL id of required parent clock
|
|
* @param mux_bits Set to number of bits in mux register: 2 or 4
|
|
* @param divider_bits Set to number of divider bits (8 or 16)
|
|
* @return mux value (0-4, or -1 if not found)
|
|
*/
|
|
int get_periph_clock_source(enum periph_id periph_id,
|
|
enum clock_id parent, int *mux_bits, int *divider_bits)
|
|
{
|
|
enum clock_type_id type;
|
|
int mux, err;
|
|
|
|
err = get_periph_clock_info(periph_id, mux_bits, divider_bits, &type);
|
|
assert(!err);
|
|
|
|
for (mux = 0; mux < CLOCK_MAX_MUX; mux++)
|
|
if (clock_source[type][mux] == parent)
|
|
return mux;
|
|
|
|
/* if we get here, either us or the caller has made a mistake */
|
|
printf("Caller requested bad clock: periph=%d, parent=%d\n", periph_id,
|
|
parent);
|
|
return -1;
|
|
}
|
|
|
|
void clock_set_enable(enum periph_id periph_id, int enable)
|
|
{
|
|
struct clk_rst_ctlr *clkrst =
|
|
(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
|
|
u32 *clk;
|
|
u32 reg;
|
|
|
|
/* Enable/disable the clock to this peripheral */
|
|
assert(clock_periph_id_isvalid(periph_id));
|
|
if ((int)periph_id < (int)PERIPH_ID_VW_FIRST)
|
|
clk = &clkrst->crc_clk_out_enb[PERIPH_REG(periph_id)];
|
|
else if ((int)periph_id < (int)PERIPH_ID_X_FIRST)
|
|
clk = &clkrst->crc_clk_out_enb_vw[PERIPH_REG(periph_id)];
|
|
else if ((int)periph_id < (int)PERIPH_ID_Y_FIRST)
|
|
clk = &clkrst->crc_clk_out_enb_x;
|
|
else
|
|
clk = &clkrst->crc_clk_out_enb_y;
|
|
|
|
reg = readl(clk);
|
|
if (enable)
|
|
reg |= PERIPH_MASK(periph_id);
|
|
else
|
|
reg &= ~PERIPH_MASK(periph_id);
|
|
writel(reg, clk);
|
|
}
|
|
|
|
void reset_set_enable(enum periph_id periph_id, int enable)
|
|
{
|
|
struct clk_rst_ctlr *clkrst =
|
|
(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
|
|
u32 *reset;
|
|
u32 reg;
|
|
|
|
/* Enable/disable reset to the peripheral */
|
|
assert(clock_periph_id_isvalid(periph_id));
|
|
if (periph_id < PERIPH_ID_VW_FIRST)
|
|
reset = &clkrst->crc_rst_dev[PERIPH_REG(periph_id)];
|
|
else if ((int)periph_id < (int)PERIPH_ID_X_FIRST)
|
|
reset = &clkrst->crc_rst_dev_vw[PERIPH_REG(periph_id)];
|
|
else if ((int)periph_id < (int)PERIPH_ID_Y_FIRST)
|
|
reset = &clkrst->crc_rst_devices_x;
|
|
else
|
|
reset = &clkrst->crc_rst_devices_y;
|
|
|
|
reg = readl(reset);
|
|
if (enable)
|
|
reg |= PERIPH_MASK(periph_id);
|
|
else
|
|
reg &= ~PERIPH_MASK(periph_id);
|
|
writel(reg, reset);
|
|
}
|
|
|
|
#ifdef CONFIG_OF_CONTROL
|
|
/*
|
|
* Convert a device tree clock ID to our peripheral ID. They are mostly
|
|
* the same but we are very cautious so we check that a valid clock ID is
|
|
* provided.
|
|
*
|
|
* @param clk_id Clock ID according to tegra210 device tree binding
|
|
* @return peripheral ID, or PERIPH_ID_NONE if the clock ID is invalid
|
|
*/
|
|
enum periph_id clk_id_to_periph_id(int clk_id)
|
|
{
|
|
if (clk_id > PERIPH_ID_COUNT)
|
|
return PERIPH_ID_NONE;
|
|
|
|
switch (clk_id) {
|
|
case PERIPH_ID_RESERVED4:
|
|
case PERIPH_ID_RESERVED25:
|
|
case PERIPH_ID_RESERVED35:
|
|
case PERIPH_ID_RESERVED36:
|
|
case PERIPH_ID_RESERVED38:
|
|
case PERIPH_ID_RESERVED43:
|
|
case PERIPH_ID_RESERVED49:
|
|
case PERIPH_ID_RESERVED53:
|
|
case PERIPH_ID_RESERVED64:
|
|
case PERIPH_ID_RESERVED84:
|
|
case PERIPH_ID_RESERVED85:
|
|
case PERIPH_ID_RESERVED86:
|
|
case PERIPH_ID_RESERVED88:
|
|
case PERIPH_ID_RESERVED90:
|
|
case PERIPH_ID_RESERVED92:
|
|
case PERIPH_ID_RESERVED93:
|
|
case PERIPH_ID_RESERVED94:
|
|
case PERIPH_ID_V_RESERVED2:
|
|
case PERIPH_ID_V_RESERVED4:
|
|
case PERIPH_ID_V_RESERVED17:
|
|
case PERIPH_ID_V_RESERVED18:
|
|
case PERIPH_ID_V_RESERVED19:
|
|
case PERIPH_ID_V_RESERVED20:
|
|
case PERIPH_ID_V_RESERVED21:
|
|
case PERIPH_ID_V_RESERVED22:
|
|
case PERIPH_ID_W_RESERVED2:
|
|
case PERIPH_ID_W_RESERVED3:
|
|
case PERIPH_ID_W_RESERVED4:
|
|
case PERIPH_ID_W_RESERVED5:
|
|
case PERIPH_ID_W_RESERVED6:
|
|
case PERIPH_ID_W_RESERVED7:
|
|
case PERIPH_ID_W_RESERVED9:
|
|
case PERIPH_ID_W_RESERVED10:
|
|
case PERIPH_ID_W_RESERVED11:
|
|
case PERIPH_ID_W_RESERVED12:
|
|
case PERIPH_ID_W_RESERVED13:
|
|
case PERIPH_ID_W_RESERVED15:
|
|
case PERIPH_ID_W_RESERVED16:
|
|
case PERIPH_ID_W_RESERVED17:
|
|
case PERIPH_ID_W_RESERVED18:
|
|
case PERIPH_ID_W_RESERVED19:
|
|
case PERIPH_ID_W_RESERVED20:
|
|
case PERIPH_ID_W_RESERVED23:
|
|
case PERIPH_ID_W_RESERVED29:
|
|
case PERIPH_ID_W_RESERVED30:
|
|
case PERIPH_ID_W_RESERVED31:
|
|
return PERIPH_ID_NONE;
|
|
default:
|
|
return clk_id;
|
|
}
|
|
}
|
|
#endif /* CONFIG_OF_CONTROL */
|
|
|
|
/*
|
|
* T210 redefines PLLP_OUT2 as PLLP_VCO/DIVP, so do different OUT1-4 setup here.
|
|
* PLLP_BASE/MISC/etc. is already set up for 408MHz in the BootROM.
|
|
*/
|
|
void tegra210_setup_pllp(void)
|
|
{
|
|
struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
|
|
u32 reg;
|
|
|
|
/* Set PLLP_OUT1, 3 & 4 freqs to 9.6, 102 & 204MHz */
|
|
|
|
/* OUT1 */
|
|
/* Assert RSTN before enable */
|
|
reg = PLLP_OUT1_RSTN_EN;
|
|
writel(reg, &clkrst->crc_pll[CLOCK_ID_PERIPH].pll_out[0]);
|
|
/* Set divisor and reenable */
|
|
reg = (IN_408_OUT_9_6_DIVISOR << PLLP_OUT1_RATIO)
|
|
| PLLP_OUT1_OVR | PLLP_OUT1_CLKEN | PLLP_OUT1_RSTN_DIS;
|
|
writel(reg, &clkrst->crc_pll[CLOCK_ID_PERIPH].pll_out[0]);
|
|
|
|
/* OUT3, 4 */
|
|
/* Assert RSTN before enable */
|
|
reg = PLLP_OUT4_RSTN_EN | PLLP_OUT3_RSTN_EN;
|
|
writel(reg, &clkrst->crc_pll[CLOCK_ID_PERIPH].pll_out[1]);
|
|
/* Set divisor and reenable */
|
|
reg = (IN_408_OUT_204_DIVISOR << PLLP_OUT4_RATIO)
|
|
| PLLP_OUT4_OVR | PLLP_OUT4_CLKEN | PLLP_OUT4_RSTN_DIS
|
|
| (IN_408_OUT_102_DIVISOR << PLLP_OUT3_RATIO)
|
|
| PLLP_OUT3_OVR | PLLP_OUT3_CLKEN | PLLP_OUT3_RSTN_DIS;
|
|
writel(reg, &clkrst->crc_pll[CLOCK_ID_PERIPH].pll_out[1]);
|
|
|
|
/*
|
|
* NOTE: If you want to change PLLP_OUT2 away from 204MHz,
|
|
* you can change PLLP_BASE DIVP here. Currently defaults
|
|
* to 1, which is 2^1, or 2, so PLLP_OUT2 is 204MHz.
|
|
* See Table 13 in section 5.1.4 in T210 TRM for more info.
|
|
*/
|
|
}
|
|
|
|
void clock_early_init(void)
|
|
{
|
|
struct clk_rst_ctlr *clkrst =
|
|
(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
|
|
struct clk_pll_info *pllinfo = &tegra_pll_info_table[CLOCK_ID_DISPLAY];
|
|
u32 data;
|
|
|
|
tegra210_setup_pllp();
|
|
|
|
/*
|
|
* PLLC output frequency set to 600Mhz
|
|
* PLLD output frequency set to 925Mhz
|
|
*/
|
|
switch (clock_get_osc_freq()) {
|
|
case CLOCK_OSC_FREQ_12_0: /* OSC is 12Mhz */
|
|
clock_set_rate(CLOCK_ID_CGENERAL, 600, 12, 0, 8);
|
|
clock_set_rate(CLOCK_ID_DISPLAY, 925, 12, 0, 12);
|
|
break;
|
|
|
|
case CLOCK_OSC_FREQ_26_0: /* OSC is 26Mhz */
|
|
clock_set_rate(CLOCK_ID_CGENERAL, 600, 26, 0, 8);
|
|
clock_set_rate(CLOCK_ID_DISPLAY, 925, 26, 0, 12);
|
|
break;
|
|
|
|
case CLOCK_OSC_FREQ_13_0: /* OSC is 13Mhz */
|
|
clock_set_rate(CLOCK_ID_CGENERAL, 600, 13, 0, 8);
|
|
clock_set_rate(CLOCK_ID_DISPLAY, 925, 13, 0, 12);
|
|
break;
|
|
case CLOCK_OSC_FREQ_19_2:
|
|
clock_set_rate(CLOCK_ID_CGENERAL, 125, 4, 0, 0);
|
|
clock_set_rate(CLOCK_ID_DISPLAY, 96, 2, 0, 12);
|
|
break;
|
|
case CLOCK_OSC_FREQ_38_4:
|
|
clock_set_rate(CLOCK_ID_CGENERAL, 125, 8, 0, 0);
|
|
clock_set_rate(CLOCK_ID_DISPLAY, 96, 4, 0, 0);
|
|
break;
|
|
default:
|
|
/*
|
|
* These are not supported. It is too early to print a
|
|
* message and the UART likely won't work anyway due to the
|
|
* oscillator being wrong.
|
|
*/
|
|
break;
|
|
}
|
|
|
|
/* PLLC_MISC1: Turn IDDQ off. NOTE: T210 PLLC_MISC_1 maps to pll_misc */
|
|
clrbits_le32(&clkrst->crc_pll[CLOCK_ID_CGENERAL].pll_misc,
|
|
(1 << PLLC_IDDQ));
|
|
udelay(2);
|
|
|
|
/*
|
|
* PLLC_MISC: Take PLLC out of reset. NOTE: T210 PLLC_MISC maps
|
|
* to pll_out[1]
|
|
*/
|
|
clrbits_le32(&clkrst->crc_pll[CLOCK_ID_CGENERAL].pll_out[1],
|
|
(1 << PLLC_RESET));
|
|
udelay(2);
|
|
|
|
/* PLLD_MISC: Set CLKENABLE and LOCK_DETECT bits */
|
|
data = (1 << PLLD_ENABLE_CLK) | (1 << pllinfo->lock_ena);
|
|
writel(data, &clkrst->crc_pll[CLOCK_ID_DISPLAY].pll_misc);
|
|
udelay(2);
|
|
}
|
|
|
|
unsigned int clk_m_get_rate(unsigned parent_rate)
|
|
{
|
|
struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
|
|
u32 value, div;
|
|
|
|
value = readl(&clkrst->crc_spare_reg0);
|
|
div = ((value >> 2) & 0x3) + 1;
|
|
|
|
return parent_rate / div;
|
|
}
|
|
|
|
void arch_timer_init(void)
|
|
{
|
|
struct sysctr_ctlr *sysctr = (struct sysctr_ctlr *)NV_PA_TSC_BASE;
|
|
u32 freq, val;
|
|
|
|
freq = clock_get_rate(CLOCK_ID_CLK_M);
|
|
debug("%s: clk_m freq is %dHz [0x%08X]\n", __func__, freq, freq);
|
|
|
|
if (current_el() == 3)
|
|
asm("msr cntfrq_el0, %0\n" : : "r" (freq));
|
|
|
|
/* Only Tegra114+ has the System Counter regs */
|
|
debug("%s: setting CNTFID0 to 0x%08X\n", __func__, freq);
|
|
writel(freq, &sysctr->cntfid0);
|
|
|
|
val = readl(&sysctr->cntcr);
|
|
val |= TSC_CNTCR_ENABLE | TSC_CNTCR_HDBG;
|
|
writel(val, &sysctr->cntcr);
|
|
debug("%s: TSC CNTCR = 0x%08X\n", __func__, val);
|
|
}
|
|
|
|
#define PLLREFE_MISC 0x4c8
|
|
#define PLLREFE_MISC_LOCK BIT(27)
|
|
#define PLLREFE_MISC_IDDQ BIT(24)
|
|
|
|
#define PLLREFE_BASE 0x4c4
|
|
#define PLLREFE_BASE_BYPASS BIT(31)
|
|
#define PLLREFE_BASE_ENABLE BIT(30)
|
|
#define PLLREFE_BASE_REF_DIS BIT(29)
|
|
#define PLLREFE_BASE_KCP(kcp) (((kcp) & 0x3) << 27)
|
|
#define PLLREFE_BASE_KVCO BIT(26)
|
|
#define PLLREFE_BASE_DIVP(p) (((p) & 0x1f) << 16)
|
|
#define PLLREFE_BASE_DIVN(n) (((n) & 0xff) << 8)
|
|
#define PLLREFE_BASE_DIVM(m) (((m) & 0xff) << 0)
|
|
|
|
static int tegra_pllref_enable(void)
|
|
{
|
|
u32 value;
|
|
unsigned long start;
|
|
|
|
/*
|
|
* This sequence comes from Tegra X1 TRM section "Cold Boot, with no
|
|
* Recovery Mode or Boot from USB", sub-section "PLLREFE".
|
|
*/
|
|
|
|
value = readl(NV_PA_CLK_RST_BASE + PLLREFE_MISC);
|
|
value &= ~PLLREFE_MISC_IDDQ;
|
|
writel(value, NV_PA_CLK_RST_BASE + PLLREFE_MISC);
|
|
|
|
udelay(5);
|
|
|
|
value = PLLREFE_BASE_ENABLE |
|
|
PLLREFE_BASE_KCP(0) |
|
|
PLLREFE_BASE_DIVP(0) |
|
|
PLLREFE_BASE_DIVN(0x41) |
|
|
PLLREFE_BASE_DIVM(4);
|
|
writel(value, NV_PA_CLK_RST_BASE + PLLREFE_BASE);
|
|
|
|
debug("waiting for pllrefe lock\n");
|
|
start = get_timer(0);
|
|
while (get_timer(start) < 250) {
|
|
value = readl(NV_PA_CLK_RST_BASE + PLLREFE_MISC);
|
|
if (value & PLLREFE_MISC_LOCK)
|
|
break;
|
|
}
|
|
if (!(value & PLLREFE_MISC_LOCK)) {
|
|
debug(" timeout\n");
|
|
return -ETIMEDOUT;
|
|
}
|
|
debug(" done\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define PLLE_SS_CNTL 0x68
|
|
#define PLLE_SS_CNTL_SSCINCINTR(x) (((x) & 0x3f) << 24)
|
|
#define PLLE_SS_CNTL_SSCINC(x) (((x) & 0xff) << 16)
|
|
#define PLLE_SS_CNTL_SSCINVERT (1 << 15)
|
|
#define PLLE_SS_CNTL_SSCCENTER (1 << 14)
|
|
#define PLLE_SS_CNTL_SSCBYP (1 << 12)
|
|
#define PLLE_SS_CNTL_INTERP_RESET (1 << 11)
|
|
#define PLLE_SS_CNTL_BYPASS_SS (1 << 10)
|
|
#define PLLE_SS_CNTL_SSCMAX(x) (((x) & 0x1ff) << 0)
|
|
|
|
#define PLLE_BASE 0x0e8
|
|
#define PLLE_BASE_ENABLE (1 << 31)
|
|
#define PLLE_BASE_PLDIV_CML(x) (((x) & 0x1f) << 24)
|
|
#define PLLE_BASE_NDIV(x) (((x) & 0xff) << 8)
|
|
#define PLLE_BASE_MDIV(x) (((x) & 0xff) << 0)
|
|
|
|
#define PLLE_MISC 0x0ec
|
|
#define PLLE_MISC_IDDQ_SWCTL (1 << 14)
|
|
#define PLLE_MISC_IDDQ_OVERRIDE_VALUE (1 << 13)
|
|
#define PLLE_MISC_LOCK (1 << 11)
|
|
#define PLLE_PTS (1 << 8)
|
|
#define PLLE_MISC_KCP(x) (((x) & 0x3) << 6)
|
|
#define PLLE_MISC_VREG_CTRL(x) (((x) & 0x3) << 2)
|
|
#define PLLE_MISC_KVCO (1 << 0)
|
|
|
|
#define PLLE_AUX 0x48c
|
|
#define PLLE_AUX_SS_SEQ_INCLUDE (1 << 31)
|
|
#define PLLE_AUX_REF_SEL_PLLREFE (1 << 28)
|
|
#define PLLE_AUX_SEQ_ENABLE (1 << 24)
|
|
#define PLLE_AUX_SS_SWCTL (1 << 6)
|
|
#define PLLE_AUX_ENABLE_SWCTL (1 << 4)
|
|
#define PLLE_AUX_USE_LOCKDET (1 << 3)
|
|
|
|
int tegra_plle_enable(void)
|
|
{
|
|
u32 value;
|
|
unsigned long start;
|
|
|
|
/* PLLREF feeds PLLE */
|
|
tegra_pllref_enable();
|
|
|
|
/*
|
|
* This sequence comes from Tegra X1 TRM section "Cold Boot, with no
|
|
* Recovery Mode or Boot from USB", sub-section "PLLEs".
|
|
*/
|
|
|
|
/* 1. Select XTAL as the source */
|
|
|
|
value = readl(NV_PA_CLK_RST_BASE + PLLE_AUX);
|
|
value &= ~PLLE_AUX_REF_SEL_PLLREFE;
|
|
writel(value, NV_PA_CLK_RST_BASE + PLLE_AUX);
|
|
|
|
value = readl(NV_PA_CLK_RST_BASE + PLLE_MISC);
|
|
value &= ~PLLE_MISC_IDDQ_OVERRIDE_VALUE;
|
|
writel(value, NV_PA_CLK_RST_BASE + PLLE_MISC);
|
|
|
|
/* 2. Wait 5 us */
|
|
udelay(5);
|
|
|
|
/*
|
|
* 3. Program the following registers to generate a low jitter 100MHz
|
|
* clock.
|
|
*/
|
|
|
|
value = readl(NV_PA_CLK_RST_BASE + PLLE_BASE);
|
|
value &= ~PLLE_BASE_PLDIV_CML(0x1f);
|
|
value &= ~PLLE_BASE_NDIV(0xff);
|
|
value &= ~PLLE_BASE_MDIV(0xff);
|
|
value |= PLLE_BASE_PLDIV_CML(0xe);
|
|
value |= PLLE_BASE_NDIV(0x7d);
|
|
value |= PLLE_BASE_MDIV(2);
|
|
writel(value, NV_PA_CLK_RST_BASE + PLLE_BASE);
|
|
|
|
value = readl(NV_PA_CLK_RST_BASE + PLLE_MISC);
|
|
value |= PLLE_PTS;
|
|
value &= ~PLLE_MISC_KCP(3);
|
|
value &= ~PLLE_MISC_VREG_CTRL(3);
|
|
value &= ~PLLE_MISC_KVCO;
|
|
writel(value, NV_PA_CLK_RST_BASE + PLLE_MISC);
|
|
|
|
value = readl(NV_PA_CLK_RST_BASE + PLLE_BASE);
|
|
value |= PLLE_BASE_ENABLE;
|
|
writel(value, NV_PA_CLK_RST_BASE + PLLE_BASE);
|
|
|
|
/* 4. Wait for LOCK */
|
|
|
|
debug("waiting for plle lock\n");
|
|
start = get_timer(0);
|
|
while (get_timer(start) < 250) {
|
|
value = readl(NV_PA_CLK_RST_BASE + PLLE_MISC);
|
|
if (value & PLLE_MISC_LOCK)
|
|
break;
|
|
}
|
|
if (!(value & PLLE_MISC_LOCK)) {
|
|
debug(" timeout\n");
|
|
return -ETIMEDOUT;
|
|
}
|
|
debug(" done\n");
|
|
|
|
/* 5. Enable SSA */
|
|
|
|
value = readl(NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
|
|
value &= ~PLLE_SS_CNTL_SSCINC(0xff);
|
|
value |= PLLE_SS_CNTL_SSCINC(1);
|
|
value &= ~PLLE_SS_CNTL_SSCINCINTR(0x3f);
|
|
value |= PLLE_SS_CNTL_SSCINCINTR(0x23);
|
|
value &= ~PLLE_SS_CNTL_SSCMAX(0x1fff);
|
|
value |= PLLE_SS_CNTL_SSCMAX(0x21);
|
|
value &= ~PLLE_SS_CNTL_SSCINVERT;
|
|
value &= ~PLLE_SS_CNTL_SSCCENTER;
|
|
value &= ~PLLE_SS_CNTL_BYPASS_SS;
|
|
value &= ~PLLE_SS_CNTL_SSCBYP;
|
|
writel(value, NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
|
|
|
|
/* 6. Wait 300 ns */
|
|
|
|
udelay(1);
|
|
value &= ~PLLE_SS_CNTL_INTERP_RESET;
|
|
writel(value, NV_PA_CLK_RST_BASE + PLLE_SS_CNTL);
|
|
|
|
/* 7. Enable HW power sequencer for PLLE */
|
|
|
|
value = readl(NV_PA_CLK_RST_BASE + PLLE_MISC);
|
|
value &= ~PLLE_MISC_IDDQ_SWCTL;
|
|
writel(value, NV_PA_CLK_RST_BASE + PLLE_MISC);
|
|
|
|
value = readl(NV_PA_CLK_RST_BASE + PLLE_AUX);
|
|
value &= ~PLLE_AUX_SS_SWCTL;
|
|
value &= ~PLLE_AUX_ENABLE_SWCTL;
|
|
value |= PLLE_AUX_SS_SEQ_INCLUDE;
|
|
value |= PLLE_AUX_USE_LOCKDET;
|
|
writel(value, NV_PA_CLK_RST_BASE + PLLE_AUX);
|
|
|
|
/* 8. Wait 1 us */
|
|
|
|
udelay(1);
|
|
value |= PLLE_AUX_SEQ_ENABLE;
|
|
writel(value, NV_PA_CLK_RST_BASE + PLLE_AUX);
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct periph_clk_init periph_clk_init_table[] = {
|
|
{ PERIPH_ID_SBC1, CLOCK_ID_PERIPH },
|
|
{ PERIPH_ID_SBC2, CLOCK_ID_PERIPH },
|
|
{ PERIPH_ID_SBC3, CLOCK_ID_PERIPH },
|
|
{ PERIPH_ID_SBC4, CLOCK_ID_PERIPH },
|
|
{ PERIPH_ID_SBC5, CLOCK_ID_PERIPH },
|
|
{ PERIPH_ID_SBC6, CLOCK_ID_PERIPH },
|
|
{ PERIPH_ID_HOST1X, CLOCK_ID_PERIPH },
|
|
{ PERIPH_ID_DISP1, CLOCK_ID_CGENERAL },
|
|
{ PERIPH_ID_SDMMC1, CLOCK_ID_PERIPH },
|
|
{ PERIPH_ID_SDMMC2, CLOCK_ID_PERIPH },
|
|
{ PERIPH_ID_SDMMC3, CLOCK_ID_PERIPH },
|
|
{ PERIPH_ID_SDMMC4, CLOCK_ID_PERIPH },
|
|
{ PERIPH_ID_PWM, CLOCK_ID_SFROM32KHZ },
|
|
{ PERIPH_ID_I2C1, CLOCK_ID_PERIPH },
|
|
{ PERIPH_ID_I2C2, CLOCK_ID_PERIPH },
|
|
{ PERIPH_ID_I2C3, CLOCK_ID_PERIPH },
|
|
{ PERIPH_ID_I2C4, CLOCK_ID_PERIPH },
|
|
{ PERIPH_ID_I2C5, CLOCK_ID_PERIPH },
|
|
{ PERIPH_ID_I2C6, CLOCK_ID_PERIPH },
|
|
{ -1, },
|
|
};
|