From 51ff1eda6f788fc76666d275a87a7c7aff32baa8 Mon Sep 17 00:00:00 2001 From: Rajeshwari Shinde Date: Tue, 12 Feb 2013 20:40:01 +0000 Subject: EXYNOS5: Add function to setup set ps hold This patch adds a function to set ps_hold data driving value high. This enables the machine to stay powered on even after the initial power-on condition goes away(e.g. power button). Acked-by: Simon Glass Signed-off-by: Rajeshwari Shinde Signed-off-by: Minkyu Kang --- arch/arm/cpu/armv7/exynos/power.c | 16 ++++++++++++++++ arch/arm/include/asm/arch-exynos/power.h | 9 +++++++++ 2 files changed, 25 insertions(+) diff --git a/arch/arm/cpu/armv7/exynos/power.c b/arch/arm/cpu/armv7/exynos/power.c index d4bce6d4dd..400c8bcfc5 100644 --- a/arch/arm/cpu/armv7/exynos/power.c +++ b/arch/arm/cpu/armv7/exynos/power.c @@ -95,3 +95,19 @@ void set_dp_phy_ctrl(unsigned int enable) if (cpu_is_exynos5()) exynos5_dp_phy_control(enable); } + +static void exynos5_set_ps_hold_ctrl(void) +{ + struct exynos5_power *power = + (struct exynos5_power *)samsung_get_base_power(); + + /* Set PS-Hold high */ + setbits_le32(&power->ps_hold_control, + EXYNOS_PS_HOLD_CONTROL_DATA_HIGH); +} + +void set_ps_hold_ctrl(void) +{ + if (cpu_is_exynos5()) + exynos5_set_ps_hold_ctrl(); +} diff --git a/arch/arm/include/asm/arch-exynos/power.h b/arch/arm/include/asm/arch-exynos/power.h index d2fdb59817..f2f73faa75 100644 --- a/arch/arm/include/asm/arch-exynos/power.h +++ b/arch/arm/include/asm/arch-exynos/power.h @@ -864,4 +864,13 @@ void set_dp_phy_ctrl(unsigned int enable); #define EXYNOS_DP_PHY_ENABLE (1 << 0) +#define EXYNOS_PS_HOLD_CONTROL_DATA_HIGH (1 << 8) + +/* + * Set ps_hold data driving value high + * This enables the machine to stay powered on + * after the initial power-on condition goes away + * (e.g. power button). + */ +void set_ps_hold_ctrl(void); #endif -- cgit v1.2.3 From b278c4095b59c40ff512c5433b735b000e547554 Mon Sep 17 00:00:00 2001 From: Rajeshwari Shinde Date: Tue, 12 Feb 2013 20:40:02 +0000 Subject: SMDK5250: Add PMIC voltage settings This patch adds required pmic voltage settings for SMDK5250. Acked-by: Simon Glass Signed-off-by: Rajeshwari Shinde Signed-off-by: Minkyu Kang --- board/samsung/smdk5250/smdk5250.c | 113 +++++++++++++++++++++++++++++++++++++- include/power/max77686_pmic.h | 32 +++++++++++ 2 files changed, 143 insertions(+), 2 deletions(-) diff --git a/board/samsung/smdk5250/smdk5250.c b/board/samsung/smdk5250/smdk5250.c index 7a5f132ebb..ffc5ee5a61 100644 --- a/board/samsung/smdk5250/smdk5250.c +++ b/board/samsung/smdk5250/smdk5250.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,7 @@ #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -80,12 +82,119 @@ int dram_init(void) } #if defined(CONFIG_POWER) +static int pmic_reg_update(struct pmic *p, int reg, uint regval) +{ + u32 val; + int ret = 0; + + ret = pmic_reg_read(p, reg, &val); + if (ret) { + debug("%s: PMIC %d register read failed\n", __func__, reg); + return -1; + } + val |= regval; + ret = pmic_reg_write(p, reg, val); + if (ret) { + debug("%s: PMIC %d register write failed\n", __func__, reg); + return -1; + } + return 0; +} + int power_init_board(void) { + struct pmic *p; + + set_ps_hold_ctrl(); + + i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); + if (pmic_init(I2C_PMIC)) return -1; - else - return 0; + + p = pmic_get("MAX77686_PMIC"); + if (!p) + return -ENODEV; + + if (pmic_probe(p)) + return -1; + + if (pmic_reg_update(p, MAX77686_REG_PMIC_32KHZ, MAX77686_32KHCP_EN)) + return -1; + + if (pmic_reg_update(p, MAX77686_REG_PMIC_BBAT, + MAX77686_BBCHOSTEN | MAX77686_BBCVS_3_5V)) + return -1; + + /* VDD_MIF */ + if (pmic_reg_write(p, MAX77686_REG_PMIC_BUCK1OUT, + MAX77686_BUCK1OUT_1V)) { + debug("%s: PMIC %d register write failed\n", __func__, + MAX77686_REG_PMIC_BUCK1OUT); + return -1; + } + + if (pmic_reg_update(p, MAX77686_REG_PMIC_BUCK1CRTL, + MAX77686_BUCK1CTRL_EN)) + return -1; + + /* VDD_ARM */ + if (pmic_reg_write(p, MAX77686_REG_PMIC_BUCK2DVS1, + MAX77686_BUCK2DVS1_1_3V)) { + debug("%s: PMIC %d register write failed\n", __func__, + MAX77686_REG_PMIC_BUCK2DVS1); + return -1; + } + + if (pmic_reg_update(p, MAX77686_REG_PMIC_BUCK2CTRL1, + MAX77686_BUCK2CTRL_ON)) + return -1; + + /* VDD_INT */ + if (pmic_reg_write(p, MAX77686_REG_PMIC_BUCK3DVS1, + MAX77686_BUCK3DVS1_1_0125V)) { + debug("%s: PMIC %d register write failed\n", __func__, + MAX77686_REG_PMIC_BUCK3DVS1); + return -1; + } + + if (pmic_reg_update(p, MAX77686_REG_PMIC_BUCK3CTRL, + MAX77686_BUCK3CTRL_ON)) + return -1; + + /* VDD_G3D */ + if (pmic_reg_write(p, MAX77686_REG_PMIC_BUCK4DVS1, + MAX77686_BUCK4DVS1_1_2V)) { + debug("%s: PMIC %d register write failed\n", __func__, + MAX77686_REG_PMIC_BUCK4DVS1); + return -1; + } + + if (pmic_reg_update(p, MAX77686_REG_PMIC_BUCK4CTRL1, + MAX77686_BUCK3CTRL_ON)) + return -1; + + /* VDD_LDO2 */ + if (pmic_reg_update(p, MAX77686_REG_PMIC_LDO2CTRL1, + MAX77686_LD02CTRL1_1_5V | EN_LDO)) + return -1; + + /* VDD_LDO3 */ + if (pmic_reg_update(p, MAX77686_REG_PMIC_LDO3CTRL1, + MAX77686_LD03CTRL1_1_8V | EN_LDO)) + return -1; + + /* VDD_LDO5 */ + if (pmic_reg_update(p, MAX77686_REG_PMIC_LDO5CTRL1, + MAX77686_LD05CTRL1_1_8V | EN_LDO)) + return -1; + + /* VDD_LDO10 */ + if (pmic_reg_update(p, MAX77686_REG_PMIC_LDO10CTRL1, + MAX77686_LD10CTRL1_1_8V | EN_LDO)) + return -1; + + return 0; } #endif diff --git a/include/power/max77686_pmic.h b/include/power/max77686_pmic.h index d949aced09..fdc7ca9e5a 100644 --- a/include/power/max77686_pmic.h +++ b/include/power/max77686_pmic.h @@ -155,4 +155,36 @@ enum { EN_LDO = (0x3 << 6), }; +/* Buck1 1 volt value */ +#define MAX77686_BUCK1OUT_1V 0x5 +#define MAX77686_BUCK1CTRL_EN (3 << 0) +/* Buck2 1.3 volt value */ +#define MAX77686_BUCK2DVS1_1_3V 0x38 +#define MAX77686_BUCK2CTRL_ON (1 << 4) +/* Buck3 1.0125 volt value */ +#define MAX77686_BUCK3DVS1_1_0125V 0x21 +#define MAX77686_BUCK3CTRL_ON (1 << 4) +/* Buck4 1.2 volt value */ +#define MAX77686_BUCK4DVS1_1_2V 0x30 +#define MAX77686_BUCK4CTRL_ON (1 << 4) +/* LDO2 1.5 volt value */ +#define MAX77686_LD02CTRL1_1_5V 0x1c +/* LDO3 1.8 volt value */ +#define MAX77686_LD03CTRL1_1_8V 0x14 +/* LDO5 1.8 volt value */ +#define MAX77686_LD05CTRL1_1_8V 0x14 +/* LDO10 1.8 volt value */ +#define MAX77686_LD10CTRL1_1_8V 0x14 +/* + * MAX77686_REG_PMIC_32KHZ set to 32KH CP + * output is activated + */ +#define MAX77686_32KHCP_EN (1 << 1) +/* + * MAX77686_REG_PMIC_BBAT set to + * Back up batery charger on and + * limit voltage setting to 3.5v + */ +#define MAX77686_BBCHOSTEN (1 << 0) +#define MAX77686_BBCVS_3_5V (3 << 3) #endif /* __MAX77686_PMIC_H_ */ -- cgit v1.2.3 From a006076b15c32e2f9c2c133697b5c662f7d1294e Mon Sep 17 00:00:00 2001 From: Rajeshwari Shinde Date: Thu, 14 Feb 2013 19:46:11 +0000 Subject: EXYNOS5: Add function to enable XXTI clock source This patch adds funtion to enable XXTI clock source required by MAX98095 codec. Signed-off-by: Rajeshwari Shinde Signed-off-by: Minkyu Kang --- arch/arm/cpu/armv7/exynos/power.c | 17 +++++++++++++++++ arch/arm/include/asm/arch-exynos/power.h | 11 +++++++++++ 2 files changed, 28 insertions(+) diff --git a/arch/arm/cpu/armv7/exynos/power.c b/arch/arm/cpu/armv7/exynos/power.c index 400c8bcfc5..db7249ef7f 100644 --- a/arch/arm/cpu/armv7/exynos/power.c +++ b/arch/arm/cpu/armv7/exynos/power.c @@ -111,3 +111,20 @@ void set_ps_hold_ctrl(void) if (cpu_is_exynos5()) exynos5_set_ps_hold_ctrl(); } + + +static void exynos5_set_xclkout(void) +{ + struct exynos5_power *power = + (struct exynos5_power *)samsung_get_base_power(); + + /* use xxti for xclk out */ + clrsetbits_le32(&power->pmu_debug, PMU_DEBUG_CLKOUT_SEL_MASK, + PMU_DEBUG_XXTI); +} + +void set_xclkout(void) +{ + if (cpu_is_exynos5()) + exynos5_set_xclkout(); +} diff --git a/arch/arm/include/asm/arch-exynos/power.h b/arch/arm/include/asm/arch-exynos/power.h index f2f73faa75..5f2633763c 100644 --- a/arch/arm/include/asm/arch-exynos/power.h +++ b/arch/arm/include/asm/arch-exynos/power.h @@ -873,4 +873,15 @@ void set_dp_phy_ctrl(unsigned int enable); * (e.g. power button). */ void set_ps_hold_ctrl(void); + +/* PMU_DEBUG bits [12:8] = 0x1000 selects XXTI clock source */ +#define PMU_DEBUG_XXTI 0x1000 +/* Mask bit[12:8] for xxti clock selection */ +#define PMU_DEBUG_CLKOUT_SEL_MASK 0x1f00 + +/* + * Pmu debug is used for xclkout, enable xclkout with + * source as XXTI + */ +void set_xclkout(void); #endif -- cgit v1.2.3 From 5febe8db91a9feca467ce8e0189a69b49cba02e7 Mon Sep 17 00:00:00 2001 From: Rajeshwari Shinde Date: Thu, 14 Feb 2013 19:46:12 +0000 Subject: Sound: MAX98095: Add the driver for codec This patch adds the driver for codec MAX98095 required by Snow Board Signed-off-by: Rajeshwari Shinde Acked-by: Simon Glass Signed-off-by: Minkyu Kang --- drivers/sound/Makefile | 1 + drivers/sound/max98095.c | 550 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/sound/max98095.h | 311 +++++++++++++++++++++++++++ 3 files changed, 862 insertions(+) create mode 100644 drivers/sound/max98095.c create mode 100644 drivers/sound/max98095.h diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile index 8fdffb10ef..1987ca1a05 100644 --- a/drivers/sound/Makefile +++ b/drivers/sound/Makefile @@ -28,6 +28,7 @@ LIB := $(obj)libsound.o COBJS-$(CONFIG_SOUND) += sound.o COBJS-$(CONFIG_I2S) += samsung-i2s.o COBJS-$(CONFIG_SOUND_WM8994) += wm8994.o +COBJS-$(CONFIG_SOUND_MAX98095) += max98095.o COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/sound/max98095.c b/drivers/sound/max98095.c new file mode 100644 index 0000000000..d69db58dcd --- /dev/null +++ b/drivers/sound/max98095.c @@ -0,0 +1,550 @@ +/* + * max98095.c -- MAX98095 ALSA SoC Audio driver + * + * Copyright 2011 Maxim Integrated Products + * + * Modified for uboot by R. Chandrasekar (rcsekar@samsung.com) + * + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "i2s.h" +#include "max98095.h" + +enum max98095_type { + MAX98095, +}; + +struct max98095_priv { + enum max98095_type devtype; + unsigned int sysclk; + unsigned int rate; + unsigned int fmt; +}; + +static struct sound_codec_info g_codec_info; +struct max98095_priv g_max98095_info; +unsigned int g_max98095_i2c_dev_addr; + +/* Index 0 is reserved. */ +int rate_table[] = {0, 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, + 88200, 96000}; + +/* + * Writes value to a device register through i2c + * + * @param reg reg number to be write + * @param data data to be writen to the above registor + * + * @return int value 1 for change, 0 for no change or negative error code. + */ +static int max98095_i2c_write(unsigned int reg, unsigned char data) +{ + debug("%s: Write Addr : 0x%02X, Data : 0x%02X\n", + __func__, reg, data); + return i2c_write(g_max98095_i2c_dev_addr, reg, 1, &data, 1); +} + +/* + * Read a value from a device register through i2c + * + * @param reg reg number to be read + * @param data address of read data to be stored + * + * @return int value 0 for success, -1 in case of error. + */ +static unsigned int max98095_i2c_read(unsigned int reg, unsigned char *data) +{ + int ret; + + ret = i2c_read(g_max98095_i2c_dev_addr, reg, 1, data, 1); + if (ret != 0) { + debug("%s: Error while reading register %#04x\n", + __func__, reg); + return -1; + } + + return 0; +} + +/* + * update device register bits through i2c + * + * @param reg codec register + * @param mask register mask + * @param value new value + * + * @return int value 0 for success, non-zero error code. + */ +static int max98095_update_bits(unsigned int reg, unsigned char mask, + unsigned char value) +{ + int change, ret = 0; + unsigned char old, new; + + if (max98095_i2c_read(reg, &old) != 0) + return -1; + new = (old & ~mask) | (value & mask); + change = (old != new) ? 1 : 0; + if (change) + ret = max98095_i2c_write(reg, new); + if (ret < 0) + return ret; + + return change; +} + +/* + * codec mclk clock divider coefficients based on sampling rate + * + * @param rate sampling rate + * @param value address of indexvalue to be stored + * + * @return 0 for success or negative error code. + */ +static int rate_value(int rate, u8 *value) +{ + int i; + + for (i = 1; i < ARRAY_SIZE(rate_table); i++) { + if (rate_table[i] >= rate) { + *value = i; + return 0; + } + } + *value = 1; + + return -1; +} + +/* + * Sets hw params for max98095 + * + * @param max98095 max98095 information pointer + * @param rate Sampling rate + * @param bits_per_sample Bits per sample + * + * @return -1 for error and 0 Success. + */ +static int max98095_hw_params(struct max98095_priv *max98095, + unsigned int rate, unsigned int bits_per_sample) +{ + u8 regval; + int error; + + switch (bits_per_sample) { + case 16: + error = max98095_update_bits(M98095_034_DAI2_FORMAT, + M98095_DAI_WS, 0); + break; + case 24: + error = max98095_update_bits(M98095_034_DAI2_FORMAT, + M98095_DAI_WS, M98095_DAI_WS); + break; + default: + debug("%s: Illegal bits per sample %d.\n", + __func__, bits_per_sample); + return -1; + } + + if (rate_value(rate, ®val)) { + debug("%s: Failed to set sample rate to %d.\n", + __func__, rate); + return -1; + } + max98095->rate = rate; + + error |= max98095_update_bits(M98095_031_DAI2_CLKMODE, + M98095_CLKMODE_MASK, regval); + + /* Update sample rate mode */ + if (rate < 50000) + error |= max98095_update_bits(M98095_038_DAI2_FILTERS, + M98095_DAI_DHF, 0); + else + error |= max98095_update_bits(M98095_038_DAI2_FILTERS, + M98095_DAI_DHF, M98095_DAI_DHF); + + if (error < 0) { + debug("%s: Error setting hardware params.\n", __func__); + return -1; + } + + return 0; +} + +/* + * Configures Audio interface system clock for the given frequency + * + * @param max98095 max98095 information + * @param freq Sampling frequency in Hz + * + * @return -1 for error and 0 success. + */ +static int max98095_set_sysclk(struct max98095_priv *max98095, + unsigned int freq) +{ + int error = 0; + + /* Requested clock frequency is already setup */ + if (freq == max98095->sysclk) + return 0; + + /* Setup clocks for slave mode, and using the PLL + * PSCLK = 0x01 (when master clk is 10MHz to 20MHz) + * 0x02 (when master clk is 20MHz to 40MHz).. + * 0x03 (when master clk is 40MHz to 60MHz).. + */ + if ((freq >= 10000000) && (freq < 20000000)) { + error = max98095_i2c_write(M98095_026_SYS_CLK, 0x10); + } else if ((freq >= 20000000) && (freq < 40000000)) { + error = max98095_i2c_write(M98095_026_SYS_CLK, 0x20); + } else if ((freq >= 40000000) && (freq < 60000000)) { + error = max98095_i2c_write(M98095_026_SYS_CLK, 0x30); + } else { + debug("%s: Invalid master clock frequency\n", __func__); + return -1; + } + + debug("%s: Clock at %uHz\n", __func__, freq); + + if (error < 0) + return -1; + + max98095->sysclk = freq; + return 0; +} + +/* + * Sets Max98095 I2S format + * + * @param max98095 max98095 information + * @param fmt i2S format - supports a subset of the options defined + * in i2s.h. + * + * @return -1 for error and 0 Success. + */ +static int max98095_set_fmt(struct max98095_priv *max98095, int fmt) +{ + u8 regval = 0; + int error = 0; + + if (fmt == max98095->fmt) + return 0; + + max98095->fmt = fmt; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + /* Slave mode PLL */ + error |= max98095_i2c_write(M98095_032_DAI2_CLKCFG_HI, + 0x80); + error |= max98095_i2c_write(M98095_033_DAI2_CLKCFG_LO, + 0x00); + break; + case SND_SOC_DAIFMT_CBM_CFM: + /* Set to master mode */ + regval |= M98095_DAI_MAS; + break; + case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBM_CFS: + default: + debug("%s: Clock mode unsupported\n", __func__); + return -1; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + regval |= M98095_DAI_DLY; + break; + case SND_SOC_DAIFMT_LEFT_J: + break; + default: + debug("%s: Unrecognized format.\n", __func__); + return -1; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_NB_IF: + regval |= M98095_DAI_WCI; + break; + case SND_SOC_DAIFMT_IB_NF: + regval |= M98095_DAI_BCI; + break; + case SND_SOC_DAIFMT_IB_IF: + regval |= M98095_DAI_BCI | M98095_DAI_WCI; + break; + default: + debug("%s: Unrecognized inversion settings.\n", __func__); + return -1; + } + + error |= max98095_update_bits(M98095_034_DAI2_FORMAT, + M98095_DAI_MAS | M98095_DAI_DLY | M98095_DAI_BCI | + M98095_DAI_WCI, regval); + + error |= max98095_i2c_write(M98095_035_DAI2_CLOCK, + M98095_DAI_BSEL64); + + if (error < 0) { + debug("%s: Error setting i2s format.\n", __func__); + return -1; + } + + return 0; +} + +/* + * resets the audio codec + * + * @return -1 for error and 0 success. + */ +static int max98095_reset(void) +{ + int i, ret; + + /* + * Gracefully reset the DSP core and the codec hardware in a proper + * sequence. + */ + ret = max98095_i2c_write(M98095_00F_HOST_CFG, 0); + if (ret != 0) { + debug("%s: Failed to reset DSP: %d\n", __func__, ret); + return ret; + } + + ret = max98095_i2c_write(M98095_097_PWR_SYS, 0); + if (ret != 0) { + debug("%s: Failed to reset codec: %d\n", __func__, ret); + return ret; + } + + /* + * Reset to hardware default for registers, as there is not a soft + * reset hardware control register. + */ + for (i = M98095_010_HOST_INT_CFG; i < M98095_REG_MAX_CACHED; i++) { + ret = max98095_i2c_write(i, 0); + if (ret < 0) { + debug("%s: Failed to reset: %d\n", __func__, ret); + return ret; + } + } + + return 0; +} + +/* + * Intialise max98095 codec device + * + * @param max98095 max98095 information + * + * @returns -1 for error and 0 Success. + */ +static int max98095_device_init(struct max98095_priv *max98095) +{ + unsigned char id; + int error = 0; + + /* reset the codec, the DSP core, and disable all interrupts */ + error = max98095_reset(); + if (error != 0) { + debug("Reset\n"); + return error; + } + + /* initialize private data */ + max98095->sysclk = -1U; + max98095->rate = -1U; + max98095->fmt = -1U; + + error = max98095_i2c_read(M98095_0FF_REV_ID, &id); + if (error < 0) { + debug("%s: Failure reading hardware revision: %d\n", + __func__, id); + goto err_access; + } + debug("%s: Hardware revision: %c\n", __func__, (id - 0x40) + 'A'); + + error |= max98095_i2c_write(M98095_097_PWR_SYS, M98095_PWRSV); + + /* + * initialize registers to hardware default configuring audio + * interface2 to DAC + */ + error |= max98095_i2c_write(M98095_048_MIX_DAC_LR, + M98095_DAI2M_TO_DACL|M98095_DAI2M_TO_DACR); + + error |= max98095_i2c_write(M98095_092_PWR_EN_OUT, + M98095_SPK_SPREADSPECTRUM); + error |= max98095_i2c_write(M98095_045_CFG_DSP, M98095_DSPNORMAL); + error |= max98095_i2c_write(M98095_04E_CFG_HP, M98095_HPNORMAL); + + error |= max98095_i2c_write(M98095_02C_DAI1_IOCFG, + M98095_S1NORMAL|M98095_SDATA); + + error |= max98095_i2c_write(M98095_036_DAI2_IOCFG, + M98095_S2NORMAL|M98095_SDATA); + + error |= max98095_i2c_write(M98095_040_DAI3_IOCFG, + M98095_S3NORMAL|M98095_SDATA); + + /* take the codec out of the shut down */ + error |= max98095_update_bits(M98095_097_PWR_SYS, M98095_SHDNRUN, + M98095_SHDNRUN); + /* route DACL and DACR output to HO and Spekers */ + error |= max98095_i2c_write(M98095_050_MIX_SPK_LEFT, 0x01); /* DACL */ + error |= max98095_i2c_write(M98095_051_MIX_SPK_RIGHT, 0x01);/* DACR */ + error |= max98095_i2c_write(M98095_04C_MIX_HP_LEFT, 0x01); /* DACL */ + error |= max98095_i2c_write(M98095_04D_MIX_HP_RIGHT, 0x01); /* DACR */ + + /* power Enable */ + error |= max98095_i2c_write(M98095_091_PWR_EN_OUT, 0xF3); + + /* set Volume */ + error |= max98095_i2c_write(M98095_064_LVL_HP_L, 15); + error |= max98095_i2c_write(M98095_065_LVL_HP_R, 15); + error |= max98095_i2c_write(M98095_067_LVL_SPK_L, 16); + error |= max98095_i2c_write(M98095_068_LVL_SPK_R, 16); + + /* Enable DAIs */ + error |= max98095_i2c_write(M98095_093_BIAS_CTRL, 0x30); + error |= max98095_i2c_write(M98095_096_PWR_DAC_CK, 0x07); + +err_access: + if (error < 0) + return -1; + + return 0; +} + +static int max98095_do_init(struct sound_codec_info *pcodec_info, + int sampling_rate, int mclk_freq, + int bits_per_sample) +{ + int ret = 0; + + /* Enable codec clock */ + set_xclkout(); + + /* shift the device address by 1 for 7 bit addressing */ + g_max98095_i2c_dev_addr = pcodec_info->i2c_dev_addr >> 1; + + if (pcodec_info->codec_type == CODEC_MAX_98095) + g_max98095_info.devtype = MAX98095; + else { + debug("%s: Codec id [%d] not defined\n", __func__, + pcodec_info->codec_type); + return -1; + } + + ret = max98095_device_init(&g_max98095_info); + if (ret < 0) { + debug("%s: max98095 codec chip init failed\n", __func__); + return ret; + } + + ret = max98095_set_sysclk(&g_max98095_info, mclk_freq); + if (ret < 0) { + debug("%s: max98095 codec set sys clock failed\n", __func__); + return ret; + } + + ret = max98095_hw_params(&g_max98095_info, sampling_rate, + bits_per_sample); + + if (ret == 0) { + ret = max98095_set_fmt(&g_max98095_info, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS); + } + + return ret; +} + +static int get_max98095_codec_values(struct sound_codec_info *pcodec_info, + const void *blob) +{ + int error = 0; +#ifdef CONFIG_OF_CONTROL + enum fdt_compat_id compat; + int node; + int parent; + + /* Get the node from FDT for codec */ + node = fdtdec_next_compatible(blob, 0, COMPAT_MAXIM_98095_CODEC); + if (node <= 0) { + debug("EXYNOS_SOUND: No node for codec in device tree\n"); + debug("node = %d\n", node); + return -1; + } + + parent = fdt_parent_offset(blob, node); + if (parent < 0) { + debug("%s: Cannot find node parent\n", __func__); + return -1; + } + + compat = fdtdec_lookup(blob, parent); + switch (compat) { + case COMPAT_SAMSUNG_S3C2440_I2C: + pcodec_info->i2c_bus = i2c_get_bus_num_fdt(parent); + error |= pcodec_info->i2c_bus; + debug("i2c bus = %d\n", pcodec_info->i2c_bus); + pcodec_info->i2c_dev_addr = fdtdec_get_int(blob, node, + "reg", 0); + error |= pcodec_info->i2c_dev_addr; + debug("i2c dev addr = %x\n", pcodec_info->i2c_dev_addr); + break; + default: + debug("%s: Unknown compat id %d\n", __func__, compat); + return -1; + } +#else + pcodec_info->i2c_bus = AUDIO_I2C_BUS; + pcodec_info->i2c_dev_addr = AUDIO_I2C_REG; + debug("i2c dev addr = %d\n", pcodec_info->i2c_dev_addr); +#endif + pcodec_info->codec_type = CODEC_MAX_98095; + if (error == -1) { + debug("fail to get max98095 codec node properties\n"); + return -1; + } + + return 0; +} + +/* max98095 Device Initialisation */ +int max98095_init(const void *blob, int sampling_rate, int mclk_freq, + int bits_per_sample) +{ + int ret; + int old_bus = i2c_get_bus_num(); + struct sound_codec_info *pcodec_info = &g_codec_info; + + if (get_max98095_codec_values(pcodec_info, blob) < 0) { + debug("FDT Codec values failed\n"); + return -1; + } + + i2c_set_bus_num(pcodec_info->i2c_bus); + ret = max98095_do_init(pcodec_info, sampling_rate, mclk_freq, + bits_per_sample); + i2c_set_bus_num(old_bus); + + return ret; +} diff --git a/drivers/sound/max98095.h b/drivers/sound/max98095.h new file mode 100644 index 0000000000..ae5eb14dbb --- /dev/null +++ b/drivers/sound/max98095.h @@ -0,0 +1,311 @@ +/* + * max98095.h -- MAX98095 ALSA SoC Audio driver + * + * Copyright 2011 Maxim Integrated Products + * + * 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. + */ + +#ifndef _MAX98095_H +#define _MAX98095_H + +/* + * MAX98095 Registers Definition + */ + +#define M98095_000_HOST_DATA 0x00 +#define M98095_001_HOST_INT_STS 0x01 +#define M98095_002_HOST_RSP_STS 0x02 +#define M98095_003_HOST_CMD_STS 0x03 +#define M98095_004_CODEC_STS 0x04 +#define M98095_005_DAI1_ALC_STS 0x05 +#define M98095_006_DAI2_ALC_STS 0x06 +#define M98095_007_JACK_AUTO_STS 0x07 +#define M98095_008_JACK_MANUAL_STS 0x08 +#define M98095_009_JACK_VBAT_STS 0x09 +#define M98095_00A_ACC_ADC_STS 0x0A +#define M98095_00B_MIC_NG_AGC_STS 0x0B +#define M98095_00C_SPK_L_VOLT_STS 0x0C +#define M98095_00D_SPK_R_VOLT_STS 0x0D +#define M98095_00E_TEMP_SENSOR_STS 0x0E +#define M98095_00F_HOST_CFG 0x0F +#define M98095_010_HOST_INT_CFG 0x10 +#define M98095_011_HOST_INT_EN 0x11 +#define M98095_012_CODEC_INT_EN 0x12 +#define M98095_013_JACK_INT_EN 0x13 +#define M98095_014_JACK_INT_EN 0x14 +#define M98095_015_DEC 0x15 +#define M98095_016_RESERVED 0x16 +#define M98095_017_RESERVED 0x17 +#define M98095_018_KEYCODE3 0x18 +#define M98095_019_KEYCODE2 0x19 +#define M98095_01A_KEYCODE1 0x1A +#define M98095_01B_KEYCODE0 0x1B +#define M98095_01C_OEMCODE1 0x1C +#define M98095_01D_OEMCODE0 0x1D +#define M98095_01E_XCFG1 0x1E +#define M98095_01F_XCFG2 0x1F +#define M98095_020_XCFG3 0x20 +#define M98095_021_XCFG4 0x21 +#define M98095_022_XCFG5 0x22 +#define M98095_023_XCFG6 0x23 +#define M98095_024_XGPIO 0x24 +#define M98095_025_XCLKCFG 0x25 +#define M98095_026_SYS_CLK 0x26 +#define M98095_027_DAI1_CLKMODE 0x27 +#define M98095_028_DAI1_CLKCFG_HI 0x28 +#define M98095_029_DAI1_CLKCFG_LO 0x29 +#define M98095_02A_DAI1_FORMAT 0x2A +#define M98095_02B_DAI1_CLOCK 0x2B +#define M98095_02C_DAI1_IOCFG 0x2C +#define M98095_02D_DAI1_TDM 0x2D +#define M98095_02E_DAI1_FILTERS 0x2E +#define M98095_02F_DAI1_LVL1 0x2F +#define M98095_030_DAI1_LVL2 0x30 +#define M98095_031_DAI2_CLKMODE 0x31 +#define M98095_032_DAI2_CLKCFG_HI 0x32 +#define M98095_033_DAI2_CLKCFG_LO 0x33 +#define M98095_034_DAI2_FORMAT 0x34 +#define M98095_035_DAI2_CLOCK 0x35 +#define M98095_036_DAI2_IOCFG 0x36 +#define M98095_037_DAI2_TDM 0x37 +#define M98095_038_DAI2_FILTERS 0x38 +#define M98095_039_DAI2_LVL1 0x39 +#define M98095_03A_DAI2_LVL2 0x3A +#define M98095_03B_DAI3_CLKMODE 0x3B +#define M98095_03C_DAI3_CLKCFG_HI 0x3C +#define M98095_03D_DAI3_CLKCFG_LO 0x3D +#define M98095_03E_DAI3_FORMAT 0x3E +#define M98095_03F_DAI3_CLOCK 0x3F +#define M98095_040_DAI3_IOCFG 0x40 +#define M98095_041_DAI3_TDM 0x41 +#define M98095_042_DAI3_FILTERS 0x42 +#define M98095_043_DAI3_LVL1 0x43 +#define M98095_044_DAI3_LVL2 0x44 +#define M98095_045_CFG_DSP 0x45 +#define M98095_046_DAC_CTRL1 0x46 +#define M98095_047_DAC_CTRL2 0x47 +#define M98095_048_MIX_DAC_LR 0x48 +#define M98095_049_MIX_DAC_M 0x49 +#define M98095_04A_MIX_ADC_LEFT 0x4A +#define M98095_04B_MIX_ADC_RIGHT 0x4B +#define M98095_04C_MIX_HP_LEFT 0x4C +#define M98095_04D_MIX_HP_RIGHT 0x4D +#define M98095_04E_CFG_HP 0x4E +#define M98095_04F_MIX_RCV 0x4F +#define M98095_050_MIX_SPK_LEFT 0x50 +#define M98095_051_MIX_SPK_RIGHT 0x51 +#define M98095_052_MIX_SPK_CFG 0x52 +#define M98095_053_MIX_LINEOUT1 0x53 +#define M98095_054_MIX_LINEOUT2 0x54 +#define M98095_055_MIX_LINEOUT_CFG 0x55 +#define M98095_056_LVL_SIDETONE_DAI12 0x56 +#define M98095_057_LVL_SIDETONE_DAI3 0x57 +#define M98095_058_LVL_DAI1_PLAY 0x58 +#define M98095_059_LVL_DAI1_EQ 0x59 +#define M98095_05A_LVL_DAI2_PLAY 0x5A +#define M98095_05B_LVL_DAI2_EQ 0x5B +#define M98095_05C_LVL_DAI3_PLAY 0x5C +#define M98095_05D_LVL_ADC_L 0x5D +#define M98095_05E_LVL_ADC_R 0x5E +#define M98095_05F_LVL_MIC1 0x5F +#define M98095_060_LVL_MIC2 0x60 +#define M98095_061_LVL_LINEIN 0x61 +#define M98095_062_LVL_LINEOUT1 0x62 +#define M98095_063_LVL_LINEOUT2 0x63 +#define M98095_064_LVL_HP_L 0x64 +#define M98095_065_LVL_HP_R 0x65 +#define M98095_066_LVL_RCV 0x66 +#define M98095_067_LVL_SPK_L 0x67 +#define M98095_068_LVL_SPK_R 0x68 +#define M98095_069_MICAGC_CFG 0x69 +#define M98095_06A_MICAGC_THRESH 0x6A +#define M98095_06B_SPK_NOISEGATE 0x6B +#define M98095_06C_DAI1_ALC1_TIME 0x6C +#define M98095_06D_DAI1_ALC1_COMP 0x6D +#define M98095_06E_DAI1_ALC1_EXPN 0x6E +#define M98095_06F_DAI1_ALC1_GAIN 0x6F +#define M98095_070_DAI1_ALC2_TIME 0x70 +#define M98095_071_DAI1_ALC2_COMP 0x71 +#define M98095_072_DAI1_ALC2_EXPN 0x72 +#define M98095_073_DAI1_ALC2_GAIN 0x73 +#define M98095_074_DAI1_ALC3_TIME 0x74 +#define M98095_075_DAI1_ALC3_COMP 0x75 +#define M98095_076_DAI1_ALC3_EXPN 0x76 +#define M98095_077_DAI1_ALC3_GAIN 0x77 +#define M98095_078_DAI2_ALC1_TIME 0x78 +#define M98095_079_DAI2_ALC1_COMP 0x79 +#define M98095_07A_DAI2_ALC1_EXPN 0x7A +#define M98095_07B_DAI2_ALC1_GAIN 0x7B +#define M98095_07C_DAI2_ALC2_TIME 0x7C +#define M98095_07D_DAI2_ALC2_COMP 0x7D +#define M98095_07E_DAI2_ALC2_EXPN 0x7E +#define M98095_07F_DAI2_ALC2_GAIN 0x7F +#define M98095_080_DAI2_ALC3_TIME 0x80 +#define M98095_081_DAI2_ALC3_COMP 0x81 +#define M98095_082_DAI2_ALC3_EXPN 0x82 +#define M98095_083_DAI2_ALC3_GAIN 0x83 +#define M98095_084_HP_NOISE_GATE 0x84 +#define M98095_085_AUX_ADC 0x85 +#define M98095_086_CFG_LINE 0x86 +#define M98095_087_CFG_MIC 0x87 +#define M98095_088_CFG_LEVEL 0x88 +#define M98095_089_JACK_DET_AUTO 0x89 +#define M98095_08A_JACK_DET_MANUAL 0x8A +#define M98095_08B_JACK_KEYSCAN_DBC 0x8B +#define M98095_08C_JACK_KEYSCAN_DLY 0x8C +#define M98095_08D_JACK_KEY_THRESH 0x8D +#define M98095_08E_JACK_DC_SLEW 0x8E +#define M98095_08F_JACK_TEST_CFG 0x8F +#define M98095_090_PWR_EN_IN 0x90 +#define M98095_091_PWR_EN_OUT 0x91 +#define M98095_092_PWR_EN_OUT 0x92 +#define M98095_093_BIAS_CTRL 0x93 +#define M98095_094_PWR_DAC_21 0x94 +#define M98095_095_PWR_DAC_03 0x95 +#define M98095_096_PWR_DAC_CK 0x96 +#define M98095_097_PWR_SYS 0x97 + +#define M98095_0FF_REV_ID 0xFF + +#define M98095_REG_CNT (0xFF+1) +#define M98095_REG_MAX_CACHED 0X97 + +/* MAX98095 Registers Bit Fields */ + +/* M98095_00F_HOST_CFG */ +#define M98095_SEG (1<<0) +#define M98095_XTEN (1<<1) +#define M98095_MDLLEN (1<<2) + +/* M98095_027_DAI1_CLKMODE, M98095_031_DAI2_CLKMODE, M98095_03B_DAI3_CLKMODE */ +#define M98095_CLKMODE_MASK 0xFF + +/* M98095_02A_DAI1_FORMAT, M98095_034_DAI2_FORMAT, M98095_03E_DAI3_FORMAT */ +#define M98095_DAI_MAS (1<<7) +#define M98095_DAI_WCI (1<<6) +#define M98095_DAI_BCI (1<<5) +#define M98095_DAI_DLY (1<<4) +#define M98095_DAI_TDM (1<<2) +#define M98095_DAI_FSW (1<<1) +#define M98095_DAI_WS (1<<0) + +/* M98095_02B_DAI1_CLOCK, M98095_035_DAI2_CLOCK, M98095_03F_DAI3_CLOCK */ +#define M98095_DAI_BSEL64 (1<<0) +#define M98095_DAI_DOSR_DIV2 (0<<5) +#define M98095_DAI_DOSR_DIV4 (1<<5) + +/* M98095_02C_DAI1_IOCFG, M98095_036_DAI2_IOCFG, M98095_040_DAI3_IOCFG */ +#define M98095_S1NORMAL (1<<6) +#define M98095_S2NORMAL (2<<6) +#define M98095_S3NORMAL (3<<6) +#define M98095_SDATA (3<<0) + +/* M98095_02E_DAI1_FILTERS, M98095_038_DAI2_FILTERS, M98095_042_DAI3_FILTERS */ +#define M98095_DAI_DHF (1<<3) + +/* M98095_045_DSP_CFG */ +#define M98095_DSPNORMAL (5<<4) + +/* M98095_048_MIX_DAC_LR */ +#define M98095_DAI1L_TO_DACR (1<<7) +#define M98095_DAI1R_TO_DACR (1<<6) +#define M98095_DAI2M_TO_DACR (1<<5) +#define M98095_DAI1L_TO_DACL (1<<3) +#define M98095_DAI1R_TO_DACL (1<<2) +#define M98095_DAI2M_TO_DACL (1<<1) +#define M98095_DAI3M_TO_DACL (1<<0) + +/* M98095_049_MIX_DAC_M */ +#define M98095_DAI1L_TO_DACM (1<<3) +#define M98095_DAI1R_TO_DACM (1<<2) +#define M98095_DAI2M_TO_DACM (1<<1) +#define M98095_DAI3M_TO_DACM (1<<0) + +/* M98095_04E_MIX_HP_CFG */ +#define M98095_HPNORMAL (3<<4) + +/* M98095_05F_LVL_MIC1, M98095_060_LVL_MIC2 */ +#define M98095_MICPRE_MASK (3<<5) +#define M98095_MICPRE_SHIFT 5 + +/* M98095_064_LVL_HP_L, M98095_065_LVL_HP_R */ +#define M98095_HP_MUTE (1<<7) + +/* M98095_066_LVL_RCV */ +#define M98095_REC_MUTE (1<<7) + +/* M98095_067_LVL_SPK_L, M98095_068_LVL_SPK_R */ +#define M98095_SP_MUTE (1<<7) + +/* M98095_087_CFG_MIC */ +#define M98095_MICSEL_MASK (3<<0) +#define M98095_DIGMIC_L (1<<2) +#define M98095_DIGMIC_R (1<<3) +#define M98095_DIGMIC2L (1<<4) +#define M98095_DIGMIC2R (1<<5) + +/* M98095_088_CFG_LEVEL */ +#define M98095_VSEN (1<<6) +#define M98095_ZDEN (1<<5) +#define M98095_BQ2EN (1<<3) +#define M98095_BQ1EN (1<<2) +#define M98095_EQ2EN (1<<1) +#define M98095_EQ1EN (1<<0) + +/* M98095_090_PWR_EN_IN */ +#define M98095_INEN (1<<7) +#define M98095_MB2EN (1<<3) +#define M98095_MB1EN (1<<2) +#define M98095_MBEN (3<<2) +#define M98095_ADREN (1<<1) +#define M98095_ADLEN (1<<0) + +/* M98095_091_PWR_EN_OUT */ +#define M98095_HPLEN (1<<7) +#define M98095_HPREN (1<<6) +#define M98095_SPLEN (1<<5) +#define M98095_SPREN (1<<4) +#define M98095_RECEN (1<<3) +#define M98095_DALEN (1<<1) +#define M98095_DAREN (1<<0) + +/* M98095_092_PWR_EN_OUT */ +#define M98095_SPK_FIXEDSPECTRUM (0<<4) +#define M98095_SPK_SPREADSPECTRUM (1<<4) + +/* M98095_097_PWR_SYS */ +#define M98095_SHDNRUN (1<<7) +#define M98095_PERFMODE (1<<3) +#define M98095_HPPLYBACK (1<<2) +#define M98095_PWRSV8K (1<<1) +#define M98095_PWRSV (1<<0) + +#define M98095_COEFS_PER_BAND 5 + +/* Equalizer filter coefficients */ +#define M98095_110_DAI1_EQ_BASE 0x10 +#define M98095_142_DAI2_EQ_BASE 0x42 + +/* Biquad filter coefficients */ +#define M98095_174_DAI1_BQ_BASE 0x74 +#define M98095_17E_DAI2_BQ_BASE 0x7E + +/* function prototype */ + +/* + * intialise max98095 sound codec device for the given configuration + * + * @param blob FDT node for codec values + * @param sampling_rate Sampling rate (Hz) + * @param mclk_freq MCLK Frequency (Hz) + * @param bits_per_sample bits per Sample (must be 16 or 24) + * + * @returns -1 for error and 0 Success. + */ +int max98095_init(const void *blob, int sampling_rate, int mclk_freq, + int bits_per_sample); + +#endif -- cgit v1.2.3 From 14d2dfc33a087cf98ae37e453edd294c7835caae Mon Sep 17 00:00:00 2001 From: Rajeshwari Shinde Date: Thu, 14 Feb 2013 19:46:13 +0000 Subject: Sound: Support for MAX98095 codec in driver This patchs adds support for MAX98095 codec in sound driver. Signed-off-by: Rajeshwari Shinde Acked-by: Simon Glass Signed-off-by: Minkyu Kang --- drivers/sound/sound.c | 9 +++++++-- include/sound.h | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/sound/sound.c b/drivers/sound/sound.c index fa8432d48a..a4bf4adcb3 100644 --- a/drivers/sound/sound.c +++ b/drivers/sound/sound.c @@ -31,6 +31,7 @@ #include #include #include "wm8994.h" +#include "max98095.h" /* defines */ #define SOUND_400_HZ 400 @@ -149,11 +150,15 @@ static int codec_init(const void *blob, struct i2stx_info *pi2s_tx) pi2s_tx->samplingrate, (pi2s_tx->samplingrate * (pi2s_tx->rfs)), pi2s_tx->bitspersample, pi2s_tx->channels); + } else if (!strcmp(codectype, "max98095")) { + ret = max98095_init(blob, pi2s_tx->samplingrate, + (pi2s_tx->samplingrate * (pi2s_tx->rfs)), + pi2s_tx->bitspersample); } else { - debug("%s: Unknown code type %s\n", __func__, - codectype); + debug("%s: Unknown codec type %s\n", __func__, codectype); return -1; } + if (ret) { debug("%s: Codec init failed\n", __func__); return -1; diff --git a/include/sound.h b/include/sound.h index d73839d9f0..94922f66da 100644 --- a/include/sound.h +++ b/include/sound.h @@ -28,6 +28,7 @@ enum en_sound_codec { CODEC_WM_8994, CODEC_WM_8995, + CODEC_MAX_98095, CODEC_MAX }; -- cgit v1.2.3 From ce07380534a9fc3cba2b3c1f97932d126ef9979a Mon Sep 17 00:00:00 2001 From: Rajeshwari Shinde Date: Thu, 14 Feb 2013 19:46:14 +0000 Subject: EXYNOS5: GPIO to enable MAX98095 This patch sets high a GPIO to enable the codec MAX98095 Signed-off-by: Rajeshwari Shinde Acked-by: Simon Glass Signed-off-by: Minkyu Kang --- board/samsung/smdk5250/smdk5250.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/board/samsung/smdk5250/smdk5250.c b/board/samsung/smdk5250/smdk5250.c index ffc5ee5a61..6f6f2c240f 100644 --- a/board/samsung/smdk5250/smdk5250.c +++ b/board/samsung/smdk5250/smdk5250.c @@ -56,6 +56,18 @@ int board_usb_vbus_init(void) } #endif +#ifdef CONFIG_SOUND_MAX98095 +static void board_enable_audio_codec(void) +{ + struct exynos5_gpio_part1 *gpio1 = (struct exynos5_gpio_part1 *) + samsung_get_base_gpio_part1(); + + /* Enable MAX98095 Codec */ + s5p_gpio_direction_output(&gpio1->x1, 7, 1); + s5p_gpio_set_pull(&gpio1->x1, 7, GPIO_PULL_NONE); +} +#endif + int board_init(void) { gd->bd->bi_boot_params = (PHYS_SDRAM_1 + 0x100UL); @@ -64,6 +76,9 @@ int board_init(void) #endif #ifdef CONFIG_USB_EHCI_EXYNOS board_usb_vbus_init(); +#endif +#ifdef CONFIG_SOUND_MAX98095 + board_enable_audio_codec(); #endif return 0; } -- cgit v1.2.3 From 7772bb787e50eb93544755dd8d21180d28a1f8ee Mon Sep 17 00:00:00 2001 From: Rajeshwari Shinde Date: Thu, 14 Feb 2013 19:46:15 +0000 Subject: EXYNOS5: FDT: Add compatible strings for MAX98095 Add required compatible information for MAX98095 codec Signed-off-by: Rajeshwari Shinde Acked-by: Simon Glass Signed-off-by: Minkyu Kang --- include/fdtdec.h | 1 + lib/fdtdec.c | 1 + 2 files changed, 2 insertions(+) diff --git a/include/fdtdec.h b/include/fdtdec.h index 77f244f417..b885a9578f 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -81,6 +81,7 @@ enum fdt_compat_id { COMPAT_SAMSUNG_EXYNOS_EHCI, /* Exynos EHCI controller */ COMPAT_SAMSUNG_EXYNOS_USB_PHY, /* Exynos phy controller for usb2.0 */ COMPAT_MAXIM_MAX77686_PMIC, /* MAX77686 PMIC */ + COMPAT_MAXIM_98095_CODEC, /* MAX98095 Codec */ COMPAT_COUNT, }; diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 3ae348dd30..9a527ffd82 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -56,6 +56,7 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(SAMSUNG_EXYNOS_EHCI, "samsung,exynos-ehci"), COMPAT(SAMSUNG_EXYNOS_USB_PHY, "samsung,exynos-usb-phy"), COMPAT(MAXIM_MAX77686_PMIC, "maxim,max77686_pmic"), + COMPAT(MAXIM_98095_CODEC, "maxim,max98095-codec"), }; const char *fdtdec_get_compatible(enum fdt_compat_id id) -- cgit v1.2.3 From cfa6df19091ec831a4767fe36907abb8a8e99f84 Mon Sep 17 00:00:00 2001 From: Rajeshwari Shinde Date: Thu, 14 Feb 2013 19:46:16 +0000 Subject: config: Snow: Enable MAX98095 codec This patch enables MAX98095 codec required for Snow Signed-off-by: Rajeshwari Shinde Acked-by: Simon Glass Signed-off-by: Minkyu Kang --- include/configs/exynos5250-dt.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/configs/exynos5250-dt.h b/include/configs/exynos5250-dt.h index cabd2f2524..89fcda5f40 100644 --- a/include/configs/exynos5250-dt.h +++ b/include/configs/exynos5250-dt.h @@ -296,6 +296,7 @@ #ifdef CONFIG_CMD_SOUND #define CONFIG_SOUND #define CONFIG_I2S +#define CONFIG_SOUND_MAX98095 #define CONFIG_SOUND_WM8994 #endif -- cgit v1.2.3 From c42ffff02a1edd24fc50e5efb33ead1bfa843a26 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 18 Feb 2013 20:32:59 +0000 Subject: EXYNOS: Correct ordering of SPL machine_params The mem_manuf is not in the correct order according to the string table. This causes cros_bundle_firmware to get the BL2 settings in the wrong order. This patch fixes the same. Signed-off-by: Simon Glass Signed-off-by: Rajeshwari Shinde Acked-by: Simon Glass Signed-off-by: Minkyu Kang --- arch/arm/include/asm/arch-exynos/spl.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/include/asm/arch-exynos/spl.h b/arch/arm/include/asm/arch-exynos/spl.h index 306b41d825..46b25a608b 100644 --- a/arch/arm/include/asm/arch-exynos/spl.h +++ b/arch/arm/include/asm/arch-exynos/spl.h @@ -78,11 +78,12 @@ struct spl_machine_param { */ u32 uboot_size; enum boot_mode boot_source; /* Boot device */ - enum mem_manuf mem_manuf; /* Memory Manufacturer */ unsigned frequency_mhz; /* Frequency of memory in MHz */ unsigned arm_freq_mhz; /* ARM Frequency in MHz */ u32 serial_base; /* Serial base address */ u32 i2c_base; /* i2c base address */ + u32 board_rev_gpios; /* Board revision GPIOs */ + enum mem_manuf mem_manuf; /* Memory Manufacturer */ } __attribute__((__packed__)); #endif -- cgit v1.2.3 From 07f17507c4309d3ccc1fbfd912d078a9ca609aba Mon Sep 17 00:00:00 2001 From: Rajeshwari Shinde Date: Mon, 18 Feb 2013 02:51:49 +0000 Subject: SMDK5250: FDT: Retrieve board model via DT Print out the board model by parsing the device tree file. Signed-off-by: Rajeshwari Shinde Acked-by: Simon Glass Signed-off-by: Minkyu Kang --- board/samsung/smdk5250/smdk5250.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/board/samsung/smdk5250/smdk5250.c b/board/samsung/smdk5250/smdk5250.c index 6f6f2c240f..0097b3fda7 100644 --- a/board/samsung/smdk5250/smdk5250.c +++ b/board/samsung/smdk5250/smdk5250.c @@ -336,8 +336,17 @@ int board_eth_init(bd_t *bis) #ifdef CONFIG_DISPLAY_BOARDINFO int checkboard(void) { - printf("\nBoard: SMDK5250\n"); +#ifdef CONFIG_OF_CONTROL + const char *board_name; + board_name = fdt_getprop(gd->fdt_blob, 0, "model", NULL); + if (board_name == NULL) + printf("\nUnknown Board\n"); + else + printf("\nBoard: %s\n", board_name); +#else + printf("\nBoard: SMDK5250\n"); +#endif return 0; } #endif -- cgit v1.2.3 From 39d182d3de5dcfaeb7d6997be4ab764081ff529e Mon Sep 17 00:00:00 2001 From: Akshay Saraswat Date: Mon, 25 Feb 2013 01:13:00 +0000 Subject: Exynos5: TMU: Add driver for Thermal Management Unit Adding Exynos Thermal Management Unit driver to monitor SOC temperature and take actions corresponding to states of TMU. Signed-off-by: Akshay Saraswat Acked-by: Simon Glass Signed-off-by: Minkyu Kang --- arch/arm/include/asm/arch-exynos/tmu.h | 58 +++++++ drivers/power/Makefile | 1 + drivers/power/exynos-tmu.c | 304 +++++++++++++++++++++++++++++++++ include/tmu.h | 46 +++++ 4 files changed, 409 insertions(+) create mode 100644 arch/arm/include/asm/arch-exynos/tmu.h create mode 100644 drivers/power/exynos-tmu.c create mode 100644 include/tmu.h diff --git a/arch/arm/include/asm/arch-exynos/tmu.h b/arch/arm/include/asm/arch-exynos/tmu.h new file mode 100644 index 0000000000..7e0158efb6 --- /dev/null +++ b/arch/arm/include/asm/arch-exynos/tmu.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * Akshay Saraswat + * + * EXYNOS - Thermal Management Unit + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __ASM_ARCH_TMU_H +#define __ASM_ARCH_TMU_H + +struct exynos5_tmu_reg { + unsigned triminfo; + unsigned rsvd1; + unsigned rsvd2; + unsigned rsvd3; + unsigned rsvd4; + unsigned triminfo_control; + unsigned rsvd5; + unsigned rsvd6; + unsigned tmu_control; + unsigned rsvd7; + unsigned tmu_status; + unsigned sampling_internal; + unsigned counter_value0; + unsigned counter_value1; + unsigned rsvd8; + unsigned rsvd9; + unsigned current_temp; + unsigned rsvd10; + unsigned rsvd11; + unsigned rsvd12; + unsigned threshold_temp_rise; + unsigned threshold_temp_fall; + unsigned rsvd13; + unsigned rsvd14; + unsigned past_temp3_0; + unsigned past_temp7_4; + unsigned past_temp11_8; + unsigned past_temp15_12; + unsigned inten; + unsigned intstat; + unsigned intclear; + unsigned rsvd15; + unsigned emul_con; +}; +#endif /* __ASM_ARCH_TMU_H */ diff --git a/drivers/power/Makefile b/drivers/power/Makefile index 8c7190156c..1dac16a9f7 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -25,6 +25,7 @@ include $(TOPDIR)/config.mk LIB := $(obj)libpower.o +COBJS-$(CONFIG_EXYNOS_TMU) += exynos-tmu.o COBJS-$(CONFIG_FTPMU010_POWER) += ftpmu010.o COBJS-$(CONFIG_TPS6586X_POWER) += tps6586x.o COBJS-$(CONFIG_TWL4030_POWER) += twl4030.o diff --git a/drivers/power/exynos-tmu.c b/drivers/power/exynos-tmu.c new file mode 100644 index 0000000000..d8313b1d3b --- /dev/null +++ b/drivers/power/exynos-tmu.c @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * Akshay Saraswat + * + * EXYNOS - Thermal Management Unit + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#define TRIMINFO_RELOAD 1 +#define CORE_EN 1 + +#define INTEN_RISE0 1 +#define INTEN_RISE1 (1 << 4) +#define INTEN_RISE2 (1 << 8) +#define INTEN_FALL0 (1 << 16) +#define INTEN_FALL1 (1 << 20) +#define INTEN_FALL2 (1 << 24) + +#define TRIM_INFO_MASK 0xff + +#define INTCLEAR_RISE0 1 +#define INTCLEAR_RISE1 (1 << 4) +#define INTCLEAR_RISE2 (1 << 8) +#define INTCLEAR_FALL0 (1 << 16) +#define INTCLEAR_FALL1 (1 << 20) +#define INTCLEAR_FALL2 (1 << 24) +#define INTCLEARALL (INTCLEAR_RISE0 | INTCLEAR_RISE1 | \ + INTCLEAR_RISE2 | INTCLEAR_FALL0 | \ + INTCLEAR_FALL1 | INTCLEAR_FALL2) + +/* Tmeperature threshold values for various thermal events */ +struct temperature_params { + /* minimum value in temperature code range */ + unsigned int min_val; + /* maximum value in temperature code range */ + unsigned int max_val; + /* temperature threshold to start warning */ + unsigned int start_warning; + /* temperature threshold CPU tripping */ + unsigned int start_tripping; +}; + +/* Pre-defined values and thresholds for calibration of current temperature */ +struct tmu_data { + /* pre-defined temperature thresholds */ + struct temperature_params ts; + /* pre-defined efuse range minimum value */ + unsigned int efuse_min_value; + /* pre-defined efuse value for temperature calibration */ + unsigned int efuse_value; + /* pre-defined efuse range maximum value */ + unsigned int efuse_max_value; + /* current temperature sensing slope */ + unsigned int slope; +}; + +/* TMU device specific details and status */ +struct tmu_info { + /* base Address for the TMU */ + unsigned tmu_base; + /* pre-defined values for calibration and thresholds */ + struct tmu_data data; + /* value required for triminfo_25 calibration */ + unsigned int te1; + /* value required for triminfo_85 calibration */ + unsigned int te2; + /* Value for measured data calibration */ + int dc_value; + /* enum value indicating status of the TMU */ + int tmu_state; +}; + +/* Global struct tmu_info variable to store init values */ +static struct tmu_info gbl_info; + +/* + * Get current temperature code from register, + * then calculate and calibrate it's value + * in degree celsius. + * + * @return current temperature of the chip as sensed by TMU + */ +static int get_cur_temp(struct tmu_info *info) +{ + int cur_temp; + struct exynos5_tmu_reg *reg = (struct exynos5_tmu_reg *)info->tmu_base; + + /* + * Temperature code range between min 25 and max 125. + * May run more than once for first call as initial sensing + * has not yet happened. + */ + do { + cur_temp = readl(®->current_temp) & 0xff; + } while (cur_temp == 0 && info->tmu_state == TMU_STATUS_NORMAL); + + /* Calibrate current temperature */ + cur_temp = cur_temp - info->te1 + info->dc_value; + + return cur_temp; +} + +/* + * Monitors status of the TMU device and exynos temperature + * + * @param temp pointer to the current temperature value + * @return enum tmu_status_t value, code indicating event to execute + */ +enum tmu_status_t tmu_monitor(int *temp) +{ + int cur_temp; + struct tmu_data *data = &gbl_info.data; + + if (gbl_info.tmu_state == TMU_STATUS_INIT) + return TMU_STATUS_INIT; + + /* Read current temperature of the SOC */ + cur_temp = get_cur_temp(&gbl_info); + *temp = cur_temp; + + /* Temperature code lies between min 25 and max 125 */ + if (cur_temp >= data->ts.start_tripping && + cur_temp <= data->ts.max_val) { + return TMU_STATUS_TRIPPED; + } else if (cur_temp >= data->ts.start_warning) { + return TMU_STATUS_WARNING; + } else if (cur_temp < data->ts.start_warning && + cur_temp >= data->ts.min_val) { + return TMU_STATUS_NORMAL; + } else { + /* Temperature code does not lie between min 25 and max 125 */ + gbl_info.tmu_state = TMU_STATUS_INIT; + debug("EXYNOS_TMU: Thermal reading failed\n"); + return TMU_STATUS_INIT; + } +} + +/* + * Get TMU specific pre-defined values from FDT + * + * @param info pointer to the tmu_info struct + * @param blob FDT blob + * @return int value, 0 for success + */ +static int get_tmu_fdt_values(struct tmu_info *info, const void *blob) +{ +#ifdef CONFIG_OF_CONTROL + int node; + int error = 0; + + /* Get the node from FDT for TMU */ + node = fdtdec_next_compatible(blob, 0, + COMPAT_SAMSUNG_EXYNOS_TMU); + if (node < 0) { + debug("EXYNOS_TMU: No node for tmu in device tree\n"); + return -1; + } + + /* + * Get the pre-defined TMU specific values from FDT. + * All of these are expected to be correct otherwise + * miscalculation of register values in tmu_setup_parameters + * may result in misleading current temperature. + */ + info->tmu_base = fdtdec_get_addr(blob, node, "reg"); + if (info->tmu_base == FDT_ADDR_T_NONE) { + debug("%s: Missing tmu-base\n", __func__); + return -1; + } + info->data.ts.min_val = fdtdec_get_int(blob, + node, "samsung,min-temp", -1); + error |= info->data.ts.min_val; + info->data.ts.max_val = fdtdec_get_int(blob, + node, "samsung,max-temp", -1); + error |= info->data.ts.max_val; + info->data.ts.start_warning = fdtdec_get_int(blob, + node, "samsung,start-warning", -1); + error |= info->data.ts.start_warning; + info->data.ts.start_tripping = fdtdec_get_int(blob, + node, "samsung,start-tripping", -1); + error |= info->data.ts.start_tripping; + info->data.efuse_min_value = fdtdec_get_int(blob, + node, "samsung,efuse-min-value", -1); + error |= info->data.efuse_min_value; + info->data.efuse_value = fdtdec_get_int(blob, + node, "samsung,efuse-value", -1); + error |= info->data.efuse_value; + info->data.efuse_max_value = fdtdec_get_int(blob, + node, "samsung,efuse-max-value", -1); + error |= info->data.efuse_max_value; + info->data.slope = fdtdec_get_int(blob, + node, "samsung,slope", -1); + error |= info->data.slope; + info->dc_value = fdtdec_get_int(blob, + node, "samsung,dc-value", -1); + error |= info->dc_value; + + if (error == -1) { + debug("fail to get tmu node properties\n"); + return -1; + } +#endif + + return 0; +} + +/* + * Calibrate and calculate threshold values and + * enable interrupt levels + * + * @param info pointer to the tmu_info struct + */ +static void tmu_setup_parameters(struct tmu_info *info) +{ + unsigned int te_code, con; + unsigned int warning_code, trip_code; + unsigned int cooling_temp; + unsigned int rising_value; + struct tmu_data *data = &info->data; + struct exynos5_tmu_reg *reg = (struct exynos5_tmu_reg *)info->tmu_base; + + /* Must reload for reading efuse value from triminfo register */ + writel(TRIMINFO_RELOAD, ®->triminfo_control); + + /* Get the compensation parameter */ + te_code = readl(®->triminfo); + info->te1 = te_code & TRIM_INFO_MASK; + info->te2 = ((te_code >> 8) & TRIM_INFO_MASK); + + if ((data->efuse_min_value > info->te1) || + (info->te1 > data->efuse_max_value) + || (info->te2 != 0)) + info->te1 = data->efuse_value; + + /* Get RISING & FALLING Threshold value */ + warning_code = data->ts.start_warning + + info->te1 - info->dc_value; + trip_code = data->ts.start_tripping + + info->te1 - info->dc_value; + cooling_temp = 0; + + rising_value = ((warning_code << 8) | (trip_code << 16)); + + /* Set interrupt level */ + writel(rising_value, ®->threshold_temp_rise); + writel(cooling_temp, ®->threshold_temp_fall); + + /* + * Init TMU control tuning parameters + * [28:24] VREF - Voltage reference + * [15:13] THERM_TRIP_MODE - Tripping mode + * [12] THERM_TRIP_EN - Thermal tripping enable + * [11:8] BUF_SLOPE_SEL - Gain of amplifier + * [6] THERM_TRIP_BY_TQ_EN - Tripping by TQ pin + */ + writel(data->slope, ®->tmu_control); + + writel(INTCLEARALL, ®->intclear); + + /* TMU core enable */ + con = readl(®->tmu_control); + con |= CORE_EN; + + writel(con, ®->tmu_control); + + /* LEV0 LEV1 LEV2 interrupt enable */ + writel(INTEN_RISE0 | INTEN_RISE1 | INTEN_RISE2, ®->inten); +} + +/* + * Initialize TMU device + * + * @param blob FDT blob + * @return int value, 0 for success + */ +int tmu_init(const void *blob) +{ + gbl_info.tmu_state = TMU_STATUS_INIT; + if (get_tmu_fdt_values(&gbl_info, blob) < 0) + goto ret; + + tmu_setup_parameters(&gbl_info); + gbl_info.tmu_state = TMU_STATUS_NORMAL; +ret: + + return gbl_info.tmu_state; +} diff --git a/include/tmu.h b/include/tmu.h new file mode 100644 index 0000000000..da07a2211e --- /dev/null +++ b/include/tmu.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * Akshay Saraswat + * + * Thermal Management Unit + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _TMU_H +#define _TMU_H + +enum tmu_status_t { + TMU_STATUS_INIT = -1, + TMU_STATUS_NORMAL = 0, + TMU_STATUS_WARNING, + TMU_STATUS_TRIPPED, +}; + +/* + * Monitors status of the TMU device and exynos temperature + * + * @param temp pointer to the current temperature value + * @return enum tmu_status_t value, code indicating event to execute + * and -1 on error + */ +enum tmu_status_t tmu_monitor(int *temp); + +/* + * Initialize TMU device + * + * @param blob FDT blob + * @return int value, 0 for success + */ +int tmu_init(const void *blob); +#endif /* _THERMAL_H_ */ -- cgit v1.2.3 From 618766c09855f7167f510eafa89172ae44cae543 Mon Sep 17 00:00:00 2001 From: Akshay Saraswat Date: Mon, 25 Feb 2013 01:13:01 +0000 Subject: Exynos5: FDT: Add TMU device node values Fdt entry for Exynos TMU driver specific pre-defined values used for calibration of current temperature and defining threshold values. Signed-off-by: Akshay Saraswat Acked-by: Simon Glass Signed-off-by: Minkyu Kang --- arch/arm/dts/exynos5250.dtsi | 5 ++++ board/samsung/dts/exynos5250-smdk5250.dts | 12 +++++++++ doc/device-tree-bindings/exynos/tmu.txt | 41 +++++++++++++++++++++++++++++++ include/fdtdec.h | 1 + lib/fdtdec.c | 1 + 5 files changed, 60 insertions(+) create mode 100644 doc/device-tree-bindings/exynos/tmu.txt diff --git a/arch/arm/dts/exynos5250.dtsi b/arch/arm/dts/exynos5250.dtsi index ed8c8dd606..61d35a83ea 100644 --- a/arch/arm/dts/exynos5250.dtsi +++ b/arch/arm/dts/exynos5250.dtsi @@ -151,4 +151,9 @@ }; }; + tmu@10060000 { + compatible = "samsung,exynos-tmu"; + reg = <0x10060000 0x10000>; + }; + }; diff --git a/board/samsung/dts/exynos5250-smdk5250.dts b/board/samsung/dts/exynos5250-smdk5250.dts index cbfab6f97f..00dac40b39 100644 --- a/board/samsung/dts/exynos5250-smdk5250.dts +++ b/board/samsung/dts/exynos5250-smdk5250.dts @@ -66,4 +66,16 @@ compatible = "maxim,max77686_pmic"; }; }; + + tmu@10060000 { + samsung,min-temp = <25>; + samsung,max-temp = <125>; + samsung,start-warning = <95>; + samsung,start-tripping = <105>; + samsung,efuse-min-value = <40>; + samsung,efuse-value = <55>; + samsung,efuse-max-value = <100>; + samsung,slope = <274761730>; + samsung,dc-value = <25>; + }; }; diff --git a/doc/device-tree-bindings/exynos/tmu.txt b/doc/device-tree-bindings/exynos/tmu.txt new file mode 100644 index 0000000000..bb734dcaca --- /dev/null +++ b/doc/device-tree-bindings/exynos/tmu.txt @@ -0,0 +1,41 @@ +Exynos Thermal management Unit + +Required properties: + + - compatible : Should be "samsung,exynos-tmu" for TMU + - samsung,min-temp : Minimum temperature value (25 degree celsius) + - Current temperature of SoC should be more than this value. + - samsung,max-temp : Maximum temperature value (125 degree celsius) + - Current temperature of SoC should be less than this value. + - samsung,start-warning : Temperature at which TMU starts giving warning (degree celsius) + - samsung,start-tripping : Temperature at which system will trip and shutdown (degree celsius) + - samsung,efuse-min-value : SOC efuse min value (Constant 40) + - efuse-value should be more than this value. + - samsung,efuse-value : SOC actual efuse value (Literal value) + - This is the data trimming info. + - This value is used to calculate measuring error. + - samsung,efuse-max-value : SoC max efuse value (Constant 100) + - efuse-value should be less than this value. + - samsung,slope : Default value 274761730 (Constant 0x1060_8802). + - This is the default value for TMU_CONTROL register. + - It sets the gain of amplifier to the positive-tc generator block. + - It selects thermal tripping mode and enables thermal tripping. + - samsung,dc-value : Measured data calibration value (Constant 25) + - Used for tempearture calculation. + - This is 25 because temperature measured is always above 25 degrees. + + +Example: + +tmu@10060000 { + compatible = "samsung,exynos-tmu" + samsung,min-temp = <25>; + samsung,max-temp = <125>; + samsung,start-warning = <95>; + samsung,start-tripping = <105>; + samsung,efuse-min-value = <40>; + samsung,efuse-value = <55>; + samsung,efuse-max-value = <100>; + samsung,slope = <274761730>; + samsung,dc-value = <25>; +}; diff --git a/include/fdtdec.h b/include/fdtdec.h index b885a9578f..6552942116 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -80,6 +80,7 @@ enum fdt_compat_id { COMPAT_SAMSUNG_EXYNOS_SPI, /* Exynos SPI */ COMPAT_SAMSUNG_EXYNOS_EHCI, /* Exynos EHCI controller */ COMPAT_SAMSUNG_EXYNOS_USB_PHY, /* Exynos phy controller for usb2.0 */ + COMPAT_SAMSUNG_EXYNOS_TMU, /* Exynos TMU */ COMPAT_MAXIM_MAX77686_PMIC, /* MAX77686 PMIC */ COMPAT_MAXIM_98095_CODEC, /* MAX98095 Codec */ diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 9a527ffd82..88f6b68270 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -55,6 +55,7 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(SAMSUNG_EXYNOS_SPI, "samsung,exynos-spi"), COMPAT(SAMSUNG_EXYNOS_EHCI, "samsung,exynos-ehci"), COMPAT(SAMSUNG_EXYNOS_USB_PHY, "samsung,exynos-usb-phy"), + COMPAT(SAMSUNG_EXYNOS_TMU, "samsung,exynos-tmu"), COMPAT(MAXIM_MAX77686_PMIC, "maxim,max77686_pmic"), COMPAT(MAXIM_98095_CODEC, "maxim,max98095-codec"), }; -- cgit v1.2.3 From 7e30ad8bf3c6f7768158ad994b9180c6906fa5da Mon Sep 17 00:00:00 2001 From: Akshay Saraswat Date: Mon, 25 Feb 2013 01:13:02 +0000 Subject: Exynos5: TMU: Add TMU init and status check This adds call to tmu_init() and TMU boot time analysis for the SoC temperature threshold breach. Signed-off-by: Akshay Saraswat Acked-by: Simon Glass Signed-off-by: Minkyu Kang --- board/samsung/smdk5250/smdk5250.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/board/samsung/smdk5250/smdk5250.c b/board/samsung/smdk5250/smdk5250.c index 0097b3fda7..217c6df301 100644 --- a/board/samsung/smdk5250/smdk5250.c +++ b/board/samsung/smdk5250/smdk5250.c @@ -37,9 +37,39 @@ #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; +#if defined CONFIG_EXYNOS_TMU +/* + * Boot Time Thermal Analysis for SoC temperature threshold breach + */ +static void boot_temp_check(void) +{ + int temp; + + switch (tmu_monitor(&temp)) { + /* Status TRIPPED ans WARNING means corresponding threshold breach */ + case TMU_STATUS_TRIPPED: + puts("EXYNOS_TMU: TRIPPING! Device power going down ...\n"); + set_ps_hold_ctrl(); + hang(); + break; + case TMU_STATUS_WARNING: + puts("EXYNOS_TMU: WARNING! Temperature very high\n"); + break; + /* + * TMU_STATUS_INIT means something is wrong with temperature sensing + * and TMU status was changed back from NORMAL to INIT. + */ + case TMU_STATUS_INIT: + default: + debug("EXYNOS_TMU: Unknown TMU state\n"); + } +} +#endif + #ifdef CONFIG_USB_EHCI_EXYNOS int board_usb_vbus_init(void) { @@ -71,6 +101,15 @@ static void board_enable_audio_codec(void) int board_init(void) { gd->bd->bi_boot_params = (PHYS_SDRAM_1 + 0x100UL); + +#if defined CONFIG_EXYNOS_TMU + if (tmu_init(gd->fdt_blob) != TMU_STATUS_NORMAL) { + debug("%s: Failed to init TMU\n", __func__); + return -1; + } + boot_temp_check(); +#endif + #ifdef CONFIG_EXYNOS_SPI spi_init(); #endif -- cgit v1.2.3 From f7f85f7dc32143593d8e2ed85f3ab844c9c9c0ff Mon Sep 17 00:00:00 2001 From: Akshay Saraswat Date: Mon, 25 Feb 2013 01:13:03 +0000 Subject: Exynos5: Config: Enable support for Exynos TMU driver Enables TMU driver support for exynos5250 Signed-off-by: Akshay Saraswat Acked-by: Simon Glass Signed-off-by: Minkyu Kang --- include/configs/exynos5250-dt.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/configs/exynos5250-dt.h b/include/configs/exynos5250-dt.h index 89fcda5f40..fe9a3c6ed6 100644 --- a/include/configs/exynos5250-dt.h +++ b/include/configs/exynos5250-dt.h @@ -117,6 +117,9 @@ #define CONFIG_BOOTDELAY 3 #define CONFIG_ZERO_BOOTDELAY_CHECK +/* Thermal Management Unit */ +#define CONFIG_EXYNOS_TMU + /* USB */ #define CONFIG_CMD_USB #define CONFIG_USB_EHCI -- cgit v1.2.3 From bc5478b2757c9ee0068056206ea52f93ada544c8 Mon Sep 17 00:00:00 2001 From: Akshay Saraswat Date: Mon, 25 Feb 2013 01:13:04 +0000 Subject: TMU: Add TMU support in dtt command Add generic TMU support alongwith i2c sensors in dtt command to enable temperature reading in cases where TMU is present along-with/instead-of i2c sensors. Signed-off-by: Akshay Saraswat Acked-by: Simon Glass Signed-off-by: Minkyu Kang --- common/cmd_dtt.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/common/cmd_dtt.c b/common/cmd_dtt.c index cd94423d21..edbd4a83ca 100644 --- a/common/cmd_dtt.c +++ b/common/cmd_dtt.c @@ -27,7 +27,9 @@ #include #include +#include +#if defined CONFIG_DTT_SENSORS static unsigned long sensor_initialized; static void _initialize_dtt(void) @@ -59,9 +61,11 @@ void dtt_init(void) /* switch back to original I2C bus */ I2C_SET_BUS(old_bus); } +#endif -int do_dtt (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) +int dtt_i2c(void) { +#if defined CONFIG_DTT_SENSORS int i; unsigned char sensors[] = CONFIG_DTT_SENSORS; int old_bus; @@ -83,8 +87,34 @@ int do_dtt (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) /* switch back to original I2C bus */ I2C_SET_BUS(old_bus); +#endif return 0; +} + +int dtt_tmu(void) +{ +#if defined CONFIG_TMU_CMD_DTT + int cur_temp; + + /* Sense and return latest thermal info */ + if (tmu_monitor(&cur_temp) == TMU_STATUS_INIT) { + puts("TMU is in unknown state, temperature is invalid\n"); + return -1; + } + printf("Current temperature: %u degrees Celsius\n", cur_temp); +#endif + return 0; +} + +int do_dtt(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ + int err = 0; + + err |= dtt_i2c(); + err |= dtt_tmu(); + + return err; } /* do_dtt() */ /***************************************************/ -- cgit v1.2.3 From 8afcfc212415b8bacdf08b752aef7976e7da52a8 Mon Sep 17 00:00:00 2001 From: Akshay Saraswat Date: Mon, 25 Feb 2013 01:13:05 +0000 Subject: Exynos5: Config: Enable dtt command for TMU This enables the dtt command to read the current SOC temperature with the help of TMU Signed-off-by: Akshay Saraswat Acked-by: Simon Glass Signed-off-by: Minkyu Kang --- include/configs/exynos5250-dt.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/configs/exynos5250-dt.h b/include/configs/exynos5250-dt.h index fe9a3c6ed6..f334d4595a 100644 --- a/include/configs/exynos5250-dt.h +++ b/include/configs/exynos5250-dt.h @@ -119,6 +119,8 @@ /* Thermal Management Unit */ #define CONFIG_EXYNOS_TMU +#define CONFIG_CMD_DTT +#define CONFIG_TMU_CMD_DTT /* USB */ #define CONFIG_CMD_USB -- cgit v1.2.3 From 3a0b1dae5b9b853559b87a2332a27d1ed6a91fb8 Mon Sep 17 00:00:00 2001 From: Akshay Saraswat Date: Mon, 25 Feb 2013 01:13:06 +0000 Subject: Exynos5: TMU: Add hardware tripping This adds hardware tripping at 110 degrees celsius which must enable forced system shutdown in case TMU fails to power off. Signed-off-by: Akshay Saraswat Acked-by: Simon Glass Signed-off-by: Minkyu Kang --- arch/arm/cpu/armv7/exynos/power.c | 12 ++++++++++++ arch/arm/include/asm/arch-exynos/power.h | 4 ++++ drivers/power/exynos-tmu.c | 25 ++++++++++++++++++++----- 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/arch/arm/cpu/armv7/exynos/power.c b/arch/arm/cpu/armv7/exynos/power.c index db7249ef7f..6375a81fd4 100644 --- a/arch/arm/cpu/armv7/exynos/power.c +++ b/arch/arm/cpu/armv7/exynos/power.c @@ -128,3 +128,15 @@ void set_xclkout(void) if (cpu_is_exynos5()) exynos5_set_xclkout(); } + +/* Enables hardware tripping to power off the system when TMU fails */ +void set_hw_thermal_trip(void) +{ + if (cpu_is_exynos5()) { + struct exynos5_power *power = + (struct exynos5_power *)samsung_get_base_power(); + + /* PS_HOLD_CONTROL register ENABLE_HW_TRIP bit*/ + setbits_le32(&power->ps_hold_control, POWER_ENABLE_HW_TRIP); + } +} diff --git a/arch/arm/include/asm/arch-exynos/power.h b/arch/arm/include/asm/arch-exynos/power.h index 5f2633763c..3549667d91 100644 --- a/arch/arm/include/asm/arch-exynos/power.h +++ b/arch/arm/include/asm/arch-exynos/power.h @@ -857,6 +857,9 @@ void set_mipi_phy_ctrl(unsigned int dev_index, unsigned int enable); void set_usbhost_phy_ctrl(unsigned int enable); +/* Enables hardware tripping to power off the system when TMU fails */ +void set_hw_thermal_trip(void); + #define POWER_USB_HOST_PHY_CTRL_EN (1 << 0) #define POWER_USB_HOST_PHY_CTRL_DISABLE (0 << 0) @@ -865,6 +868,7 @@ void set_dp_phy_ctrl(unsigned int enable); #define EXYNOS_DP_PHY_ENABLE (1 << 0) #define EXYNOS_PS_HOLD_CONTROL_DATA_HIGH (1 << 8) +#define POWER_ENABLE_HW_TRIP (1UL << 31) /* * Set ps_hold data driving value high diff --git a/drivers/power/exynos-tmu.c b/drivers/power/exynos-tmu.c index d8313b1d3b..d4b3e65a3e 100644 --- a/drivers/power/exynos-tmu.c +++ b/drivers/power/exynos-tmu.c @@ -22,9 +22,11 @@ #include #include #include +#include #define TRIMINFO_RELOAD 1 #define CORE_EN 1 +#define THERM_TRIP_EN (1 << 12) #define INTEN_RISE0 1 #define INTEN_RISE1 (1 << 4) @@ -55,6 +57,8 @@ struct temperature_params { unsigned int start_warning; /* temperature threshold CPU tripping */ unsigned int start_tripping; + /* temperature threshold for HW tripping */ + unsigned int hardware_tripping; }; /* Pre-defined values and thresholds for calibration of current temperature */ @@ -196,6 +200,9 @@ static int get_tmu_fdt_values(struct tmu_info *info, const void *blob) info->data.ts.start_tripping = fdtdec_get_int(blob, node, "samsung,start-tripping", -1); error |= info->data.ts.start_tripping; + info->data.ts.hardware_tripping = fdtdec_get_int(blob, + node, "samsung,hw-tripping", -1); + error |= info->data.ts.hardware_tripping; info->data.efuse_min_value = fdtdec_get_int(blob, node, "samsung,efuse-min-value", -1); error |= info->data.efuse_min_value; @@ -230,7 +237,7 @@ static int get_tmu_fdt_values(struct tmu_info *info, const void *blob) static void tmu_setup_parameters(struct tmu_info *info) { unsigned int te_code, con; - unsigned int warning_code, trip_code; + unsigned int warning_code, trip_code, hwtrip_code; unsigned int cooling_temp; unsigned int rising_value; struct tmu_data *data = &info->data; @@ -254,9 +261,14 @@ static void tmu_setup_parameters(struct tmu_info *info) + info->te1 - info->dc_value; trip_code = data->ts.start_tripping + info->te1 - info->dc_value; + hwtrip_code = data->ts.hardware_tripping + + info->te1 - info->dc_value; + cooling_temp = 0; - rising_value = ((warning_code << 8) | (trip_code << 16)); + rising_value = ((warning_code << 8) | + (trip_code << 16) | + (hwtrip_code << 24)); /* Set interrupt level */ writel(rising_value, ®->threshold_temp_rise); @@ -276,12 +288,15 @@ static void tmu_setup_parameters(struct tmu_info *info) /* TMU core enable */ con = readl(®->tmu_control); - con |= CORE_EN; + con |= THERM_TRIP_EN | CORE_EN; writel(con, ®->tmu_control); - /* LEV0 LEV1 LEV2 interrupt enable */ - writel(INTEN_RISE0 | INTEN_RISE1 | INTEN_RISE2, ®->inten); + /* Enable HW thermal trip */ + set_hw_thermal_trip(); + + /* LEV1 LEV2 interrupt enable */ + writel(INTEN_RISE1 | INTEN_RISE2, ®->inten); } /* -- cgit v1.2.3 From 871333fcfe3b0865f37a803e010f7b06d6e546f2 Mon Sep 17 00:00:00 2001 From: Akshay Saraswat Date: Mon, 25 Feb 2013 01:13:07 +0000 Subject: Exynos5: FDT: Add a H/W-trip member to TMU node This adds a member to TMU FDT node for providing hardware tripping temperature threshold. Signed-off-by: Akshay Saraswat Acked-by: Simon Glass Signed-off-by: Minkyu Kang --- board/samsung/dts/exynos5250-smdk5250.dts | 1 + doc/device-tree-bindings/exynos/tmu.txt | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/board/samsung/dts/exynos5250-smdk5250.dts b/board/samsung/dts/exynos5250-smdk5250.dts index 00dac40b39..1c2d52d622 100644 --- a/board/samsung/dts/exynos5250-smdk5250.dts +++ b/board/samsung/dts/exynos5250-smdk5250.dts @@ -72,6 +72,7 @@ samsung,max-temp = <125>; samsung,start-warning = <95>; samsung,start-tripping = <105>; + samsung,hw-tripping = <110>; samsung,efuse-min-value = <40>; samsung,efuse-value = <55>; samsung,efuse-max-value = <100>; diff --git a/doc/device-tree-bindings/exynos/tmu.txt b/doc/device-tree-bindings/exynos/tmu.txt index bb734dcaca..89d3bf05f7 100644 --- a/doc/device-tree-bindings/exynos/tmu.txt +++ b/doc/device-tree-bindings/exynos/tmu.txt @@ -8,7 +8,9 @@ Required properties: - samsung,max-temp : Maximum temperature value (125 degree celsius) - Current temperature of SoC should be less than this value. - samsung,start-warning : Temperature at which TMU starts giving warning (degree celsius) - - samsung,start-tripping : Temperature at which system will trip and shutdown (degree celsius) + - samsung,start-tripping : Temperature at which TMU shuts down the system (degree celsius) + - samsung,hw-tripping : Temperature at which hardware tripping should happen + in case TMU fails to power off (degree celsius) - samsung,efuse-min-value : SOC efuse min value (Constant 40) - efuse-value should be more than this value. - samsung,efuse-value : SOC actual efuse value (Literal value) @@ -33,6 +35,7 @@ tmu@10060000 { samsung,max-temp = <125>; samsung,start-warning = <95>; samsung,start-tripping = <105>; + samsung,hw-tripping = <110>; samsung,efuse-min-value = <40>; samsung,efuse-value = <55>; samsung,efuse-max-value = <100>; -- cgit v1.2.3 From 2881e533472bffbf7cfa3afedb05b18cca574648 Mon Sep 17 00:00:00 2001 From: Rajeshwari Shinde Date: Thu, 28 Feb 2013 01:40:41 +0000 Subject: EXYNOS5: Add initial DTS file for Snow. This patch adds the DTS file for Snow Board. Signed-off-by: Rajeshwari Shinde Acked-by: Simon Glass Signed-off-by: Minkyu Kang --- board/samsung/dts/exynos5250-snow.dts | 58 +++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 board/samsung/dts/exynos5250-snow.dts diff --git a/board/samsung/dts/exynos5250-snow.dts b/board/samsung/dts/exynos5250-snow.dts new file mode 100644 index 0000000000..8b303bf4e4 --- /dev/null +++ b/board/samsung/dts/exynos5250-snow.dts @@ -0,0 +1,58 @@ +/* + * SAMSUNG Snow board device tree source + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * 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. +*/ + +/dts-v1/; +/include/ ARCH_CPU_DTS + +/ { + model = "Google Snow"; + compatible = "google,snow", "samsung,exynos5250"; + + aliases { + i2c0 = "/i2c@12c60000"; + i2c1 = "/i2c@12c70000"; + i2c2 = "/i2c@12c80000"; + i2c3 = "/i2c@12c90000"; + i2c4 = "/i2c@12ca0000"; + i2c5 = "/i2c@12cb0000"; + i2c6 = "/i2c@12cc0000"; + i2c7 = "/i2c@12cd0000"; + spi0 = "/spi@12d20000"; + spi1 = "/spi@12d30000"; + spi2 = "/spi@12d40000"; + spi3 = "/spi@131a0000"; + spi4 = "/spi@131b0000"; + }; + + sound@12d60000 { + samsung,i2s-epll-clock-frequency = <192000000>; + samsung,i2s-sampling-rate = <48000>; + samsung,i2s-bits-per-sample = <16>; + samsung,i2s-channels = <2>; + samsung,i2s-lr-clk-framesize = <256>; + samsung,i2s-bit-clk-framesize = <32>; + samsung,codec-type = "max98095"; + }; + + i2c@12cd0000 { + soundcodec@22 { + reg = <0x22>; + compatible = "maxim,max98095-codec"; + }; + }; + + i2c@12c60000 { + pmic@9 { + reg = <0x9>; + compatible = "maxim,max77686_pmic"; + }; + }; +}; -- cgit v1.2.3 From d4ea072ca633d3acb9b74281f05fc30a7e6cda73 Mon Sep 17 00:00:00 2001 From: Rajeshwari Shinde Date: Thu, 28 Feb 2013 01:40:42 +0000 Subject: EXYNOS5: Snow: Add a configuration file This patch adds the configuration file for Snow Board and defines the same in boards.cfg. Signed-off-by: Rajeshwari Shinde Acked-by: Simon Glass Signed-off-by: Minkyu Kang --- MAINTAINERS | 4 ++++ boards.cfg | 1 + include/configs/snow.h | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+) create mode 100644 include/configs/snow.h diff --git a/MAINTAINERS b/MAINTAINERS index 45e2dd4541..f6723efc84 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -910,6 +910,10 @@ Matt Sealey Bo Shen at91sam9x5ek ARM926EJS (AT91SAM9G15,G25,G35,X25,X35 SoC) +Rajeshwari Shinde + + snow ARM ARMV7 (EXYNOS5250 SoC) + Michal Simek zynq ARM ARMV7 (Zynq SoC) diff --git a/boards.cfg b/boards.cfg index b1319aace0..54357eb5a2 100644 --- a/boards.cfg +++ b/boards.cfg @@ -286,6 +286,7 @@ s5p_goni arm armv7 goni samsung smdkc100 arm armv7 smdkc100 samsung s5pc1xx origen arm armv7 origen samsung exynos s5pc210_universal arm armv7 universal_c210 samsung exynos +snow arm armv7 smdk5250 samsung exynos smdk5250 arm armv7 smdk5250 samsung exynos smdkv310 arm armv7 smdkv310 samsung exynos trats arm armv7 trats samsung exynos diff --git a/include/configs/snow.h b/include/configs/snow.h new file mode 100644 index 0000000000..b8460fd1b4 --- /dev/null +++ b/include/configs/snow.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2013 Samsung Electronics + * + * Configuration settings for the SAMSUNG EXYNOS5 Snow board. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __CONFIG_SNOW_H +#define __CONFIG_SNOW_H + +#include + +#undef CONFIG_DEFAULT_DEVICE_TREE +#define CONFIG_DEFAULT_DEVICE_TREE exynos5250-snow + +#endif /* __CONFIG_SNOW_H */ -- cgit v1.2.3 From ce0c1bc13556fbf1bdfa2a4a27ca6744e7beb32a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Majewski?= Date: Fri, 11 Jan 2013 05:08:54 +0000 Subject: mmc:sdhci:fix: Change default interrupts enabled at SDHCI initialization This patch changes sdhci_init()'s behavior to NOT enable all interrupt sources by default. Moreover interrupt signaling has been disabled. This patch do not enable interrupts which aren't served in u-boot (they are defined at sdhci.h but NOT used elsewhere): - SDHCI_INT_CARD_INSERT, SDHCI_INT_CARD_REMOVE, SDHCI_BUS_POWER, SDHCI_INT_CARD_REMOVE, SDHCI_INT_CARD_INT Special care shall be put on SDHCI_INT_CARD_INT, which indicates interrupt generated by SD card. According to "SD Host Controller Simplified Spec. ver 3.00" when bit 8 (Card Interrupt Status Enable) at "Normal Interrupt Status Enable Register" (offset 0x34) is set, the card interrupt detection is started. Then eMMC card may cause the SD controller to set this bit and then this interrupt is passed to booted OS and might cause kernel crash. To sum up: - Only enable interrupts, which are served at u-boot - This cleanup as a side effect fixes SDHCI's CARD INTERRUPT problem at Linux kernel (versions 3.6+, sdhci controller) - Keep masked bits at "Normal Interrupt Signal Enable Register" (0x38h) Signed-off-by: Lukasz Majewski Signed-off-by: Kyungmin Park Cc: Lei Wen Cc: Andy Fleming Acked-by: Jaehoon Chung Signed-off-by: Minkyu Kang --- drivers/mmc/sdhci.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index b9cbe34f1f..551b4232c8 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -412,9 +412,11 @@ int sdhci_init(struct mmc *mmc) status = sdhci_readl(host, SDHCI_PRESENT_STATE); } - /* Eable all state */ - sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_ENABLE); - sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_SIGNAL_ENABLE); + /* Enable only interrupts served by the SD controller */ + sdhci_writel(host, SDHCI_INT_DATA_MASK | SDHCI_INT_CMD_MASK + , SDHCI_INT_ENABLE); + /* Mask all sdhci interrupt sources */ + sdhci_writel(host, 0x0, SDHCI_SIGNAL_ENABLE); return 0; } -- cgit v1.2.3 From 88077280c48ba4e0f3b9a305ffb748b1bba8380a Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 29 Jan 2013 16:37:36 +0000 Subject: ARM: bcm2835: add mailbox driver The BCM2835 SoC contains (at least) two CPUs; the VideoCore (a/k/a "GPU") and the ARM CPU. The ARM CPU is often thought of as the main CPU. However, the VideoCore actually controls the initial SoC boot, and hides much of the hardware behind a protocol. This protocol is transported using the SoC's mailbox hardware module. Here, we add a very simplistic driver for the mailbox module, and define a few structures for the property messages. Signed-off-by: Stephen Warren --- arch/arm/cpu/arm1176/bcm2835/Makefile | 2 +- arch/arm/cpu/arm1176/bcm2835/mbox.c | 164 +++++++++++++ arch/arm/include/asm/arch-bcm2835/mbox.h | 407 +++++++++++++++++++++++++++++++ 3 files changed, 572 insertions(+), 1 deletion(-) create mode 100644 arch/arm/cpu/arm1176/bcm2835/mbox.c create mode 100644 arch/arm/include/asm/arch-bcm2835/mbox.h diff --git a/arch/arm/cpu/arm1176/bcm2835/Makefile b/arch/arm/cpu/arm1176/bcm2835/Makefile index 95da6a822a..135de42d37 100644 --- a/arch/arm/cpu/arm1176/bcm2835/Makefile +++ b/arch/arm/cpu/arm1176/bcm2835/Makefile @@ -17,7 +17,7 @@ include $(TOPDIR)/config.mk LIB = $(obj)lib$(SOC).o SOBJS := lowlevel_init.o -COBJS := init.o reset.o timer.o +COBJS := init.o reset.o timer.o mbox.o SRCS := $(SOBJS:.o=.c) $(COBJS:.o=.c) OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS)) diff --git a/arch/arm/cpu/arm1176/bcm2835/mbox.c b/arch/arm/cpu/arm1176/bcm2835/mbox.c new file mode 100644 index 0000000000..fd65e3387f --- /dev/null +++ b/arch/arm/cpu/arm1176/bcm2835/mbox.c @@ -0,0 +1,164 @@ +/* + * (C) Copyright 2012 Stephen Warren + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include + +#define TIMEOUT (100 * 1000) /* 100mS in uS */ + +int bcm2835_mbox_call_raw(u32 chan, u32 send, u32 *recv) +{ + struct bcm2835_mbox_regs *regs = + (struct bcm2835_mbox_regs *)BCM2835_MBOX_PHYSADDR; + ulong endtime = get_timer(0) + TIMEOUT; + u32 val; + + debug("time: %lu timeout: %lu\n", get_timer(0), endtime); + + if (send & BCM2835_CHAN_MASK) { + printf("mbox: Illegal mbox data 0x%08x\n", send); + return -1; + } + + /* Drain any stale responses */ + + for (;;) { + val = readl(®s->status); + if (val & BCM2835_MBOX_STATUS_RD_EMPTY) + break; + if (get_timer(0) >= endtime) { + printf("mbox: Timeout draining stale responses\n"); + return -1; + } + val = readl(®s->read); + } + + /* Wait for space to send */ + + for (;;) { + val = readl(®s->status); + if (!(val & BCM2835_MBOX_STATUS_WR_FULL)) + break; + if (get_timer(0) >= endtime) { + printf("mbox: Timeout waiting for send space\n"); + return -1; + } + } + + /* Send the request */ + + val = BCM2835_MBOX_PACK(chan, send); + debug("mbox: TX raw: 0x%08x\n", val); + writel(val, ®s->write); + + /* Wait for the response */ + + for (;;) { + val = readl(®s->status); + if (!(val & BCM2835_MBOX_STATUS_RD_EMPTY)) + break; + if (get_timer(0) >= endtime) { + printf("mbox: Timeout waiting for response\n"); + return -1; + } + } + + /* Read the response */ + + val = readl(®s->read); + debug("mbox: RX raw: 0x%08x\n", val); + + /* Validate the response */ + + if (BCM2835_MBOX_UNPACK_CHAN(val) != chan) { + printf("mbox: Response channel mismatch\n"); + return -1; + } + + *recv = BCM2835_MBOX_UNPACK_DATA(val); + + return 0; +} + +#ifdef DEBUG +void dump_buf(struct bcm2835_mbox_hdr *buffer) +{ + u32 *p; + u32 words; + int i; + + p = (u32 *)buffer; + words = buffer->buf_size / 4; + for (i = 0; i < words; i++) + printf(" 0x%04x: 0x%08x\n", i * 4, p[i]); +} +#endif + +int bcm2835_mbox_call_prop(u32 chan, struct bcm2835_mbox_hdr *buffer) +{ + int ret; + u32 rbuffer; + struct bcm2835_mbox_tag_hdr *tag; + int tag_index; + +#ifdef DEBUG + printf("mbox: TX buffer\n"); + dump_buf(buffer); +#endif + + ret = bcm2835_mbox_call_raw(chan, (u32)buffer, &rbuffer); + if (ret) + return ret; + if (rbuffer != (u32)buffer) { + printf("mbox: Response buffer mismatch\n"); + return -1; + } + +#ifdef DEBUG + printf("mbox: RX buffer\n"); + dump_buf(buffer); +#endif + + /* Validate overall response status */ + + if (buffer->code != BCM2835_MBOX_RESP_CODE_SUCCESS) { + printf("mbox: Header response code invalid\n"); + return -1; + } + + /* Validate each tag's response status */ + + tag = (void *)(buffer + 1); + tag_index = 0; + while (tag->tag) { + if (!(tag->val_len & BCM2835_MBOX_TAG_VAL_LEN_RESPONSE)) { + printf("mbox: Tag %d missing val_len response bit\n", + tag_index); + return -1; + } + /* + * Clear the reponse bit so clients can just look right at the + * length field without extra processing + */ + tag->val_len &= ~BCM2835_MBOX_TAG_VAL_LEN_RESPONSE; + tag = (void *)(((u8 *)tag) + sizeof(*tag) + tag->val_buf_size); + tag_index++; + } + + return 0; +} diff --git a/arch/arm/include/asm/arch-bcm2835/mbox.h b/arch/arm/include/asm/arch-bcm2835/mbox.h new file mode 100644 index 0000000000..4752091b95 --- /dev/null +++ b/arch/arm/include/asm/arch-bcm2835/mbox.h @@ -0,0 +1,407 @@ +/* + * (C) Copyright 2012 Stephen Warren + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _BCM2835_MBOX_H +#define _BCM2835_MBOX_H + +#include + +/* + * The BCM2835 SoC contains (at least) two CPUs; the VideoCore (a/k/a "GPU") + * and the ARM CPU. The ARM CPU is often thought of as the main CPU. + * However, the VideoCore actually controls the initial SoC boot, and hides + * much of the hardware behind a protocol. This protocol is transported + * using the SoC's mailbox hardware module. + * + * The mailbox hardware supports passing 32-bit values back and forth. + * Presumably by software convention of the firmware, the bottom 4 bits of the + * value are used to indicate a logical channel, and the upper 28 bits are the + * actual payload. Various channels exist using these simple raw messages. See + * https://github.com/raspberrypi/firmware/wiki/Mailboxes for a list. As an + * example, the messages on the power management channel are a bitmask of + * devices whose power should be enabled. + * + * The property mailbox channel passes messages that contain the (16-byte + * aligned) ARM physical address of a memory buffer. This buffer is passed to + * the VC for processing, is modified in-place by the VC, and the address then + * passed back to the ARM CPU as the response mailbox message to indicate + * request completion. The buffers have a generic and extensible format; each + * buffer contains a standard header, a list of "tags", and a terminating zero + * entry. Each tag contains an ID indicating its type, and length fields for + * generic parsing. With some limitations, an arbitrary set of tags may be + * combined together into a single message buffer. This file defines structs + * representing the header and many individual tag layouts and IDs. + */ + +/* Raw mailbox HW */ + +#define BCM2835_MBOX_PHYSADDR 0x2000b880 + +struct bcm2835_mbox_regs { + u32 read; + u32 rsvd0[5]; + u32 status; + u32 config; + u32 write; +}; + +#define BCM2835_MBOX_STATUS_WR_FULL 0x80000000 +#define BCM2835_MBOX_STATUS_RD_EMPTY 0x40000000 + +/* Lower 4-bits are channel ID */ +#define BCM2835_CHAN_MASK 0xf +#define BCM2835_MBOX_PACK(chan, data) (((data) & (~BCM2835_CHAN_MASK)) | \ + (chan & BCM2835_CHAN_MASK)) +#define BCM2835_MBOX_UNPACK_CHAN(val) ((val) & BCM2835_CHAN_MASK) +#define BCM2835_MBOX_UNPACK_DATA(val) ((val) & (~BCM2835_CHAN_MASK)) + +/* Property mailbox buffer structures */ + +#define BCM2835_MBOX_PROP_CHAN 8 + +/* All message buffers must start with this header */ +struct bcm2835_mbox_hdr { + u32 buf_size; + u32 code; +}; + +#define BCM2835_MBOX_REQ_CODE 0 +#define BCM2835_MBOX_RESP_CODE_SUCCESS 0x80000000 + +#define BCM2835_MBOX_INIT_HDR(_m_) { \ + memset((_m_), 0, sizeof(*(_m_))); \ + (_m_)->hdr.buf_size = sizeof(*(_m_)); \ + (_m_)->hdr.code = 0; \ + (_m_)->end_tag = 0; \ + } + +/* + * A message buffer contains a list of tags. Each tag must also start with + * a standardized header. + */ +struct bcm2835_mbox_tag_hdr { + u32 tag; + u32 val_buf_size; + u32 val_len; +}; + +#define BCM2835_MBOX_INIT_TAG(_t_, _id_) { \ + (_t_)->tag_hdr.tag = BCM2835_MBOX_TAG_##_id_; \ + (_t_)->tag_hdr.val_buf_size = sizeof((_t_)->body); \ + (_t_)->tag_hdr.val_len = sizeof((_t_)->body.req); \ + } + +#define BCM2835_MBOX_INIT_TAG_NO_REQ(_t_, _id_) { \ + (_t_)->tag_hdr.tag = BCM2835_MBOX_TAG_##_id_; \ + (_t_)->tag_hdr.val_buf_size = sizeof((_t_)->body); \ + (_t_)->tag_hdr.val_len = 0; \ + } + +/* When responding, the VC sets this bit in val_len to indicate a response */ +#define BCM2835_MBOX_TAG_VAL_LEN_RESPONSE 0x80000000 + +/* + * Below we define the ID and struct for many possible tags. This header only + * defines individual tag structs, not entire message structs, since in + * general an arbitrary set of tags may be combined into a single message. + * Clients of the mbox API are expected to define their own overall message + * structures by combining the header, a set of tags, and a terminating + * entry. For example, + * + * struct msg { + * struct bcm2835_mbox_hdr hdr; + * struct bcm2835_mbox_tag_get_arm_mem get_arm_mem; + * ... perhaps other tags here ... + * u32 end_tag; + * }; + */ + +#define BCM2835_MBOX_TAG_GET_ARM_MEMORY 0x00010005 + +struct bcm2835_mbox_tag_get_arm_mem { + struct bcm2835_mbox_tag_hdr tag_hdr; + union { + struct { + } req; + struct { + u32 mem_base; + u32 mem_size; + } resp; + } body; +}; + +#define BCM2835_MBOX_TAG_ALLOCATE_BUFFER 0x00040001 + +struct bcm2835_mbox_tag_allocate_buffer { + struct bcm2835_mbox_tag_hdr tag_hdr; + union { + struct { + u32 alignment; + } req; + struct { + u32 fb_address; + u32 fb_size; + } resp; + } body; +}; + +#define BCM2835_MBOX_TAG_RELEASE_BUFFER 0x00048001 + +struct bcm2835_mbox_tag_release_buffer { + struct bcm2835_mbox_tag_hdr tag_hdr; + union { + struct { + } req; + struct { + } resp; + } body; +}; + +#define BCM2835_MBOX_TAG_BLANK_SCREEN 0x00040002 + +struct bcm2835_mbox_tag_blank_screen { + struct bcm2835_mbox_tag_hdr tag_hdr; + union { + struct { + /* bit 0 means on, other bots reserved */ + u32 state; + } req; + struct { + u32 state; + } resp; + } body; +}; + +/* Physical means output signal */ +#define BCM2835_MBOX_TAG_GET_PHYSICAL_W_H 0x00040003 +#define BCM2835_MBOX_TAG_TEST_PHYSICAL_W_H 0x00044003 +#define BCM2835_MBOX_TAG_SET_PHYSICAL_W_H 0x00048003 + +struct bcm2835_mbox_tag_physical_w_h { + struct bcm2835_mbox_tag_hdr tag_hdr; + union { + /* req not used for get */ + struct { + u32 width; + u32 height; + } req; + struct { + u32 width; + u32 height; + } resp; + } body; +}; + +/* Virtual means display buffer */ +#define BCM2835_MBOX_TAG_GET_VIRTUAL_W_H 0x00040004 +#define BCM2835_MBOX_TAG_TEST_VIRTUAL_W_H 0x00044004 +#define BCM2835_MBOX_TAG_SET_VIRTUAL_W_H 0x00048004 + +struct bcm2835_mbox_tag_virtual_w_h { + struct bcm2835_mbox_tag_hdr tag_hdr; + union { + /* req not used for get */ + struct { + u32 width; + u32 height; + } req; + struct { + u32 width; + u32 height; + } resp; + } body; +}; + +#define BCM2835_MBOX_TAG_GET_DEPTH 0x00040005 +#define BCM2835_MBOX_TAG_TEST_DEPTH 0x00044005 +#define BCM2835_MBOX_TAG_SET_DEPTH 0x00048005 + +struct bcm2835_mbox_tag_depth { + struct bcm2835_mbox_tag_hdr tag_hdr; + union { + /* req not used for get */ + struct { + u32 bpp; + } req; + struct { + u32 bpp; + } resp; + } body; +}; + +#define BCM2835_MBOX_TAG_GET_PIXEL_ORDER 0x00040006 +#define BCM2835_MBOX_TAG_TEST_PIXEL_ORDER 0x00044005 +#define BCM2835_MBOX_TAG_SET_PIXEL_ORDER 0x00048006 + +#define BCM2835_MBOX_PIXEL_ORDER_BGR 0 +#define BCM2835_MBOX_PIXEL_ORDER_RGB 1 + +struct bcm2835_mbox_tag_pixel_order { + struct bcm2835_mbox_tag_hdr tag_hdr; + union { + /* req not used for get */ + struct { + u32 order; + } req; + struct { + u32 order; + } resp; + } body; +}; + +#define BCM2835_MBOX_TAG_GET_ALPHA_MODE 0x00040007 +#define BCM2835_MBOX_TAG_TEST_ALPHA_MODE 0x00044007 +#define BCM2835_MBOX_TAG_SET_ALPHA_MODE 0x00048007 + +#define BCM2835_MBOX_ALPHA_MODE_0_OPAQUE 0 +#define BCM2835_MBOX_ALPHA_MODE_0_TRANSPARENT 1 +#define BCM2835_MBOX_ALPHA_MODE_IGNORED 2 + +struct bcm2835_mbox_tag_alpha_mode { + struct bcm2835_mbox_tag_hdr tag_hdr; + union { + /* req not used for get */ + struct { + u32 alpha; + } req; + struct { + u32 alpha; + } resp; + } body; +}; + +#define BCM2835_MBOX_TAG_GET_PITCH 0x00040008 + +struct bcm2835_mbox_tag_pitch { + struct bcm2835_mbox_tag_hdr tag_hdr; + union { + struct { + } req; + struct { + u32 pitch; + } resp; + } body; +}; + +/* Offset of display window within buffer */ +#define BCM2835_MBOX_TAG_GET_VIRTUAL_OFFSET 0x00040009 +#define BCM2835_MBOX_TAG_TEST_VIRTUAL_OFFSET 0x00044009 +#define BCM2835_MBOX_TAG_SET_VIRTUAL_OFFSET 0x00048009 + +struct bcm2835_mbox_tag_virtual_offset { + struct bcm2835_mbox_tag_hdr tag_hdr; + union { + /* req not used for get */ + struct { + u32 x; + u32 y; + } req; + struct { + u32 x; + u32 y; + } resp; + } body; +}; + +#define BCM2835_MBOX_TAG_GET_OVERSCAN 0x0004000a +#define BCM2835_MBOX_TAG_TEST_OVERSCAN 0x0004400a +#define BCM2835_MBOX_TAG_SET_OVERSCAN 0x0004800a + +struct bcm2835_mbox_tag_overscan { + struct bcm2835_mbox_tag_hdr tag_hdr; + union { + /* req not used for get */ + struct { + u32 top; + u32 bottom; + u32 left; + u32 right; + } req; + struct { + u32 top; + u32 bottom; + u32 left; + } resp; + } body; +}; + +#define BCM2835_MBOX_TAG_GET_PALETTE 0x0004000b + +struct bcm2835_mbox_tag_get_palette { + struct bcm2835_mbox_tag_hdr tag_hdr; + union { + struct { + } req; + struct { + u32 data[1024]; + } resp; + } body; +}; + +#define BCM2835_MBOX_TAG_TEST_PALETTE 0x0004400b + +struct bcm2835_mbox_tag_test_palette { + struct bcm2835_mbox_tag_hdr tag_hdr; + union { + struct { + u32 offset; + u32 num_entries; + u32 data[256]; + } req; + struct { + u32 is_invalid; + } resp; + } body; +}; + +#define BCM2835_MBOX_TAG_SET_PALETTE 0x0004800b + +struct bcm2835_mbox_tag_set_palette { + struct bcm2835_mbox_tag_hdr tag_hdr; + union { + struct { + u32 offset; + u32 num_entries; + u32 data[256]; + } req; + struct { + u32 is_invalid; + } resp; + } body; +}; + +/* + * Pass a raw u32 message to the VC, and receive a raw u32 back. + * + * Returns 0 for success, any other value for error. + */ +int bcm2835_mbox_call_raw(u32 chan, u32 send, u32 *recv); + +/* + * Pass a complete property-style buffer to the VC, and wait until it has + * been processed. + * + * This function expects a pointer to the mbox_hdr structure in an attempt + * to ensure some degree of type safety. However, some number of tags and + * a termination value are expected to immediately follow the header in + * memory, as required by the property protocol. + * + * Returns 0 for success, any other value for error. + */ +int bcm2835_mbox_call_prop(u32 chan, struct bcm2835_mbox_hdr *buffer); + +#endif -- cgit v1.2.3 From 3f397782ae6c6148f7fa12bbb62f309a4f5d897c Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 29 Jan 2013 16:37:37 +0000 Subject: ARM: rpi_b: use bcm2835 mbox driver to get memory size The firmware running on the bcm2835 SoC's VideoCore CPU determines how much of the system RAM is available for use by the ARM CPU. Previously, U-Boot assumed that only 128MB was available, since this was the smallest value configured by any public firmware. However, we can now query the actual value at run-time from the firmware using the mbox property protocol. Signed-off-by: Stephen Warren --- board/raspberrypi/rpi_b/rpi_b.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/board/raspberrypi/rpi_b/rpi_b.c b/board/raspberrypi/rpi_b/rpi_b.c index 688b0aade1..3c654a1ac1 100644 --- a/board/raspberrypi/rpi_b/rpi_b.c +++ b/board/raspberrypi/rpi_b/rpi_b.c @@ -15,13 +15,32 @@ */ #include +#include #include DECLARE_GLOBAL_DATA_PTR; +struct msg_get_arm_mem { + struct bcm2835_mbox_hdr hdr; + struct bcm2835_mbox_tag_get_arm_mem get_arm_mem; + u32 end_tag; +}; + int dram_init(void) { - gd->ram_size = CONFIG_SYS_SDRAM_SIZE; + ALLOC_ALIGN_BUFFER(struct msg_get_arm_mem, msg, 1, 16); + int ret; + + BCM2835_MBOX_INIT_HDR(msg); + BCM2835_MBOX_INIT_TAG(&msg->get_arm_mem, GET_ARM_MEMORY); + + ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr); + if (ret) { + printf("bcm2835: Could not query ARM memory size\n"); + return -1; + } + + gd->ram_size = msg->get_arm_mem.body.resp.mem_size; return 0; } -- cgit v1.2.3 From 6d3307195d583b7590068299420db4b44c6df4bf Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 29 Jan 2013 16:37:38 +0000 Subject: lcd: calculate line_length after lcd_ctrl_init() When an LCD driver is actually driving a regular external display, e.g. an HDMI monitor, the display resolution might not be known until the display controller has initialized, i.e. during lcd_ctrl_init(). However, lcd.c calculates lcd_line_length before calling this function, thus relying on a hard-coded resolution in struct panel_info. Instead, defer this calculation until after lcd_ctrl_init() has had the chance to dynamically determine the resolution. This needs to happen before lcd_clear(), since the value is used there. grep indicates that no code outside lcd.c uses this lcd_line_length; in particular, no lcd_ctrl_init() implementations read it. Signed-off-by: Stephen Warren Acked-by: Anatolij Gustschin --- common/lcd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/lcd.c b/common/lcd.c index 590bbb9301..77914adbce 100644 --- a/common/lcd.c +++ b/common/lcd.c @@ -386,8 +386,6 @@ int drv_lcd_init (void) lcd_base = (void *)(gd->fb_base); - lcd_get_size(&lcd_line_length); - lcd_init(lcd_base); /* LCD initialization */ /* Device initialization */ @@ -470,6 +468,8 @@ static int lcd_init(void *lcdbase) debug("[LCD] Initializing LCD frambuffer at %p\n", lcdbase); lcd_ctrl_init(lcdbase); + lcd_get_size(&lcd_line_length); + lcd_line_length = (panel_info.vl_col * NBITS(panel_info.vl_bpix)) / 8; lcd_is_enabled = 1; lcd_clear(); lcd_enable (); -- cgit v1.2.3 From 38baa4f6d69f3ba933a2578d111dc04151d9e169 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 29 Jan 2013 16:37:39 +0000 Subject: ARM: rpi_b: disable rpi_b dcache explicitly There appears to be no implementation of flush_dcache_range() for ARM1176, so explicitly disable dcache support to avoid references to that function from the LCD core in the next patch. This was presumably not noticed before simply because no drivers for the rpi_b were attempting DMA. Signed-off-by: Stephen Warren --- include/configs/rpi_b.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/configs/rpi_b.h b/include/configs/rpi_b.h index cf62e45e8b..5db31f58be 100644 --- a/include/configs/rpi_b.h +++ b/include/configs/rpi_b.h @@ -23,6 +23,7 @@ #define CONFIG_ARM1176 #define CONFIG_BCM2835 #define CONFIG_ARCH_CPU_INIT +#define CONFIG_SYS_DCACHE_OFF /* * 2835 is a SKU in a series for which the 2708 is the first or primary SoC, * so 2708 has historically been used rather than a dedicated 2835 ID. -- cgit v1.2.3 From 6be3c9fca27252590b55b211bcf1df884fe3adbd Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 29 Jan 2013 16:37:40 +0000 Subject: video: add a driver for the bcm2835 The firmware running on the bcm2835 SoC's VideoCore CPU manages the display controller. Add a simple "LCD" driver that communicates with the firmware using the property mailbox protocol. This configures the display and frame-buffer to match whatever physical resolution the firmware chosen when booting, which is typically the native resolution of the attached display device, presumably unless otherwise specified in config.txt on the boot media. Enable this driver in the Raspberry Pi board configuration. Signed-off-by: Stephen Warren Acked-by: Anatolij Gustschin --- drivers/video/Makefile | 1 + drivers/video/bcm2835.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++++ include/configs/rpi_b.h | 16 ++++++ 3 files changed, 144 insertions(+) create mode 100644 drivers/video/bcm2835.c diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 170a358b52..e8cecca55a 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -40,6 +40,7 @@ COBJS-$(CONFIG_S6E63D6) += s6e63d6.o COBJS-$(CONFIG_LD9040) += ld9040.o COBJS-$(CONFIG_SED156X) += sed156x.o COBJS-$(CONFIG_VIDEO_AMBA) += amba.o +COBJS-$(CONFIG_VIDEO_BCM2835) += bcm2835.o COBJS-$(CONFIG_VIDEO_COREBOOT) += coreboot_fb.o COBJS-$(CONFIG_VIDEO_CT69000) += ct69000.o videomodes.o COBJS-$(CONFIG_VIDEO_DA8XX) += da8xx-fb.o videomodes.o diff --git a/drivers/video/bcm2835.c b/drivers/video/bcm2835.c new file mode 100644 index 0000000000..1e9a84ac1f --- /dev/null +++ b/drivers/video/bcm2835.c @@ -0,0 +1,127 @@ +/* + * (C) Copyright 2012 Stephen Warren + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +/* Global variables that lcd.c expects to exist */ +int lcd_line_length; +int lcd_color_fg; +int lcd_color_bg; +void *lcd_base; +void *lcd_console_address; +short console_col; +short console_row; +vidinfo_t panel_info; +char lcd_cursor_enabled; +ushort lcd_cursor_width; +ushort lcd_cursor_height; + +struct msg_query { + struct bcm2835_mbox_hdr hdr; + struct bcm2835_mbox_tag_physical_w_h physical_w_h; + u32 end_tag; +}; + +struct msg_setup { + struct bcm2835_mbox_hdr hdr; + struct bcm2835_mbox_tag_physical_w_h physical_w_h; + struct bcm2835_mbox_tag_virtual_w_h virtual_w_h; + struct bcm2835_mbox_tag_depth depth; + struct bcm2835_mbox_tag_pixel_order pixel_order; + struct bcm2835_mbox_tag_alpha_mode alpha_mode; + struct bcm2835_mbox_tag_virtual_offset virtual_offset; + struct bcm2835_mbox_tag_overscan overscan; + struct bcm2835_mbox_tag_allocate_buffer allocate_buffer; + u32 end_tag; +}; + +void lcd_ctrl_init(void *lcdbase) +{ + ALLOC_ALIGN_BUFFER(struct msg_query, msg_query, 1, 16); + ALLOC_ALIGN_BUFFER(struct msg_setup, msg_setup, 1, 16); + int ret; + u32 w, h; + + debug("bcm2835: Query resolution...\n"); + + BCM2835_MBOX_INIT_HDR(msg_query); + BCM2835_MBOX_INIT_TAG_NO_REQ(&msg_query->physical_w_h, + GET_PHYSICAL_W_H); + ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg_query->hdr); + if (ret) { + printf("bcm2835: Could not query display resolution\n"); + /* FIXME: How to disable the LCD to prevent errors? hang()? */ + return; + } + + w = msg_query->physical_w_h.body.resp.width; + h = msg_query->physical_w_h.body.resp.height; + + debug("bcm2835: Setting up display for %d x %d\n", w, h); + + BCM2835_MBOX_INIT_HDR(msg_setup); + BCM2835_MBOX_INIT_TAG(&msg_setup->physical_w_h, SET_PHYSICAL_W_H); + msg_setup->physical_w_h.body.req.width = w; + msg_setup->physical_w_h.body.req.height = h; + BCM2835_MBOX_INIT_TAG(&msg_setup->virtual_w_h, SET_VIRTUAL_W_H); + msg_setup->virtual_w_h.body.req.width = w; + msg_setup->virtual_w_h.body.req.height = h; + BCM2835_MBOX_INIT_TAG(&msg_setup->depth, SET_DEPTH); + msg_setup->depth.body.req.bpp = 16; + BCM2835_MBOX_INIT_TAG(&msg_setup->pixel_order, SET_PIXEL_ORDER); + msg_setup->pixel_order.body.req.order = BCM2835_MBOX_PIXEL_ORDER_BGR; + BCM2835_MBOX_INIT_TAG(&msg_setup->alpha_mode, SET_ALPHA_MODE); + msg_setup->alpha_mode.body.req.alpha = BCM2835_MBOX_ALPHA_MODE_IGNORED; + BCM2835_MBOX_INIT_TAG(&msg_setup->virtual_offset, SET_VIRTUAL_OFFSET); + msg_setup->virtual_offset.body.req.x = 0; + msg_setup->virtual_offset.body.req.y = 0; + BCM2835_MBOX_INIT_TAG(&msg_setup->overscan, SET_OVERSCAN); + msg_setup->overscan.body.req.top = 0; + msg_setup->overscan.body.req.bottom = 0; + msg_setup->overscan.body.req.left = 0; + msg_setup->overscan.body.req.right = 0; + BCM2835_MBOX_INIT_TAG(&msg_setup->allocate_buffer, ALLOCATE_BUFFER); + msg_setup->allocate_buffer.body.req.alignment = 0x100; + + ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg_setup->hdr); + if (ret) { + printf("bcm2835: Could not configure display\n"); + /* FIXME: How to disable the LCD to prevent errors? hang()? */ + return; + } + + w = msg_setup->physical_w_h.body.resp.width; + h = msg_setup->physical_w_h.body.resp.height; + + debug("bcm2835: Final resolution is %d x %d\n", w, h); + + panel_info.vl_col = w; + panel_info.vl_row = h; + panel_info.vl_bpix = LCD_COLOR16; + + gd->fb_base = msg_setup->allocate_buffer.body.resp.fb_address; + lcd_base = (void *)gd->fb_base; +} + +void lcd_enable(void) +{ +} diff --git a/include/configs/rpi_b.h b/include/configs/rpi_b.h index 5db31f58be..e485a061a6 100644 --- a/include/configs/rpi_b.h +++ b/include/configs/rpi_b.h @@ -58,6 +58,17 @@ /* Devices */ /* GPIO */ #define CONFIG_BCM2835_GPIO +/* LCD */ +#define CONFIG_LCD +#define LCD_BPP LCD_COLOR16 +/* + * Prevent allocation of RAM for FB; the real FB address is queried + * dynamically from the VideoCore co-processor, and comes from RAM + * not owned by the ARM CPU. + */ +#define CONFIG_FB_ADDR 0 +#define CONFIG_VIDEO_BCM2835 +#define CONFIG_SYS_WHITE_ON_BLACK /* Console UART */ #define CONFIG_PL011_SERIAL @@ -75,6 +86,11 @@ #define CONFIG_ENV_SIZE SZ_16K #define CONFIG_ENV_IS_NOWHERE #define CONFIG_SYS_LOAD_ADDR 0x1000000 +#define CONFIG_CONSOLE_MUX +#define CONFIG_SYS_CONSOLE_IS_IN_ENV +#define CONFIG_EXTRA_ENV_SETTINGS "stdin=serial\0" \ + "stderr=serial,lcd\0" \ + "stdout=serial,lcd\0" /* Shell */ #define CONFIG_SYS_HUSH_PARSER -- cgit v1.2.3 From 9a4fbe4fbdeb3ffadeb277236c672c2712443a1b Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 29 Jan 2013 16:37:41 +0000 Subject: mmc: add bcm2835 driver This adds a simple driver for the BCM2835's SD controller. Workarounds are implemented for: * Register writes can't be too close to each-other in time, or they will be lost. * Register accesses must all be 32-bit, so implement custom accessors. This code was extracted from: git://github.com/gonzoua/u-boot-pi.git master which was created by Oleksandr Tymoshenko. Portions of the code there were obviously based on the Linux kernel at: git://github.com/raspberrypi/linux.git rpi-3.6.y commit f5b930b "Main bcm2708 linux port" signed-off-by Dom Cobley. swarren changed the following for upstream: * Removed hack udelay()s in bcm2835_sdhci_raw_writel(); setting SDHCI_QUIRK_WAIT_SEND_CMD appears to solve the issues. * Remove register logging from read*/write* functions. * Sort out confusion with min/max_freq values passed to add_sdhci(). * Use more descriptive variable names and calculations in IO accessors. * Simplified and commented twoticks_delay calculation. * checkpatch fixes. Cc: Andy Fleming Signed-off-by: Oleksandr Tymoshenko Signed-off-by: Stephen Warren Acked-by: Andy Fleming --- arch/arm/include/asm/arch-bcm2835/sdhci.h | 24 ++++ drivers/mmc/Makefile | 1 + drivers/mmc/bcm2835_sdhci.c | 189 ++++++++++++++++++++++++++++++ 3 files changed, 214 insertions(+) create mode 100644 arch/arm/include/asm/arch-bcm2835/sdhci.h create mode 100644 drivers/mmc/bcm2835_sdhci.c diff --git a/arch/arm/include/asm/arch-bcm2835/sdhci.h b/arch/arm/include/asm/arch-bcm2835/sdhci.h new file mode 100644 index 0000000000..a4f867b2e9 --- /dev/null +++ b/arch/arm/include/asm/arch-bcm2835/sdhci.h @@ -0,0 +1,24 @@ +/* + * (C) Copyright 2012 Stephen Warren + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _BCM2835_SDHCI_H_ +#define _BCM2835_SDHCI_H_ + +#define BCM2835_SDHCI_BASE 0x20300000 + +int bcm2835_sdhci_init(u32 regbase, u32 emmc_freq); + +#endif diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 65791aa218..1d6faa2a92 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -43,6 +43,7 @@ COBJS-$(CONFIG_MXS_MMC) += mxsmmc.o COBJS-$(CONFIG_OMAP_HSMMC) += omap_hsmmc.o COBJS-$(CONFIG_PXA_MMC_GENERIC) += pxa_mmc_gen.o COBJS-$(CONFIG_SDHCI) += sdhci.o +COBJS-$(CONFIG_BCM2835_SDHCI) += bcm2835_sdhci.o COBJS-$(CONFIG_S5P_SDHCI) += s5p_sdhci.o COBJS-$(CONFIG_SH_MMCIF) += sh_mmcif.o COBJS-$(CONFIG_TEGRA_MMC) += tegra_mmc.o diff --git a/drivers/mmc/bcm2835_sdhci.c b/drivers/mmc/bcm2835_sdhci.c new file mode 100644 index 0000000000..b0afc3c9ce --- /dev/null +++ b/drivers/mmc/bcm2835_sdhci.c @@ -0,0 +1,189 @@ +/* + * This code was extracted from: + * git://github.com/gonzoua/u-boot-pi.git master + * and hence presumably (C) 2012 Oleksandr Tymoshenko + * + * Tweaks for U-Boot upstreaming + * (C) 2012 Stephen Warren + * + * Portions (e.g. read/write macros, concepts for back-to-back register write + * timing workarounds) obviously extracted from the Linux kernel at: + * https://github.com/raspberrypi/linux.git rpi-3.6.y + * + * The Linux kernel code has the following (c) and license, which is hence + * propagated to Oleksandr's tree and here: + * + * Support for SDHCI device on 2835 + * Based on sdhci-bcm2708.c (c) 2010 Broadcom + * + * 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* Supports: + * SDHCI platform device - Arasan SD controller in BCM2708 + * + * Inspired by sdhci-pci.c, by Pierre Ossman + */ + +#include +#include +#include + +/* 400KHz is max freq for card ID etc. Use that as min */ +#define MIN_FREQ 400000 + +struct bcm2835_sdhci_host { + struct sdhci_host host; + uint twoticks_delay; + ulong last_write; +}; + +static inline struct bcm2835_sdhci_host *to_bcm(struct sdhci_host *host) +{ + return (struct bcm2835_sdhci_host *)host; +} + +static inline void bcm2835_sdhci_raw_writel(struct sdhci_host *host, u32 val, + int reg) +{ + struct bcm2835_sdhci_host *bcm_host = to_bcm(host); + + /* + * The Arasan has a bugette whereby it may lose the content of + * successive writes to registers that are within two SD-card clock + * cycles of each other (a clock domain crossing problem). + * It seems, however, that the data register does not have this problem. + * (Which is just as well - otherwise we'd have to nobble the DMA engine + * too) + */ + while (get_timer(bcm_host->last_write) < bcm_host->twoticks_delay) + ; + + writel(val, host->ioaddr + reg); + bcm_host->last_write = get_timer(0); +} + +static inline u32 bcm2835_sdhci_raw_readl(struct sdhci_host *host, int reg) +{ + return readl(host->ioaddr + reg); +} + +static void bcm2835_sdhci_writel(struct sdhci_host *host, u32 val, int reg) +{ + bcm2835_sdhci_raw_writel(host, val, reg); +} + +static void bcm2835_sdhci_writew(struct sdhci_host *host, u16 val, int reg) +{ + static u32 shadow; + u32 oldval = (reg == SDHCI_COMMAND) ? shadow : + bcm2835_sdhci_raw_readl(host, reg & ~3); + u32 word_num = (reg >> 1) & 1; + u32 word_shift = word_num * 16; + u32 mask = 0xffff << word_shift; + u32 newval = (oldval & ~mask) | (val << word_shift); + + if (reg == SDHCI_TRANSFER_MODE) + shadow = newval; + else + bcm2835_sdhci_raw_writel(host, newval, reg & ~3); +} + +static void bcm2835_sdhci_writeb(struct sdhci_host *host, u8 val, int reg) +{ + u32 oldval = bcm2835_sdhci_raw_readl(host, reg & ~3); + u32 byte_num = reg & 3; + u32 byte_shift = byte_num * 8; + u32 mask = 0xff << byte_shift; + u32 newval = (oldval & ~mask) | (val << byte_shift); + + bcm2835_sdhci_raw_writel(host, newval, reg & ~3); +} + +static u32 bcm2835_sdhci_readl(struct sdhci_host *host, int reg) +{ + u32 val = bcm2835_sdhci_raw_readl(host, reg); + + return val; +} + +static u16 bcm2835_sdhci_readw(struct sdhci_host *host, int reg) +{ + u32 val = bcm2835_sdhci_raw_readl(host, (reg & ~3)); + u32 word_num = (reg >> 1) & 1; + u32 word_shift = word_num * 16; + u32 word = (val >> word_shift) & 0xffff; + + return word; +} + +static u8 bcm2835_sdhci_readb(struct sdhci_host *host, int reg) +{ + u32 val = bcm2835_sdhci_raw_readl(host, (reg & ~3)); + u32 byte_num = reg & 3; + u32 byte_shift = byte_num * 8; + u32 byte = (val >> byte_shift) & 0xff; + + return byte; +} + +static const struct sdhci_ops bcm2835_ops = { + .write_l = bcm2835_sdhci_writel, + .write_w = bcm2835_sdhci_writew, + .write_b = bcm2835_sdhci_writeb, + .read_l = bcm2835_sdhci_readl, + .read_w = bcm2835_sdhci_readw, + .read_b = bcm2835_sdhci_readb, +}; + +int bcm2835_sdhci_init(u32 regbase, u32 emmc_freq) +{ + struct bcm2835_sdhci_host *bcm_host; + struct sdhci_host *host; + + bcm_host = malloc(sizeof(*bcm_host)); + if (!bcm_host) { + printf("sdhci_host malloc fail!\n"); + return 1; + } + + /* + * See the comments in bcm2835_sdhci_raw_writel(). + * + * This should probably be dynamically calculated based on the actual + * frequency. However, this is the longest we'll have to wait, and + * doesn't seem to slow access down too much, so the added complexity + * doesn't seem worth it for now. + * + * 1/MIN_FREQ is (max) time per tick of eMMC clock. + * 2/MIN_FREQ is time for two ticks. + * Multiply by 1000000 to get uS per two ticks. + * +1 for hack rounding. + */ + bcm_host->twoticks_delay = ((2 * 1000000) / MIN_FREQ) + 1; + bcm_host->last_write = 0; + + host = &bcm_host->host; + host->name = "bcm2835_sdhci"; + host->ioaddr = (void *)regbase; + host->quirks = SDHCI_QUIRK_BROKEN_VOLTAGE | SDHCI_QUIRK_BROKEN_R1B | + SDHCI_QUIRK_WAIT_SEND_CMD; + host->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; + host->ops = &bcm2835_ops; + + host->version = sdhci_readw(host, SDHCI_HOST_VERSION); + add_sdhci(host, emmc_freq, MIN_FREQ); + + return 0; +} -- cgit v1.2.3 From 131a1e603b3a8438b84b41940bc6a2051a36e087 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 29 Jan 2013 16:37:42 +0000 Subject: ARM: rpi_b: enable SD controller, add related env/cmds Enable the SD controller driver for the Raspberry Pi. Enable a number of useful MMC, partition, and filesystem-related commands. Set up the environment to provide standard locations for loading a kernel, DTB, etc. Provide a boot command that loads and executes boot.scr.uimg from the SD card; this is written considering future extensibilty to USB storage. Signed-off-by: Stephen Warren --- arch/arm/include/asm/arch-bcm2835/mbox.h | 26 ++++++++++++ board/raspberrypi/rpi_b/rpi_b.c | 26 ++++++++++++ include/configs/rpi_b.h | 68 ++++++++++++++++++++++++++++++-- 3 files changed, 117 insertions(+), 3 deletions(-) diff --git a/arch/arm/include/asm/arch-bcm2835/mbox.h b/arch/arm/include/asm/arch-bcm2835/mbox.h index 4752091b95..b07c4a02bb 100644 --- a/arch/arm/include/asm/arch-bcm2835/mbox.h +++ b/arch/arm/include/asm/arch-bcm2835/mbox.h @@ -144,6 +144,32 @@ struct bcm2835_mbox_tag_get_arm_mem { } body; }; +#define BCM2835_MBOX_TAG_GET_CLOCK_RATE 0x00030002 + +#define BCM2835_MBOX_CLOCK_ID_EMMC 1 +#define BCM2835_MBOX_CLOCK_ID_UART 2 +#define BCM2835_MBOX_CLOCK_ID_ARM 3 +#define BCM2835_MBOX_CLOCK_ID_CORE 4 +#define BCM2835_MBOX_CLOCK_ID_V3D 5 +#define BCM2835_MBOX_CLOCK_ID_H264 6 +#define BCM2835_MBOX_CLOCK_ID_ISP 7 +#define BCM2835_MBOX_CLOCK_ID_SDRAM 8 +#define BCM2835_MBOX_CLOCK_ID_PIXEL 9 +#define BCM2835_MBOX_CLOCK_ID_PWM 10 + +struct bcm2835_mbox_tag_get_clock_rate { + struct bcm2835_mbox_tag_hdr tag_hdr; + union { + struct { + u32 clock_id; + } req; + struct { + u32 clock_id; + u32 rate_hz; + } resp; + } body; +}; + #define BCM2835_MBOX_TAG_ALLOCATE_BUFFER 0x00040001 struct bcm2835_mbox_tag_allocate_buffer { diff --git a/board/raspberrypi/rpi_b/rpi_b.c b/board/raspberrypi/rpi_b/rpi_b.c index 3c654a1ac1..6b3e095ba8 100644 --- a/board/raspberrypi/rpi_b/rpi_b.c +++ b/board/raspberrypi/rpi_b/rpi_b.c @@ -16,6 +16,7 @@ #include #include +#include #include DECLARE_GLOBAL_DATA_PTR; @@ -26,6 +27,12 @@ struct msg_get_arm_mem { u32 end_tag; }; +struct msg_get_clock_rate { + struct bcm2835_mbox_hdr hdr; + struct bcm2835_mbox_tag_get_clock_rate get_clock_rate; + u32 end_tag; +}; + int dram_init(void) { ALLOC_ALIGN_BUFFER(struct msg_get_arm_mem, msg, 1, 16); @@ -51,3 +58,22 @@ int board_init(void) return 0; } + +int board_mmc_init(void) +{ + ALLOC_ALIGN_BUFFER(struct msg_get_clock_rate, msg_clk, 1, 16); + int ret; + + BCM2835_MBOX_INIT_HDR(msg_clk); + BCM2835_MBOX_INIT_TAG(&msg_clk->get_clock_rate, GET_CLOCK_RATE); + msg_clk->get_clock_rate.body.req.clock_id = BCM2835_MBOX_CLOCK_ID_EMMC; + + ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg_clk->hdr); + if (ret) { + printf("bcm2835: Could not query eMMC clock rate\n"); + return -1; + } + + return bcm2835_sdhci_init(BCM2835_SDHCI_BASE, + msg_clk->get_clock_rate.body.resp.rate_hz); +} diff --git a/include/configs/rpi_b.h b/include/configs/rpi_b.h index e485a061a6..3d55d36c6e 100644 --- a/include/configs/rpi_b.h +++ b/include/configs/rpi_b.h @@ -51,6 +51,7 @@ #define CONFIG_SYS_MALLOC_LEN SZ_4M #define CONFIG_SYS_MEMTEST_START 0x00100000 #define CONFIG_SYS_MEMTEST_END 0x00200000 +#define CONFIG_LOADADDR 0x00200000 /* Flash */ #define CONFIG_SYS_NO_FLASH @@ -70,6 +71,13 @@ #define CONFIG_VIDEO_BCM2835 #define CONFIG_SYS_WHITE_ON_BLACK +/* SD/MMC configuration */ +#define CONFIG_GENERIC_MMC +#define CONFIG_MMC +#define CONFIG_SDHCI +#define CONFIG_MMC_SDHCI_IO_ACCESSORS +#define CONFIG_BCM2835_SDHCI + /* Console UART */ #define CONFIG_PL011_SERIAL #define CONFIG_PL011_CLOCK 3000000 @@ -85,12 +93,59 @@ /* Environment */ #define CONFIG_ENV_SIZE SZ_16K #define CONFIG_ENV_IS_NOWHERE +#define CONFIG_ENV_VARS_UBOOT_CONFIG #define CONFIG_SYS_LOAD_ADDR 0x1000000 #define CONFIG_CONSOLE_MUX #define CONFIG_SYS_CONSOLE_IS_IN_ENV -#define CONFIG_EXTRA_ENV_SETTINGS "stdin=serial\0" \ - "stderr=serial,lcd\0" \ - "stdout=serial,lcd\0" +/* + * Memory layout for where various images get loaded by boot scripts: + * + * scriptaddr can be pretty much anywhere that doesn't conflict with something + * else. Put it low in memory to avoid conflicts. + * + * kernel_addr_r must be within the first 128M of RAM in order for the + * kernel's CONFIG_AUTO_ZRELADDR option to work. Since the kernel will + * decompress itself to 0x8000 after the start of RAM, kernel_addr_r + * should not overlap that area, or the kernel will have to copy itself + * somewhere else before decompression. Similarly, the address of any other + * data passed to the kernel shouldn't overlap the start of RAM. Pushing + * this up to 16M allows for a sizable kernel to be decompressed below the + * compressed load address. + * + * fdt_addr_r simply shouldn't overlap anything else. Choosing 32M allows for + * the compressed kernel to be up to 16M too. + * + * ramdisk_addr_r simply shouldn't overlap anything else. Choosing 33M allows + * for the FDT/DTB to be up to 1M, which is hopefully plenty. + */ +#define CONFIG_EXTRA_ENV_SETTINGS \ + "stdin=serial\0" \ + "stderr=serial,lcd\0" \ + "stdout=serial,lcd\0" \ + "scriptaddr=0x00000000\0" \ + "kernel_addr_r=0x01000000\0" \ + "fdt_addr_r=0x02000000\0" \ + "ramdisk_addr_r=0x02100000\0" \ + "boot_targets=mmc0\0" \ + \ + "script_boot=" \ + "if fatload ${devtype} ${devnum}:1 " \ + "${scriptaddr} boot.scr.uimg; then " \ + "source ${scriptaddr}; " \ + "fi;\0" \ + \ + "mmc_boot=" \ + "setenv devtype mmc; " \ + "if mmc dev ${devnum}; then " \ + "run script_boot; " \ + "fi\0" \ + \ + "bootcmd_mmc0=setenv devnum 0; run mmc_boot\0" \ + +#define CONFIG_BOOTCOMMAND \ + "for target in ${boot_targets}; do run bootcmd_${target}; done" + +#define CONFIG_BOOTDELAY 2 /* Shell */ #define CONFIG_SYS_HUSH_PARSER @@ -105,6 +160,13 @@ #include #define CONFIG_CMD_BOOTZ #define CONFIG_CMD_GPIO +#define CONFIG_CMD_MMC +#define CONFIG_DOS_PARTITION +#define CONFIG_PARTITION_UUIDS +#define CONFIG_CMD_PART +#define CONFIG_CMD_FS_GENERIC +#define CONFIG_CMD_FAT +#define CONFIG_CMD_EXT /* Some things don't make sense on this HW or yet */ #undef CONFIG_CMD_FPGA #undef CONFIG_CMD_NET -- cgit v1.2.3 From f35034fe16871a156a9898ac6ed5a9987d91ea05 Mon Sep 17 00:00:00 2001 From: Nikita Kiryanov Date: Sat, 22 Dec 2012 21:03:48 +0000 Subject: cm-t35: add support for loading splash image from NAND Add support for loading splash image from NAND Signed-off-by: Nikita Kiryanov Signed-off-by: Igor Grinberg --- board/cm_t35/cm_t35.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++ include/configs/cm_t35.h | 4 ++++ 2 files changed, 65 insertions(+) diff --git a/board/cm_t35/cm_t35.c b/board/cm_t35/cm_t35.c index e0e8235d73..629ce4a505 100644 --- a/board/cm_t35/cm_t35.c +++ b/board/cm_t35/cm_t35.c @@ -34,7 +34,9 @@ #include #include #include +#include #include +#include #include #include @@ -76,6 +78,65 @@ static u32 gpmc_nand_config[GPMC_MAX_REG] = { 0, }; +#ifdef CONFIG_LCD +#ifdef CONFIG_CMD_NAND +static int splash_load_from_nand(u32 bmp_load_addr) +{ + struct bmp_header *bmp_hdr; + int res, splash_screen_nand_offset = 0x100000; + size_t bmp_size, bmp_header_size = sizeof(struct bmp_header); + + if (bmp_load_addr + bmp_header_size >= gd->start_addr_sp) + goto splash_address_too_high; + + res = nand_read_skip_bad(&nand_info[nand_curr_device], + splash_screen_nand_offset, &bmp_header_size, + (u_char *)bmp_load_addr); + if (res < 0) + return res; + + bmp_hdr = (struct bmp_header *)bmp_load_addr; + bmp_size = le32_to_cpu(bmp_hdr->file_size); + + if (bmp_load_addr + bmp_size >= gd->start_addr_sp) + goto splash_address_too_high; + + return nand_read_skip_bad(&nand_info[nand_curr_device], + splash_screen_nand_offset, &bmp_size, + (u_char *)bmp_load_addr); + +splash_address_too_high: + printf("Error: splashimage address too high. Data overwrites U-Boot " + "and/or placed beyond DRAM boundaries.\n"); + + return -1; +} +#else +static inline int splash_load_from_nand(void) +{ + return -1; +} +#endif /* CONFIG_CMD_NAND */ + +int board_splash_screen_prepare(void) +{ + char *env_splashimage_value; + u32 bmp_load_addr; + + env_splashimage_value = getenv("splashimage"); + if (env_splashimage_value == NULL) + return -1; + + bmp_load_addr = simple_strtoul(env_splashimage_value, 0, 16); + if (bmp_load_addr == 0) { + printf("Error: bad splashimage address specified\n"); + return -1; + } + + return splash_load_from_nand(bmp_load_addr); +} +#endif /* CONFIG_LCD */ + /* * Routine: board_init * Description: hardware init. diff --git a/include/configs/cm_t35.h b/include/configs/cm_t35.h index 8d79ffd48a..726714dd21 100644 --- a/include/configs/cm_t35.h +++ b/include/configs/cm_t35.h @@ -344,5 +344,9 @@ #define LCD_BPP LCD_COLOR16 #define CONFIG_LCD +#define CONFIG_SPLASH_SCREEN +#define CONFIG_CMD_BMP +#define CONFIG_BMP_16BPP +#define CONFIG_SPLASH_SCREEN_PREPARE #endif /* __CONFIG_H */ -- cgit v1.2.3 From fc33705e66cc2c753026f04f92555ad00b709f11 Mon Sep 17 00:00:00 2001 From: Mark Jackson Date: Mon, 4 Mar 2013 01:27:20 +0000 Subject: Allow AM335x MPU core clock speed to be specified in the board config file Allow AM335x MPU core clock speed to be specified in the board config file. To use, add the following to the board's config file:- #define CONFIG_SYS_MPUCLK Signed-off-by: Mark Jackson Acked-by: Peter Korsgaard --- README | 4 ++++ arch/arm/include/asm/arch-am33xx/clocks_am33xx.h | 7 +++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/README b/README index 7f2506a9b9..a73234efdc 100644 --- a/README +++ b/README @@ -3878,6 +3878,10 @@ Low Level (hardware related) configuration options: If defined, the x86 reset vector code is included. This is not needed when U-Boot is running from Coreboot. +- CONFIG_SYS_MPUCLK + Defines the MPU clock speed (in MHz). + + NOTE : currently only supported on AM335x platforms. Freescale QE/FMAN Firmware Support: ----------------------------------- diff --git a/arch/arm/include/asm/arch-am33xx/clocks_am33xx.h b/arch/arm/include/asm/arch-am33xx/clocks_am33xx.h index d748dd2787..2d960070f1 100644 --- a/arch/arm/include/asm/arch-am33xx/clocks_am33xx.h +++ b/arch/arm/include/asm/arch-am33xx/clocks_am33xx.h @@ -21,8 +21,11 @@ #define OSC (V_OSCK/1000000) -/* MAIN PLL Fdll = 550 MHZ, */ -#define MPUPLL_M 550 +/* MAIN PLL Fdll = 550 MHz, by default */ +#ifndef CONFIG_SYS_MPUCLK +#define CONFIG_SYS_MPUCLK 550 +#endif +#define MPUPLL_M CONFIG_SYS_MPUCLK #define MPUPLL_N (OSC-1) #define MPUPLL_M2 1 -- cgit v1.2.3 From 296de3bbec3aa7d9103a1fee121fbad3a97d3133 Mon Sep 17 00:00:00 2001 From: Mark Jackson Date: Thu, 21 Feb 2013 02:49:38 +0000 Subject: Initialise correct GPMC WAITx irq for AM33xx Currently WAIT0 irq is reset and then WAIT1 irq is enabled. Fix it such that WAIT0 irq is enabled instead. Signed-off-by: Mark Jackson Acked-by: Peter Korsgaard --- arch/arm/cpu/armv7/am33xx/mem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/cpu/armv7/am33xx/mem.c b/arch/arm/cpu/armv7/am33xx/mem.c index b8f54abae2..b86b0ded3f 100644 --- a/arch/arm/cpu/armv7/am33xx/mem.c +++ b/arch/arm/cpu/armv7/am33xx/mem.c @@ -83,7 +83,7 @@ void gpmc_init(void) /* global settings */ writel(0x00000008, &gpmc_cfg->sysconfig); writel(0x00000100, &gpmc_cfg->irqstatus); - writel(0x00000200, &gpmc_cfg->irqenable); + writel(0x00000100, &gpmc_cfg->irqenable); writel(0x00000012, &gpmc_cfg->config); /* * Disable the GPMC0 config set by ROM code -- cgit v1.2.3 From 2077590644fdbd0d42c2b448bd5e5531c1639cef Mon Sep 17 00:00:00 2001 From: Koen Kooi Date: Thu, 14 Mar 2013 05:55:19 +0000 Subject: am335x_evm: add support for BeagleBone Black DT name Cc: Matt Porter Cc: Nishanth Menon Signed-off-by: Koen Kooi Signed-off-by: Tom Rini Acked-by: Matt Porter Acked-by: Peter Korsgaard Acked-by: Nishanth Menon --- include/configs/am335x_evm.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/configs/am335x_evm.h b/include/configs/am335x_evm.h index 9eada95c04..f3541d422c 100644 --- a/include/configs/am335x_evm.h +++ b/include/configs/am335x_evm.h @@ -130,6 +130,8 @@ "findfdt="\ "if test $board_name = A335BONE; then " \ "setenv fdtfile am335x-bone.dtb; fi; " \ + "if test $board_name = A335BNLT; then " \ + "setenv fdtfile am335x-boneblack.dtb; fi; " \ "if test $board_name = A33515BB; then " \ "setenv fdtfile am335x-evm.dtb; fi; " \ "if test $board_name = A335X_SK; then " \ -- cgit v1.2.3 From 73a27a84e58cb99b4e64ed6a35eab5bc61f44f29 Mon Sep 17 00:00:00 2001 From: Koen Kooi Date: Thu, 14 Mar 2013 05:55:20 +0000 Subject: am335x_evm: Enable CMD_EXT4 and CMD_FS_GENERIC, add bootpart to env The kernel is loaded from some form of ext[234] or FAT, depending on the distribution used. We add a bootpart variable to the environment so that we can load from the correct mmc partition as well. We leave CONFIG_CMD_EXT2 for existing scripts that use ext2load. Signed-off-by: Koen Kooi Signed-off-by: Tom Rini Acked-by: Peter Korsgaard --- include/configs/am335x_evm.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/include/configs/am335x_evm.h b/include/configs/am335x_evm.h index f3541d422c..fc14c90306 100644 --- a/include/configs/am335x_evm.h +++ b/include/configs/am335x_evm.h @@ -63,6 +63,7 @@ "mmcdev=0\0" \ "mmcroot=/dev/mmcblk0p2 ro\0" \ "mmcrootfstype=ext4 rootwait\0" \ + "bootpart=0:2\0" \ "nandroot=ubi0:rootfs rw ubi.mtd=7,2048\0" \ "nandrootfstype=ubifs rootwait=1\0" \ "nandsrcaddr=0x280000\0" \ @@ -96,16 +97,15 @@ "nfsroot=${serverip}:${rootpath},${nfsopts} rw " \ "ip=dhcp\0" \ "bootenv=uEnv.txt\0" \ - "loadbootenv=fatload mmc ${mmcdev} ${loadaddr} ${bootenv}\0" \ + "loadbootenv=load mmc ${mmcdev} ${loadaddr} ${bootenv}\0" \ "importbootenv=echo Importing environment from mmc ...; " \ "env import -t $loadaddr $filesize\0" \ "ramargs=setenv bootargs console=${console} " \ "${optargs} " \ "root=${ramroot} " \ "rootfstype=${ramrootfstype}\0" \ - "loadramdisk=fatload mmc ${mmcdev} ${rdaddr} ramdisk.gz\0" \ - "loaduimagefat=fatload mmc ${mmcdev} ${loadaddr} ${bootfile}\0" \ - "loaduimage=ext2load mmc ${mmcdev}:2 ${loadaddr} ${bootfile}\0" \ + "loadramdisk=load mmc ${mmcdev} ${rdaddr} ramdisk.gz\0" \ + "loaduimage=load mmc ${bootpart} ${loadaddr} ${bootfile}\0" \ "mmcboot=echo Booting from mmc ...; " \ "run mmcargs; " \ "bootm ${loadaddr}\0" \ @@ -194,6 +194,8 @@ #define CONFIG_DOS_PARTITION #define CONFIG_CMD_FAT #define CONFIG_CMD_EXT2 +#define CONFIG_CMD_EXT4 +#define CONFIG_CMD_FS_GENERIC #define CONFIG_SPI #define CONFIG_OMAP3_SPI -- cgit v1.2.3 From 951d582778a221a79682c4a2619dfcdb7d05d54e Mon Sep 17 00:00:00 2001 From: Koen Kooi Date: Thu, 14 Mar 2013 05:55:21 +0000 Subject: am335x_evm: Add more variables and switch to DT booting. Make bootcmd run findfdt so that we know what dtb file to load. Add a loadfdt command to load this file in. Make mmcboot pass in ${fdtaddr} and make the mmc section of bootcmd run loadfdt. Signed-off-by: Koen Kooi Signed-off-by: Tom Rini Acked-by: Peter Korsgaard --- include/configs/am335x_evm.h | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/include/configs/am335x_evm.h b/include/configs/am335x_evm.h index fc14c90306..92daff5e00 100644 --- a/include/configs/am335x_evm.h +++ b/include/configs/am335x_evm.h @@ -56,7 +56,8 @@ "fdtaddr=0x80F80000\0" \ "fdt_high=0xffffffff\0" \ "rdaddr=0x81000000\0" \ - "bootfile=/boot/uImage\0" \ + "bootdir=/boot\0" \ + "bootfile=uImage\0" \ "fdtfile=\0" \ "console=ttyO0,115200n8\0" \ "optargs=\0" \ @@ -105,10 +106,11 @@ "root=${ramroot} " \ "rootfstype=${ramrootfstype}\0" \ "loadramdisk=load mmc ${mmcdev} ${rdaddr} ramdisk.gz\0" \ - "loaduimage=load mmc ${bootpart} ${loadaddr} ${bootfile}\0" \ + "loaduimage=load mmc ${bootpart} ${loadaddr} ${bootdir}/${bootfile}\0" \ + "loadfdt=load mmc ${bootpart} ${fdtaddr} ${bootdir}/${fdtfile}\0" \ "mmcboot=echo Booting from mmc ...; " \ "run mmcargs; " \ - "bootm ${loadaddr}\0" \ + "bootm ${loadaddr} - ${fdtaddr}\0" \ "nandboot=echo Booting from nand ...; " \ "run nandargs; " \ "nand read ${loadaddr} ${nandsrcaddr} ${nandimgsize}; " \ @@ -122,11 +124,12 @@ "setenv autoload no; " \ "dhcp; " \ "tftp ${loadaddr} ${bootfile}; " \ + "tftp ${fdtaddr} ${fdtfile}; " \ "run netargs; " \ - "bootm ${loadaddr}\0" \ + "bootm ${loadaddr} - ${fdtaddr}\0" \ "ramboot=echo Booting from ramdisk ...; " \ "run ramargs; " \ - "bootm ${loadaddr}\0" \ + "bootm ${loadaddr} ${rdaddr} ${fdtaddr}\0" \ "findfdt="\ "if test $board_name = A335BONE; then " \ "setenv fdtfile am335x-bone.dtb; fi; " \ @@ -140,6 +143,7 @@ #endif #define CONFIG_BOOTCOMMAND \ + "run findfdt; " \ "mmc dev ${mmcdev}; if mmc rescan; then " \ "echo SD/MMC found on device ${mmcdev};" \ "if run loadbootenv; then " \ @@ -151,6 +155,7 @@ "run uenvcmd;" \ "fi;" \ "if run loaduimage; then " \ + "run loadfdt;" \ "run mmcboot;" \ "fi;" \ "else " \ -- cgit v1.2.3 From 1e7e374b3577888ff6f9e3273fa0ad67e2dc45bf Mon Sep 17 00:00:00 2001 From: Steve Kipisz Date: Fri, 8 Mar 2013 07:40:58 +0000 Subject: am33xx:ddr:Fix config_sdram to work for all DDR The original write to sdram_config is correct for DDR3 but incorrect for DDR2 so SPL was hanging. For DDR2, the write to sdram_config should be after the writes to ref_ctrl. This was working for DDR3 because there was a write of 0x2800 to ref_ctrl before a write to sdram_config. Tested on: GP EVM 1.1A (DDR2), GP EVM 1.5A (DDR3), Beaglebone A6 (DDR2), Beagleone Blacd A4A (DDR3) Signed-off-by: Steve Kipisz --- arch/arm/cpu/armv7/am33xx/ddr.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/arm/cpu/armv7/am33xx/ddr.c b/arch/arm/cpu/armv7/am33xx/ddr.c index 448cc40157..7932a39e7c 100644 --- a/arch/arm/cpu/armv7/am33xx/ddr.c +++ b/arch/arm/cpu/armv7/am33xx/ddr.c @@ -54,10 +54,13 @@ void config_sdram(const struct emif_regs *regs) writel(0x2800, &emif_reg->emif_sdram_ref_ctrl); writel(regs->zq_config, &emif_reg->emif_zq_config); writel(regs->sdram_config, &cstat->secure_emif_sdram_config); + writel(regs->sdram_config, &emif_reg->emif_sdram_config); + writel(regs->ref_ctrl, &emif_reg->emif_sdram_ref_ctrl); + writel(regs->ref_ctrl, &emif_reg->emif_sdram_ref_ctrl_shdw); } - writel(regs->sdram_config, &emif_reg->emif_sdram_config); writel(regs->ref_ctrl, &emif_reg->emif_sdram_ref_ctrl); writel(regs->ref_ctrl, &emif_reg->emif_sdram_ref_ctrl_shdw); + writel(regs->sdram_config, &emif_reg->emif_sdram_config); } /** -- cgit v1.2.3 From c5d4752c0541ea0af559250bd2bec6556fed6915 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Mon, 4 Mar 2013 13:29:40 +0000 Subject: ARM: implement erratum 716044 workaround Add common code to enable the workaround for ARM erratum 716044. This will be enabled for Tegra. Signed-off-by: Stephen Warren --- README | 1 + arch/arm/cpu/armv7/start.S | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/README b/README index 7f2506a9b9..616bfb0c6e 100644 --- a/README +++ b/README @@ -485,6 +485,7 @@ The following options need to be configured: Thumb2 this flag will result in Thumb2 code generated by GCC. + CONFIG_ARM_ERRATA_716044 CONFIG_ARM_ERRATA_742230 CONFIG_ARM_ERRATA_743622 CONFIG_ARM_ERRATA_751472 diff --git a/arch/arm/cpu/armv7/start.S b/arch/arm/cpu/armv7/start.S index fa5fad1b0c..c0e184994a 100644 --- a/arch/arm/cpu/armv7/start.S +++ b/arch/arm/cpu/armv7/start.S @@ -310,6 +310,12 @@ ENTRY(cpu_init_cp15) #endif mcr p15, 0, r0, c1, c0, 0 +#ifdef CONFIG_ARM_ERRATA_716044 + mrc p15, 0, r0, c1, c0, 0 @ read system control register + orr r0, r0, #1 << 11 @ set bit #11 + mcr p15, 0, r0, c1, c0, 0 @ write system control register +#endif + #ifdef CONFIG_ARM_ERRATA_742230 mrc p15, 0, r0, c15, c0, 1 @ read diagnostic register orr r0, r0, #1 << 4 @ set bit #4 -- cgit v1.2.3 From 536121328eae940458f065608345b5fed8286859 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Mon, 4 Mar 2013 13:29:41 +0000 Subject: ARM: tegra: enable workaround for ARM erratum 716044 Tegra20 requires the workaround for this erratum. Enable it. Signed-off-by: Stephen Warren --- include/configs/tegra20-common.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/configs/tegra20-common.h b/include/configs/tegra20-common.h index e464e06173..395a657584 100644 --- a/include/configs/tegra20-common.h +++ b/include/configs/tegra20-common.h @@ -28,6 +28,7 @@ /* * Errata configuration */ +#define CONFIG_ARM_ERRATA_716044 #define CONFIG_ARM_ERRATA_742230 #define CONFIG_ARM_ERRATA_751472 -- cgit v1.2.3 From 59dcf970d11ebff5d9f4bbbde79fda584e9e7ad4 Mon Sep 17 00:00:00 2001 From: Vaibhav Hiremath Date: Thu, 14 Mar 2013 21:11:16 +0000 Subject: am335x: Enable DDR PHY dynamic power down bit for DDR3 boards Enable DDR PHY dynamic power down bit, which enables powering down the IO receiver when not performing read. This also helps in reducing overall power consumption in low power states (suspend/standby). Signed-off-by: Vaibhav Hiremath Signed-off-by: Satyanarayana, Sandhya Cc: Tom Rini Reviewed-by: Tom Rini --- arch/arm/include/asm/arch-am33xx/ddr_defs.h | 1 + board/ti/am335x/board.c | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/arm/include/asm/arch-am33xx/ddr_defs.h b/arch/arm/include/asm/arch-am33xx/ddr_defs.h index ae43ef8778..7ab3bafc95 100644 --- a/arch/arm/include/asm/arch-am33xx/ddr_defs.h +++ b/arch/arm/include/asm/arch-am33xx/ddr_defs.h @@ -28,6 +28,7 @@ #define VTP_CTRL_START_EN (0x1) #define PHY_DLL_LOCK_DIFF 0x0 #define DDR_CKE_CTRL_NORMAL 0x1 +#define PHY_EN_DYN_PWRDN (0x1 << 20) /* Micron MT47H128M16RT-25E */ #define MT47H128M16RT25E_EMIF_READ_LATENCY 0x100005 diff --git a/board/ti/am335x/board.c b/board/ti/am335x/board.c index f4b972b3e9..2e230f456f 100644 --- a/board/ti/am335x/board.c +++ b/board/ti/am335x/board.c @@ -251,7 +251,8 @@ static struct emif_regs ddr3_emif_reg_data = { .sdram_tim2 = MT41J128MJT125_EMIF_TIM2, .sdram_tim3 = MT41J128MJT125_EMIF_TIM3, .zq_config = MT41J128MJT125_ZQ_CFG, - .emif_ddr_phy_ctlr_1 = MT41J128MJT125_EMIF_READ_LATENCY, + .emif_ddr_phy_ctlr_1 = MT41J128MJT125_EMIF_READ_LATENCY | + PHY_EN_DYN_PWRDN, }; static struct emif_regs ddr3_evm_emif_reg_data = { @@ -261,7 +262,8 @@ static struct emif_regs ddr3_evm_emif_reg_data = { .sdram_tim2 = MT41J512M8RH125_EMIF_TIM2, .sdram_tim3 = MT41J512M8RH125_EMIF_TIM3, .zq_config = MT41J512M8RH125_ZQ_CFG, - .emif_ddr_phy_ctlr_1 = MT41J512M8RH125_EMIF_READ_LATENCY, + .emif_ddr_phy_ctlr_1 = MT41J512M8RH125_EMIF_READ_LATENCY | + PHY_EN_DYN_PWRDN, }; #endif -- cgit v1.2.3 From 244044e151860b114c69c15e322ee3a5df3d5e1e Mon Sep 17 00:00:00 2001 From: Enric Balletbo i Serra Date: Fri, 15 Mar 2013 01:35:37 +0000 Subject: ARM: AM33XX: Fix typo that causes an AM duplication in CPU name. Just fix a typo displaying the CPU info. With CONFIG_DISPLAY_INFO we see something like AMAM335X-GP rev 0 instead of AM335X-GP rev 0. Signed-off-by: Enric Balletbo i Serra Reviewed-by: Javier Martinez Canillas --- arch/arm/cpu/armv7/am33xx/sys_info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/cpu/armv7/am33xx/sys_info.c b/arch/arm/cpu/armv7/am33xx/sys_info.c index 507b6180e6..db99e9535f 100644 --- a/arch/arm/cpu/armv7/am33xx/sys_info.c +++ b/arch/arm/cpu/armv7/am33xx/sys_info.c @@ -120,7 +120,7 @@ int print_cpuinfo(void) sec_s = "?"; } - printf("AM%s-%s rev %d\n", + printf("%s-%s rev %d\n", cpu_s, sec_s, get_cpu_rev()); /* TODO: Print ARM and DDR frequencies */ -- cgit v1.2.3 From e284f88bafb337641423b29c49a3b8570d67e2d2 Mon Sep 17 00:00:00 2001 From: Enric Balletbo i Serra Date: Fri, 15 Mar 2013 02:32:35 +0000 Subject: igep00x0: Enable CONFIG_CMD_BOOTZ With v3.9 and later of the Linux Kernel defaulting to multi-platform images with omap2plus_defconfig, uImage isn't builtable anymore by default. Add CONFIG_CMD_BOOTZ so that we can still boot something the kernel spits out. Signed-off-by: Enric Balletbo i Serra Reviewed-by: Javier Martinez Canillas --- include/configs/igep00x0.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/configs/igep00x0.h b/include/configs/igep00x0.h index 559e3759de..849fb1624f 100644 --- a/include/configs/igep00x0.h +++ b/include/configs/igep00x0.h @@ -55,7 +55,8 @@ #define CONFIG_INITRD_TAG 1 #define CONFIG_REVISION_TAG 1 -#define CONFIG_OF_LIBFDT 1 +#define CONFIG_OF_LIBFDT +#define CONFIG_CMD_BOOTZ /* * NS16550 Configuration -- cgit v1.2.3 From 98f92001b3af0748d02e36b515a59865fb187415 Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Thu, 14 Mar 2013 11:15:25 +0000 Subject: am33xx: Add required includes to some omap/am33xx code - In arch/arm/cpu/armv7/omap-common/timer.c, drivers/mtd/nand/omap_gpmc.c and drivers/net/cpsw.c add #include files that the driver needs but had been relying on to bring in. - In arch/arm/cpu/armv7/omap-common/lowlevel_init.S add - In am335x_evm.h and pcm051.h don't globally include and but just as that is the only include which defines things the config uses. Cc: Lars Poeschel Signed-off-by: Tom Rini --- arch/arm/cpu/armv7/omap-common/lowlevel_init.S | 1 + arch/arm/cpu/armv7/omap-common/timer.c | 1 + arch/arm/include/asm/arch-am33xx/sys_proto.h | 2 ++ drivers/mtd/nand/omap_gpmc.c | 1 + drivers/net/cpsw.c | 1 + include/configs/am335x_evm.h | 3 +-- include/configs/pcm051.h | 3 +-- 7 files changed, 8 insertions(+), 4 deletions(-) diff --git a/arch/arm/cpu/armv7/omap-common/lowlevel_init.S b/arch/arm/cpu/armv7/omap-common/lowlevel_init.S index 358107776d..b933fe8437 100644 --- a/arch/arm/cpu/armv7/omap-common/lowlevel_init.S +++ b/arch/arm/cpu/armv7/omap-common/lowlevel_init.S @@ -26,6 +26,7 @@ * MA 02111-1307 USA */ +#include #include #include #include diff --git a/arch/arm/cpu/armv7/omap-common/timer.c b/arch/arm/cpu/armv7/omap-common/timer.c index 36bea5f94c..507f6873e9 100644 --- a/arch/arm/cpu/armv7/omap-common/timer.c +++ b/arch/arm/cpu/armv7/omap-common/timer.c @@ -34,6 +34,7 @@ #include #include +#include DECLARE_GLOBAL_DATA_PTR; diff --git a/arch/arm/include/asm/arch-am33xx/sys_proto.h b/arch/arm/include/asm/arch-am33xx/sys_proto.h index 97ab60d1b2..0910a9451a 100644 --- a/arch/arm/include/asm/arch-am33xx/sys_proto.h +++ b/arch/arm/include/asm/arch-am33xx/sys_proto.h @@ -34,6 +34,8 @@ void setup_clocks_for_console(void); void ddr_pll_config(unsigned int ddrpll_M); void sdelay(unsigned long); + +struct gpmc_cs; void gpmc_init(void); void enable_gpmc_cs_config(const u32 *gpmc_config, struct gpmc_cs *cs, u32 base, u32 size); diff --git a/drivers/mtd/nand/omap_gpmc.c b/drivers/mtd/nand/omap_gpmc.c index cee394ece4..bbf5443ec8 100644 --- a/drivers/mtd/nand/omap_gpmc.c +++ b/drivers/mtd/nand/omap_gpmc.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/net/cpsw.c b/drivers/net/cpsw.c index 93f8417a4c..7a36850198 100644 --- a/drivers/net/cpsw.c +++ b/drivers/net/cpsw.c @@ -24,6 +24,7 @@ #include #include #include +#include #define BITMASK(bits) (BIT(bits) - 1) #define PHY_REG_MASK 0x1f diff --git a/include/configs/am335x_evm.h b/include/configs/am335x_evm.h index 92daff5e00..b7c443c573 100644 --- a/include/configs/am335x_evm.h +++ b/include/configs/am335x_evm.h @@ -18,8 +18,7 @@ #define CONFIG_AM33XX -#include -#include +#include #define CONFIG_DMA_COHERENT #define CONFIG_DMA_COHERENT_SIZE (1 << 20) diff --git a/include/configs/pcm051.h b/include/configs/pcm051.h index 63ab12329b..d0ea74e0b4 100644 --- a/include/configs/pcm051.h +++ b/include/configs/pcm051.h @@ -21,8 +21,7 @@ #define CONFIG_AM33XX -#include -#include +#include #define CONFIG_DMA_COHERENT #define CONFIG_DMA_COHERENT_SIZE (1 << 20) -- cgit v1.2.3 From 81df2bab46d3bed319e21571c68db8e0a048bbfd Mon Sep 17 00:00:00 2001 From: Matt Porter Date: Fri, 15 Mar 2013 10:07:02 +0000 Subject: am33xx: convert defines from am33xx-specific to generic names Eliminate AM33xx specific names to prepare for TI814x support within AM33xx-land. Signed-off-by: Matt Porter Reviewed-by: Tom Rini --- arch/arm/cpu/armv7/am33xx/board.c | 4 ++-- arch/arm/include/asm/arch-am33xx/hardware.h | 10 +++++----- board/phytec/pcm051/board.c | 6 +++--- board/ti/am335x/board.c | 6 +++--- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/arch/arm/cpu/armv7/am33xx/board.c b/arch/arm/cpu/armv7/am33xx/board.c index e35a3e3a70..885fb2d20e 100644 --- a/arch/arm/cpu/armv7/am33xx/board.c +++ b/arch/arm/cpu/armv7/am33xx/board.c @@ -141,11 +141,11 @@ int arch_misc_init(void) { #ifdef CONFIG_AM335X_USB0 musb_register(&otg0_plat, &otg0_board_data, - (void *)AM335X_USB0_OTG_BASE); + (void *)USB0_OTG_BASE); #endif #ifdef CONFIG_AM335X_USB1 musb_register(&otg1_plat, &otg1_board_data, - (void *)AM335X_USB1_OTG_BASE); + (void *)USB1_OTG_BASE); #endif return 0; } diff --git a/arch/arm/include/asm/arch-am33xx/hardware.h b/arch/arm/include/asm/arch-am33xx/hardware.h index 6dd3296907..7016e25a41 100644 --- a/arch/arm/include/asm/arch-am33xx/hardware.h +++ b/arch/arm/include/asm/arch-am33xx/hardware.h @@ -84,14 +84,14 @@ #define GPMC_BASE 0x50000000 /* CPSW Config space */ -#define AM335X_CPSW_BASE 0x4A100000 -#define AM335X_CPSW_MDIO_BASE 0x4A101000 +#define CPSW_BASE 0x4A100000 +#define CPSW_MDIO_BASE 0x4A101000 /* RTC base address */ -#define AM335X_RTC_BASE 0x44E3E000 +#define RTC_BASE 0x44E3E000 /* OTG */ -#define AM335X_USB0_OTG_BASE 0x47401000 -#define AM335X_USB1_OTG_BASE 0x47401800 +#define USB0_OTG_BASE 0x47401000 +#define USB1_OTG_BASE 0x47401800 #endif /* __AM33XX_HARDWARE_H */ diff --git a/board/phytec/pcm051/board.c b/board/phytec/pcm051/board.c index 55bc018714..471725a2fa 100644 --- a/board/phytec/pcm051/board.c +++ b/board/phytec/pcm051/board.c @@ -61,7 +61,7 @@ static struct ctrl_dev *cdev = (struct ctrl_dev *)CTRL_DEVICE_BASE; static void rtc32k_enable(void) { - struct rtc_regs *rtc = (struct rtc_regs *)AM335X_RTC_BASE; + struct rtc_regs *rtc = (struct rtc_regs *)RTC_BASE; /* * Unlock the RTC's registers. For more details please see the @@ -199,8 +199,8 @@ static struct cpsw_slave_data cpsw_slaves[] = { }; static struct cpsw_platform_data cpsw_data = { - .mdio_base = AM335X_CPSW_MDIO_BASE, - .cpsw_base = AM335X_CPSW_BASE, + .mdio_base = CPSW_MDIO_BASE, + .cpsw_base = CPSW_BASE, .mdio_div = 0xff, .channels = 8, .cpdma_reg_ofs = 0x800, diff --git a/board/ti/am335x/board.c b/board/ti/am335x/board.c index 2e230f456f..758ba15430 100644 --- a/board/ti/am335x/board.c +++ b/board/ti/am335x/board.c @@ -134,7 +134,7 @@ static int read_eeprom(void) static void rtc32k_enable(void) { - struct rtc_regs *rtc = (struct rtc_regs *)AM335X_RTC_BASE; + struct rtc_regs *rtc = (struct rtc_regs *)RTC_BASE; /* * Unlock the RTC's registers. For more details please see the @@ -414,8 +414,8 @@ static struct cpsw_slave_data cpsw_slaves[] = { }; static struct cpsw_platform_data cpsw_data = { - .mdio_base = AM335X_CPSW_MDIO_BASE, - .cpsw_base = AM335X_CPSW_BASE, + .mdio_base = CPSW_MDIO_BASE, + .cpsw_base = CPSW_BASE, .mdio_div = 0xff, .channels = 8, .cpdma_reg_ofs = 0x800, -- cgit v1.2.3 From 3ba65f97cbedb39fb486f42f8daa9b9e0d36705a Mon Sep 17 00:00:00 2001 From: Matt Porter Date: Fri, 15 Mar 2013 10:07:03 +0000 Subject: am33xx: refactor emif4/ddr to support multiple EMIF instances The AM33xx emif4/ddr support closely matches what is need to support TI814x except that TI814x has two EMIF instances. Refactor all the emif4 helper calls and the config_ddr() init function to use an additional instance number argument. Signed-off-by: Matt Porter Reviewed-by: Tom Rini --- arch/arm/cpu/armv7/am33xx/ddr.c | 107 ++++++++++++++++------------ arch/arm/cpu/armv7/am33xx/emif4.c | 40 ++++++----- arch/arm/include/asm/arch-am33xx/ddr_defs.h | 52 ++++++++++++-- arch/arm/include/asm/arch-am33xx/hardware.h | 13 ++-- board/phytec/pcm051/board.c | 2 +- board/ti/am335x/board.c | 6 +- 6 files changed, 144 insertions(+), 76 deletions(-) diff --git a/arch/arm/cpu/armv7/am33xx/ddr.c b/arch/arm/cpu/armv7/am33xx/ddr.c index 7932a39e7c..d1e2fd3f21 100644 --- a/arch/arm/cpu/armv7/am33xx/ddr.c +++ b/arch/arm/cpu/armv7/am33xx/ddr.c @@ -24,15 +24,20 @@ http://www.ti.com/ /** * Base address for EMIF instances */ -static struct emif_reg_struct *emif_reg = { - (struct emif_reg_struct *)EMIF4_0_CFG_BASE}; +static struct emif_reg_struct *emif_reg[2] = { + (struct emif_reg_struct *)EMIF4_0_CFG_BASE, + (struct emif_reg_struct *)EMIF4_1_CFG_BASE}; /** - * Base address for DDR instance + * Base addresses for DDR PHY cmd/data regs */ -static struct ddr_regs *ddr_reg[2] = { - (struct ddr_regs *)DDR_PHY_BASE_ADDR, - (struct ddr_regs *)DDR_PHY_BASE_ADDR2}; +static struct ddr_cmd_regs *ddr_cmd_reg[2] = { + (struct ddr_cmd_regs *)DDR_PHY_CMD_ADDR, + (struct ddr_cmd_regs *)DDR_PHY_CMD_ADDR2}; + +static struct ddr_data_regs *ddr_data_reg[2] = { + (struct ddr_data_regs *)DDR_PHY_DATA_ADDR, + (struct ddr_data_regs *)DDR_PHY_DATA_ADDR2}; /** * Base address for ddr io control instances @@ -43,7 +48,7 @@ static struct ddr_cmdtctrl *ioctrl_reg = { /** * Configure SDRAM */ -void config_sdram(const struct emif_regs *regs) +void config_sdram(const struct emif_regs *regs, int nr) { if (regs->zq_config) { /* @@ -51,71 +56,85 @@ void config_sdram(const struct emif_regs *regs) * about 570us for a delay, which will be long enough * to configure things. */ - writel(0x2800, &emif_reg->emif_sdram_ref_ctrl); - writel(regs->zq_config, &emif_reg->emif_zq_config); + writel(0x2800, &emif_reg[nr]->emif_sdram_ref_ctrl); + writel(regs->zq_config, &emif_reg[nr]->emif_zq_config); writel(regs->sdram_config, &cstat->secure_emif_sdram_config); - writel(regs->sdram_config, &emif_reg->emif_sdram_config); - writel(regs->ref_ctrl, &emif_reg->emif_sdram_ref_ctrl); - writel(regs->ref_ctrl, &emif_reg->emif_sdram_ref_ctrl_shdw); + writel(regs->sdram_config, &emif_reg[nr]->emif_sdram_config); + writel(regs->ref_ctrl, &emif_reg[nr]->emif_sdram_ref_ctrl); + writel(regs->ref_ctrl, &emif_reg[nr]->emif_sdram_ref_ctrl_shdw); } - writel(regs->ref_ctrl, &emif_reg->emif_sdram_ref_ctrl); - writel(regs->ref_ctrl, &emif_reg->emif_sdram_ref_ctrl_shdw); - writel(regs->sdram_config, &emif_reg->emif_sdram_config); + writel(regs->ref_ctrl, &emif_reg[nr]->emif_sdram_ref_ctrl); + writel(regs->ref_ctrl, &emif_reg[nr]->emif_sdram_ref_ctrl_shdw); + writel(regs->sdram_config, &emif_reg[nr]->emif_sdram_config); } /** * Set SDRAM timings */ -void set_sdram_timings(const struct emif_regs *regs) +void set_sdram_timings(const struct emif_regs *regs, int nr) { - writel(regs->sdram_tim1, &emif_reg->emif_sdram_tim_1); - writel(regs->sdram_tim1, &emif_reg->emif_sdram_tim_1_shdw); - writel(regs->sdram_tim2, &emif_reg->emif_sdram_tim_2); - writel(regs->sdram_tim2, &emif_reg->emif_sdram_tim_2_shdw); - writel(regs->sdram_tim3, &emif_reg->emif_sdram_tim_3); - writel(regs->sdram_tim3, &emif_reg->emif_sdram_tim_3_shdw); + writel(regs->sdram_tim1, &emif_reg[nr]->emif_sdram_tim_1); + writel(regs->sdram_tim1, &emif_reg[nr]->emif_sdram_tim_1_shdw); + writel(regs->sdram_tim2, &emif_reg[nr]->emif_sdram_tim_2); + writel(regs->sdram_tim2, &emif_reg[nr]->emif_sdram_tim_2_shdw); + writel(regs->sdram_tim3, &emif_reg[nr]->emif_sdram_tim_3); + writel(regs->sdram_tim3, &emif_reg[nr]->emif_sdram_tim_3_shdw); } /** * Configure DDR PHY */ -void config_ddr_phy(const struct emif_regs *regs) +void config_ddr_phy(const struct emif_regs *regs, int nr) { - writel(regs->emif_ddr_phy_ctlr_1, &emif_reg->emif_ddr_phy_ctrl_1); - writel(regs->emif_ddr_phy_ctlr_1, &emif_reg->emif_ddr_phy_ctrl_1_shdw); + writel(regs->emif_ddr_phy_ctlr_1, + &emif_reg[nr]->emif_ddr_phy_ctrl_1); + writel(regs->emif_ddr_phy_ctlr_1, + &emif_reg[nr]->emif_ddr_phy_ctrl_1_shdw); } /** * Configure DDR CMD control registers */ -void config_cmd_ctrl(const struct cmd_control *cmd) +void config_cmd_ctrl(const struct cmd_control *cmd, int nr) { - writel(cmd->cmd0csratio, &ddr_reg[0]->cm0csratio); - writel(cmd->cmd0dldiff, &ddr_reg[0]->cm0dldiff); - writel(cmd->cmd0iclkout, &ddr_reg[0]->cm0iclkout); + writel(cmd->cmd0csratio, &ddr_cmd_reg[nr]->cm0csratio); + writel(cmd->cmd0dldiff, &ddr_cmd_reg[nr]->cm0dldiff); + writel(cmd->cmd0iclkout, &ddr_cmd_reg[nr]->cm0iclkout); - writel(cmd->cmd1csratio, &ddr_reg[0]->cm1csratio); - writel(cmd->cmd1dldiff, &ddr_reg[0]->cm1dldiff); - writel(cmd->cmd1iclkout, &ddr_reg[0]->cm1iclkout); + writel(cmd->cmd1csratio, &ddr_cmd_reg[nr]->cm1csratio); + writel(cmd->cmd1dldiff, &ddr_cmd_reg[nr]->cm1dldiff); + writel(cmd->cmd1iclkout, &ddr_cmd_reg[nr]->cm1iclkout); - writel(cmd->cmd2csratio, &ddr_reg[0]->cm2csratio); - writel(cmd->cmd2dldiff, &ddr_reg[0]->cm2dldiff); - writel(cmd->cmd2iclkout, &ddr_reg[0]->cm2iclkout); + writel(cmd->cmd2csratio, &ddr_cmd_reg[nr]->cm2csratio); + writel(cmd->cmd2dldiff, &ddr_cmd_reg[nr]->cm2dldiff); + writel(cmd->cmd2iclkout, &ddr_cmd_reg[nr]->cm2iclkout); } /** * Configure DDR DATA registers */ -void config_ddr_data(int macrono, const struct ddr_data *data) +void config_ddr_data(const struct ddr_data *data, int nr) { - writel(data->datardsratio0, &ddr_reg[macrono]->dt0rdsratio0); - writel(data->datawdsratio0, &ddr_reg[macrono]->dt0wdsratio0); - writel(data->datawiratio0, &ddr_reg[macrono]->dt0wiratio0); - writel(data->datagiratio0, &ddr_reg[macrono]->dt0giratio0); - writel(data->datafwsratio0, &ddr_reg[macrono]->dt0fwsratio0); - writel(data->datawrsratio0, &ddr_reg[macrono]->dt0wrsratio0); - writel(data->datauserank0delay, &ddr_reg[macrono]->dt0rdelays0); - writel(data->datadldiff0, &ddr_reg[macrono]->dt0dldiff0); + int i; + + for (i = 0; i < DDR_DATA_REGS_NR; i++) { + writel(data->datardsratio0, + &(ddr_data_reg[nr]+i)->dt0rdsratio0); + writel(data->datawdsratio0, + &(ddr_data_reg[nr]+i)->dt0wdsratio0); + writel(data->datawiratio0, + &(ddr_data_reg[nr]+i)->dt0wiratio0); + writel(data->datagiratio0, + &(ddr_data_reg[nr]+i)->dt0giratio0); + writel(data->datafwsratio0, + &(ddr_data_reg[nr]+i)->dt0fwsratio0); + writel(data->datawrsratio0, + &(ddr_data_reg[nr]+i)->dt0wrsratio0); + writel(data->datauserank0delay, + &(ddr_data_reg[nr]+i)->dt0rdelays0); + writel(data->datadldiff0, + &(ddr_data_reg[nr]+i)->dt0dldiff0); + } } void config_io_ctrl(unsigned long val) diff --git a/arch/arm/cpu/armv7/am33xx/emif4.c b/arch/arm/cpu/armv7/am33xx/emif4.c index 01e3a5204e..76459d81f9 100644 --- a/arch/arm/cpu/armv7/am33xx/emif4.c +++ b/arch/arm/cpu/armv7/am33xx/emif4.c @@ -44,44 +44,48 @@ void dram_init_banksize(void) #ifdef CONFIG_SPL_BUILD -static struct vtp_reg *vtpreg = (struct vtp_reg *)VTP0_CTRL_ADDR; +static struct vtp_reg *vtpreg[2] = { + (struct vtp_reg *)VTP0_CTRL_ADDR, + (struct vtp_reg *)VTP1_CTRL_ADDR}; +#ifdef CONFIG_AM33XX static struct ddr_ctrl *ddrctrl = (struct ddr_ctrl *)DDR_CTRL_ADDR; +#endif -static void config_vtp(void) +static void config_vtp(int nr) { - writel(readl(&vtpreg->vtp0ctrlreg) | VTP_CTRL_ENABLE, - &vtpreg->vtp0ctrlreg); - writel(readl(&vtpreg->vtp0ctrlreg) & (~VTP_CTRL_START_EN), - &vtpreg->vtp0ctrlreg); - writel(readl(&vtpreg->vtp0ctrlreg) | VTP_CTRL_START_EN, - &vtpreg->vtp0ctrlreg); + writel(readl(&vtpreg[nr]->vtp0ctrlreg) | VTP_CTRL_ENABLE, + &vtpreg[nr]->vtp0ctrlreg); + writel(readl(&vtpreg[nr]->vtp0ctrlreg) & (~VTP_CTRL_START_EN), + &vtpreg[nr]->vtp0ctrlreg); + writel(readl(&vtpreg[nr]->vtp0ctrlreg) | VTP_CTRL_START_EN, + &vtpreg[nr]->vtp0ctrlreg); /* Poll for READY */ - while ((readl(&vtpreg->vtp0ctrlreg) & VTP_CTRL_READY) != + while ((readl(&vtpreg[nr]->vtp0ctrlreg) & VTP_CTRL_READY) != VTP_CTRL_READY) ; } void config_ddr(unsigned int pll, unsigned int ioctrl, const struct ddr_data *data, const struct cmd_control *ctrl, - const struct emif_regs *regs) + const struct emif_regs *regs, int nr) { enable_emif_clocks(); ddr_pll_config(pll); - config_vtp(); - config_cmd_ctrl(ctrl); - - config_ddr_data(0, data); - config_ddr_data(1, data); + config_vtp(nr); + config_cmd_ctrl(ctrl, nr); + config_ddr_data(data, nr); +#ifdef CONFIG_AM33XX config_io_ctrl(ioctrl); /* Set CKE to be controlled by EMIF/DDR PHY */ writel(DDR_CKE_CTRL_NORMAL, &ddrctrl->ddrckectrl); +#endif /* Program EMIF instance */ - config_ddr_phy(regs); - set_sdram_timings(regs); - config_sdram(regs); + config_ddr_phy(regs, nr); + set_sdram_timings(regs, nr); + config_sdram(regs, nr); } #endif diff --git a/arch/arm/include/asm/arch-am33xx/ddr_defs.h b/arch/arm/include/asm/arch-am33xx/ddr_defs.h index 7ab3bafc95..55c61e6598 100644 --- a/arch/arm/include/asm/arch-am33xx/ddr_defs.h +++ b/arch/arm/include/asm/arch-am33xx/ddr_defs.h @@ -103,17 +103,57 @@ /** * Configure SDRAM */ -void config_sdram(const struct emif_regs *regs); +void config_sdram(const struct emif_regs *regs, int nr); /** * Set SDRAM timings */ -void set_sdram_timings(const struct emif_regs *regs); +void set_sdram_timings(const struct emif_regs *regs, int nr); /** * Configure DDR PHY */ -void config_ddr_phy(const struct emif_regs *regs); +void config_ddr_phy(const struct emif_regs *regs, int nr); + +struct ddr_cmd_regs { + unsigned int resv0[7]; + unsigned int cm0csratio; /* offset 0x01C */ + unsigned int resv1[2]; + unsigned int cm0dldiff; /* offset 0x028 */ + unsigned int cm0iclkout; /* offset 0x02C */ + unsigned int resv2[8]; + unsigned int cm1csratio; /* offset 0x050 */ + unsigned int resv3[2]; + unsigned int cm1dldiff; /* offset 0x05C */ + unsigned int cm1iclkout; /* offset 0x060 */ + unsigned int resv4[8]; + unsigned int cm2csratio; /* offset 0x084 */ + unsigned int resv5[2]; + unsigned int cm2dldiff; /* offset 0x090 */ + unsigned int cm2iclkout; /* offset 0x094 */ + unsigned int resv6[3]; +}; + +struct ddr_data_regs { + unsigned int dt0rdsratio0; /* offset 0x0C8 */ + unsigned int resv1[4]; + unsigned int dt0wdsratio0; /* offset 0x0DC */ + unsigned int resv2[4]; + unsigned int dt0wiratio0; /* offset 0x0F0 */ + unsigned int resv3; + unsigned int dt0wimode0; /* offset 0x0F8 */ + unsigned int dt0giratio0; /* offset 0x0FC */ + unsigned int resv4; + unsigned int dt0gimode0; /* offset 0x104 */ + unsigned int dt0fwsratio0; /* offset 0x108 */ + unsigned int resv5[4]; + unsigned int dt0dqoffset; /* offset 0x11C */ + unsigned int dt0wrsratio0; /* offset 0x120 */ + unsigned int resv6[4]; + unsigned int dt0rdelays0; /* offset 0x134 */ + unsigned int dt0dldiff0; /* offset 0x138 */ + unsigned int resv7[12]; +}; /** * This structure represents the DDR registers on AM33XX devices. @@ -194,12 +234,12 @@ struct ddr_data { /** * Configure DDR CMD control registers */ -void config_cmd_ctrl(const struct cmd_control *cmd); +void config_cmd_ctrl(const struct cmd_control *cmd, int nr); /** * Configure DDR DATA registers */ -void config_ddr_data(int data_macrono, const struct ddr_data *data); +void config_ddr_data(const struct ddr_data *data, int nr); /** * This structure represents the DDR io control on AM33XX devices. @@ -227,6 +267,6 @@ struct ddr_ctrl { void config_ddr(unsigned int pll, unsigned int ioctrl, const struct ddr_data *data, const struct cmd_control *ctrl, - const struct emif_regs *regs); + const struct emif_regs *regs, int nr); #endif /* _DDR_DEFS_H */ diff --git a/arch/arm/include/asm/arch-am33xx/hardware.h b/arch/arm/include/asm/arch-am33xx/hardware.h index 7016e25a41..24a9b8d2d4 100644 --- a/arch/arm/include/asm/arch-am33xx/hardware.h +++ b/arch/arm/include/asm/arch-am33xx/hardware.h @@ -3,7 +3,7 @@ * * hardware specific header * - * Copyright (C) 2011, Texas Instruments, Incorporated - http://www.ti.com/ + * Copyright (C) 2013, Texas Instruments, Incorporated - http://www.ti.com/ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -20,6 +20,11 @@ #define __AM33XX_HARDWARE_H #include +#ifdef CONFIG_AM33XX +#include +#elif defined(CONFIG_TI814X) +#include +#endif /* Module base addresses */ #define UART0_BASE 0x44E09000 @@ -66,13 +71,13 @@ #define PRM_DEVICE 0x44E00F00 /* VTP Base address */ -#define VTP0_CTRL_ADDR 0x44E10E0C +#define VTP1_CTRL_ADDR 0x48140E10 /* DDR Base address */ #define DDR_CTRL_ADDR 0x44E10E04 #define DDR_CONTROL_BASE_ADDR 0x44E11404 -#define DDR_PHY_BASE_ADDR 0x44E12000 -#define DDR_PHY_BASE_ADDR2 0x44E120A4 +#define DDR_PHY_CMD_ADDR2 0x47C0C800 +#define DDR_PHY_DATA_ADDR2 0x47C0C8C8 /* UART */ #define DEFAULT_UART_BASE UART0_BASE diff --git a/board/phytec/pcm051/board.c b/board/phytec/pcm051/board.c index 471725a2fa..1708ac2acd 100644 --- a/board/phytec/pcm051/board.c +++ b/board/phytec/pcm051/board.c @@ -159,7 +159,7 @@ void s_init(void) enable_board_pin_mux(); config_ddr(DDR_CLK_MHZ, MT41J256M8HX15E_IOCTRL_VALUE, &ddr3_data, - &ddr3_cmd_ctrl_data, &ddr3_emif_reg_data); + &ddr3_cmd_ctrl_data, &ddr3_emif_reg_data, 0); #endif } diff --git a/board/ti/am335x/board.c b/board/ti/am335x/board.c index 758ba15430..d61d650ea3 100644 --- a/board/ti/am335x/board.c +++ b/board/ti/am335x/board.c @@ -345,13 +345,13 @@ void s_init(void) if (board_is_evm_sk() || board_is_bone_lt()) config_ddr(303, MT41J128MJT125_IOCTRL_VALUE, &ddr3_data, - &ddr3_cmd_ctrl_data, &ddr3_emif_reg_data); + &ddr3_cmd_ctrl_data, &ddr3_emif_reg_data, 0); else if (board_is_evm_15_or_later()) config_ddr(303, MT41J512M8RH125_IOCTRL_VALUE, &ddr3_evm_data, - &ddr3_evm_cmd_ctrl_data, &ddr3_evm_emif_reg_data); + &ddr3_evm_cmd_ctrl_data, &ddr3_evm_emif_reg_data, 0); else config_ddr(266, MT47H128M16RT25E_IOCTRL_VALUE, &ddr2_data, - &ddr2_cmd_ctrl_data, &ddr2_emif_reg_data); + &ddr2_cmd_ctrl_data, &ddr2_emif_reg_data, 0); #endif } -- cgit v1.2.3 From b43c17cba66a8ba88f8a0abc98b2bbb561c54b08 Mon Sep 17 00:00:00 2001 From: Matt Porter Date: Fri, 15 Mar 2013 10:07:04 +0000 Subject: am33xx: refactor am33xx clocks and add ti814x support Split clock.c for am335x and ti814x and add ti814x specific clock support. Signed-off-by: Matt Porter --- arch/arm/cpu/armv7/am33xx/Makefile | 3 +- arch/arm/cpu/armv7/am33xx/clock.c | 374 ------------------- arch/arm/cpu/armv7/am33xx/clock_am33xx.c | 403 ++++++++++++++++++++ arch/arm/cpu/armv7/am33xx/clock_ti814x.c | 406 +++++++++++++++++++++ arch/arm/include/asm/arch-am33xx/clock.h | 2 +- arch/arm/include/asm/arch-am33xx/clocks_am33xx.h | 31 +- arch/arm/include/asm/arch-am33xx/hardware_am33xx.h | 30 ++ arch/arm/include/asm/arch-am33xx/hardware_ti814x.h | 30 ++ 8 files changed, 874 insertions(+), 405 deletions(-) delete mode 100644 arch/arm/cpu/armv7/am33xx/clock.c create mode 100644 arch/arm/cpu/armv7/am33xx/clock_am33xx.c create mode 100644 arch/arm/cpu/armv7/am33xx/clock_ti814x.c create mode 100644 arch/arm/include/asm/arch-am33xx/hardware_am33xx.h create mode 100644 arch/arm/include/asm/arch-am33xx/hardware_ti814x.h diff --git a/arch/arm/cpu/armv7/am33xx/Makefile b/arch/arm/cpu/armv7/am33xx/Makefile index 70c443edbb..c97e30d441 100644 --- a/arch/arm/cpu/armv7/am33xx/Makefile +++ b/arch/arm/cpu/armv7/am33xx/Makefile @@ -16,7 +16,8 @@ include $(TOPDIR)/config.mk LIB = $(obj)lib$(SOC).o -COBJS += clock.o +COBJS-$(CONFIG_AM33XX) += clock_am33xx.o +COBJS-$(CONFIG_TI814X) += clock_ti814x.o COBJS += sys_info.o COBJS += mem.o COBJS += ddr.o diff --git a/arch/arm/cpu/armv7/am33xx/clock.c b/arch/arm/cpu/armv7/am33xx/clock.c deleted file mode 100644 index d7d98d1111..0000000000 --- a/arch/arm/cpu/armv7/am33xx/clock.c +++ /dev/null @@ -1,374 +0,0 @@ -/* - * clock.c - * - * clocks for AM33XX based boards - * - * Copyright (C) 2011, Texas Instruments, Incorporated - http://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include - -#define PRCM_MOD_EN 0x2 -#define PRCM_FORCE_WAKEUP 0x2 -#define PRCM_FUNCTL 0x0 - -#define PRCM_EMIF_CLK_ACTIVITY BIT(2) -#define PRCM_L3_GCLK_ACTIVITY BIT(4) - -#define PLL_BYPASS_MODE 0x4 -#define ST_MN_BYPASS 0x00000100 -#define ST_DPLL_CLK 0x00000001 -#define CLK_SEL_MASK 0x7ffff -#define CLK_DIV_MASK 0x1f -#define CLK_DIV2_MASK 0x7f -#define CLK_SEL_SHIFT 0x8 -#define CLK_MODE_SEL 0x7 -#define CLK_MODE_MASK 0xfffffff8 -#define CLK_DIV_SEL 0xFFFFFFE0 -#define CPGMAC0_IDLE 0x30000 -#define DPLL_CLKDCOLDO_GATE_CTRL 0x300 - -const struct cm_perpll *cmper = (struct cm_perpll *)CM_PER; -const struct cm_wkuppll *cmwkup = (struct cm_wkuppll *)CM_WKUP; -const struct cm_dpll *cmdpll = (struct cm_dpll *)CM_DPLL; -const struct cm_rtc *cmrtc = (struct cm_rtc *)CM_RTC; - -static void enable_interface_clocks(void) -{ - /* Enable all the Interconnect Modules */ - writel(PRCM_MOD_EN, &cmper->l3clkctrl); - while (readl(&cmper->l3clkctrl) != PRCM_MOD_EN) - ; - - writel(PRCM_MOD_EN, &cmper->l4lsclkctrl); - while (readl(&cmper->l4lsclkctrl) != PRCM_MOD_EN) - ; - - writel(PRCM_MOD_EN, &cmper->l4fwclkctrl); - while (readl(&cmper->l4fwclkctrl) != PRCM_MOD_EN) - ; - - writel(PRCM_MOD_EN, &cmwkup->wkl4wkclkctrl); - while (readl(&cmwkup->wkl4wkclkctrl) != PRCM_MOD_EN) - ; - - writel(PRCM_MOD_EN, &cmper->l3instrclkctrl); - while (readl(&cmper->l3instrclkctrl) != PRCM_MOD_EN) - ; - - writel(PRCM_MOD_EN, &cmper->l4hsclkctrl); - while (readl(&cmper->l4hsclkctrl) != PRCM_MOD_EN) - ; - - writel(PRCM_MOD_EN, &cmwkup->wkgpio0clkctrl); - while (readl(&cmwkup->wkgpio0clkctrl) != PRCM_MOD_EN) - ; -} - -/* - * Force power domain wake up transition - * Ensure that the corresponding interface clock is active before - * using the peripheral - */ -static void power_domain_wkup_transition(void) -{ - writel(PRCM_FORCE_WAKEUP, &cmper->l3clkstctrl); - writel(PRCM_FORCE_WAKEUP, &cmper->l4lsclkstctrl); - writel(PRCM_FORCE_WAKEUP, &cmwkup->wkclkstctrl); - writel(PRCM_FORCE_WAKEUP, &cmper->l4fwclkstctrl); - writel(PRCM_FORCE_WAKEUP, &cmper->l3sclkstctrl); -} - -/* - * Enable the peripheral clock for required peripherals - */ -static void enable_per_clocks(void) -{ - /* Enable the control module though RBL would have done it*/ - writel(PRCM_MOD_EN, &cmwkup->wkctrlclkctrl); - while (readl(&cmwkup->wkctrlclkctrl) != PRCM_MOD_EN) - ; - - /* Enable the module clock */ - writel(PRCM_MOD_EN, &cmper->timer2clkctrl); - while (readl(&cmper->timer2clkctrl) != PRCM_MOD_EN) - ; - - /* Select the Master osc 24 MHZ as Timer2 clock source */ - writel(0x1, &cmdpll->clktimer2clk); - - /* UART0 */ - writel(PRCM_MOD_EN, &cmwkup->wkup_uart0ctrl); - while (readl(&cmwkup->wkup_uart0ctrl) != PRCM_MOD_EN) - ; - - /* UART1 */ -#ifdef CONFIG_SERIAL2 - writel(PRCM_MOD_EN, &cmper->uart1clkctrl); - while (readl(&cmper->uart1clkctrl) != PRCM_MOD_EN) - ; -#endif /* CONFIG_SERIAL2 */ - - /* UART2 */ -#ifdef CONFIG_SERIAL3 - writel(PRCM_MOD_EN, &cmper->uart2clkctrl); - while (readl(&cmper->uart2clkctrl) != PRCM_MOD_EN) - ; -#endif /* CONFIG_SERIAL3 */ - - /* UART3 */ -#ifdef CONFIG_SERIAL4 - writel(PRCM_MOD_EN, &cmper->uart3clkctrl); - while (readl(&cmper->uart3clkctrl) != PRCM_MOD_EN) - ; -#endif /* CONFIG_SERIAL4 */ - - /* UART4 */ -#ifdef CONFIG_SERIAL5 - writel(PRCM_MOD_EN, &cmper->uart4clkctrl); - while (readl(&cmper->uart4clkctrl) != PRCM_MOD_EN) - ; -#endif /* CONFIG_SERIAL5 */ - - /* UART5 */ -#ifdef CONFIG_SERIAL6 - writel(PRCM_MOD_EN, &cmper->uart5clkctrl); - while (readl(&cmper->uart5clkctrl) != PRCM_MOD_EN) - ; -#endif /* CONFIG_SERIAL6 */ - - /* GPMC */ - writel(PRCM_MOD_EN, &cmper->gpmcclkctrl); - while (readl(&cmper->gpmcclkctrl) != PRCM_MOD_EN) - ; - - /* ELM */ - writel(PRCM_MOD_EN, &cmper->elmclkctrl); - while (readl(&cmper->elmclkctrl) != PRCM_MOD_EN) - ; - - /* MMC0*/ - writel(PRCM_MOD_EN, &cmper->mmc0clkctrl); - while (readl(&cmper->mmc0clkctrl) != PRCM_MOD_EN) - ; - - /* i2c0 */ - writel(PRCM_MOD_EN, &cmwkup->wkup_i2c0ctrl); - while (readl(&cmwkup->wkup_i2c0ctrl) != PRCM_MOD_EN) - ; - - /* gpio1 module */ - writel(PRCM_MOD_EN, &cmper->gpio1clkctrl); - while (readl(&cmper->gpio1clkctrl) != PRCM_MOD_EN) - ; - - /* gpio2 module */ - writel(PRCM_MOD_EN, &cmper->gpio2clkctrl); - while (readl(&cmper->gpio2clkctrl) != PRCM_MOD_EN) - ; - - /* gpio3 module */ - writel(PRCM_MOD_EN, &cmper->gpio3clkctrl); - while (readl(&cmper->gpio3clkctrl) != PRCM_MOD_EN) - ; - - /* i2c1 */ - writel(PRCM_MOD_EN, &cmper->i2c1clkctrl); - while (readl(&cmper->i2c1clkctrl) != PRCM_MOD_EN) - ; - - /* Ethernet */ - writel(PRCM_MOD_EN, &cmper->cpgmac0clkctrl); - while ((readl(&cmper->cpgmac0clkctrl) & CPGMAC0_IDLE) != PRCM_FUNCTL) - ; - - /* spi0 */ - writel(PRCM_MOD_EN, &cmper->spi0clkctrl); - while (readl(&cmper->spi0clkctrl) != PRCM_MOD_EN) - ; - - /* RTC */ - writel(PRCM_MOD_EN, &cmrtc->rtcclkctrl); - while (readl(&cmrtc->rtcclkctrl) != PRCM_MOD_EN) - ; - - /* MUSB */ - writel(PRCM_MOD_EN, &cmper->usb0clkctrl); - while (readl(&cmper->usb0clkctrl) != PRCM_MOD_EN) - ; -} - -static void mpu_pll_config(void) -{ - u32 clkmode, clksel, div_m2; - - clkmode = readl(&cmwkup->clkmoddpllmpu); - clksel = readl(&cmwkup->clkseldpllmpu); - div_m2 = readl(&cmwkup->divm2dpllmpu); - - /* Set the PLL to bypass Mode */ - writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllmpu); - while (readl(&cmwkup->idlestdpllmpu) != ST_MN_BYPASS) - ; - - clksel = clksel & (~CLK_SEL_MASK); - clksel = clksel | ((MPUPLL_M << CLK_SEL_SHIFT) | MPUPLL_N); - writel(clksel, &cmwkup->clkseldpllmpu); - - div_m2 = div_m2 & ~CLK_DIV_MASK; - div_m2 = div_m2 | MPUPLL_M2; - writel(div_m2, &cmwkup->divm2dpllmpu); - - clkmode = clkmode | CLK_MODE_SEL; - writel(clkmode, &cmwkup->clkmoddpllmpu); - - while (readl(&cmwkup->idlestdpllmpu) != ST_DPLL_CLK) - ; -} - -static void core_pll_config(void) -{ - u32 clkmode, clksel, div_m4, div_m5, div_m6; - - clkmode = readl(&cmwkup->clkmoddpllcore); - clksel = readl(&cmwkup->clkseldpllcore); - div_m4 = readl(&cmwkup->divm4dpllcore); - div_m5 = readl(&cmwkup->divm5dpllcore); - div_m6 = readl(&cmwkup->divm6dpllcore); - - /* Set the PLL to bypass Mode */ - writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllcore); - - while (readl(&cmwkup->idlestdpllcore) != ST_MN_BYPASS) - ; - - clksel = clksel & (~CLK_SEL_MASK); - clksel = clksel | ((COREPLL_M << CLK_SEL_SHIFT) | COREPLL_N); - writel(clksel, &cmwkup->clkseldpllcore); - - div_m4 = div_m4 & ~CLK_DIV_MASK; - div_m4 = div_m4 | COREPLL_M4; - writel(div_m4, &cmwkup->divm4dpllcore); - - div_m5 = div_m5 & ~CLK_DIV_MASK; - div_m5 = div_m5 | COREPLL_M5; - writel(div_m5, &cmwkup->divm5dpllcore); - - div_m6 = div_m6 & ~CLK_DIV_MASK; - div_m6 = div_m6 | COREPLL_M6; - writel(div_m6, &cmwkup->divm6dpllcore); - - clkmode = clkmode | CLK_MODE_SEL; - writel(clkmode, &cmwkup->clkmoddpllcore); - - while (readl(&cmwkup->idlestdpllcore) != ST_DPLL_CLK) - ; -} - -static void per_pll_config(void) -{ - u32 clkmode, clksel, div_m2; - - clkmode = readl(&cmwkup->clkmoddpllper); - clksel = readl(&cmwkup->clkseldpllper); - div_m2 = readl(&cmwkup->divm2dpllper); - - /* Set the PLL to bypass Mode */ - writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllper); - - while (readl(&cmwkup->idlestdpllper) != ST_MN_BYPASS) - ; - - clksel = clksel & (~CLK_SEL_MASK); - clksel = clksel | ((PERPLL_M << CLK_SEL_SHIFT) | PERPLL_N); - writel(clksel, &cmwkup->clkseldpllper); - - div_m2 = div_m2 & ~CLK_DIV2_MASK; - div_m2 = div_m2 | PERPLL_M2; - writel(div_m2, &cmwkup->divm2dpllper); - - clkmode = clkmode | CLK_MODE_SEL; - writel(clkmode, &cmwkup->clkmoddpllper); - - while (readl(&cmwkup->idlestdpllper) != ST_DPLL_CLK) - ; - - writel(DPLL_CLKDCOLDO_GATE_CTRL, &cmwkup->clkdcoldodpllper); -} - -void ddr_pll_config(unsigned int ddrpll_m) -{ - u32 clkmode, clksel, div_m2; - - clkmode = readl(&cmwkup->clkmoddpllddr); - clksel = readl(&cmwkup->clkseldpllddr); - div_m2 = readl(&cmwkup->divm2dpllddr); - - /* Set the PLL to bypass Mode */ - clkmode = (clkmode & CLK_MODE_MASK) | PLL_BYPASS_MODE; - writel(clkmode, &cmwkup->clkmoddpllddr); - - /* Wait till bypass mode is enabled */ - while ((readl(&cmwkup->idlestdpllddr) & ST_MN_BYPASS) - != ST_MN_BYPASS) - ; - - clksel = clksel & (~CLK_SEL_MASK); - clksel = clksel | ((ddrpll_m << CLK_SEL_SHIFT) | DDRPLL_N); - writel(clksel, &cmwkup->clkseldpllddr); - - div_m2 = div_m2 & CLK_DIV_SEL; - div_m2 = div_m2 | DDRPLL_M2; - writel(div_m2, &cmwkup->divm2dpllddr); - - clkmode = (clkmode & CLK_MODE_MASK) | CLK_MODE_SEL; - writel(clkmode, &cmwkup->clkmoddpllddr); - - /* Wait till dpll is locked */ - while ((readl(&cmwkup->idlestdpllddr) & ST_DPLL_CLK) != ST_DPLL_CLK) - ; -} - -void enable_emif_clocks(void) -{ - /* Enable the EMIF_FW Functional clock */ - writel(PRCM_MOD_EN, &cmper->emiffwclkctrl); - /* Enable EMIF0 Clock */ - writel(PRCM_MOD_EN, &cmper->emifclkctrl); - /* Poll if module is functional */ - while ((readl(&cmper->emifclkctrl)) != PRCM_MOD_EN) - ; -} - -/* - * Configure the PLL/PRCM for necessary peripherals - */ -void pll_init() -{ - mpu_pll_config(); - core_pll_config(); - per_pll_config(); - - /* Enable the required interconnect clocks */ - enable_interface_clocks(); - - /* Power domain wake up transition */ - power_domain_wkup_transition(); - - /* Enable the required peripherals */ - enable_per_clocks(); -} diff --git a/arch/arm/cpu/armv7/am33xx/clock_am33xx.c b/arch/arm/cpu/armv7/am33xx/clock_am33xx.c new file mode 100644 index 0000000000..afc0d92059 --- /dev/null +++ b/arch/arm/cpu/armv7/am33xx/clock_am33xx.c @@ -0,0 +1,403 @@ +/* + * clock_am33xx.c + * + * clocks for AM33XX based boards + * + * Copyright (C) 2013, Texas Instruments, Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include + +#define PRCM_MOD_EN 0x2 +#define PRCM_FORCE_WAKEUP 0x2 +#define PRCM_FUNCTL 0x0 + +#define PRCM_EMIF_CLK_ACTIVITY BIT(2) +#define PRCM_L3_GCLK_ACTIVITY BIT(4) + +#define PLL_BYPASS_MODE 0x4 +#define ST_MN_BYPASS 0x00000100 +#define ST_DPLL_CLK 0x00000001 +#define CLK_SEL_MASK 0x7ffff +#define CLK_DIV_MASK 0x1f +#define CLK_DIV2_MASK 0x7f +#define CLK_SEL_SHIFT 0x8 +#define CLK_MODE_SEL 0x7 +#define CLK_MODE_MASK 0xfffffff8 +#define CLK_DIV_SEL 0xFFFFFFE0 +#define CPGMAC0_IDLE 0x30000 +#define DPLL_CLKDCOLDO_GATE_CTRL 0x300 + +#define OSC (V_OSCK/1000000) + +#define MPUPLL_M CONFIG_SYS_MPUCLK +#define MPUPLL_N (OSC-1) +#define MPUPLL_M2 1 + +/* Core PLL Fdll = 1 GHZ, */ +#define COREPLL_M 1000 +#define COREPLL_N (OSC-1) + +#define COREPLL_M4 10 /* CORE_CLKOUTM4 = 200 MHZ */ +#define COREPLL_M5 8 /* CORE_CLKOUTM5 = 250 MHZ */ +#define COREPLL_M6 4 /* CORE_CLKOUTM6 = 500 MHZ */ + +/* + * USB PHY clock is 960 MHZ. Since, this comes directly from Fdll, Fdll + * frequency needs to be set to 960 MHZ. Hence, + * For clkout = 192 MHZ, Fdll = 960 MHZ, divider values are given below + */ +#define PERPLL_M 960 +#define PERPLL_N (OSC-1) +#define PERPLL_M2 5 + +/* DDR Freq is 266 MHZ for now */ +/* Set Fdll = 400 MHZ , Fdll = M * 2 * CLKINP/ N + 1; clkout = Fdll /(2 * M2) */ +#define DDRPLL_M 266 +#define DDRPLL_N (OSC-1) +#define DDRPLL_M2 1 + +const struct cm_perpll *cmper = (struct cm_perpll *)CM_PER; +const struct cm_wkuppll *cmwkup = (struct cm_wkuppll *)CM_WKUP; +const struct cm_dpll *cmdpll = (struct cm_dpll *)CM_DPLL; +const struct cm_rtc *cmrtc = (struct cm_rtc *)CM_RTC; + +static void enable_interface_clocks(void) +{ + /* Enable all the Interconnect Modules */ + writel(PRCM_MOD_EN, &cmper->l3clkctrl); + while (readl(&cmper->l3clkctrl) != PRCM_MOD_EN) + ; + + writel(PRCM_MOD_EN, &cmper->l4lsclkctrl); + while (readl(&cmper->l4lsclkctrl) != PRCM_MOD_EN) + ; + + writel(PRCM_MOD_EN, &cmper->l4fwclkctrl); + while (readl(&cmper->l4fwclkctrl) != PRCM_MOD_EN) + ; + + writel(PRCM_MOD_EN, &cmwkup->wkl4wkclkctrl); + while (readl(&cmwkup->wkl4wkclkctrl) != PRCM_MOD_EN) + ; + + writel(PRCM_MOD_EN, &cmper->l3instrclkctrl); + while (readl(&cmper->l3instrclkctrl) != PRCM_MOD_EN) + ; + + writel(PRCM_MOD_EN, &cmper->l4hsclkctrl); + while (readl(&cmper->l4hsclkctrl) != PRCM_MOD_EN) + ; + + writel(PRCM_MOD_EN, &cmwkup->wkgpio0clkctrl); + while (readl(&cmwkup->wkgpio0clkctrl) != PRCM_MOD_EN) + ; +} + +/* + * Force power domain wake up transition + * Ensure that the corresponding interface clock is active before + * using the peripheral + */ +static void power_domain_wkup_transition(void) +{ + writel(PRCM_FORCE_WAKEUP, &cmper->l3clkstctrl); + writel(PRCM_FORCE_WAKEUP, &cmper->l4lsclkstctrl); + writel(PRCM_FORCE_WAKEUP, &cmwkup->wkclkstctrl); + writel(PRCM_FORCE_WAKEUP, &cmper->l4fwclkstctrl); + writel(PRCM_FORCE_WAKEUP, &cmper->l3sclkstctrl); +} + +/* + * Enable the peripheral clock for required peripherals + */ +static void enable_per_clocks(void) +{ + /* Enable the control module though RBL would have done it*/ + writel(PRCM_MOD_EN, &cmwkup->wkctrlclkctrl); + while (readl(&cmwkup->wkctrlclkctrl) != PRCM_MOD_EN) + ; + + /* Enable the module clock */ + writel(PRCM_MOD_EN, &cmper->timer2clkctrl); + while (readl(&cmper->timer2clkctrl) != PRCM_MOD_EN) + ; + + /* Select the Master osc 24 MHZ as Timer2 clock source */ + writel(0x1, &cmdpll->clktimer2clk); + + /* UART0 */ + writel(PRCM_MOD_EN, &cmwkup->wkup_uart0ctrl); + while (readl(&cmwkup->wkup_uart0ctrl) != PRCM_MOD_EN) + ; + + /* UART1 */ +#ifdef CONFIG_SERIAL2 + writel(PRCM_MOD_EN, &cmper->uart1clkctrl); + while (readl(&cmper->uart1clkctrl) != PRCM_MOD_EN) + ; +#endif /* CONFIG_SERIAL2 */ + + /* UART2 */ +#ifdef CONFIG_SERIAL3 + writel(PRCM_MOD_EN, &cmper->uart2clkctrl); + while (readl(&cmper->uart2clkctrl) != PRCM_MOD_EN) + ; +#endif /* CONFIG_SERIAL3 */ + + /* UART3 */ +#ifdef CONFIG_SERIAL4 + writel(PRCM_MOD_EN, &cmper->uart3clkctrl); + while (readl(&cmper->uart3clkctrl) != PRCM_MOD_EN) + ; +#endif /* CONFIG_SERIAL4 */ + + /* UART4 */ +#ifdef CONFIG_SERIAL5 + writel(PRCM_MOD_EN, &cmper->uart4clkctrl); + while (readl(&cmper->uart4clkctrl) != PRCM_MOD_EN) + ; +#endif /* CONFIG_SERIAL5 */ + + /* UART5 */ +#ifdef CONFIG_SERIAL6 + writel(PRCM_MOD_EN, &cmper->uart5clkctrl); + while (readl(&cmper->uart5clkctrl) != PRCM_MOD_EN) + ; +#endif /* CONFIG_SERIAL6 */ + + /* GPMC */ + writel(PRCM_MOD_EN, &cmper->gpmcclkctrl); + while (readl(&cmper->gpmcclkctrl) != PRCM_MOD_EN) + ; + + /* ELM */ + writel(PRCM_MOD_EN, &cmper->elmclkctrl); + while (readl(&cmper->elmclkctrl) != PRCM_MOD_EN) + ; + + /* MMC0*/ + writel(PRCM_MOD_EN, &cmper->mmc0clkctrl); + while (readl(&cmper->mmc0clkctrl) != PRCM_MOD_EN) + ; + + /* i2c0 */ + writel(PRCM_MOD_EN, &cmwkup->wkup_i2c0ctrl); + while (readl(&cmwkup->wkup_i2c0ctrl) != PRCM_MOD_EN) + ; + + /* gpio1 module */ + writel(PRCM_MOD_EN, &cmper->gpio1clkctrl); + while (readl(&cmper->gpio1clkctrl) != PRCM_MOD_EN) + ; + + /* gpio2 module */ + writel(PRCM_MOD_EN, &cmper->gpio2clkctrl); + while (readl(&cmper->gpio2clkctrl) != PRCM_MOD_EN) + ; + + /* gpio3 module */ + writel(PRCM_MOD_EN, &cmper->gpio3clkctrl); + while (readl(&cmper->gpio3clkctrl) != PRCM_MOD_EN) + ; + + /* i2c1 */ + writel(PRCM_MOD_EN, &cmper->i2c1clkctrl); + while (readl(&cmper->i2c1clkctrl) != PRCM_MOD_EN) + ; + + /* Ethernet */ + writel(PRCM_MOD_EN, &cmper->cpgmac0clkctrl); + while ((readl(&cmper->cpgmac0clkctrl) & CPGMAC0_IDLE) != PRCM_FUNCTL) + ; + + /* spi0 */ + writel(PRCM_MOD_EN, &cmper->spi0clkctrl); + while (readl(&cmper->spi0clkctrl) != PRCM_MOD_EN) + ; + + /* RTC */ + writel(PRCM_MOD_EN, &cmrtc->rtcclkctrl); + while (readl(&cmrtc->rtcclkctrl) != PRCM_MOD_EN) + ; + + /* MUSB */ + writel(PRCM_MOD_EN, &cmper->usb0clkctrl); + while (readl(&cmper->usb0clkctrl) != PRCM_MOD_EN) + ; +} + +static void mpu_pll_config(void) +{ + u32 clkmode, clksel, div_m2; + + clkmode = readl(&cmwkup->clkmoddpllmpu); + clksel = readl(&cmwkup->clkseldpllmpu); + div_m2 = readl(&cmwkup->divm2dpllmpu); + + /* Set the PLL to bypass Mode */ + writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllmpu); + while (readl(&cmwkup->idlestdpllmpu) != ST_MN_BYPASS) + ; + + clksel = clksel & (~CLK_SEL_MASK); + clksel = clksel | ((MPUPLL_M << CLK_SEL_SHIFT) | MPUPLL_N); + writel(clksel, &cmwkup->clkseldpllmpu); + + div_m2 = div_m2 & ~CLK_DIV_MASK; + div_m2 = div_m2 | MPUPLL_M2; + writel(div_m2, &cmwkup->divm2dpllmpu); + + clkmode = clkmode | CLK_MODE_SEL; + writel(clkmode, &cmwkup->clkmoddpllmpu); + + while (readl(&cmwkup->idlestdpllmpu) != ST_DPLL_CLK) + ; +} + +static void core_pll_config(void) +{ + u32 clkmode, clksel, div_m4, div_m5, div_m6; + + clkmode = readl(&cmwkup->clkmoddpllcore); + clksel = readl(&cmwkup->clkseldpllcore); + div_m4 = readl(&cmwkup->divm4dpllcore); + div_m5 = readl(&cmwkup->divm5dpllcore); + div_m6 = readl(&cmwkup->divm6dpllcore); + + /* Set the PLL to bypass Mode */ + writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllcore); + + while (readl(&cmwkup->idlestdpllcore) != ST_MN_BYPASS) + ; + + clksel = clksel & (~CLK_SEL_MASK); + clksel = clksel | ((COREPLL_M << CLK_SEL_SHIFT) | COREPLL_N); + writel(clksel, &cmwkup->clkseldpllcore); + + div_m4 = div_m4 & ~CLK_DIV_MASK; + div_m4 = div_m4 | COREPLL_M4; + writel(div_m4, &cmwkup->divm4dpllcore); + + div_m5 = div_m5 & ~CLK_DIV_MASK; + div_m5 = div_m5 | COREPLL_M5; + writel(div_m5, &cmwkup->divm5dpllcore); + + div_m6 = div_m6 & ~CLK_DIV_MASK; + div_m6 = div_m6 | COREPLL_M6; + writel(div_m6, &cmwkup->divm6dpllcore); + + clkmode = clkmode | CLK_MODE_SEL; + writel(clkmode, &cmwkup->clkmoddpllcore); + + while (readl(&cmwkup->idlestdpllcore) != ST_DPLL_CLK) + ; +} + +static void per_pll_config(void) +{ + u32 clkmode, clksel, div_m2; + + clkmode = readl(&cmwkup->clkmoddpllper); + clksel = readl(&cmwkup->clkseldpllper); + div_m2 = readl(&cmwkup->divm2dpllper); + + /* Set the PLL to bypass Mode */ + writel(PLL_BYPASS_MODE, &cmwkup->clkmoddpllper); + + while (readl(&cmwkup->idlestdpllper) != ST_MN_BYPASS) + ; + + clksel = clksel & (~CLK_SEL_MASK); + clksel = clksel | ((PERPLL_M << CLK_SEL_SHIFT) | PERPLL_N); + writel(clksel, &cmwkup->clkseldpllper); + + div_m2 = div_m2 & ~CLK_DIV2_MASK; + div_m2 = div_m2 | PERPLL_M2; + writel(div_m2, &cmwkup->divm2dpllper); + + clkmode = clkmode | CLK_MODE_SEL; + writel(clkmode, &cmwkup->clkmoddpllper); + + while (readl(&cmwkup->idlestdpllper) != ST_DPLL_CLK) + ; + + writel(DPLL_CLKDCOLDO_GATE_CTRL, &cmwkup->clkdcoldodpllper); +} + +void ddr_pll_config(unsigned int ddrpll_m) +{ + u32 clkmode, clksel, div_m2; + + clkmode = readl(&cmwkup->clkmoddpllddr); + clksel = readl(&cmwkup->clkseldpllddr); + div_m2 = readl(&cmwkup->divm2dpllddr); + + /* Set the PLL to bypass Mode */ + clkmode = (clkmode & CLK_MODE_MASK) | PLL_BYPASS_MODE; + writel(clkmode, &cmwkup->clkmoddpllddr); + + /* Wait till bypass mode is enabled */ + while ((readl(&cmwkup->idlestdpllddr) & ST_MN_BYPASS) + != ST_MN_BYPASS) + ; + + clksel = clksel & (~CLK_SEL_MASK); + clksel = clksel | ((ddrpll_m << CLK_SEL_SHIFT) | DDRPLL_N); + writel(clksel, &cmwkup->clkseldpllddr); + + div_m2 = div_m2 & CLK_DIV_SEL; + div_m2 = div_m2 | DDRPLL_M2; + writel(div_m2, &cmwkup->divm2dpllddr); + + clkmode = (clkmode & CLK_MODE_MASK) | CLK_MODE_SEL; + writel(clkmode, &cmwkup->clkmoddpllddr); + + /* Wait till dpll is locked */ + while ((readl(&cmwkup->idlestdpllddr) & ST_DPLL_CLK) != ST_DPLL_CLK) + ; +} + +void enable_emif_clocks(void) +{ + /* Enable the EMIF_FW Functional clock */ + writel(PRCM_MOD_EN, &cmper->emiffwclkctrl); + /* Enable EMIF0 Clock */ + writel(PRCM_MOD_EN, &cmper->emifclkctrl); + /* Poll if module is functional */ + while ((readl(&cmper->emifclkctrl)) != PRCM_MOD_EN) + ; +} + +/* + * Configure the PLL/PRCM for necessary peripherals + */ +void pll_init() +{ + mpu_pll_config(); + core_pll_config(); + per_pll_config(); + + /* Enable the required interconnect clocks */ + enable_interface_clocks(); + + /* Power domain wake up transition */ + power_domain_wkup_transition(); + + /* Enable the required peripherals */ + enable_per_clocks(); +} diff --git a/arch/arm/cpu/armv7/am33xx/clock_ti814x.c b/arch/arm/cpu/armv7/am33xx/clock_ti814x.c new file mode 100644 index 0000000000..cb4210f6e6 --- /dev/null +++ b/arch/arm/cpu/armv7/am33xx/clock_ti814x.c @@ -0,0 +1,406 @@ +/* + * clock_ti814x.c + * + * Clocks for TI814X based boards + * + * Copyright (C) 2013, Texas Instruments, Incorporated + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include + +/* PRCM */ +#define PRCM_MOD_EN 0x2 + +/* CLK_SRC */ +#define OSC_SRC0 0 +#define OSC_SRC1 1 + +#define L3_OSC_SRC OSC_SRC0 + +#define OSC_0_FREQ 20 + +#define DCO_HS2_MIN 500 +#define DCO_HS2_MAX 1000 +#define DCO_HS1_MIN 1000 +#define DCO_HS1_MAX 2000 + +#define SELFREQDCO_HS2 0x00000801 +#define SELFREQDCO_HS1 0x00001001 + +#define MPU_N 0x1 +#define MPU_M 0x3C +#define MPU_M2 1 +#define MPU_CLKCTRL 0x1 + +#define L3_N 19 +#define L3_M 880 +#define L3_M2 4 +#define L3_CLKCTRL 0x801 + +#define DDR_N 19 +#define DDR_M 666 +#define DDR_M2 2 +#define DDR_CLKCTRL 0x801 + +/* ADPLLJ register values */ +#define ADPLLJ_CLKCTRL_HS2 0x00000801 /* HS2 mode, TINT2 = 1 */ +#define ADPLLJ_CLKCTRL_HS1 0x00001001 /* HS1 mode, TINT2 = 1 */ +#define ADPLLJ_CLKCTRL_CLKDCOLDOEN (1 << 29) +#define ADPLLJ_CLKCTRL_IDLE (1 << 23) +#define ADPLLJ_CLKCTRL_CLKOUTEN (1 << 20) +#define ADPLLJ_CLKCTRL_CLKOUTLDOEN (1 << 19) +#define ADPLLJ_CLKCTRL_CLKDCOLDOPWDNZ (1 << 17) +#define ADPLLJ_CLKCTRL_LPMODE (1 << 12) +#define ADPLLJ_CLKCTRL_DRIFTGUARDIAN (1 << 11) +#define ADPLLJ_CLKCTRL_REGM4XEN (1 << 10) +#define ADPLLJ_CLKCTRL_TINITZ (1 << 0) +#define ADPLLJ_CLKCTRL_CLKDCO (ADPLLJ_CLKCTRL_CLKDCOLDOEN | \ + ADPLLJ_CLKCTRL_CLKOUTEN | \ + ADPLLJ_CLKCTRL_CLKOUTLDOEN | \ + ADPLLJ_CLKCTRL_CLKDCOLDOPWDNZ) + +#define ADPLLJ_STATUS_PHASELOCK (1 << 10) +#define ADPLLJ_STATUS_FREQLOCK (1 << 9) +#define ADPLLJ_STATUS_PHSFRQLOCK (ADPLLJ_STATUS_PHASELOCK | \ + ADPLLJ_STATUS_FREQLOCK) +#define ADPLLJ_STATUS_BYPASSACK (1 << 8) +#define ADPLLJ_STATUS_BYPASS (1 << 0) +#define ADPLLJ_STATUS_BYPASSANDACK (ADPLLJ_STATUS_BYPASSACK | \ + ADPLLJ_STATUS_BYPASS) + +#define ADPLLJ_TENABLE_ENB (1 << 0) +#define ADPLLJ_TENABLEDIV_ENB (1 << 0) + +#define ADPLLJ_M2NDIV_M2SHIFT 16 + +#define MPU_PLL_BASE (PLL_SUBSYS_BASE + 0x048) +#define L3_PLL_BASE (PLL_SUBSYS_BASE + 0x110) +#define DDR_PLL_BASE (PLL_SUBSYS_BASE + 0x290) + +struct ad_pll { + unsigned int pwrctrl; + unsigned int clkctrl; + unsigned int tenable; + unsigned int tenablediv; + unsigned int m2ndiv; + unsigned int mn2div; + unsigned int fracdiv; + unsigned int bwctrl; + unsigned int fracctrl; + unsigned int status; + unsigned int m3div; + unsigned int rampctrl; +}; + +#define OSC_SRC_CTRL (PLL_SUBSYS_BASE + 0x2C0) + +/* PRCM */ +#define CM_DEFAULT_BASE (PRCM_BASE + 0x0500) + +struct cm_def { + unsigned int resv0[2]; + unsigned int l3fastclkstctrl; + unsigned int resv1[1]; + unsigned int pciclkstctrl; + unsigned int resv2[1]; + unsigned int ducaticlkstctrl; + unsigned int resv3[1]; + unsigned int emif0clkctrl; + unsigned int emif1clkctrl; + unsigned int dmmclkctrl; + unsigned int fwclkctrl; + unsigned int resv4[10]; + unsigned int usbclkctrl; + unsigned int resv5[1]; + unsigned int sataclkctrl; + unsigned int resv6[4]; + unsigned int ducaticlkctrl; + unsigned int pciclkctrl; +}; + +#define CM_ALWON_BASE (PRCM_BASE + 0x1400) + +struct cm_alwon { + unsigned int l3slowclkstctrl; + unsigned int ethclkstctrl; + unsigned int l3medclkstctrl; + unsigned int mmu_clkstctrl; + unsigned int mmucfg_clkstctrl; + unsigned int ocmc0clkstctrl; + unsigned int vcpclkstctrl; + unsigned int mpuclkstctrl; + unsigned int sysclk4clkstctrl; + unsigned int sysclk5clkstctrl; + unsigned int sysclk6clkstctrl; + unsigned int rtcclkstctrl; + unsigned int l3fastclkstctrl; + unsigned int resv0[67]; + unsigned int mcasp0clkctrl; + unsigned int mcasp1clkctrl; + unsigned int mcasp2clkctrl; + unsigned int mcbspclkctrl; + unsigned int uart0clkctrl; + unsigned int uart1clkctrl; + unsigned int uart2clkctrl; + unsigned int gpio0clkctrl; + unsigned int gpio1clkctrl; + unsigned int i2c0clkctrl; + unsigned int i2c1clkctrl; + unsigned int mcasp345clkctrl; + unsigned int atlclkctrl; + unsigned int mlbclkctrl; + unsigned int pataclkctrl; + unsigned int resv1[1]; + unsigned int uart3clkctrl; + unsigned int uart4clkctrl; + unsigned int uart5clkctrl; + unsigned int wdtimerclkctrl; + unsigned int spiclkctrl; + unsigned int mailboxclkctrl; + unsigned int spinboxclkctrl; + unsigned int mmudataclkctrl; + unsigned int resv2[2]; + unsigned int mmucfgclkctrl; + unsigned int resv3[2]; + unsigned int ocmc0clkctrl; + unsigned int vcpclkctrl; + unsigned int resv4[2]; + unsigned int controlclkctrl; + unsigned int resv5[2]; + unsigned int gpmcclkctrl; + unsigned int ethernet0clkctrl; + unsigned int resv6[1]; + unsigned int mpuclkctrl; + unsigned int debugssclkctrl; + unsigned int l3clkctrl; + unsigned int l4hsclkctrl; + unsigned int l4lsclkctrl; + unsigned int rtcclkctrl; + unsigned int tpccclkctrl; + unsigned int tptc0clkctrl; + unsigned int tptc1clkctrl; + unsigned int tptc2clkctrl; + unsigned int tptc3clkctrl; + unsigned int resv7[4]; + unsigned int dcan01clkctrl; + unsigned int mmchs0clkctrl; + unsigned int mmchs1clkctrl; + unsigned int mmchs2clkctrl; + unsigned int custefuseclkctrl; +}; + + +const struct cm_alwon *cmalwon = (struct cm_alwon *)CM_ALWON_BASE; +const struct cm_def *cmdef = (struct cm_def *)CM_DEFAULT_BASE; + +/* + * Enable the peripheral clock for required peripherals + */ +static void enable_per_clocks(void) +{ + /* UART0 */ + writel(PRCM_MOD_EN, &cmalwon->uart0clkctrl); + while (readl(&cmalwon->uart0clkctrl) != PRCM_MOD_EN) + ; + + /* HSMMC1 */ + writel(PRCM_MOD_EN, &cmalwon->mmchs1clkctrl); + while (readl(&cmalwon->mmchs1clkctrl) != PRCM_MOD_EN) + ; +} + +/* + * select the HS1 or HS2 for DCO Freq + * return : CLKCTRL + */ +static u32 pll_dco_freq_sel(u32 clkout_dco) +{ + if (clkout_dco >= DCO_HS2_MIN && clkout_dco < DCO_HS2_MAX) + return SELFREQDCO_HS2; + else if (clkout_dco >= DCO_HS1_MIN && clkout_dco < DCO_HS1_MAX) + return SELFREQDCO_HS1; + else + return -1; +} + +/* + * select the sigma delta config + * return: sigma delta val + */ +static u32 pll_sigma_delta_val(u32 clkout_dco) +{ + u32 sig_val = 0; + float frac_div; + + frac_div = (float) clkout_dco / 250; + frac_div = frac_div + 0.90; + sig_val = (int)frac_div; + sig_val = sig_val << 24; + + return sig_val; +} + +/* + * configure individual ADPLLJ + */ +static void pll_config(u32 base, u32 n, u32 m, u32 m2, + u32 clkctrl_val, int adpllj) +{ + const struct ad_pll *adpll = (struct ad_pll *)base; + u32 m2nval, mn2val, read_clkctrl = 0, clkout_dco = 0; + u32 sig_val = 0, hs_mod = 0; + + m2nval = (m2 << ADPLLJ_M2NDIV_M2SHIFT) | n; + mn2val = m; + + /* calculate clkout_dco */ + clkout_dco = ((OSC_0_FREQ / (n+1)) * m); + + /* sigma delta & Hs mode selection skip for ADPLLS*/ + if (adpllj) { + sig_val = pll_sigma_delta_val(clkout_dco); + hs_mod = pll_dco_freq_sel(clkout_dco); + } + + /* by-pass pll */ + read_clkctrl = readl(&adpll->clkctrl); + writel((read_clkctrl | ADPLLJ_CLKCTRL_IDLE), &adpll->clkctrl); + while ((readl(&adpll->status) & ADPLLJ_STATUS_BYPASSANDACK) + != ADPLLJ_STATUS_BYPASSANDACK) + ; + + /* clear TINITZ */ + read_clkctrl = readl(&adpll->clkctrl); + writel((read_clkctrl & ~ADPLLJ_CLKCTRL_TINITZ), &adpll->clkctrl); + + /* + * ref_clk = 20/(n + 1); + * clkout_dco = ref_clk * m; + * clk_out = clkout_dco/m2; + */ + read_clkctrl = readl(&adpll->clkctrl) & + ~(ADPLLJ_CLKCTRL_LPMODE | + ADPLLJ_CLKCTRL_DRIFTGUARDIAN | + ADPLLJ_CLKCTRL_REGM4XEN); + writel(m2nval, &adpll->m2ndiv); + writel(mn2val, &adpll->mn2div); + + /* Skip for modena(ADPLLS) */ + if (adpllj) { + writel(sig_val, &adpll->fracdiv); + writel((read_clkctrl | hs_mod), &adpll->clkctrl); + } + + /* Load M2, N2 dividers of ADPLL */ + writel(ADPLLJ_TENABLEDIV_ENB, &adpll->tenablediv); + writel(~ADPLLJ_TENABLEDIV_ENB, &adpll->tenablediv); + + /* Load M, N dividers of ADPLL */ + writel(ADPLLJ_TENABLE_ENB, &adpll->tenable); + writel(~ADPLLJ_TENABLE_ENB, &adpll->tenable); + + /* Configure CLKDCOLDOEN,CLKOUTLDOEN,CLKOUT Enable BITS */ + read_clkctrl = readl(&adpll->clkctrl) & ~ADPLLJ_CLKCTRL_CLKDCO; + if (adpllj) + writel((read_clkctrl | ADPLLJ_CLKCTRL_CLKDCO), + &adpll->clkctrl); + + /* Enable TINTZ and disable IDLE(PLL in Active & Locked Mode */ + read_clkctrl = readl(&adpll->clkctrl) & ~ADPLLJ_CLKCTRL_IDLE; + writel((read_clkctrl | ADPLLJ_CLKCTRL_TINITZ), &adpll->clkctrl); + + /* Wait for phase and freq lock */ + while ((readl(&adpll->status) & ADPLLJ_STATUS_PHSFRQLOCK) != + ADPLLJ_STATUS_PHSFRQLOCK) + ; +} + +static void unlock_pll_control_mmr(void) +{ + /* TRM 2.10.1.4 and 3.2.7-3.2.11 */ + writel(0x1EDA4C3D, 0x481C5040); + writel(0x2FF1AC2B, 0x48140060); + writel(0xF757FDC0, 0x48140064); + writel(0xE2BC3A6D, 0x48140068); + writel(0x1EBF131D, 0x4814006c); + writel(0x6F361E05, 0x48140070); +} + +static void mpu_pll_config(void) +{ + pll_config(MPU_PLL_BASE, MPU_N, MPU_M, MPU_M2, MPU_CLKCTRL, 0); +} + +static void l3_pll_config(void) +{ + u32 l3_osc_src, rd_osc_src = 0; + + l3_osc_src = L3_OSC_SRC; + rd_osc_src = readl(OSC_SRC_CTRL); + + if (OSC_SRC0 == l3_osc_src) + writel((rd_osc_src & 0xfffffffe)|0x0, OSC_SRC_CTRL); + else + writel((rd_osc_src & 0xfffffffe)|0x1, OSC_SRC_CTRL); + + pll_config(L3_PLL_BASE, L3_N, L3_M, L3_M2, L3_CLKCTRL, 1); +} + +void ddr_pll_config(unsigned int ddrpll_m) +{ + pll_config(DDR_PLL_BASE, DDR_N, DDR_M, DDR_M2, DDR_CLKCTRL, 1); +} + +void enable_emif_clocks(void) {}; + +void enable_dmm_clocks(void) +{ + writel(PRCM_MOD_EN, &cmdef->fwclkctrl); + writel(PRCM_MOD_EN, &cmdef->l3fastclkstctrl); + writel(PRCM_MOD_EN, &cmdef->emif0clkctrl); + while ((readl(&cmdef->emif0clkctrl)) != PRCM_MOD_EN) + ; + writel(PRCM_MOD_EN, &cmdef->emif1clkctrl); + while ((readl(&cmdef->emif1clkctrl)) != PRCM_MOD_EN) + ; + while ((readl(&cmdef->l3fastclkstctrl) & 0x300) != 0x300) + ; + writel(PRCM_MOD_EN, &cmdef->dmmclkctrl); + while ((readl(&cmdef->dmmclkctrl)) != PRCM_MOD_EN) + ; + writel(PRCM_MOD_EN, &cmalwon->l3slowclkstctrl); + while ((readl(&cmalwon->l3slowclkstctrl) & 0x2100) != 0x2100) + ; +} + +/* + * Configure the PLL/PRCM for necessary peripherals + */ +void pll_init() +{ + unlock_pll_control_mmr(); + + /* Enable the control module */ + writel(PRCM_MOD_EN, &cmalwon->controlclkctrl); + + mpu_pll_config(); + + l3_pll_config(); + + /* Enable the required peripherals */ + enable_per_clocks(); +} diff --git a/arch/arm/include/asm/arch-am33xx/clock.h b/arch/arm/include/asm/arch-am33xx/clock.h index 872ff820af..ecb5901857 100644 --- a/arch/arm/include/asm/arch-am33xx/clock.h +++ b/arch/arm/include/asm/arch-am33xx/clock.h @@ -3,7 +3,7 @@ * * clock header * - * Copyright (C) 2011, Texas Instruments, Incorporated - http://www.ti.com/ + * Copyright (C) 2011, Texas Instruments Incorporated - http://www.ti.com/ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as diff --git a/arch/arm/include/asm/arch-am33xx/clocks_am33xx.h b/arch/arm/include/asm/arch-am33xx/clocks_am33xx.h index 2d960070f1..89b63d9a8c 100644 --- a/arch/arm/include/asm/arch-am33xx/clocks_am33xx.h +++ b/arch/arm/include/asm/arch-am33xx/clocks_am33xx.h @@ -3,7 +3,7 @@ * * AM33xx clock define * - * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -19,40 +19,13 @@ #ifndef _CLOCKS_AM33XX_H_ #define _CLOCKS_AM33XX_H_ -#define OSC (V_OSCK/1000000) - /* MAIN PLL Fdll = 550 MHz, by default */ #ifndef CONFIG_SYS_MPUCLK #define CONFIG_SYS_MPUCLK 550 #endif -#define MPUPLL_M CONFIG_SYS_MPUCLK -#define MPUPLL_N (OSC-1) -#define MPUPLL_M2 1 - -/* Core PLL Fdll = 1 GHZ, */ -#define COREPLL_M 1000 -#define COREPLL_N (OSC-1) - -#define COREPLL_M4 10 /* CORE_CLKOUTM4 = 200 MHZ */ -#define COREPLL_M5 8 /* CORE_CLKOUTM5 = 250 MHZ */ -#define COREPLL_M6 4 /* CORE_CLKOUTM6 = 500 MHZ */ - -/* - * USB PHY clock is 960 MHZ. Since, this comes directly from Fdll, Fdll - * frequency needs to be set to 960 MHZ. Hence, - * For clkout = 192 MHZ, Fdll = 960 MHZ, divider values are given below - */ -#define PERPLL_M 960 -#define PERPLL_N (OSC-1) -#define PERPLL_M2 5 - -/* DDR Freq is 266 MHZ for now */ -/* Set Fdll = 400 MHZ , Fdll = M * 2 * CLKINP/ N + 1; clkout = Fdll /(2 * M2) */ -#define DDRPLL_M 266 -#define DDRPLL_N (OSC-1) -#define DDRPLL_M2 1 extern void pll_init(void); extern void enable_emif_clocks(void); +extern void enable_dmm_clocks(void); #endif /* endif _CLOCKS_AM33XX_H_ */ diff --git a/arch/arm/include/asm/arch-am33xx/hardware_am33xx.h b/arch/arm/include/asm/arch-am33xx/hardware_am33xx.h new file mode 100644 index 0000000000..7a4070c6af --- /dev/null +++ b/arch/arm/include/asm/arch-am33xx/hardware_am33xx.h @@ -0,0 +1,30 @@ +/* + * hardware_am33xx.h + * + * AM33xx hardware specific header + * + * Copyright (C) 2013, Texas Instruments, Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __AM33XX_HARDWARE_AM33XX_H +#define __AM33XX_HARDWARE_AM33XX_H + +/* VTP Base address */ +#define VTP0_CTRL_ADDR 0x44E10E0C + +/* DDR Base address */ +#define DDR_PHY_CMD_ADDR 0x44E12000 +#define DDR_PHY_DATA_ADDR 0x44E120C8 +#define DDR_DATA_REGS_NR 2 + +#endif /* __AM33XX_HARDWARE_AM33XX_H */ diff --git a/arch/arm/include/asm/arch-am33xx/hardware_ti814x.h b/arch/arm/include/asm/arch-am33xx/hardware_ti814x.h new file mode 100644 index 0000000000..af7d1d82e7 --- /dev/null +++ b/arch/arm/include/asm/arch-am33xx/hardware_ti814x.h @@ -0,0 +1,30 @@ +/* + * hardware_ti814x.h + * + * TI814x hardware specific header + * + * Copyright (C) 2013, Texas Instruments, Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __AM33XX_HARDWARE_TI814X_H +#define __AM33XX_HARDWARE_TI814X_H + +/* VTP Base address */ +#define VTP0_CTRL_ADDR 0x48140E0C + +/* DDR Base address */ +#define DDR_PHY_CMD_ADDR 0x47C0C400 +#define DDR_PHY_DATA_ADDR 0x47C0C4C8 +#define DDR_DATA_REGS_NR 4 + +#endif /* __AM33XX_HARDWARE_TI814X_H */ -- cgit v1.2.3 From b2e682f7a08e4f589b7b2266ced58ae7493a344b Mon Sep 17 00:00:00 2001 From: Matt Porter Date: Fri, 15 Mar 2013 10:07:05 +0000 Subject: am33xx: refactor am33xx mux support and add ti814x support AM33XX and TI814X have a similar mux though the pinmux register layout and address space differ. Add a separate ti814x mux include to support the TI814X-specific differences. Signed-off-by: Matt Porter Reviewed-by: Tom Rini Acked-by: Peter Korsgaard --- arch/arm/include/asm/arch-am33xx/mux.h | 235 +------------------ arch/arm/include/asm/arch-am33xx/mux_am33xx.h | 247 ++++++++++++++++++++ arch/arm/include/asm/arch-am33xx/mux_ti814x.h | 311 ++++++++++++++++++++++++++ 3 files changed, 566 insertions(+), 227 deletions(-) create mode 100644 arch/arm/include/asm/arch-am33xx/mux_am33xx.h create mode 100644 arch/arm/include/asm/arch-am33xx/mux_ti814x.h diff --git a/arch/arm/include/asm/arch-am33xx/mux.h b/arch/arm/include/asm/arch-am33xx/mux.h index 460ac1c02d..1c6b65f4a0 100644 --- a/arch/arm/include/asm/arch-am33xx/mux.h +++ b/arch/arm/include/asm/arch-am33xx/mux.h @@ -1,7 +1,7 @@ /* * mux.h * - * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -19,234 +19,15 @@ #include #include -#define MUX_CFG(value, offset) \ - __raw_writel(value, (CTRL_BASE + offset)); - -/* PAD Control Fields */ -#define SLEWCTRL (0x1 << 6) -#define RXACTIVE (0x1 << 5) -#define PULLDOWN_EN (0x0 << 4) /* Pull Down Selection */ -#define PULLUP_EN (0x1 << 4) /* Pull Up Selection */ -#define PULLUDEN (0x0 << 3) /* Pull up enabled */ -#define PULLUDDIS (0x1 << 3) /* Pull up disabled */ -#define MODE(val) val /* used for Readability */ - -/* - * PAD CONTROL OFFSETS - * Field names corresponds to the pad signal name - */ -struct pad_signals { - int gpmc_ad0; - int gpmc_ad1; - int gpmc_ad2; - int gpmc_ad3; - int gpmc_ad4; - int gpmc_ad5; - int gpmc_ad6; - int gpmc_ad7; - int gpmc_ad8; - int gpmc_ad9; - int gpmc_ad10; - int gpmc_ad11; - int gpmc_ad12; - int gpmc_ad13; - int gpmc_ad14; - int gpmc_ad15; - int gpmc_a0; - int gpmc_a1; - int gpmc_a2; - int gpmc_a3; - int gpmc_a4; - int gpmc_a5; - int gpmc_a6; - int gpmc_a7; - int gpmc_a8; - int gpmc_a9; - int gpmc_a10; - int gpmc_a11; - int gpmc_wait0; - int gpmc_wpn; - int gpmc_be1n; - int gpmc_csn0; - int gpmc_csn1; - int gpmc_csn2; - int gpmc_csn3; - int gpmc_clk; - int gpmc_advn_ale; - int gpmc_oen_ren; - int gpmc_wen; - int gpmc_be0n_cle; - int lcd_data0; - int lcd_data1; - int lcd_data2; - int lcd_data3; - int lcd_data4; - int lcd_data5; - int lcd_data6; - int lcd_data7; - int lcd_data8; - int lcd_data9; - int lcd_data10; - int lcd_data11; - int lcd_data12; - int lcd_data13; - int lcd_data14; - int lcd_data15; - int lcd_vsync; - int lcd_hsync; - int lcd_pclk; - int lcd_ac_bias_en; - int mmc0_dat3; - int mmc0_dat2; - int mmc0_dat1; - int mmc0_dat0; - int mmc0_clk; - int mmc0_cmd; - int mii1_col; - int mii1_crs; - int mii1_rxerr; - int mii1_txen; - int mii1_rxdv; - int mii1_txd3; - int mii1_txd2; - int mii1_txd1; - int mii1_txd0; - int mii1_txclk; - int mii1_rxclk; - int mii1_rxd3; - int mii1_rxd2; - int mii1_rxd1; - int mii1_rxd0; - int rmii1_refclk; - int mdio_data; - int mdio_clk; - int spi0_sclk; - int spi0_d0; - int spi0_d1; - int spi0_cs0; - int spi0_cs1; - int ecap0_in_pwm0_out; - int uart0_ctsn; - int uart0_rtsn; - int uart0_rxd; - int uart0_txd; - int uart1_ctsn; - int uart1_rtsn; - int uart1_rxd; - int uart1_txd; - int i2c0_sda; - int i2c0_scl; - int mcasp0_aclkx; - int mcasp0_fsx; - int mcasp0_axr0; - int mcasp0_ahclkr; - int mcasp0_aclkr; - int mcasp0_fsr; - int mcasp0_axr1; - int mcasp0_ahclkx; - int xdma_event_intr0; - int xdma_event_intr1; - int nresetin_out; - int porz; - int nnmi; - int osc0_in; - int osc0_out; - int rsvd1; - int tms; - int tdi; - int tdo; - int tck; - int ntrst; - int emu0; - int emu1; - int osc1_in; - int osc1_out; - int pmic_power_en; - int rtc_porz; - int rsvd2; - int ext_wakeup; - int enz_kaldo_1p8v; - int usb0_dm; - int usb0_dp; - int usb0_ce; - int usb0_id; - int usb0_vbus; - int usb0_drvvbus; - int usb1_dm; - int usb1_dp; - int usb1_ce; - int usb1_id; - int usb1_vbus; - int usb1_drvvbus; - int ddr_resetn; - int ddr_csn0; - int ddr_cke; - int ddr_ck; - int ddr_nck; - int ddr_casn; - int ddr_rasn; - int ddr_wen; - int ddr_ba0; - int ddr_ba1; - int ddr_ba2; - int ddr_a0; - int ddr_a1; - int ddr_a2; - int ddr_a3; - int ddr_a4; - int ddr_a5; - int ddr_a6; - int ddr_a7; - int ddr_a8; - int ddr_a9; - int ddr_a10; - int ddr_a11; - int ddr_a12; - int ddr_a13; - int ddr_a14; - int ddr_a15; - int ddr_odt; - int ddr_d0; - int ddr_d1; - int ddr_d2; - int ddr_d3; - int ddr_d4; - int ddr_d5; - int ddr_d6; - int ddr_d7; - int ddr_d8; - int ddr_d9; - int ddr_d10; - int ddr_d11; - int ddr_d12; - int ddr_d13; - int ddr_d14; - int ddr_d15; - int ddr_dqm0; - int ddr_dqm1; - int ddr_dqs0; - int ddr_dqsn0; - int ddr_dqs1; - int ddr_dqsn1; - int ddr_vref; - int ddr_vtp; - int ddr_strben0; - int ddr_strben1; - int ain7; - int ain6; - int ain5; - int ain4; - int ain3; - int ain2; - int ain1; - int ain0; - int vrefp; - int vrefn; -}; +#ifdef CONFIG_AM33XX +#include +#elif defined(CONFIG_TI814X) +#include +#endif struct module_pin_mux { short reg_offset; - unsigned char val; + unsigned int val; }; /* Pad control register offset */ @@ -259,4 +40,4 @@ struct module_pin_mux { */ void configure_module_pin_mux(struct module_pin_mux *mod_pin_mux); -#endif +#endif /* endif _MUX_H */ diff --git a/arch/arm/include/asm/arch-am33xx/mux_am33xx.h b/arch/arm/include/asm/arch-am33xx/mux_am33xx.h new file mode 100644 index 0000000000..d5cab3e083 --- /dev/null +++ b/arch/arm/include/asm/arch-am33xx/mux_am33xx.h @@ -0,0 +1,247 @@ +/* + * mux_am33xx.h + * + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _MUX_AM33XX_H_ +#define _MUX_AM33XX_H_ + +#include +#include + +#define MUX_CFG(value, offset) \ + __raw_writel(value, (CTRL_BASE + offset)); + +/* PAD Control Fields */ +#define SLEWCTRL (0x1 << 6) +#define RXACTIVE (0x1 << 5) +#define PULLDOWN_EN (0x0 << 4) /* Pull Down Selection */ +#define PULLUP_EN (0x1 << 4) /* Pull Up Selection */ +#define PULLUDEN (0x0 << 3) /* Pull up enabled */ +#define PULLUDDIS (0x1 << 3) /* Pull up disabled */ +#define MODE(val) val /* used for Readability */ + +/* + * PAD CONTROL OFFSETS + * Field names corresponds to the pad signal name + */ +struct pad_signals { + int gpmc_ad0; + int gpmc_ad1; + int gpmc_ad2; + int gpmc_ad3; + int gpmc_ad4; + int gpmc_ad5; + int gpmc_ad6; + int gpmc_ad7; + int gpmc_ad8; + int gpmc_ad9; + int gpmc_ad10; + int gpmc_ad11; + int gpmc_ad12; + int gpmc_ad13; + int gpmc_ad14; + int gpmc_ad15; + int gpmc_a0; + int gpmc_a1; + int gpmc_a2; + int gpmc_a3; + int gpmc_a4; + int gpmc_a5; + int gpmc_a6; + int gpmc_a7; + int gpmc_a8; + int gpmc_a9; + int gpmc_a10; + int gpmc_a11; + int gpmc_wait0; + int gpmc_wpn; + int gpmc_be1n; + int gpmc_csn0; + int gpmc_csn1; + int gpmc_csn2; + int gpmc_csn3; + int gpmc_clk; + int gpmc_advn_ale; + int gpmc_oen_ren; + int gpmc_wen; + int gpmc_be0n_cle; + int lcd_data0; + int lcd_data1; + int lcd_data2; + int lcd_data3; + int lcd_data4; + int lcd_data5; + int lcd_data6; + int lcd_data7; + int lcd_data8; + int lcd_data9; + int lcd_data10; + int lcd_data11; + int lcd_data12; + int lcd_data13; + int lcd_data14; + int lcd_data15; + int lcd_vsync; + int lcd_hsync; + int lcd_pclk; + int lcd_ac_bias_en; + int mmc0_dat3; + int mmc0_dat2; + int mmc0_dat1; + int mmc0_dat0; + int mmc0_clk; + int mmc0_cmd; + int mii1_col; + int mii1_crs; + int mii1_rxerr; + int mii1_txen; + int mii1_rxdv; + int mii1_txd3; + int mii1_txd2; + int mii1_txd1; + int mii1_txd0; + int mii1_txclk; + int mii1_rxclk; + int mii1_rxd3; + int mii1_rxd2; + int mii1_rxd1; + int mii1_rxd0; + int rmii1_refclk; + int mdio_data; + int mdio_clk; + int spi0_sclk; + int spi0_d0; + int spi0_d1; + int spi0_cs0; + int spi0_cs1; + int ecap0_in_pwm0_out; + int uart0_ctsn; + int uart0_rtsn; + int uart0_rxd; + int uart0_txd; + int uart1_ctsn; + int uart1_rtsn; + int uart1_rxd; + int uart1_txd; + int i2c0_sda; + int i2c0_scl; + int mcasp0_aclkx; + int mcasp0_fsx; + int mcasp0_axr0; + int mcasp0_ahclkr; + int mcasp0_aclkr; + int mcasp0_fsr; + int mcasp0_axr1; + int mcasp0_ahclkx; + int xdma_event_intr0; + int xdma_event_intr1; + int nresetin_out; + int porz; + int nnmi; + int osc0_in; + int osc0_out; + int rsvd1; + int tms; + int tdi; + int tdo; + int tck; + int ntrst; + int emu0; + int emu1; + int osc1_in; + int osc1_out; + int pmic_power_en; + int rtc_porz; + int rsvd2; + int ext_wakeup; + int enz_kaldo_1p8v; + int usb0_dm; + int usb0_dp; + int usb0_ce; + int usb0_id; + int usb0_vbus; + int usb0_drvvbus; + int usb1_dm; + int usb1_dp; + int usb1_ce; + int usb1_id; + int usb1_vbus; + int usb1_drvvbus; + int ddr_resetn; + int ddr_csn0; + int ddr_cke; + int ddr_ck; + int ddr_nck; + int ddr_casn; + int ddr_rasn; + int ddr_wen; + int ddr_ba0; + int ddr_ba1; + int ddr_ba2; + int ddr_a0; + int ddr_a1; + int ddr_a2; + int ddr_a3; + int ddr_a4; + int ddr_a5; + int ddr_a6; + int ddr_a7; + int ddr_a8; + int ddr_a9; + int ddr_a10; + int ddr_a11; + int ddr_a12; + int ddr_a13; + int ddr_a14; + int ddr_a15; + int ddr_odt; + int ddr_d0; + int ddr_d1; + int ddr_d2; + int ddr_d3; + int ddr_d4; + int ddr_d5; + int ddr_d6; + int ddr_d7; + int ddr_d8; + int ddr_d9; + int ddr_d10; + int ddr_d11; + int ddr_d12; + int ddr_d13; + int ddr_d14; + int ddr_d15; + int ddr_dqm0; + int ddr_dqm1; + int ddr_dqs0; + int ddr_dqsn0; + int ddr_dqs1; + int ddr_dqsn1; + int ddr_vref; + int ddr_vtp; + int ddr_strben0; + int ddr_strben1; + int ain7; + int ain6; + int ain5; + int ain4; + int ain3; + int ain2; + int ain1; + int ain0; + int vrefp; + int vrefn; +}; + +#endif /* endif _MUX_AM33XX_H_ */ diff --git a/arch/arm/include/asm/arch-am33xx/mux_ti814x.h b/arch/arm/include/asm/arch-am33xx/mux_ti814x.h new file mode 100644 index 0000000000..a26e5038f7 --- /dev/null +++ b/arch/arm/include/asm/arch-am33xx/mux_ti814x.h @@ -0,0 +1,311 @@ +/* + * mux_ti814x.h + * + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _MUX_TI814X_H_ +#define _MUX_TI814X_H_ + +/* PAD Control Fields */ +#define PINCNTL_RSV_MSK (0x3 << 18) /* Reserved bitmask */ +#define PULLUP_EN (0x1 << 17) /* Pull UP Selection */ +#define PULLUDEN (0x0 << 16) /* Pull up enabled */ +#define PULLUDDIS (0x1 << 16) /* Pull up disabled */ +#define MODE(val) val /* used for Readability */ + +#define MUX_CFG(value, offset) \ +{ \ + int tmp; \ + tmp = __raw_readl(CTRL_BASE + offset); \ + tmp &= PINCNTL_RSV_MSK; \ + __raw_writel(tmp | value, (CTRL_BASE + offset));\ +} + +/* + * PAD CONTROL OFFSETS + * Field names corresponds to the pad signal name + */ +struct pad_signals { + int pincntl1; + int pincntl2; + int pincntl3; + int pincntl4; + int pincntl5; + int pincntl6; + int pincntl7; + int pincntl8; + int pincntl9; + int pincntl10; + int pincntl11; + int pincntl12; + int pincntl13; + int pincntl14; + int pincntl15; + int pincntl16; + int pincntl17; + int pincntl18; + int pincntl19; + int pincntl20; + int pincntl21; + int pincntl22; + int pincntl23; + int pincntl24; + int pincntl25; + int pincntl26; + int pincntl27; + int pincntl28; + int pincntl29; + int pincntl30; + int pincntl31; + int pincntl32; + int pincntl33; + int pincntl34; + int pincntl35; + int pincntl36; + int pincntl37; + int pincntl38; + int pincntl39; + int pincntl40; + int pincntl41; + int pincntl42; + int pincntl43; + int pincntl44; + int pincntl45; + int pincntl46; + int pincntl47; + int pincntl48; + int pincntl49; + int pincntl50; + int pincntl51; + int pincntl52; + int pincntl53; + int pincntl54; + int pincntl55; + int pincntl56; + int pincntl57; + int pincntl58; + int pincntl59; + int pincntl60; + int pincntl61; + int pincntl62; + int pincntl63; + int pincntl64; + int pincntl65; + int pincntl66; + int pincntl67; + int pincntl68; + int pincntl69; + int pincntl70; + int pincntl71; + int pincntl72; + int pincntl73; + int pincntl74; + int pincntl75; + int pincntl76; + int pincntl77; + int pincntl78; + int pincntl79; + int pincntl80; + int pincntl81; + int pincntl82; + int pincntl83; + int pincntl84; + int pincntl85; + int pincntl86; + int pincntl87; + int pincntl88; + int pincntl89; + int pincntl90; + int pincntl91; + int pincntl92; + int pincntl93; + int pincntl94; + int pincntl95; + int pincntl96; + int pincntl97; + int pincntl98; + int pincntl99; + int pincntl100; + int pincntl101; + int pincntl102; + int pincntl103; + int pincntl104; + int pincntl105; + int pincntl106; + int pincntl107; + int pincntl108; + int pincntl109; + int pincntl110; + int pincntl111; + int pincntl112; + int pincntl113; + int pincntl114; + int pincntl115; + int pincntl116; + int pincntl117; + int pincntl118; + int pincntl119; + int pincntl120; + int pincntl121; + int pincntl122; + int pincntl123; + int pincntl124; + int pincntl125; + int pincntl126; + int pincntl127; + int pincntl128; + int pincntl129; + int pincntl130; + int pincntl131; + int pincntl132; + int pincntl133; + int pincntl134; + int pincntl135; + int pincntl136; + int pincntl137; + int pincntl138; + int pincntl139; + int pincntl140; + int pincntl141; + int pincntl142; + int pincntl143; + int pincntl144; + int pincntl145; + int pincntl146; + int pincntl147; + int pincntl148; + int pincntl149; + int pincntl150; + int pincntl151; + int pincntl152; + int pincntl153; + int pincntl154; + int pincntl155; + int pincntl156; + int pincntl157; + int pincntl158; + int pincntl159; + int pincntl160; + int pincntl161; + int pincntl162; + int pincntl163; + int pincntl164; + int pincntl165; + int pincntl166; + int pincntl167; + int pincntl168; + int pincntl169; + int pincntl170; + int pincntl171; + int pincntl172; + int pincntl173; + int pincntl174; + int pincntl175; + int pincntl176; + int pincntl177; + int pincntl178; + int pincntl179; + int pincntl180; + int pincntl181; + int pincntl182; + int pincntl183; + int pincntl184; + int pincntl185; + int pincntl186; + int pincntl187; + int pincntl188; + int pincntl189; + int pincntl190; + int pincntl191; + int pincntl192; + int pincntl193; + int pincntl194; + int pincntl195; + int pincntl196; + int pincntl197; + int pincntl198; + int pincntl199; + int pincntl200; + int pincntl201; + int pincntl202; + int pincntl203; + int pincntl204; + int pincntl205; + int pincntl206; + int pincntl207; + int pincntl208; + int pincntl209; + int pincntl210; + int pincntl211; + int pincntl212; + int pincntl213; + int pincntl214; + int pincntl215; + int pincntl216; + int pincntl217; + int pincntl218; + int pincntl219; + int pincntl220; + int pincntl221; + int pincntl222; + int pincntl223; + int pincntl224; + int pincntl225; + int pincntl226; + int pincntl227; + int pincntl228; + int pincntl229; + int pincntl230; + int pincntl231; + int pincntl232; + int pincntl233; + int pincntl234; + int pincntl235; + int pincntl236; + int pincntl237; + int pincntl238; + int pincntl239; + int pincntl240; + int pincntl241; + int pincntl242; + int pincntl243; + int pincntl244; + int pincntl245; + int pincntl246; + int pincntl247; + int pincntl248; + int pincntl249; + int pincntl250; + int pincntl251; + int pincntl252; + int pincntl253; + int pincntl254; + int pincntl255; + int pincntl256; + int pincntl257; + int pincntl258; + int pincntl259; + int pincntl260; + int pincntl261; + int pincntl262; + int pincntl263; + int pincntl264; + int pincntl265; + int pincntl266; + int pincntl267; + int pincntl268; + int pincntl269; + int pincntl270; +}; + +#endif /* endif _MUX_TI814X_H_ */ -- cgit v1.2.3 From 8b029f22a6618f9966d2840c5d962646fc0829d6 Mon Sep 17 00:00:00 2001 From: Matt Porter Date: Fri, 15 Mar 2013 10:07:06 +0000 Subject: am33xx: add ti814x specific register definitions Support the ti814x specific register definitions within arch-am33xx. Signed-off-by: Matt Porter Reviewed-by: Tom Rini --- arch/arm/cpu/armv7/am33xx/sys_info.c | 3 +++ arch/arm/include/asm/arch-am33xx/cpu.h | 11 ++++++---- arch/arm/include/asm/arch-am33xx/hardware.h | 21 ++++--------------- arch/arm/include/asm/arch-am33xx/hardware_am33xx.h | 24 ++++++++++++++++++++++ arch/arm/include/asm/arch-am33xx/hardware_ti814x.h | 23 +++++++++++++++++++++ arch/arm/include/asm/arch-am33xx/omap.h | 5 +++++ arch/arm/include/asm/arch-am33xx/spl.h | 5 +++++ 7 files changed, 71 insertions(+), 21 deletions(-) diff --git a/arch/arm/cpu/armv7/am33xx/sys_info.c b/arch/arm/cpu/armv7/am33xx/sys_info.c index db99e9535f..5fd8b47b2d 100644 --- a/arch/arm/cpu/armv7/am33xx/sys_info.c +++ b/arch/arm/cpu/armv7/am33xx/sys_info.c @@ -98,6 +98,9 @@ int print_cpuinfo(void) case AM335X: cpu_s = "AM335X"; break; + case TI81XX: + cpu_s = "TI81XX"; + break; default: cpu_s = "Unknown cpu type"; break; diff --git a/arch/arm/include/asm/arch-am33xx/cpu.h b/arch/arm/include/asm/arch-am33xx/cpu.h index 16e8a80700..3d3a7c8ac2 100644 --- a/arch/arm/include/asm/arch-am33xx/cpu.h +++ b/arch/arm/include/asm/arch-am33xx/cpu.h @@ -42,9 +42,10 @@ #define HS_DEVICE 0x2 #define GP_DEVICE 0x3 -/* cpu-id for AM33XX family */ +/* cpu-id for AM33XX and TI81XX family */ #define AM335X 0xB944 -#define DEVICE_ID 0x44E10600 +#define TI81XX 0xB81E +#define DEVICE_ID (CTRL_BASE + 0x0600) /* This gives the status of the boot mode pins on the evm */ #define SYSBOOT_MASK (BIT(0) | BIT(1) | BIT(2)\ @@ -52,9 +53,11 @@ /* Reset control */ #ifdef CONFIG_AM33XX -#define PRM_RSTCTRL 0x44E00F00 -#define PRM_RSTST 0x44E00F08 +#define PRM_RSTCTRL (PRCM_BASE + 0x0F00) +#elif defined(CONFIG_TI814X) +#define PRM_RSTCTRL (PRCM_BASE + 0x00A0) #endif +#define PRM_RSTST (PRM_RSTCTRL + 8) #define PRM_RSTCTRL_RESET 0x01 #define PRM_RSTST_WARM_RESET_MASK 0x232 diff --git a/arch/arm/include/asm/arch-am33xx/hardware.h b/arch/arm/include/asm/arch-am33xx/hardware.h index 24a9b8d2d4..5a27f9cf5e 100644 --- a/arch/arm/include/asm/arch-am33xx/hardware.h +++ b/arch/arm/include/asm/arch-am33xx/hardware.h @@ -19,6 +19,7 @@ #ifndef __AM33XX_HARDWARE_H #define __AM33XX_HARDWARE_H +#include #include #ifdef CONFIG_AM33XX #include @@ -26,8 +27,9 @@ #include #endif -/* Module base addresses */ -#define UART0_BASE 0x44E09000 +/* + * Common hardware definitions + */ /* DM Timer base addresses */ #define DM_TIMER0_BASE 0x4802C000 @@ -42,21 +44,10 @@ /* GPIO Base address */ #define GPIO0_BASE 0x48032000 #define GPIO1_BASE 0x4804C000 -#define GPIO2_BASE 0x481AC000 /* BCH Error Location Module */ #define ELM_BASE 0x48080000 -/* Watchdog Timer */ -#define WDT_BASE 0x44E35000 - -/* Control Module Base Address */ -#define CTRL_BASE 0x44E10000 -#define CTRL_DEVICE_BASE 0x44E10600 - -/* PRCM Base Address */ -#define PRCM_BASE 0x44E00000 - /* EMIF Base address */ #define EMIF4_0_CFG_BASE 0x4C000000 #define EMIF4_1_CFG_BASE 0x4D000000 @@ -90,10 +81,6 @@ /* CPSW Config space */ #define CPSW_BASE 0x4A100000 -#define CPSW_MDIO_BASE 0x4A101000 - -/* RTC base address */ -#define RTC_BASE 0x44E3E000 /* OTG */ #define USB0_OTG_BASE 0x47401000 diff --git a/arch/arm/include/asm/arch-am33xx/hardware_am33xx.h b/arch/arm/include/asm/arch-am33xx/hardware_am33xx.h index 7a4070c6af..fa02f195ff 100644 --- a/arch/arm/include/asm/arch-am33xx/hardware_am33xx.h +++ b/arch/arm/include/asm/arch-am33xx/hardware_am33xx.h @@ -19,6 +19,24 @@ #ifndef __AM33XX_HARDWARE_AM33XX_H #define __AM33XX_HARDWARE_AM33XX_H +/* Module base addresses */ + +/* UART Base Address */ +#define UART0_BASE 0x44E09000 + +/* GPIO Base address */ +#define GPIO2_BASE 0x481AC000 + +/* Watchdog Timer */ +#define WDT_BASE 0x44E35000 + +/* Control Module Base Address */ +#define CTRL_BASE 0x44E10000 +#define CTRL_DEVICE_BASE 0x44E10600 + +/* PRCM Base Address */ +#define PRCM_BASE 0x44E00000 + /* VTP Base address */ #define VTP0_CTRL_ADDR 0x44E10E0C @@ -27,4 +45,10 @@ #define DDR_PHY_DATA_ADDR 0x44E120C8 #define DDR_DATA_REGS_NR 2 +/* CPSW Config space */ +#define CPSW_MDIO_BASE 0x4A101000 + +/* RTC base address */ +#define RTC_BASE 0x44E3E000 + #endif /* __AM33XX_HARDWARE_AM33XX_H */ diff --git a/arch/arm/include/asm/arch-am33xx/hardware_ti814x.h b/arch/arm/include/asm/arch-am33xx/hardware_ti814x.h index af7d1d82e7..a950ac3c18 100644 --- a/arch/arm/include/asm/arch-am33xx/hardware_ti814x.h +++ b/arch/arm/include/asm/arch-am33xx/hardware_ti814x.h @@ -19,6 +19,23 @@ #ifndef __AM33XX_HARDWARE_TI814X_H #define __AM33XX_HARDWARE_TI814X_H +/* Module base addresses */ + +/* UART Base Address */ +#define UART0_BASE 0x48020000 + +/* Watchdog Timer */ +#define WDT_BASE 0x481C7000 + +/* Control Module Base Address */ +#define CTRL_BASE 0x48140000 + +/* PRCM Base Address */ +#define PRCM_BASE 0x48180000 + +/* PLL Subsystem Base Address */ +#define PLL_SUBSYS_BASE 0x481C5000 + /* VTP Base address */ #define VTP0_CTRL_ADDR 0x48140E0C @@ -27,4 +44,10 @@ #define DDR_PHY_DATA_ADDR 0x47C0C4C8 #define DDR_DATA_REGS_NR 4 +/* CPSW Config space */ +#define CPSW_MDIO_BASE 0x4A100800 + +/* RTC base address */ +#define RTC_BASE 0x480C0000 + #endif /* __AM33XX_HARDWARE_TI814X_H */ diff --git a/arch/arm/include/asm/arch-am33xx/omap.h b/arch/arm/include/asm/arch-am33xx/omap.h index 850f8a551d..d28f9a83ff 100644 --- a/arch/arm/include/asm/arch-am33xx/omap.h +++ b/arch/arm/include/asm/arch-am33xx/omap.h @@ -28,8 +28,13 @@ * Non-secure RAM starts at 0x40300000 for GP devices. But we keep SRAM_BASE * at 0x40304000(EMU base) so that our code works for both EMU and GP */ +#ifdef CONFIG_AM33XX #define NON_SECURE_SRAM_START 0x40304000 #define NON_SECURE_SRAM_END 0x4030E000 +#elif defined(CONFIG_TI814X) +#define NON_SECURE_SRAM_START 0x40300000 +#define NON_SECURE_SRAM_END 0x40320000 +#endif /* ROM code defines */ /* Boot device */ diff --git a/arch/arm/include/asm/arch-am33xx/spl.h b/arch/arm/include/asm/arch-am33xx/spl.h index e961ce0578..f60b086366 100644 --- a/arch/arm/include/asm/arch-am33xx/spl.h +++ b/arch/arm/include/asm/arch-am33xx/spl.h @@ -25,8 +25,13 @@ #define BOOT_DEVICE_XIP 2 #define BOOT_DEVICE_NAND 5 +#ifdef CONFIG_AM33XX #define BOOT_DEVICE_MMC1 8 #define BOOT_DEVICE_MMC2 9 /* eMMC or daughter card */ +#elif defined(CONFIG_TI814X) +#define BOOT_DEVICE_MMC1 9 +#define BOOT_DEVICE_MMC2 8 /* ROM only supports 2nd instance */ +#endif #define BOOT_DEVICE_SPI 11 #define BOOT_DEVICE_UART 65 #define BOOT_DEVICE_USBETH 68 -- cgit v1.2.3 From 4fab8d7bbd5784771594f3d8c38827e7306381c3 Mon Sep 17 00:00:00 2001 From: Matt Porter Date: Fri, 15 Mar 2013 10:07:07 +0000 Subject: am33xx: add dmm support to emif4 library Adds a config_dmm() routine to support TI814X DMM configuration. Signed-off-by: Matt Porter Reviewed-by: Tom Rini --- arch/arm/cpu/armv7/am33xx/emif4.c | 17 +++++++++++++++++ arch/arm/include/asm/arch-am33xx/ddr_defs.h | 5 +++++ 2 files changed, 22 insertions(+) diff --git a/arch/arm/cpu/armv7/am33xx/emif4.c b/arch/arm/cpu/armv7/am33xx/emif4.c index 76459d81f9..aa84e96173 100644 --- a/arch/arm/cpu/armv7/am33xx/emif4.c +++ b/arch/arm/cpu/armv7/am33xx/emif4.c @@ -44,6 +44,8 @@ void dram_init_banksize(void) #ifdef CONFIG_SPL_BUILD +static struct dmm_lisa_map_regs *hw_lisa_map_regs = + (struct dmm_lisa_map_regs *)DMM_BASE; static struct vtp_reg *vtpreg[2] = { (struct vtp_reg *)VTP0_CTRL_ADDR, (struct vtp_reg *)VTP1_CTRL_ADDR}; @@ -51,6 +53,21 @@ static struct vtp_reg *vtpreg[2] = { static struct ddr_ctrl *ddrctrl = (struct ddr_ctrl *)DDR_CTRL_ADDR; #endif +void config_dmm(const struct dmm_lisa_map_regs *regs) +{ + enable_dmm_clocks(); + + writel(0, &hw_lisa_map_regs->dmm_lisa_map_3); + writel(0, &hw_lisa_map_regs->dmm_lisa_map_2); + writel(0, &hw_lisa_map_regs->dmm_lisa_map_1); + writel(0, &hw_lisa_map_regs->dmm_lisa_map_0); + + writel(regs->dmm_lisa_map_3, &hw_lisa_map_regs->dmm_lisa_map_3); + writel(regs->dmm_lisa_map_2, &hw_lisa_map_regs->dmm_lisa_map_2); + writel(regs->dmm_lisa_map_1, &hw_lisa_map_regs->dmm_lisa_map_1); + writel(regs->dmm_lisa_map_0, &hw_lisa_map_regs->dmm_lisa_map_0); +} + static void config_vtp(int nr) { writel(readl(&vtpreg[nr]->vtp0ctrlreg) | VTP_CTRL_ENABLE, diff --git a/arch/arm/include/asm/arch-am33xx/ddr_defs.h b/arch/arm/include/asm/arch-am33xx/ddr_defs.h index 55c61e6598..72156af5c5 100644 --- a/arch/arm/include/asm/arch-am33xx/ddr_defs.h +++ b/arch/arm/include/asm/arch-am33xx/ddr_defs.h @@ -100,6 +100,11 @@ #define MT41J512M8RH125_PHY_WR_DATA 0x74 #define MT41J512M8RH125_IOCTRL_VALUE 0x18B +/** + * Configure DMM + */ +void config_dmm(const struct dmm_lisa_map_regs *regs); + /** * Configure SDRAM */ -- cgit v1.2.3 From 26fa57842b2a0387e9e8a1da9cdee77bb467e3ee Mon Sep 17 00:00:00 2001 From: Matt Porter Date: Fri, 15 Mar 2013 10:07:08 +0000 Subject: am33xx: support ti814x mmc reference clock TI814x has a 192MHz hsmmc reference clock. Select that clock rate when building for TI814x. Signed-off-by: Matt Porter --- arch/arm/include/asm/arch-am33xx/mmc_host_def.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm/include/asm/arch-am33xx/mmc_host_def.h b/arch/arm/include/asm/arch-am33xx/mmc_host_def.h index 33c9c83892..51ba79190a 100644 --- a/arch/arm/include/asm/arch-am33xx/mmc_host_def.h +++ b/arch/arm/include/asm/arch-am33xx/mmc_host_def.h @@ -24,4 +24,9 @@ #define OMAP_HSMMC1_BASE 0x48060100 #define OMAP_HSMMC2_BASE 0x481D8100 +#if defined(CONFIG_TI814X) +#undef MMC_CLOCK_REFERENCE +#define MMC_CLOCK_REFERENCE 192 /* MHz */ +#endif + #endif /* MMC_HOST_DEF_H */ -- cgit v1.2.3 From 6213a68fe8da8be772e12def2302eb2bef85e1c9 Mon Sep 17 00:00:00 2001 From: Matt Porter Date: Fri, 15 Mar 2013 10:07:09 +0000 Subject: ns16550: enable quirks for ti814x TI814X requires the same quirks as AM33XX to be enabled. Signed-off-by: Matt Porter Reviewed-by: Tom Rini --- drivers/serial/ns16550.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index b2da8b318e..ed4e6b3a1f 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -43,7 +43,7 @@ void NS16550_init(NS16550_t com_port, int baud_divisor) serial_out(CONFIG_SYS_NS16550_IER, &com_port->ier); #if (defined(CONFIG_OMAP) && !defined(CONFIG_OMAP3_ZOOM2)) || \ - defined(CONFIG_AM33XX) + defined(CONFIG_AM33XX) || defined(CONFIG_TI814X) serial_out(0x7, &com_port->mdr1); /* mode select reset TL16C750*/ #endif serial_out(UART_LCR_BKSE | UART_LCRVAL, &com_port->lcr); @@ -57,7 +57,8 @@ void NS16550_init(NS16550_t com_port, int baud_divisor) serial_out((baud_divisor >> 8) & 0xff, &com_port->dlm); serial_out(UART_LCRVAL, &com_port->lcr); #if (defined(CONFIG_OMAP) && !defined(CONFIG_OMAP3_ZOOM2)) || \ - defined(CONFIG_AM33XX) || defined(CONFIG_SOC_DA8XX) + defined(CONFIG_AM33XX) || defined(CONFIG_SOC_DA8XX) || \ + defined(CONFIG_TI814X) #if defined(CONFIG_APTIX) /* /13 mode so Aptix 6MHz can hit 115200 */ -- cgit v1.2.3 From ea7b96b6aa06fea40547333e8796f8ea9a856d67 Mon Sep 17 00:00:00 2001 From: Matt Porter Date: Fri, 15 Mar 2013 10:07:10 +0000 Subject: ti814x_evm: add ti814x evm board support Add TI814X EVM board directory, config file, and MAINTAINERS entry. Enable build. Signed-off-by: Matt Porter Reviewed-by: Tom Rini [trini: Adapt to recent omap_hsmmc requirements, Matt re-tested] Signed-off-by: Tom Rini --- MAINTAINERS | 4 + Makefile | 2 +- arch/arm/cpu/armv7/Makefile | 2 +- arch/arm/cpu/armv7/omap-common/Makefile | 2 +- board/ti/ti814x/Makefile | 46 +++++++ board/ti/ti814x/evm.c | 198 ++++++++++++++++++++++++++++ board/ti/ti814x/evm.h | 7 + board/ti/ti814x/mux.c | 51 ++++++++ boards.cfg | 1 + include/configs/ti814x_evm.h | 221 ++++++++++++++++++++++++++++++++ spl/Makefile | 2 +- 11 files changed, 532 insertions(+), 4 deletions(-) create mode 100644 board/ti/ti814x/Makefile create mode 100644 board/ti/ti814x/evm.c create mode 100644 board/ti/ti814x/evm.h create mode 100644 board/ti/ti814x/mux.c create mode 100644 include/configs/ti814x_evm.h diff --git a/MAINTAINERS b/MAINTAINERS index d031c3a9df..09430ba4a3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -833,6 +833,10 @@ Stelian Pop at91sam9263ek ARM926EJS (AT91SAM9263 SoC) at91sam9rlek ARM926EJS (AT91SAM9RL SoC) +Matt Porter + + ti814x_evm ARM ARMV7 (TI814x Soc) + Dave Purdy pogo_e02 ARM926EJS (Kirkwood SoC) diff --git a/Makefile b/Makefile index 12763ce0f9..d60a14b587 100644 --- a/Makefile +++ b/Makefile @@ -331,7 +331,7 @@ LIBS-y += api/libapi.o LIBS-y += post/libpost.o LIBS-y += test/libtest.o -ifneq ($(CONFIG_AM33XX)$(CONFIG_OMAP34XX)$(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX),) +ifneq ($(CONFIG_AM33XX)$(CONFIG_OMAP34XX)$(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX)$(CONFIG_TI814X),) LIBS-y += $(CPUDIR)/omap-common/libomap-common.o endif diff --git a/arch/arm/cpu/armv7/Makefile b/arch/arm/cpu/armv7/Makefile index 4668b3cf2f..7a8c2d0e59 100644 --- a/arch/arm/cpu/armv7/Makefile +++ b/arch/arm/cpu/armv7/Makefile @@ -32,7 +32,7 @@ COBJS += cache_v7.o COBJS += cpu.o COBJS += syslib.o -ifneq ($(CONFIG_AM33XX)$(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX)$(CONFIG_TEGRA)$(CONFIG_MX6),) +ifneq ($(CONFIG_AM33XX)$(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX)$(CONFIG_TEGRA)$(CONFIG_MX6)$(CONFIG_TI814X),) SOBJS += lowlevel_init.o endif diff --git a/arch/arm/cpu/armv7/omap-common/Makefile b/arch/arm/cpu/armv7/omap-common/Makefile index 0efc80ddeb..55e82ba369 100644 --- a/arch/arm/cpu/armv7/omap-common/Makefile +++ b/arch/arm/cpu/armv7/omap-common/Makefile @@ -36,7 +36,7 @@ COBJS += emif-common.o COBJS += vc.o endif -ifneq ($(CONFIG_AM33XX)$(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX),) +ifneq ($(CONFIG_AM33XX)$(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX)$(CONFIG_TI814X),) COBJS += boot-common.o SOBJS += lowlevel_init.o endif diff --git a/board/ti/ti814x/Makefile b/board/ti/ti814x/Makefile new file mode 100644 index 0000000000..09d24222f3 --- /dev/null +++ b/board/ti/ti814x/Makefile @@ -0,0 +1,46 @@ +# +# Makefile +# +# Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed "as is" WITHOUT ANY WARRANTY of any +# kind, whether express or implied; without even the implied warranty +# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# + +include $(TOPDIR)/config.mk + +LIB = $(obj)lib$(BOARD).o + +ifdef CONFIG_SPL_BUILD +COBJS := mux.o +endif + +COBJS += evm.o +SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) +SOBJS := $(addprefix $(obj),$(SOBJS)) + +$(LIB): $(obj).depend $(OBJS) $(SOBJS) + $(call cmd_link_o_target, $(OBJS) $(SOBJS)) + +clean: + rm -f $(SOBJS) $(OBJS) + +distclean: clean + rm -f $(LIB) core *.bak $(obj).depend + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/board/ti/ti814x/evm.c b/board/ti/ti814x/evm.c new file mode 100644 index 0000000000..446e36b844 --- /dev/null +++ b/board/ti/ti814x/evm.c @@ -0,0 +1,198 @@ +/* + * evm.c + * + * Board functions for TI814x EVM + * + * Copyright (C) 2011, Texas Instruments, Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "evm.h" + +DECLARE_GLOBAL_DATA_PTR; + +#ifdef CONFIG_SPL_BUILD +static struct wd_timer *wdtimer = (struct wd_timer *)WDT_BASE; +static struct uart_sys *uart_base = (struct uart_sys *)DEFAULT_UART_BASE; +#endif + +/* UART Defines */ +#ifdef CONFIG_SPL_BUILD +#define UART_RESET (0x1 << 1) +#define UART_CLK_RUNNING_MASK 0x1 +#define UART_SMART_IDLE_EN (0x1 << 0x3) + +static void rtc32k_enable(void) +{ + struct rtc_regs *rtc = (struct rtc_regs *)RTC_BASE; + + /* + * Unlock the RTC's registers. For more details please see the + * RTC_SS section of the TRM. In order to unlock we need to + * write these specific values (keys) in this order. + */ + writel(0x83e70b13, &rtc->kick0r); + writel(0x95a4f1e0, &rtc->kick1r); + + /* Enable the RTC 32K OSC by setting bits 3 and 6. */ + writel((1 << 3) | (1 << 6), &rtc->osc); +} + +static void uart_enable(void) +{ + u32 regVal; + + /* UART softreset */ + regVal = readl(&uart_base->uartsyscfg); + regVal |= UART_RESET; + writel(regVal, &uart_base->uartsyscfg); + while ((readl(&uart_base->uartsyssts) & + UART_CLK_RUNNING_MASK) != UART_CLK_RUNNING_MASK) + ; + + /* Disable smart idle */ + regVal = readl(&uart_base->uartsyscfg); + regVal |= UART_SMART_IDLE_EN; + writel(regVal, &uart_base->uartsyscfg); +} + +static void wdt_disable(void) +{ + writel(0xAAAA, &wdtimer->wdtwspr); + while (readl(&wdtimer->wdtwwps) != 0x0) + ; + writel(0x5555, &wdtimer->wdtwspr); + while (readl(&wdtimer->wdtwwps) != 0x0) + ; +} + +static const struct cmd_control evm_ddr2_cctrl_data = { + .cmd0csratio = 0x80, + .cmd0dldiff = 0x04, + .cmd0iclkout = 0x00, + + .cmd1csratio = 0x80, + .cmd1dldiff = 0x04, + .cmd1iclkout = 0x00, + + .cmd2csratio = 0x80, + .cmd2dldiff = 0x04, + .cmd2iclkout = 0x00, +}; + +static const struct emif_regs evm_ddr2_emif0_regs = { + .sdram_config = 0x40801ab2, + .ref_ctrl = 0x10000c30, + .sdram_tim1 = 0x0aaaf552, + .sdram_tim2 = 0x043631d2, + .sdram_tim3 = 0x00000327, + .emif_ddr_phy_ctlr_1 = 0x00000007 +}; + +static const struct emif_regs evm_ddr2_emif1_regs = { + .sdram_config = 0x40801ab2, + .ref_ctrl = 0x10000c30, + .sdram_tim1 = 0x0aaaf552, + .sdram_tim2 = 0x043631d2, + .sdram_tim3 = 0x00000327, + .emif_ddr_phy_ctlr_1 = 0x00000007 +}; + +const struct dmm_lisa_map_regs evm_lisa_map_regs = { + .dmm_lisa_map_0 = 0x00000000, + .dmm_lisa_map_1 = 0x00000000, + .dmm_lisa_map_2 = 0x806c0300, + .dmm_lisa_map_3 = 0x806c0300, +}; + +static const struct ddr_data evm_ddr2_data = { + .datardsratio0 = ((0x35<<10) | (0x35<<0)), + .datawdsratio0 = ((0x20<<10) | (0x20<<0)), + .datawiratio0 = ((0<<10) | (0<<0)), + .datagiratio0 = ((0<<10) | (0<<0)), + .datafwsratio0 = ((0x90<<10) | (0x90<<0)), + .datawrsratio0 = ((0x50<<10) | (0x50<<0)), + .datauserank0delay = 1, + .datadldiff0 = 0x4, +}; +#endif + +/* + * early system init of muxing and clocks. + */ +void s_init(void) +{ +#ifdef CONFIG_SPL_BUILD + /* WDT1 is already running when the bootloader gets control + * Disable it to avoid "random" resets + */ + wdt_disable(); + + /* Setup the PLLs and the clocks for the peripherals */ + pll_init(); + + /* Enable RTC32K clock */ + rtc32k_enable(); + + /* Set UART pins */ + enable_uart0_pin_mux(); + + /* Set MMC pins */ + enable_mmc1_pin_mux(); + + /* Enable UART */ + uart_enable(); + + gd = &gdata; + + preloader_console_init(); + + config_dmm(&evm_lisa_map_regs); + + config_ddr(0, 0, &evm_ddr2_data, &evm_ddr2_cctrl_data, + &evm_ddr2_emif0_regs, 0); + config_ddr(0, 0, &evm_ddr2_data, &evm_ddr2_cctrl_data, + &evm_ddr2_emif1_regs, 1); +#endif +} + +/* + * Basic board specific setup. Pinmux has been handled already. + */ +int board_init(void) +{ + gd->bd->bi_boot_params = PHYS_DRAM_1 + 0x100; + return 0; +} + +#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_GENERIC_MMC) +int board_mmc_init(bd_t *bis) +{ + omap_mmc_init(1, 0, 0, -1, -1); + + return 0; +} +#endif diff --git a/board/ti/ti814x/evm.h b/board/ti/ti814x/evm.h new file mode 100644 index 0000000000..40f8710c89 --- /dev/null +++ b/board/ti/ti814x/evm.h @@ -0,0 +1,7 @@ +#ifndef _EVM_H +#define _EVM_H + +void enable_uart0_pin_mux(void); +void enable_mmc1_pin_mux(void); + +#endif /* _EVM_H */ diff --git a/board/ti/ti814x/mux.c b/board/ti/ti814x/mux.c new file mode 100644 index 0000000000..137acb4523 --- /dev/null +++ b/board/ti/ti814x/mux.c @@ -0,0 +1,51 @@ +/* + * mux.c + * + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include "evm.h" + +static struct module_pin_mux uart0_pin_mux[] = { + {OFFSET(pincntl70), PULLUP_EN | MODE(0x01)}, /* UART0_RXD */ + {OFFSET(pincntl71), PULLUP_EN | MODE(0x01)}, /* UART0_TXD */ + {-1}, +}; + +static struct module_pin_mux mmc1_pin_mux[] = { + {OFFSET(pincntl1), PULLUP_EN | MODE(0x01)}, /* SD1_CLK */ + {OFFSET(pincntl2), PULLUP_EN | MODE(0x01)}, /* SD1_CMD */ + {OFFSET(pincntl3), PULLUP_EN | MODE(0x01)}, /* SD1_DAT[0] */ + {OFFSET(pincntl4), PULLUP_EN | MODE(0x01)}, /* SD1_DAT[1] */ + {OFFSET(pincntl5), PULLUP_EN | MODE(0x01)}, /* SD1_DAT[2] */ + {OFFSET(pincntl6), PULLUP_EN | MODE(0x01)}, /* SD1_DAT[3] */ + {OFFSET(pincntl74), PULLUP_EN | MODE(0x40)}, /* SD1_POW */ + {OFFSET(pincntl75), MODE(0x40)}, /* SD1_SDWP */ + {OFFSET(pincntl80), PULLUP_EN | MODE(0x02)}, /* SD1_SDCD */ + {-1}, +}; + +void enable_uart0_pin_mux(void) +{ + configure_module_pin_mux(uart0_pin_mux); +} + +void enable_mmc1_pin_mux(void) +{ + configure_module_pin_mux(mmc1_pin_mux); +} diff --git a/boards.cfg b/boards.cfg index ee68fdda83..718a5d6f4e 100644 --- a/boards.cfg +++ b/boards.cfg @@ -241,6 +241,7 @@ am335x_evm_uart3 arm armv7 am335x ti am335x_evm_uart4 arm armv7 am335x ti am33xx am335x_evm:SERIAL5,CONS_INDEX=5 am335x_evm_uart5 arm armv7 am335x ti am33xx am335x_evm:SERIAL6,CONS_INDEX=6 am335x_evm_usbspl arm armv7 am335x ti am33xx am335x_evm:SERIAL1,CONS_INDEX=1,SPL_USBETH_SUPPORT +ti814x_evm arm armv7 ti814x ti am33xx pcm051 arm armv7 pcm051 phytec am33xx pcm051 highbank arm armv7 highbank - highbank mx51_efikamx arm armv7 mx51_efikamx genesi mx5 mx51_efikamx:MACH_TYPE=MACH_TYPE_MX51_EFIKAMX,IMX_CONFIG=board/genesi/mx51_efikamx/imximage_mx.cfg diff --git a/include/configs/ti814x_evm.h b/include/configs/ti814x_evm.h new file mode 100644 index 0000000000..16547e3314 --- /dev/null +++ b/include/configs/ti814x_evm.h @@ -0,0 +1,221 @@ +/* + * ti814x_evm.h + * + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __CONFIG_TI814X_EVM_H +#define __CONFIG_TI814X_EVM_H + +#define CONFIG_TI81XX +#define CONFIG_TI814X +#define CONFIG_SYS_NO_FLASH + +#include + +#define CONFIG_DMA_COHERENT +#define CONFIG_DMA_COHERENT_SIZE (1 << 20) + +#define CONFIG_ENV_SIZE (128 << 10) /* 128 KiB */ +#define CONFIG_SYS_MALLOC_LEN (1024 << 10) +#define CONFIG_SYS_LONGHELP /* undef to save memory */ +#define CONFIG_SYS_HUSH_PARSER /* Use HUSH for command parsing */ +#define CONFIG_SYS_PROMPT "U-Boot# " +#define CONFIG_SYS_NO_FLASH +#define CONFIG_MACH_TYPE MACH_TYPE_TI8148EVM + +#define CONFIG_OF_LIBFDT +#define CONFIG_CMDLINE_TAG /* enable passing of ATAGs */ +#define CONFIG_SETUP_MEMORY_TAGS +#define CONFIG_INITRD_TAG /* for ramdisk support */ + +/* commands to include */ +# include + +#define CONFIG_CMD_ASKENV +#define CONFIG_VERSION_VARIABLE + +#define CONFIG_BOOTDELAY 1 /* negative for no autoboot */ +#define CONFIG_ENV_VARS_UBOOT_CONFIG +#define CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG +#define CONFIG_EXTRA_ENV_SETTINGS \ + "loadaddr=0x80200000\0" \ + "fdtaddr=0x80F80000\0" \ + "rdaddr=0x81000000\0" \ + "bootfile=/boot/uImage\0" \ + "fdtfile=\0" \ + "console=ttyO0,115200n8\0" \ + "optargs=\0" \ + "mmcdev=0\0" \ + "mmcroot=/dev/mmcblk0p2 ro\0" \ + "mmcrootfstype=ext4 rootwait\0" \ + "ramroot=/dev/ram0 rw ramdisk_size=65536 initrd=${rdaddr},64M\0" \ + "ramrootfstype=ext2\0" \ + "mmcargs=setenv bootargs console=${console} " \ + "${optargs} " \ + "root=${mmcroot} " \ + "rootfstype=${mmcrootfstype}\0" \ + "bootenv=uEnv.txt\0" \ + "loadbootenv=fatload mmc ${mmcdev} ${loadaddr} ${bootenv}\0" \ + "importbootenv=echo Importing environment from mmc ...; " \ + "env import -t $loadaddr $filesize\0" \ + "ramargs=setenv bootargs console=${console} " \ + "${optargs} " \ + "root=${ramroot} " \ + "rootfstype=${ramrootfstype}\0" \ + "loadramdisk=fatload mmc ${mmcdev} ${rdaddr} ramdisk.gz\0" \ + "loaduimagefat=fatload mmc ${mmcdev} ${loadaddr} ${bootfile}\0" \ + "loaduimage=ext2load mmc ${mmcdev}:2 ${loadaddr} ${bootfile}\0" \ + "mmcboot=echo Booting from mmc ...; " \ + "run mmcargs; " \ + "bootm ${loadaddr}\0" \ + "ramboot=echo Booting from ramdisk ...; " \ + "run ramargs; " \ + "bootm ${loadaddr}\0" \ + "fdtfile=ti814x-evm.dtb\0" \ + +#define CONFIG_BOOTCOMMAND \ + "mmc dev ${mmcdev}; if mmc rescan; then " \ + "echo SD/MMC found on device ${mmcdev};" \ + "if run loadbootenv; then " \ + "echo Loaded environment from ${bootenv};" \ + "run importbootenv;" \ + "fi;" \ + "if test -n $uenvcmd; then " \ + "echo Running uenvcmd ...;" \ + "run uenvcmd;" \ + "fi;" \ + "if run loaduimage; then " \ + "run mmcboot;" \ + "fi;" \ + "fi;" \ + +/* Clock Defines */ +#define V_OSCK 24000000 /* Clock output from T2 */ +#define V_SCLK (V_OSCK >> 1) + +#define CONFIG_CMD_ECHO + +/* max number of command args */ +#define CONFIG_SYS_MAXARGS 16 + +/* Console I/O Buffer Size */ +#define CONFIG_SYS_CBSIZE 512 + +/* Print Buffer Size */ +#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE \ + + sizeof(CONFIG_SYS_PROMPT) + 16) + +/* Boot Argument Buffer Size */ +#define CONFIG_SYS_BARGSIZE CONFIG_SYS_CBSIZE + +#define CONFIG_SYS_MEMTEST_START PHYS_DRAM_1 +#define CONFIG_SYS_MEMTEST_END (CONFIG_SYS_MEMTEST_START \ + + PHYS_DRAM_1_SIZE - (8 << 12)) + +#define CONFIG_SYS_LOAD_ADDR 0x81000000 /* Default */ +#define CONFIG_SYS_HZ 1000 /* 1ms clock */ + +#define CONFIG_OMAP_GPIO +#define CONFIG_MMC +#define CONFIG_GENERIC_MMC +#define CONFIG_OMAP_HSMMC +#define CONFIG_CMD_MMC +#define CONFIG_DOS_PARTITION +#define CONFIG_CMD_FAT +#define CONFIG_CMD_EXT2 + +/** + * Physical Memory Map + */ +#define CONFIG_NR_DRAM_BANKS 1 /* 1 banks of DRAM */ +#define PHYS_DRAM_1 0x80000000 /* DRAM Bank #1 */ +#define PHYS_DRAM_1_SIZE 0x20000000 /* 512MB */ +#define CONFIG_MAX_RAM_BANK_SIZE (1024 << 20) /* 1024MB */ + +#define CONFIG_SYS_SDRAM_BASE PHYS_DRAM_1 +#define CONFIG_SYS_INIT_SP_ADDR (NON_SECURE_SRAM_END - \ + GENERATED_GBL_DATA_SIZE) + +/** + * Platform/Board specific defs + */ +#define CONFIG_SYS_TIMERBASE 0x4802E000 +#define CONFIG_SYS_PTV 2 /* Divisor: 2^(PTV+1) => 8 */ +#define CONFIG_SYS_HZ 1000 + +/* NS16550 Configuration */ +#define CONFIG_SYS_NS16550 +#define CONFIG_SYS_NS16550_SERIAL +#define CONFIG_SYS_NS16550_REG_SIZE (-4) +#define CONFIG_SYS_NS16550_CLK (48000000) +#define CONFIG_SYS_NS16550_COM1 0x48020000 /* Base EVM has UART0 */ + +#define CONFIG_BAUDRATE 115200 + +#define CONFIG_ENV_OVERWRITE +#define CONFIG_CONS_INDEX 1 +#define CONFIG_SYS_CONSOLE_INFO_QUIET + +#define CONFIG_ENV_IS_NOWHERE + +/* Defines for SPL */ +#define CONFIG_SPL +#define CONFIG_SPL_FRAMEWORK +#define CONFIG_SPL_TEXT_BASE 0x40300000 +#define CONFIG_SPL_MAX_SIZE ((128 - 18) * 1024) +#define CONFIG_SPL_STACK CONFIG_SYS_INIT_SP_ADDR + +#define CONFIG_SPL_BSS_START_ADDR 0x80000000 +#define CONFIG_SPL_BSS_MAX_SIZE 0x80000 /* 512 KB */ + +#define CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR 0x300 /* address 0x60000 */ +#define CONFIG_SYS_U_BOOT_MAX_SIZE_SECTORS 0x200 /* 256 KB */ +#define CONFIG_SYS_MMC_SD_FAT_BOOT_PARTITION 1 +#define CONFIG_SPL_FAT_LOAD_PAYLOAD_NAME "u-boot.img" +#define CONFIG_SPL_MMC_SUPPORT +#define CONFIG_SPL_FAT_SUPPORT + +#define CONFIG_SPL_LIBCOMMON_SUPPORT +#define CONFIG_SPL_LIBDISK_SUPPORT +#define CONFIG_SPL_LIBGENERIC_SUPPORT +#define CONFIG_SPL_SERIAL_SUPPORT +#define CONFIG_SPL_GPIO_SUPPORT +#define CONFIG_SPL_YMODEM_SUPPORT +#define CONFIG_SYS_SPI_U_BOOT_OFFS 0x20000 +#define CONFIG_SYS_SPI_U_BOOT_SIZE 0x40000 +#define CONFIG_SPL_LDSCRIPT "$(CPUDIR)/omap-common/u-boot-spl.lds" + +#define CONFIG_SPL_BOARD_INIT + +/* + * 1MB into the SDRAM to allow for SPL's bss at the beginning of SDRAM + * 64 bytes before this address should be set aside for u-boot.img's + * header. That is 0x800FFFC0--0x80800000 should not be used for any + * other needs. + */ +#define CONFIG_SYS_TEXT_BASE 0x80800000 +#define CONFIG_SYS_SPL_MALLOC_START 0x80208000 +#define CONFIG_SYS_SPL_MALLOC_SIZE 0x100000 + +/* + * Since SPL did pll and ddr initialization for us, + * we don't need to do it twice. + */ +#ifndef CONFIG_SPL_BUILD +#define CONFIG_SKIP_LOWLEVEL_INIT +#endif + +/* Unsupported features */ +#undef CONFIG_USE_IRQ + +#endif /* ! __CONFIG_TI814X_EVM_H */ diff --git a/spl/Makefile b/spl/Makefile index 14095c8df7..b5a8de7835 100644 --- a/spl/Makefile +++ b/spl/Makefile @@ -84,7 +84,7 @@ LIBS-$(CONFIG_SPL_ETH_SUPPORT) += drivers/net/phy/libphy.o LIBS-$(CONFIG_SPL_MUSB_NEW_SUPPORT) += drivers/usb/musb-new/libusb_musb-new.o LIBS-$(CONFIG_SPL_USBETH_SUPPORT) += drivers/usb/gadget/libusb_gadget.o -ifneq ($(CONFIG_AM33XX)$(CONFIG_OMAP34XX)$(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX),) +ifneq ($(CONFIG_AM33XX)$(CONFIG_OMAP34XX)$(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX)$(CONFIG_TI814X),) LIBS-y += $(CPUDIR)/omap-common/libomap-common.o endif -- cgit v1.2.3 From c7ba18ad4b52d35b0166eeecbe05a0e1560e00ec Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Thu, 21 Mar 2013 04:30:02 +0000 Subject: am335x_evm: Add better timings for the new BeagleBoard DDR3 part Tested-by: Rao Bodapati Signed-off-by: Tom Rini --- arch/arm/include/asm/arch-am33xx/ddr_defs.h | 17 +++++++++++++ board/ti/am335x/board.c | 39 ++++++++++++++++++++++++++++- 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/arch/arm/include/asm/arch-am33xx/ddr_defs.h b/arch/arm/include/asm/arch-am33xx/ddr_defs.h index 72156af5c5..260cc3484f 100644 --- a/arch/arm/include/asm/arch-am33xx/ddr_defs.h +++ b/arch/arm/include/asm/arch-am33xx/ddr_defs.h @@ -83,6 +83,23 @@ #define MT41J256M8HX15E_PHY_FIFO_WE 0x100 #define MT41J256M8HX15E_IOCTRL_VALUE 0x18B +/* Micron MT41K256M16HA-125E */ +#define MT41K256M16HA125E_EMIF_READ_LATENCY 0x100006 +#define MT41K256M16HA125E_EMIF_TIM1 0x0888A39B +#define MT41K256M16HA125E_EMIF_TIM2 0x26517FDA +#define MT41K256M16HA125E_EMIF_TIM3 0x501F84EF +#define MT41K256M16HA125E_EMIF_SDCFG 0x61C04BB2 +#define MT41K256M16HA125E_EMIF_SDREF 0x0000093B +#define MT41K256M16HA125E_ZQ_CFG 0x50074BE4 +#define MT41K256M16HA125E_DLL_LOCK_DIFF 0x1 +#define MT41K256M16HA125E_RATIO 0x40 +#define MT41K256M16HA125E_INVERT_CLKOUT 0x0 +#define MT41K256M16HA125E_RD_DQS 0x3C +#define MT41K256M16HA125E_WR_DQS 0x45 +#define MT41K256M16HA125E_PHY_WR_DATA 0x7F +#define MT41K256M16HA125E_PHY_FIFO_WE 0x9B +#define MT41K256M16HA125E_IOCTRL_VALUE 0x18B + /* Micron MT41J512M8RH-125 on EVM v1.5 */ #define MT41J512M8RH125_EMIF_READ_LATENCY 0x06 #define MT41J512M8RH125_EMIF_TIM1 0x0888A39B diff --git a/board/ti/am335x/board.c b/board/ti/am335x/board.c index d61d650ea3..12620bb69c 100644 --- a/board/ti/am335x/board.c +++ b/board/ti/am335x/board.c @@ -208,6 +208,14 @@ static const struct ddr_data ddr3_data = { .datadldiff0 = PHY_DLL_LOCK_DIFF, }; +static const struct ddr_data ddr3_beagleblack_data = { + .datardsratio0 = MT41K256M16HA125E_RD_DQS, + .datawdsratio0 = MT41K256M16HA125E_WR_DQS, + .datafwsratio0 = MT41K256M16HA125E_PHY_FIFO_WE, + .datawrsratio0 = MT41K256M16HA125E_PHY_WR_DATA, + .datadldiff0 = PHY_DLL_LOCK_DIFF, +}; + static const struct ddr_data ddr3_evm_data = { .datardsratio0 = MT41J512M8RH125_RD_DQS, .datawdsratio0 = MT41J512M8RH125_WR_DQS, @@ -230,6 +238,20 @@ static const struct cmd_control ddr3_cmd_ctrl_data = { .cmd2iclkout = MT41J128MJT125_INVERT_CLKOUT, }; +static const struct cmd_control ddr3_beagleblack_cmd_ctrl_data = { + .cmd0csratio = MT41K256M16HA125E_RATIO, + .cmd0dldiff = MT41K256M16HA125E_DLL_LOCK_DIFF, + .cmd0iclkout = MT41K256M16HA125E_INVERT_CLKOUT, + + .cmd1csratio = MT41K256M16HA125E_RATIO, + .cmd1dldiff = MT41K256M16HA125E_DLL_LOCK_DIFF, + .cmd1iclkout = MT41K256M16HA125E_INVERT_CLKOUT, + + .cmd2csratio = MT41K256M16HA125E_RATIO, + .cmd2dldiff = MT41K256M16HA125E_DLL_LOCK_DIFF, + .cmd2iclkout = MT41K256M16HA125E_INVERT_CLKOUT, +}; + static const struct cmd_control ddr3_evm_cmd_ctrl_data = { .cmd0csratio = MT41J512M8RH125_RATIO, .cmd0dldiff = MT41J512M8RH125_DLL_LOCK_DIFF, @@ -255,6 +277,16 @@ static struct emif_regs ddr3_emif_reg_data = { PHY_EN_DYN_PWRDN, }; +static struct emif_regs ddr3_beagleblack_emif_reg_data = { + .sdram_config = MT41K256M16HA125E_EMIF_SDCFG, + .ref_ctrl = MT41K256M16HA125E_EMIF_SDREF, + .sdram_tim1 = MT41K256M16HA125E_EMIF_TIM1, + .sdram_tim2 = MT41K256M16HA125E_EMIF_TIM2, + .sdram_tim3 = MT41K256M16HA125E_EMIF_TIM3, + .zq_config = MT41K256M16HA125E_ZQ_CFG, + .emif_ddr_phy_ctlr_1 = MT41K256M16HA125E_EMIF_READ_LATENCY, +}; + static struct emif_regs ddr3_evm_emif_reg_data = { .sdram_config = MT41J512M8RH125_EMIF_SDCFG, .ref_ctrl = MT41J512M8RH125_EMIF_SDREF, @@ -343,9 +375,14 @@ void s_init(void) gpio_direction_output(GPIO_DDR_VTT_EN, 1); } - if (board_is_evm_sk() || board_is_bone_lt()) + if (board_is_evm_sk()) config_ddr(303, MT41J128MJT125_IOCTRL_VALUE, &ddr3_data, &ddr3_cmd_ctrl_data, &ddr3_emif_reg_data, 0); + else if (board_is_bone_lt()) + config_ddr(303, MT41K256M16HA125E_IOCTRL_VALUE, + &ddr3_beagleblack_data, + &ddr3_beagleblack_cmd_ctrl_data, + &ddr3_beagleblack_emif_reg_data, 0); else if (board_is_evm_15_or_later()) config_ddr(303, MT41J512M8RH125_IOCTRL_VALUE, &ddr3_evm_data, &ddr3_evm_cmd_ctrl_data, &ddr3_evm_emif_reg_data, 0); -- cgit v1.2.3 From bd380cf4cf9ae5b970f09784a90132bee80ee5d0 Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Thu, 14 Mar 2013 06:49:04 +0000 Subject: arm: Correct CONFIG_STANDALONE_LOAD_ADDR for AM33XX/OMAP* platforms All of these platforms have memory starting at 0x80000000, so this is the correct CONFIG_STANDALONE_LOAD_ADDR for all of them. Acked-by: Peter Korsgaard Signed-off-by: Tom Rini --- arch/arm/config.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/config.mk b/arch/arm/config.mk index a0c89b7971..e7839beced 100644 --- a/arch/arm/config.mk +++ b/arch/arm/config.mk @@ -24,7 +24,7 @@ CROSS_COMPILE ?= arm-linux- ifndef CONFIG_STANDALONE_LOAD_ADDR -ifeq ($(SOC),omap3) +ifneq ($(CONFIG_AM33XX)$(CONFIG_OMAP34XX)$(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX)$(CONFIG_TI814X),) CONFIG_STANDALONE_LOAD_ADDR = 0x80300000 else CONFIG_STANDALONE_LOAD_ADDR = 0xc100000 -- cgit v1.2.3 From d4e1da4e093d156d30bd08c90ec2e733d50904a2 Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Thu, 21 Mar 2013 04:00:03 +0000 Subject: mmc: mmc_getcd/getwp: use sensible defaults Let mmc_getcd() return true and mmc_getwp() false if mmc driver doesn't provide handlers for them. Signed-off-by: Peter Korsgaard [trini: Add braces around first if test in each case to fix warning] Signed-off-by: Tom Rini --- drivers/mmc/mmc.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 7b5fdd9f66..d732581eb8 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -51,8 +51,12 @@ int mmc_getwp(struct mmc *mmc) wp = board_mmc_getwp(mmc); - if ((wp < 0) && mmc->getwp) - wp = mmc->getwp(mmc); + if (wp < 0) { + if (mmc->getwp) + wp = mmc->getwp(mmc); + else + wp = 0; + } return wp; } @@ -692,8 +696,12 @@ int mmc_getcd(struct mmc *mmc) cd = board_mmc_getcd(mmc); - if ((cd < 0) && mmc->getcd) - cd = mmc->getcd(mmc); + if (cd < 0) { + if (mmc->getcd) + cd = mmc->getcd(mmc); + else + cd = 1; + } return cd; } -- cgit v1.2.3 From 173ddc5b68fa41e55293d1095cafdc21fd11cf65 Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Thu, 21 Mar 2013 04:00:04 +0000 Subject: mmc: omap_hsmmc.c: only register getcd/getwp callbacks if gpio could be used Gets rid of warnings from omap_gpio: ERROR : check_gpio: invalid GPIO -1 (and undefined behaviour as the -1 error code is interpreted as gpio value) Signed-off-by: Peter Korsgaard --- drivers/mmc/omap_hsmmc.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c index 67cfcc24dc..166744c320 100644 --- a/drivers/mmc/omap_hsmmc.c +++ b/drivers/mmc/omap_hsmmc.c @@ -593,8 +593,6 @@ int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio, mmc->send_cmd = mmc_send_cmd; mmc->set_ios = mmc_set_ios; mmc->init = mmc_init_setup; - mmc->getcd = omap_mmc_getcd; - mmc->getwp = omap_mmc_getwp; mmc->priv = priv_data; switch (dev_index) { @@ -616,7 +614,13 @@ int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio, return 1; } priv_data->cd_gpio = omap_mmc_setup_gpio_in(cd_gpio, "mmc_cd"); + if (priv_data->cd_gpio != -1) + mmc->getcd = omap_mmc_getcd; + priv_data->wp_gpio = omap_mmc_setup_gpio_in(wp_gpio, "mmc_wp"); + if (priv_data->wp_gpio != -1) + mmc->getwp = omap_mmc_getwp; + mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; mmc->host_caps = (MMC_MODE_4BIT | MMC_MODE_HS_52MHz | MMC_MODE_HS | MMC_MODE_HC) & ~host_caps_mask; -- cgit v1.2.3 From 9000652da0893af8a07f81622b3ef8de6c8725bb Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Sat, 16 Mar 2013 18:58:02 +0000 Subject: tegra: remove support for UART SPI switch This feature was only used for tegra20 seaboard that had a pinmux conflict on the SPI pins. These boards were never manufactured, so remove this support to clean up SPI driver. Signed-off-by: Allen Martin Signed-off-by: Tom Warren Reviewed-by: Stephen Warren --- arch/arm/include/asm/arch-tegra/board.h | 3 +- .../arm/include/asm/arch-tegra20/uart-spi-switch.h | 46 -------- board/nvidia/common/board.c | 3 - board/nvidia/common/common.mk | 1 - board/nvidia/common/uart-spi-switch.c | 125 --------------------- board/nvidia/seaboard/seaboard.c | 2 +- drivers/spi/tegra_spi.c | 25 +---- 7 files changed, 3 insertions(+), 202 deletions(-) delete mode 100644 arch/arm/include/asm/arch-tegra20/uart-spi-switch.h delete mode 100644 board/nvidia/common/uart-spi-switch.c diff --git a/arch/arm/include/asm/arch-tegra/board.h b/arch/arm/include/asm/arch-tegra/board.h index 3db0d93b89..1a6699096b 100644 --- a/arch/arm/include/asm/arch-tegra/board.h +++ b/arch/arm/include/asm/arch-tegra/board.h @@ -25,8 +25,7 @@ #define _TEGRA_BOARD_H_ /* Set up pinmux to make UART usable */ -void gpio_config_uart(void); /* CONFIG_SPI_UART_SWITCH */ -void gpio_early_init_uart(void); /*!CONFIG_SPI_UART_SWITCH */ +void gpio_early_init_uart(void); /* Set up early UART output */ void board_init_uart_f(void); diff --git a/arch/arm/include/asm/arch-tegra20/uart-spi-switch.h b/arch/arm/include/asm/arch-tegra20/uart-spi-switch.h deleted file mode 100644 index 82ac180acd..0000000000 --- a/arch/arm/include/asm/arch-tegra20/uart-spi-switch.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2011 The Chromium OS Authors. - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#ifndef _UART_SPI_SWITCH_H -#define _UART_SPI_SWITCH_H - -#if defined(CONFIG_SPI_UART_SWITCH) -/* - * Signal that we are about to use the UART. This unfortunate hack is - * required by Seaboard, which cannot use its console and SPI at the same - * time! If the board file provides this, the board config will declare it. - * Let this be a lesson for others. - */ -void pinmux_select_uart(void); - -/* - * Signal that we are about the use the SPI bus. - */ -void pinmux_select_spi(void); - -#else /* not CONFIG_SPI_UART_SWITCH */ - -static inline void pinmux_select_uart(void) {} -static inline void pinmux_select_spi(void) {} - -#endif - -#endif diff --git a/board/nvidia/common/board.c b/board/nvidia/common/board.c index 7d9f361a8a..b6e6566685 100644 --- a/board/nvidia/common/board.c +++ b/board/nvidia/common/board.c @@ -132,9 +132,6 @@ int board_init(void) clock_init(); clock_verify(); -#ifdef CONFIG_SPI_UART_SWITCH - gpio_config_uart(); -#endif #if defined(CONFIG_TEGRA_SPI) || defined(CONFIG_TEGRA_SLINK) pin_mux_spi(); spi_init(); diff --git a/board/nvidia/common/common.mk b/board/nvidia/common/common.mk index bd6202c299..d9bcb85401 100644 --- a/board/nvidia/common/common.mk +++ b/board/nvidia/common/common.mk @@ -1,4 +1,3 @@ # common options for all tegra boards COBJS-y += ../../nvidia/common/board.o -COBJS-$(CONFIG_SPI_UART_SWITCH) += ../../nvidia/common/uart-spi-switch.o COBJS-$(CONFIG_TEGRA_CLOCK_SCALING) += ../../nvidia/common/emc.o diff --git a/board/nvidia/common/uart-spi-switch.c b/board/nvidia/common/uart-spi-switch.c deleted file mode 100644 index e9d445d9e2..0000000000 --- a/board/nvidia/common/uart-spi-switch.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2011 The Chromium OS Authors. - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include - -/* position of the UART/SPI select switch */ -enum spi_uart_switch { - SWITCH_UNKNOWN, - SWITCH_SPI, - SWITCH_UART, - SWITCH_BOTH -}; - -/* Information about the spi/uart switch */ -struct spi_uart { - int gpio; /* GPIO to control switch */ - u32 port; /* Port number of UART affected */ -}; - -static struct spi_uart local; -static enum spi_uart_switch switch_pos; /* Current switch position */ - - -static void get_config(struct spi_uart *config) -{ -#if defined CONFIG_SPI_CORRUPTS_UART - config->gpio = CONFIG_UART_DISABLE_GPIO; - config->port = CONFIG_SPI_CORRUPTS_UART_NR; -#else - config->gpio = -1; -#endif -} - -/* - * Init the UART / SPI switch. This can be called before relocation so we must - * not access BSS. - */ -void gpio_early_init_uart(void) -{ - struct spi_uart config; - - get_config(&config); - if (config.gpio != -1) { - /* Cannot provide a label prior to relocation */ - gpio_request(config.gpio, NULL); - gpio_direction_output(config.gpio, 0); - } -} - -/* - * Configure the UART / SPI switch. - */ -void gpio_config_uart(void) -{ - get_config(&local); - if (local.gpio != -1) { - gpio_direction_output(local.gpio, 0); - switch_pos = SWITCH_UART; - } else { - /* - * If we're here we don't have a SPI switch; go ahead and - * enable the SPI now. We didn't in spi_init() so we wouldn't - * kill the UART. - */ - pinmux_set_func(PINGRP_GMC, PMUX_FUNC_SFLASH); - switch_pos = SWITCH_BOTH; - } -} - -static void spi_uart_switch(struct spi_uart *config, - enum spi_uart_switch new_pos) -{ - if (switch_pos == SWITCH_BOTH || new_pos == switch_pos) - return; - - /* pre-delay, allow SPI/UART to settle, FIFO to empty, etc. */ - udelay(CONFIG_SPI_CORRUPTS_UART_DLY); - - /* We need to dynamically change the pinmux, shared w/UART RXD/CTS */ - pinmux_set_func(PINGRP_GMC, new_pos == SWITCH_SPI ? - PMUX_FUNC_SFLASH : PMUX_FUNC_UARTD); - - /* - * On Seaboard, MOSI/MISO are shared w/UART. - * Use GPIO I3 (UART_DISABLE) to tristate UART during SPI activity. - * Enable UART later (cs_deactivate) so we can use it for U-Boot comms. - */ - gpio_direction_output(config->gpio, new_pos == SWITCH_SPI); - switch_pos = new_pos; -} - -void pinmux_select_uart(void) -{ - spi_uart_switch(&local, SWITCH_UART); -} - -void pinmux_select_spi(void) -{ - spi_uart_switch(&local, SWITCH_SPI); -} diff --git a/board/nvidia/seaboard/seaboard.c b/board/nvidia/seaboard/seaboard.c index e581fddf43..498e5137a3 100644 --- a/board/nvidia/seaboard/seaboard.c +++ b/board/nvidia/seaboard/seaboard.c @@ -31,7 +31,7 @@ #include /* TODO: Remove this code when the SPI switch is working */ -#if !defined(CONFIG_SPI_UART_SWITCH) && (CONFIG_MACH_TYPE != MACH_TYPE_VENTANA) +#if (CONFIG_MACH_TYPE != MACH_TYPE_VENTANA) void gpio_early_init_uart(void) { /* Enable UART via GPIO_PI3 (port 8, bit 3) so serial console works */ diff --git a/drivers/spi/tegra_spi.c b/drivers/spi/tegra_spi.c index ce19095af0..2662923ff1 100644 --- a/drivers/spi/tegra_spi.c +++ b/drivers/spi/tegra_spi.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -36,12 +35,6 @@ DECLARE_GLOBAL_DATA_PTR; -#if defined(CONFIG_SPI_CORRUPTS_UART) - #define corrupt_delay() udelay(CONFIG_SPI_CORRUPTS_UART_DLY); -#else - #define corrupt_delay() -#endif - struct tegra_spi_slave { struct spi_slave slave; struct spi_tegra *regs; @@ -175,16 +168,8 @@ int spi_claim_bus(struct spi_slave *slave) */ pinmux_set_func(PINGRP_GMD, PMUX_FUNC_SFLASH); pinmux_tristate_disable(PINGRP_LSPI); + pinmux_set_func(PINGRP_GMC, PMUX_FUNC_SFLASH); -#ifndef CONFIG_SPI_UART_SWITCH - /* - * NOTE: - * Only set PinMux bits 3:2 to SPI here on boards that don't have the - * SPI UART switch or subsequent UART data won't go out! See - * spi_uart_switch(). - */ - /* TODO: pinmux_set_func(PINGRP_GMC, PMUX_FUNC_SFLASH); */ -#endif return 0; } @@ -202,24 +187,16 @@ void spi_cs_activate(struct spi_slave *slave) { struct tegra_spi_slave *spi = to_tegra_spi(slave); - pinmux_select_spi(); - /* CS is negated on Tegra, so drive a 1 to get a 0 */ setbits_le32(&spi->regs->command, SPI_CMD_CS_VAL); - - corrupt_delay(); /* Let UART settle */ } void spi_cs_deactivate(struct spi_slave *slave) { struct tegra_spi_slave *spi = to_tegra_spi(slave); - pinmux_select_uart(); - /* CS is negated on Tegra, so drive a 0 to get a 1 */ clrbits_le32(&spi->regs->command, SPI_CMD_CS_VAL); - - corrupt_delay(); /* Let SPI settle */ } int spi_xfer(struct spi_slave *slave, unsigned int bitlen, -- cgit v1.2.3 From ff1da6fb5fe50ac15dd988e81a782a4599102424 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Sat, 16 Mar 2013 18:58:03 +0000 Subject: tegra: spi: rename tegra SPI drivers Rename tegra SPI drivers to tegra20_flash and tegra20_slink in preparation for commonization and addition of tegra114_spi. Signed-off-by: Allen Martin Signed-off-by: Tom Warren Reviewed-by: Stephen Warren --- arch/arm/include/asm/arch-tegra/tegra_slink.h | 84 ----- arch/arm/include/asm/arch-tegra/tegra_spi.h | 75 ----- arch/arm/include/asm/arch-tegra20/tegra20_sflash.h | 75 +++++ arch/arm/include/asm/arch-tegra20/tegra20_slink.h | 84 +++++ board/nvidia/common/board.c | 2 +- drivers/spi/Makefile | 4 +- drivers/spi/tegra20_sflash.c | 307 ++++++++++++++++++ drivers/spi/tegra20_slink.c | 343 +++++++++++++++++++++ drivers/spi/tegra_slink.c | 343 --------------------- drivers/spi/tegra_spi.c | 307 ------------------ include/configs/cardhu.h | 2 +- include/configs/trimslice.h | 2 +- 12 files changed, 814 insertions(+), 814 deletions(-) delete mode 100644 arch/arm/include/asm/arch-tegra/tegra_slink.h delete mode 100644 arch/arm/include/asm/arch-tegra/tegra_spi.h create mode 100644 arch/arm/include/asm/arch-tegra20/tegra20_sflash.h create mode 100644 arch/arm/include/asm/arch-tegra20/tegra20_slink.h create mode 100644 drivers/spi/tegra20_sflash.c create mode 100644 drivers/spi/tegra20_slink.c delete mode 100644 drivers/spi/tegra_slink.c delete mode 100644 drivers/spi/tegra_spi.c diff --git a/arch/arm/include/asm/arch-tegra/tegra_slink.h b/arch/arm/include/asm/arch-tegra/tegra_slink.h deleted file mode 100644 index 74804b5465..0000000000 --- a/arch/arm/include/asm/arch-tegra/tegra_slink.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * NVIDIA Tegra SPI-SLINK controller - * - * Copyright 2010-2013 NVIDIA Corporation - * - * This software may be used and distributed according to the - * terms of the GNU Public License, Version 2, incorporated - * herein by reference. - * - * 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 program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#ifndef _TEGRA_SLINK_H_ -#define _TEGRA_SLINK_H_ - -#include - -struct slink_tegra { - u32 command; /* SLINK_COMMAND_0 register */ - u32 command2; /* SLINK_COMMAND2_0 reg */ - u32 status; /* SLINK_STATUS_0 register */ - u32 reserved; /* Reserved offset 0C */ - u32 mas_data; /* SLINK_MAS_DATA_0 reg */ - u32 slav_data; /* SLINK_SLAVE_DATA_0 reg */ - u32 dma_ctl; /* SLINK_DMA_CTL_0 register */ - u32 status2; /* SLINK_STATUS2_0 reg */ - u32 rsvd[56]; /* 0x20 to 0xFF reserved */ - u32 tx_fifo; /* SLINK_TX_FIFO_0 reg off 100h */ - u32 rsvd2[31]; /* 0x104 to 0x17F reserved */ - u32 rx_fifo; /* SLINK_RX_FIFO_0 reg off 180h */ -}; - -/* COMMAND */ -#define SLINK_CMD_ENB (1 << 31) -#define SLINK_CMD_GO (1 << 30) -#define SLINK_CMD_M_S (1 << 28) -#define SLINK_CMD_CK_SDA (1 << 21) -#define SLINK_CMD_CS_POL (1 << 13) -#define SLINK_CMD_CS_VAL (1 << 12) -#define SLINK_CMD_CS_SOFT (1 << 11) -#define SLINK_CMD_BIT_LENGTH (1 << 4) -#define SLINK_CMD_BIT_LENGTH_MASK 0x0000001F -/* COMMAND2 */ -#define SLINK_CMD2_TXEN (1 << 30) -#define SLINK_CMD2_RXEN (1 << 31) -#define SLINK_CMD2_SS_EN (1 << 18) -#define SLINK_CMD2_SS_EN_SHIFT 18 -#define SLINK_CMD2_SS_EN_MASK 0x000C0000 -#define SLINK_CMD2_CS_ACTIVE_BETWEEN (1 << 17) -/* STATUS */ -#define SLINK_STAT_BSY (1 << 31) -#define SLINK_STAT_RDY (1 << 30) -#define SLINK_STAT_ERR (1 << 29) -#define SLINK_STAT_RXF_FLUSH (1 << 27) -#define SLINK_STAT_TXF_FLUSH (1 << 26) -#define SLINK_STAT_RXF_OVF (1 << 25) -#define SLINK_STAT_TXF_UNR (1 << 24) -#define SLINK_STAT_RXF_EMPTY (1 << 23) -#define SLINK_STAT_RXF_FULL (1 << 22) -#define SLINK_STAT_TXF_EMPTY (1 << 21) -#define SLINK_STAT_TXF_FULL (1 << 20) -#define SLINK_STAT_TXF_OVF (1 << 19) -#define SLINK_STAT_RXF_UNR (1 << 18) -#define SLINK_STAT_CUR_BLKCNT (1 << 15) -/* STATUS2 */ -#define SLINK_STAT2_RXF_FULL_CNT (1 << 16) -#define SLINK_STAT2_TXF_FULL_CNT (1 << 0) - -#define SPI_TIMEOUT 1000 -#define TEGRA_SPI_MAX_FREQ 52000000 - -#endif /* _TEGRA_SLINK_H_ */ diff --git a/arch/arm/include/asm/arch-tegra/tegra_spi.h b/arch/arm/include/asm/arch-tegra/tegra_spi.h deleted file mode 100644 index d53a93ff53..0000000000 --- a/arch/arm/include/asm/arch-tegra/tegra_spi.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * NVIDIA Tegra20 SPI-FLASH controller - * - * Copyright 2010-2012 NVIDIA Corporation - * - * This software may be used and distributed according to the - * terms of the GNU Public License, Version 2, incorporated - * herein by reference. - * - * 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 program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#ifndef _TEGRA_SPI_H_ -#define _TEGRA_SPI_H_ - -#include - -struct spi_tegra { - u32 command; /* SPI_COMMAND_0 register */ - u32 status; /* SPI_STATUS_0 register */ - u32 rx_cmp; /* SPI_RX_CMP_0 register */ - u32 dma_ctl; /* SPI_DMA_CTL_0 register */ - u32 tx_fifo; /* SPI_TX_FIFO_0 register */ - u32 rsvd[3]; /* offsets 0x14 to 0x1F reserved */ - u32 rx_fifo; /* SPI_RX_FIFO_0 register */ -}; - -#define SPI_CMD_GO (1 << 30) -#define SPI_CMD_ACTIVE_SCLK_SHIFT 26 -#define SPI_CMD_ACTIVE_SCLK_MASK (3 << SPI_CMD_ACTIVE_SCLK_SHIFT) -#define SPI_CMD_CK_SDA (1 << 21) -#define SPI_CMD_ACTIVE_SDA_SHIFT 18 -#define SPI_CMD_ACTIVE_SDA_MASK (3 << SPI_CMD_ACTIVE_SDA_SHIFT) -#define SPI_CMD_CS_POL (1 << 16) -#define SPI_CMD_TXEN (1 << 15) -#define SPI_CMD_RXEN (1 << 14) -#define SPI_CMD_CS_VAL (1 << 13) -#define SPI_CMD_CS_SOFT (1 << 12) -#define SPI_CMD_CS_DELAY (1 << 9) -#define SPI_CMD_CS3_EN (1 << 8) -#define SPI_CMD_CS2_EN (1 << 7) -#define SPI_CMD_CS1_EN (1 << 6) -#define SPI_CMD_CS0_EN (1 << 5) -#define SPI_CMD_BIT_LENGTH (1 << 4) -#define SPI_CMD_BIT_LENGTH_MASK 0x0000001F - -#define SPI_STAT_BSY (1 << 31) -#define SPI_STAT_RDY (1 << 30) -#define SPI_STAT_RXF_FLUSH (1 << 29) -#define SPI_STAT_TXF_FLUSH (1 << 28) -#define SPI_STAT_RXF_UNR (1 << 27) -#define SPI_STAT_TXF_OVF (1 << 26) -#define SPI_STAT_RXF_EMPTY (1 << 25) -#define SPI_STAT_RXF_FULL (1 << 24) -#define SPI_STAT_TXF_EMPTY (1 << 23) -#define SPI_STAT_TXF_FULL (1 << 22) -#define SPI_STAT_SEL_TXRX_N (1 << 16) -#define SPI_STAT_CUR_BLKCNT (1 << 15) - -#define SPI_TIMEOUT 1000 -#define TEGRA_SPI_MAX_FREQ 52000000 - -#endif /* _TEGRA_SPI_H_ */ diff --git a/arch/arm/include/asm/arch-tegra20/tegra20_sflash.h b/arch/arm/include/asm/arch-tegra20/tegra20_sflash.h new file mode 100644 index 0000000000..26a8402512 --- /dev/null +++ b/arch/arm/include/asm/arch-tegra20/tegra20_sflash.h @@ -0,0 +1,75 @@ +/* + * NVIDIA Tegra20 SPI-FLASH controller + * + * Copyright 2010-2012 NVIDIA Corporation + * + * This software may be used and distributed according to the + * terms of the GNU Public License, Version 2, incorporated + * herein by reference. + * + * 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _TEGRA20_SPI_H_ +#define _TEGRA20_SPI_H_ + +#include + +struct spi_tegra { + u32 command; /* SPI_COMMAND_0 register */ + u32 status; /* SPI_STATUS_0 register */ + u32 rx_cmp; /* SPI_RX_CMP_0 register */ + u32 dma_ctl; /* SPI_DMA_CTL_0 register */ + u32 tx_fifo; /* SPI_TX_FIFO_0 register */ + u32 rsvd[3]; /* offsets 0x14 to 0x1F reserved */ + u32 rx_fifo; /* SPI_RX_FIFO_0 register */ +}; + +#define SPI_CMD_GO (1 << 30) +#define SPI_CMD_ACTIVE_SCLK_SHIFT 26 +#define SPI_CMD_ACTIVE_SCLK_MASK (3 << SPI_CMD_ACTIVE_SCLK_SHIFT) +#define SPI_CMD_CK_SDA (1 << 21) +#define SPI_CMD_ACTIVE_SDA_SHIFT 18 +#define SPI_CMD_ACTIVE_SDA_MASK (3 << SPI_CMD_ACTIVE_SDA_SHIFT) +#define SPI_CMD_CS_POL (1 << 16) +#define SPI_CMD_TXEN (1 << 15) +#define SPI_CMD_RXEN (1 << 14) +#define SPI_CMD_CS_VAL (1 << 13) +#define SPI_CMD_CS_SOFT (1 << 12) +#define SPI_CMD_CS_DELAY (1 << 9) +#define SPI_CMD_CS3_EN (1 << 8) +#define SPI_CMD_CS2_EN (1 << 7) +#define SPI_CMD_CS1_EN (1 << 6) +#define SPI_CMD_CS0_EN (1 << 5) +#define SPI_CMD_BIT_LENGTH (1 << 4) +#define SPI_CMD_BIT_LENGTH_MASK 0x0000001F + +#define SPI_STAT_BSY (1 << 31) +#define SPI_STAT_RDY (1 << 30) +#define SPI_STAT_RXF_FLUSH (1 << 29) +#define SPI_STAT_TXF_FLUSH (1 << 28) +#define SPI_STAT_RXF_UNR (1 << 27) +#define SPI_STAT_TXF_OVF (1 << 26) +#define SPI_STAT_RXF_EMPTY (1 << 25) +#define SPI_STAT_RXF_FULL (1 << 24) +#define SPI_STAT_TXF_EMPTY (1 << 23) +#define SPI_STAT_TXF_FULL (1 << 22) +#define SPI_STAT_SEL_TXRX_N (1 << 16) +#define SPI_STAT_CUR_BLKCNT (1 << 15) + +#define SPI_TIMEOUT 1000 +#define TEGRA_SPI_MAX_FREQ 52000000 + +#endif /* _TEGRA20_SPI_H_ */ diff --git a/arch/arm/include/asm/arch-tegra20/tegra20_slink.h b/arch/arm/include/asm/arch-tegra20/tegra20_slink.h new file mode 100644 index 0000000000..afa9b36923 --- /dev/null +++ b/arch/arm/include/asm/arch-tegra20/tegra20_slink.h @@ -0,0 +1,84 @@ +/* + * NVIDIA Tegra SPI-SLINK controller + * + * Copyright 2010-2013 NVIDIA Corporation + * + * This software may be used and distributed according to the + * terms of the GNU Public License, Version 2, incorporated + * herein by reference. + * + * 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _TEGRA30_SPI_H_ +#define _TEGRA30_SPI_H_ + +#include + +struct slink_tegra { + u32 command; /* SLINK_COMMAND_0 register */ + u32 command2; /* SLINK_COMMAND2_0 reg */ + u32 status; /* SLINK_STATUS_0 register */ + u32 reserved; /* Reserved offset 0C */ + u32 mas_data; /* SLINK_MAS_DATA_0 reg */ + u32 slav_data; /* SLINK_SLAVE_DATA_0 reg */ + u32 dma_ctl; /* SLINK_DMA_CTL_0 register */ + u32 status2; /* SLINK_STATUS2_0 reg */ + u32 rsvd[56]; /* 0x20 to 0xFF reserved */ + u32 tx_fifo; /* SLINK_TX_FIFO_0 reg off 100h */ + u32 rsvd2[31]; /* 0x104 to 0x17F reserved */ + u32 rx_fifo; /* SLINK_RX_FIFO_0 reg off 180h */ +}; + +/* COMMAND */ +#define SLINK_CMD_ENB (1 << 31) +#define SLINK_CMD_GO (1 << 30) +#define SLINK_CMD_M_S (1 << 28) +#define SLINK_CMD_CK_SDA (1 << 21) +#define SLINK_CMD_CS_POL (1 << 13) +#define SLINK_CMD_CS_VAL (1 << 12) +#define SLINK_CMD_CS_SOFT (1 << 11) +#define SLINK_CMD_BIT_LENGTH (1 << 4) +#define SLINK_CMD_BIT_LENGTH_MASK 0x0000001F +/* COMMAND2 */ +#define SLINK_CMD2_TXEN (1 << 30) +#define SLINK_CMD2_RXEN (1 << 31) +#define SLINK_CMD2_SS_EN (1 << 18) +#define SLINK_CMD2_SS_EN_SHIFT 18 +#define SLINK_CMD2_SS_EN_MASK 0x000C0000 +#define SLINK_CMD2_CS_ACTIVE_BETWEEN (1 << 17) +/* STATUS */ +#define SLINK_STAT_BSY (1 << 31) +#define SLINK_STAT_RDY (1 << 30) +#define SLINK_STAT_ERR (1 << 29) +#define SLINK_STAT_RXF_FLUSH (1 << 27) +#define SLINK_STAT_TXF_FLUSH (1 << 26) +#define SLINK_STAT_RXF_OVF (1 << 25) +#define SLINK_STAT_TXF_UNR (1 << 24) +#define SLINK_STAT_RXF_EMPTY (1 << 23) +#define SLINK_STAT_RXF_FULL (1 << 22) +#define SLINK_STAT_TXF_EMPTY (1 << 21) +#define SLINK_STAT_TXF_FULL (1 << 20) +#define SLINK_STAT_TXF_OVF (1 << 19) +#define SLINK_STAT_RXF_UNR (1 << 18) +#define SLINK_STAT_CUR_BLKCNT (1 << 15) +/* STATUS2 */ +#define SLINK_STAT2_RXF_FULL_CNT (1 << 16) +#define SLINK_STAT2_TXF_FULL_CNT (1 << 0) + +#define SPI_TIMEOUT 1000 +#define TEGRA_SPI_MAX_FREQ 52000000 + +#endif /* _TEGRA30_SPI_H_ */ diff --git a/board/nvidia/common/board.c b/board/nvidia/common/board.c index b6e6566685..87a418bc6a 100644 --- a/board/nvidia/common/board.c +++ b/board/nvidia/common/board.c @@ -132,7 +132,7 @@ int board_init(void) clock_init(); clock_verify(); -#if defined(CONFIG_TEGRA_SPI) || defined(CONFIG_TEGRA_SLINK) +#if defined(CONFIG_TEGRA20_SFLASH) || defined(CONFIG_TEGRA20_SLINK) pin_mux_spi(); spi_init(); #endif diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index b8264df3a9..78e3d3d568 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -46,8 +46,8 @@ COBJS-$(CONFIG_OMAP3_SPI) += omap3_spi.o COBJS-$(CONFIG_SOFT_SPI) += soft_spi.o COBJS-$(CONFIG_SH_SPI) += sh_spi.o COBJS-$(CONFIG_FSL_ESPI) += fsl_espi.o -COBJS-$(CONFIG_TEGRA_SPI) += tegra_spi.o -COBJS-$(CONFIG_TEGRA_SLINK) += tegra_slink.o +COBJS-$(CONFIG_TEGRA20_SFLASH) += tegra20_sflash.o +COBJS-$(CONFIG_TEGRA20_SLINK) += tegra20_slink.o COBJS-$(CONFIG_XILINX_SPI) += xilinx_spi.o COBJS := $(COBJS-y) diff --git a/drivers/spi/tegra20_sflash.c b/drivers/spi/tegra20_sflash.c new file mode 100644 index 0000000000..c6af30f0d6 --- /dev/null +++ b/drivers/spi/tegra20_sflash.c @@ -0,0 +1,307 @@ +/* + * Copyright (c) 2010-2012 NVIDIA Corporation + * With help from the mpc8xxx SPI driver + * With more help from omap3_spi SPI driver + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +struct tegra_spi_slave { + struct spi_slave slave; + struct spi_tegra *regs; + unsigned int freq; + unsigned int mode; + int periph_id; +}; + +static inline struct tegra_spi_slave *to_tegra_spi(struct spi_slave *slave) +{ + return container_of(slave, struct tegra_spi_slave, slave); +} + +int spi_cs_is_valid(unsigned int bus, unsigned int cs) +{ + /* Tegra20 SPI-Flash - only 1 device ('bus/cs') */ + if (bus != 0 || cs != 0) + return 0; + else + return 1; +} + +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + struct tegra_spi_slave *spi; + + if (!spi_cs_is_valid(bus, cs)) { + printf("SPI error: unsupported bus %d / chip select %d\n", + bus, cs); + return NULL; + } + + if (max_hz > TEGRA_SPI_MAX_FREQ) { + printf("SPI error: unsupported frequency %d Hz. Max frequency" + " is %d Hz\n", max_hz, TEGRA_SPI_MAX_FREQ); + return NULL; + } + + spi = malloc(sizeof(struct tegra_spi_slave)); + if (!spi) { + printf("SPI error: malloc of SPI structure failed\n"); + return NULL; + } + spi->slave.bus = bus; + spi->slave.cs = cs; +#ifdef CONFIG_OF_CONTROL + int node = fdtdec_next_compatible(gd->fdt_blob, 0, + COMPAT_NVIDIA_TEGRA20_SFLASH); + if (node < 0) { + debug("%s: cannot locate sflash node\n", __func__); + return NULL; + } + if (!fdtdec_get_is_enabled(gd->fdt_blob, node)) { + debug("%s: sflash is disabled\n", __func__); + return NULL; + } + spi->regs = (struct spi_tegra *)fdtdec_get_addr(gd->fdt_blob, + node, "reg"); + if ((fdt_addr_t)spi->regs == FDT_ADDR_T_NONE) { + debug("%s: no sflash register found\n", __func__); + return NULL; + } + spi->freq = fdtdec_get_int(gd->fdt_blob, node, "spi-max-frequency", 0); + if (!spi->freq) { + debug("%s: no sflash max frequency found\n", __func__); + return NULL; + } + spi->periph_id = clock_decode_periph_id(gd->fdt_blob, node); + if (spi->periph_id == PERIPH_ID_NONE) { + debug("%s: could not decode periph id\n", __func__); + return NULL; + } +#else + spi->regs = (struct spi_tegra *)NV_PA_SPI_BASE; + spi->freq = TEGRA_SPI_MAX_FREQ; + spi->periph_id = PERIPH_ID_SPI1; +#endif + if (max_hz < spi->freq) { + debug("%s: limiting frequency from %u to %u\n", __func__, + spi->freq, max_hz); + spi->freq = max_hz; + } + debug("%s: controller initialized at %p, freq = %u, periph_id = %d\n", + __func__, spi->regs, spi->freq, spi->periph_id); + spi->mode = mode; + + return &spi->slave; +} + +void spi_free_slave(struct spi_slave *slave) +{ + struct tegra_spi_slave *spi = to_tegra_spi(slave); + + free(spi); +} + +void spi_init(void) +{ + /* do nothing */ +} + +int spi_claim_bus(struct spi_slave *slave) +{ + struct tegra_spi_slave *spi = to_tegra_spi(slave); + struct spi_tegra *regs = spi->regs; + u32 reg; + + /* Change SPI clock to correct frequency, PLLP_OUT0 source */ + clock_start_periph_pll(spi->periph_id, CLOCK_ID_PERIPH, spi->freq); + + /* Clear stale status here */ + reg = SPI_STAT_RDY | SPI_STAT_RXF_FLUSH | SPI_STAT_TXF_FLUSH | \ + SPI_STAT_RXF_UNR | SPI_STAT_TXF_OVF; + writel(reg, ®s->status); + debug("spi_init: STATUS = %08x\n", readl(®s->status)); + + /* + * Use sw-controlled CS, so we can clock in data after ReadID, etc. + */ + reg = (spi->mode & 1) << SPI_CMD_ACTIVE_SDA_SHIFT; + if (spi->mode & 2) + reg |= 1 << SPI_CMD_ACTIVE_SCLK_SHIFT; + clrsetbits_le32(®s->command, SPI_CMD_ACTIVE_SCLK_MASK | + SPI_CMD_ACTIVE_SDA_MASK, SPI_CMD_CS_SOFT | reg); + debug("spi_init: COMMAND = %08x\n", readl(®s->command)); + + /* + * SPI pins on Tegra20 are muxed - change pinmux later due to UART + * issue. + */ + pinmux_set_func(PINGRP_GMD, PMUX_FUNC_SFLASH); + pinmux_tristate_disable(PINGRP_LSPI); + pinmux_set_func(PINGRP_GMC, PMUX_FUNC_SFLASH); + + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ + /* + * We can't release UART_DISABLE and set pinmux to UART4 here since + * some code (e,g, spi_flash_probe) uses printf() while the SPI + * bus is held. That is arguably bad, but it has the advantage of + * already being in the source tree. + */ +} + +void spi_cs_activate(struct spi_slave *slave) +{ + struct tegra_spi_slave *spi = to_tegra_spi(slave); + + /* CS is negated on Tegra, so drive a 1 to get a 0 */ + setbits_le32(&spi->regs->command, SPI_CMD_CS_VAL); +} + +void spi_cs_deactivate(struct spi_slave *slave) +{ + struct tegra_spi_slave *spi = to_tegra_spi(slave); + + /* CS is negated on Tegra, so drive a 0 to get a 1 */ + clrbits_le32(&spi->regs->command, SPI_CMD_CS_VAL); +} + +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, + const void *data_out, void *data_in, unsigned long flags) +{ + struct tegra_spi_slave *spi = to_tegra_spi(slave); + struct spi_tegra *regs = spi->regs; + u32 reg, tmpdout, tmpdin = 0; + const u8 *dout = data_out; + u8 *din = data_in; + int num_bytes; + int ret; + + debug("spi_xfer: slave %u:%u dout %08X din %08X bitlen %u\n", + slave->bus, slave->cs, *(u8 *)dout, *(u8 *)din, bitlen); + if (bitlen % 8) + return -1; + num_bytes = bitlen / 8; + + ret = 0; + + reg = readl(®s->status); + writel(reg, ®s->status); /* Clear all SPI events via R/W */ + debug("spi_xfer entry: STATUS = %08x\n", reg); + + reg = readl(®s->command); + reg |= SPI_CMD_TXEN | SPI_CMD_RXEN; + writel(reg, ®s->command); + debug("spi_xfer: COMMAND = %08x\n", readl(®s->command)); + + if (flags & SPI_XFER_BEGIN) + spi_cs_activate(slave); + + /* handle data in 32-bit chunks */ + while (num_bytes > 0) { + int bytes; + int is_read = 0; + int tm, i; + + tmpdout = 0; + bytes = (num_bytes > 4) ? 4 : num_bytes; + + if (dout != NULL) { + for (i = 0; i < bytes; ++i) + tmpdout = (tmpdout << 8) | dout[i]; + } + + num_bytes -= bytes; + if (dout) + dout += bytes; + + clrsetbits_le32(®s->command, SPI_CMD_BIT_LENGTH_MASK, + bytes * 8 - 1); + writel(tmpdout, ®s->tx_fifo); + setbits_le32(®s->command, SPI_CMD_GO); + + /* + * Wait for SPI transmit FIFO to empty, or to time out. + * The RX FIFO status will be read and cleared last + */ + for (tm = 0, is_read = 0; tm < SPI_TIMEOUT; ++tm) { + u32 status; + + status = readl(®s->status); + + /* We can exit when we've had both RX and TX activity */ + if (is_read && (status & SPI_STAT_TXF_EMPTY)) + break; + + if ((status & (SPI_STAT_BSY | SPI_STAT_RDY)) != + SPI_STAT_RDY) + tm++; + + else if (!(status & SPI_STAT_RXF_EMPTY)) { + tmpdin = readl(®s->rx_fifo); + is_read = 1; + + /* swap bytes read in */ + if (din != NULL) { + for (i = bytes - 1; i >= 0; --i) { + din[i] = tmpdin & 0xff; + tmpdin >>= 8; + } + din += bytes; + } + } + } + + if (tm >= SPI_TIMEOUT) + ret = tm; + + /* clear ACK RDY, etc. bits */ + writel(readl(®s->status), ®s->status); + } + + if (flags & SPI_XFER_END) + spi_cs_deactivate(slave); + + debug("spi_xfer: transfer ended. Value=%08x, status = %08x\n", + tmpdin, readl(®s->status)); + + if (ret) { + printf("spi_xfer: timeout during SPI transfer, tm %d\n", ret); + return -1; + } + + return 0; +} diff --git a/drivers/spi/tegra20_slink.c b/drivers/spi/tegra20_slink.c new file mode 100644 index 0000000000..a6de4cec69 --- /dev/null +++ b/drivers/spi/tegra20_slink.c @@ -0,0 +1,343 @@ +/* + * NVIDIA Tegra SPI-SLINK controller + * + * Copyright (c) 2010-2013 NVIDIA Corporation + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +struct tegra_spi_ctrl { + struct slink_tegra *regs; + unsigned int freq; + unsigned int mode; + int periph_id; + int valid; +}; + +struct tegra_spi_slave { + struct spi_slave slave; + struct tegra_spi_ctrl *ctrl; +}; + +static struct tegra_spi_ctrl spi_ctrls[CONFIG_TEGRA_SLINK_CTRLS]; + +static inline struct tegra_spi_slave *to_tegra_spi(struct spi_slave *slave) +{ + return container_of(slave, struct tegra_spi_slave, slave); +} + +int spi_cs_is_valid(unsigned int bus, unsigned int cs) +{ + if (bus >= CONFIG_TEGRA_SLINK_CTRLS || cs > 3 || !spi_ctrls[bus].valid) + return 0; + else + return 1; +} + +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + struct tegra_spi_slave *spi; + + debug("%s: bus: %u, cs: %u, max_hz: %u, mode: %u\n", __func__, + bus, cs, max_hz, mode); + + if (!spi_cs_is_valid(bus, cs)) { + printf("SPI error: unsupported bus %d / chip select %d\n", + bus, cs); + return NULL; + } + + if (max_hz > TEGRA_SPI_MAX_FREQ) { + printf("SPI error: unsupported frequency %d Hz. Max frequency" + " is %d Hz\n", max_hz, TEGRA_SPI_MAX_FREQ); + return NULL; + } + + spi = malloc(sizeof(struct tegra_spi_slave)); + if (!spi) { + printf("SPI error: malloc of SPI structure failed\n"); + return NULL; + } + spi->slave.bus = bus; + spi->slave.cs = cs; + spi->ctrl = &spi_ctrls[bus]; + if (!spi->ctrl) { + printf("SPI error: could not find controller for bus %d\n", + bus); + return NULL; + } + + if (max_hz < spi->ctrl->freq) { + debug("%s: limiting frequency from %u to %u\n", __func__, + spi->ctrl->freq, max_hz); + spi->ctrl->freq = max_hz; + } + spi->ctrl->mode = mode; + + return &spi->slave; +} + +void spi_free_slave(struct spi_slave *slave) +{ + struct tegra_spi_slave *spi = to_tegra_spi(slave); + + free(spi); +} + +void spi_init(void) +{ + struct tegra_spi_ctrl *ctrl; + int i; +#ifdef CONFIG_OF_CONTROL + int node = 0; + int count; + int node_list[CONFIG_TEGRA_SLINK_CTRLS]; + + count = fdtdec_find_aliases_for_id(gd->fdt_blob, "spi", + COMPAT_NVIDIA_TEGRA20_SLINK, + node_list, + CONFIG_TEGRA_SLINK_CTRLS); + for (i = 0; i < count; i++) { + ctrl = &spi_ctrls[i]; + node = node_list[i]; + + ctrl->regs = (struct slink_tegra *)fdtdec_get_addr(gd->fdt_blob, + node, "reg"); + if ((fdt_addr_t)ctrl->regs == FDT_ADDR_T_NONE) { + debug("%s: no slink register found\n", __func__); + continue; + } + ctrl->freq = fdtdec_get_int(gd->fdt_blob, node, + "spi-max-frequency", 0); + if (!ctrl->freq) { + debug("%s: no slink max frequency found\n", __func__); + continue; + } + + ctrl->periph_id = clock_decode_periph_id(gd->fdt_blob, node); + if (ctrl->periph_id == PERIPH_ID_NONE) { + debug("%s: could not decode periph id\n", __func__); + continue; + } + ctrl->valid = 1; + + debug("%s: found controller at %p, freq = %u, periph_id = %d\n", + __func__, ctrl->regs, ctrl->freq, ctrl->periph_id); + } +#else + for (i = 0; i < CONFIG_TEGRA_SLINK_CTRLS; i++) { + ctrl = &spi_ctrls[i]; + u32 base_regs[] = { + NV_PA_SLINK1_BASE, + NV_PA_SLINK2_BASE, + NV_PA_SLINK3_BASE, + NV_PA_SLINK4_BASE, + NV_PA_SLINK5_BASE, + NV_PA_SLINK6_BASE, + }; + int periph_ids[] = { + PERIPH_ID_SBC1, + PERIPH_ID_SBC2, + PERIPH_ID_SBC3, + PERIPH_ID_SBC4, + PERIPH_ID_SBC5, + PERIPH_ID_SBC6, + }; + ctrl->regs = (struct slink_tegra *)base_regs[i]; + ctrl->freq = TEGRA_SPI_MAX_FREQ; + ctrl->periph_id = periph_ids[i]; + ctrl->valid = 1; + + debug("%s: found controller at %p, freq = %u, periph_id = %d\n", + __func__, ctrl->regs, ctrl->freq, ctrl->periph_id); + } +#endif +} + +int spi_claim_bus(struct spi_slave *slave) +{ + struct tegra_spi_slave *spi = to_tegra_spi(slave); + struct slink_tegra *regs = spi->ctrl->regs; + u32 reg; + + /* Change SPI clock to correct frequency, PLLP_OUT0 source */ + clock_start_periph_pll(spi->ctrl->periph_id, CLOCK_ID_PERIPH, + spi->ctrl->freq); + + /* Clear stale status here */ + reg = SLINK_STAT_RDY | SLINK_STAT_RXF_FLUSH | SLINK_STAT_TXF_FLUSH | \ + SLINK_STAT_RXF_UNR | SLINK_STAT_TXF_OVF; + writel(reg, ®s->status); + debug("%s: STATUS = %08x\n", __func__, readl(®s->status)); + + /* Set master mode and sw controlled CS */ + reg = readl(®s->command); + reg |= SLINK_CMD_M_S | SLINK_CMD_CS_SOFT; + writel(reg, ®s->command); + debug("%s: COMMAND = %08x\n", __func__, readl(®s->command)); + + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ +} + +void spi_cs_activate(struct spi_slave *slave) +{ + struct tegra_spi_slave *spi = to_tegra_spi(slave); + struct slink_tegra *regs = spi->ctrl->regs; + + /* CS is negated on Tegra, so drive a 1 to get a 0 */ + setbits_le32(®s->command, SLINK_CMD_CS_VAL); +} + +void spi_cs_deactivate(struct spi_slave *slave) +{ + struct tegra_spi_slave *spi = to_tegra_spi(slave); + struct slink_tegra *regs = spi->ctrl->regs; + + /* CS is negated on Tegra, so drive a 0 to get a 1 */ + clrbits_le32(®s->command, SLINK_CMD_CS_VAL); +} + +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, + const void *data_out, void *data_in, unsigned long flags) +{ + struct tegra_spi_slave *spi = to_tegra_spi(slave); + struct slink_tegra *regs = spi->ctrl->regs; + u32 reg, tmpdout, tmpdin = 0; + const u8 *dout = data_out; + u8 *din = data_in; + int num_bytes; + int ret; + + debug("%s: slave %u:%u dout %p din %p bitlen %u\n", + __func__, slave->bus, slave->cs, dout, din, bitlen); + if (bitlen % 8) + return -1; + num_bytes = bitlen / 8; + + ret = 0; + + reg = readl(®s->status); + writel(reg, ®s->status); /* Clear all SPI events via R/W */ + debug("%s entry: STATUS = %08x\n", __func__, reg); + + reg = readl(®s->status2); + writel(reg, ®s->status2); /* Clear all STATUS2 events via R/W */ + debug("%s entry: STATUS2 = %08x\n", __func__, reg); + + debug("%s entry: COMMAND = %08x\n", __func__, readl(®s->command)); + + clrsetbits_le32(®s->command2, SLINK_CMD2_SS_EN_MASK, + SLINK_CMD2_TXEN | SLINK_CMD2_RXEN | + (slave->cs << SLINK_CMD2_SS_EN_SHIFT)); + debug("%s entry: COMMAND2 = %08x\n", __func__, readl(®s->command2)); + + if (flags & SPI_XFER_BEGIN) + spi_cs_activate(slave); + + /* handle data in 32-bit chunks */ + while (num_bytes > 0) { + int bytes; + int is_read = 0; + int tm, i; + + tmpdout = 0; + bytes = (num_bytes > 4) ? 4 : num_bytes; + + if (dout != NULL) { + for (i = 0; i < bytes; ++i) + tmpdout = (tmpdout << 8) | dout[i]; + dout += bytes; + } + + num_bytes -= bytes; + + clrsetbits_le32(®s->command, SLINK_CMD_BIT_LENGTH_MASK, + bytes * 8 - 1); + writel(tmpdout, ®s->tx_fifo); + setbits_le32(®s->command, SLINK_CMD_GO); + + /* + * Wait for SPI transmit FIFO to empty, or to time out. + * The RX FIFO status will be read and cleared last + */ + for (tm = 0, is_read = 0; tm < SPI_TIMEOUT; ++tm) { + u32 status; + + status = readl(®s->status); + + /* We can exit when we've had both RX and TX activity */ + if (is_read && (status & SLINK_STAT_TXF_EMPTY)) + break; + + if ((status & (SLINK_STAT_BSY | SLINK_STAT_RDY)) != + SLINK_STAT_RDY) + tm++; + + else if (!(status & SLINK_STAT_RXF_EMPTY)) { + tmpdin = readl(®s->rx_fifo); + is_read = 1; + + /* swap bytes read in */ + if (din != NULL) { + for (i = bytes - 1; i >= 0; --i) { + din[i] = tmpdin & 0xff; + tmpdin >>= 8; + } + din += bytes; + } + } + } + + if (tm >= SPI_TIMEOUT) + ret = tm; + + /* clear ACK RDY, etc. bits */ + writel(readl(®s->status), ®s->status); + } + + if (flags & SPI_XFER_END) + spi_cs_deactivate(slave); + + debug("%s: transfer ended. Value=%08x, status = %08x\n", + __func__, tmpdin, readl(®s->status)); + + if (ret) { + printf("%s: timeout during SPI transfer, tm %d\n", + __func__, ret); + return -1; + } + + return 0; +} diff --git a/drivers/spi/tegra_slink.c b/drivers/spi/tegra_slink.c deleted file mode 100644 index 2c41fabe28..0000000000 --- a/drivers/spi/tegra_slink.c +++ /dev/null @@ -1,343 +0,0 @@ -/* - * NVIDIA Tegra SPI-SLINK controller - * - * Copyright (c) 2010-2013 NVIDIA Corporation - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -DECLARE_GLOBAL_DATA_PTR; - -struct tegra_spi_ctrl { - struct slink_tegra *regs; - unsigned int freq; - unsigned int mode; - int periph_id; - int valid; -}; - -struct tegra_spi_slave { - struct spi_slave slave; - struct tegra_spi_ctrl *ctrl; -}; - -static struct tegra_spi_ctrl spi_ctrls[CONFIG_TEGRA_SLINK_CTRLS]; - -static inline struct tegra_spi_slave *to_tegra_spi(struct spi_slave *slave) -{ - return container_of(slave, struct tegra_spi_slave, slave); -} - -int spi_cs_is_valid(unsigned int bus, unsigned int cs) -{ - if (bus >= CONFIG_TEGRA_SLINK_CTRLS || cs > 3 || !spi_ctrls[bus].valid) - return 0; - else - return 1; -} - -struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, - unsigned int max_hz, unsigned int mode) -{ - struct tegra_spi_slave *spi; - - debug("%s: bus: %u, cs: %u, max_hz: %u, mode: %u\n", __func__, - bus, cs, max_hz, mode); - - if (!spi_cs_is_valid(bus, cs)) { - printf("SPI error: unsupported bus %d / chip select %d\n", - bus, cs); - return NULL; - } - - if (max_hz > TEGRA_SPI_MAX_FREQ) { - printf("SPI error: unsupported frequency %d Hz. Max frequency" - " is %d Hz\n", max_hz, TEGRA_SPI_MAX_FREQ); - return NULL; - } - - spi = malloc(sizeof(struct tegra_spi_slave)); - if (!spi) { - printf("SPI error: malloc of SPI structure failed\n"); - return NULL; - } - spi->slave.bus = bus; - spi->slave.cs = cs; - spi->ctrl = &spi_ctrls[bus]; - if (!spi->ctrl) { - printf("SPI error: could not find controller for bus %d\n", - bus); - return NULL; - } - - if (max_hz < spi->ctrl->freq) { - debug("%s: limiting frequency from %u to %u\n", __func__, - spi->ctrl->freq, max_hz); - spi->ctrl->freq = max_hz; - } - spi->ctrl->mode = mode; - - return &spi->slave; -} - -void spi_free_slave(struct spi_slave *slave) -{ - struct tegra_spi_slave *spi = to_tegra_spi(slave); - - free(spi); -} - -void spi_init(void) -{ - struct tegra_spi_ctrl *ctrl; - int i; -#ifdef CONFIG_OF_CONTROL - int node = 0; - int count; - int node_list[CONFIG_TEGRA_SLINK_CTRLS]; - - count = fdtdec_find_aliases_for_id(gd->fdt_blob, "spi", - COMPAT_NVIDIA_TEGRA20_SLINK, - node_list, - CONFIG_TEGRA_SLINK_CTRLS); - for (i = 0; i < count; i++) { - ctrl = &spi_ctrls[i]; - node = node_list[i]; - - ctrl->regs = (struct slink_tegra *)fdtdec_get_addr(gd->fdt_blob, - node, "reg"); - if ((fdt_addr_t)ctrl->regs == FDT_ADDR_T_NONE) { - debug("%s: no slink register found\n", __func__); - continue; - } - ctrl->freq = fdtdec_get_int(gd->fdt_blob, node, - "spi-max-frequency", 0); - if (!ctrl->freq) { - debug("%s: no slink max frequency found\n", __func__); - continue; - } - - ctrl->periph_id = clock_decode_periph_id(gd->fdt_blob, node); - if (ctrl->periph_id == PERIPH_ID_NONE) { - debug("%s: could not decode periph id\n", __func__); - continue; - } - ctrl->valid = 1; - - debug("%s: found controller at %p, freq = %u, periph_id = %d\n", - __func__, ctrl->regs, ctrl->freq, ctrl->periph_id); - } -#else - for (i = 0; i < CONFIG_TEGRA_SLINK_CTRLS; i++) { - ctrl = &spi_ctrls[i]; - u32 base_regs[] = { - NV_PA_SLINK1_BASE, - NV_PA_SLINK2_BASE, - NV_PA_SLINK3_BASE, - NV_PA_SLINK4_BASE, - NV_PA_SLINK5_BASE, - NV_PA_SLINK6_BASE, - }; - int periph_ids[] = { - PERIPH_ID_SBC1, - PERIPH_ID_SBC2, - PERIPH_ID_SBC3, - PERIPH_ID_SBC4, - PERIPH_ID_SBC5, - PERIPH_ID_SBC6, - }; - ctrl->regs = (struct slink_tegra *)base_regs[i]; - ctrl->freq = TEGRA_SPI_MAX_FREQ; - ctrl->periph_id = periph_ids[i]; - ctrl->valid = 1; - - debug("%s: found controller at %p, freq = %u, periph_id = %d\n", - __func__, ctrl->regs, ctrl->freq, ctrl->periph_id); - } -#endif -} - -int spi_claim_bus(struct spi_slave *slave) -{ - struct tegra_spi_slave *spi = to_tegra_spi(slave); - struct slink_tegra *regs = spi->ctrl->regs; - u32 reg; - - /* Change SPI clock to correct frequency, PLLP_OUT0 source */ - clock_start_periph_pll(spi->ctrl->periph_id, CLOCK_ID_PERIPH, - spi->ctrl->freq); - - /* Clear stale status here */ - reg = SLINK_STAT_RDY | SLINK_STAT_RXF_FLUSH | SLINK_STAT_TXF_FLUSH | \ - SLINK_STAT_RXF_UNR | SLINK_STAT_TXF_OVF; - writel(reg, ®s->status); - debug("%s: STATUS = %08x\n", __func__, readl(®s->status)); - - /* Set master mode and sw controlled CS */ - reg = readl(®s->command); - reg |= SLINK_CMD_M_S | SLINK_CMD_CS_SOFT; - writel(reg, ®s->command); - debug("%s: COMMAND = %08x\n", __func__, readl(®s->command)); - - return 0; -} - -void spi_release_bus(struct spi_slave *slave) -{ -} - -void spi_cs_activate(struct spi_slave *slave) -{ - struct tegra_spi_slave *spi = to_tegra_spi(slave); - struct slink_tegra *regs = spi->ctrl->regs; - - /* CS is negated on Tegra, so drive a 1 to get a 0 */ - setbits_le32(®s->command, SLINK_CMD_CS_VAL); -} - -void spi_cs_deactivate(struct spi_slave *slave) -{ - struct tegra_spi_slave *spi = to_tegra_spi(slave); - struct slink_tegra *regs = spi->ctrl->regs; - - /* CS is negated on Tegra, so drive a 0 to get a 1 */ - clrbits_le32(®s->command, SLINK_CMD_CS_VAL); -} - -int spi_xfer(struct spi_slave *slave, unsigned int bitlen, - const void *data_out, void *data_in, unsigned long flags) -{ - struct tegra_spi_slave *spi = to_tegra_spi(slave); - struct slink_tegra *regs = spi->ctrl->regs; - u32 reg, tmpdout, tmpdin = 0; - const u8 *dout = data_out; - u8 *din = data_in; - int num_bytes; - int ret; - - debug("%s: slave %u:%u dout %p din %p bitlen %u\n", - __func__, slave->bus, slave->cs, dout, din, bitlen); - if (bitlen % 8) - return -1; - num_bytes = bitlen / 8; - - ret = 0; - - reg = readl(®s->status); - writel(reg, ®s->status); /* Clear all SPI events via R/W */ - debug("%s entry: STATUS = %08x\n", __func__, reg); - - reg = readl(®s->status2); - writel(reg, ®s->status2); /* Clear all STATUS2 events via R/W */ - debug("%s entry: STATUS2 = %08x\n", __func__, reg); - - debug("%s entry: COMMAND = %08x\n", __func__, readl(®s->command)); - - clrsetbits_le32(®s->command2, SLINK_CMD2_SS_EN_MASK, - SLINK_CMD2_TXEN | SLINK_CMD2_RXEN | - (slave->cs << SLINK_CMD2_SS_EN_SHIFT)); - debug("%s entry: COMMAND2 = %08x\n", __func__, readl(®s->command2)); - - if (flags & SPI_XFER_BEGIN) - spi_cs_activate(slave); - - /* handle data in 32-bit chunks */ - while (num_bytes > 0) { - int bytes; - int is_read = 0; - int tm, i; - - tmpdout = 0; - bytes = (num_bytes > 4) ? 4 : num_bytes; - - if (dout != NULL) { - for (i = 0; i < bytes; ++i) - tmpdout = (tmpdout << 8) | dout[i]; - dout += bytes; - } - - num_bytes -= bytes; - - clrsetbits_le32(®s->command, SLINK_CMD_BIT_LENGTH_MASK, - bytes * 8 - 1); - writel(tmpdout, ®s->tx_fifo); - setbits_le32(®s->command, SLINK_CMD_GO); - - /* - * Wait for SPI transmit FIFO to empty, or to time out. - * The RX FIFO status will be read and cleared last - */ - for (tm = 0, is_read = 0; tm < SPI_TIMEOUT; ++tm) { - u32 status; - - status = readl(®s->status); - - /* We can exit when we've had both RX and TX activity */ - if (is_read && (status & SLINK_STAT_TXF_EMPTY)) - break; - - if ((status & (SLINK_STAT_BSY | SLINK_STAT_RDY)) != - SLINK_STAT_RDY) - tm++; - - else if (!(status & SLINK_STAT_RXF_EMPTY)) { - tmpdin = readl(®s->rx_fifo); - is_read = 1; - - /* swap bytes read in */ - if (din != NULL) { - for (i = bytes - 1; i >= 0; --i) { - din[i] = tmpdin & 0xff; - tmpdin >>= 8; - } - din += bytes; - } - } - } - - if (tm >= SPI_TIMEOUT) - ret = tm; - - /* clear ACK RDY, etc. bits */ - writel(readl(®s->status), ®s->status); - } - - if (flags & SPI_XFER_END) - spi_cs_deactivate(slave); - - debug("%s: transfer ended. Value=%08x, status = %08x\n", - __func__, tmpdin, readl(®s->status)); - - if (ret) { - printf("%s: timeout during SPI transfer, tm %d\n", - __func__, ret); - return -1; - } - - return 0; -} diff --git a/drivers/spi/tegra_spi.c b/drivers/spi/tegra_spi.c deleted file mode 100644 index 2662923ff1..0000000000 --- a/drivers/spi/tegra_spi.c +++ /dev/null @@ -1,307 +0,0 @@ -/* - * Copyright (c) 2010-2012 NVIDIA Corporation - * With help from the mpc8xxx SPI driver - * With more help from omap3_spi SPI driver - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -DECLARE_GLOBAL_DATA_PTR; - -struct tegra_spi_slave { - struct spi_slave slave; - struct spi_tegra *regs; - unsigned int freq; - unsigned int mode; - int periph_id; -}; - -static inline struct tegra_spi_slave *to_tegra_spi(struct spi_slave *slave) -{ - return container_of(slave, struct tegra_spi_slave, slave); -} - -int spi_cs_is_valid(unsigned int bus, unsigned int cs) -{ - /* Tegra20 SPI-Flash - only 1 device ('bus/cs') */ - if (bus != 0 || cs != 0) - return 0; - else - return 1; -} - -struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, - unsigned int max_hz, unsigned int mode) -{ - struct tegra_spi_slave *spi; - - if (!spi_cs_is_valid(bus, cs)) { - printf("SPI error: unsupported bus %d / chip select %d\n", - bus, cs); - return NULL; - } - - if (max_hz > TEGRA_SPI_MAX_FREQ) { - printf("SPI error: unsupported frequency %d Hz. Max frequency" - " is %d Hz\n", max_hz, TEGRA_SPI_MAX_FREQ); - return NULL; - } - - spi = malloc(sizeof(struct tegra_spi_slave)); - if (!spi) { - printf("SPI error: malloc of SPI structure failed\n"); - return NULL; - } - spi->slave.bus = bus; - spi->slave.cs = cs; -#ifdef CONFIG_OF_CONTROL - int node = fdtdec_next_compatible(gd->fdt_blob, 0, - COMPAT_NVIDIA_TEGRA20_SFLASH); - if (node < 0) { - debug("%s: cannot locate sflash node\n", __func__); - return NULL; - } - if (!fdtdec_get_is_enabled(gd->fdt_blob, node)) { - debug("%s: sflash is disabled\n", __func__); - return NULL; - } - spi->regs = (struct spi_tegra *)fdtdec_get_addr(gd->fdt_blob, - node, "reg"); - if ((fdt_addr_t)spi->regs == FDT_ADDR_T_NONE) { - debug("%s: no sflash register found\n", __func__); - return NULL; - } - spi->freq = fdtdec_get_int(gd->fdt_blob, node, "spi-max-frequency", 0); - if (!spi->freq) { - debug("%s: no sflash max frequency found\n", __func__); - return NULL; - } - spi->periph_id = clock_decode_periph_id(gd->fdt_blob, node); - if (spi->periph_id == PERIPH_ID_NONE) { - debug("%s: could not decode periph id\n", __func__); - return NULL; - } -#else - spi->regs = (struct spi_tegra *)NV_PA_SPI_BASE; - spi->freq = TEGRA_SPI_MAX_FREQ; - spi->periph_id = PERIPH_ID_SPI1; -#endif - if (max_hz < spi->freq) { - debug("%s: limiting frequency from %u to %u\n", __func__, - spi->freq, max_hz); - spi->freq = max_hz; - } - debug("%s: controller initialized at %p, freq = %u, periph_id = %d\n", - __func__, spi->regs, spi->freq, spi->periph_id); - spi->mode = mode; - - return &spi->slave; -} - -void spi_free_slave(struct spi_slave *slave) -{ - struct tegra_spi_slave *spi = to_tegra_spi(slave); - - free(spi); -} - -void spi_init(void) -{ - /* do nothing */ -} - -int spi_claim_bus(struct spi_slave *slave) -{ - struct tegra_spi_slave *spi = to_tegra_spi(slave); - struct spi_tegra *regs = spi->regs; - u32 reg; - - /* Change SPI clock to correct frequency, PLLP_OUT0 source */ - clock_start_periph_pll(spi->periph_id, CLOCK_ID_PERIPH, spi->freq); - - /* Clear stale status here */ - reg = SPI_STAT_RDY | SPI_STAT_RXF_FLUSH | SPI_STAT_TXF_FLUSH | \ - SPI_STAT_RXF_UNR | SPI_STAT_TXF_OVF; - writel(reg, ®s->status); - debug("spi_init: STATUS = %08x\n", readl(®s->status)); - - /* - * Use sw-controlled CS, so we can clock in data after ReadID, etc. - */ - reg = (spi->mode & 1) << SPI_CMD_ACTIVE_SDA_SHIFT; - if (spi->mode & 2) - reg |= 1 << SPI_CMD_ACTIVE_SCLK_SHIFT; - clrsetbits_le32(®s->command, SPI_CMD_ACTIVE_SCLK_MASK | - SPI_CMD_ACTIVE_SDA_MASK, SPI_CMD_CS_SOFT | reg); - debug("spi_init: COMMAND = %08x\n", readl(®s->command)); - - /* - * SPI pins on Tegra20 are muxed - change pinmux later due to UART - * issue. - */ - pinmux_set_func(PINGRP_GMD, PMUX_FUNC_SFLASH); - pinmux_tristate_disable(PINGRP_LSPI); - pinmux_set_func(PINGRP_GMC, PMUX_FUNC_SFLASH); - - return 0; -} - -void spi_release_bus(struct spi_slave *slave) -{ - /* - * We can't release UART_DISABLE and set pinmux to UART4 here since - * some code (e,g, spi_flash_probe) uses printf() while the SPI - * bus is held. That is arguably bad, but it has the advantage of - * already being in the source tree. - */ -} - -void spi_cs_activate(struct spi_slave *slave) -{ - struct tegra_spi_slave *spi = to_tegra_spi(slave); - - /* CS is negated on Tegra, so drive a 1 to get a 0 */ - setbits_le32(&spi->regs->command, SPI_CMD_CS_VAL); -} - -void spi_cs_deactivate(struct spi_slave *slave) -{ - struct tegra_spi_slave *spi = to_tegra_spi(slave); - - /* CS is negated on Tegra, so drive a 0 to get a 1 */ - clrbits_le32(&spi->regs->command, SPI_CMD_CS_VAL); -} - -int spi_xfer(struct spi_slave *slave, unsigned int bitlen, - const void *data_out, void *data_in, unsigned long flags) -{ - struct tegra_spi_slave *spi = to_tegra_spi(slave); - struct spi_tegra *regs = spi->regs; - u32 reg, tmpdout, tmpdin = 0; - const u8 *dout = data_out; - u8 *din = data_in; - int num_bytes; - int ret; - - debug("spi_xfer: slave %u:%u dout %08X din %08X bitlen %u\n", - slave->bus, slave->cs, *(u8 *)dout, *(u8 *)din, bitlen); - if (bitlen % 8) - return -1; - num_bytes = bitlen / 8; - - ret = 0; - - reg = readl(®s->status); - writel(reg, ®s->status); /* Clear all SPI events via R/W */ - debug("spi_xfer entry: STATUS = %08x\n", reg); - - reg = readl(®s->command); - reg |= SPI_CMD_TXEN | SPI_CMD_RXEN; - writel(reg, ®s->command); - debug("spi_xfer: COMMAND = %08x\n", readl(®s->command)); - - if (flags & SPI_XFER_BEGIN) - spi_cs_activate(slave); - - /* handle data in 32-bit chunks */ - while (num_bytes > 0) { - int bytes; - int is_read = 0; - int tm, i; - - tmpdout = 0; - bytes = (num_bytes > 4) ? 4 : num_bytes; - - if (dout != NULL) { - for (i = 0; i < bytes; ++i) - tmpdout = (tmpdout << 8) | dout[i]; - } - - num_bytes -= bytes; - if (dout) - dout += bytes; - - clrsetbits_le32(®s->command, SPI_CMD_BIT_LENGTH_MASK, - bytes * 8 - 1); - writel(tmpdout, ®s->tx_fifo); - setbits_le32(®s->command, SPI_CMD_GO); - - /* - * Wait for SPI transmit FIFO to empty, or to time out. - * The RX FIFO status will be read and cleared last - */ - for (tm = 0, is_read = 0; tm < SPI_TIMEOUT; ++tm) { - u32 status; - - status = readl(®s->status); - - /* We can exit when we've had both RX and TX activity */ - if (is_read && (status & SPI_STAT_TXF_EMPTY)) - break; - - if ((status & (SPI_STAT_BSY | SPI_STAT_RDY)) != - SPI_STAT_RDY) - tm++; - - else if (!(status & SPI_STAT_RXF_EMPTY)) { - tmpdin = readl(®s->rx_fifo); - is_read = 1; - - /* swap bytes read in */ - if (din != NULL) { - for (i = bytes - 1; i >= 0; --i) { - din[i] = tmpdin & 0xff; - tmpdin >>= 8; - } - din += bytes; - } - } - } - - if (tm >= SPI_TIMEOUT) - ret = tm; - - /* clear ACK RDY, etc. bits */ - writel(readl(®s->status), ®s->status); - } - - if (flags & SPI_XFER_END) - spi_cs_deactivate(slave); - - debug("spi_xfer: transfer ended. Value=%08x, status = %08x\n", - tmpdin, readl(®s->status)); - - if (ret) { - printf("spi_xfer: timeout during SPI transfer, tm %d\n", ret); - return -1; - } - - return 0; -} diff --git a/include/configs/cardhu.h b/include/configs/cardhu.h index 55dc83da6a..6a99175211 100644 --- a/include/configs/cardhu.h +++ b/include/configs/cardhu.h @@ -60,7 +60,7 @@ #define CONFIG_SYS_MMC_ENV_PART 2 /* SPI */ -#define CONFIG_TEGRA_SLINK +#define CONFIG_TEGRA20_SLINK #define CONFIG_TEGRA_SLINK_CTRLS 6 #define CONFIG_SPI_FLASH #define CONFIG_SPI_FLASH_WINBOND diff --git a/include/configs/trimslice.h b/include/configs/trimslice.h index 0644f7a5b8..b92531477e 100644 --- a/include/configs/trimslice.h +++ b/include/configs/trimslice.h @@ -46,7 +46,7 @@ #define CONFIG_BOARD_EARLY_INIT_F /* SPI */ -#define CONFIG_TEGRA_SPI +#define CONFIG_TEGRA20_SFLASH #define CONFIG_SPI_FLASH #define CONFIG_SPI_FLASH_WINBOND #define CONFIG_SF_DEFAULT_MODE SPI_MODE_0 -- cgit v1.2.3 From 2a3c5bc29c621faf2f830c464cc395b3174800f1 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Sat, 16 Mar 2013 18:58:04 +0000 Subject: tegra: spi: remove non fdt support Remove non fdt support from tegra20 and tegra30 SPI drivers in preparation of new common fdt based SPI driver front end. Signed-off-by: Allen Martin Signed-off-by: Tom Warren Reviewed-by: Stephen Warren --- drivers/spi/tegra20_sflash.c | 12 ++++-------- drivers/spi/tegra20_slink.c | 29 ----------------------------- 2 files changed, 4 insertions(+), 37 deletions(-) diff --git a/drivers/spi/tegra20_sflash.c b/drivers/spi/tegra20_sflash.c index c6af30f0d6..3b1b6f8928 100644 --- a/drivers/spi/tegra20_sflash.c +++ b/drivers/spi/tegra20_sflash.c @@ -61,6 +61,7 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, unsigned int max_hz, unsigned int mode) { struct tegra_spi_slave *spi; + int node; if (!spi_cs_is_valid(bus, cs)) { printf("SPI error: unsupported bus %d / chip select %d\n", @@ -81,9 +82,9 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, } spi->slave.bus = bus; spi->slave.cs = cs; -#ifdef CONFIG_OF_CONTROL - int node = fdtdec_next_compatible(gd->fdt_blob, 0, - COMPAT_NVIDIA_TEGRA20_SFLASH); + + node = fdtdec_next_compatible(gd->fdt_blob, 0, + COMPAT_NVIDIA_TEGRA20_SFLASH); if (node < 0) { debug("%s: cannot locate sflash node\n", __func__); return NULL; @@ -108,11 +109,6 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, debug("%s: could not decode periph id\n", __func__); return NULL; } -#else - spi->regs = (struct spi_tegra *)NV_PA_SPI_BASE; - spi->freq = TEGRA_SPI_MAX_FREQ; - spi->periph_id = PERIPH_ID_SPI1; -#endif if (max_hz < spi->freq) { debug("%s: limiting frequency from %u to %u\n", __func__, spi->freq, max_hz); diff --git a/drivers/spi/tegra20_slink.c b/drivers/spi/tegra20_slink.c index a6de4cec69..c794054f07 100644 --- a/drivers/spi/tegra20_slink.c +++ b/drivers/spi/tegra20_slink.c @@ -116,7 +116,6 @@ void spi_init(void) { struct tegra_spi_ctrl *ctrl; int i; -#ifdef CONFIG_OF_CONTROL int node = 0; int count; int node_list[CONFIG_TEGRA_SLINK_CTRLS]; @@ -152,34 +151,6 @@ void spi_init(void) debug("%s: found controller at %p, freq = %u, periph_id = %d\n", __func__, ctrl->regs, ctrl->freq, ctrl->periph_id); } -#else - for (i = 0; i < CONFIG_TEGRA_SLINK_CTRLS; i++) { - ctrl = &spi_ctrls[i]; - u32 base_regs[] = { - NV_PA_SLINK1_BASE, - NV_PA_SLINK2_BASE, - NV_PA_SLINK3_BASE, - NV_PA_SLINK4_BASE, - NV_PA_SLINK5_BASE, - NV_PA_SLINK6_BASE, - }; - int periph_ids[] = { - PERIPH_ID_SBC1, - PERIPH_ID_SBC2, - PERIPH_ID_SBC3, - PERIPH_ID_SBC4, - PERIPH_ID_SBC5, - PERIPH_ID_SBC6, - }; - ctrl->regs = (struct slink_tegra *)base_regs[i]; - ctrl->freq = TEGRA_SPI_MAX_FREQ; - ctrl->periph_id = periph_ids[i]; - ctrl->valid = 1; - - debug("%s: found controller at %p, freq = %u, periph_id = %d\n", - __func__, ctrl->regs, ctrl->freq, ctrl->periph_id); - } -#endif } int spi_claim_bus(struct spi_slave *slave) -- cgit v1.2.3 From 7a49ba6e5b81713c5c8f8275a7ecd1036ca583d4 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Sat, 16 Mar 2013 18:58:05 +0000 Subject: tegra: spi: pull register structs out of headers Move register structs from headers into .c files and use common name. This is in preparation of making common fdt front end for SPI drivers. Signed-off-by: Allen Martin Signed-off-by: Tom Warren Reviewed-by: Stephen Warren --- arch/arm/include/asm/arch-tegra20/tegra20_sflash.h | 45 -------------- arch/arm/include/asm/arch-tegra20/tegra20_slink.h | 54 ----------------- drivers/spi/tegra20_sflash.c | 53 +++++++++++++++-- drivers/spi/tegra20_slink.c | 68 +++++++++++++++++++--- 4 files changed, 110 insertions(+), 110 deletions(-) diff --git a/arch/arm/include/asm/arch-tegra20/tegra20_sflash.h b/arch/arm/include/asm/arch-tegra20/tegra20_sflash.h index 26a8402512..28775db2a9 100644 --- a/arch/arm/include/asm/arch-tegra20/tegra20_sflash.h +++ b/arch/arm/include/asm/arch-tegra20/tegra20_sflash.h @@ -27,49 +27,4 @@ #include -struct spi_tegra { - u32 command; /* SPI_COMMAND_0 register */ - u32 status; /* SPI_STATUS_0 register */ - u32 rx_cmp; /* SPI_RX_CMP_0 register */ - u32 dma_ctl; /* SPI_DMA_CTL_0 register */ - u32 tx_fifo; /* SPI_TX_FIFO_0 register */ - u32 rsvd[3]; /* offsets 0x14 to 0x1F reserved */ - u32 rx_fifo; /* SPI_RX_FIFO_0 register */ -}; - -#define SPI_CMD_GO (1 << 30) -#define SPI_CMD_ACTIVE_SCLK_SHIFT 26 -#define SPI_CMD_ACTIVE_SCLK_MASK (3 << SPI_CMD_ACTIVE_SCLK_SHIFT) -#define SPI_CMD_CK_SDA (1 << 21) -#define SPI_CMD_ACTIVE_SDA_SHIFT 18 -#define SPI_CMD_ACTIVE_SDA_MASK (3 << SPI_CMD_ACTIVE_SDA_SHIFT) -#define SPI_CMD_CS_POL (1 << 16) -#define SPI_CMD_TXEN (1 << 15) -#define SPI_CMD_RXEN (1 << 14) -#define SPI_CMD_CS_VAL (1 << 13) -#define SPI_CMD_CS_SOFT (1 << 12) -#define SPI_CMD_CS_DELAY (1 << 9) -#define SPI_CMD_CS3_EN (1 << 8) -#define SPI_CMD_CS2_EN (1 << 7) -#define SPI_CMD_CS1_EN (1 << 6) -#define SPI_CMD_CS0_EN (1 << 5) -#define SPI_CMD_BIT_LENGTH (1 << 4) -#define SPI_CMD_BIT_LENGTH_MASK 0x0000001F - -#define SPI_STAT_BSY (1 << 31) -#define SPI_STAT_RDY (1 << 30) -#define SPI_STAT_RXF_FLUSH (1 << 29) -#define SPI_STAT_TXF_FLUSH (1 << 28) -#define SPI_STAT_RXF_UNR (1 << 27) -#define SPI_STAT_TXF_OVF (1 << 26) -#define SPI_STAT_RXF_EMPTY (1 << 25) -#define SPI_STAT_RXF_FULL (1 << 24) -#define SPI_STAT_TXF_EMPTY (1 << 23) -#define SPI_STAT_TXF_FULL (1 << 22) -#define SPI_STAT_SEL_TXRX_N (1 << 16) -#define SPI_STAT_CUR_BLKCNT (1 << 15) - -#define SPI_TIMEOUT 1000 -#define TEGRA_SPI_MAX_FREQ 52000000 - #endif /* _TEGRA20_SPI_H_ */ diff --git a/arch/arm/include/asm/arch-tegra20/tegra20_slink.h b/arch/arm/include/asm/arch-tegra20/tegra20_slink.h index afa9b36923..fe8b5347f8 100644 --- a/arch/arm/include/asm/arch-tegra20/tegra20_slink.h +++ b/arch/arm/include/asm/arch-tegra20/tegra20_slink.h @@ -27,58 +27,4 @@ #include -struct slink_tegra { - u32 command; /* SLINK_COMMAND_0 register */ - u32 command2; /* SLINK_COMMAND2_0 reg */ - u32 status; /* SLINK_STATUS_0 register */ - u32 reserved; /* Reserved offset 0C */ - u32 mas_data; /* SLINK_MAS_DATA_0 reg */ - u32 slav_data; /* SLINK_SLAVE_DATA_0 reg */ - u32 dma_ctl; /* SLINK_DMA_CTL_0 register */ - u32 status2; /* SLINK_STATUS2_0 reg */ - u32 rsvd[56]; /* 0x20 to 0xFF reserved */ - u32 tx_fifo; /* SLINK_TX_FIFO_0 reg off 100h */ - u32 rsvd2[31]; /* 0x104 to 0x17F reserved */ - u32 rx_fifo; /* SLINK_RX_FIFO_0 reg off 180h */ -}; - -/* COMMAND */ -#define SLINK_CMD_ENB (1 << 31) -#define SLINK_CMD_GO (1 << 30) -#define SLINK_CMD_M_S (1 << 28) -#define SLINK_CMD_CK_SDA (1 << 21) -#define SLINK_CMD_CS_POL (1 << 13) -#define SLINK_CMD_CS_VAL (1 << 12) -#define SLINK_CMD_CS_SOFT (1 << 11) -#define SLINK_CMD_BIT_LENGTH (1 << 4) -#define SLINK_CMD_BIT_LENGTH_MASK 0x0000001F -/* COMMAND2 */ -#define SLINK_CMD2_TXEN (1 << 30) -#define SLINK_CMD2_RXEN (1 << 31) -#define SLINK_CMD2_SS_EN (1 << 18) -#define SLINK_CMD2_SS_EN_SHIFT 18 -#define SLINK_CMD2_SS_EN_MASK 0x000C0000 -#define SLINK_CMD2_CS_ACTIVE_BETWEEN (1 << 17) -/* STATUS */ -#define SLINK_STAT_BSY (1 << 31) -#define SLINK_STAT_RDY (1 << 30) -#define SLINK_STAT_ERR (1 << 29) -#define SLINK_STAT_RXF_FLUSH (1 << 27) -#define SLINK_STAT_TXF_FLUSH (1 << 26) -#define SLINK_STAT_RXF_OVF (1 << 25) -#define SLINK_STAT_TXF_UNR (1 << 24) -#define SLINK_STAT_RXF_EMPTY (1 << 23) -#define SLINK_STAT_RXF_FULL (1 << 22) -#define SLINK_STAT_TXF_EMPTY (1 << 21) -#define SLINK_STAT_TXF_FULL (1 << 20) -#define SLINK_STAT_TXF_OVF (1 << 19) -#define SLINK_STAT_RXF_UNR (1 << 18) -#define SLINK_STAT_CUR_BLKCNT (1 << 15) -/* STATUS2 */ -#define SLINK_STAT2_RXF_FULL_CNT (1 << 16) -#define SLINK_STAT2_TXF_FULL_CNT (1 << 0) - -#define SPI_TIMEOUT 1000 -#define TEGRA_SPI_MAX_FREQ 52000000 - #endif /* _TEGRA30_SPI_H_ */ diff --git a/drivers/spi/tegra20_sflash.c b/drivers/spi/tegra20_sflash.c index 3b1b6f8928..6e72c8ee5e 100644 --- a/drivers/spi/tegra20_sflash.c +++ b/drivers/spi/tegra20_sflash.c @@ -35,9 +35,54 @@ DECLARE_GLOBAL_DATA_PTR; +#define SPI_CMD_GO (1 << 30) +#define SPI_CMD_ACTIVE_SCLK_SHIFT 26 +#define SPI_CMD_ACTIVE_SCLK_MASK (3 << SPI_CMD_ACTIVE_SCLK_SHIFT) +#define SPI_CMD_CK_SDA (1 << 21) +#define SPI_CMD_ACTIVE_SDA_SHIFT 18 +#define SPI_CMD_ACTIVE_SDA_MASK (3 << SPI_CMD_ACTIVE_SDA_SHIFT) +#define SPI_CMD_CS_POL (1 << 16) +#define SPI_CMD_TXEN (1 << 15) +#define SPI_CMD_RXEN (1 << 14) +#define SPI_CMD_CS_VAL (1 << 13) +#define SPI_CMD_CS_SOFT (1 << 12) +#define SPI_CMD_CS_DELAY (1 << 9) +#define SPI_CMD_CS3_EN (1 << 8) +#define SPI_CMD_CS2_EN (1 << 7) +#define SPI_CMD_CS1_EN (1 << 6) +#define SPI_CMD_CS0_EN (1 << 5) +#define SPI_CMD_BIT_LENGTH (1 << 4) +#define SPI_CMD_BIT_LENGTH_MASK 0x0000001F + +#define SPI_STAT_BSY (1 << 31) +#define SPI_STAT_RDY (1 << 30) +#define SPI_STAT_RXF_FLUSH (1 << 29) +#define SPI_STAT_TXF_FLUSH (1 << 28) +#define SPI_STAT_RXF_UNR (1 << 27) +#define SPI_STAT_TXF_OVF (1 << 26) +#define SPI_STAT_RXF_EMPTY (1 << 25) +#define SPI_STAT_RXF_FULL (1 << 24) +#define SPI_STAT_TXF_EMPTY (1 << 23) +#define SPI_STAT_TXF_FULL (1 << 22) +#define SPI_STAT_SEL_TXRX_N (1 << 16) +#define SPI_STAT_CUR_BLKCNT (1 << 15) + +#define SPI_TIMEOUT 1000 +#define TEGRA_SPI_MAX_FREQ 52000000 + +struct spi_regs { + u32 command; /* SPI_COMMAND_0 register */ + u32 status; /* SPI_STATUS_0 register */ + u32 rx_cmp; /* SPI_RX_CMP_0 register */ + u32 dma_ctl; /* SPI_DMA_CTL_0 register */ + u32 tx_fifo; /* SPI_TX_FIFO_0 register */ + u32 rsvd[3]; /* offsets 0x14 to 0x1F reserved */ + u32 rx_fifo; /* SPI_RX_FIFO_0 register */ +}; + struct tegra_spi_slave { struct spi_slave slave; - struct spi_tegra *regs; + struct spi_regs *regs; unsigned int freq; unsigned int mode; int periph_id; @@ -93,7 +138,7 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, debug("%s: sflash is disabled\n", __func__); return NULL; } - spi->regs = (struct spi_tegra *)fdtdec_get_addr(gd->fdt_blob, + spi->regs = (struct spi_regs *)fdtdec_get_addr(gd->fdt_blob, node, "reg"); if ((fdt_addr_t)spi->regs == FDT_ADDR_T_NONE) { debug("%s: no sflash register found\n", __func__); @@ -136,7 +181,7 @@ void spi_init(void) int spi_claim_bus(struct spi_slave *slave) { struct tegra_spi_slave *spi = to_tegra_spi(slave); - struct spi_tegra *regs = spi->regs; + struct spi_regs *regs = spi->regs; u32 reg; /* Change SPI clock to correct frequency, PLLP_OUT0 source */ @@ -199,7 +244,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *data_out, void *data_in, unsigned long flags) { struct tegra_spi_slave *spi = to_tegra_spi(slave); - struct spi_tegra *regs = spi->regs; + struct spi_regs *regs = spi->regs; u32 reg, tmpdout, tmpdin = 0; const u8 *dout = data_out; u8 *din = data_in; diff --git a/drivers/spi/tegra20_slink.c b/drivers/spi/tegra20_slink.c index c794054f07..f3b0964488 100644 --- a/drivers/spi/tegra20_slink.c +++ b/drivers/spi/tegra20_slink.c @@ -33,8 +33,62 @@ DECLARE_GLOBAL_DATA_PTR; +/* COMMAND */ +#define SLINK_CMD_ENB (1 << 31) +#define SLINK_CMD_GO (1 << 30) +#define SLINK_CMD_M_S (1 << 28) +#define SLINK_CMD_CK_SDA (1 << 21) +#define SLINK_CMD_CS_POL (1 << 13) +#define SLINK_CMD_CS_VAL (1 << 12) +#define SLINK_CMD_CS_SOFT (1 << 11) +#define SLINK_CMD_BIT_LENGTH (1 << 4) +#define SLINK_CMD_BIT_LENGTH_MASK 0x0000001F +/* COMMAND2 */ +#define SLINK_CMD2_TXEN (1 << 30) +#define SLINK_CMD2_RXEN (1 << 31) +#define SLINK_CMD2_SS_EN (1 << 18) +#define SLINK_CMD2_SS_EN_SHIFT 18 +#define SLINK_CMD2_SS_EN_MASK 0x000C0000 +#define SLINK_CMD2_CS_ACTIVE_BETWEEN (1 << 17) +/* STATUS */ +#define SLINK_STAT_BSY (1 << 31) +#define SLINK_STAT_RDY (1 << 30) +#define SLINK_STAT_ERR (1 << 29) +#define SLINK_STAT_RXF_FLUSH (1 << 27) +#define SLINK_STAT_TXF_FLUSH (1 << 26) +#define SLINK_STAT_RXF_OVF (1 << 25) +#define SLINK_STAT_TXF_UNR (1 << 24) +#define SLINK_STAT_RXF_EMPTY (1 << 23) +#define SLINK_STAT_RXF_FULL (1 << 22) +#define SLINK_STAT_TXF_EMPTY (1 << 21) +#define SLINK_STAT_TXF_FULL (1 << 20) +#define SLINK_STAT_TXF_OVF (1 << 19) +#define SLINK_STAT_RXF_UNR (1 << 18) +#define SLINK_STAT_CUR_BLKCNT (1 << 15) +/* STATUS2 */ +#define SLINK_STAT2_RXF_FULL_CNT (1 << 16) +#define SLINK_STAT2_TXF_FULL_CNT (1 << 0) + +#define SPI_TIMEOUT 1000 +#define TEGRA_SPI_MAX_FREQ 52000000 + +struct spi_regs { + u32 command; /* SLINK_COMMAND_0 register */ + u32 command2; /* SLINK_COMMAND2_0 reg */ + u32 status; /* SLINK_STATUS_0 register */ + u32 reserved; /* Reserved offset 0C */ + u32 mas_data; /* SLINK_MAS_DATA_0 reg */ + u32 slav_data; /* SLINK_SLAVE_DATA_0 reg */ + u32 dma_ctl; /* SLINK_DMA_CTL_0 register */ + u32 status2; /* SLINK_STATUS2_0 reg */ + u32 rsvd[56]; /* 0x20 to 0xFF reserved */ + u32 tx_fifo; /* SLINK_TX_FIFO_0 reg off 100h */ + u32 rsvd2[31]; /* 0x104 to 0x17F reserved */ + u32 rx_fifo; /* SLINK_RX_FIFO_0 reg off 180h */ +}; + struct tegra_spi_ctrl { - struct slink_tegra *regs; + struct spi_regs *regs; unsigned int freq; unsigned int mode; int periph_id; @@ -128,8 +182,8 @@ void spi_init(void) ctrl = &spi_ctrls[i]; node = node_list[i]; - ctrl->regs = (struct slink_tegra *)fdtdec_get_addr(gd->fdt_blob, - node, "reg"); + ctrl->regs = (struct spi_regs *)fdtdec_get_addr(gd->fdt_blob, + node, "reg"); if ((fdt_addr_t)ctrl->regs == FDT_ADDR_T_NONE) { debug("%s: no slink register found\n", __func__); continue; @@ -156,7 +210,7 @@ void spi_init(void) int spi_claim_bus(struct spi_slave *slave) { struct tegra_spi_slave *spi = to_tegra_spi(slave); - struct slink_tegra *regs = spi->ctrl->regs; + struct spi_regs *regs = spi->ctrl->regs; u32 reg; /* Change SPI clock to correct frequency, PLLP_OUT0 source */ @@ -185,7 +239,7 @@ void spi_release_bus(struct spi_slave *slave) void spi_cs_activate(struct spi_slave *slave) { struct tegra_spi_slave *spi = to_tegra_spi(slave); - struct slink_tegra *regs = spi->ctrl->regs; + struct spi_regs *regs = spi->ctrl->regs; /* CS is negated on Tegra, so drive a 1 to get a 0 */ setbits_le32(®s->command, SLINK_CMD_CS_VAL); @@ -194,7 +248,7 @@ void spi_cs_activate(struct spi_slave *slave) void spi_cs_deactivate(struct spi_slave *slave) { struct tegra_spi_slave *spi = to_tegra_spi(slave); - struct slink_tegra *regs = spi->ctrl->regs; + struct spi_regs *regs = spi->ctrl->regs; /* CS is negated on Tegra, so drive a 0 to get a 1 */ clrbits_le32(®s->command, SLINK_CMD_CS_VAL); @@ -204,7 +258,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *data_out, void *data_in, unsigned long flags) { struct tegra_spi_slave *spi = to_tegra_spi(slave); - struct slink_tegra *regs = spi->ctrl->regs; + struct spi_regs *regs = spi->ctrl->regs; u32 reg, tmpdout, tmpdin = 0; const u8 *dout = data_out; u8 *din = data_in; -- cgit v1.2.3 From 6b3a03e112cecda55b58f3de40f4fc760159979b Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Sat, 16 Mar 2013 18:58:06 +0000 Subject: tegra20: spi: move fdt probe to spi_init Make the tegra20 SPI driver similar to the tegra30 (and soon to be tegra114) SPI drivers in preparation of common fdt SPI driver front end. Signed-off-by: Allen Martin Signed-off-by: Tom Warren Reviewed-by: Stephen Warren --- drivers/spi/tegra20_sflash.c | 110 ++++++++++++++++++++++++++----------------- 1 file changed, 67 insertions(+), 43 deletions(-) diff --git a/drivers/spi/tegra20_sflash.c b/drivers/spi/tegra20_sflash.c index 6e72c8ee5e..bb1e57d5e8 100644 --- a/drivers/spi/tegra20_sflash.c +++ b/drivers/spi/tegra20_sflash.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2012 NVIDIA Corporation + * Copyright (c) 2010-2013 NVIDIA Corporation * With help from the mpc8xxx SPI driver * With more help from omap3_spi SPI driver * @@ -80,14 +80,22 @@ struct spi_regs { u32 rx_fifo; /* SPI_RX_FIFO_0 register */ }; -struct tegra_spi_slave { - struct spi_slave slave; +struct tegra_spi_ctrl { struct spi_regs *regs; unsigned int freq; unsigned int mode; int periph_id; + int valid; +}; + +struct tegra_spi_slave { + struct spi_slave slave; + struct tegra_spi_ctrl *ctrl; }; +/* tegra20 only supports one SFLASH controller */ +static struct tegra_spi_ctrl spi_ctrls[1]; + static inline struct tegra_spi_slave *to_tegra_spi(struct spi_slave *slave) { return container_of(slave, struct tegra_spi_slave, slave); @@ -106,7 +114,6 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, unsigned int max_hz, unsigned int mode) { struct tegra_spi_slave *spi; - int node; if (!spi_cs_is_valid(bus, cs)) { printf("SPI error: unsupported bus %d / chip select %d\n", @@ -127,41 +134,19 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, } spi->slave.bus = bus; spi->slave.cs = cs; - - node = fdtdec_next_compatible(gd->fdt_blob, 0, - COMPAT_NVIDIA_TEGRA20_SFLASH); - if (node < 0) { - debug("%s: cannot locate sflash node\n", __func__); - return NULL; - } - if (!fdtdec_get_is_enabled(gd->fdt_blob, node)) { - debug("%s: sflash is disabled\n", __func__); - return NULL; - } - spi->regs = (struct spi_regs *)fdtdec_get_addr(gd->fdt_blob, - node, "reg"); - if ((fdt_addr_t)spi->regs == FDT_ADDR_T_NONE) { - debug("%s: no sflash register found\n", __func__); + spi->ctrl = &spi_ctrls[bus]; + if (!spi->ctrl) { + printf("SPI error: could not find controller for bus %d\n", + bus); return NULL; } - spi->freq = fdtdec_get_int(gd->fdt_blob, node, "spi-max-frequency", 0); - if (!spi->freq) { - debug("%s: no sflash max frequency found\n", __func__); - return NULL; - } - spi->periph_id = clock_decode_periph_id(gd->fdt_blob, node); - if (spi->periph_id == PERIPH_ID_NONE) { - debug("%s: could not decode periph id\n", __func__); - return NULL; - } - if (max_hz < spi->freq) { + + if (max_hz < spi->ctrl->freq) { debug("%s: limiting frequency from %u to %u\n", __func__, - spi->freq, max_hz); - spi->freq = max_hz; + spi->ctrl->freq, max_hz); + spi->ctrl->freq = max_hz; } - debug("%s: controller initialized at %p, freq = %u, periph_id = %d\n", - __func__, spi->regs, spi->freq, spi->periph_id); - spi->mode = mode; + spi->ctrl->mode = mode; return &spi->slave; } @@ -175,17 +160,54 @@ void spi_free_slave(struct spi_slave *slave) void spi_init(void) { - /* do nothing */ + struct tegra_spi_ctrl *ctrl; + int i; + int node = 0; + int count; + int node_list[1]; + + count = fdtdec_find_aliases_for_id(gd->fdt_blob, "spi", + COMPAT_NVIDIA_TEGRA20_SFLASH, + node_list, + 1); + for (i = 0; i < count; i++) { + ctrl = &spi_ctrls[i]; + node = node_list[i]; + + ctrl->regs = (struct spi_regs *)fdtdec_get_addr(gd->fdt_blob, + node, "reg"); + if ((fdt_addr_t)ctrl->regs == FDT_ADDR_T_NONE) { + debug("%s: no slink register found\n", __func__); + continue; + } + ctrl->freq = fdtdec_get_int(gd->fdt_blob, node, + "spi-max-frequency", 0); + if (!ctrl->freq) { + debug("%s: no slink max frequency found\n", __func__); + continue; + } + + ctrl->periph_id = clock_decode_periph_id(gd->fdt_blob, node); + if (ctrl->periph_id == PERIPH_ID_NONE) { + debug("%s: could not decode periph id\n", __func__); + continue; + } + ctrl->valid = 1; + + debug("%s: found controller at %p, freq = %u, periph_id = %d\n", + __func__, ctrl->regs, ctrl->freq, ctrl->periph_id); + } } int spi_claim_bus(struct spi_slave *slave) { struct tegra_spi_slave *spi = to_tegra_spi(slave); - struct spi_regs *regs = spi->regs; + struct spi_regs *regs = spi->ctrl->regs; u32 reg; /* Change SPI clock to correct frequency, PLLP_OUT0 source */ - clock_start_periph_pll(spi->periph_id, CLOCK_ID_PERIPH, spi->freq); + clock_start_periph_pll(spi->ctrl->periph_id, CLOCK_ID_PERIPH, + spi->ctrl->freq); /* Clear stale status here */ reg = SPI_STAT_RDY | SPI_STAT_RXF_FLUSH | SPI_STAT_TXF_FLUSH | \ @@ -196,8 +218,8 @@ int spi_claim_bus(struct spi_slave *slave) /* * Use sw-controlled CS, so we can clock in data after ReadID, etc. */ - reg = (spi->mode & 1) << SPI_CMD_ACTIVE_SDA_SHIFT; - if (spi->mode & 2) + reg = (spi->ctrl->mode & 1) << SPI_CMD_ACTIVE_SDA_SHIFT; + if (spi->ctrl->mode & 2) reg |= 1 << SPI_CMD_ACTIVE_SCLK_SHIFT; clrsetbits_le32(®s->command, SPI_CMD_ACTIVE_SCLK_MASK | SPI_CMD_ACTIVE_SDA_MASK, SPI_CMD_CS_SOFT | reg); @@ -227,24 +249,26 @@ void spi_release_bus(struct spi_slave *slave) void spi_cs_activate(struct spi_slave *slave) { struct tegra_spi_slave *spi = to_tegra_spi(slave); + struct spi_regs *regs = spi->ctrl->regs; /* CS is negated on Tegra, so drive a 1 to get a 0 */ - setbits_le32(&spi->regs->command, SPI_CMD_CS_VAL); + setbits_le32(®s->command, SPI_CMD_CS_VAL); } void spi_cs_deactivate(struct spi_slave *slave) { struct tegra_spi_slave *spi = to_tegra_spi(slave); + struct spi_regs *regs = spi->ctrl->regs; /* CS is negated on Tegra, so drive a 0 to get a 1 */ - clrbits_le32(&spi->regs->command, SPI_CMD_CS_VAL); + clrbits_le32(®s->command, SPI_CMD_CS_VAL); } int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *data_out, void *data_in, unsigned long flags) { struct tegra_spi_slave *spi = to_tegra_spi(slave); - struct spi_regs *regs = spi->regs; + struct spi_regs *regs = spi->ctrl->regs; u32 reg, tmpdout, tmpdin = 0; const u8 *dout = data_out; u8 *din = data_in; -- cgit v1.2.3 From 78f47b7353ebe1f243203dcc1ce0a2a374c08a40 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Sat, 16 Mar 2013 18:58:07 +0000 Subject: spi: add common fdt SPI driver interface Add a common interface to fdt based SPI drivers. Each driver is represented by a table entry in fdt_spi_drivers[]. If there are multiple SPI drivers in the table, the first driver to return success from spi_init() will be registered as the SPI driver. Signed-off-by: Allen Martin Signed-off-by: Tom Warren Reviewed-by: Stephen Warren --- arch/arm/include/asm/arch-tegra20/tegra20_sflash.h | 11 ++ arch/arm/include/asm/arch-tegra20/tegra20_slink.h | 11 ++ board/nvidia/common/board.c | 2 +- drivers/spi/Makefile | 1 + drivers/spi/fdt_spi.c | 171 +++++++++++++++++++++ drivers/spi/tegra20_sflash.c | 41 ++--- drivers/spi/tegra20_slink.c | 29 ++-- include/configs/tegra-common-post.h | 4 + 8 files changed, 224 insertions(+), 46 deletions(-) create mode 100644 drivers/spi/fdt_spi.c diff --git a/arch/arm/include/asm/arch-tegra20/tegra20_sflash.h b/arch/arm/include/asm/arch-tegra20/tegra20_sflash.h index 28775db2a9..e8cc68c6ea 100644 --- a/arch/arm/include/asm/arch-tegra20/tegra20_sflash.h +++ b/arch/arm/include/asm/arch-tegra20/tegra20_sflash.h @@ -27,4 +27,15 @@ #include +int tegra20_spi_cs_is_valid(unsigned int bus, unsigned int cs); +struct spi_slave *tegra20_spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode); +void tegra20_spi_free_slave(struct spi_slave *slave); +int tegra20_spi_init(int *node_list, int count); +int tegra20_spi_claim_bus(struct spi_slave *slave); +void tegra20_spi_cs_activate(struct spi_slave *slave); +void tegra20_spi_cs_deactivate(struct spi_slave *slave); +int tegra20_spi_xfer(struct spi_slave *slave, unsigned int bitlen, + const void *data_out, void *data_in, unsigned long flags); + #endif /* _TEGRA20_SPI_H_ */ diff --git a/arch/arm/include/asm/arch-tegra20/tegra20_slink.h b/arch/arm/include/asm/arch-tegra20/tegra20_slink.h index fe8b5347f8..5aa74ddd6d 100644 --- a/arch/arm/include/asm/arch-tegra20/tegra20_slink.h +++ b/arch/arm/include/asm/arch-tegra20/tegra20_slink.h @@ -27,4 +27,15 @@ #include +int tegra30_spi_init(int *node_list, int count); +int tegra30_spi_cs_is_valid(unsigned int bus, unsigned int cs); +struct spi_slave *tegra30_spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode); +void tegra30_spi_free_slave(struct spi_slave *slave); +int tegra30_spi_claim_bus(struct spi_slave *slave); +void tegra30_spi_cs_activate(struct spi_slave *slave); +void tegra30_spi_cs_deactivate(struct spi_slave *slave); +int tegra30_spi_xfer(struct spi_slave *slave, unsigned int bitlen, + const void *data_out, void *data_in, unsigned long flags); + #endif /* _TEGRA30_SPI_H_ */ diff --git a/board/nvidia/common/board.c b/board/nvidia/common/board.c index 87a418bc6a..8d7a22765a 100644 --- a/board/nvidia/common/board.c +++ b/board/nvidia/common/board.c @@ -132,7 +132,7 @@ int board_init(void) clock_init(); clock_verify(); -#if defined(CONFIG_TEGRA20_SFLASH) || defined(CONFIG_TEGRA20_SLINK) +#ifdef CONFIG_FDT_SPI pin_mux_spi(); spi_init(); #endif diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 78e3d3d568..3762d59dd0 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -46,6 +46,7 @@ COBJS-$(CONFIG_OMAP3_SPI) += omap3_spi.o COBJS-$(CONFIG_SOFT_SPI) += soft_spi.o COBJS-$(CONFIG_SH_SPI) += sh_spi.o COBJS-$(CONFIG_FSL_ESPI) += fsl_espi.o +COBJS-$(CONFIG_FDT_SPI) += fdt_spi.o COBJS-$(CONFIG_TEGRA20_SFLASH) += tegra20_sflash.o COBJS-$(CONFIG_TEGRA20_SLINK) += tegra20_slink.o COBJS-$(CONFIG_XILINX_SPI) += xilinx_spi.o diff --git a/drivers/spi/fdt_spi.c b/drivers/spi/fdt_spi.c new file mode 100644 index 0000000000..c6ae719d63 --- /dev/null +++ b/drivers/spi/fdt_spi.c @@ -0,0 +1,171 @@ +/* + * Common fdt based SPI driver front end + * + * Copyright (c) 2013 NVIDIA Corporation + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +struct fdt_spi_driver { + int compat; + int max_ctrls; + int (*init)(int *node_list, int count); + int (*claim_bus)(struct spi_slave *slave); + int (*release_bus)(struct spi_slave *slave); + int (*cs_is_valid)(unsigned int bus, unsigned int cs); + struct spi_slave *(*setup_slave)(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode); + void (*free_slave)(struct spi_slave *slave); + void (*cs_activate)(struct spi_slave *slave); + void (*cs_deactivate)(struct spi_slave *slave); + int (*xfer)(struct spi_slave *slave, unsigned int bitlen, + const void *data_out, void *data_in, unsigned long flags); +}; + +static struct fdt_spi_driver fdt_spi_drivers[] = { +#ifdef CONFIG_TEGRA20_SFLASH + { + .compat = COMPAT_NVIDIA_TEGRA20_SFLASH, + .max_ctrls = 1, + .init = tegra20_spi_init, + .claim_bus = tegra20_spi_claim_bus, + .cs_is_valid = tegra20_spi_cs_is_valid, + .setup_slave = tegra20_spi_setup_slave, + .free_slave = tegra20_spi_free_slave, + .cs_activate = tegra20_spi_cs_activate, + .cs_deactivate = tegra20_spi_cs_deactivate, + .xfer = tegra20_spi_xfer, + }, +#endif +#ifdef CONFIG_TEGRA20_SLINK + { + .compat = COMPAT_NVIDIA_TEGRA20_SLINK, + .max_ctrls = CONFIG_TEGRA_SLINK_CTRLS, + .init = tegra30_spi_init, + .claim_bus = tegra30_spi_claim_bus, + .cs_is_valid = tegra30_spi_cs_is_valid, + .setup_slave = tegra30_spi_setup_slave, + .free_slave = tegra30_spi_free_slave, + .cs_activate = tegra30_spi_cs_activate, + .cs_deactivate = tegra30_spi_cs_deactivate, + .xfer = tegra30_spi_xfer, + }, +#endif +}; + +static struct fdt_spi_driver *driver; + +int spi_cs_is_valid(unsigned int bus, unsigned int cs) +{ + if (!driver) + return 0; + else if (!driver->cs_is_valid) + return 1; + else + return driver->cs_is_valid(bus, cs); +} + +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + if (!driver || !driver->setup_slave) + return NULL; + + return driver->setup_slave(bus, cs, max_hz, mode); +} + +void spi_free_slave(struct spi_slave *slave) +{ + if (driver && driver->free_slave) + return driver->free_slave(slave); +} + +static int spi_init_driver(struct fdt_spi_driver *driver) +{ + int count; + int node_list[driver->max_ctrls]; + + count = fdtdec_find_aliases_for_id(gd->fdt_blob, "spi", + driver->compat, + node_list, + driver->max_ctrls); + return driver->init(node_list, count); +} + +void spi_init(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(fdt_spi_drivers); i++) { + driver = &fdt_spi_drivers[i]; + if (!spi_init_driver(driver)) + break; + } + if (i == ARRAY_SIZE(fdt_spi_drivers)) + driver = NULL; +} + +int spi_claim_bus(struct spi_slave *slave) +{ + if (!driver) + return 1; + if (!driver->claim_bus) + return 0; + + return driver->claim_bus(slave); +} + +void spi_release_bus(struct spi_slave *slave) +{ + if (driver && driver->release_bus) + driver->release_bus(slave); +} + +void spi_cs_activate(struct spi_slave *slave) +{ + if (driver && driver->cs_activate) + driver->cs_activate(slave); +} + +void spi_cs_deactivate(struct spi_slave *slave) +{ + if (driver && driver->cs_deactivate) + driver->cs_deactivate(slave); +} + +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, + const void *data_out, void *data_in, unsigned long flags) +{ + if (!driver || !driver->xfer) + return -1; + + return driver->xfer(slave, bitlen, data_out, data_in, flags); +} diff --git a/drivers/spi/tegra20_sflash.c b/drivers/spi/tegra20_sflash.c index bb1e57d5e8..a4e6c9aa3f 100644 --- a/drivers/spi/tegra20_sflash.c +++ b/drivers/spi/tegra20_sflash.c @@ -101,7 +101,7 @@ static inline struct tegra_spi_slave *to_tegra_spi(struct spi_slave *slave) return container_of(slave, struct tegra_spi_slave, slave); } -int spi_cs_is_valid(unsigned int bus, unsigned int cs) +int tegra20_spi_cs_is_valid(unsigned int bus, unsigned int cs) { /* Tegra20 SPI-Flash - only 1 device ('bus/cs') */ if (bus != 0 || cs != 0) @@ -110,8 +110,8 @@ int spi_cs_is_valid(unsigned int bus, unsigned int cs) return 1; } -struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, - unsigned int max_hz, unsigned int mode) +struct spi_slave *tegra20_spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) { struct tegra_spi_slave *spi; @@ -151,25 +151,20 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, return &spi->slave; } -void spi_free_slave(struct spi_slave *slave) +void tegra20_spi_free_slave(struct spi_slave *slave) { struct tegra_spi_slave *spi = to_tegra_spi(slave); free(spi); } -void spi_init(void) +int tegra20_spi_init(int *node_list, int count) { struct tegra_spi_ctrl *ctrl; int i; int node = 0; - int count; - int node_list[1]; + int found = 0; - count = fdtdec_find_aliases_for_id(gd->fdt_blob, "spi", - COMPAT_NVIDIA_TEGRA20_SFLASH, - node_list, - 1); for (i = 0; i < count; i++) { ctrl = &spi_ctrls[i]; node = node_list[i]; @@ -193,13 +188,15 @@ void spi_init(void) continue; } ctrl->valid = 1; + found = 1; debug("%s: found controller at %p, freq = %u, periph_id = %d\n", __func__, ctrl->regs, ctrl->freq, ctrl->periph_id); } + return !found; } -int spi_claim_bus(struct spi_slave *slave) +int tegra20_spi_claim_bus(struct spi_slave *slave) { struct tegra_spi_slave *spi = to_tegra_spi(slave); struct spi_regs *regs = spi->ctrl->regs; @@ -213,7 +210,7 @@ int spi_claim_bus(struct spi_slave *slave) reg = SPI_STAT_RDY | SPI_STAT_RXF_FLUSH | SPI_STAT_TXF_FLUSH | \ SPI_STAT_RXF_UNR | SPI_STAT_TXF_OVF; writel(reg, ®s->status); - debug("spi_init: STATUS = %08x\n", readl(®s->status)); + debug("%s: STATUS = %08x\n", __func__, readl(®s->status)); /* * Use sw-controlled CS, so we can clock in data after ReadID, etc. @@ -223,7 +220,7 @@ int spi_claim_bus(struct spi_slave *slave) reg |= 1 << SPI_CMD_ACTIVE_SCLK_SHIFT; clrsetbits_le32(®s->command, SPI_CMD_ACTIVE_SCLK_MASK | SPI_CMD_ACTIVE_SDA_MASK, SPI_CMD_CS_SOFT | reg); - debug("spi_init: COMMAND = %08x\n", readl(®s->command)); + debug("%s: COMMAND = %08x\n", __func__, readl(®s->command)); /* * SPI pins on Tegra20 are muxed - change pinmux later due to UART @@ -236,17 +233,7 @@ int spi_claim_bus(struct spi_slave *slave) return 0; } -void spi_release_bus(struct spi_slave *slave) -{ - /* - * We can't release UART_DISABLE and set pinmux to UART4 here since - * some code (e,g, spi_flash_probe) uses printf() while the SPI - * bus is held. That is arguably bad, but it has the advantage of - * already being in the source tree. - */ -} - -void spi_cs_activate(struct spi_slave *slave) +void tegra20_spi_cs_activate(struct spi_slave *slave) { struct tegra_spi_slave *spi = to_tegra_spi(slave); struct spi_regs *regs = spi->ctrl->regs; @@ -255,7 +242,7 @@ void spi_cs_activate(struct spi_slave *slave) setbits_le32(®s->command, SPI_CMD_CS_VAL); } -void spi_cs_deactivate(struct spi_slave *slave) +void tegra20_spi_cs_deactivate(struct spi_slave *slave) { struct tegra_spi_slave *spi = to_tegra_spi(slave); struct spi_regs *regs = spi->ctrl->regs; @@ -264,7 +251,7 @@ void spi_cs_deactivate(struct spi_slave *slave) clrbits_le32(®s->command, SPI_CMD_CS_VAL); } -int spi_xfer(struct spi_slave *slave, unsigned int bitlen, +int tegra20_spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *data_out, void *data_in, unsigned long flags) { struct tegra_spi_slave *spi = to_tegra_spi(slave); diff --git a/drivers/spi/tegra20_slink.c b/drivers/spi/tegra20_slink.c index f3b0964488..2ef2eb8495 100644 --- a/drivers/spi/tegra20_slink.c +++ b/drivers/spi/tegra20_slink.c @@ -107,7 +107,7 @@ static inline struct tegra_spi_slave *to_tegra_spi(struct spi_slave *slave) return container_of(slave, struct tegra_spi_slave, slave); } -int spi_cs_is_valid(unsigned int bus, unsigned int cs) +int tegra30_spi_cs_is_valid(unsigned int bus, unsigned int cs) { if (bus >= CONFIG_TEGRA_SLINK_CTRLS || cs > 3 || !spi_ctrls[bus].valid) return 0; @@ -115,7 +115,7 @@ int spi_cs_is_valid(unsigned int bus, unsigned int cs) return 1; } -struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, +struct spi_slave *tegra30_spi_setup_slave(unsigned int bus, unsigned int cs, unsigned int max_hz, unsigned int mode) { struct tegra_spi_slave *spi; @@ -159,25 +159,20 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, return &spi->slave; } -void spi_free_slave(struct spi_slave *slave) +void tegra30_spi_free_slave(struct spi_slave *slave) { struct tegra_spi_slave *spi = to_tegra_spi(slave); free(spi); } -void spi_init(void) +int tegra30_spi_init(int *node_list, int count) { struct tegra_spi_ctrl *ctrl; int i; int node = 0; - int count; - int node_list[CONFIG_TEGRA_SLINK_CTRLS]; + int found = 0; - count = fdtdec_find_aliases_for_id(gd->fdt_blob, "spi", - COMPAT_NVIDIA_TEGRA20_SLINK, - node_list, - CONFIG_TEGRA_SLINK_CTRLS); for (i = 0; i < count; i++) { ctrl = &spi_ctrls[i]; node = node_list[i]; @@ -201,13 +196,15 @@ void spi_init(void) continue; } ctrl->valid = 1; + found = 1; debug("%s: found controller at %p, freq = %u, periph_id = %d\n", __func__, ctrl->regs, ctrl->freq, ctrl->periph_id); } + return !found; } -int spi_claim_bus(struct spi_slave *slave) +int tegra30_spi_claim_bus(struct spi_slave *slave) { struct tegra_spi_slave *spi = to_tegra_spi(slave); struct spi_regs *regs = spi->ctrl->regs; @@ -232,11 +229,7 @@ int spi_claim_bus(struct spi_slave *slave) return 0; } -void spi_release_bus(struct spi_slave *slave) -{ -} - -void spi_cs_activate(struct spi_slave *slave) +void tegra30_spi_cs_activate(struct spi_slave *slave) { struct tegra_spi_slave *spi = to_tegra_spi(slave); struct spi_regs *regs = spi->ctrl->regs; @@ -245,7 +238,7 @@ void spi_cs_activate(struct spi_slave *slave) setbits_le32(®s->command, SLINK_CMD_CS_VAL); } -void spi_cs_deactivate(struct spi_slave *slave) +void tegra30_spi_cs_deactivate(struct spi_slave *slave) { struct tegra_spi_slave *spi = to_tegra_spi(slave); struct spi_regs *regs = spi->ctrl->regs; @@ -254,7 +247,7 @@ void spi_cs_deactivate(struct spi_slave *slave) clrbits_le32(®s->command, SLINK_CMD_CS_VAL); } -int spi_xfer(struct spi_slave *slave, unsigned int bitlen, +int tegra30_spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *data_out, void *data_in, unsigned long flags) { struct tegra_spi_slave *spi = to_tegra_spi(slave); diff --git a/include/configs/tegra-common-post.h b/include/configs/tegra-common-post.h index f2a70b1a35..d967a75b3a 100644 --- a/include/configs/tegra-common-post.h +++ b/include/configs/tegra-common-post.h @@ -150,6 +150,10 @@ MEM_LAYOUT_ENV_SETTINGS \ BOOTCMDS_COMMON +#if defined(CONFIG_TEGRA20_SFLASH) || defined(CONFIG_TEGRA20_SLINK) +#define CONFIG_FDT_SPI +#endif + /* overrides for SPL build here */ #ifdef CONFIG_SPL_BUILD -- cgit v1.2.3 From 772ba15474f73adc942e817cc072b6e9750836cc Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Sat, 16 Mar 2013 18:58:08 +0000 Subject: sf: winbond: add W25Q32DW Add support for Winbond W25Q32DW 32Mbit part Signed-off-by: Allen Martin Signed-off-by: Tom Warren Reviewed-by: Stephen Warren --- drivers/mtd/spi/winbond.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/mtd/spi/winbond.c b/drivers/mtd/spi/winbond.c index 4418302169..3560fcb6ba 100644 --- a/drivers/mtd/spi/winbond.c +++ b/drivers/mtd/spi/winbond.c @@ -67,6 +67,11 @@ static const struct winbond_spi_flash_params winbond_spi_flash_table[] = { .nr_blocks = 128, .name = "W25Q80", }, + { + .id = 0x6016, + .nr_blocks = 512, + .name = "W25Q32DW", + }, { .id = 0x6017, .nr_blocks = 128, -- cgit v1.2.3 From c3bb3c8bb3de2078334f4b95e04d37eed78781c2 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Sat, 16 Mar 2013 18:58:09 +0000 Subject: tegra114: fdt: add compatible string for tegra114 SPI ctrl Add "nvidia,tegra114-spi" to represent t114 SPI controller hardware. Signed-off-by: Allen Martin Signed-off-by: Tom Warren Reviewed-by: Stephen Warren --- include/fdtdec.h | 1 + lib/fdtdec.c | 1 + 2 files changed, 2 insertions(+) diff --git a/include/fdtdec.h b/include/fdtdec.h index 21894835d1..19c970743b 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -75,6 +75,7 @@ enum fdt_compat_id { COMPAT_NVIDIA_TEGRA20_SDMMC, /* Tegra20 SDMMC controller */ COMPAT_NVIDIA_TEGRA20_SFLASH, /* Tegra 2 SPI flash controller */ COMPAT_NVIDIA_TEGRA20_SLINK, /* Tegra 2 SPI SLINK controller */ + COMPAT_NVIDIA_TEGRA114_SPI, /* Tegra 114 SPI controller */ COMPAT_SMSC_LAN9215, /* SMSC 10/100 Ethernet LAN9215 */ COMPAT_SAMSUNG_EXYNOS5_SROMC, /* Exynos5 SROMC */ COMPAT_SAMSUNG_S3C2440_I2C, /* Exynos I2C Controller */ diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 43f29f5c6b..c56f7d4845 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -50,6 +50,7 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(NVIDIA_TEGRA20_SDMMC, "nvidia,tegra20-sdhci"), COMPAT(NVIDIA_TEGRA20_SFLASH, "nvidia,tegra20-sflash"), COMPAT(NVIDIA_TEGRA20_SLINK, "nvidia,tegra20-slink"), + COMPAT(NVIDIA_TEGRA114_SPI, "nvidia,tegra114-spi"), COMPAT(SMSC_LAN9215, "smsc,lan9215"), COMPAT(SAMSUNG_EXYNOS5_SROMC, "samsung,exynos-sromc"), COMPAT(SAMSUNG_S3C2440_I2C, "samsung,s3c2440-i2c"), -- cgit v1.2.3 From 6a3742fe7abfe4b5f4e942a579c0eceaa5a5ed15 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Sat, 16 Mar 2013 18:58:10 +0000 Subject: tegra114: fdt: add apbdma block Add node for apbdma controller hardware. Signed-off-by: Allen Martin Signed-off-by: Tom Warren Reviewed-by: Stephen Warren --- arch/arm/dts/tegra114.dtsi | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/arch/arm/dts/tegra114.dtsi b/arch/arm/dts/tegra114.dtsi index 701c0f9aff..0cb13d0735 100644 --- a/arch/arm/dts/tegra114.dtsi +++ b/arch/arm/dts/tegra114.dtsi @@ -9,6 +9,43 @@ #clock-cells = <1>; }; + apbdma: dma { + compatible = "nvidia,tegra114-apbdma", "nvidia,tegra30-apbdma", "nvidia,tegra20-apbdma"; + reg = <0x6000a000 0x1400>; + interrupts = <0 104 0x04 + 0 105 0x04 + 0 106 0x04 + 0 107 0x04 + 0 108 0x04 + 0 109 0x04 + 0 110 0x04 + 0 111 0x04 + 0 112 0x04 + 0 113 0x04 + 0 114 0x04 + 0 115 0x04 + 0 116 0x04 + 0 117 0x04 + 0 118 0x04 + 0 119 0x04 + 0 128 0x04 + 0 129 0x04 + 0 130 0x04 + 0 131 0x04 + 0 132 0x04 + 0 133 0x04 + 0 134 0x04 + 0 135 0x04 + 0 136 0x04 + 0 137 0x04 + 0 138 0x04 + 0 139 0x04 + 0 140 0x04 + 0 141 0x04 + 0 142 0x04 + 0 143 0x04>; + }; + gpio: gpio { compatible = "nvidia,tegra114-gpio", "nvidia,tegra30-gpio"; reg = <0x6000d000 0x1000>; -- cgit v1.2.3 From 9a38fb4d949700175e304e044571f51655a17e11 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Sat, 16 Mar 2013 18:58:11 +0000 Subject: tegra114: fdt: add SPI blocks Add nodes for t114 SPI controller hardware Signed-off-by: Allen Martin Signed-off-by: Tom Warren Reviewed-by: Stephen Warren --- arch/arm/dts/tegra114.dtsi | 72 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/arch/arm/dts/tegra114.dtsi b/arch/arm/dts/tegra114.dtsi index 0cb13d0735..3b1ca35fcc 100644 --- a/arch/arm/dts/tegra114.dtsi +++ b/arch/arm/dts/tegra114.dtsi @@ -112,4 +112,76 @@ clocks = <&tegra_car 47>; status = "disabled"; }; + + spi@7000d400 { + compatible = "nvidia,tegra114-spi"; + reg = <0x7000d400 0x200>; + interrupts = <0 59 0x04>; + nvidia,dma-request-selector = <&apbdma 15>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + /* PERIPH_ID_SBC1, PLLP_OUT0 */ + clocks = <&tegra_car 41>; + }; + + spi@7000d600 { + compatible = "nvidia,tegra114-spi"; + reg = <0x7000d600 0x200>; + interrupts = <0 82 0x04>; + nvidia,dma-request-selector = <&apbdma 16>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + /* PERIPH_ID_SBC2, PLLP_OUT0 */ + clocks = <&tegra_car 44>; + }; + + spi@7000d800 { + compatible = "nvidia,tegra114-spi"; + reg = <0x7000d480 0x200>; + interrupts = <0 83 0x04>; + nvidia,dma-request-selector = <&apbdma 17>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + /* PERIPH_ID_SBC3, PLLP_OUT0 */ + clocks = <&tegra_car 46>; + }; + + spi@7000da00 { + compatible = "nvidia,tegra114-spi"; + reg = <0x7000da00 0x200>; + interrupts = <0 93 0x04>; + nvidia,dma-request-selector = <&apbdma 18>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + /* PERIPH_ID_SBC4, PLLP_OUT0 */ + clocks = <&tegra_car 68>; + }; + + spi@7000dc00 { + compatible = "nvidia,tegra114-spi"; + reg = <0x7000dc00 0x200>; + interrupts = <0 94 0x04>; + nvidia,dma-request-selector = <&apbdma 27>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + /* PERIPH_ID_SBC5, PLLP_OUT0 */ + clocks = <&tegra_car 104>; + }; + + spi@7000de00 { + compatible = "nvidia,tegra114-spi"; + reg = <0x7000de00 0x200>; + interrupts = <0 79 0x04>; + nvidia,dma-request-selector = <&apbdma 28>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + /* PERIPH_ID_SBC6, PLLP_OUT0 */ + clocks = <&tegra_car 105>; + }; }; -- cgit v1.2.3 From af77fdb2ce7184104c6eb5a7b981def549c771e0 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Sat, 16 Mar 2013 18:58:12 +0000 Subject: tegra114: dalmore: fdt: enable dalmore SPI controller Dalmore has a SPI flash part attached to controller 4, so enable controller 4 and set to 25MHz. Signed-off-by: Allen Martin Signed-off-by: Tom Warren Reviewed-by: Stephen Warren --- board/nvidia/dts/tegra114-dalmore.dts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/board/nvidia/dts/tegra114-dalmore.dts b/board/nvidia/dts/tegra114-dalmore.dts index 30cf1fb730..87cb0ba361 100644 --- a/board/nvidia/dts/tegra114-dalmore.dts +++ b/board/nvidia/dts/tegra114-dalmore.dts @@ -43,4 +43,9 @@ status = "okay"; clock-frequency = <400000>; }; + + spi@7000da00 { + status = "okay"; + spi-max-frequency = <25000000>; + }; }; -- cgit v1.2.3 From 77c42e80b936cf44334a59a7890c775712f5b707 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Sat, 16 Mar 2013 18:58:13 +0000 Subject: tegra114: add SPI driver Add driver for tegra114 SPI controller. This controller is not compatible with either the tegra20 or tegra30 controllers, so it requires a new driver. Signed-off-by: Allen Martin Signed-off-by: Tom Warren Reviewed-by: Stephen Warren --- arch/arm/include/asm/arch-tegra114/tegra114_spi.h | 41 +++ drivers/spi/Makefile | 1 + drivers/spi/fdt_spi.c | 15 + drivers/spi/tegra114_spi.c | 405 ++++++++++++++++++++++ include/configs/tegra-common-post.h | 2 +- 5 files changed, 463 insertions(+), 1 deletion(-) create mode 100644 arch/arm/include/asm/arch-tegra114/tegra114_spi.h create mode 100644 drivers/spi/tegra114_spi.c diff --git a/arch/arm/include/asm/arch-tegra114/tegra114_spi.h b/arch/arm/include/asm/arch-tegra114/tegra114_spi.h new file mode 100644 index 0000000000..48197bc27f --- /dev/null +++ b/arch/arm/include/asm/arch-tegra114/tegra114_spi.h @@ -0,0 +1,41 @@ +/* + * NVIDIA Tegra SPI controller + * + * Copyright 2010-2013 NVIDIA Corporation + * + * This software may be used and distributed according to the + * terms of the GNU Public License, Version 2, incorporated + * herein by reference. + * + * 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _TEGRA114_SPI_H_ +#define _TEGRA114_SPI_H_ + +#include + +int tegra114_spi_init(int *node_list, int count); +int tegra114_spi_cs_is_valid(unsigned int bus, unsigned int cs); +struct spi_slave *tegra114_spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode); +void tegra114_spi_free_slave(struct spi_slave *slave); +int tegra114_spi_claim_bus(struct spi_slave *slave); +void tegra114_spi_cs_activate(struct spi_slave *slave); +void tegra114_spi_cs_deactivate(struct spi_slave *slave); +int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen, + const void *data_out, void *data_in, unsigned long flags); + +#endif /* _TEGRA114_SPI_H_ */ diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 3762d59dd0..46e8fa3bef 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -49,6 +49,7 @@ COBJS-$(CONFIG_FSL_ESPI) += fsl_espi.o COBJS-$(CONFIG_FDT_SPI) += fdt_spi.o COBJS-$(CONFIG_TEGRA20_SFLASH) += tegra20_sflash.o COBJS-$(CONFIG_TEGRA20_SLINK) += tegra20_slink.o +COBJS-$(CONFIG_TEGRA114_SPI) += tegra114_spi.o COBJS-$(CONFIG_XILINX_SPI) += xilinx_spi.o COBJS := $(COBJS-y) diff --git a/drivers/spi/fdt_spi.c b/drivers/spi/fdt_spi.c index c6ae719d63..58f139a54e 100644 --- a/drivers/spi/fdt_spi.c +++ b/drivers/spi/fdt_spi.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -79,6 +80,20 @@ static struct fdt_spi_driver fdt_spi_drivers[] = { .xfer = tegra30_spi_xfer, }, #endif +#ifdef CONFIG_TEGRA114_SPI + { + .compat = COMPAT_NVIDIA_TEGRA114_SPI, + .max_ctrls = CONFIG_TEGRA114_SPI_CTRLS, + .init = tegra114_spi_init, + .claim_bus = tegra114_spi_claim_bus, + .cs_is_valid = tegra114_spi_cs_is_valid, + .setup_slave = tegra114_spi_setup_slave, + .free_slave = tegra114_spi_free_slave, + .cs_activate = tegra114_spi_cs_activate, + .cs_deactivate = tegra114_spi_cs_deactivate, + .xfer = tegra114_spi_xfer, + }, +#endif }; static struct fdt_spi_driver *driver; diff --git a/drivers/spi/tegra114_spi.c b/drivers/spi/tegra114_spi.c new file mode 100644 index 0000000000..b11a0a1ff7 --- /dev/null +++ b/drivers/spi/tegra114_spi.c @@ -0,0 +1,405 @@ +/* + * NVIDIA Tegra SPI controller (T114 and later) + * + * Copyright (c) 2010-2013 NVIDIA Corporation + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +/* COMMAND1 */ +#define SPI_CMD1_GO (1 << 31) +#define SPI_CMD1_M_S (1 << 30) +#define SPI_CMD1_MODE_MASK 0x3 +#define SPI_CMD1_MODE_SHIFT 28 +#define SPI_CMD1_CS_SEL_MASK 0x3 +#define SPI_CMD1_CS_SEL_SHIFT 26 +#define SPI_CMD1_CS_POL_INACTIVE3 (1 << 25) +#define SPI_CMD1_CS_POL_INACTIVE2 (1 << 24) +#define SPI_CMD1_CS_POL_INACTIVE1 (1 << 23) +#define SPI_CMD1_CS_POL_INACTIVE0 (1 << 22) +#define SPI_CMD1_CS_SW_HW (1 << 21) +#define SPI_CMD1_CS_SW_VAL (1 << 20) +#define SPI_CMD1_IDLE_SDA_MASK 0x3 +#define SPI_CMD1_IDLE_SDA_SHIFT 18 +#define SPI_CMD1_BIDIR (1 << 17) +#define SPI_CMD1_LSBI_FE (1 << 16) +#define SPI_CMD1_LSBY_FE (1 << 15) +#define SPI_CMD1_BOTH_EN_BIT (1 << 14) +#define SPI_CMD1_BOTH_EN_BYTE (1 << 13) +#define SPI_CMD1_RX_EN (1 << 12) +#define SPI_CMD1_TX_EN (1 << 11) +#define SPI_CMD1_PACKED (1 << 5) +#define SPI_CMD1_BIT_LEN_MASK 0x1F +#define SPI_CMD1_BIT_LEN_SHIFT 0 + +/* COMMAND2 */ +#define SPI_CMD2_TX_CLK_TAP_DELAY (1 << 6) +#define SPI_CMD2_TX_CLK_TAP_DELAY_MASK (0x3F << 6) +#define SPI_CMD2_RX_CLK_TAP_DELAY (1 << 0) +#define SPI_CMD2_RX_CLK_TAP_DELAY_MASK (0x3F << 0) + +/* TRANSFER STATUS */ +#define SPI_XFER_STS_RDY (1 << 30) + +/* FIFO STATUS */ +#define SPI_FIFO_STS_CS_INACTIVE (1 << 31) +#define SPI_FIFO_STS_FRAME_END (1 << 30) +#define SPI_FIFO_STS_RX_FIFO_FLUSH (1 << 15) +#define SPI_FIFO_STS_TX_FIFO_FLUSH (1 << 14) +#define SPI_FIFO_STS_ERR (1 << 8) +#define SPI_FIFO_STS_TX_FIFO_OVF (1 << 7) +#define SPI_FIFO_STS_TX_FIFO_UNR (1 << 6) +#define SPI_FIFO_STS_RX_FIFO_OVF (1 << 5) +#define SPI_FIFO_STS_RX_FIFO_UNR (1 << 4) +#define SPI_FIFO_STS_TX_FIFO_FULL (1 << 3) +#define SPI_FIFO_STS_TX_FIFO_EMPTY (1 << 2) +#define SPI_FIFO_STS_RX_FIFO_FULL (1 << 1) +#define SPI_FIFO_STS_RX_FIFO_EMPTY (1 << 0) + +#define SPI_TIMEOUT 1000 +#define TEGRA_SPI_MAX_FREQ 52000000 + +struct spi_regs { + u32 command1; /* 000:SPI_COMMAND1 register */ + u32 command2; /* 004:SPI_COMMAND2 register */ + u32 timing1; /* 008:SPI_CS_TIM1 register */ + u32 timing2; /* 00c:SPI_CS_TIM2 register */ + u32 xfer_status;/* 010:SPI_TRANS_STATUS register */ + u32 fifo_status;/* 014:SPI_FIFO_STATUS register */ + u32 tx_data; /* 018:SPI_TX_DATA register */ + u32 rx_data; /* 01c:SPI_RX_DATA register */ + u32 dma_ctl; /* 020:SPI_DMA_CTL register */ + u32 dma_blk; /* 024:SPI_DMA_BLK register */ + u32 rsvd[56]; /* 028-107 reserved */ + u32 tx_fifo; /* 108:SPI_FIFO1 register */ + u32 rsvd2[31]; /* 10c-187 reserved */ + u32 rx_fifo; /* 188:SPI_FIFO2 register */ + u32 spare_ctl; /* 18c:SPI_SPARE_CTRL register */ +}; + +struct tegra_spi_ctrl { + struct spi_regs *regs; + unsigned int freq; + unsigned int mode; + int periph_id; + int valid; +}; + +struct tegra_spi_slave { + struct spi_slave slave; + struct tegra_spi_ctrl *ctrl; +}; + +static struct tegra_spi_ctrl spi_ctrls[CONFIG_TEGRA114_SPI_CTRLS]; + +static inline struct tegra_spi_slave *to_tegra_spi(struct spi_slave *slave) +{ + return container_of(slave, struct tegra_spi_slave, slave); +} + +int tegra114_spi_cs_is_valid(unsigned int bus, unsigned int cs) +{ + if (bus >= CONFIG_TEGRA114_SPI_CTRLS || cs > 3 || !spi_ctrls[bus].valid) + return 0; + else + return 1; +} + +struct spi_slave *tegra114_spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + struct tegra_spi_slave *spi; + + debug("%s: bus: %u, cs: %u, max_hz: %u, mode: %u\n", __func__, + bus, cs, max_hz, mode); + + if (!spi_cs_is_valid(bus, cs)) { + printf("SPI error: unsupported bus %d / chip select %d\n", + bus, cs); + return NULL; + } + + if (max_hz > TEGRA_SPI_MAX_FREQ) { + printf("SPI error: unsupported frequency %d Hz. Max frequency" + " is %d Hz\n", max_hz, TEGRA_SPI_MAX_FREQ); + return NULL; + } + + spi = malloc(sizeof(struct tegra_spi_slave)); + if (!spi) { + printf("SPI error: malloc of SPI structure failed\n"); + return NULL; + } + spi->slave.bus = bus; + spi->slave.cs = cs; + spi->ctrl = &spi_ctrls[bus]; + if (!spi->ctrl) { + printf("SPI error: could not find controller for bus %d\n", + bus); + return NULL; + } + + if (max_hz < spi->ctrl->freq) { + debug("%s: limiting frequency from %u to %u\n", __func__, + spi->ctrl->freq, max_hz); + spi->ctrl->freq = max_hz; + } + spi->ctrl->mode = mode; + + return &spi->slave; +} + +void tegra114_spi_free_slave(struct spi_slave *slave) +{ + struct tegra_spi_slave *spi = to_tegra_spi(slave); + + free(spi); +} + +int tegra114_spi_init(int *node_list, int count) +{ + struct tegra_spi_ctrl *ctrl; + int i; + int node = 0; + int found = 0; + + for (i = 0; i < count; i++) { + ctrl = &spi_ctrls[i]; + node = node_list[i]; + + ctrl->regs = (struct spi_regs *)fdtdec_get_addr(gd->fdt_blob, + node, "reg"); + if ((fdt_addr_t)ctrl->regs == FDT_ADDR_T_NONE) { + debug("%s: no spi register found\n", __func__); + continue; + } + ctrl->freq = fdtdec_get_int(gd->fdt_blob, node, + "spi-max-frequency", 0); + if (!ctrl->freq) { + debug("%s: no spi max frequency found\n", __func__); + continue; + } + + ctrl->periph_id = clock_decode_periph_id(gd->fdt_blob, node); + if (ctrl->periph_id == PERIPH_ID_NONE) { + debug("%s: could not decode periph id\n", __func__); + continue; + } + ctrl->valid = 1; + found = 1; + + debug("%s: found controller at %p, freq = %u, periph_id = %d\n", + __func__, ctrl->regs, ctrl->freq, ctrl->periph_id); + } + + return !found; +} + +int tegra114_spi_claim_bus(struct spi_slave *slave) +{ + struct tegra_spi_slave *spi = to_tegra_spi(slave); + struct spi_regs *regs = spi->ctrl->regs; + + /* Change SPI clock to correct frequency, PLLP_OUT0 source */ + clock_start_periph_pll(spi->ctrl->periph_id, CLOCK_ID_PERIPH, + spi->ctrl->freq); + + /* Clear stale status here */ + setbits_le32(®s->fifo_status, + SPI_FIFO_STS_ERR | + SPI_FIFO_STS_TX_FIFO_OVF | + SPI_FIFO_STS_TX_FIFO_UNR | + SPI_FIFO_STS_RX_FIFO_OVF | + SPI_FIFO_STS_RX_FIFO_UNR | + SPI_FIFO_STS_TX_FIFO_FULL | + SPI_FIFO_STS_TX_FIFO_EMPTY | + SPI_FIFO_STS_RX_FIFO_FULL | + SPI_FIFO_STS_RX_FIFO_EMPTY); + debug("%s: FIFO STATUS = %08x\n", __func__, readl(®s->fifo_status)); + + /* Set master mode and sw controlled CS */ + setbits_le32(®s->command1, SPI_CMD1_M_S | SPI_CMD1_CS_SW_HW | + (spi->ctrl->mode << SPI_CMD1_MODE_SHIFT)); + debug("%s: COMMAND1 = %08x\n", __func__, readl(®s->command1)); + + return 0; +} + +void tegra114_spi_cs_activate(struct spi_slave *slave) +{ + struct tegra_spi_slave *spi = to_tegra_spi(slave); + struct spi_regs *regs = spi->ctrl->regs; + + clrbits_le32(®s->command1, SPI_CMD1_CS_SW_VAL); +} + +void tegra114_spi_cs_deactivate(struct spi_slave *slave) +{ + struct tegra_spi_slave *spi = to_tegra_spi(slave); + struct spi_regs *regs = spi->ctrl->regs; + + setbits_le32(®s->command1, SPI_CMD1_CS_SW_VAL); +} + +int tegra114_spi_xfer(struct spi_slave *slave, unsigned int bitlen, + const void *data_out, void *data_in, unsigned long flags) +{ + struct tegra_spi_slave *spi = to_tegra_spi(slave); + struct spi_regs *regs = spi->ctrl->regs; + u32 reg, tmpdout, tmpdin = 0; + const u8 *dout = data_out; + u8 *din = data_in; + int num_bytes; + int ret; + + debug("%s: slave %u:%u dout %p din %p bitlen %u\n", + __func__, slave->bus, slave->cs, dout, din, bitlen); + if (bitlen % 8) + return -1; + num_bytes = bitlen / 8; + + ret = 0; + + /* clear all error status bits */ + reg = readl(®s->fifo_status); + writel(reg, ®s->fifo_status); + + /* clear ready bit */ + setbits_le32(®s->xfer_status, SPI_XFER_STS_RDY); + + clrsetbits_le32(®s->command1, SPI_CMD1_CS_SW_VAL, + SPI_CMD1_RX_EN | SPI_CMD1_TX_EN | SPI_CMD1_LSBY_FE | + (slave->cs << SPI_CMD1_CS_SEL_SHIFT)); + + /* set xfer size to 1 block (32 bits) */ + writel(0, ®s->dma_blk); + + if (flags & SPI_XFER_BEGIN) + spi_cs_activate(slave); + + /* handle data in 32-bit chunks */ + while (num_bytes > 0) { + int bytes; + int is_read = 0; + int tm, i; + + tmpdout = 0; + bytes = (num_bytes > 4) ? 4 : num_bytes; + + if (dout != NULL) { + for (i = 0; i < bytes; ++i) + tmpdout = (tmpdout << 8) | dout[i]; + dout += bytes; + } + + num_bytes -= bytes; + + clrsetbits_le32(®s->command1, + SPI_CMD1_BIT_LEN_MASK << SPI_CMD1_BIT_LEN_SHIFT, + (bytes * 8 - 1) << SPI_CMD1_BIT_LEN_SHIFT); + writel(tmpdout, ®s->tx_fifo); + setbits_le32(®s->command1, SPI_CMD1_GO); + + /* + * Wait for SPI transmit FIFO to empty, or to time out. + * The RX FIFO status will be read and cleared last + */ + for (tm = 0, is_read = 0; tm < SPI_TIMEOUT; ++tm) { + u32 fifo_status, xfer_status; + + fifo_status = readl(®s->fifo_status); + + /* We can exit when we've had both RX and TX activity */ + if (is_read && + (fifo_status & SPI_FIFO_STS_TX_FIFO_EMPTY)) + break; + + xfer_status = readl(®s->xfer_status); + if (!(xfer_status & SPI_XFER_STS_RDY)) + continue; + + if (fifo_status & SPI_FIFO_STS_ERR) { + debug("%s: got a fifo error: ", __func__); + if (fifo_status & SPI_FIFO_STS_TX_FIFO_OVF) + debug("tx FIFO overflow "); + if (fifo_status & SPI_FIFO_STS_TX_FIFO_UNR) + debug("tx FIFO underrun "); + if (fifo_status & SPI_FIFO_STS_RX_FIFO_OVF) + debug("rx FIFO overflow "); + if (fifo_status & SPI_FIFO_STS_RX_FIFO_UNR) + debug("rx FIFO underrun "); + if (fifo_status & SPI_FIFO_STS_TX_FIFO_FULL) + debug("tx FIFO full "); + if (fifo_status & SPI_FIFO_STS_TX_FIFO_EMPTY) + debug("tx FIFO empty "); + if (fifo_status & SPI_FIFO_STS_RX_FIFO_FULL) + debug("rx FIFO full "); + if (fifo_status & SPI_FIFO_STS_RX_FIFO_EMPTY) + debug("rx FIFO empty "); + debug("\n"); + break; + } + + if (!(fifo_status & SPI_FIFO_STS_RX_FIFO_EMPTY)) { + tmpdin = readl(®s->rx_fifo); + is_read = 1; + + /* swap bytes read in */ + if (din != NULL) { + for (i = bytes - 1; i >= 0; --i) { + din[i] = tmpdin & 0xff; + tmpdin >>= 8; + } + din += bytes; + } + } + } + + if (tm >= SPI_TIMEOUT) + ret = tm; + + /* clear ACK RDY, etc. bits */ + writel(readl(®s->fifo_status), ®s->fifo_status); + } + + if (flags & SPI_XFER_END) + spi_cs_deactivate(slave); + + debug("%s: transfer ended. Value=%08x, fifo_status = %08x\n", + __func__, tmpdin, readl(®s->fifo_status)); + + if (ret) { + printf("%s: timeout during SPI transfer, tm %d\n", + __func__, ret); + return -1; + } + + return 0; +} diff --git a/include/configs/tegra-common-post.h b/include/configs/tegra-common-post.h index d967a75b3a..bf186995ed 100644 --- a/include/configs/tegra-common-post.h +++ b/include/configs/tegra-common-post.h @@ -150,7 +150,7 @@ MEM_LAYOUT_ENV_SETTINGS \ BOOTCMDS_COMMON -#if defined(CONFIG_TEGRA20_SFLASH) || defined(CONFIG_TEGRA20_SLINK) +#if defined(CONFIG_TEGRA20_SFLASH) || defined(CONFIG_TEGRA20_SLINK) || defined(CONFIG_TEGRA114_SPI) #define CONFIG_FDT_SPI #endif -- cgit v1.2.3 From ec37b2b423df552425d59a63763ce0c4773e57f8 Mon Sep 17 00:00:00 2001 From: Allen Martin Date: Sat, 16 Mar 2013 18:58:14 +0000 Subject: tegra114: dalmore: config: enable SPI Turn on SPI in dalmore config file Signed-off-by: Allen Martin Signed-off-by: Tom Warren Reviewed-by: Stephen Warren --- include/configs/dalmore.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/configs/dalmore.h b/include/configs/dalmore.h index b1a6e34eba..c7deea5350 100644 --- a/include/configs/dalmore.h +++ b/include/configs/dalmore.h @@ -54,6 +54,17 @@ #define MACH_TYPE_DALMORE 4304 /* not yet in mach-types.h */ +/* SPI */ +#define CONFIG_TEGRA114_SPI +#define CONFIG_TEGRA114_SPI_CTRLS 6 +#define CONFIG_SPI_FLASH +#define CONFIG_SPI_FLASH_WINBOND +#define CONFIG_SF_DEFAULT_MODE SPI_MODE_0 +#define CONFIG_SF_DEFAULT_SPEED 24000000 +#define CONFIG_CMD_SPI +#define CONFIG_CMD_SF +#define CONFIG_SPI_FLASH_SIZE (4 << 20) + #include "tegra-common-post.h" #endif /* __CONFIG_H */ -- cgit v1.2.3 From e9cd20654c1ce3112cac0f369640a74f694618a3 Mon Sep 17 00:00:00 2001 From: Tom Warren Date: Mon, 18 Mar 2013 14:46:46 -0700 Subject: Tegra114: fdt: Add SDMMC (sdhci) nodes for T114 boards (Dalmore for now) Took these values directly from the kernel dts files. Signed-off-by: Tom Warren Reviewed-by: Stephen Warren --- arch/arm/dts/tegra114.dtsi | 32 ++++++++++++++++++++++++++++++++ board/nvidia/dts/tegra114-dalmore.dts | 13 +++++++++++++ 2 files changed, 45 insertions(+) diff --git a/arch/arm/dts/tegra114.dtsi b/arch/arm/dts/tegra114.dtsi index 3b1ca35fcc..f86d18dd7c 100644 --- a/arch/arm/dts/tegra114.dtsi +++ b/arch/arm/dts/tegra114.dtsi @@ -184,4 +184,36 @@ /* PERIPH_ID_SBC6, PLLP_OUT0 */ clocks = <&tegra_car 105>; }; + + sdhci@78000000 { + compatible = "nvidia,tegra114-sdhci", "nvidia,tegra30-sdhci"; + reg = <0x78000000 0x200>; + interrupts = <0 14 0x04>; + clocks = <&tegra_car 14>; + status = "disable"; + }; + + sdhci@78000200 { + compatible = "nvidia,tegra114-sdhci", "nvidia,tegra30-sdhci"; + reg = <0x78000200 0x200>; + interrupts = <0 15 0x04>; + clocks = <&tegra_car 9>; + status = "disable"; + }; + + sdhci@78000400 { + compatible = "nvidia,tegra114-sdhci", "nvidia,tegra30-sdhci"; + reg = <0x78000400 0x200>; + interrupts = <0 19 0x04>; + clocks = <&tegra_car 69>; + status = "disable"; + }; + + sdhci@78000600 { + compatible = "nvidia,tegra114-sdhci", "nvidia,tegra30-sdhci"; + reg = <0x78000600 0x200>; + interrupts = <0 31 0x04>; + clocks = <&tegra_car 15>; + status = "disable"; + }; }; diff --git a/board/nvidia/dts/tegra114-dalmore.dts b/board/nvidia/dts/tegra114-dalmore.dts index 87cb0ba361..86e9459b3a 100644 --- a/board/nvidia/dts/tegra114-dalmore.dts +++ b/board/nvidia/dts/tegra114-dalmore.dts @@ -12,6 +12,8 @@ i2c2 = "/i2c@7000c400"; i2c3 = "/i2c@7000c500"; i2c4 = "/i2c@7000c700"; + sdhci0 = "/sdhci@78000600"; + sdhci1 = "/sdhci@78000400"; }; memory { @@ -48,4 +50,15 @@ status = "okay"; spi-max-frequency = <25000000>; }; + + sdhci@78000400 { + cd-gpios = <&gpio 170 1>; /* gpio PV2 */ + bus-width = <4>; + status = "okay"; + }; + + sdhci@78000600 { + bus-width = <8>; + status = "okay"; + }; }; -- cgit v1.2.3 From 2a04a317911a550e55c2943d59063b621ea5f4ee Mon Sep 17 00:00:00 2001 From: Tom Warren Date: Mon, 18 Mar 2013 14:47:55 -0700 Subject: Tegra114: Dalmore: Add SDIO3 pad config to pinctrl_config table SDIO1 (the SD-card slot on Dalmore) needs to have its pads setup before the MMC driver is added. Signed-off-by: Tom Warren Reviewed-by: Stephen Warren --- arch/arm/include/asm/arch-tegra114/gp_padctrl.h | 6 ++++++ board/nvidia/dalmore/dalmore.c | 4 ++++ board/nvidia/dalmore/pinmux-config-dalmore.h | 6 ++++++ 3 files changed, 16 insertions(+) diff --git a/arch/arm/include/asm/arch-tegra114/gp_padctrl.h b/arch/arm/include/asm/arch-tegra114/gp_padctrl.h index 1ef1a1484d..41ce677807 100644 --- a/arch/arm/include/asm/arch-tegra114/gp_padctrl.h +++ b/arch/arm/include/asm/arch-tegra114/gp_padctrl.h @@ -74,4 +74,10 @@ struct apb_misc_gp_ctlr { u32 aocfg0; /* 0x1AC: APB_MISC_GP_AOCFG0PADCTRL */ }; +/* SDMMC1/3 settings from section 27.5 of T114 TRM */ +#define SDIOCFG_DRVUP_SLWF 0 +#define SDIOCFG_DRVDN_SLWR 0 +#define SDIOCFG_DRVUP 0x24 +#define SDIOCFG_DRVDN 0x14 + #endif /* _TEGRA114_GP_PADCTRL_H_ */ diff --git a/board/nvidia/dalmore/dalmore.c b/board/nvidia/dalmore/dalmore.c index 2020a5f00d..7449b5b99d 100644 --- a/board/nvidia/dalmore/dalmore.c +++ b/board/nvidia/dalmore/dalmore.c @@ -16,6 +16,7 @@ #include #include +#include #include "pinmux-config-dalmore.h" /* @@ -32,4 +33,7 @@ void pinmux_init(void) pinmux_config_table(unused_pins_lowpower, ARRAY_SIZE(unused_pins_lowpower)); + + /* Initialize any non-default pad configs (APB_MISC_GP regs) */ + padgrp_config_table(dalmore_padctrl, ARRAY_SIZE(dalmore_padctrl)); } diff --git a/board/nvidia/dalmore/pinmux-config-dalmore.h b/board/nvidia/dalmore/pinmux-config-dalmore.h index 3ef6f4eaf6..8c05a1517c 100644 --- a/board/nvidia/dalmore/pinmux-config-dalmore.h +++ b/board/nvidia/dalmore/pinmux-config-dalmore.h @@ -361,4 +361,10 @@ static struct pingroup_config tegra114_pinmux_set_nontristate[] = { DEFAULT_PINMUX(SDMMC3_CD_N, SDMMC3, UP, NORMAL, INPUT), }; + +static struct padctrl_config dalmore_padctrl[] = { + /* (_padgrp, _slwf, _slwr, _drvup, _drvdn, _lpmd, _schmt, _hsm) */ + DEFAULT_PADCFG(SDIO3, SDIOCFG_DRVUP_SLWF, SDIOCFG_DRVDN_SLWR, \ + SDIOCFG_DRVUP, SDIOCFG_DRVDN, NONE, NONE, NONE), +}; #endif /* PINMUX_CONFIG_COMMON_H */ -- cgit v1.2.3 From 6d9ea159e4900dc6bc4b38a064fc87cba4582c09 Mon Sep 17 00:00:00 2001 From: Tom Warren Date: Mon, 18 Mar 2013 14:51:20 -0700 Subject: Tegra114: MMC: Add SD bus power-rail init routine T114 requires SD bus power-rail bringup for the SDIO card on SDMMC3. Signed-off-by: Tom Warren Reviewed-by: Stephen Warren --- board/nvidia/dalmore/dalmore.c | 62 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/board/nvidia/dalmore/dalmore.c b/board/nvidia/dalmore/dalmore.c index 7449b5b99d..2c23a29db7 100644 --- a/board/nvidia/dalmore/dalmore.c +++ b/board/nvidia/dalmore/dalmore.c @@ -18,6 +18,10 @@ #include #include #include "pinmux-config-dalmore.h" +#include + +#define BAT_I2C_ADDRESS 0x48 /* TPS65090 charger */ +#define PMU_I2C_ADDRESS 0x58 /* TPS65913 PMU */ /* * Routine: pinmux_init @@ -37,3 +41,61 @@ void pinmux_init(void) /* Initialize any non-default pad configs (APB_MISC_GP regs) */ padgrp_config_table(dalmore_padctrl, ARRAY_SIZE(dalmore_padctrl)); } + +#if defined(CONFIG_TEGRA_MMC) +/* + * Do I2C/PMU writes to bring up SD card bus power + * + */ +void board_sdmmc_voltage_init(void) +{ + uchar reg, data_buffer[1]; + int ret; + + ret = i2c_set_bus_num(0);/* PMU is on bus 0 */ + if (ret) + printf("%s: i2c_set_bus_num returned %d\n", __func__, ret); + + /* TPS65913: LDO9_VOLTAGE = 3.3V */ + data_buffer[0] = 0x31; + reg = 0x61; + + ret = i2c_write(PMU_I2C_ADDRESS, reg, 1, data_buffer, 1); + if (ret) + printf("%s: PMU i2c_write %02X<-%02X returned %d\n", + __func__, reg, data_buffer[0], ret); + + /* TPS65913: LDO9_CTRL = Active */ + data_buffer[0] = 0x01; + reg = 0x60; + + ret = i2c_write(PMU_I2C_ADDRESS, reg, 1, data_buffer, 1); + if (ret) + printf("%s: PMU i2c_write %02X<-%02X returned %d\n", + __func__, reg, data_buffer[0], ret); + + /* TPS65090: FET6_CTRL = enable output auto discharge, enable FET6 */ + data_buffer[0] = 0x03; + reg = 0x14; + + ret = i2c_write(BAT_I2C_ADDRESS, reg, 1, data_buffer, 1); + if (ret) + printf("%s: BAT i2c_write %02X<-%02X returned %d\n", + __func__, reg, data_buffer[0], ret); +} + +/* + * Routine: pin_mux_mmc + * Description: setup the MMC muxes, power rails, etc. + */ +void pin_mux_mmc(void) +{ + /* + * NOTE: We don't do mmc-specific pin muxes here. + * They were done globally in pinmux_init(). + */ + + /* Bring up the SDIO3 power rail */ + board_sdmmc_voltage_init(); +} +#endif /* MMC */ -- cgit v1.2.3 From f789be6086f3e6302fe4b163fa9b7bd6b358c4ce Mon Sep 17 00:00:00 2001 From: Tom Warren Date: Mon, 18 Mar 2013 14:52:26 -0700 Subject: Tegra114: MMC: Enable DT MMC driver support for Tegra114 Dalmore boards Tested on my Dalmore E1611 board, eMMC and SD-Card work fine, can load a kernel off of an SD card OK, card detect works, and the env is now stored in eMMC (end of the 2nd 'boot' sector, same as Tegra20/30). Signed-off-by: Tom Warren Reviewed-by: Stephen Warren --- include/configs/dalmore.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/include/configs/dalmore.h b/include/configs/dalmore.h index c7deea5350..7b68f7ca98 100644 --- a/include/configs/dalmore.h +++ b/include/configs/dalmore.h @@ -50,7 +50,17 @@ #define CONFIG_SYS_I2C_SPEED 100000 #define CONFIG_CMD_I2C -#define CONFIG_ENV_IS_NOWHERE +/* SD/MMC */ +#define CONFIG_MMC +#define CONFIG_GENERIC_MMC +#define CONFIG_TEGRA_MMC +#define CONFIG_CMD_MMC + +/* Environment in eMMC, at the end of 2nd "boot sector" */ +#define CONFIG_ENV_IS_IN_MMC +#define CONFIG_SYS_MMC_ENV_DEV 0 +#define CONFIG_SYS_MMC_ENV_PART 2 +#define CONFIG_ENV_OFFSET ((4096 * 1024) - CONFIG_ENV_SIZE) #define MACH_TYPE_DALMORE 4304 /* not yet in mach-types.h */ -- cgit v1.2.3 From dfa41387155daed35cc6b294b2390641aa887a1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20Stehl=C3=A9?= Date: Mon, 4 Mar 2013 20:04:43 +0000 Subject: ARM: cache: declare set_section_dcache MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We declare the set_section_dcache function globally in the cache header, for later use by e.g. machine specific code. Signed-off-by: Vincent StehlĂ© ti.com> Cc: Tom Rini ti.com> Cc: Albert ARIBAUD --- arch/arm/include/asm/cache.h | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/include/asm/cache.h b/arch/arm/include/asm/cache.h index eef6a5a8f2..416d2c8f93 100644 --- a/arch/arm/include/asm/cache.h +++ b/arch/arm/include/asm/cache.h @@ -41,6 +41,7 @@ static inline void invalidate_l2_cache(void) void l2_cache_enable(void); void l2_cache_disable(void); +void set_section_dcache(int section, enum dcache_option option); /* * The current upper bound for ARM L1 data cache line sizes is 64 bytes. We -- cgit v1.2.3 From 96fdbec2f96c9e11758c8742409069eeef841722 Mon Sep 17 00:00:00 2001 From: R Sricharan Date: Mon, 4 Mar 2013 20:04:44 +0000 Subject: ARM: mmu: Introduce weak dram_bank_setup function Introduce a weak version of dram_bank_setup function to allow a platform specific function. This is used in the subsequent patch to setup dram region without 'XN' attribute in order to enable the region under client permissions. Signed-off-by: R Sricharan Cc: Vincent Stehle Cc: Tom Rini Cc: Albert ARIBAUD --- arch/arm/include/asm/cache.h | 1 + arch/arm/lib/cache-cp15.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/arm/include/asm/cache.h b/arch/arm/include/asm/cache.h index 416d2c8f93..8153484899 100644 --- a/arch/arm/include/asm/cache.h +++ b/arch/arm/include/asm/cache.h @@ -43,6 +43,7 @@ void l2_cache_enable(void); void l2_cache_disable(void); void set_section_dcache(int section, enum dcache_option option); +void dram_bank_mmu_setup(int bank); /* * The current upper bound for ARM L1 data cache line sizes is 64 bytes. We * use that value for aligning DMA buffers unless the board config has specified diff --git a/arch/arm/lib/cache-cp15.c b/arch/arm/lib/cache-cp15.c index b6e5e95530..6ecbedfed9 100644 --- a/arch/arm/lib/cache-cp15.c +++ b/arch/arm/lib/cache-cp15.c @@ -23,6 +23,8 @@ #include #include +#include +#include #if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF)) @@ -77,7 +79,7 @@ void mmu_set_region_dcache_behaviour(u32 start, int size, mmu_page_table_flush((u32)&page_table[start], (u32)&page_table[end]); } -static inline void dram_bank_mmu_setup(int bank) +__weak void dram_bank_mmu_setup(int bank) { bd_t *bd = gd->bd; int i; -- cgit v1.2.3 From de63ac278cbaaa387da3efaf0b21b819c2b0c496 Mon Sep 17 00:00:00 2001 From: R Sricharan Date: Mon, 4 Mar 2013 20:04:45 +0000 Subject: ARM: mmu: Set domain permissions to client access The 'XN' execute never bit is set in the pagetables. This will prevent speculative prefetches to non executable regions. But the domain permissions are set as master in the DACR register. So the pagetable attribute for 'XN' is not effective. Change the permissions to client. This fixes lot of speculative prefetch aborts seen on OMAP5 secure devices. Signed-off-by: R Sricharan Tested-by: Vincent Stehle Cc: Vincent Stehle Cc: Tom Rini Cc: Albert ARIBAUD --- arch/arm/cpu/armv7/cache_v7.c | 3 +++ arch/arm/cpu/armv7/omap-common/hwinit-common.c | 35 ++++++++++++++++++++++++++ arch/arm/include/asm/system.h | 14 +++++++++++ arch/arm/lib/cache-cp15.c | 7 ++++++ 4 files changed, 59 insertions(+) diff --git a/arch/arm/cpu/armv7/cache_v7.c b/arch/arm/cpu/armv7/cache_v7.c index 5f6d0396f3..8748c145c4 100644 --- a/arch/arm/cpu/armv7/cache_v7.c +++ b/arch/arm/cpu/armv7/cache_v7.c @@ -340,6 +340,9 @@ void mmu_page_table_flush(unsigned long start, unsigned long stop) { } +void arm_init_domains(void) +{ +} #endif /* #ifndef CONFIG_SYS_DCACHE_OFF */ #ifndef CONFIG_SYS_ICACHE_OFF diff --git a/arch/arm/cpu/armv7/omap-common/hwinit-common.c b/arch/arm/cpu/armv7/omap-common/hwinit-common.c index 05ff2e868f..70d16a8160 100644 --- a/arch/arm/cpu/armv7/omap-common/hwinit-common.c +++ b/arch/arm/cpu/armv7/omap-common/hwinit-common.c @@ -34,6 +34,12 @@ #include #include #include +#include +#include + +#define ARMV7_DCACHE_WRITEBACK 0xe +#define ARMV7_DOMAIN_CLIENT 1 +#define ARMV7_DOMAIN_MASK (0x3 << 0) DECLARE_GLOBAL_DATA_PTR; @@ -269,4 +275,33 @@ void enable_caches(void) /* Enable D-cache. I-cache is already enabled in start.S */ dcache_enable(); } + +void dram_bank_mmu_setup(int bank) +{ + bd_t *bd = gd->bd; + int i; + + u32 start = bd->bi_dram[bank].start >> 20; + u32 size = bd->bi_dram[bank].size >> 20; + u32 end = start + size; + + debug("%s: bank: %d\n", __func__, bank); + for (i = start; i < end; i++) + set_section_dcache(i, ARMV7_DCACHE_WRITEBACK); + +} + +void arm_init_domains(void) +{ + u32 reg; + + reg = get_dacr(); + /* + * Set DOMAIN to client access so that all permissions + * set in pagetables are validated by the mmu. + */ + reg &= ~ARMV7_DOMAIN_MASK; + reg |= ARMV7_DOMAIN_CLIENT; + set_dacr(reg); +} #endif diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h index 1918492eae..760345f847 100644 --- a/arch/arm/include/asm/system.h +++ b/arch/arm/include/asm/system.h @@ -81,6 +81,20 @@ static inline void set_cr(unsigned int val) isb(); } +static inline unsigned int get_dacr(void) +{ + unsigned int val; + asm("mrc p15, 0, %0, c3, c0, 0 @ get DACR" : "=r" (val) : : "cc"); + return val; +} + +static inline void set_dacr(unsigned int val) +{ + asm volatile("mcr p15, 0, %0, c3, c0, 0 @ set DACR" + : : "r" (val) : "cc"); + isb(); +} + /* options available for data cache on each page */ enum dcache_option { DCACHE_OFF = 0x12, diff --git a/arch/arm/lib/cache-cp15.c b/arch/arm/lib/cache-cp15.c index 6ecbedfed9..4abe1cf061 100644 --- a/arch/arm/lib/cache-cp15.c +++ b/arch/arm/lib/cache-cp15.c @@ -36,6 +36,10 @@ void __arm_init_before_mmu(void) void arm_init_before_mmu(void) __attribute__((weak, alias("__arm_init_before_mmu"))); +__weak void arm_init_domains(void) +{ +} + static void cp_delay (void) { volatile int i; @@ -117,6 +121,9 @@ static inline void mmu_setup(void) /* Set the access control to all-supervisor */ asm volatile("mcr p15, 0, %0, c3, c0, 0" : : "r" (~0)); + + arm_init_domains(); + /* and enable the mmu */ reg = get_cr(); /* get control reg. */ cp_delay(); -- cgit v1.2.3 From d53e340edf65ff253d3a7b06ebe60501045892e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20Stehl=C3=A9?= Date: Fri, 15 Mar 2013 06:54:00 +0000 Subject: armv7: do not relocate _start twice MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The _start symbol is already relocated, so do not add the relocation the second time in c_runtime_cpu_setup. This fixes e.g. the abort exception handling path, which ended in double fault due to bad address in VBAR. Signed-off-by: Vincent StehlĂ© Reported-by: Lubomir Popov --- arch/arm/cpu/armv7/start.S | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/cpu/armv7/start.S b/arch/arm/cpu/armv7/start.S index c0e184994a..36a4c3cfda 100644 --- a/arch/arm/cpu/armv7/start.S +++ b/arch/arm/cpu/armv7/start.S @@ -254,7 +254,6 @@ ENTRY(c_runtime_cpu_setup) #if !defined(CONFIG_TEGRA) /* Set vector address in CP15 VBAR register */ ldr r0, =_start - add r0, r0, r9 mcr p15, 0, r0, c12, c0, 0 @Set VBAR #endif /* !Tegra */ -- cgit v1.2.3